<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 TRANSITIONAL//EN">
<HTML>
<HEAD>
  <META HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=UTF-8">
  <META NAME="GENERATOR" CONTENT="GtkHTML/3.18.1">
</HEAD>
<BODY>
Patch adds IPv6 support for RDMA CM operations. It provides  basic support and have limitations bellow:<BR>
<BR>
No support for link-local addresses.<BR>
Can't use mixed IPv6 and IPv4 addresses as source and destinations<BR>
Not perform checks against ANYCAST address type.<BR>
<BR>
<BR>
Details:<BR>
<BR>
struct addr_req extended to support sockaddr_in6 family<BR>
Functions like address_resolve_local, addr_resolve_remote changed to get pointer to generic sockaddr struct insted of sockadd_in. Such functions used as upper layer, and after parsing sa_family call corresponding IPv6 ot IPv4 function.<BR>
To perform network discovery and to symbols should be exported:<BR>
    nd_table<BR>
    ndisc_send_ns<BR>
<BR>
The points that must be improved to specified above are:<BR>
    recognition of local device by given IP address<BR>
    sending network discovery without exporting symbols<BR>
<BR>
<BR>
Waiting for feedback, suggestions.  <BR>
<BR>
<BR>
-----------------<BR>
<BR>
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c<BR>
index 09a2bec..3c3f665 100644<BR>
--- a/drivers/infiniband/core/addr.c<BR>
+++ b/drivers/infiniband/core/addr.c<BR>
@@ -38,10 +38,13 @@<BR>
 #include <linux/workqueue.h><BR>
 #include <linux/if_arp.h><BR>
 #include <net/arp.h><BR>
+#include <net/ndisc.h><BR>
+#include <net/ip6_route.h><BR>
 #include <net/neighbour.h><BR>
 #include <net/route.h><BR>
 #include <net/netevent.h><BR>
 #include <rdma/ib_addr.h><BR>
+#include <net/addrconf.h><BR>
 <BR>
 MODULE_AUTHOR("Sean Hefty");<BR>
 MODULE_DESCRIPTION("IB Address Translation");<BR>
@@ -50,7 +53,9 @@ MODULE_LICENSE("Dual BSD/GPL");<BR>
 struct addr_req {<BR>
        struct list_head list;<BR>
        struct sockaddr src_addr;<BR>
+       u8 src_pad[sizeof(struct sockaddr_in6) - sizeof(struct sockaddr)];<BR>
        struct sockaddr dst_addr;<BR>
+       u8 dst_pad[sizeof(struct sockaddr_in6) - sizeof(struct sockaddr)];<BR>
        struct rdma_dev_addr *addr;<BR>
        struct rdma_addr_client *client;<BR>
        void *context;<BR>
@@ -113,15 +118,24 @@ EXPORT_SYMBOL(rdma_copy_addr);<BR>
 int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr)<BR>
 {<BR>
        struct net_device *dev;<BR>
-       __be32 ip = ((struct sockaddr_in *) addr)->sin_addr.s_addr;<BR>
        int ret;<BR>
 <BR>
-       dev = ip_dev_find(&init_net, ip);<BR>
-       if (!dev)<BR>
+       if (addr->sa_family  == AF_INET ) {<BR>
+           __be32 ip = ((struct sockaddr_in *) addr)->sin_addr.s_addr;<BR>
+           dev = ip_dev_find(&init_net, ip);<BR>
+           if (!dev)<BR>
                return -EADDRNOTAVAIL;<BR>
 <BR>
-       ret = rdma_copy_addr(dev_addr, dev, NULL);<BR>
-       dev_put(dev);<BR>
+           ret = rdma_copy_addr(dev_addr, dev, NULL);<BR>
+           dev_put(dev);<BR>
+       } else {<BR>
+           for_each_netdev(&init_net, dev)<BR>
+               if ( ipv6_chk_addr(&init_net,  &((struct sockaddr_in6*)addr)->sin6_addr, dev, 1) ) {<BR>
+                   ret = rdma_copy_addr(dev_addr, dev, NULL);<BR>
+                   break;<BR>
+               }<BR>
+       }<BR>
+<BR>
        return ret;<BR>
 }<BR>
 EXPORT_SYMBOL(rdma_translate_ip);<BR>
@@ -171,7 +185,8 @@ static void addr_send_arp(struct sockaddr_in *dst_in)<BR>
        ip_rt_put(rt);<BR>
 }<BR>
 <BR>
