xref: /linux/drivers/net/netconsole.c (revision 4359a011e259a4608afc7fb3635370c9d4ba5943)
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  * @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  */
97 struct 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 
109 static struct configfs_subsystem netconsole_subsys;
110 static DEFINE_MUTEX(dynamic_netconsole_mutex);
111 
112 static 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 
119 static 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  */
129 static void netconsole_target_get(struct netconsole_target *nt)
130 {
131 	if (config_item_name(&nt->item))
132 		config_item_get(&nt->item);
133 }
134 
135 static 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 
143 static int __init dynamic_netconsole_init(void)
144 {
145 	return 0;
146 }
147 
148 static 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  */
156 static void netconsole_target_get(struct netconsole_target *nt)
157 {
158 }
159 
160 static 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 */
167 static 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 
204 fail:
205 	kfree(nt);
206 	return ERR_PTR(err);
207 }
208 
209 /* Cleanup netpoll for given target (from boot/module param) and free it */
210 static 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 
236 static 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 
247 static 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 
252 static 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 
257 static 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 
262 static 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 
267 static 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 
272 static 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 
282 static 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 
292 static 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 
300 static 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  */
312 static 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);
366 out_unlock:
367 	mutex_unlock(&dynamic_netconsole_mutex);
368 	return err;
369 }
370 
371 static 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);
398 out_unlock:
399 	mutex_unlock(&dynamic_netconsole_mutex);
400 	return err;
401 }
402 
403 static 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 
428 static 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);
446 out_unlock:
447 	mutex_unlock(&dynamic_netconsole_mutex);
448 	return rv;
449 }
450 
451 static 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);
469 out_unlock:
470 	mutex_unlock(&dynamic_netconsole_mutex);
471 	return rv;
472 }
473 
474 static 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);
505 out_unlock:
506 	mutex_unlock(&dynamic_netconsole_mutex);
507 	return -EINVAL;
508 }
509 
510 static 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);
541 out_unlock:
542 	mutex_unlock(&dynamic_netconsole_mutex);
543 	return -EINVAL;
544 }
545 
546 static 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);
567 out_unlock:
568 	mutex_unlock(&dynamic_netconsole_mutex);
569 	return -EINVAL;
570 }
571 
572 CONFIGFS_ATTR(, enabled);
573 CONFIGFS_ATTR(, extended);
574 CONFIGFS_ATTR(, dev_name);
575 CONFIGFS_ATTR(, local_port);
576 CONFIGFS_ATTR(, remote_port);
577 CONFIGFS_ATTR(, local_ip);
578 CONFIGFS_ATTR(, remote_ip);
579 CONFIGFS_ATTR_RO(, local_mac);
580 CONFIGFS_ATTR(, remote_mac);
581 
582 static 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 
599 static void netconsole_target_release(struct config_item *item)
600 {
601 	kfree(to_target(item));
602 }
603 
604 static struct configfs_item_operations netconsole_target_item_ops = {
605 	.release		= netconsole_target_release,
606 };
607 
608 static 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 
618 static 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 
649 static 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 
669 static struct configfs_group_operations netconsole_subsys_group_ops = {
670 	.make_item	= make_netconsole_target,
671 	.drop_item	= drop_netconsole_target,
672 };
673 
674 static 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 */
680 static 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 */
692 static 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);
705 restart:
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 				netdev_put(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 
752 done:
753 	return NOTIFY_DONE;
754 }
755 
756 static 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  */
770 static 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 
820 static 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 
836 static 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 
870 static 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 
876 static struct console netconsole = {
877 	.name	= "netcon",
878 	.flags	= CON_ENABLED,
879 	.write	= write_msg,
880 };
881 
882 static 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 
925 undonotifier:
926 	unregister_netdevice_notifier(&netconsole_netdev_notifier);
927 
928 fail:
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 
944 static 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  */
973 late_initcall(init_netconsole);
974 module_exit(cleanup_netconsole);
975