1406 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * linux/drivers/net/netconsole.c4 *5 * Copyright (C) 2001 Ingo Molnar <mingo@redhat.com>6 *7 * This file contains the implementation of an IRQ-safe, crash-safe8 * kernel console implementation that outputs kernel messages to the9 * network.10 *11 * Modification history:12 *13 * 2001-09-17 started by Ingo Molnar.14 * 2003-08-11 2.6 port by Matt Mackall15 * simplified options16 * generic card hooks17 * works non-modular18 * 2003-09-07 rewritten with netpoll api19 */20 21/****************************************************************22 *23 ****************************************************************/24 25#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt26 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/utsname.h>40#include <linux/rtnetlink.h>41 42MODULE_AUTHOR("Matt Mackall <mpm@selenic.com>");43MODULE_DESCRIPTION("Console driver for network interfaces");44MODULE_LICENSE("GPL");45 46#define MAX_PARAM_LENGTH 25647#define MAX_USERDATA_ENTRY_LENGTH 25648#define MAX_USERDATA_VALUE_LENGTH 20049/* The number 3 comes from userdata entry format characters (' ', '=', '\n') */50#define MAX_USERDATA_NAME_LENGTH (MAX_USERDATA_ENTRY_LENGTH - \51 MAX_USERDATA_VALUE_LENGTH - 3)52#define MAX_USERDATA_ITEMS 1653#define MAX_PRINT_CHUNK 100054 55static char config[MAX_PARAM_LENGTH];56module_param_string(netconsole, config, MAX_PARAM_LENGTH, 0);57MODULE_PARM_DESC(netconsole, " netconsole=[src-port]@[src-ip]/[dev],[tgt-port]@<tgt-ip>/[tgt-macaddr]");58 59static bool oops_only;60module_param(oops_only, bool, 0600);61MODULE_PARM_DESC(oops_only, "Only log oops messages");62 63#define NETCONSOLE_PARAM_TARGET_PREFIX "cmdline"64 65#ifndef MODULE66static int __init option_setup(char *opt)67{68 strscpy(config, opt, MAX_PARAM_LENGTH);69 return 1;70}71__setup("netconsole=", option_setup);72#endif /* MODULE */73 74/* Linked list of all configured targets */75static LIST_HEAD(target_list);76/* target_cleanup_list is used to track targets that need to be cleaned outside77 * of target_list_lock. It should be cleaned in the same function it is78 * populated.79 */80static LIST_HEAD(target_cleanup_list);81 82/* This needs to be a spinlock because write_msg() cannot sleep */83static DEFINE_SPINLOCK(target_list_lock);84/* This needs to be a mutex because netpoll_cleanup might sleep */85static DEFINE_MUTEX(target_cleanup_list_lock);86 87/*88 * Console driver for extended netconsoles. Registered on the first use to89 * avoid unnecessarily enabling ext message formatting.90 */91static struct console netconsole_ext;92 93/**94 * struct netconsole_target - Represents a configured netconsole target.95 * @list: Links this target into the target_list.96 * @group: Links us into the configfs subsystem hierarchy.97 * @userdata_group: Links to the userdata configfs hierarchy98 * @userdata_complete: Cached, formatted string of append99 * @userdata_length: String length of userdata_complete100 * @enabled: On / off knob to enable / disable target.101 * Visible from userspace (read-write).102 * We maintain a strict 1:1 correspondence between this and103 * whether the corresponding netpoll is active or inactive.104 * Also, other parameters of a target may be modified at105 * runtime only when it is disabled (enabled == 0).106 * @extended: Denotes whether console is extended or not.107 * @release: Denotes whether kernel release version should be prepended108 * to the message. Depends on extended console.109 * @np: The netpoll structure for this target.110 * Contains the other userspace visible parameters:111 * dev_name (read-write)112 * local_port (read-write)113 * remote_port (read-write)114 * local_ip (read-write)115 * remote_ip (read-write)116 * local_mac (read-only)117 * remote_mac (read-write)118 */119struct netconsole_target {120 struct list_head list;121#ifdef CONFIG_NETCONSOLE_DYNAMIC122 struct config_group group;123 struct config_group userdata_group;124 char userdata_complete[MAX_USERDATA_ENTRY_LENGTH * MAX_USERDATA_ITEMS];125 size_t userdata_length;126#endif127 bool enabled;128 bool extended;129 bool release;130 struct netpoll np;131};132 133#ifdef CONFIG_NETCONSOLE_DYNAMIC134 135static struct configfs_subsystem netconsole_subsys;136static DEFINE_MUTEX(dynamic_netconsole_mutex);137 138static int __init dynamic_netconsole_init(void)139{140 config_group_init(&netconsole_subsys.su_group);141 mutex_init(&netconsole_subsys.su_mutex);142 return configfs_register_subsystem(&netconsole_subsys);143}144 145static void __exit dynamic_netconsole_exit(void)146{147 configfs_unregister_subsystem(&netconsole_subsys);148}149 150/*151 * Targets that were created by parsing the boot/module option string152 * do not exist in the configfs hierarchy (and have NULL names) and will153 * never go away, so make these a no-op for them.154 */155static void netconsole_target_get(struct netconsole_target *nt)156{157 if (config_item_name(&nt->group.cg_item))158 config_group_get(&nt->group);159}160 161static void netconsole_target_put(struct netconsole_target *nt)162{163 if (config_item_name(&nt->group.cg_item))164 config_group_put(&nt->group);165}166 167#else /* !CONFIG_NETCONSOLE_DYNAMIC */168 169static int __init dynamic_netconsole_init(void)170{171 return 0;172}173 174static void __exit dynamic_netconsole_exit(void)175{176}177 178/*179 * No danger of targets going away from under us when dynamic180 * reconfigurability is off.181 */182static void netconsole_target_get(struct netconsole_target *nt)183{184}185 186static void netconsole_target_put(struct netconsole_target *nt)187{188}189 190static void populate_configfs_item(struct netconsole_target *nt,191 int cmdline_count)192{193}194#endif /* CONFIG_NETCONSOLE_DYNAMIC */195 196/* Allocate and initialize with defaults.197 * Note that these targets get their config_item fields zeroed-out.198 */199static struct netconsole_target *alloc_and_init(void)200{201 struct netconsole_target *nt;202 203 nt = kzalloc(sizeof(*nt), GFP_KERNEL);204 if (!nt)205 return nt;206 207 if (IS_ENABLED(CONFIG_NETCONSOLE_EXTENDED_LOG))208 nt->extended = true;209 if (IS_ENABLED(CONFIG_NETCONSOLE_PREPEND_RELEASE))210 nt->release = true;211 212 nt->np.name = "netconsole";213 strscpy(nt->np.dev_name, "eth0", IFNAMSIZ);214 nt->np.local_port = 6665;215 nt->np.remote_port = 6666;216 eth_broadcast_addr(nt->np.remote_mac);217 218 return nt;219}220 221/* Clean up every target in the cleanup_list and move the clean targets back to222 * the main target_list.223 */224static void netconsole_process_cleanups_core(void)225{226 struct netconsole_target *nt, *tmp;227 unsigned long flags;228 229 /* The cleanup needs RTNL locked */230 ASSERT_RTNL();231 232 mutex_lock(&target_cleanup_list_lock);233 list_for_each_entry_safe(nt, tmp, &target_cleanup_list, list) {234 /* all entries in the cleanup_list needs to be disabled */235 WARN_ON_ONCE(nt->enabled);236 do_netpoll_cleanup(&nt->np);237 /* moved the cleaned target to target_list. Need to hold both238 * locks239 */240 spin_lock_irqsave(&target_list_lock, flags);241 list_move(&nt->list, &target_list);242 spin_unlock_irqrestore(&target_list_lock, flags);243 }244 WARN_ON_ONCE(!list_empty(&target_cleanup_list));245 mutex_unlock(&target_cleanup_list_lock);246}247 248#ifdef CONFIG_NETCONSOLE_DYNAMIC249 250/*251 * Our subsystem hierarchy is:252 *253 * /sys/kernel/config/netconsole/254 * |255 * <target>/256 * | enabled257 * | release258 * | dev_name259 * | local_port260 * | remote_port261 * | local_ip262 * | remote_ip263 * | local_mac264 * | remote_mac265 * | userdata/266 * | <key>/267 * | value268 * | ...269 * |270 * <target>/...271 */272 273static struct netconsole_target *to_target(struct config_item *item)274{275 struct config_group *cfg_group;276 277 cfg_group = to_config_group(item);278 if (!cfg_group)279 return NULL;280 return container_of(to_config_group(item),281 struct netconsole_target, group);282}283 284/* Do the list cleanup with the rtnl lock hold. rtnl lock is necessary because285 * netdev might be cleaned-up by calling __netpoll_cleanup(),286 */287static void netconsole_process_cleanups(void)288{289 /* rtnl lock is called here, because it has precedence over290 * target_cleanup_list_lock mutex and target_cleanup_list291 */292 rtnl_lock();293 netconsole_process_cleanups_core();294 rtnl_unlock();295}296 297/* Get rid of possible trailing newline, returning the new length */298static void trim_newline(char *s, size_t maxlen)299{300 size_t len;301 302 len = strnlen(s, maxlen);303 if (s[len - 1] == '\n')304 s[len - 1] = '\0';305}306 307/*308 * Attribute operations for netconsole_target.309 */310 311static ssize_t enabled_show(struct config_item *item, char *buf)312{313 return sysfs_emit(buf, "%d\n", to_target(item)->enabled);314}315 316static ssize_t extended_show(struct config_item *item, char *buf)317{318 return sysfs_emit(buf, "%d\n", to_target(item)->extended);319}320 321static ssize_t release_show(struct config_item *item, char *buf)322{323 return sysfs_emit(buf, "%d\n", to_target(item)->release);324}325 326static ssize_t dev_name_show(struct config_item *item, char *buf)327{328 return sysfs_emit(buf, "%s\n", to_target(item)->np.dev_name);329}330 331static ssize_t local_port_show(struct config_item *item, char *buf)332{333 return sysfs_emit(buf, "%d\n", to_target(item)->np.local_port);334}335 336static ssize_t remote_port_show(struct config_item *item, char *buf)337{338 return sysfs_emit(buf, "%d\n", to_target(item)->np.remote_port);339}340 341static ssize_t local_ip_show(struct config_item *item, char *buf)342{343 struct netconsole_target *nt = to_target(item);344 345 if (nt->np.ipv6)346 return sysfs_emit(buf, "%pI6c\n", &nt->np.local_ip.in6);347 else348 return sysfs_emit(buf, "%pI4\n", &nt->np.local_ip);349}350 351static ssize_t remote_ip_show(struct config_item *item, char *buf)352{353 struct netconsole_target *nt = to_target(item);354 355 if (nt->np.ipv6)356 return sysfs_emit(buf, "%pI6c\n", &nt->np.remote_ip.in6);357 else358 return sysfs_emit(buf, "%pI4\n", &nt->np.remote_ip);359}360 361static ssize_t local_mac_show(struct config_item *item, char *buf)362{363 struct net_device *dev = to_target(item)->np.dev;364 static const u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };365 366 return sysfs_emit(buf, "%pM\n", dev ? dev->dev_addr : bcast);367}368 369static ssize_t remote_mac_show(struct config_item *item, char *buf)370{371 return sysfs_emit(buf, "%pM\n", to_target(item)->np.remote_mac);372}373 374/*375 * This one is special -- targets created through the configfs interface376 * are not enabled (and the corresponding netpoll activated) by default.377 * The user is expected to set the desired parameters first (which378 * would enable him to dynamically add new netpoll targets for new379 * network interfaces as and when they come up).380 */381static ssize_t enabled_store(struct config_item *item,382 const char *buf, size_t count)383{384 struct netconsole_target *nt = to_target(item);385 unsigned long flags;386 bool enabled;387 ssize_t ret;388 389 mutex_lock(&dynamic_netconsole_mutex);390 ret = kstrtobool(buf, &enabled);391 if (ret)392 goto out_unlock;393 394 ret = -EINVAL;395 if (enabled == nt->enabled) {396 pr_info("network logging has already %s\n",397 nt->enabled ? "started" : "stopped");398 goto out_unlock;399 }400 401 if (enabled) { /* true */402 if (nt->release && !nt->extended) {403 pr_err("Not enabling netconsole. Release feature requires extended log message");404 goto out_unlock;405 }406 407 if (nt->extended && !console_is_registered(&netconsole_ext))408 register_console(&netconsole_ext);409 410 /*411 * Skip netpoll_parse_options() -- all the attributes are412 * already configured via configfs. Just print them out.413 */414 netpoll_print_options(&nt->np);415 416 ret = netpoll_setup(&nt->np);417 if (ret)418 goto out_unlock;419 420 nt->enabled = true;421 pr_info("network logging started\n");422 } else { /* false */423 /* We need to disable the netconsole before cleaning it up424 * otherwise we might end up in write_msg() with425 * nt->np.dev == NULL and nt->enabled == true426 */427 mutex_lock(&target_cleanup_list_lock);428 spin_lock_irqsave(&target_list_lock, flags);429 nt->enabled = false;430 /* Remove the target from the list, while holding431 * target_list_lock432 */433 list_move(&nt->list, &target_cleanup_list);434 spin_unlock_irqrestore(&target_list_lock, flags);435 mutex_unlock(&target_cleanup_list_lock);436 }437 438 ret = strnlen(buf, count);439 /* Deferred cleanup */440 netconsole_process_cleanups();441out_unlock:442 mutex_unlock(&dynamic_netconsole_mutex);443 return ret;444}445 446static ssize_t release_store(struct config_item *item, const char *buf,447 size_t count)448{449 struct netconsole_target *nt = to_target(item);450 bool release;451 ssize_t ret;452 453 mutex_lock(&dynamic_netconsole_mutex);454 if (nt->enabled) {455 pr_err("target (%s) is enabled, disable to update parameters\n",456 config_item_name(&nt->group.cg_item));457 ret = -EINVAL;458 goto out_unlock;459 }460 461 ret = kstrtobool(buf, &release);462 if (ret)463 goto out_unlock;464 465 nt->release = release;466 467 ret = strnlen(buf, count);468out_unlock:469 mutex_unlock(&dynamic_netconsole_mutex);470 return ret;471}472 473static ssize_t extended_store(struct config_item *item, const char *buf,474 size_t count)475{476 struct netconsole_target *nt = to_target(item);477 bool extended;478 ssize_t ret;479 480 mutex_lock(&dynamic_netconsole_mutex);481 if (nt->enabled) {482 pr_err("target (%s) is enabled, disable to update parameters\n",483 config_item_name(&nt->group.cg_item));484 ret = -EINVAL;485 goto out_unlock;486 }487 488 ret = kstrtobool(buf, &extended);489 if (ret)490 goto out_unlock;491 492 nt->extended = extended;493 ret = strnlen(buf, count);494out_unlock:495 mutex_unlock(&dynamic_netconsole_mutex);496 return ret;497}498 499static ssize_t dev_name_store(struct config_item *item, const char *buf,500 size_t count)501{502 struct netconsole_target *nt = to_target(item);503 504 mutex_lock(&dynamic_netconsole_mutex);505 if (nt->enabled) {506 pr_err("target (%s) is enabled, disable to update parameters\n",507 config_item_name(&nt->group.cg_item));508 mutex_unlock(&dynamic_netconsole_mutex);509 return -EINVAL;510 }511 512 strscpy(nt->np.dev_name, buf, IFNAMSIZ);513 trim_newline(nt->np.dev_name, IFNAMSIZ);514 515 mutex_unlock(&dynamic_netconsole_mutex);516 return strnlen(buf, count);517}518 519static ssize_t local_port_store(struct config_item *item, const char *buf,520 size_t count)521{522 struct netconsole_target *nt = to_target(item);523 ssize_t ret = -EINVAL;524 525 mutex_lock(&dynamic_netconsole_mutex);526 if (nt->enabled) {527 pr_err("target (%s) is enabled, disable to update parameters\n",528 config_item_name(&nt->group.cg_item));529 goto out_unlock;530 }531 532 ret = kstrtou16(buf, 10, &nt->np.local_port);533 if (ret < 0)534 goto out_unlock;535 ret = strnlen(buf, count);536out_unlock:537 mutex_unlock(&dynamic_netconsole_mutex);538 return ret;539}540 541static ssize_t remote_port_store(struct config_item *item,542 const char *buf, size_t count)543{544 struct netconsole_target *nt = to_target(item);545 ssize_t ret = -EINVAL;546 547 mutex_lock(&dynamic_netconsole_mutex);548 if (nt->enabled) {549 pr_err("target (%s) is enabled, disable to update parameters\n",550 config_item_name(&nt->group.cg_item));551 goto out_unlock;552 }553 554 ret = kstrtou16(buf, 10, &nt->np.remote_port);555 if (ret < 0)556 goto out_unlock;557 ret = strnlen(buf, count);558out_unlock:559 mutex_unlock(&dynamic_netconsole_mutex);560 return ret;561}562 563static ssize_t local_ip_store(struct config_item *item, const char *buf,564 size_t count)565{566 struct netconsole_target *nt = to_target(item);567 ssize_t ret = -EINVAL;568 569 mutex_lock(&dynamic_netconsole_mutex);570 if (nt->enabled) {571 pr_err("target (%s) is enabled, disable to update parameters\n",572 config_item_name(&nt->group.cg_item));573 goto out_unlock;574 }575 576 if (strnchr(buf, count, ':')) {577 const char *end;578 579 if (in6_pton(buf, count, nt->np.local_ip.in6.s6_addr, -1, &end) > 0) {580 if (*end && *end != '\n') {581 pr_err("invalid IPv6 address at: <%c>\n", *end);582 goto out_unlock;583 }584 nt->np.ipv6 = true;585 } else586 goto out_unlock;587 } else {588 if (!nt->np.ipv6)589 nt->np.local_ip.ip = in_aton(buf);590 else591 goto out_unlock;592 }593 594 ret = strnlen(buf, count);595out_unlock:596 mutex_unlock(&dynamic_netconsole_mutex);597 return ret;598}599 600static ssize_t remote_ip_store(struct config_item *item, const char *buf,601 size_t count)602{603 struct netconsole_target *nt = to_target(item);604 ssize_t ret = -EINVAL;605 606 mutex_lock(&dynamic_netconsole_mutex);607 if (nt->enabled) {608 pr_err("target (%s) is enabled, disable to update parameters\n",609 config_item_name(&nt->group.cg_item));610 goto out_unlock;611 }612 613 if (strnchr(buf, count, ':')) {614 const char *end;615 616 if (in6_pton(buf, count, nt->np.remote_ip.in6.s6_addr, -1, &end) > 0) {617 if (*end && *end != '\n') {618 pr_err("invalid IPv6 address at: <%c>\n", *end);619 goto out_unlock;620 }621 nt->np.ipv6 = true;622 } else623 goto out_unlock;624 } else {625 if (!nt->np.ipv6)626 nt->np.remote_ip.ip = in_aton(buf);627 else628 goto out_unlock;629 }630 631 ret = strnlen(buf, count);632out_unlock:633 mutex_unlock(&dynamic_netconsole_mutex);634 return ret;635}636 637static ssize_t remote_mac_store(struct config_item *item, const char *buf,638 size_t count)639{640 struct netconsole_target *nt = to_target(item);641 u8 remote_mac[ETH_ALEN];642 ssize_t ret = -EINVAL;643 644 mutex_lock(&dynamic_netconsole_mutex);645 if (nt->enabled) {646 pr_err("target (%s) is enabled, disable to update parameters\n",647 config_item_name(&nt->group.cg_item));648 goto out_unlock;649 }650 651 if (!mac_pton(buf, remote_mac))652 goto out_unlock;653 if (buf[3 * ETH_ALEN - 1] && buf[3 * ETH_ALEN - 1] != '\n')654 goto out_unlock;655 memcpy(nt->np.remote_mac, remote_mac, ETH_ALEN);656 657 ret = strnlen(buf, count);658out_unlock:659 mutex_unlock(&dynamic_netconsole_mutex);660 return ret;661}662 663struct userdatum {664 struct config_item item;665 char value[MAX_USERDATA_VALUE_LENGTH];666};667 668static struct userdatum *to_userdatum(struct config_item *item)669{670 return container_of(item, struct userdatum, item);671}672 673struct userdata {674 struct config_group group;675};676 677static struct userdata *to_userdata(struct config_item *item)678{679 return container_of(to_config_group(item), struct userdata, group);680}681 682static struct netconsole_target *userdata_to_target(struct userdata *ud)683{684 struct config_group *netconsole_group;685 686 netconsole_group = to_config_group(ud->group.cg_item.ci_parent);687 return to_target(&netconsole_group->cg_item);688}689 690static ssize_t userdatum_value_show(struct config_item *item, char *buf)691{692 return sysfs_emit(buf, "%s\n", &(to_userdatum(item)->value[0]));693}694 695static void update_userdata(struct netconsole_target *nt)696{697 int complete_idx = 0, child_count = 0;698 struct list_head *entry;699 700 /* Clear the current string in case the last userdatum was deleted */701 nt->userdata_length = 0;702 nt->userdata_complete[0] = 0;703 704 list_for_each(entry, &nt->userdata_group.cg_children) {705 struct userdatum *udm_item;706 struct config_item *item;707 708 if (child_count >= MAX_USERDATA_ITEMS)709 break;710 child_count++;711 712 item = container_of(entry, struct config_item, ci_entry);713 udm_item = to_userdatum(item);714 715 /* Skip userdata with no value set */716 if (strnlen(udm_item->value, MAX_USERDATA_VALUE_LENGTH) == 0)717 continue;718 719 /* This doesn't overflow userdata_complete since it will write720 * one entry length (1/MAX_USERDATA_ITEMS long), entry count is721 * checked to not exceed MAX items with child_count above722 */723 complete_idx += scnprintf(&nt->userdata_complete[complete_idx],724 MAX_USERDATA_ENTRY_LENGTH, " %s=%s\n",725 item->ci_name, udm_item->value);726 }727 nt->userdata_length = strnlen(nt->userdata_complete,728 sizeof(nt->userdata_complete));729}730 731static ssize_t userdatum_value_store(struct config_item *item, const char *buf,732 size_t count)733{734 struct userdatum *udm = to_userdatum(item);735 struct netconsole_target *nt;736 struct userdata *ud;737 ssize_t ret;738 739 if (count > MAX_USERDATA_VALUE_LENGTH)740 return -EMSGSIZE;741 742 mutex_lock(&dynamic_netconsole_mutex);743 744 ret = strscpy(udm->value, buf, sizeof(udm->value));745 if (ret < 0)746 goto out_unlock;747 trim_newline(udm->value, sizeof(udm->value));748 749 ud = to_userdata(item->ci_parent);750 nt = userdata_to_target(ud);751 update_userdata(nt);752 ret = count;753out_unlock:754 mutex_unlock(&dynamic_netconsole_mutex);755 return ret;756}757 758CONFIGFS_ATTR(userdatum_, value);759 760static struct configfs_attribute *userdatum_attrs[] = {761 &userdatum_attr_value,762 NULL,763};764 765static void userdatum_release(struct config_item *item)766{767 kfree(to_userdatum(item));768}769 770static struct configfs_item_operations userdatum_ops = {771 .release = userdatum_release,772};773 774static const struct config_item_type userdatum_type = {775 .ct_item_ops = &userdatum_ops,776 .ct_attrs = userdatum_attrs,777 .ct_owner = THIS_MODULE,778};779 780static struct config_item *userdatum_make_item(struct config_group *group,781 const char *name)782{783 struct netconsole_target *nt;784 struct userdatum *udm;785 struct userdata *ud;786 size_t child_count;787 788 if (strlen(name) > MAX_USERDATA_NAME_LENGTH)789 return ERR_PTR(-ENAMETOOLONG);790 791 ud = to_userdata(&group->cg_item);792 nt = userdata_to_target(ud);793 child_count = list_count_nodes(&nt->userdata_group.cg_children);794 if (child_count >= MAX_USERDATA_ITEMS)795 return ERR_PTR(-ENOSPC);796 797 udm = kzalloc(sizeof(*udm), GFP_KERNEL);798 if (!udm)799 return ERR_PTR(-ENOMEM);800 801 config_item_init_type_name(&udm->item, name, &userdatum_type);802 return &udm->item;803}804 805static void userdatum_drop(struct config_group *group, struct config_item *item)806{807 struct netconsole_target *nt;808 struct userdata *ud;809 810 ud = to_userdata(&group->cg_item);811 nt = userdata_to_target(ud);812 813 mutex_lock(&dynamic_netconsole_mutex);814 update_userdata(nt);815 config_item_put(item);816 mutex_unlock(&dynamic_netconsole_mutex);817}818 819static struct configfs_attribute *userdata_attrs[] = {820 NULL,821};822 823static struct configfs_group_operations userdata_ops = {824 .make_item = userdatum_make_item,825 .drop_item = userdatum_drop,826};827 828static const struct config_item_type userdata_type = {829 .ct_item_ops = &userdatum_ops,830 .ct_group_ops = &userdata_ops,831 .ct_attrs = userdata_attrs,832 .ct_owner = THIS_MODULE,833};834 835CONFIGFS_ATTR(, enabled);836CONFIGFS_ATTR(, extended);837CONFIGFS_ATTR(, dev_name);838CONFIGFS_ATTR(, local_port);839CONFIGFS_ATTR(, remote_port);840CONFIGFS_ATTR(, local_ip);841CONFIGFS_ATTR(, remote_ip);842CONFIGFS_ATTR_RO(, local_mac);843CONFIGFS_ATTR(, remote_mac);844CONFIGFS_ATTR(, release);845 846static struct configfs_attribute *netconsole_target_attrs[] = {847 &attr_enabled,848 &attr_extended,849 &attr_release,850 &attr_dev_name,851 &attr_local_port,852 &attr_remote_port,853 &attr_local_ip,854 &attr_remote_ip,855 &attr_local_mac,856 &attr_remote_mac,857 NULL,858};859 860/*861 * Item operations and type for netconsole_target.862 */863 864static void netconsole_target_release(struct config_item *item)865{866 kfree(to_target(item));867}868 869static struct configfs_item_operations netconsole_target_item_ops = {870 .release = netconsole_target_release,871};872 873static const struct config_item_type netconsole_target_type = {874 .ct_attrs = netconsole_target_attrs,875 .ct_item_ops = &netconsole_target_item_ops,876 .ct_owner = THIS_MODULE,877};878 879static void init_target_config_group(struct netconsole_target *nt,880 const char *name)881{882 config_group_init_type_name(&nt->group, name, &netconsole_target_type);883 config_group_init_type_name(&nt->userdata_group, "userdata",884 &userdata_type);885 configfs_add_default_group(&nt->userdata_group, &nt->group);886}887 888static struct netconsole_target *find_cmdline_target(const char *name)889{890 struct netconsole_target *nt, *ret = NULL;891 unsigned long flags;892 893 spin_lock_irqsave(&target_list_lock, flags);894 list_for_each_entry(nt, &target_list, list) {895 if (!strcmp(nt->group.cg_item.ci_name, name)) {896 ret = nt;897 break;898 }899 }900 spin_unlock_irqrestore(&target_list_lock, flags);901 902 return ret;903}904 905/*906 * Group operations and type for netconsole_subsys.907 */908 909static struct config_group *make_netconsole_target(struct config_group *group,910 const char *name)911{912 struct netconsole_target *nt;913 unsigned long flags;914 915 /* Checking if a target by this name was created at boot time. If so,916 * attach a configfs entry to that target. This enables dynamic917 * control.918 */919 if (!strncmp(name, NETCONSOLE_PARAM_TARGET_PREFIX,920 strlen(NETCONSOLE_PARAM_TARGET_PREFIX))) {921 nt = find_cmdline_target(name);922 if (nt) {923 init_target_config_group(nt, name);924 return &nt->group;925 }926 }927 928 nt = alloc_and_init();929 if (!nt)930 return ERR_PTR(-ENOMEM);931 932 /* Initialize the config_group member */933 init_target_config_group(nt, name);934 935 /* Adding, but it is disabled */936 spin_lock_irqsave(&target_list_lock, flags);937 list_add(&nt->list, &target_list);938 spin_unlock_irqrestore(&target_list_lock, flags);939 940 return &nt->group;941}942 943static void drop_netconsole_target(struct config_group *group,944 struct config_item *item)945{946 unsigned long flags;947 struct netconsole_target *nt = to_target(item);948 949 spin_lock_irqsave(&target_list_lock, flags);950 list_del(&nt->list);951 spin_unlock_irqrestore(&target_list_lock, flags);952 953 /*954 * The target may have never been enabled, or was manually disabled955 * before being removed so netpoll may have already been cleaned up.956 */957 if (nt->enabled)958 netpoll_cleanup(&nt->np);959 960 config_item_put(&nt->group.cg_item);961}962 963static struct configfs_group_operations netconsole_subsys_group_ops = {964 .make_group = make_netconsole_target,965 .drop_item = drop_netconsole_target,966};967 968static const struct config_item_type netconsole_subsys_type = {969 .ct_group_ops = &netconsole_subsys_group_ops,970 .ct_owner = THIS_MODULE,971};972 973/* The netconsole configfs subsystem */974static struct configfs_subsystem netconsole_subsys = {975 .su_group = {976 .cg_item = {977 .ci_namebuf = "netconsole",978 .ci_type = &netconsole_subsys_type,979 },980 },981};982 983static void populate_configfs_item(struct netconsole_target *nt,984 int cmdline_count)985{986 char target_name[16];987 988 snprintf(target_name, sizeof(target_name), "%s%d",989 NETCONSOLE_PARAM_TARGET_PREFIX, cmdline_count);990 init_target_config_group(nt, target_name);991}992 993#endif /* CONFIG_NETCONSOLE_DYNAMIC */994 995/* Handle network interface device notifications */996static int netconsole_netdev_event(struct notifier_block *this,997 unsigned long event, void *ptr)998{999 unsigned long flags;1000 struct netconsole_target *nt, *tmp;1001 struct net_device *dev = netdev_notifier_info_to_dev(ptr);1002 bool stopped = false;1003 1004 if (!(event == NETDEV_CHANGENAME || event == NETDEV_UNREGISTER ||1005 event == NETDEV_RELEASE || event == NETDEV_JOIN))1006 goto done;1007 1008 mutex_lock(&target_cleanup_list_lock);1009 spin_lock_irqsave(&target_list_lock, flags);1010 list_for_each_entry_safe(nt, tmp, &target_list, list) {1011 netconsole_target_get(nt);1012 if (nt->np.dev == dev) {1013 switch (event) {1014 case NETDEV_CHANGENAME:1015 strscpy(nt->np.dev_name, dev->name, IFNAMSIZ);1016 break;1017 case NETDEV_RELEASE:1018 case NETDEV_JOIN:1019 case NETDEV_UNREGISTER:1020 nt->enabled = false;1021 list_move(&nt->list, &target_cleanup_list);1022 stopped = true;1023 }1024 }1025 netconsole_target_put(nt);1026 }1027 spin_unlock_irqrestore(&target_list_lock, flags);1028 mutex_unlock(&target_cleanup_list_lock);1029 1030 if (stopped) {1031 const char *msg = "had an event";1032 1033 switch (event) {1034 case NETDEV_UNREGISTER:1035 msg = "unregistered";1036 break;1037 case NETDEV_RELEASE:1038 msg = "released slaves";1039 break;1040 case NETDEV_JOIN:1041 msg = "is joining a master device";1042 break;1043 }1044 pr_info("network logging stopped on interface %s as it %s\n",1045 dev->name, msg);1046 }1047 1048 /* Process target_cleanup_list entries. By the end, target_cleanup_list1049 * should be empty1050 */1051 netconsole_process_cleanups_core();1052 1053done:1054 return NOTIFY_DONE;1055}1056 1057static struct notifier_block netconsole_netdev_notifier = {1058 .notifier_call = netconsole_netdev_event,1059};1060 1061/**1062 * send_ext_msg_udp - send extended log message to target1063 * @nt: target to send message to1064 * @msg: extended log message to send1065 * @msg_len: length of message1066 *1067 * Transfer extended log @msg to @nt. If @msg is longer than1068 * MAX_PRINT_CHUNK, it'll be split and transmitted in multiple chunks with1069 * ncfrag header field added to identify them.1070 */1071static void send_ext_msg_udp(struct netconsole_target *nt, const char *msg,1072 int msg_len)1073{1074 static char buf[MAX_PRINT_CHUNK]; /* protected by target_list_lock */1075 const char *header, *body;1076 int offset = 0;1077 int header_len, body_len;1078 const char *msg_ready = msg;1079 const char *release;1080 int release_len = 0;1081 int userdata_len = 0;1082 char *userdata = NULL;1083 1084#ifdef CONFIG_NETCONSOLE_DYNAMIC1085 userdata = nt->userdata_complete;1086 userdata_len = nt->userdata_length;1087#endif1088 1089 if (nt->release) {1090 release = init_utsname()->release;1091 release_len = strlen(release) + 1;1092 }1093 1094 if (msg_len + release_len + userdata_len <= MAX_PRINT_CHUNK) {1095 /* No fragmentation needed */1096 if (nt->release) {1097 scnprintf(buf, MAX_PRINT_CHUNK, "%s,%s", release, msg);1098 msg_len += release_len;1099 } else {1100 memcpy(buf, msg, msg_len);1101 }1102 1103 if (userdata)1104 msg_len += scnprintf(&buf[msg_len],1105 MAX_PRINT_CHUNK - msg_len,1106 "%s", userdata);1107 1108 msg_ready = buf;1109 netpoll_send_udp(&nt->np, msg_ready, msg_len);1110 return;1111 }1112 1113 /* need to insert extra header fields, detect header and body */1114 header = msg;1115 body = memchr(msg, ';', msg_len);1116 if (WARN_ON_ONCE(!body))1117 return;1118 1119 header_len = body - header;1120 body_len = msg_len - header_len - 1;1121 body++;1122 1123 /*1124 * Transfer multiple chunks with the following extra header.1125 * "ncfrag=<byte-offset>/<total-bytes>"1126 */1127 if (nt->release)1128 scnprintf(buf, MAX_PRINT_CHUNK, "%s,", release);1129 memcpy(buf + release_len, header, header_len);1130 header_len += release_len;1131 1132 while (offset < body_len + userdata_len) {1133 int this_header = header_len;1134 int this_offset = 0;1135 int this_chunk = 0;1136 1137 this_header += scnprintf(buf + this_header,1138 sizeof(buf) - this_header,1139 ",ncfrag=%d/%d;", offset,1140 body_len + userdata_len);1141 1142 /* Not all body data has been written yet */1143 if (offset < body_len) {1144 this_chunk = min(body_len - offset,1145 MAX_PRINT_CHUNK - this_header);1146 if (WARN_ON_ONCE(this_chunk <= 0))1147 return;1148 memcpy(buf + this_header, body + offset, this_chunk);1149 this_offset += this_chunk;1150 }1151 /* Body is fully written and there is pending userdata to write,1152 * append userdata in this chunk1153 */1154 if (offset + this_offset >= body_len &&1155 offset + this_offset < userdata_len + body_len) {1156 int sent_userdata = (offset + this_offset) - body_len;1157 int preceding_bytes = this_chunk + this_header;1158 1159 if (WARN_ON_ONCE(sent_userdata < 0))1160 return;1161 1162 this_chunk = min(userdata_len - sent_userdata,1163 MAX_PRINT_CHUNK - preceding_bytes);1164 if (WARN_ON_ONCE(this_chunk < 0))1165 /* this_chunk could be zero if all the previous1166 * message used all the buffer. This is not a1167 * problem, userdata will be sent in the next1168 * iteration1169 */1170 return;1171 1172 memcpy(buf + this_header + this_offset,1173 userdata + sent_userdata,1174 this_chunk);1175 this_offset += this_chunk;1176 }1177 1178 netpoll_send_udp(&nt->np, buf, this_header + this_offset);1179 offset += this_offset;1180 }1181}1182 1183static void write_ext_msg(struct console *con, const char *msg,1184 unsigned int len)1185{1186 struct netconsole_target *nt;1187 unsigned long flags;1188 1189 if ((oops_only && !oops_in_progress) || list_empty(&target_list))1190 return;1191 1192 spin_lock_irqsave(&target_list_lock, flags);1193 list_for_each_entry(nt, &target_list, list)1194 if (nt->extended && nt->enabled && netif_running(nt->np.dev))1195 send_ext_msg_udp(nt, msg, len);1196 spin_unlock_irqrestore(&target_list_lock, flags);1197}1198 1199static void write_msg(struct console *con, const char *msg, unsigned int len)1200{1201 int frag, left;1202 unsigned long flags;1203 struct netconsole_target *nt;1204 const char *tmp;1205 1206 if (oops_only && !oops_in_progress)1207 return;1208 /* Avoid taking lock and disabling interrupts unnecessarily */1209 if (list_empty(&target_list))1210 return;1211 1212 spin_lock_irqsave(&target_list_lock, flags);1213 list_for_each_entry(nt, &target_list, list) {1214 if (!nt->extended && nt->enabled && netif_running(nt->np.dev)) {1215 /*1216 * We nest this inside the for-each-target loop above1217 * so that we're able to get as much logging out to1218 * at least one target if we die inside here, instead1219 * of unnecessarily keeping all targets in lock-step.1220 */1221 tmp = msg;1222 for (left = len; left;) {1223 frag = min(left, MAX_PRINT_CHUNK);1224 netpoll_send_udp(&nt->np, tmp, frag);1225 tmp += frag;1226 left -= frag;1227 }1228 }1229 }1230 spin_unlock_irqrestore(&target_list_lock, flags);1231}1232 1233/* Allocate new target (from boot/module param) and setup netpoll for it */1234static struct netconsole_target *alloc_param_target(char *target_config,1235 int cmdline_count)1236{1237 struct netconsole_target *nt;1238 int err;1239 1240 nt = alloc_and_init();1241 if (!nt) {1242 err = -ENOMEM;1243 goto fail;1244 }1245 1246 if (*target_config == '+') {1247 nt->extended = true;1248 target_config++;1249 }1250 1251 if (*target_config == 'r') {1252 if (!nt->extended) {1253 pr_err("Netconsole configuration error. Release feature requires extended log message");1254 err = -EINVAL;1255 goto fail;1256 }1257 nt->release = true;1258 target_config++;1259 }1260 1261 /* Parse parameters and setup netpoll */1262 err = netpoll_parse_options(&nt->np, target_config);1263 if (err)1264 goto fail;1265 1266 err = netpoll_setup(&nt->np);1267 if (err) {1268 pr_err("Not enabling netconsole for %s%d. Netpoll setup failed\n",1269 NETCONSOLE_PARAM_TARGET_PREFIX, cmdline_count);1270 if (!IS_ENABLED(CONFIG_NETCONSOLE_DYNAMIC))1271 /* only fail if dynamic reconfiguration is set,1272 * otherwise, keep the target in the list, but disabled.1273 */1274 goto fail;1275 } else {1276 nt->enabled = true;1277 }1278 populate_configfs_item(nt, cmdline_count);1279 1280 return nt;1281 1282fail:1283 kfree(nt);1284 return ERR_PTR(err);1285}1286 1287/* Cleanup netpoll for given target (from boot/module param) and free it */1288static void free_param_target(struct netconsole_target *nt)1289{1290 netpoll_cleanup(&nt->np);1291 kfree(nt);1292}1293 1294static struct console netconsole_ext = {1295 .name = "netcon_ext",1296 .flags = CON_ENABLED | CON_EXTENDED,1297 .write = write_ext_msg,1298};1299 1300static struct console netconsole = {1301 .name = "netcon",1302 .flags = CON_ENABLED,1303 .write = write_msg,1304};1305 1306static int __init init_netconsole(void)1307{1308 int err;1309 struct netconsole_target *nt, *tmp;1310 unsigned int count = 0;1311 bool extended = false;1312 unsigned long flags;1313 char *target_config;1314 char *input = config;1315 1316 if (strnlen(input, MAX_PARAM_LENGTH)) {1317 while ((target_config = strsep(&input, ";"))) {1318 nt = alloc_param_target(target_config, count);1319 if (IS_ERR(nt)) {1320 if (IS_ENABLED(CONFIG_NETCONSOLE_DYNAMIC))1321 continue;1322 err = PTR_ERR(nt);1323 goto fail;1324 }1325 /* Dump existing printks when we register */1326 if (nt->extended) {1327 extended = true;1328 netconsole_ext.flags |= CON_PRINTBUFFER;1329 } else {1330 netconsole.flags |= CON_PRINTBUFFER;1331 }1332 1333 spin_lock_irqsave(&target_list_lock, flags);1334 list_add(&nt->list, &target_list);1335 spin_unlock_irqrestore(&target_list_lock, flags);1336 count++;1337 }1338 }1339 1340 err = register_netdevice_notifier(&netconsole_netdev_notifier);1341 if (err)1342 goto fail;1343 1344 err = dynamic_netconsole_init();1345 if (err)1346 goto undonotifier;1347 1348 if (extended)1349 register_console(&netconsole_ext);1350 register_console(&netconsole);1351 pr_info("network logging started\n");1352 1353 return err;1354 1355undonotifier:1356 unregister_netdevice_notifier(&netconsole_netdev_notifier);1357 1358fail:1359 pr_err("cleaning up\n");1360 1361 /*1362 * Remove all targets and destroy them (only targets created1363 * from the boot/module option exist here). Skipping the list1364 * lock is safe here, and netpoll_cleanup() will sleep.1365 */1366 list_for_each_entry_safe(nt, tmp, &target_list, list) {1367 list_del(&nt->list);1368 free_param_target(nt);1369 }1370 1371 return err;1372}1373 1374static void __exit cleanup_netconsole(void)1375{1376 struct netconsole_target *nt, *tmp;1377 1378 if (console_is_registered(&netconsole_ext))1379 unregister_console(&netconsole_ext);1380 unregister_console(&netconsole);1381 dynamic_netconsole_exit();1382 unregister_netdevice_notifier(&netconsole_netdev_notifier);1383 1384 /*1385 * Targets created via configfs pin references on our module1386 * and would first be rmdir(2)'ed from userspace. We reach1387 * here only when they are already destroyed, and only those1388 * created from the boot/module option are left, so remove and1389 * destroy them. Skipping the list lock is safe here, and1390 * netpoll_cleanup() will sleep.1391 */1392 list_for_each_entry_safe(nt, tmp, &target_list, list) {1393 list_del(&nt->list);1394 free_param_target(nt);1395 }1396}1397 1398/*1399 * Use late_initcall to ensure netconsole is1400 * initialized after network device driver if built-in.1401 *1402 * late_initcall() and module_init() are identical if built as module.1403 */1404late_initcall(init_netconsole);1405module_exit(cleanup_netconsole);1406