xref: /linux/drivers/infiniband/core/cma.c (revision 6da2ec56059c3c7a7e5f729e6349e74ace1e5c57)
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>
41bee3c3c9SMoni Shoua #include <linux/igmp.h>
42e51060f0SSean Hefty #include <linux/idr.h>
4307ebafbaSTom Tucker #include <linux/inetdevice.h>
445a0e3ad6STejun Heo #include <linux/slab.h>
45e4dd23d7SPaul Gortmaker #include <linux/module.h>
46366cddb4SAmir Vadai #include <net/route.h>
47e51060f0SSean Hefty 
484be74b42SHaggai Eran #include <net/net_namespace.h>
494be74b42SHaggai Eran #include <net/netns/generic.h>
50e51060f0SSean Hefty #include <net/tcp.h>
511f5175adSAleksey Senin #include <net/ipv6.h>
52f887f2acSHaggai Eran #include <net/ip_fib.h>
53f887f2acSHaggai Eran #include <net/ip6_route.h>
54e51060f0SSean Hefty 
55e51060f0SSean Hefty #include <rdma/rdma_cm.h>
56e51060f0SSean Hefty #include <rdma/rdma_cm_ib.h>
57753f618aSNir Muchtar #include <rdma/rdma_netlink.h>
582e2d190cSSean Hefty #include <rdma/ib.h>
59e51060f0SSean Hefty #include <rdma/ib_cache.h>
60e51060f0SSean Hefty #include <rdma/ib_cm.h>
61e51060f0SSean Hefty #include <rdma/ib_sa.h>
6207ebafbaSTom Tucker #include <rdma/iw_cm.h>
63e51060f0SSean Hefty 
64218a773fSMatan Barak #include "core_priv.h"
65a3b641afSSteve Wise #include "cma_priv.h"
66218a773fSMatan Barak 
67e51060f0SSean Hefty MODULE_AUTHOR("Sean Hefty");
68e51060f0SSean Hefty MODULE_DESCRIPTION("Generic RDMA CM Agent");
69e51060f0SSean Hefty MODULE_LICENSE("Dual BSD/GPL");
70e51060f0SSean Hefty 
71e51060f0SSean Hefty #define CMA_CM_RESPONSE_TIMEOUT 20
72ab15c95aSAlex Vesker #define CMA_QUERY_CLASSPORT_INFO_TIMEOUT 3000
73d5bb7599SMichael S. Tsirkin #define CMA_MAX_CM_RETRIES 15
74dcb3f974SSean Hefty #define CMA_CM_MRA_SETTING (IB_CM_MRA_FLAG_DELAY | 24)
753c86aa70SEli Cohen #define CMA_IBOE_PACKET_LIFETIME 18
765ab2d89bSLeon Romanovsky #define CMA_PREFERRED_ROCE_GID_TYPE IB_GID_TYPE_ROCE_UDP_ENCAP
77e51060f0SSean Hefty 
782b1b5b60SSagi Grimberg static const char * const cma_events[] = {
792b1b5b60SSagi Grimberg 	[RDMA_CM_EVENT_ADDR_RESOLVED]	 = "address resolved",
802b1b5b60SSagi Grimberg 	[RDMA_CM_EVENT_ADDR_ERROR]	 = "address error",
812b1b5b60SSagi Grimberg 	[RDMA_CM_EVENT_ROUTE_RESOLVED]	 = "route resolved ",
822b1b5b60SSagi Grimberg 	[RDMA_CM_EVENT_ROUTE_ERROR]	 = "route error",
832b1b5b60SSagi Grimberg 	[RDMA_CM_EVENT_CONNECT_REQUEST]	 = "connect request",
842b1b5b60SSagi Grimberg 	[RDMA_CM_EVENT_CONNECT_RESPONSE] = "connect response",
852b1b5b60SSagi Grimberg 	[RDMA_CM_EVENT_CONNECT_ERROR]	 = "connect error",
862b1b5b60SSagi Grimberg 	[RDMA_CM_EVENT_UNREACHABLE]	 = "unreachable",
872b1b5b60SSagi Grimberg 	[RDMA_CM_EVENT_REJECTED]	 = "rejected",
882b1b5b60SSagi Grimberg 	[RDMA_CM_EVENT_ESTABLISHED]	 = "established",
892b1b5b60SSagi Grimberg 	[RDMA_CM_EVENT_DISCONNECTED]	 = "disconnected",
902b1b5b60SSagi Grimberg 	[RDMA_CM_EVENT_DEVICE_REMOVAL]	 = "device removal",
912b1b5b60SSagi Grimberg 	[RDMA_CM_EVENT_MULTICAST_JOIN]	 = "multicast join",
922b1b5b60SSagi Grimberg 	[RDMA_CM_EVENT_MULTICAST_ERROR]	 = "multicast error",
932b1b5b60SSagi Grimberg 	[RDMA_CM_EVENT_ADDR_CHANGE]	 = "address change",
942b1b5b60SSagi Grimberg 	[RDMA_CM_EVENT_TIMEWAIT_EXIT]	 = "timewait exit",
952b1b5b60SSagi Grimberg };
962b1b5b60SSagi Grimberg 
97db7489e0SBart Van Assche const char *__attribute_const__ rdma_event_msg(enum rdma_cm_event_type event)
982b1b5b60SSagi Grimberg {
992b1b5b60SSagi Grimberg 	size_t index = event;
1002b1b5b60SSagi Grimberg 
1012b1b5b60SSagi Grimberg 	return (index < ARRAY_SIZE(cma_events) && cma_events[index]) ?
1022b1b5b60SSagi Grimberg 			cma_events[index] : "unrecognized event";
1032b1b5b60SSagi Grimberg }
1042b1b5b60SSagi Grimberg EXPORT_SYMBOL(rdma_event_msg);
1052b1b5b60SSagi Grimberg 
10677a5db13SSteve Wise const char *__attribute_const__ rdma_reject_msg(struct rdma_cm_id *id,
10777a5db13SSteve Wise 						int reason)
10877a5db13SSteve Wise {
10977a5db13SSteve Wise 	if (rdma_ib_or_roce(id->device, id->port_num))
11077a5db13SSteve Wise 		return ibcm_reject_msg(reason);
11177a5db13SSteve Wise 
11277a5db13SSteve Wise 	if (rdma_protocol_iwarp(id->device, id->port_num))
11377a5db13SSteve Wise 		return iwcm_reject_msg(reason);
11477a5db13SSteve Wise 
11577a5db13SSteve Wise 	WARN_ON_ONCE(1);
11677a5db13SSteve Wise 	return "unrecognized transport";
11777a5db13SSteve Wise }
11877a5db13SSteve Wise EXPORT_SYMBOL(rdma_reject_msg);
11977a5db13SSteve Wise 
1205042a73dSSteve Wise bool rdma_is_consumer_reject(struct rdma_cm_id *id, int reason)
1215042a73dSSteve Wise {
1225042a73dSSteve Wise 	if (rdma_ib_or_roce(id->device, id->port_num))
1235042a73dSSteve Wise 		return reason == IB_CM_REJ_CONSUMER_DEFINED;
1245042a73dSSteve Wise 
1255042a73dSSteve Wise 	if (rdma_protocol_iwarp(id->device, id->port_num))
1265042a73dSSteve Wise 		return reason == -ECONNREFUSED;
1275042a73dSSteve Wise 
1285042a73dSSteve Wise 	WARN_ON_ONCE(1);
1295042a73dSSteve Wise 	return false;
1305042a73dSSteve Wise }
1315042a73dSSteve Wise EXPORT_SYMBOL(rdma_is_consumer_reject);
1325042a73dSSteve Wise 
1335f244104SSteve Wise const void *rdma_consumer_reject_data(struct rdma_cm_id *id,
1345f244104SSteve Wise 				      struct rdma_cm_event *ev, u8 *data_len)
1355f244104SSteve Wise {
1365f244104SSteve Wise 	const void *p;
1375f244104SSteve Wise 
1385f244104SSteve Wise 	if (rdma_is_consumer_reject(id, ev->status)) {
1395f244104SSteve Wise 		*data_len = ev->param.conn.private_data_len;
1405f244104SSteve Wise 		p = ev->param.conn.private_data;
1415f244104SSteve Wise 	} else {
1425f244104SSteve Wise 		*data_len = 0;
1435f244104SSteve Wise 		p = NULL;
1445f244104SSteve Wise 	}
1455f244104SSteve Wise 	return p;
1465f244104SSteve Wise }
1475f244104SSteve Wise EXPORT_SYMBOL(rdma_consumer_reject_data);
1485f244104SSteve Wise 
149fbdb0a91SSteve Wise /**
150fbdb0a91SSteve Wise  * rdma_iw_cm_id() - return the iw_cm_id pointer for this cm_id.
151fbdb0a91SSteve Wise  * @id: Communication Identifier
152fbdb0a91SSteve Wise  */
153fbdb0a91SSteve Wise struct iw_cm_id *rdma_iw_cm_id(struct rdma_cm_id *id)
154fbdb0a91SSteve Wise {
155fbdb0a91SSteve Wise 	struct rdma_id_private *id_priv;
156fbdb0a91SSteve Wise 
157fbdb0a91SSteve Wise 	id_priv = container_of(id, struct rdma_id_private, id);
158fbdb0a91SSteve Wise 	if (id->device->node_type == RDMA_NODE_RNIC)
159fbdb0a91SSteve Wise 		return id_priv->cm_id.iw;
160fbdb0a91SSteve Wise 	return NULL;
161fbdb0a91SSteve Wise }
162fbdb0a91SSteve Wise EXPORT_SYMBOL(rdma_iw_cm_id);
163fbdb0a91SSteve Wise 
164fbdb0a91SSteve Wise /**
165fbdb0a91SSteve Wise  * rdma_res_to_id() - return the rdma_cm_id pointer for this restrack.
166fbdb0a91SSteve Wise  * @res: rdma resource tracking entry pointer
167fbdb0a91SSteve Wise  */
168fbdb0a91SSteve Wise struct rdma_cm_id *rdma_res_to_id(struct rdma_restrack_entry *res)
169fbdb0a91SSteve Wise {
170fbdb0a91SSteve Wise 	struct rdma_id_private *id_priv =
171fbdb0a91SSteve Wise 		container_of(res, struct rdma_id_private, res);
172fbdb0a91SSteve Wise 
173fbdb0a91SSteve Wise 	return &id_priv->id;
174fbdb0a91SSteve Wise }
175fbdb0a91SSteve Wise EXPORT_SYMBOL(rdma_res_to_id);
176fbdb0a91SSteve Wise 
177e51060f0SSean Hefty static void cma_add_one(struct ib_device *device);
1787c1eb45aSHaggai Eran static void cma_remove_one(struct ib_device *device, void *client_data);
179e51060f0SSean Hefty 
180e51060f0SSean Hefty static struct ib_client cma_client = {
181e51060f0SSean Hefty 	.name   = "cma",
182e51060f0SSean Hefty 	.add    = cma_add_one,
183e51060f0SSean Hefty 	.remove = cma_remove_one
184e51060f0SSean Hefty };
185e51060f0SSean Hefty 
186c1a0b23bSMichael S. Tsirkin static struct ib_sa_client sa_client;
187e51060f0SSean Hefty static LIST_HEAD(dev_list);
188e51060f0SSean Hefty static LIST_HEAD(listen_any_list);
189e51060f0SSean Hefty static DEFINE_MUTEX(lock);
190e51060f0SSean Hefty static struct workqueue_struct *cma_wq;
191c7d03a00SAlexey Dobriyan static unsigned int cma_pernet_id;
192e51060f0SSean Hefty 
1934be74b42SHaggai Eran struct cma_pernet {
1944be74b42SHaggai Eran 	struct idr tcp_ps;
1954be74b42SHaggai Eran 	struct idr udp_ps;
1964be74b42SHaggai Eran 	struct idr ipoib_ps;
1974be74b42SHaggai Eran 	struct idr ib_ps;
1984be74b42SHaggai Eran };
1994be74b42SHaggai Eran 
2004be74b42SHaggai Eran static struct cma_pernet *cma_pernet(struct net *net)
201aac978e1SHaggai Eran {
2024be74b42SHaggai Eran 	return net_generic(net, cma_pernet_id);
2034be74b42SHaggai Eran }
2044be74b42SHaggai Eran 
2052253fc0cSSteve Wise static struct idr *cma_pernet_idr(struct net *net, enum rdma_ucm_port_space ps)
2064be74b42SHaggai Eran {
2074be74b42SHaggai Eran 	struct cma_pernet *pernet = cma_pernet(net);
2084be74b42SHaggai Eran 
209aac978e1SHaggai Eran 	switch (ps) {
210aac978e1SHaggai Eran 	case RDMA_PS_TCP:
2114be74b42SHaggai Eran 		return &pernet->tcp_ps;
212aac978e1SHaggai Eran 	case RDMA_PS_UDP:
2134be74b42SHaggai Eran 		return &pernet->udp_ps;
214aac978e1SHaggai Eran 	case RDMA_PS_IPOIB:
2154be74b42SHaggai Eran 		return &pernet->ipoib_ps;
216aac978e1SHaggai Eran 	case RDMA_PS_IB:
2174be74b42SHaggai Eran 		return &pernet->ib_ps;
218aac978e1SHaggai Eran 	default:
219aac978e1SHaggai Eran 		return NULL;
220aac978e1SHaggai Eran 	}
221aac978e1SHaggai Eran }
222aac978e1SHaggai Eran 
223e51060f0SSean Hefty struct cma_device {
224e51060f0SSean Hefty 	struct list_head	list;
225e51060f0SSean Hefty 	struct ib_device	*device;
226e51060f0SSean Hefty 	struct completion	comp;
227e51060f0SSean Hefty 	atomic_t		refcount;
228e51060f0SSean Hefty 	struct list_head	id_list;
229045959dbSMatan Barak 	enum ib_gid_type	*default_gid_type;
23089052d78SMajd Dibbiny 	u8			*default_roce_tos;
231e51060f0SSean Hefty };
232e51060f0SSean Hefty 
233e51060f0SSean Hefty struct rdma_bind_list {
2342253fc0cSSteve Wise 	enum rdma_ucm_port_space ps;
235e51060f0SSean Hefty 	struct hlist_head	owners;
236e51060f0SSean Hefty 	unsigned short		port;
237e51060f0SSean Hefty };
238e51060f0SSean Hefty 
239ab15c95aSAlex Vesker struct class_port_info_context {
240ab15c95aSAlex Vesker 	struct ib_class_port_info	*class_port_info;
241ab15c95aSAlex Vesker 	struct ib_device		*device;
242ab15c95aSAlex Vesker 	struct completion		done;
243ab15c95aSAlex Vesker 	struct ib_sa_query		*sa_query;
244ab15c95aSAlex Vesker 	u8				port_num;
245ab15c95aSAlex Vesker };
246ab15c95aSAlex Vesker 
2472253fc0cSSteve Wise static int cma_ps_alloc(struct net *net, enum rdma_ucm_port_space ps,
248aac978e1SHaggai Eran 			struct rdma_bind_list *bind_list, int snum)
249aac978e1SHaggai Eran {
2504be74b42SHaggai Eran 	struct idr *idr = cma_pernet_idr(net, ps);
251aac978e1SHaggai Eran 
252aac978e1SHaggai Eran 	return idr_alloc(idr, bind_list, snum, snum + 1, GFP_KERNEL);
253aac978e1SHaggai Eran }
254aac978e1SHaggai Eran 
2554be74b42SHaggai Eran static struct rdma_bind_list *cma_ps_find(struct net *net,
2562253fc0cSSteve Wise 					  enum rdma_ucm_port_space ps, int snum)
257aac978e1SHaggai Eran {
2584be74b42SHaggai Eran 	struct idr *idr = cma_pernet_idr(net, ps);
259aac978e1SHaggai Eran 
260aac978e1SHaggai Eran 	return idr_find(idr, snum);
261aac978e1SHaggai Eran }
262aac978e1SHaggai Eran 
2632253fc0cSSteve Wise static void cma_ps_remove(struct net *net, enum rdma_ucm_port_space ps,
2642253fc0cSSteve Wise 			  int snum)
265aac978e1SHaggai Eran {
2664be74b42SHaggai Eran 	struct idr *idr = cma_pernet_idr(net, ps);
267aac978e1SHaggai Eran 
268aac978e1SHaggai Eran 	idr_remove(idr, snum);
269aac978e1SHaggai Eran }
270aac978e1SHaggai Eran 
27168602120SSean Hefty enum {
27268602120SSean Hefty 	CMA_OPTION_AFONLY,
27368602120SSean Hefty };
27468602120SSean Hefty 
275218a773fSMatan Barak void cma_ref_dev(struct cma_device *cma_dev)
276218a773fSMatan Barak {
277218a773fSMatan Barak 	atomic_inc(&cma_dev->refcount);
278218a773fSMatan Barak }
279218a773fSMatan Barak 
280045959dbSMatan Barak struct cma_device *cma_enum_devices_by_ibdev(cma_device_filter	filter,
281045959dbSMatan Barak 					     void		*cookie)
282045959dbSMatan Barak {
283045959dbSMatan Barak 	struct cma_device *cma_dev;
284045959dbSMatan Barak 	struct cma_device *found_cma_dev = NULL;
285045959dbSMatan Barak 
286045959dbSMatan Barak 	mutex_lock(&lock);
287045959dbSMatan Barak 
288045959dbSMatan Barak 	list_for_each_entry(cma_dev, &dev_list, list)
289045959dbSMatan Barak 		if (filter(cma_dev->device, cookie)) {
290045959dbSMatan Barak 			found_cma_dev = cma_dev;
291045959dbSMatan Barak 			break;
292045959dbSMatan Barak 		}
293045959dbSMatan Barak 
294045959dbSMatan Barak 	if (found_cma_dev)
295045959dbSMatan Barak 		cma_ref_dev(found_cma_dev);
296045959dbSMatan Barak 	mutex_unlock(&lock);
297045959dbSMatan Barak 	return found_cma_dev;
298045959dbSMatan Barak }
299045959dbSMatan Barak 
300045959dbSMatan Barak int cma_get_default_gid_type(struct cma_device *cma_dev,
301045959dbSMatan Barak 			     unsigned int port)
302045959dbSMatan Barak {
30324dc831bSYuval Shaia 	if (!rdma_is_port_valid(cma_dev->device, port))
304045959dbSMatan Barak 		return -EINVAL;
305045959dbSMatan Barak 
306045959dbSMatan Barak 	return cma_dev->default_gid_type[port - rdma_start_port(cma_dev->device)];
307045959dbSMatan Barak }
308045959dbSMatan Barak 
309045959dbSMatan Barak int cma_set_default_gid_type(struct cma_device *cma_dev,
310045959dbSMatan Barak 			     unsigned int port,
311045959dbSMatan Barak 			     enum ib_gid_type default_gid_type)
312045959dbSMatan Barak {
313045959dbSMatan Barak 	unsigned long supported_gids;
314045959dbSMatan Barak 
31524dc831bSYuval Shaia 	if (!rdma_is_port_valid(cma_dev->device, port))
316045959dbSMatan Barak 		return -EINVAL;
317045959dbSMatan Barak 
318045959dbSMatan Barak 	supported_gids = roce_gid_type_mask_support(cma_dev->device, port);
319045959dbSMatan Barak 
320045959dbSMatan Barak 	if (!(supported_gids & 1 << default_gid_type))
321045959dbSMatan Barak 		return -EINVAL;
322045959dbSMatan Barak 
323045959dbSMatan Barak 	cma_dev->default_gid_type[port - rdma_start_port(cma_dev->device)] =
324045959dbSMatan Barak 		default_gid_type;
325045959dbSMatan Barak 
326045959dbSMatan Barak 	return 0;
327045959dbSMatan Barak }
328045959dbSMatan Barak 
32989052d78SMajd Dibbiny int cma_get_default_roce_tos(struct cma_device *cma_dev, unsigned int port)
33089052d78SMajd Dibbiny {
33189052d78SMajd Dibbiny 	if (!rdma_is_port_valid(cma_dev->device, port))
33289052d78SMajd Dibbiny 		return -EINVAL;
33389052d78SMajd Dibbiny 
33489052d78SMajd Dibbiny 	return cma_dev->default_roce_tos[port - rdma_start_port(cma_dev->device)];
33589052d78SMajd Dibbiny }
33689052d78SMajd Dibbiny 
33789052d78SMajd Dibbiny int cma_set_default_roce_tos(struct cma_device *cma_dev, unsigned int port,
33889052d78SMajd Dibbiny 			     u8 default_roce_tos)
33989052d78SMajd Dibbiny {
34089052d78SMajd Dibbiny 	if (!rdma_is_port_valid(cma_dev->device, port))
34189052d78SMajd Dibbiny 		return -EINVAL;
34289052d78SMajd Dibbiny 
34389052d78SMajd Dibbiny 	cma_dev->default_roce_tos[port - rdma_start_port(cma_dev->device)] =
34489052d78SMajd Dibbiny 		 default_roce_tos;
34589052d78SMajd Dibbiny 
34689052d78SMajd Dibbiny 	return 0;
34789052d78SMajd Dibbiny }
348045959dbSMatan Barak struct ib_device *cma_get_ib_dev(struct cma_device *cma_dev)
349045959dbSMatan Barak {
350045959dbSMatan Barak 	return cma_dev->device;
351045959dbSMatan Barak }
352045959dbSMatan Barak 
353e51060f0SSean Hefty /*
354e51060f0SSean Hefty  * Device removal can occur at anytime, so we need extra handling to
355e51060f0SSean Hefty  * serialize notifying the user of device removal with other callbacks.
356e51060f0SSean Hefty  * We do this by disabling removal notification while a callback is in process,
357e51060f0SSean Hefty  * and reporting it after the callback completes.
358e51060f0SSean Hefty  */
359e51060f0SSean Hefty 
360c8f6a362SSean Hefty struct cma_multicast {
361c8f6a362SSean Hefty 	struct rdma_id_private *id_priv;
362c8f6a362SSean Hefty 	union {
363c8f6a362SSean Hefty 		struct ib_sa_multicast *ib;
364c8f6a362SSean Hefty 	} multicast;
365c8f6a362SSean Hefty 	struct list_head	list;
366c8f6a362SSean Hefty 	void			*context;
3673f446754SRoland Dreier 	struct sockaddr_storage	addr;
3683c86aa70SEli Cohen 	struct kref		mcref;
369bee3c3c9SMoni Shoua 	bool			igmp_joined;
370ab15c95aSAlex Vesker 	u8			join_state;
371c8f6a362SSean Hefty };
372c8f6a362SSean Hefty 
373e51060f0SSean Hefty struct cma_work {
374e51060f0SSean Hefty 	struct work_struct	work;
375e51060f0SSean Hefty 	struct rdma_id_private	*id;
376550e5ca7SNir Muchtar 	enum rdma_cm_state	old_state;
377550e5ca7SNir Muchtar 	enum rdma_cm_state	new_state;
378e51060f0SSean Hefty 	struct rdma_cm_event	event;
379e51060f0SSean Hefty };
380e51060f0SSean Hefty 
381dd5bdff8SOr Gerlitz struct cma_ndev_work {
382dd5bdff8SOr Gerlitz 	struct work_struct	work;
383dd5bdff8SOr Gerlitz 	struct rdma_id_private	*id;
384dd5bdff8SOr Gerlitz 	struct rdma_cm_event	event;
385dd5bdff8SOr Gerlitz };
386dd5bdff8SOr Gerlitz 
3873c86aa70SEli Cohen struct iboe_mcast_work {
3883c86aa70SEli Cohen 	struct work_struct	 work;
3893c86aa70SEli Cohen 	struct rdma_id_private	*id;
3903c86aa70SEli Cohen 	struct cma_multicast	*mc;
3913c86aa70SEli Cohen };
3923c86aa70SEli Cohen 
393e51060f0SSean Hefty union cma_ip_addr {
394e51060f0SSean Hefty 	struct in6_addr ip6;
395e51060f0SSean Hefty 	struct {
3961b90c137SAl Viro 		__be32 pad[3];
3971b90c137SAl Viro 		__be32 addr;
398e51060f0SSean Hefty 	} ip4;
399e51060f0SSean Hefty };
400e51060f0SSean Hefty 
401e51060f0SSean Hefty struct cma_hdr {
402e51060f0SSean Hefty 	u8 cma_version;
403e51060f0SSean Hefty 	u8 ip_version;	/* IP version: 7:4 */
4041b90c137SAl Viro 	__be16 port;
405e51060f0SSean Hefty 	union cma_ip_addr src_addr;
406e51060f0SSean Hefty 	union cma_ip_addr dst_addr;
407e51060f0SSean Hefty };
408e51060f0SSean Hefty 
409e51060f0SSean Hefty #define CMA_VERSION 0x00
410e51060f0SSean Hefty 
4114c21b5bcSHaggai Eran struct cma_req_info {
4122918c1a9SParav Pandit 	struct sockaddr_storage listen_addr_storage;
4132918c1a9SParav Pandit 	struct sockaddr_storage src_addr_storage;
4144c21b5bcSHaggai Eran 	struct ib_device *device;
4154c21b5bcSHaggai Eran 	int port;
4164c21b5bcSHaggai Eran 	union ib_gid local_gid;
4174c21b5bcSHaggai Eran 	__be64 service_id;
4184c21b5bcSHaggai Eran 	u16 pkey;
4194c21b5bcSHaggai Eran 	bool has_gid:1;
4204c21b5bcSHaggai Eran };
4214c21b5bcSHaggai Eran 
422550e5ca7SNir Muchtar static int cma_comp(struct rdma_id_private *id_priv, enum rdma_cm_state comp)
423e51060f0SSean Hefty {
424e51060f0SSean Hefty 	unsigned long flags;
425e51060f0SSean Hefty 	int ret;
426e51060f0SSean Hefty 
427e51060f0SSean Hefty 	spin_lock_irqsave(&id_priv->lock, flags);
428e51060f0SSean Hefty 	ret = (id_priv->state == comp);
429e51060f0SSean Hefty 	spin_unlock_irqrestore(&id_priv->lock, flags);
430e51060f0SSean Hefty 	return ret;
431e51060f0SSean Hefty }
432e51060f0SSean Hefty 
433e51060f0SSean Hefty static int cma_comp_exch(struct rdma_id_private *id_priv,
434550e5ca7SNir Muchtar 			 enum rdma_cm_state comp, enum rdma_cm_state exch)
435e51060f0SSean Hefty {
436e51060f0SSean Hefty 	unsigned long flags;
437e51060f0SSean Hefty 	int ret;
438e51060f0SSean Hefty 
439e51060f0SSean Hefty 	spin_lock_irqsave(&id_priv->lock, flags);
440e51060f0SSean Hefty 	if ((ret = (id_priv->state == comp)))
441e51060f0SSean Hefty 		id_priv->state = exch;
442e51060f0SSean Hefty 	spin_unlock_irqrestore(&id_priv->lock, flags);
443e51060f0SSean Hefty 	return ret;
444e51060f0SSean Hefty }
445e51060f0SSean Hefty 
446550e5ca7SNir Muchtar static enum rdma_cm_state cma_exch(struct rdma_id_private *id_priv,
447550e5ca7SNir Muchtar 				   enum rdma_cm_state exch)
448e51060f0SSean Hefty {
449e51060f0SSean Hefty 	unsigned long flags;
450550e5ca7SNir Muchtar 	enum rdma_cm_state old;
451e51060f0SSean Hefty 
452e51060f0SSean Hefty 	spin_lock_irqsave(&id_priv->lock, flags);
453e51060f0SSean Hefty 	old = id_priv->state;
454e51060f0SSean Hefty 	id_priv->state = exch;
455e51060f0SSean Hefty 	spin_unlock_irqrestore(&id_priv->lock, flags);
456e51060f0SSean Hefty 	return old;
457e51060f0SSean Hefty }
458e51060f0SSean Hefty 
4594c21b5bcSHaggai Eran static inline u8 cma_get_ip_ver(const struct cma_hdr *hdr)
460e51060f0SSean Hefty {
461e51060f0SSean Hefty 	return hdr->ip_version >> 4;
462e51060f0SSean Hefty }
463e51060f0SSean Hefty 
464e51060f0SSean Hefty static inline void cma_set_ip_ver(struct cma_hdr *hdr, u8 ip_ver)
465e51060f0SSean Hefty {
466e51060f0SSean Hefty 	hdr->ip_version = (ip_ver << 4) | (hdr->ip_version & 0xF);
467e51060f0SSean Hefty }
468e51060f0SSean Hefty 
469bee3c3c9SMoni Shoua static int cma_igmp_send(struct net_device *ndev, union ib_gid *mgid, bool join)
470bee3c3c9SMoni Shoua {
471bee3c3c9SMoni Shoua 	struct in_device *in_dev = NULL;
472bee3c3c9SMoni Shoua 
473bee3c3c9SMoni Shoua 	if (ndev) {
474bee3c3c9SMoni Shoua 		rtnl_lock();
475bee3c3c9SMoni Shoua 		in_dev = __in_dev_get_rtnl(ndev);
476bee3c3c9SMoni Shoua 		if (in_dev) {
477bee3c3c9SMoni Shoua 			if (join)
478bee3c3c9SMoni Shoua 				ip_mc_inc_group(in_dev,
479bee3c3c9SMoni Shoua 						*(__be32 *)(mgid->raw + 12));
480bee3c3c9SMoni Shoua 			else
481bee3c3c9SMoni Shoua 				ip_mc_dec_group(in_dev,
482bee3c3c9SMoni Shoua 						*(__be32 *)(mgid->raw + 12));
483bee3c3c9SMoni Shoua 		}
484bee3c3c9SMoni Shoua 		rtnl_unlock();
485bee3c3c9SMoni Shoua 	}
486bee3c3c9SMoni Shoua 	return (in_dev) ? 0 : -ENODEV;
487bee3c3c9SMoni Shoua }
488bee3c3c9SMoni Shoua 
489045959dbSMatan Barak static void _cma_attach_to_dev(struct rdma_id_private *id_priv,
490e51060f0SSean Hefty 			       struct cma_device *cma_dev)
491e51060f0SSean Hefty {
492218a773fSMatan Barak 	cma_ref_dev(cma_dev);
493e51060f0SSean Hefty 	id_priv->cma_dev = cma_dev;
494045959dbSMatan Barak 	id_priv->gid_type = 0;
495e51060f0SSean Hefty 	id_priv->id.device = cma_dev->device;
4963c86aa70SEli Cohen 	id_priv->id.route.addr.dev_addr.transport =
4973c86aa70SEli Cohen 		rdma_node_get_transport(cma_dev->device->node_type);
498e51060f0SSean Hefty 	list_add_tail(&id_priv->list, &cma_dev->id_list);
49900313983SSteve Wise 	id_priv->res.type = RDMA_RESTRACK_CM_ID;
50000313983SSteve Wise 	rdma_restrack_add(&id_priv->res);
501e51060f0SSean Hefty }
502e51060f0SSean Hefty 
503045959dbSMatan Barak static void cma_attach_to_dev(struct rdma_id_private *id_priv,
504045959dbSMatan Barak 			      struct cma_device *cma_dev)
505045959dbSMatan Barak {
506045959dbSMatan Barak 	_cma_attach_to_dev(id_priv, cma_dev);
507045959dbSMatan Barak 	id_priv->gid_type =
508045959dbSMatan Barak 		cma_dev->default_gid_type[id_priv->id.port_num -
509045959dbSMatan Barak 					  rdma_start_port(cma_dev->device)];
510045959dbSMatan Barak }
511045959dbSMatan Barak 
512218a773fSMatan Barak void cma_deref_dev(struct cma_device *cma_dev)
513e51060f0SSean Hefty {
514e51060f0SSean Hefty 	if (atomic_dec_and_test(&cma_dev->refcount))
515e51060f0SSean Hefty 		complete(&cma_dev->comp);
516e51060f0SSean Hefty }
517e51060f0SSean Hefty 
5183c86aa70SEli Cohen static inline void release_mc(struct kref *kref)
5193c86aa70SEli Cohen {
5203c86aa70SEli Cohen 	struct cma_multicast *mc = container_of(kref, struct cma_multicast, mcref);
5213c86aa70SEli Cohen 
5223c86aa70SEli Cohen 	kfree(mc->multicast.ib);
5233c86aa70SEli Cohen 	kfree(mc);
5243c86aa70SEli Cohen }
5253c86aa70SEli Cohen 
526a396d43aSSean Hefty static void cma_release_dev(struct rdma_id_private *id_priv)
527e51060f0SSean Hefty {
528a396d43aSSean Hefty 	mutex_lock(&lock);
529e51060f0SSean Hefty 	list_del(&id_priv->list);
530e51060f0SSean Hefty 	cma_deref_dev(id_priv->cma_dev);
531e51060f0SSean Hefty 	id_priv->cma_dev = NULL;
532a396d43aSSean Hefty 	mutex_unlock(&lock);
533e51060f0SSean Hefty }
534e51060f0SSean Hefty 
535f4753834SSean Hefty static inline struct sockaddr *cma_src_addr(struct rdma_id_private *id_priv)
536f4753834SSean Hefty {
537f4753834SSean Hefty 	return (struct sockaddr *) &id_priv->id.route.addr.src_addr;
538f4753834SSean Hefty }
539f4753834SSean Hefty 
540f4753834SSean Hefty static inline struct sockaddr *cma_dst_addr(struct rdma_id_private *id_priv)
541f4753834SSean Hefty {
542f4753834SSean Hefty 	return (struct sockaddr *) &id_priv->id.route.addr.dst_addr;
543f4753834SSean Hefty }
544f4753834SSean Hefty 
545f4753834SSean Hefty static inline unsigned short cma_family(struct rdma_id_private *id_priv)
546f4753834SSean Hefty {
547f4753834SSean Hefty 	return id_priv->id.route.addr.src_addr.ss_family;
548f4753834SSean Hefty }
549f4753834SSean Hefty 
5505c438135SSean Hefty static int cma_set_qkey(struct rdma_id_private *id_priv, u32 qkey)
551c8f6a362SSean Hefty {
552c8f6a362SSean Hefty 	struct ib_sa_mcmember_rec rec;
553c8f6a362SSean Hefty 	int ret = 0;
554c8f6a362SSean Hefty 
5555c438135SSean Hefty 	if (id_priv->qkey) {
5565c438135SSean Hefty 		if (qkey && id_priv->qkey != qkey)
5575c438135SSean Hefty 			return -EINVAL;
558d2ca39f2SYossi Etigin 		return 0;
5595c438135SSean Hefty 	}
5605c438135SSean Hefty 
5615c438135SSean Hefty 	if (qkey) {
5625c438135SSean Hefty 		id_priv->qkey = qkey;
5635c438135SSean Hefty 		return 0;
5645c438135SSean Hefty 	}
565d2ca39f2SYossi Etigin 
566d2ca39f2SYossi Etigin 	switch (id_priv->id.ps) {
567c8f6a362SSean Hefty 	case RDMA_PS_UDP:
5685c438135SSean Hefty 	case RDMA_PS_IB:
569d2ca39f2SYossi Etigin 		id_priv->qkey = RDMA_UDP_QKEY;
570c8f6a362SSean Hefty 		break;
571c8f6a362SSean Hefty 	case RDMA_PS_IPOIB:
572d2ca39f2SYossi Etigin 		ib_addr_get_mgid(&id_priv->id.route.addr.dev_addr, &rec.mgid);
573d2ca39f2SYossi Etigin 		ret = ib_sa_get_mcmember_rec(id_priv->id.device,
574d2ca39f2SYossi Etigin 					     id_priv->id.port_num, &rec.mgid,
575d2ca39f2SYossi Etigin 					     &rec);
576d2ca39f2SYossi Etigin 		if (!ret)
577d2ca39f2SYossi Etigin 			id_priv->qkey = be32_to_cpu(rec.qkey);
578c8f6a362SSean Hefty 		break;
579c8f6a362SSean Hefty 	default:
580c8f6a362SSean Hefty 		break;
581c8f6a362SSean Hefty 	}
582c8f6a362SSean Hefty 	return ret;
583c8f6a362SSean Hefty }
584c8f6a362SSean Hefty 
585680f920aSSean Hefty static void cma_translate_ib(struct sockaddr_ib *sib, struct rdma_dev_addr *dev_addr)
586680f920aSSean Hefty {
587680f920aSSean Hefty 	dev_addr->dev_type = ARPHRD_INFINIBAND;
588680f920aSSean Hefty 	rdma_addr_set_sgid(dev_addr, (union ib_gid *) &sib->sib_addr);
589680f920aSSean Hefty 	ib_addr_set_pkey(dev_addr, ntohs(sib->sib_pkey));
590680f920aSSean Hefty }
591680f920aSSean Hefty 
592680f920aSSean Hefty static int cma_translate_addr(struct sockaddr *addr, struct rdma_dev_addr *dev_addr)
593680f920aSSean Hefty {
594680f920aSSean Hefty 	int ret;
595680f920aSSean Hefty 
596680f920aSSean Hefty 	if (addr->sa_family != AF_IB) {
597575c7e58SParav Pandit 		ret = rdma_translate_ip(addr, dev_addr);
598680f920aSSean Hefty 	} else {
599680f920aSSean Hefty 		cma_translate_ib((struct sockaddr_ib *) addr, dev_addr);
600680f920aSSean Hefty 		ret = 0;
601680f920aSSean Hefty 	}
602680f920aSSean Hefty 
603680f920aSSean Hefty 	return ret;
604680f920aSSean Hefty }
605680f920aSSean Hefty 
6067c11147dSMichael Wang static inline int cma_validate_port(struct ib_device *device, u8 port,
607045959dbSMatan Barak 				    enum ib_gid_type gid_type,
6082493a57bSParav Pandit 				    union ib_gid *gid,
6092493a57bSParav Pandit 				    struct rdma_id_private *id_priv)
6107c11147dSMichael Wang {
6112493a57bSParav Pandit 	struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
6122493a57bSParav Pandit 	int bound_if_index = dev_addr->bound_dev_if;
6132493a57bSParav Pandit 	int dev_type = dev_addr->dev_type;
614abae1b71SMatan Barak 	struct net_device *ndev = NULL;
6152493a57bSParav Pandit 	int ret = -ENODEV;
6167c11147dSMichael Wang 
6177c11147dSMichael Wang 	if ((dev_type == ARPHRD_INFINIBAND) && !rdma_protocol_ib(device, port))
6187c11147dSMichael Wang 		return ret;
6197c11147dSMichael Wang 
6207c11147dSMichael Wang 	if ((dev_type != ARPHRD_INFINIBAND) && rdma_protocol_ib(device, port))
6217c11147dSMichael Wang 		return ret;
6227c11147dSMichael Wang 
62300db63c1SParav Pandit 	if (dev_type == ARPHRD_ETHER && rdma_protocol_roce(device, port)) {
62466c74d74SParav Pandit 		ndev = dev_get_by_index(dev_addr->net, bound_if_index);
62500db63c1SParav Pandit 		if (!ndev)
62600db63c1SParav Pandit 			return ret;
62700db63c1SParav Pandit 	} else {
628045959dbSMatan Barak 		gid_type = IB_GID_TYPE_IB;
62900db63c1SParav Pandit 	}
630abae1b71SMatan Barak 
631045959dbSMatan Barak 	ret = ib_find_cached_gid_by_port(device, gid, gid_type, port,
632b39ffa1dSMatan Barak 					 ndev, NULL);
633abae1b71SMatan Barak 
634abae1b71SMatan Barak 	if (ndev)
635abae1b71SMatan Barak 		dev_put(ndev);
6367c11147dSMichael Wang 
6377c11147dSMichael Wang 	return ret;
6387c11147dSMichael Wang }
6397c11147dSMichael Wang 
640be9130ccSDoug Ledford static int cma_acquire_dev(struct rdma_id_private *id_priv,
641be9130ccSDoug Ledford 			   struct rdma_id_private *listen_id_priv)
642e51060f0SSean Hefty {
643c8f6a362SSean Hefty 	struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
644e51060f0SSean Hefty 	struct cma_device *cma_dev;
6457c11147dSMichael Wang 	union ib_gid gid, iboe_gid, *gidp;
646e51060f0SSean Hefty 	int ret = -ENODEV;
6477c11147dSMichael Wang 	u8 port;
648e51060f0SSean Hefty 
6497c11147dSMichael Wang 	if (dev_addr->dev_type != ARPHRD_INFINIBAND &&
6502efdd6a0SMoni Shoua 	    id_priv->id.ps == RDMA_PS_IPOIB)
6512efdd6a0SMoni Shoua 		return -EINVAL;
6522efdd6a0SMoni Shoua 
653a396d43aSSean Hefty 	mutex_lock(&lock);
6547b85627bSMoni Shoua 	rdma_ip2gid((struct sockaddr *)&id_priv->id.route.addr.src_addr,
6557b85627bSMoni Shoua 		    &iboe_gid);
6567b85627bSMoni Shoua 
6573c86aa70SEli Cohen 	memcpy(&gid, dev_addr->src_dev_addr +
6583c86aa70SEli Cohen 	       rdma_addr_gid_offset(dev_addr), sizeof gid);
6597c11147dSMichael Wang 
6607c11147dSMichael Wang 	if (listen_id_priv) {
661be9130ccSDoug Ledford 		cma_dev = listen_id_priv->cma_dev;
662be9130ccSDoug Ledford 		port = listen_id_priv->id.port_num;
6635d9fb044SIra Weiny 		gidp = rdma_protocol_roce(cma_dev->device, port) ?
6647c11147dSMichael Wang 		       &iboe_gid : &gid;
665be9130ccSDoug Ledford 
666045959dbSMatan Barak 		ret = cma_validate_port(cma_dev->device, port,
667045959dbSMatan Barak 					rdma_protocol_ib(cma_dev->device, port) ?
668045959dbSMatan Barak 					IB_GID_TYPE_IB :
669045959dbSMatan Barak 					listen_id_priv->gid_type, gidp,
6702493a57bSParav Pandit 					id_priv);
6717c11147dSMichael Wang 		if (!ret) {
6727c11147dSMichael Wang 			id_priv->id.port_num = port;
673be9130ccSDoug Ledford 			goto out;
674be9130ccSDoug Ledford 		}
675be9130ccSDoug Ledford 	}
6767c11147dSMichael Wang 
677e51060f0SSean Hefty 	list_for_each_entry(cma_dev, &dev_list, list) {
6783c86aa70SEli Cohen 		for (port = 1; port <= cma_dev->device->phys_port_cnt; ++port) {
679be9130ccSDoug Ledford 			if (listen_id_priv &&
680be9130ccSDoug Ledford 			    listen_id_priv->cma_dev == cma_dev &&
681be9130ccSDoug Ledford 			    listen_id_priv->id.port_num == port)
682be9130ccSDoug Ledford 				continue;
6833c86aa70SEli Cohen 
6845d9fb044SIra Weiny 			gidp = rdma_protocol_roce(cma_dev->device, port) ?
6857c11147dSMichael Wang 			       &iboe_gid : &gid;
6867c11147dSMichael Wang 
687045959dbSMatan Barak 			ret = cma_validate_port(cma_dev->device, port,
688045959dbSMatan Barak 						rdma_protocol_ib(cma_dev->device, port) ?
689045959dbSMatan Barak 						IB_GID_TYPE_IB :
690045959dbSMatan Barak 						cma_dev->default_gid_type[port - 1],
6912493a57bSParav Pandit 						gidp, id_priv);
6927c11147dSMichael Wang 			if (!ret) {
6937c11147dSMichael Wang 				id_priv->id.port_num = port;
6943c86aa70SEli Cohen 				goto out;
69563f05be2Sshefty 			}
696e51060f0SSean Hefty 		}
697e51060f0SSean Hefty 	}
6983c86aa70SEli Cohen 
6993c86aa70SEli Cohen out:
7003c86aa70SEli Cohen 	if (!ret)
7013c86aa70SEli Cohen 		cma_attach_to_dev(id_priv, cma_dev);
7023c86aa70SEli Cohen 
703a396d43aSSean Hefty 	mutex_unlock(&lock);
704e51060f0SSean Hefty 	return ret;
705e51060f0SSean Hefty }
706e51060f0SSean Hefty 
707f17df3b0SSean Hefty /*
708f17df3b0SSean Hefty  * Select the source IB device and address to reach the destination IB address.
709f17df3b0SSean Hefty  */
710f17df3b0SSean Hefty static int cma_resolve_ib_dev(struct rdma_id_private *id_priv)
711f17df3b0SSean Hefty {
712f17df3b0SSean Hefty 	struct cma_device *cma_dev, *cur_dev;
713f17df3b0SSean Hefty 	struct sockaddr_ib *addr;
714f17df3b0SSean Hefty 	union ib_gid gid, sgid, *dgid;
715f17df3b0SSean Hefty 	u16 pkey, index;
7168fb488d7SPaul Bolle 	u8 p;
71793b1f29dSJack Wang 	enum ib_port_state port_state;
718f17df3b0SSean Hefty 	int i;
719f17df3b0SSean Hefty 
720f17df3b0SSean Hefty 	cma_dev = NULL;
721f17df3b0SSean Hefty 	addr = (struct sockaddr_ib *) cma_dst_addr(id_priv);
722f17df3b0SSean Hefty 	dgid = (union ib_gid *) &addr->sib_addr;
723f17df3b0SSean Hefty 	pkey = ntohs(addr->sib_pkey);
724f17df3b0SSean Hefty 
725f17df3b0SSean Hefty 	list_for_each_entry(cur_dev, &dev_list, list) {
726fef60902SMichael Wang 		for (p = 1; p <= cur_dev->device->phys_port_cnt; ++p) {
72730a74ef4SMichael Wang 			if (!rdma_cap_af_ib(cur_dev->device, p))
728f17df3b0SSean Hefty 				continue;
729f17df3b0SSean Hefty 
730f17df3b0SSean Hefty 			if (ib_find_cached_pkey(cur_dev->device, p, pkey, &index))
731f17df3b0SSean Hefty 				continue;
732f17df3b0SSean Hefty 
73393b1f29dSJack Wang 			if (ib_get_cached_port_state(cur_dev->device, p, &port_state))
73493b1f29dSJack Wang 				continue;
73555ee3ab2SMatan Barak 			for (i = 0; !ib_get_cached_gid(cur_dev->device, p, i,
73655ee3ab2SMatan Barak 						       &gid, NULL);
73755ee3ab2SMatan Barak 			     i++) {
738f17df3b0SSean Hefty 				if (!memcmp(&gid, dgid, sizeof(gid))) {
739f17df3b0SSean Hefty 					cma_dev = cur_dev;
740f17df3b0SSean Hefty 					sgid = gid;
7418fb488d7SPaul Bolle 					id_priv->id.port_num = p;
742f17df3b0SSean Hefty 					goto found;
743f17df3b0SSean Hefty 				}
744f17df3b0SSean Hefty 
745f17df3b0SSean Hefty 				if (!cma_dev && (gid.global.subnet_prefix ==
74693b1f29dSJack Wang 				    dgid->global.subnet_prefix) &&
74793b1f29dSJack Wang 				    port_state == IB_PORT_ACTIVE) {
748f17df3b0SSean Hefty 					cma_dev = cur_dev;
749f17df3b0SSean Hefty 					sgid = gid;
7508fb488d7SPaul Bolle 					id_priv->id.port_num = p;
751f17df3b0SSean Hefty 				}
752f17df3b0SSean Hefty 			}
753f17df3b0SSean Hefty 		}
754f17df3b0SSean Hefty 	}
755f17df3b0SSean Hefty 
756f17df3b0SSean Hefty 	if (!cma_dev)
757f17df3b0SSean Hefty 		return -ENODEV;
758f17df3b0SSean Hefty 
759f17df3b0SSean Hefty found:
760f17df3b0SSean Hefty 	cma_attach_to_dev(id_priv, cma_dev);
761f17df3b0SSean Hefty 	addr = (struct sockaddr_ib *) cma_src_addr(id_priv);
762f17df3b0SSean Hefty 	memcpy(&addr->sib_addr, &sgid, sizeof sgid);
763f17df3b0SSean Hefty 	cma_translate_ib(addr, &id_priv->id.route.addr.dev_addr);
764f17df3b0SSean Hefty 	return 0;
765f17df3b0SSean Hefty }
766f17df3b0SSean Hefty 
767e51060f0SSean Hefty static void cma_deref_id(struct rdma_id_private *id_priv)
768e51060f0SSean Hefty {
769e51060f0SSean Hefty 	if (atomic_dec_and_test(&id_priv->refcount))
770e51060f0SSean Hefty 		complete(&id_priv->comp);
771e51060f0SSean Hefty }
772e51060f0SSean Hefty 
77300313983SSteve Wise struct rdma_cm_id *__rdma_create_id(struct net *net,
774fa20105eSGuy Shapiro 				    rdma_cm_event_handler event_handler,
7752253fc0cSSteve Wise 				    void *context, enum rdma_ucm_port_space ps,
77600313983SSteve Wise 				    enum ib_qp_type qp_type, const char *caller)
777e51060f0SSean Hefty {
778e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
779e51060f0SSean Hefty 
780e51060f0SSean Hefty 	id_priv = kzalloc(sizeof *id_priv, GFP_KERNEL);
781e51060f0SSean Hefty 	if (!id_priv)
782e51060f0SSean Hefty 		return ERR_PTR(-ENOMEM);
783e51060f0SSean Hefty 
78400313983SSteve Wise 	if (caller)
78500313983SSteve Wise 		id_priv->res.kern_name = caller;
78600313983SSteve Wise 	else
78700313983SSteve Wise 		rdma_restrack_set_task(&id_priv->res, current);
788550e5ca7SNir Muchtar 	id_priv->state = RDMA_CM_IDLE;
789e51060f0SSean Hefty 	id_priv->id.context = context;
790e51060f0SSean Hefty 	id_priv->id.event_handler = event_handler;
791e51060f0SSean Hefty 	id_priv->id.ps = ps;
792b26f9b99SSean Hefty 	id_priv->id.qp_type = qp_type;
79389052d78SMajd Dibbiny 	id_priv->tos_set = false;
794e51060f0SSean Hefty 	spin_lock_init(&id_priv->lock);
795c5483388SSean Hefty 	mutex_init(&id_priv->qp_mutex);
796e51060f0SSean Hefty 	init_completion(&id_priv->comp);
797e51060f0SSean Hefty 	atomic_set(&id_priv->refcount, 1);
798de910bd9SOr Gerlitz 	mutex_init(&id_priv->handler_mutex);
799e51060f0SSean Hefty 	INIT_LIST_HEAD(&id_priv->listen_list);
800c8f6a362SSean Hefty 	INIT_LIST_HEAD(&id_priv->mc_list);
801e51060f0SSean Hefty 	get_random_bytes(&id_priv->seq_num, sizeof id_priv->seq_num);
802fa20105eSGuy Shapiro 	id_priv->id.route.addr.dev_addr.net = get_net(net);
80323a9cd2aSMoni Shoua 	id_priv->seq_num &= 0x00ffffff;
804e51060f0SSean Hefty 
805e51060f0SSean Hefty 	return &id_priv->id;
806e51060f0SSean Hefty }
80700313983SSteve Wise EXPORT_SYMBOL(__rdma_create_id);
808e51060f0SSean Hefty 
809c8f6a362SSean Hefty static int cma_init_ud_qp(struct rdma_id_private *id_priv, struct ib_qp *qp)
810e51060f0SSean Hefty {
811e51060f0SSean Hefty 	struct ib_qp_attr qp_attr;
812c8f6a362SSean Hefty 	int qp_attr_mask, ret;
813e51060f0SSean Hefty 
814c8f6a362SSean Hefty 	qp_attr.qp_state = IB_QPS_INIT;
815c8f6a362SSean Hefty 	ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask);
816e51060f0SSean Hefty 	if (ret)
817e51060f0SSean Hefty 		return ret;
818e51060f0SSean Hefty 
819c8f6a362SSean Hefty 	ret = ib_modify_qp(qp, &qp_attr, qp_attr_mask);
820c8f6a362SSean Hefty 	if (ret)
821c8f6a362SSean Hefty 		return ret;
822c8f6a362SSean Hefty 
823c8f6a362SSean Hefty 	qp_attr.qp_state = IB_QPS_RTR;
824c8f6a362SSean Hefty 	ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE);
825c8f6a362SSean Hefty 	if (ret)
826c8f6a362SSean Hefty 		return ret;
827c8f6a362SSean Hefty 
828c8f6a362SSean Hefty 	qp_attr.qp_state = IB_QPS_RTS;
829c8f6a362SSean Hefty 	qp_attr.sq_psn = 0;
830c8f6a362SSean Hefty 	ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE | IB_QP_SQ_PSN);
831c8f6a362SSean Hefty 
832c8f6a362SSean Hefty 	return ret;
833e51060f0SSean Hefty }
834e51060f0SSean Hefty 
835c8f6a362SSean Hefty static int cma_init_conn_qp(struct rdma_id_private *id_priv, struct ib_qp *qp)
83607ebafbaSTom Tucker {
83707ebafbaSTom Tucker 	struct ib_qp_attr qp_attr;
838c8f6a362SSean Hefty 	int qp_attr_mask, ret;
83907ebafbaSTom Tucker 
84007ebafbaSTom Tucker 	qp_attr.qp_state = IB_QPS_INIT;
841c8f6a362SSean Hefty 	ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask);
842c8f6a362SSean Hefty 	if (ret)
843c8f6a362SSean Hefty 		return ret;
84407ebafbaSTom Tucker 
845c8f6a362SSean Hefty 	return ib_modify_qp(qp, &qp_attr, qp_attr_mask);
84607ebafbaSTom Tucker }
84707ebafbaSTom Tucker 
848e51060f0SSean Hefty int rdma_create_qp(struct rdma_cm_id *id, struct ib_pd *pd,
849e51060f0SSean Hefty 		   struct ib_qp_init_attr *qp_init_attr)
850e51060f0SSean Hefty {
851e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
852e51060f0SSean Hefty 	struct ib_qp *qp;
853e51060f0SSean Hefty 	int ret;
854e51060f0SSean Hefty 
855e51060f0SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
856e51060f0SSean Hefty 	if (id->device != pd->device)
857e51060f0SSean Hefty 		return -EINVAL;
858e51060f0SSean Hefty 
8590691a286SChristoph Hellwig 	qp_init_attr->port_num = id->port_num;
860e51060f0SSean Hefty 	qp = ib_create_qp(pd, qp_init_attr);
861e51060f0SSean Hefty 	if (IS_ERR(qp))
862e51060f0SSean Hefty 		return PTR_ERR(qp);
863e51060f0SSean Hefty 
864b26f9b99SSean Hefty 	if (id->qp_type == IB_QPT_UD)
865c8f6a362SSean Hefty 		ret = cma_init_ud_qp(id_priv, qp);
866c8f6a362SSean Hefty 	else
867c8f6a362SSean Hefty 		ret = cma_init_conn_qp(id_priv, qp);
868e51060f0SSean Hefty 	if (ret)
869e51060f0SSean Hefty 		goto err;
870e51060f0SSean Hefty 
871e51060f0SSean Hefty 	id->qp = qp;
872e51060f0SSean Hefty 	id_priv->qp_num = qp->qp_num;
873e51060f0SSean Hefty 	id_priv->srq = (qp->srq != NULL);
874e51060f0SSean Hefty 	return 0;
875e51060f0SSean Hefty err:
876e51060f0SSean Hefty 	ib_destroy_qp(qp);
877e51060f0SSean Hefty 	return ret;
878e51060f0SSean Hefty }
879e51060f0SSean Hefty EXPORT_SYMBOL(rdma_create_qp);
880e51060f0SSean Hefty 
881e51060f0SSean Hefty void rdma_destroy_qp(struct rdma_cm_id *id)
882e51060f0SSean Hefty {
883c5483388SSean Hefty 	struct rdma_id_private *id_priv;
884c5483388SSean Hefty 
885c5483388SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
886c5483388SSean Hefty 	mutex_lock(&id_priv->qp_mutex);
887c5483388SSean Hefty 	ib_destroy_qp(id_priv->id.qp);
888c5483388SSean Hefty 	id_priv->id.qp = NULL;
889c5483388SSean Hefty 	mutex_unlock(&id_priv->qp_mutex);
890e51060f0SSean Hefty }
891e51060f0SSean Hefty EXPORT_SYMBOL(rdma_destroy_qp);
892e51060f0SSean Hefty 
8935851bb89SSean Hefty static int cma_modify_qp_rtr(struct rdma_id_private *id_priv,
8945851bb89SSean Hefty 			     struct rdma_conn_param *conn_param)
895e51060f0SSean Hefty {
896e51060f0SSean Hefty 	struct ib_qp_attr qp_attr;
897e51060f0SSean Hefty 	int qp_attr_mask, ret;
898e51060f0SSean Hefty 
899c5483388SSean Hefty 	mutex_lock(&id_priv->qp_mutex);
900c5483388SSean Hefty 	if (!id_priv->id.qp) {
901c5483388SSean Hefty 		ret = 0;
902c5483388SSean Hefty 		goto out;
903c5483388SSean Hefty 	}
904e51060f0SSean Hefty 
905e51060f0SSean Hefty 	/* Need to update QP attributes from default values. */
906e51060f0SSean Hefty 	qp_attr.qp_state = IB_QPS_INIT;
907c5483388SSean Hefty 	ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask);
908e51060f0SSean Hefty 	if (ret)
909c5483388SSean Hefty 		goto out;
910e51060f0SSean Hefty 
911c5483388SSean Hefty 	ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask);
912e51060f0SSean Hefty 	if (ret)
913c5483388SSean Hefty 		goto out;
914e51060f0SSean Hefty 
915e51060f0SSean Hefty 	qp_attr.qp_state = IB_QPS_RTR;
916c5483388SSean Hefty 	ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask);
917e51060f0SSean Hefty 	if (ret)
918c5483388SSean Hefty 		goto out;
919e51060f0SSean Hefty 
920fef60902SMichael Wang 	BUG_ON(id_priv->cma_dev->device != id_priv->id.device);
921fef60902SMichael Wang 
9225851bb89SSean Hefty 	if (conn_param)
9235851bb89SSean Hefty 		qp_attr.max_dest_rd_atomic = conn_param->responder_resources;
924c5483388SSean Hefty 	ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask);
925c5483388SSean Hefty out:
926c5483388SSean Hefty 	mutex_unlock(&id_priv->qp_mutex);
927c5483388SSean Hefty 	return ret;
928e51060f0SSean Hefty }
929e51060f0SSean Hefty 
9305851bb89SSean Hefty static int cma_modify_qp_rts(struct rdma_id_private *id_priv,
9315851bb89SSean Hefty 			     struct rdma_conn_param *conn_param)
932e51060f0SSean Hefty {
933e51060f0SSean Hefty 	struct ib_qp_attr qp_attr;
934e51060f0SSean Hefty 	int qp_attr_mask, ret;
935e51060f0SSean Hefty 
936c5483388SSean Hefty 	mutex_lock(&id_priv->qp_mutex);
937c5483388SSean Hefty 	if (!id_priv->id.qp) {
938c5483388SSean Hefty 		ret = 0;
939c5483388SSean Hefty 		goto out;
940e51060f0SSean Hefty 	}
941e51060f0SSean Hefty 
942c5483388SSean Hefty 	qp_attr.qp_state = IB_QPS_RTS;
943c5483388SSean Hefty 	ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask);
944c5483388SSean Hefty 	if (ret)
945c5483388SSean Hefty 		goto out;
946c5483388SSean Hefty 
9475851bb89SSean Hefty 	if (conn_param)
9485851bb89SSean Hefty 		qp_attr.max_rd_atomic = conn_param->initiator_depth;
949c5483388SSean Hefty 	ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask);
950c5483388SSean Hefty out:
951c5483388SSean Hefty 	mutex_unlock(&id_priv->qp_mutex);
952c5483388SSean Hefty 	return ret;
953c5483388SSean Hefty }
954c5483388SSean Hefty 
955c5483388SSean Hefty static int cma_modify_qp_err(struct rdma_id_private *id_priv)
956e51060f0SSean Hefty {
957e51060f0SSean Hefty 	struct ib_qp_attr qp_attr;
958c5483388SSean Hefty 	int ret;
959e51060f0SSean Hefty 
960c5483388SSean Hefty 	mutex_lock(&id_priv->qp_mutex);
961c5483388SSean Hefty 	if (!id_priv->id.qp) {
962c5483388SSean Hefty 		ret = 0;
963c5483388SSean Hefty 		goto out;
964c5483388SSean Hefty 	}
965e51060f0SSean Hefty 
966e51060f0SSean Hefty 	qp_attr.qp_state = IB_QPS_ERR;
967c5483388SSean Hefty 	ret = ib_modify_qp(id_priv->id.qp, &qp_attr, IB_QP_STATE);
968c5483388SSean Hefty out:
969c5483388SSean Hefty 	mutex_unlock(&id_priv->qp_mutex);
970c5483388SSean Hefty 	return ret;
971e51060f0SSean Hefty }
972e51060f0SSean Hefty 
973c8f6a362SSean Hefty static int cma_ib_init_qp_attr(struct rdma_id_private *id_priv,
974c8f6a362SSean Hefty 			       struct ib_qp_attr *qp_attr, int *qp_attr_mask)
975c8f6a362SSean Hefty {
976c8f6a362SSean Hefty 	struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
977c8f6a362SSean Hefty 	int ret;
9783c86aa70SEli Cohen 	u16 pkey;
9793c86aa70SEli Cohen 
980227128fcSMichael Wang 	if (rdma_cap_eth_ah(id_priv->id.device, id_priv->id.port_num))
9813c86aa70SEli Cohen 		pkey = 0xffff;
982fef60902SMichael Wang 	else
983fef60902SMichael Wang 		pkey = ib_addr_get_pkey(dev_addr);
984c8f6a362SSean Hefty 
985c8f6a362SSean Hefty 	ret = ib_find_cached_pkey(id_priv->id.device, id_priv->id.port_num,
9863c86aa70SEli Cohen 				  pkey, &qp_attr->pkey_index);
987c8f6a362SSean Hefty 	if (ret)
988c8f6a362SSean Hefty 		return ret;
989c8f6a362SSean Hefty 
990c8f6a362SSean Hefty 	qp_attr->port_num = id_priv->id.port_num;
991c8f6a362SSean Hefty 	*qp_attr_mask = IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_PORT;
992c8f6a362SSean Hefty 
993b26f9b99SSean Hefty 	if (id_priv->id.qp_type == IB_QPT_UD) {
9945c438135SSean Hefty 		ret = cma_set_qkey(id_priv, 0);
995d2ca39f2SYossi Etigin 		if (ret)
996d2ca39f2SYossi Etigin 			return ret;
997d2ca39f2SYossi Etigin 
998c8f6a362SSean Hefty 		qp_attr->qkey = id_priv->qkey;
999c8f6a362SSean Hefty 		*qp_attr_mask |= IB_QP_QKEY;
1000c8f6a362SSean Hefty 	} else {
1001c8f6a362SSean Hefty 		qp_attr->qp_access_flags = 0;
1002c8f6a362SSean Hefty 		*qp_attr_mask |= IB_QP_ACCESS_FLAGS;
1003c8f6a362SSean Hefty 	}
1004c8f6a362SSean Hefty 	return 0;
1005c8f6a362SSean Hefty }
1006c8f6a362SSean Hefty 
1007e51060f0SSean Hefty int rdma_init_qp_attr(struct rdma_cm_id *id, struct ib_qp_attr *qp_attr,
1008e51060f0SSean Hefty 		       int *qp_attr_mask)
1009e51060f0SSean Hefty {
1010e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
1011c8f6a362SSean Hefty 	int ret = 0;
1012e51060f0SSean Hefty 
1013e51060f0SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
101472219ceaSMichael Wang 	if (rdma_cap_ib_cm(id->device, id->port_num)) {
1015b26f9b99SSean Hefty 		if (!id_priv->cm_id.ib || (id_priv->id.qp_type == IB_QPT_UD))
1016c8f6a362SSean Hefty 			ret = cma_ib_init_qp_attr(id_priv, qp_attr, qp_attr_mask);
1017c8f6a362SSean Hefty 		else
1018e51060f0SSean Hefty 			ret = ib_cm_init_qp_attr(id_priv->cm_id.ib, qp_attr,
1019e51060f0SSean Hefty 						 qp_attr_mask);
1020dd5f03beSMatan Barak 
1021e51060f0SSean Hefty 		if (qp_attr->qp_state == IB_QPS_RTR)
1022e51060f0SSean Hefty 			qp_attr->rq_psn = id_priv->seq_num;
102304215330SMichael Wang 	} else if (rdma_cap_iw_cm(id->device, id->port_num)) {
1024c8f6a362SSean Hefty 		if (!id_priv->cm_id.iw) {
10258f076531SDotan Barak 			qp_attr->qp_access_flags = 0;
1026c8f6a362SSean Hefty 			*qp_attr_mask = IB_QP_STATE | IB_QP_ACCESS_FLAGS;
1027c8f6a362SSean Hefty 		} else
102807ebafbaSTom Tucker 			ret = iw_cm_init_qp_attr(id_priv->cm_id.iw, qp_attr,
102907ebafbaSTom Tucker 						 qp_attr_mask);
1030a62ab66bSIsmail, Mustafa 		qp_attr->port_num = id_priv->id.port_num;
1031a62ab66bSIsmail, Mustafa 		*qp_attr_mask |= IB_QP_PORT;
103221655afcSMichael Wang 	} else
1033e51060f0SSean Hefty 		ret = -ENOSYS;
1034e51060f0SSean Hefty 
1035e51060f0SSean Hefty 	return ret;
1036e51060f0SSean Hefty }
1037e51060f0SSean Hefty EXPORT_SYMBOL(rdma_init_qp_attr);
1038e51060f0SSean Hefty 
1039e51060f0SSean Hefty static inline int cma_zero_addr(struct sockaddr *addr)
1040e51060f0SSean Hefty {
10412e2d190cSSean Hefty 	switch (addr->sa_family) {
10422e2d190cSSean Hefty 	case AF_INET:
10432e2d190cSSean Hefty 		return ipv4_is_zeronet(((struct sockaddr_in *)addr)->sin_addr.s_addr);
10442e2d190cSSean Hefty 	case AF_INET6:
10452e2d190cSSean Hefty 		return ipv6_addr_any(&((struct sockaddr_in6 *) addr)->sin6_addr);
10462e2d190cSSean Hefty 	case AF_IB:
10472e2d190cSSean Hefty 		return ib_addr_any(&((struct sockaddr_ib *) addr)->sib_addr);
10482e2d190cSSean Hefty 	default:
10492e2d190cSSean Hefty 		return 0;
1050e51060f0SSean Hefty 	}
1051e51060f0SSean Hefty }
1052e51060f0SSean Hefty 
1053e51060f0SSean Hefty static inline int cma_loopback_addr(struct sockaddr *addr)
1054e51060f0SSean Hefty {
10552e2d190cSSean Hefty 	switch (addr->sa_family) {
10562e2d190cSSean Hefty 	case AF_INET:
10572e2d190cSSean Hefty 		return ipv4_is_loopback(((struct sockaddr_in *) addr)->sin_addr.s_addr);
10582e2d190cSSean Hefty 	case AF_INET6:
10592e2d190cSSean Hefty 		return ipv6_addr_loopback(&((struct sockaddr_in6 *) addr)->sin6_addr);
10602e2d190cSSean Hefty 	case AF_IB:
10612e2d190cSSean Hefty 		return ib_addr_loopback(&((struct sockaddr_ib *) addr)->sib_addr);
10622e2d190cSSean Hefty 	default:
10632e2d190cSSean Hefty 		return 0;
10642e2d190cSSean Hefty 	}
1065e51060f0SSean Hefty }
1066e51060f0SSean Hefty 
1067e51060f0SSean Hefty static inline int cma_any_addr(struct sockaddr *addr)
1068e51060f0SSean Hefty {
1069e51060f0SSean Hefty 	return cma_zero_addr(addr) || cma_loopback_addr(addr);
1070e51060f0SSean Hefty }
1071e51060f0SSean Hefty 
107243b752daSHefty, Sean static int cma_addr_cmp(struct sockaddr *src, struct sockaddr *dst)
107343b752daSHefty, Sean {
107443b752daSHefty, Sean 	if (src->sa_family != dst->sa_family)
107543b752daSHefty, Sean 		return -1;
107643b752daSHefty, Sean 
107743b752daSHefty, Sean 	switch (src->sa_family) {
107843b752daSHefty, Sean 	case AF_INET:
107943b752daSHefty, Sean 		return ((struct sockaddr_in *) src)->sin_addr.s_addr !=
108043b752daSHefty, Sean 		       ((struct sockaddr_in *) dst)->sin_addr.s_addr;
10812e2d190cSSean Hefty 	case AF_INET6:
108243b752daSHefty, Sean 		return ipv6_addr_cmp(&((struct sockaddr_in6 *) src)->sin6_addr,
108343b752daSHefty, Sean 				     &((struct sockaddr_in6 *) dst)->sin6_addr);
10842e2d190cSSean Hefty 	default:
10852e2d190cSSean Hefty 		return ib_addr_cmp(&((struct sockaddr_ib *) src)->sib_addr,
10862e2d190cSSean Hefty 				   &((struct sockaddr_ib *) dst)->sib_addr);
108743b752daSHefty, Sean 	}
108843b752daSHefty, Sean }
108943b752daSHefty, Sean 
109058afdcb7SSean Hefty static __be16 cma_port(struct sockaddr *addr)
1091628e5f6dSSean Hefty {
109258afdcb7SSean Hefty 	struct sockaddr_ib *sib;
109358afdcb7SSean Hefty 
109458afdcb7SSean Hefty 	switch (addr->sa_family) {
109558afdcb7SSean Hefty 	case AF_INET:
1096628e5f6dSSean Hefty 		return ((struct sockaddr_in *) addr)->sin_port;
109758afdcb7SSean Hefty 	case AF_INET6:
1098628e5f6dSSean Hefty 		return ((struct sockaddr_in6 *) addr)->sin6_port;
109958afdcb7SSean Hefty 	case AF_IB:
110058afdcb7SSean Hefty 		sib = (struct sockaddr_ib *) addr;
110158afdcb7SSean Hefty 		return htons((u16) (be64_to_cpu(sib->sib_sid) &
110258afdcb7SSean Hefty 				    be64_to_cpu(sib->sib_sid_mask)));
110358afdcb7SSean Hefty 	default:
110458afdcb7SSean Hefty 		return 0;
110558afdcb7SSean Hefty 	}
1106628e5f6dSSean Hefty }
1107628e5f6dSSean Hefty 
1108e51060f0SSean Hefty static inline int cma_any_port(struct sockaddr *addr)
1109e51060f0SSean Hefty {
1110628e5f6dSSean Hefty 	return !cma_port(addr);
1111e51060f0SSean Hefty }
1112e51060f0SSean Hefty 
11130c505f70SHaggai Eran static void cma_save_ib_info(struct sockaddr *src_addr,
11140c505f70SHaggai Eran 			     struct sockaddr *dst_addr,
11150c505f70SHaggai Eran 			     struct rdma_cm_id *listen_id,
1116c2f8fc4eSDasaratharaman Chandramouli 			     struct sa_path_rec *path)
1117e51060f0SSean Hefty {
1118fbaa1a6dSSean Hefty 	struct sockaddr_ib *listen_ib, *ib;
1119e51060f0SSean Hefty 
1120fbaa1a6dSSean Hefty 	listen_ib = (struct sockaddr_ib *) &listen_id->route.addr.src_addr;
11210c505f70SHaggai Eran 	if (src_addr) {
11220c505f70SHaggai Eran 		ib = (struct sockaddr_ib *)src_addr;
11230c505f70SHaggai Eran 		ib->sib_family = AF_IB;
1124c07678bbSMatthew Finlay 		if (path) {
1125fbaa1a6dSSean Hefty 			ib->sib_pkey = path->pkey;
1126fbaa1a6dSSean Hefty 			ib->sib_flowinfo = path->flow_label;
1127fbaa1a6dSSean Hefty 			memcpy(&ib->sib_addr, &path->sgid, 16);
1128d3957b86SMajd Dibbiny 			ib->sib_sid = path->service_id;
11290c505f70SHaggai Eran 			ib->sib_scope_id = 0;
1130c07678bbSMatthew Finlay 		} else {
1131c07678bbSMatthew Finlay 			ib->sib_pkey = listen_ib->sib_pkey;
1132c07678bbSMatthew Finlay 			ib->sib_flowinfo = listen_ib->sib_flowinfo;
1133c07678bbSMatthew Finlay 			ib->sib_addr = listen_ib->sib_addr;
1134fbaa1a6dSSean Hefty 			ib->sib_sid = listen_ib->sib_sid;
1135fbaa1a6dSSean Hefty 			ib->sib_scope_id = listen_ib->sib_scope_id;
11360c505f70SHaggai Eran 		}
11370c505f70SHaggai Eran 		ib->sib_sid_mask = cpu_to_be64(0xffffffffffffffffULL);
11380c505f70SHaggai Eran 	}
11390c505f70SHaggai Eran 	if (dst_addr) {
11400c505f70SHaggai Eran 		ib = (struct sockaddr_ib *)dst_addr;
11410c505f70SHaggai Eran 		ib->sib_family = AF_IB;
1142c07678bbSMatthew Finlay 		if (path) {
1143fbaa1a6dSSean Hefty 			ib->sib_pkey = path->pkey;
1144fbaa1a6dSSean Hefty 			ib->sib_flowinfo = path->flow_label;
1145fbaa1a6dSSean Hefty 			memcpy(&ib->sib_addr, &path->dgid, 16);
1146fbaa1a6dSSean Hefty 		}
1147c07678bbSMatthew Finlay 	}
114828521440SJason Gunthorpe }
114928521440SJason Gunthorpe 
1150c50e90d0SArnd Bergmann static void cma_save_ip4_info(struct sockaddr_in *src_addr,
1151c50e90d0SArnd Bergmann 			      struct sockaddr_in *dst_addr,
11520c505f70SHaggai Eran 			      struct cma_hdr *hdr,
11530c505f70SHaggai Eran 			      __be16 local_port)
1154fbaa1a6dSSean Hefty {
11550c505f70SHaggai Eran 	if (src_addr) {
1156c50e90d0SArnd Bergmann 		*src_addr = (struct sockaddr_in) {
1157c50e90d0SArnd Bergmann 			.sin_family = AF_INET,
1158c50e90d0SArnd Bergmann 			.sin_addr.s_addr = hdr->dst_addr.ip4.addr,
1159c50e90d0SArnd Bergmann 			.sin_port = local_port,
1160c50e90d0SArnd Bergmann 		};
11610c505f70SHaggai Eran 	}
1162fbaa1a6dSSean Hefty 
11630c505f70SHaggai Eran 	if (dst_addr) {
1164c50e90d0SArnd Bergmann 		*dst_addr = (struct sockaddr_in) {
1165c50e90d0SArnd Bergmann 			.sin_family = AF_INET,
1166c50e90d0SArnd Bergmann 			.sin_addr.s_addr = hdr->src_addr.ip4.addr,
1167c50e90d0SArnd Bergmann 			.sin_port = hdr->port,
1168c50e90d0SArnd Bergmann 		};
1169fbaa1a6dSSean Hefty 	}
11700c505f70SHaggai Eran }
1171fbaa1a6dSSean Hefty 
1172c50e90d0SArnd Bergmann static void cma_save_ip6_info(struct sockaddr_in6 *src_addr,
1173c50e90d0SArnd Bergmann 			      struct sockaddr_in6 *dst_addr,
11740c505f70SHaggai Eran 			      struct cma_hdr *hdr,
11750c505f70SHaggai Eran 			      __be16 local_port)
1176fbaa1a6dSSean Hefty {
11770c505f70SHaggai Eran 	if (src_addr) {
1178c50e90d0SArnd Bergmann 		*src_addr = (struct sockaddr_in6) {
1179c50e90d0SArnd Bergmann 			.sin6_family = AF_INET6,
1180c50e90d0SArnd Bergmann 			.sin6_addr = hdr->dst_addr.ip6,
1181c50e90d0SArnd Bergmann 			.sin6_port = local_port,
1182c50e90d0SArnd Bergmann 		};
11830c505f70SHaggai Eran 	}
1184fbaa1a6dSSean Hefty 
11850c505f70SHaggai Eran 	if (dst_addr) {
1186c50e90d0SArnd Bergmann 		*dst_addr = (struct sockaddr_in6) {
1187c50e90d0SArnd Bergmann 			.sin6_family = AF_INET6,
1188c50e90d0SArnd Bergmann 			.sin6_addr = hdr->src_addr.ip6,
1189c50e90d0SArnd Bergmann 			.sin6_port = hdr->port,
1190c50e90d0SArnd Bergmann 		};
1191fbaa1a6dSSean Hefty 	}
11920c505f70SHaggai Eran }
1193fbaa1a6dSSean Hefty 
11940c505f70SHaggai Eran static u16 cma_port_from_service_id(__be64 service_id)
11950c505f70SHaggai Eran {
11960c505f70SHaggai Eran 	return (u16)be64_to_cpu(service_id);
11970c505f70SHaggai Eran }
11980c505f70SHaggai Eran 
11990c505f70SHaggai Eran static int cma_save_ip_info(struct sockaddr *src_addr,
12000c505f70SHaggai Eran 			    struct sockaddr *dst_addr,
12010c505f70SHaggai Eran 			    struct ib_cm_event *ib_event,
12020c505f70SHaggai Eran 			    __be64 service_id)
1203fbaa1a6dSSean Hefty {
1204fbaa1a6dSSean Hefty 	struct cma_hdr *hdr;
12050c505f70SHaggai Eran 	__be16 port;
1206e51060f0SSean Hefty 
1207fbaa1a6dSSean Hefty 	hdr = ib_event->private_data;
1208fbaa1a6dSSean Hefty 	if (hdr->cma_version != CMA_VERSION)
1209fbaa1a6dSSean Hefty 		return -EINVAL;
1210e51060f0SSean Hefty 
12110c505f70SHaggai Eran 	port = htons(cma_port_from_service_id(service_id));
12120c505f70SHaggai Eran 
1213fbaa1a6dSSean Hefty 	switch (cma_get_ip_ver(hdr)) {
1214e51060f0SSean Hefty 	case 4:
1215c50e90d0SArnd Bergmann 		cma_save_ip4_info((struct sockaddr_in *)src_addr,
1216c50e90d0SArnd Bergmann 				  (struct sockaddr_in *)dst_addr, hdr, port);
1217e51060f0SSean Hefty 		break;
1218e51060f0SSean Hefty 	case 6:
1219c50e90d0SArnd Bergmann 		cma_save_ip6_info((struct sockaddr_in6 *)src_addr,
1220c50e90d0SArnd Bergmann 				  (struct sockaddr_in6 *)dst_addr, hdr, port);
1221e51060f0SSean Hefty 		break;
1222e51060f0SSean Hefty 	default:
12234c21b5bcSHaggai Eran 		return -EAFNOSUPPORT;
1224e51060f0SSean Hefty 	}
12250c505f70SHaggai Eran 
1226fbaa1a6dSSean Hefty 	return 0;
1227e51060f0SSean Hefty }
1228e51060f0SSean Hefty 
12290c505f70SHaggai Eran static int cma_save_net_info(struct sockaddr *src_addr,
12300c505f70SHaggai Eran 			     struct sockaddr *dst_addr,
12310c505f70SHaggai Eran 			     struct rdma_cm_id *listen_id,
12320c505f70SHaggai Eran 			     struct ib_cm_event *ib_event,
12330c505f70SHaggai Eran 			     sa_family_t sa_family, __be64 service_id)
12340c505f70SHaggai Eran {
12350c505f70SHaggai Eran 	if (sa_family == AF_IB) {
12360c505f70SHaggai Eran 		if (ib_event->event == IB_CM_REQ_RECEIVED)
12370c505f70SHaggai Eran 			cma_save_ib_info(src_addr, dst_addr, listen_id,
12380c505f70SHaggai Eran 					 ib_event->param.req_rcvd.primary_path);
12390c505f70SHaggai Eran 		else if (ib_event->event == IB_CM_SIDR_REQ_RECEIVED)
12400c505f70SHaggai Eran 			cma_save_ib_info(src_addr, dst_addr, listen_id, NULL);
12410c505f70SHaggai Eran 		return 0;
12420c505f70SHaggai Eran 	}
12430c505f70SHaggai Eran 
12440c505f70SHaggai Eran 	return cma_save_ip_info(src_addr, dst_addr, ib_event, service_id);
12450c505f70SHaggai Eran }
12460c505f70SHaggai Eran 
12474c21b5bcSHaggai Eran static int cma_save_req_info(const struct ib_cm_event *ib_event,
12484c21b5bcSHaggai Eran 			     struct cma_req_info *req)
12494c21b5bcSHaggai Eran {
12504c21b5bcSHaggai Eran 	const struct ib_cm_req_event_param *req_param =
12514c21b5bcSHaggai Eran 		&ib_event->param.req_rcvd;
12524c21b5bcSHaggai Eran 	const struct ib_cm_sidr_req_event_param *sidr_param =
12534c21b5bcSHaggai Eran 		&ib_event->param.sidr_req_rcvd;
12544c21b5bcSHaggai Eran 
12554c21b5bcSHaggai Eran 	switch (ib_event->event) {
12564c21b5bcSHaggai Eran 	case IB_CM_REQ_RECEIVED:
12574c21b5bcSHaggai Eran 		req->device	= req_param->listen_id->device;
12584c21b5bcSHaggai Eran 		req->port	= req_param->port;
12594c21b5bcSHaggai Eran 		memcpy(&req->local_gid, &req_param->primary_path->sgid,
12604c21b5bcSHaggai Eran 		       sizeof(req->local_gid));
12614c21b5bcSHaggai Eran 		req->has_gid	= true;
1262d3957b86SMajd Dibbiny 		req->service_id = req_param->primary_path->service_id;
1263ab3964adSHaggai Eran 		req->pkey	= be16_to_cpu(req_param->primary_path->pkey);
126484424a7fSHaggai Eran 		if (req->pkey != req_param->bth_pkey)
126584424a7fSHaggai Eran 			pr_warn_ratelimited("RDMA CMA: got different BTH P_Key (0x%x) and primary path P_Key (0x%x)\n"
126684424a7fSHaggai Eran 					    "RDMA CMA: in the future this may cause the request to be dropped\n",
126784424a7fSHaggai Eran 					    req_param->bth_pkey, req->pkey);
12684c21b5bcSHaggai Eran 		break;
12694c21b5bcSHaggai Eran 	case IB_CM_SIDR_REQ_RECEIVED:
12704c21b5bcSHaggai Eran 		req->device	= sidr_param->listen_id->device;
12714c21b5bcSHaggai Eran 		req->port	= sidr_param->port;
12724c21b5bcSHaggai Eran 		req->has_gid	= false;
12734c21b5bcSHaggai Eran 		req->service_id	= sidr_param->service_id;
1274ab3964adSHaggai Eran 		req->pkey	= sidr_param->pkey;
127584424a7fSHaggai Eran 		if (req->pkey != sidr_param->bth_pkey)
127684424a7fSHaggai Eran 			pr_warn_ratelimited("RDMA CMA: got different BTH P_Key (0x%x) and SIDR request payload P_Key (0x%x)\n"
127784424a7fSHaggai Eran 					    "RDMA CMA: in the future this may cause the request to be dropped\n",
127884424a7fSHaggai Eran 					    sidr_param->bth_pkey, req->pkey);
12794c21b5bcSHaggai Eran 		break;
12804c21b5bcSHaggai Eran 	default:
12814c21b5bcSHaggai Eran 		return -EINVAL;
12824c21b5bcSHaggai Eran 	}
12834c21b5bcSHaggai Eran 
12844c21b5bcSHaggai Eran 	return 0;
12854c21b5bcSHaggai Eran }
12864c21b5bcSHaggai Eran 
1287f887f2acSHaggai Eran static bool validate_ipv4_net_dev(struct net_device *net_dev,
1288f887f2acSHaggai Eran 				  const struct sockaddr_in *dst_addr,
1289f887f2acSHaggai Eran 				  const struct sockaddr_in *src_addr)
1290f887f2acSHaggai Eran {
1291f887f2acSHaggai Eran 	__be32 daddr = dst_addr->sin_addr.s_addr,
1292f887f2acSHaggai Eran 	       saddr = src_addr->sin_addr.s_addr;
1293f887f2acSHaggai Eran 	struct fib_result res;
1294f887f2acSHaggai Eran 	struct flowi4 fl4;
1295f887f2acSHaggai Eran 	int err;
1296f887f2acSHaggai Eran 	bool ret;
1297f887f2acSHaggai Eran 
1298f887f2acSHaggai Eran 	if (ipv4_is_multicast(saddr) || ipv4_is_lbcast(saddr) ||
1299f887f2acSHaggai Eran 	    ipv4_is_lbcast(daddr) || ipv4_is_zeronet(saddr) ||
1300f887f2acSHaggai Eran 	    ipv4_is_zeronet(daddr) || ipv4_is_loopback(daddr) ||
1301f887f2acSHaggai Eran 	    ipv4_is_loopback(saddr))
1302f887f2acSHaggai Eran 		return false;
1303f887f2acSHaggai Eran 
1304f887f2acSHaggai Eran 	memset(&fl4, 0, sizeof(fl4));
1305f887f2acSHaggai Eran 	fl4.flowi4_iif = net_dev->ifindex;
1306f887f2acSHaggai Eran 	fl4.daddr = daddr;
1307f887f2acSHaggai Eran 	fl4.saddr = saddr;
1308f887f2acSHaggai Eran 
1309f887f2acSHaggai Eran 	rcu_read_lock();
1310f887f2acSHaggai Eran 	err = fib_lookup(dev_net(net_dev), &fl4, &res, 0);
1311d3632493SBart Van Assche 	ret = err == 0 && FIB_RES_DEV(res) == net_dev;
1312f887f2acSHaggai Eran 	rcu_read_unlock();
1313f887f2acSHaggai Eran 
1314f887f2acSHaggai Eran 	return ret;
1315f887f2acSHaggai Eran }
1316f887f2acSHaggai Eran 
1317f887f2acSHaggai Eran static bool validate_ipv6_net_dev(struct net_device *net_dev,
1318f887f2acSHaggai Eran 				  const struct sockaddr_in6 *dst_addr,
1319f887f2acSHaggai Eran 				  const struct sockaddr_in6 *src_addr)
1320f887f2acSHaggai Eran {
1321f887f2acSHaggai Eran #if IS_ENABLED(CONFIG_IPV6)
1322f887f2acSHaggai Eran 	const int strict = ipv6_addr_type(&dst_addr->sin6_addr) &
1323f887f2acSHaggai Eran 			   IPV6_ADDR_LINKLOCAL;
1324f887f2acSHaggai Eran 	struct rt6_info *rt = rt6_lookup(dev_net(net_dev), &dst_addr->sin6_addr,
1325f887f2acSHaggai Eran 					 &src_addr->sin6_addr, net_dev->ifindex,
1326b75cc8f9SDavid Ahern 					 NULL, strict);
1327f887f2acSHaggai Eran 	bool ret;
1328f887f2acSHaggai Eran 
1329f887f2acSHaggai Eran 	if (!rt)
1330f887f2acSHaggai Eran 		return false;
1331f887f2acSHaggai Eran 
1332f887f2acSHaggai Eran 	ret = rt->rt6i_idev->dev == net_dev;
1333f887f2acSHaggai Eran 	ip6_rt_put(rt);
1334f887f2acSHaggai Eran 
1335f887f2acSHaggai Eran 	return ret;
1336f887f2acSHaggai Eran #else
1337f887f2acSHaggai Eran 	return false;
1338f887f2acSHaggai Eran #endif
1339f887f2acSHaggai Eran }
1340f887f2acSHaggai Eran 
1341f887f2acSHaggai Eran static bool validate_net_dev(struct net_device *net_dev,
1342f887f2acSHaggai Eran 			     const struct sockaddr *daddr,
1343f887f2acSHaggai Eran 			     const struct sockaddr *saddr)
1344f887f2acSHaggai Eran {
1345f887f2acSHaggai Eran 	const struct sockaddr_in *daddr4 = (const struct sockaddr_in *)daddr;
1346f887f2acSHaggai Eran 	const struct sockaddr_in *saddr4 = (const struct sockaddr_in *)saddr;
1347f887f2acSHaggai Eran 	const struct sockaddr_in6 *daddr6 = (const struct sockaddr_in6 *)daddr;
1348f887f2acSHaggai Eran 	const struct sockaddr_in6 *saddr6 = (const struct sockaddr_in6 *)saddr;
1349f887f2acSHaggai Eran 
1350f887f2acSHaggai Eran 	switch (daddr->sa_family) {
1351f887f2acSHaggai Eran 	case AF_INET:
1352f887f2acSHaggai Eran 		return saddr->sa_family == AF_INET &&
1353f887f2acSHaggai Eran 		       validate_ipv4_net_dev(net_dev, daddr4, saddr4);
1354f887f2acSHaggai Eran 
1355f887f2acSHaggai Eran 	case AF_INET6:
1356f887f2acSHaggai Eran 		return saddr->sa_family == AF_INET6 &&
1357f887f2acSHaggai Eran 		       validate_ipv6_net_dev(net_dev, daddr6, saddr6);
1358f887f2acSHaggai Eran 
1359f887f2acSHaggai Eran 	default:
1360f887f2acSHaggai Eran 		return false;
1361f887f2acSHaggai Eran 	}
1362f887f2acSHaggai Eran }
1363f887f2acSHaggai Eran 
13644c21b5bcSHaggai Eran static struct net_device *cma_get_net_dev(struct ib_cm_event *ib_event,
13652918c1a9SParav Pandit 					  struct cma_req_info *req)
13664c21b5bcSHaggai Eran {
13672918c1a9SParav Pandit 	struct sockaddr *listen_addr =
13682918c1a9SParav Pandit 			(struct sockaddr *)&req->listen_addr_storage;
13692918c1a9SParav Pandit 	struct sockaddr *src_addr = (struct sockaddr *)&req->src_addr_storage;
13704c21b5bcSHaggai Eran 	struct net_device *net_dev;
13714c21b5bcSHaggai Eran 	const union ib_gid *gid = req->has_gid ? &req->local_gid : NULL;
13724c21b5bcSHaggai Eran 	int err;
13734c21b5bcSHaggai Eran 
1374f887f2acSHaggai Eran 	err = cma_save_ip_info(listen_addr, src_addr, ib_event,
1375f887f2acSHaggai Eran 			       req->service_id);
13764c21b5bcSHaggai Eran 	if (err)
13774c21b5bcSHaggai Eran 		return ERR_PTR(err);
13784c21b5bcSHaggai Eran 
13794c21b5bcSHaggai Eran 	net_dev = ib_get_net_dev_by_params(req->device, req->port, req->pkey,
13804c21b5bcSHaggai Eran 					   gid, listen_addr);
13814c21b5bcSHaggai Eran 	if (!net_dev)
13824c21b5bcSHaggai Eran 		return ERR_PTR(-ENODEV);
13834c21b5bcSHaggai Eran 
13844c21b5bcSHaggai Eran 	return net_dev;
13854c21b5bcSHaggai Eran }
13864c21b5bcSHaggai Eran 
13872253fc0cSSteve Wise static enum rdma_ucm_port_space rdma_ps_from_service_id(__be64 service_id)
13884c21b5bcSHaggai Eran {
13894c21b5bcSHaggai Eran 	return (be64_to_cpu(service_id) >> 16) & 0xffff;
13904c21b5bcSHaggai Eran }
13914c21b5bcSHaggai Eran 
13924c21b5bcSHaggai Eran static bool cma_match_private_data(struct rdma_id_private *id_priv,
13934c21b5bcSHaggai Eran 				   const struct cma_hdr *hdr)
13944c21b5bcSHaggai Eran {
13954c21b5bcSHaggai Eran 	struct sockaddr *addr = cma_src_addr(id_priv);
13964c21b5bcSHaggai Eran 	__be32 ip4_addr;
13974c21b5bcSHaggai Eran 	struct in6_addr ip6_addr;
13984c21b5bcSHaggai Eran 
13994c21b5bcSHaggai Eran 	if (cma_any_addr(addr) && !id_priv->afonly)
14004c21b5bcSHaggai Eran 		return true;
14014c21b5bcSHaggai Eran 
14024c21b5bcSHaggai Eran 	switch (addr->sa_family) {
14034c21b5bcSHaggai Eran 	case AF_INET:
14044c21b5bcSHaggai Eran 		ip4_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
14054c21b5bcSHaggai Eran 		if (cma_get_ip_ver(hdr) != 4)
14064c21b5bcSHaggai Eran 			return false;
14074c21b5bcSHaggai Eran 		if (!cma_any_addr(addr) &&
14084c21b5bcSHaggai Eran 		    hdr->dst_addr.ip4.addr != ip4_addr)
14094c21b5bcSHaggai Eran 			return false;
14104c21b5bcSHaggai Eran 		break;
14114c21b5bcSHaggai Eran 	case AF_INET6:
14124c21b5bcSHaggai Eran 		ip6_addr = ((struct sockaddr_in6 *)addr)->sin6_addr;
14134c21b5bcSHaggai Eran 		if (cma_get_ip_ver(hdr) != 6)
14144c21b5bcSHaggai Eran 			return false;
14154c21b5bcSHaggai Eran 		if (!cma_any_addr(addr) &&
14164c21b5bcSHaggai Eran 		    memcmp(&hdr->dst_addr.ip6, &ip6_addr, sizeof(ip6_addr)))
14174c21b5bcSHaggai Eran 			return false;
14184c21b5bcSHaggai Eran 		break;
14194c21b5bcSHaggai Eran 	case AF_IB:
14204c21b5bcSHaggai Eran 		return true;
14214c21b5bcSHaggai Eran 	default:
14224c21b5bcSHaggai Eran 		return false;
14234c21b5bcSHaggai Eran 	}
14244c21b5bcSHaggai Eran 
14254c21b5bcSHaggai Eran 	return true;
14264c21b5bcSHaggai Eran }
14274c21b5bcSHaggai Eran 
1428b8cab5daSHaggai Eran static bool cma_protocol_roce(const struct rdma_cm_id *id)
1429b8cab5daSHaggai Eran {
1430b8cab5daSHaggai Eran 	struct ib_device *device = id->device;
1431b8cab5daSHaggai Eran 	const int port_num = id->port_num ?: rdma_start_port(device);
1432b8cab5daSHaggai Eran 
14335ac08a34SParav Pandit 	return rdma_protocol_roce(device, port_num);
1434b8cab5daSHaggai Eran }
1435b8cab5daSHaggai Eran 
1436fac51590SMatan Barak static bool cma_match_net_dev(const struct rdma_cm_id *id,
1437fac51590SMatan Barak 			      const struct net_device *net_dev,
1438fac51590SMatan Barak 			      u8 port_num)
14394c21b5bcSHaggai Eran {
1440fac51590SMatan Barak 	const struct rdma_addr *addr = &id->route.addr;
14414c21b5bcSHaggai Eran 
14424c21b5bcSHaggai Eran 	if (!net_dev)
1443b8cab5daSHaggai Eran 		/* This request is an AF_IB request or a RoCE request */
1444fac51590SMatan Barak 		return (!id->port_num || id->port_num == port_num) &&
1445fac51590SMatan Barak 		       (addr->src_addr.ss_family == AF_IB ||
14465ac08a34SParav Pandit 			rdma_protocol_roce(id->device, port_num));
14474c21b5bcSHaggai Eran 
14484c21b5bcSHaggai Eran 	return !addr->dev_addr.bound_dev_if ||
1449fa20105eSGuy Shapiro 	       (net_eq(dev_net(net_dev), addr->dev_addr.net) &&
14504c21b5bcSHaggai Eran 		addr->dev_addr.bound_dev_if == net_dev->ifindex);
14514c21b5bcSHaggai Eran }
14524c21b5bcSHaggai Eran 
14534c21b5bcSHaggai Eran static struct rdma_id_private *cma_find_listener(
14544c21b5bcSHaggai Eran 		const struct rdma_bind_list *bind_list,
14554c21b5bcSHaggai Eran 		const struct ib_cm_id *cm_id,
14564c21b5bcSHaggai Eran 		const struct ib_cm_event *ib_event,
14574c21b5bcSHaggai Eran 		const struct cma_req_info *req,
14584c21b5bcSHaggai Eran 		const struct net_device *net_dev)
14594c21b5bcSHaggai Eran {
14604c21b5bcSHaggai Eran 	struct rdma_id_private *id_priv, *id_priv_dev;
14614c21b5bcSHaggai Eran 
14624c21b5bcSHaggai Eran 	if (!bind_list)
14634c21b5bcSHaggai Eran 		return ERR_PTR(-EINVAL);
14644c21b5bcSHaggai Eran 
14654c21b5bcSHaggai Eran 	hlist_for_each_entry(id_priv, &bind_list->owners, node) {
14664c21b5bcSHaggai Eran 		if (cma_match_private_data(id_priv, ib_event->private_data)) {
14674c21b5bcSHaggai Eran 			if (id_priv->id.device == cm_id->device &&
1468fac51590SMatan Barak 			    cma_match_net_dev(&id_priv->id, net_dev, req->port))
14694c21b5bcSHaggai Eran 				return id_priv;
14704c21b5bcSHaggai Eran 			list_for_each_entry(id_priv_dev,
14714c21b5bcSHaggai Eran 					    &id_priv->listen_list,
14724c21b5bcSHaggai Eran 					    listen_list) {
14734c21b5bcSHaggai Eran 				if (id_priv_dev->id.device == cm_id->device &&
1474fac51590SMatan Barak 				    cma_match_net_dev(&id_priv_dev->id, net_dev, req->port))
14754c21b5bcSHaggai Eran 					return id_priv_dev;
14764c21b5bcSHaggai Eran 			}
14774c21b5bcSHaggai Eran 		}
14784c21b5bcSHaggai Eran 	}
14794c21b5bcSHaggai Eran 
14804c21b5bcSHaggai Eran 	return ERR_PTR(-EINVAL);
14814c21b5bcSHaggai Eran }
14824c21b5bcSHaggai Eran 
14834c21b5bcSHaggai Eran static struct rdma_id_private *cma_id_from_event(struct ib_cm_id *cm_id,
14840b3ca768SHaggai Eran 						 struct ib_cm_event *ib_event,
14850b3ca768SHaggai Eran 						 struct net_device **net_dev)
14864c21b5bcSHaggai Eran {
14874c21b5bcSHaggai Eran 	struct cma_req_info req;
14884c21b5bcSHaggai Eran 	struct rdma_bind_list *bind_list;
14894c21b5bcSHaggai Eran 	struct rdma_id_private *id_priv;
14904c21b5bcSHaggai Eran 	int err;
14914c21b5bcSHaggai Eran 
14924c21b5bcSHaggai Eran 	err = cma_save_req_info(ib_event, &req);
14934c21b5bcSHaggai Eran 	if (err)
14944c21b5bcSHaggai Eran 		return ERR_PTR(err);
14954c21b5bcSHaggai Eran 
14960b3ca768SHaggai Eran 	*net_dev = cma_get_net_dev(ib_event, &req);
14970b3ca768SHaggai Eran 	if (IS_ERR(*net_dev)) {
14980b3ca768SHaggai Eran 		if (PTR_ERR(*net_dev) == -EAFNOSUPPORT) {
14994c21b5bcSHaggai Eran 			/* Assuming the protocol is AF_IB */
15000b3ca768SHaggai Eran 			*net_dev = NULL;
15015ac08a34SParav Pandit 		} else if (rdma_protocol_roce(req.device, req.port)) {
1502b8cab5daSHaggai Eran 			/* TODO find the net dev matching the request parameters
1503b8cab5daSHaggai Eran 			 * through the RoCE GID table */
1504b8cab5daSHaggai Eran 			*net_dev = NULL;
15054c21b5bcSHaggai Eran 		} else {
15060b3ca768SHaggai Eran 			return ERR_CAST(*net_dev);
15074c21b5bcSHaggai Eran 		}
15084c21b5bcSHaggai Eran 	}
15094c21b5bcSHaggai Eran 
15102918c1a9SParav Pandit 	/*
15112918c1a9SParav Pandit 	 * Net namespace might be getting deleted while route lookup,
15122918c1a9SParav Pandit 	 * cm_id lookup is in progress. Therefore, perform netdevice
15132918c1a9SParav Pandit 	 * validation, cm_id lookup under rcu lock.
15142918c1a9SParav Pandit 	 * RCU lock along with netdevice state check, synchronizes with
15152918c1a9SParav Pandit 	 * netdevice migrating to different net namespace and also avoids
15162918c1a9SParav Pandit 	 * case where net namespace doesn't get deleted while lookup is in
15172918c1a9SParav Pandit 	 * progress.
15182918c1a9SParav Pandit 	 * If the device state is not IFF_UP, its properties such as ifindex
15192918c1a9SParav Pandit 	 * and nd_net cannot be trusted to remain valid without rcu lock.
15202918c1a9SParav Pandit 	 * net/core/dev.c change_net_namespace() ensures to synchronize with
15212918c1a9SParav Pandit 	 * ongoing operations on net device after device is closed using
15222918c1a9SParav Pandit 	 * synchronize_net().
15232918c1a9SParav Pandit 	 */
15242918c1a9SParav Pandit 	rcu_read_lock();
15252918c1a9SParav Pandit 	if (*net_dev) {
15262918c1a9SParav Pandit 		/*
15272918c1a9SParav Pandit 		 * If netdevice is down, it is likely that it is administratively
15282918c1a9SParav Pandit 		 * down or it might be migrating to different namespace.
15292918c1a9SParav Pandit 		 * In that case avoid further processing, as the net namespace
15302918c1a9SParav Pandit 		 * or ifindex may change.
15312918c1a9SParav Pandit 		 */
15322918c1a9SParav Pandit 		if (((*net_dev)->flags & IFF_UP) == 0) {
15332918c1a9SParav Pandit 			id_priv = ERR_PTR(-EHOSTUNREACH);
15342918c1a9SParav Pandit 			goto err;
15352918c1a9SParav Pandit 		}
15362918c1a9SParav Pandit 
15372918c1a9SParav Pandit 		if (!validate_net_dev(*net_dev,
15382918c1a9SParav Pandit 				 (struct sockaddr *)&req.listen_addr_storage,
15392918c1a9SParav Pandit 				 (struct sockaddr *)&req.src_addr_storage)) {
15402918c1a9SParav Pandit 			id_priv = ERR_PTR(-EHOSTUNREACH);
15412918c1a9SParav Pandit 			goto err;
15422918c1a9SParav Pandit 		}
15432918c1a9SParav Pandit 	}
15442918c1a9SParav Pandit 
1545fa20105eSGuy Shapiro 	bind_list = cma_ps_find(*net_dev ? dev_net(*net_dev) : &init_net,
15464be74b42SHaggai Eran 				rdma_ps_from_service_id(req.service_id),
15474c21b5bcSHaggai Eran 				cma_port_from_service_id(req.service_id));
15480b3ca768SHaggai Eran 	id_priv = cma_find_listener(bind_list, cm_id, ib_event, &req, *net_dev);
15492918c1a9SParav Pandit err:
15502918c1a9SParav Pandit 	rcu_read_unlock();
1551b3b51f9fSHaggai Eran 	if (IS_ERR(id_priv) && *net_dev) {
1552be688195SHaggai Eran 		dev_put(*net_dev);
1553be688195SHaggai Eran 		*net_dev = NULL;
1554be688195SHaggai Eran 	}
15554c21b5bcSHaggai Eran 	return id_priv;
15564c21b5bcSHaggai Eran }
15574c21b5bcSHaggai Eran 
1558c0b64f58SBart Van Assche static inline u8 cma_user_data_offset(struct rdma_id_private *id_priv)
1559e51060f0SSean Hefty {
1560e8160e15SSean Hefty 	return cma_family(id_priv) == AF_IB ? 0 : sizeof(struct cma_hdr);
1561e51060f0SSean Hefty }
1562e51060f0SSean Hefty 
1563e51060f0SSean Hefty static void cma_cancel_route(struct rdma_id_private *id_priv)
1564e51060f0SSean Hefty {
1565fe53ba2fSMichael Wang 	if (rdma_cap_ib_sa(id_priv->id.device, id_priv->id.port_num)) {
1566e51060f0SSean Hefty 		if (id_priv->query)
1567e51060f0SSean Hefty 			ib_sa_cancel_query(id_priv->query_id, id_priv->query);
1568e51060f0SSean Hefty 	}
1569e51060f0SSean Hefty }
1570e51060f0SSean Hefty 
1571e51060f0SSean Hefty static void cma_cancel_listens(struct rdma_id_private *id_priv)
1572e51060f0SSean Hefty {
1573e51060f0SSean Hefty 	struct rdma_id_private *dev_id_priv;
1574e51060f0SSean Hefty 
1575d02d1f53SSean Hefty 	/*
1576d02d1f53SSean Hefty 	 * Remove from listen_any_list to prevent added devices from spawning
1577d02d1f53SSean Hefty 	 * additional listen requests.
1578d02d1f53SSean Hefty 	 */
1579e51060f0SSean Hefty 	mutex_lock(&lock);
1580e51060f0SSean Hefty 	list_del(&id_priv->list);
1581e51060f0SSean Hefty 
1582e51060f0SSean Hefty 	while (!list_empty(&id_priv->listen_list)) {
1583e51060f0SSean Hefty 		dev_id_priv = list_entry(id_priv->listen_list.next,
1584e51060f0SSean Hefty 					 struct rdma_id_private, listen_list);
1585d02d1f53SSean Hefty 		/* sync with device removal to avoid duplicate destruction */
1586d02d1f53SSean Hefty 		list_del_init(&dev_id_priv->list);
1587d02d1f53SSean Hefty 		list_del(&dev_id_priv->listen_list);
1588d02d1f53SSean Hefty 		mutex_unlock(&lock);
1589d02d1f53SSean Hefty 
1590d02d1f53SSean Hefty 		rdma_destroy_id(&dev_id_priv->id);
1591d02d1f53SSean Hefty 		mutex_lock(&lock);
1592e51060f0SSean Hefty 	}
1593e51060f0SSean Hefty 	mutex_unlock(&lock);
1594e51060f0SSean Hefty }
1595e51060f0SSean Hefty 
1596e51060f0SSean Hefty static void cma_cancel_operation(struct rdma_id_private *id_priv,
1597550e5ca7SNir Muchtar 				 enum rdma_cm_state state)
1598e51060f0SSean Hefty {
1599e51060f0SSean Hefty 	switch (state) {
1600550e5ca7SNir Muchtar 	case RDMA_CM_ADDR_QUERY:
1601e51060f0SSean Hefty 		rdma_addr_cancel(&id_priv->id.route.addr.dev_addr);
1602e51060f0SSean Hefty 		break;
1603550e5ca7SNir Muchtar 	case RDMA_CM_ROUTE_QUERY:
1604e51060f0SSean Hefty 		cma_cancel_route(id_priv);
1605e51060f0SSean Hefty 		break;
1606550e5ca7SNir Muchtar 	case RDMA_CM_LISTEN:
1607f4753834SSean Hefty 		if (cma_any_addr(cma_src_addr(id_priv)) && !id_priv->cma_dev)
1608e51060f0SSean Hefty 			cma_cancel_listens(id_priv);
1609e51060f0SSean Hefty 		break;
1610e51060f0SSean Hefty 	default:
1611e51060f0SSean Hefty 		break;
1612e51060f0SSean Hefty 	}
1613e51060f0SSean Hefty }
1614e51060f0SSean Hefty 
1615e51060f0SSean Hefty static void cma_release_port(struct rdma_id_private *id_priv)
1616e51060f0SSean Hefty {
1617e51060f0SSean Hefty 	struct rdma_bind_list *bind_list = id_priv->bind_list;
1618fa20105eSGuy Shapiro 	struct net *net = id_priv->id.route.addr.dev_addr.net;
1619e51060f0SSean Hefty 
1620e51060f0SSean Hefty 	if (!bind_list)
1621e51060f0SSean Hefty 		return;
1622e51060f0SSean Hefty 
1623e51060f0SSean Hefty 	mutex_lock(&lock);
1624e51060f0SSean Hefty 	hlist_del(&id_priv->node);
1625e51060f0SSean Hefty 	if (hlist_empty(&bind_list->owners)) {
1626fa20105eSGuy Shapiro 		cma_ps_remove(net, bind_list->ps, bind_list->port);
1627e51060f0SSean Hefty 		kfree(bind_list);
1628e51060f0SSean Hefty 	}
1629e51060f0SSean Hefty 	mutex_unlock(&lock);
1630e51060f0SSean Hefty }
1631e51060f0SSean Hefty 
1632c8f6a362SSean Hefty static void cma_leave_mc_groups(struct rdma_id_private *id_priv)
1633c8f6a362SSean Hefty {
1634c8f6a362SSean Hefty 	struct cma_multicast *mc;
1635c8f6a362SSean Hefty 
1636c8f6a362SSean Hefty 	while (!list_empty(&id_priv->mc_list)) {
1637c8f6a362SSean Hefty 		mc = container_of(id_priv->mc_list.next,
1638c8f6a362SSean Hefty 				  struct cma_multicast, list);
1639c8f6a362SSean Hefty 		list_del(&mc->list);
1640a31ad3b0SMichael Wang 		if (rdma_cap_ib_mcast(id_priv->cma_dev->device,
16415c9a5282SMichael Wang 				      id_priv->id.port_num)) {
1642c8f6a362SSean Hefty 			ib_sa_free_multicast(mc->multicast.ib);
1643c8f6a362SSean Hefty 			kfree(mc);
1644bee3c3c9SMoni Shoua 		} else {
1645bee3c3c9SMoni Shoua 			if (mc->igmp_joined) {
1646bee3c3c9SMoni Shoua 				struct rdma_dev_addr *dev_addr =
1647bee3c3c9SMoni Shoua 					&id_priv->id.route.addr.dev_addr;
1648bee3c3c9SMoni Shoua 				struct net_device *ndev = NULL;
1649bee3c3c9SMoni Shoua 
1650bee3c3c9SMoni Shoua 				if (dev_addr->bound_dev_if)
1651bee3c3c9SMoni Shoua 					ndev = dev_get_by_index(&init_net,
1652bee3c3c9SMoni Shoua 								dev_addr->bound_dev_if);
1653bee3c3c9SMoni Shoua 				if (ndev) {
1654bee3c3c9SMoni Shoua 					cma_igmp_send(ndev,
1655bee3c3c9SMoni Shoua 						      &mc->multicast.ib->rec.mgid,
1656bee3c3c9SMoni Shoua 						      false);
1657bee3c3c9SMoni Shoua 					dev_put(ndev);
1658bee3c3c9SMoni Shoua 				}
1659bee3c3c9SMoni Shoua 			}
16603c86aa70SEli Cohen 			kref_put(&mc->mcref, release_mc);
1661c8f6a362SSean Hefty 		}
1662c8f6a362SSean Hefty 	}
1663bee3c3c9SMoni Shoua }
1664c8f6a362SSean Hefty 
1665e51060f0SSean Hefty void rdma_destroy_id(struct rdma_cm_id *id)
1666e51060f0SSean Hefty {
1667e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
1668550e5ca7SNir Muchtar 	enum rdma_cm_state state;
1669e51060f0SSean Hefty 
1670e51060f0SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
1671550e5ca7SNir Muchtar 	state = cma_exch(id_priv, RDMA_CM_DESTROYING);
1672e51060f0SSean Hefty 	cma_cancel_operation(id_priv, state);
1673e51060f0SSean Hefty 
1674a396d43aSSean Hefty 	/*
1675a396d43aSSean Hefty 	 * Wait for any active callback to finish.  New callbacks will find
1676a396d43aSSean Hefty 	 * the id_priv state set to destroying and abort.
1677a396d43aSSean Hefty 	 */
1678a396d43aSSean Hefty 	mutex_lock(&id_priv->handler_mutex);
1679a396d43aSSean Hefty 	mutex_unlock(&id_priv->handler_mutex);
1680a396d43aSSean Hefty 
1681e51060f0SSean Hefty 	if (id_priv->cma_dev) {
168200313983SSteve Wise 		rdma_restrack_del(&id_priv->res);
168372219ceaSMichael Wang 		if (rdma_cap_ib_cm(id_priv->id.device, 1)) {
16840c9361fcSJack Morgenstein 			if (id_priv->cm_id.ib)
1685e51060f0SSean Hefty 				ib_destroy_cm_id(id_priv->cm_id.ib);
168604215330SMichael Wang 		} else if (rdma_cap_iw_cm(id_priv->id.device, 1)) {
16870c9361fcSJack Morgenstein 			if (id_priv->cm_id.iw)
168807ebafbaSTom Tucker 				iw_destroy_cm_id(id_priv->cm_id.iw);
1689e51060f0SSean Hefty 		}
1690c8f6a362SSean Hefty 		cma_leave_mc_groups(id_priv);
1691a396d43aSSean Hefty 		cma_release_dev(id_priv);
1692e51060f0SSean Hefty 	}
1693e51060f0SSean Hefty 
1694e51060f0SSean Hefty 	cma_release_port(id_priv);
1695e51060f0SSean Hefty 	cma_deref_id(id_priv);
1696e51060f0SSean Hefty 	wait_for_completion(&id_priv->comp);
1697e51060f0SSean Hefty 
1698d02d1f53SSean Hefty 	if (id_priv->internal_id)
1699d02d1f53SSean Hefty 		cma_deref_id(id_priv->id.context);
1700d02d1f53SSean Hefty 
1701e51060f0SSean Hefty 	kfree(id_priv->id.route.path_rec);
1702fa20105eSGuy Shapiro 	put_net(id_priv->id.route.addr.dev_addr.net);
1703e51060f0SSean Hefty 	kfree(id_priv);
1704e51060f0SSean Hefty }
1705e51060f0SSean Hefty EXPORT_SYMBOL(rdma_destroy_id);
1706e51060f0SSean Hefty 
1707e51060f0SSean Hefty static int cma_rep_recv(struct rdma_id_private *id_priv)
1708e51060f0SSean Hefty {
1709e51060f0SSean Hefty 	int ret;
1710e51060f0SSean Hefty 
17115851bb89SSean Hefty 	ret = cma_modify_qp_rtr(id_priv, NULL);
1712e51060f0SSean Hefty 	if (ret)
1713e51060f0SSean Hefty 		goto reject;
1714e51060f0SSean Hefty 
17155851bb89SSean Hefty 	ret = cma_modify_qp_rts(id_priv, NULL);
1716e51060f0SSean Hefty 	if (ret)
1717e51060f0SSean Hefty 		goto reject;
1718e51060f0SSean Hefty 
1719e51060f0SSean Hefty 	ret = ib_send_cm_rtu(id_priv->cm_id.ib, NULL, 0);
1720e51060f0SSean Hefty 	if (ret)
1721e51060f0SSean Hefty 		goto reject;
1722e51060f0SSean Hefty 
1723e51060f0SSean Hefty 	return 0;
1724e51060f0SSean Hefty reject:
1725498683c6SMoni Shoua 	pr_debug_ratelimited("RDMA CM: CONNECT_ERROR: failed to handle reply. status %d\n", ret);
1726c5483388SSean Hefty 	cma_modify_qp_err(id_priv);
1727e51060f0SSean Hefty 	ib_send_cm_rej(id_priv->cm_id.ib, IB_CM_REJ_CONSUMER_DEFINED,
1728e51060f0SSean Hefty 		       NULL, 0, NULL, 0);
1729e51060f0SSean Hefty 	return ret;
1730e51060f0SSean Hefty }
1731e51060f0SSean Hefty 
1732a1b1b61fSSean Hefty static void cma_set_rep_event_data(struct rdma_cm_event *event,
1733a1b1b61fSSean Hefty 				   struct ib_cm_rep_event_param *rep_data,
1734a1b1b61fSSean Hefty 				   void *private_data)
1735a1b1b61fSSean Hefty {
1736a1b1b61fSSean Hefty 	event->param.conn.private_data = private_data;
1737a1b1b61fSSean Hefty 	event->param.conn.private_data_len = IB_CM_REP_PRIVATE_DATA_SIZE;
1738a1b1b61fSSean Hefty 	event->param.conn.responder_resources = rep_data->responder_resources;
1739a1b1b61fSSean Hefty 	event->param.conn.initiator_depth = rep_data->initiator_depth;
1740a1b1b61fSSean Hefty 	event->param.conn.flow_control = rep_data->flow_control;
1741a1b1b61fSSean Hefty 	event->param.conn.rnr_retry_count = rep_data->rnr_retry_count;
1742a1b1b61fSSean Hefty 	event->param.conn.srq = rep_data->srq;
1743a1b1b61fSSean Hefty 	event->param.conn.qp_num = rep_data->remote_qpn;
1744a1b1b61fSSean Hefty }
1745a1b1b61fSSean Hefty 
1746e51060f0SSean Hefty static int cma_ib_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
1747e51060f0SSean Hefty {
1748e51060f0SSean Hefty 	struct rdma_id_private *id_priv = cm_id->context;
1749a1b1b61fSSean Hefty 	struct rdma_cm_event event;
1750a1b1b61fSSean Hefty 	int ret = 0;
1751e51060f0SSean Hefty 
175237e07cdaSBart Van Assche 	mutex_lock(&id_priv->handler_mutex);
175338ca83a5SAmir Vadai 	if ((ib_event->event != IB_CM_TIMEWAIT_EXIT &&
175437e07cdaSBart Van Assche 	     id_priv->state != RDMA_CM_CONNECT) ||
175538ca83a5SAmir Vadai 	    (ib_event->event == IB_CM_TIMEWAIT_EXIT &&
175637e07cdaSBart Van Assche 	     id_priv->state != RDMA_CM_DISCONNECT))
175737e07cdaSBart Van Assche 		goto out;
1758e51060f0SSean Hefty 
1759a1b1b61fSSean Hefty 	memset(&event, 0, sizeof event);
1760e51060f0SSean Hefty 	switch (ib_event->event) {
1761e51060f0SSean Hefty 	case IB_CM_REQ_ERROR:
1762e51060f0SSean Hefty 	case IB_CM_REP_ERROR:
1763a1b1b61fSSean Hefty 		event.event = RDMA_CM_EVENT_UNREACHABLE;
1764a1b1b61fSSean Hefty 		event.status = -ETIMEDOUT;
1765e51060f0SSean Hefty 		break;
1766e51060f0SSean Hefty 	case IB_CM_REP_RECEIVED:
176761c0ddbeSMoni Shoua 		if (cma_comp(id_priv, RDMA_CM_CONNECT) &&
176861c0ddbeSMoni Shoua 		    (id_priv->id.qp_type != IB_QPT_UD))
176961c0ddbeSMoni Shoua 			ib_send_cm_mra(cm_id, CMA_CM_MRA_SETTING, NULL, 0);
177001602f11SSean Hefty 		if (id_priv->id.qp) {
1771a1b1b61fSSean Hefty 			event.status = cma_rep_recv(id_priv);
1772a1b1b61fSSean Hefty 			event.event = event.status ? RDMA_CM_EVENT_CONNECT_ERROR :
1773e51060f0SSean Hefty 						     RDMA_CM_EVENT_ESTABLISHED;
177401602f11SSean Hefty 		} else {
1775a1b1b61fSSean Hefty 			event.event = RDMA_CM_EVENT_CONNECT_RESPONSE;
177601602f11SSean Hefty 		}
1777a1b1b61fSSean Hefty 		cma_set_rep_event_data(&event, &ib_event->param.rep_rcvd,
1778a1b1b61fSSean Hefty 				       ib_event->private_data);
1779e51060f0SSean Hefty 		break;
1780e51060f0SSean Hefty 	case IB_CM_RTU_RECEIVED:
17810fe313b0SSean Hefty 	case IB_CM_USER_ESTABLISHED:
17820fe313b0SSean Hefty 		event.event = RDMA_CM_EVENT_ESTABLISHED;
1783e51060f0SSean Hefty 		break;
1784e51060f0SSean Hefty 	case IB_CM_DREQ_ERROR:
1785a1b1b61fSSean Hefty 		event.status = -ETIMEDOUT; /* fall through */
1786e51060f0SSean Hefty 	case IB_CM_DREQ_RECEIVED:
1787e51060f0SSean Hefty 	case IB_CM_DREP_RECEIVED:
1788550e5ca7SNir Muchtar 		if (!cma_comp_exch(id_priv, RDMA_CM_CONNECT,
1789550e5ca7SNir Muchtar 				   RDMA_CM_DISCONNECT))
1790e51060f0SSean Hefty 			goto out;
1791a1b1b61fSSean Hefty 		event.event = RDMA_CM_EVENT_DISCONNECTED;
1792e51060f0SSean Hefty 		break;
1793e51060f0SSean Hefty 	case IB_CM_TIMEWAIT_EXIT:
179438ca83a5SAmir Vadai 		event.event = RDMA_CM_EVENT_TIMEWAIT_EXIT;
179538ca83a5SAmir Vadai 		break;
1796e51060f0SSean Hefty 	case IB_CM_MRA_RECEIVED:
1797e51060f0SSean Hefty 		/* ignore event */
1798e51060f0SSean Hefty 		goto out;
1799e51060f0SSean Hefty 	case IB_CM_REJ_RECEIVED:
1800498683c6SMoni Shoua 		pr_debug_ratelimited("RDMA CM: REJECTED: %s\n", rdma_reject_msg(&id_priv->id,
1801498683c6SMoni Shoua 										ib_event->param.rej_rcvd.reason));
1802c5483388SSean Hefty 		cma_modify_qp_err(id_priv);
1803a1b1b61fSSean Hefty 		event.status = ib_event->param.rej_rcvd.reason;
1804a1b1b61fSSean Hefty 		event.event = RDMA_CM_EVENT_REJECTED;
1805a1b1b61fSSean Hefty 		event.param.conn.private_data = ib_event->private_data;
1806a1b1b61fSSean Hefty 		event.param.conn.private_data_len = IB_CM_REJ_PRIVATE_DATA_SIZE;
1807e51060f0SSean Hefty 		break;
1808e51060f0SSean Hefty 	default:
1809aba25a3eSParav Pandit 		pr_err("RDMA CMA: unexpected IB CM event: %d\n",
1810e51060f0SSean Hefty 		       ib_event->event);
1811e51060f0SSean Hefty 		goto out;
1812e51060f0SSean Hefty 	}
1813e51060f0SSean Hefty 
1814a1b1b61fSSean Hefty 	ret = id_priv->id.event_handler(&id_priv->id, &event);
1815e51060f0SSean Hefty 	if (ret) {
1816e51060f0SSean Hefty 		/* Destroy the CM ID by returning a non-zero value. */
1817e51060f0SSean Hefty 		id_priv->cm_id.ib = NULL;
1818550e5ca7SNir Muchtar 		cma_exch(id_priv, RDMA_CM_DESTROYING);
1819de910bd9SOr Gerlitz 		mutex_unlock(&id_priv->handler_mutex);
1820e51060f0SSean Hefty 		rdma_destroy_id(&id_priv->id);
1821e51060f0SSean Hefty 		return ret;
1822e51060f0SSean Hefty 	}
1823e51060f0SSean Hefty out:
1824de910bd9SOr Gerlitz 	mutex_unlock(&id_priv->handler_mutex);
1825e51060f0SSean Hefty 	return ret;
1826e51060f0SSean Hefty }
1827e51060f0SSean Hefty 
1828628e5f6dSSean Hefty static struct rdma_id_private *cma_new_conn_id(struct rdma_cm_id *listen_id,
18290b3ca768SHaggai Eran 					       struct ib_cm_event *ib_event,
18300b3ca768SHaggai Eran 					       struct net_device *net_dev)
1831e51060f0SSean Hefty {
183200313983SSteve Wise 	struct rdma_id_private *listen_id_priv;
1833e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
1834e51060f0SSean Hefty 	struct rdma_cm_id *id;
1835e51060f0SSean Hefty 	struct rdma_route *rt;
18360c505f70SHaggai Eran 	const sa_family_t ss_family = listen_id->route.addr.src_addr.ss_family;
18379fdca4daSDasaratharaman Chandramouli 	struct sa_path_rec *path = ib_event->param.req_rcvd.primary_path;
1838d3957b86SMajd Dibbiny 	const __be64 service_id =
1839d3957b86SMajd Dibbiny 		ib_event->param.req_rcvd.primary_path->service_id;
184064c5e613SOr Gerlitz 	int ret;
1841e51060f0SSean Hefty 
184200313983SSteve Wise 	listen_id_priv = container_of(listen_id, struct rdma_id_private, id);
184300313983SSteve Wise 	id = __rdma_create_id(listen_id->route.addr.dev_addr.net,
1844fa20105eSGuy Shapiro 			    listen_id->event_handler, listen_id->context,
184500313983SSteve Wise 			    listen_id->ps, ib_event->param.req_rcvd.qp_type,
184600313983SSteve Wise 			    listen_id_priv->res.kern_name);
18473f168d2bSKrishna Kumar 	if (IS_ERR(id))
18480c9361fcSJack Morgenstein 		return NULL;
18493f168d2bSKrishna Kumar 
1850f4753834SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
18510c505f70SHaggai Eran 	if (cma_save_net_info((struct sockaddr *)&id->route.addr.src_addr,
18520c505f70SHaggai Eran 			      (struct sockaddr *)&id->route.addr.dst_addr,
18530c505f70SHaggai Eran 			      listen_id, ib_event, ss_family, service_id))
1854fbaa1a6dSSean Hefty 		goto err;
18553f168d2bSKrishna Kumar 
18563f168d2bSKrishna Kumar 	rt = &id->route;
18573f168d2bSKrishna Kumar 	rt->num_paths = ib_event->param.req_rcvd.alternate_path ? 2 : 1;
1858*6da2ec56SKees Cook 	rt->path_rec = kmalloc_array(rt->num_paths, sizeof(*rt->path_rec),
18593f168d2bSKrishna Kumar 				     GFP_KERNEL);
18603f168d2bSKrishna Kumar 	if (!rt->path_rec)
18610c9361fcSJack Morgenstein 		goto err;
18623f168d2bSKrishna Kumar 
18639fdca4daSDasaratharaman Chandramouli 	rt->path_rec[0] = *path;
1864e51060f0SSean Hefty 	if (rt->num_paths == 2)
1865e51060f0SSean Hefty 		rt->path_rec[1] = *ib_event->param.req_rcvd.alternate_path;
1866e51060f0SSean Hefty 
18670b3ca768SHaggai Eran 	if (net_dev) {
1868e08ce2e8SYuval Shaia 		rdma_copy_addr(&rt->addr.dev_addr, net_dev, NULL);
18690b3ca768SHaggai Eran 	} else {
1870b8cab5daSHaggai Eran 		if (!cma_protocol_roce(listen_id) &&
1871b8cab5daSHaggai Eran 		    cma_any_addr(cma_src_addr(id_priv))) {
1872b8cab5daSHaggai Eran 			rt->addr.dev_addr.dev_type = ARPHRD_INFINIBAND;
1873b8cab5daSHaggai Eran 			rdma_addr_set_sgid(&rt->addr.dev_addr, &rt->path_rec[0].sgid);
1874b8cab5daSHaggai Eran 			ib_addr_set_pkey(&rt->addr.dev_addr, be16_to_cpu(rt->path_rec[0].pkey));
1875b8cab5daSHaggai Eran 		} else if (!cma_any_addr(cma_src_addr(id_priv))) {
1876b8cab5daSHaggai Eran 			ret = cma_translate_addr(cma_src_addr(id_priv), &rt->addr.dev_addr);
1877b8cab5daSHaggai Eran 			if (ret)
1878b8cab5daSHaggai Eran 				goto err;
1879b8cab5daSHaggai Eran 		}
18806f8372b6SSean Hefty 	}
18816f8372b6SSean Hefty 	rdma_addr_set_dgid(&rt->addr.dev_addr, &rt->path_rec[0].dgid);
1882e51060f0SSean Hefty 
1883550e5ca7SNir Muchtar 	id_priv->state = RDMA_CM_CONNECT;
1884e51060f0SSean Hefty 	return id_priv;
18853f168d2bSKrishna Kumar 
18863f168d2bSKrishna Kumar err:
18870c9361fcSJack Morgenstein 	rdma_destroy_id(id);
1888e51060f0SSean Hefty 	return NULL;
1889e51060f0SSean Hefty }
1890e51060f0SSean Hefty 
1891628e5f6dSSean Hefty static struct rdma_id_private *cma_new_udp_id(struct rdma_cm_id *listen_id,
18920b3ca768SHaggai Eran 					      struct ib_cm_event *ib_event,
18930b3ca768SHaggai Eran 					      struct net_device *net_dev)
1894628e5f6dSSean Hefty {
189500313983SSteve Wise 	struct rdma_id_private *listen_id_priv;
1896628e5f6dSSean Hefty 	struct rdma_id_private *id_priv;
1897628e5f6dSSean Hefty 	struct rdma_cm_id *id;
18980c505f70SHaggai Eran 	const sa_family_t ss_family = listen_id->route.addr.src_addr.ss_family;
1899fa20105eSGuy Shapiro 	struct net *net = listen_id->route.addr.dev_addr.net;
1900628e5f6dSSean Hefty 	int ret;
1901628e5f6dSSean Hefty 
190200313983SSteve Wise 	listen_id_priv = container_of(listen_id, struct rdma_id_private, id);
190300313983SSteve Wise 	id = __rdma_create_id(net, listen_id->event_handler, listen_id->context,
190400313983SSteve Wise 			      listen_id->ps, IB_QPT_UD,
190500313983SSteve Wise 			      listen_id_priv->res.kern_name);
1906628e5f6dSSean Hefty 	if (IS_ERR(id))
1907628e5f6dSSean Hefty 		return NULL;
1908628e5f6dSSean Hefty 
1909f4753834SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
19100c505f70SHaggai Eran 	if (cma_save_net_info((struct sockaddr *)&id->route.addr.src_addr,
19110c505f70SHaggai Eran 			      (struct sockaddr *)&id->route.addr.dst_addr,
19120c505f70SHaggai Eran 			      listen_id, ib_event, ss_family,
19130c505f70SHaggai Eran 			      ib_event->param.sidr_req_rcvd.service_id))
1914628e5f6dSSean Hefty 		goto err;
1915628e5f6dSSean Hefty 
19160b3ca768SHaggai Eran 	if (net_dev) {
1917e08ce2e8SYuval Shaia 		rdma_copy_addr(&id->route.addr.dev_addr, net_dev, NULL);
19180b3ca768SHaggai Eran 	} else {
1919b8cab5daSHaggai Eran 		if (!cma_any_addr(cma_src_addr(id_priv))) {
1920b8cab5daSHaggai Eran 			ret = cma_translate_addr(cma_src_addr(id_priv),
19210b3ca768SHaggai Eran 						 &id->route.addr.dev_addr);
1922b8cab5daSHaggai Eran 			if (ret)
1923b8cab5daSHaggai Eran 				goto err;
1924b8cab5daSHaggai Eran 		}
19256f8372b6SSean Hefty 	}
1926628e5f6dSSean Hefty 
1927550e5ca7SNir Muchtar 	id_priv->state = RDMA_CM_CONNECT;
1928628e5f6dSSean Hefty 	return id_priv;
1929628e5f6dSSean Hefty err:
1930628e5f6dSSean Hefty 	rdma_destroy_id(id);
1931628e5f6dSSean Hefty 	return NULL;
1932628e5f6dSSean Hefty }
1933628e5f6dSSean Hefty 
1934a1b1b61fSSean Hefty static void cma_set_req_event_data(struct rdma_cm_event *event,
1935a1b1b61fSSean Hefty 				   struct ib_cm_req_event_param *req_data,
1936a1b1b61fSSean Hefty 				   void *private_data, int offset)
1937a1b1b61fSSean Hefty {
1938a1b1b61fSSean Hefty 	event->param.conn.private_data = private_data + offset;
1939a1b1b61fSSean Hefty 	event->param.conn.private_data_len = IB_CM_REQ_PRIVATE_DATA_SIZE - offset;
1940a1b1b61fSSean Hefty 	event->param.conn.responder_resources = req_data->responder_resources;
1941a1b1b61fSSean Hefty 	event->param.conn.initiator_depth = req_data->initiator_depth;
1942a1b1b61fSSean Hefty 	event->param.conn.flow_control = req_data->flow_control;
1943a1b1b61fSSean Hefty 	event->param.conn.retry_count = req_data->retry_count;
1944a1b1b61fSSean Hefty 	event->param.conn.rnr_retry_count = req_data->rnr_retry_count;
1945a1b1b61fSSean Hefty 	event->param.conn.srq = req_data->srq;
1946a1b1b61fSSean Hefty 	event->param.conn.qp_num = req_data->remote_qpn;
1947a1b1b61fSSean Hefty }
1948a1b1b61fSSean Hefty 
19499595480cSHefty, Sean static int cma_check_req_qp_type(struct rdma_cm_id *id, struct ib_cm_event *ib_event)
19509595480cSHefty, Sean {
19514dd81e89SSean Hefty 	return (((ib_event->event == IB_CM_REQ_RECEIVED) &&
19529595480cSHefty, Sean 		 (ib_event->param.req_rcvd.qp_type == id->qp_type)) ||
19539595480cSHefty, Sean 		((ib_event->event == IB_CM_SIDR_REQ_RECEIVED) &&
19549595480cSHefty, Sean 		 (id->qp_type == IB_QPT_UD)) ||
19559595480cSHefty, Sean 		(!id->qp_type));
19569595480cSHefty, Sean }
19579595480cSHefty, Sean 
1958e51060f0SSean Hefty static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
1959e51060f0SSean Hefty {
196037e07cdaSBart Van Assche 	struct rdma_id_private *listen_id, *conn_id = NULL;
1961a1b1b61fSSean Hefty 	struct rdma_cm_event event;
19620b3ca768SHaggai Eran 	struct net_device *net_dev;
1963c0b64f58SBart Van Assche 	u8 offset;
1964c0b64f58SBart Van Assche 	int ret;
1965e51060f0SSean Hefty 
19660b3ca768SHaggai Eran 	listen_id = cma_id_from_event(cm_id, ib_event, &net_dev);
19674c21b5bcSHaggai Eran 	if (IS_ERR(listen_id))
19684c21b5bcSHaggai Eran 		return PTR_ERR(listen_id);
19694c21b5bcSHaggai Eran 
19700b3ca768SHaggai Eran 	if (!cma_check_req_qp_type(&listen_id->id, ib_event)) {
19710b3ca768SHaggai Eran 		ret = -EINVAL;
19720b3ca768SHaggai Eran 		goto net_dev_put;
19730b3ca768SHaggai Eran 	}
19749595480cSHefty, Sean 
197537e07cdaSBart Van Assche 	mutex_lock(&listen_id->handler_mutex);
197637e07cdaSBart Van Assche 	if (listen_id->state != RDMA_CM_LISTEN) {
19770b3ca768SHaggai Eran 		ret = -ECONNABORTED;
197837e07cdaSBart Van Assche 		goto err1;
19790b3ca768SHaggai Eran 	}
1980e51060f0SSean Hefty 
1981628e5f6dSSean Hefty 	memset(&event, 0, sizeof event);
1982e8160e15SSean Hefty 	offset = cma_user_data_offset(listen_id);
1983628e5f6dSSean Hefty 	event.event = RDMA_CM_EVENT_CONNECT_REQUEST;
19849595480cSHefty, Sean 	if (ib_event->event == IB_CM_SIDR_REQ_RECEIVED) {
19850b3ca768SHaggai Eran 		conn_id = cma_new_udp_id(&listen_id->id, ib_event, net_dev);
1986628e5f6dSSean Hefty 		event.param.ud.private_data = ib_event->private_data + offset;
1987628e5f6dSSean Hefty 		event.param.ud.private_data_len =
1988628e5f6dSSean Hefty 				IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE - offset;
1989628e5f6dSSean Hefty 	} else {
19900b3ca768SHaggai Eran 		conn_id = cma_new_conn_id(&listen_id->id, ib_event, net_dev);
1991628e5f6dSSean Hefty 		cma_set_req_event_data(&event, &ib_event->param.req_rcvd,
1992628e5f6dSSean Hefty 				       ib_event->private_data, offset);
1993628e5f6dSSean Hefty 	}
1994e51060f0SSean Hefty 	if (!conn_id) {
1995e51060f0SSean Hefty 		ret = -ENOMEM;
1996b6cec8aaSSean Hefty 		goto err1;
1997e51060f0SSean Hefty 	}
1998e51060f0SSean Hefty 
1999de910bd9SOr Gerlitz 	mutex_lock_nested(&conn_id->handler_mutex, SINGLE_DEPTH_NESTING);
2000be9130ccSDoug Ledford 	ret = cma_acquire_dev(conn_id, listen_id);
2001a1a733f6SKrishna Kumar 	if (ret)
2002b6cec8aaSSean Hefty 		goto err2;
2003e51060f0SSean Hefty 
2004e51060f0SSean Hefty 	conn_id->cm_id.ib = cm_id;
2005e51060f0SSean Hefty 	cm_id->context = conn_id;
2006e51060f0SSean Hefty 	cm_id->cm_handler = cma_ib_handler;
2007e51060f0SSean Hefty 
200825ae21a1SSean Hefty 	/*
200925ae21a1SSean Hefty 	 * Protect against the user destroying conn_id from another thread
201025ae21a1SSean Hefty 	 * until we're done accessing it.
201125ae21a1SSean Hefty 	 */
201225ae21a1SSean Hefty 	atomic_inc(&conn_id->refcount);
2013a1b1b61fSSean Hefty 	ret = conn_id->id.event_handler(&conn_id->id, &event);
2014b6cec8aaSSean Hefty 	if (ret)
2015b6cec8aaSSean Hefty 		goto err3;
2016ead595aeSSean Hefty 	/*
2017ead595aeSSean Hefty 	 * Acquire mutex to prevent user executing rdma_destroy_id()
2018ead595aeSSean Hefty 	 * while we're accessing the cm_id.
2019ead595aeSSean Hefty 	 */
2020ead595aeSSean Hefty 	mutex_lock(&lock);
2021dd5f03beSMatan Barak 	if (cma_comp(conn_id, RDMA_CM_CONNECT) &&
2022dd5f03beSMatan Barak 	    (conn_id->id.qp_type != IB_QPT_UD))
2023ead595aeSSean Hefty 		ib_send_cm_mra(cm_id, CMA_CM_MRA_SETTING, NULL, 0);
2024ead595aeSSean Hefty 	mutex_unlock(&lock);
2025de910bd9SOr Gerlitz 	mutex_unlock(&conn_id->handler_mutex);
2026b6cec8aaSSean Hefty 	mutex_unlock(&listen_id->handler_mutex);
202725ae21a1SSean Hefty 	cma_deref_id(conn_id);
20280b3ca768SHaggai Eran 	if (net_dev)
20290b3ca768SHaggai Eran 		dev_put(net_dev);
2030b6cec8aaSSean Hefty 	return 0;
2031a1a733f6SKrishna Kumar 
2032b6cec8aaSSean Hefty err3:
2033b6cec8aaSSean Hefty 	cma_deref_id(conn_id);
2034e51060f0SSean Hefty 	/* Destroy the CM ID by returning a non-zero value. */
2035e51060f0SSean Hefty 	conn_id->cm_id.ib = NULL;
2036b6cec8aaSSean Hefty err2:
2037550e5ca7SNir Muchtar 	cma_exch(conn_id, RDMA_CM_DESTROYING);
2038de910bd9SOr Gerlitz 	mutex_unlock(&conn_id->handler_mutex);
2039b6cec8aaSSean Hefty err1:
2040de910bd9SOr Gerlitz 	mutex_unlock(&listen_id->handler_mutex);
2041b6cec8aaSSean Hefty 	if (conn_id)
2042b6cec8aaSSean Hefty 		rdma_destroy_id(&conn_id->id);
20430b3ca768SHaggai Eran 
20440b3ca768SHaggai Eran net_dev_put:
20450b3ca768SHaggai Eran 	if (net_dev)
20460b3ca768SHaggai Eran 		dev_put(net_dev);
20470b3ca768SHaggai Eran 
2048e51060f0SSean Hefty 	return ret;
2049e51060f0SSean Hefty }
2050e51060f0SSean Hefty 
2051cf53936fSSean Hefty __be64 rdma_get_service_id(struct rdma_cm_id *id, struct sockaddr *addr)
2052e51060f0SSean Hefty {
2053496ce3ceSSean Hefty 	if (addr->sa_family == AF_IB)
2054496ce3ceSSean Hefty 		return ((struct sockaddr_ib *) addr)->sib_sid;
2055496ce3ceSSean Hefty 
2056cf53936fSSean Hefty 	return cpu_to_be64(((u64)id->ps << 16) + be16_to_cpu(cma_port(addr)));
2057e51060f0SSean Hefty }
2058cf53936fSSean Hefty EXPORT_SYMBOL(rdma_get_service_id);
2059e51060f0SSean Hefty 
2060411460acSParav Pandit void rdma_read_gids(struct rdma_cm_id *cm_id, union ib_gid *sgid,
2061411460acSParav Pandit 		    union ib_gid *dgid)
2062411460acSParav Pandit {
2063411460acSParav Pandit 	struct rdma_addr *addr = &cm_id->route.addr;
2064411460acSParav Pandit 
2065411460acSParav Pandit 	if (!cm_id->device) {
2066411460acSParav Pandit 		if (sgid)
2067411460acSParav Pandit 			memset(sgid, 0, sizeof(*sgid));
2068411460acSParav Pandit 		if (dgid)
2069411460acSParav Pandit 			memset(dgid, 0, sizeof(*dgid));
2070411460acSParav Pandit 		return;
2071411460acSParav Pandit 	}
2072411460acSParav Pandit 
2073411460acSParav Pandit 	if (rdma_protocol_roce(cm_id->device, cm_id->port_num)) {
2074411460acSParav Pandit 		if (sgid)
2075411460acSParav Pandit 			rdma_ip2gid((struct sockaddr *)&addr->src_addr, sgid);
2076411460acSParav Pandit 		if (dgid)
2077411460acSParav Pandit 			rdma_ip2gid((struct sockaddr *)&addr->dst_addr, dgid);
2078411460acSParav Pandit 	} else {
2079411460acSParav Pandit 		if (sgid)
2080411460acSParav Pandit 			rdma_addr_get_sgid(&addr->dev_addr, sgid);
2081411460acSParav Pandit 		if (dgid)
2082411460acSParav Pandit 			rdma_addr_get_dgid(&addr->dev_addr, dgid);
2083411460acSParav Pandit 	}
2084411460acSParav Pandit }
2085411460acSParav Pandit EXPORT_SYMBOL(rdma_read_gids);
2086411460acSParav Pandit 
208707ebafbaSTom Tucker static int cma_iw_handler(struct iw_cm_id *iw_id, struct iw_cm_event *iw_event)
208807ebafbaSTom Tucker {
208907ebafbaSTom Tucker 	struct rdma_id_private *id_priv = iw_id->context;
2090a1b1b61fSSean Hefty 	struct rdma_cm_event event;
209107ebafbaSTom Tucker 	int ret = 0;
209224d44a39SSteve Wise 	struct sockaddr *laddr = (struct sockaddr *)&iw_event->local_addr;
209324d44a39SSteve Wise 	struct sockaddr *raddr = (struct sockaddr *)&iw_event->remote_addr;
209407ebafbaSTom Tucker 
209537e07cdaSBart Van Assche 	mutex_lock(&id_priv->handler_mutex);
209637e07cdaSBart Van Assche 	if (id_priv->state != RDMA_CM_CONNECT)
209737e07cdaSBart Van Assche 		goto out;
209807ebafbaSTom Tucker 
2099be65f086SSean Hefty 	memset(&event, 0, sizeof event);
210007ebafbaSTom Tucker 	switch (iw_event->event) {
210107ebafbaSTom Tucker 	case IW_CM_EVENT_CLOSE:
2102a1b1b61fSSean Hefty 		event.event = RDMA_CM_EVENT_DISCONNECTED;
210307ebafbaSTom Tucker 		break;
210407ebafbaSTom Tucker 	case IW_CM_EVENT_CONNECT_REPLY:
210524d44a39SSteve Wise 		memcpy(cma_src_addr(id_priv), laddr,
210624d44a39SSteve Wise 		       rdma_addr_size(laddr));
210724d44a39SSteve Wise 		memcpy(cma_dst_addr(id_priv), raddr,
210824d44a39SSteve Wise 		       rdma_addr_size(raddr));
2109881a045fSSteve Wise 		switch (iw_event->status) {
2110881a045fSSteve Wise 		case 0:
2111a1b1b61fSSean Hefty 			event.event = RDMA_CM_EVENT_ESTABLISHED;
21123ebeebc3SKumar Sanghvi 			event.param.conn.initiator_depth = iw_event->ird;
21133ebeebc3SKumar Sanghvi 			event.param.conn.responder_resources = iw_event->ord;
211407ebafbaSTom Tucker 			break;
2115881a045fSSteve Wise 		case -ECONNRESET:
2116881a045fSSteve Wise 		case -ECONNREFUSED:
2117881a045fSSteve Wise 			event.event = RDMA_CM_EVENT_REJECTED;
2118881a045fSSteve Wise 			break;
2119881a045fSSteve Wise 		case -ETIMEDOUT:
2120881a045fSSteve Wise 			event.event = RDMA_CM_EVENT_UNREACHABLE;
2121881a045fSSteve Wise 			break;
2122881a045fSSteve Wise 		default:
2123881a045fSSteve Wise 			event.event = RDMA_CM_EVENT_CONNECT_ERROR;
2124881a045fSSteve Wise 			break;
2125881a045fSSteve Wise 		}
2126881a045fSSteve Wise 		break;
212707ebafbaSTom Tucker 	case IW_CM_EVENT_ESTABLISHED:
2128a1b1b61fSSean Hefty 		event.event = RDMA_CM_EVENT_ESTABLISHED;
21293ebeebc3SKumar Sanghvi 		event.param.conn.initiator_depth = iw_event->ird;
21303ebeebc3SKumar Sanghvi 		event.param.conn.responder_resources = iw_event->ord;
213107ebafbaSTom Tucker 		break;
213207ebafbaSTom Tucker 	default:
2133671a6cc2SLeon Romanovsky 		goto out;
213407ebafbaSTom Tucker 	}
213507ebafbaSTom Tucker 
2136a1b1b61fSSean Hefty 	event.status = iw_event->status;
2137a1b1b61fSSean Hefty 	event.param.conn.private_data = iw_event->private_data;
2138a1b1b61fSSean Hefty 	event.param.conn.private_data_len = iw_event->private_data_len;
2139a1b1b61fSSean Hefty 	ret = id_priv->id.event_handler(&id_priv->id, &event);
214007ebafbaSTom Tucker 	if (ret) {
214107ebafbaSTom Tucker 		/* Destroy the CM ID by returning a non-zero value. */
214207ebafbaSTom Tucker 		id_priv->cm_id.iw = NULL;
2143550e5ca7SNir Muchtar 		cma_exch(id_priv, RDMA_CM_DESTROYING);
2144de910bd9SOr Gerlitz 		mutex_unlock(&id_priv->handler_mutex);
214507ebafbaSTom Tucker 		rdma_destroy_id(&id_priv->id);
214607ebafbaSTom Tucker 		return ret;
214707ebafbaSTom Tucker 	}
214807ebafbaSTom Tucker 
214937e07cdaSBart Van Assche out:
2150de910bd9SOr Gerlitz 	mutex_unlock(&id_priv->handler_mutex);
215107ebafbaSTom Tucker 	return ret;
215207ebafbaSTom Tucker }
215307ebafbaSTom Tucker 
215407ebafbaSTom Tucker static int iw_conn_req_handler(struct iw_cm_id *cm_id,
215507ebafbaSTom Tucker 			       struct iw_cm_event *iw_event)
215607ebafbaSTom Tucker {
215707ebafbaSTom Tucker 	struct rdma_cm_id *new_cm_id;
215807ebafbaSTom Tucker 	struct rdma_id_private *listen_id, *conn_id;
2159a1b1b61fSSean Hefty 	struct rdma_cm_event event;
216037e07cdaSBart Van Assche 	int ret = -ECONNABORTED;
216124d44a39SSteve Wise 	struct sockaddr *laddr = (struct sockaddr *)&iw_event->local_addr;
216224d44a39SSteve Wise 	struct sockaddr *raddr = (struct sockaddr *)&iw_event->remote_addr;
216307ebafbaSTom Tucker 
216407ebafbaSTom Tucker 	listen_id = cm_id->context;
216537e07cdaSBart Van Assche 
216637e07cdaSBart Van Assche 	mutex_lock(&listen_id->handler_mutex);
216737e07cdaSBart Van Assche 	if (listen_id->state != RDMA_CM_LISTEN)
216837e07cdaSBart Van Assche 		goto out;
216907ebafbaSTom Tucker 
217007ebafbaSTom Tucker 	/* Create a new RDMA id for the new IW CM ID */
217100313983SSteve Wise 	new_cm_id = __rdma_create_id(listen_id->id.route.addr.dev_addr.net,
2172fa20105eSGuy Shapiro 				     listen_id->id.event_handler,
217307ebafbaSTom Tucker 				     listen_id->id.context,
217400313983SSteve Wise 				     RDMA_PS_TCP, IB_QPT_RC,
217500313983SSteve Wise 				     listen_id->res.kern_name);
217610f32065SJulia Lawall 	if (IS_ERR(new_cm_id)) {
217707ebafbaSTom Tucker 		ret = -ENOMEM;
217807ebafbaSTom Tucker 		goto out;
217907ebafbaSTom Tucker 	}
218007ebafbaSTom Tucker 	conn_id = container_of(new_cm_id, struct rdma_id_private, id);
2181de910bd9SOr Gerlitz 	mutex_lock_nested(&conn_id->handler_mutex, SINGLE_DEPTH_NESTING);
2182550e5ca7SNir Muchtar 	conn_id->state = RDMA_CM_CONNECT;
218307ebafbaSTom Tucker 
2184575c7e58SParav Pandit 	ret = rdma_translate_ip(laddr, &conn_id->id.route.addr.dev_addr);
218507ebafbaSTom Tucker 	if (ret) {
2186de910bd9SOr Gerlitz 		mutex_unlock(&conn_id->handler_mutex);
218707ebafbaSTom Tucker 		rdma_destroy_id(new_cm_id);
218807ebafbaSTom Tucker 		goto out;
218907ebafbaSTom Tucker 	}
219007ebafbaSTom Tucker 
2191be9130ccSDoug Ledford 	ret = cma_acquire_dev(conn_id, listen_id);
219207ebafbaSTom Tucker 	if (ret) {
2193de910bd9SOr Gerlitz 		mutex_unlock(&conn_id->handler_mutex);
219407ebafbaSTom Tucker 		rdma_destroy_id(new_cm_id);
219507ebafbaSTom Tucker 		goto out;
219607ebafbaSTom Tucker 	}
219707ebafbaSTom Tucker 
219807ebafbaSTom Tucker 	conn_id->cm_id.iw = cm_id;
219907ebafbaSTom Tucker 	cm_id->context = conn_id;
220007ebafbaSTom Tucker 	cm_id->cm_handler = cma_iw_handler;
220107ebafbaSTom Tucker 
220224d44a39SSteve Wise 	memcpy(cma_src_addr(conn_id), laddr, rdma_addr_size(laddr));
220324d44a39SSteve Wise 	memcpy(cma_dst_addr(conn_id), raddr, rdma_addr_size(raddr));
220407ebafbaSTom Tucker 
2205a1b1b61fSSean Hefty 	memset(&event, 0, sizeof event);
2206a1b1b61fSSean Hefty 	event.event = RDMA_CM_EVENT_CONNECT_REQUEST;
2207a1b1b61fSSean Hefty 	event.param.conn.private_data = iw_event->private_data;
2208a1b1b61fSSean Hefty 	event.param.conn.private_data_len = iw_event->private_data_len;
22093ebeebc3SKumar Sanghvi 	event.param.conn.initiator_depth = iw_event->ird;
22103ebeebc3SKumar Sanghvi 	event.param.conn.responder_resources = iw_event->ord;
221125ae21a1SSean Hefty 
221225ae21a1SSean Hefty 	/*
221325ae21a1SSean Hefty 	 * Protect against the user destroying conn_id from another thread
221425ae21a1SSean Hefty 	 * until we're done accessing it.
221525ae21a1SSean Hefty 	 */
221625ae21a1SSean Hefty 	atomic_inc(&conn_id->refcount);
2217a1b1b61fSSean Hefty 	ret = conn_id->id.event_handler(&conn_id->id, &event);
221807ebafbaSTom Tucker 	if (ret) {
221907ebafbaSTom Tucker 		/* User wants to destroy the CM ID */
222007ebafbaSTom Tucker 		conn_id->cm_id.iw = NULL;
2221550e5ca7SNir Muchtar 		cma_exch(conn_id, RDMA_CM_DESTROYING);
2222de910bd9SOr Gerlitz 		mutex_unlock(&conn_id->handler_mutex);
222325ae21a1SSean Hefty 		cma_deref_id(conn_id);
222407ebafbaSTom Tucker 		rdma_destroy_id(&conn_id->id);
2225de910bd9SOr Gerlitz 		goto out;
222607ebafbaSTom Tucker 	}
222707ebafbaSTom Tucker 
2228de910bd9SOr Gerlitz 	mutex_unlock(&conn_id->handler_mutex);
222925ae21a1SSean Hefty 	cma_deref_id(conn_id);
2230de910bd9SOr Gerlitz 
223107ebafbaSTom Tucker out:
2232de910bd9SOr Gerlitz 	mutex_unlock(&listen_id->handler_mutex);
223307ebafbaSTom Tucker 	return ret;
223407ebafbaSTom Tucker }
223507ebafbaSTom Tucker 
2236e51060f0SSean Hefty static int cma_ib_listen(struct rdma_id_private *id_priv)
2237e51060f0SSean Hefty {
2238e51060f0SSean Hefty 	struct sockaddr *addr;
22390c9361fcSJack Morgenstein 	struct ib_cm_id	*id;
2240e51060f0SSean Hefty 	__be64 svc_id;
2241e51060f0SSean Hefty 
2242f4753834SSean Hefty 	addr = cma_src_addr(id_priv);
2243cf53936fSSean Hefty 	svc_id = rdma_get_service_id(&id_priv->id, addr);
224451efe394SHaggai Eran 	id = ib_cm_insert_listen(id_priv->id.device, cma_req_handler, svc_id);
224551efe394SHaggai Eran 	if (IS_ERR(id))
224651efe394SHaggai Eran 		return PTR_ERR(id);
224751efe394SHaggai Eran 	id_priv->cm_id.ib = id;
2248e51060f0SSean Hefty 
224951efe394SHaggai Eran 	return 0;
2250e51060f0SSean Hefty }
2251e51060f0SSean Hefty 
225207ebafbaSTom Tucker static int cma_iw_listen(struct rdma_id_private *id_priv, int backlog)
225307ebafbaSTom Tucker {
225407ebafbaSTom Tucker 	int ret;
22550c9361fcSJack Morgenstein 	struct iw_cm_id	*id;
225607ebafbaSTom Tucker 
22570c9361fcSJack Morgenstein 	id = iw_create_cm_id(id_priv->id.device,
225807ebafbaSTom Tucker 			     iw_conn_req_handler,
225907ebafbaSTom Tucker 			     id_priv);
22600c9361fcSJack Morgenstein 	if (IS_ERR(id))
22610c9361fcSJack Morgenstein 		return PTR_ERR(id);
22620c9361fcSJack Morgenstein 
226368cdba06SSteve Wise 	id->tos = id_priv->tos;
22640c9361fcSJack Morgenstein 	id_priv->cm_id.iw = id;
226507ebafbaSTom Tucker 
226624d44a39SSteve Wise 	memcpy(&id_priv->cm_id.iw->local_addr, cma_src_addr(id_priv),
226724d44a39SSteve Wise 	       rdma_addr_size(cma_src_addr(id_priv)));
226807ebafbaSTom Tucker 
226907ebafbaSTom Tucker 	ret = iw_cm_listen(id_priv->cm_id.iw, backlog);
227007ebafbaSTom Tucker 
227107ebafbaSTom Tucker 	if (ret) {
227207ebafbaSTom Tucker 		iw_destroy_cm_id(id_priv->cm_id.iw);
227307ebafbaSTom Tucker 		id_priv->cm_id.iw = NULL;
227407ebafbaSTom Tucker 	}
227507ebafbaSTom Tucker 
227607ebafbaSTom Tucker 	return ret;
227707ebafbaSTom Tucker }
227807ebafbaSTom Tucker 
2279e51060f0SSean Hefty static int cma_listen_handler(struct rdma_cm_id *id,
2280e51060f0SSean Hefty 			      struct rdma_cm_event *event)
2281e51060f0SSean Hefty {
2282e51060f0SSean Hefty 	struct rdma_id_private *id_priv = id->context;
2283e51060f0SSean Hefty 
2284e51060f0SSean Hefty 	id->context = id_priv->id.context;
2285e51060f0SSean Hefty 	id->event_handler = id_priv->id.event_handler;
2286e51060f0SSean Hefty 	return id_priv->id.event_handler(id, event);
2287e51060f0SSean Hefty }
2288e51060f0SSean Hefty 
2289e51060f0SSean Hefty static void cma_listen_on_dev(struct rdma_id_private *id_priv,
2290e51060f0SSean Hefty 			      struct cma_device *cma_dev)
2291e51060f0SSean Hefty {
2292e51060f0SSean Hefty 	struct rdma_id_private *dev_id_priv;
2293e51060f0SSean Hefty 	struct rdma_cm_id *id;
2294fa20105eSGuy Shapiro 	struct net *net = id_priv->id.route.addr.dev_addr.net;
2295e51060f0SSean Hefty 	int ret;
2296e51060f0SSean Hefty 
229772219ceaSMichael Wang 	if (cma_family(id_priv) == AF_IB && !rdma_cap_ib_cm(cma_dev->device, 1))
229894d0c939SSean Hefty 		return;
229994d0c939SSean Hefty 
230000313983SSteve Wise 	id = __rdma_create_id(net, cma_listen_handler, id_priv, id_priv->id.ps,
230100313983SSteve Wise 			      id_priv->id.qp_type, id_priv->res.kern_name);
2302e51060f0SSean Hefty 	if (IS_ERR(id))
2303e51060f0SSean Hefty 		return;
2304e51060f0SSean Hefty 
2305e51060f0SSean Hefty 	dev_id_priv = container_of(id, struct rdma_id_private, id);
2306e51060f0SSean Hefty 
2307550e5ca7SNir Muchtar 	dev_id_priv->state = RDMA_CM_ADDR_BOUND;
2308f4753834SSean Hefty 	memcpy(cma_src_addr(dev_id_priv), cma_src_addr(id_priv),
2309f4753834SSean Hefty 	       rdma_addr_size(cma_src_addr(id_priv)));
2310e51060f0SSean Hefty 
2311045959dbSMatan Barak 	_cma_attach_to_dev(dev_id_priv, cma_dev);
2312e51060f0SSean Hefty 	list_add_tail(&dev_id_priv->listen_list, &id_priv->listen_list);
2313d02d1f53SSean Hefty 	atomic_inc(&id_priv->refcount);
2314d02d1f53SSean Hefty 	dev_id_priv->internal_id = 1;
23155b0ec991SSean Hefty 	dev_id_priv->afonly = id_priv->afonly;
2316e51060f0SSean Hefty 
2317e51060f0SSean Hefty 	ret = rdma_listen(id, id_priv->backlog);
2318e51060f0SSean Hefty 	if (ret)
2319aba25a3eSParav Pandit 		pr_warn("RDMA CMA: cma_listen_on_dev, error %d, listening on device %s\n",
2320aba25a3eSParav Pandit 			ret, cma_dev->device->name);
2321e51060f0SSean Hefty }
2322e51060f0SSean Hefty 
2323e51060f0SSean Hefty static void cma_listen_on_all(struct rdma_id_private *id_priv)
2324e51060f0SSean Hefty {
2325e51060f0SSean Hefty 	struct cma_device *cma_dev;
2326e51060f0SSean Hefty 
2327e51060f0SSean Hefty 	mutex_lock(&lock);
2328e51060f0SSean Hefty 	list_add_tail(&id_priv->list, &listen_any_list);
2329e51060f0SSean Hefty 	list_for_each_entry(cma_dev, &dev_list, list)
2330e51060f0SSean Hefty 		cma_listen_on_dev(id_priv, cma_dev);
2331e51060f0SSean Hefty 	mutex_unlock(&lock);
2332e51060f0SSean Hefty }
2333e51060f0SSean Hefty 
2334a81c994dSSean Hefty void rdma_set_service_type(struct rdma_cm_id *id, int tos)
2335a81c994dSSean Hefty {
2336a81c994dSSean Hefty 	struct rdma_id_private *id_priv;
2337a81c994dSSean Hefty 
2338a81c994dSSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
2339a81c994dSSean Hefty 	id_priv->tos = (u8) tos;
234089052d78SMajd Dibbiny 	id_priv->tos_set = true;
2341a81c994dSSean Hefty }
2342a81c994dSSean Hefty EXPORT_SYMBOL(rdma_set_service_type);
2343a81c994dSSean Hefty 
2344c2f8fc4eSDasaratharaman Chandramouli static void cma_query_handler(int status, struct sa_path_rec *path_rec,
2345e51060f0SSean Hefty 			      void *context)
2346e51060f0SSean Hefty {
2347e51060f0SSean Hefty 	struct cma_work *work = context;
2348e51060f0SSean Hefty 	struct rdma_route *route;
2349e51060f0SSean Hefty 
2350e51060f0SSean Hefty 	route = &work->id->id.route;
2351e51060f0SSean Hefty 
2352e51060f0SSean Hefty 	if (!status) {
2353e51060f0SSean Hefty 		route->num_paths = 1;
2354e51060f0SSean Hefty 		*route->path_rec = *path_rec;
2355e51060f0SSean Hefty 	} else {
2356550e5ca7SNir Muchtar 		work->old_state = RDMA_CM_ROUTE_QUERY;
2357550e5ca7SNir Muchtar 		work->new_state = RDMA_CM_ADDR_RESOLVED;
2358e51060f0SSean Hefty 		work->event.event = RDMA_CM_EVENT_ROUTE_ERROR;
23598f0472d3SSean Hefty 		work->event.status = status;
2360498683c6SMoni Shoua 		pr_debug_ratelimited("RDMA CM: ROUTE_ERROR: failed to query path. status %d\n",
2361498683c6SMoni Shoua 				     status);
2362e51060f0SSean Hefty 	}
2363e51060f0SSean Hefty 
2364e51060f0SSean Hefty 	queue_work(cma_wq, &work->work);
2365e51060f0SSean Hefty }
2366e51060f0SSean Hefty 
2367e51060f0SSean Hefty static int cma_query_ib_route(struct rdma_id_private *id_priv, int timeout_ms,
2368e51060f0SSean Hefty 			      struct cma_work *work)
2369e51060f0SSean Hefty {
2370f4753834SSean Hefty 	struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
2371c2f8fc4eSDasaratharaman Chandramouli 	struct sa_path_rec path_rec;
2372a81c994dSSean Hefty 	ib_sa_comp_mask comp_mask;
2373a81c994dSSean Hefty 	struct sockaddr_in6 *sin6;
2374f68194caSSean Hefty 	struct sockaddr_ib *sib;
2375e51060f0SSean Hefty 
2376e51060f0SSean Hefty 	memset(&path_rec, 0, sizeof path_rec);
23774c33bd19SDasaratharaman Chandramouli 
23784c33bd19SDasaratharaman Chandramouli 	if (rdma_cap_opa_ah(id_priv->id.device, id_priv->id.port_num))
23794c33bd19SDasaratharaman Chandramouli 		path_rec.rec_type = SA_PATH_REC_TYPE_OPA;
23804c33bd19SDasaratharaman Chandramouli 	else
23819fdca4daSDasaratharaman Chandramouli 		path_rec.rec_type = SA_PATH_REC_TYPE_IB;
2382f4753834SSean Hefty 	rdma_addr_get_sgid(dev_addr, &path_rec.sgid);
2383f4753834SSean Hefty 	rdma_addr_get_dgid(dev_addr, &path_rec.dgid);
2384f4753834SSean Hefty 	path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr));
2385e51060f0SSean Hefty 	path_rec.numb_path = 1;
2386962063e6SSean Hefty 	path_rec.reversible = 1;
2387d3957b86SMajd Dibbiny 	path_rec.service_id = rdma_get_service_id(&id_priv->id,
2388d3957b86SMajd Dibbiny 						  cma_dst_addr(id_priv));
2389a81c994dSSean Hefty 
2390a81c994dSSean Hefty 	comp_mask = IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID |
2391a81c994dSSean Hefty 		    IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH |
2392a81c994dSSean Hefty 		    IB_SA_PATH_REC_REVERSIBLE | IB_SA_PATH_REC_SERVICE_ID;
2393a81c994dSSean Hefty 
2394f68194caSSean Hefty 	switch (cma_family(id_priv)) {
2395f68194caSSean Hefty 	case AF_INET:
2396a81c994dSSean Hefty 		path_rec.qos_class = cpu_to_be16((u16) id_priv->tos);
2397a81c994dSSean Hefty 		comp_mask |= IB_SA_PATH_REC_QOS_CLASS;
2398f68194caSSean Hefty 		break;
2399f68194caSSean Hefty 	case AF_INET6:
2400f4753834SSean Hefty 		sin6 = (struct sockaddr_in6 *) cma_src_addr(id_priv);
2401a81c994dSSean Hefty 		path_rec.traffic_class = (u8) (be32_to_cpu(sin6->sin6_flowinfo) >> 20);
2402a81c994dSSean Hefty 		comp_mask |= IB_SA_PATH_REC_TRAFFIC_CLASS;
2403f68194caSSean Hefty 		break;
2404f68194caSSean Hefty 	case AF_IB:
2405f68194caSSean Hefty 		sib = (struct sockaddr_ib *) cma_src_addr(id_priv);
2406f68194caSSean Hefty 		path_rec.traffic_class = (u8) (be32_to_cpu(sib->sib_flowinfo) >> 20);
2407f68194caSSean Hefty 		comp_mask |= IB_SA_PATH_REC_TRAFFIC_CLASS;
2408f68194caSSean Hefty 		break;
2409a81c994dSSean Hefty 	}
2410e51060f0SSean Hefty 
2411c1a0b23bSMichael S. Tsirkin 	id_priv->query_id = ib_sa_path_rec_get(&sa_client, id_priv->id.device,
2412e51060f0SSean Hefty 					       id_priv->id.port_num, &path_rec,
2413a81c994dSSean Hefty 					       comp_mask, timeout_ms,
2414a81c994dSSean Hefty 					       GFP_KERNEL, cma_query_handler,
2415a81c994dSSean Hefty 					       work, &id_priv->query);
2416e51060f0SSean Hefty 
2417e51060f0SSean Hefty 	return (id_priv->query_id < 0) ? id_priv->query_id : 0;
2418e51060f0SSean Hefty }
2419e51060f0SSean Hefty 
2420c4028958SDavid Howells static void cma_work_handler(struct work_struct *_work)
2421e51060f0SSean Hefty {
2422c4028958SDavid Howells 	struct cma_work *work = container_of(_work, struct cma_work, work);
2423e51060f0SSean Hefty 	struct rdma_id_private *id_priv = work->id;
2424e51060f0SSean Hefty 	int destroy = 0;
2425e51060f0SSean Hefty 
2426de910bd9SOr Gerlitz 	mutex_lock(&id_priv->handler_mutex);
2427e51060f0SSean Hefty 	if (!cma_comp_exch(id_priv, work->old_state, work->new_state))
2428e51060f0SSean Hefty 		goto out;
2429e51060f0SSean Hefty 
2430e51060f0SSean Hefty 	if (id_priv->id.event_handler(&id_priv->id, &work->event)) {
2431550e5ca7SNir Muchtar 		cma_exch(id_priv, RDMA_CM_DESTROYING);
2432e51060f0SSean Hefty 		destroy = 1;
2433e51060f0SSean Hefty 	}
2434e51060f0SSean Hefty out:
2435de910bd9SOr Gerlitz 	mutex_unlock(&id_priv->handler_mutex);
2436e51060f0SSean Hefty 	cma_deref_id(id_priv);
2437e51060f0SSean Hefty 	if (destroy)
2438e51060f0SSean Hefty 		rdma_destroy_id(&id_priv->id);
2439e51060f0SSean Hefty 	kfree(work);
2440e51060f0SSean Hefty }
2441e51060f0SSean Hefty 
2442dd5bdff8SOr Gerlitz static void cma_ndev_work_handler(struct work_struct *_work)
2443dd5bdff8SOr Gerlitz {
2444dd5bdff8SOr Gerlitz 	struct cma_ndev_work *work = container_of(_work, struct cma_ndev_work, work);
2445dd5bdff8SOr Gerlitz 	struct rdma_id_private *id_priv = work->id;
2446dd5bdff8SOr Gerlitz 	int destroy = 0;
2447dd5bdff8SOr Gerlitz 
2448dd5bdff8SOr Gerlitz 	mutex_lock(&id_priv->handler_mutex);
2449550e5ca7SNir Muchtar 	if (id_priv->state == RDMA_CM_DESTROYING ||
2450550e5ca7SNir Muchtar 	    id_priv->state == RDMA_CM_DEVICE_REMOVAL)
2451dd5bdff8SOr Gerlitz 		goto out;
2452dd5bdff8SOr Gerlitz 
2453dd5bdff8SOr Gerlitz 	if (id_priv->id.event_handler(&id_priv->id, &work->event)) {
2454550e5ca7SNir Muchtar 		cma_exch(id_priv, RDMA_CM_DESTROYING);
2455dd5bdff8SOr Gerlitz 		destroy = 1;
2456dd5bdff8SOr Gerlitz 	}
2457dd5bdff8SOr Gerlitz 
2458dd5bdff8SOr Gerlitz out:
2459dd5bdff8SOr Gerlitz 	mutex_unlock(&id_priv->handler_mutex);
2460dd5bdff8SOr Gerlitz 	cma_deref_id(id_priv);
2461dd5bdff8SOr Gerlitz 	if (destroy)
2462dd5bdff8SOr Gerlitz 		rdma_destroy_id(&id_priv->id);
2463dd5bdff8SOr Gerlitz 	kfree(work);
2464dd5bdff8SOr Gerlitz }
2465dd5bdff8SOr Gerlitz 
2466981b5a23SParav Pandit static void cma_init_resolve_route_work(struct cma_work *work,
2467981b5a23SParav Pandit 					struct rdma_id_private *id_priv)
2468981b5a23SParav Pandit {
2469981b5a23SParav Pandit 	work->id = id_priv;
2470981b5a23SParav Pandit 	INIT_WORK(&work->work, cma_work_handler);
2471981b5a23SParav Pandit 	work->old_state = RDMA_CM_ROUTE_QUERY;
2472981b5a23SParav Pandit 	work->new_state = RDMA_CM_ROUTE_RESOLVED;
2473981b5a23SParav Pandit 	work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED;
2474981b5a23SParav Pandit }
2475981b5a23SParav Pandit 
2476981b5a23SParav Pandit static void cma_init_resolve_addr_work(struct cma_work *work,
2477981b5a23SParav Pandit 				       struct rdma_id_private *id_priv)
2478981b5a23SParav Pandit {
2479981b5a23SParav Pandit 	work->id = id_priv;
2480981b5a23SParav Pandit 	INIT_WORK(&work->work, cma_work_handler);
2481981b5a23SParav Pandit 	work->old_state = RDMA_CM_ADDR_QUERY;
2482981b5a23SParav Pandit 	work->new_state = RDMA_CM_ADDR_RESOLVED;
2483981b5a23SParav Pandit 	work->event.event = RDMA_CM_EVENT_ADDR_RESOLVED;
2484981b5a23SParav Pandit }
2485981b5a23SParav Pandit 
2486e51060f0SSean Hefty static int cma_resolve_ib_route(struct rdma_id_private *id_priv, int timeout_ms)
2487e51060f0SSean Hefty {
2488e51060f0SSean Hefty 	struct rdma_route *route = &id_priv->id.route;
2489e51060f0SSean Hefty 	struct cma_work *work;
2490e51060f0SSean Hefty 	int ret;
2491e51060f0SSean Hefty 
2492e51060f0SSean Hefty 	work = kzalloc(sizeof *work, GFP_KERNEL);
2493e51060f0SSean Hefty 	if (!work)
2494e51060f0SSean Hefty 		return -ENOMEM;
2495e51060f0SSean Hefty 
2496981b5a23SParav Pandit 	cma_init_resolve_route_work(work, id_priv);
2497e51060f0SSean Hefty 
2498e51060f0SSean Hefty 	route->path_rec = kmalloc(sizeof *route->path_rec, GFP_KERNEL);
2499e51060f0SSean Hefty 	if (!route->path_rec) {
2500e51060f0SSean Hefty 		ret = -ENOMEM;
2501e51060f0SSean Hefty 		goto err1;
2502e51060f0SSean Hefty 	}
2503e51060f0SSean Hefty 
2504e51060f0SSean Hefty 	ret = cma_query_ib_route(id_priv, timeout_ms, work);
2505e51060f0SSean Hefty 	if (ret)
2506e51060f0SSean Hefty 		goto err2;
2507e51060f0SSean Hefty 
2508e51060f0SSean Hefty 	return 0;
2509e51060f0SSean Hefty err2:
2510e51060f0SSean Hefty 	kfree(route->path_rec);
2511e51060f0SSean Hefty 	route->path_rec = NULL;
2512e51060f0SSean Hefty err1:
2513e51060f0SSean Hefty 	kfree(work);
2514e51060f0SSean Hefty 	return ret;
2515e51060f0SSean Hefty }
2516e51060f0SSean Hefty 
25179327c7afSParav Pandit static enum ib_gid_type cma_route_gid_type(enum rdma_network_type network_type,
25189327c7afSParav Pandit 					   unsigned long supported_gids,
25199327c7afSParav Pandit 					   enum ib_gid_type default_gid)
25209327c7afSParav Pandit {
25219327c7afSParav Pandit 	if ((network_type == RDMA_NETWORK_IPV4 ||
25229327c7afSParav Pandit 	     network_type == RDMA_NETWORK_IPV6) &&
25239327c7afSParav Pandit 	    test_bit(IB_GID_TYPE_ROCE_UDP_ENCAP, &supported_gids))
25249327c7afSParav Pandit 		return IB_GID_TYPE_ROCE_UDP_ENCAP;
25259327c7afSParav Pandit 
25269327c7afSParav Pandit 	return default_gid;
25279327c7afSParav Pandit }
25289327c7afSParav Pandit 
25299327c7afSParav Pandit /*
25309327c7afSParav Pandit  * cma_iboe_set_path_rec_l2_fields() is helper function which sets
25319327c7afSParav Pandit  * path record type based on GID type.
25329327c7afSParav Pandit  * It also sets up other L2 fields which includes destination mac address
25339327c7afSParav Pandit  * netdev ifindex, of the path record.
25349327c7afSParav Pandit  * It returns the netdev of the bound interface for this path record entry.
25359327c7afSParav Pandit  */
25369327c7afSParav Pandit static struct net_device *
25379327c7afSParav Pandit cma_iboe_set_path_rec_l2_fields(struct rdma_id_private *id_priv)
25389327c7afSParav Pandit {
25399327c7afSParav Pandit 	struct rdma_route *route = &id_priv->id.route;
25409327c7afSParav Pandit 	enum ib_gid_type gid_type = IB_GID_TYPE_ROCE;
25419327c7afSParav Pandit 	struct rdma_addr *addr = &route->addr;
25429327c7afSParav Pandit 	unsigned long supported_gids;
25439327c7afSParav Pandit 	struct net_device *ndev;
25449327c7afSParav Pandit 
25459327c7afSParav Pandit 	if (!addr->dev_addr.bound_dev_if)
25469327c7afSParav Pandit 		return NULL;
25479327c7afSParav Pandit 
25489327c7afSParav Pandit 	ndev = dev_get_by_index(addr->dev_addr.net,
25499327c7afSParav Pandit 				addr->dev_addr.bound_dev_if);
25509327c7afSParav Pandit 	if (!ndev)
25519327c7afSParav Pandit 		return NULL;
25529327c7afSParav Pandit 
25539327c7afSParav Pandit 	supported_gids = roce_gid_type_mask_support(id_priv->id.device,
25549327c7afSParav Pandit 						    id_priv->id.port_num);
25559327c7afSParav Pandit 	gid_type = cma_route_gid_type(addr->dev_addr.network,
25569327c7afSParav Pandit 				      supported_gids,
25579327c7afSParav Pandit 				      id_priv->gid_type);
25589327c7afSParav Pandit 	/* Use the hint from IP Stack to select GID Type */
25599327c7afSParav Pandit 	if (gid_type < ib_network_to_gid_type(addr->dev_addr.network))
25609327c7afSParav Pandit 		gid_type = ib_network_to_gid_type(addr->dev_addr.network);
25619327c7afSParav Pandit 	route->path_rec->rec_type = sa_conv_gid_to_pathrec_type(gid_type);
25629327c7afSParav Pandit 
2563114cc9c4SParav Pandit 	route->path_rec->roce.route_resolved = true;
25649327c7afSParav Pandit 	sa_path_set_ndev(route->path_rec, addr->dev_addr.net);
25659327c7afSParav Pandit 	sa_path_set_ifindex(route->path_rec, ndev->ifindex);
25669327c7afSParav Pandit 	sa_path_set_dmac(route->path_rec, addr->dev_addr.dst_dev_addr);
25679327c7afSParav Pandit 	return ndev;
25689327c7afSParav Pandit }
25699327c7afSParav Pandit 
2570fe75889fSParav Pandit int rdma_set_ib_path(struct rdma_cm_id *id,
2571fe75889fSParav Pandit 		     struct sa_path_rec *path_rec)
2572e51060f0SSean Hefty {
2573e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
25748d20a1f0SParav Pandit 	struct net_device *ndev;
2575e51060f0SSean Hefty 	int ret;
2576e51060f0SSean Hefty 
2577e51060f0SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
2578550e5ca7SNir Muchtar 	if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED,
2579550e5ca7SNir Muchtar 			   RDMA_CM_ROUTE_RESOLVED))
2580e51060f0SSean Hefty 		return -EINVAL;
2581e51060f0SSean Hefty 
2582fe75889fSParav Pandit 	id->route.path_rec = kmemdup(path_rec, sizeof(*path_rec),
25839893e742SJulia Lawall 				     GFP_KERNEL);
2584e51060f0SSean Hefty 	if (!id->route.path_rec) {
2585e51060f0SSean Hefty 		ret = -ENOMEM;
2586e51060f0SSean Hefty 		goto err;
2587e51060f0SSean Hefty 	}
2588e51060f0SSean Hefty 
25898d20a1f0SParav Pandit 	if (rdma_protocol_roce(id->device, id->port_num)) {
25908d20a1f0SParav Pandit 		ndev = cma_iboe_set_path_rec_l2_fields(id_priv);
25918d20a1f0SParav Pandit 		if (!ndev) {
25928d20a1f0SParav Pandit 			ret = -ENODEV;
25938d20a1f0SParav Pandit 			goto err_free;
25948d20a1f0SParav Pandit 		}
25958d20a1f0SParav Pandit 		dev_put(ndev);
25968d20a1f0SParav Pandit 	}
25978d20a1f0SParav Pandit 
2598fe75889fSParav Pandit 	id->route.num_paths = 1;
2599e51060f0SSean Hefty 	return 0;
26008d20a1f0SParav Pandit 
26018d20a1f0SParav Pandit err_free:
26028d20a1f0SParav Pandit 	kfree(id->route.path_rec);
26038d20a1f0SParav Pandit 	id->route.path_rec = NULL;
2604e51060f0SSean Hefty err:
2605550e5ca7SNir Muchtar 	cma_comp_exch(id_priv, RDMA_CM_ROUTE_RESOLVED, RDMA_CM_ADDR_RESOLVED);
2606e51060f0SSean Hefty 	return ret;
2607e51060f0SSean Hefty }
2608fe75889fSParav Pandit EXPORT_SYMBOL(rdma_set_ib_path);
2609e51060f0SSean Hefty 
261007ebafbaSTom Tucker static int cma_resolve_iw_route(struct rdma_id_private *id_priv, int timeout_ms)
261107ebafbaSTom Tucker {
261207ebafbaSTom Tucker 	struct cma_work *work;
261307ebafbaSTom Tucker 
261407ebafbaSTom Tucker 	work = kzalloc(sizeof *work, GFP_KERNEL);
261507ebafbaSTom Tucker 	if (!work)
261607ebafbaSTom Tucker 		return -ENOMEM;
261707ebafbaSTom Tucker 
2618981b5a23SParav Pandit 	cma_init_resolve_route_work(work, id_priv);
261907ebafbaSTom Tucker 	queue_work(cma_wq, &work->work);
262007ebafbaSTom Tucker 	return 0;
262107ebafbaSTom Tucker }
262207ebafbaSTom Tucker 
2623eb072c4bSEyal Perry static int iboe_tos_to_sl(struct net_device *ndev, int tos)
2624eb072c4bSEyal Perry {
2625eb072c4bSEyal Perry 	int prio;
2626eb072c4bSEyal Perry 	struct net_device *dev;
2627eb072c4bSEyal Perry 
2628eb072c4bSEyal Perry 	prio = rt_tos2priority(tos);
2629d0d7b10bSParav Pandit 	dev = is_vlan_dev(ndev) ? vlan_dev_real_dev(ndev) : ndev;
2630eb072c4bSEyal Perry 	if (dev->num_tc)
2631eb072c4bSEyal Perry 		return netdev_get_prio_tc_map(dev, prio);
2632eb072c4bSEyal Perry 
2633eb072c4bSEyal Perry #if IS_ENABLED(CONFIG_VLAN_8021Q)
2634d0d7b10bSParav Pandit 	if (is_vlan_dev(ndev))
2635eb072c4bSEyal Perry 		return (vlan_dev_get_egress_qos_mask(ndev, prio) &
2636eb072c4bSEyal Perry 			VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
2637eb072c4bSEyal Perry #endif
2638eb072c4bSEyal Perry 	return 0;
2639eb072c4bSEyal Perry }
2640eb072c4bSEyal Perry 
26413c86aa70SEli Cohen static int cma_resolve_iboe_route(struct rdma_id_private *id_priv)
26423c86aa70SEli Cohen {
26433c86aa70SEli Cohen 	struct rdma_route *route = &id_priv->id.route;
26443c86aa70SEli Cohen 	struct rdma_addr *addr = &route->addr;
26453c86aa70SEli Cohen 	struct cma_work *work;
26463c86aa70SEli Cohen 	int ret;
26474367ec7fSParav Pandit 	struct net_device *ndev;
26484367ec7fSParav Pandit 
264989052d78SMajd Dibbiny 	u8 default_roce_tos = id_priv->cma_dev->default_roce_tos[id_priv->id.port_num -
265089052d78SMajd Dibbiny 					rdma_start_port(id_priv->cma_dev->device)];
265189052d78SMajd Dibbiny 	u8 tos = id_priv->tos_set ? id_priv->tos : default_roce_tos;
2652dd5f03beSMatan Barak 
26533c86aa70SEli Cohen 
26543c86aa70SEli Cohen 	work = kzalloc(sizeof *work, GFP_KERNEL);
26553c86aa70SEli Cohen 	if (!work)
26563c86aa70SEli Cohen 		return -ENOMEM;
26573c86aa70SEli Cohen 
26583c86aa70SEli Cohen 	route->path_rec = kzalloc(sizeof *route->path_rec, GFP_KERNEL);
26593c86aa70SEli Cohen 	if (!route->path_rec) {
26603c86aa70SEli Cohen 		ret = -ENOMEM;
26613c86aa70SEli Cohen 		goto err1;
26623c86aa70SEli Cohen 	}
26633c86aa70SEli Cohen 
26643c86aa70SEli Cohen 	route->num_paths = 1;
26653c86aa70SEli Cohen 
26669327c7afSParav Pandit 	ndev = cma_iboe_set_path_rec_l2_fields(id_priv);
266723d70503SWei Yongjun 	if (!ndev) {
266823d70503SWei Yongjun 		ret = -ENODEV;
266923d70503SWei Yongjun 		goto err2;
267023d70503SWei Yongjun 	}
267120029832SMatan Barak 
26727b85627bSMoni Shoua 	rdma_ip2gid((struct sockaddr *)&id_priv->id.route.addr.src_addr,
26737b85627bSMoni Shoua 		    &route->path_rec->sgid);
26747b85627bSMoni Shoua 	rdma_ip2gid((struct sockaddr *)&id_priv->id.route.addr.dst_addr,
26757b85627bSMoni Shoua 		    &route->path_rec->dgid);
2676af7bd463SEli Cohen 
2677c3efe750SMatan Barak 	if (((struct sockaddr *)&id_priv->id.route.addr.dst_addr)->sa_family != AF_IB)
2678c865f246SSomnath Kotur 		/* TODO: get the hoplimit from the inet/inet6 device */
2679c3efe750SMatan Barak 		route->path_rec->hop_limit = addr->dev_addr.hoplimit;
2680c3efe750SMatan Barak 	else
2681af7bd463SEli Cohen 		route->path_rec->hop_limit = 1;
2682af7bd463SEli Cohen 	route->path_rec->reversible = 1;
2683af7bd463SEli Cohen 	route->path_rec->pkey = cpu_to_be16(0xffff);
2684af7bd463SEli Cohen 	route->path_rec->mtu_selector = IB_SA_EQ;
268589052d78SMajd Dibbiny 	route->path_rec->sl = iboe_tos_to_sl(ndev, tos);
268689052d78SMajd Dibbiny 	route->path_rec->traffic_class = tos;
26873c86aa70SEli Cohen 	route->path_rec->mtu = iboe_get_mtu(ndev->mtu);
26883c86aa70SEli Cohen 	route->path_rec->rate_selector = IB_SA_EQ;
26893c86aa70SEli Cohen 	route->path_rec->rate = iboe_get_rate(ndev);
26903c86aa70SEli Cohen 	dev_put(ndev);
26913c86aa70SEli Cohen 	route->path_rec->packet_life_time_selector = IB_SA_EQ;
26923c86aa70SEli Cohen 	route->path_rec->packet_life_time = CMA_IBOE_PACKET_LIFETIME;
26933c86aa70SEli Cohen 	if (!route->path_rec->mtu) {
26943c86aa70SEli Cohen 		ret = -EINVAL;
26953c86aa70SEli Cohen 		goto err2;
26963c86aa70SEli Cohen 	}
26973c86aa70SEli Cohen 
2698981b5a23SParav Pandit 	cma_init_resolve_route_work(work, id_priv);
26993c86aa70SEli Cohen 	queue_work(cma_wq, &work->work);
27003c86aa70SEli Cohen 
27013c86aa70SEli Cohen 	return 0;
27023c86aa70SEli Cohen 
27033c86aa70SEli Cohen err2:
27043c86aa70SEli Cohen 	kfree(route->path_rec);
27053c86aa70SEli Cohen 	route->path_rec = NULL;
27063c86aa70SEli Cohen err1:
27073c86aa70SEli Cohen 	kfree(work);
27083c86aa70SEli Cohen 	return ret;
27093c86aa70SEli Cohen }
27103c86aa70SEli Cohen 
2711e51060f0SSean Hefty int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms)
2712e51060f0SSean Hefty {
2713e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
2714e51060f0SSean Hefty 	int ret;
2715e51060f0SSean Hefty 
2716e51060f0SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
2717550e5ca7SNir Muchtar 	if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED, RDMA_CM_ROUTE_QUERY))
2718e51060f0SSean Hefty 		return -EINVAL;
2719e51060f0SSean Hefty 
2720e51060f0SSean Hefty 	atomic_inc(&id_priv->refcount);
2721fe53ba2fSMichael Wang 	if (rdma_cap_ib_sa(id->device, id->port_num))
2722e51060f0SSean Hefty 		ret = cma_resolve_ib_route(id_priv, timeout_ms);
27235d9fb044SIra Weiny 	else if (rdma_protocol_roce(id->device, id->port_num))
27243c86aa70SEli Cohen 		ret = cma_resolve_iboe_route(id_priv);
2725c72f2189SMichael Wang 	else if (rdma_protocol_iwarp(id->device, id->port_num))
272607ebafbaSTom Tucker 		ret = cma_resolve_iw_route(id_priv, timeout_ms);
2727c72f2189SMichael Wang 	else
2728e51060f0SSean Hefty 		ret = -ENOSYS;
2729c72f2189SMichael Wang 
2730e51060f0SSean Hefty 	if (ret)
2731e51060f0SSean Hefty 		goto err;
2732e51060f0SSean Hefty 
2733e51060f0SSean Hefty 	return 0;
2734e51060f0SSean Hefty err:
2735550e5ca7SNir Muchtar 	cma_comp_exch(id_priv, RDMA_CM_ROUTE_QUERY, RDMA_CM_ADDR_RESOLVED);
2736e51060f0SSean Hefty 	cma_deref_id(id_priv);
2737e51060f0SSean Hefty 	return ret;
2738e51060f0SSean Hefty }
2739e51060f0SSean Hefty EXPORT_SYMBOL(rdma_resolve_route);
2740e51060f0SSean Hefty 
27416a3e362dSSean Hefty static void cma_set_loopback(struct sockaddr *addr)
27426a3e362dSSean Hefty {
27436a3e362dSSean Hefty 	switch (addr->sa_family) {
27446a3e362dSSean Hefty 	case AF_INET:
27456a3e362dSSean Hefty 		((struct sockaddr_in *) addr)->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
27466a3e362dSSean Hefty 		break;
27476a3e362dSSean Hefty 	case AF_INET6:
27486a3e362dSSean Hefty 		ipv6_addr_set(&((struct sockaddr_in6 *) addr)->sin6_addr,
27496a3e362dSSean Hefty 			      0, 0, 0, htonl(1));
27506a3e362dSSean Hefty 		break;
27516a3e362dSSean Hefty 	default:
27526a3e362dSSean Hefty 		ib_addr_set(&((struct sockaddr_ib *) addr)->sib_addr,
27536a3e362dSSean Hefty 			    0, 0, 0, htonl(1));
27546a3e362dSSean Hefty 		break;
27556a3e362dSSean Hefty 	}
27566a3e362dSSean Hefty }
27576a3e362dSSean Hefty 
2758e51060f0SSean Hefty static int cma_bind_loopback(struct rdma_id_private *id_priv)
2759e51060f0SSean Hefty {
2760b0569e40SSean Hefty 	struct cma_device *cma_dev, *cur_dev;
2761f0ee3404SMichael S. Tsirkin 	union ib_gid gid;
2762102c5ce0SJack Wang 	enum ib_port_state port_state;
2763e51060f0SSean Hefty 	u16 pkey;
2764e51060f0SSean Hefty 	int ret;
2765e51060f0SSean Hefty 	u8 p;
2766e51060f0SSean Hefty 
2767b0569e40SSean Hefty 	cma_dev = NULL;
2768e51060f0SSean Hefty 	mutex_lock(&lock);
2769b0569e40SSean Hefty 	list_for_each_entry(cur_dev, &dev_list, list) {
2770b0569e40SSean Hefty 		if (cma_family(id_priv) == AF_IB &&
277172219ceaSMichael Wang 		    !rdma_cap_ib_cm(cur_dev->device, 1))
2772b0569e40SSean Hefty 			continue;
2773b0569e40SSean Hefty 
2774b0569e40SSean Hefty 		if (!cma_dev)
2775b0569e40SSean Hefty 			cma_dev = cur_dev;
2776b0569e40SSean Hefty 
2777b0569e40SSean Hefty 		for (p = 1; p <= cur_dev->device->phys_port_cnt; ++p) {
2778102c5ce0SJack Wang 			if (!ib_get_cached_port_state(cur_dev->device, p, &port_state) &&
2779102c5ce0SJack Wang 			    port_state == IB_PORT_ACTIVE) {
2780b0569e40SSean Hefty 				cma_dev = cur_dev;
2781b0569e40SSean Hefty 				goto port_found;
2782b0569e40SSean Hefty 			}
2783b0569e40SSean Hefty 		}
2784b0569e40SSean Hefty 	}
2785b0569e40SSean Hefty 
2786b0569e40SSean Hefty 	if (!cma_dev) {
2787e82153b5SKrishna Kumar 		ret = -ENODEV;
2788e82153b5SKrishna Kumar 		goto out;
2789e82153b5SKrishna Kumar 	}
2790e51060f0SSean Hefty 
2791e51060f0SSean Hefty 	p = 1;
2792e51060f0SSean Hefty 
2793e51060f0SSean Hefty port_found:
279455ee3ab2SMatan Barak 	ret = ib_get_cached_gid(cma_dev->device, p, 0, &gid, NULL);
2795e51060f0SSean Hefty 	if (ret)
2796e51060f0SSean Hefty 		goto out;
2797e51060f0SSean Hefty 
2798e51060f0SSean Hefty 	ret = ib_get_cached_pkey(cma_dev->device, p, 0, &pkey);
2799e51060f0SSean Hefty 	if (ret)
2800e51060f0SSean Hefty 		goto out;
2801e51060f0SSean Hefty 
28026f8372b6SSean Hefty 	id_priv->id.route.addr.dev_addr.dev_type =
280321655afcSMichael Wang 		(rdma_protocol_ib(cma_dev->device, p)) ?
28046f8372b6SSean Hefty 		ARPHRD_INFINIBAND : ARPHRD_ETHER;
28056f8372b6SSean Hefty 
28066f8372b6SSean Hefty 	rdma_addr_set_sgid(&id_priv->id.route.addr.dev_addr, &gid);
2807e51060f0SSean Hefty 	ib_addr_set_pkey(&id_priv->id.route.addr.dev_addr, pkey);
2808e51060f0SSean Hefty 	id_priv->id.port_num = p;
2809e51060f0SSean Hefty 	cma_attach_to_dev(id_priv, cma_dev);
2810f4753834SSean Hefty 	cma_set_loopback(cma_src_addr(id_priv));
2811e51060f0SSean Hefty out:
2812e51060f0SSean Hefty 	mutex_unlock(&lock);
2813e51060f0SSean Hefty 	return ret;
2814e51060f0SSean Hefty }
2815e51060f0SSean Hefty 
2816e51060f0SSean Hefty static void addr_handler(int status, struct sockaddr *src_addr,
2817e51060f0SSean Hefty 			 struct rdma_dev_addr *dev_addr, void *context)
2818e51060f0SSean Hefty {
2819e51060f0SSean Hefty 	struct rdma_id_private *id_priv = context;
2820a1b1b61fSSean Hefty 	struct rdma_cm_event event;
2821e51060f0SSean Hefty 
2822a1b1b61fSSean Hefty 	memset(&event, 0, sizeof event);
2823de910bd9SOr Gerlitz 	mutex_lock(&id_priv->handler_mutex);
2824550e5ca7SNir Muchtar 	if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_QUERY,
2825550e5ca7SNir Muchtar 			   RDMA_CM_ADDR_RESOLVED))
282661a73c70SSean Hefty 		goto out;
282761a73c70SSean Hefty 
28287b85627bSMoni Shoua 	memcpy(cma_src_addr(id_priv), src_addr, rdma_addr_size(src_addr));
2829498683c6SMoni Shoua 	if (!status && !id_priv->cma_dev) {
2830be9130ccSDoug Ledford 		status = cma_acquire_dev(id_priv, NULL);
2831498683c6SMoni Shoua 		if (status)
2832498683c6SMoni Shoua 			pr_debug_ratelimited("RDMA CM: ADDR_ERROR: failed to acquire device. status %d\n",
2833498683c6SMoni Shoua 					     status);
2834498683c6SMoni Shoua 	} else {
2835498683c6SMoni Shoua 		pr_debug_ratelimited("RDMA CM: ADDR_ERROR: failed to resolve IP. status %d\n", status);
2836498683c6SMoni Shoua 	}
2837e51060f0SSean Hefty 
2838e51060f0SSean Hefty 	if (status) {
2839550e5ca7SNir Muchtar 		if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED,
2840550e5ca7SNir Muchtar 				   RDMA_CM_ADDR_BOUND))
2841e51060f0SSean Hefty 			goto out;
2842a1b1b61fSSean Hefty 		event.event = RDMA_CM_EVENT_ADDR_ERROR;
2843a1b1b61fSSean Hefty 		event.status = status;
28447b85627bSMoni Shoua 	} else
2845a1b1b61fSSean Hefty 		event.event = RDMA_CM_EVENT_ADDR_RESOLVED;
2846e51060f0SSean Hefty 
2847a1b1b61fSSean Hefty 	if (id_priv->id.event_handler(&id_priv->id, &event)) {
2848550e5ca7SNir Muchtar 		cma_exch(id_priv, RDMA_CM_DESTROYING);
2849de910bd9SOr Gerlitz 		mutex_unlock(&id_priv->handler_mutex);
2850e51060f0SSean Hefty 		cma_deref_id(id_priv);
2851e51060f0SSean Hefty 		rdma_destroy_id(&id_priv->id);
2852e51060f0SSean Hefty 		return;
2853e51060f0SSean Hefty 	}
2854e51060f0SSean Hefty out:
2855de910bd9SOr Gerlitz 	mutex_unlock(&id_priv->handler_mutex);
2856e51060f0SSean Hefty 	cma_deref_id(id_priv);
2857e51060f0SSean Hefty }
2858e51060f0SSean Hefty 
2859e51060f0SSean Hefty static int cma_resolve_loopback(struct rdma_id_private *id_priv)
2860e51060f0SSean Hefty {
2861e51060f0SSean Hefty 	struct cma_work *work;
2862f0ee3404SMichael S. Tsirkin 	union ib_gid gid;
2863e51060f0SSean Hefty 	int ret;
2864e51060f0SSean Hefty 
2865e51060f0SSean Hefty 	work = kzalloc(sizeof *work, GFP_KERNEL);
2866e51060f0SSean Hefty 	if (!work)
2867e51060f0SSean Hefty 		return -ENOMEM;
2868e51060f0SSean Hefty 
2869e51060f0SSean Hefty 	if (!id_priv->cma_dev) {
2870e51060f0SSean Hefty 		ret = cma_bind_loopback(id_priv);
2871e51060f0SSean Hefty 		if (ret)
2872e51060f0SSean Hefty 			goto err;
2873e51060f0SSean Hefty 	}
2874e51060f0SSean Hefty 
28756f8372b6SSean Hefty 	rdma_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid);
28766f8372b6SSean Hefty 	rdma_addr_set_dgid(&id_priv->id.route.addr.dev_addr, &gid);
2877e51060f0SSean Hefty 
2878981b5a23SParav Pandit 	cma_init_resolve_addr_work(work, id_priv);
2879e51060f0SSean Hefty 	queue_work(cma_wq, &work->work);
2880e51060f0SSean Hefty 	return 0;
2881e51060f0SSean Hefty err:
2882e51060f0SSean Hefty 	kfree(work);
2883e51060f0SSean Hefty 	return ret;
2884e51060f0SSean Hefty }
2885e51060f0SSean Hefty 
2886f17df3b0SSean Hefty static int cma_resolve_ib_addr(struct rdma_id_private *id_priv)
2887f17df3b0SSean Hefty {
2888f17df3b0SSean Hefty 	struct cma_work *work;
2889f17df3b0SSean Hefty 	int ret;
2890f17df3b0SSean Hefty 
2891f17df3b0SSean Hefty 	work = kzalloc(sizeof *work, GFP_KERNEL);
2892f17df3b0SSean Hefty 	if (!work)
2893f17df3b0SSean Hefty 		return -ENOMEM;
2894f17df3b0SSean Hefty 
2895f17df3b0SSean Hefty 	if (!id_priv->cma_dev) {
2896f17df3b0SSean Hefty 		ret = cma_resolve_ib_dev(id_priv);
2897f17df3b0SSean Hefty 		if (ret)
2898f17df3b0SSean Hefty 			goto err;
2899f17df3b0SSean Hefty 	}
2900f17df3b0SSean Hefty 
2901f17df3b0SSean Hefty 	rdma_addr_set_dgid(&id_priv->id.route.addr.dev_addr, (union ib_gid *)
2902f17df3b0SSean Hefty 		&(((struct sockaddr_ib *) &id_priv->id.route.addr.dst_addr)->sib_addr));
2903f17df3b0SSean Hefty 
2904981b5a23SParav Pandit 	cma_init_resolve_addr_work(work, id_priv);
2905f17df3b0SSean Hefty 	queue_work(cma_wq, &work->work);
2906f17df3b0SSean Hefty 	return 0;
2907f17df3b0SSean Hefty err:
2908f17df3b0SSean Hefty 	kfree(work);
2909f17df3b0SSean Hefty 	return ret;
2910f17df3b0SSean Hefty }
2911f17df3b0SSean Hefty 
2912e51060f0SSean Hefty static int cma_bind_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
2913e51060f0SSean Hefty 			 struct sockaddr *dst_addr)
2914e51060f0SSean Hefty {
2915d14714dfSSean Hefty 	if (!src_addr || !src_addr->sa_family) {
2916d14714dfSSean Hefty 		src_addr = (struct sockaddr *) &id->route.addr.src_addr;
2917f17df3b0SSean Hefty 		src_addr->sa_family = dst_addr->sa_family;
2918b4cfe397SJack Morgenstein 		if (IS_ENABLED(CONFIG_IPV6) &&
2919b4cfe397SJack Morgenstein 		    dst_addr->sa_family == AF_INET6) {
29206c26a771SSpencer Baugh 			struct sockaddr_in6 *src_addr6 = (struct sockaddr_in6 *) src_addr;
29216c26a771SSpencer Baugh 			struct sockaddr_in6 *dst_addr6 = (struct sockaddr_in6 *) dst_addr;
29226c26a771SSpencer Baugh 			src_addr6->sin6_scope_id = dst_addr6->sin6_scope_id;
29236c26a771SSpencer Baugh 			if (ipv6_addr_type(&dst_addr6->sin6_addr) & IPV6_ADDR_LINKLOCAL)
29246c26a771SSpencer Baugh 				id->route.addr.dev_addr.bound_dev_if = dst_addr6->sin6_scope_id;
2925f17df3b0SSean Hefty 		} else if (dst_addr->sa_family == AF_IB) {
2926f17df3b0SSean Hefty 			((struct sockaddr_ib *) src_addr)->sib_pkey =
2927f17df3b0SSean Hefty 				((struct sockaddr_ib *) dst_addr)->sib_pkey;
2928d14714dfSSean Hefty 		}
2929d14714dfSSean Hefty 	}
2930e51060f0SSean Hefty 	return rdma_bind_addr(id, src_addr);
2931e51060f0SSean Hefty }
2932e51060f0SSean Hefty 
2933e51060f0SSean Hefty int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
2934e51060f0SSean Hefty 		      struct sockaddr *dst_addr, int timeout_ms)
2935e51060f0SSean Hefty {
2936e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
2937e51060f0SSean Hefty 	int ret;
2938e51060f0SSean Hefty 
2939e51060f0SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
294019b752a1SMoni Shoua 	memcpy(cma_dst_addr(id_priv), dst_addr, rdma_addr_size(dst_addr));
2941550e5ca7SNir Muchtar 	if (id_priv->state == RDMA_CM_IDLE) {
2942e51060f0SSean Hefty 		ret = cma_bind_addr(id, src_addr, dst_addr);
294319b752a1SMoni Shoua 		if (ret) {
294419b752a1SMoni Shoua 			memset(cma_dst_addr(id_priv), 0, rdma_addr_size(dst_addr));
2945e51060f0SSean Hefty 			return ret;
2946e51060f0SSean Hefty 		}
294719b752a1SMoni Shoua 	}
2948e51060f0SSean Hefty 
294919b752a1SMoni Shoua 	if (cma_family(id_priv) != dst_addr->sa_family) {
295019b752a1SMoni Shoua 		memset(cma_dst_addr(id_priv), 0, rdma_addr_size(dst_addr));
29514ae7152eSSean Hefty 		return -EINVAL;
295219b752a1SMoni Shoua 	}
29534ae7152eSSean Hefty 
295419b752a1SMoni Shoua 	if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_ADDR_QUERY)) {
295519b752a1SMoni Shoua 		memset(cma_dst_addr(id_priv), 0, rdma_addr_size(dst_addr));
2956e51060f0SSean Hefty 		return -EINVAL;
295719b752a1SMoni Shoua 	}
2958e51060f0SSean Hefty 
2959e51060f0SSean Hefty 	atomic_inc(&id_priv->refcount);
2960f17df3b0SSean Hefty 	if (cma_any_addr(dst_addr)) {
2961e51060f0SSean Hefty 		ret = cma_resolve_loopback(id_priv);
2962f17df3b0SSean Hefty 	} else {
2963f17df3b0SSean Hefty 		if (dst_addr->sa_family == AF_IB) {
2964f17df3b0SSean Hefty 			ret = cma_resolve_ib_addr(id_priv);
2965f17df3b0SSean Hefty 		} else {
2966ee6548d1SJason Gunthorpe 			ret = rdma_resolve_ip(cma_src_addr(id_priv),
29677a118df3SSean Hefty 					      dst_addr, &id->route.addr.dev_addr,
2968e51060f0SSean Hefty 					      timeout_ms, addr_handler, id_priv);
2969f17df3b0SSean Hefty 		}
2970f17df3b0SSean Hefty 	}
2971e51060f0SSean Hefty 	if (ret)
2972e51060f0SSean Hefty 		goto err;
2973e51060f0SSean Hefty 
2974e51060f0SSean Hefty 	return 0;
2975e51060f0SSean Hefty err:
2976550e5ca7SNir Muchtar 	cma_comp_exch(id_priv, RDMA_CM_ADDR_QUERY, RDMA_CM_ADDR_BOUND);
2977e51060f0SSean Hefty 	cma_deref_id(id_priv);
2978e51060f0SSean Hefty 	return ret;
2979e51060f0SSean Hefty }
2980e51060f0SSean Hefty EXPORT_SYMBOL(rdma_resolve_addr);
2981e51060f0SSean Hefty 
2982a9bb7912SHefty, Sean int rdma_set_reuseaddr(struct rdma_cm_id *id, int reuse)
2983a9bb7912SHefty, Sean {
2984a9bb7912SHefty, Sean 	struct rdma_id_private *id_priv;
2985a9bb7912SHefty, Sean 	unsigned long flags;
2986a9bb7912SHefty, Sean 	int ret;
2987a9bb7912SHefty, Sean 
2988a9bb7912SHefty, Sean 	id_priv = container_of(id, struct rdma_id_private, id);
2989a9bb7912SHefty, Sean 	spin_lock_irqsave(&id_priv->lock, flags);
2990c8dea2f9SSean Hefty 	if (reuse || id_priv->state == RDMA_CM_IDLE) {
2991a9bb7912SHefty, Sean 		id_priv->reuseaddr = reuse;
2992a9bb7912SHefty, Sean 		ret = 0;
2993a9bb7912SHefty, Sean 	} else {
2994a9bb7912SHefty, Sean 		ret = -EINVAL;
2995a9bb7912SHefty, Sean 	}
2996a9bb7912SHefty, Sean 	spin_unlock_irqrestore(&id_priv->lock, flags);
2997a9bb7912SHefty, Sean 	return ret;
2998a9bb7912SHefty, Sean }
2999a9bb7912SHefty, Sean EXPORT_SYMBOL(rdma_set_reuseaddr);
3000a9bb7912SHefty, Sean 
300168602120SSean Hefty int rdma_set_afonly(struct rdma_cm_id *id, int afonly)
300268602120SSean Hefty {
300368602120SSean Hefty 	struct rdma_id_private *id_priv;
300468602120SSean Hefty 	unsigned long flags;
300568602120SSean Hefty 	int ret;
300668602120SSean Hefty 
300768602120SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
300868602120SSean Hefty 	spin_lock_irqsave(&id_priv->lock, flags);
300968602120SSean Hefty 	if (id_priv->state == RDMA_CM_IDLE || id_priv->state == RDMA_CM_ADDR_BOUND) {
301068602120SSean Hefty 		id_priv->options |= (1 << CMA_OPTION_AFONLY);
301168602120SSean Hefty 		id_priv->afonly = afonly;
301268602120SSean Hefty 		ret = 0;
301368602120SSean Hefty 	} else {
301468602120SSean Hefty 		ret = -EINVAL;
301568602120SSean Hefty 	}
301668602120SSean Hefty 	spin_unlock_irqrestore(&id_priv->lock, flags);
301768602120SSean Hefty 	return ret;
301868602120SSean Hefty }
301968602120SSean Hefty EXPORT_SYMBOL(rdma_set_afonly);
302068602120SSean Hefty 
3021e51060f0SSean Hefty static void cma_bind_port(struct rdma_bind_list *bind_list,
3022e51060f0SSean Hefty 			  struct rdma_id_private *id_priv)
3023e51060f0SSean Hefty {
302458afdcb7SSean Hefty 	struct sockaddr *addr;
302558afdcb7SSean Hefty 	struct sockaddr_ib *sib;
302658afdcb7SSean Hefty 	u64 sid, mask;
302758afdcb7SSean Hefty 	__be16 port;
3028e51060f0SSean Hefty 
3029f4753834SSean Hefty 	addr = cma_src_addr(id_priv);
303058afdcb7SSean Hefty 	port = htons(bind_list->port);
303158afdcb7SSean Hefty 
303258afdcb7SSean Hefty 	switch (addr->sa_family) {
303358afdcb7SSean Hefty 	case AF_INET:
303458afdcb7SSean Hefty 		((struct sockaddr_in *) addr)->sin_port = port;
303558afdcb7SSean Hefty 		break;
303658afdcb7SSean Hefty 	case AF_INET6:
303758afdcb7SSean Hefty 		((struct sockaddr_in6 *) addr)->sin6_port = port;
303858afdcb7SSean Hefty 		break;
303958afdcb7SSean Hefty 	case AF_IB:
304058afdcb7SSean Hefty 		sib = (struct sockaddr_ib *) addr;
304158afdcb7SSean Hefty 		sid = be64_to_cpu(sib->sib_sid);
304258afdcb7SSean Hefty 		mask = be64_to_cpu(sib->sib_sid_mask);
304358afdcb7SSean Hefty 		sib->sib_sid = cpu_to_be64((sid & mask) | (u64) ntohs(port));
304458afdcb7SSean Hefty 		sib->sib_sid_mask = cpu_to_be64(~0ULL);
304558afdcb7SSean Hefty 		break;
304658afdcb7SSean Hefty 	}
3047e51060f0SSean Hefty 	id_priv->bind_list = bind_list;
3048e51060f0SSean Hefty 	hlist_add_head(&id_priv->node, &bind_list->owners);
3049e51060f0SSean Hefty }
3050e51060f0SSean Hefty 
30512253fc0cSSteve Wise static int cma_alloc_port(enum rdma_ucm_port_space ps,
3052aac978e1SHaggai Eran 			  struct rdma_id_private *id_priv, unsigned short snum)
3053e51060f0SSean Hefty {
3054e51060f0SSean Hefty 	struct rdma_bind_list *bind_list;
30553b069c5dSTejun Heo 	int ret;
3056e51060f0SSean Hefty 
3057cb164b8cSSean Hefty 	bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL);
3058e51060f0SSean Hefty 	if (!bind_list)
3059e51060f0SSean Hefty 		return -ENOMEM;
3060e51060f0SSean Hefty 
3061fa20105eSGuy Shapiro 	ret = cma_ps_alloc(id_priv->id.route.addr.dev_addr.net, ps, bind_list,
3062fa20105eSGuy Shapiro 			   snum);
30633b069c5dSTejun Heo 	if (ret < 0)
30643b069c5dSTejun Heo 		goto err;
3065e51060f0SSean Hefty 
3066e51060f0SSean Hefty 	bind_list->ps = ps;
30673b069c5dSTejun Heo 	bind_list->port = (unsigned short)ret;
3068e51060f0SSean Hefty 	cma_bind_port(bind_list, id_priv);
3069e51060f0SSean Hefty 	return 0;
30703b069c5dSTejun Heo err:
3071aedec080SSean Hefty 	kfree(bind_list);
30723b069c5dSTejun Heo 	return ret == -ENOSPC ? -EADDRNOTAVAIL : ret;
3073aedec080SSean Hefty }
3074aedec080SSean Hefty 
307519b752a1SMoni Shoua static int cma_port_is_unique(struct rdma_bind_list *bind_list,
307619b752a1SMoni Shoua 			      struct rdma_id_private *id_priv)
307719b752a1SMoni Shoua {
307819b752a1SMoni Shoua 	struct rdma_id_private *cur_id;
307919b752a1SMoni Shoua 	struct sockaddr  *daddr = cma_dst_addr(id_priv);
308019b752a1SMoni Shoua 	struct sockaddr  *saddr = cma_src_addr(id_priv);
308119b752a1SMoni Shoua 	__be16 dport = cma_port(daddr);
308219b752a1SMoni Shoua 
308319b752a1SMoni Shoua 	hlist_for_each_entry(cur_id, &bind_list->owners, node) {
308419b752a1SMoni Shoua 		struct sockaddr  *cur_daddr = cma_dst_addr(cur_id);
308519b752a1SMoni Shoua 		struct sockaddr  *cur_saddr = cma_src_addr(cur_id);
308619b752a1SMoni Shoua 		__be16 cur_dport = cma_port(cur_daddr);
308719b752a1SMoni Shoua 
308819b752a1SMoni Shoua 		if (id_priv == cur_id)
308919b752a1SMoni Shoua 			continue;
309019b752a1SMoni Shoua 
309119b752a1SMoni Shoua 		/* different dest port -> unique */
30929dea9a2fSTatyana Nikolova 		if (!cma_any_port(daddr) &&
30939dea9a2fSTatyana Nikolova 		    !cma_any_port(cur_daddr) &&
309419b752a1SMoni Shoua 		    (dport != cur_dport))
309519b752a1SMoni Shoua 			continue;
309619b752a1SMoni Shoua 
309719b752a1SMoni Shoua 		/* different src address -> unique */
309819b752a1SMoni Shoua 		if (!cma_any_addr(saddr) &&
309919b752a1SMoni Shoua 		    !cma_any_addr(cur_saddr) &&
310019b752a1SMoni Shoua 		    cma_addr_cmp(saddr, cur_saddr))
310119b752a1SMoni Shoua 			continue;
310219b752a1SMoni Shoua 
310319b752a1SMoni Shoua 		/* different dst address -> unique */
31049dea9a2fSTatyana Nikolova 		if (!cma_any_addr(daddr) &&
31059dea9a2fSTatyana Nikolova 		    !cma_any_addr(cur_daddr) &&
310619b752a1SMoni Shoua 		    cma_addr_cmp(daddr, cur_daddr))
310719b752a1SMoni Shoua 			continue;
310819b752a1SMoni Shoua 
310919b752a1SMoni Shoua 		return -EADDRNOTAVAIL;
311019b752a1SMoni Shoua 	}
311119b752a1SMoni Shoua 	return 0;
311219b752a1SMoni Shoua }
311319b752a1SMoni Shoua 
31142253fc0cSSteve Wise static int cma_alloc_any_port(enum rdma_ucm_port_space ps,
3115aac978e1SHaggai Eran 			      struct rdma_id_private *id_priv)
3116aedec080SSean Hefty {
31175d7220e8STetsuo Handa 	static unsigned int last_used_port;
31185d7220e8STetsuo Handa 	int low, high, remaining;
31195d7220e8STetsuo Handa 	unsigned int rover;
3120fa20105eSGuy Shapiro 	struct net *net = id_priv->id.route.addr.dev_addr.net;
3121aedec080SSean Hefty 
3122fa20105eSGuy Shapiro 	inet_get_local_port_range(net, &low, &high);
31235d7220e8STetsuo Handa 	remaining = (high - low) + 1;
312463862b5bSAruna-Hewapathirane 	rover = prandom_u32() % remaining + low;
31255d7220e8STetsuo Handa retry:
312619b752a1SMoni Shoua 	if (last_used_port != rover) {
312719b752a1SMoni Shoua 		struct rdma_bind_list *bind_list;
312819b752a1SMoni Shoua 		int ret;
312919b752a1SMoni Shoua 
313019b752a1SMoni Shoua 		bind_list = cma_ps_find(net, ps, (unsigned short)rover);
313119b752a1SMoni Shoua 
313219b752a1SMoni Shoua 		if (!bind_list) {
313319b752a1SMoni Shoua 			ret = cma_alloc_port(ps, id_priv, rover);
313419b752a1SMoni Shoua 		} else {
313519b752a1SMoni Shoua 			ret = cma_port_is_unique(bind_list, id_priv);
313619b752a1SMoni Shoua 			if (!ret)
313719b752a1SMoni Shoua 				cma_bind_port(bind_list, id_priv);
313819b752a1SMoni Shoua 		}
31395d7220e8STetsuo Handa 		/*
31405d7220e8STetsuo Handa 		 * Remember previously used port number in order to avoid
31415d7220e8STetsuo Handa 		 * re-using same port immediately after it is closed.
31425d7220e8STetsuo Handa 		 */
31435d7220e8STetsuo Handa 		if (!ret)
31445d7220e8STetsuo Handa 			last_used_port = rover;
31455d7220e8STetsuo Handa 		if (ret != -EADDRNOTAVAIL)
31465d7220e8STetsuo Handa 			return ret;
31475d7220e8STetsuo Handa 	}
31485d7220e8STetsuo Handa 	if (--remaining) {
31495d7220e8STetsuo Handa 		rover++;
31505d7220e8STetsuo Handa 		if ((rover < low) || (rover > high))
31515d7220e8STetsuo Handa 			rover = low;
3152aedec080SSean Hefty 		goto retry;
3153aedec080SSean Hefty 	}
31545d7220e8STetsuo Handa 	return -EADDRNOTAVAIL;
3155e51060f0SSean Hefty }
3156e51060f0SSean Hefty 
3157a9bb7912SHefty, Sean /*
3158a9bb7912SHefty, Sean  * Check that the requested port is available.  This is called when trying to
3159a9bb7912SHefty, Sean  * bind to a specific port, or when trying to listen on a bound port.  In
3160a9bb7912SHefty, Sean  * the latter case, the provided id_priv may already be on the bind_list, but
3161a9bb7912SHefty, Sean  * we still need to check that it's okay to start listening.
3162a9bb7912SHefty, Sean  */
3163a9bb7912SHefty, Sean static int cma_check_port(struct rdma_bind_list *bind_list,
3164a9bb7912SHefty, Sean 			  struct rdma_id_private *id_priv, uint8_t reuseaddr)
3165e51060f0SSean Hefty {
3166e51060f0SSean Hefty 	struct rdma_id_private *cur_id;
316743b752daSHefty, Sean 	struct sockaddr *addr, *cur_addr;
3168e51060f0SSean Hefty 
3169f4753834SSean Hefty 	addr = cma_src_addr(id_priv);
3170b67bfe0dSSasha Levin 	hlist_for_each_entry(cur_id, &bind_list->owners, node) {
3171a9bb7912SHefty, Sean 		if (id_priv == cur_id)
3172a9bb7912SHefty, Sean 			continue;
3173a9bb7912SHefty, Sean 
31745b0ec991SSean Hefty 		if ((cur_id->state != RDMA_CM_LISTEN) && reuseaddr &&
31755b0ec991SSean Hefty 		    cur_id->reuseaddr)
31765b0ec991SSean Hefty 			continue;
31775b0ec991SSean Hefty 
3178f4753834SSean Hefty 		cur_addr = cma_src_addr(cur_id);
31795b0ec991SSean Hefty 		if (id_priv->afonly && cur_id->afonly &&
31805b0ec991SSean Hefty 		    (addr->sa_family != cur_addr->sa_family))
31815b0ec991SSean Hefty 			continue;
31825b0ec991SSean Hefty 
31835b0ec991SSean Hefty 		if (cma_any_addr(addr) || cma_any_addr(cur_addr))
3184e51060f0SSean Hefty 			return -EADDRNOTAVAIL;
3185e51060f0SSean Hefty 
318643b752daSHefty, Sean 		if (!cma_addr_cmp(addr, cur_addr))
3187e51060f0SSean Hefty 			return -EADDRINUSE;
3188e51060f0SSean Hefty 	}
3189e51060f0SSean Hefty 	return 0;
3190e51060f0SSean Hefty }
3191e51060f0SSean Hefty 
31922253fc0cSSteve Wise static int cma_use_port(enum rdma_ucm_port_space ps,
3193aac978e1SHaggai Eran 			struct rdma_id_private *id_priv)
3194a9bb7912SHefty, Sean {
3195a9bb7912SHefty, Sean 	struct rdma_bind_list *bind_list;
3196a9bb7912SHefty, Sean 	unsigned short snum;
3197a9bb7912SHefty, Sean 	int ret;
3198a9bb7912SHefty, Sean 
3199f4753834SSean Hefty 	snum = ntohs(cma_port(cma_src_addr(id_priv)));
3200a9bb7912SHefty, Sean 	if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
3201a9bb7912SHefty, Sean 		return -EACCES;
3202a9bb7912SHefty, Sean 
3203fa20105eSGuy Shapiro 	bind_list = cma_ps_find(id_priv->id.route.addr.dev_addr.net, ps, snum);
3204a9bb7912SHefty, Sean 	if (!bind_list) {
3205a9bb7912SHefty, Sean 		ret = cma_alloc_port(ps, id_priv, snum);
3206a9bb7912SHefty, Sean 	} else {
3207a9bb7912SHefty, Sean 		ret = cma_check_port(bind_list, id_priv, id_priv->reuseaddr);
3208a9bb7912SHefty, Sean 		if (!ret)
3209a9bb7912SHefty, Sean 			cma_bind_port(bind_list, id_priv);
3210a9bb7912SHefty, Sean 	}
3211a9bb7912SHefty, Sean 	return ret;
3212a9bb7912SHefty, Sean }
3213a9bb7912SHefty, Sean 
3214a9bb7912SHefty, Sean static int cma_bind_listen(struct rdma_id_private *id_priv)
3215a9bb7912SHefty, Sean {
3216a9bb7912SHefty, Sean 	struct rdma_bind_list *bind_list = id_priv->bind_list;
3217a9bb7912SHefty, Sean 	int ret = 0;
3218a9bb7912SHefty, Sean 
3219a9bb7912SHefty, Sean 	mutex_lock(&lock);
3220a9bb7912SHefty, Sean 	if (bind_list->owners.first->next)
3221a9bb7912SHefty, Sean 		ret = cma_check_port(bind_list, id_priv, 0);
3222a9bb7912SHefty, Sean 	mutex_unlock(&lock);
3223a9bb7912SHefty, Sean 	return ret;
3224a9bb7912SHefty, Sean }
3225a9bb7912SHefty, Sean 
32262253fc0cSSteve Wise static enum rdma_ucm_port_space
32272253fc0cSSteve Wise cma_select_inet_ps(struct rdma_id_private *id_priv)
322858afdcb7SSean Hefty {
322958afdcb7SSean Hefty 	switch (id_priv->id.ps) {
323058afdcb7SSean Hefty 	case RDMA_PS_TCP:
323158afdcb7SSean Hefty 	case RDMA_PS_UDP:
323258afdcb7SSean Hefty 	case RDMA_PS_IPOIB:
323358afdcb7SSean Hefty 	case RDMA_PS_IB:
3234aac978e1SHaggai Eran 		return id_priv->id.ps;
323558afdcb7SSean Hefty 	default:
3236aac978e1SHaggai Eran 
3237aac978e1SHaggai Eran 		return 0;
323858afdcb7SSean Hefty 	}
323958afdcb7SSean Hefty }
324058afdcb7SSean Hefty 
32412253fc0cSSteve Wise static enum rdma_ucm_port_space
32422253fc0cSSteve Wise cma_select_ib_ps(struct rdma_id_private *id_priv)
324358afdcb7SSean Hefty {
32442253fc0cSSteve Wise 	enum rdma_ucm_port_space ps = 0;
324558afdcb7SSean Hefty 	struct sockaddr_ib *sib;
324658afdcb7SSean Hefty 	u64 sid_ps, mask, sid;
324758afdcb7SSean Hefty 
3248f4753834SSean Hefty 	sib = (struct sockaddr_ib *) cma_src_addr(id_priv);
324958afdcb7SSean Hefty 	mask = be64_to_cpu(sib->sib_sid_mask) & RDMA_IB_IP_PS_MASK;
325058afdcb7SSean Hefty 	sid = be64_to_cpu(sib->sib_sid) & mask;
325158afdcb7SSean Hefty 
325258afdcb7SSean Hefty 	if ((id_priv->id.ps == RDMA_PS_IB) && (sid == (RDMA_IB_IP_PS_IB & mask))) {
325358afdcb7SSean Hefty 		sid_ps = RDMA_IB_IP_PS_IB;
3254aac978e1SHaggai Eran 		ps = RDMA_PS_IB;
325558afdcb7SSean Hefty 	} else if (((id_priv->id.ps == RDMA_PS_IB) || (id_priv->id.ps == RDMA_PS_TCP)) &&
325658afdcb7SSean Hefty 		   (sid == (RDMA_IB_IP_PS_TCP & mask))) {
325758afdcb7SSean Hefty 		sid_ps = RDMA_IB_IP_PS_TCP;
3258aac978e1SHaggai Eran 		ps = RDMA_PS_TCP;
325958afdcb7SSean Hefty 	} else if (((id_priv->id.ps == RDMA_PS_IB) || (id_priv->id.ps == RDMA_PS_UDP)) &&
326058afdcb7SSean Hefty 		   (sid == (RDMA_IB_IP_PS_UDP & mask))) {
326158afdcb7SSean Hefty 		sid_ps = RDMA_IB_IP_PS_UDP;
3262aac978e1SHaggai Eran 		ps = RDMA_PS_UDP;
326358afdcb7SSean Hefty 	}
326458afdcb7SSean Hefty 
326558afdcb7SSean Hefty 	if (ps) {
326658afdcb7SSean Hefty 		sib->sib_sid = cpu_to_be64(sid_ps | ntohs(cma_port((struct sockaddr *) sib)));
326758afdcb7SSean Hefty 		sib->sib_sid_mask = cpu_to_be64(RDMA_IB_IP_PS_MASK |
326858afdcb7SSean Hefty 						be64_to_cpu(sib->sib_sid_mask));
326958afdcb7SSean Hefty 	}
327058afdcb7SSean Hefty 	return ps;
327158afdcb7SSean Hefty }
327258afdcb7SSean Hefty 
3273e51060f0SSean Hefty static int cma_get_port(struct rdma_id_private *id_priv)
3274e51060f0SSean Hefty {
32752253fc0cSSteve Wise 	enum rdma_ucm_port_space ps;
3276e51060f0SSean Hefty 	int ret;
3277e51060f0SSean Hefty 
3278f4753834SSean Hefty 	if (cma_family(id_priv) != AF_IB)
327958afdcb7SSean Hefty 		ps = cma_select_inet_ps(id_priv);
328058afdcb7SSean Hefty 	else
328158afdcb7SSean Hefty 		ps = cma_select_ib_ps(id_priv);
328258afdcb7SSean Hefty 	if (!ps)
3283e51060f0SSean Hefty 		return -EPROTONOSUPPORT;
3284e51060f0SSean Hefty 
3285e51060f0SSean Hefty 	mutex_lock(&lock);
3286f4753834SSean Hefty 	if (cma_any_port(cma_src_addr(id_priv)))
3287aedec080SSean Hefty 		ret = cma_alloc_any_port(ps, id_priv);
3288e51060f0SSean Hefty 	else
3289e51060f0SSean Hefty 		ret = cma_use_port(ps, id_priv);
3290e51060f0SSean Hefty 	mutex_unlock(&lock);
3291e51060f0SSean Hefty 
3292e51060f0SSean Hefty 	return ret;
3293e51060f0SSean Hefty }
3294e51060f0SSean Hefty 
3295d14714dfSSean Hefty static int cma_check_linklocal(struct rdma_dev_addr *dev_addr,
3296d14714dfSSean Hefty 			       struct sockaddr *addr)
3297d14714dfSSean Hefty {
3298d90f9b35SRoland Dreier #if IS_ENABLED(CONFIG_IPV6)
3299d14714dfSSean Hefty 	struct sockaddr_in6 *sin6;
3300d14714dfSSean Hefty 
3301d14714dfSSean Hefty 	if (addr->sa_family != AF_INET6)
3302d14714dfSSean Hefty 		return 0;
3303d14714dfSSean Hefty 
3304d14714dfSSean Hefty 	sin6 = (struct sockaddr_in6 *) addr;
33055462edddSSomnath Kotur 
33065462edddSSomnath Kotur 	if (!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL))
33075462edddSSomnath Kotur 		return 0;
33085462edddSSomnath Kotur 
33095462edddSSomnath Kotur 	if (!sin6->sin6_scope_id)
3310d14714dfSSean Hefty 			return -EINVAL;
3311d14714dfSSean Hefty 
3312d14714dfSSean Hefty 	dev_addr->bound_dev_if = sin6->sin6_scope_id;
3313d14714dfSSean Hefty #endif
3314d14714dfSSean Hefty 	return 0;
3315d14714dfSSean Hefty }
3316d14714dfSSean Hefty 
3317a9bb7912SHefty, Sean int rdma_listen(struct rdma_cm_id *id, int backlog)
3318a9bb7912SHefty, Sean {
3319a9bb7912SHefty, Sean 	struct rdma_id_private *id_priv;
3320a9bb7912SHefty, Sean 	int ret;
3321a9bb7912SHefty, Sean 
3322a9bb7912SHefty, Sean 	id_priv = container_of(id, struct rdma_id_private, id);
3323550e5ca7SNir Muchtar 	if (id_priv->state == RDMA_CM_IDLE) {
3324f4753834SSean Hefty 		id->route.addr.src_addr.ss_family = AF_INET;
3325f4753834SSean Hefty 		ret = rdma_bind_addr(id, cma_src_addr(id_priv));
3326a9bb7912SHefty, Sean 		if (ret)
3327a9bb7912SHefty, Sean 			return ret;
3328a9bb7912SHefty, Sean 	}
3329a9bb7912SHefty, Sean 
3330550e5ca7SNir Muchtar 	if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_LISTEN))
3331a9bb7912SHefty, Sean 		return -EINVAL;
3332a9bb7912SHefty, Sean 
3333a9bb7912SHefty, Sean 	if (id_priv->reuseaddr) {
3334a9bb7912SHefty, Sean 		ret = cma_bind_listen(id_priv);
3335a9bb7912SHefty, Sean 		if (ret)
3336a9bb7912SHefty, Sean 			goto err;
3337a9bb7912SHefty, Sean 	}
3338a9bb7912SHefty, Sean 
3339a9bb7912SHefty, Sean 	id_priv->backlog = backlog;
3340a9bb7912SHefty, Sean 	if (id->device) {
334172219ceaSMichael Wang 		if (rdma_cap_ib_cm(id->device, 1)) {
3342a9bb7912SHefty, Sean 			ret = cma_ib_listen(id_priv);
3343a9bb7912SHefty, Sean 			if (ret)
3344a9bb7912SHefty, Sean 				goto err;
334504215330SMichael Wang 		} else if (rdma_cap_iw_cm(id->device, 1)) {
3346a9bb7912SHefty, Sean 			ret = cma_iw_listen(id_priv, backlog);
3347a9bb7912SHefty, Sean 			if (ret)
3348a9bb7912SHefty, Sean 				goto err;
334921655afcSMichael Wang 		} else {
3350a9bb7912SHefty, Sean 			ret = -ENOSYS;
3351a9bb7912SHefty, Sean 			goto err;
3352a9bb7912SHefty, Sean 		}
3353a9bb7912SHefty, Sean 	} else
3354a9bb7912SHefty, Sean 		cma_listen_on_all(id_priv);
3355a9bb7912SHefty, Sean 
3356a9bb7912SHefty, Sean 	return 0;
3357a9bb7912SHefty, Sean err:
3358a9bb7912SHefty, Sean 	id_priv->backlog = 0;
3359550e5ca7SNir Muchtar 	cma_comp_exch(id_priv, RDMA_CM_LISTEN, RDMA_CM_ADDR_BOUND);
3360a9bb7912SHefty, Sean 	return ret;
3361a9bb7912SHefty, Sean }
3362a9bb7912SHefty, Sean EXPORT_SYMBOL(rdma_listen);
3363a9bb7912SHefty, Sean 
3364e51060f0SSean Hefty int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
3365e51060f0SSean Hefty {
3366e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
3367e51060f0SSean Hefty 	int ret;
33686df6b4a9SMoni Shoua 	struct sockaddr  *daddr;
3369e51060f0SSean Hefty 
3370680f920aSSean Hefty 	if (addr->sa_family != AF_INET && addr->sa_family != AF_INET6 &&
3371680f920aSSean Hefty 	    addr->sa_family != AF_IB)
3372e51060f0SSean Hefty 		return -EAFNOSUPPORT;
3373e51060f0SSean Hefty 
3374e51060f0SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
3375550e5ca7SNir Muchtar 	if (!cma_comp_exch(id_priv, RDMA_CM_IDLE, RDMA_CM_ADDR_BOUND))
3376e51060f0SSean Hefty 		return -EINVAL;
3377e51060f0SSean Hefty 
3378d14714dfSSean Hefty 	ret = cma_check_linklocal(&id->route.addr.dev_addr, addr);
3379d14714dfSSean Hefty 	if (ret)
3380d14714dfSSean Hefty 		goto err1;
3381d14714dfSSean Hefty 
33827b85627bSMoni Shoua 	memcpy(cma_src_addr(id_priv), addr, rdma_addr_size(addr));
33838523c048SSean Hefty 	if (!cma_any_addr(addr)) {
3384680f920aSSean Hefty 		ret = cma_translate_addr(addr, &id->route.addr.dev_addr);
3385255d0c14SKrishna Kumar 		if (ret)
3386255d0c14SKrishna Kumar 			goto err1;
3387255d0c14SKrishna Kumar 
3388be9130ccSDoug Ledford 		ret = cma_acquire_dev(id_priv, NULL);
3389e51060f0SSean Hefty 		if (ret)
3390255d0c14SKrishna Kumar 			goto err1;
3391e51060f0SSean Hefty 	}
3392e51060f0SSean Hefty 
339368602120SSean Hefty 	if (!(id_priv->options & (1 << CMA_OPTION_AFONLY))) {
33945b0ec991SSean Hefty 		if (addr->sa_family == AF_INET)
33955b0ec991SSean Hefty 			id_priv->afonly = 1;
33965b0ec991SSean Hefty #if IS_ENABLED(CONFIG_IPV6)
3397fa20105eSGuy Shapiro 		else if (addr->sa_family == AF_INET6) {
3398fa20105eSGuy Shapiro 			struct net *net = id_priv->id.route.addr.dev_addr.net;
3399fa20105eSGuy Shapiro 
3400fa20105eSGuy Shapiro 			id_priv->afonly = net->ipv6.sysctl.bindv6only;
3401fa20105eSGuy Shapiro 		}
34025b0ec991SSean Hefty #endif
340368602120SSean Hefty 	}
34049dea9a2fSTatyana Nikolova 	daddr = cma_dst_addr(id_priv);
34059dea9a2fSTatyana Nikolova 	daddr->sa_family = addr->sa_family;
34069dea9a2fSTatyana Nikolova 
3407e51060f0SSean Hefty 	ret = cma_get_port(id_priv);
3408e51060f0SSean Hefty 	if (ret)
3409255d0c14SKrishna Kumar 		goto err2;
3410e51060f0SSean Hefty 
3411e51060f0SSean Hefty 	return 0;
3412255d0c14SKrishna Kumar err2:
341300313983SSteve Wise 	if (id_priv->cma_dev) {
341400313983SSteve Wise 		rdma_restrack_del(&id_priv->res);
3415a396d43aSSean Hefty 		cma_release_dev(id_priv);
341600313983SSteve Wise 	}
3417255d0c14SKrishna Kumar err1:
3418550e5ca7SNir Muchtar 	cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_IDLE);
3419e51060f0SSean Hefty 	return ret;
3420e51060f0SSean Hefty }
3421e51060f0SSean Hefty EXPORT_SYMBOL(rdma_bind_addr);
3422e51060f0SSean Hefty 
3423f4753834SSean Hefty static int cma_format_hdr(void *hdr, struct rdma_id_private *id_priv)
3424e51060f0SSean Hefty {
3425e51060f0SSean Hefty 	struct cma_hdr *cma_hdr;
3426e51060f0SSean Hefty 
342701602f11SSean Hefty 	cma_hdr = hdr;
342801602f11SSean Hefty 	cma_hdr->cma_version = CMA_VERSION;
3429f4753834SSean Hefty 	if (cma_family(id_priv) == AF_INET) {
34301f5175adSAleksey Senin 		struct sockaddr_in *src4, *dst4;
34311f5175adSAleksey Senin 
3432f4753834SSean Hefty 		src4 = (struct sockaddr_in *) cma_src_addr(id_priv);
3433f4753834SSean Hefty 		dst4 = (struct sockaddr_in *) cma_dst_addr(id_priv);
3434e51060f0SSean Hefty 
3435e51060f0SSean Hefty 		cma_set_ip_ver(cma_hdr, 4);
3436e51060f0SSean Hefty 		cma_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr;
3437e51060f0SSean Hefty 		cma_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr;
3438e51060f0SSean Hefty 		cma_hdr->port = src4->sin_port;
3439e8160e15SSean Hefty 	} else if (cma_family(id_priv) == AF_INET6) {
34401f5175adSAleksey Senin 		struct sockaddr_in6 *src6, *dst6;
34411f5175adSAleksey Senin 
3442f4753834SSean Hefty 		src6 = (struct sockaddr_in6 *) cma_src_addr(id_priv);
3443f4753834SSean Hefty 		dst6 = (struct sockaddr_in6 *) cma_dst_addr(id_priv);
34441f5175adSAleksey Senin 
34451f5175adSAleksey Senin 		cma_set_ip_ver(cma_hdr, 6);
34461f5175adSAleksey Senin 		cma_hdr->src_addr.ip6 = src6->sin6_addr;
34471f5175adSAleksey Senin 		cma_hdr->dst_addr.ip6 = dst6->sin6_addr;
34481f5175adSAleksey Senin 		cma_hdr->port = src6->sin6_port;
34491f5175adSAleksey Senin 	}
3450e51060f0SSean Hefty 	return 0;
3451e51060f0SSean Hefty }
3452e51060f0SSean Hefty 
3453628e5f6dSSean Hefty static int cma_sidr_rep_handler(struct ib_cm_id *cm_id,
3454628e5f6dSSean Hefty 				struct ib_cm_event *ib_event)
3455628e5f6dSSean Hefty {
3456628e5f6dSSean Hefty 	struct rdma_id_private *id_priv = cm_id->context;
3457628e5f6dSSean Hefty 	struct rdma_cm_event event;
3458628e5f6dSSean Hefty 	struct ib_cm_sidr_rep_event_param *rep = &ib_event->param.sidr_rep_rcvd;
3459628e5f6dSSean Hefty 	int ret = 0;
3460628e5f6dSSean Hefty 
346137e07cdaSBart Van Assche 	mutex_lock(&id_priv->handler_mutex);
346237e07cdaSBart Van Assche 	if (id_priv->state != RDMA_CM_CONNECT)
346337e07cdaSBart Van Assche 		goto out;
3464628e5f6dSSean Hefty 
34658aa08602SSean Hefty 	memset(&event, 0, sizeof event);
3466628e5f6dSSean Hefty 	switch (ib_event->event) {
3467628e5f6dSSean Hefty 	case IB_CM_SIDR_REQ_ERROR:
3468628e5f6dSSean Hefty 		event.event = RDMA_CM_EVENT_UNREACHABLE;
3469628e5f6dSSean Hefty 		event.status = -ETIMEDOUT;
3470628e5f6dSSean Hefty 		break;
3471628e5f6dSSean Hefty 	case IB_CM_SIDR_REP_RECEIVED:
3472628e5f6dSSean Hefty 		event.param.ud.private_data = ib_event->private_data;
3473628e5f6dSSean Hefty 		event.param.ud.private_data_len = IB_CM_SIDR_REP_PRIVATE_DATA_SIZE;
3474628e5f6dSSean Hefty 		if (rep->status != IB_SIDR_SUCCESS) {
3475628e5f6dSSean Hefty 			event.event = RDMA_CM_EVENT_UNREACHABLE;
3476628e5f6dSSean Hefty 			event.status = ib_event->param.sidr_rep_rcvd.status;
3477498683c6SMoni Shoua 			pr_debug_ratelimited("RDMA CM: UNREACHABLE: bad SIDR reply. status %d\n",
3478498683c6SMoni Shoua 					     event.status);
3479628e5f6dSSean Hefty 			break;
3480628e5f6dSSean Hefty 		}
34815c438135SSean Hefty 		ret = cma_set_qkey(id_priv, rep->qkey);
3482d2ca39f2SYossi Etigin 		if (ret) {
3483498683c6SMoni Shoua 			pr_debug_ratelimited("RDMA CM: ADDR_ERROR: failed to set qkey. status %d\n", ret);
3484d2ca39f2SYossi Etigin 			event.event = RDMA_CM_EVENT_ADDR_ERROR;
34855c438135SSean Hefty 			event.status = ret;
3486628e5f6dSSean Hefty 			break;
3487628e5f6dSSean Hefty 		}
34884ad6a024SParav Pandit 		ib_init_ah_attr_from_path(id_priv->id.device,
34894ad6a024SParav Pandit 					  id_priv->id.port_num,
3490628e5f6dSSean Hefty 					  id_priv->id.route.path_rec,
3491628e5f6dSSean Hefty 					  &event.param.ud.ah_attr);
3492628e5f6dSSean Hefty 		event.param.ud.qp_num = rep->qpn;
3493628e5f6dSSean Hefty 		event.param.ud.qkey = rep->qkey;
3494628e5f6dSSean Hefty 		event.event = RDMA_CM_EVENT_ESTABLISHED;
3495628e5f6dSSean Hefty 		event.status = 0;
3496628e5f6dSSean Hefty 		break;
3497628e5f6dSSean Hefty 	default:
3498aba25a3eSParav Pandit 		pr_err("RDMA CMA: unexpected IB CM event: %d\n",
3499628e5f6dSSean Hefty 		       ib_event->event);
3500628e5f6dSSean Hefty 		goto out;
3501628e5f6dSSean Hefty 	}
3502628e5f6dSSean Hefty 
3503628e5f6dSSean Hefty 	ret = id_priv->id.event_handler(&id_priv->id, &event);
3504628e5f6dSSean Hefty 	if (ret) {
3505628e5f6dSSean Hefty 		/* Destroy the CM ID by returning a non-zero value. */
3506628e5f6dSSean Hefty 		id_priv->cm_id.ib = NULL;
3507550e5ca7SNir Muchtar 		cma_exch(id_priv, RDMA_CM_DESTROYING);
3508de910bd9SOr Gerlitz 		mutex_unlock(&id_priv->handler_mutex);
3509628e5f6dSSean Hefty 		rdma_destroy_id(&id_priv->id);
3510628e5f6dSSean Hefty 		return ret;
3511628e5f6dSSean Hefty 	}
3512628e5f6dSSean Hefty out:
3513de910bd9SOr Gerlitz 	mutex_unlock(&id_priv->handler_mutex);
3514628e5f6dSSean Hefty 	return ret;
3515628e5f6dSSean Hefty }
3516628e5f6dSSean Hefty 
3517628e5f6dSSean Hefty static int cma_resolve_ib_udp(struct rdma_id_private *id_priv,
3518628e5f6dSSean Hefty 			      struct rdma_conn_param *conn_param)
3519628e5f6dSSean Hefty {
3520628e5f6dSSean Hefty 	struct ib_cm_sidr_req_param req;
35210c9361fcSJack Morgenstein 	struct ib_cm_id	*id;
3522e511d1aeSSean Hefty 	void *private_data;
3523c0b64f58SBart Van Assche 	u8 offset;
3524c0b64f58SBart Van Assche 	int ret;
3525628e5f6dSSean Hefty 
3526e511d1aeSSean Hefty 	memset(&req, 0, sizeof req);
3527e8160e15SSean Hefty 	offset = cma_user_data_offset(id_priv);
3528e8160e15SSean Hefty 	req.private_data_len = offset + conn_param->private_data_len;
352904ded167SSean Hefty 	if (req.private_data_len < conn_param->private_data_len)
353004ded167SSean Hefty 		return -EINVAL;
353104ded167SSean Hefty 
3532e8160e15SSean Hefty 	if (req.private_data_len) {
3533e511d1aeSSean Hefty 		private_data = kzalloc(req.private_data_len, GFP_ATOMIC);
3534e511d1aeSSean Hefty 		if (!private_data)
3535628e5f6dSSean Hefty 			return -ENOMEM;
3536e8160e15SSean Hefty 	} else {
3537e511d1aeSSean Hefty 		private_data = NULL;
3538e8160e15SSean Hefty 	}
3539628e5f6dSSean Hefty 
3540628e5f6dSSean Hefty 	if (conn_param->private_data && conn_param->private_data_len)
3541e511d1aeSSean Hefty 		memcpy(private_data + offset, conn_param->private_data,
3542e511d1aeSSean Hefty 		       conn_param->private_data_len);
3543628e5f6dSSean Hefty 
3544e511d1aeSSean Hefty 	if (private_data) {
3545e511d1aeSSean Hefty 		ret = cma_format_hdr(private_data, id_priv);
3546628e5f6dSSean Hefty 		if (ret)
3547628e5f6dSSean Hefty 			goto out;
3548e511d1aeSSean Hefty 		req.private_data = private_data;
3549e8160e15SSean Hefty 	}
3550628e5f6dSSean Hefty 
35510c9361fcSJack Morgenstein 	id = ib_create_cm_id(id_priv->id.device, cma_sidr_rep_handler,
35520c9361fcSJack Morgenstein 			     id_priv);
35530c9361fcSJack Morgenstein 	if (IS_ERR(id)) {
35540c9361fcSJack Morgenstein 		ret = PTR_ERR(id);
3555628e5f6dSSean Hefty 		goto out;
3556628e5f6dSSean Hefty 	}
35570c9361fcSJack Morgenstein 	id_priv->cm_id.ib = id;
3558628e5f6dSSean Hefty 
3559f4753834SSean Hefty 	req.path = id_priv->id.route.path_rec;
3560cf53936fSSean Hefty 	req.service_id = rdma_get_service_id(&id_priv->id, cma_dst_addr(id_priv));
3561628e5f6dSSean Hefty 	req.timeout_ms = 1 << (CMA_CM_RESPONSE_TIMEOUT - 8);
3562628e5f6dSSean Hefty 	req.max_cm_retries = CMA_MAX_CM_RETRIES;
3563628e5f6dSSean Hefty 
3564628e5f6dSSean Hefty 	ret = ib_send_cm_sidr_req(id_priv->cm_id.ib, &req);
3565628e5f6dSSean Hefty 	if (ret) {
3566628e5f6dSSean Hefty 		ib_destroy_cm_id(id_priv->cm_id.ib);
3567628e5f6dSSean Hefty 		id_priv->cm_id.ib = NULL;
3568628e5f6dSSean Hefty 	}
3569628e5f6dSSean Hefty out:
3570e511d1aeSSean Hefty 	kfree(private_data);
3571628e5f6dSSean Hefty 	return ret;
3572628e5f6dSSean Hefty }
3573628e5f6dSSean Hefty 
3574e51060f0SSean Hefty static int cma_connect_ib(struct rdma_id_private *id_priv,
3575e51060f0SSean Hefty 			  struct rdma_conn_param *conn_param)
3576e51060f0SSean Hefty {
3577e51060f0SSean Hefty 	struct ib_cm_req_param req;
3578e51060f0SSean Hefty 	struct rdma_route *route;
3579e51060f0SSean Hefty 	void *private_data;
35800c9361fcSJack Morgenstein 	struct ib_cm_id	*id;
3581c0b64f58SBart Van Assche 	u8 offset;
3582c0b64f58SBart Van Assche 	int ret;
3583e51060f0SSean Hefty 
3584e51060f0SSean Hefty 	memset(&req, 0, sizeof req);
3585e8160e15SSean Hefty 	offset = cma_user_data_offset(id_priv);
3586e51060f0SSean Hefty 	req.private_data_len = offset + conn_param->private_data_len;
358704ded167SSean Hefty 	if (req.private_data_len < conn_param->private_data_len)
358804ded167SSean Hefty 		return -EINVAL;
358904ded167SSean Hefty 
3590e8160e15SSean Hefty 	if (req.private_data_len) {
3591e51060f0SSean Hefty 		private_data = kzalloc(req.private_data_len, GFP_ATOMIC);
3592e51060f0SSean Hefty 		if (!private_data)
3593e51060f0SSean Hefty 			return -ENOMEM;
3594e8160e15SSean Hefty 	} else {
3595e8160e15SSean Hefty 		private_data = NULL;
3596e8160e15SSean Hefty 	}
3597e51060f0SSean Hefty 
3598e51060f0SSean Hefty 	if (conn_param->private_data && conn_param->private_data_len)
3599e51060f0SSean Hefty 		memcpy(private_data + offset, conn_param->private_data,
3600e51060f0SSean Hefty 		       conn_param->private_data_len);
3601e51060f0SSean Hefty 
36020c9361fcSJack Morgenstein 	id = ib_create_cm_id(id_priv->id.device, cma_ib_handler, id_priv);
36030c9361fcSJack Morgenstein 	if (IS_ERR(id)) {
36040c9361fcSJack Morgenstein 		ret = PTR_ERR(id);
3605e51060f0SSean Hefty 		goto out;
3606e51060f0SSean Hefty 	}
36070c9361fcSJack Morgenstein 	id_priv->cm_id.ib = id;
3608e51060f0SSean Hefty 
3609e51060f0SSean Hefty 	route = &id_priv->id.route;
3610e8160e15SSean Hefty 	if (private_data) {
3611f4753834SSean Hefty 		ret = cma_format_hdr(private_data, id_priv);
3612e51060f0SSean Hefty 		if (ret)
3613e51060f0SSean Hefty 			goto out;
3614e51060f0SSean Hefty 		req.private_data = private_data;
3615e8160e15SSean Hefty 	}
3616e51060f0SSean Hefty 
3617e51060f0SSean Hefty 	req.primary_path = &route->path_rec[0];
3618e51060f0SSean Hefty 	if (route->num_paths == 2)
3619e51060f0SSean Hefty 		req.alternate_path = &route->path_rec[1];
3620e51060f0SSean Hefty 
3621cf53936fSSean Hefty 	req.service_id = rdma_get_service_id(&id_priv->id, cma_dst_addr(id_priv));
3622e51060f0SSean Hefty 	req.qp_num = id_priv->qp_num;
362318c441a6SSean Hefty 	req.qp_type = id_priv->id.qp_type;
3624e51060f0SSean Hefty 	req.starting_psn = id_priv->seq_num;
3625e51060f0SSean Hefty 	req.responder_resources = conn_param->responder_resources;
3626e51060f0SSean Hefty 	req.initiator_depth = conn_param->initiator_depth;
3627e51060f0SSean Hefty 	req.flow_control = conn_param->flow_control;
36284ede178aSSean Hefty 	req.retry_count = min_t(u8, 7, conn_param->retry_count);
36294ede178aSSean Hefty 	req.rnr_retry_count = min_t(u8, 7, conn_param->rnr_retry_count);
3630e51060f0SSean Hefty 	req.remote_cm_response_timeout = CMA_CM_RESPONSE_TIMEOUT;
3631e51060f0SSean Hefty 	req.local_cm_response_timeout = CMA_CM_RESPONSE_TIMEOUT;
3632e51060f0SSean Hefty 	req.max_cm_retries = CMA_MAX_CM_RETRIES;
3633e51060f0SSean Hefty 	req.srq = id_priv->srq ? 1 : 0;
3634e51060f0SSean Hefty 
3635e51060f0SSean Hefty 	ret = ib_send_cm_req(id_priv->cm_id.ib, &req);
3636e51060f0SSean Hefty out:
36370c9361fcSJack Morgenstein 	if (ret && !IS_ERR(id)) {
36380c9361fcSJack Morgenstein 		ib_destroy_cm_id(id);
3639675a027cSKrishna Kumar 		id_priv->cm_id.ib = NULL;
3640675a027cSKrishna Kumar 	}
3641675a027cSKrishna Kumar 
3642e51060f0SSean Hefty 	kfree(private_data);
3643e51060f0SSean Hefty 	return ret;
3644e51060f0SSean Hefty }
3645e51060f0SSean Hefty 
364607ebafbaSTom Tucker static int cma_connect_iw(struct rdma_id_private *id_priv,
364707ebafbaSTom Tucker 			  struct rdma_conn_param *conn_param)
364807ebafbaSTom Tucker {
364907ebafbaSTom Tucker 	struct iw_cm_id *cm_id;
365007ebafbaSTom Tucker 	int ret;
365107ebafbaSTom Tucker 	struct iw_cm_conn_param iw_param;
365207ebafbaSTom Tucker 
365307ebafbaSTom Tucker 	cm_id = iw_create_cm_id(id_priv->id.device, cma_iw_handler, id_priv);
36540c9361fcSJack Morgenstein 	if (IS_ERR(cm_id))
36550c9361fcSJack Morgenstein 		return PTR_ERR(cm_id);
365607ebafbaSTom Tucker 
365768cdba06SSteve Wise 	cm_id->tos = id_priv->tos;
365807ebafbaSTom Tucker 	id_priv->cm_id.iw = cm_id;
365907ebafbaSTom Tucker 
366024d44a39SSteve Wise 	memcpy(&cm_id->local_addr, cma_src_addr(id_priv),
366124d44a39SSteve Wise 	       rdma_addr_size(cma_src_addr(id_priv)));
366224d44a39SSteve Wise 	memcpy(&cm_id->remote_addr, cma_dst_addr(id_priv),
366324d44a39SSteve Wise 	       rdma_addr_size(cma_dst_addr(id_priv)));
366407ebafbaSTom Tucker 
36655851bb89SSean Hefty 	ret = cma_modify_qp_rtr(id_priv, conn_param);
3666675a027cSKrishna Kumar 	if (ret)
3667675a027cSKrishna Kumar 		goto out;
366807ebafbaSTom Tucker 
3669f45ee80eSHefty, Sean 	if (conn_param) {
367007ebafbaSTom Tucker 		iw_param.ord = conn_param->initiator_depth;
367107ebafbaSTom Tucker 		iw_param.ird = conn_param->responder_resources;
367207ebafbaSTom Tucker 		iw_param.private_data = conn_param->private_data;
367307ebafbaSTom Tucker 		iw_param.private_data_len = conn_param->private_data_len;
3674f45ee80eSHefty, Sean 		iw_param.qpn = id_priv->id.qp ? id_priv->qp_num : conn_param->qp_num;
3675f45ee80eSHefty, Sean 	} else {
3676f45ee80eSHefty, Sean 		memset(&iw_param, 0, sizeof iw_param);
367707ebafbaSTom Tucker 		iw_param.qpn = id_priv->qp_num;
3678f45ee80eSHefty, Sean 	}
367907ebafbaSTom Tucker 	ret = iw_cm_connect(cm_id, &iw_param);
368007ebafbaSTom Tucker out:
36810c9361fcSJack Morgenstein 	if (ret) {
3682675a027cSKrishna Kumar 		iw_destroy_cm_id(cm_id);
3683675a027cSKrishna Kumar 		id_priv->cm_id.iw = NULL;
3684675a027cSKrishna Kumar 	}
368507ebafbaSTom Tucker 	return ret;
368607ebafbaSTom Tucker }
368707ebafbaSTom Tucker 
3688e51060f0SSean Hefty int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
3689e51060f0SSean Hefty {
3690e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
3691e51060f0SSean Hefty 	int ret;
3692e51060f0SSean Hefty 
3693e51060f0SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
3694550e5ca7SNir Muchtar 	if (!cma_comp_exch(id_priv, RDMA_CM_ROUTE_RESOLVED, RDMA_CM_CONNECT))
3695e51060f0SSean Hefty 		return -EINVAL;
3696e51060f0SSean Hefty 
3697e51060f0SSean Hefty 	if (!id->qp) {
3698e51060f0SSean Hefty 		id_priv->qp_num = conn_param->qp_num;
3699e51060f0SSean Hefty 		id_priv->srq = conn_param->srq;
3700e51060f0SSean Hefty 	}
3701e51060f0SSean Hefty 
370272219ceaSMichael Wang 	if (rdma_cap_ib_cm(id->device, id->port_num)) {
3703b26f9b99SSean Hefty 		if (id->qp_type == IB_QPT_UD)
3704628e5f6dSSean Hefty 			ret = cma_resolve_ib_udp(id_priv, conn_param);
3705628e5f6dSSean Hefty 		else
3706e51060f0SSean Hefty 			ret = cma_connect_ib(id_priv, conn_param);
370704215330SMichael Wang 	} else if (rdma_cap_iw_cm(id->device, id->port_num))
370807ebafbaSTom Tucker 		ret = cma_connect_iw(id_priv, conn_param);
370921655afcSMichael Wang 	else
3710e51060f0SSean Hefty 		ret = -ENOSYS;
3711e51060f0SSean Hefty 	if (ret)
3712e51060f0SSean Hefty 		goto err;
3713e51060f0SSean Hefty 
3714e51060f0SSean Hefty 	return 0;
3715e51060f0SSean Hefty err:
3716550e5ca7SNir Muchtar 	cma_comp_exch(id_priv, RDMA_CM_CONNECT, RDMA_CM_ROUTE_RESOLVED);
3717e51060f0SSean Hefty 	return ret;
3718e51060f0SSean Hefty }
3719e51060f0SSean Hefty EXPORT_SYMBOL(rdma_connect);
3720e51060f0SSean Hefty 
3721e51060f0SSean Hefty static int cma_accept_ib(struct rdma_id_private *id_priv,
3722e51060f0SSean Hefty 			 struct rdma_conn_param *conn_param)
3723e51060f0SSean Hefty {
3724e51060f0SSean Hefty 	struct ib_cm_rep_param rep;
37255851bb89SSean Hefty 	int ret;
3726e51060f0SSean Hefty 
37275851bb89SSean Hefty 	ret = cma_modify_qp_rtr(id_priv, conn_param);
3728e51060f0SSean Hefty 	if (ret)
37290fe313b0SSean Hefty 		goto out;
37300fe313b0SSean Hefty 
37315851bb89SSean Hefty 	ret = cma_modify_qp_rts(id_priv, conn_param);
37320fe313b0SSean Hefty 	if (ret)
37330fe313b0SSean Hefty 		goto out;
37340fe313b0SSean Hefty 
3735e51060f0SSean Hefty 	memset(&rep, 0, sizeof rep);
3736e51060f0SSean Hefty 	rep.qp_num = id_priv->qp_num;
3737e51060f0SSean Hefty 	rep.starting_psn = id_priv->seq_num;
3738e51060f0SSean Hefty 	rep.private_data = conn_param->private_data;
3739e51060f0SSean Hefty 	rep.private_data_len = conn_param->private_data_len;
3740e51060f0SSean Hefty 	rep.responder_resources = conn_param->responder_resources;
3741e51060f0SSean Hefty 	rep.initiator_depth = conn_param->initiator_depth;
3742e51060f0SSean Hefty 	rep.failover_accepted = 0;
3743e51060f0SSean Hefty 	rep.flow_control = conn_param->flow_control;
37444ede178aSSean Hefty 	rep.rnr_retry_count = min_t(u8, 7, conn_param->rnr_retry_count);
3745e51060f0SSean Hefty 	rep.srq = id_priv->srq ? 1 : 0;
3746e51060f0SSean Hefty 
37470fe313b0SSean Hefty 	ret = ib_send_cm_rep(id_priv->cm_id.ib, &rep);
37480fe313b0SSean Hefty out:
37490fe313b0SSean Hefty 	return ret;
3750e51060f0SSean Hefty }
3751e51060f0SSean Hefty 
375207ebafbaSTom Tucker static int cma_accept_iw(struct rdma_id_private *id_priv,
375307ebafbaSTom Tucker 		  struct rdma_conn_param *conn_param)
375407ebafbaSTom Tucker {
375507ebafbaSTom Tucker 	struct iw_cm_conn_param iw_param;
375607ebafbaSTom Tucker 	int ret;
375707ebafbaSTom Tucker 
3758f2625f7dSSteve Wise 	if (!conn_param)
3759f2625f7dSSteve Wise 		return -EINVAL;
3760f2625f7dSSteve Wise 
37615851bb89SSean Hefty 	ret = cma_modify_qp_rtr(id_priv, conn_param);
376207ebafbaSTom Tucker 	if (ret)
376307ebafbaSTom Tucker 		return ret;
376407ebafbaSTom Tucker 
376507ebafbaSTom Tucker 	iw_param.ord = conn_param->initiator_depth;
376607ebafbaSTom Tucker 	iw_param.ird = conn_param->responder_resources;
376707ebafbaSTom Tucker 	iw_param.private_data = conn_param->private_data;
376807ebafbaSTom Tucker 	iw_param.private_data_len = conn_param->private_data_len;
376907ebafbaSTom Tucker 	if (id_priv->id.qp) {
377007ebafbaSTom Tucker 		iw_param.qpn = id_priv->qp_num;
377107ebafbaSTom Tucker 	} else
377207ebafbaSTom Tucker 		iw_param.qpn = conn_param->qp_num;
377307ebafbaSTom Tucker 
377407ebafbaSTom Tucker 	return iw_cm_accept(id_priv->cm_id.iw, &iw_param);
377507ebafbaSTom Tucker }
377607ebafbaSTom Tucker 
3777628e5f6dSSean Hefty static int cma_send_sidr_rep(struct rdma_id_private *id_priv,
37785c438135SSean Hefty 			     enum ib_cm_sidr_status status, u32 qkey,
3779628e5f6dSSean Hefty 			     const void *private_data, int private_data_len)
3780628e5f6dSSean Hefty {
3781628e5f6dSSean Hefty 	struct ib_cm_sidr_rep_param rep;
3782d2ca39f2SYossi Etigin 	int ret;
3783628e5f6dSSean Hefty 
3784628e5f6dSSean Hefty 	memset(&rep, 0, sizeof rep);
3785628e5f6dSSean Hefty 	rep.status = status;
3786628e5f6dSSean Hefty 	if (status == IB_SIDR_SUCCESS) {
37875c438135SSean Hefty 		ret = cma_set_qkey(id_priv, qkey);
3788d2ca39f2SYossi Etigin 		if (ret)
3789d2ca39f2SYossi Etigin 			return ret;
3790628e5f6dSSean Hefty 		rep.qp_num = id_priv->qp_num;
3791c8f6a362SSean Hefty 		rep.qkey = id_priv->qkey;
3792628e5f6dSSean Hefty 	}
3793628e5f6dSSean Hefty 	rep.private_data = private_data;
3794628e5f6dSSean Hefty 	rep.private_data_len = private_data_len;
3795628e5f6dSSean Hefty 
3796628e5f6dSSean Hefty 	return ib_send_cm_sidr_rep(id_priv->cm_id.ib, &rep);
3797628e5f6dSSean Hefty }
3798628e5f6dSSean Hefty 
379900313983SSteve Wise int __rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param,
380000313983SSteve Wise 		  const char *caller)
3801e51060f0SSean Hefty {
3802e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
3803e51060f0SSean Hefty 	int ret;
3804e51060f0SSean Hefty 
3805e51060f0SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
380683e9502dSNir Muchtar 
380700313983SSteve Wise 	if (caller)
380800313983SSteve Wise 		id_priv->res.kern_name = caller;
380900313983SSteve Wise 	else
381000313983SSteve Wise 		rdma_restrack_set_task(&id_priv->res, current);
381183e9502dSNir Muchtar 
3812550e5ca7SNir Muchtar 	if (!cma_comp(id_priv, RDMA_CM_CONNECT))
3813e51060f0SSean Hefty 		return -EINVAL;
3814e51060f0SSean Hefty 
3815e51060f0SSean Hefty 	if (!id->qp && conn_param) {
3816e51060f0SSean Hefty 		id_priv->qp_num = conn_param->qp_num;
3817e51060f0SSean Hefty 		id_priv->srq = conn_param->srq;
3818e51060f0SSean Hefty 	}
3819e51060f0SSean Hefty 
382072219ceaSMichael Wang 	if (rdma_cap_ib_cm(id->device, id->port_num)) {
3821f45ee80eSHefty, Sean 		if (id->qp_type == IB_QPT_UD) {
3822f45ee80eSHefty, Sean 			if (conn_param)
3823628e5f6dSSean Hefty 				ret = cma_send_sidr_rep(id_priv, IB_SIDR_SUCCESS,
38245c438135SSean Hefty 							conn_param->qkey,
3825628e5f6dSSean Hefty 							conn_param->private_data,
3826628e5f6dSSean Hefty 							conn_param->private_data_len);
3827f45ee80eSHefty, Sean 			else
3828f45ee80eSHefty, Sean 				ret = cma_send_sidr_rep(id_priv, IB_SIDR_SUCCESS,
38295c438135SSean Hefty 							0, NULL, 0);
3830f45ee80eSHefty, Sean 		} else {
3831f45ee80eSHefty, Sean 			if (conn_param)
3832e51060f0SSean Hefty 				ret = cma_accept_ib(id_priv, conn_param);
3833e51060f0SSean Hefty 			else
3834e51060f0SSean Hefty 				ret = cma_rep_recv(id_priv);
3835f45ee80eSHefty, Sean 		}
383604215330SMichael Wang 	} else if (rdma_cap_iw_cm(id->device, id->port_num))
383707ebafbaSTom Tucker 		ret = cma_accept_iw(id_priv, conn_param);
383821655afcSMichael Wang 	else
3839e51060f0SSean Hefty 		ret = -ENOSYS;
3840e51060f0SSean Hefty 
3841e51060f0SSean Hefty 	if (ret)
3842e51060f0SSean Hefty 		goto reject;
3843e51060f0SSean Hefty 
3844e51060f0SSean Hefty 	return 0;
3845e51060f0SSean Hefty reject:
3846c5483388SSean Hefty 	cma_modify_qp_err(id_priv);
3847e51060f0SSean Hefty 	rdma_reject(id, NULL, 0);
3848e51060f0SSean Hefty 	return ret;
3849e51060f0SSean Hefty }
385000313983SSteve Wise EXPORT_SYMBOL(__rdma_accept);
3851e51060f0SSean Hefty 
38520fe313b0SSean Hefty int rdma_notify(struct rdma_cm_id *id, enum ib_event_type event)
38530fe313b0SSean Hefty {
38540fe313b0SSean Hefty 	struct rdma_id_private *id_priv;
38550fe313b0SSean Hefty 	int ret;
38560fe313b0SSean Hefty 
38570fe313b0SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
38580c9361fcSJack Morgenstein 	if (!id_priv->cm_id.ib)
38590fe313b0SSean Hefty 		return -EINVAL;
38600fe313b0SSean Hefty 
38610fe313b0SSean Hefty 	switch (id->device->node_type) {
38620fe313b0SSean Hefty 	case RDMA_NODE_IB_CA:
38630fe313b0SSean Hefty 		ret = ib_cm_notify(id_priv->cm_id.ib, event);
38640fe313b0SSean Hefty 		break;
38650fe313b0SSean Hefty 	default:
38660fe313b0SSean Hefty 		ret = 0;
38670fe313b0SSean Hefty 		break;
38680fe313b0SSean Hefty 	}
38690fe313b0SSean Hefty 	return ret;
38700fe313b0SSean Hefty }
38710fe313b0SSean Hefty EXPORT_SYMBOL(rdma_notify);
38720fe313b0SSean Hefty 
3873e51060f0SSean Hefty int rdma_reject(struct rdma_cm_id *id, const void *private_data,
3874e51060f0SSean Hefty 		u8 private_data_len)
3875e51060f0SSean Hefty {
3876e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
3877e51060f0SSean Hefty 	int ret;
3878e51060f0SSean Hefty 
3879e51060f0SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
38800c9361fcSJack Morgenstein 	if (!id_priv->cm_id.ib)
3881e51060f0SSean Hefty 		return -EINVAL;
3882e51060f0SSean Hefty 
388372219ceaSMichael Wang 	if (rdma_cap_ib_cm(id->device, id->port_num)) {
3884b26f9b99SSean Hefty 		if (id->qp_type == IB_QPT_UD)
38855c438135SSean Hefty 			ret = cma_send_sidr_rep(id_priv, IB_SIDR_REJECT, 0,
3886e51060f0SSean Hefty 						private_data, private_data_len);
3887628e5f6dSSean Hefty 		else
3888628e5f6dSSean Hefty 			ret = ib_send_cm_rej(id_priv->cm_id.ib,
3889628e5f6dSSean Hefty 					     IB_CM_REJ_CONSUMER_DEFINED, NULL,
3890628e5f6dSSean Hefty 					     0, private_data, private_data_len);
389104215330SMichael Wang 	} else if (rdma_cap_iw_cm(id->device, id->port_num)) {
389207ebafbaSTom Tucker 		ret = iw_cm_reject(id_priv->cm_id.iw,
389307ebafbaSTom Tucker 				   private_data, private_data_len);
389421655afcSMichael Wang 	} else
3895e51060f0SSean Hefty 		ret = -ENOSYS;
389621655afcSMichael Wang 
3897e51060f0SSean Hefty 	return ret;
3898e51060f0SSean Hefty }
3899e51060f0SSean Hefty EXPORT_SYMBOL(rdma_reject);
3900e51060f0SSean Hefty 
3901e51060f0SSean Hefty int rdma_disconnect(struct rdma_cm_id *id)
3902e51060f0SSean Hefty {
3903e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
3904e51060f0SSean Hefty 	int ret;
3905e51060f0SSean Hefty 
3906e51060f0SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
39070c9361fcSJack Morgenstein 	if (!id_priv->cm_id.ib)
3908e51060f0SSean Hefty 		return -EINVAL;
3909e51060f0SSean Hefty 
391072219ceaSMichael Wang 	if (rdma_cap_ib_cm(id->device, id->port_num)) {
3911c5483388SSean Hefty 		ret = cma_modify_qp_err(id_priv);
3912e51060f0SSean Hefty 		if (ret)
3913e51060f0SSean Hefty 			goto out;
3914e51060f0SSean Hefty 		/* Initiate or respond to a disconnect. */
3915e51060f0SSean Hefty 		if (ib_send_cm_dreq(id_priv->cm_id.ib, NULL, 0))
3916e51060f0SSean Hefty 			ib_send_cm_drep(id_priv->cm_id.ib, NULL, 0);
391704215330SMichael Wang 	} else if (rdma_cap_iw_cm(id->device, id->port_num)) {
391807ebafbaSTom Tucker 		ret = iw_cm_disconnect(id_priv->cm_id.iw, 0);
391921655afcSMichael Wang 	} else
392007ebafbaSTom Tucker 		ret = -EINVAL;
392121655afcSMichael Wang 
3922e51060f0SSean Hefty out:
3923e51060f0SSean Hefty 	return ret;
3924e51060f0SSean Hefty }
3925e51060f0SSean Hefty EXPORT_SYMBOL(rdma_disconnect);
3926e51060f0SSean Hefty 
3927c8f6a362SSean Hefty static int cma_ib_mc_handler(int status, struct ib_sa_multicast *multicast)
3928c8f6a362SSean Hefty {
3929c8f6a362SSean Hefty 	struct rdma_id_private *id_priv;
3930c8f6a362SSean Hefty 	struct cma_multicast *mc = multicast->context;
3931c8f6a362SSean Hefty 	struct rdma_cm_event event;
393237e07cdaSBart Van Assche 	int ret = 0;
3933c8f6a362SSean Hefty 
3934c8f6a362SSean Hefty 	id_priv = mc->id_priv;
393537e07cdaSBart Van Assche 	mutex_lock(&id_priv->handler_mutex);
393637e07cdaSBart Van Assche 	if (id_priv->state != RDMA_CM_ADDR_BOUND &&
393737e07cdaSBart Van Assche 	    id_priv->state != RDMA_CM_ADDR_RESOLVED)
393837e07cdaSBart Van Assche 		goto out;
3939c8f6a362SSean Hefty 
39405c438135SSean Hefty 	if (!status)
39415c438135SSean Hefty 		status = cma_set_qkey(id_priv, be32_to_cpu(multicast->rec.qkey));
3942498683c6SMoni Shoua 	else
3943498683c6SMoni Shoua 		pr_debug_ratelimited("RDMA CM: MULTICAST_ERROR: failed to join multicast. status %d\n",
3944498683c6SMoni Shoua 				     status);
3945c5483388SSean Hefty 	mutex_lock(&id_priv->qp_mutex);
3946498683c6SMoni Shoua 	if (!status && id_priv->id.qp) {
3947c8f6a362SSean Hefty 		status = ib_attach_mcast(id_priv->id.qp, &multicast->rec.mgid,
394846ea5061SSean Hefty 					 be16_to_cpu(multicast->rec.mlid));
3949a3dd3a48SChristophe Jaillet 		if (status)
3950498683c6SMoni Shoua 			pr_debug_ratelimited("RDMA CM: MULTICAST_ERROR: failed to attach QP. status %d\n",
3951498683c6SMoni Shoua 					     status);
3952498683c6SMoni Shoua 	}
3953c5483388SSean Hefty 	mutex_unlock(&id_priv->qp_mutex);
3954c8f6a362SSean Hefty 
3955c8f6a362SSean Hefty 	memset(&event, 0, sizeof event);
3956c8f6a362SSean Hefty 	event.status = status;
3957c8f6a362SSean Hefty 	event.param.ud.private_data = mc->context;
3958c8f6a362SSean Hefty 	if (!status) {
3959bee3c3c9SMoni Shoua 		struct rdma_dev_addr *dev_addr =
3960bee3c3c9SMoni Shoua 			&id_priv->id.route.addr.dev_addr;
3961bee3c3c9SMoni Shoua 		struct net_device *ndev =
3962052eac6eSParav Pandit 			dev_get_by_index(dev_addr->net, dev_addr->bound_dev_if);
3963bee3c3c9SMoni Shoua 		enum ib_gid_type gid_type =
3964bee3c3c9SMoni Shoua 			id_priv->cma_dev->default_gid_type[id_priv->id.port_num -
3965bee3c3c9SMoni Shoua 			rdma_start_port(id_priv->cma_dev->device)];
3966bee3c3c9SMoni Shoua 
3967c8f6a362SSean Hefty 		event.event = RDMA_CM_EVENT_MULTICAST_JOIN;
39686d337179SParav Pandit 		ret = ib_init_ah_from_mcmember(id_priv->id.device,
39696d337179SParav Pandit 					       id_priv->id.port_num,
39706d337179SParav Pandit 					       &multicast->rec,
3971bee3c3c9SMoni Shoua 					       ndev, gid_type,
3972c8f6a362SSean Hefty 					       &event.param.ud.ah_attr);
39736d337179SParav Pandit 		if (ret)
39746d337179SParav Pandit 			event.event = RDMA_CM_EVENT_MULTICAST_ERROR;
39756d337179SParav Pandit 
3976c8f6a362SSean Hefty 		event.param.ud.qp_num = 0xFFFFFF;
3977c8f6a362SSean Hefty 		event.param.ud.qkey = be32_to_cpu(multicast->rec.qkey);
3978bee3c3c9SMoni Shoua 		if (ndev)
3979bee3c3c9SMoni Shoua 			dev_put(ndev);
3980c8f6a362SSean Hefty 	} else
3981c8f6a362SSean Hefty 		event.event = RDMA_CM_EVENT_MULTICAST_ERROR;
3982c8f6a362SSean Hefty 
3983c8f6a362SSean Hefty 	ret = id_priv->id.event_handler(&id_priv->id, &event);
3984c8f6a362SSean Hefty 	if (ret) {
3985550e5ca7SNir Muchtar 		cma_exch(id_priv, RDMA_CM_DESTROYING);
3986de910bd9SOr Gerlitz 		mutex_unlock(&id_priv->handler_mutex);
3987c8f6a362SSean Hefty 		rdma_destroy_id(&id_priv->id);
3988c8f6a362SSean Hefty 		return 0;
3989c8f6a362SSean Hefty 	}
39908aa08602SSean Hefty 
399137e07cdaSBart Van Assche out:
3992de910bd9SOr Gerlitz 	mutex_unlock(&id_priv->handler_mutex);
3993c8f6a362SSean Hefty 	return 0;
3994c8f6a362SSean Hefty }
3995c8f6a362SSean Hefty 
3996c8f6a362SSean Hefty static void cma_set_mgid(struct rdma_id_private *id_priv,
3997c8f6a362SSean Hefty 			 struct sockaddr *addr, union ib_gid *mgid)
3998c8f6a362SSean Hefty {
3999c8f6a362SSean Hefty 	unsigned char mc_map[MAX_ADDR_LEN];
4000c8f6a362SSean Hefty 	struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
4001c8f6a362SSean Hefty 	struct sockaddr_in *sin = (struct sockaddr_in *) addr;
4002c8f6a362SSean Hefty 	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) addr;
4003c8f6a362SSean Hefty 
4004c8f6a362SSean Hefty 	if (cma_any_addr(addr)) {
4005c8f6a362SSean Hefty 		memset(mgid, 0, sizeof *mgid);
4006c8f6a362SSean Hefty 	} else if ((addr->sa_family == AF_INET6) &&
40071c9b2819SJason Gunthorpe 		   ((be32_to_cpu(sin6->sin6_addr.s6_addr32[0]) & 0xFFF0FFFF) ==
4008c8f6a362SSean Hefty 								 0xFF10A01B)) {
4009c8f6a362SSean Hefty 		/* IPv6 address is an SA assigned MGID. */
4010c8f6a362SSean Hefty 		memcpy(mgid, &sin6->sin6_addr, sizeof *mgid);
40115bc2b7b3SSean Hefty 	} else if (addr->sa_family == AF_IB) {
40125bc2b7b3SSean Hefty 		memcpy(mgid, &((struct sockaddr_ib *) addr)->sib_addr, sizeof *mgid);
4013e2e62697SJason Gunthorpe 	} else if ((addr->sa_family == AF_INET6)) {
4014e2e62697SJason Gunthorpe 		ipv6_ib_mc_map(&sin6->sin6_addr, dev_addr->broadcast, mc_map);
4015e2e62697SJason Gunthorpe 		if (id_priv->id.ps == RDMA_PS_UDP)
4016e2e62697SJason Gunthorpe 			mc_map[7] = 0x01;	/* Use RDMA CM signature */
4017e2e62697SJason Gunthorpe 		*mgid = *(union ib_gid *) (mc_map + 4);
4018c8f6a362SSean Hefty 	} else {
4019a9e527e3SRolf Manderscheid 		ip_ib_mc_map(sin->sin_addr.s_addr, dev_addr->broadcast, mc_map);
4020c8f6a362SSean Hefty 		if (id_priv->id.ps == RDMA_PS_UDP)
4021c8f6a362SSean Hefty 			mc_map[7] = 0x01;	/* Use RDMA CM signature */
4022c8f6a362SSean Hefty 		*mgid = *(union ib_gid *) (mc_map + 4);
4023c8f6a362SSean Hefty 	}
4024c8f6a362SSean Hefty }
4025c8f6a362SSean Hefty 
4026c8f6a362SSean Hefty static int cma_join_ib_multicast(struct rdma_id_private *id_priv,
4027c8f6a362SSean Hefty 				 struct cma_multicast *mc)
4028c8f6a362SSean Hefty {
4029c8f6a362SSean Hefty 	struct ib_sa_mcmember_rec rec;
4030c8f6a362SSean Hefty 	struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
4031c8f6a362SSean Hefty 	ib_sa_comp_mask comp_mask;
4032c8f6a362SSean Hefty 	int ret;
4033c8f6a362SSean Hefty 
4034c8f6a362SSean Hefty 	ib_addr_get_mgid(dev_addr, &rec.mgid);
4035c8f6a362SSean Hefty 	ret = ib_sa_get_mcmember_rec(id_priv->id.device, id_priv->id.port_num,
4036c8f6a362SSean Hefty 				     &rec.mgid, &rec);
4037c8f6a362SSean Hefty 	if (ret)
4038c8f6a362SSean Hefty 		return ret;
4039c8f6a362SSean Hefty 
40405bc2b7b3SSean Hefty 	ret = cma_set_qkey(id_priv, 0);
40415bc2b7b3SSean Hefty 	if (ret)
40425bc2b7b3SSean Hefty 		return ret;
40435bc2b7b3SSean Hefty 
40443f446754SRoland Dreier 	cma_set_mgid(id_priv, (struct sockaddr *) &mc->addr, &rec.mgid);
40455bc2b7b3SSean Hefty 	rec.qkey = cpu_to_be32(id_priv->qkey);
40466f8372b6SSean Hefty 	rdma_addr_get_sgid(dev_addr, &rec.port_gid);
4047c8f6a362SSean Hefty 	rec.pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr));
4048ab15c95aSAlex Vesker 	rec.join_state = mc->join_state;
4049ab15c95aSAlex Vesker 
4050ee1c60b1SDasaratharaman Chandramouli 	if ((rec.join_state == BIT(SENDONLY_FULLMEMBER_JOIN)) &&
4051ee1c60b1SDasaratharaman Chandramouli 	    (!ib_sa_sendonly_fullmem_support(&sa_client,
4052ee1c60b1SDasaratharaman Chandramouli 					     id_priv->id.device,
4053ee1c60b1SDasaratharaman Chandramouli 					     id_priv->id.port_num))) {
4054ab15c95aSAlex Vesker 		pr_warn("RDMA CM: %s port %u Unable to multicast join\n"
4055ab15c95aSAlex Vesker 			"RDMA CM: SM doesn't support Send Only Full Member option\n",
4056ab15c95aSAlex Vesker 			id_priv->id.device->name, id_priv->id.port_num);
4057ab15c95aSAlex Vesker 		return -EOPNOTSUPP;
4058ab15c95aSAlex Vesker 	}
4059c8f6a362SSean Hefty 
4060c8f6a362SSean Hefty 	comp_mask = IB_SA_MCMEMBER_REC_MGID | IB_SA_MCMEMBER_REC_PORT_GID |
4061c8f6a362SSean Hefty 		    IB_SA_MCMEMBER_REC_PKEY | IB_SA_MCMEMBER_REC_JOIN_STATE |
4062c8f6a362SSean Hefty 		    IB_SA_MCMEMBER_REC_QKEY | IB_SA_MCMEMBER_REC_SL |
4063c8f6a362SSean Hefty 		    IB_SA_MCMEMBER_REC_FLOW_LABEL |
4064c8f6a362SSean Hefty 		    IB_SA_MCMEMBER_REC_TRAFFIC_CLASS;
4065c8f6a362SSean Hefty 
406684adeee9SYossi Etigin 	if (id_priv->id.ps == RDMA_PS_IPOIB)
406784adeee9SYossi Etigin 		comp_mask |= IB_SA_MCMEMBER_REC_RATE |
40682a22fb8cSDotan Barak 			     IB_SA_MCMEMBER_REC_RATE_SELECTOR |
40692a22fb8cSDotan Barak 			     IB_SA_MCMEMBER_REC_MTU_SELECTOR |
40702a22fb8cSDotan Barak 			     IB_SA_MCMEMBER_REC_MTU |
40712a22fb8cSDotan Barak 			     IB_SA_MCMEMBER_REC_HOP_LIMIT;
407284adeee9SYossi Etigin 
4073c8f6a362SSean Hefty 	mc->multicast.ib = ib_sa_join_multicast(&sa_client, id_priv->id.device,
4074c8f6a362SSean Hefty 						id_priv->id.port_num, &rec,
4075c8f6a362SSean Hefty 						comp_mask, GFP_KERNEL,
4076c8f6a362SSean Hefty 						cma_ib_mc_handler, mc);
40778c6ffba0SRusty Russell 	return PTR_ERR_OR_ZERO(mc->multicast.ib);
4078c8f6a362SSean Hefty }
4079c8f6a362SSean Hefty 
40803c86aa70SEli Cohen static void iboe_mcast_work_handler(struct work_struct *work)
40813c86aa70SEli Cohen {
40823c86aa70SEli Cohen 	struct iboe_mcast_work *mw = container_of(work, struct iboe_mcast_work, work);
40833c86aa70SEli Cohen 	struct cma_multicast *mc = mw->mc;
40843c86aa70SEli Cohen 	struct ib_sa_multicast *m = mc->multicast.ib;
40853c86aa70SEli Cohen 
40863c86aa70SEli Cohen 	mc->multicast.ib->context = mc;
40873c86aa70SEli Cohen 	cma_ib_mc_handler(0, m);
40883c86aa70SEli Cohen 	kref_put(&mc->mcref, release_mc);
40893c86aa70SEli Cohen 	kfree(mw);
40903c86aa70SEli Cohen }
40913c86aa70SEli Cohen 
4092be1d325aSNoa Osherovich static void cma_iboe_set_mgid(struct sockaddr *addr, union ib_gid *mgid,
4093be1d325aSNoa Osherovich 			      enum ib_gid_type gid_type)
40943c86aa70SEli Cohen {
40953c86aa70SEli Cohen 	struct sockaddr_in *sin = (struct sockaddr_in *)addr;
40963c86aa70SEli Cohen 	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
40973c86aa70SEli Cohen 
40983c86aa70SEli Cohen 	if (cma_any_addr(addr)) {
40993c86aa70SEli Cohen 		memset(mgid, 0, sizeof *mgid);
41003c86aa70SEli Cohen 	} else if (addr->sa_family == AF_INET6) {
41013c86aa70SEli Cohen 		memcpy(mgid, &sin6->sin6_addr, sizeof *mgid);
41023c86aa70SEli Cohen 	} else {
41035c181bdaSParav Pandit 		mgid->raw[0] =
41045c181bdaSParav Pandit 			(gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) ? 0 : 0xff;
41055c181bdaSParav Pandit 		mgid->raw[1] =
41065c181bdaSParav Pandit 			(gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) ? 0 : 0x0e;
41073c86aa70SEli Cohen 		mgid->raw[2] = 0;
41083c86aa70SEli Cohen 		mgid->raw[3] = 0;
41093c86aa70SEli Cohen 		mgid->raw[4] = 0;
41103c86aa70SEli Cohen 		mgid->raw[5] = 0;
41113c86aa70SEli Cohen 		mgid->raw[6] = 0;
41123c86aa70SEli Cohen 		mgid->raw[7] = 0;
41133c86aa70SEli Cohen 		mgid->raw[8] = 0;
41143c86aa70SEli Cohen 		mgid->raw[9] = 0;
41153c86aa70SEli Cohen 		mgid->raw[10] = 0xff;
41163c86aa70SEli Cohen 		mgid->raw[11] = 0xff;
41173c86aa70SEli Cohen 		*(__be32 *)(&mgid->raw[12]) = sin->sin_addr.s_addr;
41183c86aa70SEli Cohen 	}
41193c86aa70SEli Cohen }
41203c86aa70SEli Cohen 
41213c86aa70SEli Cohen static int cma_iboe_join_multicast(struct rdma_id_private *id_priv,
41223c86aa70SEli Cohen 				   struct cma_multicast *mc)
41233c86aa70SEli Cohen {
41243c86aa70SEli Cohen 	struct iboe_mcast_work *work;
41253c86aa70SEli Cohen 	struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
4126bee3c3c9SMoni Shoua 	int err = 0;
41273c86aa70SEli Cohen 	struct sockaddr *addr = (struct sockaddr *)&mc->addr;
41283c86aa70SEli Cohen 	struct net_device *ndev = NULL;
4129bee3c3c9SMoni Shoua 	enum ib_gid_type gid_type;
4130ab15c95aSAlex Vesker 	bool send_only;
4131ab15c95aSAlex Vesker 
4132ab15c95aSAlex Vesker 	send_only = mc->join_state == BIT(SENDONLY_FULLMEMBER_JOIN);
41333c86aa70SEli Cohen 
41343c86aa70SEli Cohen 	if (cma_zero_addr((struct sockaddr *)&mc->addr))
41353c86aa70SEli Cohen 		return -EINVAL;
41363c86aa70SEli Cohen 
41373c86aa70SEli Cohen 	work = kzalloc(sizeof *work, GFP_KERNEL);
41383c86aa70SEli Cohen 	if (!work)
41393c86aa70SEli Cohen 		return -ENOMEM;
41403c86aa70SEli Cohen 
41413c86aa70SEli Cohen 	mc->multicast.ib = kzalloc(sizeof(struct ib_sa_multicast), GFP_KERNEL);
41423c86aa70SEli Cohen 	if (!mc->multicast.ib) {
41433c86aa70SEli Cohen 		err = -ENOMEM;
41443c86aa70SEli Cohen 		goto out1;
41453c86aa70SEli Cohen 	}
41463c86aa70SEli Cohen 
4147be1d325aSNoa Osherovich 	gid_type = id_priv->cma_dev->default_gid_type[id_priv->id.port_num -
4148be1d325aSNoa Osherovich 		   rdma_start_port(id_priv->cma_dev->device)];
4149be1d325aSNoa Osherovich 	cma_iboe_set_mgid(addr, &mc->multicast.ib->rec.mgid, gid_type);
41503c86aa70SEli Cohen 
41513c86aa70SEli Cohen 	mc->multicast.ib->rec.pkey = cpu_to_be16(0xffff);
41523c86aa70SEli Cohen 	if (id_priv->id.ps == RDMA_PS_UDP)
41533c86aa70SEli Cohen 		mc->multicast.ib->rec.qkey = cpu_to_be32(RDMA_UDP_QKEY);
41543c86aa70SEli Cohen 
41553c86aa70SEli Cohen 	if (dev_addr->bound_dev_if)
4156052eac6eSParav Pandit 		ndev = dev_get_by_index(dev_addr->net, dev_addr->bound_dev_if);
41573c86aa70SEli Cohen 	if (!ndev) {
41583c86aa70SEli Cohen 		err = -ENODEV;
41593c86aa70SEli Cohen 		goto out2;
41603c86aa70SEli Cohen 	}
41613c86aa70SEli Cohen 	mc->multicast.ib->rec.rate = iboe_get_rate(ndev);
41623c86aa70SEli Cohen 	mc->multicast.ib->rec.hop_limit = 1;
41633c86aa70SEli Cohen 	mc->multicast.ib->rec.mtu = iboe_get_mtu(ndev->mtu);
4164bee3c3c9SMoni Shoua 
4165bee3c3c9SMoni Shoua 	if (addr->sa_family == AF_INET) {
4166c65f6c5aSAlex Vesker 		if (gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) {
4167c65f6c5aSAlex Vesker 			mc->multicast.ib->rec.hop_limit = IPV6_DEFAULT_HOPLIMIT;
4168ab15c95aSAlex Vesker 			if (!send_only) {
4169bee3c3c9SMoni Shoua 				err = cma_igmp_send(ndev, &mc->multicast.ib->rec.mgid,
4170bee3c3c9SMoni Shoua 						    true);
4171c65f6c5aSAlex Vesker 				if (!err)
4172bee3c3c9SMoni Shoua 					mc->igmp_joined = true;
4173bee3c3c9SMoni Shoua 			}
4174bee3c3c9SMoni Shoua 		}
4175bee3c3c9SMoni Shoua 	} else {
4176bee3c3c9SMoni Shoua 		if (gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP)
4177bee3c3c9SMoni Shoua 			err = -ENOTSUPP;
4178bee3c3c9SMoni Shoua 	}
41793c86aa70SEli Cohen 	dev_put(ndev);
4180bee3c3c9SMoni Shoua 	if (err || !mc->multicast.ib->rec.mtu) {
4181bee3c3c9SMoni Shoua 		if (!err)
41823c86aa70SEli Cohen 			err = -EINVAL;
41833c86aa70SEli Cohen 		goto out2;
41843c86aa70SEli Cohen 	}
41857b85627bSMoni Shoua 	rdma_ip2gid((struct sockaddr *)&id_priv->id.route.addr.src_addr,
41867b85627bSMoni Shoua 		    &mc->multicast.ib->rec.port_gid);
41873c86aa70SEli Cohen 	work->id = id_priv;
41883c86aa70SEli Cohen 	work->mc = mc;
41893c86aa70SEli Cohen 	INIT_WORK(&work->work, iboe_mcast_work_handler);
41903c86aa70SEli Cohen 	kref_get(&mc->mcref);
41913c86aa70SEli Cohen 	queue_work(cma_wq, &work->work);
41923c86aa70SEli Cohen 
41933c86aa70SEli Cohen 	return 0;
41943c86aa70SEli Cohen 
41953c86aa70SEli Cohen out2:
41963c86aa70SEli Cohen 	kfree(mc->multicast.ib);
41973c86aa70SEli Cohen out1:
41983c86aa70SEli Cohen 	kfree(work);
41993c86aa70SEli Cohen 	return err;
42003c86aa70SEli Cohen }
42013c86aa70SEli Cohen 
4202c8f6a362SSean Hefty int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr,
4203ab15c95aSAlex Vesker 			u8 join_state, void *context)
4204c8f6a362SSean Hefty {
4205c8f6a362SSean Hefty 	struct rdma_id_private *id_priv;
4206c8f6a362SSean Hefty 	struct cma_multicast *mc;
4207c8f6a362SSean Hefty 	int ret;
4208c8f6a362SSean Hefty 
42097688f2c3SLeon Romanovsky 	if (!id->device)
42107688f2c3SLeon Romanovsky 		return -EINVAL;
42117688f2c3SLeon Romanovsky 
4212c8f6a362SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
4213550e5ca7SNir Muchtar 	if (!cma_comp(id_priv, RDMA_CM_ADDR_BOUND) &&
4214550e5ca7SNir Muchtar 	    !cma_comp(id_priv, RDMA_CM_ADDR_RESOLVED))
4215c8f6a362SSean Hefty 		return -EINVAL;
4216c8f6a362SSean Hefty 
4217c8f6a362SSean Hefty 	mc = kmalloc(sizeof *mc, GFP_KERNEL);
4218c8f6a362SSean Hefty 	if (!mc)
4219c8f6a362SSean Hefty 		return -ENOMEM;
4220c8f6a362SSean Hefty 
4221ef560861SSean Hefty 	memcpy(&mc->addr, addr, rdma_addr_size(addr));
4222c8f6a362SSean Hefty 	mc->context = context;
4223c8f6a362SSean Hefty 	mc->id_priv = id_priv;
4224bee3c3c9SMoni Shoua 	mc->igmp_joined = false;
4225ab15c95aSAlex Vesker 	mc->join_state = join_state;
4226c8f6a362SSean Hefty 	spin_lock(&id_priv->lock);
4227c8f6a362SSean Hefty 	list_add(&mc->list, &id_priv->mc_list);
4228c8f6a362SSean Hefty 	spin_unlock(&id_priv->lock);
4229c8f6a362SSean Hefty 
42305d9fb044SIra Weiny 	if (rdma_protocol_roce(id->device, id->port_num)) {
42313c86aa70SEli Cohen 		kref_init(&mc->mcref);
42323c86aa70SEli Cohen 		ret = cma_iboe_join_multicast(id_priv, mc);
4233a31ad3b0SMichael Wang 	} else if (rdma_cap_ib_mcast(id->device, id->port_num))
42345c9a5282SMichael Wang 		ret = cma_join_ib_multicast(id_priv, mc);
42355c9a5282SMichael Wang 	else
4236c8f6a362SSean Hefty 		ret = -ENOSYS;
4237c8f6a362SSean Hefty 
4238c8f6a362SSean Hefty 	if (ret) {
4239c8f6a362SSean Hefty 		spin_lock_irq(&id_priv->lock);
4240c8f6a362SSean Hefty 		list_del(&mc->list);
4241c8f6a362SSean Hefty 		spin_unlock_irq(&id_priv->lock);
4242c8f6a362SSean Hefty 		kfree(mc);
4243c8f6a362SSean Hefty 	}
4244c8f6a362SSean Hefty 	return ret;
4245c8f6a362SSean Hefty }
4246c8f6a362SSean Hefty EXPORT_SYMBOL(rdma_join_multicast);
4247c8f6a362SSean Hefty 
4248c8f6a362SSean Hefty void rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr)
4249c8f6a362SSean Hefty {
4250c8f6a362SSean Hefty 	struct rdma_id_private *id_priv;
4251c8f6a362SSean Hefty 	struct cma_multicast *mc;
4252c8f6a362SSean Hefty 
4253c8f6a362SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
4254c8f6a362SSean Hefty 	spin_lock_irq(&id_priv->lock);
4255c8f6a362SSean Hefty 	list_for_each_entry(mc, &id_priv->mc_list, list) {
4256ef560861SSean Hefty 		if (!memcmp(&mc->addr, addr, rdma_addr_size(addr))) {
4257c8f6a362SSean Hefty 			list_del(&mc->list);
4258c8f6a362SSean Hefty 			spin_unlock_irq(&id_priv->lock);
4259c8f6a362SSean Hefty 
4260c8f6a362SSean Hefty 			if (id->qp)
4261c8f6a362SSean Hefty 				ib_detach_mcast(id->qp,
4262c8f6a362SSean Hefty 						&mc->multicast.ib->rec.mgid,
426346ea5061SSean Hefty 						be16_to_cpu(mc->multicast.ib->rec.mlid));
42645c9a5282SMichael Wang 
42655c9a5282SMichael Wang 			BUG_ON(id_priv->cma_dev->device != id->device);
42665c9a5282SMichael Wang 
4267a31ad3b0SMichael Wang 			if (rdma_cap_ib_mcast(id->device, id->port_num)) {
4268c8f6a362SSean Hefty 				ib_sa_free_multicast(mc->multicast.ib);
4269c8f6a362SSean Hefty 				kfree(mc);
4270bee3c3c9SMoni Shoua 			} else if (rdma_protocol_roce(id->device, id->port_num)) {
4271bee3c3c9SMoni Shoua 				if (mc->igmp_joined) {
4272bee3c3c9SMoni Shoua 					struct rdma_dev_addr *dev_addr =
4273bee3c3c9SMoni Shoua 						&id->route.addr.dev_addr;
4274bee3c3c9SMoni Shoua 					struct net_device *ndev = NULL;
42755c9a5282SMichael Wang 
4276bee3c3c9SMoni Shoua 					if (dev_addr->bound_dev_if)
4277052eac6eSParav Pandit 						ndev = dev_get_by_index(dev_addr->net,
4278bee3c3c9SMoni Shoua 									dev_addr->bound_dev_if);
4279bee3c3c9SMoni Shoua 					if (ndev) {
4280bee3c3c9SMoni Shoua 						cma_igmp_send(ndev,
4281bee3c3c9SMoni Shoua 							      &mc->multicast.ib->rec.mgid,
4282bee3c3c9SMoni Shoua 							      false);
4283bee3c3c9SMoni Shoua 						dev_put(ndev);
4284bee3c3c9SMoni Shoua 					}
4285bee3c3c9SMoni Shoua 					mc->igmp_joined = false;
4286bee3c3c9SMoni Shoua 				}
4287bee3c3c9SMoni Shoua 				kref_put(&mc->mcref, release_mc);
4288bee3c3c9SMoni Shoua 			}
4289c8f6a362SSean Hefty 			return;
4290c8f6a362SSean Hefty 		}
4291c8f6a362SSean Hefty 	}
4292c8f6a362SSean Hefty 	spin_unlock_irq(&id_priv->lock);
4293c8f6a362SSean Hefty }
4294c8f6a362SSean Hefty EXPORT_SYMBOL(rdma_leave_multicast);
4295c8f6a362SSean Hefty 
4296dd5bdff8SOr Gerlitz static int cma_netdev_change(struct net_device *ndev, struct rdma_id_private *id_priv)
4297dd5bdff8SOr Gerlitz {
4298dd5bdff8SOr Gerlitz 	struct rdma_dev_addr *dev_addr;
4299dd5bdff8SOr Gerlitz 	struct cma_ndev_work *work;
4300dd5bdff8SOr Gerlitz 
4301dd5bdff8SOr Gerlitz 	dev_addr = &id_priv->id.route.addr.dev_addr;
4302dd5bdff8SOr Gerlitz 
43036266ed6eSSean Hefty 	if ((dev_addr->bound_dev_if == ndev->ifindex) &&
4304fa20105eSGuy Shapiro 	    (net_eq(dev_net(ndev), dev_addr->net)) &&
4305dd5bdff8SOr Gerlitz 	    memcmp(dev_addr->src_dev_addr, ndev->dev_addr, ndev->addr_len)) {
4306aba25a3eSParav Pandit 		pr_info("RDMA CM addr change for ndev %s used by id %p\n",
4307dd5bdff8SOr Gerlitz 			ndev->name, &id_priv->id);
4308dd5bdff8SOr Gerlitz 		work = kzalloc(sizeof *work, GFP_KERNEL);
4309dd5bdff8SOr Gerlitz 		if (!work)
4310dd5bdff8SOr Gerlitz 			return -ENOMEM;
4311dd5bdff8SOr Gerlitz 
4312dd5bdff8SOr Gerlitz 		INIT_WORK(&work->work, cma_ndev_work_handler);
4313dd5bdff8SOr Gerlitz 		work->id = id_priv;
4314dd5bdff8SOr Gerlitz 		work->event.event = RDMA_CM_EVENT_ADDR_CHANGE;
4315dd5bdff8SOr Gerlitz 		atomic_inc(&id_priv->refcount);
4316dd5bdff8SOr Gerlitz 		queue_work(cma_wq, &work->work);
4317dd5bdff8SOr Gerlitz 	}
4318dd5bdff8SOr Gerlitz 
4319dd5bdff8SOr Gerlitz 	return 0;
4320dd5bdff8SOr Gerlitz }
4321dd5bdff8SOr Gerlitz 
4322dd5bdff8SOr Gerlitz static int cma_netdev_callback(struct notifier_block *self, unsigned long event,
4323351638e7SJiri Pirko 			       void *ptr)
4324dd5bdff8SOr Gerlitz {
4325351638e7SJiri Pirko 	struct net_device *ndev = netdev_notifier_info_to_dev(ptr);
4326dd5bdff8SOr Gerlitz 	struct cma_device *cma_dev;
4327dd5bdff8SOr Gerlitz 	struct rdma_id_private *id_priv;
4328dd5bdff8SOr Gerlitz 	int ret = NOTIFY_DONE;
4329dd5bdff8SOr Gerlitz 
4330dd5bdff8SOr Gerlitz 	if (event != NETDEV_BONDING_FAILOVER)
4331dd5bdff8SOr Gerlitz 		return NOTIFY_DONE;
4332dd5bdff8SOr Gerlitz 
43333cd96fddSParav Pandit 	if (!netif_is_bond_master(ndev))
4334dd5bdff8SOr Gerlitz 		return NOTIFY_DONE;
4335dd5bdff8SOr Gerlitz 
4336dd5bdff8SOr Gerlitz 	mutex_lock(&lock);
4337dd5bdff8SOr Gerlitz 	list_for_each_entry(cma_dev, &dev_list, list)
4338dd5bdff8SOr Gerlitz 		list_for_each_entry(id_priv, &cma_dev->id_list, list) {
4339dd5bdff8SOr Gerlitz 			ret = cma_netdev_change(ndev, id_priv);
4340dd5bdff8SOr Gerlitz 			if (ret)
4341dd5bdff8SOr Gerlitz 				goto out;
4342dd5bdff8SOr Gerlitz 		}
4343dd5bdff8SOr Gerlitz 
4344dd5bdff8SOr Gerlitz out:
4345dd5bdff8SOr Gerlitz 	mutex_unlock(&lock);
4346dd5bdff8SOr Gerlitz 	return ret;
4347dd5bdff8SOr Gerlitz }
4348dd5bdff8SOr Gerlitz 
4349dd5bdff8SOr Gerlitz static struct notifier_block cma_nb = {
4350dd5bdff8SOr Gerlitz 	.notifier_call = cma_netdev_callback
4351dd5bdff8SOr Gerlitz };
4352dd5bdff8SOr Gerlitz 
4353e51060f0SSean Hefty static void cma_add_one(struct ib_device *device)
4354e51060f0SSean Hefty {
4355e51060f0SSean Hefty 	struct cma_device *cma_dev;
4356e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
4357045959dbSMatan Barak 	unsigned int i;
4358045959dbSMatan Barak 	unsigned long supported_gids = 0;
4359e51060f0SSean Hefty 
4360e51060f0SSean Hefty 	cma_dev = kmalloc(sizeof *cma_dev, GFP_KERNEL);
4361e51060f0SSean Hefty 	if (!cma_dev)
4362e51060f0SSean Hefty 		return;
4363e51060f0SSean Hefty 
4364e51060f0SSean Hefty 	cma_dev->device = device;
4365045959dbSMatan Barak 	cma_dev->default_gid_type = kcalloc(device->phys_port_cnt,
4366045959dbSMatan Barak 					    sizeof(*cma_dev->default_gid_type),
4367045959dbSMatan Barak 					    GFP_KERNEL);
436889052d78SMajd Dibbiny 	if (!cma_dev->default_gid_type)
436989052d78SMajd Dibbiny 		goto free_cma_dev;
437089052d78SMajd Dibbiny 
437189052d78SMajd Dibbiny 	cma_dev->default_roce_tos = kcalloc(device->phys_port_cnt,
437289052d78SMajd Dibbiny 					    sizeof(*cma_dev->default_roce_tos),
437389052d78SMajd Dibbiny 					    GFP_KERNEL);
437489052d78SMajd Dibbiny 	if (!cma_dev->default_roce_tos)
437589052d78SMajd Dibbiny 		goto free_gid_type;
437689052d78SMajd Dibbiny 
4377045959dbSMatan Barak 	for (i = rdma_start_port(device); i <= rdma_end_port(device); i++) {
4378045959dbSMatan Barak 		supported_gids = roce_gid_type_mask_support(device, i);
4379045959dbSMatan Barak 		WARN_ON(!supported_gids);
43805ab2d89bSLeon Romanovsky 		if (supported_gids & (1 << CMA_PREFERRED_ROCE_GID_TYPE))
438163a5f483SMoni Shoua 			cma_dev->default_gid_type[i - rdma_start_port(device)] =
438263a5f483SMoni Shoua 				CMA_PREFERRED_ROCE_GID_TYPE;
438363a5f483SMoni Shoua 		else
4384045959dbSMatan Barak 			cma_dev->default_gid_type[i - rdma_start_port(device)] =
4385045959dbSMatan Barak 				find_first_bit(&supported_gids, BITS_PER_LONG);
438689052d78SMajd Dibbiny 		cma_dev->default_roce_tos[i - rdma_start_port(device)] = 0;
4387045959dbSMatan Barak 	}
4388e51060f0SSean Hefty 
4389e51060f0SSean Hefty 	init_completion(&cma_dev->comp);
4390e51060f0SSean Hefty 	atomic_set(&cma_dev->refcount, 1);
4391e51060f0SSean Hefty 	INIT_LIST_HEAD(&cma_dev->id_list);
4392e51060f0SSean Hefty 	ib_set_client_data(device, &cma_client, cma_dev);
4393e51060f0SSean Hefty 
4394e51060f0SSean Hefty 	mutex_lock(&lock);
4395e51060f0SSean Hefty 	list_add_tail(&cma_dev->list, &dev_list);
4396e51060f0SSean Hefty 	list_for_each_entry(id_priv, &listen_any_list, list)
4397e51060f0SSean Hefty 		cma_listen_on_dev(id_priv, cma_dev);
4398e51060f0SSean Hefty 	mutex_unlock(&lock);
439989052d78SMajd Dibbiny 
440089052d78SMajd Dibbiny 	return;
440189052d78SMajd Dibbiny 
440289052d78SMajd Dibbiny free_gid_type:
440389052d78SMajd Dibbiny 	kfree(cma_dev->default_gid_type);
440489052d78SMajd Dibbiny 
440589052d78SMajd Dibbiny free_cma_dev:
440689052d78SMajd Dibbiny 	kfree(cma_dev);
440789052d78SMajd Dibbiny 
440889052d78SMajd Dibbiny 	return;
4409e51060f0SSean Hefty }
4410e51060f0SSean Hefty 
4411e51060f0SSean Hefty static int cma_remove_id_dev(struct rdma_id_private *id_priv)
4412e51060f0SSean Hefty {
4413a1b1b61fSSean Hefty 	struct rdma_cm_event event;
4414550e5ca7SNir Muchtar 	enum rdma_cm_state state;
4415de910bd9SOr Gerlitz 	int ret = 0;
4416e51060f0SSean Hefty 
4417e51060f0SSean Hefty 	/* Record that we want to remove the device */
4418550e5ca7SNir Muchtar 	state = cma_exch(id_priv, RDMA_CM_DEVICE_REMOVAL);
4419550e5ca7SNir Muchtar 	if (state == RDMA_CM_DESTROYING)
4420e51060f0SSean Hefty 		return 0;
4421e51060f0SSean Hefty 
4422e51060f0SSean Hefty 	cma_cancel_operation(id_priv, state);
4423de910bd9SOr Gerlitz 	mutex_lock(&id_priv->handler_mutex);
4424e51060f0SSean Hefty 
4425e51060f0SSean Hefty 	/* Check for destruction from another callback. */
4426550e5ca7SNir Muchtar 	if (!cma_comp(id_priv, RDMA_CM_DEVICE_REMOVAL))
4427de910bd9SOr Gerlitz 		goto out;
4428e51060f0SSean Hefty 
4429a1b1b61fSSean Hefty 	memset(&event, 0, sizeof event);
4430a1b1b61fSSean Hefty 	event.event = RDMA_CM_EVENT_DEVICE_REMOVAL;
4431de910bd9SOr Gerlitz 	ret = id_priv->id.event_handler(&id_priv->id, &event);
4432de910bd9SOr Gerlitz out:
4433de910bd9SOr Gerlitz 	mutex_unlock(&id_priv->handler_mutex);
4434de910bd9SOr Gerlitz 	return ret;
4435e51060f0SSean Hefty }
4436e51060f0SSean Hefty 
4437e51060f0SSean Hefty static void cma_process_remove(struct cma_device *cma_dev)
4438e51060f0SSean Hefty {
4439e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
4440e51060f0SSean Hefty 	int ret;
4441e51060f0SSean Hefty 
4442e51060f0SSean Hefty 	mutex_lock(&lock);
4443e51060f0SSean Hefty 	while (!list_empty(&cma_dev->id_list)) {
4444e51060f0SSean Hefty 		id_priv = list_entry(cma_dev->id_list.next,
4445e51060f0SSean Hefty 				     struct rdma_id_private, list);
4446e51060f0SSean Hefty 
4447d02d1f53SSean Hefty 		list_del(&id_priv->listen_list);
444894de178aSKrishna Kumar 		list_del_init(&id_priv->list);
4449e51060f0SSean Hefty 		atomic_inc(&id_priv->refcount);
4450e51060f0SSean Hefty 		mutex_unlock(&lock);
4451e51060f0SSean Hefty 
4452d02d1f53SSean Hefty 		ret = id_priv->internal_id ? 1 : cma_remove_id_dev(id_priv);
4453e51060f0SSean Hefty 		cma_deref_id(id_priv);
4454e51060f0SSean Hefty 		if (ret)
4455e51060f0SSean Hefty 			rdma_destroy_id(&id_priv->id);
4456e51060f0SSean Hefty 
4457e51060f0SSean Hefty 		mutex_lock(&lock);
4458e51060f0SSean Hefty 	}
4459e51060f0SSean Hefty 	mutex_unlock(&lock);
4460e51060f0SSean Hefty 
4461e51060f0SSean Hefty 	cma_deref_dev(cma_dev);
4462e51060f0SSean Hefty 	wait_for_completion(&cma_dev->comp);
4463e51060f0SSean Hefty }
4464e51060f0SSean Hefty 
44657c1eb45aSHaggai Eran static void cma_remove_one(struct ib_device *device, void *client_data)
4466e51060f0SSean Hefty {
44677c1eb45aSHaggai Eran 	struct cma_device *cma_dev = client_data;
4468e51060f0SSean Hefty 
4469e51060f0SSean Hefty 	if (!cma_dev)
4470e51060f0SSean Hefty 		return;
4471e51060f0SSean Hefty 
4472e51060f0SSean Hefty 	mutex_lock(&lock);
4473e51060f0SSean Hefty 	list_del(&cma_dev->list);
4474e51060f0SSean Hefty 	mutex_unlock(&lock);
4475e51060f0SSean Hefty 
4476e51060f0SSean Hefty 	cma_process_remove(cma_dev);
447789052d78SMajd Dibbiny 	kfree(cma_dev->default_roce_tos);
4478045959dbSMatan Barak 	kfree(cma_dev->default_gid_type);
4479e51060f0SSean Hefty 	kfree(cma_dev);
4480e51060f0SSean Hefty }
4481e51060f0SSean Hefty 
4482753f618aSNir Muchtar static int cma_get_id_stats(struct sk_buff *skb, struct netlink_callback *cb)
4483753f618aSNir Muchtar {
4484753f618aSNir Muchtar 	struct nlmsghdr *nlh;
4485753f618aSNir Muchtar 	struct rdma_cm_id_stats *id_stats;
4486753f618aSNir Muchtar 	struct rdma_id_private *id_priv;
4487753f618aSNir Muchtar 	struct rdma_cm_id *id = NULL;
4488753f618aSNir Muchtar 	struct cma_device *cma_dev;
4489753f618aSNir Muchtar 	int i_dev = 0, i_id = 0;
4490753f618aSNir Muchtar 
4491753f618aSNir Muchtar 	/*
4492753f618aSNir Muchtar 	 * We export all of the IDs as a sequence of messages.  Each
4493753f618aSNir Muchtar 	 * ID gets its own netlink message.
4494753f618aSNir Muchtar 	 */
4495753f618aSNir Muchtar 	mutex_lock(&lock);
4496753f618aSNir Muchtar 
4497753f618aSNir Muchtar 	list_for_each_entry(cma_dev, &dev_list, list) {
4498753f618aSNir Muchtar 		if (i_dev < cb->args[0]) {
4499753f618aSNir Muchtar 			i_dev++;
4500753f618aSNir Muchtar 			continue;
4501753f618aSNir Muchtar 		}
4502753f618aSNir Muchtar 
4503753f618aSNir Muchtar 		i_id = 0;
4504753f618aSNir Muchtar 		list_for_each_entry(id_priv, &cma_dev->id_list, list) {
4505753f618aSNir Muchtar 			if (i_id < cb->args[1]) {
4506753f618aSNir Muchtar 				i_id++;
4507753f618aSNir Muchtar 				continue;
4508753f618aSNir Muchtar 			}
4509753f618aSNir Muchtar 
4510753f618aSNir Muchtar 			id_stats = ibnl_put_msg(skb, &nlh, cb->nlh->nlmsg_seq,
4511753f618aSNir Muchtar 						sizeof *id_stats, RDMA_NL_RDMA_CM,
451230dc5e63STatyana Nikolova 						RDMA_NL_RDMA_CM_ID_STATS,
451330dc5e63STatyana Nikolova 						NLM_F_MULTI);
4514753f618aSNir Muchtar 			if (!id_stats)
4515753f618aSNir Muchtar 				goto out;
4516753f618aSNir Muchtar 
4517753f618aSNir Muchtar 			memset(id_stats, 0, sizeof *id_stats);
4518753f618aSNir Muchtar 			id = &id_priv->id;
4519753f618aSNir Muchtar 			id_stats->node_type = id->route.addr.dev_addr.dev_type;
4520753f618aSNir Muchtar 			id_stats->port_num = id->port_num;
4521753f618aSNir Muchtar 			id_stats->bound_dev_if =
4522753f618aSNir Muchtar 				id->route.addr.dev_addr.bound_dev_if;
4523753f618aSNir Muchtar 
4524753f618aSNir Muchtar 			if (ibnl_put_attr(skb, nlh,
4525ce117ffaSSean Hefty 					  rdma_addr_size(cma_src_addr(id_priv)),
4526f4753834SSean Hefty 					  cma_src_addr(id_priv),
4527ce117ffaSSean Hefty 					  RDMA_NL_RDMA_CM_ATTR_SRC_ADDR))
4528753f618aSNir Muchtar 				goto out;
4529753f618aSNir Muchtar 			if (ibnl_put_attr(skb, nlh,
45307baaa49aSParav Pandit 					  rdma_addr_size(cma_dst_addr(id_priv)),
4531f4753834SSean Hefty 					  cma_dst_addr(id_priv),
4532ce117ffaSSean Hefty 					  RDMA_NL_RDMA_CM_ATTR_DST_ADDR))
4533753f618aSNir Muchtar 				goto out;
4534753f618aSNir Muchtar 
453500313983SSteve Wise 			id_stats->pid	= task_pid_vnr(id_priv->res.task);
4536753f618aSNir Muchtar 			id_stats->port_space	= id->ps;
4537753f618aSNir Muchtar 			id_stats->cm_state	= id_priv->state;
4538753f618aSNir Muchtar 			id_stats->qp_num	= id_priv->qp_num;
4539753f618aSNir Muchtar 			id_stats->qp_type	= id->qp_type;
4540753f618aSNir Muchtar 
4541753f618aSNir Muchtar 			i_id++;
4542e48e5e19SLeon Romanovsky 			nlmsg_end(skb, nlh);
4543753f618aSNir Muchtar 		}
4544753f618aSNir Muchtar 
4545753f618aSNir Muchtar 		cb->args[1] = 0;
4546753f618aSNir Muchtar 		i_dev++;
4547753f618aSNir Muchtar 	}
4548753f618aSNir Muchtar 
4549753f618aSNir Muchtar out:
4550753f618aSNir Muchtar 	mutex_unlock(&lock);
4551753f618aSNir Muchtar 	cb->args[0] = i_dev;
4552753f618aSNir Muchtar 	cb->args[1] = i_id;
4553753f618aSNir Muchtar 
4554753f618aSNir Muchtar 	return skb->len;
4555753f618aSNir Muchtar }
4556753f618aSNir Muchtar 
4557d0e312feSLeon Romanovsky static const struct rdma_nl_cbs cma_cb_table[RDMA_NL_RDMA_CM_NUM_OPS] = {
455864401b69SLeon Romanovsky 	[RDMA_NL_RDMA_CM_ID_STATS] = { .dump = cma_get_id_stats},
4559753f618aSNir Muchtar };
4560753f618aSNir Muchtar 
45614be74b42SHaggai Eran static int cma_init_net(struct net *net)
45624be74b42SHaggai Eran {
45634be74b42SHaggai Eran 	struct cma_pernet *pernet = cma_pernet(net);
45644be74b42SHaggai Eran 
45654be74b42SHaggai Eran 	idr_init(&pernet->tcp_ps);
45664be74b42SHaggai Eran 	idr_init(&pernet->udp_ps);
45674be74b42SHaggai Eran 	idr_init(&pernet->ipoib_ps);
45684be74b42SHaggai Eran 	idr_init(&pernet->ib_ps);
45694be74b42SHaggai Eran 
45704be74b42SHaggai Eran 	return 0;
45714be74b42SHaggai Eran }
45724be74b42SHaggai Eran 
45734be74b42SHaggai Eran static void cma_exit_net(struct net *net)
45744be74b42SHaggai Eran {
45754be74b42SHaggai Eran 	struct cma_pernet *pernet = cma_pernet(net);
45764be74b42SHaggai Eran 
45774be74b42SHaggai Eran 	idr_destroy(&pernet->tcp_ps);
45784be74b42SHaggai Eran 	idr_destroy(&pernet->udp_ps);
45794be74b42SHaggai Eran 	idr_destroy(&pernet->ipoib_ps);
45804be74b42SHaggai Eran 	idr_destroy(&pernet->ib_ps);
45814be74b42SHaggai Eran }
45824be74b42SHaggai Eran 
45834be74b42SHaggai Eran static struct pernet_operations cma_pernet_operations = {
45844be74b42SHaggai Eran 	.init = cma_init_net,
45854be74b42SHaggai Eran 	.exit = cma_exit_net,
45864be74b42SHaggai Eran 	.id = &cma_pernet_id,
45874be74b42SHaggai Eran 	.size = sizeof(struct cma_pernet),
45884be74b42SHaggai Eran };
45894be74b42SHaggai Eran 
4590716abb1fSPeter Huewe static int __init cma_init(void)
4591e51060f0SSean Hefty {
45925d7220e8STetsuo Handa 	int ret;
4593227b60f5SStephen Hemminger 
4594dee9acbbSBhaktipriya Shridhar 	cma_wq = alloc_ordered_workqueue("rdma_cm", WQ_MEM_RECLAIM);
4595e51060f0SSean Hefty 	if (!cma_wq)
4596e51060f0SSean Hefty 		return -ENOMEM;
4597e51060f0SSean Hefty 
45984be74b42SHaggai Eran 	ret = register_pernet_subsys(&cma_pernet_operations);
45994be74b42SHaggai Eran 	if (ret)
46004be74b42SHaggai Eran 		goto err_wq;
46014be74b42SHaggai Eran 
4602c1a0b23bSMichael S. Tsirkin 	ib_sa_register_client(&sa_client);
4603dd5bdff8SOr Gerlitz 	register_netdevice_notifier(&cma_nb);
4604c1a0b23bSMichael S. Tsirkin 
4605e51060f0SSean Hefty 	ret = ib_register_client(&cma_client);
4606e51060f0SSean Hefty 	if (ret)
4607e51060f0SSean Hefty 		goto err;
4608753f618aSNir Muchtar 
4609c9901724SLeon Romanovsky 	rdma_nl_register(RDMA_NL_RDMA_CM, cma_cb_table);
4610045959dbSMatan Barak 	cma_configfs_init();
4611753f618aSNir Muchtar 
4612e51060f0SSean Hefty 	return 0;
4613e51060f0SSean Hefty 
4614e51060f0SSean Hefty err:
4615dd5bdff8SOr Gerlitz 	unregister_netdevice_notifier(&cma_nb);
4616c1a0b23bSMichael S. Tsirkin 	ib_sa_unregister_client(&sa_client);
46174be74b42SHaggai Eran err_wq:
4618e51060f0SSean Hefty 	destroy_workqueue(cma_wq);
4619e51060f0SSean Hefty 	return ret;
4620e51060f0SSean Hefty }
4621e51060f0SSean Hefty 
4622716abb1fSPeter Huewe static void __exit cma_cleanup(void)
4623e51060f0SSean Hefty {
4624045959dbSMatan Barak 	cma_configfs_exit();
4625c9901724SLeon Romanovsky 	rdma_nl_unregister(RDMA_NL_RDMA_CM);
4626e51060f0SSean Hefty 	ib_unregister_client(&cma_client);
4627dd5bdff8SOr Gerlitz 	unregister_netdevice_notifier(&cma_nb);
4628c1a0b23bSMichael S. Tsirkin 	ib_sa_unregister_client(&sa_client);
46294be74b42SHaggai Eran 	unregister_pernet_subsys(&cma_pernet_operations);
4630e51060f0SSean Hefty 	destroy_workqueue(cma_wq);
4631e51060f0SSean Hefty }
4632e51060f0SSean Hefty 
4633e3bf14bdSJason Gunthorpe MODULE_ALIAS_RDMA_NETLINK(RDMA_NL_RDMA_CM, 1);
4634e3bf14bdSJason Gunthorpe 
4635e51060f0SSean Hefty module_init(cma_init);
4636e51060f0SSean Hefty module_exit(cma_cleanup);
4637