Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  linux/drivers/net/netconsole.c
0004  *
0005  *  Copyright (C) 2001  Ingo Molnar <mingo@redhat.com>
0006  *
0007  *  This file contains the implementation of an IRQ-safe, crash-safe
0008  *  kernel console implementation that outputs kernel messages to the
0009  *  network.
0010  *
0011  * Modification history:
0012  *
0013  * 2001-09-17    started by Ingo Molnar.
0014  * 2003-08-11    2.6 port by Matt Mackall
0015  *               simplified options
0016  *               generic card hooks
0017  *               works non-modular
0018  * 2003-09-07    rewritten with netpoll api
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  /* MODULE */
0063 
0064 /* Linked list of all configured targets */
0065 static LIST_HEAD(target_list);
0066 
0067 /* This needs to be a spinlock because write_msg() cannot sleep */
0068 static DEFINE_SPINLOCK(target_list_lock);
0069 
0070 /*
0071  * Console driver for extended netconsoles.  Registered on the first use to
0072  * avoid unnecessarily enabling ext message formatting.
0073  */
0074 static struct console netconsole_ext;
0075 
0076 /**
0077  * struct netconsole_target - Represents a configured netconsole target.
0078  * @list:   Links this target into the target_list.
0079  * @item:   Links us into the configfs subsystem hierarchy.
0080  * @enabled:    On / off knob to enable / disable target.
0081  *      Visible from userspace (read-write).
0082  *      We maintain a strict 1:1 correspondence between this and
0083  *      whether the corresponding netpoll is active or inactive.
0084  *      Also, other parameters of a target may be modified at
0085  *      runtime only when it is disabled (enabled == 0).
0086  * @extended:   Denotes whether console is extended or not.
0087  * @np:     The netpoll structure for this target.
0088  *      Contains the other userspace visible parameters:
0089  *      dev_name    (read-write)
0090  *      local_port  (read-write)
0091  *      remote_port (read-write)
0092  *      local_ip    (read-write)
0093  *      remote_ip   (read-write)
0094  *      local_mac   (read-only)
0095  *      remote_mac  (read-write)
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  * Targets that were created by parsing the boot/module option string
0126  * do not exist in the configfs hierarchy (and have NULL names) and will
0127  * never go away, so make these a no-op for them.
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   /* !CONFIG_NETCONSOLE_DYNAMIC */
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  * No danger of targets going away from under us when dynamic
0154  * reconfigurability is off.
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  /* CONFIG_NETCONSOLE_DYNAMIC */
0165 
0166 /* Allocate new target (from boot/module param) and setup netpoll for it */
0167 static struct netconsole_target *alloc_param_target(char *target_config)
0168 {
0169     int err = -ENOMEM;
0170     struct netconsole_target *nt;
0171 
0172     /*
0173      * Allocate and initialize with defaults.
0174      * Note that these targets get their config_item fields zeroed-out.
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     /* Parse parameters and setup netpoll */
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 /* Cleanup netpoll for given target (from boot/module param) and free it */
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  * Our subsystem hierarchy is:
0220  *
0221  * /sys/kernel/config/netconsole/
0222  *              |
0223  *              <target>/
0224  *              |   enabled
0225  *              |   dev_name
0226  *              |   local_port
0227  *              |   remote_port
0228  *              |   local_ip
0229  *              |   remote_ip
0230  *              |   local_mac
0231  *              |   remote_mac
0232  *              |
0233  *              <target>/...
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  * Attribute operations for netconsole_target.
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  * This one is special -- targets created through the configfs interface
0307  * are not enabled (and the corresponding netpoll activated) by default.
0308  * The user is expected to set the desired parameters first (which
0309  * would enable him to dynamically add new netpoll targets for new
0310  * network interfaces as and when they come up).
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) {  /* true */
0335         if (nt->extended && !(netconsole_ext.flags & CON_ENABLED)) {
0336             netconsole_ext.flags |= CON_ENABLED;
0337             register_console(&netconsole_ext);
0338         }
0339 
0340         /*
0341          * Skip netpoll_parse_options() -- all the attributes are
0342          * already configured via configfs. Just print them out.
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 {    /* false */
0352         /* We need to disable the netconsole before cleaning it up
0353          * otherwise we might end up in write_msg() with
0354          * nt->np.dev == NULL and nt->enabled == true
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     /* Get rid of possible trailing newline from echo(1) */
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  * Item operations and type for netconsole_target.
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  * Group operations and type for netconsole_subsys.
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      * Allocate and initialize with defaults.
0626      * Target is disabled at creation (!enabled).
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     /* Initialize the config_item member */
0639     config_item_init_type_name(&nt->item, name, &netconsole_target_type);
0640 
0641     /* Adding, but it is disabled */
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      * The target may have never been enabled, or was manually disabled
0661      * before being removed so netpoll may have already been cleaned up.
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 /* The netconsole configfs subsystem */
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  /* CONFIG_NETCONSOLE_DYNAMIC */
0690 
0691 /* Handle network interface device notifications */
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                 /* rtnl_lock already held
0717                  * we might sleep in __netpoll_cleanup()
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  * send_ext_msg_udp - send extended log message to target
0762  * @nt: target to send message to
0763  * @msg: extended log message to send
0764  * @msg_len: length of message
0765  *
0766  * Transfer extended log @msg to @nt.  If @msg is longer than
0767  * MAX_PRINT_CHUNK, it'll be split and transmitted in multiple chunks with
0768  * ncfrag header field added to identify them.
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]; /* protected by target_list_lock */
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     /* need to insert extra header fields, detect header and body */
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      * Transfer multiple chunks with the following extra header.
0795      * "ncfrag=<byte-offset>/<total-bytes>"
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     /* Avoid taking lock and disabling interrupts unnecessarily */
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              * We nest this inside the for-each-target loop above
0854              * so that we're able to get as much logging out to
0855              * at least one target if we die inside here, instead
0856              * of unnecessarily keeping all targets in lock-step.
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, /* starts disabled, registered on first use */
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             /* Dump existing printks when we register */
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      * Remove all targets and destroy them (only targets created
0933      * from the boot/module option exist here). Skipping the list
0934      * lock is safe here, and netpoll_cleanup() will sleep.
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      * Targets created via configfs pin references on our module
0955      * and would first be rmdir(2)'ed from userspace. We reach
0956      * here only when they are already destroyed, and only those
0957      * created from the boot/module option are left, so remove and
0958      * destroy them. Skipping the list lock is safe here, and
0959      * netpoll_cleanup() will sleep.
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  * Use late_initcall to ensure netconsole is
0969  * initialized after network device driver if built-in.
0970  *
0971  * late_initcall() and module_init() are identical if built as module.
0972  */
0973 late_initcall(init_netconsole);
0974 module_exit(cleanup_netconsole);