1e51060f0SSean Hefty /* 2e51060f0SSean Hefty * Copyright (c) 2005 Voltaire Inc. All rights reserved. 3e51060f0SSean Hefty * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. 4e51060f0SSean Hefty * Copyright (c) 1999-2005, Mellanox Technologies, Inc. All rights reserved. 5e51060f0SSean Hefty * Copyright (c) 2005-2006 Intel Corporation. All rights reserved. 6e51060f0SSean Hefty * 7a9474917SSean Hefty * This software is available to you under a choice of one of two 8a9474917SSean Hefty * licenses. You may choose to be licensed under the terms of the GNU 9a9474917SSean Hefty * General Public License (GPL) Version 2, available from the file 10a9474917SSean Hefty * COPYING in the main directory of this source tree, or the 11a9474917SSean Hefty * OpenIB.org BSD license below: 12e51060f0SSean Hefty * 13a9474917SSean Hefty * Redistribution and use in source and binary forms, with or 14a9474917SSean Hefty * without modification, are permitted provided that the following 15a9474917SSean Hefty * conditions are met: 16e51060f0SSean Hefty * 17a9474917SSean Hefty * - Redistributions of source code must retain the above 18a9474917SSean Hefty * copyright notice, this list of conditions and the following 19a9474917SSean Hefty * disclaimer. 20e51060f0SSean Hefty * 21a9474917SSean Hefty * - Redistributions in binary form must reproduce the above 22a9474917SSean Hefty * copyright notice, this list of conditions and the following 23a9474917SSean Hefty * disclaimer in the documentation and/or other materials 24a9474917SSean Hefty * provided with the distribution. 25e51060f0SSean Hefty * 26a9474917SSean Hefty * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 27a9474917SSean Hefty * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 28a9474917SSean Hefty * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 29a9474917SSean Hefty * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 30a9474917SSean Hefty * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 31a9474917SSean Hefty * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 32a9474917SSean Hefty * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 33a9474917SSean Hefty * SOFTWARE. 34e51060f0SSean Hefty */ 35e51060f0SSean Hefty 36e51060f0SSean Hefty #include <linux/completion.h> 37e51060f0SSean Hefty #include <linux/in.h> 38e51060f0SSean Hefty #include <linux/in6.h> 39e51060f0SSean Hefty #include <linux/mutex.h> 40e51060f0SSean Hefty #include <linux/random.h> 41e51060f0SSean Hefty #include <linux/idr.h> 4207ebafbaSTom Tucker #include <linux/inetdevice.h> 435a0e3ad6STejun Heo #include <linux/slab.h> 44e4dd23d7SPaul Gortmaker #include <linux/module.h> 45366cddb4SAmir Vadai #include <net/route.h> 46e51060f0SSean Hefty 47e51060f0SSean Hefty #include <net/tcp.h> 481f5175adSAleksey Senin #include <net/ipv6.h> 49e51060f0SSean Hefty 50e51060f0SSean Hefty #include <rdma/rdma_cm.h> 51e51060f0SSean Hefty #include <rdma/rdma_cm_ib.h> 52753f618aSNir Muchtar #include <rdma/rdma_netlink.h> 532e2d190cSSean Hefty #include <rdma/ib.h> 54e51060f0SSean Hefty #include <rdma/ib_cache.h> 55e51060f0SSean Hefty #include <rdma/ib_cm.h> 56e51060f0SSean Hefty #include <rdma/ib_sa.h> 5707ebafbaSTom Tucker #include <rdma/iw_cm.h> 58e51060f0SSean Hefty 59e51060f0SSean Hefty MODULE_AUTHOR("Sean Hefty"); 60e51060f0SSean Hefty MODULE_DESCRIPTION("Generic RDMA CM Agent"); 61e51060f0SSean Hefty MODULE_LICENSE("Dual BSD/GPL"); 62e51060f0SSean Hefty 63e51060f0SSean Hefty #define CMA_CM_RESPONSE_TIMEOUT 20 64d5bb7599SMichael S. Tsirkin #define CMA_MAX_CM_RETRIES 15 65dcb3f974SSean Hefty #define CMA_CM_MRA_SETTING (IB_CM_MRA_FLAG_DELAY | 24) 663c86aa70SEli Cohen #define CMA_IBOE_PACKET_LIFETIME 18 67e51060f0SSean Hefty 68e51060f0SSean Hefty static void cma_add_one(struct ib_device *device); 69e51060f0SSean Hefty static void cma_remove_one(struct ib_device *device); 70e51060f0SSean Hefty 71e51060f0SSean Hefty static struct ib_client cma_client = { 72e51060f0SSean Hefty .name = "cma", 73e51060f0SSean Hefty .add = cma_add_one, 74e51060f0SSean Hefty .remove = cma_remove_one 75e51060f0SSean Hefty }; 76e51060f0SSean Hefty 77c1a0b23bSMichael S. Tsirkin static struct ib_sa_client sa_client; 787a118df3SSean Hefty static struct rdma_addr_client addr_client; 79e51060f0SSean Hefty static LIST_HEAD(dev_list); 80e51060f0SSean Hefty static LIST_HEAD(listen_any_list); 81e51060f0SSean Hefty static DEFINE_MUTEX(lock); 82e51060f0SSean Hefty static struct workqueue_struct *cma_wq; 83e51060f0SSean Hefty static DEFINE_IDR(sdp_ps); 84e51060f0SSean Hefty static DEFINE_IDR(tcp_ps); 85628e5f6dSSean Hefty static DEFINE_IDR(udp_ps); 86c8f6a362SSean Hefty static DEFINE_IDR(ipoib_ps); 872d2e9415SSean Hefty static DEFINE_IDR(ib_ps); 88e51060f0SSean Hefty 89e51060f0SSean Hefty struct cma_device { 90e51060f0SSean Hefty struct list_head list; 91e51060f0SSean Hefty struct ib_device *device; 92e51060f0SSean Hefty struct completion comp; 93e51060f0SSean Hefty atomic_t refcount; 94e51060f0SSean Hefty struct list_head id_list; 95e51060f0SSean Hefty }; 96e51060f0SSean Hefty 97e51060f0SSean Hefty struct rdma_bind_list { 98e51060f0SSean Hefty struct idr *ps; 99e51060f0SSean Hefty struct hlist_head owners; 100e51060f0SSean Hefty unsigned short port; 101e51060f0SSean Hefty }; 102e51060f0SSean Hefty 10368602120SSean Hefty enum { 10468602120SSean Hefty CMA_OPTION_AFONLY, 10568602120SSean Hefty }; 10668602120SSean Hefty 107e51060f0SSean Hefty /* 108e51060f0SSean Hefty * Device removal can occur at anytime, so we need extra handling to 109e51060f0SSean Hefty * serialize notifying the user of device removal with other callbacks. 110e51060f0SSean Hefty * We do this by disabling removal notification while a callback is in process, 111e51060f0SSean Hefty * and reporting it after the callback completes. 112e51060f0SSean Hefty */ 113e51060f0SSean Hefty struct rdma_id_private { 114e51060f0SSean Hefty struct rdma_cm_id id; 115e51060f0SSean Hefty 116e51060f0SSean Hefty struct rdma_bind_list *bind_list; 117e51060f0SSean Hefty struct hlist_node node; 118d02d1f53SSean Hefty struct list_head list; /* listen_any_list or cma_device.list */ 119d02d1f53SSean Hefty struct list_head listen_list; /* per device listens */ 120e51060f0SSean Hefty struct cma_device *cma_dev; 121c8f6a362SSean Hefty struct list_head mc_list; 122e51060f0SSean Hefty 123d02d1f53SSean Hefty int internal_id; 124550e5ca7SNir Muchtar enum rdma_cm_state state; 125e51060f0SSean Hefty spinlock_t lock; 126c5483388SSean Hefty struct mutex qp_mutex; 127c5483388SSean Hefty 128e51060f0SSean Hefty struct completion comp; 129e51060f0SSean Hefty atomic_t refcount; 130de910bd9SOr Gerlitz struct mutex handler_mutex; 131e51060f0SSean Hefty 132e51060f0SSean Hefty int backlog; 133e51060f0SSean Hefty int timeout_ms; 134e51060f0SSean Hefty struct ib_sa_query *query; 135e51060f0SSean Hefty int query_id; 136e51060f0SSean Hefty union { 137e51060f0SSean Hefty struct ib_cm_id *ib; 13807ebafbaSTom Tucker struct iw_cm_id *iw; 139e51060f0SSean Hefty } cm_id; 140e51060f0SSean Hefty 141e51060f0SSean Hefty u32 seq_num; 142c8f6a362SSean Hefty u32 qkey; 143e51060f0SSean Hefty u32 qp_num; 14483e9502dSNir Muchtar pid_t owner; 14568602120SSean Hefty u32 options; 146e51060f0SSean Hefty u8 srq; 147a81c994dSSean Hefty u8 tos; 148a9bb7912SHefty, Sean u8 reuseaddr; 1495b0ec991SSean Hefty u8 afonly; 150e51060f0SSean Hefty }; 151e51060f0SSean Hefty 152c8f6a362SSean Hefty struct cma_multicast { 153c8f6a362SSean Hefty struct rdma_id_private *id_priv; 154c8f6a362SSean Hefty union { 155c8f6a362SSean Hefty struct ib_sa_multicast *ib; 156c8f6a362SSean Hefty } multicast; 157c8f6a362SSean Hefty struct list_head list; 158c8f6a362SSean Hefty void *context; 1593f446754SRoland Dreier struct sockaddr_storage addr; 1603c86aa70SEli Cohen struct kref mcref; 161c8f6a362SSean Hefty }; 162c8f6a362SSean Hefty 163e51060f0SSean Hefty struct cma_work { 164e51060f0SSean Hefty struct work_struct work; 165e51060f0SSean Hefty struct rdma_id_private *id; 166550e5ca7SNir Muchtar enum rdma_cm_state old_state; 167550e5ca7SNir Muchtar enum rdma_cm_state new_state; 168e51060f0SSean Hefty struct rdma_cm_event event; 169e51060f0SSean Hefty }; 170e51060f0SSean Hefty 171dd5bdff8SOr Gerlitz struct cma_ndev_work { 172dd5bdff8SOr Gerlitz struct work_struct work; 173dd5bdff8SOr Gerlitz struct rdma_id_private *id; 174dd5bdff8SOr Gerlitz struct rdma_cm_event event; 175dd5bdff8SOr Gerlitz }; 176dd5bdff8SOr Gerlitz 1773c86aa70SEli Cohen struct iboe_mcast_work { 1783c86aa70SEli Cohen struct work_struct work; 1793c86aa70SEli Cohen struct rdma_id_private *id; 1803c86aa70SEli Cohen struct cma_multicast *mc; 1813c86aa70SEli Cohen }; 1823c86aa70SEli Cohen 183e51060f0SSean Hefty union cma_ip_addr { 184e51060f0SSean Hefty struct in6_addr ip6; 185e51060f0SSean Hefty struct { 1861b90c137SAl Viro __be32 pad[3]; 1871b90c137SAl Viro __be32 addr; 188e51060f0SSean Hefty } ip4; 189e51060f0SSean Hefty }; 190e51060f0SSean Hefty 191e51060f0SSean Hefty struct cma_hdr { 192e51060f0SSean Hefty u8 cma_version; 193e51060f0SSean Hefty u8 ip_version; /* IP version: 7:4 */ 1941b90c137SAl Viro __be16 port; 195e51060f0SSean Hefty union cma_ip_addr src_addr; 196e51060f0SSean Hefty union cma_ip_addr dst_addr; 197e51060f0SSean Hefty }; 198e51060f0SSean Hefty 199e51060f0SSean Hefty struct sdp_hh { 200e51060f0SSean Hefty u8 bsdh[16]; 201e51060f0SSean Hefty u8 sdp_version; /* Major version: 7:4 */ 202e51060f0SSean Hefty u8 ip_version; /* IP version: 7:4 */ 203e51060f0SSean Hefty u8 sdp_specific1[10]; 2041b90c137SAl Viro __be16 port; 2051b90c137SAl Viro __be16 sdp_specific2; 206e51060f0SSean Hefty union cma_ip_addr src_addr; 207e51060f0SSean Hefty union cma_ip_addr dst_addr; 208e51060f0SSean Hefty }; 209e51060f0SSean Hefty 210e51060f0SSean Hefty struct sdp_hah { 211e51060f0SSean Hefty u8 bsdh[16]; 212e51060f0SSean Hefty u8 sdp_version; 213e51060f0SSean Hefty }; 214e51060f0SSean Hefty 215e51060f0SSean Hefty #define CMA_VERSION 0x00 216e51060f0SSean Hefty #define SDP_MAJ_VERSION 0x2 217e51060f0SSean Hefty 218550e5ca7SNir Muchtar static int cma_comp(struct rdma_id_private *id_priv, enum rdma_cm_state comp) 219e51060f0SSean Hefty { 220e51060f0SSean Hefty unsigned long flags; 221e51060f0SSean Hefty int ret; 222e51060f0SSean Hefty 223e51060f0SSean Hefty spin_lock_irqsave(&id_priv->lock, flags); 224e51060f0SSean Hefty ret = (id_priv->state == comp); 225e51060f0SSean Hefty spin_unlock_irqrestore(&id_priv->lock, flags); 226e51060f0SSean Hefty return ret; 227e51060f0SSean Hefty } 228e51060f0SSean Hefty 229e51060f0SSean Hefty static int cma_comp_exch(struct rdma_id_private *id_priv, 230550e5ca7SNir Muchtar enum rdma_cm_state comp, enum rdma_cm_state exch) 231e51060f0SSean Hefty { 232e51060f0SSean Hefty unsigned long flags; 233e51060f0SSean Hefty int ret; 234e51060f0SSean Hefty 235e51060f0SSean Hefty spin_lock_irqsave(&id_priv->lock, flags); 236e51060f0SSean Hefty if ((ret = (id_priv->state == comp))) 237e51060f0SSean Hefty id_priv->state = exch; 238e51060f0SSean Hefty spin_unlock_irqrestore(&id_priv->lock, flags); 239e51060f0SSean Hefty return ret; 240e51060f0SSean Hefty } 241e51060f0SSean Hefty 242550e5ca7SNir Muchtar static enum rdma_cm_state cma_exch(struct rdma_id_private *id_priv, 243550e5ca7SNir Muchtar enum rdma_cm_state exch) 244e51060f0SSean Hefty { 245e51060f0SSean Hefty unsigned long flags; 246550e5ca7SNir Muchtar enum rdma_cm_state old; 247e51060f0SSean Hefty 248e51060f0SSean Hefty spin_lock_irqsave(&id_priv->lock, flags); 249e51060f0SSean Hefty old = id_priv->state; 250e51060f0SSean Hefty id_priv->state = exch; 251e51060f0SSean Hefty spin_unlock_irqrestore(&id_priv->lock, flags); 252e51060f0SSean Hefty return old; 253e51060f0SSean Hefty } 254e51060f0SSean Hefty 255e51060f0SSean Hefty static inline u8 cma_get_ip_ver(struct cma_hdr *hdr) 256e51060f0SSean Hefty { 257e51060f0SSean Hefty return hdr->ip_version >> 4; 258e51060f0SSean Hefty } 259e51060f0SSean Hefty 260e51060f0SSean Hefty static inline void cma_set_ip_ver(struct cma_hdr *hdr, u8 ip_ver) 261e51060f0SSean Hefty { 262e51060f0SSean Hefty hdr->ip_version = (ip_ver << 4) | (hdr->ip_version & 0xF); 263e51060f0SSean Hefty } 264e51060f0SSean Hefty 265e51060f0SSean Hefty static inline u8 sdp_get_majv(u8 sdp_version) 266e51060f0SSean Hefty { 267e51060f0SSean Hefty return sdp_version >> 4; 268e51060f0SSean Hefty } 269e51060f0SSean Hefty 270e51060f0SSean Hefty static inline u8 sdp_get_ip_ver(struct sdp_hh *hh) 271e51060f0SSean Hefty { 272e51060f0SSean Hefty return hh->ip_version >> 4; 273e51060f0SSean Hefty } 274e51060f0SSean Hefty 275e51060f0SSean Hefty static inline void sdp_set_ip_ver(struct sdp_hh *hh, u8 ip_ver) 276e51060f0SSean Hefty { 277e51060f0SSean Hefty hh->ip_version = (ip_ver << 4) | (hh->ip_version & 0xF); 278e51060f0SSean Hefty } 279e51060f0SSean Hefty 280e51060f0SSean Hefty static void cma_attach_to_dev(struct rdma_id_private *id_priv, 281e51060f0SSean Hefty struct cma_device *cma_dev) 282e51060f0SSean Hefty { 283e51060f0SSean Hefty atomic_inc(&cma_dev->refcount); 284e51060f0SSean Hefty id_priv->cma_dev = cma_dev; 285e51060f0SSean Hefty id_priv->id.device = cma_dev->device; 2863c86aa70SEli Cohen id_priv->id.route.addr.dev_addr.transport = 2873c86aa70SEli Cohen rdma_node_get_transport(cma_dev->device->node_type); 288e51060f0SSean Hefty list_add_tail(&id_priv->list, &cma_dev->id_list); 289e51060f0SSean Hefty } 290e51060f0SSean Hefty 291e51060f0SSean Hefty static inline void cma_deref_dev(struct cma_device *cma_dev) 292e51060f0SSean Hefty { 293e51060f0SSean Hefty if (atomic_dec_and_test(&cma_dev->refcount)) 294e51060f0SSean Hefty complete(&cma_dev->comp); 295e51060f0SSean Hefty } 296e51060f0SSean Hefty 2973c86aa70SEli Cohen static inline void release_mc(struct kref *kref) 2983c86aa70SEli Cohen { 2993c86aa70SEli Cohen struct cma_multicast *mc = container_of(kref, struct cma_multicast, mcref); 3003c86aa70SEli Cohen 3013c86aa70SEli Cohen kfree(mc->multicast.ib); 3023c86aa70SEli Cohen kfree(mc); 3033c86aa70SEli Cohen } 3043c86aa70SEli Cohen 305a396d43aSSean Hefty static void cma_release_dev(struct rdma_id_private *id_priv) 306e51060f0SSean Hefty { 307a396d43aSSean Hefty mutex_lock(&lock); 308e51060f0SSean Hefty list_del(&id_priv->list); 309e51060f0SSean Hefty cma_deref_dev(id_priv->cma_dev); 310e51060f0SSean Hefty id_priv->cma_dev = NULL; 311a396d43aSSean Hefty mutex_unlock(&lock); 312e51060f0SSean Hefty } 313e51060f0SSean Hefty 314f4753834SSean Hefty static inline struct sockaddr *cma_src_addr(struct rdma_id_private *id_priv) 315f4753834SSean Hefty { 316f4753834SSean Hefty return (struct sockaddr *) &id_priv->id.route.addr.src_addr; 317f4753834SSean Hefty } 318f4753834SSean Hefty 319f4753834SSean Hefty static inline struct sockaddr *cma_dst_addr(struct rdma_id_private *id_priv) 320f4753834SSean Hefty { 321f4753834SSean Hefty return (struct sockaddr *) &id_priv->id.route.addr.dst_addr; 322f4753834SSean Hefty } 323f4753834SSean Hefty 324f4753834SSean Hefty static inline unsigned short cma_family(struct rdma_id_private *id_priv) 325f4753834SSean Hefty { 326f4753834SSean Hefty return id_priv->id.route.addr.src_addr.ss_family; 327f4753834SSean Hefty } 328f4753834SSean Hefty 329d2ca39f2SYossi Etigin static int cma_set_qkey(struct rdma_id_private *id_priv) 330c8f6a362SSean Hefty { 331c8f6a362SSean Hefty struct ib_sa_mcmember_rec rec; 332c8f6a362SSean Hefty int ret = 0; 333c8f6a362SSean Hefty 334d2ca39f2SYossi Etigin if (id_priv->qkey) 335d2ca39f2SYossi Etigin return 0; 336d2ca39f2SYossi Etigin 337d2ca39f2SYossi Etigin switch (id_priv->id.ps) { 338c8f6a362SSean Hefty case RDMA_PS_UDP: 339d2ca39f2SYossi Etigin id_priv->qkey = RDMA_UDP_QKEY; 340c8f6a362SSean Hefty break; 341c8f6a362SSean Hefty case RDMA_PS_IPOIB: 342d2ca39f2SYossi Etigin ib_addr_get_mgid(&id_priv->id.route.addr.dev_addr, &rec.mgid); 343d2ca39f2SYossi Etigin ret = ib_sa_get_mcmember_rec(id_priv->id.device, 344d2ca39f2SYossi Etigin id_priv->id.port_num, &rec.mgid, 345d2ca39f2SYossi Etigin &rec); 346d2ca39f2SYossi Etigin if (!ret) 347d2ca39f2SYossi Etigin id_priv->qkey = be32_to_cpu(rec.qkey); 348c8f6a362SSean Hefty break; 349c8f6a362SSean Hefty default: 350c8f6a362SSean Hefty break; 351c8f6a362SSean Hefty } 352c8f6a362SSean Hefty return ret; 353c8f6a362SSean Hefty } 354c8f6a362SSean Hefty 3553c86aa70SEli Cohen static int find_gid_port(struct ib_device *device, union ib_gid *gid, u8 port_num) 3563c86aa70SEli Cohen { 3573c86aa70SEli Cohen int i; 3583c86aa70SEli Cohen int err; 3593c86aa70SEli Cohen struct ib_port_attr props; 3603c86aa70SEli Cohen union ib_gid tmp; 3613c86aa70SEli Cohen 3623c86aa70SEli Cohen err = ib_query_port(device, port_num, &props); 3633c86aa70SEli Cohen if (err) 36463f05be2Sshefty return err; 3653c86aa70SEli Cohen 3663c86aa70SEli Cohen for (i = 0; i < props.gid_tbl_len; ++i) { 3673c86aa70SEli Cohen err = ib_query_gid(device, port_num, i, &tmp); 3683c86aa70SEli Cohen if (err) 36963f05be2Sshefty return err; 3703c86aa70SEli Cohen if (!memcmp(&tmp, gid, sizeof tmp)) 3713c86aa70SEli Cohen return 0; 3723c86aa70SEli Cohen } 3733c86aa70SEli Cohen 37463f05be2Sshefty return -EADDRNOTAVAIL; 3753c86aa70SEli Cohen } 3763c86aa70SEli Cohen 377680f920aSSean Hefty static void cma_translate_ib(struct sockaddr_ib *sib, struct rdma_dev_addr *dev_addr) 378680f920aSSean Hefty { 379680f920aSSean Hefty dev_addr->dev_type = ARPHRD_INFINIBAND; 380680f920aSSean Hefty rdma_addr_set_sgid(dev_addr, (union ib_gid *) &sib->sib_addr); 381680f920aSSean Hefty ib_addr_set_pkey(dev_addr, ntohs(sib->sib_pkey)); 382680f920aSSean Hefty } 383680f920aSSean Hefty 384680f920aSSean Hefty static int cma_translate_addr(struct sockaddr *addr, struct rdma_dev_addr *dev_addr) 385680f920aSSean Hefty { 386680f920aSSean Hefty int ret; 387680f920aSSean Hefty 388680f920aSSean Hefty if (addr->sa_family != AF_IB) { 389680f920aSSean Hefty ret = rdma_translate_ip(addr, dev_addr); 390680f920aSSean Hefty } else { 391680f920aSSean Hefty cma_translate_ib((struct sockaddr_ib *) addr, dev_addr); 392680f920aSSean Hefty ret = 0; 393680f920aSSean Hefty } 394680f920aSSean Hefty 395680f920aSSean Hefty return ret; 396680f920aSSean Hefty } 397680f920aSSean Hefty 39807ebafbaSTom Tucker static int cma_acquire_dev(struct rdma_id_private *id_priv) 399e51060f0SSean Hefty { 400c8f6a362SSean Hefty struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 401e51060f0SSean Hefty struct cma_device *cma_dev; 4023c86aa70SEli Cohen union ib_gid gid, iboe_gid; 403e51060f0SSean Hefty int ret = -ENODEV; 4043c86aa70SEli Cohen u8 port; 4053c86aa70SEli Cohen enum rdma_link_layer dev_ll = dev_addr->dev_type == ARPHRD_INFINIBAND ? 4063c86aa70SEli Cohen IB_LINK_LAYER_INFINIBAND : IB_LINK_LAYER_ETHERNET; 407e51060f0SSean Hefty 4082efdd6a0SMoni Shoua if (dev_ll != IB_LINK_LAYER_INFINIBAND && 4092efdd6a0SMoni Shoua id_priv->id.ps == RDMA_PS_IPOIB) 4102efdd6a0SMoni Shoua return -EINVAL; 4112efdd6a0SMoni Shoua 412a396d43aSSean Hefty mutex_lock(&lock); 4133c86aa70SEli Cohen iboe_addr_get_sgid(dev_addr, &iboe_gid); 4143c86aa70SEli Cohen memcpy(&gid, dev_addr->src_dev_addr + 4153c86aa70SEli Cohen rdma_addr_gid_offset(dev_addr), sizeof gid); 416e51060f0SSean Hefty list_for_each_entry(cma_dev, &dev_list, list) { 4173c86aa70SEli Cohen for (port = 1; port <= cma_dev->device->phys_port_cnt; ++port) { 4183c86aa70SEli Cohen if (rdma_port_get_link_layer(cma_dev->device, port) == dev_ll) { 4193c86aa70SEli Cohen if (rdma_node_get_transport(cma_dev->device->node_type) == RDMA_TRANSPORT_IB && 4203c86aa70SEli Cohen rdma_port_get_link_layer(cma_dev->device, port) == IB_LINK_LAYER_ETHERNET) 4213c86aa70SEli Cohen ret = find_gid_port(cma_dev->device, &iboe_gid, port); 4223c86aa70SEli Cohen else 4233c86aa70SEli Cohen ret = find_gid_port(cma_dev->device, &gid, port); 4243c86aa70SEli Cohen 425e51060f0SSean Hefty if (!ret) { 4263c86aa70SEli Cohen id_priv->id.port_num = port; 4273c86aa70SEli Cohen goto out; 42863f05be2Sshefty } 429e51060f0SSean Hefty } 430e51060f0SSean Hefty } 4313c86aa70SEli Cohen } 4323c86aa70SEli Cohen 4333c86aa70SEli Cohen out: 4343c86aa70SEli Cohen if (!ret) 4353c86aa70SEli Cohen cma_attach_to_dev(id_priv, cma_dev); 4363c86aa70SEli Cohen 437a396d43aSSean Hefty mutex_unlock(&lock); 438e51060f0SSean Hefty return ret; 439e51060f0SSean Hefty } 440e51060f0SSean Hefty 441*f17df3b0SSean Hefty /* 442*f17df3b0SSean Hefty * Select the source IB device and address to reach the destination IB address. 443*f17df3b0SSean Hefty */ 444*f17df3b0SSean Hefty static int cma_resolve_ib_dev(struct rdma_id_private *id_priv) 445*f17df3b0SSean Hefty { 446*f17df3b0SSean Hefty struct cma_device *cma_dev, *cur_dev; 447*f17df3b0SSean Hefty struct sockaddr_ib *addr; 448*f17df3b0SSean Hefty union ib_gid gid, sgid, *dgid; 449*f17df3b0SSean Hefty u16 pkey, index; 450*f17df3b0SSean Hefty u8 port, p; 451*f17df3b0SSean Hefty int i; 452*f17df3b0SSean Hefty 453*f17df3b0SSean Hefty cma_dev = NULL; 454*f17df3b0SSean Hefty addr = (struct sockaddr_ib *) cma_dst_addr(id_priv); 455*f17df3b0SSean Hefty dgid = (union ib_gid *) &addr->sib_addr; 456*f17df3b0SSean Hefty pkey = ntohs(addr->sib_pkey); 457*f17df3b0SSean Hefty 458*f17df3b0SSean Hefty list_for_each_entry(cur_dev, &dev_list, list) { 459*f17df3b0SSean Hefty if (rdma_node_get_transport(cur_dev->device->node_type) != RDMA_TRANSPORT_IB) 460*f17df3b0SSean Hefty continue; 461*f17df3b0SSean Hefty 462*f17df3b0SSean Hefty for (p = 1; p <= cur_dev->device->phys_port_cnt; ++p) { 463*f17df3b0SSean Hefty if (ib_find_cached_pkey(cur_dev->device, p, pkey, &index)) 464*f17df3b0SSean Hefty continue; 465*f17df3b0SSean Hefty 466*f17df3b0SSean Hefty for (i = 0; !ib_get_cached_gid(cur_dev->device, p, i, &gid); i++) { 467*f17df3b0SSean Hefty if (!memcmp(&gid, dgid, sizeof(gid))) { 468*f17df3b0SSean Hefty cma_dev = cur_dev; 469*f17df3b0SSean Hefty sgid = gid; 470*f17df3b0SSean Hefty port = p; 471*f17df3b0SSean Hefty goto found; 472*f17df3b0SSean Hefty } 473*f17df3b0SSean Hefty 474*f17df3b0SSean Hefty if (!cma_dev && (gid.global.subnet_prefix == 475*f17df3b0SSean Hefty dgid->global.subnet_prefix)) { 476*f17df3b0SSean Hefty cma_dev = cur_dev; 477*f17df3b0SSean Hefty sgid = gid; 478*f17df3b0SSean Hefty port = p; 479*f17df3b0SSean Hefty } 480*f17df3b0SSean Hefty } 481*f17df3b0SSean Hefty } 482*f17df3b0SSean Hefty } 483*f17df3b0SSean Hefty 484*f17df3b0SSean Hefty if (!cma_dev) 485*f17df3b0SSean Hefty return -ENODEV; 486*f17df3b0SSean Hefty 487*f17df3b0SSean Hefty found: 488*f17df3b0SSean Hefty cma_attach_to_dev(id_priv, cma_dev); 489*f17df3b0SSean Hefty id_priv->id.port_num = port; 490*f17df3b0SSean Hefty addr = (struct sockaddr_ib *) cma_src_addr(id_priv); 491*f17df3b0SSean Hefty memcpy(&addr->sib_addr, &sgid, sizeof sgid); 492*f17df3b0SSean Hefty cma_translate_ib(addr, &id_priv->id.route.addr.dev_addr); 493*f17df3b0SSean Hefty return 0; 494*f17df3b0SSean Hefty } 495*f17df3b0SSean Hefty 496e51060f0SSean Hefty static void cma_deref_id(struct rdma_id_private *id_priv) 497e51060f0SSean Hefty { 498e51060f0SSean Hefty if (atomic_dec_and_test(&id_priv->refcount)) 499e51060f0SSean Hefty complete(&id_priv->comp); 500e51060f0SSean Hefty } 501e51060f0SSean Hefty 502de910bd9SOr Gerlitz static int cma_disable_callback(struct rdma_id_private *id_priv, 503550e5ca7SNir Muchtar enum rdma_cm_state state) 5048aa08602SSean Hefty { 505de910bd9SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 506de910bd9SOr Gerlitz if (id_priv->state != state) { 507de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 508de910bd9SOr Gerlitz return -EINVAL; 5098aa08602SSean Hefty } 510de910bd9SOr Gerlitz return 0; 511e51060f0SSean Hefty } 512e51060f0SSean Hefty 513e51060f0SSean Hefty struct rdma_cm_id *rdma_create_id(rdma_cm_event_handler event_handler, 514b26f9b99SSean Hefty void *context, enum rdma_port_space ps, 515b26f9b99SSean Hefty enum ib_qp_type qp_type) 516e51060f0SSean Hefty { 517e51060f0SSean Hefty struct rdma_id_private *id_priv; 518e51060f0SSean Hefty 519e51060f0SSean Hefty id_priv = kzalloc(sizeof *id_priv, GFP_KERNEL); 520e51060f0SSean Hefty if (!id_priv) 521e51060f0SSean Hefty return ERR_PTR(-ENOMEM); 522e51060f0SSean Hefty 52383e9502dSNir Muchtar id_priv->owner = task_pid_nr(current); 524550e5ca7SNir Muchtar id_priv->state = RDMA_CM_IDLE; 525e51060f0SSean Hefty id_priv->id.context = context; 526e51060f0SSean Hefty id_priv->id.event_handler = event_handler; 527e51060f0SSean Hefty id_priv->id.ps = ps; 528b26f9b99SSean Hefty id_priv->id.qp_type = qp_type; 529e51060f0SSean Hefty spin_lock_init(&id_priv->lock); 530c5483388SSean Hefty mutex_init(&id_priv->qp_mutex); 531e51060f0SSean Hefty init_completion(&id_priv->comp); 532e51060f0SSean Hefty atomic_set(&id_priv->refcount, 1); 533de910bd9SOr Gerlitz mutex_init(&id_priv->handler_mutex); 534e51060f0SSean Hefty INIT_LIST_HEAD(&id_priv->listen_list); 535c8f6a362SSean Hefty INIT_LIST_HEAD(&id_priv->mc_list); 536e51060f0SSean Hefty get_random_bytes(&id_priv->seq_num, sizeof id_priv->seq_num); 537e51060f0SSean Hefty 538e51060f0SSean Hefty return &id_priv->id; 539e51060f0SSean Hefty } 540e51060f0SSean Hefty EXPORT_SYMBOL(rdma_create_id); 541e51060f0SSean Hefty 542c8f6a362SSean Hefty static int cma_init_ud_qp(struct rdma_id_private *id_priv, struct ib_qp *qp) 543e51060f0SSean Hefty { 544e51060f0SSean Hefty struct ib_qp_attr qp_attr; 545c8f6a362SSean Hefty int qp_attr_mask, ret; 546e51060f0SSean Hefty 547c8f6a362SSean Hefty qp_attr.qp_state = IB_QPS_INIT; 548c8f6a362SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 549e51060f0SSean Hefty if (ret) 550e51060f0SSean Hefty return ret; 551e51060f0SSean Hefty 552c8f6a362SSean Hefty ret = ib_modify_qp(qp, &qp_attr, qp_attr_mask); 553c8f6a362SSean Hefty if (ret) 554c8f6a362SSean Hefty return ret; 555c8f6a362SSean Hefty 556c8f6a362SSean Hefty qp_attr.qp_state = IB_QPS_RTR; 557c8f6a362SSean Hefty ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE); 558c8f6a362SSean Hefty if (ret) 559c8f6a362SSean Hefty return ret; 560c8f6a362SSean Hefty 561c8f6a362SSean Hefty qp_attr.qp_state = IB_QPS_RTS; 562c8f6a362SSean Hefty qp_attr.sq_psn = 0; 563c8f6a362SSean Hefty ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE | IB_QP_SQ_PSN); 564c8f6a362SSean Hefty 565c8f6a362SSean Hefty return ret; 566e51060f0SSean Hefty } 567e51060f0SSean Hefty 568c8f6a362SSean Hefty static int cma_init_conn_qp(struct rdma_id_private *id_priv, struct ib_qp *qp) 56907ebafbaSTom Tucker { 57007ebafbaSTom Tucker struct ib_qp_attr qp_attr; 571c8f6a362SSean Hefty int qp_attr_mask, ret; 57207ebafbaSTom Tucker 57307ebafbaSTom Tucker qp_attr.qp_state = IB_QPS_INIT; 574c8f6a362SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 575c8f6a362SSean Hefty if (ret) 576c8f6a362SSean Hefty return ret; 57707ebafbaSTom Tucker 578c8f6a362SSean Hefty return ib_modify_qp(qp, &qp_attr, qp_attr_mask); 57907ebafbaSTom Tucker } 58007ebafbaSTom Tucker 581e51060f0SSean Hefty int rdma_create_qp(struct rdma_cm_id *id, struct ib_pd *pd, 582e51060f0SSean Hefty struct ib_qp_init_attr *qp_init_attr) 583e51060f0SSean Hefty { 584e51060f0SSean Hefty struct rdma_id_private *id_priv; 585e51060f0SSean Hefty struct ib_qp *qp; 586e51060f0SSean Hefty int ret; 587e51060f0SSean Hefty 588e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 589e51060f0SSean Hefty if (id->device != pd->device) 590e51060f0SSean Hefty return -EINVAL; 591e51060f0SSean Hefty 592e51060f0SSean Hefty qp = ib_create_qp(pd, qp_init_attr); 593e51060f0SSean Hefty if (IS_ERR(qp)) 594e51060f0SSean Hefty return PTR_ERR(qp); 595e51060f0SSean Hefty 596b26f9b99SSean Hefty if (id->qp_type == IB_QPT_UD) 597c8f6a362SSean Hefty ret = cma_init_ud_qp(id_priv, qp); 598c8f6a362SSean Hefty else 599c8f6a362SSean Hefty ret = cma_init_conn_qp(id_priv, qp); 600e51060f0SSean Hefty if (ret) 601e51060f0SSean Hefty goto err; 602e51060f0SSean Hefty 603e51060f0SSean Hefty id->qp = qp; 604e51060f0SSean Hefty id_priv->qp_num = qp->qp_num; 605e51060f0SSean Hefty id_priv->srq = (qp->srq != NULL); 606e51060f0SSean Hefty return 0; 607e51060f0SSean Hefty err: 608e51060f0SSean Hefty ib_destroy_qp(qp); 609e51060f0SSean Hefty return ret; 610e51060f0SSean Hefty } 611e51060f0SSean Hefty EXPORT_SYMBOL(rdma_create_qp); 612e51060f0SSean Hefty 613e51060f0SSean Hefty void rdma_destroy_qp(struct rdma_cm_id *id) 614e51060f0SSean Hefty { 615c5483388SSean Hefty struct rdma_id_private *id_priv; 616c5483388SSean Hefty 617c5483388SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 618c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 619c5483388SSean Hefty ib_destroy_qp(id_priv->id.qp); 620c5483388SSean Hefty id_priv->id.qp = NULL; 621c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 622e51060f0SSean Hefty } 623e51060f0SSean Hefty EXPORT_SYMBOL(rdma_destroy_qp); 624e51060f0SSean Hefty 6255851bb89SSean Hefty static int cma_modify_qp_rtr(struct rdma_id_private *id_priv, 6265851bb89SSean Hefty struct rdma_conn_param *conn_param) 627e51060f0SSean Hefty { 628e51060f0SSean Hefty struct ib_qp_attr qp_attr; 629e51060f0SSean Hefty int qp_attr_mask, ret; 630e51060f0SSean Hefty 631c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 632c5483388SSean Hefty if (!id_priv->id.qp) { 633c5483388SSean Hefty ret = 0; 634c5483388SSean Hefty goto out; 635c5483388SSean Hefty } 636e51060f0SSean Hefty 637e51060f0SSean Hefty /* Need to update QP attributes from default values. */ 638e51060f0SSean Hefty qp_attr.qp_state = IB_QPS_INIT; 639c5483388SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 640e51060f0SSean Hefty if (ret) 641c5483388SSean Hefty goto out; 642e51060f0SSean Hefty 643c5483388SSean Hefty ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask); 644e51060f0SSean Hefty if (ret) 645c5483388SSean Hefty goto out; 646e51060f0SSean Hefty 647e51060f0SSean Hefty qp_attr.qp_state = IB_QPS_RTR; 648c5483388SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 649e51060f0SSean Hefty if (ret) 650c5483388SSean Hefty goto out; 651e51060f0SSean Hefty 6525851bb89SSean Hefty if (conn_param) 6535851bb89SSean Hefty qp_attr.max_dest_rd_atomic = conn_param->responder_resources; 654c5483388SSean Hefty ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask); 655c5483388SSean Hefty out: 656c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 657c5483388SSean Hefty return ret; 658e51060f0SSean Hefty } 659e51060f0SSean Hefty 6605851bb89SSean Hefty static int cma_modify_qp_rts(struct rdma_id_private *id_priv, 6615851bb89SSean Hefty struct rdma_conn_param *conn_param) 662e51060f0SSean Hefty { 663e51060f0SSean Hefty struct ib_qp_attr qp_attr; 664e51060f0SSean Hefty int qp_attr_mask, ret; 665e51060f0SSean Hefty 666c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 667c5483388SSean Hefty if (!id_priv->id.qp) { 668c5483388SSean Hefty ret = 0; 669c5483388SSean Hefty goto out; 670e51060f0SSean Hefty } 671e51060f0SSean Hefty 672c5483388SSean Hefty qp_attr.qp_state = IB_QPS_RTS; 673c5483388SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 674c5483388SSean Hefty if (ret) 675c5483388SSean Hefty goto out; 676c5483388SSean Hefty 6775851bb89SSean Hefty if (conn_param) 6785851bb89SSean Hefty qp_attr.max_rd_atomic = conn_param->initiator_depth; 679c5483388SSean Hefty ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask); 680c5483388SSean Hefty out: 681c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 682c5483388SSean Hefty return ret; 683c5483388SSean Hefty } 684c5483388SSean Hefty 685c5483388SSean Hefty static int cma_modify_qp_err(struct rdma_id_private *id_priv) 686e51060f0SSean Hefty { 687e51060f0SSean Hefty struct ib_qp_attr qp_attr; 688c5483388SSean Hefty int ret; 689e51060f0SSean Hefty 690c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 691c5483388SSean Hefty if (!id_priv->id.qp) { 692c5483388SSean Hefty ret = 0; 693c5483388SSean Hefty goto out; 694c5483388SSean Hefty } 695e51060f0SSean Hefty 696e51060f0SSean Hefty qp_attr.qp_state = IB_QPS_ERR; 697c5483388SSean Hefty ret = ib_modify_qp(id_priv->id.qp, &qp_attr, IB_QP_STATE); 698c5483388SSean Hefty out: 699c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 700c5483388SSean Hefty return ret; 701e51060f0SSean Hefty } 702e51060f0SSean Hefty 703c8f6a362SSean Hefty static int cma_ib_init_qp_attr(struct rdma_id_private *id_priv, 704c8f6a362SSean Hefty struct ib_qp_attr *qp_attr, int *qp_attr_mask) 705c8f6a362SSean Hefty { 706c8f6a362SSean Hefty struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 707c8f6a362SSean Hefty int ret; 7083c86aa70SEli Cohen u16 pkey; 7093c86aa70SEli Cohen 7103c86aa70SEli Cohen if (rdma_port_get_link_layer(id_priv->id.device, id_priv->id.port_num) == 7113c86aa70SEli Cohen IB_LINK_LAYER_INFINIBAND) 7123c86aa70SEli Cohen pkey = ib_addr_get_pkey(dev_addr); 7133c86aa70SEli Cohen else 7143c86aa70SEli Cohen pkey = 0xffff; 715c8f6a362SSean Hefty 716c8f6a362SSean Hefty ret = ib_find_cached_pkey(id_priv->id.device, id_priv->id.port_num, 7173c86aa70SEli Cohen pkey, &qp_attr->pkey_index); 718c8f6a362SSean Hefty if (ret) 719c8f6a362SSean Hefty return ret; 720c8f6a362SSean Hefty 721c8f6a362SSean Hefty qp_attr->port_num = id_priv->id.port_num; 722c8f6a362SSean Hefty *qp_attr_mask = IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_PORT; 723c8f6a362SSean Hefty 724b26f9b99SSean Hefty if (id_priv->id.qp_type == IB_QPT_UD) { 725d2ca39f2SYossi Etigin ret = cma_set_qkey(id_priv); 726d2ca39f2SYossi Etigin if (ret) 727d2ca39f2SYossi Etigin return ret; 728d2ca39f2SYossi Etigin 729c8f6a362SSean Hefty qp_attr->qkey = id_priv->qkey; 730c8f6a362SSean Hefty *qp_attr_mask |= IB_QP_QKEY; 731c8f6a362SSean Hefty } else { 732c8f6a362SSean Hefty qp_attr->qp_access_flags = 0; 733c8f6a362SSean Hefty *qp_attr_mask |= IB_QP_ACCESS_FLAGS; 734c8f6a362SSean Hefty } 735c8f6a362SSean Hefty return 0; 736c8f6a362SSean Hefty } 737c8f6a362SSean Hefty 738e51060f0SSean Hefty int rdma_init_qp_attr(struct rdma_cm_id *id, struct ib_qp_attr *qp_attr, 739e51060f0SSean Hefty int *qp_attr_mask) 740e51060f0SSean Hefty { 741e51060f0SSean Hefty struct rdma_id_private *id_priv; 742c8f6a362SSean Hefty int ret = 0; 743e51060f0SSean Hefty 744e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 74507ebafbaSTom Tucker switch (rdma_node_get_transport(id_priv->id.device->node_type)) { 74607ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 747b26f9b99SSean Hefty if (!id_priv->cm_id.ib || (id_priv->id.qp_type == IB_QPT_UD)) 748c8f6a362SSean Hefty ret = cma_ib_init_qp_attr(id_priv, qp_attr, qp_attr_mask); 749c8f6a362SSean Hefty else 750e51060f0SSean Hefty ret = ib_cm_init_qp_attr(id_priv->cm_id.ib, qp_attr, 751e51060f0SSean Hefty qp_attr_mask); 752e51060f0SSean Hefty if (qp_attr->qp_state == IB_QPS_RTR) 753e51060f0SSean Hefty qp_attr->rq_psn = id_priv->seq_num; 754e51060f0SSean Hefty break; 75507ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 756c8f6a362SSean Hefty if (!id_priv->cm_id.iw) { 7578f076531SDotan Barak qp_attr->qp_access_flags = 0; 758c8f6a362SSean Hefty *qp_attr_mask = IB_QP_STATE | IB_QP_ACCESS_FLAGS; 759c8f6a362SSean Hefty } else 76007ebafbaSTom Tucker ret = iw_cm_init_qp_attr(id_priv->cm_id.iw, qp_attr, 76107ebafbaSTom Tucker qp_attr_mask); 76207ebafbaSTom Tucker break; 763e51060f0SSean Hefty default: 764e51060f0SSean Hefty ret = -ENOSYS; 765e51060f0SSean Hefty break; 766e51060f0SSean Hefty } 767e51060f0SSean Hefty 768e51060f0SSean Hefty return ret; 769e51060f0SSean Hefty } 770e51060f0SSean Hefty EXPORT_SYMBOL(rdma_init_qp_attr); 771e51060f0SSean Hefty 772e51060f0SSean Hefty static inline int cma_zero_addr(struct sockaddr *addr) 773e51060f0SSean Hefty { 7742e2d190cSSean Hefty switch (addr->sa_family) { 7752e2d190cSSean Hefty case AF_INET: 7762e2d190cSSean Hefty return ipv4_is_zeronet(((struct sockaddr_in *)addr)->sin_addr.s_addr); 7772e2d190cSSean Hefty case AF_INET6: 7782e2d190cSSean Hefty return ipv6_addr_any(&((struct sockaddr_in6 *) addr)->sin6_addr); 7792e2d190cSSean Hefty case AF_IB: 7802e2d190cSSean Hefty return ib_addr_any(&((struct sockaddr_ib *) addr)->sib_addr); 7812e2d190cSSean Hefty default: 7822e2d190cSSean Hefty return 0; 783e51060f0SSean Hefty } 784e51060f0SSean Hefty } 785e51060f0SSean Hefty 786e51060f0SSean Hefty static inline int cma_loopback_addr(struct sockaddr *addr) 787e51060f0SSean Hefty { 7882e2d190cSSean Hefty switch (addr->sa_family) { 7892e2d190cSSean Hefty case AF_INET: 7902e2d190cSSean Hefty return ipv4_is_loopback(((struct sockaddr_in *) addr)->sin_addr.s_addr); 7912e2d190cSSean Hefty case AF_INET6: 7922e2d190cSSean Hefty return ipv6_addr_loopback(&((struct sockaddr_in6 *) addr)->sin6_addr); 7932e2d190cSSean Hefty case AF_IB: 7942e2d190cSSean Hefty return ib_addr_loopback(&((struct sockaddr_ib *) addr)->sib_addr); 7952e2d190cSSean Hefty default: 7962e2d190cSSean Hefty return 0; 7972e2d190cSSean Hefty } 798e51060f0SSean Hefty } 799e51060f0SSean Hefty 800e51060f0SSean Hefty static inline int cma_any_addr(struct sockaddr *addr) 801e51060f0SSean Hefty { 802e51060f0SSean Hefty return cma_zero_addr(addr) || cma_loopback_addr(addr); 803e51060f0SSean Hefty } 804e51060f0SSean Hefty 80543b752daSHefty, Sean static int cma_addr_cmp(struct sockaddr *src, struct sockaddr *dst) 80643b752daSHefty, Sean { 80743b752daSHefty, Sean if (src->sa_family != dst->sa_family) 80843b752daSHefty, Sean return -1; 80943b752daSHefty, Sean 81043b752daSHefty, Sean switch (src->sa_family) { 81143b752daSHefty, Sean case AF_INET: 81243b752daSHefty, Sean return ((struct sockaddr_in *) src)->sin_addr.s_addr != 81343b752daSHefty, Sean ((struct sockaddr_in *) dst)->sin_addr.s_addr; 8142e2d190cSSean Hefty case AF_INET6: 81543b752daSHefty, Sean return ipv6_addr_cmp(&((struct sockaddr_in6 *) src)->sin6_addr, 81643b752daSHefty, Sean &((struct sockaddr_in6 *) dst)->sin6_addr); 8172e2d190cSSean Hefty default: 8182e2d190cSSean Hefty return ib_addr_cmp(&((struct sockaddr_ib *) src)->sib_addr, 8192e2d190cSSean Hefty &((struct sockaddr_ib *) dst)->sib_addr); 82043b752daSHefty, Sean } 82143b752daSHefty, Sean } 82243b752daSHefty, Sean 82358afdcb7SSean Hefty static __be16 cma_port(struct sockaddr *addr) 824628e5f6dSSean Hefty { 82558afdcb7SSean Hefty struct sockaddr_ib *sib; 82658afdcb7SSean Hefty 82758afdcb7SSean Hefty switch (addr->sa_family) { 82858afdcb7SSean Hefty case AF_INET: 829628e5f6dSSean Hefty return ((struct sockaddr_in *) addr)->sin_port; 83058afdcb7SSean Hefty case AF_INET6: 831628e5f6dSSean Hefty return ((struct sockaddr_in6 *) addr)->sin6_port; 83258afdcb7SSean Hefty case AF_IB: 83358afdcb7SSean Hefty sib = (struct sockaddr_ib *) addr; 83458afdcb7SSean Hefty return htons((u16) (be64_to_cpu(sib->sib_sid) & 83558afdcb7SSean Hefty be64_to_cpu(sib->sib_sid_mask))); 83658afdcb7SSean Hefty default: 83758afdcb7SSean Hefty return 0; 83858afdcb7SSean Hefty } 839628e5f6dSSean Hefty } 840628e5f6dSSean Hefty 841e51060f0SSean Hefty static inline int cma_any_port(struct sockaddr *addr) 842e51060f0SSean Hefty { 843628e5f6dSSean Hefty return !cma_port(addr); 844e51060f0SSean Hefty } 845e51060f0SSean Hefty 846e51060f0SSean Hefty static int cma_get_net_info(void *hdr, enum rdma_port_space ps, 8471b90c137SAl Viro u8 *ip_ver, __be16 *port, 848e51060f0SSean Hefty union cma_ip_addr **src, union cma_ip_addr **dst) 849e51060f0SSean Hefty { 850e51060f0SSean Hefty switch (ps) { 851e51060f0SSean Hefty case RDMA_PS_SDP: 852e51060f0SSean Hefty if (sdp_get_majv(((struct sdp_hh *) hdr)->sdp_version) != 853e51060f0SSean Hefty SDP_MAJ_VERSION) 854e51060f0SSean Hefty return -EINVAL; 855e51060f0SSean Hefty 856e51060f0SSean Hefty *ip_ver = sdp_get_ip_ver(hdr); 857e51060f0SSean Hefty *port = ((struct sdp_hh *) hdr)->port; 858e51060f0SSean Hefty *src = &((struct sdp_hh *) hdr)->src_addr; 859e51060f0SSean Hefty *dst = &((struct sdp_hh *) hdr)->dst_addr; 860e51060f0SSean Hefty break; 861e51060f0SSean Hefty default: 862e51060f0SSean Hefty if (((struct cma_hdr *) hdr)->cma_version != CMA_VERSION) 863e51060f0SSean Hefty return -EINVAL; 864e51060f0SSean Hefty 865e51060f0SSean Hefty *ip_ver = cma_get_ip_ver(hdr); 866e51060f0SSean Hefty *port = ((struct cma_hdr *) hdr)->port; 867e51060f0SSean Hefty *src = &((struct cma_hdr *) hdr)->src_addr; 868e51060f0SSean Hefty *dst = &((struct cma_hdr *) hdr)->dst_addr; 869e51060f0SSean Hefty break; 870e51060f0SSean Hefty } 871e51060f0SSean Hefty 872e51060f0SSean Hefty if (*ip_ver != 4 && *ip_ver != 6) 873e51060f0SSean Hefty return -EINVAL; 874e51060f0SSean Hefty return 0; 875e51060f0SSean Hefty } 876e51060f0SSean Hefty 877e51060f0SSean Hefty static void cma_save_net_info(struct rdma_addr *addr, 878e51060f0SSean Hefty struct rdma_addr *listen_addr, 8791b90c137SAl Viro u8 ip_ver, __be16 port, 880e51060f0SSean Hefty union cma_ip_addr *src, union cma_ip_addr *dst) 881e51060f0SSean Hefty { 882e51060f0SSean Hefty struct sockaddr_in *listen4, *ip4; 883e51060f0SSean Hefty struct sockaddr_in6 *listen6, *ip6; 884e51060f0SSean Hefty 885e51060f0SSean Hefty switch (ip_ver) { 886e51060f0SSean Hefty case 4: 887e51060f0SSean Hefty listen4 = (struct sockaddr_in *) &listen_addr->src_addr; 888e51060f0SSean Hefty ip4 = (struct sockaddr_in *) &addr->src_addr; 889e51060f0SSean Hefty ip4->sin_family = listen4->sin_family; 890e51060f0SSean Hefty ip4->sin_addr.s_addr = dst->ip4.addr; 891e51060f0SSean Hefty ip4->sin_port = listen4->sin_port; 892e51060f0SSean Hefty 893e51060f0SSean Hefty ip4 = (struct sockaddr_in *) &addr->dst_addr; 894e51060f0SSean Hefty ip4->sin_family = listen4->sin_family; 895e51060f0SSean Hefty ip4->sin_addr.s_addr = src->ip4.addr; 896e51060f0SSean Hefty ip4->sin_port = port; 897e51060f0SSean Hefty break; 898e51060f0SSean Hefty case 6: 899e51060f0SSean Hefty listen6 = (struct sockaddr_in6 *) &listen_addr->src_addr; 900e51060f0SSean Hefty ip6 = (struct sockaddr_in6 *) &addr->src_addr; 901e51060f0SSean Hefty ip6->sin6_family = listen6->sin6_family; 902e51060f0SSean Hefty ip6->sin6_addr = dst->ip6; 903e51060f0SSean Hefty ip6->sin6_port = listen6->sin6_port; 904e51060f0SSean Hefty 905e51060f0SSean Hefty ip6 = (struct sockaddr_in6 *) &addr->dst_addr; 906e51060f0SSean Hefty ip6->sin6_family = listen6->sin6_family; 907e51060f0SSean Hefty ip6->sin6_addr = src->ip6; 908e51060f0SSean Hefty ip6->sin6_port = port; 909e51060f0SSean Hefty break; 910e51060f0SSean Hefty default: 911e51060f0SSean Hefty break; 912e51060f0SSean Hefty } 913e51060f0SSean Hefty } 914e51060f0SSean Hefty 915e51060f0SSean Hefty static inline int cma_user_data_offset(enum rdma_port_space ps) 916e51060f0SSean Hefty { 917e51060f0SSean Hefty switch (ps) { 918e51060f0SSean Hefty case RDMA_PS_SDP: 919e51060f0SSean Hefty return 0; 920e51060f0SSean Hefty default: 921e51060f0SSean Hefty return sizeof(struct cma_hdr); 922e51060f0SSean Hefty } 923e51060f0SSean Hefty } 924e51060f0SSean Hefty 925e51060f0SSean Hefty static void cma_cancel_route(struct rdma_id_private *id_priv) 926e51060f0SSean Hefty { 9273c86aa70SEli Cohen switch (rdma_port_get_link_layer(id_priv->id.device, id_priv->id.port_num)) { 9283c86aa70SEli Cohen case IB_LINK_LAYER_INFINIBAND: 929e51060f0SSean Hefty if (id_priv->query) 930e51060f0SSean Hefty ib_sa_cancel_query(id_priv->query_id, id_priv->query); 931e51060f0SSean Hefty break; 932e51060f0SSean Hefty default: 933e51060f0SSean Hefty break; 934e51060f0SSean Hefty } 935e51060f0SSean Hefty } 936e51060f0SSean Hefty 937e51060f0SSean Hefty static void cma_cancel_listens(struct rdma_id_private *id_priv) 938e51060f0SSean Hefty { 939e51060f0SSean Hefty struct rdma_id_private *dev_id_priv; 940e51060f0SSean Hefty 941d02d1f53SSean Hefty /* 942d02d1f53SSean Hefty * Remove from listen_any_list to prevent added devices from spawning 943d02d1f53SSean Hefty * additional listen requests. 944d02d1f53SSean Hefty */ 945e51060f0SSean Hefty mutex_lock(&lock); 946e51060f0SSean Hefty list_del(&id_priv->list); 947e51060f0SSean Hefty 948e51060f0SSean Hefty while (!list_empty(&id_priv->listen_list)) { 949e51060f0SSean Hefty dev_id_priv = list_entry(id_priv->listen_list.next, 950e51060f0SSean Hefty struct rdma_id_private, listen_list); 951d02d1f53SSean Hefty /* sync with device removal to avoid duplicate destruction */ 952d02d1f53SSean Hefty list_del_init(&dev_id_priv->list); 953d02d1f53SSean Hefty list_del(&dev_id_priv->listen_list); 954d02d1f53SSean Hefty mutex_unlock(&lock); 955d02d1f53SSean Hefty 956d02d1f53SSean Hefty rdma_destroy_id(&dev_id_priv->id); 957d02d1f53SSean Hefty mutex_lock(&lock); 958e51060f0SSean Hefty } 959e51060f0SSean Hefty mutex_unlock(&lock); 960e51060f0SSean Hefty } 961e51060f0SSean Hefty 962e51060f0SSean Hefty static void cma_cancel_operation(struct rdma_id_private *id_priv, 963550e5ca7SNir Muchtar enum rdma_cm_state state) 964e51060f0SSean Hefty { 965e51060f0SSean Hefty switch (state) { 966550e5ca7SNir Muchtar case RDMA_CM_ADDR_QUERY: 967e51060f0SSean Hefty rdma_addr_cancel(&id_priv->id.route.addr.dev_addr); 968e51060f0SSean Hefty break; 969550e5ca7SNir Muchtar case RDMA_CM_ROUTE_QUERY: 970e51060f0SSean Hefty cma_cancel_route(id_priv); 971e51060f0SSean Hefty break; 972550e5ca7SNir Muchtar case RDMA_CM_LISTEN: 973f4753834SSean Hefty if (cma_any_addr(cma_src_addr(id_priv)) && !id_priv->cma_dev) 974e51060f0SSean Hefty cma_cancel_listens(id_priv); 975e51060f0SSean Hefty break; 976e51060f0SSean Hefty default: 977e51060f0SSean Hefty break; 978e51060f0SSean Hefty } 979e51060f0SSean Hefty } 980e51060f0SSean Hefty 981e51060f0SSean Hefty static void cma_release_port(struct rdma_id_private *id_priv) 982e51060f0SSean Hefty { 983e51060f0SSean Hefty struct rdma_bind_list *bind_list = id_priv->bind_list; 984e51060f0SSean Hefty 985e51060f0SSean Hefty if (!bind_list) 986e51060f0SSean Hefty return; 987e51060f0SSean Hefty 988e51060f0SSean Hefty mutex_lock(&lock); 989e51060f0SSean Hefty hlist_del(&id_priv->node); 990e51060f0SSean Hefty if (hlist_empty(&bind_list->owners)) { 991e51060f0SSean Hefty idr_remove(bind_list->ps, bind_list->port); 992e51060f0SSean Hefty kfree(bind_list); 993e51060f0SSean Hefty } 994e51060f0SSean Hefty mutex_unlock(&lock); 995e51060f0SSean Hefty } 996e51060f0SSean Hefty 997c8f6a362SSean Hefty static void cma_leave_mc_groups(struct rdma_id_private *id_priv) 998c8f6a362SSean Hefty { 999c8f6a362SSean Hefty struct cma_multicast *mc; 1000c8f6a362SSean Hefty 1001c8f6a362SSean Hefty while (!list_empty(&id_priv->mc_list)) { 1002c8f6a362SSean Hefty mc = container_of(id_priv->mc_list.next, 1003c8f6a362SSean Hefty struct cma_multicast, list); 1004c8f6a362SSean Hefty list_del(&mc->list); 10053c86aa70SEli Cohen switch (rdma_port_get_link_layer(id_priv->cma_dev->device, id_priv->id.port_num)) { 10063c86aa70SEli Cohen case IB_LINK_LAYER_INFINIBAND: 1007c8f6a362SSean Hefty ib_sa_free_multicast(mc->multicast.ib); 1008c8f6a362SSean Hefty kfree(mc); 10093c86aa70SEli Cohen break; 10103c86aa70SEli Cohen case IB_LINK_LAYER_ETHERNET: 10113c86aa70SEli Cohen kref_put(&mc->mcref, release_mc); 10123c86aa70SEli Cohen break; 10133c86aa70SEli Cohen default: 10143c86aa70SEli Cohen break; 10153c86aa70SEli Cohen } 1016c8f6a362SSean Hefty } 1017c8f6a362SSean Hefty } 1018c8f6a362SSean Hefty 1019e51060f0SSean Hefty void rdma_destroy_id(struct rdma_cm_id *id) 1020e51060f0SSean Hefty { 1021e51060f0SSean Hefty struct rdma_id_private *id_priv; 1022550e5ca7SNir Muchtar enum rdma_cm_state state; 1023e51060f0SSean Hefty 1024e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1025550e5ca7SNir Muchtar state = cma_exch(id_priv, RDMA_CM_DESTROYING); 1026e51060f0SSean Hefty cma_cancel_operation(id_priv, state); 1027e51060f0SSean Hefty 1028a396d43aSSean Hefty /* 1029a396d43aSSean Hefty * Wait for any active callback to finish. New callbacks will find 1030a396d43aSSean Hefty * the id_priv state set to destroying and abort. 1031a396d43aSSean Hefty */ 1032a396d43aSSean Hefty mutex_lock(&id_priv->handler_mutex); 1033a396d43aSSean Hefty mutex_unlock(&id_priv->handler_mutex); 1034a396d43aSSean Hefty 1035e51060f0SSean Hefty if (id_priv->cma_dev) { 10363c86aa70SEli Cohen switch (rdma_node_get_transport(id_priv->id.device->node_type)) { 103707ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 10380c9361fcSJack Morgenstein if (id_priv->cm_id.ib) 1039e51060f0SSean Hefty ib_destroy_cm_id(id_priv->cm_id.ib); 1040e51060f0SSean Hefty break; 104107ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 10420c9361fcSJack Morgenstein if (id_priv->cm_id.iw) 104307ebafbaSTom Tucker iw_destroy_cm_id(id_priv->cm_id.iw); 104407ebafbaSTom Tucker break; 1045e51060f0SSean Hefty default: 1046e51060f0SSean Hefty break; 1047e51060f0SSean Hefty } 1048c8f6a362SSean Hefty cma_leave_mc_groups(id_priv); 1049a396d43aSSean Hefty cma_release_dev(id_priv); 1050e51060f0SSean Hefty } 1051e51060f0SSean Hefty 1052e51060f0SSean Hefty cma_release_port(id_priv); 1053e51060f0SSean Hefty cma_deref_id(id_priv); 1054e51060f0SSean Hefty wait_for_completion(&id_priv->comp); 1055e51060f0SSean Hefty 1056d02d1f53SSean Hefty if (id_priv->internal_id) 1057d02d1f53SSean Hefty cma_deref_id(id_priv->id.context); 1058d02d1f53SSean Hefty 1059e51060f0SSean Hefty kfree(id_priv->id.route.path_rec); 1060e51060f0SSean Hefty kfree(id_priv); 1061e51060f0SSean Hefty } 1062e51060f0SSean Hefty EXPORT_SYMBOL(rdma_destroy_id); 1063e51060f0SSean Hefty 1064e51060f0SSean Hefty static int cma_rep_recv(struct rdma_id_private *id_priv) 1065e51060f0SSean Hefty { 1066e51060f0SSean Hefty int ret; 1067e51060f0SSean Hefty 10685851bb89SSean Hefty ret = cma_modify_qp_rtr(id_priv, NULL); 1069e51060f0SSean Hefty if (ret) 1070e51060f0SSean Hefty goto reject; 1071e51060f0SSean Hefty 10725851bb89SSean Hefty ret = cma_modify_qp_rts(id_priv, NULL); 1073e51060f0SSean Hefty if (ret) 1074e51060f0SSean Hefty goto reject; 1075e51060f0SSean Hefty 1076e51060f0SSean Hefty ret = ib_send_cm_rtu(id_priv->cm_id.ib, NULL, 0); 1077e51060f0SSean Hefty if (ret) 1078e51060f0SSean Hefty goto reject; 1079e51060f0SSean Hefty 1080e51060f0SSean Hefty return 0; 1081e51060f0SSean Hefty reject: 1082c5483388SSean Hefty cma_modify_qp_err(id_priv); 1083e51060f0SSean Hefty ib_send_cm_rej(id_priv->cm_id.ib, IB_CM_REJ_CONSUMER_DEFINED, 1084e51060f0SSean Hefty NULL, 0, NULL, 0); 1085e51060f0SSean Hefty return ret; 1086e51060f0SSean Hefty } 1087e51060f0SSean Hefty 1088e51060f0SSean Hefty static int cma_verify_rep(struct rdma_id_private *id_priv, void *data) 1089e51060f0SSean Hefty { 1090e51060f0SSean Hefty if (id_priv->id.ps == RDMA_PS_SDP && 1091e51060f0SSean Hefty sdp_get_majv(((struct sdp_hah *) data)->sdp_version) != 1092e51060f0SSean Hefty SDP_MAJ_VERSION) 1093e51060f0SSean Hefty return -EINVAL; 1094e51060f0SSean Hefty 1095e51060f0SSean Hefty return 0; 1096e51060f0SSean Hefty } 1097e51060f0SSean Hefty 1098a1b1b61fSSean Hefty static void cma_set_rep_event_data(struct rdma_cm_event *event, 1099a1b1b61fSSean Hefty struct ib_cm_rep_event_param *rep_data, 1100a1b1b61fSSean Hefty void *private_data) 1101a1b1b61fSSean Hefty { 1102a1b1b61fSSean Hefty event->param.conn.private_data = private_data; 1103a1b1b61fSSean Hefty event->param.conn.private_data_len = IB_CM_REP_PRIVATE_DATA_SIZE; 1104a1b1b61fSSean Hefty event->param.conn.responder_resources = rep_data->responder_resources; 1105a1b1b61fSSean Hefty event->param.conn.initiator_depth = rep_data->initiator_depth; 1106a1b1b61fSSean Hefty event->param.conn.flow_control = rep_data->flow_control; 1107a1b1b61fSSean Hefty event->param.conn.rnr_retry_count = rep_data->rnr_retry_count; 1108a1b1b61fSSean Hefty event->param.conn.srq = rep_data->srq; 1109a1b1b61fSSean Hefty event->param.conn.qp_num = rep_data->remote_qpn; 1110a1b1b61fSSean Hefty } 1111a1b1b61fSSean Hefty 1112e51060f0SSean Hefty static int cma_ib_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event) 1113e51060f0SSean Hefty { 1114e51060f0SSean Hefty struct rdma_id_private *id_priv = cm_id->context; 1115a1b1b61fSSean Hefty struct rdma_cm_event event; 1116a1b1b61fSSean Hefty int ret = 0; 1117e51060f0SSean Hefty 111838ca83a5SAmir Vadai if ((ib_event->event != IB_CM_TIMEWAIT_EXIT && 1119550e5ca7SNir Muchtar cma_disable_callback(id_priv, RDMA_CM_CONNECT)) || 112038ca83a5SAmir Vadai (ib_event->event == IB_CM_TIMEWAIT_EXIT && 1121550e5ca7SNir Muchtar cma_disable_callback(id_priv, RDMA_CM_DISCONNECT))) 11228aa08602SSean Hefty return 0; 1123e51060f0SSean Hefty 1124a1b1b61fSSean Hefty memset(&event, 0, sizeof event); 1125e51060f0SSean Hefty switch (ib_event->event) { 1126e51060f0SSean Hefty case IB_CM_REQ_ERROR: 1127e51060f0SSean Hefty case IB_CM_REP_ERROR: 1128a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_UNREACHABLE; 1129a1b1b61fSSean Hefty event.status = -ETIMEDOUT; 1130e51060f0SSean Hefty break; 1131e51060f0SSean Hefty case IB_CM_REP_RECEIVED: 1132a1b1b61fSSean Hefty event.status = cma_verify_rep(id_priv, ib_event->private_data); 1133a1b1b61fSSean Hefty if (event.status) 1134a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_CONNECT_ERROR; 1135e51060f0SSean Hefty else if (id_priv->id.qp && id_priv->id.ps != RDMA_PS_SDP) { 1136a1b1b61fSSean Hefty event.status = cma_rep_recv(id_priv); 1137a1b1b61fSSean Hefty event.event = event.status ? RDMA_CM_EVENT_CONNECT_ERROR : 1138e51060f0SSean Hefty RDMA_CM_EVENT_ESTABLISHED; 1139e51060f0SSean Hefty } else 1140a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_CONNECT_RESPONSE; 1141a1b1b61fSSean Hefty cma_set_rep_event_data(&event, &ib_event->param.rep_rcvd, 1142a1b1b61fSSean Hefty ib_event->private_data); 1143e51060f0SSean Hefty break; 1144e51060f0SSean Hefty case IB_CM_RTU_RECEIVED: 11450fe313b0SSean Hefty case IB_CM_USER_ESTABLISHED: 11460fe313b0SSean Hefty event.event = RDMA_CM_EVENT_ESTABLISHED; 1147e51060f0SSean Hefty break; 1148e51060f0SSean Hefty case IB_CM_DREQ_ERROR: 1149a1b1b61fSSean Hefty event.status = -ETIMEDOUT; /* fall through */ 1150e51060f0SSean Hefty case IB_CM_DREQ_RECEIVED: 1151e51060f0SSean Hefty case IB_CM_DREP_RECEIVED: 1152550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_CONNECT, 1153550e5ca7SNir Muchtar RDMA_CM_DISCONNECT)) 1154e51060f0SSean Hefty goto out; 1155a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_DISCONNECTED; 1156e51060f0SSean Hefty break; 1157e51060f0SSean Hefty case IB_CM_TIMEWAIT_EXIT: 115838ca83a5SAmir Vadai event.event = RDMA_CM_EVENT_TIMEWAIT_EXIT; 115938ca83a5SAmir Vadai break; 1160e51060f0SSean Hefty case IB_CM_MRA_RECEIVED: 1161e51060f0SSean Hefty /* ignore event */ 1162e51060f0SSean Hefty goto out; 1163e51060f0SSean Hefty case IB_CM_REJ_RECEIVED: 1164c5483388SSean Hefty cma_modify_qp_err(id_priv); 1165a1b1b61fSSean Hefty event.status = ib_event->param.rej_rcvd.reason; 1166a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_REJECTED; 1167a1b1b61fSSean Hefty event.param.conn.private_data = ib_event->private_data; 1168a1b1b61fSSean Hefty event.param.conn.private_data_len = IB_CM_REJ_PRIVATE_DATA_SIZE; 1169e51060f0SSean Hefty break; 1170e51060f0SSean Hefty default: 1171468f2239SRoland Dreier printk(KERN_ERR "RDMA CMA: unexpected IB CM event: %d\n", 1172e51060f0SSean Hefty ib_event->event); 1173e51060f0SSean Hefty goto out; 1174e51060f0SSean Hefty } 1175e51060f0SSean Hefty 1176a1b1b61fSSean Hefty ret = id_priv->id.event_handler(&id_priv->id, &event); 1177e51060f0SSean Hefty if (ret) { 1178e51060f0SSean Hefty /* Destroy the CM ID by returning a non-zero value. */ 1179e51060f0SSean Hefty id_priv->cm_id.ib = NULL; 1180550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 1181de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 1182e51060f0SSean Hefty rdma_destroy_id(&id_priv->id); 1183e51060f0SSean Hefty return ret; 1184e51060f0SSean Hefty } 1185e51060f0SSean Hefty out: 1186de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 1187e51060f0SSean Hefty return ret; 1188e51060f0SSean Hefty } 1189e51060f0SSean Hefty 1190628e5f6dSSean Hefty static struct rdma_id_private *cma_new_conn_id(struct rdma_cm_id *listen_id, 1191e51060f0SSean Hefty struct ib_cm_event *ib_event) 1192e51060f0SSean Hefty { 1193e51060f0SSean Hefty struct rdma_id_private *id_priv; 1194e51060f0SSean Hefty struct rdma_cm_id *id; 1195e51060f0SSean Hefty struct rdma_route *rt; 1196e51060f0SSean Hefty union cma_ip_addr *src, *dst; 11971b90c137SAl Viro __be16 port; 1198e51060f0SSean Hefty u8 ip_ver; 119964c5e613SOr Gerlitz int ret; 1200e51060f0SSean Hefty 1201e51060f0SSean Hefty if (cma_get_net_info(ib_event->private_data, listen_id->ps, 1202e51060f0SSean Hefty &ip_ver, &port, &src, &dst)) 12030c9361fcSJack Morgenstein return NULL; 1204e51060f0SSean Hefty 12053f168d2bSKrishna Kumar id = rdma_create_id(listen_id->event_handler, listen_id->context, 1206b26f9b99SSean Hefty listen_id->ps, ib_event->param.req_rcvd.qp_type); 12073f168d2bSKrishna Kumar if (IS_ERR(id)) 12080c9361fcSJack Morgenstein return NULL; 12093f168d2bSKrishna Kumar 1210f4753834SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1211e51060f0SSean Hefty cma_save_net_info(&id->route.addr, &listen_id->route.addr, 1212e51060f0SSean Hefty ip_ver, port, src, dst); 12133f168d2bSKrishna Kumar 12143f168d2bSKrishna Kumar rt = &id->route; 12153f168d2bSKrishna Kumar rt->num_paths = ib_event->param.req_rcvd.alternate_path ? 2 : 1; 12163f168d2bSKrishna Kumar rt->path_rec = kmalloc(sizeof *rt->path_rec * rt->num_paths, 12173f168d2bSKrishna Kumar GFP_KERNEL); 12183f168d2bSKrishna Kumar if (!rt->path_rec) 12190c9361fcSJack Morgenstein goto err; 12203f168d2bSKrishna Kumar 1221e51060f0SSean Hefty rt->path_rec[0] = *ib_event->param.req_rcvd.primary_path; 1222e51060f0SSean Hefty if (rt->num_paths == 2) 1223e51060f0SSean Hefty rt->path_rec[1] = *ib_event->param.req_rcvd.alternate_path; 1224e51060f0SSean Hefty 1225f4753834SSean Hefty if (cma_any_addr(cma_src_addr(id_priv))) { 12266f8372b6SSean Hefty rt->addr.dev_addr.dev_type = ARPHRD_INFINIBAND; 12276f8372b6SSean Hefty rdma_addr_set_sgid(&rt->addr.dev_addr, &rt->path_rec[0].sgid); 122846ea5061SSean Hefty ib_addr_set_pkey(&rt->addr.dev_addr, be16_to_cpu(rt->path_rec[0].pkey)); 12296f8372b6SSean Hefty } else { 1230f4753834SSean Hefty ret = cma_translate_addr(cma_src_addr(id_priv), &rt->addr.dev_addr); 123164c5e613SOr Gerlitz if (ret) 12320c9361fcSJack Morgenstein goto err; 12336f8372b6SSean Hefty } 12346f8372b6SSean Hefty rdma_addr_set_dgid(&rt->addr.dev_addr, &rt->path_rec[0].dgid); 1235e51060f0SSean Hefty 1236550e5ca7SNir Muchtar id_priv->state = RDMA_CM_CONNECT; 1237e51060f0SSean Hefty return id_priv; 12383f168d2bSKrishna Kumar 12393f168d2bSKrishna Kumar err: 12400c9361fcSJack Morgenstein rdma_destroy_id(id); 1241e51060f0SSean Hefty return NULL; 1242e51060f0SSean Hefty } 1243e51060f0SSean Hefty 1244628e5f6dSSean Hefty static struct rdma_id_private *cma_new_udp_id(struct rdma_cm_id *listen_id, 1245628e5f6dSSean Hefty struct ib_cm_event *ib_event) 1246628e5f6dSSean Hefty { 1247628e5f6dSSean Hefty struct rdma_id_private *id_priv; 1248628e5f6dSSean Hefty struct rdma_cm_id *id; 1249628e5f6dSSean Hefty union cma_ip_addr *src, *dst; 12501b90c137SAl Viro __be16 port; 1251628e5f6dSSean Hefty u8 ip_ver; 1252628e5f6dSSean Hefty int ret; 1253628e5f6dSSean Hefty 1254628e5f6dSSean Hefty id = rdma_create_id(listen_id->event_handler, listen_id->context, 1255b26f9b99SSean Hefty listen_id->ps, IB_QPT_UD); 1256628e5f6dSSean Hefty if (IS_ERR(id)) 1257628e5f6dSSean Hefty return NULL; 1258628e5f6dSSean Hefty 1259f4753834SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1260628e5f6dSSean Hefty if (cma_get_net_info(ib_event->private_data, listen_id->ps, 1261628e5f6dSSean Hefty &ip_ver, &port, &src, &dst)) 1262628e5f6dSSean Hefty goto err; 1263628e5f6dSSean Hefty 1264628e5f6dSSean Hefty cma_save_net_info(&id->route.addr, &listen_id->route.addr, 1265628e5f6dSSean Hefty ip_ver, port, src, dst); 1266628e5f6dSSean Hefty 12676f8372b6SSean Hefty if (!cma_any_addr((struct sockaddr *) &id->route.addr.src_addr)) { 1268f4753834SSean Hefty ret = cma_translate_addr(cma_src_addr(id_priv), &id->route.addr.dev_addr); 1269628e5f6dSSean Hefty if (ret) 1270628e5f6dSSean Hefty goto err; 12716f8372b6SSean Hefty } 1272628e5f6dSSean Hefty 1273550e5ca7SNir Muchtar id_priv->state = RDMA_CM_CONNECT; 1274628e5f6dSSean Hefty return id_priv; 1275628e5f6dSSean Hefty err: 1276628e5f6dSSean Hefty rdma_destroy_id(id); 1277628e5f6dSSean Hefty return NULL; 1278628e5f6dSSean Hefty } 1279628e5f6dSSean Hefty 1280a1b1b61fSSean Hefty static void cma_set_req_event_data(struct rdma_cm_event *event, 1281a1b1b61fSSean Hefty struct ib_cm_req_event_param *req_data, 1282a1b1b61fSSean Hefty void *private_data, int offset) 1283a1b1b61fSSean Hefty { 1284a1b1b61fSSean Hefty event->param.conn.private_data = private_data + offset; 1285a1b1b61fSSean Hefty event->param.conn.private_data_len = IB_CM_REQ_PRIVATE_DATA_SIZE - offset; 1286a1b1b61fSSean Hefty event->param.conn.responder_resources = req_data->responder_resources; 1287a1b1b61fSSean Hefty event->param.conn.initiator_depth = req_data->initiator_depth; 1288a1b1b61fSSean Hefty event->param.conn.flow_control = req_data->flow_control; 1289a1b1b61fSSean Hefty event->param.conn.retry_count = req_data->retry_count; 1290a1b1b61fSSean Hefty event->param.conn.rnr_retry_count = req_data->rnr_retry_count; 1291a1b1b61fSSean Hefty event->param.conn.srq = req_data->srq; 1292a1b1b61fSSean Hefty event->param.conn.qp_num = req_data->remote_qpn; 1293a1b1b61fSSean Hefty } 1294a1b1b61fSSean Hefty 12959595480cSHefty, Sean static int cma_check_req_qp_type(struct rdma_cm_id *id, struct ib_cm_event *ib_event) 12969595480cSHefty, Sean { 12974dd81e89SSean Hefty return (((ib_event->event == IB_CM_REQ_RECEIVED) && 12989595480cSHefty, Sean (ib_event->param.req_rcvd.qp_type == id->qp_type)) || 12999595480cSHefty, Sean ((ib_event->event == IB_CM_SIDR_REQ_RECEIVED) && 13009595480cSHefty, Sean (id->qp_type == IB_QPT_UD)) || 13019595480cSHefty, Sean (!id->qp_type)); 13029595480cSHefty, Sean } 13039595480cSHefty, Sean 1304e51060f0SSean Hefty static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event) 1305e51060f0SSean Hefty { 1306e51060f0SSean Hefty struct rdma_id_private *listen_id, *conn_id; 1307a1b1b61fSSean Hefty struct rdma_cm_event event; 1308e51060f0SSean Hefty int offset, ret; 1309e51060f0SSean Hefty 1310e51060f0SSean Hefty listen_id = cm_id->context; 13119595480cSHefty, Sean if (!cma_check_req_qp_type(&listen_id->id, ib_event)) 13129595480cSHefty, Sean return -EINVAL; 13139595480cSHefty, Sean 1314550e5ca7SNir Muchtar if (cma_disable_callback(listen_id, RDMA_CM_LISTEN)) 13158aa08602SSean Hefty return -ECONNABORTED; 1316e51060f0SSean Hefty 1317628e5f6dSSean Hefty memset(&event, 0, sizeof event); 1318628e5f6dSSean Hefty offset = cma_user_data_offset(listen_id->id.ps); 1319628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_CONNECT_REQUEST; 13209595480cSHefty, Sean if (ib_event->event == IB_CM_SIDR_REQ_RECEIVED) { 1321628e5f6dSSean Hefty conn_id = cma_new_udp_id(&listen_id->id, ib_event); 1322628e5f6dSSean Hefty event.param.ud.private_data = ib_event->private_data + offset; 1323628e5f6dSSean Hefty event.param.ud.private_data_len = 1324628e5f6dSSean Hefty IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE - offset; 1325628e5f6dSSean Hefty } else { 1326628e5f6dSSean Hefty conn_id = cma_new_conn_id(&listen_id->id, ib_event); 1327628e5f6dSSean Hefty cma_set_req_event_data(&event, &ib_event->param.req_rcvd, 1328628e5f6dSSean Hefty ib_event->private_data, offset); 1329628e5f6dSSean Hefty } 1330e51060f0SSean Hefty if (!conn_id) { 1331e51060f0SSean Hefty ret = -ENOMEM; 1332b6cec8aaSSean Hefty goto err1; 1333e51060f0SSean Hefty } 1334e51060f0SSean Hefty 1335de910bd9SOr Gerlitz mutex_lock_nested(&conn_id->handler_mutex, SINGLE_DEPTH_NESTING); 133607ebafbaSTom Tucker ret = cma_acquire_dev(conn_id); 1337a1a733f6SKrishna Kumar if (ret) 1338b6cec8aaSSean Hefty goto err2; 1339e51060f0SSean Hefty 1340e51060f0SSean Hefty conn_id->cm_id.ib = cm_id; 1341e51060f0SSean Hefty cm_id->context = conn_id; 1342e51060f0SSean Hefty cm_id->cm_handler = cma_ib_handler; 1343e51060f0SSean Hefty 134425ae21a1SSean Hefty /* 134525ae21a1SSean Hefty * Protect against the user destroying conn_id from another thread 134625ae21a1SSean Hefty * until we're done accessing it. 134725ae21a1SSean Hefty */ 134825ae21a1SSean Hefty atomic_inc(&conn_id->refcount); 1349a1b1b61fSSean Hefty ret = conn_id->id.event_handler(&conn_id->id, &event); 1350b6cec8aaSSean Hefty if (ret) 1351b6cec8aaSSean Hefty goto err3; 1352b6cec8aaSSean Hefty 1353ead595aeSSean Hefty /* 1354ead595aeSSean Hefty * Acquire mutex to prevent user executing rdma_destroy_id() 1355ead595aeSSean Hefty * while we're accessing the cm_id. 1356ead595aeSSean Hefty */ 1357ead595aeSSean Hefty mutex_lock(&lock); 1358b26f9b99SSean Hefty if (cma_comp(conn_id, RDMA_CM_CONNECT) && (conn_id->id.qp_type != IB_QPT_UD)) 1359ead595aeSSean Hefty ib_send_cm_mra(cm_id, CMA_CM_MRA_SETTING, NULL, 0); 1360ead595aeSSean Hefty mutex_unlock(&lock); 1361de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 1362b6cec8aaSSean Hefty mutex_unlock(&listen_id->handler_mutex); 136325ae21a1SSean Hefty cma_deref_id(conn_id); 1364b6cec8aaSSean Hefty return 0; 1365a1a733f6SKrishna Kumar 1366b6cec8aaSSean Hefty err3: 1367b6cec8aaSSean Hefty cma_deref_id(conn_id); 1368e51060f0SSean Hefty /* Destroy the CM ID by returning a non-zero value. */ 1369e51060f0SSean Hefty conn_id->cm_id.ib = NULL; 1370b6cec8aaSSean Hefty err2: 1371550e5ca7SNir Muchtar cma_exch(conn_id, RDMA_CM_DESTROYING); 1372de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 1373b6cec8aaSSean Hefty err1: 1374de910bd9SOr Gerlitz mutex_unlock(&listen_id->handler_mutex); 1375b6cec8aaSSean Hefty if (conn_id) 1376b6cec8aaSSean Hefty rdma_destroy_id(&conn_id->id); 1377e51060f0SSean Hefty return ret; 1378e51060f0SSean Hefty } 1379e51060f0SSean Hefty 1380e51060f0SSean Hefty static __be64 cma_get_service_id(enum rdma_port_space ps, struct sockaddr *addr) 1381e51060f0SSean Hefty { 1382628e5f6dSSean Hefty return cpu_to_be64(((u64)ps << 16) + be16_to_cpu(cma_port(addr))); 1383e51060f0SSean Hefty } 1384e51060f0SSean Hefty 1385e51060f0SSean Hefty static void cma_set_compare_data(enum rdma_port_space ps, struct sockaddr *addr, 1386e51060f0SSean Hefty struct ib_cm_compare_data *compare) 1387e51060f0SSean Hefty { 1388e51060f0SSean Hefty struct cma_hdr *cma_data, *cma_mask; 1389e51060f0SSean Hefty struct sdp_hh *sdp_data, *sdp_mask; 13901b90c137SAl Viro __be32 ip4_addr; 1391e51060f0SSean Hefty struct in6_addr ip6_addr; 1392e51060f0SSean Hefty 1393e51060f0SSean Hefty memset(compare, 0, sizeof *compare); 1394e51060f0SSean Hefty cma_data = (void *) compare->data; 1395e51060f0SSean Hefty cma_mask = (void *) compare->mask; 1396e51060f0SSean Hefty sdp_data = (void *) compare->data; 1397e51060f0SSean Hefty sdp_mask = (void *) compare->mask; 1398e51060f0SSean Hefty 1399e51060f0SSean Hefty switch (addr->sa_family) { 1400e51060f0SSean Hefty case AF_INET: 1401e51060f0SSean Hefty ip4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr; 1402e51060f0SSean Hefty if (ps == RDMA_PS_SDP) { 1403e51060f0SSean Hefty sdp_set_ip_ver(sdp_data, 4); 1404e51060f0SSean Hefty sdp_set_ip_ver(sdp_mask, 0xF); 1405e51060f0SSean Hefty sdp_data->dst_addr.ip4.addr = ip4_addr; 14061b90c137SAl Viro sdp_mask->dst_addr.ip4.addr = htonl(~0); 1407e51060f0SSean Hefty } else { 1408e51060f0SSean Hefty cma_set_ip_ver(cma_data, 4); 1409e51060f0SSean Hefty cma_set_ip_ver(cma_mask, 0xF); 1410406b6a25SSean Hefty if (!cma_any_addr(addr)) { 1411e51060f0SSean Hefty cma_data->dst_addr.ip4.addr = ip4_addr; 14121b90c137SAl Viro cma_mask->dst_addr.ip4.addr = htonl(~0); 1413e51060f0SSean Hefty } 1414406b6a25SSean Hefty } 1415e51060f0SSean Hefty break; 1416e51060f0SSean Hefty case AF_INET6: 1417e51060f0SSean Hefty ip6_addr = ((struct sockaddr_in6 *) addr)->sin6_addr; 1418e51060f0SSean Hefty if (ps == RDMA_PS_SDP) { 1419e51060f0SSean Hefty sdp_set_ip_ver(sdp_data, 6); 1420e51060f0SSean Hefty sdp_set_ip_ver(sdp_mask, 0xF); 1421e51060f0SSean Hefty sdp_data->dst_addr.ip6 = ip6_addr; 1422e51060f0SSean Hefty memset(&sdp_mask->dst_addr.ip6, 0xFF, 1423e51060f0SSean Hefty sizeof sdp_mask->dst_addr.ip6); 1424e51060f0SSean Hefty } else { 1425e51060f0SSean Hefty cma_set_ip_ver(cma_data, 6); 1426e51060f0SSean Hefty cma_set_ip_ver(cma_mask, 0xF); 1427406b6a25SSean Hefty if (!cma_any_addr(addr)) { 1428e51060f0SSean Hefty cma_data->dst_addr.ip6 = ip6_addr; 1429e51060f0SSean Hefty memset(&cma_mask->dst_addr.ip6, 0xFF, 1430e51060f0SSean Hefty sizeof cma_mask->dst_addr.ip6); 1431e51060f0SSean Hefty } 1432406b6a25SSean Hefty } 1433e51060f0SSean Hefty break; 1434e51060f0SSean Hefty default: 1435e51060f0SSean Hefty break; 1436e51060f0SSean Hefty } 1437e51060f0SSean Hefty } 1438e51060f0SSean Hefty 143907ebafbaSTom Tucker static int cma_iw_handler(struct iw_cm_id *iw_id, struct iw_cm_event *iw_event) 144007ebafbaSTom Tucker { 144107ebafbaSTom Tucker struct rdma_id_private *id_priv = iw_id->context; 1442a1b1b61fSSean Hefty struct rdma_cm_event event; 144307ebafbaSTom Tucker struct sockaddr_in *sin; 144407ebafbaSTom Tucker int ret = 0; 144507ebafbaSTom Tucker 1446550e5ca7SNir Muchtar if (cma_disable_callback(id_priv, RDMA_CM_CONNECT)) 1447be65f086SSean Hefty return 0; 144807ebafbaSTom Tucker 1449be65f086SSean Hefty memset(&event, 0, sizeof event); 145007ebafbaSTom Tucker switch (iw_event->event) { 145107ebafbaSTom Tucker case IW_CM_EVENT_CLOSE: 1452a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_DISCONNECTED; 145307ebafbaSTom Tucker break; 145407ebafbaSTom Tucker case IW_CM_EVENT_CONNECT_REPLY: 1455f4753834SSean Hefty sin = (struct sockaddr_in *) cma_src_addr(id_priv); 145607ebafbaSTom Tucker *sin = iw_event->local_addr; 1457f4753834SSean Hefty sin = (struct sockaddr_in *) cma_dst_addr(id_priv); 145807ebafbaSTom Tucker *sin = iw_event->remote_addr; 1459881a045fSSteve Wise switch (iw_event->status) { 1460881a045fSSteve Wise case 0: 1461a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_ESTABLISHED; 14623ebeebc3SKumar Sanghvi event.param.conn.initiator_depth = iw_event->ird; 14633ebeebc3SKumar Sanghvi event.param.conn.responder_resources = iw_event->ord; 146407ebafbaSTom Tucker break; 1465881a045fSSteve Wise case -ECONNRESET: 1466881a045fSSteve Wise case -ECONNREFUSED: 1467881a045fSSteve Wise event.event = RDMA_CM_EVENT_REJECTED; 1468881a045fSSteve Wise break; 1469881a045fSSteve Wise case -ETIMEDOUT: 1470881a045fSSteve Wise event.event = RDMA_CM_EVENT_UNREACHABLE; 1471881a045fSSteve Wise break; 1472881a045fSSteve Wise default: 1473881a045fSSteve Wise event.event = RDMA_CM_EVENT_CONNECT_ERROR; 1474881a045fSSteve Wise break; 1475881a045fSSteve Wise } 1476881a045fSSteve Wise break; 147707ebafbaSTom Tucker case IW_CM_EVENT_ESTABLISHED: 1478a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_ESTABLISHED; 14793ebeebc3SKumar Sanghvi event.param.conn.initiator_depth = iw_event->ird; 14803ebeebc3SKumar Sanghvi event.param.conn.responder_resources = iw_event->ord; 148107ebafbaSTom Tucker break; 148207ebafbaSTom Tucker default: 148307ebafbaSTom Tucker BUG_ON(1); 148407ebafbaSTom Tucker } 148507ebafbaSTom Tucker 1486a1b1b61fSSean Hefty event.status = iw_event->status; 1487a1b1b61fSSean Hefty event.param.conn.private_data = iw_event->private_data; 1488a1b1b61fSSean Hefty event.param.conn.private_data_len = iw_event->private_data_len; 1489a1b1b61fSSean Hefty ret = id_priv->id.event_handler(&id_priv->id, &event); 149007ebafbaSTom Tucker if (ret) { 149107ebafbaSTom Tucker /* Destroy the CM ID by returning a non-zero value. */ 149207ebafbaSTom Tucker id_priv->cm_id.iw = NULL; 1493550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 1494de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 149507ebafbaSTom Tucker rdma_destroy_id(&id_priv->id); 149607ebafbaSTom Tucker return ret; 149707ebafbaSTom Tucker } 149807ebafbaSTom Tucker 1499de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 150007ebafbaSTom Tucker return ret; 150107ebafbaSTom Tucker } 150207ebafbaSTom Tucker 150307ebafbaSTom Tucker static int iw_conn_req_handler(struct iw_cm_id *cm_id, 150407ebafbaSTom Tucker struct iw_cm_event *iw_event) 150507ebafbaSTom Tucker { 150607ebafbaSTom Tucker struct rdma_cm_id *new_cm_id; 150707ebafbaSTom Tucker struct rdma_id_private *listen_id, *conn_id; 150807ebafbaSTom Tucker struct sockaddr_in *sin; 150907ebafbaSTom Tucker struct net_device *dev = NULL; 1510a1b1b61fSSean Hefty struct rdma_cm_event event; 151107ebafbaSTom Tucker int ret; 15128d8293cfSSteve Wise struct ib_device_attr attr; 151307ebafbaSTom Tucker 151407ebafbaSTom Tucker listen_id = cm_id->context; 1515550e5ca7SNir Muchtar if (cma_disable_callback(listen_id, RDMA_CM_LISTEN)) 15168aa08602SSean Hefty return -ECONNABORTED; 151707ebafbaSTom Tucker 151807ebafbaSTom Tucker /* Create a new RDMA id for the new IW CM ID */ 151907ebafbaSTom Tucker new_cm_id = rdma_create_id(listen_id->id.event_handler, 152007ebafbaSTom Tucker listen_id->id.context, 1521b26f9b99SSean Hefty RDMA_PS_TCP, IB_QPT_RC); 152210f32065SJulia Lawall if (IS_ERR(new_cm_id)) { 152307ebafbaSTom Tucker ret = -ENOMEM; 152407ebafbaSTom Tucker goto out; 152507ebafbaSTom Tucker } 152607ebafbaSTom Tucker conn_id = container_of(new_cm_id, struct rdma_id_private, id); 1527de910bd9SOr Gerlitz mutex_lock_nested(&conn_id->handler_mutex, SINGLE_DEPTH_NESTING); 1528550e5ca7SNir Muchtar conn_id->state = RDMA_CM_CONNECT; 152907ebafbaSTom Tucker 15301ab35276SDenis V. Lunev dev = ip_dev_find(&init_net, iw_event->local_addr.sin_addr.s_addr); 153107ebafbaSTom Tucker if (!dev) { 153207ebafbaSTom Tucker ret = -EADDRNOTAVAIL; 1533de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 153407ebafbaSTom Tucker rdma_destroy_id(new_cm_id); 153507ebafbaSTom Tucker goto out; 153607ebafbaSTom Tucker } 153707ebafbaSTom Tucker ret = rdma_copy_addr(&conn_id->id.route.addr.dev_addr, dev, NULL); 153807ebafbaSTom Tucker if (ret) { 1539de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 154007ebafbaSTom Tucker rdma_destroy_id(new_cm_id); 154107ebafbaSTom Tucker goto out; 154207ebafbaSTom Tucker } 154307ebafbaSTom Tucker 154407ebafbaSTom Tucker ret = cma_acquire_dev(conn_id); 154507ebafbaSTom Tucker if (ret) { 1546de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 154707ebafbaSTom Tucker rdma_destroy_id(new_cm_id); 154807ebafbaSTom Tucker goto out; 154907ebafbaSTom Tucker } 155007ebafbaSTom Tucker 155107ebafbaSTom Tucker conn_id->cm_id.iw = cm_id; 155207ebafbaSTom Tucker cm_id->context = conn_id; 155307ebafbaSTom Tucker cm_id->cm_handler = cma_iw_handler; 155407ebafbaSTom Tucker 1555f4753834SSean Hefty sin = (struct sockaddr_in *) cma_src_addr(conn_id); 155607ebafbaSTom Tucker *sin = iw_event->local_addr; 1557f4753834SSean Hefty sin = (struct sockaddr_in *) cma_dst_addr(conn_id); 155807ebafbaSTom Tucker *sin = iw_event->remote_addr; 155907ebafbaSTom Tucker 15608d8293cfSSteve Wise ret = ib_query_device(conn_id->id.device, &attr); 15618d8293cfSSteve Wise if (ret) { 1562de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 15638d8293cfSSteve Wise rdma_destroy_id(new_cm_id); 15648d8293cfSSteve Wise goto out; 15658d8293cfSSteve Wise } 15668d8293cfSSteve Wise 1567a1b1b61fSSean Hefty memset(&event, 0, sizeof event); 1568a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_CONNECT_REQUEST; 1569a1b1b61fSSean Hefty event.param.conn.private_data = iw_event->private_data; 1570a1b1b61fSSean Hefty event.param.conn.private_data_len = iw_event->private_data_len; 15713ebeebc3SKumar Sanghvi event.param.conn.initiator_depth = iw_event->ird; 15723ebeebc3SKumar Sanghvi event.param.conn.responder_resources = iw_event->ord; 157325ae21a1SSean Hefty 157425ae21a1SSean Hefty /* 157525ae21a1SSean Hefty * Protect against the user destroying conn_id from another thread 157625ae21a1SSean Hefty * until we're done accessing it. 157725ae21a1SSean Hefty */ 157825ae21a1SSean Hefty atomic_inc(&conn_id->refcount); 1579a1b1b61fSSean Hefty ret = conn_id->id.event_handler(&conn_id->id, &event); 158007ebafbaSTom Tucker if (ret) { 158107ebafbaSTom Tucker /* User wants to destroy the CM ID */ 158207ebafbaSTom Tucker conn_id->cm_id.iw = NULL; 1583550e5ca7SNir Muchtar cma_exch(conn_id, RDMA_CM_DESTROYING); 1584de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 158525ae21a1SSean Hefty cma_deref_id(conn_id); 158607ebafbaSTom Tucker rdma_destroy_id(&conn_id->id); 1587de910bd9SOr Gerlitz goto out; 158807ebafbaSTom Tucker } 158907ebafbaSTom Tucker 1590de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 159125ae21a1SSean Hefty cma_deref_id(conn_id); 1592de910bd9SOr Gerlitz 159307ebafbaSTom Tucker out: 159407ebafbaSTom Tucker if (dev) 159507ebafbaSTom Tucker dev_put(dev); 1596de910bd9SOr Gerlitz mutex_unlock(&listen_id->handler_mutex); 159707ebafbaSTom Tucker return ret; 159807ebafbaSTom Tucker } 159907ebafbaSTom Tucker 1600e51060f0SSean Hefty static int cma_ib_listen(struct rdma_id_private *id_priv) 1601e51060f0SSean Hefty { 1602e51060f0SSean Hefty struct ib_cm_compare_data compare_data; 1603e51060f0SSean Hefty struct sockaddr *addr; 16040c9361fcSJack Morgenstein struct ib_cm_id *id; 1605e51060f0SSean Hefty __be64 svc_id; 1606e51060f0SSean Hefty int ret; 1607e51060f0SSean Hefty 16080c9361fcSJack Morgenstein id = ib_create_cm_id(id_priv->id.device, cma_req_handler, id_priv); 16090c9361fcSJack Morgenstein if (IS_ERR(id)) 16100c9361fcSJack Morgenstein return PTR_ERR(id); 16110c9361fcSJack Morgenstein 16120c9361fcSJack Morgenstein id_priv->cm_id.ib = id; 1613e51060f0SSean Hefty 1614f4753834SSean Hefty addr = cma_src_addr(id_priv); 1615e51060f0SSean Hefty svc_id = cma_get_service_id(id_priv->id.ps, addr); 1616406b6a25SSean Hefty if (cma_any_addr(addr) && !id_priv->afonly) 1617e51060f0SSean Hefty ret = ib_cm_listen(id_priv->cm_id.ib, svc_id, 0, NULL); 1618e51060f0SSean Hefty else { 1619e51060f0SSean Hefty cma_set_compare_data(id_priv->id.ps, addr, &compare_data); 1620e51060f0SSean Hefty ret = ib_cm_listen(id_priv->cm_id.ib, svc_id, 0, &compare_data); 1621e51060f0SSean Hefty } 1622e51060f0SSean Hefty 1623e51060f0SSean Hefty if (ret) { 1624e51060f0SSean Hefty ib_destroy_cm_id(id_priv->cm_id.ib); 1625e51060f0SSean Hefty id_priv->cm_id.ib = NULL; 1626e51060f0SSean Hefty } 1627e51060f0SSean Hefty 1628e51060f0SSean Hefty return ret; 1629e51060f0SSean Hefty } 1630e51060f0SSean Hefty 163107ebafbaSTom Tucker static int cma_iw_listen(struct rdma_id_private *id_priv, int backlog) 163207ebafbaSTom Tucker { 163307ebafbaSTom Tucker int ret; 163407ebafbaSTom Tucker struct sockaddr_in *sin; 16350c9361fcSJack Morgenstein struct iw_cm_id *id; 163607ebafbaSTom Tucker 16370c9361fcSJack Morgenstein id = iw_create_cm_id(id_priv->id.device, 163807ebafbaSTom Tucker iw_conn_req_handler, 163907ebafbaSTom Tucker id_priv); 16400c9361fcSJack Morgenstein if (IS_ERR(id)) 16410c9361fcSJack Morgenstein return PTR_ERR(id); 16420c9361fcSJack Morgenstein 16430c9361fcSJack Morgenstein id_priv->cm_id.iw = id; 164407ebafbaSTom Tucker 1645f4753834SSean Hefty sin = (struct sockaddr_in *) cma_src_addr(id_priv); 164607ebafbaSTom Tucker id_priv->cm_id.iw->local_addr = *sin; 164707ebafbaSTom Tucker 164807ebafbaSTom Tucker ret = iw_cm_listen(id_priv->cm_id.iw, backlog); 164907ebafbaSTom Tucker 165007ebafbaSTom Tucker if (ret) { 165107ebafbaSTom Tucker iw_destroy_cm_id(id_priv->cm_id.iw); 165207ebafbaSTom Tucker id_priv->cm_id.iw = NULL; 165307ebafbaSTom Tucker } 165407ebafbaSTom Tucker 165507ebafbaSTom Tucker return ret; 165607ebafbaSTom Tucker } 165707ebafbaSTom Tucker 1658e51060f0SSean Hefty static int cma_listen_handler(struct rdma_cm_id *id, 1659e51060f0SSean Hefty struct rdma_cm_event *event) 1660e51060f0SSean Hefty { 1661e51060f0SSean Hefty struct rdma_id_private *id_priv = id->context; 1662e51060f0SSean Hefty 1663e51060f0SSean Hefty id->context = id_priv->id.context; 1664e51060f0SSean Hefty id->event_handler = id_priv->id.event_handler; 1665e51060f0SSean Hefty return id_priv->id.event_handler(id, event); 1666e51060f0SSean Hefty } 1667e51060f0SSean Hefty 1668e51060f0SSean Hefty static void cma_listen_on_dev(struct rdma_id_private *id_priv, 1669e51060f0SSean Hefty struct cma_device *cma_dev) 1670e51060f0SSean Hefty { 1671e51060f0SSean Hefty struct rdma_id_private *dev_id_priv; 1672e51060f0SSean Hefty struct rdma_cm_id *id; 1673e51060f0SSean Hefty int ret; 1674e51060f0SSean Hefty 1675b26f9b99SSean Hefty id = rdma_create_id(cma_listen_handler, id_priv, id_priv->id.ps, 1676b26f9b99SSean Hefty id_priv->id.qp_type); 1677e51060f0SSean Hefty if (IS_ERR(id)) 1678e51060f0SSean Hefty return; 1679e51060f0SSean Hefty 1680e51060f0SSean Hefty dev_id_priv = container_of(id, struct rdma_id_private, id); 1681e51060f0SSean Hefty 1682550e5ca7SNir Muchtar dev_id_priv->state = RDMA_CM_ADDR_BOUND; 1683f4753834SSean Hefty memcpy(cma_src_addr(dev_id_priv), cma_src_addr(id_priv), 1684f4753834SSean Hefty rdma_addr_size(cma_src_addr(id_priv))); 1685e51060f0SSean Hefty 1686e51060f0SSean Hefty cma_attach_to_dev(dev_id_priv, cma_dev); 1687e51060f0SSean Hefty list_add_tail(&dev_id_priv->listen_list, &id_priv->listen_list); 1688d02d1f53SSean Hefty atomic_inc(&id_priv->refcount); 1689d02d1f53SSean Hefty dev_id_priv->internal_id = 1; 16905b0ec991SSean Hefty dev_id_priv->afonly = id_priv->afonly; 1691e51060f0SSean Hefty 1692e51060f0SSean Hefty ret = rdma_listen(id, id_priv->backlog); 1693e51060f0SSean Hefty if (ret) 1694d02d1f53SSean Hefty printk(KERN_WARNING "RDMA CMA: cma_listen_on_dev, error %d, " 1695468f2239SRoland Dreier "listening on device %s\n", ret, cma_dev->device->name); 1696e51060f0SSean Hefty } 1697e51060f0SSean Hefty 1698e51060f0SSean Hefty static void cma_listen_on_all(struct rdma_id_private *id_priv) 1699e51060f0SSean Hefty { 1700e51060f0SSean Hefty struct cma_device *cma_dev; 1701e51060f0SSean Hefty 1702e51060f0SSean Hefty mutex_lock(&lock); 1703e51060f0SSean Hefty list_add_tail(&id_priv->list, &listen_any_list); 1704e51060f0SSean Hefty list_for_each_entry(cma_dev, &dev_list, list) 1705e51060f0SSean Hefty cma_listen_on_dev(id_priv, cma_dev); 1706e51060f0SSean Hefty mutex_unlock(&lock); 1707e51060f0SSean Hefty } 1708e51060f0SSean Hefty 1709a81c994dSSean Hefty void rdma_set_service_type(struct rdma_cm_id *id, int tos) 1710a81c994dSSean Hefty { 1711a81c994dSSean Hefty struct rdma_id_private *id_priv; 1712a81c994dSSean Hefty 1713a81c994dSSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1714a81c994dSSean Hefty id_priv->tos = (u8) tos; 1715a81c994dSSean Hefty } 1716a81c994dSSean Hefty EXPORT_SYMBOL(rdma_set_service_type); 1717a81c994dSSean Hefty 1718e51060f0SSean Hefty static void cma_query_handler(int status, struct ib_sa_path_rec *path_rec, 1719e51060f0SSean Hefty void *context) 1720e51060f0SSean Hefty { 1721e51060f0SSean Hefty struct cma_work *work = context; 1722e51060f0SSean Hefty struct rdma_route *route; 1723e51060f0SSean Hefty 1724e51060f0SSean Hefty route = &work->id->id.route; 1725e51060f0SSean Hefty 1726e51060f0SSean Hefty if (!status) { 1727e51060f0SSean Hefty route->num_paths = 1; 1728e51060f0SSean Hefty *route->path_rec = *path_rec; 1729e51060f0SSean Hefty } else { 1730550e5ca7SNir Muchtar work->old_state = RDMA_CM_ROUTE_QUERY; 1731550e5ca7SNir Muchtar work->new_state = RDMA_CM_ADDR_RESOLVED; 1732e51060f0SSean Hefty work->event.event = RDMA_CM_EVENT_ROUTE_ERROR; 17338f0472d3SSean Hefty work->event.status = status; 1734e51060f0SSean Hefty } 1735e51060f0SSean Hefty 1736e51060f0SSean Hefty queue_work(cma_wq, &work->work); 1737e51060f0SSean Hefty } 1738e51060f0SSean Hefty 1739e51060f0SSean Hefty static int cma_query_ib_route(struct rdma_id_private *id_priv, int timeout_ms, 1740e51060f0SSean Hefty struct cma_work *work) 1741e51060f0SSean Hefty { 1742f4753834SSean Hefty struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 1743e51060f0SSean Hefty struct ib_sa_path_rec path_rec; 1744a81c994dSSean Hefty ib_sa_comp_mask comp_mask; 1745a81c994dSSean Hefty struct sockaddr_in6 *sin6; 1746e51060f0SSean Hefty 1747e51060f0SSean Hefty memset(&path_rec, 0, sizeof path_rec); 1748f4753834SSean Hefty rdma_addr_get_sgid(dev_addr, &path_rec.sgid); 1749f4753834SSean Hefty rdma_addr_get_dgid(dev_addr, &path_rec.dgid); 1750f4753834SSean Hefty path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr)); 1751e51060f0SSean Hefty path_rec.numb_path = 1; 1752962063e6SSean Hefty path_rec.reversible = 1; 1753f4753834SSean Hefty path_rec.service_id = cma_get_service_id(id_priv->id.ps, cma_dst_addr(id_priv)); 1754a81c994dSSean Hefty 1755a81c994dSSean Hefty comp_mask = IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID | 1756a81c994dSSean Hefty IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH | 1757a81c994dSSean Hefty IB_SA_PATH_REC_REVERSIBLE | IB_SA_PATH_REC_SERVICE_ID; 1758a81c994dSSean Hefty 1759f4753834SSean Hefty if (cma_family(id_priv) == AF_INET) { 1760a81c994dSSean Hefty path_rec.qos_class = cpu_to_be16((u16) id_priv->tos); 1761a81c994dSSean Hefty comp_mask |= IB_SA_PATH_REC_QOS_CLASS; 1762a81c994dSSean Hefty } else { 1763f4753834SSean Hefty sin6 = (struct sockaddr_in6 *) cma_src_addr(id_priv); 1764a81c994dSSean Hefty path_rec.traffic_class = (u8) (be32_to_cpu(sin6->sin6_flowinfo) >> 20); 1765a81c994dSSean Hefty comp_mask |= IB_SA_PATH_REC_TRAFFIC_CLASS; 1766a81c994dSSean Hefty } 1767e51060f0SSean Hefty 1768c1a0b23bSMichael S. Tsirkin id_priv->query_id = ib_sa_path_rec_get(&sa_client, id_priv->id.device, 1769e51060f0SSean Hefty id_priv->id.port_num, &path_rec, 1770a81c994dSSean Hefty comp_mask, timeout_ms, 1771a81c994dSSean Hefty GFP_KERNEL, cma_query_handler, 1772a81c994dSSean Hefty work, &id_priv->query); 1773e51060f0SSean Hefty 1774e51060f0SSean Hefty return (id_priv->query_id < 0) ? id_priv->query_id : 0; 1775e51060f0SSean Hefty } 1776e51060f0SSean Hefty 1777c4028958SDavid Howells static void cma_work_handler(struct work_struct *_work) 1778e51060f0SSean Hefty { 1779c4028958SDavid Howells struct cma_work *work = container_of(_work, struct cma_work, work); 1780e51060f0SSean Hefty struct rdma_id_private *id_priv = work->id; 1781e51060f0SSean Hefty int destroy = 0; 1782e51060f0SSean Hefty 1783de910bd9SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 1784e51060f0SSean Hefty if (!cma_comp_exch(id_priv, work->old_state, work->new_state)) 1785e51060f0SSean Hefty goto out; 1786e51060f0SSean Hefty 1787e51060f0SSean Hefty if (id_priv->id.event_handler(&id_priv->id, &work->event)) { 1788550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 1789e51060f0SSean Hefty destroy = 1; 1790e51060f0SSean Hefty } 1791e51060f0SSean Hefty out: 1792de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 1793e51060f0SSean Hefty cma_deref_id(id_priv); 1794e51060f0SSean Hefty if (destroy) 1795e51060f0SSean Hefty rdma_destroy_id(&id_priv->id); 1796e51060f0SSean Hefty kfree(work); 1797e51060f0SSean Hefty } 1798e51060f0SSean Hefty 1799dd5bdff8SOr Gerlitz static void cma_ndev_work_handler(struct work_struct *_work) 1800dd5bdff8SOr Gerlitz { 1801dd5bdff8SOr Gerlitz struct cma_ndev_work *work = container_of(_work, struct cma_ndev_work, work); 1802dd5bdff8SOr Gerlitz struct rdma_id_private *id_priv = work->id; 1803dd5bdff8SOr Gerlitz int destroy = 0; 1804dd5bdff8SOr Gerlitz 1805dd5bdff8SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 1806550e5ca7SNir Muchtar if (id_priv->state == RDMA_CM_DESTROYING || 1807550e5ca7SNir Muchtar id_priv->state == RDMA_CM_DEVICE_REMOVAL) 1808dd5bdff8SOr Gerlitz goto out; 1809dd5bdff8SOr Gerlitz 1810dd5bdff8SOr Gerlitz if (id_priv->id.event_handler(&id_priv->id, &work->event)) { 1811550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 1812dd5bdff8SOr Gerlitz destroy = 1; 1813dd5bdff8SOr Gerlitz } 1814dd5bdff8SOr Gerlitz 1815dd5bdff8SOr Gerlitz out: 1816dd5bdff8SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 1817dd5bdff8SOr Gerlitz cma_deref_id(id_priv); 1818dd5bdff8SOr Gerlitz if (destroy) 1819dd5bdff8SOr Gerlitz rdma_destroy_id(&id_priv->id); 1820dd5bdff8SOr Gerlitz kfree(work); 1821dd5bdff8SOr Gerlitz } 1822dd5bdff8SOr Gerlitz 1823e51060f0SSean Hefty static int cma_resolve_ib_route(struct rdma_id_private *id_priv, int timeout_ms) 1824e51060f0SSean Hefty { 1825e51060f0SSean Hefty struct rdma_route *route = &id_priv->id.route; 1826e51060f0SSean Hefty struct cma_work *work; 1827e51060f0SSean Hefty int ret; 1828e51060f0SSean Hefty 1829e51060f0SSean Hefty work = kzalloc(sizeof *work, GFP_KERNEL); 1830e51060f0SSean Hefty if (!work) 1831e51060f0SSean Hefty return -ENOMEM; 1832e51060f0SSean Hefty 1833e51060f0SSean Hefty work->id = id_priv; 1834c4028958SDavid Howells INIT_WORK(&work->work, cma_work_handler); 1835550e5ca7SNir Muchtar work->old_state = RDMA_CM_ROUTE_QUERY; 1836550e5ca7SNir Muchtar work->new_state = RDMA_CM_ROUTE_RESOLVED; 1837e51060f0SSean Hefty work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED; 1838e51060f0SSean Hefty 1839e51060f0SSean Hefty route->path_rec = kmalloc(sizeof *route->path_rec, GFP_KERNEL); 1840e51060f0SSean Hefty if (!route->path_rec) { 1841e51060f0SSean Hefty ret = -ENOMEM; 1842e51060f0SSean Hefty goto err1; 1843e51060f0SSean Hefty } 1844e51060f0SSean Hefty 1845e51060f0SSean Hefty ret = cma_query_ib_route(id_priv, timeout_ms, work); 1846e51060f0SSean Hefty if (ret) 1847e51060f0SSean Hefty goto err2; 1848e51060f0SSean Hefty 1849e51060f0SSean Hefty return 0; 1850e51060f0SSean Hefty err2: 1851e51060f0SSean Hefty kfree(route->path_rec); 1852e51060f0SSean Hefty route->path_rec = NULL; 1853e51060f0SSean Hefty err1: 1854e51060f0SSean Hefty kfree(work); 1855e51060f0SSean Hefty return ret; 1856e51060f0SSean Hefty } 1857e51060f0SSean Hefty 1858e51060f0SSean Hefty int rdma_set_ib_paths(struct rdma_cm_id *id, 1859e51060f0SSean Hefty struct ib_sa_path_rec *path_rec, int num_paths) 1860e51060f0SSean Hefty { 1861e51060f0SSean Hefty struct rdma_id_private *id_priv; 1862e51060f0SSean Hefty int ret; 1863e51060f0SSean Hefty 1864e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1865550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED, 1866550e5ca7SNir Muchtar RDMA_CM_ROUTE_RESOLVED)) 1867e51060f0SSean Hefty return -EINVAL; 1868e51060f0SSean Hefty 18699893e742SJulia Lawall id->route.path_rec = kmemdup(path_rec, sizeof *path_rec * num_paths, 18709893e742SJulia Lawall GFP_KERNEL); 1871e51060f0SSean Hefty if (!id->route.path_rec) { 1872e51060f0SSean Hefty ret = -ENOMEM; 1873e51060f0SSean Hefty goto err; 1874e51060f0SSean Hefty } 1875e51060f0SSean Hefty 1876ae2d9293SSean Hefty id->route.num_paths = num_paths; 1877e51060f0SSean Hefty return 0; 1878e51060f0SSean Hefty err: 1879550e5ca7SNir Muchtar cma_comp_exch(id_priv, RDMA_CM_ROUTE_RESOLVED, RDMA_CM_ADDR_RESOLVED); 1880e51060f0SSean Hefty return ret; 1881e51060f0SSean Hefty } 1882e51060f0SSean Hefty EXPORT_SYMBOL(rdma_set_ib_paths); 1883e51060f0SSean Hefty 188407ebafbaSTom Tucker static int cma_resolve_iw_route(struct rdma_id_private *id_priv, int timeout_ms) 188507ebafbaSTom Tucker { 188607ebafbaSTom Tucker struct cma_work *work; 188707ebafbaSTom Tucker 188807ebafbaSTom Tucker work = kzalloc(sizeof *work, GFP_KERNEL); 188907ebafbaSTom Tucker if (!work) 189007ebafbaSTom Tucker return -ENOMEM; 189107ebafbaSTom Tucker 189207ebafbaSTom Tucker work->id = id_priv; 1893c4028958SDavid Howells INIT_WORK(&work->work, cma_work_handler); 1894550e5ca7SNir Muchtar work->old_state = RDMA_CM_ROUTE_QUERY; 1895550e5ca7SNir Muchtar work->new_state = RDMA_CM_ROUTE_RESOLVED; 189607ebafbaSTom Tucker work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED; 189707ebafbaSTom Tucker queue_work(cma_wq, &work->work); 189807ebafbaSTom Tucker return 0; 189907ebafbaSTom Tucker } 190007ebafbaSTom Tucker 19013c86aa70SEli Cohen static int cma_resolve_iboe_route(struct rdma_id_private *id_priv) 19023c86aa70SEli Cohen { 19033c86aa70SEli Cohen struct rdma_route *route = &id_priv->id.route; 19043c86aa70SEli Cohen struct rdma_addr *addr = &route->addr; 19053c86aa70SEli Cohen struct cma_work *work; 19063c86aa70SEli Cohen int ret; 19073c86aa70SEli Cohen struct net_device *ndev = NULL; 1908af7bd463SEli Cohen u16 vid; 19093c86aa70SEli Cohen 19103c86aa70SEli Cohen work = kzalloc(sizeof *work, GFP_KERNEL); 19113c86aa70SEli Cohen if (!work) 19123c86aa70SEli Cohen return -ENOMEM; 19133c86aa70SEli Cohen 19143c86aa70SEli Cohen work->id = id_priv; 19153c86aa70SEli Cohen INIT_WORK(&work->work, cma_work_handler); 19163c86aa70SEli Cohen 19173c86aa70SEli Cohen route->path_rec = kzalloc(sizeof *route->path_rec, GFP_KERNEL); 19183c86aa70SEli Cohen if (!route->path_rec) { 19193c86aa70SEli Cohen ret = -ENOMEM; 19203c86aa70SEli Cohen goto err1; 19213c86aa70SEli Cohen } 19223c86aa70SEli Cohen 19233c86aa70SEli Cohen route->num_paths = 1; 19243c86aa70SEli Cohen 19253c86aa70SEli Cohen if (addr->dev_addr.bound_dev_if) 19263c86aa70SEli Cohen ndev = dev_get_by_index(&init_net, addr->dev_addr.bound_dev_if); 19273c86aa70SEli Cohen if (!ndev) { 19283c86aa70SEli Cohen ret = -ENODEV; 19293c86aa70SEli Cohen goto err2; 19303c86aa70SEli Cohen } 19313c86aa70SEli Cohen 1932af7bd463SEli Cohen vid = rdma_vlan_dev_vlan_id(ndev); 1933af7bd463SEli Cohen 1934af7bd463SEli Cohen iboe_mac_vlan_to_ll(&route->path_rec->sgid, addr->dev_addr.src_dev_addr, vid); 1935af7bd463SEli Cohen iboe_mac_vlan_to_ll(&route->path_rec->dgid, addr->dev_addr.dst_dev_addr, vid); 1936af7bd463SEli Cohen 1937af7bd463SEli Cohen route->path_rec->hop_limit = 1; 1938af7bd463SEli Cohen route->path_rec->reversible = 1; 1939af7bd463SEli Cohen route->path_rec->pkey = cpu_to_be16(0xffff); 1940af7bd463SEli Cohen route->path_rec->mtu_selector = IB_SA_EQ; 1941366cddb4SAmir Vadai route->path_rec->sl = netdev_get_prio_tc_map( 1942366cddb4SAmir Vadai ndev->priv_flags & IFF_802_1Q_VLAN ? 1943366cddb4SAmir Vadai vlan_dev_real_dev(ndev) : ndev, 1944366cddb4SAmir Vadai rt_tos2priority(id_priv->tos)); 1945af7bd463SEli Cohen 19463c86aa70SEli Cohen route->path_rec->mtu = iboe_get_mtu(ndev->mtu); 19473c86aa70SEli Cohen route->path_rec->rate_selector = IB_SA_EQ; 19483c86aa70SEli Cohen route->path_rec->rate = iboe_get_rate(ndev); 19493c86aa70SEli Cohen dev_put(ndev); 19503c86aa70SEli Cohen route->path_rec->packet_life_time_selector = IB_SA_EQ; 19513c86aa70SEli Cohen route->path_rec->packet_life_time = CMA_IBOE_PACKET_LIFETIME; 19523c86aa70SEli Cohen if (!route->path_rec->mtu) { 19533c86aa70SEli Cohen ret = -EINVAL; 19543c86aa70SEli Cohen goto err2; 19553c86aa70SEli Cohen } 19563c86aa70SEli Cohen 1957550e5ca7SNir Muchtar work->old_state = RDMA_CM_ROUTE_QUERY; 1958550e5ca7SNir Muchtar work->new_state = RDMA_CM_ROUTE_RESOLVED; 19593c86aa70SEli Cohen work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED; 19603c86aa70SEli Cohen work->event.status = 0; 19613c86aa70SEli Cohen 19623c86aa70SEli Cohen queue_work(cma_wq, &work->work); 19633c86aa70SEli Cohen 19643c86aa70SEli Cohen return 0; 19653c86aa70SEli Cohen 19663c86aa70SEli Cohen err2: 19673c86aa70SEli Cohen kfree(route->path_rec); 19683c86aa70SEli Cohen route->path_rec = NULL; 19693c86aa70SEli Cohen err1: 19703c86aa70SEli Cohen kfree(work); 19713c86aa70SEli Cohen return ret; 19723c86aa70SEli Cohen } 19733c86aa70SEli Cohen 1974e51060f0SSean Hefty int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms) 1975e51060f0SSean Hefty { 1976e51060f0SSean Hefty struct rdma_id_private *id_priv; 1977e51060f0SSean Hefty int ret; 1978e51060f0SSean Hefty 1979e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1980550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED, RDMA_CM_ROUTE_QUERY)) 1981e51060f0SSean Hefty return -EINVAL; 1982e51060f0SSean Hefty 1983e51060f0SSean Hefty atomic_inc(&id_priv->refcount); 198407ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 198507ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 19863c86aa70SEli Cohen switch (rdma_port_get_link_layer(id->device, id->port_num)) { 19873c86aa70SEli Cohen case IB_LINK_LAYER_INFINIBAND: 1988e51060f0SSean Hefty ret = cma_resolve_ib_route(id_priv, timeout_ms); 1989e51060f0SSean Hefty break; 19903c86aa70SEli Cohen case IB_LINK_LAYER_ETHERNET: 19913c86aa70SEli Cohen ret = cma_resolve_iboe_route(id_priv); 19923c86aa70SEli Cohen break; 19933c86aa70SEli Cohen default: 19943c86aa70SEli Cohen ret = -ENOSYS; 19953c86aa70SEli Cohen } 19963c86aa70SEli Cohen break; 199707ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 199807ebafbaSTom Tucker ret = cma_resolve_iw_route(id_priv, timeout_ms); 199907ebafbaSTom Tucker break; 2000e51060f0SSean Hefty default: 2001e51060f0SSean Hefty ret = -ENOSYS; 2002e51060f0SSean Hefty break; 2003e51060f0SSean Hefty } 2004e51060f0SSean Hefty if (ret) 2005e51060f0SSean Hefty goto err; 2006e51060f0SSean Hefty 2007e51060f0SSean Hefty return 0; 2008e51060f0SSean Hefty err: 2009550e5ca7SNir Muchtar cma_comp_exch(id_priv, RDMA_CM_ROUTE_QUERY, RDMA_CM_ADDR_RESOLVED); 2010e51060f0SSean Hefty cma_deref_id(id_priv); 2011e51060f0SSean Hefty return ret; 2012e51060f0SSean Hefty } 2013e51060f0SSean Hefty EXPORT_SYMBOL(rdma_resolve_route); 2014e51060f0SSean Hefty 20156a3e362dSSean Hefty static void cma_set_loopback(struct sockaddr *addr) 20166a3e362dSSean Hefty { 20176a3e362dSSean Hefty switch (addr->sa_family) { 20186a3e362dSSean Hefty case AF_INET: 20196a3e362dSSean Hefty ((struct sockaddr_in *) addr)->sin_addr.s_addr = htonl(INADDR_LOOPBACK); 20206a3e362dSSean Hefty break; 20216a3e362dSSean Hefty case AF_INET6: 20226a3e362dSSean Hefty ipv6_addr_set(&((struct sockaddr_in6 *) addr)->sin6_addr, 20236a3e362dSSean Hefty 0, 0, 0, htonl(1)); 20246a3e362dSSean Hefty break; 20256a3e362dSSean Hefty default: 20266a3e362dSSean Hefty ib_addr_set(&((struct sockaddr_ib *) addr)->sib_addr, 20276a3e362dSSean Hefty 0, 0, 0, htonl(1)); 20286a3e362dSSean Hefty break; 20296a3e362dSSean Hefty } 20306a3e362dSSean Hefty } 20316a3e362dSSean Hefty 2032e51060f0SSean Hefty static int cma_bind_loopback(struct rdma_id_private *id_priv) 2033e51060f0SSean Hefty { 2034b0569e40SSean Hefty struct cma_device *cma_dev, *cur_dev; 2035e51060f0SSean Hefty struct ib_port_attr port_attr; 2036f0ee3404SMichael S. Tsirkin union ib_gid gid; 2037e51060f0SSean Hefty u16 pkey; 2038e51060f0SSean Hefty int ret; 2039e51060f0SSean Hefty u8 p; 2040e51060f0SSean Hefty 2041b0569e40SSean Hefty cma_dev = NULL; 2042e51060f0SSean Hefty mutex_lock(&lock); 2043b0569e40SSean Hefty list_for_each_entry(cur_dev, &dev_list, list) { 2044b0569e40SSean Hefty if (cma_family(id_priv) == AF_IB && 2045b0569e40SSean Hefty rdma_node_get_transport(cur_dev->device->node_type) != RDMA_TRANSPORT_IB) 2046b0569e40SSean Hefty continue; 2047b0569e40SSean Hefty 2048b0569e40SSean Hefty if (!cma_dev) 2049b0569e40SSean Hefty cma_dev = cur_dev; 2050b0569e40SSean Hefty 2051b0569e40SSean Hefty for (p = 1; p <= cur_dev->device->phys_port_cnt; ++p) { 2052b0569e40SSean Hefty if (!ib_query_port(cur_dev->device, p, &port_attr) && 2053b0569e40SSean Hefty port_attr.state == IB_PORT_ACTIVE) { 2054b0569e40SSean Hefty cma_dev = cur_dev; 2055b0569e40SSean Hefty goto port_found; 2056b0569e40SSean Hefty } 2057b0569e40SSean Hefty } 2058b0569e40SSean Hefty } 2059b0569e40SSean Hefty 2060b0569e40SSean Hefty if (!cma_dev) { 2061e82153b5SKrishna Kumar ret = -ENODEV; 2062e82153b5SKrishna Kumar goto out; 2063e82153b5SKrishna Kumar } 2064e51060f0SSean Hefty 2065e51060f0SSean Hefty p = 1; 2066e51060f0SSean Hefty 2067e51060f0SSean Hefty port_found: 2068f0ee3404SMichael S. Tsirkin ret = ib_get_cached_gid(cma_dev->device, p, 0, &gid); 2069e51060f0SSean Hefty if (ret) 2070e51060f0SSean Hefty goto out; 2071e51060f0SSean Hefty 2072e51060f0SSean Hefty ret = ib_get_cached_pkey(cma_dev->device, p, 0, &pkey); 2073e51060f0SSean Hefty if (ret) 2074e51060f0SSean Hefty goto out; 2075e51060f0SSean Hefty 20766f8372b6SSean Hefty id_priv->id.route.addr.dev_addr.dev_type = 20773c86aa70SEli Cohen (rdma_port_get_link_layer(cma_dev->device, p) == IB_LINK_LAYER_INFINIBAND) ? 20786f8372b6SSean Hefty ARPHRD_INFINIBAND : ARPHRD_ETHER; 20796f8372b6SSean Hefty 20806f8372b6SSean Hefty rdma_addr_set_sgid(&id_priv->id.route.addr.dev_addr, &gid); 2081e51060f0SSean Hefty ib_addr_set_pkey(&id_priv->id.route.addr.dev_addr, pkey); 2082e51060f0SSean Hefty id_priv->id.port_num = p; 2083e51060f0SSean Hefty cma_attach_to_dev(id_priv, cma_dev); 2084f4753834SSean Hefty cma_set_loopback(cma_src_addr(id_priv)); 2085e51060f0SSean Hefty out: 2086e51060f0SSean Hefty mutex_unlock(&lock); 2087e51060f0SSean Hefty return ret; 2088e51060f0SSean Hefty } 2089e51060f0SSean Hefty 2090e51060f0SSean Hefty static void addr_handler(int status, struct sockaddr *src_addr, 2091e51060f0SSean Hefty struct rdma_dev_addr *dev_addr, void *context) 2092e51060f0SSean Hefty { 2093e51060f0SSean Hefty struct rdma_id_private *id_priv = context; 2094a1b1b61fSSean Hefty struct rdma_cm_event event; 2095e51060f0SSean Hefty 2096a1b1b61fSSean Hefty memset(&event, 0, sizeof event); 2097de910bd9SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 2098550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_QUERY, 2099550e5ca7SNir Muchtar RDMA_CM_ADDR_RESOLVED)) 210061a73c70SSean Hefty goto out; 210161a73c70SSean Hefty 210261a73c70SSean Hefty if (!status && !id_priv->cma_dev) 2103e51060f0SSean Hefty status = cma_acquire_dev(id_priv); 2104e51060f0SSean Hefty 2105e51060f0SSean Hefty if (status) { 2106550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED, 2107550e5ca7SNir Muchtar RDMA_CM_ADDR_BOUND)) 2108e51060f0SSean Hefty goto out; 2109a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_ADDR_ERROR; 2110a1b1b61fSSean Hefty event.status = status; 2111e51060f0SSean Hefty } else { 2112f4753834SSean Hefty memcpy(cma_src_addr(id_priv), src_addr, rdma_addr_size(src_addr)); 2113a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_ADDR_RESOLVED; 2114e51060f0SSean Hefty } 2115e51060f0SSean Hefty 2116a1b1b61fSSean Hefty if (id_priv->id.event_handler(&id_priv->id, &event)) { 2117550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 2118de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 2119e51060f0SSean Hefty cma_deref_id(id_priv); 2120e51060f0SSean Hefty rdma_destroy_id(&id_priv->id); 2121e51060f0SSean Hefty return; 2122e51060f0SSean Hefty } 2123e51060f0SSean Hefty out: 2124de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 2125e51060f0SSean Hefty cma_deref_id(id_priv); 2126e51060f0SSean Hefty } 2127e51060f0SSean Hefty 2128e51060f0SSean Hefty static int cma_resolve_loopback(struct rdma_id_private *id_priv) 2129e51060f0SSean Hefty { 2130e51060f0SSean Hefty struct cma_work *work; 2131f0ee3404SMichael S. Tsirkin union ib_gid gid; 2132e51060f0SSean Hefty int ret; 2133e51060f0SSean Hefty 2134e51060f0SSean Hefty work = kzalloc(sizeof *work, GFP_KERNEL); 2135e51060f0SSean Hefty if (!work) 2136e51060f0SSean Hefty return -ENOMEM; 2137e51060f0SSean Hefty 2138e51060f0SSean Hefty if (!id_priv->cma_dev) { 2139e51060f0SSean Hefty ret = cma_bind_loopback(id_priv); 2140e51060f0SSean Hefty if (ret) 2141e51060f0SSean Hefty goto err; 2142e51060f0SSean Hefty } 2143e51060f0SSean Hefty 21446f8372b6SSean Hefty rdma_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid); 21456f8372b6SSean Hefty rdma_addr_set_dgid(&id_priv->id.route.addr.dev_addr, &gid); 2146e51060f0SSean Hefty 2147e51060f0SSean Hefty work->id = id_priv; 2148c4028958SDavid Howells INIT_WORK(&work->work, cma_work_handler); 2149550e5ca7SNir Muchtar work->old_state = RDMA_CM_ADDR_QUERY; 2150550e5ca7SNir Muchtar work->new_state = RDMA_CM_ADDR_RESOLVED; 2151e51060f0SSean Hefty work->event.event = RDMA_CM_EVENT_ADDR_RESOLVED; 2152e51060f0SSean Hefty queue_work(cma_wq, &work->work); 2153e51060f0SSean Hefty return 0; 2154e51060f0SSean Hefty err: 2155e51060f0SSean Hefty kfree(work); 2156e51060f0SSean Hefty return ret; 2157e51060f0SSean Hefty } 2158e51060f0SSean Hefty 2159*f17df3b0SSean Hefty static int cma_resolve_ib_addr(struct rdma_id_private *id_priv) 2160*f17df3b0SSean Hefty { 2161*f17df3b0SSean Hefty struct cma_work *work; 2162*f17df3b0SSean Hefty int ret; 2163*f17df3b0SSean Hefty 2164*f17df3b0SSean Hefty work = kzalloc(sizeof *work, GFP_KERNEL); 2165*f17df3b0SSean Hefty if (!work) 2166*f17df3b0SSean Hefty return -ENOMEM; 2167*f17df3b0SSean Hefty 2168*f17df3b0SSean Hefty if (!id_priv->cma_dev) { 2169*f17df3b0SSean Hefty ret = cma_resolve_ib_dev(id_priv); 2170*f17df3b0SSean Hefty if (ret) 2171*f17df3b0SSean Hefty goto err; 2172*f17df3b0SSean Hefty } 2173*f17df3b0SSean Hefty 2174*f17df3b0SSean Hefty rdma_addr_set_dgid(&id_priv->id.route.addr.dev_addr, (union ib_gid *) 2175*f17df3b0SSean Hefty &(((struct sockaddr_ib *) &id_priv->id.route.addr.dst_addr)->sib_addr)); 2176*f17df3b0SSean Hefty 2177*f17df3b0SSean Hefty work->id = id_priv; 2178*f17df3b0SSean Hefty INIT_WORK(&work->work, cma_work_handler); 2179*f17df3b0SSean Hefty work->old_state = RDMA_CM_ADDR_QUERY; 2180*f17df3b0SSean Hefty work->new_state = RDMA_CM_ADDR_RESOLVED; 2181*f17df3b0SSean Hefty work->event.event = RDMA_CM_EVENT_ADDR_RESOLVED; 2182*f17df3b0SSean Hefty queue_work(cma_wq, &work->work); 2183*f17df3b0SSean Hefty return 0; 2184*f17df3b0SSean Hefty err: 2185*f17df3b0SSean Hefty kfree(work); 2186*f17df3b0SSean Hefty return ret; 2187*f17df3b0SSean Hefty } 2188*f17df3b0SSean Hefty 2189e51060f0SSean Hefty static int cma_bind_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, 2190e51060f0SSean Hefty struct sockaddr *dst_addr) 2191e51060f0SSean Hefty { 2192d14714dfSSean Hefty if (!src_addr || !src_addr->sa_family) { 2193d14714dfSSean Hefty src_addr = (struct sockaddr *) &id->route.addr.src_addr; 2194*f17df3b0SSean Hefty src_addr->sa_family = dst_addr->sa_family; 2195*f17df3b0SSean Hefty if (dst_addr->sa_family == AF_INET6) { 2196d14714dfSSean Hefty ((struct sockaddr_in6 *) src_addr)->sin6_scope_id = 2197d14714dfSSean Hefty ((struct sockaddr_in6 *) dst_addr)->sin6_scope_id; 2198*f17df3b0SSean Hefty } else if (dst_addr->sa_family == AF_IB) { 2199*f17df3b0SSean Hefty ((struct sockaddr_ib *) src_addr)->sib_pkey = 2200*f17df3b0SSean Hefty ((struct sockaddr_ib *) dst_addr)->sib_pkey; 2201d14714dfSSean Hefty } 2202d14714dfSSean Hefty } 2203e51060f0SSean Hefty return rdma_bind_addr(id, src_addr); 2204e51060f0SSean Hefty } 2205e51060f0SSean Hefty 2206e51060f0SSean Hefty int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, 2207e51060f0SSean Hefty struct sockaddr *dst_addr, int timeout_ms) 2208e51060f0SSean Hefty { 2209e51060f0SSean Hefty struct rdma_id_private *id_priv; 2210e51060f0SSean Hefty int ret; 2211e51060f0SSean Hefty 2212e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 2213550e5ca7SNir Muchtar if (id_priv->state == RDMA_CM_IDLE) { 2214e51060f0SSean Hefty ret = cma_bind_addr(id, src_addr, dst_addr); 2215e51060f0SSean Hefty if (ret) 2216e51060f0SSean Hefty return ret; 2217e51060f0SSean Hefty } 2218e51060f0SSean Hefty 22194ae7152eSSean Hefty if (cma_family(id_priv) != dst_addr->sa_family) 22204ae7152eSSean Hefty return -EINVAL; 22214ae7152eSSean Hefty 2222550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_ADDR_QUERY)) 2223e51060f0SSean Hefty return -EINVAL; 2224e51060f0SSean Hefty 2225e51060f0SSean Hefty atomic_inc(&id_priv->refcount); 2226f4753834SSean Hefty memcpy(cma_dst_addr(id_priv), dst_addr, rdma_addr_size(dst_addr)); 2227*f17df3b0SSean Hefty if (cma_any_addr(dst_addr)) { 2228e51060f0SSean Hefty ret = cma_resolve_loopback(id_priv); 2229*f17df3b0SSean Hefty } else { 2230*f17df3b0SSean Hefty if (dst_addr->sa_family == AF_IB) { 2231*f17df3b0SSean Hefty ret = cma_resolve_ib_addr(id_priv); 2232*f17df3b0SSean Hefty } else { 2233f4753834SSean Hefty ret = rdma_resolve_ip(&addr_client, cma_src_addr(id_priv), 22347a118df3SSean Hefty dst_addr, &id->route.addr.dev_addr, 2235e51060f0SSean Hefty timeout_ms, addr_handler, id_priv); 2236*f17df3b0SSean Hefty } 2237*f17df3b0SSean Hefty } 2238e51060f0SSean Hefty if (ret) 2239e51060f0SSean Hefty goto err; 2240e51060f0SSean Hefty 2241e51060f0SSean Hefty return 0; 2242e51060f0SSean Hefty err: 2243550e5ca7SNir Muchtar cma_comp_exch(id_priv, RDMA_CM_ADDR_QUERY, RDMA_CM_ADDR_BOUND); 2244e51060f0SSean Hefty cma_deref_id(id_priv); 2245e51060f0SSean Hefty return ret; 2246e51060f0SSean Hefty } 2247e51060f0SSean Hefty EXPORT_SYMBOL(rdma_resolve_addr); 2248e51060f0SSean Hefty 2249a9bb7912SHefty, Sean int rdma_set_reuseaddr(struct rdma_cm_id *id, int reuse) 2250a9bb7912SHefty, Sean { 2251a9bb7912SHefty, Sean struct rdma_id_private *id_priv; 2252a9bb7912SHefty, Sean unsigned long flags; 2253a9bb7912SHefty, Sean int ret; 2254a9bb7912SHefty, Sean 2255a9bb7912SHefty, Sean id_priv = container_of(id, struct rdma_id_private, id); 2256a9bb7912SHefty, Sean spin_lock_irqsave(&id_priv->lock, flags); 2257c8dea2f9SSean Hefty if (reuse || id_priv->state == RDMA_CM_IDLE) { 2258a9bb7912SHefty, Sean id_priv->reuseaddr = reuse; 2259a9bb7912SHefty, Sean ret = 0; 2260a9bb7912SHefty, Sean } else { 2261a9bb7912SHefty, Sean ret = -EINVAL; 2262a9bb7912SHefty, Sean } 2263a9bb7912SHefty, Sean spin_unlock_irqrestore(&id_priv->lock, flags); 2264a9bb7912SHefty, Sean return ret; 2265a9bb7912SHefty, Sean } 2266a9bb7912SHefty, Sean EXPORT_SYMBOL(rdma_set_reuseaddr); 2267a9bb7912SHefty, Sean 226868602120SSean Hefty int rdma_set_afonly(struct rdma_cm_id *id, int afonly) 226968602120SSean Hefty { 227068602120SSean Hefty struct rdma_id_private *id_priv; 227168602120SSean Hefty unsigned long flags; 227268602120SSean Hefty int ret; 227368602120SSean Hefty 227468602120SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 227568602120SSean Hefty spin_lock_irqsave(&id_priv->lock, flags); 227668602120SSean Hefty if (id_priv->state == RDMA_CM_IDLE || id_priv->state == RDMA_CM_ADDR_BOUND) { 227768602120SSean Hefty id_priv->options |= (1 << CMA_OPTION_AFONLY); 227868602120SSean Hefty id_priv->afonly = afonly; 227968602120SSean Hefty ret = 0; 228068602120SSean Hefty } else { 228168602120SSean Hefty ret = -EINVAL; 228268602120SSean Hefty } 228368602120SSean Hefty spin_unlock_irqrestore(&id_priv->lock, flags); 228468602120SSean Hefty return ret; 228568602120SSean Hefty } 228668602120SSean Hefty EXPORT_SYMBOL(rdma_set_afonly); 228768602120SSean Hefty 2288e51060f0SSean Hefty static void cma_bind_port(struct rdma_bind_list *bind_list, 2289e51060f0SSean Hefty struct rdma_id_private *id_priv) 2290e51060f0SSean Hefty { 229158afdcb7SSean Hefty struct sockaddr *addr; 229258afdcb7SSean Hefty struct sockaddr_ib *sib; 229358afdcb7SSean Hefty u64 sid, mask; 229458afdcb7SSean Hefty __be16 port; 2295e51060f0SSean Hefty 2296f4753834SSean Hefty addr = cma_src_addr(id_priv); 229758afdcb7SSean Hefty port = htons(bind_list->port); 229858afdcb7SSean Hefty 229958afdcb7SSean Hefty switch (addr->sa_family) { 230058afdcb7SSean Hefty case AF_INET: 230158afdcb7SSean Hefty ((struct sockaddr_in *) addr)->sin_port = port; 230258afdcb7SSean Hefty break; 230358afdcb7SSean Hefty case AF_INET6: 230458afdcb7SSean Hefty ((struct sockaddr_in6 *) addr)->sin6_port = port; 230558afdcb7SSean Hefty break; 230658afdcb7SSean Hefty case AF_IB: 230758afdcb7SSean Hefty sib = (struct sockaddr_ib *) addr; 230858afdcb7SSean Hefty sid = be64_to_cpu(sib->sib_sid); 230958afdcb7SSean Hefty mask = be64_to_cpu(sib->sib_sid_mask); 231058afdcb7SSean Hefty sib->sib_sid = cpu_to_be64((sid & mask) | (u64) ntohs(port)); 231158afdcb7SSean Hefty sib->sib_sid_mask = cpu_to_be64(~0ULL); 231258afdcb7SSean Hefty break; 231358afdcb7SSean Hefty } 2314e51060f0SSean Hefty id_priv->bind_list = bind_list; 2315e51060f0SSean Hefty hlist_add_head(&id_priv->node, &bind_list->owners); 2316e51060f0SSean Hefty } 2317e51060f0SSean Hefty 2318e51060f0SSean Hefty static int cma_alloc_port(struct idr *ps, struct rdma_id_private *id_priv, 2319e51060f0SSean Hefty unsigned short snum) 2320e51060f0SSean Hefty { 2321e51060f0SSean Hefty struct rdma_bind_list *bind_list; 23223b069c5dSTejun Heo int ret; 2323e51060f0SSean Hefty 2324cb164b8cSSean Hefty bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL); 2325e51060f0SSean Hefty if (!bind_list) 2326e51060f0SSean Hefty return -ENOMEM; 2327e51060f0SSean Hefty 23283b069c5dSTejun Heo ret = idr_alloc(ps, bind_list, snum, snum + 1, GFP_KERNEL); 23293b069c5dSTejun Heo if (ret < 0) 23303b069c5dSTejun Heo goto err; 2331e51060f0SSean Hefty 2332e51060f0SSean Hefty bind_list->ps = ps; 23333b069c5dSTejun Heo bind_list->port = (unsigned short)ret; 2334e51060f0SSean Hefty cma_bind_port(bind_list, id_priv); 2335e51060f0SSean Hefty return 0; 23363b069c5dSTejun Heo err: 2337aedec080SSean Hefty kfree(bind_list); 23383b069c5dSTejun Heo return ret == -ENOSPC ? -EADDRNOTAVAIL : ret; 2339aedec080SSean Hefty } 2340aedec080SSean Hefty 2341aedec080SSean Hefty static int cma_alloc_any_port(struct idr *ps, struct rdma_id_private *id_priv) 2342aedec080SSean Hefty { 23435d7220e8STetsuo Handa static unsigned int last_used_port; 23445d7220e8STetsuo Handa int low, high, remaining; 23455d7220e8STetsuo Handa unsigned int rover; 2346aedec080SSean Hefty 2347227b60f5SStephen Hemminger inet_get_local_port_range(&low, &high); 23485d7220e8STetsuo Handa remaining = (high - low) + 1; 23495d7220e8STetsuo Handa rover = net_random() % remaining + low; 23505d7220e8STetsuo Handa retry: 23515d7220e8STetsuo Handa if (last_used_port != rover && 23525d7220e8STetsuo Handa !idr_find(ps, (unsigned short) rover)) { 23535d7220e8STetsuo Handa int ret = cma_alloc_port(ps, id_priv, rover); 23545d7220e8STetsuo Handa /* 23555d7220e8STetsuo Handa * Remember previously used port number in order to avoid 23565d7220e8STetsuo Handa * re-using same port immediately after it is closed. 23575d7220e8STetsuo Handa */ 23585d7220e8STetsuo Handa if (!ret) 23595d7220e8STetsuo Handa last_used_port = rover; 23605d7220e8STetsuo Handa if (ret != -EADDRNOTAVAIL) 23615d7220e8STetsuo Handa return ret; 23625d7220e8STetsuo Handa } 23635d7220e8STetsuo Handa if (--remaining) { 23645d7220e8STetsuo Handa rover++; 23655d7220e8STetsuo Handa if ((rover < low) || (rover > high)) 23665d7220e8STetsuo Handa rover = low; 2367aedec080SSean Hefty goto retry; 2368aedec080SSean Hefty } 23695d7220e8STetsuo Handa return -EADDRNOTAVAIL; 2370e51060f0SSean Hefty } 2371e51060f0SSean Hefty 2372a9bb7912SHefty, Sean /* 2373a9bb7912SHefty, Sean * Check that the requested port is available. This is called when trying to 2374a9bb7912SHefty, Sean * bind to a specific port, or when trying to listen on a bound port. In 2375a9bb7912SHefty, Sean * the latter case, the provided id_priv may already be on the bind_list, but 2376a9bb7912SHefty, Sean * we still need to check that it's okay to start listening. 2377a9bb7912SHefty, Sean */ 2378a9bb7912SHefty, Sean static int cma_check_port(struct rdma_bind_list *bind_list, 2379a9bb7912SHefty, Sean struct rdma_id_private *id_priv, uint8_t reuseaddr) 2380e51060f0SSean Hefty { 2381e51060f0SSean Hefty struct rdma_id_private *cur_id; 238243b752daSHefty, Sean struct sockaddr *addr, *cur_addr; 2383e51060f0SSean Hefty 2384f4753834SSean Hefty addr = cma_src_addr(id_priv); 2385b67bfe0dSSasha Levin hlist_for_each_entry(cur_id, &bind_list->owners, node) { 2386a9bb7912SHefty, Sean if (id_priv == cur_id) 2387a9bb7912SHefty, Sean continue; 2388a9bb7912SHefty, Sean 23895b0ec991SSean Hefty if ((cur_id->state != RDMA_CM_LISTEN) && reuseaddr && 23905b0ec991SSean Hefty cur_id->reuseaddr) 23915b0ec991SSean Hefty continue; 23925b0ec991SSean Hefty 2393f4753834SSean Hefty cur_addr = cma_src_addr(cur_id); 23945b0ec991SSean Hefty if (id_priv->afonly && cur_id->afonly && 23955b0ec991SSean Hefty (addr->sa_family != cur_addr->sa_family)) 23965b0ec991SSean Hefty continue; 23975b0ec991SSean Hefty 23985b0ec991SSean Hefty if (cma_any_addr(addr) || cma_any_addr(cur_addr)) 2399e51060f0SSean Hefty return -EADDRNOTAVAIL; 2400e51060f0SSean Hefty 240143b752daSHefty, Sean if (!cma_addr_cmp(addr, cur_addr)) 2402e51060f0SSean Hefty return -EADDRINUSE; 2403e51060f0SSean Hefty } 2404e51060f0SSean Hefty return 0; 2405e51060f0SSean Hefty } 2406e51060f0SSean Hefty 2407a9bb7912SHefty, Sean static int cma_use_port(struct idr *ps, struct rdma_id_private *id_priv) 2408a9bb7912SHefty, Sean { 2409a9bb7912SHefty, Sean struct rdma_bind_list *bind_list; 2410a9bb7912SHefty, Sean unsigned short snum; 2411a9bb7912SHefty, Sean int ret; 2412a9bb7912SHefty, Sean 2413f4753834SSean Hefty snum = ntohs(cma_port(cma_src_addr(id_priv))); 2414a9bb7912SHefty, Sean if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) 2415a9bb7912SHefty, Sean return -EACCES; 2416a9bb7912SHefty, Sean 2417a9bb7912SHefty, Sean bind_list = idr_find(ps, snum); 2418a9bb7912SHefty, Sean if (!bind_list) { 2419a9bb7912SHefty, Sean ret = cma_alloc_port(ps, id_priv, snum); 2420a9bb7912SHefty, Sean } else { 2421a9bb7912SHefty, Sean ret = cma_check_port(bind_list, id_priv, id_priv->reuseaddr); 2422a9bb7912SHefty, Sean if (!ret) 2423a9bb7912SHefty, Sean cma_bind_port(bind_list, id_priv); 2424a9bb7912SHefty, Sean } 2425a9bb7912SHefty, Sean return ret; 2426a9bb7912SHefty, Sean } 2427a9bb7912SHefty, Sean 2428a9bb7912SHefty, Sean static int cma_bind_listen(struct rdma_id_private *id_priv) 2429a9bb7912SHefty, Sean { 2430a9bb7912SHefty, Sean struct rdma_bind_list *bind_list = id_priv->bind_list; 2431a9bb7912SHefty, Sean int ret = 0; 2432a9bb7912SHefty, Sean 2433a9bb7912SHefty, Sean mutex_lock(&lock); 2434a9bb7912SHefty, Sean if (bind_list->owners.first->next) 2435a9bb7912SHefty, Sean ret = cma_check_port(bind_list, id_priv, 0); 2436a9bb7912SHefty, Sean mutex_unlock(&lock); 2437a9bb7912SHefty, Sean return ret; 2438a9bb7912SHefty, Sean } 2439a9bb7912SHefty, Sean 244058afdcb7SSean Hefty static struct idr *cma_select_inet_ps(struct rdma_id_private *id_priv) 244158afdcb7SSean Hefty { 244258afdcb7SSean Hefty switch (id_priv->id.ps) { 244358afdcb7SSean Hefty case RDMA_PS_SDP: 244458afdcb7SSean Hefty return &sdp_ps; 244558afdcb7SSean Hefty case RDMA_PS_TCP: 244658afdcb7SSean Hefty return &tcp_ps; 244758afdcb7SSean Hefty case RDMA_PS_UDP: 244858afdcb7SSean Hefty return &udp_ps; 244958afdcb7SSean Hefty case RDMA_PS_IPOIB: 245058afdcb7SSean Hefty return &ipoib_ps; 245158afdcb7SSean Hefty case RDMA_PS_IB: 245258afdcb7SSean Hefty return &ib_ps; 245358afdcb7SSean Hefty default: 245458afdcb7SSean Hefty return NULL; 245558afdcb7SSean Hefty } 245658afdcb7SSean Hefty } 245758afdcb7SSean Hefty 245858afdcb7SSean Hefty static struct idr *cma_select_ib_ps(struct rdma_id_private *id_priv) 245958afdcb7SSean Hefty { 246058afdcb7SSean Hefty struct idr *ps = NULL; 246158afdcb7SSean Hefty struct sockaddr_ib *sib; 246258afdcb7SSean Hefty u64 sid_ps, mask, sid; 246358afdcb7SSean Hefty 2464f4753834SSean Hefty sib = (struct sockaddr_ib *) cma_src_addr(id_priv); 246558afdcb7SSean Hefty mask = be64_to_cpu(sib->sib_sid_mask) & RDMA_IB_IP_PS_MASK; 246658afdcb7SSean Hefty sid = be64_to_cpu(sib->sib_sid) & mask; 246758afdcb7SSean Hefty 246858afdcb7SSean Hefty if ((id_priv->id.ps == RDMA_PS_IB) && (sid == (RDMA_IB_IP_PS_IB & mask))) { 246958afdcb7SSean Hefty sid_ps = RDMA_IB_IP_PS_IB; 247058afdcb7SSean Hefty ps = &ib_ps; 247158afdcb7SSean Hefty } else if (((id_priv->id.ps == RDMA_PS_IB) || (id_priv->id.ps == RDMA_PS_TCP)) && 247258afdcb7SSean Hefty (sid == (RDMA_IB_IP_PS_TCP & mask))) { 247358afdcb7SSean Hefty sid_ps = RDMA_IB_IP_PS_TCP; 247458afdcb7SSean Hefty ps = &tcp_ps; 247558afdcb7SSean Hefty } else if (((id_priv->id.ps == RDMA_PS_IB) || (id_priv->id.ps == RDMA_PS_UDP)) && 247658afdcb7SSean Hefty (sid == (RDMA_IB_IP_PS_UDP & mask))) { 247758afdcb7SSean Hefty sid_ps = RDMA_IB_IP_PS_UDP; 247858afdcb7SSean Hefty ps = &udp_ps; 247958afdcb7SSean Hefty } 248058afdcb7SSean Hefty 248158afdcb7SSean Hefty if (ps) { 248258afdcb7SSean Hefty sib->sib_sid = cpu_to_be64(sid_ps | ntohs(cma_port((struct sockaddr *) sib))); 248358afdcb7SSean Hefty sib->sib_sid_mask = cpu_to_be64(RDMA_IB_IP_PS_MASK | 248458afdcb7SSean Hefty be64_to_cpu(sib->sib_sid_mask)); 248558afdcb7SSean Hefty } 248658afdcb7SSean Hefty return ps; 248758afdcb7SSean Hefty } 248858afdcb7SSean Hefty 2489e51060f0SSean Hefty static int cma_get_port(struct rdma_id_private *id_priv) 2490e51060f0SSean Hefty { 2491e51060f0SSean Hefty struct idr *ps; 2492e51060f0SSean Hefty int ret; 2493e51060f0SSean Hefty 2494f4753834SSean Hefty if (cma_family(id_priv) != AF_IB) 249558afdcb7SSean Hefty ps = cma_select_inet_ps(id_priv); 249658afdcb7SSean Hefty else 249758afdcb7SSean Hefty ps = cma_select_ib_ps(id_priv); 249858afdcb7SSean Hefty if (!ps) 2499e51060f0SSean Hefty return -EPROTONOSUPPORT; 2500e51060f0SSean Hefty 2501e51060f0SSean Hefty mutex_lock(&lock); 2502f4753834SSean Hefty if (cma_any_port(cma_src_addr(id_priv))) 2503aedec080SSean Hefty ret = cma_alloc_any_port(ps, id_priv); 2504e51060f0SSean Hefty else 2505e51060f0SSean Hefty ret = cma_use_port(ps, id_priv); 2506e51060f0SSean Hefty mutex_unlock(&lock); 2507e51060f0SSean Hefty 2508e51060f0SSean Hefty return ret; 2509e51060f0SSean Hefty } 2510e51060f0SSean Hefty 2511d14714dfSSean Hefty static int cma_check_linklocal(struct rdma_dev_addr *dev_addr, 2512d14714dfSSean Hefty struct sockaddr *addr) 2513d14714dfSSean Hefty { 2514d90f9b35SRoland Dreier #if IS_ENABLED(CONFIG_IPV6) 2515d14714dfSSean Hefty struct sockaddr_in6 *sin6; 2516d14714dfSSean Hefty 2517d14714dfSSean Hefty if (addr->sa_family != AF_INET6) 2518d14714dfSSean Hefty return 0; 2519d14714dfSSean Hefty 2520d14714dfSSean Hefty sin6 = (struct sockaddr_in6 *) addr; 2521d14714dfSSean Hefty if ((ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) && 2522d14714dfSSean Hefty !sin6->sin6_scope_id) 2523d14714dfSSean Hefty return -EINVAL; 2524d14714dfSSean Hefty 2525d14714dfSSean Hefty dev_addr->bound_dev_if = sin6->sin6_scope_id; 2526d14714dfSSean Hefty #endif 2527d14714dfSSean Hefty return 0; 2528d14714dfSSean Hefty } 2529d14714dfSSean Hefty 2530a9bb7912SHefty, Sean int rdma_listen(struct rdma_cm_id *id, int backlog) 2531a9bb7912SHefty, Sean { 2532a9bb7912SHefty, Sean struct rdma_id_private *id_priv; 2533a9bb7912SHefty, Sean int ret; 2534a9bb7912SHefty, Sean 2535a9bb7912SHefty, Sean id_priv = container_of(id, struct rdma_id_private, id); 2536550e5ca7SNir Muchtar if (id_priv->state == RDMA_CM_IDLE) { 2537f4753834SSean Hefty id->route.addr.src_addr.ss_family = AF_INET; 2538f4753834SSean Hefty ret = rdma_bind_addr(id, cma_src_addr(id_priv)); 2539a9bb7912SHefty, Sean if (ret) 2540a9bb7912SHefty, Sean return ret; 2541a9bb7912SHefty, Sean } 2542a9bb7912SHefty, Sean 2543550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_LISTEN)) 2544a9bb7912SHefty, Sean return -EINVAL; 2545a9bb7912SHefty, Sean 2546a9bb7912SHefty, Sean if (id_priv->reuseaddr) { 2547a9bb7912SHefty, Sean ret = cma_bind_listen(id_priv); 2548a9bb7912SHefty, Sean if (ret) 2549a9bb7912SHefty, Sean goto err; 2550a9bb7912SHefty, Sean } 2551a9bb7912SHefty, Sean 2552a9bb7912SHefty, Sean id_priv->backlog = backlog; 2553a9bb7912SHefty, Sean if (id->device) { 2554a9bb7912SHefty, Sean switch (rdma_node_get_transport(id->device->node_type)) { 2555a9bb7912SHefty, Sean case RDMA_TRANSPORT_IB: 2556a9bb7912SHefty, Sean ret = cma_ib_listen(id_priv); 2557a9bb7912SHefty, Sean if (ret) 2558a9bb7912SHefty, Sean goto err; 2559a9bb7912SHefty, Sean break; 2560a9bb7912SHefty, Sean case RDMA_TRANSPORT_IWARP: 2561a9bb7912SHefty, Sean ret = cma_iw_listen(id_priv, backlog); 2562a9bb7912SHefty, Sean if (ret) 2563a9bb7912SHefty, Sean goto err; 2564a9bb7912SHefty, Sean break; 2565a9bb7912SHefty, Sean default: 2566a9bb7912SHefty, Sean ret = -ENOSYS; 2567a9bb7912SHefty, Sean goto err; 2568a9bb7912SHefty, Sean } 2569a9bb7912SHefty, Sean } else 2570a9bb7912SHefty, Sean cma_listen_on_all(id_priv); 2571a9bb7912SHefty, Sean 2572a9bb7912SHefty, Sean return 0; 2573a9bb7912SHefty, Sean err: 2574a9bb7912SHefty, Sean id_priv->backlog = 0; 2575550e5ca7SNir Muchtar cma_comp_exch(id_priv, RDMA_CM_LISTEN, RDMA_CM_ADDR_BOUND); 2576a9bb7912SHefty, Sean return ret; 2577a9bb7912SHefty, Sean } 2578a9bb7912SHefty, Sean EXPORT_SYMBOL(rdma_listen); 2579a9bb7912SHefty, Sean 2580e51060f0SSean Hefty int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr) 2581e51060f0SSean Hefty { 2582e51060f0SSean Hefty struct rdma_id_private *id_priv; 2583e51060f0SSean Hefty int ret; 2584e51060f0SSean Hefty 2585680f920aSSean Hefty if (addr->sa_family != AF_INET && addr->sa_family != AF_INET6 && 2586680f920aSSean Hefty addr->sa_family != AF_IB) 2587e51060f0SSean Hefty return -EAFNOSUPPORT; 2588e51060f0SSean Hefty 2589e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 2590550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_IDLE, RDMA_CM_ADDR_BOUND)) 2591e51060f0SSean Hefty return -EINVAL; 2592e51060f0SSean Hefty 2593d14714dfSSean Hefty ret = cma_check_linklocal(&id->route.addr.dev_addr, addr); 2594d14714dfSSean Hefty if (ret) 2595d14714dfSSean Hefty goto err1; 2596d14714dfSSean Hefty 25978523c048SSean Hefty if (!cma_any_addr(addr)) { 2598680f920aSSean Hefty ret = cma_translate_addr(addr, &id->route.addr.dev_addr); 2599255d0c14SKrishna Kumar if (ret) 2600255d0c14SKrishna Kumar goto err1; 2601255d0c14SKrishna Kumar 2602e51060f0SSean Hefty ret = cma_acquire_dev(id_priv); 2603e51060f0SSean Hefty if (ret) 2604255d0c14SKrishna Kumar goto err1; 2605e51060f0SSean Hefty } 2606e51060f0SSean Hefty 2607f4753834SSean Hefty memcpy(cma_src_addr(id_priv), addr, rdma_addr_size(addr)); 260868602120SSean Hefty if (!(id_priv->options & (1 << CMA_OPTION_AFONLY))) { 26095b0ec991SSean Hefty if (addr->sa_family == AF_INET) 26105b0ec991SSean Hefty id_priv->afonly = 1; 26115b0ec991SSean Hefty #if IS_ENABLED(CONFIG_IPV6) 26125b0ec991SSean Hefty else if (addr->sa_family == AF_INET6) 26135b0ec991SSean Hefty id_priv->afonly = init_net.ipv6.sysctl.bindv6only; 26145b0ec991SSean Hefty #endif 261568602120SSean Hefty } 2616e51060f0SSean Hefty ret = cma_get_port(id_priv); 2617e51060f0SSean Hefty if (ret) 2618255d0c14SKrishna Kumar goto err2; 2619e51060f0SSean Hefty 2620e51060f0SSean Hefty return 0; 2621255d0c14SKrishna Kumar err2: 2622a396d43aSSean Hefty if (id_priv->cma_dev) 2623a396d43aSSean Hefty cma_release_dev(id_priv); 2624255d0c14SKrishna Kumar err1: 2625550e5ca7SNir Muchtar cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_IDLE); 2626e51060f0SSean Hefty return ret; 2627e51060f0SSean Hefty } 2628e51060f0SSean Hefty EXPORT_SYMBOL(rdma_bind_addr); 2629e51060f0SSean Hefty 2630f4753834SSean Hefty static int cma_format_hdr(void *hdr, struct rdma_id_private *id_priv) 2631e51060f0SSean Hefty { 2632e51060f0SSean Hefty struct cma_hdr *cma_hdr; 2633e51060f0SSean Hefty struct sdp_hh *sdp_hdr; 2634e51060f0SSean Hefty 2635f4753834SSean Hefty if (cma_family(id_priv) == AF_INET) { 26361f5175adSAleksey Senin struct sockaddr_in *src4, *dst4; 26371f5175adSAleksey Senin 2638f4753834SSean Hefty src4 = (struct sockaddr_in *) cma_src_addr(id_priv); 2639f4753834SSean Hefty dst4 = (struct sockaddr_in *) cma_dst_addr(id_priv); 2640e51060f0SSean Hefty 2641f4753834SSean Hefty switch (id_priv->id.ps) { 2642e51060f0SSean Hefty case RDMA_PS_SDP: 2643e51060f0SSean Hefty sdp_hdr = hdr; 2644e51060f0SSean Hefty if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION) 2645e51060f0SSean Hefty return -EINVAL; 2646e51060f0SSean Hefty sdp_set_ip_ver(sdp_hdr, 4); 2647e51060f0SSean Hefty sdp_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr; 2648e51060f0SSean Hefty sdp_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr; 2649e51060f0SSean Hefty sdp_hdr->port = src4->sin_port; 2650e51060f0SSean Hefty break; 2651e51060f0SSean Hefty default: 2652e51060f0SSean Hefty cma_hdr = hdr; 2653e51060f0SSean Hefty cma_hdr->cma_version = CMA_VERSION; 2654e51060f0SSean Hefty cma_set_ip_ver(cma_hdr, 4); 2655e51060f0SSean Hefty cma_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr; 2656e51060f0SSean Hefty cma_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr; 2657e51060f0SSean Hefty cma_hdr->port = src4->sin_port; 2658e51060f0SSean Hefty break; 2659e51060f0SSean Hefty } 26601f5175adSAleksey Senin } else { 26611f5175adSAleksey Senin struct sockaddr_in6 *src6, *dst6; 26621f5175adSAleksey Senin 2663f4753834SSean Hefty src6 = (struct sockaddr_in6 *) cma_src_addr(id_priv); 2664f4753834SSean Hefty dst6 = (struct sockaddr_in6 *) cma_dst_addr(id_priv); 26651f5175adSAleksey Senin 2666f4753834SSean Hefty switch (id_priv->id.ps) { 26671f5175adSAleksey Senin case RDMA_PS_SDP: 26681f5175adSAleksey Senin sdp_hdr = hdr; 26691f5175adSAleksey Senin if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION) 26701f5175adSAleksey Senin return -EINVAL; 26711f5175adSAleksey Senin sdp_set_ip_ver(sdp_hdr, 6); 26721f5175adSAleksey Senin sdp_hdr->src_addr.ip6 = src6->sin6_addr; 26731f5175adSAleksey Senin sdp_hdr->dst_addr.ip6 = dst6->sin6_addr; 26741f5175adSAleksey Senin sdp_hdr->port = src6->sin6_port; 26751f5175adSAleksey Senin break; 26761f5175adSAleksey Senin default: 26771f5175adSAleksey Senin cma_hdr = hdr; 26781f5175adSAleksey Senin cma_hdr->cma_version = CMA_VERSION; 26791f5175adSAleksey Senin cma_set_ip_ver(cma_hdr, 6); 26801f5175adSAleksey Senin cma_hdr->src_addr.ip6 = src6->sin6_addr; 26811f5175adSAleksey Senin cma_hdr->dst_addr.ip6 = dst6->sin6_addr; 26821f5175adSAleksey Senin cma_hdr->port = src6->sin6_port; 26831f5175adSAleksey Senin break; 26841f5175adSAleksey Senin } 26851f5175adSAleksey Senin } 2686e51060f0SSean Hefty return 0; 2687e51060f0SSean Hefty } 2688e51060f0SSean Hefty 2689628e5f6dSSean Hefty static int cma_sidr_rep_handler(struct ib_cm_id *cm_id, 2690628e5f6dSSean Hefty struct ib_cm_event *ib_event) 2691628e5f6dSSean Hefty { 2692628e5f6dSSean Hefty struct rdma_id_private *id_priv = cm_id->context; 2693628e5f6dSSean Hefty struct rdma_cm_event event; 2694628e5f6dSSean Hefty struct ib_cm_sidr_rep_event_param *rep = &ib_event->param.sidr_rep_rcvd; 2695628e5f6dSSean Hefty int ret = 0; 2696628e5f6dSSean Hefty 2697550e5ca7SNir Muchtar if (cma_disable_callback(id_priv, RDMA_CM_CONNECT)) 26988aa08602SSean Hefty return 0; 2699628e5f6dSSean Hefty 27008aa08602SSean Hefty memset(&event, 0, sizeof event); 2701628e5f6dSSean Hefty switch (ib_event->event) { 2702628e5f6dSSean Hefty case IB_CM_SIDR_REQ_ERROR: 2703628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_UNREACHABLE; 2704628e5f6dSSean Hefty event.status = -ETIMEDOUT; 2705628e5f6dSSean Hefty break; 2706628e5f6dSSean Hefty case IB_CM_SIDR_REP_RECEIVED: 2707628e5f6dSSean Hefty event.param.ud.private_data = ib_event->private_data; 2708628e5f6dSSean Hefty event.param.ud.private_data_len = IB_CM_SIDR_REP_PRIVATE_DATA_SIZE; 2709628e5f6dSSean Hefty if (rep->status != IB_SIDR_SUCCESS) { 2710628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_UNREACHABLE; 2711628e5f6dSSean Hefty event.status = ib_event->param.sidr_rep_rcvd.status; 2712628e5f6dSSean Hefty break; 2713628e5f6dSSean Hefty } 2714d2ca39f2SYossi Etigin ret = cma_set_qkey(id_priv); 2715d2ca39f2SYossi Etigin if (ret) { 2716d2ca39f2SYossi Etigin event.event = RDMA_CM_EVENT_ADDR_ERROR; 2717d2ca39f2SYossi Etigin event.status = -EINVAL; 2718d2ca39f2SYossi Etigin break; 2719d2ca39f2SYossi Etigin } 2720c8f6a362SSean Hefty if (id_priv->qkey != rep->qkey) { 2721628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_UNREACHABLE; 2722628e5f6dSSean Hefty event.status = -EINVAL; 2723628e5f6dSSean Hefty break; 2724628e5f6dSSean Hefty } 2725628e5f6dSSean Hefty ib_init_ah_from_path(id_priv->id.device, id_priv->id.port_num, 2726628e5f6dSSean Hefty id_priv->id.route.path_rec, 2727628e5f6dSSean Hefty &event.param.ud.ah_attr); 2728628e5f6dSSean Hefty event.param.ud.qp_num = rep->qpn; 2729628e5f6dSSean Hefty event.param.ud.qkey = rep->qkey; 2730628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_ESTABLISHED; 2731628e5f6dSSean Hefty event.status = 0; 2732628e5f6dSSean Hefty break; 2733628e5f6dSSean Hefty default: 2734468f2239SRoland Dreier printk(KERN_ERR "RDMA CMA: unexpected IB CM event: %d\n", 2735628e5f6dSSean Hefty ib_event->event); 2736628e5f6dSSean Hefty goto out; 2737628e5f6dSSean Hefty } 2738628e5f6dSSean Hefty 2739628e5f6dSSean Hefty ret = id_priv->id.event_handler(&id_priv->id, &event); 2740628e5f6dSSean Hefty if (ret) { 2741628e5f6dSSean Hefty /* Destroy the CM ID by returning a non-zero value. */ 2742628e5f6dSSean Hefty id_priv->cm_id.ib = NULL; 2743550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 2744de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 2745628e5f6dSSean Hefty rdma_destroy_id(&id_priv->id); 2746628e5f6dSSean Hefty return ret; 2747628e5f6dSSean Hefty } 2748628e5f6dSSean Hefty out: 2749de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 2750628e5f6dSSean Hefty return ret; 2751628e5f6dSSean Hefty } 2752628e5f6dSSean Hefty 2753628e5f6dSSean Hefty static int cma_resolve_ib_udp(struct rdma_id_private *id_priv, 2754628e5f6dSSean Hefty struct rdma_conn_param *conn_param) 2755628e5f6dSSean Hefty { 2756628e5f6dSSean Hefty struct ib_cm_sidr_req_param req; 27570c9361fcSJack Morgenstein struct ib_cm_id *id; 2758628e5f6dSSean Hefty int ret; 2759628e5f6dSSean Hefty 2760628e5f6dSSean Hefty req.private_data_len = sizeof(struct cma_hdr) + 2761628e5f6dSSean Hefty conn_param->private_data_len; 276204ded167SSean Hefty if (req.private_data_len < conn_param->private_data_len) 276304ded167SSean Hefty return -EINVAL; 276404ded167SSean Hefty 2765628e5f6dSSean Hefty req.private_data = kzalloc(req.private_data_len, GFP_ATOMIC); 2766628e5f6dSSean Hefty if (!req.private_data) 2767628e5f6dSSean Hefty return -ENOMEM; 2768628e5f6dSSean Hefty 2769628e5f6dSSean Hefty if (conn_param->private_data && conn_param->private_data_len) 2770628e5f6dSSean Hefty memcpy((void *) req.private_data + sizeof(struct cma_hdr), 2771628e5f6dSSean Hefty conn_param->private_data, conn_param->private_data_len); 2772628e5f6dSSean Hefty 2773f4753834SSean Hefty ret = cma_format_hdr((void *) req.private_data, id_priv); 2774628e5f6dSSean Hefty if (ret) 2775628e5f6dSSean Hefty goto out; 2776628e5f6dSSean Hefty 27770c9361fcSJack Morgenstein id = ib_create_cm_id(id_priv->id.device, cma_sidr_rep_handler, 27780c9361fcSJack Morgenstein id_priv); 27790c9361fcSJack Morgenstein if (IS_ERR(id)) { 27800c9361fcSJack Morgenstein ret = PTR_ERR(id); 2781628e5f6dSSean Hefty goto out; 2782628e5f6dSSean Hefty } 27830c9361fcSJack Morgenstein id_priv->cm_id.ib = id; 2784628e5f6dSSean Hefty 2785f4753834SSean Hefty req.path = id_priv->id.route.path_rec; 2786f4753834SSean Hefty req.service_id = cma_get_service_id(id_priv->id.ps, cma_dst_addr(id_priv)); 2787628e5f6dSSean Hefty req.timeout_ms = 1 << (CMA_CM_RESPONSE_TIMEOUT - 8); 2788628e5f6dSSean Hefty req.max_cm_retries = CMA_MAX_CM_RETRIES; 2789628e5f6dSSean Hefty 2790628e5f6dSSean Hefty ret = ib_send_cm_sidr_req(id_priv->cm_id.ib, &req); 2791628e5f6dSSean Hefty if (ret) { 2792628e5f6dSSean Hefty ib_destroy_cm_id(id_priv->cm_id.ib); 2793628e5f6dSSean Hefty id_priv->cm_id.ib = NULL; 2794628e5f6dSSean Hefty } 2795628e5f6dSSean Hefty out: 2796628e5f6dSSean Hefty kfree(req.private_data); 2797628e5f6dSSean Hefty return ret; 2798628e5f6dSSean Hefty } 2799628e5f6dSSean Hefty 2800e51060f0SSean Hefty static int cma_connect_ib(struct rdma_id_private *id_priv, 2801e51060f0SSean Hefty struct rdma_conn_param *conn_param) 2802e51060f0SSean Hefty { 2803e51060f0SSean Hefty struct ib_cm_req_param req; 2804e51060f0SSean Hefty struct rdma_route *route; 2805e51060f0SSean Hefty void *private_data; 28060c9361fcSJack Morgenstein struct ib_cm_id *id; 2807e51060f0SSean Hefty int offset, ret; 2808e51060f0SSean Hefty 2809e51060f0SSean Hefty memset(&req, 0, sizeof req); 2810e51060f0SSean Hefty offset = cma_user_data_offset(id_priv->id.ps); 2811e51060f0SSean Hefty req.private_data_len = offset + conn_param->private_data_len; 281204ded167SSean Hefty if (req.private_data_len < conn_param->private_data_len) 281304ded167SSean Hefty return -EINVAL; 281404ded167SSean Hefty 2815e51060f0SSean Hefty private_data = kzalloc(req.private_data_len, GFP_ATOMIC); 2816e51060f0SSean Hefty if (!private_data) 2817e51060f0SSean Hefty return -ENOMEM; 2818e51060f0SSean Hefty 2819e51060f0SSean Hefty if (conn_param->private_data && conn_param->private_data_len) 2820e51060f0SSean Hefty memcpy(private_data + offset, conn_param->private_data, 2821e51060f0SSean Hefty conn_param->private_data_len); 2822e51060f0SSean Hefty 28230c9361fcSJack Morgenstein id = ib_create_cm_id(id_priv->id.device, cma_ib_handler, id_priv); 28240c9361fcSJack Morgenstein if (IS_ERR(id)) { 28250c9361fcSJack Morgenstein ret = PTR_ERR(id); 2826e51060f0SSean Hefty goto out; 2827e51060f0SSean Hefty } 28280c9361fcSJack Morgenstein id_priv->cm_id.ib = id; 2829e51060f0SSean Hefty 2830e51060f0SSean Hefty route = &id_priv->id.route; 2831f4753834SSean Hefty ret = cma_format_hdr(private_data, id_priv); 2832e51060f0SSean Hefty if (ret) 2833e51060f0SSean Hefty goto out; 2834e51060f0SSean Hefty req.private_data = private_data; 2835e51060f0SSean Hefty 2836e51060f0SSean Hefty req.primary_path = &route->path_rec[0]; 2837e51060f0SSean Hefty if (route->num_paths == 2) 2838e51060f0SSean Hefty req.alternate_path = &route->path_rec[1]; 2839e51060f0SSean Hefty 2840f4753834SSean Hefty req.service_id = cma_get_service_id(id_priv->id.ps, cma_dst_addr(id_priv)); 2841e51060f0SSean Hefty req.qp_num = id_priv->qp_num; 284218c441a6SSean Hefty req.qp_type = id_priv->id.qp_type; 2843e51060f0SSean Hefty req.starting_psn = id_priv->seq_num; 2844e51060f0SSean Hefty req.responder_resources = conn_param->responder_resources; 2845e51060f0SSean Hefty req.initiator_depth = conn_param->initiator_depth; 2846e51060f0SSean Hefty req.flow_control = conn_param->flow_control; 28474ede178aSSean Hefty req.retry_count = min_t(u8, 7, conn_param->retry_count); 28484ede178aSSean Hefty req.rnr_retry_count = min_t(u8, 7, conn_param->rnr_retry_count); 2849e51060f0SSean Hefty req.remote_cm_response_timeout = CMA_CM_RESPONSE_TIMEOUT; 2850e51060f0SSean Hefty req.local_cm_response_timeout = CMA_CM_RESPONSE_TIMEOUT; 2851e51060f0SSean Hefty req.max_cm_retries = CMA_MAX_CM_RETRIES; 2852e51060f0SSean Hefty req.srq = id_priv->srq ? 1 : 0; 2853e51060f0SSean Hefty 2854e51060f0SSean Hefty ret = ib_send_cm_req(id_priv->cm_id.ib, &req); 2855e51060f0SSean Hefty out: 28560c9361fcSJack Morgenstein if (ret && !IS_ERR(id)) { 28570c9361fcSJack Morgenstein ib_destroy_cm_id(id); 2858675a027cSKrishna Kumar id_priv->cm_id.ib = NULL; 2859675a027cSKrishna Kumar } 2860675a027cSKrishna Kumar 2861e51060f0SSean Hefty kfree(private_data); 2862e51060f0SSean Hefty return ret; 2863e51060f0SSean Hefty } 2864e51060f0SSean Hefty 286507ebafbaSTom Tucker static int cma_connect_iw(struct rdma_id_private *id_priv, 286607ebafbaSTom Tucker struct rdma_conn_param *conn_param) 286707ebafbaSTom Tucker { 286807ebafbaSTom Tucker struct iw_cm_id *cm_id; 286907ebafbaSTom Tucker struct sockaddr_in* sin; 287007ebafbaSTom Tucker int ret; 287107ebafbaSTom Tucker struct iw_cm_conn_param iw_param; 287207ebafbaSTom Tucker 287307ebafbaSTom Tucker cm_id = iw_create_cm_id(id_priv->id.device, cma_iw_handler, id_priv); 28740c9361fcSJack Morgenstein if (IS_ERR(cm_id)) 28750c9361fcSJack Morgenstein return PTR_ERR(cm_id); 287607ebafbaSTom Tucker 287707ebafbaSTom Tucker id_priv->cm_id.iw = cm_id; 287807ebafbaSTom Tucker 2879f4753834SSean Hefty sin = (struct sockaddr_in *) cma_src_addr(id_priv); 288007ebafbaSTom Tucker cm_id->local_addr = *sin; 288107ebafbaSTom Tucker 2882f4753834SSean Hefty sin = (struct sockaddr_in *) cma_dst_addr(id_priv); 288307ebafbaSTom Tucker cm_id->remote_addr = *sin; 288407ebafbaSTom Tucker 28855851bb89SSean Hefty ret = cma_modify_qp_rtr(id_priv, conn_param); 2886675a027cSKrishna Kumar if (ret) 2887675a027cSKrishna Kumar goto out; 288807ebafbaSTom Tucker 2889f45ee80eSHefty, Sean if (conn_param) { 289007ebafbaSTom Tucker iw_param.ord = conn_param->initiator_depth; 289107ebafbaSTom Tucker iw_param.ird = conn_param->responder_resources; 289207ebafbaSTom Tucker iw_param.private_data = conn_param->private_data; 289307ebafbaSTom Tucker iw_param.private_data_len = conn_param->private_data_len; 2894f45ee80eSHefty, Sean iw_param.qpn = id_priv->id.qp ? id_priv->qp_num : conn_param->qp_num; 2895f45ee80eSHefty, Sean } else { 2896f45ee80eSHefty, Sean memset(&iw_param, 0, sizeof iw_param); 289707ebafbaSTom Tucker iw_param.qpn = id_priv->qp_num; 2898f45ee80eSHefty, Sean } 289907ebafbaSTom Tucker ret = iw_cm_connect(cm_id, &iw_param); 290007ebafbaSTom Tucker out: 29010c9361fcSJack Morgenstein if (ret) { 2902675a027cSKrishna Kumar iw_destroy_cm_id(cm_id); 2903675a027cSKrishna Kumar id_priv->cm_id.iw = NULL; 2904675a027cSKrishna Kumar } 290507ebafbaSTom Tucker return ret; 290607ebafbaSTom Tucker } 290707ebafbaSTom Tucker 2908e51060f0SSean Hefty int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param) 2909e51060f0SSean Hefty { 2910e51060f0SSean Hefty struct rdma_id_private *id_priv; 2911e51060f0SSean Hefty int ret; 2912e51060f0SSean Hefty 2913e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 2914550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_ROUTE_RESOLVED, RDMA_CM_CONNECT)) 2915e51060f0SSean Hefty return -EINVAL; 2916e51060f0SSean Hefty 2917e51060f0SSean Hefty if (!id->qp) { 2918e51060f0SSean Hefty id_priv->qp_num = conn_param->qp_num; 2919e51060f0SSean Hefty id_priv->srq = conn_param->srq; 2920e51060f0SSean Hefty } 2921e51060f0SSean Hefty 292207ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 292307ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 2924b26f9b99SSean Hefty if (id->qp_type == IB_QPT_UD) 2925628e5f6dSSean Hefty ret = cma_resolve_ib_udp(id_priv, conn_param); 2926628e5f6dSSean Hefty else 2927e51060f0SSean Hefty ret = cma_connect_ib(id_priv, conn_param); 2928e51060f0SSean Hefty break; 292907ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 293007ebafbaSTom Tucker ret = cma_connect_iw(id_priv, conn_param); 293107ebafbaSTom Tucker break; 2932e51060f0SSean Hefty default: 2933e51060f0SSean Hefty ret = -ENOSYS; 2934e51060f0SSean Hefty break; 2935e51060f0SSean Hefty } 2936e51060f0SSean Hefty if (ret) 2937e51060f0SSean Hefty goto err; 2938e51060f0SSean Hefty 2939e51060f0SSean Hefty return 0; 2940e51060f0SSean Hefty err: 2941550e5ca7SNir Muchtar cma_comp_exch(id_priv, RDMA_CM_CONNECT, RDMA_CM_ROUTE_RESOLVED); 2942e51060f0SSean Hefty return ret; 2943e51060f0SSean Hefty } 2944e51060f0SSean Hefty EXPORT_SYMBOL(rdma_connect); 2945e51060f0SSean Hefty 2946e51060f0SSean Hefty static int cma_accept_ib(struct rdma_id_private *id_priv, 2947e51060f0SSean Hefty struct rdma_conn_param *conn_param) 2948e51060f0SSean Hefty { 2949e51060f0SSean Hefty struct ib_cm_rep_param rep; 29505851bb89SSean Hefty int ret; 2951e51060f0SSean Hefty 29525851bb89SSean Hefty ret = cma_modify_qp_rtr(id_priv, conn_param); 2953e51060f0SSean Hefty if (ret) 29540fe313b0SSean Hefty goto out; 29550fe313b0SSean Hefty 29565851bb89SSean Hefty ret = cma_modify_qp_rts(id_priv, conn_param); 29570fe313b0SSean Hefty if (ret) 29580fe313b0SSean Hefty goto out; 29590fe313b0SSean Hefty 2960e51060f0SSean Hefty memset(&rep, 0, sizeof rep); 2961e51060f0SSean Hefty rep.qp_num = id_priv->qp_num; 2962e51060f0SSean Hefty rep.starting_psn = id_priv->seq_num; 2963e51060f0SSean Hefty rep.private_data = conn_param->private_data; 2964e51060f0SSean Hefty rep.private_data_len = conn_param->private_data_len; 2965e51060f0SSean Hefty rep.responder_resources = conn_param->responder_resources; 2966e51060f0SSean Hefty rep.initiator_depth = conn_param->initiator_depth; 2967e51060f0SSean Hefty rep.failover_accepted = 0; 2968e51060f0SSean Hefty rep.flow_control = conn_param->flow_control; 29694ede178aSSean Hefty rep.rnr_retry_count = min_t(u8, 7, conn_param->rnr_retry_count); 2970e51060f0SSean Hefty rep.srq = id_priv->srq ? 1 : 0; 2971e51060f0SSean Hefty 29720fe313b0SSean Hefty ret = ib_send_cm_rep(id_priv->cm_id.ib, &rep); 29730fe313b0SSean Hefty out: 29740fe313b0SSean Hefty return ret; 2975e51060f0SSean Hefty } 2976e51060f0SSean Hefty 297707ebafbaSTom Tucker static int cma_accept_iw(struct rdma_id_private *id_priv, 297807ebafbaSTom Tucker struct rdma_conn_param *conn_param) 297907ebafbaSTom Tucker { 298007ebafbaSTom Tucker struct iw_cm_conn_param iw_param; 298107ebafbaSTom Tucker int ret; 298207ebafbaSTom Tucker 29835851bb89SSean Hefty ret = cma_modify_qp_rtr(id_priv, conn_param); 298407ebafbaSTom Tucker if (ret) 298507ebafbaSTom Tucker return ret; 298607ebafbaSTom Tucker 298707ebafbaSTom Tucker iw_param.ord = conn_param->initiator_depth; 298807ebafbaSTom Tucker iw_param.ird = conn_param->responder_resources; 298907ebafbaSTom Tucker iw_param.private_data = conn_param->private_data; 299007ebafbaSTom Tucker iw_param.private_data_len = conn_param->private_data_len; 299107ebafbaSTom Tucker if (id_priv->id.qp) { 299207ebafbaSTom Tucker iw_param.qpn = id_priv->qp_num; 299307ebafbaSTom Tucker } else 299407ebafbaSTom Tucker iw_param.qpn = conn_param->qp_num; 299507ebafbaSTom Tucker 299607ebafbaSTom Tucker return iw_cm_accept(id_priv->cm_id.iw, &iw_param); 299707ebafbaSTom Tucker } 299807ebafbaSTom Tucker 2999628e5f6dSSean Hefty static int cma_send_sidr_rep(struct rdma_id_private *id_priv, 3000628e5f6dSSean Hefty enum ib_cm_sidr_status status, 3001628e5f6dSSean Hefty const void *private_data, int private_data_len) 3002628e5f6dSSean Hefty { 3003628e5f6dSSean Hefty struct ib_cm_sidr_rep_param rep; 3004d2ca39f2SYossi Etigin int ret; 3005628e5f6dSSean Hefty 3006628e5f6dSSean Hefty memset(&rep, 0, sizeof rep); 3007628e5f6dSSean Hefty rep.status = status; 3008628e5f6dSSean Hefty if (status == IB_SIDR_SUCCESS) { 3009d2ca39f2SYossi Etigin ret = cma_set_qkey(id_priv); 3010d2ca39f2SYossi Etigin if (ret) 3011d2ca39f2SYossi Etigin return ret; 3012628e5f6dSSean Hefty rep.qp_num = id_priv->qp_num; 3013c8f6a362SSean Hefty rep.qkey = id_priv->qkey; 3014628e5f6dSSean Hefty } 3015628e5f6dSSean Hefty rep.private_data = private_data; 3016628e5f6dSSean Hefty rep.private_data_len = private_data_len; 3017628e5f6dSSean Hefty 3018628e5f6dSSean Hefty return ib_send_cm_sidr_rep(id_priv->cm_id.ib, &rep); 3019628e5f6dSSean Hefty } 3020628e5f6dSSean Hefty 3021e51060f0SSean Hefty int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param) 3022e51060f0SSean Hefty { 3023e51060f0SSean Hefty struct rdma_id_private *id_priv; 3024e51060f0SSean Hefty int ret; 3025e51060f0SSean Hefty 3026e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 302783e9502dSNir Muchtar 302883e9502dSNir Muchtar id_priv->owner = task_pid_nr(current); 302983e9502dSNir Muchtar 3030550e5ca7SNir Muchtar if (!cma_comp(id_priv, RDMA_CM_CONNECT)) 3031e51060f0SSean Hefty return -EINVAL; 3032e51060f0SSean Hefty 3033e51060f0SSean Hefty if (!id->qp && conn_param) { 3034e51060f0SSean Hefty id_priv->qp_num = conn_param->qp_num; 3035e51060f0SSean Hefty id_priv->srq = conn_param->srq; 3036e51060f0SSean Hefty } 3037e51060f0SSean Hefty 303807ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 303907ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 3040f45ee80eSHefty, Sean if (id->qp_type == IB_QPT_UD) { 3041f45ee80eSHefty, Sean if (conn_param) 3042628e5f6dSSean Hefty ret = cma_send_sidr_rep(id_priv, IB_SIDR_SUCCESS, 3043628e5f6dSSean Hefty conn_param->private_data, 3044628e5f6dSSean Hefty conn_param->private_data_len); 3045f45ee80eSHefty, Sean else 3046f45ee80eSHefty, Sean ret = cma_send_sidr_rep(id_priv, IB_SIDR_SUCCESS, 3047f45ee80eSHefty, Sean NULL, 0); 3048f45ee80eSHefty, Sean } else { 3049f45ee80eSHefty, Sean if (conn_param) 3050e51060f0SSean Hefty ret = cma_accept_ib(id_priv, conn_param); 3051e51060f0SSean Hefty else 3052e51060f0SSean Hefty ret = cma_rep_recv(id_priv); 3053f45ee80eSHefty, Sean } 3054e51060f0SSean Hefty break; 305507ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 305607ebafbaSTom Tucker ret = cma_accept_iw(id_priv, conn_param); 305707ebafbaSTom Tucker break; 3058e51060f0SSean Hefty default: 3059e51060f0SSean Hefty ret = -ENOSYS; 3060e51060f0SSean Hefty break; 3061e51060f0SSean Hefty } 3062e51060f0SSean Hefty 3063e51060f0SSean Hefty if (ret) 3064e51060f0SSean Hefty goto reject; 3065e51060f0SSean Hefty 3066e51060f0SSean Hefty return 0; 3067e51060f0SSean Hefty reject: 3068c5483388SSean Hefty cma_modify_qp_err(id_priv); 3069e51060f0SSean Hefty rdma_reject(id, NULL, 0); 3070e51060f0SSean Hefty return ret; 3071e51060f0SSean Hefty } 3072e51060f0SSean Hefty EXPORT_SYMBOL(rdma_accept); 3073e51060f0SSean Hefty 30740fe313b0SSean Hefty int rdma_notify(struct rdma_cm_id *id, enum ib_event_type event) 30750fe313b0SSean Hefty { 30760fe313b0SSean Hefty struct rdma_id_private *id_priv; 30770fe313b0SSean Hefty int ret; 30780fe313b0SSean Hefty 30790fe313b0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 30800c9361fcSJack Morgenstein if (!id_priv->cm_id.ib) 30810fe313b0SSean Hefty return -EINVAL; 30820fe313b0SSean Hefty 30830fe313b0SSean Hefty switch (id->device->node_type) { 30840fe313b0SSean Hefty case RDMA_NODE_IB_CA: 30850fe313b0SSean Hefty ret = ib_cm_notify(id_priv->cm_id.ib, event); 30860fe313b0SSean Hefty break; 30870fe313b0SSean Hefty default: 30880fe313b0SSean Hefty ret = 0; 30890fe313b0SSean Hefty break; 30900fe313b0SSean Hefty } 30910fe313b0SSean Hefty return ret; 30920fe313b0SSean Hefty } 30930fe313b0SSean Hefty EXPORT_SYMBOL(rdma_notify); 30940fe313b0SSean Hefty 3095e51060f0SSean Hefty int rdma_reject(struct rdma_cm_id *id, const void *private_data, 3096e51060f0SSean Hefty u8 private_data_len) 3097e51060f0SSean Hefty { 3098e51060f0SSean Hefty struct rdma_id_private *id_priv; 3099e51060f0SSean Hefty int ret; 3100e51060f0SSean Hefty 3101e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 31020c9361fcSJack Morgenstein if (!id_priv->cm_id.ib) 3103e51060f0SSean Hefty return -EINVAL; 3104e51060f0SSean Hefty 310507ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 310607ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 3107b26f9b99SSean Hefty if (id->qp_type == IB_QPT_UD) 3108628e5f6dSSean Hefty ret = cma_send_sidr_rep(id_priv, IB_SIDR_REJECT, 3109e51060f0SSean Hefty private_data, private_data_len); 3110628e5f6dSSean Hefty else 3111628e5f6dSSean Hefty ret = ib_send_cm_rej(id_priv->cm_id.ib, 3112628e5f6dSSean Hefty IB_CM_REJ_CONSUMER_DEFINED, NULL, 3113628e5f6dSSean Hefty 0, private_data, private_data_len); 3114e51060f0SSean Hefty break; 311507ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 311607ebafbaSTom Tucker ret = iw_cm_reject(id_priv->cm_id.iw, 311707ebafbaSTom Tucker private_data, private_data_len); 311807ebafbaSTom Tucker break; 3119e51060f0SSean Hefty default: 3120e51060f0SSean Hefty ret = -ENOSYS; 3121e51060f0SSean Hefty break; 3122e51060f0SSean Hefty } 3123e51060f0SSean Hefty return ret; 3124e51060f0SSean Hefty } 3125e51060f0SSean Hefty EXPORT_SYMBOL(rdma_reject); 3126e51060f0SSean Hefty 3127e51060f0SSean Hefty int rdma_disconnect(struct rdma_cm_id *id) 3128e51060f0SSean Hefty { 3129e51060f0SSean Hefty struct rdma_id_private *id_priv; 3130e51060f0SSean Hefty int ret; 3131e51060f0SSean Hefty 3132e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 31330c9361fcSJack Morgenstein if (!id_priv->cm_id.ib) 3134e51060f0SSean Hefty return -EINVAL; 3135e51060f0SSean Hefty 313607ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 313707ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 3138c5483388SSean Hefty ret = cma_modify_qp_err(id_priv); 3139e51060f0SSean Hefty if (ret) 3140e51060f0SSean Hefty goto out; 3141e51060f0SSean Hefty /* Initiate or respond to a disconnect. */ 3142e51060f0SSean Hefty if (ib_send_cm_dreq(id_priv->cm_id.ib, NULL, 0)) 3143e51060f0SSean Hefty ib_send_cm_drep(id_priv->cm_id.ib, NULL, 0); 3144e51060f0SSean Hefty break; 314507ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 314607ebafbaSTom Tucker ret = iw_cm_disconnect(id_priv->cm_id.iw, 0); 314707ebafbaSTom Tucker break; 3148e51060f0SSean Hefty default: 314907ebafbaSTom Tucker ret = -EINVAL; 3150e51060f0SSean Hefty break; 3151e51060f0SSean Hefty } 3152e51060f0SSean Hefty out: 3153e51060f0SSean Hefty return ret; 3154e51060f0SSean Hefty } 3155e51060f0SSean Hefty EXPORT_SYMBOL(rdma_disconnect); 3156e51060f0SSean Hefty 3157c8f6a362SSean Hefty static int cma_ib_mc_handler(int status, struct ib_sa_multicast *multicast) 3158c8f6a362SSean Hefty { 3159c8f6a362SSean Hefty struct rdma_id_private *id_priv; 3160c8f6a362SSean Hefty struct cma_multicast *mc = multicast->context; 3161c8f6a362SSean Hefty struct rdma_cm_event event; 3162c8f6a362SSean Hefty int ret; 3163c8f6a362SSean Hefty 3164c8f6a362SSean Hefty id_priv = mc->id_priv; 3165550e5ca7SNir Muchtar if (cma_disable_callback(id_priv, RDMA_CM_ADDR_BOUND) && 3166550e5ca7SNir Muchtar cma_disable_callback(id_priv, RDMA_CM_ADDR_RESOLVED)) 31678aa08602SSean Hefty return 0; 3168c8f6a362SSean Hefty 3169c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 3170c8f6a362SSean Hefty if (!status && id_priv->id.qp) 3171c8f6a362SSean Hefty status = ib_attach_mcast(id_priv->id.qp, &multicast->rec.mgid, 317246ea5061SSean Hefty be16_to_cpu(multicast->rec.mlid)); 3173c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 3174c8f6a362SSean Hefty 3175c8f6a362SSean Hefty memset(&event, 0, sizeof event); 3176c8f6a362SSean Hefty event.status = status; 3177c8f6a362SSean Hefty event.param.ud.private_data = mc->context; 3178c8f6a362SSean Hefty if (!status) { 3179c8f6a362SSean Hefty event.event = RDMA_CM_EVENT_MULTICAST_JOIN; 3180c8f6a362SSean Hefty ib_init_ah_from_mcmember(id_priv->id.device, 3181c8f6a362SSean Hefty id_priv->id.port_num, &multicast->rec, 3182c8f6a362SSean Hefty &event.param.ud.ah_attr); 3183c8f6a362SSean Hefty event.param.ud.qp_num = 0xFFFFFF; 3184c8f6a362SSean Hefty event.param.ud.qkey = be32_to_cpu(multicast->rec.qkey); 3185c8f6a362SSean Hefty } else 3186c8f6a362SSean Hefty event.event = RDMA_CM_EVENT_MULTICAST_ERROR; 3187c8f6a362SSean Hefty 3188c8f6a362SSean Hefty ret = id_priv->id.event_handler(&id_priv->id, &event); 3189c8f6a362SSean Hefty if (ret) { 3190550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 3191de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 3192c8f6a362SSean Hefty rdma_destroy_id(&id_priv->id); 3193c8f6a362SSean Hefty return 0; 3194c8f6a362SSean Hefty } 31958aa08602SSean Hefty 3196de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 3197c8f6a362SSean Hefty return 0; 3198c8f6a362SSean Hefty } 3199c8f6a362SSean Hefty 3200c8f6a362SSean Hefty static void cma_set_mgid(struct rdma_id_private *id_priv, 3201c8f6a362SSean Hefty struct sockaddr *addr, union ib_gid *mgid) 3202c8f6a362SSean Hefty { 3203c8f6a362SSean Hefty unsigned char mc_map[MAX_ADDR_LEN]; 3204c8f6a362SSean Hefty struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 3205c8f6a362SSean Hefty struct sockaddr_in *sin = (struct sockaddr_in *) addr; 3206c8f6a362SSean Hefty struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) addr; 3207c8f6a362SSean Hefty 3208c8f6a362SSean Hefty if (cma_any_addr(addr)) { 3209c8f6a362SSean Hefty memset(mgid, 0, sizeof *mgid); 3210c8f6a362SSean Hefty } else if ((addr->sa_family == AF_INET6) && 32111c9b2819SJason Gunthorpe ((be32_to_cpu(sin6->sin6_addr.s6_addr32[0]) & 0xFFF0FFFF) == 3212c8f6a362SSean Hefty 0xFF10A01B)) { 3213c8f6a362SSean Hefty /* IPv6 address is an SA assigned MGID. */ 3214c8f6a362SSean Hefty memcpy(mgid, &sin6->sin6_addr, sizeof *mgid); 3215e2e62697SJason Gunthorpe } else if ((addr->sa_family == AF_INET6)) { 3216e2e62697SJason Gunthorpe ipv6_ib_mc_map(&sin6->sin6_addr, dev_addr->broadcast, mc_map); 3217e2e62697SJason Gunthorpe if (id_priv->id.ps == RDMA_PS_UDP) 3218e2e62697SJason Gunthorpe mc_map[7] = 0x01; /* Use RDMA CM signature */ 3219e2e62697SJason Gunthorpe *mgid = *(union ib_gid *) (mc_map + 4); 3220c8f6a362SSean Hefty } else { 3221a9e527e3SRolf Manderscheid ip_ib_mc_map(sin->sin_addr.s_addr, dev_addr->broadcast, mc_map); 3222c8f6a362SSean Hefty if (id_priv->id.ps == RDMA_PS_UDP) 3223c8f6a362SSean Hefty mc_map[7] = 0x01; /* Use RDMA CM signature */ 3224c8f6a362SSean Hefty *mgid = *(union ib_gid *) (mc_map + 4); 3225c8f6a362SSean Hefty } 3226c8f6a362SSean Hefty } 3227c8f6a362SSean Hefty 3228c8f6a362SSean Hefty static int cma_join_ib_multicast(struct rdma_id_private *id_priv, 3229c8f6a362SSean Hefty struct cma_multicast *mc) 3230c8f6a362SSean Hefty { 3231c8f6a362SSean Hefty struct ib_sa_mcmember_rec rec; 3232c8f6a362SSean Hefty struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 3233c8f6a362SSean Hefty ib_sa_comp_mask comp_mask; 3234c8f6a362SSean Hefty int ret; 3235c8f6a362SSean Hefty 3236c8f6a362SSean Hefty ib_addr_get_mgid(dev_addr, &rec.mgid); 3237c8f6a362SSean Hefty ret = ib_sa_get_mcmember_rec(id_priv->id.device, id_priv->id.port_num, 3238c8f6a362SSean Hefty &rec.mgid, &rec); 3239c8f6a362SSean Hefty if (ret) 3240c8f6a362SSean Hefty return ret; 3241c8f6a362SSean Hefty 32423f446754SRoland Dreier cma_set_mgid(id_priv, (struct sockaddr *) &mc->addr, &rec.mgid); 3243c8f6a362SSean Hefty if (id_priv->id.ps == RDMA_PS_UDP) 3244c8f6a362SSean Hefty rec.qkey = cpu_to_be32(RDMA_UDP_QKEY); 32456f8372b6SSean Hefty rdma_addr_get_sgid(dev_addr, &rec.port_gid); 3246c8f6a362SSean Hefty rec.pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr)); 3247c8f6a362SSean Hefty rec.join_state = 1; 3248c8f6a362SSean Hefty 3249c8f6a362SSean Hefty comp_mask = IB_SA_MCMEMBER_REC_MGID | IB_SA_MCMEMBER_REC_PORT_GID | 3250c8f6a362SSean Hefty IB_SA_MCMEMBER_REC_PKEY | IB_SA_MCMEMBER_REC_JOIN_STATE | 3251c8f6a362SSean Hefty IB_SA_MCMEMBER_REC_QKEY | IB_SA_MCMEMBER_REC_SL | 3252c8f6a362SSean Hefty IB_SA_MCMEMBER_REC_FLOW_LABEL | 3253c8f6a362SSean Hefty IB_SA_MCMEMBER_REC_TRAFFIC_CLASS; 3254c8f6a362SSean Hefty 325584adeee9SYossi Etigin if (id_priv->id.ps == RDMA_PS_IPOIB) 325684adeee9SYossi Etigin comp_mask |= IB_SA_MCMEMBER_REC_RATE | 32572a22fb8cSDotan Barak IB_SA_MCMEMBER_REC_RATE_SELECTOR | 32582a22fb8cSDotan Barak IB_SA_MCMEMBER_REC_MTU_SELECTOR | 32592a22fb8cSDotan Barak IB_SA_MCMEMBER_REC_MTU | 32602a22fb8cSDotan Barak IB_SA_MCMEMBER_REC_HOP_LIMIT; 326184adeee9SYossi Etigin 3262c8f6a362SSean Hefty mc->multicast.ib = ib_sa_join_multicast(&sa_client, id_priv->id.device, 3263c8f6a362SSean Hefty id_priv->id.port_num, &rec, 3264c8f6a362SSean Hefty comp_mask, GFP_KERNEL, 3265c8f6a362SSean Hefty cma_ib_mc_handler, mc); 32664e289045SFengguang Wu return PTR_RET(mc->multicast.ib); 3267c8f6a362SSean Hefty } 3268c8f6a362SSean Hefty 32693c86aa70SEli Cohen static void iboe_mcast_work_handler(struct work_struct *work) 32703c86aa70SEli Cohen { 32713c86aa70SEli Cohen struct iboe_mcast_work *mw = container_of(work, struct iboe_mcast_work, work); 32723c86aa70SEli Cohen struct cma_multicast *mc = mw->mc; 32733c86aa70SEli Cohen struct ib_sa_multicast *m = mc->multicast.ib; 32743c86aa70SEli Cohen 32753c86aa70SEli Cohen mc->multicast.ib->context = mc; 32763c86aa70SEli Cohen cma_ib_mc_handler(0, m); 32773c86aa70SEli Cohen kref_put(&mc->mcref, release_mc); 32783c86aa70SEli Cohen kfree(mw); 32793c86aa70SEli Cohen } 32803c86aa70SEli Cohen 32813c86aa70SEli Cohen static void cma_iboe_set_mgid(struct sockaddr *addr, union ib_gid *mgid) 32823c86aa70SEli Cohen { 32833c86aa70SEli Cohen struct sockaddr_in *sin = (struct sockaddr_in *)addr; 32843c86aa70SEli Cohen struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr; 32853c86aa70SEli Cohen 32863c86aa70SEli Cohen if (cma_any_addr(addr)) { 32873c86aa70SEli Cohen memset(mgid, 0, sizeof *mgid); 32883c86aa70SEli Cohen } else if (addr->sa_family == AF_INET6) { 32893c86aa70SEli Cohen memcpy(mgid, &sin6->sin6_addr, sizeof *mgid); 32903c86aa70SEli Cohen } else { 32913c86aa70SEli Cohen mgid->raw[0] = 0xff; 32923c86aa70SEli Cohen mgid->raw[1] = 0x0e; 32933c86aa70SEli Cohen mgid->raw[2] = 0; 32943c86aa70SEli Cohen mgid->raw[3] = 0; 32953c86aa70SEli Cohen mgid->raw[4] = 0; 32963c86aa70SEli Cohen mgid->raw[5] = 0; 32973c86aa70SEli Cohen mgid->raw[6] = 0; 32983c86aa70SEli Cohen mgid->raw[7] = 0; 32993c86aa70SEli Cohen mgid->raw[8] = 0; 33003c86aa70SEli Cohen mgid->raw[9] = 0; 33013c86aa70SEli Cohen mgid->raw[10] = 0xff; 33023c86aa70SEli Cohen mgid->raw[11] = 0xff; 33033c86aa70SEli Cohen *(__be32 *)(&mgid->raw[12]) = sin->sin_addr.s_addr; 33043c86aa70SEli Cohen } 33053c86aa70SEli Cohen } 33063c86aa70SEli Cohen 33073c86aa70SEli Cohen static int cma_iboe_join_multicast(struct rdma_id_private *id_priv, 33083c86aa70SEli Cohen struct cma_multicast *mc) 33093c86aa70SEli Cohen { 33103c86aa70SEli Cohen struct iboe_mcast_work *work; 33113c86aa70SEli Cohen struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 33123c86aa70SEli Cohen int err; 33133c86aa70SEli Cohen struct sockaddr *addr = (struct sockaddr *)&mc->addr; 33143c86aa70SEli Cohen struct net_device *ndev = NULL; 33153c86aa70SEli Cohen 33163c86aa70SEli Cohen if (cma_zero_addr((struct sockaddr *)&mc->addr)) 33173c86aa70SEli Cohen return -EINVAL; 33183c86aa70SEli Cohen 33193c86aa70SEli Cohen work = kzalloc(sizeof *work, GFP_KERNEL); 33203c86aa70SEli Cohen if (!work) 33213c86aa70SEli Cohen return -ENOMEM; 33223c86aa70SEli Cohen 33233c86aa70SEli Cohen mc->multicast.ib = kzalloc(sizeof(struct ib_sa_multicast), GFP_KERNEL); 33243c86aa70SEli Cohen if (!mc->multicast.ib) { 33253c86aa70SEli Cohen err = -ENOMEM; 33263c86aa70SEli Cohen goto out1; 33273c86aa70SEli Cohen } 33283c86aa70SEli Cohen 33293c86aa70SEli Cohen cma_iboe_set_mgid(addr, &mc->multicast.ib->rec.mgid); 33303c86aa70SEli Cohen 33313c86aa70SEli Cohen mc->multicast.ib->rec.pkey = cpu_to_be16(0xffff); 33323c86aa70SEli Cohen if (id_priv->id.ps == RDMA_PS_UDP) 33333c86aa70SEli Cohen mc->multicast.ib->rec.qkey = cpu_to_be32(RDMA_UDP_QKEY); 33343c86aa70SEli Cohen 33353c86aa70SEli Cohen if (dev_addr->bound_dev_if) 33363c86aa70SEli Cohen ndev = dev_get_by_index(&init_net, dev_addr->bound_dev_if); 33373c86aa70SEli Cohen if (!ndev) { 33383c86aa70SEli Cohen err = -ENODEV; 33393c86aa70SEli Cohen goto out2; 33403c86aa70SEli Cohen } 33413c86aa70SEli Cohen mc->multicast.ib->rec.rate = iboe_get_rate(ndev); 33423c86aa70SEli Cohen mc->multicast.ib->rec.hop_limit = 1; 33433c86aa70SEli Cohen mc->multicast.ib->rec.mtu = iboe_get_mtu(ndev->mtu); 33443c86aa70SEli Cohen dev_put(ndev); 33453c86aa70SEli Cohen if (!mc->multicast.ib->rec.mtu) { 33463c86aa70SEli Cohen err = -EINVAL; 33473c86aa70SEli Cohen goto out2; 33483c86aa70SEli Cohen } 33493c86aa70SEli Cohen iboe_addr_get_sgid(dev_addr, &mc->multicast.ib->rec.port_gid); 33503c86aa70SEli Cohen work->id = id_priv; 33513c86aa70SEli Cohen work->mc = mc; 33523c86aa70SEli Cohen INIT_WORK(&work->work, iboe_mcast_work_handler); 33533c86aa70SEli Cohen kref_get(&mc->mcref); 33543c86aa70SEli Cohen queue_work(cma_wq, &work->work); 33553c86aa70SEli Cohen 33563c86aa70SEli Cohen return 0; 33573c86aa70SEli Cohen 33583c86aa70SEli Cohen out2: 33593c86aa70SEli Cohen kfree(mc->multicast.ib); 33603c86aa70SEli Cohen out1: 33613c86aa70SEli Cohen kfree(work); 33623c86aa70SEli Cohen return err; 33633c86aa70SEli Cohen } 33643c86aa70SEli Cohen 3365c8f6a362SSean Hefty int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr, 3366c8f6a362SSean Hefty void *context) 3367c8f6a362SSean Hefty { 3368c8f6a362SSean Hefty struct rdma_id_private *id_priv; 3369c8f6a362SSean Hefty struct cma_multicast *mc; 3370c8f6a362SSean Hefty int ret; 3371c8f6a362SSean Hefty 3372c8f6a362SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 3373550e5ca7SNir Muchtar if (!cma_comp(id_priv, RDMA_CM_ADDR_BOUND) && 3374550e5ca7SNir Muchtar !cma_comp(id_priv, RDMA_CM_ADDR_RESOLVED)) 3375c8f6a362SSean Hefty return -EINVAL; 3376c8f6a362SSean Hefty 3377c8f6a362SSean Hefty mc = kmalloc(sizeof *mc, GFP_KERNEL); 3378c8f6a362SSean Hefty if (!mc) 3379c8f6a362SSean Hefty return -ENOMEM; 3380c8f6a362SSean Hefty 3381ef560861SSean Hefty memcpy(&mc->addr, addr, rdma_addr_size(addr)); 3382c8f6a362SSean Hefty mc->context = context; 3383c8f6a362SSean Hefty mc->id_priv = id_priv; 3384c8f6a362SSean Hefty 3385c8f6a362SSean Hefty spin_lock(&id_priv->lock); 3386c8f6a362SSean Hefty list_add(&mc->list, &id_priv->mc_list); 3387c8f6a362SSean Hefty spin_unlock(&id_priv->lock); 3388c8f6a362SSean Hefty 3389c8f6a362SSean Hefty switch (rdma_node_get_transport(id->device->node_type)) { 3390c8f6a362SSean Hefty case RDMA_TRANSPORT_IB: 33913c86aa70SEli Cohen switch (rdma_port_get_link_layer(id->device, id->port_num)) { 33923c86aa70SEli Cohen case IB_LINK_LAYER_INFINIBAND: 3393c8f6a362SSean Hefty ret = cma_join_ib_multicast(id_priv, mc); 3394c8f6a362SSean Hefty break; 33953c86aa70SEli Cohen case IB_LINK_LAYER_ETHERNET: 33963c86aa70SEli Cohen kref_init(&mc->mcref); 33973c86aa70SEli Cohen ret = cma_iboe_join_multicast(id_priv, mc); 33983c86aa70SEli Cohen break; 33993c86aa70SEli Cohen default: 34003c86aa70SEli Cohen ret = -EINVAL; 34013c86aa70SEli Cohen } 34023c86aa70SEli Cohen break; 3403c8f6a362SSean Hefty default: 3404c8f6a362SSean Hefty ret = -ENOSYS; 3405c8f6a362SSean Hefty break; 3406c8f6a362SSean Hefty } 3407c8f6a362SSean Hefty 3408c8f6a362SSean Hefty if (ret) { 3409c8f6a362SSean Hefty spin_lock_irq(&id_priv->lock); 3410c8f6a362SSean Hefty list_del(&mc->list); 3411c8f6a362SSean Hefty spin_unlock_irq(&id_priv->lock); 3412c8f6a362SSean Hefty kfree(mc); 3413c8f6a362SSean Hefty } 3414c8f6a362SSean Hefty return ret; 3415c8f6a362SSean Hefty } 3416c8f6a362SSean Hefty EXPORT_SYMBOL(rdma_join_multicast); 3417c8f6a362SSean Hefty 3418c8f6a362SSean Hefty void rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr) 3419c8f6a362SSean Hefty { 3420c8f6a362SSean Hefty struct rdma_id_private *id_priv; 3421c8f6a362SSean Hefty struct cma_multicast *mc; 3422c8f6a362SSean Hefty 3423c8f6a362SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 3424c8f6a362SSean Hefty spin_lock_irq(&id_priv->lock); 3425c8f6a362SSean Hefty list_for_each_entry(mc, &id_priv->mc_list, list) { 3426ef560861SSean Hefty if (!memcmp(&mc->addr, addr, rdma_addr_size(addr))) { 3427c8f6a362SSean Hefty list_del(&mc->list); 3428c8f6a362SSean Hefty spin_unlock_irq(&id_priv->lock); 3429c8f6a362SSean Hefty 3430c8f6a362SSean Hefty if (id->qp) 3431c8f6a362SSean Hefty ib_detach_mcast(id->qp, 3432c8f6a362SSean Hefty &mc->multicast.ib->rec.mgid, 343346ea5061SSean Hefty be16_to_cpu(mc->multicast.ib->rec.mlid)); 34343c86aa70SEli Cohen if (rdma_node_get_transport(id_priv->cma_dev->device->node_type) == RDMA_TRANSPORT_IB) { 34353c86aa70SEli Cohen switch (rdma_port_get_link_layer(id->device, id->port_num)) { 34363c86aa70SEli Cohen case IB_LINK_LAYER_INFINIBAND: 3437c8f6a362SSean Hefty ib_sa_free_multicast(mc->multicast.ib); 3438c8f6a362SSean Hefty kfree(mc); 34393c86aa70SEli Cohen break; 34403c86aa70SEli Cohen case IB_LINK_LAYER_ETHERNET: 34413c86aa70SEli Cohen kref_put(&mc->mcref, release_mc); 34423c86aa70SEli Cohen break; 34433c86aa70SEli Cohen default: 34443c86aa70SEli Cohen break; 34453c86aa70SEli Cohen } 34463c86aa70SEli Cohen } 3447c8f6a362SSean Hefty return; 3448c8f6a362SSean Hefty } 3449c8f6a362SSean Hefty } 3450c8f6a362SSean Hefty spin_unlock_irq(&id_priv->lock); 3451c8f6a362SSean Hefty } 3452c8f6a362SSean Hefty EXPORT_SYMBOL(rdma_leave_multicast); 3453c8f6a362SSean Hefty 3454dd5bdff8SOr Gerlitz static int cma_netdev_change(struct net_device *ndev, struct rdma_id_private *id_priv) 3455dd5bdff8SOr Gerlitz { 3456dd5bdff8SOr Gerlitz struct rdma_dev_addr *dev_addr; 3457dd5bdff8SOr Gerlitz struct cma_ndev_work *work; 3458dd5bdff8SOr Gerlitz 3459dd5bdff8SOr Gerlitz dev_addr = &id_priv->id.route.addr.dev_addr; 3460dd5bdff8SOr Gerlitz 34616266ed6eSSean Hefty if ((dev_addr->bound_dev_if == ndev->ifindex) && 3462dd5bdff8SOr Gerlitz memcmp(dev_addr->src_dev_addr, ndev->dev_addr, ndev->addr_len)) { 3463dd5bdff8SOr Gerlitz printk(KERN_INFO "RDMA CM addr change for ndev %s used by id %p\n", 3464dd5bdff8SOr Gerlitz ndev->name, &id_priv->id); 3465dd5bdff8SOr Gerlitz work = kzalloc(sizeof *work, GFP_KERNEL); 3466dd5bdff8SOr Gerlitz if (!work) 3467dd5bdff8SOr Gerlitz return -ENOMEM; 3468dd5bdff8SOr Gerlitz 3469dd5bdff8SOr Gerlitz INIT_WORK(&work->work, cma_ndev_work_handler); 3470dd5bdff8SOr Gerlitz work->id = id_priv; 3471dd5bdff8SOr Gerlitz work->event.event = RDMA_CM_EVENT_ADDR_CHANGE; 3472dd5bdff8SOr Gerlitz atomic_inc(&id_priv->refcount); 3473dd5bdff8SOr Gerlitz queue_work(cma_wq, &work->work); 3474dd5bdff8SOr Gerlitz } 3475dd5bdff8SOr Gerlitz 3476dd5bdff8SOr Gerlitz return 0; 3477dd5bdff8SOr Gerlitz } 3478dd5bdff8SOr Gerlitz 3479dd5bdff8SOr Gerlitz static int cma_netdev_callback(struct notifier_block *self, unsigned long event, 3480351638e7SJiri Pirko void *ptr) 3481dd5bdff8SOr Gerlitz { 3482351638e7SJiri Pirko struct net_device *ndev = netdev_notifier_info_to_dev(ptr); 3483dd5bdff8SOr Gerlitz struct cma_device *cma_dev; 3484dd5bdff8SOr Gerlitz struct rdma_id_private *id_priv; 3485dd5bdff8SOr Gerlitz int ret = NOTIFY_DONE; 3486dd5bdff8SOr Gerlitz 3487dd5bdff8SOr Gerlitz if (dev_net(ndev) != &init_net) 3488dd5bdff8SOr Gerlitz return NOTIFY_DONE; 3489dd5bdff8SOr Gerlitz 3490dd5bdff8SOr Gerlitz if (event != NETDEV_BONDING_FAILOVER) 3491dd5bdff8SOr Gerlitz return NOTIFY_DONE; 3492dd5bdff8SOr Gerlitz 3493dd5bdff8SOr Gerlitz if (!(ndev->flags & IFF_MASTER) || !(ndev->priv_flags & IFF_BONDING)) 3494dd5bdff8SOr Gerlitz return NOTIFY_DONE; 3495dd5bdff8SOr Gerlitz 3496dd5bdff8SOr Gerlitz mutex_lock(&lock); 3497dd5bdff8SOr Gerlitz list_for_each_entry(cma_dev, &dev_list, list) 3498dd5bdff8SOr Gerlitz list_for_each_entry(id_priv, &cma_dev->id_list, list) { 3499dd5bdff8SOr Gerlitz ret = cma_netdev_change(ndev, id_priv); 3500dd5bdff8SOr Gerlitz if (ret) 3501dd5bdff8SOr Gerlitz goto out; 3502dd5bdff8SOr Gerlitz } 3503dd5bdff8SOr Gerlitz 3504dd5bdff8SOr Gerlitz out: 3505dd5bdff8SOr Gerlitz mutex_unlock(&lock); 3506dd5bdff8SOr Gerlitz return ret; 3507dd5bdff8SOr Gerlitz } 3508dd5bdff8SOr Gerlitz 3509dd5bdff8SOr Gerlitz static struct notifier_block cma_nb = { 3510dd5bdff8SOr Gerlitz .notifier_call = cma_netdev_callback 3511dd5bdff8SOr Gerlitz }; 3512dd5bdff8SOr Gerlitz 3513e51060f0SSean Hefty static void cma_add_one(struct ib_device *device) 3514e51060f0SSean Hefty { 3515e51060f0SSean Hefty struct cma_device *cma_dev; 3516e51060f0SSean Hefty struct rdma_id_private *id_priv; 3517e51060f0SSean Hefty 3518e51060f0SSean Hefty cma_dev = kmalloc(sizeof *cma_dev, GFP_KERNEL); 3519e51060f0SSean Hefty if (!cma_dev) 3520e51060f0SSean Hefty return; 3521e51060f0SSean Hefty 3522e51060f0SSean Hefty cma_dev->device = device; 3523e51060f0SSean Hefty 3524e51060f0SSean Hefty init_completion(&cma_dev->comp); 3525e51060f0SSean Hefty atomic_set(&cma_dev->refcount, 1); 3526e51060f0SSean Hefty INIT_LIST_HEAD(&cma_dev->id_list); 3527e51060f0SSean Hefty ib_set_client_data(device, &cma_client, cma_dev); 3528e51060f0SSean Hefty 3529e51060f0SSean Hefty mutex_lock(&lock); 3530e51060f0SSean Hefty list_add_tail(&cma_dev->list, &dev_list); 3531e51060f0SSean Hefty list_for_each_entry(id_priv, &listen_any_list, list) 3532e51060f0SSean Hefty cma_listen_on_dev(id_priv, cma_dev); 3533e51060f0SSean Hefty mutex_unlock(&lock); 3534e51060f0SSean Hefty } 3535e51060f0SSean Hefty 3536e51060f0SSean Hefty static int cma_remove_id_dev(struct rdma_id_private *id_priv) 3537e51060f0SSean Hefty { 3538a1b1b61fSSean Hefty struct rdma_cm_event event; 3539550e5ca7SNir Muchtar enum rdma_cm_state state; 3540de910bd9SOr Gerlitz int ret = 0; 3541e51060f0SSean Hefty 3542e51060f0SSean Hefty /* Record that we want to remove the device */ 3543550e5ca7SNir Muchtar state = cma_exch(id_priv, RDMA_CM_DEVICE_REMOVAL); 3544550e5ca7SNir Muchtar if (state == RDMA_CM_DESTROYING) 3545e51060f0SSean Hefty return 0; 3546e51060f0SSean Hefty 3547e51060f0SSean Hefty cma_cancel_operation(id_priv, state); 3548de910bd9SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 3549e51060f0SSean Hefty 3550e51060f0SSean Hefty /* Check for destruction from another callback. */ 3551550e5ca7SNir Muchtar if (!cma_comp(id_priv, RDMA_CM_DEVICE_REMOVAL)) 3552de910bd9SOr Gerlitz goto out; 3553e51060f0SSean Hefty 3554a1b1b61fSSean Hefty memset(&event, 0, sizeof event); 3555a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_DEVICE_REMOVAL; 3556de910bd9SOr Gerlitz ret = id_priv->id.event_handler(&id_priv->id, &event); 3557de910bd9SOr Gerlitz out: 3558de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 3559de910bd9SOr Gerlitz return ret; 3560e51060f0SSean Hefty } 3561e51060f0SSean Hefty 3562e51060f0SSean Hefty static void cma_process_remove(struct cma_device *cma_dev) 3563e51060f0SSean Hefty { 3564e51060f0SSean Hefty struct rdma_id_private *id_priv; 3565e51060f0SSean Hefty int ret; 3566e51060f0SSean Hefty 3567e51060f0SSean Hefty mutex_lock(&lock); 3568e51060f0SSean Hefty while (!list_empty(&cma_dev->id_list)) { 3569e51060f0SSean Hefty id_priv = list_entry(cma_dev->id_list.next, 3570e51060f0SSean Hefty struct rdma_id_private, list); 3571e51060f0SSean Hefty 3572d02d1f53SSean Hefty list_del(&id_priv->listen_list); 357394de178aSKrishna Kumar list_del_init(&id_priv->list); 3574e51060f0SSean Hefty atomic_inc(&id_priv->refcount); 3575e51060f0SSean Hefty mutex_unlock(&lock); 3576e51060f0SSean Hefty 3577d02d1f53SSean Hefty ret = id_priv->internal_id ? 1 : cma_remove_id_dev(id_priv); 3578e51060f0SSean Hefty cma_deref_id(id_priv); 3579e51060f0SSean Hefty if (ret) 3580e51060f0SSean Hefty rdma_destroy_id(&id_priv->id); 3581e51060f0SSean Hefty 3582e51060f0SSean Hefty mutex_lock(&lock); 3583e51060f0SSean Hefty } 3584e51060f0SSean Hefty mutex_unlock(&lock); 3585e51060f0SSean Hefty 3586e51060f0SSean Hefty cma_deref_dev(cma_dev); 3587e51060f0SSean Hefty wait_for_completion(&cma_dev->comp); 3588e51060f0SSean Hefty } 3589e51060f0SSean Hefty 3590e51060f0SSean Hefty static void cma_remove_one(struct ib_device *device) 3591e51060f0SSean Hefty { 3592e51060f0SSean Hefty struct cma_device *cma_dev; 3593e51060f0SSean Hefty 3594e51060f0SSean Hefty cma_dev = ib_get_client_data(device, &cma_client); 3595e51060f0SSean Hefty if (!cma_dev) 3596e51060f0SSean Hefty return; 3597e51060f0SSean Hefty 3598e51060f0SSean Hefty mutex_lock(&lock); 3599e51060f0SSean Hefty list_del(&cma_dev->list); 3600e51060f0SSean Hefty mutex_unlock(&lock); 3601e51060f0SSean Hefty 3602e51060f0SSean Hefty cma_process_remove(cma_dev); 3603e51060f0SSean Hefty kfree(cma_dev); 3604e51060f0SSean Hefty } 3605e51060f0SSean Hefty 3606753f618aSNir Muchtar static int cma_get_id_stats(struct sk_buff *skb, struct netlink_callback *cb) 3607753f618aSNir Muchtar { 3608753f618aSNir Muchtar struct nlmsghdr *nlh; 3609753f618aSNir Muchtar struct rdma_cm_id_stats *id_stats; 3610753f618aSNir Muchtar struct rdma_id_private *id_priv; 3611753f618aSNir Muchtar struct rdma_cm_id *id = NULL; 3612753f618aSNir Muchtar struct cma_device *cma_dev; 3613753f618aSNir Muchtar int i_dev = 0, i_id = 0; 3614753f618aSNir Muchtar 3615753f618aSNir Muchtar /* 3616753f618aSNir Muchtar * We export all of the IDs as a sequence of messages. Each 3617753f618aSNir Muchtar * ID gets its own netlink message. 3618753f618aSNir Muchtar */ 3619753f618aSNir Muchtar mutex_lock(&lock); 3620753f618aSNir Muchtar 3621753f618aSNir Muchtar list_for_each_entry(cma_dev, &dev_list, list) { 3622753f618aSNir Muchtar if (i_dev < cb->args[0]) { 3623753f618aSNir Muchtar i_dev++; 3624753f618aSNir Muchtar continue; 3625753f618aSNir Muchtar } 3626753f618aSNir Muchtar 3627753f618aSNir Muchtar i_id = 0; 3628753f618aSNir Muchtar list_for_each_entry(id_priv, &cma_dev->id_list, list) { 3629753f618aSNir Muchtar if (i_id < cb->args[1]) { 3630753f618aSNir Muchtar i_id++; 3631753f618aSNir Muchtar continue; 3632753f618aSNir Muchtar } 3633753f618aSNir Muchtar 3634753f618aSNir Muchtar id_stats = ibnl_put_msg(skb, &nlh, cb->nlh->nlmsg_seq, 3635753f618aSNir Muchtar sizeof *id_stats, RDMA_NL_RDMA_CM, 3636753f618aSNir Muchtar RDMA_NL_RDMA_CM_ID_STATS); 3637753f618aSNir Muchtar if (!id_stats) 3638753f618aSNir Muchtar goto out; 3639753f618aSNir Muchtar 3640753f618aSNir Muchtar memset(id_stats, 0, sizeof *id_stats); 3641753f618aSNir Muchtar id = &id_priv->id; 3642753f618aSNir Muchtar id_stats->node_type = id->route.addr.dev_addr.dev_type; 3643753f618aSNir Muchtar id_stats->port_num = id->port_num; 3644753f618aSNir Muchtar id_stats->bound_dev_if = 3645753f618aSNir Muchtar id->route.addr.dev_addr.bound_dev_if; 3646753f618aSNir Muchtar 3647f4753834SSean Hefty if (cma_family(id_priv) == AF_INET) { 3648753f618aSNir Muchtar if (ibnl_put_attr(skb, nlh, 3649753f618aSNir Muchtar sizeof(struct sockaddr_in), 3650f4753834SSean Hefty cma_src_addr(id_priv), 3651753f618aSNir Muchtar RDMA_NL_RDMA_CM_ATTR_SRC_ADDR)) { 3652753f618aSNir Muchtar goto out; 3653753f618aSNir Muchtar } 3654753f618aSNir Muchtar if (ibnl_put_attr(skb, nlh, 3655753f618aSNir Muchtar sizeof(struct sockaddr_in), 3656f4753834SSean Hefty cma_dst_addr(id_priv), 3657753f618aSNir Muchtar RDMA_NL_RDMA_CM_ATTR_DST_ADDR)) { 3658753f618aSNir Muchtar goto out; 3659753f618aSNir Muchtar } 3660f4753834SSean Hefty } else if (cma_family(id_priv) == AF_INET6) { 3661753f618aSNir Muchtar if (ibnl_put_attr(skb, nlh, 3662753f618aSNir Muchtar sizeof(struct sockaddr_in6), 3663f4753834SSean Hefty cma_src_addr(id_priv), 3664753f618aSNir Muchtar RDMA_NL_RDMA_CM_ATTR_SRC_ADDR)) { 3665753f618aSNir Muchtar goto out; 3666753f618aSNir Muchtar } 3667753f618aSNir Muchtar if (ibnl_put_attr(skb, nlh, 3668753f618aSNir Muchtar sizeof(struct sockaddr_in6), 3669f4753834SSean Hefty cma_dst_addr(id_priv), 3670753f618aSNir Muchtar RDMA_NL_RDMA_CM_ATTR_DST_ADDR)) { 3671753f618aSNir Muchtar goto out; 3672753f618aSNir Muchtar } 3673753f618aSNir Muchtar } 3674753f618aSNir Muchtar 367583e9502dSNir Muchtar id_stats->pid = id_priv->owner; 3676753f618aSNir Muchtar id_stats->port_space = id->ps; 3677753f618aSNir Muchtar id_stats->cm_state = id_priv->state; 3678753f618aSNir Muchtar id_stats->qp_num = id_priv->qp_num; 3679753f618aSNir Muchtar id_stats->qp_type = id->qp_type; 3680753f618aSNir Muchtar 3681753f618aSNir Muchtar i_id++; 3682753f618aSNir Muchtar } 3683753f618aSNir Muchtar 3684753f618aSNir Muchtar cb->args[1] = 0; 3685753f618aSNir Muchtar i_dev++; 3686753f618aSNir Muchtar } 3687753f618aSNir Muchtar 3688753f618aSNir Muchtar out: 3689753f618aSNir Muchtar mutex_unlock(&lock); 3690753f618aSNir Muchtar cb->args[0] = i_dev; 3691753f618aSNir Muchtar cb->args[1] = i_id; 3692753f618aSNir Muchtar 3693753f618aSNir Muchtar return skb->len; 3694753f618aSNir Muchtar } 3695753f618aSNir Muchtar 3696753f618aSNir Muchtar static const struct ibnl_client_cbs cma_cb_table[] = { 3697809d5fc9SGao feng [RDMA_NL_RDMA_CM_ID_STATS] = { .dump = cma_get_id_stats, 3698809d5fc9SGao feng .module = THIS_MODULE }, 3699753f618aSNir Muchtar }; 3700753f618aSNir Muchtar 3701716abb1fSPeter Huewe static int __init cma_init(void) 3702e51060f0SSean Hefty { 37035d7220e8STetsuo Handa int ret; 3704227b60f5SStephen Hemminger 3705c7f743a6SSean Hefty cma_wq = create_singlethread_workqueue("rdma_cm"); 3706e51060f0SSean Hefty if (!cma_wq) 3707e51060f0SSean Hefty return -ENOMEM; 3708e51060f0SSean Hefty 3709c1a0b23bSMichael S. Tsirkin ib_sa_register_client(&sa_client); 37107a118df3SSean Hefty rdma_addr_register_client(&addr_client); 3711dd5bdff8SOr Gerlitz register_netdevice_notifier(&cma_nb); 3712c1a0b23bSMichael S. Tsirkin 3713e51060f0SSean Hefty ret = ib_register_client(&cma_client); 3714e51060f0SSean Hefty if (ret) 3715e51060f0SSean Hefty goto err; 3716753f618aSNir Muchtar 3717753f618aSNir Muchtar if (ibnl_add_client(RDMA_NL_RDMA_CM, RDMA_NL_RDMA_CM_NUM_OPS, cma_cb_table)) 3718753f618aSNir Muchtar printk(KERN_WARNING "RDMA CMA: failed to add netlink callback\n"); 3719753f618aSNir Muchtar 3720e51060f0SSean Hefty return 0; 3721e51060f0SSean Hefty 3722e51060f0SSean Hefty err: 3723dd5bdff8SOr Gerlitz unregister_netdevice_notifier(&cma_nb); 37247a118df3SSean Hefty rdma_addr_unregister_client(&addr_client); 3725c1a0b23bSMichael S. Tsirkin ib_sa_unregister_client(&sa_client); 3726e51060f0SSean Hefty destroy_workqueue(cma_wq); 3727e51060f0SSean Hefty return ret; 3728e51060f0SSean Hefty } 3729e51060f0SSean Hefty 3730716abb1fSPeter Huewe static void __exit cma_cleanup(void) 3731e51060f0SSean Hefty { 3732753f618aSNir Muchtar ibnl_remove_client(RDMA_NL_RDMA_CM); 3733e51060f0SSean Hefty ib_unregister_client(&cma_client); 3734dd5bdff8SOr Gerlitz unregister_netdevice_notifier(&cma_nb); 37357a118df3SSean Hefty rdma_addr_unregister_client(&addr_client); 3736c1a0b23bSMichael S. Tsirkin ib_sa_unregister_client(&sa_client); 3737e51060f0SSean Hefty destroy_workqueue(cma_wq); 3738e51060f0SSean Hefty idr_destroy(&sdp_ps); 3739e51060f0SSean Hefty idr_destroy(&tcp_ps); 3740628e5f6dSSean Hefty idr_destroy(&udp_ps); 3741c8f6a362SSean Hefty idr_destroy(&ipoib_ps); 37422d2e9415SSean Hefty idr_destroy(&ib_ps); 3743e51060f0SSean Hefty } 3744e51060f0SSean Hefty 3745e51060f0SSean Hefty module_init(cma_init); 3746e51060f0SSean Hefty module_exit(cma_cleanup); 3747