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