This source file includes following definitions.
- option_setup
- dynamic_netconsole_init
- dynamic_netconsole_exit
- netconsole_target_get
- netconsole_target_put
- dynamic_netconsole_init
- dynamic_netconsole_exit
- netconsole_target_get
- netconsole_target_put
- alloc_param_target
- free_param_target
- to_target
- enabled_show
- extended_show
- dev_name_show
- local_port_show
- remote_port_show
- local_ip_show
- remote_ip_show
- local_mac_show
- remote_mac_show
- enabled_store
- extended_store
- dev_name_store
- local_port_store
- remote_port_store
- local_ip_store
- remote_ip_store
- remote_mac_store
- netconsole_target_release
- make_netconsole_target
- drop_netconsole_target
- netconsole_netdev_event
- send_ext_msg_udp
- write_ext_msg
- write_msg
- init_netconsole
- cleanup_netconsole
   1 
   2 
   3 
   4 
   5 
   6 
   7 
   8 
   9 
  10 
  11 
  12 
  13 
  14 
  15 
  16 
  17 
  18 
  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 
  40 MODULE_AUTHOR("Maintainer: Matt Mackall <mpm@selenic.com>");
  41 MODULE_DESCRIPTION("Console driver for network interfaces");
  42 MODULE_LICENSE("GPL");
  43 
  44 #define MAX_PARAM_LENGTH        256
  45 #define MAX_PRINT_CHUNK         1000
  46 
  47 static char config[MAX_PARAM_LENGTH];
  48 module_param_string(netconsole, config, MAX_PARAM_LENGTH, 0);
  49 MODULE_PARM_DESC(netconsole, " netconsole=[src-port]@[src-ip]/[dev],[tgt-port]@<tgt-ip>/[tgt-macaddr]");
  50 
  51 static bool oops_only = false;
  52 module_param(oops_only, bool, 0600);
  53 MODULE_PARM_DESC(oops_only, "Only log oops messages");
  54 
  55 #ifndef MODULE
  56 static 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  
  63 
  64 
  65 static LIST_HEAD(target_list);
  66 
  67 
  68 static DEFINE_SPINLOCK(target_list_lock);
  69 
  70 
  71 
  72 
  73 
  74 static struct console netconsole_ext;
  75 
  76 
  77 
  78 
  79 
  80 
  81 
  82 
  83 
  84 
  85 
  86 
  87 
  88 
  89 
  90 
  91 
  92 
  93 
  94 
  95 
  96 struct 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 
 108 static struct configfs_subsystem netconsole_subsys;
 109 static DEFINE_MUTEX(dynamic_netconsole_mutex);
 110 
 111 static 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 
 118 static void __exit dynamic_netconsole_exit(void)
 119 {
 120         configfs_unregister_subsystem(&netconsole_subsys);
 121 }
 122 
 123 
 124 
 125 
 126 
 127 
 128 static void netconsole_target_get(struct netconsole_target *nt)
 129 {
 130         if (config_item_name(&nt->item))
 131                 config_item_get(&nt->item);
 132 }
 133 
 134 static 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   
 141 
 142 static int __init dynamic_netconsole_init(void)
 143 {
 144         return 0;
 145 }
 146 
 147 static void __exit dynamic_netconsole_exit(void)
 148 {
 149 }
 150 
 151 
 152 
 153 
 154 
 155 static void netconsole_target_get(struct netconsole_target *nt)
 156 {
 157 }
 158 
 159 static void netconsole_target_put(struct netconsole_target *nt)
 160 {
 161 }
 162 
 163 #endif  
 164 
 165 
 166 static struct netconsole_target *alloc_param_target(char *target_config)
 167 {
 168         int err = -ENOMEM;
 169         struct netconsole_target *nt;
 170 
 171         
 172 
 173 
 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         
 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 
 203 fail:
 204         kfree(nt);
 205         return ERR_PTR(err);
 206 }
 207 
 208 
 209 static 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 
 219 
 220 
 221 
 222 
 223 
 224 
 225 
 226 
 227 
 228 
 229 
 230 
 231 
 232 
 233 
 234 
 235 static 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 
 244 
 245 
 246 static 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 
 251 static 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 
 256 static 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 
 261 static 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 
 266 static 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 
 271 static 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 
 281 static 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 
 291 static 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 
 299 static 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 
 306 
 307 
 308 
 309 
 310 
 311 static 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) {  
 334                 if (nt->extended && !(netconsole_ext.flags & CON_ENABLED)) {
 335                         netconsole_ext.flags |= CON_ENABLED;
 336                         register_console(&netconsole_ext);
 337                 }
 338 
 339                 
 340 
 341 
 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 {        
 351                 
 352 
 353 
 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);
 365 out_unlock:
 366         mutex_unlock(&dynamic_netconsole_mutex);
 367         return err;
 368 }
 369 
 370 static 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);
 397 out_unlock:
 398         mutex_unlock(&dynamic_netconsole_mutex);
 399         return err;
 400 }
 401 
 402 static 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         
 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 
 427 static 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);
 445 out_unlock:
 446         mutex_unlock(&dynamic_netconsole_mutex);
 447         return rv;
 448 }
 449 
 450 static 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);
 468 out_unlock:
 469         mutex_unlock(&dynamic_netconsole_mutex);
 470         return rv;
 471 }
 472 
 473 static 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);
 504 out_unlock:
 505         mutex_unlock(&dynamic_netconsole_mutex);
 506         return -EINVAL;
 507 }
 508 
 509 static 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);
 540 out_unlock:
 541         mutex_unlock(&dynamic_netconsole_mutex);
 542         return -EINVAL;
 543 }
 544 
 545 static 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);
 566 out_unlock:
 567         mutex_unlock(&dynamic_netconsole_mutex);
 568         return -EINVAL;
 569 }
 570 
 571 CONFIGFS_ATTR(, enabled);
 572 CONFIGFS_ATTR(, extended);
 573 CONFIGFS_ATTR(, dev_name);
 574 CONFIGFS_ATTR(, local_port);
 575 CONFIGFS_ATTR(, remote_port);
 576 CONFIGFS_ATTR(, local_ip);
 577 CONFIGFS_ATTR(, remote_ip);
 578 CONFIGFS_ATTR_RO(, local_mac);
 579 CONFIGFS_ATTR(, remote_mac);
 580 
 581 static 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 
 596 
 597 
 598 static void netconsole_target_release(struct config_item *item)
 599 {
 600         kfree(to_target(item));
 601 }
 602 
 603 static struct configfs_item_operations netconsole_target_item_ops = {
 604         .release                = netconsole_target_release,
 605 };
 606 
 607 static 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 
 615 
 616 
 617 static 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 
 625 
 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         
 638         config_item_init_type_name(&nt->item, name, &netconsole_target_type);
 639 
 640         
 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 
 648 static 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 
 660 
 661 
 662         if (nt->enabled)
 663                 netpoll_cleanup(&nt->np);
 664 
 665         config_item_put(&nt->item);
 666 }
 667 
 668 static struct configfs_group_operations netconsole_subsys_group_ops = {
 669         .make_item      = make_netconsole_target,
 670         .drop_item      = drop_netconsole_target,
 671 };
 672 
 673 static const struct config_item_type netconsole_subsys_type = {
 674         .ct_group_ops   = &netconsole_subsys_group_ops,
 675         .ct_owner       = THIS_MODULE,
 676 };
 677 
 678 
 679 static 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  
 689 
 690 
 691 static 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);
 704 restart:
 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                                 
 716 
 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 
 751 done:
 752         return NOTIFY_DONE;
 753 }
 754 
 755 static struct notifier_block netconsole_netdev_notifier = {
 756         .notifier_call  = netconsole_netdev_event,
 757 };
 758 
 759 
 760 
 761 
 762 
 763 
 764 
 765 
 766 
 767 
 768 
 769 static void send_ext_msg_udp(struct netconsole_target *nt, const char *msg,
 770                              int msg_len)
 771 {
 772         static char buf[MAX_PRINT_CHUNK]; 
 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         
 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 
 794 
 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 
 819 static 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 
 835 static 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         
 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 
 853 
 854 
 855 
 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 
 869 static struct console netconsole_ext = {
 870         .name   = "netcon_ext",
 871         .flags  = CON_EXTENDED, 
 872         .write  = write_ext_msg,
 873 };
 874 
 875 static struct console netconsole = {
 876         .name   = "netcon",
 877         .flags  = CON_ENABLED,
 878         .write  = write_msg,
 879 };
 880 
 881 static 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                         
 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 
 924 undonotifier:
 925         unregister_netdevice_notifier(&netconsole_netdev_notifier);
 926 
 927 fail:
 928         pr_err("cleaning up\n");
 929 
 930         
 931 
 932 
 933 
 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 
 943 static 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 
 954 
 955 
 956 
 957 
 958 
 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 
 968 
 969 
 970 
 971 
 972 late_initcall(init_netconsole);
 973 module_exit(cleanup_netconsole);