-static int addr_resolve_remote(struct sockaddr_in *src_in,<BR>
+<BR>
+static int addr4_resolve_remote(struct sockaddr_in *src_in,<BR>
                               struct sockaddr_in *dst_in,<BR>
                               struct rdma_dev_addr *addr)<BR>
 {<BR>
@@ -220,10 +235,78 @@ out:<BR>
        return ret;<BR>
 }<BR>
 <BR>
+static int addr6_resolve_remote(struct sockaddr_in6 *src_in,<BR>
+                              struct sockaddr_in6 *dst_in,<BR>
+                              struct rdma_dev_addr *addr)<BR>
+{<BR>
+<BR>
+       struct neighbour *neigh;<BR>
+       int ret=-ENODATA;<BR>
+       struct dst_entry *dst;<BR>
+       struct in6_addr *target;<BR>
+       struct in6_addr mcaddr;<BR>
+<BR>
+       struct flowi fl = {<BR>
+               .nl_u = {<BR>
+                       .ip6_u = {<BR>
+                               .daddr = dst_in->sin6_addr,<BR>
+                               .saddr = src_in->sin6_addr,<BR>
+                       },<BR>
+               },<BR>
+       };<BR>
+<BR>
+       dst = ip6_route_output(&init_net, NULL, &fl);<BR>
+       if(!dst)<BR>
+               goto out;<BR>
+<BR>
+       /* If the device does ARP internally, return 'done' */<BR>
+       if (dst->dev->flags & IFF_NOARP) {<BR>
+               ret = rdma_copy_addr(addr, dst->dev, NULL);<BR>
+               goto put;<BR>
+       }<BR>
+<BR>
+       neigh = ndisc_get_neigh(dst->dev, &dst_in->sin6_addr);<BR>
+       if (!neigh) {<BR>
+               ret = -ENOMEM;<BR>
+               goto put;<BR>
+       }<BR>
+<BR>
+       if (!(neigh->nud_state & NUD_VALID)) {<BR>
+               target = (struct in6_addr*)&neigh->primary_key;<BR>
+               addrconf_addr_solict_mult(target, &mcaddr);<BR>
+               ndisc_send_ns(dst->dev, neigh, target, &mcaddr , NULL);<BR>
+               /* ret = rdma_copy_addr(addr, neigh->dev, neigh->ha); */<BR>
+<BR>
+               ret = -ENODATA;<BR>
+               goto release;<BR>
+       }<BR>
+       ret = rdma_copy_addr(addr, neigh->dev, neigh->ha);<BR>
+<BR>
+<BR>
+release:<BR>
+       neigh_release(neigh);<BR>
+put:<BR>
+       dst_release(dst);<BR>
+out:<BR>
+       return ret;<BR>
+}<BR>
+<BR>
+static int addr_resolve_remote(struct sockaddr *src_in,<BR>
+                                       struct sockaddr *dst_in,<BR>
+                                       struct rdma_dev_addr *addr)<BR>
+{<BR>
+       int ret = -ENODATA;<BR>
+       if ( src_in->sa_family == AF_INET ) {<BR>
+               ret = addr4_resolve_remote((struct sockaddr_in*)src_in, (struct sockaddr_in*)dst_in, addr);<BR>
+       } else if ( src_in->sa_family == AF_INET6 ) {<BR>
+               ret = addr6_resolve_remote((struct sockaddr_in6*)src_in, (struct sockaddr_in6*)dst_in, addr);<BR>
+       }<BR>
+       return ret;<BR>
+}<BR>
+<BR>
 static void process_req(struct work_struct *work)<BR>
 {<BR>
        struct addr_req *req, *temp_req;<BR>
-       struct sockaddr_in *src_in, *dst_in;<BR>
        struct list_head done_list;<BR>
 <BR>
        INIT_LIST_HEAD(&done_list);<BR>
@@ -231,10 +314,7 @@ static void process_req(struct work_struct *work)<BR>
        mutex_lock(&lock);<BR>
        list_for_each_entry_safe(req, temp_req, &req_list, list) {<BR>
                if (req->status == -ENODATA) {<BR>
-                       src_in = (struct sockaddr_in *) &req->src_addr;<BR>
-                       dst_in = (struct sockaddr_in *) &req->dst_addr;<BR>
-                       req->status = addr_resolve_remote(src_in, dst_in,<BR>
-                                                         req->addr);<BR>
+                   req->status = addr_resolve_remote(&req->src_addr, &req->dst_addr, req->addr);<BR>
                        if (req->status && time_after_eq(jiffies, req->timeout))<BR>
                                req->status = -ETIMEDOUT;<BR>
                        else if (req->status == -ENODATA)<BR>
@@ -258,7 +338,7 @@ static void process_req(struct work_struct *work)<BR>
        }<BR>
 }<BR>
 <BR>
-static int addr_resolve_local(struct sockaddr_in *src_in,<BR>
+static int addr4_resolve_local(struct sockaddr_in *src_in,<BR>
                              struct sockaddr_in *dst_in,<BR>
                              struct rdma_dev_addr *addr)<BR>
 {<BR>
@@ -289,6 +369,24 @@ static int addr_resolve_local(struct sockaddr_in *src_in,<BR>
        return ret;<BR>
 }<BR>
 <BR>
+static int addr6_resolve_local(struct sockaddr_in6 *src_in,<BR>
+                               struct sockaddr_in6 *dst_in,<BR>
+                               struct rdma_dev_addr *addr)<BR>
+{<BR>
+       return -EADDRNOTAVAIL;<BR>
+}<BR>
+<BR>
+static int addr_resolve_local(struct sockaddr *src_in,<BR>
+                             struct sockaddr *dst_in,<BR>
+                             struct rdma_dev_addr *addr)<BR>
+{<BR>
+       if ( src_in->sa_family == AF_INET ) {<BR>
+                return addr4_resolve_local((struct sockaddr_in*)src_in, (struct sockaddr_in*)dst_in, addr);<BR>
+       } else<BR>
+                return addr6_resolve_local((struct sockaddr_in6*)src_in, (struct sockaddr_in6*)dst_in, addr);<BR>
+}<BR>
+<BR>
+<BR>
 int rdma_resolve_ip(struct rdma_addr_client *client,<BR>
                    struct sockaddr *src_addr, struct sockaddr *dst_addr,<BR>
                    struct rdma_dev_addr *addr, int timeout_ms,<BR>
@@ -296,7 +394,6 @@ int rdma_resolve_ip(struct rdma_addr_client *client,<BR>
                                     struct rdma_dev_addr *addr, void *context),<BR>
                    void *context)<BR>
 {<BR>
-       struct sockaddr_in *src_in, *dst_in;<BR>
        struct addr_req *req;<BR>
        int ret = 0;<BR>
 <BR>
@@ -313,12 +410,10 @@ int rdma_resolve_ip(struct rdma_addr_client *client,<BR>
        req->client = client;<BR>
        atomic_inc(&client->refcount);<BR>
 <BR>
-       src_in = (struct sockaddr_in *) &req->src_addr;<BR>
-       dst_in = (struct sockaddr_in *) &req->dst_addr;<BR>
-<BR>
-       req->status = addr_resolve_local(src_in, dst_in, addr);<BR>
-       if (req->status == -EADDRNOTAVAIL)<BR>
-               req->status = addr_resolve_remote(src_in, dst_in, addr);<BR>
+       req->status = addr_resolve_local(&req->src_addr, &req->dst_addr, addr);<BR>
+       if (req->status == -EADDRNOTAVAIL) {<BR>
+               req->status = addr_resolve_remote(&req->src_addr, &req->dst_addr, addr);<BR>
+       }<BR>
 <BR>
        switch (req->status) {<BR>
        case 0:<BR>
@@ -328,7 +423,8 @@ int rdma_resolve_ip(struct rdma_addr_client *client,<BR>
        case -ENODATA:<BR>
                req->timeout = msecs_to_jiffies(timeout_ms) + jiffies;<BR>
                queue_req(req);<BR>
-               addr_send_arp(dst_in);<BR>
+               if(req->dst_addr.sa_family == AF_INET )<BR>
+                       addr_send_arp((struct sockaddr_in*)&req->dst_addr);<BR>
                break;<BR>
        default:<BR>
                ret = req->status;<BR>
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c<BR>
index e980ff3..87ae995 100644<BR>
--- a/drivers/infiniband/core/cma.c<BR>
+++ b/drivers/infiniband/core/cma.c<BR>
@@ -2074,7 +2074,7 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)<BR>
        struct rdma_id_private *id_priv;<BR>
        int ret;<BR>
 <BR>
-       if (addr->sa_family != AF_INET)<BR>
+       if (addr->sa_family != AF_INET && addr->sa_family != AF_INET6 )<BR>
                return -EAFNOSUPPORT;<BR>
 <BR>
        id_priv = container_of(id, struct rdma_id_private, id);<BR>
@@ -2115,30 +2115,58 @@ static int cma_format_hdr(void *hdr, enum rdma_port_space ps,<BR>
                          struct rdma_route *route)<BR>
 {<BR>
        struct sockaddr_in *src4, *dst4;<BR>
+       struct sockaddr_in6 *src6, *dst6;<BR>
        struct cma_hdr *cma_hdr;<BR>
        struct sdp_hh *sdp_hdr;<BR>
-<BR>
-       src4 = (struct sockaddr_in *) &route->addr.src_addr;<BR>
-       dst4 = (struct sockaddr_in *) &route->addr.dst_addr;<BR>
-<BR>
-       switch (ps) {<BR>
-       case RDMA_PS_SDP:<BR>
-               sdp_hdr = hdr;<BR>
-               if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION)<BR>
-                       return -EINVAL;<BR>
-               sdp_set_ip_ver(sdp_hdr, 4);<BR>
-               sdp_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr;<BR>
-               sdp_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr;<BR>
-               sdp_hdr->port = src4->sin_port;<BR>
-               break;<BR>
-       default:<BR>
-               cma_hdr = hdr;<BR>
-               cma_hdr->cma_version = CMA_VERSION;<BR>
-               cma_set_ip_ver(cma_hdr, 4);<BR>
-               cma_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr;<BR>
-               cma_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr;<BR>
-               cma_hdr->port = src4->sin_port;<BR>
-               break;<BR>
+       if ( route->addr.src_addr.sa_family == AF_INET) {<BR>
+               src4 = (struct sockaddr_in *) &route->addr.src_addr;<BR>
+               dst4 = (struct sockaddr_in *) &route->addr.dst_addr;<BR>
+       }else if (route->addr.src_addr.sa_family == AF_INET6) {<BR>
+               src6 = (struct sockaddr_in6 *) &route->addr.src_addr;<BR>
+               dst6 = (struct sockaddr_in6 *) &route->addr.dst_addr;<BR>
+       }else<BR>
+           return -EINVAL;<BR>
+<BR>
+       if ( route->addr.src_addr.sa_family == AF_INET) {<BR>
+           switch (ps) {<BR>
+               case RDMA_PS_SDP:<BR>
+                        sdp_hdr = hdr;<BR>
+                        if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION)<BR>
+                          return -EINVAL;<BR>
+                        sdp_set_ip_ver(sdp_hdr, 4);<BR>
+                        sdp_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr;<BR>
+                        sdp_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr;<BR>
+                        sdp_hdr->port = src4->sin_port;<BR>
+                        break;<BR>
+               default:<BR>
+                       cma_hdr = hdr;<BR>
+                       cma_hdr->cma_version = CMA_VERSION;<BR>
+                       cma_set_ip_ver(cma_hdr, 4);<BR>
+                       cma_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr;<BR>
+                       cma_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr;<BR>
+                       cma_hdr->port = src4->sin_port;<BR>
+                       break;<BR>
+           }<BR>
+       }else {<BR>
+           switch (ps) {<BR>
+               case RDMA_PS_SDP:<BR>
+                       sdp_hdr = hdr;<BR>
+                       if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION)<BR>
+                           return -EINVAL;<BR>
+                       sdp_set_ip_ver(sdp_hdr, 6);<BR>
+                       sdp_hdr->src_addr.ip6 = src6->sin6_addr;<BR>
+                       sdp_hdr->dst_addr.ip6 = dst6->sin6_addr;<BR>
+                       sdp_hdr->port = src6->sin6_port;<BR>
+                       break;<BR>
+               default:<BR>
+                       cma_hdr = hdr;<BR>
+                       cma_hdr->cma_version = CMA_VERSION;<BR>
+                       cma_set_ip_ver(cma_hdr, 6);<BR>
+                       cma_hdr->src_addr.ip6 = src6->sin6_addr;<BR>
+                       cma_hdr->dst_addr.ip6 = dst6->sin6_addr;<BR>
+                       cma_hdr->port = src6->sin6_port;<BR>
+                       break;<BR>
+       }<BR>
        }<BR>
        return 0;<BR>
 }<BR>
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c<BR>
index beb48e3..fb1f59c 100644<BR>
--- a/net/ipv6/ndisc.c<BR>
+++ b/net/ipv6/ndisc.c<BR>
@@ -157,6 +157,7 @@ struct neigh_table nd_tbl = {<BR>
        .gc_thresh3 =   1024,<BR>
 };<BR>
 <BR>
+EXPORT_SYMBOL(nd_tbl);<BR>
 /* ND options */<BR>
 struct ndisc_options {<BR>
        struct nd_opt_hdr *nd_opt_array[__ND_OPT_ARRAY_MAX];<BR>
@@ -586,6 +587,8 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,<BR>
                     !ipv6_addr_any(saddr) ? ND_OPT_SOURCE_LL_ADDR : 0);<BR>
 }<BR>
 <BR>
+EXPORT_SYMBOL(ndisc_send_ns);<BR>
+<BR>
 void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,<BR>
                   const struct in6_addr *daddr)<BR>
 {<BR>
<BR>
</BODY>
</HTML>