xref: /linux/drivers/infiniband/core/cma.c (revision 88145678924891bdb959010de20b1bb4f27542d5)
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;
7351dfce294SParav Pandit 			for (i = 0; !rdma_query_gid(cur_dev->device,
7361dfce294SParav Pandit 						    p, i, &gid);
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 
1632*88145678SParav Pandit static void cma_leave_roce_mc_group(struct rdma_id_private *id_priv,
1633*88145678SParav Pandit 				    struct cma_multicast *mc)
1634*88145678SParav Pandit {
1635*88145678SParav Pandit 	if (mc->igmp_joined) {
1636*88145678SParav Pandit 		struct rdma_dev_addr *dev_addr =
1637*88145678SParav Pandit 			&id_priv->id.route.addr.dev_addr;
1638*88145678SParav Pandit 		struct net_device *ndev = NULL;
1639*88145678SParav Pandit 
1640*88145678SParav Pandit 		if (dev_addr->bound_dev_if)
1641*88145678SParav Pandit 			ndev = dev_get_by_index(dev_addr->net,
1642*88145678SParav Pandit 						dev_addr->bound_dev_if);
1643*88145678SParav Pandit 		if (ndev) {
1644*88145678SParav Pandit 			cma_igmp_send(ndev,
1645*88145678SParav Pandit 				      &mc->multicast.ib->rec.mgid,
1646*88145678SParav Pandit 				      false);
1647*88145678SParav Pandit 			dev_put(ndev);
1648*88145678SParav Pandit 		}
1649*88145678SParav Pandit 		mc->igmp_joined = false;
1650*88145678SParav Pandit 	}
1651*88145678SParav Pandit 	kref_put(&mc->mcref, release_mc);
1652*88145678SParav Pandit }
1653*88145678SParav Pandit 
1654c8f6a362SSean Hefty static void cma_leave_mc_groups(struct rdma_id_private *id_priv)
1655c8f6a362SSean Hefty {
1656c8f6a362SSean Hefty 	struct cma_multicast *mc;
1657c8f6a362SSean Hefty 
1658c8f6a362SSean Hefty 	while (!list_empty(&id_priv->mc_list)) {
1659c8f6a362SSean Hefty 		mc = container_of(id_priv->mc_list.next,
1660c8f6a362SSean Hefty 				  struct cma_multicast, list);
1661c8f6a362SSean Hefty 		list_del(&mc->list);
1662a31ad3b0SMichael Wang 		if (rdma_cap_ib_mcast(id_priv->cma_dev->device,
16635c9a5282SMichael Wang 				      id_priv->id.port_num)) {
1664c8f6a362SSean Hefty 			ib_sa_free_multicast(mc->multicast.ib);
1665c8f6a362SSean Hefty 			kfree(mc);
1666bee3c3c9SMoni Shoua 		} else {
1667*88145678SParav Pandit 			cma_leave_roce_mc_group(id_priv, mc);
1668c8f6a362SSean Hefty 		}
1669c8f6a362SSean Hefty 	}
1670bee3c3c9SMoni Shoua }
1671c8f6a362SSean Hefty 
1672e51060f0SSean Hefty void rdma_destroy_id(struct rdma_cm_id *id)
1673e51060f0SSean Hefty {
1674e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
1675550e5ca7SNir Muchtar 	enum rdma_cm_state state;
1676e51060f0SSean Hefty 
1677e51060f0SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
1678550e5ca7SNir Muchtar 	state = cma_exch(id_priv, RDMA_CM_DESTROYING);
1679e51060f0SSean Hefty 	cma_cancel_operation(id_priv, state);
1680e51060f0SSean Hefty 
1681a396d43aSSean Hefty 	/*
1682a396d43aSSean Hefty 	 * Wait for any active callback to finish.  New callbacks will find
1683a396d43aSSean Hefty 	 * the id_priv state set to destroying and abort.
1684a396d43aSSean Hefty 	 */
1685a396d43aSSean Hefty 	mutex_lock(&id_priv->handler_mutex);
1686a396d43aSSean Hefty 	mutex_unlock(&id_priv->handler_mutex);
1687a396d43aSSean Hefty 
1688e51060f0SSean Hefty 	if (id_priv->cma_dev) {
168900313983SSteve Wise 		rdma_restrack_del(&id_priv->res);
169072219ceaSMichael Wang 		if (rdma_cap_ib_cm(id_priv->id.device, 1)) {
16910c9361fcSJack Morgenstein 			if (id_priv->cm_id.ib)
1692e51060f0SSean Hefty 				ib_destroy_cm_id(id_priv->cm_id.ib);
169304215330SMichael Wang 		} else if (rdma_cap_iw_cm(id_priv->id.device, 1)) {
16940c9361fcSJack Morgenstein 			if (id_priv->cm_id.iw)
169507ebafbaSTom Tucker 				iw_destroy_cm_id(id_priv->cm_id.iw);
1696e51060f0SSean Hefty 		}
1697c8f6a362SSean Hefty 		cma_leave_mc_groups(id_priv);
1698a396d43aSSean Hefty 		cma_release_dev(id_priv);
1699e51060f0SSean Hefty 	}
1700e51060f0SSean Hefty 
1701e51060f0SSean Hefty 	cma_release_port(id_priv);
1702e51060f0SSean Hefty 	cma_deref_id(id_priv);
1703e51060f0SSean Hefty 	wait_for_completion(&id_priv->comp);
1704e51060f0SSean Hefty 
1705d02d1f53SSean Hefty 	if (id_priv->internal_id)
1706d02d1f53SSean Hefty 		cma_deref_id(id_priv->id.context);
1707d02d1f53SSean Hefty 
1708e51060f0SSean Hefty 	kfree(id_priv->id.route.path_rec);
1709fa20105eSGuy Shapiro 	put_net(id_priv->id.route.addr.dev_addr.net);
1710e51060f0SSean Hefty 	kfree(id_priv);
1711e51060f0SSean Hefty }
1712e51060f0SSean Hefty EXPORT_SYMBOL(rdma_destroy_id);
1713e51060f0SSean Hefty 
1714e51060f0SSean Hefty static int cma_rep_recv(struct rdma_id_private *id_priv)
1715e51060f0SSean Hefty {
1716e51060f0SSean Hefty 	int ret;
1717e51060f0SSean Hefty 
17185851bb89SSean Hefty 	ret = cma_modify_qp_rtr(id_priv, NULL);
1719e51060f0SSean Hefty 	if (ret)
1720e51060f0SSean Hefty 		goto reject;
1721e51060f0SSean Hefty 
17225851bb89SSean Hefty 	ret = cma_modify_qp_rts(id_priv, NULL);
1723e51060f0SSean Hefty 	if (ret)
1724e51060f0SSean Hefty 		goto reject;
1725e51060f0SSean Hefty 
1726e51060f0SSean Hefty 	ret = ib_send_cm_rtu(id_priv->cm_id.ib, NULL, 0);
1727e51060f0SSean Hefty 	if (ret)
1728e51060f0SSean Hefty 		goto reject;
1729e51060f0SSean Hefty 
1730e51060f0SSean Hefty 	return 0;
1731e51060f0SSean Hefty reject:
1732498683c6SMoni Shoua 	pr_debug_ratelimited("RDMA CM: CONNECT_ERROR: failed to handle reply. status %d\n", ret);
1733c5483388SSean Hefty 	cma_modify_qp_err(id_priv);
1734e51060f0SSean Hefty 	ib_send_cm_rej(id_priv->cm_id.ib, IB_CM_REJ_CONSUMER_DEFINED,
1735e51060f0SSean Hefty 		       NULL, 0, NULL, 0);
1736e51060f0SSean Hefty 	return ret;
1737e51060f0SSean Hefty }
1738e51060f0SSean Hefty 
1739a1b1b61fSSean Hefty static void cma_set_rep_event_data(struct rdma_cm_event *event,
1740a1b1b61fSSean Hefty 				   struct ib_cm_rep_event_param *rep_data,
1741a1b1b61fSSean Hefty 				   void *private_data)
1742a1b1b61fSSean Hefty {
1743a1b1b61fSSean Hefty 	event->param.conn.private_data = private_data;
1744a1b1b61fSSean Hefty 	event->param.conn.private_data_len = IB_CM_REP_PRIVATE_DATA_SIZE;
1745a1b1b61fSSean Hefty 	event->param.conn.responder_resources = rep_data->responder_resources;
1746a1b1b61fSSean Hefty 	event->param.conn.initiator_depth = rep_data->initiator_depth;
1747a1b1b61fSSean Hefty 	event->param.conn.flow_control = rep_data->flow_control;
1748a1b1b61fSSean Hefty 	event->param.conn.rnr_retry_count = rep_data->rnr_retry_count;
1749a1b1b61fSSean Hefty 	event->param.conn.srq = rep_data->srq;
1750a1b1b61fSSean Hefty 	event->param.conn.qp_num = rep_data->remote_qpn;
1751a1b1b61fSSean Hefty }
1752a1b1b61fSSean Hefty 
1753e51060f0SSean Hefty static int cma_ib_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
1754e51060f0SSean Hefty {
1755e51060f0SSean Hefty 	struct rdma_id_private *id_priv = cm_id->context;
1756a1b1b61fSSean Hefty 	struct rdma_cm_event event;
1757a1b1b61fSSean Hefty 	int ret = 0;
1758e51060f0SSean Hefty 
175937e07cdaSBart Van Assche 	mutex_lock(&id_priv->handler_mutex);
176038ca83a5SAmir Vadai 	if ((ib_event->event != IB_CM_TIMEWAIT_EXIT &&
176137e07cdaSBart Van Assche 	     id_priv->state != RDMA_CM_CONNECT) ||
176238ca83a5SAmir Vadai 	    (ib_event->event == IB_CM_TIMEWAIT_EXIT &&
176337e07cdaSBart Van Assche 	     id_priv->state != RDMA_CM_DISCONNECT))
176437e07cdaSBart Van Assche 		goto out;
1765e51060f0SSean Hefty 
1766a1b1b61fSSean Hefty 	memset(&event, 0, sizeof event);
1767e51060f0SSean Hefty 	switch (ib_event->event) {
1768e51060f0SSean Hefty 	case IB_CM_REQ_ERROR:
1769e51060f0SSean Hefty 	case IB_CM_REP_ERROR:
1770a1b1b61fSSean Hefty 		event.event = RDMA_CM_EVENT_UNREACHABLE;
1771a1b1b61fSSean Hefty 		event.status = -ETIMEDOUT;
1772e51060f0SSean Hefty 		break;
1773e51060f0SSean Hefty 	case IB_CM_REP_RECEIVED:
177461c0ddbeSMoni Shoua 		if (cma_comp(id_priv, RDMA_CM_CONNECT) &&
177561c0ddbeSMoni Shoua 		    (id_priv->id.qp_type != IB_QPT_UD))
177661c0ddbeSMoni Shoua 			ib_send_cm_mra(cm_id, CMA_CM_MRA_SETTING, NULL, 0);
177701602f11SSean Hefty 		if (id_priv->id.qp) {
1778a1b1b61fSSean Hefty 			event.status = cma_rep_recv(id_priv);
1779a1b1b61fSSean Hefty 			event.event = event.status ? RDMA_CM_EVENT_CONNECT_ERROR :
1780e51060f0SSean Hefty 						     RDMA_CM_EVENT_ESTABLISHED;
178101602f11SSean Hefty 		} else {
1782a1b1b61fSSean Hefty 			event.event = RDMA_CM_EVENT_CONNECT_RESPONSE;
178301602f11SSean Hefty 		}
1784a1b1b61fSSean Hefty 		cma_set_rep_event_data(&event, &ib_event->param.rep_rcvd,
1785a1b1b61fSSean Hefty 				       ib_event->private_data);
1786e51060f0SSean Hefty 		break;
1787e51060f0SSean Hefty 	case IB_CM_RTU_RECEIVED:
17880fe313b0SSean Hefty 	case IB_CM_USER_ESTABLISHED:
17890fe313b0SSean Hefty 		event.event = RDMA_CM_EVENT_ESTABLISHED;
1790e51060f0SSean Hefty 		break;
1791e51060f0SSean Hefty 	case IB_CM_DREQ_ERROR:
1792a1b1b61fSSean Hefty 		event.status = -ETIMEDOUT; /* fall through */
1793e51060f0SSean Hefty 	case IB_CM_DREQ_RECEIVED:
1794e51060f0SSean Hefty 	case IB_CM_DREP_RECEIVED:
1795550e5ca7SNir Muchtar 		if (!cma_comp_exch(id_priv, RDMA_CM_CONNECT,
1796550e5ca7SNir Muchtar 				   RDMA_CM_DISCONNECT))
1797e51060f0SSean Hefty 			goto out;
1798a1b1b61fSSean Hefty 		event.event = RDMA_CM_EVENT_DISCONNECTED;
1799e51060f0SSean Hefty 		break;
1800e51060f0SSean Hefty 	case IB_CM_TIMEWAIT_EXIT:
180138ca83a5SAmir Vadai 		event.event = RDMA_CM_EVENT_TIMEWAIT_EXIT;
180238ca83a5SAmir Vadai 		break;
1803e51060f0SSean Hefty 	case IB_CM_MRA_RECEIVED:
1804e51060f0SSean Hefty 		/* ignore event */
1805e51060f0SSean Hefty 		goto out;
1806e51060f0SSean Hefty 	case IB_CM_REJ_RECEIVED:
1807498683c6SMoni Shoua 		pr_debug_ratelimited("RDMA CM: REJECTED: %s\n", rdma_reject_msg(&id_priv->id,
1808498683c6SMoni Shoua 										ib_event->param.rej_rcvd.reason));
1809c5483388SSean Hefty 		cma_modify_qp_err(id_priv);
1810a1b1b61fSSean Hefty 		event.status = ib_event->param.rej_rcvd.reason;
1811a1b1b61fSSean Hefty 		event.event = RDMA_CM_EVENT_REJECTED;
1812a1b1b61fSSean Hefty 		event.param.conn.private_data = ib_event->private_data;
1813a1b1b61fSSean Hefty 		event.param.conn.private_data_len = IB_CM_REJ_PRIVATE_DATA_SIZE;
1814e51060f0SSean Hefty 		break;
1815e51060f0SSean Hefty 	default:
1816aba25a3eSParav Pandit 		pr_err("RDMA CMA: unexpected IB CM event: %d\n",
1817e51060f0SSean Hefty 		       ib_event->event);
1818e51060f0SSean Hefty 		goto out;
1819e51060f0SSean Hefty 	}
1820e51060f0SSean Hefty 
1821a1b1b61fSSean Hefty 	ret = id_priv->id.event_handler(&id_priv->id, &event);
1822e51060f0SSean Hefty 	if (ret) {
1823e51060f0SSean Hefty 		/* Destroy the CM ID by returning a non-zero value. */
1824e51060f0SSean Hefty 		id_priv->cm_id.ib = NULL;
1825550e5ca7SNir Muchtar 		cma_exch(id_priv, RDMA_CM_DESTROYING);
1826de910bd9SOr Gerlitz 		mutex_unlock(&id_priv->handler_mutex);
1827e51060f0SSean Hefty 		rdma_destroy_id(&id_priv->id);
1828e51060f0SSean Hefty 		return ret;
1829e51060f0SSean Hefty 	}
1830e51060f0SSean Hefty out:
1831de910bd9SOr Gerlitz 	mutex_unlock(&id_priv->handler_mutex);
1832e51060f0SSean Hefty 	return ret;
1833e51060f0SSean Hefty }
1834e51060f0SSean Hefty 
1835628e5f6dSSean Hefty static struct rdma_id_private *cma_new_conn_id(struct rdma_cm_id *listen_id,
18360b3ca768SHaggai Eran 					       struct ib_cm_event *ib_event,
18370b3ca768SHaggai Eran 					       struct net_device *net_dev)
1838e51060f0SSean Hefty {
183900313983SSteve Wise 	struct rdma_id_private *listen_id_priv;
1840e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
1841e51060f0SSean Hefty 	struct rdma_cm_id *id;
1842e51060f0SSean Hefty 	struct rdma_route *rt;
18430c505f70SHaggai Eran 	const sa_family_t ss_family = listen_id->route.addr.src_addr.ss_family;
18449fdca4daSDasaratharaman Chandramouli 	struct sa_path_rec *path = ib_event->param.req_rcvd.primary_path;
1845d3957b86SMajd Dibbiny 	const __be64 service_id =
1846d3957b86SMajd Dibbiny 		ib_event->param.req_rcvd.primary_path->service_id;
184764c5e613SOr Gerlitz 	int ret;
1848e51060f0SSean Hefty 
184900313983SSteve Wise 	listen_id_priv = container_of(listen_id, struct rdma_id_private, id);
185000313983SSteve Wise 	id = __rdma_create_id(listen_id->route.addr.dev_addr.net,
1851fa20105eSGuy Shapiro 			    listen_id->event_handler, listen_id->context,
185200313983SSteve Wise 			    listen_id->ps, ib_event->param.req_rcvd.qp_type,
185300313983SSteve Wise 			    listen_id_priv->res.kern_name);
18543f168d2bSKrishna Kumar 	if (IS_ERR(id))
18550c9361fcSJack Morgenstein 		return NULL;
18563f168d2bSKrishna Kumar 
1857f4753834SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
18580c505f70SHaggai Eran 	if (cma_save_net_info((struct sockaddr *)&id->route.addr.src_addr,
18590c505f70SHaggai Eran 			      (struct sockaddr *)&id->route.addr.dst_addr,
18600c505f70SHaggai Eran 			      listen_id, ib_event, ss_family, service_id))
1861fbaa1a6dSSean Hefty 		goto err;
18623f168d2bSKrishna Kumar 
18633f168d2bSKrishna Kumar 	rt = &id->route;
18643f168d2bSKrishna Kumar 	rt->num_paths = ib_event->param.req_rcvd.alternate_path ? 2 : 1;
18656da2ec56SKees Cook 	rt->path_rec = kmalloc_array(rt->num_paths, sizeof(*rt->path_rec),
18663f168d2bSKrishna Kumar 				     GFP_KERNEL);
18673f168d2bSKrishna Kumar 	if (!rt->path_rec)
18680c9361fcSJack Morgenstein 		goto err;
18693f168d2bSKrishna Kumar 
18709fdca4daSDasaratharaman Chandramouli 	rt->path_rec[0] = *path;
1871e51060f0SSean Hefty 	if (rt->num_paths == 2)
1872e51060f0SSean Hefty 		rt->path_rec[1] = *ib_event->param.req_rcvd.alternate_path;
1873e51060f0SSean Hefty 
18740b3ca768SHaggai Eran 	if (net_dev) {
1875e08ce2e8SYuval Shaia 		rdma_copy_addr(&rt->addr.dev_addr, net_dev, NULL);
18760b3ca768SHaggai Eran 	} else {
1877b8cab5daSHaggai Eran 		if (!cma_protocol_roce(listen_id) &&
1878b8cab5daSHaggai Eran 		    cma_any_addr(cma_src_addr(id_priv))) {
1879b8cab5daSHaggai Eran 			rt->addr.dev_addr.dev_type = ARPHRD_INFINIBAND;
1880b8cab5daSHaggai Eran 			rdma_addr_set_sgid(&rt->addr.dev_addr, &rt->path_rec[0].sgid);
1881b8cab5daSHaggai Eran 			ib_addr_set_pkey(&rt->addr.dev_addr, be16_to_cpu(rt->path_rec[0].pkey));
1882b8cab5daSHaggai Eran 		} else if (!cma_any_addr(cma_src_addr(id_priv))) {
1883b8cab5daSHaggai Eran 			ret = cma_translate_addr(cma_src_addr(id_priv), &rt->addr.dev_addr);
1884b8cab5daSHaggai Eran 			if (ret)
1885b8cab5daSHaggai Eran 				goto err;
1886b8cab5daSHaggai Eran 		}
18876f8372b6SSean Hefty 	}
18886f8372b6SSean Hefty 	rdma_addr_set_dgid(&rt->addr.dev_addr, &rt->path_rec[0].dgid);
1889e51060f0SSean Hefty 
1890550e5ca7SNir Muchtar 	id_priv->state = RDMA_CM_CONNECT;
1891e51060f0SSean Hefty 	return id_priv;
18923f168d2bSKrishna Kumar 
18933f168d2bSKrishna Kumar err:
18940c9361fcSJack Morgenstein 	rdma_destroy_id(id);
1895e51060f0SSean Hefty 	return NULL;
1896e51060f0SSean Hefty }
1897e51060f0SSean Hefty 
1898628e5f6dSSean Hefty static struct rdma_id_private *cma_new_udp_id(struct rdma_cm_id *listen_id,
18990b3ca768SHaggai Eran 					      struct ib_cm_event *ib_event,
19000b3ca768SHaggai Eran 					      struct net_device *net_dev)
1901628e5f6dSSean Hefty {
190200313983SSteve Wise 	struct rdma_id_private *listen_id_priv;
1903628e5f6dSSean Hefty 	struct rdma_id_private *id_priv;
1904628e5f6dSSean Hefty 	struct rdma_cm_id *id;
19050c505f70SHaggai Eran 	const sa_family_t ss_family = listen_id->route.addr.src_addr.ss_family;
1906fa20105eSGuy Shapiro 	struct net *net = listen_id->route.addr.dev_addr.net;
1907628e5f6dSSean Hefty 	int ret;
1908628e5f6dSSean Hefty 
190900313983SSteve Wise 	listen_id_priv = container_of(listen_id, struct rdma_id_private, id);
191000313983SSteve Wise 	id = __rdma_create_id(net, listen_id->event_handler, listen_id->context,
191100313983SSteve Wise 			      listen_id->ps, IB_QPT_UD,
191200313983SSteve Wise 			      listen_id_priv->res.kern_name);
1913628e5f6dSSean Hefty 	if (IS_ERR(id))
1914628e5f6dSSean Hefty 		return NULL;
1915628e5f6dSSean Hefty 
1916f4753834SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
19170c505f70SHaggai Eran 	if (cma_save_net_info((struct sockaddr *)&id->route.addr.src_addr,
19180c505f70SHaggai Eran 			      (struct sockaddr *)&id->route.addr.dst_addr,
19190c505f70SHaggai Eran 			      listen_id, ib_event, ss_family,
19200c505f70SHaggai Eran 			      ib_event->param.sidr_req_rcvd.service_id))
1921628e5f6dSSean Hefty 		goto err;
1922628e5f6dSSean Hefty 
19230b3ca768SHaggai Eran 	if (net_dev) {
1924e08ce2e8SYuval Shaia 		rdma_copy_addr(&id->route.addr.dev_addr, net_dev, NULL);
19250b3ca768SHaggai Eran 	} else {
1926b8cab5daSHaggai Eran 		if (!cma_any_addr(cma_src_addr(id_priv))) {
1927b8cab5daSHaggai Eran 			ret = cma_translate_addr(cma_src_addr(id_priv),
19280b3ca768SHaggai Eran 						 &id->route.addr.dev_addr);
1929b8cab5daSHaggai Eran 			if (ret)
1930b8cab5daSHaggai Eran 				goto err;
1931b8cab5daSHaggai Eran 		}
19326f8372b6SSean Hefty 	}
1933628e5f6dSSean Hefty 
1934550e5ca7SNir Muchtar 	id_priv->state = RDMA_CM_CONNECT;
1935628e5f6dSSean Hefty 	return id_priv;
1936628e5f6dSSean Hefty err:
1937628e5f6dSSean Hefty 	rdma_destroy_id(id);
1938628e5f6dSSean Hefty 	return NULL;
1939628e5f6dSSean Hefty }
1940628e5f6dSSean Hefty 
1941a1b1b61fSSean Hefty static void cma_set_req_event_data(struct rdma_cm_event *event,
1942a1b1b61fSSean Hefty 				   struct ib_cm_req_event_param *req_data,
1943a1b1b61fSSean Hefty 				   void *private_data, int offset)
1944a1b1b61fSSean Hefty {
1945a1b1b61fSSean Hefty 	event->param.conn.private_data = private_data + offset;
1946a1b1b61fSSean Hefty 	event->param.conn.private_data_len = IB_CM_REQ_PRIVATE_DATA_SIZE - offset;
1947a1b1b61fSSean Hefty 	event->param.conn.responder_resources = req_data->responder_resources;
1948a1b1b61fSSean Hefty 	event->param.conn.initiator_depth = req_data->initiator_depth;
1949a1b1b61fSSean Hefty 	event->param.conn.flow_control = req_data->flow_control;
1950a1b1b61fSSean Hefty 	event->param.conn.retry_count = req_data->retry_count;
1951a1b1b61fSSean Hefty 	event->param.conn.rnr_retry_count = req_data->rnr_retry_count;
1952a1b1b61fSSean Hefty 	event->param.conn.srq = req_data->srq;
1953a1b1b61fSSean Hefty 	event->param.conn.qp_num = req_data->remote_qpn;
1954a1b1b61fSSean Hefty }
1955a1b1b61fSSean Hefty 
19569595480cSHefty, Sean static int cma_check_req_qp_type(struct rdma_cm_id *id, struct ib_cm_event *ib_event)
19579595480cSHefty, Sean {
19584dd81e89SSean Hefty 	return (((ib_event->event == IB_CM_REQ_RECEIVED) &&
19599595480cSHefty, Sean 		 (ib_event->param.req_rcvd.qp_type == id->qp_type)) ||
19609595480cSHefty, Sean 		((ib_event->event == IB_CM_SIDR_REQ_RECEIVED) &&
19619595480cSHefty, Sean 		 (id->qp_type == IB_QPT_UD)) ||
19629595480cSHefty, Sean 		(!id->qp_type));
19639595480cSHefty, Sean }
19649595480cSHefty, Sean 
1965e51060f0SSean Hefty static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
1966e51060f0SSean Hefty {
196737e07cdaSBart Van Assche 	struct rdma_id_private *listen_id, *conn_id = NULL;
1968a1b1b61fSSean Hefty 	struct rdma_cm_event event;
19690b3ca768SHaggai Eran 	struct net_device *net_dev;
1970c0b64f58SBart Van Assche 	u8 offset;
1971c0b64f58SBart Van Assche 	int ret;
1972e51060f0SSean Hefty 
19730b3ca768SHaggai Eran 	listen_id = cma_id_from_event(cm_id, ib_event, &net_dev);
19744c21b5bcSHaggai Eran 	if (IS_ERR(listen_id))
19754c21b5bcSHaggai Eran 		return PTR_ERR(listen_id);
19764c21b5bcSHaggai Eran 
19770b3ca768SHaggai Eran 	if (!cma_check_req_qp_type(&listen_id->id, ib_event)) {
19780b3ca768SHaggai Eran 		ret = -EINVAL;
19790b3ca768SHaggai Eran 		goto net_dev_put;
19800b3ca768SHaggai Eran 	}
19819595480cSHefty, Sean 
198237e07cdaSBart Van Assche 	mutex_lock(&listen_id->handler_mutex);
198337e07cdaSBart Van Assche 	if (listen_id->state != RDMA_CM_LISTEN) {
19840b3ca768SHaggai Eran 		ret = -ECONNABORTED;
198537e07cdaSBart Van Assche 		goto err1;
19860b3ca768SHaggai Eran 	}
1987e51060f0SSean Hefty 
1988628e5f6dSSean Hefty 	memset(&event, 0, sizeof event);
1989e8160e15SSean Hefty 	offset = cma_user_data_offset(listen_id);
1990628e5f6dSSean Hefty 	event.event = RDMA_CM_EVENT_CONNECT_REQUEST;
19919595480cSHefty, Sean 	if (ib_event->event == IB_CM_SIDR_REQ_RECEIVED) {
19920b3ca768SHaggai Eran 		conn_id = cma_new_udp_id(&listen_id->id, ib_event, net_dev);
1993628e5f6dSSean Hefty 		event.param.ud.private_data = ib_event->private_data + offset;
1994628e5f6dSSean Hefty 		event.param.ud.private_data_len =
1995628e5f6dSSean Hefty 				IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE - offset;
1996628e5f6dSSean Hefty 	} else {
19970b3ca768SHaggai Eran 		conn_id = cma_new_conn_id(&listen_id->id, ib_event, net_dev);
1998628e5f6dSSean Hefty 		cma_set_req_event_data(&event, &ib_event->param.req_rcvd,
1999628e5f6dSSean Hefty 				       ib_event->private_data, offset);
2000628e5f6dSSean Hefty 	}
2001e51060f0SSean Hefty 	if (!conn_id) {
2002e51060f0SSean Hefty 		ret = -ENOMEM;
2003b6cec8aaSSean Hefty 		goto err1;
2004e51060f0SSean Hefty 	}
2005e51060f0SSean Hefty 
2006de910bd9SOr Gerlitz 	mutex_lock_nested(&conn_id->handler_mutex, SINGLE_DEPTH_NESTING);
2007be9130ccSDoug Ledford 	ret = cma_acquire_dev(conn_id, listen_id);
2008a1a733f6SKrishna Kumar 	if (ret)
2009b6cec8aaSSean Hefty 		goto err2;
2010e51060f0SSean Hefty 
2011e51060f0SSean Hefty 	conn_id->cm_id.ib = cm_id;
2012e51060f0SSean Hefty 	cm_id->context = conn_id;
2013e51060f0SSean Hefty 	cm_id->cm_handler = cma_ib_handler;
2014e51060f0SSean Hefty 
201525ae21a1SSean Hefty 	/*
201625ae21a1SSean Hefty 	 * Protect against the user destroying conn_id from another thread
201725ae21a1SSean Hefty 	 * until we're done accessing it.
201825ae21a1SSean Hefty 	 */
201925ae21a1SSean Hefty 	atomic_inc(&conn_id->refcount);
2020a1b1b61fSSean Hefty 	ret = conn_id->id.event_handler(&conn_id->id, &event);
2021b6cec8aaSSean Hefty 	if (ret)
2022b6cec8aaSSean Hefty 		goto err3;
2023ead595aeSSean Hefty 	/*
2024ead595aeSSean Hefty 	 * Acquire mutex to prevent user executing rdma_destroy_id()
2025ead595aeSSean Hefty 	 * while we're accessing the cm_id.
2026ead595aeSSean Hefty 	 */
2027ead595aeSSean Hefty 	mutex_lock(&lock);
2028dd5f03beSMatan Barak 	if (cma_comp(conn_id, RDMA_CM_CONNECT) &&
2029dd5f03beSMatan Barak 	    (conn_id->id.qp_type != IB_QPT_UD))
2030ead595aeSSean Hefty 		ib_send_cm_mra(cm_id, CMA_CM_MRA_SETTING, NULL, 0);
2031ead595aeSSean Hefty 	mutex_unlock(&lock);
2032de910bd9SOr Gerlitz 	mutex_unlock(&conn_id->handler_mutex);
2033b6cec8aaSSean Hefty 	mutex_unlock(&listen_id->handler_mutex);
203425ae21a1SSean Hefty 	cma_deref_id(conn_id);
20350b3ca768SHaggai Eran 	if (net_dev)
20360b3ca768SHaggai Eran 		dev_put(net_dev);
2037b6cec8aaSSean Hefty 	return 0;
2038a1a733f6SKrishna Kumar 
2039b6cec8aaSSean Hefty err3:
2040b6cec8aaSSean Hefty 	cma_deref_id(conn_id);
2041e51060f0SSean Hefty 	/* Destroy the CM ID by returning a non-zero value. */
2042e51060f0SSean Hefty 	conn_id->cm_id.ib = NULL;
2043b6cec8aaSSean Hefty err2:
2044550e5ca7SNir Muchtar 	cma_exch(conn_id, RDMA_CM_DESTROYING);
2045de910bd9SOr Gerlitz 	mutex_unlock(&conn_id->handler_mutex);
2046b6cec8aaSSean Hefty err1:
2047de910bd9SOr Gerlitz 	mutex_unlock(&listen_id->handler_mutex);
2048b6cec8aaSSean Hefty 	if (conn_id)
2049b6cec8aaSSean Hefty 		rdma_destroy_id(&conn_id->id);
20500b3ca768SHaggai Eran 
20510b3ca768SHaggai Eran net_dev_put:
20520b3ca768SHaggai Eran 	if (net_dev)
20530b3ca768SHaggai Eran 		dev_put(net_dev);
20540b3ca768SHaggai Eran 
2055e51060f0SSean Hefty 	return ret;
2056e51060f0SSean Hefty }
2057e51060f0SSean Hefty 
2058cf53936fSSean Hefty __be64 rdma_get_service_id(struct rdma_cm_id *id, struct sockaddr *addr)
2059e51060f0SSean Hefty {
2060496ce3ceSSean Hefty 	if (addr->sa_family == AF_IB)
2061496ce3ceSSean Hefty 		return ((struct sockaddr_ib *) addr)->sib_sid;
2062496ce3ceSSean Hefty 
2063cf53936fSSean Hefty 	return cpu_to_be64(((u64)id->ps << 16) + be16_to_cpu(cma_port(addr)));
2064e51060f0SSean Hefty }
2065cf53936fSSean Hefty EXPORT_SYMBOL(rdma_get_service_id);
2066e51060f0SSean Hefty 
2067411460acSParav Pandit void rdma_read_gids(struct rdma_cm_id *cm_id, union ib_gid *sgid,
2068411460acSParav Pandit 		    union ib_gid *dgid)
2069411460acSParav Pandit {
2070411460acSParav Pandit 	struct rdma_addr *addr = &cm_id->route.addr;
2071411460acSParav Pandit 
2072411460acSParav Pandit 	if (!cm_id->device) {
2073411460acSParav Pandit 		if (sgid)
2074411460acSParav Pandit 			memset(sgid, 0, sizeof(*sgid));
2075411460acSParav Pandit 		if (dgid)
2076411460acSParav Pandit 			memset(dgid, 0, sizeof(*dgid));
2077411460acSParav Pandit 		return;
2078411460acSParav Pandit 	}
2079411460acSParav Pandit 
2080411460acSParav Pandit 	if (rdma_protocol_roce(cm_id->device, cm_id->port_num)) {
2081411460acSParav Pandit 		if (sgid)
2082411460acSParav Pandit 			rdma_ip2gid((struct sockaddr *)&addr->src_addr, sgid);
2083411460acSParav Pandit 		if (dgid)
2084411460acSParav Pandit 			rdma_ip2gid((struct sockaddr *)&addr->dst_addr, dgid);
2085411460acSParav Pandit 	} else {
2086411460acSParav Pandit 		if (sgid)
2087411460acSParav Pandit 			rdma_addr_get_sgid(&addr->dev_addr, sgid);
2088411460acSParav Pandit 		if (dgid)
2089411460acSParav Pandit 			rdma_addr_get_dgid(&addr->dev_addr, dgid);
2090411460acSParav Pandit 	}
2091411460acSParav Pandit }
2092411460acSParav Pandit EXPORT_SYMBOL(rdma_read_gids);
2093411460acSParav Pandit 
209407ebafbaSTom Tucker static int cma_iw_handler(struct iw_cm_id *iw_id, struct iw_cm_event *iw_event)
209507ebafbaSTom Tucker {
209607ebafbaSTom Tucker 	struct rdma_id_private *id_priv = iw_id->context;
2097a1b1b61fSSean Hefty 	struct rdma_cm_event event;
209807ebafbaSTom Tucker 	int ret = 0;
209924d44a39SSteve Wise 	struct sockaddr *laddr = (struct sockaddr *)&iw_event->local_addr;
210024d44a39SSteve Wise 	struct sockaddr *raddr = (struct sockaddr *)&iw_event->remote_addr;
210107ebafbaSTom Tucker 
210237e07cdaSBart Van Assche 	mutex_lock(&id_priv->handler_mutex);
210337e07cdaSBart Van Assche 	if (id_priv->state != RDMA_CM_CONNECT)
210437e07cdaSBart Van Assche 		goto out;
210507ebafbaSTom Tucker 
2106be65f086SSean Hefty 	memset(&event, 0, sizeof event);
210707ebafbaSTom Tucker 	switch (iw_event->event) {
210807ebafbaSTom Tucker 	case IW_CM_EVENT_CLOSE:
2109a1b1b61fSSean Hefty 		event.event = RDMA_CM_EVENT_DISCONNECTED;
211007ebafbaSTom Tucker 		break;
211107ebafbaSTom Tucker 	case IW_CM_EVENT_CONNECT_REPLY:
211224d44a39SSteve Wise 		memcpy(cma_src_addr(id_priv), laddr,
211324d44a39SSteve Wise 		       rdma_addr_size(laddr));
211424d44a39SSteve Wise 		memcpy(cma_dst_addr(id_priv), raddr,
211524d44a39SSteve Wise 		       rdma_addr_size(raddr));
2116881a045fSSteve Wise 		switch (iw_event->status) {
2117881a045fSSteve Wise 		case 0:
2118a1b1b61fSSean Hefty 			event.event = RDMA_CM_EVENT_ESTABLISHED;
21193ebeebc3SKumar Sanghvi 			event.param.conn.initiator_depth = iw_event->ird;
21203ebeebc3SKumar Sanghvi 			event.param.conn.responder_resources = iw_event->ord;
212107ebafbaSTom Tucker 			break;
2122881a045fSSteve Wise 		case -ECONNRESET:
2123881a045fSSteve Wise 		case -ECONNREFUSED:
2124881a045fSSteve Wise 			event.event = RDMA_CM_EVENT_REJECTED;
2125881a045fSSteve Wise 			break;
2126881a045fSSteve Wise 		case -ETIMEDOUT:
2127881a045fSSteve Wise 			event.event = RDMA_CM_EVENT_UNREACHABLE;
2128881a045fSSteve Wise 			break;
2129881a045fSSteve Wise 		default:
2130881a045fSSteve Wise 			event.event = RDMA_CM_EVENT_CONNECT_ERROR;
2131881a045fSSteve Wise 			break;
2132881a045fSSteve Wise 		}
2133881a045fSSteve Wise 		break;
213407ebafbaSTom Tucker 	case IW_CM_EVENT_ESTABLISHED:
2135a1b1b61fSSean Hefty 		event.event = RDMA_CM_EVENT_ESTABLISHED;
21363ebeebc3SKumar Sanghvi 		event.param.conn.initiator_depth = iw_event->ird;
21373ebeebc3SKumar Sanghvi 		event.param.conn.responder_resources = iw_event->ord;
213807ebafbaSTom Tucker 		break;
213907ebafbaSTom Tucker 	default:
2140671a6cc2SLeon Romanovsky 		goto out;
214107ebafbaSTom Tucker 	}
214207ebafbaSTom Tucker 
2143a1b1b61fSSean Hefty 	event.status = iw_event->status;
2144a1b1b61fSSean Hefty 	event.param.conn.private_data = iw_event->private_data;
2145a1b1b61fSSean Hefty 	event.param.conn.private_data_len = iw_event->private_data_len;
2146a1b1b61fSSean Hefty 	ret = id_priv->id.event_handler(&id_priv->id, &event);
214707ebafbaSTom Tucker 	if (ret) {
214807ebafbaSTom Tucker 		/* Destroy the CM ID by returning a non-zero value. */
214907ebafbaSTom Tucker 		id_priv->cm_id.iw = NULL;
2150550e5ca7SNir Muchtar 		cma_exch(id_priv, RDMA_CM_DESTROYING);
2151de910bd9SOr Gerlitz 		mutex_unlock(&id_priv->handler_mutex);
215207ebafbaSTom Tucker 		rdma_destroy_id(&id_priv->id);
215307ebafbaSTom Tucker 		return ret;
215407ebafbaSTom Tucker 	}
215507ebafbaSTom Tucker 
215637e07cdaSBart Van Assche out:
2157de910bd9SOr Gerlitz 	mutex_unlock(&id_priv->handler_mutex);
215807ebafbaSTom Tucker 	return ret;
215907ebafbaSTom Tucker }
216007ebafbaSTom Tucker 
216107ebafbaSTom Tucker static int iw_conn_req_handler(struct iw_cm_id *cm_id,
216207ebafbaSTom Tucker 			       struct iw_cm_event *iw_event)
216307ebafbaSTom Tucker {
216407ebafbaSTom Tucker 	struct rdma_cm_id *new_cm_id;
216507ebafbaSTom Tucker 	struct rdma_id_private *listen_id, *conn_id;
2166a1b1b61fSSean Hefty 	struct rdma_cm_event event;
216737e07cdaSBart Van Assche 	int ret = -ECONNABORTED;
216824d44a39SSteve Wise 	struct sockaddr *laddr = (struct sockaddr *)&iw_event->local_addr;
216924d44a39SSteve Wise 	struct sockaddr *raddr = (struct sockaddr *)&iw_event->remote_addr;
217007ebafbaSTom Tucker 
217107ebafbaSTom Tucker 	listen_id = cm_id->context;
217237e07cdaSBart Van Assche 
217337e07cdaSBart Van Assche 	mutex_lock(&listen_id->handler_mutex);
217437e07cdaSBart Van Assche 	if (listen_id->state != RDMA_CM_LISTEN)
217537e07cdaSBart Van Assche 		goto out;
217607ebafbaSTom Tucker 
217707ebafbaSTom Tucker 	/* Create a new RDMA id for the new IW CM ID */
217800313983SSteve Wise 	new_cm_id = __rdma_create_id(listen_id->id.route.addr.dev_addr.net,
2179fa20105eSGuy Shapiro 				     listen_id->id.event_handler,
218007ebafbaSTom Tucker 				     listen_id->id.context,
218100313983SSteve Wise 				     RDMA_PS_TCP, IB_QPT_RC,
218200313983SSteve Wise 				     listen_id->res.kern_name);
218310f32065SJulia Lawall 	if (IS_ERR(new_cm_id)) {
218407ebafbaSTom Tucker 		ret = -ENOMEM;
218507ebafbaSTom Tucker 		goto out;
218607ebafbaSTom Tucker 	}
218707ebafbaSTom Tucker 	conn_id = container_of(new_cm_id, struct rdma_id_private, id);
2188de910bd9SOr Gerlitz 	mutex_lock_nested(&conn_id->handler_mutex, SINGLE_DEPTH_NESTING);
2189550e5ca7SNir Muchtar 	conn_id->state = RDMA_CM_CONNECT;
219007ebafbaSTom Tucker 
2191575c7e58SParav Pandit 	ret = rdma_translate_ip(laddr, &conn_id->id.route.addr.dev_addr);
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 
2198be9130ccSDoug Ledford 	ret = cma_acquire_dev(conn_id, listen_id);
219907ebafbaSTom Tucker 	if (ret) {
2200de910bd9SOr Gerlitz 		mutex_unlock(&conn_id->handler_mutex);
220107ebafbaSTom Tucker 		rdma_destroy_id(new_cm_id);
220207ebafbaSTom Tucker 		goto out;
220307ebafbaSTom Tucker 	}
220407ebafbaSTom Tucker 
220507ebafbaSTom Tucker 	conn_id->cm_id.iw = cm_id;
220607ebafbaSTom Tucker 	cm_id->context = conn_id;
220707ebafbaSTom Tucker 	cm_id->cm_handler = cma_iw_handler;
220807ebafbaSTom Tucker 
220924d44a39SSteve Wise 	memcpy(cma_src_addr(conn_id), laddr, rdma_addr_size(laddr));
221024d44a39SSteve Wise 	memcpy(cma_dst_addr(conn_id), raddr, rdma_addr_size(raddr));
221107ebafbaSTom Tucker 
2212a1b1b61fSSean Hefty 	memset(&event, 0, sizeof event);
2213a1b1b61fSSean Hefty 	event.event = RDMA_CM_EVENT_CONNECT_REQUEST;
2214a1b1b61fSSean Hefty 	event.param.conn.private_data = iw_event->private_data;
2215a1b1b61fSSean Hefty 	event.param.conn.private_data_len = iw_event->private_data_len;
22163ebeebc3SKumar Sanghvi 	event.param.conn.initiator_depth = iw_event->ird;
22173ebeebc3SKumar Sanghvi 	event.param.conn.responder_resources = iw_event->ord;
221825ae21a1SSean Hefty 
221925ae21a1SSean Hefty 	/*
222025ae21a1SSean Hefty 	 * Protect against the user destroying conn_id from another thread
222125ae21a1SSean Hefty 	 * until we're done accessing it.
222225ae21a1SSean Hefty 	 */
222325ae21a1SSean Hefty 	atomic_inc(&conn_id->refcount);
2224a1b1b61fSSean Hefty 	ret = conn_id->id.event_handler(&conn_id->id, &event);
222507ebafbaSTom Tucker 	if (ret) {
222607ebafbaSTom Tucker 		/* User wants to destroy the CM ID */
222707ebafbaSTom Tucker 		conn_id->cm_id.iw = NULL;
2228550e5ca7SNir Muchtar 		cma_exch(conn_id, RDMA_CM_DESTROYING);
2229de910bd9SOr Gerlitz 		mutex_unlock(&conn_id->handler_mutex);
223025ae21a1SSean Hefty 		cma_deref_id(conn_id);
223107ebafbaSTom Tucker 		rdma_destroy_id(&conn_id->id);
2232de910bd9SOr Gerlitz 		goto out;
223307ebafbaSTom Tucker 	}
223407ebafbaSTom Tucker 
2235de910bd9SOr Gerlitz 	mutex_unlock(&conn_id->handler_mutex);
223625ae21a1SSean Hefty 	cma_deref_id(conn_id);
2237de910bd9SOr Gerlitz 
223807ebafbaSTom Tucker out:
2239de910bd9SOr Gerlitz 	mutex_unlock(&listen_id->handler_mutex);
224007ebafbaSTom Tucker 	return ret;
224107ebafbaSTom Tucker }
224207ebafbaSTom Tucker 
2243e51060f0SSean Hefty static int cma_ib_listen(struct rdma_id_private *id_priv)
2244e51060f0SSean Hefty {
2245e51060f0SSean Hefty 	struct sockaddr *addr;
22460c9361fcSJack Morgenstein 	struct ib_cm_id	*id;
2247e51060f0SSean Hefty 	__be64 svc_id;
2248e51060f0SSean Hefty 
2249f4753834SSean Hefty 	addr = cma_src_addr(id_priv);
2250cf53936fSSean Hefty 	svc_id = rdma_get_service_id(&id_priv->id, addr);
225151efe394SHaggai Eran 	id = ib_cm_insert_listen(id_priv->id.device, cma_req_handler, svc_id);
225251efe394SHaggai Eran 	if (IS_ERR(id))
225351efe394SHaggai Eran 		return PTR_ERR(id);
225451efe394SHaggai Eran 	id_priv->cm_id.ib = id;
2255e51060f0SSean Hefty 
225651efe394SHaggai Eran 	return 0;
2257e51060f0SSean Hefty }
2258e51060f0SSean Hefty 
225907ebafbaSTom Tucker static int cma_iw_listen(struct rdma_id_private *id_priv, int backlog)
226007ebafbaSTom Tucker {
226107ebafbaSTom Tucker 	int ret;
22620c9361fcSJack Morgenstein 	struct iw_cm_id	*id;
226307ebafbaSTom Tucker 
22640c9361fcSJack Morgenstein 	id = iw_create_cm_id(id_priv->id.device,
226507ebafbaSTom Tucker 			     iw_conn_req_handler,
226607ebafbaSTom Tucker 			     id_priv);
22670c9361fcSJack Morgenstein 	if (IS_ERR(id))
22680c9361fcSJack Morgenstein 		return PTR_ERR(id);
22690c9361fcSJack Morgenstein 
227068cdba06SSteve Wise 	id->tos = id_priv->tos;
22710c9361fcSJack Morgenstein 	id_priv->cm_id.iw = id;
227207ebafbaSTom Tucker 
227324d44a39SSteve Wise 	memcpy(&id_priv->cm_id.iw->local_addr, cma_src_addr(id_priv),
227424d44a39SSteve Wise 	       rdma_addr_size(cma_src_addr(id_priv)));
227507ebafbaSTom Tucker 
227607ebafbaSTom Tucker 	ret = iw_cm_listen(id_priv->cm_id.iw, backlog);
227707ebafbaSTom Tucker 
227807ebafbaSTom Tucker 	if (ret) {
227907ebafbaSTom Tucker 		iw_destroy_cm_id(id_priv->cm_id.iw);
228007ebafbaSTom Tucker 		id_priv->cm_id.iw = NULL;
228107ebafbaSTom Tucker 	}
228207ebafbaSTom Tucker 
228307ebafbaSTom Tucker 	return ret;
228407ebafbaSTom Tucker }
228507ebafbaSTom Tucker 
2286e51060f0SSean Hefty static int cma_listen_handler(struct rdma_cm_id *id,
2287e51060f0SSean Hefty 			      struct rdma_cm_event *event)
2288e51060f0SSean Hefty {
2289e51060f0SSean Hefty 	struct rdma_id_private *id_priv = id->context;
2290e51060f0SSean Hefty 
2291e51060f0SSean Hefty 	id->context = id_priv->id.context;
2292e51060f0SSean Hefty 	id->event_handler = id_priv->id.event_handler;
2293e51060f0SSean Hefty 	return id_priv->id.event_handler(id, event);
2294e51060f0SSean Hefty }
2295e51060f0SSean Hefty 
2296e51060f0SSean Hefty static void cma_listen_on_dev(struct rdma_id_private *id_priv,
2297e51060f0SSean Hefty 			      struct cma_device *cma_dev)
2298e51060f0SSean Hefty {
2299e51060f0SSean Hefty 	struct rdma_id_private *dev_id_priv;
2300e51060f0SSean Hefty 	struct rdma_cm_id *id;
2301fa20105eSGuy Shapiro 	struct net *net = id_priv->id.route.addr.dev_addr.net;
2302e51060f0SSean Hefty 	int ret;
2303e51060f0SSean Hefty 
230472219ceaSMichael Wang 	if (cma_family(id_priv) == AF_IB && !rdma_cap_ib_cm(cma_dev->device, 1))
230594d0c939SSean Hefty 		return;
230694d0c939SSean Hefty 
230700313983SSteve Wise 	id = __rdma_create_id(net, cma_listen_handler, id_priv, id_priv->id.ps,
230800313983SSteve Wise 			      id_priv->id.qp_type, id_priv->res.kern_name);
2309e51060f0SSean Hefty 	if (IS_ERR(id))
2310e51060f0SSean Hefty 		return;
2311e51060f0SSean Hefty 
2312e51060f0SSean Hefty 	dev_id_priv = container_of(id, struct rdma_id_private, id);
2313e51060f0SSean Hefty 
2314550e5ca7SNir Muchtar 	dev_id_priv->state = RDMA_CM_ADDR_BOUND;
2315f4753834SSean Hefty 	memcpy(cma_src_addr(dev_id_priv), cma_src_addr(id_priv),
2316f4753834SSean Hefty 	       rdma_addr_size(cma_src_addr(id_priv)));
2317e51060f0SSean Hefty 
2318045959dbSMatan Barak 	_cma_attach_to_dev(dev_id_priv, cma_dev);
2319e51060f0SSean Hefty 	list_add_tail(&dev_id_priv->listen_list, &id_priv->listen_list);
2320d02d1f53SSean Hefty 	atomic_inc(&id_priv->refcount);
2321d02d1f53SSean Hefty 	dev_id_priv->internal_id = 1;
23225b0ec991SSean Hefty 	dev_id_priv->afonly = id_priv->afonly;
2323e51060f0SSean Hefty 
2324e51060f0SSean Hefty 	ret = rdma_listen(id, id_priv->backlog);
2325e51060f0SSean Hefty 	if (ret)
2326aba25a3eSParav Pandit 		pr_warn("RDMA CMA: cma_listen_on_dev, error %d, listening on device %s\n",
2327aba25a3eSParav Pandit 			ret, cma_dev->device->name);
2328e51060f0SSean Hefty }
2329e51060f0SSean Hefty 
2330e51060f0SSean Hefty static void cma_listen_on_all(struct rdma_id_private *id_priv)
2331e51060f0SSean Hefty {
2332e51060f0SSean Hefty 	struct cma_device *cma_dev;
2333e51060f0SSean Hefty 
2334e51060f0SSean Hefty 	mutex_lock(&lock);
2335e51060f0SSean Hefty 	list_add_tail(&id_priv->list, &listen_any_list);
2336e51060f0SSean Hefty 	list_for_each_entry(cma_dev, &dev_list, list)
2337e51060f0SSean Hefty 		cma_listen_on_dev(id_priv, cma_dev);
2338e51060f0SSean Hefty 	mutex_unlock(&lock);
2339e51060f0SSean Hefty }
2340e51060f0SSean Hefty 
2341a81c994dSSean Hefty void rdma_set_service_type(struct rdma_cm_id *id, int tos)
2342a81c994dSSean Hefty {
2343a81c994dSSean Hefty 	struct rdma_id_private *id_priv;
2344a81c994dSSean Hefty 
2345a81c994dSSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
2346a81c994dSSean Hefty 	id_priv->tos = (u8) tos;
234789052d78SMajd Dibbiny 	id_priv->tos_set = true;
2348a81c994dSSean Hefty }
2349a81c994dSSean Hefty EXPORT_SYMBOL(rdma_set_service_type);
2350a81c994dSSean Hefty 
2351c2f8fc4eSDasaratharaman Chandramouli static void cma_query_handler(int status, struct sa_path_rec *path_rec,
2352e51060f0SSean Hefty 			      void *context)
2353e51060f0SSean Hefty {
2354e51060f0SSean Hefty 	struct cma_work *work = context;
2355e51060f0SSean Hefty 	struct rdma_route *route;
2356e51060f0SSean Hefty 
2357e51060f0SSean Hefty 	route = &work->id->id.route;
2358e51060f0SSean Hefty 
2359e51060f0SSean Hefty 	if (!status) {
2360e51060f0SSean Hefty 		route->num_paths = 1;
2361e51060f0SSean Hefty 		*route->path_rec = *path_rec;
2362e51060f0SSean Hefty 	} else {
2363550e5ca7SNir Muchtar 		work->old_state = RDMA_CM_ROUTE_QUERY;
2364550e5ca7SNir Muchtar 		work->new_state = RDMA_CM_ADDR_RESOLVED;
2365e51060f0SSean Hefty 		work->event.event = RDMA_CM_EVENT_ROUTE_ERROR;
23668f0472d3SSean Hefty 		work->event.status = status;
2367498683c6SMoni Shoua 		pr_debug_ratelimited("RDMA CM: ROUTE_ERROR: failed to query path. status %d\n",
2368498683c6SMoni Shoua 				     status);
2369e51060f0SSean Hefty 	}
2370e51060f0SSean Hefty 
2371e51060f0SSean Hefty 	queue_work(cma_wq, &work->work);
2372e51060f0SSean Hefty }
2373e51060f0SSean Hefty 
2374e51060f0SSean Hefty static int cma_query_ib_route(struct rdma_id_private *id_priv, int timeout_ms,
2375e51060f0SSean Hefty 			      struct cma_work *work)
2376e51060f0SSean Hefty {
2377f4753834SSean Hefty 	struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
2378c2f8fc4eSDasaratharaman Chandramouli 	struct sa_path_rec path_rec;
2379a81c994dSSean Hefty 	ib_sa_comp_mask comp_mask;
2380a81c994dSSean Hefty 	struct sockaddr_in6 *sin6;
2381f68194caSSean Hefty 	struct sockaddr_ib *sib;
2382e51060f0SSean Hefty 
2383e51060f0SSean Hefty 	memset(&path_rec, 0, sizeof path_rec);
23844c33bd19SDasaratharaman Chandramouli 
23854c33bd19SDasaratharaman Chandramouli 	if (rdma_cap_opa_ah(id_priv->id.device, id_priv->id.port_num))
23864c33bd19SDasaratharaman Chandramouli 		path_rec.rec_type = SA_PATH_REC_TYPE_OPA;
23874c33bd19SDasaratharaman Chandramouli 	else
23889fdca4daSDasaratharaman Chandramouli 		path_rec.rec_type = SA_PATH_REC_TYPE_IB;
2389f4753834SSean Hefty 	rdma_addr_get_sgid(dev_addr, &path_rec.sgid);
2390f4753834SSean Hefty 	rdma_addr_get_dgid(dev_addr, &path_rec.dgid);
2391f4753834SSean Hefty 	path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr));
2392e51060f0SSean Hefty 	path_rec.numb_path = 1;
2393962063e6SSean Hefty 	path_rec.reversible = 1;
2394d3957b86SMajd Dibbiny 	path_rec.service_id = rdma_get_service_id(&id_priv->id,
2395d3957b86SMajd Dibbiny 						  cma_dst_addr(id_priv));
2396a81c994dSSean Hefty 
2397a81c994dSSean Hefty 	comp_mask = IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID |
2398a81c994dSSean Hefty 		    IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH |
2399a81c994dSSean Hefty 		    IB_SA_PATH_REC_REVERSIBLE | IB_SA_PATH_REC_SERVICE_ID;
2400a81c994dSSean Hefty 
2401f68194caSSean Hefty 	switch (cma_family(id_priv)) {
2402f68194caSSean Hefty 	case AF_INET:
2403a81c994dSSean Hefty 		path_rec.qos_class = cpu_to_be16((u16) id_priv->tos);
2404a81c994dSSean Hefty 		comp_mask |= IB_SA_PATH_REC_QOS_CLASS;
2405f68194caSSean Hefty 		break;
2406f68194caSSean Hefty 	case AF_INET6:
2407f4753834SSean Hefty 		sin6 = (struct sockaddr_in6 *) cma_src_addr(id_priv);
2408a81c994dSSean Hefty 		path_rec.traffic_class = (u8) (be32_to_cpu(sin6->sin6_flowinfo) >> 20);
2409a81c994dSSean Hefty 		comp_mask |= IB_SA_PATH_REC_TRAFFIC_CLASS;
2410f68194caSSean Hefty 		break;
2411f68194caSSean Hefty 	case AF_IB:
2412f68194caSSean Hefty 		sib = (struct sockaddr_ib *) cma_src_addr(id_priv);
2413f68194caSSean Hefty 		path_rec.traffic_class = (u8) (be32_to_cpu(sib->sib_flowinfo) >> 20);
2414f68194caSSean Hefty 		comp_mask |= IB_SA_PATH_REC_TRAFFIC_CLASS;
2415f68194caSSean Hefty 		break;
2416a81c994dSSean Hefty 	}
2417e51060f0SSean Hefty 
2418c1a0b23bSMichael S. Tsirkin 	id_priv->query_id = ib_sa_path_rec_get(&sa_client, id_priv->id.device,
2419e51060f0SSean Hefty 					       id_priv->id.port_num, &path_rec,
2420a81c994dSSean Hefty 					       comp_mask, timeout_ms,
2421a81c994dSSean Hefty 					       GFP_KERNEL, cma_query_handler,
2422a81c994dSSean Hefty 					       work, &id_priv->query);
2423e51060f0SSean Hefty 
2424e51060f0SSean Hefty 	return (id_priv->query_id < 0) ? id_priv->query_id : 0;
2425e51060f0SSean Hefty }
2426e51060f0SSean Hefty 
2427c4028958SDavid Howells static void cma_work_handler(struct work_struct *_work)
2428e51060f0SSean Hefty {
2429c4028958SDavid Howells 	struct cma_work *work = container_of(_work, struct cma_work, work);
2430e51060f0SSean Hefty 	struct rdma_id_private *id_priv = work->id;
2431e51060f0SSean Hefty 	int destroy = 0;
2432e51060f0SSean Hefty 
2433de910bd9SOr Gerlitz 	mutex_lock(&id_priv->handler_mutex);
2434e51060f0SSean Hefty 	if (!cma_comp_exch(id_priv, work->old_state, work->new_state))
2435e51060f0SSean Hefty 		goto out;
2436e51060f0SSean Hefty 
2437e51060f0SSean Hefty 	if (id_priv->id.event_handler(&id_priv->id, &work->event)) {
2438550e5ca7SNir Muchtar 		cma_exch(id_priv, RDMA_CM_DESTROYING);
2439e51060f0SSean Hefty 		destroy = 1;
2440e51060f0SSean Hefty 	}
2441e51060f0SSean Hefty out:
2442de910bd9SOr Gerlitz 	mutex_unlock(&id_priv->handler_mutex);
2443e51060f0SSean Hefty 	cma_deref_id(id_priv);
2444e51060f0SSean Hefty 	if (destroy)
2445e51060f0SSean Hefty 		rdma_destroy_id(&id_priv->id);
2446e51060f0SSean Hefty 	kfree(work);
2447e51060f0SSean Hefty }
2448e51060f0SSean Hefty 
2449dd5bdff8SOr Gerlitz static void cma_ndev_work_handler(struct work_struct *_work)
2450dd5bdff8SOr Gerlitz {
2451dd5bdff8SOr Gerlitz 	struct cma_ndev_work *work = container_of(_work, struct cma_ndev_work, work);
2452dd5bdff8SOr Gerlitz 	struct rdma_id_private *id_priv = work->id;
2453dd5bdff8SOr Gerlitz 	int destroy = 0;
2454dd5bdff8SOr Gerlitz 
2455dd5bdff8SOr Gerlitz 	mutex_lock(&id_priv->handler_mutex);
2456550e5ca7SNir Muchtar 	if (id_priv->state == RDMA_CM_DESTROYING ||
2457550e5ca7SNir Muchtar 	    id_priv->state == RDMA_CM_DEVICE_REMOVAL)
2458dd5bdff8SOr Gerlitz 		goto out;
2459dd5bdff8SOr Gerlitz 
2460dd5bdff8SOr Gerlitz 	if (id_priv->id.event_handler(&id_priv->id, &work->event)) {
2461550e5ca7SNir Muchtar 		cma_exch(id_priv, RDMA_CM_DESTROYING);
2462dd5bdff8SOr Gerlitz 		destroy = 1;
2463dd5bdff8SOr Gerlitz 	}
2464dd5bdff8SOr Gerlitz 
2465dd5bdff8SOr Gerlitz out:
2466dd5bdff8SOr Gerlitz 	mutex_unlock(&id_priv->handler_mutex);
2467dd5bdff8SOr Gerlitz 	cma_deref_id(id_priv);
2468dd5bdff8SOr Gerlitz 	if (destroy)
2469dd5bdff8SOr Gerlitz 		rdma_destroy_id(&id_priv->id);
2470dd5bdff8SOr Gerlitz 	kfree(work);
2471dd5bdff8SOr Gerlitz }
2472dd5bdff8SOr Gerlitz 
2473981b5a23SParav Pandit static void cma_init_resolve_route_work(struct cma_work *work,
2474981b5a23SParav Pandit 					struct rdma_id_private *id_priv)
2475981b5a23SParav Pandit {
2476981b5a23SParav Pandit 	work->id = id_priv;
2477981b5a23SParav Pandit 	INIT_WORK(&work->work, cma_work_handler);
2478981b5a23SParav Pandit 	work->old_state = RDMA_CM_ROUTE_QUERY;
2479981b5a23SParav Pandit 	work->new_state = RDMA_CM_ROUTE_RESOLVED;
2480981b5a23SParav Pandit 	work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED;
2481981b5a23SParav Pandit }
2482981b5a23SParav Pandit 
2483981b5a23SParav Pandit static void cma_init_resolve_addr_work(struct cma_work *work,
2484981b5a23SParav Pandit 				       struct rdma_id_private *id_priv)
2485981b5a23SParav Pandit {
2486981b5a23SParav Pandit 	work->id = id_priv;
2487981b5a23SParav Pandit 	INIT_WORK(&work->work, cma_work_handler);
2488981b5a23SParav Pandit 	work->old_state = RDMA_CM_ADDR_QUERY;
2489981b5a23SParav Pandit 	work->new_state = RDMA_CM_ADDR_RESOLVED;
2490981b5a23SParav Pandit 	work->event.event = RDMA_CM_EVENT_ADDR_RESOLVED;
2491981b5a23SParav Pandit }
2492981b5a23SParav Pandit 
2493e51060f0SSean Hefty static int cma_resolve_ib_route(struct rdma_id_private *id_priv, int timeout_ms)
2494e51060f0SSean Hefty {
2495e51060f0SSean Hefty 	struct rdma_route *route = &id_priv->id.route;
2496e51060f0SSean Hefty 	struct cma_work *work;
2497e51060f0SSean Hefty 	int ret;
2498e51060f0SSean Hefty 
2499e51060f0SSean Hefty 	work = kzalloc(sizeof *work, GFP_KERNEL);
2500e51060f0SSean Hefty 	if (!work)
2501e51060f0SSean Hefty 		return -ENOMEM;
2502e51060f0SSean Hefty 
2503981b5a23SParav Pandit 	cma_init_resolve_route_work(work, id_priv);
2504e51060f0SSean Hefty 
2505e51060f0SSean Hefty 	route->path_rec = kmalloc(sizeof *route->path_rec, GFP_KERNEL);
2506e51060f0SSean Hefty 	if (!route->path_rec) {
2507e51060f0SSean Hefty 		ret = -ENOMEM;
2508e51060f0SSean Hefty 		goto err1;
2509e51060f0SSean Hefty 	}
2510e51060f0SSean Hefty 
2511e51060f0SSean Hefty 	ret = cma_query_ib_route(id_priv, timeout_ms, work);
2512e51060f0SSean Hefty 	if (ret)
2513e51060f0SSean Hefty 		goto err2;
2514e51060f0SSean Hefty 
2515e51060f0SSean Hefty 	return 0;
2516e51060f0SSean Hefty err2:
2517e51060f0SSean Hefty 	kfree(route->path_rec);
2518e51060f0SSean Hefty 	route->path_rec = NULL;
2519e51060f0SSean Hefty err1:
2520e51060f0SSean Hefty 	kfree(work);
2521e51060f0SSean Hefty 	return ret;
2522e51060f0SSean Hefty }
2523e51060f0SSean Hefty 
25249327c7afSParav Pandit static enum ib_gid_type cma_route_gid_type(enum rdma_network_type network_type,
25259327c7afSParav Pandit 					   unsigned long supported_gids,
25269327c7afSParav Pandit 					   enum ib_gid_type default_gid)
25279327c7afSParav Pandit {
25289327c7afSParav Pandit 	if ((network_type == RDMA_NETWORK_IPV4 ||
25299327c7afSParav Pandit 	     network_type == RDMA_NETWORK_IPV6) &&
25309327c7afSParav Pandit 	    test_bit(IB_GID_TYPE_ROCE_UDP_ENCAP, &supported_gids))
25319327c7afSParav Pandit 		return IB_GID_TYPE_ROCE_UDP_ENCAP;
25329327c7afSParav Pandit 
25339327c7afSParav Pandit 	return default_gid;
25349327c7afSParav Pandit }
25359327c7afSParav Pandit 
25369327c7afSParav Pandit /*
25379327c7afSParav Pandit  * cma_iboe_set_path_rec_l2_fields() is helper function which sets
25389327c7afSParav Pandit  * path record type based on GID type.
25399327c7afSParav Pandit  * It also sets up other L2 fields which includes destination mac address
25409327c7afSParav Pandit  * netdev ifindex, of the path record.
25419327c7afSParav Pandit  * It returns the netdev of the bound interface for this path record entry.
25429327c7afSParav Pandit  */
25439327c7afSParav Pandit static struct net_device *
25449327c7afSParav Pandit cma_iboe_set_path_rec_l2_fields(struct rdma_id_private *id_priv)
25459327c7afSParav Pandit {
25469327c7afSParav Pandit 	struct rdma_route *route = &id_priv->id.route;
25479327c7afSParav Pandit 	enum ib_gid_type gid_type = IB_GID_TYPE_ROCE;
25489327c7afSParav Pandit 	struct rdma_addr *addr = &route->addr;
25499327c7afSParav Pandit 	unsigned long supported_gids;
25509327c7afSParav Pandit 	struct net_device *ndev;
25519327c7afSParav Pandit 
25529327c7afSParav Pandit 	if (!addr->dev_addr.bound_dev_if)
25539327c7afSParav Pandit 		return NULL;
25549327c7afSParav Pandit 
25559327c7afSParav Pandit 	ndev = dev_get_by_index(addr->dev_addr.net,
25569327c7afSParav Pandit 				addr->dev_addr.bound_dev_if);
25579327c7afSParav Pandit 	if (!ndev)
25589327c7afSParav Pandit 		return NULL;
25599327c7afSParav Pandit 
25609327c7afSParav Pandit 	supported_gids = roce_gid_type_mask_support(id_priv->id.device,
25619327c7afSParav Pandit 						    id_priv->id.port_num);
25629327c7afSParav Pandit 	gid_type = cma_route_gid_type(addr->dev_addr.network,
25639327c7afSParav Pandit 				      supported_gids,
25649327c7afSParav Pandit 				      id_priv->gid_type);
25659327c7afSParav Pandit 	/* Use the hint from IP Stack to select GID Type */
25669327c7afSParav Pandit 	if (gid_type < ib_network_to_gid_type(addr->dev_addr.network))
25679327c7afSParav Pandit 		gid_type = ib_network_to_gid_type(addr->dev_addr.network);
25689327c7afSParav Pandit 	route->path_rec->rec_type = sa_conv_gid_to_pathrec_type(gid_type);
25699327c7afSParav Pandit 
2570114cc9c4SParav Pandit 	route->path_rec->roce.route_resolved = true;
25719327c7afSParav Pandit 	sa_path_set_ndev(route->path_rec, addr->dev_addr.net);
25729327c7afSParav Pandit 	sa_path_set_ifindex(route->path_rec, ndev->ifindex);
25739327c7afSParav Pandit 	sa_path_set_dmac(route->path_rec, addr->dev_addr.dst_dev_addr);
25749327c7afSParav Pandit 	return ndev;
25759327c7afSParav Pandit }
25769327c7afSParav Pandit 
2577fe75889fSParav Pandit int rdma_set_ib_path(struct rdma_cm_id *id,
2578fe75889fSParav Pandit 		     struct sa_path_rec *path_rec)
2579e51060f0SSean Hefty {
2580e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
25818d20a1f0SParav Pandit 	struct net_device *ndev;
2582e51060f0SSean Hefty 	int ret;
2583e51060f0SSean Hefty 
2584e51060f0SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
2585550e5ca7SNir Muchtar 	if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED,
2586550e5ca7SNir Muchtar 			   RDMA_CM_ROUTE_RESOLVED))
2587e51060f0SSean Hefty 		return -EINVAL;
2588e51060f0SSean Hefty 
2589fe75889fSParav Pandit 	id->route.path_rec = kmemdup(path_rec, sizeof(*path_rec),
25909893e742SJulia Lawall 				     GFP_KERNEL);
2591e51060f0SSean Hefty 	if (!id->route.path_rec) {
2592e51060f0SSean Hefty 		ret = -ENOMEM;
2593e51060f0SSean Hefty 		goto err;
2594e51060f0SSean Hefty 	}
2595e51060f0SSean Hefty 
25968d20a1f0SParav Pandit 	if (rdma_protocol_roce(id->device, id->port_num)) {
25978d20a1f0SParav Pandit 		ndev = cma_iboe_set_path_rec_l2_fields(id_priv);
25988d20a1f0SParav Pandit 		if (!ndev) {
25998d20a1f0SParav Pandit 			ret = -ENODEV;
26008d20a1f0SParav Pandit 			goto err_free;
26018d20a1f0SParav Pandit 		}
26028d20a1f0SParav Pandit 		dev_put(ndev);
26038d20a1f0SParav Pandit 	}
26048d20a1f0SParav Pandit 
2605fe75889fSParav Pandit 	id->route.num_paths = 1;
2606e51060f0SSean Hefty 	return 0;
26078d20a1f0SParav Pandit 
26088d20a1f0SParav Pandit err_free:
26098d20a1f0SParav Pandit 	kfree(id->route.path_rec);
26108d20a1f0SParav Pandit 	id->route.path_rec = NULL;
2611e51060f0SSean Hefty err:
2612550e5ca7SNir Muchtar 	cma_comp_exch(id_priv, RDMA_CM_ROUTE_RESOLVED, RDMA_CM_ADDR_RESOLVED);
2613e51060f0SSean Hefty 	return ret;
2614e51060f0SSean Hefty }
2615fe75889fSParav Pandit EXPORT_SYMBOL(rdma_set_ib_path);
2616e51060f0SSean Hefty 
261707ebafbaSTom Tucker static int cma_resolve_iw_route(struct rdma_id_private *id_priv, int timeout_ms)
261807ebafbaSTom Tucker {
261907ebafbaSTom Tucker 	struct cma_work *work;
262007ebafbaSTom Tucker 
262107ebafbaSTom Tucker 	work = kzalloc(sizeof *work, GFP_KERNEL);
262207ebafbaSTom Tucker 	if (!work)
262307ebafbaSTom Tucker 		return -ENOMEM;
262407ebafbaSTom Tucker 
2625981b5a23SParav Pandit 	cma_init_resolve_route_work(work, id_priv);
262607ebafbaSTom Tucker 	queue_work(cma_wq, &work->work);
262707ebafbaSTom Tucker 	return 0;
262807ebafbaSTom Tucker }
262907ebafbaSTom Tucker 
2630eb072c4bSEyal Perry static int iboe_tos_to_sl(struct net_device *ndev, int tos)
2631eb072c4bSEyal Perry {
2632eb072c4bSEyal Perry 	int prio;
2633eb072c4bSEyal Perry 	struct net_device *dev;
2634eb072c4bSEyal Perry 
2635eb072c4bSEyal Perry 	prio = rt_tos2priority(tos);
2636d0d7b10bSParav Pandit 	dev = is_vlan_dev(ndev) ? vlan_dev_real_dev(ndev) : ndev;
2637eb072c4bSEyal Perry 	if (dev->num_tc)
2638eb072c4bSEyal Perry 		return netdev_get_prio_tc_map(dev, prio);
2639eb072c4bSEyal Perry 
2640eb072c4bSEyal Perry #if IS_ENABLED(CONFIG_VLAN_8021Q)
2641d0d7b10bSParav Pandit 	if (is_vlan_dev(ndev))
2642eb072c4bSEyal Perry 		return (vlan_dev_get_egress_qos_mask(ndev, prio) &
2643eb072c4bSEyal Perry 			VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
2644eb072c4bSEyal Perry #endif
2645eb072c4bSEyal Perry 	return 0;
2646eb072c4bSEyal Perry }
2647eb072c4bSEyal Perry 
26483c86aa70SEli Cohen static int cma_resolve_iboe_route(struct rdma_id_private *id_priv)
26493c86aa70SEli Cohen {
26503c86aa70SEli Cohen 	struct rdma_route *route = &id_priv->id.route;
26513c86aa70SEli Cohen 	struct rdma_addr *addr = &route->addr;
26523c86aa70SEli Cohen 	struct cma_work *work;
26533c86aa70SEli Cohen 	int ret;
26544367ec7fSParav Pandit 	struct net_device *ndev;
26554367ec7fSParav Pandit 
265689052d78SMajd Dibbiny 	u8 default_roce_tos = id_priv->cma_dev->default_roce_tos[id_priv->id.port_num -
265789052d78SMajd Dibbiny 					rdma_start_port(id_priv->cma_dev->device)];
265889052d78SMajd Dibbiny 	u8 tos = id_priv->tos_set ? id_priv->tos : default_roce_tos;
2659dd5f03beSMatan Barak 
26603c86aa70SEli Cohen 
26613c86aa70SEli Cohen 	work = kzalloc(sizeof *work, GFP_KERNEL);
26623c86aa70SEli Cohen 	if (!work)
26633c86aa70SEli Cohen 		return -ENOMEM;
26643c86aa70SEli Cohen 
26653c86aa70SEli Cohen 	route->path_rec = kzalloc(sizeof *route->path_rec, GFP_KERNEL);
26663c86aa70SEli Cohen 	if (!route->path_rec) {
26673c86aa70SEli Cohen 		ret = -ENOMEM;
26683c86aa70SEli Cohen 		goto err1;
26693c86aa70SEli Cohen 	}
26703c86aa70SEli Cohen 
26713c86aa70SEli Cohen 	route->num_paths = 1;
26723c86aa70SEli Cohen 
26739327c7afSParav Pandit 	ndev = cma_iboe_set_path_rec_l2_fields(id_priv);
267423d70503SWei Yongjun 	if (!ndev) {
267523d70503SWei Yongjun 		ret = -ENODEV;
267623d70503SWei Yongjun 		goto err2;
267723d70503SWei Yongjun 	}
267820029832SMatan Barak 
26797b85627bSMoni Shoua 	rdma_ip2gid((struct sockaddr *)&id_priv->id.route.addr.src_addr,
26807b85627bSMoni Shoua 		    &route->path_rec->sgid);
26817b85627bSMoni Shoua 	rdma_ip2gid((struct sockaddr *)&id_priv->id.route.addr.dst_addr,
26827b85627bSMoni Shoua 		    &route->path_rec->dgid);
2683af7bd463SEli Cohen 
2684c3efe750SMatan Barak 	if (((struct sockaddr *)&id_priv->id.route.addr.dst_addr)->sa_family != AF_IB)
2685c865f246SSomnath Kotur 		/* TODO: get the hoplimit from the inet/inet6 device */
2686c3efe750SMatan Barak 		route->path_rec->hop_limit = addr->dev_addr.hoplimit;
2687c3efe750SMatan Barak 	else
2688af7bd463SEli Cohen 		route->path_rec->hop_limit = 1;
2689af7bd463SEli Cohen 	route->path_rec->reversible = 1;
2690af7bd463SEli Cohen 	route->path_rec->pkey = cpu_to_be16(0xffff);
2691af7bd463SEli Cohen 	route->path_rec->mtu_selector = IB_SA_EQ;
269289052d78SMajd Dibbiny 	route->path_rec->sl = iboe_tos_to_sl(ndev, tos);
269389052d78SMajd Dibbiny 	route->path_rec->traffic_class = tos;
26943c86aa70SEli Cohen 	route->path_rec->mtu = iboe_get_mtu(ndev->mtu);
26953c86aa70SEli Cohen 	route->path_rec->rate_selector = IB_SA_EQ;
26963c86aa70SEli Cohen 	route->path_rec->rate = iboe_get_rate(ndev);
26973c86aa70SEli Cohen 	dev_put(ndev);
26983c86aa70SEli Cohen 	route->path_rec->packet_life_time_selector = IB_SA_EQ;
26993c86aa70SEli Cohen 	route->path_rec->packet_life_time = CMA_IBOE_PACKET_LIFETIME;
27003c86aa70SEli Cohen 	if (!route->path_rec->mtu) {
27013c86aa70SEli Cohen 		ret = -EINVAL;
27023c86aa70SEli Cohen 		goto err2;
27033c86aa70SEli Cohen 	}
27043c86aa70SEli Cohen 
2705981b5a23SParav Pandit 	cma_init_resolve_route_work(work, id_priv);
27063c86aa70SEli Cohen 	queue_work(cma_wq, &work->work);
27073c86aa70SEli Cohen 
27083c86aa70SEli Cohen 	return 0;
27093c86aa70SEli Cohen 
27103c86aa70SEli Cohen err2:
27113c86aa70SEli Cohen 	kfree(route->path_rec);
27123c86aa70SEli Cohen 	route->path_rec = NULL;
27133c86aa70SEli Cohen err1:
27143c86aa70SEli Cohen 	kfree(work);
27153c86aa70SEli Cohen 	return ret;
27163c86aa70SEli Cohen }
27173c86aa70SEli Cohen 
2718e51060f0SSean Hefty int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms)
2719e51060f0SSean Hefty {
2720e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
2721e51060f0SSean Hefty 	int ret;
2722e51060f0SSean Hefty 
2723e51060f0SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
2724550e5ca7SNir Muchtar 	if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED, RDMA_CM_ROUTE_QUERY))
2725e51060f0SSean Hefty 		return -EINVAL;
2726e51060f0SSean Hefty 
2727e51060f0SSean Hefty 	atomic_inc(&id_priv->refcount);
2728fe53ba2fSMichael Wang 	if (rdma_cap_ib_sa(id->device, id->port_num))
2729e51060f0SSean Hefty 		ret = cma_resolve_ib_route(id_priv, timeout_ms);
27305d9fb044SIra Weiny 	else if (rdma_protocol_roce(id->device, id->port_num))
27313c86aa70SEli Cohen 		ret = cma_resolve_iboe_route(id_priv);
2732c72f2189SMichael Wang 	else if (rdma_protocol_iwarp(id->device, id->port_num))
273307ebafbaSTom Tucker 		ret = cma_resolve_iw_route(id_priv, timeout_ms);
2734c72f2189SMichael Wang 	else
2735e51060f0SSean Hefty 		ret = -ENOSYS;
2736c72f2189SMichael Wang 
2737e51060f0SSean Hefty 	if (ret)
2738e51060f0SSean Hefty 		goto err;
2739e51060f0SSean Hefty 
2740e51060f0SSean Hefty 	return 0;
2741e51060f0SSean Hefty err:
2742550e5ca7SNir Muchtar 	cma_comp_exch(id_priv, RDMA_CM_ROUTE_QUERY, RDMA_CM_ADDR_RESOLVED);
2743e51060f0SSean Hefty 	cma_deref_id(id_priv);
2744e51060f0SSean Hefty 	return ret;
2745e51060f0SSean Hefty }
2746e51060f0SSean Hefty EXPORT_SYMBOL(rdma_resolve_route);
2747e51060f0SSean Hefty 
27486a3e362dSSean Hefty static void cma_set_loopback(struct sockaddr *addr)
27496a3e362dSSean Hefty {
27506a3e362dSSean Hefty 	switch (addr->sa_family) {
27516a3e362dSSean Hefty 	case AF_INET:
27526a3e362dSSean Hefty 		((struct sockaddr_in *) addr)->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
27536a3e362dSSean Hefty 		break;
27546a3e362dSSean Hefty 	case AF_INET6:
27556a3e362dSSean Hefty 		ipv6_addr_set(&((struct sockaddr_in6 *) addr)->sin6_addr,
27566a3e362dSSean Hefty 			      0, 0, 0, htonl(1));
27576a3e362dSSean Hefty 		break;
27586a3e362dSSean Hefty 	default:
27596a3e362dSSean Hefty 		ib_addr_set(&((struct sockaddr_ib *) addr)->sib_addr,
27606a3e362dSSean Hefty 			    0, 0, 0, htonl(1));
27616a3e362dSSean Hefty 		break;
27626a3e362dSSean Hefty 	}
27636a3e362dSSean Hefty }
27646a3e362dSSean Hefty 
2765e51060f0SSean Hefty static int cma_bind_loopback(struct rdma_id_private *id_priv)
2766e51060f0SSean Hefty {
2767b0569e40SSean Hefty 	struct cma_device *cma_dev, *cur_dev;
2768f0ee3404SMichael S. Tsirkin 	union ib_gid gid;
2769102c5ce0SJack Wang 	enum ib_port_state port_state;
2770e51060f0SSean Hefty 	u16 pkey;
2771e51060f0SSean Hefty 	int ret;
2772e51060f0SSean Hefty 	u8 p;
2773e51060f0SSean Hefty 
2774b0569e40SSean Hefty 	cma_dev = NULL;
2775e51060f0SSean Hefty 	mutex_lock(&lock);
2776b0569e40SSean Hefty 	list_for_each_entry(cur_dev, &dev_list, list) {
2777b0569e40SSean Hefty 		if (cma_family(id_priv) == AF_IB &&
277872219ceaSMichael Wang 		    !rdma_cap_ib_cm(cur_dev->device, 1))
2779b0569e40SSean Hefty 			continue;
2780b0569e40SSean Hefty 
2781b0569e40SSean Hefty 		if (!cma_dev)
2782b0569e40SSean Hefty 			cma_dev = cur_dev;
2783b0569e40SSean Hefty 
2784b0569e40SSean Hefty 		for (p = 1; p <= cur_dev->device->phys_port_cnt; ++p) {
2785102c5ce0SJack Wang 			if (!ib_get_cached_port_state(cur_dev->device, p, &port_state) &&
2786102c5ce0SJack Wang 			    port_state == IB_PORT_ACTIVE) {
2787b0569e40SSean Hefty 				cma_dev = cur_dev;
2788b0569e40SSean Hefty 				goto port_found;
2789b0569e40SSean Hefty 			}
2790b0569e40SSean Hefty 		}
2791b0569e40SSean Hefty 	}
2792b0569e40SSean Hefty 
2793b0569e40SSean Hefty 	if (!cma_dev) {
2794e82153b5SKrishna Kumar 		ret = -ENODEV;
2795e82153b5SKrishna Kumar 		goto out;
2796e82153b5SKrishna Kumar 	}
2797e51060f0SSean Hefty 
2798e51060f0SSean Hefty 	p = 1;
2799e51060f0SSean Hefty 
2800e51060f0SSean Hefty port_found:
28011dfce294SParav Pandit 	ret = rdma_query_gid(cma_dev->device, p, 0, &gid);
2802e51060f0SSean Hefty 	if (ret)
2803e51060f0SSean Hefty 		goto out;
2804e51060f0SSean Hefty 
2805e51060f0SSean Hefty 	ret = ib_get_cached_pkey(cma_dev->device, p, 0, &pkey);
2806e51060f0SSean Hefty 	if (ret)
2807e51060f0SSean Hefty 		goto out;
2808e51060f0SSean Hefty 
28096f8372b6SSean Hefty 	id_priv->id.route.addr.dev_addr.dev_type =
281021655afcSMichael Wang 		(rdma_protocol_ib(cma_dev->device, p)) ?
28116f8372b6SSean Hefty 		ARPHRD_INFINIBAND : ARPHRD_ETHER;
28126f8372b6SSean Hefty 
28136f8372b6SSean Hefty 	rdma_addr_set_sgid(&id_priv->id.route.addr.dev_addr, &gid);
2814e51060f0SSean Hefty 	ib_addr_set_pkey(&id_priv->id.route.addr.dev_addr, pkey);
2815e51060f0SSean Hefty 	id_priv->id.port_num = p;
2816e51060f0SSean Hefty 	cma_attach_to_dev(id_priv, cma_dev);
2817f4753834SSean Hefty 	cma_set_loopback(cma_src_addr(id_priv));
2818e51060f0SSean Hefty out:
2819e51060f0SSean Hefty 	mutex_unlock(&lock);
2820e51060f0SSean Hefty 	return ret;
2821e51060f0SSean Hefty }
2822e51060f0SSean Hefty 
2823e51060f0SSean Hefty static void addr_handler(int status, struct sockaddr *src_addr,
2824e51060f0SSean Hefty 			 struct rdma_dev_addr *dev_addr, void *context)
2825e51060f0SSean Hefty {
2826e51060f0SSean Hefty 	struct rdma_id_private *id_priv = context;
2827a1b1b61fSSean Hefty 	struct rdma_cm_event event;
2828e51060f0SSean Hefty 
2829a1b1b61fSSean Hefty 	memset(&event, 0, sizeof event);
2830de910bd9SOr Gerlitz 	mutex_lock(&id_priv->handler_mutex);
2831550e5ca7SNir Muchtar 	if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_QUERY,
2832550e5ca7SNir Muchtar 			   RDMA_CM_ADDR_RESOLVED))
283361a73c70SSean Hefty 		goto out;
283461a73c70SSean Hefty 
28357b85627bSMoni Shoua 	memcpy(cma_src_addr(id_priv), src_addr, rdma_addr_size(src_addr));
2836498683c6SMoni Shoua 	if (!status && !id_priv->cma_dev) {
2837be9130ccSDoug Ledford 		status = cma_acquire_dev(id_priv, NULL);
2838498683c6SMoni Shoua 		if (status)
2839498683c6SMoni Shoua 			pr_debug_ratelimited("RDMA CM: ADDR_ERROR: failed to acquire device. status %d\n",
2840498683c6SMoni Shoua 					     status);
2841498683c6SMoni Shoua 	} else {
2842498683c6SMoni Shoua 		pr_debug_ratelimited("RDMA CM: ADDR_ERROR: failed to resolve IP. status %d\n", status);
2843498683c6SMoni Shoua 	}
2844e51060f0SSean Hefty 
2845e51060f0SSean Hefty 	if (status) {
2846550e5ca7SNir Muchtar 		if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED,
2847550e5ca7SNir Muchtar 				   RDMA_CM_ADDR_BOUND))
2848e51060f0SSean Hefty 			goto out;
2849a1b1b61fSSean Hefty 		event.event = RDMA_CM_EVENT_ADDR_ERROR;
2850a1b1b61fSSean Hefty 		event.status = status;
28517b85627bSMoni Shoua 	} else
2852a1b1b61fSSean Hefty 		event.event = RDMA_CM_EVENT_ADDR_RESOLVED;
2853e51060f0SSean Hefty 
2854a1b1b61fSSean Hefty 	if (id_priv->id.event_handler(&id_priv->id, &event)) {
2855550e5ca7SNir Muchtar 		cma_exch(id_priv, RDMA_CM_DESTROYING);
2856de910bd9SOr Gerlitz 		mutex_unlock(&id_priv->handler_mutex);
2857e51060f0SSean Hefty 		cma_deref_id(id_priv);
2858e51060f0SSean Hefty 		rdma_destroy_id(&id_priv->id);
2859e51060f0SSean Hefty 		return;
2860e51060f0SSean Hefty 	}
2861e51060f0SSean Hefty out:
2862de910bd9SOr Gerlitz 	mutex_unlock(&id_priv->handler_mutex);
2863e51060f0SSean Hefty 	cma_deref_id(id_priv);
2864e51060f0SSean Hefty }
2865e51060f0SSean Hefty 
2866e51060f0SSean Hefty static int cma_resolve_loopback(struct rdma_id_private *id_priv)
2867e51060f0SSean Hefty {
2868e51060f0SSean Hefty 	struct cma_work *work;
2869f0ee3404SMichael S. Tsirkin 	union ib_gid gid;
2870e51060f0SSean Hefty 	int ret;
2871e51060f0SSean Hefty 
2872e51060f0SSean Hefty 	work = kzalloc(sizeof *work, GFP_KERNEL);
2873e51060f0SSean Hefty 	if (!work)
2874e51060f0SSean Hefty 		return -ENOMEM;
2875e51060f0SSean Hefty 
2876e51060f0SSean Hefty 	if (!id_priv->cma_dev) {
2877e51060f0SSean Hefty 		ret = cma_bind_loopback(id_priv);
2878e51060f0SSean Hefty 		if (ret)
2879e51060f0SSean Hefty 			goto err;
2880e51060f0SSean Hefty 	}
2881e51060f0SSean Hefty 
28826f8372b6SSean Hefty 	rdma_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid);
28836f8372b6SSean Hefty 	rdma_addr_set_dgid(&id_priv->id.route.addr.dev_addr, &gid);
2884e51060f0SSean Hefty 
2885981b5a23SParav Pandit 	cma_init_resolve_addr_work(work, id_priv);
2886e51060f0SSean Hefty 	queue_work(cma_wq, &work->work);
2887e51060f0SSean Hefty 	return 0;
2888e51060f0SSean Hefty err:
2889e51060f0SSean Hefty 	kfree(work);
2890e51060f0SSean Hefty 	return ret;
2891e51060f0SSean Hefty }
2892e51060f0SSean Hefty 
2893f17df3b0SSean Hefty static int cma_resolve_ib_addr(struct rdma_id_private *id_priv)
2894f17df3b0SSean Hefty {
2895f17df3b0SSean Hefty 	struct cma_work *work;
2896f17df3b0SSean Hefty 	int ret;
2897f17df3b0SSean Hefty 
2898f17df3b0SSean Hefty 	work = kzalloc(sizeof *work, GFP_KERNEL);
2899f17df3b0SSean Hefty 	if (!work)
2900f17df3b0SSean Hefty 		return -ENOMEM;
2901f17df3b0SSean Hefty 
2902f17df3b0SSean Hefty 	if (!id_priv->cma_dev) {
2903f17df3b0SSean Hefty 		ret = cma_resolve_ib_dev(id_priv);
2904f17df3b0SSean Hefty 		if (ret)
2905f17df3b0SSean Hefty 			goto err;
2906f17df3b0SSean Hefty 	}
2907f17df3b0SSean Hefty 
2908f17df3b0SSean Hefty 	rdma_addr_set_dgid(&id_priv->id.route.addr.dev_addr, (union ib_gid *)
2909f17df3b0SSean Hefty 		&(((struct sockaddr_ib *) &id_priv->id.route.addr.dst_addr)->sib_addr));
2910f17df3b0SSean Hefty 
2911981b5a23SParav Pandit 	cma_init_resolve_addr_work(work, id_priv);
2912f17df3b0SSean Hefty 	queue_work(cma_wq, &work->work);
2913f17df3b0SSean Hefty 	return 0;
2914f17df3b0SSean Hefty err:
2915f17df3b0SSean Hefty 	kfree(work);
2916f17df3b0SSean Hefty 	return ret;
2917f17df3b0SSean Hefty }
2918f17df3b0SSean Hefty 
2919e51060f0SSean Hefty static int cma_bind_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
2920e51060f0SSean Hefty 			 struct sockaddr *dst_addr)
2921e51060f0SSean Hefty {
2922d14714dfSSean Hefty 	if (!src_addr || !src_addr->sa_family) {
2923d14714dfSSean Hefty 		src_addr = (struct sockaddr *) &id->route.addr.src_addr;
2924f17df3b0SSean Hefty 		src_addr->sa_family = dst_addr->sa_family;
2925b4cfe397SJack Morgenstein 		if (IS_ENABLED(CONFIG_IPV6) &&
2926b4cfe397SJack Morgenstein 		    dst_addr->sa_family == AF_INET6) {
29276c26a771SSpencer Baugh 			struct sockaddr_in6 *src_addr6 = (struct sockaddr_in6 *) src_addr;
29286c26a771SSpencer Baugh 			struct sockaddr_in6 *dst_addr6 = (struct sockaddr_in6 *) dst_addr;
29296c26a771SSpencer Baugh 			src_addr6->sin6_scope_id = dst_addr6->sin6_scope_id;
29306c26a771SSpencer Baugh 			if (ipv6_addr_type(&dst_addr6->sin6_addr) & IPV6_ADDR_LINKLOCAL)
29316c26a771SSpencer Baugh 				id->route.addr.dev_addr.bound_dev_if = dst_addr6->sin6_scope_id;
2932f17df3b0SSean Hefty 		} else if (dst_addr->sa_family == AF_IB) {
2933f17df3b0SSean Hefty 			((struct sockaddr_ib *) src_addr)->sib_pkey =
2934f17df3b0SSean Hefty 				((struct sockaddr_ib *) dst_addr)->sib_pkey;
2935d14714dfSSean Hefty 		}
2936d14714dfSSean Hefty 	}
2937e51060f0SSean Hefty 	return rdma_bind_addr(id, src_addr);
2938e51060f0SSean Hefty }
2939e51060f0SSean Hefty 
2940e51060f0SSean Hefty int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
2941e51060f0SSean Hefty 		      struct sockaddr *dst_addr, int timeout_ms)
2942e51060f0SSean Hefty {
2943e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
2944e51060f0SSean Hefty 	int ret;
2945e51060f0SSean Hefty 
2946e51060f0SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
294719b752a1SMoni Shoua 	memcpy(cma_dst_addr(id_priv), dst_addr, rdma_addr_size(dst_addr));
2948550e5ca7SNir Muchtar 	if (id_priv->state == RDMA_CM_IDLE) {
2949e51060f0SSean Hefty 		ret = cma_bind_addr(id, src_addr, dst_addr);
295019b752a1SMoni Shoua 		if (ret) {
295119b752a1SMoni Shoua 			memset(cma_dst_addr(id_priv), 0, rdma_addr_size(dst_addr));
2952e51060f0SSean Hefty 			return ret;
2953e51060f0SSean Hefty 		}
295419b752a1SMoni Shoua 	}
2955e51060f0SSean Hefty 
295619b752a1SMoni Shoua 	if (cma_family(id_priv) != dst_addr->sa_family) {
295719b752a1SMoni Shoua 		memset(cma_dst_addr(id_priv), 0, rdma_addr_size(dst_addr));
29584ae7152eSSean Hefty 		return -EINVAL;
295919b752a1SMoni Shoua 	}
29604ae7152eSSean Hefty 
296119b752a1SMoni Shoua 	if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_ADDR_QUERY)) {
296219b752a1SMoni Shoua 		memset(cma_dst_addr(id_priv), 0, rdma_addr_size(dst_addr));
2963e51060f0SSean Hefty 		return -EINVAL;
296419b752a1SMoni Shoua 	}
2965e51060f0SSean Hefty 
2966e51060f0SSean Hefty 	atomic_inc(&id_priv->refcount);
2967f17df3b0SSean Hefty 	if (cma_any_addr(dst_addr)) {
2968e51060f0SSean Hefty 		ret = cma_resolve_loopback(id_priv);
2969f17df3b0SSean Hefty 	} else {
2970f17df3b0SSean Hefty 		if (dst_addr->sa_family == AF_IB) {
2971f17df3b0SSean Hefty 			ret = cma_resolve_ib_addr(id_priv);
2972f17df3b0SSean Hefty 		} else {
2973ee6548d1SJason Gunthorpe 			ret = rdma_resolve_ip(cma_src_addr(id_priv),
29747a118df3SSean Hefty 					      dst_addr, &id->route.addr.dev_addr,
2975e51060f0SSean Hefty 					      timeout_ms, addr_handler, id_priv);
2976f17df3b0SSean Hefty 		}
2977f17df3b0SSean Hefty 	}
2978e51060f0SSean Hefty 	if (ret)
2979e51060f0SSean Hefty 		goto err;
2980e51060f0SSean Hefty 
2981e51060f0SSean Hefty 	return 0;
2982e51060f0SSean Hefty err:
2983550e5ca7SNir Muchtar 	cma_comp_exch(id_priv, RDMA_CM_ADDR_QUERY, RDMA_CM_ADDR_BOUND);
2984e51060f0SSean Hefty 	cma_deref_id(id_priv);
2985e51060f0SSean Hefty 	return ret;
2986e51060f0SSean Hefty }
2987e51060f0SSean Hefty EXPORT_SYMBOL(rdma_resolve_addr);
2988e51060f0SSean Hefty 
2989a9bb7912SHefty, Sean int rdma_set_reuseaddr(struct rdma_cm_id *id, int reuse)
2990a9bb7912SHefty, Sean {
2991a9bb7912SHefty, Sean 	struct rdma_id_private *id_priv;
2992a9bb7912SHefty, Sean 	unsigned long flags;
2993a9bb7912SHefty, Sean 	int ret;
2994a9bb7912SHefty, Sean 
2995a9bb7912SHefty, Sean 	id_priv = container_of(id, struct rdma_id_private, id);
2996a9bb7912SHefty, Sean 	spin_lock_irqsave(&id_priv->lock, flags);
2997c8dea2f9SSean Hefty 	if (reuse || id_priv->state == RDMA_CM_IDLE) {
2998a9bb7912SHefty, Sean 		id_priv->reuseaddr = reuse;
2999a9bb7912SHefty, Sean 		ret = 0;
3000a9bb7912SHefty, Sean 	} else {
3001a9bb7912SHefty, Sean 		ret = -EINVAL;
3002a9bb7912SHefty, Sean 	}
3003a9bb7912SHefty, Sean 	spin_unlock_irqrestore(&id_priv->lock, flags);
3004a9bb7912SHefty, Sean 	return ret;
3005a9bb7912SHefty, Sean }
3006a9bb7912SHefty, Sean EXPORT_SYMBOL(rdma_set_reuseaddr);
3007a9bb7912SHefty, Sean 
300868602120SSean Hefty int rdma_set_afonly(struct rdma_cm_id *id, int afonly)
300968602120SSean Hefty {
301068602120SSean Hefty 	struct rdma_id_private *id_priv;
301168602120SSean Hefty 	unsigned long flags;
301268602120SSean Hefty 	int ret;
301368602120SSean Hefty 
301468602120SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
301568602120SSean Hefty 	spin_lock_irqsave(&id_priv->lock, flags);
301668602120SSean Hefty 	if (id_priv->state == RDMA_CM_IDLE || id_priv->state == RDMA_CM_ADDR_BOUND) {
301768602120SSean Hefty 		id_priv->options |= (1 << CMA_OPTION_AFONLY);
301868602120SSean Hefty 		id_priv->afonly = afonly;
301968602120SSean Hefty 		ret = 0;
302068602120SSean Hefty 	} else {
302168602120SSean Hefty 		ret = -EINVAL;
302268602120SSean Hefty 	}
302368602120SSean Hefty 	spin_unlock_irqrestore(&id_priv->lock, flags);
302468602120SSean Hefty 	return ret;
302568602120SSean Hefty }
302668602120SSean Hefty EXPORT_SYMBOL(rdma_set_afonly);
302768602120SSean Hefty 
3028e51060f0SSean Hefty static void cma_bind_port(struct rdma_bind_list *bind_list,
3029e51060f0SSean Hefty 			  struct rdma_id_private *id_priv)
3030e51060f0SSean Hefty {
303158afdcb7SSean Hefty 	struct sockaddr *addr;
303258afdcb7SSean Hefty 	struct sockaddr_ib *sib;
303358afdcb7SSean Hefty 	u64 sid, mask;
303458afdcb7SSean Hefty 	__be16 port;
3035e51060f0SSean Hefty 
3036f4753834SSean Hefty 	addr = cma_src_addr(id_priv);
303758afdcb7SSean Hefty 	port = htons(bind_list->port);
303858afdcb7SSean Hefty 
303958afdcb7SSean Hefty 	switch (addr->sa_family) {
304058afdcb7SSean Hefty 	case AF_INET:
304158afdcb7SSean Hefty 		((struct sockaddr_in *) addr)->sin_port = port;
304258afdcb7SSean Hefty 		break;
304358afdcb7SSean Hefty 	case AF_INET6:
304458afdcb7SSean Hefty 		((struct sockaddr_in6 *) addr)->sin6_port = port;
304558afdcb7SSean Hefty 		break;
304658afdcb7SSean Hefty 	case AF_IB:
304758afdcb7SSean Hefty 		sib = (struct sockaddr_ib *) addr;
304858afdcb7SSean Hefty 		sid = be64_to_cpu(sib->sib_sid);
304958afdcb7SSean Hefty 		mask = be64_to_cpu(sib->sib_sid_mask);
305058afdcb7SSean Hefty 		sib->sib_sid = cpu_to_be64((sid & mask) | (u64) ntohs(port));
305158afdcb7SSean Hefty 		sib->sib_sid_mask = cpu_to_be64(~0ULL);
305258afdcb7SSean Hefty 		break;
305358afdcb7SSean Hefty 	}
3054e51060f0SSean Hefty 	id_priv->bind_list = bind_list;
3055e51060f0SSean Hefty 	hlist_add_head(&id_priv->node, &bind_list->owners);
3056e51060f0SSean Hefty }
3057e51060f0SSean Hefty 
30582253fc0cSSteve Wise static int cma_alloc_port(enum rdma_ucm_port_space ps,
3059aac978e1SHaggai Eran 			  struct rdma_id_private *id_priv, unsigned short snum)
3060e51060f0SSean Hefty {
3061e51060f0SSean Hefty 	struct rdma_bind_list *bind_list;
30623b069c5dSTejun Heo 	int ret;
3063e51060f0SSean Hefty 
3064cb164b8cSSean Hefty 	bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL);
3065e51060f0SSean Hefty 	if (!bind_list)
3066e51060f0SSean Hefty 		return -ENOMEM;
3067e51060f0SSean Hefty 
3068fa20105eSGuy Shapiro 	ret = cma_ps_alloc(id_priv->id.route.addr.dev_addr.net, ps, bind_list,
3069fa20105eSGuy Shapiro 			   snum);
30703b069c5dSTejun Heo 	if (ret < 0)
30713b069c5dSTejun Heo 		goto err;
3072e51060f0SSean Hefty 
3073e51060f0SSean Hefty 	bind_list->ps = ps;
30743b069c5dSTejun Heo 	bind_list->port = (unsigned short)ret;
3075e51060f0SSean Hefty 	cma_bind_port(bind_list, id_priv);
3076e51060f0SSean Hefty 	return 0;
30773b069c5dSTejun Heo err:
3078aedec080SSean Hefty 	kfree(bind_list);
30793b069c5dSTejun Heo 	return ret == -ENOSPC ? -EADDRNOTAVAIL : ret;
3080aedec080SSean Hefty }
3081aedec080SSean Hefty 
308219b752a1SMoni Shoua static int cma_port_is_unique(struct rdma_bind_list *bind_list,
308319b752a1SMoni Shoua 			      struct rdma_id_private *id_priv)
308419b752a1SMoni Shoua {
308519b752a1SMoni Shoua 	struct rdma_id_private *cur_id;
308619b752a1SMoni Shoua 	struct sockaddr  *daddr = cma_dst_addr(id_priv);
308719b752a1SMoni Shoua 	struct sockaddr  *saddr = cma_src_addr(id_priv);
308819b752a1SMoni Shoua 	__be16 dport = cma_port(daddr);
308919b752a1SMoni Shoua 
309019b752a1SMoni Shoua 	hlist_for_each_entry(cur_id, &bind_list->owners, node) {
309119b752a1SMoni Shoua 		struct sockaddr  *cur_daddr = cma_dst_addr(cur_id);
309219b752a1SMoni Shoua 		struct sockaddr  *cur_saddr = cma_src_addr(cur_id);
309319b752a1SMoni Shoua 		__be16 cur_dport = cma_port(cur_daddr);
309419b752a1SMoni Shoua 
309519b752a1SMoni Shoua 		if (id_priv == cur_id)
309619b752a1SMoni Shoua 			continue;
309719b752a1SMoni Shoua 
309819b752a1SMoni Shoua 		/* different dest port -> unique */
30999dea9a2fSTatyana Nikolova 		if (!cma_any_port(daddr) &&
31009dea9a2fSTatyana Nikolova 		    !cma_any_port(cur_daddr) &&
310119b752a1SMoni Shoua 		    (dport != cur_dport))
310219b752a1SMoni Shoua 			continue;
310319b752a1SMoni Shoua 
310419b752a1SMoni Shoua 		/* different src address -> unique */
310519b752a1SMoni Shoua 		if (!cma_any_addr(saddr) &&
310619b752a1SMoni Shoua 		    !cma_any_addr(cur_saddr) &&
310719b752a1SMoni Shoua 		    cma_addr_cmp(saddr, cur_saddr))
310819b752a1SMoni Shoua 			continue;
310919b752a1SMoni Shoua 
311019b752a1SMoni Shoua 		/* different dst address -> unique */
31119dea9a2fSTatyana Nikolova 		if (!cma_any_addr(daddr) &&
31129dea9a2fSTatyana Nikolova 		    !cma_any_addr(cur_daddr) &&
311319b752a1SMoni Shoua 		    cma_addr_cmp(daddr, cur_daddr))
311419b752a1SMoni Shoua 			continue;
311519b752a1SMoni Shoua 
311619b752a1SMoni Shoua 		return -EADDRNOTAVAIL;
311719b752a1SMoni Shoua 	}
311819b752a1SMoni Shoua 	return 0;
311919b752a1SMoni Shoua }
312019b752a1SMoni Shoua 
31212253fc0cSSteve Wise static int cma_alloc_any_port(enum rdma_ucm_port_space ps,
3122aac978e1SHaggai Eran 			      struct rdma_id_private *id_priv)
3123aedec080SSean Hefty {
31245d7220e8STetsuo Handa 	static unsigned int last_used_port;
31255d7220e8STetsuo Handa 	int low, high, remaining;
31265d7220e8STetsuo Handa 	unsigned int rover;
3127fa20105eSGuy Shapiro 	struct net *net = id_priv->id.route.addr.dev_addr.net;
3128aedec080SSean Hefty 
3129fa20105eSGuy Shapiro 	inet_get_local_port_range(net, &low, &high);
31305d7220e8STetsuo Handa 	remaining = (high - low) + 1;
313163862b5bSAruna-Hewapathirane 	rover = prandom_u32() % remaining + low;
31325d7220e8STetsuo Handa retry:
313319b752a1SMoni Shoua 	if (last_used_port != rover) {
313419b752a1SMoni Shoua 		struct rdma_bind_list *bind_list;
313519b752a1SMoni Shoua 		int ret;
313619b752a1SMoni Shoua 
313719b752a1SMoni Shoua 		bind_list = cma_ps_find(net, ps, (unsigned short)rover);
313819b752a1SMoni Shoua 
313919b752a1SMoni Shoua 		if (!bind_list) {
314019b752a1SMoni Shoua 			ret = cma_alloc_port(ps, id_priv, rover);
314119b752a1SMoni Shoua 		} else {
314219b752a1SMoni Shoua 			ret = cma_port_is_unique(bind_list, id_priv);
314319b752a1SMoni Shoua 			if (!ret)
314419b752a1SMoni Shoua 				cma_bind_port(bind_list, id_priv);
314519b752a1SMoni Shoua 		}
31465d7220e8STetsuo Handa 		/*
31475d7220e8STetsuo Handa 		 * Remember previously used port number in order to avoid
31485d7220e8STetsuo Handa 		 * re-using same port immediately after it is closed.
31495d7220e8STetsuo Handa 		 */
31505d7220e8STetsuo Handa 		if (!ret)
31515d7220e8STetsuo Handa 			last_used_port = rover;
31525d7220e8STetsuo Handa 		if (ret != -EADDRNOTAVAIL)
31535d7220e8STetsuo Handa 			return ret;
31545d7220e8STetsuo Handa 	}
31555d7220e8STetsuo Handa 	if (--remaining) {
31565d7220e8STetsuo Handa 		rover++;
31575d7220e8STetsuo Handa 		if ((rover < low) || (rover > high))
31585d7220e8STetsuo Handa 			rover = low;
3159aedec080SSean Hefty 		goto retry;
3160aedec080SSean Hefty 	}
31615d7220e8STetsuo Handa 	return -EADDRNOTAVAIL;
3162e51060f0SSean Hefty }
3163e51060f0SSean Hefty 
3164a9bb7912SHefty, Sean /*
3165a9bb7912SHefty, Sean  * Check that the requested port is available.  This is called when trying to
3166a9bb7912SHefty, Sean  * bind to a specific port, or when trying to listen on a bound port.  In
3167a9bb7912SHefty, Sean  * the latter case, the provided id_priv may already be on the bind_list, but
3168a9bb7912SHefty, Sean  * we still need to check that it's okay to start listening.
3169a9bb7912SHefty, Sean  */
3170a9bb7912SHefty, Sean static int cma_check_port(struct rdma_bind_list *bind_list,
3171a9bb7912SHefty, Sean 			  struct rdma_id_private *id_priv, uint8_t reuseaddr)
3172e51060f0SSean Hefty {
3173e51060f0SSean Hefty 	struct rdma_id_private *cur_id;
317443b752daSHefty, Sean 	struct sockaddr *addr, *cur_addr;
3175e51060f0SSean Hefty 
3176f4753834SSean Hefty 	addr = cma_src_addr(id_priv);
3177b67bfe0dSSasha Levin 	hlist_for_each_entry(cur_id, &bind_list->owners, node) {
3178a9bb7912SHefty, Sean 		if (id_priv == cur_id)
3179a9bb7912SHefty, Sean 			continue;
3180a9bb7912SHefty, Sean 
31815b0ec991SSean Hefty 		if ((cur_id->state != RDMA_CM_LISTEN) && reuseaddr &&
31825b0ec991SSean Hefty 		    cur_id->reuseaddr)
31835b0ec991SSean Hefty 			continue;
31845b0ec991SSean Hefty 
3185f4753834SSean Hefty 		cur_addr = cma_src_addr(cur_id);
31865b0ec991SSean Hefty 		if (id_priv->afonly && cur_id->afonly &&
31875b0ec991SSean Hefty 		    (addr->sa_family != cur_addr->sa_family))
31885b0ec991SSean Hefty 			continue;
31895b0ec991SSean Hefty 
31905b0ec991SSean Hefty 		if (cma_any_addr(addr) || cma_any_addr(cur_addr))
3191e51060f0SSean Hefty 			return -EADDRNOTAVAIL;
3192e51060f0SSean Hefty 
319343b752daSHefty, Sean 		if (!cma_addr_cmp(addr, cur_addr))
3194e51060f0SSean Hefty 			return -EADDRINUSE;
3195e51060f0SSean Hefty 	}
3196e51060f0SSean Hefty 	return 0;
3197e51060f0SSean Hefty }
3198e51060f0SSean Hefty 
31992253fc0cSSteve Wise static int cma_use_port(enum rdma_ucm_port_space ps,
3200aac978e1SHaggai Eran 			struct rdma_id_private *id_priv)
3201a9bb7912SHefty, Sean {
3202a9bb7912SHefty, Sean 	struct rdma_bind_list *bind_list;
3203a9bb7912SHefty, Sean 	unsigned short snum;
3204a9bb7912SHefty, Sean 	int ret;
3205a9bb7912SHefty, Sean 
3206f4753834SSean Hefty 	snum = ntohs(cma_port(cma_src_addr(id_priv)));
3207a9bb7912SHefty, Sean 	if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
3208a9bb7912SHefty, Sean 		return -EACCES;
3209a9bb7912SHefty, Sean 
3210fa20105eSGuy Shapiro 	bind_list = cma_ps_find(id_priv->id.route.addr.dev_addr.net, ps, snum);
3211a9bb7912SHefty, Sean 	if (!bind_list) {
3212a9bb7912SHefty, Sean 		ret = cma_alloc_port(ps, id_priv, snum);
3213a9bb7912SHefty, Sean 	} else {
3214a9bb7912SHefty, Sean 		ret = cma_check_port(bind_list, id_priv, id_priv->reuseaddr);
3215a9bb7912SHefty, Sean 		if (!ret)
3216a9bb7912SHefty, Sean 			cma_bind_port(bind_list, id_priv);
3217a9bb7912SHefty, Sean 	}
3218a9bb7912SHefty, Sean 	return ret;
3219a9bb7912SHefty, Sean }
3220a9bb7912SHefty, Sean 
3221a9bb7912SHefty, Sean static int cma_bind_listen(struct rdma_id_private *id_priv)
3222a9bb7912SHefty, Sean {
3223a9bb7912SHefty, Sean 	struct rdma_bind_list *bind_list = id_priv->bind_list;
3224a9bb7912SHefty, Sean 	int ret = 0;
3225a9bb7912SHefty, Sean 
3226a9bb7912SHefty, Sean 	mutex_lock(&lock);
3227a9bb7912SHefty, Sean 	if (bind_list->owners.first->next)
3228a9bb7912SHefty, Sean 		ret = cma_check_port(bind_list, id_priv, 0);
3229a9bb7912SHefty, Sean 	mutex_unlock(&lock);
3230a9bb7912SHefty, Sean 	return ret;
3231a9bb7912SHefty, Sean }
3232a9bb7912SHefty, Sean 
32332253fc0cSSteve Wise static enum rdma_ucm_port_space
32342253fc0cSSteve Wise cma_select_inet_ps(struct rdma_id_private *id_priv)
323558afdcb7SSean Hefty {
323658afdcb7SSean Hefty 	switch (id_priv->id.ps) {
323758afdcb7SSean Hefty 	case RDMA_PS_TCP:
323858afdcb7SSean Hefty 	case RDMA_PS_UDP:
323958afdcb7SSean Hefty 	case RDMA_PS_IPOIB:
324058afdcb7SSean Hefty 	case RDMA_PS_IB:
3241aac978e1SHaggai Eran 		return id_priv->id.ps;
324258afdcb7SSean Hefty 	default:
3243aac978e1SHaggai Eran 
3244aac978e1SHaggai Eran 		return 0;
324558afdcb7SSean Hefty 	}
324658afdcb7SSean Hefty }
324758afdcb7SSean Hefty 
32482253fc0cSSteve Wise static enum rdma_ucm_port_space
32492253fc0cSSteve Wise cma_select_ib_ps(struct rdma_id_private *id_priv)
325058afdcb7SSean Hefty {
32512253fc0cSSteve Wise 	enum rdma_ucm_port_space ps = 0;
325258afdcb7SSean Hefty 	struct sockaddr_ib *sib;
325358afdcb7SSean Hefty 	u64 sid_ps, mask, sid;
325458afdcb7SSean Hefty 
3255f4753834SSean Hefty 	sib = (struct sockaddr_ib *) cma_src_addr(id_priv);
325658afdcb7SSean Hefty 	mask = be64_to_cpu(sib->sib_sid_mask) & RDMA_IB_IP_PS_MASK;
325758afdcb7SSean Hefty 	sid = be64_to_cpu(sib->sib_sid) & mask;
325858afdcb7SSean Hefty 
325958afdcb7SSean Hefty 	if ((id_priv->id.ps == RDMA_PS_IB) && (sid == (RDMA_IB_IP_PS_IB & mask))) {
326058afdcb7SSean Hefty 		sid_ps = RDMA_IB_IP_PS_IB;
3261aac978e1SHaggai Eran 		ps = RDMA_PS_IB;
326258afdcb7SSean Hefty 	} else if (((id_priv->id.ps == RDMA_PS_IB) || (id_priv->id.ps == RDMA_PS_TCP)) &&
326358afdcb7SSean Hefty 		   (sid == (RDMA_IB_IP_PS_TCP & mask))) {
326458afdcb7SSean Hefty 		sid_ps = RDMA_IB_IP_PS_TCP;
3265aac978e1SHaggai Eran 		ps = RDMA_PS_TCP;
326658afdcb7SSean Hefty 	} else if (((id_priv->id.ps == RDMA_PS_IB) || (id_priv->id.ps == RDMA_PS_UDP)) &&
326758afdcb7SSean Hefty 		   (sid == (RDMA_IB_IP_PS_UDP & mask))) {
326858afdcb7SSean Hefty 		sid_ps = RDMA_IB_IP_PS_UDP;
3269aac978e1SHaggai Eran 		ps = RDMA_PS_UDP;
327058afdcb7SSean Hefty 	}
327158afdcb7SSean Hefty 
327258afdcb7SSean Hefty 	if (ps) {
327358afdcb7SSean Hefty 		sib->sib_sid = cpu_to_be64(sid_ps | ntohs(cma_port((struct sockaddr *) sib)));
327458afdcb7SSean Hefty 		sib->sib_sid_mask = cpu_to_be64(RDMA_IB_IP_PS_MASK |
327558afdcb7SSean Hefty 						be64_to_cpu(sib->sib_sid_mask));
327658afdcb7SSean Hefty 	}
327758afdcb7SSean Hefty 	return ps;
327858afdcb7SSean Hefty }
327958afdcb7SSean Hefty 
3280e51060f0SSean Hefty static int cma_get_port(struct rdma_id_private *id_priv)
3281e51060f0SSean Hefty {
32822253fc0cSSteve Wise 	enum rdma_ucm_port_space ps;
3283e51060f0SSean Hefty 	int ret;
3284e51060f0SSean Hefty 
3285f4753834SSean Hefty 	if (cma_family(id_priv) != AF_IB)
328658afdcb7SSean Hefty 		ps = cma_select_inet_ps(id_priv);
328758afdcb7SSean Hefty 	else
328858afdcb7SSean Hefty 		ps = cma_select_ib_ps(id_priv);
328958afdcb7SSean Hefty 	if (!ps)
3290e51060f0SSean Hefty 		return -EPROTONOSUPPORT;
3291e51060f0SSean Hefty 
3292e51060f0SSean Hefty 	mutex_lock(&lock);
3293f4753834SSean Hefty 	if (cma_any_port(cma_src_addr(id_priv)))
3294aedec080SSean Hefty 		ret = cma_alloc_any_port(ps, id_priv);
3295e51060f0SSean Hefty 	else
3296e51060f0SSean Hefty 		ret = cma_use_port(ps, id_priv);
3297e51060f0SSean Hefty 	mutex_unlock(&lock);
3298e51060f0SSean Hefty 
3299e51060f0SSean Hefty 	return ret;
3300e51060f0SSean Hefty }
3301e51060f0SSean Hefty 
3302d14714dfSSean Hefty static int cma_check_linklocal(struct rdma_dev_addr *dev_addr,
3303d14714dfSSean Hefty 			       struct sockaddr *addr)
3304d14714dfSSean Hefty {
3305d90f9b35SRoland Dreier #if IS_ENABLED(CONFIG_IPV6)
3306d14714dfSSean Hefty 	struct sockaddr_in6 *sin6;
3307d14714dfSSean Hefty 
3308d14714dfSSean Hefty 	if (addr->sa_family != AF_INET6)
3309d14714dfSSean Hefty 		return 0;
3310d14714dfSSean Hefty 
3311d14714dfSSean Hefty 	sin6 = (struct sockaddr_in6 *) addr;
33125462edddSSomnath Kotur 
33135462edddSSomnath Kotur 	if (!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL))
33145462edddSSomnath Kotur 		return 0;
33155462edddSSomnath Kotur 
33165462edddSSomnath Kotur 	if (!sin6->sin6_scope_id)
3317d14714dfSSean Hefty 			return -EINVAL;
3318d14714dfSSean Hefty 
3319d14714dfSSean Hefty 	dev_addr->bound_dev_if = sin6->sin6_scope_id;
3320d14714dfSSean Hefty #endif
3321d14714dfSSean Hefty 	return 0;
3322d14714dfSSean Hefty }
3323d14714dfSSean Hefty 
3324a9bb7912SHefty, Sean int rdma_listen(struct rdma_cm_id *id, int backlog)
3325a9bb7912SHefty, Sean {
3326a9bb7912SHefty, Sean 	struct rdma_id_private *id_priv;
3327a9bb7912SHefty, Sean 	int ret;
3328a9bb7912SHefty, Sean 
3329a9bb7912SHefty, Sean 	id_priv = container_of(id, struct rdma_id_private, id);
3330550e5ca7SNir Muchtar 	if (id_priv->state == RDMA_CM_IDLE) {
3331f4753834SSean Hefty 		id->route.addr.src_addr.ss_family = AF_INET;
3332f4753834SSean Hefty 		ret = rdma_bind_addr(id, cma_src_addr(id_priv));
3333a9bb7912SHefty, Sean 		if (ret)
3334a9bb7912SHefty, Sean 			return ret;
3335a9bb7912SHefty, Sean 	}
3336a9bb7912SHefty, Sean 
3337550e5ca7SNir Muchtar 	if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_LISTEN))
3338a9bb7912SHefty, Sean 		return -EINVAL;
3339a9bb7912SHefty, Sean 
3340a9bb7912SHefty, Sean 	if (id_priv->reuseaddr) {
3341a9bb7912SHefty, Sean 		ret = cma_bind_listen(id_priv);
3342a9bb7912SHefty, Sean 		if (ret)
3343a9bb7912SHefty, Sean 			goto err;
3344a9bb7912SHefty, Sean 	}
3345a9bb7912SHefty, Sean 
3346a9bb7912SHefty, Sean 	id_priv->backlog = backlog;
3347a9bb7912SHefty, Sean 	if (id->device) {
334872219ceaSMichael Wang 		if (rdma_cap_ib_cm(id->device, 1)) {
3349a9bb7912SHefty, Sean 			ret = cma_ib_listen(id_priv);
3350a9bb7912SHefty, Sean 			if (ret)
3351a9bb7912SHefty, Sean 				goto err;
335204215330SMichael Wang 		} else if (rdma_cap_iw_cm(id->device, 1)) {
3353a9bb7912SHefty, Sean 			ret = cma_iw_listen(id_priv, backlog);
3354a9bb7912SHefty, Sean 			if (ret)
3355a9bb7912SHefty, Sean 				goto err;
335621655afcSMichael Wang 		} else {
3357a9bb7912SHefty, Sean 			ret = -ENOSYS;
3358a9bb7912SHefty, Sean 			goto err;
3359a9bb7912SHefty, Sean 		}
3360a9bb7912SHefty, Sean 	} else
3361a9bb7912SHefty, Sean 		cma_listen_on_all(id_priv);
3362a9bb7912SHefty, Sean 
3363a9bb7912SHefty, Sean 	return 0;
3364a9bb7912SHefty, Sean err:
3365a9bb7912SHefty, Sean 	id_priv->backlog = 0;
3366550e5ca7SNir Muchtar 	cma_comp_exch(id_priv, RDMA_CM_LISTEN, RDMA_CM_ADDR_BOUND);
3367a9bb7912SHefty, Sean 	return ret;
3368a9bb7912SHefty, Sean }
3369a9bb7912SHefty, Sean EXPORT_SYMBOL(rdma_listen);
3370a9bb7912SHefty, Sean 
3371e51060f0SSean Hefty int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
3372e51060f0SSean Hefty {
3373e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
3374e51060f0SSean Hefty 	int ret;
33756df6b4a9SMoni Shoua 	struct sockaddr  *daddr;
3376e51060f0SSean Hefty 
3377680f920aSSean Hefty 	if (addr->sa_family != AF_INET && addr->sa_family != AF_INET6 &&
3378680f920aSSean Hefty 	    addr->sa_family != AF_IB)
3379e51060f0SSean Hefty 		return -EAFNOSUPPORT;
3380e51060f0SSean Hefty 
3381e51060f0SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
3382550e5ca7SNir Muchtar 	if (!cma_comp_exch(id_priv, RDMA_CM_IDLE, RDMA_CM_ADDR_BOUND))
3383e51060f0SSean Hefty 		return -EINVAL;
3384e51060f0SSean Hefty 
3385d14714dfSSean Hefty 	ret = cma_check_linklocal(&id->route.addr.dev_addr, addr);
3386d14714dfSSean Hefty 	if (ret)
3387d14714dfSSean Hefty 		goto err1;
3388d14714dfSSean Hefty 
33897b85627bSMoni Shoua 	memcpy(cma_src_addr(id_priv), addr, rdma_addr_size(addr));
33908523c048SSean Hefty 	if (!cma_any_addr(addr)) {
3391680f920aSSean Hefty 		ret = cma_translate_addr(addr, &id->route.addr.dev_addr);
3392255d0c14SKrishna Kumar 		if (ret)
3393255d0c14SKrishna Kumar 			goto err1;
3394255d0c14SKrishna Kumar 
3395be9130ccSDoug Ledford 		ret = cma_acquire_dev(id_priv, NULL);
3396e51060f0SSean Hefty 		if (ret)
3397255d0c14SKrishna Kumar 			goto err1;
3398e51060f0SSean Hefty 	}
3399e51060f0SSean Hefty 
340068602120SSean Hefty 	if (!(id_priv->options & (1 << CMA_OPTION_AFONLY))) {
34015b0ec991SSean Hefty 		if (addr->sa_family == AF_INET)
34025b0ec991SSean Hefty 			id_priv->afonly = 1;
34035b0ec991SSean Hefty #if IS_ENABLED(CONFIG_IPV6)
3404fa20105eSGuy Shapiro 		else if (addr->sa_family == AF_INET6) {
3405fa20105eSGuy Shapiro 			struct net *net = id_priv->id.route.addr.dev_addr.net;
3406fa20105eSGuy Shapiro 
3407fa20105eSGuy Shapiro 			id_priv->afonly = net->ipv6.sysctl.bindv6only;
3408fa20105eSGuy Shapiro 		}
34095b0ec991SSean Hefty #endif
341068602120SSean Hefty 	}
34119dea9a2fSTatyana Nikolova 	daddr = cma_dst_addr(id_priv);
34129dea9a2fSTatyana Nikolova 	daddr->sa_family = addr->sa_family;
34139dea9a2fSTatyana Nikolova 
3414e51060f0SSean Hefty 	ret = cma_get_port(id_priv);
3415e51060f0SSean Hefty 	if (ret)
3416255d0c14SKrishna Kumar 		goto err2;
3417e51060f0SSean Hefty 
3418e51060f0SSean Hefty 	return 0;
3419255d0c14SKrishna Kumar err2:
342000313983SSteve Wise 	if (id_priv->cma_dev) {
342100313983SSteve Wise 		rdma_restrack_del(&id_priv->res);
3422a396d43aSSean Hefty 		cma_release_dev(id_priv);
342300313983SSteve Wise 	}
3424255d0c14SKrishna Kumar err1:
3425550e5ca7SNir Muchtar 	cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_IDLE);
3426e51060f0SSean Hefty 	return ret;
3427e51060f0SSean Hefty }
3428e51060f0SSean Hefty EXPORT_SYMBOL(rdma_bind_addr);
3429e51060f0SSean Hefty 
3430f4753834SSean Hefty static int cma_format_hdr(void *hdr, struct rdma_id_private *id_priv)
3431e51060f0SSean Hefty {
3432e51060f0SSean Hefty 	struct cma_hdr *cma_hdr;
3433e51060f0SSean Hefty 
343401602f11SSean Hefty 	cma_hdr = hdr;
343501602f11SSean Hefty 	cma_hdr->cma_version = CMA_VERSION;
3436f4753834SSean Hefty 	if (cma_family(id_priv) == AF_INET) {
34371f5175adSAleksey Senin 		struct sockaddr_in *src4, *dst4;
34381f5175adSAleksey Senin 
3439f4753834SSean Hefty 		src4 = (struct sockaddr_in *) cma_src_addr(id_priv);
3440f4753834SSean Hefty 		dst4 = (struct sockaddr_in *) cma_dst_addr(id_priv);
3441e51060f0SSean Hefty 
3442e51060f0SSean Hefty 		cma_set_ip_ver(cma_hdr, 4);
3443e51060f0SSean Hefty 		cma_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr;
3444e51060f0SSean Hefty 		cma_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr;
3445e51060f0SSean Hefty 		cma_hdr->port = src4->sin_port;
3446e8160e15SSean Hefty 	} else if (cma_family(id_priv) == AF_INET6) {
34471f5175adSAleksey Senin 		struct sockaddr_in6 *src6, *dst6;
34481f5175adSAleksey Senin 
3449f4753834SSean Hefty 		src6 = (struct sockaddr_in6 *) cma_src_addr(id_priv);
3450f4753834SSean Hefty 		dst6 = (struct sockaddr_in6 *) cma_dst_addr(id_priv);
34511f5175adSAleksey Senin 
34521f5175adSAleksey Senin 		cma_set_ip_ver(cma_hdr, 6);
34531f5175adSAleksey Senin 		cma_hdr->src_addr.ip6 = src6->sin6_addr;
34541f5175adSAleksey Senin 		cma_hdr->dst_addr.ip6 = dst6->sin6_addr;
34551f5175adSAleksey Senin 		cma_hdr->port = src6->sin6_port;
34561f5175adSAleksey Senin 	}
3457e51060f0SSean Hefty 	return 0;
3458e51060f0SSean Hefty }
3459e51060f0SSean Hefty 
3460628e5f6dSSean Hefty static int cma_sidr_rep_handler(struct ib_cm_id *cm_id,
3461628e5f6dSSean Hefty 				struct ib_cm_event *ib_event)
3462628e5f6dSSean Hefty {
3463628e5f6dSSean Hefty 	struct rdma_id_private *id_priv = cm_id->context;
3464628e5f6dSSean Hefty 	struct rdma_cm_event event;
3465628e5f6dSSean Hefty 	struct ib_cm_sidr_rep_event_param *rep = &ib_event->param.sidr_rep_rcvd;
3466628e5f6dSSean Hefty 	int ret = 0;
3467628e5f6dSSean Hefty 
346837e07cdaSBart Van Assche 	mutex_lock(&id_priv->handler_mutex);
346937e07cdaSBart Van Assche 	if (id_priv->state != RDMA_CM_CONNECT)
347037e07cdaSBart Van Assche 		goto out;
3471628e5f6dSSean Hefty 
34728aa08602SSean Hefty 	memset(&event, 0, sizeof event);
3473628e5f6dSSean Hefty 	switch (ib_event->event) {
3474628e5f6dSSean Hefty 	case IB_CM_SIDR_REQ_ERROR:
3475628e5f6dSSean Hefty 		event.event = RDMA_CM_EVENT_UNREACHABLE;
3476628e5f6dSSean Hefty 		event.status = -ETIMEDOUT;
3477628e5f6dSSean Hefty 		break;
3478628e5f6dSSean Hefty 	case IB_CM_SIDR_REP_RECEIVED:
3479628e5f6dSSean Hefty 		event.param.ud.private_data = ib_event->private_data;
3480628e5f6dSSean Hefty 		event.param.ud.private_data_len = IB_CM_SIDR_REP_PRIVATE_DATA_SIZE;
3481628e5f6dSSean Hefty 		if (rep->status != IB_SIDR_SUCCESS) {
3482628e5f6dSSean Hefty 			event.event = RDMA_CM_EVENT_UNREACHABLE;
3483628e5f6dSSean Hefty 			event.status = ib_event->param.sidr_rep_rcvd.status;
3484498683c6SMoni Shoua 			pr_debug_ratelimited("RDMA CM: UNREACHABLE: bad SIDR reply. status %d\n",
3485498683c6SMoni Shoua 					     event.status);
3486628e5f6dSSean Hefty 			break;
3487628e5f6dSSean Hefty 		}
34885c438135SSean Hefty 		ret = cma_set_qkey(id_priv, rep->qkey);
3489d2ca39f2SYossi Etigin 		if (ret) {
3490498683c6SMoni Shoua 			pr_debug_ratelimited("RDMA CM: ADDR_ERROR: failed to set qkey. status %d\n", ret);
3491d2ca39f2SYossi Etigin 			event.event = RDMA_CM_EVENT_ADDR_ERROR;
34925c438135SSean Hefty 			event.status = ret;
3493628e5f6dSSean Hefty 			break;
3494628e5f6dSSean Hefty 		}
34954ad6a024SParav Pandit 		ib_init_ah_attr_from_path(id_priv->id.device,
34964ad6a024SParav Pandit 					  id_priv->id.port_num,
3497628e5f6dSSean Hefty 					  id_priv->id.route.path_rec,
3498628e5f6dSSean Hefty 					  &event.param.ud.ah_attr);
3499628e5f6dSSean Hefty 		event.param.ud.qp_num = rep->qpn;
3500628e5f6dSSean Hefty 		event.param.ud.qkey = rep->qkey;
3501628e5f6dSSean Hefty 		event.event = RDMA_CM_EVENT_ESTABLISHED;
3502628e5f6dSSean Hefty 		event.status = 0;
3503628e5f6dSSean Hefty 		break;
3504628e5f6dSSean Hefty 	default:
3505aba25a3eSParav Pandit 		pr_err("RDMA CMA: unexpected IB CM event: %d\n",
3506628e5f6dSSean Hefty 		       ib_event->event);
3507628e5f6dSSean Hefty 		goto out;
3508628e5f6dSSean Hefty 	}
3509628e5f6dSSean Hefty 
3510628e5f6dSSean Hefty 	ret = id_priv->id.event_handler(&id_priv->id, &event);
3511628e5f6dSSean Hefty 	if (ret) {
3512628e5f6dSSean Hefty 		/* Destroy the CM ID by returning a non-zero value. */
3513628e5f6dSSean Hefty 		id_priv->cm_id.ib = NULL;
3514550e5ca7SNir Muchtar 		cma_exch(id_priv, RDMA_CM_DESTROYING);
3515de910bd9SOr Gerlitz 		mutex_unlock(&id_priv->handler_mutex);
3516628e5f6dSSean Hefty 		rdma_destroy_id(&id_priv->id);
3517628e5f6dSSean Hefty 		return ret;
3518628e5f6dSSean Hefty 	}
3519628e5f6dSSean Hefty out:
3520de910bd9SOr Gerlitz 	mutex_unlock(&id_priv->handler_mutex);
3521628e5f6dSSean Hefty 	return ret;
3522628e5f6dSSean Hefty }
3523628e5f6dSSean Hefty 
3524628e5f6dSSean Hefty static int cma_resolve_ib_udp(struct rdma_id_private *id_priv,
3525628e5f6dSSean Hefty 			      struct rdma_conn_param *conn_param)
3526628e5f6dSSean Hefty {
3527628e5f6dSSean Hefty 	struct ib_cm_sidr_req_param req;
35280c9361fcSJack Morgenstein 	struct ib_cm_id	*id;
3529e511d1aeSSean Hefty 	void *private_data;
3530c0b64f58SBart Van Assche 	u8 offset;
3531c0b64f58SBart Van Assche 	int ret;
3532628e5f6dSSean Hefty 
3533e511d1aeSSean Hefty 	memset(&req, 0, sizeof req);
3534e8160e15SSean Hefty 	offset = cma_user_data_offset(id_priv);
3535e8160e15SSean Hefty 	req.private_data_len = offset + conn_param->private_data_len;
353604ded167SSean Hefty 	if (req.private_data_len < conn_param->private_data_len)
353704ded167SSean Hefty 		return -EINVAL;
353804ded167SSean Hefty 
3539e8160e15SSean Hefty 	if (req.private_data_len) {
3540e511d1aeSSean Hefty 		private_data = kzalloc(req.private_data_len, GFP_ATOMIC);
3541e511d1aeSSean Hefty 		if (!private_data)
3542628e5f6dSSean Hefty 			return -ENOMEM;
3543e8160e15SSean Hefty 	} else {
3544e511d1aeSSean Hefty 		private_data = NULL;
3545e8160e15SSean Hefty 	}
3546628e5f6dSSean Hefty 
3547628e5f6dSSean Hefty 	if (conn_param->private_data && conn_param->private_data_len)
3548e511d1aeSSean Hefty 		memcpy(private_data + offset, conn_param->private_data,
3549e511d1aeSSean Hefty 		       conn_param->private_data_len);
3550628e5f6dSSean Hefty 
3551e511d1aeSSean Hefty 	if (private_data) {
3552e511d1aeSSean Hefty 		ret = cma_format_hdr(private_data, id_priv);
3553628e5f6dSSean Hefty 		if (ret)
3554628e5f6dSSean Hefty 			goto out;
3555e511d1aeSSean Hefty 		req.private_data = private_data;
3556e8160e15SSean Hefty 	}
3557628e5f6dSSean Hefty 
35580c9361fcSJack Morgenstein 	id = ib_create_cm_id(id_priv->id.device, cma_sidr_rep_handler,
35590c9361fcSJack Morgenstein 			     id_priv);
35600c9361fcSJack Morgenstein 	if (IS_ERR(id)) {
35610c9361fcSJack Morgenstein 		ret = PTR_ERR(id);
3562628e5f6dSSean Hefty 		goto out;
3563628e5f6dSSean Hefty 	}
35640c9361fcSJack Morgenstein 	id_priv->cm_id.ib = id;
3565628e5f6dSSean Hefty 
3566f4753834SSean Hefty 	req.path = id_priv->id.route.path_rec;
3567cf53936fSSean Hefty 	req.service_id = rdma_get_service_id(&id_priv->id, cma_dst_addr(id_priv));
3568628e5f6dSSean Hefty 	req.timeout_ms = 1 << (CMA_CM_RESPONSE_TIMEOUT - 8);
3569628e5f6dSSean Hefty 	req.max_cm_retries = CMA_MAX_CM_RETRIES;
3570628e5f6dSSean Hefty 
3571628e5f6dSSean Hefty 	ret = ib_send_cm_sidr_req(id_priv->cm_id.ib, &req);
3572628e5f6dSSean Hefty 	if (ret) {
3573628e5f6dSSean Hefty 		ib_destroy_cm_id(id_priv->cm_id.ib);
3574628e5f6dSSean Hefty 		id_priv->cm_id.ib = NULL;
3575628e5f6dSSean Hefty 	}
3576628e5f6dSSean Hefty out:
3577e511d1aeSSean Hefty 	kfree(private_data);
3578628e5f6dSSean Hefty 	return ret;
3579628e5f6dSSean Hefty }
3580628e5f6dSSean Hefty 
3581e51060f0SSean Hefty static int cma_connect_ib(struct rdma_id_private *id_priv,
3582e51060f0SSean Hefty 			  struct rdma_conn_param *conn_param)
3583e51060f0SSean Hefty {
3584e51060f0SSean Hefty 	struct ib_cm_req_param req;
3585e51060f0SSean Hefty 	struct rdma_route *route;
3586e51060f0SSean Hefty 	void *private_data;
35870c9361fcSJack Morgenstein 	struct ib_cm_id	*id;
3588c0b64f58SBart Van Assche 	u8 offset;
3589c0b64f58SBart Van Assche 	int ret;
3590e51060f0SSean Hefty 
3591e51060f0SSean Hefty 	memset(&req, 0, sizeof req);
3592e8160e15SSean Hefty 	offset = cma_user_data_offset(id_priv);
3593e51060f0SSean Hefty 	req.private_data_len = offset + conn_param->private_data_len;
359404ded167SSean Hefty 	if (req.private_data_len < conn_param->private_data_len)
359504ded167SSean Hefty 		return -EINVAL;
359604ded167SSean Hefty 
3597e8160e15SSean Hefty 	if (req.private_data_len) {
3598e51060f0SSean Hefty 		private_data = kzalloc(req.private_data_len, GFP_ATOMIC);
3599e51060f0SSean Hefty 		if (!private_data)
3600e51060f0SSean Hefty 			return -ENOMEM;
3601e8160e15SSean Hefty 	} else {
3602e8160e15SSean Hefty 		private_data = NULL;
3603e8160e15SSean Hefty 	}
3604e51060f0SSean Hefty 
3605e51060f0SSean Hefty 	if (conn_param->private_data && conn_param->private_data_len)
3606e51060f0SSean Hefty 		memcpy(private_data + offset, conn_param->private_data,
3607e51060f0SSean Hefty 		       conn_param->private_data_len);
3608e51060f0SSean Hefty 
36090c9361fcSJack Morgenstein 	id = ib_create_cm_id(id_priv->id.device, cma_ib_handler, id_priv);
36100c9361fcSJack Morgenstein 	if (IS_ERR(id)) {
36110c9361fcSJack Morgenstein 		ret = PTR_ERR(id);
3612e51060f0SSean Hefty 		goto out;
3613e51060f0SSean Hefty 	}
36140c9361fcSJack Morgenstein 	id_priv->cm_id.ib = id;
3615e51060f0SSean Hefty 
3616e51060f0SSean Hefty 	route = &id_priv->id.route;
3617e8160e15SSean Hefty 	if (private_data) {
3618f4753834SSean Hefty 		ret = cma_format_hdr(private_data, id_priv);
3619e51060f0SSean Hefty 		if (ret)
3620e51060f0SSean Hefty 			goto out;
3621e51060f0SSean Hefty 		req.private_data = private_data;
3622e8160e15SSean Hefty 	}
3623e51060f0SSean Hefty 
3624e51060f0SSean Hefty 	req.primary_path = &route->path_rec[0];
3625e51060f0SSean Hefty 	if (route->num_paths == 2)
3626e51060f0SSean Hefty 		req.alternate_path = &route->path_rec[1];
3627e51060f0SSean Hefty 
3628cf53936fSSean Hefty 	req.service_id = rdma_get_service_id(&id_priv->id, cma_dst_addr(id_priv));
3629e51060f0SSean Hefty 	req.qp_num = id_priv->qp_num;
363018c441a6SSean Hefty 	req.qp_type = id_priv->id.qp_type;
3631e51060f0SSean Hefty 	req.starting_psn = id_priv->seq_num;
3632e51060f0SSean Hefty 	req.responder_resources = conn_param->responder_resources;
3633e51060f0SSean Hefty 	req.initiator_depth = conn_param->initiator_depth;
3634e51060f0SSean Hefty 	req.flow_control = conn_param->flow_control;
36354ede178aSSean Hefty 	req.retry_count = min_t(u8, 7, conn_param->retry_count);
36364ede178aSSean Hefty 	req.rnr_retry_count = min_t(u8, 7, conn_param->rnr_retry_count);
3637e51060f0SSean Hefty 	req.remote_cm_response_timeout = CMA_CM_RESPONSE_TIMEOUT;
3638e51060f0SSean Hefty 	req.local_cm_response_timeout = CMA_CM_RESPONSE_TIMEOUT;
3639e51060f0SSean Hefty 	req.max_cm_retries = CMA_MAX_CM_RETRIES;
3640e51060f0SSean Hefty 	req.srq = id_priv->srq ? 1 : 0;
3641e51060f0SSean Hefty 
3642e51060f0SSean Hefty 	ret = ib_send_cm_req(id_priv->cm_id.ib, &req);
3643e51060f0SSean Hefty out:
36440c9361fcSJack Morgenstein 	if (ret && !IS_ERR(id)) {
36450c9361fcSJack Morgenstein 		ib_destroy_cm_id(id);
3646675a027cSKrishna Kumar 		id_priv->cm_id.ib = NULL;
3647675a027cSKrishna Kumar 	}
3648675a027cSKrishna Kumar 
3649e51060f0SSean Hefty 	kfree(private_data);
3650e51060f0SSean Hefty 	return ret;
3651e51060f0SSean Hefty }
3652e51060f0SSean Hefty 
365307ebafbaSTom Tucker static int cma_connect_iw(struct rdma_id_private *id_priv,
365407ebafbaSTom Tucker 			  struct rdma_conn_param *conn_param)
365507ebafbaSTom Tucker {
365607ebafbaSTom Tucker 	struct iw_cm_id *cm_id;
365707ebafbaSTom Tucker 	int ret;
365807ebafbaSTom Tucker 	struct iw_cm_conn_param iw_param;
365907ebafbaSTom Tucker 
366007ebafbaSTom Tucker 	cm_id = iw_create_cm_id(id_priv->id.device, cma_iw_handler, id_priv);
36610c9361fcSJack Morgenstein 	if (IS_ERR(cm_id))
36620c9361fcSJack Morgenstein 		return PTR_ERR(cm_id);
366307ebafbaSTom Tucker 
366468cdba06SSteve Wise 	cm_id->tos = id_priv->tos;
366507ebafbaSTom Tucker 	id_priv->cm_id.iw = cm_id;
366607ebafbaSTom Tucker 
366724d44a39SSteve Wise 	memcpy(&cm_id->local_addr, cma_src_addr(id_priv),
366824d44a39SSteve Wise 	       rdma_addr_size(cma_src_addr(id_priv)));
366924d44a39SSteve Wise 	memcpy(&cm_id->remote_addr, cma_dst_addr(id_priv),
367024d44a39SSteve Wise 	       rdma_addr_size(cma_dst_addr(id_priv)));
367107ebafbaSTom Tucker 
36725851bb89SSean Hefty 	ret = cma_modify_qp_rtr(id_priv, conn_param);
3673675a027cSKrishna Kumar 	if (ret)
3674675a027cSKrishna Kumar 		goto out;
367507ebafbaSTom Tucker 
3676f45ee80eSHefty, Sean 	if (conn_param) {
367707ebafbaSTom Tucker 		iw_param.ord = conn_param->initiator_depth;
367807ebafbaSTom Tucker 		iw_param.ird = conn_param->responder_resources;
367907ebafbaSTom Tucker 		iw_param.private_data = conn_param->private_data;
368007ebafbaSTom Tucker 		iw_param.private_data_len = conn_param->private_data_len;
3681f45ee80eSHefty, Sean 		iw_param.qpn = id_priv->id.qp ? id_priv->qp_num : conn_param->qp_num;
3682f45ee80eSHefty, Sean 	} else {
3683f45ee80eSHefty, Sean 		memset(&iw_param, 0, sizeof iw_param);
368407ebafbaSTom Tucker 		iw_param.qpn = id_priv->qp_num;
3685f45ee80eSHefty, Sean 	}
368607ebafbaSTom Tucker 	ret = iw_cm_connect(cm_id, &iw_param);
368707ebafbaSTom Tucker out:
36880c9361fcSJack Morgenstein 	if (ret) {
3689675a027cSKrishna Kumar 		iw_destroy_cm_id(cm_id);
3690675a027cSKrishna Kumar 		id_priv->cm_id.iw = NULL;
3691675a027cSKrishna Kumar 	}
369207ebafbaSTom Tucker 	return ret;
369307ebafbaSTom Tucker }
369407ebafbaSTom Tucker 
3695e51060f0SSean Hefty int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
3696e51060f0SSean Hefty {
3697e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
3698e51060f0SSean Hefty 	int ret;
3699e51060f0SSean Hefty 
3700e51060f0SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
3701550e5ca7SNir Muchtar 	if (!cma_comp_exch(id_priv, RDMA_CM_ROUTE_RESOLVED, RDMA_CM_CONNECT))
3702e51060f0SSean Hefty 		return -EINVAL;
3703e51060f0SSean Hefty 
3704e51060f0SSean Hefty 	if (!id->qp) {
3705e51060f0SSean Hefty 		id_priv->qp_num = conn_param->qp_num;
3706e51060f0SSean Hefty 		id_priv->srq = conn_param->srq;
3707e51060f0SSean Hefty 	}
3708e51060f0SSean Hefty 
370972219ceaSMichael Wang 	if (rdma_cap_ib_cm(id->device, id->port_num)) {
3710b26f9b99SSean Hefty 		if (id->qp_type == IB_QPT_UD)
3711628e5f6dSSean Hefty 			ret = cma_resolve_ib_udp(id_priv, conn_param);
3712628e5f6dSSean Hefty 		else
3713e51060f0SSean Hefty 			ret = cma_connect_ib(id_priv, conn_param);
371404215330SMichael Wang 	} else if (rdma_cap_iw_cm(id->device, id->port_num))
371507ebafbaSTom Tucker 		ret = cma_connect_iw(id_priv, conn_param);
371621655afcSMichael Wang 	else
3717e51060f0SSean Hefty 		ret = -ENOSYS;
3718e51060f0SSean Hefty 	if (ret)
3719e51060f0SSean Hefty 		goto err;
3720e51060f0SSean Hefty 
3721e51060f0SSean Hefty 	return 0;
3722e51060f0SSean Hefty err:
3723550e5ca7SNir Muchtar 	cma_comp_exch(id_priv, RDMA_CM_CONNECT, RDMA_CM_ROUTE_RESOLVED);
3724e51060f0SSean Hefty 	return ret;
3725e51060f0SSean Hefty }
3726e51060f0SSean Hefty EXPORT_SYMBOL(rdma_connect);
3727e51060f0SSean Hefty 
3728e51060f0SSean Hefty static int cma_accept_ib(struct rdma_id_private *id_priv,
3729e51060f0SSean Hefty 			 struct rdma_conn_param *conn_param)
3730e51060f0SSean Hefty {
3731e51060f0SSean Hefty 	struct ib_cm_rep_param rep;
37325851bb89SSean Hefty 	int ret;
3733e51060f0SSean Hefty 
37345851bb89SSean Hefty 	ret = cma_modify_qp_rtr(id_priv, conn_param);
3735e51060f0SSean Hefty 	if (ret)
37360fe313b0SSean Hefty 		goto out;
37370fe313b0SSean Hefty 
37385851bb89SSean Hefty 	ret = cma_modify_qp_rts(id_priv, conn_param);
37390fe313b0SSean Hefty 	if (ret)
37400fe313b0SSean Hefty 		goto out;
37410fe313b0SSean Hefty 
3742e51060f0SSean Hefty 	memset(&rep, 0, sizeof rep);
3743e51060f0SSean Hefty 	rep.qp_num = id_priv->qp_num;
3744e51060f0SSean Hefty 	rep.starting_psn = id_priv->seq_num;
3745e51060f0SSean Hefty 	rep.private_data = conn_param->private_data;
3746e51060f0SSean Hefty 	rep.private_data_len = conn_param->private_data_len;
3747e51060f0SSean Hefty 	rep.responder_resources = conn_param->responder_resources;
3748e51060f0SSean Hefty 	rep.initiator_depth = conn_param->initiator_depth;
3749e51060f0SSean Hefty 	rep.failover_accepted = 0;
3750e51060f0SSean Hefty 	rep.flow_control = conn_param->flow_control;
37514ede178aSSean Hefty 	rep.rnr_retry_count = min_t(u8, 7, conn_param->rnr_retry_count);
3752e51060f0SSean Hefty 	rep.srq = id_priv->srq ? 1 : 0;
3753e51060f0SSean Hefty 
37540fe313b0SSean Hefty 	ret = ib_send_cm_rep(id_priv->cm_id.ib, &rep);
37550fe313b0SSean Hefty out:
37560fe313b0SSean Hefty 	return ret;
3757e51060f0SSean Hefty }
3758e51060f0SSean Hefty 
375907ebafbaSTom Tucker static int cma_accept_iw(struct rdma_id_private *id_priv,
376007ebafbaSTom Tucker 		  struct rdma_conn_param *conn_param)
376107ebafbaSTom Tucker {
376207ebafbaSTom Tucker 	struct iw_cm_conn_param iw_param;
376307ebafbaSTom Tucker 	int ret;
376407ebafbaSTom Tucker 
3765f2625f7dSSteve Wise 	if (!conn_param)
3766f2625f7dSSteve Wise 		return -EINVAL;
3767f2625f7dSSteve Wise 
37685851bb89SSean Hefty 	ret = cma_modify_qp_rtr(id_priv, conn_param);
376907ebafbaSTom Tucker 	if (ret)
377007ebafbaSTom Tucker 		return ret;
377107ebafbaSTom Tucker 
377207ebafbaSTom Tucker 	iw_param.ord = conn_param->initiator_depth;
377307ebafbaSTom Tucker 	iw_param.ird = conn_param->responder_resources;
377407ebafbaSTom Tucker 	iw_param.private_data = conn_param->private_data;
377507ebafbaSTom Tucker 	iw_param.private_data_len = conn_param->private_data_len;
377607ebafbaSTom Tucker 	if (id_priv->id.qp) {
377707ebafbaSTom Tucker 		iw_param.qpn = id_priv->qp_num;
377807ebafbaSTom Tucker 	} else
377907ebafbaSTom Tucker 		iw_param.qpn = conn_param->qp_num;
378007ebafbaSTom Tucker 
378107ebafbaSTom Tucker 	return iw_cm_accept(id_priv->cm_id.iw, &iw_param);
378207ebafbaSTom Tucker }
378307ebafbaSTom Tucker 
3784628e5f6dSSean Hefty static int cma_send_sidr_rep(struct rdma_id_private *id_priv,
37855c438135SSean Hefty 			     enum ib_cm_sidr_status status, u32 qkey,
3786628e5f6dSSean Hefty 			     const void *private_data, int private_data_len)
3787628e5f6dSSean Hefty {
3788628e5f6dSSean Hefty 	struct ib_cm_sidr_rep_param rep;
3789d2ca39f2SYossi Etigin 	int ret;
3790628e5f6dSSean Hefty 
3791628e5f6dSSean Hefty 	memset(&rep, 0, sizeof rep);
3792628e5f6dSSean Hefty 	rep.status = status;
3793628e5f6dSSean Hefty 	if (status == IB_SIDR_SUCCESS) {
37945c438135SSean Hefty 		ret = cma_set_qkey(id_priv, qkey);
3795d2ca39f2SYossi Etigin 		if (ret)
3796d2ca39f2SYossi Etigin 			return ret;
3797628e5f6dSSean Hefty 		rep.qp_num = id_priv->qp_num;
3798c8f6a362SSean Hefty 		rep.qkey = id_priv->qkey;
3799628e5f6dSSean Hefty 	}
3800628e5f6dSSean Hefty 	rep.private_data = private_data;
3801628e5f6dSSean Hefty 	rep.private_data_len = private_data_len;
3802628e5f6dSSean Hefty 
3803628e5f6dSSean Hefty 	return ib_send_cm_sidr_rep(id_priv->cm_id.ib, &rep);
3804628e5f6dSSean Hefty }
3805628e5f6dSSean Hefty 
380600313983SSteve Wise int __rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param,
380700313983SSteve Wise 		  const char *caller)
3808e51060f0SSean Hefty {
3809e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
3810e51060f0SSean Hefty 	int ret;
3811e51060f0SSean Hefty 
3812e51060f0SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
381383e9502dSNir Muchtar 
381400313983SSteve Wise 	if (caller)
381500313983SSteve Wise 		id_priv->res.kern_name = caller;
381600313983SSteve Wise 	else
381700313983SSteve Wise 		rdma_restrack_set_task(&id_priv->res, current);
381883e9502dSNir Muchtar 
3819550e5ca7SNir Muchtar 	if (!cma_comp(id_priv, RDMA_CM_CONNECT))
3820e51060f0SSean Hefty 		return -EINVAL;
3821e51060f0SSean Hefty 
3822e51060f0SSean Hefty 	if (!id->qp && conn_param) {
3823e51060f0SSean Hefty 		id_priv->qp_num = conn_param->qp_num;
3824e51060f0SSean Hefty 		id_priv->srq = conn_param->srq;
3825e51060f0SSean Hefty 	}
3826e51060f0SSean Hefty 
382772219ceaSMichael Wang 	if (rdma_cap_ib_cm(id->device, id->port_num)) {
3828f45ee80eSHefty, Sean 		if (id->qp_type == IB_QPT_UD) {
3829f45ee80eSHefty, Sean 			if (conn_param)
3830628e5f6dSSean Hefty 				ret = cma_send_sidr_rep(id_priv, IB_SIDR_SUCCESS,
38315c438135SSean Hefty 							conn_param->qkey,
3832628e5f6dSSean Hefty 							conn_param->private_data,
3833628e5f6dSSean Hefty 							conn_param->private_data_len);
3834f45ee80eSHefty, Sean 			else
3835f45ee80eSHefty, Sean 				ret = cma_send_sidr_rep(id_priv, IB_SIDR_SUCCESS,
38365c438135SSean Hefty 							0, NULL, 0);
3837f45ee80eSHefty, Sean 		} else {
3838f45ee80eSHefty, Sean 			if (conn_param)
3839e51060f0SSean Hefty 				ret = cma_accept_ib(id_priv, conn_param);
3840e51060f0SSean Hefty 			else
3841e51060f0SSean Hefty 				ret = cma_rep_recv(id_priv);
3842f45ee80eSHefty, Sean 		}
384304215330SMichael Wang 	} else if (rdma_cap_iw_cm(id->device, id->port_num))
384407ebafbaSTom Tucker 		ret = cma_accept_iw(id_priv, conn_param);
384521655afcSMichael Wang 	else
3846e51060f0SSean Hefty 		ret = -ENOSYS;
3847e51060f0SSean Hefty 
3848e51060f0SSean Hefty 	if (ret)
3849e51060f0SSean Hefty 		goto reject;
3850e51060f0SSean Hefty 
3851e51060f0SSean Hefty 	return 0;
3852e51060f0SSean Hefty reject:
3853c5483388SSean Hefty 	cma_modify_qp_err(id_priv);
3854e51060f0SSean Hefty 	rdma_reject(id, NULL, 0);
3855e51060f0SSean Hefty 	return ret;
3856e51060f0SSean Hefty }
385700313983SSteve Wise EXPORT_SYMBOL(__rdma_accept);
3858e51060f0SSean Hefty 
38590fe313b0SSean Hefty int rdma_notify(struct rdma_cm_id *id, enum ib_event_type event)
38600fe313b0SSean Hefty {
38610fe313b0SSean Hefty 	struct rdma_id_private *id_priv;
38620fe313b0SSean Hefty 	int ret;
38630fe313b0SSean Hefty 
38640fe313b0SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
38650c9361fcSJack Morgenstein 	if (!id_priv->cm_id.ib)
38660fe313b0SSean Hefty 		return -EINVAL;
38670fe313b0SSean Hefty 
38680fe313b0SSean Hefty 	switch (id->device->node_type) {
38690fe313b0SSean Hefty 	case RDMA_NODE_IB_CA:
38700fe313b0SSean Hefty 		ret = ib_cm_notify(id_priv->cm_id.ib, event);
38710fe313b0SSean Hefty 		break;
38720fe313b0SSean Hefty 	default:
38730fe313b0SSean Hefty 		ret = 0;
38740fe313b0SSean Hefty 		break;
38750fe313b0SSean Hefty 	}
38760fe313b0SSean Hefty 	return ret;
38770fe313b0SSean Hefty }
38780fe313b0SSean Hefty EXPORT_SYMBOL(rdma_notify);
38790fe313b0SSean Hefty 
3880e51060f0SSean Hefty int rdma_reject(struct rdma_cm_id *id, const void *private_data,
3881e51060f0SSean Hefty 		u8 private_data_len)
3882e51060f0SSean Hefty {
3883e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
3884e51060f0SSean Hefty 	int ret;
3885e51060f0SSean Hefty 
3886e51060f0SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
38870c9361fcSJack Morgenstein 	if (!id_priv->cm_id.ib)
3888e51060f0SSean Hefty 		return -EINVAL;
3889e51060f0SSean Hefty 
389072219ceaSMichael Wang 	if (rdma_cap_ib_cm(id->device, id->port_num)) {
3891b26f9b99SSean Hefty 		if (id->qp_type == IB_QPT_UD)
38925c438135SSean Hefty 			ret = cma_send_sidr_rep(id_priv, IB_SIDR_REJECT, 0,
3893e51060f0SSean Hefty 						private_data, private_data_len);
3894628e5f6dSSean Hefty 		else
3895628e5f6dSSean Hefty 			ret = ib_send_cm_rej(id_priv->cm_id.ib,
3896628e5f6dSSean Hefty 					     IB_CM_REJ_CONSUMER_DEFINED, NULL,
3897628e5f6dSSean Hefty 					     0, private_data, private_data_len);
389804215330SMichael Wang 	} else if (rdma_cap_iw_cm(id->device, id->port_num)) {
389907ebafbaSTom Tucker 		ret = iw_cm_reject(id_priv->cm_id.iw,
390007ebafbaSTom Tucker 				   private_data, private_data_len);
390121655afcSMichael Wang 	} else
3902e51060f0SSean Hefty 		ret = -ENOSYS;
390321655afcSMichael Wang 
3904e51060f0SSean Hefty 	return ret;
3905e51060f0SSean Hefty }
3906e51060f0SSean Hefty EXPORT_SYMBOL(rdma_reject);
3907e51060f0SSean Hefty 
3908e51060f0SSean Hefty int rdma_disconnect(struct rdma_cm_id *id)
3909e51060f0SSean Hefty {
3910e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
3911e51060f0SSean Hefty 	int ret;
3912e51060f0SSean Hefty 
3913e51060f0SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
39140c9361fcSJack Morgenstein 	if (!id_priv->cm_id.ib)
3915e51060f0SSean Hefty 		return -EINVAL;
3916e51060f0SSean Hefty 
391772219ceaSMichael Wang 	if (rdma_cap_ib_cm(id->device, id->port_num)) {
3918c5483388SSean Hefty 		ret = cma_modify_qp_err(id_priv);
3919e51060f0SSean Hefty 		if (ret)
3920e51060f0SSean Hefty 			goto out;
3921e51060f0SSean Hefty 		/* Initiate or respond to a disconnect. */
3922e51060f0SSean Hefty 		if (ib_send_cm_dreq(id_priv->cm_id.ib, NULL, 0))
3923e51060f0SSean Hefty 			ib_send_cm_drep(id_priv->cm_id.ib, NULL, 0);
392404215330SMichael Wang 	} else if (rdma_cap_iw_cm(id->device, id->port_num)) {
392507ebafbaSTom Tucker 		ret = iw_cm_disconnect(id_priv->cm_id.iw, 0);
392621655afcSMichael Wang 	} else
392707ebafbaSTom Tucker 		ret = -EINVAL;
392821655afcSMichael Wang 
3929e51060f0SSean Hefty out:
3930e51060f0SSean Hefty 	return ret;
3931e51060f0SSean Hefty }
3932e51060f0SSean Hefty EXPORT_SYMBOL(rdma_disconnect);
3933e51060f0SSean Hefty 
3934c8f6a362SSean Hefty static int cma_ib_mc_handler(int status, struct ib_sa_multicast *multicast)
3935c8f6a362SSean Hefty {
3936c8f6a362SSean Hefty 	struct rdma_id_private *id_priv;
3937c8f6a362SSean Hefty 	struct cma_multicast *mc = multicast->context;
3938c8f6a362SSean Hefty 	struct rdma_cm_event event;
393937e07cdaSBart Van Assche 	int ret = 0;
3940c8f6a362SSean Hefty 
3941c8f6a362SSean Hefty 	id_priv = mc->id_priv;
394237e07cdaSBart Van Assche 	mutex_lock(&id_priv->handler_mutex);
394337e07cdaSBart Van Assche 	if (id_priv->state != RDMA_CM_ADDR_BOUND &&
394437e07cdaSBart Van Assche 	    id_priv->state != RDMA_CM_ADDR_RESOLVED)
394537e07cdaSBart Van Assche 		goto out;
3946c8f6a362SSean Hefty 
39475c438135SSean Hefty 	if (!status)
39485c438135SSean Hefty 		status = cma_set_qkey(id_priv, be32_to_cpu(multicast->rec.qkey));
3949498683c6SMoni Shoua 	else
3950498683c6SMoni Shoua 		pr_debug_ratelimited("RDMA CM: MULTICAST_ERROR: failed to join multicast. status %d\n",
3951498683c6SMoni Shoua 				     status);
3952c5483388SSean Hefty 	mutex_lock(&id_priv->qp_mutex);
3953498683c6SMoni Shoua 	if (!status && id_priv->id.qp) {
3954c8f6a362SSean Hefty 		status = ib_attach_mcast(id_priv->id.qp, &multicast->rec.mgid,
395546ea5061SSean Hefty 					 be16_to_cpu(multicast->rec.mlid));
3956a3dd3a48SChristophe Jaillet 		if (status)
3957498683c6SMoni Shoua 			pr_debug_ratelimited("RDMA CM: MULTICAST_ERROR: failed to attach QP. status %d\n",
3958498683c6SMoni Shoua 					     status);
3959498683c6SMoni Shoua 	}
3960c5483388SSean Hefty 	mutex_unlock(&id_priv->qp_mutex);
3961c8f6a362SSean Hefty 
3962c8f6a362SSean Hefty 	memset(&event, 0, sizeof event);
3963c8f6a362SSean Hefty 	event.status = status;
3964c8f6a362SSean Hefty 	event.param.ud.private_data = mc->context;
3965c8f6a362SSean Hefty 	if (!status) {
3966bee3c3c9SMoni Shoua 		struct rdma_dev_addr *dev_addr =
3967bee3c3c9SMoni Shoua 			&id_priv->id.route.addr.dev_addr;
3968bee3c3c9SMoni Shoua 		struct net_device *ndev =
3969052eac6eSParav Pandit 			dev_get_by_index(dev_addr->net, dev_addr->bound_dev_if);
3970bee3c3c9SMoni Shoua 		enum ib_gid_type gid_type =
3971bee3c3c9SMoni Shoua 			id_priv->cma_dev->default_gid_type[id_priv->id.port_num -
3972bee3c3c9SMoni Shoua 			rdma_start_port(id_priv->cma_dev->device)];
3973bee3c3c9SMoni Shoua 
3974c8f6a362SSean Hefty 		event.event = RDMA_CM_EVENT_MULTICAST_JOIN;
39756d337179SParav Pandit 		ret = ib_init_ah_from_mcmember(id_priv->id.device,
39766d337179SParav Pandit 					       id_priv->id.port_num,
39776d337179SParav Pandit 					       &multicast->rec,
3978bee3c3c9SMoni Shoua 					       ndev, gid_type,
3979c8f6a362SSean Hefty 					       &event.param.ud.ah_attr);
39806d337179SParav Pandit 		if (ret)
39816d337179SParav Pandit 			event.event = RDMA_CM_EVENT_MULTICAST_ERROR;
39826d337179SParav Pandit 
3983c8f6a362SSean Hefty 		event.param.ud.qp_num = 0xFFFFFF;
3984c8f6a362SSean Hefty 		event.param.ud.qkey = be32_to_cpu(multicast->rec.qkey);
3985bee3c3c9SMoni Shoua 		if (ndev)
3986bee3c3c9SMoni Shoua 			dev_put(ndev);
3987c8f6a362SSean Hefty 	} else
3988c8f6a362SSean Hefty 		event.event = RDMA_CM_EVENT_MULTICAST_ERROR;
3989c8f6a362SSean Hefty 
3990c8f6a362SSean Hefty 	ret = id_priv->id.event_handler(&id_priv->id, &event);
3991c8f6a362SSean Hefty 	if (ret) {
3992550e5ca7SNir Muchtar 		cma_exch(id_priv, RDMA_CM_DESTROYING);
3993de910bd9SOr Gerlitz 		mutex_unlock(&id_priv->handler_mutex);
3994c8f6a362SSean Hefty 		rdma_destroy_id(&id_priv->id);
3995c8f6a362SSean Hefty 		return 0;
3996c8f6a362SSean Hefty 	}
39978aa08602SSean Hefty 
399837e07cdaSBart Van Assche out:
3999de910bd9SOr Gerlitz 	mutex_unlock(&id_priv->handler_mutex);
4000c8f6a362SSean Hefty 	return 0;
4001c8f6a362SSean Hefty }
4002c8f6a362SSean Hefty 
4003c8f6a362SSean Hefty static void cma_set_mgid(struct rdma_id_private *id_priv,
4004c8f6a362SSean Hefty 			 struct sockaddr *addr, union ib_gid *mgid)
4005c8f6a362SSean Hefty {
4006c8f6a362SSean Hefty 	unsigned char mc_map[MAX_ADDR_LEN];
4007c8f6a362SSean Hefty 	struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
4008c8f6a362SSean Hefty 	struct sockaddr_in *sin = (struct sockaddr_in *) addr;
4009c8f6a362SSean Hefty 	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) addr;
4010c8f6a362SSean Hefty 
4011c8f6a362SSean Hefty 	if (cma_any_addr(addr)) {
4012c8f6a362SSean Hefty 		memset(mgid, 0, sizeof *mgid);
4013c8f6a362SSean Hefty 	} else if ((addr->sa_family == AF_INET6) &&
40141c9b2819SJason Gunthorpe 		   ((be32_to_cpu(sin6->sin6_addr.s6_addr32[0]) & 0xFFF0FFFF) ==
4015c8f6a362SSean Hefty 								 0xFF10A01B)) {
4016c8f6a362SSean Hefty 		/* IPv6 address is an SA assigned MGID. */
4017c8f6a362SSean Hefty 		memcpy(mgid, &sin6->sin6_addr, sizeof *mgid);
40185bc2b7b3SSean Hefty 	} else if (addr->sa_family == AF_IB) {
40195bc2b7b3SSean Hefty 		memcpy(mgid, &((struct sockaddr_ib *) addr)->sib_addr, sizeof *mgid);
4020e2e62697SJason Gunthorpe 	} else if ((addr->sa_family == AF_INET6)) {
4021e2e62697SJason Gunthorpe 		ipv6_ib_mc_map(&sin6->sin6_addr, dev_addr->broadcast, mc_map);
4022e2e62697SJason Gunthorpe 		if (id_priv->id.ps == RDMA_PS_UDP)
4023e2e62697SJason Gunthorpe 			mc_map[7] = 0x01;	/* Use RDMA CM signature */
4024e2e62697SJason Gunthorpe 		*mgid = *(union ib_gid *) (mc_map + 4);
4025c8f6a362SSean Hefty 	} else {
4026a9e527e3SRolf Manderscheid 		ip_ib_mc_map(sin->sin_addr.s_addr, dev_addr->broadcast, mc_map);
4027c8f6a362SSean Hefty 		if (id_priv->id.ps == RDMA_PS_UDP)
4028c8f6a362SSean Hefty 			mc_map[7] = 0x01;	/* Use RDMA CM signature */
4029c8f6a362SSean Hefty 		*mgid = *(union ib_gid *) (mc_map + 4);
4030c8f6a362SSean Hefty 	}
4031c8f6a362SSean Hefty }
4032c8f6a362SSean Hefty 
4033c8f6a362SSean Hefty static int cma_join_ib_multicast(struct rdma_id_private *id_priv,
4034c8f6a362SSean Hefty 				 struct cma_multicast *mc)
4035c8f6a362SSean Hefty {
4036c8f6a362SSean Hefty 	struct ib_sa_mcmember_rec rec;
4037c8f6a362SSean Hefty 	struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
4038c8f6a362SSean Hefty 	ib_sa_comp_mask comp_mask;
4039c8f6a362SSean Hefty 	int ret;
4040c8f6a362SSean Hefty 
4041c8f6a362SSean Hefty 	ib_addr_get_mgid(dev_addr, &rec.mgid);
4042c8f6a362SSean Hefty 	ret = ib_sa_get_mcmember_rec(id_priv->id.device, id_priv->id.port_num,
4043c8f6a362SSean Hefty 				     &rec.mgid, &rec);
4044c8f6a362SSean Hefty 	if (ret)
4045c8f6a362SSean Hefty 		return ret;
4046c8f6a362SSean Hefty 
40475bc2b7b3SSean Hefty 	ret = cma_set_qkey(id_priv, 0);
40485bc2b7b3SSean Hefty 	if (ret)
40495bc2b7b3SSean Hefty 		return ret;
40505bc2b7b3SSean Hefty 
40513f446754SRoland Dreier 	cma_set_mgid(id_priv, (struct sockaddr *) &mc->addr, &rec.mgid);
40525bc2b7b3SSean Hefty 	rec.qkey = cpu_to_be32(id_priv->qkey);
40536f8372b6SSean Hefty 	rdma_addr_get_sgid(dev_addr, &rec.port_gid);
4054c8f6a362SSean Hefty 	rec.pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr));
4055ab15c95aSAlex Vesker 	rec.join_state = mc->join_state;
4056ab15c95aSAlex Vesker 
4057ee1c60b1SDasaratharaman Chandramouli 	if ((rec.join_state == BIT(SENDONLY_FULLMEMBER_JOIN)) &&
4058ee1c60b1SDasaratharaman Chandramouli 	    (!ib_sa_sendonly_fullmem_support(&sa_client,
4059ee1c60b1SDasaratharaman Chandramouli 					     id_priv->id.device,
4060ee1c60b1SDasaratharaman Chandramouli 					     id_priv->id.port_num))) {
4061ab15c95aSAlex Vesker 		pr_warn("RDMA CM: %s port %u Unable to multicast join\n"
4062ab15c95aSAlex Vesker 			"RDMA CM: SM doesn't support Send Only Full Member option\n",
4063ab15c95aSAlex Vesker 			id_priv->id.device->name, id_priv->id.port_num);
4064ab15c95aSAlex Vesker 		return -EOPNOTSUPP;
4065ab15c95aSAlex Vesker 	}
4066c8f6a362SSean Hefty 
4067c8f6a362SSean Hefty 	comp_mask = IB_SA_MCMEMBER_REC_MGID | IB_SA_MCMEMBER_REC_PORT_GID |
4068c8f6a362SSean Hefty 		    IB_SA_MCMEMBER_REC_PKEY | IB_SA_MCMEMBER_REC_JOIN_STATE |
4069c8f6a362SSean Hefty 		    IB_SA_MCMEMBER_REC_QKEY | IB_SA_MCMEMBER_REC_SL |
4070c8f6a362SSean Hefty 		    IB_SA_MCMEMBER_REC_FLOW_LABEL |
4071c8f6a362SSean Hefty 		    IB_SA_MCMEMBER_REC_TRAFFIC_CLASS;
4072c8f6a362SSean Hefty 
407384adeee9SYossi Etigin 	if (id_priv->id.ps == RDMA_PS_IPOIB)
407484adeee9SYossi Etigin 		comp_mask |= IB_SA_MCMEMBER_REC_RATE |
40752a22fb8cSDotan Barak 			     IB_SA_MCMEMBER_REC_RATE_SELECTOR |
40762a22fb8cSDotan Barak 			     IB_SA_MCMEMBER_REC_MTU_SELECTOR |
40772a22fb8cSDotan Barak 			     IB_SA_MCMEMBER_REC_MTU |
40782a22fb8cSDotan Barak 			     IB_SA_MCMEMBER_REC_HOP_LIMIT;
407984adeee9SYossi Etigin 
4080c8f6a362SSean Hefty 	mc->multicast.ib = ib_sa_join_multicast(&sa_client, id_priv->id.device,
4081c8f6a362SSean Hefty 						id_priv->id.port_num, &rec,
4082c8f6a362SSean Hefty 						comp_mask, GFP_KERNEL,
4083c8f6a362SSean Hefty 						cma_ib_mc_handler, mc);
40848c6ffba0SRusty Russell 	return PTR_ERR_OR_ZERO(mc->multicast.ib);
4085c8f6a362SSean Hefty }
4086c8f6a362SSean Hefty 
40873c86aa70SEli Cohen static void iboe_mcast_work_handler(struct work_struct *work)
40883c86aa70SEli Cohen {
40893c86aa70SEli Cohen 	struct iboe_mcast_work *mw = container_of(work, struct iboe_mcast_work, work);
40903c86aa70SEli Cohen 	struct cma_multicast *mc = mw->mc;
40913c86aa70SEli Cohen 	struct ib_sa_multicast *m = mc->multicast.ib;
40923c86aa70SEli Cohen 
40933c86aa70SEli Cohen 	mc->multicast.ib->context = mc;
40943c86aa70SEli Cohen 	cma_ib_mc_handler(0, m);
40953c86aa70SEli Cohen 	kref_put(&mc->mcref, release_mc);
40963c86aa70SEli Cohen 	kfree(mw);
40973c86aa70SEli Cohen }
40983c86aa70SEli Cohen 
4099be1d325aSNoa Osherovich static void cma_iboe_set_mgid(struct sockaddr *addr, union ib_gid *mgid,
4100be1d325aSNoa Osherovich 			      enum ib_gid_type gid_type)
41013c86aa70SEli Cohen {
41023c86aa70SEli Cohen 	struct sockaddr_in *sin = (struct sockaddr_in *)addr;
41033c86aa70SEli Cohen 	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
41043c86aa70SEli Cohen 
41053c86aa70SEli Cohen 	if (cma_any_addr(addr)) {
41063c86aa70SEli Cohen 		memset(mgid, 0, sizeof *mgid);
41073c86aa70SEli Cohen 	} else if (addr->sa_family == AF_INET6) {
41083c86aa70SEli Cohen 		memcpy(mgid, &sin6->sin6_addr, sizeof *mgid);
41093c86aa70SEli Cohen 	} else {
41105c181bdaSParav Pandit 		mgid->raw[0] =
41115c181bdaSParav Pandit 			(gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) ? 0 : 0xff;
41125c181bdaSParav Pandit 		mgid->raw[1] =
41135c181bdaSParav Pandit 			(gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) ? 0 : 0x0e;
41143c86aa70SEli Cohen 		mgid->raw[2] = 0;
41153c86aa70SEli Cohen 		mgid->raw[3] = 0;
41163c86aa70SEli Cohen 		mgid->raw[4] = 0;
41173c86aa70SEli Cohen 		mgid->raw[5] = 0;
41183c86aa70SEli Cohen 		mgid->raw[6] = 0;
41193c86aa70SEli Cohen 		mgid->raw[7] = 0;
41203c86aa70SEli Cohen 		mgid->raw[8] = 0;
41213c86aa70SEli Cohen 		mgid->raw[9] = 0;
41223c86aa70SEli Cohen 		mgid->raw[10] = 0xff;
41233c86aa70SEli Cohen 		mgid->raw[11] = 0xff;
41243c86aa70SEli Cohen 		*(__be32 *)(&mgid->raw[12]) = sin->sin_addr.s_addr;
41253c86aa70SEli Cohen 	}
41263c86aa70SEli Cohen }
41273c86aa70SEli Cohen 
41283c86aa70SEli Cohen static int cma_iboe_join_multicast(struct rdma_id_private *id_priv,
41293c86aa70SEli Cohen 				   struct cma_multicast *mc)
41303c86aa70SEli Cohen {
41313c86aa70SEli Cohen 	struct iboe_mcast_work *work;
41323c86aa70SEli Cohen 	struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
4133bee3c3c9SMoni Shoua 	int err = 0;
41343c86aa70SEli Cohen 	struct sockaddr *addr = (struct sockaddr *)&mc->addr;
41353c86aa70SEli Cohen 	struct net_device *ndev = NULL;
4136bee3c3c9SMoni Shoua 	enum ib_gid_type gid_type;
4137ab15c95aSAlex Vesker 	bool send_only;
4138ab15c95aSAlex Vesker 
4139ab15c95aSAlex Vesker 	send_only = mc->join_state == BIT(SENDONLY_FULLMEMBER_JOIN);
41403c86aa70SEli Cohen 
41413c86aa70SEli Cohen 	if (cma_zero_addr((struct sockaddr *)&mc->addr))
41423c86aa70SEli Cohen 		return -EINVAL;
41433c86aa70SEli Cohen 
41443c86aa70SEli Cohen 	work = kzalloc(sizeof *work, GFP_KERNEL);
41453c86aa70SEli Cohen 	if (!work)
41463c86aa70SEli Cohen 		return -ENOMEM;
41473c86aa70SEli Cohen 
41483c86aa70SEli Cohen 	mc->multicast.ib = kzalloc(sizeof(struct ib_sa_multicast), GFP_KERNEL);
41493c86aa70SEli Cohen 	if (!mc->multicast.ib) {
41503c86aa70SEli Cohen 		err = -ENOMEM;
41513c86aa70SEli Cohen 		goto out1;
41523c86aa70SEli Cohen 	}
41533c86aa70SEli Cohen 
4154be1d325aSNoa Osherovich 	gid_type = id_priv->cma_dev->default_gid_type[id_priv->id.port_num -
4155be1d325aSNoa Osherovich 		   rdma_start_port(id_priv->cma_dev->device)];
4156be1d325aSNoa Osherovich 	cma_iboe_set_mgid(addr, &mc->multicast.ib->rec.mgid, gid_type);
41573c86aa70SEli Cohen 
41583c86aa70SEli Cohen 	mc->multicast.ib->rec.pkey = cpu_to_be16(0xffff);
41593c86aa70SEli Cohen 	if (id_priv->id.ps == RDMA_PS_UDP)
41603c86aa70SEli Cohen 		mc->multicast.ib->rec.qkey = cpu_to_be32(RDMA_UDP_QKEY);
41613c86aa70SEli Cohen 
41623c86aa70SEli Cohen 	if (dev_addr->bound_dev_if)
4163052eac6eSParav Pandit 		ndev = dev_get_by_index(dev_addr->net, dev_addr->bound_dev_if);
41643c86aa70SEli Cohen 	if (!ndev) {
41653c86aa70SEli Cohen 		err = -ENODEV;
41663c86aa70SEli Cohen 		goto out2;
41673c86aa70SEli Cohen 	}
41683c86aa70SEli Cohen 	mc->multicast.ib->rec.rate = iboe_get_rate(ndev);
41693c86aa70SEli Cohen 	mc->multicast.ib->rec.hop_limit = 1;
41703c86aa70SEli Cohen 	mc->multicast.ib->rec.mtu = iboe_get_mtu(ndev->mtu);
4171bee3c3c9SMoni Shoua 
4172bee3c3c9SMoni Shoua 	if (addr->sa_family == AF_INET) {
4173c65f6c5aSAlex Vesker 		if (gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) {
4174c65f6c5aSAlex Vesker 			mc->multicast.ib->rec.hop_limit = IPV6_DEFAULT_HOPLIMIT;
4175ab15c95aSAlex Vesker 			if (!send_only) {
4176bee3c3c9SMoni Shoua 				err = cma_igmp_send(ndev, &mc->multicast.ib->rec.mgid,
4177bee3c3c9SMoni Shoua 						    true);
4178c65f6c5aSAlex Vesker 				if (!err)
4179bee3c3c9SMoni Shoua 					mc->igmp_joined = true;
4180bee3c3c9SMoni Shoua 			}
4181bee3c3c9SMoni Shoua 		}
4182bee3c3c9SMoni Shoua 	} else {
4183bee3c3c9SMoni Shoua 		if (gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP)
4184bee3c3c9SMoni Shoua 			err = -ENOTSUPP;
4185bee3c3c9SMoni Shoua 	}
41863c86aa70SEli Cohen 	dev_put(ndev);
4187bee3c3c9SMoni Shoua 	if (err || !mc->multicast.ib->rec.mtu) {
4188bee3c3c9SMoni Shoua 		if (!err)
41893c86aa70SEli Cohen 			err = -EINVAL;
41903c86aa70SEli Cohen 		goto out2;
41913c86aa70SEli Cohen 	}
41927b85627bSMoni Shoua 	rdma_ip2gid((struct sockaddr *)&id_priv->id.route.addr.src_addr,
41937b85627bSMoni Shoua 		    &mc->multicast.ib->rec.port_gid);
41943c86aa70SEli Cohen 	work->id = id_priv;
41953c86aa70SEli Cohen 	work->mc = mc;
41963c86aa70SEli Cohen 	INIT_WORK(&work->work, iboe_mcast_work_handler);
41973c86aa70SEli Cohen 	kref_get(&mc->mcref);
41983c86aa70SEli Cohen 	queue_work(cma_wq, &work->work);
41993c86aa70SEli Cohen 
42003c86aa70SEli Cohen 	return 0;
42013c86aa70SEli Cohen 
42023c86aa70SEli Cohen out2:
42033c86aa70SEli Cohen 	kfree(mc->multicast.ib);
42043c86aa70SEli Cohen out1:
42053c86aa70SEli Cohen 	kfree(work);
42063c86aa70SEli Cohen 	return err;
42073c86aa70SEli Cohen }
42083c86aa70SEli Cohen 
4209c8f6a362SSean Hefty int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr,
4210ab15c95aSAlex Vesker 			u8 join_state, void *context)
4211c8f6a362SSean Hefty {
4212c8f6a362SSean Hefty 	struct rdma_id_private *id_priv;
4213c8f6a362SSean Hefty 	struct cma_multicast *mc;
4214c8f6a362SSean Hefty 	int ret;
4215c8f6a362SSean Hefty 
42167688f2c3SLeon Romanovsky 	if (!id->device)
42177688f2c3SLeon Romanovsky 		return -EINVAL;
42187688f2c3SLeon Romanovsky 
4219c8f6a362SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
4220550e5ca7SNir Muchtar 	if (!cma_comp(id_priv, RDMA_CM_ADDR_BOUND) &&
4221550e5ca7SNir Muchtar 	    !cma_comp(id_priv, RDMA_CM_ADDR_RESOLVED))
4222c8f6a362SSean Hefty 		return -EINVAL;
4223c8f6a362SSean Hefty 
4224c8f6a362SSean Hefty 	mc = kmalloc(sizeof *mc, GFP_KERNEL);
4225c8f6a362SSean Hefty 	if (!mc)
4226c8f6a362SSean Hefty 		return -ENOMEM;
4227c8f6a362SSean Hefty 
4228ef560861SSean Hefty 	memcpy(&mc->addr, addr, rdma_addr_size(addr));
4229c8f6a362SSean Hefty 	mc->context = context;
4230c8f6a362SSean Hefty 	mc->id_priv = id_priv;
4231bee3c3c9SMoni Shoua 	mc->igmp_joined = false;
4232ab15c95aSAlex Vesker 	mc->join_state = join_state;
4233c8f6a362SSean Hefty 	spin_lock(&id_priv->lock);
4234c8f6a362SSean Hefty 	list_add(&mc->list, &id_priv->mc_list);
4235c8f6a362SSean Hefty 	spin_unlock(&id_priv->lock);
4236c8f6a362SSean Hefty 
42375d9fb044SIra Weiny 	if (rdma_protocol_roce(id->device, id->port_num)) {
42383c86aa70SEli Cohen 		kref_init(&mc->mcref);
42393c86aa70SEli Cohen 		ret = cma_iboe_join_multicast(id_priv, mc);
4240a31ad3b0SMichael Wang 	} else if (rdma_cap_ib_mcast(id->device, id->port_num))
42415c9a5282SMichael Wang 		ret = cma_join_ib_multicast(id_priv, mc);
42425c9a5282SMichael Wang 	else
4243c8f6a362SSean Hefty 		ret = -ENOSYS;
4244c8f6a362SSean Hefty 
4245c8f6a362SSean Hefty 	if (ret) {
4246c8f6a362SSean Hefty 		spin_lock_irq(&id_priv->lock);
4247c8f6a362SSean Hefty 		list_del(&mc->list);
4248c8f6a362SSean Hefty 		spin_unlock_irq(&id_priv->lock);
4249c8f6a362SSean Hefty 		kfree(mc);
4250c8f6a362SSean Hefty 	}
4251c8f6a362SSean Hefty 	return ret;
4252c8f6a362SSean Hefty }
4253c8f6a362SSean Hefty EXPORT_SYMBOL(rdma_join_multicast);
4254c8f6a362SSean Hefty 
4255c8f6a362SSean Hefty void rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr)
4256c8f6a362SSean Hefty {
4257c8f6a362SSean Hefty 	struct rdma_id_private *id_priv;
4258c8f6a362SSean Hefty 	struct cma_multicast *mc;
4259c8f6a362SSean Hefty 
4260c8f6a362SSean Hefty 	id_priv = container_of(id, struct rdma_id_private, id);
4261c8f6a362SSean Hefty 	spin_lock_irq(&id_priv->lock);
4262c8f6a362SSean Hefty 	list_for_each_entry(mc, &id_priv->mc_list, list) {
4263ef560861SSean Hefty 		if (!memcmp(&mc->addr, addr, rdma_addr_size(addr))) {
4264c8f6a362SSean Hefty 			list_del(&mc->list);
4265c8f6a362SSean Hefty 			spin_unlock_irq(&id_priv->lock);
4266c8f6a362SSean Hefty 
4267c8f6a362SSean Hefty 			if (id->qp)
4268c8f6a362SSean Hefty 				ib_detach_mcast(id->qp,
4269c8f6a362SSean Hefty 						&mc->multicast.ib->rec.mgid,
427046ea5061SSean Hefty 						be16_to_cpu(mc->multicast.ib->rec.mlid));
42715c9a5282SMichael Wang 
42725c9a5282SMichael Wang 			BUG_ON(id_priv->cma_dev->device != id->device);
42735c9a5282SMichael Wang 
4274a31ad3b0SMichael Wang 			if (rdma_cap_ib_mcast(id->device, id->port_num)) {
4275c8f6a362SSean Hefty 				ib_sa_free_multicast(mc->multicast.ib);
4276c8f6a362SSean Hefty 				kfree(mc);
4277bee3c3c9SMoni Shoua 			} else if (rdma_protocol_roce(id->device, id->port_num)) {
4278*88145678SParav Pandit 				cma_leave_roce_mc_group(id_priv, mc);
4279bee3c3c9SMoni Shoua 			}
4280c8f6a362SSean Hefty 			return;
4281c8f6a362SSean Hefty 		}
4282c8f6a362SSean Hefty 	}
4283c8f6a362SSean Hefty 	spin_unlock_irq(&id_priv->lock);
4284c8f6a362SSean Hefty }
4285c8f6a362SSean Hefty EXPORT_SYMBOL(rdma_leave_multicast);
4286c8f6a362SSean Hefty 
4287dd5bdff8SOr Gerlitz static int cma_netdev_change(struct net_device *ndev, struct rdma_id_private *id_priv)
4288dd5bdff8SOr Gerlitz {
4289dd5bdff8SOr Gerlitz 	struct rdma_dev_addr *dev_addr;
4290dd5bdff8SOr Gerlitz 	struct cma_ndev_work *work;
4291dd5bdff8SOr Gerlitz 
4292dd5bdff8SOr Gerlitz 	dev_addr = &id_priv->id.route.addr.dev_addr;
4293dd5bdff8SOr Gerlitz 
42946266ed6eSSean Hefty 	if ((dev_addr->bound_dev_if == ndev->ifindex) &&
4295fa20105eSGuy Shapiro 	    (net_eq(dev_net(ndev), dev_addr->net)) &&
4296dd5bdff8SOr Gerlitz 	    memcmp(dev_addr->src_dev_addr, ndev->dev_addr, ndev->addr_len)) {
4297aba25a3eSParav Pandit 		pr_info("RDMA CM addr change for ndev %s used by id %p\n",
4298dd5bdff8SOr Gerlitz 			ndev->name, &id_priv->id);
4299dd5bdff8SOr Gerlitz 		work = kzalloc(sizeof *work, GFP_KERNEL);
4300dd5bdff8SOr Gerlitz 		if (!work)
4301dd5bdff8SOr Gerlitz 			return -ENOMEM;
4302dd5bdff8SOr Gerlitz 
4303dd5bdff8SOr Gerlitz 		INIT_WORK(&work->work, cma_ndev_work_handler);
4304dd5bdff8SOr Gerlitz 		work->id = id_priv;
4305dd5bdff8SOr Gerlitz 		work->event.event = RDMA_CM_EVENT_ADDR_CHANGE;
4306dd5bdff8SOr Gerlitz 		atomic_inc(&id_priv->refcount);
4307dd5bdff8SOr Gerlitz 		queue_work(cma_wq, &work->work);
4308dd5bdff8SOr Gerlitz 	}
4309dd5bdff8SOr Gerlitz 
4310dd5bdff8SOr Gerlitz 	return 0;
4311dd5bdff8SOr Gerlitz }
4312dd5bdff8SOr Gerlitz 
4313dd5bdff8SOr Gerlitz static int cma_netdev_callback(struct notifier_block *self, unsigned long event,
4314351638e7SJiri Pirko 			       void *ptr)
4315dd5bdff8SOr Gerlitz {
4316351638e7SJiri Pirko 	struct net_device *ndev = netdev_notifier_info_to_dev(ptr);
4317dd5bdff8SOr Gerlitz 	struct cma_device *cma_dev;
4318dd5bdff8SOr Gerlitz 	struct rdma_id_private *id_priv;
4319dd5bdff8SOr Gerlitz 	int ret = NOTIFY_DONE;
4320dd5bdff8SOr Gerlitz 
4321dd5bdff8SOr Gerlitz 	if (event != NETDEV_BONDING_FAILOVER)
4322dd5bdff8SOr Gerlitz 		return NOTIFY_DONE;
4323dd5bdff8SOr Gerlitz 
43243cd96fddSParav Pandit 	if (!netif_is_bond_master(ndev))
4325dd5bdff8SOr Gerlitz 		return NOTIFY_DONE;
4326dd5bdff8SOr Gerlitz 
4327dd5bdff8SOr Gerlitz 	mutex_lock(&lock);
4328dd5bdff8SOr Gerlitz 	list_for_each_entry(cma_dev, &dev_list, list)
4329dd5bdff8SOr Gerlitz 		list_for_each_entry(id_priv, &cma_dev->id_list, list) {
4330dd5bdff8SOr Gerlitz 			ret = cma_netdev_change(ndev, id_priv);
4331dd5bdff8SOr Gerlitz 			if (ret)
4332dd5bdff8SOr Gerlitz 				goto out;
4333dd5bdff8SOr Gerlitz 		}
4334dd5bdff8SOr Gerlitz 
4335dd5bdff8SOr Gerlitz out:
4336dd5bdff8SOr Gerlitz 	mutex_unlock(&lock);
4337dd5bdff8SOr Gerlitz 	return ret;
4338dd5bdff8SOr Gerlitz }
4339dd5bdff8SOr Gerlitz 
4340dd5bdff8SOr Gerlitz static struct notifier_block cma_nb = {
4341dd5bdff8SOr Gerlitz 	.notifier_call = cma_netdev_callback
4342dd5bdff8SOr Gerlitz };
4343dd5bdff8SOr Gerlitz 
4344e51060f0SSean Hefty static void cma_add_one(struct ib_device *device)
4345e51060f0SSean Hefty {
4346e51060f0SSean Hefty 	struct cma_device *cma_dev;
4347e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
4348045959dbSMatan Barak 	unsigned int i;
4349045959dbSMatan Barak 	unsigned long supported_gids = 0;
4350e51060f0SSean Hefty 
4351e51060f0SSean Hefty 	cma_dev = kmalloc(sizeof *cma_dev, GFP_KERNEL);
4352e51060f0SSean Hefty 	if (!cma_dev)
4353e51060f0SSean Hefty 		return;
4354e51060f0SSean Hefty 
4355e51060f0SSean Hefty 	cma_dev->device = device;
4356045959dbSMatan Barak 	cma_dev->default_gid_type = kcalloc(device->phys_port_cnt,
4357045959dbSMatan Barak 					    sizeof(*cma_dev->default_gid_type),
4358045959dbSMatan Barak 					    GFP_KERNEL);
435989052d78SMajd Dibbiny 	if (!cma_dev->default_gid_type)
436089052d78SMajd Dibbiny 		goto free_cma_dev;
436189052d78SMajd Dibbiny 
436289052d78SMajd Dibbiny 	cma_dev->default_roce_tos = kcalloc(device->phys_port_cnt,
436389052d78SMajd Dibbiny 					    sizeof(*cma_dev->default_roce_tos),
436489052d78SMajd Dibbiny 					    GFP_KERNEL);
436589052d78SMajd Dibbiny 	if (!cma_dev->default_roce_tos)
436689052d78SMajd Dibbiny 		goto free_gid_type;
436789052d78SMajd Dibbiny 
4368045959dbSMatan Barak 	for (i = rdma_start_port(device); i <= rdma_end_port(device); i++) {
4369045959dbSMatan Barak 		supported_gids = roce_gid_type_mask_support(device, i);
4370045959dbSMatan Barak 		WARN_ON(!supported_gids);
43715ab2d89bSLeon Romanovsky 		if (supported_gids & (1 << CMA_PREFERRED_ROCE_GID_TYPE))
437263a5f483SMoni Shoua 			cma_dev->default_gid_type[i - rdma_start_port(device)] =
437363a5f483SMoni Shoua 				CMA_PREFERRED_ROCE_GID_TYPE;
437463a5f483SMoni Shoua 		else
4375045959dbSMatan Barak 			cma_dev->default_gid_type[i - rdma_start_port(device)] =
4376045959dbSMatan Barak 				find_first_bit(&supported_gids, BITS_PER_LONG);
437789052d78SMajd Dibbiny 		cma_dev->default_roce_tos[i - rdma_start_port(device)] = 0;
4378045959dbSMatan Barak 	}
4379e51060f0SSean Hefty 
4380e51060f0SSean Hefty 	init_completion(&cma_dev->comp);
4381e51060f0SSean Hefty 	atomic_set(&cma_dev->refcount, 1);
4382e51060f0SSean Hefty 	INIT_LIST_HEAD(&cma_dev->id_list);
4383e51060f0SSean Hefty 	ib_set_client_data(device, &cma_client, cma_dev);
4384e51060f0SSean Hefty 
4385e51060f0SSean Hefty 	mutex_lock(&lock);
4386e51060f0SSean Hefty 	list_add_tail(&cma_dev->list, &dev_list);
4387e51060f0SSean Hefty 	list_for_each_entry(id_priv, &listen_any_list, list)
4388e51060f0SSean Hefty 		cma_listen_on_dev(id_priv, cma_dev);
4389e51060f0SSean Hefty 	mutex_unlock(&lock);
439089052d78SMajd Dibbiny 
439189052d78SMajd Dibbiny 	return;
439289052d78SMajd Dibbiny 
439389052d78SMajd Dibbiny free_gid_type:
439489052d78SMajd Dibbiny 	kfree(cma_dev->default_gid_type);
439589052d78SMajd Dibbiny 
439689052d78SMajd Dibbiny free_cma_dev:
439789052d78SMajd Dibbiny 	kfree(cma_dev);
439889052d78SMajd Dibbiny 
439989052d78SMajd Dibbiny 	return;
4400e51060f0SSean Hefty }
4401e51060f0SSean Hefty 
4402e51060f0SSean Hefty static int cma_remove_id_dev(struct rdma_id_private *id_priv)
4403e51060f0SSean Hefty {
4404a1b1b61fSSean Hefty 	struct rdma_cm_event event;
4405550e5ca7SNir Muchtar 	enum rdma_cm_state state;
4406de910bd9SOr Gerlitz 	int ret = 0;
4407e51060f0SSean Hefty 
4408e51060f0SSean Hefty 	/* Record that we want to remove the device */
4409550e5ca7SNir Muchtar 	state = cma_exch(id_priv, RDMA_CM_DEVICE_REMOVAL);
4410550e5ca7SNir Muchtar 	if (state == RDMA_CM_DESTROYING)
4411e51060f0SSean Hefty 		return 0;
4412e51060f0SSean Hefty 
4413e51060f0SSean Hefty 	cma_cancel_operation(id_priv, state);
4414de910bd9SOr Gerlitz 	mutex_lock(&id_priv->handler_mutex);
4415e51060f0SSean Hefty 
4416e51060f0SSean Hefty 	/* Check for destruction from another callback. */
4417550e5ca7SNir Muchtar 	if (!cma_comp(id_priv, RDMA_CM_DEVICE_REMOVAL))
4418de910bd9SOr Gerlitz 		goto out;
4419e51060f0SSean Hefty 
4420a1b1b61fSSean Hefty 	memset(&event, 0, sizeof event);
4421a1b1b61fSSean Hefty 	event.event = RDMA_CM_EVENT_DEVICE_REMOVAL;
4422de910bd9SOr Gerlitz 	ret = id_priv->id.event_handler(&id_priv->id, &event);
4423de910bd9SOr Gerlitz out:
4424de910bd9SOr Gerlitz 	mutex_unlock(&id_priv->handler_mutex);
4425de910bd9SOr Gerlitz 	return ret;
4426e51060f0SSean Hefty }
4427e51060f0SSean Hefty 
4428e51060f0SSean Hefty static void cma_process_remove(struct cma_device *cma_dev)
4429e51060f0SSean Hefty {
4430e51060f0SSean Hefty 	struct rdma_id_private *id_priv;
4431e51060f0SSean Hefty 	int ret;
4432e51060f0SSean Hefty 
4433e51060f0SSean Hefty 	mutex_lock(&lock);
4434e51060f0SSean Hefty 	while (!list_empty(&cma_dev->id_list)) {
4435e51060f0SSean Hefty 		id_priv = list_entry(cma_dev->id_list.next,
4436e51060f0SSean Hefty 				     struct rdma_id_private, list);
4437e51060f0SSean Hefty 
4438d02d1f53SSean Hefty 		list_del(&id_priv->listen_list);
443994de178aSKrishna Kumar 		list_del_init(&id_priv->list);
4440e51060f0SSean Hefty 		atomic_inc(&id_priv->refcount);
4441e51060f0SSean Hefty 		mutex_unlock(&lock);
4442e51060f0SSean Hefty 
4443d02d1f53SSean Hefty 		ret = id_priv->internal_id ? 1 : cma_remove_id_dev(id_priv);
4444e51060f0SSean Hefty 		cma_deref_id(id_priv);
4445e51060f0SSean Hefty 		if (ret)
4446e51060f0SSean Hefty 			rdma_destroy_id(&id_priv->id);
4447e51060f0SSean Hefty 
4448e51060f0SSean Hefty 		mutex_lock(&lock);
4449e51060f0SSean Hefty 	}
4450e51060f0SSean Hefty 	mutex_unlock(&lock);
4451e51060f0SSean Hefty 
4452e51060f0SSean Hefty 	cma_deref_dev(cma_dev);
4453e51060f0SSean Hefty 	wait_for_completion(&cma_dev->comp);
4454e51060f0SSean Hefty }
4455e51060f0SSean Hefty 
44567c1eb45aSHaggai Eran static void cma_remove_one(struct ib_device *device, void *client_data)
4457e51060f0SSean Hefty {
44587c1eb45aSHaggai Eran 	struct cma_device *cma_dev = client_data;
4459e51060f0SSean Hefty 
4460e51060f0SSean Hefty 	if (!cma_dev)
4461e51060f0SSean Hefty 		return;
4462e51060f0SSean Hefty 
4463e51060f0SSean Hefty 	mutex_lock(&lock);
4464e51060f0SSean Hefty 	list_del(&cma_dev->list);
4465e51060f0SSean Hefty 	mutex_unlock(&lock);
4466e51060f0SSean Hefty 
4467e51060f0SSean Hefty 	cma_process_remove(cma_dev);
446889052d78SMajd Dibbiny 	kfree(cma_dev->default_roce_tos);
4469045959dbSMatan Barak 	kfree(cma_dev->default_gid_type);
4470e51060f0SSean Hefty 	kfree(cma_dev);
4471e51060f0SSean Hefty }
4472e51060f0SSean Hefty 
4473753f618aSNir Muchtar static int cma_get_id_stats(struct sk_buff *skb, struct netlink_callback *cb)
4474753f618aSNir Muchtar {
4475753f618aSNir Muchtar 	struct nlmsghdr *nlh;
4476753f618aSNir Muchtar 	struct rdma_cm_id_stats *id_stats;
4477753f618aSNir Muchtar 	struct rdma_id_private *id_priv;
4478753f618aSNir Muchtar 	struct rdma_cm_id *id = NULL;
4479753f618aSNir Muchtar 	struct cma_device *cma_dev;
4480753f618aSNir Muchtar 	int i_dev = 0, i_id = 0;
4481753f618aSNir Muchtar 
4482753f618aSNir Muchtar 	/*
4483753f618aSNir Muchtar 	 * We export all of the IDs as a sequence of messages.  Each
4484753f618aSNir Muchtar 	 * ID gets its own netlink message.
4485753f618aSNir Muchtar 	 */
4486753f618aSNir Muchtar 	mutex_lock(&lock);
4487753f618aSNir Muchtar 
4488753f618aSNir Muchtar 	list_for_each_entry(cma_dev, &dev_list, list) {
4489753f618aSNir Muchtar 		if (i_dev < cb->args[0]) {
4490753f618aSNir Muchtar 			i_dev++;
4491753f618aSNir Muchtar 			continue;
4492753f618aSNir Muchtar 		}
4493753f618aSNir Muchtar 
4494753f618aSNir Muchtar 		i_id = 0;
4495753f618aSNir Muchtar 		list_for_each_entry(id_priv, &cma_dev->id_list, list) {
4496753f618aSNir Muchtar 			if (i_id < cb->args[1]) {
4497753f618aSNir Muchtar 				i_id++;
4498753f618aSNir Muchtar 				continue;
4499753f618aSNir Muchtar 			}
4500753f618aSNir Muchtar 
4501753f618aSNir Muchtar 			id_stats = ibnl_put_msg(skb, &nlh, cb->nlh->nlmsg_seq,
4502753f618aSNir Muchtar 						sizeof *id_stats, RDMA_NL_RDMA_CM,
450330dc5e63STatyana Nikolova 						RDMA_NL_RDMA_CM_ID_STATS,
450430dc5e63STatyana Nikolova 						NLM_F_MULTI);
4505753f618aSNir Muchtar 			if (!id_stats)
4506753f618aSNir Muchtar 				goto out;
4507753f618aSNir Muchtar 
4508753f618aSNir Muchtar 			memset(id_stats, 0, sizeof *id_stats);
4509753f618aSNir Muchtar 			id = &id_priv->id;
4510753f618aSNir Muchtar 			id_stats->node_type = id->route.addr.dev_addr.dev_type;
4511753f618aSNir Muchtar 			id_stats->port_num = id->port_num;
4512753f618aSNir Muchtar 			id_stats->bound_dev_if =
4513753f618aSNir Muchtar 				id->route.addr.dev_addr.bound_dev_if;
4514753f618aSNir Muchtar 
4515753f618aSNir Muchtar 			if (ibnl_put_attr(skb, nlh,
4516ce117ffaSSean Hefty 					  rdma_addr_size(cma_src_addr(id_priv)),
4517f4753834SSean Hefty 					  cma_src_addr(id_priv),
4518ce117ffaSSean Hefty 					  RDMA_NL_RDMA_CM_ATTR_SRC_ADDR))
4519753f618aSNir Muchtar 				goto out;
4520753f618aSNir Muchtar 			if (ibnl_put_attr(skb, nlh,
45217baaa49aSParav Pandit 					  rdma_addr_size(cma_dst_addr(id_priv)),
4522f4753834SSean Hefty 					  cma_dst_addr(id_priv),
4523ce117ffaSSean Hefty 					  RDMA_NL_RDMA_CM_ATTR_DST_ADDR))
4524753f618aSNir Muchtar 				goto out;
4525753f618aSNir Muchtar 
452600313983SSteve Wise 			id_stats->pid	= task_pid_vnr(id_priv->res.task);
4527753f618aSNir Muchtar 			id_stats->port_space	= id->ps;
4528753f618aSNir Muchtar 			id_stats->cm_state	= id_priv->state;
4529753f618aSNir Muchtar 			id_stats->qp_num	= id_priv->qp_num;
4530753f618aSNir Muchtar 			id_stats->qp_type	= id->qp_type;
4531753f618aSNir Muchtar 
4532753f618aSNir Muchtar 			i_id++;
4533e48e5e19SLeon Romanovsky 			nlmsg_end(skb, nlh);
4534753f618aSNir Muchtar 		}
4535753f618aSNir Muchtar 
4536753f618aSNir Muchtar 		cb->args[1] = 0;
4537753f618aSNir Muchtar 		i_dev++;
4538753f618aSNir Muchtar 	}
4539753f618aSNir Muchtar 
4540753f618aSNir Muchtar out:
4541753f618aSNir Muchtar 	mutex_unlock(&lock);
4542753f618aSNir Muchtar 	cb->args[0] = i_dev;
4543753f618aSNir Muchtar 	cb->args[1] = i_id;
4544753f618aSNir Muchtar 
4545753f618aSNir Muchtar 	return skb->len;
4546753f618aSNir Muchtar }
4547753f618aSNir Muchtar 
4548d0e312feSLeon Romanovsky static const struct rdma_nl_cbs cma_cb_table[RDMA_NL_RDMA_CM_NUM_OPS] = {
454964401b69SLeon Romanovsky 	[RDMA_NL_RDMA_CM_ID_STATS] = { .dump = cma_get_id_stats},
4550753f618aSNir Muchtar };
4551753f618aSNir Muchtar 
45524be74b42SHaggai Eran static int cma_init_net(struct net *net)
45534be74b42SHaggai Eran {
45544be74b42SHaggai Eran 	struct cma_pernet *pernet = cma_pernet(net);
45554be74b42SHaggai Eran 
45564be74b42SHaggai Eran 	idr_init(&pernet->tcp_ps);
45574be74b42SHaggai Eran 	idr_init(&pernet->udp_ps);
45584be74b42SHaggai Eran 	idr_init(&pernet->ipoib_ps);
45594be74b42SHaggai Eran 	idr_init(&pernet->ib_ps);
45604be74b42SHaggai Eran 
45614be74b42SHaggai Eran 	return 0;
45624be74b42SHaggai Eran }
45634be74b42SHaggai Eran 
45644be74b42SHaggai Eran static void cma_exit_net(struct net *net)
45654be74b42SHaggai Eran {
45664be74b42SHaggai Eran 	struct cma_pernet *pernet = cma_pernet(net);
45674be74b42SHaggai Eran 
45684be74b42SHaggai Eran 	idr_destroy(&pernet->tcp_ps);
45694be74b42SHaggai Eran 	idr_destroy(&pernet->udp_ps);
45704be74b42SHaggai Eran 	idr_destroy(&pernet->ipoib_ps);
45714be74b42SHaggai Eran 	idr_destroy(&pernet->ib_ps);
45724be74b42SHaggai Eran }
45734be74b42SHaggai Eran 
45744be74b42SHaggai Eran static struct pernet_operations cma_pernet_operations = {
45754be74b42SHaggai Eran 	.init = cma_init_net,
45764be74b42SHaggai Eran 	.exit = cma_exit_net,
45774be74b42SHaggai Eran 	.id = &cma_pernet_id,
45784be74b42SHaggai Eran 	.size = sizeof(struct cma_pernet),
45794be74b42SHaggai Eran };
45804be74b42SHaggai Eran 
4581716abb1fSPeter Huewe static int __init cma_init(void)
4582e51060f0SSean Hefty {
45835d7220e8STetsuo Handa 	int ret;
4584227b60f5SStephen Hemminger 
4585dee9acbbSBhaktipriya Shridhar 	cma_wq = alloc_ordered_workqueue("rdma_cm", WQ_MEM_RECLAIM);
4586e51060f0SSean Hefty 	if (!cma_wq)
4587e51060f0SSean Hefty 		return -ENOMEM;
4588e51060f0SSean Hefty 
45894be74b42SHaggai Eran 	ret = register_pernet_subsys(&cma_pernet_operations);
45904be74b42SHaggai Eran 	if (ret)
45914be74b42SHaggai Eran 		goto err_wq;
45924be74b42SHaggai Eran 
4593c1a0b23bSMichael S. Tsirkin 	ib_sa_register_client(&sa_client);
4594dd5bdff8SOr Gerlitz 	register_netdevice_notifier(&cma_nb);
4595c1a0b23bSMichael S. Tsirkin 
4596e51060f0SSean Hefty 	ret = ib_register_client(&cma_client);
4597e51060f0SSean Hefty 	if (ret)
4598e51060f0SSean Hefty 		goto err;
4599753f618aSNir Muchtar 
4600c9901724SLeon Romanovsky 	rdma_nl_register(RDMA_NL_RDMA_CM, cma_cb_table);
4601045959dbSMatan Barak 	cma_configfs_init();
4602753f618aSNir Muchtar 
4603e51060f0SSean Hefty 	return 0;
4604e51060f0SSean Hefty 
4605e51060f0SSean Hefty err:
4606dd5bdff8SOr Gerlitz 	unregister_netdevice_notifier(&cma_nb);
4607c1a0b23bSMichael S. Tsirkin 	ib_sa_unregister_client(&sa_client);
46084be74b42SHaggai Eran err_wq:
4609e51060f0SSean Hefty 	destroy_workqueue(cma_wq);
4610e51060f0SSean Hefty 	return ret;
4611e51060f0SSean Hefty }
4612e51060f0SSean Hefty 
4613716abb1fSPeter Huewe static void __exit cma_cleanup(void)
4614e51060f0SSean Hefty {
4615045959dbSMatan Barak 	cma_configfs_exit();
4616c9901724SLeon Romanovsky 	rdma_nl_unregister(RDMA_NL_RDMA_CM);
4617e51060f0SSean Hefty 	ib_unregister_client(&cma_client);
4618dd5bdff8SOr Gerlitz 	unregister_netdevice_notifier(&cma_nb);
4619c1a0b23bSMichael S. Tsirkin 	ib_sa_unregister_client(&sa_client);
46204be74b42SHaggai Eran 	unregister_pernet_subsys(&cma_pernet_operations);
4621e51060f0SSean Hefty 	destroy_workqueue(cma_wq);
4622e51060f0SSean Hefty }
4623e51060f0SSean Hefty 
4624e3bf14bdSJason Gunthorpe MODULE_ALIAS_RDMA_NETLINK(RDMA_NL_RDMA_CM, 1);
4625e3bf14bdSJason Gunthorpe 
4626e51060f0SSean Hefty module_init(cma_init);
4627e51060f0SSean Hefty module_exit(cma_cleanup);
4628