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