0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0026
0027 #include <linux/mm.h>
0028 #include <linux/init.h>
0029 #include <linux/module.h>
0030 #include <linux/slab.h>
0031 #include <linux/console.h>
0032 #include <linux/moduleparam.h>
0033 #include <linux/kernel.h>
0034 #include <linux/string.h>
0035 #include <linux/netpoll.h>
0036 #include <linux/inet.h>
0037 #include <linux/configfs.h>
0038 #include <linux/etherdevice.h>
0039
0040 MODULE_AUTHOR("Maintainer: Matt Mackall <mpm@selenic.com>");
0041 MODULE_DESCRIPTION("Console driver for network interfaces");
0042 MODULE_LICENSE("GPL");
0043
0044 #define MAX_PARAM_LENGTH 256
0045 #define MAX_PRINT_CHUNK 1000
0046
0047 static char config[MAX_PARAM_LENGTH];
0048 module_param_string(netconsole, config, MAX_PARAM_LENGTH, 0);
0049 MODULE_PARM_DESC(netconsole, " netconsole=[src-port]@[src-ip]/[dev],[tgt-port]@<tgt-ip>/[tgt-macaddr]");
0050
0051 static bool oops_only = false;
0052 module_param(oops_only, bool, 0600);
0053 MODULE_PARM_DESC(oops_only, "Only log oops messages");
0054
0055 #ifndef MODULE
0056 static int __init option_setup(char *opt)
0057 {
0058 strlcpy(config, opt, MAX_PARAM_LENGTH);
0059 return 1;
0060 }
0061 __setup("netconsole=", option_setup);
0062 #endif
0063
0064
0065 static LIST_HEAD(target_list);
0066
0067
0068 static DEFINE_SPINLOCK(target_list_lock);
0069
0070
0071
0072
0073
0074 static struct console netconsole_ext;
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097 struct netconsole_target {
0098 struct list_head list;
0099 #ifdef CONFIG_NETCONSOLE_DYNAMIC
0100 struct config_item item;
0101 #endif
0102 bool enabled;
0103 bool extended;
0104 struct netpoll np;
0105 };
0106
0107 #ifdef CONFIG_NETCONSOLE_DYNAMIC
0108
0109 static struct configfs_subsystem netconsole_subsys;
0110 static DEFINE_MUTEX(dynamic_netconsole_mutex);
0111
0112 static int __init dynamic_netconsole_init(void)
0113 {
0114 config_group_init(&netconsole_subsys.su_group);
0115 mutex_init(&netconsole_subsys.su_mutex);
0116 return configfs_register_subsystem(&netconsole_subsys);
0117 }
0118
0119 static void __exit dynamic_netconsole_exit(void)
0120 {
0121 configfs_unregister_subsystem(&netconsole_subsys);
0122 }
0123
0124
0125
0126
0127
0128
0129 static void netconsole_target_get(struct netconsole_target *nt)
0130 {
0131 if (config_item_name(&nt->item))
0132 config_item_get(&nt->item);
0133 }
0134
0135 static void netconsole_target_put(struct netconsole_target *nt)
0136 {
0137 if (config_item_name(&nt->item))
0138 config_item_put(&nt->item);
0139 }
0140
0141 #else
0142
0143 static int __init dynamic_netconsole_init(void)
0144 {
0145 return 0;
0146 }
0147
0148 static void __exit dynamic_netconsole_exit(void)
0149 {
0150 }
0151
0152
0153
0154
0155
0156 static void netconsole_target_get(struct netconsole_target *nt)
0157 {
0158 }
0159
0160 static void netconsole_target_put(struct netconsole_target *nt)
0161 {
0162 }
0163
0164 #endif
0165
0166
0167 static struct netconsole_target *alloc_param_target(char *target_config)
0168 {
0169 int err = -ENOMEM;
0170 struct netconsole_target *nt;
0171
0172
0173
0174
0175
0176 nt = kzalloc(sizeof(*nt), GFP_KERNEL);
0177 if (!nt)
0178 goto fail;
0179
0180 nt->np.name = "netconsole";
0181 strlcpy(nt->np.dev_name, "eth0", IFNAMSIZ);
0182 nt->np.local_port = 6665;
0183 nt->np.remote_port = 6666;
0184 eth_broadcast_addr(nt->np.remote_mac);
0185
0186 if (*target_config == '+') {
0187 nt->extended = true;
0188 target_config++;
0189 }
0190
0191
0192 err = netpoll_parse_options(&nt->np, target_config);
0193 if (err)
0194 goto fail;
0195
0196 err = netpoll_setup(&nt->np);
0197 if (err)
0198 goto fail;
0199
0200 nt->enabled = true;
0201
0202 return nt;
0203
0204 fail:
0205 kfree(nt);
0206 return ERR_PTR(err);
0207 }
0208
0209
0210 static void free_param_target(struct netconsole_target *nt)
0211 {
0212 netpoll_cleanup(&nt->np);
0213 kfree(nt);
0214 }
0215
0216 #ifdef CONFIG_NETCONSOLE_DYNAMIC
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236 static struct netconsole_target *to_target(struct config_item *item)
0237 {
0238 return item ?
0239 container_of(item, struct netconsole_target, item) :
0240 NULL;
0241 }
0242
0243
0244
0245
0246
0247 static ssize_t enabled_show(struct config_item *item, char *buf)
0248 {
0249 return snprintf(buf, PAGE_SIZE, "%d\n", to_target(item)->enabled);
0250 }
0251
0252 static ssize_t extended_show(struct config_item *item, char *buf)
0253 {
0254 return snprintf(buf, PAGE_SIZE, "%d\n", to_target(item)->extended);
0255 }
0256
0257 static ssize_t dev_name_show(struct config_item *item, char *buf)
0258 {
0259 return snprintf(buf, PAGE_SIZE, "%s\n", to_target(item)->np.dev_name);
0260 }
0261
0262 static ssize_t local_port_show(struct config_item *item, char *buf)
0263 {
0264 return snprintf(buf, PAGE_SIZE, "%d\n", to_target(item)->np.local_port);
0265 }
0266
0267 static ssize_t remote_port_show(struct config_item *item, char *buf)
0268 {
0269 return snprintf(buf, PAGE_SIZE, "%d\n", to_target(item)->np.remote_port);
0270 }
0271
0272 static ssize_t local_ip_show(struct config_item *item, char *buf)
0273 {
0274 struct netconsole_target *nt = to_target(item);
0275
0276 if (nt->np.ipv6)
0277 return snprintf(buf, PAGE_SIZE, "%pI6c\n", &nt->np.local_ip.in6);
0278 else
0279 return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.local_ip);
0280 }
0281
0282 static ssize_t remote_ip_show(struct config_item *item, char *buf)
0283 {
0284 struct netconsole_target *nt = to_target(item);
0285
0286 if (nt->np.ipv6)
0287 return snprintf(buf, PAGE_SIZE, "%pI6c\n", &nt->np.remote_ip.in6);
0288 else
0289 return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.remote_ip);
0290 }
0291
0292 static ssize_t local_mac_show(struct config_item *item, char *buf)
0293 {
0294 struct net_device *dev = to_target(item)->np.dev;
0295 static const u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
0296
0297 return snprintf(buf, PAGE_SIZE, "%pM\n", dev ? dev->dev_addr : bcast);
0298 }
0299
0300 static ssize_t remote_mac_show(struct config_item *item, char *buf)
0301 {
0302 return snprintf(buf, PAGE_SIZE, "%pM\n", to_target(item)->np.remote_mac);
0303 }
0304
0305
0306
0307
0308
0309
0310
0311
0312 static ssize_t enabled_store(struct config_item *item,
0313 const char *buf, size_t count)
0314 {
0315 struct netconsole_target *nt = to_target(item);
0316 unsigned long flags;
0317 int enabled;
0318 int err;
0319
0320 mutex_lock(&dynamic_netconsole_mutex);
0321 err = kstrtoint(buf, 10, &enabled);
0322 if (err < 0)
0323 goto out_unlock;
0324
0325 err = -EINVAL;
0326 if (enabled < 0 || enabled > 1)
0327 goto out_unlock;
0328 if ((bool)enabled == nt->enabled) {
0329 pr_info("network logging has already %s\n",
0330 nt->enabled ? "started" : "stopped");
0331 goto out_unlock;
0332 }
0333
0334 if (enabled) {
0335 if (nt->extended && !(netconsole_ext.flags & CON_ENABLED)) {
0336 netconsole_ext.flags |= CON_ENABLED;
0337 register_console(&netconsole_ext);
0338 }
0339
0340
0341
0342
0343
0344 netpoll_print_options(&nt->np);
0345
0346 err = netpoll_setup(&nt->np);
0347 if (err)
0348 goto out_unlock;
0349
0350 pr_info("network logging started\n");
0351 } else {
0352
0353
0354
0355
0356 spin_lock_irqsave(&target_list_lock, flags);
0357 nt->enabled = false;
0358 spin_unlock_irqrestore(&target_list_lock, flags);
0359 netpoll_cleanup(&nt->np);
0360 }
0361
0362 nt->enabled = enabled;
0363
0364 mutex_unlock(&dynamic_netconsole_mutex);
0365 return strnlen(buf, count);
0366 out_unlock:
0367 mutex_unlock(&dynamic_netconsole_mutex);
0368 return err;
0369 }
0370
0371 static ssize_t extended_store(struct config_item *item, const char *buf,
0372 size_t count)
0373 {
0374 struct netconsole_target *nt = to_target(item);
0375 int extended;
0376 int err;
0377
0378 mutex_lock(&dynamic_netconsole_mutex);
0379 if (nt->enabled) {
0380 pr_err("target (%s) is enabled, disable to update parameters\n",
0381 config_item_name(&nt->item));
0382 err = -EINVAL;
0383 goto out_unlock;
0384 }
0385
0386 err = kstrtoint(buf, 10, &extended);
0387 if (err < 0)
0388 goto out_unlock;
0389 if (extended < 0 || extended > 1) {
0390 err = -EINVAL;
0391 goto out_unlock;
0392 }
0393
0394 nt->extended = extended;
0395
0396 mutex_unlock(&dynamic_netconsole_mutex);
0397 return strnlen(buf, count);
0398 out_unlock:
0399 mutex_unlock(&dynamic_netconsole_mutex);
0400 return err;
0401 }
0402
0403 static ssize_t dev_name_store(struct config_item *item, const char *buf,
0404 size_t count)
0405 {
0406 struct netconsole_target *nt = to_target(item);
0407 size_t len;
0408
0409 mutex_lock(&dynamic_netconsole_mutex);
0410 if (nt->enabled) {
0411 pr_err("target (%s) is enabled, disable to update parameters\n",
0412 config_item_name(&nt->item));
0413 mutex_unlock(&dynamic_netconsole_mutex);
0414 return -EINVAL;
0415 }
0416
0417 strlcpy(nt->np.dev_name, buf, IFNAMSIZ);
0418
0419
0420 len = strnlen(nt->np.dev_name, IFNAMSIZ);
0421 if (nt->np.dev_name[len - 1] == '\n')
0422 nt->np.dev_name[len - 1] = '\0';
0423
0424 mutex_unlock(&dynamic_netconsole_mutex);
0425 return strnlen(buf, count);
0426 }
0427
0428 static ssize_t local_port_store(struct config_item *item, const char *buf,
0429 size_t count)
0430 {
0431 struct netconsole_target *nt = to_target(item);
0432 int rv = -EINVAL;
0433
0434 mutex_lock(&dynamic_netconsole_mutex);
0435 if (nt->enabled) {
0436 pr_err("target (%s) is enabled, disable to update parameters\n",
0437 config_item_name(&nt->item));
0438 goto out_unlock;
0439 }
0440
0441 rv = kstrtou16(buf, 10, &nt->np.local_port);
0442 if (rv < 0)
0443 goto out_unlock;
0444 mutex_unlock(&dynamic_netconsole_mutex);
0445 return strnlen(buf, count);
0446 out_unlock:
0447 mutex_unlock(&dynamic_netconsole_mutex);
0448 return rv;
0449 }
0450
0451 static ssize_t remote_port_store(struct config_item *item,
0452 const char *buf, size_t count)
0453 {
0454 struct netconsole_target *nt = to_target(item);
0455 int rv = -EINVAL;
0456
0457 mutex_lock(&dynamic_netconsole_mutex);
0458 if (nt->enabled) {
0459 pr_err("target (%s) is enabled, disable to update parameters\n",
0460 config_item_name(&nt->item));
0461 goto out_unlock;
0462 }
0463
0464 rv = kstrtou16(buf, 10, &nt->np.remote_port);
0465 if (rv < 0)
0466 goto out_unlock;
0467 mutex_unlock(&dynamic_netconsole_mutex);
0468 return strnlen(buf, count);
0469 out_unlock:
0470 mutex_unlock(&dynamic_netconsole_mutex);
0471 return rv;
0472 }
0473
0474 static ssize_t local_ip_store(struct config_item *item, const char *buf,
0475 size_t count)
0476 {
0477 struct netconsole_target *nt = to_target(item);
0478
0479 mutex_lock(&dynamic_netconsole_mutex);
0480 if (nt->enabled) {
0481 pr_err("target (%s) is enabled, disable to update parameters\n",
0482 config_item_name(&nt->item));
0483 goto out_unlock;
0484 }
0485
0486 if (strnchr(buf, count, ':')) {
0487 const char *end;
0488 if (in6_pton(buf, count, nt->np.local_ip.in6.s6_addr, -1, &end) > 0) {
0489 if (*end && *end != '\n') {
0490 pr_err("invalid IPv6 address at: <%c>\n", *end);
0491 goto out_unlock;
0492 }
0493 nt->np.ipv6 = true;
0494 } else
0495 goto out_unlock;
0496 } else {
0497 if (!nt->np.ipv6) {
0498 nt->np.local_ip.ip = in_aton(buf);
0499 } else
0500 goto out_unlock;
0501 }
0502
0503 mutex_unlock(&dynamic_netconsole_mutex);
0504 return strnlen(buf, count);
0505 out_unlock:
0506 mutex_unlock(&dynamic_netconsole_mutex);
0507 return -EINVAL;
0508 }
0509
0510 static ssize_t remote_ip_store(struct config_item *item, const char *buf,
0511 size_t count)
0512 {
0513 struct netconsole_target *nt = to_target(item);
0514
0515 mutex_lock(&dynamic_netconsole_mutex);
0516 if (nt->enabled) {
0517 pr_err("target (%s) is enabled, disable to update parameters\n",
0518 config_item_name(&nt->item));
0519 goto out_unlock;
0520 }
0521
0522 if (strnchr(buf, count, ':')) {
0523 const char *end;
0524 if (in6_pton(buf, count, nt->np.remote_ip.in6.s6_addr, -1, &end) > 0) {
0525 if (*end && *end != '\n') {
0526 pr_err("invalid IPv6 address at: <%c>\n", *end);
0527 goto out_unlock;
0528 }
0529 nt->np.ipv6 = true;
0530 } else
0531 goto out_unlock;
0532 } else {
0533 if (!nt->np.ipv6) {
0534 nt->np.remote_ip.ip = in_aton(buf);
0535 } else
0536 goto out_unlock;
0537 }
0538
0539 mutex_unlock(&dynamic_netconsole_mutex);
0540 return strnlen(buf, count);
0541 out_unlock:
0542 mutex_unlock(&dynamic_netconsole_mutex);
0543 return -EINVAL;
0544 }
0545
0546 static ssize_t remote_mac_store(struct config_item *item, const char *buf,
0547 size_t count)
0548 {
0549 struct netconsole_target *nt = to_target(item);
0550 u8 remote_mac[ETH_ALEN];
0551
0552 mutex_lock(&dynamic_netconsole_mutex);
0553 if (nt->enabled) {
0554 pr_err("target (%s) is enabled, disable to update parameters\n",
0555 config_item_name(&nt->item));
0556 goto out_unlock;
0557 }
0558
0559 if (!mac_pton(buf, remote_mac))
0560 goto out_unlock;
0561 if (buf[3 * ETH_ALEN - 1] && buf[3 * ETH_ALEN - 1] != '\n')
0562 goto out_unlock;
0563 memcpy(nt->np.remote_mac, remote_mac, ETH_ALEN);
0564
0565 mutex_unlock(&dynamic_netconsole_mutex);
0566 return strnlen(buf, count);
0567 out_unlock:
0568 mutex_unlock(&dynamic_netconsole_mutex);
0569 return -EINVAL;
0570 }
0571
0572 CONFIGFS_ATTR(, enabled);
0573 CONFIGFS_ATTR(, extended);
0574 CONFIGFS_ATTR(, dev_name);
0575 CONFIGFS_ATTR(, local_port);
0576 CONFIGFS_ATTR(, remote_port);
0577 CONFIGFS_ATTR(, local_ip);
0578 CONFIGFS_ATTR(, remote_ip);
0579 CONFIGFS_ATTR_RO(, local_mac);
0580 CONFIGFS_ATTR(, remote_mac);
0581
0582 static struct configfs_attribute *netconsole_target_attrs[] = {
0583 &attr_enabled,
0584 &attr_extended,
0585 &attr_dev_name,
0586 &attr_local_port,
0587 &attr_remote_port,
0588 &attr_local_ip,
0589 &attr_remote_ip,
0590 &attr_local_mac,
0591 &attr_remote_mac,
0592 NULL,
0593 };
0594
0595
0596
0597
0598
0599 static void netconsole_target_release(struct config_item *item)
0600 {
0601 kfree(to_target(item));
0602 }
0603
0604 static struct configfs_item_operations netconsole_target_item_ops = {
0605 .release = netconsole_target_release,
0606 };
0607
0608 static const struct config_item_type netconsole_target_type = {
0609 .ct_attrs = netconsole_target_attrs,
0610 .ct_item_ops = &netconsole_target_item_ops,
0611 .ct_owner = THIS_MODULE,
0612 };
0613
0614
0615
0616
0617
0618 static struct config_item *make_netconsole_target(struct config_group *group,
0619 const char *name)
0620 {
0621 unsigned long flags;
0622 struct netconsole_target *nt;
0623
0624
0625
0626
0627
0628 nt = kzalloc(sizeof(*nt), GFP_KERNEL);
0629 if (!nt)
0630 return ERR_PTR(-ENOMEM);
0631
0632 nt->np.name = "netconsole";
0633 strlcpy(nt->np.dev_name, "eth0", IFNAMSIZ);
0634 nt->np.local_port = 6665;
0635 nt->np.remote_port = 6666;
0636 eth_broadcast_addr(nt->np.remote_mac);
0637
0638
0639 config_item_init_type_name(&nt->item, name, &netconsole_target_type);
0640
0641
0642 spin_lock_irqsave(&target_list_lock, flags);
0643 list_add(&nt->list, &target_list);
0644 spin_unlock_irqrestore(&target_list_lock, flags);
0645
0646 return &nt->item;
0647 }
0648
0649 static void drop_netconsole_target(struct config_group *group,
0650 struct config_item *item)
0651 {
0652 unsigned long flags;
0653 struct netconsole_target *nt = to_target(item);
0654
0655 spin_lock_irqsave(&target_list_lock, flags);
0656 list_del(&nt->list);
0657 spin_unlock_irqrestore(&target_list_lock, flags);
0658
0659
0660
0661
0662
0663 if (nt->enabled)
0664 netpoll_cleanup(&nt->np);
0665
0666 config_item_put(&nt->item);
0667 }
0668
0669 static struct configfs_group_operations netconsole_subsys_group_ops = {
0670 .make_item = make_netconsole_target,
0671 .drop_item = drop_netconsole_target,
0672 };
0673
0674 static const struct config_item_type netconsole_subsys_type = {
0675 .ct_group_ops = &netconsole_subsys_group_ops,
0676 .ct_owner = THIS_MODULE,
0677 };
0678
0679
0680 static struct configfs_subsystem netconsole_subsys = {
0681 .su_group = {
0682 .cg_item = {
0683 .ci_namebuf = "netconsole",
0684 .ci_type = &netconsole_subsys_type,
0685 },
0686 },
0687 };
0688
0689 #endif
0690
0691
0692 static int netconsole_netdev_event(struct notifier_block *this,
0693 unsigned long event, void *ptr)
0694 {
0695 unsigned long flags;
0696 struct netconsole_target *nt;
0697 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
0698 bool stopped = false;
0699
0700 if (!(event == NETDEV_CHANGENAME || event == NETDEV_UNREGISTER ||
0701 event == NETDEV_RELEASE || event == NETDEV_JOIN))
0702 goto done;
0703
0704 spin_lock_irqsave(&target_list_lock, flags);
0705 restart:
0706 list_for_each_entry(nt, &target_list, list) {
0707 netconsole_target_get(nt);
0708 if (nt->np.dev == dev) {
0709 switch (event) {
0710 case NETDEV_CHANGENAME:
0711 strlcpy(nt->np.dev_name, dev->name, IFNAMSIZ);
0712 break;
0713 case NETDEV_RELEASE:
0714 case NETDEV_JOIN:
0715 case NETDEV_UNREGISTER:
0716
0717
0718
0719 spin_unlock_irqrestore(&target_list_lock, flags);
0720
0721 __netpoll_cleanup(&nt->np);
0722
0723 spin_lock_irqsave(&target_list_lock, flags);
0724 netdev_put(nt->np.dev, &nt->np.dev_tracker);
0725 nt->np.dev = NULL;
0726 nt->enabled = false;
0727 stopped = true;
0728 netconsole_target_put(nt);
0729 goto restart;
0730 }
0731 }
0732 netconsole_target_put(nt);
0733 }
0734 spin_unlock_irqrestore(&target_list_lock, flags);
0735 if (stopped) {
0736 const char *msg = "had an event";
0737 switch (event) {
0738 case NETDEV_UNREGISTER:
0739 msg = "unregistered";
0740 break;
0741 case NETDEV_RELEASE:
0742 msg = "released slaves";
0743 break;
0744 case NETDEV_JOIN:
0745 msg = "is joining a master device";
0746 break;
0747 }
0748 pr_info("network logging stopped on interface %s as it %s\n",
0749 dev->name, msg);
0750 }
0751
0752 done:
0753 return NOTIFY_DONE;
0754 }
0755
0756 static struct notifier_block netconsole_netdev_notifier = {
0757 .notifier_call = netconsole_netdev_event,
0758 };
0759
0760
0761
0762
0763
0764
0765
0766
0767
0768
0769
0770 static void send_ext_msg_udp(struct netconsole_target *nt, const char *msg,
0771 int msg_len)
0772 {
0773 static char buf[MAX_PRINT_CHUNK];
0774 const char *header, *body;
0775 int offset = 0;
0776 int header_len, body_len;
0777
0778 if (msg_len <= MAX_PRINT_CHUNK) {
0779 netpoll_send_udp(&nt->np, msg, msg_len);
0780 return;
0781 }
0782
0783
0784 header = msg;
0785 body = memchr(msg, ';', msg_len);
0786 if (WARN_ON_ONCE(!body))
0787 return;
0788
0789 header_len = body - header;
0790 body_len = msg_len - header_len - 1;
0791 body++;
0792
0793
0794
0795
0796
0797 memcpy(buf, header, header_len);
0798
0799 while (offset < body_len) {
0800 int this_header = header_len;
0801 int this_chunk;
0802
0803 this_header += scnprintf(buf + this_header,
0804 sizeof(buf) - this_header,
0805 ",ncfrag=%d/%d;", offset, body_len);
0806
0807 this_chunk = min(body_len - offset,
0808 MAX_PRINT_CHUNK - this_header);
0809 if (WARN_ON_ONCE(this_chunk <= 0))
0810 return;
0811
0812 memcpy(buf + this_header, body + offset, this_chunk);
0813
0814 netpoll_send_udp(&nt->np, buf, this_header + this_chunk);
0815
0816 offset += this_chunk;
0817 }
0818 }
0819
0820 static void write_ext_msg(struct console *con, const char *msg,
0821 unsigned int len)
0822 {
0823 struct netconsole_target *nt;
0824 unsigned long flags;
0825
0826 if ((oops_only && !oops_in_progress) || list_empty(&target_list))
0827 return;
0828
0829 spin_lock_irqsave(&target_list_lock, flags);
0830 list_for_each_entry(nt, &target_list, list)
0831 if (nt->extended && nt->enabled && netif_running(nt->np.dev))
0832 send_ext_msg_udp(nt, msg, len);
0833 spin_unlock_irqrestore(&target_list_lock, flags);
0834 }
0835
0836 static void write_msg(struct console *con, const char *msg, unsigned int len)
0837 {
0838 int frag, left;
0839 unsigned long flags;
0840 struct netconsole_target *nt;
0841 const char *tmp;
0842
0843 if (oops_only && !oops_in_progress)
0844 return;
0845
0846 if (list_empty(&target_list))
0847 return;
0848
0849 spin_lock_irqsave(&target_list_lock, flags);
0850 list_for_each_entry(nt, &target_list, list) {
0851 if (!nt->extended && nt->enabled && netif_running(nt->np.dev)) {
0852
0853
0854
0855
0856
0857
0858 tmp = msg;
0859 for (left = len; left;) {
0860 frag = min(left, MAX_PRINT_CHUNK);
0861 netpoll_send_udp(&nt->np, tmp, frag);
0862 tmp += frag;
0863 left -= frag;
0864 }
0865 }
0866 }
0867 spin_unlock_irqrestore(&target_list_lock, flags);
0868 }
0869
0870 static struct console netconsole_ext = {
0871 .name = "netcon_ext",
0872 .flags = CON_EXTENDED,
0873 .write = write_ext_msg,
0874 };
0875
0876 static struct console netconsole = {
0877 .name = "netcon",
0878 .flags = CON_ENABLED,
0879 .write = write_msg,
0880 };
0881
0882 static int __init init_netconsole(void)
0883 {
0884 int err;
0885 struct netconsole_target *nt, *tmp;
0886 unsigned long flags;
0887 char *target_config;
0888 char *input = config;
0889
0890 if (strnlen(input, MAX_PARAM_LENGTH)) {
0891 while ((target_config = strsep(&input, ";"))) {
0892 nt = alloc_param_target(target_config);
0893 if (IS_ERR(nt)) {
0894 err = PTR_ERR(nt);
0895 goto fail;
0896 }
0897
0898 if (nt->extended)
0899 netconsole_ext.flags |= CON_PRINTBUFFER |
0900 CON_ENABLED;
0901 else
0902 netconsole.flags |= CON_PRINTBUFFER;
0903
0904 spin_lock_irqsave(&target_list_lock, flags);
0905 list_add(&nt->list, &target_list);
0906 spin_unlock_irqrestore(&target_list_lock, flags);
0907 }
0908 }
0909
0910 err = register_netdevice_notifier(&netconsole_netdev_notifier);
0911 if (err)
0912 goto fail;
0913
0914 err = dynamic_netconsole_init();
0915 if (err)
0916 goto undonotifier;
0917
0918 if (netconsole_ext.flags & CON_ENABLED)
0919 register_console(&netconsole_ext);
0920 register_console(&netconsole);
0921 pr_info("network logging started\n");
0922
0923 return err;
0924
0925 undonotifier:
0926 unregister_netdevice_notifier(&netconsole_netdev_notifier);
0927
0928 fail:
0929 pr_err("cleaning up\n");
0930
0931
0932
0933
0934
0935
0936 list_for_each_entry_safe(nt, tmp, &target_list, list) {
0937 list_del(&nt->list);
0938 free_param_target(nt);
0939 }
0940
0941 return err;
0942 }
0943
0944 static void __exit cleanup_netconsole(void)
0945 {
0946 struct netconsole_target *nt, *tmp;
0947
0948 unregister_console(&netconsole_ext);
0949 unregister_console(&netconsole);
0950 dynamic_netconsole_exit();
0951 unregister_netdevice_notifier(&netconsole_netdev_notifier);
0952
0953
0954
0955
0956
0957
0958
0959
0960
0961 list_for_each_entry_safe(nt, tmp, &target_list, list) {
0962 list_del(&nt->list);
0963 free_param_target(nt);
0964 }
0965 }
0966
0967
0968
0969
0970
0971
0972
0973 late_initcall(init_netconsole);
0974 module_exit(cleanup_netconsole);