130dc5e63STatyana Nikolova /*
230dc5e63STatyana Nikolova  * Copyright (c) 2014 Intel Corporation. All rights reserved.
330dc5e63STatyana Nikolova  * Copyright (c) 2014 Chelsio, Inc. All rights reserved.
430dc5e63STatyana Nikolova  *
530dc5e63STatyana Nikolova  * This software is available to you under a choice of one of two
630dc5e63STatyana Nikolova  * licenses.  You may choose to be licensed under the terms of the GNU
730dc5e63STatyana Nikolova  * General Public License (GPL) Version 2, available from the file
830dc5e63STatyana Nikolova  * COPYING in the main directory of this source tree, or the
930dc5e63STatyana Nikolova  * OpenIB.org BSD license below:
1030dc5e63STatyana Nikolova  *
1130dc5e63STatyana Nikolova  *     Redistribution and use in source and binary forms, with or
1230dc5e63STatyana Nikolova  *     without modification, are permitted provided that the following
1330dc5e63STatyana Nikolova  *     conditions are met:
1430dc5e63STatyana Nikolova  *
1530dc5e63STatyana Nikolova  *      - Redistributions of source code must retain the above
1630dc5e63STatyana Nikolova  *        copyright notice, this list of conditions and the following
1730dc5e63STatyana Nikolova  *        disclaimer.
1830dc5e63STatyana Nikolova  *
1930dc5e63STatyana Nikolova  *      - Redistributions in binary form must reproduce the above
2030dc5e63STatyana Nikolova  *        copyright notice, this list of conditions and the following
2130dc5e63STatyana Nikolova  *        disclaimer in the documentation and/or other materials
2230dc5e63STatyana Nikolova  *        provided with the distribution.
2330dc5e63STatyana Nikolova  *
2430dc5e63STatyana Nikolova  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2530dc5e63STatyana Nikolova  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2630dc5e63STatyana Nikolova  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2730dc5e63STatyana Nikolova  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
2830dc5e63STatyana Nikolova  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
2930dc5e63STatyana Nikolova  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
3030dc5e63STatyana Nikolova  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3130dc5e63STatyana Nikolova  * SOFTWARE.
3230dc5e63STatyana Nikolova  */
3330dc5e63STatyana Nikolova 
3430dc5e63STatyana Nikolova #include "iwpm_util.h"
3530dc5e63STatyana Nikolova 
36ec04847cSTatyana Nikolova static const char iwpm_ulib_name[IWPM_ULIBNAME_SIZE] = "iWarpPortMapperUser";
37b0bad9adSSteve Wise u16 iwpm_ulib_version = IWPM_UABI_VERSION_MIN;
3830dc5e63STatyana Nikolova static int iwpm_user_pid = IWPM_PID_UNDEFINED;
3930dc5e63STatyana Nikolova static atomic_t echo_nlmsg_seq;
4030dc5e63STatyana Nikolova 
41a2bfd708SSteve Wise /**
42a2bfd708SSteve Wise  * iwpm_valid_pid - Check if the userspace iwarp port mapper pid is valid
43a2bfd708SSteve Wise  *
44a2bfd708SSteve Wise  * Returns true if the pid is greater than zero, otherwise returns false
45a2bfd708SSteve Wise  */
iwpm_valid_pid(void)4630dc5e63STatyana Nikolova int iwpm_valid_pid(void)
4730dc5e63STatyana Nikolova {
4830dc5e63STatyana Nikolova 	return iwpm_user_pid > 0;
4930dc5e63STatyana Nikolova }
5030dc5e63STatyana Nikolova 
51a2bfd708SSteve Wise /**
5230dc5e63STatyana Nikolova  * iwpm_register_pid - Send a netlink query to userspace
53a2bfd708SSteve Wise  *                     to get the iwarp port mapper pid
54a2bfd708SSteve Wise  * @pm_msg: Contains driver info to send to the userspace port mapper
55a2bfd708SSteve Wise  * @nl_client: The index of the netlink client
5630dc5e63STatyana Nikolova  *
5730dc5e63STatyana Nikolova  * nlmsg attributes:
5830dc5e63STatyana Nikolova  *	[IWPM_NLA_REG_PID_SEQ]
5930dc5e63STatyana Nikolova  *	[IWPM_NLA_REG_IF_NAME]
6030dc5e63STatyana Nikolova  *	[IWPM_NLA_REG_IBDEV_NAME]
6130dc5e63STatyana Nikolova  *	[IWPM_NLA_REG_ULIB_NAME]
6230dc5e63STatyana Nikolova  */
iwpm_register_pid(struct iwpm_dev_data * pm_msg,u8 nl_client)6330dc5e63STatyana Nikolova int iwpm_register_pid(struct iwpm_dev_data *pm_msg, u8 nl_client)
6430dc5e63STatyana Nikolova {
6530dc5e63STatyana Nikolova 	struct sk_buff *skb = NULL;
6630dc5e63STatyana Nikolova 	struct iwpm_nlmsg_request *nlmsg_request = NULL;
6730dc5e63STatyana Nikolova 	struct nlmsghdr *nlh;
6830dc5e63STatyana Nikolova 	u32 msg_seq;
6930dc5e63STatyana Nikolova 	const char *err_str = "";
7030dc5e63STatyana Nikolova 	int ret = -EINVAL;
7130dc5e63STatyana Nikolova 
72a7f2f24cSTatyana Nikolova 	if (iwpm_check_registration(nl_client, IWPM_REG_VALID) ||
73a7f2f24cSTatyana Nikolova 			iwpm_user_pid == IWPM_PID_UNAVAILABLE)
7430dc5e63STatyana Nikolova 		return 0;
7530dc5e63STatyana Nikolova 	skb = iwpm_create_nlmsg(RDMA_NL_IWPM_REG_PID, &nlh, nl_client);
7630dc5e63STatyana Nikolova 	if (!skb) {
7730dc5e63STatyana Nikolova 		err_str = "Unable to create a nlmsg";
7830dc5e63STatyana Nikolova 		goto pid_query_error;
7930dc5e63STatyana Nikolova 	}
8030dc5e63STatyana Nikolova 	nlh->nlmsg_seq = iwpm_get_nlmsg_seq();
8130dc5e63STatyana Nikolova 	nlmsg_request = iwpm_get_nlmsg_request(nlh->nlmsg_seq, nl_client, GFP_KERNEL);
8230dc5e63STatyana Nikolova 	if (!nlmsg_request) {
8330dc5e63STatyana Nikolova 		err_str = "Unable to allocate netlink request";
8430dc5e63STatyana Nikolova 		goto pid_query_error;
8530dc5e63STatyana Nikolova 	}
8630dc5e63STatyana Nikolova 	msg_seq = atomic_read(&echo_nlmsg_seq);
8730dc5e63STatyana Nikolova 
8830dc5e63STatyana Nikolova 	/* fill in the pid request message */
8930dc5e63STatyana Nikolova 	err_str = "Unable to put attribute of the nlmsg";
9030dc5e63STatyana Nikolova 	ret = ibnl_put_attr(skb, nlh, sizeof(u32), &msg_seq, IWPM_NLA_REG_PID_SEQ);
9130dc5e63STatyana Nikolova 	if (ret)
9230dc5e63STatyana Nikolova 		goto pid_query_error;
93b493d91dSFaisal Latif 	ret = ibnl_put_attr(skb, nlh, IFNAMSIZ,
9430dc5e63STatyana Nikolova 			    pm_msg->if_name, IWPM_NLA_REG_IF_NAME);
9530dc5e63STatyana Nikolova 	if (ret)
9630dc5e63STatyana Nikolova 		goto pid_query_error;
9730dc5e63STatyana Nikolova 	ret = ibnl_put_attr(skb, nlh, IWPM_DEVNAME_SIZE,
9830dc5e63STatyana Nikolova 				pm_msg->dev_name, IWPM_NLA_REG_IBDEV_NAME);
9930dc5e63STatyana Nikolova 	if (ret)
10030dc5e63STatyana Nikolova 		goto pid_query_error;
10130dc5e63STatyana Nikolova 	ret = ibnl_put_attr(skb, nlh, IWPM_ULIBNAME_SIZE,
10230dc5e63STatyana Nikolova 				(char *)iwpm_ulib_name, IWPM_NLA_REG_ULIB_NAME);
10330dc5e63STatyana Nikolova 	if (ret)
10430dc5e63STatyana Nikolova 		goto pid_query_error;
10530dc5e63STatyana Nikolova 
10604eae427SShiraz Saleem 	nlmsg_end(skb, nlh);
10704eae427SShiraz Saleem 
10830dc5e63STatyana Nikolova 	pr_debug("%s: Multicasting a nlmsg (dev = %s ifname = %s iwpm = %s)\n",
10930dc5e63STatyana Nikolova 		__func__, pm_msg->dev_name, pm_msg->if_name, iwpm_ulib_name);
11030dc5e63STatyana Nikolova 
1111d2fedd8SParav Pandit 	ret = rdma_nl_multicast(&init_net, skb, RDMA_NL_GROUP_IWPM, GFP_KERNEL);
11230dc5e63STatyana Nikolova 	if (ret) {
11330dc5e63STatyana Nikolova 		skb = NULL; /* skb is freed in the netlink send-op handling */
11430dc5e63STatyana Nikolova 		iwpm_user_pid = IWPM_PID_UNAVAILABLE;
11530dc5e63STatyana Nikolova 		err_str = "Unable to send a nlmsg";
11630dc5e63STatyana Nikolova 		goto pid_query_error;
11730dc5e63STatyana Nikolova 	}
11830dc5e63STatyana Nikolova 	nlmsg_request->req_buffer = pm_msg;
11930dc5e63STatyana Nikolova 	ret = iwpm_wait_complete_req(nlmsg_request);
12030dc5e63STatyana Nikolova 	return ret;
12130dc5e63STatyana Nikolova pid_query_error:
122*3cea7b4aSWenpeng Liang 	pr_info("%s: %s (client = %u)\n", __func__, err_str, nl_client);
12330dc5e63STatyana Nikolova 	dev_kfree_skb(skb);
12430dc5e63STatyana Nikolova 	if (nlmsg_request)
12530dc5e63STatyana Nikolova 		iwpm_free_nlmsg_request(&nlmsg_request->kref);
12630dc5e63STatyana Nikolova 	return ret;
12730dc5e63STatyana Nikolova }
12830dc5e63STatyana Nikolova 
129a2bfd708SSteve Wise /**
130a2bfd708SSteve Wise  * iwpm_add_mapping - Send a netlink add mapping request to
131a2bfd708SSteve Wise  *                    the userspace port mapper
132a2bfd708SSteve Wise  * @pm_msg: Contains the local ip/tcp address info to send
133a2bfd708SSteve Wise  * @nl_client: The index of the netlink client
134a2bfd708SSteve Wise  *
13530dc5e63STatyana Nikolova  * nlmsg attributes:
13630dc5e63STatyana Nikolova  *	[IWPM_NLA_MANAGE_MAPPING_SEQ]
13730dc5e63STatyana Nikolova  *	[IWPM_NLA_MANAGE_ADDR]
138b0bad9adSSteve Wise  *	[IWPM_NLA_MANAGE_FLAGS]
139a2bfd708SSteve Wise  *
140a2bfd708SSteve Wise  * If the request is successful, the pm_msg stores
141a2bfd708SSteve Wise  * the port mapper response (mapped address info)
14230dc5e63STatyana Nikolova  */
iwpm_add_mapping(struct iwpm_sa_data * pm_msg,u8 nl_client)14330dc5e63STatyana Nikolova int iwpm_add_mapping(struct iwpm_sa_data *pm_msg, u8 nl_client)
14430dc5e63STatyana Nikolova {
14530dc5e63STatyana Nikolova 	struct sk_buff *skb = NULL;
14630dc5e63STatyana Nikolova 	struct iwpm_nlmsg_request *nlmsg_request = NULL;
14730dc5e63STatyana Nikolova 	struct nlmsghdr *nlh;
14830dc5e63STatyana Nikolova 	u32 msg_seq;
14930dc5e63STatyana Nikolova 	const char *err_str = "";
15030dc5e63STatyana Nikolova 	int ret = -EINVAL;
15130dc5e63STatyana Nikolova 
152a7f2f24cSTatyana Nikolova 	if (!iwpm_valid_pid())
153a7f2f24cSTatyana Nikolova 		return 0;
154a7f2f24cSTatyana Nikolova 	if (!iwpm_check_registration(nl_client, IWPM_REG_VALID)) {
15530dc5e63STatyana Nikolova 		err_str = "Unregistered port mapper client";
15630dc5e63STatyana Nikolova 		goto add_mapping_error;
15730dc5e63STatyana Nikolova 	}
15830dc5e63STatyana Nikolova 	skb = iwpm_create_nlmsg(RDMA_NL_IWPM_ADD_MAPPING, &nlh, nl_client);
15930dc5e63STatyana Nikolova 	if (!skb) {
16030dc5e63STatyana Nikolova 		err_str = "Unable to create a nlmsg";
16130dc5e63STatyana Nikolova 		goto add_mapping_error;
16230dc5e63STatyana Nikolova 	}
16330dc5e63STatyana Nikolova 	nlh->nlmsg_seq = iwpm_get_nlmsg_seq();
16430dc5e63STatyana Nikolova 	nlmsg_request = iwpm_get_nlmsg_request(nlh->nlmsg_seq, nl_client, GFP_KERNEL);
16530dc5e63STatyana Nikolova 	if (!nlmsg_request) {
16630dc5e63STatyana Nikolova 		err_str = "Unable to allocate netlink request";
16730dc5e63STatyana Nikolova 		goto add_mapping_error;
16830dc5e63STatyana Nikolova 	}
16930dc5e63STatyana Nikolova 	msg_seq = atomic_read(&echo_nlmsg_seq);
17030dc5e63STatyana Nikolova 	/* fill in the add mapping message */
17130dc5e63STatyana Nikolova 	err_str = "Unable to put attribute of the nlmsg";
17230dc5e63STatyana Nikolova 	ret = ibnl_put_attr(skb, nlh, sizeof(u32), &msg_seq,
17330dc5e63STatyana Nikolova 				IWPM_NLA_MANAGE_MAPPING_SEQ);
17430dc5e63STatyana Nikolova 	if (ret)
17530dc5e63STatyana Nikolova 		goto add_mapping_error;
17630dc5e63STatyana Nikolova 	ret = ibnl_put_attr(skb, nlh, sizeof(struct sockaddr_storage),
17730dc5e63STatyana Nikolova 				&pm_msg->loc_addr, IWPM_NLA_MANAGE_ADDR);
17830dc5e63STatyana Nikolova 	if (ret)
17930dc5e63STatyana Nikolova 		goto add_mapping_error;
18004eae427SShiraz Saleem 
181b0bad9adSSteve Wise 	/* If flags are required and we're not V4, then return a quiet error */
182b0bad9adSSteve Wise 	if (pm_msg->flags && iwpm_ulib_version == IWPM_UABI_VERSION_MIN) {
183b0bad9adSSteve Wise 		ret = -EINVAL;
184b0bad9adSSteve Wise 		goto add_mapping_error_nowarn;
185b0bad9adSSteve Wise 	}
186b0bad9adSSteve Wise 	if (iwpm_ulib_version > IWPM_UABI_VERSION_MIN) {
187b0bad9adSSteve Wise 		ret = ibnl_put_attr(skb, nlh, sizeof(u32), &pm_msg->flags,
188b0bad9adSSteve Wise 				IWPM_NLA_MANAGE_FLAGS);
189b0bad9adSSteve Wise 		if (ret)
190b0bad9adSSteve Wise 			goto add_mapping_error;
191b0bad9adSSteve Wise 	}
192b0bad9adSSteve Wise 
19304eae427SShiraz Saleem 	nlmsg_end(skb, nlh);
19430dc5e63STatyana Nikolova 	nlmsg_request->req_buffer = pm_msg;
19530dc5e63STatyana Nikolova 
1961d2fedd8SParav Pandit 	ret = rdma_nl_unicast_wait(&init_net, skb, iwpm_user_pid);
19730dc5e63STatyana Nikolova 	if (ret) {
19830dc5e63STatyana Nikolova 		skb = NULL; /* skb is freed in the netlink send-op handling */
19930dc5e63STatyana Nikolova 		iwpm_user_pid = IWPM_PID_UNDEFINED;
20030dc5e63STatyana Nikolova 		err_str = "Unable to send a nlmsg";
20130dc5e63STatyana Nikolova 		goto add_mapping_error;
20230dc5e63STatyana Nikolova 	}
20330dc5e63STatyana Nikolova 	ret = iwpm_wait_complete_req(nlmsg_request);
20430dc5e63STatyana Nikolova 	return ret;
20530dc5e63STatyana Nikolova add_mapping_error:
206*3cea7b4aSWenpeng Liang 	pr_info("%s: %s (client = %u)\n", __func__, err_str, nl_client);
207b0bad9adSSteve Wise add_mapping_error_nowarn:
20830dc5e63STatyana Nikolova 	dev_kfree_skb(skb);
20930dc5e63STatyana Nikolova 	if (nlmsg_request)
21030dc5e63STatyana Nikolova 		iwpm_free_nlmsg_request(&nlmsg_request->kref);
21130dc5e63STatyana Nikolova 	return ret;
21230dc5e63STatyana Nikolova }
21330dc5e63STatyana Nikolova 
214a2bfd708SSteve Wise /**
215a2bfd708SSteve Wise  * iwpm_add_and_query_mapping - Process the port mapper response to
216a2bfd708SSteve Wise  *                              iwpm_add_and_query_mapping request
217a2bfd708SSteve Wise  * @pm_msg: Contains the local ip/tcp address info to send
218a2bfd708SSteve Wise  * @nl_client: The index of the netlink client
219a2bfd708SSteve Wise  *
22030dc5e63STatyana Nikolova  * nlmsg attributes:
22130dc5e63STatyana Nikolova  *	[IWPM_NLA_QUERY_MAPPING_SEQ]
22230dc5e63STatyana Nikolova  *	[IWPM_NLA_QUERY_LOCAL_ADDR]
22330dc5e63STatyana Nikolova  *	[IWPM_NLA_QUERY_REMOTE_ADDR]
224b0bad9adSSteve Wise  *	[IWPM_NLA_QUERY_FLAGS]
22530dc5e63STatyana Nikolova  */
iwpm_add_and_query_mapping(struct iwpm_sa_data * pm_msg,u8 nl_client)22630dc5e63STatyana Nikolova int iwpm_add_and_query_mapping(struct iwpm_sa_data *pm_msg, u8 nl_client)
22730dc5e63STatyana Nikolova {
22830dc5e63STatyana Nikolova 	struct sk_buff *skb = NULL;
22930dc5e63STatyana Nikolova 	struct iwpm_nlmsg_request *nlmsg_request = NULL;
23030dc5e63STatyana Nikolova 	struct nlmsghdr *nlh;
23130dc5e63STatyana Nikolova 	u32 msg_seq;
23230dc5e63STatyana Nikolova 	const char *err_str = "";
23330dc5e63STatyana Nikolova 	int ret = -EINVAL;
23430dc5e63STatyana Nikolova 
235a7f2f24cSTatyana Nikolova 	if (!iwpm_valid_pid())
236a7f2f24cSTatyana Nikolova 		return 0;
237a7f2f24cSTatyana Nikolova 	if (!iwpm_check_registration(nl_client, IWPM_REG_VALID)) {
23830dc5e63STatyana Nikolova 		err_str = "Unregistered port mapper client";
23930dc5e63STatyana Nikolova 		goto query_mapping_error;
24030dc5e63STatyana Nikolova 	}
24130dc5e63STatyana Nikolova 	ret = -ENOMEM;
24230dc5e63STatyana Nikolova 	skb = iwpm_create_nlmsg(RDMA_NL_IWPM_QUERY_MAPPING, &nlh, nl_client);
24330dc5e63STatyana Nikolova 	if (!skb) {
24430dc5e63STatyana Nikolova 		err_str = "Unable to create a nlmsg";
24530dc5e63STatyana Nikolova 		goto query_mapping_error;
24630dc5e63STatyana Nikolova 	}
24730dc5e63STatyana Nikolova 	nlh->nlmsg_seq = iwpm_get_nlmsg_seq();
24830dc5e63STatyana Nikolova 	nlmsg_request = iwpm_get_nlmsg_request(nlh->nlmsg_seq,
24930dc5e63STatyana Nikolova 				nl_client, GFP_KERNEL);
25030dc5e63STatyana Nikolova 	if (!nlmsg_request) {
25130dc5e63STatyana Nikolova 		err_str = "Unable to allocate netlink request";
25230dc5e63STatyana Nikolova 		goto query_mapping_error;
25330dc5e63STatyana Nikolova 	}
25430dc5e63STatyana Nikolova 	msg_seq = atomic_read(&echo_nlmsg_seq);
25530dc5e63STatyana Nikolova 
25630dc5e63STatyana Nikolova 	/* fill in the query message */
25730dc5e63STatyana Nikolova 	err_str = "Unable to put attribute of the nlmsg";
25830dc5e63STatyana Nikolova 	ret = ibnl_put_attr(skb, nlh, sizeof(u32), &msg_seq,
25930dc5e63STatyana Nikolova 				IWPM_NLA_QUERY_MAPPING_SEQ);
26030dc5e63STatyana Nikolova 	if (ret)
26130dc5e63STatyana Nikolova 		goto query_mapping_error;
26230dc5e63STatyana Nikolova 	ret = ibnl_put_attr(skb, nlh, sizeof(struct sockaddr_storage),
26330dc5e63STatyana Nikolova 				&pm_msg->loc_addr, IWPM_NLA_QUERY_LOCAL_ADDR);
26430dc5e63STatyana Nikolova 	if (ret)
26530dc5e63STatyana Nikolova 		goto query_mapping_error;
26630dc5e63STatyana Nikolova 	ret = ibnl_put_attr(skb, nlh, sizeof(struct sockaddr_storage),
26730dc5e63STatyana Nikolova 				&pm_msg->rem_addr, IWPM_NLA_QUERY_REMOTE_ADDR);
26830dc5e63STatyana Nikolova 	if (ret)
26930dc5e63STatyana Nikolova 		goto query_mapping_error;
27004eae427SShiraz Saleem 
271b0bad9adSSteve Wise 	/* If flags are required and we're not V4, then return a quite error */
272b0bad9adSSteve Wise 	if (pm_msg->flags && iwpm_ulib_version == IWPM_UABI_VERSION_MIN) {
273b0bad9adSSteve Wise 		ret = -EINVAL;
274b0bad9adSSteve Wise 		goto query_mapping_error_nowarn;
275b0bad9adSSteve Wise 	}
276b0bad9adSSteve Wise 	if (iwpm_ulib_version > IWPM_UABI_VERSION_MIN) {
277b0bad9adSSteve Wise 		ret = ibnl_put_attr(skb, nlh, sizeof(u32), &pm_msg->flags,
278b0bad9adSSteve Wise 				IWPM_NLA_QUERY_FLAGS);
279b0bad9adSSteve Wise 		if (ret)
280b0bad9adSSteve Wise 			goto query_mapping_error;
281b0bad9adSSteve Wise 	}
282b0bad9adSSteve Wise 
28304eae427SShiraz Saleem 	nlmsg_end(skb, nlh);
28430dc5e63STatyana Nikolova 	nlmsg_request->req_buffer = pm_msg;
28530dc5e63STatyana Nikolova 
2861d2fedd8SParav Pandit 	ret = rdma_nl_unicast_wait(&init_net, skb, iwpm_user_pid);
28730dc5e63STatyana Nikolova 	if (ret) {
28830dc5e63STatyana Nikolova 		skb = NULL; /* skb is freed in the netlink send-op handling */
28930dc5e63STatyana Nikolova 		err_str = "Unable to send a nlmsg";
29030dc5e63STatyana Nikolova 		goto query_mapping_error;
29130dc5e63STatyana Nikolova 	}
29230dc5e63STatyana Nikolova 	ret = iwpm_wait_complete_req(nlmsg_request);
29330dc5e63STatyana Nikolova 	return ret;
29430dc5e63STatyana Nikolova query_mapping_error:
295*3cea7b4aSWenpeng Liang 	pr_info("%s: %s (client = %u)\n", __func__, err_str, nl_client);
296b0bad9adSSteve Wise query_mapping_error_nowarn:
29730dc5e63STatyana Nikolova 	dev_kfree_skb(skb);
29830dc5e63STatyana Nikolova 	if (nlmsg_request)
29930dc5e63STatyana Nikolova 		iwpm_free_nlmsg_request(&nlmsg_request->kref);
30030dc5e63STatyana Nikolova 	return ret;
30130dc5e63STatyana Nikolova }
30230dc5e63STatyana Nikolova 
303a2bfd708SSteve Wise /**
304a2bfd708SSteve Wise  * iwpm_remove_mapping - Send a netlink remove mapping request
305a2bfd708SSteve Wise  *                       to the userspace port mapper
306a2bfd708SSteve Wise  *
307a2bfd708SSteve Wise  * @local_addr: Local ip/tcp address to remove
308a2bfd708SSteve Wise  * @nl_client: The index of the netlink client
309a2bfd708SSteve Wise  *
31030dc5e63STatyana Nikolova  * nlmsg attributes:
31130dc5e63STatyana Nikolova  *	[IWPM_NLA_MANAGE_MAPPING_SEQ]
31230dc5e63STatyana Nikolova  *	[IWPM_NLA_MANAGE_ADDR]
31330dc5e63STatyana Nikolova  */
iwpm_remove_mapping(struct sockaddr_storage * local_addr,u8 nl_client)31430dc5e63STatyana Nikolova int iwpm_remove_mapping(struct sockaddr_storage *local_addr, u8 nl_client)
31530dc5e63STatyana Nikolova {
31630dc5e63STatyana Nikolova 	struct sk_buff *skb = NULL;
31730dc5e63STatyana Nikolova 	struct nlmsghdr *nlh;
31830dc5e63STatyana Nikolova 	u32 msg_seq;
31930dc5e63STatyana Nikolova 	const char *err_str = "";
32030dc5e63STatyana Nikolova 	int ret = -EINVAL;
32130dc5e63STatyana Nikolova 
322a7f2f24cSTatyana Nikolova 	if (!iwpm_valid_pid())
323a7f2f24cSTatyana Nikolova 		return 0;
324a7f2f24cSTatyana Nikolova 	if (iwpm_check_registration(nl_client, IWPM_REG_UNDEF)) {
32530dc5e63STatyana Nikolova 		err_str = "Unregistered port mapper client";
32630dc5e63STatyana Nikolova 		goto remove_mapping_error;
32730dc5e63STatyana Nikolova 	}
32830dc5e63STatyana Nikolova 	skb = iwpm_create_nlmsg(RDMA_NL_IWPM_REMOVE_MAPPING, &nlh, nl_client);
32930dc5e63STatyana Nikolova 	if (!skb) {
33030dc5e63STatyana Nikolova 		ret = -ENOMEM;
33130dc5e63STatyana Nikolova 		err_str = "Unable to create a nlmsg";
33230dc5e63STatyana Nikolova 		goto remove_mapping_error;
33330dc5e63STatyana Nikolova 	}
33430dc5e63STatyana Nikolova 	msg_seq = atomic_read(&echo_nlmsg_seq);
33530dc5e63STatyana Nikolova 	nlh->nlmsg_seq = iwpm_get_nlmsg_seq();
33630dc5e63STatyana Nikolova 	err_str = "Unable to put attribute of the nlmsg";
33730dc5e63STatyana Nikolova 	ret = ibnl_put_attr(skb, nlh, sizeof(u32), &msg_seq,
33830dc5e63STatyana Nikolova 				IWPM_NLA_MANAGE_MAPPING_SEQ);
33930dc5e63STatyana Nikolova 	if (ret)
34030dc5e63STatyana Nikolova 		goto remove_mapping_error;
34130dc5e63STatyana Nikolova 	ret = ibnl_put_attr(skb, nlh, sizeof(struct sockaddr_storage),
34230dc5e63STatyana Nikolova 				local_addr, IWPM_NLA_MANAGE_ADDR);
34330dc5e63STatyana Nikolova 	if (ret)
34430dc5e63STatyana Nikolova 		goto remove_mapping_error;
34530dc5e63STatyana Nikolova 
34604eae427SShiraz Saleem 	nlmsg_end(skb, nlh);
34704eae427SShiraz Saleem 
3481d2fedd8SParav Pandit 	ret = rdma_nl_unicast_wait(&init_net, skb, iwpm_user_pid);
34930dc5e63STatyana Nikolova 	if (ret) {
35030dc5e63STatyana Nikolova 		skb = NULL; /* skb is freed in the netlink send-op handling */
35130dc5e63STatyana Nikolova 		iwpm_user_pid = IWPM_PID_UNDEFINED;
35230dc5e63STatyana Nikolova 		err_str = "Unable to send a nlmsg";
35330dc5e63STatyana Nikolova 		goto remove_mapping_error;
35430dc5e63STatyana Nikolova 	}
35530dc5e63STatyana Nikolova 	iwpm_print_sockaddr(local_addr,
35630dc5e63STatyana Nikolova 			"remove_mapping: Local sockaddr:");
35730dc5e63STatyana Nikolova 	return 0;
35830dc5e63STatyana Nikolova remove_mapping_error:
359*3cea7b4aSWenpeng Liang 	pr_info("%s: %s (client = %u)\n", __func__, err_str, nl_client);
36030dc5e63STatyana Nikolova 	if (skb)
36130dc5e63STatyana Nikolova 		dev_kfree_skb_any(skb);
36230dc5e63STatyana Nikolova 	return ret;
36330dc5e63STatyana Nikolova }
36430dc5e63STatyana Nikolova 
36530dc5e63STatyana Nikolova /* netlink attribute policy for the received response to register pid request */
36630dc5e63STatyana Nikolova static const struct nla_policy resp_reg_policy[IWPM_NLA_RREG_PID_MAX] = {
36730dc5e63STatyana Nikolova 	[IWPM_NLA_RREG_PID_SEQ]     = { .type = NLA_U32 },
36830dc5e63STatyana Nikolova 	[IWPM_NLA_RREG_IBDEV_NAME]  = { .type = NLA_STRING,
36930dc5e63STatyana Nikolova 					.len = IWPM_DEVNAME_SIZE - 1 },
37030dc5e63STatyana Nikolova 	[IWPM_NLA_RREG_ULIB_NAME]   = { .type = NLA_STRING,
37130dc5e63STatyana Nikolova 					.len = IWPM_ULIBNAME_SIZE - 1 },
37230dc5e63STatyana Nikolova 	[IWPM_NLA_RREG_ULIB_VER]    = { .type = NLA_U16 },
37330dc5e63STatyana Nikolova 	[IWPM_NLA_RREG_PID_ERR]     = { .type = NLA_U16 }
37430dc5e63STatyana Nikolova };
37530dc5e63STatyana Nikolova 
376a2bfd708SSteve Wise /**
377a2bfd708SSteve Wise  * iwpm_register_pid_cb - Process the port mapper response to
378a2bfd708SSteve Wise  *                        iwpm_register_pid query
379abfa4565SLee Jones  * @skb: The socket buffer
380a2bfd708SSteve Wise  * @cb: Contains the received message (payload and netlink header)
381a2bfd708SSteve Wise  *
382a2bfd708SSteve Wise  * If successful, the function receives the userspace port mapper pid
383a2bfd708SSteve Wise  * which is used in future communication with the port mapper
38430dc5e63STatyana Nikolova  */
iwpm_register_pid_cb(struct sk_buff * skb,struct netlink_callback * cb)38530dc5e63STatyana Nikolova int iwpm_register_pid_cb(struct sk_buff *skb, struct netlink_callback *cb)
38630dc5e63STatyana Nikolova {
38730dc5e63STatyana Nikolova 	struct iwpm_nlmsg_request *nlmsg_request = NULL;
38830dc5e63STatyana Nikolova 	struct nlattr *nltb[IWPM_NLA_RREG_PID_MAX];
38930dc5e63STatyana Nikolova 	struct iwpm_dev_data *pm_msg;
39030dc5e63STatyana Nikolova 	char *dev_name, *iwpm_name;
39130dc5e63STatyana Nikolova 	u32 msg_seq;
39230dc5e63STatyana Nikolova 	u8 nl_client;
39330dc5e63STatyana Nikolova 	u16 iwpm_version;
39430dc5e63STatyana Nikolova 	const char *msg_type = "Register Pid response";
39530dc5e63STatyana Nikolova 
39630dc5e63STatyana Nikolova 	if (iwpm_parse_nlmsg(cb, IWPM_NLA_RREG_PID_MAX,
39730dc5e63STatyana Nikolova 				resp_reg_policy, nltb, msg_type))
39830dc5e63STatyana Nikolova 		return -EINVAL;
39930dc5e63STatyana Nikolova 
40030dc5e63STatyana Nikolova 	msg_seq = nla_get_u32(nltb[IWPM_NLA_RREG_PID_SEQ]);
40130dc5e63STatyana Nikolova 	nlmsg_request = iwpm_find_nlmsg_request(msg_seq);
40230dc5e63STatyana Nikolova 	if (!nlmsg_request) {
40330dc5e63STatyana Nikolova 		pr_info("%s: Could not find a matching request (seq = %u)\n",
40430dc5e63STatyana Nikolova 				 __func__, msg_seq);
40530dc5e63STatyana Nikolova 		return -EINVAL;
40630dc5e63STatyana Nikolova 	}
40730dc5e63STatyana Nikolova 	pm_msg = nlmsg_request->req_buffer;
40830dc5e63STatyana Nikolova 	nl_client = nlmsg_request->nl_client;
40930dc5e63STatyana Nikolova 	dev_name = (char *)nla_data(nltb[IWPM_NLA_RREG_IBDEV_NAME]);
41030dc5e63STatyana Nikolova 	iwpm_name = (char *)nla_data(nltb[IWPM_NLA_RREG_ULIB_NAME]);
41130dc5e63STatyana Nikolova 	iwpm_version = nla_get_u16(nltb[IWPM_NLA_RREG_ULIB_VER]);
41230dc5e63STatyana Nikolova 
41330dc5e63STatyana Nikolova 	/* check device name, ulib name and version */
41430dc5e63STatyana Nikolova 	if (strcmp(pm_msg->dev_name, dev_name) ||
41530dc5e63STatyana Nikolova 			strcmp(iwpm_ulib_name, iwpm_name) ||
416b0bad9adSSteve Wise 			iwpm_version < IWPM_UABI_VERSION_MIN) {
41730dc5e63STatyana Nikolova 
418*3cea7b4aSWenpeng Liang 		pr_info("%s: Incorrect info (dev = %s name = %s version = %u)\n",
41930dc5e63STatyana Nikolova 				__func__, dev_name, iwpm_name, iwpm_version);
42030dc5e63STatyana Nikolova 		nlmsg_request->err_code = IWPM_USER_LIB_INFO_ERR;
42130dc5e63STatyana Nikolova 		goto register_pid_response_exit;
42230dc5e63STatyana Nikolova 	}
42330dc5e63STatyana Nikolova 	iwpm_user_pid = cb->nlh->nlmsg_pid;
424b0bad9adSSteve Wise 	iwpm_ulib_version = iwpm_version;
425b0bad9adSSteve Wise 	if (iwpm_ulib_version < IWPM_UABI_VERSION)
426*3cea7b4aSWenpeng Liang 		pr_warn_once("%s: Down level iwpmd/pid %d.  Continuing...",
427b0bad9adSSteve Wise 			__func__, iwpm_user_pid);
42830dc5e63STatyana Nikolova 	atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
42930dc5e63STatyana Nikolova 	pr_debug("%s: iWarp Port Mapper (pid = %d) is available!\n",
43030dc5e63STatyana Nikolova 			__func__, iwpm_user_pid);
431a7f2f24cSTatyana Nikolova 	iwpm_set_registration(nl_client, IWPM_REG_VALID);
43230dc5e63STatyana Nikolova register_pid_response_exit:
43330dc5e63STatyana Nikolova 	nlmsg_request->request_done = 1;
43430dc5e63STatyana Nikolova 	/* always for found nlmsg_request */
43530dc5e63STatyana Nikolova 	kref_put(&nlmsg_request->kref, iwpm_free_nlmsg_request);
43630dc5e63STatyana Nikolova 	barrier();
437dafb5587SFaisal Latif 	up(&nlmsg_request->sem);
43830dc5e63STatyana Nikolova 	return 0;
43930dc5e63STatyana Nikolova }
44030dc5e63STatyana Nikolova 
44130dc5e63STatyana Nikolova /* netlink attribute policy for the received response to add mapping request */
44230dc5e63STatyana Nikolova static const struct nla_policy resp_add_policy[IWPM_NLA_RMANAGE_MAPPING_MAX] = {
443f76903d5SSteve Wise 	[IWPM_NLA_RMANAGE_MAPPING_SEQ]     = { .type = NLA_U32 },
444f76903d5SSteve Wise 	[IWPM_NLA_RMANAGE_ADDR]            = {
445f76903d5SSteve Wise 				.len = sizeof(struct sockaddr_storage) },
446f76903d5SSteve Wise 	[IWPM_NLA_RMANAGE_MAPPED_LOC_ADDR] = {
447f76903d5SSteve Wise 				.len = sizeof(struct sockaddr_storage) },
44830dc5e63STatyana Nikolova 	[IWPM_NLA_RMANAGE_MAPPING_ERR]	   = { .type = NLA_U16 }
44930dc5e63STatyana Nikolova };
45030dc5e63STatyana Nikolova 
451a2bfd708SSteve Wise /**
452a2bfd708SSteve Wise  * iwpm_add_mapping_cb - Process the port mapper response to
453a2bfd708SSteve Wise  *                       iwpm_add_mapping request
454abfa4565SLee Jones  * @skb: The socket buffer
455a2bfd708SSteve Wise  * @cb: Contains the received message (payload and netlink header)
45630dc5e63STatyana Nikolova  */
iwpm_add_mapping_cb(struct sk_buff * skb,struct netlink_callback * cb)45730dc5e63STatyana Nikolova int iwpm_add_mapping_cb(struct sk_buff *skb, struct netlink_callback *cb)
45830dc5e63STatyana Nikolova {
45930dc5e63STatyana Nikolova 	struct iwpm_sa_data *pm_msg;
46030dc5e63STatyana Nikolova 	struct iwpm_nlmsg_request *nlmsg_request = NULL;
46130dc5e63STatyana Nikolova 	struct nlattr *nltb[IWPM_NLA_RMANAGE_MAPPING_MAX];
46230dc5e63STatyana Nikolova 	struct sockaddr_storage *local_sockaddr;
46330dc5e63STatyana Nikolova 	struct sockaddr_storage *mapped_sockaddr;
46430dc5e63STatyana Nikolova 	const char *msg_type;
46530dc5e63STatyana Nikolova 	u32 msg_seq;
46630dc5e63STatyana Nikolova 
46730dc5e63STatyana Nikolova 	msg_type = "Add Mapping response";
46830dc5e63STatyana Nikolova 	if (iwpm_parse_nlmsg(cb, IWPM_NLA_RMANAGE_MAPPING_MAX,
46930dc5e63STatyana Nikolova 				resp_add_policy, nltb, msg_type))
47030dc5e63STatyana Nikolova 		return -EINVAL;
47130dc5e63STatyana Nikolova 
47230dc5e63STatyana Nikolova 	atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
47330dc5e63STatyana Nikolova 
474f76903d5SSteve Wise 	msg_seq = nla_get_u32(nltb[IWPM_NLA_RMANAGE_MAPPING_SEQ]);
47530dc5e63STatyana Nikolova 	nlmsg_request = iwpm_find_nlmsg_request(msg_seq);
47630dc5e63STatyana Nikolova 	if (!nlmsg_request) {
47730dc5e63STatyana Nikolova 		pr_info("%s: Could not find a matching request (seq = %u)\n",
47830dc5e63STatyana Nikolova 				 __func__, msg_seq);
47930dc5e63STatyana Nikolova 		return -EINVAL;
48030dc5e63STatyana Nikolova 	}
48130dc5e63STatyana Nikolova 	pm_msg = nlmsg_request->req_buffer;
48230dc5e63STatyana Nikolova 	local_sockaddr = (struct sockaddr_storage *)
483f76903d5SSteve Wise 			nla_data(nltb[IWPM_NLA_RMANAGE_ADDR]);
48430dc5e63STatyana Nikolova 	mapped_sockaddr = (struct sockaddr_storage *)
485f76903d5SSteve Wise 			nla_data(nltb[IWPM_NLA_RMANAGE_MAPPED_LOC_ADDR]);
48630dc5e63STatyana Nikolova 
48730dc5e63STatyana Nikolova 	if (iwpm_compare_sockaddr(local_sockaddr, &pm_msg->loc_addr)) {
48830dc5e63STatyana Nikolova 		nlmsg_request->err_code = IWPM_USER_LIB_INFO_ERR;
48930dc5e63STatyana Nikolova 		goto add_mapping_response_exit;
49030dc5e63STatyana Nikolova 	}
49130dc5e63STatyana Nikolova 	if (mapped_sockaddr->ss_family != local_sockaddr->ss_family) {
49230dc5e63STatyana Nikolova 		pr_info("%s: Sockaddr family doesn't match the requested one\n",
49330dc5e63STatyana Nikolova 				__func__);
49430dc5e63STatyana Nikolova 		nlmsg_request->err_code = IWPM_USER_LIB_INFO_ERR;
49530dc5e63STatyana Nikolova 		goto add_mapping_response_exit;
49630dc5e63STatyana Nikolova 	}
49730dc5e63STatyana Nikolova 	memcpy(&pm_msg->mapped_loc_addr, mapped_sockaddr,
49830dc5e63STatyana Nikolova 			sizeof(*mapped_sockaddr));
49930dc5e63STatyana Nikolova 	iwpm_print_sockaddr(&pm_msg->loc_addr,
50030dc5e63STatyana Nikolova 			"add_mapping: Local sockaddr:");
50130dc5e63STatyana Nikolova 	iwpm_print_sockaddr(&pm_msg->mapped_loc_addr,
50230dc5e63STatyana Nikolova 			"add_mapping: Mapped local sockaddr:");
50330dc5e63STatyana Nikolova 
50430dc5e63STatyana Nikolova add_mapping_response_exit:
50530dc5e63STatyana Nikolova 	nlmsg_request->request_done = 1;
50630dc5e63STatyana Nikolova 	/* always for found request */
50730dc5e63STatyana Nikolova 	kref_put(&nlmsg_request->kref, iwpm_free_nlmsg_request);
50830dc5e63STatyana Nikolova 	barrier();
509dafb5587SFaisal Latif 	up(&nlmsg_request->sem);
51030dc5e63STatyana Nikolova 	return 0;
51130dc5e63STatyana Nikolova }
51230dc5e63STatyana Nikolova 
5136eec1774STatyana Nikolova /* netlink attribute policy for the response to add and query mapping request
51426caea5fSWenpeng Liang  * and response with remote address info
51526caea5fSWenpeng Liang  */
51630dc5e63STatyana Nikolova static const struct nla_policy resp_query_policy[IWPM_NLA_RQUERY_MAPPING_MAX] = {
517f76903d5SSteve Wise 	[IWPM_NLA_RQUERY_MAPPING_SEQ]     = { .type = NLA_U32 },
518f76903d5SSteve Wise 	[IWPM_NLA_RQUERY_LOCAL_ADDR]      = {
519f76903d5SSteve Wise 				.len = sizeof(struct sockaddr_storage) },
520f76903d5SSteve Wise 	[IWPM_NLA_RQUERY_REMOTE_ADDR]     = {
521f76903d5SSteve Wise 				.len = sizeof(struct sockaddr_storage) },
522f76903d5SSteve Wise 	[IWPM_NLA_RQUERY_MAPPED_LOC_ADDR] = {
523f76903d5SSteve Wise 				.len = sizeof(struct sockaddr_storage) },
524f76903d5SSteve Wise 	[IWPM_NLA_RQUERY_MAPPED_REM_ADDR] = {
525f76903d5SSteve Wise 				.len = sizeof(struct sockaddr_storage) },
52630dc5e63STatyana Nikolova 	[IWPM_NLA_RQUERY_MAPPING_ERR]	  = { .type = NLA_U16 }
52730dc5e63STatyana Nikolova };
52830dc5e63STatyana Nikolova 
529a2bfd708SSteve Wise /**
530a2bfd708SSteve Wise  * iwpm_add_and_query_mapping_cb - Process the port mapper response to
531a2bfd708SSteve Wise  *                                 iwpm_add_and_query_mapping request
532abfa4565SLee Jones  * @skb: The socket buffer
533a2bfd708SSteve Wise  * @cb: Contains the received message (payload and netlink header)
53430dc5e63STatyana Nikolova  */
iwpm_add_and_query_mapping_cb(struct sk_buff * skb,struct netlink_callback * cb)53530dc5e63STatyana Nikolova int iwpm_add_and_query_mapping_cb(struct sk_buff *skb,
53630dc5e63STatyana Nikolova 				struct netlink_callback *cb)
53730dc5e63STatyana Nikolova {
53830dc5e63STatyana Nikolova 	struct iwpm_sa_data *pm_msg;
53930dc5e63STatyana Nikolova 	struct iwpm_nlmsg_request *nlmsg_request = NULL;
54030dc5e63STatyana Nikolova 	struct nlattr *nltb[IWPM_NLA_RQUERY_MAPPING_MAX];
54130dc5e63STatyana Nikolova 	struct sockaddr_storage *local_sockaddr, *remote_sockaddr;
54230dc5e63STatyana Nikolova 	struct sockaddr_storage *mapped_loc_sockaddr, *mapped_rem_sockaddr;
54330dc5e63STatyana Nikolova 	const char *msg_type;
54430dc5e63STatyana Nikolova 	u32 msg_seq;
54530dc5e63STatyana Nikolova 	u16 err_code;
54630dc5e63STatyana Nikolova 
54730dc5e63STatyana Nikolova 	msg_type = "Query Mapping response";
54830dc5e63STatyana Nikolova 	if (iwpm_parse_nlmsg(cb, IWPM_NLA_RQUERY_MAPPING_MAX,
54930dc5e63STatyana Nikolova 				resp_query_policy, nltb, msg_type))
55030dc5e63STatyana Nikolova 		return -EINVAL;
55130dc5e63STatyana Nikolova 	atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
55230dc5e63STatyana Nikolova 
553f76903d5SSteve Wise 	msg_seq = nla_get_u32(nltb[IWPM_NLA_RQUERY_MAPPING_SEQ]);
55430dc5e63STatyana Nikolova 	nlmsg_request = iwpm_find_nlmsg_request(msg_seq);
55530dc5e63STatyana Nikolova 	if (!nlmsg_request) {
55630dc5e63STatyana Nikolova 		pr_info("%s: Could not find a matching request (seq = %u)\n",
55730dc5e63STatyana Nikolova 				 __func__, msg_seq);
55830dc5e63STatyana Nikolova 		return -EINVAL;
55930dc5e63STatyana Nikolova 	}
56030dc5e63STatyana Nikolova 	pm_msg = nlmsg_request->req_buffer;
56130dc5e63STatyana Nikolova 	local_sockaddr = (struct sockaddr_storage *)
562f76903d5SSteve Wise 			nla_data(nltb[IWPM_NLA_RQUERY_LOCAL_ADDR]);
56330dc5e63STatyana Nikolova 	remote_sockaddr = (struct sockaddr_storage *)
564f76903d5SSteve Wise 			nla_data(nltb[IWPM_NLA_RQUERY_REMOTE_ADDR]);
56530dc5e63STatyana Nikolova 	mapped_loc_sockaddr = (struct sockaddr_storage *)
56630dc5e63STatyana Nikolova 			nla_data(nltb[IWPM_NLA_RQUERY_MAPPED_LOC_ADDR]);
56730dc5e63STatyana Nikolova 	mapped_rem_sockaddr = (struct sockaddr_storage *)
56830dc5e63STatyana Nikolova 			nla_data(nltb[IWPM_NLA_RQUERY_MAPPED_REM_ADDR]);
56930dc5e63STatyana Nikolova 
57030dc5e63STatyana Nikolova 	err_code = nla_get_u16(nltb[IWPM_NLA_RQUERY_MAPPING_ERR]);
57130dc5e63STatyana Nikolova 	if (err_code == IWPM_REMOTE_QUERY_REJECT) {
57230dc5e63STatyana Nikolova 		pr_info("%s: Received a Reject (pid = %u, echo seq = %u)\n",
57330dc5e63STatyana Nikolova 			__func__, cb->nlh->nlmsg_pid, msg_seq);
57430dc5e63STatyana Nikolova 		nlmsg_request->err_code = IWPM_REMOTE_QUERY_REJECT;
57530dc5e63STatyana Nikolova 	}
57630dc5e63STatyana Nikolova 	if (iwpm_compare_sockaddr(local_sockaddr, &pm_msg->loc_addr) ||
57730dc5e63STatyana Nikolova 		iwpm_compare_sockaddr(remote_sockaddr, &pm_msg->rem_addr)) {
57830dc5e63STatyana Nikolova 		pr_info("%s: Incorrect local sockaddr\n", __func__);
57930dc5e63STatyana Nikolova 		nlmsg_request->err_code = IWPM_USER_LIB_INFO_ERR;
58030dc5e63STatyana Nikolova 		goto query_mapping_response_exit;
58130dc5e63STatyana Nikolova 	}
58230dc5e63STatyana Nikolova 	if (mapped_loc_sockaddr->ss_family != local_sockaddr->ss_family ||
58330dc5e63STatyana Nikolova 		mapped_rem_sockaddr->ss_family != remote_sockaddr->ss_family) {
58430dc5e63STatyana Nikolova 		pr_info("%s: Sockaddr family doesn't match the requested one\n",
58530dc5e63STatyana Nikolova 				__func__);
58630dc5e63STatyana Nikolova 		nlmsg_request->err_code = IWPM_USER_LIB_INFO_ERR;
58730dc5e63STatyana Nikolova 		goto query_mapping_response_exit;
58830dc5e63STatyana Nikolova 	}
58930dc5e63STatyana Nikolova 	memcpy(&pm_msg->mapped_loc_addr, mapped_loc_sockaddr,
59030dc5e63STatyana Nikolova 			sizeof(*mapped_loc_sockaddr));
59130dc5e63STatyana Nikolova 	memcpy(&pm_msg->mapped_rem_addr, mapped_rem_sockaddr,
59230dc5e63STatyana Nikolova 			sizeof(*mapped_rem_sockaddr));
59330dc5e63STatyana Nikolova 
59430dc5e63STatyana Nikolova 	iwpm_print_sockaddr(&pm_msg->loc_addr,
59530dc5e63STatyana Nikolova 			"query_mapping: Local sockaddr:");
59630dc5e63STatyana Nikolova 	iwpm_print_sockaddr(&pm_msg->mapped_loc_addr,
59730dc5e63STatyana Nikolova 			"query_mapping: Mapped local sockaddr:");
59830dc5e63STatyana Nikolova 	iwpm_print_sockaddr(&pm_msg->rem_addr,
59930dc5e63STatyana Nikolova 			"query_mapping: Remote sockaddr:");
60030dc5e63STatyana Nikolova 	iwpm_print_sockaddr(&pm_msg->mapped_rem_addr,
60130dc5e63STatyana Nikolova 			"query_mapping: Mapped remote sockaddr:");
60230dc5e63STatyana Nikolova query_mapping_response_exit:
60330dc5e63STatyana Nikolova 	nlmsg_request->request_done = 1;
60430dc5e63STatyana Nikolova 	/* always for found request */
60530dc5e63STatyana Nikolova 	kref_put(&nlmsg_request->kref, iwpm_free_nlmsg_request);
60630dc5e63STatyana Nikolova 	barrier();
607dafb5587SFaisal Latif 	up(&nlmsg_request->sem);
60830dc5e63STatyana Nikolova 	return 0;
60930dc5e63STatyana Nikolova }
61030dc5e63STatyana Nikolova 
611a2bfd708SSteve Wise /**
612a2bfd708SSteve Wise  * iwpm_remote_info_cb - Process remote connecting peer address info, which
613a2bfd708SSteve Wise  *                       the port mapper has received from the connecting peer
614abfa4565SLee Jones  * @skb: The socket buffer
615a2bfd708SSteve Wise  * @cb: Contains the received message (payload and netlink header)
616a2bfd708SSteve Wise  *
617a2bfd708SSteve Wise  * Stores the IPv4/IPv6 address info in a hash table
6186eec1774STatyana Nikolova  */
iwpm_remote_info_cb(struct sk_buff * skb,struct netlink_callback * cb)6196eec1774STatyana Nikolova int iwpm_remote_info_cb(struct sk_buff *skb, struct netlink_callback *cb)
6206eec1774STatyana Nikolova {
6216eec1774STatyana Nikolova 	struct nlattr *nltb[IWPM_NLA_RQUERY_MAPPING_MAX];
6226eec1774STatyana Nikolova 	struct sockaddr_storage *local_sockaddr, *remote_sockaddr;
6236eec1774STatyana Nikolova 	struct sockaddr_storage *mapped_loc_sockaddr, *mapped_rem_sockaddr;
6246eec1774STatyana Nikolova 	struct iwpm_remote_info *rem_info;
6256eec1774STatyana Nikolova 	const char *msg_type;
6266eec1774STatyana Nikolova 	u8 nl_client;
6276eec1774STatyana Nikolova 	int ret = -EINVAL;
6286eec1774STatyana Nikolova 
6296eec1774STatyana Nikolova 	msg_type = "Remote Mapping info";
6306eec1774STatyana Nikolova 	if (iwpm_parse_nlmsg(cb, IWPM_NLA_RQUERY_MAPPING_MAX,
6316eec1774STatyana Nikolova 				resp_query_policy, nltb, msg_type))
6326eec1774STatyana Nikolova 		return ret;
6336eec1774STatyana Nikolova 
6346eec1774STatyana Nikolova 	nl_client = RDMA_NL_GET_CLIENT(cb->nlh->nlmsg_type);
6356eec1774STatyana Nikolova 	atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
6366eec1774STatyana Nikolova 
6376eec1774STatyana Nikolova 	local_sockaddr = (struct sockaddr_storage *)
638f76903d5SSteve Wise 			nla_data(nltb[IWPM_NLA_RQUERY_LOCAL_ADDR]);
6396eec1774STatyana Nikolova 	remote_sockaddr = (struct sockaddr_storage *)
640f76903d5SSteve Wise 			nla_data(nltb[IWPM_NLA_RQUERY_REMOTE_ADDR]);
6416eec1774STatyana Nikolova 	mapped_loc_sockaddr = (struct sockaddr_storage *)
6426eec1774STatyana Nikolova 			nla_data(nltb[IWPM_NLA_RQUERY_MAPPED_LOC_ADDR]);
6436eec1774STatyana Nikolova 	mapped_rem_sockaddr = (struct sockaddr_storage *)
6446eec1774STatyana Nikolova 			nla_data(nltb[IWPM_NLA_RQUERY_MAPPED_REM_ADDR]);
6456eec1774STatyana Nikolova 
6466eec1774STatyana Nikolova 	if (mapped_loc_sockaddr->ss_family != local_sockaddr->ss_family ||
6476eec1774STatyana Nikolova 		mapped_rem_sockaddr->ss_family != remote_sockaddr->ss_family) {
6486eec1774STatyana Nikolova 		pr_info("%s: Sockaddr family doesn't match the requested one\n",
6496eec1774STatyana Nikolova 				__func__);
6506eec1774STatyana Nikolova 		return ret;
6516eec1774STatyana Nikolova 	}
6526eec1774STatyana Nikolova 	rem_info = kzalloc(sizeof(struct iwpm_remote_info), GFP_ATOMIC);
6536eec1774STatyana Nikolova 	if (!rem_info) {
6546eec1774STatyana Nikolova 		ret = -ENOMEM;
6556eec1774STatyana Nikolova 		return ret;
6566eec1774STatyana Nikolova 	}
6576eec1774STatyana Nikolova 	memcpy(&rem_info->mapped_loc_sockaddr, mapped_loc_sockaddr,
6586eec1774STatyana Nikolova 	       sizeof(struct sockaddr_storage));
6596eec1774STatyana Nikolova 	memcpy(&rem_info->remote_sockaddr, remote_sockaddr,
6606eec1774STatyana Nikolova 	       sizeof(struct sockaddr_storage));
6616eec1774STatyana Nikolova 	memcpy(&rem_info->mapped_rem_sockaddr, mapped_rem_sockaddr,
6626eec1774STatyana Nikolova 	       sizeof(struct sockaddr_storage));
6636eec1774STatyana Nikolova 	rem_info->nl_client = nl_client;
6646eec1774STatyana Nikolova 
6656eec1774STatyana Nikolova 	iwpm_add_remote_info(rem_info);
6666eec1774STatyana Nikolova 
6676eec1774STatyana Nikolova 	iwpm_print_sockaddr(local_sockaddr,
6686eec1774STatyana Nikolova 			"remote_info: Local sockaddr:");
6696eec1774STatyana Nikolova 	iwpm_print_sockaddr(mapped_loc_sockaddr,
6706eec1774STatyana Nikolova 			"remote_info: Mapped local sockaddr:");
6716eec1774STatyana Nikolova 	iwpm_print_sockaddr(remote_sockaddr,
6726eec1774STatyana Nikolova 			"remote_info: Remote sockaddr:");
6736eec1774STatyana Nikolova 	iwpm_print_sockaddr(mapped_rem_sockaddr,
6746eec1774STatyana Nikolova 			"remote_info: Mapped remote sockaddr:");
6756eec1774STatyana Nikolova 	return ret;
6766eec1774STatyana Nikolova }
6776eec1774STatyana Nikolova 
67830dc5e63STatyana Nikolova /* netlink attribute policy for the received request for mapping info */
67930dc5e63STatyana Nikolova static const struct nla_policy resp_mapinfo_policy[IWPM_NLA_MAPINFO_REQ_MAX] = {
68030dc5e63STatyana Nikolova 	[IWPM_NLA_MAPINFO_ULIB_NAME] = { .type = NLA_STRING,
68130dc5e63STatyana Nikolova 					.len = IWPM_ULIBNAME_SIZE - 1 },
68230dc5e63STatyana Nikolova 	[IWPM_NLA_MAPINFO_ULIB_VER]  = { .type = NLA_U16 }
68330dc5e63STatyana Nikolova };
68430dc5e63STatyana Nikolova 
685a2bfd708SSteve Wise /**
686a2bfd708SSteve Wise  * iwpm_mapping_info_cb - Process a notification that the userspace
687a2bfd708SSteve Wise  *                        port mapper daemon is started
688abfa4565SLee Jones  * @skb: The socket buffer
689a2bfd708SSteve Wise  * @cb: Contains the received message (payload and netlink header)
690a2bfd708SSteve Wise  *
691a2bfd708SSteve Wise  * Using the received port mapper pid, send all the local mapping
692a2bfd708SSteve Wise  * info records to the userspace port mapper
69330dc5e63STatyana Nikolova  */
iwpm_mapping_info_cb(struct sk_buff * skb,struct netlink_callback * cb)69430dc5e63STatyana Nikolova int iwpm_mapping_info_cb(struct sk_buff *skb, struct netlink_callback *cb)
69530dc5e63STatyana Nikolova {
69630dc5e63STatyana Nikolova 	struct nlattr *nltb[IWPM_NLA_MAPINFO_REQ_MAX];
69730dc5e63STatyana Nikolova 	const char *msg_type = "Mapping Info response";
69830dc5e63STatyana Nikolova 	u8 nl_client;
69930dc5e63STatyana Nikolova 	char *iwpm_name;
70030dc5e63STatyana Nikolova 	u16 iwpm_version;
70130dc5e63STatyana Nikolova 	int ret = -EINVAL;
70230dc5e63STatyana Nikolova 
70330dc5e63STatyana Nikolova 	if (iwpm_parse_nlmsg(cb, IWPM_NLA_MAPINFO_REQ_MAX,
70430dc5e63STatyana Nikolova 				resp_mapinfo_policy, nltb, msg_type)) {
70530dc5e63STatyana Nikolova 		pr_info("%s: Unable to parse nlmsg\n", __func__);
70630dc5e63STatyana Nikolova 		return ret;
70730dc5e63STatyana Nikolova 	}
70830dc5e63STatyana Nikolova 	iwpm_name = (char *)nla_data(nltb[IWPM_NLA_MAPINFO_ULIB_NAME]);
70930dc5e63STatyana Nikolova 	iwpm_version = nla_get_u16(nltb[IWPM_NLA_MAPINFO_ULIB_VER]);
71030dc5e63STatyana Nikolova 	if (strcmp(iwpm_ulib_name, iwpm_name) ||
711b0bad9adSSteve Wise 			iwpm_version < IWPM_UABI_VERSION_MIN) {
712*3cea7b4aSWenpeng Liang 		pr_info("%s: Invalid port mapper name = %s version = %u\n",
71330dc5e63STatyana Nikolova 				__func__, iwpm_name, iwpm_version);
71430dc5e63STatyana Nikolova 		return ret;
71530dc5e63STatyana Nikolova 	}
71630dc5e63STatyana Nikolova 	nl_client = RDMA_NL_GET_CLIENT(cb->nlh->nlmsg_type);
717a7f2f24cSTatyana Nikolova 	iwpm_set_registration(nl_client, IWPM_REG_INCOMPL);
71830dc5e63STatyana Nikolova 	atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
719a7f2f24cSTatyana Nikolova 	iwpm_user_pid = cb->nlh->nlmsg_pid;
720b0bad9adSSteve Wise 
721b0bad9adSSteve Wise 	if (iwpm_ulib_version < IWPM_UABI_VERSION)
722*3cea7b4aSWenpeng Liang 		pr_warn_once("%s: Down level iwpmd/pid %d.  Continuing...",
723b0bad9adSSteve Wise 			__func__, iwpm_user_pid);
724b0bad9adSSteve Wise 
72530dc5e63STatyana Nikolova 	if (!iwpm_mapinfo_available())
72630dc5e63STatyana Nikolova 		return 0;
72730dc5e63STatyana Nikolova 	pr_debug("%s: iWarp Port Mapper (pid = %d) is available!\n",
728a7f2f24cSTatyana Nikolova 		 __func__, iwpm_user_pid);
729a7f2f24cSTatyana Nikolova 	ret = iwpm_send_mapinfo(nl_client, iwpm_user_pid);
73030dc5e63STatyana Nikolova 	return ret;
73130dc5e63STatyana Nikolova }
73230dc5e63STatyana Nikolova 
73330dc5e63STatyana Nikolova /* netlink attribute policy for the received mapping info ack */
73430dc5e63STatyana Nikolova static const struct nla_policy ack_mapinfo_policy[IWPM_NLA_MAPINFO_NUM_MAX] = {
73530dc5e63STatyana Nikolova 	[IWPM_NLA_MAPINFO_SEQ]    =   { .type = NLA_U32 },
73630dc5e63STatyana Nikolova 	[IWPM_NLA_MAPINFO_SEND_NUM] = { .type = NLA_U32 },
73730dc5e63STatyana Nikolova 	[IWPM_NLA_MAPINFO_ACK_NUM] =  { .type = NLA_U32 }
73830dc5e63STatyana Nikolova };
73930dc5e63STatyana Nikolova 
740a2bfd708SSteve Wise /**
741a2bfd708SSteve Wise  * iwpm_ack_mapping_info_cb - Process the port mapper ack for
742a2bfd708SSteve Wise  *                            the provided local mapping info records
743abfa4565SLee Jones  * @skb: The socket buffer
744a2bfd708SSteve Wise  * @cb: Contains the received message (payload and netlink header)
74530dc5e63STatyana Nikolova  */
iwpm_ack_mapping_info_cb(struct sk_buff * skb,struct netlink_callback * cb)74630dc5e63STatyana Nikolova int iwpm_ack_mapping_info_cb(struct sk_buff *skb, struct netlink_callback *cb)
74730dc5e63STatyana Nikolova {
74830dc5e63STatyana Nikolova 	struct nlattr *nltb[IWPM_NLA_MAPINFO_NUM_MAX];
74930dc5e63STatyana Nikolova 	u32 mapinfo_send, mapinfo_ack;
75030dc5e63STatyana Nikolova 	const char *msg_type = "Mapping Info Ack";
75130dc5e63STatyana Nikolova 
75230dc5e63STatyana Nikolova 	if (iwpm_parse_nlmsg(cb, IWPM_NLA_MAPINFO_NUM_MAX,
75330dc5e63STatyana Nikolova 				ack_mapinfo_policy, nltb, msg_type))
75430dc5e63STatyana Nikolova 		return -EINVAL;
75530dc5e63STatyana Nikolova 	mapinfo_send = nla_get_u32(nltb[IWPM_NLA_MAPINFO_SEND_NUM]);
75630dc5e63STatyana Nikolova 	mapinfo_ack = nla_get_u32(nltb[IWPM_NLA_MAPINFO_ACK_NUM]);
75730dc5e63STatyana Nikolova 	if (mapinfo_ack != mapinfo_send)
75830dc5e63STatyana Nikolova 		pr_info("%s: Invalid mapinfo number (sent = %u ack-ed = %u)\n",
75930dc5e63STatyana Nikolova 			__func__, mapinfo_send, mapinfo_ack);
76030dc5e63STatyana Nikolova 	atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
76130dc5e63STatyana Nikolova 	return 0;
76230dc5e63STatyana Nikolova }
76330dc5e63STatyana Nikolova 
76430dc5e63STatyana Nikolova /* netlink attribute policy for the received port mapper error message */
76530dc5e63STatyana Nikolova static const struct nla_policy map_error_policy[IWPM_NLA_ERR_MAX] = {
76630dc5e63STatyana Nikolova 	[IWPM_NLA_ERR_SEQ]        = { .type = NLA_U32 },
76730dc5e63STatyana Nikolova 	[IWPM_NLA_ERR_CODE]       = { .type = NLA_U16 },
76830dc5e63STatyana Nikolova };
76930dc5e63STatyana Nikolova 
770a2bfd708SSteve Wise /**
771a2bfd708SSteve Wise  * iwpm_mapping_error_cb - Process port mapper notification for error
772a2bfd708SSteve Wise  *
773abfa4565SLee Jones  * @skb: The socket buffer
774a2bfd708SSteve Wise  * @cb: Contains the received message (payload and netlink header)
77530dc5e63STatyana Nikolova  */
iwpm_mapping_error_cb(struct sk_buff * skb,struct netlink_callback * cb)77630dc5e63STatyana Nikolova int iwpm_mapping_error_cb(struct sk_buff *skb, struct netlink_callback *cb)
77730dc5e63STatyana Nikolova {
77830dc5e63STatyana Nikolova 	struct iwpm_nlmsg_request *nlmsg_request = NULL;
77930dc5e63STatyana Nikolova 	int nl_client = RDMA_NL_GET_CLIENT(cb->nlh->nlmsg_type);
78030dc5e63STatyana Nikolova 	struct nlattr *nltb[IWPM_NLA_ERR_MAX];
78130dc5e63STatyana Nikolova 	u32 msg_seq;
78230dc5e63STatyana Nikolova 	u16 err_code;
78330dc5e63STatyana Nikolova 	const char *msg_type = "Mapping Error Msg";
78430dc5e63STatyana Nikolova 
78530dc5e63STatyana Nikolova 	if (iwpm_parse_nlmsg(cb, IWPM_NLA_ERR_MAX,
78630dc5e63STatyana Nikolova 				map_error_policy, nltb, msg_type))
78730dc5e63STatyana Nikolova 		return -EINVAL;
78830dc5e63STatyana Nikolova 
78930dc5e63STatyana Nikolova 	msg_seq = nla_get_u32(nltb[IWPM_NLA_ERR_SEQ]);
79030dc5e63STatyana Nikolova 	err_code = nla_get_u16(nltb[IWPM_NLA_ERR_CODE]);
79130dc5e63STatyana Nikolova 	pr_info("%s: Received msg seq = %u err code = %u client = %d\n",
79230dc5e63STatyana Nikolova 				__func__, msg_seq, err_code, nl_client);
79330dc5e63STatyana Nikolova 	/* look for nlmsg_request */
79430dc5e63STatyana Nikolova 	nlmsg_request = iwpm_find_nlmsg_request(msg_seq);
79530dc5e63STatyana Nikolova 	if (!nlmsg_request) {
79630dc5e63STatyana Nikolova 		/* not all errors have associated requests */
79730dc5e63STatyana Nikolova 		pr_debug("Could not find matching req (seq = %u)\n", msg_seq);
79830dc5e63STatyana Nikolova 		return 0;
79930dc5e63STatyana Nikolova 	}
80030dc5e63STatyana Nikolova 	atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
80130dc5e63STatyana Nikolova 	nlmsg_request->err_code = err_code;
80230dc5e63STatyana Nikolova 	nlmsg_request->request_done = 1;
80330dc5e63STatyana Nikolova 	/* always for found request */
80430dc5e63STatyana Nikolova 	kref_put(&nlmsg_request->kref, iwpm_free_nlmsg_request);
80530dc5e63STatyana Nikolova 	barrier();
806dafb5587SFaisal Latif 	up(&nlmsg_request->sem);
80730dc5e63STatyana Nikolova 	return 0;
80830dc5e63STatyana Nikolova }
809b0bad9adSSteve Wise 
810b0bad9adSSteve Wise /* netlink attribute policy for the received hello request */
811b0bad9adSSteve Wise static const struct nla_policy hello_policy[IWPM_NLA_HELLO_MAX] = {
812b0bad9adSSteve Wise 	[IWPM_NLA_HELLO_ABI_VERSION]     = { .type = NLA_U16 }
813b0bad9adSSteve Wise };
814b0bad9adSSteve Wise 
815a2bfd708SSteve Wise /**
816a2bfd708SSteve Wise  * iwpm_hello_cb - Process a hello message from iwpmd
817a2bfd708SSteve Wise  *
818abfa4565SLee Jones  * @skb: The socket buffer
819a2bfd708SSteve Wise  * @cb: Contains the received message (payload and netlink header)
820a2bfd708SSteve Wise  *
821a2bfd708SSteve Wise  * Using the received port mapper pid, send the kernel's abi_version
822a2bfd708SSteve Wise  * after adjusting it to support the iwpmd version.
823b0bad9adSSteve Wise  */
iwpm_hello_cb(struct sk_buff * skb,struct netlink_callback * cb)824b0bad9adSSteve Wise int iwpm_hello_cb(struct sk_buff *skb, struct netlink_callback *cb)
825b0bad9adSSteve Wise {
826b0bad9adSSteve Wise 	struct nlattr *nltb[IWPM_NLA_HELLO_MAX];
827b0bad9adSSteve Wise 	const char *msg_type = "Hello request";
828b0bad9adSSteve Wise 	u8 nl_client;
829b0bad9adSSteve Wise 	u16 abi_version;
830b0bad9adSSteve Wise 	int ret = -EINVAL;
831b0bad9adSSteve Wise 
832b0bad9adSSteve Wise 	if (iwpm_parse_nlmsg(cb, IWPM_NLA_HELLO_MAX, hello_policy, nltb,
833b0bad9adSSteve Wise 			     msg_type)) {
834b0bad9adSSteve Wise 		pr_info("%s: Unable to parse nlmsg\n", __func__);
835b0bad9adSSteve Wise 		return ret;
836b0bad9adSSteve Wise 	}
837b0bad9adSSteve Wise 	abi_version = nla_get_u16(nltb[IWPM_NLA_HELLO_ABI_VERSION]);
838b0bad9adSSteve Wise 	nl_client = RDMA_NL_GET_CLIENT(cb->nlh->nlmsg_type);
839b0bad9adSSteve Wise 	iwpm_set_registration(nl_client, IWPM_REG_INCOMPL);
840b0bad9adSSteve Wise 	atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
841b0bad9adSSteve Wise 	iwpm_ulib_version = min_t(u16, IWPM_UABI_VERSION, abi_version);
842b0bad9adSSteve Wise 	pr_debug("Using ABI version %u\n", iwpm_ulib_version);
843b0bad9adSSteve Wise 	iwpm_user_pid = cb->nlh->nlmsg_pid;
844b0bad9adSSteve Wise 	ret = iwpm_send_hello(nl_client, iwpm_user_pid, iwpm_ulib_version);
845b0bad9adSSteve Wise 	return ret;
846b0bad9adSSteve Wise }
847