cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

iwpm_util.c (22120B)


      1/*
      2 * Copyright (c) 2014 Chelsio, Inc. All rights reserved.
      3 * Copyright (c) 2014 Intel Corporation. All rights reserved.
      4 *
      5 * This software is available to you under a choice of one of two
      6 * licenses.  You may choose to be licensed under the terms of the GNU
      7 * General Public License (GPL) Version 2, available from the file
      8 * COPYING in the main directory of this source tree, or the
      9 * OpenIB.org BSD license below:
     10 *
     11 *     Redistribution and use in source and binary forms, with or
     12 *     without modification, are permitted provided that the following
     13 *     conditions are met:
     14 *
     15 *      - Redistributions of source code must retain the above
     16 *	  copyright notice, this list of conditions and the following
     17 *	  disclaimer.
     18 *
     19 *      - Redistributions in binary form must reproduce the above
     20 *	  copyright notice, this list of conditions and the following
     21 *	  disclaimer in the documentation and/or other materials
     22 *	  provided with the distribution.
     23 *
     24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
     28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
     29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     31 * SOFTWARE.
     32 */
     33
     34#include "iwpm_util.h"
     35
     36#define IWPM_MAPINFO_HASH_SIZE	512
     37#define IWPM_MAPINFO_HASH_MASK	(IWPM_MAPINFO_HASH_SIZE - 1)
     38#define IWPM_REMINFO_HASH_SIZE	64
     39#define IWPM_REMINFO_HASH_MASK	(IWPM_REMINFO_HASH_SIZE - 1)
     40#define IWPM_MSG_SIZE		512
     41
     42static LIST_HEAD(iwpm_nlmsg_req_list);
     43static DEFINE_SPINLOCK(iwpm_nlmsg_req_lock);
     44
     45static struct hlist_head *iwpm_hash_bucket;
     46static DEFINE_SPINLOCK(iwpm_mapinfo_lock);
     47
     48static struct hlist_head *iwpm_reminfo_bucket;
     49static DEFINE_SPINLOCK(iwpm_reminfo_lock);
     50
     51static struct iwpm_admin_data iwpm_admin;
     52
     53/**
     54 * iwpm_init - Allocate resources for the iwarp port mapper
     55 * @nl_client: The index of the netlink client
     56 *
     57 * Should be called when network interface goes up.
     58 */
     59int iwpm_init(u8 nl_client)
     60{
     61	iwpm_hash_bucket = kcalloc(IWPM_MAPINFO_HASH_SIZE,
     62				   sizeof(struct hlist_head), GFP_KERNEL);
     63	if (!iwpm_hash_bucket)
     64		return -ENOMEM;
     65
     66	iwpm_reminfo_bucket = kcalloc(IWPM_REMINFO_HASH_SIZE,
     67				      sizeof(struct hlist_head), GFP_KERNEL);
     68	if (!iwpm_reminfo_bucket) {
     69		kfree(iwpm_hash_bucket);
     70		return -ENOMEM;
     71	}
     72
     73	iwpm_set_registration(nl_client, IWPM_REG_UNDEF);
     74	pr_debug("%s: Mapinfo and reminfo tables are created\n", __func__);
     75	return 0;
     76}
     77
     78static void free_hash_bucket(void);
     79static void free_reminfo_bucket(void);
     80
     81/**
     82 * iwpm_exit - Deallocate resources for the iwarp port mapper
     83 * @nl_client: The index of the netlink client
     84 *
     85 * Should be called when network interface goes down.
     86 */
     87int iwpm_exit(u8 nl_client)
     88{
     89	free_hash_bucket();
     90	free_reminfo_bucket();
     91	pr_debug("%s: Resources are destroyed\n", __func__);
     92	iwpm_set_registration(nl_client, IWPM_REG_UNDEF);
     93	return 0;
     94}
     95
     96static struct hlist_head *get_mapinfo_hash_bucket(struct sockaddr_storage *,
     97					       struct sockaddr_storage *);
     98
     99/**
    100 * iwpm_create_mapinfo - Store local and mapped IPv4/IPv6 address
    101 *                       info in a hash table
    102 * @local_sockaddr: Local ip/tcp address
    103 * @mapped_sockaddr: Mapped local ip/tcp address
    104 * @nl_client: The index of the netlink client
    105 * @map_flags: IWPM mapping flags
    106 */
    107int iwpm_create_mapinfo(struct sockaddr_storage *local_sockaddr,
    108			struct sockaddr_storage *mapped_sockaddr,
    109			u8 nl_client, u32 map_flags)
    110{
    111	struct hlist_head *hash_bucket_head = NULL;
    112	struct iwpm_mapping_info *map_info;
    113	unsigned long flags;
    114	int ret = -EINVAL;
    115
    116	map_info = kzalloc(sizeof(struct iwpm_mapping_info), GFP_KERNEL);
    117	if (!map_info)
    118		return -ENOMEM;
    119
    120	memcpy(&map_info->local_sockaddr, local_sockaddr,
    121	       sizeof(struct sockaddr_storage));
    122	memcpy(&map_info->mapped_sockaddr, mapped_sockaddr,
    123	       sizeof(struct sockaddr_storage));
    124	map_info->nl_client = nl_client;
    125	map_info->map_flags = map_flags;
    126
    127	spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
    128	if (iwpm_hash_bucket) {
    129		hash_bucket_head = get_mapinfo_hash_bucket(
    130					&map_info->local_sockaddr,
    131					&map_info->mapped_sockaddr);
    132		if (hash_bucket_head) {
    133			hlist_add_head(&map_info->hlist_node, hash_bucket_head);
    134			ret = 0;
    135		}
    136	}
    137	spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags);
    138
    139	if (!hash_bucket_head)
    140		kfree(map_info);
    141	return ret;
    142}
    143
    144/**
    145 * iwpm_remove_mapinfo - Remove local and mapped IPv4/IPv6 address
    146 *                       info from the hash table
    147 * @local_sockaddr: Local ip/tcp address
    148 * @mapped_local_addr: Mapped local ip/tcp address
    149 *
    150 * Returns err code if mapping info is not found in the hash table,
    151 * otherwise returns 0
    152 */
    153int iwpm_remove_mapinfo(struct sockaddr_storage *local_sockaddr,
    154			struct sockaddr_storage *mapped_local_addr)
    155{
    156	struct hlist_node *tmp_hlist_node;
    157	struct hlist_head *hash_bucket_head;
    158	struct iwpm_mapping_info *map_info = NULL;
    159	unsigned long flags;
    160	int ret = -EINVAL;
    161
    162	spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
    163	if (iwpm_hash_bucket) {
    164		hash_bucket_head = get_mapinfo_hash_bucket(
    165					local_sockaddr,
    166					mapped_local_addr);
    167		if (!hash_bucket_head)
    168			goto remove_mapinfo_exit;
    169
    170		hlist_for_each_entry_safe(map_info, tmp_hlist_node,
    171					hash_bucket_head, hlist_node) {
    172
    173			if (!iwpm_compare_sockaddr(&map_info->mapped_sockaddr,
    174						mapped_local_addr)) {
    175
    176				hlist_del_init(&map_info->hlist_node);
    177				kfree(map_info);
    178				ret = 0;
    179				break;
    180			}
    181		}
    182	}
    183remove_mapinfo_exit:
    184	spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags);
    185	return ret;
    186}
    187
    188static void free_hash_bucket(void)
    189{
    190	struct hlist_node *tmp_hlist_node;
    191	struct iwpm_mapping_info *map_info;
    192	unsigned long flags;
    193	int i;
    194
    195	/* remove all the mapinfo data from the list */
    196	spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
    197	for (i = 0; i < IWPM_MAPINFO_HASH_SIZE; i++) {
    198		hlist_for_each_entry_safe(map_info, tmp_hlist_node,
    199			&iwpm_hash_bucket[i], hlist_node) {
    200
    201				hlist_del_init(&map_info->hlist_node);
    202				kfree(map_info);
    203			}
    204	}
    205	/* free the hash list */
    206	kfree(iwpm_hash_bucket);
    207	iwpm_hash_bucket = NULL;
    208	spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags);
    209}
    210
    211static void free_reminfo_bucket(void)
    212{
    213	struct hlist_node *tmp_hlist_node;
    214	struct iwpm_remote_info *rem_info;
    215	unsigned long flags;
    216	int i;
    217
    218	/* remove all the remote info from the list */
    219	spin_lock_irqsave(&iwpm_reminfo_lock, flags);
    220	for (i = 0; i < IWPM_REMINFO_HASH_SIZE; i++) {
    221		hlist_for_each_entry_safe(rem_info, tmp_hlist_node,
    222			&iwpm_reminfo_bucket[i], hlist_node) {
    223
    224				hlist_del_init(&rem_info->hlist_node);
    225				kfree(rem_info);
    226			}
    227	}
    228	/* free the hash list */
    229	kfree(iwpm_reminfo_bucket);
    230	iwpm_reminfo_bucket = NULL;
    231	spin_unlock_irqrestore(&iwpm_reminfo_lock, flags);
    232}
    233
    234static struct hlist_head *get_reminfo_hash_bucket(struct sockaddr_storage *,
    235						struct sockaddr_storage *);
    236
    237void iwpm_add_remote_info(struct iwpm_remote_info *rem_info)
    238{
    239	struct hlist_head *hash_bucket_head;
    240	unsigned long flags;
    241
    242	spin_lock_irqsave(&iwpm_reminfo_lock, flags);
    243	if (iwpm_reminfo_bucket) {
    244		hash_bucket_head = get_reminfo_hash_bucket(
    245					&rem_info->mapped_loc_sockaddr,
    246					&rem_info->mapped_rem_sockaddr);
    247		if (hash_bucket_head)
    248			hlist_add_head(&rem_info->hlist_node, hash_bucket_head);
    249	}
    250	spin_unlock_irqrestore(&iwpm_reminfo_lock, flags);
    251}
    252
    253/**
    254 * iwpm_get_remote_info - Get the remote connecting peer address info
    255 *
    256 * @mapped_loc_addr: Mapped local address of the listening peer
    257 * @mapped_rem_addr: Mapped remote address of the connecting peer
    258 * @remote_addr: To store the remote address of the connecting peer
    259 * @nl_client: The index of the netlink client
    260 *
    261 * The remote address info is retrieved and provided to the client in
    262 * the remote_addr. After that it is removed from the hash table
    263 */
    264int iwpm_get_remote_info(struct sockaddr_storage *mapped_loc_addr,
    265			 struct sockaddr_storage *mapped_rem_addr,
    266			 struct sockaddr_storage *remote_addr,
    267			 u8 nl_client)
    268{
    269	struct hlist_node *tmp_hlist_node;
    270	struct hlist_head *hash_bucket_head;
    271	struct iwpm_remote_info *rem_info = NULL;
    272	unsigned long flags;
    273	int ret = -EINVAL;
    274
    275	spin_lock_irqsave(&iwpm_reminfo_lock, flags);
    276	if (iwpm_reminfo_bucket) {
    277		hash_bucket_head = get_reminfo_hash_bucket(
    278					mapped_loc_addr,
    279					mapped_rem_addr);
    280		if (!hash_bucket_head)
    281			goto get_remote_info_exit;
    282		hlist_for_each_entry_safe(rem_info, tmp_hlist_node,
    283					hash_bucket_head, hlist_node) {
    284
    285			if (!iwpm_compare_sockaddr(&rem_info->mapped_loc_sockaddr,
    286				mapped_loc_addr) &&
    287				!iwpm_compare_sockaddr(&rem_info->mapped_rem_sockaddr,
    288				mapped_rem_addr)) {
    289
    290				memcpy(remote_addr, &rem_info->remote_sockaddr,
    291					sizeof(struct sockaddr_storage));
    292				iwpm_print_sockaddr(remote_addr,
    293						"get_remote_info: Remote sockaddr:");
    294
    295				hlist_del_init(&rem_info->hlist_node);
    296				kfree(rem_info);
    297				ret = 0;
    298				break;
    299			}
    300		}
    301	}
    302get_remote_info_exit:
    303	spin_unlock_irqrestore(&iwpm_reminfo_lock, flags);
    304	return ret;
    305}
    306
    307struct iwpm_nlmsg_request *iwpm_get_nlmsg_request(__u32 nlmsg_seq,
    308					u8 nl_client, gfp_t gfp)
    309{
    310	struct iwpm_nlmsg_request *nlmsg_request = NULL;
    311	unsigned long flags;
    312
    313	nlmsg_request = kzalloc(sizeof(struct iwpm_nlmsg_request), gfp);
    314	if (!nlmsg_request)
    315		return NULL;
    316
    317	spin_lock_irqsave(&iwpm_nlmsg_req_lock, flags);
    318	list_add_tail(&nlmsg_request->inprocess_list, &iwpm_nlmsg_req_list);
    319	spin_unlock_irqrestore(&iwpm_nlmsg_req_lock, flags);
    320
    321	kref_init(&nlmsg_request->kref);
    322	kref_get(&nlmsg_request->kref);
    323	nlmsg_request->nlmsg_seq = nlmsg_seq;
    324	nlmsg_request->nl_client = nl_client;
    325	nlmsg_request->request_done = 0;
    326	nlmsg_request->err_code = 0;
    327	sema_init(&nlmsg_request->sem, 1);
    328	down(&nlmsg_request->sem);
    329	return nlmsg_request;
    330}
    331
    332void iwpm_free_nlmsg_request(struct kref *kref)
    333{
    334	struct iwpm_nlmsg_request *nlmsg_request;
    335	unsigned long flags;
    336
    337	nlmsg_request = container_of(kref, struct iwpm_nlmsg_request, kref);
    338
    339	spin_lock_irqsave(&iwpm_nlmsg_req_lock, flags);
    340	list_del_init(&nlmsg_request->inprocess_list);
    341	spin_unlock_irqrestore(&iwpm_nlmsg_req_lock, flags);
    342
    343	if (!nlmsg_request->request_done)
    344		pr_debug("%s Freeing incomplete nlmsg request (seq = %u).\n",
    345			__func__, nlmsg_request->nlmsg_seq);
    346	kfree(nlmsg_request);
    347}
    348
    349struct iwpm_nlmsg_request *iwpm_find_nlmsg_request(__u32 echo_seq)
    350{
    351	struct iwpm_nlmsg_request *nlmsg_request;
    352	struct iwpm_nlmsg_request *found_request = NULL;
    353	unsigned long flags;
    354
    355	spin_lock_irqsave(&iwpm_nlmsg_req_lock, flags);
    356	list_for_each_entry(nlmsg_request, &iwpm_nlmsg_req_list,
    357			    inprocess_list) {
    358		if (nlmsg_request->nlmsg_seq == echo_seq) {
    359			found_request = nlmsg_request;
    360			kref_get(&nlmsg_request->kref);
    361			break;
    362		}
    363	}
    364	spin_unlock_irqrestore(&iwpm_nlmsg_req_lock, flags);
    365	return found_request;
    366}
    367
    368int iwpm_wait_complete_req(struct iwpm_nlmsg_request *nlmsg_request)
    369{
    370	int ret;
    371
    372	ret = down_timeout(&nlmsg_request->sem, IWPM_NL_TIMEOUT);
    373	if (ret) {
    374		ret = -EINVAL;
    375		pr_info("%s: Timeout %d sec for netlink request (seq = %u)\n",
    376			__func__, (IWPM_NL_TIMEOUT/HZ), nlmsg_request->nlmsg_seq);
    377	} else {
    378		ret = nlmsg_request->err_code;
    379	}
    380	kref_put(&nlmsg_request->kref, iwpm_free_nlmsg_request);
    381	return ret;
    382}
    383
    384int iwpm_get_nlmsg_seq(void)
    385{
    386	return atomic_inc_return(&iwpm_admin.nlmsg_seq);
    387}
    388
    389/* valid client */
    390u32 iwpm_get_registration(u8 nl_client)
    391{
    392	return iwpm_admin.reg_list[nl_client];
    393}
    394
    395/* valid client */
    396void iwpm_set_registration(u8 nl_client, u32 reg)
    397{
    398	iwpm_admin.reg_list[nl_client] = reg;
    399}
    400
    401/* valid client */
    402u32 iwpm_check_registration(u8 nl_client, u32 reg)
    403{
    404	return (iwpm_get_registration(nl_client) & reg);
    405}
    406
    407int iwpm_compare_sockaddr(struct sockaddr_storage *a_sockaddr,
    408				struct sockaddr_storage *b_sockaddr)
    409{
    410	if (a_sockaddr->ss_family != b_sockaddr->ss_family)
    411		return 1;
    412	if (a_sockaddr->ss_family == AF_INET) {
    413		struct sockaddr_in *a4_sockaddr =
    414			(struct sockaddr_in *)a_sockaddr;
    415		struct sockaddr_in *b4_sockaddr =
    416			(struct sockaddr_in *)b_sockaddr;
    417		if (!memcmp(&a4_sockaddr->sin_addr,
    418			&b4_sockaddr->sin_addr, sizeof(struct in_addr))
    419			&& a4_sockaddr->sin_port == b4_sockaddr->sin_port)
    420				return 0;
    421
    422	} else if (a_sockaddr->ss_family == AF_INET6) {
    423		struct sockaddr_in6 *a6_sockaddr =
    424			(struct sockaddr_in6 *)a_sockaddr;
    425		struct sockaddr_in6 *b6_sockaddr =
    426			(struct sockaddr_in6 *)b_sockaddr;
    427		if (!memcmp(&a6_sockaddr->sin6_addr,
    428			&b6_sockaddr->sin6_addr, sizeof(struct in6_addr))
    429			&& a6_sockaddr->sin6_port == b6_sockaddr->sin6_port)
    430				return 0;
    431
    432	} else {
    433		pr_err("%s: Invalid sockaddr family\n", __func__);
    434	}
    435	return 1;
    436}
    437
    438struct sk_buff *iwpm_create_nlmsg(u32 nl_op, struct nlmsghdr **nlh,
    439						int nl_client)
    440{
    441	struct sk_buff *skb = NULL;
    442
    443	skb = dev_alloc_skb(IWPM_MSG_SIZE);
    444	if (!skb)
    445		goto create_nlmsg_exit;
    446
    447	if (!(ibnl_put_msg(skb, nlh, 0, 0, nl_client, nl_op,
    448			   NLM_F_REQUEST))) {
    449		pr_warn("%s: Unable to put the nlmsg header\n", __func__);
    450		dev_kfree_skb(skb);
    451		skb = NULL;
    452	}
    453create_nlmsg_exit:
    454	return skb;
    455}
    456
    457int iwpm_parse_nlmsg(struct netlink_callback *cb, int policy_max,
    458				   const struct nla_policy *nlmsg_policy,
    459				   struct nlattr *nltb[], const char *msg_type)
    460{
    461	int nlh_len = 0;
    462	int ret;
    463	const char *err_str = "";
    464
    465	ret = nlmsg_validate_deprecated(cb->nlh, nlh_len, policy_max - 1,
    466					nlmsg_policy, NULL);
    467	if (ret) {
    468		err_str = "Invalid attribute";
    469		goto parse_nlmsg_error;
    470	}
    471	ret = nlmsg_parse_deprecated(cb->nlh, nlh_len, nltb, policy_max - 1,
    472				     nlmsg_policy, NULL);
    473	if (ret) {
    474		err_str = "Unable to parse the nlmsg";
    475		goto parse_nlmsg_error;
    476	}
    477	ret = iwpm_validate_nlmsg_attr(nltb, policy_max);
    478	if (ret) {
    479		err_str = "Invalid NULL attribute";
    480		goto parse_nlmsg_error;
    481	}
    482	return 0;
    483parse_nlmsg_error:
    484	pr_warn("%s: %s (msg type %s ret = %d)\n",
    485			__func__, err_str, msg_type, ret);
    486	return ret;
    487}
    488
    489void iwpm_print_sockaddr(struct sockaddr_storage *sockaddr, char *msg)
    490{
    491	struct sockaddr_in6 *sockaddr_v6;
    492	struct sockaddr_in *sockaddr_v4;
    493
    494	switch (sockaddr->ss_family) {
    495	case AF_INET:
    496		sockaddr_v4 = (struct sockaddr_in *)sockaddr;
    497		pr_debug("%s IPV4 %pI4: %u(0x%04X)\n",
    498			msg, &sockaddr_v4->sin_addr,
    499			ntohs(sockaddr_v4->sin_port),
    500			ntohs(sockaddr_v4->sin_port));
    501		break;
    502	case AF_INET6:
    503		sockaddr_v6 = (struct sockaddr_in6 *)sockaddr;
    504		pr_debug("%s IPV6 %pI6: %u(0x%04X)\n",
    505			msg, &sockaddr_v6->sin6_addr,
    506			ntohs(sockaddr_v6->sin6_port),
    507			ntohs(sockaddr_v6->sin6_port));
    508		break;
    509	default:
    510		break;
    511	}
    512}
    513
    514static u32 iwpm_ipv6_jhash(struct sockaddr_in6 *ipv6_sockaddr)
    515{
    516	u32 ipv6_hash = jhash(&ipv6_sockaddr->sin6_addr, sizeof(struct in6_addr), 0);
    517	u32 hash = jhash_2words(ipv6_hash, (__force u32) ipv6_sockaddr->sin6_port, 0);
    518	return hash;
    519}
    520
    521static u32 iwpm_ipv4_jhash(struct sockaddr_in *ipv4_sockaddr)
    522{
    523	u32 ipv4_hash = jhash(&ipv4_sockaddr->sin_addr, sizeof(struct in_addr), 0);
    524	u32 hash = jhash_2words(ipv4_hash, (__force u32) ipv4_sockaddr->sin_port, 0);
    525	return hash;
    526}
    527
    528static int get_hash_bucket(struct sockaddr_storage *a_sockaddr,
    529				struct sockaddr_storage *b_sockaddr, u32 *hash)
    530{
    531	u32 a_hash, b_hash;
    532
    533	if (a_sockaddr->ss_family == AF_INET) {
    534		a_hash = iwpm_ipv4_jhash((struct sockaddr_in *) a_sockaddr);
    535		b_hash = iwpm_ipv4_jhash((struct sockaddr_in *) b_sockaddr);
    536
    537	} else if (a_sockaddr->ss_family == AF_INET6) {
    538		a_hash = iwpm_ipv6_jhash((struct sockaddr_in6 *) a_sockaddr);
    539		b_hash = iwpm_ipv6_jhash((struct sockaddr_in6 *) b_sockaddr);
    540	} else {
    541		pr_err("%s: Invalid sockaddr family\n", __func__);
    542		return -EINVAL;
    543	}
    544
    545	if (a_hash == b_hash) /* if port mapper isn't available */
    546		*hash = a_hash;
    547	else
    548		*hash = jhash_2words(a_hash, b_hash, 0);
    549	return 0;
    550}
    551
    552static struct hlist_head *get_mapinfo_hash_bucket(struct sockaddr_storage
    553				*local_sockaddr, struct sockaddr_storage
    554				*mapped_sockaddr)
    555{
    556	u32 hash;
    557	int ret;
    558
    559	ret = get_hash_bucket(local_sockaddr, mapped_sockaddr, &hash);
    560	if (ret)
    561		return NULL;
    562	return &iwpm_hash_bucket[hash & IWPM_MAPINFO_HASH_MASK];
    563}
    564
    565static struct hlist_head *get_reminfo_hash_bucket(struct sockaddr_storage
    566				*mapped_loc_sockaddr, struct sockaddr_storage
    567				*mapped_rem_sockaddr)
    568{
    569	u32 hash;
    570	int ret;
    571
    572	ret = get_hash_bucket(mapped_loc_sockaddr, mapped_rem_sockaddr, &hash);
    573	if (ret)
    574		return NULL;
    575	return &iwpm_reminfo_bucket[hash & IWPM_REMINFO_HASH_MASK];
    576}
    577
    578static int send_mapinfo_num(u32 mapping_num, u8 nl_client, int iwpm_pid)
    579{
    580	struct sk_buff *skb = NULL;
    581	struct nlmsghdr *nlh;
    582	u32 msg_seq;
    583	const char *err_str = "";
    584	int ret = -EINVAL;
    585
    586	skb = iwpm_create_nlmsg(RDMA_NL_IWPM_MAPINFO_NUM, &nlh, nl_client);
    587	if (!skb) {
    588		err_str = "Unable to create a nlmsg";
    589		goto mapinfo_num_error;
    590	}
    591	nlh->nlmsg_seq = iwpm_get_nlmsg_seq();
    592	msg_seq = 0;
    593	err_str = "Unable to put attribute of mapinfo number nlmsg";
    594	ret = ibnl_put_attr(skb, nlh, sizeof(u32), &msg_seq, IWPM_NLA_MAPINFO_SEQ);
    595	if (ret)
    596		goto mapinfo_num_error;
    597	ret = ibnl_put_attr(skb, nlh, sizeof(u32),
    598				&mapping_num, IWPM_NLA_MAPINFO_SEND_NUM);
    599	if (ret)
    600		goto mapinfo_num_error;
    601
    602	nlmsg_end(skb, nlh);
    603
    604	ret = rdma_nl_unicast(&init_net, skb, iwpm_pid);
    605	if (ret) {
    606		skb = NULL;
    607		err_str = "Unable to send a nlmsg";
    608		goto mapinfo_num_error;
    609	}
    610	pr_debug("%s: Sent mapping number = %u\n", __func__, mapping_num);
    611	return 0;
    612mapinfo_num_error:
    613	pr_info("%s: %s\n", __func__, err_str);
    614	dev_kfree_skb(skb);
    615	return ret;
    616}
    617
    618static int send_nlmsg_done(struct sk_buff *skb, u8 nl_client, int iwpm_pid)
    619{
    620	struct nlmsghdr *nlh = NULL;
    621	int ret = 0;
    622
    623	if (!skb)
    624		return ret;
    625	if (!(ibnl_put_msg(skb, &nlh, 0, 0, nl_client,
    626			   RDMA_NL_IWPM_MAPINFO, NLM_F_MULTI))) {
    627		pr_warn("%s Unable to put NLMSG_DONE\n", __func__);
    628		dev_kfree_skb(skb);
    629		return -ENOMEM;
    630	}
    631	nlh->nlmsg_type = NLMSG_DONE;
    632	ret = rdma_nl_unicast(&init_net, skb, iwpm_pid);
    633	if (ret)
    634		pr_warn("%s Unable to send a nlmsg\n", __func__);
    635	return ret;
    636}
    637
    638int iwpm_send_mapinfo(u8 nl_client, int iwpm_pid)
    639{
    640	struct iwpm_mapping_info *map_info;
    641	struct sk_buff *skb = NULL;
    642	struct nlmsghdr *nlh;
    643	int skb_num = 0, mapping_num = 0;
    644	int i = 0, nlmsg_bytes = 0;
    645	unsigned long flags;
    646	const char *err_str = "";
    647	int ret;
    648
    649	skb = dev_alloc_skb(NLMSG_GOODSIZE);
    650	if (!skb) {
    651		ret = -ENOMEM;
    652		err_str = "Unable to allocate skb";
    653		goto send_mapping_info_exit;
    654	}
    655	skb_num++;
    656	spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
    657	ret = -EINVAL;
    658	for (i = 0; i < IWPM_MAPINFO_HASH_SIZE; i++) {
    659		hlist_for_each_entry(map_info, &iwpm_hash_bucket[i],
    660				     hlist_node) {
    661			if (map_info->nl_client != nl_client)
    662				continue;
    663			nlh = NULL;
    664			if (!(ibnl_put_msg(skb, &nlh, 0, 0, nl_client,
    665					RDMA_NL_IWPM_MAPINFO, NLM_F_MULTI))) {
    666				ret = -ENOMEM;
    667				err_str = "Unable to put the nlmsg header";
    668				goto send_mapping_info_unlock;
    669			}
    670			err_str = "Unable to put attribute of the nlmsg";
    671			ret = ibnl_put_attr(skb, nlh,
    672					sizeof(struct sockaddr_storage),
    673					&map_info->local_sockaddr,
    674					IWPM_NLA_MAPINFO_LOCAL_ADDR);
    675			if (ret)
    676				goto send_mapping_info_unlock;
    677
    678			ret = ibnl_put_attr(skb, nlh,
    679					sizeof(struct sockaddr_storage),
    680					&map_info->mapped_sockaddr,
    681					IWPM_NLA_MAPINFO_MAPPED_ADDR);
    682			if (ret)
    683				goto send_mapping_info_unlock;
    684
    685			if (iwpm_ulib_version > IWPM_UABI_VERSION_MIN) {
    686				ret = ibnl_put_attr(skb, nlh, sizeof(u32),
    687						&map_info->map_flags,
    688						IWPM_NLA_MAPINFO_FLAGS);
    689				if (ret)
    690					goto send_mapping_info_unlock;
    691			}
    692
    693			nlmsg_end(skb, nlh);
    694
    695			iwpm_print_sockaddr(&map_info->local_sockaddr,
    696				"send_mapping_info: Local sockaddr:");
    697			iwpm_print_sockaddr(&map_info->mapped_sockaddr,
    698				"send_mapping_info: Mapped local sockaddr:");
    699			mapping_num++;
    700			nlmsg_bytes += nlh->nlmsg_len;
    701
    702			/* check if all mappings can fit in one skb */
    703			if (NLMSG_GOODSIZE - nlmsg_bytes < nlh->nlmsg_len * 2) {
    704				/* and leave room for NLMSG_DONE */
    705				nlmsg_bytes = 0;
    706				skb_num++;
    707				spin_unlock_irqrestore(&iwpm_mapinfo_lock,
    708						       flags);
    709				/* send the skb */
    710				ret = send_nlmsg_done(skb, nl_client, iwpm_pid);
    711				skb = NULL;
    712				if (ret) {
    713					err_str = "Unable to send map info";
    714					goto send_mapping_info_exit;
    715				}
    716				if (skb_num == IWPM_MAPINFO_SKB_COUNT) {
    717					ret = -ENOMEM;
    718					err_str = "Insufficient skbs for map info";
    719					goto send_mapping_info_exit;
    720				}
    721				skb = dev_alloc_skb(NLMSG_GOODSIZE);
    722				if (!skb) {
    723					ret = -ENOMEM;
    724					err_str = "Unable to allocate skb";
    725					goto send_mapping_info_exit;
    726				}
    727				spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
    728			}
    729		}
    730	}
    731send_mapping_info_unlock:
    732	spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags);
    733send_mapping_info_exit:
    734	if (ret) {
    735		pr_warn("%s: %s (ret = %d)\n", __func__, err_str, ret);
    736		dev_kfree_skb(skb);
    737		return ret;
    738	}
    739	send_nlmsg_done(skb, nl_client, iwpm_pid);
    740	return send_mapinfo_num(mapping_num, nl_client, iwpm_pid);
    741}
    742
    743int iwpm_mapinfo_available(void)
    744{
    745	unsigned long flags;
    746	int full_bucket = 0, i = 0;
    747
    748	spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
    749	if (iwpm_hash_bucket) {
    750		for (i = 0; i < IWPM_MAPINFO_HASH_SIZE; i++) {
    751			if (!hlist_empty(&iwpm_hash_bucket[i])) {
    752				full_bucket = 1;
    753				break;
    754			}
    755		}
    756	}
    757	spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags);
    758	return full_bucket;
    759}
    760
    761int iwpm_send_hello(u8 nl_client, int iwpm_pid, u16 abi_version)
    762{
    763	struct sk_buff *skb = NULL;
    764	struct nlmsghdr *nlh;
    765	const char *err_str;
    766	int ret = -EINVAL;
    767
    768	skb = iwpm_create_nlmsg(RDMA_NL_IWPM_HELLO, &nlh, nl_client);
    769	if (!skb) {
    770		err_str = "Unable to create a nlmsg";
    771		goto hello_num_error;
    772	}
    773	nlh->nlmsg_seq = iwpm_get_nlmsg_seq();
    774	err_str = "Unable to put attribute of abi_version into nlmsg";
    775	ret = ibnl_put_attr(skb, nlh, sizeof(u16), &abi_version,
    776			    IWPM_NLA_HELLO_ABI_VERSION);
    777	if (ret)
    778		goto hello_num_error;
    779	nlmsg_end(skb, nlh);
    780
    781	ret = rdma_nl_unicast(&init_net, skb, iwpm_pid);
    782	if (ret) {
    783		skb = NULL;
    784		err_str = "Unable to send a nlmsg";
    785		goto hello_num_error;
    786	}
    787	pr_debug("%s: Sent hello abi_version = %u\n", __func__, abi_version);
    788	return 0;
    789hello_num_error:
    790	pr_info("%s: %s\n", __func__, err_str);
    791	dev_kfree_skb(skb);
    792	return ret;
    793}