linux/drivers/net/netconsole.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 *  linux/drivers/net/netconsole.c
   4 *
   5 *  Copyright (C) 2001  Ingo Molnar <mingo@redhat.com>
   6 *
   7 *  This file contains the implementation of an IRQ-safe, crash-safe
   8 *  kernel console implementation that outputs kernel messages to the
   9 *  network.
  10 *
  11 * Modification history:
  12 *
  13 * 2001-09-17    started by Ingo Molnar.
  14 * 2003-08-11    2.6 port by Matt Mackall
  15 *               simplified options
  16 *               generic card hooks
  17 *               works non-modular
  18 * 2003-09-07    rewritten with netpoll api
  19 */
  20
  21/****************************************************************
  22 *
  23 ****************************************************************/
  24
  25#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  26
  27#include <linux/mm.h>
  28#include <linux/init.h>
  29#include <linux/module.h>
  30#include <linux/slab.h>
  31#include <linux/console.h>
  32#include <linux/moduleparam.h>
  33#include <linux/kernel.h>
  34#include <linux/string.h>
  35#include <linux/netpoll.h>
  36#include <linux/inet.h>
  37#include <linux/configfs.h>
  38#include <linux/etherdevice.h>
  39
  40MODULE_AUTHOR("Maintainer: Matt Mackall <mpm@selenic.com>");
  41MODULE_DESCRIPTION("Console driver for network interfaces");
  42MODULE_LICENSE("GPL");
  43
  44#define MAX_PARAM_LENGTH        256
  45#define MAX_PRINT_CHUNK         1000
  46
  47static char config[MAX_PARAM_LENGTH];
  48module_param_string(netconsole, config, MAX_PARAM_LENGTH, 0);
  49MODULE_PARM_DESC(netconsole, " netconsole=[src-port]@[src-ip]/[dev],[tgt-port]@<tgt-ip>/[tgt-macaddr]");
  50
  51static bool oops_only = false;
  52module_param(oops_only, bool, 0600);
  53MODULE_PARM_DESC(oops_only, "Only log oops messages");
  54
  55#ifndef MODULE
  56static int __init option_setup(char *opt)
  57{
  58        strlcpy(config, opt, MAX_PARAM_LENGTH);
  59        return 1;
  60}
  61__setup("netconsole=", option_setup);
  62#endif  /* MODULE */
  63
  64/* Linked list of all configured targets */
  65static LIST_HEAD(target_list);
  66
  67/* This needs to be a spinlock because write_msg() cannot sleep */
  68static DEFINE_SPINLOCK(target_list_lock);
  69
  70/*
  71 * Console driver for extended netconsoles.  Registered on the first use to
  72 * avoid unnecessarily enabling ext message formatting.
  73 */
  74static struct console netconsole_ext;
  75
  76/**
  77 * struct netconsole_target - Represents a configured netconsole target.
  78 * @list:       Links this target into the target_list.
  79 * @item:       Links us into the configfs subsystem hierarchy.
  80 * @enabled:    On / off knob to enable / disable target.
  81 *              Visible from userspace (read-write).
  82 *              We maintain a strict 1:1 correspondence between this and
  83 *              whether the corresponding netpoll is active or inactive.
  84 *              Also, other parameters of a target may be modified at
  85 *              runtime only when it is disabled (enabled == 0).
  86 * @extended:   Denotes whether console is extended or not.
  87 * @np:         The netpoll structure for this target.
  88 *              Contains the other userspace visible parameters:
  89 *              dev_name        (read-write)
  90 *              local_port      (read-write)
  91 *              remote_port     (read-write)
  92 *              local_ip        (read-write)
  93 *              remote_ip       (read-write)
  94 *              local_mac       (read-only)
  95 *              remote_mac      (read-write)
  96 */
  97struct netconsole_target {
  98        struct list_head        list;
  99#ifdef  CONFIG_NETCONSOLE_DYNAMIC
 100        struct config_item      item;
 101#endif
 102        bool                    enabled;
 103        bool                    extended;
 104        struct netpoll          np;
 105};
 106
 107#ifdef  CONFIG_NETCONSOLE_DYNAMIC
 108
 109static struct configfs_subsystem netconsole_subsys;
 110static DEFINE_MUTEX(dynamic_netconsole_mutex);
 111
 112static int __init dynamic_netconsole_init(void)
 113{
 114        config_group_init(&netconsole_subsys.su_group);
 115        mutex_init(&netconsole_subsys.su_mutex);
 116        return configfs_register_subsystem(&netconsole_subsys);
 117}
 118
 119static void __exit dynamic_netconsole_exit(void)
 120{
 121        configfs_unregister_subsystem(&netconsole_subsys);
 122}
 123
 124/*
 125 * Targets that were created by parsing the boot/module option string
 126 * do not exist in the configfs hierarchy (and have NULL names) and will
 127 * never go away, so make these a no-op for them.
 128 */
 129static void netconsole_target_get(struct netconsole_target *nt)
 130{
 131        if (config_item_name(&nt->item))
 132                config_item_get(&nt->item);
 133}
 134
 135static void netconsole_target_put(struct netconsole_target *nt)
 136{
 137        if (config_item_name(&nt->item))
 138                config_item_put(&nt->item);
 139}
 140
 141#else   /* !CONFIG_NETCONSOLE_DYNAMIC */
 142
 143static int __init dynamic_netconsole_init(void)
 144{
 145        return 0;
 146}
 147
 148static void __exit dynamic_netconsole_exit(void)
 149{
 150}
 151
 152/*
 153 * No danger of targets going away from under us when dynamic
 154 * reconfigurability is off.
 155 */
 156static void netconsole_target_get(struct netconsole_target *nt)
 157{
 158}
 159
 160static void netconsole_target_put(struct netconsole_target *nt)
 161{
 162}
 163
 164#endif  /* CONFIG_NETCONSOLE_DYNAMIC */
 165
 166/* Allocate new target (from boot/module param) and setup netpoll for it */
 167static struct netconsole_target *alloc_param_target(char *target_config)
 168{
 169        int err = -ENOMEM;
 170        struct netconsole_target *nt;
 171
 172        /*
 173         * Allocate and initialize with defaults.
 174         * Note that these targets get their config_item fields zeroed-out.
 175         */
 176        nt = kzalloc(sizeof(*nt), GFP_KERNEL);
 177        if (!nt)
 178                goto fail;
 179
 180        nt->np.name = "netconsole";
 181        strlcpy(nt->np.dev_name, "eth0", IFNAMSIZ);
 182        nt->np.local_port = 6665;
 183        nt->np.remote_port = 6666;
 184        eth_broadcast_addr(nt->np.remote_mac);
 185
 186        if (*target_config == '+') {
 187                nt->extended = true;
 188                target_config++;
 189        }
 190
 191        /* Parse parameters and setup netpoll */
 192        err = netpoll_parse_options(&nt->np, target_config);
 193        if (err)
 194                goto fail;
 195
 196        err = netpoll_setup(&nt->np);
 197        if (err)
 198                goto fail;
 199
 200        nt->enabled = true;
 201
 202        return nt;
 203
 204fail:
 205        kfree(nt);
 206        return ERR_PTR(err);
 207}
 208
 209/* Cleanup netpoll for given target (from boot/module param) and free it */
 210static void free_param_target(struct netconsole_target *nt)
 211{
 212        netpoll_cleanup(&nt->np);
 213        kfree(nt);
 214}
 215
 216#ifdef  CONFIG_NETCONSOLE_DYNAMIC
 217
 218/*
 219 * Our subsystem hierarchy is:
 220 *
 221 * /sys/kernel/config/netconsole/
 222 *                              |
 223 *                              <target>/
 224 *                              |       enabled
 225 *                              |       dev_name
 226 *                              |       local_port
 227 *                              |       remote_port
 228 *                              |       local_ip
 229 *                              |       remote_ip
 230 *                              |       local_mac
 231 *                              |       remote_mac
 232 *                              |
 233 *                              <target>/...
 234 */
 235
 236static struct netconsole_target *to_target(struct config_item *item)
 237{
 238        return item ?
 239                container_of(item, struct netconsole_target, item) :
 240                NULL;
 241}
 242
 243/*
 244 * Attribute operations for netconsole_target.
 245 */
 246
 247static ssize_t enabled_show(struct config_item *item, char *buf)
 248{
 249        return snprintf(buf, PAGE_SIZE, "%d\n", to_target(item)->enabled);
 250}
 251
 252static ssize_t extended_show(struct config_item *item, char *buf)
 253{
 254        return snprintf(buf, PAGE_SIZE, "%d\n", to_target(item)->extended);
 255}
 256
 257static ssize_t dev_name_show(struct config_item *item, char *buf)
 258{
 259        return snprintf(buf, PAGE_SIZE, "%s\n", to_target(item)->np.dev_name);
 260}
 261
 262static ssize_t local_port_show(struct config_item *item, char *buf)
 263{
 264        return snprintf(buf, PAGE_SIZE, "%d\n", to_target(item)->np.local_port);
 265}
 266
 267static ssize_t remote_port_show(struct config_item *item, char *buf)
 268{
 269        return snprintf(buf, PAGE_SIZE, "%d\n", to_target(item)->np.remote_port);
 270}
 271
 272static ssize_t local_ip_show(struct config_item *item, char *buf)
 273{
 274        struct netconsole_target *nt = to_target(item);
 275
 276        if (nt->np.ipv6)
 277                return snprintf(buf, PAGE_SIZE, "%pI6c\n", &nt->np.local_ip.in6);
 278        else
 279                return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.local_ip);
 280}
 281
 282static ssize_t remote_ip_show(struct config_item *item, char *buf)
 283{
 284        struct netconsole_target *nt = to_target(item);
 285
 286        if (nt->np.ipv6)
 287                return snprintf(buf, PAGE_SIZE, "%pI6c\n", &nt->np.remote_ip.in6);
 288        else
 289                return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.remote_ip);
 290}
 291
 292static ssize_t local_mac_show(struct config_item *item, char *buf)
 293{
 294        struct net_device *dev = to_target(item)->np.dev;
 295        static const u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 296
 297        return snprintf(buf, PAGE_SIZE, "%pM\n", dev ? dev->dev_addr : bcast);
 298}
 299
 300static ssize_t remote_mac_show(struct config_item *item, char *buf)
 301{
 302        return snprintf(buf, PAGE_SIZE, "%pM\n", to_target(item)->np.remote_mac);
 303}
 304
 305/*
 306 * This one is special -- targets created through the configfs interface
 307 * are not enabled (and the corresponding netpoll activated) by default.
 308 * The user is expected to set the desired parameters first (which
 309 * would enable him to dynamically add new netpoll targets for new
 310 * network interfaces as and when they come up).
 311 */
 312static ssize_t enabled_store(struct config_item *item,
 313                const char *buf, size_t count)
 314{
 315        struct netconsole_target *nt = to_target(item);
 316        unsigned long flags;
 317        int enabled;
 318        int err;
 319
 320        mutex_lock(&dynamic_netconsole_mutex);
 321        err = kstrtoint(buf, 10, &enabled);
 322        if (err < 0)
 323                goto out_unlock;
 324
 325        err = -EINVAL;
 326        if (enabled < 0 || enabled > 1)
 327                goto out_unlock;
 328        if ((bool)enabled == nt->enabled) {
 329                pr_info("network logging has already %s\n",
 330                        nt->enabled ? "started" : "stopped");
 331                goto out_unlock;
 332        }
 333
 334        if (enabled) {  /* true */
 335                if (nt->extended && !(netconsole_ext.flags & CON_ENABLED)) {
 336                        netconsole_ext.flags |= CON_ENABLED;
 337                        register_console(&netconsole_ext);
 338                }
 339
 340                /*
 341                 * Skip netpoll_parse_options() -- all the attributes are
 342                 * already configured via configfs. Just print them out.
 343                 */
 344                netpoll_print_options(&nt->np);
 345
 346                err = netpoll_setup(&nt->np);
 347                if (err)
 348                        goto out_unlock;
 349
 350                pr_info("network logging started\n");
 351        } else {        /* false */
 352                /* We need to disable the netconsole before cleaning it up
 353                 * otherwise we might end up in write_msg() with
 354                 * nt->np.dev == NULL and nt->enabled == true
 355                 */
 356                spin_lock_irqsave(&target_list_lock, flags);
 357                nt->enabled = false;
 358                spin_unlock_irqrestore(&target_list_lock, flags);
 359                netpoll_cleanup(&nt->np);
 360        }
 361
 362        nt->enabled = enabled;
 363
 364        mutex_unlock(&dynamic_netconsole_mutex);
 365        return strnlen(buf, count);
 366out_unlock:
 367        mutex_unlock(&dynamic_netconsole_mutex);
 368        return err;
 369}
 370
 371static ssize_t extended_store(struct config_item *item, const char *buf,
 372                size_t count)
 373{
 374        struct netconsole_target *nt = to_target(item);
 375        int extended;
 376        int err;
 377
 378        mutex_lock(&dynamic_netconsole_mutex);
 379        if (nt->enabled) {
 380                pr_err("target (%s) is enabled, disable to update parameters\n",
 381                       config_item_name(&nt->item));
 382                err = -EINVAL;
 383                goto out_unlock;
 384        }
 385
 386        err = kstrtoint(buf, 10, &extended);
 387        if (err < 0)
 388                goto out_unlock;
 389        if (extended < 0 || extended > 1) {
 390                err = -EINVAL;
 391                goto out_unlock;
 392        }
 393
 394        nt->extended = extended;
 395
 396        mutex_unlock(&dynamic_netconsole_mutex);
 397        return strnlen(buf, count);
 398out_unlock:
 399        mutex_unlock(&dynamic_netconsole_mutex);
 400        return err;
 401}
 402
 403static ssize_t dev_name_store(struct config_item *item, const char *buf,
 404                size_t count)
 405{
 406        struct netconsole_target *nt = to_target(item);
 407        size_t len;
 408
 409        mutex_lock(&dynamic_netconsole_mutex);
 410        if (nt->enabled) {
 411                pr_err("target (%s) is enabled, disable to update parameters\n",
 412                       config_item_name(&nt->item));
 413                mutex_unlock(&dynamic_netconsole_mutex);
 414                return -EINVAL;
 415        }
 416
 417        strlcpy(nt->np.dev_name, buf, IFNAMSIZ);
 418
 419        /* Get rid of possible trailing newline from echo(1) */
 420        len = strnlen(nt->np.dev_name, IFNAMSIZ);
 421        if (nt->np.dev_name[len - 1] == '\n')
 422                nt->np.dev_name[len - 1] = '\0';
 423
 424        mutex_unlock(&dynamic_netconsole_mutex);
 425        return strnlen(buf, count);
 426}
 427
 428static ssize_t local_port_store(struct config_item *item, const char *buf,
 429                size_t count)
 430{
 431        struct netconsole_target *nt = to_target(item);
 432        int rv = -EINVAL;
 433
 434        mutex_lock(&dynamic_netconsole_mutex);
 435        if (nt->enabled) {
 436                pr_err("target (%s) is enabled, disable to update parameters\n",
 437                       config_item_name(&nt->item));
 438                goto out_unlock;
 439        }
 440
 441        rv = kstrtou16(buf, 10, &nt->np.local_port);
 442        if (rv < 0)
 443                goto out_unlock;
 444        mutex_unlock(&dynamic_netconsole_mutex);
 445        return strnlen(buf, count);
 446out_unlock:
 447        mutex_unlock(&dynamic_netconsole_mutex);
 448        return rv;
 449}
 450
 451static ssize_t remote_port_store(struct config_item *item,
 452                const char *buf, size_t count)
 453{
 454        struct netconsole_target *nt = to_target(item);
 455        int rv = -EINVAL;
 456
 457        mutex_lock(&dynamic_netconsole_mutex);
 458        if (nt->enabled) {
 459                pr_err("target (%s) is enabled, disable to update parameters\n",
 460                       config_item_name(&nt->item));
 461                goto out_unlock;
 462        }
 463
 464        rv = kstrtou16(buf, 10, &nt->np.remote_port);
 465        if (rv < 0)
 466                goto out_unlock;
 467        mutex_unlock(&dynamic_netconsole_mutex);
 468        return strnlen(buf, count);
 469out_unlock:
 470        mutex_unlock(&dynamic_netconsole_mutex);
 471        return rv;
 472}
 473
 474static ssize_t local_ip_store(struct config_item *item, const char *buf,
 475                size_t count)
 476{
 477        struct netconsole_target *nt = to_target(item);
 478
 479        mutex_lock(&dynamic_netconsole_mutex);
 480        if (nt->enabled) {
 481                pr_err("target (%s) is enabled, disable to update parameters\n",
 482                       config_item_name(&nt->item));
 483                goto out_unlock;
 484        }
 485
 486        if (strnchr(buf, count, ':')) {
 487                const char *end;
 488                if (in6_pton(buf, count, nt->np.local_ip.in6.s6_addr, -1, &end) > 0) {
 489                        if (*end && *end != '\n') {
 490                                pr_err("invalid IPv6 address at: <%c>\n", *end);
 491                                goto out_unlock;
 492                        }
 493                        nt->np.ipv6 = true;
 494                } else
 495                        goto out_unlock;
 496        } else {
 497                if (!nt->np.ipv6) {
 498                        nt->np.local_ip.ip = in_aton(buf);
 499                } else
 500                        goto out_unlock;
 501        }
 502
 503        mutex_unlock(&dynamic_netconsole_mutex);
 504        return strnlen(buf, count);
 505out_unlock:
 506        mutex_unlock(&dynamic_netconsole_mutex);
 507        return -EINVAL;
 508}
 509
 510static ssize_t remote_ip_store(struct config_item *item, const char *buf,
 511               size_t count)
 512{
 513        struct netconsole_target *nt = to_target(item);
 514
 515        mutex_lock(&dynamic_netconsole_mutex);
 516        if (nt->enabled) {
 517                pr_err("target (%s) is enabled, disable to update parameters\n",
 518                       config_item_name(&nt->item));
 519                goto out_unlock;
 520        }
 521
 522        if (strnchr(buf, count, ':')) {
 523                const char *end;
 524                if (in6_pton(buf, count, nt->np.remote_ip.in6.s6_addr, -1, &end) > 0) {
 525                        if (*end && *end != '\n') {
 526                                pr_err("invalid IPv6 address at: <%c>\n", *end);
 527                                goto out_unlock;
 528                        }
 529                        nt->np.ipv6 = true;
 530                } else
 531                        goto out_unlock;
 532        } else {
 533                if (!nt->np.ipv6) {
 534                        nt->np.remote_ip.ip = in_aton(buf);
 535                } else
 536                        goto out_unlock;
 537        }
 538
 539        mutex_unlock(&dynamic_netconsole_mutex);
 540        return strnlen(buf, count);
 541out_unlock:
 542        mutex_unlock(&dynamic_netconsole_mutex);
 543        return -EINVAL;
 544}
 545
 546static ssize_t remote_mac_store(struct config_item *item, const char *buf,
 547                size_t count)
 548{
 549        struct netconsole_target *nt = to_target(item);
 550        u8 remote_mac[ETH_ALEN];
 551
 552        mutex_lock(&dynamic_netconsole_mutex);
 553        if (nt->enabled) {
 554                pr_err("target (%s) is enabled, disable to update parameters\n",
 555                       config_item_name(&nt->item));
 556                goto out_unlock;
 557        }
 558
 559        if (!mac_pton(buf, remote_mac))
 560                goto out_unlock;
 561        if (buf[3 * ETH_ALEN - 1] && buf[3 * ETH_ALEN - 1] != '\n')
 562                goto out_unlock;
 563        memcpy(nt->np.remote_mac, remote_mac, ETH_ALEN);
 564
 565        mutex_unlock(&dynamic_netconsole_mutex);
 566        return strnlen(buf, count);
 567out_unlock:
 568        mutex_unlock(&dynamic_netconsole_mutex);
 569        return -EINVAL;
 570}
 571
 572CONFIGFS_ATTR(, enabled);
 573CONFIGFS_ATTR(, extended);
 574CONFIGFS_ATTR(, dev_name);
 575CONFIGFS_ATTR(, local_port);
 576CONFIGFS_ATTR(, remote_port);
 577CONFIGFS_ATTR(, local_ip);
 578CONFIGFS_ATTR(, remote_ip);
 579CONFIGFS_ATTR_RO(, local_mac);
 580CONFIGFS_ATTR(, remote_mac);
 581
 582static struct configfs_attribute *netconsole_target_attrs[] = {
 583        &attr_enabled,
 584        &attr_extended,
 585        &attr_dev_name,
 586        &attr_local_port,
 587        &attr_remote_port,
 588        &attr_local_ip,
 589        &attr_remote_ip,
 590        &attr_local_mac,
 591        &attr_remote_mac,
 592        NULL,
 593};
 594
 595/*
 596 * Item operations and type for netconsole_target.
 597 */
 598
 599static void netconsole_target_release(struct config_item *item)
 600{
 601        kfree(to_target(item));
 602}
 603
 604static struct configfs_item_operations netconsole_target_item_ops = {
 605        .release                = netconsole_target_release,
 606};
 607
 608static const struct config_item_type netconsole_target_type = {
 609        .ct_attrs               = netconsole_target_attrs,
 610        .ct_item_ops            = &netconsole_target_item_ops,
 611        .ct_owner               = THIS_MODULE,
 612};
 613
 614/*
 615 * Group operations and type for netconsole_subsys.
 616 */
 617
 618static struct config_item *make_netconsole_target(struct config_group *group,
 619                                                  const char *name)
 620{
 621        unsigned long flags;
 622        struct netconsole_target *nt;
 623
 624        /*
 625         * Allocate and initialize with defaults.
 626         * Target is disabled at creation (!enabled).
 627         */
 628        nt = kzalloc(sizeof(*nt), GFP_KERNEL);
 629        if (!nt)
 630                return ERR_PTR(-ENOMEM);
 631
 632        nt->np.name = "netconsole";
 633        strlcpy(nt->np.dev_name, "eth0", IFNAMSIZ);
 634        nt->np.local_port = 6665;
 635        nt->np.remote_port = 6666;
 636        eth_broadcast_addr(nt->np.remote_mac);
 637
 638        /* Initialize the config_item member */
 639        config_item_init_type_name(&nt->item, name, &netconsole_target_type);
 640
 641        /* Adding, but it is disabled */
 642        spin_lock_irqsave(&target_list_lock, flags);
 643        list_add(&nt->list, &target_list);
 644        spin_unlock_irqrestore(&target_list_lock, flags);
 645
 646        return &nt->item;
 647}
 648
 649static void drop_netconsole_target(struct config_group *group,
 650                                   struct config_item *item)
 651{
 652        unsigned long flags;
 653        struct netconsole_target *nt = to_target(item);
 654
 655        spin_lock_irqsave(&target_list_lock, flags);
 656        list_del(&nt->list);
 657        spin_unlock_irqrestore(&target_list_lock, flags);
 658
 659        /*
 660         * The target may have never been enabled, or was manually disabled
 661         * before being removed so netpoll may have already been cleaned up.
 662         */
 663        if (nt->enabled)
 664                netpoll_cleanup(&nt->np);
 665
 666        config_item_put(&nt->item);
 667}
 668
 669static struct configfs_group_operations netconsole_subsys_group_ops = {
 670        .make_item      = make_netconsole_target,
 671        .drop_item      = drop_netconsole_target,
 672};
 673
 674static const struct config_item_type netconsole_subsys_type = {
 675        .ct_group_ops   = &netconsole_subsys_group_ops,
 676        .ct_owner       = THIS_MODULE,
 677};
 678
 679/* The netconsole configfs subsystem */
 680static struct configfs_subsystem netconsole_subsys = {
 681        .su_group       = {
 682                .cg_item        = {
 683                        .ci_namebuf     = "netconsole",
 684                        .ci_type        = &netconsole_subsys_type,
 685                },
 686        },
 687};
 688
 689#endif  /* CONFIG_NETCONSOLE_DYNAMIC */
 690
 691/* Handle network interface device notifications */
 692static int netconsole_netdev_event(struct notifier_block *this,
 693                                   unsigned long event, void *ptr)
 694{
 695        unsigned long flags;
 696        struct netconsole_target *nt;
 697        struct net_device *dev = netdev_notifier_info_to_dev(ptr);
 698        bool stopped = false;
 699
 700        if (!(event == NETDEV_CHANGENAME || event == NETDEV_UNREGISTER ||
 701              event == NETDEV_RELEASE || event == NETDEV_JOIN))
 702                goto done;
 703
 704        spin_lock_irqsave(&target_list_lock, flags);
 705restart:
 706        list_for_each_entry(nt, &target_list, list) {
 707                netconsole_target_get(nt);
 708                if (nt->np.dev == dev) {
 709                        switch (event) {
 710                        case NETDEV_CHANGENAME:
 711                                strlcpy(nt->np.dev_name, dev->name, IFNAMSIZ);
 712                                break;
 713                        case NETDEV_RELEASE:
 714                        case NETDEV_JOIN:
 715                        case NETDEV_UNREGISTER:
 716                                /* rtnl_lock already held
 717                                 * we might sleep in __netpoll_cleanup()
 718                                 */
 719                                spin_unlock_irqrestore(&target_list_lock, flags);
 720
 721                                __netpoll_cleanup(&nt->np);
 722
 723                                spin_lock_irqsave(&target_list_lock, flags);
 724                                dev_put(nt->np.dev);
 725                                nt->np.dev = NULL;
 726                                nt->enabled = false;
 727                                stopped = true;
 728                                netconsole_target_put(nt);
 729                                goto restart;
 730                        }
 731                }
 732                netconsole_target_put(nt);
 733        }
 734        spin_unlock_irqrestore(&target_list_lock, flags);
 735        if (stopped) {
 736                const char *msg = "had an event";
 737                switch (event) {
 738                case NETDEV_UNREGISTER:
 739                        msg = "unregistered";
 740                        break;
 741                case NETDEV_RELEASE:
 742                        msg = "released slaves";
 743                        break;
 744                case NETDEV_JOIN:
 745                        msg = "is joining a master device";
 746                        break;
 747                }
 748                pr_info("network logging stopped on interface %s as it %s\n",
 749                        dev->name, msg);
 750        }
 751
 752done:
 753        return NOTIFY_DONE;
 754}
 755
 756static struct notifier_block netconsole_netdev_notifier = {
 757        .notifier_call  = netconsole_netdev_event,
 758};
 759
 760/**
 761 * send_ext_msg_udp - send extended log message to target
 762 * @nt: target to send message to
 763 * @msg: extended log message to send
 764 * @msg_len: length of message
 765 *
 766 * Transfer extended log @msg to @nt.  If @msg is longer than
 767 * MAX_PRINT_CHUNK, it'll be split and transmitted in multiple chunks with
 768 * ncfrag header field added to identify them.
 769 */
 770static void send_ext_msg_udp(struct netconsole_target *nt, const char *msg,
 771                             int msg_len)
 772{
 773        static char buf[MAX_PRINT_CHUNK]; /* protected by target_list_lock */
 774        const char *header, *body;
 775        int offset = 0;
 776        int header_len, body_len;
 777
 778        if (msg_len <= MAX_PRINT_CHUNK) {
 779                netpoll_send_udp(&nt->np, msg, msg_len);
 780                return;
 781        }
 782
 783        /* need to insert extra header fields, detect header and body */
 784        header = msg;
 785        body = memchr(msg, ';', msg_len);
 786        if (WARN_ON_ONCE(!body))
 787                return;
 788
 789        header_len = body - header;
 790        body_len = msg_len - header_len - 1;
 791        body++;
 792
 793        /*
 794         * Transfer multiple chunks with the following extra header.
 795         * "ncfrag=<byte-offset>/<total-bytes>"
 796         */
 797        memcpy(buf, header, header_len);
 798
 799        while (offset < body_len) {
 800                int this_header = header_len;
 801                int this_chunk;
 802
 803                this_header += scnprintf(buf + this_header,
 804                                         sizeof(buf) - this_header,
 805                                         ",ncfrag=%d/%d;", offset, body_len);
 806
 807                this_chunk = min(body_len - offset,
 808                                 MAX_PRINT_CHUNK - this_header);
 809                if (WARN_ON_ONCE(this_chunk <= 0))
 810                        return;
 811
 812                memcpy(buf + this_header, body + offset, this_chunk);
 813
 814                netpoll_send_udp(&nt->np, buf, this_header + this_chunk);
 815
 816                offset += this_chunk;
 817        }
 818}
 819
 820static void write_ext_msg(struct console *con, const char *msg,
 821                          unsigned int len)
 822{
 823        struct netconsole_target *nt;
 824        unsigned long flags;
 825
 826        if ((oops_only && !oops_in_progress) || list_empty(&target_list))
 827                return;
 828
 829        spin_lock_irqsave(&target_list_lock, flags);
 830        list_for_each_entry(nt, &target_list, list)
 831                if (nt->extended && nt->enabled && netif_running(nt->np.dev))
 832                        send_ext_msg_udp(nt, msg, len);
 833        spin_unlock_irqrestore(&target_list_lock, flags);
 834}
 835
 836static void write_msg(struct console *con, const char *msg, unsigned int len)
 837{
 838        int frag, left;
 839        unsigned long flags;
 840        struct netconsole_target *nt;
 841        const char *tmp;
 842
 843        if (oops_only && !oops_in_progress)
 844                return;
 845        /* Avoid taking lock and disabling interrupts unnecessarily */
 846        if (list_empty(&target_list))
 847                return;
 848
 849        spin_lock_irqsave(&target_list_lock, flags);
 850        list_for_each_entry(nt, &target_list, list) {
 851                if (!nt->extended && nt->enabled && netif_running(nt->np.dev)) {
 852                        /*
 853                         * We nest this inside the for-each-target loop above
 854                         * so that we're able to get as much logging out to
 855                         * at least one target if we die inside here, instead
 856                         * of unnecessarily keeping all targets in lock-step.
 857                         */
 858                        tmp = msg;
 859                        for (left = len; left;) {
 860                                frag = min(left, MAX_PRINT_CHUNK);
 861                                netpoll_send_udp(&nt->np, tmp, frag);
 862                                tmp += frag;
 863                                left -= frag;
 864                        }
 865                }
 866        }
 867        spin_unlock_irqrestore(&target_list_lock, flags);
 868}
 869
 870static struct console netconsole_ext = {
 871        .name   = "netcon_ext",
 872        .flags  = CON_EXTENDED, /* starts disabled, registered on first use */
 873        .write  = write_ext_msg,
 874};
 875
 876static struct console netconsole = {
 877        .name   = "netcon",
 878        .flags  = CON_ENABLED,
 879        .write  = write_msg,
 880};
 881
 882static int __init init_netconsole(void)
 883{
 884        int err;
 885        struct netconsole_target *nt, *tmp;
 886        unsigned long flags;
 887        char *target_config;
 888        char *input = config;
 889
 890        if (strnlen(input, MAX_PARAM_LENGTH)) {
 891                while ((target_config = strsep(&input, ";"))) {
 892                        nt = alloc_param_target(target_config);
 893                        if (IS_ERR(nt)) {
 894                                err = PTR_ERR(nt);
 895                                goto fail;
 896                        }
 897                        /* Dump existing printks when we register */
 898                        if (nt->extended)
 899                                netconsole_ext.flags |= CON_PRINTBUFFER |
 900                                                        CON_ENABLED;
 901                        else
 902                                netconsole.flags |= CON_PRINTBUFFER;
 903
 904                        spin_lock_irqsave(&target_list_lock, flags);
 905                        list_add(&nt->list, &target_list);
 906                        spin_unlock_irqrestore(&target_list_lock, flags);
 907                }
 908        }
 909
 910        err = register_netdevice_notifier(&netconsole_netdev_notifier);
 911        if (err)
 912                goto fail;
 913
 914        err = dynamic_netconsole_init();
 915        if (err)
 916                goto undonotifier;
 917
 918        if (netconsole_ext.flags & CON_ENABLED)
 919                register_console(&netconsole_ext);
 920        register_console(&netconsole);
 921        pr_info("network logging started\n");
 922
 923        return err;
 924
 925undonotifier:
 926        unregister_netdevice_notifier(&netconsole_netdev_notifier);
 927
 928fail:
 929        pr_err("cleaning up\n");
 930
 931        /*
 932         * Remove all targets and destroy them (only targets created
 933         * from the boot/module option exist here). Skipping the list
 934         * lock is safe here, and netpoll_cleanup() will sleep.
 935         */
 936        list_for_each_entry_safe(nt, tmp, &target_list, list) {
 937                list_del(&nt->list);
 938                free_param_target(nt);
 939        }
 940
 941        return err;
 942}
 943
 944static void __exit cleanup_netconsole(void)
 945{
 946        struct netconsole_target *nt, *tmp;
 947
 948        unregister_console(&netconsole_ext);
 949        unregister_console(&netconsole);
 950        dynamic_netconsole_exit();
 951        unregister_netdevice_notifier(&netconsole_netdev_notifier);
 952
 953        /*
 954         * Targets created via configfs pin references on our module
 955         * and would first be rmdir(2)'ed from userspace. We reach
 956         * here only when they are already destroyed, and only those
 957         * created from the boot/module option are left, so remove and
 958         * destroy them. Skipping the list lock is safe here, and
 959         * netpoll_cleanup() will sleep.
 960         */
 961        list_for_each_entry_safe(nt, tmp, &target_list, list) {
 962                list_del(&nt->list);
 963                free_param_target(nt);
 964        }
 965}
 966
 967/*
 968 * Use late_initcall to ensure netconsole is
 969 * initialized after network device driver if built-in.
 970 *
 971 * late_initcall() and module_init() are identical if built as module.
 972 */
 973late_initcall(init_netconsole);
 974module_exit(cleanup_netconsole);
 975