xref: /openbmc/linux/drivers/net/netconsole.c (revision 37744fee)
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 
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	/* MODULE */
63 
64 /* Linked list of all configured targets */
65 static LIST_HEAD(target_list);
66 
67 /* This needs to be a spinlock because write_msg() cannot sleep */
68 static 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  */
74 static 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  * @np:		The netpoll structure for this target.
87  *		Contains the other userspace visible parameters:
88  *		dev_name	(read-write)
89  *		local_port	(read-write)
90  *		remote_port	(read-write)
91  *		local_ip	(read-write)
92  *		remote_ip	(read-write)
93  *		local_mac	(read-only)
94  *		remote_mac	(read-write)
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  * Targets that were created by parsing the boot/module option string
125  * do not exist in the configfs hierarchy (and have NULL names) and will
126  * never go away, so make these a no-op for them.
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	/* !CONFIG_NETCONSOLE_DYNAMIC */
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  * No danger of targets going away from under us when dynamic
153  * reconfigurability is off.
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	/* CONFIG_NETCONSOLE_DYNAMIC */
164 
165 /* Allocate new target (from boot/module param) and setup netpoll for it */
166 static struct netconsole_target *alloc_param_target(char *target_config)
167 {
168 	int err = -ENOMEM;
169 	struct netconsole_target *nt;
170 
171 	/*
172 	 * Allocate and initialize with defaults.
173 	 * Note that these targets get their config_item fields zeroed-out.
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 	/* Parse parameters and setup netpoll */
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 /* Cleanup netpoll for given target (from boot/module param) and free it */
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  * Our subsystem hierarchy is:
219  *
220  * /sys/kernel/config/netconsole/
221  *				|
222  *				<target>/
223  *				|	enabled
224  *				|	dev_name
225  *				|	local_port
226  *				|	remote_port
227  *				|	local_ip
228  *				|	remote_ip
229  *				|	local_mac
230  *				|	remote_mac
231  *				|
232  *				<target>/...
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  * Attribute operations for netconsole_target.
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  * This one is special -- targets created through the configfs interface
306  * are not enabled (and the corresponding netpoll activated) by default.
307  * The user is expected to set the desired parameters first (which
308  * would enable him to dynamically add new netpoll targets for new
309  * network interfaces as and when they come up).
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) {	/* true */
334 		if (nt->extended && !(netconsole_ext.flags & CON_ENABLED)) {
335 			netconsole_ext.flags |= CON_ENABLED;
336 			register_console(&netconsole_ext);
337 		}
338 
339 		/*
340 		 * Skip netpoll_parse_options() -- all the attributes are
341 		 * already configured via configfs. Just print them out.
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 {	/* false */
351 		/* We need to disable the netconsole before cleaning it up
352 		 * otherwise we might end up in write_msg() with
353 		 * nt->np.dev == NULL and nt->enabled == true
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 	/* Get rid of possible trailing newline from echo(1) */
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  * Item operations and type for netconsole_target.
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  * Group operations and type for netconsole_subsys.
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 	 * Allocate and initialize with defaults.
625 	 * Target is disabled at creation (!enabled).
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 	/* Initialize the config_item member */
638 	config_item_init_type_name(&nt->item, name, &netconsole_target_type);
639 
640 	/* Adding, but it is disabled */
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 	 * The target may have never been enabled, or was manually disabled
660 	 * before being removed so netpoll may have already been cleaned up.
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 /* The netconsole configfs subsystem */
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	/* CONFIG_NETCONSOLE_DYNAMIC */
689 
690 /* Handle network interface device notifications */
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 				/* rtnl_lock already held
716 				 * we might sleep in __netpoll_cleanup()
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  * send_ext_msg_udp - send extended log message to target
761  * @nt: target to send message to
762  * @msg: extended log message to send
763  * @msg_len: length of message
764  *
765  * Transfer extended log @msg to @nt.  If @msg is longer than
766  * MAX_PRINT_CHUNK, it'll be split and transmitted in multiple chunks with
767  * ncfrag header field added to identify them.
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]; /* protected by target_list_lock */
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 	/* need to insert extra header fields, detect header and body */
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 	 * Transfer multiple chunks with the following extra header.
794 	 * "ncfrag=<byte-offset>/<total-bytes>"
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 	/* Avoid taking lock and disabling interrupts unnecessarily */
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 			 * We nest this inside the for-each-target loop above
853 			 * so that we're able to get as much logging out to
854 			 * at least one target if we die inside here, instead
855 			 * of unnecessarily keeping all targets in lock-step.
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,	/* starts disabled, registered on first use */
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 			/* Dump existing printks when we register */
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 	 * Remove all targets and destroy them (only targets created
932 	 * from the boot/module option exist here). Skipping the list
933 	 * lock is safe here, and netpoll_cleanup() will sleep.
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 	 * Targets created via configfs pin references on our module
954 	 * and would first be rmdir(2)'ed from userspace. We reach
955 	 * here only when they are already destroyed, and only those
956 	 * created from the boot/module option are left, so remove and
957 	 * destroy them. Skipping the list lock is safe here, and
958 	 * netpoll_cleanup() will sleep.
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  * Use late_initcall to ensure netconsole is
968  * initialized after network device driver if built-in.
969  *
970  * late_initcall() and module_init() are identical if built as module.
971  */
972 late_initcall(init_netconsole);
973 module_exit(cleanup_netconsole);
974