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 #include <linux/u64_stats_sync.h>
40 #include <linux/utsname.h>
41 #include <linux/rtnetlink.h>
42
43 MODULE_AUTHOR("Matt Mackall <mpm@selenic.com>");
44 MODULE_DESCRIPTION("Console driver for network interfaces");
45 MODULE_LICENSE("GPL");
46
47 #define MAX_PARAM_LENGTH 256
48 #define MAX_EXTRADATA_ENTRY_LEN 256
49 #define MAX_EXTRADATA_VALUE_LEN 200
50 /* The number 3 comes from userdata entry format characters (' ', '=', '\n') */
51 #define MAX_EXTRADATA_NAME_LEN (MAX_EXTRADATA_ENTRY_LEN - \
52 MAX_EXTRADATA_VALUE_LEN - 3)
53 #define MAX_EXTRADATA_ITEMS 16
54 #define MAX_PRINT_CHUNK 1000
55
56 static char config[MAX_PARAM_LENGTH];
57 module_param_string(netconsole, config, MAX_PARAM_LENGTH, 0);
58 MODULE_PARM_DESC(netconsole, " netconsole=[src-port]@[src-ip]/[dev],[tgt-port]@<tgt-ip>/[tgt-macaddr]");
59
60 static bool oops_only;
61 module_param(oops_only, bool, 0600);
62 MODULE_PARM_DESC(oops_only, "Only log oops messages");
63
64 #define NETCONSOLE_PARAM_TARGET_PREFIX "cmdline"
65
66 #ifndef MODULE
option_setup(char * opt)67 static int __init option_setup(char *opt)
68 {
69 strscpy(config, opt, MAX_PARAM_LENGTH);
70 return 1;
71 }
72 __setup("netconsole=", option_setup);
73 #endif /* MODULE */
74
75 /* Linked list of all configured targets */
76 static LIST_HEAD(target_list);
77 /* target_cleanup_list is used to track targets that need to be cleaned outside
78 * of target_list_lock. It should be cleaned in the same function it is
79 * populated.
80 */
81 static LIST_HEAD(target_cleanup_list);
82
83 /* This needs to be a spinlock because write_msg() cannot sleep */
84 static DEFINE_SPINLOCK(target_list_lock);
85 /* This needs to be a mutex because netpoll_cleanup might sleep */
86 static DEFINE_MUTEX(target_cleanup_list_lock);
87
88 /*
89 * Console driver for extended netconsoles. Registered on the first use to
90 * avoid unnecessarily enabling ext message formatting.
91 */
92 static struct console netconsole_ext;
93
94 struct netconsole_target_stats {
95 u64_stats_t xmit_drop_count;
96 u64_stats_t enomem_count;
97 struct u64_stats_sync syncp;
98 };
99
100 /* Features enabled in sysdata. Contrary to userdata, this data is populated by
101 * the kernel. The fields are designed as bitwise flags, allowing multiple
102 * features to be set in sysdata_fields.
103 */
104 enum sysdata_feature {
105 /* Populate the CPU that sends the message */
106 SYSDATA_CPU_NR = BIT(0),
107 /* Populate the task name (as in current->comm) in sysdata */
108 SYSDATA_TASKNAME = BIT(1),
109 /* Kernel release/version as part of sysdata */
110 SYSDATA_RELEASE = BIT(2),
111 };
112
113 /**
114 * struct netconsole_target - Represents a configured netconsole target.
115 * @list: Links this target into the target_list.
116 * @group: Links us into the configfs subsystem hierarchy.
117 * @userdata_group: Links to the userdata configfs hierarchy
118 * @extradata_complete: Cached, formatted string of append
119 * @userdata_length: String length of usedata in extradata_complete.
120 * @sysdata_fields: Sysdata features enabled.
121 * @stats: Packet send stats for the target. Used for debugging.
122 * @enabled: On / off knob to enable / disable target.
123 * Visible from userspace (read-write).
124 * We maintain a strict 1:1 correspondence between this and
125 * whether the corresponding netpoll is active or inactive.
126 * Also, other parameters of a target may be modified at
127 * runtime only when it is disabled (enabled == 0).
128 * @extended: Denotes whether console is extended or not.
129 * @release: Denotes whether kernel release version should be prepended
130 * to the message. Depends on extended console.
131 * @np: The netpoll structure for this target.
132 * Contains the other userspace visible parameters:
133 * dev_name (read-write)
134 * local_port (read-write)
135 * remote_port (read-write)
136 * local_ip (read-write)
137 * remote_ip (read-write)
138 * local_mac (read-only)
139 * remote_mac (read-write)
140 * @buf: The buffer used to send the full msg to the network stack
141 */
142 struct netconsole_target {
143 struct list_head list;
144 #ifdef CONFIG_NETCONSOLE_DYNAMIC
145 struct config_group group;
146 struct config_group userdata_group;
147 char extradata_complete[MAX_EXTRADATA_ENTRY_LEN * MAX_EXTRADATA_ITEMS];
148 size_t userdata_length;
149 /* bit-wise with sysdata_feature bits */
150 u32 sysdata_fields;
151 #endif
152 struct netconsole_target_stats stats;
153 bool enabled;
154 bool extended;
155 bool release;
156 struct netpoll np;
157 /* protected by target_list_lock */
158 char buf[MAX_PRINT_CHUNK];
159 };
160
161 #ifdef CONFIG_NETCONSOLE_DYNAMIC
162
163 static struct configfs_subsystem netconsole_subsys;
164 static DEFINE_MUTEX(dynamic_netconsole_mutex);
165
dynamic_netconsole_init(void)166 static int __init dynamic_netconsole_init(void)
167 {
168 config_group_init(&netconsole_subsys.su_group);
169 mutex_init(&netconsole_subsys.su_mutex);
170 return configfs_register_subsystem(&netconsole_subsys);
171 }
172
dynamic_netconsole_exit(void)173 static void __exit dynamic_netconsole_exit(void)
174 {
175 configfs_unregister_subsystem(&netconsole_subsys);
176 }
177
178 /*
179 * Targets that were created by parsing the boot/module option string
180 * do not exist in the configfs hierarchy (and have NULL names) and will
181 * never go away, so make these a no-op for them.
182 */
netconsole_target_get(struct netconsole_target * nt)183 static void netconsole_target_get(struct netconsole_target *nt)
184 {
185 if (config_item_name(&nt->group.cg_item))
186 config_group_get(&nt->group);
187 }
188
netconsole_target_put(struct netconsole_target * nt)189 static void netconsole_target_put(struct netconsole_target *nt)
190 {
191 if (config_item_name(&nt->group.cg_item))
192 config_group_put(&nt->group);
193 }
194
195 #else /* !CONFIG_NETCONSOLE_DYNAMIC */
196
dynamic_netconsole_init(void)197 static int __init dynamic_netconsole_init(void)
198 {
199 return 0;
200 }
201
dynamic_netconsole_exit(void)202 static void __exit dynamic_netconsole_exit(void)
203 {
204 }
205
206 /*
207 * No danger of targets going away from under us when dynamic
208 * reconfigurability is off.
209 */
netconsole_target_get(struct netconsole_target * nt)210 static void netconsole_target_get(struct netconsole_target *nt)
211 {
212 }
213
netconsole_target_put(struct netconsole_target * nt)214 static void netconsole_target_put(struct netconsole_target *nt)
215 {
216 }
217
populate_configfs_item(struct netconsole_target * nt,int cmdline_count)218 static void populate_configfs_item(struct netconsole_target *nt,
219 int cmdline_count)
220 {
221 }
222 #endif /* CONFIG_NETCONSOLE_DYNAMIC */
223
224 /* Allocate and initialize with defaults.
225 * Note that these targets get their config_item fields zeroed-out.
226 */
alloc_and_init(void)227 static struct netconsole_target *alloc_and_init(void)
228 {
229 struct netconsole_target *nt;
230
231 nt = kzalloc(sizeof(*nt), GFP_KERNEL);
232 if (!nt)
233 return nt;
234
235 if (IS_ENABLED(CONFIG_NETCONSOLE_EXTENDED_LOG))
236 nt->extended = true;
237 if (IS_ENABLED(CONFIG_NETCONSOLE_PREPEND_RELEASE))
238 nt->release = true;
239
240 nt->np.name = "netconsole";
241 strscpy(nt->np.dev_name, "eth0", IFNAMSIZ);
242 nt->np.local_port = 6665;
243 nt->np.remote_port = 6666;
244 eth_broadcast_addr(nt->np.remote_mac);
245
246 return nt;
247 }
248
249 /* Clean up every target in the cleanup_list and move the clean targets back to
250 * the main target_list.
251 */
netconsole_process_cleanups_core(void)252 static void netconsole_process_cleanups_core(void)
253 {
254 struct netconsole_target *nt, *tmp;
255 unsigned long flags;
256
257 /* The cleanup needs RTNL locked */
258 ASSERT_RTNL();
259
260 mutex_lock(&target_cleanup_list_lock);
261 list_for_each_entry_safe(nt, tmp, &target_cleanup_list, list) {
262 /* all entries in the cleanup_list needs to be disabled */
263 WARN_ON_ONCE(nt->enabled);
264 do_netpoll_cleanup(&nt->np);
265 /* moved the cleaned target to target_list. Need to hold both
266 * locks
267 */
268 spin_lock_irqsave(&target_list_lock, flags);
269 list_move(&nt->list, &target_list);
270 spin_unlock_irqrestore(&target_list_lock, flags);
271 }
272 WARN_ON_ONCE(!list_empty(&target_cleanup_list));
273 mutex_unlock(&target_cleanup_list_lock);
274 }
275
276 #ifdef CONFIG_NETCONSOLE_DYNAMIC
277
278 /*
279 * Our subsystem hierarchy is:
280 *
281 * /sys/kernel/config/netconsole/
282 * |
283 * <target>/
284 * | enabled
285 * | release
286 * | dev_name
287 * | local_port
288 * | remote_port
289 * | local_ip
290 * | remote_ip
291 * | local_mac
292 * | remote_mac
293 * | transmit_errors
294 * | userdata/
295 * | <key>/
296 * | value
297 * | ...
298 * |
299 * <target>/...
300 */
301
to_target(struct config_item * item)302 static struct netconsole_target *to_target(struct config_item *item)
303 {
304 struct config_group *cfg_group;
305
306 cfg_group = to_config_group(item);
307 if (!cfg_group)
308 return NULL;
309 return container_of(to_config_group(item),
310 struct netconsole_target, group);
311 }
312
313 /* Do the list cleanup with the rtnl lock hold. rtnl lock is necessary because
314 * netdev might be cleaned-up by calling __netpoll_cleanup(),
315 */
netconsole_process_cleanups(void)316 static void netconsole_process_cleanups(void)
317 {
318 /* rtnl lock is called here, because it has precedence over
319 * target_cleanup_list_lock mutex and target_cleanup_list
320 */
321 rtnl_lock();
322 netconsole_process_cleanups_core();
323 rtnl_unlock();
324 }
325
326 /* Get rid of possible trailing newline, returning the new length */
trim_newline(char * s,size_t maxlen)327 static void trim_newline(char *s, size_t maxlen)
328 {
329 size_t len;
330
331 len = strnlen(s, maxlen);
332 if (s[len - 1] == '\n')
333 s[len - 1] = '\0';
334 }
335
336 /*
337 * Attribute operations for netconsole_target.
338 */
339
enabled_show(struct config_item * item,char * buf)340 static ssize_t enabled_show(struct config_item *item, char *buf)
341 {
342 return sysfs_emit(buf, "%d\n", to_target(item)->enabled);
343 }
344
extended_show(struct config_item * item,char * buf)345 static ssize_t extended_show(struct config_item *item, char *buf)
346 {
347 return sysfs_emit(buf, "%d\n", to_target(item)->extended);
348 }
349
release_show(struct config_item * item,char * buf)350 static ssize_t release_show(struct config_item *item, char *buf)
351 {
352 return sysfs_emit(buf, "%d\n", to_target(item)->release);
353 }
354
dev_name_show(struct config_item * item,char * buf)355 static ssize_t dev_name_show(struct config_item *item, char *buf)
356 {
357 return sysfs_emit(buf, "%s\n", to_target(item)->np.dev_name);
358 }
359
local_port_show(struct config_item * item,char * buf)360 static ssize_t local_port_show(struct config_item *item, char *buf)
361 {
362 return sysfs_emit(buf, "%d\n", to_target(item)->np.local_port);
363 }
364
remote_port_show(struct config_item * item,char * buf)365 static ssize_t remote_port_show(struct config_item *item, char *buf)
366 {
367 return sysfs_emit(buf, "%d\n", to_target(item)->np.remote_port);
368 }
369
local_ip_show(struct config_item * item,char * buf)370 static ssize_t local_ip_show(struct config_item *item, char *buf)
371 {
372 struct netconsole_target *nt = to_target(item);
373
374 if (nt->np.ipv6)
375 return sysfs_emit(buf, "%pI6c\n", &nt->np.local_ip.in6);
376 else
377 return sysfs_emit(buf, "%pI4\n", &nt->np.local_ip);
378 }
379
remote_ip_show(struct config_item * item,char * buf)380 static ssize_t remote_ip_show(struct config_item *item, char *buf)
381 {
382 struct netconsole_target *nt = to_target(item);
383
384 if (nt->np.ipv6)
385 return sysfs_emit(buf, "%pI6c\n", &nt->np.remote_ip.in6);
386 else
387 return sysfs_emit(buf, "%pI4\n", &nt->np.remote_ip);
388 }
389
local_mac_show(struct config_item * item,char * buf)390 static ssize_t local_mac_show(struct config_item *item, char *buf)
391 {
392 struct net_device *dev = to_target(item)->np.dev;
393 static const u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
394
395 return sysfs_emit(buf, "%pM\n", dev ? dev->dev_addr : bcast);
396 }
397
remote_mac_show(struct config_item * item,char * buf)398 static ssize_t remote_mac_show(struct config_item *item, char *buf)
399 {
400 return sysfs_emit(buf, "%pM\n", to_target(item)->np.remote_mac);
401 }
402
transmit_errors_show(struct config_item * item,char * buf)403 static ssize_t transmit_errors_show(struct config_item *item, char *buf)
404 {
405 struct netconsole_target *nt = to_target(item);
406 u64 xmit_drop_count, enomem_count;
407 unsigned int start;
408
409 do {
410 start = u64_stats_fetch_begin(&nt->stats.syncp);
411 xmit_drop_count = u64_stats_read(&nt->stats.xmit_drop_count);
412 enomem_count = u64_stats_read(&nt->stats.enomem_count);
413 } while (u64_stats_fetch_retry(&nt->stats.syncp, start));
414
415 return sysfs_emit(buf, "%llu\n", xmit_drop_count + enomem_count);
416 }
417
418 /* configfs helper to display if cpu_nr sysdata feature is enabled */
sysdata_cpu_nr_enabled_show(struct config_item * item,char * buf)419 static ssize_t sysdata_cpu_nr_enabled_show(struct config_item *item, char *buf)
420 {
421 struct netconsole_target *nt = to_target(item->ci_parent);
422 bool cpu_nr_enabled;
423
424 mutex_lock(&dynamic_netconsole_mutex);
425 cpu_nr_enabled = !!(nt->sysdata_fields & SYSDATA_CPU_NR);
426 mutex_unlock(&dynamic_netconsole_mutex);
427
428 return sysfs_emit(buf, "%d\n", cpu_nr_enabled);
429 }
430
431 /* configfs helper to display if taskname sysdata feature is enabled */
sysdata_taskname_enabled_show(struct config_item * item,char * buf)432 static ssize_t sysdata_taskname_enabled_show(struct config_item *item,
433 char *buf)
434 {
435 struct netconsole_target *nt = to_target(item->ci_parent);
436 bool taskname_enabled;
437
438 mutex_lock(&dynamic_netconsole_mutex);
439 taskname_enabled = !!(nt->sysdata_fields & SYSDATA_TASKNAME);
440 mutex_unlock(&dynamic_netconsole_mutex);
441
442 return sysfs_emit(buf, "%d\n", taskname_enabled);
443 }
444
sysdata_release_enabled_show(struct config_item * item,char * buf)445 static ssize_t sysdata_release_enabled_show(struct config_item *item,
446 char *buf)
447 {
448 struct netconsole_target *nt = to_target(item->ci_parent);
449 bool release_enabled;
450
451 mutex_lock(&dynamic_netconsole_mutex);
452 release_enabled = !!(nt->sysdata_fields & SYSDATA_TASKNAME);
453 mutex_unlock(&dynamic_netconsole_mutex);
454
455 return sysfs_emit(buf, "%d\n", release_enabled);
456 }
457
458 /*
459 * This one is special -- targets created through the configfs interface
460 * are not enabled (and the corresponding netpoll activated) by default.
461 * The user is expected to set the desired parameters first (which
462 * would enable him to dynamically add new netpoll targets for new
463 * network interfaces as and when they come up).
464 */
enabled_store(struct config_item * item,const char * buf,size_t count)465 static ssize_t enabled_store(struct config_item *item,
466 const char *buf, size_t count)
467 {
468 struct netconsole_target *nt = to_target(item);
469 unsigned long flags;
470 bool enabled;
471 ssize_t ret;
472
473 mutex_lock(&dynamic_netconsole_mutex);
474 ret = kstrtobool(buf, &enabled);
475 if (ret)
476 goto out_unlock;
477
478 ret = -EINVAL;
479 if (enabled == nt->enabled) {
480 pr_info("network logging has already %s\n",
481 nt->enabled ? "started" : "stopped");
482 goto out_unlock;
483 }
484
485 if (enabled) { /* true */
486 if (nt->release && !nt->extended) {
487 pr_err("Not enabling netconsole. Release feature requires extended log message");
488 goto out_unlock;
489 }
490
491 if (nt->extended && !console_is_registered(&netconsole_ext))
492 register_console(&netconsole_ext);
493
494 /*
495 * Skip netpoll_parse_options() -- all the attributes are
496 * already configured via configfs. Just print them out.
497 */
498 netpoll_print_options(&nt->np);
499
500 ret = netpoll_setup(&nt->np);
501 if (ret)
502 goto out_unlock;
503
504 nt->enabled = true;
505 pr_info("network logging started\n");
506 } else { /* false */
507 /* We need to disable the netconsole before cleaning it up
508 * otherwise we might end up in write_msg() with
509 * nt->np.dev == NULL and nt->enabled == true
510 */
511 mutex_lock(&target_cleanup_list_lock);
512 spin_lock_irqsave(&target_list_lock, flags);
513 nt->enabled = false;
514 /* Remove the target from the list, while holding
515 * target_list_lock
516 */
517 list_move(&nt->list, &target_cleanup_list);
518 spin_unlock_irqrestore(&target_list_lock, flags);
519 mutex_unlock(&target_cleanup_list_lock);
520 }
521
522 ret = strnlen(buf, count);
523 /* Deferred cleanup */
524 netconsole_process_cleanups();
525 out_unlock:
526 mutex_unlock(&dynamic_netconsole_mutex);
527 return ret;
528 }
529
release_store(struct config_item * item,const char * buf,size_t count)530 static ssize_t release_store(struct config_item *item, const char *buf,
531 size_t count)
532 {
533 struct netconsole_target *nt = to_target(item);
534 bool release;
535 ssize_t ret;
536
537 mutex_lock(&dynamic_netconsole_mutex);
538 if (nt->enabled) {
539 pr_err("target (%s) is enabled, disable to update parameters\n",
540 config_item_name(&nt->group.cg_item));
541 ret = -EINVAL;
542 goto out_unlock;
543 }
544
545 ret = kstrtobool(buf, &release);
546 if (ret)
547 goto out_unlock;
548
549 nt->release = release;
550
551 ret = strnlen(buf, count);
552 out_unlock:
553 mutex_unlock(&dynamic_netconsole_mutex);
554 return ret;
555 }
556
extended_store(struct config_item * item,const char * buf,size_t count)557 static ssize_t extended_store(struct config_item *item, const char *buf,
558 size_t count)
559 {
560 struct netconsole_target *nt = to_target(item);
561 bool extended;
562 ssize_t ret;
563
564 mutex_lock(&dynamic_netconsole_mutex);
565 if (nt->enabled) {
566 pr_err("target (%s) is enabled, disable to update parameters\n",
567 config_item_name(&nt->group.cg_item));
568 ret = -EINVAL;
569 goto out_unlock;
570 }
571
572 ret = kstrtobool(buf, &extended);
573 if (ret)
574 goto out_unlock;
575
576 nt->extended = extended;
577 ret = strnlen(buf, count);
578 out_unlock:
579 mutex_unlock(&dynamic_netconsole_mutex);
580 return ret;
581 }
582
dev_name_store(struct config_item * item,const char * buf,size_t count)583 static ssize_t dev_name_store(struct config_item *item, const char *buf,
584 size_t count)
585 {
586 struct netconsole_target *nt = to_target(item);
587
588 mutex_lock(&dynamic_netconsole_mutex);
589 if (nt->enabled) {
590 pr_err("target (%s) is enabled, disable to update parameters\n",
591 config_item_name(&nt->group.cg_item));
592 mutex_unlock(&dynamic_netconsole_mutex);
593 return -EINVAL;
594 }
595
596 strscpy(nt->np.dev_name, buf, IFNAMSIZ);
597 trim_newline(nt->np.dev_name, IFNAMSIZ);
598
599 mutex_unlock(&dynamic_netconsole_mutex);
600 return strnlen(buf, count);
601 }
602
local_port_store(struct config_item * item,const char * buf,size_t count)603 static ssize_t local_port_store(struct config_item *item, const char *buf,
604 size_t count)
605 {
606 struct netconsole_target *nt = to_target(item);
607 ssize_t ret = -EINVAL;
608
609 mutex_lock(&dynamic_netconsole_mutex);
610 if (nt->enabled) {
611 pr_err("target (%s) is enabled, disable to update parameters\n",
612 config_item_name(&nt->group.cg_item));
613 goto out_unlock;
614 }
615
616 ret = kstrtou16(buf, 10, &nt->np.local_port);
617 if (ret < 0)
618 goto out_unlock;
619 ret = strnlen(buf, count);
620 out_unlock:
621 mutex_unlock(&dynamic_netconsole_mutex);
622 return ret;
623 }
624
remote_port_store(struct config_item * item,const char * buf,size_t count)625 static ssize_t remote_port_store(struct config_item *item,
626 const char *buf, size_t count)
627 {
628 struct netconsole_target *nt = to_target(item);
629 ssize_t ret = -EINVAL;
630
631 mutex_lock(&dynamic_netconsole_mutex);
632 if (nt->enabled) {
633 pr_err("target (%s) is enabled, disable to update parameters\n",
634 config_item_name(&nt->group.cg_item));
635 goto out_unlock;
636 }
637
638 ret = kstrtou16(buf, 10, &nt->np.remote_port);
639 if (ret < 0)
640 goto out_unlock;
641 ret = strnlen(buf, count);
642 out_unlock:
643 mutex_unlock(&dynamic_netconsole_mutex);
644 return ret;
645 }
646
local_ip_store(struct config_item * item,const char * buf,size_t count)647 static ssize_t local_ip_store(struct config_item *item, const char *buf,
648 size_t count)
649 {
650 struct netconsole_target *nt = to_target(item);
651 ssize_t ret = -EINVAL;
652
653 mutex_lock(&dynamic_netconsole_mutex);
654 if (nt->enabled) {
655 pr_err("target (%s) is enabled, disable to update parameters\n",
656 config_item_name(&nt->group.cg_item));
657 goto out_unlock;
658 }
659
660 if (strnchr(buf, count, ':')) {
661 const char *end;
662
663 if (in6_pton(buf, count, nt->np.local_ip.in6.s6_addr, -1, &end) > 0) {
664 if (*end && *end != '\n') {
665 pr_err("invalid IPv6 address at: <%c>\n", *end);
666 goto out_unlock;
667 }
668 nt->np.ipv6 = true;
669 } else
670 goto out_unlock;
671 } else {
672 if (!nt->np.ipv6)
673 nt->np.local_ip.ip = in_aton(buf);
674 else
675 goto out_unlock;
676 }
677
678 ret = strnlen(buf, count);
679 out_unlock:
680 mutex_unlock(&dynamic_netconsole_mutex);
681 return ret;
682 }
683
remote_ip_store(struct config_item * item,const char * buf,size_t count)684 static ssize_t remote_ip_store(struct config_item *item, const char *buf,
685 size_t count)
686 {
687 struct netconsole_target *nt = to_target(item);
688 ssize_t ret = -EINVAL;
689
690 mutex_lock(&dynamic_netconsole_mutex);
691 if (nt->enabled) {
692 pr_err("target (%s) is enabled, disable to update parameters\n",
693 config_item_name(&nt->group.cg_item));
694 goto out_unlock;
695 }
696
697 if (strnchr(buf, count, ':')) {
698 const char *end;
699
700 if (in6_pton(buf, count, nt->np.remote_ip.in6.s6_addr, -1, &end) > 0) {
701 if (*end && *end != '\n') {
702 pr_err("invalid IPv6 address at: <%c>\n", *end);
703 goto out_unlock;
704 }
705 nt->np.ipv6 = true;
706 } else
707 goto out_unlock;
708 } else {
709 if (!nt->np.ipv6)
710 nt->np.remote_ip.ip = in_aton(buf);
711 else
712 goto out_unlock;
713 }
714
715 ret = strnlen(buf, count);
716 out_unlock:
717 mutex_unlock(&dynamic_netconsole_mutex);
718 return ret;
719 }
720
721 /* Count number of entries we have in extradata.
722 * This is important because the extradata_complete only supports
723 * MAX_EXTRADATA_ITEMS entries. Before enabling any new {user,sys}data
724 * feature, number of entries needs to checked for available space.
725 */
count_extradata_entries(struct netconsole_target * nt)726 static size_t count_extradata_entries(struct netconsole_target *nt)
727 {
728 size_t entries;
729
730 /* Userdata entries */
731 entries = list_count_nodes(&nt->userdata_group.cg_children);
732 /* Plus sysdata entries */
733 if (nt->sysdata_fields & SYSDATA_CPU_NR)
734 entries += 1;
735 if (nt->sysdata_fields & SYSDATA_TASKNAME)
736 entries += 1;
737 if (nt->sysdata_fields & SYSDATA_RELEASE)
738 entries += 1;
739
740 return entries;
741 }
742
remote_mac_store(struct config_item * item,const char * buf,size_t count)743 static ssize_t remote_mac_store(struct config_item *item, const char *buf,
744 size_t count)
745 {
746 struct netconsole_target *nt = to_target(item);
747 u8 remote_mac[ETH_ALEN];
748 ssize_t ret = -EINVAL;
749
750 mutex_lock(&dynamic_netconsole_mutex);
751 if (nt->enabled) {
752 pr_err("target (%s) is enabled, disable to update parameters\n",
753 config_item_name(&nt->group.cg_item));
754 goto out_unlock;
755 }
756
757 if (!mac_pton(buf, remote_mac))
758 goto out_unlock;
759 if (buf[MAC_ADDR_STR_LEN] && buf[MAC_ADDR_STR_LEN] != '\n')
760 goto out_unlock;
761 memcpy(nt->np.remote_mac, remote_mac, ETH_ALEN);
762
763 ret = strnlen(buf, count);
764 out_unlock:
765 mutex_unlock(&dynamic_netconsole_mutex);
766 return ret;
767 }
768
769 struct userdatum {
770 struct config_item item;
771 char value[MAX_EXTRADATA_VALUE_LEN];
772 };
773
to_userdatum(struct config_item * item)774 static struct userdatum *to_userdatum(struct config_item *item)
775 {
776 return container_of(item, struct userdatum, item);
777 }
778
779 struct userdata {
780 struct config_group group;
781 };
782
to_userdata(struct config_item * item)783 static struct userdata *to_userdata(struct config_item *item)
784 {
785 return container_of(to_config_group(item), struct userdata, group);
786 }
787
userdata_to_target(struct userdata * ud)788 static struct netconsole_target *userdata_to_target(struct userdata *ud)
789 {
790 struct config_group *netconsole_group;
791
792 netconsole_group = to_config_group(ud->group.cg_item.ci_parent);
793 return to_target(&netconsole_group->cg_item);
794 }
795
userdatum_value_show(struct config_item * item,char * buf)796 static ssize_t userdatum_value_show(struct config_item *item, char *buf)
797 {
798 return sysfs_emit(buf, "%s\n", &(to_userdatum(item)->value[0]));
799 }
800
update_userdata(struct netconsole_target * nt)801 static void update_userdata(struct netconsole_target *nt)
802 {
803 int complete_idx = 0, child_count = 0;
804 struct list_head *entry;
805
806 /* Clear the current string in case the last userdatum was deleted */
807 nt->userdata_length = 0;
808 nt->extradata_complete[0] = 0;
809
810 list_for_each(entry, &nt->userdata_group.cg_children) {
811 struct userdatum *udm_item;
812 struct config_item *item;
813
814 if (WARN_ON_ONCE(child_count >= MAX_EXTRADATA_ITEMS))
815 break;
816 child_count++;
817
818 item = container_of(entry, struct config_item, ci_entry);
819 udm_item = to_userdatum(item);
820
821 /* Skip userdata with no value set */
822 if (strnlen(udm_item->value, MAX_EXTRADATA_VALUE_LEN) == 0)
823 continue;
824
825 /* This doesn't overflow extradata_complete since it will write
826 * one entry length (1/MAX_EXTRADATA_ITEMS long), entry count is
827 * checked to not exceed MAX items with child_count above
828 */
829 complete_idx += scnprintf(&nt->extradata_complete[complete_idx],
830 MAX_EXTRADATA_ENTRY_LEN, " %s=%s\n",
831 item->ci_name, udm_item->value);
832 }
833 nt->userdata_length = strnlen(nt->extradata_complete,
834 sizeof(nt->extradata_complete));
835 }
836
userdatum_value_store(struct config_item * item,const char * buf,size_t count)837 static ssize_t userdatum_value_store(struct config_item *item, const char *buf,
838 size_t count)
839 {
840 struct userdatum *udm = to_userdatum(item);
841 struct netconsole_target *nt;
842 struct userdata *ud;
843 ssize_t ret;
844
845 if (count > MAX_EXTRADATA_VALUE_LEN)
846 return -EMSGSIZE;
847
848 mutex_lock(&dynamic_netconsole_mutex);
849
850 ret = strscpy(udm->value, buf, sizeof(udm->value));
851 if (ret < 0)
852 goto out_unlock;
853 trim_newline(udm->value, sizeof(udm->value));
854
855 ud = to_userdata(item->ci_parent);
856 nt = userdata_to_target(ud);
857 update_userdata(nt);
858 ret = count;
859 out_unlock:
860 mutex_unlock(&dynamic_netconsole_mutex);
861 return ret;
862 }
863
864 /* disable_sysdata_feature - Disable sysdata feature and clean sysdata
865 * @nt: target that is disabling the feature
866 * @feature: feature being disabled
867 */
disable_sysdata_feature(struct netconsole_target * nt,enum sysdata_feature feature)868 static void disable_sysdata_feature(struct netconsole_target *nt,
869 enum sysdata_feature feature)
870 {
871 nt->sysdata_fields &= ~feature;
872 nt->extradata_complete[nt->userdata_length] = 0;
873 }
874
sysdata_release_enabled_store(struct config_item * item,const char * buf,size_t count)875 static ssize_t sysdata_release_enabled_store(struct config_item *item,
876 const char *buf, size_t count)
877 {
878 struct netconsole_target *nt = to_target(item->ci_parent);
879 bool release_enabled, curr;
880 ssize_t ret;
881
882 ret = kstrtobool(buf, &release_enabled);
883 if (ret)
884 return ret;
885
886 mutex_lock(&dynamic_netconsole_mutex);
887 curr = !!(nt->sysdata_fields & SYSDATA_RELEASE);
888 if (release_enabled == curr)
889 goto unlock_ok;
890
891 if (release_enabled &&
892 count_extradata_entries(nt) >= MAX_EXTRADATA_ITEMS) {
893 ret = -ENOSPC;
894 goto unlock;
895 }
896
897 if (release_enabled)
898 nt->sysdata_fields |= SYSDATA_RELEASE;
899 else
900 disable_sysdata_feature(nt, SYSDATA_RELEASE);
901
902 unlock_ok:
903 ret = strnlen(buf, count);
904 unlock:
905 mutex_unlock(&dynamic_netconsole_mutex);
906 return ret;
907 }
908
sysdata_taskname_enabled_store(struct config_item * item,const char * buf,size_t count)909 static ssize_t sysdata_taskname_enabled_store(struct config_item *item,
910 const char *buf, size_t count)
911 {
912 struct netconsole_target *nt = to_target(item->ci_parent);
913 bool taskname_enabled, curr;
914 ssize_t ret;
915
916 ret = kstrtobool(buf, &taskname_enabled);
917 if (ret)
918 return ret;
919
920 mutex_lock(&dynamic_netconsole_mutex);
921 curr = !!(nt->sysdata_fields & SYSDATA_TASKNAME);
922 if (taskname_enabled == curr)
923 goto unlock_ok;
924
925 if (taskname_enabled &&
926 count_extradata_entries(nt) >= MAX_EXTRADATA_ITEMS) {
927 ret = -ENOSPC;
928 goto unlock;
929 }
930
931 if (taskname_enabled)
932 nt->sysdata_fields |= SYSDATA_TASKNAME;
933 else
934 disable_sysdata_feature(nt, SYSDATA_TASKNAME);
935
936 unlock_ok:
937 ret = strnlen(buf, count);
938 unlock:
939 mutex_unlock(&dynamic_netconsole_mutex);
940 return ret;
941 }
942
943 /* configfs helper to sysdata cpu_nr feature */
sysdata_cpu_nr_enabled_store(struct config_item * item,const char * buf,size_t count)944 static ssize_t sysdata_cpu_nr_enabled_store(struct config_item *item,
945 const char *buf, size_t count)
946 {
947 struct netconsole_target *nt = to_target(item->ci_parent);
948 bool cpu_nr_enabled, curr;
949 ssize_t ret;
950
951 ret = kstrtobool(buf, &cpu_nr_enabled);
952 if (ret)
953 return ret;
954
955 mutex_lock(&dynamic_netconsole_mutex);
956 curr = !!(nt->sysdata_fields & SYSDATA_CPU_NR);
957 if (cpu_nr_enabled == curr)
958 /* no change requested */
959 goto unlock_ok;
960
961 if (cpu_nr_enabled &&
962 count_extradata_entries(nt) >= MAX_EXTRADATA_ITEMS) {
963 /* user wants the new feature, but there is no space in the
964 * buffer.
965 */
966 ret = -ENOSPC;
967 goto unlock;
968 }
969
970 if (cpu_nr_enabled)
971 nt->sysdata_fields |= SYSDATA_CPU_NR;
972 else
973 /* This is special because extradata_complete might have
974 * remaining data from previous sysdata, and it needs to be
975 * cleaned.
976 */
977 disable_sysdata_feature(nt, SYSDATA_CPU_NR);
978
979 unlock_ok:
980 ret = strnlen(buf, count);
981 unlock:
982 mutex_unlock(&dynamic_netconsole_mutex);
983 return ret;
984 }
985
986 CONFIGFS_ATTR(userdatum_, value);
987 CONFIGFS_ATTR(sysdata_, cpu_nr_enabled);
988 CONFIGFS_ATTR(sysdata_, taskname_enabled);
989 CONFIGFS_ATTR(sysdata_, release_enabled);
990
991 static struct configfs_attribute *userdatum_attrs[] = {
992 &userdatum_attr_value,
993 NULL,
994 };
995
userdatum_release(struct config_item * item)996 static void userdatum_release(struct config_item *item)
997 {
998 kfree(to_userdatum(item));
999 }
1000
1001 static struct configfs_item_operations userdatum_ops = {
1002 .release = userdatum_release,
1003 };
1004
1005 static const struct config_item_type userdatum_type = {
1006 .ct_item_ops = &userdatum_ops,
1007 .ct_attrs = userdatum_attrs,
1008 .ct_owner = THIS_MODULE,
1009 };
1010
userdatum_make_item(struct config_group * group,const char * name)1011 static struct config_item *userdatum_make_item(struct config_group *group,
1012 const char *name)
1013 {
1014 struct netconsole_target *nt;
1015 struct userdatum *udm;
1016 struct userdata *ud;
1017
1018 if (strlen(name) > MAX_EXTRADATA_NAME_LEN)
1019 return ERR_PTR(-ENAMETOOLONG);
1020
1021 ud = to_userdata(&group->cg_item);
1022 nt = userdata_to_target(ud);
1023 if (count_extradata_entries(nt) >= MAX_EXTRADATA_ITEMS)
1024 return ERR_PTR(-ENOSPC);
1025
1026 udm = kzalloc(sizeof(*udm), GFP_KERNEL);
1027 if (!udm)
1028 return ERR_PTR(-ENOMEM);
1029
1030 config_item_init_type_name(&udm->item, name, &userdatum_type);
1031 return &udm->item;
1032 }
1033
userdatum_drop(struct config_group * group,struct config_item * item)1034 static void userdatum_drop(struct config_group *group, struct config_item *item)
1035 {
1036 struct netconsole_target *nt;
1037 struct userdata *ud;
1038
1039 ud = to_userdata(&group->cg_item);
1040 nt = userdata_to_target(ud);
1041
1042 mutex_lock(&dynamic_netconsole_mutex);
1043 update_userdata(nt);
1044 config_item_put(item);
1045 mutex_unlock(&dynamic_netconsole_mutex);
1046 }
1047
1048 static struct configfs_attribute *userdata_attrs[] = {
1049 &sysdata_attr_cpu_nr_enabled,
1050 &sysdata_attr_taskname_enabled,
1051 &sysdata_attr_release_enabled,
1052 NULL,
1053 };
1054
1055 static struct configfs_group_operations userdata_ops = {
1056 .make_item = userdatum_make_item,
1057 .drop_item = userdatum_drop,
1058 };
1059
1060 static const struct config_item_type userdata_type = {
1061 .ct_item_ops = &userdatum_ops,
1062 .ct_group_ops = &userdata_ops,
1063 .ct_attrs = userdata_attrs,
1064 .ct_owner = THIS_MODULE,
1065 };
1066
1067 CONFIGFS_ATTR(, enabled);
1068 CONFIGFS_ATTR(, extended);
1069 CONFIGFS_ATTR(, dev_name);
1070 CONFIGFS_ATTR(, local_port);
1071 CONFIGFS_ATTR(, remote_port);
1072 CONFIGFS_ATTR(, local_ip);
1073 CONFIGFS_ATTR(, remote_ip);
1074 CONFIGFS_ATTR_RO(, local_mac);
1075 CONFIGFS_ATTR(, remote_mac);
1076 CONFIGFS_ATTR(, release);
1077 CONFIGFS_ATTR_RO(, transmit_errors);
1078
1079 static struct configfs_attribute *netconsole_target_attrs[] = {
1080 &attr_enabled,
1081 &attr_extended,
1082 &attr_release,
1083 &attr_dev_name,
1084 &attr_local_port,
1085 &attr_remote_port,
1086 &attr_local_ip,
1087 &attr_remote_ip,
1088 &attr_local_mac,
1089 &attr_remote_mac,
1090 &attr_transmit_errors,
1091 NULL,
1092 };
1093
1094 /*
1095 * Item operations and type for netconsole_target.
1096 */
1097
netconsole_target_release(struct config_item * item)1098 static void netconsole_target_release(struct config_item *item)
1099 {
1100 kfree(to_target(item));
1101 }
1102
1103 static struct configfs_item_operations netconsole_target_item_ops = {
1104 .release = netconsole_target_release,
1105 };
1106
1107 static const struct config_item_type netconsole_target_type = {
1108 .ct_attrs = netconsole_target_attrs,
1109 .ct_item_ops = &netconsole_target_item_ops,
1110 .ct_owner = THIS_MODULE,
1111 };
1112
init_target_config_group(struct netconsole_target * nt,const char * name)1113 static void init_target_config_group(struct netconsole_target *nt,
1114 const char *name)
1115 {
1116 config_group_init_type_name(&nt->group, name, &netconsole_target_type);
1117 config_group_init_type_name(&nt->userdata_group, "userdata",
1118 &userdata_type);
1119 configfs_add_default_group(&nt->userdata_group, &nt->group);
1120 }
1121
find_cmdline_target(const char * name)1122 static struct netconsole_target *find_cmdline_target(const char *name)
1123 {
1124 struct netconsole_target *nt, *ret = NULL;
1125 unsigned long flags;
1126
1127 spin_lock_irqsave(&target_list_lock, flags);
1128 list_for_each_entry(nt, &target_list, list) {
1129 if (!strcmp(nt->group.cg_item.ci_name, name)) {
1130 ret = nt;
1131 break;
1132 }
1133 }
1134 spin_unlock_irqrestore(&target_list_lock, flags);
1135
1136 return ret;
1137 }
1138
1139 /*
1140 * Group operations and type for netconsole_subsys.
1141 */
1142
make_netconsole_target(struct config_group * group,const char * name)1143 static struct config_group *make_netconsole_target(struct config_group *group,
1144 const char *name)
1145 {
1146 struct netconsole_target *nt;
1147 unsigned long flags;
1148
1149 /* Checking if a target by this name was created at boot time. If so,
1150 * attach a configfs entry to that target. This enables dynamic
1151 * control.
1152 */
1153 if (!strncmp(name, NETCONSOLE_PARAM_TARGET_PREFIX,
1154 strlen(NETCONSOLE_PARAM_TARGET_PREFIX))) {
1155 nt = find_cmdline_target(name);
1156 if (nt) {
1157 init_target_config_group(nt, name);
1158 return &nt->group;
1159 }
1160 }
1161
1162 nt = alloc_and_init();
1163 if (!nt)
1164 return ERR_PTR(-ENOMEM);
1165
1166 /* Initialize the config_group member */
1167 init_target_config_group(nt, name);
1168
1169 /* Adding, but it is disabled */
1170 spin_lock_irqsave(&target_list_lock, flags);
1171 list_add(&nt->list, &target_list);
1172 spin_unlock_irqrestore(&target_list_lock, flags);
1173
1174 return &nt->group;
1175 }
1176
drop_netconsole_target(struct config_group * group,struct config_item * item)1177 static void drop_netconsole_target(struct config_group *group,
1178 struct config_item *item)
1179 {
1180 unsigned long flags;
1181 struct netconsole_target *nt = to_target(item);
1182
1183 spin_lock_irqsave(&target_list_lock, flags);
1184 list_del(&nt->list);
1185 spin_unlock_irqrestore(&target_list_lock, flags);
1186
1187 /*
1188 * The target may have never been enabled, or was manually disabled
1189 * before being removed so netpoll may have already been cleaned up.
1190 */
1191 if (nt->enabled)
1192 netpoll_cleanup(&nt->np);
1193
1194 config_item_put(&nt->group.cg_item);
1195 }
1196
1197 static struct configfs_group_operations netconsole_subsys_group_ops = {
1198 .make_group = make_netconsole_target,
1199 .drop_item = drop_netconsole_target,
1200 };
1201
1202 static const struct config_item_type netconsole_subsys_type = {
1203 .ct_group_ops = &netconsole_subsys_group_ops,
1204 .ct_owner = THIS_MODULE,
1205 };
1206
1207 /* The netconsole configfs subsystem */
1208 static struct configfs_subsystem netconsole_subsys = {
1209 .su_group = {
1210 .cg_item = {
1211 .ci_namebuf = "netconsole",
1212 .ci_type = &netconsole_subsys_type,
1213 },
1214 },
1215 };
1216
populate_configfs_item(struct netconsole_target * nt,int cmdline_count)1217 static void populate_configfs_item(struct netconsole_target *nt,
1218 int cmdline_count)
1219 {
1220 char target_name[16];
1221
1222 snprintf(target_name, sizeof(target_name), "%s%d",
1223 NETCONSOLE_PARAM_TARGET_PREFIX, cmdline_count);
1224 init_target_config_group(nt, target_name);
1225 }
1226
sysdata_append_cpu_nr(struct netconsole_target * nt,int offset)1227 static int sysdata_append_cpu_nr(struct netconsole_target *nt, int offset)
1228 {
1229 /* Append cpu=%d at extradata_complete after userdata str */
1230 return scnprintf(&nt->extradata_complete[offset],
1231 MAX_EXTRADATA_ENTRY_LEN, " cpu=%u\n",
1232 raw_smp_processor_id());
1233 }
1234
sysdata_append_taskname(struct netconsole_target * nt,int offset)1235 static int sysdata_append_taskname(struct netconsole_target *nt, int offset)
1236 {
1237 return scnprintf(&nt->extradata_complete[offset],
1238 MAX_EXTRADATA_ENTRY_LEN, " taskname=%s\n",
1239 current->comm);
1240 }
1241
sysdata_append_release(struct netconsole_target * nt,int offset)1242 static int sysdata_append_release(struct netconsole_target *nt, int offset)
1243 {
1244 return scnprintf(&nt->extradata_complete[offset],
1245 MAX_EXTRADATA_ENTRY_LEN, " release=%s\n",
1246 init_utsname()->release);
1247 }
1248
1249 /*
1250 * prepare_extradata - append sysdata at extradata_complete in runtime
1251 * @nt: target to send message to
1252 */
prepare_extradata(struct netconsole_target * nt)1253 static int prepare_extradata(struct netconsole_target *nt)
1254 {
1255 u32 fields = SYSDATA_CPU_NR | SYSDATA_TASKNAME;
1256 int extradata_len;
1257
1258 /* userdata was appended when configfs write helper was called
1259 * by update_userdata().
1260 */
1261 extradata_len = nt->userdata_length;
1262
1263 if (!(nt->sysdata_fields & fields))
1264 goto out;
1265
1266 if (nt->sysdata_fields & SYSDATA_CPU_NR)
1267 extradata_len += sysdata_append_cpu_nr(nt, extradata_len);
1268 if (nt->sysdata_fields & SYSDATA_TASKNAME)
1269 extradata_len += sysdata_append_taskname(nt, extradata_len);
1270 if (nt->sysdata_fields & SYSDATA_RELEASE)
1271 extradata_len += sysdata_append_release(nt, extradata_len);
1272
1273 WARN_ON_ONCE(extradata_len >
1274 MAX_EXTRADATA_ENTRY_LEN * MAX_EXTRADATA_ITEMS);
1275
1276 out:
1277 return extradata_len;
1278 }
1279 #else /* CONFIG_NETCONSOLE_DYNAMIC not set */
prepare_extradata(struct netconsole_target * nt)1280 static int prepare_extradata(struct netconsole_target *nt)
1281 {
1282 return 0;
1283 }
1284 #endif /* CONFIG_NETCONSOLE_DYNAMIC */
1285
1286 /* Handle network interface device notifications */
netconsole_netdev_event(struct notifier_block * this,unsigned long event,void * ptr)1287 static int netconsole_netdev_event(struct notifier_block *this,
1288 unsigned long event, void *ptr)
1289 {
1290 unsigned long flags;
1291 struct netconsole_target *nt, *tmp;
1292 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
1293 bool stopped = false;
1294
1295 if (!(event == NETDEV_CHANGENAME || event == NETDEV_UNREGISTER ||
1296 event == NETDEV_RELEASE || event == NETDEV_JOIN))
1297 goto done;
1298
1299 mutex_lock(&target_cleanup_list_lock);
1300 spin_lock_irqsave(&target_list_lock, flags);
1301 list_for_each_entry_safe(nt, tmp, &target_list, list) {
1302 netconsole_target_get(nt);
1303 if (nt->np.dev == dev) {
1304 switch (event) {
1305 case NETDEV_CHANGENAME:
1306 strscpy(nt->np.dev_name, dev->name, IFNAMSIZ);
1307 break;
1308 case NETDEV_RELEASE:
1309 case NETDEV_JOIN:
1310 case NETDEV_UNREGISTER:
1311 nt->enabled = false;
1312 list_move(&nt->list, &target_cleanup_list);
1313 stopped = true;
1314 }
1315 }
1316 netconsole_target_put(nt);
1317 }
1318 spin_unlock_irqrestore(&target_list_lock, flags);
1319 mutex_unlock(&target_cleanup_list_lock);
1320
1321 if (stopped) {
1322 const char *msg = "had an event";
1323
1324 switch (event) {
1325 case NETDEV_UNREGISTER:
1326 msg = "unregistered";
1327 break;
1328 case NETDEV_RELEASE:
1329 msg = "released slaves";
1330 break;
1331 case NETDEV_JOIN:
1332 msg = "is joining a master device";
1333 break;
1334 }
1335 pr_info("network logging stopped on interface %s as it %s\n",
1336 dev->name, msg);
1337 }
1338
1339 /* Process target_cleanup_list entries. By the end, target_cleanup_list
1340 * should be empty
1341 */
1342 netconsole_process_cleanups_core();
1343
1344 done:
1345 return NOTIFY_DONE;
1346 }
1347
1348 static struct notifier_block netconsole_netdev_notifier = {
1349 .notifier_call = netconsole_netdev_event,
1350 };
1351
1352 /**
1353 * send_udp - Wrapper for netpoll_send_udp that counts errors
1354 * @nt: target to send message to
1355 * @msg: message to send
1356 * @len: length of message
1357 *
1358 * Calls netpoll_send_udp and classifies the return value. If an error
1359 * occurred it increments statistics in nt->stats accordingly.
1360 * Only calls netpoll_send_udp if CONFIG_NETCONSOLE_DYNAMIC is disabled.
1361 */
send_udp(struct netconsole_target * nt,const char * msg,int len)1362 static void send_udp(struct netconsole_target *nt, const char *msg, int len)
1363 {
1364 int result = netpoll_send_udp(&nt->np, msg, len);
1365
1366 if (IS_ENABLED(CONFIG_NETCONSOLE_DYNAMIC)) {
1367 if (result == NET_XMIT_DROP) {
1368 u64_stats_update_begin(&nt->stats.syncp);
1369 u64_stats_inc(&nt->stats.xmit_drop_count);
1370 u64_stats_update_end(&nt->stats.syncp);
1371 } else if (result == -ENOMEM) {
1372 u64_stats_update_begin(&nt->stats.syncp);
1373 u64_stats_inc(&nt->stats.enomem_count);
1374 u64_stats_update_end(&nt->stats.syncp);
1375 }
1376 }
1377 }
1378
send_msg_no_fragmentation(struct netconsole_target * nt,const char * msg,int msg_len,int release_len)1379 static void send_msg_no_fragmentation(struct netconsole_target *nt,
1380 const char *msg,
1381 int msg_len,
1382 int release_len)
1383 {
1384 const char *extradata = NULL;
1385 const char *release;
1386
1387 #ifdef CONFIG_NETCONSOLE_DYNAMIC
1388 extradata = nt->extradata_complete;
1389 #endif
1390
1391 if (release_len) {
1392 release = init_utsname()->release;
1393
1394 scnprintf(nt->buf, MAX_PRINT_CHUNK, "%s,%s", release, msg);
1395 msg_len += release_len;
1396 } else {
1397 memcpy(nt->buf, msg, msg_len);
1398 }
1399
1400 if (extradata)
1401 msg_len += scnprintf(&nt->buf[msg_len],
1402 MAX_PRINT_CHUNK - msg_len,
1403 "%s", extradata);
1404
1405 send_udp(nt, nt->buf, msg_len);
1406 }
1407
append_release(char * buf)1408 static void append_release(char *buf)
1409 {
1410 const char *release;
1411
1412 release = init_utsname()->release;
1413 scnprintf(buf, MAX_PRINT_CHUNK, "%s,", release);
1414 }
1415
send_fragmented_body(struct netconsole_target * nt,const char * msgbody,int header_len,int msgbody_len,int extradata_len)1416 static void send_fragmented_body(struct netconsole_target *nt,
1417 const char *msgbody, int header_len,
1418 int msgbody_len, int extradata_len)
1419 {
1420 int sent_extradata, preceding_bytes;
1421 const char *extradata = NULL;
1422 int body_len, offset = 0;
1423
1424 #ifdef CONFIG_NETCONSOLE_DYNAMIC
1425 extradata = nt->extradata_complete;
1426 #endif
1427
1428 /* body_len represents the number of bytes that will be sent. This is
1429 * bigger than MAX_PRINT_CHUNK, thus, it will be split in multiple
1430 * packets
1431 */
1432 body_len = msgbody_len + extradata_len;
1433
1434 /* In each iteration of the while loop below, we send a packet
1435 * containing the header and a portion of the body. The body is
1436 * composed of two parts: msgbody and extradata. We keep track of how
1437 * many bytes have been sent so far using the offset variable, which
1438 * ranges from 0 to the total length of the body.
1439 */
1440 while (offset < body_len) {
1441 int this_header = header_len;
1442 bool msgbody_written = false;
1443 int this_offset = 0;
1444 int this_chunk = 0;
1445
1446 this_header += scnprintf(nt->buf + this_header,
1447 MAX_PRINT_CHUNK - this_header,
1448 ",ncfrag=%d/%d;", offset,
1449 body_len);
1450
1451 /* Not all msgbody data has been written yet */
1452 if (offset < msgbody_len) {
1453 this_chunk = min(msgbody_len - offset,
1454 MAX_PRINT_CHUNK - this_header);
1455 if (WARN_ON_ONCE(this_chunk <= 0))
1456 return;
1457 memcpy(nt->buf + this_header, msgbody + offset,
1458 this_chunk);
1459 this_offset += this_chunk;
1460 }
1461
1462 /* msgbody was finally written, either in the previous
1463 * messages and/or in the current buf. Time to write
1464 * the extradata.
1465 */
1466 msgbody_written |= offset + this_offset >= msgbody_len;
1467
1468 /* Msg body is fully written and there is pending extradata to
1469 * write, append extradata in this chunk
1470 */
1471 if (msgbody_written && offset + this_offset < body_len) {
1472 /* Track how much user data was already sent. First
1473 * time here, sent_userdata is zero
1474 */
1475 sent_extradata = (offset + this_offset) - msgbody_len;
1476 /* offset of bytes used in current buf */
1477 preceding_bytes = this_chunk + this_header;
1478
1479 if (WARN_ON_ONCE(sent_extradata < 0))
1480 return;
1481
1482 this_chunk = min(extradata_len - sent_extradata,
1483 MAX_PRINT_CHUNK - preceding_bytes);
1484 if (WARN_ON_ONCE(this_chunk < 0))
1485 /* this_chunk could be zero if all the previous
1486 * message used all the buffer. This is not a
1487 * problem, extradata will be sent in the next
1488 * iteration
1489 */
1490 return;
1491
1492 memcpy(nt->buf + this_header + this_offset,
1493 extradata + sent_extradata,
1494 this_chunk);
1495 this_offset += this_chunk;
1496 }
1497
1498 send_udp(nt, nt->buf, this_header + this_offset);
1499 offset += this_offset;
1500 }
1501 }
1502
send_msg_fragmented(struct netconsole_target * nt,const char * msg,int msg_len,int release_len,int extradata_len)1503 static void send_msg_fragmented(struct netconsole_target *nt,
1504 const char *msg,
1505 int msg_len,
1506 int release_len,
1507 int extradata_len)
1508 {
1509 int header_len, msgbody_len;
1510 const char *msgbody;
1511
1512 /* need to insert extra header fields, detect header and msgbody */
1513 msgbody = memchr(msg, ';', msg_len);
1514 if (WARN_ON_ONCE(!msgbody))
1515 return;
1516
1517 header_len = msgbody - msg;
1518 msgbody_len = msg_len - header_len - 1;
1519 msgbody++;
1520
1521 /*
1522 * Transfer multiple chunks with the following extra header.
1523 * "ncfrag=<byte-offset>/<total-bytes>"
1524 */
1525 if (release_len)
1526 append_release(nt->buf);
1527
1528 /* Copy the header into the buffer */
1529 memcpy(nt->buf + release_len, msg, header_len);
1530 header_len += release_len;
1531
1532 /* for now on, the header will be persisted, and the msgbody
1533 * will be replaced
1534 */
1535 send_fragmented_body(nt, msgbody, header_len, msgbody_len,
1536 extradata_len);
1537 }
1538
1539 /**
1540 * send_ext_msg_udp - send extended log message to target
1541 * @nt: target to send message to
1542 * @msg: extended log message to send
1543 * @msg_len: length of message
1544 *
1545 * Transfer extended log @msg to @nt. If @msg is longer than
1546 * MAX_PRINT_CHUNK, it'll be split and transmitted in multiple chunks with
1547 * ncfrag header field added to identify them.
1548 */
send_ext_msg_udp(struct netconsole_target * nt,const char * msg,int msg_len)1549 static void send_ext_msg_udp(struct netconsole_target *nt, const char *msg,
1550 int msg_len)
1551 {
1552 int release_len = 0;
1553 int extradata_len;
1554
1555 extradata_len = prepare_extradata(nt);
1556
1557 if (nt->release)
1558 release_len = strlen(init_utsname()->release) + 1;
1559
1560 if (msg_len + release_len + extradata_len <= MAX_PRINT_CHUNK)
1561 return send_msg_no_fragmentation(nt, msg, msg_len, release_len);
1562
1563 return send_msg_fragmented(nt, msg, msg_len, release_len,
1564 extradata_len);
1565 }
1566
write_ext_msg(struct console * con,const char * msg,unsigned int len)1567 static void write_ext_msg(struct console *con, const char *msg,
1568 unsigned int len)
1569 {
1570 struct netconsole_target *nt;
1571 unsigned long flags;
1572
1573 if ((oops_only && !oops_in_progress) || list_empty(&target_list))
1574 return;
1575
1576 spin_lock_irqsave(&target_list_lock, flags);
1577 list_for_each_entry(nt, &target_list, list)
1578 if (nt->extended && nt->enabled && netif_running(nt->np.dev))
1579 send_ext_msg_udp(nt, msg, len);
1580 spin_unlock_irqrestore(&target_list_lock, flags);
1581 }
1582
write_msg(struct console * con,const char * msg,unsigned int len)1583 static void write_msg(struct console *con, const char *msg, unsigned int len)
1584 {
1585 int frag, left;
1586 unsigned long flags;
1587 struct netconsole_target *nt;
1588 const char *tmp;
1589
1590 if (oops_only && !oops_in_progress)
1591 return;
1592 /* Avoid taking lock and disabling interrupts unnecessarily */
1593 if (list_empty(&target_list))
1594 return;
1595
1596 spin_lock_irqsave(&target_list_lock, flags);
1597 list_for_each_entry(nt, &target_list, list) {
1598 if (!nt->extended && nt->enabled && netif_running(nt->np.dev)) {
1599 /*
1600 * We nest this inside the for-each-target loop above
1601 * so that we're able to get as much logging out to
1602 * at least one target if we die inside here, instead
1603 * of unnecessarily keeping all targets in lock-step.
1604 */
1605 tmp = msg;
1606 for (left = len; left;) {
1607 frag = min(left, MAX_PRINT_CHUNK);
1608 send_udp(nt, tmp, frag);
1609 tmp += frag;
1610 left -= frag;
1611 }
1612 }
1613 }
1614 spin_unlock_irqrestore(&target_list_lock, flags);
1615 }
1616
1617 /* Allocate new target (from boot/module param) and setup netpoll for it */
alloc_param_target(char * target_config,int cmdline_count)1618 static struct netconsole_target *alloc_param_target(char *target_config,
1619 int cmdline_count)
1620 {
1621 struct netconsole_target *nt;
1622 int err;
1623
1624 nt = alloc_and_init();
1625 if (!nt) {
1626 err = -ENOMEM;
1627 goto fail;
1628 }
1629
1630 if (*target_config == '+') {
1631 nt->extended = true;
1632 target_config++;
1633 }
1634
1635 if (*target_config == 'r') {
1636 if (!nt->extended) {
1637 pr_err("Netconsole configuration error. Release feature requires extended log message");
1638 err = -EINVAL;
1639 goto fail;
1640 }
1641 nt->release = true;
1642 target_config++;
1643 }
1644
1645 /* Parse parameters and setup netpoll */
1646 err = netpoll_parse_options(&nt->np, target_config);
1647 if (err)
1648 goto fail;
1649
1650 err = netpoll_setup(&nt->np);
1651 if (err) {
1652 pr_err("Not enabling netconsole for %s%d. Netpoll setup failed\n",
1653 NETCONSOLE_PARAM_TARGET_PREFIX, cmdline_count);
1654 if (!IS_ENABLED(CONFIG_NETCONSOLE_DYNAMIC))
1655 /* only fail if dynamic reconfiguration is set,
1656 * otherwise, keep the target in the list, but disabled.
1657 */
1658 goto fail;
1659 } else {
1660 nt->enabled = true;
1661 }
1662 populate_configfs_item(nt, cmdline_count);
1663
1664 return nt;
1665
1666 fail:
1667 kfree(nt);
1668 return ERR_PTR(err);
1669 }
1670
1671 /* Cleanup netpoll for given target (from boot/module param) and free it */
free_param_target(struct netconsole_target * nt)1672 static void free_param_target(struct netconsole_target *nt)
1673 {
1674 netpoll_cleanup(&nt->np);
1675 kfree(nt);
1676 }
1677
1678 static struct console netconsole_ext = {
1679 .name = "netcon_ext",
1680 .flags = CON_ENABLED | CON_EXTENDED,
1681 .write = write_ext_msg,
1682 };
1683
1684 static struct console netconsole = {
1685 .name = "netcon",
1686 .flags = CON_ENABLED,
1687 .write = write_msg,
1688 };
1689
init_netconsole(void)1690 static int __init init_netconsole(void)
1691 {
1692 int err;
1693 struct netconsole_target *nt, *tmp;
1694 unsigned int count = 0;
1695 bool extended = false;
1696 unsigned long flags;
1697 char *target_config;
1698 char *input = config;
1699
1700 if (strnlen(input, MAX_PARAM_LENGTH)) {
1701 while ((target_config = strsep(&input, ";"))) {
1702 nt = alloc_param_target(target_config, count);
1703 if (IS_ERR(nt)) {
1704 if (IS_ENABLED(CONFIG_NETCONSOLE_DYNAMIC))
1705 continue;
1706 err = PTR_ERR(nt);
1707 goto fail;
1708 }
1709 /* Dump existing printks when we register */
1710 if (nt->extended) {
1711 extended = true;
1712 netconsole_ext.flags |= CON_PRINTBUFFER;
1713 } else {
1714 netconsole.flags |= CON_PRINTBUFFER;
1715 }
1716
1717 spin_lock_irqsave(&target_list_lock, flags);
1718 list_add(&nt->list, &target_list);
1719 spin_unlock_irqrestore(&target_list_lock, flags);
1720 count++;
1721 }
1722 }
1723
1724 err = register_netdevice_notifier(&netconsole_netdev_notifier);
1725 if (err)
1726 goto fail;
1727
1728 err = dynamic_netconsole_init();
1729 if (err)
1730 goto undonotifier;
1731
1732 if (extended)
1733 register_console(&netconsole_ext);
1734 register_console(&netconsole);
1735 pr_info("network logging started\n");
1736
1737 return err;
1738
1739 undonotifier:
1740 unregister_netdevice_notifier(&netconsole_netdev_notifier);
1741
1742 fail:
1743 pr_err("cleaning up\n");
1744
1745 /*
1746 * Remove all targets and destroy them (only targets created
1747 * from the boot/module option exist here). Skipping the list
1748 * lock is safe here, and netpoll_cleanup() will sleep.
1749 */
1750 list_for_each_entry_safe(nt, tmp, &target_list, list) {
1751 list_del(&nt->list);
1752 free_param_target(nt);
1753 }
1754
1755 return err;
1756 }
1757
cleanup_netconsole(void)1758 static void __exit cleanup_netconsole(void)
1759 {
1760 struct netconsole_target *nt, *tmp;
1761
1762 if (console_is_registered(&netconsole_ext))
1763 unregister_console(&netconsole_ext);
1764 unregister_console(&netconsole);
1765 dynamic_netconsole_exit();
1766 unregister_netdevice_notifier(&netconsole_netdev_notifier);
1767
1768 /*
1769 * Targets created via configfs pin references on our module
1770 * and would first be rmdir(2)'ed from userspace. We reach
1771 * here only when they are already destroyed, and only those
1772 * created from the boot/module option are left, so remove and
1773 * destroy them. Skipping the list lock is safe here, and
1774 * netpoll_cleanup() will sleep.
1775 */
1776 list_for_each_entry_safe(nt, tmp, &target_list, list) {
1777 list_del(&nt->list);
1778 free_param_target(nt);
1779 }
1780 }
1781
1782 /*
1783 * Use late_initcall to ensure netconsole is
1784 * initialized after network device driver if built-in.
1785 *
1786 * late_initcall() and module_init() are identical if built as module.
1787 */
1788 late_initcall(init_netconsole);
1789 module_exit(cleanup_netconsole);
1790