IB/srp: Fix IPv6 address parsing
authorBart Van Assche <bart.vanassche@wdc.com>
Mon, 12 Mar 2018 20:55:55 +0000 (13:55 -0700)
committerDoug Ledford <dledford@redhat.com>
Wed, 14 Mar 2018 19:54:07 +0000 (15:54 -0400)
Split IPv6 addresses at the colon that separates the IPv6 address
and the port number instead of at a colon in the middle of the IPv6
address. Check whether the IPv6 address is surrounded with square
brackets.

Fixes: 19f313438c77 ("IB/srp: Add RDMA/CM support")
Signed-off-by: Bart Van Assche <bart.vanassche@wdc.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
drivers/infiniband/ulp/srp/ib_srp.c

index 9a5ea625145071e5c381e8d22285574b46756cad..4c52ca922f0ba07bc8d9f58401aec441d40d6020 100644 (file)
@@ -3414,18 +3414,37 @@ static const match_table_t srp_opt_tokens = {
        { SRP_OPT_ERR,                  NULL                    }
 };
 
+/**
+ * srp_parse_in - parse an IP address and port number combination
+ *
+ * Parse the following address formats:
+ * - IPv4: <ip_address>:<port>, e.g. 1.2.3.4:5.
+ * - IPv6: \[<ipv6_address>\]:<port>, e.g. [1::2:3%4]:5.
+ */
 static int srp_parse_in(struct net *net, struct sockaddr_storage *sa,
                        const char *addr_port_str)
 {
-       char *addr = kstrdup(addr_port_str, GFP_KERNEL);
-       char *port_str = addr;
+       char *addr_end, *addr = kstrdup(addr_port_str, GFP_KERNEL);
+       char *port_str;
        int ret;
 
        if (!addr)
                return -ENOMEM;
-       strsep(&port_str, ":");
-       ret = inet_pton_with_scope(net, AF_UNSPEC, addr, port_str, sa);
+       port_str = strrchr(addr, ':');
+       if (!port_str)
+               return -EINVAL;
+       *port_str++ = '\0';
+       ret = inet_pton_with_scope(net, AF_INET, addr, port_str, sa);
+       if (ret && addr[0]) {
+               addr_end = addr + strlen(addr) - 1;
+               if (addr[0] == '[' && *addr_end == ']') {
+                       *addr_end = '\0';
+                       ret = inet_pton_with_scope(net, AF_INET6, addr + 1,
+                                                  port_str, sa);
+               }
+       }
        kfree(addr);
+       pr_debug("%s -> %pISpfsc\n", addr_port_str, sa);
        return ret;
 }