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; 369ab15c95aSAlex Vesker u8 join_state; 370c8f6a362SSean Hefty }; 371c8f6a362SSean Hefty 372e51060f0SSean Hefty struct cma_work { 373e51060f0SSean Hefty struct work_struct work; 374e51060f0SSean Hefty struct rdma_id_private *id; 375550e5ca7SNir Muchtar enum rdma_cm_state old_state; 376550e5ca7SNir Muchtar enum rdma_cm_state new_state; 377e51060f0SSean Hefty struct rdma_cm_event event; 378e51060f0SSean Hefty }; 379e51060f0SSean Hefty 380dd5bdff8SOr Gerlitz struct cma_ndev_work { 381dd5bdff8SOr Gerlitz struct work_struct work; 382dd5bdff8SOr Gerlitz struct rdma_id_private *id; 383dd5bdff8SOr Gerlitz struct rdma_cm_event event; 384dd5bdff8SOr Gerlitz }; 385dd5bdff8SOr Gerlitz 3863c86aa70SEli Cohen struct iboe_mcast_work { 3873c86aa70SEli Cohen struct work_struct work; 3883c86aa70SEli Cohen struct rdma_id_private *id; 3893c86aa70SEli Cohen struct cma_multicast *mc; 3903c86aa70SEli Cohen }; 3913c86aa70SEli Cohen 392e51060f0SSean Hefty union cma_ip_addr { 393e51060f0SSean Hefty struct in6_addr ip6; 394e51060f0SSean Hefty struct { 3951b90c137SAl Viro __be32 pad[3]; 3961b90c137SAl Viro __be32 addr; 397e51060f0SSean Hefty } ip4; 398e51060f0SSean Hefty }; 399e51060f0SSean Hefty 400e51060f0SSean Hefty struct cma_hdr { 401e51060f0SSean Hefty u8 cma_version; 402e51060f0SSean Hefty u8 ip_version; /* IP version: 7:4 */ 4031b90c137SAl Viro __be16 port; 404e51060f0SSean Hefty union cma_ip_addr src_addr; 405e51060f0SSean Hefty union cma_ip_addr dst_addr; 406e51060f0SSean Hefty }; 407e51060f0SSean Hefty 408e51060f0SSean Hefty #define CMA_VERSION 0x00 409e51060f0SSean Hefty 4104c21b5bcSHaggai Eran struct cma_req_info { 4112918c1a9SParav Pandit struct sockaddr_storage listen_addr_storage; 4122918c1a9SParav Pandit struct sockaddr_storage src_addr_storage; 4134c21b5bcSHaggai Eran struct ib_device *device; 4144c21b5bcSHaggai Eran union ib_gid local_gid; 4154c21b5bcSHaggai Eran __be64 service_id; 41605e0b86cSParav Pandit int port; 41705e0b86cSParav Pandit bool has_gid; 4184c21b5bcSHaggai Eran u16 pkey; 4194c21b5bcSHaggai Eran }; 4204c21b5bcSHaggai Eran 421550e5ca7SNir Muchtar static int cma_comp(struct rdma_id_private *id_priv, enum rdma_cm_state comp) 422e51060f0SSean Hefty { 423e51060f0SSean Hefty unsigned long flags; 424e51060f0SSean Hefty int ret; 425e51060f0SSean Hefty 426e51060f0SSean Hefty spin_lock_irqsave(&id_priv->lock, flags); 427e51060f0SSean Hefty ret = (id_priv->state == comp); 428e51060f0SSean Hefty spin_unlock_irqrestore(&id_priv->lock, flags); 429e51060f0SSean Hefty return ret; 430e51060f0SSean Hefty } 431e51060f0SSean Hefty 432e51060f0SSean Hefty static int cma_comp_exch(struct rdma_id_private *id_priv, 433550e5ca7SNir Muchtar enum rdma_cm_state comp, enum rdma_cm_state exch) 434e51060f0SSean Hefty { 435e51060f0SSean Hefty unsigned long flags; 436e51060f0SSean Hefty int ret; 437e51060f0SSean Hefty 438e51060f0SSean Hefty spin_lock_irqsave(&id_priv->lock, flags); 439e51060f0SSean Hefty if ((ret = (id_priv->state == comp))) 440e51060f0SSean Hefty id_priv->state = exch; 441e51060f0SSean Hefty spin_unlock_irqrestore(&id_priv->lock, flags); 442e51060f0SSean Hefty return ret; 443e51060f0SSean Hefty } 444e51060f0SSean Hefty 445550e5ca7SNir Muchtar static enum rdma_cm_state cma_exch(struct rdma_id_private *id_priv, 446550e5ca7SNir Muchtar enum rdma_cm_state exch) 447e51060f0SSean Hefty { 448e51060f0SSean Hefty unsigned long flags; 449550e5ca7SNir Muchtar enum rdma_cm_state old; 450e51060f0SSean Hefty 451e51060f0SSean Hefty spin_lock_irqsave(&id_priv->lock, flags); 452e51060f0SSean Hefty old = id_priv->state; 453e51060f0SSean Hefty id_priv->state = exch; 454e51060f0SSean Hefty spin_unlock_irqrestore(&id_priv->lock, flags); 455e51060f0SSean Hefty return old; 456e51060f0SSean Hefty } 457e51060f0SSean Hefty 4584c21b5bcSHaggai Eran static inline u8 cma_get_ip_ver(const struct cma_hdr *hdr) 459e51060f0SSean Hefty { 460e51060f0SSean Hefty return hdr->ip_version >> 4; 461e51060f0SSean Hefty } 462e51060f0SSean Hefty 463e51060f0SSean Hefty static inline void cma_set_ip_ver(struct cma_hdr *hdr, u8 ip_ver) 464e51060f0SSean Hefty { 465e51060f0SSean Hefty hdr->ip_version = (ip_ver << 4) | (hdr->ip_version & 0xF); 466e51060f0SSean Hefty } 467e51060f0SSean Hefty 468bee3c3c9SMoni Shoua static int cma_igmp_send(struct net_device *ndev, union ib_gid *mgid, bool join) 469bee3c3c9SMoni Shoua { 470bee3c3c9SMoni Shoua struct in_device *in_dev = NULL; 471bee3c3c9SMoni Shoua 472bee3c3c9SMoni Shoua if (ndev) { 473bee3c3c9SMoni Shoua rtnl_lock(); 474bee3c3c9SMoni Shoua in_dev = __in_dev_get_rtnl(ndev); 475bee3c3c9SMoni Shoua if (in_dev) { 476bee3c3c9SMoni Shoua if (join) 477bee3c3c9SMoni Shoua ip_mc_inc_group(in_dev, 478bee3c3c9SMoni Shoua *(__be32 *)(mgid->raw + 12)); 479bee3c3c9SMoni Shoua else 480bee3c3c9SMoni Shoua ip_mc_dec_group(in_dev, 481bee3c3c9SMoni Shoua *(__be32 *)(mgid->raw + 12)); 482bee3c3c9SMoni Shoua } 483bee3c3c9SMoni Shoua rtnl_unlock(); 484bee3c3c9SMoni Shoua } 485bee3c3c9SMoni Shoua return (in_dev) ? 0 : -ENODEV; 486bee3c3c9SMoni Shoua } 487bee3c3c9SMoni Shoua 488045959dbSMatan Barak static void _cma_attach_to_dev(struct rdma_id_private *id_priv, 489e51060f0SSean Hefty struct cma_device *cma_dev) 490e51060f0SSean Hefty { 491218a773fSMatan Barak cma_ref_dev(cma_dev); 492e51060f0SSean Hefty id_priv->cma_dev = cma_dev; 493e51060f0SSean Hefty id_priv->id.device = cma_dev->device; 4943c86aa70SEli Cohen id_priv->id.route.addr.dev_addr.transport = 4953c86aa70SEli Cohen rdma_node_get_transport(cma_dev->device->node_type); 496e51060f0SSean Hefty list_add_tail(&id_priv->list, &cma_dev->id_list); 497917cb8a7SSteve Wise if (id_priv->res.kern_name) 498af8d7037SShamir Rabinovitch rdma_restrack_kadd(&id_priv->res); 499917cb8a7SSteve Wise else 500917cb8a7SSteve Wise rdma_restrack_uadd(&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 6064ed13a5fSParav Pandit static const struct ib_gid_attr * 6074ed13a5fSParav Pandit cma_validate_port(struct ib_device *device, u8 port, 608045959dbSMatan Barak enum ib_gid_type gid_type, 6092493a57bSParav Pandit union ib_gid *gid, 6102493a57bSParav Pandit struct rdma_id_private *id_priv) 6117c11147dSMichael Wang { 6122493a57bSParav Pandit struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 6132493a57bSParav Pandit int bound_if_index = dev_addr->bound_dev_if; 6144ed13a5fSParav Pandit const struct ib_gid_attr *sgid_attr; 6152493a57bSParav Pandit int dev_type = dev_addr->dev_type; 616abae1b71SMatan Barak struct net_device *ndev = NULL; 6177c11147dSMichael Wang 6187c11147dSMichael Wang if ((dev_type == ARPHRD_INFINIBAND) && !rdma_protocol_ib(device, port)) 6194ed13a5fSParav Pandit return ERR_PTR(-ENODEV); 6207c11147dSMichael Wang 6217c11147dSMichael Wang if ((dev_type != ARPHRD_INFINIBAND) && rdma_protocol_ib(device, port)) 6224ed13a5fSParav Pandit return ERR_PTR(-ENODEV); 6237c11147dSMichael Wang 62400db63c1SParav Pandit if (dev_type == ARPHRD_ETHER && rdma_protocol_roce(device, port)) { 62566c74d74SParav Pandit ndev = dev_get_by_index(dev_addr->net, bound_if_index); 62600db63c1SParav Pandit if (!ndev) 6274ed13a5fSParav Pandit return ERR_PTR(-ENODEV); 62800db63c1SParav Pandit } else { 629045959dbSMatan Barak gid_type = IB_GID_TYPE_IB; 63000db63c1SParav Pandit } 631abae1b71SMatan Barak 6324ed13a5fSParav Pandit sgid_attr = rdma_find_gid_by_port(device, gid, gid_type, port, ndev); 633abae1b71SMatan Barak if (ndev) 634abae1b71SMatan Barak dev_put(ndev); 6354ed13a5fSParav Pandit return sgid_attr; 6364ed13a5fSParav Pandit } 6377c11147dSMichael Wang 6384ed13a5fSParav Pandit static void cma_bind_sgid_attr(struct rdma_id_private *id_priv, 6394ed13a5fSParav Pandit const struct ib_gid_attr *sgid_attr) 6404ed13a5fSParav Pandit { 6414ed13a5fSParav Pandit WARN_ON(id_priv->id.route.addr.dev_addr.sgid_attr); 6424ed13a5fSParav Pandit id_priv->id.route.addr.dev_addr.sgid_attr = sgid_attr; 6437c11147dSMichael Wang } 6447c11147dSMichael Wang 645ff11c6cdSParav Pandit /** 646ff11c6cdSParav Pandit * cma_acquire_dev_by_src_ip - Acquire cma device, port, gid attribute 647ff11c6cdSParav Pandit * based on source ip address. 648ff11c6cdSParav Pandit * @id_priv: cm_id which should be bound to cma device 649ff11c6cdSParav Pandit * 650ff11c6cdSParav Pandit * cma_acquire_dev_by_src_ip() binds cm id to cma device, port and GID attribute 651ff11c6cdSParav Pandit * based on source IP address. It returns 0 on success or error code otherwise. 652ff11c6cdSParav Pandit * It is applicable to active and passive side cm_id. 653ff11c6cdSParav Pandit */ 654ff11c6cdSParav Pandit static int cma_acquire_dev_by_src_ip(struct rdma_id_private *id_priv) 655ff11c6cdSParav Pandit { 656ff11c6cdSParav Pandit struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 657ff11c6cdSParav Pandit const struct ib_gid_attr *sgid_attr; 658ff11c6cdSParav Pandit union ib_gid gid, iboe_gid, *gidp; 659ff11c6cdSParav Pandit struct cma_device *cma_dev; 660ff11c6cdSParav Pandit enum ib_gid_type gid_type; 661ff11c6cdSParav Pandit int ret = -ENODEV; 662ff11c6cdSParav Pandit u8 port; 663ff11c6cdSParav Pandit 664ff11c6cdSParav Pandit if (dev_addr->dev_type != ARPHRD_INFINIBAND && 665ff11c6cdSParav Pandit id_priv->id.ps == RDMA_PS_IPOIB) 666ff11c6cdSParav Pandit return -EINVAL; 667ff11c6cdSParav Pandit 668ff11c6cdSParav Pandit rdma_ip2gid((struct sockaddr *)&id_priv->id.route.addr.src_addr, 669ff11c6cdSParav Pandit &iboe_gid); 670ff11c6cdSParav Pandit 671ff11c6cdSParav Pandit memcpy(&gid, dev_addr->src_dev_addr + 672ff11c6cdSParav Pandit rdma_addr_gid_offset(dev_addr), sizeof(gid)); 673ff11c6cdSParav Pandit 674ff11c6cdSParav Pandit mutex_lock(&lock); 675ff11c6cdSParav Pandit list_for_each_entry(cma_dev, &dev_list, list) { 676ff11c6cdSParav Pandit for (port = rdma_start_port(cma_dev->device); 677ff11c6cdSParav Pandit port <= rdma_end_port(cma_dev->device); port++) { 678ff11c6cdSParav Pandit gidp = rdma_protocol_roce(cma_dev->device, port) ? 679ff11c6cdSParav Pandit &iboe_gid : &gid; 680ff11c6cdSParav Pandit gid_type = cma_dev->default_gid_type[port - 1]; 681ff11c6cdSParav Pandit sgid_attr = cma_validate_port(cma_dev->device, port, 682ff11c6cdSParav Pandit gid_type, gidp, id_priv); 683ff11c6cdSParav Pandit if (!IS_ERR(sgid_attr)) { 684ff11c6cdSParav Pandit id_priv->id.port_num = port; 685ff11c6cdSParav Pandit cma_bind_sgid_attr(id_priv, sgid_attr); 686ff11c6cdSParav Pandit cma_attach_to_dev(id_priv, cma_dev); 687ff11c6cdSParav Pandit ret = 0; 688ff11c6cdSParav Pandit goto out; 689ff11c6cdSParav Pandit } 690ff11c6cdSParav Pandit } 691ff11c6cdSParav Pandit } 692ff11c6cdSParav Pandit out: 693ff11c6cdSParav Pandit mutex_unlock(&lock); 694ff11c6cdSParav Pandit return ret; 695ff11c6cdSParav Pandit } 696ff11c6cdSParav Pandit 69741ab1cb7SParav Pandit /** 69841ab1cb7SParav Pandit * cma_ib_acquire_dev - Acquire cma device, port and SGID attribute 69941ab1cb7SParav Pandit * @id_priv: cm id to bind to cma device 70041ab1cb7SParav Pandit * @listen_id_priv: listener cm id to match against 70141ab1cb7SParav Pandit * @req: Pointer to req structure containaining incoming 70241ab1cb7SParav Pandit * request information 70341ab1cb7SParav Pandit * cma_ib_acquire_dev() acquires cma device, port and SGID attribute when 70441ab1cb7SParav Pandit * rdma device matches for listen_id and incoming request. It also verifies 70541ab1cb7SParav Pandit * that a GID table entry is present for the source address. 70641ab1cb7SParav Pandit * Returns 0 on success, or returns error code otherwise. 70741ab1cb7SParav Pandit */ 70841ab1cb7SParav Pandit static int cma_ib_acquire_dev(struct rdma_id_private *id_priv, 70941ab1cb7SParav Pandit const struct rdma_id_private *listen_id_priv, 71041ab1cb7SParav Pandit struct cma_req_info *req) 71141ab1cb7SParav Pandit { 71241ab1cb7SParav Pandit struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 71341ab1cb7SParav Pandit const struct ib_gid_attr *sgid_attr; 71441ab1cb7SParav Pandit enum ib_gid_type gid_type; 71541ab1cb7SParav Pandit union ib_gid gid; 71641ab1cb7SParav Pandit 71741ab1cb7SParav Pandit if (dev_addr->dev_type != ARPHRD_INFINIBAND && 71841ab1cb7SParav Pandit id_priv->id.ps == RDMA_PS_IPOIB) 71941ab1cb7SParav Pandit return -EINVAL; 72041ab1cb7SParav Pandit 72141ab1cb7SParav Pandit if (rdma_protocol_roce(req->device, req->port)) 72241ab1cb7SParav Pandit rdma_ip2gid((struct sockaddr *)&id_priv->id.route.addr.src_addr, 72341ab1cb7SParav Pandit &gid); 72441ab1cb7SParav Pandit else 72541ab1cb7SParav Pandit memcpy(&gid, dev_addr->src_dev_addr + 72641ab1cb7SParav Pandit rdma_addr_gid_offset(dev_addr), sizeof(gid)); 72741ab1cb7SParav Pandit 72841ab1cb7SParav Pandit gid_type = listen_id_priv->cma_dev->default_gid_type[req->port - 1]; 72941ab1cb7SParav Pandit sgid_attr = cma_validate_port(req->device, req->port, 73041ab1cb7SParav Pandit gid_type, &gid, id_priv); 73141ab1cb7SParav Pandit if (IS_ERR(sgid_attr)) 73241ab1cb7SParav Pandit return PTR_ERR(sgid_attr); 73341ab1cb7SParav Pandit 73441ab1cb7SParav Pandit id_priv->id.port_num = req->port; 73541ab1cb7SParav Pandit cma_bind_sgid_attr(id_priv, sgid_attr); 73641ab1cb7SParav Pandit /* Need to acquire lock to protect against reader 73741ab1cb7SParav Pandit * of cma_dev->id_list such as cma_netdev_callback() and 73841ab1cb7SParav Pandit * cma_process_remove(). 73941ab1cb7SParav Pandit */ 74041ab1cb7SParav Pandit mutex_lock(&lock); 74141ab1cb7SParav Pandit cma_attach_to_dev(id_priv, listen_id_priv->cma_dev); 74241ab1cb7SParav Pandit mutex_unlock(&lock); 74341ab1cb7SParav Pandit return 0; 74441ab1cb7SParav Pandit } 74541ab1cb7SParav Pandit 74641ab1cb7SParav Pandit static int cma_iw_acquire_dev(struct rdma_id_private *id_priv, 747e7ff98aeSParav Pandit const struct rdma_id_private *listen_id_priv) 748e51060f0SSean Hefty { 749c8f6a362SSean Hefty struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 7504ed13a5fSParav Pandit const struct ib_gid_attr *sgid_attr; 751e51060f0SSean Hefty struct cma_device *cma_dev; 7524ed13a5fSParav Pandit enum ib_gid_type gid_type; 753e51060f0SSean Hefty int ret = -ENODEV; 75441ab1cb7SParav Pandit union ib_gid gid; 7557c11147dSMichael Wang u8 port; 756e51060f0SSean Hefty 7577c11147dSMichael Wang if (dev_addr->dev_type != ARPHRD_INFINIBAND && 7582efdd6a0SMoni Shoua id_priv->id.ps == RDMA_PS_IPOIB) 7592efdd6a0SMoni Shoua return -EINVAL; 7602efdd6a0SMoni Shoua 7613c86aa70SEli Cohen memcpy(&gid, dev_addr->src_dev_addr + 76241ab1cb7SParav Pandit rdma_addr_gid_offset(dev_addr), sizeof(gid)); 76341ab1cb7SParav Pandit 76441ab1cb7SParav Pandit mutex_lock(&lock); 7657c11147dSMichael Wang 766be9130ccSDoug Ledford cma_dev = listen_id_priv->cma_dev; 767be9130ccSDoug Ledford port = listen_id_priv->id.port_num; 76879d684f0SParav Pandit gid_type = listen_id_priv->gid_type; 7694ed13a5fSParav Pandit sgid_attr = cma_validate_port(cma_dev->device, port, 77041ab1cb7SParav Pandit gid_type, &gid, id_priv); 7714ed13a5fSParav Pandit if (!IS_ERR(sgid_attr)) { 7727c11147dSMichael Wang id_priv->id.port_num = port; 7734ed13a5fSParav Pandit cma_bind_sgid_attr(id_priv, sgid_attr); 7744ed13a5fSParav Pandit ret = 0; 775be9130ccSDoug Ledford goto out; 776be9130ccSDoug Ledford } 7777c11147dSMichael Wang 778e51060f0SSean Hefty list_for_each_entry(cma_dev, &dev_list, list) { 7793c86aa70SEli Cohen for (port = 1; port <= cma_dev->device->phys_port_cnt; ++port) { 780ff11c6cdSParav Pandit if (listen_id_priv->cma_dev == cma_dev && 781be9130ccSDoug Ledford listen_id_priv->id.port_num == port) 782be9130ccSDoug Ledford continue; 7833c86aa70SEli Cohen 78479d684f0SParav Pandit gid_type = cma_dev->default_gid_type[port - 1]; 7854ed13a5fSParav Pandit sgid_attr = cma_validate_port(cma_dev->device, port, 78641ab1cb7SParav Pandit gid_type, &gid, id_priv); 7874ed13a5fSParav Pandit if (!IS_ERR(sgid_attr)) { 7887c11147dSMichael Wang id_priv->id.port_num = port; 7894ed13a5fSParav Pandit cma_bind_sgid_attr(id_priv, sgid_attr); 7904ed13a5fSParav Pandit ret = 0; 7913c86aa70SEli Cohen goto out; 79263f05be2Sshefty } 793e51060f0SSean Hefty } 794e51060f0SSean Hefty } 7953c86aa70SEli Cohen 7963c86aa70SEli Cohen out: 7973c86aa70SEli Cohen if (!ret) 7983c86aa70SEli Cohen cma_attach_to_dev(id_priv, cma_dev); 7993c86aa70SEli Cohen 800a396d43aSSean Hefty mutex_unlock(&lock); 801e51060f0SSean Hefty return ret; 802e51060f0SSean Hefty } 803e51060f0SSean Hefty 804f17df3b0SSean Hefty /* 805f17df3b0SSean Hefty * Select the source IB device and address to reach the destination IB address. 806f17df3b0SSean Hefty */ 807f17df3b0SSean Hefty static int cma_resolve_ib_dev(struct rdma_id_private *id_priv) 808f17df3b0SSean Hefty { 809f17df3b0SSean Hefty struct cma_device *cma_dev, *cur_dev; 810f17df3b0SSean Hefty struct sockaddr_ib *addr; 811f17df3b0SSean Hefty union ib_gid gid, sgid, *dgid; 812f17df3b0SSean Hefty u16 pkey, index; 8138fb488d7SPaul Bolle u8 p; 81493b1f29dSJack Wang enum ib_port_state port_state; 815f17df3b0SSean Hefty int i; 816f17df3b0SSean Hefty 817f17df3b0SSean Hefty cma_dev = NULL; 818f17df3b0SSean Hefty addr = (struct sockaddr_ib *) cma_dst_addr(id_priv); 819f17df3b0SSean Hefty dgid = (union ib_gid *) &addr->sib_addr; 820f17df3b0SSean Hefty pkey = ntohs(addr->sib_pkey); 821f17df3b0SSean Hefty 822954a8e3aSParav Pandit mutex_lock(&lock); 823f17df3b0SSean Hefty list_for_each_entry(cur_dev, &dev_list, list) { 824fef60902SMichael Wang for (p = 1; p <= cur_dev->device->phys_port_cnt; ++p) { 82530a74ef4SMichael Wang if (!rdma_cap_af_ib(cur_dev->device, p)) 826f17df3b0SSean Hefty continue; 827f17df3b0SSean Hefty 828f17df3b0SSean Hefty if (ib_find_cached_pkey(cur_dev->device, p, pkey, &index)) 829f17df3b0SSean Hefty continue; 830f17df3b0SSean Hefty 83193b1f29dSJack Wang if (ib_get_cached_port_state(cur_dev->device, p, &port_state)) 83293b1f29dSJack Wang continue; 8331dfce294SParav Pandit for (i = 0; !rdma_query_gid(cur_dev->device, 8341dfce294SParav Pandit p, i, &gid); 83555ee3ab2SMatan Barak i++) { 836f17df3b0SSean Hefty if (!memcmp(&gid, dgid, sizeof(gid))) { 837f17df3b0SSean Hefty cma_dev = cur_dev; 838f17df3b0SSean Hefty sgid = gid; 8398fb488d7SPaul Bolle id_priv->id.port_num = p; 840f17df3b0SSean Hefty goto found; 841f17df3b0SSean Hefty } 842f17df3b0SSean Hefty 843f17df3b0SSean Hefty if (!cma_dev && (gid.global.subnet_prefix == 84493b1f29dSJack Wang dgid->global.subnet_prefix) && 84593b1f29dSJack Wang port_state == IB_PORT_ACTIVE) { 846f17df3b0SSean Hefty cma_dev = cur_dev; 847f17df3b0SSean Hefty sgid = gid; 8488fb488d7SPaul Bolle id_priv->id.port_num = p; 849954a8e3aSParav Pandit goto found; 850f17df3b0SSean Hefty } 851f17df3b0SSean Hefty } 852f17df3b0SSean Hefty } 853f17df3b0SSean Hefty } 854954a8e3aSParav Pandit mutex_unlock(&lock); 855f17df3b0SSean Hefty return -ENODEV; 856f17df3b0SSean Hefty 857f17df3b0SSean Hefty found: 858f17df3b0SSean Hefty cma_attach_to_dev(id_priv, cma_dev); 859954a8e3aSParav Pandit mutex_unlock(&lock); 860f17df3b0SSean Hefty addr = (struct sockaddr_ib *)cma_src_addr(id_priv); 861954a8e3aSParav Pandit memcpy(&addr->sib_addr, &sgid, sizeof(sgid)); 862f17df3b0SSean Hefty cma_translate_ib(addr, &id_priv->id.route.addr.dev_addr); 863f17df3b0SSean Hefty return 0; 864f17df3b0SSean Hefty } 865f17df3b0SSean Hefty 866e51060f0SSean Hefty static void cma_deref_id(struct rdma_id_private *id_priv) 867e51060f0SSean Hefty { 868e51060f0SSean Hefty if (atomic_dec_and_test(&id_priv->refcount)) 869e51060f0SSean Hefty complete(&id_priv->comp); 870e51060f0SSean Hefty } 871e51060f0SSean Hefty 87200313983SSteve Wise struct rdma_cm_id *__rdma_create_id(struct net *net, 873fa20105eSGuy Shapiro rdma_cm_event_handler event_handler, 8742253fc0cSSteve Wise void *context, enum rdma_ucm_port_space ps, 87500313983SSteve Wise enum ib_qp_type qp_type, const char *caller) 876e51060f0SSean Hefty { 877e51060f0SSean Hefty struct rdma_id_private *id_priv; 878e51060f0SSean Hefty 879e51060f0SSean Hefty id_priv = kzalloc(sizeof *id_priv, GFP_KERNEL); 880e51060f0SSean Hefty if (!id_priv) 881e51060f0SSean Hefty return ERR_PTR(-ENOMEM); 882e51060f0SSean Hefty 8832165fc26SLeon Romanovsky rdma_restrack_set_task(&id_priv->res, caller); 884e11fef9fSParav Pandit id_priv->res.type = RDMA_RESTRACK_CM_ID; 885550e5ca7SNir Muchtar id_priv->state = RDMA_CM_IDLE; 886e51060f0SSean Hefty id_priv->id.context = context; 887e51060f0SSean Hefty id_priv->id.event_handler = event_handler; 888e51060f0SSean Hefty id_priv->id.ps = ps; 889b26f9b99SSean Hefty id_priv->id.qp_type = qp_type; 89089052d78SMajd Dibbiny id_priv->tos_set = false; 891*2c1619edSDanit Goldberg id_priv->timeout_set = false; 89279d684f0SParav Pandit id_priv->gid_type = IB_GID_TYPE_IB; 893e51060f0SSean Hefty spin_lock_init(&id_priv->lock); 894c5483388SSean Hefty mutex_init(&id_priv->qp_mutex); 895e51060f0SSean Hefty init_completion(&id_priv->comp); 896e51060f0SSean Hefty atomic_set(&id_priv->refcount, 1); 897de910bd9SOr Gerlitz mutex_init(&id_priv->handler_mutex); 898e51060f0SSean Hefty INIT_LIST_HEAD(&id_priv->listen_list); 899c8f6a362SSean Hefty INIT_LIST_HEAD(&id_priv->mc_list); 900e51060f0SSean Hefty get_random_bytes(&id_priv->seq_num, sizeof id_priv->seq_num); 901fa20105eSGuy Shapiro id_priv->id.route.addr.dev_addr.net = get_net(net); 90223a9cd2aSMoni Shoua id_priv->seq_num &= 0x00ffffff; 903e51060f0SSean Hefty 904e51060f0SSean Hefty return &id_priv->id; 905e51060f0SSean Hefty } 90600313983SSteve Wise EXPORT_SYMBOL(__rdma_create_id); 907e51060f0SSean Hefty 908c8f6a362SSean Hefty static int cma_init_ud_qp(struct rdma_id_private *id_priv, struct ib_qp *qp) 909e51060f0SSean Hefty { 910e51060f0SSean Hefty struct ib_qp_attr qp_attr; 911c8f6a362SSean Hefty int qp_attr_mask, ret; 912e51060f0SSean Hefty 913c8f6a362SSean Hefty qp_attr.qp_state = IB_QPS_INIT; 914c8f6a362SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 915e51060f0SSean Hefty if (ret) 916e51060f0SSean Hefty return ret; 917e51060f0SSean Hefty 918c8f6a362SSean Hefty ret = ib_modify_qp(qp, &qp_attr, qp_attr_mask); 919c8f6a362SSean Hefty if (ret) 920c8f6a362SSean Hefty return ret; 921c8f6a362SSean Hefty 922c8f6a362SSean Hefty qp_attr.qp_state = IB_QPS_RTR; 923c8f6a362SSean Hefty ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE); 924c8f6a362SSean Hefty if (ret) 925c8f6a362SSean Hefty return ret; 926c8f6a362SSean Hefty 927c8f6a362SSean Hefty qp_attr.qp_state = IB_QPS_RTS; 928c8f6a362SSean Hefty qp_attr.sq_psn = 0; 929c8f6a362SSean Hefty ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE | IB_QP_SQ_PSN); 930c8f6a362SSean Hefty 931c8f6a362SSean Hefty return ret; 932e51060f0SSean Hefty } 933e51060f0SSean Hefty 934c8f6a362SSean Hefty static int cma_init_conn_qp(struct rdma_id_private *id_priv, struct ib_qp *qp) 93507ebafbaSTom Tucker { 93607ebafbaSTom Tucker struct ib_qp_attr qp_attr; 937c8f6a362SSean Hefty int qp_attr_mask, ret; 93807ebafbaSTom Tucker 93907ebafbaSTom Tucker qp_attr.qp_state = IB_QPS_INIT; 940c8f6a362SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 941c8f6a362SSean Hefty if (ret) 942c8f6a362SSean Hefty return ret; 94307ebafbaSTom Tucker 944c8f6a362SSean Hefty return ib_modify_qp(qp, &qp_attr, qp_attr_mask); 94507ebafbaSTom Tucker } 94607ebafbaSTom Tucker 947e51060f0SSean Hefty int rdma_create_qp(struct rdma_cm_id *id, struct ib_pd *pd, 948e51060f0SSean Hefty struct ib_qp_init_attr *qp_init_attr) 949e51060f0SSean Hefty { 950e51060f0SSean Hefty struct rdma_id_private *id_priv; 951e51060f0SSean Hefty struct ib_qp *qp; 952e51060f0SSean Hefty int ret; 953e51060f0SSean Hefty 954e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 955e51060f0SSean Hefty if (id->device != pd->device) 956e51060f0SSean Hefty return -EINVAL; 957e51060f0SSean Hefty 9580691a286SChristoph Hellwig qp_init_attr->port_num = id->port_num; 959e51060f0SSean Hefty qp = ib_create_qp(pd, qp_init_attr); 960e51060f0SSean Hefty if (IS_ERR(qp)) 961e51060f0SSean Hefty return PTR_ERR(qp); 962e51060f0SSean Hefty 963b26f9b99SSean Hefty if (id->qp_type == IB_QPT_UD) 964c8f6a362SSean Hefty ret = cma_init_ud_qp(id_priv, qp); 965c8f6a362SSean Hefty else 966c8f6a362SSean Hefty ret = cma_init_conn_qp(id_priv, qp); 967e51060f0SSean Hefty if (ret) 968e51060f0SSean Hefty goto err; 969e51060f0SSean Hefty 970e51060f0SSean Hefty id->qp = qp; 971e51060f0SSean Hefty id_priv->qp_num = qp->qp_num; 972e51060f0SSean Hefty id_priv->srq = (qp->srq != NULL); 973e51060f0SSean Hefty return 0; 974e51060f0SSean Hefty err: 975e51060f0SSean Hefty ib_destroy_qp(qp); 976e51060f0SSean Hefty return ret; 977e51060f0SSean Hefty } 978e51060f0SSean Hefty EXPORT_SYMBOL(rdma_create_qp); 979e51060f0SSean Hefty 980e51060f0SSean Hefty void rdma_destroy_qp(struct rdma_cm_id *id) 981e51060f0SSean Hefty { 982c5483388SSean Hefty struct rdma_id_private *id_priv; 983c5483388SSean Hefty 984c5483388SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 985c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 986c5483388SSean Hefty ib_destroy_qp(id_priv->id.qp); 987c5483388SSean Hefty id_priv->id.qp = NULL; 988c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 989e51060f0SSean Hefty } 990e51060f0SSean Hefty EXPORT_SYMBOL(rdma_destroy_qp); 991e51060f0SSean Hefty 9925851bb89SSean Hefty static int cma_modify_qp_rtr(struct rdma_id_private *id_priv, 9935851bb89SSean Hefty struct rdma_conn_param *conn_param) 994e51060f0SSean Hefty { 995e51060f0SSean Hefty struct ib_qp_attr qp_attr; 996e51060f0SSean Hefty int qp_attr_mask, ret; 997e51060f0SSean Hefty 998c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 999c5483388SSean Hefty if (!id_priv->id.qp) { 1000c5483388SSean Hefty ret = 0; 1001c5483388SSean Hefty goto out; 1002c5483388SSean Hefty } 1003e51060f0SSean Hefty 1004e51060f0SSean Hefty /* Need to update QP attributes from default values. */ 1005e51060f0SSean Hefty qp_attr.qp_state = IB_QPS_INIT; 1006c5483388SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 1007e51060f0SSean Hefty if (ret) 1008c5483388SSean Hefty goto out; 1009e51060f0SSean Hefty 1010c5483388SSean Hefty ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask); 1011e51060f0SSean Hefty if (ret) 1012c5483388SSean Hefty goto out; 1013e51060f0SSean Hefty 1014e51060f0SSean Hefty qp_attr.qp_state = IB_QPS_RTR; 1015c5483388SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 1016e51060f0SSean Hefty if (ret) 1017c5483388SSean Hefty goto out; 1018e51060f0SSean Hefty 1019fef60902SMichael Wang BUG_ON(id_priv->cma_dev->device != id_priv->id.device); 1020fef60902SMichael Wang 10215851bb89SSean Hefty if (conn_param) 10225851bb89SSean Hefty qp_attr.max_dest_rd_atomic = conn_param->responder_resources; 1023c5483388SSean Hefty ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask); 1024c5483388SSean Hefty out: 1025c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 1026c5483388SSean Hefty return ret; 1027e51060f0SSean Hefty } 1028e51060f0SSean Hefty 10295851bb89SSean Hefty static int cma_modify_qp_rts(struct rdma_id_private *id_priv, 10305851bb89SSean Hefty struct rdma_conn_param *conn_param) 1031e51060f0SSean Hefty { 1032e51060f0SSean Hefty struct ib_qp_attr qp_attr; 1033e51060f0SSean Hefty int qp_attr_mask, ret; 1034e51060f0SSean Hefty 1035c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 1036c5483388SSean Hefty if (!id_priv->id.qp) { 1037c5483388SSean Hefty ret = 0; 1038c5483388SSean Hefty goto out; 1039e51060f0SSean Hefty } 1040e51060f0SSean Hefty 1041c5483388SSean Hefty qp_attr.qp_state = IB_QPS_RTS; 1042c5483388SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 1043c5483388SSean Hefty if (ret) 1044c5483388SSean Hefty goto out; 1045c5483388SSean Hefty 10465851bb89SSean Hefty if (conn_param) 10475851bb89SSean Hefty qp_attr.max_rd_atomic = conn_param->initiator_depth; 1048c5483388SSean Hefty ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask); 1049c5483388SSean Hefty out: 1050c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 1051c5483388SSean Hefty return ret; 1052c5483388SSean Hefty } 1053c5483388SSean Hefty 1054c5483388SSean Hefty static int cma_modify_qp_err(struct rdma_id_private *id_priv) 1055e51060f0SSean Hefty { 1056e51060f0SSean Hefty struct ib_qp_attr qp_attr; 1057c5483388SSean Hefty int ret; 1058e51060f0SSean Hefty 1059c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 1060c5483388SSean Hefty if (!id_priv->id.qp) { 1061c5483388SSean Hefty ret = 0; 1062c5483388SSean Hefty goto out; 1063c5483388SSean Hefty } 1064e51060f0SSean Hefty 1065e51060f0SSean Hefty qp_attr.qp_state = IB_QPS_ERR; 1066c5483388SSean Hefty ret = ib_modify_qp(id_priv->id.qp, &qp_attr, IB_QP_STATE); 1067c5483388SSean Hefty out: 1068c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 1069c5483388SSean Hefty return ret; 1070e51060f0SSean Hefty } 1071e51060f0SSean Hefty 1072c8f6a362SSean Hefty static int cma_ib_init_qp_attr(struct rdma_id_private *id_priv, 1073c8f6a362SSean Hefty struct ib_qp_attr *qp_attr, int *qp_attr_mask) 1074c8f6a362SSean Hefty { 1075c8f6a362SSean Hefty struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 1076c8f6a362SSean Hefty int ret; 10773c86aa70SEli Cohen u16 pkey; 10783c86aa70SEli Cohen 1079227128fcSMichael Wang if (rdma_cap_eth_ah(id_priv->id.device, id_priv->id.port_num)) 10803c86aa70SEli Cohen pkey = 0xffff; 1081fef60902SMichael Wang else 1082fef60902SMichael Wang pkey = ib_addr_get_pkey(dev_addr); 1083c8f6a362SSean Hefty 1084c8f6a362SSean Hefty ret = ib_find_cached_pkey(id_priv->id.device, id_priv->id.port_num, 10853c86aa70SEli Cohen pkey, &qp_attr->pkey_index); 1086c8f6a362SSean Hefty if (ret) 1087c8f6a362SSean Hefty return ret; 1088c8f6a362SSean Hefty 1089c8f6a362SSean Hefty qp_attr->port_num = id_priv->id.port_num; 1090c8f6a362SSean Hefty *qp_attr_mask = IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_PORT; 1091c8f6a362SSean Hefty 1092b26f9b99SSean Hefty if (id_priv->id.qp_type == IB_QPT_UD) { 10935c438135SSean Hefty ret = cma_set_qkey(id_priv, 0); 1094d2ca39f2SYossi Etigin if (ret) 1095d2ca39f2SYossi Etigin return ret; 1096d2ca39f2SYossi Etigin 1097c8f6a362SSean Hefty qp_attr->qkey = id_priv->qkey; 1098c8f6a362SSean Hefty *qp_attr_mask |= IB_QP_QKEY; 1099c8f6a362SSean Hefty } else { 1100c8f6a362SSean Hefty qp_attr->qp_access_flags = 0; 1101c8f6a362SSean Hefty *qp_attr_mask |= IB_QP_ACCESS_FLAGS; 1102c8f6a362SSean Hefty } 1103c8f6a362SSean Hefty return 0; 1104c8f6a362SSean Hefty } 1105c8f6a362SSean Hefty 1106e51060f0SSean Hefty int rdma_init_qp_attr(struct rdma_cm_id *id, struct ib_qp_attr *qp_attr, 1107e51060f0SSean Hefty int *qp_attr_mask) 1108e51060f0SSean Hefty { 1109e51060f0SSean Hefty struct rdma_id_private *id_priv; 1110c8f6a362SSean Hefty int ret = 0; 1111e51060f0SSean Hefty 1112e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 111372219ceaSMichael Wang if (rdma_cap_ib_cm(id->device, id->port_num)) { 1114b26f9b99SSean Hefty if (!id_priv->cm_id.ib || (id_priv->id.qp_type == IB_QPT_UD)) 1115c8f6a362SSean Hefty ret = cma_ib_init_qp_attr(id_priv, qp_attr, qp_attr_mask); 1116c8f6a362SSean Hefty else 1117e51060f0SSean Hefty ret = ib_cm_init_qp_attr(id_priv->cm_id.ib, qp_attr, 1118e51060f0SSean Hefty qp_attr_mask); 1119dd5f03beSMatan Barak 1120e51060f0SSean Hefty if (qp_attr->qp_state == IB_QPS_RTR) 1121e51060f0SSean Hefty qp_attr->rq_psn = id_priv->seq_num; 112204215330SMichael Wang } else if (rdma_cap_iw_cm(id->device, id->port_num)) { 1123c8f6a362SSean Hefty if (!id_priv->cm_id.iw) { 11248f076531SDotan Barak qp_attr->qp_access_flags = 0; 1125c8f6a362SSean Hefty *qp_attr_mask = IB_QP_STATE | IB_QP_ACCESS_FLAGS; 1126c8f6a362SSean Hefty } else 112707ebafbaSTom Tucker ret = iw_cm_init_qp_attr(id_priv->cm_id.iw, qp_attr, 112807ebafbaSTom Tucker qp_attr_mask); 1129a62ab66bSIsmail, Mustafa qp_attr->port_num = id_priv->id.port_num; 1130a62ab66bSIsmail, Mustafa *qp_attr_mask |= IB_QP_PORT; 113121655afcSMichael Wang } else 1132e51060f0SSean Hefty ret = -ENOSYS; 1133e51060f0SSean Hefty 1134*2c1619edSDanit Goldberg if ((*qp_attr_mask & IB_QP_TIMEOUT) && id_priv->timeout_set) 1135*2c1619edSDanit Goldberg qp_attr->timeout = id_priv->timeout; 1136*2c1619edSDanit Goldberg 1137e51060f0SSean Hefty return ret; 1138e51060f0SSean Hefty } 1139e51060f0SSean Hefty EXPORT_SYMBOL(rdma_init_qp_attr); 1140e51060f0SSean Hefty 1141ca3a8aceSParav Pandit static inline bool cma_zero_addr(const struct sockaddr *addr) 1142e51060f0SSean Hefty { 11432e2d190cSSean Hefty switch (addr->sa_family) { 11442e2d190cSSean Hefty case AF_INET: 11452e2d190cSSean Hefty return ipv4_is_zeronet(((struct sockaddr_in *)addr)->sin_addr.s_addr); 11462e2d190cSSean Hefty case AF_INET6: 11472e2d190cSSean Hefty return ipv6_addr_any(&((struct sockaddr_in6 *)addr)->sin6_addr); 11482e2d190cSSean Hefty case AF_IB: 11492e2d190cSSean Hefty return ib_addr_any(&((struct sockaddr_ib *)addr)->sib_addr); 11502e2d190cSSean Hefty default: 1151ca3a8aceSParav Pandit return false; 1152e51060f0SSean Hefty } 1153e51060f0SSean Hefty } 1154e51060f0SSean Hefty 1155ca3a8aceSParav Pandit static inline bool cma_loopback_addr(const struct sockaddr *addr) 1156e51060f0SSean Hefty { 11572e2d190cSSean Hefty switch (addr->sa_family) { 11582e2d190cSSean Hefty case AF_INET: 1159ca3a8aceSParav Pandit return ipv4_is_loopback( 1160ca3a8aceSParav Pandit ((struct sockaddr_in *)addr)->sin_addr.s_addr); 11612e2d190cSSean Hefty case AF_INET6: 1162ca3a8aceSParav Pandit return ipv6_addr_loopback( 1163ca3a8aceSParav Pandit &((struct sockaddr_in6 *)addr)->sin6_addr); 11642e2d190cSSean Hefty case AF_IB: 1165ca3a8aceSParav Pandit return ib_addr_loopback( 1166ca3a8aceSParav Pandit &((struct sockaddr_ib *)addr)->sib_addr); 11672e2d190cSSean Hefty default: 1168ca3a8aceSParav Pandit return false; 11692e2d190cSSean Hefty } 1170e51060f0SSean Hefty } 1171e51060f0SSean Hefty 1172ca3a8aceSParav Pandit static inline bool cma_any_addr(const struct sockaddr *addr) 1173e51060f0SSean Hefty { 1174e51060f0SSean Hefty return cma_zero_addr(addr) || cma_loopback_addr(addr); 1175e51060f0SSean Hefty } 1176e51060f0SSean Hefty 117743b752daSHefty, Sean static int cma_addr_cmp(struct sockaddr *src, struct sockaddr *dst) 117843b752daSHefty, Sean { 117943b752daSHefty, Sean if (src->sa_family != dst->sa_family) 118043b752daSHefty, Sean return -1; 118143b752daSHefty, Sean 118243b752daSHefty, Sean switch (src->sa_family) { 118343b752daSHefty, Sean case AF_INET: 118443b752daSHefty, Sean return ((struct sockaddr_in *) src)->sin_addr.s_addr != 118543b752daSHefty, Sean ((struct sockaddr_in *) dst)->sin_addr.s_addr; 11862e2d190cSSean Hefty case AF_INET6: 118743b752daSHefty, Sean return ipv6_addr_cmp(&((struct sockaddr_in6 *) src)->sin6_addr, 118843b752daSHefty, Sean &((struct sockaddr_in6 *) dst)->sin6_addr); 11892e2d190cSSean Hefty default: 11902e2d190cSSean Hefty return ib_addr_cmp(&((struct sockaddr_ib *) src)->sib_addr, 11912e2d190cSSean Hefty &((struct sockaddr_ib *) dst)->sib_addr); 119243b752daSHefty, Sean } 119343b752daSHefty, Sean } 119443b752daSHefty, Sean 11952df7dba8SParav Pandit static __be16 cma_port(const struct sockaddr *addr) 1196628e5f6dSSean Hefty { 119758afdcb7SSean Hefty struct sockaddr_ib *sib; 119858afdcb7SSean Hefty 119958afdcb7SSean Hefty switch (addr->sa_family) { 120058afdcb7SSean Hefty case AF_INET: 1201628e5f6dSSean Hefty return ((struct sockaddr_in *) addr)->sin_port; 120258afdcb7SSean Hefty case AF_INET6: 1203628e5f6dSSean Hefty return ((struct sockaddr_in6 *) addr)->sin6_port; 120458afdcb7SSean Hefty case AF_IB: 120558afdcb7SSean Hefty sib = (struct sockaddr_ib *) addr; 120658afdcb7SSean Hefty return htons((u16) (be64_to_cpu(sib->sib_sid) & 120758afdcb7SSean Hefty be64_to_cpu(sib->sib_sid_mask))); 120858afdcb7SSean Hefty default: 120958afdcb7SSean Hefty return 0; 121058afdcb7SSean Hefty } 1211628e5f6dSSean Hefty } 1212628e5f6dSSean Hefty 12132df7dba8SParav Pandit static inline int cma_any_port(const struct sockaddr *addr) 1214e51060f0SSean Hefty { 1215628e5f6dSSean Hefty return !cma_port(addr); 1216e51060f0SSean Hefty } 1217e51060f0SSean Hefty 12180c505f70SHaggai Eran static void cma_save_ib_info(struct sockaddr *src_addr, 12190c505f70SHaggai Eran struct sockaddr *dst_addr, 1220e7ff98aeSParav Pandit const struct rdma_cm_id *listen_id, 1221e7ff98aeSParav Pandit const struct sa_path_rec *path) 1222e51060f0SSean Hefty { 1223fbaa1a6dSSean Hefty struct sockaddr_ib *listen_ib, *ib; 1224e51060f0SSean Hefty 1225fbaa1a6dSSean Hefty listen_ib = (struct sockaddr_ib *) &listen_id->route.addr.src_addr; 12260c505f70SHaggai Eran if (src_addr) { 12270c505f70SHaggai Eran ib = (struct sockaddr_ib *)src_addr; 12280c505f70SHaggai Eran ib->sib_family = AF_IB; 1229c07678bbSMatthew Finlay if (path) { 1230fbaa1a6dSSean Hefty ib->sib_pkey = path->pkey; 1231fbaa1a6dSSean Hefty ib->sib_flowinfo = path->flow_label; 1232fbaa1a6dSSean Hefty memcpy(&ib->sib_addr, &path->sgid, 16); 1233d3957b86SMajd Dibbiny ib->sib_sid = path->service_id; 12340c505f70SHaggai Eran ib->sib_scope_id = 0; 1235c07678bbSMatthew Finlay } else { 1236c07678bbSMatthew Finlay ib->sib_pkey = listen_ib->sib_pkey; 1237c07678bbSMatthew Finlay ib->sib_flowinfo = listen_ib->sib_flowinfo; 1238c07678bbSMatthew Finlay ib->sib_addr = listen_ib->sib_addr; 1239fbaa1a6dSSean Hefty ib->sib_sid = listen_ib->sib_sid; 1240fbaa1a6dSSean Hefty ib->sib_scope_id = listen_ib->sib_scope_id; 12410c505f70SHaggai Eran } 12420c505f70SHaggai Eran ib->sib_sid_mask = cpu_to_be64(0xffffffffffffffffULL); 12430c505f70SHaggai Eran } 12440c505f70SHaggai Eran if (dst_addr) { 12450c505f70SHaggai Eran ib = (struct sockaddr_ib *)dst_addr; 12460c505f70SHaggai Eran ib->sib_family = AF_IB; 1247c07678bbSMatthew Finlay if (path) { 1248fbaa1a6dSSean Hefty ib->sib_pkey = path->pkey; 1249fbaa1a6dSSean Hefty ib->sib_flowinfo = path->flow_label; 1250fbaa1a6dSSean Hefty memcpy(&ib->sib_addr, &path->dgid, 16); 1251fbaa1a6dSSean Hefty } 1252c07678bbSMatthew Finlay } 125328521440SJason Gunthorpe } 125428521440SJason Gunthorpe 1255c50e90d0SArnd Bergmann static void cma_save_ip4_info(struct sockaddr_in *src_addr, 1256c50e90d0SArnd Bergmann struct sockaddr_in *dst_addr, 12570c505f70SHaggai Eran struct cma_hdr *hdr, 12580c505f70SHaggai Eran __be16 local_port) 1259fbaa1a6dSSean Hefty { 12600c505f70SHaggai Eran if (src_addr) { 1261c50e90d0SArnd Bergmann *src_addr = (struct sockaddr_in) { 1262c50e90d0SArnd Bergmann .sin_family = AF_INET, 1263c50e90d0SArnd Bergmann .sin_addr.s_addr = hdr->dst_addr.ip4.addr, 1264c50e90d0SArnd Bergmann .sin_port = local_port, 1265c50e90d0SArnd Bergmann }; 12660c505f70SHaggai Eran } 1267fbaa1a6dSSean Hefty 12680c505f70SHaggai Eran if (dst_addr) { 1269c50e90d0SArnd Bergmann *dst_addr = (struct sockaddr_in) { 1270c50e90d0SArnd Bergmann .sin_family = AF_INET, 1271c50e90d0SArnd Bergmann .sin_addr.s_addr = hdr->src_addr.ip4.addr, 1272c50e90d0SArnd Bergmann .sin_port = hdr->port, 1273c50e90d0SArnd Bergmann }; 1274fbaa1a6dSSean Hefty } 12750c505f70SHaggai Eran } 1276fbaa1a6dSSean Hefty 1277c50e90d0SArnd Bergmann static void cma_save_ip6_info(struct sockaddr_in6 *src_addr, 1278c50e90d0SArnd Bergmann struct sockaddr_in6 *dst_addr, 12790c505f70SHaggai Eran struct cma_hdr *hdr, 12800c505f70SHaggai Eran __be16 local_port) 1281fbaa1a6dSSean Hefty { 12820c505f70SHaggai Eran if (src_addr) { 1283c50e90d0SArnd Bergmann *src_addr = (struct sockaddr_in6) { 1284c50e90d0SArnd Bergmann .sin6_family = AF_INET6, 1285c50e90d0SArnd Bergmann .sin6_addr = hdr->dst_addr.ip6, 1286c50e90d0SArnd Bergmann .sin6_port = local_port, 1287c50e90d0SArnd Bergmann }; 12880c505f70SHaggai Eran } 1289fbaa1a6dSSean Hefty 12900c505f70SHaggai Eran if (dst_addr) { 1291c50e90d0SArnd Bergmann *dst_addr = (struct sockaddr_in6) { 1292c50e90d0SArnd Bergmann .sin6_family = AF_INET6, 1293c50e90d0SArnd Bergmann .sin6_addr = hdr->src_addr.ip6, 1294c50e90d0SArnd Bergmann .sin6_port = hdr->port, 1295c50e90d0SArnd Bergmann }; 1296fbaa1a6dSSean Hefty } 12970c505f70SHaggai Eran } 1298fbaa1a6dSSean Hefty 12990c505f70SHaggai Eran static u16 cma_port_from_service_id(__be64 service_id) 13000c505f70SHaggai Eran { 13010c505f70SHaggai Eran return (u16)be64_to_cpu(service_id); 13020c505f70SHaggai Eran } 13030c505f70SHaggai Eran 13040c505f70SHaggai Eran static int cma_save_ip_info(struct sockaddr *src_addr, 13050c505f70SHaggai Eran struct sockaddr *dst_addr, 1306e7ff98aeSParav Pandit const struct ib_cm_event *ib_event, 13070c505f70SHaggai Eran __be64 service_id) 1308fbaa1a6dSSean Hefty { 1309fbaa1a6dSSean Hefty struct cma_hdr *hdr; 13100c505f70SHaggai Eran __be16 port; 1311e51060f0SSean Hefty 1312fbaa1a6dSSean Hefty hdr = ib_event->private_data; 1313fbaa1a6dSSean Hefty if (hdr->cma_version != CMA_VERSION) 1314fbaa1a6dSSean Hefty return -EINVAL; 1315e51060f0SSean Hefty 13160c505f70SHaggai Eran port = htons(cma_port_from_service_id(service_id)); 13170c505f70SHaggai Eran 1318fbaa1a6dSSean Hefty switch (cma_get_ip_ver(hdr)) { 1319e51060f0SSean Hefty case 4: 1320c50e90d0SArnd Bergmann cma_save_ip4_info((struct sockaddr_in *)src_addr, 1321c50e90d0SArnd Bergmann (struct sockaddr_in *)dst_addr, hdr, port); 1322e51060f0SSean Hefty break; 1323e51060f0SSean Hefty case 6: 1324c50e90d0SArnd Bergmann cma_save_ip6_info((struct sockaddr_in6 *)src_addr, 1325c50e90d0SArnd Bergmann (struct sockaddr_in6 *)dst_addr, hdr, port); 1326e51060f0SSean Hefty break; 1327e51060f0SSean Hefty default: 13284c21b5bcSHaggai Eran return -EAFNOSUPPORT; 1329e51060f0SSean Hefty } 13300c505f70SHaggai Eran 1331fbaa1a6dSSean Hefty return 0; 1332e51060f0SSean Hefty } 1333e51060f0SSean Hefty 13340c505f70SHaggai Eran static int cma_save_net_info(struct sockaddr *src_addr, 13350c505f70SHaggai Eran struct sockaddr *dst_addr, 1336e7ff98aeSParav Pandit const struct rdma_cm_id *listen_id, 1337e7ff98aeSParav Pandit const struct ib_cm_event *ib_event, 13380c505f70SHaggai Eran sa_family_t sa_family, __be64 service_id) 13390c505f70SHaggai Eran { 13400c505f70SHaggai Eran if (sa_family == AF_IB) { 13410c505f70SHaggai Eran if (ib_event->event == IB_CM_REQ_RECEIVED) 13420c505f70SHaggai Eran cma_save_ib_info(src_addr, dst_addr, listen_id, 13430c505f70SHaggai Eran ib_event->param.req_rcvd.primary_path); 13440c505f70SHaggai Eran else if (ib_event->event == IB_CM_SIDR_REQ_RECEIVED) 13450c505f70SHaggai Eran cma_save_ib_info(src_addr, dst_addr, listen_id, NULL); 13460c505f70SHaggai Eran return 0; 13470c505f70SHaggai Eran } 13480c505f70SHaggai Eran 13490c505f70SHaggai Eran return cma_save_ip_info(src_addr, dst_addr, ib_event, service_id); 13500c505f70SHaggai Eran } 13510c505f70SHaggai Eran 13524c21b5bcSHaggai Eran static int cma_save_req_info(const struct ib_cm_event *ib_event, 13534c21b5bcSHaggai Eran struct cma_req_info *req) 13544c21b5bcSHaggai Eran { 13554c21b5bcSHaggai Eran const struct ib_cm_req_event_param *req_param = 13564c21b5bcSHaggai Eran &ib_event->param.req_rcvd; 13574c21b5bcSHaggai Eran const struct ib_cm_sidr_req_event_param *sidr_param = 13584c21b5bcSHaggai Eran &ib_event->param.sidr_req_rcvd; 13594c21b5bcSHaggai Eran 13604c21b5bcSHaggai Eran switch (ib_event->event) { 13614c21b5bcSHaggai Eran case IB_CM_REQ_RECEIVED: 13624c21b5bcSHaggai Eran req->device = req_param->listen_id->device; 13634c21b5bcSHaggai Eran req->port = req_param->port; 13644c21b5bcSHaggai Eran memcpy(&req->local_gid, &req_param->primary_path->sgid, 13654c21b5bcSHaggai Eran sizeof(req->local_gid)); 13664c21b5bcSHaggai Eran req->has_gid = true; 1367d3957b86SMajd Dibbiny req->service_id = req_param->primary_path->service_id; 1368ab3964adSHaggai Eran req->pkey = be16_to_cpu(req_param->primary_path->pkey); 136984424a7fSHaggai Eran if (req->pkey != req_param->bth_pkey) 137084424a7fSHaggai Eran pr_warn_ratelimited("RDMA CMA: got different BTH P_Key (0x%x) and primary path P_Key (0x%x)\n" 137184424a7fSHaggai Eran "RDMA CMA: in the future this may cause the request to be dropped\n", 137284424a7fSHaggai Eran req_param->bth_pkey, req->pkey); 13734c21b5bcSHaggai Eran break; 13744c21b5bcSHaggai Eran case IB_CM_SIDR_REQ_RECEIVED: 13754c21b5bcSHaggai Eran req->device = sidr_param->listen_id->device; 13764c21b5bcSHaggai Eran req->port = sidr_param->port; 13774c21b5bcSHaggai Eran req->has_gid = false; 13784c21b5bcSHaggai Eran req->service_id = sidr_param->service_id; 1379ab3964adSHaggai Eran req->pkey = sidr_param->pkey; 138084424a7fSHaggai Eran if (req->pkey != sidr_param->bth_pkey) 138184424a7fSHaggai Eran pr_warn_ratelimited("RDMA CMA: got different BTH P_Key (0x%x) and SIDR request payload P_Key (0x%x)\n" 138284424a7fSHaggai Eran "RDMA CMA: in the future this may cause the request to be dropped\n", 138384424a7fSHaggai Eran sidr_param->bth_pkey, req->pkey); 13844c21b5bcSHaggai Eran break; 13854c21b5bcSHaggai Eran default: 13864c21b5bcSHaggai Eran return -EINVAL; 13874c21b5bcSHaggai Eran } 13884c21b5bcSHaggai Eran 13894c21b5bcSHaggai Eran return 0; 13904c21b5bcSHaggai Eran } 13914c21b5bcSHaggai Eran 1392f887f2acSHaggai Eran static bool validate_ipv4_net_dev(struct net_device *net_dev, 1393f887f2acSHaggai Eran const struct sockaddr_in *dst_addr, 1394f887f2acSHaggai Eran const struct sockaddr_in *src_addr) 1395f887f2acSHaggai Eran { 1396f887f2acSHaggai Eran __be32 daddr = dst_addr->sin_addr.s_addr, 1397f887f2acSHaggai Eran saddr = src_addr->sin_addr.s_addr; 1398f887f2acSHaggai Eran struct fib_result res; 1399f887f2acSHaggai Eran struct flowi4 fl4; 1400f887f2acSHaggai Eran int err; 1401f887f2acSHaggai Eran bool ret; 1402f887f2acSHaggai Eran 1403f887f2acSHaggai Eran if (ipv4_is_multicast(saddr) || ipv4_is_lbcast(saddr) || 1404f887f2acSHaggai Eran ipv4_is_lbcast(daddr) || ipv4_is_zeronet(saddr) || 1405f887f2acSHaggai Eran ipv4_is_zeronet(daddr) || ipv4_is_loopback(daddr) || 1406f887f2acSHaggai Eran ipv4_is_loopback(saddr)) 1407f887f2acSHaggai Eran return false; 1408f887f2acSHaggai Eran 1409f887f2acSHaggai Eran memset(&fl4, 0, sizeof(fl4)); 1410f887f2acSHaggai Eran fl4.flowi4_iif = net_dev->ifindex; 1411f887f2acSHaggai Eran fl4.daddr = daddr; 1412f887f2acSHaggai Eran fl4.saddr = saddr; 1413f887f2acSHaggai Eran 1414f887f2acSHaggai Eran rcu_read_lock(); 1415f887f2acSHaggai Eran err = fib_lookup(dev_net(net_dev), &fl4, &res, 0); 1416d3632493SBart Van Assche ret = err == 0 && FIB_RES_DEV(res) == net_dev; 1417f887f2acSHaggai Eran rcu_read_unlock(); 1418f887f2acSHaggai Eran 1419f887f2acSHaggai Eran return ret; 1420f887f2acSHaggai Eran } 1421f887f2acSHaggai Eran 1422f887f2acSHaggai Eran static bool validate_ipv6_net_dev(struct net_device *net_dev, 1423f887f2acSHaggai Eran const struct sockaddr_in6 *dst_addr, 1424f887f2acSHaggai Eran const struct sockaddr_in6 *src_addr) 1425f887f2acSHaggai Eran { 1426f887f2acSHaggai Eran #if IS_ENABLED(CONFIG_IPV6) 1427f887f2acSHaggai Eran const int strict = ipv6_addr_type(&dst_addr->sin6_addr) & 1428f887f2acSHaggai Eran IPV6_ADDR_LINKLOCAL; 1429f887f2acSHaggai Eran struct rt6_info *rt = rt6_lookup(dev_net(net_dev), &dst_addr->sin6_addr, 1430f887f2acSHaggai Eran &src_addr->sin6_addr, net_dev->ifindex, 1431b75cc8f9SDavid Ahern NULL, strict); 1432f887f2acSHaggai Eran bool ret; 1433f887f2acSHaggai Eran 1434f887f2acSHaggai Eran if (!rt) 1435f887f2acSHaggai Eran return false; 1436f887f2acSHaggai Eran 1437f887f2acSHaggai Eran ret = rt->rt6i_idev->dev == net_dev; 1438f887f2acSHaggai Eran ip6_rt_put(rt); 1439f887f2acSHaggai Eran 1440f887f2acSHaggai Eran return ret; 1441f887f2acSHaggai Eran #else 1442f887f2acSHaggai Eran return false; 1443f887f2acSHaggai Eran #endif 1444f887f2acSHaggai Eran } 1445f887f2acSHaggai Eran 1446f887f2acSHaggai Eran static bool validate_net_dev(struct net_device *net_dev, 1447f887f2acSHaggai Eran const struct sockaddr *daddr, 1448f887f2acSHaggai Eran const struct sockaddr *saddr) 1449f887f2acSHaggai Eran { 1450f887f2acSHaggai Eran const struct sockaddr_in *daddr4 = (const struct sockaddr_in *)daddr; 1451f887f2acSHaggai Eran const struct sockaddr_in *saddr4 = (const struct sockaddr_in *)saddr; 1452f887f2acSHaggai Eran const struct sockaddr_in6 *daddr6 = (const struct sockaddr_in6 *)daddr; 1453f887f2acSHaggai Eran const struct sockaddr_in6 *saddr6 = (const struct sockaddr_in6 *)saddr; 1454f887f2acSHaggai Eran 1455f887f2acSHaggai Eran switch (daddr->sa_family) { 1456f887f2acSHaggai Eran case AF_INET: 1457f887f2acSHaggai Eran return saddr->sa_family == AF_INET && 1458f887f2acSHaggai Eran validate_ipv4_net_dev(net_dev, daddr4, saddr4); 1459f887f2acSHaggai Eran 1460f887f2acSHaggai Eran case AF_INET6: 1461f887f2acSHaggai Eran return saddr->sa_family == AF_INET6 && 1462f887f2acSHaggai Eran validate_ipv6_net_dev(net_dev, daddr6, saddr6); 1463f887f2acSHaggai Eran 1464f887f2acSHaggai Eran default: 1465f887f2acSHaggai Eran return false; 1466f887f2acSHaggai Eran } 1467f887f2acSHaggai Eran } 1468f887f2acSHaggai Eran 1469cee10433SParav Pandit static struct net_device * 1470cee10433SParav Pandit roce_get_net_dev_by_cm_event(const struct ib_cm_event *ib_event) 1471cee10433SParav Pandit { 1472cee10433SParav Pandit const struct ib_gid_attr *sgid_attr = NULL; 1473cee10433SParav Pandit 1474cee10433SParav Pandit if (ib_event->event == IB_CM_REQ_RECEIVED) 1475cee10433SParav Pandit sgid_attr = ib_event->param.req_rcvd.ppath_sgid_attr; 1476cee10433SParav Pandit else if (ib_event->event == IB_CM_SIDR_REQ_RECEIVED) 1477cee10433SParav Pandit sgid_attr = ib_event->param.sidr_req_rcvd.sgid_attr; 1478cee10433SParav Pandit 1479cee10433SParav Pandit if (!sgid_attr) 1480cee10433SParav Pandit return NULL; 1481cee10433SParav Pandit dev_hold(sgid_attr->ndev); 1482cee10433SParav Pandit return sgid_attr->ndev; 1483cee10433SParav Pandit } 1484cee10433SParav Pandit 1485e7ff98aeSParav Pandit static struct net_device *cma_get_net_dev(const struct ib_cm_event *ib_event, 14862918c1a9SParav Pandit struct cma_req_info *req) 14874c21b5bcSHaggai Eran { 14882918c1a9SParav Pandit struct sockaddr *listen_addr = 14892918c1a9SParav Pandit (struct sockaddr *)&req->listen_addr_storage; 14902918c1a9SParav Pandit struct sockaddr *src_addr = (struct sockaddr *)&req->src_addr_storage; 14914c21b5bcSHaggai Eran struct net_device *net_dev; 14924c21b5bcSHaggai Eran const union ib_gid *gid = req->has_gid ? &req->local_gid : NULL; 14934c21b5bcSHaggai Eran int err; 14944c21b5bcSHaggai Eran 1495f887f2acSHaggai Eran err = cma_save_ip_info(listen_addr, src_addr, ib_event, 1496f887f2acSHaggai Eran req->service_id); 14974c21b5bcSHaggai Eran if (err) 14984c21b5bcSHaggai Eran return ERR_PTR(err); 14994c21b5bcSHaggai Eran 1500cee10433SParav Pandit if (rdma_protocol_roce(req->device, req->port)) 1501cee10433SParav Pandit net_dev = roce_get_net_dev_by_cm_event(ib_event); 1502cee10433SParav Pandit else 1503cee10433SParav Pandit net_dev = ib_get_net_dev_by_params(req->device, req->port, 1504cee10433SParav Pandit req->pkey, 15054c21b5bcSHaggai Eran gid, listen_addr); 15064c21b5bcSHaggai Eran if (!net_dev) 15074c21b5bcSHaggai Eran return ERR_PTR(-ENODEV); 15084c21b5bcSHaggai Eran 15094c21b5bcSHaggai Eran return net_dev; 15104c21b5bcSHaggai Eran } 15114c21b5bcSHaggai Eran 15122253fc0cSSteve Wise static enum rdma_ucm_port_space rdma_ps_from_service_id(__be64 service_id) 15134c21b5bcSHaggai Eran { 15144c21b5bcSHaggai Eran return (be64_to_cpu(service_id) >> 16) & 0xffff; 15154c21b5bcSHaggai Eran } 15164c21b5bcSHaggai Eran 15174c21b5bcSHaggai Eran static bool cma_match_private_data(struct rdma_id_private *id_priv, 15184c21b5bcSHaggai Eran const struct cma_hdr *hdr) 15194c21b5bcSHaggai Eran { 15204c21b5bcSHaggai Eran struct sockaddr *addr = cma_src_addr(id_priv); 15214c21b5bcSHaggai Eran __be32 ip4_addr; 15224c21b5bcSHaggai Eran struct in6_addr ip6_addr; 15234c21b5bcSHaggai Eran 15244c21b5bcSHaggai Eran if (cma_any_addr(addr) && !id_priv->afonly) 15254c21b5bcSHaggai Eran return true; 15264c21b5bcSHaggai Eran 15274c21b5bcSHaggai Eran switch (addr->sa_family) { 15284c21b5bcSHaggai Eran case AF_INET: 15294c21b5bcSHaggai Eran ip4_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr; 15304c21b5bcSHaggai Eran if (cma_get_ip_ver(hdr) != 4) 15314c21b5bcSHaggai Eran return false; 15324c21b5bcSHaggai Eran if (!cma_any_addr(addr) && 15334c21b5bcSHaggai Eran hdr->dst_addr.ip4.addr != ip4_addr) 15344c21b5bcSHaggai Eran return false; 15354c21b5bcSHaggai Eran break; 15364c21b5bcSHaggai Eran case AF_INET6: 15374c21b5bcSHaggai Eran ip6_addr = ((struct sockaddr_in6 *)addr)->sin6_addr; 15384c21b5bcSHaggai Eran if (cma_get_ip_ver(hdr) != 6) 15394c21b5bcSHaggai Eran return false; 15404c21b5bcSHaggai Eran if (!cma_any_addr(addr) && 15414c21b5bcSHaggai Eran memcmp(&hdr->dst_addr.ip6, &ip6_addr, sizeof(ip6_addr))) 15424c21b5bcSHaggai Eran return false; 15434c21b5bcSHaggai Eran break; 15444c21b5bcSHaggai Eran case AF_IB: 15454c21b5bcSHaggai Eran return true; 15464c21b5bcSHaggai Eran default: 15474c21b5bcSHaggai Eran return false; 15484c21b5bcSHaggai Eran } 15494c21b5bcSHaggai Eran 15504c21b5bcSHaggai Eran return true; 15514c21b5bcSHaggai Eran } 15524c21b5bcSHaggai Eran 1553b8cab5daSHaggai Eran static bool cma_protocol_roce(const struct rdma_cm_id *id) 1554b8cab5daSHaggai Eran { 1555b8cab5daSHaggai Eran struct ib_device *device = id->device; 1556b8cab5daSHaggai Eran const int port_num = id->port_num ?: rdma_start_port(device); 1557b8cab5daSHaggai Eran 15585ac08a34SParav Pandit return rdma_protocol_roce(device, port_num); 1559b8cab5daSHaggai Eran } 1560b8cab5daSHaggai Eran 156178fb282bSParav Pandit static bool cma_is_req_ipv6_ll(const struct cma_req_info *req) 156278fb282bSParav Pandit { 156378fb282bSParav Pandit const struct sockaddr *daddr = 156478fb282bSParav Pandit (const struct sockaddr *)&req->listen_addr_storage; 156578fb282bSParav Pandit const struct sockaddr_in6 *daddr6 = (const struct sockaddr_in6 *)daddr; 156678fb282bSParav Pandit 156778fb282bSParav Pandit /* Returns true if the req is for IPv6 link local */ 156878fb282bSParav Pandit return (daddr->sa_family == AF_INET6 && 156978fb282bSParav Pandit (ipv6_addr_type(&daddr6->sin6_addr) & IPV6_ADDR_LINKLOCAL)); 157078fb282bSParav Pandit } 157178fb282bSParav Pandit 1572fac51590SMatan Barak static bool cma_match_net_dev(const struct rdma_cm_id *id, 1573fac51590SMatan Barak const struct net_device *net_dev, 157478fb282bSParav Pandit const struct cma_req_info *req) 15754c21b5bcSHaggai Eran { 1576fac51590SMatan Barak const struct rdma_addr *addr = &id->route.addr; 15774c21b5bcSHaggai Eran 15784c21b5bcSHaggai Eran if (!net_dev) 1579d274e45cSParav Pandit /* This request is an AF_IB request */ 158078fb282bSParav Pandit return (!id->port_num || id->port_num == req->port) && 1581d274e45cSParav Pandit (addr->src_addr.ss_family == AF_IB); 15824c21b5bcSHaggai Eran 1583643d213aSParav Pandit /* 158478fb282bSParav Pandit * If the request is not for IPv6 link local, allow matching 158578fb282bSParav Pandit * request to any netdevice of the one or multiport rdma device. 158678fb282bSParav Pandit */ 158778fb282bSParav Pandit if (!cma_is_req_ipv6_ll(req)) 158878fb282bSParav Pandit return true; 158978fb282bSParav Pandit /* 1590643d213aSParav Pandit * Net namespaces must match, and if the listner is listening 1591643d213aSParav Pandit * on a specific netdevice than netdevice must match as well. 1592643d213aSParav Pandit */ 1593643d213aSParav Pandit if (net_eq(dev_net(net_dev), addr->dev_addr.net) && 1594643d213aSParav Pandit (!!addr->dev_addr.bound_dev_if == 1595643d213aSParav Pandit (addr->dev_addr.bound_dev_if == net_dev->ifindex))) 1596643d213aSParav Pandit return true; 1597643d213aSParav Pandit else 1598643d213aSParav Pandit return false; 15994c21b5bcSHaggai Eran } 16004c21b5bcSHaggai Eran 16014c21b5bcSHaggai Eran static struct rdma_id_private *cma_find_listener( 16024c21b5bcSHaggai Eran const struct rdma_bind_list *bind_list, 16034c21b5bcSHaggai Eran const struct ib_cm_id *cm_id, 16044c21b5bcSHaggai Eran const struct ib_cm_event *ib_event, 16054c21b5bcSHaggai Eran const struct cma_req_info *req, 16064c21b5bcSHaggai Eran const struct net_device *net_dev) 16074c21b5bcSHaggai Eran { 16084c21b5bcSHaggai Eran struct rdma_id_private *id_priv, *id_priv_dev; 16094c21b5bcSHaggai Eran 16104c21b5bcSHaggai Eran if (!bind_list) 16114c21b5bcSHaggai Eran return ERR_PTR(-EINVAL); 16124c21b5bcSHaggai Eran 16134c21b5bcSHaggai Eran hlist_for_each_entry(id_priv, &bind_list->owners, node) { 16144c21b5bcSHaggai Eran if (cma_match_private_data(id_priv, ib_event->private_data)) { 16154c21b5bcSHaggai Eran if (id_priv->id.device == cm_id->device && 161678fb282bSParav Pandit cma_match_net_dev(&id_priv->id, net_dev, req)) 16174c21b5bcSHaggai Eran return id_priv; 16184c21b5bcSHaggai Eran list_for_each_entry(id_priv_dev, 16194c21b5bcSHaggai Eran &id_priv->listen_list, 16204c21b5bcSHaggai Eran listen_list) { 16214c21b5bcSHaggai Eran if (id_priv_dev->id.device == cm_id->device && 162278fb282bSParav Pandit cma_match_net_dev(&id_priv_dev->id, 162378fb282bSParav Pandit net_dev, req)) 16244c21b5bcSHaggai Eran return id_priv_dev; 16254c21b5bcSHaggai Eran } 16264c21b5bcSHaggai Eran } 16274c21b5bcSHaggai Eran } 16284c21b5bcSHaggai Eran 16294c21b5bcSHaggai Eran return ERR_PTR(-EINVAL); 16304c21b5bcSHaggai Eran } 16314c21b5bcSHaggai Eran 1632e7ff98aeSParav Pandit static struct rdma_id_private * 163385463316SParav Pandit cma_ib_id_from_event(struct ib_cm_id *cm_id, 1634e7ff98aeSParav Pandit const struct ib_cm_event *ib_event, 163541ab1cb7SParav Pandit struct cma_req_info *req, 16360b3ca768SHaggai Eran struct net_device **net_dev) 16374c21b5bcSHaggai Eran { 16384c21b5bcSHaggai Eran struct rdma_bind_list *bind_list; 16394c21b5bcSHaggai Eran struct rdma_id_private *id_priv; 16404c21b5bcSHaggai Eran int err; 16414c21b5bcSHaggai Eran 164241ab1cb7SParav Pandit err = cma_save_req_info(ib_event, req); 16434c21b5bcSHaggai Eran if (err) 16444c21b5bcSHaggai Eran return ERR_PTR(err); 16454c21b5bcSHaggai Eran 164641ab1cb7SParav Pandit *net_dev = cma_get_net_dev(ib_event, req); 16470b3ca768SHaggai Eran if (IS_ERR(*net_dev)) { 16480b3ca768SHaggai Eran if (PTR_ERR(*net_dev) == -EAFNOSUPPORT) { 16494c21b5bcSHaggai Eran /* Assuming the protocol is AF_IB */ 16500b3ca768SHaggai Eran *net_dev = NULL; 16514c21b5bcSHaggai Eran } else { 16520b3ca768SHaggai Eran return ERR_CAST(*net_dev); 16534c21b5bcSHaggai Eran } 16544c21b5bcSHaggai Eran } 16554c21b5bcSHaggai Eran 16562918c1a9SParav Pandit /* 16572918c1a9SParav Pandit * Net namespace might be getting deleted while route lookup, 16582918c1a9SParav Pandit * cm_id lookup is in progress. Therefore, perform netdevice 16592918c1a9SParav Pandit * validation, cm_id lookup under rcu lock. 16602918c1a9SParav Pandit * RCU lock along with netdevice state check, synchronizes with 16612918c1a9SParav Pandit * netdevice migrating to different net namespace and also avoids 16622918c1a9SParav Pandit * case where net namespace doesn't get deleted while lookup is in 16632918c1a9SParav Pandit * progress. 16642918c1a9SParav Pandit * If the device state is not IFF_UP, its properties such as ifindex 16652918c1a9SParav Pandit * and nd_net cannot be trusted to remain valid without rcu lock. 16662918c1a9SParav Pandit * net/core/dev.c change_net_namespace() ensures to synchronize with 16672918c1a9SParav Pandit * ongoing operations on net device after device is closed using 16682918c1a9SParav Pandit * synchronize_net(). 16692918c1a9SParav Pandit */ 16702918c1a9SParav Pandit rcu_read_lock(); 16712918c1a9SParav Pandit if (*net_dev) { 16722918c1a9SParav Pandit /* 16732918c1a9SParav Pandit * If netdevice is down, it is likely that it is administratively 16742918c1a9SParav Pandit * down or it might be migrating to different namespace. 16752918c1a9SParav Pandit * In that case avoid further processing, as the net namespace 16762918c1a9SParav Pandit * or ifindex may change. 16772918c1a9SParav Pandit */ 16782918c1a9SParav Pandit if (((*net_dev)->flags & IFF_UP) == 0) { 16792918c1a9SParav Pandit id_priv = ERR_PTR(-EHOSTUNREACH); 16802918c1a9SParav Pandit goto err; 16812918c1a9SParav Pandit } 16822918c1a9SParav Pandit 16832918c1a9SParav Pandit if (!validate_net_dev(*net_dev, 168441ab1cb7SParav Pandit (struct sockaddr *)&req->listen_addr_storage, 168541ab1cb7SParav Pandit (struct sockaddr *)&req->src_addr_storage)) { 16862918c1a9SParav Pandit id_priv = ERR_PTR(-EHOSTUNREACH); 16872918c1a9SParav Pandit goto err; 16882918c1a9SParav Pandit } 16892918c1a9SParav Pandit } 16902918c1a9SParav Pandit 1691fa20105eSGuy Shapiro bind_list = cma_ps_find(*net_dev ? dev_net(*net_dev) : &init_net, 169241ab1cb7SParav Pandit rdma_ps_from_service_id(req->service_id), 169341ab1cb7SParav Pandit cma_port_from_service_id(req->service_id)); 169441ab1cb7SParav Pandit id_priv = cma_find_listener(bind_list, cm_id, ib_event, req, *net_dev); 16952918c1a9SParav Pandit err: 16962918c1a9SParav Pandit rcu_read_unlock(); 1697b3b51f9fSHaggai Eran if (IS_ERR(id_priv) && *net_dev) { 1698be688195SHaggai Eran dev_put(*net_dev); 1699be688195SHaggai Eran *net_dev = NULL; 1700be688195SHaggai Eran } 17014c21b5bcSHaggai Eran return id_priv; 17024c21b5bcSHaggai Eran } 17034c21b5bcSHaggai Eran 1704c0b64f58SBart Van Assche static inline u8 cma_user_data_offset(struct rdma_id_private *id_priv) 1705e51060f0SSean Hefty { 1706e8160e15SSean Hefty return cma_family(id_priv) == AF_IB ? 0 : sizeof(struct cma_hdr); 1707e51060f0SSean Hefty } 1708e51060f0SSean Hefty 1709e51060f0SSean Hefty static void cma_cancel_route(struct rdma_id_private *id_priv) 1710e51060f0SSean Hefty { 1711fe53ba2fSMichael Wang if (rdma_cap_ib_sa(id_priv->id.device, id_priv->id.port_num)) { 1712e51060f0SSean Hefty if (id_priv->query) 1713e51060f0SSean Hefty ib_sa_cancel_query(id_priv->query_id, id_priv->query); 1714e51060f0SSean Hefty } 1715e51060f0SSean Hefty } 1716e51060f0SSean Hefty 1717e51060f0SSean Hefty static void cma_cancel_listens(struct rdma_id_private *id_priv) 1718e51060f0SSean Hefty { 1719e51060f0SSean Hefty struct rdma_id_private *dev_id_priv; 1720e51060f0SSean Hefty 1721d02d1f53SSean Hefty /* 1722d02d1f53SSean Hefty * Remove from listen_any_list to prevent added devices from spawning 1723d02d1f53SSean Hefty * additional listen requests. 1724d02d1f53SSean Hefty */ 1725e51060f0SSean Hefty mutex_lock(&lock); 1726e51060f0SSean Hefty list_del(&id_priv->list); 1727e51060f0SSean Hefty 1728e51060f0SSean Hefty while (!list_empty(&id_priv->listen_list)) { 1729e51060f0SSean Hefty dev_id_priv = list_entry(id_priv->listen_list.next, 1730e51060f0SSean Hefty struct rdma_id_private, listen_list); 1731d02d1f53SSean Hefty /* sync with device removal to avoid duplicate destruction */ 1732d02d1f53SSean Hefty list_del_init(&dev_id_priv->list); 1733d02d1f53SSean Hefty list_del(&dev_id_priv->listen_list); 1734d02d1f53SSean Hefty mutex_unlock(&lock); 1735d02d1f53SSean Hefty 1736d02d1f53SSean Hefty rdma_destroy_id(&dev_id_priv->id); 1737d02d1f53SSean Hefty mutex_lock(&lock); 1738e51060f0SSean Hefty } 1739e51060f0SSean Hefty mutex_unlock(&lock); 1740e51060f0SSean Hefty } 1741e51060f0SSean Hefty 1742e51060f0SSean Hefty static void cma_cancel_operation(struct rdma_id_private *id_priv, 1743550e5ca7SNir Muchtar enum rdma_cm_state state) 1744e51060f0SSean Hefty { 1745e51060f0SSean Hefty switch (state) { 1746550e5ca7SNir Muchtar case RDMA_CM_ADDR_QUERY: 1747e51060f0SSean Hefty rdma_addr_cancel(&id_priv->id.route.addr.dev_addr); 1748e51060f0SSean Hefty break; 1749550e5ca7SNir Muchtar case RDMA_CM_ROUTE_QUERY: 1750e51060f0SSean Hefty cma_cancel_route(id_priv); 1751e51060f0SSean Hefty break; 1752550e5ca7SNir Muchtar case RDMA_CM_LISTEN: 1753f4753834SSean Hefty if (cma_any_addr(cma_src_addr(id_priv)) && !id_priv->cma_dev) 1754e51060f0SSean Hefty cma_cancel_listens(id_priv); 1755e51060f0SSean Hefty break; 1756e51060f0SSean Hefty default: 1757e51060f0SSean Hefty break; 1758e51060f0SSean Hefty } 1759e51060f0SSean Hefty } 1760e51060f0SSean Hefty 1761e51060f0SSean Hefty static void cma_release_port(struct rdma_id_private *id_priv) 1762e51060f0SSean Hefty { 1763e51060f0SSean Hefty struct rdma_bind_list *bind_list = id_priv->bind_list; 1764fa20105eSGuy Shapiro struct net *net = id_priv->id.route.addr.dev_addr.net; 1765e51060f0SSean Hefty 1766e51060f0SSean Hefty if (!bind_list) 1767e51060f0SSean Hefty return; 1768e51060f0SSean Hefty 1769e51060f0SSean Hefty mutex_lock(&lock); 1770e51060f0SSean Hefty hlist_del(&id_priv->node); 1771e51060f0SSean Hefty if (hlist_empty(&bind_list->owners)) { 1772fa20105eSGuy Shapiro cma_ps_remove(net, bind_list->ps, bind_list->port); 1773e51060f0SSean Hefty kfree(bind_list); 1774e51060f0SSean Hefty } 1775e51060f0SSean Hefty mutex_unlock(&lock); 1776e51060f0SSean Hefty } 1777e51060f0SSean Hefty 177888145678SParav Pandit static void cma_leave_roce_mc_group(struct rdma_id_private *id_priv, 177988145678SParav Pandit struct cma_multicast *mc) 178088145678SParav Pandit { 1781c0126915SJason Gunthorpe struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 178288145678SParav Pandit struct net_device *ndev = NULL; 178388145678SParav Pandit 178488145678SParav Pandit if (dev_addr->bound_dev_if) 1785c0126915SJason Gunthorpe ndev = dev_get_by_index(dev_addr->net, dev_addr->bound_dev_if); 178688145678SParav Pandit if (ndev) { 1787c0126915SJason Gunthorpe cma_igmp_send(ndev, &mc->multicast.ib->rec.mgid, false); 178888145678SParav Pandit dev_put(ndev); 178988145678SParav Pandit } 179088145678SParav Pandit kref_put(&mc->mcref, release_mc); 179188145678SParav Pandit } 179288145678SParav Pandit 1793c8f6a362SSean Hefty static void cma_leave_mc_groups(struct rdma_id_private *id_priv) 1794c8f6a362SSean Hefty { 1795c8f6a362SSean Hefty struct cma_multicast *mc; 1796c8f6a362SSean Hefty 1797c8f6a362SSean Hefty while (!list_empty(&id_priv->mc_list)) { 1798c8f6a362SSean Hefty mc = container_of(id_priv->mc_list.next, 1799c8f6a362SSean Hefty struct cma_multicast, list); 1800c8f6a362SSean Hefty list_del(&mc->list); 1801a31ad3b0SMichael Wang if (rdma_cap_ib_mcast(id_priv->cma_dev->device, 18025c9a5282SMichael Wang id_priv->id.port_num)) { 1803c8f6a362SSean Hefty ib_sa_free_multicast(mc->multicast.ib); 1804c8f6a362SSean Hefty kfree(mc); 1805bee3c3c9SMoni Shoua } else { 180688145678SParav Pandit cma_leave_roce_mc_group(id_priv, mc); 1807c8f6a362SSean Hefty } 1808c8f6a362SSean Hefty } 1809bee3c3c9SMoni Shoua } 1810c8f6a362SSean Hefty 1811e51060f0SSean Hefty void rdma_destroy_id(struct rdma_cm_id *id) 1812e51060f0SSean Hefty { 1813e51060f0SSean Hefty struct rdma_id_private *id_priv; 1814550e5ca7SNir Muchtar enum rdma_cm_state state; 1815e51060f0SSean Hefty 1816e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1817550e5ca7SNir Muchtar state = cma_exch(id_priv, RDMA_CM_DESTROYING); 1818e51060f0SSean Hefty cma_cancel_operation(id_priv, state); 1819e51060f0SSean Hefty 1820a396d43aSSean Hefty /* 1821a396d43aSSean Hefty * Wait for any active callback to finish. New callbacks will find 1822a396d43aSSean Hefty * the id_priv state set to destroying and abort. 1823a396d43aSSean Hefty */ 1824a396d43aSSean Hefty mutex_lock(&id_priv->handler_mutex); 1825a396d43aSSean Hefty mutex_unlock(&id_priv->handler_mutex); 1826a396d43aSSean Hefty 182700313983SSteve Wise rdma_restrack_del(&id_priv->res); 1828ed7a01fdSLeon Romanovsky if (id_priv->cma_dev) { 182972219ceaSMichael Wang if (rdma_cap_ib_cm(id_priv->id.device, 1)) { 18300c9361fcSJack Morgenstein if (id_priv->cm_id.ib) 1831e51060f0SSean Hefty ib_destroy_cm_id(id_priv->cm_id.ib); 183204215330SMichael Wang } else if (rdma_cap_iw_cm(id_priv->id.device, 1)) { 18330c9361fcSJack Morgenstein if (id_priv->cm_id.iw) 183407ebafbaSTom Tucker iw_destroy_cm_id(id_priv->cm_id.iw); 1835e51060f0SSean Hefty } 1836c8f6a362SSean Hefty cma_leave_mc_groups(id_priv); 1837a396d43aSSean Hefty cma_release_dev(id_priv); 1838e51060f0SSean Hefty } 1839e51060f0SSean Hefty 1840e51060f0SSean Hefty cma_release_port(id_priv); 1841e51060f0SSean Hefty cma_deref_id(id_priv); 1842e51060f0SSean Hefty wait_for_completion(&id_priv->comp); 1843e51060f0SSean Hefty 1844d02d1f53SSean Hefty if (id_priv->internal_id) 1845d02d1f53SSean Hefty cma_deref_id(id_priv->id.context); 1846d02d1f53SSean Hefty 1847e51060f0SSean Hefty kfree(id_priv->id.route.path_rec); 18484ed13a5fSParav Pandit 18494ed13a5fSParav Pandit if (id_priv->id.route.addr.dev_addr.sgid_attr) 18504ed13a5fSParav Pandit rdma_put_gid_attr(id_priv->id.route.addr.dev_addr.sgid_attr); 18514ed13a5fSParav Pandit 1852fa20105eSGuy Shapiro put_net(id_priv->id.route.addr.dev_addr.net); 1853e51060f0SSean Hefty kfree(id_priv); 1854e51060f0SSean Hefty } 1855e51060f0SSean Hefty EXPORT_SYMBOL(rdma_destroy_id); 1856e51060f0SSean Hefty 1857e51060f0SSean Hefty static int cma_rep_recv(struct rdma_id_private *id_priv) 1858e51060f0SSean Hefty { 1859e51060f0SSean Hefty int ret; 1860e51060f0SSean Hefty 18615851bb89SSean Hefty ret = cma_modify_qp_rtr(id_priv, NULL); 1862e51060f0SSean Hefty if (ret) 1863e51060f0SSean Hefty goto reject; 1864e51060f0SSean Hefty 18655851bb89SSean Hefty ret = cma_modify_qp_rts(id_priv, NULL); 1866e51060f0SSean Hefty if (ret) 1867e51060f0SSean Hefty goto reject; 1868e51060f0SSean Hefty 1869e51060f0SSean Hefty ret = ib_send_cm_rtu(id_priv->cm_id.ib, NULL, 0); 1870e51060f0SSean Hefty if (ret) 1871e51060f0SSean Hefty goto reject; 1872e51060f0SSean Hefty 1873e51060f0SSean Hefty return 0; 1874e51060f0SSean Hefty reject: 1875498683c6SMoni Shoua pr_debug_ratelimited("RDMA CM: CONNECT_ERROR: failed to handle reply. status %d\n", ret); 1876c5483388SSean Hefty cma_modify_qp_err(id_priv); 1877e51060f0SSean Hefty ib_send_cm_rej(id_priv->cm_id.ib, IB_CM_REJ_CONSUMER_DEFINED, 1878e51060f0SSean Hefty NULL, 0, NULL, 0); 1879e51060f0SSean Hefty return ret; 1880e51060f0SSean Hefty } 1881e51060f0SSean Hefty 1882a1b1b61fSSean Hefty static void cma_set_rep_event_data(struct rdma_cm_event *event, 1883e7ff98aeSParav Pandit const struct ib_cm_rep_event_param *rep_data, 1884a1b1b61fSSean Hefty void *private_data) 1885a1b1b61fSSean Hefty { 1886a1b1b61fSSean Hefty event->param.conn.private_data = private_data; 1887a1b1b61fSSean Hefty event->param.conn.private_data_len = IB_CM_REP_PRIVATE_DATA_SIZE; 1888a1b1b61fSSean Hefty event->param.conn.responder_resources = rep_data->responder_resources; 1889a1b1b61fSSean Hefty event->param.conn.initiator_depth = rep_data->initiator_depth; 1890a1b1b61fSSean Hefty event->param.conn.flow_control = rep_data->flow_control; 1891a1b1b61fSSean Hefty event->param.conn.rnr_retry_count = rep_data->rnr_retry_count; 1892a1b1b61fSSean Hefty event->param.conn.srq = rep_data->srq; 1893a1b1b61fSSean Hefty event->param.conn.qp_num = rep_data->remote_qpn; 1894a1b1b61fSSean Hefty } 1895a1b1b61fSSean Hefty 1896e7ff98aeSParav Pandit static int cma_ib_handler(struct ib_cm_id *cm_id, 1897e7ff98aeSParav Pandit const struct ib_cm_event *ib_event) 1898e51060f0SSean Hefty { 1899e51060f0SSean Hefty struct rdma_id_private *id_priv = cm_id->context; 19007582df82SParav Pandit struct rdma_cm_event event = {}; 1901a1b1b61fSSean Hefty int ret = 0; 1902e51060f0SSean Hefty 190337e07cdaSBart Van Assche mutex_lock(&id_priv->handler_mutex); 190438ca83a5SAmir Vadai if ((ib_event->event != IB_CM_TIMEWAIT_EXIT && 190537e07cdaSBart Van Assche id_priv->state != RDMA_CM_CONNECT) || 190638ca83a5SAmir Vadai (ib_event->event == IB_CM_TIMEWAIT_EXIT && 190737e07cdaSBart Van Assche id_priv->state != RDMA_CM_DISCONNECT)) 190837e07cdaSBart Van Assche goto out; 1909e51060f0SSean Hefty 1910e51060f0SSean Hefty switch (ib_event->event) { 1911e51060f0SSean Hefty case IB_CM_REQ_ERROR: 1912e51060f0SSean Hefty case IB_CM_REP_ERROR: 1913a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_UNREACHABLE; 1914a1b1b61fSSean Hefty event.status = -ETIMEDOUT; 1915e51060f0SSean Hefty break; 1916e51060f0SSean Hefty case IB_CM_REP_RECEIVED: 191761c0ddbeSMoni Shoua if (cma_comp(id_priv, RDMA_CM_CONNECT) && 191861c0ddbeSMoni Shoua (id_priv->id.qp_type != IB_QPT_UD)) 191961c0ddbeSMoni Shoua ib_send_cm_mra(cm_id, CMA_CM_MRA_SETTING, NULL, 0); 192001602f11SSean Hefty if (id_priv->id.qp) { 1921a1b1b61fSSean Hefty event.status = cma_rep_recv(id_priv); 1922a1b1b61fSSean Hefty event.event = event.status ? RDMA_CM_EVENT_CONNECT_ERROR : 1923e51060f0SSean Hefty RDMA_CM_EVENT_ESTABLISHED; 192401602f11SSean Hefty } else { 1925a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_CONNECT_RESPONSE; 192601602f11SSean Hefty } 1927a1b1b61fSSean Hefty cma_set_rep_event_data(&event, &ib_event->param.rep_rcvd, 1928a1b1b61fSSean Hefty ib_event->private_data); 1929e51060f0SSean Hefty break; 1930e51060f0SSean Hefty case IB_CM_RTU_RECEIVED: 19310fe313b0SSean Hefty case IB_CM_USER_ESTABLISHED: 19320fe313b0SSean Hefty event.event = RDMA_CM_EVENT_ESTABLISHED; 1933e51060f0SSean Hefty break; 1934e51060f0SSean Hefty case IB_CM_DREQ_ERROR: 1935a1b1b61fSSean Hefty event.status = -ETIMEDOUT; /* fall through */ 1936e51060f0SSean Hefty case IB_CM_DREQ_RECEIVED: 1937e51060f0SSean Hefty case IB_CM_DREP_RECEIVED: 1938550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_CONNECT, 1939550e5ca7SNir Muchtar RDMA_CM_DISCONNECT)) 1940e51060f0SSean Hefty goto out; 1941a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_DISCONNECTED; 1942e51060f0SSean Hefty break; 1943e51060f0SSean Hefty case IB_CM_TIMEWAIT_EXIT: 194438ca83a5SAmir Vadai event.event = RDMA_CM_EVENT_TIMEWAIT_EXIT; 194538ca83a5SAmir Vadai break; 1946e51060f0SSean Hefty case IB_CM_MRA_RECEIVED: 1947e51060f0SSean Hefty /* ignore event */ 1948e51060f0SSean Hefty goto out; 1949e51060f0SSean Hefty case IB_CM_REJ_RECEIVED: 1950498683c6SMoni Shoua pr_debug_ratelimited("RDMA CM: REJECTED: %s\n", rdma_reject_msg(&id_priv->id, 1951498683c6SMoni Shoua ib_event->param.rej_rcvd.reason)); 1952c5483388SSean Hefty cma_modify_qp_err(id_priv); 1953a1b1b61fSSean Hefty event.status = ib_event->param.rej_rcvd.reason; 1954a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_REJECTED; 1955a1b1b61fSSean Hefty event.param.conn.private_data = ib_event->private_data; 1956a1b1b61fSSean Hefty event.param.conn.private_data_len = IB_CM_REJ_PRIVATE_DATA_SIZE; 1957e51060f0SSean Hefty break; 1958e51060f0SSean Hefty default: 1959aba25a3eSParav Pandit pr_err("RDMA CMA: unexpected IB CM event: %d\n", 1960e51060f0SSean Hefty ib_event->event); 1961e51060f0SSean Hefty goto out; 1962e51060f0SSean Hefty } 1963e51060f0SSean Hefty 1964a1b1b61fSSean Hefty ret = id_priv->id.event_handler(&id_priv->id, &event); 1965e51060f0SSean Hefty if (ret) { 1966e51060f0SSean Hefty /* Destroy the CM ID by returning a non-zero value. */ 1967e51060f0SSean Hefty id_priv->cm_id.ib = NULL; 1968550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 1969de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 1970e51060f0SSean Hefty rdma_destroy_id(&id_priv->id); 1971e51060f0SSean Hefty return ret; 1972e51060f0SSean Hefty } 1973e51060f0SSean Hefty out: 1974de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 1975e51060f0SSean Hefty return ret; 1976e51060f0SSean Hefty } 1977e51060f0SSean Hefty 1978e7ff98aeSParav Pandit static struct rdma_id_private * 197985463316SParav Pandit cma_ib_new_conn_id(const struct rdma_cm_id *listen_id, 1980e7ff98aeSParav Pandit const struct ib_cm_event *ib_event, 19810b3ca768SHaggai Eran struct net_device *net_dev) 1982e51060f0SSean Hefty { 198300313983SSteve Wise struct rdma_id_private *listen_id_priv; 1984e51060f0SSean Hefty struct rdma_id_private *id_priv; 1985e51060f0SSean Hefty struct rdma_cm_id *id; 1986e51060f0SSean Hefty struct rdma_route *rt; 19870c505f70SHaggai Eran const sa_family_t ss_family = listen_id->route.addr.src_addr.ss_family; 19889fdca4daSDasaratharaman Chandramouli struct sa_path_rec *path = ib_event->param.req_rcvd.primary_path; 1989d3957b86SMajd Dibbiny const __be64 service_id = 1990d3957b86SMajd Dibbiny ib_event->param.req_rcvd.primary_path->service_id; 199164c5e613SOr Gerlitz int ret; 1992e51060f0SSean Hefty 199300313983SSteve Wise listen_id_priv = container_of(listen_id, struct rdma_id_private, id); 199400313983SSteve Wise id = __rdma_create_id(listen_id->route.addr.dev_addr.net, 1995fa20105eSGuy Shapiro listen_id->event_handler, listen_id->context, 199600313983SSteve Wise listen_id->ps, ib_event->param.req_rcvd.qp_type, 199700313983SSteve Wise listen_id_priv->res.kern_name); 19983f168d2bSKrishna Kumar if (IS_ERR(id)) 19990c9361fcSJack Morgenstein return NULL; 20003f168d2bSKrishna Kumar 2001f4753834SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 20020c505f70SHaggai Eran if (cma_save_net_info((struct sockaddr *)&id->route.addr.src_addr, 20030c505f70SHaggai Eran (struct sockaddr *)&id->route.addr.dst_addr, 20040c505f70SHaggai Eran listen_id, ib_event, ss_family, service_id)) 2005fbaa1a6dSSean Hefty goto err; 20063f168d2bSKrishna Kumar 20073f168d2bSKrishna Kumar rt = &id->route; 20083f168d2bSKrishna Kumar rt->num_paths = ib_event->param.req_rcvd.alternate_path ? 2 : 1; 20096da2ec56SKees Cook rt->path_rec = kmalloc_array(rt->num_paths, sizeof(*rt->path_rec), 20103f168d2bSKrishna Kumar GFP_KERNEL); 20113f168d2bSKrishna Kumar if (!rt->path_rec) 20120c9361fcSJack Morgenstein goto err; 20133f168d2bSKrishna Kumar 20149fdca4daSDasaratharaman Chandramouli rt->path_rec[0] = *path; 2015e51060f0SSean Hefty if (rt->num_paths == 2) 2016e51060f0SSean Hefty rt->path_rec[1] = *ib_event->param.req_rcvd.alternate_path; 2017e51060f0SSean Hefty 20180b3ca768SHaggai Eran if (net_dev) { 201977addc52SParav Pandit rdma_copy_src_l2_addr(&rt->addr.dev_addr, net_dev); 20200b3ca768SHaggai Eran } else { 2021b8cab5daSHaggai Eran if (!cma_protocol_roce(listen_id) && 2022b8cab5daSHaggai Eran cma_any_addr(cma_src_addr(id_priv))) { 2023b8cab5daSHaggai Eran rt->addr.dev_addr.dev_type = ARPHRD_INFINIBAND; 2024b8cab5daSHaggai Eran rdma_addr_set_sgid(&rt->addr.dev_addr, &rt->path_rec[0].sgid); 2025b8cab5daSHaggai Eran ib_addr_set_pkey(&rt->addr.dev_addr, be16_to_cpu(rt->path_rec[0].pkey)); 2026b8cab5daSHaggai Eran } else if (!cma_any_addr(cma_src_addr(id_priv))) { 2027b8cab5daSHaggai Eran ret = cma_translate_addr(cma_src_addr(id_priv), &rt->addr.dev_addr); 2028b8cab5daSHaggai Eran if (ret) 2029b8cab5daSHaggai Eran goto err; 2030b8cab5daSHaggai Eran } 20316f8372b6SSean Hefty } 20326f8372b6SSean Hefty rdma_addr_set_dgid(&rt->addr.dev_addr, &rt->path_rec[0].dgid); 2033e51060f0SSean Hefty 2034550e5ca7SNir Muchtar id_priv->state = RDMA_CM_CONNECT; 2035e51060f0SSean Hefty return id_priv; 20363f168d2bSKrishna Kumar 20373f168d2bSKrishna Kumar err: 20380c9361fcSJack Morgenstein rdma_destroy_id(id); 2039e51060f0SSean Hefty return NULL; 2040e51060f0SSean Hefty } 2041e51060f0SSean Hefty 2042e7ff98aeSParav Pandit static struct rdma_id_private * 204385463316SParav Pandit cma_ib_new_udp_id(const struct rdma_cm_id *listen_id, 2044e7ff98aeSParav Pandit const struct ib_cm_event *ib_event, 20450b3ca768SHaggai Eran struct net_device *net_dev) 2046628e5f6dSSean Hefty { 2047e7ff98aeSParav Pandit const struct rdma_id_private *listen_id_priv; 2048628e5f6dSSean Hefty struct rdma_id_private *id_priv; 2049628e5f6dSSean Hefty struct rdma_cm_id *id; 20500c505f70SHaggai Eran const sa_family_t ss_family = listen_id->route.addr.src_addr.ss_family; 2051fa20105eSGuy Shapiro struct net *net = listen_id->route.addr.dev_addr.net; 2052628e5f6dSSean Hefty int ret; 2053628e5f6dSSean Hefty 205400313983SSteve Wise listen_id_priv = container_of(listen_id, struct rdma_id_private, id); 205500313983SSteve Wise id = __rdma_create_id(net, listen_id->event_handler, listen_id->context, 205600313983SSteve Wise listen_id->ps, IB_QPT_UD, 205700313983SSteve Wise listen_id_priv->res.kern_name); 2058628e5f6dSSean Hefty if (IS_ERR(id)) 2059628e5f6dSSean Hefty return NULL; 2060628e5f6dSSean Hefty 2061f4753834SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 20620c505f70SHaggai Eran if (cma_save_net_info((struct sockaddr *)&id->route.addr.src_addr, 20630c505f70SHaggai Eran (struct sockaddr *)&id->route.addr.dst_addr, 20640c505f70SHaggai Eran listen_id, ib_event, ss_family, 20650c505f70SHaggai Eran ib_event->param.sidr_req_rcvd.service_id)) 2066628e5f6dSSean Hefty goto err; 2067628e5f6dSSean Hefty 20680b3ca768SHaggai Eran if (net_dev) { 206977addc52SParav Pandit rdma_copy_src_l2_addr(&id->route.addr.dev_addr, net_dev); 20700b3ca768SHaggai Eran } else { 2071b8cab5daSHaggai Eran if (!cma_any_addr(cma_src_addr(id_priv))) { 2072b8cab5daSHaggai Eran ret = cma_translate_addr(cma_src_addr(id_priv), 20730b3ca768SHaggai Eran &id->route.addr.dev_addr); 2074b8cab5daSHaggai Eran if (ret) 2075b8cab5daSHaggai Eran goto err; 2076b8cab5daSHaggai Eran } 20776f8372b6SSean Hefty } 2078628e5f6dSSean Hefty 2079550e5ca7SNir Muchtar id_priv->state = RDMA_CM_CONNECT; 2080628e5f6dSSean Hefty return id_priv; 2081628e5f6dSSean Hefty err: 2082628e5f6dSSean Hefty rdma_destroy_id(id); 2083628e5f6dSSean Hefty return NULL; 2084628e5f6dSSean Hefty } 2085628e5f6dSSean Hefty 2086a1b1b61fSSean Hefty static void cma_set_req_event_data(struct rdma_cm_event *event, 2087e7ff98aeSParav Pandit const struct ib_cm_req_event_param *req_data, 2088a1b1b61fSSean Hefty void *private_data, int offset) 2089a1b1b61fSSean Hefty { 2090a1b1b61fSSean Hefty event->param.conn.private_data = private_data + offset; 2091a1b1b61fSSean Hefty event->param.conn.private_data_len = IB_CM_REQ_PRIVATE_DATA_SIZE - offset; 2092a1b1b61fSSean Hefty event->param.conn.responder_resources = req_data->responder_resources; 2093a1b1b61fSSean Hefty event->param.conn.initiator_depth = req_data->initiator_depth; 2094a1b1b61fSSean Hefty event->param.conn.flow_control = req_data->flow_control; 2095a1b1b61fSSean Hefty event->param.conn.retry_count = req_data->retry_count; 2096a1b1b61fSSean Hefty event->param.conn.rnr_retry_count = req_data->rnr_retry_count; 2097a1b1b61fSSean Hefty event->param.conn.srq = req_data->srq; 2098a1b1b61fSSean Hefty event->param.conn.qp_num = req_data->remote_qpn; 2099a1b1b61fSSean Hefty } 2100a1b1b61fSSean Hefty 210185463316SParav Pandit static int cma_ib_check_req_qp_type(const struct rdma_cm_id *id, 2102e7ff98aeSParav Pandit const struct ib_cm_event *ib_event) 21039595480cSHefty, Sean { 21044dd81e89SSean Hefty return (((ib_event->event == IB_CM_REQ_RECEIVED) && 21059595480cSHefty, Sean (ib_event->param.req_rcvd.qp_type == id->qp_type)) || 21069595480cSHefty, Sean ((ib_event->event == IB_CM_SIDR_REQ_RECEIVED) && 21079595480cSHefty, Sean (id->qp_type == IB_QPT_UD)) || 21089595480cSHefty, Sean (!id->qp_type)); 21099595480cSHefty, Sean } 21109595480cSHefty, Sean 211185463316SParav Pandit static int cma_ib_req_handler(struct ib_cm_id *cm_id, 2112e7ff98aeSParav Pandit const struct ib_cm_event *ib_event) 2113e51060f0SSean Hefty { 211437e07cdaSBart Van Assche struct rdma_id_private *listen_id, *conn_id = NULL; 21157582df82SParav Pandit struct rdma_cm_event event = {}; 211641ab1cb7SParav Pandit struct cma_req_info req = {}; 21170b3ca768SHaggai Eran struct net_device *net_dev; 2118c0b64f58SBart Van Assche u8 offset; 2119c0b64f58SBart Van Assche int ret; 2120e51060f0SSean Hefty 212141ab1cb7SParav Pandit listen_id = cma_ib_id_from_event(cm_id, ib_event, &req, &net_dev); 21224c21b5bcSHaggai Eran if (IS_ERR(listen_id)) 21234c21b5bcSHaggai Eran return PTR_ERR(listen_id); 21244c21b5bcSHaggai Eran 212585463316SParav Pandit if (!cma_ib_check_req_qp_type(&listen_id->id, ib_event)) { 21260b3ca768SHaggai Eran ret = -EINVAL; 21270b3ca768SHaggai Eran goto net_dev_put; 21280b3ca768SHaggai Eran } 21299595480cSHefty, Sean 213037e07cdaSBart Van Assche mutex_lock(&listen_id->handler_mutex); 213137e07cdaSBart Van Assche if (listen_id->state != RDMA_CM_LISTEN) { 21320b3ca768SHaggai Eran ret = -ECONNABORTED; 213337e07cdaSBart Van Assche goto err1; 21340b3ca768SHaggai Eran } 2135e51060f0SSean Hefty 2136e8160e15SSean Hefty offset = cma_user_data_offset(listen_id); 2137628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_CONNECT_REQUEST; 21389595480cSHefty, Sean if (ib_event->event == IB_CM_SIDR_REQ_RECEIVED) { 213985463316SParav Pandit conn_id = cma_ib_new_udp_id(&listen_id->id, ib_event, net_dev); 2140628e5f6dSSean Hefty event.param.ud.private_data = ib_event->private_data + offset; 2141628e5f6dSSean Hefty event.param.ud.private_data_len = 2142628e5f6dSSean Hefty IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE - offset; 2143628e5f6dSSean Hefty } else { 214485463316SParav Pandit conn_id = cma_ib_new_conn_id(&listen_id->id, ib_event, net_dev); 2145628e5f6dSSean Hefty cma_set_req_event_data(&event, &ib_event->param.req_rcvd, 2146628e5f6dSSean Hefty ib_event->private_data, offset); 2147628e5f6dSSean Hefty } 2148e51060f0SSean Hefty if (!conn_id) { 2149e51060f0SSean Hefty ret = -ENOMEM; 2150b6cec8aaSSean Hefty goto err1; 2151e51060f0SSean Hefty } 2152e51060f0SSean Hefty 2153de910bd9SOr Gerlitz mutex_lock_nested(&conn_id->handler_mutex, SINGLE_DEPTH_NESTING); 215441ab1cb7SParav Pandit ret = cma_ib_acquire_dev(conn_id, listen_id, &req); 2155a1a733f6SKrishna Kumar if (ret) 2156b6cec8aaSSean Hefty goto err2; 2157e51060f0SSean Hefty 2158e51060f0SSean Hefty conn_id->cm_id.ib = cm_id; 2159e51060f0SSean Hefty cm_id->context = conn_id; 2160e51060f0SSean Hefty cm_id->cm_handler = cma_ib_handler; 2161e51060f0SSean Hefty 216225ae21a1SSean Hefty /* 216325ae21a1SSean Hefty * Protect against the user destroying conn_id from another thread 216425ae21a1SSean Hefty * until we're done accessing it. 216525ae21a1SSean Hefty */ 216625ae21a1SSean Hefty atomic_inc(&conn_id->refcount); 2167a1b1b61fSSean Hefty ret = conn_id->id.event_handler(&conn_id->id, &event); 2168b6cec8aaSSean Hefty if (ret) 2169b6cec8aaSSean Hefty goto err3; 2170ead595aeSSean Hefty /* 2171ead595aeSSean Hefty * Acquire mutex to prevent user executing rdma_destroy_id() 2172ead595aeSSean Hefty * while we're accessing the cm_id. 2173ead595aeSSean Hefty */ 2174ead595aeSSean Hefty mutex_lock(&lock); 2175dd5f03beSMatan Barak if (cma_comp(conn_id, RDMA_CM_CONNECT) && 2176dd5f03beSMatan Barak (conn_id->id.qp_type != IB_QPT_UD)) 2177ead595aeSSean Hefty ib_send_cm_mra(cm_id, CMA_CM_MRA_SETTING, NULL, 0); 2178ead595aeSSean Hefty mutex_unlock(&lock); 2179de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 2180b6cec8aaSSean Hefty mutex_unlock(&listen_id->handler_mutex); 218125ae21a1SSean Hefty cma_deref_id(conn_id); 21820b3ca768SHaggai Eran if (net_dev) 21830b3ca768SHaggai Eran dev_put(net_dev); 2184b6cec8aaSSean Hefty return 0; 2185a1a733f6SKrishna Kumar 2186b6cec8aaSSean Hefty err3: 2187b6cec8aaSSean Hefty cma_deref_id(conn_id); 2188e51060f0SSean Hefty /* Destroy the CM ID by returning a non-zero value. */ 2189e51060f0SSean Hefty conn_id->cm_id.ib = NULL; 2190b6cec8aaSSean Hefty err2: 2191550e5ca7SNir Muchtar cma_exch(conn_id, RDMA_CM_DESTROYING); 2192de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 2193b6cec8aaSSean Hefty err1: 2194de910bd9SOr Gerlitz mutex_unlock(&listen_id->handler_mutex); 2195b6cec8aaSSean Hefty if (conn_id) 2196b6cec8aaSSean Hefty rdma_destroy_id(&conn_id->id); 21970b3ca768SHaggai Eran 21980b3ca768SHaggai Eran net_dev_put: 21990b3ca768SHaggai Eran if (net_dev) 22000b3ca768SHaggai Eran dev_put(net_dev); 22010b3ca768SHaggai Eran 2202e51060f0SSean Hefty return ret; 2203e51060f0SSean Hefty } 2204e51060f0SSean Hefty 2205cf53936fSSean Hefty __be64 rdma_get_service_id(struct rdma_cm_id *id, struct sockaddr *addr) 2206e51060f0SSean Hefty { 2207496ce3ceSSean Hefty if (addr->sa_family == AF_IB) 2208496ce3ceSSean Hefty return ((struct sockaddr_ib *) addr)->sib_sid; 2209496ce3ceSSean Hefty 2210cf53936fSSean Hefty return cpu_to_be64(((u64)id->ps << 16) + be16_to_cpu(cma_port(addr))); 2211e51060f0SSean Hefty } 2212cf53936fSSean Hefty EXPORT_SYMBOL(rdma_get_service_id); 2213e51060f0SSean Hefty 2214411460acSParav Pandit void rdma_read_gids(struct rdma_cm_id *cm_id, union ib_gid *sgid, 2215411460acSParav Pandit union ib_gid *dgid) 2216411460acSParav Pandit { 2217411460acSParav Pandit struct rdma_addr *addr = &cm_id->route.addr; 2218411460acSParav Pandit 2219411460acSParav Pandit if (!cm_id->device) { 2220411460acSParav Pandit if (sgid) 2221411460acSParav Pandit memset(sgid, 0, sizeof(*sgid)); 2222411460acSParav Pandit if (dgid) 2223411460acSParav Pandit memset(dgid, 0, sizeof(*dgid)); 2224411460acSParav Pandit return; 2225411460acSParav Pandit } 2226411460acSParav Pandit 2227411460acSParav Pandit if (rdma_protocol_roce(cm_id->device, cm_id->port_num)) { 2228411460acSParav Pandit if (sgid) 2229411460acSParav Pandit rdma_ip2gid((struct sockaddr *)&addr->src_addr, sgid); 2230411460acSParav Pandit if (dgid) 2231411460acSParav Pandit rdma_ip2gid((struct sockaddr *)&addr->dst_addr, dgid); 2232411460acSParav Pandit } else { 2233411460acSParav Pandit if (sgid) 2234411460acSParav Pandit rdma_addr_get_sgid(&addr->dev_addr, sgid); 2235411460acSParav Pandit if (dgid) 2236411460acSParav Pandit rdma_addr_get_dgid(&addr->dev_addr, dgid); 2237411460acSParav Pandit } 2238411460acSParav Pandit } 2239411460acSParav Pandit EXPORT_SYMBOL(rdma_read_gids); 2240411460acSParav Pandit 224107ebafbaSTom Tucker static int cma_iw_handler(struct iw_cm_id *iw_id, struct iw_cm_event *iw_event) 224207ebafbaSTom Tucker { 224307ebafbaSTom Tucker struct rdma_id_private *id_priv = iw_id->context; 22447582df82SParav Pandit struct rdma_cm_event event = {}; 224507ebafbaSTom Tucker int ret = 0; 224624d44a39SSteve Wise struct sockaddr *laddr = (struct sockaddr *)&iw_event->local_addr; 224724d44a39SSteve Wise struct sockaddr *raddr = (struct sockaddr *)&iw_event->remote_addr; 224807ebafbaSTom Tucker 224937e07cdaSBart Van Assche mutex_lock(&id_priv->handler_mutex); 225037e07cdaSBart Van Assche if (id_priv->state != RDMA_CM_CONNECT) 225137e07cdaSBart Van Assche goto out; 225207ebafbaSTom Tucker 225307ebafbaSTom Tucker switch (iw_event->event) { 225407ebafbaSTom Tucker case IW_CM_EVENT_CLOSE: 2255a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_DISCONNECTED; 225607ebafbaSTom Tucker break; 225707ebafbaSTom Tucker case IW_CM_EVENT_CONNECT_REPLY: 225824d44a39SSteve Wise memcpy(cma_src_addr(id_priv), laddr, 225924d44a39SSteve Wise rdma_addr_size(laddr)); 226024d44a39SSteve Wise memcpy(cma_dst_addr(id_priv), raddr, 226124d44a39SSteve Wise rdma_addr_size(raddr)); 2262881a045fSSteve Wise switch (iw_event->status) { 2263881a045fSSteve Wise case 0: 2264a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_ESTABLISHED; 22653ebeebc3SKumar Sanghvi event.param.conn.initiator_depth = iw_event->ird; 22663ebeebc3SKumar Sanghvi event.param.conn.responder_resources = iw_event->ord; 226707ebafbaSTom Tucker break; 2268881a045fSSteve Wise case -ECONNRESET: 2269881a045fSSteve Wise case -ECONNREFUSED: 2270881a045fSSteve Wise event.event = RDMA_CM_EVENT_REJECTED; 2271881a045fSSteve Wise break; 2272881a045fSSteve Wise case -ETIMEDOUT: 2273881a045fSSteve Wise event.event = RDMA_CM_EVENT_UNREACHABLE; 2274881a045fSSteve Wise break; 2275881a045fSSteve Wise default: 2276881a045fSSteve Wise event.event = RDMA_CM_EVENT_CONNECT_ERROR; 2277881a045fSSteve Wise break; 2278881a045fSSteve Wise } 2279881a045fSSteve Wise break; 228007ebafbaSTom Tucker case IW_CM_EVENT_ESTABLISHED: 2281a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_ESTABLISHED; 22823ebeebc3SKumar Sanghvi event.param.conn.initiator_depth = iw_event->ird; 22833ebeebc3SKumar Sanghvi event.param.conn.responder_resources = iw_event->ord; 228407ebafbaSTom Tucker break; 228507ebafbaSTom Tucker default: 2286671a6cc2SLeon Romanovsky goto out; 228707ebafbaSTom Tucker } 228807ebafbaSTom Tucker 2289a1b1b61fSSean Hefty event.status = iw_event->status; 2290a1b1b61fSSean Hefty event.param.conn.private_data = iw_event->private_data; 2291a1b1b61fSSean Hefty event.param.conn.private_data_len = iw_event->private_data_len; 2292a1b1b61fSSean Hefty ret = id_priv->id.event_handler(&id_priv->id, &event); 229307ebafbaSTom Tucker if (ret) { 229407ebafbaSTom Tucker /* Destroy the CM ID by returning a non-zero value. */ 229507ebafbaSTom Tucker id_priv->cm_id.iw = NULL; 2296550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 2297de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 229807ebafbaSTom Tucker rdma_destroy_id(&id_priv->id); 229907ebafbaSTom Tucker return ret; 230007ebafbaSTom Tucker } 230107ebafbaSTom Tucker 230237e07cdaSBart Van Assche out: 2303de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 230407ebafbaSTom Tucker return ret; 230507ebafbaSTom Tucker } 230607ebafbaSTom Tucker 230707ebafbaSTom Tucker static int iw_conn_req_handler(struct iw_cm_id *cm_id, 230807ebafbaSTom Tucker struct iw_cm_event *iw_event) 230907ebafbaSTom Tucker { 231007ebafbaSTom Tucker struct rdma_cm_id *new_cm_id; 231107ebafbaSTom Tucker struct rdma_id_private *listen_id, *conn_id; 23127582df82SParav Pandit struct rdma_cm_event event = {}; 231337e07cdaSBart Van Assche int ret = -ECONNABORTED; 231424d44a39SSteve Wise struct sockaddr *laddr = (struct sockaddr *)&iw_event->local_addr; 231524d44a39SSteve Wise struct sockaddr *raddr = (struct sockaddr *)&iw_event->remote_addr; 231607ebafbaSTom Tucker 23177582df82SParav Pandit event.event = RDMA_CM_EVENT_CONNECT_REQUEST; 23187582df82SParav Pandit event.param.conn.private_data = iw_event->private_data; 23197582df82SParav Pandit event.param.conn.private_data_len = iw_event->private_data_len; 23207582df82SParav Pandit event.param.conn.initiator_depth = iw_event->ird; 23217582df82SParav Pandit event.param.conn.responder_resources = iw_event->ord; 23227582df82SParav Pandit 232307ebafbaSTom Tucker listen_id = cm_id->context; 232437e07cdaSBart Van Assche 232537e07cdaSBart Van Assche mutex_lock(&listen_id->handler_mutex); 232637e07cdaSBart Van Assche if (listen_id->state != RDMA_CM_LISTEN) 232737e07cdaSBart Van Assche goto out; 232807ebafbaSTom Tucker 232907ebafbaSTom Tucker /* Create a new RDMA id for the new IW CM ID */ 233000313983SSteve Wise new_cm_id = __rdma_create_id(listen_id->id.route.addr.dev_addr.net, 2331fa20105eSGuy Shapiro listen_id->id.event_handler, 233207ebafbaSTom Tucker listen_id->id.context, 233300313983SSteve Wise RDMA_PS_TCP, IB_QPT_RC, 233400313983SSteve Wise listen_id->res.kern_name); 233510f32065SJulia Lawall if (IS_ERR(new_cm_id)) { 233607ebafbaSTom Tucker ret = -ENOMEM; 233707ebafbaSTom Tucker goto out; 233807ebafbaSTom Tucker } 233907ebafbaSTom Tucker conn_id = container_of(new_cm_id, struct rdma_id_private, id); 2340de910bd9SOr Gerlitz mutex_lock_nested(&conn_id->handler_mutex, SINGLE_DEPTH_NESTING); 2341550e5ca7SNir Muchtar conn_id->state = RDMA_CM_CONNECT; 234207ebafbaSTom Tucker 2343575c7e58SParav Pandit ret = rdma_translate_ip(laddr, &conn_id->id.route.addr.dev_addr); 234407ebafbaSTom Tucker if (ret) { 2345de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 234607ebafbaSTom Tucker rdma_destroy_id(new_cm_id); 234707ebafbaSTom Tucker goto out; 234807ebafbaSTom Tucker } 234907ebafbaSTom Tucker 235041ab1cb7SParav Pandit ret = cma_iw_acquire_dev(conn_id, listen_id); 235107ebafbaSTom Tucker if (ret) { 2352de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 235307ebafbaSTom Tucker rdma_destroy_id(new_cm_id); 235407ebafbaSTom Tucker goto out; 235507ebafbaSTom Tucker } 235607ebafbaSTom Tucker 235707ebafbaSTom Tucker conn_id->cm_id.iw = cm_id; 235807ebafbaSTom Tucker cm_id->context = conn_id; 235907ebafbaSTom Tucker cm_id->cm_handler = cma_iw_handler; 236007ebafbaSTom Tucker 236124d44a39SSteve Wise memcpy(cma_src_addr(conn_id), laddr, rdma_addr_size(laddr)); 236224d44a39SSteve Wise memcpy(cma_dst_addr(conn_id), raddr, rdma_addr_size(raddr)); 236307ebafbaSTom Tucker 236425ae21a1SSean Hefty /* 236525ae21a1SSean Hefty * Protect against the user destroying conn_id from another thread 236625ae21a1SSean Hefty * until we're done accessing it. 236725ae21a1SSean Hefty */ 236825ae21a1SSean Hefty atomic_inc(&conn_id->refcount); 2369a1b1b61fSSean Hefty ret = conn_id->id.event_handler(&conn_id->id, &event); 237007ebafbaSTom Tucker if (ret) { 237107ebafbaSTom Tucker /* User wants to destroy the CM ID */ 237207ebafbaSTom Tucker conn_id->cm_id.iw = NULL; 2373550e5ca7SNir Muchtar cma_exch(conn_id, RDMA_CM_DESTROYING); 2374de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 237525ae21a1SSean Hefty cma_deref_id(conn_id); 237607ebafbaSTom Tucker rdma_destroy_id(&conn_id->id); 2377de910bd9SOr Gerlitz goto out; 237807ebafbaSTom Tucker } 237907ebafbaSTom Tucker 2380de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 238125ae21a1SSean Hefty cma_deref_id(conn_id); 2382de910bd9SOr Gerlitz 238307ebafbaSTom Tucker out: 2384de910bd9SOr Gerlitz mutex_unlock(&listen_id->handler_mutex); 238507ebafbaSTom Tucker return ret; 238607ebafbaSTom Tucker } 238707ebafbaSTom Tucker 2388e51060f0SSean Hefty static int cma_ib_listen(struct rdma_id_private *id_priv) 2389e51060f0SSean Hefty { 2390e51060f0SSean Hefty struct sockaddr *addr; 23910c9361fcSJack Morgenstein struct ib_cm_id *id; 2392e51060f0SSean Hefty __be64 svc_id; 2393e51060f0SSean Hefty 2394f4753834SSean Hefty addr = cma_src_addr(id_priv); 2395cf53936fSSean Hefty svc_id = rdma_get_service_id(&id_priv->id, addr); 239685463316SParav Pandit id = ib_cm_insert_listen(id_priv->id.device, 239785463316SParav Pandit cma_ib_req_handler, svc_id); 239851efe394SHaggai Eran if (IS_ERR(id)) 239951efe394SHaggai Eran return PTR_ERR(id); 240051efe394SHaggai Eran id_priv->cm_id.ib = id; 2401e51060f0SSean Hefty 240251efe394SHaggai Eran return 0; 2403e51060f0SSean Hefty } 2404e51060f0SSean Hefty 240507ebafbaSTom Tucker static int cma_iw_listen(struct rdma_id_private *id_priv, int backlog) 240607ebafbaSTom Tucker { 240707ebafbaSTom Tucker int ret; 24080c9361fcSJack Morgenstein struct iw_cm_id *id; 240907ebafbaSTom Tucker 24100c9361fcSJack Morgenstein id = iw_create_cm_id(id_priv->id.device, 241107ebafbaSTom Tucker iw_conn_req_handler, 241207ebafbaSTom Tucker id_priv); 24130c9361fcSJack Morgenstein if (IS_ERR(id)) 24140c9361fcSJack Morgenstein return PTR_ERR(id); 24150c9361fcSJack Morgenstein 241668cdba06SSteve Wise id->tos = id_priv->tos; 24170c9361fcSJack Morgenstein id_priv->cm_id.iw = id; 241807ebafbaSTom Tucker 241924d44a39SSteve Wise memcpy(&id_priv->cm_id.iw->local_addr, cma_src_addr(id_priv), 242024d44a39SSteve Wise rdma_addr_size(cma_src_addr(id_priv))); 242107ebafbaSTom Tucker 242207ebafbaSTom Tucker ret = iw_cm_listen(id_priv->cm_id.iw, backlog); 242307ebafbaSTom Tucker 242407ebafbaSTom Tucker if (ret) { 242507ebafbaSTom Tucker iw_destroy_cm_id(id_priv->cm_id.iw); 242607ebafbaSTom Tucker id_priv->cm_id.iw = NULL; 242707ebafbaSTom Tucker } 242807ebafbaSTom Tucker 242907ebafbaSTom Tucker return ret; 243007ebafbaSTom Tucker } 243107ebafbaSTom Tucker 2432e51060f0SSean Hefty static int cma_listen_handler(struct rdma_cm_id *id, 2433e51060f0SSean Hefty struct rdma_cm_event *event) 2434e51060f0SSean Hefty { 2435e51060f0SSean Hefty struct rdma_id_private *id_priv = id->context; 2436e51060f0SSean Hefty 2437e51060f0SSean Hefty id->context = id_priv->id.context; 2438e51060f0SSean Hefty id->event_handler = id_priv->id.event_handler; 2439e51060f0SSean Hefty return id_priv->id.event_handler(id, event); 2440e51060f0SSean Hefty } 2441e51060f0SSean Hefty 2442e51060f0SSean Hefty static void cma_listen_on_dev(struct rdma_id_private *id_priv, 2443e51060f0SSean Hefty struct cma_device *cma_dev) 2444e51060f0SSean Hefty { 2445e51060f0SSean Hefty struct rdma_id_private *dev_id_priv; 2446e51060f0SSean Hefty struct rdma_cm_id *id; 2447fa20105eSGuy Shapiro struct net *net = id_priv->id.route.addr.dev_addr.net; 2448e51060f0SSean Hefty int ret; 2449e51060f0SSean Hefty 245072219ceaSMichael Wang if (cma_family(id_priv) == AF_IB && !rdma_cap_ib_cm(cma_dev->device, 1)) 245194d0c939SSean Hefty return; 245294d0c939SSean Hefty 245300313983SSteve Wise id = __rdma_create_id(net, cma_listen_handler, id_priv, id_priv->id.ps, 245400313983SSteve Wise id_priv->id.qp_type, id_priv->res.kern_name); 2455e51060f0SSean Hefty if (IS_ERR(id)) 2456e51060f0SSean Hefty return; 2457e51060f0SSean Hefty 2458e51060f0SSean Hefty dev_id_priv = container_of(id, struct rdma_id_private, id); 2459e51060f0SSean Hefty 2460550e5ca7SNir Muchtar dev_id_priv->state = RDMA_CM_ADDR_BOUND; 2461f4753834SSean Hefty memcpy(cma_src_addr(dev_id_priv), cma_src_addr(id_priv), 2462f4753834SSean Hefty rdma_addr_size(cma_src_addr(id_priv))); 2463e51060f0SSean Hefty 2464045959dbSMatan Barak _cma_attach_to_dev(dev_id_priv, cma_dev); 2465e51060f0SSean Hefty list_add_tail(&dev_id_priv->listen_list, &id_priv->listen_list); 2466d02d1f53SSean Hefty atomic_inc(&id_priv->refcount); 2467d02d1f53SSean Hefty dev_id_priv->internal_id = 1; 24685b0ec991SSean Hefty dev_id_priv->afonly = id_priv->afonly; 2469e51060f0SSean Hefty 2470e51060f0SSean Hefty ret = rdma_listen(id, id_priv->backlog); 2471e51060f0SSean Hefty if (ret) 247243c7c851SJason Gunthorpe dev_warn(&cma_dev->device->dev, 247343c7c851SJason Gunthorpe "RDMA CMA: cma_listen_on_dev, error %d\n", ret); 2474e51060f0SSean Hefty } 2475e51060f0SSean Hefty 2476e51060f0SSean Hefty static void cma_listen_on_all(struct rdma_id_private *id_priv) 2477e51060f0SSean Hefty { 2478e51060f0SSean Hefty struct cma_device *cma_dev; 2479e51060f0SSean Hefty 2480e51060f0SSean Hefty mutex_lock(&lock); 2481e51060f0SSean Hefty list_add_tail(&id_priv->list, &listen_any_list); 2482e51060f0SSean Hefty list_for_each_entry(cma_dev, &dev_list, list) 2483e51060f0SSean Hefty cma_listen_on_dev(id_priv, cma_dev); 2484e51060f0SSean Hefty mutex_unlock(&lock); 2485e51060f0SSean Hefty } 2486e51060f0SSean Hefty 2487a81c994dSSean Hefty void rdma_set_service_type(struct rdma_cm_id *id, int tos) 2488a81c994dSSean Hefty { 2489a81c994dSSean Hefty struct rdma_id_private *id_priv; 2490a81c994dSSean Hefty 2491a81c994dSSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 2492a81c994dSSean Hefty id_priv->tos = (u8) tos; 249389052d78SMajd Dibbiny id_priv->tos_set = true; 2494a81c994dSSean Hefty } 2495a81c994dSSean Hefty EXPORT_SYMBOL(rdma_set_service_type); 2496a81c994dSSean Hefty 2497*2c1619edSDanit Goldberg /** 2498*2c1619edSDanit Goldberg * rdma_set_ack_timeout() - Set the ack timeout of QP associated 2499*2c1619edSDanit Goldberg * with a connection identifier. 2500*2c1619edSDanit Goldberg * @id: Communication identifier to associated with service type. 2501*2c1619edSDanit Goldberg * @timeout: Ack timeout to set a QP, expressed as 4.096 * 2^(timeout) usec. 2502*2c1619edSDanit Goldberg * 2503*2c1619edSDanit Goldberg * This function should be called before rdma_connect() on active side, 2504*2c1619edSDanit Goldberg * and on passive side before rdma_accept(). It is applicable to primary 2505*2c1619edSDanit Goldberg * path only. The timeout will affect the local side of the QP, it is not 2506*2c1619edSDanit Goldberg * negotiated with remote side and zero disables the timer. 2507*2c1619edSDanit Goldberg * 2508*2c1619edSDanit Goldberg * Return: 0 for success 2509*2c1619edSDanit Goldberg */ 2510*2c1619edSDanit Goldberg int rdma_set_ack_timeout(struct rdma_cm_id *id, u8 timeout) 2511*2c1619edSDanit Goldberg { 2512*2c1619edSDanit Goldberg struct rdma_id_private *id_priv; 2513*2c1619edSDanit Goldberg 2514*2c1619edSDanit Goldberg if (id->qp_type != IB_QPT_RC) 2515*2c1619edSDanit Goldberg return -EINVAL; 2516*2c1619edSDanit Goldberg 2517*2c1619edSDanit Goldberg id_priv = container_of(id, struct rdma_id_private, id); 2518*2c1619edSDanit Goldberg id_priv->timeout = timeout; 2519*2c1619edSDanit Goldberg id_priv->timeout_set = true; 2520*2c1619edSDanit Goldberg 2521*2c1619edSDanit Goldberg return 0; 2522*2c1619edSDanit Goldberg } 2523*2c1619edSDanit Goldberg EXPORT_SYMBOL(rdma_set_ack_timeout); 2524*2c1619edSDanit Goldberg 2525c2f8fc4eSDasaratharaman Chandramouli static void cma_query_handler(int status, struct sa_path_rec *path_rec, 2526e51060f0SSean Hefty void *context) 2527e51060f0SSean Hefty { 2528e51060f0SSean Hefty struct cma_work *work = context; 2529e51060f0SSean Hefty struct rdma_route *route; 2530e51060f0SSean Hefty 2531e51060f0SSean Hefty route = &work->id->id.route; 2532e51060f0SSean Hefty 2533e51060f0SSean Hefty if (!status) { 2534e51060f0SSean Hefty route->num_paths = 1; 2535e51060f0SSean Hefty *route->path_rec = *path_rec; 2536e51060f0SSean Hefty } else { 2537550e5ca7SNir Muchtar work->old_state = RDMA_CM_ROUTE_QUERY; 2538550e5ca7SNir Muchtar work->new_state = RDMA_CM_ADDR_RESOLVED; 2539e51060f0SSean Hefty work->event.event = RDMA_CM_EVENT_ROUTE_ERROR; 25408f0472d3SSean Hefty work->event.status = status; 2541498683c6SMoni Shoua pr_debug_ratelimited("RDMA CM: ROUTE_ERROR: failed to query path. status %d\n", 2542498683c6SMoni Shoua status); 2543e51060f0SSean Hefty } 2544e51060f0SSean Hefty 2545e51060f0SSean Hefty queue_work(cma_wq, &work->work); 2546e51060f0SSean Hefty } 2547e51060f0SSean Hefty 2548dbace111SLeon Romanovsky static int cma_query_ib_route(struct rdma_id_private *id_priv, 2549dbace111SLeon Romanovsky unsigned long timeout_ms, struct cma_work *work) 2550e51060f0SSean Hefty { 2551f4753834SSean Hefty struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 2552c2f8fc4eSDasaratharaman Chandramouli struct sa_path_rec path_rec; 2553a81c994dSSean Hefty ib_sa_comp_mask comp_mask; 2554a81c994dSSean Hefty struct sockaddr_in6 *sin6; 2555f68194caSSean Hefty struct sockaddr_ib *sib; 2556e51060f0SSean Hefty 2557e51060f0SSean Hefty memset(&path_rec, 0, sizeof path_rec); 25584c33bd19SDasaratharaman Chandramouli 25594c33bd19SDasaratharaman Chandramouli if (rdma_cap_opa_ah(id_priv->id.device, id_priv->id.port_num)) 25604c33bd19SDasaratharaman Chandramouli path_rec.rec_type = SA_PATH_REC_TYPE_OPA; 25614c33bd19SDasaratharaman Chandramouli else 25629fdca4daSDasaratharaman Chandramouli path_rec.rec_type = SA_PATH_REC_TYPE_IB; 2563f4753834SSean Hefty rdma_addr_get_sgid(dev_addr, &path_rec.sgid); 2564f4753834SSean Hefty rdma_addr_get_dgid(dev_addr, &path_rec.dgid); 2565f4753834SSean Hefty path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr)); 2566e51060f0SSean Hefty path_rec.numb_path = 1; 2567962063e6SSean Hefty path_rec.reversible = 1; 2568d3957b86SMajd Dibbiny path_rec.service_id = rdma_get_service_id(&id_priv->id, 2569d3957b86SMajd Dibbiny cma_dst_addr(id_priv)); 2570a81c994dSSean Hefty 2571a81c994dSSean Hefty comp_mask = IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID | 2572a81c994dSSean Hefty IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH | 2573a81c994dSSean Hefty IB_SA_PATH_REC_REVERSIBLE | IB_SA_PATH_REC_SERVICE_ID; 2574a81c994dSSean Hefty 2575f68194caSSean Hefty switch (cma_family(id_priv)) { 2576f68194caSSean Hefty case AF_INET: 2577a81c994dSSean Hefty path_rec.qos_class = cpu_to_be16((u16) id_priv->tos); 2578a81c994dSSean Hefty comp_mask |= IB_SA_PATH_REC_QOS_CLASS; 2579f68194caSSean Hefty break; 2580f68194caSSean Hefty case AF_INET6: 2581f4753834SSean Hefty sin6 = (struct sockaddr_in6 *) cma_src_addr(id_priv); 2582a81c994dSSean Hefty path_rec.traffic_class = (u8) (be32_to_cpu(sin6->sin6_flowinfo) >> 20); 2583a81c994dSSean Hefty comp_mask |= IB_SA_PATH_REC_TRAFFIC_CLASS; 2584f68194caSSean Hefty break; 2585f68194caSSean Hefty case AF_IB: 2586f68194caSSean Hefty sib = (struct sockaddr_ib *) cma_src_addr(id_priv); 2587f68194caSSean Hefty path_rec.traffic_class = (u8) (be32_to_cpu(sib->sib_flowinfo) >> 20); 2588f68194caSSean Hefty comp_mask |= IB_SA_PATH_REC_TRAFFIC_CLASS; 2589f68194caSSean Hefty break; 2590a81c994dSSean Hefty } 2591e51060f0SSean Hefty 2592c1a0b23bSMichael S. Tsirkin id_priv->query_id = ib_sa_path_rec_get(&sa_client, id_priv->id.device, 2593e51060f0SSean Hefty id_priv->id.port_num, &path_rec, 2594a81c994dSSean Hefty comp_mask, timeout_ms, 2595a81c994dSSean Hefty GFP_KERNEL, cma_query_handler, 2596a81c994dSSean Hefty work, &id_priv->query); 2597e51060f0SSean Hefty 2598e51060f0SSean Hefty return (id_priv->query_id < 0) ? id_priv->query_id : 0; 2599e51060f0SSean Hefty } 2600e51060f0SSean Hefty 2601c4028958SDavid Howells static void cma_work_handler(struct work_struct *_work) 2602e51060f0SSean Hefty { 2603c4028958SDavid Howells struct cma_work *work = container_of(_work, struct cma_work, work); 2604e51060f0SSean Hefty struct rdma_id_private *id_priv = work->id; 2605e51060f0SSean Hefty int destroy = 0; 2606e51060f0SSean Hefty 2607de910bd9SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 2608e51060f0SSean Hefty if (!cma_comp_exch(id_priv, work->old_state, work->new_state)) 2609e51060f0SSean Hefty goto out; 2610e51060f0SSean Hefty 2611e51060f0SSean Hefty if (id_priv->id.event_handler(&id_priv->id, &work->event)) { 2612550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 2613e51060f0SSean Hefty destroy = 1; 2614e51060f0SSean Hefty } 2615e51060f0SSean Hefty out: 2616de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 2617e51060f0SSean Hefty cma_deref_id(id_priv); 2618e51060f0SSean Hefty if (destroy) 2619e51060f0SSean Hefty rdma_destroy_id(&id_priv->id); 2620e51060f0SSean Hefty kfree(work); 2621e51060f0SSean Hefty } 2622e51060f0SSean Hefty 2623dd5bdff8SOr Gerlitz static void cma_ndev_work_handler(struct work_struct *_work) 2624dd5bdff8SOr Gerlitz { 2625dd5bdff8SOr Gerlitz struct cma_ndev_work *work = container_of(_work, struct cma_ndev_work, work); 2626dd5bdff8SOr Gerlitz struct rdma_id_private *id_priv = work->id; 2627dd5bdff8SOr Gerlitz int destroy = 0; 2628dd5bdff8SOr Gerlitz 2629dd5bdff8SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 2630550e5ca7SNir Muchtar if (id_priv->state == RDMA_CM_DESTROYING || 2631550e5ca7SNir Muchtar id_priv->state == RDMA_CM_DEVICE_REMOVAL) 2632dd5bdff8SOr Gerlitz goto out; 2633dd5bdff8SOr Gerlitz 2634dd5bdff8SOr Gerlitz if (id_priv->id.event_handler(&id_priv->id, &work->event)) { 2635550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 2636dd5bdff8SOr Gerlitz destroy = 1; 2637dd5bdff8SOr Gerlitz } 2638dd5bdff8SOr Gerlitz 2639dd5bdff8SOr Gerlitz out: 2640dd5bdff8SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 2641dd5bdff8SOr Gerlitz cma_deref_id(id_priv); 2642dd5bdff8SOr Gerlitz if (destroy) 2643dd5bdff8SOr Gerlitz rdma_destroy_id(&id_priv->id); 2644dd5bdff8SOr Gerlitz kfree(work); 2645dd5bdff8SOr Gerlitz } 2646dd5bdff8SOr Gerlitz 2647981b5a23SParav Pandit static void cma_init_resolve_route_work(struct cma_work *work, 2648981b5a23SParav Pandit struct rdma_id_private *id_priv) 2649981b5a23SParav Pandit { 2650981b5a23SParav Pandit work->id = id_priv; 2651981b5a23SParav Pandit INIT_WORK(&work->work, cma_work_handler); 2652981b5a23SParav Pandit work->old_state = RDMA_CM_ROUTE_QUERY; 2653981b5a23SParav Pandit work->new_state = RDMA_CM_ROUTE_RESOLVED; 2654981b5a23SParav Pandit work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED; 2655981b5a23SParav Pandit } 2656981b5a23SParav Pandit 2657981b5a23SParav Pandit static void cma_init_resolve_addr_work(struct cma_work *work, 2658981b5a23SParav Pandit struct rdma_id_private *id_priv) 2659981b5a23SParav Pandit { 2660981b5a23SParav Pandit work->id = id_priv; 2661981b5a23SParav Pandit INIT_WORK(&work->work, cma_work_handler); 2662981b5a23SParav Pandit work->old_state = RDMA_CM_ADDR_QUERY; 2663981b5a23SParav Pandit work->new_state = RDMA_CM_ADDR_RESOLVED; 2664981b5a23SParav Pandit work->event.event = RDMA_CM_EVENT_ADDR_RESOLVED; 2665981b5a23SParav Pandit } 2666981b5a23SParav Pandit 2667dbace111SLeon Romanovsky static int cma_resolve_ib_route(struct rdma_id_private *id_priv, 2668dbace111SLeon Romanovsky unsigned long timeout_ms) 2669e51060f0SSean Hefty { 2670e51060f0SSean Hefty struct rdma_route *route = &id_priv->id.route; 2671e51060f0SSean Hefty struct cma_work *work; 2672e51060f0SSean Hefty int ret; 2673e51060f0SSean Hefty 2674e51060f0SSean Hefty work = kzalloc(sizeof *work, GFP_KERNEL); 2675e51060f0SSean Hefty if (!work) 2676e51060f0SSean Hefty return -ENOMEM; 2677e51060f0SSean Hefty 2678981b5a23SParav Pandit cma_init_resolve_route_work(work, id_priv); 2679e51060f0SSean Hefty 2680e51060f0SSean Hefty route->path_rec = kmalloc(sizeof *route->path_rec, GFP_KERNEL); 2681e51060f0SSean Hefty if (!route->path_rec) { 2682e51060f0SSean Hefty ret = -ENOMEM; 2683e51060f0SSean Hefty goto err1; 2684e51060f0SSean Hefty } 2685e51060f0SSean Hefty 2686e51060f0SSean Hefty ret = cma_query_ib_route(id_priv, timeout_ms, work); 2687e51060f0SSean Hefty if (ret) 2688e51060f0SSean Hefty goto err2; 2689e51060f0SSean Hefty 2690e51060f0SSean Hefty return 0; 2691e51060f0SSean Hefty err2: 2692e51060f0SSean Hefty kfree(route->path_rec); 2693e51060f0SSean Hefty route->path_rec = NULL; 2694e51060f0SSean Hefty err1: 2695e51060f0SSean Hefty kfree(work); 2696e51060f0SSean Hefty return ret; 2697e51060f0SSean Hefty } 2698e51060f0SSean Hefty 26999327c7afSParav Pandit static enum ib_gid_type cma_route_gid_type(enum rdma_network_type network_type, 27009327c7afSParav Pandit unsigned long supported_gids, 27019327c7afSParav Pandit enum ib_gid_type default_gid) 27029327c7afSParav Pandit { 27039327c7afSParav Pandit if ((network_type == RDMA_NETWORK_IPV4 || 27049327c7afSParav Pandit network_type == RDMA_NETWORK_IPV6) && 27059327c7afSParav Pandit test_bit(IB_GID_TYPE_ROCE_UDP_ENCAP, &supported_gids)) 27069327c7afSParav Pandit return IB_GID_TYPE_ROCE_UDP_ENCAP; 27079327c7afSParav Pandit 27089327c7afSParav Pandit return default_gid; 27099327c7afSParav Pandit } 27109327c7afSParav Pandit 27119327c7afSParav Pandit /* 27129327c7afSParav Pandit * cma_iboe_set_path_rec_l2_fields() is helper function which sets 27139327c7afSParav Pandit * path record type based on GID type. 27149327c7afSParav Pandit * It also sets up other L2 fields which includes destination mac address 27159327c7afSParav Pandit * netdev ifindex, of the path record. 27169327c7afSParav Pandit * It returns the netdev of the bound interface for this path record entry. 27179327c7afSParav Pandit */ 27189327c7afSParav Pandit static struct net_device * 27199327c7afSParav Pandit cma_iboe_set_path_rec_l2_fields(struct rdma_id_private *id_priv) 27209327c7afSParav Pandit { 27219327c7afSParav Pandit struct rdma_route *route = &id_priv->id.route; 27229327c7afSParav Pandit enum ib_gid_type gid_type = IB_GID_TYPE_ROCE; 27239327c7afSParav Pandit struct rdma_addr *addr = &route->addr; 27249327c7afSParav Pandit unsigned long supported_gids; 27259327c7afSParav Pandit struct net_device *ndev; 27269327c7afSParav Pandit 27279327c7afSParav Pandit if (!addr->dev_addr.bound_dev_if) 27289327c7afSParav Pandit return NULL; 27299327c7afSParav Pandit 27309327c7afSParav Pandit ndev = dev_get_by_index(addr->dev_addr.net, 27319327c7afSParav Pandit addr->dev_addr.bound_dev_if); 27329327c7afSParav Pandit if (!ndev) 27339327c7afSParav Pandit return NULL; 27349327c7afSParav Pandit 27359327c7afSParav Pandit supported_gids = roce_gid_type_mask_support(id_priv->id.device, 27369327c7afSParav Pandit id_priv->id.port_num); 27379327c7afSParav Pandit gid_type = cma_route_gid_type(addr->dev_addr.network, 27389327c7afSParav Pandit supported_gids, 27399327c7afSParav Pandit id_priv->gid_type); 27409327c7afSParav Pandit /* Use the hint from IP Stack to select GID Type */ 27419327c7afSParav Pandit if (gid_type < ib_network_to_gid_type(addr->dev_addr.network)) 27429327c7afSParav Pandit gid_type = ib_network_to_gid_type(addr->dev_addr.network); 27439327c7afSParav Pandit route->path_rec->rec_type = sa_conv_gid_to_pathrec_type(gid_type); 27449327c7afSParav Pandit 2745114cc9c4SParav Pandit route->path_rec->roce.route_resolved = true; 27469327c7afSParav Pandit sa_path_set_dmac(route->path_rec, addr->dev_addr.dst_dev_addr); 27479327c7afSParav Pandit return ndev; 27489327c7afSParav Pandit } 27499327c7afSParav Pandit 2750fe75889fSParav Pandit int rdma_set_ib_path(struct rdma_cm_id *id, 2751fe75889fSParav Pandit struct sa_path_rec *path_rec) 2752e51060f0SSean Hefty { 2753e51060f0SSean Hefty struct rdma_id_private *id_priv; 27548d20a1f0SParav Pandit struct net_device *ndev; 2755e51060f0SSean Hefty int ret; 2756e51060f0SSean Hefty 2757e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 2758550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED, 2759550e5ca7SNir Muchtar RDMA_CM_ROUTE_RESOLVED)) 2760e51060f0SSean Hefty return -EINVAL; 2761e51060f0SSean Hefty 2762fe75889fSParav Pandit id->route.path_rec = kmemdup(path_rec, sizeof(*path_rec), 27639893e742SJulia Lawall GFP_KERNEL); 2764e51060f0SSean Hefty if (!id->route.path_rec) { 2765e51060f0SSean Hefty ret = -ENOMEM; 2766e51060f0SSean Hefty goto err; 2767e51060f0SSean Hefty } 2768e51060f0SSean Hefty 27698d20a1f0SParav Pandit if (rdma_protocol_roce(id->device, id->port_num)) { 27708d20a1f0SParav Pandit ndev = cma_iboe_set_path_rec_l2_fields(id_priv); 27718d20a1f0SParav Pandit if (!ndev) { 27728d20a1f0SParav Pandit ret = -ENODEV; 27738d20a1f0SParav Pandit goto err_free; 27748d20a1f0SParav Pandit } 27758d20a1f0SParav Pandit dev_put(ndev); 27768d20a1f0SParav Pandit } 27778d20a1f0SParav Pandit 2778fe75889fSParav Pandit id->route.num_paths = 1; 2779e51060f0SSean Hefty return 0; 27808d20a1f0SParav Pandit 27818d20a1f0SParav Pandit err_free: 27828d20a1f0SParav Pandit kfree(id->route.path_rec); 27838d20a1f0SParav Pandit id->route.path_rec = NULL; 2784e51060f0SSean Hefty err: 2785550e5ca7SNir Muchtar cma_comp_exch(id_priv, RDMA_CM_ROUTE_RESOLVED, RDMA_CM_ADDR_RESOLVED); 2786e51060f0SSean Hefty return ret; 2787e51060f0SSean Hefty } 2788fe75889fSParav Pandit EXPORT_SYMBOL(rdma_set_ib_path); 2789e51060f0SSean Hefty 2790d6f91252SLeon Romanovsky static int cma_resolve_iw_route(struct rdma_id_private *id_priv) 279107ebafbaSTom Tucker { 279207ebafbaSTom Tucker struct cma_work *work; 279307ebafbaSTom Tucker 279407ebafbaSTom Tucker work = kzalloc(sizeof *work, GFP_KERNEL); 279507ebafbaSTom Tucker if (!work) 279607ebafbaSTom Tucker return -ENOMEM; 279707ebafbaSTom Tucker 2798981b5a23SParav Pandit cma_init_resolve_route_work(work, id_priv); 279907ebafbaSTom Tucker queue_work(cma_wq, &work->work); 280007ebafbaSTom Tucker return 0; 280107ebafbaSTom Tucker } 280207ebafbaSTom Tucker 2803eb072c4bSEyal Perry static int iboe_tos_to_sl(struct net_device *ndev, int tos) 2804eb072c4bSEyal Perry { 2805eb072c4bSEyal Perry int prio; 2806eb072c4bSEyal Perry struct net_device *dev; 2807eb072c4bSEyal Perry 2808eb072c4bSEyal Perry prio = rt_tos2priority(tos); 2809d0d7b10bSParav Pandit dev = is_vlan_dev(ndev) ? vlan_dev_real_dev(ndev) : ndev; 2810eb072c4bSEyal Perry if (dev->num_tc) 2811eb072c4bSEyal Perry return netdev_get_prio_tc_map(dev, prio); 2812eb072c4bSEyal Perry 2813eb072c4bSEyal Perry #if IS_ENABLED(CONFIG_VLAN_8021Q) 2814d0d7b10bSParav Pandit if (is_vlan_dev(ndev)) 2815eb072c4bSEyal Perry return (vlan_dev_get_egress_qos_mask(ndev, prio) & 2816eb072c4bSEyal Perry VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; 2817eb072c4bSEyal Perry #endif 2818eb072c4bSEyal Perry return 0; 2819eb072c4bSEyal Perry } 2820eb072c4bSEyal Perry 28213c86aa70SEli Cohen static int cma_resolve_iboe_route(struct rdma_id_private *id_priv) 28223c86aa70SEli Cohen { 28233c86aa70SEli Cohen struct rdma_route *route = &id_priv->id.route; 28243c86aa70SEli Cohen struct rdma_addr *addr = &route->addr; 28253c86aa70SEli Cohen struct cma_work *work; 28263c86aa70SEli Cohen int ret; 28274367ec7fSParav Pandit struct net_device *ndev; 28284367ec7fSParav Pandit 282989052d78SMajd Dibbiny u8 default_roce_tos = id_priv->cma_dev->default_roce_tos[id_priv->id.port_num - 283089052d78SMajd Dibbiny rdma_start_port(id_priv->cma_dev->device)]; 283189052d78SMajd Dibbiny u8 tos = id_priv->tos_set ? id_priv->tos : default_roce_tos; 2832dd5f03beSMatan Barak 28333c86aa70SEli Cohen 28343c86aa70SEli Cohen work = kzalloc(sizeof *work, GFP_KERNEL); 28353c86aa70SEli Cohen if (!work) 28363c86aa70SEli Cohen return -ENOMEM; 28373c86aa70SEli Cohen 28383c86aa70SEli Cohen route->path_rec = kzalloc(sizeof *route->path_rec, GFP_KERNEL); 28393c86aa70SEli Cohen if (!route->path_rec) { 28403c86aa70SEli Cohen ret = -ENOMEM; 28413c86aa70SEli Cohen goto err1; 28423c86aa70SEli Cohen } 28433c86aa70SEli Cohen 28443c86aa70SEli Cohen route->num_paths = 1; 28453c86aa70SEli Cohen 28469327c7afSParav Pandit ndev = cma_iboe_set_path_rec_l2_fields(id_priv); 284723d70503SWei Yongjun if (!ndev) { 284823d70503SWei Yongjun ret = -ENODEV; 284923d70503SWei Yongjun goto err2; 285023d70503SWei Yongjun } 285120029832SMatan Barak 28527b85627bSMoni Shoua rdma_ip2gid((struct sockaddr *)&id_priv->id.route.addr.src_addr, 28537b85627bSMoni Shoua &route->path_rec->sgid); 28547b85627bSMoni Shoua rdma_ip2gid((struct sockaddr *)&id_priv->id.route.addr.dst_addr, 28557b85627bSMoni Shoua &route->path_rec->dgid); 2856af7bd463SEli Cohen 2857c3efe750SMatan Barak if (((struct sockaddr *)&id_priv->id.route.addr.dst_addr)->sa_family != AF_IB) 2858c865f246SSomnath Kotur /* TODO: get the hoplimit from the inet/inet6 device */ 2859c3efe750SMatan Barak route->path_rec->hop_limit = addr->dev_addr.hoplimit; 2860c3efe750SMatan Barak else 2861af7bd463SEli Cohen route->path_rec->hop_limit = 1; 2862af7bd463SEli Cohen route->path_rec->reversible = 1; 2863af7bd463SEli Cohen route->path_rec->pkey = cpu_to_be16(0xffff); 2864af7bd463SEli Cohen route->path_rec->mtu_selector = IB_SA_EQ; 286589052d78SMajd Dibbiny route->path_rec->sl = iboe_tos_to_sl(ndev, tos); 286689052d78SMajd Dibbiny route->path_rec->traffic_class = tos; 28673c86aa70SEli Cohen route->path_rec->mtu = iboe_get_mtu(ndev->mtu); 28683c86aa70SEli Cohen route->path_rec->rate_selector = IB_SA_EQ; 28693c86aa70SEli Cohen route->path_rec->rate = iboe_get_rate(ndev); 28703c86aa70SEli Cohen dev_put(ndev); 28713c86aa70SEli Cohen route->path_rec->packet_life_time_selector = IB_SA_EQ; 28723c86aa70SEli Cohen route->path_rec->packet_life_time = CMA_IBOE_PACKET_LIFETIME; 28733c86aa70SEli Cohen if (!route->path_rec->mtu) { 28743c86aa70SEli Cohen ret = -EINVAL; 28753c86aa70SEli Cohen goto err2; 28763c86aa70SEli Cohen } 28773c86aa70SEli Cohen 2878981b5a23SParav Pandit cma_init_resolve_route_work(work, id_priv); 28793c86aa70SEli Cohen queue_work(cma_wq, &work->work); 28803c86aa70SEli Cohen 28813c86aa70SEli Cohen return 0; 28823c86aa70SEli Cohen 28833c86aa70SEli Cohen err2: 28843c86aa70SEli Cohen kfree(route->path_rec); 28853c86aa70SEli Cohen route->path_rec = NULL; 28863c86aa70SEli Cohen err1: 28873c86aa70SEli Cohen kfree(work); 28883c86aa70SEli Cohen return ret; 28893c86aa70SEli Cohen } 28903c86aa70SEli Cohen 2891dbace111SLeon Romanovsky int rdma_resolve_route(struct rdma_cm_id *id, unsigned long timeout_ms) 2892e51060f0SSean Hefty { 2893e51060f0SSean Hefty struct rdma_id_private *id_priv; 2894e51060f0SSean Hefty int ret; 2895e51060f0SSean Hefty 2896e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 2897550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED, RDMA_CM_ROUTE_QUERY)) 2898e51060f0SSean Hefty return -EINVAL; 2899e51060f0SSean Hefty 2900e51060f0SSean Hefty atomic_inc(&id_priv->refcount); 2901fe53ba2fSMichael Wang if (rdma_cap_ib_sa(id->device, id->port_num)) 2902e51060f0SSean Hefty ret = cma_resolve_ib_route(id_priv, timeout_ms); 29035d9fb044SIra Weiny else if (rdma_protocol_roce(id->device, id->port_num)) 29043c86aa70SEli Cohen ret = cma_resolve_iboe_route(id_priv); 2905c72f2189SMichael Wang else if (rdma_protocol_iwarp(id->device, id->port_num)) 2906d6f91252SLeon Romanovsky ret = cma_resolve_iw_route(id_priv); 2907c72f2189SMichael Wang else 2908e51060f0SSean Hefty ret = -ENOSYS; 2909c72f2189SMichael Wang 2910e51060f0SSean Hefty if (ret) 2911e51060f0SSean Hefty goto err; 2912e51060f0SSean Hefty 2913e51060f0SSean Hefty return 0; 2914e51060f0SSean Hefty err: 2915550e5ca7SNir Muchtar cma_comp_exch(id_priv, RDMA_CM_ROUTE_QUERY, RDMA_CM_ADDR_RESOLVED); 2916e51060f0SSean Hefty cma_deref_id(id_priv); 2917e51060f0SSean Hefty return ret; 2918e51060f0SSean Hefty } 2919e51060f0SSean Hefty EXPORT_SYMBOL(rdma_resolve_route); 2920e51060f0SSean Hefty 29216a3e362dSSean Hefty static void cma_set_loopback(struct sockaddr *addr) 29226a3e362dSSean Hefty { 29236a3e362dSSean Hefty switch (addr->sa_family) { 29246a3e362dSSean Hefty case AF_INET: 29256a3e362dSSean Hefty ((struct sockaddr_in *) addr)->sin_addr.s_addr = htonl(INADDR_LOOPBACK); 29266a3e362dSSean Hefty break; 29276a3e362dSSean Hefty case AF_INET6: 29286a3e362dSSean Hefty ipv6_addr_set(&((struct sockaddr_in6 *) addr)->sin6_addr, 29296a3e362dSSean Hefty 0, 0, 0, htonl(1)); 29306a3e362dSSean Hefty break; 29316a3e362dSSean Hefty default: 29326a3e362dSSean Hefty ib_addr_set(&((struct sockaddr_ib *) addr)->sib_addr, 29336a3e362dSSean Hefty 0, 0, 0, htonl(1)); 29346a3e362dSSean Hefty break; 29356a3e362dSSean Hefty } 29366a3e362dSSean Hefty } 29376a3e362dSSean Hefty 2938e51060f0SSean Hefty static int cma_bind_loopback(struct rdma_id_private *id_priv) 2939e51060f0SSean Hefty { 2940b0569e40SSean Hefty struct cma_device *cma_dev, *cur_dev; 2941f0ee3404SMichael S. Tsirkin union ib_gid gid; 2942102c5ce0SJack Wang enum ib_port_state port_state; 2943e51060f0SSean Hefty u16 pkey; 2944e51060f0SSean Hefty int ret; 2945e51060f0SSean Hefty u8 p; 2946e51060f0SSean Hefty 2947b0569e40SSean Hefty cma_dev = NULL; 2948e51060f0SSean Hefty mutex_lock(&lock); 2949b0569e40SSean Hefty list_for_each_entry(cur_dev, &dev_list, list) { 2950b0569e40SSean Hefty if (cma_family(id_priv) == AF_IB && 295172219ceaSMichael Wang !rdma_cap_ib_cm(cur_dev->device, 1)) 2952b0569e40SSean Hefty continue; 2953b0569e40SSean Hefty 2954b0569e40SSean Hefty if (!cma_dev) 2955b0569e40SSean Hefty cma_dev = cur_dev; 2956b0569e40SSean Hefty 2957b0569e40SSean Hefty for (p = 1; p <= cur_dev->device->phys_port_cnt; ++p) { 2958102c5ce0SJack Wang if (!ib_get_cached_port_state(cur_dev->device, p, &port_state) && 2959102c5ce0SJack Wang port_state == IB_PORT_ACTIVE) { 2960b0569e40SSean Hefty cma_dev = cur_dev; 2961b0569e40SSean Hefty goto port_found; 2962b0569e40SSean Hefty } 2963b0569e40SSean Hefty } 2964b0569e40SSean Hefty } 2965b0569e40SSean Hefty 2966b0569e40SSean Hefty if (!cma_dev) { 2967e82153b5SKrishna Kumar ret = -ENODEV; 2968e82153b5SKrishna Kumar goto out; 2969e82153b5SKrishna Kumar } 2970e51060f0SSean Hefty 2971e51060f0SSean Hefty p = 1; 2972e51060f0SSean Hefty 2973e51060f0SSean Hefty port_found: 29741dfce294SParav Pandit ret = rdma_query_gid(cma_dev->device, p, 0, &gid); 2975e51060f0SSean Hefty if (ret) 2976e51060f0SSean Hefty goto out; 2977e51060f0SSean Hefty 2978e51060f0SSean Hefty ret = ib_get_cached_pkey(cma_dev->device, p, 0, &pkey); 2979e51060f0SSean Hefty if (ret) 2980e51060f0SSean Hefty goto out; 2981e51060f0SSean Hefty 29826f8372b6SSean Hefty id_priv->id.route.addr.dev_addr.dev_type = 298321655afcSMichael Wang (rdma_protocol_ib(cma_dev->device, p)) ? 29846f8372b6SSean Hefty ARPHRD_INFINIBAND : ARPHRD_ETHER; 29856f8372b6SSean Hefty 29866f8372b6SSean Hefty rdma_addr_set_sgid(&id_priv->id.route.addr.dev_addr, &gid); 2987e51060f0SSean Hefty ib_addr_set_pkey(&id_priv->id.route.addr.dev_addr, pkey); 2988e51060f0SSean Hefty id_priv->id.port_num = p; 2989e51060f0SSean Hefty cma_attach_to_dev(id_priv, cma_dev); 2990f4753834SSean Hefty cma_set_loopback(cma_src_addr(id_priv)); 2991e51060f0SSean Hefty out: 2992e51060f0SSean Hefty mutex_unlock(&lock); 2993e51060f0SSean Hefty return ret; 2994e51060f0SSean Hefty } 2995e51060f0SSean Hefty 2996e51060f0SSean Hefty static void addr_handler(int status, struct sockaddr *src_addr, 2997e51060f0SSean Hefty struct rdma_dev_addr *dev_addr, void *context) 2998e51060f0SSean Hefty { 2999e51060f0SSean Hefty struct rdma_id_private *id_priv = context; 30007582df82SParav Pandit struct rdma_cm_event event = {}; 30015fc01fb8SMyungho Jung struct sockaddr *addr; 30025fc01fb8SMyungho Jung struct sockaddr_storage old_addr; 3003e51060f0SSean Hefty 3004de910bd9SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 3005550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_QUERY, 3006550e5ca7SNir Muchtar RDMA_CM_ADDR_RESOLVED)) 300761a73c70SSean Hefty goto out; 300861a73c70SSean Hefty 30095fc01fb8SMyungho Jung /* 30105fc01fb8SMyungho Jung * Store the previous src address, so that if we fail to acquire 30115fc01fb8SMyungho Jung * matching rdma device, old address can be restored back, which helps 30125fc01fb8SMyungho Jung * to cancel the cma listen operation correctly. 30135fc01fb8SMyungho Jung */ 30145fc01fb8SMyungho Jung addr = cma_src_addr(id_priv); 30155fc01fb8SMyungho Jung memcpy(&old_addr, addr, rdma_addr_size(addr)); 30165fc01fb8SMyungho Jung memcpy(addr, src_addr, rdma_addr_size(src_addr)); 3017498683c6SMoni Shoua if (!status && !id_priv->cma_dev) { 3018ff11c6cdSParav Pandit status = cma_acquire_dev_by_src_ip(id_priv); 3019498683c6SMoni Shoua if (status) 3020498683c6SMoni Shoua pr_debug_ratelimited("RDMA CM: ADDR_ERROR: failed to acquire device. status %d\n", 3021498683c6SMoni Shoua status); 3022498683c6SMoni Shoua } else { 3023498683c6SMoni Shoua pr_debug_ratelimited("RDMA CM: ADDR_ERROR: failed to resolve IP. status %d\n", status); 3024498683c6SMoni Shoua } 3025e51060f0SSean Hefty 3026e51060f0SSean Hefty if (status) { 30275fc01fb8SMyungho Jung memcpy(addr, &old_addr, 30285fc01fb8SMyungho Jung rdma_addr_size((struct sockaddr *)&old_addr)); 3029550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED, 3030550e5ca7SNir Muchtar RDMA_CM_ADDR_BOUND)) 3031e51060f0SSean Hefty goto out; 3032a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_ADDR_ERROR; 3033a1b1b61fSSean Hefty event.status = status; 30347b85627bSMoni Shoua } else 3035a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_ADDR_RESOLVED; 3036e51060f0SSean Hefty 3037a1b1b61fSSean Hefty if (id_priv->id.event_handler(&id_priv->id, &event)) { 3038550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 3039de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 3040e51060f0SSean Hefty rdma_destroy_id(&id_priv->id); 3041e51060f0SSean Hefty return; 3042e51060f0SSean Hefty } 3043e51060f0SSean Hefty out: 3044de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 3045e51060f0SSean Hefty } 3046e51060f0SSean Hefty 3047e51060f0SSean Hefty static int cma_resolve_loopback(struct rdma_id_private *id_priv) 3048e51060f0SSean Hefty { 3049e51060f0SSean Hefty struct cma_work *work; 3050f0ee3404SMichael S. Tsirkin union ib_gid gid; 3051e51060f0SSean Hefty int ret; 3052e51060f0SSean Hefty 3053e51060f0SSean Hefty work = kzalloc(sizeof *work, GFP_KERNEL); 3054e51060f0SSean Hefty if (!work) 3055e51060f0SSean Hefty return -ENOMEM; 3056e51060f0SSean Hefty 3057e51060f0SSean Hefty if (!id_priv->cma_dev) { 3058e51060f0SSean Hefty ret = cma_bind_loopback(id_priv); 3059e51060f0SSean Hefty if (ret) 3060e51060f0SSean Hefty goto err; 3061e51060f0SSean Hefty } 3062e51060f0SSean Hefty 30636f8372b6SSean Hefty rdma_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid); 30646f8372b6SSean Hefty rdma_addr_set_dgid(&id_priv->id.route.addr.dev_addr, &gid); 3065e51060f0SSean Hefty 3066981b5a23SParav Pandit cma_init_resolve_addr_work(work, id_priv); 3067e51060f0SSean Hefty queue_work(cma_wq, &work->work); 3068e51060f0SSean Hefty return 0; 3069e51060f0SSean Hefty err: 3070e51060f0SSean Hefty kfree(work); 3071e51060f0SSean Hefty return ret; 3072e51060f0SSean Hefty } 3073e51060f0SSean Hefty 3074f17df3b0SSean Hefty static int cma_resolve_ib_addr(struct rdma_id_private *id_priv) 3075f17df3b0SSean Hefty { 3076f17df3b0SSean Hefty struct cma_work *work; 3077f17df3b0SSean Hefty int ret; 3078f17df3b0SSean Hefty 3079f17df3b0SSean Hefty work = kzalloc(sizeof *work, GFP_KERNEL); 3080f17df3b0SSean Hefty if (!work) 3081f17df3b0SSean Hefty return -ENOMEM; 3082f17df3b0SSean Hefty 3083f17df3b0SSean Hefty if (!id_priv->cma_dev) { 3084f17df3b0SSean Hefty ret = cma_resolve_ib_dev(id_priv); 3085f17df3b0SSean Hefty if (ret) 3086f17df3b0SSean Hefty goto err; 3087f17df3b0SSean Hefty } 3088f17df3b0SSean Hefty 3089f17df3b0SSean Hefty rdma_addr_set_dgid(&id_priv->id.route.addr.dev_addr, (union ib_gid *) 3090f17df3b0SSean Hefty &(((struct sockaddr_ib *) &id_priv->id.route.addr.dst_addr)->sib_addr)); 3091f17df3b0SSean Hefty 3092981b5a23SParav Pandit cma_init_resolve_addr_work(work, id_priv); 3093f17df3b0SSean Hefty queue_work(cma_wq, &work->work); 3094f17df3b0SSean Hefty return 0; 3095f17df3b0SSean Hefty err: 3096f17df3b0SSean Hefty kfree(work); 3097f17df3b0SSean Hefty return ret; 3098f17df3b0SSean Hefty } 3099f17df3b0SSean Hefty 3100e51060f0SSean Hefty static int cma_bind_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, 31012df7dba8SParav Pandit const struct sockaddr *dst_addr) 3102e51060f0SSean Hefty { 3103d14714dfSSean Hefty if (!src_addr || !src_addr->sa_family) { 3104d14714dfSSean Hefty src_addr = (struct sockaddr *) &id->route.addr.src_addr; 3105f17df3b0SSean Hefty src_addr->sa_family = dst_addr->sa_family; 3106b4cfe397SJack Morgenstein if (IS_ENABLED(CONFIG_IPV6) && 3107b4cfe397SJack Morgenstein dst_addr->sa_family == AF_INET6) { 31086c26a771SSpencer Baugh struct sockaddr_in6 *src_addr6 = (struct sockaddr_in6 *) src_addr; 31096c26a771SSpencer Baugh struct sockaddr_in6 *dst_addr6 = (struct sockaddr_in6 *) dst_addr; 31106c26a771SSpencer Baugh src_addr6->sin6_scope_id = dst_addr6->sin6_scope_id; 31116c26a771SSpencer Baugh if (ipv6_addr_type(&dst_addr6->sin6_addr) & IPV6_ADDR_LINKLOCAL) 31126c26a771SSpencer Baugh id->route.addr.dev_addr.bound_dev_if = dst_addr6->sin6_scope_id; 3113f17df3b0SSean Hefty } else if (dst_addr->sa_family == AF_IB) { 3114f17df3b0SSean Hefty ((struct sockaddr_ib *) src_addr)->sib_pkey = 3115f17df3b0SSean Hefty ((struct sockaddr_ib *) dst_addr)->sib_pkey; 3116d14714dfSSean Hefty } 3117d14714dfSSean Hefty } 3118e51060f0SSean Hefty return rdma_bind_addr(id, src_addr); 3119e51060f0SSean Hefty } 3120e51060f0SSean Hefty 3121e51060f0SSean Hefty int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, 3122dbace111SLeon Romanovsky const struct sockaddr *dst_addr, unsigned long timeout_ms) 3123e51060f0SSean Hefty { 3124e51060f0SSean Hefty struct rdma_id_private *id_priv; 3125e51060f0SSean Hefty int ret; 3126e51060f0SSean Hefty 3127e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 3128550e5ca7SNir Muchtar if (id_priv->state == RDMA_CM_IDLE) { 3129e51060f0SSean Hefty ret = cma_bind_addr(id, src_addr, dst_addr); 3130219d2e9dSParav Pandit if (ret) 3131e51060f0SSean Hefty return ret; 3132e51060f0SSean Hefty } 3133e51060f0SSean Hefty 3134219d2e9dSParav Pandit if (cma_family(id_priv) != dst_addr->sa_family) 31354ae7152eSSean Hefty return -EINVAL; 31364ae7152eSSean Hefty 3137219d2e9dSParav Pandit if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_ADDR_QUERY)) 3138e51060f0SSean Hefty return -EINVAL; 3139e51060f0SSean Hefty 3140219d2e9dSParav Pandit memcpy(cma_dst_addr(id_priv), dst_addr, rdma_addr_size(dst_addr)); 3141f17df3b0SSean Hefty if (cma_any_addr(dst_addr)) { 3142e51060f0SSean Hefty ret = cma_resolve_loopback(id_priv); 3143f17df3b0SSean Hefty } else { 3144f17df3b0SSean Hefty if (dst_addr->sa_family == AF_IB) { 3145f17df3b0SSean Hefty ret = cma_resolve_ib_addr(id_priv); 3146f17df3b0SSean Hefty } else { 31470e9d2c19SParav Pandit ret = rdma_resolve_ip(cma_src_addr(id_priv), dst_addr, 31480e9d2c19SParav Pandit &id->route.addr.dev_addr, 31490e9d2c19SParav Pandit timeout_ms, addr_handler, 31500e9d2c19SParav Pandit false, id_priv); 3151f17df3b0SSean Hefty } 3152f17df3b0SSean Hefty } 3153e51060f0SSean Hefty if (ret) 3154e51060f0SSean Hefty goto err; 3155e51060f0SSean Hefty 3156e51060f0SSean Hefty return 0; 3157e51060f0SSean Hefty err: 3158550e5ca7SNir Muchtar cma_comp_exch(id_priv, RDMA_CM_ADDR_QUERY, RDMA_CM_ADDR_BOUND); 3159e51060f0SSean Hefty return ret; 3160e51060f0SSean Hefty } 3161e51060f0SSean Hefty EXPORT_SYMBOL(rdma_resolve_addr); 3162e51060f0SSean Hefty 3163a9bb7912SHefty, Sean int rdma_set_reuseaddr(struct rdma_cm_id *id, int reuse) 3164a9bb7912SHefty, Sean { 3165a9bb7912SHefty, Sean struct rdma_id_private *id_priv; 3166a9bb7912SHefty, Sean unsigned long flags; 3167a9bb7912SHefty, Sean int ret; 3168a9bb7912SHefty, Sean 3169a9bb7912SHefty, Sean id_priv = container_of(id, struct rdma_id_private, id); 3170a9bb7912SHefty, Sean spin_lock_irqsave(&id_priv->lock, flags); 3171c8dea2f9SSean Hefty if (reuse || id_priv->state == RDMA_CM_IDLE) { 3172a9bb7912SHefty, Sean id_priv->reuseaddr = reuse; 3173a9bb7912SHefty, Sean ret = 0; 3174a9bb7912SHefty, Sean } else { 3175a9bb7912SHefty, Sean ret = -EINVAL; 3176a9bb7912SHefty, Sean } 3177a9bb7912SHefty, Sean spin_unlock_irqrestore(&id_priv->lock, flags); 3178a9bb7912SHefty, Sean return ret; 3179a9bb7912SHefty, Sean } 3180a9bb7912SHefty, Sean EXPORT_SYMBOL(rdma_set_reuseaddr); 3181a9bb7912SHefty, Sean 318268602120SSean Hefty int rdma_set_afonly(struct rdma_cm_id *id, int afonly) 318368602120SSean Hefty { 318468602120SSean Hefty struct rdma_id_private *id_priv; 318568602120SSean Hefty unsigned long flags; 318668602120SSean Hefty int ret; 318768602120SSean Hefty 318868602120SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 318968602120SSean Hefty spin_lock_irqsave(&id_priv->lock, flags); 319068602120SSean Hefty if (id_priv->state == RDMA_CM_IDLE || id_priv->state == RDMA_CM_ADDR_BOUND) { 319168602120SSean Hefty id_priv->options |= (1 << CMA_OPTION_AFONLY); 319268602120SSean Hefty id_priv->afonly = afonly; 319368602120SSean Hefty ret = 0; 319468602120SSean Hefty } else { 319568602120SSean Hefty ret = -EINVAL; 319668602120SSean Hefty } 319768602120SSean Hefty spin_unlock_irqrestore(&id_priv->lock, flags); 319868602120SSean Hefty return ret; 319968602120SSean Hefty } 320068602120SSean Hefty EXPORT_SYMBOL(rdma_set_afonly); 320168602120SSean Hefty 3202e51060f0SSean Hefty static void cma_bind_port(struct rdma_bind_list *bind_list, 3203e51060f0SSean Hefty struct rdma_id_private *id_priv) 3204e51060f0SSean Hefty { 320558afdcb7SSean Hefty struct sockaddr *addr; 320658afdcb7SSean Hefty struct sockaddr_ib *sib; 320758afdcb7SSean Hefty u64 sid, mask; 320858afdcb7SSean Hefty __be16 port; 3209e51060f0SSean Hefty 3210f4753834SSean Hefty addr = cma_src_addr(id_priv); 321158afdcb7SSean Hefty port = htons(bind_list->port); 321258afdcb7SSean Hefty 321358afdcb7SSean Hefty switch (addr->sa_family) { 321458afdcb7SSean Hefty case AF_INET: 321558afdcb7SSean Hefty ((struct sockaddr_in *) addr)->sin_port = port; 321658afdcb7SSean Hefty break; 321758afdcb7SSean Hefty case AF_INET6: 321858afdcb7SSean Hefty ((struct sockaddr_in6 *) addr)->sin6_port = port; 321958afdcb7SSean Hefty break; 322058afdcb7SSean Hefty case AF_IB: 322158afdcb7SSean Hefty sib = (struct sockaddr_ib *) addr; 322258afdcb7SSean Hefty sid = be64_to_cpu(sib->sib_sid); 322358afdcb7SSean Hefty mask = be64_to_cpu(sib->sib_sid_mask); 322458afdcb7SSean Hefty sib->sib_sid = cpu_to_be64((sid & mask) | (u64) ntohs(port)); 322558afdcb7SSean Hefty sib->sib_sid_mask = cpu_to_be64(~0ULL); 322658afdcb7SSean Hefty break; 322758afdcb7SSean Hefty } 3228e51060f0SSean Hefty id_priv->bind_list = bind_list; 3229e51060f0SSean Hefty hlist_add_head(&id_priv->node, &bind_list->owners); 3230e51060f0SSean Hefty } 3231e51060f0SSean Hefty 32322253fc0cSSteve Wise static int cma_alloc_port(enum rdma_ucm_port_space ps, 3233aac978e1SHaggai Eran struct rdma_id_private *id_priv, unsigned short snum) 3234e51060f0SSean Hefty { 3235e51060f0SSean Hefty struct rdma_bind_list *bind_list; 32363b069c5dSTejun Heo int ret; 3237e51060f0SSean Hefty 3238cb164b8cSSean Hefty bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL); 3239e51060f0SSean Hefty if (!bind_list) 3240e51060f0SSean Hefty return -ENOMEM; 3241e51060f0SSean Hefty 3242fa20105eSGuy Shapiro ret = cma_ps_alloc(id_priv->id.route.addr.dev_addr.net, ps, bind_list, 3243fa20105eSGuy Shapiro snum); 32443b069c5dSTejun Heo if (ret < 0) 32453b069c5dSTejun Heo goto err; 3246e51060f0SSean Hefty 3247e51060f0SSean Hefty bind_list->ps = ps; 32483b069c5dSTejun Heo bind_list->port = (unsigned short)ret; 3249e51060f0SSean Hefty cma_bind_port(bind_list, id_priv); 3250e51060f0SSean Hefty return 0; 32513b069c5dSTejun Heo err: 3252aedec080SSean Hefty kfree(bind_list); 32533b069c5dSTejun Heo return ret == -ENOSPC ? -EADDRNOTAVAIL : ret; 3254aedec080SSean Hefty } 3255aedec080SSean Hefty 325619b752a1SMoni Shoua static int cma_port_is_unique(struct rdma_bind_list *bind_list, 325719b752a1SMoni Shoua struct rdma_id_private *id_priv) 325819b752a1SMoni Shoua { 325919b752a1SMoni Shoua struct rdma_id_private *cur_id; 326019b752a1SMoni Shoua struct sockaddr *daddr = cma_dst_addr(id_priv); 326119b752a1SMoni Shoua struct sockaddr *saddr = cma_src_addr(id_priv); 326219b752a1SMoni Shoua __be16 dport = cma_port(daddr); 326319b752a1SMoni Shoua 326419b752a1SMoni Shoua hlist_for_each_entry(cur_id, &bind_list->owners, node) { 326519b752a1SMoni Shoua struct sockaddr *cur_daddr = cma_dst_addr(cur_id); 326619b752a1SMoni Shoua struct sockaddr *cur_saddr = cma_src_addr(cur_id); 326719b752a1SMoni Shoua __be16 cur_dport = cma_port(cur_daddr); 326819b752a1SMoni Shoua 326919b752a1SMoni Shoua if (id_priv == cur_id) 327019b752a1SMoni Shoua continue; 327119b752a1SMoni Shoua 327219b752a1SMoni Shoua /* different dest port -> unique */ 32739dea9a2fSTatyana Nikolova if (!cma_any_port(daddr) && 32749dea9a2fSTatyana Nikolova !cma_any_port(cur_daddr) && 327519b752a1SMoni Shoua (dport != cur_dport)) 327619b752a1SMoni Shoua continue; 327719b752a1SMoni Shoua 327819b752a1SMoni Shoua /* different src address -> unique */ 327919b752a1SMoni Shoua if (!cma_any_addr(saddr) && 328019b752a1SMoni Shoua !cma_any_addr(cur_saddr) && 328119b752a1SMoni Shoua cma_addr_cmp(saddr, cur_saddr)) 328219b752a1SMoni Shoua continue; 328319b752a1SMoni Shoua 328419b752a1SMoni Shoua /* different dst address -> unique */ 32859dea9a2fSTatyana Nikolova if (!cma_any_addr(daddr) && 32869dea9a2fSTatyana Nikolova !cma_any_addr(cur_daddr) && 328719b752a1SMoni Shoua cma_addr_cmp(daddr, cur_daddr)) 328819b752a1SMoni Shoua continue; 328919b752a1SMoni Shoua 329019b752a1SMoni Shoua return -EADDRNOTAVAIL; 329119b752a1SMoni Shoua } 329219b752a1SMoni Shoua return 0; 329319b752a1SMoni Shoua } 329419b752a1SMoni Shoua 32952253fc0cSSteve Wise static int cma_alloc_any_port(enum rdma_ucm_port_space ps, 3296aac978e1SHaggai Eran struct rdma_id_private *id_priv) 3297aedec080SSean Hefty { 32985d7220e8STetsuo Handa static unsigned int last_used_port; 32995d7220e8STetsuo Handa int low, high, remaining; 33005d7220e8STetsuo Handa unsigned int rover; 3301fa20105eSGuy Shapiro struct net *net = id_priv->id.route.addr.dev_addr.net; 3302aedec080SSean Hefty 3303fa20105eSGuy Shapiro inet_get_local_port_range(net, &low, &high); 33045d7220e8STetsuo Handa remaining = (high - low) + 1; 330563862b5bSAruna-Hewapathirane rover = prandom_u32() % remaining + low; 33065d7220e8STetsuo Handa retry: 330719b752a1SMoni Shoua if (last_used_port != rover) { 330819b752a1SMoni Shoua struct rdma_bind_list *bind_list; 330919b752a1SMoni Shoua int ret; 331019b752a1SMoni Shoua 331119b752a1SMoni Shoua bind_list = cma_ps_find(net, ps, (unsigned short)rover); 331219b752a1SMoni Shoua 331319b752a1SMoni Shoua if (!bind_list) { 331419b752a1SMoni Shoua ret = cma_alloc_port(ps, id_priv, rover); 331519b752a1SMoni Shoua } else { 331619b752a1SMoni Shoua ret = cma_port_is_unique(bind_list, id_priv); 331719b752a1SMoni Shoua if (!ret) 331819b752a1SMoni Shoua cma_bind_port(bind_list, id_priv); 331919b752a1SMoni Shoua } 33205d7220e8STetsuo Handa /* 33215d7220e8STetsuo Handa * Remember previously used port number in order to avoid 33225d7220e8STetsuo Handa * re-using same port immediately after it is closed. 33235d7220e8STetsuo Handa */ 33245d7220e8STetsuo Handa if (!ret) 33255d7220e8STetsuo Handa last_used_port = rover; 33265d7220e8STetsuo Handa if (ret != -EADDRNOTAVAIL) 33275d7220e8STetsuo Handa return ret; 33285d7220e8STetsuo Handa } 33295d7220e8STetsuo Handa if (--remaining) { 33305d7220e8STetsuo Handa rover++; 33315d7220e8STetsuo Handa if ((rover < low) || (rover > high)) 33325d7220e8STetsuo Handa rover = low; 3333aedec080SSean Hefty goto retry; 3334aedec080SSean Hefty } 33355d7220e8STetsuo Handa return -EADDRNOTAVAIL; 3336e51060f0SSean Hefty } 3337e51060f0SSean Hefty 3338a9bb7912SHefty, Sean /* 3339a9bb7912SHefty, Sean * Check that the requested port is available. This is called when trying to 3340a9bb7912SHefty, Sean * bind to a specific port, or when trying to listen on a bound port. In 3341a9bb7912SHefty, Sean * the latter case, the provided id_priv may already be on the bind_list, but 3342a9bb7912SHefty, Sean * we still need to check that it's okay to start listening. 3343a9bb7912SHefty, Sean */ 3344a9bb7912SHefty, Sean static int cma_check_port(struct rdma_bind_list *bind_list, 3345a9bb7912SHefty, Sean struct rdma_id_private *id_priv, uint8_t reuseaddr) 3346e51060f0SSean Hefty { 3347e51060f0SSean Hefty struct rdma_id_private *cur_id; 334843b752daSHefty, Sean struct sockaddr *addr, *cur_addr; 3349e51060f0SSean Hefty 3350f4753834SSean Hefty addr = cma_src_addr(id_priv); 3351b67bfe0dSSasha Levin hlist_for_each_entry(cur_id, &bind_list->owners, node) { 3352a9bb7912SHefty, Sean if (id_priv == cur_id) 3353a9bb7912SHefty, Sean continue; 3354a9bb7912SHefty, Sean 33555b0ec991SSean Hefty if ((cur_id->state != RDMA_CM_LISTEN) && reuseaddr && 33565b0ec991SSean Hefty cur_id->reuseaddr) 33575b0ec991SSean Hefty continue; 33585b0ec991SSean Hefty 3359f4753834SSean Hefty cur_addr = cma_src_addr(cur_id); 33605b0ec991SSean Hefty if (id_priv->afonly && cur_id->afonly && 33615b0ec991SSean Hefty (addr->sa_family != cur_addr->sa_family)) 33625b0ec991SSean Hefty continue; 33635b0ec991SSean Hefty 33645b0ec991SSean Hefty if (cma_any_addr(addr) || cma_any_addr(cur_addr)) 3365e51060f0SSean Hefty return -EADDRNOTAVAIL; 3366e51060f0SSean Hefty 336743b752daSHefty, Sean if (!cma_addr_cmp(addr, cur_addr)) 3368e51060f0SSean Hefty return -EADDRINUSE; 3369e51060f0SSean Hefty } 3370e51060f0SSean Hefty return 0; 3371e51060f0SSean Hefty } 3372e51060f0SSean Hefty 33732253fc0cSSteve Wise static int cma_use_port(enum rdma_ucm_port_space ps, 3374aac978e1SHaggai Eran struct rdma_id_private *id_priv) 3375a9bb7912SHefty, Sean { 3376a9bb7912SHefty, Sean struct rdma_bind_list *bind_list; 3377a9bb7912SHefty, Sean unsigned short snum; 3378a9bb7912SHefty, Sean int ret; 3379a9bb7912SHefty, Sean 3380f4753834SSean Hefty snum = ntohs(cma_port(cma_src_addr(id_priv))); 3381a9bb7912SHefty, Sean if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) 3382a9bb7912SHefty, Sean return -EACCES; 3383a9bb7912SHefty, Sean 3384fa20105eSGuy Shapiro bind_list = cma_ps_find(id_priv->id.route.addr.dev_addr.net, ps, snum); 3385a9bb7912SHefty, Sean if (!bind_list) { 3386a9bb7912SHefty, Sean ret = cma_alloc_port(ps, id_priv, snum); 3387a9bb7912SHefty, Sean } else { 3388a9bb7912SHefty, Sean ret = cma_check_port(bind_list, id_priv, id_priv->reuseaddr); 3389a9bb7912SHefty, Sean if (!ret) 3390a9bb7912SHefty, Sean cma_bind_port(bind_list, id_priv); 3391a9bb7912SHefty, Sean } 3392a9bb7912SHefty, Sean return ret; 3393a9bb7912SHefty, Sean } 3394a9bb7912SHefty, Sean 3395a9bb7912SHefty, Sean static int cma_bind_listen(struct rdma_id_private *id_priv) 3396a9bb7912SHefty, Sean { 3397a9bb7912SHefty, Sean struct rdma_bind_list *bind_list = id_priv->bind_list; 3398a9bb7912SHefty, Sean int ret = 0; 3399a9bb7912SHefty, Sean 3400a9bb7912SHefty, Sean mutex_lock(&lock); 3401a9bb7912SHefty, Sean if (bind_list->owners.first->next) 3402a9bb7912SHefty, Sean ret = cma_check_port(bind_list, id_priv, 0); 3403a9bb7912SHefty, Sean mutex_unlock(&lock); 3404a9bb7912SHefty, Sean return ret; 3405a9bb7912SHefty, Sean } 3406a9bb7912SHefty, Sean 34072253fc0cSSteve Wise static enum rdma_ucm_port_space 34082253fc0cSSteve Wise cma_select_inet_ps(struct rdma_id_private *id_priv) 340958afdcb7SSean Hefty { 341058afdcb7SSean Hefty switch (id_priv->id.ps) { 341158afdcb7SSean Hefty case RDMA_PS_TCP: 341258afdcb7SSean Hefty case RDMA_PS_UDP: 341358afdcb7SSean Hefty case RDMA_PS_IPOIB: 341458afdcb7SSean Hefty case RDMA_PS_IB: 3415aac978e1SHaggai Eran return id_priv->id.ps; 341658afdcb7SSean Hefty default: 3417aac978e1SHaggai Eran 3418aac978e1SHaggai Eran return 0; 341958afdcb7SSean Hefty } 342058afdcb7SSean Hefty } 342158afdcb7SSean Hefty 34222253fc0cSSteve Wise static enum rdma_ucm_port_space 34232253fc0cSSteve Wise cma_select_ib_ps(struct rdma_id_private *id_priv) 342458afdcb7SSean Hefty { 34252253fc0cSSteve Wise enum rdma_ucm_port_space ps = 0; 342658afdcb7SSean Hefty struct sockaddr_ib *sib; 342758afdcb7SSean Hefty u64 sid_ps, mask, sid; 342858afdcb7SSean Hefty 3429f4753834SSean Hefty sib = (struct sockaddr_ib *) cma_src_addr(id_priv); 343058afdcb7SSean Hefty mask = be64_to_cpu(sib->sib_sid_mask) & RDMA_IB_IP_PS_MASK; 343158afdcb7SSean Hefty sid = be64_to_cpu(sib->sib_sid) & mask; 343258afdcb7SSean Hefty 343358afdcb7SSean Hefty if ((id_priv->id.ps == RDMA_PS_IB) && (sid == (RDMA_IB_IP_PS_IB & mask))) { 343458afdcb7SSean Hefty sid_ps = RDMA_IB_IP_PS_IB; 3435aac978e1SHaggai Eran ps = RDMA_PS_IB; 343658afdcb7SSean Hefty } else if (((id_priv->id.ps == RDMA_PS_IB) || (id_priv->id.ps == RDMA_PS_TCP)) && 343758afdcb7SSean Hefty (sid == (RDMA_IB_IP_PS_TCP & mask))) { 343858afdcb7SSean Hefty sid_ps = RDMA_IB_IP_PS_TCP; 3439aac978e1SHaggai Eran ps = RDMA_PS_TCP; 344058afdcb7SSean Hefty } else if (((id_priv->id.ps == RDMA_PS_IB) || (id_priv->id.ps == RDMA_PS_UDP)) && 344158afdcb7SSean Hefty (sid == (RDMA_IB_IP_PS_UDP & mask))) { 344258afdcb7SSean Hefty sid_ps = RDMA_IB_IP_PS_UDP; 3443aac978e1SHaggai Eran ps = RDMA_PS_UDP; 344458afdcb7SSean Hefty } 344558afdcb7SSean Hefty 344658afdcb7SSean Hefty if (ps) { 344758afdcb7SSean Hefty sib->sib_sid = cpu_to_be64(sid_ps | ntohs(cma_port((struct sockaddr *) sib))); 344858afdcb7SSean Hefty sib->sib_sid_mask = cpu_to_be64(RDMA_IB_IP_PS_MASK | 344958afdcb7SSean Hefty be64_to_cpu(sib->sib_sid_mask)); 345058afdcb7SSean Hefty } 345158afdcb7SSean Hefty return ps; 345258afdcb7SSean Hefty } 345358afdcb7SSean Hefty 3454e51060f0SSean Hefty static int cma_get_port(struct rdma_id_private *id_priv) 3455e51060f0SSean Hefty { 34562253fc0cSSteve Wise enum rdma_ucm_port_space ps; 3457e51060f0SSean Hefty int ret; 3458e51060f0SSean Hefty 3459f4753834SSean Hefty if (cma_family(id_priv) != AF_IB) 346058afdcb7SSean Hefty ps = cma_select_inet_ps(id_priv); 346158afdcb7SSean Hefty else 346258afdcb7SSean Hefty ps = cma_select_ib_ps(id_priv); 346358afdcb7SSean Hefty if (!ps) 3464e51060f0SSean Hefty return -EPROTONOSUPPORT; 3465e51060f0SSean Hefty 3466e51060f0SSean Hefty mutex_lock(&lock); 3467f4753834SSean Hefty if (cma_any_port(cma_src_addr(id_priv))) 3468aedec080SSean Hefty ret = cma_alloc_any_port(ps, id_priv); 3469e51060f0SSean Hefty else 3470e51060f0SSean Hefty ret = cma_use_port(ps, id_priv); 3471e51060f0SSean Hefty mutex_unlock(&lock); 3472e51060f0SSean Hefty 3473e51060f0SSean Hefty return ret; 3474e51060f0SSean Hefty } 3475e51060f0SSean Hefty 3476d14714dfSSean Hefty static int cma_check_linklocal(struct rdma_dev_addr *dev_addr, 3477d14714dfSSean Hefty struct sockaddr *addr) 3478d14714dfSSean Hefty { 3479d90f9b35SRoland Dreier #if IS_ENABLED(CONFIG_IPV6) 3480d14714dfSSean Hefty struct sockaddr_in6 *sin6; 3481d14714dfSSean Hefty 3482d14714dfSSean Hefty if (addr->sa_family != AF_INET6) 3483d14714dfSSean Hefty return 0; 3484d14714dfSSean Hefty 3485d14714dfSSean Hefty sin6 = (struct sockaddr_in6 *) addr; 34865462edddSSomnath Kotur 34875462edddSSomnath Kotur if (!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)) 34885462edddSSomnath Kotur return 0; 34895462edddSSomnath Kotur 34905462edddSSomnath Kotur if (!sin6->sin6_scope_id) 3491d14714dfSSean Hefty return -EINVAL; 3492d14714dfSSean Hefty 3493d14714dfSSean Hefty dev_addr->bound_dev_if = sin6->sin6_scope_id; 3494d14714dfSSean Hefty #endif 3495d14714dfSSean Hefty return 0; 3496d14714dfSSean Hefty } 3497d14714dfSSean Hefty 3498a9bb7912SHefty, Sean int rdma_listen(struct rdma_cm_id *id, int backlog) 3499a9bb7912SHefty, Sean { 3500a9bb7912SHefty, Sean struct rdma_id_private *id_priv; 3501a9bb7912SHefty, Sean int ret; 3502a9bb7912SHefty, Sean 3503a9bb7912SHefty, Sean id_priv = container_of(id, struct rdma_id_private, id); 3504550e5ca7SNir Muchtar if (id_priv->state == RDMA_CM_IDLE) { 3505f4753834SSean Hefty id->route.addr.src_addr.ss_family = AF_INET; 3506f4753834SSean Hefty ret = rdma_bind_addr(id, cma_src_addr(id_priv)); 3507a9bb7912SHefty, Sean if (ret) 3508a9bb7912SHefty, Sean return ret; 3509a9bb7912SHefty, Sean } 3510a9bb7912SHefty, Sean 3511550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_LISTEN)) 3512a9bb7912SHefty, Sean return -EINVAL; 3513a9bb7912SHefty, Sean 3514a9bb7912SHefty, Sean if (id_priv->reuseaddr) { 3515a9bb7912SHefty, Sean ret = cma_bind_listen(id_priv); 3516a9bb7912SHefty, Sean if (ret) 3517a9bb7912SHefty, Sean goto err; 3518a9bb7912SHefty, Sean } 3519a9bb7912SHefty, Sean 3520a9bb7912SHefty, Sean id_priv->backlog = backlog; 3521a9bb7912SHefty, Sean if (id->device) { 352272219ceaSMichael Wang if (rdma_cap_ib_cm(id->device, 1)) { 3523a9bb7912SHefty, Sean ret = cma_ib_listen(id_priv); 3524a9bb7912SHefty, Sean if (ret) 3525a9bb7912SHefty, Sean goto err; 352604215330SMichael Wang } else if (rdma_cap_iw_cm(id->device, 1)) { 3527a9bb7912SHefty, Sean ret = cma_iw_listen(id_priv, backlog); 3528a9bb7912SHefty, Sean if (ret) 3529a9bb7912SHefty, Sean goto err; 353021655afcSMichael Wang } else { 3531a9bb7912SHefty, Sean ret = -ENOSYS; 3532a9bb7912SHefty, Sean goto err; 3533a9bb7912SHefty, Sean } 3534a9bb7912SHefty, Sean } else 3535a9bb7912SHefty, Sean cma_listen_on_all(id_priv); 3536a9bb7912SHefty, Sean 3537a9bb7912SHefty, Sean return 0; 3538a9bb7912SHefty, Sean err: 3539a9bb7912SHefty, Sean id_priv->backlog = 0; 3540550e5ca7SNir Muchtar cma_comp_exch(id_priv, RDMA_CM_LISTEN, RDMA_CM_ADDR_BOUND); 3541a9bb7912SHefty, Sean return ret; 3542a9bb7912SHefty, Sean } 3543a9bb7912SHefty, Sean EXPORT_SYMBOL(rdma_listen); 3544a9bb7912SHefty, Sean 3545e51060f0SSean Hefty int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr) 3546e51060f0SSean Hefty { 3547e51060f0SSean Hefty struct rdma_id_private *id_priv; 3548e51060f0SSean Hefty int ret; 35496df6b4a9SMoni Shoua struct sockaddr *daddr; 3550e51060f0SSean Hefty 3551680f920aSSean Hefty if (addr->sa_family != AF_INET && addr->sa_family != AF_INET6 && 3552680f920aSSean Hefty addr->sa_family != AF_IB) 3553e51060f0SSean Hefty return -EAFNOSUPPORT; 3554e51060f0SSean Hefty 3555e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 3556550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_IDLE, RDMA_CM_ADDR_BOUND)) 3557e51060f0SSean Hefty return -EINVAL; 3558e51060f0SSean Hefty 3559d14714dfSSean Hefty ret = cma_check_linklocal(&id->route.addr.dev_addr, addr); 3560d14714dfSSean Hefty if (ret) 3561d14714dfSSean Hefty goto err1; 3562d14714dfSSean Hefty 35637b85627bSMoni Shoua memcpy(cma_src_addr(id_priv), addr, rdma_addr_size(addr)); 35648523c048SSean Hefty if (!cma_any_addr(addr)) { 3565680f920aSSean Hefty ret = cma_translate_addr(addr, &id->route.addr.dev_addr); 3566255d0c14SKrishna Kumar if (ret) 3567255d0c14SKrishna Kumar goto err1; 3568255d0c14SKrishna Kumar 3569ff11c6cdSParav Pandit ret = cma_acquire_dev_by_src_ip(id_priv); 3570e51060f0SSean Hefty if (ret) 3571255d0c14SKrishna Kumar goto err1; 3572e51060f0SSean Hefty } 3573e51060f0SSean Hefty 357468602120SSean Hefty if (!(id_priv->options & (1 << CMA_OPTION_AFONLY))) { 35755b0ec991SSean Hefty if (addr->sa_family == AF_INET) 35765b0ec991SSean Hefty id_priv->afonly = 1; 35775b0ec991SSean Hefty #if IS_ENABLED(CONFIG_IPV6) 3578fa20105eSGuy Shapiro else if (addr->sa_family == AF_INET6) { 3579fa20105eSGuy Shapiro struct net *net = id_priv->id.route.addr.dev_addr.net; 3580fa20105eSGuy Shapiro 3581fa20105eSGuy Shapiro id_priv->afonly = net->ipv6.sysctl.bindv6only; 3582fa20105eSGuy Shapiro } 35835b0ec991SSean Hefty #endif 358468602120SSean Hefty } 35859dea9a2fSTatyana Nikolova daddr = cma_dst_addr(id_priv); 35869dea9a2fSTatyana Nikolova daddr->sa_family = addr->sa_family; 35879dea9a2fSTatyana Nikolova 3588e51060f0SSean Hefty ret = cma_get_port(id_priv); 3589e51060f0SSean Hefty if (ret) 3590255d0c14SKrishna Kumar goto err2; 3591e51060f0SSean Hefty 3592e51060f0SSean Hefty return 0; 3593255d0c14SKrishna Kumar err2: 359400313983SSteve Wise rdma_restrack_del(&id_priv->res); 3595ed7a01fdSLeon Romanovsky if (id_priv->cma_dev) 3596a396d43aSSean Hefty cma_release_dev(id_priv); 3597255d0c14SKrishna Kumar err1: 3598550e5ca7SNir Muchtar cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_IDLE); 3599e51060f0SSean Hefty return ret; 3600e51060f0SSean Hefty } 3601e51060f0SSean Hefty EXPORT_SYMBOL(rdma_bind_addr); 3602e51060f0SSean Hefty 3603f4753834SSean Hefty static int cma_format_hdr(void *hdr, struct rdma_id_private *id_priv) 3604e51060f0SSean Hefty { 3605e51060f0SSean Hefty struct cma_hdr *cma_hdr; 3606e51060f0SSean Hefty 360701602f11SSean Hefty cma_hdr = hdr; 360801602f11SSean Hefty cma_hdr->cma_version = CMA_VERSION; 3609f4753834SSean Hefty if (cma_family(id_priv) == AF_INET) { 36101f5175adSAleksey Senin struct sockaddr_in *src4, *dst4; 36111f5175adSAleksey Senin 3612f4753834SSean Hefty src4 = (struct sockaddr_in *) cma_src_addr(id_priv); 3613f4753834SSean Hefty dst4 = (struct sockaddr_in *) cma_dst_addr(id_priv); 3614e51060f0SSean Hefty 3615e51060f0SSean Hefty cma_set_ip_ver(cma_hdr, 4); 3616e51060f0SSean Hefty cma_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr; 3617e51060f0SSean Hefty cma_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr; 3618e51060f0SSean Hefty cma_hdr->port = src4->sin_port; 3619e8160e15SSean Hefty } else if (cma_family(id_priv) == AF_INET6) { 36201f5175adSAleksey Senin struct sockaddr_in6 *src6, *dst6; 36211f5175adSAleksey Senin 3622f4753834SSean Hefty src6 = (struct sockaddr_in6 *) cma_src_addr(id_priv); 3623f4753834SSean Hefty dst6 = (struct sockaddr_in6 *) cma_dst_addr(id_priv); 36241f5175adSAleksey Senin 36251f5175adSAleksey Senin cma_set_ip_ver(cma_hdr, 6); 36261f5175adSAleksey Senin cma_hdr->src_addr.ip6 = src6->sin6_addr; 36271f5175adSAleksey Senin cma_hdr->dst_addr.ip6 = dst6->sin6_addr; 36281f5175adSAleksey Senin cma_hdr->port = src6->sin6_port; 36291f5175adSAleksey Senin } 3630e51060f0SSean Hefty return 0; 3631e51060f0SSean Hefty } 3632e51060f0SSean Hefty 3633628e5f6dSSean Hefty static int cma_sidr_rep_handler(struct ib_cm_id *cm_id, 3634e7ff98aeSParav Pandit const struct ib_cm_event *ib_event) 3635628e5f6dSSean Hefty { 3636628e5f6dSSean Hefty struct rdma_id_private *id_priv = cm_id->context; 36377582df82SParav Pandit struct rdma_cm_event event = {}; 3638e7ff98aeSParav Pandit const struct ib_cm_sidr_rep_event_param *rep = 3639e7ff98aeSParav Pandit &ib_event->param.sidr_rep_rcvd; 3640628e5f6dSSean Hefty int ret = 0; 3641628e5f6dSSean Hefty 364237e07cdaSBart Van Assche mutex_lock(&id_priv->handler_mutex); 364337e07cdaSBart Van Assche if (id_priv->state != RDMA_CM_CONNECT) 364437e07cdaSBart Van Assche goto out; 3645628e5f6dSSean Hefty 3646628e5f6dSSean Hefty switch (ib_event->event) { 3647628e5f6dSSean Hefty case IB_CM_SIDR_REQ_ERROR: 3648628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_UNREACHABLE; 3649628e5f6dSSean Hefty event.status = -ETIMEDOUT; 3650628e5f6dSSean Hefty break; 3651628e5f6dSSean Hefty case IB_CM_SIDR_REP_RECEIVED: 3652628e5f6dSSean Hefty event.param.ud.private_data = ib_event->private_data; 3653628e5f6dSSean Hefty event.param.ud.private_data_len = IB_CM_SIDR_REP_PRIVATE_DATA_SIZE; 3654628e5f6dSSean Hefty if (rep->status != IB_SIDR_SUCCESS) { 3655628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_UNREACHABLE; 3656628e5f6dSSean Hefty event.status = ib_event->param.sidr_rep_rcvd.status; 3657498683c6SMoni Shoua pr_debug_ratelimited("RDMA CM: UNREACHABLE: bad SIDR reply. status %d\n", 3658498683c6SMoni Shoua event.status); 3659628e5f6dSSean Hefty break; 3660628e5f6dSSean Hefty } 36615c438135SSean Hefty ret = cma_set_qkey(id_priv, rep->qkey); 3662d2ca39f2SYossi Etigin if (ret) { 3663498683c6SMoni Shoua pr_debug_ratelimited("RDMA CM: ADDR_ERROR: failed to set qkey. status %d\n", ret); 3664d2ca39f2SYossi Etigin event.event = RDMA_CM_EVENT_ADDR_ERROR; 36655c438135SSean Hefty event.status = ret; 3666628e5f6dSSean Hefty break; 3667628e5f6dSSean Hefty } 36684ad6a024SParav Pandit ib_init_ah_attr_from_path(id_priv->id.device, 36694ad6a024SParav Pandit id_priv->id.port_num, 3670628e5f6dSSean Hefty id_priv->id.route.path_rec, 367139839107SParav Pandit &event.param.ud.ah_attr, 367239839107SParav Pandit rep->sgid_attr); 3673628e5f6dSSean Hefty event.param.ud.qp_num = rep->qpn; 3674628e5f6dSSean Hefty event.param.ud.qkey = rep->qkey; 3675628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_ESTABLISHED; 3676628e5f6dSSean Hefty event.status = 0; 3677628e5f6dSSean Hefty break; 3678628e5f6dSSean Hefty default: 3679aba25a3eSParav Pandit pr_err("RDMA CMA: unexpected IB CM event: %d\n", 3680628e5f6dSSean Hefty ib_event->event); 3681628e5f6dSSean Hefty goto out; 3682628e5f6dSSean Hefty } 3683628e5f6dSSean Hefty 3684628e5f6dSSean Hefty ret = id_priv->id.event_handler(&id_priv->id, &event); 3685aa74f487SParav Pandit 3686aa74f487SParav Pandit rdma_destroy_ah_attr(&event.param.ud.ah_attr); 3687628e5f6dSSean Hefty if (ret) { 3688628e5f6dSSean Hefty /* Destroy the CM ID by returning a non-zero value. */ 3689628e5f6dSSean Hefty id_priv->cm_id.ib = NULL; 3690550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 3691de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 3692628e5f6dSSean Hefty rdma_destroy_id(&id_priv->id); 3693628e5f6dSSean Hefty return ret; 3694628e5f6dSSean Hefty } 3695628e5f6dSSean Hefty out: 3696de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 3697628e5f6dSSean Hefty return ret; 3698628e5f6dSSean Hefty } 3699628e5f6dSSean Hefty 3700628e5f6dSSean Hefty static int cma_resolve_ib_udp(struct rdma_id_private *id_priv, 3701628e5f6dSSean Hefty struct rdma_conn_param *conn_param) 3702628e5f6dSSean Hefty { 3703628e5f6dSSean Hefty struct ib_cm_sidr_req_param req; 37040c9361fcSJack Morgenstein struct ib_cm_id *id; 3705e511d1aeSSean Hefty void *private_data; 3706c0b64f58SBart Van Assche u8 offset; 3707c0b64f58SBart Van Assche int ret; 3708628e5f6dSSean Hefty 3709e511d1aeSSean Hefty memset(&req, 0, sizeof req); 3710e8160e15SSean Hefty offset = cma_user_data_offset(id_priv); 3711e8160e15SSean Hefty req.private_data_len = offset + conn_param->private_data_len; 371204ded167SSean Hefty if (req.private_data_len < conn_param->private_data_len) 371304ded167SSean Hefty return -EINVAL; 371404ded167SSean Hefty 3715e8160e15SSean Hefty if (req.private_data_len) { 3716e511d1aeSSean Hefty private_data = kzalloc(req.private_data_len, GFP_ATOMIC); 3717e511d1aeSSean Hefty if (!private_data) 3718628e5f6dSSean Hefty return -ENOMEM; 3719e8160e15SSean Hefty } else { 3720e511d1aeSSean Hefty private_data = NULL; 3721e8160e15SSean Hefty } 3722628e5f6dSSean Hefty 3723628e5f6dSSean Hefty if (conn_param->private_data && conn_param->private_data_len) 3724e511d1aeSSean Hefty memcpy(private_data + offset, conn_param->private_data, 3725e511d1aeSSean Hefty conn_param->private_data_len); 3726628e5f6dSSean Hefty 3727e511d1aeSSean Hefty if (private_data) { 3728e511d1aeSSean Hefty ret = cma_format_hdr(private_data, id_priv); 3729628e5f6dSSean Hefty if (ret) 3730628e5f6dSSean Hefty goto out; 3731e511d1aeSSean Hefty req.private_data = private_data; 3732e8160e15SSean Hefty } 3733628e5f6dSSean Hefty 37340c9361fcSJack Morgenstein id = ib_create_cm_id(id_priv->id.device, cma_sidr_rep_handler, 37350c9361fcSJack Morgenstein id_priv); 37360c9361fcSJack Morgenstein if (IS_ERR(id)) { 37370c9361fcSJack Morgenstein ret = PTR_ERR(id); 3738628e5f6dSSean Hefty goto out; 3739628e5f6dSSean Hefty } 37400c9361fcSJack Morgenstein id_priv->cm_id.ib = id; 3741628e5f6dSSean Hefty 3742f4753834SSean Hefty req.path = id_priv->id.route.path_rec; 3743815d456eSParav Pandit req.sgid_attr = id_priv->id.route.addr.dev_addr.sgid_attr; 3744cf53936fSSean Hefty req.service_id = rdma_get_service_id(&id_priv->id, cma_dst_addr(id_priv)); 3745628e5f6dSSean Hefty req.timeout_ms = 1 << (CMA_CM_RESPONSE_TIMEOUT - 8); 3746628e5f6dSSean Hefty req.max_cm_retries = CMA_MAX_CM_RETRIES; 3747628e5f6dSSean Hefty 3748628e5f6dSSean Hefty ret = ib_send_cm_sidr_req(id_priv->cm_id.ib, &req); 3749628e5f6dSSean Hefty if (ret) { 3750628e5f6dSSean Hefty ib_destroy_cm_id(id_priv->cm_id.ib); 3751628e5f6dSSean Hefty id_priv->cm_id.ib = NULL; 3752628e5f6dSSean Hefty } 3753628e5f6dSSean Hefty out: 3754e511d1aeSSean Hefty kfree(private_data); 3755628e5f6dSSean Hefty return ret; 3756628e5f6dSSean Hefty } 3757628e5f6dSSean Hefty 3758e51060f0SSean Hefty static int cma_connect_ib(struct rdma_id_private *id_priv, 3759e51060f0SSean Hefty struct rdma_conn_param *conn_param) 3760e51060f0SSean Hefty { 3761e51060f0SSean Hefty struct ib_cm_req_param req; 3762e51060f0SSean Hefty struct rdma_route *route; 3763e51060f0SSean Hefty void *private_data; 37640c9361fcSJack Morgenstein struct ib_cm_id *id; 3765c0b64f58SBart Van Assche u8 offset; 3766c0b64f58SBart Van Assche int ret; 3767e51060f0SSean Hefty 3768e51060f0SSean Hefty memset(&req, 0, sizeof req); 3769e8160e15SSean Hefty offset = cma_user_data_offset(id_priv); 3770e51060f0SSean Hefty req.private_data_len = offset + conn_param->private_data_len; 377104ded167SSean Hefty if (req.private_data_len < conn_param->private_data_len) 377204ded167SSean Hefty return -EINVAL; 377304ded167SSean Hefty 3774e8160e15SSean Hefty if (req.private_data_len) { 3775e51060f0SSean Hefty private_data = kzalloc(req.private_data_len, GFP_ATOMIC); 3776e51060f0SSean Hefty if (!private_data) 3777e51060f0SSean Hefty return -ENOMEM; 3778e8160e15SSean Hefty } else { 3779e8160e15SSean Hefty private_data = NULL; 3780e8160e15SSean Hefty } 3781e51060f0SSean Hefty 3782e51060f0SSean Hefty if (conn_param->private_data && conn_param->private_data_len) 3783e51060f0SSean Hefty memcpy(private_data + offset, conn_param->private_data, 3784e51060f0SSean Hefty conn_param->private_data_len); 3785e51060f0SSean Hefty 37860c9361fcSJack Morgenstein id = ib_create_cm_id(id_priv->id.device, cma_ib_handler, id_priv); 37870c9361fcSJack Morgenstein if (IS_ERR(id)) { 37880c9361fcSJack Morgenstein ret = PTR_ERR(id); 3789e51060f0SSean Hefty goto out; 3790e51060f0SSean Hefty } 37910c9361fcSJack Morgenstein id_priv->cm_id.ib = id; 3792e51060f0SSean Hefty 3793e51060f0SSean Hefty route = &id_priv->id.route; 3794e8160e15SSean Hefty if (private_data) { 3795f4753834SSean Hefty ret = cma_format_hdr(private_data, id_priv); 3796e51060f0SSean Hefty if (ret) 3797e51060f0SSean Hefty goto out; 3798e51060f0SSean Hefty req.private_data = private_data; 3799e8160e15SSean Hefty } 3800e51060f0SSean Hefty 3801e51060f0SSean Hefty req.primary_path = &route->path_rec[0]; 3802e51060f0SSean Hefty if (route->num_paths == 2) 3803e51060f0SSean Hefty req.alternate_path = &route->path_rec[1]; 3804e51060f0SSean Hefty 3805815d456eSParav Pandit req.ppath_sgid_attr = id_priv->id.route.addr.dev_addr.sgid_attr; 3806815d456eSParav Pandit /* Alternate path SGID attribute currently unsupported */ 3807cf53936fSSean Hefty req.service_id = rdma_get_service_id(&id_priv->id, cma_dst_addr(id_priv)); 3808e51060f0SSean Hefty req.qp_num = id_priv->qp_num; 380918c441a6SSean Hefty req.qp_type = id_priv->id.qp_type; 3810e51060f0SSean Hefty req.starting_psn = id_priv->seq_num; 3811e51060f0SSean Hefty req.responder_resources = conn_param->responder_resources; 3812e51060f0SSean Hefty req.initiator_depth = conn_param->initiator_depth; 3813e51060f0SSean Hefty req.flow_control = conn_param->flow_control; 38144ede178aSSean Hefty req.retry_count = min_t(u8, 7, conn_param->retry_count); 38154ede178aSSean Hefty req.rnr_retry_count = min_t(u8, 7, conn_param->rnr_retry_count); 3816e51060f0SSean Hefty req.remote_cm_response_timeout = CMA_CM_RESPONSE_TIMEOUT; 3817e51060f0SSean Hefty req.local_cm_response_timeout = CMA_CM_RESPONSE_TIMEOUT; 3818e51060f0SSean Hefty req.max_cm_retries = CMA_MAX_CM_RETRIES; 3819e51060f0SSean Hefty req.srq = id_priv->srq ? 1 : 0; 3820e51060f0SSean Hefty 3821e51060f0SSean Hefty ret = ib_send_cm_req(id_priv->cm_id.ib, &req); 3822e51060f0SSean Hefty out: 38230c9361fcSJack Morgenstein if (ret && !IS_ERR(id)) { 38240c9361fcSJack Morgenstein ib_destroy_cm_id(id); 3825675a027cSKrishna Kumar id_priv->cm_id.ib = NULL; 3826675a027cSKrishna Kumar } 3827675a027cSKrishna Kumar 3828e51060f0SSean Hefty kfree(private_data); 3829e51060f0SSean Hefty return ret; 3830e51060f0SSean Hefty } 3831e51060f0SSean Hefty 383207ebafbaSTom Tucker static int cma_connect_iw(struct rdma_id_private *id_priv, 383307ebafbaSTom Tucker struct rdma_conn_param *conn_param) 383407ebafbaSTom Tucker { 383507ebafbaSTom Tucker struct iw_cm_id *cm_id; 383607ebafbaSTom Tucker int ret; 383707ebafbaSTom Tucker struct iw_cm_conn_param iw_param; 383807ebafbaSTom Tucker 383907ebafbaSTom Tucker cm_id = iw_create_cm_id(id_priv->id.device, cma_iw_handler, id_priv); 38400c9361fcSJack Morgenstein if (IS_ERR(cm_id)) 38410c9361fcSJack Morgenstein return PTR_ERR(cm_id); 384207ebafbaSTom Tucker 384368cdba06SSteve Wise cm_id->tos = id_priv->tos; 384407ebafbaSTom Tucker id_priv->cm_id.iw = cm_id; 384507ebafbaSTom Tucker 384624d44a39SSteve Wise memcpy(&cm_id->local_addr, cma_src_addr(id_priv), 384724d44a39SSteve Wise rdma_addr_size(cma_src_addr(id_priv))); 384824d44a39SSteve Wise memcpy(&cm_id->remote_addr, cma_dst_addr(id_priv), 384924d44a39SSteve Wise rdma_addr_size(cma_dst_addr(id_priv))); 385007ebafbaSTom Tucker 38515851bb89SSean Hefty ret = cma_modify_qp_rtr(id_priv, conn_param); 3852675a027cSKrishna Kumar if (ret) 3853675a027cSKrishna Kumar goto out; 385407ebafbaSTom Tucker 3855f45ee80eSHefty, Sean if (conn_param) { 385607ebafbaSTom Tucker iw_param.ord = conn_param->initiator_depth; 385707ebafbaSTom Tucker iw_param.ird = conn_param->responder_resources; 385807ebafbaSTom Tucker iw_param.private_data = conn_param->private_data; 385907ebafbaSTom Tucker iw_param.private_data_len = conn_param->private_data_len; 3860f45ee80eSHefty, Sean iw_param.qpn = id_priv->id.qp ? id_priv->qp_num : conn_param->qp_num; 3861f45ee80eSHefty, Sean } else { 3862f45ee80eSHefty, Sean memset(&iw_param, 0, sizeof iw_param); 386307ebafbaSTom Tucker iw_param.qpn = id_priv->qp_num; 3864f45ee80eSHefty, Sean } 386507ebafbaSTom Tucker ret = iw_cm_connect(cm_id, &iw_param); 386607ebafbaSTom Tucker out: 38670c9361fcSJack Morgenstein if (ret) { 3868675a027cSKrishna Kumar iw_destroy_cm_id(cm_id); 3869675a027cSKrishna Kumar id_priv->cm_id.iw = NULL; 3870675a027cSKrishna Kumar } 387107ebafbaSTom Tucker return ret; 387207ebafbaSTom Tucker } 387307ebafbaSTom Tucker 3874e51060f0SSean Hefty int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param) 3875e51060f0SSean Hefty { 3876e51060f0SSean Hefty struct rdma_id_private *id_priv; 3877e51060f0SSean Hefty int ret; 3878e51060f0SSean Hefty 3879e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 3880550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_ROUTE_RESOLVED, RDMA_CM_CONNECT)) 3881e51060f0SSean Hefty return -EINVAL; 3882e51060f0SSean Hefty 3883e51060f0SSean Hefty if (!id->qp) { 3884e51060f0SSean Hefty id_priv->qp_num = conn_param->qp_num; 3885e51060f0SSean Hefty id_priv->srq = conn_param->srq; 3886e51060f0SSean Hefty } 3887e51060f0SSean Hefty 388872219ceaSMichael Wang if (rdma_cap_ib_cm(id->device, id->port_num)) { 3889b26f9b99SSean Hefty if (id->qp_type == IB_QPT_UD) 3890628e5f6dSSean Hefty ret = cma_resolve_ib_udp(id_priv, conn_param); 3891628e5f6dSSean Hefty else 3892e51060f0SSean Hefty ret = cma_connect_ib(id_priv, conn_param); 389304215330SMichael Wang } else if (rdma_cap_iw_cm(id->device, id->port_num)) 389407ebafbaSTom Tucker ret = cma_connect_iw(id_priv, conn_param); 389521655afcSMichael Wang else 3896e51060f0SSean Hefty ret = -ENOSYS; 3897e51060f0SSean Hefty if (ret) 3898e51060f0SSean Hefty goto err; 3899e51060f0SSean Hefty 3900e51060f0SSean Hefty return 0; 3901e51060f0SSean Hefty err: 3902550e5ca7SNir Muchtar cma_comp_exch(id_priv, RDMA_CM_CONNECT, RDMA_CM_ROUTE_RESOLVED); 3903e51060f0SSean Hefty return ret; 3904e51060f0SSean Hefty } 3905e51060f0SSean Hefty EXPORT_SYMBOL(rdma_connect); 3906e51060f0SSean Hefty 3907e51060f0SSean Hefty static int cma_accept_ib(struct rdma_id_private *id_priv, 3908e51060f0SSean Hefty struct rdma_conn_param *conn_param) 3909e51060f0SSean Hefty { 3910e51060f0SSean Hefty struct ib_cm_rep_param rep; 39115851bb89SSean Hefty int ret; 3912e51060f0SSean Hefty 39135851bb89SSean Hefty ret = cma_modify_qp_rtr(id_priv, conn_param); 3914e51060f0SSean Hefty if (ret) 39150fe313b0SSean Hefty goto out; 39160fe313b0SSean Hefty 39175851bb89SSean Hefty ret = cma_modify_qp_rts(id_priv, conn_param); 39180fe313b0SSean Hefty if (ret) 39190fe313b0SSean Hefty goto out; 39200fe313b0SSean Hefty 3921e51060f0SSean Hefty memset(&rep, 0, sizeof rep); 3922e51060f0SSean Hefty rep.qp_num = id_priv->qp_num; 3923e51060f0SSean Hefty rep.starting_psn = id_priv->seq_num; 3924e51060f0SSean Hefty rep.private_data = conn_param->private_data; 3925e51060f0SSean Hefty rep.private_data_len = conn_param->private_data_len; 3926e51060f0SSean Hefty rep.responder_resources = conn_param->responder_resources; 3927e51060f0SSean Hefty rep.initiator_depth = conn_param->initiator_depth; 3928e51060f0SSean Hefty rep.failover_accepted = 0; 3929e51060f0SSean Hefty rep.flow_control = conn_param->flow_control; 39304ede178aSSean Hefty rep.rnr_retry_count = min_t(u8, 7, conn_param->rnr_retry_count); 3931e51060f0SSean Hefty rep.srq = id_priv->srq ? 1 : 0; 3932e51060f0SSean Hefty 39330fe313b0SSean Hefty ret = ib_send_cm_rep(id_priv->cm_id.ib, &rep); 39340fe313b0SSean Hefty out: 39350fe313b0SSean Hefty return ret; 3936e51060f0SSean Hefty } 3937e51060f0SSean Hefty 393807ebafbaSTom Tucker static int cma_accept_iw(struct rdma_id_private *id_priv, 393907ebafbaSTom Tucker struct rdma_conn_param *conn_param) 394007ebafbaSTom Tucker { 394107ebafbaSTom Tucker struct iw_cm_conn_param iw_param; 394207ebafbaSTom Tucker int ret; 394307ebafbaSTom Tucker 3944f2625f7dSSteve Wise if (!conn_param) 3945f2625f7dSSteve Wise return -EINVAL; 3946f2625f7dSSteve Wise 39475851bb89SSean Hefty ret = cma_modify_qp_rtr(id_priv, conn_param); 394807ebafbaSTom Tucker if (ret) 394907ebafbaSTom Tucker return ret; 395007ebafbaSTom Tucker 395107ebafbaSTom Tucker iw_param.ord = conn_param->initiator_depth; 395207ebafbaSTom Tucker iw_param.ird = conn_param->responder_resources; 395307ebafbaSTom Tucker iw_param.private_data = conn_param->private_data; 395407ebafbaSTom Tucker iw_param.private_data_len = conn_param->private_data_len; 395507ebafbaSTom Tucker if (id_priv->id.qp) { 395607ebafbaSTom Tucker iw_param.qpn = id_priv->qp_num; 395707ebafbaSTom Tucker } else 395807ebafbaSTom Tucker iw_param.qpn = conn_param->qp_num; 395907ebafbaSTom Tucker 396007ebafbaSTom Tucker return iw_cm_accept(id_priv->cm_id.iw, &iw_param); 396107ebafbaSTom Tucker } 396207ebafbaSTom Tucker 3963628e5f6dSSean Hefty static int cma_send_sidr_rep(struct rdma_id_private *id_priv, 39645c438135SSean Hefty enum ib_cm_sidr_status status, u32 qkey, 3965628e5f6dSSean Hefty const void *private_data, int private_data_len) 3966628e5f6dSSean Hefty { 3967628e5f6dSSean Hefty struct ib_cm_sidr_rep_param rep; 3968d2ca39f2SYossi Etigin int ret; 3969628e5f6dSSean Hefty 3970628e5f6dSSean Hefty memset(&rep, 0, sizeof rep); 3971628e5f6dSSean Hefty rep.status = status; 3972628e5f6dSSean Hefty if (status == IB_SIDR_SUCCESS) { 39735c438135SSean Hefty ret = cma_set_qkey(id_priv, qkey); 3974d2ca39f2SYossi Etigin if (ret) 3975d2ca39f2SYossi Etigin return ret; 3976628e5f6dSSean Hefty rep.qp_num = id_priv->qp_num; 3977c8f6a362SSean Hefty rep.qkey = id_priv->qkey; 3978628e5f6dSSean Hefty } 3979628e5f6dSSean Hefty rep.private_data = private_data; 3980628e5f6dSSean Hefty rep.private_data_len = private_data_len; 3981628e5f6dSSean Hefty 3982628e5f6dSSean Hefty return ib_send_cm_sidr_rep(id_priv->cm_id.ib, &rep); 3983628e5f6dSSean Hefty } 3984628e5f6dSSean Hefty 398500313983SSteve Wise int __rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param, 398600313983SSteve Wise const char *caller) 3987e51060f0SSean Hefty { 3988e51060f0SSean Hefty struct rdma_id_private *id_priv; 3989e51060f0SSean Hefty int ret; 3990e51060f0SSean Hefty 3991e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 399283e9502dSNir Muchtar 39932165fc26SLeon Romanovsky rdma_restrack_set_task(&id_priv->res, caller); 399483e9502dSNir Muchtar 3995550e5ca7SNir Muchtar if (!cma_comp(id_priv, RDMA_CM_CONNECT)) 3996e51060f0SSean Hefty return -EINVAL; 3997e51060f0SSean Hefty 3998e51060f0SSean Hefty if (!id->qp && conn_param) { 3999e51060f0SSean Hefty id_priv->qp_num = conn_param->qp_num; 4000e51060f0SSean Hefty id_priv->srq = conn_param->srq; 4001e51060f0SSean Hefty } 4002e51060f0SSean Hefty 400372219ceaSMichael Wang if (rdma_cap_ib_cm(id->device, id->port_num)) { 4004f45ee80eSHefty, Sean if (id->qp_type == IB_QPT_UD) { 4005f45ee80eSHefty, Sean if (conn_param) 4006628e5f6dSSean Hefty ret = cma_send_sidr_rep(id_priv, IB_SIDR_SUCCESS, 40075c438135SSean Hefty conn_param->qkey, 4008628e5f6dSSean Hefty conn_param->private_data, 4009628e5f6dSSean Hefty conn_param->private_data_len); 4010f45ee80eSHefty, Sean else 4011f45ee80eSHefty, Sean ret = cma_send_sidr_rep(id_priv, IB_SIDR_SUCCESS, 40125c438135SSean Hefty 0, NULL, 0); 4013f45ee80eSHefty, Sean } else { 4014f45ee80eSHefty, Sean if (conn_param) 4015e51060f0SSean Hefty ret = cma_accept_ib(id_priv, conn_param); 4016e51060f0SSean Hefty else 4017e51060f0SSean Hefty ret = cma_rep_recv(id_priv); 4018f45ee80eSHefty, Sean } 401904215330SMichael Wang } else if (rdma_cap_iw_cm(id->device, id->port_num)) 402007ebafbaSTom Tucker ret = cma_accept_iw(id_priv, conn_param); 402121655afcSMichael Wang else 4022e51060f0SSean Hefty ret = -ENOSYS; 4023e51060f0SSean Hefty 4024e51060f0SSean Hefty if (ret) 4025e51060f0SSean Hefty goto reject; 4026e51060f0SSean Hefty 4027e51060f0SSean Hefty return 0; 4028e51060f0SSean Hefty reject: 4029c5483388SSean Hefty cma_modify_qp_err(id_priv); 4030e51060f0SSean Hefty rdma_reject(id, NULL, 0); 4031e51060f0SSean Hefty return ret; 4032e51060f0SSean Hefty } 403300313983SSteve Wise EXPORT_SYMBOL(__rdma_accept); 4034e51060f0SSean Hefty 40350fe313b0SSean Hefty int rdma_notify(struct rdma_cm_id *id, enum ib_event_type event) 40360fe313b0SSean Hefty { 40370fe313b0SSean Hefty struct rdma_id_private *id_priv; 40380fe313b0SSean Hefty int ret; 40390fe313b0SSean Hefty 40400fe313b0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 40410c9361fcSJack Morgenstein if (!id_priv->cm_id.ib) 40420fe313b0SSean Hefty return -EINVAL; 40430fe313b0SSean Hefty 40440fe313b0SSean Hefty switch (id->device->node_type) { 40450fe313b0SSean Hefty case RDMA_NODE_IB_CA: 40460fe313b0SSean Hefty ret = ib_cm_notify(id_priv->cm_id.ib, event); 40470fe313b0SSean Hefty break; 40480fe313b0SSean Hefty default: 40490fe313b0SSean Hefty ret = 0; 40500fe313b0SSean Hefty break; 40510fe313b0SSean Hefty } 40520fe313b0SSean Hefty return ret; 40530fe313b0SSean Hefty } 40540fe313b0SSean Hefty EXPORT_SYMBOL(rdma_notify); 40550fe313b0SSean Hefty 4056e51060f0SSean Hefty int rdma_reject(struct rdma_cm_id *id, const void *private_data, 4057e51060f0SSean Hefty u8 private_data_len) 4058e51060f0SSean Hefty { 4059e51060f0SSean Hefty struct rdma_id_private *id_priv; 4060e51060f0SSean Hefty int ret; 4061e51060f0SSean Hefty 4062e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 40630c9361fcSJack Morgenstein if (!id_priv->cm_id.ib) 4064e51060f0SSean Hefty return -EINVAL; 4065e51060f0SSean Hefty 406672219ceaSMichael Wang if (rdma_cap_ib_cm(id->device, id->port_num)) { 4067b26f9b99SSean Hefty if (id->qp_type == IB_QPT_UD) 40685c438135SSean Hefty ret = cma_send_sidr_rep(id_priv, IB_SIDR_REJECT, 0, 4069e51060f0SSean Hefty private_data, private_data_len); 4070628e5f6dSSean Hefty else 4071628e5f6dSSean Hefty ret = ib_send_cm_rej(id_priv->cm_id.ib, 4072628e5f6dSSean Hefty IB_CM_REJ_CONSUMER_DEFINED, NULL, 4073628e5f6dSSean Hefty 0, private_data, private_data_len); 407404215330SMichael Wang } else if (rdma_cap_iw_cm(id->device, id->port_num)) { 407507ebafbaSTom Tucker ret = iw_cm_reject(id_priv->cm_id.iw, 407607ebafbaSTom Tucker private_data, private_data_len); 407721655afcSMichael Wang } else 4078e51060f0SSean Hefty ret = -ENOSYS; 407921655afcSMichael Wang 4080e51060f0SSean Hefty return ret; 4081e51060f0SSean Hefty } 4082e51060f0SSean Hefty EXPORT_SYMBOL(rdma_reject); 4083e51060f0SSean Hefty 4084e51060f0SSean Hefty int rdma_disconnect(struct rdma_cm_id *id) 4085e51060f0SSean Hefty { 4086e51060f0SSean Hefty struct rdma_id_private *id_priv; 4087e51060f0SSean Hefty int ret; 4088e51060f0SSean Hefty 4089e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 40900c9361fcSJack Morgenstein if (!id_priv->cm_id.ib) 4091e51060f0SSean Hefty return -EINVAL; 4092e51060f0SSean Hefty 409372219ceaSMichael Wang if (rdma_cap_ib_cm(id->device, id->port_num)) { 4094c5483388SSean Hefty ret = cma_modify_qp_err(id_priv); 4095e51060f0SSean Hefty if (ret) 4096e51060f0SSean Hefty goto out; 4097e51060f0SSean Hefty /* Initiate or respond to a disconnect. */ 4098e51060f0SSean Hefty if (ib_send_cm_dreq(id_priv->cm_id.ib, NULL, 0)) 4099e51060f0SSean Hefty ib_send_cm_drep(id_priv->cm_id.ib, NULL, 0); 410004215330SMichael Wang } else if (rdma_cap_iw_cm(id->device, id->port_num)) { 410107ebafbaSTom Tucker ret = iw_cm_disconnect(id_priv->cm_id.iw, 0); 410221655afcSMichael Wang } else 410307ebafbaSTom Tucker ret = -EINVAL; 410421655afcSMichael Wang 4105e51060f0SSean Hefty out: 4106e51060f0SSean Hefty return ret; 4107e51060f0SSean Hefty } 4108e51060f0SSean Hefty EXPORT_SYMBOL(rdma_disconnect); 4109e51060f0SSean Hefty 4110c8f6a362SSean Hefty static int cma_ib_mc_handler(int status, struct ib_sa_multicast *multicast) 4111c8f6a362SSean Hefty { 4112c8f6a362SSean Hefty struct rdma_id_private *id_priv; 4113c8f6a362SSean Hefty struct cma_multicast *mc = multicast->context; 41147582df82SParav Pandit struct rdma_cm_event event = {}; 411537e07cdaSBart Van Assche int ret = 0; 4116c8f6a362SSean Hefty 4117c8f6a362SSean Hefty id_priv = mc->id_priv; 411837e07cdaSBart Van Assche mutex_lock(&id_priv->handler_mutex); 411937e07cdaSBart Van Assche if (id_priv->state != RDMA_CM_ADDR_BOUND && 412037e07cdaSBart Van Assche id_priv->state != RDMA_CM_ADDR_RESOLVED) 412137e07cdaSBart Van Assche goto out; 4122c8f6a362SSean Hefty 41235c438135SSean Hefty if (!status) 41245c438135SSean Hefty status = cma_set_qkey(id_priv, be32_to_cpu(multicast->rec.qkey)); 4125498683c6SMoni Shoua else 4126498683c6SMoni Shoua pr_debug_ratelimited("RDMA CM: MULTICAST_ERROR: failed to join multicast. status %d\n", 4127498683c6SMoni Shoua status); 4128c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 4129498683c6SMoni Shoua if (!status && id_priv->id.qp) { 4130c8f6a362SSean Hefty status = ib_attach_mcast(id_priv->id.qp, &multicast->rec.mgid, 413146ea5061SSean Hefty be16_to_cpu(multicast->rec.mlid)); 4132a3dd3a48SChristophe Jaillet if (status) 4133498683c6SMoni Shoua pr_debug_ratelimited("RDMA CM: MULTICAST_ERROR: failed to attach QP. status %d\n", 4134498683c6SMoni Shoua status); 4135498683c6SMoni Shoua } 4136c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 4137c8f6a362SSean Hefty 4138c8f6a362SSean Hefty event.status = status; 4139c8f6a362SSean Hefty event.param.ud.private_data = mc->context; 4140c8f6a362SSean Hefty if (!status) { 4141bee3c3c9SMoni Shoua struct rdma_dev_addr *dev_addr = 4142bee3c3c9SMoni Shoua &id_priv->id.route.addr.dev_addr; 4143bee3c3c9SMoni Shoua struct net_device *ndev = 4144052eac6eSParav Pandit dev_get_by_index(dev_addr->net, dev_addr->bound_dev_if); 4145bee3c3c9SMoni Shoua enum ib_gid_type gid_type = 4146bee3c3c9SMoni Shoua id_priv->cma_dev->default_gid_type[id_priv->id.port_num - 4147bee3c3c9SMoni Shoua rdma_start_port(id_priv->cma_dev->device)]; 4148bee3c3c9SMoni Shoua 4149c8f6a362SSean Hefty event.event = RDMA_CM_EVENT_MULTICAST_JOIN; 41506d337179SParav Pandit ret = ib_init_ah_from_mcmember(id_priv->id.device, 41516d337179SParav Pandit id_priv->id.port_num, 41526d337179SParav Pandit &multicast->rec, 4153bee3c3c9SMoni Shoua ndev, gid_type, 4154c8f6a362SSean Hefty &event.param.ud.ah_attr); 41556d337179SParav Pandit if (ret) 41566d337179SParav Pandit event.event = RDMA_CM_EVENT_MULTICAST_ERROR; 41576d337179SParav Pandit 4158c8f6a362SSean Hefty event.param.ud.qp_num = 0xFFFFFF; 4159c8f6a362SSean Hefty event.param.ud.qkey = be32_to_cpu(multicast->rec.qkey); 4160bee3c3c9SMoni Shoua if (ndev) 4161bee3c3c9SMoni Shoua dev_put(ndev); 4162c8f6a362SSean Hefty } else 4163c8f6a362SSean Hefty event.event = RDMA_CM_EVENT_MULTICAST_ERROR; 4164c8f6a362SSean Hefty 4165c8f6a362SSean Hefty ret = id_priv->id.event_handler(&id_priv->id, &event); 4166f685c195SParav Pandit 4167f685c195SParav Pandit rdma_destroy_ah_attr(&event.param.ud.ah_attr); 4168c8f6a362SSean Hefty if (ret) { 4169550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 4170de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 4171c8f6a362SSean Hefty rdma_destroy_id(&id_priv->id); 4172c8f6a362SSean Hefty return 0; 4173c8f6a362SSean Hefty } 41748aa08602SSean Hefty 417537e07cdaSBart Van Assche out: 4176de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 4177c8f6a362SSean Hefty return 0; 4178c8f6a362SSean Hefty } 4179c8f6a362SSean Hefty 4180c8f6a362SSean Hefty static void cma_set_mgid(struct rdma_id_private *id_priv, 4181c8f6a362SSean Hefty struct sockaddr *addr, union ib_gid *mgid) 4182c8f6a362SSean Hefty { 4183c8f6a362SSean Hefty unsigned char mc_map[MAX_ADDR_LEN]; 4184c8f6a362SSean Hefty struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 4185c8f6a362SSean Hefty struct sockaddr_in *sin = (struct sockaddr_in *) addr; 4186c8f6a362SSean Hefty struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) addr; 4187c8f6a362SSean Hefty 4188c8f6a362SSean Hefty if (cma_any_addr(addr)) { 4189c8f6a362SSean Hefty memset(mgid, 0, sizeof *mgid); 4190c8f6a362SSean Hefty } else if ((addr->sa_family == AF_INET6) && 41911c9b2819SJason Gunthorpe ((be32_to_cpu(sin6->sin6_addr.s6_addr32[0]) & 0xFFF0FFFF) == 4192c8f6a362SSean Hefty 0xFF10A01B)) { 4193c8f6a362SSean Hefty /* IPv6 address is an SA assigned MGID. */ 4194c8f6a362SSean Hefty memcpy(mgid, &sin6->sin6_addr, sizeof *mgid); 41955bc2b7b3SSean Hefty } else if (addr->sa_family == AF_IB) { 41965bc2b7b3SSean Hefty memcpy(mgid, &((struct sockaddr_ib *) addr)->sib_addr, sizeof *mgid); 4197076dd53bSVarsha Rao } else if (addr->sa_family == AF_INET6) { 4198e2e62697SJason Gunthorpe ipv6_ib_mc_map(&sin6->sin6_addr, dev_addr->broadcast, mc_map); 4199e2e62697SJason Gunthorpe if (id_priv->id.ps == RDMA_PS_UDP) 4200e2e62697SJason Gunthorpe mc_map[7] = 0x01; /* Use RDMA CM signature */ 4201e2e62697SJason Gunthorpe *mgid = *(union ib_gid *) (mc_map + 4); 4202c8f6a362SSean Hefty } else { 4203a9e527e3SRolf Manderscheid ip_ib_mc_map(sin->sin_addr.s_addr, dev_addr->broadcast, mc_map); 4204c8f6a362SSean Hefty if (id_priv->id.ps == RDMA_PS_UDP) 4205c8f6a362SSean Hefty mc_map[7] = 0x01; /* Use RDMA CM signature */ 4206c8f6a362SSean Hefty *mgid = *(union ib_gid *) (mc_map + 4); 4207c8f6a362SSean Hefty } 4208c8f6a362SSean Hefty } 4209c8f6a362SSean Hefty 4210c8f6a362SSean Hefty static int cma_join_ib_multicast(struct rdma_id_private *id_priv, 4211c8f6a362SSean Hefty struct cma_multicast *mc) 4212c8f6a362SSean Hefty { 4213c8f6a362SSean Hefty struct ib_sa_mcmember_rec rec; 4214c8f6a362SSean Hefty struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 4215c8f6a362SSean Hefty ib_sa_comp_mask comp_mask; 4216c8f6a362SSean Hefty int ret; 4217c8f6a362SSean Hefty 4218c8f6a362SSean Hefty ib_addr_get_mgid(dev_addr, &rec.mgid); 4219c8f6a362SSean Hefty ret = ib_sa_get_mcmember_rec(id_priv->id.device, id_priv->id.port_num, 4220c8f6a362SSean Hefty &rec.mgid, &rec); 4221c8f6a362SSean Hefty if (ret) 4222c8f6a362SSean Hefty return ret; 4223c8f6a362SSean Hefty 42245bc2b7b3SSean Hefty ret = cma_set_qkey(id_priv, 0); 42255bc2b7b3SSean Hefty if (ret) 42265bc2b7b3SSean Hefty return ret; 42275bc2b7b3SSean Hefty 42283f446754SRoland Dreier cma_set_mgid(id_priv, (struct sockaddr *) &mc->addr, &rec.mgid); 42295bc2b7b3SSean Hefty rec.qkey = cpu_to_be32(id_priv->qkey); 42306f8372b6SSean Hefty rdma_addr_get_sgid(dev_addr, &rec.port_gid); 4231c8f6a362SSean Hefty rec.pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr)); 4232ab15c95aSAlex Vesker rec.join_state = mc->join_state; 4233ab15c95aSAlex Vesker 4234ee1c60b1SDasaratharaman Chandramouli if ((rec.join_state == BIT(SENDONLY_FULLMEMBER_JOIN)) && 4235ee1c60b1SDasaratharaman Chandramouli (!ib_sa_sendonly_fullmem_support(&sa_client, 4236ee1c60b1SDasaratharaman Chandramouli id_priv->id.device, 4237ee1c60b1SDasaratharaman Chandramouli id_priv->id.port_num))) { 423843c7c851SJason Gunthorpe dev_warn( 423943c7c851SJason Gunthorpe &id_priv->id.device->dev, 424043c7c851SJason Gunthorpe "RDMA CM: port %u Unable to multicast join: SM doesn't support Send Only Full Member option\n", 424143c7c851SJason Gunthorpe id_priv->id.port_num); 4242ab15c95aSAlex Vesker return -EOPNOTSUPP; 4243ab15c95aSAlex Vesker } 4244c8f6a362SSean Hefty 4245c8f6a362SSean Hefty comp_mask = IB_SA_MCMEMBER_REC_MGID | IB_SA_MCMEMBER_REC_PORT_GID | 4246c8f6a362SSean Hefty IB_SA_MCMEMBER_REC_PKEY | IB_SA_MCMEMBER_REC_JOIN_STATE | 4247c8f6a362SSean Hefty IB_SA_MCMEMBER_REC_QKEY | IB_SA_MCMEMBER_REC_SL | 4248c8f6a362SSean Hefty IB_SA_MCMEMBER_REC_FLOW_LABEL | 4249c8f6a362SSean Hefty IB_SA_MCMEMBER_REC_TRAFFIC_CLASS; 4250c8f6a362SSean Hefty 425184adeee9SYossi Etigin if (id_priv->id.ps == RDMA_PS_IPOIB) 425284adeee9SYossi Etigin comp_mask |= IB_SA_MCMEMBER_REC_RATE | 42532a22fb8cSDotan Barak IB_SA_MCMEMBER_REC_RATE_SELECTOR | 42542a22fb8cSDotan Barak IB_SA_MCMEMBER_REC_MTU_SELECTOR | 42552a22fb8cSDotan Barak IB_SA_MCMEMBER_REC_MTU | 42562a22fb8cSDotan Barak IB_SA_MCMEMBER_REC_HOP_LIMIT; 425784adeee9SYossi Etigin 4258c8f6a362SSean Hefty mc->multicast.ib = ib_sa_join_multicast(&sa_client, id_priv->id.device, 4259c8f6a362SSean Hefty id_priv->id.port_num, &rec, 4260c8f6a362SSean Hefty comp_mask, GFP_KERNEL, 4261c8f6a362SSean Hefty cma_ib_mc_handler, mc); 42628c6ffba0SRusty Russell return PTR_ERR_OR_ZERO(mc->multicast.ib); 4263c8f6a362SSean Hefty } 4264c8f6a362SSean Hefty 42653c86aa70SEli Cohen static void iboe_mcast_work_handler(struct work_struct *work) 42663c86aa70SEli Cohen { 42673c86aa70SEli Cohen struct iboe_mcast_work *mw = container_of(work, struct iboe_mcast_work, work); 42683c86aa70SEli Cohen struct cma_multicast *mc = mw->mc; 42693c86aa70SEli Cohen struct ib_sa_multicast *m = mc->multicast.ib; 42703c86aa70SEli Cohen 42713c86aa70SEli Cohen mc->multicast.ib->context = mc; 42723c86aa70SEli Cohen cma_ib_mc_handler(0, m); 42733c86aa70SEli Cohen kref_put(&mc->mcref, release_mc); 42743c86aa70SEli Cohen kfree(mw); 42753c86aa70SEli Cohen } 42763c86aa70SEli Cohen 4277be1d325aSNoa Osherovich static void cma_iboe_set_mgid(struct sockaddr *addr, union ib_gid *mgid, 4278be1d325aSNoa Osherovich enum ib_gid_type gid_type) 42793c86aa70SEli Cohen { 42803c86aa70SEli Cohen struct sockaddr_in *sin = (struct sockaddr_in *)addr; 42813c86aa70SEli Cohen struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr; 42823c86aa70SEli Cohen 42833c86aa70SEli Cohen if (cma_any_addr(addr)) { 42843c86aa70SEli Cohen memset(mgid, 0, sizeof *mgid); 42853c86aa70SEli Cohen } else if (addr->sa_family == AF_INET6) { 42863c86aa70SEli Cohen memcpy(mgid, &sin6->sin6_addr, sizeof *mgid); 42873c86aa70SEli Cohen } else { 42885c181bdaSParav Pandit mgid->raw[0] = 42895c181bdaSParav Pandit (gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) ? 0 : 0xff; 42905c181bdaSParav Pandit mgid->raw[1] = 42915c181bdaSParav Pandit (gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) ? 0 : 0x0e; 42923c86aa70SEli Cohen mgid->raw[2] = 0; 42933c86aa70SEli Cohen mgid->raw[3] = 0; 42943c86aa70SEli Cohen mgid->raw[4] = 0; 42953c86aa70SEli Cohen mgid->raw[5] = 0; 42963c86aa70SEli Cohen mgid->raw[6] = 0; 42973c86aa70SEli Cohen mgid->raw[7] = 0; 42983c86aa70SEli Cohen mgid->raw[8] = 0; 42993c86aa70SEli Cohen mgid->raw[9] = 0; 43003c86aa70SEli Cohen mgid->raw[10] = 0xff; 43013c86aa70SEli Cohen mgid->raw[11] = 0xff; 43023c86aa70SEli Cohen *(__be32 *)(&mgid->raw[12]) = sin->sin_addr.s_addr; 43033c86aa70SEli Cohen } 43043c86aa70SEli Cohen } 43053c86aa70SEli Cohen 43063c86aa70SEli Cohen static int cma_iboe_join_multicast(struct rdma_id_private *id_priv, 43073c86aa70SEli Cohen struct cma_multicast *mc) 43083c86aa70SEli Cohen { 43093c86aa70SEli Cohen struct iboe_mcast_work *work; 43103c86aa70SEli Cohen struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 4311bee3c3c9SMoni Shoua int err = 0; 43123c86aa70SEli Cohen struct sockaddr *addr = (struct sockaddr *)&mc->addr; 43133c86aa70SEli Cohen struct net_device *ndev = NULL; 4314bee3c3c9SMoni Shoua enum ib_gid_type gid_type; 4315ab15c95aSAlex Vesker bool send_only; 4316ab15c95aSAlex Vesker 4317ab15c95aSAlex Vesker send_only = mc->join_state == BIT(SENDONLY_FULLMEMBER_JOIN); 43183c86aa70SEli Cohen 43193c86aa70SEli Cohen if (cma_zero_addr((struct sockaddr *)&mc->addr)) 43203c86aa70SEli Cohen return -EINVAL; 43213c86aa70SEli Cohen 43223c86aa70SEli Cohen work = kzalloc(sizeof *work, GFP_KERNEL); 43233c86aa70SEli Cohen if (!work) 43243c86aa70SEli Cohen return -ENOMEM; 43253c86aa70SEli Cohen 43263c86aa70SEli Cohen mc->multicast.ib = kzalloc(sizeof(struct ib_sa_multicast), GFP_KERNEL); 43273c86aa70SEli Cohen if (!mc->multicast.ib) { 43283c86aa70SEli Cohen err = -ENOMEM; 43293c86aa70SEli Cohen goto out1; 43303c86aa70SEli Cohen } 43313c86aa70SEli Cohen 4332be1d325aSNoa Osherovich gid_type = id_priv->cma_dev->default_gid_type[id_priv->id.port_num - 4333be1d325aSNoa Osherovich rdma_start_port(id_priv->cma_dev->device)]; 4334be1d325aSNoa Osherovich cma_iboe_set_mgid(addr, &mc->multicast.ib->rec.mgid, gid_type); 43353c86aa70SEli Cohen 43363c86aa70SEli Cohen mc->multicast.ib->rec.pkey = cpu_to_be16(0xffff); 43373c86aa70SEli Cohen if (id_priv->id.ps == RDMA_PS_UDP) 43383c86aa70SEli Cohen mc->multicast.ib->rec.qkey = cpu_to_be32(RDMA_UDP_QKEY); 43393c86aa70SEli Cohen 43403c86aa70SEli Cohen if (dev_addr->bound_dev_if) 4341052eac6eSParav Pandit ndev = dev_get_by_index(dev_addr->net, dev_addr->bound_dev_if); 43423c86aa70SEli Cohen if (!ndev) { 43433c86aa70SEli Cohen err = -ENODEV; 43443c86aa70SEli Cohen goto out2; 43453c86aa70SEli Cohen } 43463c86aa70SEli Cohen mc->multicast.ib->rec.rate = iboe_get_rate(ndev); 43473c86aa70SEli Cohen mc->multicast.ib->rec.hop_limit = 1; 43483c86aa70SEli Cohen mc->multicast.ib->rec.mtu = iboe_get_mtu(ndev->mtu); 4349bee3c3c9SMoni Shoua 4350bee3c3c9SMoni Shoua if (addr->sa_family == AF_INET) { 4351c65f6c5aSAlex Vesker if (gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) { 4352c65f6c5aSAlex Vesker mc->multicast.ib->rec.hop_limit = IPV6_DEFAULT_HOPLIMIT; 4353ab15c95aSAlex Vesker if (!send_only) { 4354bee3c3c9SMoni Shoua err = cma_igmp_send(ndev, &mc->multicast.ib->rec.mgid, 4355bee3c3c9SMoni Shoua true); 4356bee3c3c9SMoni Shoua } 4357bee3c3c9SMoni Shoua } 4358bee3c3c9SMoni Shoua } else { 4359bee3c3c9SMoni Shoua if (gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) 4360bee3c3c9SMoni Shoua err = -ENOTSUPP; 4361bee3c3c9SMoni Shoua } 43623c86aa70SEli Cohen dev_put(ndev); 4363bee3c3c9SMoni Shoua if (err || !mc->multicast.ib->rec.mtu) { 4364bee3c3c9SMoni Shoua if (!err) 43653c86aa70SEli Cohen err = -EINVAL; 43663c86aa70SEli Cohen goto out2; 43673c86aa70SEli Cohen } 43687b85627bSMoni Shoua rdma_ip2gid((struct sockaddr *)&id_priv->id.route.addr.src_addr, 43697b85627bSMoni Shoua &mc->multicast.ib->rec.port_gid); 43703c86aa70SEli Cohen work->id = id_priv; 43713c86aa70SEli Cohen work->mc = mc; 43723c86aa70SEli Cohen INIT_WORK(&work->work, iboe_mcast_work_handler); 43733c86aa70SEli Cohen kref_get(&mc->mcref); 43743c86aa70SEli Cohen queue_work(cma_wq, &work->work); 43753c86aa70SEli Cohen 43763c86aa70SEli Cohen return 0; 43773c86aa70SEli Cohen 43783c86aa70SEli Cohen out2: 43793c86aa70SEli Cohen kfree(mc->multicast.ib); 43803c86aa70SEli Cohen out1: 43813c86aa70SEli Cohen kfree(work); 43823c86aa70SEli Cohen return err; 43833c86aa70SEli Cohen } 43843c86aa70SEli Cohen 4385c8f6a362SSean Hefty int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr, 4386ab15c95aSAlex Vesker u8 join_state, void *context) 4387c8f6a362SSean Hefty { 4388c8f6a362SSean Hefty struct rdma_id_private *id_priv; 4389c8f6a362SSean Hefty struct cma_multicast *mc; 4390c8f6a362SSean Hefty int ret; 4391c8f6a362SSean Hefty 43927688f2c3SLeon Romanovsky if (!id->device) 43937688f2c3SLeon Romanovsky return -EINVAL; 43947688f2c3SLeon Romanovsky 4395c8f6a362SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 4396550e5ca7SNir Muchtar if (!cma_comp(id_priv, RDMA_CM_ADDR_BOUND) && 4397550e5ca7SNir Muchtar !cma_comp(id_priv, RDMA_CM_ADDR_RESOLVED)) 4398c8f6a362SSean Hefty return -EINVAL; 4399c8f6a362SSean Hefty 4400c8f6a362SSean Hefty mc = kmalloc(sizeof *mc, GFP_KERNEL); 4401c8f6a362SSean Hefty if (!mc) 4402c8f6a362SSean Hefty return -ENOMEM; 4403c8f6a362SSean Hefty 4404ef560861SSean Hefty memcpy(&mc->addr, addr, rdma_addr_size(addr)); 4405c8f6a362SSean Hefty mc->context = context; 4406c8f6a362SSean Hefty mc->id_priv = id_priv; 4407ab15c95aSAlex Vesker mc->join_state = join_state; 4408c8f6a362SSean Hefty 44095d9fb044SIra Weiny if (rdma_protocol_roce(id->device, id->port_num)) { 44103c86aa70SEli Cohen kref_init(&mc->mcref); 44113c86aa70SEli Cohen ret = cma_iboe_join_multicast(id_priv, mc); 4412c0126915SJason Gunthorpe if (ret) 4413c0126915SJason Gunthorpe goto out_err; 4414c0126915SJason Gunthorpe } else if (rdma_cap_ib_mcast(id->device, id->port_num)) { 44155c9a5282SMichael Wang ret = cma_join_ib_multicast(id_priv, mc); 4416c0126915SJason Gunthorpe if (ret) 4417c0126915SJason Gunthorpe goto out_err; 4418c0126915SJason Gunthorpe } else { 4419c8f6a362SSean Hefty ret = -ENOSYS; 4420c0126915SJason Gunthorpe goto out_err; 4421c8f6a362SSean Hefty } 4422c0126915SJason Gunthorpe 4423c0126915SJason Gunthorpe spin_lock(&id_priv->lock); 4424c0126915SJason Gunthorpe list_add(&mc->list, &id_priv->mc_list); 4425c0126915SJason Gunthorpe spin_unlock(&id_priv->lock); 4426c0126915SJason Gunthorpe 4427c0126915SJason Gunthorpe return 0; 4428c0126915SJason Gunthorpe out_err: 4429c0126915SJason Gunthorpe kfree(mc); 4430c8f6a362SSean Hefty return ret; 4431c8f6a362SSean Hefty } 4432c8f6a362SSean Hefty EXPORT_SYMBOL(rdma_join_multicast); 4433c8f6a362SSean Hefty 4434c8f6a362SSean Hefty void rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr) 4435c8f6a362SSean Hefty { 4436c8f6a362SSean Hefty struct rdma_id_private *id_priv; 4437c8f6a362SSean Hefty struct cma_multicast *mc; 4438c8f6a362SSean Hefty 4439c8f6a362SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 4440c8f6a362SSean Hefty spin_lock_irq(&id_priv->lock); 4441c8f6a362SSean Hefty list_for_each_entry(mc, &id_priv->mc_list, list) { 4442ef560861SSean Hefty if (!memcmp(&mc->addr, addr, rdma_addr_size(addr))) { 4443c8f6a362SSean Hefty list_del(&mc->list); 4444c8f6a362SSean Hefty spin_unlock_irq(&id_priv->lock); 4445c8f6a362SSean Hefty 4446c8f6a362SSean Hefty if (id->qp) 4447c8f6a362SSean Hefty ib_detach_mcast(id->qp, 4448c8f6a362SSean Hefty &mc->multicast.ib->rec.mgid, 444946ea5061SSean Hefty be16_to_cpu(mc->multicast.ib->rec.mlid)); 44505c9a5282SMichael Wang 44515c9a5282SMichael Wang BUG_ON(id_priv->cma_dev->device != id->device); 44525c9a5282SMichael Wang 4453a31ad3b0SMichael Wang if (rdma_cap_ib_mcast(id->device, id->port_num)) { 4454c8f6a362SSean Hefty ib_sa_free_multicast(mc->multicast.ib); 4455c8f6a362SSean Hefty kfree(mc); 4456bee3c3c9SMoni Shoua } else if (rdma_protocol_roce(id->device, id->port_num)) { 445788145678SParav Pandit cma_leave_roce_mc_group(id_priv, mc); 4458bee3c3c9SMoni Shoua } 4459c8f6a362SSean Hefty return; 4460c8f6a362SSean Hefty } 4461c8f6a362SSean Hefty } 4462c8f6a362SSean Hefty spin_unlock_irq(&id_priv->lock); 4463c8f6a362SSean Hefty } 4464c8f6a362SSean Hefty EXPORT_SYMBOL(rdma_leave_multicast); 4465c8f6a362SSean Hefty 4466dd5bdff8SOr Gerlitz static int cma_netdev_change(struct net_device *ndev, struct rdma_id_private *id_priv) 4467dd5bdff8SOr Gerlitz { 4468dd5bdff8SOr Gerlitz struct rdma_dev_addr *dev_addr; 4469dd5bdff8SOr Gerlitz struct cma_ndev_work *work; 4470dd5bdff8SOr Gerlitz 4471dd5bdff8SOr Gerlitz dev_addr = &id_priv->id.route.addr.dev_addr; 4472dd5bdff8SOr Gerlitz 44736266ed6eSSean Hefty if ((dev_addr->bound_dev_if == ndev->ifindex) && 4474fa20105eSGuy Shapiro (net_eq(dev_net(ndev), dev_addr->net)) && 4475dd5bdff8SOr Gerlitz memcmp(dev_addr->src_dev_addr, ndev->dev_addr, ndev->addr_len)) { 4476aba25a3eSParav Pandit pr_info("RDMA CM addr change for ndev %s used by id %p\n", 4477dd5bdff8SOr Gerlitz ndev->name, &id_priv->id); 4478dd5bdff8SOr Gerlitz work = kzalloc(sizeof *work, GFP_KERNEL); 4479dd5bdff8SOr Gerlitz if (!work) 4480dd5bdff8SOr Gerlitz return -ENOMEM; 4481dd5bdff8SOr Gerlitz 4482dd5bdff8SOr Gerlitz INIT_WORK(&work->work, cma_ndev_work_handler); 4483dd5bdff8SOr Gerlitz work->id = id_priv; 4484dd5bdff8SOr Gerlitz work->event.event = RDMA_CM_EVENT_ADDR_CHANGE; 4485dd5bdff8SOr Gerlitz atomic_inc(&id_priv->refcount); 4486dd5bdff8SOr Gerlitz queue_work(cma_wq, &work->work); 4487dd5bdff8SOr Gerlitz } 4488dd5bdff8SOr Gerlitz 4489dd5bdff8SOr Gerlitz return 0; 4490dd5bdff8SOr Gerlitz } 4491dd5bdff8SOr Gerlitz 4492dd5bdff8SOr Gerlitz static int cma_netdev_callback(struct notifier_block *self, unsigned long event, 4493351638e7SJiri Pirko void *ptr) 4494dd5bdff8SOr Gerlitz { 4495351638e7SJiri Pirko struct net_device *ndev = netdev_notifier_info_to_dev(ptr); 4496dd5bdff8SOr Gerlitz struct cma_device *cma_dev; 4497dd5bdff8SOr Gerlitz struct rdma_id_private *id_priv; 4498dd5bdff8SOr Gerlitz int ret = NOTIFY_DONE; 4499dd5bdff8SOr Gerlitz 4500dd5bdff8SOr Gerlitz if (event != NETDEV_BONDING_FAILOVER) 4501dd5bdff8SOr Gerlitz return NOTIFY_DONE; 4502dd5bdff8SOr Gerlitz 45033cd96fddSParav Pandit if (!netif_is_bond_master(ndev)) 4504dd5bdff8SOr Gerlitz return NOTIFY_DONE; 4505dd5bdff8SOr Gerlitz 4506dd5bdff8SOr Gerlitz mutex_lock(&lock); 4507dd5bdff8SOr Gerlitz list_for_each_entry(cma_dev, &dev_list, list) 4508dd5bdff8SOr Gerlitz list_for_each_entry(id_priv, &cma_dev->id_list, list) { 4509dd5bdff8SOr Gerlitz ret = cma_netdev_change(ndev, id_priv); 4510dd5bdff8SOr Gerlitz if (ret) 4511dd5bdff8SOr Gerlitz goto out; 4512dd5bdff8SOr Gerlitz } 4513dd5bdff8SOr Gerlitz 4514dd5bdff8SOr Gerlitz out: 4515dd5bdff8SOr Gerlitz mutex_unlock(&lock); 4516dd5bdff8SOr Gerlitz return ret; 4517dd5bdff8SOr Gerlitz } 4518dd5bdff8SOr Gerlitz 4519dd5bdff8SOr Gerlitz static struct notifier_block cma_nb = { 4520dd5bdff8SOr Gerlitz .notifier_call = cma_netdev_callback 4521dd5bdff8SOr Gerlitz }; 4522dd5bdff8SOr Gerlitz 4523e51060f0SSean Hefty static void cma_add_one(struct ib_device *device) 4524e51060f0SSean Hefty { 4525e51060f0SSean Hefty struct cma_device *cma_dev; 4526e51060f0SSean Hefty struct rdma_id_private *id_priv; 4527045959dbSMatan Barak unsigned int i; 4528045959dbSMatan Barak unsigned long supported_gids = 0; 4529e51060f0SSean Hefty 4530e51060f0SSean Hefty cma_dev = kmalloc(sizeof *cma_dev, GFP_KERNEL); 4531e51060f0SSean Hefty if (!cma_dev) 4532e51060f0SSean Hefty return; 4533e51060f0SSean Hefty 4534e51060f0SSean Hefty cma_dev->device = device; 4535045959dbSMatan Barak cma_dev->default_gid_type = kcalloc(device->phys_port_cnt, 4536045959dbSMatan Barak sizeof(*cma_dev->default_gid_type), 4537045959dbSMatan Barak GFP_KERNEL); 453889052d78SMajd Dibbiny if (!cma_dev->default_gid_type) 453989052d78SMajd Dibbiny goto free_cma_dev; 454089052d78SMajd Dibbiny 454189052d78SMajd Dibbiny cma_dev->default_roce_tos = kcalloc(device->phys_port_cnt, 454289052d78SMajd Dibbiny sizeof(*cma_dev->default_roce_tos), 454389052d78SMajd Dibbiny GFP_KERNEL); 454489052d78SMajd Dibbiny if (!cma_dev->default_roce_tos) 454589052d78SMajd Dibbiny goto free_gid_type; 454689052d78SMajd Dibbiny 4547045959dbSMatan Barak for (i = rdma_start_port(device); i <= rdma_end_port(device); i++) { 4548045959dbSMatan Barak supported_gids = roce_gid_type_mask_support(device, i); 4549045959dbSMatan Barak WARN_ON(!supported_gids); 45505ab2d89bSLeon Romanovsky if (supported_gids & (1 << CMA_PREFERRED_ROCE_GID_TYPE)) 455163a5f483SMoni Shoua cma_dev->default_gid_type[i - rdma_start_port(device)] = 455263a5f483SMoni Shoua CMA_PREFERRED_ROCE_GID_TYPE; 455363a5f483SMoni Shoua else 4554045959dbSMatan Barak cma_dev->default_gid_type[i - rdma_start_port(device)] = 4555045959dbSMatan Barak find_first_bit(&supported_gids, BITS_PER_LONG); 455689052d78SMajd Dibbiny cma_dev->default_roce_tos[i - rdma_start_port(device)] = 0; 4557045959dbSMatan Barak } 4558e51060f0SSean Hefty 4559e51060f0SSean Hefty init_completion(&cma_dev->comp); 4560e51060f0SSean Hefty atomic_set(&cma_dev->refcount, 1); 4561e51060f0SSean Hefty INIT_LIST_HEAD(&cma_dev->id_list); 4562e51060f0SSean Hefty ib_set_client_data(device, &cma_client, cma_dev); 4563e51060f0SSean Hefty 4564e51060f0SSean Hefty mutex_lock(&lock); 4565e51060f0SSean Hefty list_add_tail(&cma_dev->list, &dev_list); 4566e51060f0SSean Hefty list_for_each_entry(id_priv, &listen_any_list, list) 4567e51060f0SSean Hefty cma_listen_on_dev(id_priv, cma_dev); 4568e51060f0SSean Hefty mutex_unlock(&lock); 456989052d78SMajd Dibbiny 457089052d78SMajd Dibbiny return; 457189052d78SMajd Dibbiny 457289052d78SMajd Dibbiny free_gid_type: 457389052d78SMajd Dibbiny kfree(cma_dev->default_gid_type); 457489052d78SMajd Dibbiny 457589052d78SMajd Dibbiny free_cma_dev: 457689052d78SMajd Dibbiny kfree(cma_dev); 457789052d78SMajd Dibbiny 457889052d78SMajd Dibbiny return; 4579e51060f0SSean Hefty } 4580e51060f0SSean Hefty 4581e51060f0SSean Hefty static int cma_remove_id_dev(struct rdma_id_private *id_priv) 4582e51060f0SSean Hefty { 45837582df82SParav Pandit struct rdma_cm_event event = {}; 4584550e5ca7SNir Muchtar enum rdma_cm_state state; 4585de910bd9SOr Gerlitz int ret = 0; 4586e51060f0SSean Hefty 4587e51060f0SSean Hefty /* Record that we want to remove the device */ 4588550e5ca7SNir Muchtar state = cma_exch(id_priv, RDMA_CM_DEVICE_REMOVAL); 4589550e5ca7SNir Muchtar if (state == RDMA_CM_DESTROYING) 4590e51060f0SSean Hefty return 0; 4591e51060f0SSean Hefty 4592e51060f0SSean Hefty cma_cancel_operation(id_priv, state); 4593de910bd9SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 4594e51060f0SSean Hefty 4595e51060f0SSean Hefty /* Check for destruction from another callback. */ 4596550e5ca7SNir Muchtar if (!cma_comp(id_priv, RDMA_CM_DEVICE_REMOVAL)) 4597de910bd9SOr Gerlitz goto out; 4598e51060f0SSean Hefty 4599a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_DEVICE_REMOVAL; 4600de910bd9SOr Gerlitz ret = id_priv->id.event_handler(&id_priv->id, &event); 4601de910bd9SOr Gerlitz out: 4602de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 4603de910bd9SOr Gerlitz return ret; 4604e51060f0SSean Hefty } 4605e51060f0SSean Hefty 4606e51060f0SSean Hefty static void cma_process_remove(struct cma_device *cma_dev) 4607e51060f0SSean Hefty { 4608e51060f0SSean Hefty struct rdma_id_private *id_priv; 4609e51060f0SSean Hefty int ret; 4610e51060f0SSean Hefty 4611e51060f0SSean Hefty mutex_lock(&lock); 4612e51060f0SSean Hefty while (!list_empty(&cma_dev->id_list)) { 4613e51060f0SSean Hefty id_priv = list_entry(cma_dev->id_list.next, 4614e51060f0SSean Hefty struct rdma_id_private, list); 4615e51060f0SSean Hefty 4616d02d1f53SSean Hefty list_del(&id_priv->listen_list); 461794de178aSKrishna Kumar list_del_init(&id_priv->list); 4618e51060f0SSean Hefty atomic_inc(&id_priv->refcount); 4619e51060f0SSean Hefty mutex_unlock(&lock); 4620e51060f0SSean Hefty 4621d02d1f53SSean Hefty ret = id_priv->internal_id ? 1 : cma_remove_id_dev(id_priv); 4622e51060f0SSean Hefty cma_deref_id(id_priv); 4623e51060f0SSean Hefty if (ret) 4624e51060f0SSean Hefty rdma_destroy_id(&id_priv->id); 4625e51060f0SSean Hefty 4626e51060f0SSean Hefty mutex_lock(&lock); 4627e51060f0SSean Hefty } 4628e51060f0SSean Hefty mutex_unlock(&lock); 4629e51060f0SSean Hefty 4630e51060f0SSean Hefty cma_deref_dev(cma_dev); 4631e51060f0SSean Hefty wait_for_completion(&cma_dev->comp); 4632e51060f0SSean Hefty } 4633e51060f0SSean Hefty 46347c1eb45aSHaggai Eran static void cma_remove_one(struct ib_device *device, void *client_data) 4635e51060f0SSean Hefty { 46367c1eb45aSHaggai Eran struct cma_device *cma_dev = client_data; 4637e51060f0SSean Hefty 4638e51060f0SSean Hefty if (!cma_dev) 4639e51060f0SSean Hefty return; 4640e51060f0SSean Hefty 4641e51060f0SSean Hefty mutex_lock(&lock); 4642e51060f0SSean Hefty list_del(&cma_dev->list); 4643e51060f0SSean Hefty mutex_unlock(&lock); 4644e51060f0SSean Hefty 4645e51060f0SSean Hefty cma_process_remove(cma_dev); 464689052d78SMajd Dibbiny kfree(cma_dev->default_roce_tos); 4647045959dbSMatan Barak kfree(cma_dev->default_gid_type); 4648e51060f0SSean Hefty kfree(cma_dev); 4649e51060f0SSean Hefty } 4650e51060f0SSean Hefty 46514be74b42SHaggai Eran static int cma_init_net(struct net *net) 46524be74b42SHaggai Eran { 46534be74b42SHaggai Eran struct cma_pernet *pernet = cma_pernet(net); 46544be74b42SHaggai Eran 46554be74b42SHaggai Eran idr_init(&pernet->tcp_ps); 46564be74b42SHaggai Eran idr_init(&pernet->udp_ps); 46574be74b42SHaggai Eran idr_init(&pernet->ipoib_ps); 46584be74b42SHaggai Eran idr_init(&pernet->ib_ps); 46594be74b42SHaggai Eran 46604be74b42SHaggai Eran return 0; 46614be74b42SHaggai Eran } 46624be74b42SHaggai Eran 46634be74b42SHaggai Eran static void cma_exit_net(struct net *net) 46644be74b42SHaggai Eran { 46654be74b42SHaggai Eran struct cma_pernet *pernet = cma_pernet(net); 46664be74b42SHaggai Eran 46674be74b42SHaggai Eran idr_destroy(&pernet->tcp_ps); 46684be74b42SHaggai Eran idr_destroy(&pernet->udp_ps); 46694be74b42SHaggai Eran idr_destroy(&pernet->ipoib_ps); 46704be74b42SHaggai Eran idr_destroy(&pernet->ib_ps); 46714be74b42SHaggai Eran } 46724be74b42SHaggai Eran 46734be74b42SHaggai Eran static struct pernet_operations cma_pernet_operations = { 46744be74b42SHaggai Eran .init = cma_init_net, 46754be74b42SHaggai Eran .exit = cma_exit_net, 46764be74b42SHaggai Eran .id = &cma_pernet_id, 46774be74b42SHaggai Eran .size = sizeof(struct cma_pernet), 46784be74b42SHaggai Eran }; 46794be74b42SHaggai Eran 4680716abb1fSPeter Huewe static int __init cma_init(void) 4681e51060f0SSean Hefty { 46825d7220e8STetsuo Handa int ret; 4683227b60f5SStephen Hemminger 4684dee9acbbSBhaktipriya Shridhar cma_wq = alloc_ordered_workqueue("rdma_cm", WQ_MEM_RECLAIM); 4685e51060f0SSean Hefty if (!cma_wq) 4686e51060f0SSean Hefty return -ENOMEM; 4687e51060f0SSean Hefty 46884be74b42SHaggai Eran ret = register_pernet_subsys(&cma_pernet_operations); 46894be74b42SHaggai Eran if (ret) 46904be74b42SHaggai Eran goto err_wq; 46914be74b42SHaggai Eran 4692c1a0b23bSMichael S. Tsirkin ib_sa_register_client(&sa_client); 4693dd5bdff8SOr Gerlitz register_netdevice_notifier(&cma_nb); 4694c1a0b23bSMichael S. Tsirkin 4695e51060f0SSean Hefty ret = ib_register_client(&cma_client); 4696e51060f0SSean Hefty if (ret) 4697e51060f0SSean Hefty goto err; 4698753f618aSNir Muchtar 4699045959dbSMatan Barak cma_configfs_init(); 4700753f618aSNir Muchtar 4701e51060f0SSean Hefty return 0; 4702e51060f0SSean Hefty 4703e51060f0SSean Hefty err: 4704dd5bdff8SOr Gerlitz unregister_netdevice_notifier(&cma_nb); 4705c1a0b23bSMichael S. Tsirkin ib_sa_unregister_client(&sa_client); 47064be74b42SHaggai Eran err_wq: 4707e51060f0SSean Hefty destroy_workqueue(cma_wq); 4708e51060f0SSean Hefty return ret; 4709e51060f0SSean Hefty } 4710e51060f0SSean Hefty 4711716abb1fSPeter Huewe static void __exit cma_cleanup(void) 4712e51060f0SSean Hefty { 4713045959dbSMatan Barak cma_configfs_exit(); 4714e51060f0SSean Hefty ib_unregister_client(&cma_client); 4715dd5bdff8SOr Gerlitz unregister_netdevice_notifier(&cma_nb); 4716c1a0b23bSMichael S. Tsirkin ib_sa_unregister_client(&sa_client); 47174be74b42SHaggai Eran unregister_pernet_subsys(&cma_pernet_operations); 4718e51060f0SSean Hefty destroy_workqueue(cma_wq); 4719e51060f0SSean Hefty } 4720e51060f0SSean Hefty 4721e51060f0SSean Hefty module_init(cma_init); 4722e51060f0SSean Hefty module_exit(cma_cleanup); 4723