xref: /linux/drivers/infiniband/core/cma.c (revision 2efdd6a038b2d72e74deb8d4725db1663135268c)
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>
44e51060f0SSean Hefty 
45e51060f0SSean Hefty #include <net/tcp.h>
461f5175adSAleksey Senin #include <net/ipv6.h>
47e51060f0SSean Hefty 
48e51060f0SSean Hefty #include <rdma/rdma_cm.h>
49e51060f0SSean Hefty #include <rdma/rdma_cm_ib.h>
50753f618aSNir Muchtar #include <rdma/rdma_netlink.h>
51e51060f0SSean Hefty #include <rdma/ib_cache.h>
52e51060f0SSean Hefty #include <rdma/ib_cm.h>
53e51060f0SSean Hefty #include <rdma/ib_sa.h>
5407ebafbaSTom Tucker #include <rdma/iw_cm.h>
55e51060f0SSean Hefty 
56e51060f0SSean Hefty MODULE_AUTHOR("Sean Hefty");
57e51060f0SSean Hefty MODULE_DESCRIPTION("Generic RDMA CM Agent");
58e51060f0SSean Hefty MODULE_LICENSE("Dual BSD/GPL");
59e51060f0SSean Hefty 
60e51060f0SSean Hefty #define CMA_CM_RESPONSE_TIMEOUT 20
61d5bb7599SMichael S. Tsirkin #define CMA_MAX_CM_RETRIES 15
62dcb3f974SSean Hefty #define CMA_CM_MRA_SETTING (IB_CM_MRA_FLAG_DELAY | 24)
633c86aa70SEli Cohen #define CMA_IBOE_PACKET_LIFETIME 18
64e51060f0SSean Hefty 
65e51060f0SSean Hefty static void cma_add_one(struct ib_device *device);
66e51060f0SSean Hefty static void cma_remove_one(struct ib_device *device);
67e51060f0SSean Hefty 
68e51060f0SSean Hefty static struct ib_client cma_client = {
69e51060f0SSean Hefty 	.name   = "cma",
70e51060f0SSean Hefty 	.add    = cma_add_one,
71e51060f0SSean Hefty 	.remove = cma_remove_one
72e51060f0SSean Hefty };
73e51060f0SSean Hefty 
74c1a0b23bSMichael S. Tsirkin static struct ib_sa_client sa_client;
757a118df3SSean Hefty static struct rdma_addr_client addr_client;
76e51060f0SSean Hefty static LIST_HEAD(dev_list);
77e51060f0SSean Hefty static LIST_HEAD(listen_any_list);
78e51060f0SSean Hefty static DEFINE_MUTEX(lock);
79e51060f0SSean Hefty static struct workqueue_struct *cma_wq;
80e51060f0SSean Hefty static DEFINE_IDR(sdp_ps);
81e51060f0SSean Hefty static DEFINE_IDR(tcp_ps);
82628e5f6dSSean Hefty static DEFINE_IDR(udp_ps);
83c8f6a362SSean Hefty static DEFINE_IDR(ipoib_ps);
84e51060f0SSean Hefty 
85e51060f0SSean Hefty struct cma_device {
86e51060f0SSean Hefty 	struct list_head	list;
87e51060f0SSean Hefty 	struct ib_device	*device;
88e51060f0SSean Hefty 	struct completion	comp;
89e51060f0SSean Hefty 	atomic_t		refcount;
90e51060f0SSean Hefty 	struct list_head	id_list;
91e51060f0SSean Hefty };
92e51060f0SSean Hefty 
93e51060f0SSean Hefty struct rdma_bind_list {
94e51060f0SSean Hefty 	struct idr		*ps;
95e51060f0SSean Hefty 	struct hlist_head	owners;
96e51060f0SSean Hefty 	unsigned short		port;
97e51060f0SSean Hefty };
98e51060f0SSean Hefty 
99e51060f0SSean Hefty /*
100e51060f0SSean Hefty  * Device removal can occur at anytime, so we need extra handling to
101e51060f0SSean Hefty  * serialize notifying the user of device removal with other callbacks.
102e51060f0SSean Hefty  * We do this by disabling removal notification while a callback is in process,
103e51060f0SSean Hefty  * and reporting it after the callback completes.
104e51060f0SSean Hefty  */
105e51060f0SSean Hefty struct rdma_id_private {
106e51060f0SSean Hefty 	struct rdma_cm_id	id;
107e51060f0SSean Hefty 
108e51060f0SSean Hefty 	struct rdma_bind_list	*bind_list;
109e51060f0SSean Hefty 	struct hlist_node	node;
110d02d1f53SSean Hefty 	struct list_head	list; /* listen_any_list or cma_device.list */
111d02d1f53SSean Hefty 	struct list_head	listen_list; /* per device listens */
112e51060f0SSean Hefty 	struct cma_device	*cma_dev;
113c8f6a362SSean Hefty 	struct list_head	mc_list;
114e51060f0SSean Hefty 
115d02d1f53SSean Hefty 	int			internal_id;
116550e5ca7SNir Muchtar 	enum rdma_cm_state	state;
117e51060f0SSean Hefty 	spinlock_t		lock;
118c5483388SSean Hefty 	struct mutex		qp_mutex;
119c5483388SSean Hefty 
120e51060f0SSean Hefty 	struct completion	comp;
121e51060f0SSean Hefty 	atomic_t		refcount;
122de910bd9SOr Gerlitz 	struct mutex		handler_mutex;
123e51060f0SSean Hefty 
124e51060f0SSean Hefty 	int			backlog;
125e51060f0SSean Hefty 	int			timeout_ms;
126e51060f0SSean Hefty 	struct ib_sa_query	*query;
127e51060f0SSean Hefty 	int			query_id;
128e51060f0SSean Hefty 	union {
129e51060f0SSean Hefty 		struct ib_cm_id	*ib;
13007ebafbaSTom Tucker 		struct iw_cm_id	*iw;
131e51060f0SSean Hefty 	} cm_id;
132e51060f0SSean Hefty 
133e51060f0SSean Hefty 	u32			seq_num;
134c8f6a362SSean Hefty 	u32			qkey;
135e51060f0SSean Hefty 	u32			qp_num;
13683e9502dSNir Muchtar 	pid_t			owner;
137e51060f0SSean Hefty 	u8			srq;
138a81c994dSSean Hefty 	u8			tos;
139a9bb7912SHefty, Sean 	u8			reuseaddr;
140e51060f0SSean Hefty };
141e51060f0SSean Hefty 
142c8f6a362SSean Hefty struct cma_multicast {
143c8f6a362SSean Hefty 	struct rdma_id_private *id_priv;
144c8f6a362SSean Hefty 	union {
145c8f6a362SSean Hefty 		struct ib_sa_multicast *ib;
146c8f6a362SSean Hefty 	} multicast;
147c8f6a362SSean Hefty 	struct list_head	list;
148c8f6a362SSean Hefty 	void			*context;
1493f446754SRoland Dreier 	struct sockaddr_storage	addr;
1503c86aa70SEli Cohen 	struct kref		mcref;
151c8f6a362SSean Hefty };
152c8f6a362SSean Hefty 
153e51060f0SSean Hefty struct cma_work {
154e51060f0SSean Hefty 	struct work_struct	work;
155e51060f0SSean Hefty 	struct rdma_id_private	*id;
156550e5ca7SNir Muchtar 	enum rdma_cm_state	old_state;
157550e5ca7SNir Muchtar 	enum rdma_cm_state	new_state;
158e51060f0SSean Hefty 	struct rdma_cm_event	event;
159e51060f0SSean Hefty };
160e51060f0SSean Hefty 
161dd5bdff8SOr Gerlitz struct cma_ndev_work {
162dd5bdff8SOr Gerlitz 	struct work_struct	work;
163dd5bdff8SOr Gerlitz 	struct rdma_id_private	*id;
164dd5bdff8SOr Gerlitz 	struct rdma_cm_event	event;
165dd5bdff8SOr Gerlitz };
166dd5bdff8SOr Gerlitz 
1673c86aa70SEli Cohen struct iboe_mcast_work {
1683c86aa70SEli Cohen 	struct work_struct	 work;
1693c86aa70SEli Cohen 	struct rdma_id_private	*id;
1703c86aa70SEli Cohen 	struct cma_multicast	*mc;
1713c86aa70SEli Cohen };
1723c86aa70SEli Cohen 
173e51060f0SSean Hefty union cma_ip_addr {
174e51060f0SSean Hefty 	struct in6_addr ip6;
175e51060f0SSean Hefty 	struct {
1761b90c137SAl Viro 		__be32 pad[3];
1771b90c137SAl Viro 		__be32 addr;
178e51060f0SSean Hefty 	} ip4;
179e51060f0SSean Hefty };
180e51060f0SSean Hefty 
181e51060f0SSean Hefty struct cma_hdr {
182e51060f0SSean Hefty 	u8 cma_version;
183e51060f0SSean Hefty 	u8 ip_version;	/* IP version: 7:4 */
1841b90c137SAl Viro 	__be16 port;
185e51060f0SSean Hefty 	union cma_ip_addr src_addr;
186e51060f0SSean Hefty 	union cma_ip_addr dst_addr;
187e51060f0SSean Hefty };
188e51060f0SSean Hefty 
189e51060f0SSean Hefty struct sdp_hh {
190e51060f0SSean Hefty 	u8 bsdh[16];
191e51060f0SSean Hefty 	u8 sdp_version; /* Major version: 7:4 */
192e51060f0SSean Hefty 	u8 ip_version;	/* IP version: 7:4 */
193e51060f0SSean Hefty 	u8 sdp_specific1[10];
1941b90c137SAl Viro 	__be16 port;
1951b90c137SAl Viro 	__be16 sdp_specific2;
196e51060f0SSean Hefty 	union cma_ip_addr src_addr;
197e51060f0SSean Hefty 	union cma_ip_addr dst_addr;
198e51060f0SSean Hefty };
199e51060f0SSean Hefty 
200e51060f0SSean Hefty struct sdp_hah {
201e51060f0SSean Hefty 	u8 bsdh[16];
202e51060f0SSean Hefty 	u8 sdp_version;
203e51060f0SSean Hefty };
204e51060f0SSean Hefty 
205e51060f0SSean Hefty #define CMA_VERSION 0x00
206e51060f0SSean Hefty #define SDP_MAJ_VERSION 0x2
207e51060f0SSean Hefty 
208550e5ca7SNir Muchtar static int cma_comp(struct rdma_id_private *id_priv, enum rdma_cm_state comp)
209e51060f0SSean Hefty {
210e51060f0SSean Hefty 	unsigned long flags;
211e51060f0SSean Hefty 	int ret;
212e51060f0SSean Hefty 
213e51060f0SSean Hefty 	spin_lock_irqsave(&id_priv->lock, flags);
214e51060f0SSean Hefty 	ret = (id_priv->state == comp);
215e51060f0SSean Hefty 	spin_unlock_irqrestore(&id_priv->lock, flags);
216e51060f0SSean Hefty 	return ret;
217e51060f0SSean Hefty }
218e51060f0SSean Hefty 
219e51060f0SSean Hefty static int cma_comp_exch(struct rdma_id_private *id_priv,
220550e5ca7SNir Muchtar 			 enum rdma_cm_state comp, enum rdma_cm_state exch)
221e51060f0SSean Hefty {
222e51060f0SSean Hefty 	unsigned long flags;
223e51060f0SSean Hefty 	int ret;
224e51060f0SSean Hefty 
225e51060f0SSean Hefty 	spin_lock_irqsave(&id_priv->lock, flags);
226e51060f0SSean Hefty 	if ((ret = (id_priv->state == comp)))
227e51060f0SSean Hefty 		id_priv->state = exch;
228e51060f0SSean Hefty 	spin_unlock_irqrestore(&id_priv->lock, flags);
229e51060f0SSean Hefty 	return ret;
230e51060f0SSean Hefty }
231e51060f0SSean Hefty 
232550e5ca7SNir Muchtar static enum rdma_cm_state cma_exch(struct rdma_id_private *id_priv,
233550e5ca7SNir Muchtar 				   enum rdma_cm_state exch)
234e51060f0SSean Hefty {
235e51060f0SSean Hefty 	unsigned long flags;
236550e5ca7SNir Muchtar 	enum rdma_cm_state old;
237e51060f0SSean Hefty 
238e51060f0SSean Hefty 	spin_lock_irqsave(&id_priv->lock, flags);
239e51060f0SSean Hefty 	old = id_priv->state;
240e51060f0SSean Hefty 	id_priv->state = exch;
241e51060f0SSean Hefty 	spin_unlock_irqrestore(&id_priv->lock, flags);
242e51060f0SSean Hefty 	return old;
243e51060f0SSean Hefty }
244e51060f0SSean Hefty 
245e51060f0SSean Hefty static inline u8 cma_get_ip_ver(struct cma_hdr *hdr)
246e51060f0SSean Hefty {
247e51060f0SSean Hefty 	return hdr->ip_version >> 4;
248e51060f0SSean Hefty }
249e51060f0SSean Hefty 
250e51060f0SSean Hefty static inline void cma_set_ip_ver(struct cma_hdr *hdr, u8 ip_ver)
251e51060f0SSean Hefty {
252e51060f0SSean Hefty 	hdr->ip_version = (ip_ver << 4) | (hdr->ip_version & 0xF);
253e51060f0SSean Hefty }
254e51060f0SSean Hefty 
255e51060f0SSean Hefty static inline u8 sdp_get_majv(u8 sdp_version)
256e51060f0SSean Hefty {
257e51060f0SSean Hefty 	return sdp_version >> 4;
258e51060f0SSean Hefty }
259e51060f0SSean Hefty 
260e51060f0SSean Hefty static inline u8 sdp_get_ip_ver(struct sdp_hh *hh)
261e51060f0SSean Hefty {
262e51060f0SSean Hefty 	return hh->ip_version >> 4;
263e51060f0SSean Hefty }
264e51060f0SSean Hefty 
265e51060f0SSean Hefty static inline void sdp_set_ip_ver(struct sdp_hh *hh, u8 ip_ver)
266e51060f0SSean Hefty {
267e51060f0SSean Hefty 	hh->ip_version = (ip_ver << 4) | (hh->ip_version & 0xF);
268e51060f0SSean Hefty }
269e51060f0SSean Hefty 
270e51060f0SSean Hefty static void cma_attach_to_dev(struct rdma_id_private *id_priv,
271e51060f0SSean Hefty 			      struct cma_device *cma_dev)
272e51060f0SSean Hefty {
273e51060f0SSean Hefty 	atomic_inc(&cma_dev->refcount);
274e51060f0SSean Hefty 	id_priv->cma_dev = cma_dev;
275e51060f0SSean Hefty 	id_priv->id.device = cma_dev->device;
2763c86aa70SEli Cohen 	id_priv->id.route.addr.dev_addr.transport =
2773c86aa70SEli Cohen 		rdma_node_get_transport(cma_dev->device->node_type);
278e51060f0SSean Hefty 	list_add_tail(&id_priv->list, &cma_dev->id_list);
279e51060f0SSean Hefty }
280e51060f0SSean Hefty 
281e51060f0SSean Hefty static inline void cma_deref_dev(struct cma_device *cma_dev)
282e51060f0SSean Hefty {
283e51060f0SSean Hefty 	if (atomic_dec_and_test(&cma_dev->refcount))
284e51060f0SSean Hefty 		complete(&cma_dev->comp);
285e51060f0SSean Hefty }
286e51060f0SSean Hefty 
2873c86aa70SEli Cohen static inline void release_mc(struct kref *kref)
2883c86aa70SEli Cohen {
2893c86aa70SEli Cohen 	struct cma_multicast *mc = container_of(kref, struct cma_multicast, mcref);
2903c86aa70SEli Cohen 
2913c86aa70SEli Cohen 	kfree(mc->multicast.ib);
2923c86aa70SEli Cohen 	kfree(mc);
2933c86aa70SEli Cohen }
2943c86aa70SEli Cohen 
295a396d43aSSean Hefty static void cma_release_dev(struct rdma_id_private *id_priv)
296e51060f0SSean Hefty {
297a396d43aSSean Hefty 	mutex_lock(&lock);
298e51060f0SSean Hefty 	list_del(&id_priv->list);
299e51060f0SSean Hefty 	cma_deref_dev(id_priv->cma_dev);
300e51060f0SSean Hefty 	id_priv->cma_dev = NULL;
301a396d43aSSean Hefty 	mutex_unlock(&lock);
302e51060f0SSean Hefty }
303e51060f0SSean Hefty 
304d2ca39f2SYossi Etigin static int cma_set_qkey(struct rdma_id_private *id_priv)
305c8f6a362SSean Hefty {
306c8f6a362SSean Hefty 	struct ib_sa_mcmember_rec rec;
307c8f6a362SSean Hefty 	int ret = 0;
308c8f6a362SSean Hefty 
309d2ca39f2SYossi Etigin 	if (id_priv->qkey)
310d2ca39f2SYossi Etigin 		return 0;
311d2ca39f2SYossi Etigin 
312d2ca39f2SYossi Etigin 	switch (id_priv->id.ps) {
313c8f6a362SSean Hefty 	case RDMA_PS_UDP:
314d2ca39f2SYossi Etigin 		id_priv->qkey = RDMA_UDP_QKEY;
315c8f6a362SSean Hefty 		break;
316c8f6a362SSean Hefty 	case RDMA_PS_IPOIB:
317d2ca39f2SYossi Etigin 		ib_addr_get_mgid(&id_priv->id.route.addr.dev_addr, &rec.mgid);
318d2ca39f2SYossi Etigin 		ret = ib_sa_get_mcmember_rec(id_priv->id.device,
319d2ca39f2SYossi Etigin 					     id_priv->id.port_num, &rec.mgid,
320d2ca39f2SYossi Etigin 					     &rec);
321d2ca39f2SYossi Etigin 		if (!ret)
322d2ca39f2SYossi Etigin 			id_priv->qkey = be32_to_cpu(rec.qkey);
323c8f6a362SSean Hefty 		break;
324c8f6a362SSean Hefty 	default:
325c8f6a362SSean Hefty 		break;
326c8f6a362SSean Hefty 	}
327c8f6a362SSean Hefty 	return ret;
328c8f6a362SSean Hefty }
329c8f6a362SSean Hefty 
3303c86aa70SEli Cohen static int find_gid_port(struct ib_device *device, union ib_gid *gid, u8 port_num)
3313c86aa70SEli Cohen {
3323c86aa70SEli Cohen 	int i;
3333c86aa70SEli Cohen 	int err;
3343c86aa70SEli Cohen 	struct ib_port_attr props;
3353c86aa70SEli Cohen 	union ib_gid tmp;
3363c86aa70SEli Cohen 
3373c86aa70SEli Cohen 	err = ib_query_port(device, port_num, &props);
3383c86aa70SEli Cohen 	if (err)
3393c86aa70SEli Cohen 		return 1;
3403c86aa70SEli Cohen 
3413c86aa70SEli Cohen 	for (i = 0; i < props.gid_tbl_len; ++i) {
3423c86aa70SEli Cohen 		err = ib_query_gid(device, port_num, i, &tmp);
3433c86aa70SEli Cohen 		if (err)
3443c86aa70SEli Cohen 			return 1;
3453c86aa70SEli Cohen 		if (!memcmp(&tmp, gid, sizeof tmp))
3463c86aa70SEli Cohen 			return 0;
3473c86aa70SEli Cohen 	}
3483c86aa70SEli Cohen 
3493c86aa70SEli Cohen 	return -EAGAIN;
3503c86aa70SEli Cohen }
3513c86aa70SEli Cohen 
35207ebafbaSTom Tucker static int cma_acquire_dev(struct rdma_id_private *id_priv)
353e51060f0SSean Hefty {
354c8f6a362SSean Hefty 	struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
355e51060f0SSean Hefty 	struct cma_device *cma_dev;
3563c86aa70SEli Cohen 	union ib_gid gid, iboe_gid;
357e51060f0SSean Hefty 	int ret = -ENODEV;
3583c86aa70SEli Cohen 	u8 port;
3593c86aa70SEli Cohen 	enum rdma_link_layer dev_ll = dev_addr->dev_type == ARPHRD_INFINIBAND ?
3603c86aa70SEli Cohen 		IB_LINK_LAYER_INFINIBAND : IB_LINK_LAYER_ETHERNET;
361e51060f0SSean Hefty 
362*2efdd6a0SMoni Shoua 	if (dev_ll != IB_LINK_LAYER_INFINIBAND &&
363*2efdd6a0SMoni Shoua 	    id_priv->id.ps == RDMA_PS_IPOIB)
364*2efdd6a0SMoni Shoua 		return -EINVAL;
365*2efdd6a0SMoni Shoua 
366a396d43aSSean Hefty 	mutex_lock(&lock);
3673c86aa70SEli Cohen 	iboe_addr_get_sgid(dev_addr, &iboe_gid);
3683c86aa70SEli Cohen 	memcpy(&gid, dev_addr->src_dev_addr +
3693c86aa70SEli Cohen 	       rdma_addr_gid_offset(dev_addr), sizeof gid);
370e51060f0SSean Hefty 	list_for_each_entry(cma_dev, &dev_list, list) {
3713c86aa70SEli Cohen 		for (port = 1; port <= cma_dev->device->phys_port_cnt; ++port) {
3723c86aa70SEli Cohen 			if (rdma_port_get_link_layer(cma_dev->device, port) == dev_ll) {
3733c86aa70SEli Cohen 				if (rdma_node_get_transport(cma_dev->device->node_type) == RDMA_TRANSPORT_IB &&
3743c86aa70SEli Cohen 				    rdma_port_get_link_layer(cma_dev->device, port) == IB_LINK_LAYER_ETHERNET)
3753c86aa70SEli Cohen 					ret = find_gid_port(cma_dev->device, &iboe_gid, port);
3763c86aa70SEli Cohen 				else
3773c86aa70SEli Cohen 					ret = find_gid_port(cma_dev->device, &gid, port);
3783c86aa70SEli Cohen 
379e51060f0SSean Hefty 				if (!ret) {
3803c86aa70SEli Cohen 					id_priv->id.port_num = port;
3813c86aa70SEli Cohen 					goto out;
3823c86aa70SEli Cohen 				} else if (ret == 1)
383e51060f0SSean Hefty 					break;
384e51060f0SSean Hefty 			}
385e51060f0SSean Hefty 		}
3863c86aa70SEli Cohen 	}
3873c86aa70SEli Cohen 
3883c86aa70SEli Cohen out:
3893c86aa70SEli Cohen 	if (!ret)
3903c86aa70SEli Cohen 		cma_attach_to_dev(id_priv, cma_dev);
3913c86aa70SEli Cohen 
392a396d43aSSean Hefty 	mutex_unlock(&lock);
393e51060f0SSean Hefty 	return ret;
394e51060f0SSean Hefty }
395e51060f0SSean Hefty 
396e51060f0SSean Hefty static void cma_deref_id(struct rdma_id_private *id_priv)
397e51060f0SSean Hefty {
398e51060f0SSean Hefty 	if (atomic_dec_and_test(&id_priv->refcount))
399e51060f0SSean Hefty 		complete(&id_priv->comp);
400e51060f0SSean Hefty }
401e51060f0SSean Hefty 
402de910bd9SOr Gerlitz static int cma_disable_callback(struct rdma_id_private *id_priv,
403550e5ca7SNir Muchtar 				enum rdma_cm_state state)
4048aa08602SSean Hefty {
405de910bd9SOr Gerlitz 	mutex_lock(&id_priv->handler_mutex);
406de910bd9SOr Gerlitz 	if (id_priv->state != state) {
407de910bd9SOr Gerlitz 		mutex_unlock(&id_priv->handler_mutex);
408de910bd9SOr Gerlitz 		return -EINVAL;
4098aa08602SSean Hefty 	}
410de910bd9SOr Gerlitz 	return 0;
411e51060f0SSean Hefty }
412e51060f0SSean Hefty 
413e51060f0SSean Hefty struct rdma_cm_id *rdma_create_id(rdma_cm_event_handler event_handler,
414b26f9b99SSean Hefty 				  void *context, enum rdma_port_space ps,
415b26f9b99SSean Hefty 				  enum ib_qp_type qp_type)
416e51060f0SSean Hefty {
417e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
418e51060f0SSean Hefty 
419e51060f0SSean Hefty 	id_priv = kzalloc(sizeof *id_priv, GFP_KERNEL);
420e51060f0SSean Hefty 	if (!id_priv)
421e51060f0SSean Hefty 		return ERR_PTR(-ENOMEM);
422e51060f0SSean Hefty 
42383e9502dSNir Muchtar 	id_priv->owner = task_pid_nr(current);
424550e5ca7SNir Muchtar 	id_priv->state = RDMA_CM_IDLE;
425e51060f0SSean Hefty 	id_priv->id.context = context;
426e51060f0SSean Hefty 	id_priv->id.event_handler = event_handler;
427e51060f0SSean Hefty 	id_priv->id.ps = ps;
428b26f9b99SSean Hefty 	id_priv->id.qp_type = qp_type;
429e51060f0SSean Hefty 	spin_lock_init(&id_priv->lock);
430c5483388SSean Hefty 	mutex_init(&id_priv->qp_mutex);
431e51060f0SSean Hefty 	init_completion(&id_priv->comp);
432e51060f0SSean Hefty 	atomic_set(&id_priv->refcount, 1);
433de910bd9SOr Gerlitz 	mutex_init(&id_priv->handler_mutex);
434e51060f0SSean Hefty 	INIT_LIST_HEAD(&id_priv->listen_list);
435c8f6a362SSean Hefty 	INIT_LIST_HEAD(&id_priv->mc_list);
436e51060f0SSean Hefty 	get_random_bytes(&id_priv->seq_num, sizeof id_priv->seq_num);
437e51060f0SSean Hefty 
438e51060f0SSean Hefty 	return &id_priv->id;
439e51060f0SSean Hefty }
440e51060f0SSean Hefty EXPORT_SYMBOL(rdma_create_id);
441e51060f0SSean Hefty 
442c8f6a362SSean Hefty static int cma_init_ud_qp(struct rdma_id_private *id_priv, struct ib_qp *qp)
443e51060f0SSean Hefty {
444e51060f0SSean Hefty 	struct ib_qp_attr qp_attr;
445c8f6a362SSean Hefty 	int qp_attr_mask, ret;
446e51060f0SSean Hefty 
447c8f6a362SSean Hefty 	qp_attr.qp_state = IB_QPS_INIT;
448c8f6a362SSean Hefty 	ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask);
449e51060f0SSean Hefty 	if (ret)
450e51060f0SSean Hefty 		return ret;
451e51060f0SSean Hefty 
452c8f6a362SSean Hefty 	ret = ib_modify_qp(qp, &qp_attr, qp_attr_mask);
453c8f6a362SSean Hefty 	if (ret)
454c8f6a362SSean Hefty 		return ret;
455c8f6a362SSean Hefty 
456c8f6a362SSean Hefty 	qp_attr.qp_state = IB_QPS_RTR;
457c8f6a362SSean Hefty 	ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE);
458c8f6a362SSean Hefty 	if (ret)
459c8f6a362SSean Hefty 		return ret;
460c8f6a362SSean Hefty 
461c8f6a362SSean Hefty 	qp_attr.qp_state = IB_QPS_RTS;
462c8f6a362SSean Hefty 	qp_attr.sq_psn = 0;
463c8f6a362SSean Hefty 	ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE | IB_QP_SQ_PSN);
464c8f6a362SSean Hefty 
465c8f6a362SSean Hefty 	return ret;
466e51060f0SSean Hefty }
467e51060f0SSean Hefty 
468c8f6a362SSean Hefty static int cma_init_conn_qp(struct rdma_id_private *id_priv, struct ib_qp *qp)
46907ebafbaSTom Tucker {
47007ebafbaSTom Tucker 	struct ib_qp_attr qp_attr;
471c8f6a362SSean Hefty 	int qp_attr_mask, ret;
47207ebafbaSTom Tucker 
47307ebafbaSTom Tucker 	qp_attr.qp_state = IB_QPS_INIT;
474c8f6a362SSean Hefty 	ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask);
475c8f6a362SSean Hefty 	if (ret)
476c8f6a362SSean Hefty 		return ret;
47707ebafbaSTom Tucker 
478c8f6a362SSean Hefty 	return ib_modify_qp(qp, &qp_attr, qp_attr_mask);
47907ebafbaSTom Tucker }
48007ebafbaSTom Tucker 
481e51060f0SSean Hefty int rdma_create_qp(struct rdma_cm_id *id, struct ib_pd *pd,
482e51060f0SSean Hefty 		   struct ib_qp_init_attr *qp_init_attr)
483e51060f0SSean Hefty {
484e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
485e51060f0SSean Hefty 	struct ib_qp *qp;
486e51060f0SSean Hefty 	int ret;
487e51060f0SSean Hefty 
488e51060f0SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
489e51060f0SSean Hefty 	if (id->device != pd->device)
490e51060f0SSean Hefty 		return -EINVAL;
491e51060f0SSean Hefty 
492e51060f0SSean Hefty 	qp = ib_create_qp(pd, qp_init_attr);
493e51060f0SSean Hefty 	if (IS_ERR(qp))
494e51060f0SSean Hefty 		return PTR_ERR(qp);
495e51060f0SSean Hefty 
496b26f9b99SSean Hefty 	if (id->qp_type == IB_QPT_UD)
497c8f6a362SSean Hefty 		ret = cma_init_ud_qp(id_priv, qp);
498c8f6a362SSean Hefty 	else
499c8f6a362SSean Hefty 		ret = cma_init_conn_qp(id_priv, qp);
500e51060f0SSean Hefty 	if (ret)
501e51060f0SSean Hefty 		goto err;
502e51060f0SSean Hefty 
503e51060f0SSean Hefty 	id->qp = qp;
504e51060f0SSean Hefty 	id_priv->qp_num = qp->qp_num;
505e51060f0SSean Hefty 	id_priv->srq = (qp->srq != NULL);
506e51060f0SSean Hefty 	return 0;
507e51060f0SSean Hefty err:
508e51060f0SSean Hefty 	ib_destroy_qp(qp);
509e51060f0SSean Hefty 	return ret;
510e51060f0SSean Hefty }
511e51060f0SSean Hefty EXPORT_SYMBOL(rdma_create_qp);
512e51060f0SSean Hefty 
513e51060f0SSean Hefty void rdma_destroy_qp(struct rdma_cm_id *id)
514e51060f0SSean Hefty {
515c5483388SSean Hefty 	struct rdma_id_private *id_priv;
516c5483388SSean Hefty 
517c5483388SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
518c5483388SSean Hefty 	mutex_lock(&id_priv->qp_mutex);
519c5483388SSean Hefty 	ib_destroy_qp(id_priv->id.qp);
520c5483388SSean Hefty 	id_priv->id.qp = NULL;
521c5483388SSean Hefty 	mutex_unlock(&id_priv->qp_mutex);
522e51060f0SSean Hefty }
523e51060f0SSean Hefty EXPORT_SYMBOL(rdma_destroy_qp);
524e51060f0SSean Hefty 
5255851bb89SSean Hefty static int cma_modify_qp_rtr(struct rdma_id_private *id_priv,
5265851bb89SSean Hefty 			     struct rdma_conn_param *conn_param)
527e51060f0SSean Hefty {
528e51060f0SSean Hefty 	struct ib_qp_attr qp_attr;
529e51060f0SSean Hefty 	int qp_attr_mask, ret;
530e51060f0SSean Hefty 
531c5483388SSean Hefty 	mutex_lock(&id_priv->qp_mutex);
532c5483388SSean Hefty 	if (!id_priv->id.qp) {
533c5483388SSean Hefty 		ret = 0;
534c5483388SSean Hefty 		goto out;
535c5483388SSean Hefty 	}
536e51060f0SSean Hefty 
537e51060f0SSean Hefty 	/* Need to update QP attributes from default values. */
538e51060f0SSean Hefty 	qp_attr.qp_state = IB_QPS_INIT;
539c5483388SSean Hefty 	ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask);
540e51060f0SSean Hefty 	if (ret)
541c5483388SSean Hefty 		goto out;
542e51060f0SSean Hefty 
543c5483388SSean Hefty 	ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask);
544e51060f0SSean Hefty 	if (ret)
545c5483388SSean Hefty 		goto out;
546e51060f0SSean Hefty 
547e51060f0SSean Hefty 	qp_attr.qp_state = IB_QPS_RTR;
548c5483388SSean Hefty 	ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask);
549e51060f0SSean Hefty 	if (ret)
550c5483388SSean Hefty 		goto out;
551e51060f0SSean Hefty 
5525851bb89SSean Hefty 	if (conn_param)
5535851bb89SSean Hefty 		qp_attr.max_dest_rd_atomic = conn_param->responder_resources;
554c5483388SSean Hefty 	ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask);
555c5483388SSean Hefty out:
556c5483388SSean Hefty 	mutex_unlock(&id_priv->qp_mutex);
557c5483388SSean Hefty 	return ret;
558e51060f0SSean Hefty }
559e51060f0SSean Hefty 
5605851bb89SSean Hefty static int cma_modify_qp_rts(struct rdma_id_private *id_priv,
5615851bb89SSean Hefty 			     struct rdma_conn_param *conn_param)
562e51060f0SSean Hefty {
563e51060f0SSean Hefty 	struct ib_qp_attr qp_attr;
564e51060f0SSean Hefty 	int qp_attr_mask, ret;
565e51060f0SSean Hefty 
566c5483388SSean Hefty 	mutex_lock(&id_priv->qp_mutex);
567c5483388SSean Hefty 	if (!id_priv->id.qp) {
568c5483388SSean Hefty 		ret = 0;
569c5483388SSean Hefty 		goto out;
570e51060f0SSean Hefty 	}
571e51060f0SSean Hefty 
572c5483388SSean Hefty 	qp_attr.qp_state = IB_QPS_RTS;
573c5483388SSean Hefty 	ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask);
574c5483388SSean Hefty 	if (ret)
575c5483388SSean Hefty 		goto out;
576c5483388SSean Hefty 
5775851bb89SSean Hefty 	if (conn_param)
5785851bb89SSean Hefty 		qp_attr.max_rd_atomic = conn_param->initiator_depth;
579c5483388SSean Hefty 	ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask);
580c5483388SSean Hefty out:
581c5483388SSean Hefty 	mutex_unlock(&id_priv->qp_mutex);
582c5483388SSean Hefty 	return ret;
583c5483388SSean Hefty }
584c5483388SSean Hefty 
585c5483388SSean Hefty static int cma_modify_qp_err(struct rdma_id_private *id_priv)
586e51060f0SSean Hefty {
587e51060f0SSean Hefty 	struct ib_qp_attr qp_attr;
588c5483388SSean Hefty 	int ret;
589e51060f0SSean Hefty 
590c5483388SSean Hefty 	mutex_lock(&id_priv->qp_mutex);
591c5483388SSean Hefty 	if (!id_priv->id.qp) {
592c5483388SSean Hefty 		ret = 0;
593c5483388SSean Hefty 		goto out;
594c5483388SSean Hefty 	}
595e51060f0SSean Hefty 
596e51060f0SSean Hefty 	qp_attr.qp_state = IB_QPS_ERR;
597c5483388SSean Hefty 	ret = ib_modify_qp(id_priv->id.qp, &qp_attr, IB_QP_STATE);
598c5483388SSean Hefty out:
599c5483388SSean Hefty 	mutex_unlock(&id_priv->qp_mutex);
600c5483388SSean Hefty 	return ret;
601e51060f0SSean Hefty }
602e51060f0SSean Hefty 
603c8f6a362SSean Hefty static int cma_ib_init_qp_attr(struct rdma_id_private *id_priv,
604c8f6a362SSean Hefty 			       struct ib_qp_attr *qp_attr, int *qp_attr_mask)
605c8f6a362SSean Hefty {
606c8f6a362SSean Hefty 	struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
607c8f6a362SSean Hefty 	int ret;
6083c86aa70SEli Cohen 	u16 pkey;
6093c86aa70SEli Cohen 
6103c86aa70SEli Cohen 	if (rdma_port_get_link_layer(id_priv->id.device, id_priv->id.port_num) ==
6113c86aa70SEli Cohen 	    IB_LINK_LAYER_INFINIBAND)
6123c86aa70SEli Cohen 		pkey = ib_addr_get_pkey(dev_addr);
6133c86aa70SEli Cohen 	else
6143c86aa70SEli Cohen 		pkey = 0xffff;
615c8f6a362SSean Hefty 
616c8f6a362SSean Hefty 	ret = ib_find_cached_pkey(id_priv->id.device, id_priv->id.port_num,
6173c86aa70SEli Cohen 				  pkey, &qp_attr->pkey_index);
618c8f6a362SSean Hefty 	if (ret)
619c8f6a362SSean Hefty 		return ret;
620c8f6a362SSean Hefty 
621c8f6a362SSean Hefty 	qp_attr->port_num = id_priv->id.port_num;
622c8f6a362SSean Hefty 	*qp_attr_mask = IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_PORT;
623c8f6a362SSean Hefty 
624b26f9b99SSean Hefty 	if (id_priv->id.qp_type == IB_QPT_UD) {
625d2ca39f2SYossi Etigin 		ret = cma_set_qkey(id_priv);
626d2ca39f2SYossi Etigin 		if (ret)
627d2ca39f2SYossi Etigin 			return ret;
628d2ca39f2SYossi Etigin 
629c8f6a362SSean Hefty 		qp_attr->qkey = id_priv->qkey;
630c8f6a362SSean Hefty 		*qp_attr_mask |= IB_QP_QKEY;
631c8f6a362SSean Hefty 	} else {
632c8f6a362SSean Hefty 		qp_attr->qp_access_flags = 0;
633c8f6a362SSean Hefty 		*qp_attr_mask |= IB_QP_ACCESS_FLAGS;
634c8f6a362SSean Hefty 	}
635c8f6a362SSean Hefty 	return 0;
636c8f6a362SSean Hefty }
637c8f6a362SSean Hefty 
638e51060f0SSean Hefty int rdma_init_qp_attr(struct rdma_cm_id *id, struct ib_qp_attr *qp_attr,
639e51060f0SSean Hefty 		       int *qp_attr_mask)
640e51060f0SSean Hefty {
641e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
642c8f6a362SSean Hefty 	int ret = 0;
643e51060f0SSean Hefty 
644e51060f0SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
64507ebafbaSTom Tucker 	switch (rdma_node_get_transport(id_priv->id.device->node_type)) {
64607ebafbaSTom Tucker 	case RDMA_TRANSPORT_IB:
647b26f9b99SSean Hefty 		if (!id_priv->cm_id.ib || (id_priv->id.qp_type == IB_QPT_UD))
648c8f6a362SSean Hefty 			ret = cma_ib_init_qp_attr(id_priv, qp_attr, qp_attr_mask);
649c8f6a362SSean Hefty 		else
650e51060f0SSean Hefty 			ret = ib_cm_init_qp_attr(id_priv->cm_id.ib, qp_attr,
651e51060f0SSean Hefty 						 qp_attr_mask);
652e51060f0SSean Hefty 		if (qp_attr->qp_state == IB_QPS_RTR)
653e51060f0SSean Hefty 			qp_attr->rq_psn = id_priv->seq_num;
654e51060f0SSean Hefty 		break;
65507ebafbaSTom Tucker 	case RDMA_TRANSPORT_IWARP:
656c8f6a362SSean Hefty 		if (!id_priv->cm_id.iw) {
6578f076531SDotan Barak 			qp_attr->qp_access_flags = 0;
658c8f6a362SSean Hefty 			*qp_attr_mask = IB_QP_STATE | IB_QP_ACCESS_FLAGS;
659c8f6a362SSean Hefty 		} else
66007ebafbaSTom Tucker 			ret = iw_cm_init_qp_attr(id_priv->cm_id.iw, qp_attr,
66107ebafbaSTom Tucker 						 qp_attr_mask);
66207ebafbaSTom Tucker 		break;
663e51060f0SSean Hefty 	default:
664e51060f0SSean Hefty 		ret = -ENOSYS;
665e51060f0SSean Hefty 		break;
666e51060f0SSean Hefty 	}
667e51060f0SSean Hefty 
668e51060f0SSean Hefty 	return ret;
669e51060f0SSean Hefty }
670e51060f0SSean Hefty EXPORT_SYMBOL(rdma_init_qp_attr);
671e51060f0SSean Hefty 
672e51060f0SSean Hefty static inline int cma_zero_addr(struct sockaddr *addr)
673e51060f0SSean Hefty {
674e51060f0SSean Hefty 	struct in6_addr *ip6;
675e51060f0SSean Hefty 
676e51060f0SSean Hefty 	if (addr->sa_family == AF_INET)
6776360a02aSJoe Perches 		return ipv4_is_zeronet(
6786360a02aSJoe Perches 			((struct sockaddr_in *)addr)->sin_addr.s_addr);
679e51060f0SSean Hefty 	else {
680e51060f0SSean Hefty 		ip6 = &((struct sockaddr_in6 *) addr)->sin6_addr;
681e51060f0SSean Hefty 		return (ip6->s6_addr32[0] | ip6->s6_addr32[1] |
6825fd571cbSEric Sesterhenn 			ip6->s6_addr32[2] | ip6->s6_addr32[3]) == 0;
683e51060f0SSean Hefty 	}
684e51060f0SSean Hefty }
685e51060f0SSean Hefty 
686e51060f0SSean Hefty static inline int cma_loopback_addr(struct sockaddr *addr)
687e51060f0SSean Hefty {
6881f5175adSAleksey Senin 	if (addr->sa_family == AF_INET)
6891f5175adSAleksey Senin 		return ipv4_is_loopback(
6901f5175adSAleksey Senin 			((struct sockaddr_in *) addr)->sin_addr.s_addr);
6911f5175adSAleksey Senin 	else
6921f5175adSAleksey Senin 		return ipv6_addr_loopback(
6931f5175adSAleksey Senin 			&((struct sockaddr_in6 *) addr)->sin6_addr);
694e51060f0SSean Hefty }
695e51060f0SSean Hefty 
696e51060f0SSean Hefty static inline int cma_any_addr(struct sockaddr *addr)
697e51060f0SSean Hefty {
698e51060f0SSean Hefty 	return cma_zero_addr(addr) || cma_loopback_addr(addr);
699e51060f0SSean Hefty }
700e51060f0SSean Hefty 
70143b752daSHefty, Sean static int cma_addr_cmp(struct sockaddr *src, struct sockaddr *dst)
70243b752daSHefty, Sean {
70343b752daSHefty, Sean 	if (src->sa_family != dst->sa_family)
70443b752daSHefty, Sean 		return -1;
70543b752daSHefty, Sean 
70643b752daSHefty, Sean 	switch (src->sa_family) {
70743b752daSHefty, Sean 	case AF_INET:
70843b752daSHefty, Sean 		return ((struct sockaddr_in *) src)->sin_addr.s_addr !=
70943b752daSHefty, Sean 		       ((struct sockaddr_in *) dst)->sin_addr.s_addr;
71043b752daSHefty, Sean 	default:
71143b752daSHefty, Sean 		return ipv6_addr_cmp(&((struct sockaddr_in6 *) src)->sin6_addr,
71243b752daSHefty, Sean 				     &((struct sockaddr_in6 *) dst)->sin6_addr);
71343b752daSHefty, Sean 	}
71443b752daSHefty, Sean }
71543b752daSHefty, Sean 
716628e5f6dSSean Hefty static inline __be16 cma_port(struct sockaddr *addr)
717628e5f6dSSean Hefty {
718628e5f6dSSean Hefty 	if (addr->sa_family == AF_INET)
719628e5f6dSSean Hefty 		return ((struct sockaddr_in *) addr)->sin_port;
720628e5f6dSSean Hefty 	else
721628e5f6dSSean Hefty 		return ((struct sockaddr_in6 *) addr)->sin6_port;
722628e5f6dSSean Hefty }
723628e5f6dSSean Hefty 
724e51060f0SSean Hefty static inline int cma_any_port(struct sockaddr *addr)
725e51060f0SSean Hefty {
726628e5f6dSSean Hefty 	return !cma_port(addr);
727e51060f0SSean Hefty }
728e51060f0SSean Hefty 
729e51060f0SSean Hefty static int cma_get_net_info(void *hdr, enum rdma_port_space ps,
7301b90c137SAl Viro 			    u8 *ip_ver, __be16 *port,
731e51060f0SSean Hefty 			    union cma_ip_addr **src, union cma_ip_addr **dst)
732e51060f0SSean Hefty {
733e51060f0SSean Hefty 	switch (ps) {
734e51060f0SSean Hefty 	case RDMA_PS_SDP:
735e51060f0SSean Hefty 		if (sdp_get_majv(((struct sdp_hh *) hdr)->sdp_version) !=
736e51060f0SSean Hefty 		    SDP_MAJ_VERSION)
737e51060f0SSean Hefty 			return -EINVAL;
738e51060f0SSean Hefty 
739e51060f0SSean Hefty 		*ip_ver	= sdp_get_ip_ver(hdr);
740e51060f0SSean Hefty 		*port	= ((struct sdp_hh *) hdr)->port;
741e51060f0SSean Hefty 		*src	= &((struct sdp_hh *) hdr)->src_addr;
742e51060f0SSean Hefty 		*dst	= &((struct sdp_hh *) hdr)->dst_addr;
743e51060f0SSean Hefty 		break;
744e51060f0SSean Hefty 	default:
745e51060f0SSean Hefty 		if (((struct cma_hdr *) hdr)->cma_version != CMA_VERSION)
746e51060f0SSean Hefty 			return -EINVAL;
747e51060f0SSean Hefty 
748e51060f0SSean Hefty 		*ip_ver	= cma_get_ip_ver(hdr);
749e51060f0SSean Hefty 		*port	= ((struct cma_hdr *) hdr)->port;
750e51060f0SSean Hefty 		*src	= &((struct cma_hdr *) hdr)->src_addr;
751e51060f0SSean Hefty 		*dst	= &((struct cma_hdr *) hdr)->dst_addr;
752e51060f0SSean Hefty 		break;
753e51060f0SSean Hefty 	}
754e51060f0SSean Hefty 
755e51060f0SSean Hefty 	if (*ip_ver != 4 && *ip_ver != 6)
756e51060f0SSean Hefty 		return -EINVAL;
757e51060f0SSean Hefty 	return 0;
758e51060f0SSean Hefty }
759e51060f0SSean Hefty 
760e51060f0SSean Hefty static void cma_save_net_info(struct rdma_addr *addr,
761e51060f0SSean Hefty 			      struct rdma_addr *listen_addr,
7621b90c137SAl Viro 			      u8 ip_ver, __be16 port,
763e51060f0SSean Hefty 			      union cma_ip_addr *src, union cma_ip_addr *dst)
764e51060f0SSean Hefty {
765e51060f0SSean Hefty 	struct sockaddr_in *listen4, *ip4;
766e51060f0SSean Hefty 	struct sockaddr_in6 *listen6, *ip6;
767e51060f0SSean Hefty 
768e51060f0SSean Hefty 	switch (ip_ver) {
769e51060f0SSean Hefty 	case 4:
770e51060f0SSean Hefty 		listen4 = (struct sockaddr_in *) &listen_addr->src_addr;
771e51060f0SSean Hefty 		ip4 = (struct sockaddr_in *) &addr->src_addr;
772e51060f0SSean Hefty 		ip4->sin_family = listen4->sin_family;
773e51060f0SSean Hefty 		ip4->sin_addr.s_addr = dst->ip4.addr;
774e51060f0SSean Hefty 		ip4->sin_port = listen4->sin_port;
775e51060f0SSean Hefty 
776e51060f0SSean Hefty 		ip4 = (struct sockaddr_in *) &addr->dst_addr;
777e51060f0SSean Hefty 		ip4->sin_family = listen4->sin_family;
778e51060f0SSean Hefty 		ip4->sin_addr.s_addr = src->ip4.addr;
779e51060f0SSean Hefty 		ip4->sin_port = port;
780e51060f0SSean Hefty 		break;
781e51060f0SSean Hefty 	case 6:
782e51060f0SSean Hefty 		listen6 = (struct sockaddr_in6 *) &listen_addr->src_addr;
783e51060f0SSean Hefty 		ip6 = (struct sockaddr_in6 *) &addr->src_addr;
784e51060f0SSean Hefty 		ip6->sin6_family = listen6->sin6_family;
785e51060f0SSean Hefty 		ip6->sin6_addr = dst->ip6;
786e51060f0SSean Hefty 		ip6->sin6_port = listen6->sin6_port;
787e51060f0SSean Hefty 
788e51060f0SSean Hefty 		ip6 = (struct sockaddr_in6 *) &addr->dst_addr;
789e51060f0SSean Hefty 		ip6->sin6_family = listen6->sin6_family;
790e51060f0SSean Hefty 		ip6->sin6_addr = src->ip6;
791e51060f0SSean Hefty 		ip6->sin6_port = port;
792e51060f0SSean Hefty 		break;
793e51060f0SSean Hefty 	default:
794e51060f0SSean Hefty 		break;
795e51060f0SSean Hefty 	}
796e51060f0SSean Hefty }
797e51060f0SSean Hefty 
798e51060f0SSean Hefty static inline int cma_user_data_offset(enum rdma_port_space ps)
799e51060f0SSean Hefty {
800e51060f0SSean Hefty 	switch (ps) {
801e51060f0SSean Hefty 	case RDMA_PS_SDP:
802e51060f0SSean Hefty 		return 0;
803e51060f0SSean Hefty 	default:
804e51060f0SSean Hefty 		return sizeof(struct cma_hdr);
805e51060f0SSean Hefty 	}
806e51060f0SSean Hefty }
807e51060f0SSean Hefty 
808e51060f0SSean Hefty static void cma_cancel_route(struct rdma_id_private *id_priv)
809e51060f0SSean Hefty {
8103c86aa70SEli Cohen 	switch (rdma_port_get_link_layer(id_priv->id.device, id_priv->id.port_num)) {
8113c86aa70SEli Cohen 	case IB_LINK_LAYER_INFINIBAND:
812e51060f0SSean Hefty 		if (id_priv->query)
813e51060f0SSean Hefty 			ib_sa_cancel_query(id_priv->query_id, id_priv->query);
814e51060f0SSean Hefty 		break;
815e51060f0SSean Hefty 	default:
816e51060f0SSean Hefty 		break;
817e51060f0SSean Hefty 	}
818e51060f0SSean Hefty }
819e51060f0SSean Hefty 
820e51060f0SSean Hefty static void cma_cancel_listens(struct rdma_id_private *id_priv)
821e51060f0SSean Hefty {
822e51060f0SSean Hefty 	struct rdma_id_private *dev_id_priv;
823e51060f0SSean Hefty 
824d02d1f53SSean Hefty 	/*
825d02d1f53SSean Hefty 	 * Remove from listen_any_list to prevent added devices from spawning
826d02d1f53SSean Hefty 	 * additional listen requests.
827d02d1f53SSean Hefty 	 */
828e51060f0SSean Hefty 	mutex_lock(&lock);
829e51060f0SSean Hefty 	list_del(&id_priv->list);
830e51060f0SSean Hefty 
831e51060f0SSean Hefty 	while (!list_empty(&id_priv->listen_list)) {
832e51060f0SSean Hefty 		dev_id_priv = list_entry(id_priv->listen_list.next,
833e51060f0SSean Hefty 					 struct rdma_id_private, listen_list);
834d02d1f53SSean Hefty 		/* sync with device removal to avoid duplicate destruction */
835d02d1f53SSean Hefty 		list_del_init(&dev_id_priv->list);
836d02d1f53SSean Hefty 		list_del(&dev_id_priv->listen_list);
837d02d1f53SSean Hefty 		mutex_unlock(&lock);
838d02d1f53SSean Hefty 
839d02d1f53SSean Hefty 		rdma_destroy_id(&dev_id_priv->id);
840d02d1f53SSean Hefty 		mutex_lock(&lock);
841e51060f0SSean Hefty 	}
842e51060f0SSean Hefty 	mutex_unlock(&lock);
843e51060f0SSean Hefty }
844e51060f0SSean Hefty 
845e51060f0SSean Hefty static void cma_cancel_operation(struct rdma_id_private *id_priv,
846550e5ca7SNir Muchtar 				 enum rdma_cm_state state)
847e51060f0SSean Hefty {
848e51060f0SSean Hefty 	switch (state) {
849550e5ca7SNir Muchtar 	case RDMA_CM_ADDR_QUERY:
850e51060f0SSean Hefty 		rdma_addr_cancel(&id_priv->id.route.addr.dev_addr);
851e51060f0SSean Hefty 		break;
852550e5ca7SNir Muchtar 	case RDMA_CM_ROUTE_QUERY:
853e51060f0SSean Hefty 		cma_cancel_route(id_priv);
854e51060f0SSean Hefty 		break;
855550e5ca7SNir Muchtar 	case RDMA_CM_LISTEN:
8563f446754SRoland Dreier 		if (cma_any_addr((struct sockaddr *) &id_priv->id.route.addr.src_addr)
8573f446754SRoland Dreier 				&& !id_priv->cma_dev)
858e51060f0SSean Hefty 			cma_cancel_listens(id_priv);
859e51060f0SSean Hefty 		break;
860e51060f0SSean Hefty 	default:
861e51060f0SSean Hefty 		break;
862e51060f0SSean Hefty 	}
863e51060f0SSean Hefty }
864e51060f0SSean Hefty 
865e51060f0SSean Hefty static void cma_release_port(struct rdma_id_private *id_priv)
866e51060f0SSean Hefty {
867e51060f0SSean Hefty 	struct rdma_bind_list *bind_list = id_priv->bind_list;
868e51060f0SSean Hefty 
869e51060f0SSean Hefty 	if (!bind_list)
870e51060f0SSean Hefty 		return;
871e51060f0SSean Hefty 
872e51060f0SSean Hefty 	mutex_lock(&lock);
873e51060f0SSean Hefty 	hlist_del(&id_priv->node);
874e51060f0SSean Hefty 	if (hlist_empty(&bind_list->owners)) {
875e51060f0SSean Hefty 		idr_remove(bind_list->ps, bind_list->port);
876e51060f0SSean Hefty 		kfree(bind_list);
877e51060f0SSean Hefty 	}
878e51060f0SSean Hefty 	mutex_unlock(&lock);
879e51060f0SSean Hefty }
880e51060f0SSean Hefty 
881c8f6a362SSean Hefty static void cma_leave_mc_groups(struct rdma_id_private *id_priv)
882c8f6a362SSean Hefty {
883c8f6a362SSean Hefty 	struct cma_multicast *mc;
884c8f6a362SSean Hefty 
885c8f6a362SSean Hefty 	while (!list_empty(&id_priv->mc_list)) {
886c8f6a362SSean Hefty 		mc = container_of(id_priv->mc_list.next,
887c8f6a362SSean Hefty 				  struct cma_multicast, list);
888c8f6a362SSean Hefty 		list_del(&mc->list);
8893c86aa70SEli Cohen 		switch (rdma_port_get_link_layer(id_priv->cma_dev->device, id_priv->id.port_num)) {
8903c86aa70SEli Cohen 		case IB_LINK_LAYER_INFINIBAND:
891c8f6a362SSean Hefty 			ib_sa_free_multicast(mc->multicast.ib);
892c8f6a362SSean Hefty 			kfree(mc);
8933c86aa70SEli Cohen 			break;
8943c86aa70SEli Cohen 		case IB_LINK_LAYER_ETHERNET:
8953c86aa70SEli Cohen 			kref_put(&mc->mcref, release_mc);
8963c86aa70SEli Cohen 			break;
8973c86aa70SEli Cohen 		default:
8983c86aa70SEli Cohen 			break;
8993c86aa70SEli Cohen 		}
900c8f6a362SSean Hefty 	}
901c8f6a362SSean Hefty }
902c8f6a362SSean Hefty 
903e51060f0SSean Hefty void rdma_destroy_id(struct rdma_cm_id *id)
904e51060f0SSean Hefty {
905e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
906550e5ca7SNir Muchtar 	enum rdma_cm_state state;
907e51060f0SSean Hefty 
908e51060f0SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
909550e5ca7SNir Muchtar 	state = cma_exch(id_priv, RDMA_CM_DESTROYING);
910e51060f0SSean Hefty 	cma_cancel_operation(id_priv, state);
911e51060f0SSean Hefty 
912a396d43aSSean Hefty 	/*
913a396d43aSSean Hefty 	 * Wait for any active callback to finish.  New callbacks will find
914a396d43aSSean Hefty 	 * the id_priv state set to destroying and abort.
915a396d43aSSean Hefty 	 */
916a396d43aSSean Hefty 	mutex_lock(&id_priv->handler_mutex);
917a396d43aSSean Hefty 	mutex_unlock(&id_priv->handler_mutex);
918a396d43aSSean Hefty 
919e51060f0SSean Hefty 	if (id_priv->cma_dev) {
9203c86aa70SEli Cohen 		switch (rdma_node_get_transport(id_priv->id.device->node_type)) {
92107ebafbaSTom Tucker 		case RDMA_TRANSPORT_IB:
9220c9361fcSJack Morgenstein 			if (id_priv->cm_id.ib)
923e51060f0SSean Hefty 				ib_destroy_cm_id(id_priv->cm_id.ib);
924e51060f0SSean Hefty 			break;
92507ebafbaSTom Tucker 		case RDMA_TRANSPORT_IWARP:
9260c9361fcSJack Morgenstein 			if (id_priv->cm_id.iw)
92707ebafbaSTom Tucker 				iw_destroy_cm_id(id_priv->cm_id.iw);
92807ebafbaSTom Tucker 			break;
929e51060f0SSean Hefty 		default:
930e51060f0SSean Hefty 			break;
931e51060f0SSean Hefty 		}
932c8f6a362SSean Hefty 		cma_leave_mc_groups(id_priv);
933a396d43aSSean Hefty 		cma_release_dev(id_priv);
934e51060f0SSean Hefty 	}
935e51060f0SSean Hefty 
936e51060f0SSean Hefty 	cma_release_port(id_priv);
937e51060f0SSean Hefty 	cma_deref_id(id_priv);
938e51060f0SSean Hefty 	wait_for_completion(&id_priv->comp);
939e51060f0SSean Hefty 
940d02d1f53SSean Hefty 	if (id_priv->internal_id)
941d02d1f53SSean Hefty 		cma_deref_id(id_priv->id.context);
942d02d1f53SSean Hefty 
943e51060f0SSean Hefty 	kfree(id_priv->id.route.path_rec);
944e51060f0SSean Hefty 	kfree(id_priv);
945e51060f0SSean Hefty }
946e51060f0SSean Hefty EXPORT_SYMBOL(rdma_destroy_id);
947e51060f0SSean Hefty 
948e51060f0SSean Hefty static int cma_rep_recv(struct rdma_id_private *id_priv)
949e51060f0SSean Hefty {
950e51060f0SSean Hefty 	int ret;
951e51060f0SSean Hefty 
9525851bb89SSean Hefty 	ret = cma_modify_qp_rtr(id_priv, NULL);
953e51060f0SSean Hefty 	if (ret)
954e51060f0SSean Hefty 		goto reject;
955e51060f0SSean Hefty 
9565851bb89SSean Hefty 	ret = cma_modify_qp_rts(id_priv, NULL);
957e51060f0SSean Hefty 	if (ret)
958e51060f0SSean Hefty 		goto reject;
959e51060f0SSean Hefty 
960e51060f0SSean Hefty 	ret = ib_send_cm_rtu(id_priv->cm_id.ib, NULL, 0);
961e51060f0SSean Hefty 	if (ret)
962e51060f0SSean Hefty 		goto reject;
963e51060f0SSean Hefty 
964e51060f0SSean Hefty 	return 0;
965e51060f0SSean Hefty reject:
966c5483388SSean Hefty 	cma_modify_qp_err(id_priv);
967e51060f0SSean Hefty 	ib_send_cm_rej(id_priv->cm_id.ib, IB_CM_REJ_CONSUMER_DEFINED,
968e51060f0SSean Hefty 		       NULL, 0, NULL, 0);
969e51060f0SSean Hefty 	return ret;
970e51060f0SSean Hefty }
971e51060f0SSean Hefty 
972e51060f0SSean Hefty static int cma_verify_rep(struct rdma_id_private *id_priv, void *data)
973e51060f0SSean Hefty {
974e51060f0SSean Hefty 	if (id_priv->id.ps == RDMA_PS_SDP &&
975e51060f0SSean Hefty 	    sdp_get_majv(((struct sdp_hah *) data)->sdp_version) !=
976e51060f0SSean Hefty 	    SDP_MAJ_VERSION)
977e51060f0SSean Hefty 		return -EINVAL;
978e51060f0SSean Hefty 
979e51060f0SSean Hefty 	return 0;
980e51060f0SSean Hefty }
981e51060f0SSean Hefty 
982a1b1b61fSSean Hefty static void cma_set_rep_event_data(struct rdma_cm_event *event,
983a1b1b61fSSean Hefty 				   struct ib_cm_rep_event_param *rep_data,
984a1b1b61fSSean Hefty 				   void *private_data)
985a1b1b61fSSean Hefty {
986a1b1b61fSSean Hefty 	event->param.conn.private_data = private_data;
987a1b1b61fSSean Hefty 	event->param.conn.private_data_len = IB_CM_REP_PRIVATE_DATA_SIZE;
988a1b1b61fSSean Hefty 	event->param.conn.responder_resources = rep_data->responder_resources;
989a1b1b61fSSean Hefty 	event->param.conn.initiator_depth = rep_data->initiator_depth;
990a1b1b61fSSean Hefty 	event->param.conn.flow_control = rep_data->flow_control;
991a1b1b61fSSean Hefty 	event->param.conn.rnr_retry_count = rep_data->rnr_retry_count;
992a1b1b61fSSean Hefty 	event->param.conn.srq = rep_data->srq;
993a1b1b61fSSean Hefty 	event->param.conn.qp_num = rep_data->remote_qpn;
994a1b1b61fSSean Hefty }
995a1b1b61fSSean Hefty 
996e51060f0SSean Hefty static int cma_ib_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
997e51060f0SSean Hefty {
998e51060f0SSean Hefty 	struct rdma_id_private *id_priv = cm_id->context;
999a1b1b61fSSean Hefty 	struct rdma_cm_event event;
1000a1b1b61fSSean Hefty 	int ret = 0;
1001e51060f0SSean Hefty 
100238ca83a5SAmir Vadai 	if ((ib_event->event != IB_CM_TIMEWAIT_EXIT &&
1003550e5ca7SNir Muchtar 		cma_disable_callback(id_priv, RDMA_CM_CONNECT)) ||
100438ca83a5SAmir Vadai 	    (ib_event->event == IB_CM_TIMEWAIT_EXIT &&
1005550e5ca7SNir Muchtar 		cma_disable_callback(id_priv, RDMA_CM_DISCONNECT)))
10068aa08602SSean Hefty 		return 0;
1007e51060f0SSean Hefty 
1008a1b1b61fSSean Hefty 	memset(&event, 0, sizeof event);
1009e51060f0SSean Hefty 	switch (ib_event->event) {
1010e51060f0SSean Hefty 	case IB_CM_REQ_ERROR:
1011e51060f0SSean Hefty 	case IB_CM_REP_ERROR:
1012a1b1b61fSSean Hefty 		event.event = RDMA_CM_EVENT_UNREACHABLE;
1013a1b1b61fSSean Hefty 		event.status = -ETIMEDOUT;
1014e51060f0SSean Hefty 		break;
1015e51060f0SSean Hefty 	case IB_CM_REP_RECEIVED:
1016a1b1b61fSSean Hefty 		event.status = cma_verify_rep(id_priv, ib_event->private_data);
1017a1b1b61fSSean Hefty 		if (event.status)
1018a1b1b61fSSean Hefty 			event.event = RDMA_CM_EVENT_CONNECT_ERROR;
1019e51060f0SSean Hefty 		else if (id_priv->id.qp && id_priv->id.ps != RDMA_PS_SDP) {
1020a1b1b61fSSean Hefty 			event.status = cma_rep_recv(id_priv);
1021a1b1b61fSSean Hefty 			event.event = event.status ? RDMA_CM_EVENT_CONNECT_ERROR :
1022e51060f0SSean Hefty 						     RDMA_CM_EVENT_ESTABLISHED;
1023e51060f0SSean Hefty 		} else
1024a1b1b61fSSean Hefty 			event.event = RDMA_CM_EVENT_CONNECT_RESPONSE;
1025a1b1b61fSSean Hefty 		cma_set_rep_event_data(&event, &ib_event->param.rep_rcvd,
1026a1b1b61fSSean Hefty 				       ib_event->private_data);
1027e51060f0SSean Hefty 		break;
1028e51060f0SSean Hefty 	case IB_CM_RTU_RECEIVED:
10290fe313b0SSean Hefty 	case IB_CM_USER_ESTABLISHED:
10300fe313b0SSean Hefty 		event.event = RDMA_CM_EVENT_ESTABLISHED;
1031e51060f0SSean Hefty 		break;
1032e51060f0SSean Hefty 	case IB_CM_DREQ_ERROR:
1033a1b1b61fSSean Hefty 		event.status = -ETIMEDOUT; /* fall through */
1034e51060f0SSean Hefty 	case IB_CM_DREQ_RECEIVED:
1035e51060f0SSean Hefty 	case IB_CM_DREP_RECEIVED:
1036550e5ca7SNir Muchtar 		if (!cma_comp_exch(id_priv, RDMA_CM_CONNECT,
1037550e5ca7SNir Muchtar 				   RDMA_CM_DISCONNECT))
1038e51060f0SSean Hefty 			goto out;
1039a1b1b61fSSean Hefty 		event.event = RDMA_CM_EVENT_DISCONNECTED;
1040e51060f0SSean Hefty 		break;
1041e51060f0SSean Hefty 	case IB_CM_TIMEWAIT_EXIT:
104238ca83a5SAmir Vadai 		event.event = RDMA_CM_EVENT_TIMEWAIT_EXIT;
104338ca83a5SAmir Vadai 		break;
1044e51060f0SSean Hefty 	case IB_CM_MRA_RECEIVED:
1045e51060f0SSean Hefty 		/* ignore event */
1046e51060f0SSean Hefty 		goto out;
1047e51060f0SSean Hefty 	case IB_CM_REJ_RECEIVED:
1048c5483388SSean Hefty 		cma_modify_qp_err(id_priv);
1049a1b1b61fSSean Hefty 		event.status = ib_event->param.rej_rcvd.reason;
1050a1b1b61fSSean Hefty 		event.event = RDMA_CM_EVENT_REJECTED;
1051a1b1b61fSSean Hefty 		event.param.conn.private_data = ib_event->private_data;
1052a1b1b61fSSean Hefty 		event.param.conn.private_data_len = IB_CM_REJ_PRIVATE_DATA_SIZE;
1053e51060f0SSean Hefty 		break;
1054e51060f0SSean Hefty 	default:
1055468f2239SRoland Dreier 		printk(KERN_ERR "RDMA CMA: unexpected IB CM event: %d\n",
1056e51060f0SSean Hefty 		       ib_event->event);
1057e51060f0SSean Hefty 		goto out;
1058e51060f0SSean Hefty 	}
1059e51060f0SSean Hefty 
1060a1b1b61fSSean Hefty 	ret = id_priv->id.event_handler(&id_priv->id, &event);
1061e51060f0SSean Hefty 	if (ret) {
1062e51060f0SSean Hefty 		/* Destroy the CM ID by returning a non-zero value. */
1063e51060f0SSean Hefty 		id_priv->cm_id.ib = NULL;
1064550e5ca7SNir Muchtar 		cma_exch(id_priv, RDMA_CM_DESTROYING);
1065de910bd9SOr Gerlitz 		mutex_unlock(&id_priv->handler_mutex);
1066e51060f0SSean Hefty 		rdma_destroy_id(&id_priv->id);
1067e51060f0SSean Hefty 		return ret;
1068e51060f0SSean Hefty 	}
1069e51060f0SSean Hefty out:
1070de910bd9SOr Gerlitz 	mutex_unlock(&id_priv->handler_mutex);
1071e51060f0SSean Hefty 	return ret;
1072e51060f0SSean Hefty }
1073e51060f0SSean Hefty 
1074628e5f6dSSean Hefty static struct rdma_id_private *cma_new_conn_id(struct rdma_cm_id *listen_id,
1075e51060f0SSean Hefty 					       struct ib_cm_event *ib_event)
1076e51060f0SSean Hefty {
1077e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
1078e51060f0SSean Hefty 	struct rdma_cm_id *id;
1079e51060f0SSean Hefty 	struct rdma_route *rt;
1080e51060f0SSean Hefty 	union cma_ip_addr *src, *dst;
10811b90c137SAl Viro 	__be16 port;
1082e51060f0SSean Hefty 	u8 ip_ver;
108364c5e613SOr Gerlitz 	int ret;
1084e51060f0SSean Hefty 
1085e51060f0SSean Hefty 	if (cma_get_net_info(ib_event->private_data, listen_id->ps,
1086e51060f0SSean Hefty 			     &ip_ver, &port, &src, &dst))
10870c9361fcSJack Morgenstein 		return NULL;
1088e51060f0SSean Hefty 
10893f168d2bSKrishna Kumar 	id = rdma_create_id(listen_id->event_handler, listen_id->context,
1090b26f9b99SSean Hefty 			    listen_id->ps, ib_event->param.req_rcvd.qp_type);
10913f168d2bSKrishna Kumar 	if (IS_ERR(id))
10920c9361fcSJack Morgenstein 		return NULL;
10933f168d2bSKrishna Kumar 
1094e51060f0SSean Hefty 	cma_save_net_info(&id->route.addr, &listen_id->route.addr,
1095e51060f0SSean Hefty 			  ip_ver, port, src, dst);
10963f168d2bSKrishna Kumar 
10973f168d2bSKrishna Kumar 	rt = &id->route;
10983f168d2bSKrishna Kumar 	rt->num_paths = ib_event->param.req_rcvd.alternate_path ? 2 : 1;
10993f168d2bSKrishna Kumar 	rt->path_rec = kmalloc(sizeof *rt->path_rec * rt->num_paths,
11003f168d2bSKrishna Kumar 			       GFP_KERNEL);
11013f168d2bSKrishna Kumar 	if (!rt->path_rec)
11020c9361fcSJack Morgenstein 		goto err;
11033f168d2bSKrishna Kumar 
1104e51060f0SSean Hefty 	rt->path_rec[0] = *ib_event->param.req_rcvd.primary_path;
1105e51060f0SSean Hefty 	if (rt->num_paths == 2)
1106e51060f0SSean Hefty 		rt->path_rec[1] = *ib_event->param.req_rcvd.alternate_path;
1107e51060f0SSean Hefty 
11086f8372b6SSean Hefty 	if (cma_any_addr((struct sockaddr *) &rt->addr.src_addr)) {
11096f8372b6SSean Hefty 		rt->addr.dev_addr.dev_type = ARPHRD_INFINIBAND;
11106f8372b6SSean Hefty 		rdma_addr_set_sgid(&rt->addr.dev_addr, &rt->path_rec[0].sgid);
11116f8372b6SSean Hefty 		ib_addr_set_pkey(&rt->addr.dev_addr, rt->path_rec[0].pkey);
11126f8372b6SSean Hefty 	} else {
11136f8372b6SSean Hefty 		ret = rdma_translate_ip((struct sockaddr *) &rt->addr.src_addr,
11146f8372b6SSean Hefty 					&rt->addr.dev_addr);
111564c5e613SOr Gerlitz 		if (ret)
11160c9361fcSJack Morgenstein 			goto err;
11176f8372b6SSean Hefty 	}
11186f8372b6SSean Hefty 	rdma_addr_set_dgid(&rt->addr.dev_addr, &rt->path_rec[0].dgid);
1119e51060f0SSean Hefty 
1120e51060f0SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
1121550e5ca7SNir Muchtar 	id_priv->state = RDMA_CM_CONNECT;
1122e51060f0SSean Hefty 	return id_priv;
11233f168d2bSKrishna Kumar 
11243f168d2bSKrishna Kumar err:
11250c9361fcSJack Morgenstein 	rdma_destroy_id(id);
1126e51060f0SSean Hefty 	return NULL;
1127e51060f0SSean Hefty }
1128e51060f0SSean Hefty 
1129628e5f6dSSean Hefty static struct rdma_id_private *cma_new_udp_id(struct rdma_cm_id *listen_id,
1130628e5f6dSSean Hefty 					      struct ib_cm_event *ib_event)
1131628e5f6dSSean Hefty {
1132628e5f6dSSean Hefty 	struct rdma_id_private *id_priv;
1133628e5f6dSSean Hefty 	struct rdma_cm_id *id;
1134628e5f6dSSean Hefty 	union cma_ip_addr *src, *dst;
11351b90c137SAl Viro 	__be16 port;
1136628e5f6dSSean Hefty 	u8 ip_ver;
1137628e5f6dSSean Hefty 	int ret;
1138628e5f6dSSean Hefty 
1139628e5f6dSSean Hefty 	id = rdma_create_id(listen_id->event_handler, listen_id->context,
1140b26f9b99SSean Hefty 			    listen_id->ps, IB_QPT_UD);
1141628e5f6dSSean Hefty 	if (IS_ERR(id))
1142628e5f6dSSean Hefty 		return NULL;
1143628e5f6dSSean Hefty 
1144628e5f6dSSean Hefty 
1145628e5f6dSSean Hefty 	if (cma_get_net_info(ib_event->private_data, listen_id->ps,
1146628e5f6dSSean Hefty 			     &ip_ver, &port, &src, &dst))
1147628e5f6dSSean Hefty 		goto err;
1148628e5f6dSSean Hefty 
1149628e5f6dSSean Hefty 	cma_save_net_info(&id->route.addr, &listen_id->route.addr,
1150628e5f6dSSean Hefty 			  ip_ver, port, src, dst);
1151628e5f6dSSean Hefty 
11526f8372b6SSean Hefty 	if (!cma_any_addr((struct sockaddr *) &id->route.addr.src_addr)) {
11533f446754SRoland Dreier 		ret = rdma_translate_ip((struct sockaddr *) &id->route.addr.src_addr,
1154628e5f6dSSean Hefty 					&id->route.addr.dev_addr);
1155628e5f6dSSean Hefty 		if (ret)
1156628e5f6dSSean Hefty 			goto err;
11576f8372b6SSean Hefty 	}
1158628e5f6dSSean Hefty 
1159628e5f6dSSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
1160550e5ca7SNir Muchtar 	id_priv->state = RDMA_CM_CONNECT;
1161628e5f6dSSean Hefty 	return id_priv;
1162628e5f6dSSean Hefty err:
1163628e5f6dSSean Hefty 	rdma_destroy_id(id);
1164628e5f6dSSean Hefty 	return NULL;
1165628e5f6dSSean Hefty }
1166628e5f6dSSean Hefty 
1167a1b1b61fSSean Hefty static void cma_set_req_event_data(struct rdma_cm_event *event,
1168a1b1b61fSSean Hefty 				   struct ib_cm_req_event_param *req_data,
1169a1b1b61fSSean Hefty 				   void *private_data, int offset)
1170a1b1b61fSSean Hefty {
1171a1b1b61fSSean Hefty 	event->param.conn.private_data = private_data + offset;
1172a1b1b61fSSean Hefty 	event->param.conn.private_data_len = IB_CM_REQ_PRIVATE_DATA_SIZE - offset;
1173a1b1b61fSSean Hefty 	event->param.conn.responder_resources = req_data->responder_resources;
1174a1b1b61fSSean Hefty 	event->param.conn.initiator_depth = req_data->initiator_depth;
1175a1b1b61fSSean Hefty 	event->param.conn.flow_control = req_data->flow_control;
1176a1b1b61fSSean Hefty 	event->param.conn.retry_count = req_data->retry_count;
1177a1b1b61fSSean Hefty 	event->param.conn.rnr_retry_count = req_data->rnr_retry_count;
1178a1b1b61fSSean Hefty 	event->param.conn.srq = req_data->srq;
1179a1b1b61fSSean Hefty 	event->param.conn.qp_num = req_data->remote_qpn;
1180a1b1b61fSSean Hefty }
1181a1b1b61fSSean Hefty 
1182e51060f0SSean Hefty static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
1183e51060f0SSean Hefty {
1184e51060f0SSean Hefty 	struct rdma_id_private *listen_id, *conn_id;
1185a1b1b61fSSean Hefty 	struct rdma_cm_event event;
1186e51060f0SSean Hefty 	int offset, ret;
1187e51060f0SSean Hefty 
1188e51060f0SSean Hefty 	listen_id = cm_id->context;
1189550e5ca7SNir Muchtar 	if (cma_disable_callback(listen_id, RDMA_CM_LISTEN))
11908aa08602SSean Hefty 		return -ECONNABORTED;
1191e51060f0SSean Hefty 
1192628e5f6dSSean Hefty 	memset(&event, 0, sizeof event);
1193628e5f6dSSean Hefty 	offset = cma_user_data_offset(listen_id->id.ps);
1194628e5f6dSSean Hefty 	event.event = RDMA_CM_EVENT_CONNECT_REQUEST;
1195b26f9b99SSean Hefty 	if (listen_id->id.qp_type == IB_QPT_UD) {
1196628e5f6dSSean Hefty 		conn_id = cma_new_udp_id(&listen_id->id, ib_event);
1197628e5f6dSSean Hefty 		event.param.ud.private_data = ib_event->private_data + offset;
1198628e5f6dSSean Hefty 		event.param.ud.private_data_len =
1199628e5f6dSSean Hefty 				IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE - offset;
1200628e5f6dSSean Hefty 	} else {
1201628e5f6dSSean Hefty 		conn_id = cma_new_conn_id(&listen_id->id, ib_event);
1202628e5f6dSSean Hefty 		cma_set_req_event_data(&event, &ib_event->param.req_rcvd,
1203628e5f6dSSean Hefty 				       ib_event->private_data, offset);
1204628e5f6dSSean Hefty 	}
1205e51060f0SSean Hefty 	if (!conn_id) {
1206e51060f0SSean Hefty 		ret = -ENOMEM;
1207e51060f0SSean Hefty 		goto out;
1208e51060f0SSean Hefty 	}
1209e51060f0SSean Hefty 
1210de910bd9SOr Gerlitz 	mutex_lock_nested(&conn_id->handler_mutex, SINGLE_DEPTH_NESTING);
121107ebafbaSTom Tucker 	ret = cma_acquire_dev(conn_id);
1212a1a733f6SKrishna Kumar 	if (ret)
1213a1a733f6SKrishna Kumar 		goto release_conn_id;
1214e51060f0SSean Hefty 
1215e51060f0SSean Hefty 	conn_id->cm_id.ib = cm_id;
1216e51060f0SSean Hefty 	cm_id->context = conn_id;
1217e51060f0SSean Hefty 	cm_id->cm_handler = cma_ib_handler;
1218e51060f0SSean Hefty 
121925ae21a1SSean Hefty 	/*
122025ae21a1SSean Hefty 	 * Protect against the user destroying conn_id from another thread
122125ae21a1SSean Hefty 	 * until we're done accessing it.
122225ae21a1SSean Hefty 	 */
122325ae21a1SSean Hefty 	atomic_inc(&conn_id->refcount);
1224a1b1b61fSSean Hefty 	ret = conn_id->id.event_handler(&conn_id->id, &event);
122545d9478dSVladimir Sokolovsky 	if (!ret) {
1226ead595aeSSean Hefty 		/*
1227ead595aeSSean Hefty 		 * Acquire mutex to prevent user executing rdma_destroy_id()
1228ead595aeSSean Hefty 		 * while we're accessing the cm_id.
1229ead595aeSSean Hefty 		 */
1230ead595aeSSean Hefty 		mutex_lock(&lock);
1231b26f9b99SSean Hefty 		if (cma_comp(conn_id, RDMA_CM_CONNECT) && (conn_id->id.qp_type != IB_QPT_UD))
1232ead595aeSSean Hefty 			ib_send_cm_mra(cm_id, CMA_CM_MRA_SETTING, NULL, 0);
1233ead595aeSSean Hefty 		mutex_unlock(&lock);
1234de910bd9SOr Gerlitz 		mutex_unlock(&conn_id->handler_mutex);
123525ae21a1SSean Hefty 		cma_deref_id(conn_id);
1236a1a733f6SKrishna Kumar 		goto out;
123745d9478dSVladimir Sokolovsky 	}
123825ae21a1SSean Hefty 	cma_deref_id(conn_id);
1239a1a733f6SKrishna Kumar 
1240e51060f0SSean Hefty 	/* Destroy the CM ID by returning a non-zero value. */
1241e51060f0SSean Hefty 	conn_id->cm_id.ib = NULL;
1242a1a733f6SKrishna Kumar 
1243a1a733f6SKrishna Kumar release_conn_id:
1244550e5ca7SNir Muchtar 	cma_exch(conn_id, RDMA_CM_DESTROYING);
1245de910bd9SOr Gerlitz 	mutex_unlock(&conn_id->handler_mutex);
1246e51060f0SSean Hefty 	rdma_destroy_id(&conn_id->id);
1247a1a733f6SKrishna Kumar 
1248e51060f0SSean Hefty out:
1249de910bd9SOr Gerlitz 	mutex_unlock(&listen_id->handler_mutex);
1250e51060f0SSean Hefty 	return ret;
1251e51060f0SSean Hefty }
1252e51060f0SSean Hefty 
1253e51060f0SSean Hefty static __be64 cma_get_service_id(enum rdma_port_space ps, struct sockaddr *addr)
1254e51060f0SSean Hefty {
1255628e5f6dSSean Hefty 	return cpu_to_be64(((u64)ps << 16) + be16_to_cpu(cma_port(addr)));
1256e51060f0SSean Hefty }
1257e51060f0SSean Hefty 
1258e51060f0SSean Hefty static void cma_set_compare_data(enum rdma_port_space ps, struct sockaddr *addr,
1259e51060f0SSean Hefty 				 struct ib_cm_compare_data *compare)
1260e51060f0SSean Hefty {
1261e51060f0SSean Hefty 	struct cma_hdr *cma_data, *cma_mask;
1262e51060f0SSean Hefty 	struct sdp_hh *sdp_data, *sdp_mask;
12631b90c137SAl Viro 	__be32 ip4_addr;
1264e51060f0SSean Hefty 	struct in6_addr ip6_addr;
1265e51060f0SSean Hefty 
1266e51060f0SSean Hefty 	memset(compare, 0, sizeof *compare);
1267e51060f0SSean Hefty 	cma_data = (void *) compare->data;
1268e51060f0SSean Hefty 	cma_mask = (void *) compare->mask;
1269e51060f0SSean Hefty 	sdp_data = (void *) compare->data;
1270e51060f0SSean Hefty 	sdp_mask = (void *) compare->mask;
1271e51060f0SSean Hefty 
1272e51060f0SSean Hefty 	switch (addr->sa_family) {
1273e51060f0SSean Hefty 	case AF_INET:
1274e51060f0SSean Hefty 		ip4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
1275e51060f0SSean Hefty 		if (ps == RDMA_PS_SDP) {
1276e51060f0SSean Hefty 			sdp_set_ip_ver(sdp_data, 4);
1277e51060f0SSean Hefty 			sdp_set_ip_ver(sdp_mask, 0xF);
1278e51060f0SSean Hefty 			sdp_data->dst_addr.ip4.addr = ip4_addr;
12791b90c137SAl Viro 			sdp_mask->dst_addr.ip4.addr = htonl(~0);
1280e51060f0SSean Hefty 		} else {
1281e51060f0SSean Hefty 			cma_set_ip_ver(cma_data, 4);
1282e51060f0SSean Hefty 			cma_set_ip_ver(cma_mask, 0xF);
1283e51060f0SSean Hefty 			cma_data->dst_addr.ip4.addr = ip4_addr;
12841b90c137SAl Viro 			cma_mask->dst_addr.ip4.addr = htonl(~0);
1285e51060f0SSean Hefty 		}
1286e51060f0SSean Hefty 		break;
1287e51060f0SSean Hefty 	case AF_INET6:
1288e51060f0SSean Hefty 		ip6_addr = ((struct sockaddr_in6 *) addr)->sin6_addr;
1289e51060f0SSean Hefty 		if (ps == RDMA_PS_SDP) {
1290e51060f0SSean Hefty 			sdp_set_ip_ver(sdp_data, 6);
1291e51060f0SSean Hefty 			sdp_set_ip_ver(sdp_mask, 0xF);
1292e51060f0SSean Hefty 			sdp_data->dst_addr.ip6 = ip6_addr;
1293e51060f0SSean Hefty 			memset(&sdp_mask->dst_addr.ip6, 0xFF,
1294e51060f0SSean Hefty 			       sizeof sdp_mask->dst_addr.ip6);
1295e51060f0SSean Hefty 		} else {
1296e51060f0SSean Hefty 			cma_set_ip_ver(cma_data, 6);
1297e51060f0SSean Hefty 			cma_set_ip_ver(cma_mask, 0xF);
1298e51060f0SSean Hefty 			cma_data->dst_addr.ip6 = ip6_addr;
1299e51060f0SSean Hefty 			memset(&cma_mask->dst_addr.ip6, 0xFF,
1300e51060f0SSean Hefty 			       sizeof cma_mask->dst_addr.ip6);
1301e51060f0SSean Hefty 		}
1302e51060f0SSean Hefty 		break;
1303e51060f0SSean Hefty 	default:
1304e51060f0SSean Hefty 		break;
1305e51060f0SSean Hefty 	}
1306e51060f0SSean Hefty }
1307e51060f0SSean Hefty 
130807ebafbaSTom Tucker static int cma_iw_handler(struct iw_cm_id *iw_id, struct iw_cm_event *iw_event)
130907ebafbaSTom Tucker {
131007ebafbaSTom Tucker 	struct rdma_id_private *id_priv = iw_id->context;
1311a1b1b61fSSean Hefty 	struct rdma_cm_event event;
131207ebafbaSTom Tucker 	struct sockaddr_in *sin;
131307ebafbaSTom Tucker 	int ret = 0;
131407ebafbaSTom Tucker 
1315550e5ca7SNir Muchtar 	if (cma_disable_callback(id_priv, RDMA_CM_CONNECT))
1316be65f086SSean Hefty 		return 0;
131707ebafbaSTom Tucker 
1318be65f086SSean Hefty 	memset(&event, 0, sizeof event);
131907ebafbaSTom Tucker 	switch (iw_event->event) {
132007ebafbaSTom Tucker 	case IW_CM_EVENT_CLOSE:
1321a1b1b61fSSean Hefty 		event.event = RDMA_CM_EVENT_DISCONNECTED;
132207ebafbaSTom Tucker 		break;
132307ebafbaSTom Tucker 	case IW_CM_EVENT_CONNECT_REPLY:
132407ebafbaSTom Tucker 		sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr;
132507ebafbaSTom Tucker 		*sin = iw_event->local_addr;
132607ebafbaSTom Tucker 		sin = (struct sockaddr_in *) &id_priv->id.route.addr.dst_addr;
132707ebafbaSTom Tucker 		*sin = iw_event->remote_addr;
1328881a045fSSteve Wise 		switch (iw_event->status) {
1329881a045fSSteve Wise 		case 0:
1330a1b1b61fSSean Hefty 			event.event = RDMA_CM_EVENT_ESTABLISHED;
133107ebafbaSTom Tucker 			break;
1332881a045fSSteve Wise 		case -ECONNRESET:
1333881a045fSSteve Wise 		case -ECONNREFUSED:
1334881a045fSSteve Wise 			event.event = RDMA_CM_EVENT_REJECTED;
1335881a045fSSteve Wise 			break;
1336881a045fSSteve Wise 		case -ETIMEDOUT:
1337881a045fSSteve Wise 			event.event = RDMA_CM_EVENT_UNREACHABLE;
1338881a045fSSteve Wise 			break;
1339881a045fSSteve Wise 		default:
1340881a045fSSteve Wise 			event.event = RDMA_CM_EVENT_CONNECT_ERROR;
1341881a045fSSteve Wise 			break;
1342881a045fSSteve Wise 		}
1343881a045fSSteve Wise 		break;
134407ebafbaSTom Tucker 	case IW_CM_EVENT_ESTABLISHED:
1345a1b1b61fSSean Hefty 		event.event = RDMA_CM_EVENT_ESTABLISHED;
134607ebafbaSTom Tucker 		break;
134707ebafbaSTom Tucker 	default:
134807ebafbaSTom Tucker 		BUG_ON(1);
134907ebafbaSTom Tucker 	}
135007ebafbaSTom Tucker 
1351a1b1b61fSSean Hefty 	event.status = iw_event->status;
1352a1b1b61fSSean Hefty 	event.param.conn.private_data = iw_event->private_data;
1353a1b1b61fSSean Hefty 	event.param.conn.private_data_len = iw_event->private_data_len;
1354a1b1b61fSSean Hefty 	ret = id_priv->id.event_handler(&id_priv->id, &event);
135507ebafbaSTom Tucker 	if (ret) {
135607ebafbaSTom Tucker 		/* Destroy the CM ID by returning a non-zero value. */
135707ebafbaSTom Tucker 		id_priv->cm_id.iw = NULL;
1358550e5ca7SNir Muchtar 		cma_exch(id_priv, RDMA_CM_DESTROYING);
1359de910bd9SOr Gerlitz 		mutex_unlock(&id_priv->handler_mutex);
136007ebafbaSTom Tucker 		rdma_destroy_id(&id_priv->id);
136107ebafbaSTom Tucker 		return ret;
136207ebafbaSTom Tucker 	}
136307ebafbaSTom Tucker 
1364de910bd9SOr Gerlitz 	mutex_unlock(&id_priv->handler_mutex);
136507ebafbaSTom Tucker 	return ret;
136607ebafbaSTom Tucker }
136707ebafbaSTom Tucker 
136807ebafbaSTom Tucker static int iw_conn_req_handler(struct iw_cm_id *cm_id,
136907ebafbaSTom Tucker 			       struct iw_cm_event *iw_event)
137007ebafbaSTom Tucker {
137107ebafbaSTom Tucker 	struct rdma_cm_id *new_cm_id;
137207ebafbaSTom Tucker 	struct rdma_id_private *listen_id, *conn_id;
137307ebafbaSTom Tucker 	struct sockaddr_in *sin;
137407ebafbaSTom Tucker 	struct net_device *dev = NULL;
1375a1b1b61fSSean Hefty 	struct rdma_cm_event event;
137607ebafbaSTom Tucker 	int ret;
13778d8293cfSSteve Wise 	struct ib_device_attr attr;
137807ebafbaSTom Tucker 
137907ebafbaSTom Tucker 	listen_id = cm_id->context;
1380550e5ca7SNir Muchtar 	if (cma_disable_callback(listen_id, RDMA_CM_LISTEN))
13818aa08602SSean Hefty 		return -ECONNABORTED;
138207ebafbaSTom Tucker 
138307ebafbaSTom Tucker 	/* Create a new RDMA id for the new IW CM ID */
138407ebafbaSTom Tucker 	new_cm_id = rdma_create_id(listen_id->id.event_handler,
138507ebafbaSTom Tucker 				   listen_id->id.context,
1386b26f9b99SSean Hefty 				   RDMA_PS_TCP, IB_QPT_RC);
138710f32065SJulia Lawall 	if (IS_ERR(new_cm_id)) {
138807ebafbaSTom Tucker 		ret = -ENOMEM;
138907ebafbaSTom Tucker 		goto out;
139007ebafbaSTom Tucker 	}
139107ebafbaSTom Tucker 	conn_id = container_of(new_cm_id, struct rdma_id_private, id);
1392de910bd9SOr Gerlitz 	mutex_lock_nested(&conn_id->handler_mutex, SINGLE_DEPTH_NESTING);
1393550e5ca7SNir Muchtar 	conn_id->state = RDMA_CM_CONNECT;
139407ebafbaSTom Tucker 
13951ab35276SDenis V. Lunev 	dev = ip_dev_find(&init_net, iw_event->local_addr.sin_addr.s_addr);
139607ebafbaSTom Tucker 	if (!dev) {
139707ebafbaSTom Tucker 		ret = -EADDRNOTAVAIL;
1398de910bd9SOr Gerlitz 		mutex_unlock(&conn_id->handler_mutex);
139907ebafbaSTom Tucker 		rdma_destroy_id(new_cm_id);
140007ebafbaSTom Tucker 		goto out;
140107ebafbaSTom Tucker 	}
140207ebafbaSTom Tucker 	ret = rdma_copy_addr(&conn_id->id.route.addr.dev_addr, dev, NULL);
140307ebafbaSTom Tucker 	if (ret) {
1404de910bd9SOr Gerlitz 		mutex_unlock(&conn_id->handler_mutex);
140507ebafbaSTom Tucker 		rdma_destroy_id(new_cm_id);
140607ebafbaSTom Tucker 		goto out;
140707ebafbaSTom Tucker 	}
140807ebafbaSTom Tucker 
140907ebafbaSTom Tucker 	ret = cma_acquire_dev(conn_id);
141007ebafbaSTom Tucker 	if (ret) {
1411de910bd9SOr Gerlitz 		mutex_unlock(&conn_id->handler_mutex);
141207ebafbaSTom Tucker 		rdma_destroy_id(new_cm_id);
141307ebafbaSTom Tucker 		goto out;
141407ebafbaSTom Tucker 	}
141507ebafbaSTom Tucker 
141607ebafbaSTom Tucker 	conn_id->cm_id.iw = cm_id;
141707ebafbaSTom Tucker 	cm_id->context = conn_id;
141807ebafbaSTom Tucker 	cm_id->cm_handler = cma_iw_handler;
141907ebafbaSTom Tucker 
142007ebafbaSTom Tucker 	sin = (struct sockaddr_in *) &new_cm_id->route.addr.src_addr;
142107ebafbaSTom Tucker 	*sin = iw_event->local_addr;
142207ebafbaSTom Tucker 	sin = (struct sockaddr_in *) &new_cm_id->route.addr.dst_addr;
142307ebafbaSTom Tucker 	*sin = iw_event->remote_addr;
142407ebafbaSTom Tucker 
14258d8293cfSSteve Wise 	ret = ib_query_device(conn_id->id.device, &attr);
14268d8293cfSSteve Wise 	if (ret) {
1427de910bd9SOr Gerlitz 		mutex_unlock(&conn_id->handler_mutex);
14288d8293cfSSteve Wise 		rdma_destroy_id(new_cm_id);
14298d8293cfSSteve Wise 		goto out;
14308d8293cfSSteve Wise 	}
14318d8293cfSSteve Wise 
1432a1b1b61fSSean Hefty 	memset(&event, 0, sizeof event);
1433a1b1b61fSSean Hefty 	event.event = RDMA_CM_EVENT_CONNECT_REQUEST;
1434a1b1b61fSSean Hefty 	event.param.conn.private_data = iw_event->private_data;
1435a1b1b61fSSean Hefty 	event.param.conn.private_data_len = iw_event->private_data_len;
14368d8293cfSSteve Wise 	event.param.conn.initiator_depth = attr.max_qp_init_rd_atom;
14378d8293cfSSteve Wise 	event.param.conn.responder_resources = attr.max_qp_rd_atom;
143825ae21a1SSean Hefty 
143925ae21a1SSean Hefty 	/*
144025ae21a1SSean Hefty 	 * Protect against the user destroying conn_id from another thread
144125ae21a1SSean Hefty 	 * until we're done accessing it.
144225ae21a1SSean Hefty 	 */
144325ae21a1SSean Hefty 	atomic_inc(&conn_id->refcount);
1444a1b1b61fSSean Hefty 	ret = conn_id->id.event_handler(&conn_id->id, &event);
144507ebafbaSTom Tucker 	if (ret) {
144607ebafbaSTom Tucker 		/* User wants to destroy the CM ID */
144707ebafbaSTom Tucker 		conn_id->cm_id.iw = NULL;
1448550e5ca7SNir Muchtar 		cma_exch(conn_id, RDMA_CM_DESTROYING);
1449de910bd9SOr Gerlitz 		mutex_unlock(&conn_id->handler_mutex);
145025ae21a1SSean Hefty 		cma_deref_id(conn_id);
145107ebafbaSTom Tucker 		rdma_destroy_id(&conn_id->id);
1452de910bd9SOr Gerlitz 		goto out;
145307ebafbaSTom Tucker 	}
145407ebafbaSTom Tucker 
1455de910bd9SOr Gerlitz 	mutex_unlock(&conn_id->handler_mutex);
145625ae21a1SSean Hefty 	cma_deref_id(conn_id);
1457de910bd9SOr Gerlitz 
145807ebafbaSTom Tucker out:
145907ebafbaSTom Tucker 	if (dev)
146007ebafbaSTom Tucker 		dev_put(dev);
1461de910bd9SOr Gerlitz 	mutex_unlock(&listen_id->handler_mutex);
146207ebafbaSTom Tucker 	return ret;
146307ebafbaSTom Tucker }
146407ebafbaSTom Tucker 
1465e51060f0SSean Hefty static int cma_ib_listen(struct rdma_id_private *id_priv)
1466e51060f0SSean Hefty {
1467e51060f0SSean Hefty 	struct ib_cm_compare_data compare_data;
1468e51060f0SSean Hefty 	struct sockaddr *addr;
14690c9361fcSJack Morgenstein 	struct ib_cm_id	*id;
1470e51060f0SSean Hefty 	__be64 svc_id;
1471e51060f0SSean Hefty 	int ret;
1472e51060f0SSean Hefty 
14730c9361fcSJack Morgenstein 	id = ib_create_cm_id(id_priv->id.device, cma_req_handler, id_priv);
14740c9361fcSJack Morgenstein 	if (IS_ERR(id))
14750c9361fcSJack Morgenstein 		return PTR_ERR(id);
14760c9361fcSJack Morgenstein 
14770c9361fcSJack Morgenstein 	id_priv->cm_id.ib = id;
1478e51060f0SSean Hefty 
14793f446754SRoland Dreier 	addr = (struct sockaddr *) &id_priv->id.route.addr.src_addr;
1480e51060f0SSean Hefty 	svc_id = cma_get_service_id(id_priv->id.ps, addr);
1481e51060f0SSean Hefty 	if (cma_any_addr(addr))
1482e51060f0SSean Hefty 		ret = ib_cm_listen(id_priv->cm_id.ib, svc_id, 0, NULL);
1483e51060f0SSean Hefty 	else {
1484e51060f0SSean Hefty 		cma_set_compare_data(id_priv->id.ps, addr, &compare_data);
1485e51060f0SSean Hefty 		ret = ib_cm_listen(id_priv->cm_id.ib, svc_id, 0, &compare_data);
1486e51060f0SSean Hefty 	}
1487e51060f0SSean Hefty 
1488e51060f0SSean Hefty 	if (ret) {
1489e51060f0SSean Hefty 		ib_destroy_cm_id(id_priv->cm_id.ib);
1490e51060f0SSean Hefty 		id_priv->cm_id.ib = NULL;
1491e51060f0SSean Hefty 	}
1492e51060f0SSean Hefty 
1493e51060f0SSean Hefty 	return ret;
1494e51060f0SSean Hefty }
1495e51060f0SSean Hefty 
149607ebafbaSTom Tucker static int cma_iw_listen(struct rdma_id_private *id_priv, int backlog)
149707ebafbaSTom Tucker {
149807ebafbaSTom Tucker 	int ret;
149907ebafbaSTom Tucker 	struct sockaddr_in *sin;
15000c9361fcSJack Morgenstein 	struct iw_cm_id	*id;
150107ebafbaSTom Tucker 
15020c9361fcSJack Morgenstein 	id = iw_create_cm_id(id_priv->id.device,
150307ebafbaSTom Tucker 			     iw_conn_req_handler,
150407ebafbaSTom Tucker 			     id_priv);
15050c9361fcSJack Morgenstein 	if (IS_ERR(id))
15060c9361fcSJack Morgenstein 		return PTR_ERR(id);
15070c9361fcSJack Morgenstein 
15080c9361fcSJack Morgenstein 	id_priv->cm_id.iw = id;
150907ebafbaSTom Tucker 
151007ebafbaSTom Tucker 	sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr;
151107ebafbaSTom Tucker 	id_priv->cm_id.iw->local_addr = *sin;
151207ebafbaSTom Tucker 
151307ebafbaSTom Tucker 	ret = iw_cm_listen(id_priv->cm_id.iw, backlog);
151407ebafbaSTom Tucker 
151507ebafbaSTom Tucker 	if (ret) {
151607ebafbaSTom Tucker 		iw_destroy_cm_id(id_priv->cm_id.iw);
151707ebafbaSTom Tucker 		id_priv->cm_id.iw = NULL;
151807ebafbaSTom Tucker 	}
151907ebafbaSTom Tucker 
152007ebafbaSTom Tucker 	return ret;
152107ebafbaSTom Tucker }
152207ebafbaSTom Tucker 
1523e51060f0SSean Hefty static int cma_listen_handler(struct rdma_cm_id *id,
1524e51060f0SSean Hefty 			      struct rdma_cm_event *event)
1525e51060f0SSean Hefty {
1526e51060f0SSean Hefty 	struct rdma_id_private *id_priv = id->context;
1527e51060f0SSean Hefty 
1528e51060f0SSean Hefty 	id->context = id_priv->id.context;
1529e51060f0SSean Hefty 	id->event_handler = id_priv->id.event_handler;
1530e51060f0SSean Hefty 	return id_priv->id.event_handler(id, event);
1531e51060f0SSean Hefty }
1532e51060f0SSean Hefty 
1533e51060f0SSean Hefty static void cma_listen_on_dev(struct rdma_id_private *id_priv,
1534e51060f0SSean Hefty 			      struct cma_device *cma_dev)
1535e51060f0SSean Hefty {
1536e51060f0SSean Hefty 	struct rdma_id_private *dev_id_priv;
1537e51060f0SSean Hefty 	struct rdma_cm_id *id;
1538e51060f0SSean Hefty 	int ret;
1539e51060f0SSean Hefty 
1540b26f9b99SSean Hefty 	id = rdma_create_id(cma_listen_handler, id_priv, id_priv->id.ps,
1541b26f9b99SSean Hefty 			    id_priv->id.qp_type);
1542e51060f0SSean Hefty 	if (IS_ERR(id))
1543e51060f0SSean Hefty 		return;
1544e51060f0SSean Hefty 
1545e51060f0SSean Hefty 	dev_id_priv = container_of(id, struct rdma_id_private, id);
1546e51060f0SSean Hefty 
1547550e5ca7SNir Muchtar 	dev_id_priv->state = RDMA_CM_ADDR_BOUND;
1548e51060f0SSean Hefty 	memcpy(&id->route.addr.src_addr, &id_priv->id.route.addr.src_addr,
15493f446754SRoland Dreier 	       ip_addr_size((struct sockaddr *) &id_priv->id.route.addr.src_addr));
1550e51060f0SSean Hefty 
1551e51060f0SSean Hefty 	cma_attach_to_dev(dev_id_priv, cma_dev);
1552e51060f0SSean Hefty 	list_add_tail(&dev_id_priv->listen_list, &id_priv->listen_list);
1553d02d1f53SSean Hefty 	atomic_inc(&id_priv->refcount);
1554d02d1f53SSean Hefty 	dev_id_priv->internal_id = 1;
1555e51060f0SSean Hefty 
1556e51060f0SSean Hefty 	ret = rdma_listen(id, id_priv->backlog);
1557e51060f0SSean Hefty 	if (ret)
1558d02d1f53SSean Hefty 		printk(KERN_WARNING "RDMA CMA: cma_listen_on_dev, error %d, "
1559468f2239SRoland Dreier 		       "listening on device %s\n", ret, cma_dev->device->name);
1560e51060f0SSean Hefty }
1561e51060f0SSean Hefty 
1562e51060f0SSean Hefty static void cma_listen_on_all(struct rdma_id_private *id_priv)
1563e51060f0SSean Hefty {
1564e51060f0SSean Hefty 	struct cma_device *cma_dev;
1565e51060f0SSean Hefty 
1566e51060f0SSean Hefty 	mutex_lock(&lock);
1567e51060f0SSean Hefty 	list_add_tail(&id_priv->list, &listen_any_list);
1568e51060f0SSean Hefty 	list_for_each_entry(cma_dev, &dev_list, list)
1569e51060f0SSean Hefty 		cma_listen_on_dev(id_priv, cma_dev);
1570e51060f0SSean Hefty 	mutex_unlock(&lock);
1571e51060f0SSean Hefty }
1572e51060f0SSean Hefty 
1573a81c994dSSean Hefty void rdma_set_service_type(struct rdma_cm_id *id, int tos)
1574a81c994dSSean Hefty {
1575a81c994dSSean Hefty 	struct rdma_id_private *id_priv;
1576a81c994dSSean Hefty 
1577a81c994dSSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
1578a81c994dSSean Hefty 	id_priv->tos = (u8) tos;
1579a81c994dSSean Hefty }
1580a81c994dSSean Hefty EXPORT_SYMBOL(rdma_set_service_type);
1581a81c994dSSean Hefty 
1582e51060f0SSean Hefty static void cma_query_handler(int status, struct ib_sa_path_rec *path_rec,
1583e51060f0SSean Hefty 			      void *context)
1584e51060f0SSean Hefty {
1585e51060f0SSean Hefty 	struct cma_work *work = context;
1586e51060f0SSean Hefty 	struct rdma_route *route;
1587e51060f0SSean Hefty 
1588e51060f0SSean Hefty 	route = &work->id->id.route;
1589e51060f0SSean Hefty 
1590e51060f0SSean Hefty 	if (!status) {
1591e51060f0SSean Hefty 		route->num_paths = 1;
1592e51060f0SSean Hefty 		*route->path_rec = *path_rec;
1593e51060f0SSean Hefty 	} else {
1594550e5ca7SNir Muchtar 		work->old_state = RDMA_CM_ROUTE_QUERY;
1595550e5ca7SNir Muchtar 		work->new_state = RDMA_CM_ADDR_RESOLVED;
1596e51060f0SSean Hefty 		work->event.event = RDMA_CM_EVENT_ROUTE_ERROR;
15978f0472d3SSean Hefty 		work->event.status = status;
1598e51060f0SSean Hefty 	}
1599e51060f0SSean Hefty 
1600e51060f0SSean Hefty 	queue_work(cma_wq, &work->work);
1601e51060f0SSean Hefty }
1602e51060f0SSean Hefty 
1603e51060f0SSean Hefty static int cma_query_ib_route(struct rdma_id_private *id_priv, int timeout_ms,
1604e51060f0SSean Hefty 			      struct cma_work *work)
1605e51060f0SSean Hefty {
1606a81c994dSSean Hefty 	struct rdma_addr *addr = &id_priv->id.route.addr;
1607e51060f0SSean Hefty 	struct ib_sa_path_rec path_rec;
1608a81c994dSSean Hefty 	ib_sa_comp_mask comp_mask;
1609a81c994dSSean Hefty 	struct sockaddr_in6 *sin6;
1610e51060f0SSean Hefty 
1611e51060f0SSean Hefty 	memset(&path_rec, 0, sizeof path_rec);
16126f8372b6SSean Hefty 	rdma_addr_get_sgid(&addr->dev_addr, &path_rec.sgid);
16136f8372b6SSean Hefty 	rdma_addr_get_dgid(&addr->dev_addr, &path_rec.dgid);
1614a81c994dSSean Hefty 	path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(&addr->dev_addr));
1615e51060f0SSean Hefty 	path_rec.numb_path = 1;
1616962063e6SSean Hefty 	path_rec.reversible = 1;
16173f446754SRoland Dreier 	path_rec.service_id = cma_get_service_id(id_priv->id.ps,
16183f446754SRoland Dreier 							(struct sockaddr *) &addr->dst_addr);
1619a81c994dSSean Hefty 
1620a81c994dSSean Hefty 	comp_mask = IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID |
1621a81c994dSSean Hefty 		    IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH |
1622a81c994dSSean Hefty 		    IB_SA_PATH_REC_REVERSIBLE | IB_SA_PATH_REC_SERVICE_ID;
1623a81c994dSSean Hefty 
16243f446754SRoland Dreier 	if (addr->src_addr.ss_family == AF_INET) {
1625a81c994dSSean Hefty 		path_rec.qos_class = cpu_to_be16((u16) id_priv->tos);
1626a81c994dSSean Hefty 		comp_mask |= IB_SA_PATH_REC_QOS_CLASS;
1627a81c994dSSean Hefty 	} else {
1628a81c994dSSean Hefty 		sin6 = (struct sockaddr_in6 *) &addr->src_addr;
1629a81c994dSSean Hefty 		path_rec.traffic_class = (u8) (be32_to_cpu(sin6->sin6_flowinfo) >> 20);
1630a81c994dSSean Hefty 		comp_mask |= IB_SA_PATH_REC_TRAFFIC_CLASS;
1631a81c994dSSean Hefty 	}
1632e51060f0SSean Hefty 
1633c1a0b23bSMichael S. Tsirkin 	id_priv->query_id = ib_sa_path_rec_get(&sa_client, id_priv->id.device,
1634e51060f0SSean Hefty 					       id_priv->id.port_num, &path_rec,
1635a81c994dSSean Hefty 					       comp_mask, timeout_ms,
1636a81c994dSSean Hefty 					       GFP_KERNEL, cma_query_handler,
1637a81c994dSSean Hefty 					       work, &id_priv->query);
1638e51060f0SSean Hefty 
1639e51060f0SSean Hefty 	return (id_priv->query_id < 0) ? id_priv->query_id : 0;
1640e51060f0SSean Hefty }
1641e51060f0SSean Hefty 
1642c4028958SDavid Howells static void cma_work_handler(struct work_struct *_work)
1643e51060f0SSean Hefty {
1644c4028958SDavid Howells 	struct cma_work *work = container_of(_work, struct cma_work, work);
1645e51060f0SSean Hefty 	struct rdma_id_private *id_priv = work->id;
1646e51060f0SSean Hefty 	int destroy = 0;
1647e51060f0SSean Hefty 
1648de910bd9SOr Gerlitz 	mutex_lock(&id_priv->handler_mutex);
1649e51060f0SSean Hefty 	if (!cma_comp_exch(id_priv, work->old_state, work->new_state))
1650e51060f0SSean Hefty 		goto out;
1651e51060f0SSean Hefty 
1652e51060f0SSean Hefty 	if (id_priv->id.event_handler(&id_priv->id, &work->event)) {
1653550e5ca7SNir Muchtar 		cma_exch(id_priv, RDMA_CM_DESTROYING);
1654e51060f0SSean Hefty 		destroy = 1;
1655e51060f0SSean Hefty 	}
1656e51060f0SSean Hefty out:
1657de910bd9SOr Gerlitz 	mutex_unlock(&id_priv->handler_mutex);
1658e51060f0SSean Hefty 	cma_deref_id(id_priv);
1659e51060f0SSean Hefty 	if (destroy)
1660e51060f0SSean Hefty 		rdma_destroy_id(&id_priv->id);
1661e51060f0SSean Hefty 	kfree(work);
1662e51060f0SSean Hefty }
1663e51060f0SSean Hefty 
1664dd5bdff8SOr Gerlitz static void cma_ndev_work_handler(struct work_struct *_work)
1665dd5bdff8SOr Gerlitz {
1666dd5bdff8SOr Gerlitz 	struct cma_ndev_work *work = container_of(_work, struct cma_ndev_work, work);
1667dd5bdff8SOr Gerlitz 	struct rdma_id_private *id_priv = work->id;
1668dd5bdff8SOr Gerlitz 	int destroy = 0;
1669dd5bdff8SOr Gerlitz 
1670dd5bdff8SOr Gerlitz 	mutex_lock(&id_priv->handler_mutex);
1671550e5ca7SNir Muchtar 	if (id_priv->state == RDMA_CM_DESTROYING ||
1672550e5ca7SNir Muchtar 	    id_priv->state == RDMA_CM_DEVICE_REMOVAL)
1673dd5bdff8SOr Gerlitz 		goto out;
1674dd5bdff8SOr Gerlitz 
1675dd5bdff8SOr Gerlitz 	if (id_priv->id.event_handler(&id_priv->id, &work->event)) {
1676550e5ca7SNir Muchtar 		cma_exch(id_priv, RDMA_CM_DESTROYING);
1677dd5bdff8SOr Gerlitz 		destroy = 1;
1678dd5bdff8SOr Gerlitz 	}
1679dd5bdff8SOr Gerlitz 
1680dd5bdff8SOr Gerlitz out:
1681dd5bdff8SOr Gerlitz 	mutex_unlock(&id_priv->handler_mutex);
1682dd5bdff8SOr Gerlitz 	cma_deref_id(id_priv);
1683dd5bdff8SOr Gerlitz 	if (destroy)
1684dd5bdff8SOr Gerlitz 		rdma_destroy_id(&id_priv->id);
1685dd5bdff8SOr Gerlitz 	kfree(work);
1686dd5bdff8SOr Gerlitz }
1687dd5bdff8SOr Gerlitz 
1688e51060f0SSean Hefty static int cma_resolve_ib_route(struct rdma_id_private *id_priv, int timeout_ms)
1689e51060f0SSean Hefty {
1690e51060f0SSean Hefty 	struct rdma_route *route = &id_priv->id.route;
1691e51060f0SSean Hefty 	struct cma_work *work;
1692e51060f0SSean Hefty 	int ret;
1693e51060f0SSean Hefty 
1694e51060f0SSean Hefty 	work = kzalloc(sizeof *work, GFP_KERNEL);
1695e51060f0SSean Hefty 	if (!work)
1696e51060f0SSean Hefty 		return -ENOMEM;
1697e51060f0SSean Hefty 
1698e51060f0SSean Hefty 	work->id = id_priv;
1699c4028958SDavid Howells 	INIT_WORK(&work->work, cma_work_handler);
1700550e5ca7SNir Muchtar 	work->old_state = RDMA_CM_ROUTE_QUERY;
1701550e5ca7SNir Muchtar 	work->new_state = RDMA_CM_ROUTE_RESOLVED;
1702e51060f0SSean Hefty 	work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED;
1703e51060f0SSean Hefty 
1704e51060f0SSean Hefty 	route->path_rec = kmalloc(sizeof *route->path_rec, GFP_KERNEL);
1705e51060f0SSean Hefty 	if (!route->path_rec) {
1706e51060f0SSean Hefty 		ret = -ENOMEM;
1707e51060f0SSean Hefty 		goto err1;
1708e51060f0SSean Hefty 	}
1709e51060f0SSean Hefty 
1710e51060f0SSean Hefty 	ret = cma_query_ib_route(id_priv, timeout_ms, work);
1711e51060f0SSean Hefty 	if (ret)
1712e51060f0SSean Hefty 		goto err2;
1713e51060f0SSean Hefty 
1714e51060f0SSean Hefty 	return 0;
1715e51060f0SSean Hefty err2:
1716e51060f0SSean Hefty 	kfree(route->path_rec);
1717e51060f0SSean Hefty 	route->path_rec = NULL;
1718e51060f0SSean Hefty err1:
1719e51060f0SSean Hefty 	kfree(work);
1720e51060f0SSean Hefty 	return ret;
1721e51060f0SSean Hefty }
1722e51060f0SSean Hefty 
1723e51060f0SSean Hefty int rdma_set_ib_paths(struct rdma_cm_id *id,
1724e51060f0SSean Hefty 		      struct ib_sa_path_rec *path_rec, int num_paths)
1725e51060f0SSean Hefty {
1726e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
1727e51060f0SSean Hefty 	int ret;
1728e51060f0SSean Hefty 
1729e51060f0SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
1730550e5ca7SNir Muchtar 	if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED,
1731550e5ca7SNir Muchtar 			   RDMA_CM_ROUTE_RESOLVED))
1732e51060f0SSean Hefty 		return -EINVAL;
1733e51060f0SSean Hefty 
17349893e742SJulia Lawall 	id->route.path_rec = kmemdup(path_rec, sizeof *path_rec * num_paths,
17359893e742SJulia Lawall 				     GFP_KERNEL);
1736e51060f0SSean Hefty 	if (!id->route.path_rec) {
1737e51060f0SSean Hefty 		ret = -ENOMEM;
1738e51060f0SSean Hefty 		goto err;
1739e51060f0SSean Hefty 	}
1740e51060f0SSean Hefty 
1741ae2d9293SSean Hefty 	id->route.num_paths = num_paths;
1742e51060f0SSean Hefty 	return 0;
1743e51060f0SSean Hefty err:
1744550e5ca7SNir Muchtar 	cma_comp_exch(id_priv, RDMA_CM_ROUTE_RESOLVED, RDMA_CM_ADDR_RESOLVED);
1745e51060f0SSean Hefty 	return ret;
1746e51060f0SSean Hefty }
1747e51060f0SSean Hefty EXPORT_SYMBOL(rdma_set_ib_paths);
1748e51060f0SSean Hefty 
174907ebafbaSTom Tucker static int cma_resolve_iw_route(struct rdma_id_private *id_priv, int timeout_ms)
175007ebafbaSTom Tucker {
175107ebafbaSTom Tucker 	struct cma_work *work;
175207ebafbaSTom Tucker 
175307ebafbaSTom Tucker 	work = kzalloc(sizeof *work, GFP_KERNEL);
175407ebafbaSTom Tucker 	if (!work)
175507ebafbaSTom Tucker 		return -ENOMEM;
175607ebafbaSTom Tucker 
175707ebafbaSTom Tucker 	work->id = id_priv;
1758c4028958SDavid Howells 	INIT_WORK(&work->work, cma_work_handler);
1759550e5ca7SNir Muchtar 	work->old_state = RDMA_CM_ROUTE_QUERY;
1760550e5ca7SNir Muchtar 	work->new_state = RDMA_CM_ROUTE_RESOLVED;
176107ebafbaSTom Tucker 	work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED;
176207ebafbaSTom Tucker 	queue_work(cma_wq, &work->work);
176307ebafbaSTom Tucker 	return 0;
176407ebafbaSTom Tucker }
176507ebafbaSTom Tucker 
17663c86aa70SEli Cohen static int cma_resolve_iboe_route(struct rdma_id_private *id_priv)
17673c86aa70SEli Cohen {
17683c86aa70SEli Cohen 	struct rdma_route *route = &id_priv->id.route;
17693c86aa70SEli Cohen 	struct rdma_addr *addr = &route->addr;
17703c86aa70SEli Cohen 	struct cma_work *work;
17713c86aa70SEli Cohen 	int ret;
17723c86aa70SEli Cohen 	struct sockaddr_in *src_addr = (struct sockaddr_in *)&route->addr.src_addr;
17733c86aa70SEli Cohen 	struct sockaddr_in *dst_addr = (struct sockaddr_in *)&route->addr.dst_addr;
17743c86aa70SEli Cohen 	struct net_device *ndev = NULL;
1775af7bd463SEli Cohen 	u16 vid;
17763c86aa70SEli Cohen 
17773c86aa70SEli Cohen 	if (src_addr->sin_family != dst_addr->sin_family)
17783c86aa70SEli Cohen 		return -EINVAL;
17793c86aa70SEli Cohen 
17803c86aa70SEli Cohen 	work = kzalloc(sizeof *work, GFP_KERNEL);
17813c86aa70SEli Cohen 	if (!work)
17823c86aa70SEli Cohen 		return -ENOMEM;
17833c86aa70SEli Cohen 
17843c86aa70SEli Cohen 	work->id = id_priv;
17853c86aa70SEli Cohen 	INIT_WORK(&work->work, cma_work_handler);
17863c86aa70SEli Cohen 
17873c86aa70SEli Cohen 	route->path_rec = kzalloc(sizeof *route->path_rec, GFP_KERNEL);
17883c86aa70SEli Cohen 	if (!route->path_rec) {
17893c86aa70SEli Cohen 		ret = -ENOMEM;
17903c86aa70SEli Cohen 		goto err1;
17913c86aa70SEli Cohen 	}
17923c86aa70SEli Cohen 
17933c86aa70SEli Cohen 	route->num_paths = 1;
17943c86aa70SEli Cohen 
17953c86aa70SEli Cohen 	if (addr->dev_addr.bound_dev_if)
17963c86aa70SEli Cohen 		ndev = dev_get_by_index(&init_net, addr->dev_addr.bound_dev_if);
17973c86aa70SEli Cohen 	if (!ndev) {
17983c86aa70SEli Cohen 		ret = -ENODEV;
17993c86aa70SEli Cohen 		goto err2;
18003c86aa70SEli Cohen 	}
18013c86aa70SEli Cohen 
1802af7bd463SEli Cohen 	vid = rdma_vlan_dev_vlan_id(ndev);
1803af7bd463SEli Cohen 
1804af7bd463SEli Cohen 	iboe_mac_vlan_to_ll(&route->path_rec->sgid, addr->dev_addr.src_dev_addr, vid);
1805af7bd463SEli Cohen 	iboe_mac_vlan_to_ll(&route->path_rec->dgid, addr->dev_addr.dst_dev_addr, vid);
1806af7bd463SEli Cohen 
1807af7bd463SEli Cohen 	route->path_rec->hop_limit = 1;
1808af7bd463SEli Cohen 	route->path_rec->reversible = 1;
1809af7bd463SEli Cohen 	route->path_rec->pkey = cpu_to_be16(0xffff);
1810af7bd463SEli Cohen 	route->path_rec->mtu_selector = IB_SA_EQ;
1811af7bd463SEli Cohen 	route->path_rec->sl = id_priv->tos >> 5;
1812af7bd463SEli Cohen 
18133c86aa70SEli Cohen 	route->path_rec->mtu = iboe_get_mtu(ndev->mtu);
18143c86aa70SEli Cohen 	route->path_rec->rate_selector = IB_SA_EQ;
18153c86aa70SEli Cohen 	route->path_rec->rate = iboe_get_rate(ndev);
18163c86aa70SEli Cohen 	dev_put(ndev);
18173c86aa70SEli Cohen 	route->path_rec->packet_life_time_selector = IB_SA_EQ;
18183c86aa70SEli Cohen 	route->path_rec->packet_life_time = CMA_IBOE_PACKET_LIFETIME;
18193c86aa70SEli Cohen 	if (!route->path_rec->mtu) {
18203c86aa70SEli Cohen 		ret = -EINVAL;
18213c86aa70SEli Cohen 		goto err2;
18223c86aa70SEli Cohen 	}
18233c86aa70SEli Cohen 
1824550e5ca7SNir Muchtar 	work->old_state = RDMA_CM_ROUTE_QUERY;
1825550e5ca7SNir Muchtar 	work->new_state = RDMA_CM_ROUTE_RESOLVED;
18263c86aa70SEli Cohen 	work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED;
18273c86aa70SEli Cohen 	work->event.status = 0;
18283c86aa70SEli Cohen 
18293c86aa70SEli Cohen 	queue_work(cma_wq, &work->work);
18303c86aa70SEli Cohen 
18313c86aa70SEli Cohen 	return 0;
18323c86aa70SEli Cohen 
18333c86aa70SEli Cohen err2:
18343c86aa70SEli Cohen 	kfree(route->path_rec);
18353c86aa70SEli Cohen 	route->path_rec = NULL;
18363c86aa70SEli Cohen err1:
18373c86aa70SEli Cohen 	kfree(work);
18383c86aa70SEli Cohen 	return ret;
18393c86aa70SEli Cohen }
18403c86aa70SEli Cohen 
1841e51060f0SSean Hefty int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms)
1842e51060f0SSean Hefty {
1843e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
1844e51060f0SSean Hefty 	int ret;
1845e51060f0SSean Hefty 
1846e51060f0SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
1847550e5ca7SNir Muchtar 	if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED, RDMA_CM_ROUTE_QUERY))
1848e51060f0SSean Hefty 		return -EINVAL;
1849e51060f0SSean Hefty 
1850e51060f0SSean Hefty 	atomic_inc(&id_priv->refcount);
185107ebafbaSTom Tucker 	switch (rdma_node_get_transport(id->device->node_type)) {
185207ebafbaSTom Tucker 	case RDMA_TRANSPORT_IB:
18533c86aa70SEli Cohen 		switch (rdma_port_get_link_layer(id->device, id->port_num)) {
18543c86aa70SEli Cohen 		case IB_LINK_LAYER_INFINIBAND:
1855e51060f0SSean Hefty 			ret = cma_resolve_ib_route(id_priv, timeout_ms);
1856e51060f0SSean Hefty 			break;
18573c86aa70SEli Cohen 		case IB_LINK_LAYER_ETHERNET:
18583c86aa70SEli Cohen 			ret = cma_resolve_iboe_route(id_priv);
18593c86aa70SEli Cohen 			break;
18603c86aa70SEli Cohen 		default:
18613c86aa70SEli Cohen 			ret = -ENOSYS;
18623c86aa70SEli Cohen 		}
18633c86aa70SEli Cohen 		break;
186407ebafbaSTom Tucker 	case RDMA_TRANSPORT_IWARP:
186507ebafbaSTom Tucker 		ret = cma_resolve_iw_route(id_priv, timeout_ms);
186607ebafbaSTom Tucker 		break;
1867e51060f0SSean Hefty 	default:
1868e51060f0SSean Hefty 		ret = -ENOSYS;
1869e51060f0SSean Hefty 		break;
1870e51060f0SSean Hefty 	}
1871e51060f0SSean Hefty 	if (ret)
1872e51060f0SSean Hefty 		goto err;
1873e51060f0SSean Hefty 
1874e51060f0SSean Hefty 	return 0;
1875e51060f0SSean Hefty err:
1876550e5ca7SNir Muchtar 	cma_comp_exch(id_priv, RDMA_CM_ROUTE_QUERY, RDMA_CM_ADDR_RESOLVED);
1877e51060f0SSean Hefty 	cma_deref_id(id_priv);
1878e51060f0SSean Hefty 	return ret;
1879e51060f0SSean Hefty }
1880e51060f0SSean Hefty EXPORT_SYMBOL(rdma_resolve_route);
1881e51060f0SSean Hefty 
1882e51060f0SSean Hefty static int cma_bind_loopback(struct rdma_id_private *id_priv)
1883e51060f0SSean Hefty {
1884e51060f0SSean Hefty 	struct cma_device *cma_dev;
1885e51060f0SSean Hefty 	struct ib_port_attr port_attr;
1886f0ee3404SMichael S. Tsirkin 	union ib_gid gid;
1887e51060f0SSean Hefty 	u16 pkey;
1888e51060f0SSean Hefty 	int ret;
1889e51060f0SSean Hefty 	u8 p;
1890e51060f0SSean Hefty 
1891e51060f0SSean Hefty 	mutex_lock(&lock);
1892e82153b5SKrishna Kumar 	if (list_empty(&dev_list)) {
1893e82153b5SKrishna Kumar 		ret = -ENODEV;
1894e82153b5SKrishna Kumar 		goto out;
1895e82153b5SKrishna Kumar 	}
1896e51060f0SSean Hefty 	list_for_each_entry(cma_dev, &dev_list, list)
1897e51060f0SSean Hefty 		for (p = 1; p <= cma_dev->device->phys_port_cnt; ++p)
1898e51060f0SSean Hefty 			if (!ib_query_port(cma_dev->device, p, &port_attr) &&
1899e51060f0SSean Hefty 			    port_attr.state == IB_PORT_ACTIVE)
1900e51060f0SSean Hefty 				goto port_found;
1901e51060f0SSean Hefty 
1902e51060f0SSean Hefty 	p = 1;
1903e51060f0SSean Hefty 	cma_dev = list_entry(dev_list.next, struct cma_device, list);
1904e51060f0SSean Hefty 
1905e51060f0SSean Hefty port_found:
1906f0ee3404SMichael S. Tsirkin 	ret = ib_get_cached_gid(cma_dev->device, p, 0, &gid);
1907e51060f0SSean Hefty 	if (ret)
1908e51060f0SSean Hefty 		goto out;
1909e51060f0SSean Hefty 
1910e51060f0SSean Hefty 	ret = ib_get_cached_pkey(cma_dev->device, p, 0, &pkey);
1911e51060f0SSean Hefty 	if (ret)
1912e51060f0SSean Hefty 		goto out;
1913e51060f0SSean Hefty 
19146f8372b6SSean Hefty 	id_priv->id.route.addr.dev_addr.dev_type =
19153c86aa70SEli Cohen 		(rdma_port_get_link_layer(cma_dev->device, p) == IB_LINK_LAYER_INFINIBAND) ?
19166f8372b6SSean Hefty 		ARPHRD_INFINIBAND : ARPHRD_ETHER;
19176f8372b6SSean Hefty 
19186f8372b6SSean Hefty 	rdma_addr_set_sgid(&id_priv->id.route.addr.dev_addr, &gid);
1919e51060f0SSean Hefty 	ib_addr_set_pkey(&id_priv->id.route.addr.dev_addr, pkey);
1920e51060f0SSean Hefty 	id_priv->id.port_num = p;
1921e51060f0SSean Hefty 	cma_attach_to_dev(id_priv, cma_dev);
1922e51060f0SSean Hefty out:
1923e51060f0SSean Hefty 	mutex_unlock(&lock);
1924e51060f0SSean Hefty 	return ret;
1925e51060f0SSean Hefty }
1926e51060f0SSean Hefty 
1927e51060f0SSean Hefty static void addr_handler(int status, struct sockaddr *src_addr,
1928e51060f0SSean Hefty 			 struct rdma_dev_addr *dev_addr, void *context)
1929e51060f0SSean Hefty {
1930e51060f0SSean Hefty 	struct rdma_id_private *id_priv = context;
1931a1b1b61fSSean Hefty 	struct rdma_cm_event event;
1932e51060f0SSean Hefty 
1933a1b1b61fSSean Hefty 	memset(&event, 0, sizeof event);
1934de910bd9SOr Gerlitz 	mutex_lock(&id_priv->handler_mutex);
1935550e5ca7SNir Muchtar 	if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_QUERY,
1936550e5ca7SNir Muchtar 			   RDMA_CM_ADDR_RESOLVED))
193761a73c70SSean Hefty 		goto out;
193861a73c70SSean Hefty 
193961a73c70SSean Hefty 	if (!status && !id_priv->cma_dev)
1940e51060f0SSean Hefty 		status = cma_acquire_dev(id_priv);
1941e51060f0SSean Hefty 
1942e51060f0SSean Hefty 	if (status) {
1943550e5ca7SNir Muchtar 		if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED,
1944550e5ca7SNir Muchtar 				   RDMA_CM_ADDR_BOUND))
1945e51060f0SSean Hefty 			goto out;
1946a1b1b61fSSean Hefty 		event.event = RDMA_CM_EVENT_ADDR_ERROR;
1947a1b1b61fSSean Hefty 		event.status = status;
1948e51060f0SSean Hefty 	} else {
1949e51060f0SSean Hefty 		memcpy(&id_priv->id.route.addr.src_addr, src_addr,
1950e51060f0SSean Hefty 		       ip_addr_size(src_addr));
1951a1b1b61fSSean Hefty 		event.event = RDMA_CM_EVENT_ADDR_RESOLVED;
1952e51060f0SSean Hefty 	}
1953e51060f0SSean Hefty 
1954a1b1b61fSSean Hefty 	if (id_priv->id.event_handler(&id_priv->id, &event)) {
1955550e5ca7SNir Muchtar 		cma_exch(id_priv, RDMA_CM_DESTROYING);
1956de910bd9SOr Gerlitz 		mutex_unlock(&id_priv->handler_mutex);
1957e51060f0SSean Hefty 		cma_deref_id(id_priv);
1958e51060f0SSean Hefty 		rdma_destroy_id(&id_priv->id);
1959e51060f0SSean Hefty 		return;
1960e51060f0SSean Hefty 	}
1961e51060f0SSean Hefty out:
1962de910bd9SOr Gerlitz 	mutex_unlock(&id_priv->handler_mutex);
1963e51060f0SSean Hefty 	cma_deref_id(id_priv);
1964e51060f0SSean Hefty }
1965e51060f0SSean Hefty 
1966e51060f0SSean Hefty static int cma_resolve_loopback(struct rdma_id_private *id_priv)
1967e51060f0SSean Hefty {
1968e51060f0SSean Hefty 	struct cma_work *work;
19696f8372b6SSean Hefty 	struct sockaddr *src, *dst;
1970f0ee3404SMichael S. Tsirkin 	union ib_gid gid;
1971e51060f0SSean Hefty 	int ret;
1972e51060f0SSean Hefty 
1973e51060f0SSean Hefty 	work = kzalloc(sizeof *work, GFP_KERNEL);
1974e51060f0SSean Hefty 	if (!work)
1975e51060f0SSean Hefty 		return -ENOMEM;
1976e51060f0SSean Hefty 
1977e51060f0SSean Hefty 	if (!id_priv->cma_dev) {
1978e51060f0SSean Hefty 		ret = cma_bind_loopback(id_priv);
1979e51060f0SSean Hefty 		if (ret)
1980e51060f0SSean Hefty 			goto err;
1981e51060f0SSean Hefty 	}
1982e51060f0SSean Hefty 
19836f8372b6SSean Hefty 	rdma_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid);
19846f8372b6SSean Hefty 	rdma_addr_set_dgid(&id_priv->id.route.addr.dev_addr, &gid);
1985e51060f0SSean Hefty 
19866f8372b6SSean Hefty 	src = (struct sockaddr *) &id_priv->id.route.addr.src_addr;
19876f8372b6SSean Hefty 	if (cma_zero_addr(src)) {
19886f8372b6SSean Hefty 		dst = (struct sockaddr *) &id_priv->id.route.addr.dst_addr;
19896f8372b6SSean Hefty 		if ((src->sa_family = dst->sa_family) == AF_INET) {
19906f8372b6SSean Hefty 			((struct sockaddr_in *) src)->sin_addr.s_addr =
19916f8372b6SSean Hefty 				((struct sockaddr_in *) dst)->sin_addr.s_addr;
19926f8372b6SSean Hefty 		} else {
19936f8372b6SSean Hefty 			ipv6_addr_copy(&((struct sockaddr_in6 *) src)->sin6_addr,
19946f8372b6SSean Hefty 				       &((struct sockaddr_in6 *) dst)->sin6_addr);
19956f8372b6SSean Hefty 		}
1996e51060f0SSean Hefty 	}
1997e51060f0SSean Hefty 
1998e51060f0SSean Hefty 	work->id = id_priv;
1999c4028958SDavid Howells 	INIT_WORK(&work->work, cma_work_handler);
2000550e5ca7SNir Muchtar 	work->old_state = RDMA_CM_ADDR_QUERY;
2001550e5ca7SNir Muchtar 	work->new_state = RDMA_CM_ADDR_RESOLVED;
2002e51060f0SSean Hefty 	work->event.event = RDMA_CM_EVENT_ADDR_RESOLVED;
2003e51060f0SSean Hefty 	queue_work(cma_wq, &work->work);
2004e51060f0SSean Hefty 	return 0;
2005e51060f0SSean Hefty err:
2006e51060f0SSean Hefty 	kfree(work);
2007e51060f0SSean Hefty 	return ret;
2008e51060f0SSean Hefty }
2009e51060f0SSean Hefty 
2010e51060f0SSean Hefty static int cma_bind_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
2011e51060f0SSean Hefty 			 struct sockaddr *dst_addr)
2012e51060f0SSean Hefty {
2013d14714dfSSean Hefty 	if (!src_addr || !src_addr->sa_family) {
2014d14714dfSSean Hefty 		src_addr = (struct sockaddr *) &id->route.addr.src_addr;
2015d14714dfSSean Hefty 		if ((src_addr->sa_family = dst_addr->sa_family) == AF_INET6) {
2016d14714dfSSean Hefty 			((struct sockaddr_in6 *) src_addr)->sin6_scope_id =
2017d14714dfSSean Hefty 				((struct sockaddr_in6 *) dst_addr)->sin6_scope_id;
2018d14714dfSSean Hefty 		}
2019d14714dfSSean Hefty 	}
2020e51060f0SSean Hefty 	return rdma_bind_addr(id, src_addr);
2021e51060f0SSean Hefty }
2022e51060f0SSean Hefty 
2023e51060f0SSean Hefty int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
2024e51060f0SSean Hefty 		      struct sockaddr *dst_addr, int timeout_ms)
2025e51060f0SSean Hefty {
2026e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
2027e51060f0SSean Hefty 	int ret;
2028e51060f0SSean Hefty 
2029e51060f0SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
2030550e5ca7SNir Muchtar 	if (id_priv->state == RDMA_CM_IDLE) {
2031e51060f0SSean Hefty 		ret = cma_bind_addr(id, src_addr, dst_addr);
2032e51060f0SSean Hefty 		if (ret)
2033e51060f0SSean Hefty 			return ret;
2034e51060f0SSean Hefty 	}
2035e51060f0SSean Hefty 
2036550e5ca7SNir Muchtar 	if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_ADDR_QUERY))
2037e51060f0SSean Hefty 		return -EINVAL;
2038e51060f0SSean Hefty 
2039e51060f0SSean Hefty 	atomic_inc(&id_priv->refcount);
2040e51060f0SSean Hefty 	memcpy(&id->route.addr.dst_addr, dst_addr, ip_addr_size(dst_addr));
2041e51060f0SSean Hefty 	if (cma_any_addr(dst_addr))
2042e51060f0SSean Hefty 		ret = cma_resolve_loopback(id_priv);
2043e51060f0SSean Hefty 	else
20443f446754SRoland Dreier 		ret = rdma_resolve_ip(&addr_client, (struct sockaddr *) &id->route.addr.src_addr,
20457a118df3SSean Hefty 				      dst_addr, &id->route.addr.dev_addr,
2046e51060f0SSean Hefty 				      timeout_ms, addr_handler, id_priv);
2047e51060f0SSean Hefty 	if (ret)
2048e51060f0SSean Hefty 		goto err;
2049e51060f0SSean Hefty 
2050e51060f0SSean Hefty 	return 0;
2051e51060f0SSean Hefty err:
2052550e5ca7SNir Muchtar 	cma_comp_exch(id_priv, RDMA_CM_ADDR_QUERY, RDMA_CM_ADDR_BOUND);
2053e51060f0SSean Hefty 	cma_deref_id(id_priv);
2054e51060f0SSean Hefty 	return ret;
2055e51060f0SSean Hefty }
2056e51060f0SSean Hefty EXPORT_SYMBOL(rdma_resolve_addr);
2057e51060f0SSean Hefty 
2058a9bb7912SHefty, Sean int rdma_set_reuseaddr(struct rdma_cm_id *id, int reuse)
2059a9bb7912SHefty, Sean {
2060a9bb7912SHefty, Sean 	struct rdma_id_private *id_priv;
2061a9bb7912SHefty, Sean 	unsigned long flags;
2062a9bb7912SHefty, Sean 	int ret;
2063a9bb7912SHefty, Sean 
2064a9bb7912SHefty, Sean 	id_priv = container_of(id, struct rdma_id_private, id);
2065a9bb7912SHefty, Sean 	spin_lock_irqsave(&id_priv->lock, flags);
2066550e5ca7SNir Muchtar 	if (id_priv->state == RDMA_CM_IDLE) {
2067a9bb7912SHefty, Sean 		id_priv->reuseaddr = reuse;
2068a9bb7912SHefty, Sean 		ret = 0;
2069a9bb7912SHefty, Sean 	} else {
2070a9bb7912SHefty, Sean 		ret = -EINVAL;
2071a9bb7912SHefty, Sean 	}
2072a9bb7912SHefty, Sean 	spin_unlock_irqrestore(&id_priv->lock, flags);
2073a9bb7912SHefty, Sean 	return ret;
2074a9bb7912SHefty, Sean }
2075a9bb7912SHefty, Sean EXPORT_SYMBOL(rdma_set_reuseaddr);
2076a9bb7912SHefty, Sean 
2077e51060f0SSean Hefty static void cma_bind_port(struct rdma_bind_list *bind_list,
2078e51060f0SSean Hefty 			  struct rdma_id_private *id_priv)
2079e51060f0SSean Hefty {
2080e51060f0SSean Hefty 	struct sockaddr_in *sin;
2081e51060f0SSean Hefty 
2082e51060f0SSean Hefty 	sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr;
2083e51060f0SSean Hefty 	sin->sin_port = htons(bind_list->port);
2084e51060f0SSean Hefty 	id_priv->bind_list = bind_list;
2085e51060f0SSean Hefty 	hlist_add_head(&id_priv->node, &bind_list->owners);
2086e51060f0SSean Hefty }
2087e51060f0SSean Hefty 
2088e51060f0SSean Hefty static int cma_alloc_port(struct idr *ps, struct rdma_id_private *id_priv,
2089e51060f0SSean Hefty 			  unsigned short snum)
2090e51060f0SSean Hefty {
2091e51060f0SSean Hefty 	struct rdma_bind_list *bind_list;
2092aedec080SSean Hefty 	int port, ret;
2093e51060f0SSean Hefty 
2094cb164b8cSSean Hefty 	bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL);
2095e51060f0SSean Hefty 	if (!bind_list)
2096e51060f0SSean Hefty 		return -ENOMEM;
2097e51060f0SSean Hefty 
2098e51060f0SSean Hefty 	do {
2099aedec080SSean Hefty 		ret = idr_get_new_above(ps, bind_list, snum, &port);
2100e51060f0SSean Hefty 	} while ((ret == -EAGAIN) && idr_pre_get(ps, GFP_KERNEL));
2101e51060f0SSean Hefty 
2102e51060f0SSean Hefty 	if (ret)
2103aedec080SSean Hefty 		goto err1;
2104e51060f0SSean Hefty 
2105aedec080SSean Hefty 	if (port != snum) {
2106e51060f0SSean Hefty 		ret = -EADDRNOTAVAIL;
2107aedec080SSean Hefty 		goto err2;
2108e51060f0SSean Hefty 	}
2109e51060f0SSean Hefty 
2110e51060f0SSean Hefty 	bind_list->ps = ps;
2111e51060f0SSean Hefty 	bind_list->port = (unsigned short) port;
2112e51060f0SSean Hefty 	cma_bind_port(bind_list, id_priv);
2113e51060f0SSean Hefty 	return 0;
2114aedec080SSean Hefty err2:
2115aedec080SSean Hefty 	idr_remove(ps, port);
2116aedec080SSean Hefty err1:
2117aedec080SSean Hefty 	kfree(bind_list);
2118aedec080SSean Hefty 	return ret;
2119aedec080SSean Hefty }
2120aedec080SSean Hefty 
2121aedec080SSean Hefty static int cma_alloc_any_port(struct idr *ps, struct rdma_id_private *id_priv)
2122aedec080SSean Hefty {
21235d7220e8STetsuo Handa 	static unsigned int last_used_port;
21245d7220e8STetsuo Handa 	int low, high, remaining;
21255d7220e8STetsuo Handa 	unsigned int rover;
2126aedec080SSean Hefty 
2127227b60f5SStephen Hemminger 	inet_get_local_port_range(&low, &high);
21285d7220e8STetsuo Handa 	remaining = (high - low) + 1;
21295d7220e8STetsuo Handa 	rover = net_random() % remaining + low;
21305d7220e8STetsuo Handa retry:
21315d7220e8STetsuo Handa 	if (last_used_port != rover &&
21325d7220e8STetsuo Handa 	    !idr_find(ps, (unsigned short) rover)) {
21335d7220e8STetsuo Handa 		int ret = cma_alloc_port(ps, id_priv, rover);
21345d7220e8STetsuo Handa 		/*
21355d7220e8STetsuo Handa 		 * Remember previously used port number in order to avoid
21365d7220e8STetsuo Handa 		 * re-using same port immediately after it is closed.
21375d7220e8STetsuo Handa 		 */
21385d7220e8STetsuo Handa 		if (!ret)
21395d7220e8STetsuo Handa 			last_used_port = rover;
21405d7220e8STetsuo Handa 		if (ret != -EADDRNOTAVAIL)
21415d7220e8STetsuo Handa 			return ret;
21425d7220e8STetsuo Handa 	}
21435d7220e8STetsuo Handa 	if (--remaining) {
21445d7220e8STetsuo Handa 		rover++;
21455d7220e8STetsuo Handa 		if ((rover < low) || (rover > high))
21465d7220e8STetsuo Handa 			rover = low;
2147aedec080SSean Hefty 		goto retry;
2148aedec080SSean Hefty 	}
21495d7220e8STetsuo Handa 	return -EADDRNOTAVAIL;
2150e51060f0SSean Hefty }
2151e51060f0SSean Hefty 
2152a9bb7912SHefty, Sean /*
2153a9bb7912SHefty, Sean  * Check that the requested port is available.  This is called when trying to
2154a9bb7912SHefty, Sean  * bind to a specific port, or when trying to listen on a bound port.  In
2155a9bb7912SHefty, Sean  * the latter case, the provided id_priv may already be on the bind_list, but
2156a9bb7912SHefty, Sean  * we still need to check that it's okay to start listening.
2157a9bb7912SHefty, Sean  */
2158a9bb7912SHefty, Sean static int cma_check_port(struct rdma_bind_list *bind_list,
2159a9bb7912SHefty, Sean 			  struct rdma_id_private *id_priv, uint8_t reuseaddr)
2160e51060f0SSean Hefty {
2161e51060f0SSean Hefty 	struct rdma_id_private *cur_id;
216243b752daSHefty, Sean 	struct sockaddr *addr, *cur_addr;
2163e51060f0SSean Hefty 	struct hlist_node *node;
2164e51060f0SSean Hefty 
216543b752daSHefty, Sean 	addr = (struct sockaddr *) &id_priv->id.route.addr.src_addr;
2166a9bb7912SHefty, Sean 	if (cma_any_addr(addr) && !reuseaddr)
2167e51060f0SSean Hefty 		return -EADDRNOTAVAIL;
2168e51060f0SSean Hefty 
2169e51060f0SSean Hefty 	hlist_for_each_entry(cur_id, node, &bind_list->owners, node) {
2170a9bb7912SHefty, Sean 		if (id_priv == cur_id)
2171a9bb7912SHefty, Sean 			continue;
2172a9bb7912SHefty, Sean 
2173550e5ca7SNir Muchtar 		if ((cur_id->state == RDMA_CM_LISTEN) ||
2174a9bb7912SHefty, Sean 		    !reuseaddr || !cur_id->reuseaddr) {
217543b752daSHefty, Sean 			cur_addr = (struct sockaddr *) &cur_id->id.route.addr.src_addr;
217643b752daSHefty, Sean 			if (cma_any_addr(cur_addr))
2177e51060f0SSean Hefty 				return -EADDRNOTAVAIL;
2178e51060f0SSean Hefty 
217943b752daSHefty, Sean 			if (!cma_addr_cmp(addr, cur_addr))
2180e51060f0SSean Hefty 				return -EADDRINUSE;
2181e51060f0SSean Hefty 		}
2182a9bb7912SHefty, Sean 	}
2183e51060f0SSean Hefty 	return 0;
2184e51060f0SSean Hefty }
2185e51060f0SSean Hefty 
2186a9bb7912SHefty, Sean static int cma_use_port(struct idr *ps, struct rdma_id_private *id_priv)
2187a9bb7912SHefty, Sean {
2188a9bb7912SHefty, Sean 	struct rdma_bind_list *bind_list;
2189a9bb7912SHefty, Sean 	unsigned short snum;
2190a9bb7912SHefty, Sean 	int ret;
2191a9bb7912SHefty, Sean 
2192a9bb7912SHefty, Sean 	snum = ntohs(cma_port((struct sockaddr *) &id_priv->id.route.addr.src_addr));
2193a9bb7912SHefty, Sean 	if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
2194a9bb7912SHefty, Sean 		return -EACCES;
2195a9bb7912SHefty, Sean 
2196a9bb7912SHefty, Sean 	bind_list = idr_find(ps, snum);
2197a9bb7912SHefty, Sean 	if (!bind_list) {
2198a9bb7912SHefty, Sean 		ret = cma_alloc_port(ps, id_priv, snum);
2199a9bb7912SHefty, Sean 	} else {
2200a9bb7912SHefty, Sean 		ret = cma_check_port(bind_list, id_priv, id_priv->reuseaddr);
2201a9bb7912SHefty, Sean 		if (!ret)
2202a9bb7912SHefty, Sean 			cma_bind_port(bind_list, id_priv);
2203a9bb7912SHefty, Sean 	}
2204a9bb7912SHefty, Sean 	return ret;
2205a9bb7912SHefty, Sean }
2206a9bb7912SHefty, Sean 
2207a9bb7912SHefty, Sean static int cma_bind_listen(struct rdma_id_private *id_priv)
2208a9bb7912SHefty, Sean {
2209a9bb7912SHefty, Sean 	struct rdma_bind_list *bind_list = id_priv->bind_list;
2210a9bb7912SHefty, Sean 	int ret = 0;
2211a9bb7912SHefty, Sean 
2212a9bb7912SHefty, Sean 	mutex_lock(&lock);
2213a9bb7912SHefty, Sean 	if (bind_list->owners.first->next)
2214a9bb7912SHefty, Sean 		ret = cma_check_port(bind_list, id_priv, 0);
2215a9bb7912SHefty, Sean 	mutex_unlock(&lock);
2216a9bb7912SHefty, Sean 	return ret;
2217a9bb7912SHefty, Sean }
2218a9bb7912SHefty, Sean 
2219e51060f0SSean Hefty static int cma_get_port(struct rdma_id_private *id_priv)
2220e51060f0SSean Hefty {
2221e51060f0SSean Hefty 	struct idr *ps;
2222e51060f0SSean Hefty 	int ret;
2223e51060f0SSean Hefty 
2224e51060f0SSean Hefty 	switch (id_priv->id.ps) {
2225e51060f0SSean Hefty 	case RDMA_PS_SDP:
2226e51060f0SSean Hefty 		ps = &sdp_ps;
2227e51060f0SSean Hefty 		break;
2228e51060f0SSean Hefty 	case RDMA_PS_TCP:
2229e51060f0SSean Hefty 		ps = &tcp_ps;
2230e51060f0SSean Hefty 		break;
2231628e5f6dSSean Hefty 	case RDMA_PS_UDP:
2232628e5f6dSSean Hefty 		ps = &udp_ps;
2233628e5f6dSSean Hefty 		break;
2234c8f6a362SSean Hefty 	case RDMA_PS_IPOIB:
2235c8f6a362SSean Hefty 		ps = &ipoib_ps;
2236c8f6a362SSean Hefty 		break;
2237e51060f0SSean Hefty 	default:
2238e51060f0SSean Hefty 		return -EPROTONOSUPPORT;
2239e51060f0SSean Hefty 	}
2240e51060f0SSean Hefty 
2241e51060f0SSean Hefty 	mutex_lock(&lock);
22423f446754SRoland Dreier 	if (cma_any_port((struct sockaddr *) &id_priv->id.route.addr.src_addr))
2243aedec080SSean Hefty 		ret = cma_alloc_any_port(ps, id_priv);
2244e51060f0SSean Hefty 	else
2245e51060f0SSean Hefty 		ret = cma_use_port(ps, id_priv);
2246e51060f0SSean Hefty 	mutex_unlock(&lock);
2247e51060f0SSean Hefty 
2248e51060f0SSean Hefty 	return ret;
2249e51060f0SSean Hefty }
2250e51060f0SSean Hefty 
2251d14714dfSSean Hefty static int cma_check_linklocal(struct rdma_dev_addr *dev_addr,
2252d14714dfSSean Hefty 			       struct sockaddr *addr)
2253d14714dfSSean Hefty {
2254fd4582a3SRobert P. J. Day #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
2255d14714dfSSean Hefty 	struct sockaddr_in6 *sin6;
2256d14714dfSSean Hefty 
2257d14714dfSSean Hefty 	if (addr->sa_family != AF_INET6)
2258d14714dfSSean Hefty 		return 0;
2259d14714dfSSean Hefty 
2260d14714dfSSean Hefty 	sin6 = (struct sockaddr_in6 *) addr;
2261d14714dfSSean Hefty 	if ((ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) &&
2262d14714dfSSean Hefty 	    !sin6->sin6_scope_id)
2263d14714dfSSean Hefty 			return -EINVAL;
2264d14714dfSSean Hefty 
2265d14714dfSSean Hefty 	dev_addr->bound_dev_if = sin6->sin6_scope_id;
2266d14714dfSSean Hefty #endif
2267d14714dfSSean Hefty 	return 0;
2268d14714dfSSean Hefty }
2269d14714dfSSean Hefty 
2270a9bb7912SHefty, Sean int rdma_listen(struct rdma_cm_id *id, int backlog)
2271a9bb7912SHefty, Sean {
2272a9bb7912SHefty, Sean 	struct rdma_id_private *id_priv;
2273a9bb7912SHefty, Sean 	int ret;
2274a9bb7912SHefty, Sean 
2275a9bb7912SHefty, Sean 	id_priv = container_of(id, struct rdma_id_private, id);
2276550e5ca7SNir Muchtar 	if (id_priv->state == RDMA_CM_IDLE) {
2277a9bb7912SHefty, Sean 		((struct sockaddr *) &id->route.addr.src_addr)->sa_family = AF_INET;
2278a9bb7912SHefty, Sean 		ret = rdma_bind_addr(id, (struct sockaddr *) &id->route.addr.src_addr);
2279a9bb7912SHefty, Sean 		if (ret)
2280a9bb7912SHefty, Sean 			return ret;
2281a9bb7912SHefty, Sean 	}
2282a9bb7912SHefty, Sean 
2283550e5ca7SNir Muchtar 	if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_LISTEN))
2284a9bb7912SHefty, Sean 		return -EINVAL;
2285a9bb7912SHefty, Sean 
2286a9bb7912SHefty, Sean 	if (id_priv->reuseaddr) {
2287a9bb7912SHefty, Sean 		ret = cma_bind_listen(id_priv);
2288a9bb7912SHefty, Sean 		if (ret)
2289a9bb7912SHefty, Sean 			goto err;
2290a9bb7912SHefty, Sean 	}
2291a9bb7912SHefty, Sean 
2292a9bb7912SHefty, Sean 	id_priv->backlog = backlog;
2293a9bb7912SHefty, Sean 	if (id->device) {
2294a9bb7912SHefty, Sean 		switch (rdma_node_get_transport(id->device->node_type)) {
2295a9bb7912SHefty, Sean 		case RDMA_TRANSPORT_IB:
2296a9bb7912SHefty, Sean 			ret = cma_ib_listen(id_priv);
2297a9bb7912SHefty, Sean 			if (ret)
2298a9bb7912SHefty, Sean 				goto err;
2299a9bb7912SHefty, Sean 			break;
2300a9bb7912SHefty, Sean 		case RDMA_TRANSPORT_IWARP:
2301a9bb7912SHefty, Sean 			ret = cma_iw_listen(id_priv, backlog);
2302a9bb7912SHefty, Sean 			if (ret)
2303a9bb7912SHefty, Sean 				goto err;
2304a9bb7912SHefty, Sean 			break;
2305a9bb7912SHefty, Sean 		default:
2306a9bb7912SHefty, Sean 			ret = -ENOSYS;
2307a9bb7912SHefty, Sean 			goto err;
2308a9bb7912SHefty, Sean 		}
2309a9bb7912SHefty, Sean 	} else
2310a9bb7912SHefty, Sean 		cma_listen_on_all(id_priv);
2311a9bb7912SHefty, Sean 
2312a9bb7912SHefty, Sean 	return 0;
2313a9bb7912SHefty, Sean err:
2314a9bb7912SHefty, Sean 	id_priv->backlog = 0;
2315550e5ca7SNir Muchtar 	cma_comp_exch(id_priv, RDMA_CM_LISTEN, RDMA_CM_ADDR_BOUND);
2316a9bb7912SHefty, Sean 	return ret;
2317a9bb7912SHefty, Sean }
2318a9bb7912SHefty, Sean EXPORT_SYMBOL(rdma_listen);
2319a9bb7912SHefty, Sean 
2320e51060f0SSean Hefty int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
2321e51060f0SSean Hefty {
2322e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
2323e51060f0SSean Hefty 	int ret;
2324e51060f0SSean Hefty 
23251f5175adSAleksey Senin 	if (addr->sa_family != AF_INET && addr->sa_family != AF_INET6)
2326e51060f0SSean Hefty 		return -EAFNOSUPPORT;
2327e51060f0SSean Hefty 
2328e51060f0SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
2329550e5ca7SNir Muchtar 	if (!cma_comp_exch(id_priv, RDMA_CM_IDLE, RDMA_CM_ADDR_BOUND))
2330e51060f0SSean Hefty 		return -EINVAL;
2331e51060f0SSean Hefty 
2332d14714dfSSean Hefty 	ret = cma_check_linklocal(&id->route.addr.dev_addr, addr);
2333d14714dfSSean Hefty 	if (ret)
2334d14714dfSSean Hefty 		goto err1;
2335d14714dfSSean Hefty 
23368523c048SSean Hefty 	if (!cma_any_addr(addr)) {
2337e51060f0SSean Hefty 		ret = rdma_translate_ip(addr, &id->route.addr.dev_addr);
2338255d0c14SKrishna Kumar 		if (ret)
2339255d0c14SKrishna Kumar 			goto err1;
2340255d0c14SKrishna Kumar 
2341e51060f0SSean Hefty 		ret = cma_acquire_dev(id_priv);
2342e51060f0SSean Hefty 		if (ret)
2343255d0c14SKrishna Kumar 			goto err1;
2344e51060f0SSean Hefty 	}
2345e51060f0SSean Hefty 
2346e51060f0SSean Hefty 	memcpy(&id->route.addr.src_addr, addr, ip_addr_size(addr));
2347e51060f0SSean Hefty 	ret = cma_get_port(id_priv);
2348e51060f0SSean Hefty 	if (ret)
2349255d0c14SKrishna Kumar 		goto err2;
2350e51060f0SSean Hefty 
2351e51060f0SSean Hefty 	return 0;
2352255d0c14SKrishna Kumar err2:
2353a396d43aSSean Hefty 	if (id_priv->cma_dev)
2354a396d43aSSean Hefty 		cma_release_dev(id_priv);
2355255d0c14SKrishna Kumar err1:
2356550e5ca7SNir Muchtar 	cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_IDLE);
2357e51060f0SSean Hefty 	return ret;
2358e51060f0SSean Hefty }
2359e51060f0SSean Hefty EXPORT_SYMBOL(rdma_bind_addr);
2360e51060f0SSean Hefty 
2361e51060f0SSean Hefty static int cma_format_hdr(void *hdr, enum rdma_port_space ps,
2362e51060f0SSean Hefty 			  struct rdma_route *route)
2363e51060f0SSean Hefty {
2364e51060f0SSean Hefty 	struct cma_hdr *cma_hdr;
2365e51060f0SSean Hefty 	struct sdp_hh *sdp_hdr;
2366e51060f0SSean Hefty 
23671f5175adSAleksey Senin 	if (route->addr.src_addr.ss_family == AF_INET) {
23681f5175adSAleksey Senin 		struct sockaddr_in *src4, *dst4;
23691f5175adSAleksey Senin 
2370e51060f0SSean Hefty 		src4 = (struct sockaddr_in *) &route->addr.src_addr;
2371e51060f0SSean Hefty 		dst4 = (struct sockaddr_in *) &route->addr.dst_addr;
2372e51060f0SSean Hefty 
2373e51060f0SSean Hefty 		switch (ps) {
2374e51060f0SSean Hefty 		case RDMA_PS_SDP:
2375e51060f0SSean Hefty 			sdp_hdr = hdr;
2376e51060f0SSean Hefty 			if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION)
2377e51060f0SSean Hefty 				return -EINVAL;
2378e51060f0SSean Hefty 			sdp_set_ip_ver(sdp_hdr, 4);
2379e51060f0SSean Hefty 			sdp_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr;
2380e51060f0SSean Hefty 			sdp_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr;
2381e51060f0SSean Hefty 			sdp_hdr->port = src4->sin_port;
2382e51060f0SSean Hefty 			break;
2383e51060f0SSean Hefty 		default:
2384e51060f0SSean Hefty 			cma_hdr = hdr;
2385e51060f0SSean Hefty 			cma_hdr->cma_version = CMA_VERSION;
2386e51060f0SSean Hefty 			cma_set_ip_ver(cma_hdr, 4);
2387e51060f0SSean Hefty 			cma_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr;
2388e51060f0SSean Hefty 			cma_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr;
2389e51060f0SSean Hefty 			cma_hdr->port = src4->sin_port;
2390e51060f0SSean Hefty 			break;
2391e51060f0SSean Hefty 		}
23921f5175adSAleksey Senin 	} else {
23931f5175adSAleksey Senin 		struct sockaddr_in6 *src6, *dst6;
23941f5175adSAleksey Senin 
23951f5175adSAleksey Senin 		src6 = (struct sockaddr_in6 *) &route->addr.src_addr;
23961f5175adSAleksey Senin 		dst6 = (struct sockaddr_in6 *) &route->addr.dst_addr;
23971f5175adSAleksey Senin 
23981f5175adSAleksey Senin 		switch (ps) {
23991f5175adSAleksey Senin 		case RDMA_PS_SDP:
24001f5175adSAleksey Senin 			sdp_hdr = hdr;
24011f5175adSAleksey Senin 			if (sdp_get_majv(sdp_hdr->sdp_version) != SDP_MAJ_VERSION)
24021f5175adSAleksey Senin 				return -EINVAL;
24031f5175adSAleksey Senin 			sdp_set_ip_ver(sdp_hdr, 6);
24041f5175adSAleksey Senin 			sdp_hdr->src_addr.ip6 = src6->sin6_addr;
24051f5175adSAleksey Senin 			sdp_hdr->dst_addr.ip6 = dst6->sin6_addr;
24061f5175adSAleksey Senin 			sdp_hdr->port = src6->sin6_port;
24071f5175adSAleksey Senin 			break;
24081f5175adSAleksey Senin 		default:
24091f5175adSAleksey Senin 			cma_hdr = hdr;
24101f5175adSAleksey Senin 			cma_hdr->cma_version = CMA_VERSION;
24111f5175adSAleksey Senin 			cma_set_ip_ver(cma_hdr, 6);
24121f5175adSAleksey Senin 			cma_hdr->src_addr.ip6 = src6->sin6_addr;
24131f5175adSAleksey Senin 			cma_hdr->dst_addr.ip6 = dst6->sin6_addr;
24141f5175adSAleksey Senin 			cma_hdr->port = src6->sin6_port;
24151f5175adSAleksey Senin 			break;
24161f5175adSAleksey Senin 		}
24171f5175adSAleksey Senin 	}
2418e51060f0SSean Hefty 	return 0;
2419e51060f0SSean Hefty }
2420e51060f0SSean Hefty 
2421628e5f6dSSean Hefty static int cma_sidr_rep_handler(struct ib_cm_id *cm_id,
2422628e5f6dSSean Hefty 				struct ib_cm_event *ib_event)
2423628e5f6dSSean Hefty {
2424628e5f6dSSean Hefty 	struct rdma_id_private *id_priv = cm_id->context;
2425628e5f6dSSean Hefty 	struct rdma_cm_event event;
2426628e5f6dSSean Hefty 	struct ib_cm_sidr_rep_event_param *rep = &ib_event->param.sidr_rep_rcvd;
2427628e5f6dSSean Hefty 	int ret = 0;
2428628e5f6dSSean Hefty 
2429550e5ca7SNir Muchtar 	if (cma_disable_callback(id_priv, RDMA_CM_CONNECT))
24308aa08602SSean Hefty 		return 0;
2431628e5f6dSSean Hefty 
24328aa08602SSean Hefty 	memset(&event, 0, sizeof event);
2433628e5f6dSSean Hefty 	switch (ib_event->event) {
2434628e5f6dSSean Hefty 	case IB_CM_SIDR_REQ_ERROR:
2435628e5f6dSSean Hefty 		event.event = RDMA_CM_EVENT_UNREACHABLE;
2436628e5f6dSSean Hefty 		event.status = -ETIMEDOUT;
2437628e5f6dSSean Hefty 		break;
2438628e5f6dSSean Hefty 	case IB_CM_SIDR_REP_RECEIVED:
2439628e5f6dSSean Hefty 		event.param.ud.private_data = ib_event->private_data;
2440628e5f6dSSean Hefty 		event.param.ud.private_data_len = IB_CM_SIDR_REP_PRIVATE_DATA_SIZE;
2441628e5f6dSSean Hefty 		if (rep->status != IB_SIDR_SUCCESS) {
2442628e5f6dSSean Hefty 			event.event = RDMA_CM_EVENT_UNREACHABLE;
2443628e5f6dSSean Hefty 			event.status = ib_event->param.sidr_rep_rcvd.status;
2444628e5f6dSSean Hefty 			break;
2445628e5f6dSSean Hefty 		}
2446d2ca39f2SYossi Etigin 		ret = cma_set_qkey(id_priv);
2447d2ca39f2SYossi Etigin 		if (ret) {
2448d2ca39f2SYossi Etigin 			event.event = RDMA_CM_EVENT_ADDR_ERROR;
2449d2ca39f2SYossi Etigin 			event.status = -EINVAL;
2450d2ca39f2SYossi Etigin 			break;
2451d2ca39f2SYossi Etigin 		}
2452c8f6a362SSean Hefty 		if (id_priv->qkey != rep->qkey) {
2453628e5f6dSSean Hefty 			event.event = RDMA_CM_EVENT_UNREACHABLE;
2454628e5f6dSSean Hefty 			event.status = -EINVAL;
2455628e5f6dSSean Hefty 			break;
2456628e5f6dSSean Hefty 		}
2457628e5f6dSSean Hefty 		ib_init_ah_from_path(id_priv->id.device, id_priv->id.port_num,
2458628e5f6dSSean Hefty 				     id_priv->id.route.path_rec,
2459628e5f6dSSean Hefty 				     &event.param.ud.ah_attr);
2460628e5f6dSSean Hefty 		event.param.ud.qp_num = rep->qpn;
2461628e5f6dSSean Hefty 		event.param.ud.qkey = rep->qkey;
2462628e5f6dSSean Hefty 		event.event = RDMA_CM_EVENT_ESTABLISHED;
2463628e5f6dSSean Hefty 		event.status = 0;
2464628e5f6dSSean Hefty 		break;
2465628e5f6dSSean Hefty 	default:
2466468f2239SRoland Dreier 		printk(KERN_ERR "RDMA CMA: unexpected IB CM event: %d\n",
2467628e5f6dSSean Hefty 		       ib_event->event);
2468628e5f6dSSean Hefty 		goto out;
2469628e5f6dSSean Hefty 	}
2470628e5f6dSSean Hefty 
2471628e5f6dSSean Hefty 	ret = id_priv->id.event_handler(&id_priv->id, &event);
2472628e5f6dSSean Hefty 	if (ret) {
2473628e5f6dSSean Hefty 		/* Destroy the CM ID by returning a non-zero value. */
2474628e5f6dSSean Hefty 		id_priv->cm_id.ib = NULL;
2475550e5ca7SNir Muchtar 		cma_exch(id_priv, RDMA_CM_DESTROYING);
2476de910bd9SOr Gerlitz 		mutex_unlock(&id_priv->handler_mutex);
2477628e5f6dSSean Hefty 		rdma_destroy_id(&id_priv->id);
2478628e5f6dSSean Hefty 		return ret;
2479628e5f6dSSean Hefty 	}
2480628e5f6dSSean Hefty out:
2481de910bd9SOr Gerlitz 	mutex_unlock(&id_priv->handler_mutex);
2482628e5f6dSSean Hefty 	return ret;
2483628e5f6dSSean Hefty }
2484628e5f6dSSean Hefty 
2485628e5f6dSSean Hefty static int cma_resolve_ib_udp(struct rdma_id_private *id_priv,
2486628e5f6dSSean Hefty 			      struct rdma_conn_param *conn_param)
2487628e5f6dSSean Hefty {
2488628e5f6dSSean Hefty 	struct ib_cm_sidr_req_param req;
2489628e5f6dSSean Hefty 	struct rdma_route *route;
24900c9361fcSJack Morgenstein 	struct ib_cm_id	*id;
2491628e5f6dSSean Hefty 	int ret;
2492628e5f6dSSean Hefty 
2493628e5f6dSSean Hefty 	req.private_data_len = sizeof(struct cma_hdr) +
2494628e5f6dSSean Hefty 			       conn_param->private_data_len;
2495628e5f6dSSean Hefty 	req.private_data = kzalloc(req.private_data_len, GFP_ATOMIC);
2496628e5f6dSSean Hefty 	if (!req.private_data)
2497628e5f6dSSean Hefty 		return -ENOMEM;
2498628e5f6dSSean Hefty 
2499628e5f6dSSean Hefty 	if (conn_param->private_data && conn_param->private_data_len)
2500628e5f6dSSean Hefty 		memcpy((void *) req.private_data + sizeof(struct cma_hdr),
2501628e5f6dSSean Hefty 		       conn_param->private_data, conn_param->private_data_len);
2502628e5f6dSSean Hefty 
2503628e5f6dSSean Hefty 	route = &id_priv->id.route;
2504628e5f6dSSean Hefty 	ret = cma_format_hdr((void *) req.private_data, id_priv->id.ps, route);
2505628e5f6dSSean Hefty 	if (ret)
2506628e5f6dSSean Hefty 		goto out;
2507628e5f6dSSean Hefty 
25080c9361fcSJack Morgenstein 	id = ib_create_cm_id(id_priv->id.device, cma_sidr_rep_handler,
25090c9361fcSJack Morgenstein 			     id_priv);
25100c9361fcSJack Morgenstein 	if (IS_ERR(id)) {
25110c9361fcSJack Morgenstein 		ret = PTR_ERR(id);
2512628e5f6dSSean Hefty 		goto out;
2513628e5f6dSSean Hefty 	}
25140c9361fcSJack Morgenstein 	id_priv->cm_id.ib = id;
2515628e5f6dSSean Hefty 
2516628e5f6dSSean Hefty 	req.path = route->path_rec;
2517628e5f6dSSean Hefty 	req.service_id = cma_get_service_id(id_priv->id.ps,
25183f446754SRoland Dreier 					    (struct sockaddr *) &route->addr.dst_addr);
2519628e5f6dSSean Hefty 	req.timeout_ms = 1 << (CMA_CM_RESPONSE_TIMEOUT - 8);
2520628e5f6dSSean Hefty 	req.max_cm_retries = CMA_MAX_CM_RETRIES;
2521628e5f6dSSean Hefty 
2522628e5f6dSSean Hefty 	ret = ib_send_cm_sidr_req(id_priv->cm_id.ib, &req);
2523628e5f6dSSean Hefty 	if (ret) {
2524628e5f6dSSean Hefty 		ib_destroy_cm_id(id_priv->cm_id.ib);
2525628e5f6dSSean Hefty 		id_priv->cm_id.ib = NULL;
2526628e5f6dSSean Hefty 	}
2527628e5f6dSSean Hefty out:
2528628e5f6dSSean Hefty 	kfree(req.private_data);
2529628e5f6dSSean Hefty 	return ret;
2530628e5f6dSSean Hefty }
2531628e5f6dSSean Hefty 
2532e51060f0SSean Hefty static int cma_connect_ib(struct rdma_id_private *id_priv,
2533e51060f0SSean Hefty 			  struct rdma_conn_param *conn_param)
2534e51060f0SSean Hefty {
2535e51060f0SSean Hefty 	struct ib_cm_req_param req;
2536e51060f0SSean Hefty 	struct rdma_route *route;
2537e51060f0SSean Hefty 	void *private_data;
25380c9361fcSJack Morgenstein 	struct ib_cm_id	*id;
2539e51060f0SSean Hefty 	int offset, ret;
2540e51060f0SSean Hefty 
2541e51060f0SSean Hefty 	memset(&req, 0, sizeof req);
2542e51060f0SSean Hefty 	offset = cma_user_data_offset(id_priv->id.ps);
2543e51060f0SSean Hefty 	req.private_data_len = offset + conn_param->private_data_len;
2544e51060f0SSean Hefty 	private_data = kzalloc(req.private_data_len, GFP_ATOMIC);
2545e51060f0SSean Hefty 	if (!private_data)
2546e51060f0SSean Hefty 		return -ENOMEM;
2547e51060f0SSean Hefty 
2548e51060f0SSean Hefty 	if (conn_param->private_data && conn_param->private_data_len)
2549e51060f0SSean Hefty 		memcpy(private_data + offset, conn_param->private_data,
2550e51060f0SSean Hefty 		       conn_param->private_data_len);
2551e51060f0SSean Hefty 
25520c9361fcSJack Morgenstein 	id = ib_create_cm_id(id_priv->id.device, cma_ib_handler, id_priv);
25530c9361fcSJack Morgenstein 	if (IS_ERR(id)) {
25540c9361fcSJack Morgenstein 		ret = PTR_ERR(id);
2555e51060f0SSean Hefty 		goto out;
2556e51060f0SSean Hefty 	}
25570c9361fcSJack Morgenstein 	id_priv->cm_id.ib = id;
2558e51060f0SSean Hefty 
2559e51060f0SSean Hefty 	route = &id_priv->id.route;
2560e51060f0SSean Hefty 	ret = cma_format_hdr(private_data, id_priv->id.ps, route);
2561e51060f0SSean Hefty 	if (ret)
2562e51060f0SSean Hefty 		goto out;
2563e51060f0SSean Hefty 	req.private_data = private_data;
2564e51060f0SSean Hefty 
2565e51060f0SSean Hefty 	req.primary_path = &route->path_rec[0];
2566e51060f0SSean Hefty 	if (route->num_paths == 2)
2567e51060f0SSean Hefty 		req.alternate_path = &route->path_rec[1];
2568e51060f0SSean Hefty 
2569e51060f0SSean Hefty 	req.service_id = cma_get_service_id(id_priv->id.ps,
25703f446754SRoland Dreier 					    (struct sockaddr *) &route->addr.dst_addr);
2571e51060f0SSean Hefty 	req.qp_num = id_priv->qp_num;
25729b2e9c0cSSean Hefty 	req.qp_type = IB_QPT_RC;
2573e51060f0SSean Hefty 	req.starting_psn = id_priv->seq_num;
2574e51060f0SSean Hefty 	req.responder_resources = conn_param->responder_resources;
2575e51060f0SSean Hefty 	req.initiator_depth = conn_param->initiator_depth;
2576e51060f0SSean Hefty 	req.flow_control = conn_param->flow_control;
2577e51060f0SSean Hefty 	req.retry_count = conn_param->retry_count;
2578e51060f0SSean Hefty 	req.rnr_retry_count = conn_param->rnr_retry_count;
2579e51060f0SSean Hefty 	req.remote_cm_response_timeout = CMA_CM_RESPONSE_TIMEOUT;
2580e51060f0SSean Hefty 	req.local_cm_response_timeout = CMA_CM_RESPONSE_TIMEOUT;
2581e51060f0SSean Hefty 	req.max_cm_retries = CMA_MAX_CM_RETRIES;
2582e51060f0SSean Hefty 	req.srq = id_priv->srq ? 1 : 0;
2583e51060f0SSean Hefty 
2584e51060f0SSean Hefty 	ret = ib_send_cm_req(id_priv->cm_id.ib, &req);
2585e51060f0SSean Hefty out:
25860c9361fcSJack Morgenstein 	if (ret && !IS_ERR(id)) {
25870c9361fcSJack Morgenstein 		ib_destroy_cm_id(id);
2588675a027cSKrishna Kumar 		id_priv->cm_id.ib = NULL;
2589675a027cSKrishna Kumar 	}
2590675a027cSKrishna Kumar 
2591e51060f0SSean Hefty 	kfree(private_data);
2592e51060f0SSean Hefty 	return ret;
2593e51060f0SSean Hefty }
2594e51060f0SSean Hefty 
259507ebafbaSTom Tucker static int cma_connect_iw(struct rdma_id_private *id_priv,
259607ebafbaSTom Tucker 			  struct rdma_conn_param *conn_param)
259707ebafbaSTom Tucker {
259807ebafbaSTom Tucker 	struct iw_cm_id *cm_id;
259907ebafbaSTom Tucker 	struct sockaddr_in* sin;
260007ebafbaSTom Tucker 	int ret;
260107ebafbaSTom Tucker 	struct iw_cm_conn_param iw_param;
260207ebafbaSTom Tucker 
260307ebafbaSTom Tucker 	cm_id = iw_create_cm_id(id_priv->id.device, cma_iw_handler, id_priv);
26040c9361fcSJack Morgenstein 	if (IS_ERR(cm_id))
26050c9361fcSJack Morgenstein 		return PTR_ERR(cm_id);
260607ebafbaSTom Tucker 
260707ebafbaSTom Tucker 	id_priv->cm_id.iw = cm_id;
260807ebafbaSTom Tucker 
260907ebafbaSTom Tucker 	sin = (struct sockaddr_in*) &id_priv->id.route.addr.src_addr;
261007ebafbaSTom Tucker 	cm_id->local_addr = *sin;
261107ebafbaSTom Tucker 
261207ebafbaSTom Tucker 	sin = (struct sockaddr_in*) &id_priv->id.route.addr.dst_addr;
261307ebafbaSTom Tucker 	cm_id->remote_addr = *sin;
261407ebafbaSTom Tucker 
26155851bb89SSean Hefty 	ret = cma_modify_qp_rtr(id_priv, conn_param);
2616675a027cSKrishna Kumar 	if (ret)
2617675a027cSKrishna Kumar 		goto out;
261807ebafbaSTom Tucker 
261907ebafbaSTom Tucker 	iw_param.ord = conn_param->initiator_depth;
262007ebafbaSTom Tucker 	iw_param.ird = conn_param->responder_resources;
262107ebafbaSTom Tucker 	iw_param.private_data = conn_param->private_data;
262207ebafbaSTom Tucker 	iw_param.private_data_len = conn_param->private_data_len;
262307ebafbaSTom Tucker 	if (id_priv->id.qp)
262407ebafbaSTom Tucker 		iw_param.qpn = id_priv->qp_num;
262507ebafbaSTom Tucker 	else
262607ebafbaSTom Tucker 		iw_param.qpn = conn_param->qp_num;
262707ebafbaSTom Tucker 	ret = iw_cm_connect(cm_id, &iw_param);
262807ebafbaSTom Tucker out:
26290c9361fcSJack Morgenstein 	if (ret) {
2630675a027cSKrishna Kumar 		iw_destroy_cm_id(cm_id);
2631675a027cSKrishna Kumar 		id_priv->cm_id.iw = NULL;
2632675a027cSKrishna Kumar 	}
263307ebafbaSTom Tucker 	return ret;
263407ebafbaSTom Tucker }
263507ebafbaSTom Tucker 
2636e51060f0SSean Hefty int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
2637e51060f0SSean Hefty {
2638e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
2639e51060f0SSean Hefty 	int ret;
2640e51060f0SSean Hefty 
2641e51060f0SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
2642550e5ca7SNir Muchtar 	if (!cma_comp_exch(id_priv, RDMA_CM_ROUTE_RESOLVED, RDMA_CM_CONNECT))
2643e51060f0SSean Hefty 		return -EINVAL;
2644e51060f0SSean Hefty 
2645e51060f0SSean Hefty 	if (!id->qp) {
2646e51060f0SSean Hefty 		id_priv->qp_num = conn_param->qp_num;
2647e51060f0SSean Hefty 		id_priv->srq = conn_param->srq;
2648e51060f0SSean Hefty 	}
2649e51060f0SSean Hefty 
265007ebafbaSTom Tucker 	switch (rdma_node_get_transport(id->device->node_type)) {
265107ebafbaSTom Tucker 	case RDMA_TRANSPORT_IB:
2652b26f9b99SSean Hefty 		if (id->qp_type == IB_QPT_UD)
2653628e5f6dSSean Hefty 			ret = cma_resolve_ib_udp(id_priv, conn_param);
2654628e5f6dSSean Hefty 		else
2655e51060f0SSean Hefty 			ret = cma_connect_ib(id_priv, conn_param);
2656e51060f0SSean Hefty 		break;
265707ebafbaSTom Tucker 	case RDMA_TRANSPORT_IWARP:
265807ebafbaSTom Tucker 		ret = cma_connect_iw(id_priv, conn_param);
265907ebafbaSTom Tucker 		break;
2660e51060f0SSean Hefty 	default:
2661e51060f0SSean Hefty 		ret = -ENOSYS;
2662e51060f0SSean Hefty 		break;
2663e51060f0SSean Hefty 	}
2664e51060f0SSean Hefty 	if (ret)
2665e51060f0SSean Hefty 		goto err;
2666e51060f0SSean Hefty 
2667e51060f0SSean Hefty 	return 0;
2668e51060f0SSean Hefty err:
2669550e5ca7SNir Muchtar 	cma_comp_exch(id_priv, RDMA_CM_CONNECT, RDMA_CM_ROUTE_RESOLVED);
2670e51060f0SSean Hefty 	return ret;
2671e51060f0SSean Hefty }
2672e51060f0SSean Hefty EXPORT_SYMBOL(rdma_connect);
2673e51060f0SSean Hefty 
2674e51060f0SSean Hefty static int cma_accept_ib(struct rdma_id_private *id_priv,
2675e51060f0SSean Hefty 			 struct rdma_conn_param *conn_param)
2676e51060f0SSean Hefty {
2677e51060f0SSean Hefty 	struct ib_cm_rep_param rep;
26785851bb89SSean Hefty 	int ret;
2679e51060f0SSean Hefty 
26805851bb89SSean Hefty 	ret = cma_modify_qp_rtr(id_priv, conn_param);
2681e51060f0SSean Hefty 	if (ret)
26820fe313b0SSean Hefty 		goto out;
26830fe313b0SSean Hefty 
26845851bb89SSean Hefty 	ret = cma_modify_qp_rts(id_priv, conn_param);
26850fe313b0SSean Hefty 	if (ret)
26860fe313b0SSean Hefty 		goto out;
26870fe313b0SSean Hefty 
2688e51060f0SSean Hefty 	memset(&rep, 0, sizeof rep);
2689e51060f0SSean Hefty 	rep.qp_num = id_priv->qp_num;
2690e51060f0SSean Hefty 	rep.starting_psn = id_priv->seq_num;
2691e51060f0SSean Hefty 	rep.private_data = conn_param->private_data;
2692e51060f0SSean Hefty 	rep.private_data_len = conn_param->private_data_len;
2693e51060f0SSean Hefty 	rep.responder_resources = conn_param->responder_resources;
2694e51060f0SSean Hefty 	rep.initiator_depth = conn_param->initiator_depth;
2695e51060f0SSean Hefty 	rep.failover_accepted = 0;
2696e51060f0SSean Hefty 	rep.flow_control = conn_param->flow_control;
2697e51060f0SSean Hefty 	rep.rnr_retry_count = conn_param->rnr_retry_count;
2698e51060f0SSean Hefty 	rep.srq = id_priv->srq ? 1 : 0;
2699e51060f0SSean Hefty 
27000fe313b0SSean Hefty 	ret = ib_send_cm_rep(id_priv->cm_id.ib, &rep);
27010fe313b0SSean Hefty out:
27020fe313b0SSean Hefty 	return ret;
2703e51060f0SSean Hefty }
2704e51060f0SSean Hefty 
270507ebafbaSTom Tucker static int cma_accept_iw(struct rdma_id_private *id_priv,
270607ebafbaSTom Tucker 		  struct rdma_conn_param *conn_param)
270707ebafbaSTom Tucker {
270807ebafbaSTom Tucker 	struct iw_cm_conn_param iw_param;
270907ebafbaSTom Tucker 	int ret;
271007ebafbaSTom Tucker 
27115851bb89SSean Hefty 	ret = cma_modify_qp_rtr(id_priv, conn_param);
271207ebafbaSTom Tucker 	if (ret)
271307ebafbaSTom Tucker 		return ret;
271407ebafbaSTom Tucker 
271507ebafbaSTom Tucker 	iw_param.ord = conn_param->initiator_depth;
271607ebafbaSTom Tucker 	iw_param.ird = conn_param->responder_resources;
271707ebafbaSTom Tucker 	iw_param.private_data = conn_param->private_data;
271807ebafbaSTom Tucker 	iw_param.private_data_len = conn_param->private_data_len;
271907ebafbaSTom Tucker 	if (id_priv->id.qp) {
272007ebafbaSTom Tucker 		iw_param.qpn = id_priv->qp_num;
272107ebafbaSTom Tucker 	} else
272207ebafbaSTom Tucker 		iw_param.qpn = conn_param->qp_num;
272307ebafbaSTom Tucker 
272407ebafbaSTom Tucker 	return iw_cm_accept(id_priv->cm_id.iw, &iw_param);
272507ebafbaSTom Tucker }
272607ebafbaSTom Tucker 
2727628e5f6dSSean Hefty static int cma_send_sidr_rep(struct rdma_id_private *id_priv,
2728628e5f6dSSean Hefty 			     enum ib_cm_sidr_status status,
2729628e5f6dSSean Hefty 			     const void *private_data, int private_data_len)
2730628e5f6dSSean Hefty {
2731628e5f6dSSean Hefty 	struct ib_cm_sidr_rep_param rep;
2732d2ca39f2SYossi Etigin 	int ret;
2733628e5f6dSSean Hefty 
2734628e5f6dSSean Hefty 	memset(&rep, 0, sizeof rep);
2735628e5f6dSSean Hefty 	rep.status = status;
2736628e5f6dSSean Hefty 	if (status == IB_SIDR_SUCCESS) {
2737d2ca39f2SYossi Etigin 		ret = cma_set_qkey(id_priv);
2738d2ca39f2SYossi Etigin 		if (ret)
2739d2ca39f2SYossi Etigin 			return ret;
2740628e5f6dSSean Hefty 		rep.qp_num = id_priv->qp_num;
2741c8f6a362SSean Hefty 		rep.qkey = id_priv->qkey;
2742628e5f6dSSean Hefty 	}
2743628e5f6dSSean Hefty 	rep.private_data = private_data;
2744628e5f6dSSean Hefty 	rep.private_data_len = private_data_len;
2745628e5f6dSSean Hefty 
2746628e5f6dSSean Hefty 	return ib_send_cm_sidr_rep(id_priv->cm_id.ib, &rep);
2747628e5f6dSSean Hefty }
2748628e5f6dSSean Hefty 
2749e51060f0SSean Hefty int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
2750e51060f0SSean Hefty {
2751e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
2752e51060f0SSean Hefty 	int ret;
2753e51060f0SSean Hefty 
2754e51060f0SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
275583e9502dSNir Muchtar 
275683e9502dSNir Muchtar 	id_priv->owner = task_pid_nr(current);
275783e9502dSNir Muchtar 
2758550e5ca7SNir Muchtar 	if (!cma_comp(id_priv, RDMA_CM_CONNECT))
2759e51060f0SSean Hefty 		return -EINVAL;
2760e51060f0SSean Hefty 
2761e51060f0SSean Hefty 	if (!id->qp && conn_param) {
2762e51060f0SSean Hefty 		id_priv->qp_num = conn_param->qp_num;
2763e51060f0SSean Hefty 		id_priv->srq = conn_param->srq;
2764e51060f0SSean Hefty 	}
2765e51060f0SSean Hefty 
276607ebafbaSTom Tucker 	switch (rdma_node_get_transport(id->device->node_type)) {
276707ebafbaSTom Tucker 	case RDMA_TRANSPORT_IB:
2768b26f9b99SSean Hefty 		if (id->qp_type == IB_QPT_UD)
2769628e5f6dSSean Hefty 			ret = cma_send_sidr_rep(id_priv, IB_SIDR_SUCCESS,
2770628e5f6dSSean Hefty 						conn_param->private_data,
2771628e5f6dSSean Hefty 						conn_param->private_data_len);
2772628e5f6dSSean Hefty 		else if (conn_param)
2773e51060f0SSean Hefty 			ret = cma_accept_ib(id_priv, conn_param);
2774e51060f0SSean Hefty 		else
2775e51060f0SSean Hefty 			ret = cma_rep_recv(id_priv);
2776e51060f0SSean Hefty 		break;
277707ebafbaSTom Tucker 	case RDMA_TRANSPORT_IWARP:
277807ebafbaSTom Tucker 		ret = cma_accept_iw(id_priv, conn_param);
277907ebafbaSTom Tucker 		break;
2780e51060f0SSean Hefty 	default:
2781e51060f0SSean Hefty 		ret = -ENOSYS;
2782e51060f0SSean Hefty 		break;
2783e51060f0SSean Hefty 	}
2784e51060f0SSean Hefty 
2785e51060f0SSean Hefty 	if (ret)
2786e51060f0SSean Hefty 		goto reject;
2787e51060f0SSean Hefty 
2788e51060f0SSean Hefty 	return 0;
2789e51060f0SSean Hefty reject:
2790c5483388SSean Hefty 	cma_modify_qp_err(id_priv);
2791e51060f0SSean Hefty 	rdma_reject(id, NULL, 0);
2792e51060f0SSean Hefty 	return ret;
2793e51060f0SSean Hefty }
2794e51060f0SSean Hefty EXPORT_SYMBOL(rdma_accept);
2795e51060f0SSean Hefty 
27960fe313b0SSean Hefty int rdma_notify(struct rdma_cm_id *id, enum ib_event_type event)
27970fe313b0SSean Hefty {
27980fe313b0SSean Hefty 	struct rdma_id_private *id_priv;
27990fe313b0SSean Hefty 	int ret;
28000fe313b0SSean Hefty 
28010fe313b0SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
28020c9361fcSJack Morgenstein 	if (!id_priv->cm_id.ib)
28030fe313b0SSean Hefty 		return -EINVAL;
28040fe313b0SSean Hefty 
28050fe313b0SSean Hefty 	switch (id->device->node_type) {
28060fe313b0SSean Hefty 	case RDMA_NODE_IB_CA:
28070fe313b0SSean Hefty 		ret = ib_cm_notify(id_priv->cm_id.ib, event);
28080fe313b0SSean Hefty 		break;
28090fe313b0SSean Hefty 	default:
28100fe313b0SSean Hefty 		ret = 0;
28110fe313b0SSean Hefty 		break;
28120fe313b0SSean Hefty 	}
28130fe313b0SSean Hefty 	return ret;
28140fe313b0SSean Hefty }
28150fe313b0SSean Hefty EXPORT_SYMBOL(rdma_notify);
28160fe313b0SSean Hefty 
2817e51060f0SSean Hefty int rdma_reject(struct rdma_cm_id *id, const void *private_data,
2818e51060f0SSean Hefty 		u8 private_data_len)
2819e51060f0SSean Hefty {
2820e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
2821e51060f0SSean Hefty 	int ret;
2822e51060f0SSean Hefty 
2823e51060f0SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
28240c9361fcSJack Morgenstein 	if (!id_priv->cm_id.ib)
2825e51060f0SSean Hefty 		return -EINVAL;
2826e51060f0SSean Hefty 
282707ebafbaSTom Tucker 	switch (rdma_node_get_transport(id->device->node_type)) {
282807ebafbaSTom Tucker 	case RDMA_TRANSPORT_IB:
2829b26f9b99SSean Hefty 		if (id->qp_type == IB_QPT_UD)
2830628e5f6dSSean Hefty 			ret = cma_send_sidr_rep(id_priv, IB_SIDR_REJECT,
2831e51060f0SSean Hefty 						private_data, private_data_len);
2832628e5f6dSSean Hefty 		else
2833628e5f6dSSean Hefty 			ret = ib_send_cm_rej(id_priv->cm_id.ib,
2834628e5f6dSSean Hefty 					     IB_CM_REJ_CONSUMER_DEFINED, NULL,
2835628e5f6dSSean Hefty 					     0, private_data, private_data_len);
2836e51060f0SSean Hefty 		break;
283707ebafbaSTom Tucker 	case RDMA_TRANSPORT_IWARP:
283807ebafbaSTom Tucker 		ret = iw_cm_reject(id_priv->cm_id.iw,
283907ebafbaSTom Tucker 				   private_data, private_data_len);
284007ebafbaSTom Tucker 		break;
2841e51060f0SSean Hefty 	default:
2842e51060f0SSean Hefty 		ret = -ENOSYS;
2843e51060f0SSean Hefty 		break;
2844e51060f0SSean Hefty 	}
2845e51060f0SSean Hefty 	return ret;
2846e51060f0SSean Hefty }
2847e51060f0SSean Hefty EXPORT_SYMBOL(rdma_reject);
2848e51060f0SSean Hefty 
2849e51060f0SSean Hefty int rdma_disconnect(struct rdma_cm_id *id)
2850e51060f0SSean Hefty {
2851e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
2852e51060f0SSean Hefty 	int ret;
2853e51060f0SSean Hefty 
2854e51060f0SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
28550c9361fcSJack Morgenstein 	if (!id_priv->cm_id.ib)
2856e51060f0SSean Hefty 		return -EINVAL;
2857e51060f0SSean Hefty 
285807ebafbaSTom Tucker 	switch (rdma_node_get_transport(id->device->node_type)) {
285907ebafbaSTom Tucker 	case RDMA_TRANSPORT_IB:
2860c5483388SSean Hefty 		ret = cma_modify_qp_err(id_priv);
2861e51060f0SSean Hefty 		if (ret)
2862e51060f0SSean Hefty 			goto out;
2863e51060f0SSean Hefty 		/* Initiate or respond to a disconnect. */
2864e51060f0SSean Hefty 		if (ib_send_cm_dreq(id_priv->cm_id.ib, NULL, 0))
2865e51060f0SSean Hefty 			ib_send_cm_drep(id_priv->cm_id.ib, NULL, 0);
2866e51060f0SSean Hefty 		break;
286707ebafbaSTom Tucker 	case RDMA_TRANSPORT_IWARP:
286807ebafbaSTom Tucker 		ret = iw_cm_disconnect(id_priv->cm_id.iw, 0);
286907ebafbaSTom Tucker 		break;
2870e51060f0SSean Hefty 	default:
287107ebafbaSTom Tucker 		ret = -EINVAL;
2872e51060f0SSean Hefty 		break;
2873e51060f0SSean Hefty 	}
2874e51060f0SSean Hefty out:
2875e51060f0SSean Hefty 	return ret;
2876e51060f0SSean Hefty }
2877e51060f0SSean Hefty EXPORT_SYMBOL(rdma_disconnect);
2878e51060f0SSean Hefty 
2879c8f6a362SSean Hefty static int cma_ib_mc_handler(int status, struct ib_sa_multicast *multicast)
2880c8f6a362SSean Hefty {
2881c8f6a362SSean Hefty 	struct rdma_id_private *id_priv;
2882c8f6a362SSean Hefty 	struct cma_multicast *mc = multicast->context;
2883c8f6a362SSean Hefty 	struct rdma_cm_event event;
2884c8f6a362SSean Hefty 	int ret;
2885c8f6a362SSean Hefty 
2886c8f6a362SSean Hefty 	id_priv = mc->id_priv;
2887550e5ca7SNir Muchtar 	if (cma_disable_callback(id_priv, RDMA_CM_ADDR_BOUND) &&
2888550e5ca7SNir Muchtar 	    cma_disable_callback(id_priv, RDMA_CM_ADDR_RESOLVED))
28898aa08602SSean Hefty 		return 0;
2890c8f6a362SSean Hefty 
2891c5483388SSean Hefty 	mutex_lock(&id_priv->qp_mutex);
2892c8f6a362SSean Hefty 	if (!status && id_priv->id.qp)
2893c8f6a362SSean Hefty 		status = ib_attach_mcast(id_priv->id.qp, &multicast->rec.mgid,
2894c8f6a362SSean Hefty 					 multicast->rec.mlid);
2895c5483388SSean Hefty 	mutex_unlock(&id_priv->qp_mutex);
2896c8f6a362SSean Hefty 
2897c8f6a362SSean Hefty 	memset(&event, 0, sizeof event);
2898c8f6a362SSean Hefty 	event.status = status;
2899c8f6a362SSean Hefty 	event.param.ud.private_data = mc->context;
2900c8f6a362SSean Hefty 	if (!status) {
2901c8f6a362SSean Hefty 		event.event = RDMA_CM_EVENT_MULTICAST_JOIN;
2902c8f6a362SSean Hefty 		ib_init_ah_from_mcmember(id_priv->id.device,
2903c8f6a362SSean Hefty 					 id_priv->id.port_num, &multicast->rec,
2904c8f6a362SSean Hefty 					 &event.param.ud.ah_attr);
2905c8f6a362SSean Hefty 		event.param.ud.qp_num = 0xFFFFFF;
2906c8f6a362SSean Hefty 		event.param.ud.qkey = be32_to_cpu(multicast->rec.qkey);
2907c8f6a362SSean Hefty 	} else
2908c8f6a362SSean Hefty 		event.event = RDMA_CM_EVENT_MULTICAST_ERROR;
2909c8f6a362SSean Hefty 
2910c8f6a362SSean Hefty 	ret = id_priv->id.event_handler(&id_priv->id, &event);
2911c8f6a362SSean Hefty 	if (ret) {
2912550e5ca7SNir Muchtar 		cma_exch(id_priv, RDMA_CM_DESTROYING);
2913de910bd9SOr Gerlitz 		mutex_unlock(&id_priv->handler_mutex);
2914c8f6a362SSean Hefty 		rdma_destroy_id(&id_priv->id);
2915c8f6a362SSean Hefty 		return 0;
2916c8f6a362SSean Hefty 	}
29178aa08602SSean Hefty 
2918de910bd9SOr Gerlitz 	mutex_unlock(&id_priv->handler_mutex);
2919c8f6a362SSean Hefty 	return 0;
2920c8f6a362SSean Hefty }
2921c8f6a362SSean Hefty 
2922c8f6a362SSean Hefty static void cma_set_mgid(struct rdma_id_private *id_priv,
2923c8f6a362SSean Hefty 			 struct sockaddr *addr, union ib_gid *mgid)
2924c8f6a362SSean Hefty {
2925c8f6a362SSean Hefty 	unsigned char mc_map[MAX_ADDR_LEN];
2926c8f6a362SSean Hefty 	struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
2927c8f6a362SSean Hefty 	struct sockaddr_in *sin = (struct sockaddr_in *) addr;
2928c8f6a362SSean Hefty 	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) addr;
2929c8f6a362SSean Hefty 
2930c8f6a362SSean Hefty 	if (cma_any_addr(addr)) {
2931c8f6a362SSean Hefty 		memset(mgid, 0, sizeof *mgid);
2932c8f6a362SSean Hefty 	} else if ((addr->sa_family == AF_INET6) &&
29331c9b2819SJason Gunthorpe 		   ((be32_to_cpu(sin6->sin6_addr.s6_addr32[0]) & 0xFFF0FFFF) ==
2934c8f6a362SSean Hefty 								 0xFF10A01B)) {
2935c8f6a362SSean Hefty 		/* IPv6 address is an SA assigned MGID. */
2936c8f6a362SSean Hefty 		memcpy(mgid, &sin6->sin6_addr, sizeof *mgid);
2937e2e62697SJason Gunthorpe 	} else if ((addr->sa_family == AF_INET6)) {
2938e2e62697SJason Gunthorpe 		ipv6_ib_mc_map(&sin6->sin6_addr, dev_addr->broadcast, mc_map);
2939e2e62697SJason Gunthorpe 		if (id_priv->id.ps == RDMA_PS_UDP)
2940e2e62697SJason Gunthorpe 			mc_map[7] = 0x01;	/* Use RDMA CM signature */
2941e2e62697SJason Gunthorpe 		*mgid = *(union ib_gid *) (mc_map + 4);
2942c8f6a362SSean Hefty 	} else {
2943a9e527e3SRolf Manderscheid 		ip_ib_mc_map(sin->sin_addr.s_addr, dev_addr->broadcast, mc_map);
2944c8f6a362SSean Hefty 		if (id_priv->id.ps == RDMA_PS_UDP)
2945c8f6a362SSean Hefty 			mc_map[7] = 0x01;	/* Use RDMA CM signature */
2946c8f6a362SSean Hefty 		*mgid = *(union ib_gid *) (mc_map + 4);
2947c8f6a362SSean Hefty 	}
2948c8f6a362SSean Hefty }
2949c8f6a362SSean Hefty 
2950c8f6a362SSean Hefty static int cma_join_ib_multicast(struct rdma_id_private *id_priv,
2951c8f6a362SSean Hefty 				 struct cma_multicast *mc)
2952c8f6a362SSean Hefty {
2953c8f6a362SSean Hefty 	struct ib_sa_mcmember_rec rec;
2954c8f6a362SSean Hefty 	struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
2955c8f6a362SSean Hefty 	ib_sa_comp_mask comp_mask;
2956c8f6a362SSean Hefty 	int ret;
2957c8f6a362SSean Hefty 
2958c8f6a362SSean Hefty 	ib_addr_get_mgid(dev_addr, &rec.mgid);
2959c8f6a362SSean Hefty 	ret = ib_sa_get_mcmember_rec(id_priv->id.device, id_priv->id.port_num,
2960c8f6a362SSean Hefty 				     &rec.mgid, &rec);
2961c8f6a362SSean Hefty 	if (ret)
2962c8f6a362SSean Hefty 		return ret;
2963c8f6a362SSean Hefty 
29643f446754SRoland Dreier 	cma_set_mgid(id_priv, (struct sockaddr *) &mc->addr, &rec.mgid);
2965c8f6a362SSean Hefty 	if (id_priv->id.ps == RDMA_PS_UDP)
2966c8f6a362SSean Hefty 		rec.qkey = cpu_to_be32(RDMA_UDP_QKEY);
29676f8372b6SSean Hefty 	rdma_addr_get_sgid(dev_addr, &rec.port_gid);
2968c8f6a362SSean Hefty 	rec.pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr));
2969c8f6a362SSean Hefty 	rec.join_state = 1;
2970c8f6a362SSean Hefty 
2971c8f6a362SSean Hefty 	comp_mask = IB_SA_MCMEMBER_REC_MGID | IB_SA_MCMEMBER_REC_PORT_GID |
2972c8f6a362SSean Hefty 		    IB_SA_MCMEMBER_REC_PKEY | IB_SA_MCMEMBER_REC_JOIN_STATE |
2973c8f6a362SSean Hefty 		    IB_SA_MCMEMBER_REC_QKEY | IB_SA_MCMEMBER_REC_SL |
2974c8f6a362SSean Hefty 		    IB_SA_MCMEMBER_REC_FLOW_LABEL |
2975c8f6a362SSean Hefty 		    IB_SA_MCMEMBER_REC_TRAFFIC_CLASS;
2976c8f6a362SSean Hefty 
297784adeee9SYossi Etigin 	if (id_priv->id.ps == RDMA_PS_IPOIB)
297884adeee9SYossi Etigin 		comp_mask |= IB_SA_MCMEMBER_REC_RATE |
297984adeee9SYossi Etigin 			     IB_SA_MCMEMBER_REC_RATE_SELECTOR;
298084adeee9SYossi Etigin 
2981c8f6a362SSean Hefty 	mc->multicast.ib = ib_sa_join_multicast(&sa_client, id_priv->id.device,
2982c8f6a362SSean Hefty 						id_priv->id.port_num, &rec,
2983c8f6a362SSean Hefty 						comp_mask, GFP_KERNEL,
2984c8f6a362SSean Hefty 						cma_ib_mc_handler, mc);
2985c8f6a362SSean Hefty 	if (IS_ERR(mc->multicast.ib))
2986c8f6a362SSean Hefty 		return PTR_ERR(mc->multicast.ib);
2987c8f6a362SSean Hefty 
2988c8f6a362SSean Hefty 	return 0;
2989c8f6a362SSean Hefty }
2990c8f6a362SSean Hefty 
29913c86aa70SEli Cohen static void iboe_mcast_work_handler(struct work_struct *work)
29923c86aa70SEli Cohen {
29933c86aa70SEli Cohen 	struct iboe_mcast_work *mw = container_of(work, struct iboe_mcast_work, work);
29943c86aa70SEli Cohen 	struct cma_multicast *mc = mw->mc;
29953c86aa70SEli Cohen 	struct ib_sa_multicast *m = mc->multicast.ib;
29963c86aa70SEli Cohen 
29973c86aa70SEli Cohen 	mc->multicast.ib->context = mc;
29983c86aa70SEli Cohen 	cma_ib_mc_handler(0, m);
29993c86aa70SEli Cohen 	kref_put(&mc->mcref, release_mc);
30003c86aa70SEli Cohen 	kfree(mw);
30013c86aa70SEli Cohen }
30023c86aa70SEli Cohen 
30033c86aa70SEli Cohen static void cma_iboe_set_mgid(struct sockaddr *addr, union ib_gid *mgid)
30043c86aa70SEli Cohen {
30053c86aa70SEli Cohen 	struct sockaddr_in *sin = (struct sockaddr_in *)addr;
30063c86aa70SEli Cohen 	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
30073c86aa70SEli Cohen 
30083c86aa70SEli Cohen 	if (cma_any_addr(addr)) {
30093c86aa70SEli Cohen 		memset(mgid, 0, sizeof *mgid);
30103c86aa70SEli Cohen 	} else if (addr->sa_family == AF_INET6) {
30113c86aa70SEli Cohen 		memcpy(mgid, &sin6->sin6_addr, sizeof *mgid);
30123c86aa70SEli Cohen 	} else {
30133c86aa70SEli Cohen 		mgid->raw[0] = 0xff;
30143c86aa70SEli Cohen 		mgid->raw[1] = 0x0e;
30153c86aa70SEli Cohen 		mgid->raw[2] = 0;
30163c86aa70SEli Cohen 		mgid->raw[3] = 0;
30173c86aa70SEli Cohen 		mgid->raw[4] = 0;
30183c86aa70SEli Cohen 		mgid->raw[5] = 0;
30193c86aa70SEli Cohen 		mgid->raw[6] = 0;
30203c86aa70SEli Cohen 		mgid->raw[7] = 0;
30213c86aa70SEli Cohen 		mgid->raw[8] = 0;
30223c86aa70SEli Cohen 		mgid->raw[9] = 0;
30233c86aa70SEli Cohen 		mgid->raw[10] = 0xff;
30243c86aa70SEli Cohen 		mgid->raw[11] = 0xff;
30253c86aa70SEli Cohen 		*(__be32 *)(&mgid->raw[12]) = sin->sin_addr.s_addr;
30263c86aa70SEli Cohen 	}
30273c86aa70SEli Cohen }
30283c86aa70SEli Cohen 
30293c86aa70SEli Cohen static int cma_iboe_join_multicast(struct rdma_id_private *id_priv,
30303c86aa70SEli Cohen 				   struct cma_multicast *mc)
30313c86aa70SEli Cohen {
30323c86aa70SEli Cohen 	struct iboe_mcast_work *work;
30333c86aa70SEli Cohen 	struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
30343c86aa70SEli Cohen 	int err;
30353c86aa70SEli Cohen 	struct sockaddr *addr = (struct sockaddr *)&mc->addr;
30363c86aa70SEli Cohen 	struct net_device *ndev = NULL;
30373c86aa70SEli Cohen 
30383c86aa70SEli Cohen 	if (cma_zero_addr((struct sockaddr *)&mc->addr))
30393c86aa70SEli Cohen 		return -EINVAL;
30403c86aa70SEli Cohen 
30413c86aa70SEli Cohen 	work = kzalloc(sizeof *work, GFP_KERNEL);
30423c86aa70SEli Cohen 	if (!work)
30433c86aa70SEli Cohen 		return -ENOMEM;
30443c86aa70SEli Cohen 
30453c86aa70SEli Cohen 	mc->multicast.ib = kzalloc(sizeof(struct ib_sa_multicast), GFP_KERNEL);
30463c86aa70SEli Cohen 	if (!mc->multicast.ib) {
30473c86aa70SEli Cohen 		err = -ENOMEM;
30483c86aa70SEli Cohen 		goto out1;
30493c86aa70SEli Cohen 	}
30503c86aa70SEli Cohen 
30513c86aa70SEli Cohen 	cma_iboe_set_mgid(addr, &mc->multicast.ib->rec.mgid);
30523c86aa70SEli Cohen 
30533c86aa70SEli Cohen 	mc->multicast.ib->rec.pkey = cpu_to_be16(0xffff);
30543c86aa70SEli Cohen 	if (id_priv->id.ps == RDMA_PS_UDP)
30553c86aa70SEli Cohen 		mc->multicast.ib->rec.qkey = cpu_to_be32(RDMA_UDP_QKEY);
30563c86aa70SEli Cohen 
30573c86aa70SEli Cohen 	if (dev_addr->bound_dev_if)
30583c86aa70SEli Cohen 		ndev = dev_get_by_index(&init_net, dev_addr->bound_dev_if);
30593c86aa70SEli Cohen 	if (!ndev) {
30603c86aa70SEli Cohen 		err = -ENODEV;
30613c86aa70SEli Cohen 		goto out2;
30623c86aa70SEli Cohen 	}
30633c86aa70SEli Cohen 	mc->multicast.ib->rec.rate = iboe_get_rate(ndev);
30643c86aa70SEli Cohen 	mc->multicast.ib->rec.hop_limit = 1;
30653c86aa70SEli Cohen 	mc->multicast.ib->rec.mtu = iboe_get_mtu(ndev->mtu);
30663c86aa70SEli Cohen 	dev_put(ndev);
30673c86aa70SEli Cohen 	if (!mc->multicast.ib->rec.mtu) {
30683c86aa70SEli Cohen 		err = -EINVAL;
30693c86aa70SEli Cohen 		goto out2;
30703c86aa70SEli Cohen 	}
30713c86aa70SEli Cohen 	iboe_addr_get_sgid(dev_addr, &mc->multicast.ib->rec.port_gid);
30723c86aa70SEli Cohen 	work->id = id_priv;
30733c86aa70SEli Cohen 	work->mc = mc;
30743c86aa70SEli Cohen 	INIT_WORK(&work->work, iboe_mcast_work_handler);
30753c86aa70SEli Cohen 	kref_get(&mc->mcref);
30763c86aa70SEli Cohen 	queue_work(cma_wq, &work->work);
30773c86aa70SEli Cohen 
30783c86aa70SEli Cohen 	return 0;
30793c86aa70SEli Cohen 
30803c86aa70SEli Cohen out2:
30813c86aa70SEli Cohen 	kfree(mc->multicast.ib);
30823c86aa70SEli Cohen out1:
30833c86aa70SEli Cohen 	kfree(work);
30843c86aa70SEli Cohen 	return err;
30853c86aa70SEli Cohen }
30863c86aa70SEli Cohen 
3087c8f6a362SSean Hefty int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr,
3088c8f6a362SSean Hefty 			void *context)
3089c8f6a362SSean Hefty {
3090c8f6a362SSean Hefty 	struct rdma_id_private *id_priv;
3091c8f6a362SSean Hefty 	struct cma_multicast *mc;
3092c8f6a362SSean Hefty 	int ret;
3093c8f6a362SSean Hefty 
3094c8f6a362SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
3095550e5ca7SNir Muchtar 	if (!cma_comp(id_priv, RDMA_CM_ADDR_BOUND) &&
3096550e5ca7SNir Muchtar 	    !cma_comp(id_priv, RDMA_CM_ADDR_RESOLVED))
3097c8f6a362SSean Hefty 		return -EINVAL;
3098c8f6a362SSean Hefty 
3099c8f6a362SSean Hefty 	mc = kmalloc(sizeof *mc, GFP_KERNEL);
3100c8f6a362SSean Hefty 	if (!mc)
3101c8f6a362SSean Hefty 		return -ENOMEM;
3102c8f6a362SSean Hefty 
3103c8f6a362SSean Hefty 	memcpy(&mc->addr, addr, ip_addr_size(addr));
3104c8f6a362SSean Hefty 	mc->context = context;
3105c8f6a362SSean Hefty 	mc->id_priv = id_priv;
3106c8f6a362SSean Hefty 
3107c8f6a362SSean Hefty 	spin_lock(&id_priv->lock);
3108c8f6a362SSean Hefty 	list_add(&mc->list, &id_priv->mc_list);
3109c8f6a362SSean Hefty 	spin_unlock(&id_priv->lock);
3110c8f6a362SSean Hefty 
3111c8f6a362SSean Hefty 	switch (rdma_node_get_transport(id->device->node_type)) {
3112c8f6a362SSean Hefty 	case RDMA_TRANSPORT_IB:
31133c86aa70SEli Cohen 		switch (rdma_port_get_link_layer(id->device, id->port_num)) {
31143c86aa70SEli Cohen 		case IB_LINK_LAYER_INFINIBAND:
3115c8f6a362SSean Hefty 			ret = cma_join_ib_multicast(id_priv, mc);
3116c8f6a362SSean Hefty 			break;
31173c86aa70SEli Cohen 		case IB_LINK_LAYER_ETHERNET:
31183c86aa70SEli Cohen 			kref_init(&mc->mcref);
31193c86aa70SEli Cohen 			ret = cma_iboe_join_multicast(id_priv, mc);
31203c86aa70SEli Cohen 			break;
31213c86aa70SEli Cohen 		default:
31223c86aa70SEli Cohen 			ret = -EINVAL;
31233c86aa70SEli Cohen 		}
31243c86aa70SEli Cohen 		break;
3125c8f6a362SSean Hefty 	default:
3126c8f6a362SSean Hefty 		ret = -ENOSYS;
3127c8f6a362SSean Hefty 		break;
3128c8f6a362SSean Hefty 	}
3129c8f6a362SSean Hefty 
3130c8f6a362SSean Hefty 	if (ret) {
3131c8f6a362SSean Hefty 		spin_lock_irq(&id_priv->lock);
3132c8f6a362SSean Hefty 		list_del(&mc->list);
3133c8f6a362SSean Hefty 		spin_unlock_irq(&id_priv->lock);
3134c8f6a362SSean Hefty 		kfree(mc);
3135c8f6a362SSean Hefty 	}
3136c8f6a362SSean Hefty 	return ret;
3137c8f6a362SSean Hefty }
3138c8f6a362SSean Hefty EXPORT_SYMBOL(rdma_join_multicast);
3139c8f6a362SSean Hefty 
3140c8f6a362SSean Hefty void rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr)
3141c8f6a362SSean Hefty {
3142c8f6a362SSean Hefty 	struct rdma_id_private *id_priv;
3143c8f6a362SSean Hefty 	struct cma_multicast *mc;
3144c8f6a362SSean Hefty 
3145c8f6a362SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
3146c8f6a362SSean Hefty 	spin_lock_irq(&id_priv->lock);
3147c8f6a362SSean Hefty 	list_for_each_entry(mc, &id_priv->mc_list, list) {
3148c8f6a362SSean Hefty 		if (!memcmp(&mc->addr, addr, ip_addr_size(addr))) {
3149c8f6a362SSean Hefty 			list_del(&mc->list);
3150c8f6a362SSean Hefty 			spin_unlock_irq(&id_priv->lock);
3151c8f6a362SSean Hefty 
3152c8f6a362SSean Hefty 			if (id->qp)
3153c8f6a362SSean Hefty 				ib_detach_mcast(id->qp,
3154c8f6a362SSean Hefty 						&mc->multicast.ib->rec.mgid,
3155c8f6a362SSean Hefty 						mc->multicast.ib->rec.mlid);
31563c86aa70SEli Cohen 			if (rdma_node_get_transport(id_priv->cma_dev->device->node_type) == RDMA_TRANSPORT_IB) {
31573c86aa70SEli Cohen 				switch (rdma_port_get_link_layer(id->device, id->port_num)) {
31583c86aa70SEli Cohen 				case IB_LINK_LAYER_INFINIBAND:
3159c8f6a362SSean Hefty 					ib_sa_free_multicast(mc->multicast.ib);
3160c8f6a362SSean Hefty 					kfree(mc);
31613c86aa70SEli Cohen 					break;
31623c86aa70SEli Cohen 				case IB_LINK_LAYER_ETHERNET:
31633c86aa70SEli Cohen 					kref_put(&mc->mcref, release_mc);
31643c86aa70SEli Cohen 					break;
31653c86aa70SEli Cohen 				default:
31663c86aa70SEli Cohen 					break;
31673c86aa70SEli Cohen 				}
31683c86aa70SEli Cohen 			}
3169c8f6a362SSean Hefty 			return;
3170c8f6a362SSean Hefty 		}
3171c8f6a362SSean Hefty 	}
3172c8f6a362SSean Hefty 	spin_unlock_irq(&id_priv->lock);
3173c8f6a362SSean Hefty }
3174c8f6a362SSean Hefty EXPORT_SYMBOL(rdma_leave_multicast);
3175c8f6a362SSean Hefty 
3176dd5bdff8SOr Gerlitz static int cma_netdev_change(struct net_device *ndev, struct rdma_id_private *id_priv)
3177dd5bdff8SOr Gerlitz {
3178dd5bdff8SOr Gerlitz 	struct rdma_dev_addr *dev_addr;
3179dd5bdff8SOr Gerlitz 	struct cma_ndev_work *work;
3180dd5bdff8SOr Gerlitz 
3181dd5bdff8SOr Gerlitz 	dev_addr = &id_priv->id.route.addr.dev_addr;
3182dd5bdff8SOr Gerlitz 
31836266ed6eSSean Hefty 	if ((dev_addr->bound_dev_if == ndev->ifindex) &&
3184dd5bdff8SOr Gerlitz 	    memcmp(dev_addr->src_dev_addr, ndev->dev_addr, ndev->addr_len)) {
3185dd5bdff8SOr Gerlitz 		printk(KERN_INFO "RDMA CM addr change for ndev %s used by id %p\n",
3186dd5bdff8SOr Gerlitz 		       ndev->name, &id_priv->id);
3187dd5bdff8SOr Gerlitz 		work = kzalloc(sizeof *work, GFP_KERNEL);
3188dd5bdff8SOr Gerlitz 		if (!work)
3189dd5bdff8SOr Gerlitz 			return -ENOMEM;
3190dd5bdff8SOr Gerlitz 
3191dd5bdff8SOr Gerlitz 		INIT_WORK(&work->work, cma_ndev_work_handler);
3192dd5bdff8SOr Gerlitz 		work->id = id_priv;
3193dd5bdff8SOr Gerlitz 		work->event.event = RDMA_CM_EVENT_ADDR_CHANGE;
3194dd5bdff8SOr Gerlitz 		atomic_inc(&id_priv->refcount);
3195dd5bdff8SOr Gerlitz 		queue_work(cma_wq, &work->work);
3196dd5bdff8SOr Gerlitz 	}
3197dd5bdff8SOr Gerlitz 
3198dd5bdff8SOr Gerlitz 	return 0;
3199dd5bdff8SOr Gerlitz }
3200dd5bdff8SOr Gerlitz 
3201dd5bdff8SOr Gerlitz static int cma_netdev_callback(struct notifier_block *self, unsigned long event,
3202dd5bdff8SOr Gerlitz 			       void *ctx)
3203dd5bdff8SOr Gerlitz {
3204dd5bdff8SOr Gerlitz 	struct net_device *ndev = (struct net_device *)ctx;
3205dd5bdff8SOr Gerlitz 	struct cma_device *cma_dev;
3206dd5bdff8SOr Gerlitz 	struct rdma_id_private *id_priv;
3207dd5bdff8SOr Gerlitz 	int ret = NOTIFY_DONE;
3208dd5bdff8SOr Gerlitz 
3209dd5bdff8SOr Gerlitz 	if (dev_net(ndev) != &init_net)
3210dd5bdff8SOr Gerlitz 		return NOTIFY_DONE;
3211dd5bdff8SOr Gerlitz 
3212dd5bdff8SOr Gerlitz 	if (event != NETDEV_BONDING_FAILOVER)
3213dd5bdff8SOr Gerlitz 		return NOTIFY_DONE;
3214dd5bdff8SOr Gerlitz 
3215dd5bdff8SOr Gerlitz 	if (!(ndev->flags & IFF_MASTER) || !(ndev->priv_flags & IFF_BONDING))
3216dd5bdff8SOr Gerlitz 		return NOTIFY_DONE;
3217dd5bdff8SOr Gerlitz 
3218dd5bdff8SOr Gerlitz 	mutex_lock(&lock);
3219dd5bdff8SOr Gerlitz 	list_for_each_entry(cma_dev, &dev_list, list)
3220dd5bdff8SOr Gerlitz 		list_for_each_entry(id_priv, &cma_dev->id_list, list) {
3221dd5bdff8SOr Gerlitz 			ret = cma_netdev_change(ndev, id_priv);
3222dd5bdff8SOr Gerlitz 			if (ret)
3223dd5bdff8SOr Gerlitz 				goto out;
3224dd5bdff8SOr Gerlitz 		}
3225dd5bdff8SOr Gerlitz 
3226dd5bdff8SOr Gerlitz out:
3227dd5bdff8SOr Gerlitz 	mutex_unlock(&lock);
3228dd5bdff8SOr Gerlitz 	return ret;
3229dd5bdff8SOr Gerlitz }
3230dd5bdff8SOr Gerlitz 
3231dd5bdff8SOr Gerlitz static struct notifier_block cma_nb = {
3232dd5bdff8SOr Gerlitz 	.notifier_call = cma_netdev_callback
3233dd5bdff8SOr Gerlitz };
3234dd5bdff8SOr Gerlitz 
3235e51060f0SSean Hefty static void cma_add_one(struct ib_device *device)
3236e51060f0SSean Hefty {
3237e51060f0SSean Hefty 	struct cma_device *cma_dev;
3238e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
3239e51060f0SSean Hefty 
3240e51060f0SSean Hefty 	cma_dev = kmalloc(sizeof *cma_dev, GFP_KERNEL);
3241e51060f0SSean Hefty 	if (!cma_dev)
3242e51060f0SSean Hefty 		return;
3243e51060f0SSean Hefty 
3244e51060f0SSean Hefty 	cma_dev->device = device;
3245e51060f0SSean Hefty 
3246e51060f0SSean Hefty 	init_completion(&cma_dev->comp);
3247e51060f0SSean Hefty 	atomic_set(&cma_dev->refcount, 1);
3248e51060f0SSean Hefty 	INIT_LIST_HEAD(&cma_dev->id_list);
3249e51060f0SSean Hefty 	ib_set_client_data(device, &cma_client, cma_dev);
3250e51060f0SSean Hefty 
3251e51060f0SSean Hefty 	mutex_lock(&lock);
3252e51060f0SSean Hefty 	list_add_tail(&cma_dev->list, &dev_list);
3253e51060f0SSean Hefty 	list_for_each_entry(id_priv, &listen_any_list, list)
3254e51060f0SSean Hefty 		cma_listen_on_dev(id_priv, cma_dev);
3255e51060f0SSean Hefty 	mutex_unlock(&lock);
3256e51060f0SSean Hefty }
3257e51060f0SSean Hefty 
3258e51060f0SSean Hefty static int cma_remove_id_dev(struct rdma_id_private *id_priv)
3259e51060f0SSean Hefty {
3260a1b1b61fSSean Hefty 	struct rdma_cm_event event;
3261550e5ca7SNir Muchtar 	enum rdma_cm_state state;
3262de910bd9SOr Gerlitz 	int ret = 0;
3263e51060f0SSean Hefty 
3264e51060f0SSean Hefty 	/* Record that we want to remove the device */
3265550e5ca7SNir Muchtar 	state = cma_exch(id_priv, RDMA_CM_DEVICE_REMOVAL);
3266550e5ca7SNir Muchtar 	if (state == RDMA_CM_DESTROYING)
3267e51060f0SSean Hefty 		return 0;
3268e51060f0SSean Hefty 
3269e51060f0SSean Hefty 	cma_cancel_operation(id_priv, state);
3270de910bd9SOr Gerlitz 	mutex_lock(&id_priv->handler_mutex);
3271e51060f0SSean Hefty 
3272e51060f0SSean Hefty 	/* Check for destruction from another callback. */
3273550e5ca7SNir Muchtar 	if (!cma_comp(id_priv, RDMA_CM_DEVICE_REMOVAL))
3274de910bd9SOr Gerlitz 		goto out;
3275e51060f0SSean Hefty 
3276a1b1b61fSSean Hefty 	memset(&event, 0, sizeof event);
3277a1b1b61fSSean Hefty 	event.event = RDMA_CM_EVENT_DEVICE_REMOVAL;
3278de910bd9SOr Gerlitz 	ret = id_priv->id.event_handler(&id_priv->id, &event);
3279de910bd9SOr Gerlitz out:
3280de910bd9SOr Gerlitz 	mutex_unlock(&id_priv->handler_mutex);
3281de910bd9SOr Gerlitz 	return ret;
3282e51060f0SSean Hefty }
3283e51060f0SSean Hefty 
3284e51060f0SSean Hefty static void cma_process_remove(struct cma_device *cma_dev)
3285e51060f0SSean Hefty {
3286e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
3287e51060f0SSean Hefty 	int ret;
3288e51060f0SSean Hefty 
3289e51060f0SSean Hefty 	mutex_lock(&lock);
3290e51060f0SSean Hefty 	while (!list_empty(&cma_dev->id_list)) {
3291e51060f0SSean Hefty 		id_priv = list_entry(cma_dev->id_list.next,
3292e51060f0SSean Hefty 				     struct rdma_id_private, list);
3293e51060f0SSean Hefty 
3294d02d1f53SSean Hefty 		list_del(&id_priv->listen_list);
329594de178aSKrishna Kumar 		list_del_init(&id_priv->list);
3296e51060f0SSean Hefty 		atomic_inc(&id_priv->refcount);
3297e51060f0SSean Hefty 		mutex_unlock(&lock);
3298e51060f0SSean Hefty 
3299d02d1f53SSean Hefty 		ret = id_priv->internal_id ? 1 : cma_remove_id_dev(id_priv);
3300e51060f0SSean Hefty 		cma_deref_id(id_priv);
3301e51060f0SSean Hefty 		if (ret)
3302e51060f0SSean Hefty 			rdma_destroy_id(&id_priv->id);
3303e51060f0SSean Hefty 
3304e51060f0SSean Hefty 		mutex_lock(&lock);
3305e51060f0SSean Hefty 	}
3306e51060f0SSean Hefty 	mutex_unlock(&lock);
3307e51060f0SSean Hefty 
3308e51060f0SSean Hefty 	cma_deref_dev(cma_dev);
3309e51060f0SSean Hefty 	wait_for_completion(&cma_dev->comp);
3310e51060f0SSean Hefty }
3311e51060f0SSean Hefty 
3312e51060f0SSean Hefty static void cma_remove_one(struct ib_device *device)
3313e51060f0SSean Hefty {
3314e51060f0SSean Hefty 	struct cma_device *cma_dev;
3315e51060f0SSean Hefty 
3316e51060f0SSean Hefty 	cma_dev = ib_get_client_data(device, &cma_client);
3317e51060f0SSean Hefty 	if (!cma_dev)
3318e51060f0SSean Hefty 		return;
3319e51060f0SSean Hefty 
3320e51060f0SSean Hefty 	mutex_lock(&lock);
3321e51060f0SSean Hefty 	list_del(&cma_dev->list);
3322e51060f0SSean Hefty 	mutex_unlock(&lock);
3323e51060f0SSean Hefty 
3324e51060f0SSean Hefty 	cma_process_remove(cma_dev);
3325e51060f0SSean Hefty 	kfree(cma_dev);
3326e51060f0SSean Hefty }
3327e51060f0SSean Hefty 
3328753f618aSNir Muchtar static int cma_get_id_stats(struct sk_buff *skb, struct netlink_callback *cb)
3329753f618aSNir Muchtar {
3330753f618aSNir Muchtar 	struct nlmsghdr *nlh;
3331753f618aSNir Muchtar 	struct rdma_cm_id_stats *id_stats;
3332753f618aSNir Muchtar 	struct rdma_id_private *id_priv;
3333753f618aSNir Muchtar 	struct rdma_cm_id *id = NULL;
3334753f618aSNir Muchtar 	struct cma_device *cma_dev;
3335753f618aSNir Muchtar 	int i_dev = 0, i_id = 0;
3336753f618aSNir Muchtar 
3337753f618aSNir Muchtar 	/*
3338753f618aSNir Muchtar 	 * We export all of the IDs as a sequence of messages.  Each
3339753f618aSNir Muchtar 	 * ID gets its own netlink message.
3340753f618aSNir Muchtar 	 */
3341753f618aSNir Muchtar 	mutex_lock(&lock);
3342753f618aSNir Muchtar 
3343753f618aSNir Muchtar 	list_for_each_entry(cma_dev, &dev_list, list) {
3344753f618aSNir Muchtar 		if (i_dev < cb->args[0]) {
3345753f618aSNir Muchtar 			i_dev++;
3346753f618aSNir Muchtar 			continue;
3347753f618aSNir Muchtar 		}
3348753f618aSNir Muchtar 
3349753f618aSNir Muchtar 		i_id = 0;
3350753f618aSNir Muchtar 		list_for_each_entry(id_priv, &cma_dev->id_list, list) {
3351753f618aSNir Muchtar 			if (i_id < cb->args[1]) {
3352753f618aSNir Muchtar 				i_id++;
3353753f618aSNir Muchtar 				continue;
3354753f618aSNir Muchtar 			}
3355753f618aSNir Muchtar 
3356753f618aSNir Muchtar 			id_stats = ibnl_put_msg(skb, &nlh, cb->nlh->nlmsg_seq,
3357753f618aSNir Muchtar 						sizeof *id_stats, RDMA_NL_RDMA_CM,
3358753f618aSNir Muchtar 						RDMA_NL_RDMA_CM_ID_STATS);
3359753f618aSNir Muchtar 			if (!id_stats)
3360753f618aSNir Muchtar 				goto out;
3361753f618aSNir Muchtar 
3362753f618aSNir Muchtar 			memset(id_stats, 0, sizeof *id_stats);
3363753f618aSNir Muchtar 			id = &id_priv->id;
3364753f618aSNir Muchtar 			id_stats->node_type = id->route.addr.dev_addr.dev_type;
3365753f618aSNir Muchtar 			id_stats->port_num = id->port_num;
3366753f618aSNir Muchtar 			id_stats->bound_dev_if =
3367753f618aSNir Muchtar 				id->route.addr.dev_addr.bound_dev_if;
3368753f618aSNir Muchtar 
3369753f618aSNir Muchtar 			if (id->route.addr.src_addr.ss_family == AF_INET) {
3370753f618aSNir Muchtar 				if (ibnl_put_attr(skb, nlh,
3371753f618aSNir Muchtar 						  sizeof(struct sockaddr_in),
3372753f618aSNir Muchtar 						  &id->route.addr.src_addr,
3373753f618aSNir Muchtar 						  RDMA_NL_RDMA_CM_ATTR_SRC_ADDR)) {
3374753f618aSNir Muchtar 					goto out;
3375753f618aSNir Muchtar 				}
3376753f618aSNir Muchtar 				if (ibnl_put_attr(skb, nlh,
3377753f618aSNir Muchtar 						  sizeof(struct sockaddr_in),
3378753f618aSNir Muchtar 						  &id->route.addr.dst_addr,
3379753f618aSNir Muchtar 						  RDMA_NL_RDMA_CM_ATTR_DST_ADDR)) {
3380753f618aSNir Muchtar 					goto out;
3381753f618aSNir Muchtar 				}
3382753f618aSNir Muchtar 			} else if (id->route.addr.src_addr.ss_family == AF_INET6) {
3383753f618aSNir Muchtar 				if (ibnl_put_attr(skb, nlh,
3384753f618aSNir Muchtar 						  sizeof(struct sockaddr_in6),
3385753f618aSNir Muchtar 						  &id->route.addr.src_addr,
3386753f618aSNir Muchtar 						  RDMA_NL_RDMA_CM_ATTR_SRC_ADDR)) {
3387753f618aSNir Muchtar 					goto out;
3388753f618aSNir Muchtar 				}
3389753f618aSNir Muchtar 				if (ibnl_put_attr(skb, nlh,
3390753f618aSNir Muchtar 						  sizeof(struct sockaddr_in6),
3391753f618aSNir Muchtar 						  &id->route.addr.dst_addr,
3392753f618aSNir Muchtar 						  RDMA_NL_RDMA_CM_ATTR_DST_ADDR)) {
3393753f618aSNir Muchtar 					goto out;
3394753f618aSNir Muchtar 				}
3395753f618aSNir Muchtar 			}
3396753f618aSNir Muchtar 
339783e9502dSNir Muchtar 			id_stats->pid		= id_priv->owner;
3398753f618aSNir Muchtar 			id_stats->port_space	= id->ps;
3399753f618aSNir Muchtar 			id_stats->cm_state	= id_priv->state;
3400753f618aSNir Muchtar 			id_stats->qp_num	= id_priv->qp_num;
3401753f618aSNir Muchtar 			id_stats->qp_type	= id->qp_type;
3402753f618aSNir Muchtar 
3403753f618aSNir Muchtar 			i_id++;
3404753f618aSNir Muchtar 		}
3405753f618aSNir Muchtar 
3406753f618aSNir Muchtar 		cb->args[1] = 0;
3407753f618aSNir Muchtar 		i_dev++;
3408753f618aSNir Muchtar 	}
3409753f618aSNir Muchtar 
3410753f618aSNir Muchtar out:
3411753f618aSNir Muchtar 	mutex_unlock(&lock);
3412753f618aSNir Muchtar 	cb->args[0] = i_dev;
3413753f618aSNir Muchtar 	cb->args[1] = i_id;
3414753f618aSNir Muchtar 
3415753f618aSNir Muchtar 	return skb->len;
3416753f618aSNir Muchtar }
3417753f618aSNir Muchtar 
3418753f618aSNir Muchtar static const struct ibnl_client_cbs cma_cb_table[] = {
3419753f618aSNir Muchtar 	[RDMA_NL_RDMA_CM_ID_STATS] = { .dump = cma_get_id_stats },
3420753f618aSNir Muchtar };
3421753f618aSNir Muchtar 
3422716abb1fSPeter Huewe static int __init cma_init(void)
3423e51060f0SSean Hefty {
34245d7220e8STetsuo Handa 	int ret;
3425227b60f5SStephen Hemminger 
3426c7f743a6SSean Hefty 	cma_wq = create_singlethread_workqueue("rdma_cm");
3427e51060f0SSean Hefty 	if (!cma_wq)
3428e51060f0SSean Hefty 		return -ENOMEM;
3429e51060f0SSean Hefty 
3430c1a0b23bSMichael S. Tsirkin 	ib_sa_register_client(&sa_client);
34317a118df3SSean Hefty 	rdma_addr_register_client(&addr_client);
3432dd5bdff8SOr Gerlitz 	register_netdevice_notifier(&cma_nb);
3433c1a0b23bSMichael S. Tsirkin 
3434e51060f0SSean Hefty 	ret = ib_register_client(&cma_client);
3435e51060f0SSean Hefty 	if (ret)
3436e51060f0SSean Hefty 		goto err;
3437753f618aSNir Muchtar 
3438753f618aSNir Muchtar 	if (ibnl_add_client(RDMA_NL_RDMA_CM, RDMA_NL_RDMA_CM_NUM_OPS, cma_cb_table))
3439753f618aSNir Muchtar 		printk(KERN_WARNING "RDMA CMA: failed to add netlink callback\n");
3440753f618aSNir Muchtar 
3441e51060f0SSean Hefty 	return 0;
3442e51060f0SSean Hefty 
3443e51060f0SSean Hefty err:
3444dd5bdff8SOr Gerlitz 	unregister_netdevice_notifier(&cma_nb);
34457a118df3SSean Hefty 	rdma_addr_unregister_client(&addr_client);
3446c1a0b23bSMichael S. Tsirkin 	ib_sa_unregister_client(&sa_client);
3447e51060f0SSean Hefty 	destroy_workqueue(cma_wq);
3448e51060f0SSean Hefty 	return ret;
3449e51060f0SSean Hefty }
3450e51060f0SSean Hefty 
3451716abb1fSPeter Huewe static void __exit cma_cleanup(void)
3452e51060f0SSean Hefty {
3453753f618aSNir Muchtar 	ibnl_remove_client(RDMA_NL_RDMA_CM);
3454e51060f0SSean Hefty 	ib_unregister_client(&cma_client);
3455dd5bdff8SOr Gerlitz 	unregister_netdevice_notifier(&cma_nb);
34567a118df3SSean Hefty 	rdma_addr_unregister_client(&addr_client);
3457c1a0b23bSMichael S. Tsirkin 	ib_sa_unregister_client(&sa_client);
3458e51060f0SSean Hefty 	destroy_workqueue(cma_wq);
3459e51060f0SSean Hefty 	idr_destroy(&sdp_ps);
3460e51060f0SSean Hefty 	idr_destroy(&tcp_ps);
3461628e5f6dSSean Hefty 	idr_destroy(&udp_ps);
3462c8f6a362SSean Hefty 	idr_destroy(&ipoib_ps);
3463e51060f0SSean Hefty }
3464e51060f0SSean Hefty 
3465e51060f0SSean Hefty module_init(cma_init);
3466e51060f0SSean Hefty module_exit(cma_cleanup);
3467