include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[safe/jmp/linux-2.6] / drivers / infiniband / core / cma.c
index d951896..7794249 100644 (file)
 #include <linux/random.h>
 #include <linux/idr.h>
 #include <linux/inetdevice.h>
+#include <linux/slab.h>
 
 #include <net/tcp.h>
+#include <net/ipv6.h>
 
 #include <rdma/rdma_cm.h>
 #include <rdma/rdma_cm_ib.h>
@@ -296,21 +298,25 @@ static void cma_detach_from_dev(struct rdma_id_private *id_priv)
        id_priv->cma_dev = NULL;
 }
 
-static int cma_set_qkey(struct ib_device *device, u8 port_num,
-                       enum rdma_port_space ps,
-                       struct rdma_dev_addr *dev_addr, u32 *qkey)
+static int cma_set_qkey(struct rdma_id_private *id_priv)
 {
        struct ib_sa_mcmember_rec rec;
        int ret = 0;
 
-       switch (ps) {
+       if (id_priv->qkey)
+               return 0;
+
+       switch (id_priv->id.ps) {
        case RDMA_PS_UDP:
-               *qkey = RDMA_UDP_QKEY;
+               id_priv->qkey = RDMA_UDP_QKEY;
                break;
        case RDMA_PS_IPOIB:
-               ib_addr_get_mgid(dev_addr, &rec.mgid);
-               ret = ib_sa_get_mcmember_rec(device, port_num, &rec.mgid, &rec);
-               *qkey = be32_to_cpu(rec.qkey);
+               ib_addr_get_mgid(&id_priv->id.route.addr.dev_addr, &rec.mgid);
+               ret = ib_sa_get_mcmember_rec(id_priv->id.device,
+                                            id_priv->id.port_num, &rec.mgid,
+                                            &rec);
+               if (!ret)
+                       id_priv->qkey = be32_to_cpu(rec.qkey);
                break;
        default:
                break;
@@ -325,27 +331,12 @@ static int cma_acquire_dev(struct rdma_id_private *id_priv)
        union ib_gid gid;
        int ret = -ENODEV;
 
-       switch (rdma_node_get_transport(dev_addr->dev_type)) {
-       case RDMA_TRANSPORT_IB:
-               ib_addr_get_sgid(dev_addr, &gid);
-               break;
-       case RDMA_TRANSPORT_IWARP:
-               iw_addr_get_sgid(dev_addr, &gid);
-               break;
-       default:
-               return -ENODEV;
-       }
-
+       rdma_addr_get_sgid(dev_addr, &gid);
        list_for_each_entry(cma_dev, &dev_list, list) {
                ret = ib_find_cached_gid(cma_dev->device, &gid,
                                         &id_priv->id.port_num, NULL);
                if (!ret) {
-                       ret = cma_set_qkey(cma_dev->device,
-                                          id_priv->id.port_num,
-                                          id_priv->id.ps, dev_addr,
-                                          &id_priv->qkey);
-                       if (!ret)
-                               cma_attach_to_dev(id_priv, cma_dev);
+                       cma_attach_to_dev(id_priv, cma_dev);
                        break;
                }
        }
@@ -577,6 +568,10 @@ static int cma_ib_init_qp_attr(struct rdma_id_private *id_priv,
        *qp_attr_mask = IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_PORT;
 
        if (cma_is_ud_ps(id_priv->id.ps)) {
+               ret = cma_set_qkey(id_priv);
+               if (ret)
+                       return ret;
+
                qp_attr->qkey = id_priv->qkey;
                *qp_attr_mask |= IB_QP_QKEY;
        } else {
@@ -636,7 +631,12 @@ static inline int cma_zero_addr(struct sockaddr *addr)
 
 static inline int cma_loopback_addr(struct sockaddr *addr)
 {
-       return ipv4_is_loopback(((struct sockaddr_in *) addr)->sin_addr.s_addr);
+       if (addr->sa_family == AF_INET)
+               return ipv4_is_loopback(
+                       ((struct sockaddr_in *) addr)->sin_addr.s_addr);
+       else
+               return ipv6_addr_loopback(
+                       &((struct sockaddr_in6 *) addr)->sin6_addr);
 }
 
 static inline int cma_any_addr(struct sockaddr *addr)
@@ -1023,11 +1023,17 @@ static struct rdma_id_private *cma_new_conn_id(struct rdma_cm_id *listen_id,
        if (rt->num_paths == 2)
                rt->path_rec[1] = *ib_event->param.req_rcvd.alternate_path;
 
-       ib_addr_set_dgid(&rt->addr.dev_addr, &rt->path_rec[0].dgid);
-       ret = rdma_translate_ip((struct sockaddr *) &id->route.addr.src_addr,
-                               &id->route.addr.dev_addr);
-       if (ret)
-               goto destroy_id;
+       if (cma_any_addr((struct sockaddr *) &rt->addr.src_addr)) {
+               rt->addr.dev_addr.dev_type = ARPHRD_INFINIBAND;
+               rdma_addr_set_sgid(&rt->addr.dev_addr, &rt->path_rec[0].sgid);
+               ib_addr_set_pkey(&rt->addr.dev_addr, rt->path_rec[0].pkey);
+       } else {
+               ret = rdma_translate_ip((struct sockaddr *) &rt->addr.src_addr,
+                                       &rt->addr.dev_addr);
+               if (ret)
+                       goto destroy_id;
+       }
+       rdma_addr_set_dgid(&rt->addr.dev_addr, &rt->path_rec[0].dgid);
 
        id_priv = container_of(id, struct rdma_id_private, id);
        id_priv->state = CMA_CONNECT;
@@ -1062,10 +1068,12 @@ static struct rdma_id_private *cma_new_udp_id(struct rdma_cm_id *listen_id,
        cma_save_net_info(&id->route.addr, &listen_id->route.addr,
                          ip_ver, port, src, dst);
 
-       ret = rdma_translate_ip((struct sockaddr *) &id->route.addr.src_addr,
-                               &id->route.addr.dev_addr);
-       if (ret)
-               goto err;
+       if (!cma_any_addr((struct sockaddr *) &id->route.addr.src_addr)) {
+               ret = rdma_translate_ip((struct sockaddr *) &id->route.addr.src_addr,
+                                       &id->route.addr.dev_addr);
+               if (ret)
+                       goto err;
+       }
 
        id_priv = container_of(id, struct rdma_id_private, id);
        id_priv->state = CMA_CONNECT;
@@ -1465,15 +1473,6 @@ static void cma_listen_on_all(struct rdma_id_private *id_priv)
        mutex_unlock(&lock);
 }
 
-static int cma_bind_any(struct rdma_cm_id *id, sa_family_t af)
-{
-       struct sockaddr_in addr_in;
-
-       memset(&addr_in, 0, sizeof addr_in);
-       addr_in.sin_family = af;
-       return rdma_bind_addr(id, (struct sockaddr *) &addr_in);
-}
-
 int rdma_listen(struct rdma_cm_id *id, int backlog)
 {
        struct rdma_id_private *id_priv;
@@ -1481,7 +1480,8 @@ int rdma_listen(struct rdma_cm_id *id, int backlog)
 
        id_priv = container_of(id, struct rdma_id_private, id);
        if (id_priv->state == CMA_IDLE) {
-               ret = cma_bind_any(id, AF_INET);
+               ((struct sockaddr *) &id->route.addr.src_addr)->sa_family = AF_INET;
+               ret = rdma_bind_addr(id, (struct sockaddr *) &id->route.addr.src_addr);
                if (ret)
                        return ret;
        }
@@ -1556,8 +1556,8 @@ static int cma_query_ib_route(struct rdma_id_private *id_priv, int timeout_ms,
        struct sockaddr_in6 *sin6;
 
        memset(&path_rec, 0, sizeof path_rec);
-       ib_addr_get_sgid(&addr->dev_addr, &path_rec.sgid);
-       ib_addr_get_dgid(&addr->dev_addr, &path_rec.dgid);
+       rdma_addr_get_sgid(&addr->dev_addr, &path_rec.sgid);
+       rdma_addr_get_dgid(&addr->dev_addr, &path_rec.dgid);
        path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(&addr->dev_addr));
        path_rec.numb_path = 1;
        path_rec.reversible = 1;
@@ -1772,7 +1772,11 @@ port_found:
        if (ret)
                goto out;
 
-       ib_addr_set_sgid(&id_priv->id.route.addr.dev_addr, &gid);
+       id_priv->id.route.addr.dev_addr.dev_type =
+               (rdma_node_get_transport(cma_dev->device->node_type) == RDMA_TRANSPORT_IB) ?
+               ARPHRD_INFINIBAND : ARPHRD_ETHER;
+
+       rdma_addr_set_sgid(&id_priv->id.route.addr.dev_addr, &gid);
        ib_addr_set_pkey(&id_priv->id.route.addr.dev_addr, pkey);
        id_priv->id.port_num = p;
        cma_attach_to_dev(id_priv, cma_dev);
@@ -1830,7 +1834,7 @@ out:
 static int cma_resolve_loopback(struct rdma_id_private *id_priv)
 {
        struct cma_work *work;
-       struct sockaddr_in *src_in, *dst_in;
+       struct sockaddr *src, *dst;
        union ib_gid gid;
        int ret;
 
@@ -1844,14 +1848,19 @@ static int cma_resolve_loopback(struct rdma_id_private *id_priv)
                        goto err;
        }
 
-       ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid);
-       ib_addr_set_dgid(&id_priv->id.route.addr.dev_addr, &gid);
+       rdma_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid);
+       rdma_addr_set_dgid(&id_priv->id.route.addr.dev_addr, &gid);
 
-       if (cma_zero_addr((struct sockaddr *) &id_priv->id.route.addr.src_addr)) {
-               src_in = (struct sockaddr_in *)&id_priv->id.route.addr.src_addr;
-               dst_in = (struct sockaddr_in *)&id_priv->id.route.addr.dst_addr;
-               src_in->sin_family = dst_in->sin_family;
-               src_in->sin_addr.s_addr = dst_in->sin_addr.s_addr;
+       src = (struct sockaddr *) &id_priv->id.route.addr.src_addr;
+       if (cma_zero_addr(src)) {
+               dst = (struct sockaddr *) &id_priv->id.route.addr.dst_addr;
+               if ((src->sa_family = dst->sa_family) == AF_INET) {
+                       ((struct sockaddr_in *) src)->sin_addr.s_addr =
+                               ((struct sockaddr_in *) dst)->sin_addr.s_addr;
+               } else {
+                       ipv6_addr_copy(&((struct sockaddr_in6 *) src)->sin6_addr,
+                                      &((struct sockaddr_in6 *) dst)->sin6_addr);
+               }
        }
 
        work->id = id_priv;
@@ -1869,10 +1878,14 @@ err:
 static int cma_bind_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
                         struct sockaddr *dst_addr)
 {
-       if (src_addr && src_addr->sa_family)
-               return rdma_bind_addr(id, src_addr);
-       else
-               return cma_bind_any(id, dst_addr->sa_family);
+       if (!src_addr || !src_addr->sa_family) {
+               src_addr = (struct sockaddr *) &id->route.addr.src_addr;
+               if ((src_addr->sa_family = dst_addr->sa_family) == AF_INET6) {
+                       ((struct sockaddr_in6 *) src_addr)->sin6_scope_id =
+                               ((struct sockaddr_in6 *) dst_addr)->sin6_scope_id;
+               }
+       }
+       return rdma_bind_addr(id, src_addr);
 }
 
 int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
@@ -2068,18 +2081,41 @@ static int cma_get_port(struct rdma_id_private *id_priv)
        return ret;
 }
 
+static int cma_check_linklocal(struct rdma_dev_addr *dev_addr,
+                              struct sockaddr *addr)
+{
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       struct sockaddr_in6 *sin6;
+
+       if (addr->sa_family != AF_INET6)
+               return 0;
+
+       sin6 = (struct sockaddr_in6 *) addr;
+       if ((ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) &&
+           !sin6->sin6_scope_id)
+                       return -EINVAL;
+
+       dev_addr->bound_dev_if = sin6->sin6_scope_id;
+#endif
+       return 0;
+}
+
 int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
 {
        struct rdma_id_private *id_priv;
        int ret;
 
-       if (addr->sa_family != AF_INET)
+       if (addr->sa_family != AF_INET && addr->sa_family != AF_INET6)
                return -EAFNOSUPPORT;
 
        id_priv = container_of(id, struct rdma_id_private, id);
        if (!cma_comp_exch(id_priv, CMA_IDLE, CMA_ADDR_BOUND))
                return -EINVAL;
 
+       ret = cma_check_linklocal(&id->route.addr.dev_addr, addr);
+       if (ret)
+               goto err1;
+
        if (!cma_any_addr(addr)) {
                ret = rdma_translate_ip(addr, &id->route.addr.dev_addr);
                if (ret)
@@ -2099,7 +2135,7 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
 
        return 0;
 err2:
-       if (!cma_any_addr(addr)) {
+       if (id_priv->cma_dev) {
                mutex_lock(&lock);
                cma_detach_from_dev(id_priv);
                mutex_unlock(&lock);
@@ -2113,31 +2149,59 @@ EXPORT_SYMBOL(rdma_bind_addr);
 static int cma_format_hdr(void *hdr, enum rdma_port_space ps,
                          struct rdma_route *route)
 {
-       struct sockaddr_in *src4, *dst4;
        struct cma_hdr *cma_hdr;
        struct sdp_hh *sdp_hdr;
 
-       src4 = (struct sockaddr_in *) &route->addr.src_addr;
-       dst4 = (struct sockaddr_in *) &route->addr.dst_addr;
-
-       switch (ps) {
-       case RDMA_PS_SDP:
-               sdp_hdr = hdr;
-               if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION)
-                       return -EINVAL;
-               sdp_set_ip_ver(sdp_hdr, 4);
-               sdp_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr;
-               sdp_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr;
-               sdp_hdr->port = src4->sin_port;
-               break;
-       default:
-               cma_hdr = hdr;
-               cma_hdr->cma_version = CMA_VERSION;
-               cma_set_ip_ver(cma_hdr, 4);
-               cma_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr;
-               cma_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr;
-               cma_hdr->port = src4->sin_port;
-               break;
+       if (route->addr.src_addr.ss_family == AF_INET) {
+               struct sockaddr_in *src4, *dst4;
+
+               src4 = (struct sockaddr_in *) &route->addr.src_addr;
+               dst4 = (struct sockaddr_in *) &route->addr.dst_addr;
+
+               switch (ps) {
+               case RDMA_PS_SDP:
+                       sdp_hdr = hdr;
+                       if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION)
+                               return -EINVAL;
+                       sdp_set_ip_ver(sdp_hdr, 4);
+                       sdp_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr;
+                       sdp_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr;
+                       sdp_hdr->port = src4->sin_port;
+                       break;
+               default:
+                       cma_hdr = hdr;
+                       cma_hdr->cma_version = CMA_VERSION;
+                       cma_set_ip_ver(cma_hdr, 4);
+                       cma_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr;
+                       cma_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr;
+                       cma_hdr->port = src4->sin_port;
+                       break;
+               }
+       } else {
+               struct sockaddr_in6 *src6, *dst6;
+
+               src6 = (struct sockaddr_in6 *) &route->addr.src_addr;
+               dst6 = (struct sockaddr_in6 *) &route->addr.dst_addr;
+
+               switch (ps) {
+               case RDMA_PS_SDP:
+                       sdp_hdr = hdr;
+                       if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION)
+                               return -EINVAL;
+                       sdp_set_ip_ver(sdp_hdr, 6);
+                       sdp_hdr->src_addr.ip6 = src6->sin6_addr;
+                       sdp_hdr->dst_addr.ip6 = dst6->sin6_addr;
+                       sdp_hdr->port = src6->sin6_port;
+                       break;
+               default:
+                       cma_hdr = hdr;
+                       cma_hdr->cma_version = CMA_VERSION;
+                       cma_set_ip_ver(cma_hdr, 6);
+                       cma_hdr->src_addr.ip6 = src6->sin6_addr;
+                       cma_hdr->dst_addr.ip6 = dst6->sin6_addr;
+                       cma_hdr->port = src6->sin6_port;
+                       break;
+               }
        }
        return 0;
 }
@@ -2167,6 +2231,12 @@ static int cma_sidr_rep_handler(struct ib_cm_id *cm_id,
                        event.status = ib_event->param.sidr_rep_rcvd.status;
                        break;
                }
+               ret = cma_set_qkey(id_priv);
+               if (ret) {
+                       event.event = RDMA_CM_EVENT_ADDR_ERROR;
+                       event.status = -EINVAL;
+                       break;
+               }
                if (id_priv->qkey != rep->qkey) {
                        event.event = RDMA_CM_EVENT_UNREACHABLE;
                        event.status = -EINVAL;
@@ -2446,10 +2516,14 @@ static int cma_send_sidr_rep(struct rdma_id_private *id_priv,
                             const void *private_data, int private_data_len)
 {
        struct ib_cm_sidr_rep_param rep;
+       int ret;
 
        memset(&rep, 0, sizeof rep);
        rep.status = status;
        if (status == IB_SIDR_SUCCESS) {
+               ret = cma_set_qkey(id_priv);
+               if (ret)
+                       return ret;
                rep.qp_num = id_priv->qp_num;
                rep.qkey = id_priv->qkey;
        }
@@ -2640,10 +2714,15 @@ static void cma_set_mgid(struct rdma_id_private *id_priv,
        if (cma_any_addr(addr)) {
                memset(mgid, 0, sizeof *mgid);
        } else if ((addr->sa_family == AF_INET6) &&
-                  ((be32_to_cpu(sin6->sin6_addr.s6_addr32[0]) & 0xFF10A01B) ==
+                  ((be32_to_cpu(sin6->sin6_addr.s6_addr32[0]) & 0xFFF0FFFF) ==
                                                                 0xFF10A01B)) {
                /* IPv6 address is an SA assigned MGID. */
                memcpy(mgid, &sin6->sin6_addr, sizeof *mgid);
+       } else if ((addr->sa_family == AF_INET6)) {
+               ipv6_ib_mc_map(&sin6->sin6_addr, dev_addr->broadcast, mc_map);
+               if (id_priv->id.ps == RDMA_PS_UDP)
+                       mc_map[7] = 0x01;       /* Use RDMA CM signature */
+               *mgid = *(union ib_gid *) (mc_map + 4);
        } else {
                ip_ib_mc_map(sin->sin_addr.s_addr, dev_addr->broadcast, mc_map);
                if (id_priv->id.ps == RDMA_PS_UDP)
@@ -2669,7 +2748,7 @@ static int cma_join_ib_multicast(struct rdma_id_private *id_priv,
        cma_set_mgid(id_priv, (struct sockaddr *) &mc->addr, &rec.mgid);
        if (id_priv->id.ps == RDMA_PS_UDP)
                rec.qkey = cpu_to_be32(RDMA_UDP_QKEY);
-       ib_addr_get_sgid(dev_addr, &rec.port_gid);
+       rdma_addr_get_sgid(dev_addr, &rec.port_gid);
        rec.pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr));
        rec.join_state = 1;
 
@@ -2679,6 +2758,10 @@ static int cma_join_ib_multicast(struct rdma_id_private *id_priv,
                    IB_SA_MCMEMBER_REC_FLOW_LABEL |
                    IB_SA_MCMEMBER_REC_TRAFFIC_CLASS;
 
+       if (id_priv->id.ps == RDMA_PS_IPOIB)
+               comp_mask |= IB_SA_MCMEMBER_REC_RATE |
+                            IB_SA_MCMEMBER_REC_RATE_SELECTOR;
+
        mc->multicast.ib = ib_sa_join_multicast(&sa_client, id_priv->id.device,
                                                id_priv->id.port_num, &rec,
                                                comp_mask, GFP_KERNEL,
@@ -2764,7 +2847,7 @@ static int cma_netdev_change(struct net_device *ndev, struct rdma_id_private *id
 
        dev_addr = &id_priv->id.route.addr.dev_addr;
 
-       if ((dev_addr->src_dev == ndev) &&
+       if ((dev_addr->bound_dev_if == ndev->ifindex) &&
            memcmp(dev_addr->src_dev_addr, ndev->dev_addr, ndev->addr_len)) {
                printk(KERN_INFO "RDMA CM addr change for ndev %s used by id %p\n",
                       ndev->name, &id_priv->id);
@@ -2909,7 +2992,7 @@ static void cma_remove_one(struct ib_device *device)
        kfree(cma_dev);
 }
 
-static int cma_init(void)
+static int __init cma_init(void)
 {
        int ret, low, high, remaining;
 
@@ -2939,7 +3022,7 @@ err:
        return ret;
 }
 
-static void cma_cleanup(void)
+static void __exit cma_cleanup(void)
 {
        ib_unregister_client(&cma_client);
        unregister_netdevice_notifier(&cma_nb);