]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/net/netconsole.c
Merge branch 'vfree' into for-next
[karo-tx-linux.git] / drivers / net / netconsole.c
index 6989ebe2bc7902c44e429dfefda4c432d3eb7131..59ac143dec2576a697d9f383ef4d5d7372eef93c 100644 (file)
@@ -269,12 +269,18 @@ static ssize_t show_remote_port(struct netconsole_target *nt, char *buf)
 
 static ssize_t show_local_ip(struct netconsole_target *nt, char *buf)
 {
-       return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.local_ip);
+       if (nt->np.ipv6)
+               return snprintf(buf, PAGE_SIZE, "%pI6c\n", &nt->np.local_ip.in6);
+       else
+               return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.local_ip);
 }
 
 static ssize_t show_remote_ip(struct netconsole_target *nt, char *buf)
 {
-       return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.remote_ip);
+       if (nt->np.ipv6)
+               return snprintf(buf, PAGE_SIZE, "%pI6c\n", &nt->np.remote_ip.in6);
+       else
+               return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.remote_ip);
 }
 
 static ssize_t show_local_mac(struct netconsole_target *nt, char *buf)
@@ -410,7 +416,22 @@ static ssize_t store_local_ip(struct netconsole_target *nt,
                return -EINVAL;
        }
 
-       nt->np.local_ip = in_aton(buf);
+       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') {
+                               printk(KERN_ERR "netconsole: invalid IPv6 address at: <%c>\n", *end);
+                               return -EINVAL;
+                       }
+                       nt->np.ipv6 = true;
+               } else
+                       return -EINVAL;
+       } else {
+               if (!nt->np.ipv6) {
+                       nt->np.local_ip.ip = in_aton(buf);
+               } else
+                       return -EINVAL;
+       }
 
        return strnlen(buf, count);
 }
@@ -426,7 +447,22 @@ static ssize_t store_remote_ip(struct netconsole_target *nt,
                return -EINVAL;
        }
 
-       nt->np.remote_ip = in_aton(buf);
+       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') {
+                               printk(KERN_ERR "netconsole: invalid IPv6 address at: <%c>\n", *end);
+                               return -EINVAL;
+                       }
+                       nt->np.ipv6 = true;
+               } else
+                       return -EINVAL;
+       } else {
+               if (!nt->np.ipv6) {
+                       nt->np.remote_ip.ip = in_aton(buf);
+               } else
+                       return -EINVAL;
+       }
 
        return strnlen(buf, count);
 }
@@ -630,6 +666,7 @@ static int netconsole_netdev_event(struct notifier_block *this,
                goto done;
 
        spin_lock_irqsave(&target_list_lock, flags);
+restart:
        list_for_each_entry(nt, &target_list, list) {
                netconsole_target_get(nt);
                if (nt->np.dev == dev) {
@@ -642,15 +679,17 @@ static int netconsole_netdev_event(struct notifier_block *this,
                        case NETDEV_UNREGISTER:
                                /*
                                 * rtnl_lock already held
+                                * we might sleep in __netpoll_cleanup()
                                 */
-                               if (nt->np.dev) {
-                                       __netpoll_cleanup(&nt->np);
-                                       dev_put(nt->np.dev);
-                                       nt->np.dev = NULL;
-                               }
+                               spin_unlock_irqrestore(&target_list_lock, flags);
+                               __netpoll_cleanup(&nt->np);
+                               spin_lock_irqsave(&target_list_lock, flags);
+                               dev_put(nt->np.dev);
+                               nt->np.dev = NULL;
                                nt->enabled = 0;
                                stopped = true;
-                               break;
+                               netconsole_target_put(nt);
+                               goto restart;
                        }
                }
                netconsole_target_put(nt);