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 441e51060f0SSean Hefty static void cma_deref_id(struct rdma_id_private *id_priv) 442e51060f0SSean Hefty { 443e51060f0SSean Hefty if (atomic_dec_and_test(&id_priv->refcount)) 444e51060f0SSean Hefty complete(&id_priv->comp); 445e51060f0SSean Hefty } 446e51060f0SSean Hefty 447de910bd9SOr Gerlitz static int cma_disable_callback(struct rdma_id_private *id_priv, 448550e5ca7SNir Muchtar enum rdma_cm_state state) 4498aa08602SSean Hefty { 450de910bd9SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 451de910bd9SOr Gerlitz if (id_priv->state != state) { 452de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 453de910bd9SOr Gerlitz return -EINVAL; 4548aa08602SSean Hefty } 455de910bd9SOr Gerlitz return 0; 456e51060f0SSean Hefty } 457e51060f0SSean Hefty 458e51060f0SSean Hefty struct rdma_cm_id *rdma_create_id(rdma_cm_event_handler event_handler, 459b26f9b99SSean Hefty void *context, enum rdma_port_space ps, 460b26f9b99SSean Hefty enum ib_qp_type qp_type) 461e51060f0SSean Hefty { 462e51060f0SSean Hefty struct rdma_id_private *id_priv; 463e51060f0SSean Hefty 464e51060f0SSean Hefty id_priv = kzalloc(sizeof *id_priv, GFP_KERNEL); 465e51060f0SSean Hefty if (!id_priv) 466e51060f0SSean Hefty return ERR_PTR(-ENOMEM); 467e51060f0SSean Hefty 46883e9502dSNir Muchtar id_priv->owner = task_pid_nr(current); 469550e5ca7SNir Muchtar id_priv->state = RDMA_CM_IDLE; 470e51060f0SSean Hefty id_priv->id.context = context; 471e51060f0SSean Hefty id_priv->id.event_handler = event_handler; 472e51060f0SSean Hefty id_priv->id.ps = ps; 473b26f9b99SSean Hefty id_priv->id.qp_type = qp_type; 474e51060f0SSean Hefty spin_lock_init(&id_priv->lock); 475c5483388SSean Hefty mutex_init(&id_priv->qp_mutex); 476e51060f0SSean Hefty init_completion(&id_priv->comp); 477e51060f0SSean Hefty atomic_set(&id_priv->refcount, 1); 478de910bd9SOr Gerlitz mutex_init(&id_priv->handler_mutex); 479e51060f0SSean Hefty INIT_LIST_HEAD(&id_priv->listen_list); 480c8f6a362SSean Hefty INIT_LIST_HEAD(&id_priv->mc_list); 481e51060f0SSean Hefty get_random_bytes(&id_priv->seq_num, sizeof id_priv->seq_num); 482e51060f0SSean Hefty 483e51060f0SSean Hefty return &id_priv->id; 484e51060f0SSean Hefty } 485e51060f0SSean Hefty EXPORT_SYMBOL(rdma_create_id); 486e51060f0SSean Hefty 487c8f6a362SSean Hefty static int cma_init_ud_qp(struct rdma_id_private *id_priv, struct ib_qp *qp) 488e51060f0SSean Hefty { 489e51060f0SSean Hefty struct ib_qp_attr qp_attr; 490c8f6a362SSean Hefty int qp_attr_mask, ret; 491e51060f0SSean Hefty 492c8f6a362SSean Hefty qp_attr.qp_state = IB_QPS_INIT; 493c8f6a362SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 494e51060f0SSean Hefty if (ret) 495e51060f0SSean Hefty return ret; 496e51060f0SSean Hefty 497c8f6a362SSean Hefty ret = ib_modify_qp(qp, &qp_attr, qp_attr_mask); 498c8f6a362SSean Hefty if (ret) 499c8f6a362SSean Hefty return ret; 500c8f6a362SSean Hefty 501c8f6a362SSean Hefty qp_attr.qp_state = IB_QPS_RTR; 502c8f6a362SSean Hefty ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE); 503c8f6a362SSean Hefty if (ret) 504c8f6a362SSean Hefty return ret; 505c8f6a362SSean Hefty 506c8f6a362SSean Hefty qp_attr.qp_state = IB_QPS_RTS; 507c8f6a362SSean Hefty qp_attr.sq_psn = 0; 508c8f6a362SSean Hefty ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE | IB_QP_SQ_PSN); 509c8f6a362SSean Hefty 510c8f6a362SSean Hefty return ret; 511e51060f0SSean Hefty } 512e51060f0SSean Hefty 513c8f6a362SSean Hefty static int cma_init_conn_qp(struct rdma_id_private *id_priv, struct ib_qp *qp) 51407ebafbaSTom Tucker { 51507ebafbaSTom Tucker struct ib_qp_attr qp_attr; 516c8f6a362SSean Hefty int qp_attr_mask, ret; 51707ebafbaSTom Tucker 51807ebafbaSTom Tucker qp_attr.qp_state = IB_QPS_INIT; 519c8f6a362SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 520c8f6a362SSean Hefty if (ret) 521c8f6a362SSean Hefty return ret; 52207ebafbaSTom Tucker 523c8f6a362SSean Hefty return ib_modify_qp(qp, &qp_attr, qp_attr_mask); 52407ebafbaSTom Tucker } 52507ebafbaSTom Tucker 526e51060f0SSean Hefty int rdma_create_qp(struct rdma_cm_id *id, struct ib_pd *pd, 527e51060f0SSean Hefty struct ib_qp_init_attr *qp_init_attr) 528e51060f0SSean Hefty { 529e51060f0SSean Hefty struct rdma_id_private *id_priv; 530e51060f0SSean Hefty struct ib_qp *qp; 531e51060f0SSean Hefty int ret; 532e51060f0SSean Hefty 533e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 534e51060f0SSean Hefty if (id->device != pd->device) 535e51060f0SSean Hefty return -EINVAL; 536e51060f0SSean Hefty 537e51060f0SSean Hefty qp = ib_create_qp(pd, qp_init_attr); 538e51060f0SSean Hefty if (IS_ERR(qp)) 539e51060f0SSean Hefty return PTR_ERR(qp); 540e51060f0SSean Hefty 541b26f9b99SSean Hefty if (id->qp_type == IB_QPT_UD) 542c8f6a362SSean Hefty ret = cma_init_ud_qp(id_priv, qp); 543c8f6a362SSean Hefty else 544c8f6a362SSean Hefty ret = cma_init_conn_qp(id_priv, qp); 545e51060f0SSean Hefty if (ret) 546e51060f0SSean Hefty goto err; 547e51060f0SSean Hefty 548e51060f0SSean Hefty id->qp = qp; 549e51060f0SSean Hefty id_priv->qp_num = qp->qp_num; 550e51060f0SSean Hefty id_priv->srq = (qp->srq != NULL); 551e51060f0SSean Hefty return 0; 552e51060f0SSean Hefty err: 553e51060f0SSean Hefty ib_destroy_qp(qp); 554e51060f0SSean Hefty return ret; 555e51060f0SSean Hefty } 556e51060f0SSean Hefty EXPORT_SYMBOL(rdma_create_qp); 557e51060f0SSean Hefty 558e51060f0SSean Hefty void rdma_destroy_qp(struct rdma_cm_id *id) 559e51060f0SSean Hefty { 560c5483388SSean Hefty struct rdma_id_private *id_priv; 561c5483388SSean Hefty 562c5483388SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 563c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 564c5483388SSean Hefty ib_destroy_qp(id_priv->id.qp); 565c5483388SSean Hefty id_priv->id.qp = NULL; 566c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 567e51060f0SSean Hefty } 568e51060f0SSean Hefty EXPORT_SYMBOL(rdma_destroy_qp); 569e51060f0SSean Hefty 5705851bb89SSean Hefty static int cma_modify_qp_rtr(struct rdma_id_private *id_priv, 5715851bb89SSean Hefty struct rdma_conn_param *conn_param) 572e51060f0SSean Hefty { 573e51060f0SSean Hefty struct ib_qp_attr qp_attr; 574e51060f0SSean Hefty int qp_attr_mask, ret; 575e51060f0SSean Hefty 576c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 577c5483388SSean Hefty if (!id_priv->id.qp) { 578c5483388SSean Hefty ret = 0; 579c5483388SSean Hefty goto out; 580c5483388SSean Hefty } 581e51060f0SSean Hefty 582e51060f0SSean Hefty /* Need to update QP attributes from default values. */ 583e51060f0SSean Hefty qp_attr.qp_state = IB_QPS_INIT; 584c5483388SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 585e51060f0SSean Hefty if (ret) 586c5483388SSean Hefty goto out; 587e51060f0SSean Hefty 588c5483388SSean Hefty ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask); 589e51060f0SSean Hefty if (ret) 590c5483388SSean Hefty goto out; 591e51060f0SSean Hefty 592e51060f0SSean Hefty qp_attr.qp_state = IB_QPS_RTR; 593c5483388SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 594e51060f0SSean Hefty if (ret) 595c5483388SSean Hefty goto out; 596e51060f0SSean Hefty 5975851bb89SSean Hefty if (conn_param) 5985851bb89SSean Hefty qp_attr.max_dest_rd_atomic = conn_param->responder_resources; 599c5483388SSean Hefty ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask); 600c5483388SSean Hefty out: 601c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 602c5483388SSean Hefty return ret; 603e51060f0SSean Hefty } 604e51060f0SSean Hefty 6055851bb89SSean Hefty static int cma_modify_qp_rts(struct rdma_id_private *id_priv, 6065851bb89SSean Hefty struct rdma_conn_param *conn_param) 607e51060f0SSean Hefty { 608e51060f0SSean Hefty struct ib_qp_attr qp_attr; 609e51060f0SSean Hefty int qp_attr_mask, ret; 610e51060f0SSean Hefty 611c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 612c5483388SSean Hefty if (!id_priv->id.qp) { 613c5483388SSean Hefty ret = 0; 614c5483388SSean Hefty goto out; 615e51060f0SSean Hefty } 616e51060f0SSean Hefty 617c5483388SSean Hefty qp_attr.qp_state = IB_QPS_RTS; 618c5483388SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 619c5483388SSean Hefty if (ret) 620c5483388SSean Hefty goto out; 621c5483388SSean Hefty 6225851bb89SSean Hefty if (conn_param) 6235851bb89SSean Hefty qp_attr.max_rd_atomic = conn_param->initiator_depth; 624c5483388SSean Hefty ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask); 625c5483388SSean Hefty out: 626c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 627c5483388SSean Hefty return ret; 628c5483388SSean Hefty } 629c5483388SSean Hefty 630c5483388SSean Hefty static int cma_modify_qp_err(struct rdma_id_private *id_priv) 631e51060f0SSean Hefty { 632e51060f0SSean Hefty struct ib_qp_attr qp_attr; 633c5483388SSean Hefty int ret; 634e51060f0SSean Hefty 635c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 636c5483388SSean Hefty if (!id_priv->id.qp) { 637c5483388SSean Hefty ret = 0; 638c5483388SSean Hefty goto out; 639c5483388SSean Hefty } 640e51060f0SSean Hefty 641e51060f0SSean Hefty qp_attr.qp_state = IB_QPS_ERR; 642c5483388SSean Hefty ret = ib_modify_qp(id_priv->id.qp, &qp_attr, IB_QP_STATE); 643c5483388SSean Hefty out: 644c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 645c5483388SSean Hefty return ret; 646e51060f0SSean Hefty } 647e51060f0SSean Hefty 648c8f6a362SSean Hefty static int cma_ib_init_qp_attr(struct rdma_id_private *id_priv, 649c8f6a362SSean Hefty struct ib_qp_attr *qp_attr, int *qp_attr_mask) 650c8f6a362SSean Hefty { 651c8f6a362SSean Hefty struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 652c8f6a362SSean Hefty int ret; 6533c86aa70SEli Cohen u16 pkey; 6543c86aa70SEli Cohen 6553c86aa70SEli Cohen if (rdma_port_get_link_layer(id_priv->id.device, id_priv->id.port_num) == 6563c86aa70SEli Cohen IB_LINK_LAYER_INFINIBAND) 6573c86aa70SEli Cohen pkey = ib_addr_get_pkey(dev_addr); 6583c86aa70SEli Cohen else 6593c86aa70SEli Cohen pkey = 0xffff; 660c8f6a362SSean Hefty 661c8f6a362SSean Hefty ret = ib_find_cached_pkey(id_priv->id.device, id_priv->id.port_num, 6623c86aa70SEli Cohen pkey, &qp_attr->pkey_index); 663c8f6a362SSean Hefty if (ret) 664c8f6a362SSean Hefty return ret; 665c8f6a362SSean Hefty 666c8f6a362SSean Hefty qp_attr->port_num = id_priv->id.port_num; 667c8f6a362SSean Hefty *qp_attr_mask = IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_PORT; 668c8f6a362SSean Hefty 669b26f9b99SSean Hefty if (id_priv->id.qp_type == IB_QPT_UD) { 670d2ca39f2SYossi Etigin ret = cma_set_qkey(id_priv); 671d2ca39f2SYossi Etigin if (ret) 672d2ca39f2SYossi Etigin return ret; 673d2ca39f2SYossi Etigin 674c8f6a362SSean Hefty qp_attr->qkey = id_priv->qkey; 675c8f6a362SSean Hefty *qp_attr_mask |= IB_QP_QKEY; 676c8f6a362SSean Hefty } else { 677c8f6a362SSean Hefty qp_attr->qp_access_flags = 0; 678c8f6a362SSean Hefty *qp_attr_mask |= IB_QP_ACCESS_FLAGS; 679c8f6a362SSean Hefty } 680c8f6a362SSean Hefty return 0; 681c8f6a362SSean Hefty } 682c8f6a362SSean Hefty 683e51060f0SSean Hefty int rdma_init_qp_attr(struct rdma_cm_id *id, struct ib_qp_attr *qp_attr, 684e51060f0SSean Hefty int *qp_attr_mask) 685e51060f0SSean Hefty { 686e51060f0SSean Hefty struct rdma_id_private *id_priv; 687c8f6a362SSean Hefty int ret = 0; 688e51060f0SSean Hefty 689e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 69007ebafbaSTom Tucker switch (rdma_node_get_transport(id_priv->id.device->node_type)) { 69107ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 692b26f9b99SSean Hefty if (!id_priv->cm_id.ib || (id_priv->id.qp_type == IB_QPT_UD)) 693c8f6a362SSean Hefty ret = cma_ib_init_qp_attr(id_priv, qp_attr, qp_attr_mask); 694c8f6a362SSean Hefty else 695e51060f0SSean Hefty ret = ib_cm_init_qp_attr(id_priv->cm_id.ib, qp_attr, 696e51060f0SSean Hefty qp_attr_mask); 697e51060f0SSean Hefty if (qp_attr->qp_state == IB_QPS_RTR) 698e51060f0SSean Hefty qp_attr->rq_psn = id_priv->seq_num; 699e51060f0SSean Hefty break; 70007ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 701c8f6a362SSean Hefty if (!id_priv->cm_id.iw) { 7028f076531SDotan Barak qp_attr->qp_access_flags = 0; 703c8f6a362SSean Hefty *qp_attr_mask = IB_QP_STATE | IB_QP_ACCESS_FLAGS; 704c8f6a362SSean Hefty } else 70507ebafbaSTom Tucker ret = iw_cm_init_qp_attr(id_priv->cm_id.iw, qp_attr, 70607ebafbaSTom Tucker qp_attr_mask); 70707ebafbaSTom Tucker break; 708e51060f0SSean Hefty default: 709e51060f0SSean Hefty ret = -ENOSYS; 710e51060f0SSean Hefty break; 711e51060f0SSean Hefty } 712e51060f0SSean Hefty 713e51060f0SSean Hefty return ret; 714e51060f0SSean Hefty } 715e51060f0SSean Hefty EXPORT_SYMBOL(rdma_init_qp_attr); 716e51060f0SSean Hefty 717e51060f0SSean Hefty static inline int cma_zero_addr(struct sockaddr *addr) 718e51060f0SSean Hefty { 7192e2d190cSSean Hefty switch (addr->sa_family) { 7202e2d190cSSean Hefty case AF_INET: 7212e2d190cSSean Hefty return ipv4_is_zeronet(((struct sockaddr_in *)addr)->sin_addr.s_addr); 7222e2d190cSSean Hefty case AF_INET6: 7232e2d190cSSean Hefty return ipv6_addr_any(&((struct sockaddr_in6 *) addr)->sin6_addr); 7242e2d190cSSean Hefty case AF_IB: 7252e2d190cSSean Hefty return ib_addr_any(&((struct sockaddr_ib *) addr)->sib_addr); 7262e2d190cSSean Hefty default: 7272e2d190cSSean Hefty return 0; 728e51060f0SSean Hefty } 729e51060f0SSean Hefty } 730e51060f0SSean Hefty 731e51060f0SSean Hefty static inline int cma_loopback_addr(struct sockaddr *addr) 732e51060f0SSean Hefty { 7332e2d190cSSean Hefty switch (addr->sa_family) { 7342e2d190cSSean Hefty case AF_INET: 7352e2d190cSSean Hefty return ipv4_is_loopback(((struct sockaddr_in *) addr)->sin_addr.s_addr); 7362e2d190cSSean Hefty case AF_INET6: 7372e2d190cSSean Hefty return ipv6_addr_loopback(&((struct sockaddr_in6 *) addr)->sin6_addr); 7382e2d190cSSean Hefty case AF_IB: 7392e2d190cSSean Hefty return ib_addr_loopback(&((struct sockaddr_ib *) addr)->sib_addr); 7402e2d190cSSean Hefty default: 7412e2d190cSSean Hefty return 0; 7422e2d190cSSean Hefty } 743e51060f0SSean Hefty } 744e51060f0SSean Hefty 745e51060f0SSean Hefty static inline int cma_any_addr(struct sockaddr *addr) 746e51060f0SSean Hefty { 747e51060f0SSean Hefty return cma_zero_addr(addr) || cma_loopback_addr(addr); 748e51060f0SSean Hefty } 749e51060f0SSean Hefty 75043b752daSHefty, Sean static int cma_addr_cmp(struct sockaddr *src, struct sockaddr *dst) 75143b752daSHefty, Sean { 75243b752daSHefty, Sean if (src->sa_family != dst->sa_family) 75343b752daSHefty, Sean return -1; 75443b752daSHefty, Sean 75543b752daSHefty, Sean switch (src->sa_family) { 75643b752daSHefty, Sean case AF_INET: 75743b752daSHefty, Sean return ((struct sockaddr_in *) src)->sin_addr.s_addr != 75843b752daSHefty, Sean ((struct sockaddr_in *) dst)->sin_addr.s_addr; 7592e2d190cSSean Hefty case AF_INET6: 76043b752daSHefty, Sean return ipv6_addr_cmp(&((struct sockaddr_in6 *) src)->sin6_addr, 76143b752daSHefty, Sean &((struct sockaddr_in6 *) dst)->sin6_addr); 7622e2d190cSSean Hefty default: 7632e2d190cSSean Hefty return ib_addr_cmp(&((struct sockaddr_ib *) src)->sib_addr, 7642e2d190cSSean Hefty &((struct sockaddr_ib *) dst)->sib_addr); 76543b752daSHefty, Sean } 76643b752daSHefty, Sean } 76743b752daSHefty, Sean 76858afdcb7SSean Hefty static __be16 cma_port(struct sockaddr *addr) 769628e5f6dSSean Hefty { 77058afdcb7SSean Hefty struct sockaddr_ib *sib; 77158afdcb7SSean Hefty 77258afdcb7SSean Hefty switch (addr->sa_family) { 77358afdcb7SSean Hefty case AF_INET: 774628e5f6dSSean Hefty return ((struct sockaddr_in *) addr)->sin_port; 77558afdcb7SSean Hefty case AF_INET6: 776628e5f6dSSean Hefty return ((struct sockaddr_in6 *) addr)->sin6_port; 77758afdcb7SSean Hefty case AF_IB: 77858afdcb7SSean Hefty sib = (struct sockaddr_ib *) addr; 77958afdcb7SSean Hefty return htons((u16) (be64_to_cpu(sib->sib_sid) & 78058afdcb7SSean Hefty be64_to_cpu(sib->sib_sid_mask))); 78158afdcb7SSean Hefty default: 78258afdcb7SSean Hefty return 0; 78358afdcb7SSean Hefty } 784628e5f6dSSean Hefty } 785628e5f6dSSean Hefty 786e51060f0SSean Hefty static inline int cma_any_port(struct sockaddr *addr) 787e51060f0SSean Hefty { 788628e5f6dSSean Hefty return !cma_port(addr); 789e51060f0SSean Hefty } 790e51060f0SSean Hefty 791e51060f0SSean Hefty static int cma_get_net_info(void *hdr, enum rdma_port_space ps, 7921b90c137SAl Viro u8 *ip_ver, __be16 *port, 793e51060f0SSean Hefty union cma_ip_addr **src, union cma_ip_addr **dst) 794e51060f0SSean Hefty { 795e51060f0SSean Hefty switch (ps) { 796e51060f0SSean Hefty case RDMA_PS_SDP: 797e51060f0SSean Hefty if (sdp_get_majv(((struct sdp_hh *) hdr)->sdp_version) != 798e51060f0SSean Hefty SDP_MAJ_VERSION) 799e51060f0SSean Hefty return -EINVAL; 800e51060f0SSean Hefty 801e51060f0SSean Hefty *ip_ver = sdp_get_ip_ver(hdr); 802e51060f0SSean Hefty *port = ((struct sdp_hh *) hdr)->port; 803e51060f0SSean Hefty *src = &((struct sdp_hh *) hdr)->src_addr; 804e51060f0SSean Hefty *dst = &((struct sdp_hh *) hdr)->dst_addr; 805e51060f0SSean Hefty break; 806e51060f0SSean Hefty default: 807e51060f0SSean Hefty if (((struct cma_hdr *) hdr)->cma_version != CMA_VERSION) 808e51060f0SSean Hefty return -EINVAL; 809e51060f0SSean Hefty 810e51060f0SSean Hefty *ip_ver = cma_get_ip_ver(hdr); 811e51060f0SSean Hefty *port = ((struct cma_hdr *) hdr)->port; 812e51060f0SSean Hefty *src = &((struct cma_hdr *) hdr)->src_addr; 813e51060f0SSean Hefty *dst = &((struct cma_hdr *) hdr)->dst_addr; 814e51060f0SSean Hefty break; 815e51060f0SSean Hefty } 816e51060f0SSean Hefty 817e51060f0SSean Hefty if (*ip_ver != 4 && *ip_ver != 6) 818e51060f0SSean Hefty return -EINVAL; 819e51060f0SSean Hefty return 0; 820e51060f0SSean Hefty } 821e51060f0SSean Hefty 822e51060f0SSean Hefty static void cma_save_net_info(struct rdma_addr *addr, 823e51060f0SSean Hefty struct rdma_addr *listen_addr, 8241b90c137SAl Viro u8 ip_ver, __be16 port, 825e51060f0SSean Hefty union cma_ip_addr *src, union cma_ip_addr *dst) 826e51060f0SSean Hefty { 827e51060f0SSean Hefty struct sockaddr_in *listen4, *ip4; 828e51060f0SSean Hefty struct sockaddr_in6 *listen6, *ip6; 829e51060f0SSean Hefty 830e51060f0SSean Hefty switch (ip_ver) { 831e51060f0SSean Hefty case 4: 832e51060f0SSean Hefty listen4 = (struct sockaddr_in *) &listen_addr->src_addr; 833e51060f0SSean Hefty ip4 = (struct sockaddr_in *) &addr->src_addr; 834e51060f0SSean Hefty ip4->sin_family = listen4->sin_family; 835e51060f0SSean Hefty ip4->sin_addr.s_addr = dst->ip4.addr; 836e51060f0SSean Hefty ip4->sin_port = listen4->sin_port; 837e51060f0SSean Hefty 838e51060f0SSean Hefty ip4 = (struct sockaddr_in *) &addr->dst_addr; 839e51060f0SSean Hefty ip4->sin_family = listen4->sin_family; 840e51060f0SSean Hefty ip4->sin_addr.s_addr = src->ip4.addr; 841e51060f0SSean Hefty ip4->sin_port = port; 842e51060f0SSean Hefty break; 843e51060f0SSean Hefty case 6: 844e51060f0SSean Hefty listen6 = (struct sockaddr_in6 *) &listen_addr->src_addr; 845e51060f0SSean Hefty ip6 = (struct sockaddr_in6 *) &addr->src_addr; 846e51060f0SSean Hefty ip6->sin6_family = listen6->sin6_family; 847e51060f0SSean Hefty ip6->sin6_addr = dst->ip6; 848e51060f0SSean Hefty ip6->sin6_port = listen6->sin6_port; 849e51060f0SSean Hefty 850e51060f0SSean Hefty ip6 = (struct sockaddr_in6 *) &addr->dst_addr; 851e51060f0SSean Hefty ip6->sin6_family = listen6->sin6_family; 852e51060f0SSean Hefty ip6->sin6_addr = src->ip6; 853e51060f0SSean Hefty ip6->sin6_port = port; 854e51060f0SSean Hefty break; 855e51060f0SSean Hefty default: 856e51060f0SSean Hefty break; 857e51060f0SSean Hefty } 858e51060f0SSean Hefty } 859e51060f0SSean Hefty 860e51060f0SSean Hefty static inline int cma_user_data_offset(enum rdma_port_space ps) 861e51060f0SSean Hefty { 862e51060f0SSean Hefty switch (ps) { 863e51060f0SSean Hefty case RDMA_PS_SDP: 864e51060f0SSean Hefty return 0; 865e51060f0SSean Hefty default: 866e51060f0SSean Hefty return sizeof(struct cma_hdr); 867e51060f0SSean Hefty } 868e51060f0SSean Hefty } 869e51060f0SSean Hefty 870e51060f0SSean Hefty static void cma_cancel_route(struct rdma_id_private *id_priv) 871e51060f0SSean Hefty { 8723c86aa70SEli Cohen switch (rdma_port_get_link_layer(id_priv->id.device, id_priv->id.port_num)) { 8733c86aa70SEli Cohen case IB_LINK_LAYER_INFINIBAND: 874e51060f0SSean Hefty if (id_priv->query) 875e51060f0SSean Hefty ib_sa_cancel_query(id_priv->query_id, id_priv->query); 876e51060f0SSean Hefty break; 877e51060f0SSean Hefty default: 878e51060f0SSean Hefty break; 879e51060f0SSean Hefty } 880e51060f0SSean Hefty } 881e51060f0SSean Hefty 882e51060f0SSean Hefty static void cma_cancel_listens(struct rdma_id_private *id_priv) 883e51060f0SSean Hefty { 884e51060f0SSean Hefty struct rdma_id_private *dev_id_priv; 885e51060f0SSean Hefty 886d02d1f53SSean Hefty /* 887d02d1f53SSean Hefty * Remove from listen_any_list to prevent added devices from spawning 888d02d1f53SSean Hefty * additional listen requests. 889d02d1f53SSean Hefty */ 890e51060f0SSean Hefty mutex_lock(&lock); 891e51060f0SSean Hefty list_del(&id_priv->list); 892e51060f0SSean Hefty 893e51060f0SSean Hefty while (!list_empty(&id_priv->listen_list)) { 894e51060f0SSean Hefty dev_id_priv = list_entry(id_priv->listen_list.next, 895e51060f0SSean Hefty struct rdma_id_private, listen_list); 896d02d1f53SSean Hefty /* sync with device removal to avoid duplicate destruction */ 897d02d1f53SSean Hefty list_del_init(&dev_id_priv->list); 898d02d1f53SSean Hefty list_del(&dev_id_priv->listen_list); 899d02d1f53SSean Hefty mutex_unlock(&lock); 900d02d1f53SSean Hefty 901d02d1f53SSean Hefty rdma_destroy_id(&dev_id_priv->id); 902d02d1f53SSean Hefty mutex_lock(&lock); 903e51060f0SSean Hefty } 904e51060f0SSean Hefty mutex_unlock(&lock); 905e51060f0SSean Hefty } 906e51060f0SSean Hefty 907e51060f0SSean Hefty static void cma_cancel_operation(struct rdma_id_private *id_priv, 908550e5ca7SNir Muchtar enum rdma_cm_state state) 909e51060f0SSean Hefty { 910e51060f0SSean Hefty switch (state) { 911550e5ca7SNir Muchtar case RDMA_CM_ADDR_QUERY: 912e51060f0SSean Hefty rdma_addr_cancel(&id_priv->id.route.addr.dev_addr); 913e51060f0SSean Hefty break; 914550e5ca7SNir Muchtar case RDMA_CM_ROUTE_QUERY: 915e51060f0SSean Hefty cma_cancel_route(id_priv); 916e51060f0SSean Hefty break; 917550e5ca7SNir Muchtar case RDMA_CM_LISTEN: 918f4753834SSean Hefty if (cma_any_addr(cma_src_addr(id_priv)) && !id_priv->cma_dev) 919e51060f0SSean Hefty cma_cancel_listens(id_priv); 920e51060f0SSean Hefty break; 921e51060f0SSean Hefty default: 922e51060f0SSean Hefty break; 923e51060f0SSean Hefty } 924e51060f0SSean Hefty } 925e51060f0SSean Hefty 926e51060f0SSean Hefty static void cma_release_port(struct rdma_id_private *id_priv) 927e51060f0SSean Hefty { 928e51060f0SSean Hefty struct rdma_bind_list *bind_list = id_priv->bind_list; 929e51060f0SSean Hefty 930e51060f0SSean Hefty if (!bind_list) 931e51060f0SSean Hefty return; 932e51060f0SSean Hefty 933e51060f0SSean Hefty mutex_lock(&lock); 934e51060f0SSean Hefty hlist_del(&id_priv->node); 935e51060f0SSean Hefty if (hlist_empty(&bind_list->owners)) { 936e51060f0SSean Hefty idr_remove(bind_list->ps, bind_list->port); 937e51060f0SSean Hefty kfree(bind_list); 938e51060f0SSean Hefty } 939e51060f0SSean Hefty mutex_unlock(&lock); 940e51060f0SSean Hefty } 941e51060f0SSean Hefty 942c8f6a362SSean Hefty static void cma_leave_mc_groups(struct rdma_id_private *id_priv) 943c8f6a362SSean Hefty { 944c8f6a362SSean Hefty struct cma_multicast *mc; 945c8f6a362SSean Hefty 946c8f6a362SSean Hefty while (!list_empty(&id_priv->mc_list)) { 947c8f6a362SSean Hefty mc = container_of(id_priv->mc_list.next, 948c8f6a362SSean Hefty struct cma_multicast, list); 949c8f6a362SSean Hefty list_del(&mc->list); 9503c86aa70SEli Cohen switch (rdma_port_get_link_layer(id_priv->cma_dev->device, id_priv->id.port_num)) { 9513c86aa70SEli Cohen case IB_LINK_LAYER_INFINIBAND: 952c8f6a362SSean Hefty ib_sa_free_multicast(mc->multicast.ib); 953c8f6a362SSean Hefty kfree(mc); 9543c86aa70SEli Cohen break; 9553c86aa70SEli Cohen case IB_LINK_LAYER_ETHERNET: 9563c86aa70SEli Cohen kref_put(&mc->mcref, release_mc); 9573c86aa70SEli Cohen break; 9583c86aa70SEli Cohen default: 9593c86aa70SEli Cohen break; 9603c86aa70SEli Cohen } 961c8f6a362SSean Hefty } 962c8f6a362SSean Hefty } 963c8f6a362SSean Hefty 964e51060f0SSean Hefty void rdma_destroy_id(struct rdma_cm_id *id) 965e51060f0SSean Hefty { 966e51060f0SSean Hefty struct rdma_id_private *id_priv; 967550e5ca7SNir Muchtar enum rdma_cm_state state; 968e51060f0SSean Hefty 969e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 970550e5ca7SNir Muchtar state = cma_exch(id_priv, RDMA_CM_DESTROYING); 971e51060f0SSean Hefty cma_cancel_operation(id_priv, state); 972e51060f0SSean Hefty 973a396d43aSSean Hefty /* 974a396d43aSSean Hefty * Wait for any active callback to finish. New callbacks will find 975a396d43aSSean Hefty * the id_priv state set to destroying and abort. 976a396d43aSSean Hefty */ 977a396d43aSSean Hefty mutex_lock(&id_priv->handler_mutex); 978a396d43aSSean Hefty mutex_unlock(&id_priv->handler_mutex); 979a396d43aSSean Hefty 980e51060f0SSean Hefty if (id_priv->cma_dev) { 9813c86aa70SEli Cohen switch (rdma_node_get_transport(id_priv->id.device->node_type)) { 98207ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 9830c9361fcSJack Morgenstein if (id_priv->cm_id.ib) 984e51060f0SSean Hefty ib_destroy_cm_id(id_priv->cm_id.ib); 985e51060f0SSean Hefty break; 98607ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 9870c9361fcSJack Morgenstein if (id_priv->cm_id.iw) 98807ebafbaSTom Tucker iw_destroy_cm_id(id_priv->cm_id.iw); 98907ebafbaSTom Tucker break; 990e51060f0SSean Hefty default: 991e51060f0SSean Hefty break; 992e51060f0SSean Hefty } 993c8f6a362SSean Hefty cma_leave_mc_groups(id_priv); 994a396d43aSSean Hefty cma_release_dev(id_priv); 995e51060f0SSean Hefty } 996e51060f0SSean Hefty 997e51060f0SSean Hefty cma_release_port(id_priv); 998e51060f0SSean Hefty cma_deref_id(id_priv); 999e51060f0SSean Hefty wait_for_completion(&id_priv->comp); 1000e51060f0SSean Hefty 1001d02d1f53SSean Hefty if (id_priv->internal_id) 1002d02d1f53SSean Hefty cma_deref_id(id_priv->id.context); 1003d02d1f53SSean Hefty 1004e51060f0SSean Hefty kfree(id_priv->id.route.path_rec); 1005e51060f0SSean Hefty kfree(id_priv); 1006e51060f0SSean Hefty } 1007e51060f0SSean Hefty EXPORT_SYMBOL(rdma_destroy_id); 1008e51060f0SSean Hefty 1009e51060f0SSean Hefty static int cma_rep_recv(struct rdma_id_private *id_priv) 1010e51060f0SSean Hefty { 1011e51060f0SSean Hefty int ret; 1012e51060f0SSean Hefty 10135851bb89SSean Hefty ret = cma_modify_qp_rtr(id_priv, NULL); 1014e51060f0SSean Hefty if (ret) 1015e51060f0SSean Hefty goto reject; 1016e51060f0SSean Hefty 10175851bb89SSean Hefty ret = cma_modify_qp_rts(id_priv, NULL); 1018e51060f0SSean Hefty if (ret) 1019e51060f0SSean Hefty goto reject; 1020e51060f0SSean Hefty 1021e51060f0SSean Hefty ret = ib_send_cm_rtu(id_priv->cm_id.ib, NULL, 0); 1022e51060f0SSean Hefty if (ret) 1023e51060f0SSean Hefty goto reject; 1024e51060f0SSean Hefty 1025e51060f0SSean Hefty return 0; 1026e51060f0SSean Hefty reject: 1027c5483388SSean Hefty cma_modify_qp_err(id_priv); 1028e51060f0SSean Hefty ib_send_cm_rej(id_priv->cm_id.ib, IB_CM_REJ_CONSUMER_DEFINED, 1029e51060f0SSean Hefty NULL, 0, NULL, 0); 1030e51060f0SSean Hefty return ret; 1031e51060f0SSean Hefty } 1032e51060f0SSean Hefty 1033e51060f0SSean Hefty static int cma_verify_rep(struct rdma_id_private *id_priv, void *data) 1034e51060f0SSean Hefty { 1035e51060f0SSean Hefty if (id_priv->id.ps == RDMA_PS_SDP && 1036e51060f0SSean Hefty sdp_get_majv(((struct sdp_hah *) data)->sdp_version) != 1037e51060f0SSean Hefty SDP_MAJ_VERSION) 1038e51060f0SSean Hefty return -EINVAL; 1039e51060f0SSean Hefty 1040e51060f0SSean Hefty return 0; 1041e51060f0SSean Hefty } 1042e51060f0SSean Hefty 1043a1b1b61fSSean Hefty static void cma_set_rep_event_data(struct rdma_cm_event *event, 1044a1b1b61fSSean Hefty struct ib_cm_rep_event_param *rep_data, 1045a1b1b61fSSean Hefty void *private_data) 1046a1b1b61fSSean Hefty { 1047a1b1b61fSSean Hefty event->param.conn.private_data = private_data; 1048a1b1b61fSSean Hefty event->param.conn.private_data_len = IB_CM_REP_PRIVATE_DATA_SIZE; 1049a1b1b61fSSean Hefty event->param.conn.responder_resources = rep_data->responder_resources; 1050a1b1b61fSSean Hefty event->param.conn.initiator_depth = rep_data->initiator_depth; 1051a1b1b61fSSean Hefty event->param.conn.flow_control = rep_data->flow_control; 1052a1b1b61fSSean Hefty event->param.conn.rnr_retry_count = rep_data->rnr_retry_count; 1053a1b1b61fSSean Hefty event->param.conn.srq = rep_data->srq; 1054a1b1b61fSSean Hefty event->param.conn.qp_num = rep_data->remote_qpn; 1055a1b1b61fSSean Hefty } 1056a1b1b61fSSean Hefty 1057e51060f0SSean Hefty static int cma_ib_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event) 1058e51060f0SSean Hefty { 1059e51060f0SSean Hefty struct rdma_id_private *id_priv = cm_id->context; 1060a1b1b61fSSean Hefty struct rdma_cm_event event; 1061a1b1b61fSSean Hefty int ret = 0; 1062e51060f0SSean Hefty 106338ca83a5SAmir Vadai if ((ib_event->event != IB_CM_TIMEWAIT_EXIT && 1064550e5ca7SNir Muchtar cma_disable_callback(id_priv, RDMA_CM_CONNECT)) || 106538ca83a5SAmir Vadai (ib_event->event == IB_CM_TIMEWAIT_EXIT && 1066550e5ca7SNir Muchtar cma_disable_callback(id_priv, RDMA_CM_DISCONNECT))) 10678aa08602SSean Hefty return 0; 1068e51060f0SSean Hefty 1069a1b1b61fSSean Hefty memset(&event, 0, sizeof event); 1070e51060f0SSean Hefty switch (ib_event->event) { 1071e51060f0SSean Hefty case IB_CM_REQ_ERROR: 1072e51060f0SSean Hefty case IB_CM_REP_ERROR: 1073a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_UNREACHABLE; 1074a1b1b61fSSean Hefty event.status = -ETIMEDOUT; 1075e51060f0SSean Hefty break; 1076e51060f0SSean Hefty case IB_CM_REP_RECEIVED: 1077a1b1b61fSSean Hefty event.status = cma_verify_rep(id_priv, ib_event->private_data); 1078a1b1b61fSSean Hefty if (event.status) 1079a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_CONNECT_ERROR; 1080e51060f0SSean Hefty else if (id_priv->id.qp && id_priv->id.ps != RDMA_PS_SDP) { 1081a1b1b61fSSean Hefty event.status = cma_rep_recv(id_priv); 1082a1b1b61fSSean Hefty event.event = event.status ? RDMA_CM_EVENT_CONNECT_ERROR : 1083e51060f0SSean Hefty RDMA_CM_EVENT_ESTABLISHED; 1084e51060f0SSean Hefty } else 1085a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_CONNECT_RESPONSE; 1086a1b1b61fSSean Hefty cma_set_rep_event_data(&event, &ib_event->param.rep_rcvd, 1087a1b1b61fSSean Hefty ib_event->private_data); 1088e51060f0SSean Hefty break; 1089e51060f0SSean Hefty case IB_CM_RTU_RECEIVED: 10900fe313b0SSean Hefty case IB_CM_USER_ESTABLISHED: 10910fe313b0SSean Hefty event.event = RDMA_CM_EVENT_ESTABLISHED; 1092e51060f0SSean Hefty break; 1093e51060f0SSean Hefty case IB_CM_DREQ_ERROR: 1094a1b1b61fSSean Hefty event.status = -ETIMEDOUT; /* fall through */ 1095e51060f0SSean Hefty case IB_CM_DREQ_RECEIVED: 1096e51060f0SSean Hefty case IB_CM_DREP_RECEIVED: 1097550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_CONNECT, 1098550e5ca7SNir Muchtar RDMA_CM_DISCONNECT)) 1099e51060f0SSean Hefty goto out; 1100a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_DISCONNECTED; 1101e51060f0SSean Hefty break; 1102e51060f0SSean Hefty case IB_CM_TIMEWAIT_EXIT: 110338ca83a5SAmir Vadai event.event = RDMA_CM_EVENT_TIMEWAIT_EXIT; 110438ca83a5SAmir Vadai break; 1105e51060f0SSean Hefty case IB_CM_MRA_RECEIVED: 1106e51060f0SSean Hefty /* ignore event */ 1107e51060f0SSean Hefty goto out; 1108e51060f0SSean Hefty case IB_CM_REJ_RECEIVED: 1109c5483388SSean Hefty cma_modify_qp_err(id_priv); 1110a1b1b61fSSean Hefty event.status = ib_event->param.rej_rcvd.reason; 1111a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_REJECTED; 1112a1b1b61fSSean Hefty event.param.conn.private_data = ib_event->private_data; 1113a1b1b61fSSean Hefty event.param.conn.private_data_len = IB_CM_REJ_PRIVATE_DATA_SIZE; 1114e51060f0SSean Hefty break; 1115e51060f0SSean Hefty default: 1116468f2239SRoland Dreier printk(KERN_ERR "RDMA CMA: unexpected IB CM event: %d\n", 1117e51060f0SSean Hefty ib_event->event); 1118e51060f0SSean Hefty goto out; 1119e51060f0SSean Hefty } 1120e51060f0SSean Hefty 1121a1b1b61fSSean Hefty ret = id_priv->id.event_handler(&id_priv->id, &event); 1122e51060f0SSean Hefty if (ret) { 1123e51060f0SSean Hefty /* Destroy the CM ID by returning a non-zero value. */ 1124e51060f0SSean Hefty id_priv->cm_id.ib = NULL; 1125550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 1126de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 1127e51060f0SSean Hefty rdma_destroy_id(&id_priv->id); 1128e51060f0SSean Hefty return ret; 1129e51060f0SSean Hefty } 1130e51060f0SSean Hefty out: 1131de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 1132e51060f0SSean Hefty return ret; 1133e51060f0SSean Hefty } 1134e51060f0SSean Hefty 1135628e5f6dSSean Hefty static struct rdma_id_private *cma_new_conn_id(struct rdma_cm_id *listen_id, 1136e51060f0SSean Hefty struct ib_cm_event *ib_event) 1137e51060f0SSean Hefty { 1138e51060f0SSean Hefty struct rdma_id_private *id_priv; 1139e51060f0SSean Hefty struct rdma_cm_id *id; 1140e51060f0SSean Hefty struct rdma_route *rt; 1141e51060f0SSean Hefty union cma_ip_addr *src, *dst; 11421b90c137SAl Viro __be16 port; 1143e51060f0SSean Hefty u8 ip_ver; 114464c5e613SOr Gerlitz int ret; 1145e51060f0SSean Hefty 1146e51060f0SSean Hefty if (cma_get_net_info(ib_event->private_data, listen_id->ps, 1147e51060f0SSean Hefty &ip_ver, &port, &src, &dst)) 11480c9361fcSJack Morgenstein return NULL; 1149e51060f0SSean Hefty 11503f168d2bSKrishna Kumar id = rdma_create_id(listen_id->event_handler, listen_id->context, 1151b26f9b99SSean Hefty listen_id->ps, ib_event->param.req_rcvd.qp_type); 11523f168d2bSKrishna Kumar if (IS_ERR(id)) 11530c9361fcSJack Morgenstein return NULL; 11543f168d2bSKrishna Kumar 1155f4753834SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1156e51060f0SSean Hefty cma_save_net_info(&id->route.addr, &listen_id->route.addr, 1157e51060f0SSean Hefty ip_ver, port, src, dst); 11583f168d2bSKrishna Kumar 11593f168d2bSKrishna Kumar rt = &id->route; 11603f168d2bSKrishna Kumar rt->num_paths = ib_event->param.req_rcvd.alternate_path ? 2 : 1; 11613f168d2bSKrishna Kumar rt->path_rec = kmalloc(sizeof *rt->path_rec * rt->num_paths, 11623f168d2bSKrishna Kumar GFP_KERNEL); 11633f168d2bSKrishna Kumar if (!rt->path_rec) 11640c9361fcSJack Morgenstein goto err; 11653f168d2bSKrishna Kumar 1166e51060f0SSean Hefty rt->path_rec[0] = *ib_event->param.req_rcvd.primary_path; 1167e51060f0SSean Hefty if (rt->num_paths == 2) 1168e51060f0SSean Hefty rt->path_rec[1] = *ib_event->param.req_rcvd.alternate_path; 1169e51060f0SSean Hefty 1170f4753834SSean Hefty if (cma_any_addr(cma_src_addr(id_priv))) { 11716f8372b6SSean Hefty rt->addr.dev_addr.dev_type = ARPHRD_INFINIBAND; 11726f8372b6SSean Hefty rdma_addr_set_sgid(&rt->addr.dev_addr, &rt->path_rec[0].sgid); 117346ea5061SSean Hefty ib_addr_set_pkey(&rt->addr.dev_addr, be16_to_cpu(rt->path_rec[0].pkey)); 11746f8372b6SSean Hefty } else { 1175f4753834SSean Hefty ret = cma_translate_addr(cma_src_addr(id_priv), &rt->addr.dev_addr); 117664c5e613SOr Gerlitz if (ret) 11770c9361fcSJack Morgenstein goto err; 11786f8372b6SSean Hefty } 11796f8372b6SSean Hefty rdma_addr_set_dgid(&rt->addr.dev_addr, &rt->path_rec[0].dgid); 1180e51060f0SSean Hefty 1181550e5ca7SNir Muchtar id_priv->state = RDMA_CM_CONNECT; 1182e51060f0SSean Hefty return id_priv; 11833f168d2bSKrishna Kumar 11843f168d2bSKrishna Kumar err: 11850c9361fcSJack Morgenstein rdma_destroy_id(id); 1186e51060f0SSean Hefty return NULL; 1187e51060f0SSean Hefty } 1188e51060f0SSean Hefty 1189628e5f6dSSean Hefty static struct rdma_id_private *cma_new_udp_id(struct rdma_cm_id *listen_id, 1190628e5f6dSSean Hefty struct ib_cm_event *ib_event) 1191628e5f6dSSean Hefty { 1192628e5f6dSSean Hefty struct rdma_id_private *id_priv; 1193628e5f6dSSean Hefty struct rdma_cm_id *id; 1194628e5f6dSSean Hefty union cma_ip_addr *src, *dst; 11951b90c137SAl Viro __be16 port; 1196628e5f6dSSean Hefty u8 ip_ver; 1197628e5f6dSSean Hefty int ret; 1198628e5f6dSSean Hefty 1199628e5f6dSSean Hefty id = rdma_create_id(listen_id->event_handler, listen_id->context, 1200b26f9b99SSean Hefty listen_id->ps, IB_QPT_UD); 1201628e5f6dSSean Hefty if (IS_ERR(id)) 1202628e5f6dSSean Hefty return NULL; 1203628e5f6dSSean Hefty 1204f4753834SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1205628e5f6dSSean Hefty if (cma_get_net_info(ib_event->private_data, listen_id->ps, 1206628e5f6dSSean Hefty &ip_ver, &port, &src, &dst)) 1207628e5f6dSSean Hefty goto err; 1208628e5f6dSSean Hefty 1209628e5f6dSSean Hefty cma_save_net_info(&id->route.addr, &listen_id->route.addr, 1210628e5f6dSSean Hefty ip_ver, port, src, dst); 1211628e5f6dSSean Hefty 12126f8372b6SSean Hefty if (!cma_any_addr((struct sockaddr *) &id->route.addr.src_addr)) { 1213f4753834SSean Hefty ret = cma_translate_addr(cma_src_addr(id_priv), &id->route.addr.dev_addr); 1214628e5f6dSSean Hefty if (ret) 1215628e5f6dSSean Hefty goto err; 12166f8372b6SSean Hefty } 1217628e5f6dSSean Hefty 1218550e5ca7SNir Muchtar id_priv->state = RDMA_CM_CONNECT; 1219628e5f6dSSean Hefty return id_priv; 1220628e5f6dSSean Hefty err: 1221628e5f6dSSean Hefty rdma_destroy_id(id); 1222628e5f6dSSean Hefty return NULL; 1223628e5f6dSSean Hefty } 1224628e5f6dSSean Hefty 1225a1b1b61fSSean Hefty static void cma_set_req_event_data(struct rdma_cm_event *event, 1226a1b1b61fSSean Hefty struct ib_cm_req_event_param *req_data, 1227a1b1b61fSSean Hefty void *private_data, int offset) 1228a1b1b61fSSean Hefty { 1229a1b1b61fSSean Hefty event->param.conn.private_data = private_data + offset; 1230a1b1b61fSSean Hefty event->param.conn.private_data_len = IB_CM_REQ_PRIVATE_DATA_SIZE - offset; 1231a1b1b61fSSean Hefty event->param.conn.responder_resources = req_data->responder_resources; 1232a1b1b61fSSean Hefty event->param.conn.initiator_depth = req_data->initiator_depth; 1233a1b1b61fSSean Hefty event->param.conn.flow_control = req_data->flow_control; 1234a1b1b61fSSean Hefty event->param.conn.retry_count = req_data->retry_count; 1235a1b1b61fSSean Hefty event->param.conn.rnr_retry_count = req_data->rnr_retry_count; 1236a1b1b61fSSean Hefty event->param.conn.srq = req_data->srq; 1237a1b1b61fSSean Hefty event->param.conn.qp_num = req_data->remote_qpn; 1238a1b1b61fSSean Hefty } 1239a1b1b61fSSean Hefty 12409595480cSHefty, Sean static int cma_check_req_qp_type(struct rdma_cm_id *id, struct ib_cm_event *ib_event) 12419595480cSHefty, Sean { 12424dd81e89SSean Hefty return (((ib_event->event == IB_CM_REQ_RECEIVED) && 12439595480cSHefty, Sean (ib_event->param.req_rcvd.qp_type == id->qp_type)) || 12449595480cSHefty, Sean ((ib_event->event == IB_CM_SIDR_REQ_RECEIVED) && 12459595480cSHefty, Sean (id->qp_type == IB_QPT_UD)) || 12469595480cSHefty, Sean (!id->qp_type)); 12479595480cSHefty, Sean } 12489595480cSHefty, Sean 1249e51060f0SSean Hefty static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event) 1250e51060f0SSean Hefty { 1251e51060f0SSean Hefty struct rdma_id_private *listen_id, *conn_id; 1252a1b1b61fSSean Hefty struct rdma_cm_event event; 1253e51060f0SSean Hefty int offset, ret; 1254e51060f0SSean Hefty 1255e51060f0SSean Hefty listen_id = cm_id->context; 12569595480cSHefty, Sean if (!cma_check_req_qp_type(&listen_id->id, ib_event)) 12579595480cSHefty, Sean return -EINVAL; 12589595480cSHefty, Sean 1259550e5ca7SNir Muchtar if (cma_disable_callback(listen_id, RDMA_CM_LISTEN)) 12608aa08602SSean Hefty return -ECONNABORTED; 1261e51060f0SSean Hefty 1262628e5f6dSSean Hefty memset(&event, 0, sizeof event); 1263628e5f6dSSean Hefty offset = cma_user_data_offset(listen_id->id.ps); 1264628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_CONNECT_REQUEST; 12659595480cSHefty, Sean if (ib_event->event == IB_CM_SIDR_REQ_RECEIVED) { 1266628e5f6dSSean Hefty conn_id = cma_new_udp_id(&listen_id->id, ib_event); 1267628e5f6dSSean Hefty event.param.ud.private_data = ib_event->private_data + offset; 1268628e5f6dSSean Hefty event.param.ud.private_data_len = 1269628e5f6dSSean Hefty IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE - offset; 1270628e5f6dSSean Hefty } else { 1271628e5f6dSSean Hefty conn_id = cma_new_conn_id(&listen_id->id, ib_event); 1272628e5f6dSSean Hefty cma_set_req_event_data(&event, &ib_event->param.req_rcvd, 1273628e5f6dSSean Hefty ib_event->private_data, offset); 1274628e5f6dSSean Hefty } 1275e51060f0SSean Hefty if (!conn_id) { 1276e51060f0SSean Hefty ret = -ENOMEM; 1277b6cec8aaSSean Hefty goto err1; 1278e51060f0SSean Hefty } 1279e51060f0SSean Hefty 1280de910bd9SOr Gerlitz mutex_lock_nested(&conn_id->handler_mutex, SINGLE_DEPTH_NESTING); 128107ebafbaSTom Tucker ret = cma_acquire_dev(conn_id); 1282a1a733f6SKrishna Kumar if (ret) 1283b6cec8aaSSean Hefty goto err2; 1284e51060f0SSean Hefty 1285e51060f0SSean Hefty conn_id->cm_id.ib = cm_id; 1286e51060f0SSean Hefty cm_id->context = conn_id; 1287e51060f0SSean Hefty cm_id->cm_handler = cma_ib_handler; 1288e51060f0SSean Hefty 128925ae21a1SSean Hefty /* 129025ae21a1SSean Hefty * Protect against the user destroying conn_id from another thread 129125ae21a1SSean Hefty * until we're done accessing it. 129225ae21a1SSean Hefty */ 129325ae21a1SSean Hefty atomic_inc(&conn_id->refcount); 1294a1b1b61fSSean Hefty ret = conn_id->id.event_handler(&conn_id->id, &event); 1295b6cec8aaSSean Hefty if (ret) 1296b6cec8aaSSean Hefty goto err3; 1297b6cec8aaSSean Hefty 1298ead595aeSSean Hefty /* 1299ead595aeSSean Hefty * Acquire mutex to prevent user executing rdma_destroy_id() 1300ead595aeSSean Hefty * while we're accessing the cm_id. 1301ead595aeSSean Hefty */ 1302ead595aeSSean Hefty mutex_lock(&lock); 1303b26f9b99SSean Hefty if (cma_comp(conn_id, RDMA_CM_CONNECT) && (conn_id->id.qp_type != IB_QPT_UD)) 1304ead595aeSSean Hefty ib_send_cm_mra(cm_id, CMA_CM_MRA_SETTING, NULL, 0); 1305ead595aeSSean Hefty mutex_unlock(&lock); 1306de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 1307b6cec8aaSSean Hefty mutex_unlock(&listen_id->handler_mutex); 130825ae21a1SSean Hefty cma_deref_id(conn_id); 1309b6cec8aaSSean Hefty return 0; 1310a1a733f6SKrishna Kumar 1311b6cec8aaSSean Hefty err3: 1312b6cec8aaSSean Hefty cma_deref_id(conn_id); 1313e51060f0SSean Hefty /* Destroy the CM ID by returning a non-zero value. */ 1314e51060f0SSean Hefty conn_id->cm_id.ib = NULL; 1315b6cec8aaSSean Hefty err2: 1316550e5ca7SNir Muchtar cma_exch(conn_id, RDMA_CM_DESTROYING); 1317de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 1318b6cec8aaSSean Hefty err1: 1319de910bd9SOr Gerlitz mutex_unlock(&listen_id->handler_mutex); 1320b6cec8aaSSean Hefty if (conn_id) 1321b6cec8aaSSean Hefty rdma_destroy_id(&conn_id->id); 1322e51060f0SSean Hefty return ret; 1323e51060f0SSean Hefty } 1324e51060f0SSean Hefty 1325e51060f0SSean Hefty static __be64 cma_get_service_id(enum rdma_port_space ps, struct sockaddr *addr) 1326e51060f0SSean Hefty { 1327628e5f6dSSean Hefty return cpu_to_be64(((u64)ps << 16) + be16_to_cpu(cma_port(addr))); 1328e51060f0SSean Hefty } 1329e51060f0SSean Hefty 1330e51060f0SSean Hefty static void cma_set_compare_data(enum rdma_port_space ps, struct sockaddr *addr, 1331e51060f0SSean Hefty struct ib_cm_compare_data *compare) 1332e51060f0SSean Hefty { 1333e51060f0SSean Hefty struct cma_hdr *cma_data, *cma_mask; 1334e51060f0SSean Hefty struct sdp_hh *sdp_data, *sdp_mask; 13351b90c137SAl Viro __be32 ip4_addr; 1336e51060f0SSean Hefty struct in6_addr ip6_addr; 1337e51060f0SSean Hefty 1338e51060f0SSean Hefty memset(compare, 0, sizeof *compare); 1339e51060f0SSean Hefty cma_data = (void *) compare->data; 1340e51060f0SSean Hefty cma_mask = (void *) compare->mask; 1341e51060f0SSean Hefty sdp_data = (void *) compare->data; 1342e51060f0SSean Hefty sdp_mask = (void *) compare->mask; 1343e51060f0SSean Hefty 1344e51060f0SSean Hefty switch (addr->sa_family) { 1345e51060f0SSean Hefty case AF_INET: 1346e51060f0SSean Hefty ip4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr; 1347e51060f0SSean Hefty if (ps == RDMA_PS_SDP) { 1348e51060f0SSean Hefty sdp_set_ip_ver(sdp_data, 4); 1349e51060f0SSean Hefty sdp_set_ip_ver(sdp_mask, 0xF); 1350e51060f0SSean Hefty sdp_data->dst_addr.ip4.addr = ip4_addr; 13511b90c137SAl Viro sdp_mask->dst_addr.ip4.addr = htonl(~0); 1352e51060f0SSean Hefty } else { 1353e51060f0SSean Hefty cma_set_ip_ver(cma_data, 4); 1354e51060f0SSean Hefty cma_set_ip_ver(cma_mask, 0xF); 1355406b6a25SSean Hefty if (!cma_any_addr(addr)) { 1356e51060f0SSean Hefty cma_data->dst_addr.ip4.addr = ip4_addr; 13571b90c137SAl Viro cma_mask->dst_addr.ip4.addr = htonl(~0); 1358e51060f0SSean Hefty } 1359406b6a25SSean Hefty } 1360e51060f0SSean Hefty break; 1361e51060f0SSean Hefty case AF_INET6: 1362e51060f0SSean Hefty ip6_addr = ((struct sockaddr_in6 *) addr)->sin6_addr; 1363e51060f0SSean Hefty if (ps == RDMA_PS_SDP) { 1364e51060f0SSean Hefty sdp_set_ip_ver(sdp_data, 6); 1365e51060f0SSean Hefty sdp_set_ip_ver(sdp_mask, 0xF); 1366e51060f0SSean Hefty sdp_data->dst_addr.ip6 = ip6_addr; 1367e51060f0SSean Hefty memset(&sdp_mask->dst_addr.ip6, 0xFF, 1368e51060f0SSean Hefty sizeof sdp_mask->dst_addr.ip6); 1369e51060f0SSean Hefty } else { 1370e51060f0SSean Hefty cma_set_ip_ver(cma_data, 6); 1371e51060f0SSean Hefty cma_set_ip_ver(cma_mask, 0xF); 1372406b6a25SSean Hefty if (!cma_any_addr(addr)) { 1373e51060f0SSean Hefty cma_data->dst_addr.ip6 = ip6_addr; 1374e51060f0SSean Hefty memset(&cma_mask->dst_addr.ip6, 0xFF, 1375e51060f0SSean Hefty sizeof cma_mask->dst_addr.ip6); 1376e51060f0SSean Hefty } 1377406b6a25SSean Hefty } 1378e51060f0SSean Hefty break; 1379e51060f0SSean Hefty default: 1380e51060f0SSean Hefty break; 1381e51060f0SSean Hefty } 1382e51060f0SSean Hefty } 1383e51060f0SSean Hefty 138407ebafbaSTom Tucker static int cma_iw_handler(struct iw_cm_id *iw_id, struct iw_cm_event *iw_event) 138507ebafbaSTom Tucker { 138607ebafbaSTom Tucker struct rdma_id_private *id_priv = iw_id->context; 1387a1b1b61fSSean Hefty struct rdma_cm_event event; 138807ebafbaSTom Tucker struct sockaddr_in *sin; 138907ebafbaSTom Tucker int ret = 0; 139007ebafbaSTom Tucker 1391550e5ca7SNir Muchtar if (cma_disable_callback(id_priv, RDMA_CM_CONNECT)) 1392be65f086SSean Hefty return 0; 139307ebafbaSTom Tucker 1394be65f086SSean Hefty memset(&event, 0, sizeof event); 139507ebafbaSTom Tucker switch (iw_event->event) { 139607ebafbaSTom Tucker case IW_CM_EVENT_CLOSE: 1397a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_DISCONNECTED; 139807ebafbaSTom Tucker break; 139907ebafbaSTom Tucker case IW_CM_EVENT_CONNECT_REPLY: 1400f4753834SSean Hefty sin = (struct sockaddr_in *) cma_src_addr(id_priv); 140107ebafbaSTom Tucker *sin = iw_event->local_addr; 1402f4753834SSean Hefty sin = (struct sockaddr_in *) cma_dst_addr(id_priv); 140307ebafbaSTom Tucker *sin = iw_event->remote_addr; 1404881a045fSSteve Wise switch (iw_event->status) { 1405881a045fSSteve Wise case 0: 1406a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_ESTABLISHED; 14073ebeebc3SKumar Sanghvi event.param.conn.initiator_depth = iw_event->ird; 14083ebeebc3SKumar Sanghvi event.param.conn.responder_resources = iw_event->ord; 140907ebafbaSTom Tucker break; 1410881a045fSSteve Wise case -ECONNRESET: 1411881a045fSSteve Wise case -ECONNREFUSED: 1412881a045fSSteve Wise event.event = RDMA_CM_EVENT_REJECTED; 1413881a045fSSteve Wise break; 1414881a045fSSteve Wise case -ETIMEDOUT: 1415881a045fSSteve Wise event.event = RDMA_CM_EVENT_UNREACHABLE; 1416881a045fSSteve Wise break; 1417881a045fSSteve Wise default: 1418881a045fSSteve Wise event.event = RDMA_CM_EVENT_CONNECT_ERROR; 1419881a045fSSteve Wise break; 1420881a045fSSteve Wise } 1421881a045fSSteve Wise break; 142207ebafbaSTom Tucker case IW_CM_EVENT_ESTABLISHED: 1423a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_ESTABLISHED; 14243ebeebc3SKumar Sanghvi event.param.conn.initiator_depth = iw_event->ird; 14253ebeebc3SKumar Sanghvi event.param.conn.responder_resources = iw_event->ord; 142607ebafbaSTom Tucker break; 142707ebafbaSTom Tucker default: 142807ebafbaSTom Tucker BUG_ON(1); 142907ebafbaSTom Tucker } 143007ebafbaSTom Tucker 1431a1b1b61fSSean Hefty event.status = iw_event->status; 1432a1b1b61fSSean Hefty event.param.conn.private_data = iw_event->private_data; 1433a1b1b61fSSean Hefty event.param.conn.private_data_len = iw_event->private_data_len; 1434a1b1b61fSSean Hefty ret = id_priv->id.event_handler(&id_priv->id, &event); 143507ebafbaSTom Tucker if (ret) { 143607ebafbaSTom Tucker /* Destroy the CM ID by returning a non-zero value. */ 143707ebafbaSTom Tucker id_priv->cm_id.iw = NULL; 1438550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 1439de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 144007ebafbaSTom Tucker rdma_destroy_id(&id_priv->id); 144107ebafbaSTom Tucker return ret; 144207ebafbaSTom Tucker } 144307ebafbaSTom Tucker 1444de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 144507ebafbaSTom Tucker return ret; 144607ebafbaSTom Tucker } 144707ebafbaSTom Tucker 144807ebafbaSTom Tucker static int iw_conn_req_handler(struct iw_cm_id *cm_id, 144907ebafbaSTom Tucker struct iw_cm_event *iw_event) 145007ebafbaSTom Tucker { 145107ebafbaSTom Tucker struct rdma_cm_id *new_cm_id; 145207ebafbaSTom Tucker struct rdma_id_private *listen_id, *conn_id; 145307ebafbaSTom Tucker struct sockaddr_in *sin; 145407ebafbaSTom Tucker struct net_device *dev = NULL; 1455a1b1b61fSSean Hefty struct rdma_cm_event event; 145607ebafbaSTom Tucker int ret; 14578d8293cfSSteve Wise struct ib_device_attr attr; 145807ebafbaSTom Tucker 145907ebafbaSTom Tucker listen_id = cm_id->context; 1460550e5ca7SNir Muchtar if (cma_disable_callback(listen_id, RDMA_CM_LISTEN)) 14618aa08602SSean Hefty return -ECONNABORTED; 146207ebafbaSTom Tucker 146307ebafbaSTom Tucker /* Create a new RDMA id for the new IW CM ID */ 146407ebafbaSTom Tucker new_cm_id = rdma_create_id(listen_id->id.event_handler, 146507ebafbaSTom Tucker listen_id->id.context, 1466b26f9b99SSean Hefty RDMA_PS_TCP, IB_QPT_RC); 146710f32065SJulia Lawall if (IS_ERR(new_cm_id)) { 146807ebafbaSTom Tucker ret = -ENOMEM; 146907ebafbaSTom Tucker goto out; 147007ebafbaSTom Tucker } 147107ebafbaSTom Tucker conn_id = container_of(new_cm_id, struct rdma_id_private, id); 1472de910bd9SOr Gerlitz mutex_lock_nested(&conn_id->handler_mutex, SINGLE_DEPTH_NESTING); 1473550e5ca7SNir Muchtar conn_id->state = RDMA_CM_CONNECT; 147407ebafbaSTom Tucker 14751ab35276SDenis V. Lunev dev = ip_dev_find(&init_net, iw_event->local_addr.sin_addr.s_addr); 147607ebafbaSTom Tucker if (!dev) { 147707ebafbaSTom Tucker ret = -EADDRNOTAVAIL; 1478de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 147907ebafbaSTom Tucker rdma_destroy_id(new_cm_id); 148007ebafbaSTom Tucker goto out; 148107ebafbaSTom Tucker } 148207ebafbaSTom Tucker ret = rdma_copy_addr(&conn_id->id.route.addr.dev_addr, dev, NULL); 148307ebafbaSTom Tucker if (ret) { 1484de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 148507ebafbaSTom Tucker rdma_destroy_id(new_cm_id); 148607ebafbaSTom Tucker goto out; 148707ebafbaSTom Tucker } 148807ebafbaSTom Tucker 148907ebafbaSTom Tucker ret = cma_acquire_dev(conn_id); 149007ebafbaSTom Tucker if (ret) { 1491de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 149207ebafbaSTom Tucker rdma_destroy_id(new_cm_id); 149307ebafbaSTom Tucker goto out; 149407ebafbaSTom Tucker } 149507ebafbaSTom Tucker 149607ebafbaSTom Tucker conn_id->cm_id.iw = cm_id; 149707ebafbaSTom Tucker cm_id->context = conn_id; 149807ebafbaSTom Tucker cm_id->cm_handler = cma_iw_handler; 149907ebafbaSTom Tucker 1500f4753834SSean Hefty sin = (struct sockaddr_in *) cma_src_addr(conn_id); 150107ebafbaSTom Tucker *sin = iw_event->local_addr; 1502f4753834SSean Hefty sin = (struct sockaddr_in *) cma_dst_addr(conn_id); 150307ebafbaSTom Tucker *sin = iw_event->remote_addr; 150407ebafbaSTom Tucker 15058d8293cfSSteve Wise ret = ib_query_device(conn_id->id.device, &attr); 15068d8293cfSSteve Wise if (ret) { 1507de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 15088d8293cfSSteve Wise rdma_destroy_id(new_cm_id); 15098d8293cfSSteve Wise goto out; 15108d8293cfSSteve Wise } 15118d8293cfSSteve Wise 1512a1b1b61fSSean Hefty memset(&event, 0, sizeof event); 1513a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_CONNECT_REQUEST; 1514a1b1b61fSSean Hefty event.param.conn.private_data = iw_event->private_data; 1515a1b1b61fSSean Hefty event.param.conn.private_data_len = iw_event->private_data_len; 15163ebeebc3SKumar Sanghvi event.param.conn.initiator_depth = iw_event->ird; 15173ebeebc3SKumar Sanghvi event.param.conn.responder_resources = iw_event->ord; 151825ae21a1SSean Hefty 151925ae21a1SSean Hefty /* 152025ae21a1SSean Hefty * Protect against the user destroying conn_id from another thread 152125ae21a1SSean Hefty * until we're done accessing it. 152225ae21a1SSean Hefty */ 152325ae21a1SSean Hefty atomic_inc(&conn_id->refcount); 1524a1b1b61fSSean Hefty ret = conn_id->id.event_handler(&conn_id->id, &event); 152507ebafbaSTom Tucker if (ret) { 152607ebafbaSTom Tucker /* User wants to destroy the CM ID */ 152707ebafbaSTom Tucker conn_id->cm_id.iw = NULL; 1528550e5ca7SNir Muchtar cma_exch(conn_id, RDMA_CM_DESTROYING); 1529de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 153025ae21a1SSean Hefty cma_deref_id(conn_id); 153107ebafbaSTom Tucker rdma_destroy_id(&conn_id->id); 1532de910bd9SOr Gerlitz goto out; 153307ebafbaSTom Tucker } 153407ebafbaSTom Tucker 1535de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 153625ae21a1SSean Hefty cma_deref_id(conn_id); 1537de910bd9SOr Gerlitz 153807ebafbaSTom Tucker out: 153907ebafbaSTom Tucker if (dev) 154007ebafbaSTom Tucker dev_put(dev); 1541de910bd9SOr Gerlitz mutex_unlock(&listen_id->handler_mutex); 154207ebafbaSTom Tucker return ret; 154307ebafbaSTom Tucker } 154407ebafbaSTom Tucker 1545e51060f0SSean Hefty static int cma_ib_listen(struct rdma_id_private *id_priv) 1546e51060f0SSean Hefty { 1547e51060f0SSean Hefty struct ib_cm_compare_data compare_data; 1548e51060f0SSean Hefty struct sockaddr *addr; 15490c9361fcSJack Morgenstein struct ib_cm_id *id; 1550e51060f0SSean Hefty __be64 svc_id; 1551e51060f0SSean Hefty int ret; 1552e51060f0SSean Hefty 15530c9361fcSJack Morgenstein id = ib_create_cm_id(id_priv->id.device, cma_req_handler, id_priv); 15540c9361fcSJack Morgenstein if (IS_ERR(id)) 15550c9361fcSJack Morgenstein return PTR_ERR(id); 15560c9361fcSJack Morgenstein 15570c9361fcSJack Morgenstein id_priv->cm_id.ib = id; 1558e51060f0SSean Hefty 1559f4753834SSean Hefty addr = cma_src_addr(id_priv); 1560e51060f0SSean Hefty svc_id = cma_get_service_id(id_priv->id.ps, addr); 1561406b6a25SSean Hefty if (cma_any_addr(addr) && !id_priv->afonly) 1562e51060f0SSean Hefty ret = ib_cm_listen(id_priv->cm_id.ib, svc_id, 0, NULL); 1563e51060f0SSean Hefty else { 1564e51060f0SSean Hefty cma_set_compare_data(id_priv->id.ps, addr, &compare_data); 1565e51060f0SSean Hefty ret = ib_cm_listen(id_priv->cm_id.ib, svc_id, 0, &compare_data); 1566e51060f0SSean Hefty } 1567e51060f0SSean Hefty 1568e51060f0SSean Hefty if (ret) { 1569e51060f0SSean Hefty ib_destroy_cm_id(id_priv->cm_id.ib); 1570e51060f0SSean Hefty id_priv->cm_id.ib = NULL; 1571e51060f0SSean Hefty } 1572e51060f0SSean Hefty 1573e51060f0SSean Hefty return ret; 1574e51060f0SSean Hefty } 1575e51060f0SSean Hefty 157607ebafbaSTom Tucker static int cma_iw_listen(struct rdma_id_private *id_priv, int backlog) 157707ebafbaSTom Tucker { 157807ebafbaSTom Tucker int ret; 157907ebafbaSTom Tucker struct sockaddr_in *sin; 15800c9361fcSJack Morgenstein struct iw_cm_id *id; 158107ebafbaSTom Tucker 15820c9361fcSJack Morgenstein id = iw_create_cm_id(id_priv->id.device, 158307ebafbaSTom Tucker iw_conn_req_handler, 158407ebafbaSTom Tucker id_priv); 15850c9361fcSJack Morgenstein if (IS_ERR(id)) 15860c9361fcSJack Morgenstein return PTR_ERR(id); 15870c9361fcSJack Morgenstein 15880c9361fcSJack Morgenstein id_priv->cm_id.iw = id; 158907ebafbaSTom Tucker 1590f4753834SSean Hefty sin = (struct sockaddr_in *) cma_src_addr(id_priv); 159107ebafbaSTom Tucker id_priv->cm_id.iw->local_addr = *sin; 159207ebafbaSTom Tucker 159307ebafbaSTom Tucker ret = iw_cm_listen(id_priv->cm_id.iw, backlog); 159407ebafbaSTom Tucker 159507ebafbaSTom Tucker if (ret) { 159607ebafbaSTom Tucker iw_destroy_cm_id(id_priv->cm_id.iw); 159707ebafbaSTom Tucker id_priv->cm_id.iw = NULL; 159807ebafbaSTom Tucker } 159907ebafbaSTom Tucker 160007ebafbaSTom Tucker return ret; 160107ebafbaSTom Tucker } 160207ebafbaSTom Tucker 1603e51060f0SSean Hefty static int cma_listen_handler(struct rdma_cm_id *id, 1604e51060f0SSean Hefty struct rdma_cm_event *event) 1605e51060f0SSean Hefty { 1606e51060f0SSean Hefty struct rdma_id_private *id_priv = id->context; 1607e51060f0SSean Hefty 1608e51060f0SSean Hefty id->context = id_priv->id.context; 1609e51060f0SSean Hefty id->event_handler = id_priv->id.event_handler; 1610e51060f0SSean Hefty return id_priv->id.event_handler(id, event); 1611e51060f0SSean Hefty } 1612e51060f0SSean Hefty 1613e51060f0SSean Hefty static void cma_listen_on_dev(struct rdma_id_private *id_priv, 1614e51060f0SSean Hefty struct cma_device *cma_dev) 1615e51060f0SSean Hefty { 1616e51060f0SSean Hefty struct rdma_id_private *dev_id_priv; 1617e51060f0SSean Hefty struct rdma_cm_id *id; 1618e51060f0SSean Hefty int ret; 1619e51060f0SSean Hefty 1620b26f9b99SSean Hefty id = rdma_create_id(cma_listen_handler, id_priv, id_priv->id.ps, 1621b26f9b99SSean Hefty id_priv->id.qp_type); 1622e51060f0SSean Hefty if (IS_ERR(id)) 1623e51060f0SSean Hefty return; 1624e51060f0SSean Hefty 1625e51060f0SSean Hefty dev_id_priv = container_of(id, struct rdma_id_private, id); 1626e51060f0SSean Hefty 1627550e5ca7SNir Muchtar dev_id_priv->state = RDMA_CM_ADDR_BOUND; 1628f4753834SSean Hefty memcpy(cma_src_addr(dev_id_priv), cma_src_addr(id_priv), 1629f4753834SSean Hefty rdma_addr_size(cma_src_addr(id_priv))); 1630e51060f0SSean Hefty 1631e51060f0SSean Hefty cma_attach_to_dev(dev_id_priv, cma_dev); 1632e51060f0SSean Hefty list_add_tail(&dev_id_priv->listen_list, &id_priv->listen_list); 1633d02d1f53SSean Hefty atomic_inc(&id_priv->refcount); 1634d02d1f53SSean Hefty dev_id_priv->internal_id = 1; 16355b0ec991SSean Hefty dev_id_priv->afonly = id_priv->afonly; 1636e51060f0SSean Hefty 1637e51060f0SSean Hefty ret = rdma_listen(id, id_priv->backlog); 1638e51060f0SSean Hefty if (ret) 1639d02d1f53SSean Hefty printk(KERN_WARNING "RDMA CMA: cma_listen_on_dev, error %d, " 1640468f2239SRoland Dreier "listening on device %s\n", ret, cma_dev->device->name); 1641e51060f0SSean Hefty } 1642e51060f0SSean Hefty 1643e51060f0SSean Hefty static void cma_listen_on_all(struct rdma_id_private *id_priv) 1644e51060f0SSean Hefty { 1645e51060f0SSean Hefty struct cma_device *cma_dev; 1646e51060f0SSean Hefty 1647e51060f0SSean Hefty mutex_lock(&lock); 1648e51060f0SSean Hefty list_add_tail(&id_priv->list, &listen_any_list); 1649e51060f0SSean Hefty list_for_each_entry(cma_dev, &dev_list, list) 1650e51060f0SSean Hefty cma_listen_on_dev(id_priv, cma_dev); 1651e51060f0SSean Hefty mutex_unlock(&lock); 1652e51060f0SSean Hefty } 1653e51060f0SSean Hefty 1654a81c994dSSean Hefty void rdma_set_service_type(struct rdma_cm_id *id, int tos) 1655a81c994dSSean Hefty { 1656a81c994dSSean Hefty struct rdma_id_private *id_priv; 1657a81c994dSSean Hefty 1658a81c994dSSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1659a81c994dSSean Hefty id_priv->tos = (u8) tos; 1660a81c994dSSean Hefty } 1661a81c994dSSean Hefty EXPORT_SYMBOL(rdma_set_service_type); 1662a81c994dSSean Hefty 1663e51060f0SSean Hefty static void cma_query_handler(int status, struct ib_sa_path_rec *path_rec, 1664e51060f0SSean Hefty void *context) 1665e51060f0SSean Hefty { 1666e51060f0SSean Hefty struct cma_work *work = context; 1667e51060f0SSean Hefty struct rdma_route *route; 1668e51060f0SSean Hefty 1669e51060f0SSean Hefty route = &work->id->id.route; 1670e51060f0SSean Hefty 1671e51060f0SSean Hefty if (!status) { 1672e51060f0SSean Hefty route->num_paths = 1; 1673e51060f0SSean Hefty *route->path_rec = *path_rec; 1674e51060f0SSean Hefty } else { 1675550e5ca7SNir Muchtar work->old_state = RDMA_CM_ROUTE_QUERY; 1676550e5ca7SNir Muchtar work->new_state = RDMA_CM_ADDR_RESOLVED; 1677e51060f0SSean Hefty work->event.event = RDMA_CM_EVENT_ROUTE_ERROR; 16788f0472d3SSean Hefty work->event.status = status; 1679e51060f0SSean Hefty } 1680e51060f0SSean Hefty 1681e51060f0SSean Hefty queue_work(cma_wq, &work->work); 1682e51060f0SSean Hefty } 1683e51060f0SSean Hefty 1684e51060f0SSean Hefty static int cma_query_ib_route(struct rdma_id_private *id_priv, int timeout_ms, 1685e51060f0SSean Hefty struct cma_work *work) 1686e51060f0SSean Hefty { 1687f4753834SSean Hefty struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 1688e51060f0SSean Hefty struct ib_sa_path_rec path_rec; 1689a81c994dSSean Hefty ib_sa_comp_mask comp_mask; 1690a81c994dSSean Hefty struct sockaddr_in6 *sin6; 1691e51060f0SSean Hefty 1692e51060f0SSean Hefty memset(&path_rec, 0, sizeof path_rec); 1693f4753834SSean Hefty rdma_addr_get_sgid(dev_addr, &path_rec.sgid); 1694f4753834SSean Hefty rdma_addr_get_dgid(dev_addr, &path_rec.dgid); 1695f4753834SSean Hefty path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr)); 1696e51060f0SSean Hefty path_rec.numb_path = 1; 1697962063e6SSean Hefty path_rec.reversible = 1; 1698f4753834SSean Hefty path_rec.service_id = cma_get_service_id(id_priv->id.ps, cma_dst_addr(id_priv)); 1699a81c994dSSean Hefty 1700a81c994dSSean Hefty comp_mask = IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID | 1701a81c994dSSean Hefty IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH | 1702a81c994dSSean Hefty IB_SA_PATH_REC_REVERSIBLE | IB_SA_PATH_REC_SERVICE_ID; 1703a81c994dSSean Hefty 1704f4753834SSean Hefty if (cma_family(id_priv) == AF_INET) { 1705a81c994dSSean Hefty path_rec.qos_class = cpu_to_be16((u16) id_priv->tos); 1706a81c994dSSean Hefty comp_mask |= IB_SA_PATH_REC_QOS_CLASS; 1707a81c994dSSean Hefty } else { 1708f4753834SSean Hefty sin6 = (struct sockaddr_in6 *) cma_src_addr(id_priv); 1709a81c994dSSean Hefty path_rec.traffic_class = (u8) (be32_to_cpu(sin6->sin6_flowinfo) >> 20); 1710a81c994dSSean Hefty comp_mask |= IB_SA_PATH_REC_TRAFFIC_CLASS; 1711a81c994dSSean Hefty } 1712e51060f0SSean Hefty 1713c1a0b23bSMichael S. Tsirkin id_priv->query_id = ib_sa_path_rec_get(&sa_client, id_priv->id.device, 1714e51060f0SSean Hefty id_priv->id.port_num, &path_rec, 1715a81c994dSSean Hefty comp_mask, timeout_ms, 1716a81c994dSSean Hefty GFP_KERNEL, cma_query_handler, 1717a81c994dSSean Hefty work, &id_priv->query); 1718e51060f0SSean Hefty 1719e51060f0SSean Hefty return (id_priv->query_id < 0) ? id_priv->query_id : 0; 1720e51060f0SSean Hefty } 1721e51060f0SSean Hefty 1722c4028958SDavid Howells static void cma_work_handler(struct work_struct *_work) 1723e51060f0SSean Hefty { 1724c4028958SDavid Howells struct cma_work *work = container_of(_work, struct cma_work, work); 1725e51060f0SSean Hefty struct rdma_id_private *id_priv = work->id; 1726e51060f0SSean Hefty int destroy = 0; 1727e51060f0SSean Hefty 1728de910bd9SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 1729e51060f0SSean Hefty if (!cma_comp_exch(id_priv, work->old_state, work->new_state)) 1730e51060f0SSean Hefty goto out; 1731e51060f0SSean Hefty 1732e51060f0SSean Hefty if (id_priv->id.event_handler(&id_priv->id, &work->event)) { 1733550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 1734e51060f0SSean Hefty destroy = 1; 1735e51060f0SSean Hefty } 1736e51060f0SSean Hefty out: 1737de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 1738e51060f0SSean Hefty cma_deref_id(id_priv); 1739e51060f0SSean Hefty if (destroy) 1740e51060f0SSean Hefty rdma_destroy_id(&id_priv->id); 1741e51060f0SSean Hefty kfree(work); 1742e51060f0SSean Hefty } 1743e51060f0SSean Hefty 1744dd5bdff8SOr Gerlitz static void cma_ndev_work_handler(struct work_struct *_work) 1745dd5bdff8SOr Gerlitz { 1746dd5bdff8SOr Gerlitz struct cma_ndev_work *work = container_of(_work, struct cma_ndev_work, work); 1747dd5bdff8SOr Gerlitz struct rdma_id_private *id_priv = work->id; 1748dd5bdff8SOr Gerlitz int destroy = 0; 1749dd5bdff8SOr Gerlitz 1750dd5bdff8SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 1751550e5ca7SNir Muchtar if (id_priv->state == RDMA_CM_DESTROYING || 1752550e5ca7SNir Muchtar id_priv->state == RDMA_CM_DEVICE_REMOVAL) 1753dd5bdff8SOr Gerlitz goto out; 1754dd5bdff8SOr Gerlitz 1755dd5bdff8SOr Gerlitz if (id_priv->id.event_handler(&id_priv->id, &work->event)) { 1756550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 1757dd5bdff8SOr Gerlitz destroy = 1; 1758dd5bdff8SOr Gerlitz } 1759dd5bdff8SOr Gerlitz 1760dd5bdff8SOr Gerlitz out: 1761dd5bdff8SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 1762dd5bdff8SOr Gerlitz cma_deref_id(id_priv); 1763dd5bdff8SOr Gerlitz if (destroy) 1764dd5bdff8SOr Gerlitz rdma_destroy_id(&id_priv->id); 1765dd5bdff8SOr Gerlitz kfree(work); 1766dd5bdff8SOr Gerlitz } 1767dd5bdff8SOr Gerlitz 1768e51060f0SSean Hefty static int cma_resolve_ib_route(struct rdma_id_private *id_priv, int timeout_ms) 1769e51060f0SSean Hefty { 1770e51060f0SSean Hefty struct rdma_route *route = &id_priv->id.route; 1771e51060f0SSean Hefty struct cma_work *work; 1772e51060f0SSean Hefty int ret; 1773e51060f0SSean Hefty 1774e51060f0SSean Hefty work = kzalloc(sizeof *work, GFP_KERNEL); 1775e51060f0SSean Hefty if (!work) 1776e51060f0SSean Hefty return -ENOMEM; 1777e51060f0SSean Hefty 1778e51060f0SSean Hefty work->id = id_priv; 1779c4028958SDavid Howells INIT_WORK(&work->work, cma_work_handler); 1780550e5ca7SNir Muchtar work->old_state = RDMA_CM_ROUTE_QUERY; 1781550e5ca7SNir Muchtar work->new_state = RDMA_CM_ROUTE_RESOLVED; 1782e51060f0SSean Hefty work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED; 1783e51060f0SSean Hefty 1784e51060f0SSean Hefty route->path_rec = kmalloc(sizeof *route->path_rec, GFP_KERNEL); 1785e51060f0SSean Hefty if (!route->path_rec) { 1786e51060f0SSean Hefty ret = -ENOMEM; 1787e51060f0SSean Hefty goto err1; 1788e51060f0SSean Hefty } 1789e51060f0SSean Hefty 1790e51060f0SSean Hefty ret = cma_query_ib_route(id_priv, timeout_ms, work); 1791e51060f0SSean Hefty if (ret) 1792e51060f0SSean Hefty goto err2; 1793e51060f0SSean Hefty 1794e51060f0SSean Hefty return 0; 1795e51060f0SSean Hefty err2: 1796e51060f0SSean Hefty kfree(route->path_rec); 1797e51060f0SSean Hefty route->path_rec = NULL; 1798e51060f0SSean Hefty err1: 1799e51060f0SSean Hefty kfree(work); 1800e51060f0SSean Hefty return ret; 1801e51060f0SSean Hefty } 1802e51060f0SSean Hefty 1803e51060f0SSean Hefty int rdma_set_ib_paths(struct rdma_cm_id *id, 1804e51060f0SSean Hefty struct ib_sa_path_rec *path_rec, int num_paths) 1805e51060f0SSean Hefty { 1806e51060f0SSean Hefty struct rdma_id_private *id_priv; 1807e51060f0SSean Hefty int ret; 1808e51060f0SSean Hefty 1809e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1810550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED, 1811550e5ca7SNir Muchtar RDMA_CM_ROUTE_RESOLVED)) 1812e51060f0SSean Hefty return -EINVAL; 1813e51060f0SSean Hefty 18149893e742SJulia Lawall id->route.path_rec = kmemdup(path_rec, sizeof *path_rec * num_paths, 18159893e742SJulia Lawall GFP_KERNEL); 1816e51060f0SSean Hefty if (!id->route.path_rec) { 1817e51060f0SSean Hefty ret = -ENOMEM; 1818e51060f0SSean Hefty goto err; 1819e51060f0SSean Hefty } 1820e51060f0SSean Hefty 1821ae2d9293SSean Hefty id->route.num_paths = num_paths; 1822e51060f0SSean Hefty return 0; 1823e51060f0SSean Hefty err: 1824550e5ca7SNir Muchtar cma_comp_exch(id_priv, RDMA_CM_ROUTE_RESOLVED, RDMA_CM_ADDR_RESOLVED); 1825e51060f0SSean Hefty return ret; 1826e51060f0SSean Hefty } 1827e51060f0SSean Hefty EXPORT_SYMBOL(rdma_set_ib_paths); 1828e51060f0SSean Hefty 182907ebafbaSTom Tucker static int cma_resolve_iw_route(struct rdma_id_private *id_priv, int timeout_ms) 183007ebafbaSTom Tucker { 183107ebafbaSTom Tucker struct cma_work *work; 183207ebafbaSTom Tucker 183307ebafbaSTom Tucker work = kzalloc(sizeof *work, GFP_KERNEL); 183407ebafbaSTom Tucker if (!work) 183507ebafbaSTom Tucker return -ENOMEM; 183607ebafbaSTom Tucker 183707ebafbaSTom Tucker work->id = id_priv; 1838c4028958SDavid Howells INIT_WORK(&work->work, cma_work_handler); 1839550e5ca7SNir Muchtar work->old_state = RDMA_CM_ROUTE_QUERY; 1840550e5ca7SNir Muchtar work->new_state = RDMA_CM_ROUTE_RESOLVED; 184107ebafbaSTom Tucker work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED; 184207ebafbaSTom Tucker queue_work(cma_wq, &work->work); 184307ebafbaSTom Tucker return 0; 184407ebafbaSTom Tucker } 184507ebafbaSTom Tucker 18463c86aa70SEli Cohen static int cma_resolve_iboe_route(struct rdma_id_private *id_priv) 18473c86aa70SEli Cohen { 18483c86aa70SEli Cohen struct rdma_route *route = &id_priv->id.route; 18493c86aa70SEli Cohen struct rdma_addr *addr = &route->addr; 18503c86aa70SEli Cohen struct cma_work *work; 18513c86aa70SEli Cohen int ret; 18523c86aa70SEli Cohen struct net_device *ndev = NULL; 1853af7bd463SEli Cohen u16 vid; 18543c86aa70SEli Cohen 18553c86aa70SEli Cohen work = kzalloc(sizeof *work, GFP_KERNEL); 18563c86aa70SEli Cohen if (!work) 18573c86aa70SEli Cohen return -ENOMEM; 18583c86aa70SEli Cohen 18593c86aa70SEli Cohen work->id = id_priv; 18603c86aa70SEli Cohen INIT_WORK(&work->work, cma_work_handler); 18613c86aa70SEli Cohen 18623c86aa70SEli Cohen route->path_rec = kzalloc(sizeof *route->path_rec, GFP_KERNEL); 18633c86aa70SEli Cohen if (!route->path_rec) { 18643c86aa70SEli Cohen ret = -ENOMEM; 18653c86aa70SEli Cohen goto err1; 18663c86aa70SEli Cohen } 18673c86aa70SEli Cohen 18683c86aa70SEli Cohen route->num_paths = 1; 18693c86aa70SEli Cohen 18703c86aa70SEli Cohen if (addr->dev_addr.bound_dev_if) 18713c86aa70SEli Cohen ndev = dev_get_by_index(&init_net, addr->dev_addr.bound_dev_if); 18723c86aa70SEli Cohen if (!ndev) { 18733c86aa70SEli Cohen ret = -ENODEV; 18743c86aa70SEli Cohen goto err2; 18753c86aa70SEli Cohen } 18763c86aa70SEli Cohen 1877af7bd463SEli Cohen vid = rdma_vlan_dev_vlan_id(ndev); 1878af7bd463SEli Cohen 1879af7bd463SEli Cohen iboe_mac_vlan_to_ll(&route->path_rec->sgid, addr->dev_addr.src_dev_addr, vid); 1880af7bd463SEli Cohen iboe_mac_vlan_to_ll(&route->path_rec->dgid, addr->dev_addr.dst_dev_addr, vid); 1881af7bd463SEli Cohen 1882af7bd463SEli Cohen route->path_rec->hop_limit = 1; 1883af7bd463SEli Cohen route->path_rec->reversible = 1; 1884af7bd463SEli Cohen route->path_rec->pkey = cpu_to_be16(0xffff); 1885af7bd463SEli Cohen route->path_rec->mtu_selector = IB_SA_EQ; 1886366cddb4SAmir Vadai route->path_rec->sl = netdev_get_prio_tc_map( 1887366cddb4SAmir Vadai ndev->priv_flags & IFF_802_1Q_VLAN ? 1888366cddb4SAmir Vadai vlan_dev_real_dev(ndev) : ndev, 1889366cddb4SAmir Vadai rt_tos2priority(id_priv->tos)); 1890af7bd463SEli Cohen 18913c86aa70SEli Cohen route->path_rec->mtu = iboe_get_mtu(ndev->mtu); 18923c86aa70SEli Cohen route->path_rec->rate_selector = IB_SA_EQ; 18933c86aa70SEli Cohen route->path_rec->rate = iboe_get_rate(ndev); 18943c86aa70SEli Cohen dev_put(ndev); 18953c86aa70SEli Cohen route->path_rec->packet_life_time_selector = IB_SA_EQ; 18963c86aa70SEli Cohen route->path_rec->packet_life_time = CMA_IBOE_PACKET_LIFETIME; 18973c86aa70SEli Cohen if (!route->path_rec->mtu) { 18983c86aa70SEli Cohen ret = -EINVAL; 18993c86aa70SEli Cohen goto err2; 19003c86aa70SEli Cohen } 19013c86aa70SEli Cohen 1902550e5ca7SNir Muchtar work->old_state = RDMA_CM_ROUTE_QUERY; 1903550e5ca7SNir Muchtar work->new_state = RDMA_CM_ROUTE_RESOLVED; 19043c86aa70SEli Cohen work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED; 19053c86aa70SEli Cohen work->event.status = 0; 19063c86aa70SEli Cohen 19073c86aa70SEli Cohen queue_work(cma_wq, &work->work); 19083c86aa70SEli Cohen 19093c86aa70SEli Cohen return 0; 19103c86aa70SEli Cohen 19113c86aa70SEli Cohen err2: 19123c86aa70SEli Cohen kfree(route->path_rec); 19133c86aa70SEli Cohen route->path_rec = NULL; 19143c86aa70SEli Cohen err1: 19153c86aa70SEli Cohen kfree(work); 19163c86aa70SEli Cohen return ret; 19173c86aa70SEli Cohen } 19183c86aa70SEli Cohen 1919e51060f0SSean Hefty int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms) 1920e51060f0SSean Hefty { 1921e51060f0SSean Hefty struct rdma_id_private *id_priv; 1922e51060f0SSean Hefty int ret; 1923e51060f0SSean Hefty 1924e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1925550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED, RDMA_CM_ROUTE_QUERY)) 1926e51060f0SSean Hefty return -EINVAL; 1927e51060f0SSean Hefty 1928e51060f0SSean Hefty atomic_inc(&id_priv->refcount); 192907ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 193007ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 19313c86aa70SEli Cohen switch (rdma_port_get_link_layer(id->device, id->port_num)) { 19323c86aa70SEli Cohen case IB_LINK_LAYER_INFINIBAND: 1933e51060f0SSean Hefty ret = cma_resolve_ib_route(id_priv, timeout_ms); 1934e51060f0SSean Hefty break; 19353c86aa70SEli Cohen case IB_LINK_LAYER_ETHERNET: 19363c86aa70SEli Cohen ret = cma_resolve_iboe_route(id_priv); 19373c86aa70SEli Cohen break; 19383c86aa70SEli Cohen default: 19393c86aa70SEli Cohen ret = -ENOSYS; 19403c86aa70SEli Cohen } 19413c86aa70SEli Cohen break; 194207ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 194307ebafbaSTom Tucker ret = cma_resolve_iw_route(id_priv, timeout_ms); 194407ebafbaSTom Tucker break; 1945e51060f0SSean Hefty default: 1946e51060f0SSean Hefty ret = -ENOSYS; 1947e51060f0SSean Hefty break; 1948e51060f0SSean Hefty } 1949e51060f0SSean Hefty if (ret) 1950e51060f0SSean Hefty goto err; 1951e51060f0SSean Hefty 1952e51060f0SSean Hefty return 0; 1953e51060f0SSean Hefty err: 1954550e5ca7SNir Muchtar cma_comp_exch(id_priv, RDMA_CM_ROUTE_QUERY, RDMA_CM_ADDR_RESOLVED); 1955e51060f0SSean Hefty cma_deref_id(id_priv); 1956e51060f0SSean Hefty return ret; 1957e51060f0SSean Hefty } 1958e51060f0SSean Hefty EXPORT_SYMBOL(rdma_resolve_route); 1959e51060f0SSean Hefty 19606a3e362dSSean Hefty static void cma_set_loopback(struct sockaddr *addr) 19616a3e362dSSean Hefty { 19626a3e362dSSean Hefty switch (addr->sa_family) { 19636a3e362dSSean Hefty case AF_INET: 19646a3e362dSSean Hefty ((struct sockaddr_in *) addr)->sin_addr.s_addr = htonl(INADDR_LOOPBACK); 19656a3e362dSSean Hefty break; 19666a3e362dSSean Hefty case AF_INET6: 19676a3e362dSSean Hefty ipv6_addr_set(&((struct sockaddr_in6 *) addr)->sin6_addr, 19686a3e362dSSean Hefty 0, 0, 0, htonl(1)); 19696a3e362dSSean Hefty break; 19706a3e362dSSean Hefty default: 19716a3e362dSSean Hefty ib_addr_set(&((struct sockaddr_ib *) addr)->sib_addr, 19726a3e362dSSean Hefty 0, 0, 0, htonl(1)); 19736a3e362dSSean Hefty break; 19746a3e362dSSean Hefty } 19756a3e362dSSean Hefty } 19766a3e362dSSean Hefty 1977e51060f0SSean Hefty static int cma_bind_loopback(struct rdma_id_private *id_priv) 1978e51060f0SSean Hefty { 1979b0569e40SSean Hefty struct cma_device *cma_dev, *cur_dev; 1980e51060f0SSean Hefty struct ib_port_attr port_attr; 1981f0ee3404SMichael S. Tsirkin union ib_gid gid; 1982e51060f0SSean Hefty u16 pkey; 1983e51060f0SSean Hefty int ret; 1984e51060f0SSean Hefty u8 p; 1985e51060f0SSean Hefty 1986b0569e40SSean Hefty cma_dev = NULL; 1987e51060f0SSean Hefty mutex_lock(&lock); 1988b0569e40SSean Hefty list_for_each_entry(cur_dev, &dev_list, list) { 1989b0569e40SSean Hefty if (cma_family(id_priv) == AF_IB && 1990b0569e40SSean Hefty rdma_node_get_transport(cur_dev->device->node_type) != RDMA_TRANSPORT_IB) 1991b0569e40SSean Hefty continue; 1992b0569e40SSean Hefty 1993b0569e40SSean Hefty if (!cma_dev) 1994b0569e40SSean Hefty cma_dev = cur_dev; 1995b0569e40SSean Hefty 1996b0569e40SSean Hefty for (p = 1; p <= cur_dev->device->phys_port_cnt; ++p) { 1997b0569e40SSean Hefty if (!ib_query_port(cur_dev->device, p, &port_attr) && 1998b0569e40SSean Hefty port_attr.state == IB_PORT_ACTIVE) { 1999b0569e40SSean Hefty cma_dev = cur_dev; 2000b0569e40SSean Hefty goto port_found; 2001b0569e40SSean Hefty } 2002b0569e40SSean Hefty } 2003b0569e40SSean Hefty } 2004b0569e40SSean Hefty 2005b0569e40SSean Hefty if (!cma_dev) { 2006e82153b5SKrishna Kumar ret = -ENODEV; 2007e82153b5SKrishna Kumar goto out; 2008e82153b5SKrishna Kumar } 2009e51060f0SSean Hefty 2010e51060f0SSean Hefty p = 1; 2011e51060f0SSean Hefty 2012e51060f0SSean Hefty port_found: 2013f0ee3404SMichael S. Tsirkin ret = ib_get_cached_gid(cma_dev->device, p, 0, &gid); 2014e51060f0SSean Hefty if (ret) 2015e51060f0SSean Hefty goto out; 2016e51060f0SSean Hefty 2017e51060f0SSean Hefty ret = ib_get_cached_pkey(cma_dev->device, p, 0, &pkey); 2018e51060f0SSean Hefty if (ret) 2019e51060f0SSean Hefty goto out; 2020e51060f0SSean Hefty 20216f8372b6SSean Hefty id_priv->id.route.addr.dev_addr.dev_type = 20223c86aa70SEli Cohen (rdma_port_get_link_layer(cma_dev->device, p) == IB_LINK_LAYER_INFINIBAND) ? 20236f8372b6SSean Hefty ARPHRD_INFINIBAND : ARPHRD_ETHER; 20246f8372b6SSean Hefty 20256f8372b6SSean Hefty rdma_addr_set_sgid(&id_priv->id.route.addr.dev_addr, &gid); 2026e51060f0SSean Hefty ib_addr_set_pkey(&id_priv->id.route.addr.dev_addr, pkey); 2027e51060f0SSean Hefty id_priv->id.port_num = p; 2028e51060f0SSean Hefty cma_attach_to_dev(id_priv, cma_dev); 2029f4753834SSean Hefty cma_set_loopback(cma_src_addr(id_priv)); 2030e51060f0SSean Hefty out: 2031e51060f0SSean Hefty mutex_unlock(&lock); 2032e51060f0SSean Hefty return ret; 2033e51060f0SSean Hefty } 2034e51060f0SSean Hefty 2035e51060f0SSean Hefty static void addr_handler(int status, struct sockaddr *src_addr, 2036e51060f0SSean Hefty struct rdma_dev_addr *dev_addr, void *context) 2037e51060f0SSean Hefty { 2038e51060f0SSean Hefty struct rdma_id_private *id_priv = context; 2039a1b1b61fSSean Hefty struct rdma_cm_event event; 2040e51060f0SSean Hefty 2041a1b1b61fSSean Hefty memset(&event, 0, sizeof event); 2042de910bd9SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 2043550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_QUERY, 2044550e5ca7SNir Muchtar RDMA_CM_ADDR_RESOLVED)) 204561a73c70SSean Hefty goto out; 204661a73c70SSean Hefty 204761a73c70SSean Hefty if (!status && !id_priv->cma_dev) 2048e51060f0SSean Hefty status = cma_acquire_dev(id_priv); 2049e51060f0SSean Hefty 2050e51060f0SSean Hefty if (status) { 2051550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED, 2052550e5ca7SNir Muchtar RDMA_CM_ADDR_BOUND)) 2053e51060f0SSean Hefty goto out; 2054a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_ADDR_ERROR; 2055a1b1b61fSSean Hefty event.status = status; 2056e51060f0SSean Hefty } else { 2057f4753834SSean Hefty memcpy(cma_src_addr(id_priv), src_addr, rdma_addr_size(src_addr)); 2058a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_ADDR_RESOLVED; 2059e51060f0SSean Hefty } 2060e51060f0SSean Hefty 2061a1b1b61fSSean Hefty if (id_priv->id.event_handler(&id_priv->id, &event)) { 2062550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 2063de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 2064e51060f0SSean Hefty cma_deref_id(id_priv); 2065e51060f0SSean Hefty rdma_destroy_id(&id_priv->id); 2066e51060f0SSean Hefty return; 2067e51060f0SSean Hefty } 2068e51060f0SSean Hefty out: 2069de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 2070e51060f0SSean Hefty cma_deref_id(id_priv); 2071e51060f0SSean Hefty } 2072e51060f0SSean Hefty 2073e51060f0SSean Hefty static int cma_resolve_loopback(struct rdma_id_private *id_priv) 2074e51060f0SSean Hefty { 2075e51060f0SSean Hefty struct cma_work *work; 2076f0ee3404SMichael S. Tsirkin union ib_gid gid; 2077e51060f0SSean Hefty int ret; 2078e51060f0SSean Hefty 2079e51060f0SSean Hefty work = kzalloc(sizeof *work, GFP_KERNEL); 2080e51060f0SSean Hefty if (!work) 2081e51060f0SSean Hefty return -ENOMEM; 2082e51060f0SSean Hefty 2083e51060f0SSean Hefty if (!id_priv->cma_dev) { 2084e51060f0SSean Hefty ret = cma_bind_loopback(id_priv); 2085e51060f0SSean Hefty if (ret) 2086e51060f0SSean Hefty goto err; 2087e51060f0SSean Hefty } 2088e51060f0SSean Hefty 20896f8372b6SSean Hefty rdma_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid); 20906f8372b6SSean Hefty rdma_addr_set_dgid(&id_priv->id.route.addr.dev_addr, &gid); 2091e51060f0SSean Hefty 2092e51060f0SSean Hefty work->id = id_priv; 2093c4028958SDavid Howells INIT_WORK(&work->work, cma_work_handler); 2094550e5ca7SNir Muchtar work->old_state = RDMA_CM_ADDR_QUERY; 2095550e5ca7SNir Muchtar work->new_state = RDMA_CM_ADDR_RESOLVED; 2096e51060f0SSean Hefty work->event.event = RDMA_CM_EVENT_ADDR_RESOLVED; 2097e51060f0SSean Hefty queue_work(cma_wq, &work->work); 2098e51060f0SSean Hefty return 0; 2099e51060f0SSean Hefty err: 2100e51060f0SSean Hefty kfree(work); 2101e51060f0SSean Hefty return ret; 2102e51060f0SSean Hefty } 2103e51060f0SSean Hefty 2104e51060f0SSean Hefty static int cma_bind_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, 2105e51060f0SSean Hefty struct sockaddr *dst_addr) 2106e51060f0SSean Hefty { 2107d14714dfSSean Hefty if (!src_addr || !src_addr->sa_family) { 2108d14714dfSSean Hefty src_addr = (struct sockaddr *) &id->route.addr.src_addr; 2109d14714dfSSean Hefty if ((src_addr->sa_family = dst_addr->sa_family) == AF_INET6) { 2110d14714dfSSean Hefty ((struct sockaddr_in6 *) src_addr)->sin6_scope_id = 2111d14714dfSSean Hefty ((struct sockaddr_in6 *) dst_addr)->sin6_scope_id; 2112d14714dfSSean Hefty } 2113d14714dfSSean Hefty } 2114e51060f0SSean Hefty return rdma_bind_addr(id, src_addr); 2115e51060f0SSean Hefty } 2116e51060f0SSean Hefty 2117e51060f0SSean Hefty int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, 2118e51060f0SSean Hefty struct sockaddr *dst_addr, int timeout_ms) 2119e51060f0SSean Hefty { 2120e51060f0SSean Hefty struct rdma_id_private *id_priv; 2121e51060f0SSean Hefty int ret; 2122e51060f0SSean Hefty 2123e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 2124550e5ca7SNir Muchtar if (id_priv->state == RDMA_CM_IDLE) { 2125e51060f0SSean Hefty ret = cma_bind_addr(id, src_addr, dst_addr); 2126e51060f0SSean Hefty if (ret) 2127e51060f0SSean Hefty return ret; 2128e51060f0SSean Hefty } 2129e51060f0SSean Hefty 2130*4ae7152eSSean Hefty if (cma_family(id_priv) != dst_addr->sa_family) 2131*4ae7152eSSean Hefty return -EINVAL; 2132*4ae7152eSSean Hefty 2133550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_ADDR_QUERY)) 2134e51060f0SSean Hefty return -EINVAL; 2135e51060f0SSean Hefty 2136e51060f0SSean Hefty atomic_inc(&id_priv->refcount); 2137f4753834SSean Hefty memcpy(cma_dst_addr(id_priv), dst_addr, rdma_addr_size(dst_addr)); 2138e51060f0SSean Hefty if (cma_any_addr(dst_addr)) 2139e51060f0SSean Hefty ret = cma_resolve_loopback(id_priv); 2140e51060f0SSean Hefty else 2141f4753834SSean Hefty ret = rdma_resolve_ip(&addr_client, cma_src_addr(id_priv), 21427a118df3SSean Hefty dst_addr, &id->route.addr.dev_addr, 2143e51060f0SSean Hefty timeout_ms, addr_handler, id_priv); 2144e51060f0SSean Hefty if (ret) 2145e51060f0SSean Hefty goto err; 2146e51060f0SSean Hefty 2147e51060f0SSean Hefty return 0; 2148e51060f0SSean Hefty err: 2149550e5ca7SNir Muchtar cma_comp_exch(id_priv, RDMA_CM_ADDR_QUERY, RDMA_CM_ADDR_BOUND); 2150e51060f0SSean Hefty cma_deref_id(id_priv); 2151e51060f0SSean Hefty return ret; 2152e51060f0SSean Hefty } 2153e51060f0SSean Hefty EXPORT_SYMBOL(rdma_resolve_addr); 2154e51060f0SSean Hefty 2155a9bb7912SHefty, Sean int rdma_set_reuseaddr(struct rdma_cm_id *id, int reuse) 2156a9bb7912SHefty, Sean { 2157a9bb7912SHefty, Sean struct rdma_id_private *id_priv; 2158a9bb7912SHefty, Sean unsigned long flags; 2159a9bb7912SHefty, Sean int ret; 2160a9bb7912SHefty, Sean 2161a9bb7912SHefty, Sean id_priv = container_of(id, struct rdma_id_private, id); 2162a9bb7912SHefty, Sean spin_lock_irqsave(&id_priv->lock, flags); 2163c8dea2f9SSean Hefty if (reuse || id_priv->state == RDMA_CM_IDLE) { 2164a9bb7912SHefty, Sean id_priv->reuseaddr = reuse; 2165a9bb7912SHefty, Sean ret = 0; 2166a9bb7912SHefty, Sean } else { 2167a9bb7912SHefty, Sean ret = -EINVAL; 2168a9bb7912SHefty, Sean } 2169a9bb7912SHefty, Sean spin_unlock_irqrestore(&id_priv->lock, flags); 2170a9bb7912SHefty, Sean return ret; 2171a9bb7912SHefty, Sean } 2172a9bb7912SHefty, Sean EXPORT_SYMBOL(rdma_set_reuseaddr); 2173a9bb7912SHefty, Sean 217468602120SSean Hefty int rdma_set_afonly(struct rdma_cm_id *id, int afonly) 217568602120SSean Hefty { 217668602120SSean Hefty struct rdma_id_private *id_priv; 217768602120SSean Hefty unsigned long flags; 217868602120SSean Hefty int ret; 217968602120SSean Hefty 218068602120SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 218168602120SSean Hefty spin_lock_irqsave(&id_priv->lock, flags); 218268602120SSean Hefty if (id_priv->state == RDMA_CM_IDLE || id_priv->state == RDMA_CM_ADDR_BOUND) { 218368602120SSean Hefty id_priv->options |= (1 << CMA_OPTION_AFONLY); 218468602120SSean Hefty id_priv->afonly = afonly; 218568602120SSean Hefty ret = 0; 218668602120SSean Hefty } else { 218768602120SSean Hefty ret = -EINVAL; 218868602120SSean Hefty } 218968602120SSean Hefty spin_unlock_irqrestore(&id_priv->lock, flags); 219068602120SSean Hefty return ret; 219168602120SSean Hefty } 219268602120SSean Hefty EXPORT_SYMBOL(rdma_set_afonly); 219368602120SSean Hefty 2194e51060f0SSean Hefty static void cma_bind_port(struct rdma_bind_list *bind_list, 2195e51060f0SSean Hefty struct rdma_id_private *id_priv) 2196e51060f0SSean Hefty { 219758afdcb7SSean Hefty struct sockaddr *addr; 219858afdcb7SSean Hefty struct sockaddr_ib *sib; 219958afdcb7SSean Hefty u64 sid, mask; 220058afdcb7SSean Hefty __be16 port; 2201e51060f0SSean Hefty 2202f4753834SSean Hefty addr = cma_src_addr(id_priv); 220358afdcb7SSean Hefty port = htons(bind_list->port); 220458afdcb7SSean Hefty 220558afdcb7SSean Hefty switch (addr->sa_family) { 220658afdcb7SSean Hefty case AF_INET: 220758afdcb7SSean Hefty ((struct sockaddr_in *) addr)->sin_port = port; 220858afdcb7SSean Hefty break; 220958afdcb7SSean Hefty case AF_INET6: 221058afdcb7SSean Hefty ((struct sockaddr_in6 *) addr)->sin6_port = port; 221158afdcb7SSean Hefty break; 221258afdcb7SSean Hefty case AF_IB: 221358afdcb7SSean Hefty sib = (struct sockaddr_ib *) addr; 221458afdcb7SSean Hefty sid = be64_to_cpu(sib->sib_sid); 221558afdcb7SSean Hefty mask = be64_to_cpu(sib->sib_sid_mask); 221658afdcb7SSean Hefty sib->sib_sid = cpu_to_be64((sid & mask) | (u64) ntohs(port)); 221758afdcb7SSean Hefty sib->sib_sid_mask = cpu_to_be64(~0ULL); 221858afdcb7SSean Hefty break; 221958afdcb7SSean Hefty } 2220e51060f0SSean Hefty id_priv->bind_list = bind_list; 2221e51060f0SSean Hefty hlist_add_head(&id_priv->node, &bind_list->owners); 2222e51060f0SSean Hefty } 2223e51060f0SSean Hefty 2224e51060f0SSean Hefty static int cma_alloc_port(struct idr *ps, struct rdma_id_private *id_priv, 2225e51060f0SSean Hefty unsigned short snum) 2226e51060f0SSean Hefty { 2227e51060f0SSean Hefty struct rdma_bind_list *bind_list; 22283b069c5dSTejun Heo int ret; 2229e51060f0SSean Hefty 2230cb164b8cSSean Hefty bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL); 2231e51060f0SSean Hefty if (!bind_list) 2232e51060f0SSean Hefty return -ENOMEM; 2233e51060f0SSean Hefty 22343b069c5dSTejun Heo ret = idr_alloc(ps, bind_list, snum, snum + 1, GFP_KERNEL); 22353b069c5dSTejun Heo if (ret < 0) 22363b069c5dSTejun Heo goto err; 2237e51060f0SSean Hefty 2238e51060f0SSean Hefty bind_list->ps = ps; 22393b069c5dSTejun Heo bind_list->port = (unsigned short)ret; 2240e51060f0SSean Hefty cma_bind_port(bind_list, id_priv); 2241e51060f0SSean Hefty return 0; 22423b069c5dSTejun Heo err: 2243aedec080SSean Hefty kfree(bind_list); 22443b069c5dSTejun Heo return ret == -ENOSPC ? -EADDRNOTAVAIL : ret; 2245aedec080SSean Hefty } 2246aedec080SSean Hefty 2247aedec080SSean Hefty static int cma_alloc_any_port(struct idr *ps, struct rdma_id_private *id_priv) 2248aedec080SSean Hefty { 22495d7220e8STetsuo Handa static unsigned int last_used_port; 22505d7220e8STetsuo Handa int low, high, remaining; 22515d7220e8STetsuo Handa unsigned int rover; 2252aedec080SSean Hefty 2253227b60f5SStephen Hemminger inet_get_local_port_range(&low, &high); 22545d7220e8STetsuo Handa remaining = (high - low) + 1; 22555d7220e8STetsuo Handa rover = net_random() % remaining + low; 22565d7220e8STetsuo Handa retry: 22575d7220e8STetsuo Handa if (last_used_port != rover && 22585d7220e8STetsuo Handa !idr_find(ps, (unsigned short) rover)) { 22595d7220e8STetsuo Handa int ret = cma_alloc_port(ps, id_priv, rover); 22605d7220e8STetsuo Handa /* 22615d7220e8STetsuo Handa * Remember previously used port number in order to avoid 22625d7220e8STetsuo Handa * re-using same port immediately after it is closed. 22635d7220e8STetsuo Handa */ 22645d7220e8STetsuo Handa if (!ret) 22655d7220e8STetsuo Handa last_used_port = rover; 22665d7220e8STetsuo Handa if (ret != -EADDRNOTAVAIL) 22675d7220e8STetsuo Handa return ret; 22685d7220e8STetsuo Handa } 22695d7220e8STetsuo Handa if (--remaining) { 22705d7220e8STetsuo Handa rover++; 22715d7220e8STetsuo Handa if ((rover < low) || (rover > high)) 22725d7220e8STetsuo Handa rover = low; 2273aedec080SSean Hefty goto retry; 2274aedec080SSean Hefty } 22755d7220e8STetsuo Handa return -EADDRNOTAVAIL; 2276e51060f0SSean Hefty } 2277e51060f0SSean Hefty 2278a9bb7912SHefty, Sean /* 2279a9bb7912SHefty, Sean * Check that the requested port is available. This is called when trying to 2280a9bb7912SHefty, Sean * bind to a specific port, or when trying to listen on a bound port. In 2281a9bb7912SHefty, Sean * the latter case, the provided id_priv may already be on the bind_list, but 2282a9bb7912SHefty, Sean * we still need to check that it's okay to start listening. 2283a9bb7912SHefty, Sean */ 2284a9bb7912SHefty, Sean static int cma_check_port(struct rdma_bind_list *bind_list, 2285a9bb7912SHefty, Sean struct rdma_id_private *id_priv, uint8_t reuseaddr) 2286e51060f0SSean Hefty { 2287e51060f0SSean Hefty struct rdma_id_private *cur_id; 228843b752daSHefty, Sean struct sockaddr *addr, *cur_addr; 2289e51060f0SSean Hefty 2290f4753834SSean Hefty addr = cma_src_addr(id_priv); 2291b67bfe0dSSasha Levin hlist_for_each_entry(cur_id, &bind_list->owners, node) { 2292a9bb7912SHefty, Sean if (id_priv == cur_id) 2293a9bb7912SHefty, Sean continue; 2294a9bb7912SHefty, Sean 22955b0ec991SSean Hefty if ((cur_id->state != RDMA_CM_LISTEN) && reuseaddr && 22965b0ec991SSean Hefty cur_id->reuseaddr) 22975b0ec991SSean Hefty continue; 22985b0ec991SSean Hefty 2299f4753834SSean Hefty cur_addr = cma_src_addr(cur_id); 23005b0ec991SSean Hefty if (id_priv->afonly && cur_id->afonly && 23015b0ec991SSean Hefty (addr->sa_family != cur_addr->sa_family)) 23025b0ec991SSean Hefty continue; 23035b0ec991SSean Hefty 23045b0ec991SSean Hefty if (cma_any_addr(addr) || cma_any_addr(cur_addr)) 2305e51060f0SSean Hefty return -EADDRNOTAVAIL; 2306e51060f0SSean Hefty 230743b752daSHefty, Sean if (!cma_addr_cmp(addr, cur_addr)) 2308e51060f0SSean Hefty return -EADDRINUSE; 2309e51060f0SSean Hefty } 2310e51060f0SSean Hefty return 0; 2311e51060f0SSean Hefty } 2312e51060f0SSean Hefty 2313a9bb7912SHefty, Sean static int cma_use_port(struct idr *ps, struct rdma_id_private *id_priv) 2314a9bb7912SHefty, Sean { 2315a9bb7912SHefty, Sean struct rdma_bind_list *bind_list; 2316a9bb7912SHefty, Sean unsigned short snum; 2317a9bb7912SHefty, Sean int ret; 2318a9bb7912SHefty, Sean 2319f4753834SSean Hefty snum = ntohs(cma_port(cma_src_addr(id_priv))); 2320a9bb7912SHefty, Sean if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) 2321a9bb7912SHefty, Sean return -EACCES; 2322a9bb7912SHefty, Sean 2323a9bb7912SHefty, Sean bind_list = idr_find(ps, snum); 2324a9bb7912SHefty, Sean if (!bind_list) { 2325a9bb7912SHefty, Sean ret = cma_alloc_port(ps, id_priv, snum); 2326a9bb7912SHefty, Sean } else { 2327a9bb7912SHefty, Sean ret = cma_check_port(bind_list, id_priv, id_priv->reuseaddr); 2328a9bb7912SHefty, Sean if (!ret) 2329a9bb7912SHefty, Sean cma_bind_port(bind_list, id_priv); 2330a9bb7912SHefty, Sean } 2331a9bb7912SHefty, Sean return ret; 2332a9bb7912SHefty, Sean } 2333a9bb7912SHefty, Sean 2334a9bb7912SHefty, Sean static int cma_bind_listen(struct rdma_id_private *id_priv) 2335a9bb7912SHefty, Sean { 2336a9bb7912SHefty, Sean struct rdma_bind_list *bind_list = id_priv->bind_list; 2337a9bb7912SHefty, Sean int ret = 0; 2338a9bb7912SHefty, Sean 2339a9bb7912SHefty, Sean mutex_lock(&lock); 2340a9bb7912SHefty, Sean if (bind_list->owners.first->next) 2341a9bb7912SHefty, Sean ret = cma_check_port(bind_list, id_priv, 0); 2342a9bb7912SHefty, Sean mutex_unlock(&lock); 2343a9bb7912SHefty, Sean return ret; 2344a9bb7912SHefty, Sean } 2345a9bb7912SHefty, Sean 234658afdcb7SSean Hefty static struct idr *cma_select_inet_ps(struct rdma_id_private *id_priv) 234758afdcb7SSean Hefty { 234858afdcb7SSean Hefty switch (id_priv->id.ps) { 234958afdcb7SSean Hefty case RDMA_PS_SDP: 235058afdcb7SSean Hefty return &sdp_ps; 235158afdcb7SSean Hefty case RDMA_PS_TCP: 235258afdcb7SSean Hefty return &tcp_ps; 235358afdcb7SSean Hefty case RDMA_PS_UDP: 235458afdcb7SSean Hefty return &udp_ps; 235558afdcb7SSean Hefty case RDMA_PS_IPOIB: 235658afdcb7SSean Hefty return &ipoib_ps; 235758afdcb7SSean Hefty case RDMA_PS_IB: 235858afdcb7SSean Hefty return &ib_ps; 235958afdcb7SSean Hefty default: 236058afdcb7SSean Hefty return NULL; 236158afdcb7SSean Hefty } 236258afdcb7SSean Hefty } 236358afdcb7SSean Hefty 236458afdcb7SSean Hefty static struct idr *cma_select_ib_ps(struct rdma_id_private *id_priv) 236558afdcb7SSean Hefty { 236658afdcb7SSean Hefty struct idr *ps = NULL; 236758afdcb7SSean Hefty struct sockaddr_ib *sib; 236858afdcb7SSean Hefty u64 sid_ps, mask, sid; 236958afdcb7SSean Hefty 2370f4753834SSean Hefty sib = (struct sockaddr_ib *) cma_src_addr(id_priv); 237158afdcb7SSean Hefty mask = be64_to_cpu(sib->sib_sid_mask) & RDMA_IB_IP_PS_MASK; 237258afdcb7SSean Hefty sid = be64_to_cpu(sib->sib_sid) & mask; 237358afdcb7SSean Hefty 237458afdcb7SSean Hefty if ((id_priv->id.ps == RDMA_PS_IB) && (sid == (RDMA_IB_IP_PS_IB & mask))) { 237558afdcb7SSean Hefty sid_ps = RDMA_IB_IP_PS_IB; 237658afdcb7SSean Hefty ps = &ib_ps; 237758afdcb7SSean Hefty } else if (((id_priv->id.ps == RDMA_PS_IB) || (id_priv->id.ps == RDMA_PS_TCP)) && 237858afdcb7SSean Hefty (sid == (RDMA_IB_IP_PS_TCP & mask))) { 237958afdcb7SSean Hefty sid_ps = RDMA_IB_IP_PS_TCP; 238058afdcb7SSean Hefty ps = &tcp_ps; 238158afdcb7SSean Hefty } else if (((id_priv->id.ps == RDMA_PS_IB) || (id_priv->id.ps == RDMA_PS_UDP)) && 238258afdcb7SSean Hefty (sid == (RDMA_IB_IP_PS_UDP & mask))) { 238358afdcb7SSean Hefty sid_ps = RDMA_IB_IP_PS_UDP; 238458afdcb7SSean Hefty ps = &udp_ps; 238558afdcb7SSean Hefty } 238658afdcb7SSean Hefty 238758afdcb7SSean Hefty if (ps) { 238858afdcb7SSean Hefty sib->sib_sid = cpu_to_be64(sid_ps | ntohs(cma_port((struct sockaddr *) sib))); 238958afdcb7SSean Hefty sib->sib_sid_mask = cpu_to_be64(RDMA_IB_IP_PS_MASK | 239058afdcb7SSean Hefty be64_to_cpu(sib->sib_sid_mask)); 239158afdcb7SSean Hefty } 239258afdcb7SSean Hefty return ps; 239358afdcb7SSean Hefty } 239458afdcb7SSean Hefty 2395e51060f0SSean Hefty static int cma_get_port(struct rdma_id_private *id_priv) 2396e51060f0SSean Hefty { 2397e51060f0SSean Hefty struct idr *ps; 2398e51060f0SSean Hefty int ret; 2399e51060f0SSean Hefty 2400f4753834SSean Hefty if (cma_family(id_priv) != AF_IB) 240158afdcb7SSean Hefty ps = cma_select_inet_ps(id_priv); 240258afdcb7SSean Hefty else 240358afdcb7SSean Hefty ps = cma_select_ib_ps(id_priv); 240458afdcb7SSean Hefty if (!ps) 2405e51060f0SSean Hefty return -EPROTONOSUPPORT; 2406e51060f0SSean Hefty 2407e51060f0SSean Hefty mutex_lock(&lock); 2408f4753834SSean Hefty if (cma_any_port(cma_src_addr(id_priv))) 2409aedec080SSean Hefty ret = cma_alloc_any_port(ps, id_priv); 2410e51060f0SSean Hefty else 2411e51060f0SSean Hefty ret = cma_use_port(ps, id_priv); 2412e51060f0SSean Hefty mutex_unlock(&lock); 2413e51060f0SSean Hefty 2414e51060f0SSean Hefty return ret; 2415e51060f0SSean Hefty } 2416e51060f0SSean Hefty 2417d14714dfSSean Hefty static int cma_check_linklocal(struct rdma_dev_addr *dev_addr, 2418d14714dfSSean Hefty struct sockaddr *addr) 2419d14714dfSSean Hefty { 2420d90f9b35SRoland Dreier #if IS_ENABLED(CONFIG_IPV6) 2421d14714dfSSean Hefty struct sockaddr_in6 *sin6; 2422d14714dfSSean Hefty 2423d14714dfSSean Hefty if (addr->sa_family != AF_INET6) 2424d14714dfSSean Hefty return 0; 2425d14714dfSSean Hefty 2426d14714dfSSean Hefty sin6 = (struct sockaddr_in6 *) addr; 2427d14714dfSSean Hefty if ((ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) && 2428d14714dfSSean Hefty !sin6->sin6_scope_id) 2429d14714dfSSean Hefty return -EINVAL; 2430d14714dfSSean Hefty 2431d14714dfSSean Hefty dev_addr->bound_dev_if = sin6->sin6_scope_id; 2432d14714dfSSean Hefty #endif 2433d14714dfSSean Hefty return 0; 2434d14714dfSSean Hefty } 2435d14714dfSSean Hefty 2436a9bb7912SHefty, Sean int rdma_listen(struct rdma_cm_id *id, int backlog) 2437a9bb7912SHefty, Sean { 2438a9bb7912SHefty, Sean struct rdma_id_private *id_priv; 2439a9bb7912SHefty, Sean int ret; 2440a9bb7912SHefty, Sean 2441a9bb7912SHefty, Sean id_priv = container_of(id, struct rdma_id_private, id); 2442550e5ca7SNir Muchtar if (id_priv->state == RDMA_CM_IDLE) { 2443f4753834SSean Hefty id->route.addr.src_addr.ss_family = AF_INET; 2444f4753834SSean Hefty ret = rdma_bind_addr(id, cma_src_addr(id_priv)); 2445a9bb7912SHefty, Sean if (ret) 2446a9bb7912SHefty, Sean return ret; 2447a9bb7912SHefty, Sean } 2448a9bb7912SHefty, Sean 2449550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_LISTEN)) 2450a9bb7912SHefty, Sean return -EINVAL; 2451a9bb7912SHefty, Sean 2452a9bb7912SHefty, Sean if (id_priv->reuseaddr) { 2453a9bb7912SHefty, Sean ret = cma_bind_listen(id_priv); 2454a9bb7912SHefty, Sean if (ret) 2455a9bb7912SHefty, Sean goto err; 2456a9bb7912SHefty, Sean } 2457a9bb7912SHefty, Sean 2458a9bb7912SHefty, Sean id_priv->backlog = backlog; 2459a9bb7912SHefty, Sean if (id->device) { 2460a9bb7912SHefty, Sean switch (rdma_node_get_transport(id->device->node_type)) { 2461a9bb7912SHefty, Sean case RDMA_TRANSPORT_IB: 2462a9bb7912SHefty, Sean ret = cma_ib_listen(id_priv); 2463a9bb7912SHefty, Sean if (ret) 2464a9bb7912SHefty, Sean goto err; 2465a9bb7912SHefty, Sean break; 2466a9bb7912SHefty, Sean case RDMA_TRANSPORT_IWARP: 2467a9bb7912SHefty, Sean ret = cma_iw_listen(id_priv, backlog); 2468a9bb7912SHefty, Sean if (ret) 2469a9bb7912SHefty, Sean goto err; 2470a9bb7912SHefty, Sean break; 2471a9bb7912SHefty, Sean default: 2472a9bb7912SHefty, Sean ret = -ENOSYS; 2473a9bb7912SHefty, Sean goto err; 2474a9bb7912SHefty, Sean } 2475a9bb7912SHefty, Sean } else 2476a9bb7912SHefty, Sean cma_listen_on_all(id_priv); 2477a9bb7912SHefty, Sean 2478a9bb7912SHefty, Sean return 0; 2479a9bb7912SHefty, Sean err: 2480a9bb7912SHefty, Sean id_priv->backlog = 0; 2481550e5ca7SNir Muchtar cma_comp_exch(id_priv, RDMA_CM_LISTEN, RDMA_CM_ADDR_BOUND); 2482a9bb7912SHefty, Sean return ret; 2483a9bb7912SHefty, Sean } 2484a9bb7912SHefty, Sean EXPORT_SYMBOL(rdma_listen); 2485a9bb7912SHefty, Sean 2486e51060f0SSean Hefty int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr) 2487e51060f0SSean Hefty { 2488e51060f0SSean Hefty struct rdma_id_private *id_priv; 2489e51060f0SSean Hefty int ret; 2490e51060f0SSean Hefty 2491680f920aSSean Hefty if (addr->sa_family != AF_INET && addr->sa_family != AF_INET6 && 2492680f920aSSean Hefty addr->sa_family != AF_IB) 2493e51060f0SSean Hefty return -EAFNOSUPPORT; 2494e51060f0SSean Hefty 2495e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 2496550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_IDLE, RDMA_CM_ADDR_BOUND)) 2497e51060f0SSean Hefty return -EINVAL; 2498e51060f0SSean Hefty 2499d14714dfSSean Hefty ret = cma_check_linklocal(&id->route.addr.dev_addr, addr); 2500d14714dfSSean Hefty if (ret) 2501d14714dfSSean Hefty goto err1; 2502d14714dfSSean Hefty 25038523c048SSean Hefty if (!cma_any_addr(addr)) { 2504680f920aSSean Hefty ret = cma_translate_addr(addr, &id->route.addr.dev_addr); 2505255d0c14SKrishna Kumar if (ret) 2506255d0c14SKrishna Kumar goto err1; 2507255d0c14SKrishna Kumar 2508e51060f0SSean Hefty ret = cma_acquire_dev(id_priv); 2509e51060f0SSean Hefty if (ret) 2510255d0c14SKrishna Kumar goto err1; 2511e51060f0SSean Hefty } 2512e51060f0SSean Hefty 2513f4753834SSean Hefty memcpy(cma_src_addr(id_priv), addr, rdma_addr_size(addr)); 251468602120SSean Hefty if (!(id_priv->options & (1 << CMA_OPTION_AFONLY))) { 25155b0ec991SSean Hefty if (addr->sa_family == AF_INET) 25165b0ec991SSean Hefty id_priv->afonly = 1; 25175b0ec991SSean Hefty #if IS_ENABLED(CONFIG_IPV6) 25185b0ec991SSean Hefty else if (addr->sa_family == AF_INET6) 25195b0ec991SSean Hefty id_priv->afonly = init_net.ipv6.sysctl.bindv6only; 25205b0ec991SSean Hefty #endif 252168602120SSean Hefty } 2522e51060f0SSean Hefty ret = cma_get_port(id_priv); 2523e51060f0SSean Hefty if (ret) 2524255d0c14SKrishna Kumar goto err2; 2525e51060f0SSean Hefty 2526e51060f0SSean Hefty return 0; 2527255d0c14SKrishna Kumar err2: 2528a396d43aSSean Hefty if (id_priv->cma_dev) 2529a396d43aSSean Hefty cma_release_dev(id_priv); 2530255d0c14SKrishna Kumar err1: 2531550e5ca7SNir Muchtar cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_IDLE); 2532e51060f0SSean Hefty return ret; 2533e51060f0SSean Hefty } 2534e51060f0SSean Hefty EXPORT_SYMBOL(rdma_bind_addr); 2535e51060f0SSean Hefty 2536f4753834SSean Hefty static int cma_format_hdr(void *hdr, struct rdma_id_private *id_priv) 2537e51060f0SSean Hefty { 2538e51060f0SSean Hefty struct cma_hdr *cma_hdr; 2539e51060f0SSean Hefty struct sdp_hh *sdp_hdr; 2540e51060f0SSean Hefty 2541f4753834SSean Hefty if (cma_family(id_priv) == AF_INET) { 25421f5175adSAleksey Senin struct sockaddr_in *src4, *dst4; 25431f5175adSAleksey Senin 2544f4753834SSean Hefty src4 = (struct sockaddr_in *) cma_src_addr(id_priv); 2545f4753834SSean Hefty dst4 = (struct sockaddr_in *) cma_dst_addr(id_priv); 2546e51060f0SSean Hefty 2547f4753834SSean Hefty switch (id_priv->id.ps) { 2548e51060f0SSean Hefty case RDMA_PS_SDP: 2549e51060f0SSean Hefty sdp_hdr = hdr; 2550e51060f0SSean Hefty if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION) 2551e51060f0SSean Hefty return -EINVAL; 2552e51060f0SSean Hefty sdp_set_ip_ver(sdp_hdr, 4); 2553e51060f0SSean Hefty sdp_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr; 2554e51060f0SSean Hefty sdp_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr; 2555e51060f0SSean Hefty sdp_hdr->port = src4->sin_port; 2556e51060f0SSean Hefty break; 2557e51060f0SSean Hefty default: 2558e51060f0SSean Hefty cma_hdr = hdr; 2559e51060f0SSean Hefty cma_hdr->cma_version = CMA_VERSION; 2560e51060f0SSean Hefty cma_set_ip_ver(cma_hdr, 4); 2561e51060f0SSean Hefty cma_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr; 2562e51060f0SSean Hefty cma_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr; 2563e51060f0SSean Hefty cma_hdr->port = src4->sin_port; 2564e51060f0SSean Hefty break; 2565e51060f0SSean Hefty } 25661f5175adSAleksey Senin } else { 25671f5175adSAleksey Senin struct sockaddr_in6 *src6, *dst6; 25681f5175adSAleksey Senin 2569f4753834SSean Hefty src6 = (struct sockaddr_in6 *) cma_src_addr(id_priv); 2570f4753834SSean Hefty dst6 = (struct sockaddr_in6 *) cma_dst_addr(id_priv); 25711f5175adSAleksey Senin 2572f4753834SSean Hefty switch (id_priv->id.ps) { 25731f5175adSAleksey Senin case RDMA_PS_SDP: 25741f5175adSAleksey Senin sdp_hdr = hdr; 25751f5175adSAleksey Senin if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION) 25761f5175adSAleksey Senin return -EINVAL; 25771f5175adSAleksey Senin sdp_set_ip_ver(sdp_hdr, 6); 25781f5175adSAleksey Senin sdp_hdr->src_addr.ip6 = src6->sin6_addr; 25791f5175adSAleksey Senin sdp_hdr->dst_addr.ip6 = dst6->sin6_addr; 25801f5175adSAleksey Senin sdp_hdr->port = src6->sin6_port; 25811f5175adSAleksey Senin break; 25821f5175adSAleksey Senin default: 25831f5175adSAleksey Senin cma_hdr = hdr; 25841f5175adSAleksey Senin cma_hdr->cma_version = CMA_VERSION; 25851f5175adSAleksey Senin cma_set_ip_ver(cma_hdr, 6); 25861f5175adSAleksey Senin cma_hdr->src_addr.ip6 = src6->sin6_addr; 25871f5175adSAleksey Senin cma_hdr->dst_addr.ip6 = dst6->sin6_addr; 25881f5175adSAleksey Senin cma_hdr->port = src6->sin6_port; 25891f5175adSAleksey Senin break; 25901f5175adSAleksey Senin } 25911f5175adSAleksey Senin } 2592e51060f0SSean Hefty return 0; 2593e51060f0SSean Hefty } 2594e51060f0SSean Hefty 2595628e5f6dSSean Hefty static int cma_sidr_rep_handler(struct ib_cm_id *cm_id, 2596628e5f6dSSean Hefty struct ib_cm_event *ib_event) 2597628e5f6dSSean Hefty { 2598628e5f6dSSean Hefty struct rdma_id_private *id_priv = cm_id->context; 2599628e5f6dSSean Hefty struct rdma_cm_event event; 2600628e5f6dSSean Hefty struct ib_cm_sidr_rep_event_param *rep = &ib_event->param.sidr_rep_rcvd; 2601628e5f6dSSean Hefty int ret = 0; 2602628e5f6dSSean Hefty 2603550e5ca7SNir Muchtar if (cma_disable_callback(id_priv, RDMA_CM_CONNECT)) 26048aa08602SSean Hefty return 0; 2605628e5f6dSSean Hefty 26068aa08602SSean Hefty memset(&event, 0, sizeof event); 2607628e5f6dSSean Hefty switch (ib_event->event) { 2608628e5f6dSSean Hefty case IB_CM_SIDR_REQ_ERROR: 2609628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_UNREACHABLE; 2610628e5f6dSSean Hefty event.status = -ETIMEDOUT; 2611628e5f6dSSean Hefty break; 2612628e5f6dSSean Hefty case IB_CM_SIDR_REP_RECEIVED: 2613628e5f6dSSean Hefty event.param.ud.private_data = ib_event->private_data; 2614628e5f6dSSean Hefty event.param.ud.private_data_len = IB_CM_SIDR_REP_PRIVATE_DATA_SIZE; 2615628e5f6dSSean Hefty if (rep->status != IB_SIDR_SUCCESS) { 2616628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_UNREACHABLE; 2617628e5f6dSSean Hefty event.status = ib_event->param.sidr_rep_rcvd.status; 2618628e5f6dSSean Hefty break; 2619628e5f6dSSean Hefty } 2620d2ca39f2SYossi Etigin ret = cma_set_qkey(id_priv); 2621d2ca39f2SYossi Etigin if (ret) { 2622d2ca39f2SYossi Etigin event.event = RDMA_CM_EVENT_ADDR_ERROR; 2623d2ca39f2SYossi Etigin event.status = -EINVAL; 2624d2ca39f2SYossi Etigin break; 2625d2ca39f2SYossi Etigin } 2626c8f6a362SSean Hefty if (id_priv->qkey != rep->qkey) { 2627628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_UNREACHABLE; 2628628e5f6dSSean Hefty event.status = -EINVAL; 2629628e5f6dSSean Hefty break; 2630628e5f6dSSean Hefty } 2631628e5f6dSSean Hefty ib_init_ah_from_path(id_priv->id.device, id_priv->id.port_num, 2632628e5f6dSSean Hefty id_priv->id.route.path_rec, 2633628e5f6dSSean Hefty &event.param.ud.ah_attr); 2634628e5f6dSSean Hefty event.param.ud.qp_num = rep->qpn; 2635628e5f6dSSean Hefty event.param.ud.qkey = rep->qkey; 2636628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_ESTABLISHED; 2637628e5f6dSSean Hefty event.status = 0; 2638628e5f6dSSean Hefty break; 2639628e5f6dSSean Hefty default: 2640468f2239SRoland Dreier printk(KERN_ERR "RDMA CMA: unexpected IB CM event: %d\n", 2641628e5f6dSSean Hefty ib_event->event); 2642628e5f6dSSean Hefty goto out; 2643628e5f6dSSean Hefty } 2644628e5f6dSSean Hefty 2645628e5f6dSSean Hefty ret = id_priv->id.event_handler(&id_priv->id, &event); 2646628e5f6dSSean Hefty if (ret) { 2647628e5f6dSSean Hefty /* Destroy the CM ID by returning a non-zero value. */ 2648628e5f6dSSean Hefty id_priv->cm_id.ib = NULL; 2649550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 2650de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 2651628e5f6dSSean Hefty rdma_destroy_id(&id_priv->id); 2652628e5f6dSSean Hefty return ret; 2653628e5f6dSSean Hefty } 2654628e5f6dSSean Hefty out: 2655de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 2656628e5f6dSSean Hefty return ret; 2657628e5f6dSSean Hefty } 2658628e5f6dSSean Hefty 2659628e5f6dSSean Hefty static int cma_resolve_ib_udp(struct rdma_id_private *id_priv, 2660628e5f6dSSean Hefty struct rdma_conn_param *conn_param) 2661628e5f6dSSean Hefty { 2662628e5f6dSSean Hefty struct ib_cm_sidr_req_param req; 26630c9361fcSJack Morgenstein struct ib_cm_id *id; 2664628e5f6dSSean Hefty int ret; 2665628e5f6dSSean Hefty 2666628e5f6dSSean Hefty req.private_data_len = sizeof(struct cma_hdr) + 2667628e5f6dSSean Hefty conn_param->private_data_len; 266804ded167SSean Hefty if (req.private_data_len < conn_param->private_data_len) 266904ded167SSean Hefty return -EINVAL; 267004ded167SSean Hefty 2671628e5f6dSSean Hefty req.private_data = kzalloc(req.private_data_len, GFP_ATOMIC); 2672628e5f6dSSean Hefty if (!req.private_data) 2673628e5f6dSSean Hefty return -ENOMEM; 2674628e5f6dSSean Hefty 2675628e5f6dSSean Hefty if (conn_param->private_data && conn_param->private_data_len) 2676628e5f6dSSean Hefty memcpy((void *) req.private_data + sizeof(struct cma_hdr), 2677628e5f6dSSean Hefty conn_param->private_data, conn_param->private_data_len); 2678628e5f6dSSean Hefty 2679f4753834SSean Hefty ret = cma_format_hdr((void *) req.private_data, id_priv); 2680628e5f6dSSean Hefty if (ret) 2681628e5f6dSSean Hefty goto out; 2682628e5f6dSSean Hefty 26830c9361fcSJack Morgenstein id = ib_create_cm_id(id_priv->id.device, cma_sidr_rep_handler, 26840c9361fcSJack Morgenstein id_priv); 26850c9361fcSJack Morgenstein if (IS_ERR(id)) { 26860c9361fcSJack Morgenstein ret = PTR_ERR(id); 2687628e5f6dSSean Hefty goto out; 2688628e5f6dSSean Hefty } 26890c9361fcSJack Morgenstein id_priv->cm_id.ib = id; 2690628e5f6dSSean Hefty 2691f4753834SSean Hefty req.path = id_priv->id.route.path_rec; 2692f4753834SSean Hefty req.service_id = cma_get_service_id(id_priv->id.ps, cma_dst_addr(id_priv)); 2693628e5f6dSSean Hefty req.timeout_ms = 1 << (CMA_CM_RESPONSE_TIMEOUT - 8); 2694628e5f6dSSean Hefty req.max_cm_retries = CMA_MAX_CM_RETRIES; 2695628e5f6dSSean Hefty 2696628e5f6dSSean Hefty ret = ib_send_cm_sidr_req(id_priv->cm_id.ib, &req); 2697628e5f6dSSean Hefty if (ret) { 2698628e5f6dSSean Hefty ib_destroy_cm_id(id_priv->cm_id.ib); 2699628e5f6dSSean Hefty id_priv->cm_id.ib = NULL; 2700628e5f6dSSean Hefty } 2701628e5f6dSSean Hefty out: 2702628e5f6dSSean Hefty kfree(req.private_data); 2703628e5f6dSSean Hefty return ret; 2704628e5f6dSSean Hefty } 2705628e5f6dSSean Hefty 2706e51060f0SSean Hefty static int cma_connect_ib(struct rdma_id_private *id_priv, 2707e51060f0SSean Hefty struct rdma_conn_param *conn_param) 2708e51060f0SSean Hefty { 2709e51060f0SSean Hefty struct ib_cm_req_param req; 2710e51060f0SSean Hefty struct rdma_route *route; 2711e51060f0SSean Hefty void *private_data; 27120c9361fcSJack Morgenstein struct ib_cm_id *id; 2713e51060f0SSean Hefty int offset, ret; 2714e51060f0SSean Hefty 2715e51060f0SSean Hefty memset(&req, 0, sizeof req); 2716e51060f0SSean Hefty offset = cma_user_data_offset(id_priv->id.ps); 2717e51060f0SSean Hefty req.private_data_len = offset + conn_param->private_data_len; 271804ded167SSean Hefty if (req.private_data_len < conn_param->private_data_len) 271904ded167SSean Hefty return -EINVAL; 272004ded167SSean Hefty 2721e51060f0SSean Hefty private_data = kzalloc(req.private_data_len, GFP_ATOMIC); 2722e51060f0SSean Hefty if (!private_data) 2723e51060f0SSean Hefty return -ENOMEM; 2724e51060f0SSean Hefty 2725e51060f0SSean Hefty if (conn_param->private_data && conn_param->private_data_len) 2726e51060f0SSean Hefty memcpy(private_data + offset, conn_param->private_data, 2727e51060f0SSean Hefty conn_param->private_data_len); 2728e51060f0SSean Hefty 27290c9361fcSJack Morgenstein id = ib_create_cm_id(id_priv->id.device, cma_ib_handler, id_priv); 27300c9361fcSJack Morgenstein if (IS_ERR(id)) { 27310c9361fcSJack Morgenstein ret = PTR_ERR(id); 2732e51060f0SSean Hefty goto out; 2733e51060f0SSean Hefty } 27340c9361fcSJack Morgenstein id_priv->cm_id.ib = id; 2735e51060f0SSean Hefty 2736e51060f0SSean Hefty route = &id_priv->id.route; 2737f4753834SSean Hefty ret = cma_format_hdr(private_data, id_priv); 2738e51060f0SSean Hefty if (ret) 2739e51060f0SSean Hefty goto out; 2740e51060f0SSean Hefty req.private_data = private_data; 2741e51060f0SSean Hefty 2742e51060f0SSean Hefty req.primary_path = &route->path_rec[0]; 2743e51060f0SSean Hefty if (route->num_paths == 2) 2744e51060f0SSean Hefty req.alternate_path = &route->path_rec[1]; 2745e51060f0SSean Hefty 2746f4753834SSean Hefty req.service_id = cma_get_service_id(id_priv->id.ps, cma_dst_addr(id_priv)); 2747e51060f0SSean Hefty req.qp_num = id_priv->qp_num; 274818c441a6SSean Hefty req.qp_type = id_priv->id.qp_type; 2749e51060f0SSean Hefty req.starting_psn = id_priv->seq_num; 2750e51060f0SSean Hefty req.responder_resources = conn_param->responder_resources; 2751e51060f0SSean Hefty req.initiator_depth = conn_param->initiator_depth; 2752e51060f0SSean Hefty req.flow_control = conn_param->flow_control; 27534ede178aSSean Hefty req.retry_count = min_t(u8, 7, conn_param->retry_count); 27544ede178aSSean Hefty req.rnr_retry_count = min_t(u8, 7, conn_param->rnr_retry_count); 2755e51060f0SSean Hefty req.remote_cm_response_timeout = CMA_CM_RESPONSE_TIMEOUT; 2756e51060f0SSean Hefty req.local_cm_response_timeout = CMA_CM_RESPONSE_TIMEOUT; 2757e51060f0SSean Hefty req.max_cm_retries = CMA_MAX_CM_RETRIES; 2758e51060f0SSean Hefty req.srq = id_priv->srq ? 1 : 0; 2759e51060f0SSean Hefty 2760e51060f0SSean Hefty ret = ib_send_cm_req(id_priv->cm_id.ib, &req); 2761e51060f0SSean Hefty out: 27620c9361fcSJack Morgenstein if (ret && !IS_ERR(id)) { 27630c9361fcSJack Morgenstein ib_destroy_cm_id(id); 2764675a027cSKrishna Kumar id_priv->cm_id.ib = NULL; 2765675a027cSKrishna Kumar } 2766675a027cSKrishna Kumar 2767e51060f0SSean Hefty kfree(private_data); 2768e51060f0SSean Hefty return ret; 2769e51060f0SSean Hefty } 2770e51060f0SSean Hefty 277107ebafbaSTom Tucker static int cma_connect_iw(struct rdma_id_private *id_priv, 277207ebafbaSTom Tucker struct rdma_conn_param *conn_param) 277307ebafbaSTom Tucker { 277407ebafbaSTom Tucker struct iw_cm_id *cm_id; 277507ebafbaSTom Tucker struct sockaddr_in* sin; 277607ebafbaSTom Tucker int ret; 277707ebafbaSTom Tucker struct iw_cm_conn_param iw_param; 277807ebafbaSTom Tucker 277907ebafbaSTom Tucker cm_id = iw_create_cm_id(id_priv->id.device, cma_iw_handler, id_priv); 27800c9361fcSJack Morgenstein if (IS_ERR(cm_id)) 27810c9361fcSJack Morgenstein return PTR_ERR(cm_id); 278207ebafbaSTom Tucker 278307ebafbaSTom Tucker id_priv->cm_id.iw = cm_id; 278407ebafbaSTom Tucker 2785f4753834SSean Hefty sin = (struct sockaddr_in *) cma_src_addr(id_priv); 278607ebafbaSTom Tucker cm_id->local_addr = *sin; 278707ebafbaSTom Tucker 2788f4753834SSean Hefty sin = (struct sockaddr_in *) cma_dst_addr(id_priv); 278907ebafbaSTom Tucker cm_id->remote_addr = *sin; 279007ebafbaSTom Tucker 27915851bb89SSean Hefty ret = cma_modify_qp_rtr(id_priv, conn_param); 2792675a027cSKrishna Kumar if (ret) 2793675a027cSKrishna Kumar goto out; 279407ebafbaSTom Tucker 2795f45ee80eSHefty, Sean if (conn_param) { 279607ebafbaSTom Tucker iw_param.ord = conn_param->initiator_depth; 279707ebafbaSTom Tucker iw_param.ird = conn_param->responder_resources; 279807ebafbaSTom Tucker iw_param.private_data = conn_param->private_data; 279907ebafbaSTom Tucker iw_param.private_data_len = conn_param->private_data_len; 2800f45ee80eSHefty, Sean iw_param.qpn = id_priv->id.qp ? id_priv->qp_num : conn_param->qp_num; 2801f45ee80eSHefty, Sean } else { 2802f45ee80eSHefty, Sean memset(&iw_param, 0, sizeof iw_param); 280307ebafbaSTom Tucker iw_param.qpn = id_priv->qp_num; 2804f45ee80eSHefty, Sean } 280507ebafbaSTom Tucker ret = iw_cm_connect(cm_id, &iw_param); 280607ebafbaSTom Tucker out: 28070c9361fcSJack Morgenstein if (ret) { 2808675a027cSKrishna Kumar iw_destroy_cm_id(cm_id); 2809675a027cSKrishna Kumar id_priv->cm_id.iw = NULL; 2810675a027cSKrishna Kumar } 281107ebafbaSTom Tucker return ret; 281207ebafbaSTom Tucker } 281307ebafbaSTom Tucker 2814e51060f0SSean Hefty int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param) 2815e51060f0SSean Hefty { 2816e51060f0SSean Hefty struct rdma_id_private *id_priv; 2817e51060f0SSean Hefty int ret; 2818e51060f0SSean Hefty 2819e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 2820550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_ROUTE_RESOLVED, RDMA_CM_CONNECT)) 2821e51060f0SSean Hefty return -EINVAL; 2822e51060f0SSean Hefty 2823e51060f0SSean Hefty if (!id->qp) { 2824e51060f0SSean Hefty id_priv->qp_num = conn_param->qp_num; 2825e51060f0SSean Hefty id_priv->srq = conn_param->srq; 2826e51060f0SSean Hefty } 2827e51060f0SSean Hefty 282807ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 282907ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 2830b26f9b99SSean Hefty if (id->qp_type == IB_QPT_UD) 2831628e5f6dSSean Hefty ret = cma_resolve_ib_udp(id_priv, conn_param); 2832628e5f6dSSean Hefty else 2833e51060f0SSean Hefty ret = cma_connect_ib(id_priv, conn_param); 2834e51060f0SSean Hefty break; 283507ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 283607ebafbaSTom Tucker ret = cma_connect_iw(id_priv, conn_param); 283707ebafbaSTom Tucker break; 2838e51060f0SSean Hefty default: 2839e51060f0SSean Hefty ret = -ENOSYS; 2840e51060f0SSean Hefty break; 2841e51060f0SSean Hefty } 2842e51060f0SSean Hefty if (ret) 2843e51060f0SSean Hefty goto err; 2844e51060f0SSean Hefty 2845e51060f0SSean Hefty return 0; 2846e51060f0SSean Hefty err: 2847550e5ca7SNir Muchtar cma_comp_exch(id_priv, RDMA_CM_CONNECT, RDMA_CM_ROUTE_RESOLVED); 2848e51060f0SSean Hefty return ret; 2849e51060f0SSean Hefty } 2850e51060f0SSean Hefty EXPORT_SYMBOL(rdma_connect); 2851e51060f0SSean Hefty 2852e51060f0SSean Hefty static int cma_accept_ib(struct rdma_id_private *id_priv, 2853e51060f0SSean Hefty struct rdma_conn_param *conn_param) 2854e51060f0SSean Hefty { 2855e51060f0SSean Hefty struct ib_cm_rep_param rep; 28565851bb89SSean Hefty int ret; 2857e51060f0SSean Hefty 28585851bb89SSean Hefty ret = cma_modify_qp_rtr(id_priv, conn_param); 2859e51060f0SSean Hefty if (ret) 28600fe313b0SSean Hefty goto out; 28610fe313b0SSean Hefty 28625851bb89SSean Hefty ret = cma_modify_qp_rts(id_priv, conn_param); 28630fe313b0SSean Hefty if (ret) 28640fe313b0SSean Hefty goto out; 28650fe313b0SSean Hefty 2866e51060f0SSean Hefty memset(&rep, 0, sizeof rep); 2867e51060f0SSean Hefty rep.qp_num = id_priv->qp_num; 2868e51060f0SSean Hefty rep.starting_psn = id_priv->seq_num; 2869e51060f0SSean Hefty rep.private_data = conn_param->private_data; 2870e51060f0SSean Hefty rep.private_data_len = conn_param->private_data_len; 2871e51060f0SSean Hefty rep.responder_resources = conn_param->responder_resources; 2872e51060f0SSean Hefty rep.initiator_depth = conn_param->initiator_depth; 2873e51060f0SSean Hefty rep.failover_accepted = 0; 2874e51060f0SSean Hefty rep.flow_control = conn_param->flow_control; 28754ede178aSSean Hefty rep.rnr_retry_count = min_t(u8, 7, conn_param->rnr_retry_count); 2876e51060f0SSean Hefty rep.srq = id_priv->srq ? 1 : 0; 2877e51060f0SSean Hefty 28780fe313b0SSean Hefty ret = ib_send_cm_rep(id_priv->cm_id.ib, &rep); 28790fe313b0SSean Hefty out: 28800fe313b0SSean Hefty return ret; 2881e51060f0SSean Hefty } 2882e51060f0SSean Hefty 288307ebafbaSTom Tucker static int cma_accept_iw(struct rdma_id_private *id_priv, 288407ebafbaSTom Tucker struct rdma_conn_param *conn_param) 288507ebafbaSTom Tucker { 288607ebafbaSTom Tucker struct iw_cm_conn_param iw_param; 288707ebafbaSTom Tucker int ret; 288807ebafbaSTom Tucker 28895851bb89SSean Hefty ret = cma_modify_qp_rtr(id_priv, conn_param); 289007ebafbaSTom Tucker if (ret) 289107ebafbaSTom Tucker return ret; 289207ebafbaSTom Tucker 289307ebafbaSTom Tucker iw_param.ord = conn_param->initiator_depth; 289407ebafbaSTom Tucker iw_param.ird = conn_param->responder_resources; 289507ebafbaSTom Tucker iw_param.private_data = conn_param->private_data; 289607ebafbaSTom Tucker iw_param.private_data_len = conn_param->private_data_len; 289707ebafbaSTom Tucker if (id_priv->id.qp) { 289807ebafbaSTom Tucker iw_param.qpn = id_priv->qp_num; 289907ebafbaSTom Tucker } else 290007ebafbaSTom Tucker iw_param.qpn = conn_param->qp_num; 290107ebafbaSTom Tucker 290207ebafbaSTom Tucker return iw_cm_accept(id_priv->cm_id.iw, &iw_param); 290307ebafbaSTom Tucker } 290407ebafbaSTom Tucker 2905628e5f6dSSean Hefty static int cma_send_sidr_rep(struct rdma_id_private *id_priv, 2906628e5f6dSSean Hefty enum ib_cm_sidr_status status, 2907628e5f6dSSean Hefty const void *private_data, int private_data_len) 2908628e5f6dSSean Hefty { 2909628e5f6dSSean Hefty struct ib_cm_sidr_rep_param rep; 2910d2ca39f2SYossi Etigin int ret; 2911628e5f6dSSean Hefty 2912628e5f6dSSean Hefty memset(&rep, 0, sizeof rep); 2913628e5f6dSSean Hefty rep.status = status; 2914628e5f6dSSean Hefty if (status == IB_SIDR_SUCCESS) { 2915d2ca39f2SYossi Etigin ret = cma_set_qkey(id_priv); 2916d2ca39f2SYossi Etigin if (ret) 2917d2ca39f2SYossi Etigin return ret; 2918628e5f6dSSean Hefty rep.qp_num = id_priv->qp_num; 2919c8f6a362SSean Hefty rep.qkey = id_priv->qkey; 2920628e5f6dSSean Hefty } 2921628e5f6dSSean Hefty rep.private_data = private_data; 2922628e5f6dSSean Hefty rep.private_data_len = private_data_len; 2923628e5f6dSSean Hefty 2924628e5f6dSSean Hefty return ib_send_cm_sidr_rep(id_priv->cm_id.ib, &rep); 2925628e5f6dSSean Hefty } 2926628e5f6dSSean Hefty 2927e51060f0SSean Hefty int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param) 2928e51060f0SSean Hefty { 2929e51060f0SSean Hefty struct rdma_id_private *id_priv; 2930e51060f0SSean Hefty int ret; 2931e51060f0SSean Hefty 2932e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 293383e9502dSNir Muchtar 293483e9502dSNir Muchtar id_priv->owner = task_pid_nr(current); 293583e9502dSNir Muchtar 2936550e5ca7SNir Muchtar if (!cma_comp(id_priv, RDMA_CM_CONNECT)) 2937e51060f0SSean Hefty return -EINVAL; 2938e51060f0SSean Hefty 2939e51060f0SSean Hefty if (!id->qp && conn_param) { 2940e51060f0SSean Hefty id_priv->qp_num = conn_param->qp_num; 2941e51060f0SSean Hefty id_priv->srq = conn_param->srq; 2942e51060f0SSean Hefty } 2943e51060f0SSean Hefty 294407ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 294507ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 2946f45ee80eSHefty, Sean if (id->qp_type == IB_QPT_UD) { 2947f45ee80eSHefty, Sean if (conn_param) 2948628e5f6dSSean Hefty ret = cma_send_sidr_rep(id_priv, IB_SIDR_SUCCESS, 2949628e5f6dSSean Hefty conn_param->private_data, 2950628e5f6dSSean Hefty conn_param->private_data_len); 2951f45ee80eSHefty, Sean else 2952f45ee80eSHefty, Sean ret = cma_send_sidr_rep(id_priv, IB_SIDR_SUCCESS, 2953f45ee80eSHefty, Sean NULL, 0); 2954f45ee80eSHefty, Sean } else { 2955f45ee80eSHefty, Sean if (conn_param) 2956e51060f0SSean Hefty ret = cma_accept_ib(id_priv, conn_param); 2957e51060f0SSean Hefty else 2958e51060f0SSean Hefty ret = cma_rep_recv(id_priv); 2959f45ee80eSHefty, Sean } 2960e51060f0SSean Hefty break; 296107ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 296207ebafbaSTom Tucker ret = cma_accept_iw(id_priv, conn_param); 296307ebafbaSTom Tucker break; 2964e51060f0SSean Hefty default: 2965e51060f0SSean Hefty ret = -ENOSYS; 2966e51060f0SSean Hefty break; 2967e51060f0SSean Hefty } 2968e51060f0SSean Hefty 2969e51060f0SSean Hefty if (ret) 2970e51060f0SSean Hefty goto reject; 2971e51060f0SSean Hefty 2972e51060f0SSean Hefty return 0; 2973e51060f0SSean Hefty reject: 2974c5483388SSean Hefty cma_modify_qp_err(id_priv); 2975e51060f0SSean Hefty rdma_reject(id, NULL, 0); 2976e51060f0SSean Hefty return ret; 2977e51060f0SSean Hefty } 2978e51060f0SSean Hefty EXPORT_SYMBOL(rdma_accept); 2979e51060f0SSean Hefty 29800fe313b0SSean Hefty int rdma_notify(struct rdma_cm_id *id, enum ib_event_type event) 29810fe313b0SSean Hefty { 29820fe313b0SSean Hefty struct rdma_id_private *id_priv; 29830fe313b0SSean Hefty int ret; 29840fe313b0SSean Hefty 29850fe313b0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 29860c9361fcSJack Morgenstein if (!id_priv->cm_id.ib) 29870fe313b0SSean Hefty return -EINVAL; 29880fe313b0SSean Hefty 29890fe313b0SSean Hefty switch (id->device->node_type) { 29900fe313b0SSean Hefty case RDMA_NODE_IB_CA: 29910fe313b0SSean Hefty ret = ib_cm_notify(id_priv->cm_id.ib, event); 29920fe313b0SSean Hefty break; 29930fe313b0SSean Hefty default: 29940fe313b0SSean Hefty ret = 0; 29950fe313b0SSean Hefty break; 29960fe313b0SSean Hefty } 29970fe313b0SSean Hefty return ret; 29980fe313b0SSean Hefty } 29990fe313b0SSean Hefty EXPORT_SYMBOL(rdma_notify); 30000fe313b0SSean Hefty 3001e51060f0SSean Hefty int rdma_reject(struct rdma_cm_id *id, const void *private_data, 3002e51060f0SSean Hefty u8 private_data_len) 3003e51060f0SSean Hefty { 3004e51060f0SSean Hefty struct rdma_id_private *id_priv; 3005e51060f0SSean Hefty int ret; 3006e51060f0SSean Hefty 3007e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 30080c9361fcSJack Morgenstein if (!id_priv->cm_id.ib) 3009e51060f0SSean Hefty return -EINVAL; 3010e51060f0SSean Hefty 301107ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 301207ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 3013b26f9b99SSean Hefty if (id->qp_type == IB_QPT_UD) 3014628e5f6dSSean Hefty ret = cma_send_sidr_rep(id_priv, IB_SIDR_REJECT, 3015e51060f0SSean Hefty private_data, private_data_len); 3016628e5f6dSSean Hefty else 3017628e5f6dSSean Hefty ret = ib_send_cm_rej(id_priv->cm_id.ib, 3018628e5f6dSSean Hefty IB_CM_REJ_CONSUMER_DEFINED, NULL, 3019628e5f6dSSean Hefty 0, private_data, private_data_len); 3020e51060f0SSean Hefty break; 302107ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 302207ebafbaSTom Tucker ret = iw_cm_reject(id_priv->cm_id.iw, 302307ebafbaSTom Tucker private_data, private_data_len); 302407ebafbaSTom Tucker break; 3025e51060f0SSean Hefty default: 3026e51060f0SSean Hefty ret = -ENOSYS; 3027e51060f0SSean Hefty break; 3028e51060f0SSean Hefty } 3029e51060f0SSean Hefty return ret; 3030e51060f0SSean Hefty } 3031e51060f0SSean Hefty EXPORT_SYMBOL(rdma_reject); 3032e51060f0SSean Hefty 3033e51060f0SSean Hefty int rdma_disconnect(struct rdma_cm_id *id) 3034e51060f0SSean Hefty { 3035e51060f0SSean Hefty struct rdma_id_private *id_priv; 3036e51060f0SSean Hefty int ret; 3037e51060f0SSean Hefty 3038e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 30390c9361fcSJack Morgenstein if (!id_priv->cm_id.ib) 3040e51060f0SSean Hefty return -EINVAL; 3041e51060f0SSean Hefty 304207ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 304307ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 3044c5483388SSean Hefty ret = cma_modify_qp_err(id_priv); 3045e51060f0SSean Hefty if (ret) 3046e51060f0SSean Hefty goto out; 3047e51060f0SSean Hefty /* Initiate or respond to a disconnect. */ 3048e51060f0SSean Hefty if (ib_send_cm_dreq(id_priv->cm_id.ib, NULL, 0)) 3049e51060f0SSean Hefty ib_send_cm_drep(id_priv->cm_id.ib, NULL, 0); 3050e51060f0SSean Hefty break; 305107ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 305207ebafbaSTom Tucker ret = iw_cm_disconnect(id_priv->cm_id.iw, 0); 305307ebafbaSTom Tucker break; 3054e51060f0SSean Hefty default: 305507ebafbaSTom Tucker ret = -EINVAL; 3056e51060f0SSean Hefty break; 3057e51060f0SSean Hefty } 3058e51060f0SSean Hefty out: 3059e51060f0SSean Hefty return ret; 3060e51060f0SSean Hefty } 3061e51060f0SSean Hefty EXPORT_SYMBOL(rdma_disconnect); 3062e51060f0SSean Hefty 3063c8f6a362SSean Hefty static int cma_ib_mc_handler(int status, struct ib_sa_multicast *multicast) 3064c8f6a362SSean Hefty { 3065c8f6a362SSean Hefty struct rdma_id_private *id_priv; 3066c8f6a362SSean Hefty struct cma_multicast *mc = multicast->context; 3067c8f6a362SSean Hefty struct rdma_cm_event event; 3068c8f6a362SSean Hefty int ret; 3069c8f6a362SSean Hefty 3070c8f6a362SSean Hefty id_priv = mc->id_priv; 3071550e5ca7SNir Muchtar if (cma_disable_callback(id_priv, RDMA_CM_ADDR_BOUND) && 3072550e5ca7SNir Muchtar cma_disable_callback(id_priv, RDMA_CM_ADDR_RESOLVED)) 30738aa08602SSean Hefty return 0; 3074c8f6a362SSean Hefty 3075c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 3076c8f6a362SSean Hefty if (!status && id_priv->id.qp) 3077c8f6a362SSean Hefty status = ib_attach_mcast(id_priv->id.qp, &multicast->rec.mgid, 307846ea5061SSean Hefty be16_to_cpu(multicast->rec.mlid)); 3079c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 3080c8f6a362SSean Hefty 3081c8f6a362SSean Hefty memset(&event, 0, sizeof event); 3082c8f6a362SSean Hefty event.status = status; 3083c8f6a362SSean Hefty event.param.ud.private_data = mc->context; 3084c8f6a362SSean Hefty if (!status) { 3085c8f6a362SSean Hefty event.event = RDMA_CM_EVENT_MULTICAST_JOIN; 3086c8f6a362SSean Hefty ib_init_ah_from_mcmember(id_priv->id.device, 3087c8f6a362SSean Hefty id_priv->id.port_num, &multicast->rec, 3088c8f6a362SSean Hefty &event.param.ud.ah_attr); 3089c8f6a362SSean Hefty event.param.ud.qp_num = 0xFFFFFF; 3090c8f6a362SSean Hefty event.param.ud.qkey = be32_to_cpu(multicast->rec.qkey); 3091c8f6a362SSean Hefty } else 3092c8f6a362SSean Hefty event.event = RDMA_CM_EVENT_MULTICAST_ERROR; 3093c8f6a362SSean Hefty 3094c8f6a362SSean Hefty ret = id_priv->id.event_handler(&id_priv->id, &event); 3095c8f6a362SSean Hefty if (ret) { 3096550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 3097de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 3098c8f6a362SSean Hefty rdma_destroy_id(&id_priv->id); 3099c8f6a362SSean Hefty return 0; 3100c8f6a362SSean Hefty } 31018aa08602SSean Hefty 3102de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 3103c8f6a362SSean Hefty return 0; 3104c8f6a362SSean Hefty } 3105c8f6a362SSean Hefty 3106c8f6a362SSean Hefty static void cma_set_mgid(struct rdma_id_private *id_priv, 3107c8f6a362SSean Hefty struct sockaddr *addr, union ib_gid *mgid) 3108c8f6a362SSean Hefty { 3109c8f6a362SSean Hefty unsigned char mc_map[MAX_ADDR_LEN]; 3110c8f6a362SSean Hefty struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 3111c8f6a362SSean Hefty struct sockaddr_in *sin = (struct sockaddr_in *) addr; 3112c8f6a362SSean Hefty struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) addr; 3113c8f6a362SSean Hefty 3114c8f6a362SSean Hefty if (cma_any_addr(addr)) { 3115c8f6a362SSean Hefty memset(mgid, 0, sizeof *mgid); 3116c8f6a362SSean Hefty } else if ((addr->sa_family == AF_INET6) && 31171c9b2819SJason Gunthorpe ((be32_to_cpu(sin6->sin6_addr.s6_addr32[0]) & 0xFFF0FFFF) == 3118c8f6a362SSean Hefty 0xFF10A01B)) { 3119c8f6a362SSean Hefty /* IPv6 address is an SA assigned MGID. */ 3120c8f6a362SSean Hefty memcpy(mgid, &sin6->sin6_addr, sizeof *mgid); 3121e2e62697SJason Gunthorpe } else if ((addr->sa_family == AF_INET6)) { 3122e2e62697SJason Gunthorpe ipv6_ib_mc_map(&sin6->sin6_addr, dev_addr->broadcast, mc_map); 3123e2e62697SJason Gunthorpe if (id_priv->id.ps == RDMA_PS_UDP) 3124e2e62697SJason Gunthorpe mc_map[7] = 0x01; /* Use RDMA CM signature */ 3125e2e62697SJason Gunthorpe *mgid = *(union ib_gid *) (mc_map + 4); 3126c8f6a362SSean Hefty } else { 3127a9e527e3SRolf Manderscheid ip_ib_mc_map(sin->sin_addr.s_addr, dev_addr->broadcast, mc_map); 3128c8f6a362SSean Hefty if (id_priv->id.ps == RDMA_PS_UDP) 3129c8f6a362SSean Hefty mc_map[7] = 0x01; /* Use RDMA CM signature */ 3130c8f6a362SSean Hefty *mgid = *(union ib_gid *) (mc_map + 4); 3131c8f6a362SSean Hefty } 3132c8f6a362SSean Hefty } 3133c8f6a362SSean Hefty 3134c8f6a362SSean Hefty static int cma_join_ib_multicast(struct rdma_id_private *id_priv, 3135c8f6a362SSean Hefty struct cma_multicast *mc) 3136c8f6a362SSean Hefty { 3137c8f6a362SSean Hefty struct ib_sa_mcmember_rec rec; 3138c8f6a362SSean Hefty struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 3139c8f6a362SSean Hefty ib_sa_comp_mask comp_mask; 3140c8f6a362SSean Hefty int ret; 3141c8f6a362SSean Hefty 3142c8f6a362SSean Hefty ib_addr_get_mgid(dev_addr, &rec.mgid); 3143c8f6a362SSean Hefty ret = ib_sa_get_mcmember_rec(id_priv->id.device, id_priv->id.port_num, 3144c8f6a362SSean Hefty &rec.mgid, &rec); 3145c8f6a362SSean Hefty if (ret) 3146c8f6a362SSean Hefty return ret; 3147c8f6a362SSean Hefty 31483f446754SRoland Dreier cma_set_mgid(id_priv, (struct sockaddr *) &mc->addr, &rec.mgid); 3149c8f6a362SSean Hefty if (id_priv->id.ps == RDMA_PS_UDP) 3150c8f6a362SSean Hefty rec.qkey = cpu_to_be32(RDMA_UDP_QKEY); 31516f8372b6SSean Hefty rdma_addr_get_sgid(dev_addr, &rec.port_gid); 3152c8f6a362SSean Hefty rec.pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr)); 3153c8f6a362SSean Hefty rec.join_state = 1; 3154c8f6a362SSean Hefty 3155c8f6a362SSean Hefty comp_mask = IB_SA_MCMEMBER_REC_MGID | IB_SA_MCMEMBER_REC_PORT_GID | 3156c8f6a362SSean Hefty IB_SA_MCMEMBER_REC_PKEY | IB_SA_MCMEMBER_REC_JOIN_STATE | 3157c8f6a362SSean Hefty IB_SA_MCMEMBER_REC_QKEY | IB_SA_MCMEMBER_REC_SL | 3158c8f6a362SSean Hefty IB_SA_MCMEMBER_REC_FLOW_LABEL | 3159c8f6a362SSean Hefty IB_SA_MCMEMBER_REC_TRAFFIC_CLASS; 3160c8f6a362SSean Hefty 316184adeee9SYossi Etigin if (id_priv->id.ps == RDMA_PS_IPOIB) 316284adeee9SYossi Etigin comp_mask |= IB_SA_MCMEMBER_REC_RATE | 31632a22fb8cSDotan Barak IB_SA_MCMEMBER_REC_RATE_SELECTOR | 31642a22fb8cSDotan Barak IB_SA_MCMEMBER_REC_MTU_SELECTOR | 31652a22fb8cSDotan Barak IB_SA_MCMEMBER_REC_MTU | 31662a22fb8cSDotan Barak IB_SA_MCMEMBER_REC_HOP_LIMIT; 316784adeee9SYossi Etigin 3168c8f6a362SSean Hefty mc->multicast.ib = ib_sa_join_multicast(&sa_client, id_priv->id.device, 3169c8f6a362SSean Hefty id_priv->id.port_num, &rec, 3170c8f6a362SSean Hefty comp_mask, GFP_KERNEL, 3171c8f6a362SSean Hefty cma_ib_mc_handler, mc); 31724e289045SFengguang Wu return PTR_RET(mc->multicast.ib); 3173c8f6a362SSean Hefty } 3174c8f6a362SSean Hefty 31753c86aa70SEli Cohen static void iboe_mcast_work_handler(struct work_struct *work) 31763c86aa70SEli Cohen { 31773c86aa70SEli Cohen struct iboe_mcast_work *mw = container_of(work, struct iboe_mcast_work, work); 31783c86aa70SEli Cohen struct cma_multicast *mc = mw->mc; 31793c86aa70SEli Cohen struct ib_sa_multicast *m = mc->multicast.ib; 31803c86aa70SEli Cohen 31813c86aa70SEli Cohen mc->multicast.ib->context = mc; 31823c86aa70SEli Cohen cma_ib_mc_handler(0, m); 31833c86aa70SEli Cohen kref_put(&mc->mcref, release_mc); 31843c86aa70SEli Cohen kfree(mw); 31853c86aa70SEli Cohen } 31863c86aa70SEli Cohen 31873c86aa70SEli Cohen static void cma_iboe_set_mgid(struct sockaddr *addr, union ib_gid *mgid) 31883c86aa70SEli Cohen { 31893c86aa70SEli Cohen struct sockaddr_in *sin = (struct sockaddr_in *)addr; 31903c86aa70SEli Cohen struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr; 31913c86aa70SEli Cohen 31923c86aa70SEli Cohen if (cma_any_addr(addr)) { 31933c86aa70SEli Cohen memset(mgid, 0, sizeof *mgid); 31943c86aa70SEli Cohen } else if (addr->sa_family == AF_INET6) { 31953c86aa70SEli Cohen memcpy(mgid, &sin6->sin6_addr, sizeof *mgid); 31963c86aa70SEli Cohen } else { 31973c86aa70SEli Cohen mgid->raw[0] = 0xff; 31983c86aa70SEli Cohen mgid->raw[1] = 0x0e; 31993c86aa70SEli Cohen mgid->raw[2] = 0; 32003c86aa70SEli Cohen mgid->raw[3] = 0; 32013c86aa70SEli Cohen mgid->raw[4] = 0; 32023c86aa70SEli Cohen mgid->raw[5] = 0; 32033c86aa70SEli Cohen mgid->raw[6] = 0; 32043c86aa70SEli Cohen mgid->raw[7] = 0; 32053c86aa70SEli Cohen mgid->raw[8] = 0; 32063c86aa70SEli Cohen mgid->raw[9] = 0; 32073c86aa70SEli Cohen mgid->raw[10] = 0xff; 32083c86aa70SEli Cohen mgid->raw[11] = 0xff; 32093c86aa70SEli Cohen *(__be32 *)(&mgid->raw[12]) = sin->sin_addr.s_addr; 32103c86aa70SEli Cohen } 32113c86aa70SEli Cohen } 32123c86aa70SEli Cohen 32133c86aa70SEli Cohen static int cma_iboe_join_multicast(struct rdma_id_private *id_priv, 32143c86aa70SEli Cohen struct cma_multicast *mc) 32153c86aa70SEli Cohen { 32163c86aa70SEli Cohen struct iboe_mcast_work *work; 32173c86aa70SEli Cohen struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 32183c86aa70SEli Cohen int err; 32193c86aa70SEli Cohen struct sockaddr *addr = (struct sockaddr *)&mc->addr; 32203c86aa70SEli Cohen struct net_device *ndev = NULL; 32213c86aa70SEli Cohen 32223c86aa70SEli Cohen if (cma_zero_addr((struct sockaddr *)&mc->addr)) 32233c86aa70SEli Cohen return -EINVAL; 32243c86aa70SEli Cohen 32253c86aa70SEli Cohen work = kzalloc(sizeof *work, GFP_KERNEL); 32263c86aa70SEli Cohen if (!work) 32273c86aa70SEli Cohen return -ENOMEM; 32283c86aa70SEli Cohen 32293c86aa70SEli Cohen mc->multicast.ib = kzalloc(sizeof(struct ib_sa_multicast), GFP_KERNEL); 32303c86aa70SEli Cohen if (!mc->multicast.ib) { 32313c86aa70SEli Cohen err = -ENOMEM; 32323c86aa70SEli Cohen goto out1; 32333c86aa70SEli Cohen } 32343c86aa70SEli Cohen 32353c86aa70SEli Cohen cma_iboe_set_mgid(addr, &mc->multicast.ib->rec.mgid); 32363c86aa70SEli Cohen 32373c86aa70SEli Cohen mc->multicast.ib->rec.pkey = cpu_to_be16(0xffff); 32383c86aa70SEli Cohen if (id_priv->id.ps == RDMA_PS_UDP) 32393c86aa70SEli Cohen mc->multicast.ib->rec.qkey = cpu_to_be32(RDMA_UDP_QKEY); 32403c86aa70SEli Cohen 32413c86aa70SEli Cohen if (dev_addr->bound_dev_if) 32423c86aa70SEli Cohen ndev = dev_get_by_index(&init_net, dev_addr->bound_dev_if); 32433c86aa70SEli Cohen if (!ndev) { 32443c86aa70SEli Cohen err = -ENODEV; 32453c86aa70SEli Cohen goto out2; 32463c86aa70SEli Cohen } 32473c86aa70SEli Cohen mc->multicast.ib->rec.rate = iboe_get_rate(ndev); 32483c86aa70SEli Cohen mc->multicast.ib->rec.hop_limit = 1; 32493c86aa70SEli Cohen mc->multicast.ib->rec.mtu = iboe_get_mtu(ndev->mtu); 32503c86aa70SEli Cohen dev_put(ndev); 32513c86aa70SEli Cohen if (!mc->multicast.ib->rec.mtu) { 32523c86aa70SEli Cohen err = -EINVAL; 32533c86aa70SEli Cohen goto out2; 32543c86aa70SEli Cohen } 32553c86aa70SEli Cohen iboe_addr_get_sgid(dev_addr, &mc->multicast.ib->rec.port_gid); 32563c86aa70SEli Cohen work->id = id_priv; 32573c86aa70SEli Cohen work->mc = mc; 32583c86aa70SEli Cohen INIT_WORK(&work->work, iboe_mcast_work_handler); 32593c86aa70SEli Cohen kref_get(&mc->mcref); 32603c86aa70SEli Cohen queue_work(cma_wq, &work->work); 32613c86aa70SEli Cohen 32623c86aa70SEli Cohen return 0; 32633c86aa70SEli Cohen 32643c86aa70SEli Cohen out2: 32653c86aa70SEli Cohen kfree(mc->multicast.ib); 32663c86aa70SEli Cohen out1: 32673c86aa70SEli Cohen kfree(work); 32683c86aa70SEli Cohen return err; 32693c86aa70SEli Cohen } 32703c86aa70SEli Cohen 3271c8f6a362SSean Hefty int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr, 3272c8f6a362SSean Hefty void *context) 3273c8f6a362SSean Hefty { 3274c8f6a362SSean Hefty struct rdma_id_private *id_priv; 3275c8f6a362SSean Hefty struct cma_multicast *mc; 3276c8f6a362SSean Hefty int ret; 3277c8f6a362SSean Hefty 3278c8f6a362SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 3279550e5ca7SNir Muchtar if (!cma_comp(id_priv, RDMA_CM_ADDR_BOUND) && 3280550e5ca7SNir Muchtar !cma_comp(id_priv, RDMA_CM_ADDR_RESOLVED)) 3281c8f6a362SSean Hefty return -EINVAL; 3282c8f6a362SSean Hefty 3283c8f6a362SSean Hefty mc = kmalloc(sizeof *mc, GFP_KERNEL); 3284c8f6a362SSean Hefty if (!mc) 3285c8f6a362SSean Hefty return -ENOMEM; 3286c8f6a362SSean Hefty 3287ef560861SSean Hefty memcpy(&mc->addr, addr, rdma_addr_size(addr)); 3288c8f6a362SSean Hefty mc->context = context; 3289c8f6a362SSean Hefty mc->id_priv = id_priv; 3290c8f6a362SSean Hefty 3291c8f6a362SSean Hefty spin_lock(&id_priv->lock); 3292c8f6a362SSean Hefty list_add(&mc->list, &id_priv->mc_list); 3293c8f6a362SSean Hefty spin_unlock(&id_priv->lock); 3294c8f6a362SSean Hefty 3295c8f6a362SSean Hefty switch (rdma_node_get_transport(id->device->node_type)) { 3296c8f6a362SSean Hefty case RDMA_TRANSPORT_IB: 32973c86aa70SEli Cohen switch (rdma_port_get_link_layer(id->device, id->port_num)) { 32983c86aa70SEli Cohen case IB_LINK_LAYER_INFINIBAND: 3299c8f6a362SSean Hefty ret = cma_join_ib_multicast(id_priv, mc); 3300c8f6a362SSean Hefty break; 33013c86aa70SEli Cohen case IB_LINK_LAYER_ETHERNET: 33023c86aa70SEli Cohen kref_init(&mc->mcref); 33033c86aa70SEli Cohen ret = cma_iboe_join_multicast(id_priv, mc); 33043c86aa70SEli Cohen break; 33053c86aa70SEli Cohen default: 33063c86aa70SEli Cohen ret = -EINVAL; 33073c86aa70SEli Cohen } 33083c86aa70SEli Cohen break; 3309c8f6a362SSean Hefty default: 3310c8f6a362SSean Hefty ret = -ENOSYS; 3311c8f6a362SSean Hefty break; 3312c8f6a362SSean Hefty } 3313c8f6a362SSean Hefty 3314c8f6a362SSean Hefty if (ret) { 3315c8f6a362SSean Hefty spin_lock_irq(&id_priv->lock); 3316c8f6a362SSean Hefty list_del(&mc->list); 3317c8f6a362SSean Hefty spin_unlock_irq(&id_priv->lock); 3318c8f6a362SSean Hefty kfree(mc); 3319c8f6a362SSean Hefty } 3320c8f6a362SSean Hefty return ret; 3321c8f6a362SSean Hefty } 3322c8f6a362SSean Hefty EXPORT_SYMBOL(rdma_join_multicast); 3323c8f6a362SSean Hefty 3324c8f6a362SSean Hefty void rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr) 3325c8f6a362SSean Hefty { 3326c8f6a362SSean Hefty struct rdma_id_private *id_priv; 3327c8f6a362SSean Hefty struct cma_multicast *mc; 3328c8f6a362SSean Hefty 3329c8f6a362SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 3330c8f6a362SSean Hefty spin_lock_irq(&id_priv->lock); 3331c8f6a362SSean Hefty list_for_each_entry(mc, &id_priv->mc_list, list) { 3332ef560861SSean Hefty if (!memcmp(&mc->addr, addr, rdma_addr_size(addr))) { 3333c8f6a362SSean Hefty list_del(&mc->list); 3334c8f6a362SSean Hefty spin_unlock_irq(&id_priv->lock); 3335c8f6a362SSean Hefty 3336c8f6a362SSean Hefty if (id->qp) 3337c8f6a362SSean Hefty ib_detach_mcast(id->qp, 3338c8f6a362SSean Hefty &mc->multicast.ib->rec.mgid, 333946ea5061SSean Hefty be16_to_cpu(mc->multicast.ib->rec.mlid)); 33403c86aa70SEli Cohen if (rdma_node_get_transport(id_priv->cma_dev->device->node_type) == RDMA_TRANSPORT_IB) { 33413c86aa70SEli Cohen switch (rdma_port_get_link_layer(id->device, id->port_num)) { 33423c86aa70SEli Cohen case IB_LINK_LAYER_INFINIBAND: 3343c8f6a362SSean Hefty ib_sa_free_multicast(mc->multicast.ib); 3344c8f6a362SSean Hefty kfree(mc); 33453c86aa70SEli Cohen break; 33463c86aa70SEli Cohen case IB_LINK_LAYER_ETHERNET: 33473c86aa70SEli Cohen kref_put(&mc->mcref, release_mc); 33483c86aa70SEli Cohen break; 33493c86aa70SEli Cohen default: 33503c86aa70SEli Cohen break; 33513c86aa70SEli Cohen } 33523c86aa70SEli Cohen } 3353c8f6a362SSean Hefty return; 3354c8f6a362SSean Hefty } 3355c8f6a362SSean Hefty } 3356c8f6a362SSean Hefty spin_unlock_irq(&id_priv->lock); 3357c8f6a362SSean Hefty } 3358c8f6a362SSean Hefty EXPORT_SYMBOL(rdma_leave_multicast); 3359c8f6a362SSean Hefty 3360dd5bdff8SOr Gerlitz static int cma_netdev_change(struct net_device *ndev, struct rdma_id_private *id_priv) 3361dd5bdff8SOr Gerlitz { 3362dd5bdff8SOr Gerlitz struct rdma_dev_addr *dev_addr; 3363dd5bdff8SOr Gerlitz struct cma_ndev_work *work; 3364dd5bdff8SOr Gerlitz 3365dd5bdff8SOr Gerlitz dev_addr = &id_priv->id.route.addr.dev_addr; 3366dd5bdff8SOr Gerlitz 33676266ed6eSSean Hefty if ((dev_addr->bound_dev_if == ndev->ifindex) && 3368dd5bdff8SOr Gerlitz memcmp(dev_addr->src_dev_addr, ndev->dev_addr, ndev->addr_len)) { 3369dd5bdff8SOr Gerlitz printk(KERN_INFO "RDMA CM addr change for ndev %s used by id %p\n", 3370dd5bdff8SOr Gerlitz ndev->name, &id_priv->id); 3371dd5bdff8SOr Gerlitz work = kzalloc(sizeof *work, GFP_KERNEL); 3372dd5bdff8SOr Gerlitz if (!work) 3373dd5bdff8SOr Gerlitz return -ENOMEM; 3374dd5bdff8SOr Gerlitz 3375dd5bdff8SOr Gerlitz INIT_WORK(&work->work, cma_ndev_work_handler); 3376dd5bdff8SOr Gerlitz work->id = id_priv; 3377dd5bdff8SOr Gerlitz work->event.event = RDMA_CM_EVENT_ADDR_CHANGE; 3378dd5bdff8SOr Gerlitz atomic_inc(&id_priv->refcount); 3379dd5bdff8SOr Gerlitz queue_work(cma_wq, &work->work); 3380dd5bdff8SOr Gerlitz } 3381dd5bdff8SOr Gerlitz 3382dd5bdff8SOr Gerlitz return 0; 3383dd5bdff8SOr Gerlitz } 3384dd5bdff8SOr Gerlitz 3385dd5bdff8SOr Gerlitz static int cma_netdev_callback(struct notifier_block *self, unsigned long event, 3386351638e7SJiri Pirko void *ptr) 3387dd5bdff8SOr Gerlitz { 3388351638e7SJiri Pirko struct net_device *ndev = netdev_notifier_info_to_dev(ptr); 3389dd5bdff8SOr Gerlitz struct cma_device *cma_dev; 3390dd5bdff8SOr Gerlitz struct rdma_id_private *id_priv; 3391dd5bdff8SOr Gerlitz int ret = NOTIFY_DONE; 3392dd5bdff8SOr Gerlitz 3393dd5bdff8SOr Gerlitz if (dev_net(ndev) != &init_net) 3394dd5bdff8SOr Gerlitz return NOTIFY_DONE; 3395dd5bdff8SOr Gerlitz 3396dd5bdff8SOr Gerlitz if (event != NETDEV_BONDING_FAILOVER) 3397dd5bdff8SOr Gerlitz return NOTIFY_DONE; 3398dd5bdff8SOr Gerlitz 3399dd5bdff8SOr Gerlitz if (!(ndev->flags & IFF_MASTER) || !(ndev->priv_flags & IFF_BONDING)) 3400dd5bdff8SOr Gerlitz return NOTIFY_DONE; 3401dd5bdff8SOr Gerlitz 3402dd5bdff8SOr Gerlitz mutex_lock(&lock); 3403dd5bdff8SOr Gerlitz list_for_each_entry(cma_dev, &dev_list, list) 3404dd5bdff8SOr Gerlitz list_for_each_entry(id_priv, &cma_dev->id_list, list) { 3405dd5bdff8SOr Gerlitz ret = cma_netdev_change(ndev, id_priv); 3406dd5bdff8SOr Gerlitz if (ret) 3407dd5bdff8SOr Gerlitz goto out; 3408dd5bdff8SOr Gerlitz } 3409dd5bdff8SOr Gerlitz 3410dd5bdff8SOr Gerlitz out: 3411dd5bdff8SOr Gerlitz mutex_unlock(&lock); 3412dd5bdff8SOr Gerlitz return ret; 3413dd5bdff8SOr Gerlitz } 3414dd5bdff8SOr Gerlitz 3415dd5bdff8SOr Gerlitz static struct notifier_block cma_nb = { 3416dd5bdff8SOr Gerlitz .notifier_call = cma_netdev_callback 3417dd5bdff8SOr Gerlitz }; 3418dd5bdff8SOr Gerlitz 3419e51060f0SSean Hefty static void cma_add_one(struct ib_device *device) 3420e51060f0SSean Hefty { 3421e51060f0SSean Hefty struct cma_device *cma_dev; 3422e51060f0SSean Hefty struct rdma_id_private *id_priv; 3423e51060f0SSean Hefty 3424e51060f0SSean Hefty cma_dev = kmalloc(sizeof *cma_dev, GFP_KERNEL); 3425e51060f0SSean Hefty if (!cma_dev) 3426e51060f0SSean Hefty return; 3427e51060f0SSean Hefty 3428e51060f0SSean Hefty cma_dev->device = device; 3429e51060f0SSean Hefty 3430e51060f0SSean Hefty init_completion(&cma_dev->comp); 3431e51060f0SSean Hefty atomic_set(&cma_dev->refcount, 1); 3432e51060f0SSean Hefty INIT_LIST_HEAD(&cma_dev->id_list); 3433e51060f0SSean Hefty ib_set_client_data(device, &cma_client, cma_dev); 3434e51060f0SSean Hefty 3435e51060f0SSean Hefty mutex_lock(&lock); 3436e51060f0SSean Hefty list_add_tail(&cma_dev->list, &dev_list); 3437e51060f0SSean Hefty list_for_each_entry(id_priv, &listen_any_list, list) 3438e51060f0SSean Hefty cma_listen_on_dev(id_priv, cma_dev); 3439e51060f0SSean Hefty mutex_unlock(&lock); 3440e51060f0SSean Hefty } 3441e51060f0SSean Hefty 3442e51060f0SSean Hefty static int cma_remove_id_dev(struct rdma_id_private *id_priv) 3443e51060f0SSean Hefty { 3444a1b1b61fSSean Hefty struct rdma_cm_event event; 3445550e5ca7SNir Muchtar enum rdma_cm_state state; 3446de910bd9SOr Gerlitz int ret = 0; 3447e51060f0SSean Hefty 3448e51060f0SSean Hefty /* Record that we want to remove the device */ 3449550e5ca7SNir Muchtar state = cma_exch(id_priv, RDMA_CM_DEVICE_REMOVAL); 3450550e5ca7SNir Muchtar if (state == RDMA_CM_DESTROYING) 3451e51060f0SSean Hefty return 0; 3452e51060f0SSean Hefty 3453e51060f0SSean Hefty cma_cancel_operation(id_priv, state); 3454de910bd9SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 3455e51060f0SSean Hefty 3456e51060f0SSean Hefty /* Check for destruction from another callback. */ 3457550e5ca7SNir Muchtar if (!cma_comp(id_priv, RDMA_CM_DEVICE_REMOVAL)) 3458de910bd9SOr Gerlitz goto out; 3459e51060f0SSean Hefty 3460a1b1b61fSSean Hefty memset(&event, 0, sizeof event); 3461a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_DEVICE_REMOVAL; 3462de910bd9SOr Gerlitz ret = id_priv->id.event_handler(&id_priv->id, &event); 3463de910bd9SOr Gerlitz out: 3464de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 3465de910bd9SOr Gerlitz return ret; 3466e51060f0SSean Hefty } 3467e51060f0SSean Hefty 3468e51060f0SSean Hefty static void cma_process_remove(struct cma_device *cma_dev) 3469e51060f0SSean Hefty { 3470e51060f0SSean Hefty struct rdma_id_private *id_priv; 3471e51060f0SSean Hefty int ret; 3472e51060f0SSean Hefty 3473e51060f0SSean Hefty mutex_lock(&lock); 3474e51060f0SSean Hefty while (!list_empty(&cma_dev->id_list)) { 3475e51060f0SSean Hefty id_priv = list_entry(cma_dev->id_list.next, 3476e51060f0SSean Hefty struct rdma_id_private, list); 3477e51060f0SSean Hefty 3478d02d1f53SSean Hefty list_del(&id_priv->listen_list); 347994de178aSKrishna Kumar list_del_init(&id_priv->list); 3480e51060f0SSean Hefty atomic_inc(&id_priv->refcount); 3481e51060f0SSean Hefty mutex_unlock(&lock); 3482e51060f0SSean Hefty 3483d02d1f53SSean Hefty ret = id_priv->internal_id ? 1 : cma_remove_id_dev(id_priv); 3484e51060f0SSean Hefty cma_deref_id(id_priv); 3485e51060f0SSean Hefty if (ret) 3486e51060f0SSean Hefty rdma_destroy_id(&id_priv->id); 3487e51060f0SSean Hefty 3488e51060f0SSean Hefty mutex_lock(&lock); 3489e51060f0SSean Hefty } 3490e51060f0SSean Hefty mutex_unlock(&lock); 3491e51060f0SSean Hefty 3492e51060f0SSean Hefty cma_deref_dev(cma_dev); 3493e51060f0SSean Hefty wait_for_completion(&cma_dev->comp); 3494e51060f0SSean Hefty } 3495e51060f0SSean Hefty 3496e51060f0SSean Hefty static void cma_remove_one(struct ib_device *device) 3497e51060f0SSean Hefty { 3498e51060f0SSean Hefty struct cma_device *cma_dev; 3499e51060f0SSean Hefty 3500e51060f0SSean Hefty cma_dev = ib_get_client_data(device, &cma_client); 3501e51060f0SSean Hefty if (!cma_dev) 3502e51060f0SSean Hefty return; 3503e51060f0SSean Hefty 3504e51060f0SSean Hefty mutex_lock(&lock); 3505e51060f0SSean Hefty list_del(&cma_dev->list); 3506e51060f0SSean Hefty mutex_unlock(&lock); 3507e51060f0SSean Hefty 3508e51060f0SSean Hefty cma_process_remove(cma_dev); 3509e51060f0SSean Hefty kfree(cma_dev); 3510e51060f0SSean Hefty } 3511e51060f0SSean Hefty 3512753f618aSNir Muchtar static int cma_get_id_stats(struct sk_buff *skb, struct netlink_callback *cb) 3513753f618aSNir Muchtar { 3514753f618aSNir Muchtar struct nlmsghdr *nlh; 3515753f618aSNir Muchtar struct rdma_cm_id_stats *id_stats; 3516753f618aSNir Muchtar struct rdma_id_private *id_priv; 3517753f618aSNir Muchtar struct rdma_cm_id *id = NULL; 3518753f618aSNir Muchtar struct cma_device *cma_dev; 3519753f618aSNir Muchtar int i_dev = 0, i_id = 0; 3520753f618aSNir Muchtar 3521753f618aSNir Muchtar /* 3522753f618aSNir Muchtar * We export all of the IDs as a sequence of messages. Each 3523753f618aSNir Muchtar * ID gets its own netlink message. 3524753f618aSNir Muchtar */ 3525753f618aSNir Muchtar mutex_lock(&lock); 3526753f618aSNir Muchtar 3527753f618aSNir Muchtar list_for_each_entry(cma_dev, &dev_list, list) { 3528753f618aSNir Muchtar if (i_dev < cb->args[0]) { 3529753f618aSNir Muchtar i_dev++; 3530753f618aSNir Muchtar continue; 3531753f618aSNir Muchtar } 3532753f618aSNir Muchtar 3533753f618aSNir Muchtar i_id = 0; 3534753f618aSNir Muchtar list_for_each_entry(id_priv, &cma_dev->id_list, list) { 3535753f618aSNir Muchtar if (i_id < cb->args[1]) { 3536753f618aSNir Muchtar i_id++; 3537753f618aSNir Muchtar continue; 3538753f618aSNir Muchtar } 3539753f618aSNir Muchtar 3540753f618aSNir Muchtar id_stats = ibnl_put_msg(skb, &nlh, cb->nlh->nlmsg_seq, 3541753f618aSNir Muchtar sizeof *id_stats, RDMA_NL_RDMA_CM, 3542753f618aSNir Muchtar RDMA_NL_RDMA_CM_ID_STATS); 3543753f618aSNir Muchtar if (!id_stats) 3544753f618aSNir Muchtar goto out; 3545753f618aSNir Muchtar 3546753f618aSNir Muchtar memset(id_stats, 0, sizeof *id_stats); 3547753f618aSNir Muchtar id = &id_priv->id; 3548753f618aSNir Muchtar id_stats->node_type = id->route.addr.dev_addr.dev_type; 3549753f618aSNir Muchtar id_stats->port_num = id->port_num; 3550753f618aSNir Muchtar id_stats->bound_dev_if = 3551753f618aSNir Muchtar id->route.addr.dev_addr.bound_dev_if; 3552753f618aSNir Muchtar 3553f4753834SSean Hefty if (cma_family(id_priv) == AF_INET) { 3554753f618aSNir Muchtar if (ibnl_put_attr(skb, nlh, 3555753f618aSNir Muchtar sizeof(struct sockaddr_in), 3556f4753834SSean Hefty cma_src_addr(id_priv), 3557753f618aSNir Muchtar RDMA_NL_RDMA_CM_ATTR_SRC_ADDR)) { 3558753f618aSNir Muchtar goto out; 3559753f618aSNir Muchtar } 3560753f618aSNir Muchtar if (ibnl_put_attr(skb, nlh, 3561753f618aSNir Muchtar sizeof(struct sockaddr_in), 3562f4753834SSean Hefty cma_dst_addr(id_priv), 3563753f618aSNir Muchtar RDMA_NL_RDMA_CM_ATTR_DST_ADDR)) { 3564753f618aSNir Muchtar goto out; 3565753f618aSNir Muchtar } 3566f4753834SSean Hefty } else if (cma_family(id_priv) == AF_INET6) { 3567753f618aSNir Muchtar if (ibnl_put_attr(skb, nlh, 3568753f618aSNir Muchtar sizeof(struct sockaddr_in6), 3569f4753834SSean Hefty cma_src_addr(id_priv), 3570753f618aSNir Muchtar RDMA_NL_RDMA_CM_ATTR_SRC_ADDR)) { 3571753f618aSNir Muchtar goto out; 3572753f618aSNir Muchtar } 3573753f618aSNir Muchtar if (ibnl_put_attr(skb, nlh, 3574753f618aSNir Muchtar sizeof(struct sockaddr_in6), 3575f4753834SSean Hefty cma_dst_addr(id_priv), 3576753f618aSNir Muchtar RDMA_NL_RDMA_CM_ATTR_DST_ADDR)) { 3577753f618aSNir Muchtar goto out; 3578753f618aSNir Muchtar } 3579753f618aSNir Muchtar } 3580753f618aSNir Muchtar 358183e9502dSNir Muchtar id_stats->pid = id_priv->owner; 3582753f618aSNir Muchtar id_stats->port_space = id->ps; 3583753f618aSNir Muchtar id_stats->cm_state = id_priv->state; 3584753f618aSNir Muchtar id_stats->qp_num = id_priv->qp_num; 3585753f618aSNir Muchtar id_stats->qp_type = id->qp_type; 3586753f618aSNir Muchtar 3587753f618aSNir Muchtar i_id++; 3588753f618aSNir Muchtar } 3589753f618aSNir Muchtar 3590753f618aSNir Muchtar cb->args[1] = 0; 3591753f618aSNir Muchtar i_dev++; 3592753f618aSNir Muchtar } 3593753f618aSNir Muchtar 3594753f618aSNir Muchtar out: 3595753f618aSNir Muchtar mutex_unlock(&lock); 3596753f618aSNir Muchtar cb->args[0] = i_dev; 3597753f618aSNir Muchtar cb->args[1] = i_id; 3598753f618aSNir Muchtar 3599753f618aSNir Muchtar return skb->len; 3600753f618aSNir Muchtar } 3601753f618aSNir Muchtar 3602753f618aSNir Muchtar static const struct ibnl_client_cbs cma_cb_table[] = { 3603809d5fc9SGao feng [RDMA_NL_RDMA_CM_ID_STATS] = { .dump = cma_get_id_stats, 3604809d5fc9SGao feng .module = THIS_MODULE }, 3605753f618aSNir Muchtar }; 3606753f618aSNir Muchtar 3607716abb1fSPeter Huewe static int __init cma_init(void) 3608e51060f0SSean Hefty { 36095d7220e8STetsuo Handa int ret; 3610227b60f5SStephen Hemminger 3611c7f743a6SSean Hefty cma_wq = create_singlethread_workqueue("rdma_cm"); 3612e51060f0SSean Hefty if (!cma_wq) 3613e51060f0SSean Hefty return -ENOMEM; 3614e51060f0SSean Hefty 3615c1a0b23bSMichael S. Tsirkin ib_sa_register_client(&sa_client); 36167a118df3SSean Hefty rdma_addr_register_client(&addr_client); 3617dd5bdff8SOr Gerlitz register_netdevice_notifier(&cma_nb); 3618c1a0b23bSMichael S. Tsirkin 3619e51060f0SSean Hefty ret = ib_register_client(&cma_client); 3620e51060f0SSean Hefty if (ret) 3621e51060f0SSean Hefty goto err; 3622753f618aSNir Muchtar 3623753f618aSNir Muchtar if (ibnl_add_client(RDMA_NL_RDMA_CM, RDMA_NL_RDMA_CM_NUM_OPS, cma_cb_table)) 3624753f618aSNir Muchtar printk(KERN_WARNING "RDMA CMA: failed to add netlink callback\n"); 3625753f618aSNir Muchtar 3626e51060f0SSean Hefty return 0; 3627e51060f0SSean Hefty 3628e51060f0SSean Hefty err: 3629dd5bdff8SOr Gerlitz unregister_netdevice_notifier(&cma_nb); 36307a118df3SSean Hefty rdma_addr_unregister_client(&addr_client); 3631c1a0b23bSMichael S. Tsirkin ib_sa_unregister_client(&sa_client); 3632e51060f0SSean Hefty destroy_workqueue(cma_wq); 3633e51060f0SSean Hefty return ret; 3634e51060f0SSean Hefty } 3635e51060f0SSean Hefty 3636716abb1fSPeter Huewe static void __exit cma_cleanup(void) 3637e51060f0SSean Hefty { 3638753f618aSNir Muchtar ibnl_remove_client(RDMA_NL_RDMA_CM); 3639e51060f0SSean Hefty ib_unregister_client(&cma_client); 3640dd5bdff8SOr Gerlitz unregister_netdevice_notifier(&cma_nb); 36417a118df3SSean Hefty rdma_addr_unregister_client(&addr_client); 3642c1a0b23bSMichael S. Tsirkin ib_sa_unregister_client(&sa_client); 3643e51060f0SSean Hefty destroy_workqueue(cma_wq); 3644e51060f0SSean Hefty idr_destroy(&sdp_ps); 3645e51060f0SSean Hefty idr_destroy(&tcp_ps); 3646628e5f6dSSean Hefty idr_destroy(&udp_ps); 3647c8f6a362SSean Hefty idr_destroy(&ipoib_ps); 36482d2e9415SSean Hefty idr_destroy(&ib_ps); 3649e51060f0SSean Hefty } 3650e51060f0SSean Hefty 3651e51060f0SSean Hefty module_init(cma_init); 3652e51060f0SSean Hefty module_exit(cma_cleanup); 3653