1*24f52149SLeon Romanovsky // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2e51060f0SSean Hefty /* 3e51060f0SSean Hefty * Copyright (c) 2005 Voltaire Inc. All rights reserved. 4e51060f0SSean Hefty * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. 5*24f52149SLeon Romanovsky * Copyright (c) 1999-2019, Mellanox Technologies, Inc. All rights reserved. 6e51060f0SSean Hefty * Copyright (c) 2005-2006 Intel Corporation. All rights reserved. 7e51060f0SSean Hefty */ 8e51060f0SSean Hefty 9e51060f0SSean Hefty #include <linux/completion.h> 10e51060f0SSean Hefty #include <linux/in.h> 11e51060f0SSean Hefty #include <linux/in6.h> 12e51060f0SSean Hefty #include <linux/mutex.h> 13e51060f0SSean Hefty #include <linux/random.h> 14bee3c3c9SMoni Shoua #include <linux/igmp.h> 1563826753SMatthew Wilcox #include <linux/xarray.h> 1607ebafbaSTom Tucker #include <linux/inetdevice.h> 175a0e3ad6STejun Heo #include <linux/slab.h> 18e4dd23d7SPaul Gortmaker #include <linux/module.h> 19366cddb4SAmir Vadai #include <net/route.h> 20e51060f0SSean Hefty 214be74b42SHaggai Eran #include <net/net_namespace.h> 224be74b42SHaggai Eran #include <net/netns/generic.h> 23e51060f0SSean Hefty #include <net/tcp.h> 241f5175adSAleksey Senin #include <net/ipv6.h> 25f887f2acSHaggai Eran #include <net/ip_fib.h> 26f887f2acSHaggai Eran #include <net/ip6_route.h> 27e51060f0SSean Hefty 28e51060f0SSean Hefty #include <rdma/rdma_cm.h> 29e51060f0SSean Hefty #include <rdma/rdma_cm_ib.h> 30753f618aSNir Muchtar #include <rdma/rdma_netlink.h> 312e2d190cSSean Hefty #include <rdma/ib.h> 32e51060f0SSean Hefty #include <rdma/ib_cache.h> 33e51060f0SSean Hefty #include <rdma/ib_cm.h> 34e51060f0SSean Hefty #include <rdma/ib_sa.h> 3507ebafbaSTom Tucker #include <rdma/iw_cm.h> 36e51060f0SSean Hefty 37218a773fSMatan Barak #include "core_priv.h" 38a3b641afSSteve Wise #include "cma_priv.h" 39218a773fSMatan Barak 40e51060f0SSean Hefty MODULE_AUTHOR("Sean Hefty"); 41e51060f0SSean Hefty MODULE_DESCRIPTION("Generic RDMA CM Agent"); 42e51060f0SSean Hefty MODULE_LICENSE("Dual BSD/GPL"); 43e51060f0SSean Hefty 44e51060f0SSean Hefty #define CMA_CM_RESPONSE_TIMEOUT 20 45ab15c95aSAlex Vesker #define CMA_QUERY_CLASSPORT_INFO_TIMEOUT 3000 46d5bb7599SMichael S. Tsirkin #define CMA_MAX_CM_RETRIES 15 47dcb3f974SSean Hefty #define CMA_CM_MRA_SETTING (IB_CM_MRA_FLAG_DELAY | 24) 483c86aa70SEli Cohen #define CMA_IBOE_PACKET_LIFETIME 18 495ab2d89bSLeon Romanovsky #define CMA_PREFERRED_ROCE_GID_TYPE IB_GID_TYPE_ROCE_UDP_ENCAP 50e51060f0SSean Hefty 512b1b5b60SSagi Grimberg static const char * const cma_events[] = { 522b1b5b60SSagi Grimberg [RDMA_CM_EVENT_ADDR_RESOLVED] = "address resolved", 532b1b5b60SSagi Grimberg [RDMA_CM_EVENT_ADDR_ERROR] = "address error", 542b1b5b60SSagi Grimberg [RDMA_CM_EVENT_ROUTE_RESOLVED] = "route resolved ", 552b1b5b60SSagi Grimberg [RDMA_CM_EVENT_ROUTE_ERROR] = "route error", 562b1b5b60SSagi Grimberg [RDMA_CM_EVENT_CONNECT_REQUEST] = "connect request", 572b1b5b60SSagi Grimberg [RDMA_CM_EVENT_CONNECT_RESPONSE] = "connect response", 582b1b5b60SSagi Grimberg [RDMA_CM_EVENT_CONNECT_ERROR] = "connect error", 592b1b5b60SSagi Grimberg [RDMA_CM_EVENT_UNREACHABLE] = "unreachable", 602b1b5b60SSagi Grimberg [RDMA_CM_EVENT_REJECTED] = "rejected", 612b1b5b60SSagi Grimberg [RDMA_CM_EVENT_ESTABLISHED] = "established", 622b1b5b60SSagi Grimberg [RDMA_CM_EVENT_DISCONNECTED] = "disconnected", 632b1b5b60SSagi Grimberg [RDMA_CM_EVENT_DEVICE_REMOVAL] = "device removal", 642b1b5b60SSagi Grimberg [RDMA_CM_EVENT_MULTICAST_JOIN] = "multicast join", 652b1b5b60SSagi Grimberg [RDMA_CM_EVENT_MULTICAST_ERROR] = "multicast error", 662b1b5b60SSagi Grimberg [RDMA_CM_EVENT_ADDR_CHANGE] = "address change", 672b1b5b60SSagi Grimberg [RDMA_CM_EVENT_TIMEWAIT_EXIT] = "timewait exit", 682b1b5b60SSagi Grimberg }; 692b1b5b60SSagi Grimberg 70db7489e0SBart Van Assche const char *__attribute_const__ rdma_event_msg(enum rdma_cm_event_type event) 712b1b5b60SSagi Grimberg { 722b1b5b60SSagi Grimberg size_t index = event; 732b1b5b60SSagi Grimberg 742b1b5b60SSagi Grimberg return (index < ARRAY_SIZE(cma_events) && cma_events[index]) ? 752b1b5b60SSagi Grimberg cma_events[index] : "unrecognized event"; 762b1b5b60SSagi Grimberg } 772b1b5b60SSagi Grimberg EXPORT_SYMBOL(rdma_event_msg); 782b1b5b60SSagi Grimberg 7977a5db13SSteve Wise const char *__attribute_const__ rdma_reject_msg(struct rdma_cm_id *id, 8077a5db13SSteve Wise int reason) 8177a5db13SSteve Wise { 8277a5db13SSteve Wise if (rdma_ib_or_roce(id->device, id->port_num)) 8377a5db13SSteve Wise return ibcm_reject_msg(reason); 8477a5db13SSteve Wise 8577a5db13SSteve Wise if (rdma_protocol_iwarp(id->device, id->port_num)) 8677a5db13SSteve Wise return iwcm_reject_msg(reason); 8777a5db13SSteve Wise 8877a5db13SSteve Wise WARN_ON_ONCE(1); 8977a5db13SSteve Wise return "unrecognized transport"; 9077a5db13SSteve Wise } 9177a5db13SSteve Wise EXPORT_SYMBOL(rdma_reject_msg); 9277a5db13SSteve Wise 935042a73dSSteve Wise bool rdma_is_consumer_reject(struct rdma_cm_id *id, int reason) 945042a73dSSteve Wise { 955042a73dSSteve Wise if (rdma_ib_or_roce(id->device, id->port_num)) 965042a73dSSteve Wise return reason == IB_CM_REJ_CONSUMER_DEFINED; 975042a73dSSteve Wise 985042a73dSSteve Wise if (rdma_protocol_iwarp(id->device, id->port_num)) 995042a73dSSteve Wise return reason == -ECONNREFUSED; 1005042a73dSSteve Wise 1015042a73dSSteve Wise WARN_ON_ONCE(1); 1025042a73dSSteve Wise return false; 1035042a73dSSteve Wise } 1045042a73dSSteve Wise EXPORT_SYMBOL(rdma_is_consumer_reject); 1055042a73dSSteve Wise 1065f244104SSteve Wise const void *rdma_consumer_reject_data(struct rdma_cm_id *id, 1075f244104SSteve Wise struct rdma_cm_event *ev, u8 *data_len) 1085f244104SSteve Wise { 1095f244104SSteve Wise const void *p; 1105f244104SSteve Wise 1115f244104SSteve Wise if (rdma_is_consumer_reject(id, ev->status)) { 1125f244104SSteve Wise *data_len = ev->param.conn.private_data_len; 1135f244104SSteve Wise p = ev->param.conn.private_data; 1145f244104SSteve Wise } else { 1155f244104SSteve Wise *data_len = 0; 1165f244104SSteve Wise p = NULL; 1175f244104SSteve Wise } 1185f244104SSteve Wise return p; 1195f244104SSteve Wise } 1205f244104SSteve Wise EXPORT_SYMBOL(rdma_consumer_reject_data); 1215f244104SSteve Wise 122fbdb0a91SSteve Wise /** 123fbdb0a91SSteve Wise * rdma_iw_cm_id() - return the iw_cm_id pointer for this cm_id. 124fbdb0a91SSteve Wise * @id: Communication Identifier 125fbdb0a91SSteve Wise */ 126fbdb0a91SSteve Wise struct iw_cm_id *rdma_iw_cm_id(struct rdma_cm_id *id) 127fbdb0a91SSteve Wise { 128fbdb0a91SSteve Wise struct rdma_id_private *id_priv; 129fbdb0a91SSteve Wise 130fbdb0a91SSteve Wise id_priv = container_of(id, struct rdma_id_private, id); 131fbdb0a91SSteve Wise if (id->device->node_type == RDMA_NODE_RNIC) 132fbdb0a91SSteve Wise return id_priv->cm_id.iw; 133fbdb0a91SSteve Wise return NULL; 134fbdb0a91SSteve Wise } 135fbdb0a91SSteve Wise EXPORT_SYMBOL(rdma_iw_cm_id); 136fbdb0a91SSteve Wise 137fbdb0a91SSteve Wise /** 138fbdb0a91SSteve Wise * rdma_res_to_id() - return the rdma_cm_id pointer for this restrack. 139fbdb0a91SSteve Wise * @res: rdma resource tracking entry pointer 140fbdb0a91SSteve Wise */ 141fbdb0a91SSteve Wise struct rdma_cm_id *rdma_res_to_id(struct rdma_restrack_entry *res) 142fbdb0a91SSteve Wise { 143fbdb0a91SSteve Wise struct rdma_id_private *id_priv = 144fbdb0a91SSteve Wise container_of(res, struct rdma_id_private, res); 145fbdb0a91SSteve Wise 146fbdb0a91SSteve Wise return &id_priv->id; 147fbdb0a91SSteve Wise } 148fbdb0a91SSteve Wise EXPORT_SYMBOL(rdma_res_to_id); 149fbdb0a91SSteve Wise 150e51060f0SSean Hefty static void cma_add_one(struct ib_device *device); 1517c1eb45aSHaggai Eran static void cma_remove_one(struct ib_device *device, void *client_data); 152e51060f0SSean Hefty 153e51060f0SSean Hefty static struct ib_client cma_client = { 154e51060f0SSean Hefty .name = "cma", 155e51060f0SSean Hefty .add = cma_add_one, 156e51060f0SSean Hefty .remove = cma_remove_one 157e51060f0SSean Hefty }; 158e51060f0SSean Hefty 159c1a0b23bSMichael S. Tsirkin static struct ib_sa_client sa_client; 160e51060f0SSean Hefty static LIST_HEAD(dev_list); 161e51060f0SSean Hefty static LIST_HEAD(listen_any_list); 162e51060f0SSean Hefty static DEFINE_MUTEX(lock); 163e51060f0SSean Hefty static struct workqueue_struct *cma_wq; 164c7d03a00SAlexey Dobriyan static unsigned int cma_pernet_id; 165e51060f0SSean Hefty 1664be74b42SHaggai Eran struct cma_pernet { 16763826753SMatthew Wilcox struct xarray tcp_ps; 16863826753SMatthew Wilcox struct xarray udp_ps; 16963826753SMatthew Wilcox struct xarray ipoib_ps; 17063826753SMatthew Wilcox struct xarray ib_ps; 1714be74b42SHaggai Eran }; 1724be74b42SHaggai Eran 1734be74b42SHaggai Eran static struct cma_pernet *cma_pernet(struct net *net) 174aac978e1SHaggai Eran { 1754be74b42SHaggai Eran return net_generic(net, cma_pernet_id); 1764be74b42SHaggai Eran } 1774be74b42SHaggai Eran 17863826753SMatthew Wilcox static 17963826753SMatthew Wilcox struct xarray *cma_pernet_xa(struct net *net, enum rdma_ucm_port_space ps) 1804be74b42SHaggai Eran { 1814be74b42SHaggai Eran struct cma_pernet *pernet = cma_pernet(net); 1824be74b42SHaggai Eran 183aac978e1SHaggai Eran switch (ps) { 184aac978e1SHaggai Eran case RDMA_PS_TCP: 1854be74b42SHaggai Eran return &pernet->tcp_ps; 186aac978e1SHaggai Eran case RDMA_PS_UDP: 1874be74b42SHaggai Eran return &pernet->udp_ps; 188aac978e1SHaggai Eran case RDMA_PS_IPOIB: 1894be74b42SHaggai Eran return &pernet->ipoib_ps; 190aac978e1SHaggai Eran case RDMA_PS_IB: 1914be74b42SHaggai Eran return &pernet->ib_ps; 192aac978e1SHaggai Eran default: 193aac978e1SHaggai Eran return NULL; 194aac978e1SHaggai Eran } 195aac978e1SHaggai Eran } 196aac978e1SHaggai Eran 197e51060f0SSean Hefty struct cma_device { 198e51060f0SSean Hefty struct list_head list; 199e51060f0SSean Hefty struct ib_device *device; 200e51060f0SSean Hefty struct completion comp; 201e51060f0SSean Hefty atomic_t refcount; 202e51060f0SSean Hefty struct list_head id_list; 203045959dbSMatan Barak enum ib_gid_type *default_gid_type; 20489052d78SMajd Dibbiny u8 *default_roce_tos; 205e51060f0SSean Hefty }; 206e51060f0SSean Hefty 207e51060f0SSean Hefty struct rdma_bind_list { 2082253fc0cSSteve Wise enum rdma_ucm_port_space ps; 209e51060f0SSean Hefty struct hlist_head owners; 210e51060f0SSean Hefty unsigned short port; 211e51060f0SSean Hefty }; 212e51060f0SSean Hefty 213ab15c95aSAlex Vesker struct class_port_info_context { 214ab15c95aSAlex Vesker struct ib_class_port_info *class_port_info; 215ab15c95aSAlex Vesker struct ib_device *device; 216ab15c95aSAlex Vesker struct completion done; 217ab15c95aSAlex Vesker struct ib_sa_query *sa_query; 218ab15c95aSAlex Vesker u8 port_num; 219ab15c95aSAlex Vesker }; 220ab15c95aSAlex Vesker 2212253fc0cSSteve Wise static int cma_ps_alloc(struct net *net, enum rdma_ucm_port_space ps, 222aac978e1SHaggai Eran struct rdma_bind_list *bind_list, int snum) 223aac978e1SHaggai Eran { 22463826753SMatthew Wilcox struct xarray *xa = cma_pernet_xa(net, ps); 225aac978e1SHaggai Eran 22663826753SMatthew Wilcox return xa_insert(xa, snum, bind_list, GFP_KERNEL); 227aac978e1SHaggai Eran } 228aac978e1SHaggai Eran 2294be74b42SHaggai Eran static struct rdma_bind_list *cma_ps_find(struct net *net, 2302253fc0cSSteve Wise enum rdma_ucm_port_space ps, int snum) 231aac978e1SHaggai Eran { 23263826753SMatthew Wilcox struct xarray *xa = cma_pernet_xa(net, ps); 233aac978e1SHaggai Eran 23463826753SMatthew Wilcox return xa_load(xa, snum); 235aac978e1SHaggai Eran } 236aac978e1SHaggai Eran 2372253fc0cSSteve Wise static void cma_ps_remove(struct net *net, enum rdma_ucm_port_space ps, 2382253fc0cSSteve Wise int snum) 239aac978e1SHaggai Eran { 24063826753SMatthew Wilcox struct xarray *xa = cma_pernet_xa(net, ps); 241aac978e1SHaggai Eran 24263826753SMatthew Wilcox xa_erase(xa, snum); 243aac978e1SHaggai Eran } 244aac978e1SHaggai Eran 24568602120SSean Hefty enum { 24668602120SSean Hefty CMA_OPTION_AFONLY, 24768602120SSean Hefty }; 24868602120SSean Hefty 249218a773fSMatan Barak void cma_ref_dev(struct cma_device *cma_dev) 250218a773fSMatan Barak { 251218a773fSMatan Barak atomic_inc(&cma_dev->refcount); 252218a773fSMatan Barak } 253218a773fSMatan Barak 254045959dbSMatan Barak struct cma_device *cma_enum_devices_by_ibdev(cma_device_filter filter, 255045959dbSMatan Barak void *cookie) 256045959dbSMatan Barak { 257045959dbSMatan Barak struct cma_device *cma_dev; 258045959dbSMatan Barak struct cma_device *found_cma_dev = NULL; 259045959dbSMatan Barak 260045959dbSMatan Barak mutex_lock(&lock); 261045959dbSMatan Barak 262045959dbSMatan Barak list_for_each_entry(cma_dev, &dev_list, list) 263045959dbSMatan Barak if (filter(cma_dev->device, cookie)) { 264045959dbSMatan Barak found_cma_dev = cma_dev; 265045959dbSMatan Barak break; 266045959dbSMatan Barak } 267045959dbSMatan Barak 268045959dbSMatan Barak if (found_cma_dev) 269045959dbSMatan Barak cma_ref_dev(found_cma_dev); 270045959dbSMatan Barak mutex_unlock(&lock); 271045959dbSMatan Barak return found_cma_dev; 272045959dbSMatan Barak } 273045959dbSMatan Barak 274045959dbSMatan Barak int cma_get_default_gid_type(struct cma_device *cma_dev, 275045959dbSMatan Barak unsigned int port) 276045959dbSMatan Barak { 27724dc831bSYuval Shaia if (!rdma_is_port_valid(cma_dev->device, port)) 278045959dbSMatan Barak return -EINVAL; 279045959dbSMatan Barak 280045959dbSMatan Barak return cma_dev->default_gid_type[port - rdma_start_port(cma_dev->device)]; 281045959dbSMatan Barak } 282045959dbSMatan Barak 283045959dbSMatan Barak int cma_set_default_gid_type(struct cma_device *cma_dev, 284045959dbSMatan Barak unsigned int port, 285045959dbSMatan Barak enum ib_gid_type default_gid_type) 286045959dbSMatan Barak { 287045959dbSMatan Barak unsigned long supported_gids; 288045959dbSMatan Barak 28924dc831bSYuval Shaia if (!rdma_is_port_valid(cma_dev->device, port)) 290045959dbSMatan Barak return -EINVAL; 291045959dbSMatan Barak 292045959dbSMatan Barak supported_gids = roce_gid_type_mask_support(cma_dev->device, port); 293045959dbSMatan Barak 294045959dbSMatan Barak if (!(supported_gids & 1 << default_gid_type)) 295045959dbSMatan Barak return -EINVAL; 296045959dbSMatan Barak 297045959dbSMatan Barak cma_dev->default_gid_type[port - rdma_start_port(cma_dev->device)] = 298045959dbSMatan Barak default_gid_type; 299045959dbSMatan Barak 300045959dbSMatan Barak return 0; 301045959dbSMatan Barak } 302045959dbSMatan Barak 30389052d78SMajd Dibbiny int cma_get_default_roce_tos(struct cma_device *cma_dev, unsigned int port) 30489052d78SMajd Dibbiny { 30589052d78SMajd Dibbiny if (!rdma_is_port_valid(cma_dev->device, port)) 30689052d78SMajd Dibbiny return -EINVAL; 30789052d78SMajd Dibbiny 30889052d78SMajd Dibbiny return cma_dev->default_roce_tos[port - rdma_start_port(cma_dev->device)]; 30989052d78SMajd Dibbiny } 31089052d78SMajd Dibbiny 31189052d78SMajd Dibbiny int cma_set_default_roce_tos(struct cma_device *cma_dev, unsigned int port, 31289052d78SMajd Dibbiny u8 default_roce_tos) 31389052d78SMajd Dibbiny { 31489052d78SMajd Dibbiny if (!rdma_is_port_valid(cma_dev->device, port)) 31589052d78SMajd Dibbiny return -EINVAL; 31689052d78SMajd Dibbiny 31789052d78SMajd Dibbiny cma_dev->default_roce_tos[port - rdma_start_port(cma_dev->device)] = 31889052d78SMajd Dibbiny default_roce_tos; 31989052d78SMajd Dibbiny 32089052d78SMajd Dibbiny return 0; 32189052d78SMajd Dibbiny } 322045959dbSMatan Barak struct ib_device *cma_get_ib_dev(struct cma_device *cma_dev) 323045959dbSMatan Barak { 324045959dbSMatan Barak return cma_dev->device; 325045959dbSMatan Barak } 326045959dbSMatan Barak 327e51060f0SSean Hefty /* 328e51060f0SSean Hefty * Device removal can occur at anytime, so we need extra handling to 329e51060f0SSean Hefty * serialize notifying the user of device removal with other callbacks. 330e51060f0SSean Hefty * We do this by disabling removal notification while a callback is in process, 331e51060f0SSean Hefty * and reporting it after the callback completes. 332e51060f0SSean Hefty */ 333e51060f0SSean Hefty 334c8f6a362SSean Hefty struct cma_multicast { 335c8f6a362SSean Hefty struct rdma_id_private *id_priv; 336c8f6a362SSean Hefty union { 337c8f6a362SSean Hefty struct ib_sa_multicast *ib; 338c8f6a362SSean Hefty } multicast; 339c8f6a362SSean Hefty struct list_head list; 340c8f6a362SSean Hefty void *context; 3413f446754SRoland Dreier struct sockaddr_storage addr; 3423c86aa70SEli Cohen struct kref mcref; 343ab15c95aSAlex Vesker u8 join_state; 344c8f6a362SSean Hefty }; 345c8f6a362SSean Hefty 346e51060f0SSean Hefty struct cma_work { 347e51060f0SSean Hefty struct work_struct work; 348e51060f0SSean Hefty struct rdma_id_private *id; 349550e5ca7SNir Muchtar enum rdma_cm_state old_state; 350550e5ca7SNir Muchtar enum rdma_cm_state new_state; 351e51060f0SSean Hefty struct rdma_cm_event event; 352e51060f0SSean Hefty }; 353e51060f0SSean Hefty 354dd5bdff8SOr Gerlitz struct cma_ndev_work { 355dd5bdff8SOr Gerlitz struct work_struct work; 356dd5bdff8SOr Gerlitz struct rdma_id_private *id; 357dd5bdff8SOr Gerlitz struct rdma_cm_event event; 358dd5bdff8SOr Gerlitz }; 359dd5bdff8SOr Gerlitz 3603c86aa70SEli Cohen struct iboe_mcast_work { 3613c86aa70SEli Cohen struct work_struct work; 3623c86aa70SEli Cohen struct rdma_id_private *id; 3633c86aa70SEli Cohen struct cma_multicast *mc; 3643c86aa70SEli Cohen }; 3653c86aa70SEli Cohen 366e51060f0SSean Hefty union cma_ip_addr { 367e51060f0SSean Hefty struct in6_addr ip6; 368e51060f0SSean Hefty struct { 3691b90c137SAl Viro __be32 pad[3]; 3701b90c137SAl Viro __be32 addr; 371e51060f0SSean Hefty } ip4; 372e51060f0SSean Hefty }; 373e51060f0SSean Hefty 374e51060f0SSean Hefty struct cma_hdr { 375e51060f0SSean Hefty u8 cma_version; 376e51060f0SSean Hefty u8 ip_version; /* IP version: 7:4 */ 3771b90c137SAl Viro __be16 port; 378e51060f0SSean Hefty union cma_ip_addr src_addr; 379e51060f0SSean Hefty union cma_ip_addr dst_addr; 380e51060f0SSean Hefty }; 381e51060f0SSean Hefty 382e51060f0SSean Hefty #define CMA_VERSION 0x00 383e51060f0SSean Hefty 3844c21b5bcSHaggai Eran struct cma_req_info { 3852918c1a9SParav Pandit struct sockaddr_storage listen_addr_storage; 3862918c1a9SParav Pandit struct sockaddr_storage src_addr_storage; 3874c21b5bcSHaggai Eran struct ib_device *device; 3884c21b5bcSHaggai Eran union ib_gid local_gid; 3894c21b5bcSHaggai Eran __be64 service_id; 39005e0b86cSParav Pandit int port; 39105e0b86cSParav Pandit bool has_gid; 3924c21b5bcSHaggai Eran u16 pkey; 3934c21b5bcSHaggai Eran }; 3944c21b5bcSHaggai Eran 395550e5ca7SNir Muchtar static int cma_comp(struct rdma_id_private *id_priv, enum rdma_cm_state comp) 396e51060f0SSean Hefty { 397e51060f0SSean Hefty unsigned long flags; 398e51060f0SSean Hefty int ret; 399e51060f0SSean Hefty 400e51060f0SSean Hefty spin_lock_irqsave(&id_priv->lock, flags); 401e51060f0SSean Hefty ret = (id_priv->state == comp); 402e51060f0SSean Hefty spin_unlock_irqrestore(&id_priv->lock, flags); 403e51060f0SSean Hefty return ret; 404e51060f0SSean Hefty } 405e51060f0SSean Hefty 406e51060f0SSean Hefty static int cma_comp_exch(struct rdma_id_private *id_priv, 407550e5ca7SNir Muchtar enum rdma_cm_state comp, enum rdma_cm_state exch) 408e51060f0SSean Hefty { 409e51060f0SSean Hefty unsigned long flags; 410e51060f0SSean Hefty int ret; 411e51060f0SSean Hefty 412e51060f0SSean Hefty spin_lock_irqsave(&id_priv->lock, flags); 413e51060f0SSean Hefty if ((ret = (id_priv->state == comp))) 414e51060f0SSean Hefty id_priv->state = exch; 415e51060f0SSean Hefty spin_unlock_irqrestore(&id_priv->lock, flags); 416e51060f0SSean Hefty return ret; 417e51060f0SSean Hefty } 418e51060f0SSean Hefty 419550e5ca7SNir Muchtar static enum rdma_cm_state cma_exch(struct rdma_id_private *id_priv, 420550e5ca7SNir Muchtar enum rdma_cm_state exch) 421e51060f0SSean Hefty { 422e51060f0SSean Hefty unsigned long flags; 423550e5ca7SNir Muchtar enum rdma_cm_state old; 424e51060f0SSean Hefty 425e51060f0SSean Hefty spin_lock_irqsave(&id_priv->lock, flags); 426e51060f0SSean Hefty old = id_priv->state; 427e51060f0SSean Hefty id_priv->state = exch; 428e51060f0SSean Hefty spin_unlock_irqrestore(&id_priv->lock, flags); 429e51060f0SSean Hefty return old; 430e51060f0SSean Hefty } 431e51060f0SSean Hefty 4324c21b5bcSHaggai Eran static inline u8 cma_get_ip_ver(const struct cma_hdr *hdr) 433e51060f0SSean Hefty { 434e51060f0SSean Hefty return hdr->ip_version >> 4; 435e51060f0SSean Hefty } 436e51060f0SSean Hefty 437e51060f0SSean Hefty static inline void cma_set_ip_ver(struct cma_hdr *hdr, u8 ip_ver) 438e51060f0SSean Hefty { 439e51060f0SSean Hefty hdr->ip_version = (ip_ver << 4) | (hdr->ip_version & 0xF); 440e51060f0SSean Hefty } 441e51060f0SSean Hefty 442bee3c3c9SMoni Shoua static int cma_igmp_send(struct net_device *ndev, union ib_gid *mgid, bool join) 443bee3c3c9SMoni Shoua { 444bee3c3c9SMoni Shoua struct in_device *in_dev = NULL; 445bee3c3c9SMoni Shoua 446bee3c3c9SMoni Shoua if (ndev) { 447bee3c3c9SMoni Shoua rtnl_lock(); 448bee3c3c9SMoni Shoua in_dev = __in_dev_get_rtnl(ndev); 449bee3c3c9SMoni Shoua if (in_dev) { 450bee3c3c9SMoni Shoua if (join) 451bee3c3c9SMoni Shoua ip_mc_inc_group(in_dev, 452bee3c3c9SMoni Shoua *(__be32 *)(mgid->raw + 12)); 453bee3c3c9SMoni Shoua else 454bee3c3c9SMoni Shoua ip_mc_dec_group(in_dev, 455bee3c3c9SMoni Shoua *(__be32 *)(mgid->raw + 12)); 456bee3c3c9SMoni Shoua } 457bee3c3c9SMoni Shoua rtnl_unlock(); 458bee3c3c9SMoni Shoua } 459bee3c3c9SMoni Shoua return (in_dev) ? 0 : -ENODEV; 460bee3c3c9SMoni Shoua } 461bee3c3c9SMoni Shoua 462045959dbSMatan Barak static void _cma_attach_to_dev(struct rdma_id_private *id_priv, 463e51060f0SSean Hefty struct cma_device *cma_dev) 464e51060f0SSean Hefty { 465218a773fSMatan Barak cma_ref_dev(cma_dev); 466e51060f0SSean Hefty id_priv->cma_dev = cma_dev; 467e51060f0SSean Hefty id_priv->id.device = cma_dev->device; 4683c86aa70SEli Cohen id_priv->id.route.addr.dev_addr.transport = 4693c86aa70SEli Cohen rdma_node_get_transport(cma_dev->device->node_type); 470e51060f0SSean Hefty list_add_tail(&id_priv->list, &cma_dev->id_list); 471917cb8a7SSteve Wise if (id_priv->res.kern_name) 472af8d7037SShamir Rabinovitch rdma_restrack_kadd(&id_priv->res); 473917cb8a7SSteve Wise else 474917cb8a7SSteve Wise rdma_restrack_uadd(&id_priv->res); 475e51060f0SSean Hefty } 476e51060f0SSean Hefty 477045959dbSMatan Barak static void cma_attach_to_dev(struct rdma_id_private *id_priv, 478045959dbSMatan Barak struct cma_device *cma_dev) 479045959dbSMatan Barak { 480045959dbSMatan Barak _cma_attach_to_dev(id_priv, cma_dev); 481045959dbSMatan Barak id_priv->gid_type = 482045959dbSMatan Barak cma_dev->default_gid_type[id_priv->id.port_num - 483045959dbSMatan Barak rdma_start_port(cma_dev->device)]; 484045959dbSMatan Barak } 485045959dbSMatan Barak 486218a773fSMatan Barak void cma_deref_dev(struct cma_device *cma_dev) 487e51060f0SSean Hefty { 488e51060f0SSean Hefty if (atomic_dec_and_test(&cma_dev->refcount)) 489e51060f0SSean Hefty complete(&cma_dev->comp); 490e51060f0SSean Hefty } 491e51060f0SSean Hefty 4923c86aa70SEli Cohen static inline void release_mc(struct kref *kref) 4933c86aa70SEli Cohen { 4943c86aa70SEli Cohen struct cma_multicast *mc = container_of(kref, struct cma_multicast, mcref); 4953c86aa70SEli Cohen 4963c86aa70SEli Cohen kfree(mc->multicast.ib); 4973c86aa70SEli Cohen kfree(mc); 4983c86aa70SEli Cohen } 4993c86aa70SEli Cohen 500a396d43aSSean Hefty static void cma_release_dev(struct rdma_id_private *id_priv) 501e51060f0SSean Hefty { 502a396d43aSSean Hefty mutex_lock(&lock); 503e51060f0SSean Hefty list_del(&id_priv->list); 504e51060f0SSean Hefty cma_deref_dev(id_priv->cma_dev); 505e51060f0SSean Hefty id_priv->cma_dev = NULL; 506a396d43aSSean Hefty mutex_unlock(&lock); 507e51060f0SSean Hefty } 508e51060f0SSean Hefty 509f4753834SSean Hefty static inline struct sockaddr *cma_src_addr(struct rdma_id_private *id_priv) 510f4753834SSean Hefty { 511f4753834SSean Hefty return (struct sockaddr *) &id_priv->id.route.addr.src_addr; 512f4753834SSean Hefty } 513f4753834SSean Hefty 514f4753834SSean Hefty static inline struct sockaddr *cma_dst_addr(struct rdma_id_private *id_priv) 515f4753834SSean Hefty { 516f4753834SSean Hefty return (struct sockaddr *) &id_priv->id.route.addr.dst_addr; 517f4753834SSean Hefty } 518f4753834SSean Hefty 519f4753834SSean Hefty static inline unsigned short cma_family(struct rdma_id_private *id_priv) 520f4753834SSean Hefty { 521f4753834SSean Hefty return id_priv->id.route.addr.src_addr.ss_family; 522f4753834SSean Hefty } 523f4753834SSean Hefty 5245c438135SSean Hefty static int cma_set_qkey(struct rdma_id_private *id_priv, u32 qkey) 525c8f6a362SSean Hefty { 526c8f6a362SSean Hefty struct ib_sa_mcmember_rec rec; 527c8f6a362SSean Hefty int ret = 0; 528c8f6a362SSean Hefty 5295c438135SSean Hefty if (id_priv->qkey) { 5305c438135SSean Hefty if (qkey && id_priv->qkey != qkey) 5315c438135SSean Hefty return -EINVAL; 532d2ca39f2SYossi Etigin return 0; 5335c438135SSean Hefty } 5345c438135SSean Hefty 5355c438135SSean Hefty if (qkey) { 5365c438135SSean Hefty id_priv->qkey = qkey; 5375c438135SSean Hefty return 0; 5385c438135SSean Hefty } 539d2ca39f2SYossi Etigin 540d2ca39f2SYossi Etigin switch (id_priv->id.ps) { 541c8f6a362SSean Hefty case RDMA_PS_UDP: 5425c438135SSean Hefty case RDMA_PS_IB: 543d2ca39f2SYossi Etigin id_priv->qkey = RDMA_UDP_QKEY; 544c8f6a362SSean Hefty break; 545c8f6a362SSean Hefty case RDMA_PS_IPOIB: 546d2ca39f2SYossi Etigin ib_addr_get_mgid(&id_priv->id.route.addr.dev_addr, &rec.mgid); 547d2ca39f2SYossi Etigin ret = ib_sa_get_mcmember_rec(id_priv->id.device, 548d2ca39f2SYossi Etigin id_priv->id.port_num, &rec.mgid, 549d2ca39f2SYossi Etigin &rec); 550d2ca39f2SYossi Etigin if (!ret) 551d2ca39f2SYossi Etigin id_priv->qkey = be32_to_cpu(rec.qkey); 552c8f6a362SSean Hefty break; 553c8f6a362SSean Hefty default: 554c8f6a362SSean Hefty break; 555c8f6a362SSean Hefty } 556c8f6a362SSean Hefty return ret; 557c8f6a362SSean Hefty } 558c8f6a362SSean Hefty 559680f920aSSean Hefty static void cma_translate_ib(struct sockaddr_ib *sib, struct rdma_dev_addr *dev_addr) 560680f920aSSean Hefty { 561680f920aSSean Hefty dev_addr->dev_type = ARPHRD_INFINIBAND; 562680f920aSSean Hefty rdma_addr_set_sgid(dev_addr, (union ib_gid *) &sib->sib_addr); 563680f920aSSean Hefty ib_addr_set_pkey(dev_addr, ntohs(sib->sib_pkey)); 564680f920aSSean Hefty } 565680f920aSSean Hefty 566680f920aSSean Hefty static int cma_translate_addr(struct sockaddr *addr, struct rdma_dev_addr *dev_addr) 567680f920aSSean Hefty { 568680f920aSSean Hefty int ret; 569680f920aSSean Hefty 570680f920aSSean Hefty if (addr->sa_family != AF_IB) { 571575c7e58SParav Pandit ret = rdma_translate_ip(addr, dev_addr); 572680f920aSSean Hefty } else { 573680f920aSSean Hefty cma_translate_ib((struct sockaddr_ib *) addr, dev_addr); 574680f920aSSean Hefty ret = 0; 575680f920aSSean Hefty } 576680f920aSSean Hefty 577680f920aSSean Hefty return ret; 578680f920aSSean Hefty } 579680f920aSSean Hefty 5804ed13a5fSParav Pandit static const struct ib_gid_attr * 5814ed13a5fSParav Pandit cma_validate_port(struct ib_device *device, u8 port, 582045959dbSMatan Barak enum ib_gid_type gid_type, 5832493a57bSParav Pandit union ib_gid *gid, 5842493a57bSParav Pandit struct rdma_id_private *id_priv) 5857c11147dSMichael Wang { 5862493a57bSParav Pandit struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 5872493a57bSParav Pandit int bound_if_index = dev_addr->bound_dev_if; 5884ed13a5fSParav Pandit const struct ib_gid_attr *sgid_attr; 5892493a57bSParav Pandit int dev_type = dev_addr->dev_type; 590abae1b71SMatan Barak struct net_device *ndev = NULL; 5917c11147dSMichael Wang 59241c61401SParav Pandit if (!rdma_dev_access_netns(device, id_priv->id.route.addr.dev_addr.net)) 59341c61401SParav Pandit return ERR_PTR(-ENODEV); 59441c61401SParav Pandit 5957c11147dSMichael Wang if ((dev_type == ARPHRD_INFINIBAND) && !rdma_protocol_ib(device, port)) 5964ed13a5fSParav Pandit return ERR_PTR(-ENODEV); 5977c11147dSMichael Wang 5987c11147dSMichael Wang if ((dev_type != ARPHRD_INFINIBAND) && rdma_protocol_ib(device, port)) 5994ed13a5fSParav Pandit return ERR_PTR(-ENODEV); 6007c11147dSMichael Wang 60100db63c1SParav Pandit if (dev_type == ARPHRD_ETHER && rdma_protocol_roce(device, port)) { 60266c74d74SParav Pandit ndev = dev_get_by_index(dev_addr->net, bound_if_index); 60300db63c1SParav Pandit if (!ndev) 6044ed13a5fSParav Pandit return ERR_PTR(-ENODEV); 60500db63c1SParav Pandit } else { 606045959dbSMatan Barak gid_type = IB_GID_TYPE_IB; 60700db63c1SParav Pandit } 608abae1b71SMatan Barak 6094ed13a5fSParav Pandit sgid_attr = rdma_find_gid_by_port(device, gid, gid_type, port, ndev); 610abae1b71SMatan Barak if (ndev) 611abae1b71SMatan Barak dev_put(ndev); 6124ed13a5fSParav Pandit return sgid_attr; 6134ed13a5fSParav Pandit } 6147c11147dSMichael Wang 6154ed13a5fSParav Pandit static void cma_bind_sgid_attr(struct rdma_id_private *id_priv, 6164ed13a5fSParav Pandit const struct ib_gid_attr *sgid_attr) 6174ed13a5fSParav Pandit { 6184ed13a5fSParav Pandit WARN_ON(id_priv->id.route.addr.dev_addr.sgid_attr); 6194ed13a5fSParav Pandit id_priv->id.route.addr.dev_addr.sgid_attr = sgid_attr; 6207c11147dSMichael Wang } 6217c11147dSMichael Wang 622ff11c6cdSParav Pandit /** 623ff11c6cdSParav Pandit * cma_acquire_dev_by_src_ip - Acquire cma device, port, gid attribute 624ff11c6cdSParav Pandit * based on source ip address. 625ff11c6cdSParav Pandit * @id_priv: cm_id which should be bound to cma device 626ff11c6cdSParav Pandit * 627ff11c6cdSParav Pandit * cma_acquire_dev_by_src_ip() binds cm id to cma device, port and GID attribute 628ff11c6cdSParav Pandit * based on source IP address. It returns 0 on success or error code otherwise. 629ff11c6cdSParav Pandit * It is applicable to active and passive side cm_id. 630ff11c6cdSParav Pandit */ 631ff11c6cdSParav Pandit static int cma_acquire_dev_by_src_ip(struct rdma_id_private *id_priv) 632ff11c6cdSParav Pandit { 633ff11c6cdSParav Pandit struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 634ff11c6cdSParav Pandit const struct ib_gid_attr *sgid_attr; 635ff11c6cdSParav Pandit union ib_gid gid, iboe_gid, *gidp; 636ff11c6cdSParav Pandit struct cma_device *cma_dev; 637ff11c6cdSParav Pandit enum ib_gid_type gid_type; 638ff11c6cdSParav Pandit int ret = -ENODEV; 639ea1075edSJason Gunthorpe unsigned int port; 640ff11c6cdSParav Pandit 641ff11c6cdSParav Pandit if (dev_addr->dev_type != ARPHRD_INFINIBAND && 642ff11c6cdSParav Pandit id_priv->id.ps == RDMA_PS_IPOIB) 643ff11c6cdSParav Pandit return -EINVAL; 644ff11c6cdSParav Pandit 645ff11c6cdSParav Pandit rdma_ip2gid((struct sockaddr *)&id_priv->id.route.addr.src_addr, 646ff11c6cdSParav Pandit &iboe_gid); 647ff11c6cdSParav Pandit 648ff11c6cdSParav Pandit memcpy(&gid, dev_addr->src_dev_addr + 649ff11c6cdSParav Pandit rdma_addr_gid_offset(dev_addr), sizeof(gid)); 650ff11c6cdSParav Pandit 651ff11c6cdSParav Pandit mutex_lock(&lock); 652ff11c6cdSParav Pandit list_for_each_entry(cma_dev, &dev_list, list) { 653ea1075edSJason Gunthorpe rdma_for_each_port (cma_dev->device, port) { 654ff11c6cdSParav Pandit gidp = rdma_protocol_roce(cma_dev->device, port) ? 655ff11c6cdSParav Pandit &iboe_gid : &gid; 656ff11c6cdSParav Pandit gid_type = cma_dev->default_gid_type[port - 1]; 657ff11c6cdSParav Pandit sgid_attr = cma_validate_port(cma_dev->device, port, 658ff11c6cdSParav Pandit gid_type, gidp, id_priv); 659ff11c6cdSParav Pandit if (!IS_ERR(sgid_attr)) { 660ff11c6cdSParav Pandit id_priv->id.port_num = port; 661ff11c6cdSParav Pandit cma_bind_sgid_attr(id_priv, sgid_attr); 662ff11c6cdSParav Pandit cma_attach_to_dev(id_priv, cma_dev); 663ff11c6cdSParav Pandit ret = 0; 664ff11c6cdSParav Pandit goto out; 665ff11c6cdSParav Pandit } 666ff11c6cdSParav Pandit } 667ff11c6cdSParav Pandit } 668ff11c6cdSParav Pandit out: 669ff11c6cdSParav Pandit mutex_unlock(&lock); 670ff11c6cdSParav Pandit return ret; 671ff11c6cdSParav Pandit } 672ff11c6cdSParav Pandit 67341ab1cb7SParav Pandit /** 67441ab1cb7SParav Pandit * cma_ib_acquire_dev - Acquire cma device, port and SGID attribute 67541ab1cb7SParav Pandit * @id_priv: cm id to bind to cma device 67641ab1cb7SParav Pandit * @listen_id_priv: listener cm id to match against 67741ab1cb7SParav Pandit * @req: Pointer to req structure containaining incoming 67841ab1cb7SParav Pandit * request information 67941ab1cb7SParav Pandit * cma_ib_acquire_dev() acquires cma device, port and SGID attribute when 68041ab1cb7SParav Pandit * rdma device matches for listen_id and incoming request. It also verifies 68141ab1cb7SParav Pandit * that a GID table entry is present for the source address. 68241ab1cb7SParav Pandit * Returns 0 on success, or returns error code otherwise. 68341ab1cb7SParav Pandit */ 68441ab1cb7SParav Pandit static int cma_ib_acquire_dev(struct rdma_id_private *id_priv, 68541ab1cb7SParav Pandit const struct rdma_id_private *listen_id_priv, 68641ab1cb7SParav Pandit struct cma_req_info *req) 68741ab1cb7SParav Pandit { 68841ab1cb7SParav Pandit struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 68941ab1cb7SParav Pandit const struct ib_gid_attr *sgid_attr; 69041ab1cb7SParav Pandit enum ib_gid_type gid_type; 69141ab1cb7SParav Pandit union ib_gid gid; 69241ab1cb7SParav Pandit 69341ab1cb7SParav Pandit if (dev_addr->dev_type != ARPHRD_INFINIBAND && 69441ab1cb7SParav Pandit id_priv->id.ps == RDMA_PS_IPOIB) 69541ab1cb7SParav Pandit return -EINVAL; 69641ab1cb7SParav Pandit 69741ab1cb7SParav Pandit if (rdma_protocol_roce(req->device, req->port)) 69841ab1cb7SParav Pandit rdma_ip2gid((struct sockaddr *)&id_priv->id.route.addr.src_addr, 69941ab1cb7SParav Pandit &gid); 70041ab1cb7SParav Pandit else 70141ab1cb7SParav Pandit memcpy(&gid, dev_addr->src_dev_addr + 70241ab1cb7SParav Pandit rdma_addr_gid_offset(dev_addr), sizeof(gid)); 70341ab1cb7SParav Pandit 70441ab1cb7SParav Pandit gid_type = listen_id_priv->cma_dev->default_gid_type[req->port - 1]; 70541ab1cb7SParav Pandit sgid_attr = cma_validate_port(req->device, req->port, 70641ab1cb7SParav Pandit gid_type, &gid, id_priv); 70741ab1cb7SParav Pandit if (IS_ERR(sgid_attr)) 70841ab1cb7SParav Pandit return PTR_ERR(sgid_attr); 70941ab1cb7SParav Pandit 71041ab1cb7SParav Pandit id_priv->id.port_num = req->port; 71141ab1cb7SParav Pandit cma_bind_sgid_attr(id_priv, sgid_attr); 71241ab1cb7SParav Pandit /* Need to acquire lock to protect against reader 71341ab1cb7SParav Pandit * of cma_dev->id_list such as cma_netdev_callback() and 71441ab1cb7SParav Pandit * cma_process_remove(). 71541ab1cb7SParav Pandit */ 71641ab1cb7SParav Pandit mutex_lock(&lock); 71741ab1cb7SParav Pandit cma_attach_to_dev(id_priv, listen_id_priv->cma_dev); 71841ab1cb7SParav Pandit mutex_unlock(&lock); 71941ab1cb7SParav Pandit return 0; 72041ab1cb7SParav Pandit } 72141ab1cb7SParav Pandit 72241ab1cb7SParav Pandit static int cma_iw_acquire_dev(struct rdma_id_private *id_priv, 723e7ff98aeSParav Pandit const struct rdma_id_private *listen_id_priv) 724e51060f0SSean Hefty { 725c8f6a362SSean Hefty struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 7264ed13a5fSParav Pandit const struct ib_gid_attr *sgid_attr; 727e51060f0SSean Hefty struct cma_device *cma_dev; 7284ed13a5fSParav Pandit enum ib_gid_type gid_type; 729e51060f0SSean Hefty int ret = -ENODEV; 73041ab1cb7SParav Pandit union ib_gid gid; 7317c11147dSMichael Wang u8 port; 732e51060f0SSean Hefty 7337c11147dSMichael Wang if (dev_addr->dev_type != ARPHRD_INFINIBAND && 7342efdd6a0SMoni Shoua id_priv->id.ps == RDMA_PS_IPOIB) 7352efdd6a0SMoni Shoua return -EINVAL; 7362efdd6a0SMoni Shoua 7373c86aa70SEli Cohen memcpy(&gid, dev_addr->src_dev_addr + 73841ab1cb7SParav Pandit rdma_addr_gid_offset(dev_addr), sizeof(gid)); 73941ab1cb7SParav Pandit 74041ab1cb7SParav Pandit mutex_lock(&lock); 7417c11147dSMichael Wang 742be9130ccSDoug Ledford cma_dev = listen_id_priv->cma_dev; 743be9130ccSDoug Ledford port = listen_id_priv->id.port_num; 74479d684f0SParav Pandit gid_type = listen_id_priv->gid_type; 7454ed13a5fSParav Pandit sgid_attr = cma_validate_port(cma_dev->device, port, 74641ab1cb7SParav Pandit gid_type, &gid, id_priv); 7474ed13a5fSParav Pandit if (!IS_ERR(sgid_attr)) { 7487c11147dSMichael Wang id_priv->id.port_num = port; 7494ed13a5fSParav Pandit cma_bind_sgid_attr(id_priv, sgid_attr); 7504ed13a5fSParav Pandit ret = 0; 751be9130ccSDoug Ledford goto out; 752be9130ccSDoug Ledford } 7537c11147dSMichael Wang 754e51060f0SSean Hefty list_for_each_entry(cma_dev, &dev_list, list) { 7553c86aa70SEli Cohen for (port = 1; port <= cma_dev->device->phys_port_cnt; ++port) { 756ff11c6cdSParav Pandit if (listen_id_priv->cma_dev == cma_dev && 757be9130ccSDoug Ledford listen_id_priv->id.port_num == port) 758be9130ccSDoug Ledford continue; 7593c86aa70SEli Cohen 76079d684f0SParav Pandit gid_type = cma_dev->default_gid_type[port - 1]; 7614ed13a5fSParav Pandit sgid_attr = cma_validate_port(cma_dev->device, port, 76241ab1cb7SParav Pandit gid_type, &gid, id_priv); 7634ed13a5fSParav Pandit if (!IS_ERR(sgid_attr)) { 7647c11147dSMichael Wang id_priv->id.port_num = port; 7654ed13a5fSParav Pandit cma_bind_sgid_attr(id_priv, sgid_attr); 7664ed13a5fSParav Pandit ret = 0; 7673c86aa70SEli Cohen goto out; 76863f05be2Sshefty } 769e51060f0SSean Hefty } 770e51060f0SSean Hefty } 7713c86aa70SEli Cohen 7723c86aa70SEli Cohen out: 7733c86aa70SEli Cohen if (!ret) 7743c86aa70SEli Cohen cma_attach_to_dev(id_priv, cma_dev); 7753c86aa70SEli Cohen 776a396d43aSSean Hefty mutex_unlock(&lock); 777e51060f0SSean Hefty return ret; 778e51060f0SSean Hefty } 779e51060f0SSean Hefty 780f17df3b0SSean Hefty /* 781f17df3b0SSean Hefty * Select the source IB device and address to reach the destination IB address. 782f17df3b0SSean Hefty */ 783f17df3b0SSean Hefty static int cma_resolve_ib_dev(struct rdma_id_private *id_priv) 784f17df3b0SSean Hefty { 785f17df3b0SSean Hefty struct cma_device *cma_dev, *cur_dev; 786f17df3b0SSean Hefty struct sockaddr_ib *addr; 787f17df3b0SSean Hefty union ib_gid gid, sgid, *dgid; 788f17df3b0SSean Hefty u16 pkey, index; 7898fb488d7SPaul Bolle u8 p; 79093b1f29dSJack Wang enum ib_port_state port_state; 791f17df3b0SSean Hefty int i; 792f17df3b0SSean Hefty 793f17df3b0SSean Hefty cma_dev = NULL; 794f17df3b0SSean Hefty addr = (struct sockaddr_ib *) cma_dst_addr(id_priv); 795f17df3b0SSean Hefty dgid = (union ib_gid *) &addr->sib_addr; 796f17df3b0SSean Hefty pkey = ntohs(addr->sib_pkey); 797f17df3b0SSean Hefty 798954a8e3aSParav Pandit mutex_lock(&lock); 799f17df3b0SSean Hefty list_for_each_entry(cur_dev, &dev_list, list) { 800fef60902SMichael Wang for (p = 1; p <= cur_dev->device->phys_port_cnt; ++p) { 80130a74ef4SMichael Wang if (!rdma_cap_af_ib(cur_dev->device, p)) 802f17df3b0SSean Hefty continue; 803f17df3b0SSean Hefty 804f17df3b0SSean Hefty if (ib_find_cached_pkey(cur_dev->device, p, pkey, &index)) 805f17df3b0SSean Hefty continue; 806f17df3b0SSean Hefty 80793b1f29dSJack Wang if (ib_get_cached_port_state(cur_dev->device, p, &port_state)) 80893b1f29dSJack Wang continue; 8091dfce294SParav Pandit for (i = 0; !rdma_query_gid(cur_dev->device, 8101dfce294SParav Pandit p, i, &gid); 81155ee3ab2SMatan Barak i++) { 812f17df3b0SSean Hefty if (!memcmp(&gid, dgid, sizeof(gid))) { 813f17df3b0SSean Hefty cma_dev = cur_dev; 814f17df3b0SSean Hefty sgid = gid; 8158fb488d7SPaul Bolle id_priv->id.port_num = p; 816f17df3b0SSean Hefty goto found; 817f17df3b0SSean Hefty } 818f17df3b0SSean Hefty 819f17df3b0SSean Hefty if (!cma_dev && (gid.global.subnet_prefix == 82093b1f29dSJack Wang dgid->global.subnet_prefix) && 82193b1f29dSJack Wang port_state == IB_PORT_ACTIVE) { 822f17df3b0SSean Hefty cma_dev = cur_dev; 823f17df3b0SSean Hefty sgid = gid; 8248fb488d7SPaul Bolle id_priv->id.port_num = p; 825954a8e3aSParav Pandit goto found; 826f17df3b0SSean Hefty } 827f17df3b0SSean Hefty } 828f17df3b0SSean Hefty } 829f17df3b0SSean Hefty } 830954a8e3aSParav Pandit mutex_unlock(&lock); 831f17df3b0SSean Hefty return -ENODEV; 832f17df3b0SSean Hefty 833f17df3b0SSean Hefty found: 834f17df3b0SSean Hefty cma_attach_to_dev(id_priv, cma_dev); 835954a8e3aSParav Pandit mutex_unlock(&lock); 836f17df3b0SSean Hefty addr = (struct sockaddr_ib *)cma_src_addr(id_priv); 837954a8e3aSParav Pandit memcpy(&addr->sib_addr, &sgid, sizeof(sgid)); 838f17df3b0SSean Hefty cma_translate_ib(addr, &id_priv->id.route.addr.dev_addr); 839f17df3b0SSean Hefty return 0; 840f17df3b0SSean Hefty } 841f17df3b0SSean Hefty 842e51060f0SSean Hefty static void cma_deref_id(struct rdma_id_private *id_priv) 843e51060f0SSean Hefty { 844e51060f0SSean Hefty if (atomic_dec_and_test(&id_priv->refcount)) 845e51060f0SSean Hefty complete(&id_priv->comp); 846e51060f0SSean Hefty } 847e51060f0SSean Hefty 84800313983SSteve Wise struct rdma_cm_id *__rdma_create_id(struct net *net, 849fa20105eSGuy Shapiro rdma_cm_event_handler event_handler, 8502253fc0cSSteve Wise void *context, enum rdma_ucm_port_space ps, 85100313983SSteve Wise enum ib_qp_type qp_type, const char *caller) 852e51060f0SSean Hefty { 853e51060f0SSean Hefty struct rdma_id_private *id_priv; 854e51060f0SSean Hefty 855e51060f0SSean Hefty id_priv = kzalloc(sizeof *id_priv, GFP_KERNEL); 856e51060f0SSean Hefty if (!id_priv) 857e51060f0SSean Hefty return ERR_PTR(-ENOMEM); 858e51060f0SSean Hefty 8592165fc26SLeon Romanovsky rdma_restrack_set_task(&id_priv->res, caller); 860e11fef9fSParav Pandit id_priv->res.type = RDMA_RESTRACK_CM_ID; 861550e5ca7SNir Muchtar id_priv->state = RDMA_CM_IDLE; 862e51060f0SSean Hefty id_priv->id.context = context; 863e51060f0SSean Hefty id_priv->id.event_handler = event_handler; 864e51060f0SSean Hefty id_priv->id.ps = ps; 865b26f9b99SSean Hefty id_priv->id.qp_type = qp_type; 86689052d78SMajd Dibbiny id_priv->tos_set = false; 8672c1619edSDanit Goldberg id_priv->timeout_set = false; 86879d684f0SParav Pandit id_priv->gid_type = IB_GID_TYPE_IB; 869e51060f0SSean Hefty spin_lock_init(&id_priv->lock); 870c5483388SSean Hefty mutex_init(&id_priv->qp_mutex); 871e51060f0SSean Hefty init_completion(&id_priv->comp); 872e51060f0SSean Hefty atomic_set(&id_priv->refcount, 1); 873de910bd9SOr Gerlitz mutex_init(&id_priv->handler_mutex); 874e51060f0SSean Hefty INIT_LIST_HEAD(&id_priv->listen_list); 875c8f6a362SSean Hefty INIT_LIST_HEAD(&id_priv->mc_list); 876e51060f0SSean Hefty get_random_bytes(&id_priv->seq_num, sizeof id_priv->seq_num); 877fa20105eSGuy Shapiro id_priv->id.route.addr.dev_addr.net = get_net(net); 87823a9cd2aSMoni Shoua id_priv->seq_num &= 0x00ffffff; 879e51060f0SSean Hefty 880e51060f0SSean Hefty return &id_priv->id; 881e51060f0SSean Hefty } 88200313983SSteve Wise EXPORT_SYMBOL(__rdma_create_id); 883e51060f0SSean Hefty 884c8f6a362SSean Hefty static int cma_init_ud_qp(struct rdma_id_private *id_priv, struct ib_qp *qp) 885e51060f0SSean Hefty { 886e51060f0SSean Hefty struct ib_qp_attr qp_attr; 887c8f6a362SSean Hefty int qp_attr_mask, ret; 888e51060f0SSean Hefty 889c8f6a362SSean Hefty qp_attr.qp_state = IB_QPS_INIT; 890c8f6a362SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 891e51060f0SSean Hefty if (ret) 892e51060f0SSean Hefty return ret; 893e51060f0SSean Hefty 894c8f6a362SSean Hefty ret = ib_modify_qp(qp, &qp_attr, qp_attr_mask); 895c8f6a362SSean Hefty if (ret) 896c8f6a362SSean Hefty return ret; 897c8f6a362SSean Hefty 898c8f6a362SSean Hefty qp_attr.qp_state = IB_QPS_RTR; 899c8f6a362SSean Hefty ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE); 900c8f6a362SSean Hefty if (ret) 901c8f6a362SSean Hefty return ret; 902c8f6a362SSean Hefty 903c8f6a362SSean Hefty qp_attr.qp_state = IB_QPS_RTS; 904c8f6a362SSean Hefty qp_attr.sq_psn = 0; 905c8f6a362SSean Hefty ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE | IB_QP_SQ_PSN); 906c8f6a362SSean Hefty 907c8f6a362SSean Hefty return ret; 908e51060f0SSean Hefty } 909e51060f0SSean Hefty 910c8f6a362SSean Hefty static int cma_init_conn_qp(struct rdma_id_private *id_priv, struct ib_qp *qp) 91107ebafbaSTom Tucker { 91207ebafbaSTom Tucker struct ib_qp_attr qp_attr; 913c8f6a362SSean Hefty int qp_attr_mask, ret; 91407ebafbaSTom Tucker 91507ebafbaSTom Tucker qp_attr.qp_state = IB_QPS_INIT; 916c8f6a362SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 917c8f6a362SSean Hefty if (ret) 918c8f6a362SSean Hefty return ret; 91907ebafbaSTom Tucker 920c8f6a362SSean Hefty return ib_modify_qp(qp, &qp_attr, qp_attr_mask); 92107ebafbaSTom Tucker } 92207ebafbaSTom Tucker 923e51060f0SSean Hefty int rdma_create_qp(struct rdma_cm_id *id, struct ib_pd *pd, 924e51060f0SSean Hefty struct ib_qp_init_attr *qp_init_attr) 925e51060f0SSean Hefty { 926e51060f0SSean Hefty struct rdma_id_private *id_priv; 927e51060f0SSean Hefty struct ib_qp *qp; 928e51060f0SSean Hefty int ret; 929e51060f0SSean Hefty 930e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 931e51060f0SSean Hefty if (id->device != pd->device) 932e51060f0SSean Hefty return -EINVAL; 933e51060f0SSean Hefty 9340691a286SChristoph Hellwig qp_init_attr->port_num = id->port_num; 935e51060f0SSean Hefty qp = ib_create_qp(pd, qp_init_attr); 936e51060f0SSean Hefty if (IS_ERR(qp)) 937e51060f0SSean Hefty return PTR_ERR(qp); 938e51060f0SSean Hefty 939b26f9b99SSean Hefty if (id->qp_type == IB_QPT_UD) 940c8f6a362SSean Hefty ret = cma_init_ud_qp(id_priv, qp); 941c8f6a362SSean Hefty else 942c8f6a362SSean Hefty ret = cma_init_conn_qp(id_priv, qp); 943e51060f0SSean Hefty if (ret) 944e51060f0SSean Hefty goto err; 945e51060f0SSean Hefty 946e51060f0SSean Hefty id->qp = qp; 947e51060f0SSean Hefty id_priv->qp_num = qp->qp_num; 948e51060f0SSean Hefty id_priv->srq = (qp->srq != NULL); 949e51060f0SSean Hefty return 0; 950e51060f0SSean Hefty err: 951e51060f0SSean Hefty ib_destroy_qp(qp); 952e51060f0SSean Hefty return ret; 953e51060f0SSean Hefty } 954e51060f0SSean Hefty EXPORT_SYMBOL(rdma_create_qp); 955e51060f0SSean Hefty 956e51060f0SSean Hefty void rdma_destroy_qp(struct rdma_cm_id *id) 957e51060f0SSean Hefty { 958c5483388SSean Hefty struct rdma_id_private *id_priv; 959c5483388SSean Hefty 960c5483388SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 961c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 962c5483388SSean Hefty ib_destroy_qp(id_priv->id.qp); 963c5483388SSean Hefty id_priv->id.qp = NULL; 964c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 965e51060f0SSean Hefty } 966e51060f0SSean Hefty EXPORT_SYMBOL(rdma_destroy_qp); 967e51060f0SSean Hefty 9685851bb89SSean Hefty static int cma_modify_qp_rtr(struct rdma_id_private *id_priv, 9695851bb89SSean Hefty struct rdma_conn_param *conn_param) 970e51060f0SSean Hefty { 971e51060f0SSean Hefty struct ib_qp_attr qp_attr; 972e51060f0SSean Hefty int qp_attr_mask, ret; 973e51060f0SSean Hefty 974c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 975c5483388SSean Hefty if (!id_priv->id.qp) { 976c5483388SSean Hefty ret = 0; 977c5483388SSean Hefty goto out; 978c5483388SSean Hefty } 979e51060f0SSean Hefty 980e51060f0SSean Hefty /* Need to update QP attributes from default values. */ 981e51060f0SSean Hefty qp_attr.qp_state = IB_QPS_INIT; 982c5483388SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 983e51060f0SSean Hefty if (ret) 984c5483388SSean Hefty goto out; 985e51060f0SSean Hefty 986c5483388SSean Hefty ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask); 987e51060f0SSean Hefty if (ret) 988c5483388SSean Hefty goto out; 989e51060f0SSean Hefty 990e51060f0SSean Hefty qp_attr.qp_state = IB_QPS_RTR; 991c5483388SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 992e51060f0SSean Hefty if (ret) 993c5483388SSean Hefty goto out; 994e51060f0SSean Hefty 995fef60902SMichael Wang BUG_ON(id_priv->cma_dev->device != id_priv->id.device); 996fef60902SMichael Wang 9975851bb89SSean Hefty if (conn_param) 9985851bb89SSean Hefty qp_attr.max_dest_rd_atomic = conn_param->responder_resources; 999c5483388SSean Hefty ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask); 1000c5483388SSean Hefty out: 1001c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 1002c5483388SSean Hefty return ret; 1003e51060f0SSean Hefty } 1004e51060f0SSean Hefty 10055851bb89SSean Hefty static int cma_modify_qp_rts(struct rdma_id_private *id_priv, 10065851bb89SSean Hefty struct rdma_conn_param *conn_param) 1007e51060f0SSean Hefty { 1008e51060f0SSean Hefty struct ib_qp_attr qp_attr; 1009e51060f0SSean Hefty int qp_attr_mask, ret; 1010e51060f0SSean Hefty 1011c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 1012c5483388SSean Hefty if (!id_priv->id.qp) { 1013c5483388SSean Hefty ret = 0; 1014c5483388SSean Hefty goto out; 1015e51060f0SSean Hefty } 1016e51060f0SSean Hefty 1017c5483388SSean Hefty qp_attr.qp_state = IB_QPS_RTS; 1018c5483388SSean Hefty ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 1019c5483388SSean Hefty if (ret) 1020c5483388SSean Hefty goto out; 1021c5483388SSean Hefty 10225851bb89SSean Hefty if (conn_param) 10235851bb89SSean Hefty qp_attr.max_rd_atomic = conn_param->initiator_depth; 1024c5483388SSean Hefty ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask); 1025c5483388SSean Hefty out: 1026c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 1027c5483388SSean Hefty return ret; 1028c5483388SSean Hefty } 1029c5483388SSean Hefty 1030c5483388SSean Hefty static int cma_modify_qp_err(struct rdma_id_private *id_priv) 1031e51060f0SSean Hefty { 1032e51060f0SSean Hefty struct ib_qp_attr qp_attr; 1033c5483388SSean Hefty int 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; 1039c5483388SSean Hefty } 1040e51060f0SSean Hefty 1041e51060f0SSean Hefty qp_attr.qp_state = IB_QPS_ERR; 1042c5483388SSean Hefty ret = ib_modify_qp(id_priv->id.qp, &qp_attr, IB_QP_STATE); 1043c5483388SSean Hefty out: 1044c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 1045c5483388SSean Hefty return ret; 1046e51060f0SSean Hefty } 1047e51060f0SSean Hefty 1048c8f6a362SSean Hefty static int cma_ib_init_qp_attr(struct rdma_id_private *id_priv, 1049c8f6a362SSean Hefty struct ib_qp_attr *qp_attr, int *qp_attr_mask) 1050c8f6a362SSean Hefty { 1051c8f6a362SSean Hefty struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 1052c8f6a362SSean Hefty int ret; 10533c86aa70SEli Cohen u16 pkey; 10543c86aa70SEli Cohen 1055227128fcSMichael Wang if (rdma_cap_eth_ah(id_priv->id.device, id_priv->id.port_num)) 10563c86aa70SEli Cohen pkey = 0xffff; 1057fef60902SMichael Wang else 1058fef60902SMichael Wang pkey = ib_addr_get_pkey(dev_addr); 1059c8f6a362SSean Hefty 1060c8f6a362SSean Hefty ret = ib_find_cached_pkey(id_priv->id.device, id_priv->id.port_num, 10613c86aa70SEli Cohen pkey, &qp_attr->pkey_index); 1062c8f6a362SSean Hefty if (ret) 1063c8f6a362SSean Hefty return ret; 1064c8f6a362SSean Hefty 1065c8f6a362SSean Hefty qp_attr->port_num = id_priv->id.port_num; 1066c8f6a362SSean Hefty *qp_attr_mask = IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_PORT; 1067c8f6a362SSean Hefty 1068b26f9b99SSean Hefty if (id_priv->id.qp_type == IB_QPT_UD) { 10695c438135SSean Hefty ret = cma_set_qkey(id_priv, 0); 1070d2ca39f2SYossi Etigin if (ret) 1071d2ca39f2SYossi Etigin return ret; 1072d2ca39f2SYossi Etigin 1073c8f6a362SSean Hefty qp_attr->qkey = id_priv->qkey; 1074c8f6a362SSean Hefty *qp_attr_mask |= IB_QP_QKEY; 1075c8f6a362SSean Hefty } else { 1076c8f6a362SSean Hefty qp_attr->qp_access_flags = 0; 1077c8f6a362SSean Hefty *qp_attr_mask |= IB_QP_ACCESS_FLAGS; 1078c8f6a362SSean Hefty } 1079c8f6a362SSean Hefty return 0; 1080c8f6a362SSean Hefty } 1081c8f6a362SSean Hefty 1082e51060f0SSean Hefty int rdma_init_qp_attr(struct rdma_cm_id *id, struct ib_qp_attr *qp_attr, 1083e51060f0SSean Hefty int *qp_attr_mask) 1084e51060f0SSean Hefty { 1085e51060f0SSean Hefty struct rdma_id_private *id_priv; 1086c8f6a362SSean Hefty int ret = 0; 1087e51060f0SSean Hefty 1088e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 108972219ceaSMichael Wang if (rdma_cap_ib_cm(id->device, id->port_num)) { 1090b26f9b99SSean Hefty if (!id_priv->cm_id.ib || (id_priv->id.qp_type == IB_QPT_UD)) 1091c8f6a362SSean Hefty ret = cma_ib_init_qp_attr(id_priv, qp_attr, qp_attr_mask); 1092c8f6a362SSean Hefty else 1093e51060f0SSean Hefty ret = ib_cm_init_qp_attr(id_priv->cm_id.ib, qp_attr, 1094e51060f0SSean Hefty qp_attr_mask); 1095dd5f03beSMatan Barak 1096e51060f0SSean Hefty if (qp_attr->qp_state == IB_QPS_RTR) 1097e51060f0SSean Hefty qp_attr->rq_psn = id_priv->seq_num; 109804215330SMichael Wang } else if (rdma_cap_iw_cm(id->device, id->port_num)) { 1099c8f6a362SSean Hefty if (!id_priv->cm_id.iw) { 11008f076531SDotan Barak qp_attr->qp_access_flags = 0; 1101c8f6a362SSean Hefty *qp_attr_mask = IB_QP_STATE | IB_QP_ACCESS_FLAGS; 1102c8f6a362SSean Hefty } else 110307ebafbaSTom Tucker ret = iw_cm_init_qp_attr(id_priv->cm_id.iw, qp_attr, 110407ebafbaSTom Tucker qp_attr_mask); 1105a62ab66bSIsmail, Mustafa qp_attr->port_num = id_priv->id.port_num; 1106a62ab66bSIsmail, Mustafa *qp_attr_mask |= IB_QP_PORT; 110721655afcSMichael Wang } else 1108e51060f0SSean Hefty ret = -ENOSYS; 1109e51060f0SSean Hefty 11102c1619edSDanit Goldberg if ((*qp_attr_mask & IB_QP_TIMEOUT) && id_priv->timeout_set) 11112c1619edSDanit Goldberg qp_attr->timeout = id_priv->timeout; 11122c1619edSDanit Goldberg 1113e51060f0SSean Hefty return ret; 1114e51060f0SSean Hefty } 1115e51060f0SSean Hefty EXPORT_SYMBOL(rdma_init_qp_attr); 1116e51060f0SSean Hefty 1117ca3a8aceSParav Pandit static inline bool cma_zero_addr(const struct sockaddr *addr) 1118e51060f0SSean Hefty { 11192e2d190cSSean Hefty switch (addr->sa_family) { 11202e2d190cSSean Hefty case AF_INET: 11212e2d190cSSean Hefty return ipv4_is_zeronet(((struct sockaddr_in *)addr)->sin_addr.s_addr); 11222e2d190cSSean Hefty case AF_INET6: 11232e2d190cSSean Hefty return ipv6_addr_any(&((struct sockaddr_in6 *)addr)->sin6_addr); 11242e2d190cSSean Hefty case AF_IB: 11252e2d190cSSean Hefty return ib_addr_any(&((struct sockaddr_ib *)addr)->sib_addr); 11262e2d190cSSean Hefty default: 1127ca3a8aceSParav Pandit return false; 1128e51060f0SSean Hefty } 1129e51060f0SSean Hefty } 1130e51060f0SSean Hefty 1131ca3a8aceSParav Pandit static inline bool cma_loopback_addr(const struct sockaddr *addr) 1132e51060f0SSean Hefty { 11332e2d190cSSean Hefty switch (addr->sa_family) { 11342e2d190cSSean Hefty case AF_INET: 1135ca3a8aceSParav Pandit return ipv4_is_loopback( 1136ca3a8aceSParav Pandit ((struct sockaddr_in *)addr)->sin_addr.s_addr); 11372e2d190cSSean Hefty case AF_INET6: 1138ca3a8aceSParav Pandit return ipv6_addr_loopback( 1139ca3a8aceSParav Pandit &((struct sockaddr_in6 *)addr)->sin6_addr); 11402e2d190cSSean Hefty case AF_IB: 1141ca3a8aceSParav Pandit return ib_addr_loopback( 1142ca3a8aceSParav Pandit &((struct sockaddr_ib *)addr)->sib_addr); 11432e2d190cSSean Hefty default: 1144ca3a8aceSParav Pandit return false; 11452e2d190cSSean Hefty } 1146e51060f0SSean Hefty } 1147e51060f0SSean Hefty 1148ca3a8aceSParav Pandit static inline bool cma_any_addr(const struct sockaddr *addr) 1149e51060f0SSean Hefty { 1150e51060f0SSean Hefty return cma_zero_addr(addr) || cma_loopback_addr(addr); 1151e51060f0SSean Hefty } 1152e51060f0SSean Hefty 11535d7ed2f2SParav Pandit static int cma_addr_cmp(const struct sockaddr *src, const struct sockaddr *dst) 115443b752daSHefty, Sean { 115543b752daSHefty, Sean if (src->sa_family != dst->sa_family) 115643b752daSHefty, Sean return -1; 115743b752daSHefty, Sean 115843b752daSHefty, Sean switch (src->sa_family) { 115943b752daSHefty, Sean case AF_INET: 116043b752daSHefty, Sean return ((struct sockaddr_in *)src)->sin_addr.s_addr != 116143b752daSHefty, Sean ((struct sockaddr_in *)dst)->sin_addr.s_addr; 11625d7ed2f2SParav Pandit case AF_INET6: { 11635d7ed2f2SParav Pandit struct sockaddr_in6 *src_addr6 = (struct sockaddr_in6 *)src; 11645d7ed2f2SParav Pandit struct sockaddr_in6 *dst_addr6 = (struct sockaddr_in6 *)dst; 11655d7ed2f2SParav Pandit bool link_local; 11665d7ed2f2SParav Pandit 11675d7ed2f2SParav Pandit if (ipv6_addr_cmp(&src_addr6->sin6_addr, 11685d7ed2f2SParav Pandit &dst_addr6->sin6_addr)) 11695d7ed2f2SParav Pandit return 1; 11705d7ed2f2SParav Pandit link_local = ipv6_addr_type(&dst_addr6->sin6_addr) & 11715d7ed2f2SParav Pandit IPV6_ADDR_LINKLOCAL; 11725d7ed2f2SParav Pandit /* Link local must match their scope_ids */ 11735d7ed2f2SParav Pandit return link_local ? (src_addr6->sin6_scope_id != 11745d7ed2f2SParav Pandit dst_addr6->sin6_scope_id) : 11755d7ed2f2SParav Pandit 0; 11765d7ed2f2SParav Pandit } 11775d7ed2f2SParav Pandit 11782e2d190cSSean Hefty default: 11792e2d190cSSean Hefty return ib_addr_cmp(&((struct sockaddr_ib *) src)->sib_addr, 11802e2d190cSSean Hefty &((struct sockaddr_ib *) dst)->sib_addr); 118143b752daSHefty, Sean } 118243b752daSHefty, Sean } 118343b752daSHefty, Sean 11842df7dba8SParav Pandit static __be16 cma_port(const struct sockaddr *addr) 1185628e5f6dSSean Hefty { 118658afdcb7SSean Hefty struct sockaddr_ib *sib; 118758afdcb7SSean Hefty 118858afdcb7SSean Hefty switch (addr->sa_family) { 118958afdcb7SSean Hefty case AF_INET: 1190628e5f6dSSean Hefty return ((struct sockaddr_in *) addr)->sin_port; 119158afdcb7SSean Hefty case AF_INET6: 1192628e5f6dSSean Hefty return ((struct sockaddr_in6 *) addr)->sin6_port; 119358afdcb7SSean Hefty case AF_IB: 119458afdcb7SSean Hefty sib = (struct sockaddr_ib *) addr; 119558afdcb7SSean Hefty return htons((u16) (be64_to_cpu(sib->sib_sid) & 119658afdcb7SSean Hefty be64_to_cpu(sib->sib_sid_mask))); 119758afdcb7SSean Hefty default: 119858afdcb7SSean Hefty return 0; 119958afdcb7SSean Hefty } 1200628e5f6dSSean Hefty } 1201628e5f6dSSean Hefty 12022df7dba8SParav Pandit static inline int cma_any_port(const struct sockaddr *addr) 1203e51060f0SSean Hefty { 1204628e5f6dSSean Hefty return !cma_port(addr); 1205e51060f0SSean Hefty } 1206e51060f0SSean Hefty 12070c505f70SHaggai Eran static void cma_save_ib_info(struct sockaddr *src_addr, 12080c505f70SHaggai Eran struct sockaddr *dst_addr, 1209e7ff98aeSParav Pandit const struct rdma_cm_id *listen_id, 1210e7ff98aeSParav Pandit const struct sa_path_rec *path) 1211e51060f0SSean Hefty { 1212fbaa1a6dSSean Hefty struct sockaddr_ib *listen_ib, *ib; 1213e51060f0SSean Hefty 1214fbaa1a6dSSean Hefty listen_ib = (struct sockaddr_ib *) &listen_id->route.addr.src_addr; 12150c505f70SHaggai Eran if (src_addr) { 12160c505f70SHaggai Eran ib = (struct sockaddr_ib *)src_addr; 12170c505f70SHaggai Eran ib->sib_family = AF_IB; 1218c07678bbSMatthew Finlay if (path) { 1219fbaa1a6dSSean Hefty ib->sib_pkey = path->pkey; 1220fbaa1a6dSSean Hefty ib->sib_flowinfo = path->flow_label; 1221fbaa1a6dSSean Hefty memcpy(&ib->sib_addr, &path->sgid, 16); 1222d3957b86SMajd Dibbiny ib->sib_sid = path->service_id; 12230c505f70SHaggai Eran ib->sib_scope_id = 0; 1224c07678bbSMatthew Finlay } else { 1225c07678bbSMatthew Finlay ib->sib_pkey = listen_ib->sib_pkey; 1226c07678bbSMatthew Finlay ib->sib_flowinfo = listen_ib->sib_flowinfo; 1227c07678bbSMatthew Finlay ib->sib_addr = listen_ib->sib_addr; 1228fbaa1a6dSSean Hefty ib->sib_sid = listen_ib->sib_sid; 1229fbaa1a6dSSean Hefty ib->sib_scope_id = listen_ib->sib_scope_id; 12300c505f70SHaggai Eran } 12310c505f70SHaggai Eran ib->sib_sid_mask = cpu_to_be64(0xffffffffffffffffULL); 12320c505f70SHaggai Eran } 12330c505f70SHaggai Eran if (dst_addr) { 12340c505f70SHaggai Eran ib = (struct sockaddr_ib *)dst_addr; 12350c505f70SHaggai Eran ib->sib_family = AF_IB; 1236c07678bbSMatthew Finlay if (path) { 1237fbaa1a6dSSean Hefty ib->sib_pkey = path->pkey; 1238fbaa1a6dSSean Hefty ib->sib_flowinfo = path->flow_label; 1239fbaa1a6dSSean Hefty memcpy(&ib->sib_addr, &path->dgid, 16); 1240fbaa1a6dSSean Hefty } 1241c07678bbSMatthew Finlay } 124228521440SJason Gunthorpe } 124328521440SJason Gunthorpe 1244c50e90d0SArnd Bergmann static void cma_save_ip4_info(struct sockaddr_in *src_addr, 1245c50e90d0SArnd Bergmann struct sockaddr_in *dst_addr, 12460c505f70SHaggai Eran struct cma_hdr *hdr, 12470c505f70SHaggai Eran __be16 local_port) 1248fbaa1a6dSSean Hefty { 12490c505f70SHaggai Eran if (src_addr) { 1250c50e90d0SArnd Bergmann *src_addr = (struct sockaddr_in) { 1251c50e90d0SArnd Bergmann .sin_family = AF_INET, 1252c50e90d0SArnd Bergmann .sin_addr.s_addr = hdr->dst_addr.ip4.addr, 1253c50e90d0SArnd Bergmann .sin_port = local_port, 1254c50e90d0SArnd Bergmann }; 12550c505f70SHaggai Eran } 1256fbaa1a6dSSean Hefty 12570c505f70SHaggai Eran if (dst_addr) { 1258c50e90d0SArnd Bergmann *dst_addr = (struct sockaddr_in) { 1259c50e90d0SArnd Bergmann .sin_family = AF_INET, 1260c50e90d0SArnd Bergmann .sin_addr.s_addr = hdr->src_addr.ip4.addr, 1261c50e90d0SArnd Bergmann .sin_port = hdr->port, 1262c50e90d0SArnd Bergmann }; 1263fbaa1a6dSSean Hefty } 12640c505f70SHaggai Eran } 1265fbaa1a6dSSean Hefty 1266c50e90d0SArnd Bergmann static void cma_save_ip6_info(struct sockaddr_in6 *src_addr, 1267c50e90d0SArnd Bergmann struct sockaddr_in6 *dst_addr, 12680c505f70SHaggai Eran struct cma_hdr *hdr, 12690c505f70SHaggai Eran __be16 local_port) 1270fbaa1a6dSSean Hefty { 12710c505f70SHaggai Eran if (src_addr) { 1272c50e90d0SArnd Bergmann *src_addr = (struct sockaddr_in6) { 1273c50e90d0SArnd Bergmann .sin6_family = AF_INET6, 1274c50e90d0SArnd Bergmann .sin6_addr = hdr->dst_addr.ip6, 1275c50e90d0SArnd Bergmann .sin6_port = local_port, 1276c50e90d0SArnd Bergmann }; 12770c505f70SHaggai Eran } 1278fbaa1a6dSSean Hefty 12790c505f70SHaggai Eran if (dst_addr) { 1280c50e90d0SArnd Bergmann *dst_addr = (struct sockaddr_in6) { 1281c50e90d0SArnd Bergmann .sin6_family = AF_INET6, 1282c50e90d0SArnd Bergmann .sin6_addr = hdr->src_addr.ip6, 1283c50e90d0SArnd Bergmann .sin6_port = hdr->port, 1284c50e90d0SArnd Bergmann }; 1285fbaa1a6dSSean Hefty } 12860c505f70SHaggai Eran } 1287fbaa1a6dSSean Hefty 12880c505f70SHaggai Eran static u16 cma_port_from_service_id(__be64 service_id) 12890c505f70SHaggai Eran { 12900c505f70SHaggai Eran return (u16)be64_to_cpu(service_id); 12910c505f70SHaggai Eran } 12920c505f70SHaggai Eran 12930c505f70SHaggai Eran static int cma_save_ip_info(struct sockaddr *src_addr, 12940c505f70SHaggai Eran struct sockaddr *dst_addr, 1295e7ff98aeSParav Pandit const struct ib_cm_event *ib_event, 12960c505f70SHaggai Eran __be64 service_id) 1297fbaa1a6dSSean Hefty { 1298fbaa1a6dSSean Hefty struct cma_hdr *hdr; 12990c505f70SHaggai Eran __be16 port; 1300e51060f0SSean Hefty 1301fbaa1a6dSSean Hefty hdr = ib_event->private_data; 1302fbaa1a6dSSean Hefty if (hdr->cma_version != CMA_VERSION) 1303fbaa1a6dSSean Hefty return -EINVAL; 1304e51060f0SSean Hefty 13050c505f70SHaggai Eran port = htons(cma_port_from_service_id(service_id)); 13060c505f70SHaggai Eran 1307fbaa1a6dSSean Hefty switch (cma_get_ip_ver(hdr)) { 1308e51060f0SSean Hefty case 4: 1309c50e90d0SArnd Bergmann cma_save_ip4_info((struct sockaddr_in *)src_addr, 1310c50e90d0SArnd Bergmann (struct sockaddr_in *)dst_addr, hdr, port); 1311e51060f0SSean Hefty break; 1312e51060f0SSean Hefty case 6: 1313c50e90d0SArnd Bergmann cma_save_ip6_info((struct sockaddr_in6 *)src_addr, 1314c50e90d0SArnd Bergmann (struct sockaddr_in6 *)dst_addr, hdr, port); 1315e51060f0SSean Hefty break; 1316e51060f0SSean Hefty default: 13174c21b5bcSHaggai Eran return -EAFNOSUPPORT; 1318e51060f0SSean Hefty } 13190c505f70SHaggai Eran 1320fbaa1a6dSSean Hefty return 0; 1321e51060f0SSean Hefty } 1322e51060f0SSean Hefty 13230c505f70SHaggai Eran static int cma_save_net_info(struct sockaddr *src_addr, 13240c505f70SHaggai Eran struct sockaddr *dst_addr, 1325e7ff98aeSParav Pandit const struct rdma_cm_id *listen_id, 1326e7ff98aeSParav Pandit const struct ib_cm_event *ib_event, 13270c505f70SHaggai Eran sa_family_t sa_family, __be64 service_id) 13280c505f70SHaggai Eran { 13290c505f70SHaggai Eran if (sa_family == AF_IB) { 13300c505f70SHaggai Eran if (ib_event->event == IB_CM_REQ_RECEIVED) 13310c505f70SHaggai Eran cma_save_ib_info(src_addr, dst_addr, listen_id, 13320c505f70SHaggai Eran ib_event->param.req_rcvd.primary_path); 13330c505f70SHaggai Eran else if (ib_event->event == IB_CM_SIDR_REQ_RECEIVED) 13340c505f70SHaggai Eran cma_save_ib_info(src_addr, dst_addr, listen_id, NULL); 13350c505f70SHaggai Eran return 0; 13360c505f70SHaggai Eran } 13370c505f70SHaggai Eran 13380c505f70SHaggai Eran return cma_save_ip_info(src_addr, dst_addr, ib_event, service_id); 13390c505f70SHaggai Eran } 13400c505f70SHaggai Eran 13414c21b5bcSHaggai Eran static int cma_save_req_info(const struct ib_cm_event *ib_event, 13424c21b5bcSHaggai Eran struct cma_req_info *req) 13434c21b5bcSHaggai Eran { 13444c21b5bcSHaggai Eran const struct ib_cm_req_event_param *req_param = 13454c21b5bcSHaggai Eran &ib_event->param.req_rcvd; 13464c21b5bcSHaggai Eran const struct ib_cm_sidr_req_event_param *sidr_param = 13474c21b5bcSHaggai Eran &ib_event->param.sidr_req_rcvd; 13484c21b5bcSHaggai Eran 13494c21b5bcSHaggai Eran switch (ib_event->event) { 13504c21b5bcSHaggai Eran case IB_CM_REQ_RECEIVED: 13514c21b5bcSHaggai Eran req->device = req_param->listen_id->device; 13524c21b5bcSHaggai Eran req->port = req_param->port; 13534c21b5bcSHaggai Eran memcpy(&req->local_gid, &req_param->primary_path->sgid, 13544c21b5bcSHaggai Eran sizeof(req->local_gid)); 13554c21b5bcSHaggai Eran req->has_gid = true; 1356d3957b86SMajd Dibbiny req->service_id = req_param->primary_path->service_id; 1357ab3964adSHaggai Eran req->pkey = be16_to_cpu(req_param->primary_path->pkey); 135884424a7fSHaggai Eran if (req->pkey != req_param->bth_pkey) 135984424a7fSHaggai Eran pr_warn_ratelimited("RDMA CMA: got different BTH P_Key (0x%x) and primary path P_Key (0x%x)\n" 136084424a7fSHaggai Eran "RDMA CMA: in the future this may cause the request to be dropped\n", 136184424a7fSHaggai Eran req_param->bth_pkey, req->pkey); 13624c21b5bcSHaggai Eran break; 13634c21b5bcSHaggai Eran case IB_CM_SIDR_REQ_RECEIVED: 13644c21b5bcSHaggai Eran req->device = sidr_param->listen_id->device; 13654c21b5bcSHaggai Eran req->port = sidr_param->port; 13664c21b5bcSHaggai Eran req->has_gid = false; 13674c21b5bcSHaggai Eran req->service_id = sidr_param->service_id; 1368ab3964adSHaggai Eran req->pkey = sidr_param->pkey; 136984424a7fSHaggai Eran if (req->pkey != sidr_param->bth_pkey) 137084424a7fSHaggai Eran pr_warn_ratelimited("RDMA CMA: got different BTH P_Key (0x%x) and SIDR request payload P_Key (0x%x)\n" 137184424a7fSHaggai Eran "RDMA CMA: in the future this may cause the request to be dropped\n", 137284424a7fSHaggai Eran sidr_param->bth_pkey, req->pkey); 13734c21b5bcSHaggai Eran break; 13744c21b5bcSHaggai Eran default: 13754c21b5bcSHaggai Eran return -EINVAL; 13764c21b5bcSHaggai Eran } 13774c21b5bcSHaggai Eran 13784c21b5bcSHaggai Eran return 0; 13794c21b5bcSHaggai Eran } 13804c21b5bcSHaggai Eran 1381f887f2acSHaggai Eran static bool validate_ipv4_net_dev(struct net_device *net_dev, 1382f887f2acSHaggai Eran const struct sockaddr_in *dst_addr, 1383f887f2acSHaggai Eran const struct sockaddr_in *src_addr) 1384f887f2acSHaggai Eran { 1385f887f2acSHaggai Eran __be32 daddr = dst_addr->sin_addr.s_addr, 1386f887f2acSHaggai Eran saddr = src_addr->sin_addr.s_addr; 1387f887f2acSHaggai Eran struct fib_result res; 1388f887f2acSHaggai Eran struct flowi4 fl4; 1389f887f2acSHaggai Eran int err; 1390f887f2acSHaggai Eran bool ret; 1391f887f2acSHaggai Eran 1392f887f2acSHaggai Eran if (ipv4_is_multicast(saddr) || ipv4_is_lbcast(saddr) || 1393f887f2acSHaggai Eran ipv4_is_lbcast(daddr) || ipv4_is_zeronet(saddr) || 1394f887f2acSHaggai Eran ipv4_is_zeronet(daddr) || ipv4_is_loopback(daddr) || 1395f887f2acSHaggai Eran ipv4_is_loopback(saddr)) 1396f887f2acSHaggai Eran return false; 1397f887f2acSHaggai Eran 1398f887f2acSHaggai Eran memset(&fl4, 0, sizeof(fl4)); 1399f887f2acSHaggai Eran fl4.flowi4_iif = net_dev->ifindex; 1400f887f2acSHaggai Eran fl4.daddr = daddr; 1401f887f2acSHaggai Eran fl4.saddr = saddr; 1402f887f2acSHaggai Eran 1403f887f2acSHaggai Eran rcu_read_lock(); 1404f887f2acSHaggai Eran err = fib_lookup(dev_net(net_dev), &fl4, &res, 0); 1405d3632493SBart Van Assche ret = err == 0 && FIB_RES_DEV(res) == net_dev; 1406f887f2acSHaggai Eran rcu_read_unlock(); 1407f887f2acSHaggai Eran 1408f887f2acSHaggai Eran return ret; 1409f887f2acSHaggai Eran } 1410f887f2acSHaggai Eran 1411f887f2acSHaggai Eran static bool validate_ipv6_net_dev(struct net_device *net_dev, 1412f887f2acSHaggai Eran const struct sockaddr_in6 *dst_addr, 1413f887f2acSHaggai Eran const struct sockaddr_in6 *src_addr) 1414f887f2acSHaggai Eran { 1415f887f2acSHaggai Eran #if IS_ENABLED(CONFIG_IPV6) 1416f887f2acSHaggai Eran const int strict = ipv6_addr_type(&dst_addr->sin6_addr) & 1417f887f2acSHaggai Eran IPV6_ADDR_LINKLOCAL; 1418f887f2acSHaggai Eran struct rt6_info *rt = rt6_lookup(dev_net(net_dev), &dst_addr->sin6_addr, 1419f887f2acSHaggai Eran &src_addr->sin6_addr, net_dev->ifindex, 1420b75cc8f9SDavid Ahern NULL, strict); 1421f887f2acSHaggai Eran bool ret; 1422f887f2acSHaggai Eran 1423f887f2acSHaggai Eran if (!rt) 1424f887f2acSHaggai Eran return false; 1425f887f2acSHaggai Eran 1426f887f2acSHaggai Eran ret = rt->rt6i_idev->dev == net_dev; 1427f887f2acSHaggai Eran ip6_rt_put(rt); 1428f887f2acSHaggai Eran 1429f887f2acSHaggai Eran return ret; 1430f887f2acSHaggai Eran #else 1431f887f2acSHaggai Eran return false; 1432f887f2acSHaggai Eran #endif 1433f887f2acSHaggai Eran } 1434f887f2acSHaggai Eran 1435f887f2acSHaggai Eran static bool validate_net_dev(struct net_device *net_dev, 1436f887f2acSHaggai Eran const struct sockaddr *daddr, 1437f887f2acSHaggai Eran const struct sockaddr *saddr) 1438f887f2acSHaggai Eran { 1439f887f2acSHaggai Eran const struct sockaddr_in *daddr4 = (const struct sockaddr_in *)daddr; 1440f887f2acSHaggai Eran const struct sockaddr_in *saddr4 = (const struct sockaddr_in *)saddr; 1441f887f2acSHaggai Eran const struct sockaddr_in6 *daddr6 = (const struct sockaddr_in6 *)daddr; 1442f887f2acSHaggai Eran const struct sockaddr_in6 *saddr6 = (const struct sockaddr_in6 *)saddr; 1443f887f2acSHaggai Eran 1444f887f2acSHaggai Eran switch (daddr->sa_family) { 1445f887f2acSHaggai Eran case AF_INET: 1446f887f2acSHaggai Eran return saddr->sa_family == AF_INET && 1447f887f2acSHaggai Eran validate_ipv4_net_dev(net_dev, daddr4, saddr4); 1448f887f2acSHaggai Eran 1449f887f2acSHaggai Eran case AF_INET6: 1450f887f2acSHaggai Eran return saddr->sa_family == AF_INET6 && 1451f887f2acSHaggai Eran validate_ipv6_net_dev(net_dev, daddr6, saddr6); 1452f887f2acSHaggai Eran 1453f887f2acSHaggai Eran default: 1454f887f2acSHaggai Eran return false; 1455f887f2acSHaggai Eran } 1456f887f2acSHaggai Eran } 1457f887f2acSHaggai Eran 1458cee10433SParav Pandit static struct net_device * 1459cee10433SParav Pandit roce_get_net_dev_by_cm_event(const struct ib_cm_event *ib_event) 1460cee10433SParav Pandit { 1461cee10433SParav Pandit const struct ib_gid_attr *sgid_attr = NULL; 1462adb4a57aSParav Pandit struct net_device *ndev; 1463cee10433SParav Pandit 1464cee10433SParav Pandit if (ib_event->event == IB_CM_REQ_RECEIVED) 1465cee10433SParav Pandit sgid_attr = ib_event->param.req_rcvd.ppath_sgid_attr; 1466cee10433SParav Pandit else if (ib_event->event == IB_CM_SIDR_REQ_RECEIVED) 1467cee10433SParav Pandit sgid_attr = ib_event->param.sidr_req_rcvd.sgid_attr; 1468cee10433SParav Pandit 1469cee10433SParav Pandit if (!sgid_attr) 1470cee10433SParav Pandit return NULL; 1471adb4a57aSParav Pandit 1472adb4a57aSParav Pandit rcu_read_lock(); 1473adb4a57aSParav Pandit ndev = rdma_read_gid_attr_ndev_rcu(sgid_attr); 1474adb4a57aSParav Pandit if (IS_ERR(ndev)) 1475adb4a57aSParav Pandit ndev = NULL; 1476adb4a57aSParav Pandit else 1477adb4a57aSParav Pandit dev_hold(ndev); 1478adb4a57aSParav Pandit rcu_read_unlock(); 1479adb4a57aSParav Pandit return ndev; 1480cee10433SParav Pandit } 1481cee10433SParav Pandit 1482e7ff98aeSParav Pandit static struct net_device *cma_get_net_dev(const struct ib_cm_event *ib_event, 14832918c1a9SParav Pandit struct cma_req_info *req) 14844c21b5bcSHaggai Eran { 14852918c1a9SParav Pandit struct sockaddr *listen_addr = 14862918c1a9SParav Pandit (struct sockaddr *)&req->listen_addr_storage; 14872918c1a9SParav Pandit struct sockaddr *src_addr = (struct sockaddr *)&req->src_addr_storage; 14884c21b5bcSHaggai Eran struct net_device *net_dev; 14894c21b5bcSHaggai Eran const union ib_gid *gid = req->has_gid ? &req->local_gid : NULL; 14904c21b5bcSHaggai Eran int err; 14914c21b5bcSHaggai Eran 1492f887f2acSHaggai Eran err = cma_save_ip_info(listen_addr, src_addr, ib_event, 1493f887f2acSHaggai Eran req->service_id); 14944c21b5bcSHaggai Eran if (err) 14954c21b5bcSHaggai Eran return ERR_PTR(err); 14964c21b5bcSHaggai Eran 1497cee10433SParav Pandit if (rdma_protocol_roce(req->device, req->port)) 1498cee10433SParav Pandit net_dev = roce_get_net_dev_by_cm_event(ib_event); 1499cee10433SParav Pandit else 1500cee10433SParav Pandit net_dev = ib_get_net_dev_by_params(req->device, req->port, 1501cee10433SParav Pandit req->pkey, 15024c21b5bcSHaggai Eran gid, listen_addr); 15034c21b5bcSHaggai Eran if (!net_dev) 15044c21b5bcSHaggai Eran return ERR_PTR(-ENODEV); 15054c21b5bcSHaggai Eran 15064c21b5bcSHaggai Eran return net_dev; 15074c21b5bcSHaggai Eran } 15084c21b5bcSHaggai Eran 15092253fc0cSSteve Wise static enum rdma_ucm_port_space rdma_ps_from_service_id(__be64 service_id) 15104c21b5bcSHaggai Eran { 15114c21b5bcSHaggai Eran return (be64_to_cpu(service_id) >> 16) & 0xffff; 15124c21b5bcSHaggai Eran } 15134c21b5bcSHaggai Eran 15144c21b5bcSHaggai Eran static bool cma_match_private_data(struct rdma_id_private *id_priv, 15154c21b5bcSHaggai Eran const struct cma_hdr *hdr) 15164c21b5bcSHaggai Eran { 15174c21b5bcSHaggai Eran struct sockaddr *addr = cma_src_addr(id_priv); 15184c21b5bcSHaggai Eran __be32 ip4_addr; 15194c21b5bcSHaggai Eran struct in6_addr ip6_addr; 15204c21b5bcSHaggai Eran 15214c21b5bcSHaggai Eran if (cma_any_addr(addr) && !id_priv->afonly) 15224c21b5bcSHaggai Eran return true; 15234c21b5bcSHaggai Eran 15244c21b5bcSHaggai Eran switch (addr->sa_family) { 15254c21b5bcSHaggai Eran case AF_INET: 15264c21b5bcSHaggai Eran ip4_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr; 15274c21b5bcSHaggai Eran if (cma_get_ip_ver(hdr) != 4) 15284c21b5bcSHaggai Eran return false; 15294c21b5bcSHaggai Eran if (!cma_any_addr(addr) && 15304c21b5bcSHaggai Eran hdr->dst_addr.ip4.addr != ip4_addr) 15314c21b5bcSHaggai Eran return false; 15324c21b5bcSHaggai Eran break; 15334c21b5bcSHaggai Eran case AF_INET6: 15344c21b5bcSHaggai Eran ip6_addr = ((struct sockaddr_in6 *)addr)->sin6_addr; 15354c21b5bcSHaggai Eran if (cma_get_ip_ver(hdr) != 6) 15364c21b5bcSHaggai Eran return false; 15374c21b5bcSHaggai Eran if (!cma_any_addr(addr) && 15384c21b5bcSHaggai Eran memcmp(&hdr->dst_addr.ip6, &ip6_addr, sizeof(ip6_addr))) 15394c21b5bcSHaggai Eran return false; 15404c21b5bcSHaggai Eran break; 15414c21b5bcSHaggai Eran case AF_IB: 15424c21b5bcSHaggai Eran return true; 15434c21b5bcSHaggai Eran default: 15444c21b5bcSHaggai Eran return false; 15454c21b5bcSHaggai Eran } 15464c21b5bcSHaggai Eran 15474c21b5bcSHaggai Eran return true; 15484c21b5bcSHaggai Eran } 15494c21b5bcSHaggai Eran 1550b8cab5daSHaggai Eran static bool cma_protocol_roce(const struct rdma_cm_id *id) 1551b8cab5daSHaggai Eran { 1552b8cab5daSHaggai Eran struct ib_device *device = id->device; 1553b8cab5daSHaggai Eran const int port_num = id->port_num ?: rdma_start_port(device); 1554b8cab5daSHaggai Eran 15555ac08a34SParav Pandit return rdma_protocol_roce(device, port_num); 1556b8cab5daSHaggai Eran } 1557b8cab5daSHaggai Eran 155878fb282bSParav Pandit static bool cma_is_req_ipv6_ll(const struct cma_req_info *req) 155978fb282bSParav Pandit { 156078fb282bSParav Pandit const struct sockaddr *daddr = 156178fb282bSParav Pandit (const struct sockaddr *)&req->listen_addr_storage; 156278fb282bSParav Pandit const struct sockaddr_in6 *daddr6 = (const struct sockaddr_in6 *)daddr; 156378fb282bSParav Pandit 156478fb282bSParav Pandit /* Returns true if the req is for IPv6 link local */ 156578fb282bSParav Pandit return (daddr->sa_family == AF_INET6 && 156678fb282bSParav Pandit (ipv6_addr_type(&daddr6->sin6_addr) & IPV6_ADDR_LINKLOCAL)); 156778fb282bSParav Pandit } 156878fb282bSParav Pandit 1569fac51590SMatan Barak static bool cma_match_net_dev(const struct rdma_cm_id *id, 1570fac51590SMatan Barak const struct net_device *net_dev, 157178fb282bSParav Pandit const struct cma_req_info *req) 15724c21b5bcSHaggai Eran { 1573fac51590SMatan Barak const struct rdma_addr *addr = &id->route.addr; 15744c21b5bcSHaggai Eran 15754c21b5bcSHaggai Eran if (!net_dev) 1576d274e45cSParav Pandit /* This request is an AF_IB request */ 157778fb282bSParav Pandit return (!id->port_num || id->port_num == req->port) && 1578d274e45cSParav Pandit (addr->src_addr.ss_family == AF_IB); 15794c21b5bcSHaggai Eran 1580643d213aSParav Pandit /* 158178fb282bSParav Pandit * If the request is not for IPv6 link local, allow matching 158278fb282bSParav Pandit * request to any netdevice of the one or multiport rdma device. 158378fb282bSParav Pandit */ 158478fb282bSParav Pandit if (!cma_is_req_ipv6_ll(req)) 158578fb282bSParav Pandit return true; 158678fb282bSParav Pandit /* 1587643d213aSParav Pandit * Net namespaces must match, and if the listner is listening 1588643d213aSParav Pandit * on a specific netdevice than netdevice must match as well. 1589643d213aSParav Pandit */ 1590643d213aSParav Pandit if (net_eq(dev_net(net_dev), addr->dev_addr.net) && 1591643d213aSParav Pandit (!!addr->dev_addr.bound_dev_if == 1592643d213aSParav Pandit (addr->dev_addr.bound_dev_if == net_dev->ifindex))) 1593643d213aSParav Pandit return true; 1594643d213aSParav Pandit else 1595643d213aSParav Pandit return false; 15964c21b5bcSHaggai Eran } 15974c21b5bcSHaggai Eran 15984c21b5bcSHaggai Eran static struct rdma_id_private *cma_find_listener( 15994c21b5bcSHaggai Eran const struct rdma_bind_list *bind_list, 16004c21b5bcSHaggai Eran const struct ib_cm_id *cm_id, 16014c21b5bcSHaggai Eran const struct ib_cm_event *ib_event, 16024c21b5bcSHaggai Eran const struct cma_req_info *req, 16034c21b5bcSHaggai Eran const struct net_device *net_dev) 16044c21b5bcSHaggai Eran { 16054c21b5bcSHaggai Eran struct rdma_id_private *id_priv, *id_priv_dev; 16064c21b5bcSHaggai Eran 16074c21b5bcSHaggai Eran if (!bind_list) 16084c21b5bcSHaggai Eran return ERR_PTR(-EINVAL); 16094c21b5bcSHaggai Eran 16104c21b5bcSHaggai Eran hlist_for_each_entry(id_priv, &bind_list->owners, node) { 16114c21b5bcSHaggai Eran if (cma_match_private_data(id_priv, ib_event->private_data)) { 16124c21b5bcSHaggai Eran if (id_priv->id.device == cm_id->device && 161378fb282bSParav Pandit cma_match_net_dev(&id_priv->id, net_dev, req)) 16144c21b5bcSHaggai Eran return id_priv; 16154c21b5bcSHaggai Eran list_for_each_entry(id_priv_dev, 16164c21b5bcSHaggai Eran &id_priv->listen_list, 16174c21b5bcSHaggai Eran listen_list) { 16184c21b5bcSHaggai Eran if (id_priv_dev->id.device == cm_id->device && 161978fb282bSParav Pandit cma_match_net_dev(&id_priv_dev->id, 162078fb282bSParav Pandit net_dev, req)) 16214c21b5bcSHaggai Eran return id_priv_dev; 16224c21b5bcSHaggai Eran } 16234c21b5bcSHaggai Eran } 16244c21b5bcSHaggai Eran } 16254c21b5bcSHaggai Eran 16264c21b5bcSHaggai Eran return ERR_PTR(-EINVAL); 16274c21b5bcSHaggai Eran } 16284c21b5bcSHaggai Eran 1629e7ff98aeSParav Pandit static struct rdma_id_private * 163085463316SParav Pandit cma_ib_id_from_event(struct ib_cm_id *cm_id, 1631e7ff98aeSParav Pandit const struct ib_cm_event *ib_event, 163241ab1cb7SParav Pandit struct cma_req_info *req, 16330b3ca768SHaggai Eran struct net_device **net_dev) 16344c21b5bcSHaggai Eran { 16354c21b5bcSHaggai Eran struct rdma_bind_list *bind_list; 16364c21b5bcSHaggai Eran struct rdma_id_private *id_priv; 16374c21b5bcSHaggai Eran int err; 16384c21b5bcSHaggai Eran 163941ab1cb7SParav Pandit err = cma_save_req_info(ib_event, req); 16404c21b5bcSHaggai Eran if (err) 16414c21b5bcSHaggai Eran return ERR_PTR(err); 16424c21b5bcSHaggai Eran 164341ab1cb7SParav Pandit *net_dev = cma_get_net_dev(ib_event, req); 16440b3ca768SHaggai Eran if (IS_ERR(*net_dev)) { 16450b3ca768SHaggai Eran if (PTR_ERR(*net_dev) == -EAFNOSUPPORT) { 16464c21b5bcSHaggai Eran /* Assuming the protocol is AF_IB */ 16470b3ca768SHaggai Eran *net_dev = NULL; 16484c21b5bcSHaggai Eran } else { 16490b3ca768SHaggai Eran return ERR_CAST(*net_dev); 16504c21b5bcSHaggai Eran } 16514c21b5bcSHaggai Eran } 16524c21b5bcSHaggai Eran 16532918c1a9SParav Pandit /* 16542918c1a9SParav Pandit * Net namespace might be getting deleted while route lookup, 16552918c1a9SParav Pandit * cm_id lookup is in progress. Therefore, perform netdevice 16562918c1a9SParav Pandit * validation, cm_id lookup under rcu lock. 16572918c1a9SParav Pandit * RCU lock along with netdevice state check, synchronizes with 16582918c1a9SParav Pandit * netdevice migrating to different net namespace and also avoids 16592918c1a9SParav Pandit * case where net namespace doesn't get deleted while lookup is in 16602918c1a9SParav Pandit * progress. 16612918c1a9SParav Pandit * If the device state is not IFF_UP, its properties such as ifindex 16622918c1a9SParav Pandit * and nd_net cannot be trusted to remain valid without rcu lock. 16632918c1a9SParav Pandit * net/core/dev.c change_net_namespace() ensures to synchronize with 16642918c1a9SParav Pandit * ongoing operations on net device after device is closed using 16652918c1a9SParav Pandit * synchronize_net(). 16662918c1a9SParav Pandit */ 16672918c1a9SParav Pandit rcu_read_lock(); 16682918c1a9SParav Pandit if (*net_dev) { 16692918c1a9SParav Pandit /* 16702918c1a9SParav Pandit * If netdevice is down, it is likely that it is administratively 16712918c1a9SParav Pandit * down or it might be migrating to different namespace. 16722918c1a9SParav Pandit * In that case avoid further processing, as the net namespace 16732918c1a9SParav Pandit * or ifindex may change. 16742918c1a9SParav Pandit */ 16752918c1a9SParav Pandit if (((*net_dev)->flags & IFF_UP) == 0) { 16762918c1a9SParav Pandit id_priv = ERR_PTR(-EHOSTUNREACH); 16772918c1a9SParav Pandit goto err; 16782918c1a9SParav Pandit } 16792918c1a9SParav Pandit 16802918c1a9SParav Pandit if (!validate_net_dev(*net_dev, 168141ab1cb7SParav Pandit (struct sockaddr *)&req->listen_addr_storage, 168241ab1cb7SParav Pandit (struct sockaddr *)&req->src_addr_storage)) { 16832918c1a9SParav Pandit id_priv = ERR_PTR(-EHOSTUNREACH); 16842918c1a9SParav Pandit goto err; 16852918c1a9SParav Pandit } 16862918c1a9SParav Pandit } 16872918c1a9SParav Pandit 1688fa20105eSGuy Shapiro bind_list = cma_ps_find(*net_dev ? dev_net(*net_dev) : &init_net, 168941ab1cb7SParav Pandit rdma_ps_from_service_id(req->service_id), 169041ab1cb7SParav Pandit cma_port_from_service_id(req->service_id)); 169141ab1cb7SParav Pandit id_priv = cma_find_listener(bind_list, cm_id, ib_event, req, *net_dev); 16922918c1a9SParav Pandit err: 16932918c1a9SParav Pandit rcu_read_unlock(); 1694b3b51f9fSHaggai Eran if (IS_ERR(id_priv) && *net_dev) { 1695be688195SHaggai Eran dev_put(*net_dev); 1696be688195SHaggai Eran *net_dev = NULL; 1697be688195SHaggai Eran } 16984c21b5bcSHaggai Eran return id_priv; 16994c21b5bcSHaggai Eran } 17004c21b5bcSHaggai Eran 1701c0b64f58SBart Van Assche static inline u8 cma_user_data_offset(struct rdma_id_private *id_priv) 1702e51060f0SSean Hefty { 1703e8160e15SSean Hefty return cma_family(id_priv) == AF_IB ? 0 : sizeof(struct cma_hdr); 1704e51060f0SSean Hefty } 1705e51060f0SSean Hefty 1706e51060f0SSean Hefty static void cma_cancel_route(struct rdma_id_private *id_priv) 1707e51060f0SSean Hefty { 1708fe53ba2fSMichael Wang if (rdma_cap_ib_sa(id_priv->id.device, id_priv->id.port_num)) { 1709e51060f0SSean Hefty if (id_priv->query) 1710e51060f0SSean Hefty ib_sa_cancel_query(id_priv->query_id, id_priv->query); 1711e51060f0SSean Hefty } 1712e51060f0SSean Hefty } 1713e51060f0SSean Hefty 1714e51060f0SSean Hefty static void cma_cancel_listens(struct rdma_id_private *id_priv) 1715e51060f0SSean Hefty { 1716e51060f0SSean Hefty struct rdma_id_private *dev_id_priv; 1717e51060f0SSean Hefty 1718d02d1f53SSean Hefty /* 1719d02d1f53SSean Hefty * Remove from listen_any_list to prevent added devices from spawning 1720d02d1f53SSean Hefty * additional listen requests. 1721d02d1f53SSean Hefty */ 1722e51060f0SSean Hefty mutex_lock(&lock); 1723e51060f0SSean Hefty list_del(&id_priv->list); 1724e51060f0SSean Hefty 1725e51060f0SSean Hefty while (!list_empty(&id_priv->listen_list)) { 1726e51060f0SSean Hefty dev_id_priv = list_entry(id_priv->listen_list.next, 1727e51060f0SSean Hefty struct rdma_id_private, listen_list); 1728d02d1f53SSean Hefty /* sync with device removal to avoid duplicate destruction */ 1729d02d1f53SSean Hefty list_del_init(&dev_id_priv->list); 1730d02d1f53SSean Hefty list_del(&dev_id_priv->listen_list); 1731d02d1f53SSean Hefty mutex_unlock(&lock); 1732d02d1f53SSean Hefty 1733d02d1f53SSean Hefty rdma_destroy_id(&dev_id_priv->id); 1734d02d1f53SSean Hefty mutex_lock(&lock); 1735e51060f0SSean Hefty } 1736e51060f0SSean Hefty mutex_unlock(&lock); 1737e51060f0SSean Hefty } 1738e51060f0SSean Hefty 1739e51060f0SSean Hefty static void cma_cancel_operation(struct rdma_id_private *id_priv, 1740550e5ca7SNir Muchtar enum rdma_cm_state state) 1741e51060f0SSean Hefty { 1742e51060f0SSean Hefty switch (state) { 1743550e5ca7SNir Muchtar case RDMA_CM_ADDR_QUERY: 1744e51060f0SSean Hefty rdma_addr_cancel(&id_priv->id.route.addr.dev_addr); 1745e51060f0SSean Hefty break; 1746550e5ca7SNir Muchtar case RDMA_CM_ROUTE_QUERY: 1747e51060f0SSean Hefty cma_cancel_route(id_priv); 1748e51060f0SSean Hefty break; 1749550e5ca7SNir Muchtar case RDMA_CM_LISTEN: 1750f4753834SSean Hefty if (cma_any_addr(cma_src_addr(id_priv)) && !id_priv->cma_dev) 1751e51060f0SSean Hefty cma_cancel_listens(id_priv); 1752e51060f0SSean Hefty break; 1753e51060f0SSean Hefty default: 1754e51060f0SSean Hefty break; 1755e51060f0SSean Hefty } 1756e51060f0SSean Hefty } 1757e51060f0SSean Hefty 1758e51060f0SSean Hefty static void cma_release_port(struct rdma_id_private *id_priv) 1759e51060f0SSean Hefty { 1760e51060f0SSean Hefty struct rdma_bind_list *bind_list = id_priv->bind_list; 1761fa20105eSGuy Shapiro struct net *net = id_priv->id.route.addr.dev_addr.net; 1762e51060f0SSean Hefty 1763e51060f0SSean Hefty if (!bind_list) 1764e51060f0SSean Hefty return; 1765e51060f0SSean Hefty 1766e51060f0SSean Hefty mutex_lock(&lock); 1767e51060f0SSean Hefty hlist_del(&id_priv->node); 1768e51060f0SSean Hefty if (hlist_empty(&bind_list->owners)) { 1769fa20105eSGuy Shapiro cma_ps_remove(net, bind_list->ps, bind_list->port); 1770e51060f0SSean Hefty kfree(bind_list); 1771e51060f0SSean Hefty } 1772e51060f0SSean Hefty mutex_unlock(&lock); 1773e51060f0SSean Hefty } 1774e51060f0SSean Hefty 177588145678SParav Pandit static void cma_leave_roce_mc_group(struct rdma_id_private *id_priv, 177688145678SParav Pandit struct cma_multicast *mc) 177788145678SParav Pandit { 1778c0126915SJason Gunthorpe struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 177988145678SParav Pandit struct net_device *ndev = NULL; 178088145678SParav Pandit 178188145678SParav Pandit if (dev_addr->bound_dev_if) 1782c0126915SJason Gunthorpe ndev = dev_get_by_index(dev_addr->net, dev_addr->bound_dev_if); 178388145678SParav Pandit if (ndev) { 1784c0126915SJason Gunthorpe cma_igmp_send(ndev, &mc->multicast.ib->rec.mgid, false); 178588145678SParav Pandit dev_put(ndev); 178688145678SParav Pandit } 178788145678SParav Pandit kref_put(&mc->mcref, release_mc); 178888145678SParav Pandit } 178988145678SParav Pandit 1790c8f6a362SSean Hefty static void cma_leave_mc_groups(struct rdma_id_private *id_priv) 1791c8f6a362SSean Hefty { 1792c8f6a362SSean Hefty struct cma_multicast *mc; 1793c8f6a362SSean Hefty 1794c8f6a362SSean Hefty while (!list_empty(&id_priv->mc_list)) { 1795c8f6a362SSean Hefty mc = container_of(id_priv->mc_list.next, 1796c8f6a362SSean Hefty struct cma_multicast, list); 1797c8f6a362SSean Hefty list_del(&mc->list); 1798a31ad3b0SMichael Wang if (rdma_cap_ib_mcast(id_priv->cma_dev->device, 17995c9a5282SMichael Wang id_priv->id.port_num)) { 1800c8f6a362SSean Hefty ib_sa_free_multicast(mc->multicast.ib); 1801c8f6a362SSean Hefty kfree(mc); 1802bee3c3c9SMoni Shoua } else { 180388145678SParav Pandit cma_leave_roce_mc_group(id_priv, mc); 1804c8f6a362SSean Hefty } 1805c8f6a362SSean Hefty } 1806bee3c3c9SMoni Shoua } 1807c8f6a362SSean Hefty 1808e51060f0SSean Hefty void rdma_destroy_id(struct rdma_cm_id *id) 1809e51060f0SSean Hefty { 1810e51060f0SSean Hefty struct rdma_id_private *id_priv; 1811550e5ca7SNir Muchtar enum rdma_cm_state state; 1812e51060f0SSean Hefty 1813e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 1814550e5ca7SNir Muchtar state = cma_exch(id_priv, RDMA_CM_DESTROYING); 1815e51060f0SSean Hefty cma_cancel_operation(id_priv, state); 1816e51060f0SSean Hefty 1817a396d43aSSean Hefty /* 1818a396d43aSSean Hefty * Wait for any active callback to finish. New callbacks will find 1819a396d43aSSean Hefty * the id_priv state set to destroying and abort. 1820a396d43aSSean Hefty */ 1821a396d43aSSean Hefty mutex_lock(&id_priv->handler_mutex); 1822a396d43aSSean Hefty mutex_unlock(&id_priv->handler_mutex); 1823a396d43aSSean Hefty 182400313983SSteve Wise rdma_restrack_del(&id_priv->res); 1825ed7a01fdSLeon Romanovsky if (id_priv->cma_dev) { 182672219ceaSMichael Wang if (rdma_cap_ib_cm(id_priv->id.device, 1)) { 18270c9361fcSJack Morgenstein if (id_priv->cm_id.ib) 1828e51060f0SSean Hefty ib_destroy_cm_id(id_priv->cm_id.ib); 182904215330SMichael Wang } else if (rdma_cap_iw_cm(id_priv->id.device, 1)) { 18300c9361fcSJack Morgenstein if (id_priv->cm_id.iw) 183107ebafbaSTom Tucker iw_destroy_cm_id(id_priv->cm_id.iw); 1832e51060f0SSean Hefty } 1833c8f6a362SSean Hefty cma_leave_mc_groups(id_priv); 1834a396d43aSSean Hefty cma_release_dev(id_priv); 1835e51060f0SSean Hefty } 1836e51060f0SSean Hefty 1837e51060f0SSean Hefty cma_release_port(id_priv); 1838e51060f0SSean Hefty cma_deref_id(id_priv); 1839e51060f0SSean Hefty wait_for_completion(&id_priv->comp); 1840e51060f0SSean Hefty 1841d02d1f53SSean Hefty if (id_priv->internal_id) 1842d02d1f53SSean Hefty cma_deref_id(id_priv->id.context); 1843d02d1f53SSean Hefty 1844e51060f0SSean Hefty kfree(id_priv->id.route.path_rec); 18454ed13a5fSParav Pandit 18464ed13a5fSParav Pandit if (id_priv->id.route.addr.dev_addr.sgid_attr) 18474ed13a5fSParav Pandit rdma_put_gid_attr(id_priv->id.route.addr.dev_addr.sgid_attr); 18484ed13a5fSParav Pandit 1849fa20105eSGuy Shapiro put_net(id_priv->id.route.addr.dev_addr.net); 1850e51060f0SSean Hefty kfree(id_priv); 1851e51060f0SSean Hefty } 1852e51060f0SSean Hefty EXPORT_SYMBOL(rdma_destroy_id); 1853e51060f0SSean Hefty 1854e51060f0SSean Hefty static int cma_rep_recv(struct rdma_id_private *id_priv) 1855e51060f0SSean Hefty { 1856e51060f0SSean Hefty int ret; 1857e51060f0SSean Hefty 18585851bb89SSean Hefty ret = cma_modify_qp_rtr(id_priv, NULL); 1859e51060f0SSean Hefty if (ret) 1860e51060f0SSean Hefty goto reject; 1861e51060f0SSean Hefty 18625851bb89SSean Hefty ret = cma_modify_qp_rts(id_priv, NULL); 1863e51060f0SSean Hefty if (ret) 1864e51060f0SSean Hefty goto reject; 1865e51060f0SSean Hefty 1866e51060f0SSean Hefty ret = ib_send_cm_rtu(id_priv->cm_id.ib, NULL, 0); 1867e51060f0SSean Hefty if (ret) 1868e51060f0SSean Hefty goto reject; 1869e51060f0SSean Hefty 1870e51060f0SSean Hefty return 0; 1871e51060f0SSean Hefty reject: 1872498683c6SMoni Shoua pr_debug_ratelimited("RDMA CM: CONNECT_ERROR: failed to handle reply. status %d\n", ret); 1873c5483388SSean Hefty cma_modify_qp_err(id_priv); 1874e51060f0SSean Hefty ib_send_cm_rej(id_priv->cm_id.ib, IB_CM_REJ_CONSUMER_DEFINED, 1875e51060f0SSean Hefty NULL, 0, NULL, 0); 1876e51060f0SSean Hefty return ret; 1877e51060f0SSean Hefty } 1878e51060f0SSean Hefty 1879a1b1b61fSSean Hefty static void cma_set_rep_event_data(struct rdma_cm_event *event, 1880e7ff98aeSParav Pandit const struct ib_cm_rep_event_param *rep_data, 1881a1b1b61fSSean Hefty void *private_data) 1882a1b1b61fSSean Hefty { 1883a1b1b61fSSean Hefty event->param.conn.private_data = private_data; 1884a1b1b61fSSean Hefty event->param.conn.private_data_len = IB_CM_REP_PRIVATE_DATA_SIZE; 1885a1b1b61fSSean Hefty event->param.conn.responder_resources = rep_data->responder_resources; 1886a1b1b61fSSean Hefty event->param.conn.initiator_depth = rep_data->initiator_depth; 1887a1b1b61fSSean Hefty event->param.conn.flow_control = rep_data->flow_control; 1888a1b1b61fSSean Hefty event->param.conn.rnr_retry_count = rep_data->rnr_retry_count; 1889a1b1b61fSSean Hefty event->param.conn.srq = rep_data->srq; 1890a1b1b61fSSean Hefty event->param.conn.qp_num = rep_data->remote_qpn; 1891a1b1b61fSSean Hefty } 1892a1b1b61fSSean Hefty 1893e7ff98aeSParav Pandit static int cma_ib_handler(struct ib_cm_id *cm_id, 1894e7ff98aeSParav Pandit const struct ib_cm_event *ib_event) 1895e51060f0SSean Hefty { 1896e51060f0SSean Hefty struct rdma_id_private *id_priv = cm_id->context; 18977582df82SParav Pandit struct rdma_cm_event event = {}; 1898a1b1b61fSSean Hefty int ret = 0; 1899e51060f0SSean Hefty 190037e07cdaSBart Van Assche mutex_lock(&id_priv->handler_mutex); 190138ca83a5SAmir Vadai if ((ib_event->event != IB_CM_TIMEWAIT_EXIT && 190237e07cdaSBart Van Assche id_priv->state != RDMA_CM_CONNECT) || 190338ca83a5SAmir Vadai (ib_event->event == IB_CM_TIMEWAIT_EXIT && 190437e07cdaSBart Van Assche id_priv->state != RDMA_CM_DISCONNECT)) 190537e07cdaSBart Van Assche goto out; 1906e51060f0SSean Hefty 1907e51060f0SSean Hefty switch (ib_event->event) { 1908e51060f0SSean Hefty case IB_CM_REQ_ERROR: 1909e51060f0SSean Hefty case IB_CM_REP_ERROR: 1910a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_UNREACHABLE; 1911a1b1b61fSSean Hefty event.status = -ETIMEDOUT; 1912e51060f0SSean Hefty break; 1913e51060f0SSean Hefty case IB_CM_REP_RECEIVED: 191461c0ddbeSMoni Shoua if (cma_comp(id_priv, RDMA_CM_CONNECT) && 191561c0ddbeSMoni Shoua (id_priv->id.qp_type != IB_QPT_UD)) 191661c0ddbeSMoni Shoua ib_send_cm_mra(cm_id, CMA_CM_MRA_SETTING, NULL, 0); 191701602f11SSean Hefty if (id_priv->id.qp) { 1918a1b1b61fSSean Hefty event.status = cma_rep_recv(id_priv); 1919a1b1b61fSSean Hefty event.event = event.status ? RDMA_CM_EVENT_CONNECT_ERROR : 1920e51060f0SSean Hefty RDMA_CM_EVENT_ESTABLISHED; 192101602f11SSean Hefty } else { 1922a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_CONNECT_RESPONSE; 192301602f11SSean Hefty } 1924a1b1b61fSSean Hefty cma_set_rep_event_data(&event, &ib_event->param.rep_rcvd, 1925a1b1b61fSSean Hefty ib_event->private_data); 1926e51060f0SSean Hefty break; 1927e51060f0SSean Hefty case IB_CM_RTU_RECEIVED: 19280fe313b0SSean Hefty case IB_CM_USER_ESTABLISHED: 19290fe313b0SSean Hefty event.event = RDMA_CM_EVENT_ESTABLISHED; 1930e51060f0SSean Hefty break; 1931e51060f0SSean Hefty case IB_CM_DREQ_ERROR: 1932a1b1b61fSSean Hefty event.status = -ETIMEDOUT; /* fall through */ 1933e51060f0SSean Hefty case IB_CM_DREQ_RECEIVED: 1934e51060f0SSean Hefty case IB_CM_DREP_RECEIVED: 1935550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_CONNECT, 1936550e5ca7SNir Muchtar RDMA_CM_DISCONNECT)) 1937e51060f0SSean Hefty goto out; 1938a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_DISCONNECTED; 1939e51060f0SSean Hefty break; 1940e51060f0SSean Hefty case IB_CM_TIMEWAIT_EXIT: 194138ca83a5SAmir Vadai event.event = RDMA_CM_EVENT_TIMEWAIT_EXIT; 194238ca83a5SAmir Vadai break; 1943e51060f0SSean Hefty case IB_CM_MRA_RECEIVED: 1944e51060f0SSean Hefty /* ignore event */ 1945e51060f0SSean Hefty goto out; 1946e51060f0SSean Hefty case IB_CM_REJ_RECEIVED: 1947498683c6SMoni Shoua pr_debug_ratelimited("RDMA CM: REJECTED: %s\n", rdma_reject_msg(&id_priv->id, 1948498683c6SMoni Shoua ib_event->param.rej_rcvd.reason)); 1949c5483388SSean Hefty cma_modify_qp_err(id_priv); 1950a1b1b61fSSean Hefty event.status = ib_event->param.rej_rcvd.reason; 1951a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_REJECTED; 1952a1b1b61fSSean Hefty event.param.conn.private_data = ib_event->private_data; 1953a1b1b61fSSean Hefty event.param.conn.private_data_len = IB_CM_REJ_PRIVATE_DATA_SIZE; 1954e51060f0SSean Hefty break; 1955e51060f0SSean Hefty default: 1956aba25a3eSParav Pandit pr_err("RDMA CMA: unexpected IB CM event: %d\n", 1957e51060f0SSean Hefty ib_event->event); 1958e51060f0SSean Hefty goto out; 1959e51060f0SSean Hefty } 1960e51060f0SSean Hefty 1961a1b1b61fSSean Hefty ret = id_priv->id.event_handler(&id_priv->id, &event); 1962e51060f0SSean Hefty if (ret) { 1963e51060f0SSean Hefty /* Destroy the CM ID by returning a non-zero value. */ 1964e51060f0SSean Hefty id_priv->cm_id.ib = NULL; 1965550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 1966de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 1967e51060f0SSean Hefty rdma_destroy_id(&id_priv->id); 1968e51060f0SSean Hefty return ret; 1969e51060f0SSean Hefty } 1970e51060f0SSean Hefty out: 1971de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 1972e51060f0SSean Hefty return ret; 1973e51060f0SSean Hefty } 1974e51060f0SSean Hefty 1975e7ff98aeSParav Pandit static struct rdma_id_private * 197685463316SParav Pandit cma_ib_new_conn_id(const struct rdma_cm_id *listen_id, 1977e7ff98aeSParav Pandit const struct ib_cm_event *ib_event, 19780b3ca768SHaggai Eran struct net_device *net_dev) 1979e51060f0SSean Hefty { 198000313983SSteve Wise struct rdma_id_private *listen_id_priv; 1981e51060f0SSean Hefty struct rdma_id_private *id_priv; 1982e51060f0SSean Hefty struct rdma_cm_id *id; 1983e51060f0SSean Hefty struct rdma_route *rt; 19840c505f70SHaggai Eran const sa_family_t ss_family = listen_id->route.addr.src_addr.ss_family; 19859fdca4daSDasaratharaman Chandramouli struct sa_path_rec *path = ib_event->param.req_rcvd.primary_path; 1986d3957b86SMajd Dibbiny const __be64 service_id = 1987d3957b86SMajd Dibbiny ib_event->param.req_rcvd.primary_path->service_id; 198864c5e613SOr Gerlitz int ret; 1989e51060f0SSean Hefty 199000313983SSteve Wise listen_id_priv = container_of(listen_id, struct rdma_id_private, id); 199100313983SSteve Wise id = __rdma_create_id(listen_id->route.addr.dev_addr.net, 1992fa20105eSGuy Shapiro listen_id->event_handler, listen_id->context, 199300313983SSteve Wise listen_id->ps, ib_event->param.req_rcvd.qp_type, 199400313983SSteve Wise listen_id_priv->res.kern_name); 19953f168d2bSKrishna Kumar if (IS_ERR(id)) 19960c9361fcSJack Morgenstein return NULL; 19973f168d2bSKrishna Kumar 1998f4753834SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 19990c505f70SHaggai Eran if (cma_save_net_info((struct sockaddr *)&id->route.addr.src_addr, 20000c505f70SHaggai Eran (struct sockaddr *)&id->route.addr.dst_addr, 20010c505f70SHaggai Eran listen_id, ib_event, ss_family, service_id)) 2002fbaa1a6dSSean Hefty goto err; 20033f168d2bSKrishna Kumar 20043f168d2bSKrishna Kumar rt = &id->route; 20053f168d2bSKrishna Kumar rt->num_paths = ib_event->param.req_rcvd.alternate_path ? 2 : 1; 20066da2ec56SKees Cook rt->path_rec = kmalloc_array(rt->num_paths, sizeof(*rt->path_rec), 20073f168d2bSKrishna Kumar GFP_KERNEL); 20083f168d2bSKrishna Kumar if (!rt->path_rec) 20090c9361fcSJack Morgenstein goto err; 20103f168d2bSKrishna Kumar 20119fdca4daSDasaratharaman Chandramouli rt->path_rec[0] = *path; 2012e51060f0SSean Hefty if (rt->num_paths == 2) 2013e51060f0SSean Hefty rt->path_rec[1] = *ib_event->param.req_rcvd.alternate_path; 2014e51060f0SSean Hefty 20150b3ca768SHaggai Eran if (net_dev) { 201677addc52SParav Pandit rdma_copy_src_l2_addr(&rt->addr.dev_addr, net_dev); 20170b3ca768SHaggai Eran } else { 2018b8cab5daSHaggai Eran if (!cma_protocol_roce(listen_id) && 2019b8cab5daSHaggai Eran cma_any_addr(cma_src_addr(id_priv))) { 2020b8cab5daSHaggai Eran rt->addr.dev_addr.dev_type = ARPHRD_INFINIBAND; 2021b8cab5daSHaggai Eran rdma_addr_set_sgid(&rt->addr.dev_addr, &rt->path_rec[0].sgid); 2022b8cab5daSHaggai Eran ib_addr_set_pkey(&rt->addr.dev_addr, be16_to_cpu(rt->path_rec[0].pkey)); 2023b8cab5daSHaggai Eran } else if (!cma_any_addr(cma_src_addr(id_priv))) { 2024b8cab5daSHaggai Eran ret = cma_translate_addr(cma_src_addr(id_priv), &rt->addr.dev_addr); 2025b8cab5daSHaggai Eran if (ret) 2026b8cab5daSHaggai Eran goto err; 2027b8cab5daSHaggai Eran } 20286f8372b6SSean Hefty } 20296f8372b6SSean Hefty rdma_addr_set_dgid(&rt->addr.dev_addr, &rt->path_rec[0].dgid); 2030e51060f0SSean Hefty 2031550e5ca7SNir Muchtar id_priv->state = RDMA_CM_CONNECT; 2032e51060f0SSean Hefty return id_priv; 20333f168d2bSKrishna Kumar 20343f168d2bSKrishna Kumar err: 20350c9361fcSJack Morgenstein rdma_destroy_id(id); 2036e51060f0SSean Hefty return NULL; 2037e51060f0SSean Hefty } 2038e51060f0SSean Hefty 2039e7ff98aeSParav Pandit static struct rdma_id_private * 204085463316SParav Pandit cma_ib_new_udp_id(const struct rdma_cm_id *listen_id, 2041e7ff98aeSParav Pandit const struct ib_cm_event *ib_event, 20420b3ca768SHaggai Eran struct net_device *net_dev) 2043628e5f6dSSean Hefty { 2044e7ff98aeSParav Pandit const struct rdma_id_private *listen_id_priv; 2045628e5f6dSSean Hefty struct rdma_id_private *id_priv; 2046628e5f6dSSean Hefty struct rdma_cm_id *id; 20470c505f70SHaggai Eran const sa_family_t ss_family = listen_id->route.addr.src_addr.ss_family; 2048fa20105eSGuy Shapiro struct net *net = listen_id->route.addr.dev_addr.net; 2049628e5f6dSSean Hefty int ret; 2050628e5f6dSSean Hefty 205100313983SSteve Wise listen_id_priv = container_of(listen_id, struct rdma_id_private, id); 205200313983SSteve Wise id = __rdma_create_id(net, listen_id->event_handler, listen_id->context, 205300313983SSteve Wise listen_id->ps, IB_QPT_UD, 205400313983SSteve Wise listen_id_priv->res.kern_name); 2055628e5f6dSSean Hefty if (IS_ERR(id)) 2056628e5f6dSSean Hefty return NULL; 2057628e5f6dSSean Hefty 2058f4753834SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 20590c505f70SHaggai Eran if (cma_save_net_info((struct sockaddr *)&id->route.addr.src_addr, 20600c505f70SHaggai Eran (struct sockaddr *)&id->route.addr.dst_addr, 20610c505f70SHaggai Eran listen_id, ib_event, ss_family, 20620c505f70SHaggai Eran ib_event->param.sidr_req_rcvd.service_id)) 2063628e5f6dSSean Hefty goto err; 2064628e5f6dSSean Hefty 20650b3ca768SHaggai Eran if (net_dev) { 206677addc52SParav Pandit rdma_copy_src_l2_addr(&id->route.addr.dev_addr, net_dev); 20670b3ca768SHaggai Eran } else { 2068b8cab5daSHaggai Eran if (!cma_any_addr(cma_src_addr(id_priv))) { 2069b8cab5daSHaggai Eran ret = cma_translate_addr(cma_src_addr(id_priv), 20700b3ca768SHaggai Eran &id->route.addr.dev_addr); 2071b8cab5daSHaggai Eran if (ret) 2072b8cab5daSHaggai Eran goto err; 2073b8cab5daSHaggai Eran } 20746f8372b6SSean Hefty } 2075628e5f6dSSean Hefty 2076550e5ca7SNir Muchtar id_priv->state = RDMA_CM_CONNECT; 2077628e5f6dSSean Hefty return id_priv; 2078628e5f6dSSean Hefty err: 2079628e5f6dSSean Hefty rdma_destroy_id(id); 2080628e5f6dSSean Hefty return NULL; 2081628e5f6dSSean Hefty } 2082628e5f6dSSean Hefty 2083a1b1b61fSSean Hefty static void cma_set_req_event_data(struct rdma_cm_event *event, 2084e7ff98aeSParav Pandit const struct ib_cm_req_event_param *req_data, 2085a1b1b61fSSean Hefty void *private_data, int offset) 2086a1b1b61fSSean Hefty { 2087a1b1b61fSSean Hefty event->param.conn.private_data = private_data + offset; 2088a1b1b61fSSean Hefty event->param.conn.private_data_len = IB_CM_REQ_PRIVATE_DATA_SIZE - offset; 2089a1b1b61fSSean Hefty event->param.conn.responder_resources = req_data->responder_resources; 2090a1b1b61fSSean Hefty event->param.conn.initiator_depth = req_data->initiator_depth; 2091a1b1b61fSSean Hefty event->param.conn.flow_control = req_data->flow_control; 2092a1b1b61fSSean Hefty event->param.conn.retry_count = req_data->retry_count; 2093a1b1b61fSSean Hefty event->param.conn.rnr_retry_count = req_data->rnr_retry_count; 2094a1b1b61fSSean Hefty event->param.conn.srq = req_data->srq; 2095a1b1b61fSSean Hefty event->param.conn.qp_num = req_data->remote_qpn; 2096a1b1b61fSSean Hefty } 2097a1b1b61fSSean Hefty 209885463316SParav Pandit static int cma_ib_check_req_qp_type(const struct rdma_cm_id *id, 2099e7ff98aeSParav Pandit const struct ib_cm_event *ib_event) 21009595480cSHefty, Sean { 21014dd81e89SSean Hefty return (((ib_event->event == IB_CM_REQ_RECEIVED) && 21029595480cSHefty, Sean (ib_event->param.req_rcvd.qp_type == id->qp_type)) || 21039595480cSHefty, Sean ((ib_event->event == IB_CM_SIDR_REQ_RECEIVED) && 21049595480cSHefty, Sean (id->qp_type == IB_QPT_UD)) || 21059595480cSHefty, Sean (!id->qp_type)); 21069595480cSHefty, Sean } 21079595480cSHefty, Sean 210885463316SParav Pandit static int cma_ib_req_handler(struct ib_cm_id *cm_id, 2109e7ff98aeSParav Pandit const struct ib_cm_event *ib_event) 2110e51060f0SSean Hefty { 211137e07cdaSBart Van Assche struct rdma_id_private *listen_id, *conn_id = NULL; 21127582df82SParav Pandit struct rdma_cm_event event = {}; 211341ab1cb7SParav Pandit struct cma_req_info req = {}; 21140b3ca768SHaggai Eran struct net_device *net_dev; 2115c0b64f58SBart Van Assche u8 offset; 2116c0b64f58SBart Van Assche int ret; 2117e51060f0SSean Hefty 211841ab1cb7SParav Pandit listen_id = cma_ib_id_from_event(cm_id, ib_event, &req, &net_dev); 21194c21b5bcSHaggai Eran if (IS_ERR(listen_id)) 21204c21b5bcSHaggai Eran return PTR_ERR(listen_id); 21214c21b5bcSHaggai Eran 212285463316SParav Pandit if (!cma_ib_check_req_qp_type(&listen_id->id, ib_event)) { 21230b3ca768SHaggai Eran ret = -EINVAL; 21240b3ca768SHaggai Eran goto net_dev_put; 21250b3ca768SHaggai Eran } 21269595480cSHefty, Sean 212737e07cdaSBart Van Assche mutex_lock(&listen_id->handler_mutex); 212837e07cdaSBart Van Assche if (listen_id->state != RDMA_CM_LISTEN) { 21290b3ca768SHaggai Eran ret = -ECONNABORTED; 213037e07cdaSBart Van Assche goto err1; 21310b3ca768SHaggai Eran } 2132e51060f0SSean Hefty 2133e8160e15SSean Hefty offset = cma_user_data_offset(listen_id); 2134628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_CONNECT_REQUEST; 21359595480cSHefty, Sean if (ib_event->event == IB_CM_SIDR_REQ_RECEIVED) { 213685463316SParav Pandit conn_id = cma_ib_new_udp_id(&listen_id->id, ib_event, net_dev); 2137628e5f6dSSean Hefty event.param.ud.private_data = ib_event->private_data + offset; 2138628e5f6dSSean Hefty event.param.ud.private_data_len = 2139628e5f6dSSean Hefty IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE - offset; 2140628e5f6dSSean Hefty } else { 214185463316SParav Pandit conn_id = cma_ib_new_conn_id(&listen_id->id, ib_event, net_dev); 2142628e5f6dSSean Hefty cma_set_req_event_data(&event, &ib_event->param.req_rcvd, 2143628e5f6dSSean Hefty ib_event->private_data, offset); 2144628e5f6dSSean Hefty } 2145e51060f0SSean Hefty if (!conn_id) { 2146e51060f0SSean Hefty ret = -ENOMEM; 2147b6cec8aaSSean Hefty goto err1; 2148e51060f0SSean Hefty } 2149e51060f0SSean Hefty 2150de910bd9SOr Gerlitz mutex_lock_nested(&conn_id->handler_mutex, SINGLE_DEPTH_NESTING); 215141ab1cb7SParav Pandit ret = cma_ib_acquire_dev(conn_id, listen_id, &req); 2152a1a733f6SKrishna Kumar if (ret) 2153b6cec8aaSSean Hefty goto err2; 2154e51060f0SSean Hefty 2155e51060f0SSean Hefty conn_id->cm_id.ib = cm_id; 2156e51060f0SSean Hefty cm_id->context = conn_id; 2157e51060f0SSean Hefty cm_id->cm_handler = cma_ib_handler; 2158e51060f0SSean Hefty 215925ae21a1SSean Hefty /* 216025ae21a1SSean Hefty * Protect against the user destroying conn_id from another thread 216125ae21a1SSean Hefty * until we're done accessing it. 216225ae21a1SSean Hefty */ 216325ae21a1SSean Hefty atomic_inc(&conn_id->refcount); 2164a1b1b61fSSean Hefty ret = conn_id->id.event_handler(&conn_id->id, &event); 2165b6cec8aaSSean Hefty if (ret) 2166b6cec8aaSSean Hefty goto err3; 2167ead595aeSSean Hefty /* 2168ead595aeSSean Hefty * Acquire mutex to prevent user executing rdma_destroy_id() 2169ead595aeSSean Hefty * while we're accessing the cm_id. 2170ead595aeSSean Hefty */ 2171ead595aeSSean Hefty mutex_lock(&lock); 2172dd5f03beSMatan Barak if (cma_comp(conn_id, RDMA_CM_CONNECT) && 2173dd5f03beSMatan Barak (conn_id->id.qp_type != IB_QPT_UD)) 2174ead595aeSSean Hefty ib_send_cm_mra(cm_id, CMA_CM_MRA_SETTING, NULL, 0); 2175ead595aeSSean Hefty mutex_unlock(&lock); 2176de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 2177b6cec8aaSSean Hefty mutex_unlock(&listen_id->handler_mutex); 217825ae21a1SSean Hefty cma_deref_id(conn_id); 21790b3ca768SHaggai Eran if (net_dev) 21800b3ca768SHaggai Eran dev_put(net_dev); 2181b6cec8aaSSean Hefty return 0; 2182a1a733f6SKrishna Kumar 2183b6cec8aaSSean Hefty err3: 2184b6cec8aaSSean Hefty cma_deref_id(conn_id); 2185e51060f0SSean Hefty /* Destroy the CM ID by returning a non-zero value. */ 2186e51060f0SSean Hefty conn_id->cm_id.ib = NULL; 2187b6cec8aaSSean Hefty err2: 2188550e5ca7SNir Muchtar cma_exch(conn_id, RDMA_CM_DESTROYING); 2189de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 2190b6cec8aaSSean Hefty err1: 2191de910bd9SOr Gerlitz mutex_unlock(&listen_id->handler_mutex); 2192b6cec8aaSSean Hefty if (conn_id) 2193b6cec8aaSSean Hefty rdma_destroy_id(&conn_id->id); 21940b3ca768SHaggai Eran 21950b3ca768SHaggai Eran net_dev_put: 21960b3ca768SHaggai Eran if (net_dev) 21970b3ca768SHaggai Eran dev_put(net_dev); 21980b3ca768SHaggai Eran 2199e51060f0SSean Hefty return ret; 2200e51060f0SSean Hefty } 2201e51060f0SSean Hefty 2202cf53936fSSean Hefty __be64 rdma_get_service_id(struct rdma_cm_id *id, struct sockaddr *addr) 2203e51060f0SSean Hefty { 2204496ce3ceSSean Hefty if (addr->sa_family == AF_IB) 2205496ce3ceSSean Hefty return ((struct sockaddr_ib *) addr)->sib_sid; 2206496ce3ceSSean Hefty 2207cf53936fSSean Hefty return cpu_to_be64(((u64)id->ps << 16) + be16_to_cpu(cma_port(addr))); 2208e51060f0SSean Hefty } 2209cf53936fSSean Hefty EXPORT_SYMBOL(rdma_get_service_id); 2210e51060f0SSean Hefty 2211411460acSParav Pandit void rdma_read_gids(struct rdma_cm_id *cm_id, union ib_gid *sgid, 2212411460acSParav Pandit union ib_gid *dgid) 2213411460acSParav Pandit { 2214411460acSParav Pandit struct rdma_addr *addr = &cm_id->route.addr; 2215411460acSParav Pandit 2216411460acSParav Pandit if (!cm_id->device) { 2217411460acSParav Pandit if (sgid) 2218411460acSParav Pandit memset(sgid, 0, sizeof(*sgid)); 2219411460acSParav Pandit if (dgid) 2220411460acSParav Pandit memset(dgid, 0, sizeof(*dgid)); 2221411460acSParav Pandit return; 2222411460acSParav Pandit } 2223411460acSParav Pandit 2224411460acSParav Pandit if (rdma_protocol_roce(cm_id->device, cm_id->port_num)) { 2225411460acSParav Pandit if (sgid) 2226411460acSParav Pandit rdma_ip2gid((struct sockaddr *)&addr->src_addr, sgid); 2227411460acSParav Pandit if (dgid) 2228411460acSParav Pandit rdma_ip2gid((struct sockaddr *)&addr->dst_addr, dgid); 2229411460acSParav Pandit } else { 2230411460acSParav Pandit if (sgid) 2231411460acSParav Pandit rdma_addr_get_sgid(&addr->dev_addr, sgid); 2232411460acSParav Pandit if (dgid) 2233411460acSParav Pandit rdma_addr_get_dgid(&addr->dev_addr, dgid); 2234411460acSParav Pandit } 2235411460acSParav Pandit } 2236411460acSParav Pandit EXPORT_SYMBOL(rdma_read_gids); 2237411460acSParav Pandit 223807ebafbaSTom Tucker static int cma_iw_handler(struct iw_cm_id *iw_id, struct iw_cm_event *iw_event) 223907ebafbaSTom Tucker { 224007ebafbaSTom Tucker struct rdma_id_private *id_priv = iw_id->context; 22417582df82SParav Pandit struct rdma_cm_event event = {}; 224207ebafbaSTom Tucker int ret = 0; 224324d44a39SSteve Wise struct sockaddr *laddr = (struct sockaddr *)&iw_event->local_addr; 224424d44a39SSteve Wise struct sockaddr *raddr = (struct sockaddr *)&iw_event->remote_addr; 224507ebafbaSTom Tucker 224637e07cdaSBart Van Assche mutex_lock(&id_priv->handler_mutex); 224737e07cdaSBart Van Assche if (id_priv->state != RDMA_CM_CONNECT) 224837e07cdaSBart Van Assche goto out; 224907ebafbaSTom Tucker 225007ebafbaSTom Tucker switch (iw_event->event) { 225107ebafbaSTom Tucker case IW_CM_EVENT_CLOSE: 2252a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_DISCONNECTED; 225307ebafbaSTom Tucker break; 225407ebafbaSTom Tucker case IW_CM_EVENT_CONNECT_REPLY: 225524d44a39SSteve Wise memcpy(cma_src_addr(id_priv), laddr, 225624d44a39SSteve Wise rdma_addr_size(laddr)); 225724d44a39SSteve Wise memcpy(cma_dst_addr(id_priv), raddr, 225824d44a39SSteve Wise rdma_addr_size(raddr)); 2259881a045fSSteve Wise switch (iw_event->status) { 2260881a045fSSteve Wise case 0: 2261a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_ESTABLISHED; 22623ebeebc3SKumar Sanghvi event.param.conn.initiator_depth = iw_event->ird; 22633ebeebc3SKumar Sanghvi event.param.conn.responder_resources = iw_event->ord; 226407ebafbaSTom Tucker break; 2265881a045fSSteve Wise case -ECONNRESET: 2266881a045fSSteve Wise case -ECONNREFUSED: 2267881a045fSSteve Wise event.event = RDMA_CM_EVENT_REJECTED; 2268881a045fSSteve Wise break; 2269881a045fSSteve Wise case -ETIMEDOUT: 2270881a045fSSteve Wise event.event = RDMA_CM_EVENT_UNREACHABLE; 2271881a045fSSteve Wise break; 2272881a045fSSteve Wise default: 2273881a045fSSteve Wise event.event = RDMA_CM_EVENT_CONNECT_ERROR; 2274881a045fSSteve Wise break; 2275881a045fSSteve Wise } 2276881a045fSSteve Wise break; 227707ebafbaSTom Tucker case IW_CM_EVENT_ESTABLISHED: 2278a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_ESTABLISHED; 22793ebeebc3SKumar Sanghvi event.param.conn.initiator_depth = iw_event->ird; 22803ebeebc3SKumar Sanghvi event.param.conn.responder_resources = iw_event->ord; 228107ebafbaSTom Tucker break; 228207ebafbaSTom Tucker default: 2283671a6cc2SLeon Romanovsky goto out; 228407ebafbaSTom Tucker } 228507ebafbaSTom Tucker 2286a1b1b61fSSean Hefty event.status = iw_event->status; 2287a1b1b61fSSean Hefty event.param.conn.private_data = iw_event->private_data; 2288a1b1b61fSSean Hefty event.param.conn.private_data_len = iw_event->private_data_len; 2289a1b1b61fSSean Hefty ret = id_priv->id.event_handler(&id_priv->id, &event); 229007ebafbaSTom Tucker if (ret) { 229107ebafbaSTom Tucker /* Destroy the CM ID by returning a non-zero value. */ 229207ebafbaSTom Tucker id_priv->cm_id.iw = NULL; 2293550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 2294de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 229507ebafbaSTom Tucker rdma_destroy_id(&id_priv->id); 229607ebafbaSTom Tucker return ret; 229707ebafbaSTom Tucker } 229807ebafbaSTom Tucker 229937e07cdaSBart Van Assche out: 2300de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 230107ebafbaSTom Tucker return ret; 230207ebafbaSTom Tucker } 230307ebafbaSTom Tucker 230407ebafbaSTom Tucker static int iw_conn_req_handler(struct iw_cm_id *cm_id, 230507ebafbaSTom Tucker struct iw_cm_event *iw_event) 230607ebafbaSTom Tucker { 230707ebafbaSTom Tucker struct rdma_cm_id *new_cm_id; 230807ebafbaSTom Tucker struct rdma_id_private *listen_id, *conn_id; 23097582df82SParav Pandit struct rdma_cm_event event = {}; 231037e07cdaSBart Van Assche int ret = -ECONNABORTED; 231124d44a39SSteve Wise struct sockaddr *laddr = (struct sockaddr *)&iw_event->local_addr; 231224d44a39SSteve Wise struct sockaddr *raddr = (struct sockaddr *)&iw_event->remote_addr; 231307ebafbaSTom Tucker 23147582df82SParav Pandit event.event = RDMA_CM_EVENT_CONNECT_REQUEST; 23157582df82SParav Pandit event.param.conn.private_data = iw_event->private_data; 23167582df82SParav Pandit event.param.conn.private_data_len = iw_event->private_data_len; 23177582df82SParav Pandit event.param.conn.initiator_depth = iw_event->ird; 23187582df82SParav Pandit event.param.conn.responder_resources = iw_event->ord; 23197582df82SParav Pandit 232007ebafbaSTom Tucker listen_id = cm_id->context; 232137e07cdaSBart Van Assche 232237e07cdaSBart Van Assche mutex_lock(&listen_id->handler_mutex); 232337e07cdaSBart Van Assche if (listen_id->state != RDMA_CM_LISTEN) 232437e07cdaSBart Van Assche goto out; 232507ebafbaSTom Tucker 232607ebafbaSTom Tucker /* Create a new RDMA id for the new IW CM ID */ 232700313983SSteve Wise new_cm_id = __rdma_create_id(listen_id->id.route.addr.dev_addr.net, 2328fa20105eSGuy Shapiro listen_id->id.event_handler, 232907ebafbaSTom Tucker listen_id->id.context, 233000313983SSteve Wise RDMA_PS_TCP, IB_QPT_RC, 233100313983SSteve Wise listen_id->res.kern_name); 233210f32065SJulia Lawall if (IS_ERR(new_cm_id)) { 233307ebafbaSTom Tucker ret = -ENOMEM; 233407ebafbaSTom Tucker goto out; 233507ebafbaSTom Tucker } 233607ebafbaSTom Tucker conn_id = container_of(new_cm_id, struct rdma_id_private, id); 2337de910bd9SOr Gerlitz mutex_lock_nested(&conn_id->handler_mutex, SINGLE_DEPTH_NESTING); 2338550e5ca7SNir Muchtar conn_id->state = RDMA_CM_CONNECT; 233907ebafbaSTom Tucker 2340575c7e58SParav Pandit ret = rdma_translate_ip(laddr, &conn_id->id.route.addr.dev_addr); 234107ebafbaSTom Tucker if (ret) { 2342de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 234307ebafbaSTom Tucker rdma_destroy_id(new_cm_id); 234407ebafbaSTom Tucker goto out; 234507ebafbaSTom Tucker } 234607ebafbaSTom Tucker 234741ab1cb7SParav Pandit ret = cma_iw_acquire_dev(conn_id, listen_id); 234807ebafbaSTom Tucker if (ret) { 2349de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 235007ebafbaSTom Tucker rdma_destroy_id(new_cm_id); 235107ebafbaSTom Tucker goto out; 235207ebafbaSTom Tucker } 235307ebafbaSTom Tucker 235407ebafbaSTom Tucker conn_id->cm_id.iw = cm_id; 235507ebafbaSTom Tucker cm_id->context = conn_id; 235607ebafbaSTom Tucker cm_id->cm_handler = cma_iw_handler; 235707ebafbaSTom Tucker 235824d44a39SSteve Wise memcpy(cma_src_addr(conn_id), laddr, rdma_addr_size(laddr)); 235924d44a39SSteve Wise memcpy(cma_dst_addr(conn_id), raddr, rdma_addr_size(raddr)); 236007ebafbaSTom Tucker 236125ae21a1SSean Hefty /* 236225ae21a1SSean Hefty * Protect against the user destroying conn_id from another thread 236325ae21a1SSean Hefty * until we're done accessing it. 236425ae21a1SSean Hefty */ 236525ae21a1SSean Hefty atomic_inc(&conn_id->refcount); 2366a1b1b61fSSean Hefty ret = conn_id->id.event_handler(&conn_id->id, &event); 236707ebafbaSTom Tucker if (ret) { 236807ebafbaSTom Tucker /* User wants to destroy the CM ID */ 236907ebafbaSTom Tucker conn_id->cm_id.iw = NULL; 2370550e5ca7SNir Muchtar cma_exch(conn_id, RDMA_CM_DESTROYING); 2371de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 237225ae21a1SSean Hefty cma_deref_id(conn_id); 237307ebafbaSTom Tucker rdma_destroy_id(&conn_id->id); 2374de910bd9SOr Gerlitz goto out; 237507ebafbaSTom Tucker } 237607ebafbaSTom Tucker 2377de910bd9SOr Gerlitz mutex_unlock(&conn_id->handler_mutex); 237825ae21a1SSean Hefty cma_deref_id(conn_id); 2379de910bd9SOr Gerlitz 238007ebafbaSTom Tucker out: 2381de910bd9SOr Gerlitz mutex_unlock(&listen_id->handler_mutex); 238207ebafbaSTom Tucker return ret; 238307ebafbaSTom Tucker } 238407ebafbaSTom Tucker 2385e51060f0SSean Hefty static int cma_ib_listen(struct rdma_id_private *id_priv) 2386e51060f0SSean Hefty { 2387e51060f0SSean Hefty struct sockaddr *addr; 23880c9361fcSJack Morgenstein struct ib_cm_id *id; 2389e51060f0SSean Hefty __be64 svc_id; 2390e51060f0SSean Hefty 2391f4753834SSean Hefty addr = cma_src_addr(id_priv); 2392cf53936fSSean Hefty svc_id = rdma_get_service_id(&id_priv->id, addr); 239385463316SParav Pandit id = ib_cm_insert_listen(id_priv->id.device, 239485463316SParav Pandit cma_ib_req_handler, svc_id); 239551efe394SHaggai Eran if (IS_ERR(id)) 239651efe394SHaggai Eran return PTR_ERR(id); 239751efe394SHaggai Eran id_priv->cm_id.ib = id; 2398e51060f0SSean Hefty 239951efe394SHaggai Eran return 0; 2400e51060f0SSean Hefty } 2401e51060f0SSean Hefty 240207ebafbaSTom Tucker static int cma_iw_listen(struct rdma_id_private *id_priv, int backlog) 240307ebafbaSTom Tucker { 240407ebafbaSTom Tucker int ret; 24050c9361fcSJack Morgenstein struct iw_cm_id *id; 240607ebafbaSTom Tucker 24070c9361fcSJack Morgenstein id = iw_create_cm_id(id_priv->id.device, 240807ebafbaSTom Tucker iw_conn_req_handler, 240907ebafbaSTom Tucker id_priv); 24100c9361fcSJack Morgenstein if (IS_ERR(id)) 24110c9361fcSJack Morgenstein return PTR_ERR(id); 24120c9361fcSJack Morgenstein 241368cdba06SSteve Wise id->tos = id_priv->tos; 2414926ba19bSSteve Wise id->tos_set = id_priv->tos_set; 24150c9361fcSJack Morgenstein id_priv->cm_id.iw = id; 241607ebafbaSTom Tucker 241724d44a39SSteve Wise memcpy(&id_priv->cm_id.iw->local_addr, cma_src_addr(id_priv), 241824d44a39SSteve Wise rdma_addr_size(cma_src_addr(id_priv))); 241907ebafbaSTom Tucker 242007ebafbaSTom Tucker ret = iw_cm_listen(id_priv->cm_id.iw, backlog); 242107ebafbaSTom Tucker 242207ebafbaSTom Tucker if (ret) { 242307ebafbaSTom Tucker iw_destroy_cm_id(id_priv->cm_id.iw); 242407ebafbaSTom Tucker id_priv->cm_id.iw = NULL; 242507ebafbaSTom Tucker } 242607ebafbaSTom Tucker 242707ebafbaSTom Tucker return ret; 242807ebafbaSTom Tucker } 242907ebafbaSTom Tucker 2430e51060f0SSean Hefty static int cma_listen_handler(struct rdma_cm_id *id, 2431e51060f0SSean Hefty struct rdma_cm_event *event) 2432e51060f0SSean Hefty { 2433e51060f0SSean Hefty struct rdma_id_private *id_priv = id->context; 2434e51060f0SSean Hefty 2435e51060f0SSean Hefty id->context = id_priv->id.context; 2436e51060f0SSean Hefty id->event_handler = id_priv->id.event_handler; 2437e51060f0SSean Hefty return id_priv->id.event_handler(id, event); 2438e51060f0SSean Hefty } 2439e51060f0SSean Hefty 2440e51060f0SSean Hefty static void cma_listen_on_dev(struct rdma_id_private *id_priv, 2441e51060f0SSean Hefty struct cma_device *cma_dev) 2442e51060f0SSean Hefty { 2443e51060f0SSean Hefty struct rdma_id_private *dev_id_priv; 2444e51060f0SSean Hefty struct rdma_cm_id *id; 2445fa20105eSGuy Shapiro struct net *net = id_priv->id.route.addr.dev_addr.net; 2446e51060f0SSean Hefty int ret; 2447e51060f0SSean Hefty 244872219ceaSMichael Wang if (cma_family(id_priv) == AF_IB && !rdma_cap_ib_cm(cma_dev->device, 1)) 244994d0c939SSean Hefty return; 245094d0c939SSean Hefty 245100313983SSteve Wise id = __rdma_create_id(net, cma_listen_handler, id_priv, id_priv->id.ps, 245200313983SSteve Wise id_priv->id.qp_type, id_priv->res.kern_name); 2453e51060f0SSean Hefty if (IS_ERR(id)) 2454e51060f0SSean Hefty return; 2455e51060f0SSean Hefty 2456e51060f0SSean Hefty dev_id_priv = container_of(id, struct rdma_id_private, id); 2457e51060f0SSean Hefty 2458550e5ca7SNir Muchtar dev_id_priv->state = RDMA_CM_ADDR_BOUND; 2459f4753834SSean Hefty memcpy(cma_src_addr(dev_id_priv), cma_src_addr(id_priv), 2460f4753834SSean Hefty rdma_addr_size(cma_src_addr(id_priv))); 2461e51060f0SSean Hefty 2462045959dbSMatan Barak _cma_attach_to_dev(dev_id_priv, cma_dev); 2463e51060f0SSean Hefty list_add_tail(&dev_id_priv->listen_list, &id_priv->listen_list); 2464d02d1f53SSean Hefty atomic_inc(&id_priv->refcount); 2465d02d1f53SSean Hefty dev_id_priv->internal_id = 1; 24665b0ec991SSean Hefty dev_id_priv->afonly = id_priv->afonly; 24679491128fSSteve Wise dev_id_priv->tos_set = id_priv->tos_set; 24689491128fSSteve Wise dev_id_priv->tos = id_priv->tos; 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 24972c1619edSDanit Goldberg /** 24982c1619edSDanit Goldberg * rdma_set_ack_timeout() - Set the ack timeout of QP associated 24992c1619edSDanit Goldberg * with a connection identifier. 25002c1619edSDanit Goldberg * @id: Communication identifier to associated with service type. 25012c1619edSDanit Goldberg * @timeout: Ack timeout to set a QP, expressed as 4.096 * 2^(timeout) usec. 25022c1619edSDanit Goldberg * 25032c1619edSDanit Goldberg * This function should be called before rdma_connect() on active side, 25042c1619edSDanit Goldberg * and on passive side before rdma_accept(). It is applicable to primary 25052c1619edSDanit Goldberg * path only. The timeout will affect the local side of the QP, it is not 25062c1619edSDanit Goldberg * negotiated with remote side and zero disables the timer. 25072c1619edSDanit Goldberg * 25082c1619edSDanit Goldberg * Return: 0 for success 25092c1619edSDanit Goldberg */ 25102c1619edSDanit Goldberg int rdma_set_ack_timeout(struct rdma_cm_id *id, u8 timeout) 25112c1619edSDanit Goldberg { 25122c1619edSDanit Goldberg struct rdma_id_private *id_priv; 25132c1619edSDanit Goldberg 25142c1619edSDanit Goldberg if (id->qp_type != IB_QPT_RC) 25152c1619edSDanit Goldberg return -EINVAL; 25162c1619edSDanit Goldberg 25172c1619edSDanit Goldberg id_priv = container_of(id, struct rdma_id_private, id); 25182c1619edSDanit Goldberg id_priv->timeout = timeout; 25192c1619edSDanit Goldberg id_priv->timeout_set = true; 25202c1619edSDanit Goldberg 25212c1619edSDanit Goldberg return 0; 25222c1619edSDanit Goldberg } 25232c1619edSDanit Goldberg EXPORT_SYMBOL(rdma_set_ack_timeout); 25242c1619edSDanit 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 2803d3bd9396SParav Pandit static int get_vlan_ndev_tc(struct net_device *vlan_ndev, int prio) 2804eb072c4bSEyal Perry { 2805eb072c4bSEyal Perry struct net_device *dev; 2806eb072c4bSEyal Perry 2807d3bd9396SParav Pandit dev = vlan_dev_real_dev(vlan_ndev); 2808eb072c4bSEyal Perry if (dev->num_tc) 2809eb072c4bSEyal Perry return netdev_get_prio_tc_map(dev, prio); 2810eb072c4bSEyal Perry 2811d3bd9396SParav Pandit return (vlan_dev_get_egress_qos_mask(vlan_ndev, prio) & 2812eb072c4bSEyal Perry VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; 2813d3bd9396SParav Pandit } 2814d3bd9396SParav Pandit 2815d3bd9396SParav Pandit struct iboe_prio_tc_map { 2816d3bd9396SParav Pandit int input_prio; 2817d3bd9396SParav Pandit int output_tc; 2818d3bd9396SParav Pandit bool found; 2819d3bd9396SParav Pandit }; 2820d3bd9396SParav Pandit 2821d3bd9396SParav Pandit static int get_lower_vlan_dev_tc(struct net_device *dev, void *data) 2822d3bd9396SParav Pandit { 2823d3bd9396SParav Pandit struct iboe_prio_tc_map *map = data; 2824d3bd9396SParav Pandit 2825d3bd9396SParav Pandit if (is_vlan_dev(dev)) 2826d3bd9396SParav Pandit map->output_tc = get_vlan_ndev_tc(dev, map->input_prio); 2827d3bd9396SParav Pandit else if (dev->num_tc) 2828d3bd9396SParav Pandit map->output_tc = netdev_get_prio_tc_map(dev, map->input_prio); 2829d3bd9396SParav Pandit else 2830d3bd9396SParav Pandit map->output_tc = 0; 2831d3bd9396SParav Pandit /* We are interested only in first level VLAN device, so always 2832d3bd9396SParav Pandit * return 1 to stop iterating over next level devices. 2833d3bd9396SParav Pandit */ 2834d3bd9396SParav Pandit map->found = true; 2835d3bd9396SParav Pandit return 1; 2836d3bd9396SParav Pandit } 2837d3bd9396SParav Pandit 2838d3bd9396SParav Pandit static int iboe_tos_to_sl(struct net_device *ndev, int tos) 2839d3bd9396SParav Pandit { 2840d3bd9396SParav Pandit struct iboe_prio_tc_map prio_tc_map = {}; 2841d3bd9396SParav Pandit int prio = rt_tos2priority(tos); 2842d3bd9396SParav Pandit 2843d3bd9396SParav Pandit /* If VLAN device, get it directly from the VLAN netdev */ 2844d3bd9396SParav Pandit if (is_vlan_dev(ndev)) 2845d3bd9396SParav Pandit return get_vlan_ndev_tc(ndev, prio); 2846d3bd9396SParav Pandit 2847d3bd9396SParav Pandit prio_tc_map.input_prio = prio; 2848d3bd9396SParav Pandit rcu_read_lock(); 2849d3bd9396SParav Pandit netdev_walk_all_lower_dev_rcu(ndev, 2850d3bd9396SParav Pandit get_lower_vlan_dev_tc, 2851d3bd9396SParav Pandit &prio_tc_map); 2852d3bd9396SParav Pandit rcu_read_unlock(); 2853d3bd9396SParav Pandit /* If map is found from lower device, use it; Otherwise 2854d3bd9396SParav Pandit * continue with the current netdevice to get priority to tc map. 2855d3bd9396SParav Pandit */ 2856d3bd9396SParav Pandit if (prio_tc_map.found) 2857d3bd9396SParav Pandit return prio_tc_map.output_tc; 2858d3bd9396SParav Pandit else if (ndev->num_tc) 2859d3bd9396SParav Pandit return netdev_get_prio_tc_map(ndev, prio); 2860d3bd9396SParav Pandit else 2861eb072c4bSEyal Perry return 0; 2862eb072c4bSEyal Perry } 2863eb072c4bSEyal Perry 28643c86aa70SEli Cohen static int cma_resolve_iboe_route(struct rdma_id_private *id_priv) 28653c86aa70SEli Cohen { 28663c86aa70SEli Cohen struct rdma_route *route = &id_priv->id.route; 28673c86aa70SEli Cohen struct rdma_addr *addr = &route->addr; 28683c86aa70SEli Cohen struct cma_work *work; 28693c86aa70SEli Cohen int ret; 28704367ec7fSParav Pandit struct net_device *ndev; 28714367ec7fSParav Pandit 287289052d78SMajd Dibbiny u8 default_roce_tos = id_priv->cma_dev->default_roce_tos[id_priv->id.port_num - 287389052d78SMajd Dibbiny rdma_start_port(id_priv->cma_dev->device)]; 287489052d78SMajd Dibbiny u8 tos = id_priv->tos_set ? id_priv->tos : default_roce_tos; 2875dd5f03beSMatan Barak 28763c86aa70SEli Cohen 28773c86aa70SEli Cohen work = kzalloc(sizeof *work, GFP_KERNEL); 28783c86aa70SEli Cohen if (!work) 28793c86aa70SEli Cohen return -ENOMEM; 28803c86aa70SEli Cohen 28813c86aa70SEli Cohen route->path_rec = kzalloc(sizeof *route->path_rec, GFP_KERNEL); 28823c86aa70SEli Cohen if (!route->path_rec) { 28833c86aa70SEli Cohen ret = -ENOMEM; 28843c86aa70SEli Cohen goto err1; 28853c86aa70SEli Cohen } 28863c86aa70SEli Cohen 28873c86aa70SEli Cohen route->num_paths = 1; 28883c86aa70SEli Cohen 28899327c7afSParav Pandit ndev = cma_iboe_set_path_rec_l2_fields(id_priv); 289023d70503SWei Yongjun if (!ndev) { 289123d70503SWei Yongjun ret = -ENODEV; 289223d70503SWei Yongjun goto err2; 289323d70503SWei Yongjun } 289420029832SMatan Barak 28957b85627bSMoni Shoua rdma_ip2gid((struct sockaddr *)&id_priv->id.route.addr.src_addr, 28967b85627bSMoni Shoua &route->path_rec->sgid); 28977b85627bSMoni Shoua rdma_ip2gid((struct sockaddr *)&id_priv->id.route.addr.dst_addr, 28987b85627bSMoni Shoua &route->path_rec->dgid); 2899af7bd463SEli Cohen 2900c3efe750SMatan Barak if (((struct sockaddr *)&id_priv->id.route.addr.dst_addr)->sa_family != AF_IB) 2901c865f246SSomnath Kotur /* TODO: get the hoplimit from the inet/inet6 device */ 2902c3efe750SMatan Barak route->path_rec->hop_limit = addr->dev_addr.hoplimit; 2903c3efe750SMatan Barak else 2904af7bd463SEli Cohen route->path_rec->hop_limit = 1; 2905af7bd463SEli Cohen route->path_rec->reversible = 1; 2906af7bd463SEli Cohen route->path_rec->pkey = cpu_to_be16(0xffff); 2907af7bd463SEli Cohen route->path_rec->mtu_selector = IB_SA_EQ; 290889052d78SMajd Dibbiny route->path_rec->sl = iboe_tos_to_sl(ndev, tos); 290989052d78SMajd Dibbiny route->path_rec->traffic_class = tos; 29103c86aa70SEli Cohen route->path_rec->mtu = iboe_get_mtu(ndev->mtu); 29113c86aa70SEli Cohen route->path_rec->rate_selector = IB_SA_EQ; 29123c86aa70SEli Cohen route->path_rec->rate = iboe_get_rate(ndev); 29133c86aa70SEli Cohen dev_put(ndev); 29143c86aa70SEli Cohen route->path_rec->packet_life_time_selector = IB_SA_EQ; 29153c86aa70SEli Cohen route->path_rec->packet_life_time = CMA_IBOE_PACKET_LIFETIME; 29163c86aa70SEli Cohen if (!route->path_rec->mtu) { 29173c86aa70SEli Cohen ret = -EINVAL; 29183c86aa70SEli Cohen goto err2; 29193c86aa70SEli Cohen } 29203c86aa70SEli Cohen 2921981b5a23SParav Pandit cma_init_resolve_route_work(work, id_priv); 29223c86aa70SEli Cohen queue_work(cma_wq, &work->work); 29233c86aa70SEli Cohen 29243c86aa70SEli Cohen return 0; 29253c86aa70SEli Cohen 29263c86aa70SEli Cohen err2: 29273c86aa70SEli Cohen kfree(route->path_rec); 29283c86aa70SEli Cohen route->path_rec = NULL; 29293c86aa70SEli Cohen err1: 29303c86aa70SEli Cohen kfree(work); 29313c86aa70SEli Cohen return ret; 29323c86aa70SEli Cohen } 29333c86aa70SEli Cohen 2934dbace111SLeon Romanovsky int rdma_resolve_route(struct rdma_cm_id *id, unsigned long timeout_ms) 2935e51060f0SSean Hefty { 2936e51060f0SSean Hefty struct rdma_id_private *id_priv; 2937e51060f0SSean Hefty int ret; 2938e51060f0SSean Hefty 2939e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 2940550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED, RDMA_CM_ROUTE_QUERY)) 2941e51060f0SSean Hefty return -EINVAL; 2942e51060f0SSean Hefty 2943e51060f0SSean Hefty atomic_inc(&id_priv->refcount); 2944fe53ba2fSMichael Wang if (rdma_cap_ib_sa(id->device, id->port_num)) 2945e51060f0SSean Hefty ret = cma_resolve_ib_route(id_priv, timeout_ms); 29465d9fb044SIra Weiny else if (rdma_protocol_roce(id->device, id->port_num)) 29473c86aa70SEli Cohen ret = cma_resolve_iboe_route(id_priv); 2948c72f2189SMichael Wang else if (rdma_protocol_iwarp(id->device, id->port_num)) 2949d6f91252SLeon Romanovsky ret = cma_resolve_iw_route(id_priv); 2950c72f2189SMichael Wang else 2951e51060f0SSean Hefty ret = -ENOSYS; 2952c72f2189SMichael Wang 2953e51060f0SSean Hefty if (ret) 2954e51060f0SSean Hefty goto err; 2955e51060f0SSean Hefty 2956e51060f0SSean Hefty return 0; 2957e51060f0SSean Hefty err: 2958550e5ca7SNir Muchtar cma_comp_exch(id_priv, RDMA_CM_ROUTE_QUERY, RDMA_CM_ADDR_RESOLVED); 2959e51060f0SSean Hefty cma_deref_id(id_priv); 2960e51060f0SSean Hefty return ret; 2961e51060f0SSean Hefty } 2962e51060f0SSean Hefty EXPORT_SYMBOL(rdma_resolve_route); 2963e51060f0SSean Hefty 29646a3e362dSSean Hefty static void cma_set_loopback(struct sockaddr *addr) 29656a3e362dSSean Hefty { 29666a3e362dSSean Hefty switch (addr->sa_family) { 29676a3e362dSSean Hefty case AF_INET: 29686a3e362dSSean Hefty ((struct sockaddr_in *) addr)->sin_addr.s_addr = htonl(INADDR_LOOPBACK); 29696a3e362dSSean Hefty break; 29706a3e362dSSean Hefty case AF_INET6: 29716a3e362dSSean Hefty ipv6_addr_set(&((struct sockaddr_in6 *) addr)->sin6_addr, 29726a3e362dSSean Hefty 0, 0, 0, htonl(1)); 29736a3e362dSSean Hefty break; 29746a3e362dSSean Hefty default: 29756a3e362dSSean Hefty ib_addr_set(&((struct sockaddr_ib *) addr)->sib_addr, 29766a3e362dSSean Hefty 0, 0, 0, htonl(1)); 29776a3e362dSSean Hefty break; 29786a3e362dSSean Hefty } 29796a3e362dSSean Hefty } 29806a3e362dSSean Hefty 2981e51060f0SSean Hefty static int cma_bind_loopback(struct rdma_id_private *id_priv) 2982e51060f0SSean Hefty { 2983b0569e40SSean Hefty struct cma_device *cma_dev, *cur_dev; 2984f0ee3404SMichael S. Tsirkin union ib_gid gid; 2985102c5ce0SJack Wang enum ib_port_state port_state; 2986e51060f0SSean Hefty u16 pkey; 2987e51060f0SSean Hefty int ret; 2988e51060f0SSean Hefty u8 p; 2989e51060f0SSean Hefty 2990b0569e40SSean Hefty cma_dev = NULL; 2991e51060f0SSean Hefty mutex_lock(&lock); 2992b0569e40SSean Hefty list_for_each_entry(cur_dev, &dev_list, list) { 2993b0569e40SSean Hefty if (cma_family(id_priv) == AF_IB && 299472219ceaSMichael Wang !rdma_cap_ib_cm(cur_dev->device, 1)) 2995b0569e40SSean Hefty continue; 2996b0569e40SSean Hefty 2997b0569e40SSean Hefty if (!cma_dev) 2998b0569e40SSean Hefty cma_dev = cur_dev; 2999b0569e40SSean Hefty 3000b0569e40SSean Hefty for (p = 1; p <= cur_dev->device->phys_port_cnt; ++p) { 3001102c5ce0SJack Wang if (!ib_get_cached_port_state(cur_dev->device, p, &port_state) && 3002102c5ce0SJack Wang port_state == IB_PORT_ACTIVE) { 3003b0569e40SSean Hefty cma_dev = cur_dev; 3004b0569e40SSean Hefty goto port_found; 3005b0569e40SSean Hefty } 3006b0569e40SSean Hefty } 3007b0569e40SSean Hefty } 3008b0569e40SSean Hefty 3009b0569e40SSean Hefty if (!cma_dev) { 3010e82153b5SKrishna Kumar ret = -ENODEV; 3011e82153b5SKrishna Kumar goto out; 3012e82153b5SKrishna Kumar } 3013e51060f0SSean Hefty 3014e51060f0SSean Hefty p = 1; 3015e51060f0SSean Hefty 3016e51060f0SSean Hefty port_found: 30171dfce294SParav Pandit ret = rdma_query_gid(cma_dev->device, p, 0, &gid); 3018e51060f0SSean Hefty if (ret) 3019e51060f0SSean Hefty goto out; 3020e51060f0SSean Hefty 3021e51060f0SSean Hefty ret = ib_get_cached_pkey(cma_dev->device, p, 0, &pkey); 3022e51060f0SSean Hefty if (ret) 3023e51060f0SSean Hefty goto out; 3024e51060f0SSean Hefty 30256f8372b6SSean Hefty id_priv->id.route.addr.dev_addr.dev_type = 302621655afcSMichael Wang (rdma_protocol_ib(cma_dev->device, p)) ? 30276f8372b6SSean Hefty ARPHRD_INFINIBAND : ARPHRD_ETHER; 30286f8372b6SSean Hefty 30296f8372b6SSean Hefty rdma_addr_set_sgid(&id_priv->id.route.addr.dev_addr, &gid); 3030e51060f0SSean Hefty ib_addr_set_pkey(&id_priv->id.route.addr.dev_addr, pkey); 3031e51060f0SSean Hefty id_priv->id.port_num = p; 3032e51060f0SSean Hefty cma_attach_to_dev(id_priv, cma_dev); 3033f4753834SSean Hefty cma_set_loopback(cma_src_addr(id_priv)); 3034e51060f0SSean Hefty out: 3035e51060f0SSean Hefty mutex_unlock(&lock); 3036e51060f0SSean Hefty return ret; 3037e51060f0SSean Hefty } 3038e51060f0SSean Hefty 3039e51060f0SSean Hefty static void addr_handler(int status, struct sockaddr *src_addr, 3040e51060f0SSean Hefty struct rdma_dev_addr *dev_addr, void *context) 3041e51060f0SSean Hefty { 3042e51060f0SSean Hefty struct rdma_id_private *id_priv = context; 30437582df82SParav Pandit struct rdma_cm_event event = {}; 30445fc01fb8SMyungho Jung struct sockaddr *addr; 30455fc01fb8SMyungho Jung struct sockaddr_storage old_addr; 3046e51060f0SSean Hefty 3047de910bd9SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 3048550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_QUERY, 3049550e5ca7SNir Muchtar RDMA_CM_ADDR_RESOLVED)) 305061a73c70SSean Hefty goto out; 305161a73c70SSean Hefty 30525fc01fb8SMyungho Jung /* 30535fc01fb8SMyungho Jung * Store the previous src address, so that if we fail to acquire 30545fc01fb8SMyungho Jung * matching rdma device, old address can be restored back, which helps 30555fc01fb8SMyungho Jung * to cancel the cma listen operation correctly. 30565fc01fb8SMyungho Jung */ 30575fc01fb8SMyungho Jung addr = cma_src_addr(id_priv); 30585fc01fb8SMyungho Jung memcpy(&old_addr, addr, rdma_addr_size(addr)); 30595fc01fb8SMyungho Jung memcpy(addr, src_addr, rdma_addr_size(src_addr)); 3060498683c6SMoni Shoua if (!status && !id_priv->cma_dev) { 3061ff11c6cdSParav Pandit status = cma_acquire_dev_by_src_ip(id_priv); 3062498683c6SMoni Shoua if (status) 3063498683c6SMoni Shoua pr_debug_ratelimited("RDMA CM: ADDR_ERROR: failed to acquire device. status %d\n", 3064498683c6SMoni Shoua status); 3065a6e4d254SHåkon Bugge } else if (status) { 3066498683c6SMoni Shoua pr_debug_ratelimited("RDMA CM: ADDR_ERROR: failed to resolve IP. status %d\n", status); 3067498683c6SMoni Shoua } 3068e51060f0SSean Hefty 3069e51060f0SSean Hefty if (status) { 30705fc01fb8SMyungho Jung memcpy(addr, &old_addr, 30715fc01fb8SMyungho Jung rdma_addr_size((struct sockaddr *)&old_addr)); 3072550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED, 3073550e5ca7SNir Muchtar RDMA_CM_ADDR_BOUND)) 3074e51060f0SSean Hefty goto out; 3075a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_ADDR_ERROR; 3076a1b1b61fSSean Hefty event.status = status; 30777b85627bSMoni Shoua } else 3078a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_ADDR_RESOLVED; 3079e51060f0SSean Hefty 3080a1b1b61fSSean Hefty if (id_priv->id.event_handler(&id_priv->id, &event)) { 3081550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 3082de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 3083e51060f0SSean Hefty rdma_destroy_id(&id_priv->id); 3084e51060f0SSean Hefty return; 3085e51060f0SSean Hefty } 3086e51060f0SSean Hefty out: 3087de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 3088e51060f0SSean Hefty } 3089e51060f0SSean Hefty 3090e51060f0SSean Hefty static int cma_resolve_loopback(struct rdma_id_private *id_priv) 3091e51060f0SSean Hefty { 3092e51060f0SSean Hefty struct cma_work *work; 3093f0ee3404SMichael S. Tsirkin union ib_gid gid; 3094e51060f0SSean Hefty int ret; 3095e51060f0SSean Hefty 3096e51060f0SSean Hefty work = kzalloc(sizeof *work, GFP_KERNEL); 3097e51060f0SSean Hefty if (!work) 3098e51060f0SSean Hefty return -ENOMEM; 3099e51060f0SSean Hefty 3100e51060f0SSean Hefty if (!id_priv->cma_dev) { 3101e51060f0SSean Hefty ret = cma_bind_loopback(id_priv); 3102e51060f0SSean Hefty if (ret) 3103e51060f0SSean Hefty goto err; 3104e51060f0SSean Hefty } 3105e51060f0SSean Hefty 31066f8372b6SSean Hefty rdma_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid); 31076f8372b6SSean Hefty rdma_addr_set_dgid(&id_priv->id.route.addr.dev_addr, &gid); 3108e51060f0SSean Hefty 3109981b5a23SParav Pandit cma_init_resolve_addr_work(work, id_priv); 3110e51060f0SSean Hefty queue_work(cma_wq, &work->work); 3111e51060f0SSean Hefty return 0; 3112e51060f0SSean Hefty err: 3113e51060f0SSean Hefty kfree(work); 3114e51060f0SSean Hefty return ret; 3115e51060f0SSean Hefty } 3116e51060f0SSean Hefty 3117f17df3b0SSean Hefty static int cma_resolve_ib_addr(struct rdma_id_private *id_priv) 3118f17df3b0SSean Hefty { 3119f17df3b0SSean Hefty struct cma_work *work; 3120f17df3b0SSean Hefty int ret; 3121f17df3b0SSean Hefty 3122f17df3b0SSean Hefty work = kzalloc(sizeof *work, GFP_KERNEL); 3123f17df3b0SSean Hefty if (!work) 3124f17df3b0SSean Hefty return -ENOMEM; 3125f17df3b0SSean Hefty 3126f17df3b0SSean Hefty if (!id_priv->cma_dev) { 3127f17df3b0SSean Hefty ret = cma_resolve_ib_dev(id_priv); 3128f17df3b0SSean Hefty if (ret) 3129f17df3b0SSean Hefty goto err; 3130f17df3b0SSean Hefty } 3131f17df3b0SSean Hefty 3132f17df3b0SSean Hefty rdma_addr_set_dgid(&id_priv->id.route.addr.dev_addr, (union ib_gid *) 3133f17df3b0SSean Hefty &(((struct sockaddr_ib *) &id_priv->id.route.addr.dst_addr)->sib_addr)); 3134f17df3b0SSean Hefty 3135981b5a23SParav Pandit cma_init_resolve_addr_work(work, id_priv); 3136f17df3b0SSean Hefty queue_work(cma_wq, &work->work); 3137f17df3b0SSean Hefty return 0; 3138f17df3b0SSean Hefty err: 3139f17df3b0SSean Hefty kfree(work); 3140f17df3b0SSean Hefty return ret; 3141f17df3b0SSean Hefty } 3142f17df3b0SSean Hefty 3143e51060f0SSean Hefty static int cma_bind_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, 31442df7dba8SParav Pandit const struct sockaddr *dst_addr) 3145e51060f0SSean Hefty { 3146d14714dfSSean Hefty if (!src_addr || !src_addr->sa_family) { 3147d14714dfSSean Hefty src_addr = (struct sockaddr *) &id->route.addr.src_addr; 3148f17df3b0SSean Hefty src_addr->sa_family = dst_addr->sa_family; 3149b4cfe397SJack Morgenstein if (IS_ENABLED(CONFIG_IPV6) && 3150b4cfe397SJack Morgenstein dst_addr->sa_family == AF_INET6) { 31516c26a771SSpencer Baugh struct sockaddr_in6 *src_addr6 = (struct sockaddr_in6 *) src_addr; 31526c26a771SSpencer Baugh struct sockaddr_in6 *dst_addr6 = (struct sockaddr_in6 *) dst_addr; 31536c26a771SSpencer Baugh src_addr6->sin6_scope_id = dst_addr6->sin6_scope_id; 31546c26a771SSpencer Baugh if (ipv6_addr_type(&dst_addr6->sin6_addr) & IPV6_ADDR_LINKLOCAL) 31556c26a771SSpencer Baugh id->route.addr.dev_addr.bound_dev_if = dst_addr6->sin6_scope_id; 3156f17df3b0SSean Hefty } else if (dst_addr->sa_family == AF_IB) { 3157f17df3b0SSean Hefty ((struct sockaddr_ib *) src_addr)->sib_pkey = 3158f17df3b0SSean Hefty ((struct sockaddr_ib *) dst_addr)->sib_pkey; 3159d14714dfSSean Hefty } 3160d14714dfSSean Hefty } 3161e51060f0SSean Hefty return rdma_bind_addr(id, src_addr); 3162e51060f0SSean Hefty } 3163e51060f0SSean Hefty 3164e51060f0SSean Hefty int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, 3165dbace111SLeon Romanovsky const struct sockaddr *dst_addr, unsigned long timeout_ms) 3166e51060f0SSean Hefty { 3167e51060f0SSean Hefty struct rdma_id_private *id_priv; 3168e51060f0SSean Hefty int ret; 3169e51060f0SSean Hefty 3170e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 3171550e5ca7SNir Muchtar if (id_priv->state == RDMA_CM_IDLE) { 3172e51060f0SSean Hefty ret = cma_bind_addr(id, src_addr, dst_addr); 3173219d2e9dSParav Pandit if (ret) 3174e51060f0SSean Hefty return ret; 3175e51060f0SSean Hefty } 3176e51060f0SSean Hefty 3177219d2e9dSParav Pandit if (cma_family(id_priv) != dst_addr->sa_family) 31784ae7152eSSean Hefty return -EINVAL; 31794ae7152eSSean Hefty 3180219d2e9dSParav Pandit if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_ADDR_QUERY)) 3181e51060f0SSean Hefty return -EINVAL; 3182e51060f0SSean Hefty 3183219d2e9dSParav Pandit memcpy(cma_dst_addr(id_priv), dst_addr, rdma_addr_size(dst_addr)); 3184f17df3b0SSean Hefty if (cma_any_addr(dst_addr)) { 3185e51060f0SSean Hefty ret = cma_resolve_loopback(id_priv); 3186f17df3b0SSean Hefty } else { 3187f17df3b0SSean Hefty if (dst_addr->sa_family == AF_IB) { 3188f17df3b0SSean Hefty ret = cma_resolve_ib_addr(id_priv); 3189f17df3b0SSean Hefty } else { 31900e9d2c19SParav Pandit ret = rdma_resolve_ip(cma_src_addr(id_priv), dst_addr, 31910e9d2c19SParav Pandit &id->route.addr.dev_addr, 31920e9d2c19SParav Pandit timeout_ms, addr_handler, 31930e9d2c19SParav Pandit false, id_priv); 3194f17df3b0SSean Hefty } 3195f17df3b0SSean Hefty } 3196e51060f0SSean Hefty if (ret) 3197e51060f0SSean Hefty goto err; 3198e51060f0SSean Hefty 3199e51060f0SSean Hefty return 0; 3200e51060f0SSean Hefty err: 3201550e5ca7SNir Muchtar cma_comp_exch(id_priv, RDMA_CM_ADDR_QUERY, RDMA_CM_ADDR_BOUND); 3202e51060f0SSean Hefty return ret; 3203e51060f0SSean Hefty } 3204e51060f0SSean Hefty EXPORT_SYMBOL(rdma_resolve_addr); 3205e51060f0SSean Hefty 3206a9bb7912SHefty, Sean int rdma_set_reuseaddr(struct rdma_cm_id *id, int reuse) 3207a9bb7912SHefty, Sean { 3208a9bb7912SHefty, Sean struct rdma_id_private *id_priv; 3209a9bb7912SHefty, Sean unsigned long flags; 3210a9bb7912SHefty, Sean int ret; 3211a9bb7912SHefty, Sean 3212a9bb7912SHefty, Sean id_priv = container_of(id, struct rdma_id_private, id); 3213a9bb7912SHefty, Sean spin_lock_irqsave(&id_priv->lock, flags); 3214c8dea2f9SSean Hefty if (reuse || id_priv->state == RDMA_CM_IDLE) { 3215a9bb7912SHefty, Sean id_priv->reuseaddr = reuse; 3216a9bb7912SHefty, Sean ret = 0; 3217a9bb7912SHefty, Sean } else { 3218a9bb7912SHefty, Sean ret = -EINVAL; 3219a9bb7912SHefty, Sean } 3220a9bb7912SHefty, Sean spin_unlock_irqrestore(&id_priv->lock, flags); 3221a9bb7912SHefty, Sean return ret; 3222a9bb7912SHefty, Sean } 3223a9bb7912SHefty, Sean EXPORT_SYMBOL(rdma_set_reuseaddr); 3224a9bb7912SHefty, Sean 322568602120SSean Hefty int rdma_set_afonly(struct rdma_cm_id *id, int afonly) 322668602120SSean Hefty { 322768602120SSean Hefty struct rdma_id_private *id_priv; 322868602120SSean Hefty unsigned long flags; 322968602120SSean Hefty int ret; 323068602120SSean Hefty 323168602120SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 323268602120SSean Hefty spin_lock_irqsave(&id_priv->lock, flags); 323368602120SSean Hefty if (id_priv->state == RDMA_CM_IDLE || id_priv->state == RDMA_CM_ADDR_BOUND) { 323468602120SSean Hefty id_priv->options |= (1 << CMA_OPTION_AFONLY); 323568602120SSean Hefty id_priv->afonly = afonly; 323668602120SSean Hefty ret = 0; 323768602120SSean Hefty } else { 323868602120SSean Hefty ret = -EINVAL; 323968602120SSean Hefty } 324068602120SSean Hefty spin_unlock_irqrestore(&id_priv->lock, flags); 324168602120SSean Hefty return ret; 324268602120SSean Hefty } 324368602120SSean Hefty EXPORT_SYMBOL(rdma_set_afonly); 324468602120SSean Hefty 3245e51060f0SSean Hefty static void cma_bind_port(struct rdma_bind_list *bind_list, 3246e51060f0SSean Hefty struct rdma_id_private *id_priv) 3247e51060f0SSean Hefty { 324858afdcb7SSean Hefty struct sockaddr *addr; 324958afdcb7SSean Hefty struct sockaddr_ib *sib; 325058afdcb7SSean Hefty u64 sid, mask; 325158afdcb7SSean Hefty __be16 port; 3252e51060f0SSean Hefty 3253f4753834SSean Hefty addr = cma_src_addr(id_priv); 325458afdcb7SSean Hefty port = htons(bind_list->port); 325558afdcb7SSean Hefty 325658afdcb7SSean Hefty switch (addr->sa_family) { 325758afdcb7SSean Hefty case AF_INET: 325858afdcb7SSean Hefty ((struct sockaddr_in *) addr)->sin_port = port; 325958afdcb7SSean Hefty break; 326058afdcb7SSean Hefty case AF_INET6: 326158afdcb7SSean Hefty ((struct sockaddr_in6 *) addr)->sin6_port = port; 326258afdcb7SSean Hefty break; 326358afdcb7SSean Hefty case AF_IB: 326458afdcb7SSean Hefty sib = (struct sockaddr_ib *) addr; 326558afdcb7SSean Hefty sid = be64_to_cpu(sib->sib_sid); 326658afdcb7SSean Hefty mask = be64_to_cpu(sib->sib_sid_mask); 326758afdcb7SSean Hefty sib->sib_sid = cpu_to_be64((sid & mask) | (u64) ntohs(port)); 326858afdcb7SSean Hefty sib->sib_sid_mask = cpu_to_be64(~0ULL); 326958afdcb7SSean Hefty break; 327058afdcb7SSean Hefty } 3271e51060f0SSean Hefty id_priv->bind_list = bind_list; 3272e51060f0SSean Hefty hlist_add_head(&id_priv->node, &bind_list->owners); 3273e51060f0SSean Hefty } 3274e51060f0SSean Hefty 32752253fc0cSSteve Wise static int cma_alloc_port(enum rdma_ucm_port_space ps, 3276aac978e1SHaggai Eran struct rdma_id_private *id_priv, unsigned short snum) 3277e51060f0SSean Hefty { 3278e51060f0SSean Hefty struct rdma_bind_list *bind_list; 32793b069c5dSTejun Heo int ret; 3280e51060f0SSean Hefty 3281cb164b8cSSean Hefty bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL); 3282e51060f0SSean Hefty if (!bind_list) 3283e51060f0SSean Hefty return -ENOMEM; 3284e51060f0SSean Hefty 3285fa20105eSGuy Shapiro ret = cma_ps_alloc(id_priv->id.route.addr.dev_addr.net, ps, bind_list, 3286fa20105eSGuy Shapiro snum); 32873b069c5dSTejun Heo if (ret < 0) 32883b069c5dSTejun Heo goto err; 3289e51060f0SSean Hefty 3290e51060f0SSean Hefty bind_list->ps = ps; 3291061ccb52SLeon Romanovsky bind_list->port = snum; 3292e51060f0SSean Hefty cma_bind_port(bind_list, id_priv); 3293e51060f0SSean Hefty return 0; 32943b069c5dSTejun Heo err: 3295aedec080SSean Hefty kfree(bind_list); 32963b069c5dSTejun Heo return ret == -ENOSPC ? -EADDRNOTAVAIL : ret; 3297aedec080SSean Hefty } 3298aedec080SSean Hefty 329919b752a1SMoni Shoua static int cma_port_is_unique(struct rdma_bind_list *bind_list, 330019b752a1SMoni Shoua struct rdma_id_private *id_priv) 330119b752a1SMoni Shoua { 330219b752a1SMoni Shoua struct rdma_id_private *cur_id; 330319b752a1SMoni Shoua struct sockaddr *daddr = cma_dst_addr(id_priv); 330419b752a1SMoni Shoua struct sockaddr *saddr = cma_src_addr(id_priv); 330519b752a1SMoni Shoua __be16 dport = cma_port(daddr); 330619b752a1SMoni Shoua 330719b752a1SMoni Shoua hlist_for_each_entry(cur_id, &bind_list->owners, node) { 330819b752a1SMoni Shoua struct sockaddr *cur_daddr = cma_dst_addr(cur_id); 330919b752a1SMoni Shoua struct sockaddr *cur_saddr = cma_src_addr(cur_id); 331019b752a1SMoni Shoua __be16 cur_dport = cma_port(cur_daddr); 331119b752a1SMoni Shoua 331219b752a1SMoni Shoua if (id_priv == cur_id) 331319b752a1SMoni Shoua continue; 331419b752a1SMoni Shoua 331519b752a1SMoni Shoua /* different dest port -> unique */ 33169dea9a2fSTatyana Nikolova if (!cma_any_port(daddr) && 33179dea9a2fSTatyana Nikolova !cma_any_port(cur_daddr) && 331819b752a1SMoni Shoua (dport != cur_dport)) 331919b752a1SMoni Shoua continue; 332019b752a1SMoni Shoua 332119b752a1SMoni Shoua /* different src address -> unique */ 332219b752a1SMoni Shoua if (!cma_any_addr(saddr) && 332319b752a1SMoni Shoua !cma_any_addr(cur_saddr) && 332419b752a1SMoni Shoua cma_addr_cmp(saddr, cur_saddr)) 332519b752a1SMoni Shoua continue; 332619b752a1SMoni Shoua 332719b752a1SMoni Shoua /* different dst address -> unique */ 33289dea9a2fSTatyana Nikolova if (!cma_any_addr(daddr) && 33299dea9a2fSTatyana Nikolova !cma_any_addr(cur_daddr) && 333019b752a1SMoni Shoua cma_addr_cmp(daddr, cur_daddr)) 333119b752a1SMoni Shoua continue; 333219b752a1SMoni Shoua 333319b752a1SMoni Shoua return -EADDRNOTAVAIL; 333419b752a1SMoni Shoua } 333519b752a1SMoni Shoua return 0; 333619b752a1SMoni Shoua } 333719b752a1SMoni Shoua 33382253fc0cSSteve Wise static int cma_alloc_any_port(enum rdma_ucm_port_space ps, 3339aac978e1SHaggai Eran struct rdma_id_private *id_priv) 3340aedec080SSean Hefty { 33415d7220e8STetsuo Handa static unsigned int last_used_port; 33425d7220e8STetsuo Handa int low, high, remaining; 33435d7220e8STetsuo Handa unsigned int rover; 3344fa20105eSGuy Shapiro struct net *net = id_priv->id.route.addr.dev_addr.net; 3345aedec080SSean Hefty 3346fa20105eSGuy Shapiro inet_get_local_port_range(net, &low, &high); 33475d7220e8STetsuo Handa remaining = (high - low) + 1; 334863862b5bSAruna-Hewapathirane rover = prandom_u32() % remaining + low; 33495d7220e8STetsuo Handa retry: 335019b752a1SMoni Shoua if (last_used_port != rover) { 335119b752a1SMoni Shoua struct rdma_bind_list *bind_list; 335219b752a1SMoni Shoua int ret; 335319b752a1SMoni Shoua 335419b752a1SMoni Shoua bind_list = cma_ps_find(net, ps, (unsigned short)rover); 335519b752a1SMoni Shoua 335619b752a1SMoni Shoua if (!bind_list) { 335719b752a1SMoni Shoua ret = cma_alloc_port(ps, id_priv, rover); 335819b752a1SMoni Shoua } else { 335919b752a1SMoni Shoua ret = cma_port_is_unique(bind_list, id_priv); 336019b752a1SMoni Shoua if (!ret) 336119b752a1SMoni Shoua cma_bind_port(bind_list, id_priv); 336219b752a1SMoni Shoua } 33635d7220e8STetsuo Handa /* 33645d7220e8STetsuo Handa * Remember previously used port number in order to avoid 33655d7220e8STetsuo Handa * re-using same port immediately after it is closed. 33665d7220e8STetsuo Handa */ 33675d7220e8STetsuo Handa if (!ret) 33685d7220e8STetsuo Handa last_used_port = rover; 33695d7220e8STetsuo Handa if (ret != -EADDRNOTAVAIL) 33705d7220e8STetsuo Handa return ret; 33715d7220e8STetsuo Handa } 33725d7220e8STetsuo Handa if (--remaining) { 33735d7220e8STetsuo Handa rover++; 33745d7220e8STetsuo Handa if ((rover < low) || (rover > high)) 33755d7220e8STetsuo Handa rover = low; 3376aedec080SSean Hefty goto retry; 3377aedec080SSean Hefty } 33785d7220e8STetsuo Handa return -EADDRNOTAVAIL; 3379e51060f0SSean Hefty } 3380e51060f0SSean Hefty 3381a9bb7912SHefty, Sean /* 3382a9bb7912SHefty, Sean * Check that the requested port is available. This is called when trying to 3383a9bb7912SHefty, Sean * bind to a specific port, or when trying to listen on a bound port. In 3384a9bb7912SHefty, Sean * the latter case, the provided id_priv may already be on the bind_list, but 3385a9bb7912SHefty, Sean * we still need to check that it's okay to start listening. 3386a9bb7912SHefty, Sean */ 3387a9bb7912SHefty, Sean static int cma_check_port(struct rdma_bind_list *bind_list, 3388a9bb7912SHefty, Sean struct rdma_id_private *id_priv, uint8_t reuseaddr) 3389e51060f0SSean Hefty { 3390e51060f0SSean Hefty struct rdma_id_private *cur_id; 339143b752daSHefty, Sean struct sockaddr *addr, *cur_addr; 3392e51060f0SSean Hefty 3393f4753834SSean Hefty addr = cma_src_addr(id_priv); 3394b67bfe0dSSasha Levin hlist_for_each_entry(cur_id, &bind_list->owners, node) { 3395a9bb7912SHefty, Sean if (id_priv == cur_id) 3396a9bb7912SHefty, Sean continue; 3397a9bb7912SHefty, Sean 33985b0ec991SSean Hefty if ((cur_id->state != RDMA_CM_LISTEN) && reuseaddr && 33995b0ec991SSean Hefty cur_id->reuseaddr) 34005b0ec991SSean Hefty continue; 34015b0ec991SSean Hefty 3402f4753834SSean Hefty cur_addr = cma_src_addr(cur_id); 34035b0ec991SSean Hefty if (id_priv->afonly && cur_id->afonly && 34045b0ec991SSean Hefty (addr->sa_family != cur_addr->sa_family)) 34055b0ec991SSean Hefty continue; 34065b0ec991SSean Hefty 34075b0ec991SSean Hefty if (cma_any_addr(addr) || cma_any_addr(cur_addr)) 3408e51060f0SSean Hefty return -EADDRNOTAVAIL; 3409e51060f0SSean Hefty 341043b752daSHefty, Sean if (!cma_addr_cmp(addr, cur_addr)) 3411e51060f0SSean Hefty return -EADDRINUSE; 3412e51060f0SSean Hefty } 3413e51060f0SSean Hefty return 0; 3414e51060f0SSean Hefty } 3415e51060f0SSean Hefty 34162253fc0cSSteve Wise static int cma_use_port(enum rdma_ucm_port_space ps, 3417aac978e1SHaggai Eran struct rdma_id_private *id_priv) 3418a9bb7912SHefty, Sean { 3419a9bb7912SHefty, Sean struct rdma_bind_list *bind_list; 3420a9bb7912SHefty, Sean unsigned short snum; 3421a9bb7912SHefty, Sean int ret; 3422a9bb7912SHefty, Sean 3423f4753834SSean Hefty snum = ntohs(cma_port(cma_src_addr(id_priv))); 3424a9bb7912SHefty, Sean if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) 3425a9bb7912SHefty, Sean return -EACCES; 3426a9bb7912SHefty, Sean 3427fa20105eSGuy Shapiro bind_list = cma_ps_find(id_priv->id.route.addr.dev_addr.net, ps, snum); 3428a9bb7912SHefty, Sean if (!bind_list) { 3429a9bb7912SHefty, Sean ret = cma_alloc_port(ps, id_priv, snum); 3430a9bb7912SHefty, Sean } else { 3431a9bb7912SHefty, Sean ret = cma_check_port(bind_list, id_priv, id_priv->reuseaddr); 3432a9bb7912SHefty, Sean if (!ret) 3433a9bb7912SHefty, Sean cma_bind_port(bind_list, id_priv); 3434a9bb7912SHefty, Sean } 3435a9bb7912SHefty, Sean return ret; 3436a9bb7912SHefty, Sean } 3437a9bb7912SHefty, Sean 3438a9bb7912SHefty, Sean static int cma_bind_listen(struct rdma_id_private *id_priv) 3439a9bb7912SHefty, Sean { 3440a9bb7912SHefty, Sean struct rdma_bind_list *bind_list = id_priv->bind_list; 3441a9bb7912SHefty, Sean int ret = 0; 3442a9bb7912SHefty, Sean 3443a9bb7912SHefty, Sean mutex_lock(&lock); 3444a9bb7912SHefty, Sean if (bind_list->owners.first->next) 3445a9bb7912SHefty, Sean ret = cma_check_port(bind_list, id_priv, 0); 3446a9bb7912SHefty, Sean mutex_unlock(&lock); 3447a9bb7912SHefty, Sean return ret; 3448a9bb7912SHefty, Sean } 3449a9bb7912SHefty, Sean 34502253fc0cSSteve Wise static enum rdma_ucm_port_space 34512253fc0cSSteve Wise cma_select_inet_ps(struct rdma_id_private *id_priv) 345258afdcb7SSean Hefty { 345358afdcb7SSean Hefty switch (id_priv->id.ps) { 345458afdcb7SSean Hefty case RDMA_PS_TCP: 345558afdcb7SSean Hefty case RDMA_PS_UDP: 345658afdcb7SSean Hefty case RDMA_PS_IPOIB: 345758afdcb7SSean Hefty case RDMA_PS_IB: 3458aac978e1SHaggai Eran return id_priv->id.ps; 345958afdcb7SSean Hefty default: 3460aac978e1SHaggai Eran 3461aac978e1SHaggai Eran return 0; 346258afdcb7SSean Hefty } 346358afdcb7SSean Hefty } 346458afdcb7SSean Hefty 34652253fc0cSSteve Wise static enum rdma_ucm_port_space 34662253fc0cSSteve Wise cma_select_ib_ps(struct rdma_id_private *id_priv) 346758afdcb7SSean Hefty { 34682253fc0cSSteve Wise enum rdma_ucm_port_space ps = 0; 346958afdcb7SSean Hefty struct sockaddr_ib *sib; 347058afdcb7SSean Hefty u64 sid_ps, mask, sid; 347158afdcb7SSean Hefty 3472f4753834SSean Hefty sib = (struct sockaddr_ib *) cma_src_addr(id_priv); 347358afdcb7SSean Hefty mask = be64_to_cpu(sib->sib_sid_mask) & RDMA_IB_IP_PS_MASK; 347458afdcb7SSean Hefty sid = be64_to_cpu(sib->sib_sid) & mask; 347558afdcb7SSean Hefty 347658afdcb7SSean Hefty if ((id_priv->id.ps == RDMA_PS_IB) && (sid == (RDMA_IB_IP_PS_IB & mask))) { 347758afdcb7SSean Hefty sid_ps = RDMA_IB_IP_PS_IB; 3478aac978e1SHaggai Eran ps = RDMA_PS_IB; 347958afdcb7SSean Hefty } else if (((id_priv->id.ps == RDMA_PS_IB) || (id_priv->id.ps == RDMA_PS_TCP)) && 348058afdcb7SSean Hefty (sid == (RDMA_IB_IP_PS_TCP & mask))) { 348158afdcb7SSean Hefty sid_ps = RDMA_IB_IP_PS_TCP; 3482aac978e1SHaggai Eran ps = RDMA_PS_TCP; 348358afdcb7SSean Hefty } else if (((id_priv->id.ps == RDMA_PS_IB) || (id_priv->id.ps == RDMA_PS_UDP)) && 348458afdcb7SSean Hefty (sid == (RDMA_IB_IP_PS_UDP & mask))) { 348558afdcb7SSean Hefty sid_ps = RDMA_IB_IP_PS_UDP; 3486aac978e1SHaggai Eran ps = RDMA_PS_UDP; 348758afdcb7SSean Hefty } 348858afdcb7SSean Hefty 348958afdcb7SSean Hefty if (ps) { 349058afdcb7SSean Hefty sib->sib_sid = cpu_to_be64(sid_ps | ntohs(cma_port((struct sockaddr *) sib))); 349158afdcb7SSean Hefty sib->sib_sid_mask = cpu_to_be64(RDMA_IB_IP_PS_MASK | 349258afdcb7SSean Hefty be64_to_cpu(sib->sib_sid_mask)); 349358afdcb7SSean Hefty } 349458afdcb7SSean Hefty return ps; 349558afdcb7SSean Hefty } 349658afdcb7SSean Hefty 3497e51060f0SSean Hefty static int cma_get_port(struct rdma_id_private *id_priv) 3498e51060f0SSean Hefty { 34992253fc0cSSteve Wise enum rdma_ucm_port_space ps; 3500e51060f0SSean Hefty int ret; 3501e51060f0SSean Hefty 3502f4753834SSean Hefty if (cma_family(id_priv) != AF_IB) 350358afdcb7SSean Hefty ps = cma_select_inet_ps(id_priv); 350458afdcb7SSean Hefty else 350558afdcb7SSean Hefty ps = cma_select_ib_ps(id_priv); 350658afdcb7SSean Hefty if (!ps) 3507e51060f0SSean Hefty return -EPROTONOSUPPORT; 3508e51060f0SSean Hefty 3509e51060f0SSean Hefty mutex_lock(&lock); 3510f4753834SSean Hefty if (cma_any_port(cma_src_addr(id_priv))) 3511aedec080SSean Hefty ret = cma_alloc_any_port(ps, id_priv); 3512e51060f0SSean Hefty else 3513e51060f0SSean Hefty ret = cma_use_port(ps, id_priv); 3514e51060f0SSean Hefty mutex_unlock(&lock); 3515e51060f0SSean Hefty 3516e51060f0SSean Hefty return ret; 3517e51060f0SSean Hefty } 3518e51060f0SSean Hefty 3519d14714dfSSean Hefty static int cma_check_linklocal(struct rdma_dev_addr *dev_addr, 3520d14714dfSSean Hefty struct sockaddr *addr) 3521d14714dfSSean Hefty { 3522d90f9b35SRoland Dreier #if IS_ENABLED(CONFIG_IPV6) 3523d14714dfSSean Hefty struct sockaddr_in6 *sin6; 3524d14714dfSSean Hefty 3525d14714dfSSean Hefty if (addr->sa_family != AF_INET6) 3526d14714dfSSean Hefty return 0; 3527d14714dfSSean Hefty 3528d14714dfSSean Hefty sin6 = (struct sockaddr_in6 *) addr; 35295462edddSSomnath Kotur 35305462edddSSomnath Kotur if (!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)) 35315462edddSSomnath Kotur return 0; 35325462edddSSomnath Kotur 35335462edddSSomnath Kotur if (!sin6->sin6_scope_id) 3534d14714dfSSean Hefty return -EINVAL; 3535d14714dfSSean Hefty 3536d14714dfSSean Hefty dev_addr->bound_dev_if = sin6->sin6_scope_id; 3537d14714dfSSean Hefty #endif 3538d14714dfSSean Hefty return 0; 3539d14714dfSSean Hefty } 3540d14714dfSSean Hefty 3541a9bb7912SHefty, Sean int rdma_listen(struct rdma_cm_id *id, int backlog) 3542a9bb7912SHefty, Sean { 3543a9bb7912SHefty, Sean struct rdma_id_private *id_priv; 3544a9bb7912SHefty, Sean int ret; 3545a9bb7912SHefty, Sean 3546a9bb7912SHefty, Sean id_priv = container_of(id, struct rdma_id_private, id); 3547550e5ca7SNir Muchtar if (id_priv->state == RDMA_CM_IDLE) { 3548f4753834SSean Hefty id->route.addr.src_addr.ss_family = AF_INET; 3549f4753834SSean Hefty ret = rdma_bind_addr(id, cma_src_addr(id_priv)); 3550a9bb7912SHefty, Sean if (ret) 3551a9bb7912SHefty, Sean return ret; 3552a9bb7912SHefty, Sean } 3553a9bb7912SHefty, Sean 3554550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_LISTEN)) 3555a9bb7912SHefty, Sean return -EINVAL; 3556a9bb7912SHefty, Sean 3557a9bb7912SHefty, Sean if (id_priv->reuseaddr) { 3558a9bb7912SHefty, Sean ret = cma_bind_listen(id_priv); 3559a9bb7912SHefty, Sean if (ret) 3560a9bb7912SHefty, Sean goto err; 3561a9bb7912SHefty, Sean } 3562a9bb7912SHefty, Sean 3563a9bb7912SHefty, Sean id_priv->backlog = backlog; 3564a9bb7912SHefty, Sean if (id->device) { 356572219ceaSMichael Wang if (rdma_cap_ib_cm(id->device, 1)) { 3566a9bb7912SHefty, Sean ret = cma_ib_listen(id_priv); 3567a9bb7912SHefty, Sean if (ret) 3568a9bb7912SHefty, Sean goto err; 356904215330SMichael Wang } else if (rdma_cap_iw_cm(id->device, 1)) { 3570a9bb7912SHefty, Sean ret = cma_iw_listen(id_priv, backlog); 3571a9bb7912SHefty, Sean if (ret) 3572a9bb7912SHefty, Sean goto err; 357321655afcSMichael Wang } else { 3574a9bb7912SHefty, Sean ret = -ENOSYS; 3575a9bb7912SHefty, Sean goto err; 3576a9bb7912SHefty, Sean } 3577a9bb7912SHefty, Sean } else 3578a9bb7912SHefty, Sean cma_listen_on_all(id_priv); 3579a9bb7912SHefty, Sean 3580a9bb7912SHefty, Sean return 0; 3581a9bb7912SHefty, Sean err: 3582a9bb7912SHefty, Sean id_priv->backlog = 0; 3583550e5ca7SNir Muchtar cma_comp_exch(id_priv, RDMA_CM_LISTEN, RDMA_CM_ADDR_BOUND); 3584a9bb7912SHefty, Sean return ret; 3585a9bb7912SHefty, Sean } 3586a9bb7912SHefty, Sean EXPORT_SYMBOL(rdma_listen); 3587a9bb7912SHefty, Sean 3588e51060f0SSean Hefty int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr) 3589e51060f0SSean Hefty { 3590e51060f0SSean Hefty struct rdma_id_private *id_priv; 3591e51060f0SSean Hefty int ret; 35926df6b4a9SMoni Shoua struct sockaddr *daddr; 3593e51060f0SSean Hefty 3594680f920aSSean Hefty if (addr->sa_family != AF_INET && addr->sa_family != AF_INET6 && 3595680f920aSSean Hefty addr->sa_family != AF_IB) 3596e51060f0SSean Hefty return -EAFNOSUPPORT; 3597e51060f0SSean Hefty 3598e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 3599550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_IDLE, RDMA_CM_ADDR_BOUND)) 3600e51060f0SSean Hefty return -EINVAL; 3601e51060f0SSean Hefty 3602d14714dfSSean Hefty ret = cma_check_linklocal(&id->route.addr.dev_addr, addr); 3603d14714dfSSean Hefty if (ret) 3604d14714dfSSean Hefty goto err1; 3605d14714dfSSean Hefty 36067b85627bSMoni Shoua memcpy(cma_src_addr(id_priv), addr, rdma_addr_size(addr)); 36078523c048SSean Hefty if (!cma_any_addr(addr)) { 3608680f920aSSean Hefty ret = cma_translate_addr(addr, &id->route.addr.dev_addr); 3609255d0c14SKrishna Kumar if (ret) 3610255d0c14SKrishna Kumar goto err1; 3611255d0c14SKrishna Kumar 3612ff11c6cdSParav Pandit ret = cma_acquire_dev_by_src_ip(id_priv); 3613e51060f0SSean Hefty if (ret) 3614255d0c14SKrishna Kumar goto err1; 3615e51060f0SSean Hefty } 3616e51060f0SSean Hefty 361768602120SSean Hefty if (!(id_priv->options & (1 << CMA_OPTION_AFONLY))) { 36185b0ec991SSean Hefty if (addr->sa_family == AF_INET) 36195b0ec991SSean Hefty id_priv->afonly = 1; 36205b0ec991SSean Hefty #if IS_ENABLED(CONFIG_IPV6) 3621fa20105eSGuy Shapiro else if (addr->sa_family == AF_INET6) { 3622fa20105eSGuy Shapiro struct net *net = id_priv->id.route.addr.dev_addr.net; 3623fa20105eSGuy Shapiro 3624fa20105eSGuy Shapiro id_priv->afonly = net->ipv6.sysctl.bindv6only; 3625fa20105eSGuy Shapiro } 36265b0ec991SSean Hefty #endif 362768602120SSean Hefty } 36289dea9a2fSTatyana Nikolova daddr = cma_dst_addr(id_priv); 36299dea9a2fSTatyana Nikolova daddr->sa_family = addr->sa_family; 36309dea9a2fSTatyana Nikolova 3631e51060f0SSean Hefty ret = cma_get_port(id_priv); 3632e51060f0SSean Hefty if (ret) 3633255d0c14SKrishna Kumar goto err2; 3634e51060f0SSean Hefty 3635e51060f0SSean Hefty return 0; 3636255d0c14SKrishna Kumar err2: 363700313983SSteve Wise rdma_restrack_del(&id_priv->res); 3638ed7a01fdSLeon Romanovsky if (id_priv->cma_dev) 3639a396d43aSSean Hefty cma_release_dev(id_priv); 3640255d0c14SKrishna Kumar err1: 3641550e5ca7SNir Muchtar cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_IDLE); 3642e51060f0SSean Hefty return ret; 3643e51060f0SSean Hefty } 3644e51060f0SSean Hefty EXPORT_SYMBOL(rdma_bind_addr); 3645e51060f0SSean Hefty 3646f4753834SSean Hefty static int cma_format_hdr(void *hdr, struct rdma_id_private *id_priv) 3647e51060f0SSean Hefty { 3648e51060f0SSean Hefty struct cma_hdr *cma_hdr; 3649e51060f0SSean Hefty 365001602f11SSean Hefty cma_hdr = hdr; 365101602f11SSean Hefty cma_hdr->cma_version = CMA_VERSION; 3652f4753834SSean Hefty if (cma_family(id_priv) == AF_INET) { 36531f5175adSAleksey Senin struct sockaddr_in *src4, *dst4; 36541f5175adSAleksey Senin 3655f4753834SSean Hefty src4 = (struct sockaddr_in *) cma_src_addr(id_priv); 3656f4753834SSean Hefty dst4 = (struct sockaddr_in *) cma_dst_addr(id_priv); 3657e51060f0SSean Hefty 3658e51060f0SSean Hefty cma_set_ip_ver(cma_hdr, 4); 3659e51060f0SSean Hefty cma_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr; 3660e51060f0SSean Hefty cma_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr; 3661e51060f0SSean Hefty cma_hdr->port = src4->sin_port; 3662e8160e15SSean Hefty } else if (cma_family(id_priv) == AF_INET6) { 36631f5175adSAleksey Senin struct sockaddr_in6 *src6, *dst6; 36641f5175adSAleksey Senin 3665f4753834SSean Hefty src6 = (struct sockaddr_in6 *) cma_src_addr(id_priv); 3666f4753834SSean Hefty dst6 = (struct sockaddr_in6 *) cma_dst_addr(id_priv); 36671f5175adSAleksey Senin 36681f5175adSAleksey Senin cma_set_ip_ver(cma_hdr, 6); 36691f5175adSAleksey Senin cma_hdr->src_addr.ip6 = src6->sin6_addr; 36701f5175adSAleksey Senin cma_hdr->dst_addr.ip6 = dst6->sin6_addr; 36711f5175adSAleksey Senin cma_hdr->port = src6->sin6_port; 36721f5175adSAleksey Senin } 3673e51060f0SSean Hefty return 0; 3674e51060f0SSean Hefty } 3675e51060f0SSean Hefty 3676628e5f6dSSean Hefty static int cma_sidr_rep_handler(struct ib_cm_id *cm_id, 3677e7ff98aeSParav Pandit const struct ib_cm_event *ib_event) 3678628e5f6dSSean Hefty { 3679628e5f6dSSean Hefty struct rdma_id_private *id_priv = cm_id->context; 36807582df82SParav Pandit struct rdma_cm_event event = {}; 3681e7ff98aeSParav Pandit const struct ib_cm_sidr_rep_event_param *rep = 3682e7ff98aeSParav Pandit &ib_event->param.sidr_rep_rcvd; 3683628e5f6dSSean Hefty int ret = 0; 3684628e5f6dSSean Hefty 368537e07cdaSBart Van Assche mutex_lock(&id_priv->handler_mutex); 368637e07cdaSBart Van Assche if (id_priv->state != RDMA_CM_CONNECT) 368737e07cdaSBart Van Assche goto out; 3688628e5f6dSSean Hefty 3689628e5f6dSSean Hefty switch (ib_event->event) { 3690628e5f6dSSean Hefty case IB_CM_SIDR_REQ_ERROR: 3691628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_UNREACHABLE; 3692628e5f6dSSean Hefty event.status = -ETIMEDOUT; 3693628e5f6dSSean Hefty break; 3694628e5f6dSSean Hefty case IB_CM_SIDR_REP_RECEIVED: 3695628e5f6dSSean Hefty event.param.ud.private_data = ib_event->private_data; 3696628e5f6dSSean Hefty event.param.ud.private_data_len = IB_CM_SIDR_REP_PRIVATE_DATA_SIZE; 3697628e5f6dSSean Hefty if (rep->status != IB_SIDR_SUCCESS) { 3698628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_UNREACHABLE; 3699628e5f6dSSean Hefty event.status = ib_event->param.sidr_rep_rcvd.status; 3700498683c6SMoni Shoua pr_debug_ratelimited("RDMA CM: UNREACHABLE: bad SIDR reply. status %d\n", 3701498683c6SMoni Shoua event.status); 3702628e5f6dSSean Hefty break; 3703628e5f6dSSean Hefty } 37045c438135SSean Hefty ret = cma_set_qkey(id_priv, rep->qkey); 3705d2ca39f2SYossi Etigin if (ret) { 3706498683c6SMoni Shoua pr_debug_ratelimited("RDMA CM: ADDR_ERROR: failed to set qkey. status %d\n", ret); 3707d2ca39f2SYossi Etigin event.event = RDMA_CM_EVENT_ADDR_ERROR; 37085c438135SSean Hefty event.status = ret; 3709628e5f6dSSean Hefty break; 3710628e5f6dSSean Hefty } 37114ad6a024SParav Pandit ib_init_ah_attr_from_path(id_priv->id.device, 37124ad6a024SParav Pandit id_priv->id.port_num, 3713628e5f6dSSean Hefty id_priv->id.route.path_rec, 371439839107SParav Pandit &event.param.ud.ah_attr, 371539839107SParav Pandit rep->sgid_attr); 3716628e5f6dSSean Hefty event.param.ud.qp_num = rep->qpn; 3717628e5f6dSSean Hefty event.param.ud.qkey = rep->qkey; 3718628e5f6dSSean Hefty event.event = RDMA_CM_EVENT_ESTABLISHED; 3719628e5f6dSSean Hefty event.status = 0; 3720628e5f6dSSean Hefty break; 3721628e5f6dSSean Hefty default: 3722aba25a3eSParav Pandit pr_err("RDMA CMA: unexpected IB CM event: %d\n", 3723628e5f6dSSean Hefty ib_event->event); 3724628e5f6dSSean Hefty goto out; 3725628e5f6dSSean Hefty } 3726628e5f6dSSean Hefty 3727628e5f6dSSean Hefty ret = id_priv->id.event_handler(&id_priv->id, &event); 3728aa74f487SParav Pandit 3729aa74f487SParav Pandit rdma_destroy_ah_attr(&event.param.ud.ah_attr); 3730628e5f6dSSean Hefty if (ret) { 3731628e5f6dSSean Hefty /* Destroy the CM ID by returning a non-zero value. */ 3732628e5f6dSSean Hefty id_priv->cm_id.ib = NULL; 3733550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 3734de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 3735628e5f6dSSean Hefty rdma_destroy_id(&id_priv->id); 3736628e5f6dSSean Hefty return ret; 3737628e5f6dSSean Hefty } 3738628e5f6dSSean Hefty out: 3739de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 3740628e5f6dSSean Hefty return ret; 3741628e5f6dSSean Hefty } 3742628e5f6dSSean Hefty 3743628e5f6dSSean Hefty static int cma_resolve_ib_udp(struct rdma_id_private *id_priv, 3744628e5f6dSSean Hefty struct rdma_conn_param *conn_param) 3745628e5f6dSSean Hefty { 3746628e5f6dSSean Hefty struct ib_cm_sidr_req_param req; 37470c9361fcSJack Morgenstein struct ib_cm_id *id; 3748e511d1aeSSean Hefty void *private_data; 3749c0b64f58SBart Van Assche u8 offset; 3750c0b64f58SBart Van Assche int ret; 3751628e5f6dSSean Hefty 3752e511d1aeSSean Hefty memset(&req, 0, sizeof req); 3753e8160e15SSean Hefty offset = cma_user_data_offset(id_priv); 3754e8160e15SSean Hefty req.private_data_len = offset + conn_param->private_data_len; 375504ded167SSean Hefty if (req.private_data_len < conn_param->private_data_len) 375604ded167SSean Hefty return -EINVAL; 375704ded167SSean Hefty 3758e8160e15SSean Hefty if (req.private_data_len) { 3759e511d1aeSSean Hefty private_data = kzalloc(req.private_data_len, GFP_ATOMIC); 3760e511d1aeSSean Hefty if (!private_data) 3761628e5f6dSSean Hefty return -ENOMEM; 3762e8160e15SSean Hefty } else { 3763e511d1aeSSean Hefty private_data = NULL; 3764e8160e15SSean Hefty } 3765628e5f6dSSean Hefty 3766628e5f6dSSean Hefty if (conn_param->private_data && conn_param->private_data_len) 3767e511d1aeSSean Hefty memcpy(private_data + offset, conn_param->private_data, 3768e511d1aeSSean Hefty conn_param->private_data_len); 3769628e5f6dSSean Hefty 3770e511d1aeSSean Hefty if (private_data) { 3771e511d1aeSSean Hefty ret = cma_format_hdr(private_data, id_priv); 3772628e5f6dSSean Hefty if (ret) 3773628e5f6dSSean Hefty goto out; 3774e511d1aeSSean Hefty req.private_data = private_data; 3775e8160e15SSean Hefty } 3776628e5f6dSSean Hefty 37770c9361fcSJack Morgenstein id = ib_create_cm_id(id_priv->id.device, cma_sidr_rep_handler, 37780c9361fcSJack Morgenstein id_priv); 37790c9361fcSJack Morgenstein if (IS_ERR(id)) { 37800c9361fcSJack Morgenstein ret = PTR_ERR(id); 3781628e5f6dSSean Hefty goto out; 3782628e5f6dSSean Hefty } 37830c9361fcSJack Morgenstein id_priv->cm_id.ib = id; 3784628e5f6dSSean Hefty 3785f4753834SSean Hefty req.path = id_priv->id.route.path_rec; 3786815d456eSParav Pandit req.sgid_attr = id_priv->id.route.addr.dev_addr.sgid_attr; 3787cf53936fSSean Hefty req.service_id = rdma_get_service_id(&id_priv->id, cma_dst_addr(id_priv)); 3788628e5f6dSSean Hefty req.timeout_ms = 1 << (CMA_CM_RESPONSE_TIMEOUT - 8); 3789628e5f6dSSean Hefty req.max_cm_retries = CMA_MAX_CM_RETRIES; 3790628e5f6dSSean Hefty 3791628e5f6dSSean Hefty ret = ib_send_cm_sidr_req(id_priv->cm_id.ib, &req); 3792628e5f6dSSean Hefty if (ret) { 3793628e5f6dSSean Hefty ib_destroy_cm_id(id_priv->cm_id.ib); 3794628e5f6dSSean Hefty id_priv->cm_id.ib = NULL; 3795628e5f6dSSean Hefty } 3796628e5f6dSSean Hefty out: 3797e511d1aeSSean Hefty kfree(private_data); 3798628e5f6dSSean Hefty return ret; 3799628e5f6dSSean Hefty } 3800628e5f6dSSean Hefty 3801e51060f0SSean Hefty static int cma_connect_ib(struct rdma_id_private *id_priv, 3802e51060f0SSean Hefty struct rdma_conn_param *conn_param) 3803e51060f0SSean Hefty { 3804e51060f0SSean Hefty struct ib_cm_req_param req; 3805e51060f0SSean Hefty struct rdma_route *route; 3806e51060f0SSean Hefty void *private_data; 38070c9361fcSJack Morgenstein struct ib_cm_id *id; 3808c0b64f58SBart Van Assche u8 offset; 3809c0b64f58SBart Van Assche int ret; 3810e51060f0SSean Hefty 3811e51060f0SSean Hefty memset(&req, 0, sizeof req); 3812e8160e15SSean Hefty offset = cma_user_data_offset(id_priv); 3813e51060f0SSean Hefty req.private_data_len = offset + conn_param->private_data_len; 381404ded167SSean Hefty if (req.private_data_len < conn_param->private_data_len) 381504ded167SSean Hefty return -EINVAL; 381604ded167SSean Hefty 3817e8160e15SSean Hefty if (req.private_data_len) { 3818e51060f0SSean Hefty private_data = kzalloc(req.private_data_len, GFP_ATOMIC); 3819e51060f0SSean Hefty if (!private_data) 3820e51060f0SSean Hefty return -ENOMEM; 3821e8160e15SSean Hefty } else { 3822e8160e15SSean Hefty private_data = NULL; 3823e8160e15SSean Hefty } 3824e51060f0SSean Hefty 3825e51060f0SSean Hefty if (conn_param->private_data && conn_param->private_data_len) 3826e51060f0SSean Hefty memcpy(private_data + offset, conn_param->private_data, 3827e51060f0SSean Hefty conn_param->private_data_len); 3828e51060f0SSean Hefty 38290c9361fcSJack Morgenstein id = ib_create_cm_id(id_priv->id.device, cma_ib_handler, id_priv); 38300c9361fcSJack Morgenstein if (IS_ERR(id)) { 38310c9361fcSJack Morgenstein ret = PTR_ERR(id); 3832e51060f0SSean Hefty goto out; 3833e51060f0SSean Hefty } 38340c9361fcSJack Morgenstein id_priv->cm_id.ib = id; 3835e51060f0SSean Hefty 3836e51060f0SSean Hefty route = &id_priv->id.route; 3837e8160e15SSean Hefty if (private_data) { 3838f4753834SSean Hefty ret = cma_format_hdr(private_data, id_priv); 3839e51060f0SSean Hefty if (ret) 3840e51060f0SSean Hefty goto out; 3841e51060f0SSean Hefty req.private_data = private_data; 3842e8160e15SSean Hefty } 3843e51060f0SSean Hefty 3844e51060f0SSean Hefty req.primary_path = &route->path_rec[0]; 3845e51060f0SSean Hefty if (route->num_paths == 2) 3846e51060f0SSean Hefty req.alternate_path = &route->path_rec[1]; 3847e51060f0SSean Hefty 3848815d456eSParav Pandit req.ppath_sgid_attr = id_priv->id.route.addr.dev_addr.sgid_attr; 3849815d456eSParav Pandit /* Alternate path SGID attribute currently unsupported */ 3850cf53936fSSean Hefty req.service_id = rdma_get_service_id(&id_priv->id, cma_dst_addr(id_priv)); 3851e51060f0SSean Hefty req.qp_num = id_priv->qp_num; 385218c441a6SSean Hefty req.qp_type = id_priv->id.qp_type; 3853e51060f0SSean Hefty req.starting_psn = id_priv->seq_num; 3854e51060f0SSean Hefty req.responder_resources = conn_param->responder_resources; 3855e51060f0SSean Hefty req.initiator_depth = conn_param->initiator_depth; 3856e51060f0SSean Hefty req.flow_control = conn_param->flow_control; 38574ede178aSSean Hefty req.retry_count = min_t(u8, 7, conn_param->retry_count); 38584ede178aSSean Hefty req.rnr_retry_count = min_t(u8, 7, conn_param->rnr_retry_count); 3859e51060f0SSean Hefty req.remote_cm_response_timeout = CMA_CM_RESPONSE_TIMEOUT; 3860e51060f0SSean Hefty req.local_cm_response_timeout = CMA_CM_RESPONSE_TIMEOUT; 3861e51060f0SSean Hefty req.max_cm_retries = CMA_MAX_CM_RETRIES; 3862e51060f0SSean Hefty req.srq = id_priv->srq ? 1 : 0; 3863e51060f0SSean Hefty 3864e51060f0SSean Hefty ret = ib_send_cm_req(id_priv->cm_id.ib, &req); 3865e51060f0SSean Hefty out: 38660c9361fcSJack Morgenstein if (ret && !IS_ERR(id)) { 38670c9361fcSJack Morgenstein ib_destroy_cm_id(id); 3868675a027cSKrishna Kumar id_priv->cm_id.ib = NULL; 3869675a027cSKrishna Kumar } 3870675a027cSKrishna Kumar 3871e51060f0SSean Hefty kfree(private_data); 3872e51060f0SSean Hefty return ret; 3873e51060f0SSean Hefty } 3874e51060f0SSean Hefty 387507ebafbaSTom Tucker static int cma_connect_iw(struct rdma_id_private *id_priv, 387607ebafbaSTom Tucker struct rdma_conn_param *conn_param) 387707ebafbaSTom Tucker { 387807ebafbaSTom Tucker struct iw_cm_id *cm_id; 387907ebafbaSTom Tucker int ret; 388007ebafbaSTom Tucker struct iw_cm_conn_param iw_param; 388107ebafbaSTom Tucker 388207ebafbaSTom Tucker cm_id = iw_create_cm_id(id_priv->id.device, cma_iw_handler, id_priv); 38830c9361fcSJack Morgenstein if (IS_ERR(cm_id)) 38840c9361fcSJack Morgenstein return PTR_ERR(cm_id); 388507ebafbaSTom Tucker 388668cdba06SSteve Wise cm_id->tos = id_priv->tos; 3887926ba19bSSteve Wise cm_id->tos_set = id_priv->tos_set; 388807ebafbaSTom Tucker id_priv->cm_id.iw = cm_id; 388907ebafbaSTom Tucker 389024d44a39SSteve Wise memcpy(&cm_id->local_addr, cma_src_addr(id_priv), 389124d44a39SSteve Wise rdma_addr_size(cma_src_addr(id_priv))); 389224d44a39SSteve Wise memcpy(&cm_id->remote_addr, cma_dst_addr(id_priv), 389324d44a39SSteve Wise rdma_addr_size(cma_dst_addr(id_priv))); 389407ebafbaSTom Tucker 38955851bb89SSean Hefty ret = cma_modify_qp_rtr(id_priv, conn_param); 3896675a027cSKrishna Kumar if (ret) 3897675a027cSKrishna Kumar goto out; 389807ebafbaSTom Tucker 3899f45ee80eSHefty, Sean if (conn_param) { 390007ebafbaSTom Tucker iw_param.ord = conn_param->initiator_depth; 390107ebafbaSTom Tucker iw_param.ird = conn_param->responder_resources; 390207ebafbaSTom Tucker iw_param.private_data = conn_param->private_data; 390307ebafbaSTom Tucker iw_param.private_data_len = conn_param->private_data_len; 3904f45ee80eSHefty, Sean iw_param.qpn = id_priv->id.qp ? id_priv->qp_num : conn_param->qp_num; 3905f45ee80eSHefty, Sean } else { 3906f45ee80eSHefty, Sean memset(&iw_param, 0, sizeof iw_param); 390707ebafbaSTom Tucker iw_param.qpn = id_priv->qp_num; 3908f45ee80eSHefty, Sean } 390907ebafbaSTom Tucker ret = iw_cm_connect(cm_id, &iw_param); 391007ebafbaSTom Tucker out: 39110c9361fcSJack Morgenstein if (ret) { 3912675a027cSKrishna Kumar iw_destroy_cm_id(cm_id); 3913675a027cSKrishna Kumar id_priv->cm_id.iw = NULL; 3914675a027cSKrishna Kumar } 391507ebafbaSTom Tucker return ret; 391607ebafbaSTom Tucker } 391707ebafbaSTom Tucker 3918e51060f0SSean Hefty int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param) 3919e51060f0SSean Hefty { 3920e51060f0SSean Hefty struct rdma_id_private *id_priv; 3921e51060f0SSean Hefty int ret; 3922e51060f0SSean Hefty 3923e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 3924550e5ca7SNir Muchtar if (!cma_comp_exch(id_priv, RDMA_CM_ROUTE_RESOLVED, RDMA_CM_CONNECT)) 3925e51060f0SSean Hefty return -EINVAL; 3926e51060f0SSean Hefty 3927e51060f0SSean Hefty if (!id->qp) { 3928e51060f0SSean Hefty id_priv->qp_num = conn_param->qp_num; 3929e51060f0SSean Hefty id_priv->srq = conn_param->srq; 3930e51060f0SSean Hefty } 3931e51060f0SSean Hefty 393272219ceaSMichael Wang if (rdma_cap_ib_cm(id->device, id->port_num)) { 3933b26f9b99SSean Hefty if (id->qp_type == IB_QPT_UD) 3934628e5f6dSSean Hefty ret = cma_resolve_ib_udp(id_priv, conn_param); 3935628e5f6dSSean Hefty else 3936e51060f0SSean Hefty ret = cma_connect_ib(id_priv, conn_param); 393704215330SMichael Wang } else if (rdma_cap_iw_cm(id->device, id->port_num)) 393807ebafbaSTom Tucker ret = cma_connect_iw(id_priv, conn_param); 393921655afcSMichael Wang else 3940e51060f0SSean Hefty ret = -ENOSYS; 3941e51060f0SSean Hefty if (ret) 3942e51060f0SSean Hefty goto err; 3943e51060f0SSean Hefty 3944e51060f0SSean Hefty return 0; 3945e51060f0SSean Hefty err: 3946550e5ca7SNir Muchtar cma_comp_exch(id_priv, RDMA_CM_CONNECT, RDMA_CM_ROUTE_RESOLVED); 3947e51060f0SSean Hefty return ret; 3948e51060f0SSean Hefty } 3949e51060f0SSean Hefty EXPORT_SYMBOL(rdma_connect); 3950e51060f0SSean Hefty 3951e51060f0SSean Hefty static int cma_accept_ib(struct rdma_id_private *id_priv, 3952e51060f0SSean Hefty struct rdma_conn_param *conn_param) 3953e51060f0SSean Hefty { 3954e51060f0SSean Hefty struct ib_cm_rep_param rep; 39555851bb89SSean Hefty int ret; 3956e51060f0SSean Hefty 39575851bb89SSean Hefty ret = cma_modify_qp_rtr(id_priv, conn_param); 3958e51060f0SSean Hefty if (ret) 39590fe313b0SSean Hefty goto out; 39600fe313b0SSean Hefty 39615851bb89SSean Hefty ret = cma_modify_qp_rts(id_priv, conn_param); 39620fe313b0SSean Hefty if (ret) 39630fe313b0SSean Hefty goto out; 39640fe313b0SSean Hefty 3965e51060f0SSean Hefty memset(&rep, 0, sizeof rep); 3966e51060f0SSean Hefty rep.qp_num = id_priv->qp_num; 3967e51060f0SSean Hefty rep.starting_psn = id_priv->seq_num; 3968e51060f0SSean Hefty rep.private_data = conn_param->private_data; 3969e51060f0SSean Hefty rep.private_data_len = conn_param->private_data_len; 3970e51060f0SSean Hefty rep.responder_resources = conn_param->responder_resources; 3971e51060f0SSean Hefty rep.initiator_depth = conn_param->initiator_depth; 3972e51060f0SSean Hefty rep.failover_accepted = 0; 3973e51060f0SSean Hefty rep.flow_control = conn_param->flow_control; 39744ede178aSSean Hefty rep.rnr_retry_count = min_t(u8, 7, conn_param->rnr_retry_count); 3975e51060f0SSean Hefty rep.srq = id_priv->srq ? 1 : 0; 3976e51060f0SSean Hefty 39770fe313b0SSean Hefty ret = ib_send_cm_rep(id_priv->cm_id.ib, &rep); 39780fe313b0SSean Hefty out: 39790fe313b0SSean Hefty return ret; 3980e51060f0SSean Hefty } 3981e51060f0SSean Hefty 398207ebafbaSTom Tucker static int cma_accept_iw(struct rdma_id_private *id_priv, 398307ebafbaSTom Tucker struct rdma_conn_param *conn_param) 398407ebafbaSTom Tucker { 398507ebafbaSTom Tucker struct iw_cm_conn_param iw_param; 398607ebafbaSTom Tucker int ret; 398707ebafbaSTom Tucker 3988f2625f7dSSteve Wise if (!conn_param) 3989f2625f7dSSteve Wise return -EINVAL; 3990f2625f7dSSteve Wise 39915851bb89SSean Hefty ret = cma_modify_qp_rtr(id_priv, conn_param); 399207ebafbaSTom Tucker if (ret) 399307ebafbaSTom Tucker return ret; 399407ebafbaSTom Tucker 399507ebafbaSTom Tucker iw_param.ord = conn_param->initiator_depth; 399607ebafbaSTom Tucker iw_param.ird = conn_param->responder_resources; 399707ebafbaSTom Tucker iw_param.private_data = conn_param->private_data; 399807ebafbaSTom Tucker iw_param.private_data_len = conn_param->private_data_len; 399907ebafbaSTom Tucker if (id_priv->id.qp) { 400007ebafbaSTom Tucker iw_param.qpn = id_priv->qp_num; 400107ebafbaSTom Tucker } else 400207ebafbaSTom Tucker iw_param.qpn = conn_param->qp_num; 400307ebafbaSTom Tucker 400407ebafbaSTom Tucker return iw_cm_accept(id_priv->cm_id.iw, &iw_param); 400507ebafbaSTom Tucker } 400607ebafbaSTom Tucker 4007628e5f6dSSean Hefty static int cma_send_sidr_rep(struct rdma_id_private *id_priv, 40085c438135SSean Hefty enum ib_cm_sidr_status status, u32 qkey, 4009628e5f6dSSean Hefty const void *private_data, int private_data_len) 4010628e5f6dSSean Hefty { 4011628e5f6dSSean Hefty struct ib_cm_sidr_rep_param rep; 4012d2ca39f2SYossi Etigin int ret; 4013628e5f6dSSean Hefty 4014628e5f6dSSean Hefty memset(&rep, 0, sizeof rep); 4015628e5f6dSSean Hefty rep.status = status; 4016628e5f6dSSean Hefty if (status == IB_SIDR_SUCCESS) { 40175c438135SSean Hefty ret = cma_set_qkey(id_priv, qkey); 4018d2ca39f2SYossi Etigin if (ret) 4019d2ca39f2SYossi Etigin return ret; 4020628e5f6dSSean Hefty rep.qp_num = id_priv->qp_num; 4021c8f6a362SSean Hefty rep.qkey = id_priv->qkey; 4022628e5f6dSSean Hefty } 4023628e5f6dSSean Hefty rep.private_data = private_data; 4024628e5f6dSSean Hefty rep.private_data_len = private_data_len; 4025628e5f6dSSean Hefty 4026628e5f6dSSean Hefty return ib_send_cm_sidr_rep(id_priv->cm_id.ib, &rep); 4027628e5f6dSSean Hefty } 4028628e5f6dSSean Hefty 402900313983SSteve Wise int __rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param, 403000313983SSteve Wise const char *caller) 4031e51060f0SSean Hefty { 4032e51060f0SSean Hefty struct rdma_id_private *id_priv; 4033e51060f0SSean Hefty int ret; 4034e51060f0SSean Hefty 4035e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 403683e9502dSNir Muchtar 40372165fc26SLeon Romanovsky rdma_restrack_set_task(&id_priv->res, caller); 403883e9502dSNir Muchtar 4039550e5ca7SNir Muchtar if (!cma_comp(id_priv, RDMA_CM_CONNECT)) 4040e51060f0SSean Hefty return -EINVAL; 4041e51060f0SSean Hefty 4042e51060f0SSean Hefty if (!id->qp && conn_param) { 4043e51060f0SSean Hefty id_priv->qp_num = conn_param->qp_num; 4044e51060f0SSean Hefty id_priv->srq = conn_param->srq; 4045e51060f0SSean Hefty } 4046e51060f0SSean Hefty 404772219ceaSMichael Wang if (rdma_cap_ib_cm(id->device, id->port_num)) { 4048f45ee80eSHefty, Sean if (id->qp_type == IB_QPT_UD) { 4049f45ee80eSHefty, Sean if (conn_param) 4050628e5f6dSSean Hefty ret = cma_send_sidr_rep(id_priv, IB_SIDR_SUCCESS, 40515c438135SSean Hefty conn_param->qkey, 4052628e5f6dSSean Hefty conn_param->private_data, 4053628e5f6dSSean Hefty conn_param->private_data_len); 4054f45ee80eSHefty, Sean else 4055f45ee80eSHefty, Sean ret = cma_send_sidr_rep(id_priv, IB_SIDR_SUCCESS, 40565c438135SSean Hefty 0, NULL, 0); 4057f45ee80eSHefty, Sean } else { 4058f45ee80eSHefty, Sean if (conn_param) 4059e51060f0SSean Hefty ret = cma_accept_ib(id_priv, conn_param); 4060e51060f0SSean Hefty else 4061e51060f0SSean Hefty ret = cma_rep_recv(id_priv); 4062f45ee80eSHefty, Sean } 406304215330SMichael Wang } else if (rdma_cap_iw_cm(id->device, id->port_num)) 406407ebafbaSTom Tucker ret = cma_accept_iw(id_priv, conn_param); 406521655afcSMichael Wang else 4066e51060f0SSean Hefty ret = -ENOSYS; 4067e51060f0SSean Hefty 4068e51060f0SSean Hefty if (ret) 4069e51060f0SSean Hefty goto reject; 4070e51060f0SSean Hefty 4071e51060f0SSean Hefty return 0; 4072e51060f0SSean Hefty reject: 4073c5483388SSean Hefty cma_modify_qp_err(id_priv); 4074e51060f0SSean Hefty rdma_reject(id, NULL, 0); 4075e51060f0SSean Hefty return ret; 4076e51060f0SSean Hefty } 407700313983SSteve Wise EXPORT_SYMBOL(__rdma_accept); 4078e51060f0SSean Hefty 40790fe313b0SSean Hefty int rdma_notify(struct rdma_cm_id *id, enum ib_event_type event) 40800fe313b0SSean Hefty { 40810fe313b0SSean Hefty struct rdma_id_private *id_priv; 40820fe313b0SSean Hefty int ret; 40830fe313b0SSean Hefty 40840fe313b0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 40850c9361fcSJack Morgenstein if (!id_priv->cm_id.ib) 40860fe313b0SSean Hefty return -EINVAL; 40870fe313b0SSean Hefty 40880fe313b0SSean Hefty switch (id->device->node_type) { 40890fe313b0SSean Hefty case RDMA_NODE_IB_CA: 40900fe313b0SSean Hefty ret = ib_cm_notify(id_priv->cm_id.ib, event); 40910fe313b0SSean Hefty break; 40920fe313b0SSean Hefty default: 40930fe313b0SSean Hefty ret = 0; 40940fe313b0SSean Hefty break; 40950fe313b0SSean Hefty } 40960fe313b0SSean Hefty return ret; 40970fe313b0SSean Hefty } 40980fe313b0SSean Hefty EXPORT_SYMBOL(rdma_notify); 40990fe313b0SSean Hefty 4100e51060f0SSean Hefty int rdma_reject(struct rdma_cm_id *id, const void *private_data, 4101e51060f0SSean Hefty u8 private_data_len) 4102e51060f0SSean Hefty { 4103e51060f0SSean Hefty struct rdma_id_private *id_priv; 4104e51060f0SSean Hefty int ret; 4105e51060f0SSean Hefty 4106e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 41070c9361fcSJack Morgenstein if (!id_priv->cm_id.ib) 4108e51060f0SSean Hefty return -EINVAL; 4109e51060f0SSean Hefty 411072219ceaSMichael Wang if (rdma_cap_ib_cm(id->device, id->port_num)) { 4111b26f9b99SSean Hefty if (id->qp_type == IB_QPT_UD) 41125c438135SSean Hefty ret = cma_send_sidr_rep(id_priv, IB_SIDR_REJECT, 0, 4113e51060f0SSean Hefty private_data, private_data_len); 4114628e5f6dSSean Hefty else 4115628e5f6dSSean Hefty ret = ib_send_cm_rej(id_priv->cm_id.ib, 4116628e5f6dSSean Hefty IB_CM_REJ_CONSUMER_DEFINED, NULL, 4117628e5f6dSSean Hefty 0, private_data, private_data_len); 411804215330SMichael Wang } else if (rdma_cap_iw_cm(id->device, id->port_num)) { 411907ebafbaSTom Tucker ret = iw_cm_reject(id_priv->cm_id.iw, 412007ebafbaSTom Tucker private_data, private_data_len); 412121655afcSMichael Wang } else 4122e51060f0SSean Hefty ret = -ENOSYS; 412321655afcSMichael Wang 4124e51060f0SSean Hefty return ret; 4125e51060f0SSean Hefty } 4126e51060f0SSean Hefty EXPORT_SYMBOL(rdma_reject); 4127e51060f0SSean Hefty 4128e51060f0SSean Hefty int rdma_disconnect(struct rdma_cm_id *id) 4129e51060f0SSean Hefty { 4130e51060f0SSean Hefty struct rdma_id_private *id_priv; 4131e51060f0SSean Hefty int ret; 4132e51060f0SSean Hefty 4133e51060f0SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 41340c9361fcSJack Morgenstein if (!id_priv->cm_id.ib) 4135e51060f0SSean Hefty return -EINVAL; 4136e51060f0SSean Hefty 413772219ceaSMichael Wang if (rdma_cap_ib_cm(id->device, id->port_num)) { 4138c5483388SSean Hefty ret = cma_modify_qp_err(id_priv); 4139e51060f0SSean Hefty if (ret) 4140e51060f0SSean Hefty goto out; 4141e51060f0SSean Hefty /* Initiate or respond to a disconnect. */ 4142e51060f0SSean Hefty if (ib_send_cm_dreq(id_priv->cm_id.ib, NULL, 0)) 4143e51060f0SSean Hefty ib_send_cm_drep(id_priv->cm_id.ib, NULL, 0); 414404215330SMichael Wang } else if (rdma_cap_iw_cm(id->device, id->port_num)) { 414507ebafbaSTom Tucker ret = iw_cm_disconnect(id_priv->cm_id.iw, 0); 414621655afcSMichael Wang } else 414707ebafbaSTom Tucker ret = -EINVAL; 414821655afcSMichael Wang 4149e51060f0SSean Hefty out: 4150e51060f0SSean Hefty return ret; 4151e51060f0SSean Hefty } 4152e51060f0SSean Hefty EXPORT_SYMBOL(rdma_disconnect); 4153e51060f0SSean Hefty 4154c8f6a362SSean Hefty static int cma_ib_mc_handler(int status, struct ib_sa_multicast *multicast) 4155c8f6a362SSean Hefty { 4156c8f6a362SSean Hefty struct rdma_id_private *id_priv; 4157c8f6a362SSean Hefty struct cma_multicast *mc = multicast->context; 41587582df82SParav Pandit struct rdma_cm_event event = {}; 415937e07cdaSBart Van Assche int ret = 0; 4160c8f6a362SSean Hefty 4161c8f6a362SSean Hefty id_priv = mc->id_priv; 416237e07cdaSBart Van Assche mutex_lock(&id_priv->handler_mutex); 416337e07cdaSBart Van Assche if (id_priv->state != RDMA_CM_ADDR_BOUND && 416437e07cdaSBart Van Assche id_priv->state != RDMA_CM_ADDR_RESOLVED) 416537e07cdaSBart Van Assche goto out; 4166c8f6a362SSean Hefty 41675c438135SSean Hefty if (!status) 41685c438135SSean Hefty status = cma_set_qkey(id_priv, be32_to_cpu(multicast->rec.qkey)); 4169498683c6SMoni Shoua else 4170498683c6SMoni Shoua pr_debug_ratelimited("RDMA CM: MULTICAST_ERROR: failed to join multicast. status %d\n", 4171498683c6SMoni Shoua status); 4172c5483388SSean Hefty mutex_lock(&id_priv->qp_mutex); 4173498683c6SMoni Shoua if (!status && id_priv->id.qp) { 4174c8f6a362SSean Hefty status = ib_attach_mcast(id_priv->id.qp, &multicast->rec.mgid, 417546ea5061SSean Hefty be16_to_cpu(multicast->rec.mlid)); 4176a3dd3a48SChristophe Jaillet if (status) 4177498683c6SMoni Shoua pr_debug_ratelimited("RDMA CM: MULTICAST_ERROR: failed to attach QP. status %d\n", 4178498683c6SMoni Shoua status); 4179498683c6SMoni Shoua } 4180c5483388SSean Hefty mutex_unlock(&id_priv->qp_mutex); 4181c8f6a362SSean Hefty 4182c8f6a362SSean Hefty event.status = status; 4183c8f6a362SSean Hefty event.param.ud.private_data = mc->context; 4184c8f6a362SSean Hefty if (!status) { 4185bee3c3c9SMoni Shoua struct rdma_dev_addr *dev_addr = 4186bee3c3c9SMoni Shoua &id_priv->id.route.addr.dev_addr; 4187bee3c3c9SMoni Shoua struct net_device *ndev = 4188052eac6eSParav Pandit dev_get_by_index(dev_addr->net, dev_addr->bound_dev_if); 4189bee3c3c9SMoni Shoua enum ib_gid_type gid_type = 4190bee3c3c9SMoni Shoua id_priv->cma_dev->default_gid_type[id_priv->id.port_num - 4191bee3c3c9SMoni Shoua rdma_start_port(id_priv->cma_dev->device)]; 4192bee3c3c9SMoni Shoua 4193c8f6a362SSean Hefty event.event = RDMA_CM_EVENT_MULTICAST_JOIN; 41946d337179SParav Pandit ret = ib_init_ah_from_mcmember(id_priv->id.device, 41956d337179SParav Pandit id_priv->id.port_num, 41966d337179SParav Pandit &multicast->rec, 4197bee3c3c9SMoni Shoua ndev, gid_type, 4198c8f6a362SSean Hefty &event.param.ud.ah_attr); 41996d337179SParav Pandit if (ret) 42006d337179SParav Pandit event.event = RDMA_CM_EVENT_MULTICAST_ERROR; 42016d337179SParav Pandit 4202c8f6a362SSean Hefty event.param.ud.qp_num = 0xFFFFFF; 4203c8f6a362SSean Hefty event.param.ud.qkey = be32_to_cpu(multicast->rec.qkey); 4204bee3c3c9SMoni Shoua if (ndev) 4205bee3c3c9SMoni Shoua dev_put(ndev); 4206c8f6a362SSean Hefty } else 4207c8f6a362SSean Hefty event.event = RDMA_CM_EVENT_MULTICAST_ERROR; 4208c8f6a362SSean Hefty 4209c8f6a362SSean Hefty ret = id_priv->id.event_handler(&id_priv->id, &event); 4210f685c195SParav Pandit 4211f685c195SParav Pandit rdma_destroy_ah_attr(&event.param.ud.ah_attr); 4212c8f6a362SSean Hefty if (ret) { 4213550e5ca7SNir Muchtar cma_exch(id_priv, RDMA_CM_DESTROYING); 4214de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 4215c8f6a362SSean Hefty rdma_destroy_id(&id_priv->id); 4216c8f6a362SSean Hefty return 0; 4217c8f6a362SSean Hefty } 42188aa08602SSean Hefty 421937e07cdaSBart Van Assche out: 4220de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 4221c8f6a362SSean Hefty return 0; 4222c8f6a362SSean Hefty } 4223c8f6a362SSean Hefty 4224c8f6a362SSean Hefty static void cma_set_mgid(struct rdma_id_private *id_priv, 4225c8f6a362SSean Hefty struct sockaddr *addr, union ib_gid *mgid) 4226c8f6a362SSean Hefty { 4227c8f6a362SSean Hefty unsigned char mc_map[MAX_ADDR_LEN]; 4228c8f6a362SSean Hefty struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 4229c8f6a362SSean Hefty struct sockaddr_in *sin = (struct sockaddr_in *) addr; 4230c8f6a362SSean Hefty struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) addr; 4231c8f6a362SSean Hefty 4232c8f6a362SSean Hefty if (cma_any_addr(addr)) { 4233c8f6a362SSean Hefty memset(mgid, 0, sizeof *mgid); 4234c8f6a362SSean Hefty } else if ((addr->sa_family == AF_INET6) && 42351c9b2819SJason Gunthorpe ((be32_to_cpu(sin6->sin6_addr.s6_addr32[0]) & 0xFFF0FFFF) == 4236c8f6a362SSean Hefty 0xFF10A01B)) { 4237c8f6a362SSean Hefty /* IPv6 address is an SA assigned MGID. */ 4238c8f6a362SSean Hefty memcpy(mgid, &sin6->sin6_addr, sizeof *mgid); 42395bc2b7b3SSean Hefty } else if (addr->sa_family == AF_IB) { 42405bc2b7b3SSean Hefty memcpy(mgid, &((struct sockaddr_ib *) addr)->sib_addr, sizeof *mgid); 4241076dd53bSVarsha Rao } else if (addr->sa_family == AF_INET6) { 4242e2e62697SJason Gunthorpe ipv6_ib_mc_map(&sin6->sin6_addr, dev_addr->broadcast, mc_map); 4243e2e62697SJason Gunthorpe if (id_priv->id.ps == RDMA_PS_UDP) 4244e2e62697SJason Gunthorpe mc_map[7] = 0x01; /* Use RDMA CM signature */ 4245e2e62697SJason Gunthorpe *mgid = *(union ib_gid *) (mc_map + 4); 4246c8f6a362SSean Hefty } else { 4247a9e527e3SRolf Manderscheid ip_ib_mc_map(sin->sin_addr.s_addr, dev_addr->broadcast, mc_map); 4248c8f6a362SSean Hefty if (id_priv->id.ps == RDMA_PS_UDP) 4249c8f6a362SSean Hefty mc_map[7] = 0x01; /* Use RDMA CM signature */ 4250c8f6a362SSean Hefty *mgid = *(union ib_gid *) (mc_map + 4); 4251c8f6a362SSean Hefty } 4252c8f6a362SSean Hefty } 4253c8f6a362SSean Hefty 4254c8f6a362SSean Hefty static int cma_join_ib_multicast(struct rdma_id_private *id_priv, 4255c8f6a362SSean Hefty struct cma_multicast *mc) 4256c8f6a362SSean Hefty { 4257c8f6a362SSean Hefty struct ib_sa_mcmember_rec rec; 4258c8f6a362SSean Hefty struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 4259c8f6a362SSean Hefty ib_sa_comp_mask comp_mask; 4260c8f6a362SSean Hefty int ret; 4261c8f6a362SSean Hefty 4262c8f6a362SSean Hefty ib_addr_get_mgid(dev_addr, &rec.mgid); 4263c8f6a362SSean Hefty ret = ib_sa_get_mcmember_rec(id_priv->id.device, id_priv->id.port_num, 4264c8f6a362SSean Hefty &rec.mgid, &rec); 4265c8f6a362SSean Hefty if (ret) 4266c8f6a362SSean Hefty return ret; 4267c8f6a362SSean Hefty 42685bc2b7b3SSean Hefty ret = cma_set_qkey(id_priv, 0); 42695bc2b7b3SSean Hefty if (ret) 42705bc2b7b3SSean Hefty return ret; 42715bc2b7b3SSean Hefty 42723f446754SRoland Dreier cma_set_mgid(id_priv, (struct sockaddr *) &mc->addr, &rec.mgid); 42735bc2b7b3SSean Hefty rec.qkey = cpu_to_be32(id_priv->qkey); 42746f8372b6SSean Hefty rdma_addr_get_sgid(dev_addr, &rec.port_gid); 4275c8f6a362SSean Hefty rec.pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr)); 4276ab15c95aSAlex Vesker rec.join_state = mc->join_state; 4277ab15c95aSAlex Vesker 4278ee1c60b1SDasaratharaman Chandramouli if ((rec.join_state == BIT(SENDONLY_FULLMEMBER_JOIN)) && 4279ee1c60b1SDasaratharaman Chandramouli (!ib_sa_sendonly_fullmem_support(&sa_client, 4280ee1c60b1SDasaratharaman Chandramouli id_priv->id.device, 4281ee1c60b1SDasaratharaman Chandramouli id_priv->id.port_num))) { 428243c7c851SJason Gunthorpe dev_warn( 428343c7c851SJason Gunthorpe &id_priv->id.device->dev, 428443c7c851SJason Gunthorpe "RDMA CM: port %u Unable to multicast join: SM doesn't support Send Only Full Member option\n", 428543c7c851SJason Gunthorpe id_priv->id.port_num); 4286ab15c95aSAlex Vesker return -EOPNOTSUPP; 4287ab15c95aSAlex Vesker } 4288c8f6a362SSean Hefty 4289c8f6a362SSean Hefty comp_mask = IB_SA_MCMEMBER_REC_MGID | IB_SA_MCMEMBER_REC_PORT_GID | 4290c8f6a362SSean Hefty IB_SA_MCMEMBER_REC_PKEY | IB_SA_MCMEMBER_REC_JOIN_STATE | 4291c8f6a362SSean Hefty IB_SA_MCMEMBER_REC_QKEY | IB_SA_MCMEMBER_REC_SL | 4292c8f6a362SSean Hefty IB_SA_MCMEMBER_REC_FLOW_LABEL | 4293c8f6a362SSean Hefty IB_SA_MCMEMBER_REC_TRAFFIC_CLASS; 4294c8f6a362SSean Hefty 429584adeee9SYossi Etigin if (id_priv->id.ps == RDMA_PS_IPOIB) 429684adeee9SYossi Etigin comp_mask |= IB_SA_MCMEMBER_REC_RATE | 42972a22fb8cSDotan Barak IB_SA_MCMEMBER_REC_RATE_SELECTOR | 42982a22fb8cSDotan Barak IB_SA_MCMEMBER_REC_MTU_SELECTOR | 42992a22fb8cSDotan Barak IB_SA_MCMEMBER_REC_MTU | 43002a22fb8cSDotan Barak IB_SA_MCMEMBER_REC_HOP_LIMIT; 430184adeee9SYossi Etigin 4302c8f6a362SSean Hefty mc->multicast.ib = ib_sa_join_multicast(&sa_client, id_priv->id.device, 4303c8f6a362SSean Hefty id_priv->id.port_num, &rec, 4304c8f6a362SSean Hefty comp_mask, GFP_KERNEL, 4305c8f6a362SSean Hefty cma_ib_mc_handler, mc); 43068c6ffba0SRusty Russell return PTR_ERR_OR_ZERO(mc->multicast.ib); 4307c8f6a362SSean Hefty } 4308c8f6a362SSean Hefty 43093c86aa70SEli Cohen static void iboe_mcast_work_handler(struct work_struct *work) 43103c86aa70SEli Cohen { 43113c86aa70SEli Cohen struct iboe_mcast_work *mw = container_of(work, struct iboe_mcast_work, work); 43123c86aa70SEli Cohen struct cma_multicast *mc = mw->mc; 43133c86aa70SEli Cohen struct ib_sa_multicast *m = mc->multicast.ib; 43143c86aa70SEli Cohen 43153c86aa70SEli Cohen mc->multicast.ib->context = mc; 43163c86aa70SEli Cohen cma_ib_mc_handler(0, m); 43173c86aa70SEli Cohen kref_put(&mc->mcref, release_mc); 43183c86aa70SEli Cohen kfree(mw); 43193c86aa70SEli Cohen } 43203c86aa70SEli Cohen 4321be1d325aSNoa Osherovich static void cma_iboe_set_mgid(struct sockaddr *addr, union ib_gid *mgid, 4322be1d325aSNoa Osherovich enum ib_gid_type gid_type) 43233c86aa70SEli Cohen { 43243c86aa70SEli Cohen struct sockaddr_in *sin = (struct sockaddr_in *)addr; 43253c86aa70SEli Cohen struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr; 43263c86aa70SEli Cohen 43273c86aa70SEli Cohen if (cma_any_addr(addr)) { 43283c86aa70SEli Cohen memset(mgid, 0, sizeof *mgid); 43293c86aa70SEli Cohen } else if (addr->sa_family == AF_INET6) { 43303c86aa70SEli Cohen memcpy(mgid, &sin6->sin6_addr, sizeof *mgid); 43313c86aa70SEli Cohen } else { 43325c181bdaSParav Pandit mgid->raw[0] = 43335c181bdaSParav Pandit (gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) ? 0 : 0xff; 43345c181bdaSParav Pandit mgid->raw[1] = 43355c181bdaSParav Pandit (gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) ? 0 : 0x0e; 43363c86aa70SEli Cohen mgid->raw[2] = 0; 43373c86aa70SEli Cohen mgid->raw[3] = 0; 43383c86aa70SEli Cohen mgid->raw[4] = 0; 43393c86aa70SEli Cohen mgid->raw[5] = 0; 43403c86aa70SEli Cohen mgid->raw[6] = 0; 43413c86aa70SEli Cohen mgid->raw[7] = 0; 43423c86aa70SEli Cohen mgid->raw[8] = 0; 43433c86aa70SEli Cohen mgid->raw[9] = 0; 43443c86aa70SEli Cohen mgid->raw[10] = 0xff; 43453c86aa70SEli Cohen mgid->raw[11] = 0xff; 43463c86aa70SEli Cohen *(__be32 *)(&mgid->raw[12]) = sin->sin_addr.s_addr; 43473c86aa70SEli Cohen } 43483c86aa70SEli Cohen } 43493c86aa70SEli Cohen 43503c86aa70SEli Cohen static int cma_iboe_join_multicast(struct rdma_id_private *id_priv, 43513c86aa70SEli Cohen struct cma_multicast *mc) 43523c86aa70SEli Cohen { 43533c86aa70SEli Cohen struct iboe_mcast_work *work; 43543c86aa70SEli Cohen struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 4355bee3c3c9SMoni Shoua int err = 0; 43563c86aa70SEli Cohen struct sockaddr *addr = (struct sockaddr *)&mc->addr; 43573c86aa70SEli Cohen struct net_device *ndev = NULL; 4358bee3c3c9SMoni Shoua enum ib_gid_type gid_type; 4359ab15c95aSAlex Vesker bool send_only; 4360ab15c95aSAlex Vesker 4361ab15c95aSAlex Vesker send_only = mc->join_state == BIT(SENDONLY_FULLMEMBER_JOIN); 43623c86aa70SEli Cohen 43633c86aa70SEli Cohen if (cma_zero_addr((struct sockaddr *)&mc->addr)) 43643c86aa70SEli Cohen return -EINVAL; 43653c86aa70SEli Cohen 43663c86aa70SEli Cohen work = kzalloc(sizeof *work, GFP_KERNEL); 43673c86aa70SEli Cohen if (!work) 43683c86aa70SEli Cohen return -ENOMEM; 43693c86aa70SEli Cohen 43703c86aa70SEli Cohen mc->multicast.ib = kzalloc(sizeof(struct ib_sa_multicast), GFP_KERNEL); 43713c86aa70SEli Cohen if (!mc->multicast.ib) { 43723c86aa70SEli Cohen err = -ENOMEM; 43733c86aa70SEli Cohen goto out1; 43743c86aa70SEli Cohen } 43753c86aa70SEli Cohen 4376be1d325aSNoa Osherovich gid_type = id_priv->cma_dev->default_gid_type[id_priv->id.port_num - 4377be1d325aSNoa Osherovich rdma_start_port(id_priv->cma_dev->device)]; 4378be1d325aSNoa Osherovich cma_iboe_set_mgid(addr, &mc->multicast.ib->rec.mgid, gid_type); 43793c86aa70SEli Cohen 43803c86aa70SEli Cohen mc->multicast.ib->rec.pkey = cpu_to_be16(0xffff); 43813c86aa70SEli Cohen if (id_priv->id.ps == RDMA_PS_UDP) 43823c86aa70SEli Cohen mc->multicast.ib->rec.qkey = cpu_to_be32(RDMA_UDP_QKEY); 43833c86aa70SEli Cohen 43843c86aa70SEli Cohen if (dev_addr->bound_dev_if) 4385052eac6eSParav Pandit ndev = dev_get_by_index(dev_addr->net, dev_addr->bound_dev_if); 43863c86aa70SEli Cohen if (!ndev) { 43873c86aa70SEli Cohen err = -ENODEV; 43883c86aa70SEli Cohen goto out2; 43893c86aa70SEli Cohen } 43903c86aa70SEli Cohen mc->multicast.ib->rec.rate = iboe_get_rate(ndev); 43913c86aa70SEli Cohen mc->multicast.ib->rec.hop_limit = 1; 43923c86aa70SEli Cohen mc->multicast.ib->rec.mtu = iboe_get_mtu(ndev->mtu); 4393bee3c3c9SMoni Shoua 4394bee3c3c9SMoni Shoua if (addr->sa_family == AF_INET) { 4395c65f6c5aSAlex Vesker if (gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) { 4396c65f6c5aSAlex Vesker mc->multicast.ib->rec.hop_limit = IPV6_DEFAULT_HOPLIMIT; 4397ab15c95aSAlex Vesker if (!send_only) { 4398bee3c3c9SMoni Shoua err = cma_igmp_send(ndev, &mc->multicast.ib->rec.mgid, 4399bee3c3c9SMoni Shoua true); 4400bee3c3c9SMoni Shoua } 4401bee3c3c9SMoni Shoua } 4402bee3c3c9SMoni Shoua } else { 4403bee3c3c9SMoni Shoua if (gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) 4404bee3c3c9SMoni Shoua err = -ENOTSUPP; 4405bee3c3c9SMoni Shoua } 44063c86aa70SEli Cohen dev_put(ndev); 4407bee3c3c9SMoni Shoua if (err || !mc->multicast.ib->rec.mtu) { 4408bee3c3c9SMoni Shoua if (!err) 44093c86aa70SEli Cohen err = -EINVAL; 44103c86aa70SEli Cohen goto out2; 44113c86aa70SEli Cohen } 44127b85627bSMoni Shoua rdma_ip2gid((struct sockaddr *)&id_priv->id.route.addr.src_addr, 44137b85627bSMoni Shoua &mc->multicast.ib->rec.port_gid); 44143c86aa70SEli Cohen work->id = id_priv; 44153c86aa70SEli Cohen work->mc = mc; 44163c86aa70SEli Cohen INIT_WORK(&work->work, iboe_mcast_work_handler); 44173c86aa70SEli Cohen kref_get(&mc->mcref); 44183c86aa70SEli Cohen queue_work(cma_wq, &work->work); 44193c86aa70SEli Cohen 44203c86aa70SEli Cohen return 0; 44213c86aa70SEli Cohen 44223c86aa70SEli Cohen out2: 44233c86aa70SEli Cohen kfree(mc->multicast.ib); 44243c86aa70SEli Cohen out1: 44253c86aa70SEli Cohen kfree(work); 44263c86aa70SEli Cohen return err; 44273c86aa70SEli Cohen } 44283c86aa70SEli Cohen 4429c8f6a362SSean Hefty int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr, 4430ab15c95aSAlex Vesker u8 join_state, void *context) 4431c8f6a362SSean Hefty { 4432c8f6a362SSean Hefty struct rdma_id_private *id_priv; 4433c8f6a362SSean Hefty struct cma_multicast *mc; 4434c8f6a362SSean Hefty int ret; 4435c8f6a362SSean Hefty 44367688f2c3SLeon Romanovsky if (!id->device) 44377688f2c3SLeon Romanovsky return -EINVAL; 44387688f2c3SLeon Romanovsky 4439c8f6a362SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 4440550e5ca7SNir Muchtar if (!cma_comp(id_priv, RDMA_CM_ADDR_BOUND) && 4441550e5ca7SNir Muchtar !cma_comp(id_priv, RDMA_CM_ADDR_RESOLVED)) 4442c8f6a362SSean Hefty return -EINVAL; 4443c8f6a362SSean Hefty 4444c8f6a362SSean Hefty mc = kmalloc(sizeof *mc, GFP_KERNEL); 4445c8f6a362SSean Hefty if (!mc) 4446c8f6a362SSean Hefty return -ENOMEM; 4447c8f6a362SSean Hefty 4448ef560861SSean Hefty memcpy(&mc->addr, addr, rdma_addr_size(addr)); 4449c8f6a362SSean Hefty mc->context = context; 4450c8f6a362SSean Hefty mc->id_priv = id_priv; 4451ab15c95aSAlex Vesker mc->join_state = join_state; 4452c8f6a362SSean Hefty 44535d9fb044SIra Weiny if (rdma_protocol_roce(id->device, id->port_num)) { 44543c86aa70SEli Cohen kref_init(&mc->mcref); 44553c86aa70SEli Cohen ret = cma_iboe_join_multicast(id_priv, mc); 4456c0126915SJason Gunthorpe if (ret) 4457c0126915SJason Gunthorpe goto out_err; 4458c0126915SJason Gunthorpe } else if (rdma_cap_ib_mcast(id->device, id->port_num)) { 44595c9a5282SMichael Wang ret = cma_join_ib_multicast(id_priv, mc); 4460c0126915SJason Gunthorpe if (ret) 4461c0126915SJason Gunthorpe goto out_err; 4462c0126915SJason Gunthorpe } else { 4463c8f6a362SSean Hefty ret = -ENOSYS; 4464c0126915SJason Gunthorpe goto out_err; 4465c8f6a362SSean Hefty } 4466c0126915SJason Gunthorpe 4467c0126915SJason Gunthorpe spin_lock(&id_priv->lock); 4468c0126915SJason Gunthorpe list_add(&mc->list, &id_priv->mc_list); 4469c0126915SJason Gunthorpe spin_unlock(&id_priv->lock); 4470c0126915SJason Gunthorpe 4471c0126915SJason Gunthorpe return 0; 4472c0126915SJason Gunthorpe out_err: 4473c0126915SJason Gunthorpe kfree(mc); 4474c8f6a362SSean Hefty return ret; 4475c8f6a362SSean Hefty } 4476c8f6a362SSean Hefty EXPORT_SYMBOL(rdma_join_multicast); 4477c8f6a362SSean Hefty 4478c8f6a362SSean Hefty void rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr) 4479c8f6a362SSean Hefty { 4480c8f6a362SSean Hefty struct rdma_id_private *id_priv; 4481c8f6a362SSean Hefty struct cma_multicast *mc; 4482c8f6a362SSean Hefty 4483c8f6a362SSean Hefty id_priv = container_of(id, struct rdma_id_private, id); 4484c8f6a362SSean Hefty spin_lock_irq(&id_priv->lock); 4485c8f6a362SSean Hefty list_for_each_entry(mc, &id_priv->mc_list, list) { 4486ef560861SSean Hefty if (!memcmp(&mc->addr, addr, rdma_addr_size(addr))) { 4487c8f6a362SSean Hefty list_del(&mc->list); 4488c8f6a362SSean Hefty spin_unlock_irq(&id_priv->lock); 4489c8f6a362SSean Hefty 4490c8f6a362SSean Hefty if (id->qp) 4491c8f6a362SSean Hefty ib_detach_mcast(id->qp, 4492c8f6a362SSean Hefty &mc->multicast.ib->rec.mgid, 449346ea5061SSean Hefty be16_to_cpu(mc->multicast.ib->rec.mlid)); 44945c9a5282SMichael Wang 44955c9a5282SMichael Wang BUG_ON(id_priv->cma_dev->device != id->device); 44965c9a5282SMichael Wang 4497a31ad3b0SMichael Wang if (rdma_cap_ib_mcast(id->device, id->port_num)) { 4498c8f6a362SSean Hefty ib_sa_free_multicast(mc->multicast.ib); 4499c8f6a362SSean Hefty kfree(mc); 4500bee3c3c9SMoni Shoua } else if (rdma_protocol_roce(id->device, id->port_num)) { 450188145678SParav Pandit cma_leave_roce_mc_group(id_priv, mc); 4502bee3c3c9SMoni Shoua } 4503c8f6a362SSean Hefty return; 4504c8f6a362SSean Hefty } 4505c8f6a362SSean Hefty } 4506c8f6a362SSean Hefty spin_unlock_irq(&id_priv->lock); 4507c8f6a362SSean Hefty } 4508c8f6a362SSean Hefty EXPORT_SYMBOL(rdma_leave_multicast); 4509c8f6a362SSean Hefty 4510dd5bdff8SOr Gerlitz static int cma_netdev_change(struct net_device *ndev, struct rdma_id_private *id_priv) 4511dd5bdff8SOr Gerlitz { 4512dd5bdff8SOr Gerlitz struct rdma_dev_addr *dev_addr; 4513dd5bdff8SOr Gerlitz struct cma_ndev_work *work; 4514dd5bdff8SOr Gerlitz 4515dd5bdff8SOr Gerlitz dev_addr = &id_priv->id.route.addr.dev_addr; 4516dd5bdff8SOr Gerlitz 45176266ed6eSSean Hefty if ((dev_addr->bound_dev_if == ndev->ifindex) && 4518fa20105eSGuy Shapiro (net_eq(dev_net(ndev), dev_addr->net)) && 4519dd5bdff8SOr Gerlitz memcmp(dev_addr->src_dev_addr, ndev->dev_addr, ndev->addr_len)) { 4520aba25a3eSParav Pandit pr_info("RDMA CM addr change for ndev %s used by id %p\n", 4521dd5bdff8SOr Gerlitz ndev->name, &id_priv->id); 4522dd5bdff8SOr Gerlitz work = kzalloc(sizeof *work, GFP_KERNEL); 4523dd5bdff8SOr Gerlitz if (!work) 4524dd5bdff8SOr Gerlitz return -ENOMEM; 4525dd5bdff8SOr Gerlitz 4526dd5bdff8SOr Gerlitz INIT_WORK(&work->work, cma_ndev_work_handler); 4527dd5bdff8SOr Gerlitz work->id = id_priv; 4528dd5bdff8SOr Gerlitz work->event.event = RDMA_CM_EVENT_ADDR_CHANGE; 4529dd5bdff8SOr Gerlitz atomic_inc(&id_priv->refcount); 4530dd5bdff8SOr Gerlitz queue_work(cma_wq, &work->work); 4531dd5bdff8SOr Gerlitz } 4532dd5bdff8SOr Gerlitz 4533dd5bdff8SOr Gerlitz return 0; 4534dd5bdff8SOr Gerlitz } 4535dd5bdff8SOr Gerlitz 4536dd5bdff8SOr Gerlitz static int cma_netdev_callback(struct notifier_block *self, unsigned long event, 4537351638e7SJiri Pirko void *ptr) 4538dd5bdff8SOr Gerlitz { 4539351638e7SJiri Pirko struct net_device *ndev = netdev_notifier_info_to_dev(ptr); 4540dd5bdff8SOr Gerlitz struct cma_device *cma_dev; 4541dd5bdff8SOr Gerlitz struct rdma_id_private *id_priv; 4542dd5bdff8SOr Gerlitz int ret = NOTIFY_DONE; 4543dd5bdff8SOr Gerlitz 4544dd5bdff8SOr Gerlitz if (event != NETDEV_BONDING_FAILOVER) 4545dd5bdff8SOr Gerlitz return NOTIFY_DONE; 4546dd5bdff8SOr Gerlitz 45473cd96fddSParav Pandit if (!netif_is_bond_master(ndev)) 4548dd5bdff8SOr Gerlitz return NOTIFY_DONE; 4549dd5bdff8SOr Gerlitz 4550dd5bdff8SOr Gerlitz mutex_lock(&lock); 4551dd5bdff8SOr Gerlitz list_for_each_entry(cma_dev, &dev_list, list) 4552dd5bdff8SOr Gerlitz list_for_each_entry(id_priv, &cma_dev->id_list, list) { 4553dd5bdff8SOr Gerlitz ret = cma_netdev_change(ndev, id_priv); 4554dd5bdff8SOr Gerlitz if (ret) 4555dd5bdff8SOr Gerlitz goto out; 4556dd5bdff8SOr Gerlitz } 4557dd5bdff8SOr Gerlitz 4558dd5bdff8SOr Gerlitz out: 4559dd5bdff8SOr Gerlitz mutex_unlock(&lock); 4560dd5bdff8SOr Gerlitz return ret; 4561dd5bdff8SOr Gerlitz } 4562dd5bdff8SOr Gerlitz 4563dd5bdff8SOr Gerlitz static struct notifier_block cma_nb = { 4564dd5bdff8SOr Gerlitz .notifier_call = cma_netdev_callback 4565dd5bdff8SOr Gerlitz }; 4566dd5bdff8SOr Gerlitz 4567e51060f0SSean Hefty static void cma_add_one(struct ib_device *device) 4568e51060f0SSean Hefty { 4569e51060f0SSean Hefty struct cma_device *cma_dev; 4570e51060f0SSean Hefty struct rdma_id_private *id_priv; 4571045959dbSMatan Barak unsigned int i; 4572045959dbSMatan Barak unsigned long supported_gids = 0; 4573e51060f0SSean Hefty 4574e51060f0SSean Hefty cma_dev = kmalloc(sizeof *cma_dev, GFP_KERNEL); 4575e51060f0SSean Hefty if (!cma_dev) 4576e51060f0SSean Hefty return; 4577e51060f0SSean Hefty 4578e51060f0SSean Hefty cma_dev->device = device; 4579045959dbSMatan Barak cma_dev->default_gid_type = kcalloc(device->phys_port_cnt, 4580045959dbSMatan Barak sizeof(*cma_dev->default_gid_type), 4581045959dbSMatan Barak GFP_KERNEL); 458289052d78SMajd Dibbiny if (!cma_dev->default_gid_type) 458389052d78SMajd Dibbiny goto free_cma_dev; 458489052d78SMajd Dibbiny 458589052d78SMajd Dibbiny cma_dev->default_roce_tos = kcalloc(device->phys_port_cnt, 458689052d78SMajd Dibbiny sizeof(*cma_dev->default_roce_tos), 458789052d78SMajd Dibbiny GFP_KERNEL); 458889052d78SMajd Dibbiny if (!cma_dev->default_roce_tos) 458989052d78SMajd Dibbiny goto free_gid_type; 459089052d78SMajd Dibbiny 4591ea1075edSJason Gunthorpe rdma_for_each_port (device, i) { 4592045959dbSMatan Barak supported_gids = roce_gid_type_mask_support(device, i); 4593045959dbSMatan Barak WARN_ON(!supported_gids); 45945ab2d89bSLeon Romanovsky if (supported_gids & (1 << CMA_PREFERRED_ROCE_GID_TYPE)) 459563a5f483SMoni Shoua cma_dev->default_gid_type[i - rdma_start_port(device)] = 459663a5f483SMoni Shoua CMA_PREFERRED_ROCE_GID_TYPE; 459763a5f483SMoni Shoua else 4598045959dbSMatan Barak cma_dev->default_gid_type[i - rdma_start_port(device)] = 4599045959dbSMatan Barak find_first_bit(&supported_gids, BITS_PER_LONG); 460089052d78SMajd Dibbiny cma_dev->default_roce_tos[i - rdma_start_port(device)] = 0; 4601045959dbSMatan Barak } 4602e51060f0SSean Hefty 4603e51060f0SSean Hefty init_completion(&cma_dev->comp); 4604e51060f0SSean Hefty atomic_set(&cma_dev->refcount, 1); 4605e51060f0SSean Hefty INIT_LIST_HEAD(&cma_dev->id_list); 4606e51060f0SSean Hefty ib_set_client_data(device, &cma_client, cma_dev); 4607e51060f0SSean Hefty 4608e51060f0SSean Hefty mutex_lock(&lock); 4609e51060f0SSean Hefty list_add_tail(&cma_dev->list, &dev_list); 4610e51060f0SSean Hefty list_for_each_entry(id_priv, &listen_any_list, list) 4611e51060f0SSean Hefty cma_listen_on_dev(id_priv, cma_dev); 4612e51060f0SSean Hefty mutex_unlock(&lock); 461389052d78SMajd Dibbiny 461489052d78SMajd Dibbiny return; 461589052d78SMajd Dibbiny 461689052d78SMajd Dibbiny free_gid_type: 461789052d78SMajd Dibbiny kfree(cma_dev->default_gid_type); 461889052d78SMajd Dibbiny 461989052d78SMajd Dibbiny free_cma_dev: 462089052d78SMajd Dibbiny kfree(cma_dev); 462189052d78SMajd Dibbiny 462289052d78SMajd Dibbiny return; 4623e51060f0SSean Hefty } 4624e51060f0SSean Hefty 4625e51060f0SSean Hefty static int cma_remove_id_dev(struct rdma_id_private *id_priv) 4626e51060f0SSean Hefty { 46277582df82SParav Pandit struct rdma_cm_event event = {}; 4628550e5ca7SNir Muchtar enum rdma_cm_state state; 4629de910bd9SOr Gerlitz int ret = 0; 4630e51060f0SSean Hefty 4631e51060f0SSean Hefty /* Record that we want to remove the device */ 4632550e5ca7SNir Muchtar state = cma_exch(id_priv, RDMA_CM_DEVICE_REMOVAL); 4633550e5ca7SNir Muchtar if (state == RDMA_CM_DESTROYING) 4634e51060f0SSean Hefty return 0; 4635e51060f0SSean Hefty 4636e51060f0SSean Hefty cma_cancel_operation(id_priv, state); 4637de910bd9SOr Gerlitz mutex_lock(&id_priv->handler_mutex); 4638e51060f0SSean Hefty 4639e51060f0SSean Hefty /* Check for destruction from another callback. */ 4640550e5ca7SNir Muchtar if (!cma_comp(id_priv, RDMA_CM_DEVICE_REMOVAL)) 4641de910bd9SOr Gerlitz goto out; 4642e51060f0SSean Hefty 4643a1b1b61fSSean Hefty event.event = RDMA_CM_EVENT_DEVICE_REMOVAL; 4644de910bd9SOr Gerlitz ret = id_priv->id.event_handler(&id_priv->id, &event); 4645de910bd9SOr Gerlitz out: 4646de910bd9SOr Gerlitz mutex_unlock(&id_priv->handler_mutex); 4647de910bd9SOr Gerlitz return ret; 4648e51060f0SSean Hefty } 4649e51060f0SSean Hefty 4650e51060f0SSean Hefty static void cma_process_remove(struct cma_device *cma_dev) 4651e51060f0SSean Hefty { 4652e51060f0SSean Hefty struct rdma_id_private *id_priv; 4653e51060f0SSean Hefty int ret; 4654e51060f0SSean Hefty 4655e51060f0SSean Hefty mutex_lock(&lock); 4656e51060f0SSean Hefty while (!list_empty(&cma_dev->id_list)) { 4657e51060f0SSean Hefty id_priv = list_entry(cma_dev->id_list.next, 4658e51060f0SSean Hefty struct rdma_id_private, list); 4659e51060f0SSean Hefty 4660d02d1f53SSean Hefty list_del(&id_priv->listen_list); 466194de178aSKrishna Kumar list_del_init(&id_priv->list); 4662e51060f0SSean Hefty atomic_inc(&id_priv->refcount); 4663e51060f0SSean Hefty mutex_unlock(&lock); 4664e51060f0SSean Hefty 4665d02d1f53SSean Hefty ret = id_priv->internal_id ? 1 : cma_remove_id_dev(id_priv); 4666e51060f0SSean Hefty cma_deref_id(id_priv); 4667e51060f0SSean Hefty if (ret) 4668e51060f0SSean Hefty rdma_destroy_id(&id_priv->id); 4669e51060f0SSean Hefty 4670e51060f0SSean Hefty mutex_lock(&lock); 4671e51060f0SSean Hefty } 4672e51060f0SSean Hefty mutex_unlock(&lock); 4673e51060f0SSean Hefty 4674e51060f0SSean Hefty cma_deref_dev(cma_dev); 4675e51060f0SSean Hefty wait_for_completion(&cma_dev->comp); 4676e51060f0SSean Hefty } 4677e51060f0SSean Hefty 46787c1eb45aSHaggai Eran static void cma_remove_one(struct ib_device *device, void *client_data) 4679e51060f0SSean Hefty { 46807c1eb45aSHaggai Eran struct cma_device *cma_dev = client_data; 4681e51060f0SSean Hefty 4682e51060f0SSean Hefty if (!cma_dev) 4683e51060f0SSean Hefty return; 4684e51060f0SSean Hefty 4685e51060f0SSean Hefty mutex_lock(&lock); 4686e51060f0SSean Hefty list_del(&cma_dev->list); 4687e51060f0SSean Hefty mutex_unlock(&lock); 4688e51060f0SSean Hefty 4689e51060f0SSean Hefty cma_process_remove(cma_dev); 469089052d78SMajd Dibbiny kfree(cma_dev->default_roce_tos); 4691045959dbSMatan Barak kfree(cma_dev->default_gid_type); 4692e51060f0SSean Hefty kfree(cma_dev); 4693e51060f0SSean Hefty } 4694e51060f0SSean Hefty 46954be74b42SHaggai Eran static int cma_init_net(struct net *net) 46964be74b42SHaggai Eran { 46974be74b42SHaggai Eran struct cma_pernet *pernet = cma_pernet(net); 46984be74b42SHaggai Eran 469963826753SMatthew Wilcox xa_init(&pernet->tcp_ps); 470063826753SMatthew Wilcox xa_init(&pernet->udp_ps); 470163826753SMatthew Wilcox xa_init(&pernet->ipoib_ps); 470263826753SMatthew Wilcox xa_init(&pernet->ib_ps); 47034be74b42SHaggai Eran 47044be74b42SHaggai Eran return 0; 47054be74b42SHaggai Eran } 47064be74b42SHaggai Eran 47074be74b42SHaggai Eran static void cma_exit_net(struct net *net) 47084be74b42SHaggai Eran { 47094be74b42SHaggai Eran struct cma_pernet *pernet = cma_pernet(net); 47104be74b42SHaggai Eran 471163826753SMatthew Wilcox WARN_ON(!xa_empty(&pernet->tcp_ps)); 471263826753SMatthew Wilcox WARN_ON(!xa_empty(&pernet->udp_ps)); 471363826753SMatthew Wilcox WARN_ON(!xa_empty(&pernet->ipoib_ps)); 471463826753SMatthew Wilcox WARN_ON(!xa_empty(&pernet->ib_ps)); 47154be74b42SHaggai Eran } 47164be74b42SHaggai Eran 47174be74b42SHaggai Eran static struct pernet_operations cma_pernet_operations = { 47184be74b42SHaggai Eran .init = cma_init_net, 47194be74b42SHaggai Eran .exit = cma_exit_net, 47204be74b42SHaggai Eran .id = &cma_pernet_id, 47214be74b42SHaggai Eran .size = sizeof(struct cma_pernet), 47224be74b42SHaggai Eran }; 47234be74b42SHaggai Eran 4724716abb1fSPeter Huewe static int __init cma_init(void) 4725e51060f0SSean Hefty { 47265d7220e8STetsuo Handa int ret; 4727227b60f5SStephen Hemminger 4728dee9acbbSBhaktipriya Shridhar cma_wq = alloc_ordered_workqueue("rdma_cm", WQ_MEM_RECLAIM); 4729e51060f0SSean Hefty if (!cma_wq) 4730e51060f0SSean Hefty return -ENOMEM; 4731e51060f0SSean Hefty 47324be74b42SHaggai Eran ret = register_pernet_subsys(&cma_pernet_operations); 47334be74b42SHaggai Eran if (ret) 47344be74b42SHaggai Eran goto err_wq; 47354be74b42SHaggai Eran 4736c1a0b23bSMichael S. Tsirkin ib_sa_register_client(&sa_client); 4737dd5bdff8SOr Gerlitz register_netdevice_notifier(&cma_nb); 4738c1a0b23bSMichael S. Tsirkin 4739e51060f0SSean Hefty ret = ib_register_client(&cma_client); 4740e51060f0SSean Hefty if (ret) 4741e51060f0SSean Hefty goto err; 4742753f618aSNir Muchtar 4743a7bfb93fSzhengbin ret = cma_configfs_init(); 4744a7bfb93fSzhengbin if (ret) 4745a7bfb93fSzhengbin goto err_ib; 4746753f618aSNir Muchtar 4747e51060f0SSean Hefty return 0; 4748e51060f0SSean Hefty 4749a7bfb93fSzhengbin err_ib: 4750a7bfb93fSzhengbin ib_unregister_client(&cma_client); 4751e51060f0SSean Hefty err: 4752dd5bdff8SOr Gerlitz unregister_netdevice_notifier(&cma_nb); 4753c1a0b23bSMichael S. Tsirkin ib_sa_unregister_client(&sa_client); 47544be74b42SHaggai Eran err_wq: 4755e51060f0SSean Hefty destroy_workqueue(cma_wq); 4756e51060f0SSean Hefty return ret; 4757e51060f0SSean Hefty } 4758e51060f0SSean Hefty 4759716abb1fSPeter Huewe static void __exit cma_cleanup(void) 4760e51060f0SSean Hefty { 4761045959dbSMatan Barak cma_configfs_exit(); 4762e51060f0SSean Hefty ib_unregister_client(&cma_client); 4763dd5bdff8SOr Gerlitz unregister_netdevice_notifier(&cma_nb); 4764c1a0b23bSMichael S. Tsirkin ib_sa_unregister_client(&sa_client); 47654be74b42SHaggai Eran unregister_pernet_subsys(&cma_pernet_operations); 4766e51060f0SSean Hefty destroy_workqueue(cma_wq); 4767e51060f0SSean Hefty } 4768e51060f0SSean Hefty 4769e51060f0SSean Hefty module_init(cma_init); 4770e51060f0SSean Hefty module_exit(cma_cleanup); 4771