diff options
Diffstat (limited to 'drivers/net/netconsole.c')
| -rw-r--r-- | drivers/net/netconsole.c | 122 |
1 files changed, 60 insertions, 62 deletions
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index e3722de08ea9..bb6e03a92956 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -300,6 +300,33 @@ static void netconsole_print_banner(struct netpoll *np) np_info(np, "remote ethernet address %pM\n", np->remote_mac); } +/* Parse the string and populate the `inet_addr` union. Return 0 if IPv4 is + * populated, 1 if IPv6 is populated, and -1 upon failure. + */ +static int netpoll_parse_ip_addr(const char *str, union inet_addr *addr) +{ + const char *end = NULL; + int len; + + len = strlen(str); + if (!len) + return -1; + + if (str[len - 1] == '\n') + len -= 1; + + if (in4_pton(str, len, (void *)addr, -1, &end) > 0 && + (!end || *end == 0 || *end == '\n')) + return 0; + + if (IS_ENABLED(CONFIG_IPV6) && + in6_pton(str, len, (void *)addr, -1, &end) > 0 && + (!end || *end == 0 || *end == '\n')) + return 1; + + return -1; +} + #ifdef CONFIG_NETCONSOLE_DYNAMIC /* @@ -730,6 +757,7 @@ static ssize_t local_ip_store(struct config_item *item, const char *buf, { struct netconsole_target *nt = to_target(item); ssize_t ret = -EINVAL; + int ipv6; mutex_lock(&dynamic_netconsole_mutex); if (nt->enabled) { @@ -738,23 +766,10 @@ static ssize_t local_ip_store(struct config_item *item, const char *buf, goto out_unlock; } - if (strnchr(buf, count, ':')) { - const char *end; - - if (in6_pton(buf, count, nt->np.local_ip.in6.s6_addr, -1, &end) > 0) { - if (*end && *end != '\n') { - pr_err("invalid IPv6 address at: <%c>\n", *end); - goto out_unlock; - } - nt->np.ipv6 = true; - } else - goto out_unlock; - } else { - if (!nt->np.ipv6) - nt->np.local_ip.ip = in_aton(buf); - else - goto out_unlock; - } + ipv6 = netpoll_parse_ip_addr(buf, &nt->np.local_ip); + if (ipv6 == -1) + goto out_unlock; + nt->np.ipv6 = !!ipv6; ret = strnlen(buf, count); out_unlock: @@ -767,6 +782,7 @@ static ssize_t remote_ip_store(struct config_item *item, const char *buf, { struct netconsole_target *nt = to_target(item); ssize_t ret = -EINVAL; + int ipv6; mutex_lock(&dynamic_netconsole_mutex); if (nt->enabled) { @@ -775,23 +791,10 @@ static ssize_t remote_ip_store(struct config_item *item, const char *buf, goto out_unlock; } - if (strnchr(buf, count, ':')) { - const char *end; - - if (in6_pton(buf, count, nt->np.remote_ip.in6.s6_addr, -1, &end) > 0) { - if (*end && *end != '\n') { - pr_err("invalid IPv6 address at: <%c>\n", *end); - goto out_unlock; - } - nt->np.ipv6 = true; - } else - goto out_unlock; - } else { - if (!nt->np.ipv6) - nt->np.remote_ip.ip = in_aton(buf); - else - goto out_unlock; - } + ipv6 = netpoll_parse_ip_addr(buf, &nt->np.remote_ip); + if (ipv6 == -1) + goto out_unlock; + nt->np.ipv6 = !!ipv6; ret = strnlen(buf, count); out_unlock: @@ -883,8 +886,11 @@ static ssize_t userdatum_value_show(struct config_item *item, char *buf) static void update_userdata(struct netconsole_target *nt) { - int complete_idx = 0, child_count = 0; struct list_head *entry; + int child_count = 0; + unsigned long flags; + + spin_lock_irqsave(&target_list_lock, flags); /* Clear the current string in case the last userdatum was deleted */ nt->userdata_length = 0; @@ -894,8 +900,11 @@ static void update_userdata(struct netconsole_target *nt) struct userdatum *udm_item; struct config_item *item; - if (WARN_ON_ONCE(child_count >= MAX_EXTRADATA_ITEMS)) - break; + if (child_count >= MAX_EXTRADATA_ITEMS) { + spin_unlock_irqrestore(&target_list_lock, flags); + WARN_ON_ONCE(1); + return; + } child_count++; item = container_of(entry, struct config_item, ci_entry); @@ -909,12 +918,11 @@ static void update_userdata(struct netconsole_target *nt) * one entry length (1/MAX_EXTRADATA_ITEMS long), entry count is * checked to not exceed MAX items with child_count above */ - complete_idx += scnprintf(&nt->extradata_complete[complete_idx], - MAX_EXTRADATA_ENTRY_LEN, " %s=%s\n", - item->ci_name, udm_item->value); + nt->userdata_length += scnprintf(&nt->extradata_complete[nt->userdata_length], + MAX_EXTRADATA_ENTRY_LEN, " %s=%s\n", + item->ci_name, udm_item->value); } - nt->userdata_length = strnlen(nt->extradata_complete, - sizeof(nt->extradata_complete)); + spin_unlock_irqrestore(&target_list_lock, flags); } static ssize_t userdatum_value_store(struct config_item *item, const char *buf, @@ -928,6 +936,7 @@ static ssize_t userdatum_value_store(struct config_item *item, const char *buf, if (count > MAX_EXTRADATA_VALUE_LEN) return -EMSGSIZE; + mutex_lock(&netconsole_subsys.su_mutex); mutex_lock(&dynamic_netconsole_mutex); ret = strscpy(udm->value, buf, sizeof(udm->value)); @@ -941,6 +950,7 @@ static ssize_t userdatum_value_store(struct config_item *item, const char *buf, ret = count; out_unlock: mutex_unlock(&dynamic_netconsole_mutex); + mutex_unlock(&netconsole_subsys.su_mutex); return ret; } @@ -966,6 +976,7 @@ static ssize_t sysdata_msgid_enabled_store(struct config_item *item, if (ret) return ret; + mutex_lock(&netconsole_subsys.su_mutex); mutex_lock(&dynamic_netconsole_mutex); curr = !!(nt->sysdata_fields & SYSDATA_MSGID); if (msgid_enabled == curr) @@ -986,6 +997,7 @@ unlock_ok: ret = strnlen(buf, count); unlock: mutex_unlock(&dynamic_netconsole_mutex); + mutex_unlock(&netconsole_subsys.su_mutex); return ret; } @@ -1000,6 +1012,7 @@ static ssize_t sysdata_release_enabled_store(struct config_item *item, if (ret) return ret; + mutex_lock(&netconsole_subsys.su_mutex); mutex_lock(&dynamic_netconsole_mutex); curr = !!(nt->sysdata_fields & SYSDATA_RELEASE); if (release_enabled == curr) @@ -1020,6 +1033,7 @@ unlock_ok: ret = strnlen(buf, count); unlock: mutex_unlock(&dynamic_netconsole_mutex); + mutex_unlock(&netconsole_subsys.su_mutex); return ret; } @@ -1034,6 +1048,7 @@ static ssize_t sysdata_taskname_enabled_store(struct config_item *item, if (ret) return ret; + mutex_lock(&netconsole_subsys.su_mutex); mutex_lock(&dynamic_netconsole_mutex); curr = !!(nt->sysdata_fields & SYSDATA_TASKNAME); if (taskname_enabled == curr) @@ -1054,6 +1069,7 @@ unlock_ok: ret = strnlen(buf, count); unlock: mutex_unlock(&dynamic_netconsole_mutex); + mutex_unlock(&netconsole_subsys.su_mutex); return ret; } @@ -1069,6 +1085,7 @@ static ssize_t sysdata_cpu_nr_enabled_store(struct config_item *item, if (ret) return ret; + mutex_lock(&netconsole_subsys.su_mutex); mutex_lock(&dynamic_netconsole_mutex); curr = !!(nt->sysdata_fields & SYSDATA_CPU_NR); if (cpu_nr_enabled == curr) @@ -1097,6 +1114,7 @@ unlock_ok: ret = strnlen(buf, count); unlock: mutex_unlock(&dynamic_netconsole_mutex); + mutex_unlock(&netconsole_subsys.su_mutex); return ret; } @@ -1742,26 +1760,6 @@ static void write_msg(struct console *con, const char *msg, unsigned int len) spin_unlock_irqrestore(&target_list_lock, flags); } -static int netpoll_parse_ip_addr(const char *str, union inet_addr *addr) -{ - const char *end; - - if (!strchr(str, ':') && - in4_pton(str, -1, (void *)addr, -1, &end) > 0) { - if (!*end) - return 0; - } - if (in6_pton(str, -1, addr->in6.s6_addr, -1, &end) > 0) { -#if IS_ENABLED(CONFIG_IPV6) - if (!*end) - return 1; -#else - return -1; -#endif - } - return -1; -} - static int netconsole_parser_cmdline(struct netpoll *np, char *opt) { bool ipversion_set = false; |