162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2005 Voltaire Inc. All rights reserved. 462306a36Sopenharmony_ci * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. 562306a36Sopenharmony_ci * Copyright (c) 1999-2019, Mellanox Technologies, Inc. All rights reserved. 662306a36Sopenharmony_ci * Copyright (c) 2005-2006 Intel Corporation. All rights reserved. 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/completion.h> 1062306a36Sopenharmony_ci#include <linux/in.h> 1162306a36Sopenharmony_ci#include <linux/in6.h> 1262306a36Sopenharmony_ci#include <linux/mutex.h> 1362306a36Sopenharmony_ci#include <linux/random.h> 1462306a36Sopenharmony_ci#include <linux/rbtree.h> 1562306a36Sopenharmony_ci#include <linux/igmp.h> 1662306a36Sopenharmony_ci#include <linux/xarray.h> 1762306a36Sopenharmony_ci#include <linux/inetdevice.h> 1862306a36Sopenharmony_ci#include <linux/slab.h> 1962306a36Sopenharmony_ci#include <linux/module.h> 2062306a36Sopenharmony_ci#include <net/route.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include <net/net_namespace.h> 2362306a36Sopenharmony_ci#include <net/netns/generic.h> 2462306a36Sopenharmony_ci#include <net/netevent.h> 2562306a36Sopenharmony_ci#include <net/tcp.h> 2662306a36Sopenharmony_ci#include <net/ipv6.h> 2762306a36Sopenharmony_ci#include <net/ip_fib.h> 2862306a36Sopenharmony_ci#include <net/ip6_route.h> 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#include <rdma/rdma_cm.h> 3162306a36Sopenharmony_ci#include <rdma/rdma_cm_ib.h> 3262306a36Sopenharmony_ci#include <rdma/rdma_netlink.h> 3362306a36Sopenharmony_ci#include <rdma/ib.h> 3462306a36Sopenharmony_ci#include <rdma/ib_cache.h> 3562306a36Sopenharmony_ci#include <rdma/ib_cm.h> 3662306a36Sopenharmony_ci#include <rdma/ib_sa.h> 3762306a36Sopenharmony_ci#include <rdma/iw_cm.h> 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#include "core_priv.h" 4062306a36Sopenharmony_ci#include "cma_priv.h" 4162306a36Sopenharmony_ci#include "cma_trace.h" 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ciMODULE_AUTHOR("Sean Hefty"); 4462306a36Sopenharmony_ciMODULE_DESCRIPTION("Generic RDMA CM Agent"); 4562306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#define CMA_CM_RESPONSE_TIMEOUT 20 4862306a36Sopenharmony_ci#define CMA_MAX_CM_RETRIES 15 4962306a36Sopenharmony_ci#define CMA_CM_MRA_SETTING (IB_CM_MRA_FLAG_DELAY | 24) 5062306a36Sopenharmony_ci#define CMA_IBOE_PACKET_LIFETIME 16 5162306a36Sopenharmony_ci#define CMA_PREFERRED_ROCE_GID_TYPE IB_GID_TYPE_ROCE_UDP_ENCAP 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic const char * const cma_events[] = { 5462306a36Sopenharmony_ci [RDMA_CM_EVENT_ADDR_RESOLVED] = "address resolved", 5562306a36Sopenharmony_ci [RDMA_CM_EVENT_ADDR_ERROR] = "address error", 5662306a36Sopenharmony_ci [RDMA_CM_EVENT_ROUTE_RESOLVED] = "route resolved ", 5762306a36Sopenharmony_ci [RDMA_CM_EVENT_ROUTE_ERROR] = "route error", 5862306a36Sopenharmony_ci [RDMA_CM_EVENT_CONNECT_REQUEST] = "connect request", 5962306a36Sopenharmony_ci [RDMA_CM_EVENT_CONNECT_RESPONSE] = "connect response", 6062306a36Sopenharmony_ci [RDMA_CM_EVENT_CONNECT_ERROR] = "connect error", 6162306a36Sopenharmony_ci [RDMA_CM_EVENT_UNREACHABLE] = "unreachable", 6262306a36Sopenharmony_ci [RDMA_CM_EVENT_REJECTED] = "rejected", 6362306a36Sopenharmony_ci [RDMA_CM_EVENT_ESTABLISHED] = "established", 6462306a36Sopenharmony_ci [RDMA_CM_EVENT_DISCONNECTED] = "disconnected", 6562306a36Sopenharmony_ci [RDMA_CM_EVENT_DEVICE_REMOVAL] = "device removal", 6662306a36Sopenharmony_ci [RDMA_CM_EVENT_MULTICAST_JOIN] = "multicast join", 6762306a36Sopenharmony_ci [RDMA_CM_EVENT_MULTICAST_ERROR] = "multicast error", 6862306a36Sopenharmony_ci [RDMA_CM_EVENT_ADDR_CHANGE] = "address change", 6962306a36Sopenharmony_ci [RDMA_CM_EVENT_TIMEWAIT_EXIT] = "timewait exit", 7062306a36Sopenharmony_ci}; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic void cma_iboe_set_mgid(struct sockaddr *addr, union ib_gid *mgid, 7362306a36Sopenharmony_ci enum ib_gid_type gid_type); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ciconst char *__attribute_const__ rdma_event_msg(enum rdma_cm_event_type event) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci size_t index = event; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci return (index < ARRAY_SIZE(cma_events) && cma_events[index]) ? 8062306a36Sopenharmony_ci cma_events[index] : "unrecognized event"; 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_event_msg); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ciconst char *__attribute_const__ rdma_reject_msg(struct rdma_cm_id *id, 8562306a36Sopenharmony_ci int reason) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci if (rdma_ib_or_roce(id->device, id->port_num)) 8862306a36Sopenharmony_ci return ibcm_reject_msg(reason); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci if (rdma_protocol_iwarp(id->device, id->port_num)) 9162306a36Sopenharmony_ci return iwcm_reject_msg(reason); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci WARN_ON_ONCE(1); 9462306a36Sopenharmony_ci return "unrecognized transport"; 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_reject_msg); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci/** 9962306a36Sopenharmony_ci * rdma_is_consumer_reject - return true if the consumer rejected the connect 10062306a36Sopenharmony_ci * request. 10162306a36Sopenharmony_ci * @id: Communication identifier that received the REJECT event. 10262306a36Sopenharmony_ci * @reason: Value returned in the REJECT event status field. 10362306a36Sopenharmony_ci */ 10462306a36Sopenharmony_cistatic bool rdma_is_consumer_reject(struct rdma_cm_id *id, int reason) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci if (rdma_ib_or_roce(id->device, id->port_num)) 10762306a36Sopenharmony_ci return reason == IB_CM_REJ_CONSUMER_DEFINED; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci if (rdma_protocol_iwarp(id->device, id->port_num)) 11062306a36Sopenharmony_ci return reason == -ECONNREFUSED; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci WARN_ON_ONCE(1); 11362306a36Sopenharmony_ci return false; 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ciconst void *rdma_consumer_reject_data(struct rdma_cm_id *id, 11762306a36Sopenharmony_ci struct rdma_cm_event *ev, u8 *data_len) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci const void *p; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci if (rdma_is_consumer_reject(id, ev->status)) { 12262306a36Sopenharmony_ci *data_len = ev->param.conn.private_data_len; 12362306a36Sopenharmony_ci p = ev->param.conn.private_data; 12462306a36Sopenharmony_ci } else { 12562306a36Sopenharmony_ci *data_len = 0; 12662306a36Sopenharmony_ci p = NULL; 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci return p; 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_consumer_reject_data); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci/** 13362306a36Sopenharmony_ci * rdma_iw_cm_id() - return the iw_cm_id pointer for this cm_id. 13462306a36Sopenharmony_ci * @id: Communication Identifier 13562306a36Sopenharmony_ci */ 13662306a36Sopenharmony_cistruct iw_cm_id *rdma_iw_cm_id(struct rdma_cm_id *id) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci struct rdma_id_private *id_priv; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci id_priv = container_of(id, struct rdma_id_private, id); 14162306a36Sopenharmony_ci if (id->device->node_type == RDMA_NODE_RNIC) 14262306a36Sopenharmony_ci return id_priv->cm_id.iw; 14362306a36Sopenharmony_ci return NULL; 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_iw_cm_id); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci/** 14862306a36Sopenharmony_ci * rdma_res_to_id() - return the rdma_cm_id pointer for this restrack. 14962306a36Sopenharmony_ci * @res: rdma resource tracking entry pointer 15062306a36Sopenharmony_ci */ 15162306a36Sopenharmony_cistruct rdma_cm_id *rdma_res_to_id(struct rdma_restrack_entry *res) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci struct rdma_id_private *id_priv = 15462306a36Sopenharmony_ci container_of(res, struct rdma_id_private, res); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci return &id_priv->id; 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_res_to_id); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistatic int cma_add_one(struct ib_device *device); 16162306a36Sopenharmony_cistatic void cma_remove_one(struct ib_device *device, void *client_data); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_cistatic struct ib_client cma_client = { 16462306a36Sopenharmony_ci .name = "cma", 16562306a36Sopenharmony_ci .add = cma_add_one, 16662306a36Sopenharmony_ci .remove = cma_remove_one 16762306a36Sopenharmony_ci}; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic struct ib_sa_client sa_client; 17062306a36Sopenharmony_cistatic LIST_HEAD(dev_list); 17162306a36Sopenharmony_cistatic LIST_HEAD(listen_any_list); 17262306a36Sopenharmony_cistatic DEFINE_MUTEX(lock); 17362306a36Sopenharmony_cistatic struct rb_root id_table = RB_ROOT; 17462306a36Sopenharmony_ci/* Serialize operations of id_table tree */ 17562306a36Sopenharmony_cistatic DEFINE_SPINLOCK(id_table_lock); 17662306a36Sopenharmony_cistatic struct workqueue_struct *cma_wq; 17762306a36Sopenharmony_cistatic unsigned int cma_pernet_id; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cistruct cma_pernet { 18062306a36Sopenharmony_ci struct xarray tcp_ps; 18162306a36Sopenharmony_ci struct xarray udp_ps; 18262306a36Sopenharmony_ci struct xarray ipoib_ps; 18362306a36Sopenharmony_ci struct xarray ib_ps; 18462306a36Sopenharmony_ci}; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_cistatic struct cma_pernet *cma_pernet(struct net *net) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci return net_generic(net, cma_pernet_id); 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistatic 19262306a36Sopenharmony_cistruct xarray *cma_pernet_xa(struct net *net, enum rdma_ucm_port_space ps) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci struct cma_pernet *pernet = cma_pernet(net); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci switch (ps) { 19762306a36Sopenharmony_ci case RDMA_PS_TCP: 19862306a36Sopenharmony_ci return &pernet->tcp_ps; 19962306a36Sopenharmony_ci case RDMA_PS_UDP: 20062306a36Sopenharmony_ci return &pernet->udp_ps; 20162306a36Sopenharmony_ci case RDMA_PS_IPOIB: 20262306a36Sopenharmony_ci return &pernet->ipoib_ps; 20362306a36Sopenharmony_ci case RDMA_PS_IB: 20462306a36Sopenharmony_ci return &pernet->ib_ps; 20562306a36Sopenharmony_ci default: 20662306a36Sopenharmony_ci return NULL; 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistruct id_table_entry { 21162306a36Sopenharmony_ci struct list_head id_list; 21262306a36Sopenharmony_ci struct rb_node rb_node; 21362306a36Sopenharmony_ci}; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistruct cma_device { 21662306a36Sopenharmony_ci struct list_head list; 21762306a36Sopenharmony_ci struct ib_device *device; 21862306a36Sopenharmony_ci struct completion comp; 21962306a36Sopenharmony_ci refcount_t refcount; 22062306a36Sopenharmony_ci struct list_head id_list; 22162306a36Sopenharmony_ci enum ib_gid_type *default_gid_type; 22262306a36Sopenharmony_ci u8 *default_roce_tos; 22362306a36Sopenharmony_ci}; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_cistruct rdma_bind_list { 22662306a36Sopenharmony_ci enum rdma_ucm_port_space ps; 22762306a36Sopenharmony_ci struct hlist_head owners; 22862306a36Sopenharmony_ci unsigned short port; 22962306a36Sopenharmony_ci}; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cistatic int cma_ps_alloc(struct net *net, enum rdma_ucm_port_space ps, 23262306a36Sopenharmony_ci struct rdma_bind_list *bind_list, int snum) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci struct xarray *xa = cma_pernet_xa(net, ps); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci return xa_insert(xa, snum, bind_list, GFP_KERNEL); 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic struct rdma_bind_list *cma_ps_find(struct net *net, 24062306a36Sopenharmony_ci enum rdma_ucm_port_space ps, int snum) 24162306a36Sopenharmony_ci{ 24262306a36Sopenharmony_ci struct xarray *xa = cma_pernet_xa(net, ps); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci return xa_load(xa, snum); 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cistatic void cma_ps_remove(struct net *net, enum rdma_ucm_port_space ps, 24862306a36Sopenharmony_ci int snum) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci struct xarray *xa = cma_pernet_xa(net, ps); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci xa_erase(xa, snum); 25362306a36Sopenharmony_ci} 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_cienum { 25662306a36Sopenharmony_ci CMA_OPTION_AFONLY, 25762306a36Sopenharmony_ci}; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_civoid cma_dev_get(struct cma_device *cma_dev) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci refcount_inc(&cma_dev->refcount); 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_civoid cma_dev_put(struct cma_device *cma_dev) 26562306a36Sopenharmony_ci{ 26662306a36Sopenharmony_ci if (refcount_dec_and_test(&cma_dev->refcount)) 26762306a36Sopenharmony_ci complete(&cma_dev->comp); 26862306a36Sopenharmony_ci} 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_cistruct cma_device *cma_enum_devices_by_ibdev(cma_device_filter filter, 27162306a36Sopenharmony_ci void *cookie) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci struct cma_device *cma_dev; 27462306a36Sopenharmony_ci struct cma_device *found_cma_dev = NULL; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci mutex_lock(&lock); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci list_for_each_entry(cma_dev, &dev_list, list) 27962306a36Sopenharmony_ci if (filter(cma_dev->device, cookie)) { 28062306a36Sopenharmony_ci found_cma_dev = cma_dev; 28162306a36Sopenharmony_ci break; 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci if (found_cma_dev) 28562306a36Sopenharmony_ci cma_dev_get(found_cma_dev); 28662306a36Sopenharmony_ci mutex_unlock(&lock); 28762306a36Sopenharmony_ci return found_cma_dev; 28862306a36Sopenharmony_ci} 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ciint cma_get_default_gid_type(struct cma_device *cma_dev, 29162306a36Sopenharmony_ci u32 port) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci if (!rdma_is_port_valid(cma_dev->device, port)) 29462306a36Sopenharmony_ci return -EINVAL; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci return cma_dev->default_gid_type[port - rdma_start_port(cma_dev->device)]; 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ciint cma_set_default_gid_type(struct cma_device *cma_dev, 30062306a36Sopenharmony_ci u32 port, 30162306a36Sopenharmony_ci enum ib_gid_type default_gid_type) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci unsigned long supported_gids; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci if (!rdma_is_port_valid(cma_dev->device, port)) 30662306a36Sopenharmony_ci return -EINVAL; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci if (default_gid_type == IB_GID_TYPE_IB && 30962306a36Sopenharmony_ci rdma_protocol_roce_eth_encap(cma_dev->device, port)) 31062306a36Sopenharmony_ci default_gid_type = IB_GID_TYPE_ROCE; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci supported_gids = roce_gid_type_mask_support(cma_dev->device, port); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci if (!(supported_gids & 1 << default_gid_type)) 31562306a36Sopenharmony_ci return -EINVAL; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci cma_dev->default_gid_type[port - rdma_start_port(cma_dev->device)] = 31862306a36Sopenharmony_ci default_gid_type; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci return 0; 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ciint cma_get_default_roce_tos(struct cma_device *cma_dev, u32 port) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci if (!rdma_is_port_valid(cma_dev->device, port)) 32662306a36Sopenharmony_ci return -EINVAL; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci return cma_dev->default_roce_tos[port - rdma_start_port(cma_dev->device)]; 32962306a36Sopenharmony_ci} 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ciint cma_set_default_roce_tos(struct cma_device *cma_dev, u32 port, 33262306a36Sopenharmony_ci u8 default_roce_tos) 33362306a36Sopenharmony_ci{ 33462306a36Sopenharmony_ci if (!rdma_is_port_valid(cma_dev->device, port)) 33562306a36Sopenharmony_ci return -EINVAL; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci cma_dev->default_roce_tos[port - rdma_start_port(cma_dev->device)] = 33862306a36Sopenharmony_ci default_roce_tos; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci return 0; 34162306a36Sopenharmony_ci} 34262306a36Sopenharmony_cistruct ib_device *cma_get_ib_dev(struct cma_device *cma_dev) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci return cma_dev->device; 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci/* 34862306a36Sopenharmony_ci * Device removal can occur at anytime, so we need extra handling to 34962306a36Sopenharmony_ci * serialize notifying the user of device removal with other callbacks. 35062306a36Sopenharmony_ci * We do this by disabling removal notification while a callback is in process, 35162306a36Sopenharmony_ci * and reporting it after the callback completes. 35262306a36Sopenharmony_ci */ 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_cistruct cma_multicast { 35562306a36Sopenharmony_ci struct rdma_id_private *id_priv; 35662306a36Sopenharmony_ci union { 35762306a36Sopenharmony_ci struct ib_sa_multicast *sa_mc; 35862306a36Sopenharmony_ci struct { 35962306a36Sopenharmony_ci struct work_struct work; 36062306a36Sopenharmony_ci struct rdma_cm_event event; 36162306a36Sopenharmony_ci } iboe_join; 36262306a36Sopenharmony_ci }; 36362306a36Sopenharmony_ci struct list_head list; 36462306a36Sopenharmony_ci void *context; 36562306a36Sopenharmony_ci struct sockaddr_storage addr; 36662306a36Sopenharmony_ci u8 join_state; 36762306a36Sopenharmony_ci}; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_cistruct cma_work { 37062306a36Sopenharmony_ci struct work_struct work; 37162306a36Sopenharmony_ci struct rdma_id_private *id; 37262306a36Sopenharmony_ci enum rdma_cm_state old_state; 37362306a36Sopenharmony_ci enum rdma_cm_state new_state; 37462306a36Sopenharmony_ci struct rdma_cm_event event; 37562306a36Sopenharmony_ci}; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ciunion cma_ip_addr { 37862306a36Sopenharmony_ci struct in6_addr ip6; 37962306a36Sopenharmony_ci struct { 38062306a36Sopenharmony_ci __be32 pad[3]; 38162306a36Sopenharmony_ci __be32 addr; 38262306a36Sopenharmony_ci } ip4; 38362306a36Sopenharmony_ci}; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_cistruct cma_hdr { 38662306a36Sopenharmony_ci u8 cma_version; 38762306a36Sopenharmony_ci u8 ip_version; /* IP version: 7:4 */ 38862306a36Sopenharmony_ci __be16 port; 38962306a36Sopenharmony_ci union cma_ip_addr src_addr; 39062306a36Sopenharmony_ci union cma_ip_addr dst_addr; 39162306a36Sopenharmony_ci}; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci#define CMA_VERSION 0x00 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_cistruct cma_req_info { 39662306a36Sopenharmony_ci struct sockaddr_storage listen_addr_storage; 39762306a36Sopenharmony_ci struct sockaddr_storage src_addr_storage; 39862306a36Sopenharmony_ci struct ib_device *device; 39962306a36Sopenharmony_ci union ib_gid local_gid; 40062306a36Sopenharmony_ci __be64 service_id; 40162306a36Sopenharmony_ci int port; 40262306a36Sopenharmony_ci bool has_gid; 40362306a36Sopenharmony_ci u16 pkey; 40462306a36Sopenharmony_ci}; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cistatic int cma_comp_exch(struct rdma_id_private *id_priv, 40762306a36Sopenharmony_ci enum rdma_cm_state comp, enum rdma_cm_state exch) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci unsigned long flags; 41062306a36Sopenharmony_ci int ret; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci /* 41362306a36Sopenharmony_ci * The FSM uses a funny double locking where state is protected by both 41462306a36Sopenharmony_ci * the handler_mutex and the spinlock. State is not allowed to change 41562306a36Sopenharmony_ci * to/from a handler_mutex protected value without also holding 41662306a36Sopenharmony_ci * handler_mutex. 41762306a36Sopenharmony_ci */ 41862306a36Sopenharmony_ci if (comp == RDMA_CM_CONNECT || exch == RDMA_CM_CONNECT) 41962306a36Sopenharmony_ci lockdep_assert_held(&id_priv->handler_mutex); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci spin_lock_irqsave(&id_priv->lock, flags); 42262306a36Sopenharmony_ci if ((ret = (id_priv->state == comp))) 42362306a36Sopenharmony_ci id_priv->state = exch; 42462306a36Sopenharmony_ci spin_unlock_irqrestore(&id_priv->lock, flags); 42562306a36Sopenharmony_ci return ret; 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic inline u8 cma_get_ip_ver(const struct cma_hdr *hdr) 42962306a36Sopenharmony_ci{ 43062306a36Sopenharmony_ci return hdr->ip_version >> 4; 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_cistatic void cma_set_ip_ver(struct cma_hdr *hdr, u8 ip_ver) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci hdr->ip_version = (ip_ver << 4) | (hdr->ip_version & 0xF); 43662306a36Sopenharmony_ci} 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_cistatic struct sockaddr *cma_src_addr(struct rdma_id_private *id_priv) 43962306a36Sopenharmony_ci{ 44062306a36Sopenharmony_ci return (struct sockaddr *)&id_priv->id.route.addr.src_addr; 44162306a36Sopenharmony_ci} 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_cistatic inline struct sockaddr *cma_dst_addr(struct rdma_id_private *id_priv) 44462306a36Sopenharmony_ci{ 44562306a36Sopenharmony_ci return (struct sockaddr *)&id_priv->id.route.addr.dst_addr; 44662306a36Sopenharmony_ci} 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_cistatic int cma_igmp_send(struct net_device *ndev, union ib_gid *mgid, bool join) 44962306a36Sopenharmony_ci{ 45062306a36Sopenharmony_ci struct in_device *in_dev = NULL; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci if (ndev) { 45362306a36Sopenharmony_ci rtnl_lock(); 45462306a36Sopenharmony_ci in_dev = __in_dev_get_rtnl(ndev); 45562306a36Sopenharmony_ci if (in_dev) { 45662306a36Sopenharmony_ci if (join) 45762306a36Sopenharmony_ci ip_mc_inc_group(in_dev, 45862306a36Sopenharmony_ci *(__be32 *)(mgid->raw + 12)); 45962306a36Sopenharmony_ci else 46062306a36Sopenharmony_ci ip_mc_dec_group(in_dev, 46162306a36Sopenharmony_ci *(__be32 *)(mgid->raw + 12)); 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci rtnl_unlock(); 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci return (in_dev) ? 0 : -ENODEV; 46662306a36Sopenharmony_ci} 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_cistatic int compare_netdev_and_ip(int ifindex_a, struct sockaddr *sa, 46962306a36Sopenharmony_ci struct id_table_entry *entry_b) 47062306a36Sopenharmony_ci{ 47162306a36Sopenharmony_ci struct rdma_id_private *id_priv = list_first_entry( 47262306a36Sopenharmony_ci &entry_b->id_list, struct rdma_id_private, id_list_entry); 47362306a36Sopenharmony_ci int ifindex_b = id_priv->id.route.addr.dev_addr.bound_dev_if; 47462306a36Sopenharmony_ci struct sockaddr *sb = cma_dst_addr(id_priv); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci if (ifindex_a != ifindex_b) 47762306a36Sopenharmony_ci return (ifindex_a > ifindex_b) ? 1 : -1; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci if (sa->sa_family != sb->sa_family) 48062306a36Sopenharmony_ci return sa->sa_family - sb->sa_family; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci if (sa->sa_family == AF_INET && 48362306a36Sopenharmony_ci __builtin_object_size(sa, 0) >= sizeof(struct sockaddr_in)) { 48462306a36Sopenharmony_ci return memcmp(&((struct sockaddr_in *)sa)->sin_addr, 48562306a36Sopenharmony_ci &((struct sockaddr_in *)sb)->sin_addr, 48662306a36Sopenharmony_ci sizeof(((struct sockaddr_in *)sa)->sin_addr)); 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci if (sa->sa_family == AF_INET6 && 49062306a36Sopenharmony_ci __builtin_object_size(sa, 0) >= sizeof(struct sockaddr_in6)) { 49162306a36Sopenharmony_ci return ipv6_addr_cmp(&((struct sockaddr_in6 *)sa)->sin6_addr, 49262306a36Sopenharmony_ci &((struct sockaddr_in6 *)sb)->sin6_addr); 49362306a36Sopenharmony_ci } 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci return -1; 49662306a36Sopenharmony_ci} 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_cistatic int cma_add_id_to_tree(struct rdma_id_private *node_id_priv) 49962306a36Sopenharmony_ci{ 50062306a36Sopenharmony_ci struct rb_node **new, *parent = NULL; 50162306a36Sopenharmony_ci struct id_table_entry *this, *node; 50262306a36Sopenharmony_ci unsigned long flags; 50362306a36Sopenharmony_ci int result; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci node = kzalloc(sizeof(*node), GFP_KERNEL); 50662306a36Sopenharmony_ci if (!node) 50762306a36Sopenharmony_ci return -ENOMEM; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci spin_lock_irqsave(&id_table_lock, flags); 51062306a36Sopenharmony_ci new = &id_table.rb_node; 51162306a36Sopenharmony_ci while (*new) { 51262306a36Sopenharmony_ci this = container_of(*new, struct id_table_entry, rb_node); 51362306a36Sopenharmony_ci result = compare_netdev_and_ip( 51462306a36Sopenharmony_ci node_id_priv->id.route.addr.dev_addr.bound_dev_if, 51562306a36Sopenharmony_ci cma_dst_addr(node_id_priv), this); 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci parent = *new; 51862306a36Sopenharmony_ci if (result < 0) 51962306a36Sopenharmony_ci new = &((*new)->rb_left); 52062306a36Sopenharmony_ci else if (result > 0) 52162306a36Sopenharmony_ci new = &((*new)->rb_right); 52262306a36Sopenharmony_ci else { 52362306a36Sopenharmony_ci list_add_tail(&node_id_priv->id_list_entry, 52462306a36Sopenharmony_ci &this->id_list); 52562306a36Sopenharmony_ci kfree(node); 52662306a36Sopenharmony_ci goto unlock; 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci } 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci INIT_LIST_HEAD(&node->id_list); 53162306a36Sopenharmony_ci list_add_tail(&node_id_priv->id_list_entry, &node->id_list); 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci rb_link_node(&node->rb_node, parent, new); 53462306a36Sopenharmony_ci rb_insert_color(&node->rb_node, &id_table); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ciunlock: 53762306a36Sopenharmony_ci spin_unlock_irqrestore(&id_table_lock, flags); 53862306a36Sopenharmony_ci return 0; 53962306a36Sopenharmony_ci} 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_cistatic struct id_table_entry * 54262306a36Sopenharmony_cinode_from_ndev_ip(struct rb_root *root, int ifindex, struct sockaddr *sa) 54362306a36Sopenharmony_ci{ 54462306a36Sopenharmony_ci struct rb_node *node = root->rb_node; 54562306a36Sopenharmony_ci struct id_table_entry *data; 54662306a36Sopenharmony_ci int result; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci while (node) { 54962306a36Sopenharmony_ci data = container_of(node, struct id_table_entry, rb_node); 55062306a36Sopenharmony_ci result = compare_netdev_and_ip(ifindex, sa, data); 55162306a36Sopenharmony_ci if (result < 0) 55262306a36Sopenharmony_ci node = node->rb_left; 55362306a36Sopenharmony_ci else if (result > 0) 55462306a36Sopenharmony_ci node = node->rb_right; 55562306a36Sopenharmony_ci else 55662306a36Sopenharmony_ci return data; 55762306a36Sopenharmony_ci } 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci return NULL; 56062306a36Sopenharmony_ci} 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_cistatic void cma_remove_id_from_tree(struct rdma_id_private *id_priv) 56362306a36Sopenharmony_ci{ 56462306a36Sopenharmony_ci struct id_table_entry *data; 56562306a36Sopenharmony_ci unsigned long flags; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci spin_lock_irqsave(&id_table_lock, flags); 56862306a36Sopenharmony_ci if (list_empty(&id_priv->id_list_entry)) 56962306a36Sopenharmony_ci goto out; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci data = node_from_ndev_ip(&id_table, 57262306a36Sopenharmony_ci id_priv->id.route.addr.dev_addr.bound_dev_if, 57362306a36Sopenharmony_ci cma_dst_addr(id_priv)); 57462306a36Sopenharmony_ci if (!data) 57562306a36Sopenharmony_ci goto out; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci list_del_init(&id_priv->id_list_entry); 57862306a36Sopenharmony_ci if (list_empty(&data->id_list)) { 57962306a36Sopenharmony_ci rb_erase(&data->rb_node, &id_table); 58062306a36Sopenharmony_ci kfree(data); 58162306a36Sopenharmony_ci } 58262306a36Sopenharmony_ciout: 58362306a36Sopenharmony_ci spin_unlock_irqrestore(&id_table_lock, flags); 58462306a36Sopenharmony_ci} 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_cistatic void _cma_attach_to_dev(struct rdma_id_private *id_priv, 58762306a36Sopenharmony_ci struct cma_device *cma_dev) 58862306a36Sopenharmony_ci{ 58962306a36Sopenharmony_ci cma_dev_get(cma_dev); 59062306a36Sopenharmony_ci id_priv->cma_dev = cma_dev; 59162306a36Sopenharmony_ci id_priv->id.device = cma_dev->device; 59262306a36Sopenharmony_ci id_priv->id.route.addr.dev_addr.transport = 59362306a36Sopenharmony_ci rdma_node_get_transport(cma_dev->device->node_type); 59462306a36Sopenharmony_ci list_add_tail(&id_priv->device_item, &cma_dev->id_list); 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci trace_cm_id_attach(id_priv, cma_dev->device); 59762306a36Sopenharmony_ci} 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_cistatic void cma_attach_to_dev(struct rdma_id_private *id_priv, 60062306a36Sopenharmony_ci struct cma_device *cma_dev) 60162306a36Sopenharmony_ci{ 60262306a36Sopenharmony_ci _cma_attach_to_dev(id_priv, cma_dev); 60362306a36Sopenharmony_ci id_priv->gid_type = 60462306a36Sopenharmony_ci cma_dev->default_gid_type[id_priv->id.port_num - 60562306a36Sopenharmony_ci rdma_start_port(cma_dev->device)]; 60662306a36Sopenharmony_ci} 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_cistatic void cma_release_dev(struct rdma_id_private *id_priv) 60962306a36Sopenharmony_ci{ 61062306a36Sopenharmony_ci mutex_lock(&lock); 61162306a36Sopenharmony_ci list_del_init(&id_priv->device_item); 61262306a36Sopenharmony_ci cma_dev_put(id_priv->cma_dev); 61362306a36Sopenharmony_ci id_priv->cma_dev = NULL; 61462306a36Sopenharmony_ci id_priv->id.device = NULL; 61562306a36Sopenharmony_ci if (id_priv->id.route.addr.dev_addr.sgid_attr) { 61662306a36Sopenharmony_ci rdma_put_gid_attr(id_priv->id.route.addr.dev_addr.sgid_attr); 61762306a36Sopenharmony_ci id_priv->id.route.addr.dev_addr.sgid_attr = NULL; 61862306a36Sopenharmony_ci } 61962306a36Sopenharmony_ci mutex_unlock(&lock); 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_cistatic inline unsigned short cma_family(struct rdma_id_private *id_priv) 62362306a36Sopenharmony_ci{ 62462306a36Sopenharmony_ci return id_priv->id.route.addr.src_addr.ss_family; 62562306a36Sopenharmony_ci} 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_cistatic int cma_set_default_qkey(struct rdma_id_private *id_priv) 62862306a36Sopenharmony_ci{ 62962306a36Sopenharmony_ci struct ib_sa_mcmember_rec rec; 63062306a36Sopenharmony_ci int ret = 0; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci switch (id_priv->id.ps) { 63362306a36Sopenharmony_ci case RDMA_PS_UDP: 63462306a36Sopenharmony_ci case RDMA_PS_IB: 63562306a36Sopenharmony_ci id_priv->qkey = RDMA_UDP_QKEY; 63662306a36Sopenharmony_ci break; 63762306a36Sopenharmony_ci case RDMA_PS_IPOIB: 63862306a36Sopenharmony_ci ib_addr_get_mgid(&id_priv->id.route.addr.dev_addr, &rec.mgid); 63962306a36Sopenharmony_ci ret = ib_sa_get_mcmember_rec(id_priv->id.device, 64062306a36Sopenharmony_ci id_priv->id.port_num, &rec.mgid, 64162306a36Sopenharmony_ci &rec); 64262306a36Sopenharmony_ci if (!ret) 64362306a36Sopenharmony_ci id_priv->qkey = be32_to_cpu(rec.qkey); 64462306a36Sopenharmony_ci break; 64562306a36Sopenharmony_ci default: 64662306a36Sopenharmony_ci break; 64762306a36Sopenharmony_ci } 64862306a36Sopenharmony_ci return ret; 64962306a36Sopenharmony_ci} 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_cistatic int cma_set_qkey(struct rdma_id_private *id_priv, u32 qkey) 65262306a36Sopenharmony_ci{ 65362306a36Sopenharmony_ci if (!qkey || 65462306a36Sopenharmony_ci (id_priv->qkey && (id_priv->qkey != qkey))) 65562306a36Sopenharmony_ci return -EINVAL; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci id_priv->qkey = qkey; 65862306a36Sopenharmony_ci return 0; 65962306a36Sopenharmony_ci} 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_cistatic void cma_translate_ib(struct sockaddr_ib *sib, struct rdma_dev_addr *dev_addr) 66262306a36Sopenharmony_ci{ 66362306a36Sopenharmony_ci dev_addr->dev_type = ARPHRD_INFINIBAND; 66462306a36Sopenharmony_ci rdma_addr_set_sgid(dev_addr, (union ib_gid *) &sib->sib_addr); 66562306a36Sopenharmony_ci ib_addr_set_pkey(dev_addr, ntohs(sib->sib_pkey)); 66662306a36Sopenharmony_ci} 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_cistatic int cma_translate_addr(struct sockaddr *addr, struct rdma_dev_addr *dev_addr) 66962306a36Sopenharmony_ci{ 67062306a36Sopenharmony_ci int ret; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci if (addr->sa_family != AF_IB) { 67362306a36Sopenharmony_ci ret = rdma_translate_ip(addr, dev_addr); 67462306a36Sopenharmony_ci } else { 67562306a36Sopenharmony_ci cma_translate_ib((struct sockaddr_ib *) addr, dev_addr); 67662306a36Sopenharmony_ci ret = 0; 67762306a36Sopenharmony_ci } 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci return ret; 68062306a36Sopenharmony_ci} 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_cistatic const struct ib_gid_attr * 68362306a36Sopenharmony_cicma_validate_port(struct ib_device *device, u32 port, 68462306a36Sopenharmony_ci enum ib_gid_type gid_type, 68562306a36Sopenharmony_ci union ib_gid *gid, 68662306a36Sopenharmony_ci struct rdma_id_private *id_priv) 68762306a36Sopenharmony_ci{ 68862306a36Sopenharmony_ci struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 68962306a36Sopenharmony_ci const struct ib_gid_attr *sgid_attr = ERR_PTR(-ENODEV); 69062306a36Sopenharmony_ci int bound_if_index = dev_addr->bound_dev_if; 69162306a36Sopenharmony_ci int dev_type = dev_addr->dev_type; 69262306a36Sopenharmony_ci struct net_device *ndev = NULL; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci if (!rdma_dev_access_netns(device, id_priv->id.route.addr.dev_addr.net)) 69562306a36Sopenharmony_ci goto out; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci if ((dev_type == ARPHRD_INFINIBAND) && !rdma_protocol_ib(device, port)) 69862306a36Sopenharmony_ci goto out; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci if ((dev_type != ARPHRD_INFINIBAND) && rdma_protocol_ib(device, port)) 70162306a36Sopenharmony_ci goto out; 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci /* 70462306a36Sopenharmony_ci * For drivers that do not associate more than one net device with 70562306a36Sopenharmony_ci * their gid tables, such as iWARP drivers, it is sufficient to 70662306a36Sopenharmony_ci * return the first table entry. 70762306a36Sopenharmony_ci * 70862306a36Sopenharmony_ci * Other driver classes might be included in the future. 70962306a36Sopenharmony_ci */ 71062306a36Sopenharmony_ci if (rdma_protocol_iwarp(device, port)) { 71162306a36Sopenharmony_ci sgid_attr = rdma_get_gid_attr(device, port, 0); 71262306a36Sopenharmony_ci if (IS_ERR(sgid_attr)) 71362306a36Sopenharmony_ci goto out; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci rcu_read_lock(); 71662306a36Sopenharmony_ci ndev = rcu_dereference(sgid_attr->ndev); 71762306a36Sopenharmony_ci if (!net_eq(dev_net(ndev), dev_addr->net) || 71862306a36Sopenharmony_ci ndev->ifindex != bound_if_index) 71962306a36Sopenharmony_ci sgid_attr = ERR_PTR(-ENODEV); 72062306a36Sopenharmony_ci rcu_read_unlock(); 72162306a36Sopenharmony_ci goto out; 72262306a36Sopenharmony_ci } 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci if (dev_type == ARPHRD_ETHER && rdma_protocol_roce(device, port)) { 72562306a36Sopenharmony_ci ndev = dev_get_by_index(dev_addr->net, bound_if_index); 72662306a36Sopenharmony_ci if (!ndev) 72762306a36Sopenharmony_ci goto out; 72862306a36Sopenharmony_ci } else { 72962306a36Sopenharmony_ci gid_type = IB_GID_TYPE_IB; 73062306a36Sopenharmony_ci } 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci sgid_attr = rdma_find_gid_by_port(device, gid, gid_type, port, ndev); 73362306a36Sopenharmony_ci dev_put(ndev); 73462306a36Sopenharmony_ciout: 73562306a36Sopenharmony_ci return sgid_attr; 73662306a36Sopenharmony_ci} 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_cistatic void cma_bind_sgid_attr(struct rdma_id_private *id_priv, 73962306a36Sopenharmony_ci const struct ib_gid_attr *sgid_attr) 74062306a36Sopenharmony_ci{ 74162306a36Sopenharmony_ci WARN_ON(id_priv->id.route.addr.dev_addr.sgid_attr); 74262306a36Sopenharmony_ci id_priv->id.route.addr.dev_addr.sgid_attr = sgid_attr; 74362306a36Sopenharmony_ci} 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci/** 74662306a36Sopenharmony_ci * cma_acquire_dev_by_src_ip - Acquire cma device, port, gid attribute 74762306a36Sopenharmony_ci * based on source ip address. 74862306a36Sopenharmony_ci * @id_priv: cm_id which should be bound to cma device 74962306a36Sopenharmony_ci * 75062306a36Sopenharmony_ci * cma_acquire_dev_by_src_ip() binds cm id to cma device, port and GID attribute 75162306a36Sopenharmony_ci * based on source IP address. It returns 0 on success or error code otherwise. 75262306a36Sopenharmony_ci * It is applicable to active and passive side cm_id. 75362306a36Sopenharmony_ci */ 75462306a36Sopenharmony_cistatic int cma_acquire_dev_by_src_ip(struct rdma_id_private *id_priv) 75562306a36Sopenharmony_ci{ 75662306a36Sopenharmony_ci struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 75762306a36Sopenharmony_ci const struct ib_gid_attr *sgid_attr; 75862306a36Sopenharmony_ci union ib_gid gid, iboe_gid, *gidp; 75962306a36Sopenharmony_ci struct cma_device *cma_dev; 76062306a36Sopenharmony_ci enum ib_gid_type gid_type; 76162306a36Sopenharmony_ci int ret = -ENODEV; 76262306a36Sopenharmony_ci u32 port; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci if (dev_addr->dev_type != ARPHRD_INFINIBAND && 76562306a36Sopenharmony_ci id_priv->id.ps == RDMA_PS_IPOIB) 76662306a36Sopenharmony_ci return -EINVAL; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci rdma_ip2gid((struct sockaddr *)&id_priv->id.route.addr.src_addr, 76962306a36Sopenharmony_ci &iboe_gid); 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci memcpy(&gid, dev_addr->src_dev_addr + 77262306a36Sopenharmony_ci rdma_addr_gid_offset(dev_addr), sizeof(gid)); 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci mutex_lock(&lock); 77562306a36Sopenharmony_ci list_for_each_entry(cma_dev, &dev_list, list) { 77662306a36Sopenharmony_ci rdma_for_each_port (cma_dev->device, port) { 77762306a36Sopenharmony_ci gidp = rdma_protocol_roce(cma_dev->device, port) ? 77862306a36Sopenharmony_ci &iboe_gid : &gid; 77962306a36Sopenharmony_ci gid_type = cma_dev->default_gid_type[port - 1]; 78062306a36Sopenharmony_ci sgid_attr = cma_validate_port(cma_dev->device, port, 78162306a36Sopenharmony_ci gid_type, gidp, id_priv); 78262306a36Sopenharmony_ci if (!IS_ERR(sgid_attr)) { 78362306a36Sopenharmony_ci id_priv->id.port_num = port; 78462306a36Sopenharmony_ci cma_bind_sgid_attr(id_priv, sgid_attr); 78562306a36Sopenharmony_ci cma_attach_to_dev(id_priv, cma_dev); 78662306a36Sopenharmony_ci ret = 0; 78762306a36Sopenharmony_ci goto out; 78862306a36Sopenharmony_ci } 78962306a36Sopenharmony_ci } 79062306a36Sopenharmony_ci } 79162306a36Sopenharmony_ciout: 79262306a36Sopenharmony_ci mutex_unlock(&lock); 79362306a36Sopenharmony_ci return ret; 79462306a36Sopenharmony_ci} 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci/** 79762306a36Sopenharmony_ci * cma_ib_acquire_dev - Acquire cma device, port and SGID attribute 79862306a36Sopenharmony_ci * @id_priv: cm id to bind to cma device 79962306a36Sopenharmony_ci * @listen_id_priv: listener cm id to match against 80062306a36Sopenharmony_ci * @req: Pointer to req structure containaining incoming 80162306a36Sopenharmony_ci * request information 80262306a36Sopenharmony_ci * cma_ib_acquire_dev() acquires cma device, port and SGID attribute when 80362306a36Sopenharmony_ci * rdma device matches for listen_id and incoming request. It also verifies 80462306a36Sopenharmony_ci * that a GID table entry is present for the source address. 80562306a36Sopenharmony_ci * Returns 0 on success, or returns error code otherwise. 80662306a36Sopenharmony_ci */ 80762306a36Sopenharmony_cistatic int cma_ib_acquire_dev(struct rdma_id_private *id_priv, 80862306a36Sopenharmony_ci const struct rdma_id_private *listen_id_priv, 80962306a36Sopenharmony_ci struct cma_req_info *req) 81062306a36Sopenharmony_ci{ 81162306a36Sopenharmony_ci struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 81262306a36Sopenharmony_ci const struct ib_gid_attr *sgid_attr; 81362306a36Sopenharmony_ci enum ib_gid_type gid_type; 81462306a36Sopenharmony_ci union ib_gid gid; 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci if (dev_addr->dev_type != ARPHRD_INFINIBAND && 81762306a36Sopenharmony_ci id_priv->id.ps == RDMA_PS_IPOIB) 81862306a36Sopenharmony_ci return -EINVAL; 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci if (rdma_protocol_roce(req->device, req->port)) 82162306a36Sopenharmony_ci rdma_ip2gid((struct sockaddr *)&id_priv->id.route.addr.src_addr, 82262306a36Sopenharmony_ci &gid); 82362306a36Sopenharmony_ci else 82462306a36Sopenharmony_ci memcpy(&gid, dev_addr->src_dev_addr + 82562306a36Sopenharmony_ci rdma_addr_gid_offset(dev_addr), sizeof(gid)); 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci gid_type = listen_id_priv->cma_dev->default_gid_type[req->port - 1]; 82862306a36Sopenharmony_ci sgid_attr = cma_validate_port(req->device, req->port, 82962306a36Sopenharmony_ci gid_type, &gid, id_priv); 83062306a36Sopenharmony_ci if (IS_ERR(sgid_attr)) 83162306a36Sopenharmony_ci return PTR_ERR(sgid_attr); 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci id_priv->id.port_num = req->port; 83462306a36Sopenharmony_ci cma_bind_sgid_attr(id_priv, sgid_attr); 83562306a36Sopenharmony_ci /* Need to acquire lock to protect against reader 83662306a36Sopenharmony_ci * of cma_dev->id_list such as cma_netdev_callback() and 83762306a36Sopenharmony_ci * cma_process_remove(). 83862306a36Sopenharmony_ci */ 83962306a36Sopenharmony_ci mutex_lock(&lock); 84062306a36Sopenharmony_ci cma_attach_to_dev(id_priv, listen_id_priv->cma_dev); 84162306a36Sopenharmony_ci mutex_unlock(&lock); 84262306a36Sopenharmony_ci rdma_restrack_add(&id_priv->res); 84362306a36Sopenharmony_ci return 0; 84462306a36Sopenharmony_ci} 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_cistatic int cma_iw_acquire_dev(struct rdma_id_private *id_priv, 84762306a36Sopenharmony_ci const struct rdma_id_private *listen_id_priv) 84862306a36Sopenharmony_ci{ 84962306a36Sopenharmony_ci struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 85062306a36Sopenharmony_ci const struct ib_gid_attr *sgid_attr; 85162306a36Sopenharmony_ci struct cma_device *cma_dev; 85262306a36Sopenharmony_ci enum ib_gid_type gid_type; 85362306a36Sopenharmony_ci int ret = -ENODEV; 85462306a36Sopenharmony_ci union ib_gid gid; 85562306a36Sopenharmony_ci u32 port; 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci if (dev_addr->dev_type != ARPHRD_INFINIBAND && 85862306a36Sopenharmony_ci id_priv->id.ps == RDMA_PS_IPOIB) 85962306a36Sopenharmony_ci return -EINVAL; 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci memcpy(&gid, dev_addr->src_dev_addr + 86262306a36Sopenharmony_ci rdma_addr_gid_offset(dev_addr), sizeof(gid)); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci mutex_lock(&lock); 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci cma_dev = listen_id_priv->cma_dev; 86762306a36Sopenharmony_ci port = listen_id_priv->id.port_num; 86862306a36Sopenharmony_ci gid_type = listen_id_priv->gid_type; 86962306a36Sopenharmony_ci sgid_attr = cma_validate_port(cma_dev->device, port, 87062306a36Sopenharmony_ci gid_type, &gid, id_priv); 87162306a36Sopenharmony_ci if (!IS_ERR(sgid_attr)) { 87262306a36Sopenharmony_ci id_priv->id.port_num = port; 87362306a36Sopenharmony_ci cma_bind_sgid_attr(id_priv, sgid_attr); 87462306a36Sopenharmony_ci ret = 0; 87562306a36Sopenharmony_ci goto out; 87662306a36Sopenharmony_ci } 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci list_for_each_entry(cma_dev, &dev_list, list) { 87962306a36Sopenharmony_ci rdma_for_each_port (cma_dev->device, port) { 88062306a36Sopenharmony_ci if (listen_id_priv->cma_dev == cma_dev && 88162306a36Sopenharmony_ci listen_id_priv->id.port_num == port) 88262306a36Sopenharmony_ci continue; 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci gid_type = cma_dev->default_gid_type[port - 1]; 88562306a36Sopenharmony_ci sgid_attr = cma_validate_port(cma_dev->device, port, 88662306a36Sopenharmony_ci gid_type, &gid, id_priv); 88762306a36Sopenharmony_ci if (!IS_ERR(sgid_attr)) { 88862306a36Sopenharmony_ci id_priv->id.port_num = port; 88962306a36Sopenharmony_ci cma_bind_sgid_attr(id_priv, sgid_attr); 89062306a36Sopenharmony_ci ret = 0; 89162306a36Sopenharmony_ci goto out; 89262306a36Sopenharmony_ci } 89362306a36Sopenharmony_ci } 89462306a36Sopenharmony_ci } 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ciout: 89762306a36Sopenharmony_ci if (!ret) { 89862306a36Sopenharmony_ci cma_attach_to_dev(id_priv, cma_dev); 89962306a36Sopenharmony_ci rdma_restrack_add(&id_priv->res); 90062306a36Sopenharmony_ci } 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci mutex_unlock(&lock); 90362306a36Sopenharmony_ci return ret; 90462306a36Sopenharmony_ci} 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci/* 90762306a36Sopenharmony_ci * Select the source IB device and address to reach the destination IB address. 90862306a36Sopenharmony_ci */ 90962306a36Sopenharmony_cistatic int cma_resolve_ib_dev(struct rdma_id_private *id_priv) 91062306a36Sopenharmony_ci{ 91162306a36Sopenharmony_ci struct cma_device *cma_dev, *cur_dev; 91262306a36Sopenharmony_ci struct sockaddr_ib *addr; 91362306a36Sopenharmony_ci union ib_gid gid, sgid, *dgid; 91462306a36Sopenharmony_ci unsigned int p; 91562306a36Sopenharmony_ci u16 pkey, index; 91662306a36Sopenharmony_ci enum ib_port_state port_state; 91762306a36Sopenharmony_ci int ret; 91862306a36Sopenharmony_ci int i; 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci cma_dev = NULL; 92162306a36Sopenharmony_ci addr = (struct sockaddr_ib *) cma_dst_addr(id_priv); 92262306a36Sopenharmony_ci dgid = (union ib_gid *) &addr->sib_addr; 92362306a36Sopenharmony_ci pkey = ntohs(addr->sib_pkey); 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci mutex_lock(&lock); 92662306a36Sopenharmony_ci list_for_each_entry(cur_dev, &dev_list, list) { 92762306a36Sopenharmony_ci rdma_for_each_port (cur_dev->device, p) { 92862306a36Sopenharmony_ci if (!rdma_cap_af_ib(cur_dev->device, p)) 92962306a36Sopenharmony_ci continue; 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci if (ib_find_cached_pkey(cur_dev->device, p, pkey, &index)) 93262306a36Sopenharmony_ci continue; 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci if (ib_get_cached_port_state(cur_dev->device, p, &port_state)) 93562306a36Sopenharmony_ci continue; 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci for (i = 0; i < cur_dev->device->port_data[p].immutable.gid_tbl_len; 93862306a36Sopenharmony_ci ++i) { 93962306a36Sopenharmony_ci ret = rdma_query_gid(cur_dev->device, p, i, 94062306a36Sopenharmony_ci &gid); 94162306a36Sopenharmony_ci if (ret) 94262306a36Sopenharmony_ci continue; 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci if (!memcmp(&gid, dgid, sizeof(gid))) { 94562306a36Sopenharmony_ci cma_dev = cur_dev; 94662306a36Sopenharmony_ci sgid = gid; 94762306a36Sopenharmony_ci id_priv->id.port_num = p; 94862306a36Sopenharmony_ci goto found; 94962306a36Sopenharmony_ci } 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci if (!cma_dev && (gid.global.subnet_prefix == 95262306a36Sopenharmony_ci dgid->global.subnet_prefix) && 95362306a36Sopenharmony_ci port_state == IB_PORT_ACTIVE) { 95462306a36Sopenharmony_ci cma_dev = cur_dev; 95562306a36Sopenharmony_ci sgid = gid; 95662306a36Sopenharmony_ci id_priv->id.port_num = p; 95762306a36Sopenharmony_ci goto found; 95862306a36Sopenharmony_ci } 95962306a36Sopenharmony_ci } 96062306a36Sopenharmony_ci } 96162306a36Sopenharmony_ci } 96262306a36Sopenharmony_ci mutex_unlock(&lock); 96362306a36Sopenharmony_ci return -ENODEV; 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_cifound: 96662306a36Sopenharmony_ci cma_attach_to_dev(id_priv, cma_dev); 96762306a36Sopenharmony_ci rdma_restrack_add(&id_priv->res); 96862306a36Sopenharmony_ci mutex_unlock(&lock); 96962306a36Sopenharmony_ci addr = (struct sockaddr_ib *)cma_src_addr(id_priv); 97062306a36Sopenharmony_ci memcpy(&addr->sib_addr, &sgid, sizeof(sgid)); 97162306a36Sopenharmony_ci cma_translate_ib(addr, &id_priv->id.route.addr.dev_addr); 97262306a36Sopenharmony_ci return 0; 97362306a36Sopenharmony_ci} 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_cistatic void cma_id_get(struct rdma_id_private *id_priv) 97662306a36Sopenharmony_ci{ 97762306a36Sopenharmony_ci refcount_inc(&id_priv->refcount); 97862306a36Sopenharmony_ci} 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_cistatic void cma_id_put(struct rdma_id_private *id_priv) 98162306a36Sopenharmony_ci{ 98262306a36Sopenharmony_ci if (refcount_dec_and_test(&id_priv->refcount)) 98362306a36Sopenharmony_ci complete(&id_priv->comp); 98462306a36Sopenharmony_ci} 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_cistatic struct rdma_id_private * 98762306a36Sopenharmony_ci__rdma_create_id(struct net *net, rdma_cm_event_handler event_handler, 98862306a36Sopenharmony_ci void *context, enum rdma_ucm_port_space ps, 98962306a36Sopenharmony_ci enum ib_qp_type qp_type, const struct rdma_id_private *parent) 99062306a36Sopenharmony_ci{ 99162306a36Sopenharmony_ci struct rdma_id_private *id_priv; 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci id_priv = kzalloc(sizeof *id_priv, GFP_KERNEL); 99462306a36Sopenharmony_ci if (!id_priv) 99562306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci id_priv->state = RDMA_CM_IDLE; 99862306a36Sopenharmony_ci id_priv->id.context = context; 99962306a36Sopenharmony_ci id_priv->id.event_handler = event_handler; 100062306a36Sopenharmony_ci id_priv->id.ps = ps; 100162306a36Sopenharmony_ci id_priv->id.qp_type = qp_type; 100262306a36Sopenharmony_ci id_priv->tos_set = false; 100362306a36Sopenharmony_ci id_priv->timeout_set = false; 100462306a36Sopenharmony_ci id_priv->min_rnr_timer_set = false; 100562306a36Sopenharmony_ci id_priv->gid_type = IB_GID_TYPE_IB; 100662306a36Sopenharmony_ci spin_lock_init(&id_priv->lock); 100762306a36Sopenharmony_ci mutex_init(&id_priv->qp_mutex); 100862306a36Sopenharmony_ci init_completion(&id_priv->comp); 100962306a36Sopenharmony_ci refcount_set(&id_priv->refcount, 1); 101062306a36Sopenharmony_ci mutex_init(&id_priv->handler_mutex); 101162306a36Sopenharmony_ci INIT_LIST_HEAD(&id_priv->device_item); 101262306a36Sopenharmony_ci INIT_LIST_HEAD(&id_priv->id_list_entry); 101362306a36Sopenharmony_ci INIT_LIST_HEAD(&id_priv->listen_list); 101462306a36Sopenharmony_ci INIT_LIST_HEAD(&id_priv->mc_list); 101562306a36Sopenharmony_ci get_random_bytes(&id_priv->seq_num, sizeof id_priv->seq_num); 101662306a36Sopenharmony_ci id_priv->id.route.addr.dev_addr.net = get_net(net); 101762306a36Sopenharmony_ci id_priv->seq_num &= 0x00ffffff; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci rdma_restrack_new(&id_priv->res, RDMA_RESTRACK_CM_ID); 102062306a36Sopenharmony_ci if (parent) 102162306a36Sopenharmony_ci rdma_restrack_parent_name(&id_priv->res, &parent->res); 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci return id_priv; 102462306a36Sopenharmony_ci} 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_cistruct rdma_cm_id * 102762306a36Sopenharmony_ci__rdma_create_kernel_id(struct net *net, rdma_cm_event_handler event_handler, 102862306a36Sopenharmony_ci void *context, enum rdma_ucm_port_space ps, 102962306a36Sopenharmony_ci enum ib_qp_type qp_type, const char *caller) 103062306a36Sopenharmony_ci{ 103162306a36Sopenharmony_ci struct rdma_id_private *ret; 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci ret = __rdma_create_id(net, event_handler, context, ps, qp_type, NULL); 103462306a36Sopenharmony_ci if (IS_ERR(ret)) 103562306a36Sopenharmony_ci return ERR_CAST(ret); 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci rdma_restrack_set_name(&ret->res, caller); 103862306a36Sopenharmony_ci return &ret->id; 103962306a36Sopenharmony_ci} 104062306a36Sopenharmony_ciEXPORT_SYMBOL(__rdma_create_kernel_id); 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_cistruct rdma_cm_id *rdma_create_user_id(rdma_cm_event_handler event_handler, 104362306a36Sopenharmony_ci void *context, 104462306a36Sopenharmony_ci enum rdma_ucm_port_space ps, 104562306a36Sopenharmony_ci enum ib_qp_type qp_type) 104662306a36Sopenharmony_ci{ 104762306a36Sopenharmony_ci struct rdma_id_private *ret; 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci ret = __rdma_create_id(current->nsproxy->net_ns, event_handler, context, 105062306a36Sopenharmony_ci ps, qp_type, NULL); 105162306a36Sopenharmony_ci if (IS_ERR(ret)) 105262306a36Sopenharmony_ci return ERR_CAST(ret); 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci rdma_restrack_set_name(&ret->res, NULL); 105562306a36Sopenharmony_ci return &ret->id; 105662306a36Sopenharmony_ci} 105762306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_create_user_id); 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_cistatic int cma_init_ud_qp(struct rdma_id_private *id_priv, struct ib_qp *qp) 106062306a36Sopenharmony_ci{ 106162306a36Sopenharmony_ci struct ib_qp_attr qp_attr; 106262306a36Sopenharmony_ci int qp_attr_mask, ret; 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci qp_attr.qp_state = IB_QPS_INIT; 106562306a36Sopenharmony_ci ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 106662306a36Sopenharmony_ci if (ret) 106762306a36Sopenharmony_ci return ret; 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci ret = ib_modify_qp(qp, &qp_attr, qp_attr_mask); 107062306a36Sopenharmony_ci if (ret) 107162306a36Sopenharmony_ci return ret; 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci qp_attr.qp_state = IB_QPS_RTR; 107462306a36Sopenharmony_ci ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE); 107562306a36Sopenharmony_ci if (ret) 107662306a36Sopenharmony_ci return ret; 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci qp_attr.qp_state = IB_QPS_RTS; 107962306a36Sopenharmony_ci qp_attr.sq_psn = 0; 108062306a36Sopenharmony_ci ret = ib_modify_qp(qp, &qp_attr, IB_QP_STATE | IB_QP_SQ_PSN); 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci return ret; 108362306a36Sopenharmony_ci} 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_cistatic int cma_init_conn_qp(struct rdma_id_private *id_priv, struct ib_qp *qp) 108662306a36Sopenharmony_ci{ 108762306a36Sopenharmony_ci struct ib_qp_attr qp_attr; 108862306a36Sopenharmony_ci int qp_attr_mask, ret; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci qp_attr.qp_state = IB_QPS_INIT; 109162306a36Sopenharmony_ci ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 109262306a36Sopenharmony_ci if (ret) 109362306a36Sopenharmony_ci return ret; 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci return ib_modify_qp(qp, &qp_attr, qp_attr_mask); 109662306a36Sopenharmony_ci} 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ciint rdma_create_qp(struct rdma_cm_id *id, struct ib_pd *pd, 109962306a36Sopenharmony_ci struct ib_qp_init_attr *qp_init_attr) 110062306a36Sopenharmony_ci{ 110162306a36Sopenharmony_ci struct rdma_id_private *id_priv; 110262306a36Sopenharmony_ci struct ib_qp *qp; 110362306a36Sopenharmony_ci int ret; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci id_priv = container_of(id, struct rdma_id_private, id); 110662306a36Sopenharmony_ci if (id->device != pd->device) { 110762306a36Sopenharmony_ci ret = -EINVAL; 110862306a36Sopenharmony_ci goto out_err; 110962306a36Sopenharmony_ci } 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci qp_init_attr->port_num = id->port_num; 111262306a36Sopenharmony_ci qp = ib_create_qp(pd, qp_init_attr); 111362306a36Sopenharmony_ci if (IS_ERR(qp)) { 111462306a36Sopenharmony_ci ret = PTR_ERR(qp); 111562306a36Sopenharmony_ci goto out_err; 111662306a36Sopenharmony_ci } 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci if (id->qp_type == IB_QPT_UD) 111962306a36Sopenharmony_ci ret = cma_init_ud_qp(id_priv, qp); 112062306a36Sopenharmony_ci else 112162306a36Sopenharmony_ci ret = cma_init_conn_qp(id_priv, qp); 112262306a36Sopenharmony_ci if (ret) 112362306a36Sopenharmony_ci goto out_destroy; 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci id->qp = qp; 112662306a36Sopenharmony_ci id_priv->qp_num = qp->qp_num; 112762306a36Sopenharmony_ci id_priv->srq = (qp->srq != NULL); 112862306a36Sopenharmony_ci trace_cm_qp_create(id_priv, pd, qp_init_attr, 0); 112962306a36Sopenharmony_ci return 0; 113062306a36Sopenharmony_ciout_destroy: 113162306a36Sopenharmony_ci ib_destroy_qp(qp); 113262306a36Sopenharmony_ciout_err: 113362306a36Sopenharmony_ci trace_cm_qp_create(id_priv, pd, qp_init_attr, ret); 113462306a36Sopenharmony_ci return ret; 113562306a36Sopenharmony_ci} 113662306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_create_qp); 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_civoid rdma_destroy_qp(struct rdma_cm_id *id) 113962306a36Sopenharmony_ci{ 114062306a36Sopenharmony_ci struct rdma_id_private *id_priv; 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci id_priv = container_of(id, struct rdma_id_private, id); 114362306a36Sopenharmony_ci trace_cm_qp_destroy(id_priv); 114462306a36Sopenharmony_ci mutex_lock(&id_priv->qp_mutex); 114562306a36Sopenharmony_ci ib_destroy_qp(id_priv->id.qp); 114662306a36Sopenharmony_ci id_priv->id.qp = NULL; 114762306a36Sopenharmony_ci mutex_unlock(&id_priv->qp_mutex); 114862306a36Sopenharmony_ci} 114962306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_destroy_qp); 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_cistatic int cma_modify_qp_rtr(struct rdma_id_private *id_priv, 115262306a36Sopenharmony_ci struct rdma_conn_param *conn_param) 115362306a36Sopenharmony_ci{ 115462306a36Sopenharmony_ci struct ib_qp_attr qp_attr; 115562306a36Sopenharmony_ci int qp_attr_mask, ret; 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci mutex_lock(&id_priv->qp_mutex); 115862306a36Sopenharmony_ci if (!id_priv->id.qp) { 115962306a36Sopenharmony_ci ret = 0; 116062306a36Sopenharmony_ci goto out; 116162306a36Sopenharmony_ci } 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci /* Need to update QP attributes from default values. */ 116462306a36Sopenharmony_ci qp_attr.qp_state = IB_QPS_INIT; 116562306a36Sopenharmony_ci ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 116662306a36Sopenharmony_ci if (ret) 116762306a36Sopenharmony_ci goto out; 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask); 117062306a36Sopenharmony_ci if (ret) 117162306a36Sopenharmony_ci goto out; 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci qp_attr.qp_state = IB_QPS_RTR; 117462306a36Sopenharmony_ci ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 117562306a36Sopenharmony_ci if (ret) 117662306a36Sopenharmony_ci goto out; 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci BUG_ON(id_priv->cma_dev->device != id_priv->id.device); 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci if (conn_param) 118162306a36Sopenharmony_ci qp_attr.max_dest_rd_atomic = conn_param->responder_resources; 118262306a36Sopenharmony_ci ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask); 118362306a36Sopenharmony_ciout: 118462306a36Sopenharmony_ci mutex_unlock(&id_priv->qp_mutex); 118562306a36Sopenharmony_ci return ret; 118662306a36Sopenharmony_ci} 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_cistatic int cma_modify_qp_rts(struct rdma_id_private *id_priv, 118962306a36Sopenharmony_ci struct rdma_conn_param *conn_param) 119062306a36Sopenharmony_ci{ 119162306a36Sopenharmony_ci struct ib_qp_attr qp_attr; 119262306a36Sopenharmony_ci int qp_attr_mask, ret; 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci mutex_lock(&id_priv->qp_mutex); 119562306a36Sopenharmony_ci if (!id_priv->id.qp) { 119662306a36Sopenharmony_ci ret = 0; 119762306a36Sopenharmony_ci goto out; 119862306a36Sopenharmony_ci } 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci qp_attr.qp_state = IB_QPS_RTS; 120162306a36Sopenharmony_ci ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask); 120262306a36Sopenharmony_ci if (ret) 120362306a36Sopenharmony_ci goto out; 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci if (conn_param) 120662306a36Sopenharmony_ci qp_attr.max_rd_atomic = conn_param->initiator_depth; 120762306a36Sopenharmony_ci ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask); 120862306a36Sopenharmony_ciout: 120962306a36Sopenharmony_ci mutex_unlock(&id_priv->qp_mutex); 121062306a36Sopenharmony_ci return ret; 121162306a36Sopenharmony_ci} 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_cistatic int cma_modify_qp_err(struct rdma_id_private *id_priv) 121462306a36Sopenharmony_ci{ 121562306a36Sopenharmony_ci struct ib_qp_attr qp_attr; 121662306a36Sopenharmony_ci int ret; 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci mutex_lock(&id_priv->qp_mutex); 121962306a36Sopenharmony_ci if (!id_priv->id.qp) { 122062306a36Sopenharmony_ci ret = 0; 122162306a36Sopenharmony_ci goto out; 122262306a36Sopenharmony_ci } 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci qp_attr.qp_state = IB_QPS_ERR; 122562306a36Sopenharmony_ci ret = ib_modify_qp(id_priv->id.qp, &qp_attr, IB_QP_STATE); 122662306a36Sopenharmony_ciout: 122762306a36Sopenharmony_ci mutex_unlock(&id_priv->qp_mutex); 122862306a36Sopenharmony_ci return ret; 122962306a36Sopenharmony_ci} 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_cistatic int cma_ib_init_qp_attr(struct rdma_id_private *id_priv, 123262306a36Sopenharmony_ci struct ib_qp_attr *qp_attr, int *qp_attr_mask) 123362306a36Sopenharmony_ci{ 123462306a36Sopenharmony_ci struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 123562306a36Sopenharmony_ci int ret; 123662306a36Sopenharmony_ci u16 pkey; 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci if (rdma_cap_eth_ah(id_priv->id.device, id_priv->id.port_num)) 123962306a36Sopenharmony_ci pkey = 0xffff; 124062306a36Sopenharmony_ci else 124162306a36Sopenharmony_ci pkey = ib_addr_get_pkey(dev_addr); 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci ret = ib_find_cached_pkey(id_priv->id.device, id_priv->id.port_num, 124462306a36Sopenharmony_ci pkey, &qp_attr->pkey_index); 124562306a36Sopenharmony_ci if (ret) 124662306a36Sopenharmony_ci return ret; 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci qp_attr->port_num = id_priv->id.port_num; 124962306a36Sopenharmony_ci *qp_attr_mask = IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_PORT; 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci if (id_priv->id.qp_type == IB_QPT_UD) { 125262306a36Sopenharmony_ci ret = cma_set_default_qkey(id_priv); 125362306a36Sopenharmony_ci if (ret) 125462306a36Sopenharmony_ci return ret; 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci qp_attr->qkey = id_priv->qkey; 125762306a36Sopenharmony_ci *qp_attr_mask |= IB_QP_QKEY; 125862306a36Sopenharmony_ci } else { 125962306a36Sopenharmony_ci qp_attr->qp_access_flags = 0; 126062306a36Sopenharmony_ci *qp_attr_mask |= IB_QP_ACCESS_FLAGS; 126162306a36Sopenharmony_ci } 126262306a36Sopenharmony_ci return 0; 126362306a36Sopenharmony_ci} 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ciint rdma_init_qp_attr(struct rdma_cm_id *id, struct ib_qp_attr *qp_attr, 126662306a36Sopenharmony_ci int *qp_attr_mask) 126762306a36Sopenharmony_ci{ 126862306a36Sopenharmony_ci struct rdma_id_private *id_priv; 126962306a36Sopenharmony_ci int ret = 0; 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci id_priv = container_of(id, struct rdma_id_private, id); 127262306a36Sopenharmony_ci if (rdma_cap_ib_cm(id->device, id->port_num)) { 127362306a36Sopenharmony_ci if (!id_priv->cm_id.ib || (id_priv->id.qp_type == IB_QPT_UD)) 127462306a36Sopenharmony_ci ret = cma_ib_init_qp_attr(id_priv, qp_attr, qp_attr_mask); 127562306a36Sopenharmony_ci else 127662306a36Sopenharmony_ci ret = ib_cm_init_qp_attr(id_priv->cm_id.ib, qp_attr, 127762306a36Sopenharmony_ci qp_attr_mask); 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci if (qp_attr->qp_state == IB_QPS_RTR) 128062306a36Sopenharmony_ci qp_attr->rq_psn = id_priv->seq_num; 128162306a36Sopenharmony_ci } else if (rdma_cap_iw_cm(id->device, id->port_num)) { 128262306a36Sopenharmony_ci if (!id_priv->cm_id.iw) { 128362306a36Sopenharmony_ci qp_attr->qp_access_flags = 0; 128462306a36Sopenharmony_ci *qp_attr_mask = IB_QP_STATE | IB_QP_ACCESS_FLAGS; 128562306a36Sopenharmony_ci } else 128662306a36Sopenharmony_ci ret = iw_cm_init_qp_attr(id_priv->cm_id.iw, qp_attr, 128762306a36Sopenharmony_ci qp_attr_mask); 128862306a36Sopenharmony_ci qp_attr->port_num = id_priv->id.port_num; 128962306a36Sopenharmony_ci *qp_attr_mask |= IB_QP_PORT; 129062306a36Sopenharmony_ci } else { 129162306a36Sopenharmony_ci ret = -ENOSYS; 129262306a36Sopenharmony_ci } 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci if ((*qp_attr_mask & IB_QP_TIMEOUT) && id_priv->timeout_set) 129562306a36Sopenharmony_ci qp_attr->timeout = id_priv->timeout; 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci if ((*qp_attr_mask & IB_QP_MIN_RNR_TIMER) && id_priv->min_rnr_timer_set) 129862306a36Sopenharmony_ci qp_attr->min_rnr_timer = id_priv->min_rnr_timer; 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci return ret; 130162306a36Sopenharmony_ci} 130262306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_init_qp_attr); 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_cistatic inline bool cma_zero_addr(const struct sockaddr *addr) 130562306a36Sopenharmony_ci{ 130662306a36Sopenharmony_ci switch (addr->sa_family) { 130762306a36Sopenharmony_ci case AF_INET: 130862306a36Sopenharmony_ci return ipv4_is_zeronet(((struct sockaddr_in *)addr)->sin_addr.s_addr); 130962306a36Sopenharmony_ci case AF_INET6: 131062306a36Sopenharmony_ci return ipv6_addr_any(&((struct sockaddr_in6 *)addr)->sin6_addr); 131162306a36Sopenharmony_ci case AF_IB: 131262306a36Sopenharmony_ci return ib_addr_any(&((struct sockaddr_ib *)addr)->sib_addr); 131362306a36Sopenharmony_ci default: 131462306a36Sopenharmony_ci return false; 131562306a36Sopenharmony_ci } 131662306a36Sopenharmony_ci} 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_cistatic inline bool cma_loopback_addr(const struct sockaddr *addr) 131962306a36Sopenharmony_ci{ 132062306a36Sopenharmony_ci switch (addr->sa_family) { 132162306a36Sopenharmony_ci case AF_INET: 132262306a36Sopenharmony_ci return ipv4_is_loopback( 132362306a36Sopenharmony_ci ((struct sockaddr_in *)addr)->sin_addr.s_addr); 132462306a36Sopenharmony_ci case AF_INET6: 132562306a36Sopenharmony_ci return ipv6_addr_loopback( 132662306a36Sopenharmony_ci &((struct sockaddr_in6 *)addr)->sin6_addr); 132762306a36Sopenharmony_ci case AF_IB: 132862306a36Sopenharmony_ci return ib_addr_loopback( 132962306a36Sopenharmony_ci &((struct sockaddr_ib *)addr)->sib_addr); 133062306a36Sopenharmony_ci default: 133162306a36Sopenharmony_ci return false; 133262306a36Sopenharmony_ci } 133362306a36Sopenharmony_ci} 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_cistatic inline bool cma_any_addr(const struct sockaddr *addr) 133662306a36Sopenharmony_ci{ 133762306a36Sopenharmony_ci return cma_zero_addr(addr) || cma_loopback_addr(addr); 133862306a36Sopenharmony_ci} 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_cistatic int cma_addr_cmp(const struct sockaddr *src, const struct sockaddr *dst) 134162306a36Sopenharmony_ci{ 134262306a36Sopenharmony_ci if (src->sa_family != dst->sa_family) 134362306a36Sopenharmony_ci return -1; 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci switch (src->sa_family) { 134662306a36Sopenharmony_ci case AF_INET: 134762306a36Sopenharmony_ci return ((struct sockaddr_in *)src)->sin_addr.s_addr != 134862306a36Sopenharmony_ci ((struct sockaddr_in *)dst)->sin_addr.s_addr; 134962306a36Sopenharmony_ci case AF_INET6: { 135062306a36Sopenharmony_ci struct sockaddr_in6 *src_addr6 = (struct sockaddr_in6 *)src; 135162306a36Sopenharmony_ci struct sockaddr_in6 *dst_addr6 = (struct sockaddr_in6 *)dst; 135262306a36Sopenharmony_ci bool link_local; 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci if (ipv6_addr_cmp(&src_addr6->sin6_addr, 135562306a36Sopenharmony_ci &dst_addr6->sin6_addr)) 135662306a36Sopenharmony_ci return 1; 135762306a36Sopenharmony_ci link_local = ipv6_addr_type(&dst_addr6->sin6_addr) & 135862306a36Sopenharmony_ci IPV6_ADDR_LINKLOCAL; 135962306a36Sopenharmony_ci /* Link local must match their scope_ids */ 136062306a36Sopenharmony_ci return link_local ? (src_addr6->sin6_scope_id != 136162306a36Sopenharmony_ci dst_addr6->sin6_scope_id) : 136262306a36Sopenharmony_ci 0; 136362306a36Sopenharmony_ci } 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci default: 136662306a36Sopenharmony_ci return ib_addr_cmp(&((struct sockaddr_ib *) src)->sib_addr, 136762306a36Sopenharmony_ci &((struct sockaddr_ib *) dst)->sib_addr); 136862306a36Sopenharmony_ci } 136962306a36Sopenharmony_ci} 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_cistatic __be16 cma_port(const struct sockaddr *addr) 137262306a36Sopenharmony_ci{ 137362306a36Sopenharmony_ci struct sockaddr_ib *sib; 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci switch (addr->sa_family) { 137662306a36Sopenharmony_ci case AF_INET: 137762306a36Sopenharmony_ci return ((struct sockaddr_in *) addr)->sin_port; 137862306a36Sopenharmony_ci case AF_INET6: 137962306a36Sopenharmony_ci return ((struct sockaddr_in6 *) addr)->sin6_port; 138062306a36Sopenharmony_ci case AF_IB: 138162306a36Sopenharmony_ci sib = (struct sockaddr_ib *) addr; 138262306a36Sopenharmony_ci return htons((u16) (be64_to_cpu(sib->sib_sid) & 138362306a36Sopenharmony_ci be64_to_cpu(sib->sib_sid_mask))); 138462306a36Sopenharmony_ci default: 138562306a36Sopenharmony_ci return 0; 138662306a36Sopenharmony_ci } 138762306a36Sopenharmony_ci} 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_cistatic inline int cma_any_port(const struct sockaddr *addr) 139062306a36Sopenharmony_ci{ 139162306a36Sopenharmony_ci return !cma_port(addr); 139262306a36Sopenharmony_ci} 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_cistatic void cma_save_ib_info(struct sockaddr *src_addr, 139562306a36Sopenharmony_ci struct sockaddr *dst_addr, 139662306a36Sopenharmony_ci const struct rdma_cm_id *listen_id, 139762306a36Sopenharmony_ci const struct sa_path_rec *path) 139862306a36Sopenharmony_ci{ 139962306a36Sopenharmony_ci struct sockaddr_ib *listen_ib, *ib; 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci listen_ib = (struct sockaddr_ib *) &listen_id->route.addr.src_addr; 140262306a36Sopenharmony_ci if (src_addr) { 140362306a36Sopenharmony_ci ib = (struct sockaddr_ib *)src_addr; 140462306a36Sopenharmony_ci ib->sib_family = AF_IB; 140562306a36Sopenharmony_ci if (path) { 140662306a36Sopenharmony_ci ib->sib_pkey = path->pkey; 140762306a36Sopenharmony_ci ib->sib_flowinfo = path->flow_label; 140862306a36Sopenharmony_ci memcpy(&ib->sib_addr, &path->sgid, 16); 140962306a36Sopenharmony_ci ib->sib_sid = path->service_id; 141062306a36Sopenharmony_ci ib->sib_scope_id = 0; 141162306a36Sopenharmony_ci } else { 141262306a36Sopenharmony_ci ib->sib_pkey = listen_ib->sib_pkey; 141362306a36Sopenharmony_ci ib->sib_flowinfo = listen_ib->sib_flowinfo; 141462306a36Sopenharmony_ci ib->sib_addr = listen_ib->sib_addr; 141562306a36Sopenharmony_ci ib->sib_sid = listen_ib->sib_sid; 141662306a36Sopenharmony_ci ib->sib_scope_id = listen_ib->sib_scope_id; 141762306a36Sopenharmony_ci } 141862306a36Sopenharmony_ci ib->sib_sid_mask = cpu_to_be64(0xffffffffffffffffULL); 141962306a36Sopenharmony_ci } 142062306a36Sopenharmony_ci if (dst_addr) { 142162306a36Sopenharmony_ci ib = (struct sockaddr_ib *)dst_addr; 142262306a36Sopenharmony_ci ib->sib_family = AF_IB; 142362306a36Sopenharmony_ci if (path) { 142462306a36Sopenharmony_ci ib->sib_pkey = path->pkey; 142562306a36Sopenharmony_ci ib->sib_flowinfo = path->flow_label; 142662306a36Sopenharmony_ci memcpy(&ib->sib_addr, &path->dgid, 16); 142762306a36Sopenharmony_ci } 142862306a36Sopenharmony_ci } 142962306a36Sopenharmony_ci} 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_cistatic void cma_save_ip4_info(struct sockaddr_in *src_addr, 143262306a36Sopenharmony_ci struct sockaddr_in *dst_addr, 143362306a36Sopenharmony_ci struct cma_hdr *hdr, 143462306a36Sopenharmony_ci __be16 local_port) 143562306a36Sopenharmony_ci{ 143662306a36Sopenharmony_ci if (src_addr) { 143762306a36Sopenharmony_ci *src_addr = (struct sockaddr_in) { 143862306a36Sopenharmony_ci .sin_family = AF_INET, 143962306a36Sopenharmony_ci .sin_addr.s_addr = hdr->dst_addr.ip4.addr, 144062306a36Sopenharmony_ci .sin_port = local_port, 144162306a36Sopenharmony_ci }; 144262306a36Sopenharmony_ci } 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci if (dst_addr) { 144562306a36Sopenharmony_ci *dst_addr = (struct sockaddr_in) { 144662306a36Sopenharmony_ci .sin_family = AF_INET, 144762306a36Sopenharmony_ci .sin_addr.s_addr = hdr->src_addr.ip4.addr, 144862306a36Sopenharmony_ci .sin_port = hdr->port, 144962306a36Sopenharmony_ci }; 145062306a36Sopenharmony_ci } 145162306a36Sopenharmony_ci} 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_cistatic void cma_save_ip6_info(struct sockaddr_in6 *src_addr, 145462306a36Sopenharmony_ci struct sockaddr_in6 *dst_addr, 145562306a36Sopenharmony_ci struct cma_hdr *hdr, 145662306a36Sopenharmony_ci __be16 local_port) 145762306a36Sopenharmony_ci{ 145862306a36Sopenharmony_ci if (src_addr) { 145962306a36Sopenharmony_ci *src_addr = (struct sockaddr_in6) { 146062306a36Sopenharmony_ci .sin6_family = AF_INET6, 146162306a36Sopenharmony_ci .sin6_addr = hdr->dst_addr.ip6, 146262306a36Sopenharmony_ci .sin6_port = local_port, 146362306a36Sopenharmony_ci }; 146462306a36Sopenharmony_ci } 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci if (dst_addr) { 146762306a36Sopenharmony_ci *dst_addr = (struct sockaddr_in6) { 146862306a36Sopenharmony_ci .sin6_family = AF_INET6, 146962306a36Sopenharmony_ci .sin6_addr = hdr->src_addr.ip6, 147062306a36Sopenharmony_ci .sin6_port = hdr->port, 147162306a36Sopenharmony_ci }; 147262306a36Sopenharmony_ci } 147362306a36Sopenharmony_ci} 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_cistatic u16 cma_port_from_service_id(__be64 service_id) 147662306a36Sopenharmony_ci{ 147762306a36Sopenharmony_ci return (u16)be64_to_cpu(service_id); 147862306a36Sopenharmony_ci} 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_cistatic int cma_save_ip_info(struct sockaddr *src_addr, 148162306a36Sopenharmony_ci struct sockaddr *dst_addr, 148262306a36Sopenharmony_ci const struct ib_cm_event *ib_event, 148362306a36Sopenharmony_ci __be64 service_id) 148462306a36Sopenharmony_ci{ 148562306a36Sopenharmony_ci struct cma_hdr *hdr; 148662306a36Sopenharmony_ci __be16 port; 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci hdr = ib_event->private_data; 148962306a36Sopenharmony_ci if (hdr->cma_version != CMA_VERSION) 149062306a36Sopenharmony_ci return -EINVAL; 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci port = htons(cma_port_from_service_id(service_id)); 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci switch (cma_get_ip_ver(hdr)) { 149562306a36Sopenharmony_ci case 4: 149662306a36Sopenharmony_ci cma_save_ip4_info((struct sockaddr_in *)src_addr, 149762306a36Sopenharmony_ci (struct sockaddr_in *)dst_addr, hdr, port); 149862306a36Sopenharmony_ci break; 149962306a36Sopenharmony_ci case 6: 150062306a36Sopenharmony_ci cma_save_ip6_info((struct sockaddr_in6 *)src_addr, 150162306a36Sopenharmony_ci (struct sockaddr_in6 *)dst_addr, hdr, port); 150262306a36Sopenharmony_ci break; 150362306a36Sopenharmony_ci default: 150462306a36Sopenharmony_ci return -EAFNOSUPPORT; 150562306a36Sopenharmony_ci } 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci return 0; 150862306a36Sopenharmony_ci} 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_cistatic int cma_save_net_info(struct sockaddr *src_addr, 151162306a36Sopenharmony_ci struct sockaddr *dst_addr, 151262306a36Sopenharmony_ci const struct rdma_cm_id *listen_id, 151362306a36Sopenharmony_ci const struct ib_cm_event *ib_event, 151462306a36Sopenharmony_ci sa_family_t sa_family, __be64 service_id) 151562306a36Sopenharmony_ci{ 151662306a36Sopenharmony_ci if (sa_family == AF_IB) { 151762306a36Sopenharmony_ci if (ib_event->event == IB_CM_REQ_RECEIVED) 151862306a36Sopenharmony_ci cma_save_ib_info(src_addr, dst_addr, listen_id, 151962306a36Sopenharmony_ci ib_event->param.req_rcvd.primary_path); 152062306a36Sopenharmony_ci else if (ib_event->event == IB_CM_SIDR_REQ_RECEIVED) 152162306a36Sopenharmony_ci cma_save_ib_info(src_addr, dst_addr, listen_id, NULL); 152262306a36Sopenharmony_ci return 0; 152362306a36Sopenharmony_ci } 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci return cma_save_ip_info(src_addr, dst_addr, ib_event, service_id); 152662306a36Sopenharmony_ci} 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_cistatic int cma_save_req_info(const struct ib_cm_event *ib_event, 152962306a36Sopenharmony_ci struct cma_req_info *req) 153062306a36Sopenharmony_ci{ 153162306a36Sopenharmony_ci const struct ib_cm_req_event_param *req_param = 153262306a36Sopenharmony_ci &ib_event->param.req_rcvd; 153362306a36Sopenharmony_ci const struct ib_cm_sidr_req_event_param *sidr_param = 153462306a36Sopenharmony_ci &ib_event->param.sidr_req_rcvd; 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci switch (ib_event->event) { 153762306a36Sopenharmony_ci case IB_CM_REQ_RECEIVED: 153862306a36Sopenharmony_ci req->device = req_param->listen_id->device; 153962306a36Sopenharmony_ci req->port = req_param->port; 154062306a36Sopenharmony_ci memcpy(&req->local_gid, &req_param->primary_path->sgid, 154162306a36Sopenharmony_ci sizeof(req->local_gid)); 154262306a36Sopenharmony_ci req->has_gid = true; 154362306a36Sopenharmony_ci req->service_id = req_param->primary_path->service_id; 154462306a36Sopenharmony_ci req->pkey = be16_to_cpu(req_param->primary_path->pkey); 154562306a36Sopenharmony_ci if (req->pkey != req_param->bth_pkey) 154662306a36Sopenharmony_ci pr_warn_ratelimited("RDMA CMA: got different BTH P_Key (0x%x) and primary path P_Key (0x%x)\n" 154762306a36Sopenharmony_ci "RDMA CMA: in the future this may cause the request to be dropped\n", 154862306a36Sopenharmony_ci req_param->bth_pkey, req->pkey); 154962306a36Sopenharmony_ci break; 155062306a36Sopenharmony_ci case IB_CM_SIDR_REQ_RECEIVED: 155162306a36Sopenharmony_ci req->device = sidr_param->listen_id->device; 155262306a36Sopenharmony_ci req->port = sidr_param->port; 155362306a36Sopenharmony_ci req->has_gid = false; 155462306a36Sopenharmony_ci req->service_id = sidr_param->service_id; 155562306a36Sopenharmony_ci req->pkey = sidr_param->pkey; 155662306a36Sopenharmony_ci if (req->pkey != sidr_param->bth_pkey) 155762306a36Sopenharmony_ci pr_warn_ratelimited("RDMA CMA: got different BTH P_Key (0x%x) and SIDR request payload P_Key (0x%x)\n" 155862306a36Sopenharmony_ci "RDMA CMA: in the future this may cause the request to be dropped\n", 155962306a36Sopenharmony_ci sidr_param->bth_pkey, req->pkey); 156062306a36Sopenharmony_ci break; 156162306a36Sopenharmony_ci default: 156262306a36Sopenharmony_ci return -EINVAL; 156362306a36Sopenharmony_ci } 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_ci return 0; 156662306a36Sopenharmony_ci} 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_cistatic bool validate_ipv4_net_dev(struct net_device *net_dev, 156962306a36Sopenharmony_ci const struct sockaddr_in *dst_addr, 157062306a36Sopenharmony_ci const struct sockaddr_in *src_addr) 157162306a36Sopenharmony_ci{ 157262306a36Sopenharmony_ci __be32 daddr = dst_addr->sin_addr.s_addr, 157362306a36Sopenharmony_ci saddr = src_addr->sin_addr.s_addr; 157462306a36Sopenharmony_ci struct fib_result res; 157562306a36Sopenharmony_ci struct flowi4 fl4; 157662306a36Sopenharmony_ci int err; 157762306a36Sopenharmony_ci bool ret; 157862306a36Sopenharmony_ci 157962306a36Sopenharmony_ci if (ipv4_is_multicast(saddr) || ipv4_is_lbcast(saddr) || 158062306a36Sopenharmony_ci ipv4_is_lbcast(daddr) || ipv4_is_zeronet(saddr) || 158162306a36Sopenharmony_ci ipv4_is_zeronet(daddr) || ipv4_is_loopback(daddr) || 158262306a36Sopenharmony_ci ipv4_is_loopback(saddr)) 158362306a36Sopenharmony_ci return false; 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci memset(&fl4, 0, sizeof(fl4)); 158662306a36Sopenharmony_ci fl4.flowi4_oif = net_dev->ifindex; 158762306a36Sopenharmony_ci fl4.daddr = daddr; 158862306a36Sopenharmony_ci fl4.saddr = saddr; 158962306a36Sopenharmony_ci 159062306a36Sopenharmony_ci rcu_read_lock(); 159162306a36Sopenharmony_ci err = fib_lookup(dev_net(net_dev), &fl4, &res, 0); 159262306a36Sopenharmony_ci ret = err == 0 && FIB_RES_DEV(res) == net_dev; 159362306a36Sopenharmony_ci rcu_read_unlock(); 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci return ret; 159662306a36Sopenharmony_ci} 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_cistatic bool validate_ipv6_net_dev(struct net_device *net_dev, 159962306a36Sopenharmony_ci const struct sockaddr_in6 *dst_addr, 160062306a36Sopenharmony_ci const struct sockaddr_in6 *src_addr) 160162306a36Sopenharmony_ci{ 160262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 160362306a36Sopenharmony_ci const int strict = ipv6_addr_type(&dst_addr->sin6_addr) & 160462306a36Sopenharmony_ci IPV6_ADDR_LINKLOCAL; 160562306a36Sopenharmony_ci struct rt6_info *rt = rt6_lookup(dev_net(net_dev), &dst_addr->sin6_addr, 160662306a36Sopenharmony_ci &src_addr->sin6_addr, net_dev->ifindex, 160762306a36Sopenharmony_ci NULL, strict); 160862306a36Sopenharmony_ci bool ret; 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci if (!rt) 161162306a36Sopenharmony_ci return false; 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci ret = rt->rt6i_idev->dev == net_dev; 161462306a36Sopenharmony_ci ip6_rt_put(rt); 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_ci return ret; 161762306a36Sopenharmony_ci#else 161862306a36Sopenharmony_ci return false; 161962306a36Sopenharmony_ci#endif 162062306a36Sopenharmony_ci} 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_cistatic bool validate_net_dev(struct net_device *net_dev, 162362306a36Sopenharmony_ci const struct sockaddr *daddr, 162462306a36Sopenharmony_ci const struct sockaddr *saddr) 162562306a36Sopenharmony_ci{ 162662306a36Sopenharmony_ci const struct sockaddr_in *daddr4 = (const struct sockaddr_in *)daddr; 162762306a36Sopenharmony_ci const struct sockaddr_in *saddr4 = (const struct sockaddr_in *)saddr; 162862306a36Sopenharmony_ci const struct sockaddr_in6 *daddr6 = (const struct sockaddr_in6 *)daddr; 162962306a36Sopenharmony_ci const struct sockaddr_in6 *saddr6 = (const struct sockaddr_in6 *)saddr; 163062306a36Sopenharmony_ci 163162306a36Sopenharmony_ci switch (daddr->sa_family) { 163262306a36Sopenharmony_ci case AF_INET: 163362306a36Sopenharmony_ci return saddr->sa_family == AF_INET && 163462306a36Sopenharmony_ci validate_ipv4_net_dev(net_dev, daddr4, saddr4); 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ci case AF_INET6: 163762306a36Sopenharmony_ci return saddr->sa_family == AF_INET6 && 163862306a36Sopenharmony_ci validate_ipv6_net_dev(net_dev, daddr6, saddr6); 163962306a36Sopenharmony_ci 164062306a36Sopenharmony_ci default: 164162306a36Sopenharmony_ci return false; 164262306a36Sopenharmony_ci } 164362306a36Sopenharmony_ci} 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_cistatic struct net_device * 164662306a36Sopenharmony_ciroce_get_net_dev_by_cm_event(const struct ib_cm_event *ib_event) 164762306a36Sopenharmony_ci{ 164862306a36Sopenharmony_ci const struct ib_gid_attr *sgid_attr = NULL; 164962306a36Sopenharmony_ci struct net_device *ndev; 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_ci if (ib_event->event == IB_CM_REQ_RECEIVED) 165262306a36Sopenharmony_ci sgid_attr = ib_event->param.req_rcvd.ppath_sgid_attr; 165362306a36Sopenharmony_ci else if (ib_event->event == IB_CM_SIDR_REQ_RECEIVED) 165462306a36Sopenharmony_ci sgid_attr = ib_event->param.sidr_req_rcvd.sgid_attr; 165562306a36Sopenharmony_ci 165662306a36Sopenharmony_ci if (!sgid_attr) 165762306a36Sopenharmony_ci return NULL; 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_ci rcu_read_lock(); 166062306a36Sopenharmony_ci ndev = rdma_read_gid_attr_ndev_rcu(sgid_attr); 166162306a36Sopenharmony_ci if (IS_ERR(ndev)) 166262306a36Sopenharmony_ci ndev = NULL; 166362306a36Sopenharmony_ci else 166462306a36Sopenharmony_ci dev_hold(ndev); 166562306a36Sopenharmony_ci rcu_read_unlock(); 166662306a36Sopenharmony_ci return ndev; 166762306a36Sopenharmony_ci} 166862306a36Sopenharmony_ci 166962306a36Sopenharmony_cistatic struct net_device *cma_get_net_dev(const struct ib_cm_event *ib_event, 167062306a36Sopenharmony_ci struct cma_req_info *req) 167162306a36Sopenharmony_ci{ 167262306a36Sopenharmony_ci struct sockaddr *listen_addr = 167362306a36Sopenharmony_ci (struct sockaddr *)&req->listen_addr_storage; 167462306a36Sopenharmony_ci struct sockaddr *src_addr = (struct sockaddr *)&req->src_addr_storage; 167562306a36Sopenharmony_ci struct net_device *net_dev; 167662306a36Sopenharmony_ci const union ib_gid *gid = req->has_gid ? &req->local_gid : NULL; 167762306a36Sopenharmony_ci int err; 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_ci err = cma_save_ip_info(listen_addr, src_addr, ib_event, 168062306a36Sopenharmony_ci req->service_id); 168162306a36Sopenharmony_ci if (err) 168262306a36Sopenharmony_ci return ERR_PTR(err); 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci if (rdma_protocol_roce(req->device, req->port)) 168562306a36Sopenharmony_ci net_dev = roce_get_net_dev_by_cm_event(ib_event); 168662306a36Sopenharmony_ci else 168762306a36Sopenharmony_ci net_dev = ib_get_net_dev_by_params(req->device, req->port, 168862306a36Sopenharmony_ci req->pkey, 168962306a36Sopenharmony_ci gid, listen_addr); 169062306a36Sopenharmony_ci if (!net_dev) 169162306a36Sopenharmony_ci return ERR_PTR(-ENODEV); 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_ci return net_dev; 169462306a36Sopenharmony_ci} 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_cistatic enum rdma_ucm_port_space rdma_ps_from_service_id(__be64 service_id) 169762306a36Sopenharmony_ci{ 169862306a36Sopenharmony_ci return (be64_to_cpu(service_id) >> 16) & 0xffff; 169962306a36Sopenharmony_ci} 170062306a36Sopenharmony_ci 170162306a36Sopenharmony_cistatic bool cma_match_private_data(struct rdma_id_private *id_priv, 170262306a36Sopenharmony_ci const struct cma_hdr *hdr) 170362306a36Sopenharmony_ci{ 170462306a36Sopenharmony_ci struct sockaddr *addr = cma_src_addr(id_priv); 170562306a36Sopenharmony_ci __be32 ip4_addr; 170662306a36Sopenharmony_ci struct in6_addr ip6_addr; 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci if (cma_any_addr(addr) && !id_priv->afonly) 170962306a36Sopenharmony_ci return true; 171062306a36Sopenharmony_ci 171162306a36Sopenharmony_ci switch (addr->sa_family) { 171262306a36Sopenharmony_ci case AF_INET: 171362306a36Sopenharmony_ci ip4_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr; 171462306a36Sopenharmony_ci if (cma_get_ip_ver(hdr) != 4) 171562306a36Sopenharmony_ci return false; 171662306a36Sopenharmony_ci if (!cma_any_addr(addr) && 171762306a36Sopenharmony_ci hdr->dst_addr.ip4.addr != ip4_addr) 171862306a36Sopenharmony_ci return false; 171962306a36Sopenharmony_ci break; 172062306a36Sopenharmony_ci case AF_INET6: 172162306a36Sopenharmony_ci ip6_addr = ((struct sockaddr_in6 *)addr)->sin6_addr; 172262306a36Sopenharmony_ci if (cma_get_ip_ver(hdr) != 6) 172362306a36Sopenharmony_ci return false; 172462306a36Sopenharmony_ci if (!cma_any_addr(addr) && 172562306a36Sopenharmony_ci memcmp(&hdr->dst_addr.ip6, &ip6_addr, sizeof(ip6_addr))) 172662306a36Sopenharmony_ci return false; 172762306a36Sopenharmony_ci break; 172862306a36Sopenharmony_ci case AF_IB: 172962306a36Sopenharmony_ci return true; 173062306a36Sopenharmony_ci default: 173162306a36Sopenharmony_ci return false; 173262306a36Sopenharmony_ci } 173362306a36Sopenharmony_ci 173462306a36Sopenharmony_ci return true; 173562306a36Sopenharmony_ci} 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_cistatic bool cma_protocol_roce(const struct rdma_cm_id *id) 173862306a36Sopenharmony_ci{ 173962306a36Sopenharmony_ci struct ib_device *device = id->device; 174062306a36Sopenharmony_ci const u32 port_num = id->port_num ?: rdma_start_port(device); 174162306a36Sopenharmony_ci 174262306a36Sopenharmony_ci return rdma_protocol_roce(device, port_num); 174362306a36Sopenharmony_ci} 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_cistatic bool cma_is_req_ipv6_ll(const struct cma_req_info *req) 174662306a36Sopenharmony_ci{ 174762306a36Sopenharmony_ci const struct sockaddr *daddr = 174862306a36Sopenharmony_ci (const struct sockaddr *)&req->listen_addr_storage; 174962306a36Sopenharmony_ci const struct sockaddr_in6 *daddr6 = (const struct sockaddr_in6 *)daddr; 175062306a36Sopenharmony_ci 175162306a36Sopenharmony_ci /* Returns true if the req is for IPv6 link local */ 175262306a36Sopenharmony_ci return (daddr->sa_family == AF_INET6 && 175362306a36Sopenharmony_ci (ipv6_addr_type(&daddr6->sin6_addr) & IPV6_ADDR_LINKLOCAL)); 175462306a36Sopenharmony_ci} 175562306a36Sopenharmony_ci 175662306a36Sopenharmony_cistatic bool cma_match_net_dev(const struct rdma_cm_id *id, 175762306a36Sopenharmony_ci const struct net_device *net_dev, 175862306a36Sopenharmony_ci const struct cma_req_info *req) 175962306a36Sopenharmony_ci{ 176062306a36Sopenharmony_ci const struct rdma_addr *addr = &id->route.addr; 176162306a36Sopenharmony_ci 176262306a36Sopenharmony_ci if (!net_dev) 176362306a36Sopenharmony_ci /* This request is an AF_IB request */ 176462306a36Sopenharmony_ci return (!id->port_num || id->port_num == req->port) && 176562306a36Sopenharmony_ci (addr->src_addr.ss_family == AF_IB); 176662306a36Sopenharmony_ci 176762306a36Sopenharmony_ci /* 176862306a36Sopenharmony_ci * If the request is not for IPv6 link local, allow matching 176962306a36Sopenharmony_ci * request to any netdevice of the one or multiport rdma device. 177062306a36Sopenharmony_ci */ 177162306a36Sopenharmony_ci if (!cma_is_req_ipv6_ll(req)) 177262306a36Sopenharmony_ci return true; 177362306a36Sopenharmony_ci /* 177462306a36Sopenharmony_ci * Net namespaces must match, and if the listner is listening 177562306a36Sopenharmony_ci * on a specific netdevice than netdevice must match as well. 177662306a36Sopenharmony_ci */ 177762306a36Sopenharmony_ci if (net_eq(dev_net(net_dev), addr->dev_addr.net) && 177862306a36Sopenharmony_ci (!!addr->dev_addr.bound_dev_if == 177962306a36Sopenharmony_ci (addr->dev_addr.bound_dev_if == net_dev->ifindex))) 178062306a36Sopenharmony_ci return true; 178162306a36Sopenharmony_ci else 178262306a36Sopenharmony_ci return false; 178362306a36Sopenharmony_ci} 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_cistatic struct rdma_id_private *cma_find_listener( 178662306a36Sopenharmony_ci const struct rdma_bind_list *bind_list, 178762306a36Sopenharmony_ci const struct ib_cm_id *cm_id, 178862306a36Sopenharmony_ci const struct ib_cm_event *ib_event, 178962306a36Sopenharmony_ci const struct cma_req_info *req, 179062306a36Sopenharmony_ci const struct net_device *net_dev) 179162306a36Sopenharmony_ci{ 179262306a36Sopenharmony_ci struct rdma_id_private *id_priv, *id_priv_dev; 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_ci lockdep_assert_held(&lock); 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_ci if (!bind_list) 179762306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 179862306a36Sopenharmony_ci 179962306a36Sopenharmony_ci hlist_for_each_entry(id_priv, &bind_list->owners, node) { 180062306a36Sopenharmony_ci if (cma_match_private_data(id_priv, ib_event->private_data)) { 180162306a36Sopenharmony_ci if (id_priv->id.device == cm_id->device && 180262306a36Sopenharmony_ci cma_match_net_dev(&id_priv->id, net_dev, req)) 180362306a36Sopenharmony_ci return id_priv; 180462306a36Sopenharmony_ci list_for_each_entry(id_priv_dev, 180562306a36Sopenharmony_ci &id_priv->listen_list, 180662306a36Sopenharmony_ci listen_item) { 180762306a36Sopenharmony_ci if (id_priv_dev->id.device == cm_id->device && 180862306a36Sopenharmony_ci cma_match_net_dev(&id_priv_dev->id, 180962306a36Sopenharmony_ci net_dev, req)) 181062306a36Sopenharmony_ci return id_priv_dev; 181162306a36Sopenharmony_ci } 181262306a36Sopenharmony_ci } 181362306a36Sopenharmony_ci } 181462306a36Sopenharmony_ci 181562306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 181662306a36Sopenharmony_ci} 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_cistatic struct rdma_id_private * 181962306a36Sopenharmony_cicma_ib_id_from_event(struct ib_cm_id *cm_id, 182062306a36Sopenharmony_ci const struct ib_cm_event *ib_event, 182162306a36Sopenharmony_ci struct cma_req_info *req, 182262306a36Sopenharmony_ci struct net_device **net_dev) 182362306a36Sopenharmony_ci{ 182462306a36Sopenharmony_ci struct rdma_bind_list *bind_list; 182562306a36Sopenharmony_ci struct rdma_id_private *id_priv; 182662306a36Sopenharmony_ci int err; 182762306a36Sopenharmony_ci 182862306a36Sopenharmony_ci err = cma_save_req_info(ib_event, req); 182962306a36Sopenharmony_ci if (err) 183062306a36Sopenharmony_ci return ERR_PTR(err); 183162306a36Sopenharmony_ci 183262306a36Sopenharmony_ci *net_dev = cma_get_net_dev(ib_event, req); 183362306a36Sopenharmony_ci if (IS_ERR(*net_dev)) { 183462306a36Sopenharmony_ci if (PTR_ERR(*net_dev) == -EAFNOSUPPORT) { 183562306a36Sopenharmony_ci /* Assuming the protocol is AF_IB */ 183662306a36Sopenharmony_ci *net_dev = NULL; 183762306a36Sopenharmony_ci } else { 183862306a36Sopenharmony_ci return ERR_CAST(*net_dev); 183962306a36Sopenharmony_ci } 184062306a36Sopenharmony_ci } 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ci mutex_lock(&lock); 184362306a36Sopenharmony_ci /* 184462306a36Sopenharmony_ci * Net namespace might be getting deleted while route lookup, 184562306a36Sopenharmony_ci * cm_id lookup is in progress. Therefore, perform netdevice 184662306a36Sopenharmony_ci * validation, cm_id lookup under rcu lock. 184762306a36Sopenharmony_ci * RCU lock along with netdevice state check, synchronizes with 184862306a36Sopenharmony_ci * netdevice migrating to different net namespace and also avoids 184962306a36Sopenharmony_ci * case where net namespace doesn't get deleted while lookup is in 185062306a36Sopenharmony_ci * progress. 185162306a36Sopenharmony_ci * If the device state is not IFF_UP, its properties such as ifindex 185262306a36Sopenharmony_ci * and nd_net cannot be trusted to remain valid without rcu lock. 185362306a36Sopenharmony_ci * net/core/dev.c change_net_namespace() ensures to synchronize with 185462306a36Sopenharmony_ci * ongoing operations on net device after device is closed using 185562306a36Sopenharmony_ci * synchronize_net(). 185662306a36Sopenharmony_ci */ 185762306a36Sopenharmony_ci rcu_read_lock(); 185862306a36Sopenharmony_ci if (*net_dev) { 185962306a36Sopenharmony_ci /* 186062306a36Sopenharmony_ci * If netdevice is down, it is likely that it is administratively 186162306a36Sopenharmony_ci * down or it might be migrating to different namespace. 186262306a36Sopenharmony_ci * In that case avoid further processing, as the net namespace 186362306a36Sopenharmony_ci * or ifindex may change. 186462306a36Sopenharmony_ci */ 186562306a36Sopenharmony_ci if (((*net_dev)->flags & IFF_UP) == 0) { 186662306a36Sopenharmony_ci id_priv = ERR_PTR(-EHOSTUNREACH); 186762306a36Sopenharmony_ci goto err; 186862306a36Sopenharmony_ci } 186962306a36Sopenharmony_ci 187062306a36Sopenharmony_ci if (!validate_net_dev(*net_dev, 187162306a36Sopenharmony_ci (struct sockaddr *)&req->src_addr_storage, 187262306a36Sopenharmony_ci (struct sockaddr *)&req->listen_addr_storage)) { 187362306a36Sopenharmony_ci id_priv = ERR_PTR(-EHOSTUNREACH); 187462306a36Sopenharmony_ci goto err; 187562306a36Sopenharmony_ci } 187662306a36Sopenharmony_ci } 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_ci bind_list = cma_ps_find(*net_dev ? dev_net(*net_dev) : &init_net, 187962306a36Sopenharmony_ci rdma_ps_from_service_id(req->service_id), 188062306a36Sopenharmony_ci cma_port_from_service_id(req->service_id)); 188162306a36Sopenharmony_ci id_priv = cma_find_listener(bind_list, cm_id, ib_event, req, *net_dev); 188262306a36Sopenharmony_cierr: 188362306a36Sopenharmony_ci rcu_read_unlock(); 188462306a36Sopenharmony_ci mutex_unlock(&lock); 188562306a36Sopenharmony_ci if (IS_ERR(id_priv) && *net_dev) { 188662306a36Sopenharmony_ci dev_put(*net_dev); 188762306a36Sopenharmony_ci *net_dev = NULL; 188862306a36Sopenharmony_ci } 188962306a36Sopenharmony_ci return id_priv; 189062306a36Sopenharmony_ci} 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_cistatic inline u8 cma_user_data_offset(struct rdma_id_private *id_priv) 189362306a36Sopenharmony_ci{ 189462306a36Sopenharmony_ci return cma_family(id_priv) == AF_IB ? 0 : sizeof(struct cma_hdr); 189562306a36Sopenharmony_ci} 189662306a36Sopenharmony_ci 189762306a36Sopenharmony_cistatic void cma_cancel_route(struct rdma_id_private *id_priv) 189862306a36Sopenharmony_ci{ 189962306a36Sopenharmony_ci if (rdma_cap_ib_sa(id_priv->id.device, id_priv->id.port_num)) { 190062306a36Sopenharmony_ci if (id_priv->query) 190162306a36Sopenharmony_ci ib_sa_cancel_query(id_priv->query_id, id_priv->query); 190262306a36Sopenharmony_ci } 190362306a36Sopenharmony_ci} 190462306a36Sopenharmony_ci 190562306a36Sopenharmony_cistatic void _cma_cancel_listens(struct rdma_id_private *id_priv) 190662306a36Sopenharmony_ci{ 190762306a36Sopenharmony_ci struct rdma_id_private *dev_id_priv; 190862306a36Sopenharmony_ci 190962306a36Sopenharmony_ci lockdep_assert_held(&lock); 191062306a36Sopenharmony_ci 191162306a36Sopenharmony_ci /* 191262306a36Sopenharmony_ci * Remove from listen_any_list to prevent added devices from spawning 191362306a36Sopenharmony_ci * additional listen requests. 191462306a36Sopenharmony_ci */ 191562306a36Sopenharmony_ci list_del_init(&id_priv->listen_any_item); 191662306a36Sopenharmony_ci 191762306a36Sopenharmony_ci while (!list_empty(&id_priv->listen_list)) { 191862306a36Sopenharmony_ci dev_id_priv = 191962306a36Sopenharmony_ci list_first_entry(&id_priv->listen_list, 192062306a36Sopenharmony_ci struct rdma_id_private, listen_item); 192162306a36Sopenharmony_ci /* sync with device removal to avoid duplicate destruction */ 192262306a36Sopenharmony_ci list_del_init(&dev_id_priv->device_item); 192362306a36Sopenharmony_ci list_del_init(&dev_id_priv->listen_item); 192462306a36Sopenharmony_ci mutex_unlock(&lock); 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_ci rdma_destroy_id(&dev_id_priv->id); 192762306a36Sopenharmony_ci mutex_lock(&lock); 192862306a36Sopenharmony_ci } 192962306a36Sopenharmony_ci} 193062306a36Sopenharmony_ci 193162306a36Sopenharmony_cistatic void cma_cancel_listens(struct rdma_id_private *id_priv) 193262306a36Sopenharmony_ci{ 193362306a36Sopenharmony_ci mutex_lock(&lock); 193462306a36Sopenharmony_ci _cma_cancel_listens(id_priv); 193562306a36Sopenharmony_ci mutex_unlock(&lock); 193662306a36Sopenharmony_ci} 193762306a36Sopenharmony_ci 193862306a36Sopenharmony_cistatic void cma_cancel_operation(struct rdma_id_private *id_priv, 193962306a36Sopenharmony_ci enum rdma_cm_state state) 194062306a36Sopenharmony_ci{ 194162306a36Sopenharmony_ci switch (state) { 194262306a36Sopenharmony_ci case RDMA_CM_ADDR_QUERY: 194362306a36Sopenharmony_ci /* 194462306a36Sopenharmony_ci * We can avoid doing the rdma_addr_cancel() based on state, 194562306a36Sopenharmony_ci * only RDMA_CM_ADDR_QUERY has a work that could still execute. 194662306a36Sopenharmony_ci * Notice that the addr_handler work could still be exiting 194762306a36Sopenharmony_ci * outside this state, however due to the interaction with the 194862306a36Sopenharmony_ci * handler_mutex the work is guaranteed not to touch id_priv 194962306a36Sopenharmony_ci * during exit. 195062306a36Sopenharmony_ci */ 195162306a36Sopenharmony_ci rdma_addr_cancel(&id_priv->id.route.addr.dev_addr); 195262306a36Sopenharmony_ci break; 195362306a36Sopenharmony_ci case RDMA_CM_ROUTE_QUERY: 195462306a36Sopenharmony_ci cma_cancel_route(id_priv); 195562306a36Sopenharmony_ci break; 195662306a36Sopenharmony_ci case RDMA_CM_LISTEN: 195762306a36Sopenharmony_ci if (cma_any_addr(cma_src_addr(id_priv)) && !id_priv->cma_dev) 195862306a36Sopenharmony_ci cma_cancel_listens(id_priv); 195962306a36Sopenharmony_ci break; 196062306a36Sopenharmony_ci default: 196162306a36Sopenharmony_ci break; 196262306a36Sopenharmony_ci } 196362306a36Sopenharmony_ci} 196462306a36Sopenharmony_ci 196562306a36Sopenharmony_cistatic void cma_release_port(struct rdma_id_private *id_priv) 196662306a36Sopenharmony_ci{ 196762306a36Sopenharmony_ci struct rdma_bind_list *bind_list = id_priv->bind_list; 196862306a36Sopenharmony_ci struct net *net = id_priv->id.route.addr.dev_addr.net; 196962306a36Sopenharmony_ci 197062306a36Sopenharmony_ci if (!bind_list) 197162306a36Sopenharmony_ci return; 197262306a36Sopenharmony_ci 197362306a36Sopenharmony_ci mutex_lock(&lock); 197462306a36Sopenharmony_ci hlist_del(&id_priv->node); 197562306a36Sopenharmony_ci if (hlist_empty(&bind_list->owners)) { 197662306a36Sopenharmony_ci cma_ps_remove(net, bind_list->ps, bind_list->port); 197762306a36Sopenharmony_ci kfree(bind_list); 197862306a36Sopenharmony_ci } 197962306a36Sopenharmony_ci mutex_unlock(&lock); 198062306a36Sopenharmony_ci} 198162306a36Sopenharmony_ci 198262306a36Sopenharmony_cistatic void destroy_mc(struct rdma_id_private *id_priv, 198362306a36Sopenharmony_ci struct cma_multicast *mc) 198462306a36Sopenharmony_ci{ 198562306a36Sopenharmony_ci bool send_only = mc->join_state == BIT(SENDONLY_FULLMEMBER_JOIN); 198662306a36Sopenharmony_ci 198762306a36Sopenharmony_ci if (rdma_cap_ib_mcast(id_priv->id.device, id_priv->id.port_num)) 198862306a36Sopenharmony_ci ib_sa_free_multicast(mc->sa_mc); 198962306a36Sopenharmony_ci 199062306a36Sopenharmony_ci if (rdma_protocol_roce(id_priv->id.device, id_priv->id.port_num)) { 199162306a36Sopenharmony_ci struct rdma_dev_addr *dev_addr = 199262306a36Sopenharmony_ci &id_priv->id.route.addr.dev_addr; 199362306a36Sopenharmony_ci struct net_device *ndev = NULL; 199462306a36Sopenharmony_ci 199562306a36Sopenharmony_ci if (dev_addr->bound_dev_if) 199662306a36Sopenharmony_ci ndev = dev_get_by_index(dev_addr->net, 199762306a36Sopenharmony_ci dev_addr->bound_dev_if); 199862306a36Sopenharmony_ci if (ndev && !send_only) { 199962306a36Sopenharmony_ci enum ib_gid_type gid_type; 200062306a36Sopenharmony_ci union ib_gid mgid; 200162306a36Sopenharmony_ci 200262306a36Sopenharmony_ci gid_type = id_priv->cma_dev->default_gid_type 200362306a36Sopenharmony_ci [id_priv->id.port_num - 200462306a36Sopenharmony_ci rdma_start_port( 200562306a36Sopenharmony_ci id_priv->cma_dev->device)]; 200662306a36Sopenharmony_ci cma_iboe_set_mgid((struct sockaddr *)&mc->addr, &mgid, 200762306a36Sopenharmony_ci gid_type); 200862306a36Sopenharmony_ci cma_igmp_send(ndev, &mgid, false); 200962306a36Sopenharmony_ci } 201062306a36Sopenharmony_ci dev_put(ndev); 201162306a36Sopenharmony_ci 201262306a36Sopenharmony_ci cancel_work_sync(&mc->iboe_join.work); 201362306a36Sopenharmony_ci } 201462306a36Sopenharmony_ci kfree(mc); 201562306a36Sopenharmony_ci} 201662306a36Sopenharmony_ci 201762306a36Sopenharmony_cistatic void cma_leave_mc_groups(struct rdma_id_private *id_priv) 201862306a36Sopenharmony_ci{ 201962306a36Sopenharmony_ci struct cma_multicast *mc; 202062306a36Sopenharmony_ci 202162306a36Sopenharmony_ci while (!list_empty(&id_priv->mc_list)) { 202262306a36Sopenharmony_ci mc = list_first_entry(&id_priv->mc_list, struct cma_multicast, 202362306a36Sopenharmony_ci list); 202462306a36Sopenharmony_ci list_del(&mc->list); 202562306a36Sopenharmony_ci destroy_mc(id_priv, mc); 202662306a36Sopenharmony_ci } 202762306a36Sopenharmony_ci} 202862306a36Sopenharmony_ci 202962306a36Sopenharmony_cistatic void _destroy_id(struct rdma_id_private *id_priv, 203062306a36Sopenharmony_ci enum rdma_cm_state state) 203162306a36Sopenharmony_ci{ 203262306a36Sopenharmony_ci cma_cancel_operation(id_priv, state); 203362306a36Sopenharmony_ci 203462306a36Sopenharmony_ci rdma_restrack_del(&id_priv->res); 203562306a36Sopenharmony_ci cma_remove_id_from_tree(id_priv); 203662306a36Sopenharmony_ci if (id_priv->cma_dev) { 203762306a36Sopenharmony_ci if (rdma_cap_ib_cm(id_priv->id.device, 1)) { 203862306a36Sopenharmony_ci if (id_priv->cm_id.ib) 203962306a36Sopenharmony_ci ib_destroy_cm_id(id_priv->cm_id.ib); 204062306a36Sopenharmony_ci } else if (rdma_cap_iw_cm(id_priv->id.device, 1)) { 204162306a36Sopenharmony_ci if (id_priv->cm_id.iw) 204262306a36Sopenharmony_ci iw_destroy_cm_id(id_priv->cm_id.iw); 204362306a36Sopenharmony_ci } 204462306a36Sopenharmony_ci cma_leave_mc_groups(id_priv); 204562306a36Sopenharmony_ci cma_release_dev(id_priv); 204662306a36Sopenharmony_ci } 204762306a36Sopenharmony_ci 204862306a36Sopenharmony_ci cma_release_port(id_priv); 204962306a36Sopenharmony_ci cma_id_put(id_priv); 205062306a36Sopenharmony_ci wait_for_completion(&id_priv->comp); 205162306a36Sopenharmony_ci 205262306a36Sopenharmony_ci if (id_priv->internal_id) 205362306a36Sopenharmony_ci cma_id_put(id_priv->id.context); 205462306a36Sopenharmony_ci 205562306a36Sopenharmony_ci kfree(id_priv->id.route.path_rec); 205662306a36Sopenharmony_ci kfree(id_priv->id.route.path_rec_inbound); 205762306a36Sopenharmony_ci kfree(id_priv->id.route.path_rec_outbound); 205862306a36Sopenharmony_ci 205962306a36Sopenharmony_ci put_net(id_priv->id.route.addr.dev_addr.net); 206062306a36Sopenharmony_ci kfree(id_priv); 206162306a36Sopenharmony_ci} 206262306a36Sopenharmony_ci 206362306a36Sopenharmony_ci/* 206462306a36Sopenharmony_ci * destroy an ID from within the handler_mutex. This ensures that no other 206562306a36Sopenharmony_ci * handlers can start running concurrently. 206662306a36Sopenharmony_ci */ 206762306a36Sopenharmony_cistatic void destroy_id_handler_unlock(struct rdma_id_private *id_priv) 206862306a36Sopenharmony_ci __releases(&idprv->handler_mutex) 206962306a36Sopenharmony_ci{ 207062306a36Sopenharmony_ci enum rdma_cm_state state; 207162306a36Sopenharmony_ci unsigned long flags; 207262306a36Sopenharmony_ci 207362306a36Sopenharmony_ci trace_cm_id_destroy(id_priv); 207462306a36Sopenharmony_ci 207562306a36Sopenharmony_ci /* 207662306a36Sopenharmony_ci * Setting the state to destroyed under the handler mutex provides a 207762306a36Sopenharmony_ci * fence against calling handler callbacks. If this is invoked due to 207862306a36Sopenharmony_ci * the failure of a handler callback then it guarentees that no future 207962306a36Sopenharmony_ci * handlers will be called. 208062306a36Sopenharmony_ci */ 208162306a36Sopenharmony_ci lockdep_assert_held(&id_priv->handler_mutex); 208262306a36Sopenharmony_ci spin_lock_irqsave(&id_priv->lock, flags); 208362306a36Sopenharmony_ci state = id_priv->state; 208462306a36Sopenharmony_ci id_priv->state = RDMA_CM_DESTROYING; 208562306a36Sopenharmony_ci spin_unlock_irqrestore(&id_priv->lock, flags); 208662306a36Sopenharmony_ci mutex_unlock(&id_priv->handler_mutex); 208762306a36Sopenharmony_ci _destroy_id(id_priv, state); 208862306a36Sopenharmony_ci} 208962306a36Sopenharmony_ci 209062306a36Sopenharmony_civoid rdma_destroy_id(struct rdma_cm_id *id) 209162306a36Sopenharmony_ci{ 209262306a36Sopenharmony_ci struct rdma_id_private *id_priv = 209362306a36Sopenharmony_ci container_of(id, struct rdma_id_private, id); 209462306a36Sopenharmony_ci 209562306a36Sopenharmony_ci mutex_lock(&id_priv->handler_mutex); 209662306a36Sopenharmony_ci destroy_id_handler_unlock(id_priv); 209762306a36Sopenharmony_ci} 209862306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_destroy_id); 209962306a36Sopenharmony_ci 210062306a36Sopenharmony_cistatic int cma_rep_recv(struct rdma_id_private *id_priv) 210162306a36Sopenharmony_ci{ 210262306a36Sopenharmony_ci int ret; 210362306a36Sopenharmony_ci 210462306a36Sopenharmony_ci ret = cma_modify_qp_rtr(id_priv, NULL); 210562306a36Sopenharmony_ci if (ret) 210662306a36Sopenharmony_ci goto reject; 210762306a36Sopenharmony_ci 210862306a36Sopenharmony_ci ret = cma_modify_qp_rts(id_priv, NULL); 210962306a36Sopenharmony_ci if (ret) 211062306a36Sopenharmony_ci goto reject; 211162306a36Sopenharmony_ci 211262306a36Sopenharmony_ci trace_cm_send_rtu(id_priv); 211362306a36Sopenharmony_ci ret = ib_send_cm_rtu(id_priv->cm_id.ib, NULL, 0); 211462306a36Sopenharmony_ci if (ret) 211562306a36Sopenharmony_ci goto reject; 211662306a36Sopenharmony_ci 211762306a36Sopenharmony_ci return 0; 211862306a36Sopenharmony_cireject: 211962306a36Sopenharmony_ci pr_debug_ratelimited("RDMA CM: CONNECT_ERROR: failed to handle reply. status %d\n", ret); 212062306a36Sopenharmony_ci cma_modify_qp_err(id_priv); 212162306a36Sopenharmony_ci trace_cm_send_rej(id_priv); 212262306a36Sopenharmony_ci ib_send_cm_rej(id_priv->cm_id.ib, IB_CM_REJ_CONSUMER_DEFINED, 212362306a36Sopenharmony_ci NULL, 0, NULL, 0); 212462306a36Sopenharmony_ci return ret; 212562306a36Sopenharmony_ci} 212662306a36Sopenharmony_ci 212762306a36Sopenharmony_cistatic void cma_set_rep_event_data(struct rdma_cm_event *event, 212862306a36Sopenharmony_ci const struct ib_cm_rep_event_param *rep_data, 212962306a36Sopenharmony_ci void *private_data) 213062306a36Sopenharmony_ci{ 213162306a36Sopenharmony_ci event->param.conn.private_data = private_data; 213262306a36Sopenharmony_ci event->param.conn.private_data_len = IB_CM_REP_PRIVATE_DATA_SIZE; 213362306a36Sopenharmony_ci event->param.conn.responder_resources = rep_data->responder_resources; 213462306a36Sopenharmony_ci event->param.conn.initiator_depth = rep_data->initiator_depth; 213562306a36Sopenharmony_ci event->param.conn.flow_control = rep_data->flow_control; 213662306a36Sopenharmony_ci event->param.conn.rnr_retry_count = rep_data->rnr_retry_count; 213762306a36Sopenharmony_ci event->param.conn.srq = rep_data->srq; 213862306a36Sopenharmony_ci event->param.conn.qp_num = rep_data->remote_qpn; 213962306a36Sopenharmony_ci 214062306a36Sopenharmony_ci event->ece.vendor_id = rep_data->ece.vendor_id; 214162306a36Sopenharmony_ci event->ece.attr_mod = rep_data->ece.attr_mod; 214262306a36Sopenharmony_ci} 214362306a36Sopenharmony_ci 214462306a36Sopenharmony_cistatic int cma_cm_event_handler(struct rdma_id_private *id_priv, 214562306a36Sopenharmony_ci struct rdma_cm_event *event) 214662306a36Sopenharmony_ci{ 214762306a36Sopenharmony_ci int ret; 214862306a36Sopenharmony_ci 214962306a36Sopenharmony_ci lockdep_assert_held(&id_priv->handler_mutex); 215062306a36Sopenharmony_ci 215162306a36Sopenharmony_ci trace_cm_event_handler(id_priv, event); 215262306a36Sopenharmony_ci ret = id_priv->id.event_handler(&id_priv->id, event); 215362306a36Sopenharmony_ci trace_cm_event_done(id_priv, event, ret); 215462306a36Sopenharmony_ci return ret; 215562306a36Sopenharmony_ci} 215662306a36Sopenharmony_ci 215762306a36Sopenharmony_cistatic int cma_ib_handler(struct ib_cm_id *cm_id, 215862306a36Sopenharmony_ci const struct ib_cm_event *ib_event) 215962306a36Sopenharmony_ci{ 216062306a36Sopenharmony_ci struct rdma_id_private *id_priv = cm_id->context; 216162306a36Sopenharmony_ci struct rdma_cm_event event = {}; 216262306a36Sopenharmony_ci enum rdma_cm_state state; 216362306a36Sopenharmony_ci int ret; 216462306a36Sopenharmony_ci 216562306a36Sopenharmony_ci mutex_lock(&id_priv->handler_mutex); 216662306a36Sopenharmony_ci state = READ_ONCE(id_priv->state); 216762306a36Sopenharmony_ci if ((ib_event->event != IB_CM_TIMEWAIT_EXIT && 216862306a36Sopenharmony_ci state != RDMA_CM_CONNECT) || 216962306a36Sopenharmony_ci (ib_event->event == IB_CM_TIMEWAIT_EXIT && 217062306a36Sopenharmony_ci state != RDMA_CM_DISCONNECT)) 217162306a36Sopenharmony_ci goto out; 217262306a36Sopenharmony_ci 217362306a36Sopenharmony_ci switch (ib_event->event) { 217462306a36Sopenharmony_ci case IB_CM_REQ_ERROR: 217562306a36Sopenharmony_ci case IB_CM_REP_ERROR: 217662306a36Sopenharmony_ci event.event = RDMA_CM_EVENT_UNREACHABLE; 217762306a36Sopenharmony_ci event.status = -ETIMEDOUT; 217862306a36Sopenharmony_ci break; 217962306a36Sopenharmony_ci case IB_CM_REP_RECEIVED: 218062306a36Sopenharmony_ci if (state == RDMA_CM_CONNECT && 218162306a36Sopenharmony_ci (id_priv->id.qp_type != IB_QPT_UD)) { 218262306a36Sopenharmony_ci trace_cm_send_mra(id_priv); 218362306a36Sopenharmony_ci ib_send_cm_mra(cm_id, CMA_CM_MRA_SETTING, NULL, 0); 218462306a36Sopenharmony_ci } 218562306a36Sopenharmony_ci if (id_priv->id.qp) { 218662306a36Sopenharmony_ci event.status = cma_rep_recv(id_priv); 218762306a36Sopenharmony_ci event.event = event.status ? RDMA_CM_EVENT_CONNECT_ERROR : 218862306a36Sopenharmony_ci RDMA_CM_EVENT_ESTABLISHED; 218962306a36Sopenharmony_ci } else { 219062306a36Sopenharmony_ci event.event = RDMA_CM_EVENT_CONNECT_RESPONSE; 219162306a36Sopenharmony_ci } 219262306a36Sopenharmony_ci cma_set_rep_event_data(&event, &ib_event->param.rep_rcvd, 219362306a36Sopenharmony_ci ib_event->private_data); 219462306a36Sopenharmony_ci break; 219562306a36Sopenharmony_ci case IB_CM_RTU_RECEIVED: 219662306a36Sopenharmony_ci case IB_CM_USER_ESTABLISHED: 219762306a36Sopenharmony_ci event.event = RDMA_CM_EVENT_ESTABLISHED; 219862306a36Sopenharmony_ci break; 219962306a36Sopenharmony_ci case IB_CM_DREQ_ERROR: 220062306a36Sopenharmony_ci event.status = -ETIMEDOUT; 220162306a36Sopenharmony_ci fallthrough; 220262306a36Sopenharmony_ci case IB_CM_DREQ_RECEIVED: 220362306a36Sopenharmony_ci case IB_CM_DREP_RECEIVED: 220462306a36Sopenharmony_ci if (!cma_comp_exch(id_priv, RDMA_CM_CONNECT, 220562306a36Sopenharmony_ci RDMA_CM_DISCONNECT)) 220662306a36Sopenharmony_ci goto out; 220762306a36Sopenharmony_ci event.event = RDMA_CM_EVENT_DISCONNECTED; 220862306a36Sopenharmony_ci break; 220962306a36Sopenharmony_ci case IB_CM_TIMEWAIT_EXIT: 221062306a36Sopenharmony_ci event.event = RDMA_CM_EVENT_TIMEWAIT_EXIT; 221162306a36Sopenharmony_ci break; 221262306a36Sopenharmony_ci case IB_CM_MRA_RECEIVED: 221362306a36Sopenharmony_ci /* ignore event */ 221462306a36Sopenharmony_ci goto out; 221562306a36Sopenharmony_ci case IB_CM_REJ_RECEIVED: 221662306a36Sopenharmony_ci pr_debug_ratelimited("RDMA CM: REJECTED: %s\n", rdma_reject_msg(&id_priv->id, 221762306a36Sopenharmony_ci ib_event->param.rej_rcvd.reason)); 221862306a36Sopenharmony_ci cma_modify_qp_err(id_priv); 221962306a36Sopenharmony_ci event.status = ib_event->param.rej_rcvd.reason; 222062306a36Sopenharmony_ci event.event = RDMA_CM_EVENT_REJECTED; 222162306a36Sopenharmony_ci event.param.conn.private_data = ib_event->private_data; 222262306a36Sopenharmony_ci event.param.conn.private_data_len = IB_CM_REJ_PRIVATE_DATA_SIZE; 222362306a36Sopenharmony_ci break; 222462306a36Sopenharmony_ci default: 222562306a36Sopenharmony_ci pr_err("RDMA CMA: unexpected IB CM event: %d\n", 222662306a36Sopenharmony_ci ib_event->event); 222762306a36Sopenharmony_ci goto out; 222862306a36Sopenharmony_ci } 222962306a36Sopenharmony_ci 223062306a36Sopenharmony_ci ret = cma_cm_event_handler(id_priv, &event); 223162306a36Sopenharmony_ci if (ret) { 223262306a36Sopenharmony_ci /* Destroy the CM ID by returning a non-zero value. */ 223362306a36Sopenharmony_ci id_priv->cm_id.ib = NULL; 223462306a36Sopenharmony_ci destroy_id_handler_unlock(id_priv); 223562306a36Sopenharmony_ci return ret; 223662306a36Sopenharmony_ci } 223762306a36Sopenharmony_ciout: 223862306a36Sopenharmony_ci mutex_unlock(&id_priv->handler_mutex); 223962306a36Sopenharmony_ci return 0; 224062306a36Sopenharmony_ci} 224162306a36Sopenharmony_ci 224262306a36Sopenharmony_cistatic struct rdma_id_private * 224362306a36Sopenharmony_cicma_ib_new_conn_id(const struct rdma_cm_id *listen_id, 224462306a36Sopenharmony_ci const struct ib_cm_event *ib_event, 224562306a36Sopenharmony_ci struct net_device *net_dev) 224662306a36Sopenharmony_ci{ 224762306a36Sopenharmony_ci struct rdma_id_private *listen_id_priv; 224862306a36Sopenharmony_ci struct rdma_id_private *id_priv; 224962306a36Sopenharmony_ci struct rdma_cm_id *id; 225062306a36Sopenharmony_ci struct rdma_route *rt; 225162306a36Sopenharmony_ci const sa_family_t ss_family = listen_id->route.addr.src_addr.ss_family; 225262306a36Sopenharmony_ci struct sa_path_rec *path = ib_event->param.req_rcvd.primary_path; 225362306a36Sopenharmony_ci const __be64 service_id = 225462306a36Sopenharmony_ci ib_event->param.req_rcvd.primary_path->service_id; 225562306a36Sopenharmony_ci int ret; 225662306a36Sopenharmony_ci 225762306a36Sopenharmony_ci listen_id_priv = container_of(listen_id, struct rdma_id_private, id); 225862306a36Sopenharmony_ci id_priv = __rdma_create_id(listen_id->route.addr.dev_addr.net, 225962306a36Sopenharmony_ci listen_id->event_handler, listen_id->context, 226062306a36Sopenharmony_ci listen_id->ps, 226162306a36Sopenharmony_ci ib_event->param.req_rcvd.qp_type, 226262306a36Sopenharmony_ci listen_id_priv); 226362306a36Sopenharmony_ci if (IS_ERR(id_priv)) 226462306a36Sopenharmony_ci return NULL; 226562306a36Sopenharmony_ci 226662306a36Sopenharmony_ci id = &id_priv->id; 226762306a36Sopenharmony_ci if (cma_save_net_info((struct sockaddr *)&id->route.addr.src_addr, 226862306a36Sopenharmony_ci (struct sockaddr *)&id->route.addr.dst_addr, 226962306a36Sopenharmony_ci listen_id, ib_event, ss_family, service_id)) 227062306a36Sopenharmony_ci goto err; 227162306a36Sopenharmony_ci 227262306a36Sopenharmony_ci rt = &id->route; 227362306a36Sopenharmony_ci rt->num_pri_alt_paths = ib_event->param.req_rcvd.alternate_path ? 2 : 1; 227462306a36Sopenharmony_ci rt->path_rec = kmalloc_array(rt->num_pri_alt_paths, 227562306a36Sopenharmony_ci sizeof(*rt->path_rec), GFP_KERNEL); 227662306a36Sopenharmony_ci if (!rt->path_rec) 227762306a36Sopenharmony_ci goto err; 227862306a36Sopenharmony_ci 227962306a36Sopenharmony_ci rt->path_rec[0] = *path; 228062306a36Sopenharmony_ci if (rt->num_pri_alt_paths == 2) 228162306a36Sopenharmony_ci rt->path_rec[1] = *ib_event->param.req_rcvd.alternate_path; 228262306a36Sopenharmony_ci 228362306a36Sopenharmony_ci if (net_dev) { 228462306a36Sopenharmony_ci rdma_copy_src_l2_addr(&rt->addr.dev_addr, net_dev); 228562306a36Sopenharmony_ci } else { 228662306a36Sopenharmony_ci if (!cma_protocol_roce(listen_id) && 228762306a36Sopenharmony_ci cma_any_addr(cma_src_addr(id_priv))) { 228862306a36Sopenharmony_ci rt->addr.dev_addr.dev_type = ARPHRD_INFINIBAND; 228962306a36Sopenharmony_ci rdma_addr_set_sgid(&rt->addr.dev_addr, &rt->path_rec[0].sgid); 229062306a36Sopenharmony_ci ib_addr_set_pkey(&rt->addr.dev_addr, be16_to_cpu(rt->path_rec[0].pkey)); 229162306a36Sopenharmony_ci } else if (!cma_any_addr(cma_src_addr(id_priv))) { 229262306a36Sopenharmony_ci ret = cma_translate_addr(cma_src_addr(id_priv), &rt->addr.dev_addr); 229362306a36Sopenharmony_ci if (ret) 229462306a36Sopenharmony_ci goto err; 229562306a36Sopenharmony_ci } 229662306a36Sopenharmony_ci } 229762306a36Sopenharmony_ci rdma_addr_set_dgid(&rt->addr.dev_addr, &rt->path_rec[0].dgid); 229862306a36Sopenharmony_ci 229962306a36Sopenharmony_ci id_priv->state = RDMA_CM_CONNECT; 230062306a36Sopenharmony_ci return id_priv; 230162306a36Sopenharmony_ci 230262306a36Sopenharmony_cierr: 230362306a36Sopenharmony_ci rdma_destroy_id(id); 230462306a36Sopenharmony_ci return NULL; 230562306a36Sopenharmony_ci} 230662306a36Sopenharmony_ci 230762306a36Sopenharmony_cistatic struct rdma_id_private * 230862306a36Sopenharmony_cicma_ib_new_udp_id(const struct rdma_cm_id *listen_id, 230962306a36Sopenharmony_ci const struct ib_cm_event *ib_event, 231062306a36Sopenharmony_ci struct net_device *net_dev) 231162306a36Sopenharmony_ci{ 231262306a36Sopenharmony_ci const struct rdma_id_private *listen_id_priv; 231362306a36Sopenharmony_ci struct rdma_id_private *id_priv; 231462306a36Sopenharmony_ci struct rdma_cm_id *id; 231562306a36Sopenharmony_ci const sa_family_t ss_family = listen_id->route.addr.src_addr.ss_family; 231662306a36Sopenharmony_ci struct net *net = listen_id->route.addr.dev_addr.net; 231762306a36Sopenharmony_ci int ret; 231862306a36Sopenharmony_ci 231962306a36Sopenharmony_ci listen_id_priv = container_of(listen_id, struct rdma_id_private, id); 232062306a36Sopenharmony_ci id_priv = __rdma_create_id(net, listen_id->event_handler, 232162306a36Sopenharmony_ci listen_id->context, listen_id->ps, IB_QPT_UD, 232262306a36Sopenharmony_ci listen_id_priv); 232362306a36Sopenharmony_ci if (IS_ERR(id_priv)) 232462306a36Sopenharmony_ci return NULL; 232562306a36Sopenharmony_ci 232662306a36Sopenharmony_ci id = &id_priv->id; 232762306a36Sopenharmony_ci if (cma_save_net_info((struct sockaddr *)&id->route.addr.src_addr, 232862306a36Sopenharmony_ci (struct sockaddr *)&id->route.addr.dst_addr, 232962306a36Sopenharmony_ci listen_id, ib_event, ss_family, 233062306a36Sopenharmony_ci ib_event->param.sidr_req_rcvd.service_id)) 233162306a36Sopenharmony_ci goto err; 233262306a36Sopenharmony_ci 233362306a36Sopenharmony_ci if (net_dev) { 233462306a36Sopenharmony_ci rdma_copy_src_l2_addr(&id->route.addr.dev_addr, net_dev); 233562306a36Sopenharmony_ci } else { 233662306a36Sopenharmony_ci if (!cma_any_addr(cma_src_addr(id_priv))) { 233762306a36Sopenharmony_ci ret = cma_translate_addr(cma_src_addr(id_priv), 233862306a36Sopenharmony_ci &id->route.addr.dev_addr); 233962306a36Sopenharmony_ci if (ret) 234062306a36Sopenharmony_ci goto err; 234162306a36Sopenharmony_ci } 234262306a36Sopenharmony_ci } 234362306a36Sopenharmony_ci 234462306a36Sopenharmony_ci id_priv->state = RDMA_CM_CONNECT; 234562306a36Sopenharmony_ci return id_priv; 234662306a36Sopenharmony_cierr: 234762306a36Sopenharmony_ci rdma_destroy_id(id); 234862306a36Sopenharmony_ci return NULL; 234962306a36Sopenharmony_ci} 235062306a36Sopenharmony_ci 235162306a36Sopenharmony_cistatic void cma_set_req_event_data(struct rdma_cm_event *event, 235262306a36Sopenharmony_ci const struct ib_cm_req_event_param *req_data, 235362306a36Sopenharmony_ci void *private_data, int offset) 235462306a36Sopenharmony_ci{ 235562306a36Sopenharmony_ci event->param.conn.private_data = private_data + offset; 235662306a36Sopenharmony_ci event->param.conn.private_data_len = IB_CM_REQ_PRIVATE_DATA_SIZE - offset; 235762306a36Sopenharmony_ci event->param.conn.responder_resources = req_data->responder_resources; 235862306a36Sopenharmony_ci event->param.conn.initiator_depth = req_data->initiator_depth; 235962306a36Sopenharmony_ci event->param.conn.flow_control = req_data->flow_control; 236062306a36Sopenharmony_ci event->param.conn.retry_count = req_data->retry_count; 236162306a36Sopenharmony_ci event->param.conn.rnr_retry_count = req_data->rnr_retry_count; 236262306a36Sopenharmony_ci event->param.conn.srq = req_data->srq; 236362306a36Sopenharmony_ci event->param.conn.qp_num = req_data->remote_qpn; 236462306a36Sopenharmony_ci 236562306a36Sopenharmony_ci event->ece.vendor_id = req_data->ece.vendor_id; 236662306a36Sopenharmony_ci event->ece.attr_mod = req_data->ece.attr_mod; 236762306a36Sopenharmony_ci} 236862306a36Sopenharmony_ci 236962306a36Sopenharmony_cistatic int cma_ib_check_req_qp_type(const struct rdma_cm_id *id, 237062306a36Sopenharmony_ci const struct ib_cm_event *ib_event) 237162306a36Sopenharmony_ci{ 237262306a36Sopenharmony_ci return (((ib_event->event == IB_CM_REQ_RECEIVED) && 237362306a36Sopenharmony_ci (ib_event->param.req_rcvd.qp_type == id->qp_type)) || 237462306a36Sopenharmony_ci ((ib_event->event == IB_CM_SIDR_REQ_RECEIVED) && 237562306a36Sopenharmony_ci (id->qp_type == IB_QPT_UD)) || 237662306a36Sopenharmony_ci (!id->qp_type)); 237762306a36Sopenharmony_ci} 237862306a36Sopenharmony_ci 237962306a36Sopenharmony_cistatic int cma_ib_req_handler(struct ib_cm_id *cm_id, 238062306a36Sopenharmony_ci const struct ib_cm_event *ib_event) 238162306a36Sopenharmony_ci{ 238262306a36Sopenharmony_ci struct rdma_id_private *listen_id, *conn_id = NULL; 238362306a36Sopenharmony_ci struct rdma_cm_event event = {}; 238462306a36Sopenharmony_ci struct cma_req_info req = {}; 238562306a36Sopenharmony_ci struct net_device *net_dev; 238662306a36Sopenharmony_ci u8 offset; 238762306a36Sopenharmony_ci int ret; 238862306a36Sopenharmony_ci 238962306a36Sopenharmony_ci listen_id = cma_ib_id_from_event(cm_id, ib_event, &req, &net_dev); 239062306a36Sopenharmony_ci if (IS_ERR(listen_id)) 239162306a36Sopenharmony_ci return PTR_ERR(listen_id); 239262306a36Sopenharmony_ci 239362306a36Sopenharmony_ci trace_cm_req_handler(listen_id, ib_event->event); 239462306a36Sopenharmony_ci if (!cma_ib_check_req_qp_type(&listen_id->id, ib_event)) { 239562306a36Sopenharmony_ci ret = -EINVAL; 239662306a36Sopenharmony_ci goto net_dev_put; 239762306a36Sopenharmony_ci } 239862306a36Sopenharmony_ci 239962306a36Sopenharmony_ci mutex_lock(&listen_id->handler_mutex); 240062306a36Sopenharmony_ci if (READ_ONCE(listen_id->state) != RDMA_CM_LISTEN) { 240162306a36Sopenharmony_ci ret = -ECONNABORTED; 240262306a36Sopenharmony_ci goto err_unlock; 240362306a36Sopenharmony_ci } 240462306a36Sopenharmony_ci 240562306a36Sopenharmony_ci offset = cma_user_data_offset(listen_id); 240662306a36Sopenharmony_ci event.event = RDMA_CM_EVENT_CONNECT_REQUEST; 240762306a36Sopenharmony_ci if (ib_event->event == IB_CM_SIDR_REQ_RECEIVED) { 240862306a36Sopenharmony_ci conn_id = cma_ib_new_udp_id(&listen_id->id, ib_event, net_dev); 240962306a36Sopenharmony_ci event.param.ud.private_data = ib_event->private_data + offset; 241062306a36Sopenharmony_ci event.param.ud.private_data_len = 241162306a36Sopenharmony_ci IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE - offset; 241262306a36Sopenharmony_ci } else { 241362306a36Sopenharmony_ci conn_id = cma_ib_new_conn_id(&listen_id->id, ib_event, net_dev); 241462306a36Sopenharmony_ci cma_set_req_event_data(&event, &ib_event->param.req_rcvd, 241562306a36Sopenharmony_ci ib_event->private_data, offset); 241662306a36Sopenharmony_ci } 241762306a36Sopenharmony_ci if (!conn_id) { 241862306a36Sopenharmony_ci ret = -ENOMEM; 241962306a36Sopenharmony_ci goto err_unlock; 242062306a36Sopenharmony_ci } 242162306a36Sopenharmony_ci 242262306a36Sopenharmony_ci mutex_lock_nested(&conn_id->handler_mutex, SINGLE_DEPTH_NESTING); 242362306a36Sopenharmony_ci ret = cma_ib_acquire_dev(conn_id, listen_id, &req); 242462306a36Sopenharmony_ci if (ret) { 242562306a36Sopenharmony_ci destroy_id_handler_unlock(conn_id); 242662306a36Sopenharmony_ci goto err_unlock; 242762306a36Sopenharmony_ci } 242862306a36Sopenharmony_ci 242962306a36Sopenharmony_ci conn_id->cm_id.ib = cm_id; 243062306a36Sopenharmony_ci cm_id->context = conn_id; 243162306a36Sopenharmony_ci cm_id->cm_handler = cma_ib_handler; 243262306a36Sopenharmony_ci 243362306a36Sopenharmony_ci ret = cma_cm_event_handler(conn_id, &event); 243462306a36Sopenharmony_ci if (ret) { 243562306a36Sopenharmony_ci /* Destroy the CM ID by returning a non-zero value. */ 243662306a36Sopenharmony_ci conn_id->cm_id.ib = NULL; 243762306a36Sopenharmony_ci mutex_unlock(&listen_id->handler_mutex); 243862306a36Sopenharmony_ci destroy_id_handler_unlock(conn_id); 243962306a36Sopenharmony_ci goto net_dev_put; 244062306a36Sopenharmony_ci } 244162306a36Sopenharmony_ci 244262306a36Sopenharmony_ci if (READ_ONCE(conn_id->state) == RDMA_CM_CONNECT && 244362306a36Sopenharmony_ci conn_id->id.qp_type != IB_QPT_UD) { 244462306a36Sopenharmony_ci trace_cm_send_mra(cm_id->context); 244562306a36Sopenharmony_ci ib_send_cm_mra(cm_id, CMA_CM_MRA_SETTING, NULL, 0); 244662306a36Sopenharmony_ci } 244762306a36Sopenharmony_ci mutex_unlock(&conn_id->handler_mutex); 244862306a36Sopenharmony_ci 244962306a36Sopenharmony_cierr_unlock: 245062306a36Sopenharmony_ci mutex_unlock(&listen_id->handler_mutex); 245162306a36Sopenharmony_ci 245262306a36Sopenharmony_cinet_dev_put: 245362306a36Sopenharmony_ci dev_put(net_dev); 245462306a36Sopenharmony_ci 245562306a36Sopenharmony_ci return ret; 245662306a36Sopenharmony_ci} 245762306a36Sopenharmony_ci 245862306a36Sopenharmony_ci__be64 rdma_get_service_id(struct rdma_cm_id *id, struct sockaddr *addr) 245962306a36Sopenharmony_ci{ 246062306a36Sopenharmony_ci if (addr->sa_family == AF_IB) 246162306a36Sopenharmony_ci return ((struct sockaddr_ib *) addr)->sib_sid; 246262306a36Sopenharmony_ci 246362306a36Sopenharmony_ci return cpu_to_be64(((u64)id->ps << 16) + be16_to_cpu(cma_port(addr))); 246462306a36Sopenharmony_ci} 246562306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_get_service_id); 246662306a36Sopenharmony_ci 246762306a36Sopenharmony_civoid rdma_read_gids(struct rdma_cm_id *cm_id, union ib_gid *sgid, 246862306a36Sopenharmony_ci union ib_gid *dgid) 246962306a36Sopenharmony_ci{ 247062306a36Sopenharmony_ci struct rdma_addr *addr = &cm_id->route.addr; 247162306a36Sopenharmony_ci 247262306a36Sopenharmony_ci if (!cm_id->device) { 247362306a36Sopenharmony_ci if (sgid) 247462306a36Sopenharmony_ci memset(sgid, 0, sizeof(*sgid)); 247562306a36Sopenharmony_ci if (dgid) 247662306a36Sopenharmony_ci memset(dgid, 0, sizeof(*dgid)); 247762306a36Sopenharmony_ci return; 247862306a36Sopenharmony_ci } 247962306a36Sopenharmony_ci 248062306a36Sopenharmony_ci if (rdma_protocol_roce(cm_id->device, cm_id->port_num)) { 248162306a36Sopenharmony_ci if (sgid) 248262306a36Sopenharmony_ci rdma_ip2gid((struct sockaddr *)&addr->src_addr, sgid); 248362306a36Sopenharmony_ci if (dgid) 248462306a36Sopenharmony_ci rdma_ip2gid((struct sockaddr *)&addr->dst_addr, dgid); 248562306a36Sopenharmony_ci } else { 248662306a36Sopenharmony_ci if (sgid) 248762306a36Sopenharmony_ci rdma_addr_get_sgid(&addr->dev_addr, sgid); 248862306a36Sopenharmony_ci if (dgid) 248962306a36Sopenharmony_ci rdma_addr_get_dgid(&addr->dev_addr, dgid); 249062306a36Sopenharmony_ci } 249162306a36Sopenharmony_ci} 249262306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_read_gids); 249362306a36Sopenharmony_ci 249462306a36Sopenharmony_cistatic int cma_iw_handler(struct iw_cm_id *iw_id, struct iw_cm_event *iw_event) 249562306a36Sopenharmony_ci{ 249662306a36Sopenharmony_ci struct rdma_id_private *id_priv = iw_id->context; 249762306a36Sopenharmony_ci struct rdma_cm_event event = {}; 249862306a36Sopenharmony_ci int ret = 0; 249962306a36Sopenharmony_ci struct sockaddr *laddr = (struct sockaddr *)&iw_event->local_addr; 250062306a36Sopenharmony_ci struct sockaddr *raddr = (struct sockaddr *)&iw_event->remote_addr; 250162306a36Sopenharmony_ci 250262306a36Sopenharmony_ci mutex_lock(&id_priv->handler_mutex); 250362306a36Sopenharmony_ci if (READ_ONCE(id_priv->state) != RDMA_CM_CONNECT) 250462306a36Sopenharmony_ci goto out; 250562306a36Sopenharmony_ci 250662306a36Sopenharmony_ci switch (iw_event->event) { 250762306a36Sopenharmony_ci case IW_CM_EVENT_CLOSE: 250862306a36Sopenharmony_ci event.event = RDMA_CM_EVENT_DISCONNECTED; 250962306a36Sopenharmony_ci break; 251062306a36Sopenharmony_ci case IW_CM_EVENT_CONNECT_REPLY: 251162306a36Sopenharmony_ci memcpy(cma_src_addr(id_priv), laddr, 251262306a36Sopenharmony_ci rdma_addr_size(laddr)); 251362306a36Sopenharmony_ci memcpy(cma_dst_addr(id_priv), raddr, 251462306a36Sopenharmony_ci rdma_addr_size(raddr)); 251562306a36Sopenharmony_ci switch (iw_event->status) { 251662306a36Sopenharmony_ci case 0: 251762306a36Sopenharmony_ci event.event = RDMA_CM_EVENT_ESTABLISHED; 251862306a36Sopenharmony_ci event.param.conn.initiator_depth = iw_event->ird; 251962306a36Sopenharmony_ci event.param.conn.responder_resources = iw_event->ord; 252062306a36Sopenharmony_ci break; 252162306a36Sopenharmony_ci case -ECONNRESET: 252262306a36Sopenharmony_ci case -ECONNREFUSED: 252362306a36Sopenharmony_ci event.event = RDMA_CM_EVENT_REJECTED; 252462306a36Sopenharmony_ci break; 252562306a36Sopenharmony_ci case -ETIMEDOUT: 252662306a36Sopenharmony_ci event.event = RDMA_CM_EVENT_UNREACHABLE; 252762306a36Sopenharmony_ci break; 252862306a36Sopenharmony_ci default: 252962306a36Sopenharmony_ci event.event = RDMA_CM_EVENT_CONNECT_ERROR; 253062306a36Sopenharmony_ci break; 253162306a36Sopenharmony_ci } 253262306a36Sopenharmony_ci break; 253362306a36Sopenharmony_ci case IW_CM_EVENT_ESTABLISHED: 253462306a36Sopenharmony_ci event.event = RDMA_CM_EVENT_ESTABLISHED; 253562306a36Sopenharmony_ci event.param.conn.initiator_depth = iw_event->ird; 253662306a36Sopenharmony_ci event.param.conn.responder_resources = iw_event->ord; 253762306a36Sopenharmony_ci break; 253862306a36Sopenharmony_ci default: 253962306a36Sopenharmony_ci goto out; 254062306a36Sopenharmony_ci } 254162306a36Sopenharmony_ci 254262306a36Sopenharmony_ci event.status = iw_event->status; 254362306a36Sopenharmony_ci event.param.conn.private_data = iw_event->private_data; 254462306a36Sopenharmony_ci event.param.conn.private_data_len = iw_event->private_data_len; 254562306a36Sopenharmony_ci ret = cma_cm_event_handler(id_priv, &event); 254662306a36Sopenharmony_ci if (ret) { 254762306a36Sopenharmony_ci /* Destroy the CM ID by returning a non-zero value. */ 254862306a36Sopenharmony_ci id_priv->cm_id.iw = NULL; 254962306a36Sopenharmony_ci destroy_id_handler_unlock(id_priv); 255062306a36Sopenharmony_ci return ret; 255162306a36Sopenharmony_ci } 255262306a36Sopenharmony_ci 255362306a36Sopenharmony_ciout: 255462306a36Sopenharmony_ci mutex_unlock(&id_priv->handler_mutex); 255562306a36Sopenharmony_ci return ret; 255662306a36Sopenharmony_ci} 255762306a36Sopenharmony_ci 255862306a36Sopenharmony_cistatic int iw_conn_req_handler(struct iw_cm_id *cm_id, 255962306a36Sopenharmony_ci struct iw_cm_event *iw_event) 256062306a36Sopenharmony_ci{ 256162306a36Sopenharmony_ci struct rdma_id_private *listen_id, *conn_id; 256262306a36Sopenharmony_ci struct rdma_cm_event event = {}; 256362306a36Sopenharmony_ci int ret = -ECONNABORTED; 256462306a36Sopenharmony_ci struct sockaddr *laddr = (struct sockaddr *)&iw_event->local_addr; 256562306a36Sopenharmony_ci struct sockaddr *raddr = (struct sockaddr *)&iw_event->remote_addr; 256662306a36Sopenharmony_ci 256762306a36Sopenharmony_ci event.event = RDMA_CM_EVENT_CONNECT_REQUEST; 256862306a36Sopenharmony_ci event.param.conn.private_data = iw_event->private_data; 256962306a36Sopenharmony_ci event.param.conn.private_data_len = iw_event->private_data_len; 257062306a36Sopenharmony_ci event.param.conn.initiator_depth = iw_event->ird; 257162306a36Sopenharmony_ci event.param.conn.responder_resources = iw_event->ord; 257262306a36Sopenharmony_ci 257362306a36Sopenharmony_ci listen_id = cm_id->context; 257462306a36Sopenharmony_ci 257562306a36Sopenharmony_ci mutex_lock(&listen_id->handler_mutex); 257662306a36Sopenharmony_ci if (READ_ONCE(listen_id->state) != RDMA_CM_LISTEN) 257762306a36Sopenharmony_ci goto out; 257862306a36Sopenharmony_ci 257962306a36Sopenharmony_ci /* Create a new RDMA id for the new IW CM ID */ 258062306a36Sopenharmony_ci conn_id = __rdma_create_id(listen_id->id.route.addr.dev_addr.net, 258162306a36Sopenharmony_ci listen_id->id.event_handler, 258262306a36Sopenharmony_ci listen_id->id.context, RDMA_PS_TCP, 258362306a36Sopenharmony_ci IB_QPT_RC, listen_id); 258462306a36Sopenharmony_ci if (IS_ERR(conn_id)) { 258562306a36Sopenharmony_ci ret = -ENOMEM; 258662306a36Sopenharmony_ci goto out; 258762306a36Sopenharmony_ci } 258862306a36Sopenharmony_ci mutex_lock_nested(&conn_id->handler_mutex, SINGLE_DEPTH_NESTING); 258962306a36Sopenharmony_ci conn_id->state = RDMA_CM_CONNECT; 259062306a36Sopenharmony_ci 259162306a36Sopenharmony_ci ret = rdma_translate_ip(laddr, &conn_id->id.route.addr.dev_addr); 259262306a36Sopenharmony_ci if (ret) { 259362306a36Sopenharmony_ci mutex_unlock(&listen_id->handler_mutex); 259462306a36Sopenharmony_ci destroy_id_handler_unlock(conn_id); 259562306a36Sopenharmony_ci return ret; 259662306a36Sopenharmony_ci } 259762306a36Sopenharmony_ci 259862306a36Sopenharmony_ci ret = cma_iw_acquire_dev(conn_id, listen_id); 259962306a36Sopenharmony_ci if (ret) { 260062306a36Sopenharmony_ci mutex_unlock(&listen_id->handler_mutex); 260162306a36Sopenharmony_ci destroy_id_handler_unlock(conn_id); 260262306a36Sopenharmony_ci return ret; 260362306a36Sopenharmony_ci } 260462306a36Sopenharmony_ci 260562306a36Sopenharmony_ci conn_id->cm_id.iw = cm_id; 260662306a36Sopenharmony_ci cm_id->context = conn_id; 260762306a36Sopenharmony_ci cm_id->cm_handler = cma_iw_handler; 260862306a36Sopenharmony_ci 260962306a36Sopenharmony_ci memcpy(cma_src_addr(conn_id), laddr, rdma_addr_size(laddr)); 261062306a36Sopenharmony_ci memcpy(cma_dst_addr(conn_id), raddr, rdma_addr_size(raddr)); 261162306a36Sopenharmony_ci 261262306a36Sopenharmony_ci ret = cma_cm_event_handler(conn_id, &event); 261362306a36Sopenharmony_ci if (ret) { 261462306a36Sopenharmony_ci /* User wants to destroy the CM ID */ 261562306a36Sopenharmony_ci conn_id->cm_id.iw = NULL; 261662306a36Sopenharmony_ci mutex_unlock(&listen_id->handler_mutex); 261762306a36Sopenharmony_ci destroy_id_handler_unlock(conn_id); 261862306a36Sopenharmony_ci return ret; 261962306a36Sopenharmony_ci } 262062306a36Sopenharmony_ci 262162306a36Sopenharmony_ci mutex_unlock(&conn_id->handler_mutex); 262262306a36Sopenharmony_ci 262362306a36Sopenharmony_ciout: 262462306a36Sopenharmony_ci mutex_unlock(&listen_id->handler_mutex); 262562306a36Sopenharmony_ci return ret; 262662306a36Sopenharmony_ci} 262762306a36Sopenharmony_ci 262862306a36Sopenharmony_cistatic int cma_ib_listen(struct rdma_id_private *id_priv) 262962306a36Sopenharmony_ci{ 263062306a36Sopenharmony_ci struct sockaddr *addr; 263162306a36Sopenharmony_ci struct ib_cm_id *id; 263262306a36Sopenharmony_ci __be64 svc_id; 263362306a36Sopenharmony_ci 263462306a36Sopenharmony_ci addr = cma_src_addr(id_priv); 263562306a36Sopenharmony_ci svc_id = rdma_get_service_id(&id_priv->id, addr); 263662306a36Sopenharmony_ci id = ib_cm_insert_listen(id_priv->id.device, 263762306a36Sopenharmony_ci cma_ib_req_handler, svc_id); 263862306a36Sopenharmony_ci if (IS_ERR(id)) 263962306a36Sopenharmony_ci return PTR_ERR(id); 264062306a36Sopenharmony_ci id_priv->cm_id.ib = id; 264162306a36Sopenharmony_ci 264262306a36Sopenharmony_ci return 0; 264362306a36Sopenharmony_ci} 264462306a36Sopenharmony_ci 264562306a36Sopenharmony_cistatic int cma_iw_listen(struct rdma_id_private *id_priv, int backlog) 264662306a36Sopenharmony_ci{ 264762306a36Sopenharmony_ci int ret; 264862306a36Sopenharmony_ci struct iw_cm_id *id; 264962306a36Sopenharmony_ci 265062306a36Sopenharmony_ci id = iw_create_cm_id(id_priv->id.device, 265162306a36Sopenharmony_ci iw_conn_req_handler, 265262306a36Sopenharmony_ci id_priv); 265362306a36Sopenharmony_ci if (IS_ERR(id)) 265462306a36Sopenharmony_ci return PTR_ERR(id); 265562306a36Sopenharmony_ci 265662306a36Sopenharmony_ci mutex_lock(&id_priv->qp_mutex); 265762306a36Sopenharmony_ci id->tos = id_priv->tos; 265862306a36Sopenharmony_ci id->tos_set = id_priv->tos_set; 265962306a36Sopenharmony_ci mutex_unlock(&id_priv->qp_mutex); 266062306a36Sopenharmony_ci id->afonly = id_priv->afonly; 266162306a36Sopenharmony_ci id_priv->cm_id.iw = id; 266262306a36Sopenharmony_ci 266362306a36Sopenharmony_ci memcpy(&id_priv->cm_id.iw->local_addr, cma_src_addr(id_priv), 266462306a36Sopenharmony_ci rdma_addr_size(cma_src_addr(id_priv))); 266562306a36Sopenharmony_ci 266662306a36Sopenharmony_ci ret = iw_cm_listen(id_priv->cm_id.iw, backlog); 266762306a36Sopenharmony_ci 266862306a36Sopenharmony_ci if (ret) { 266962306a36Sopenharmony_ci iw_destroy_cm_id(id_priv->cm_id.iw); 267062306a36Sopenharmony_ci id_priv->cm_id.iw = NULL; 267162306a36Sopenharmony_ci } 267262306a36Sopenharmony_ci 267362306a36Sopenharmony_ci return ret; 267462306a36Sopenharmony_ci} 267562306a36Sopenharmony_ci 267662306a36Sopenharmony_cistatic int cma_listen_handler(struct rdma_cm_id *id, 267762306a36Sopenharmony_ci struct rdma_cm_event *event) 267862306a36Sopenharmony_ci{ 267962306a36Sopenharmony_ci struct rdma_id_private *id_priv = id->context; 268062306a36Sopenharmony_ci 268162306a36Sopenharmony_ci /* Listening IDs are always destroyed on removal */ 268262306a36Sopenharmony_ci if (event->event == RDMA_CM_EVENT_DEVICE_REMOVAL) 268362306a36Sopenharmony_ci return -1; 268462306a36Sopenharmony_ci 268562306a36Sopenharmony_ci id->context = id_priv->id.context; 268662306a36Sopenharmony_ci id->event_handler = id_priv->id.event_handler; 268762306a36Sopenharmony_ci trace_cm_event_handler(id_priv, event); 268862306a36Sopenharmony_ci return id_priv->id.event_handler(id, event); 268962306a36Sopenharmony_ci} 269062306a36Sopenharmony_ci 269162306a36Sopenharmony_cistatic int cma_listen_on_dev(struct rdma_id_private *id_priv, 269262306a36Sopenharmony_ci struct cma_device *cma_dev, 269362306a36Sopenharmony_ci struct rdma_id_private **to_destroy) 269462306a36Sopenharmony_ci{ 269562306a36Sopenharmony_ci struct rdma_id_private *dev_id_priv; 269662306a36Sopenharmony_ci struct net *net = id_priv->id.route.addr.dev_addr.net; 269762306a36Sopenharmony_ci int ret; 269862306a36Sopenharmony_ci 269962306a36Sopenharmony_ci lockdep_assert_held(&lock); 270062306a36Sopenharmony_ci 270162306a36Sopenharmony_ci *to_destroy = NULL; 270262306a36Sopenharmony_ci if (cma_family(id_priv) == AF_IB && !rdma_cap_ib_cm(cma_dev->device, 1)) 270362306a36Sopenharmony_ci return 0; 270462306a36Sopenharmony_ci 270562306a36Sopenharmony_ci dev_id_priv = 270662306a36Sopenharmony_ci __rdma_create_id(net, cma_listen_handler, id_priv, 270762306a36Sopenharmony_ci id_priv->id.ps, id_priv->id.qp_type, id_priv); 270862306a36Sopenharmony_ci if (IS_ERR(dev_id_priv)) 270962306a36Sopenharmony_ci return PTR_ERR(dev_id_priv); 271062306a36Sopenharmony_ci 271162306a36Sopenharmony_ci dev_id_priv->state = RDMA_CM_ADDR_BOUND; 271262306a36Sopenharmony_ci memcpy(cma_src_addr(dev_id_priv), cma_src_addr(id_priv), 271362306a36Sopenharmony_ci rdma_addr_size(cma_src_addr(id_priv))); 271462306a36Sopenharmony_ci 271562306a36Sopenharmony_ci _cma_attach_to_dev(dev_id_priv, cma_dev); 271662306a36Sopenharmony_ci rdma_restrack_add(&dev_id_priv->res); 271762306a36Sopenharmony_ci cma_id_get(id_priv); 271862306a36Sopenharmony_ci dev_id_priv->internal_id = 1; 271962306a36Sopenharmony_ci dev_id_priv->afonly = id_priv->afonly; 272062306a36Sopenharmony_ci mutex_lock(&id_priv->qp_mutex); 272162306a36Sopenharmony_ci dev_id_priv->tos_set = id_priv->tos_set; 272262306a36Sopenharmony_ci dev_id_priv->tos = id_priv->tos; 272362306a36Sopenharmony_ci mutex_unlock(&id_priv->qp_mutex); 272462306a36Sopenharmony_ci 272562306a36Sopenharmony_ci ret = rdma_listen(&dev_id_priv->id, id_priv->backlog); 272662306a36Sopenharmony_ci if (ret) 272762306a36Sopenharmony_ci goto err_listen; 272862306a36Sopenharmony_ci list_add_tail(&dev_id_priv->listen_item, &id_priv->listen_list); 272962306a36Sopenharmony_ci return 0; 273062306a36Sopenharmony_cierr_listen: 273162306a36Sopenharmony_ci /* Caller must destroy this after releasing lock */ 273262306a36Sopenharmony_ci *to_destroy = dev_id_priv; 273362306a36Sopenharmony_ci dev_warn(&cma_dev->device->dev, "RDMA CMA: %s, error %d\n", __func__, ret); 273462306a36Sopenharmony_ci return ret; 273562306a36Sopenharmony_ci} 273662306a36Sopenharmony_ci 273762306a36Sopenharmony_cistatic int cma_listen_on_all(struct rdma_id_private *id_priv) 273862306a36Sopenharmony_ci{ 273962306a36Sopenharmony_ci struct rdma_id_private *to_destroy; 274062306a36Sopenharmony_ci struct cma_device *cma_dev; 274162306a36Sopenharmony_ci int ret; 274262306a36Sopenharmony_ci 274362306a36Sopenharmony_ci mutex_lock(&lock); 274462306a36Sopenharmony_ci list_add_tail(&id_priv->listen_any_item, &listen_any_list); 274562306a36Sopenharmony_ci list_for_each_entry(cma_dev, &dev_list, list) { 274662306a36Sopenharmony_ci ret = cma_listen_on_dev(id_priv, cma_dev, &to_destroy); 274762306a36Sopenharmony_ci if (ret) { 274862306a36Sopenharmony_ci /* Prevent racing with cma_process_remove() */ 274962306a36Sopenharmony_ci if (to_destroy) 275062306a36Sopenharmony_ci list_del_init(&to_destroy->device_item); 275162306a36Sopenharmony_ci goto err_listen; 275262306a36Sopenharmony_ci } 275362306a36Sopenharmony_ci } 275462306a36Sopenharmony_ci mutex_unlock(&lock); 275562306a36Sopenharmony_ci return 0; 275662306a36Sopenharmony_ci 275762306a36Sopenharmony_cierr_listen: 275862306a36Sopenharmony_ci _cma_cancel_listens(id_priv); 275962306a36Sopenharmony_ci mutex_unlock(&lock); 276062306a36Sopenharmony_ci if (to_destroy) 276162306a36Sopenharmony_ci rdma_destroy_id(&to_destroy->id); 276262306a36Sopenharmony_ci return ret; 276362306a36Sopenharmony_ci} 276462306a36Sopenharmony_ci 276562306a36Sopenharmony_civoid rdma_set_service_type(struct rdma_cm_id *id, int tos) 276662306a36Sopenharmony_ci{ 276762306a36Sopenharmony_ci struct rdma_id_private *id_priv; 276862306a36Sopenharmony_ci 276962306a36Sopenharmony_ci id_priv = container_of(id, struct rdma_id_private, id); 277062306a36Sopenharmony_ci mutex_lock(&id_priv->qp_mutex); 277162306a36Sopenharmony_ci id_priv->tos = (u8) tos; 277262306a36Sopenharmony_ci id_priv->tos_set = true; 277362306a36Sopenharmony_ci mutex_unlock(&id_priv->qp_mutex); 277462306a36Sopenharmony_ci} 277562306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_set_service_type); 277662306a36Sopenharmony_ci 277762306a36Sopenharmony_ci/** 277862306a36Sopenharmony_ci * rdma_set_ack_timeout() - Set the ack timeout of QP associated 277962306a36Sopenharmony_ci * with a connection identifier. 278062306a36Sopenharmony_ci * @id: Communication identifier to associated with service type. 278162306a36Sopenharmony_ci * @timeout: Ack timeout to set a QP, expressed as 4.096 * 2^(timeout) usec. 278262306a36Sopenharmony_ci * 278362306a36Sopenharmony_ci * This function should be called before rdma_connect() on active side, 278462306a36Sopenharmony_ci * and on passive side before rdma_accept(). It is applicable to primary 278562306a36Sopenharmony_ci * path only. The timeout will affect the local side of the QP, it is not 278662306a36Sopenharmony_ci * negotiated with remote side and zero disables the timer. In case it is 278762306a36Sopenharmony_ci * set before rdma_resolve_route, the value will also be used to determine 278862306a36Sopenharmony_ci * PacketLifeTime for RoCE. 278962306a36Sopenharmony_ci * 279062306a36Sopenharmony_ci * Return: 0 for success 279162306a36Sopenharmony_ci */ 279262306a36Sopenharmony_ciint rdma_set_ack_timeout(struct rdma_cm_id *id, u8 timeout) 279362306a36Sopenharmony_ci{ 279462306a36Sopenharmony_ci struct rdma_id_private *id_priv; 279562306a36Sopenharmony_ci 279662306a36Sopenharmony_ci if (id->qp_type != IB_QPT_RC && id->qp_type != IB_QPT_XRC_INI) 279762306a36Sopenharmony_ci return -EINVAL; 279862306a36Sopenharmony_ci 279962306a36Sopenharmony_ci id_priv = container_of(id, struct rdma_id_private, id); 280062306a36Sopenharmony_ci mutex_lock(&id_priv->qp_mutex); 280162306a36Sopenharmony_ci id_priv->timeout = timeout; 280262306a36Sopenharmony_ci id_priv->timeout_set = true; 280362306a36Sopenharmony_ci mutex_unlock(&id_priv->qp_mutex); 280462306a36Sopenharmony_ci 280562306a36Sopenharmony_ci return 0; 280662306a36Sopenharmony_ci} 280762306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_set_ack_timeout); 280862306a36Sopenharmony_ci 280962306a36Sopenharmony_ci/** 281062306a36Sopenharmony_ci * rdma_set_min_rnr_timer() - Set the minimum RNR Retry timer of the 281162306a36Sopenharmony_ci * QP associated with a connection identifier. 281262306a36Sopenharmony_ci * @id: Communication identifier to associated with service type. 281362306a36Sopenharmony_ci * @min_rnr_timer: 5-bit value encoded as Table 45: "Encoding for RNR NAK 281462306a36Sopenharmony_ci * Timer Field" in the IBTA specification. 281562306a36Sopenharmony_ci * 281662306a36Sopenharmony_ci * This function should be called before rdma_connect() on active 281762306a36Sopenharmony_ci * side, and on passive side before rdma_accept(). The timer value 281862306a36Sopenharmony_ci * will be associated with the local QP. When it receives a send it is 281962306a36Sopenharmony_ci * not read to handle, typically if the receive queue is empty, an RNR 282062306a36Sopenharmony_ci * Retry NAK is returned to the requester with the min_rnr_timer 282162306a36Sopenharmony_ci * encoded. The requester will then wait at least the time specified 282262306a36Sopenharmony_ci * in the NAK before retrying. The default is zero, which translates 282362306a36Sopenharmony_ci * to a minimum RNR Timer value of 655 ms. 282462306a36Sopenharmony_ci * 282562306a36Sopenharmony_ci * Return: 0 for success 282662306a36Sopenharmony_ci */ 282762306a36Sopenharmony_ciint rdma_set_min_rnr_timer(struct rdma_cm_id *id, u8 min_rnr_timer) 282862306a36Sopenharmony_ci{ 282962306a36Sopenharmony_ci struct rdma_id_private *id_priv; 283062306a36Sopenharmony_ci 283162306a36Sopenharmony_ci /* It is a five-bit value */ 283262306a36Sopenharmony_ci if (min_rnr_timer & 0xe0) 283362306a36Sopenharmony_ci return -EINVAL; 283462306a36Sopenharmony_ci 283562306a36Sopenharmony_ci if (WARN_ON(id->qp_type != IB_QPT_RC && id->qp_type != IB_QPT_XRC_TGT)) 283662306a36Sopenharmony_ci return -EINVAL; 283762306a36Sopenharmony_ci 283862306a36Sopenharmony_ci id_priv = container_of(id, struct rdma_id_private, id); 283962306a36Sopenharmony_ci mutex_lock(&id_priv->qp_mutex); 284062306a36Sopenharmony_ci id_priv->min_rnr_timer = min_rnr_timer; 284162306a36Sopenharmony_ci id_priv->min_rnr_timer_set = true; 284262306a36Sopenharmony_ci mutex_unlock(&id_priv->qp_mutex); 284362306a36Sopenharmony_ci 284462306a36Sopenharmony_ci return 0; 284562306a36Sopenharmony_ci} 284662306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_set_min_rnr_timer); 284762306a36Sopenharmony_ci 284862306a36Sopenharmony_cistatic int route_set_path_rec_inbound(struct cma_work *work, 284962306a36Sopenharmony_ci struct sa_path_rec *path_rec) 285062306a36Sopenharmony_ci{ 285162306a36Sopenharmony_ci struct rdma_route *route = &work->id->id.route; 285262306a36Sopenharmony_ci 285362306a36Sopenharmony_ci if (!route->path_rec_inbound) { 285462306a36Sopenharmony_ci route->path_rec_inbound = 285562306a36Sopenharmony_ci kzalloc(sizeof(*route->path_rec_inbound), GFP_KERNEL); 285662306a36Sopenharmony_ci if (!route->path_rec_inbound) 285762306a36Sopenharmony_ci return -ENOMEM; 285862306a36Sopenharmony_ci } 285962306a36Sopenharmony_ci 286062306a36Sopenharmony_ci *route->path_rec_inbound = *path_rec; 286162306a36Sopenharmony_ci return 0; 286262306a36Sopenharmony_ci} 286362306a36Sopenharmony_ci 286462306a36Sopenharmony_cistatic int route_set_path_rec_outbound(struct cma_work *work, 286562306a36Sopenharmony_ci struct sa_path_rec *path_rec) 286662306a36Sopenharmony_ci{ 286762306a36Sopenharmony_ci struct rdma_route *route = &work->id->id.route; 286862306a36Sopenharmony_ci 286962306a36Sopenharmony_ci if (!route->path_rec_outbound) { 287062306a36Sopenharmony_ci route->path_rec_outbound = 287162306a36Sopenharmony_ci kzalloc(sizeof(*route->path_rec_outbound), GFP_KERNEL); 287262306a36Sopenharmony_ci if (!route->path_rec_outbound) 287362306a36Sopenharmony_ci return -ENOMEM; 287462306a36Sopenharmony_ci } 287562306a36Sopenharmony_ci 287662306a36Sopenharmony_ci *route->path_rec_outbound = *path_rec; 287762306a36Sopenharmony_ci return 0; 287862306a36Sopenharmony_ci} 287962306a36Sopenharmony_ci 288062306a36Sopenharmony_cistatic void cma_query_handler(int status, struct sa_path_rec *path_rec, 288162306a36Sopenharmony_ci unsigned int num_prs, void *context) 288262306a36Sopenharmony_ci{ 288362306a36Sopenharmony_ci struct cma_work *work = context; 288462306a36Sopenharmony_ci struct rdma_route *route; 288562306a36Sopenharmony_ci int i; 288662306a36Sopenharmony_ci 288762306a36Sopenharmony_ci route = &work->id->id.route; 288862306a36Sopenharmony_ci 288962306a36Sopenharmony_ci if (status) 289062306a36Sopenharmony_ci goto fail; 289162306a36Sopenharmony_ci 289262306a36Sopenharmony_ci for (i = 0; i < num_prs; i++) { 289362306a36Sopenharmony_ci if (!path_rec[i].flags || (path_rec[i].flags & IB_PATH_GMP)) 289462306a36Sopenharmony_ci *route->path_rec = path_rec[i]; 289562306a36Sopenharmony_ci else if (path_rec[i].flags & IB_PATH_INBOUND) 289662306a36Sopenharmony_ci status = route_set_path_rec_inbound(work, &path_rec[i]); 289762306a36Sopenharmony_ci else if (path_rec[i].flags & IB_PATH_OUTBOUND) 289862306a36Sopenharmony_ci status = route_set_path_rec_outbound(work, 289962306a36Sopenharmony_ci &path_rec[i]); 290062306a36Sopenharmony_ci else 290162306a36Sopenharmony_ci status = -EINVAL; 290262306a36Sopenharmony_ci 290362306a36Sopenharmony_ci if (status) 290462306a36Sopenharmony_ci goto fail; 290562306a36Sopenharmony_ci } 290662306a36Sopenharmony_ci 290762306a36Sopenharmony_ci route->num_pri_alt_paths = 1; 290862306a36Sopenharmony_ci queue_work(cma_wq, &work->work); 290962306a36Sopenharmony_ci return; 291062306a36Sopenharmony_ci 291162306a36Sopenharmony_cifail: 291262306a36Sopenharmony_ci work->old_state = RDMA_CM_ROUTE_QUERY; 291362306a36Sopenharmony_ci work->new_state = RDMA_CM_ADDR_RESOLVED; 291462306a36Sopenharmony_ci work->event.event = RDMA_CM_EVENT_ROUTE_ERROR; 291562306a36Sopenharmony_ci work->event.status = status; 291662306a36Sopenharmony_ci pr_debug_ratelimited("RDMA CM: ROUTE_ERROR: failed to query path. status %d\n", 291762306a36Sopenharmony_ci status); 291862306a36Sopenharmony_ci queue_work(cma_wq, &work->work); 291962306a36Sopenharmony_ci} 292062306a36Sopenharmony_ci 292162306a36Sopenharmony_cistatic int cma_query_ib_route(struct rdma_id_private *id_priv, 292262306a36Sopenharmony_ci unsigned long timeout_ms, struct cma_work *work) 292362306a36Sopenharmony_ci{ 292462306a36Sopenharmony_ci struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 292562306a36Sopenharmony_ci struct sa_path_rec path_rec; 292662306a36Sopenharmony_ci ib_sa_comp_mask comp_mask; 292762306a36Sopenharmony_ci struct sockaddr_in6 *sin6; 292862306a36Sopenharmony_ci struct sockaddr_ib *sib; 292962306a36Sopenharmony_ci 293062306a36Sopenharmony_ci memset(&path_rec, 0, sizeof path_rec); 293162306a36Sopenharmony_ci 293262306a36Sopenharmony_ci if (rdma_cap_opa_ah(id_priv->id.device, id_priv->id.port_num)) 293362306a36Sopenharmony_ci path_rec.rec_type = SA_PATH_REC_TYPE_OPA; 293462306a36Sopenharmony_ci else 293562306a36Sopenharmony_ci path_rec.rec_type = SA_PATH_REC_TYPE_IB; 293662306a36Sopenharmony_ci rdma_addr_get_sgid(dev_addr, &path_rec.sgid); 293762306a36Sopenharmony_ci rdma_addr_get_dgid(dev_addr, &path_rec.dgid); 293862306a36Sopenharmony_ci path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr)); 293962306a36Sopenharmony_ci path_rec.numb_path = 1; 294062306a36Sopenharmony_ci path_rec.reversible = 1; 294162306a36Sopenharmony_ci path_rec.service_id = rdma_get_service_id(&id_priv->id, 294262306a36Sopenharmony_ci cma_dst_addr(id_priv)); 294362306a36Sopenharmony_ci 294462306a36Sopenharmony_ci comp_mask = IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID | 294562306a36Sopenharmony_ci IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH | 294662306a36Sopenharmony_ci IB_SA_PATH_REC_REVERSIBLE | IB_SA_PATH_REC_SERVICE_ID; 294762306a36Sopenharmony_ci 294862306a36Sopenharmony_ci switch (cma_family(id_priv)) { 294962306a36Sopenharmony_ci case AF_INET: 295062306a36Sopenharmony_ci path_rec.qos_class = cpu_to_be16((u16) id_priv->tos); 295162306a36Sopenharmony_ci comp_mask |= IB_SA_PATH_REC_QOS_CLASS; 295262306a36Sopenharmony_ci break; 295362306a36Sopenharmony_ci case AF_INET6: 295462306a36Sopenharmony_ci sin6 = (struct sockaddr_in6 *) cma_src_addr(id_priv); 295562306a36Sopenharmony_ci path_rec.traffic_class = (u8) (be32_to_cpu(sin6->sin6_flowinfo) >> 20); 295662306a36Sopenharmony_ci comp_mask |= IB_SA_PATH_REC_TRAFFIC_CLASS; 295762306a36Sopenharmony_ci break; 295862306a36Sopenharmony_ci case AF_IB: 295962306a36Sopenharmony_ci sib = (struct sockaddr_ib *) cma_src_addr(id_priv); 296062306a36Sopenharmony_ci path_rec.traffic_class = (u8) (be32_to_cpu(sib->sib_flowinfo) >> 20); 296162306a36Sopenharmony_ci comp_mask |= IB_SA_PATH_REC_TRAFFIC_CLASS; 296262306a36Sopenharmony_ci break; 296362306a36Sopenharmony_ci } 296462306a36Sopenharmony_ci 296562306a36Sopenharmony_ci id_priv->query_id = ib_sa_path_rec_get(&sa_client, id_priv->id.device, 296662306a36Sopenharmony_ci id_priv->id.port_num, &path_rec, 296762306a36Sopenharmony_ci comp_mask, timeout_ms, 296862306a36Sopenharmony_ci GFP_KERNEL, cma_query_handler, 296962306a36Sopenharmony_ci work, &id_priv->query); 297062306a36Sopenharmony_ci 297162306a36Sopenharmony_ci return (id_priv->query_id < 0) ? id_priv->query_id : 0; 297262306a36Sopenharmony_ci} 297362306a36Sopenharmony_ci 297462306a36Sopenharmony_cistatic void cma_iboe_join_work_handler(struct work_struct *work) 297562306a36Sopenharmony_ci{ 297662306a36Sopenharmony_ci struct cma_multicast *mc = 297762306a36Sopenharmony_ci container_of(work, struct cma_multicast, iboe_join.work); 297862306a36Sopenharmony_ci struct rdma_cm_event *event = &mc->iboe_join.event; 297962306a36Sopenharmony_ci struct rdma_id_private *id_priv = mc->id_priv; 298062306a36Sopenharmony_ci int ret; 298162306a36Sopenharmony_ci 298262306a36Sopenharmony_ci mutex_lock(&id_priv->handler_mutex); 298362306a36Sopenharmony_ci if (READ_ONCE(id_priv->state) == RDMA_CM_DESTROYING || 298462306a36Sopenharmony_ci READ_ONCE(id_priv->state) == RDMA_CM_DEVICE_REMOVAL) 298562306a36Sopenharmony_ci goto out_unlock; 298662306a36Sopenharmony_ci 298762306a36Sopenharmony_ci ret = cma_cm_event_handler(id_priv, event); 298862306a36Sopenharmony_ci WARN_ON(ret); 298962306a36Sopenharmony_ci 299062306a36Sopenharmony_ciout_unlock: 299162306a36Sopenharmony_ci mutex_unlock(&id_priv->handler_mutex); 299262306a36Sopenharmony_ci if (event->event == RDMA_CM_EVENT_MULTICAST_JOIN) 299362306a36Sopenharmony_ci rdma_destroy_ah_attr(&event->param.ud.ah_attr); 299462306a36Sopenharmony_ci} 299562306a36Sopenharmony_ci 299662306a36Sopenharmony_cistatic void cma_work_handler(struct work_struct *_work) 299762306a36Sopenharmony_ci{ 299862306a36Sopenharmony_ci struct cma_work *work = container_of(_work, struct cma_work, work); 299962306a36Sopenharmony_ci struct rdma_id_private *id_priv = work->id; 300062306a36Sopenharmony_ci 300162306a36Sopenharmony_ci mutex_lock(&id_priv->handler_mutex); 300262306a36Sopenharmony_ci if (READ_ONCE(id_priv->state) == RDMA_CM_DESTROYING || 300362306a36Sopenharmony_ci READ_ONCE(id_priv->state) == RDMA_CM_DEVICE_REMOVAL) 300462306a36Sopenharmony_ci goto out_unlock; 300562306a36Sopenharmony_ci if (work->old_state != 0 || work->new_state != 0) { 300662306a36Sopenharmony_ci if (!cma_comp_exch(id_priv, work->old_state, work->new_state)) 300762306a36Sopenharmony_ci goto out_unlock; 300862306a36Sopenharmony_ci } 300962306a36Sopenharmony_ci 301062306a36Sopenharmony_ci if (cma_cm_event_handler(id_priv, &work->event)) { 301162306a36Sopenharmony_ci cma_id_put(id_priv); 301262306a36Sopenharmony_ci destroy_id_handler_unlock(id_priv); 301362306a36Sopenharmony_ci goto out_free; 301462306a36Sopenharmony_ci } 301562306a36Sopenharmony_ci 301662306a36Sopenharmony_ciout_unlock: 301762306a36Sopenharmony_ci mutex_unlock(&id_priv->handler_mutex); 301862306a36Sopenharmony_ci cma_id_put(id_priv); 301962306a36Sopenharmony_ciout_free: 302062306a36Sopenharmony_ci if (work->event.event == RDMA_CM_EVENT_MULTICAST_JOIN) 302162306a36Sopenharmony_ci rdma_destroy_ah_attr(&work->event.param.ud.ah_attr); 302262306a36Sopenharmony_ci kfree(work); 302362306a36Sopenharmony_ci} 302462306a36Sopenharmony_ci 302562306a36Sopenharmony_cistatic void cma_init_resolve_route_work(struct cma_work *work, 302662306a36Sopenharmony_ci struct rdma_id_private *id_priv) 302762306a36Sopenharmony_ci{ 302862306a36Sopenharmony_ci work->id = id_priv; 302962306a36Sopenharmony_ci INIT_WORK(&work->work, cma_work_handler); 303062306a36Sopenharmony_ci work->old_state = RDMA_CM_ROUTE_QUERY; 303162306a36Sopenharmony_ci work->new_state = RDMA_CM_ROUTE_RESOLVED; 303262306a36Sopenharmony_ci work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED; 303362306a36Sopenharmony_ci} 303462306a36Sopenharmony_ci 303562306a36Sopenharmony_cistatic void enqueue_resolve_addr_work(struct cma_work *work, 303662306a36Sopenharmony_ci struct rdma_id_private *id_priv) 303762306a36Sopenharmony_ci{ 303862306a36Sopenharmony_ci /* Balances with cma_id_put() in cma_work_handler */ 303962306a36Sopenharmony_ci cma_id_get(id_priv); 304062306a36Sopenharmony_ci 304162306a36Sopenharmony_ci work->id = id_priv; 304262306a36Sopenharmony_ci INIT_WORK(&work->work, cma_work_handler); 304362306a36Sopenharmony_ci work->old_state = RDMA_CM_ADDR_QUERY; 304462306a36Sopenharmony_ci work->new_state = RDMA_CM_ADDR_RESOLVED; 304562306a36Sopenharmony_ci work->event.event = RDMA_CM_EVENT_ADDR_RESOLVED; 304662306a36Sopenharmony_ci 304762306a36Sopenharmony_ci queue_work(cma_wq, &work->work); 304862306a36Sopenharmony_ci} 304962306a36Sopenharmony_ci 305062306a36Sopenharmony_cistatic int cma_resolve_ib_route(struct rdma_id_private *id_priv, 305162306a36Sopenharmony_ci unsigned long timeout_ms) 305262306a36Sopenharmony_ci{ 305362306a36Sopenharmony_ci struct rdma_route *route = &id_priv->id.route; 305462306a36Sopenharmony_ci struct cma_work *work; 305562306a36Sopenharmony_ci int ret; 305662306a36Sopenharmony_ci 305762306a36Sopenharmony_ci work = kzalloc(sizeof *work, GFP_KERNEL); 305862306a36Sopenharmony_ci if (!work) 305962306a36Sopenharmony_ci return -ENOMEM; 306062306a36Sopenharmony_ci 306162306a36Sopenharmony_ci cma_init_resolve_route_work(work, id_priv); 306262306a36Sopenharmony_ci 306362306a36Sopenharmony_ci if (!route->path_rec) 306462306a36Sopenharmony_ci route->path_rec = kmalloc(sizeof *route->path_rec, GFP_KERNEL); 306562306a36Sopenharmony_ci if (!route->path_rec) { 306662306a36Sopenharmony_ci ret = -ENOMEM; 306762306a36Sopenharmony_ci goto err1; 306862306a36Sopenharmony_ci } 306962306a36Sopenharmony_ci 307062306a36Sopenharmony_ci ret = cma_query_ib_route(id_priv, timeout_ms, work); 307162306a36Sopenharmony_ci if (ret) 307262306a36Sopenharmony_ci goto err2; 307362306a36Sopenharmony_ci 307462306a36Sopenharmony_ci return 0; 307562306a36Sopenharmony_cierr2: 307662306a36Sopenharmony_ci kfree(route->path_rec); 307762306a36Sopenharmony_ci route->path_rec = NULL; 307862306a36Sopenharmony_cierr1: 307962306a36Sopenharmony_ci kfree(work); 308062306a36Sopenharmony_ci return ret; 308162306a36Sopenharmony_ci} 308262306a36Sopenharmony_ci 308362306a36Sopenharmony_cistatic enum ib_gid_type cma_route_gid_type(enum rdma_network_type network_type, 308462306a36Sopenharmony_ci unsigned long supported_gids, 308562306a36Sopenharmony_ci enum ib_gid_type default_gid) 308662306a36Sopenharmony_ci{ 308762306a36Sopenharmony_ci if ((network_type == RDMA_NETWORK_IPV4 || 308862306a36Sopenharmony_ci network_type == RDMA_NETWORK_IPV6) && 308962306a36Sopenharmony_ci test_bit(IB_GID_TYPE_ROCE_UDP_ENCAP, &supported_gids)) 309062306a36Sopenharmony_ci return IB_GID_TYPE_ROCE_UDP_ENCAP; 309162306a36Sopenharmony_ci 309262306a36Sopenharmony_ci return default_gid; 309362306a36Sopenharmony_ci} 309462306a36Sopenharmony_ci 309562306a36Sopenharmony_ci/* 309662306a36Sopenharmony_ci * cma_iboe_set_path_rec_l2_fields() is helper function which sets 309762306a36Sopenharmony_ci * path record type based on GID type. 309862306a36Sopenharmony_ci * It also sets up other L2 fields which includes destination mac address 309962306a36Sopenharmony_ci * netdev ifindex, of the path record. 310062306a36Sopenharmony_ci * It returns the netdev of the bound interface for this path record entry. 310162306a36Sopenharmony_ci */ 310262306a36Sopenharmony_cistatic struct net_device * 310362306a36Sopenharmony_cicma_iboe_set_path_rec_l2_fields(struct rdma_id_private *id_priv) 310462306a36Sopenharmony_ci{ 310562306a36Sopenharmony_ci struct rdma_route *route = &id_priv->id.route; 310662306a36Sopenharmony_ci enum ib_gid_type gid_type = IB_GID_TYPE_ROCE; 310762306a36Sopenharmony_ci struct rdma_addr *addr = &route->addr; 310862306a36Sopenharmony_ci unsigned long supported_gids; 310962306a36Sopenharmony_ci struct net_device *ndev; 311062306a36Sopenharmony_ci 311162306a36Sopenharmony_ci if (!addr->dev_addr.bound_dev_if) 311262306a36Sopenharmony_ci return NULL; 311362306a36Sopenharmony_ci 311462306a36Sopenharmony_ci ndev = dev_get_by_index(addr->dev_addr.net, 311562306a36Sopenharmony_ci addr->dev_addr.bound_dev_if); 311662306a36Sopenharmony_ci if (!ndev) 311762306a36Sopenharmony_ci return NULL; 311862306a36Sopenharmony_ci 311962306a36Sopenharmony_ci supported_gids = roce_gid_type_mask_support(id_priv->id.device, 312062306a36Sopenharmony_ci id_priv->id.port_num); 312162306a36Sopenharmony_ci gid_type = cma_route_gid_type(addr->dev_addr.network, 312262306a36Sopenharmony_ci supported_gids, 312362306a36Sopenharmony_ci id_priv->gid_type); 312462306a36Sopenharmony_ci /* Use the hint from IP Stack to select GID Type */ 312562306a36Sopenharmony_ci if (gid_type < ib_network_to_gid_type(addr->dev_addr.network)) 312662306a36Sopenharmony_ci gid_type = ib_network_to_gid_type(addr->dev_addr.network); 312762306a36Sopenharmony_ci route->path_rec->rec_type = sa_conv_gid_to_pathrec_type(gid_type); 312862306a36Sopenharmony_ci 312962306a36Sopenharmony_ci route->path_rec->roce.route_resolved = true; 313062306a36Sopenharmony_ci sa_path_set_dmac(route->path_rec, addr->dev_addr.dst_dev_addr); 313162306a36Sopenharmony_ci return ndev; 313262306a36Sopenharmony_ci} 313362306a36Sopenharmony_ci 313462306a36Sopenharmony_ciint rdma_set_ib_path(struct rdma_cm_id *id, 313562306a36Sopenharmony_ci struct sa_path_rec *path_rec) 313662306a36Sopenharmony_ci{ 313762306a36Sopenharmony_ci struct rdma_id_private *id_priv; 313862306a36Sopenharmony_ci struct net_device *ndev; 313962306a36Sopenharmony_ci int ret; 314062306a36Sopenharmony_ci 314162306a36Sopenharmony_ci id_priv = container_of(id, struct rdma_id_private, id); 314262306a36Sopenharmony_ci if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED, 314362306a36Sopenharmony_ci RDMA_CM_ROUTE_RESOLVED)) 314462306a36Sopenharmony_ci return -EINVAL; 314562306a36Sopenharmony_ci 314662306a36Sopenharmony_ci id->route.path_rec = kmemdup(path_rec, sizeof(*path_rec), 314762306a36Sopenharmony_ci GFP_KERNEL); 314862306a36Sopenharmony_ci if (!id->route.path_rec) { 314962306a36Sopenharmony_ci ret = -ENOMEM; 315062306a36Sopenharmony_ci goto err; 315162306a36Sopenharmony_ci } 315262306a36Sopenharmony_ci 315362306a36Sopenharmony_ci if (rdma_protocol_roce(id->device, id->port_num)) { 315462306a36Sopenharmony_ci ndev = cma_iboe_set_path_rec_l2_fields(id_priv); 315562306a36Sopenharmony_ci if (!ndev) { 315662306a36Sopenharmony_ci ret = -ENODEV; 315762306a36Sopenharmony_ci goto err_free; 315862306a36Sopenharmony_ci } 315962306a36Sopenharmony_ci dev_put(ndev); 316062306a36Sopenharmony_ci } 316162306a36Sopenharmony_ci 316262306a36Sopenharmony_ci id->route.num_pri_alt_paths = 1; 316362306a36Sopenharmony_ci return 0; 316462306a36Sopenharmony_ci 316562306a36Sopenharmony_cierr_free: 316662306a36Sopenharmony_ci kfree(id->route.path_rec); 316762306a36Sopenharmony_ci id->route.path_rec = NULL; 316862306a36Sopenharmony_cierr: 316962306a36Sopenharmony_ci cma_comp_exch(id_priv, RDMA_CM_ROUTE_RESOLVED, RDMA_CM_ADDR_RESOLVED); 317062306a36Sopenharmony_ci return ret; 317162306a36Sopenharmony_ci} 317262306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_set_ib_path); 317362306a36Sopenharmony_ci 317462306a36Sopenharmony_cistatic int cma_resolve_iw_route(struct rdma_id_private *id_priv) 317562306a36Sopenharmony_ci{ 317662306a36Sopenharmony_ci struct cma_work *work; 317762306a36Sopenharmony_ci 317862306a36Sopenharmony_ci work = kzalloc(sizeof *work, GFP_KERNEL); 317962306a36Sopenharmony_ci if (!work) 318062306a36Sopenharmony_ci return -ENOMEM; 318162306a36Sopenharmony_ci 318262306a36Sopenharmony_ci cma_init_resolve_route_work(work, id_priv); 318362306a36Sopenharmony_ci queue_work(cma_wq, &work->work); 318462306a36Sopenharmony_ci return 0; 318562306a36Sopenharmony_ci} 318662306a36Sopenharmony_ci 318762306a36Sopenharmony_cistatic int get_vlan_ndev_tc(struct net_device *vlan_ndev, int prio) 318862306a36Sopenharmony_ci{ 318962306a36Sopenharmony_ci struct net_device *dev; 319062306a36Sopenharmony_ci 319162306a36Sopenharmony_ci dev = vlan_dev_real_dev(vlan_ndev); 319262306a36Sopenharmony_ci if (dev->num_tc) 319362306a36Sopenharmony_ci return netdev_get_prio_tc_map(dev, prio); 319462306a36Sopenharmony_ci 319562306a36Sopenharmony_ci return (vlan_dev_get_egress_qos_mask(vlan_ndev, prio) & 319662306a36Sopenharmony_ci VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; 319762306a36Sopenharmony_ci} 319862306a36Sopenharmony_ci 319962306a36Sopenharmony_cistruct iboe_prio_tc_map { 320062306a36Sopenharmony_ci int input_prio; 320162306a36Sopenharmony_ci int output_tc; 320262306a36Sopenharmony_ci bool found; 320362306a36Sopenharmony_ci}; 320462306a36Sopenharmony_ci 320562306a36Sopenharmony_cistatic int get_lower_vlan_dev_tc(struct net_device *dev, 320662306a36Sopenharmony_ci struct netdev_nested_priv *priv) 320762306a36Sopenharmony_ci{ 320862306a36Sopenharmony_ci struct iboe_prio_tc_map *map = (struct iboe_prio_tc_map *)priv->data; 320962306a36Sopenharmony_ci 321062306a36Sopenharmony_ci if (is_vlan_dev(dev)) 321162306a36Sopenharmony_ci map->output_tc = get_vlan_ndev_tc(dev, map->input_prio); 321262306a36Sopenharmony_ci else if (dev->num_tc) 321362306a36Sopenharmony_ci map->output_tc = netdev_get_prio_tc_map(dev, map->input_prio); 321462306a36Sopenharmony_ci else 321562306a36Sopenharmony_ci map->output_tc = 0; 321662306a36Sopenharmony_ci /* We are interested only in first level VLAN device, so always 321762306a36Sopenharmony_ci * return 1 to stop iterating over next level devices. 321862306a36Sopenharmony_ci */ 321962306a36Sopenharmony_ci map->found = true; 322062306a36Sopenharmony_ci return 1; 322162306a36Sopenharmony_ci} 322262306a36Sopenharmony_ci 322362306a36Sopenharmony_cistatic int iboe_tos_to_sl(struct net_device *ndev, int tos) 322462306a36Sopenharmony_ci{ 322562306a36Sopenharmony_ci struct iboe_prio_tc_map prio_tc_map = {}; 322662306a36Sopenharmony_ci int prio = rt_tos2priority(tos); 322762306a36Sopenharmony_ci struct netdev_nested_priv priv; 322862306a36Sopenharmony_ci 322962306a36Sopenharmony_ci /* If VLAN device, get it directly from the VLAN netdev */ 323062306a36Sopenharmony_ci if (is_vlan_dev(ndev)) 323162306a36Sopenharmony_ci return get_vlan_ndev_tc(ndev, prio); 323262306a36Sopenharmony_ci 323362306a36Sopenharmony_ci prio_tc_map.input_prio = prio; 323462306a36Sopenharmony_ci priv.data = (void *)&prio_tc_map; 323562306a36Sopenharmony_ci rcu_read_lock(); 323662306a36Sopenharmony_ci netdev_walk_all_lower_dev_rcu(ndev, 323762306a36Sopenharmony_ci get_lower_vlan_dev_tc, 323862306a36Sopenharmony_ci &priv); 323962306a36Sopenharmony_ci rcu_read_unlock(); 324062306a36Sopenharmony_ci /* If map is found from lower device, use it; Otherwise 324162306a36Sopenharmony_ci * continue with the current netdevice to get priority to tc map. 324262306a36Sopenharmony_ci */ 324362306a36Sopenharmony_ci if (prio_tc_map.found) 324462306a36Sopenharmony_ci return prio_tc_map.output_tc; 324562306a36Sopenharmony_ci else if (ndev->num_tc) 324662306a36Sopenharmony_ci return netdev_get_prio_tc_map(ndev, prio); 324762306a36Sopenharmony_ci else 324862306a36Sopenharmony_ci return 0; 324962306a36Sopenharmony_ci} 325062306a36Sopenharmony_ci 325162306a36Sopenharmony_cistatic __be32 cma_get_roce_udp_flow_label(struct rdma_id_private *id_priv) 325262306a36Sopenharmony_ci{ 325362306a36Sopenharmony_ci struct sockaddr_in6 *addr6; 325462306a36Sopenharmony_ci u16 dport, sport; 325562306a36Sopenharmony_ci u32 hash, fl; 325662306a36Sopenharmony_ci 325762306a36Sopenharmony_ci addr6 = (struct sockaddr_in6 *)cma_src_addr(id_priv); 325862306a36Sopenharmony_ci fl = be32_to_cpu(addr6->sin6_flowinfo) & IB_GRH_FLOWLABEL_MASK; 325962306a36Sopenharmony_ci if ((cma_family(id_priv) != AF_INET6) || !fl) { 326062306a36Sopenharmony_ci dport = be16_to_cpu(cma_port(cma_dst_addr(id_priv))); 326162306a36Sopenharmony_ci sport = be16_to_cpu(cma_port(cma_src_addr(id_priv))); 326262306a36Sopenharmony_ci hash = (u32)sport * 31 + dport; 326362306a36Sopenharmony_ci fl = hash & IB_GRH_FLOWLABEL_MASK; 326462306a36Sopenharmony_ci } 326562306a36Sopenharmony_ci 326662306a36Sopenharmony_ci return cpu_to_be32(fl); 326762306a36Sopenharmony_ci} 326862306a36Sopenharmony_ci 326962306a36Sopenharmony_cistatic int cma_resolve_iboe_route(struct rdma_id_private *id_priv) 327062306a36Sopenharmony_ci{ 327162306a36Sopenharmony_ci struct rdma_route *route = &id_priv->id.route; 327262306a36Sopenharmony_ci struct rdma_addr *addr = &route->addr; 327362306a36Sopenharmony_ci struct cma_work *work; 327462306a36Sopenharmony_ci int ret; 327562306a36Sopenharmony_ci struct net_device *ndev; 327662306a36Sopenharmony_ci 327762306a36Sopenharmony_ci u8 default_roce_tos = id_priv->cma_dev->default_roce_tos[id_priv->id.port_num - 327862306a36Sopenharmony_ci rdma_start_port(id_priv->cma_dev->device)]; 327962306a36Sopenharmony_ci u8 tos; 328062306a36Sopenharmony_ci 328162306a36Sopenharmony_ci mutex_lock(&id_priv->qp_mutex); 328262306a36Sopenharmony_ci tos = id_priv->tos_set ? id_priv->tos : default_roce_tos; 328362306a36Sopenharmony_ci mutex_unlock(&id_priv->qp_mutex); 328462306a36Sopenharmony_ci 328562306a36Sopenharmony_ci work = kzalloc(sizeof *work, GFP_KERNEL); 328662306a36Sopenharmony_ci if (!work) 328762306a36Sopenharmony_ci return -ENOMEM; 328862306a36Sopenharmony_ci 328962306a36Sopenharmony_ci route->path_rec = kzalloc(sizeof *route->path_rec, GFP_KERNEL); 329062306a36Sopenharmony_ci if (!route->path_rec) { 329162306a36Sopenharmony_ci ret = -ENOMEM; 329262306a36Sopenharmony_ci goto err1; 329362306a36Sopenharmony_ci } 329462306a36Sopenharmony_ci 329562306a36Sopenharmony_ci route->num_pri_alt_paths = 1; 329662306a36Sopenharmony_ci 329762306a36Sopenharmony_ci ndev = cma_iboe_set_path_rec_l2_fields(id_priv); 329862306a36Sopenharmony_ci if (!ndev) { 329962306a36Sopenharmony_ci ret = -ENODEV; 330062306a36Sopenharmony_ci goto err2; 330162306a36Sopenharmony_ci } 330262306a36Sopenharmony_ci 330362306a36Sopenharmony_ci rdma_ip2gid((struct sockaddr *)&id_priv->id.route.addr.src_addr, 330462306a36Sopenharmony_ci &route->path_rec->sgid); 330562306a36Sopenharmony_ci rdma_ip2gid((struct sockaddr *)&id_priv->id.route.addr.dst_addr, 330662306a36Sopenharmony_ci &route->path_rec->dgid); 330762306a36Sopenharmony_ci 330862306a36Sopenharmony_ci if (((struct sockaddr *)&id_priv->id.route.addr.dst_addr)->sa_family != AF_IB) 330962306a36Sopenharmony_ci /* TODO: get the hoplimit from the inet/inet6 device */ 331062306a36Sopenharmony_ci route->path_rec->hop_limit = addr->dev_addr.hoplimit; 331162306a36Sopenharmony_ci else 331262306a36Sopenharmony_ci route->path_rec->hop_limit = 1; 331362306a36Sopenharmony_ci route->path_rec->reversible = 1; 331462306a36Sopenharmony_ci route->path_rec->pkey = cpu_to_be16(0xffff); 331562306a36Sopenharmony_ci route->path_rec->mtu_selector = IB_SA_EQ; 331662306a36Sopenharmony_ci route->path_rec->sl = iboe_tos_to_sl(ndev, tos); 331762306a36Sopenharmony_ci route->path_rec->traffic_class = tos; 331862306a36Sopenharmony_ci route->path_rec->mtu = iboe_get_mtu(ndev->mtu); 331962306a36Sopenharmony_ci route->path_rec->rate_selector = IB_SA_EQ; 332062306a36Sopenharmony_ci route->path_rec->rate = IB_RATE_PORT_CURRENT; 332162306a36Sopenharmony_ci dev_put(ndev); 332262306a36Sopenharmony_ci route->path_rec->packet_life_time_selector = IB_SA_EQ; 332362306a36Sopenharmony_ci /* In case ACK timeout is set, use this value to calculate 332462306a36Sopenharmony_ci * PacketLifeTime. As per IBTA 12.7.34, 332562306a36Sopenharmony_ci * local ACK timeout = (2 * PacketLifeTime + Local CA’s ACK delay). 332662306a36Sopenharmony_ci * Assuming a negligible local ACK delay, we can use 332762306a36Sopenharmony_ci * PacketLifeTime = local ACK timeout/2 332862306a36Sopenharmony_ci * as a reasonable approximation for RoCE networks. 332962306a36Sopenharmony_ci */ 333062306a36Sopenharmony_ci mutex_lock(&id_priv->qp_mutex); 333162306a36Sopenharmony_ci if (id_priv->timeout_set && id_priv->timeout) 333262306a36Sopenharmony_ci route->path_rec->packet_life_time = id_priv->timeout - 1; 333362306a36Sopenharmony_ci else 333462306a36Sopenharmony_ci route->path_rec->packet_life_time = CMA_IBOE_PACKET_LIFETIME; 333562306a36Sopenharmony_ci mutex_unlock(&id_priv->qp_mutex); 333662306a36Sopenharmony_ci 333762306a36Sopenharmony_ci if (!route->path_rec->mtu) { 333862306a36Sopenharmony_ci ret = -EINVAL; 333962306a36Sopenharmony_ci goto err2; 334062306a36Sopenharmony_ci } 334162306a36Sopenharmony_ci 334262306a36Sopenharmony_ci if (rdma_protocol_roce_udp_encap(id_priv->id.device, 334362306a36Sopenharmony_ci id_priv->id.port_num)) 334462306a36Sopenharmony_ci route->path_rec->flow_label = 334562306a36Sopenharmony_ci cma_get_roce_udp_flow_label(id_priv); 334662306a36Sopenharmony_ci 334762306a36Sopenharmony_ci cma_init_resolve_route_work(work, id_priv); 334862306a36Sopenharmony_ci queue_work(cma_wq, &work->work); 334962306a36Sopenharmony_ci 335062306a36Sopenharmony_ci return 0; 335162306a36Sopenharmony_ci 335262306a36Sopenharmony_cierr2: 335362306a36Sopenharmony_ci kfree(route->path_rec); 335462306a36Sopenharmony_ci route->path_rec = NULL; 335562306a36Sopenharmony_ci route->num_pri_alt_paths = 0; 335662306a36Sopenharmony_cierr1: 335762306a36Sopenharmony_ci kfree(work); 335862306a36Sopenharmony_ci return ret; 335962306a36Sopenharmony_ci} 336062306a36Sopenharmony_ci 336162306a36Sopenharmony_ciint rdma_resolve_route(struct rdma_cm_id *id, unsigned long timeout_ms) 336262306a36Sopenharmony_ci{ 336362306a36Sopenharmony_ci struct rdma_id_private *id_priv; 336462306a36Sopenharmony_ci int ret; 336562306a36Sopenharmony_ci 336662306a36Sopenharmony_ci if (!timeout_ms) 336762306a36Sopenharmony_ci return -EINVAL; 336862306a36Sopenharmony_ci 336962306a36Sopenharmony_ci id_priv = container_of(id, struct rdma_id_private, id); 337062306a36Sopenharmony_ci if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED, RDMA_CM_ROUTE_QUERY)) 337162306a36Sopenharmony_ci return -EINVAL; 337262306a36Sopenharmony_ci 337362306a36Sopenharmony_ci cma_id_get(id_priv); 337462306a36Sopenharmony_ci if (rdma_cap_ib_sa(id->device, id->port_num)) 337562306a36Sopenharmony_ci ret = cma_resolve_ib_route(id_priv, timeout_ms); 337662306a36Sopenharmony_ci else if (rdma_protocol_roce(id->device, id->port_num)) { 337762306a36Sopenharmony_ci ret = cma_resolve_iboe_route(id_priv); 337862306a36Sopenharmony_ci if (!ret) 337962306a36Sopenharmony_ci cma_add_id_to_tree(id_priv); 338062306a36Sopenharmony_ci } 338162306a36Sopenharmony_ci else if (rdma_protocol_iwarp(id->device, id->port_num)) 338262306a36Sopenharmony_ci ret = cma_resolve_iw_route(id_priv); 338362306a36Sopenharmony_ci else 338462306a36Sopenharmony_ci ret = -ENOSYS; 338562306a36Sopenharmony_ci 338662306a36Sopenharmony_ci if (ret) 338762306a36Sopenharmony_ci goto err; 338862306a36Sopenharmony_ci 338962306a36Sopenharmony_ci return 0; 339062306a36Sopenharmony_cierr: 339162306a36Sopenharmony_ci cma_comp_exch(id_priv, RDMA_CM_ROUTE_QUERY, RDMA_CM_ADDR_RESOLVED); 339262306a36Sopenharmony_ci cma_id_put(id_priv); 339362306a36Sopenharmony_ci return ret; 339462306a36Sopenharmony_ci} 339562306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_resolve_route); 339662306a36Sopenharmony_ci 339762306a36Sopenharmony_cistatic void cma_set_loopback(struct sockaddr *addr) 339862306a36Sopenharmony_ci{ 339962306a36Sopenharmony_ci switch (addr->sa_family) { 340062306a36Sopenharmony_ci case AF_INET: 340162306a36Sopenharmony_ci ((struct sockaddr_in *) addr)->sin_addr.s_addr = htonl(INADDR_LOOPBACK); 340262306a36Sopenharmony_ci break; 340362306a36Sopenharmony_ci case AF_INET6: 340462306a36Sopenharmony_ci ipv6_addr_set(&((struct sockaddr_in6 *) addr)->sin6_addr, 340562306a36Sopenharmony_ci 0, 0, 0, htonl(1)); 340662306a36Sopenharmony_ci break; 340762306a36Sopenharmony_ci default: 340862306a36Sopenharmony_ci ib_addr_set(&((struct sockaddr_ib *) addr)->sib_addr, 340962306a36Sopenharmony_ci 0, 0, 0, htonl(1)); 341062306a36Sopenharmony_ci break; 341162306a36Sopenharmony_ci } 341262306a36Sopenharmony_ci} 341362306a36Sopenharmony_ci 341462306a36Sopenharmony_cistatic int cma_bind_loopback(struct rdma_id_private *id_priv) 341562306a36Sopenharmony_ci{ 341662306a36Sopenharmony_ci struct cma_device *cma_dev, *cur_dev; 341762306a36Sopenharmony_ci union ib_gid gid; 341862306a36Sopenharmony_ci enum ib_port_state port_state; 341962306a36Sopenharmony_ci unsigned int p; 342062306a36Sopenharmony_ci u16 pkey; 342162306a36Sopenharmony_ci int ret; 342262306a36Sopenharmony_ci 342362306a36Sopenharmony_ci cma_dev = NULL; 342462306a36Sopenharmony_ci mutex_lock(&lock); 342562306a36Sopenharmony_ci list_for_each_entry(cur_dev, &dev_list, list) { 342662306a36Sopenharmony_ci if (cma_family(id_priv) == AF_IB && 342762306a36Sopenharmony_ci !rdma_cap_ib_cm(cur_dev->device, 1)) 342862306a36Sopenharmony_ci continue; 342962306a36Sopenharmony_ci 343062306a36Sopenharmony_ci if (!cma_dev) 343162306a36Sopenharmony_ci cma_dev = cur_dev; 343262306a36Sopenharmony_ci 343362306a36Sopenharmony_ci rdma_for_each_port (cur_dev->device, p) { 343462306a36Sopenharmony_ci if (!ib_get_cached_port_state(cur_dev->device, p, &port_state) && 343562306a36Sopenharmony_ci port_state == IB_PORT_ACTIVE) { 343662306a36Sopenharmony_ci cma_dev = cur_dev; 343762306a36Sopenharmony_ci goto port_found; 343862306a36Sopenharmony_ci } 343962306a36Sopenharmony_ci } 344062306a36Sopenharmony_ci } 344162306a36Sopenharmony_ci 344262306a36Sopenharmony_ci if (!cma_dev) { 344362306a36Sopenharmony_ci ret = -ENODEV; 344462306a36Sopenharmony_ci goto out; 344562306a36Sopenharmony_ci } 344662306a36Sopenharmony_ci 344762306a36Sopenharmony_ci p = 1; 344862306a36Sopenharmony_ci 344962306a36Sopenharmony_ciport_found: 345062306a36Sopenharmony_ci ret = rdma_query_gid(cma_dev->device, p, 0, &gid); 345162306a36Sopenharmony_ci if (ret) 345262306a36Sopenharmony_ci goto out; 345362306a36Sopenharmony_ci 345462306a36Sopenharmony_ci ret = ib_get_cached_pkey(cma_dev->device, p, 0, &pkey); 345562306a36Sopenharmony_ci if (ret) 345662306a36Sopenharmony_ci goto out; 345762306a36Sopenharmony_ci 345862306a36Sopenharmony_ci id_priv->id.route.addr.dev_addr.dev_type = 345962306a36Sopenharmony_ci (rdma_protocol_ib(cma_dev->device, p)) ? 346062306a36Sopenharmony_ci ARPHRD_INFINIBAND : ARPHRD_ETHER; 346162306a36Sopenharmony_ci 346262306a36Sopenharmony_ci rdma_addr_set_sgid(&id_priv->id.route.addr.dev_addr, &gid); 346362306a36Sopenharmony_ci ib_addr_set_pkey(&id_priv->id.route.addr.dev_addr, pkey); 346462306a36Sopenharmony_ci id_priv->id.port_num = p; 346562306a36Sopenharmony_ci cma_attach_to_dev(id_priv, cma_dev); 346662306a36Sopenharmony_ci rdma_restrack_add(&id_priv->res); 346762306a36Sopenharmony_ci cma_set_loopback(cma_src_addr(id_priv)); 346862306a36Sopenharmony_ciout: 346962306a36Sopenharmony_ci mutex_unlock(&lock); 347062306a36Sopenharmony_ci return ret; 347162306a36Sopenharmony_ci} 347262306a36Sopenharmony_ci 347362306a36Sopenharmony_cistatic void addr_handler(int status, struct sockaddr *src_addr, 347462306a36Sopenharmony_ci struct rdma_dev_addr *dev_addr, void *context) 347562306a36Sopenharmony_ci{ 347662306a36Sopenharmony_ci struct rdma_id_private *id_priv = context; 347762306a36Sopenharmony_ci struct rdma_cm_event event = {}; 347862306a36Sopenharmony_ci struct sockaddr *addr; 347962306a36Sopenharmony_ci struct sockaddr_storage old_addr; 348062306a36Sopenharmony_ci 348162306a36Sopenharmony_ci mutex_lock(&id_priv->handler_mutex); 348262306a36Sopenharmony_ci if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_QUERY, 348362306a36Sopenharmony_ci RDMA_CM_ADDR_RESOLVED)) 348462306a36Sopenharmony_ci goto out; 348562306a36Sopenharmony_ci 348662306a36Sopenharmony_ci /* 348762306a36Sopenharmony_ci * Store the previous src address, so that if we fail to acquire 348862306a36Sopenharmony_ci * matching rdma device, old address can be restored back, which helps 348962306a36Sopenharmony_ci * to cancel the cma listen operation correctly. 349062306a36Sopenharmony_ci */ 349162306a36Sopenharmony_ci addr = cma_src_addr(id_priv); 349262306a36Sopenharmony_ci memcpy(&old_addr, addr, rdma_addr_size(addr)); 349362306a36Sopenharmony_ci memcpy(addr, src_addr, rdma_addr_size(src_addr)); 349462306a36Sopenharmony_ci if (!status && !id_priv->cma_dev) { 349562306a36Sopenharmony_ci status = cma_acquire_dev_by_src_ip(id_priv); 349662306a36Sopenharmony_ci if (status) 349762306a36Sopenharmony_ci pr_debug_ratelimited("RDMA CM: ADDR_ERROR: failed to acquire device. status %d\n", 349862306a36Sopenharmony_ci status); 349962306a36Sopenharmony_ci rdma_restrack_add(&id_priv->res); 350062306a36Sopenharmony_ci } else if (status) { 350162306a36Sopenharmony_ci pr_debug_ratelimited("RDMA CM: ADDR_ERROR: failed to resolve IP. status %d\n", status); 350262306a36Sopenharmony_ci } 350362306a36Sopenharmony_ci 350462306a36Sopenharmony_ci if (status) { 350562306a36Sopenharmony_ci memcpy(addr, &old_addr, 350662306a36Sopenharmony_ci rdma_addr_size((struct sockaddr *)&old_addr)); 350762306a36Sopenharmony_ci if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED, 350862306a36Sopenharmony_ci RDMA_CM_ADDR_BOUND)) 350962306a36Sopenharmony_ci goto out; 351062306a36Sopenharmony_ci event.event = RDMA_CM_EVENT_ADDR_ERROR; 351162306a36Sopenharmony_ci event.status = status; 351262306a36Sopenharmony_ci } else 351362306a36Sopenharmony_ci event.event = RDMA_CM_EVENT_ADDR_RESOLVED; 351462306a36Sopenharmony_ci 351562306a36Sopenharmony_ci if (cma_cm_event_handler(id_priv, &event)) { 351662306a36Sopenharmony_ci destroy_id_handler_unlock(id_priv); 351762306a36Sopenharmony_ci return; 351862306a36Sopenharmony_ci } 351962306a36Sopenharmony_ciout: 352062306a36Sopenharmony_ci mutex_unlock(&id_priv->handler_mutex); 352162306a36Sopenharmony_ci} 352262306a36Sopenharmony_ci 352362306a36Sopenharmony_cistatic int cma_resolve_loopback(struct rdma_id_private *id_priv) 352462306a36Sopenharmony_ci{ 352562306a36Sopenharmony_ci struct cma_work *work; 352662306a36Sopenharmony_ci union ib_gid gid; 352762306a36Sopenharmony_ci int ret; 352862306a36Sopenharmony_ci 352962306a36Sopenharmony_ci work = kzalloc(sizeof *work, GFP_KERNEL); 353062306a36Sopenharmony_ci if (!work) 353162306a36Sopenharmony_ci return -ENOMEM; 353262306a36Sopenharmony_ci 353362306a36Sopenharmony_ci if (!id_priv->cma_dev) { 353462306a36Sopenharmony_ci ret = cma_bind_loopback(id_priv); 353562306a36Sopenharmony_ci if (ret) 353662306a36Sopenharmony_ci goto err; 353762306a36Sopenharmony_ci } 353862306a36Sopenharmony_ci 353962306a36Sopenharmony_ci rdma_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid); 354062306a36Sopenharmony_ci rdma_addr_set_dgid(&id_priv->id.route.addr.dev_addr, &gid); 354162306a36Sopenharmony_ci 354262306a36Sopenharmony_ci enqueue_resolve_addr_work(work, id_priv); 354362306a36Sopenharmony_ci return 0; 354462306a36Sopenharmony_cierr: 354562306a36Sopenharmony_ci kfree(work); 354662306a36Sopenharmony_ci return ret; 354762306a36Sopenharmony_ci} 354862306a36Sopenharmony_ci 354962306a36Sopenharmony_cistatic int cma_resolve_ib_addr(struct rdma_id_private *id_priv) 355062306a36Sopenharmony_ci{ 355162306a36Sopenharmony_ci struct cma_work *work; 355262306a36Sopenharmony_ci int ret; 355362306a36Sopenharmony_ci 355462306a36Sopenharmony_ci work = kzalloc(sizeof *work, GFP_KERNEL); 355562306a36Sopenharmony_ci if (!work) 355662306a36Sopenharmony_ci return -ENOMEM; 355762306a36Sopenharmony_ci 355862306a36Sopenharmony_ci if (!id_priv->cma_dev) { 355962306a36Sopenharmony_ci ret = cma_resolve_ib_dev(id_priv); 356062306a36Sopenharmony_ci if (ret) 356162306a36Sopenharmony_ci goto err; 356262306a36Sopenharmony_ci } 356362306a36Sopenharmony_ci 356462306a36Sopenharmony_ci rdma_addr_set_dgid(&id_priv->id.route.addr.dev_addr, (union ib_gid *) 356562306a36Sopenharmony_ci &(((struct sockaddr_ib *) &id_priv->id.route.addr.dst_addr)->sib_addr)); 356662306a36Sopenharmony_ci 356762306a36Sopenharmony_ci enqueue_resolve_addr_work(work, id_priv); 356862306a36Sopenharmony_ci return 0; 356962306a36Sopenharmony_cierr: 357062306a36Sopenharmony_ci kfree(work); 357162306a36Sopenharmony_ci return ret; 357262306a36Sopenharmony_ci} 357362306a36Sopenharmony_ci 357462306a36Sopenharmony_ciint rdma_set_reuseaddr(struct rdma_cm_id *id, int reuse) 357562306a36Sopenharmony_ci{ 357662306a36Sopenharmony_ci struct rdma_id_private *id_priv; 357762306a36Sopenharmony_ci unsigned long flags; 357862306a36Sopenharmony_ci int ret; 357962306a36Sopenharmony_ci 358062306a36Sopenharmony_ci id_priv = container_of(id, struct rdma_id_private, id); 358162306a36Sopenharmony_ci spin_lock_irqsave(&id_priv->lock, flags); 358262306a36Sopenharmony_ci if ((reuse && id_priv->state != RDMA_CM_LISTEN) || 358362306a36Sopenharmony_ci id_priv->state == RDMA_CM_IDLE) { 358462306a36Sopenharmony_ci id_priv->reuseaddr = reuse; 358562306a36Sopenharmony_ci ret = 0; 358662306a36Sopenharmony_ci } else { 358762306a36Sopenharmony_ci ret = -EINVAL; 358862306a36Sopenharmony_ci } 358962306a36Sopenharmony_ci spin_unlock_irqrestore(&id_priv->lock, flags); 359062306a36Sopenharmony_ci return ret; 359162306a36Sopenharmony_ci} 359262306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_set_reuseaddr); 359362306a36Sopenharmony_ci 359462306a36Sopenharmony_ciint rdma_set_afonly(struct rdma_cm_id *id, int afonly) 359562306a36Sopenharmony_ci{ 359662306a36Sopenharmony_ci struct rdma_id_private *id_priv; 359762306a36Sopenharmony_ci unsigned long flags; 359862306a36Sopenharmony_ci int ret; 359962306a36Sopenharmony_ci 360062306a36Sopenharmony_ci id_priv = container_of(id, struct rdma_id_private, id); 360162306a36Sopenharmony_ci spin_lock_irqsave(&id_priv->lock, flags); 360262306a36Sopenharmony_ci if (id_priv->state == RDMA_CM_IDLE || id_priv->state == RDMA_CM_ADDR_BOUND) { 360362306a36Sopenharmony_ci id_priv->options |= (1 << CMA_OPTION_AFONLY); 360462306a36Sopenharmony_ci id_priv->afonly = afonly; 360562306a36Sopenharmony_ci ret = 0; 360662306a36Sopenharmony_ci } else { 360762306a36Sopenharmony_ci ret = -EINVAL; 360862306a36Sopenharmony_ci } 360962306a36Sopenharmony_ci spin_unlock_irqrestore(&id_priv->lock, flags); 361062306a36Sopenharmony_ci return ret; 361162306a36Sopenharmony_ci} 361262306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_set_afonly); 361362306a36Sopenharmony_ci 361462306a36Sopenharmony_cistatic void cma_bind_port(struct rdma_bind_list *bind_list, 361562306a36Sopenharmony_ci struct rdma_id_private *id_priv) 361662306a36Sopenharmony_ci{ 361762306a36Sopenharmony_ci struct sockaddr *addr; 361862306a36Sopenharmony_ci struct sockaddr_ib *sib; 361962306a36Sopenharmony_ci u64 sid, mask; 362062306a36Sopenharmony_ci __be16 port; 362162306a36Sopenharmony_ci 362262306a36Sopenharmony_ci lockdep_assert_held(&lock); 362362306a36Sopenharmony_ci 362462306a36Sopenharmony_ci addr = cma_src_addr(id_priv); 362562306a36Sopenharmony_ci port = htons(bind_list->port); 362662306a36Sopenharmony_ci 362762306a36Sopenharmony_ci switch (addr->sa_family) { 362862306a36Sopenharmony_ci case AF_INET: 362962306a36Sopenharmony_ci ((struct sockaddr_in *) addr)->sin_port = port; 363062306a36Sopenharmony_ci break; 363162306a36Sopenharmony_ci case AF_INET6: 363262306a36Sopenharmony_ci ((struct sockaddr_in6 *) addr)->sin6_port = port; 363362306a36Sopenharmony_ci break; 363462306a36Sopenharmony_ci case AF_IB: 363562306a36Sopenharmony_ci sib = (struct sockaddr_ib *) addr; 363662306a36Sopenharmony_ci sid = be64_to_cpu(sib->sib_sid); 363762306a36Sopenharmony_ci mask = be64_to_cpu(sib->sib_sid_mask); 363862306a36Sopenharmony_ci sib->sib_sid = cpu_to_be64((sid & mask) | (u64) ntohs(port)); 363962306a36Sopenharmony_ci sib->sib_sid_mask = cpu_to_be64(~0ULL); 364062306a36Sopenharmony_ci break; 364162306a36Sopenharmony_ci } 364262306a36Sopenharmony_ci id_priv->bind_list = bind_list; 364362306a36Sopenharmony_ci hlist_add_head(&id_priv->node, &bind_list->owners); 364462306a36Sopenharmony_ci} 364562306a36Sopenharmony_ci 364662306a36Sopenharmony_cistatic int cma_alloc_port(enum rdma_ucm_port_space ps, 364762306a36Sopenharmony_ci struct rdma_id_private *id_priv, unsigned short snum) 364862306a36Sopenharmony_ci{ 364962306a36Sopenharmony_ci struct rdma_bind_list *bind_list; 365062306a36Sopenharmony_ci int ret; 365162306a36Sopenharmony_ci 365262306a36Sopenharmony_ci lockdep_assert_held(&lock); 365362306a36Sopenharmony_ci 365462306a36Sopenharmony_ci bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL); 365562306a36Sopenharmony_ci if (!bind_list) 365662306a36Sopenharmony_ci return -ENOMEM; 365762306a36Sopenharmony_ci 365862306a36Sopenharmony_ci ret = cma_ps_alloc(id_priv->id.route.addr.dev_addr.net, ps, bind_list, 365962306a36Sopenharmony_ci snum); 366062306a36Sopenharmony_ci if (ret < 0) 366162306a36Sopenharmony_ci goto err; 366262306a36Sopenharmony_ci 366362306a36Sopenharmony_ci bind_list->ps = ps; 366462306a36Sopenharmony_ci bind_list->port = snum; 366562306a36Sopenharmony_ci cma_bind_port(bind_list, id_priv); 366662306a36Sopenharmony_ci return 0; 366762306a36Sopenharmony_cierr: 366862306a36Sopenharmony_ci kfree(bind_list); 366962306a36Sopenharmony_ci return ret == -ENOSPC ? -EADDRNOTAVAIL : ret; 367062306a36Sopenharmony_ci} 367162306a36Sopenharmony_ci 367262306a36Sopenharmony_cistatic int cma_port_is_unique(struct rdma_bind_list *bind_list, 367362306a36Sopenharmony_ci struct rdma_id_private *id_priv) 367462306a36Sopenharmony_ci{ 367562306a36Sopenharmony_ci struct rdma_id_private *cur_id; 367662306a36Sopenharmony_ci struct sockaddr *daddr = cma_dst_addr(id_priv); 367762306a36Sopenharmony_ci struct sockaddr *saddr = cma_src_addr(id_priv); 367862306a36Sopenharmony_ci __be16 dport = cma_port(daddr); 367962306a36Sopenharmony_ci 368062306a36Sopenharmony_ci lockdep_assert_held(&lock); 368162306a36Sopenharmony_ci 368262306a36Sopenharmony_ci hlist_for_each_entry(cur_id, &bind_list->owners, node) { 368362306a36Sopenharmony_ci struct sockaddr *cur_daddr = cma_dst_addr(cur_id); 368462306a36Sopenharmony_ci struct sockaddr *cur_saddr = cma_src_addr(cur_id); 368562306a36Sopenharmony_ci __be16 cur_dport = cma_port(cur_daddr); 368662306a36Sopenharmony_ci 368762306a36Sopenharmony_ci if (id_priv == cur_id) 368862306a36Sopenharmony_ci continue; 368962306a36Sopenharmony_ci 369062306a36Sopenharmony_ci /* different dest port -> unique */ 369162306a36Sopenharmony_ci if (!cma_any_port(daddr) && 369262306a36Sopenharmony_ci !cma_any_port(cur_daddr) && 369362306a36Sopenharmony_ci (dport != cur_dport)) 369462306a36Sopenharmony_ci continue; 369562306a36Sopenharmony_ci 369662306a36Sopenharmony_ci /* different src address -> unique */ 369762306a36Sopenharmony_ci if (!cma_any_addr(saddr) && 369862306a36Sopenharmony_ci !cma_any_addr(cur_saddr) && 369962306a36Sopenharmony_ci cma_addr_cmp(saddr, cur_saddr)) 370062306a36Sopenharmony_ci continue; 370162306a36Sopenharmony_ci 370262306a36Sopenharmony_ci /* different dst address -> unique */ 370362306a36Sopenharmony_ci if (!cma_any_addr(daddr) && 370462306a36Sopenharmony_ci !cma_any_addr(cur_daddr) && 370562306a36Sopenharmony_ci cma_addr_cmp(daddr, cur_daddr)) 370662306a36Sopenharmony_ci continue; 370762306a36Sopenharmony_ci 370862306a36Sopenharmony_ci return -EADDRNOTAVAIL; 370962306a36Sopenharmony_ci } 371062306a36Sopenharmony_ci return 0; 371162306a36Sopenharmony_ci} 371262306a36Sopenharmony_ci 371362306a36Sopenharmony_cistatic int cma_alloc_any_port(enum rdma_ucm_port_space ps, 371462306a36Sopenharmony_ci struct rdma_id_private *id_priv) 371562306a36Sopenharmony_ci{ 371662306a36Sopenharmony_ci static unsigned int last_used_port; 371762306a36Sopenharmony_ci int low, high, remaining; 371862306a36Sopenharmony_ci unsigned int rover; 371962306a36Sopenharmony_ci struct net *net = id_priv->id.route.addr.dev_addr.net; 372062306a36Sopenharmony_ci 372162306a36Sopenharmony_ci lockdep_assert_held(&lock); 372262306a36Sopenharmony_ci 372362306a36Sopenharmony_ci inet_get_local_port_range(net, &low, &high); 372462306a36Sopenharmony_ci remaining = (high - low) + 1; 372562306a36Sopenharmony_ci rover = get_random_u32_inclusive(low, remaining + low - 1); 372662306a36Sopenharmony_ciretry: 372762306a36Sopenharmony_ci if (last_used_port != rover) { 372862306a36Sopenharmony_ci struct rdma_bind_list *bind_list; 372962306a36Sopenharmony_ci int ret; 373062306a36Sopenharmony_ci 373162306a36Sopenharmony_ci bind_list = cma_ps_find(net, ps, (unsigned short)rover); 373262306a36Sopenharmony_ci 373362306a36Sopenharmony_ci if (!bind_list) { 373462306a36Sopenharmony_ci ret = cma_alloc_port(ps, id_priv, rover); 373562306a36Sopenharmony_ci } else { 373662306a36Sopenharmony_ci ret = cma_port_is_unique(bind_list, id_priv); 373762306a36Sopenharmony_ci if (!ret) 373862306a36Sopenharmony_ci cma_bind_port(bind_list, id_priv); 373962306a36Sopenharmony_ci } 374062306a36Sopenharmony_ci /* 374162306a36Sopenharmony_ci * Remember previously used port number in order to avoid 374262306a36Sopenharmony_ci * re-using same port immediately after it is closed. 374362306a36Sopenharmony_ci */ 374462306a36Sopenharmony_ci if (!ret) 374562306a36Sopenharmony_ci last_used_port = rover; 374662306a36Sopenharmony_ci if (ret != -EADDRNOTAVAIL) 374762306a36Sopenharmony_ci return ret; 374862306a36Sopenharmony_ci } 374962306a36Sopenharmony_ci if (--remaining) { 375062306a36Sopenharmony_ci rover++; 375162306a36Sopenharmony_ci if ((rover < low) || (rover > high)) 375262306a36Sopenharmony_ci rover = low; 375362306a36Sopenharmony_ci goto retry; 375462306a36Sopenharmony_ci } 375562306a36Sopenharmony_ci return -EADDRNOTAVAIL; 375662306a36Sopenharmony_ci} 375762306a36Sopenharmony_ci 375862306a36Sopenharmony_ci/* 375962306a36Sopenharmony_ci * Check that the requested port is available. This is called when trying to 376062306a36Sopenharmony_ci * bind to a specific port, or when trying to listen on a bound port. In 376162306a36Sopenharmony_ci * the latter case, the provided id_priv may already be on the bind_list, but 376262306a36Sopenharmony_ci * we still need to check that it's okay to start listening. 376362306a36Sopenharmony_ci */ 376462306a36Sopenharmony_cistatic int cma_check_port(struct rdma_bind_list *bind_list, 376562306a36Sopenharmony_ci struct rdma_id_private *id_priv, uint8_t reuseaddr) 376662306a36Sopenharmony_ci{ 376762306a36Sopenharmony_ci struct rdma_id_private *cur_id; 376862306a36Sopenharmony_ci struct sockaddr *addr, *cur_addr; 376962306a36Sopenharmony_ci 377062306a36Sopenharmony_ci lockdep_assert_held(&lock); 377162306a36Sopenharmony_ci 377262306a36Sopenharmony_ci addr = cma_src_addr(id_priv); 377362306a36Sopenharmony_ci hlist_for_each_entry(cur_id, &bind_list->owners, node) { 377462306a36Sopenharmony_ci if (id_priv == cur_id) 377562306a36Sopenharmony_ci continue; 377662306a36Sopenharmony_ci 377762306a36Sopenharmony_ci if (reuseaddr && cur_id->reuseaddr) 377862306a36Sopenharmony_ci continue; 377962306a36Sopenharmony_ci 378062306a36Sopenharmony_ci cur_addr = cma_src_addr(cur_id); 378162306a36Sopenharmony_ci if (id_priv->afonly && cur_id->afonly && 378262306a36Sopenharmony_ci (addr->sa_family != cur_addr->sa_family)) 378362306a36Sopenharmony_ci continue; 378462306a36Sopenharmony_ci 378562306a36Sopenharmony_ci if (cma_any_addr(addr) || cma_any_addr(cur_addr)) 378662306a36Sopenharmony_ci return -EADDRNOTAVAIL; 378762306a36Sopenharmony_ci 378862306a36Sopenharmony_ci if (!cma_addr_cmp(addr, cur_addr)) 378962306a36Sopenharmony_ci return -EADDRINUSE; 379062306a36Sopenharmony_ci } 379162306a36Sopenharmony_ci return 0; 379262306a36Sopenharmony_ci} 379362306a36Sopenharmony_ci 379462306a36Sopenharmony_cistatic int cma_use_port(enum rdma_ucm_port_space ps, 379562306a36Sopenharmony_ci struct rdma_id_private *id_priv) 379662306a36Sopenharmony_ci{ 379762306a36Sopenharmony_ci struct rdma_bind_list *bind_list; 379862306a36Sopenharmony_ci unsigned short snum; 379962306a36Sopenharmony_ci int ret; 380062306a36Sopenharmony_ci 380162306a36Sopenharmony_ci lockdep_assert_held(&lock); 380262306a36Sopenharmony_ci 380362306a36Sopenharmony_ci snum = ntohs(cma_port(cma_src_addr(id_priv))); 380462306a36Sopenharmony_ci if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) 380562306a36Sopenharmony_ci return -EACCES; 380662306a36Sopenharmony_ci 380762306a36Sopenharmony_ci bind_list = cma_ps_find(id_priv->id.route.addr.dev_addr.net, ps, snum); 380862306a36Sopenharmony_ci if (!bind_list) { 380962306a36Sopenharmony_ci ret = cma_alloc_port(ps, id_priv, snum); 381062306a36Sopenharmony_ci } else { 381162306a36Sopenharmony_ci ret = cma_check_port(bind_list, id_priv, id_priv->reuseaddr); 381262306a36Sopenharmony_ci if (!ret) 381362306a36Sopenharmony_ci cma_bind_port(bind_list, id_priv); 381462306a36Sopenharmony_ci } 381562306a36Sopenharmony_ci return ret; 381662306a36Sopenharmony_ci} 381762306a36Sopenharmony_ci 381862306a36Sopenharmony_cistatic enum rdma_ucm_port_space 381962306a36Sopenharmony_cicma_select_inet_ps(struct rdma_id_private *id_priv) 382062306a36Sopenharmony_ci{ 382162306a36Sopenharmony_ci switch (id_priv->id.ps) { 382262306a36Sopenharmony_ci case RDMA_PS_TCP: 382362306a36Sopenharmony_ci case RDMA_PS_UDP: 382462306a36Sopenharmony_ci case RDMA_PS_IPOIB: 382562306a36Sopenharmony_ci case RDMA_PS_IB: 382662306a36Sopenharmony_ci return id_priv->id.ps; 382762306a36Sopenharmony_ci default: 382862306a36Sopenharmony_ci 382962306a36Sopenharmony_ci return 0; 383062306a36Sopenharmony_ci } 383162306a36Sopenharmony_ci} 383262306a36Sopenharmony_ci 383362306a36Sopenharmony_cistatic enum rdma_ucm_port_space 383462306a36Sopenharmony_cicma_select_ib_ps(struct rdma_id_private *id_priv) 383562306a36Sopenharmony_ci{ 383662306a36Sopenharmony_ci enum rdma_ucm_port_space ps = 0; 383762306a36Sopenharmony_ci struct sockaddr_ib *sib; 383862306a36Sopenharmony_ci u64 sid_ps, mask, sid; 383962306a36Sopenharmony_ci 384062306a36Sopenharmony_ci sib = (struct sockaddr_ib *) cma_src_addr(id_priv); 384162306a36Sopenharmony_ci mask = be64_to_cpu(sib->sib_sid_mask) & RDMA_IB_IP_PS_MASK; 384262306a36Sopenharmony_ci sid = be64_to_cpu(sib->sib_sid) & mask; 384362306a36Sopenharmony_ci 384462306a36Sopenharmony_ci if ((id_priv->id.ps == RDMA_PS_IB) && (sid == (RDMA_IB_IP_PS_IB & mask))) { 384562306a36Sopenharmony_ci sid_ps = RDMA_IB_IP_PS_IB; 384662306a36Sopenharmony_ci ps = RDMA_PS_IB; 384762306a36Sopenharmony_ci } else if (((id_priv->id.ps == RDMA_PS_IB) || (id_priv->id.ps == RDMA_PS_TCP)) && 384862306a36Sopenharmony_ci (sid == (RDMA_IB_IP_PS_TCP & mask))) { 384962306a36Sopenharmony_ci sid_ps = RDMA_IB_IP_PS_TCP; 385062306a36Sopenharmony_ci ps = RDMA_PS_TCP; 385162306a36Sopenharmony_ci } else if (((id_priv->id.ps == RDMA_PS_IB) || (id_priv->id.ps == RDMA_PS_UDP)) && 385262306a36Sopenharmony_ci (sid == (RDMA_IB_IP_PS_UDP & mask))) { 385362306a36Sopenharmony_ci sid_ps = RDMA_IB_IP_PS_UDP; 385462306a36Sopenharmony_ci ps = RDMA_PS_UDP; 385562306a36Sopenharmony_ci } 385662306a36Sopenharmony_ci 385762306a36Sopenharmony_ci if (ps) { 385862306a36Sopenharmony_ci sib->sib_sid = cpu_to_be64(sid_ps | ntohs(cma_port((struct sockaddr *) sib))); 385962306a36Sopenharmony_ci sib->sib_sid_mask = cpu_to_be64(RDMA_IB_IP_PS_MASK | 386062306a36Sopenharmony_ci be64_to_cpu(sib->sib_sid_mask)); 386162306a36Sopenharmony_ci } 386262306a36Sopenharmony_ci return ps; 386362306a36Sopenharmony_ci} 386462306a36Sopenharmony_ci 386562306a36Sopenharmony_cistatic int cma_get_port(struct rdma_id_private *id_priv) 386662306a36Sopenharmony_ci{ 386762306a36Sopenharmony_ci enum rdma_ucm_port_space ps; 386862306a36Sopenharmony_ci int ret; 386962306a36Sopenharmony_ci 387062306a36Sopenharmony_ci if (cma_family(id_priv) != AF_IB) 387162306a36Sopenharmony_ci ps = cma_select_inet_ps(id_priv); 387262306a36Sopenharmony_ci else 387362306a36Sopenharmony_ci ps = cma_select_ib_ps(id_priv); 387462306a36Sopenharmony_ci if (!ps) 387562306a36Sopenharmony_ci return -EPROTONOSUPPORT; 387662306a36Sopenharmony_ci 387762306a36Sopenharmony_ci mutex_lock(&lock); 387862306a36Sopenharmony_ci if (cma_any_port(cma_src_addr(id_priv))) 387962306a36Sopenharmony_ci ret = cma_alloc_any_port(ps, id_priv); 388062306a36Sopenharmony_ci else 388162306a36Sopenharmony_ci ret = cma_use_port(ps, id_priv); 388262306a36Sopenharmony_ci mutex_unlock(&lock); 388362306a36Sopenharmony_ci 388462306a36Sopenharmony_ci return ret; 388562306a36Sopenharmony_ci} 388662306a36Sopenharmony_ci 388762306a36Sopenharmony_cistatic int cma_check_linklocal(struct rdma_dev_addr *dev_addr, 388862306a36Sopenharmony_ci struct sockaddr *addr) 388962306a36Sopenharmony_ci{ 389062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 389162306a36Sopenharmony_ci struct sockaddr_in6 *sin6; 389262306a36Sopenharmony_ci 389362306a36Sopenharmony_ci if (addr->sa_family != AF_INET6) 389462306a36Sopenharmony_ci return 0; 389562306a36Sopenharmony_ci 389662306a36Sopenharmony_ci sin6 = (struct sockaddr_in6 *) addr; 389762306a36Sopenharmony_ci 389862306a36Sopenharmony_ci if (!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)) 389962306a36Sopenharmony_ci return 0; 390062306a36Sopenharmony_ci 390162306a36Sopenharmony_ci if (!sin6->sin6_scope_id) 390262306a36Sopenharmony_ci return -EINVAL; 390362306a36Sopenharmony_ci 390462306a36Sopenharmony_ci dev_addr->bound_dev_if = sin6->sin6_scope_id; 390562306a36Sopenharmony_ci#endif 390662306a36Sopenharmony_ci return 0; 390762306a36Sopenharmony_ci} 390862306a36Sopenharmony_ci 390962306a36Sopenharmony_ciint rdma_listen(struct rdma_cm_id *id, int backlog) 391062306a36Sopenharmony_ci{ 391162306a36Sopenharmony_ci struct rdma_id_private *id_priv = 391262306a36Sopenharmony_ci container_of(id, struct rdma_id_private, id); 391362306a36Sopenharmony_ci int ret; 391462306a36Sopenharmony_ci 391562306a36Sopenharmony_ci if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_LISTEN)) { 391662306a36Sopenharmony_ci struct sockaddr_in any_in = { 391762306a36Sopenharmony_ci .sin_family = AF_INET, 391862306a36Sopenharmony_ci .sin_addr.s_addr = htonl(INADDR_ANY), 391962306a36Sopenharmony_ci }; 392062306a36Sopenharmony_ci 392162306a36Sopenharmony_ci /* For a well behaved ULP state will be RDMA_CM_IDLE */ 392262306a36Sopenharmony_ci ret = rdma_bind_addr(id, (struct sockaddr *)&any_in); 392362306a36Sopenharmony_ci if (ret) 392462306a36Sopenharmony_ci return ret; 392562306a36Sopenharmony_ci if (WARN_ON(!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, 392662306a36Sopenharmony_ci RDMA_CM_LISTEN))) 392762306a36Sopenharmony_ci return -EINVAL; 392862306a36Sopenharmony_ci } 392962306a36Sopenharmony_ci 393062306a36Sopenharmony_ci /* 393162306a36Sopenharmony_ci * Once the ID reaches RDMA_CM_LISTEN it is not allowed to be reusable 393262306a36Sopenharmony_ci * any more, and has to be unique in the bind list. 393362306a36Sopenharmony_ci */ 393462306a36Sopenharmony_ci if (id_priv->reuseaddr) { 393562306a36Sopenharmony_ci mutex_lock(&lock); 393662306a36Sopenharmony_ci ret = cma_check_port(id_priv->bind_list, id_priv, 0); 393762306a36Sopenharmony_ci if (!ret) 393862306a36Sopenharmony_ci id_priv->reuseaddr = 0; 393962306a36Sopenharmony_ci mutex_unlock(&lock); 394062306a36Sopenharmony_ci if (ret) 394162306a36Sopenharmony_ci goto err; 394262306a36Sopenharmony_ci } 394362306a36Sopenharmony_ci 394462306a36Sopenharmony_ci id_priv->backlog = backlog; 394562306a36Sopenharmony_ci if (id_priv->cma_dev) { 394662306a36Sopenharmony_ci if (rdma_cap_ib_cm(id->device, 1)) { 394762306a36Sopenharmony_ci ret = cma_ib_listen(id_priv); 394862306a36Sopenharmony_ci if (ret) 394962306a36Sopenharmony_ci goto err; 395062306a36Sopenharmony_ci } else if (rdma_cap_iw_cm(id->device, 1)) { 395162306a36Sopenharmony_ci ret = cma_iw_listen(id_priv, backlog); 395262306a36Sopenharmony_ci if (ret) 395362306a36Sopenharmony_ci goto err; 395462306a36Sopenharmony_ci } else { 395562306a36Sopenharmony_ci ret = -ENOSYS; 395662306a36Sopenharmony_ci goto err; 395762306a36Sopenharmony_ci } 395862306a36Sopenharmony_ci } else { 395962306a36Sopenharmony_ci ret = cma_listen_on_all(id_priv); 396062306a36Sopenharmony_ci if (ret) 396162306a36Sopenharmony_ci goto err; 396262306a36Sopenharmony_ci } 396362306a36Sopenharmony_ci 396462306a36Sopenharmony_ci return 0; 396562306a36Sopenharmony_cierr: 396662306a36Sopenharmony_ci id_priv->backlog = 0; 396762306a36Sopenharmony_ci /* 396862306a36Sopenharmony_ci * All the failure paths that lead here will not allow the req_handler's 396962306a36Sopenharmony_ci * to have run. 397062306a36Sopenharmony_ci */ 397162306a36Sopenharmony_ci cma_comp_exch(id_priv, RDMA_CM_LISTEN, RDMA_CM_ADDR_BOUND); 397262306a36Sopenharmony_ci return ret; 397362306a36Sopenharmony_ci} 397462306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_listen); 397562306a36Sopenharmony_ci 397662306a36Sopenharmony_cistatic int rdma_bind_addr_dst(struct rdma_id_private *id_priv, 397762306a36Sopenharmony_ci struct sockaddr *addr, const struct sockaddr *daddr) 397862306a36Sopenharmony_ci{ 397962306a36Sopenharmony_ci struct sockaddr *id_daddr; 398062306a36Sopenharmony_ci int ret; 398162306a36Sopenharmony_ci 398262306a36Sopenharmony_ci if (addr->sa_family != AF_INET && addr->sa_family != AF_INET6 && 398362306a36Sopenharmony_ci addr->sa_family != AF_IB) 398462306a36Sopenharmony_ci return -EAFNOSUPPORT; 398562306a36Sopenharmony_ci 398662306a36Sopenharmony_ci if (!cma_comp_exch(id_priv, RDMA_CM_IDLE, RDMA_CM_ADDR_BOUND)) 398762306a36Sopenharmony_ci return -EINVAL; 398862306a36Sopenharmony_ci 398962306a36Sopenharmony_ci ret = cma_check_linklocal(&id_priv->id.route.addr.dev_addr, addr); 399062306a36Sopenharmony_ci if (ret) 399162306a36Sopenharmony_ci goto err1; 399262306a36Sopenharmony_ci 399362306a36Sopenharmony_ci memcpy(cma_src_addr(id_priv), addr, rdma_addr_size(addr)); 399462306a36Sopenharmony_ci if (!cma_any_addr(addr)) { 399562306a36Sopenharmony_ci ret = cma_translate_addr(addr, &id_priv->id.route.addr.dev_addr); 399662306a36Sopenharmony_ci if (ret) 399762306a36Sopenharmony_ci goto err1; 399862306a36Sopenharmony_ci 399962306a36Sopenharmony_ci ret = cma_acquire_dev_by_src_ip(id_priv); 400062306a36Sopenharmony_ci if (ret) 400162306a36Sopenharmony_ci goto err1; 400262306a36Sopenharmony_ci } 400362306a36Sopenharmony_ci 400462306a36Sopenharmony_ci if (!(id_priv->options & (1 << CMA_OPTION_AFONLY))) { 400562306a36Sopenharmony_ci if (addr->sa_family == AF_INET) 400662306a36Sopenharmony_ci id_priv->afonly = 1; 400762306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 400862306a36Sopenharmony_ci else if (addr->sa_family == AF_INET6) { 400962306a36Sopenharmony_ci struct net *net = id_priv->id.route.addr.dev_addr.net; 401062306a36Sopenharmony_ci 401162306a36Sopenharmony_ci id_priv->afonly = net->ipv6.sysctl.bindv6only; 401262306a36Sopenharmony_ci } 401362306a36Sopenharmony_ci#endif 401462306a36Sopenharmony_ci } 401562306a36Sopenharmony_ci id_daddr = cma_dst_addr(id_priv); 401662306a36Sopenharmony_ci if (daddr != id_daddr) 401762306a36Sopenharmony_ci memcpy(id_daddr, daddr, rdma_addr_size(addr)); 401862306a36Sopenharmony_ci id_daddr->sa_family = addr->sa_family; 401962306a36Sopenharmony_ci 402062306a36Sopenharmony_ci ret = cma_get_port(id_priv); 402162306a36Sopenharmony_ci if (ret) 402262306a36Sopenharmony_ci goto err2; 402362306a36Sopenharmony_ci 402462306a36Sopenharmony_ci if (!cma_any_addr(addr)) 402562306a36Sopenharmony_ci rdma_restrack_add(&id_priv->res); 402662306a36Sopenharmony_ci return 0; 402762306a36Sopenharmony_cierr2: 402862306a36Sopenharmony_ci if (id_priv->cma_dev) 402962306a36Sopenharmony_ci cma_release_dev(id_priv); 403062306a36Sopenharmony_cierr1: 403162306a36Sopenharmony_ci cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_IDLE); 403262306a36Sopenharmony_ci return ret; 403362306a36Sopenharmony_ci} 403462306a36Sopenharmony_ci 403562306a36Sopenharmony_cistatic int cma_bind_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, 403662306a36Sopenharmony_ci const struct sockaddr *dst_addr) 403762306a36Sopenharmony_ci{ 403862306a36Sopenharmony_ci struct rdma_id_private *id_priv = 403962306a36Sopenharmony_ci container_of(id, struct rdma_id_private, id); 404062306a36Sopenharmony_ci struct sockaddr_storage zero_sock = {}; 404162306a36Sopenharmony_ci 404262306a36Sopenharmony_ci if (src_addr && src_addr->sa_family) 404362306a36Sopenharmony_ci return rdma_bind_addr_dst(id_priv, src_addr, dst_addr); 404462306a36Sopenharmony_ci 404562306a36Sopenharmony_ci /* 404662306a36Sopenharmony_ci * When the src_addr is not specified, automatically supply an any addr 404762306a36Sopenharmony_ci */ 404862306a36Sopenharmony_ci zero_sock.ss_family = dst_addr->sa_family; 404962306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_IPV6) && dst_addr->sa_family == AF_INET6) { 405062306a36Sopenharmony_ci struct sockaddr_in6 *src_addr6 = 405162306a36Sopenharmony_ci (struct sockaddr_in6 *)&zero_sock; 405262306a36Sopenharmony_ci struct sockaddr_in6 *dst_addr6 = 405362306a36Sopenharmony_ci (struct sockaddr_in6 *)dst_addr; 405462306a36Sopenharmony_ci 405562306a36Sopenharmony_ci src_addr6->sin6_scope_id = dst_addr6->sin6_scope_id; 405662306a36Sopenharmony_ci if (ipv6_addr_type(&dst_addr6->sin6_addr) & IPV6_ADDR_LINKLOCAL) 405762306a36Sopenharmony_ci id->route.addr.dev_addr.bound_dev_if = 405862306a36Sopenharmony_ci dst_addr6->sin6_scope_id; 405962306a36Sopenharmony_ci } else if (dst_addr->sa_family == AF_IB) { 406062306a36Sopenharmony_ci ((struct sockaddr_ib *)&zero_sock)->sib_pkey = 406162306a36Sopenharmony_ci ((struct sockaddr_ib *)dst_addr)->sib_pkey; 406262306a36Sopenharmony_ci } 406362306a36Sopenharmony_ci return rdma_bind_addr_dst(id_priv, (struct sockaddr *)&zero_sock, dst_addr); 406462306a36Sopenharmony_ci} 406562306a36Sopenharmony_ci 406662306a36Sopenharmony_ci/* 406762306a36Sopenharmony_ci * If required, resolve the source address for bind and leave the id_priv in 406862306a36Sopenharmony_ci * state RDMA_CM_ADDR_BOUND. This oddly uses the state to determine the prior 406962306a36Sopenharmony_ci * calls made by ULP, a previously bound ID will not be re-bound and src_addr is 407062306a36Sopenharmony_ci * ignored. 407162306a36Sopenharmony_ci */ 407262306a36Sopenharmony_cistatic int resolve_prepare_src(struct rdma_id_private *id_priv, 407362306a36Sopenharmony_ci struct sockaddr *src_addr, 407462306a36Sopenharmony_ci const struct sockaddr *dst_addr) 407562306a36Sopenharmony_ci{ 407662306a36Sopenharmony_ci int ret; 407762306a36Sopenharmony_ci 407862306a36Sopenharmony_ci if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_ADDR_QUERY)) { 407962306a36Sopenharmony_ci /* For a well behaved ULP state will be RDMA_CM_IDLE */ 408062306a36Sopenharmony_ci ret = cma_bind_addr(&id_priv->id, src_addr, dst_addr); 408162306a36Sopenharmony_ci if (ret) 408262306a36Sopenharmony_ci return ret; 408362306a36Sopenharmony_ci if (WARN_ON(!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, 408462306a36Sopenharmony_ci RDMA_CM_ADDR_QUERY))) 408562306a36Sopenharmony_ci return -EINVAL; 408662306a36Sopenharmony_ci 408762306a36Sopenharmony_ci } else { 408862306a36Sopenharmony_ci memcpy(cma_dst_addr(id_priv), dst_addr, rdma_addr_size(dst_addr)); 408962306a36Sopenharmony_ci } 409062306a36Sopenharmony_ci 409162306a36Sopenharmony_ci if (cma_family(id_priv) != dst_addr->sa_family) { 409262306a36Sopenharmony_ci ret = -EINVAL; 409362306a36Sopenharmony_ci goto err_state; 409462306a36Sopenharmony_ci } 409562306a36Sopenharmony_ci return 0; 409662306a36Sopenharmony_ci 409762306a36Sopenharmony_cierr_state: 409862306a36Sopenharmony_ci cma_comp_exch(id_priv, RDMA_CM_ADDR_QUERY, RDMA_CM_ADDR_BOUND); 409962306a36Sopenharmony_ci return ret; 410062306a36Sopenharmony_ci} 410162306a36Sopenharmony_ci 410262306a36Sopenharmony_ciint rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, 410362306a36Sopenharmony_ci const struct sockaddr *dst_addr, unsigned long timeout_ms) 410462306a36Sopenharmony_ci{ 410562306a36Sopenharmony_ci struct rdma_id_private *id_priv = 410662306a36Sopenharmony_ci container_of(id, struct rdma_id_private, id); 410762306a36Sopenharmony_ci int ret; 410862306a36Sopenharmony_ci 410962306a36Sopenharmony_ci ret = resolve_prepare_src(id_priv, src_addr, dst_addr); 411062306a36Sopenharmony_ci if (ret) 411162306a36Sopenharmony_ci return ret; 411262306a36Sopenharmony_ci 411362306a36Sopenharmony_ci if (cma_any_addr(dst_addr)) { 411462306a36Sopenharmony_ci ret = cma_resolve_loopback(id_priv); 411562306a36Sopenharmony_ci } else { 411662306a36Sopenharmony_ci if (dst_addr->sa_family == AF_IB) { 411762306a36Sopenharmony_ci ret = cma_resolve_ib_addr(id_priv); 411862306a36Sopenharmony_ci } else { 411962306a36Sopenharmony_ci /* 412062306a36Sopenharmony_ci * The FSM can return back to RDMA_CM_ADDR_BOUND after 412162306a36Sopenharmony_ci * rdma_resolve_ip() is called, eg through the error 412262306a36Sopenharmony_ci * path in addr_handler(). If this happens the existing 412362306a36Sopenharmony_ci * request must be canceled before issuing a new one. 412462306a36Sopenharmony_ci * Since canceling a request is a bit slow and this 412562306a36Sopenharmony_ci * oddball path is rare, keep track once a request has 412662306a36Sopenharmony_ci * been issued. The track turns out to be a permanent 412762306a36Sopenharmony_ci * state since this is the only cancel as it is 412862306a36Sopenharmony_ci * immediately before rdma_resolve_ip(). 412962306a36Sopenharmony_ci */ 413062306a36Sopenharmony_ci if (id_priv->used_resolve_ip) 413162306a36Sopenharmony_ci rdma_addr_cancel(&id->route.addr.dev_addr); 413262306a36Sopenharmony_ci else 413362306a36Sopenharmony_ci id_priv->used_resolve_ip = 1; 413462306a36Sopenharmony_ci ret = rdma_resolve_ip(cma_src_addr(id_priv), dst_addr, 413562306a36Sopenharmony_ci &id->route.addr.dev_addr, 413662306a36Sopenharmony_ci timeout_ms, addr_handler, 413762306a36Sopenharmony_ci false, id_priv); 413862306a36Sopenharmony_ci } 413962306a36Sopenharmony_ci } 414062306a36Sopenharmony_ci if (ret) 414162306a36Sopenharmony_ci goto err; 414262306a36Sopenharmony_ci 414362306a36Sopenharmony_ci return 0; 414462306a36Sopenharmony_cierr: 414562306a36Sopenharmony_ci cma_comp_exch(id_priv, RDMA_CM_ADDR_QUERY, RDMA_CM_ADDR_BOUND); 414662306a36Sopenharmony_ci return ret; 414762306a36Sopenharmony_ci} 414862306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_resolve_addr); 414962306a36Sopenharmony_ci 415062306a36Sopenharmony_ciint rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr) 415162306a36Sopenharmony_ci{ 415262306a36Sopenharmony_ci struct rdma_id_private *id_priv = 415362306a36Sopenharmony_ci container_of(id, struct rdma_id_private, id); 415462306a36Sopenharmony_ci 415562306a36Sopenharmony_ci return rdma_bind_addr_dst(id_priv, addr, cma_dst_addr(id_priv)); 415662306a36Sopenharmony_ci} 415762306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_bind_addr); 415862306a36Sopenharmony_ci 415962306a36Sopenharmony_cistatic int cma_format_hdr(void *hdr, struct rdma_id_private *id_priv) 416062306a36Sopenharmony_ci{ 416162306a36Sopenharmony_ci struct cma_hdr *cma_hdr; 416262306a36Sopenharmony_ci 416362306a36Sopenharmony_ci cma_hdr = hdr; 416462306a36Sopenharmony_ci cma_hdr->cma_version = CMA_VERSION; 416562306a36Sopenharmony_ci if (cma_family(id_priv) == AF_INET) { 416662306a36Sopenharmony_ci struct sockaddr_in *src4, *dst4; 416762306a36Sopenharmony_ci 416862306a36Sopenharmony_ci src4 = (struct sockaddr_in *) cma_src_addr(id_priv); 416962306a36Sopenharmony_ci dst4 = (struct sockaddr_in *) cma_dst_addr(id_priv); 417062306a36Sopenharmony_ci 417162306a36Sopenharmony_ci cma_set_ip_ver(cma_hdr, 4); 417262306a36Sopenharmony_ci cma_hdr->src_addr.ip4.addr = src4->sin_addr.s_addr; 417362306a36Sopenharmony_ci cma_hdr->dst_addr.ip4.addr = dst4->sin_addr.s_addr; 417462306a36Sopenharmony_ci cma_hdr->port = src4->sin_port; 417562306a36Sopenharmony_ci } else if (cma_family(id_priv) == AF_INET6) { 417662306a36Sopenharmony_ci struct sockaddr_in6 *src6, *dst6; 417762306a36Sopenharmony_ci 417862306a36Sopenharmony_ci src6 = (struct sockaddr_in6 *) cma_src_addr(id_priv); 417962306a36Sopenharmony_ci dst6 = (struct sockaddr_in6 *) cma_dst_addr(id_priv); 418062306a36Sopenharmony_ci 418162306a36Sopenharmony_ci cma_set_ip_ver(cma_hdr, 6); 418262306a36Sopenharmony_ci cma_hdr->src_addr.ip6 = src6->sin6_addr; 418362306a36Sopenharmony_ci cma_hdr->dst_addr.ip6 = dst6->sin6_addr; 418462306a36Sopenharmony_ci cma_hdr->port = src6->sin6_port; 418562306a36Sopenharmony_ci } 418662306a36Sopenharmony_ci return 0; 418762306a36Sopenharmony_ci} 418862306a36Sopenharmony_ci 418962306a36Sopenharmony_cistatic int cma_sidr_rep_handler(struct ib_cm_id *cm_id, 419062306a36Sopenharmony_ci const struct ib_cm_event *ib_event) 419162306a36Sopenharmony_ci{ 419262306a36Sopenharmony_ci struct rdma_id_private *id_priv = cm_id->context; 419362306a36Sopenharmony_ci struct rdma_cm_event event = {}; 419462306a36Sopenharmony_ci const struct ib_cm_sidr_rep_event_param *rep = 419562306a36Sopenharmony_ci &ib_event->param.sidr_rep_rcvd; 419662306a36Sopenharmony_ci int ret; 419762306a36Sopenharmony_ci 419862306a36Sopenharmony_ci mutex_lock(&id_priv->handler_mutex); 419962306a36Sopenharmony_ci if (READ_ONCE(id_priv->state) != RDMA_CM_CONNECT) 420062306a36Sopenharmony_ci goto out; 420162306a36Sopenharmony_ci 420262306a36Sopenharmony_ci switch (ib_event->event) { 420362306a36Sopenharmony_ci case IB_CM_SIDR_REQ_ERROR: 420462306a36Sopenharmony_ci event.event = RDMA_CM_EVENT_UNREACHABLE; 420562306a36Sopenharmony_ci event.status = -ETIMEDOUT; 420662306a36Sopenharmony_ci break; 420762306a36Sopenharmony_ci case IB_CM_SIDR_REP_RECEIVED: 420862306a36Sopenharmony_ci event.param.ud.private_data = ib_event->private_data; 420962306a36Sopenharmony_ci event.param.ud.private_data_len = IB_CM_SIDR_REP_PRIVATE_DATA_SIZE; 421062306a36Sopenharmony_ci if (rep->status != IB_SIDR_SUCCESS) { 421162306a36Sopenharmony_ci event.event = RDMA_CM_EVENT_UNREACHABLE; 421262306a36Sopenharmony_ci event.status = ib_event->param.sidr_rep_rcvd.status; 421362306a36Sopenharmony_ci pr_debug_ratelimited("RDMA CM: UNREACHABLE: bad SIDR reply. status %d\n", 421462306a36Sopenharmony_ci event.status); 421562306a36Sopenharmony_ci break; 421662306a36Sopenharmony_ci } 421762306a36Sopenharmony_ci ret = cma_set_qkey(id_priv, rep->qkey); 421862306a36Sopenharmony_ci if (ret) { 421962306a36Sopenharmony_ci pr_debug_ratelimited("RDMA CM: ADDR_ERROR: failed to set qkey. status %d\n", ret); 422062306a36Sopenharmony_ci event.event = RDMA_CM_EVENT_ADDR_ERROR; 422162306a36Sopenharmony_ci event.status = ret; 422262306a36Sopenharmony_ci break; 422362306a36Sopenharmony_ci } 422462306a36Sopenharmony_ci ib_init_ah_attr_from_path(id_priv->id.device, 422562306a36Sopenharmony_ci id_priv->id.port_num, 422662306a36Sopenharmony_ci id_priv->id.route.path_rec, 422762306a36Sopenharmony_ci &event.param.ud.ah_attr, 422862306a36Sopenharmony_ci rep->sgid_attr); 422962306a36Sopenharmony_ci event.param.ud.qp_num = rep->qpn; 423062306a36Sopenharmony_ci event.param.ud.qkey = rep->qkey; 423162306a36Sopenharmony_ci event.event = RDMA_CM_EVENT_ESTABLISHED; 423262306a36Sopenharmony_ci event.status = 0; 423362306a36Sopenharmony_ci break; 423462306a36Sopenharmony_ci default: 423562306a36Sopenharmony_ci pr_err("RDMA CMA: unexpected IB CM event: %d\n", 423662306a36Sopenharmony_ci ib_event->event); 423762306a36Sopenharmony_ci goto out; 423862306a36Sopenharmony_ci } 423962306a36Sopenharmony_ci 424062306a36Sopenharmony_ci ret = cma_cm_event_handler(id_priv, &event); 424162306a36Sopenharmony_ci 424262306a36Sopenharmony_ci rdma_destroy_ah_attr(&event.param.ud.ah_attr); 424362306a36Sopenharmony_ci if (ret) { 424462306a36Sopenharmony_ci /* Destroy the CM ID by returning a non-zero value. */ 424562306a36Sopenharmony_ci id_priv->cm_id.ib = NULL; 424662306a36Sopenharmony_ci destroy_id_handler_unlock(id_priv); 424762306a36Sopenharmony_ci return ret; 424862306a36Sopenharmony_ci } 424962306a36Sopenharmony_ciout: 425062306a36Sopenharmony_ci mutex_unlock(&id_priv->handler_mutex); 425162306a36Sopenharmony_ci return 0; 425262306a36Sopenharmony_ci} 425362306a36Sopenharmony_ci 425462306a36Sopenharmony_cistatic int cma_resolve_ib_udp(struct rdma_id_private *id_priv, 425562306a36Sopenharmony_ci struct rdma_conn_param *conn_param) 425662306a36Sopenharmony_ci{ 425762306a36Sopenharmony_ci struct ib_cm_sidr_req_param req; 425862306a36Sopenharmony_ci struct ib_cm_id *id; 425962306a36Sopenharmony_ci void *private_data; 426062306a36Sopenharmony_ci u8 offset; 426162306a36Sopenharmony_ci int ret; 426262306a36Sopenharmony_ci 426362306a36Sopenharmony_ci memset(&req, 0, sizeof req); 426462306a36Sopenharmony_ci offset = cma_user_data_offset(id_priv); 426562306a36Sopenharmony_ci if (check_add_overflow(offset, conn_param->private_data_len, &req.private_data_len)) 426662306a36Sopenharmony_ci return -EINVAL; 426762306a36Sopenharmony_ci 426862306a36Sopenharmony_ci if (req.private_data_len) { 426962306a36Sopenharmony_ci private_data = kzalloc(req.private_data_len, GFP_ATOMIC); 427062306a36Sopenharmony_ci if (!private_data) 427162306a36Sopenharmony_ci return -ENOMEM; 427262306a36Sopenharmony_ci } else { 427362306a36Sopenharmony_ci private_data = NULL; 427462306a36Sopenharmony_ci } 427562306a36Sopenharmony_ci 427662306a36Sopenharmony_ci if (conn_param->private_data && conn_param->private_data_len) 427762306a36Sopenharmony_ci memcpy(private_data + offset, conn_param->private_data, 427862306a36Sopenharmony_ci conn_param->private_data_len); 427962306a36Sopenharmony_ci 428062306a36Sopenharmony_ci if (private_data) { 428162306a36Sopenharmony_ci ret = cma_format_hdr(private_data, id_priv); 428262306a36Sopenharmony_ci if (ret) 428362306a36Sopenharmony_ci goto out; 428462306a36Sopenharmony_ci req.private_data = private_data; 428562306a36Sopenharmony_ci } 428662306a36Sopenharmony_ci 428762306a36Sopenharmony_ci id = ib_create_cm_id(id_priv->id.device, cma_sidr_rep_handler, 428862306a36Sopenharmony_ci id_priv); 428962306a36Sopenharmony_ci if (IS_ERR(id)) { 429062306a36Sopenharmony_ci ret = PTR_ERR(id); 429162306a36Sopenharmony_ci goto out; 429262306a36Sopenharmony_ci } 429362306a36Sopenharmony_ci id_priv->cm_id.ib = id; 429462306a36Sopenharmony_ci 429562306a36Sopenharmony_ci req.path = id_priv->id.route.path_rec; 429662306a36Sopenharmony_ci req.sgid_attr = id_priv->id.route.addr.dev_addr.sgid_attr; 429762306a36Sopenharmony_ci req.service_id = rdma_get_service_id(&id_priv->id, cma_dst_addr(id_priv)); 429862306a36Sopenharmony_ci req.timeout_ms = 1 << (CMA_CM_RESPONSE_TIMEOUT - 8); 429962306a36Sopenharmony_ci req.max_cm_retries = CMA_MAX_CM_RETRIES; 430062306a36Sopenharmony_ci 430162306a36Sopenharmony_ci trace_cm_send_sidr_req(id_priv); 430262306a36Sopenharmony_ci ret = ib_send_cm_sidr_req(id_priv->cm_id.ib, &req); 430362306a36Sopenharmony_ci if (ret) { 430462306a36Sopenharmony_ci ib_destroy_cm_id(id_priv->cm_id.ib); 430562306a36Sopenharmony_ci id_priv->cm_id.ib = NULL; 430662306a36Sopenharmony_ci } 430762306a36Sopenharmony_ciout: 430862306a36Sopenharmony_ci kfree(private_data); 430962306a36Sopenharmony_ci return ret; 431062306a36Sopenharmony_ci} 431162306a36Sopenharmony_ci 431262306a36Sopenharmony_cistatic int cma_connect_ib(struct rdma_id_private *id_priv, 431362306a36Sopenharmony_ci struct rdma_conn_param *conn_param) 431462306a36Sopenharmony_ci{ 431562306a36Sopenharmony_ci struct ib_cm_req_param req; 431662306a36Sopenharmony_ci struct rdma_route *route; 431762306a36Sopenharmony_ci void *private_data; 431862306a36Sopenharmony_ci struct ib_cm_id *id; 431962306a36Sopenharmony_ci u8 offset; 432062306a36Sopenharmony_ci int ret; 432162306a36Sopenharmony_ci 432262306a36Sopenharmony_ci memset(&req, 0, sizeof req); 432362306a36Sopenharmony_ci offset = cma_user_data_offset(id_priv); 432462306a36Sopenharmony_ci if (check_add_overflow(offset, conn_param->private_data_len, &req.private_data_len)) 432562306a36Sopenharmony_ci return -EINVAL; 432662306a36Sopenharmony_ci 432762306a36Sopenharmony_ci if (req.private_data_len) { 432862306a36Sopenharmony_ci private_data = kzalloc(req.private_data_len, GFP_ATOMIC); 432962306a36Sopenharmony_ci if (!private_data) 433062306a36Sopenharmony_ci return -ENOMEM; 433162306a36Sopenharmony_ci } else { 433262306a36Sopenharmony_ci private_data = NULL; 433362306a36Sopenharmony_ci } 433462306a36Sopenharmony_ci 433562306a36Sopenharmony_ci if (conn_param->private_data && conn_param->private_data_len) 433662306a36Sopenharmony_ci memcpy(private_data + offset, conn_param->private_data, 433762306a36Sopenharmony_ci conn_param->private_data_len); 433862306a36Sopenharmony_ci 433962306a36Sopenharmony_ci id = ib_create_cm_id(id_priv->id.device, cma_ib_handler, id_priv); 434062306a36Sopenharmony_ci if (IS_ERR(id)) { 434162306a36Sopenharmony_ci ret = PTR_ERR(id); 434262306a36Sopenharmony_ci goto out; 434362306a36Sopenharmony_ci } 434462306a36Sopenharmony_ci id_priv->cm_id.ib = id; 434562306a36Sopenharmony_ci 434662306a36Sopenharmony_ci route = &id_priv->id.route; 434762306a36Sopenharmony_ci if (private_data) { 434862306a36Sopenharmony_ci ret = cma_format_hdr(private_data, id_priv); 434962306a36Sopenharmony_ci if (ret) 435062306a36Sopenharmony_ci goto out; 435162306a36Sopenharmony_ci req.private_data = private_data; 435262306a36Sopenharmony_ci } 435362306a36Sopenharmony_ci 435462306a36Sopenharmony_ci req.primary_path = &route->path_rec[0]; 435562306a36Sopenharmony_ci req.primary_path_inbound = route->path_rec_inbound; 435662306a36Sopenharmony_ci req.primary_path_outbound = route->path_rec_outbound; 435762306a36Sopenharmony_ci if (route->num_pri_alt_paths == 2) 435862306a36Sopenharmony_ci req.alternate_path = &route->path_rec[1]; 435962306a36Sopenharmony_ci 436062306a36Sopenharmony_ci req.ppath_sgid_attr = id_priv->id.route.addr.dev_addr.sgid_attr; 436162306a36Sopenharmony_ci /* Alternate path SGID attribute currently unsupported */ 436262306a36Sopenharmony_ci req.service_id = rdma_get_service_id(&id_priv->id, cma_dst_addr(id_priv)); 436362306a36Sopenharmony_ci req.qp_num = id_priv->qp_num; 436462306a36Sopenharmony_ci req.qp_type = id_priv->id.qp_type; 436562306a36Sopenharmony_ci req.starting_psn = id_priv->seq_num; 436662306a36Sopenharmony_ci req.responder_resources = conn_param->responder_resources; 436762306a36Sopenharmony_ci req.initiator_depth = conn_param->initiator_depth; 436862306a36Sopenharmony_ci req.flow_control = conn_param->flow_control; 436962306a36Sopenharmony_ci req.retry_count = min_t(u8, 7, conn_param->retry_count); 437062306a36Sopenharmony_ci req.rnr_retry_count = min_t(u8, 7, conn_param->rnr_retry_count); 437162306a36Sopenharmony_ci req.remote_cm_response_timeout = CMA_CM_RESPONSE_TIMEOUT; 437262306a36Sopenharmony_ci req.local_cm_response_timeout = CMA_CM_RESPONSE_TIMEOUT; 437362306a36Sopenharmony_ci req.max_cm_retries = CMA_MAX_CM_RETRIES; 437462306a36Sopenharmony_ci req.srq = id_priv->srq ? 1 : 0; 437562306a36Sopenharmony_ci req.ece.vendor_id = id_priv->ece.vendor_id; 437662306a36Sopenharmony_ci req.ece.attr_mod = id_priv->ece.attr_mod; 437762306a36Sopenharmony_ci 437862306a36Sopenharmony_ci trace_cm_send_req(id_priv); 437962306a36Sopenharmony_ci ret = ib_send_cm_req(id_priv->cm_id.ib, &req); 438062306a36Sopenharmony_ciout: 438162306a36Sopenharmony_ci if (ret && !IS_ERR(id)) { 438262306a36Sopenharmony_ci ib_destroy_cm_id(id); 438362306a36Sopenharmony_ci id_priv->cm_id.ib = NULL; 438462306a36Sopenharmony_ci } 438562306a36Sopenharmony_ci 438662306a36Sopenharmony_ci kfree(private_data); 438762306a36Sopenharmony_ci return ret; 438862306a36Sopenharmony_ci} 438962306a36Sopenharmony_ci 439062306a36Sopenharmony_cistatic int cma_connect_iw(struct rdma_id_private *id_priv, 439162306a36Sopenharmony_ci struct rdma_conn_param *conn_param) 439262306a36Sopenharmony_ci{ 439362306a36Sopenharmony_ci struct iw_cm_id *cm_id; 439462306a36Sopenharmony_ci int ret; 439562306a36Sopenharmony_ci struct iw_cm_conn_param iw_param; 439662306a36Sopenharmony_ci 439762306a36Sopenharmony_ci cm_id = iw_create_cm_id(id_priv->id.device, cma_iw_handler, id_priv); 439862306a36Sopenharmony_ci if (IS_ERR(cm_id)) 439962306a36Sopenharmony_ci return PTR_ERR(cm_id); 440062306a36Sopenharmony_ci 440162306a36Sopenharmony_ci mutex_lock(&id_priv->qp_mutex); 440262306a36Sopenharmony_ci cm_id->tos = id_priv->tos; 440362306a36Sopenharmony_ci cm_id->tos_set = id_priv->tos_set; 440462306a36Sopenharmony_ci mutex_unlock(&id_priv->qp_mutex); 440562306a36Sopenharmony_ci 440662306a36Sopenharmony_ci id_priv->cm_id.iw = cm_id; 440762306a36Sopenharmony_ci 440862306a36Sopenharmony_ci memcpy(&cm_id->local_addr, cma_src_addr(id_priv), 440962306a36Sopenharmony_ci rdma_addr_size(cma_src_addr(id_priv))); 441062306a36Sopenharmony_ci memcpy(&cm_id->remote_addr, cma_dst_addr(id_priv), 441162306a36Sopenharmony_ci rdma_addr_size(cma_dst_addr(id_priv))); 441262306a36Sopenharmony_ci 441362306a36Sopenharmony_ci ret = cma_modify_qp_rtr(id_priv, conn_param); 441462306a36Sopenharmony_ci if (ret) 441562306a36Sopenharmony_ci goto out; 441662306a36Sopenharmony_ci 441762306a36Sopenharmony_ci if (conn_param) { 441862306a36Sopenharmony_ci iw_param.ord = conn_param->initiator_depth; 441962306a36Sopenharmony_ci iw_param.ird = conn_param->responder_resources; 442062306a36Sopenharmony_ci iw_param.private_data = conn_param->private_data; 442162306a36Sopenharmony_ci iw_param.private_data_len = conn_param->private_data_len; 442262306a36Sopenharmony_ci iw_param.qpn = id_priv->id.qp ? id_priv->qp_num : conn_param->qp_num; 442362306a36Sopenharmony_ci } else { 442462306a36Sopenharmony_ci memset(&iw_param, 0, sizeof iw_param); 442562306a36Sopenharmony_ci iw_param.qpn = id_priv->qp_num; 442662306a36Sopenharmony_ci } 442762306a36Sopenharmony_ci ret = iw_cm_connect(cm_id, &iw_param); 442862306a36Sopenharmony_ciout: 442962306a36Sopenharmony_ci if (ret) { 443062306a36Sopenharmony_ci iw_destroy_cm_id(cm_id); 443162306a36Sopenharmony_ci id_priv->cm_id.iw = NULL; 443262306a36Sopenharmony_ci } 443362306a36Sopenharmony_ci return ret; 443462306a36Sopenharmony_ci} 443562306a36Sopenharmony_ci 443662306a36Sopenharmony_ci/** 443762306a36Sopenharmony_ci * rdma_connect_locked - Initiate an active connection request. 443862306a36Sopenharmony_ci * @id: Connection identifier to connect. 443962306a36Sopenharmony_ci * @conn_param: Connection information used for connected QPs. 444062306a36Sopenharmony_ci * 444162306a36Sopenharmony_ci * Same as rdma_connect() but can only be called from the 444262306a36Sopenharmony_ci * RDMA_CM_EVENT_ROUTE_RESOLVED handler callback. 444362306a36Sopenharmony_ci */ 444462306a36Sopenharmony_ciint rdma_connect_locked(struct rdma_cm_id *id, 444562306a36Sopenharmony_ci struct rdma_conn_param *conn_param) 444662306a36Sopenharmony_ci{ 444762306a36Sopenharmony_ci struct rdma_id_private *id_priv = 444862306a36Sopenharmony_ci container_of(id, struct rdma_id_private, id); 444962306a36Sopenharmony_ci int ret; 445062306a36Sopenharmony_ci 445162306a36Sopenharmony_ci if (!cma_comp_exch(id_priv, RDMA_CM_ROUTE_RESOLVED, RDMA_CM_CONNECT)) 445262306a36Sopenharmony_ci return -EINVAL; 445362306a36Sopenharmony_ci 445462306a36Sopenharmony_ci if (!id->qp) { 445562306a36Sopenharmony_ci id_priv->qp_num = conn_param->qp_num; 445662306a36Sopenharmony_ci id_priv->srq = conn_param->srq; 445762306a36Sopenharmony_ci } 445862306a36Sopenharmony_ci 445962306a36Sopenharmony_ci if (rdma_cap_ib_cm(id->device, id->port_num)) { 446062306a36Sopenharmony_ci if (id->qp_type == IB_QPT_UD) 446162306a36Sopenharmony_ci ret = cma_resolve_ib_udp(id_priv, conn_param); 446262306a36Sopenharmony_ci else 446362306a36Sopenharmony_ci ret = cma_connect_ib(id_priv, conn_param); 446462306a36Sopenharmony_ci } else if (rdma_cap_iw_cm(id->device, id->port_num)) { 446562306a36Sopenharmony_ci ret = cma_connect_iw(id_priv, conn_param); 446662306a36Sopenharmony_ci } else { 446762306a36Sopenharmony_ci ret = -ENOSYS; 446862306a36Sopenharmony_ci } 446962306a36Sopenharmony_ci if (ret) 447062306a36Sopenharmony_ci goto err_state; 447162306a36Sopenharmony_ci return 0; 447262306a36Sopenharmony_cierr_state: 447362306a36Sopenharmony_ci cma_comp_exch(id_priv, RDMA_CM_CONNECT, RDMA_CM_ROUTE_RESOLVED); 447462306a36Sopenharmony_ci return ret; 447562306a36Sopenharmony_ci} 447662306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_connect_locked); 447762306a36Sopenharmony_ci 447862306a36Sopenharmony_ci/** 447962306a36Sopenharmony_ci * rdma_connect - Initiate an active connection request. 448062306a36Sopenharmony_ci * @id: Connection identifier to connect. 448162306a36Sopenharmony_ci * @conn_param: Connection information used for connected QPs. 448262306a36Sopenharmony_ci * 448362306a36Sopenharmony_ci * Users must have resolved a route for the rdma_cm_id to connect with by having 448462306a36Sopenharmony_ci * called rdma_resolve_route before calling this routine. 448562306a36Sopenharmony_ci * 448662306a36Sopenharmony_ci * This call will either connect to a remote QP or obtain remote QP information 448762306a36Sopenharmony_ci * for unconnected rdma_cm_id's. The actual operation is based on the 448862306a36Sopenharmony_ci * rdma_cm_id's port space. 448962306a36Sopenharmony_ci */ 449062306a36Sopenharmony_ciint rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param) 449162306a36Sopenharmony_ci{ 449262306a36Sopenharmony_ci struct rdma_id_private *id_priv = 449362306a36Sopenharmony_ci container_of(id, struct rdma_id_private, id); 449462306a36Sopenharmony_ci int ret; 449562306a36Sopenharmony_ci 449662306a36Sopenharmony_ci mutex_lock(&id_priv->handler_mutex); 449762306a36Sopenharmony_ci ret = rdma_connect_locked(id, conn_param); 449862306a36Sopenharmony_ci mutex_unlock(&id_priv->handler_mutex); 449962306a36Sopenharmony_ci return ret; 450062306a36Sopenharmony_ci} 450162306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_connect); 450262306a36Sopenharmony_ci 450362306a36Sopenharmony_ci/** 450462306a36Sopenharmony_ci * rdma_connect_ece - Initiate an active connection request with ECE data. 450562306a36Sopenharmony_ci * @id: Connection identifier to connect. 450662306a36Sopenharmony_ci * @conn_param: Connection information used for connected QPs. 450762306a36Sopenharmony_ci * @ece: ECE parameters 450862306a36Sopenharmony_ci * 450962306a36Sopenharmony_ci * See rdma_connect() explanation. 451062306a36Sopenharmony_ci */ 451162306a36Sopenharmony_ciint rdma_connect_ece(struct rdma_cm_id *id, struct rdma_conn_param *conn_param, 451262306a36Sopenharmony_ci struct rdma_ucm_ece *ece) 451362306a36Sopenharmony_ci{ 451462306a36Sopenharmony_ci struct rdma_id_private *id_priv = 451562306a36Sopenharmony_ci container_of(id, struct rdma_id_private, id); 451662306a36Sopenharmony_ci 451762306a36Sopenharmony_ci id_priv->ece.vendor_id = ece->vendor_id; 451862306a36Sopenharmony_ci id_priv->ece.attr_mod = ece->attr_mod; 451962306a36Sopenharmony_ci 452062306a36Sopenharmony_ci return rdma_connect(id, conn_param); 452162306a36Sopenharmony_ci} 452262306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_connect_ece); 452362306a36Sopenharmony_ci 452462306a36Sopenharmony_cistatic int cma_accept_ib(struct rdma_id_private *id_priv, 452562306a36Sopenharmony_ci struct rdma_conn_param *conn_param) 452662306a36Sopenharmony_ci{ 452762306a36Sopenharmony_ci struct ib_cm_rep_param rep; 452862306a36Sopenharmony_ci int ret; 452962306a36Sopenharmony_ci 453062306a36Sopenharmony_ci ret = cma_modify_qp_rtr(id_priv, conn_param); 453162306a36Sopenharmony_ci if (ret) 453262306a36Sopenharmony_ci goto out; 453362306a36Sopenharmony_ci 453462306a36Sopenharmony_ci ret = cma_modify_qp_rts(id_priv, conn_param); 453562306a36Sopenharmony_ci if (ret) 453662306a36Sopenharmony_ci goto out; 453762306a36Sopenharmony_ci 453862306a36Sopenharmony_ci memset(&rep, 0, sizeof rep); 453962306a36Sopenharmony_ci rep.qp_num = id_priv->qp_num; 454062306a36Sopenharmony_ci rep.starting_psn = id_priv->seq_num; 454162306a36Sopenharmony_ci rep.private_data = conn_param->private_data; 454262306a36Sopenharmony_ci rep.private_data_len = conn_param->private_data_len; 454362306a36Sopenharmony_ci rep.responder_resources = conn_param->responder_resources; 454462306a36Sopenharmony_ci rep.initiator_depth = conn_param->initiator_depth; 454562306a36Sopenharmony_ci rep.failover_accepted = 0; 454662306a36Sopenharmony_ci rep.flow_control = conn_param->flow_control; 454762306a36Sopenharmony_ci rep.rnr_retry_count = min_t(u8, 7, conn_param->rnr_retry_count); 454862306a36Sopenharmony_ci rep.srq = id_priv->srq ? 1 : 0; 454962306a36Sopenharmony_ci rep.ece.vendor_id = id_priv->ece.vendor_id; 455062306a36Sopenharmony_ci rep.ece.attr_mod = id_priv->ece.attr_mod; 455162306a36Sopenharmony_ci 455262306a36Sopenharmony_ci trace_cm_send_rep(id_priv); 455362306a36Sopenharmony_ci ret = ib_send_cm_rep(id_priv->cm_id.ib, &rep); 455462306a36Sopenharmony_ciout: 455562306a36Sopenharmony_ci return ret; 455662306a36Sopenharmony_ci} 455762306a36Sopenharmony_ci 455862306a36Sopenharmony_cistatic int cma_accept_iw(struct rdma_id_private *id_priv, 455962306a36Sopenharmony_ci struct rdma_conn_param *conn_param) 456062306a36Sopenharmony_ci{ 456162306a36Sopenharmony_ci struct iw_cm_conn_param iw_param; 456262306a36Sopenharmony_ci int ret; 456362306a36Sopenharmony_ci 456462306a36Sopenharmony_ci if (!conn_param) 456562306a36Sopenharmony_ci return -EINVAL; 456662306a36Sopenharmony_ci 456762306a36Sopenharmony_ci ret = cma_modify_qp_rtr(id_priv, conn_param); 456862306a36Sopenharmony_ci if (ret) 456962306a36Sopenharmony_ci return ret; 457062306a36Sopenharmony_ci 457162306a36Sopenharmony_ci iw_param.ord = conn_param->initiator_depth; 457262306a36Sopenharmony_ci iw_param.ird = conn_param->responder_resources; 457362306a36Sopenharmony_ci iw_param.private_data = conn_param->private_data; 457462306a36Sopenharmony_ci iw_param.private_data_len = conn_param->private_data_len; 457562306a36Sopenharmony_ci if (id_priv->id.qp) 457662306a36Sopenharmony_ci iw_param.qpn = id_priv->qp_num; 457762306a36Sopenharmony_ci else 457862306a36Sopenharmony_ci iw_param.qpn = conn_param->qp_num; 457962306a36Sopenharmony_ci 458062306a36Sopenharmony_ci return iw_cm_accept(id_priv->cm_id.iw, &iw_param); 458162306a36Sopenharmony_ci} 458262306a36Sopenharmony_ci 458362306a36Sopenharmony_cistatic int cma_send_sidr_rep(struct rdma_id_private *id_priv, 458462306a36Sopenharmony_ci enum ib_cm_sidr_status status, u32 qkey, 458562306a36Sopenharmony_ci const void *private_data, int private_data_len) 458662306a36Sopenharmony_ci{ 458762306a36Sopenharmony_ci struct ib_cm_sidr_rep_param rep; 458862306a36Sopenharmony_ci int ret; 458962306a36Sopenharmony_ci 459062306a36Sopenharmony_ci memset(&rep, 0, sizeof rep); 459162306a36Sopenharmony_ci rep.status = status; 459262306a36Sopenharmony_ci if (status == IB_SIDR_SUCCESS) { 459362306a36Sopenharmony_ci if (qkey) 459462306a36Sopenharmony_ci ret = cma_set_qkey(id_priv, qkey); 459562306a36Sopenharmony_ci else 459662306a36Sopenharmony_ci ret = cma_set_default_qkey(id_priv); 459762306a36Sopenharmony_ci if (ret) 459862306a36Sopenharmony_ci return ret; 459962306a36Sopenharmony_ci rep.qp_num = id_priv->qp_num; 460062306a36Sopenharmony_ci rep.qkey = id_priv->qkey; 460162306a36Sopenharmony_ci 460262306a36Sopenharmony_ci rep.ece.vendor_id = id_priv->ece.vendor_id; 460362306a36Sopenharmony_ci rep.ece.attr_mod = id_priv->ece.attr_mod; 460462306a36Sopenharmony_ci } 460562306a36Sopenharmony_ci 460662306a36Sopenharmony_ci rep.private_data = private_data; 460762306a36Sopenharmony_ci rep.private_data_len = private_data_len; 460862306a36Sopenharmony_ci 460962306a36Sopenharmony_ci trace_cm_send_sidr_rep(id_priv); 461062306a36Sopenharmony_ci return ib_send_cm_sidr_rep(id_priv->cm_id.ib, &rep); 461162306a36Sopenharmony_ci} 461262306a36Sopenharmony_ci 461362306a36Sopenharmony_ci/** 461462306a36Sopenharmony_ci * rdma_accept - Called to accept a connection request or response. 461562306a36Sopenharmony_ci * @id: Connection identifier associated with the request. 461662306a36Sopenharmony_ci * @conn_param: Information needed to establish the connection. This must be 461762306a36Sopenharmony_ci * provided if accepting a connection request. If accepting a connection 461862306a36Sopenharmony_ci * response, this parameter must be NULL. 461962306a36Sopenharmony_ci * 462062306a36Sopenharmony_ci * Typically, this routine is only called by the listener to accept a connection 462162306a36Sopenharmony_ci * request. It must also be called on the active side of a connection if the 462262306a36Sopenharmony_ci * user is performing their own QP transitions. 462362306a36Sopenharmony_ci * 462462306a36Sopenharmony_ci * In the case of error, a reject message is sent to the remote side and the 462562306a36Sopenharmony_ci * state of the qp associated with the id is modified to error, such that any 462662306a36Sopenharmony_ci * previously posted receive buffers would be flushed. 462762306a36Sopenharmony_ci * 462862306a36Sopenharmony_ci * This function is for use by kernel ULPs and must be called from under the 462962306a36Sopenharmony_ci * handler callback. 463062306a36Sopenharmony_ci */ 463162306a36Sopenharmony_ciint rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param) 463262306a36Sopenharmony_ci{ 463362306a36Sopenharmony_ci struct rdma_id_private *id_priv = 463462306a36Sopenharmony_ci container_of(id, struct rdma_id_private, id); 463562306a36Sopenharmony_ci int ret; 463662306a36Sopenharmony_ci 463762306a36Sopenharmony_ci lockdep_assert_held(&id_priv->handler_mutex); 463862306a36Sopenharmony_ci 463962306a36Sopenharmony_ci if (READ_ONCE(id_priv->state) != RDMA_CM_CONNECT) 464062306a36Sopenharmony_ci return -EINVAL; 464162306a36Sopenharmony_ci 464262306a36Sopenharmony_ci if (!id->qp && conn_param) { 464362306a36Sopenharmony_ci id_priv->qp_num = conn_param->qp_num; 464462306a36Sopenharmony_ci id_priv->srq = conn_param->srq; 464562306a36Sopenharmony_ci } 464662306a36Sopenharmony_ci 464762306a36Sopenharmony_ci if (rdma_cap_ib_cm(id->device, id->port_num)) { 464862306a36Sopenharmony_ci if (id->qp_type == IB_QPT_UD) { 464962306a36Sopenharmony_ci if (conn_param) 465062306a36Sopenharmony_ci ret = cma_send_sidr_rep(id_priv, IB_SIDR_SUCCESS, 465162306a36Sopenharmony_ci conn_param->qkey, 465262306a36Sopenharmony_ci conn_param->private_data, 465362306a36Sopenharmony_ci conn_param->private_data_len); 465462306a36Sopenharmony_ci else 465562306a36Sopenharmony_ci ret = cma_send_sidr_rep(id_priv, IB_SIDR_SUCCESS, 465662306a36Sopenharmony_ci 0, NULL, 0); 465762306a36Sopenharmony_ci } else { 465862306a36Sopenharmony_ci if (conn_param) 465962306a36Sopenharmony_ci ret = cma_accept_ib(id_priv, conn_param); 466062306a36Sopenharmony_ci else 466162306a36Sopenharmony_ci ret = cma_rep_recv(id_priv); 466262306a36Sopenharmony_ci } 466362306a36Sopenharmony_ci } else if (rdma_cap_iw_cm(id->device, id->port_num)) { 466462306a36Sopenharmony_ci ret = cma_accept_iw(id_priv, conn_param); 466562306a36Sopenharmony_ci } else { 466662306a36Sopenharmony_ci ret = -ENOSYS; 466762306a36Sopenharmony_ci } 466862306a36Sopenharmony_ci if (ret) 466962306a36Sopenharmony_ci goto reject; 467062306a36Sopenharmony_ci 467162306a36Sopenharmony_ci return 0; 467262306a36Sopenharmony_cireject: 467362306a36Sopenharmony_ci cma_modify_qp_err(id_priv); 467462306a36Sopenharmony_ci rdma_reject(id, NULL, 0, IB_CM_REJ_CONSUMER_DEFINED); 467562306a36Sopenharmony_ci return ret; 467662306a36Sopenharmony_ci} 467762306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_accept); 467862306a36Sopenharmony_ci 467962306a36Sopenharmony_ciint rdma_accept_ece(struct rdma_cm_id *id, struct rdma_conn_param *conn_param, 468062306a36Sopenharmony_ci struct rdma_ucm_ece *ece) 468162306a36Sopenharmony_ci{ 468262306a36Sopenharmony_ci struct rdma_id_private *id_priv = 468362306a36Sopenharmony_ci container_of(id, struct rdma_id_private, id); 468462306a36Sopenharmony_ci 468562306a36Sopenharmony_ci id_priv->ece.vendor_id = ece->vendor_id; 468662306a36Sopenharmony_ci id_priv->ece.attr_mod = ece->attr_mod; 468762306a36Sopenharmony_ci 468862306a36Sopenharmony_ci return rdma_accept(id, conn_param); 468962306a36Sopenharmony_ci} 469062306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_accept_ece); 469162306a36Sopenharmony_ci 469262306a36Sopenharmony_civoid rdma_lock_handler(struct rdma_cm_id *id) 469362306a36Sopenharmony_ci{ 469462306a36Sopenharmony_ci struct rdma_id_private *id_priv = 469562306a36Sopenharmony_ci container_of(id, struct rdma_id_private, id); 469662306a36Sopenharmony_ci 469762306a36Sopenharmony_ci mutex_lock(&id_priv->handler_mutex); 469862306a36Sopenharmony_ci} 469962306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_lock_handler); 470062306a36Sopenharmony_ci 470162306a36Sopenharmony_civoid rdma_unlock_handler(struct rdma_cm_id *id) 470262306a36Sopenharmony_ci{ 470362306a36Sopenharmony_ci struct rdma_id_private *id_priv = 470462306a36Sopenharmony_ci container_of(id, struct rdma_id_private, id); 470562306a36Sopenharmony_ci 470662306a36Sopenharmony_ci mutex_unlock(&id_priv->handler_mutex); 470762306a36Sopenharmony_ci} 470862306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_unlock_handler); 470962306a36Sopenharmony_ci 471062306a36Sopenharmony_ciint rdma_notify(struct rdma_cm_id *id, enum ib_event_type event) 471162306a36Sopenharmony_ci{ 471262306a36Sopenharmony_ci struct rdma_id_private *id_priv; 471362306a36Sopenharmony_ci int ret; 471462306a36Sopenharmony_ci 471562306a36Sopenharmony_ci id_priv = container_of(id, struct rdma_id_private, id); 471662306a36Sopenharmony_ci if (!id_priv->cm_id.ib) 471762306a36Sopenharmony_ci return -EINVAL; 471862306a36Sopenharmony_ci 471962306a36Sopenharmony_ci switch (id->device->node_type) { 472062306a36Sopenharmony_ci case RDMA_NODE_IB_CA: 472162306a36Sopenharmony_ci ret = ib_cm_notify(id_priv->cm_id.ib, event); 472262306a36Sopenharmony_ci break; 472362306a36Sopenharmony_ci default: 472462306a36Sopenharmony_ci ret = 0; 472562306a36Sopenharmony_ci break; 472662306a36Sopenharmony_ci } 472762306a36Sopenharmony_ci return ret; 472862306a36Sopenharmony_ci} 472962306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_notify); 473062306a36Sopenharmony_ci 473162306a36Sopenharmony_ciint rdma_reject(struct rdma_cm_id *id, const void *private_data, 473262306a36Sopenharmony_ci u8 private_data_len, u8 reason) 473362306a36Sopenharmony_ci{ 473462306a36Sopenharmony_ci struct rdma_id_private *id_priv; 473562306a36Sopenharmony_ci int ret; 473662306a36Sopenharmony_ci 473762306a36Sopenharmony_ci id_priv = container_of(id, struct rdma_id_private, id); 473862306a36Sopenharmony_ci if (!id_priv->cm_id.ib) 473962306a36Sopenharmony_ci return -EINVAL; 474062306a36Sopenharmony_ci 474162306a36Sopenharmony_ci if (rdma_cap_ib_cm(id->device, id->port_num)) { 474262306a36Sopenharmony_ci if (id->qp_type == IB_QPT_UD) { 474362306a36Sopenharmony_ci ret = cma_send_sidr_rep(id_priv, IB_SIDR_REJECT, 0, 474462306a36Sopenharmony_ci private_data, private_data_len); 474562306a36Sopenharmony_ci } else { 474662306a36Sopenharmony_ci trace_cm_send_rej(id_priv); 474762306a36Sopenharmony_ci ret = ib_send_cm_rej(id_priv->cm_id.ib, reason, NULL, 0, 474862306a36Sopenharmony_ci private_data, private_data_len); 474962306a36Sopenharmony_ci } 475062306a36Sopenharmony_ci } else if (rdma_cap_iw_cm(id->device, id->port_num)) { 475162306a36Sopenharmony_ci ret = iw_cm_reject(id_priv->cm_id.iw, 475262306a36Sopenharmony_ci private_data, private_data_len); 475362306a36Sopenharmony_ci } else { 475462306a36Sopenharmony_ci ret = -ENOSYS; 475562306a36Sopenharmony_ci } 475662306a36Sopenharmony_ci 475762306a36Sopenharmony_ci return ret; 475862306a36Sopenharmony_ci} 475962306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_reject); 476062306a36Sopenharmony_ci 476162306a36Sopenharmony_ciint rdma_disconnect(struct rdma_cm_id *id) 476262306a36Sopenharmony_ci{ 476362306a36Sopenharmony_ci struct rdma_id_private *id_priv; 476462306a36Sopenharmony_ci int ret; 476562306a36Sopenharmony_ci 476662306a36Sopenharmony_ci id_priv = container_of(id, struct rdma_id_private, id); 476762306a36Sopenharmony_ci if (!id_priv->cm_id.ib) 476862306a36Sopenharmony_ci return -EINVAL; 476962306a36Sopenharmony_ci 477062306a36Sopenharmony_ci if (rdma_cap_ib_cm(id->device, id->port_num)) { 477162306a36Sopenharmony_ci ret = cma_modify_qp_err(id_priv); 477262306a36Sopenharmony_ci if (ret) 477362306a36Sopenharmony_ci goto out; 477462306a36Sopenharmony_ci /* Initiate or respond to a disconnect. */ 477562306a36Sopenharmony_ci trace_cm_disconnect(id_priv); 477662306a36Sopenharmony_ci if (ib_send_cm_dreq(id_priv->cm_id.ib, NULL, 0)) { 477762306a36Sopenharmony_ci if (!ib_send_cm_drep(id_priv->cm_id.ib, NULL, 0)) 477862306a36Sopenharmony_ci trace_cm_sent_drep(id_priv); 477962306a36Sopenharmony_ci } else { 478062306a36Sopenharmony_ci trace_cm_sent_dreq(id_priv); 478162306a36Sopenharmony_ci } 478262306a36Sopenharmony_ci } else if (rdma_cap_iw_cm(id->device, id->port_num)) { 478362306a36Sopenharmony_ci ret = iw_cm_disconnect(id_priv->cm_id.iw, 0); 478462306a36Sopenharmony_ci } else 478562306a36Sopenharmony_ci ret = -EINVAL; 478662306a36Sopenharmony_ci 478762306a36Sopenharmony_ciout: 478862306a36Sopenharmony_ci return ret; 478962306a36Sopenharmony_ci} 479062306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_disconnect); 479162306a36Sopenharmony_ci 479262306a36Sopenharmony_cistatic void cma_make_mc_event(int status, struct rdma_id_private *id_priv, 479362306a36Sopenharmony_ci struct ib_sa_multicast *multicast, 479462306a36Sopenharmony_ci struct rdma_cm_event *event, 479562306a36Sopenharmony_ci struct cma_multicast *mc) 479662306a36Sopenharmony_ci{ 479762306a36Sopenharmony_ci struct rdma_dev_addr *dev_addr; 479862306a36Sopenharmony_ci enum ib_gid_type gid_type; 479962306a36Sopenharmony_ci struct net_device *ndev; 480062306a36Sopenharmony_ci 480162306a36Sopenharmony_ci if (status) 480262306a36Sopenharmony_ci pr_debug_ratelimited("RDMA CM: MULTICAST_ERROR: failed to join multicast. status %d\n", 480362306a36Sopenharmony_ci status); 480462306a36Sopenharmony_ci 480562306a36Sopenharmony_ci event->status = status; 480662306a36Sopenharmony_ci event->param.ud.private_data = mc->context; 480762306a36Sopenharmony_ci if (status) { 480862306a36Sopenharmony_ci event->event = RDMA_CM_EVENT_MULTICAST_ERROR; 480962306a36Sopenharmony_ci return; 481062306a36Sopenharmony_ci } 481162306a36Sopenharmony_ci 481262306a36Sopenharmony_ci dev_addr = &id_priv->id.route.addr.dev_addr; 481362306a36Sopenharmony_ci ndev = dev_get_by_index(dev_addr->net, dev_addr->bound_dev_if); 481462306a36Sopenharmony_ci gid_type = 481562306a36Sopenharmony_ci id_priv->cma_dev 481662306a36Sopenharmony_ci ->default_gid_type[id_priv->id.port_num - 481762306a36Sopenharmony_ci rdma_start_port( 481862306a36Sopenharmony_ci id_priv->cma_dev->device)]; 481962306a36Sopenharmony_ci 482062306a36Sopenharmony_ci event->event = RDMA_CM_EVENT_MULTICAST_JOIN; 482162306a36Sopenharmony_ci if (ib_init_ah_from_mcmember(id_priv->id.device, id_priv->id.port_num, 482262306a36Sopenharmony_ci &multicast->rec, ndev, gid_type, 482362306a36Sopenharmony_ci &event->param.ud.ah_attr)) { 482462306a36Sopenharmony_ci event->event = RDMA_CM_EVENT_MULTICAST_ERROR; 482562306a36Sopenharmony_ci goto out; 482662306a36Sopenharmony_ci } 482762306a36Sopenharmony_ci 482862306a36Sopenharmony_ci event->param.ud.qp_num = 0xFFFFFF; 482962306a36Sopenharmony_ci event->param.ud.qkey = id_priv->qkey; 483062306a36Sopenharmony_ci 483162306a36Sopenharmony_ciout: 483262306a36Sopenharmony_ci dev_put(ndev); 483362306a36Sopenharmony_ci} 483462306a36Sopenharmony_ci 483562306a36Sopenharmony_cistatic int cma_ib_mc_handler(int status, struct ib_sa_multicast *multicast) 483662306a36Sopenharmony_ci{ 483762306a36Sopenharmony_ci struct cma_multicast *mc = multicast->context; 483862306a36Sopenharmony_ci struct rdma_id_private *id_priv = mc->id_priv; 483962306a36Sopenharmony_ci struct rdma_cm_event event = {}; 484062306a36Sopenharmony_ci int ret = 0; 484162306a36Sopenharmony_ci 484262306a36Sopenharmony_ci mutex_lock(&id_priv->handler_mutex); 484362306a36Sopenharmony_ci if (READ_ONCE(id_priv->state) == RDMA_CM_DEVICE_REMOVAL || 484462306a36Sopenharmony_ci READ_ONCE(id_priv->state) == RDMA_CM_DESTROYING) 484562306a36Sopenharmony_ci goto out; 484662306a36Sopenharmony_ci 484762306a36Sopenharmony_ci ret = cma_set_qkey(id_priv, be32_to_cpu(multicast->rec.qkey)); 484862306a36Sopenharmony_ci if (!ret) { 484962306a36Sopenharmony_ci cma_make_mc_event(status, id_priv, multicast, &event, mc); 485062306a36Sopenharmony_ci ret = cma_cm_event_handler(id_priv, &event); 485162306a36Sopenharmony_ci } 485262306a36Sopenharmony_ci rdma_destroy_ah_attr(&event.param.ud.ah_attr); 485362306a36Sopenharmony_ci WARN_ON(ret); 485462306a36Sopenharmony_ci 485562306a36Sopenharmony_ciout: 485662306a36Sopenharmony_ci mutex_unlock(&id_priv->handler_mutex); 485762306a36Sopenharmony_ci return 0; 485862306a36Sopenharmony_ci} 485962306a36Sopenharmony_ci 486062306a36Sopenharmony_cistatic void cma_set_mgid(struct rdma_id_private *id_priv, 486162306a36Sopenharmony_ci struct sockaddr *addr, union ib_gid *mgid) 486262306a36Sopenharmony_ci{ 486362306a36Sopenharmony_ci unsigned char mc_map[MAX_ADDR_LEN]; 486462306a36Sopenharmony_ci struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 486562306a36Sopenharmony_ci struct sockaddr_in *sin = (struct sockaddr_in *) addr; 486662306a36Sopenharmony_ci struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) addr; 486762306a36Sopenharmony_ci 486862306a36Sopenharmony_ci if (cma_any_addr(addr)) { 486962306a36Sopenharmony_ci memset(mgid, 0, sizeof *mgid); 487062306a36Sopenharmony_ci } else if ((addr->sa_family == AF_INET6) && 487162306a36Sopenharmony_ci ((be32_to_cpu(sin6->sin6_addr.s6_addr32[0]) & 0xFFF0FFFF) == 487262306a36Sopenharmony_ci 0xFF10A01B)) { 487362306a36Sopenharmony_ci /* IPv6 address is an SA assigned MGID. */ 487462306a36Sopenharmony_ci memcpy(mgid, &sin6->sin6_addr, sizeof *mgid); 487562306a36Sopenharmony_ci } else if (addr->sa_family == AF_IB) { 487662306a36Sopenharmony_ci memcpy(mgid, &((struct sockaddr_ib *) addr)->sib_addr, sizeof *mgid); 487762306a36Sopenharmony_ci } else if (addr->sa_family == AF_INET6) { 487862306a36Sopenharmony_ci ipv6_ib_mc_map(&sin6->sin6_addr, dev_addr->broadcast, mc_map); 487962306a36Sopenharmony_ci if (id_priv->id.ps == RDMA_PS_UDP) 488062306a36Sopenharmony_ci mc_map[7] = 0x01; /* Use RDMA CM signature */ 488162306a36Sopenharmony_ci *mgid = *(union ib_gid *) (mc_map + 4); 488262306a36Sopenharmony_ci } else { 488362306a36Sopenharmony_ci ip_ib_mc_map(sin->sin_addr.s_addr, dev_addr->broadcast, mc_map); 488462306a36Sopenharmony_ci if (id_priv->id.ps == RDMA_PS_UDP) 488562306a36Sopenharmony_ci mc_map[7] = 0x01; /* Use RDMA CM signature */ 488662306a36Sopenharmony_ci *mgid = *(union ib_gid *) (mc_map + 4); 488762306a36Sopenharmony_ci } 488862306a36Sopenharmony_ci} 488962306a36Sopenharmony_ci 489062306a36Sopenharmony_cistatic int cma_join_ib_multicast(struct rdma_id_private *id_priv, 489162306a36Sopenharmony_ci struct cma_multicast *mc) 489262306a36Sopenharmony_ci{ 489362306a36Sopenharmony_ci struct ib_sa_mcmember_rec rec; 489462306a36Sopenharmony_ci struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 489562306a36Sopenharmony_ci ib_sa_comp_mask comp_mask; 489662306a36Sopenharmony_ci int ret; 489762306a36Sopenharmony_ci 489862306a36Sopenharmony_ci ib_addr_get_mgid(dev_addr, &rec.mgid); 489962306a36Sopenharmony_ci ret = ib_sa_get_mcmember_rec(id_priv->id.device, id_priv->id.port_num, 490062306a36Sopenharmony_ci &rec.mgid, &rec); 490162306a36Sopenharmony_ci if (ret) 490262306a36Sopenharmony_ci return ret; 490362306a36Sopenharmony_ci 490462306a36Sopenharmony_ci if (!id_priv->qkey) { 490562306a36Sopenharmony_ci ret = cma_set_default_qkey(id_priv); 490662306a36Sopenharmony_ci if (ret) 490762306a36Sopenharmony_ci return ret; 490862306a36Sopenharmony_ci } 490962306a36Sopenharmony_ci 491062306a36Sopenharmony_ci cma_set_mgid(id_priv, (struct sockaddr *) &mc->addr, &rec.mgid); 491162306a36Sopenharmony_ci rec.qkey = cpu_to_be32(id_priv->qkey); 491262306a36Sopenharmony_ci rdma_addr_get_sgid(dev_addr, &rec.port_gid); 491362306a36Sopenharmony_ci rec.pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr)); 491462306a36Sopenharmony_ci rec.join_state = mc->join_state; 491562306a36Sopenharmony_ci 491662306a36Sopenharmony_ci comp_mask = IB_SA_MCMEMBER_REC_MGID | IB_SA_MCMEMBER_REC_PORT_GID | 491762306a36Sopenharmony_ci IB_SA_MCMEMBER_REC_PKEY | IB_SA_MCMEMBER_REC_JOIN_STATE | 491862306a36Sopenharmony_ci IB_SA_MCMEMBER_REC_QKEY | IB_SA_MCMEMBER_REC_SL | 491962306a36Sopenharmony_ci IB_SA_MCMEMBER_REC_FLOW_LABEL | 492062306a36Sopenharmony_ci IB_SA_MCMEMBER_REC_TRAFFIC_CLASS; 492162306a36Sopenharmony_ci 492262306a36Sopenharmony_ci if (id_priv->id.ps == RDMA_PS_IPOIB) 492362306a36Sopenharmony_ci comp_mask |= IB_SA_MCMEMBER_REC_RATE | 492462306a36Sopenharmony_ci IB_SA_MCMEMBER_REC_RATE_SELECTOR | 492562306a36Sopenharmony_ci IB_SA_MCMEMBER_REC_MTU_SELECTOR | 492662306a36Sopenharmony_ci IB_SA_MCMEMBER_REC_MTU | 492762306a36Sopenharmony_ci IB_SA_MCMEMBER_REC_HOP_LIMIT; 492862306a36Sopenharmony_ci 492962306a36Sopenharmony_ci mc->sa_mc = ib_sa_join_multicast(&sa_client, id_priv->id.device, 493062306a36Sopenharmony_ci id_priv->id.port_num, &rec, comp_mask, 493162306a36Sopenharmony_ci GFP_KERNEL, cma_ib_mc_handler, mc); 493262306a36Sopenharmony_ci return PTR_ERR_OR_ZERO(mc->sa_mc); 493362306a36Sopenharmony_ci} 493462306a36Sopenharmony_ci 493562306a36Sopenharmony_cistatic void cma_iboe_set_mgid(struct sockaddr *addr, union ib_gid *mgid, 493662306a36Sopenharmony_ci enum ib_gid_type gid_type) 493762306a36Sopenharmony_ci{ 493862306a36Sopenharmony_ci struct sockaddr_in *sin = (struct sockaddr_in *)addr; 493962306a36Sopenharmony_ci struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr; 494062306a36Sopenharmony_ci 494162306a36Sopenharmony_ci if (cma_any_addr(addr)) { 494262306a36Sopenharmony_ci memset(mgid, 0, sizeof *mgid); 494362306a36Sopenharmony_ci } else if (addr->sa_family == AF_INET6) { 494462306a36Sopenharmony_ci memcpy(mgid, &sin6->sin6_addr, sizeof *mgid); 494562306a36Sopenharmony_ci } else { 494662306a36Sopenharmony_ci mgid->raw[0] = 494762306a36Sopenharmony_ci (gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) ? 0 : 0xff; 494862306a36Sopenharmony_ci mgid->raw[1] = 494962306a36Sopenharmony_ci (gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) ? 0 : 0x0e; 495062306a36Sopenharmony_ci mgid->raw[2] = 0; 495162306a36Sopenharmony_ci mgid->raw[3] = 0; 495262306a36Sopenharmony_ci mgid->raw[4] = 0; 495362306a36Sopenharmony_ci mgid->raw[5] = 0; 495462306a36Sopenharmony_ci mgid->raw[6] = 0; 495562306a36Sopenharmony_ci mgid->raw[7] = 0; 495662306a36Sopenharmony_ci mgid->raw[8] = 0; 495762306a36Sopenharmony_ci mgid->raw[9] = 0; 495862306a36Sopenharmony_ci mgid->raw[10] = 0xff; 495962306a36Sopenharmony_ci mgid->raw[11] = 0xff; 496062306a36Sopenharmony_ci *(__be32 *)(&mgid->raw[12]) = sin->sin_addr.s_addr; 496162306a36Sopenharmony_ci } 496262306a36Sopenharmony_ci} 496362306a36Sopenharmony_ci 496462306a36Sopenharmony_cistatic int cma_iboe_join_multicast(struct rdma_id_private *id_priv, 496562306a36Sopenharmony_ci struct cma_multicast *mc) 496662306a36Sopenharmony_ci{ 496762306a36Sopenharmony_ci struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; 496862306a36Sopenharmony_ci int err = 0; 496962306a36Sopenharmony_ci struct sockaddr *addr = (struct sockaddr *)&mc->addr; 497062306a36Sopenharmony_ci struct net_device *ndev = NULL; 497162306a36Sopenharmony_ci struct ib_sa_multicast ib = {}; 497262306a36Sopenharmony_ci enum ib_gid_type gid_type; 497362306a36Sopenharmony_ci bool send_only; 497462306a36Sopenharmony_ci 497562306a36Sopenharmony_ci send_only = mc->join_state == BIT(SENDONLY_FULLMEMBER_JOIN); 497662306a36Sopenharmony_ci 497762306a36Sopenharmony_ci if (cma_zero_addr(addr)) 497862306a36Sopenharmony_ci return -EINVAL; 497962306a36Sopenharmony_ci 498062306a36Sopenharmony_ci gid_type = id_priv->cma_dev->default_gid_type[id_priv->id.port_num - 498162306a36Sopenharmony_ci rdma_start_port(id_priv->cma_dev->device)]; 498262306a36Sopenharmony_ci cma_iboe_set_mgid(addr, &ib.rec.mgid, gid_type); 498362306a36Sopenharmony_ci 498462306a36Sopenharmony_ci ib.rec.pkey = cpu_to_be16(0xffff); 498562306a36Sopenharmony_ci if (dev_addr->bound_dev_if) 498662306a36Sopenharmony_ci ndev = dev_get_by_index(dev_addr->net, dev_addr->bound_dev_if); 498762306a36Sopenharmony_ci if (!ndev) 498862306a36Sopenharmony_ci return -ENODEV; 498962306a36Sopenharmony_ci 499062306a36Sopenharmony_ci ib.rec.rate = IB_RATE_PORT_CURRENT; 499162306a36Sopenharmony_ci ib.rec.hop_limit = 1; 499262306a36Sopenharmony_ci ib.rec.mtu = iboe_get_mtu(ndev->mtu); 499362306a36Sopenharmony_ci 499462306a36Sopenharmony_ci if (addr->sa_family == AF_INET) { 499562306a36Sopenharmony_ci if (gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) { 499662306a36Sopenharmony_ci ib.rec.hop_limit = IPV6_DEFAULT_HOPLIMIT; 499762306a36Sopenharmony_ci if (!send_only) { 499862306a36Sopenharmony_ci err = cma_igmp_send(ndev, &ib.rec.mgid, 499962306a36Sopenharmony_ci true); 500062306a36Sopenharmony_ci } 500162306a36Sopenharmony_ci } 500262306a36Sopenharmony_ci } else { 500362306a36Sopenharmony_ci if (gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) 500462306a36Sopenharmony_ci err = -ENOTSUPP; 500562306a36Sopenharmony_ci } 500662306a36Sopenharmony_ci dev_put(ndev); 500762306a36Sopenharmony_ci if (err || !ib.rec.mtu) 500862306a36Sopenharmony_ci return err ?: -EINVAL; 500962306a36Sopenharmony_ci 501062306a36Sopenharmony_ci if (!id_priv->qkey) 501162306a36Sopenharmony_ci cma_set_default_qkey(id_priv); 501262306a36Sopenharmony_ci 501362306a36Sopenharmony_ci rdma_ip2gid((struct sockaddr *)&id_priv->id.route.addr.src_addr, 501462306a36Sopenharmony_ci &ib.rec.port_gid); 501562306a36Sopenharmony_ci INIT_WORK(&mc->iboe_join.work, cma_iboe_join_work_handler); 501662306a36Sopenharmony_ci cma_make_mc_event(0, id_priv, &ib, &mc->iboe_join.event, mc); 501762306a36Sopenharmony_ci queue_work(cma_wq, &mc->iboe_join.work); 501862306a36Sopenharmony_ci return 0; 501962306a36Sopenharmony_ci} 502062306a36Sopenharmony_ci 502162306a36Sopenharmony_ciint rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr, 502262306a36Sopenharmony_ci u8 join_state, void *context) 502362306a36Sopenharmony_ci{ 502462306a36Sopenharmony_ci struct rdma_id_private *id_priv = 502562306a36Sopenharmony_ci container_of(id, struct rdma_id_private, id); 502662306a36Sopenharmony_ci struct cma_multicast *mc; 502762306a36Sopenharmony_ci int ret; 502862306a36Sopenharmony_ci 502962306a36Sopenharmony_ci /* Not supported for kernel QPs */ 503062306a36Sopenharmony_ci if (WARN_ON(id->qp)) 503162306a36Sopenharmony_ci return -EINVAL; 503262306a36Sopenharmony_ci 503362306a36Sopenharmony_ci /* ULP is calling this wrong. */ 503462306a36Sopenharmony_ci if (!id->device || (READ_ONCE(id_priv->state) != RDMA_CM_ADDR_BOUND && 503562306a36Sopenharmony_ci READ_ONCE(id_priv->state) != RDMA_CM_ADDR_RESOLVED)) 503662306a36Sopenharmony_ci return -EINVAL; 503762306a36Sopenharmony_ci 503862306a36Sopenharmony_ci if (id_priv->id.qp_type != IB_QPT_UD) 503962306a36Sopenharmony_ci return -EINVAL; 504062306a36Sopenharmony_ci 504162306a36Sopenharmony_ci mc = kzalloc(sizeof(*mc), GFP_KERNEL); 504262306a36Sopenharmony_ci if (!mc) 504362306a36Sopenharmony_ci return -ENOMEM; 504462306a36Sopenharmony_ci 504562306a36Sopenharmony_ci memcpy(&mc->addr, addr, rdma_addr_size(addr)); 504662306a36Sopenharmony_ci mc->context = context; 504762306a36Sopenharmony_ci mc->id_priv = id_priv; 504862306a36Sopenharmony_ci mc->join_state = join_state; 504962306a36Sopenharmony_ci 505062306a36Sopenharmony_ci if (rdma_protocol_roce(id->device, id->port_num)) { 505162306a36Sopenharmony_ci ret = cma_iboe_join_multicast(id_priv, mc); 505262306a36Sopenharmony_ci if (ret) 505362306a36Sopenharmony_ci goto out_err; 505462306a36Sopenharmony_ci } else if (rdma_cap_ib_mcast(id->device, id->port_num)) { 505562306a36Sopenharmony_ci ret = cma_join_ib_multicast(id_priv, mc); 505662306a36Sopenharmony_ci if (ret) 505762306a36Sopenharmony_ci goto out_err; 505862306a36Sopenharmony_ci } else { 505962306a36Sopenharmony_ci ret = -ENOSYS; 506062306a36Sopenharmony_ci goto out_err; 506162306a36Sopenharmony_ci } 506262306a36Sopenharmony_ci 506362306a36Sopenharmony_ci spin_lock(&id_priv->lock); 506462306a36Sopenharmony_ci list_add(&mc->list, &id_priv->mc_list); 506562306a36Sopenharmony_ci spin_unlock(&id_priv->lock); 506662306a36Sopenharmony_ci 506762306a36Sopenharmony_ci return 0; 506862306a36Sopenharmony_ciout_err: 506962306a36Sopenharmony_ci kfree(mc); 507062306a36Sopenharmony_ci return ret; 507162306a36Sopenharmony_ci} 507262306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_join_multicast); 507362306a36Sopenharmony_ci 507462306a36Sopenharmony_civoid rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr) 507562306a36Sopenharmony_ci{ 507662306a36Sopenharmony_ci struct rdma_id_private *id_priv; 507762306a36Sopenharmony_ci struct cma_multicast *mc; 507862306a36Sopenharmony_ci 507962306a36Sopenharmony_ci id_priv = container_of(id, struct rdma_id_private, id); 508062306a36Sopenharmony_ci spin_lock_irq(&id_priv->lock); 508162306a36Sopenharmony_ci list_for_each_entry(mc, &id_priv->mc_list, list) { 508262306a36Sopenharmony_ci if (memcmp(&mc->addr, addr, rdma_addr_size(addr)) != 0) 508362306a36Sopenharmony_ci continue; 508462306a36Sopenharmony_ci list_del(&mc->list); 508562306a36Sopenharmony_ci spin_unlock_irq(&id_priv->lock); 508662306a36Sopenharmony_ci 508762306a36Sopenharmony_ci WARN_ON(id_priv->cma_dev->device != id->device); 508862306a36Sopenharmony_ci destroy_mc(id_priv, mc); 508962306a36Sopenharmony_ci return; 509062306a36Sopenharmony_ci } 509162306a36Sopenharmony_ci spin_unlock_irq(&id_priv->lock); 509262306a36Sopenharmony_ci} 509362306a36Sopenharmony_ciEXPORT_SYMBOL(rdma_leave_multicast); 509462306a36Sopenharmony_ci 509562306a36Sopenharmony_cistatic int cma_netdev_change(struct net_device *ndev, struct rdma_id_private *id_priv) 509662306a36Sopenharmony_ci{ 509762306a36Sopenharmony_ci struct rdma_dev_addr *dev_addr; 509862306a36Sopenharmony_ci struct cma_work *work; 509962306a36Sopenharmony_ci 510062306a36Sopenharmony_ci dev_addr = &id_priv->id.route.addr.dev_addr; 510162306a36Sopenharmony_ci 510262306a36Sopenharmony_ci if ((dev_addr->bound_dev_if == ndev->ifindex) && 510362306a36Sopenharmony_ci (net_eq(dev_net(ndev), dev_addr->net)) && 510462306a36Sopenharmony_ci memcmp(dev_addr->src_dev_addr, ndev->dev_addr, ndev->addr_len)) { 510562306a36Sopenharmony_ci pr_info("RDMA CM addr change for ndev %s used by id %p\n", 510662306a36Sopenharmony_ci ndev->name, &id_priv->id); 510762306a36Sopenharmony_ci work = kzalloc(sizeof *work, GFP_KERNEL); 510862306a36Sopenharmony_ci if (!work) 510962306a36Sopenharmony_ci return -ENOMEM; 511062306a36Sopenharmony_ci 511162306a36Sopenharmony_ci INIT_WORK(&work->work, cma_work_handler); 511262306a36Sopenharmony_ci work->id = id_priv; 511362306a36Sopenharmony_ci work->event.event = RDMA_CM_EVENT_ADDR_CHANGE; 511462306a36Sopenharmony_ci cma_id_get(id_priv); 511562306a36Sopenharmony_ci queue_work(cma_wq, &work->work); 511662306a36Sopenharmony_ci } 511762306a36Sopenharmony_ci 511862306a36Sopenharmony_ci return 0; 511962306a36Sopenharmony_ci} 512062306a36Sopenharmony_ci 512162306a36Sopenharmony_cistatic int cma_netdev_callback(struct notifier_block *self, unsigned long event, 512262306a36Sopenharmony_ci void *ptr) 512362306a36Sopenharmony_ci{ 512462306a36Sopenharmony_ci struct net_device *ndev = netdev_notifier_info_to_dev(ptr); 512562306a36Sopenharmony_ci struct cma_device *cma_dev; 512662306a36Sopenharmony_ci struct rdma_id_private *id_priv; 512762306a36Sopenharmony_ci int ret = NOTIFY_DONE; 512862306a36Sopenharmony_ci 512962306a36Sopenharmony_ci if (event != NETDEV_BONDING_FAILOVER) 513062306a36Sopenharmony_ci return NOTIFY_DONE; 513162306a36Sopenharmony_ci 513262306a36Sopenharmony_ci if (!netif_is_bond_master(ndev)) 513362306a36Sopenharmony_ci return NOTIFY_DONE; 513462306a36Sopenharmony_ci 513562306a36Sopenharmony_ci mutex_lock(&lock); 513662306a36Sopenharmony_ci list_for_each_entry(cma_dev, &dev_list, list) 513762306a36Sopenharmony_ci list_for_each_entry(id_priv, &cma_dev->id_list, device_item) { 513862306a36Sopenharmony_ci ret = cma_netdev_change(ndev, id_priv); 513962306a36Sopenharmony_ci if (ret) 514062306a36Sopenharmony_ci goto out; 514162306a36Sopenharmony_ci } 514262306a36Sopenharmony_ci 514362306a36Sopenharmony_ciout: 514462306a36Sopenharmony_ci mutex_unlock(&lock); 514562306a36Sopenharmony_ci return ret; 514662306a36Sopenharmony_ci} 514762306a36Sopenharmony_ci 514862306a36Sopenharmony_cistatic void cma_netevent_work_handler(struct work_struct *_work) 514962306a36Sopenharmony_ci{ 515062306a36Sopenharmony_ci struct rdma_id_private *id_priv = 515162306a36Sopenharmony_ci container_of(_work, struct rdma_id_private, id.net_work); 515262306a36Sopenharmony_ci struct rdma_cm_event event = {}; 515362306a36Sopenharmony_ci 515462306a36Sopenharmony_ci mutex_lock(&id_priv->handler_mutex); 515562306a36Sopenharmony_ci 515662306a36Sopenharmony_ci if (READ_ONCE(id_priv->state) == RDMA_CM_DESTROYING || 515762306a36Sopenharmony_ci READ_ONCE(id_priv->state) == RDMA_CM_DEVICE_REMOVAL) 515862306a36Sopenharmony_ci goto out_unlock; 515962306a36Sopenharmony_ci 516062306a36Sopenharmony_ci event.event = RDMA_CM_EVENT_UNREACHABLE; 516162306a36Sopenharmony_ci event.status = -ETIMEDOUT; 516262306a36Sopenharmony_ci 516362306a36Sopenharmony_ci if (cma_cm_event_handler(id_priv, &event)) { 516462306a36Sopenharmony_ci __acquire(&id_priv->handler_mutex); 516562306a36Sopenharmony_ci id_priv->cm_id.ib = NULL; 516662306a36Sopenharmony_ci cma_id_put(id_priv); 516762306a36Sopenharmony_ci destroy_id_handler_unlock(id_priv); 516862306a36Sopenharmony_ci return; 516962306a36Sopenharmony_ci } 517062306a36Sopenharmony_ci 517162306a36Sopenharmony_ciout_unlock: 517262306a36Sopenharmony_ci mutex_unlock(&id_priv->handler_mutex); 517362306a36Sopenharmony_ci cma_id_put(id_priv); 517462306a36Sopenharmony_ci} 517562306a36Sopenharmony_ci 517662306a36Sopenharmony_cistatic int cma_netevent_callback(struct notifier_block *self, 517762306a36Sopenharmony_ci unsigned long event, void *ctx) 517862306a36Sopenharmony_ci{ 517962306a36Sopenharmony_ci struct id_table_entry *ips_node = NULL; 518062306a36Sopenharmony_ci struct rdma_id_private *current_id; 518162306a36Sopenharmony_ci struct neighbour *neigh = ctx; 518262306a36Sopenharmony_ci unsigned long flags; 518362306a36Sopenharmony_ci 518462306a36Sopenharmony_ci if (event != NETEVENT_NEIGH_UPDATE) 518562306a36Sopenharmony_ci return NOTIFY_DONE; 518662306a36Sopenharmony_ci 518762306a36Sopenharmony_ci spin_lock_irqsave(&id_table_lock, flags); 518862306a36Sopenharmony_ci if (neigh->tbl->family == AF_INET6) { 518962306a36Sopenharmony_ci struct sockaddr_in6 neigh_sock_6; 519062306a36Sopenharmony_ci 519162306a36Sopenharmony_ci neigh_sock_6.sin6_family = AF_INET6; 519262306a36Sopenharmony_ci neigh_sock_6.sin6_addr = *(struct in6_addr *)neigh->primary_key; 519362306a36Sopenharmony_ci ips_node = node_from_ndev_ip(&id_table, neigh->dev->ifindex, 519462306a36Sopenharmony_ci (struct sockaddr *)&neigh_sock_6); 519562306a36Sopenharmony_ci } else if (neigh->tbl->family == AF_INET) { 519662306a36Sopenharmony_ci struct sockaddr_in neigh_sock_4; 519762306a36Sopenharmony_ci 519862306a36Sopenharmony_ci neigh_sock_4.sin_family = AF_INET; 519962306a36Sopenharmony_ci neigh_sock_4.sin_addr.s_addr = *(__be32 *)(neigh->primary_key); 520062306a36Sopenharmony_ci ips_node = node_from_ndev_ip(&id_table, neigh->dev->ifindex, 520162306a36Sopenharmony_ci (struct sockaddr *)&neigh_sock_4); 520262306a36Sopenharmony_ci } else 520362306a36Sopenharmony_ci goto out; 520462306a36Sopenharmony_ci 520562306a36Sopenharmony_ci if (!ips_node) 520662306a36Sopenharmony_ci goto out; 520762306a36Sopenharmony_ci 520862306a36Sopenharmony_ci list_for_each_entry(current_id, &ips_node->id_list, id_list_entry) { 520962306a36Sopenharmony_ci if (!memcmp(current_id->id.route.addr.dev_addr.dst_dev_addr, 521062306a36Sopenharmony_ci neigh->ha, ETH_ALEN)) 521162306a36Sopenharmony_ci continue; 521262306a36Sopenharmony_ci INIT_WORK(¤t_id->id.net_work, cma_netevent_work_handler); 521362306a36Sopenharmony_ci cma_id_get(current_id); 521462306a36Sopenharmony_ci queue_work(cma_wq, ¤t_id->id.net_work); 521562306a36Sopenharmony_ci } 521662306a36Sopenharmony_ciout: 521762306a36Sopenharmony_ci spin_unlock_irqrestore(&id_table_lock, flags); 521862306a36Sopenharmony_ci return NOTIFY_DONE; 521962306a36Sopenharmony_ci} 522062306a36Sopenharmony_ci 522162306a36Sopenharmony_cistatic struct notifier_block cma_nb = { 522262306a36Sopenharmony_ci .notifier_call = cma_netdev_callback 522362306a36Sopenharmony_ci}; 522462306a36Sopenharmony_ci 522562306a36Sopenharmony_cistatic struct notifier_block cma_netevent_cb = { 522662306a36Sopenharmony_ci .notifier_call = cma_netevent_callback 522762306a36Sopenharmony_ci}; 522862306a36Sopenharmony_ci 522962306a36Sopenharmony_cistatic void cma_send_device_removal_put(struct rdma_id_private *id_priv) 523062306a36Sopenharmony_ci{ 523162306a36Sopenharmony_ci struct rdma_cm_event event = { .event = RDMA_CM_EVENT_DEVICE_REMOVAL }; 523262306a36Sopenharmony_ci enum rdma_cm_state state; 523362306a36Sopenharmony_ci unsigned long flags; 523462306a36Sopenharmony_ci 523562306a36Sopenharmony_ci mutex_lock(&id_priv->handler_mutex); 523662306a36Sopenharmony_ci /* Record that we want to remove the device */ 523762306a36Sopenharmony_ci spin_lock_irqsave(&id_priv->lock, flags); 523862306a36Sopenharmony_ci state = id_priv->state; 523962306a36Sopenharmony_ci if (state == RDMA_CM_DESTROYING || state == RDMA_CM_DEVICE_REMOVAL) { 524062306a36Sopenharmony_ci spin_unlock_irqrestore(&id_priv->lock, flags); 524162306a36Sopenharmony_ci mutex_unlock(&id_priv->handler_mutex); 524262306a36Sopenharmony_ci cma_id_put(id_priv); 524362306a36Sopenharmony_ci return; 524462306a36Sopenharmony_ci } 524562306a36Sopenharmony_ci id_priv->state = RDMA_CM_DEVICE_REMOVAL; 524662306a36Sopenharmony_ci spin_unlock_irqrestore(&id_priv->lock, flags); 524762306a36Sopenharmony_ci 524862306a36Sopenharmony_ci if (cma_cm_event_handler(id_priv, &event)) { 524962306a36Sopenharmony_ci /* 525062306a36Sopenharmony_ci * At this point the ULP promises it won't call 525162306a36Sopenharmony_ci * rdma_destroy_id() concurrently 525262306a36Sopenharmony_ci */ 525362306a36Sopenharmony_ci cma_id_put(id_priv); 525462306a36Sopenharmony_ci mutex_unlock(&id_priv->handler_mutex); 525562306a36Sopenharmony_ci trace_cm_id_destroy(id_priv); 525662306a36Sopenharmony_ci _destroy_id(id_priv, state); 525762306a36Sopenharmony_ci return; 525862306a36Sopenharmony_ci } 525962306a36Sopenharmony_ci mutex_unlock(&id_priv->handler_mutex); 526062306a36Sopenharmony_ci 526162306a36Sopenharmony_ci /* 526262306a36Sopenharmony_ci * If this races with destroy then the thread that first assigns state 526362306a36Sopenharmony_ci * to a destroying does the cancel. 526462306a36Sopenharmony_ci */ 526562306a36Sopenharmony_ci cma_cancel_operation(id_priv, state); 526662306a36Sopenharmony_ci cma_id_put(id_priv); 526762306a36Sopenharmony_ci} 526862306a36Sopenharmony_ci 526962306a36Sopenharmony_cistatic void cma_process_remove(struct cma_device *cma_dev) 527062306a36Sopenharmony_ci{ 527162306a36Sopenharmony_ci mutex_lock(&lock); 527262306a36Sopenharmony_ci while (!list_empty(&cma_dev->id_list)) { 527362306a36Sopenharmony_ci struct rdma_id_private *id_priv = list_first_entry( 527462306a36Sopenharmony_ci &cma_dev->id_list, struct rdma_id_private, device_item); 527562306a36Sopenharmony_ci 527662306a36Sopenharmony_ci list_del_init(&id_priv->listen_item); 527762306a36Sopenharmony_ci list_del_init(&id_priv->device_item); 527862306a36Sopenharmony_ci cma_id_get(id_priv); 527962306a36Sopenharmony_ci mutex_unlock(&lock); 528062306a36Sopenharmony_ci 528162306a36Sopenharmony_ci cma_send_device_removal_put(id_priv); 528262306a36Sopenharmony_ci 528362306a36Sopenharmony_ci mutex_lock(&lock); 528462306a36Sopenharmony_ci } 528562306a36Sopenharmony_ci mutex_unlock(&lock); 528662306a36Sopenharmony_ci 528762306a36Sopenharmony_ci cma_dev_put(cma_dev); 528862306a36Sopenharmony_ci wait_for_completion(&cma_dev->comp); 528962306a36Sopenharmony_ci} 529062306a36Sopenharmony_ci 529162306a36Sopenharmony_cistatic bool cma_supported(struct ib_device *device) 529262306a36Sopenharmony_ci{ 529362306a36Sopenharmony_ci u32 i; 529462306a36Sopenharmony_ci 529562306a36Sopenharmony_ci rdma_for_each_port(device, i) { 529662306a36Sopenharmony_ci if (rdma_cap_ib_cm(device, i) || rdma_cap_iw_cm(device, i)) 529762306a36Sopenharmony_ci return true; 529862306a36Sopenharmony_ci } 529962306a36Sopenharmony_ci return false; 530062306a36Sopenharmony_ci} 530162306a36Sopenharmony_ci 530262306a36Sopenharmony_cistatic int cma_add_one(struct ib_device *device) 530362306a36Sopenharmony_ci{ 530462306a36Sopenharmony_ci struct rdma_id_private *to_destroy; 530562306a36Sopenharmony_ci struct cma_device *cma_dev; 530662306a36Sopenharmony_ci struct rdma_id_private *id_priv; 530762306a36Sopenharmony_ci unsigned long supported_gids = 0; 530862306a36Sopenharmony_ci int ret; 530962306a36Sopenharmony_ci u32 i; 531062306a36Sopenharmony_ci 531162306a36Sopenharmony_ci if (!cma_supported(device)) 531262306a36Sopenharmony_ci return -EOPNOTSUPP; 531362306a36Sopenharmony_ci 531462306a36Sopenharmony_ci cma_dev = kmalloc(sizeof(*cma_dev), GFP_KERNEL); 531562306a36Sopenharmony_ci if (!cma_dev) 531662306a36Sopenharmony_ci return -ENOMEM; 531762306a36Sopenharmony_ci 531862306a36Sopenharmony_ci cma_dev->device = device; 531962306a36Sopenharmony_ci cma_dev->default_gid_type = kcalloc(device->phys_port_cnt, 532062306a36Sopenharmony_ci sizeof(*cma_dev->default_gid_type), 532162306a36Sopenharmony_ci GFP_KERNEL); 532262306a36Sopenharmony_ci if (!cma_dev->default_gid_type) { 532362306a36Sopenharmony_ci ret = -ENOMEM; 532462306a36Sopenharmony_ci goto free_cma_dev; 532562306a36Sopenharmony_ci } 532662306a36Sopenharmony_ci 532762306a36Sopenharmony_ci cma_dev->default_roce_tos = kcalloc(device->phys_port_cnt, 532862306a36Sopenharmony_ci sizeof(*cma_dev->default_roce_tos), 532962306a36Sopenharmony_ci GFP_KERNEL); 533062306a36Sopenharmony_ci if (!cma_dev->default_roce_tos) { 533162306a36Sopenharmony_ci ret = -ENOMEM; 533262306a36Sopenharmony_ci goto free_gid_type; 533362306a36Sopenharmony_ci } 533462306a36Sopenharmony_ci 533562306a36Sopenharmony_ci rdma_for_each_port (device, i) { 533662306a36Sopenharmony_ci supported_gids = roce_gid_type_mask_support(device, i); 533762306a36Sopenharmony_ci WARN_ON(!supported_gids); 533862306a36Sopenharmony_ci if (supported_gids & (1 << CMA_PREFERRED_ROCE_GID_TYPE)) 533962306a36Sopenharmony_ci cma_dev->default_gid_type[i - rdma_start_port(device)] = 534062306a36Sopenharmony_ci CMA_PREFERRED_ROCE_GID_TYPE; 534162306a36Sopenharmony_ci else 534262306a36Sopenharmony_ci cma_dev->default_gid_type[i - rdma_start_port(device)] = 534362306a36Sopenharmony_ci find_first_bit(&supported_gids, BITS_PER_LONG); 534462306a36Sopenharmony_ci cma_dev->default_roce_tos[i - rdma_start_port(device)] = 0; 534562306a36Sopenharmony_ci } 534662306a36Sopenharmony_ci 534762306a36Sopenharmony_ci init_completion(&cma_dev->comp); 534862306a36Sopenharmony_ci refcount_set(&cma_dev->refcount, 1); 534962306a36Sopenharmony_ci INIT_LIST_HEAD(&cma_dev->id_list); 535062306a36Sopenharmony_ci ib_set_client_data(device, &cma_client, cma_dev); 535162306a36Sopenharmony_ci 535262306a36Sopenharmony_ci mutex_lock(&lock); 535362306a36Sopenharmony_ci list_add_tail(&cma_dev->list, &dev_list); 535462306a36Sopenharmony_ci list_for_each_entry(id_priv, &listen_any_list, listen_any_item) { 535562306a36Sopenharmony_ci ret = cma_listen_on_dev(id_priv, cma_dev, &to_destroy); 535662306a36Sopenharmony_ci if (ret) 535762306a36Sopenharmony_ci goto free_listen; 535862306a36Sopenharmony_ci } 535962306a36Sopenharmony_ci mutex_unlock(&lock); 536062306a36Sopenharmony_ci 536162306a36Sopenharmony_ci trace_cm_add_one(device); 536262306a36Sopenharmony_ci return 0; 536362306a36Sopenharmony_ci 536462306a36Sopenharmony_cifree_listen: 536562306a36Sopenharmony_ci list_del(&cma_dev->list); 536662306a36Sopenharmony_ci mutex_unlock(&lock); 536762306a36Sopenharmony_ci 536862306a36Sopenharmony_ci /* cma_process_remove() will delete to_destroy */ 536962306a36Sopenharmony_ci cma_process_remove(cma_dev); 537062306a36Sopenharmony_ci kfree(cma_dev->default_roce_tos); 537162306a36Sopenharmony_cifree_gid_type: 537262306a36Sopenharmony_ci kfree(cma_dev->default_gid_type); 537362306a36Sopenharmony_ci 537462306a36Sopenharmony_cifree_cma_dev: 537562306a36Sopenharmony_ci kfree(cma_dev); 537662306a36Sopenharmony_ci return ret; 537762306a36Sopenharmony_ci} 537862306a36Sopenharmony_ci 537962306a36Sopenharmony_cistatic void cma_remove_one(struct ib_device *device, void *client_data) 538062306a36Sopenharmony_ci{ 538162306a36Sopenharmony_ci struct cma_device *cma_dev = client_data; 538262306a36Sopenharmony_ci 538362306a36Sopenharmony_ci trace_cm_remove_one(device); 538462306a36Sopenharmony_ci 538562306a36Sopenharmony_ci mutex_lock(&lock); 538662306a36Sopenharmony_ci list_del(&cma_dev->list); 538762306a36Sopenharmony_ci mutex_unlock(&lock); 538862306a36Sopenharmony_ci 538962306a36Sopenharmony_ci cma_process_remove(cma_dev); 539062306a36Sopenharmony_ci kfree(cma_dev->default_roce_tos); 539162306a36Sopenharmony_ci kfree(cma_dev->default_gid_type); 539262306a36Sopenharmony_ci kfree(cma_dev); 539362306a36Sopenharmony_ci} 539462306a36Sopenharmony_ci 539562306a36Sopenharmony_cistatic int cma_init_net(struct net *net) 539662306a36Sopenharmony_ci{ 539762306a36Sopenharmony_ci struct cma_pernet *pernet = cma_pernet(net); 539862306a36Sopenharmony_ci 539962306a36Sopenharmony_ci xa_init(&pernet->tcp_ps); 540062306a36Sopenharmony_ci xa_init(&pernet->udp_ps); 540162306a36Sopenharmony_ci xa_init(&pernet->ipoib_ps); 540262306a36Sopenharmony_ci xa_init(&pernet->ib_ps); 540362306a36Sopenharmony_ci 540462306a36Sopenharmony_ci return 0; 540562306a36Sopenharmony_ci} 540662306a36Sopenharmony_ci 540762306a36Sopenharmony_cistatic void cma_exit_net(struct net *net) 540862306a36Sopenharmony_ci{ 540962306a36Sopenharmony_ci struct cma_pernet *pernet = cma_pernet(net); 541062306a36Sopenharmony_ci 541162306a36Sopenharmony_ci WARN_ON(!xa_empty(&pernet->tcp_ps)); 541262306a36Sopenharmony_ci WARN_ON(!xa_empty(&pernet->udp_ps)); 541362306a36Sopenharmony_ci WARN_ON(!xa_empty(&pernet->ipoib_ps)); 541462306a36Sopenharmony_ci WARN_ON(!xa_empty(&pernet->ib_ps)); 541562306a36Sopenharmony_ci} 541662306a36Sopenharmony_ci 541762306a36Sopenharmony_cistatic struct pernet_operations cma_pernet_operations = { 541862306a36Sopenharmony_ci .init = cma_init_net, 541962306a36Sopenharmony_ci .exit = cma_exit_net, 542062306a36Sopenharmony_ci .id = &cma_pernet_id, 542162306a36Sopenharmony_ci .size = sizeof(struct cma_pernet), 542262306a36Sopenharmony_ci}; 542362306a36Sopenharmony_ci 542462306a36Sopenharmony_cistatic int __init cma_init(void) 542562306a36Sopenharmony_ci{ 542662306a36Sopenharmony_ci int ret; 542762306a36Sopenharmony_ci 542862306a36Sopenharmony_ci /* 542962306a36Sopenharmony_ci * There is a rare lock ordering dependency in cma_netdev_callback() 543062306a36Sopenharmony_ci * that only happens when bonding is enabled. Teach lockdep that rtnl 543162306a36Sopenharmony_ci * must never be nested under lock so it can find these without having 543262306a36Sopenharmony_ci * to test with bonding. 543362306a36Sopenharmony_ci */ 543462306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_LOCKDEP)) { 543562306a36Sopenharmony_ci rtnl_lock(); 543662306a36Sopenharmony_ci mutex_lock(&lock); 543762306a36Sopenharmony_ci mutex_unlock(&lock); 543862306a36Sopenharmony_ci rtnl_unlock(); 543962306a36Sopenharmony_ci } 544062306a36Sopenharmony_ci 544162306a36Sopenharmony_ci cma_wq = alloc_ordered_workqueue("rdma_cm", WQ_MEM_RECLAIM); 544262306a36Sopenharmony_ci if (!cma_wq) 544362306a36Sopenharmony_ci return -ENOMEM; 544462306a36Sopenharmony_ci 544562306a36Sopenharmony_ci ret = register_pernet_subsys(&cma_pernet_operations); 544662306a36Sopenharmony_ci if (ret) 544762306a36Sopenharmony_ci goto err_wq; 544862306a36Sopenharmony_ci 544962306a36Sopenharmony_ci ib_sa_register_client(&sa_client); 545062306a36Sopenharmony_ci register_netdevice_notifier(&cma_nb); 545162306a36Sopenharmony_ci register_netevent_notifier(&cma_netevent_cb); 545262306a36Sopenharmony_ci 545362306a36Sopenharmony_ci ret = ib_register_client(&cma_client); 545462306a36Sopenharmony_ci if (ret) 545562306a36Sopenharmony_ci goto err; 545662306a36Sopenharmony_ci 545762306a36Sopenharmony_ci ret = cma_configfs_init(); 545862306a36Sopenharmony_ci if (ret) 545962306a36Sopenharmony_ci goto err_ib; 546062306a36Sopenharmony_ci 546162306a36Sopenharmony_ci return 0; 546262306a36Sopenharmony_ci 546362306a36Sopenharmony_cierr_ib: 546462306a36Sopenharmony_ci ib_unregister_client(&cma_client); 546562306a36Sopenharmony_cierr: 546662306a36Sopenharmony_ci unregister_netevent_notifier(&cma_netevent_cb); 546762306a36Sopenharmony_ci unregister_netdevice_notifier(&cma_nb); 546862306a36Sopenharmony_ci ib_sa_unregister_client(&sa_client); 546962306a36Sopenharmony_ci unregister_pernet_subsys(&cma_pernet_operations); 547062306a36Sopenharmony_cierr_wq: 547162306a36Sopenharmony_ci destroy_workqueue(cma_wq); 547262306a36Sopenharmony_ci return ret; 547362306a36Sopenharmony_ci} 547462306a36Sopenharmony_ci 547562306a36Sopenharmony_cistatic void __exit cma_cleanup(void) 547662306a36Sopenharmony_ci{ 547762306a36Sopenharmony_ci cma_configfs_exit(); 547862306a36Sopenharmony_ci ib_unregister_client(&cma_client); 547962306a36Sopenharmony_ci unregister_netevent_notifier(&cma_netevent_cb); 548062306a36Sopenharmony_ci unregister_netdevice_notifier(&cma_nb); 548162306a36Sopenharmony_ci ib_sa_unregister_client(&sa_client); 548262306a36Sopenharmony_ci unregister_pernet_subsys(&cma_pernet_operations); 548362306a36Sopenharmony_ci destroy_workqueue(cma_wq); 548462306a36Sopenharmony_ci} 548562306a36Sopenharmony_ci 548662306a36Sopenharmony_cimodule_init(cma_init); 548762306a36Sopenharmony_cimodule_exit(cma_cleanup); 5488