cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

netconsole.c (24737B)


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