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> 53e51060f0SSean Hefty #include <rdma/ib_cache.h> 54e51060f0SSean Hefty #include <rdma/ib_cm.h> 55e51060f0SSean Hefty #include <rdma/ib_sa.h> 5607ebafbaSTom Tucker #include <rdma/iw_cm.h> 57e51060f0SSean Hefty 58e51060f0SSean Hefty MODULE_AUTHOR("Sean Hefty"); 59e51060f0SSean Hefty MODULE_DESCRIPTION("Generic RDMA CM Agent"); 60e51060f0SSean Hefty MODULE_LICENSE("Dual BSD/GPL"); 61e51060f0SSean Hefty 62e51060f0SSean Hefty #define CMA_CM_RESPONSE_TIMEOUT 20 63d5bb7599SMichael S. Tsirkin #define CMA_MAX_CM_RETRIES 15 64dcb3f974SSean Hefty #define CMA_CM_MRA_SETTING (IB_CM_MRA_FLAG_DELAY | 24) 653c86aa70SEli Cohen #define CMA_IBOE_PACKET_LIFETIME 18 66e51060f0SSean Hefty 67e51060f0SSean Hefty static void cma_add_one(struct ib_device *device); 68e51060f0SSean Hefty static void cma_remove_one(struct ib_device *device); 69e51060f0SSean Hefty 70e51060f0SSean Hefty static struct ib_client cma_client = { 71e51060f0SSean Hefty .name = "cma", 72e51060f0SSean Hefty .add = cma_add_one, 73e51060f0SSean Hefty .remove = cma_remove_one 74e51060f0SSean Hefty }; 75e51060f0SSean Hefty 76c1a0b23bSMichael S. Tsirkin static struct ib_sa_client sa_client; 777a118df3SSean Hefty static struct rdma_addr_client addr_client; 78e51060f0SSean Hefty static LIST_HEAD(dev_list); 79e51060f0SSean Hefty static LIST_HEAD(listen_any_list); 80e51060f0SSean Hefty static DEFINE_MUTEX(lock); 81e51060f0SSean Hefty static struct workqueue_struct *cma_wq; 82e51060f0SSean Hefty static DEFINE_IDR(sdp_ps); 83e51060f0SSean Hefty static DEFINE_IDR(tcp_ps); 84628e5f6dSSean Hefty static DEFINE_IDR(udp_ps); 85c8f6a362SSean Hefty static DEFINE_IDR(ipoib_ps); 862d2e9415SSean Hefty static DEFINE_IDR(ib_ps); 87e51060f0SSean Hefty 88e51060f0SSean Hefty struct cma_device { 89e51060f0SSean Hefty struct list_head list; 90e51060f0SSean Hefty struct ib_device *device; 91e51060f0SSean Hefty struct completion comp; 92e51060f0SSean Hefty atomic_t refcount; 93e51060f0SSean Hefty struct list_head id_list; 94e51060f0SSean Hefty }; 95e51060f0SSean Hefty 96e51060f0SSean Hefty struct rdma_bind_list { 97e51060f0SSean Hefty struct idr *ps; 98e51060f0SSean Hefty struct hlist_head owners; 99e51060f0SSean Hefty unsigned short port; 100e51060f0SSean Hefty }; 101e51060f0SSean Hefty 10268602120SSean Hefty enum { 10368602120SSean Hefty CMA_OPTION_AFONLY, 10468602120SSean Hefty }; 10568602120SSean Hefty 106e51060f0SSean Hefty /* 107e51060f0SSean Hefty * Device removal can occur at anytime, so we need extra handling to 108e51060f0SSean Hefty * serialize notifying the user of device removal with other callbacks. 109e51060f0SSean Hefty * We do this by disabling removal notification while a callback is in process, 110e51060f0SSean Hefty * and reporting it after the callback completes. 111e51060f0SSean Hefty */ 112e51060f0SSean Hefty struct rdma_id_private { 113e51060f0SSean Hefty struct rdma_cm_id id; 114e51060f0SSean Hefty 115e51060f0SSean Hefty struct rdma_bind_list *bind_list; 116e51060f0SSean Hefty struct hlist_node node; 117d02d1f53SSean Hefty struct list_head list; /* listen_any_list or cma_device.list */ 118d02d1f53SSean Hefty struct list_head listen_list; /* per device listens */ 119e51060f0SSean Hefty struct cma_device *cma_dev; 120c8f6a362SSean Hefty struct list_head mc_list; 121e51060f0SSean Hefty 122d02d1f53SSean Hefty int internal_id; 123550e5ca7SNir Muchtar enum rdma_cm_state state; 124e51060f0SSean Hefty spinlock_t lock; 125c5483388SSean Hefty struct mutex qp_mutex; 126c5483388SSean Hefty 127e51060f0SSean Hefty struct completion comp; 128e51060f0SSean Hefty atomic_t refcount; 129de910bd9SOr Gerlitz struct mutex handler_mutex; 130e51060f0SSean Hefty 131e51060f0SSean Hefty int backlog; 132e51060f0SSean Hefty int timeout_ms; 133e51060f0SSean Hefty struct ib_sa_query *query; 134e51060f0SSean Hefty int query_id; 135e51060f0SSean Hefty union { 136e51060f0SSean Hefty struct ib_cm_id *ib; 13707ebafbaSTom Tucker struct iw_cm_id *iw; 138e51060f0SSean Hefty } cm_id; 139e51060f0SSean Hefty 140e51060f0SSean Hefty u32 seq_num; 141c8f6a362SSean Hefty u32 qkey; 142e51060f0SSean Hefty u32 qp_num; 14383e9502dSNir Muchtar pid_t owner; 14468602120SSean Hefty u32 options; 145e51060f0SSean Hefty u8 srq; 146a81c994dSSean Hefty u8 tos; 147a9bb7912SHefty, Sean u8 reuseaddr; 1485b0ec991SSean Hefty u8 afonly; 149e51060f0SSean Hefty }; 150e51060f0SSean Hefty 151c8f6a362SSean Hefty struct cma_multicast { 152c8f6a362SSean Hefty struct rdma_id_private *id_priv; 153c8f6a362SSean Hefty union { 154c8f6a362SSean Hefty struct ib_sa_multicast *ib; 155c8f6a362SSean Hefty } multicast; 156c8f6a362SSean Hefty struct list_head list; 157c8f6a362SSean Hefty void *context; 1583f446754SRoland Dreier struct sockaddr_storage addr; 1593c86aa70SEli Cohen struct kref mcref; 160c8f6a362SSean Hefty }; 161c8f6a362SSean Hefty 162e51060f0SSean Hefty struct cma_work { 163e51060f0SSean Hefty struct work_struct work; 164e51060f0SSean Hefty struct rdma_id_private *id; 165550e5ca7SNir Muchtar enum rdma_cm_state old_state; 166550e5ca7SNir Muchtar enum rdma_cm_state new_state; 167e51060f0SSean Hefty struct rdma_cm_event event; 168e51060f0SSean Hefty }; 169e51060f0SSean Hefty 170dd5bdff8SOr Gerlitz struct cma_ndev_work { 171dd5bdff8SOr Gerlitz struct work_struct work; 172dd5bdff8SOr Gerlitz struct rdma_id_private *id; 173dd5bdff8SOr Gerlitz struct rdma_cm_event event; 174dd5bdff8SOr Gerlitz }; 175dd5bdff8SOr Gerlitz 1763c86aa70SEli Cohen struct iboe_mcast_work { 1773c86aa70SEli Cohen struct work_struct work; 1783c86aa70SEli Cohen struct rdma_id_private *id; 1793c86aa70SEli Cohen struct cma_multicast *mc; 1803c86aa70SEli Cohen }; 1813c86aa70SEli Cohen 182e51060f0SSean Hefty union cma_ip_addr { 183e51060f0SSean Hefty struct in6_addr ip6; 184e51060f0SSean Hefty struct { 1851b90c137SAl Viro __be32 pad[3]; 1861b90c137SAl Viro __be32 addr; 187e51060f0SSean Hefty } ip4; 188e51060f0SSean Hefty }; 189e51060f0SSean Hefty 190e51060f0SSean Hefty struct cma_hdr { 191e51060f0SSean Hefty u8 cma_version; 192e51060f0SSean Hefty u8 ip_version; /* IP version: 7:4 */ 1931b90c137SAl Viro __be16 port; 194e51060f0SSean Hefty union cma_ip_addr src_addr; 195e51060f0SSean Hefty union cma_ip_addr dst_addr; 196e51060f0SSean Hefty }; 197e51060f0SSean Hefty 198e51060f0SSean Hefty struct sdp_hh { 199e51060f0SSean Hefty u8 bsdh[16]; 200e51060f0SSean Hefty u8 sdp_version; /* Major version: 7:4 */ 201e51060f0SSean Hefty u8 ip_version; /* IP version: 7:4 */ 202e51060f0SSean Hefty u8 sdp_specific1[10]; 2031b90c137SAl Viro __be16 port; 2041b90c137SAl Viro __be16 sdp_specific2; 205e51060f0SSean Hefty union cma_ip_addr src_addr; 206e51060f0SSean Hefty union cma_ip_addr dst_addr; 207e51060f0SSean Hefty }; 208e51060f0SSean Hefty 209e51060f0SSean Hefty struct sdp_hah { 210e51060f0SSean Hefty u8 bsdh[16]; 211e51060f0SSean Hefty u8 sdp_version; 212e51060f0SSean Hefty }; 213e51060f0SSean Hefty 214e51060f0SSean Hefty #define CMA_VERSION 0x00 215e51060f0SSean Hefty #define SDP_MAJ_VERSION 0x2 216e51060f0SSean Hefty 217550e5ca7SNir Muchtar static int cma_comp(struct rdma_id_private *id_priv, enum rdma_cm_state comp) 218e51060f0SSean Hefty { 219e51060f0SSean Hefty unsigned long flags; 220e51060f0SSean Hefty int ret; 221e51060f0SSean Hefty 222e51060f0SSean Hefty spin_lock_irqsave(&id_priv->lock, flags); 223e51060f0SSean Hefty ret = (id_priv->state == comp); 224e51060f0SSean Hefty spin_unlock_irqrestore(&id_priv->lock, flags); 225e51060f0SSean Hefty return ret; 226e51060f0SSean Hefty } 227e51060f0SSean Hefty 228e51060f0SSean Hefty static int cma_comp_exch(struct rdma_id_private *id_priv, 229550e5ca7SNir Muchtar enum rdma_cm_state comp, enum rdma_cm_state exch) 230e51060f0SSean Hefty { 231e51060f0SSean Hefty unsigned long flags; 232e51060f0SSean Hefty int ret; 233e51060f0SSean Hefty 234e51060f0SSean Hefty spin_lock_irqsave(&id_priv->lock, flags); 235e51060f0SSean Hefty if ((ret = (id_priv->state == comp))) 236e51060f0SSean Hefty id_priv->state = exch; 237e51060f0SSean Hefty spin_unlock_irqrestore(&id_priv->lock, flags); 238e51060f0SSean Hefty return ret; 239e51060f0SSean Hefty } 240e51060f0SSean Hefty 241550e5ca7SNir Muchtar static enum rdma_cm_state cma_exch(struct rdma_id_private *id_priv, 242550e5ca7SNir Muchtar enum rdma_cm_state exch) 243e51060f0SSean Hefty { 244e51060f0SSean Hefty unsigned long flags; 245550e5ca7SNir Muchtar enum rdma_cm_state old; 246e51060f0SSean Hefty 247e51060f0SSean Hefty spin_lock_irqsave(&id_priv->lock, flags); 248e51060f0SSean Hefty old = id_priv->state; 249e51060f0SSean Hefty id_priv->state = exch; 250e51060f0SSean Hefty spin_unlock_irqrestore(&id_priv->lock, flags); 251e51060f0SSean Hefty return old; 252e51060f0SSean Hefty } 253e51060f0SSean Hefty 254e51060f0SSean Hefty static inline u8 cma_get_ip_ver(struct cma_hdr *hdr) 255e51060f0SSean Hefty { 256e51060f0SSean Hefty return hdr->ip_version >> 4; 257e51060f0SSean Hefty } 258e51060f0SSean Hefty 259e51060f0SSean Hefty static inline void cma_set_ip_ver(struct cma_hdr *hdr, u8 ip_ver) 260e51060f0SSean Hefty { 261e51060f0SSean Hefty hdr->ip_version = (ip_ver << 4) | (hdr->ip_version & 0xF); 262e51060f0SSean Hefty } 263e51060f0SSean Hefty 264e51060f0SSean Hefty static inline u8 sdp_get_majv(u8 sdp_version) 265e51060f0SSean Hefty { 266e51060f0SSean Hefty return sdp_version >> 4; 267e51060f0SSean Hefty } 268e51060f0SSean Hefty 269e51060f0SSean Hefty static inline u8 sdp_get_ip_ver(struct sdp_hh *hh) 270e51060f0SSean Hefty { 271e51060f0SSean Hefty return hh->ip_version >> 4; 272e51060f0SSean Hefty } 273e51060f0SSean Hefty 274e51060f0SSean Hefty static inline void sdp_set_ip_ver(struct sdp_hh *hh, u8 ip_ver) 275e51060f0SSean Hefty { 276e51060f0SSean Hefty hh->ip_version = (ip_ver << 4) | (hh->ip_version & 0xF); 277e51060f0SSean Hefty } 278e51060f0SSean Hefty 279e51060f0SSean Hefty static void cma_attach_to_dev(struct rdma_id_private *id_priv, 280e51060f0SSean Hefty struct cma_device *cma_dev) 281e51060f0SSean Hefty { 282e51060f0SSean Hefty atomic_inc(&cma_dev->refcount); 283e51060f0SSean Hefty id_priv->cma_dev = cma_dev; 284e51060f0SSean Hefty id_priv->id.device = cma_dev->device; 2853c86aa70SEli Cohen id_priv->id.route.addr.dev_addr.transport = 2863c86aa70SEli Cohen rdma_node_get_transport(cma_dev->device->node_type); 287e51060f0SSean Hefty list_add_tail(&id_priv->list, &cma_dev->id_list); 288e51060f0SSean Hefty } 289e51060f0SSean Hefty 290e51060f0SSean Hefty static inline void cma_deref_dev(struct cma_device *cma_dev) 291e51060f0SSean Hefty { 292e51060f0SSean Hefty if (atomic_dec_and_test(&cma_dev->refcount)) 293e51060f0SSean Hefty complete(&cma_dev->comp); 294e51060f0SSean Hefty } 295e51060f0SSean Hefty 2963c86aa70SEli Cohen static inline void release_mc(struct kref *kref) 2973c86aa70SEli Cohen { 2983c86aa70SEli Cohen struct cma_multicast *mc = container_of(kref, struct cma_multicast, mcref); 2993c86aa70SEli Cohen 3003c86aa70SEli Cohen kfree(mc->multicast.ib); 3013c86aa70SEli Cohen kfree(mc); 3023c86aa70SEli Cohen } 3033c86aa70SEli Cohen 304a396d43aSSean Hefty static void cma_release_dev(struct rdma_id_private *id_priv) 305e51060f0SSean Hefty { 306a396d43aSSean Hefty mutex_lock(&lock); 307e51060f0SSean Hefty list_del(&id_priv->list); 308e51060f0SSean Hefty cma_deref_dev(id_priv->cma_dev); 309e51060f0SSean Hefty id_priv->cma_dev = NULL; 310a396d43aSSean Hefty mutex_unlock(&lock); 311e51060f0SSean Hefty } 312e51060f0SSean Hefty 313d2ca39f2SYossi Etigin static int cma_set_qkey(struct rdma_id_private *id_priv) 314c8f6a362SSean Hefty { 315c8f6a362SSean Hefty struct ib_sa_mcmember_rec rec; 316c8f6a362SSean Hefty int ret = 0; 317c8f6a362SSean Hefty 318d2ca39f2SYossi Etigin if (id_priv->qkey) 319d2ca39f2SYossi Etigin return 0; 320d2ca39f2SYossi Etigin 321d2ca39f2SYossi Etigin switch (id_priv->id.ps) { 322c8f6a362SSean Hefty case RDMA_PS_UDP: 323d2ca39f2SYossi Etigin id_priv->qkey = RDMA_UDP_QKEY; 324c8f6a362SSean Hefty break; 325c8f6a362SSean Hefty case RDMA_PS_IPOIB: 326d2ca39f2SYossi Etigin ib_addr_get_mgid(&id_priv->id.route.addr.dev_addr, &rec.mgid); 327d2ca39f2SYossi Etigin ret = ib_sa_get_mcmember_rec(id_priv->id.device, 328d2ca39f2SYossi Etigin id_priv->id.port_num, &rec.mgid, 329d2ca39f2SYossi Etigin &rec); 330d2ca39f2SYossi Etigin if (!ret) 331d2ca39f2SYossi Etigin id_priv->qkey = be32_to_cpu(rec.qkey); 332c8f6a362SSean Hefty break; 333c8f6a362SSean Hefty default: 334c8f6a362SSean Hefty break; 335c8f6a362SSean Hefty } 336c8f6a362SSean Hefty return ret; 337c8f6a362SSean Hefty } 338c8f6a362SSean Hefty 3393c86aa70SEli Cohen static int find_gid_port(struct ib_device *device, union ib_gid *gid, u8 port_num) 3403c86aa70SEli Cohen { 3413c86aa70SEli Cohen int i; 3423c86aa70SEli Cohen int err; 3433c86aa70SEli Cohen struct ib_port_attr props; 3443c86aa70SEli Cohen union ib_gid tmp; 3453c86aa70SEli Cohen 3463c86aa70SEli Cohen err = ib_query_port(device, port_num, &props); 3473c86aa70SEli Cohen if (err) 34863f05be2Sshefty return err; 3493c86aa70SEli Cohen 3503c86aa70SEli Cohen for (i = 0; i < props.gid_tbl_len; ++i) { 3513c86aa70SEli Cohen err = ib_query_gid(device, port_num, i, &tmp); 3523c86aa70SEli Cohen if (err) 35363f05be2Sshefty return err; 3543c86aa70SEli Cohen if (!memcmp(&tmp, gid, sizeof tmp)) 3553c86aa70SEli Cohen return 0; 3563c86aa70SEli Cohen } 3573c86aa70SEli Cohen 35863f05be2Sshefty return -EADDRNOTAVAIL; 3593c86aa70SEli Cohen } 3603c86aa70SEli Cohen 36107ebafbaSTom Tucker static int cma_acquire_dev(struct rdma_id_private *id_priv) 362e51060f0SSean Hefty { 363c8f6a362SSean Hefty struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 364e51060f0SSean Hefty struct cma_device *cma_dev; 3653c86aa70SEli Cohen union ib_gid gid, iboe_gid; 366e51060f0SSean Hefty int ret = -ENODEV; 3673c86aa70SEli Cohen u8 port; 3683c86aa70SEli Cohen enum rdma_link_layer dev_ll = dev_addr->dev_type == ARPHRD_INFINIBAND ? 3693c86aa70SEli Cohen IB_LINK_LAYER_INFINIBAND : IB_LINK_LAYER_ETHERNET; 370e51060f0SSean Hefty 3712efdd6a0SMoni Shoua if (dev_ll != IB_LINK_LAYER_INFINIBAND && 3722efdd6a0SMoni Shoua id_priv->id.ps == RDMA_PS_IPOIB) 3732efdd6a0SMoni Shoua return -EINVAL; 3742efdd6a0SMoni Shoua 375a396d43aSSean Hefty mutex_lock(&lock); 3763c86aa70SEli Cohen iboe_addr_get_sgid(dev_addr, &iboe_gid); 3773c86aa70SEli Cohen memcpy(&gid, dev_addr->src_dev_addr + 3783c86aa70SEli Cohen rdma_addr_gid_offset(dev_addr), sizeof gid); 379e51060f0SSean Hefty list_for_each_entry(cma_dev, &dev_list, list) { 3803c86aa70SEli Cohen for (port = 1; port <= cma_dev->device->phys_port_cnt; ++port) { 3813c86aa70SEli Cohen if (rdma_port_get_link_layer(cma_dev->device, port) == dev_ll) { 3823c86aa70SEli Cohen if (rdma_node_get_transport(cma_dev->device->node_type) == RDMA_TRANSPORT_IB && 3833c86aa70SEli Cohen rdma_port_get_link_layer(cma_dev->device, port) == IB_LINK_LAYER_ETHERNET) 3843c86aa70SEli Cohen ret = find_gid_port(cma_dev->device, &iboe_gid, port); 3853c86aa70SEli Cohen else 3863c86aa70SEli Cohen ret = find_gid_port(cma_dev->device, &gid, port); 3873c86aa70SEli Cohen 388e51060f0SSean Hefty if (!ret) { 3893c86aa70SEli Cohen id_priv->id.port_num = port; 3903c86aa70SEli Cohen goto out; 39163f05be2Sshefty } 392e51060f0SSean Hefty } 393e51060f0SSean Hefty } 3943c86aa70SEli Cohen } 3953c86aa70SEli Cohen 3963c86aa70SEli Cohen out: 3973c86aa70SEli Cohen if (!ret) 3983c86aa70SEli Cohen cma_attach_to_dev(id_priv, cma_dev); 3993c86aa70SEli Cohen 400a396d43aSSean Hefty mutex_unlock(&lock); 401e51060f0SSean Hefty return ret; 402e51060f0SSean Hefty } 403e51060f0SSean Hefty 404e51060f0SSean Hefty static void cma_deref_id(struct rdma_id_private *id_priv) 405e51060f0SSean Hefty { 406e51060f0SSean Hefty if (atomic_dec_and_test(&id_priv->refcount)) 407e51060f0SSean Hefty complete(&id_priv->comp); 408e51060f0SSean Hefty } 409e51060f0SSean Hefty 410de910bd9SOr Gerlitz static int cma_disable_callback(struct rdma_id_private *id_priv, 411550e5ca7SNir Muchtar enum rdma_cm_state state) 4128aa08602SSean Hefty { 413de910bd9SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 414de910bd9SOr Gerlitz if (id_priv->state != state) { 415de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 416de910bd9SOr Gerlitz return -EINVAL; 4178aa08602SSean Hefty } 418de910bd9SOr Gerlitz return 0; 419e51060f0SSean Hefty } 420e51060f0SSean Hefty 421e51060f0SSean Hefty struct rdma_cm_id *rdma_create_id(rdma_cm_event_handler event_handler, 422b26f9b99SSean Hefty void *context, enum rdma_port_space ps, 423b26f9b99SSean Hefty enum ib_qp_type qp_type) 424e51060f0SSean Hefty { 425e51060f0SSean Hefty struct rdma_id_private *id_priv; 426e51060f0SSean Hefty 427e51060f0SSean Hefty id_priv = kzalloc(sizeof *id_priv, GFP_KERNEL); 428e51060f0SSean Hefty if (!id_priv) 429e51060f0SSean Hefty return ERR_PTR(-ENOMEM); 430e51060f0SSean Hefty 43183e9502dSNir Muchtar id_priv->owner = task_pid_nr(current); 432550e5ca7SNir Muchtar id_priv->state = RDMA_CM_IDLE; 433e51060f0SSean Hefty id_priv->id.context = context; 434e51060f0SSean Hefty id_priv->id.event_handler = event_handler; 435e51060f0SSean Hefty id_priv->id.ps = ps; 436b26f9b99SSean Hefty id_priv->id.qp_type = qp_type; 437e51060f0SSean Hefty spin_lock_init(&id_priv->lock); 438c5483388SSean Hefty mutex_init(&id_priv->qp_mutex); 439e51060f0SSean Hefty init_completion(&id_priv->comp); 440e51060f0SSean Hefty atomic_set(&id_priv->refcount, 1); 441de910bd9SOr Gerlitz mutex_init(&id_priv->handler_mutex); 442e51060f0SSean Hefty INIT_LIST_HEAD(&id_priv->listen_list); 443c8f6a362SSean Hefty INIT_LIST_HEAD(&id_priv->mc_list); 444e51060f0SSean Hefty get_random_bytes(&id_priv->seq_num, sizeof id_priv->seq_num); 445e51060f0SSean Hefty 446e51060f0SSean Hefty return &id_priv->id; 447e51060f0SSean Hefty } 448e51060f0SSean Hefty EXPORT_SYMBOL(rdma_create_id); 449e51060f0SSean Hefty 450c8f6a362SSean Hefty static int cma_init_ud_qp(struct rdma_id_private *id_priv, struct ib_qp *qp) 451e51060f0SSean Hefty { 452e51060f0SSean Hefty struct ib_qp_attr qp_attr; 453c8f6a362SSean Hefty int qp_attr_mask, ret; 454e51060f0SSean Hefty 455c8f6a362SSean Hefty qp_attr.qp_state = IB_QPS_INIT; 456c8f6a362SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 457e51060f0SSean Hefty if (ret) 458e51060f0SSean Hefty return ret; 459e51060f0SSean Hefty 460c8f6a362SSean Hefty ret = ib_modify_qp(qp, &qp_attr, qp_attr_mask); 461c8f6a362SSean Hefty if (ret) 462c8f6a362SSean Hefty return ret; 463c8f6a362SSean Hefty 464c8f6a362SSean Hefty qp_attr.qp_state = IB_QPS_RTR; 465c8f6a362SSean Hefty ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE); 466c8f6a362SSean Hefty if (ret) 467c8f6a362SSean Hefty return ret; 468c8f6a362SSean Hefty 469c8f6a362SSean Hefty qp_attr.qp_state = IB_QPS_RTS; 470c8f6a362SSean Hefty qp_attr.sq_psn = 0; 471c8f6a362SSean Hefty ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE | IB_QP_SQ_PSN); 472c8f6a362SSean Hefty 473c8f6a362SSean Hefty return ret; 474e51060f0SSean Hefty } 475e51060f0SSean Hefty 476c8f6a362SSean Hefty static int cma_init_conn_qp(struct rdma_id_private *id_priv, struct ib_qp *qp) 47707ebafbaSTom Tucker { 47807ebafbaSTom Tucker struct ib_qp_attr qp_attr; 479c8f6a362SSean Hefty int qp_attr_mask, ret; 48007ebafbaSTom Tucker 48107ebafbaSTom Tucker qp_attr.qp_state = IB_QPS_INIT; 482c8f6a362SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 483c8f6a362SSean Hefty if (ret) 484c8f6a362SSean Hefty return ret; 48507ebafbaSTom Tucker 486c8f6a362SSean Hefty return ib_modify_qp(qp, &qp_attr, qp_attr_mask); 48707ebafbaSTom Tucker } 48807ebafbaSTom Tucker 489e51060f0SSean Hefty int rdma_create_qp(struct rdma_cm_id *id, struct ib_pd *pd, 490e51060f0SSean Hefty struct ib_qp_init_attr *qp_init_attr) 491e51060f0SSean Hefty { 492e51060f0SSean Hefty struct rdma_id_private *id_priv; 493e51060f0SSean Hefty struct ib_qp *qp; 494e51060f0SSean Hefty int ret; 495e51060f0SSean Hefty 496e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 497e51060f0SSean Hefty if (id->device != pd->device) 498e51060f0SSean Hefty return -EINVAL; 499e51060f0SSean Hefty 500e51060f0SSean Hefty qp = ib_create_qp(pd, qp_init_attr); 501e51060f0SSean Hefty if (IS_ERR(qp)) 502e51060f0SSean Hefty return PTR_ERR(qp); 503e51060f0SSean Hefty 504b26f9b99SSean Hefty if (id->qp_type == IB_QPT_UD) 505c8f6a362SSean Hefty ret = cma_init_ud_qp(id_priv, qp); 506c8f6a362SSean Hefty else 507c8f6a362SSean Hefty ret = cma_init_conn_qp(id_priv, qp); 508e51060f0SSean Hefty if (ret) 509e51060f0SSean Hefty goto err; 510e51060f0SSean Hefty 511e51060f0SSean Hefty id->qp = qp; 512e51060f0SSean Hefty id_priv->qp_num = qp->qp_num; 513e51060f0SSean Hefty id_priv->srq = (qp->srq != NULL); 514e51060f0SSean Hefty return 0; 515e51060f0SSean Hefty err: 516e51060f0SSean Hefty ib_destroy_qp(qp); 517e51060f0SSean Hefty return ret; 518e51060f0SSean Hefty } 519e51060f0SSean Hefty EXPORT_SYMBOL(rdma_create_qp); 520e51060f0SSean Hefty 521e51060f0SSean Hefty void rdma_destroy_qp(struct rdma_cm_id *id) 522e51060f0SSean Hefty { 523c5483388SSean Hefty struct rdma_id_private *id_priv; 524c5483388SSean Hefty 525c5483388SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 526c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 527c5483388SSean Hefty ib_destroy_qp(id_priv->id.qp); 528c5483388SSean Hefty id_priv->id.qp = NULL; 529c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 530e51060f0SSean Hefty } 531e51060f0SSean Hefty EXPORT_SYMBOL(rdma_destroy_qp); 532e51060f0SSean Hefty 5335851bb89SSean Hefty static int cma_modify_qp_rtr(struct rdma_id_private *id_priv, 5345851bb89SSean Hefty struct rdma_conn_param *conn_param) 535e51060f0SSean Hefty { 536e51060f0SSean Hefty struct ib_qp_attr qp_attr; 537e51060f0SSean Hefty int qp_attr_mask, ret; 538e51060f0SSean Hefty 539c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 540c5483388SSean Hefty if (!id_priv->id.qp) { 541c5483388SSean Hefty ret = 0; 542c5483388SSean Hefty goto out; 543c5483388SSean Hefty } 544e51060f0SSean Hefty 545e51060f0SSean Hefty /* Need to update QP attributes from default values. */ 546e51060f0SSean Hefty qp_attr.qp_state = IB_QPS_INIT; 547c5483388SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 548e51060f0SSean Hefty if (ret) 549c5483388SSean Hefty goto out; 550e51060f0SSean Hefty 551c5483388SSean Hefty ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask); 552e51060f0SSean Hefty if (ret) 553c5483388SSean Hefty goto out; 554e51060f0SSean Hefty 555e51060f0SSean Hefty qp_attr.qp_state = IB_QPS_RTR; 556c5483388SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 557e51060f0SSean Hefty if (ret) 558c5483388SSean Hefty goto out; 559e51060f0SSean Hefty 5605851bb89SSean Hefty if (conn_param) 5615851bb89SSean Hefty qp_attr.max_dest_rd_atomic = conn_param->responder_resources; 562c5483388SSean Hefty ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask); 563c5483388SSean Hefty out: 564c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 565c5483388SSean Hefty return ret; 566e51060f0SSean Hefty } 567e51060f0SSean Hefty 5685851bb89SSean Hefty static int cma_modify_qp_rts(struct rdma_id_private *id_priv, 5695851bb89SSean Hefty struct rdma_conn_param *conn_param) 570e51060f0SSean Hefty { 571e51060f0SSean Hefty struct ib_qp_attr qp_attr; 572e51060f0SSean Hefty int qp_attr_mask, ret; 573e51060f0SSean Hefty 574c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 575c5483388SSean Hefty if (!id_priv->id.qp) { 576c5483388SSean Hefty ret = 0; 577c5483388SSean Hefty goto out; 578e51060f0SSean Hefty } 579e51060f0SSean Hefty 580c5483388SSean Hefty qp_attr.qp_state = IB_QPS_RTS; 581c5483388SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 582c5483388SSean Hefty if (ret) 583c5483388SSean Hefty goto out; 584c5483388SSean Hefty 5855851bb89SSean Hefty if (conn_param) 5865851bb89SSean Hefty qp_attr.max_rd_atomic = conn_param->initiator_depth; 587c5483388SSean Hefty ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask); 588c5483388SSean Hefty out: 589c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 590c5483388SSean Hefty return ret; 591c5483388SSean Hefty } 592c5483388SSean Hefty 593c5483388SSean Hefty static int cma_modify_qp_err(struct rdma_id_private *id_priv) 594e51060f0SSean Hefty { 595e51060f0SSean Hefty struct ib_qp_attr qp_attr; 596c5483388SSean Hefty int ret; 597e51060f0SSean Hefty 598c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 599c5483388SSean Hefty if (!id_priv->id.qp) { 600c5483388SSean Hefty ret = 0; 601c5483388SSean Hefty goto out; 602c5483388SSean Hefty } 603e51060f0SSean Hefty 604e51060f0SSean Hefty qp_attr.qp_state = IB_QPS_ERR; 605c5483388SSean Hefty ret = ib_modify_qp(id_priv->id.qp, &qp_attr, IB_QP_STATE); 606c5483388SSean Hefty out: 607c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 608c5483388SSean Hefty return ret; 609e51060f0SSean Hefty } 610e51060f0SSean Hefty 611c8f6a362SSean Hefty static int cma_ib_init_qp_attr(struct rdma_id_private *id_priv, 612c8f6a362SSean Hefty struct ib_qp_attr *qp_attr, int *qp_attr_mask) 613c8f6a362SSean Hefty { 614c8f6a362SSean Hefty struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 615c8f6a362SSean Hefty int ret; 6163c86aa70SEli Cohen u16 pkey; 6173c86aa70SEli Cohen 6183c86aa70SEli Cohen if (rdma_port_get_link_layer(id_priv->id.device, id_priv->id.port_num) == 6193c86aa70SEli Cohen IB_LINK_LAYER_INFINIBAND) 6203c86aa70SEli Cohen pkey = ib_addr_get_pkey(dev_addr); 6213c86aa70SEli Cohen else 6223c86aa70SEli Cohen pkey = 0xffff; 623c8f6a362SSean Hefty 624c8f6a362SSean Hefty ret = ib_find_cached_pkey(id_priv->id.device, id_priv->id.port_num, 6253c86aa70SEli Cohen pkey, &qp_attr->pkey_index); 626c8f6a362SSean Hefty if (ret) 627c8f6a362SSean Hefty return ret; 628c8f6a362SSean Hefty 629c8f6a362SSean Hefty qp_attr->port_num = id_priv->id.port_num; 630c8f6a362SSean Hefty *qp_attr_mask = IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_PORT; 631c8f6a362SSean Hefty 632b26f9b99SSean Hefty if (id_priv->id.qp_type == IB_QPT_UD) { 633d2ca39f2SYossi Etigin ret = cma_set_qkey(id_priv); 634d2ca39f2SYossi Etigin if (ret) 635d2ca39f2SYossi Etigin return ret; 636d2ca39f2SYossi Etigin 637c8f6a362SSean Hefty qp_attr->qkey = id_priv->qkey; 638c8f6a362SSean Hefty *qp_attr_mask |= IB_QP_QKEY; 639c8f6a362SSean Hefty } else { 640c8f6a362SSean Hefty qp_attr->qp_access_flags = 0; 641c8f6a362SSean Hefty *qp_attr_mask |= IB_QP_ACCESS_FLAGS; 642c8f6a362SSean Hefty } 643c8f6a362SSean Hefty return 0; 644c8f6a362SSean Hefty } 645c8f6a362SSean Hefty 646e51060f0SSean Hefty int rdma_init_qp_attr(struct rdma_cm_id *id, struct ib_qp_attr *qp_attr, 647e51060f0SSean Hefty int *qp_attr_mask) 648e51060f0SSean Hefty { 649e51060f0SSean Hefty struct rdma_id_private *id_priv; 650c8f6a362SSean Hefty int ret = 0; 651e51060f0SSean Hefty 652e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 65307ebafbaSTom Tucker switch (rdma_node_get_transport(id_priv->id.device->node_type)) { 65407ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 655b26f9b99SSean Hefty if (!id_priv->cm_id.ib || (id_priv->id.qp_type == IB_QPT_UD)) 656c8f6a362SSean Hefty ret = cma_ib_init_qp_attr(id_priv, qp_attr, qp_attr_mask); 657c8f6a362SSean Hefty else 658e51060f0SSean Hefty ret = ib_cm_init_qp_attr(id_priv->cm_id.ib, qp_attr, 659e51060f0SSean Hefty qp_attr_mask); 660e51060f0SSean Hefty if (qp_attr->qp_state == IB_QPS_RTR) 661e51060f0SSean Hefty qp_attr->rq_psn = id_priv->seq_num; 662e51060f0SSean Hefty break; 66307ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 664c8f6a362SSean Hefty if (!id_priv->cm_id.iw) { 6658f076531SDotan Barak qp_attr->qp_access_flags = 0; 666c8f6a362SSean Hefty *qp_attr_mask = IB_QP_STATE | IB_QP_ACCESS_FLAGS; 667c8f6a362SSean Hefty } else 66807ebafbaSTom Tucker ret = iw_cm_init_qp_attr(id_priv->cm_id.iw, qp_attr, 66907ebafbaSTom Tucker qp_attr_mask); 67007ebafbaSTom Tucker break; 671e51060f0SSean Hefty default: 672e51060f0SSean Hefty ret = -ENOSYS; 673e51060f0SSean Hefty break; 674e51060f0SSean Hefty } 675e51060f0SSean Hefty 676e51060f0SSean Hefty return ret; 677e51060f0SSean Hefty } 678e51060f0SSean Hefty EXPORT_SYMBOL(rdma_init_qp_attr); 679e51060f0SSean Hefty 680e51060f0SSean Hefty static inline int cma_zero_addr(struct sockaddr *addr) 681e51060f0SSean Hefty { 682e51060f0SSean Hefty struct in6_addr *ip6; 683e51060f0SSean Hefty 684e51060f0SSean Hefty if (addr->sa_family == AF_INET) 6856360a02aSJoe Perches return ipv4_is_zeronet( 6866360a02aSJoe Perches ((struct sockaddr_in *)addr)->sin_addr.s_addr); 687e51060f0SSean Hefty else { 688e51060f0SSean Hefty ip6 = &((struct sockaddr_in6 *) addr)->sin6_addr; 689e51060f0SSean Hefty return (ip6->s6_addr32[0] | ip6->s6_addr32[1] | 6905fd571cbSEric Sesterhenn ip6->s6_addr32[2] | ip6->s6_addr32[3]) == 0; 691e51060f0SSean Hefty } 692e51060f0SSean Hefty } 693e51060f0SSean Hefty 694e51060f0SSean Hefty static inline int cma_loopback_addr(struct sockaddr *addr) 695e51060f0SSean Hefty { 6961f5175adSAleksey Senin if (addr->sa_family == AF_INET) 6971f5175adSAleksey Senin return ipv4_is_loopback( 6981f5175adSAleksey Senin ((struct sockaddr_in *) addr)->sin_addr.s_addr); 6991f5175adSAleksey Senin else 7001f5175adSAleksey Senin return ipv6_addr_loopback( 7011f5175adSAleksey Senin &((struct sockaddr_in6 *) addr)->sin6_addr); 702e51060f0SSean Hefty } 703e51060f0SSean Hefty 704e51060f0SSean Hefty static inline int cma_any_addr(struct sockaddr *addr) 705e51060f0SSean Hefty { 706e51060f0SSean Hefty return cma_zero_addr(addr) || cma_loopback_addr(addr); 707e51060f0SSean Hefty } 708e51060f0SSean Hefty 70943b752daSHefty, Sean static int cma_addr_cmp(struct sockaddr *src, struct sockaddr *dst) 71043b752daSHefty, Sean { 71143b752daSHefty, Sean if (src->sa_family != dst->sa_family) 71243b752daSHefty, Sean return -1; 71343b752daSHefty, Sean 71443b752daSHefty, Sean switch (src->sa_family) { 71543b752daSHefty, Sean case AF_INET: 71643b752daSHefty, Sean return ((struct sockaddr_in *) src)->sin_addr.s_addr != 71743b752daSHefty, Sean ((struct sockaddr_in *) dst)->sin_addr.s_addr; 71843b752daSHefty, Sean default: 71943b752daSHefty, Sean return ipv6_addr_cmp(&((struct sockaddr_in6 *) src)->sin6_addr, 72043b752daSHefty, Sean &((struct sockaddr_in6 *) dst)->sin6_addr); 72143b752daSHefty, Sean } 72243b752daSHefty, Sean } 72343b752daSHefty, Sean 724628e5f6dSSean Hefty static inline __be16 cma_port(struct sockaddr *addr) 725628e5f6dSSean Hefty { 726628e5f6dSSean Hefty if (addr->sa_family == AF_INET) 727628e5f6dSSean Hefty return ((struct sockaddr_in *) addr)->sin_port; 728628e5f6dSSean Hefty else 729628e5f6dSSean Hefty return ((struct sockaddr_in6 *) addr)->sin6_port; 730628e5f6dSSean Hefty } 731628e5f6dSSean Hefty 732e51060f0SSean Hefty static inline int cma_any_port(struct sockaddr *addr) 733e51060f0SSean Hefty { 734628e5f6dSSean Hefty return !cma_port(addr); 735e51060f0SSean Hefty } 736e51060f0SSean Hefty 737e51060f0SSean Hefty static int cma_get_net_info(void *hdr, enum rdma_port_space ps, 7381b90c137SAl Viro u8 *ip_ver, __be16 *port, 739e51060f0SSean Hefty union cma_ip_addr **src, union cma_ip_addr **dst) 740e51060f0SSean Hefty { 741e51060f0SSean Hefty switch (ps) { 742e51060f0SSean Hefty case RDMA_PS_SDP: 743e51060f0SSean Hefty if (sdp_get_majv(((struct sdp_hh *) hdr)->sdp_version) != 744e51060f0SSean Hefty SDP_MAJ_VERSION) 745e51060f0SSean Hefty return -EINVAL; 746e51060f0SSean Hefty 747e51060f0SSean Hefty *ip_ver = sdp_get_ip_ver(hdr); 748e51060f0SSean Hefty *port = ((struct sdp_hh *) hdr)->port; 749e51060f0SSean Hefty *src = &((struct sdp_hh *) hdr)->src_addr; 750e51060f0SSean Hefty *dst = &((struct sdp_hh *) hdr)->dst_addr; 751e51060f0SSean Hefty break; 752e51060f0SSean Hefty default: 753e51060f0SSean Hefty if (((struct cma_hdr *) hdr)->cma_version != CMA_VERSION) 754e51060f0SSean Hefty return -EINVAL; 755e51060f0SSean Hefty 756e51060f0SSean Hefty *ip_ver = cma_get_ip_ver(hdr); 757e51060f0SSean Hefty *port = ((struct cma_hdr *) hdr)->port; 758e51060f0SSean Hefty *src = &((struct cma_hdr *) hdr)->src_addr; 759e51060f0SSean Hefty *dst = &((struct cma_hdr *) hdr)->dst_addr; 760e51060f0SSean Hefty break; 761e51060f0SSean Hefty } 762e51060f0SSean Hefty 763e51060f0SSean Hefty if (*ip_ver != 4 && *ip_ver != 6) 764e51060f0SSean Hefty return -EINVAL; 765e51060f0SSean Hefty return 0; 766e51060f0SSean Hefty } 767e51060f0SSean Hefty 768e51060f0SSean Hefty static void cma_save_net_info(struct rdma_addr *addr, 769e51060f0SSean Hefty struct rdma_addr *listen_addr, 7701b90c137SAl Viro u8 ip_ver, __be16 port, 771e51060f0SSean Hefty union cma_ip_addr *src, union cma_ip_addr *dst) 772e51060f0SSean Hefty { 773e51060f0SSean Hefty struct sockaddr_in *listen4, *ip4; 774e51060f0SSean Hefty struct sockaddr_in6 *listen6, *ip6; 775e51060f0SSean Hefty 776e51060f0SSean Hefty switch (ip_ver) { 777e51060f0SSean Hefty case 4: 778e51060f0SSean Hefty listen4 = (struct sockaddr_in *) &listen_addr->src_addr; 779e51060f0SSean Hefty ip4 = (struct sockaddr_in *) &addr->src_addr; 780e51060f0SSean Hefty ip4->sin_family = listen4->sin_family; 781e51060f0SSean Hefty ip4->sin_addr.s_addr = dst->ip4.addr; 782e51060f0SSean Hefty ip4->sin_port = listen4->sin_port; 783e51060f0SSean Hefty 784e51060f0SSean Hefty ip4 = (struct sockaddr_in *) &addr->dst_addr; 785e51060f0SSean Hefty ip4->sin_family = listen4->sin_family; 786e51060f0SSean Hefty ip4->sin_addr.s_addr = src->ip4.addr; 787e51060f0SSean Hefty ip4->sin_port = port; 788e51060f0SSean Hefty break; 789e51060f0SSean Hefty case 6: 790e51060f0SSean Hefty listen6 = (struct sockaddr_in6 *) &listen_addr->src_addr; 791e51060f0SSean Hefty ip6 = (struct sockaddr_in6 *) &addr->src_addr; 792e51060f0SSean Hefty ip6->sin6_family = listen6->sin6_family; 793e51060f0SSean Hefty ip6->sin6_addr = dst->ip6; 794e51060f0SSean Hefty ip6->sin6_port = listen6->sin6_port; 795e51060f0SSean Hefty 796e51060f0SSean Hefty ip6 = (struct sockaddr_in6 *) &addr->dst_addr; 797e51060f0SSean Hefty ip6->sin6_family = listen6->sin6_family; 798e51060f0SSean Hefty ip6->sin6_addr = src->ip6; 799e51060f0SSean Hefty ip6->sin6_port = port; 800e51060f0SSean Hefty break; 801e51060f0SSean Hefty default: 802e51060f0SSean Hefty break; 803e51060f0SSean Hefty } 804e51060f0SSean Hefty } 805e51060f0SSean Hefty 806e51060f0SSean Hefty static inline int cma_user_data_offset(enum rdma_port_space ps) 807e51060f0SSean Hefty { 808e51060f0SSean Hefty switch (ps) { 809e51060f0SSean Hefty case RDMA_PS_SDP: 810e51060f0SSean Hefty return 0; 811e51060f0SSean Hefty default: 812e51060f0SSean Hefty return sizeof(struct cma_hdr); 813e51060f0SSean Hefty } 814e51060f0SSean Hefty } 815e51060f0SSean Hefty 816e51060f0SSean Hefty static void cma_cancel_route(struct rdma_id_private *id_priv) 817e51060f0SSean Hefty { 8183c86aa70SEli Cohen switch (rdma_port_get_link_layer(id_priv->id.device, id_priv->id.port_num)) { 8193c86aa70SEli Cohen case IB_LINK_LAYER_INFINIBAND: 820e51060f0SSean Hefty if (id_priv->query) 821e51060f0SSean Hefty ib_sa_cancel_query(id_priv->query_id, id_priv->query); 822e51060f0SSean Hefty break; 823e51060f0SSean Hefty default: 824e51060f0SSean Hefty break; 825e51060f0SSean Hefty } 826e51060f0SSean Hefty } 827e51060f0SSean Hefty 828e51060f0SSean Hefty static void cma_cancel_listens(struct rdma_id_private *id_priv) 829e51060f0SSean Hefty { 830e51060f0SSean Hefty struct rdma_id_private *dev_id_priv; 831e51060f0SSean Hefty 832d02d1f53SSean Hefty /* 833d02d1f53SSean Hefty * Remove from listen_any_list to prevent added devices from spawning 834d02d1f53SSean Hefty * additional listen requests. 835d02d1f53SSean Hefty */ 836e51060f0SSean Hefty mutex_lock(&lock); 837e51060f0SSean Hefty list_del(&id_priv->list); 838e51060f0SSean Hefty 839e51060f0SSean Hefty while (!list_empty(&id_priv->listen_list)) { 840e51060f0SSean Hefty dev_id_priv = list_entry(id_priv->listen_list.next, 841e51060f0SSean Hefty struct rdma_id_private, listen_list); 842d02d1f53SSean Hefty /* sync with device removal to avoid duplicate destruction */ 843d02d1f53SSean Hefty list_del_init(&dev_id_priv->list); 844d02d1f53SSean Hefty list_del(&dev_id_priv->listen_list); 845d02d1f53SSean Hefty mutex_unlock(&lock); 846d02d1f53SSean Hefty 847d02d1f53SSean Hefty rdma_destroy_id(&dev_id_priv->id); 848d02d1f53SSean Hefty mutex_lock(&lock); 849e51060f0SSean Hefty } 850e51060f0SSean Hefty mutex_unlock(&lock); 851e51060f0SSean Hefty } 852e51060f0SSean Hefty 853e51060f0SSean Hefty static void cma_cancel_operation(struct rdma_id_private *id_priv, 854550e5ca7SNir Muchtar enum rdma_cm_state state) 855e51060f0SSean Hefty { 856e51060f0SSean Hefty switch (state) { 857550e5ca7SNir Muchtar case RDMA_CM_ADDR_QUERY: 858e51060f0SSean Hefty rdma_addr_cancel(&id_priv->id.route.addr.dev_addr); 859e51060f0SSean Hefty break; 860550e5ca7SNir Muchtar case RDMA_CM_ROUTE_QUERY: 861e51060f0SSean Hefty cma_cancel_route(id_priv); 862e51060f0SSean Hefty break; 863550e5ca7SNir Muchtar case RDMA_CM_LISTEN: 8643f446754SRoland Dreier if (cma_any_addr((struct sockaddr *) &id_priv->id.route.addr.src_addr) 8653f446754SRoland Dreier && !id_priv->cma_dev) 866e51060f0SSean Hefty cma_cancel_listens(id_priv); 867e51060f0SSean Hefty break; 868e51060f0SSean Hefty default: 869e51060f0SSean Hefty break; 870e51060f0SSean Hefty } 871e51060f0SSean Hefty } 872e51060f0SSean Hefty 873e51060f0SSean Hefty static void cma_release_port(struct rdma_id_private *id_priv) 874e51060f0SSean Hefty { 875e51060f0SSean Hefty struct rdma_bind_list *bind_list = id_priv->bind_list; 876e51060f0SSean Hefty 877e51060f0SSean Hefty if (!bind_list) 878e51060f0SSean Hefty return; 879e51060f0SSean Hefty 880e51060f0SSean Hefty mutex_lock(&lock); 881e51060f0SSean Hefty hlist_del(&id_priv->node); 882e51060f0SSean Hefty if (hlist_empty(&bind_list->owners)) { 883e51060f0SSean Hefty idr_remove(bind_list->ps, bind_list->port); 884e51060f0SSean Hefty kfree(bind_list); 885e51060f0SSean Hefty } 886e51060f0SSean Hefty mutex_unlock(&lock); 887e51060f0SSean Hefty } 888e51060f0SSean Hefty 889c8f6a362SSean Hefty static void cma_leave_mc_groups(struct rdma_id_private *id_priv) 890c8f6a362SSean Hefty { 891c8f6a362SSean Hefty struct cma_multicast *mc; 892c8f6a362SSean Hefty 893c8f6a362SSean Hefty while (!list_empty(&id_priv->mc_list)) { 894c8f6a362SSean Hefty mc = container_of(id_priv->mc_list.next, 895c8f6a362SSean Hefty struct cma_multicast, list); 896c8f6a362SSean Hefty list_del(&mc->list); 8973c86aa70SEli Cohen switch (rdma_port_get_link_layer(id_priv->cma_dev->device, id_priv->id.port_num)) { 8983c86aa70SEli Cohen case IB_LINK_LAYER_INFINIBAND: 899c8f6a362SSean Hefty ib_sa_free_multicast(mc->multicast.ib); 900c8f6a362SSean Hefty kfree(mc); 9013c86aa70SEli Cohen break; 9023c86aa70SEli Cohen case IB_LINK_LAYER_ETHERNET: 9033c86aa70SEli Cohen kref_put(&mc->mcref, release_mc); 9043c86aa70SEli Cohen break; 9053c86aa70SEli Cohen default: 9063c86aa70SEli Cohen break; 9073c86aa70SEli Cohen } 908c8f6a362SSean Hefty } 909c8f6a362SSean Hefty } 910c8f6a362SSean Hefty 911e51060f0SSean Hefty void rdma_destroy_id(struct rdma_cm_id *id) 912e51060f0SSean Hefty { 913e51060f0SSean Hefty struct rdma_id_private *id_priv; 914550e5ca7SNir Muchtar enum rdma_cm_state state; 915e51060f0SSean Hefty 916e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 917550e5ca7SNir Muchtar state = cma_exch(id_priv, RDMA_CM_DESTROYING); 918e51060f0SSean Hefty cma_cancel_operation(id_priv, state); 919e51060f0SSean Hefty 920a396d43aSSean Hefty /* 921a396d43aSSean Hefty * Wait for any active callback to finish. New callbacks will find 922a396d43aSSean Hefty * the id_priv state set to destroying and abort. 923a396d43aSSean Hefty */ 924a396d43aSSean Hefty mutex_lock(&id_priv->handler_mutex); 925a396d43aSSean Hefty mutex_unlock(&id_priv->handler_mutex); 926a396d43aSSean Hefty 927e51060f0SSean Hefty if (id_priv->cma_dev) { 9283c86aa70SEli Cohen switch (rdma_node_get_transport(id_priv->id.device->node_type)) { 92907ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 9300c9361fcSJack Morgenstein if (id_priv->cm_id.ib) 931e51060f0SSean Hefty ib_destroy_cm_id(id_priv->cm_id.ib); 932e51060f0SSean Hefty break; 93307ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 9340c9361fcSJack Morgenstein if (id_priv->cm_id.iw) 93507ebafbaSTom Tucker iw_destroy_cm_id(id_priv->cm_id.iw); 93607ebafbaSTom Tucker break; 937e51060f0SSean Hefty default: 938e51060f0SSean Hefty break; 939e51060f0SSean Hefty } 940c8f6a362SSean Hefty cma_leave_mc_groups(id_priv); 941a396d43aSSean Hefty cma_release_dev(id_priv); 942e51060f0SSean Hefty } 943e51060f0SSean Hefty 944e51060f0SSean Hefty cma_release_port(id_priv); 945e51060f0SSean Hefty cma_deref_id(id_priv); 946e51060f0SSean Hefty wait_for_completion(&id_priv->comp); 947e51060f0SSean Hefty 948d02d1f53SSean Hefty if (id_priv->internal_id) 949d02d1f53SSean Hefty cma_deref_id(id_priv->id.context); 950d02d1f53SSean Hefty 951e51060f0SSean Hefty kfree(id_priv->id.route.path_rec); 952e51060f0SSean Hefty kfree(id_priv); 953e51060f0SSean Hefty } 954e51060f0SSean Hefty EXPORT_SYMBOL(rdma_destroy_id); 955e51060f0SSean Hefty 956e51060f0SSean Hefty static int cma_rep_recv(struct rdma_id_private *id_priv) 957e51060f0SSean Hefty { 958e51060f0SSean Hefty int ret; 959e51060f0SSean Hefty 9605851bb89SSean Hefty ret = cma_modify_qp_rtr(id_priv, NULL); 961e51060f0SSean Hefty if (ret) 962e51060f0SSean Hefty goto reject; 963e51060f0SSean Hefty 9645851bb89SSean Hefty ret = cma_modify_qp_rts(id_priv, NULL); 965e51060f0SSean Hefty if (ret) 966e51060f0SSean Hefty goto reject; 967e51060f0SSean Hefty 968e51060f0SSean Hefty ret = ib_send_cm_rtu(id_priv->cm_id.ib, NULL, 0); 969e51060f0SSean Hefty if (ret) 970e51060f0SSean Hefty goto reject; 971e51060f0SSean Hefty 972e51060f0SSean Hefty return 0; 973e51060f0SSean Hefty reject: 974c5483388SSean Hefty cma_modify_qp_err(id_priv); 975e51060f0SSean Hefty ib_send_cm_rej(id_priv->cm_id.ib, IB_CM_REJ_CONSUMER_DEFINED, 976e51060f0SSean Hefty NULL, 0, NULL, 0); 977e51060f0SSean Hefty return ret; 978e51060f0SSean Hefty } 979e51060f0SSean Hefty 980e51060f0SSean Hefty static int cma_verify_rep(struct rdma_id_private *id_priv, void *data) 981e51060f0SSean Hefty { 982e51060f0SSean Hefty if (id_priv->id.ps == RDMA_PS_SDP && 983e51060f0SSean Hefty sdp_get_majv(((struct sdp_hah *) data)->sdp_version) != 984e51060f0SSean Hefty SDP_MAJ_VERSION) 985e51060f0SSean Hefty return -EINVAL; 986e51060f0SSean Hefty 987e51060f0SSean Hefty return 0; 988e51060f0SSean Hefty } 989e51060f0SSean Hefty 990a1b1b61fSSean Hefty static void cma_set_rep_event_data(struct rdma_cm_event *event, 991a1b1b61fSSean Hefty struct ib_cm_rep_event_param *rep_data, 992a1b1b61fSSean Hefty void *private_data) 993a1b1b61fSSean Hefty { 994a1b1b61fSSean Hefty event->param.conn.private_data = private_data; 995a1b1b61fSSean Hefty event->param.conn.private_data_len = IB_CM_REP_PRIVATE_DATA_SIZE; 996a1b1b61fSSean Hefty event->param.conn.responder_resources = rep_data->responder_resources; 997a1b1b61fSSean Hefty event->param.conn.initiator_depth = rep_data->initiator_depth; 998a1b1b61fSSean Hefty event->param.conn.flow_control = rep_data->flow_control; 999a1b1b61fSSean Hefty event->param.conn.rnr_retry_count = rep_data->rnr_retry_count; 1000a1b1b61fSSean Hefty event->param.conn.srq = rep_data->srq; 1001a1b1b61fSSean Hefty event->param.conn.qp_num = rep_data->remote_qpn; 1002a1b1b61fSSean Hefty } 1003a1b1b61fSSean Hefty 1004e51060f0SSean Hefty static int cma_ib_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event) 1005e51060f0SSean Hefty { 1006e51060f0SSean Hefty struct rdma_id_private *id_priv = cm_id->context; 1007a1b1b61fSSean Hefty struct rdma_cm_event event; 1008a1b1b61fSSean Hefty int ret = 0; 1009e51060f0SSean Hefty 101038ca83a5SAmir Vadai if ((ib_event->event != IB_CM_TIMEWAIT_EXIT && 1011550e5ca7SNir Muchtar cma_disable_callback(id_priv, RDMA_CM_CONNECT)) || 101238ca83a5SAmir Vadai (ib_event->event == IB_CM_TIMEWAIT_EXIT && 1013550e5ca7SNir Muchtar cma_disable_callback(id_priv, RDMA_CM_DISCONNECT))) 10148aa08602SSean Hefty return 0; 1015e51060f0SSean Hefty 1016a1b1b61fSSean Hefty memset(&event, 0, sizeof event); 1017e51060f0SSean Hefty switch (ib_event->event) { 1018e51060f0SSean Hefty case IB_CM_REQ_ERROR: 1019e51060f0SSean Hefty case IB_CM_REP_ERROR: 1020a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_UNREACHABLE; 1021a1b1b61fSSean Hefty event.status = -ETIMEDOUT; 1022e51060f0SSean Hefty break; 1023e51060f0SSean Hefty case IB_CM_REP_RECEIVED: 1024a1b1b61fSSean Hefty event.status = cma_verify_rep(id_priv, ib_event->private_data); 1025a1b1b61fSSean Hefty if (event.status) 1026a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_CONNECT_ERROR; 1027e51060f0SSean Hefty else if (id_priv->id.qp && id_priv->id.ps != RDMA_PS_SDP) { 1028a1b1b61fSSean Hefty event.status = cma_rep_recv(id_priv); 1029a1b1b61fSSean Hefty event.event = event.status ? RDMA_CM_EVENT_CONNECT_ERROR : 1030e51060f0SSean Hefty RDMA_CM_EVENT_ESTABLISHED; 1031e51060f0SSean Hefty } else 1032a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_CONNECT_RESPONSE; 1033a1b1b61fSSean Hefty cma_set_rep_event_data(&event, &ib_event->param.rep_rcvd, 1034a1b1b61fSSean Hefty ib_event->private_data); 1035e51060f0SSean Hefty break; 1036e51060f0SSean Hefty case IB_CM_RTU_RECEIVED: 10370fe313b0SSean Hefty case IB_CM_USER_ESTABLISHED: 10380fe313b0SSean Hefty event.event = RDMA_CM_EVENT_ESTABLISHED; 1039e51060f0SSean Hefty break; 1040e51060f0SSean Hefty case IB_CM_DREQ_ERROR: 1041a1b1b61fSSean Hefty event.status = -ETIMEDOUT; /* fall through */ 1042e51060f0SSean Hefty case IB_CM_DREQ_RECEIVED: 1043e51060f0SSean Hefty case IB_CM_DREP_RECEIVED: 1044550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_CONNECT, 1045550e5ca7SNir Muchtar RDMA_CM_DISCONNECT)) 1046e51060f0SSean Hefty goto out; 1047a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_DISCONNECTED; 1048e51060f0SSean Hefty break; 1049e51060f0SSean Hefty case IB_CM_TIMEWAIT_EXIT: 105038ca83a5SAmir Vadai event.event = RDMA_CM_EVENT_TIMEWAIT_EXIT; 105138ca83a5SAmir Vadai break; 1052e51060f0SSean Hefty case IB_CM_MRA_RECEIVED: 1053e51060f0SSean Hefty /* ignore event */ 1054e51060f0SSean Hefty goto out; 1055e51060f0SSean Hefty case IB_CM_REJ_RECEIVED: 1056c5483388SSean Hefty cma_modify_qp_err(id_priv); 1057a1b1b61fSSean Hefty event.status = ib_event->param.rej_rcvd.reason; 1058a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_REJECTED; 1059a1b1b61fSSean Hefty event.param.conn.private_data = ib_event->private_data; 1060a1b1b61fSSean Hefty event.param.conn.private_data_len = IB_CM_REJ_PRIVATE_DATA_SIZE; 1061e51060f0SSean Hefty break; 1062e51060f0SSean Hefty default: 1063468f2239SRoland Dreier printk(KERN_ERR "RDMA CMA: unexpected IB CM event: %d\n", 1064e51060f0SSean Hefty ib_event->event); 1065e51060f0SSean Hefty goto out; 1066e51060f0SSean Hefty } 1067e51060f0SSean Hefty 1068a1b1b61fSSean Hefty ret = id_priv->id.event_handler(&id_priv->id, &event); 1069e51060f0SSean Hefty if (ret) { 1070e51060f0SSean Hefty /* Destroy the CM ID by returning a non-zero value. */ 1071e51060f0SSean Hefty id_priv->cm_id.ib = NULL; 1072550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 1073de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 1074e51060f0SSean Hefty rdma_destroy_id(&id_priv->id); 1075e51060f0SSean Hefty return ret; 1076e51060f0SSean Hefty } 1077e51060f0SSean Hefty out: 1078de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 1079e51060f0SSean Hefty return ret; 1080e51060f0SSean Hefty } 1081e51060f0SSean Hefty 1082628e5f6dSSean Hefty static struct rdma_id_private *cma_new_conn_id(struct rdma_cm_id *listen_id, 1083e51060f0SSean Hefty struct ib_cm_event *ib_event) 1084e51060f0SSean Hefty { 1085e51060f0SSean Hefty struct rdma_id_private *id_priv; 1086e51060f0SSean Hefty struct rdma_cm_id *id; 1087e51060f0SSean Hefty struct rdma_route *rt; 1088e51060f0SSean Hefty union cma_ip_addr *src, *dst; 10891b90c137SAl Viro __be16 port; 1090e51060f0SSean Hefty u8 ip_ver; 109164c5e613SOr Gerlitz int ret; 1092e51060f0SSean Hefty 1093e51060f0SSean Hefty if (cma_get_net_info(ib_event->private_data, listen_id->ps, 1094e51060f0SSean Hefty &ip_ver, &port, &src, &dst)) 10950c9361fcSJack Morgenstein return NULL; 1096e51060f0SSean Hefty 10973f168d2bSKrishna Kumar id = rdma_create_id(listen_id->event_handler, listen_id->context, 1098b26f9b99SSean Hefty listen_id->ps, ib_event->param.req_rcvd.qp_type); 10993f168d2bSKrishna Kumar if (IS_ERR(id)) 11000c9361fcSJack Morgenstein return NULL; 11013f168d2bSKrishna Kumar 1102e51060f0SSean Hefty cma_save_net_info(&id->route.addr, &listen_id->route.addr, 1103e51060f0SSean Hefty ip_ver, port, src, dst); 11043f168d2bSKrishna Kumar 11053f168d2bSKrishna Kumar rt = &id->route; 11063f168d2bSKrishna Kumar rt->num_paths = ib_event->param.req_rcvd.alternate_path ? 2 : 1; 11073f168d2bSKrishna Kumar rt->path_rec = kmalloc(sizeof *rt->path_rec * rt->num_paths, 11083f168d2bSKrishna Kumar GFP_KERNEL); 11093f168d2bSKrishna Kumar if (!rt->path_rec) 11100c9361fcSJack Morgenstein goto err; 11113f168d2bSKrishna Kumar 1112e51060f0SSean Hefty rt->path_rec[0] = *ib_event->param.req_rcvd.primary_path; 1113e51060f0SSean Hefty if (rt->num_paths == 2) 1114e51060f0SSean Hefty rt->path_rec[1] = *ib_event->param.req_rcvd.alternate_path; 1115e51060f0SSean Hefty 11166f8372b6SSean Hefty if (cma_any_addr((struct sockaddr *) &rt->addr.src_addr)) { 11176f8372b6SSean Hefty rt->addr.dev_addr.dev_type = ARPHRD_INFINIBAND; 11186f8372b6SSean Hefty rdma_addr_set_sgid(&rt->addr.dev_addr, &rt->path_rec[0].sgid); 111946ea5061SSean Hefty ib_addr_set_pkey(&rt->addr.dev_addr, be16_to_cpu(rt->path_rec[0].pkey)); 11206f8372b6SSean Hefty } else { 11216f8372b6SSean Hefty ret = rdma_translate_ip((struct sockaddr *) &rt->addr.src_addr, 11226f8372b6SSean Hefty &rt->addr.dev_addr); 112364c5e613SOr Gerlitz if (ret) 11240c9361fcSJack Morgenstein goto err; 11256f8372b6SSean Hefty } 11266f8372b6SSean Hefty rdma_addr_set_dgid(&rt->addr.dev_addr, &rt->path_rec[0].dgid); 1127e51060f0SSean Hefty 1128e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1129550e5ca7SNir Muchtar id_priv->state = RDMA_CM_CONNECT; 1130e51060f0SSean Hefty return id_priv; 11313f168d2bSKrishna Kumar 11323f168d2bSKrishna Kumar err: 11330c9361fcSJack Morgenstein rdma_destroy_id(id); 1134e51060f0SSean Hefty return NULL; 1135e51060f0SSean Hefty } 1136e51060f0SSean Hefty 1137628e5f6dSSean Hefty static struct rdma_id_private *cma_new_udp_id(struct rdma_cm_id *listen_id, 1138628e5f6dSSean Hefty struct ib_cm_event *ib_event) 1139628e5f6dSSean Hefty { 1140628e5f6dSSean Hefty struct rdma_id_private *id_priv; 1141628e5f6dSSean Hefty struct rdma_cm_id *id; 1142628e5f6dSSean Hefty union cma_ip_addr *src, *dst; 11431b90c137SAl Viro __be16 port; 1144628e5f6dSSean Hefty u8 ip_ver; 1145628e5f6dSSean Hefty int ret; 1146628e5f6dSSean Hefty 1147628e5f6dSSean Hefty id = rdma_create_id(listen_id->event_handler, listen_id->context, 1148b26f9b99SSean Hefty listen_id->ps, IB_QPT_UD); 1149628e5f6dSSean Hefty if (IS_ERR(id)) 1150628e5f6dSSean Hefty return NULL; 1151628e5f6dSSean Hefty 1152628e5f6dSSean Hefty 1153628e5f6dSSean Hefty if (cma_get_net_info(ib_event->private_data, listen_id->ps, 1154628e5f6dSSean Hefty &ip_ver, &port, &src, &dst)) 1155628e5f6dSSean Hefty goto err; 1156628e5f6dSSean Hefty 1157628e5f6dSSean Hefty cma_save_net_info(&id->route.addr, &listen_id->route.addr, 1158628e5f6dSSean Hefty ip_ver, port, src, dst); 1159628e5f6dSSean Hefty 11606f8372b6SSean Hefty if (!cma_any_addr((struct sockaddr *) &id->route.addr.src_addr)) { 11613f446754SRoland Dreier ret = rdma_translate_ip((struct sockaddr *) &id->route.addr.src_addr, 1162628e5f6dSSean Hefty &id->route.addr.dev_addr); 1163628e5f6dSSean Hefty if (ret) 1164628e5f6dSSean Hefty goto err; 11656f8372b6SSean Hefty } 1166628e5f6dSSean Hefty 1167628e5f6dSSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1168550e5ca7SNir Muchtar id_priv->state = RDMA_CM_CONNECT; 1169628e5f6dSSean Hefty return id_priv; 1170628e5f6dSSean Hefty err: 1171628e5f6dSSean Hefty rdma_destroy_id(id); 1172628e5f6dSSean Hefty return NULL; 1173628e5f6dSSean Hefty } 1174628e5f6dSSean Hefty 1175a1b1b61fSSean Hefty static void cma_set_req_event_data(struct rdma_cm_event *event, 1176a1b1b61fSSean Hefty struct ib_cm_req_event_param *req_data, 1177a1b1b61fSSean Hefty void *private_data, int offset) 1178a1b1b61fSSean Hefty { 1179a1b1b61fSSean Hefty event->param.conn.private_data = private_data + offset; 1180a1b1b61fSSean Hefty event->param.conn.private_data_len = IB_CM_REQ_PRIVATE_DATA_SIZE - offset; 1181a1b1b61fSSean Hefty event->param.conn.responder_resources = req_data->responder_resources; 1182a1b1b61fSSean Hefty event->param.conn.initiator_depth = req_data->initiator_depth; 1183a1b1b61fSSean Hefty event->param.conn.flow_control = req_data->flow_control; 1184a1b1b61fSSean Hefty event->param.conn.retry_count = req_data->retry_count; 1185a1b1b61fSSean Hefty event->param.conn.rnr_retry_count = req_data->rnr_retry_count; 1186a1b1b61fSSean Hefty event->param.conn.srq = req_data->srq; 1187a1b1b61fSSean Hefty event->param.conn.qp_num = req_data->remote_qpn; 1188a1b1b61fSSean Hefty } 1189a1b1b61fSSean Hefty 11909595480cSHefty, Sean static int cma_check_req_qp_type(struct rdma_cm_id *id, struct ib_cm_event *ib_event) 11919595480cSHefty, Sean { 11924dd81e89SSean Hefty return (((ib_event->event == IB_CM_REQ_RECEIVED) && 11939595480cSHefty, Sean (ib_event->param.req_rcvd.qp_type == id->qp_type)) || 11949595480cSHefty, Sean ((ib_event->event == IB_CM_SIDR_REQ_RECEIVED) && 11959595480cSHefty, Sean (id->qp_type == IB_QPT_UD)) || 11969595480cSHefty, Sean (!id->qp_type)); 11979595480cSHefty, Sean } 11989595480cSHefty, Sean 1199e51060f0SSean Hefty static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event) 1200e51060f0SSean Hefty { 1201e51060f0SSean Hefty struct rdma_id_private *listen_id, *conn_id; 1202a1b1b61fSSean Hefty struct rdma_cm_event event; 1203e51060f0SSean Hefty int offset, ret; 1204e51060f0SSean Hefty 1205e51060f0SSean Hefty listen_id = cm_id->context; 12069595480cSHefty, Sean if (!cma_check_req_qp_type(&listen_id->id, ib_event)) 12079595480cSHefty, Sean return -EINVAL; 12089595480cSHefty, Sean 1209550e5ca7SNir Muchtar if (cma_disable_callback(listen_id, RDMA_CM_LISTEN)) 12108aa08602SSean Hefty return -ECONNABORTED; 1211e51060f0SSean Hefty 1212628e5f6dSSean Hefty memset(&event, 0, sizeof event); 1213628e5f6dSSean Hefty offset = cma_user_data_offset(listen_id->id.ps); 1214628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_CONNECT_REQUEST; 12159595480cSHefty, Sean if (ib_event->event == IB_CM_SIDR_REQ_RECEIVED) { 1216628e5f6dSSean Hefty conn_id = cma_new_udp_id(&listen_id->id, ib_event); 1217628e5f6dSSean Hefty event.param.ud.private_data = ib_event->private_data + offset; 1218628e5f6dSSean Hefty event.param.ud.private_data_len = 1219628e5f6dSSean Hefty IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE - offset; 1220628e5f6dSSean Hefty } else { 1221628e5f6dSSean Hefty conn_id = cma_new_conn_id(&listen_id->id, ib_event); 1222628e5f6dSSean Hefty cma_set_req_event_data(&event, &ib_event->param.req_rcvd, 1223628e5f6dSSean Hefty ib_event->private_data, offset); 1224628e5f6dSSean Hefty } 1225e51060f0SSean Hefty if (!conn_id) { 1226e51060f0SSean Hefty ret = -ENOMEM; 1227b6cec8aaSSean Hefty goto err1; 1228e51060f0SSean Hefty } 1229e51060f0SSean Hefty 1230de910bd9SOr Gerlitz mutex_lock_nested(&conn_id->handler_mutex, SINGLE_DEPTH_NESTING); 123107ebafbaSTom Tucker ret = cma_acquire_dev(conn_id); 1232a1a733f6SKrishna Kumar if (ret) 1233b6cec8aaSSean Hefty goto err2; 1234e51060f0SSean Hefty 1235e51060f0SSean Hefty conn_id->cm_id.ib = cm_id; 1236e51060f0SSean Hefty cm_id->context = conn_id; 1237e51060f0SSean Hefty cm_id->cm_handler = cma_ib_handler; 1238e51060f0SSean Hefty 123925ae21a1SSean Hefty /* 124025ae21a1SSean Hefty * Protect against the user destroying conn_id from another thread 124125ae21a1SSean Hefty * until we're done accessing it. 124225ae21a1SSean Hefty */ 124325ae21a1SSean Hefty atomic_inc(&conn_id->refcount); 1244a1b1b61fSSean Hefty ret = conn_id->id.event_handler(&conn_id->id, &event); 1245b6cec8aaSSean Hefty if (ret) 1246b6cec8aaSSean Hefty goto err3; 1247b6cec8aaSSean Hefty 1248ead595aeSSean Hefty /* 1249ead595aeSSean Hefty * Acquire mutex to prevent user executing rdma_destroy_id() 1250ead595aeSSean Hefty * while we're accessing the cm_id. 1251ead595aeSSean Hefty */ 1252ead595aeSSean Hefty mutex_lock(&lock); 1253b26f9b99SSean Hefty if (cma_comp(conn_id, RDMA_CM_CONNECT) && (conn_id->id.qp_type != IB_QPT_UD)) 1254ead595aeSSean Hefty ib_send_cm_mra(cm_id, CMA_CM_MRA_SETTING, NULL, 0); 1255ead595aeSSean Hefty mutex_unlock(&lock); 1256de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 1257b6cec8aaSSean Hefty mutex_unlock(&listen_id->handler_mutex); 125825ae21a1SSean Hefty cma_deref_id(conn_id); 1259b6cec8aaSSean Hefty return 0; 1260a1a733f6SKrishna Kumar 1261b6cec8aaSSean Hefty err3: 1262b6cec8aaSSean Hefty cma_deref_id(conn_id); 1263e51060f0SSean Hefty /* Destroy the CM ID by returning a non-zero value. */ 1264e51060f0SSean Hefty conn_id->cm_id.ib = NULL; 1265b6cec8aaSSean Hefty err2: 1266550e5ca7SNir Muchtar cma_exch(conn_id, RDMA_CM_DESTROYING); 1267de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 1268b6cec8aaSSean Hefty err1: 1269de910bd9SOr Gerlitz mutex_unlock(&listen_id->handler_mutex); 1270b6cec8aaSSean Hefty if (conn_id) 1271b6cec8aaSSean Hefty rdma_destroy_id(&conn_id->id); 1272e51060f0SSean Hefty return ret; 1273e51060f0SSean Hefty } 1274e51060f0SSean Hefty 1275e51060f0SSean Hefty static __be64 cma_get_service_id(enum rdma_port_space ps, struct sockaddr *addr) 1276e51060f0SSean Hefty { 1277628e5f6dSSean Hefty return cpu_to_be64(((u64)ps << 16) + be16_to_cpu(cma_port(addr))); 1278e51060f0SSean Hefty } 1279e51060f0SSean Hefty 1280e51060f0SSean Hefty static void cma_set_compare_data(enum rdma_port_space ps, struct sockaddr *addr, 1281e51060f0SSean Hefty struct ib_cm_compare_data *compare) 1282e51060f0SSean Hefty { 1283e51060f0SSean Hefty struct cma_hdr *cma_data, *cma_mask; 1284e51060f0SSean Hefty struct sdp_hh *sdp_data, *sdp_mask; 12851b90c137SAl Viro __be32 ip4_addr; 1286e51060f0SSean Hefty struct in6_addr ip6_addr; 1287e51060f0SSean Hefty 1288e51060f0SSean Hefty memset(compare, 0, sizeof *compare); 1289e51060f0SSean Hefty cma_data = (void *) compare->data; 1290e51060f0SSean Hefty cma_mask = (void *) compare->mask; 1291e51060f0SSean Hefty sdp_data = (void *) compare->data; 1292e51060f0SSean Hefty sdp_mask = (void *) compare->mask; 1293e51060f0SSean Hefty 1294e51060f0SSean Hefty switch (addr->sa_family) { 1295e51060f0SSean Hefty case AF_INET: 1296e51060f0SSean Hefty ip4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr; 1297e51060f0SSean Hefty if (ps == RDMA_PS_SDP) { 1298e51060f0SSean Hefty sdp_set_ip_ver(sdp_data, 4); 1299e51060f0SSean Hefty sdp_set_ip_ver(sdp_mask, 0xF); 1300e51060f0SSean Hefty sdp_data->dst_addr.ip4.addr = ip4_addr; 13011b90c137SAl Viro sdp_mask->dst_addr.ip4.addr = htonl(~0); 1302e51060f0SSean Hefty } else { 1303e51060f0SSean Hefty cma_set_ip_ver(cma_data, 4); 1304e51060f0SSean Hefty cma_set_ip_ver(cma_mask, 0xF); 1305406b6a25SSean Hefty if (!cma_any_addr(addr)) { 1306e51060f0SSean Hefty cma_data->dst_addr.ip4.addr = ip4_addr; 13071b90c137SAl Viro cma_mask->dst_addr.ip4.addr = htonl(~0); 1308e51060f0SSean Hefty } 1309406b6a25SSean Hefty } 1310e51060f0SSean Hefty break; 1311e51060f0SSean Hefty case AF_INET6: 1312e51060f0SSean Hefty ip6_addr = ((struct sockaddr_in6 *) addr)->sin6_addr; 1313e51060f0SSean Hefty if (ps == RDMA_PS_SDP) { 1314e51060f0SSean Hefty sdp_set_ip_ver(sdp_data, 6); 1315e51060f0SSean Hefty sdp_set_ip_ver(sdp_mask, 0xF); 1316e51060f0SSean Hefty sdp_data->dst_addr.ip6 = ip6_addr; 1317e51060f0SSean Hefty memset(&sdp_mask->dst_addr.ip6, 0xFF, 1318e51060f0SSean Hefty sizeof sdp_mask->dst_addr.ip6); 1319e51060f0SSean Hefty } else { 1320e51060f0SSean Hefty cma_set_ip_ver(cma_data, 6); 1321e51060f0SSean Hefty cma_set_ip_ver(cma_mask, 0xF); 1322406b6a25SSean Hefty if (!cma_any_addr(addr)) { 1323e51060f0SSean Hefty cma_data->dst_addr.ip6 = ip6_addr; 1324e51060f0SSean Hefty memset(&cma_mask->dst_addr.ip6, 0xFF, 1325e51060f0SSean Hefty sizeof cma_mask->dst_addr.ip6); 1326e51060f0SSean Hefty } 1327406b6a25SSean Hefty } 1328e51060f0SSean Hefty break; 1329e51060f0SSean Hefty default: 1330e51060f0SSean Hefty break; 1331e51060f0SSean Hefty } 1332e51060f0SSean Hefty } 1333e51060f0SSean Hefty 133407ebafbaSTom Tucker static int cma_iw_handler(struct iw_cm_id *iw_id, struct iw_cm_event *iw_event) 133507ebafbaSTom Tucker { 133607ebafbaSTom Tucker struct rdma_id_private *id_priv = iw_id->context; 1337a1b1b61fSSean Hefty struct rdma_cm_event event; 133807ebafbaSTom Tucker struct sockaddr_in *sin; 133907ebafbaSTom Tucker int ret = 0; 134007ebafbaSTom Tucker 1341550e5ca7SNir Muchtar if (cma_disable_callback(id_priv, RDMA_CM_CONNECT)) 1342be65f086SSean Hefty return 0; 134307ebafbaSTom Tucker 1344be65f086SSean Hefty memset(&event, 0, sizeof event); 134507ebafbaSTom Tucker switch (iw_event->event) { 134607ebafbaSTom Tucker case IW_CM_EVENT_CLOSE: 1347a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_DISCONNECTED; 134807ebafbaSTom Tucker break; 134907ebafbaSTom Tucker case IW_CM_EVENT_CONNECT_REPLY: 135007ebafbaSTom Tucker sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr; 135107ebafbaSTom Tucker *sin = iw_event->local_addr; 135207ebafbaSTom Tucker sin = (struct sockaddr_in *) &id_priv->id.route.addr.dst_addr; 135307ebafbaSTom Tucker *sin = iw_event->remote_addr; 1354881a045fSSteve Wise switch (iw_event->status) { 1355881a045fSSteve Wise case 0: 1356a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_ESTABLISHED; 13573ebeebc3SKumar Sanghvi event.param.conn.initiator_depth = iw_event->ird; 13583ebeebc3SKumar Sanghvi event.param.conn.responder_resources = iw_event->ord; 135907ebafbaSTom Tucker break; 1360881a045fSSteve Wise case -ECONNRESET: 1361881a045fSSteve Wise case -ECONNREFUSED: 1362881a045fSSteve Wise event.event = RDMA_CM_EVENT_REJECTED; 1363881a045fSSteve Wise break; 1364881a045fSSteve Wise case -ETIMEDOUT: 1365881a045fSSteve Wise event.event = RDMA_CM_EVENT_UNREACHABLE; 1366881a045fSSteve Wise break; 1367881a045fSSteve Wise default: 1368881a045fSSteve Wise event.event = RDMA_CM_EVENT_CONNECT_ERROR; 1369881a045fSSteve Wise break; 1370881a045fSSteve Wise } 1371881a045fSSteve Wise break; 137207ebafbaSTom Tucker case IW_CM_EVENT_ESTABLISHED: 1373a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_ESTABLISHED; 13743ebeebc3SKumar Sanghvi event.param.conn.initiator_depth = iw_event->ird; 13753ebeebc3SKumar Sanghvi event.param.conn.responder_resources = iw_event->ord; 137607ebafbaSTom Tucker break; 137707ebafbaSTom Tucker default: 137807ebafbaSTom Tucker BUG_ON(1); 137907ebafbaSTom Tucker } 138007ebafbaSTom Tucker 1381a1b1b61fSSean Hefty event.status = iw_event->status; 1382a1b1b61fSSean Hefty event.param.conn.private_data = iw_event->private_data; 1383a1b1b61fSSean Hefty event.param.conn.private_data_len = iw_event->private_data_len; 1384a1b1b61fSSean Hefty ret = id_priv->id.event_handler(&id_priv->id, &event); 138507ebafbaSTom Tucker if (ret) { 138607ebafbaSTom Tucker /* Destroy the CM ID by returning a non-zero value. */ 138707ebafbaSTom Tucker id_priv->cm_id.iw = NULL; 1388550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 1389de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 139007ebafbaSTom Tucker rdma_destroy_id(&id_priv->id); 139107ebafbaSTom Tucker return ret; 139207ebafbaSTom Tucker } 139307ebafbaSTom Tucker 1394de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 139507ebafbaSTom Tucker return ret; 139607ebafbaSTom Tucker } 139707ebafbaSTom Tucker 139807ebafbaSTom Tucker static int iw_conn_req_handler(struct iw_cm_id *cm_id, 139907ebafbaSTom Tucker struct iw_cm_event *iw_event) 140007ebafbaSTom Tucker { 140107ebafbaSTom Tucker struct rdma_cm_id *new_cm_id; 140207ebafbaSTom Tucker struct rdma_id_private *listen_id, *conn_id; 140307ebafbaSTom Tucker struct sockaddr_in *sin; 140407ebafbaSTom Tucker struct net_device *dev = NULL; 1405a1b1b61fSSean Hefty struct rdma_cm_event event; 140607ebafbaSTom Tucker int ret; 14078d8293cfSSteve Wise struct ib_device_attr attr; 140807ebafbaSTom Tucker 140907ebafbaSTom Tucker listen_id = cm_id->context; 1410550e5ca7SNir Muchtar if (cma_disable_callback(listen_id, RDMA_CM_LISTEN)) 14118aa08602SSean Hefty return -ECONNABORTED; 141207ebafbaSTom Tucker 141307ebafbaSTom Tucker /* Create a new RDMA id for the new IW CM ID */ 141407ebafbaSTom Tucker new_cm_id = rdma_create_id(listen_id->id.event_handler, 141507ebafbaSTom Tucker listen_id->id.context, 1416b26f9b99SSean Hefty RDMA_PS_TCP, IB_QPT_RC); 141710f32065SJulia Lawall if (IS_ERR(new_cm_id)) { 141807ebafbaSTom Tucker ret = -ENOMEM; 141907ebafbaSTom Tucker goto out; 142007ebafbaSTom Tucker } 142107ebafbaSTom Tucker conn_id = container_of(new_cm_id, struct rdma_id_private, id); 1422de910bd9SOr Gerlitz mutex_lock_nested(&conn_id->handler_mutex, SINGLE_DEPTH_NESTING); 1423550e5ca7SNir Muchtar conn_id->state = RDMA_CM_CONNECT; 142407ebafbaSTom Tucker 14251ab35276SDenis V. Lunev dev = ip_dev_find(&init_net, iw_event->local_addr.sin_addr.s_addr); 142607ebafbaSTom Tucker if (!dev) { 142707ebafbaSTom Tucker ret = -EADDRNOTAVAIL; 1428de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 142907ebafbaSTom Tucker rdma_destroy_id(new_cm_id); 143007ebafbaSTom Tucker goto out; 143107ebafbaSTom Tucker } 143207ebafbaSTom Tucker ret = rdma_copy_addr(&conn_id->id.route.addr.dev_addr, dev, NULL); 143307ebafbaSTom Tucker if (ret) { 1434de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 143507ebafbaSTom Tucker rdma_destroy_id(new_cm_id); 143607ebafbaSTom Tucker goto out; 143707ebafbaSTom Tucker } 143807ebafbaSTom Tucker 143907ebafbaSTom Tucker ret = cma_acquire_dev(conn_id); 144007ebafbaSTom Tucker if (ret) { 1441de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 144207ebafbaSTom Tucker rdma_destroy_id(new_cm_id); 144307ebafbaSTom Tucker goto out; 144407ebafbaSTom Tucker } 144507ebafbaSTom Tucker 144607ebafbaSTom Tucker conn_id->cm_id.iw = cm_id; 144707ebafbaSTom Tucker cm_id->context = conn_id; 144807ebafbaSTom Tucker cm_id->cm_handler = cma_iw_handler; 144907ebafbaSTom Tucker 145007ebafbaSTom Tucker sin = (struct sockaddr_in *) &new_cm_id->route.addr.src_addr; 145107ebafbaSTom Tucker *sin = iw_event->local_addr; 145207ebafbaSTom Tucker sin = (struct sockaddr_in *) &new_cm_id->route.addr.dst_addr; 145307ebafbaSTom Tucker *sin = iw_event->remote_addr; 145407ebafbaSTom Tucker 14558d8293cfSSteve Wise ret = ib_query_device(conn_id->id.device, &attr); 14568d8293cfSSteve Wise if (ret) { 1457de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 14588d8293cfSSteve Wise rdma_destroy_id(new_cm_id); 14598d8293cfSSteve Wise goto out; 14608d8293cfSSteve Wise } 14618d8293cfSSteve Wise 1462a1b1b61fSSean Hefty memset(&event, 0, sizeof event); 1463a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_CONNECT_REQUEST; 1464a1b1b61fSSean Hefty event.param.conn.private_data = iw_event->private_data; 1465a1b1b61fSSean Hefty event.param.conn.private_data_len = iw_event->private_data_len; 14663ebeebc3SKumar Sanghvi event.param.conn.initiator_depth = iw_event->ird; 14673ebeebc3SKumar Sanghvi event.param.conn.responder_resources = iw_event->ord; 146825ae21a1SSean Hefty 146925ae21a1SSean Hefty /* 147025ae21a1SSean Hefty * Protect against the user destroying conn_id from another thread 147125ae21a1SSean Hefty * until we're done accessing it. 147225ae21a1SSean Hefty */ 147325ae21a1SSean Hefty atomic_inc(&conn_id->refcount); 1474a1b1b61fSSean Hefty ret = conn_id->id.event_handler(&conn_id->id, &event); 147507ebafbaSTom Tucker if (ret) { 147607ebafbaSTom Tucker /* User wants to destroy the CM ID */ 147707ebafbaSTom Tucker conn_id->cm_id.iw = NULL; 1478550e5ca7SNir Muchtar cma_exch(conn_id, RDMA_CM_DESTROYING); 1479de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 148025ae21a1SSean Hefty cma_deref_id(conn_id); 148107ebafbaSTom Tucker rdma_destroy_id(&conn_id->id); 1482de910bd9SOr Gerlitz goto out; 148307ebafbaSTom Tucker } 148407ebafbaSTom Tucker 1485de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 148625ae21a1SSean Hefty cma_deref_id(conn_id); 1487de910bd9SOr Gerlitz 148807ebafbaSTom Tucker out: 148907ebafbaSTom Tucker if (dev) 149007ebafbaSTom Tucker dev_put(dev); 1491de910bd9SOr Gerlitz mutex_unlock(&listen_id->handler_mutex); 149207ebafbaSTom Tucker return ret; 149307ebafbaSTom Tucker } 149407ebafbaSTom Tucker 1495e51060f0SSean Hefty static int cma_ib_listen(struct rdma_id_private *id_priv) 1496e51060f0SSean Hefty { 1497e51060f0SSean Hefty struct ib_cm_compare_data compare_data; 1498e51060f0SSean Hefty struct sockaddr *addr; 14990c9361fcSJack Morgenstein struct ib_cm_id *id; 1500e51060f0SSean Hefty __be64 svc_id; 1501e51060f0SSean Hefty int ret; 1502e51060f0SSean Hefty 15030c9361fcSJack Morgenstein id = ib_create_cm_id(id_priv->id.device, cma_req_handler, id_priv); 15040c9361fcSJack Morgenstein if (IS_ERR(id)) 15050c9361fcSJack Morgenstein return PTR_ERR(id); 15060c9361fcSJack Morgenstein 15070c9361fcSJack Morgenstein id_priv->cm_id.ib = id; 1508e51060f0SSean Hefty 15093f446754SRoland Dreier addr = (struct sockaddr *) &id_priv->id.route.addr.src_addr; 1510e51060f0SSean Hefty svc_id = cma_get_service_id(id_priv->id.ps, addr); 1511406b6a25SSean Hefty if (cma_any_addr(addr) && !id_priv->afonly) 1512e51060f0SSean Hefty ret = ib_cm_listen(id_priv->cm_id.ib, svc_id, 0, NULL); 1513e51060f0SSean Hefty else { 1514e51060f0SSean Hefty cma_set_compare_data(id_priv->id.ps, addr, &compare_data); 1515e51060f0SSean Hefty ret = ib_cm_listen(id_priv->cm_id.ib, svc_id, 0, &compare_data); 1516e51060f0SSean Hefty } 1517e51060f0SSean Hefty 1518e51060f0SSean Hefty if (ret) { 1519e51060f0SSean Hefty ib_destroy_cm_id(id_priv->cm_id.ib); 1520e51060f0SSean Hefty id_priv->cm_id.ib = NULL; 1521e51060f0SSean Hefty } 1522e51060f0SSean Hefty 1523e51060f0SSean Hefty return ret; 1524e51060f0SSean Hefty } 1525e51060f0SSean Hefty 152607ebafbaSTom Tucker static int cma_iw_listen(struct rdma_id_private *id_priv, int backlog) 152707ebafbaSTom Tucker { 152807ebafbaSTom Tucker int ret; 152907ebafbaSTom Tucker struct sockaddr_in *sin; 15300c9361fcSJack Morgenstein struct iw_cm_id *id; 153107ebafbaSTom Tucker 15320c9361fcSJack Morgenstein id = iw_create_cm_id(id_priv->id.device, 153307ebafbaSTom Tucker iw_conn_req_handler, 153407ebafbaSTom Tucker id_priv); 15350c9361fcSJack Morgenstein if (IS_ERR(id)) 15360c9361fcSJack Morgenstein return PTR_ERR(id); 15370c9361fcSJack Morgenstein 15380c9361fcSJack Morgenstein id_priv->cm_id.iw = id; 153907ebafbaSTom Tucker 154007ebafbaSTom Tucker sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr; 154107ebafbaSTom Tucker id_priv->cm_id.iw->local_addr = *sin; 154207ebafbaSTom Tucker 154307ebafbaSTom Tucker ret = iw_cm_listen(id_priv->cm_id.iw, backlog); 154407ebafbaSTom Tucker 154507ebafbaSTom Tucker if (ret) { 154607ebafbaSTom Tucker iw_destroy_cm_id(id_priv->cm_id.iw); 154707ebafbaSTom Tucker id_priv->cm_id.iw = NULL; 154807ebafbaSTom Tucker } 154907ebafbaSTom Tucker 155007ebafbaSTom Tucker return ret; 155107ebafbaSTom Tucker } 155207ebafbaSTom Tucker 1553e51060f0SSean Hefty static int cma_listen_handler(struct rdma_cm_id *id, 1554e51060f0SSean Hefty struct rdma_cm_event *event) 1555e51060f0SSean Hefty { 1556e51060f0SSean Hefty struct rdma_id_private *id_priv = id->context; 1557e51060f0SSean Hefty 1558e51060f0SSean Hefty id->context = id_priv->id.context; 1559e51060f0SSean Hefty id->event_handler = id_priv->id.event_handler; 1560e51060f0SSean Hefty return id_priv->id.event_handler(id, event); 1561e51060f0SSean Hefty } 1562e51060f0SSean Hefty 1563e51060f0SSean Hefty static void cma_listen_on_dev(struct rdma_id_private *id_priv, 1564e51060f0SSean Hefty struct cma_device *cma_dev) 1565e51060f0SSean Hefty { 1566e51060f0SSean Hefty struct rdma_id_private *dev_id_priv; 1567e51060f0SSean Hefty struct rdma_cm_id *id; 1568e51060f0SSean Hefty int ret; 1569e51060f0SSean Hefty 1570b26f9b99SSean Hefty id = rdma_create_id(cma_listen_handler, id_priv, id_priv->id.ps, 1571b26f9b99SSean Hefty id_priv->id.qp_type); 1572e51060f0SSean Hefty if (IS_ERR(id)) 1573e51060f0SSean Hefty return; 1574e51060f0SSean Hefty 1575e51060f0SSean Hefty dev_id_priv = container_of(id, struct rdma_id_private, id); 1576e51060f0SSean Hefty 1577550e5ca7SNir Muchtar dev_id_priv->state = RDMA_CM_ADDR_BOUND; 1578e51060f0SSean Hefty memcpy(&id->route.addr.src_addr, &id_priv->id.route.addr.src_addr, 15793f446754SRoland Dreier ip_addr_size((struct sockaddr *) &id_priv->id.route.addr.src_addr)); 1580e51060f0SSean Hefty 1581e51060f0SSean Hefty cma_attach_to_dev(dev_id_priv, cma_dev); 1582e51060f0SSean Hefty list_add_tail(&dev_id_priv->listen_list, &id_priv->listen_list); 1583d02d1f53SSean Hefty atomic_inc(&id_priv->refcount); 1584d02d1f53SSean Hefty dev_id_priv->internal_id = 1; 15855b0ec991SSean Hefty dev_id_priv->afonly = id_priv->afonly; 1586e51060f0SSean Hefty 1587e51060f0SSean Hefty ret = rdma_listen(id, id_priv->backlog); 1588e51060f0SSean Hefty if (ret) 1589d02d1f53SSean Hefty printk(KERN_WARNING "RDMA CMA: cma_listen_on_dev, error %d, " 1590468f2239SRoland Dreier "listening on device %s\n", ret, cma_dev->device->name); 1591e51060f0SSean Hefty } 1592e51060f0SSean Hefty 1593e51060f0SSean Hefty static void cma_listen_on_all(struct rdma_id_private *id_priv) 1594e51060f0SSean Hefty { 1595e51060f0SSean Hefty struct cma_device *cma_dev; 1596e51060f0SSean Hefty 1597e51060f0SSean Hefty mutex_lock(&lock); 1598e51060f0SSean Hefty list_add_tail(&id_priv->list, &listen_any_list); 1599e51060f0SSean Hefty list_for_each_entry(cma_dev, &dev_list, list) 1600e51060f0SSean Hefty cma_listen_on_dev(id_priv, cma_dev); 1601e51060f0SSean Hefty mutex_unlock(&lock); 1602e51060f0SSean Hefty } 1603e51060f0SSean Hefty 1604a81c994dSSean Hefty void rdma_set_service_type(struct rdma_cm_id *id, int tos) 1605a81c994dSSean Hefty { 1606a81c994dSSean Hefty struct rdma_id_private *id_priv; 1607a81c994dSSean Hefty 1608a81c994dSSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1609a81c994dSSean Hefty id_priv->tos = (u8) tos; 1610a81c994dSSean Hefty } 1611a81c994dSSean Hefty EXPORT_SYMBOL(rdma_set_service_type); 1612a81c994dSSean Hefty 1613e51060f0SSean Hefty static void cma_query_handler(int status, struct ib_sa_path_rec *path_rec, 1614e51060f0SSean Hefty void *context) 1615e51060f0SSean Hefty { 1616e51060f0SSean Hefty struct cma_work *work = context; 1617e51060f0SSean Hefty struct rdma_route *route; 1618e51060f0SSean Hefty 1619e51060f0SSean Hefty route = &work->id->id.route; 1620e51060f0SSean Hefty 1621e51060f0SSean Hefty if (!status) { 1622e51060f0SSean Hefty route->num_paths = 1; 1623e51060f0SSean Hefty *route->path_rec = *path_rec; 1624e51060f0SSean Hefty } else { 1625550e5ca7SNir Muchtar work->old_state = RDMA_CM_ROUTE_QUERY; 1626550e5ca7SNir Muchtar work->new_state = RDMA_CM_ADDR_RESOLVED; 1627e51060f0SSean Hefty work->event.event = RDMA_CM_EVENT_ROUTE_ERROR; 16288f0472d3SSean Hefty work->event.status = status; 1629e51060f0SSean Hefty } 1630e51060f0SSean Hefty 1631e51060f0SSean Hefty queue_work(cma_wq, &work->work); 1632e51060f0SSean Hefty } 1633e51060f0SSean Hefty 1634e51060f0SSean Hefty static int cma_query_ib_route(struct rdma_id_private *id_priv, int timeout_ms, 1635e51060f0SSean Hefty struct cma_work *work) 1636e51060f0SSean Hefty { 1637a81c994dSSean Hefty struct rdma_addr *addr = &id_priv->id.route.addr; 1638e51060f0SSean Hefty struct ib_sa_path_rec path_rec; 1639a81c994dSSean Hefty ib_sa_comp_mask comp_mask; 1640a81c994dSSean Hefty struct sockaddr_in6 *sin6; 1641e51060f0SSean Hefty 1642e51060f0SSean Hefty memset(&path_rec, 0, sizeof path_rec); 16436f8372b6SSean Hefty rdma_addr_get_sgid(&addr->dev_addr, &path_rec.sgid); 16446f8372b6SSean Hefty rdma_addr_get_dgid(&addr->dev_addr, &path_rec.dgid); 1645a81c994dSSean Hefty path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(&addr->dev_addr)); 1646e51060f0SSean Hefty path_rec.numb_path = 1; 1647962063e6SSean Hefty path_rec.reversible = 1; 16483f446754SRoland Dreier path_rec.service_id = cma_get_service_id(id_priv->id.ps, 16493f446754SRoland Dreier (struct sockaddr *) &addr->dst_addr); 1650a81c994dSSean Hefty 1651a81c994dSSean Hefty comp_mask = IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID | 1652a81c994dSSean Hefty IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH | 1653a81c994dSSean Hefty IB_SA_PATH_REC_REVERSIBLE | IB_SA_PATH_REC_SERVICE_ID; 1654a81c994dSSean Hefty 16553f446754SRoland Dreier if (addr->src_addr.ss_family == AF_INET) { 1656a81c994dSSean Hefty path_rec.qos_class = cpu_to_be16((u16) id_priv->tos); 1657a81c994dSSean Hefty comp_mask |= IB_SA_PATH_REC_QOS_CLASS; 1658a81c994dSSean Hefty } else { 1659a81c994dSSean Hefty sin6 = (struct sockaddr_in6 *) &addr->src_addr; 1660a81c994dSSean Hefty path_rec.traffic_class = (u8) (be32_to_cpu(sin6->sin6_flowinfo) >> 20); 1661a81c994dSSean Hefty comp_mask |= IB_SA_PATH_REC_TRAFFIC_CLASS; 1662a81c994dSSean Hefty } 1663e51060f0SSean Hefty 1664c1a0b23bSMichael S. Tsirkin id_priv->query_id = ib_sa_path_rec_get(&sa_client, id_priv->id.device, 1665e51060f0SSean Hefty id_priv->id.port_num, &path_rec, 1666a81c994dSSean Hefty comp_mask, timeout_ms, 1667a81c994dSSean Hefty GFP_KERNEL, cma_query_handler, 1668a81c994dSSean Hefty work, &id_priv->query); 1669e51060f0SSean Hefty 1670e51060f0SSean Hefty return (id_priv->query_id < 0) ? id_priv->query_id : 0; 1671e51060f0SSean Hefty } 1672e51060f0SSean Hefty 1673c4028958SDavid Howells static void cma_work_handler(struct work_struct *_work) 1674e51060f0SSean Hefty { 1675c4028958SDavid Howells struct cma_work *work = container_of(_work, struct cma_work, work); 1676e51060f0SSean Hefty struct rdma_id_private *id_priv = work->id; 1677e51060f0SSean Hefty int destroy = 0; 1678e51060f0SSean Hefty 1679de910bd9SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 1680e51060f0SSean Hefty if (!cma_comp_exch(id_priv, work->old_state, work->new_state)) 1681e51060f0SSean Hefty goto out; 1682e51060f0SSean Hefty 1683e51060f0SSean Hefty if (id_priv->id.event_handler(&id_priv->id, &work->event)) { 1684550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 1685e51060f0SSean Hefty destroy = 1; 1686e51060f0SSean Hefty } 1687e51060f0SSean Hefty out: 1688de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 1689e51060f0SSean Hefty cma_deref_id(id_priv); 1690e51060f0SSean Hefty if (destroy) 1691e51060f0SSean Hefty rdma_destroy_id(&id_priv->id); 1692e51060f0SSean Hefty kfree(work); 1693e51060f0SSean Hefty } 1694e51060f0SSean Hefty 1695dd5bdff8SOr Gerlitz static void cma_ndev_work_handler(struct work_struct *_work) 1696dd5bdff8SOr Gerlitz { 1697dd5bdff8SOr Gerlitz struct cma_ndev_work *work = container_of(_work, struct cma_ndev_work, work); 1698dd5bdff8SOr Gerlitz struct rdma_id_private *id_priv = work->id; 1699dd5bdff8SOr Gerlitz int destroy = 0; 1700dd5bdff8SOr Gerlitz 1701dd5bdff8SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 1702550e5ca7SNir Muchtar if (id_priv->state == RDMA_CM_DESTROYING || 1703550e5ca7SNir Muchtar id_priv->state == RDMA_CM_DEVICE_REMOVAL) 1704dd5bdff8SOr Gerlitz goto out; 1705dd5bdff8SOr Gerlitz 1706dd5bdff8SOr Gerlitz if (id_priv->id.event_handler(&id_priv->id, &work->event)) { 1707550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 1708dd5bdff8SOr Gerlitz destroy = 1; 1709dd5bdff8SOr Gerlitz } 1710dd5bdff8SOr Gerlitz 1711dd5bdff8SOr Gerlitz out: 1712dd5bdff8SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 1713dd5bdff8SOr Gerlitz cma_deref_id(id_priv); 1714dd5bdff8SOr Gerlitz if (destroy) 1715dd5bdff8SOr Gerlitz rdma_destroy_id(&id_priv->id); 1716dd5bdff8SOr Gerlitz kfree(work); 1717dd5bdff8SOr Gerlitz } 1718dd5bdff8SOr Gerlitz 1719e51060f0SSean Hefty static int cma_resolve_ib_route(struct rdma_id_private *id_priv, int timeout_ms) 1720e51060f0SSean Hefty { 1721e51060f0SSean Hefty struct rdma_route *route = &id_priv->id.route; 1722e51060f0SSean Hefty struct cma_work *work; 1723e51060f0SSean Hefty int ret; 1724e51060f0SSean Hefty 1725e51060f0SSean Hefty work = kzalloc(sizeof *work, GFP_KERNEL); 1726e51060f0SSean Hefty if (!work) 1727e51060f0SSean Hefty return -ENOMEM; 1728e51060f0SSean Hefty 1729e51060f0SSean Hefty work->id = id_priv; 1730c4028958SDavid Howells INIT_WORK(&work->work, cma_work_handler); 1731550e5ca7SNir Muchtar work->old_state = RDMA_CM_ROUTE_QUERY; 1732550e5ca7SNir Muchtar work->new_state = RDMA_CM_ROUTE_RESOLVED; 1733e51060f0SSean Hefty work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED; 1734e51060f0SSean Hefty 1735e51060f0SSean Hefty route->path_rec = kmalloc(sizeof *route->path_rec, GFP_KERNEL); 1736e51060f0SSean Hefty if (!route->path_rec) { 1737e51060f0SSean Hefty ret = -ENOMEM; 1738e51060f0SSean Hefty goto err1; 1739e51060f0SSean Hefty } 1740e51060f0SSean Hefty 1741e51060f0SSean Hefty ret = cma_query_ib_route(id_priv, timeout_ms, work); 1742e51060f0SSean Hefty if (ret) 1743e51060f0SSean Hefty goto err2; 1744e51060f0SSean Hefty 1745e51060f0SSean Hefty return 0; 1746e51060f0SSean Hefty err2: 1747e51060f0SSean Hefty kfree(route->path_rec); 1748e51060f0SSean Hefty route->path_rec = NULL; 1749e51060f0SSean Hefty err1: 1750e51060f0SSean Hefty kfree(work); 1751e51060f0SSean Hefty return ret; 1752e51060f0SSean Hefty } 1753e51060f0SSean Hefty 1754e51060f0SSean Hefty int rdma_set_ib_paths(struct rdma_cm_id *id, 1755e51060f0SSean Hefty struct ib_sa_path_rec *path_rec, int num_paths) 1756e51060f0SSean Hefty { 1757e51060f0SSean Hefty struct rdma_id_private *id_priv; 1758e51060f0SSean Hefty int ret; 1759e51060f0SSean Hefty 1760e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1761550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED, 1762550e5ca7SNir Muchtar RDMA_CM_ROUTE_RESOLVED)) 1763e51060f0SSean Hefty return -EINVAL; 1764e51060f0SSean Hefty 17659893e742SJulia Lawall id->route.path_rec = kmemdup(path_rec, sizeof *path_rec * num_paths, 17669893e742SJulia Lawall GFP_KERNEL); 1767e51060f0SSean Hefty if (!id->route.path_rec) { 1768e51060f0SSean Hefty ret = -ENOMEM; 1769e51060f0SSean Hefty goto err; 1770e51060f0SSean Hefty } 1771e51060f0SSean Hefty 1772ae2d9293SSean Hefty id->route.num_paths = num_paths; 1773e51060f0SSean Hefty return 0; 1774e51060f0SSean Hefty err: 1775550e5ca7SNir Muchtar cma_comp_exch(id_priv, RDMA_CM_ROUTE_RESOLVED, RDMA_CM_ADDR_RESOLVED); 1776e51060f0SSean Hefty return ret; 1777e51060f0SSean Hefty } 1778e51060f0SSean Hefty EXPORT_SYMBOL(rdma_set_ib_paths); 1779e51060f0SSean Hefty 178007ebafbaSTom Tucker static int cma_resolve_iw_route(struct rdma_id_private *id_priv, int timeout_ms) 178107ebafbaSTom Tucker { 178207ebafbaSTom Tucker struct cma_work *work; 178307ebafbaSTom Tucker 178407ebafbaSTom Tucker work = kzalloc(sizeof *work, GFP_KERNEL); 178507ebafbaSTom Tucker if (!work) 178607ebafbaSTom Tucker return -ENOMEM; 178707ebafbaSTom Tucker 178807ebafbaSTom Tucker work->id = id_priv; 1789c4028958SDavid Howells INIT_WORK(&work->work, cma_work_handler); 1790550e5ca7SNir Muchtar work->old_state = RDMA_CM_ROUTE_QUERY; 1791550e5ca7SNir Muchtar work->new_state = RDMA_CM_ROUTE_RESOLVED; 179207ebafbaSTom Tucker work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED; 179307ebafbaSTom Tucker queue_work(cma_wq, &work->work); 179407ebafbaSTom Tucker return 0; 179507ebafbaSTom Tucker } 179607ebafbaSTom Tucker 17973c86aa70SEli Cohen static int cma_resolve_iboe_route(struct rdma_id_private *id_priv) 17983c86aa70SEli Cohen { 17993c86aa70SEli Cohen struct rdma_route *route = &id_priv->id.route; 18003c86aa70SEli Cohen struct rdma_addr *addr = &route->addr; 18013c86aa70SEli Cohen struct cma_work *work; 18023c86aa70SEli Cohen int ret; 18033c86aa70SEli Cohen struct sockaddr_in *src_addr = (struct sockaddr_in *)&route->addr.src_addr; 18043c86aa70SEli Cohen struct sockaddr_in *dst_addr = (struct sockaddr_in *)&route->addr.dst_addr; 18053c86aa70SEli Cohen struct net_device *ndev = NULL; 1806af7bd463SEli Cohen u16 vid; 18073c86aa70SEli Cohen 18083c86aa70SEli Cohen if (src_addr->sin_family != dst_addr->sin_family) 18093c86aa70SEli Cohen return -EINVAL; 18103c86aa70SEli Cohen 18113c86aa70SEli Cohen work = kzalloc(sizeof *work, GFP_KERNEL); 18123c86aa70SEli Cohen if (!work) 18133c86aa70SEli Cohen return -ENOMEM; 18143c86aa70SEli Cohen 18153c86aa70SEli Cohen work->id = id_priv; 18163c86aa70SEli Cohen INIT_WORK(&work->work, cma_work_handler); 18173c86aa70SEli Cohen 18183c86aa70SEli Cohen route->path_rec = kzalloc(sizeof *route->path_rec, GFP_KERNEL); 18193c86aa70SEli Cohen if (!route->path_rec) { 18203c86aa70SEli Cohen ret = -ENOMEM; 18213c86aa70SEli Cohen goto err1; 18223c86aa70SEli Cohen } 18233c86aa70SEli Cohen 18243c86aa70SEli Cohen route->num_paths = 1; 18253c86aa70SEli Cohen 18263c86aa70SEli Cohen if (addr->dev_addr.bound_dev_if) 18273c86aa70SEli Cohen ndev = dev_get_by_index(&init_net, addr->dev_addr.bound_dev_if); 18283c86aa70SEli Cohen if (!ndev) { 18293c86aa70SEli Cohen ret = -ENODEV; 18303c86aa70SEli Cohen goto err2; 18313c86aa70SEli Cohen } 18323c86aa70SEli Cohen 1833af7bd463SEli Cohen vid = rdma_vlan_dev_vlan_id(ndev); 1834af7bd463SEli Cohen 1835af7bd463SEli Cohen iboe_mac_vlan_to_ll(&route->path_rec->sgid, addr->dev_addr.src_dev_addr, vid); 1836af7bd463SEli Cohen iboe_mac_vlan_to_ll(&route->path_rec->dgid, addr->dev_addr.dst_dev_addr, vid); 1837af7bd463SEli Cohen 1838af7bd463SEli Cohen route->path_rec->hop_limit = 1; 1839af7bd463SEli Cohen route->path_rec->reversible = 1; 1840af7bd463SEli Cohen route->path_rec->pkey = cpu_to_be16(0xffff); 1841af7bd463SEli Cohen route->path_rec->mtu_selector = IB_SA_EQ; 1842366cddb4SAmir Vadai route->path_rec->sl = netdev_get_prio_tc_map( 1843366cddb4SAmir Vadai ndev->priv_flags & IFF_802_1Q_VLAN ? 1844366cddb4SAmir Vadai vlan_dev_real_dev(ndev) : ndev, 1845366cddb4SAmir Vadai rt_tos2priority(id_priv->tos)); 1846af7bd463SEli Cohen 18473c86aa70SEli Cohen route->path_rec->mtu = iboe_get_mtu(ndev->mtu); 18483c86aa70SEli Cohen route->path_rec->rate_selector = IB_SA_EQ; 18493c86aa70SEli Cohen route->path_rec->rate = iboe_get_rate(ndev); 18503c86aa70SEli Cohen dev_put(ndev); 18513c86aa70SEli Cohen route->path_rec->packet_life_time_selector = IB_SA_EQ; 18523c86aa70SEli Cohen route->path_rec->packet_life_time = CMA_IBOE_PACKET_LIFETIME; 18533c86aa70SEli Cohen if (!route->path_rec->mtu) { 18543c86aa70SEli Cohen ret = -EINVAL; 18553c86aa70SEli Cohen goto err2; 18563c86aa70SEli Cohen } 18573c86aa70SEli Cohen 1858550e5ca7SNir Muchtar work->old_state = RDMA_CM_ROUTE_QUERY; 1859550e5ca7SNir Muchtar work->new_state = RDMA_CM_ROUTE_RESOLVED; 18603c86aa70SEli Cohen work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED; 18613c86aa70SEli Cohen work->event.status = 0; 18623c86aa70SEli Cohen 18633c86aa70SEli Cohen queue_work(cma_wq, &work->work); 18643c86aa70SEli Cohen 18653c86aa70SEli Cohen return 0; 18663c86aa70SEli Cohen 18673c86aa70SEli Cohen err2: 18683c86aa70SEli Cohen kfree(route->path_rec); 18693c86aa70SEli Cohen route->path_rec = NULL; 18703c86aa70SEli Cohen err1: 18713c86aa70SEli Cohen kfree(work); 18723c86aa70SEli Cohen return ret; 18733c86aa70SEli Cohen } 18743c86aa70SEli Cohen 1875e51060f0SSean Hefty int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms) 1876e51060f0SSean Hefty { 1877e51060f0SSean Hefty struct rdma_id_private *id_priv; 1878e51060f0SSean Hefty int ret; 1879e51060f0SSean Hefty 1880e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1881550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED, RDMA_CM_ROUTE_QUERY)) 1882e51060f0SSean Hefty return -EINVAL; 1883e51060f0SSean Hefty 1884e51060f0SSean Hefty atomic_inc(&id_priv->refcount); 188507ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 188607ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 18873c86aa70SEli Cohen switch (rdma_port_get_link_layer(id->device, id->port_num)) { 18883c86aa70SEli Cohen case IB_LINK_LAYER_INFINIBAND: 1889e51060f0SSean Hefty ret = cma_resolve_ib_route(id_priv, timeout_ms); 1890e51060f0SSean Hefty break; 18913c86aa70SEli Cohen case IB_LINK_LAYER_ETHERNET: 18923c86aa70SEli Cohen ret = cma_resolve_iboe_route(id_priv); 18933c86aa70SEli Cohen break; 18943c86aa70SEli Cohen default: 18953c86aa70SEli Cohen ret = -ENOSYS; 18963c86aa70SEli Cohen } 18973c86aa70SEli Cohen break; 189807ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 189907ebafbaSTom Tucker ret = cma_resolve_iw_route(id_priv, timeout_ms); 190007ebafbaSTom Tucker break; 1901e51060f0SSean Hefty default: 1902e51060f0SSean Hefty ret = -ENOSYS; 1903e51060f0SSean Hefty break; 1904e51060f0SSean Hefty } 1905e51060f0SSean Hefty if (ret) 1906e51060f0SSean Hefty goto err; 1907e51060f0SSean Hefty 1908e51060f0SSean Hefty return 0; 1909e51060f0SSean Hefty err: 1910550e5ca7SNir Muchtar cma_comp_exch(id_priv, RDMA_CM_ROUTE_QUERY, RDMA_CM_ADDR_RESOLVED); 1911e51060f0SSean Hefty cma_deref_id(id_priv); 1912e51060f0SSean Hefty return ret; 1913e51060f0SSean Hefty } 1914e51060f0SSean Hefty EXPORT_SYMBOL(rdma_resolve_route); 1915e51060f0SSean Hefty 1916e51060f0SSean Hefty static int cma_bind_loopback(struct rdma_id_private *id_priv) 1917e51060f0SSean Hefty { 1918e51060f0SSean Hefty struct cma_device *cma_dev; 1919e51060f0SSean Hefty struct ib_port_attr port_attr; 1920f0ee3404SMichael S. Tsirkin union ib_gid gid; 1921e51060f0SSean Hefty u16 pkey; 1922e51060f0SSean Hefty int ret; 1923e51060f0SSean Hefty u8 p; 1924e51060f0SSean Hefty 1925e51060f0SSean Hefty mutex_lock(&lock); 1926e82153b5SKrishna Kumar if (list_empty(&dev_list)) { 1927e82153b5SKrishna Kumar ret = -ENODEV; 1928e82153b5SKrishna Kumar goto out; 1929e82153b5SKrishna Kumar } 1930e51060f0SSean Hefty list_for_each_entry(cma_dev, &dev_list, list) 1931e51060f0SSean Hefty for (p = 1; p <= cma_dev->device->phys_port_cnt; ++p) 1932e51060f0SSean Hefty if (!ib_query_port(cma_dev->device, p, &port_attr) && 1933e51060f0SSean Hefty port_attr.state == IB_PORT_ACTIVE) 1934e51060f0SSean Hefty goto port_found; 1935e51060f0SSean Hefty 1936e51060f0SSean Hefty p = 1; 1937e51060f0SSean Hefty cma_dev = list_entry(dev_list.next, struct cma_device, list); 1938e51060f0SSean Hefty 1939e51060f0SSean Hefty port_found: 1940f0ee3404SMichael S. Tsirkin ret = ib_get_cached_gid(cma_dev->device, p, 0, &gid); 1941e51060f0SSean Hefty if (ret) 1942e51060f0SSean Hefty goto out; 1943e51060f0SSean Hefty 1944e51060f0SSean Hefty ret = ib_get_cached_pkey(cma_dev->device, p, 0, &pkey); 1945e51060f0SSean Hefty if (ret) 1946e51060f0SSean Hefty goto out; 1947e51060f0SSean Hefty 19486f8372b6SSean Hefty id_priv->id.route.addr.dev_addr.dev_type = 19493c86aa70SEli Cohen (rdma_port_get_link_layer(cma_dev->device, p) == IB_LINK_LAYER_INFINIBAND) ? 19506f8372b6SSean Hefty ARPHRD_INFINIBAND : ARPHRD_ETHER; 19516f8372b6SSean Hefty 19526f8372b6SSean Hefty rdma_addr_set_sgid(&id_priv->id.route.addr.dev_addr, &gid); 1953e51060f0SSean Hefty ib_addr_set_pkey(&id_priv->id.route.addr.dev_addr, pkey); 1954e51060f0SSean Hefty id_priv->id.port_num = p; 1955e51060f0SSean Hefty cma_attach_to_dev(id_priv, cma_dev); 1956e51060f0SSean Hefty out: 1957e51060f0SSean Hefty mutex_unlock(&lock); 1958e51060f0SSean Hefty return ret; 1959e51060f0SSean Hefty } 1960e51060f0SSean Hefty 1961e51060f0SSean Hefty static void addr_handler(int status, struct sockaddr *src_addr, 1962e51060f0SSean Hefty struct rdma_dev_addr *dev_addr, void *context) 1963e51060f0SSean Hefty { 1964e51060f0SSean Hefty struct rdma_id_private *id_priv = context; 1965a1b1b61fSSean Hefty struct rdma_cm_event event; 1966e51060f0SSean Hefty 1967a1b1b61fSSean Hefty memset(&event, 0, sizeof event); 1968de910bd9SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 1969550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_QUERY, 1970550e5ca7SNir Muchtar RDMA_CM_ADDR_RESOLVED)) 197161a73c70SSean Hefty goto out; 197261a73c70SSean Hefty 197361a73c70SSean Hefty if (!status && !id_priv->cma_dev) 1974e51060f0SSean Hefty status = cma_acquire_dev(id_priv); 1975e51060f0SSean Hefty 1976e51060f0SSean Hefty if (status) { 1977550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED, 1978550e5ca7SNir Muchtar RDMA_CM_ADDR_BOUND)) 1979e51060f0SSean Hefty goto out; 1980a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_ADDR_ERROR; 1981a1b1b61fSSean Hefty event.status = status; 1982e51060f0SSean Hefty } else { 1983e51060f0SSean Hefty memcpy(&id_priv->id.route.addr.src_addr, src_addr, 1984e51060f0SSean Hefty ip_addr_size(src_addr)); 1985a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_ADDR_RESOLVED; 1986e51060f0SSean Hefty } 1987e51060f0SSean Hefty 1988a1b1b61fSSean Hefty if (id_priv->id.event_handler(&id_priv->id, &event)) { 1989550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 1990de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 1991e51060f0SSean Hefty cma_deref_id(id_priv); 1992e51060f0SSean Hefty rdma_destroy_id(&id_priv->id); 1993e51060f0SSean Hefty return; 1994e51060f0SSean Hefty } 1995e51060f0SSean Hefty out: 1996de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 1997e51060f0SSean Hefty cma_deref_id(id_priv); 1998e51060f0SSean Hefty } 1999e51060f0SSean Hefty 2000e51060f0SSean Hefty static int cma_resolve_loopback(struct rdma_id_private *id_priv) 2001e51060f0SSean Hefty { 2002e51060f0SSean Hefty struct cma_work *work; 20036f8372b6SSean Hefty struct sockaddr *src, *dst; 2004f0ee3404SMichael S. Tsirkin union ib_gid gid; 2005e51060f0SSean Hefty int ret; 2006e51060f0SSean Hefty 2007e51060f0SSean Hefty work = kzalloc(sizeof *work, GFP_KERNEL); 2008e51060f0SSean Hefty if (!work) 2009e51060f0SSean Hefty return -ENOMEM; 2010e51060f0SSean Hefty 2011e51060f0SSean Hefty if (!id_priv->cma_dev) { 2012e51060f0SSean Hefty ret = cma_bind_loopback(id_priv); 2013e51060f0SSean Hefty if (ret) 2014e51060f0SSean Hefty goto err; 2015e51060f0SSean Hefty } 2016e51060f0SSean Hefty 20176f8372b6SSean Hefty rdma_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid); 20186f8372b6SSean Hefty rdma_addr_set_dgid(&id_priv->id.route.addr.dev_addr, &gid); 2019e51060f0SSean Hefty 20206f8372b6SSean Hefty src = (struct sockaddr *) &id_priv->id.route.addr.src_addr; 20216f8372b6SSean Hefty if (cma_zero_addr(src)) { 20226f8372b6SSean Hefty dst = (struct sockaddr *) &id_priv->id.route.addr.dst_addr; 20236f8372b6SSean Hefty if ((src->sa_family = dst->sa_family) == AF_INET) { 20244e3fd7a0SAlexey Dobriyan ((struct sockaddr_in *)src)->sin_addr = 20254e3fd7a0SAlexey Dobriyan ((struct sockaddr_in *)dst)->sin_addr; 20266f8372b6SSean Hefty } else { 20274e3fd7a0SAlexey Dobriyan ((struct sockaddr_in6 *)src)->sin6_addr = 20284e3fd7a0SAlexey Dobriyan ((struct sockaddr_in6 *)dst)->sin6_addr; 20296f8372b6SSean Hefty } 2030e51060f0SSean Hefty } 2031e51060f0SSean Hefty 2032e51060f0SSean Hefty work->id = id_priv; 2033c4028958SDavid Howells INIT_WORK(&work->work, cma_work_handler); 2034550e5ca7SNir Muchtar work->old_state = RDMA_CM_ADDR_QUERY; 2035550e5ca7SNir Muchtar work->new_state = RDMA_CM_ADDR_RESOLVED; 2036e51060f0SSean Hefty work->event.event = RDMA_CM_EVENT_ADDR_RESOLVED; 2037e51060f0SSean Hefty queue_work(cma_wq, &work->work); 2038e51060f0SSean Hefty return 0; 2039e51060f0SSean Hefty err: 2040e51060f0SSean Hefty kfree(work); 2041e51060f0SSean Hefty return ret; 2042e51060f0SSean Hefty } 2043e51060f0SSean Hefty 2044e51060f0SSean Hefty static int cma_bind_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, 2045e51060f0SSean Hefty struct sockaddr *dst_addr) 2046e51060f0SSean Hefty { 2047d14714dfSSean Hefty if (!src_addr || !src_addr->sa_family) { 2048d14714dfSSean Hefty src_addr = (struct sockaddr *) &id->route.addr.src_addr; 2049d14714dfSSean Hefty if ((src_addr->sa_family = dst_addr->sa_family) == AF_INET6) { 2050d14714dfSSean Hefty ((struct sockaddr_in6 *) src_addr)->sin6_scope_id = 2051d14714dfSSean Hefty ((struct sockaddr_in6 *) dst_addr)->sin6_scope_id; 2052d14714dfSSean Hefty } 2053d14714dfSSean Hefty } 2054e51060f0SSean Hefty return rdma_bind_addr(id, src_addr); 2055e51060f0SSean Hefty } 2056e51060f0SSean Hefty 2057e51060f0SSean Hefty int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, 2058e51060f0SSean Hefty struct sockaddr *dst_addr, int timeout_ms) 2059e51060f0SSean Hefty { 2060e51060f0SSean Hefty struct rdma_id_private *id_priv; 2061e51060f0SSean Hefty int ret; 2062e51060f0SSean Hefty 2063e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 2064550e5ca7SNir Muchtar if (id_priv->state == RDMA_CM_IDLE) { 2065e51060f0SSean Hefty ret = cma_bind_addr(id, src_addr, dst_addr); 2066e51060f0SSean Hefty if (ret) 2067e51060f0SSean Hefty return ret; 2068e51060f0SSean Hefty } 2069e51060f0SSean Hefty 2070550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_ADDR_QUERY)) 2071e51060f0SSean Hefty return -EINVAL; 2072e51060f0SSean Hefty 2073e51060f0SSean Hefty atomic_inc(&id_priv->refcount); 2074e51060f0SSean Hefty memcpy(&id->route.addr.dst_addr, dst_addr, ip_addr_size(dst_addr)); 2075e51060f0SSean Hefty if (cma_any_addr(dst_addr)) 2076e51060f0SSean Hefty ret = cma_resolve_loopback(id_priv); 2077e51060f0SSean Hefty else 20783f446754SRoland Dreier ret = rdma_resolve_ip(&addr_client, (struct sockaddr *) &id->route.addr.src_addr, 20797a118df3SSean Hefty dst_addr, &id->route.addr.dev_addr, 2080e51060f0SSean Hefty timeout_ms, addr_handler, id_priv); 2081e51060f0SSean Hefty if (ret) 2082e51060f0SSean Hefty goto err; 2083e51060f0SSean Hefty 2084e51060f0SSean Hefty return 0; 2085e51060f0SSean Hefty err: 2086550e5ca7SNir Muchtar cma_comp_exch(id_priv, RDMA_CM_ADDR_QUERY, RDMA_CM_ADDR_BOUND); 2087e51060f0SSean Hefty cma_deref_id(id_priv); 2088e51060f0SSean Hefty return ret; 2089e51060f0SSean Hefty } 2090e51060f0SSean Hefty EXPORT_SYMBOL(rdma_resolve_addr); 2091e51060f0SSean Hefty 2092a9bb7912SHefty, Sean int rdma_set_reuseaddr(struct rdma_cm_id *id, int reuse) 2093a9bb7912SHefty, Sean { 2094a9bb7912SHefty, Sean struct rdma_id_private *id_priv; 2095a9bb7912SHefty, Sean unsigned long flags; 2096a9bb7912SHefty, Sean int ret; 2097a9bb7912SHefty, Sean 2098a9bb7912SHefty, Sean id_priv = container_of(id, struct rdma_id_private, id); 2099a9bb7912SHefty, Sean spin_lock_irqsave(&id_priv->lock, flags); 2100550e5ca7SNir Muchtar if (id_priv->state == RDMA_CM_IDLE) { 2101a9bb7912SHefty, Sean id_priv->reuseaddr = reuse; 2102a9bb7912SHefty, Sean ret = 0; 2103a9bb7912SHefty, Sean } else { 2104a9bb7912SHefty, Sean ret = -EINVAL; 2105a9bb7912SHefty, Sean } 2106a9bb7912SHefty, Sean spin_unlock_irqrestore(&id_priv->lock, flags); 2107a9bb7912SHefty, Sean return ret; 2108a9bb7912SHefty, Sean } 2109a9bb7912SHefty, Sean EXPORT_SYMBOL(rdma_set_reuseaddr); 2110a9bb7912SHefty, Sean 211168602120SSean Hefty int rdma_set_afonly(struct rdma_cm_id *id, int afonly) 211268602120SSean Hefty { 211368602120SSean Hefty struct rdma_id_private *id_priv; 211468602120SSean Hefty unsigned long flags; 211568602120SSean Hefty int ret; 211668602120SSean Hefty 211768602120SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 211868602120SSean Hefty spin_lock_irqsave(&id_priv->lock, flags); 211968602120SSean Hefty if (id_priv->state == RDMA_CM_IDLE || id_priv->state == RDMA_CM_ADDR_BOUND) { 212068602120SSean Hefty id_priv->options |= (1 << CMA_OPTION_AFONLY); 212168602120SSean Hefty id_priv->afonly = afonly; 212268602120SSean Hefty ret = 0; 212368602120SSean Hefty } else { 212468602120SSean Hefty ret = -EINVAL; 212568602120SSean Hefty } 212668602120SSean Hefty spin_unlock_irqrestore(&id_priv->lock, flags); 212768602120SSean Hefty return ret; 212868602120SSean Hefty } 212968602120SSean Hefty EXPORT_SYMBOL(rdma_set_afonly); 213068602120SSean Hefty 2131e51060f0SSean Hefty static void cma_bind_port(struct rdma_bind_list *bind_list, 2132e51060f0SSean Hefty struct rdma_id_private *id_priv) 2133e51060f0SSean Hefty { 2134e51060f0SSean Hefty struct sockaddr_in *sin; 2135e51060f0SSean Hefty 2136e51060f0SSean Hefty sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr; 2137e51060f0SSean Hefty sin->sin_port = htons(bind_list->port); 2138e51060f0SSean Hefty id_priv->bind_list = bind_list; 2139e51060f0SSean Hefty hlist_add_head(&id_priv->node, &bind_list->owners); 2140e51060f0SSean Hefty } 2141e51060f0SSean Hefty 2142e51060f0SSean Hefty static int cma_alloc_port(struct idr *ps, struct rdma_id_private *id_priv, 2143e51060f0SSean Hefty unsigned short snum) 2144e51060f0SSean Hefty { 2145e51060f0SSean Hefty struct rdma_bind_list *bind_list; 2146*3b069c5dSTejun Heo int ret; 2147e51060f0SSean Hefty 2148cb164b8cSSean Hefty bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL); 2149e51060f0SSean Hefty if (!bind_list) 2150e51060f0SSean Hefty return -ENOMEM; 2151e51060f0SSean Hefty 2152*3b069c5dSTejun Heo ret = idr_alloc(ps, bind_list, snum, snum + 1, GFP_KERNEL); 2153*3b069c5dSTejun Heo if (ret < 0) 2154*3b069c5dSTejun Heo goto err; 2155e51060f0SSean Hefty 2156e51060f0SSean Hefty bind_list->ps = ps; 2157*3b069c5dSTejun Heo bind_list->port = (unsigned short)ret; 2158e51060f0SSean Hefty cma_bind_port(bind_list, id_priv); 2159e51060f0SSean Hefty return 0; 2160*3b069c5dSTejun Heo err: 2161aedec080SSean Hefty kfree(bind_list); 2162*3b069c5dSTejun Heo return ret == -ENOSPC ? -EADDRNOTAVAIL : ret; 2163aedec080SSean Hefty } 2164aedec080SSean Hefty 2165aedec080SSean Hefty static int cma_alloc_any_port(struct idr *ps, struct rdma_id_private *id_priv) 2166aedec080SSean Hefty { 21675d7220e8STetsuo Handa static unsigned int last_used_port; 21685d7220e8STetsuo Handa int low, high, remaining; 21695d7220e8STetsuo Handa unsigned int rover; 2170aedec080SSean Hefty 2171227b60f5SStephen Hemminger inet_get_local_port_range(&low, &high); 21725d7220e8STetsuo Handa remaining = (high - low) + 1; 21735d7220e8STetsuo Handa rover = net_random() % remaining + low; 21745d7220e8STetsuo Handa retry: 21755d7220e8STetsuo Handa if (last_used_port != rover && 21765d7220e8STetsuo Handa !idr_find(ps, (unsigned short) rover)) { 21775d7220e8STetsuo Handa int ret = cma_alloc_port(ps, id_priv, rover); 21785d7220e8STetsuo Handa /* 21795d7220e8STetsuo Handa * Remember previously used port number in order to avoid 21805d7220e8STetsuo Handa * re-using same port immediately after it is closed. 21815d7220e8STetsuo Handa */ 21825d7220e8STetsuo Handa if (!ret) 21835d7220e8STetsuo Handa last_used_port = rover; 21845d7220e8STetsuo Handa if (ret != -EADDRNOTAVAIL) 21855d7220e8STetsuo Handa return ret; 21865d7220e8STetsuo Handa } 21875d7220e8STetsuo Handa if (--remaining) { 21885d7220e8STetsuo Handa rover++; 21895d7220e8STetsuo Handa if ((rover < low) || (rover > high)) 21905d7220e8STetsuo Handa rover = low; 2191aedec080SSean Hefty goto retry; 2192aedec080SSean Hefty } 21935d7220e8STetsuo Handa return -EADDRNOTAVAIL; 2194e51060f0SSean Hefty } 2195e51060f0SSean Hefty 2196a9bb7912SHefty, Sean /* 2197a9bb7912SHefty, Sean * Check that the requested port is available. This is called when trying to 2198a9bb7912SHefty, Sean * bind to a specific port, or when trying to listen on a bound port. In 2199a9bb7912SHefty, Sean * the latter case, the provided id_priv may already be on the bind_list, but 2200a9bb7912SHefty, Sean * we still need to check that it's okay to start listening. 2201a9bb7912SHefty, Sean */ 2202a9bb7912SHefty, Sean static int cma_check_port(struct rdma_bind_list *bind_list, 2203a9bb7912SHefty, Sean struct rdma_id_private *id_priv, uint8_t reuseaddr) 2204e51060f0SSean Hefty { 2205e51060f0SSean Hefty struct rdma_id_private *cur_id; 220643b752daSHefty, Sean struct sockaddr *addr, *cur_addr; 2207e51060f0SSean Hefty struct hlist_node *node; 2208e51060f0SSean Hefty 220943b752daSHefty, Sean addr = (struct sockaddr *) &id_priv->id.route.addr.src_addr; 2210e51060f0SSean Hefty hlist_for_each_entry(cur_id, node, &bind_list->owners, node) { 2211a9bb7912SHefty, Sean if (id_priv == cur_id) 2212a9bb7912SHefty, Sean continue; 2213a9bb7912SHefty, Sean 22145b0ec991SSean Hefty if ((cur_id->state != RDMA_CM_LISTEN) && reuseaddr && 22155b0ec991SSean Hefty cur_id->reuseaddr) 22165b0ec991SSean Hefty continue; 22175b0ec991SSean Hefty 221843b752daSHefty, Sean cur_addr = (struct sockaddr *) &cur_id->id.route.addr.src_addr; 22195b0ec991SSean Hefty if (id_priv->afonly && cur_id->afonly && 22205b0ec991SSean Hefty (addr->sa_family != cur_addr->sa_family)) 22215b0ec991SSean Hefty continue; 22225b0ec991SSean Hefty 22235b0ec991SSean Hefty if (cma_any_addr(addr) || cma_any_addr(cur_addr)) 2224e51060f0SSean Hefty return -EADDRNOTAVAIL; 2225e51060f0SSean Hefty 222643b752daSHefty, Sean if (!cma_addr_cmp(addr, cur_addr)) 2227e51060f0SSean Hefty return -EADDRINUSE; 2228e51060f0SSean Hefty } 2229e51060f0SSean Hefty return 0; 2230e51060f0SSean Hefty } 2231e51060f0SSean Hefty 2232a9bb7912SHefty, Sean static int cma_use_port(struct idr *ps, struct rdma_id_private *id_priv) 2233a9bb7912SHefty, Sean { 2234a9bb7912SHefty, Sean struct rdma_bind_list *bind_list; 2235a9bb7912SHefty, Sean unsigned short snum; 2236a9bb7912SHefty, Sean int ret; 2237a9bb7912SHefty, Sean 2238a9bb7912SHefty, Sean snum = ntohs(cma_port((struct sockaddr *) &id_priv->id.route.addr.src_addr)); 2239a9bb7912SHefty, Sean if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) 2240a9bb7912SHefty, Sean return -EACCES; 2241a9bb7912SHefty, Sean 2242a9bb7912SHefty, Sean bind_list = idr_find(ps, snum); 2243a9bb7912SHefty, Sean if (!bind_list) { 2244a9bb7912SHefty, Sean ret = cma_alloc_port(ps, id_priv, snum); 2245a9bb7912SHefty, Sean } else { 2246a9bb7912SHefty, Sean ret = cma_check_port(bind_list, id_priv, id_priv->reuseaddr); 2247a9bb7912SHefty, Sean if (!ret) 2248a9bb7912SHefty, Sean cma_bind_port(bind_list, id_priv); 2249a9bb7912SHefty, Sean } 2250a9bb7912SHefty, Sean return ret; 2251a9bb7912SHefty, Sean } 2252a9bb7912SHefty, Sean 2253a9bb7912SHefty, Sean static int cma_bind_listen(struct rdma_id_private *id_priv) 2254a9bb7912SHefty, Sean { 2255a9bb7912SHefty, Sean struct rdma_bind_list *bind_list = id_priv->bind_list; 2256a9bb7912SHefty, Sean int ret = 0; 2257a9bb7912SHefty, Sean 2258a9bb7912SHefty, Sean mutex_lock(&lock); 2259a9bb7912SHefty, Sean if (bind_list->owners.first->next) 2260a9bb7912SHefty, Sean ret = cma_check_port(bind_list, id_priv, 0); 2261a9bb7912SHefty, Sean mutex_unlock(&lock); 2262a9bb7912SHefty, Sean return ret; 2263a9bb7912SHefty, Sean } 2264a9bb7912SHefty, Sean 2265e51060f0SSean Hefty static int cma_get_port(struct rdma_id_private *id_priv) 2266e51060f0SSean Hefty { 2267e51060f0SSean Hefty struct idr *ps; 2268e51060f0SSean Hefty int ret; 2269e51060f0SSean Hefty 2270e51060f0SSean Hefty switch (id_priv->id.ps) { 2271e51060f0SSean Hefty case RDMA_PS_SDP: 2272e51060f0SSean Hefty ps = &sdp_ps; 2273e51060f0SSean Hefty break; 2274e51060f0SSean Hefty case RDMA_PS_TCP: 2275e51060f0SSean Hefty ps = &tcp_ps; 2276e51060f0SSean Hefty break; 2277628e5f6dSSean Hefty case RDMA_PS_UDP: 2278628e5f6dSSean Hefty ps = &udp_ps; 2279628e5f6dSSean Hefty break; 2280c8f6a362SSean Hefty case RDMA_PS_IPOIB: 2281c8f6a362SSean Hefty ps = &ipoib_ps; 2282c8f6a362SSean Hefty break; 22832d2e9415SSean Hefty case RDMA_PS_IB: 22842d2e9415SSean Hefty ps = &ib_ps; 22852d2e9415SSean Hefty break; 2286e51060f0SSean Hefty default: 2287e51060f0SSean Hefty return -EPROTONOSUPPORT; 2288e51060f0SSean Hefty } 2289e51060f0SSean Hefty 2290e51060f0SSean Hefty mutex_lock(&lock); 22913f446754SRoland Dreier if (cma_any_port((struct sockaddr *) &id_priv->id.route.addr.src_addr)) 2292aedec080SSean Hefty ret = cma_alloc_any_port(ps, id_priv); 2293e51060f0SSean Hefty else 2294e51060f0SSean Hefty ret = cma_use_port(ps, id_priv); 2295e51060f0SSean Hefty mutex_unlock(&lock); 2296e51060f0SSean Hefty 2297e51060f0SSean Hefty return ret; 2298e51060f0SSean Hefty } 2299e51060f0SSean Hefty 2300d14714dfSSean Hefty static int cma_check_linklocal(struct rdma_dev_addr *dev_addr, 2301d14714dfSSean Hefty struct sockaddr *addr) 2302d14714dfSSean Hefty { 2303d90f9b35SRoland Dreier #if IS_ENABLED(CONFIG_IPV6) 2304d14714dfSSean Hefty struct sockaddr_in6 *sin6; 2305d14714dfSSean Hefty 2306d14714dfSSean Hefty if (addr->sa_family != AF_INET6) 2307d14714dfSSean Hefty return 0; 2308d14714dfSSean Hefty 2309d14714dfSSean Hefty sin6 = (struct sockaddr_in6 *) addr; 2310d14714dfSSean Hefty if ((ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) && 2311d14714dfSSean Hefty !sin6->sin6_scope_id) 2312d14714dfSSean Hefty return -EINVAL; 2313d14714dfSSean Hefty 2314d14714dfSSean Hefty dev_addr->bound_dev_if = sin6->sin6_scope_id; 2315d14714dfSSean Hefty #endif 2316d14714dfSSean Hefty return 0; 2317d14714dfSSean Hefty } 2318d14714dfSSean Hefty 2319a9bb7912SHefty, Sean int rdma_listen(struct rdma_cm_id *id, int backlog) 2320a9bb7912SHefty, Sean { 2321a9bb7912SHefty, Sean struct rdma_id_private *id_priv; 2322a9bb7912SHefty, Sean int ret; 2323a9bb7912SHefty, Sean 2324a9bb7912SHefty, Sean id_priv = container_of(id, struct rdma_id_private, id); 2325550e5ca7SNir Muchtar if (id_priv->state == RDMA_CM_IDLE) { 2326a9bb7912SHefty, Sean ((struct sockaddr *) &id->route.addr.src_addr)->sa_family = AF_INET; 2327a9bb7912SHefty, Sean ret = rdma_bind_addr(id, (struct sockaddr *) &id->route.addr.src_addr); 2328a9bb7912SHefty, Sean if (ret) 2329a9bb7912SHefty, Sean return ret; 2330a9bb7912SHefty, Sean } 2331a9bb7912SHefty, Sean 2332550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_LISTEN)) 2333a9bb7912SHefty, Sean return -EINVAL; 2334a9bb7912SHefty, Sean 2335a9bb7912SHefty, Sean if (id_priv->reuseaddr) { 2336a9bb7912SHefty, Sean ret = cma_bind_listen(id_priv); 2337a9bb7912SHefty, Sean if (ret) 2338a9bb7912SHefty, Sean goto err; 2339a9bb7912SHefty, Sean } 2340a9bb7912SHefty, Sean 2341a9bb7912SHefty, Sean id_priv->backlog = backlog; 2342a9bb7912SHefty, Sean if (id->device) { 2343a9bb7912SHefty, Sean switch (rdma_node_get_transport(id->device->node_type)) { 2344a9bb7912SHefty, Sean case RDMA_TRANSPORT_IB: 2345a9bb7912SHefty, Sean ret = cma_ib_listen(id_priv); 2346a9bb7912SHefty, Sean if (ret) 2347a9bb7912SHefty, Sean goto err; 2348a9bb7912SHefty, Sean break; 2349a9bb7912SHefty, Sean case RDMA_TRANSPORT_IWARP: 2350a9bb7912SHefty, Sean ret = cma_iw_listen(id_priv, backlog); 2351a9bb7912SHefty, Sean if (ret) 2352a9bb7912SHefty, Sean goto err; 2353a9bb7912SHefty, Sean break; 2354a9bb7912SHefty, Sean default: 2355a9bb7912SHefty, Sean ret = -ENOSYS; 2356a9bb7912SHefty, Sean goto err; 2357a9bb7912SHefty, Sean } 2358a9bb7912SHefty, Sean } else 2359a9bb7912SHefty, Sean cma_listen_on_all(id_priv); 2360a9bb7912SHefty, Sean 2361a9bb7912SHefty, Sean return 0; 2362a9bb7912SHefty, Sean err: 2363a9bb7912SHefty, Sean id_priv->backlog = 0; 2364550e5ca7SNir Muchtar cma_comp_exch(id_priv, RDMA_CM_LISTEN, RDMA_CM_ADDR_BOUND); 2365a9bb7912SHefty, Sean return ret; 2366a9bb7912SHefty, Sean } 2367a9bb7912SHefty, Sean EXPORT_SYMBOL(rdma_listen); 2368a9bb7912SHefty, Sean 2369e51060f0SSean Hefty int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr) 2370e51060f0SSean Hefty { 2371e51060f0SSean Hefty struct rdma_id_private *id_priv; 2372e51060f0SSean Hefty int ret; 2373e51060f0SSean Hefty 23741f5175adSAleksey Senin if (addr->sa_family != AF_INET && addr->sa_family != AF_INET6) 2375e51060f0SSean Hefty return -EAFNOSUPPORT; 2376e51060f0SSean Hefty 2377e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 2378550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_IDLE, RDMA_CM_ADDR_BOUND)) 2379e51060f0SSean Hefty return -EINVAL; 2380e51060f0SSean Hefty 2381d14714dfSSean Hefty ret = cma_check_linklocal(&id->route.addr.dev_addr, addr); 2382d14714dfSSean Hefty if (ret) 2383d14714dfSSean Hefty goto err1; 2384d14714dfSSean Hefty 23858523c048SSean Hefty if (!cma_any_addr(addr)) { 2386e51060f0SSean Hefty ret = rdma_translate_ip(addr, &id->route.addr.dev_addr); 2387255d0c14SKrishna Kumar if (ret) 2388255d0c14SKrishna Kumar goto err1; 2389255d0c14SKrishna Kumar 2390e51060f0SSean Hefty ret = cma_acquire_dev(id_priv); 2391e51060f0SSean Hefty if (ret) 2392255d0c14SKrishna Kumar goto err1; 2393e51060f0SSean Hefty } 2394e51060f0SSean Hefty 2395e51060f0SSean Hefty memcpy(&id->route.addr.src_addr, addr, ip_addr_size(addr)); 239668602120SSean Hefty if (!(id_priv->options & (1 << CMA_OPTION_AFONLY))) { 23975b0ec991SSean Hefty if (addr->sa_family == AF_INET) 23985b0ec991SSean Hefty id_priv->afonly = 1; 23995b0ec991SSean Hefty #if IS_ENABLED(CONFIG_IPV6) 24005b0ec991SSean Hefty else if (addr->sa_family == AF_INET6) 24015b0ec991SSean Hefty id_priv->afonly = init_net.ipv6.sysctl.bindv6only; 24025b0ec991SSean Hefty #endif 240368602120SSean Hefty } 2404e51060f0SSean Hefty ret = cma_get_port(id_priv); 2405e51060f0SSean Hefty if (ret) 2406255d0c14SKrishna Kumar goto err2; 2407e51060f0SSean Hefty 2408e51060f0SSean Hefty return 0; 2409255d0c14SKrishna Kumar err2: 2410a396d43aSSean Hefty if (id_priv->cma_dev) 2411a396d43aSSean Hefty cma_release_dev(id_priv); 2412255d0c14SKrishna Kumar err1: 2413550e5ca7SNir Muchtar cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_IDLE); 2414e51060f0SSean Hefty return ret; 2415e51060f0SSean Hefty } 2416e51060f0SSean Hefty EXPORT_SYMBOL(rdma_bind_addr); 2417e51060f0SSean Hefty 2418e51060f0SSean Hefty static int cma_format_hdr(void *hdr, enum rdma_port_space ps, 2419e51060f0SSean Hefty struct rdma_route *route) 2420e51060f0SSean Hefty { 2421e51060f0SSean Hefty struct cma_hdr *cma_hdr; 2422e51060f0SSean Hefty struct sdp_hh *sdp_hdr; 2423e51060f0SSean Hefty 24241f5175adSAleksey Senin if (route->addr.src_addr.ss_family == AF_INET) { 24251f5175adSAleksey Senin struct sockaddr_in *src4, *dst4; 24261f5175adSAleksey Senin 2427e51060f0SSean Hefty src4 = (struct sockaddr_in *) &route->addr.src_addr; 2428e51060f0SSean Hefty dst4 = (struct sockaddr_in *) &route->addr.dst_addr; 2429e51060f0SSean Hefty 2430e51060f0SSean Hefty switch (ps) { 2431e51060f0SSean Hefty case RDMA_PS_SDP: 2432e51060f0SSean Hefty sdp_hdr = hdr; 2433e51060f0SSean Hefty if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION) 2434e51060f0SSean Hefty return -EINVAL; 2435e51060f0SSean Hefty sdp_set_ip_ver(sdp_hdr, 4); 2436e51060f0SSean Hefty sdp_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr; 2437e51060f0SSean Hefty sdp_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr; 2438e51060f0SSean Hefty sdp_hdr->port = src4->sin_port; 2439e51060f0SSean Hefty break; 2440e51060f0SSean Hefty default: 2441e51060f0SSean Hefty cma_hdr = hdr; 2442e51060f0SSean Hefty cma_hdr->cma_version = CMA_VERSION; 2443e51060f0SSean Hefty cma_set_ip_ver(cma_hdr, 4); 2444e51060f0SSean Hefty cma_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr; 2445e51060f0SSean Hefty cma_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr; 2446e51060f0SSean Hefty cma_hdr->port = src4->sin_port; 2447e51060f0SSean Hefty break; 2448e51060f0SSean Hefty } 24491f5175adSAleksey Senin } else { 24501f5175adSAleksey Senin struct sockaddr_in6 *src6, *dst6; 24511f5175adSAleksey Senin 24521f5175adSAleksey Senin src6 = (struct sockaddr_in6 *) &route->addr.src_addr; 24531f5175adSAleksey Senin dst6 = (struct sockaddr_in6 *) &route->addr.dst_addr; 24541f5175adSAleksey Senin 24551f5175adSAleksey Senin switch (ps) { 24561f5175adSAleksey Senin case RDMA_PS_SDP: 24571f5175adSAleksey Senin sdp_hdr = hdr; 24581f5175adSAleksey Senin if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION) 24591f5175adSAleksey Senin return -EINVAL; 24601f5175adSAleksey Senin sdp_set_ip_ver(sdp_hdr, 6); 24611f5175adSAleksey Senin sdp_hdr->src_addr.ip6 = src6->sin6_addr; 24621f5175adSAleksey Senin sdp_hdr->dst_addr.ip6 = dst6->sin6_addr; 24631f5175adSAleksey Senin sdp_hdr->port = src6->sin6_port; 24641f5175adSAleksey Senin break; 24651f5175adSAleksey Senin default: 24661f5175adSAleksey Senin cma_hdr = hdr; 24671f5175adSAleksey Senin cma_hdr->cma_version = CMA_VERSION; 24681f5175adSAleksey Senin cma_set_ip_ver(cma_hdr, 6); 24691f5175adSAleksey Senin cma_hdr->src_addr.ip6 = src6->sin6_addr; 24701f5175adSAleksey Senin cma_hdr->dst_addr.ip6 = dst6->sin6_addr; 24711f5175adSAleksey Senin cma_hdr->port = src6->sin6_port; 24721f5175adSAleksey Senin break; 24731f5175adSAleksey Senin } 24741f5175adSAleksey Senin } 2475e51060f0SSean Hefty return 0; 2476e51060f0SSean Hefty } 2477e51060f0SSean Hefty 2478628e5f6dSSean Hefty static int cma_sidr_rep_handler(struct ib_cm_id *cm_id, 2479628e5f6dSSean Hefty struct ib_cm_event *ib_event) 2480628e5f6dSSean Hefty { 2481628e5f6dSSean Hefty struct rdma_id_private *id_priv = cm_id->context; 2482628e5f6dSSean Hefty struct rdma_cm_event event; 2483628e5f6dSSean Hefty struct ib_cm_sidr_rep_event_param *rep = &ib_event->param.sidr_rep_rcvd; 2484628e5f6dSSean Hefty int ret = 0; 2485628e5f6dSSean Hefty 2486550e5ca7SNir Muchtar if (cma_disable_callback(id_priv, RDMA_CM_CONNECT)) 24878aa08602SSean Hefty return 0; 2488628e5f6dSSean Hefty 24898aa08602SSean Hefty memset(&event, 0, sizeof event); 2490628e5f6dSSean Hefty switch (ib_event->event) { 2491628e5f6dSSean Hefty case IB_CM_SIDR_REQ_ERROR: 2492628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_UNREACHABLE; 2493628e5f6dSSean Hefty event.status = -ETIMEDOUT; 2494628e5f6dSSean Hefty break; 2495628e5f6dSSean Hefty case IB_CM_SIDR_REP_RECEIVED: 2496628e5f6dSSean Hefty event.param.ud.private_data = ib_event->private_data; 2497628e5f6dSSean Hefty event.param.ud.private_data_len = IB_CM_SIDR_REP_PRIVATE_DATA_SIZE; 2498628e5f6dSSean Hefty if (rep->status != IB_SIDR_SUCCESS) { 2499628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_UNREACHABLE; 2500628e5f6dSSean Hefty event.status = ib_event->param.sidr_rep_rcvd.status; 2501628e5f6dSSean Hefty break; 2502628e5f6dSSean Hefty } 2503d2ca39f2SYossi Etigin ret = cma_set_qkey(id_priv); 2504d2ca39f2SYossi Etigin if (ret) { 2505d2ca39f2SYossi Etigin event.event = RDMA_CM_EVENT_ADDR_ERROR; 2506d2ca39f2SYossi Etigin event.status = -EINVAL; 2507d2ca39f2SYossi Etigin break; 2508d2ca39f2SYossi Etigin } 2509c8f6a362SSean Hefty if (id_priv->qkey != rep->qkey) { 2510628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_UNREACHABLE; 2511628e5f6dSSean Hefty event.status = -EINVAL; 2512628e5f6dSSean Hefty break; 2513628e5f6dSSean Hefty } 2514628e5f6dSSean Hefty ib_init_ah_from_path(id_priv->id.device, id_priv->id.port_num, 2515628e5f6dSSean Hefty id_priv->id.route.path_rec, 2516628e5f6dSSean Hefty &event.param.ud.ah_attr); 2517628e5f6dSSean Hefty event.param.ud.qp_num = rep->qpn; 2518628e5f6dSSean Hefty event.param.ud.qkey = rep->qkey; 2519628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_ESTABLISHED; 2520628e5f6dSSean Hefty event.status = 0; 2521628e5f6dSSean Hefty break; 2522628e5f6dSSean Hefty default: 2523468f2239SRoland Dreier printk(KERN_ERR "RDMA CMA: unexpected IB CM event: %d\n", 2524628e5f6dSSean Hefty ib_event->event); 2525628e5f6dSSean Hefty goto out; 2526628e5f6dSSean Hefty } 2527628e5f6dSSean Hefty 2528628e5f6dSSean Hefty ret = id_priv->id.event_handler(&id_priv->id, &event); 2529628e5f6dSSean Hefty if (ret) { 2530628e5f6dSSean Hefty /* Destroy the CM ID by returning a non-zero value. */ 2531628e5f6dSSean Hefty id_priv->cm_id.ib = NULL; 2532550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 2533de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 2534628e5f6dSSean Hefty rdma_destroy_id(&id_priv->id); 2535628e5f6dSSean Hefty return ret; 2536628e5f6dSSean Hefty } 2537628e5f6dSSean Hefty out: 2538de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 2539628e5f6dSSean Hefty return ret; 2540628e5f6dSSean Hefty } 2541628e5f6dSSean Hefty 2542628e5f6dSSean Hefty static int cma_resolve_ib_udp(struct rdma_id_private *id_priv, 2543628e5f6dSSean Hefty struct rdma_conn_param *conn_param) 2544628e5f6dSSean Hefty { 2545628e5f6dSSean Hefty struct ib_cm_sidr_req_param req; 2546628e5f6dSSean Hefty struct rdma_route *route; 25470c9361fcSJack Morgenstein struct ib_cm_id *id; 2548628e5f6dSSean Hefty int ret; 2549628e5f6dSSean Hefty 2550628e5f6dSSean Hefty req.private_data_len = sizeof(struct cma_hdr) + 2551628e5f6dSSean Hefty conn_param->private_data_len; 255204ded167SSean Hefty if (req.private_data_len < conn_param->private_data_len) 255304ded167SSean Hefty return -EINVAL; 255404ded167SSean Hefty 2555628e5f6dSSean Hefty req.private_data = kzalloc(req.private_data_len, GFP_ATOMIC); 2556628e5f6dSSean Hefty if (!req.private_data) 2557628e5f6dSSean Hefty return -ENOMEM; 2558628e5f6dSSean Hefty 2559628e5f6dSSean Hefty if (conn_param->private_data && conn_param->private_data_len) 2560628e5f6dSSean Hefty memcpy((void *) req.private_data + sizeof(struct cma_hdr), 2561628e5f6dSSean Hefty conn_param->private_data, conn_param->private_data_len); 2562628e5f6dSSean Hefty 2563628e5f6dSSean Hefty route = &id_priv->id.route; 2564628e5f6dSSean Hefty ret = cma_format_hdr((void *) req.private_data, id_priv->id.ps, route); 2565628e5f6dSSean Hefty if (ret) 2566628e5f6dSSean Hefty goto out; 2567628e5f6dSSean Hefty 25680c9361fcSJack Morgenstein id = ib_create_cm_id(id_priv->id.device, cma_sidr_rep_handler, 25690c9361fcSJack Morgenstein id_priv); 25700c9361fcSJack Morgenstein if (IS_ERR(id)) { 25710c9361fcSJack Morgenstein ret = PTR_ERR(id); 2572628e5f6dSSean Hefty goto out; 2573628e5f6dSSean Hefty } 25740c9361fcSJack Morgenstein id_priv->cm_id.ib = id; 2575628e5f6dSSean Hefty 2576628e5f6dSSean Hefty req.path = route->path_rec; 2577628e5f6dSSean Hefty req.service_id = cma_get_service_id(id_priv->id.ps, 25783f446754SRoland Dreier (struct sockaddr *) &route->addr.dst_addr); 2579628e5f6dSSean Hefty req.timeout_ms = 1 << (CMA_CM_RESPONSE_TIMEOUT - 8); 2580628e5f6dSSean Hefty req.max_cm_retries = CMA_MAX_CM_RETRIES; 2581628e5f6dSSean Hefty 2582628e5f6dSSean Hefty ret = ib_send_cm_sidr_req(id_priv->cm_id.ib, &req); 2583628e5f6dSSean Hefty if (ret) { 2584628e5f6dSSean Hefty ib_destroy_cm_id(id_priv->cm_id.ib); 2585628e5f6dSSean Hefty id_priv->cm_id.ib = NULL; 2586628e5f6dSSean Hefty } 2587628e5f6dSSean Hefty out: 2588628e5f6dSSean Hefty kfree(req.private_data); 2589628e5f6dSSean Hefty return ret; 2590628e5f6dSSean Hefty } 2591628e5f6dSSean Hefty 2592e51060f0SSean Hefty static int cma_connect_ib(struct rdma_id_private *id_priv, 2593e51060f0SSean Hefty struct rdma_conn_param *conn_param) 2594e51060f0SSean Hefty { 2595e51060f0SSean Hefty struct ib_cm_req_param req; 2596e51060f0SSean Hefty struct rdma_route *route; 2597e51060f0SSean Hefty void *private_data; 25980c9361fcSJack Morgenstein struct ib_cm_id *id; 2599e51060f0SSean Hefty int offset, ret; 2600e51060f0SSean Hefty 2601e51060f0SSean Hefty memset(&req, 0, sizeof req); 2602e51060f0SSean Hefty offset = cma_user_data_offset(id_priv->id.ps); 2603e51060f0SSean Hefty req.private_data_len = offset + conn_param->private_data_len; 260404ded167SSean Hefty if (req.private_data_len < conn_param->private_data_len) 260504ded167SSean Hefty return -EINVAL; 260604ded167SSean Hefty 2607e51060f0SSean Hefty private_data = kzalloc(req.private_data_len, GFP_ATOMIC); 2608e51060f0SSean Hefty if (!private_data) 2609e51060f0SSean Hefty return -ENOMEM; 2610e51060f0SSean Hefty 2611e51060f0SSean Hefty if (conn_param->private_data && conn_param->private_data_len) 2612e51060f0SSean Hefty memcpy(private_data + offset, conn_param->private_data, 2613e51060f0SSean Hefty conn_param->private_data_len); 2614e51060f0SSean Hefty 26150c9361fcSJack Morgenstein id = ib_create_cm_id(id_priv->id.device, cma_ib_handler, id_priv); 26160c9361fcSJack Morgenstein if (IS_ERR(id)) { 26170c9361fcSJack Morgenstein ret = PTR_ERR(id); 2618e51060f0SSean Hefty goto out; 2619e51060f0SSean Hefty } 26200c9361fcSJack Morgenstein id_priv->cm_id.ib = id; 2621e51060f0SSean Hefty 2622e51060f0SSean Hefty route = &id_priv->id.route; 2623e51060f0SSean Hefty ret = cma_format_hdr(private_data, id_priv->id.ps, route); 2624e51060f0SSean Hefty if (ret) 2625e51060f0SSean Hefty goto out; 2626e51060f0SSean Hefty req.private_data = private_data; 2627e51060f0SSean Hefty 2628e51060f0SSean Hefty req.primary_path = &route->path_rec[0]; 2629e51060f0SSean Hefty if (route->num_paths == 2) 2630e51060f0SSean Hefty req.alternate_path = &route->path_rec[1]; 2631e51060f0SSean Hefty 2632e51060f0SSean Hefty req.service_id = cma_get_service_id(id_priv->id.ps, 26333f446754SRoland Dreier (struct sockaddr *) &route->addr.dst_addr); 2634e51060f0SSean Hefty req.qp_num = id_priv->qp_num; 263518c441a6SSean Hefty req.qp_type = id_priv->id.qp_type; 2636e51060f0SSean Hefty req.starting_psn = id_priv->seq_num; 2637e51060f0SSean Hefty req.responder_resources = conn_param->responder_resources; 2638e51060f0SSean Hefty req.initiator_depth = conn_param->initiator_depth; 2639e51060f0SSean Hefty req.flow_control = conn_param->flow_control; 26404ede178aSSean Hefty req.retry_count = min_t(u8, 7, conn_param->retry_count); 26414ede178aSSean Hefty req.rnr_retry_count = min_t(u8, 7, conn_param->rnr_retry_count); 2642e51060f0SSean Hefty req.remote_cm_response_timeout = CMA_CM_RESPONSE_TIMEOUT; 2643e51060f0SSean Hefty req.local_cm_response_timeout = CMA_CM_RESPONSE_TIMEOUT; 2644e51060f0SSean Hefty req.max_cm_retries = CMA_MAX_CM_RETRIES; 2645e51060f0SSean Hefty req.srq = id_priv->srq ? 1 : 0; 2646e51060f0SSean Hefty 2647e51060f0SSean Hefty ret = ib_send_cm_req(id_priv->cm_id.ib, &req); 2648e51060f0SSean Hefty out: 26490c9361fcSJack Morgenstein if (ret && !IS_ERR(id)) { 26500c9361fcSJack Morgenstein ib_destroy_cm_id(id); 2651675a027cSKrishna Kumar id_priv->cm_id.ib = NULL; 2652675a027cSKrishna Kumar } 2653675a027cSKrishna Kumar 2654e51060f0SSean Hefty kfree(private_data); 2655e51060f0SSean Hefty return ret; 2656e51060f0SSean Hefty } 2657e51060f0SSean Hefty 265807ebafbaSTom Tucker static int cma_connect_iw(struct rdma_id_private *id_priv, 265907ebafbaSTom Tucker struct rdma_conn_param *conn_param) 266007ebafbaSTom Tucker { 266107ebafbaSTom Tucker struct iw_cm_id *cm_id; 266207ebafbaSTom Tucker struct sockaddr_in* sin; 266307ebafbaSTom Tucker int ret; 266407ebafbaSTom Tucker struct iw_cm_conn_param iw_param; 266507ebafbaSTom Tucker 266607ebafbaSTom Tucker cm_id = iw_create_cm_id(id_priv->id.device, cma_iw_handler, id_priv); 26670c9361fcSJack Morgenstein if (IS_ERR(cm_id)) 26680c9361fcSJack Morgenstein return PTR_ERR(cm_id); 266907ebafbaSTom Tucker 267007ebafbaSTom Tucker id_priv->cm_id.iw = cm_id; 267107ebafbaSTom Tucker 267207ebafbaSTom Tucker sin = (struct sockaddr_in*) &id_priv->id.route.addr.src_addr; 267307ebafbaSTom Tucker cm_id->local_addr = *sin; 267407ebafbaSTom Tucker 267507ebafbaSTom Tucker sin = (struct sockaddr_in*) &id_priv->id.route.addr.dst_addr; 267607ebafbaSTom Tucker cm_id->remote_addr = *sin; 267707ebafbaSTom Tucker 26785851bb89SSean Hefty ret = cma_modify_qp_rtr(id_priv, conn_param); 2679675a027cSKrishna Kumar if (ret) 2680675a027cSKrishna Kumar goto out; 268107ebafbaSTom Tucker 2682f45ee80eSHefty, Sean if (conn_param) { 268307ebafbaSTom Tucker iw_param.ord = conn_param->initiator_depth; 268407ebafbaSTom Tucker iw_param.ird = conn_param->responder_resources; 268507ebafbaSTom Tucker iw_param.private_data = conn_param->private_data; 268607ebafbaSTom Tucker iw_param.private_data_len = conn_param->private_data_len; 2687f45ee80eSHefty, Sean iw_param.qpn = id_priv->id.qp ? id_priv->qp_num : conn_param->qp_num; 2688f45ee80eSHefty, Sean } else { 2689f45ee80eSHefty, Sean memset(&iw_param, 0, sizeof iw_param); 269007ebafbaSTom Tucker iw_param.qpn = id_priv->qp_num; 2691f45ee80eSHefty, Sean } 269207ebafbaSTom Tucker ret = iw_cm_connect(cm_id, &iw_param); 269307ebafbaSTom Tucker out: 26940c9361fcSJack Morgenstein if (ret) { 2695675a027cSKrishna Kumar iw_destroy_cm_id(cm_id); 2696675a027cSKrishna Kumar id_priv->cm_id.iw = NULL; 2697675a027cSKrishna Kumar } 269807ebafbaSTom Tucker return ret; 269907ebafbaSTom Tucker } 270007ebafbaSTom Tucker 2701e51060f0SSean Hefty int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param) 2702e51060f0SSean Hefty { 2703e51060f0SSean Hefty struct rdma_id_private *id_priv; 2704e51060f0SSean Hefty int ret; 2705e51060f0SSean Hefty 2706e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 2707550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_ROUTE_RESOLVED, RDMA_CM_CONNECT)) 2708e51060f0SSean Hefty return -EINVAL; 2709e51060f0SSean Hefty 2710e51060f0SSean Hefty if (!id->qp) { 2711e51060f0SSean Hefty id_priv->qp_num = conn_param->qp_num; 2712e51060f0SSean Hefty id_priv->srq = conn_param->srq; 2713e51060f0SSean Hefty } 2714e51060f0SSean Hefty 271507ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 271607ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 2717b26f9b99SSean Hefty if (id->qp_type == IB_QPT_UD) 2718628e5f6dSSean Hefty ret = cma_resolve_ib_udp(id_priv, conn_param); 2719628e5f6dSSean Hefty else 2720e51060f0SSean Hefty ret = cma_connect_ib(id_priv, conn_param); 2721e51060f0SSean Hefty break; 272207ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 272307ebafbaSTom Tucker ret = cma_connect_iw(id_priv, conn_param); 272407ebafbaSTom Tucker break; 2725e51060f0SSean Hefty default: 2726e51060f0SSean Hefty ret = -ENOSYS; 2727e51060f0SSean Hefty break; 2728e51060f0SSean Hefty } 2729e51060f0SSean Hefty if (ret) 2730e51060f0SSean Hefty goto err; 2731e51060f0SSean Hefty 2732e51060f0SSean Hefty return 0; 2733e51060f0SSean Hefty err: 2734550e5ca7SNir Muchtar cma_comp_exch(id_priv, RDMA_CM_CONNECT, RDMA_CM_ROUTE_RESOLVED); 2735e51060f0SSean Hefty return ret; 2736e51060f0SSean Hefty } 2737e51060f0SSean Hefty EXPORT_SYMBOL(rdma_connect); 2738e51060f0SSean Hefty 2739e51060f0SSean Hefty static int cma_accept_ib(struct rdma_id_private *id_priv, 2740e51060f0SSean Hefty struct rdma_conn_param *conn_param) 2741e51060f0SSean Hefty { 2742e51060f0SSean Hefty struct ib_cm_rep_param rep; 27435851bb89SSean Hefty int ret; 2744e51060f0SSean Hefty 27455851bb89SSean Hefty ret = cma_modify_qp_rtr(id_priv, conn_param); 2746e51060f0SSean Hefty if (ret) 27470fe313b0SSean Hefty goto out; 27480fe313b0SSean Hefty 27495851bb89SSean Hefty ret = cma_modify_qp_rts(id_priv, conn_param); 27500fe313b0SSean Hefty if (ret) 27510fe313b0SSean Hefty goto out; 27520fe313b0SSean Hefty 2753e51060f0SSean Hefty memset(&rep, 0, sizeof rep); 2754e51060f0SSean Hefty rep.qp_num = id_priv->qp_num; 2755e51060f0SSean Hefty rep.starting_psn = id_priv->seq_num; 2756e51060f0SSean Hefty rep.private_data = conn_param->private_data; 2757e51060f0SSean Hefty rep.private_data_len = conn_param->private_data_len; 2758e51060f0SSean Hefty rep.responder_resources = conn_param->responder_resources; 2759e51060f0SSean Hefty rep.initiator_depth = conn_param->initiator_depth; 2760e51060f0SSean Hefty rep.failover_accepted = 0; 2761e51060f0SSean Hefty rep.flow_control = conn_param->flow_control; 27624ede178aSSean Hefty rep.rnr_retry_count = min_t(u8, 7, conn_param->rnr_retry_count); 2763e51060f0SSean Hefty rep.srq = id_priv->srq ? 1 : 0; 2764e51060f0SSean Hefty 27650fe313b0SSean Hefty ret = ib_send_cm_rep(id_priv->cm_id.ib, &rep); 27660fe313b0SSean Hefty out: 27670fe313b0SSean Hefty return ret; 2768e51060f0SSean Hefty } 2769e51060f0SSean Hefty 277007ebafbaSTom Tucker static int cma_accept_iw(struct rdma_id_private *id_priv, 277107ebafbaSTom Tucker struct rdma_conn_param *conn_param) 277207ebafbaSTom Tucker { 277307ebafbaSTom Tucker struct iw_cm_conn_param iw_param; 277407ebafbaSTom Tucker int ret; 277507ebafbaSTom Tucker 27765851bb89SSean Hefty ret = cma_modify_qp_rtr(id_priv, conn_param); 277707ebafbaSTom Tucker if (ret) 277807ebafbaSTom Tucker return ret; 277907ebafbaSTom Tucker 278007ebafbaSTom Tucker iw_param.ord = conn_param->initiator_depth; 278107ebafbaSTom Tucker iw_param.ird = conn_param->responder_resources; 278207ebafbaSTom Tucker iw_param.private_data = conn_param->private_data; 278307ebafbaSTom Tucker iw_param.private_data_len = conn_param->private_data_len; 278407ebafbaSTom Tucker if (id_priv->id.qp) { 278507ebafbaSTom Tucker iw_param.qpn = id_priv->qp_num; 278607ebafbaSTom Tucker } else 278707ebafbaSTom Tucker iw_param.qpn = conn_param->qp_num; 278807ebafbaSTom Tucker 278907ebafbaSTom Tucker return iw_cm_accept(id_priv->cm_id.iw, &iw_param); 279007ebafbaSTom Tucker } 279107ebafbaSTom Tucker 2792628e5f6dSSean Hefty static int cma_send_sidr_rep(struct rdma_id_private *id_priv, 2793628e5f6dSSean Hefty enum ib_cm_sidr_status status, 2794628e5f6dSSean Hefty const void *private_data, int private_data_len) 2795628e5f6dSSean Hefty { 2796628e5f6dSSean Hefty struct ib_cm_sidr_rep_param rep; 2797d2ca39f2SYossi Etigin int ret; 2798628e5f6dSSean Hefty 2799628e5f6dSSean Hefty memset(&rep, 0, sizeof rep); 2800628e5f6dSSean Hefty rep.status = status; 2801628e5f6dSSean Hefty if (status == IB_SIDR_SUCCESS) { 2802d2ca39f2SYossi Etigin ret = cma_set_qkey(id_priv); 2803d2ca39f2SYossi Etigin if (ret) 2804d2ca39f2SYossi Etigin return ret; 2805628e5f6dSSean Hefty rep.qp_num = id_priv->qp_num; 2806c8f6a362SSean Hefty rep.qkey = id_priv->qkey; 2807628e5f6dSSean Hefty } 2808628e5f6dSSean Hefty rep.private_data = private_data; 2809628e5f6dSSean Hefty rep.private_data_len = private_data_len; 2810628e5f6dSSean Hefty 2811628e5f6dSSean Hefty return ib_send_cm_sidr_rep(id_priv->cm_id.ib, &rep); 2812628e5f6dSSean Hefty } 2813628e5f6dSSean Hefty 2814e51060f0SSean Hefty int rdma_accept(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); 282083e9502dSNir Muchtar 282183e9502dSNir Muchtar id_priv->owner = task_pid_nr(current); 282283e9502dSNir Muchtar 2823550e5ca7SNir Muchtar if (!cma_comp(id_priv, RDMA_CM_CONNECT)) 2824e51060f0SSean Hefty return -EINVAL; 2825e51060f0SSean Hefty 2826e51060f0SSean Hefty if (!id->qp && conn_param) { 2827e51060f0SSean Hefty id_priv->qp_num = conn_param->qp_num; 2828e51060f0SSean Hefty id_priv->srq = conn_param->srq; 2829e51060f0SSean Hefty } 2830e51060f0SSean Hefty 283107ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 283207ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 2833f45ee80eSHefty, Sean if (id->qp_type == IB_QPT_UD) { 2834f45ee80eSHefty, Sean if (conn_param) 2835628e5f6dSSean Hefty ret = cma_send_sidr_rep(id_priv, IB_SIDR_SUCCESS, 2836628e5f6dSSean Hefty conn_param->private_data, 2837628e5f6dSSean Hefty conn_param->private_data_len); 2838f45ee80eSHefty, Sean else 2839f45ee80eSHefty, Sean ret = cma_send_sidr_rep(id_priv, IB_SIDR_SUCCESS, 2840f45ee80eSHefty, Sean NULL, 0); 2841f45ee80eSHefty, Sean } else { 2842f45ee80eSHefty, Sean if (conn_param) 2843e51060f0SSean Hefty ret = cma_accept_ib(id_priv, conn_param); 2844e51060f0SSean Hefty else 2845e51060f0SSean Hefty ret = cma_rep_recv(id_priv); 2846f45ee80eSHefty, Sean } 2847e51060f0SSean Hefty break; 284807ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 284907ebafbaSTom Tucker ret = cma_accept_iw(id_priv, conn_param); 285007ebafbaSTom Tucker break; 2851e51060f0SSean Hefty default: 2852e51060f0SSean Hefty ret = -ENOSYS; 2853e51060f0SSean Hefty break; 2854e51060f0SSean Hefty } 2855e51060f0SSean Hefty 2856e51060f0SSean Hefty if (ret) 2857e51060f0SSean Hefty goto reject; 2858e51060f0SSean Hefty 2859e51060f0SSean Hefty return 0; 2860e51060f0SSean Hefty reject: 2861c5483388SSean Hefty cma_modify_qp_err(id_priv); 2862e51060f0SSean Hefty rdma_reject(id, NULL, 0); 2863e51060f0SSean Hefty return ret; 2864e51060f0SSean Hefty } 2865e51060f0SSean Hefty EXPORT_SYMBOL(rdma_accept); 2866e51060f0SSean Hefty 28670fe313b0SSean Hefty int rdma_notify(struct rdma_cm_id *id, enum ib_event_type event) 28680fe313b0SSean Hefty { 28690fe313b0SSean Hefty struct rdma_id_private *id_priv; 28700fe313b0SSean Hefty int ret; 28710fe313b0SSean Hefty 28720fe313b0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 28730c9361fcSJack Morgenstein if (!id_priv->cm_id.ib) 28740fe313b0SSean Hefty return -EINVAL; 28750fe313b0SSean Hefty 28760fe313b0SSean Hefty switch (id->device->node_type) { 28770fe313b0SSean Hefty case RDMA_NODE_IB_CA: 28780fe313b0SSean Hefty ret = ib_cm_notify(id_priv->cm_id.ib, event); 28790fe313b0SSean Hefty break; 28800fe313b0SSean Hefty default: 28810fe313b0SSean Hefty ret = 0; 28820fe313b0SSean Hefty break; 28830fe313b0SSean Hefty } 28840fe313b0SSean Hefty return ret; 28850fe313b0SSean Hefty } 28860fe313b0SSean Hefty EXPORT_SYMBOL(rdma_notify); 28870fe313b0SSean Hefty 2888e51060f0SSean Hefty int rdma_reject(struct rdma_cm_id *id, const void *private_data, 2889e51060f0SSean Hefty u8 private_data_len) 2890e51060f0SSean Hefty { 2891e51060f0SSean Hefty struct rdma_id_private *id_priv; 2892e51060f0SSean Hefty int ret; 2893e51060f0SSean Hefty 2894e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 28950c9361fcSJack Morgenstein if (!id_priv->cm_id.ib) 2896e51060f0SSean Hefty return -EINVAL; 2897e51060f0SSean Hefty 289807ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 289907ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 2900b26f9b99SSean Hefty if (id->qp_type == IB_QPT_UD) 2901628e5f6dSSean Hefty ret = cma_send_sidr_rep(id_priv, IB_SIDR_REJECT, 2902e51060f0SSean Hefty private_data, private_data_len); 2903628e5f6dSSean Hefty else 2904628e5f6dSSean Hefty ret = ib_send_cm_rej(id_priv->cm_id.ib, 2905628e5f6dSSean Hefty IB_CM_REJ_CONSUMER_DEFINED, NULL, 2906628e5f6dSSean Hefty 0, private_data, private_data_len); 2907e51060f0SSean Hefty break; 290807ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 290907ebafbaSTom Tucker ret = iw_cm_reject(id_priv->cm_id.iw, 291007ebafbaSTom Tucker private_data, private_data_len); 291107ebafbaSTom Tucker break; 2912e51060f0SSean Hefty default: 2913e51060f0SSean Hefty ret = -ENOSYS; 2914e51060f0SSean Hefty break; 2915e51060f0SSean Hefty } 2916e51060f0SSean Hefty return ret; 2917e51060f0SSean Hefty } 2918e51060f0SSean Hefty EXPORT_SYMBOL(rdma_reject); 2919e51060f0SSean Hefty 2920e51060f0SSean Hefty int rdma_disconnect(struct rdma_cm_id *id) 2921e51060f0SSean Hefty { 2922e51060f0SSean Hefty struct rdma_id_private *id_priv; 2923e51060f0SSean Hefty int ret; 2924e51060f0SSean Hefty 2925e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 29260c9361fcSJack Morgenstein if (!id_priv->cm_id.ib) 2927e51060f0SSean Hefty return -EINVAL; 2928e51060f0SSean Hefty 292907ebafbaSTom Tucker switch (rdma_node_get_transport(id->device->node_type)) { 293007ebafbaSTom Tucker case RDMA_TRANSPORT_IB: 2931c5483388SSean Hefty ret = cma_modify_qp_err(id_priv); 2932e51060f0SSean Hefty if (ret) 2933e51060f0SSean Hefty goto out; 2934e51060f0SSean Hefty /* Initiate or respond to a disconnect. */ 2935e51060f0SSean Hefty if (ib_send_cm_dreq(id_priv->cm_id.ib, NULL, 0)) 2936e51060f0SSean Hefty ib_send_cm_drep(id_priv->cm_id.ib, NULL, 0); 2937e51060f0SSean Hefty break; 293807ebafbaSTom Tucker case RDMA_TRANSPORT_IWARP: 293907ebafbaSTom Tucker ret = iw_cm_disconnect(id_priv->cm_id.iw, 0); 294007ebafbaSTom Tucker break; 2941e51060f0SSean Hefty default: 294207ebafbaSTom Tucker ret = -EINVAL; 2943e51060f0SSean Hefty break; 2944e51060f0SSean Hefty } 2945e51060f0SSean Hefty out: 2946e51060f0SSean Hefty return ret; 2947e51060f0SSean Hefty } 2948e51060f0SSean Hefty EXPORT_SYMBOL(rdma_disconnect); 2949e51060f0SSean Hefty 2950c8f6a362SSean Hefty static int cma_ib_mc_handler(int status, struct ib_sa_multicast *multicast) 2951c8f6a362SSean Hefty { 2952c8f6a362SSean Hefty struct rdma_id_private *id_priv; 2953c8f6a362SSean Hefty struct cma_multicast *mc = multicast->context; 2954c8f6a362SSean Hefty struct rdma_cm_event event; 2955c8f6a362SSean Hefty int ret; 2956c8f6a362SSean Hefty 2957c8f6a362SSean Hefty id_priv = mc->id_priv; 2958550e5ca7SNir Muchtar if (cma_disable_callback(id_priv, RDMA_CM_ADDR_BOUND) && 2959550e5ca7SNir Muchtar cma_disable_callback(id_priv, RDMA_CM_ADDR_RESOLVED)) 29608aa08602SSean Hefty return 0; 2961c8f6a362SSean Hefty 2962c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 2963c8f6a362SSean Hefty if (!status && id_priv->id.qp) 2964c8f6a362SSean Hefty status = ib_attach_mcast(id_priv->id.qp, &multicast->rec.mgid, 296546ea5061SSean Hefty be16_to_cpu(multicast->rec.mlid)); 2966c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 2967c8f6a362SSean Hefty 2968c8f6a362SSean Hefty memset(&event, 0, sizeof event); 2969c8f6a362SSean Hefty event.status = status; 2970c8f6a362SSean Hefty event.param.ud.private_data = mc->context; 2971c8f6a362SSean Hefty if (!status) { 2972c8f6a362SSean Hefty event.event = RDMA_CM_EVENT_MULTICAST_JOIN; 2973c8f6a362SSean Hefty ib_init_ah_from_mcmember(id_priv->id.device, 2974c8f6a362SSean Hefty id_priv->id.port_num, &multicast->rec, 2975c8f6a362SSean Hefty &event.param.ud.ah_attr); 2976c8f6a362SSean Hefty event.param.ud.qp_num = 0xFFFFFF; 2977c8f6a362SSean Hefty event.param.ud.qkey = be32_to_cpu(multicast->rec.qkey); 2978c8f6a362SSean Hefty } else 2979c8f6a362SSean Hefty event.event = RDMA_CM_EVENT_MULTICAST_ERROR; 2980c8f6a362SSean Hefty 2981c8f6a362SSean Hefty ret = id_priv->id.event_handler(&id_priv->id, &event); 2982c8f6a362SSean Hefty if (ret) { 2983550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 2984de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 2985c8f6a362SSean Hefty rdma_destroy_id(&id_priv->id); 2986c8f6a362SSean Hefty return 0; 2987c8f6a362SSean Hefty } 29888aa08602SSean Hefty 2989de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 2990c8f6a362SSean Hefty return 0; 2991c8f6a362SSean Hefty } 2992c8f6a362SSean Hefty 2993c8f6a362SSean Hefty static void cma_set_mgid(struct rdma_id_private *id_priv, 2994c8f6a362SSean Hefty struct sockaddr *addr, union ib_gid *mgid) 2995c8f6a362SSean Hefty { 2996c8f6a362SSean Hefty unsigned char mc_map[MAX_ADDR_LEN]; 2997c8f6a362SSean Hefty struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 2998c8f6a362SSean Hefty struct sockaddr_in *sin = (struct sockaddr_in *) addr; 2999c8f6a362SSean Hefty struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) addr; 3000c8f6a362SSean Hefty 3001c8f6a362SSean Hefty if (cma_any_addr(addr)) { 3002c8f6a362SSean Hefty memset(mgid, 0, sizeof *mgid); 3003c8f6a362SSean Hefty } else if ((addr->sa_family == AF_INET6) && 30041c9b2819SJason Gunthorpe ((be32_to_cpu(sin6->sin6_addr.s6_addr32[0]) & 0xFFF0FFFF) == 3005c8f6a362SSean Hefty 0xFF10A01B)) { 3006c8f6a362SSean Hefty /* IPv6 address is an SA assigned MGID. */ 3007c8f6a362SSean Hefty memcpy(mgid, &sin6->sin6_addr, sizeof *mgid); 3008e2e62697SJason Gunthorpe } else if ((addr->sa_family == AF_INET6)) { 3009e2e62697SJason Gunthorpe ipv6_ib_mc_map(&sin6->sin6_addr, dev_addr->broadcast, mc_map); 3010e2e62697SJason Gunthorpe if (id_priv->id.ps == RDMA_PS_UDP) 3011e2e62697SJason Gunthorpe mc_map[7] = 0x01; /* Use RDMA CM signature */ 3012e2e62697SJason Gunthorpe *mgid = *(union ib_gid *) (mc_map + 4); 3013c8f6a362SSean Hefty } else { 3014a9e527e3SRolf Manderscheid ip_ib_mc_map(sin->sin_addr.s_addr, dev_addr->broadcast, mc_map); 3015c8f6a362SSean Hefty if (id_priv->id.ps == RDMA_PS_UDP) 3016c8f6a362SSean Hefty mc_map[7] = 0x01; /* Use RDMA CM signature */ 3017c8f6a362SSean Hefty *mgid = *(union ib_gid *) (mc_map + 4); 3018c8f6a362SSean Hefty } 3019c8f6a362SSean Hefty } 3020c8f6a362SSean Hefty 3021c8f6a362SSean Hefty static int cma_join_ib_multicast(struct rdma_id_private *id_priv, 3022c8f6a362SSean Hefty struct cma_multicast *mc) 3023c8f6a362SSean Hefty { 3024c8f6a362SSean Hefty struct ib_sa_mcmember_rec rec; 3025c8f6a362SSean Hefty struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 3026c8f6a362SSean Hefty ib_sa_comp_mask comp_mask; 3027c8f6a362SSean Hefty int ret; 3028c8f6a362SSean Hefty 3029c8f6a362SSean Hefty ib_addr_get_mgid(dev_addr, &rec.mgid); 3030c8f6a362SSean Hefty ret = ib_sa_get_mcmember_rec(id_priv->id.device, id_priv->id.port_num, 3031c8f6a362SSean Hefty &rec.mgid, &rec); 3032c8f6a362SSean Hefty if (ret) 3033c8f6a362SSean Hefty return ret; 3034c8f6a362SSean Hefty 30353f446754SRoland Dreier cma_set_mgid(id_priv, (struct sockaddr *) &mc->addr, &rec.mgid); 3036c8f6a362SSean Hefty if (id_priv->id.ps == RDMA_PS_UDP) 3037c8f6a362SSean Hefty rec.qkey = cpu_to_be32(RDMA_UDP_QKEY); 30386f8372b6SSean Hefty rdma_addr_get_sgid(dev_addr, &rec.port_gid); 3039c8f6a362SSean Hefty rec.pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr)); 3040c8f6a362SSean Hefty rec.join_state = 1; 3041c8f6a362SSean Hefty 3042c8f6a362SSean Hefty comp_mask = IB_SA_MCMEMBER_REC_MGID | IB_SA_MCMEMBER_REC_PORT_GID | 3043c8f6a362SSean Hefty IB_SA_MCMEMBER_REC_PKEY | IB_SA_MCMEMBER_REC_JOIN_STATE | 3044c8f6a362SSean Hefty IB_SA_MCMEMBER_REC_QKEY | IB_SA_MCMEMBER_REC_SL | 3045c8f6a362SSean Hefty IB_SA_MCMEMBER_REC_FLOW_LABEL | 3046c8f6a362SSean Hefty IB_SA_MCMEMBER_REC_TRAFFIC_CLASS; 3047c8f6a362SSean Hefty 304884adeee9SYossi Etigin if (id_priv->id.ps == RDMA_PS_IPOIB) 304984adeee9SYossi Etigin comp_mask |= IB_SA_MCMEMBER_REC_RATE | 30502a22fb8cSDotan Barak IB_SA_MCMEMBER_REC_RATE_SELECTOR | 30512a22fb8cSDotan Barak IB_SA_MCMEMBER_REC_MTU_SELECTOR | 30522a22fb8cSDotan Barak IB_SA_MCMEMBER_REC_MTU | 30532a22fb8cSDotan Barak IB_SA_MCMEMBER_REC_HOP_LIMIT; 305484adeee9SYossi Etigin 3055c8f6a362SSean Hefty mc->multicast.ib = ib_sa_join_multicast(&sa_client, id_priv->id.device, 3056c8f6a362SSean Hefty id_priv->id.port_num, &rec, 3057c8f6a362SSean Hefty comp_mask, GFP_KERNEL, 3058c8f6a362SSean Hefty cma_ib_mc_handler, mc); 30594e289045SFengguang Wu return PTR_RET(mc->multicast.ib); 3060c8f6a362SSean Hefty } 3061c8f6a362SSean Hefty 30623c86aa70SEli Cohen static void iboe_mcast_work_handler(struct work_struct *work) 30633c86aa70SEli Cohen { 30643c86aa70SEli Cohen struct iboe_mcast_work *mw = container_of(work, struct iboe_mcast_work, work); 30653c86aa70SEli Cohen struct cma_multicast *mc = mw->mc; 30663c86aa70SEli Cohen struct ib_sa_multicast *m = mc->multicast.ib; 30673c86aa70SEli Cohen 30683c86aa70SEli Cohen mc->multicast.ib->context = mc; 30693c86aa70SEli Cohen cma_ib_mc_handler(0, m); 30703c86aa70SEli Cohen kref_put(&mc->mcref, release_mc); 30713c86aa70SEli Cohen kfree(mw); 30723c86aa70SEli Cohen } 30733c86aa70SEli Cohen 30743c86aa70SEli Cohen static void cma_iboe_set_mgid(struct sockaddr *addr, union ib_gid *mgid) 30753c86aa70SEli Cohen { 30763c86aa70SEli Cohen struct sockaddr_in *sin = (struct sockaddr_in *)addr; 30773c86aa70SEli Cohen struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr; 30783c86aa70SEli Cohen 30793c86aa70SEli Cohen if (cma_any_addr(addr)) { 30803c86aa70SEli Cohen memset(mgid, 0, sizeof *mgid); 30813c86aa70SEli Cohen } else if (addr->sa_family == AF_INET6) { 30823c86aa70SEli Cohen memcpy(mgid, &sin6->sin6_addr, sizeof *mgid); 30833c86aa70SEli Cohen } else { 30843c86aa70SEli Cohen mgid->raw[0] = 0xff; 30853c86aa70SEli Cohen mgid->raw[1] = 0x0e; 30863c86aa70SEli Cohen mgid->raw[2] = 0; 30873c86aa70SEli Cohen mgid->raw[3] = 0; 30883c86aa70SEli Cohen mgid->raw[4] = 0; 30893c86aa70SEli Cohen mgid->raw[5] = 0; 30903c86aa70SEli Cohen mgid->raw[6] = 0; 30913c86aa70SEli Cohen mgid->raw[7] = 0; 30923c86aa70SEli Cohen mgid->raw[8] = 0; 30933c86aa70SEli Cohen mgid->raw[9] = 0; 30943c86aa70SEli Cohen mgid->raw[10] = 0xff; 30953c86aa70SEli Cohen mgid->raw[11] = 0xff; 30963c86aa70SEli Cohen *(__be32 *)(&mgid->raw[12]) = sin->sin_addr.s_addr; 30973c86aa70SEli Cohen } 30983c86aa70SEli Cohen } 30993c86aa70SEli Cohen 31003c86aa70SEli Cohen static int cma_iboe_join_multicast(struct rdma_id_private *id_priv, 31013c86aa70SEli Cohen struct cma_multicast *mc) 31023c86aa70SEli Cohen { 31033c86aa70SEli Cohen struct iboe_mcast_work *work; 31043c86aa70SEli Cohen struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 31053c86aa70SEli Cohen int err; 31063c86aa70SEli Cohen struct sockaddr *addr = (struct sockaddr *)&mc->addr; 31073c86aa70SEli Cohen struct net_device *ndev = NULL; 31083c86aa70SEli Cohen 31093c86aa70SEli Cohen if (cma_zero_addr((struct sockaddr *)&mc->addr)) 31103c86aa70SEli Cohen return -EINVAL; 31113c86aa70SEli Cohen 31123c86aa70SEli Cohen work = kzalloc(sizeof *work, GFP_KERNEL); 31133c86aa70SEli Cohen if (!work) 31143c86aa70SEli Cohen return -ENOMEM; 31153c86aa70SEli Cohen 31163c86aa70SEli Cohen mc->multicast.ib = kzalloc(sizeof(struct ib_sa_multicast), GFP_KERNEL); 31173c86aa70SEli Cohen if (!mc->multicast.ib) { 31183c86aa70SEli Cohen err = -ENOMEM; 31193c86aa70SEli Cohen goto out1; 31203c86aa70SEli Cohen } 31213c86aa70SEli Cohen 31223c86aa70SEli Cohen cma_iboe_set_mgid(addr, &mc->multicast.ib->rec.mgid); 31233c86aa70SEli Cohen 31243c86aa70SEli Cohen mc->multicast.ib->rec.pkey = cpu_to_be16(0xffff); 31253c86aa70SEli Cohen if (id_priv->id.ps == RDMA_PS_UDP) 31263c86aa70SEli Cohen mc->multicast.ib->rec.qkey = cpu_to_be32(RDMA_UDP_QKEY); 31273c86aa70SEli Cohen 31283c86aa70SEli Cohen if (dev_addr->bound_dev_if) 31293c86aa70SEli Cohen ndev = dev_get_by_index(&init_net, dev_addr->bound_dev_if); 31303c86aa70SEli Cohen if (!ndev) { 31313c86aa70SEli Cohen err = -ENODEV; 31323c86aa70SEli Cohen goto out2; 31333c86aa70SEli Cohen } 31343c86aa70SEli Cohen mc->multicast.ib->rec.rate = iboe_get_rate(ndev); 31353c86aa70SEli Cohen mc->multicast.ib->rec.hop_limit = 1; 31363c86aa70SEli Cohen mc->multicast.ib->rec.mtu = iboe_get_mtu(ndev->mtu); 31373c86aa70SEli Cohen dev_put(ndev); 31383c86aa70SEli Cohen if (!mc->multicast.ib->rec.mtu) { 31393c86aa70SEli Cohen err = -EINVAL; 31403c86aa70SEli Cohen goto out2; 31413c86aa70SEli Cohen } 31423c86aa70SEli Cohen iboe_addr_get_sgid(dev_addr, &mc->multicast.ib->rec.port_gid); 31433c86aa70SEli Cohen work->id = id_priv; 31443c86aa70SEli Cohen work->mc = mc; 31453c86aa70SEli Cohen INIT_WORK(&work->work, iboe_mcast_work_handler); 31463c86aa70SEli Cohen kref_get(&mc->mcref); 31473c86aa70SEli Cohen queue_work(cma_wq, &work->work); 31483c86aa70SEli Cohen 31493c86aa70SEli Cohen return 0; 31503c86aa70SEli Cohen 31513c86aa70SEli Cohen out2: 31523c86aa70SEli Cohen kfree(mc->multicast.ib); 31533c86aa70SEli Cohen out1: 31543c86aa70SEli Cohen kfree(work); 31553c86aa70SEli Cohen return err; 31563c86aa70SEli Cohen } 31573c86aa70SEli Cohen 3158c8f6a362SSean Hefty int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr, 3159c8f6a362SSean Hefty void *context) 3160c8f6a362SSean Hefty { 3161c8f6a362SSean Hefty struct rdma_id_private *id_priv; 3162c8f6a362SSean Hefty struct cma_multicast *mc; 3163c8f6a362SSean Hefty int ret; 3164c8f6a362SSean Hefty 3165c8f6a362SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 3166550e5ca7SNir Muchtar if (!cma_comp(id_priv, RDMA_CM_ADDR_BOUND) && 3167550e5ca7SNir Muchtar !cma_comp(id_priv, RDMA_CM_ADDR_RESOLVED)) 3168c8f6a362SSean Hefty return -EINVAL; 3169c8f6a362SSean Hefty 3170c8f6a362SSean Hefty mc = kmalloc(sizeof *mc, GFP_KERNEL); 3171c8f6a362SSean Hefty if (!mc) 3172c8f6a362SSean Hefty return -ENOMEM; 3173c8f6a362SSean Hefty 3174c8f6a362SSean Hefty memcpy(&mc->addr, addr, ip_addr_size(addr)); 3175c8f6a362SSean Hefty mc->context = context; 3176c8f6a362SSean Hefty mc->id_priv = id_priv; 3177c8f6a362SSean Hefty 3178c8f6a362SSean Hefty spin_lock(&id_priv->lock); 3179c8f6a362SSean Hefty list_add(&mc->list, &id_priv->mc_list); 3180c8f6a362SSean Hefty spin_unlock(&id_priv->lock); 3181c8f6a362SSean Hefty 3182c8f6a362SSean Hefty switch (rdma_node_get_transport(id->device->node_type)) { 3183c8f6a362SSean Hefty case RDMA_TRANSPORT_IB: 31843c86aa70SEli Cohen switch (rdma_port_get_link_layer(id->device, id->port_num)) { 31853c86aa70SEli Cohen case IB_LINK_LAYER_INFINIBAND: 3186c8f6a362SSean Hefty ret = cma_join_ib_multicast(id_priv, mc); 3187c8f6a362SSean Hefty break; 31883c86aa70SEli Cohen case IB_LINK_LAYER_ETHERNET: 31893c86aa70SEli Cohen kref_init(&mc->mcref); 31903c86aa70SEli Cohen ret = cma_iboe_join_multicast(id_priv, mc); 31913c86aa70SEli Cohen break; 31923c86aa70SEli Cohen default: 31933c86aa70SEli Cohen ret = -EINVAL; 31943c86aa70SEli Cohen } 31953c86aa70SEli Cohen break; 3196c8f6a362SSean Hefty default: 3197c8f6a362SSean Hefty ret = -ENOSYS; 3198c8f6a362SSean Hefty break; 3199c8f6a362SSean Hefty } 3200c8f6a362SSean Hefty 3201c8f6a362SSean Hefty if (ret) { 3202c8f6a362SSean Hefty spin_lock_irq(&id_priv->lock); 3203c8f6a362SSean Hefty list_del(&mc->list); 3204c8f6a362SSean Hefty spin_unlock_irq(&id_priv->lock); 3205c8f6a362SSean Hefty kfree(mc); 3206c8f6a362SSean Hefty } 3207c8f6a362SSean Hefty return ret; 3208c8f6a362SSean Hefty } 3209c8f6a362SSean Hefty EXPORT_SYMBOL(rdma_join_multicast); 3210c8f6a362SSean Hefty 3211c8f6a362SSean Hefty void rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr) 3212c8f6a362SSean Hefty { 3213c8f6a362SSean Hefty struct rdma_id_private *id_priv; 3214c8f6a362SSean Hefty struct cma_multicast *mc; 3215c8f6a362SSean Hefty 3216c8f6a362SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 3217c8f6a362SSean Hefty spin_lock_irq(&id_priv->lock); 3218c8f6a362SSean Hefty list_for_each_entry(mc, &id_priv->mc_list, list) { 3219c8f6a362SSean Hefty if (!memcmp(&mc->addr, addr, ip_addr_size(addr))) { 3220c8f6a362SSean Hefty list_del(&mc->list); 3221c8f6a362SSean Hefty spin_unlock_irq(&id_priv->lock); 3222c8f6a362SSean Hefty 3223c8f6a362SSean Hefty if (id->qp) 3224c8f6a362SSean Hefty ib_detach_mcast(id->qp, 3225c8f6a362SSean Hefty &mc->multicast.ib->rec.mgid, 322646ea5061SSean Hefty be16_to_cpu(mc->multicast.ib->rec.mlid)); 32273c86aa70SEli Cohen if (rdma_node_get_transport(id_priv->cma_dev->device->node_type) == RDMA_TRANSPORT_IB) { 32283c86aa70SEli Cohen switch (rdma_port_get_link_layer(id->device, id->port_num)) { 32293c86aa70SEli Cohen case IB_LINK_LAYER_INFINIBAND: 3230c8f6a362SSean Hefty ib_sa_free_multicast(mc->multicast.ib); 3231c8f6a362SSean Hefty kfree(mc); 32323c86aa70SEli Cohen break; 32333c86aa70SEli Cohen case IB_LINK_LAYER_ETHERNET: 32343c86aa70SEli Cohen kref_put(&mc->mcref, release_mc); 32353c86aa70SEli Cohen break; 32363c86aa70SEli Cohen default: 32373c86aa70SEli Cohen break; 32383c86aa70SEli Cohen } 32393c86aa70SEli Cohen } 3240c8f6a362SSean Hefty return; 3241c8f6a362SSean Hefty } 3242c8f6a362SSean Hefty } 3243c8f6a362SSean Hefty spin_unlock_irq(&id_priv->lock); 3244c8f6a362SSean Hefty } 3245c8f6a362SSean Hefty EXPORT_SYMBOL(rdma_leave_multicast); 3246c8f6a362SSean Hefty 3247dd5bdff8SOr Gerlitz static int cma_netdev_change(struct net_device *ndev, struct rdma_id_private *id_priv) 3248dd5bdff8SOr Gerlitz { 3249dd5bdff8SOr Gerlitz struct rdma_dev_addr *dev_addr; 3250dd5bdff8SOr Gerlitz struct cma_ndev_work *work; 3251dd5bdff8SOr Gerlitz 3252dd5bdff8SOr Gerlitz dev_addr = &id_priv->id.route.addr.dev_addr; 3253dd5bdff8SOr Gerlitz 32546266ed6eSSean Hefty if ((dev_addr->bound_dev_if == ndev->ifindex) && 3255dd5bdff8SOr Gerlitz memcmp(dev_addr->src_dev_addr, ndev->dev_addr, ndev->addr_len)) { 3256dd5bdff8SOr Gerlitz printk(KERN_INFO "RDMA CM addr change for ndev %s used by id %p\n", 3257dd5bdff8SOr Gerlitz ndev->name, &id_priv->id); 3258dd5bdff8SOr Gerlitz work = kzalloc(sizeof *work, GFP_KERNEL); 3259dd5bdff8SOr Gerlitz if (!work) 3260dd5bdff8SOr Gerlitz return -ENOMEM; 3261dd5bdff8SOr Gerlitz 3262dd5bdff8SOr Gerlitz INIT_WORK(&work->work, cma_ndev_work_handler); 3263dd5bdff8SOr Gerlitz work->id = id_priv; 3264dd5bdff8SOr Gerlitz work->event.event = RDMA_CM_EVENT_ADDR_CHANGE; 3265dd5bdff8SOr Gerlitz atomic_inc(&id_priv->refcount); 3266dd5bdff8SOr Gerlitz queue_work(cma_wq, &work->work); 3267dd5bdff8SOr Gerlitz } 3268dd5bdff8SOr Gerlitz 3269dd5bdff8SOr Gerlitz return 0; 3270dd5bdff8SOr Gerlitz } 3271dd5bdff8SOr Gerlitz 3272dd5bdff8SOr Gerlitz static int cma_netdev_callback(struct notifier_block *self, unsigned long event, 3273dd5bdff8SOr Gerlitz void *ctx) 3274dd5bdff8SOr Gerlitz { 3275dd5bdff8SOr Gerlitz struct net_device *ndev = (struct net_device *)ctx; 3276dd5bdff8SOr Gerlitz struct cma_device *cma_dev; 3277dd5bdff8SOr Gerlitz struct rdma_id_private *id_priv; 3278dd5bdff8SOr Gerlitz int ret = NOTIFY_DONE; 3279dd5bdff8SOr Gerlitz 3280dd5bdff8SOr Gerlitz if (dev_net(ndev) != &init_net) 3281dd5bdff8SOr Gerlitz return NOTIFY_DONE; 3282dd5bdff8SOr Gerlitz 3283dd5bdff8SOr Gerlitz if (event != NETDEV_BONDING_FAILOVER) 3284dd5bdff8SOr Gerlitz return NOTIFY_DONE; 3285dd5bdff8SOr Gerlitz 3286dd5bdff8SOr Gerlitz if (!(ndev->flags & IFF_MASTER) || !(ndev->priv_flags & IFF_BONDING)) 3287dd5bdff8SOr Gerlitz return NOTIFY_DONE; 3288dd5bdff8SOr Gerlitz 3289dd5bdff8SOr Gerlitz mutex_lock(&lock); 3290dd5bdff8SOr Gerlitz list_for_each_entry(cma_dev, &dev_list, list) 3291dd5bdff8SOr Gerlitz list_for_each_entry(id_priv, &cma_dev->id_list, list) { 3292dd5bdff8SOr Gerlitz ret = cma_netdev_change(ndev, id_priv); 3293dd5bdff8SOr Gerlitz if (ret) 3294dd5bdff8SOr Gerlitz goto out; 3295dd5bdff8SOr Gerlitz } 3296dd5bdff8SOr Gerlitz 3297dd5bdff8SOr Gerlitz out: 3298dd5bdff8SOr Gerlitz mutex_unlock(&lock); 3299dd5bdff8SOr Gerlitz return ret; 3300dd5bdff8SOr Gerlitz } 3301dd5bdff8SOr Gerlitz 3302dd5bdff8SOr Gerlitz static struct notifier_block cma_nb = { 3303dd5bdff8SOr Gerlitz .notifier_call = cma_netdev_callback 3304dd5bdff8SOr Gerlitz }; 3305dd5bdff8SOr Gerlitz 3306e51060f0SSean Hefty static void cma_add_one(struct ib_device *device) 3307e51060f0SSean Hefty { 3308e51060f0SSean Hefty struct cma_device *cma_dev; 3309e51060f0SSean Hefty struct rdma_id_private *id_priv; 3310e51060f0SSean Hefty 3311e51060f0SSean Hefty cma_dev = kmalloc(sizeof *cma_dev, GFP_KERNEL); 3312e51060f0SSean Hefty if (!cma_dev) 3313e51060f0SSean Hefty return; 3314e51060f0SSean Hefty 3315e51060f0SSean Hefty cma_dev->device = device; 3316e51060f0SSean Hefty 3317e51060f0SSean Hefty init_completion(&cma_dev->comp); 3318e51060f0SSean Hefty atomic_set(&cma_dev->refcount, 1); 3319e51060f0SSean Hefty INIT_LIST_HEAD(&cma_dev->id_list); 3320e51060f0SSean Hefty ib_set_client_data(device, &cma_client, cma_dev); 3321e51060f0SSean Hefty 3322e51060f0SSean Hefty mutex_lock(&lock); 3323e51060f0SSean Hefty list_add_tail(&cma_dev->list, &dev_list); 3324e51060f0SSean Hefty list_for_each_entry(id_priv, &listen_any_list, list) 3325e51060f0SSean Hefty cma_listen_on_dev(id_priv, cma_dev); 3326e51060f0SSean Hefty mutex_unlock(&lock); 3327e51060f0SSean Hefty } 3328e51060f0SSean Hefty 3329e51060f0SSean Hefty static int cma_remove_id_dev(struct rdma_id_private *id_priv) 3330e51060f0SSean Hefty { 3331a1b1b61fSSean Hefty struct rdma_cm_event event; 3332550e5ca7SNir Muchtar enum rdma_cm_state state; 3333de910bd9SOr Gerlitz int ret = 0; 3334e51060f0SSean Hefty 3335e51060f0SSean Hefty /* Record that we want to remove the device */ 3336550e5ca7SNir Muchtar state = cma_exch(id_priv, RDMA_CM_DEVICE_REMOVAL); 3337550e5ca7SNir Muchtar if (state == RDMA_CM_DESTROYING) 3338e51060f0SSean Hefty return 0; 3339e51060f0SSean Hefty 3340e51060f0SSean Hefty cma_cancel_operation(id_priv, state); 3341de910bd9SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 3342e51060f0SSean Hefty 3343e51060f0SSean Hefty /* Check for destruction from another callback. */ 3344550e5ca7SNir Muchtar if (!cma_comp(id_priv, RDMA_CM_DEVICE_REMOVAL)) 3345de910bd9SOr Gerlitz goto out; 3346e51060f0SSean Hefty 3347a1b1b61fSSean Hefty memset(&event, 0, sizeof event); 3348a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_DEVICE_REMOVAL; 3349de910bd9SOr Gerlitz ret = id_priv->id.event_handler(&id_priv->id, &event); 3350de910bd9SOr Gerlitz out: 3351de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 3352de910bd9SOr Gerlitz return ret; 3353e51060f0SSean Hefty } 3354e51060f0SSean Hefty 3355e51060f0SSean Hefty static void cma_process_remove(struct cma_device *cma_dev) 3356e51060f0SSean Hefty { 3357e51060f0SSean Hefty struct rdma_id_private *id_priv; 3358e51060f0SSean Hefty int ret; 3359e51060f0SSean Hefty 3360e51060f0SSean Hefty mutex_lock(&lock); 3361e51060f0SSean Hefty while (!list_empty(&cma_dev->id_list)) { 3362e51060f0SSean Hefty id_priv = list_entry(cma_dev->id_list.next, 3363e51060f0SSean Hefty struct rdma_id_private, list); 3364e51060f0SSean Hefty 3365d02d1f53SSean Hefty list_del(&id_priv->listen_list); 336694de178aSKrishna Kumar list_del_init(&id_priv->list); 3367e51060f0SSean Hefty atomic_inc(&id_priv->refcount); 3368e51060f0SSean Hefty mutex_unlock(&lock); 3369e51060f0SSean Hefty 3370d02d1f53SSean Hefty ret = id_priv->internal_id ? 1 : cma_remove_id_dev(id_priv); 3371e51060f0SSean Hefty cma_deref_id(id_priv); 3372e51060f0SSean Hefty if (ret) 3373e51060f0SSean Hefty rdma_destroy_id(&id_priv->id); 3374e51060f0SSean Hefty 3375e51060f0SSean Hefty mutex_lock(&lock); 3376e51060f0SSean Hefty } 3377e51060f0SSean Hefty mutex_unlock(&lock); 3378e51060f0SSean Hefty 3379e51060f0SSean Hefty cma_deref_dev(cma_dev); 3380e51060f0SSean Hefty wait_for_completion(&cma_dev->comp); 3381e51060f0SSean Hefty } 3382e51060f0SSean Hefty 3383e51060f0SSean Hefty static void cma_remove_one(struct ib_device *device) 3384e51060f0SSean Hefty { 3385e51060f0SSean Hefty struct cma_device *cma_dev; 3386e51060f0SSean Hefty 3387e51060f0SSean Hefty cma_dev = ib_get_client_data(device, &cma_client); 3388e51060f0SSean Hefty if (!cma_dev) 3389e51060f0SSean Hefty return; 3390e51060f0SSean Hefty 3391e51060f0SSean Hefty mutex_lock(&lock); 3392e51060f0SSean Hefty list_del(&cma_dev->list); 3393e51060f0SSean Hefty mutex_unlock(&lock); 3394e51060f0SSean Hefty 3395e51060f0SSean Hefty cma_process_remove(cma_dev); 3396e51060f0SSean Hefty kfree(cma_dev); 3397e51060f0SSean Hefty } 3398e51060f0SSean Hefty 3399753f618aSNir Muchtar static int cma_get_id_stats(struct sk_buff *skb, struct netlink_callback *cb) 3400753f618aSNir Muchtar { 3401753f618aSNir Muchtar struct nlmsghdr *nlh; 3402753f618aSNir Muchtar struct rdma_cm_id_stats *id_stats; 3403753f618aSNir Muchtar struct rdma_id_private *id_priv; 3404753f618aSNir Muchtar struct rdma_cm_id *id = NULL; 3405753f618aSNir Muchtar struct cma_device *cma_dev; 3406753f618aSNir Muchtar int i_dev = 0, i_id = 0; 3407753f618aSNir Muchtar 3408753f618aSNir Muchtar /* 3409753f618aSNir Muchtar * We export all of the IDs as a sequence of messages. Each 3410753f618aSNir Muchtar * ID gets its own netlink message. 3411753f618aSNir Muchtar */ 3412753f618aSNir Muchtar mutex_lock(&lock); 3413753f618aSNir Muchtar 3414753f618aSNir Muchtar list_for_each_entry(cma_dev, &dev_list, list) { 3415753f618aSNir Muchtar if (i_dev < cb->args[0]) { 3416753f618aSNir Muchtar i_dev++; 3417753f618aSNir Muchtar continue; 3418753f618aSNir Muchtar } 3419753f618aSNir Muchtar 3420753f618aSNir Muchtar i_id = 0; 3421753f618aSNir Muchtar list_for_each_entry(id_priv, &cma_dev->id_list, list) { 3422753f618aSNir Muchtar if (i_id < cb->args[1]) { 3423753f618aSNir Muchtar i_id++; 3424753f618aSNir Muchtar continue; 3425753f618aSNir Muchtar } 3426753f618aSNir Muchtar 3427753f618aSNir Muchtar id_stats = ibnl_put_msg(skb, &nlh, cb->nlh->nlmsg_seq, 3428753f618aSNir Muchtar sizeof *id_stats, RDMA_NL_RDMA_CM, 3429753f618aSNir Muchtar RDMA_NL_RDMA_CM_ID_STATS); 3430753f618aSNir Muchtar if (!id_stats) 3431753f618aSNir Muchtar goto out; 3432753f618aSNir Muchtar 3433753f618aSNir Muchtar memset(id_stats, 0, sizeof *id_stats); 3434753f618aSNir Muchtar id = &id_priv->id; 3435753f618aSNir Muchtar id_stats->node_type = id->route.addr.dev_addr.dev_type; 3436753f618aSNir Muchtar id_stats->port_num = id->port_num; 3437753f618aSNir Muchtar id_stats->bound_dev_if = 3438753f618aSNir Muchtar id->route.addr.dev_addr.bound_dev_if; 3439753f618aSNir Muchtar 3440753f618aSNir Muchtar if (id->route.addr.src_addr.ss_family == AF_INET) { 3441753f618aSNir Muchtar if (ibnl_put_attr(skb, nlh, 3442753f618aSNir Muchtar sizeof(struct sockaddr_in), 3443753f618aSNir Muchtar &id->route.addr.src_addr, 3444753f618aSNir Muchtar RDMA_NL_RDMA_CM_ATTR_SRC_ADDR)) { 3445753f618aSNir Muchtar goto out; 3446753f618aSNir Muchtar } 3447753f618aSNir Muchtar if (ibnl_put_attr(skb, nlh, 3448753f618aSNir Muchtar sizeof(struct sockaddr_in), 3449753f618aSNir Muchtar &id->route.addr.dst_addr, 3450753f618aSNir Muchtar RDMA_NL_RDMA_CM_ATTR_DST_ADDR)) { 3451753f618aSNir Muchtar goto out; 3452753f618aSNir Muchtar } 3453753f618aSNir Muchtar } else if (id->route.addr.src_addr.ss_family == AF_INET6) { 3454753f618aSNir Muchtar if (ibnl_put_attr(skb, nlh, 3455753f618aSNir Muchtar sizeof(struct sockaddr_in6), 3456753f618aSNir Muchtar &id->route.addr.src_addr, 3457753f618aSNir Muchtar RDMA_NL_RDMA_CM_ATTR_SRC_ADDR)) { 3458753f618aSNir Muchtar goto out; 3459753f618aSNir Muchtar } 3460753f618aSNir Muchtar if (ibnl_put_attr(skb, nlh, 3461753f618aSNir Muchtar sizeof(struct sockaddr_in6), 3462753f618aSNir Muchtar &id->route.addr.dst_addr, 3463753f618aSNir Muchtar RDMA_NL_RDMA_CM_ATTR_DST_ADDR)) { 3464753f618aSNir Muchtar goto out; 3465753f618aSNir Muchtar } 3466753f618aSNir Muchtar } 3467753f618aSNir Muchtar 346883e9502dSNir Muchtar id_stats->pid = id_priv->owner; 3469753f618aSNir Muchtar id_stats->port_space = id->ps; 3470753f618aSNir Muchtar id_stats->cm_state = id_priv->state; 3471753f618aSNir Muchtar id_stats->qp_num = id_priv->qp_num; 3472753f618aSNir Muchtar id_stats->qp_type = id->qp_type; 3473753f618aSNir Muchtar 3474753f618aSNir Muchtar i_id++; 3475753f618aSNir Muchtar } 3476753f618aSNir Muchtar 3477753f618aSNir Muchtar cb->args[1] = 0; 3478753f618aSNir Muchtar i_dev++; 3479753f618aSNir Muchtar } 3480753f618aSNir Muchtar 3481753f618aSNir Muchtar out: 3482753f618aSNir Muchtar mutex_unlock(&lock); 3483753f618aSNir Muchtar cb->args[0] = i_dev; 3484753f618aSNir Muchtar cb->args[1] = i_id; 3485753f618aSNir Muchtar 3486753f618aSNir Muchtar return skb->len; 3487753f618aSNir Muchtar } 3488753f618aSNir Muchtar 3489753f618aSNir Muchtar static const struct ibnl_client_cbs cma_cb_table[] = { 3490809d5fc9SGao feng [RDMA_NL_RDMA_CM_ID_STATS] = { .dump = cma_get_id_stats, 3491809d5fc9SGao feng .module = THIS_MODULE }, 3492753f618aSNir Muchtar }; 3493753f618aSNir Muchtar 3494716abb1fSPeter Huewe static int __init cma_init(void) 3495e51060f0SSean Hefty { 34965d7220e8STetsuo Handa int ret; 3497227b60f5SStephen Hemminger 3498c7f743a6SSean Hefty cma_wq = create_singlethread_workqueue("rdma_cm"); 3499e51060f0SSean Hefty if (!cma_wq) 3500e51060f0SSean Hefty return -ENOMEM; 3501e51060f0SSean Hefty 3502c1a0b23bSMichael S. Tsirkin ib_sa_register_client(&sa_client); 35037a118df3SSean Hefty rdma_addr_register_client(&addr_client); 3504dd5bdff8SOr Gerlitz register_netdevice_notifier(&cma_nb); 3505c1a0b23bSMichael S. Tsirkin 3506e51060f0SSean Hefty ret = ib_register_client(&cma_client); 3507e51060f0SSean Hefty if (ret) 3508e51060f0SSean Hefty goto err; 3509753f618aSNir Muchtar 3510753f618aSNir Muchtar if (ibnl_add_client(RDMA_NL_RDMA_CM, RDMA_NL_RDMA_CM_NUM_OPS, cma_cb_table)) 3511753f618aSNir Muchtar printk(KERN_WARNING "RDMA CMA: failed to add netlink callback\n"); 3512753f618aSNir Muchtar 3513e51060f0SSean Hefty return 0; 3514e51060f0SSean Hefty 3515e51060f0SSean Hefty err: 3516dd5bdff8SOr Gerlitz unregister_netdevice_notifier(&cma_nb); 35177a118df3SSean Hefty rdma_addr_unregister_client(&addr_client); 3518c1a0b23bSMichael S. Tsirkin ib_sa_unregister_client(&sa_client); 3519e51060f0SSean Hefty destroy_workqueue(cma_wq); 3520e51060f0SSean Hefty return ret; 3521e51060f0SSean Hefty } 3522e51060f0SSean Hefty 3523716abb1fSPeter Huewe static void __exit cma_cleanup(void) 3524e51060f0SSean Hefty { 3525753f618aSNir Muchtar ibnl_remove_client(RDMA_NL_RDMA_CM); 3526e51060f0SSean Hefty ib_unregister_client(&cma_client); 3527dd5bdff8SOr Gerlitz unregister_netdevice_notifier(&cma_nb); 35287a118df3SSean Hefty rdma_addr_unregister_client(&addr_client); 3529c1a0b23bSMichael S. Tsirkin ib_sa_unregister_client(&sa_client); 3530e51060f0SSean Hefty destroy_workqueue(cma_wq); 3531e51060f0SSean Hefty idr_destroy(&sdp_ps); 3532e51060f0SSean Hefty idr_destroy(&tcp_ps); 3533628e5f6dSSean Hefty idr_destroy(&udp_ps); 3534c8f6a362SSean Hefty idr_destroy(&ipoib_ps); 35352d2e9415SSean Hefty idr_destroy(&ib_ps); 3536e51060f0SSean Hefty } 3537e51060f0SSean Hefty 3538e51060f0SSean Hefty module_init(cma_init); 3539e51060f0SSean Hefty module_exit(cma_cleanup); 3540