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 #include <linux/rtnetlink.h> 41 42 MODULE_AUTHOR("Matt Mackall <mpm@selenic.com>"); 43 MODULE_DESCRIPTION("Console driver for network interfaces"); 44 MODULE_LICENSE("GPL"); 45 46 #define MAX_PARAM_LENGTH 256 47 #define MAX_USERDATA_ENTRY_LENGTH 256 48 #define MAX_USERDATA_VALUE_LENGTH 200 49 /* The number 3 comes from userdata entry format characters (' ', '=', '\n') */ 50 #define MAX_USERDATA_NAME_LENGTH (MAX_USERDATA_ENTRY_LENGTH - \ 51 MAX_USERDATA_VALUE_LENGTH - 3) 52 #define MAX_USERDATA_ITEMS 16 53 #define MAX_PRINT_CHUNK 1000 54 55 static char config[MAX_PARAM_LENGTH]; 56 module_param_string(netconsole, config, MAX_PARAM_LENGTH, 0); 57 MODULE_PARM_DESC(netconsole, " netconsole=[src-port]@[src-ip]/[dev],[tgt-port]@<tgt-ip>/[tgt-macaddr]"); 58 59 static bool oops_only; 60 module_param(oops_only, bool, 0600); 61 MODULE_PARM_DESC(oops_only, "Only log oops messages"); 62 63 #define NETCONSOLE_PARAM_TARGET_PREFIX "cmdline" 64 65 #ifndef MODULE 66 static int __init option_setup(char *opt) 67 { 68 strscpy(config, opt, MAX_PARAM_LENGTH); 69 return 1; 70 } 71 __setup("netconsole=", option_setup); 72 #endif /* MODULE */ 73 74 /* Linked list of all configured targets */ 75 static LIST_HEAD(target_list); 76 /* target_cleanup_list is used to track targets that need to be cleaned outside 77 * of target_list_lock. It should be cleaned in the same function it is 78 * populated. 79 */ 80 static LIST_HEAD(target_cleanup_list); 81 82 /* This needs to be a spinlock because write_msg() cannot sleep */ 83 static DEFINE_SPINLOCK(target_list_lock); 84 /* This needs to be a mutex because netpoll_cleanup might sleep */ 85 static DEFINE_MUTEX(target_cleanup_list_lock); 86 87 /* 88 * Console driver for extended netconsoles. Registered on the first use to 89 * avoid unnecessarily enabling ext message formatting. 90 */ 91 static struct console netconsole_ext; 92 93 /** 94 * struct netconsole_target - Represents a configured netconsole target. 95 * @list: Links this target into the target_list. 96 * @group: Links us into the configfs subsystem hierarchy. 97 * @userdata_group: Links to the userdata configfs hierarchy 98 * @userdata_complete: Cached, formatted string of append 99 * @userdata_length: String length of userdata_complete 100 * @enabled: On / off knob to enable / disable target. 101 * Visible from userspace (read-write). 102 * We maintain a strict 1:1 correspondence between this and 103 * whether the corresponding netpoll is active or inactive. 104 * Also, other parameters of a target may be modified at 105 * runtime only when it is disabled (enabled == 0). 106 * @extended: Denotes whether console is extended or not. 107 * @release: Denotes whether kernel release version should be prepended 108 * to the message. Depends on extended console. 109 * @np: The netpoll structure for this target. 110 * Contains the other userspace visible parameters: 111 * dev_name (read-write) 112 * local_port (read-write) 113 * remote_port (read-write) 114 * local_ip (read-write) 115 * remote_ip (read-write) 116 * local_mac (read-only) 117 * remote_mac (read-write) 118 */ 119 struct netconsole_target { 120 struct list_head list; 121 #ifdef CONFIG_NETCONSOLE_DYNAMIC 122 struct config_group group; 123 struct config_group userdata_group; 124 char userdata_complete[MAX_USERDATA_ENTRY_LENGTH * MAX_USERDATA_ITEMS]; 125 size_t userdata_length; 126 #endif 127 bool enabled; 128 bool extended; 129 bool release; 130 struct netpoll np; 131 }; 132 133 #ifdef CONFIG_NETCONSOLE_DYNAMIC 134 135 static struct configfs_subsystem netconsole_subsys; 136 static DEFINE_MUTEX(dynamic_netconsole_mutex); 137 138 static int __init dynamic_netconsole_init(void) 139 { 140 config_group_init(&netconsole_subsys.su_group); 141 mutex_init(&netconsole_subsys.su_mutex); 142 return configfs_register_subsystem(&netconsole_subsys); 143 } 144 145 static void __exit dynamic_netconsole_exit(void) 146 { 147 configfs_unregister_subsystem(&netconsole_subsys); 148 } 149 150 /* 151 * Targets that were created by parsing the boot/module option string 152 * do not exist in the configfs hierarchy (and have NULL names) and will 153 * never go away, so make these a no-op for them. 154 */ 155 static void netconsole_target_get(struct netconsole_target *nt) 156 { 157 if (config_item_name(&nt->group.cg_item)) 158 config_group_get(&nt->group); 159 } 160 161 static void netconsole_target_put(struct netconsole_target *nt) 162 { 163 if (config_item_name(&nt->group.cg_item)) 164 config_group_put(&nt->group); 165 } 166 167 #else /* !CONFIG_NETCONSOLE_DYNAMIC */ 168 169 static int __init dynamic_netconsole_init(void) 170 { 171 return 0; 172 } 173 174 static void __exit dynamic_netconsole_exit(void) 175 { 176 } 177 178 /* 179 * No danger of targets going away from under us when dynamic 180 * reconfigurability is off. 181 */ 182 static void netconsole_target_get(struct netconsole_target *nt) 183 { 184 } 185 186 static void netconsole_target_put(struct netconsole_target *nt) 187 { 188 } 189 190 static void populate_configfs_item(struct netconsole_target *nt, 191 int cmdline_count) 192 { 193 } 194 #endif /* CONFIG_NETCONSOLE_DYNAMIC */ 195 196 /* Allocate and initialize with defaults. 197 * Note that these targets get their config_item fields zeroed-out. 198 */ 199 static struct netconsole_target *alloc_and_init(void) 200 { 201 struct netconsole_target *nt; 202 203 nt = kzalloc(sizeof(*nt), GFP_KERNEL); 204 if (!nt) 205 return nt; 206 207 if (IS_ENABLED(CONFIG_NETCONSOLE_EXTENDED_LOG)) 208 nt->extended = true; 209 if (IS_ENABLED(CONFIG_NETCONSOLE_PREPEND_RELEASE)) 210 nt->release = true; 211 212 nt->np.name = "netconsole"; 213 strscpy(nt->np.dev_name, "eth0", IFNAMSIZ); 214 nt->np.local_port = 6665; 215 nt->np.remote_port = 6666; 216 eth_broadcast_addr(nt->np.remote_mac); 217 218 return nt; 219 } 220 221 /* Clean up every target in the cleanup_list and move the clean targets back to 222 * the main target_list. 223 */ 224 static void netconsole_process_cleanups_core(void) 225 { 226 struct netconsole_target *nt, *tmp; 227 unsigned long flags; 228 229 /* The cleanup needs RTNL locked */ 230 ASSERT_RTNL(); 231 232 mutex_lock(&target_cleanup_list_lock); 233 list_for_each_entry_safe(nt, tmp, &target_cleanup_list, list) { 234 /* all entries in the cleanup_list needs to be disabled */ 235 WARN_ON_ONCE(nt->enabled); 236 do_netpoll_cleanup(&nt->np); 237 /* moved the cleaned target to target_list. Need to hold both 238 * locks 239 */ 240 spin_lock_irqsave(&target_list_lock, flags); 241 list_move(&nt->list, &target_list); 242 spin_unlock_irqrestore(&target_list_lock, flags); 243 } 244 WARN_ON_ONCE(!list_empty(&target_cleanup_list)); 245 mutex_unlock(&target_cleanup_list_lock); 246 } 247 248 #ifdef CONFIG_NETCONSOLE_DYNAMIC 249 250 /* 251 * Our subsystem hierarchy is: 252 * 253 * /sys/kernel/config/netconsole/ 254 * | 255 * <target>/ 256 * | enabled 257 * | release 258 * | dev_name 259 * | local_port 260 * | remote_port 261 * | local_ip 262 * | remote_ip 263 * | local_mac 264 * | remote_mac 265 * | userdata/ 266 * | <key>/ 267 * | value 268 * | ... 269 * | 270 * <target>/... 271 */ 272 273 static struct netconsole_target *to_target(struct config_item *item) 274 { 275 struct config_group *cfg_group; 276 277 cfg_group = to_config_group(item); 278 if (!cfg_group) 279 return NULL; 280 return container_of(to_config_group(item), 281 struct netconsole_target, group); 282 } 283 284 /* Do the list cleanup with the rtnl lock hold. rtnl lock is necessary because 285 * netdev might be cleaned-up by calling __netpoll_cleanup(), 286 */ 287 static void netconsole_process_cleanups(void) 288 { 289 /* rtnl lock is called here, because it has precedence over 290 * target_cleanup_list_lock mutex and target_cleanup_list 291 */ 292 rtnl_lock(); 293 netconsole_process_cleanups_core(); 294 rtnl_unlock(); 295 } 296 297 /* Get rid of possible trailing newline, returning the new length */ 298 static void trim_newline(char *s, size_t maxlen) 299 { 300 size_t len; 301 302 len = strnlen(s, maxlen); 303 if (s[len - 1] == '\n') 304 s[len - 1] = '\0'; 305 } 306 307 /* 308 * Attribute operations for netconsole_target. 309 */ 310 311 static ssize_t enabled_show(struct config_item *item, char *buf) 312 { 313 return sysfs_emit(buf, "%d\n", to_target(item)->enabled); 314 } 315 316 static ssize_t extended_show(struct config_item *item, char *buf) 317 { 318 return sysfs_emit(buf, "%d\n", to_target(item)->extended); 319 } 320 321 static ssize_t release_show(struct config_item *item, char *buf) 322 { 323 return sysfs_emit(buf, "%d\n", to_target(item)->release); 324 } 325 326 static ssize_t dev_name_show(struct config_item *item, char *buf) 327 { 328 return sysfs_emit(buf, "%s\n", to_target(item)->np.dev_name); 329 } 330 331 static ssize_t local_port_show(struct config_item *item, char *buf) 332 { 333 return sysfs_emit(buf, "%d\n", to_target(item)->np.local_port); 334 } 335 336 static ssize_t remote_port_show(struct config_item *item, char *buf) 337 { 338 return sysfs_emit(buf, "%d\n", to_target(item)->np.remote_port); 339 } 340 341 static ssize_t local_ip_show(struct config_item *item, char *buf) 342 { 343 struct netconsole_target *nt = to_target(item); 344 345 if (nt->np.ipv6) 346 return sysfs_emit(buf, "%pI6c\n", &nt->np.local_ip.in6); 347 else 348 return sysfs_emit(buf, "%pI4\n", &nt->np.local_ip); 349 } 350 351 static ssize_t remote_ip_show(struct config_item *item, char *buf) 352 { 353 struct netconsole_target *nt = to_target(item); 354 355 if (nt->np.ipv6) 356 return sysfs_emit(buf, "%pI6c\n", &nt->np.remote_ip.in6); 357 else 358 return sysfs_emit(buf, "%pI4\n", &nt->np.remote_ip); 359 } 360 361 static ssize_t local_mac_show(struct config_item *item, char *buf) 362 { 363 struct net_device *dev = to_target(item)->np.dev; 364 static const u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 365 366 return sysfs_emit(buf, "%pM\n", dev ? dev->dev_addr : bcast); 367 } 368 369 static ssize_t remote_mac_show(struct config_item *item, char *buf) 370 { 371 return sysfs_emit(buf, "%pM\n", to_target(item)->np.remote_mac); 372 } 373 374 /* 375 * This one is special -- targets created through the configfs interface 376 * are not enabled (and the corresponding netpoll activated) by default. 377 * The user is expected to set the desired parameters first (which 378 * would enable him to dynamically add new netpoll targets for new 379 * network interfaces as and when they come up). 380 */ 381 static ssize_t enabled_store(struct config_item *item, 382 const char *buf, size_t count) 383 { 384 struct netconsole_target *nt = to_target(item); 385 unsigned long flags; 386 bool enabled; 387 ssize_t ret; 388 389 mutex_lock(&dynamic_netconsole_mutex); 390 ret = kstrtobool(buf, &enabled); 391 if (ret) 392 goto out_unlock; 393 394 ret = -EINVAL; 395 if (enabled == nt->enabled) { 396 pr_info("network logging has already %s\n", 397 nt->enabled ? "started" : "stopped"); 398 goto out_unlock; 399 } 400 401 if (enabled) { /* true */ 402 if (nt->release && !nt->extended) { 403 pr_err("Not enabling netconsole. Release feature requires extended log message"); 404 goto out_unlock; 405 } 406 407 if (nt->extended && !console_is_registered(&netconsole_ext)) 408 register_console(&netconsole_ext); 409 410 /* 411 * Skip netpoll_parse_options() -- all the attributes are 412 * already configured via configfs. Just print them out. 413 */ 414 netpoll_print_options(&nt->np); 415 416 ret = netpoll_setup(&nt->np); 417 if (ret) 418 goto out_unlock; 419 420 nt->enabled = true; 421 pr_info("network logging started\n"); 422 } else { /* false */ 423 /* We need to disable the netconsole before cleaning it up 424 * otherwise we might end up in write_msg() with 425 * nt->np.dev == NULL and nt->enabled == true 426 */ 427 mutex_lock(&target_cleanup_list_lock); 428 spin_lock_irqsave(&target_list_lock, flags); 429 nt->enabled = false; 430 /* Remove the target from the list, while holding 431 * target_list_lock 432 */ 433 list_move(&nt->list, &target_cleanup_list); 434 spin_unlock_irqrestore(&target_list_lock, flags); 435 mutex_unlock(&target_cleanup_list_lock); 436 } 437 438 ret = strnlen(buf, count); 439 /* Deferred cleanup */ 440 netconsole_process_cleanups(); 441 out_unlock: 442 mutex_unlock(&dynamic_netconsole_mutex); 443 return ret; 444 } 445 446 static ssize_t release_store(struct config_item *item, const char *buf, 447 size_t count) 448 { 449 struct netconsole_target *nt = to_target(item); 450 bool release; 451 ssize_t ret; 452 453 mutex_lock(&dynamic_netconsole_mutex); 454 if (nt->enabled) { 455 pr_err("target (%s) is enabled, disable to update parameters\n", 456 config_item_name(&nt->group.cg_item)); 457 ret = -EINVAL; 458 goto out_unlock; 459 } 460 461 ret = kstrtobool(buf, &release); 462 if (ret) 463 goto out_unlock; 464 465 nt->release = release; 466 467 ret = strnlen(buf, count); 468 out_unlock: 469 mutex_unlock(&dynamic_netconsole_mutex); 470 return ret; 471 } 472 473 static ssize_t extended_store(struct config_item *item, const char *buf, 474 size_t count) 475 { 476 struct netconsole_target *nt = to_target(item); 477 bool extended; 478 ssize_t ret; 479 480 mutex_lock(&dynamic_netconsole_mutex); 481 if (nt->enabled) { 482 pr_err("target (%s) is enabled, disable to update parameters\n", 483 config_item_name(&nt->group.cg_item)); 484 ret = -EINVAL; 485 goto out_unlock; 486 } 487 488 ret = kstrtobool(buf, &extended); 489 if (ret) 490 goto out_unlock; 491 492 nt->extended = extended; 493 ret = strnlen(buf, count); 494 out_unlock: 495 mutex_unlock(&dynamic_netconsole_mutex); 496 return ret; 497 } 498 499 static ssize_t dev_name_store(struct config_item *item, const char *buf, 500 size_t count) 501 { 502 struct netconsole_target *nt = to_target(item); 503 504 mutex_lock(&dynamic_netconsole_mutex); 505 if (nt->enabled) { 506 pr_err("target (%s) is enabled, disable to update parameters\n", 507 config_item_name(&nt->group.cg_item)); 508 mutex_unlock(&dynamic_netconsole_mutex); 509 return -EINVAL; 510 } 511 512 strscpy(nt->np.dev_name, buf, IFNAMSIZ); 513 trim_newline(nt->np.dev_name, IFNAMSIZ); 514 515 mutex_unlock(&dynamic_netconsole_mutex); 516 return strnlen(buf, count); 517 } 518 519 static ssize_t local_port_store(struct config_item *item, const char *buf, 520 size_t count) 521 { 522 struct netconsole_target *nt = to_target(item); 523 ssize_t ret = -EINVAL; 524 525 mutex_lock(&dynamic_netconsole_mutex); 526 if (nt->enabled) { 527 pr_err("target (%s) is enabled, disable to update parameters\n", 528 config_item_name(&nt->group.cg_item)); 529 goto out_unlock; 530 } 531 532 ret = kstrtou16(buf, 10, &nt->np.local_port); 533 if (ret < 0) 534 goto out_unlock; 535 ret = strnlen(buf, count); 536 out_unlock: 537 mutex_unlock(&dynamic_netconsole_mutex); 538 return ret; 539 } 540 541 static ssize_t remote_port_store(struct config_item *item, 542 const char *buf, size_t count) 543 { 544 struct netconsole_target *nt = to_target(item); 545 ssize_t ret = -EINVAL; 546 547 mutex_lock(&dynamic_netconsole_mutex); 548 if (nt->enabled) { 549 pr_err("target (%s) is enabled, disable to update parameters\n", 550 config_item_name(&nt->group.cg_item)); 551 goto out_unlock; 552 } 553 554 ret = kstrtou16(buf, 10, &nt->np.remote_port); 555 if (ret < 0) 556 goto out_unlock; 557 ret = strnlen(buf, count); 558 out_unlock: 559 mutex_unlock(&dynamic_netconsole_mutex); 560 return ret; 561 } 562 563 static ssize_t local_ip_store(struct config_item *item, const char *buf, 564 size_t count) 565 { 566 struct netconsole_target *nt = to_target(item); 567 ssize_t ret = -EINVAL; 568 569 mutex_lock(&dynamic_netconsole_mutex); 570 if (nt->enabled) { 571 pr_err("target (%s) is enabled, disable to update parameters\n", 572 config_item_name(&nt->group.cg_item)); 573 goto out_unlock; 574 } 575 576 if (strnchr(buf, count, ':')) { 577 const char *end; 578 579 if (in6_pton(buf, count, nt->np.local_ip.in6.s6_addr, -1, &end) > 0) { 580 if (*end && *end != '\n') { 581 pr_err("invalid IPv6 address at: <%c>\n", *end); 582 goto out_unlock; 583 } 584 nt->np.ipv6 = true; 585 } else 586 goto out_unlock; 587 } else { 588 if (!nt->np.ipv6) 589 nt->np.local_ip.ip = in_aton(buf); 590 else 591 goto out_unlock; 592 } 593 594 ret = strnlen(buf, count); 595 out_unlock: 596 mutex_unlock(&dynamic_netconsole_mutex); 597 return ret; 598 } 599 600 static ssize_t remote_ip_store(struct config_item *item, const char *buf, 601 size_t count) 602 { 603 struct netconsole_target *nt = to_target(item); 604 ssize_t ret = -EINVAL; 605 606 mutex_lock(&dynamic_netconsole_mutex); 607 if (nt->enabled) { 608 pr_err("target (%s) is enabled, disable to update parameters\n", 609 config_item_name(&nt->group.cg_item)); 610 goto out_unlock; 611 } 612 613 if (strnchr(buf, count, ':')) { 614 const char *end; 615 616 if (in6_pton(buf, count, nt->np.remote_ip.in6.s6_addr, -1, &end) > 0) { 617 if (*end && *end != '\n') { 618 pr_err("invalid IPv6 address at: <%c>\n", *end); 619 goto out_unlock; 620 } 621 nt->np.ipv6 = true; 622 } else 623 goto out_unlock; 624 } else { 625 if (!nt->np.ipv6) 626 nt->np.remote_ip.ip = in_aton(buf); 627 else 628 goto out_unlock; 629 } 630 631 ret = strnlen(buf, count); 632 out_unlock: 633 mutex_unlock(&dynamic_netconsole_mutex); 634 return ret; 635 } 636 637 static ssize_t remote_mac_store(struct config_item *item, const char *buf, 638 size_t count) 639 { 640 struct netconsole_target *nt = to_target(item); 641 u8 remote_mac[ETH_ALEN]; 642 ssize_t ret = -EINVAL; 643 644 mutex_lock(&dynamic_netconsole_mutex); 645 if (nt->enabled) { 646 pr_err("target (%s) is enabled, disable to update parameters\n", 647 config_item_name(&nt->group.cg_item)); 648 goto out_unlock; 649 } 650 651 if (!mac_pton(buf, remote_mac)) 652 goto out_unlock; 653 if (buf[3 * ETH_ALEN - 1] && buf[3 * ETH_ALEN - 1] != '\n') 654 goto out_unlock; 655 memcpy(nt->np.remote_mac, remote_mac, ETH_ALEN); 656 657 ret = strnlen(buf, count); 658 out_unlock: 659 mutex_unlock(&dynamic_netconsole_mutex); 660 return ret; 661 } 662 663 struct userdatum { 664 struct config_item item; 665 char value[MAX_USERDATA_VALUE_LENGTH]; 666 }; 667 668 static struct userdatum *to_userdatum(struct config_item *item) 669 { 670 return container_of(item, struct userdatum, item); 671 } 672 673 struct userdata { 674 struct config_group group; 675 }; 676 677 static struct userdata *to_userdata(struct config_item *item) 678 { 679 return container_of(to_config_group(item), struct userdata, group); 680 } 681 682 static struct netconsole_target *userdata_to_target(struct userdata *ud) 683 { 684 struct config_group *netconsole_group; 685 686 netconsole_group = to_config_group(ud->group.cg_item.ci_parent); 687 return to_target(&netconsole_group->cg_item); 688 } 689 690 static ssize_t userdatum_value_show(struct config_item *item, char *buf) 691 { 692 return sysfs_emit(buf, "%s\n", &(to_userdatum(item)->value[0])); 693 } 694 695 static void update_userdata(struct netconsole_target *nt) 696 { 697 int complete_idx = 0, child_count = 0; 698 struct list_head *entry; 699 700 /* Clear the current string in case the last userdatum was deleted */ 701 nt->userdata_length = 0; 702 nt->userdata_complete[0] = 0; 703 704 list_for_each(entry, &nt->userdata_group.cg_children) { 705 struct userdatum *udm_item; 706 struct config_item *item; 707 708 if (child_count >= MAX_USERDATA_ITEMS) 709 break; 710 child_count++; 711 712 item = container_of(entry, struct config_item, ci_entry); 713 udm_item = to_userdatum(item); 714 715 /* Skip userdata with no value set */ 716 if (strnlen(udm_item->value, MAX_USERDATA_VALUE_LENGTH) == 0) 717 continue; 718 719 /* This doesn't overflow userdata_complete since it will write 720 * one entry length (1/MAX_USERDATA_ITEMS long), entry count is 721 * checked to not exceed MAX items with child_count above 722 */ 723 complete_idx += scnprintf(&nt->userdata_complete[complete_idx], 724 MAX_USERDATA_ENTRY_LENGTH, " %s=%s\n", 725 item->ci_name, udm_item->value); 726 } 727 nt->userdata_length = strnlen(nt->userdata_complete, 728 sizeof(nt->userdata_complete)); 729 } 730 731 static ssize_t userdatum_value_store(struct config_item *item, const char *buf, 732 size_t count) 733 { 734 struct userdatum *udm = to_userdatum(item); 735 struct netconsole_target *nt; 736 struct userdata *ud; 737 ssize_t ret; 738 739 if (count > MAX_USERDATA_VALUE_LENGTH) 740 return -EMSGSIZE; 741 742 mutex_lock(&dynamic_netconsole_mutex); 743 744 ret = strscpy(udm->value, buf, sizeof(udm->value)); 745 if (ret < 0) 746 goto out_unlock; 747 trim_newline(udm->value, sizeof(udm->value)); 748 749 ud = to_userdata(item->ci_parent); 750 nt = userdata_to_target(ud); 751 update_userdata(nt); 752 ret = count; 753 out_unlock: 754 mutex_unlock(&dynamic_netconsole_mutex); 755 return ret; 756 } 757 758 CONFIGFS_ATTR(userdatum_, value); 759 760 static struct configfs_attribute *userdatum_attrs[] = { 761 &userdatum_attr_value, 762 NULL, 763 }; 764 765 static void userdatum_release(struct config_item *item) 766 { 767 kfree(to_userdatum(item)); 768 } 769 770 static struct configfs_item_operations userdatum_ops = { 771 .release = userdatum_release, 772 }; 773 774 static const struct config_item_type userdatum_type = { 775 .ct_item_ops = &userdatum_ops, 776 .ct_attrs = userdatum_attrs, 777 .ct_owner = THIS_MODULE, 778 }; 779 780 static struct config_item *userdatum_make_item(struct config_group *group, 781 const char *name) 782 { 783 struct netconsole_target *nt; 784 struct userdatum *udm; 785 struct userdata *ud; 786 size_t child_count; 787 788 if (strlen(name) > MAX_USERDATA_NAME_LENGTH) 789 return ERR_PTR(-ENAMETOOLONG); 790 791 ud = to_userdata(&group->cg_item); 792 nt = userdata_to_target(ud); 793 child_count = list_count_nodes(&nt->userdata_group.cg_children); 794 if (child_count >= MAX_USERDATA_ITEMS) 795 return ERR_PTR(-ENOSPC); 796 797 udm = kzalloc(sizeof(*udm), GFP_KERNEL); 798 if (!udm) 799 return ERR_PTR(-ENOMEM); 800 801 config_item_init_type_name(&udm->item, name, &userdatum_type); 802 return &udm->item; 803 } 804 805 static void userdatum_drop(struct config_group *group, struct config_item *item) 806 { 807 struct netconsole_target *nt; 808 struct userdata *ud; 809 810 ud = to_userdata(&group->cg_item); 811 nt = userdata_to_target(ud); 812 813 mutex_lock(&dynamic_netconsole_mutex); 814 update_userdata(nt); 815 config_item_put(item); 816 mutex_unlock(&dynamic_netconsole_mutex); 817 } 818 819 static struct configfs_attribute *userdata_attrs[] = { 820 NULL, 821 }; 822 823 static struct configfs_group_operations userdata_ops = { 824 .make_item = userdatum_make_item, 825 .drop_item = userdatum_drop, 826 }; 827 828 static const struct config_item_type userdata_type = { 829 .ct_item_ops = &userdatum_ops, 830 .ct_group_ops = &userdata_ops, 831 .ct_attrs = userdata_attrs, 832 .ct_owner = THIS_MODULE, 833 }; 834 835 CONFIGFS_ATTR(, enabled); 836 CONFIGFS_ATTR(, extended); 837 CONFIGFS_ATTR(, dev_name); 838 CONFIGFS_ATTR(, local_port); 839 CONFIGFS_ATTR(, remote_port); 840 CONFIGFS_ATTR(, local_ip); 841 CONFIGFS_ATTR(, remote_ip); 842 CONFIGFS_ATTR_RO(, local_mac); 843 CONFIGFS_ATTR(, remote_mac); 844 CONFIGFS_ATTR(, release); 845 846 static struct configfs_attribute *netconsole_target_attrs[] = { 847 &attr_enabled, 848 &attr_extended, 849 &attr_release, 850 &attr_dev_name, 851 &attr_local_port, 852 &attr_remote_port, 853 &attr_local_ip, 854 &attr_remote_ip, 855 &attr_local_mac, 856 &attr_remote_mac, 857 NULL, 858 }; 859 860 /* 861 * Item operations and type for netconsole_target. 862 */ 863 864 static void netconsole_target_release(struct config_item *item) 865 { 866 kfree(to_target(item)); 867 } 868 869 static struct configfs_item_operations netconsole_target_item_ops = { 870 .release = netconsole_target_release, 871 }; 872 873 static const struct config_item_type netconsole_target_type = { 874 .ct_attrs = netconsole_target_attrs, 875 .ct_item_ops = &netconsole_target_item_ops, 876 .ct_owner = THIS_MODULE, 877 }; 878 879 static void init_target_config_group(struct netconsole_target *nt, 880 const char *name) 881 { 882 config_group_init_type_name(&nt->group, name, &netconsole_target_type); 883 config_group_init_type_name(&nt->userdata_group, "userdata", 884 &userdata_type); 885 configfs_add_default_group(&nt->userdata_group, &nt->group); 886 } 887 888 static struct netconsole_target *find_cmdline_target(const char *name) 889 { 890 struct netconsole_target *nt, *ret = NULL; 891 unsigned long flags; 892 893 spin_lock_irqsave(&target_list_lock, flags); 894 list_for_each_entry(nt, &target_list, list) { 895 if (!strcmp(nt->group.cg_item.ci_name, name)) { 896 ret = nt; 897 break; 898 } 899 } 900 spin_unlock_irqrestore(&target_list_lock, flags); 901 902 return ret; 903 } 904 905 /* 906 * Group operations and type for netconsole_subsys. 907 */ 908 909 static struct config_group *make_netconsole_target(struct config_group *group, 910 const char *name) 911 { 912 struct netconsole_target *nt; 913 unsigned long flags; 914 915 /* Checking if a target by this name was created at boot time. If so, 916 * attach a configfs entry to that target. This enables dynamic 917 * control. 918 */ 919 if (!strncmp(name, NETCONSOLE_PARAM_TARGET_PREFIX, 920 strlen(NETCONSOLE_PARAM_TARGET_PREFIX))) { 921 nt = find_cmdline_target(name); 922 if (nt) { 923 init_target_config_group(nt, name); 924 return &nt->group; 925 } 926 } 927 928 nt = alloc_and_init(); 929 if (!nt) 930 return ERR_PTR(-ENOMEM); 931 932 /* Initialize the config_group member */ 933 init_target_config_group(nt, name); 934 935 /* Adding, but it is disabled */ 936 spin_lock_irqsave(&target_list_lock, flags); 937 list_add(&nt->list, &target_list); 938 spin_unlock_irqrestore(&target_list_lock, flags); 939 940 return &nt->group; 941 } 942 943 static void drop_netconsole_target(struct config_group *group, 944 struct config_item *item) 945 { 946 unsigned long flags; 947 struct netconsole_target *nt = to_target(item); 948 949 spin_lock_irqsave(&target_list_lock, flags); 950 list_del(&nt->list); 951 spin_unlock_irqrestore(&target_list_lock, flags); 952 953 /* 954 * The target may have never been enabled, or was manually disabled 955 * before being removed so netpoll may have already been cleaned up. 956 */ 957 if (nt->enabled) 958 netpoll_cleanup(&nt->np); 959 960 config_item_put(&nt->group.cg_item); 961 } 962 963 static struct configfs_group_operations netconsole_subsys_group_ops = { 964 .make_group = make_netconsole_target, 965 .drop_item = drop_netconsole_target, 966 }; 967 968 static const struct config_item_type netconsole_subsys_type = { 969 .ct_group_ops = &netconsole_subsys_group_ops, 970 .ct_owner = THIS_MODULE, 971 }; 972 973 /* The netconsole configfs subsystem */ 974 static struct configfs_subsystem netconsole_subsys = { 975 .su_group = { 976 .cg_item = { 977 .ci_namebuf = "netconsole", 978 .ci_type = &netconsole_subsys_type, 979 }, 980 }, 981 }; 982 983 static void populate_configfs_item(struct netconsole_target *nt, 984 int cmdline_count) 985 { 986 char target_name[16]; 987 988 snprintf(target_name, sizeof(target_name), "%s%d", 989 NETCONSOLE_PARAM_TARGET_PREFIX, cmdline_count); 990 init_target_config_group(nt, target_name); 991 } 992 993 #endif /* CONFIG_NETCONSOLE_DYNAMIC */ 994 995 /* Handle network interface device notifications */ 996 static int netconsole_netdev_event(struct notifier_block *this, 997 unsigned long event, void *ptr) 998 { 999 unsigned long flags; 1000 struct netconsole_target *nt, *tmp; 1001 struct net_device *dev = netdev_notifier_info_to_dev(ptr); 1002 bool stopped = false; 1003 1004 if (!(event == NETDEV_CHANGENAME || event == NETDEV_UNREGISTER || 1005 event == NETDEV_RELEASE || event == NETDEV_JOIN)) 1006 goto done; 1007 1008 mutex_lock(&target_cleanup_list_lock); 1009 spin_lock_irqsave(&target_list_lock, flags); 1010 list_for_each_entry_safe(nt, tmp, &target_list, list) { 1011 netconsole_target_get(nt); 1012 if (nt->np.dev == dev) { 1013 switch (event) { 1014 case NETDEV_CHANGENAME: 1015 strscpy(nt->np.dev_name, dev->name, IFNAMSIZ); 1016 break; 1017 case NETDEV_RELEASE: 1018 case NETDEV_JOIN: 1019 case NETDEV_UNREGISTER: 1020 nt->enabled = false; 1021 list_move(&nt->list, &target_cleanup_list); 1022 stopped = true; 1023 } 1024 } 1025 netconsole_target_put(nt); 1026 } 1027 spin_unlock_irqrestore(&target_list_lock, flags); 1028 mutex_unlock(&target_cleanup_list_lock); 1029 1030 if (stopped) { 1031 const char *msg = "had an event"; 1032 1033 switch (event) { 1034 case NETDEV_UNREGISTER: 1035 msg = "unregistered"; 1036 break; 1037 case NETDEV_RELEASE: 1038 msg = "released slaves"; 1039 break; 1040 case NETDEV_JOIN: 1041 msg = "is joining a master device"; 1042 break; 1043 } 1044 pr_info("network logging stopped on interface %s as it %s\n", 1045 dev->name, msg); 1046 } 1047 1048 /* Process target_cleanup_list entries. By the end, target_cleanup_list 1049 * should be empty 1050 */ 1051 netconsole_process_cleanups_core(); 1052 1053 done: 1054 return NOTIFY_DONE; 1055 } 1056 1057 static struct notifier_block netconsole_netdev_notifier = { 1058 .notifier_call = netconsole_netdev_event, 1059 }; 1060 1061 static void send_msg_no_fragmentation(struct netconsole_target *nt, 1062 const char *msg, 1063 int msg_len, 1064 int release_len) 1065 { 1066 static char buf[MAX_PRINT_CHUNK]; /* protected by target_list_lock */ 1067 const char *userdata = NULL; 1068 const char *release; 1069 1070 #ifdef CONFIG_NETCONSOLE_DYNAMIC 1071 userdata = nt->userdata_complete; 1072 #endif 1073 1074 if (release_len) { 1075 release = init_utsname()->release; 1076 1077 scnprintf(buf, MAX_PRINT_CHUNK, "%s,%s", release, msg); 1078 msg_len += release_len; 1079 } else { 1080 memcpy(buf, msg, msg_len); 1081 } 1082 1083 if (userdata) 1084 msg_len += scnprintf(&buf[msg_len], 1085 MAX_PRINT_CHUNK - msg_len, 1086 "%s", userdata); 1087 1088 netpoll_send_udp(&nt->np, buf, msg_len); 1089 } 1090 1091 static void append_release(char *buf) 1092 { 1093 const char *release; 1094 1095 release = init_utsname()->release; 1096 scnprintf(buf, MAX_PRINT_CHUNK, "%s,", release); 1097 } 1098 1099 static void send_fragmented_body(struct netconsole_target *nt, char *buf, 1100 const char *msgbody, int header_len, 1101 int msgbody_len) 1102 { 1103 const char *userdata = NULL; 1104 int body_len, offset = 0; 1105 int userdata_len = 0; 1106 1107 #ifdef CONFIG_NETCONSOLE_DYNAMIC 1108 userdata = nt->userdata_complete; 1109 userdata_len = nt->userdata_length; 1110 #endif 1111 1112 /* body_len represents the number of bytes that will be sent. This is 1113 * bigger than MAX_PRINT_CHUNK, thus, it will be split in multiple 1114 * packets 1115 */ 1116 body_len = msgbody_len + userdata_len; 1117 1118 /* In each iteration of the while loop below, we send a packet 1119 * containing the header and a portion of the body. The body is 1120 * composed of two parts: msgbody and userdata. We keep track of how 1121 * many bytes have been sent so far using the offset variable, which 1122 * ranges from 0 to the total length of the body. 1123 */ 1124 while (offset < body_len) { 1125 int this_header = header_len; 1126 bool msgbody_written = false; 1127 int this_offset = 0; 1128 int this_chunk = 0; 1129 1130 this_header += scnprintf(buf + this_header, 1131 MAX_PRINT_CHUNK - this_header, 1132 ",ncfrag=%d/%d;", offset, 1133 body_len); 1134 1135 /* Not all msgbody data has been written yet */ 1136 if (offset < msgbody_len) { 1137 this_chunk = min(msgbody_len - offset, 1138 MAX_PRINT_CHUNK - this_header); 1139 if (WARN_ON_ONCE(this_chunk <= 0)) 1140 return; 1141 memcpy(buf + this_header, msgbody + offset, this_chunk); 1142 this_offset += this_chunk; 1143 } 1144 1145 /* msgbody was finally written, either in the previous 1146 * messages and/or in the current buf. Time to write 1147 * the userdata. 1148 */ 1149 msgbody_written |= offset + this_offset >= msgbody_len; 1150 1151 /* Msg body is fully written and there is pending userdata to 1152 * write, append userdata in this chunk 1153 */ 1154 if (msgbody_written && offset + this_offset < body_len) { 1155 /* Track how much user data was already sent. First 1156 * time here, sent_userdata is zero 1157 */ 1158 int sent_userdata = (offset + this_offset) - msgbody_len; 1159 /* offset of bytes used in current buf */ 1160 int preceding_bytes = this_chunk + this_header; 1161 1162 if (WARN_ON_ONCE(sent_userdata < 0)) 1163 return; 1164 1165 this_chunk = min(userdata_len - sent_userdata, 1166 MAX_PRINT_CHUNK - preceding_bytes); 1167 if (WARN_ON_ONCE(this_chunk < 0)) 1168 /* this_chunk could be zero if all the previous 1169 * message used all the buffer. This is not a 1170 * problem, userdata will be sent in the next 1171 * iteration 1172 */ 1173 return; 1174 1175 memcpy(buf + this_header + this_offset, 1176 userdata + sent_userdata, 1177 this_chunk); 1178 this_offset += this_chunk; 1179 } 1180 1181 netpoll_send_udp(&nt->np, buf, this_header + this_offset); 1182 offset += this_offset; 1183 } 1184 } 1185 1186 static void send_msg_fragmented(struct netconsole_target *nt, 1187 const char *msg, 1188 int msg_len, 1189 int release_len) 1190 { 1191 static char buf[MAX_PRINT_CHUNK]; /* protected by target_list_lock */ 1192 int header_len, msgbody_len; 1193 const char *msgbody; 1194 1195 /* need to insert extra header fields, detect header and msgbody */ 1196 msgbody = memchr(msg, ';', msg_len); 1197 if (WARN_ON_ONCE(!msgbody)) 1198 return; 1199 1200 header_len = msgbody - msg; 1201 msgbody_len = msg_len - header_len - 1; 1202 msgbody++; 1203 1204 /* 1205 * Transfer multiple chunks with the following extra header. 1206 * "ncfrag=<byte-offset>/<total-bytes>" 1207 */ 1208 if (release_len) 1209 append_release(buf); 1210 1211 /* Copy the header into the buffer */ 1212 memcpy(buf + release_len, msg, header_len); 1213 header_len += release_len; 1214 1215 /* for now on, the header will be persisted, and the msgbody 1216 * will be replaced 1217 */ 1218 send_fragmented_body(nt, buf, msgbody, header_len, msgbody_len); 1219 } 1220 1221 /** 1222 * send_ext_msg_udp - send extended log message to target 1223 * @nt: target to send message to 1224 * @msg: extended log message to send 1225 * @msg_len: length of message 1226 * 1227 * Transfer extended log @msg to @nt. If @msg is longer than 1228 * MAX_PRINT_CHUNK, it'll be split and transmitted in multiple chunks with 1229 * ncfrag header field added to identify them. 1230 */ 1231 static void send_ext_msg_udp(struct netconsole_target *nt, const char *msg, 1232 int msg_len) 1233 { 1234 int userdata_len = 0; 1235 int release_len = 0; 1236 1237 #ifdef CONFIG_NETCONSOLE_DYNAMIC 1238 userdata_len = nt->userdata_length; 1239 #endif 1240 1241 if (nt->release) 1242 release_len = strlen(init_utsname()->release) + 1; 1243 1244 if (msg_len + release_len + userdata_len <= MAX_PRINT_CHUNK) 1245 return send_msg_no_fragmentation(nt, msg, msg_len, release_len); 1246 1247 return send_msg_fragmented(nt, msg, msg_len, release_len); 1248 } 1249 1250 static void write_ext_msg(struct console *con, const char *msg, 1251 unsigned int len) 1252 { 1253 struct netconsole_target *nt; 1254 unsigned long flags; 1255 1256 if ((oops_only && !oops_in_progress) || list_empty(&target_list)) 1257 return; 1258 1259 spin_lock_irqsave(&target_list_lock, flags); 1260 list_for_each_entry(nt, &target_list, list) 1261 if (nt->extended && nt->enabled && netif_running(nt->np.dev)) 1262 send_ext_msg_udp(nt, msg, len); 1263 spin_unlock_irqrestore(&target_list_lock, flags); 1264 } 1265 1266 static void write_msg(struct console *con, const char *msg, unsigned int len) 1267 { 1268 int frag, left; 1269 unsigned long flags; 1270 struct netconsole_target *nt; 1271 const char *tmp; 1272 1273 if (oops_only && !oops_in_progress) 1274 return; 1275 /* Avoid taking lock and disabling interrupts unnecessarily */ 1276 if (list_empty(&target_list)) 1277 return; 1278 1279 spin_lock_irqsave(&target_list_lock, flags); 1280 list_for_each_entry(nt, &target_list, list) { 1281 if (!nt->extended && nt->enabled && netif_running(nt->np.dev)) { 1282 /* 1283 * We nest this inside the for-each-target loop above 1284 * so that we're able to get as much logging out to 1285 * at least one target if we die inside here, instead 1286 * of unnecessarily keeping all targets in lock-step. 1287 */ 1288 tmp = msg; 1289 for (left = len; left;) { 1290 frag = min(left, MAX_PRINT_CHUNK); 1291 netpoll_send_udp(&nt->np, tmp, frag); 1292 tmp += frag; 1293 left -= frag; 1294 } 1295 } 1296 } 1297 spin_unlock_irqrestore(&target_list_lock, flags); 1298 } 1299 1300 /* Allocate new target (from boot/module param) and setup netpoll for it */ 1301 static struct netconsole_target *alloc_param_target(char *target_config, 1302 int cmdline_count) 1303 { 1304 struct netconsole_target *nt; 1305 int err; 1306 1307 nt = alloc_and_init(); 1308 if (!nt) { 1309 err = -ENOMEM; 1310 goto fail; 1311 } 1312 1313 if (*target_config == '+') { 1314 nt->extended = true; 1315 target_config++; 1316 } 1317 1318 if (*target_config == 'r') { 1319 if (!nt->extended) { 1320 pr_err("Netconsole configuration error. Release feature requires extended log message"); 1321 err = -EINVAL; 1322 goto fail; 1323 } 1324 nt->release = true; 1325 target_config++; 1326 } 1327 1328 /* Parse parameters and setup netpoll */ 1329 err = netpoll_parse_options(&nt->np, target_config); 1330 if (err) 1331 goto fail; 1332 1333 err = netpoll_setup(&nt->np); 1334 if (err) { 1335 pr_err("Not enabling netconsole for %s%d. Netpoll setup failed\n", 1336 NETCONSOLE_PARAM_TARGET_PREFIX, cmdline_count); 1337 if (!IS_ENABLED(CONFIG_NETCONSOLE_DYNAMIC)) 1338 /* only fail if dynamic reconfiguration is set, 1339 * otherwise, keep the target in the list, but disabled. 1340 */ 1341 goto fail; 1342 } else { 1343 nt->enabled = true; 1344 } 1345 populate_configfs_item(nt, cmdline_count); 1346 1347 return nt; 1348 1349 fail: 1350 kfree(nt); 1351 return ERR_PTR(err); 1352 } 1353 1354 /* Cleanup netpoll for given target (from boot/module param) and free it */ 1355 static void free_param_target(struct netconsole_target *nt) 1356 { 1357 netpoll_cleanup(&nt->np); 1358 kfree(nt); 1359 } 1360 1361 static struct console netconsole_ext = { 1362 .name = "netcon_ext", 1363 .flags = CON_ENABLED | CON_EXTENDED, 1364 .write = write_ext_msg, 1365 }; 1366 1367 static struct console netconsole = { 1368 .name = "netcon", 1369 .flags = CON_ENABLED, 1370 .write = write_msg, 1371 }; 1372 1373 static int __init init_netconsole(void) 1374 { 1375 int err; 1376 struct netconsole_target *nt, *tmp; 1377 unsigned int count = 0; 1378 bool extended = false; 1379 unsigned long flags; 1380 char *target_config; 1381 char *input = config; 1382 1383 if (strnlen(input, MAX_PARAM_LENGTH)) { 1384 while ((target_config = strsep(&input, ";"))) { 1385 nt = alloc_param_target(target_config, count); 1386 if (IS_ERR(nt)) { 1387 if (IS_ENABLED(CONFIG_NETCONSOLE_DYNAMIC)) 1388 continue; 1389 err = PTR_ERR(nt); 1390 goto fail; 1391 } 1392 /* Dump existing printks when we register */ 1393 if (nt->extended) { 1394 extended = true; 1395 netconsole_ext.flags |= CON_PRINTBUFFER; 1396 } else { 1397 netconsole.flags |= CON_PRINTBUFFER; 1398 } 1399 1400 spin_lock_irqsave(&target_list_lock, flags); 1401 list_add(&nt->list, &target_list); 1402 spin_unlock_irqrestore(&target_list_lock, flags); 1403 count++; 1404 } 1405 } 1406 1407 err = register_netdevice_notifier(&netconsole_netdev_notifier); 1408 if (err) 1409 goto fail; 1410 1411 err = dynamic_netconsole_init(); 1412 if (err) 1413 goto undonotifier; 1414 1415 if (extended) 1416 register_console(&netconsole_ext); 1417 register_console(&netconsole); 1418 pr_info("network logging started\n"); 1419 1420 return err; 1421 1422 undonotifier: 1423 unregister_netdevice_notifier(&netconsole_netdev_notifier); 1424 1425 fail: 1426 pr_err("cleaning up\n"); 1427 1428 /* 1429 * Remove all targets and destroy them (only targets created 1430 * from the boot/module option exist here). Skipping the list 1431 * lock is safe here, and netpoll_cleanup() will sleep. 1432 */ 1433 list_for_each_entry_safe(nt, tmp, &target_list, list) { 1434 list_del(&nt->list); 1435 free_param_target(nt); 1436 } 1437 1438 return err; 1439 } 1440 1441 static void __exit cleanup_netconsole(void) 1442 { 1443 struct netconsole_target *nt, *tmp; 1444 1445 if (console_is_registered(&netconsole_ext)) 1446 unregister_console(&netconsole_ext); 1447 unregister_console(&netconsole); 1448 dynamic_netconsole_exit(); 1449 unregister_netdevice_notifier(&netconsole_netdev_notifier); 1450 1451 /* 1452 * Targets created via configfs pin references on our module 1453 * and would first be rmdir(2)'ed from userspace. We reach 1454 * here only when they are already destroyed, and only those 1455 * created from the boot/module option are left, so remove and 1456 * destroy them. Skipping the list lock is safe here, and 1457 * netpoll_cleanup() will sleep. 1458 */ 1459 list_for_each_entry_safe(nt, tmp, &target_list, list) { 1460 list_del(&nt->list); 1461 free_param_target(nt); 1462 } 1463 } 1464 1465 /* 1466 * Use late_initcall to ensure netconsole is 1467 * initialized after network device driver if built-in. 1468 * 1469 * late_initcall() and module_init() are identical if built as module. 1470 */ 1471 late_initcall(init_netconsole); 1472 module_exit(cleanup_netconsole); 1473