]>
Commit | Line | Data |
---|---|---|
30dc5e63 TN |
1 | /* |
2 | * Copyright (c) 2014 Intel Corporation. All rights reserved. | |
3 | * Copyright (c) 2014 Chelsio, Inc. 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 | ||
ec04847c | 36 | static const char iwpm_ulib_name[IWPM_ULIBNAME_SIZE] = "iWarpPortMapperUser"; |
b0bad9ad | 37 | u16 iwpm_ulib_version = IWPM_UABI_VERSION_MIN; |
30dc5e63 TN |
38 | static int iwpm_user_pid = IWPM_PID_UNDEFINED; |
39 | static atomic_t echo_nlmsg_seq; | |
40 | ||
a2bfd708 SW |
41 | /** |
42 | * iwpm_valid_pid - Check if the userspace iwarp port mapper pid is valid | |
43 | * | |
44 | * Returns true if the pid is greater than zero, otherwise returns false | |
45 | */ | |
30dc5e63 TN |
46 | int iwpm_valid_pid(void) |
47 | { | |
48 | return iwpm_user_pid > 0; | |
49 | } | |
30dc5e63 | 50 | |
a2bfd708 SW |
51 | /** |
52 | * iwpm_register_pid - Send a netlink query to userspace | |
53 | * to get the iwarp port mapper pid | |
54 | * @pm_msg: Contains driver info to send to the userspace port mapper | |
55 | * @nl_client: The index of the netlink client | |
30dc5e63 TN |
56 | * |
57 | * nlmsg attributes: | |
58 | * [IWPM_NLA_REG_PID_SEQ] | |
59 | * [IWPM_NLA_REG_IF_NAME] | |
60 | * [IWPM_NLA_REG_IBDEV_NAME] | |
61 | * [IWPM_NLA_REG_ULIB_NAME] | |
62 | */ | |
63 | int iwpm_register_pid(struct iwpm_dev_data *pm_msg, u8 nl_client) | |
64 | { | |
65 | struct sk_buff *skb = NULL; | |
66 | struct iwpm_nlmsg_request *nlmsg_request = NULL; | |
67 | struct nlmsghdr *nlh; | |
68 | u32 msg_seq; | |
69 | const char *err_str = ""; | |
70 | int ret = -EINVAL; | |
71 | ||
72 | if (!iwpm_valid_client(nl_client)) { | |
73 | err_str = "Invalid port mapper client"; | |
74 | goto pid_query_error; | |
75 | } | |
a7f2f24c TN |
76 | if (iwpm_check_registration(nl_client, IWPM_REG_VALID) || |
77 | iwpm_user_pid == IWPM_PID_UNAVAILABLE) | |
30dc5e63 TN |
78 | return 0; |
79 | skb = iwpm_create_nlmsg(RDMA_NL_IWPM_REG_PID, &nlh, nl_client); | |
80 | if (!skb) { | |
81 | err_str = "Unable to create a nlmsg"; | |
82 | goto pid_query_error; | |
83 | } | |
84 | nlh->nlmsg_seq = iwpm_get_nlmsg_seq(); | |
85 | nlmsg_request = iwpm_get_nlmsg_request(nlh->nlmsg_seq, nl_client, GFP_KERNEL); | |
86 | if (!nlmsg_request) { | |
87 | err_str = "Unable to allocate netlink request"; | |
88 | goto pid_query_error; | |
89 | } | |
90 | msg_seq = atomic_read(&echo_nlmsg_seq); | |
91 | ||
92 | /* fill in the pid request message */ | |
93 | err_str = "Unable to put attribute of the nlmsg"; | |
94 | ret = ibnl_put_attr(skb, nlh, sizeof(u32), &msg_seq, IWPM_NLA_REG_PID_SEQ); | |
95 | if (ret) | |
96 | goto pid_query_error; | |
b493d91d | 97 | ret = ibnl_put_attr(skb, nlh, IFNAMSIZ, |
dafb5587 | 98 | pm_msg->if_name, IWPM_NLA_REG_IF_NAME); |
30dc5e63 TN |
99 | if (ret) |
100 | goto pid_query_error; | |
101 | ret = ibnl_put_attr(skb, nlh, IWPM_DEVNAME_SIZE, | |
102 | pm_msg->dev_name, IWPM_NLA_REG_IBDEV_NAME); | |
103 | if (ret) | |
104 | goto pid_query_error; | |
105 | ret = ibnl_put_attr(skb, nlh, IWPM_ULIBNAME_SIZE, | |
106 | (char *)iwpm_ulib_name, IWPM_NLA_REG_ULIB_NAME); | |
107 | if (ret) | |
108 | goto pid_query_error; | |
109 | ||
04eae427 SS |
110 | nlmsg_end(skb, nlh); |
111 | ||
30dc5e63 TN |
112 | pr_debug("%s: Multicasting a nlmsg (dev = %s ifname = %s iwpm = %s)\n", |
113 | __func__, pm_msg->dev_name, pm_msg->if_name, iwpm_ulib_name); | |
114 | ||
1d2fedd8 | 115 | ret = rdma_nl_multicast(&init_net, skb, RDMA_NL_GROUP_IWPM, GFP_KERNEL); |
30dc5e63 TN |
116 | if (ret) { |
117 | skb = NULL; /* skb is freed in the netlink send-op handling */ | |
30dc5e63 TN |
118 | iwpm_user_pid = IWPM_PID_UNAVAILABLE; |
119 | err_str = "Unable to send a nlmsg"; | |
120 | goto pid_query_error; | |
121 | } | |
122 | nlmsg_request->req_buffer = pm_msg; | |
123 | ret = iwpm_wait_complete_req(nlmsg_request); | |
124 | return ret; | |
125 | pid_query_error: | |
126 | pr_info("%s: %s (client = %d)\n", __func__, err_str, nl_client); | |
fd1a52f3 | 127 | dev_kfree_skb(skb); |
30dc5e63 TN |
128 | if (nlmsg_request) |
129 | iwpm_free_nlmsg_request(&nlmsg_request->kref); | |
130 | return ret; | |
131 | } | |
30dc5e63 | 132 | |
a2bfd708 SW |
133 | /** |
134 | * iwpm_add_mapping - Send a netlink add mapping request to | |
135 | * the userspace port mapper | |
136 | * @pm_msg: Contains the local ip/tcp address info to send | |
137 | * @nl_client: The index of the netlink client | |
138 | * | |
30dc5e63 TN |
139 | * nlmsg attributes: |
140 | * [IWPM_NLA_MANAGE_MAPPING_SEQ] | |
141 | * [IWPM_NLA_MANAGE_ADDR] | |
b0bad9ad | 142 | * [IWPM_NLA_MANAGE_FLAGS] |
a2bfd708 SW |
143 | * |
144 | * If the request is successful, the pm_msg stores | |
145 | * the port mapper response (mapped address info) | |
30dc5e63 TN |
146 | */ |
147 | int iwpm_add_mapping(struct iwpm_sa_data *pm_msg, u8 nl_client) | |
148 | { | |
149 | struct sk_buff *skb = NULL; | |
150 | struct iwpm_nlmsg_request *nlmsg_request = NULL; | |
151 | struct nlmsghdr *nlh; | |
152 | u32 msg_seq; | |
153 | const char *err_str = ""; | |
154 | int ret = -EINVAL; | |
155 | ||
156 | if (!iwpm_valid_client(nl_client)) { | |
157 | err_str = "Invalid port mapper client"; | |
158 | goto add_mapping_error; | |
159 | } | |
a7f2f24c TN |
160 | if (!iwpm_valid_pid()) |
161 | return 0; | |
162 | if (!iwpm_check_registration(nl_client, IWPM_REG_VALID)) { | |
30dc5e63 TN |
163 | err_str = "Unregistered port mapper client"; |
164 | goto add_mapping_error; | |
165 | } | |
30dc5e63 TN |
166 | skb = iwpm_create_nlmsg(RDMA_NL_IWPM_ADD_MAPPING, &nlh, nl_client); |
167 | if (!skb) { | |
168 | err_str = "Unable to create a nlmsg"; | |
169 | goto add_mapping_error; | |
170 | } | |
171 | nlh->nlmsg_seq = iwpm_get_nlmsg_seq(); | |
172 | nlmsg_request = iwpm_get_nlmsg_request(nlh->nlmsg_seq, nl_client, GFP_KERNEL); | |
173 | if (!nlmsg_request) { | |
174 | err_str = "Unable to allocate netlink request"; | |
175 | goto add_mapping_error; | |
176 | } | |
177 | msg_seq = atomic_read(&echo_nlmsg_seq); | |
178 | /* fill in the add mapping message */ | |
179 | err_str = "Unable to put attribute of the nlmsg"; | |
180 | ret = ibnl_put_attr(skb, nlh, sizeof(u32), &msg_seq, | |
181 | IWPM_NLA_MANAGE_MAPPING_SEQ); | |
182 | if (ret) | |
183 | goto add_mapping_error; | |
184 | ret = ibnl_put_attr(skb, nlh, sizeof(struct sockaddr_storage), | |
185 | &pm_msg->loc_addr, IWPM_NLA_MANAGE_ADDR); | |
186 | if (ret) | |
187 | goto add_mapping_error; | |
04eae427 | 188 | |
b0bad9ad SW |
189 | /* If flags are required and we're not V4, then return a quiet error */ |
190 | if (pm_msg->flags && iwpm_ulib_version == IWPM_UABI_VERSION_MIN) { | |
191 | ret = -EINVAL; | |
192 | goto add_mapping_error_nowarn; | |
193 | } | |
194 | if (iwpm_ulib_version > IWPM_UABI_VERSION_MIN) { | |
195 | ret = ibnl_put_attr(skb, nlh, sizeof(u32), &pm_msg->flags, | |
196 | IWPM_NLA_MANAGE_FLAGS); | |
197 | if (ret) | |
198 | goto add_mapping_error; | |
199 | } | |
200 | ||
04eae427 | 201 | nlmsg_end(skb, nlh); |
30dc5e63 TN |
202 | nlmsg_request->req_buffer = pm_msg; |
203 | ||
1d2fedd8 | 204 | ret = rdma_nl_unicast_wait(&init_net, skb, iwpm_user_pid); |
30dc5e63 TN |
205 | if (ret) { |
206 | skb = NULL; /* skb is freed in the netlink send-op handling */ | |
207 | iwpm_user_pid = IWPM_PID_UNDEFINED; | |
208 | err_str = "Unable to send a nlmsg"; | |
209 | goto add_mapping_error; | |
210 | } | |
211 | ret = iwpm_wait_complete_req(nlmsg_request); | |
212 | return ret; | |
213 | add_mapping_error: | |
214 | pr_info("%s: %s (client = %d)\n", __func__, err_str, nl_client); | |
b0bad9ad | 215 | add_mapping_error_nowarn: |
fd1a52f3 | 216 | dev_kfree_skb(skb); |
30dc5e63 TN |
217 | if (nlmsg_request) |
218 | iwpm_free_nlmsg_request(&nlmsg_request->kref); | |
219 | return ret; | |
220 | } | |
30dc5e63 | 221 | |
a2bfd708 SW |
222 | /** |
223 | * iwpm_add_and_query_mapping - Process the port mapper response to | |
224 | * iwpm_add_and_query_mapping request | |
225 | * @pm_msg: Contains the local ip/tcp address info to send | |
226 | * @nl_client: The index of the netlink client | |
227 | * | |
30dc5e63 TN |
228 | * nlmsg attributes: |
229 | * [IWPM_NLA_QUERY_MAPPING_SEQ] | |
230 | * [IWPM_NLA_QUERY_LOCAL_ADDR] | |
231 | * [IWPM_NLA_QUERY_REMOTE_ADDR] | |
b0bad9ad | 232 | * [IWPM_NLA_QUERY_FLAGS] |
30dc5e63 TN |
233 | */ |
234 | int iwpm_add_and_query_mapping(struct iwpm_sa_data *pm_msg, u8 nl_client) | |
235 | { | |
236 | struct sk_buff *skb = NULL; | |
237 | struct iwpm_nlmsg_request *nlmsg_request = NULL; | |
238 | struct nlmsghdr *nlh; | |
239 | u32 msg_seq; | |
240 | const char *err_str = ""; | |
241 | int ret = -EINVAL; | |
242 | ||
243 | if (!iwpm_valid_client(nl_client)) { | |
244 | err_str = "Invalid port mapper client"; | |
245 | goto query_mapping_error; | |
246 | } | |
a7f2f24c TN |
247 | if (!iwpm_valid_pid()) |
248 | return 0; | |
249 | if (!iwpm_check_registration(nl_client, IWPM_REG_VALID)) { | |
30dc5e63 TN |
250 | err_str = "Unregistered port mapper client"; |
251 | goto query_mapping_error; | |
252 | } | |
30dc5e63 TN |
253 | ret = -ENOMEM; |
254 | skb = iwpm_create_nlmsg(RDMA_NL_IWPM_QUERY_MAPPING, &nlh, nl_client); | |
255 | if (!skb) { | |
256 | err_str = "Unable to create a nlmsg"; | |
257 | goto query_mapping_error; | |
258 | } | |
259 | nlh->nlmsg_seq = iwpm_get_nlmsg_seq(); | |
260 | nlmsg_request = iwpm_get_nlmsg_request(nlh->nlmsg_seq, | |
261 | nl_client, GFP_KERNEL); | |
262 | if (!nlmsg_request) { | |
263 | err_str = "Unable to allocate netlink request"; | |
264 | goto query_mapping_error; | |
265 | } | |
266 | msg_seq = atomic_read(&echo_nlmsg_seq); | |
267 | ||
268 | /* fill in the query message */ | |
269 | err_str = "Unable to put attribute of the nlmsg"; | |
270 | ret = ibnl_put_attr(skb, nlh, sizeof(u32), &msg_seq, | |
271 | IWPM_NLA_QUERY_MAPPING_SEQ); | |
272 | if (ret) | |
273 | goto query_mapping_error; | |
274 | ret = ibnl_put_attr(skb, nlh, sizeof(struct sockaddr_storage), | |
275 | &pm_msg->loc_addr, IWPM_NLA_QUERY_LOCAL_ADDR); | |
276 | if (ret) | |
277 | goto query_mapping_error; | |
278 | ret = ibnl_put_attr(skb, nlh, sizeof(struct sockaddr_storage), | |
279 | &pm_msg->rem_addr, IWPM_NLA_QUERY_REMOTE_ADDR); | |
280 | if (ret) | |
281 | goto query_mapping_error; | |
04eae427 | 282 | |
b0bad9ad SW |
283 | /* If flags are required and we're not V4, then return a quite error */ |
284 | if (pm_msg->flags && iwpm_ulib_version == IWPM_UABI_VERSION_MIN) { | |
285 | ret = -EINVAL; | |
286 | goto query_mapping_error_nowarn; | |
287 | } | |
288 | if (iwpm_ulib_version > IWPM_UABI_VERSION_MIN) { | |
289 | ret = ibnl_put_attr(skb, nlh, sizeof(u32), &pm_msg->flags, | |
290 | IWPM_NLA_QUERY_FLAGS); | |
291 | if (ret) | |
292 | goto query_mapping_error; | |
293 | } | |
294 | ||
04eae427 | 295 | nlmsg_end(skb, nlh); |
30dc5e63 TN |
296 | nlmsg_request->req_buffer = pm_msg; |
297 | ||
1d2fedd8 | 298 | ret = rdma_nl_unicast_wait(&init_net, skb, iwpm_user_pid); |
30dc5e63 TN |
299 | if (ret) { |
300 | skb = NULL; /* skb is freed in the netlink send-op handling */ | |
301 | err_str = "Unable to send a nlmsg"; | |
302 | goto query_mapping_error; | |
303 | } | |
304 | ret = iwpm_wait_complete_req(nlmsg_request); | |
305 | return ret; | |
306 | query_mapping_error: | |
307 | pr_info("%s: %s (client = %d)\n", __func__, err_str, nl_client); | |
b0bad9ad | 308 | query_mapping_error_nowarn: |
fd1a52f3 | 309 | dev_kfree_skb(skb); |
30dc5e63 TN |
310 | if (nlmsg_request) |
311 | iwpm_free_nlmsg_request(&nlmsg_request->kref); | |
312 | return ret; | |
313 | } | |
30dc5e63 | 314 | |
a2bfd708 SW |
315 | /** |
316 | * iwpm_remove_mapping - Send a netlink remove mapping request | |
317 | * to the userspace port mapper | |
318 | * | |
319 | * @local_addr: Local ip/tcp address to remove | |
320 | * @nl_client: The index of the netlink client | |
321 | * | |
30dc5e63 TN |
322 | * nlmsg attributes: |
323 | * [IWPM_NLA_MANAGE_MAPPING_SEQ] | |
324 | * [IWPM_NLA_MANAGE_ADDR] | |
325 | */ | |
326 | int iwpm_remove_mapping(struct sockaddr_storage *local_addr, u8 nl_client) | |
327 | { | |
328 | struct sk_buff *skb = NULL; | |
329 | struct nlmsghdr *nlh; | |
330 | u32 msg_seq; | |
331 | const char *err_str = ""; | |
332 | int ret = -EINVAL; | |
333 | ||
334 | if (!iwpm_valid_client(nl_client)) { | |
335 | err_str = "Invalid port mapper client"; | |
336 | goto remove_mapping_error; | |
337 | } | |
a7f2f24c TN |
338 | if (!iwpm_valid_pid()) |
339 | return 0; | |
340 | if (iwpm_check_registration(nl_client, IWPM_REG_UNDEF)) { | |
30dc5e63 TN |
341 | err_str = "Unregistered port mapper client"; |
342 | goto remove_mapping_error; | |
343 | } | |
30dc5e63 TN |
344 | skb = iwpm_create_nlmsg(RDMA_NL_IWPM_REMOVE_MAPPING, &nlh, nl_client); |
345 | if (!skb) { | |
346 | ret = -ENOMEM; | |
347 | err_str = "Unable to create a nlmsg"; | |
348 | goto remove_mapping_error; | |
349 | } | |
350 | msg_seq = atomic_read(&echo_nlmsg_seq); | |
351 | nlh->nlmsg_seq = iwpm_get_nlmsg_seq(); | |
352 | err_str = "Unable to put attribute of the nlmsg"; | |
353 | ret = ibnl_put_attr(skb, nlh, sizeof(u32), &msg_seq, | |
354 | IWPM_NLA_MANAGE_MAPPING_SEQ); | |
355 | if (ret) | |
356 | goto remove_mapping_error; | |
357 | ret = ibnl_put_attr(skb, nlh, sizeof(struct sockaddr_storage), | |
358 | local_addr, IWPM_NLA_MANAGE_ADDR); | |
359 | if (ret) | |
360 | goto remove_mapping_error; | |
361 | ||
04eae427 SS |
362 | nlmsg_end(skb, nlh); |
363 | ||
1d2fedd8 | 364 | ret = rdma_nl_unicast_wait(&init_net, skb, iwpm_user_pid); |
30dc5e63 TN |
365 | if (ret) { |
366 | skb = NULL; /* skb is freed in the netlink send-op handling */ | |
367 | iwpm_user_pid = IWPM_PID_UNDEFINED; | |
368 | err_str = "Unable to send a nlmsg"; | |
369 | goto remove_mapping_error; | |
370 | } | |
371 | iwpm_print_sockaddr(local_addr, | |
372 | "remove_mapping: Local sockaddr:"); | |
373 | return 0; | |
374 | remove_mapping_error: | |
375 | pr_info("%s: %s (client = %d)\n", __func__, err_str, nl_client); | |
376 | if (skb) | |
377 | dev_kfree_skb_any(skb); | |
378 | return ret; | |
379 | } | |
30dc5e63 TN |
380 | |
381 | /* netlink attribute policy for the received response to register pid request */ | |
382 | static const struct nla_policy resp_reg_policy[IWPM_NLA_RREG_PID_MAX] = { | |
383 | [IWPM_NLA_RREG_PID_SEQ] = { .type = NLA_U32 }, | |
384 | [IWPM_NLA_RREG_IBDEV_NAME] = { .type = NLA_STRING, | |
385 | .len = IWPM_DEVNAME_SIZE - 1 }, | |
386 | [IWPM_NLA_RREG_ULIB_NAME] = { .type = NLA_STRING, | |
387 | .len = IWPM_ULIBNAME_SIZE - 1 }, | |
388 | [IWPM_NLA_RREG_ULIB_VER] = { .type = NLA_U16 }, | |
389 | [IWPM_NLA_RREG_PID_ERR] = { .type = NLA_U16 } | |
390 | }; | |
391 | ||
a2bfd708 SW |
392 | /** |
393 | * iwpm_register_pid_cb - Process the port mapper response to | |
394 | * iwpm_register_pid query | |
395 | * @skb: | |
396 | * @cb: Contains the received message (payload and netlink header) | |
397 | * | |
398 | * If successful, the function receives the userspace port mapper pid | |
399 | * which is used in future communication with the port mapper | |
30dc5e63 TN |
400 | */ |
401 | int iwpm_register_pid_cb(struct sk_buff *skb, struct netlink_callback *cb) | |
402 | { | |
403 | struct iwpm_nlmsg_request *nlmsg_request = NULL; | |
404 | struct nlattr *nltb[IWPM_NLA_RREG_PID_MAX]; | |
405 | struct iwpm_dev_data *pm_msg; | |
406 | char *dev_name, *iwpm_name; | |
407 | u32 msg_seq; | |
408 | u8 nl_client; | |
409 | u16 iwpm_version; | |
410 | const char *msg_type = "Register Pid response"; | |
411 | ||
412 | if (iwpm_parse_nlmsg(cb, IWPM_NLA_RREG_PID_MAX, | |
413 | resp_reg_policy, nltb, msg_type)) | |
414 | return -EINVAL; | |
415 | ||
416 | msg_seq = nla_get_u32(nltb[IWPM_NLA_RREG_PID_SEQ]); | |
417 | nlmsg_request = iwpm_find_nlmsg_request(msg_seq); | |
418 | if (!nlmsg_request) { | |
419 | pr_info("%s: Could not find a matching request (seq = %u)\n", | |
420 | __func__, msg_seq); | |
421 | return -EINVAL; | |
422 | } | |
423 | pm_msg = nlmsg_request->req_buffer; | |
424 | nl_client = nlmsg_request->nl_client; | |
425 | dev_name = (char *)nla_data(nltb[IWPM_NLA_RREG_IBDEV_NAME]); | |
426 | iwpm_name = (char *)nla_data(nltb[IWPM_NLA_RREG_ULIB_NAME]); | |
427 | iwpm_version = nla_get_u16(nltb[IWPM_NLA_RREG_ULIB_VER]); | |
428 | ||
429 | /* check device name, ulib name and version */ | |
430 | if (strcmp(pm_msg->dev_name, dev_name) || | |
431 | strcmp(iwpm_ulib_name, iwpm_name) || | |
b0bad9ad | 432 | iwpm_version < IWPM_UABI_VERSION_MIN) { |
30dc5e63 TN |
433 | |
434 | pr_info("%s: Incorrect info (dev = %s name = %s version = %d)\n", | |
435 | __func__, dev_name, iwpm_name, iwpm_version); | |
436 | nlmsg_request->err_code = IWPM_USER_LIB_INFO_ERR; | |
437 | goto register_pid_response_exit; | |
438 | } | |
439 | iwpm_user_pid = cb->nlh->nlmsg_pid; | |
b0bad9ad SW |
440 | iwpm_ulib_version = iwpm_version; |
441 | if (iwpm_ulib_version < IWPM_UABI_VERSION) | |
442 | pr_warn_once("%s: Down level iwpmd/pid %u. Continuing...", | |
443 | __func__, iwpm_user_pid); | |
30dc5e63 TN |
444 | atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq); |
445 | pr_debug("%s: iWarp Port Mapper (pid = %d) is available!\n", | |
446 | __func__, iwpm_user_pid); | |
447 | if (iwpm_valid_client(nl_client)) | |
a7f2f24c | 448 | iwpm_set_registration(nl_client, IWPM_REG_VALID); |
30dc5e63 TN |
449 | register_pid_response_exit: |
450 | nlmsg_request->request_done = 1; | |
451 | /* always for found nlmsg_request */ | |
452 | kref_put(&nlmsg_request->kref, iwpm_free_nlmsg_request); | |
453 | barrier(); | |
dafb5587 | 454 | up(&nlmsg_request->sem); |
30dc5e63 TN |
455 | return 0; |
456 | } | |
30dc5e63 TN |
457 | |
458 | /* netlink attribute policy for the received response to add mapping request */ | |
459 | static const struct nla_policy resp_add_policy[IWPM_NLA_RMANAGE_MAPPING_MAX] = { | |
f76903d5 SW |
460 | [IWPM_NLA_RMANAGE_MAPPING_SEQ] = { .type = NLA_U32 }, |
461 | [IWPM_NLA_RMANAGE_ADDR] = { | |
462 | .len = sizeof(struct sockaddr_storage) }, | |
463 | [IWPM_NLA_RMANAGE_MAPPED_LOC_ADDR] = { | |
464 | .len = sizeof(struct sockaddr_storage) }, | |
465 | [IWPM_NLA_RMANAGE_MAPPING_ERR] = { .type = NLA_U16 } | |
30dc5e63 TN |
466 | }; |
467 | ||
a2bfd708 SW |
468 | /** |
469 | * iwpm_add_mapping_cb - Process the port mapper response to | |
470 | * iwpm_add_mapping request | |
471 | * @skb: | |
472 | * @cb: Contains the received message (payload and netlink header) | |
30dc5e63 TN |
473 | */ |
474 | int iwpm_add_mapping_cb(struct sk_buff *skb, struct netlink_callback *cb) | |
475 | { | |
476 | struct iwpm_sa_data *pm_msg; | |
477 | struct iwpm_nlmsg_request *nlmsg_request = NULL; | |
478 | struct nlattr *nltb[IWPM_NLA_RMANAGE_MAPPING_MAX]; | |
479 | struct sockaddr_storage *local_sockaddr; | |
480 | struct sockaddr_storage *mapped_sockaddr; | |
481 | const char *msg_type; | |
482 | u32 msg_seq; | |
483 | ||
484 | msg_type = "Add Mapping response"; | |
485 | if (iwpm_parse_nlmsg(cb, IWPM_NLA_RMANAGE_MAPPING_MAX, | |
486 | resp_add_policy, nltb, msg_type)) | |
487 | return -EINVAL; | |
488 | ||
489 | atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq); | |
490 | ||
f76903d5 | 491 | msg_seq = nla_get_u32(nltb[IWPM_NLA_RMANAGE_MAPPING_SEQ]); |
30dc5e63 TN |
492 | nlmsg_request = iwpm_find_nlmsg_request(msg_seq); |
493 | if (!nlmsg_request) { | |
494 | pr_info("%s: Could not find a matching request (seq = %u)\n", | |
495 | __func__, msg_seq); | |
496 | return -EINVAL; | |
497 | } | |
498 | pm_msg = nlmsg_request->req_buffer; | |
499 | local_sockaddr = (struct sockaddr_storage *) | |
f76903d5 | 500 | nla_data(nltb[IWPM_NLA_RMANAGE_ADDR]); |
30dc5e63 | 501 | mapped_sockaddr = (struct sockaddr_storage *) |
f76903d5 | 502 | nla_data(nltb[IWPM_NLA_RMANAGE_MAPPED_LOC_ADDR]); |
30dc5e63 TN |
503 | |
504 | if (iwpm_compare_sockaddr(local_sockaddr, &pm_msg->loc_addr)) { | |
505 | nlmsg_request->err_code = IWPM_USER_LIB_INFO_ERR; | |
506 | goto add_mapping_response_exit; | |
507 | } | |
508 | if (mapped_sockaddr->ss_family != local_sockaddr->ss_family) { | |
509 | pr_info("%s: Sockaddr family doesn't match the requested one\n", | |
510 | __func__); | |
511 | nlmsg_request->err_code = IWPM_USER_LIB_INFO_ERR; | |
512 | goto add_mapping_response_exit; | |
513 | } | |
514 | memcpy(&pm_msg->mapped_loc_addr, mapped_sockaddr, | |
515 | sizeof(*mapped_sockaddr)); | |
516 | iwpm_print_sockaddr(&pm_msg->loc_addr, | |
517 | "add_mapping: Local sockaddr:"); | |
518 | iwpm_print_sockaddr(&pm_msg->mapped_loc_addr, | |
519 | "add_mapping: Mapped local sockaddr:"); | |
520 | ||
521 | add_mapping_response_exit: | |
522 | nlmsg_request->request_done = 1; | |
523 | /* always for found request */ | |
524 | kref_put(&nlmsg_request->kref, iwpm_free_nlmsg_request); | |
525 | barrier(); | |
dafb5587 | 526 | up(&nlmsg_request->sem); |
30dc5e63 TN |
527 | return 0; |
528 | } | |
30dc5e63 | 529 | |
6eec1774 TN |
530 | /* netlink attribute policy for the response to add and query mapping request |
531 | * and response with remote address info */ | |
30dc5e63 | 532 | static const struct nla_policy resp_query_policy[IWPM_NLA_RQUERY_MAPPING_MAX] = { |
f76903d5 SW |
533 | [IWPM_NLA_RQUERY_MAPPING_SEQ] = { .type = NLA_U32 }, |
534 | [IWPM_NLA_RQUERY_LOCAL_ADDR] = { | |
535 | .len = sizeof(struct sockaddr_storage) }, | |
536 | [IWPM_NLA_RQUERY_REMOTE_ADDR] = { | |
537 | .len = sizeof(struct sockaddr_storage) }, | |
538 | [IWPM_NLA_RQUERY_MAPPED_LOC_ADDR] = { | |
539 | .len = sizeof(struct sockaddr_storage) }, | |
540 | [IWPM_NLA_RQUERY_MAPPED_REM_ADDR] = { | |
541 | .len = sizeof(struct sockaddr_storage) }, | |
30dc5e63 TN |
542 | [IWPM_NLA_RQUERY_MAPPING_ERR] = { .type = NLA_U16 } |
543 | }; | |
544 | ||
a2bfd708 SW |
545 | /** |
546 | * iwpm_add_and_query_mapping_cb - Process the port mapper response to | |
547 | * iwpm_add_and_query_mapping request | |
548 | * @skb: | |
549 | * @cb: Contains the received message (payload and netlink header) | |
30dc5e63 TN |
550 | */ |
551 | int iwpm_add_and_query_mapping_cb(struct sk_buff *skb, | |
552 | struct netlink_callback *cb) | |
553 | { | |
554 | struct iwpm_sa_data *pm_msg; | |
555 | struct iwpm_nlmsg_request *nlmsg_request = NULL; | |
556 | struct nlattr *nltb[IWPM_NLA_RQUERY_MAPPING_MAX]; | |
557 | struct sockaddr_storage *local_sockaddr, *remote_sockaddr; | |
558 | struct sockaddr_storage *mapped_loc_sockaddr, *mapped_rem_sockaddr; | |
559 | const char *msg_type; | |
560 | u32 msg_seq; | |
561 | u16 err_code; | |
562 | ||
563 | msg_type = "Query Mapping response"; | |
564 | if (iwpm_parse_nlmsg(cb, IWPM_NLA_RQUERY_MAPPING_MAX, | |
565 | resp_query_policy, nltb, msg_type)) | |
566 | return -EINVAL; | |
567 | atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq); | |
568 | ||
f76903d5 | 569 | msg_seq = nla_get_u32(nltb[IWPM_NLA_RQUERY_MAPPING_SEQ]); |
30dc5e63 TN |
570 | nlmsg_request = iwpm_find_nlmsg_request(msg_seq); |
571 | if (!nlmsg_request) { | |
572 | pr_info("%s: Could not find a matching request (seq = %u)\n", | |
573 | __func__, msg_seq); | |
0270be78 | 574 | return -EINVAL; |
30dc5e63 TN |
575 | } |
576 | pm_msg = nlmsg_request->req_buffer; | |
577 | local_sockaddr = (struct sockaddr_storage *) | |
f76903d5 | 578 | nla_data(nltb[IWPM_NLA_RQUERY_LOCAL_ADDR]); |
30dc5e63 | 579 | remote_sockaddr = (struct sockaddr_storage *) |
f76903d5 | 580 | nla_data(nltb[IWPM_NLA_RQUERY_REMOTE_ADDR]); |
30dc5e63 TN |
581 | mapped_loc_sockaddr = (struct sockaddr_storage *) |
582 | nla_data(nltb[IWPM_NLA_RQUERY_MAPPED_LOC_ADDR]); | |
583 | mapped_rem_sockaddr = (struct sockaddr_storage *) | |
584 | nla_data(nltb[IWPM_NLA_RQUERY_MAPPED_REM_ADDR]); | |
585 | ||
586 | err_code = nla_get_u16(nltb[IWPM_NLA_RQUERY_MAPPING_ERR]); | |
587 | if (err_code == IWPM_REMOTE_QUERY_REJECT) { | |
588 | pr_info("%s: Received a Reject (pid = %u, echo seq = %u)\n", | |
589 | __func__, cb->nlh->nlmsg_pid, msg_seq); | |
590 | nlmsg_request->err_code = IWPM_REMOTE_QUERY_REJECT; | |
591 | } | |
592 | if (iwpm_compare_sockaddr(local_sockaddr, &pm_msg->loc_addr) || | |
593 | iwpm_compare_sockaddr(remote_sockaddr, &pm_msg->rem_addr)) { | |
594 | pr_info("%s: Incorrect local sockaddr\n", __func__); | |
595 | nlmsg_request->err_code = IWPM_USER_LIB_INFO_ERR; | |
596 | goto query_mapping_response_exit; | |
597 | } | |
598 | if (mapped_loc_sockaddr->ss_family != local_sockaddr->ss_family || | |
599 | mapped_rem_sockaddr->ss_family != remote_sockaddr->ss_family) { | |
600 | pr_info("%s: Sockaddr family doesn't match the requested one\n", | |
601 | __func__); | |
602 | nlmsg_request->err_code = IWPM_USER_LIB_INFO_ERR; | |
603 | goto query_mapping_response_exit; | |
604 | } | |
605 | memcpy(&pm_msg->mapped_loc_addr, mapped_loc_sockaddr, | |
606 | sizeof(*mapped_loc_sockaddr)); | |
607 | memcpy(&pm_msg->mapped_rem_addr, mapped_rem_sockaddr, | |
608 | sizeof(*mapped_rem_sockaddr)); | |
609 | ||
610 | iwpm_print_sockaddr(&pm_msg->loc_addr, | |
611 | "query_mapping: Local sockaddr:"); | |
612 | iwpm_print_sockaddr(&pm_msg->mapped_loc_addr, | |
613 | "query_mapping: Mapped local sockaddr:"); | |
614 | iwpm_print_sockaddr(&pm_msg->rem_addr, | |
615 | "query_mapping: Remote sockaddr:"); | |
616 | iwpm_print_sockaddr(&pm_msg->mapped_rem_addr, | |
617 | "query_mapping: Mapped remote sockaddr:"); | |
618 | query_mapping_response_exit: | |
619 | nlmsg_request->request_done = 1; | |
620 | /* always for found request */ | |
621 | kref_put(&nlmsg_request->kref, iwpm_free_nlmsg_request); | |
622 | barrier(); | |
dafb5587 | 623 | up(&nlmsg_request->sem); |
30dc5e63 TN |
624 | return 0; |
625 | } | |
30dc5e63 | 626 | |
a2bfd708 SW |
627 | /** |
628 | * iwpm_remote_info_cb - Process remote connecting peer address info, which | |
629 | * the port mapper has received from the connecting peer | |
630 | * @skb: | |
631 | * @cb: Contains the received message (payload and netlink header) | |
632 | * | |
633 | * Stores the IPv4/IPv6 address info in a hash table | |
6eec1774 TN |
634 | */ |
635 | int iwpm_remote_info_cb(struct sk_buff *skb, struct netlink_callback *cb) | |
636 | { | |
637 | struct nlattr *nltb[IWPM_NLA_RQUERY_MAPPING_MAX]; | |
638 | struct sockaddr_storage *local_sockaddr, *remote_sockaddr; | |
639 | struct sockaddr_storage *mapped_loc_sockaddr, *mapped_rem_sockaddr; | |
640 | struct iwpm_remote_info *rem_info; | |
641 | const char *msg_type; | |
642 | u8 nl_client; | |
643 | int ret = -EINVAL; | |
644 | ||
645 | msg_type = "Remote Mapping info"; | |
646 | if (iwpm_parse_nlmsg(cb, IWPM_NLA_RQUERY_MAPPING_MAX, | |
647 | resp_query_policy, nltb, msg_type)) | |
648 | return ret; | |
649 | ||
650 | nl_client = RDMA_NL_GET_CLIENT(cb->nlh->nlmsg_type); | |
651 | if (!iwpm_valid_client(nl_client)) { | |
652 | pr_info("%s: Invalid port mapper client = %d\n", | |
653 | __func__, nl_client); | |
654 | return ret; | |
655 | } | |
656 | atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq); | |
657 | ||
658 | local_sockaddr = (struct sockaddr_storage *) | |
f76903d5 | 659 | nla_data(nltb[IWPM_NLA_RQUERY_LOCAL_ADDR]); |
6eec1774 | 660 | remote_sockaddr = (struct sockaddr_storage *) |
f76903d5 | 661 | nla_data(nltb[IWPM_NLA_RQUERY_REMOTE_ADDR]); |
6eec1774 TN |
662 | mapped_loc_sockaddr = (struct sockaddr_storage *) |
663 | nla_data(nltb[IWPM_NLA_RQUERY_MAPPED_LOC_ADDR]); | |
664 | mapped_rem_sockaddr = (struct sockaddr_storage *) | |
665 | nla_data(nltb[IWPM_NLA_RQUERY_MAPPED_REM_ADDR]); | |
666 | ||
667 | if (mapped_loc_sockaddr->ss_family != local_sockaddr->ss_family || | |
668 | mapped_rem_sockaddr->ss_family != remote_sockaddr->ss_family) { | |
669 | pr_info("%s: Sockaddr family doesn't match the requested one\n", | |
670 | __func__); | |
671 | return ret; | |
672 | } | |
673 | rem_info = kzalloc(sizeof(struct iwpm_remote_info), GFP_ATOMIC); | |
674 | if (!rem_info) { | |
6eec1774 TN |
675 | ret = -ENOMEM; |
676 | return ret; | |
677 | } | |
678 | memcpy(&rem_info->mapped_loc_sockaddr, mapped_loc_sockaddr, | |
679 | sizeof(struct sockaddr_storage)); | |
680 | memcpy(&rem_info->remote_sockaddr, remote_sockaddr, | |
681 | sizeof(struct sockaddr_storage)); | |
682 | memcpy(&rem_info->mapped_rem_sockaddr, mapped_rem_sockaddr, | |
683 | sizeof(struct sockaddr_storage)); | |
684 | rem_info->nl_client = nl_client; | |
685 | ||
686 | iwpm_add_remote_info(rem_info); | |
687 | ||
688 | iwpm_print_sockaddr(local_sockaddr, | |
689 | "remote_info: Local sockaddr:"); | |
690 | iwpm_print_sockaddr(mapped_loc_sockaddr, | |
691 | "remote_info: Mapped local sockaddr:"); | |
692 | iwpm_print_sockaddr(remote_sockaddr, | |
693 | "remote_info: Remote sockaddr:"); | |
694 | iwpm_print_sockaddr(mapped_rem_sockaddr, | |
695 | "remote_info: Mapped remote sockaddr:"); | |
696 | return ret; | |
697 | } | |
6eec1774 | 698 | |
30dc5e63 TN |
699 | /* netlink attribute policy for the received request for mapping info */ |
700 | static const struct nla_policy resp_mapinfo_policy[IWPM_NLA_MAPINFO_REQ_MAX] = { | |
701 | [IWPM_NLA_MAPINFO_ULIB_NAME] = { .type = NLA_STRING, | |
702 | .len = IWPM_ULIBNAME_SIZE - 1 }, | |
703 | [IWPM_NLA_MAPINFO_ULIB_VER] = { .type = NLA_U16 } | |
704 | }; | |
705 | ||
a2bfd708 SW |
706 | /** |
707 | * iwpm_mapping_info_cb - Process a notification that the userspace | |
708 | * port mapper daemon is started | |
709 | * @skb: | |
710 | * @cb: Contains the received message (payload and netlink header) | |
711 | * | |
712 | * Using the received port mapper pid, send all the local mapping | |
713 | * info records to the userspace port mapper | |
30dc5e63 TN |
714 | */ |
715 | int iwpm_mapping_info_cb(struct sk_buff *skb, struct netlink_callback *cb) | |
716 | { | |
717 | struct nlattr *nltb[IWPM_NLA_MAPINFO_REQ_MAX]; | |
718 | const char *msg_type = "Mapping Info response"; | |
30dc5e63 TN |
719 | u8 nl_client; |
720 | char *iwpm_name; | |
721 | u16 iwpm_version; | |
722 | int ret = -EINVAL; | |
723 | ||
724 | if (iwpm_parse_nlmsg(cb, IWPM_NLA_MAPINFO_REQ_MAX, | |
725 | resp_mapinfo_policy, nltb, msg_type)) { | |
726 | pr_info("%s: Unable to parse nlmsg\n", __func__); | |
727 | return ret; | |
728 | } | |
729 | iwpm_name = (char *)nla_data(nltb[IWPM_NLA_MAPINFO_ULIB_NAME]); | |
730 | iwpm_version = nla_get_u16(nltb[IWPM_NLA_MAPINFO_ULIB_VER]); | |
731 | if (strcmp(iwpm_ulib_name, iwpm_name) || | |
b0bad9ad | 732 | iwpm_version < IWPM_UABI_VERSION_MIN) { |
30dc5e63 TN |
733 | pr_info("%s: Invalid port mapper name = %s version = %d\n", |
734 | __func__, iwpm_name, iwpm_version); | |
735 | return ret; | |
736 | } | |
737 | nl_client = RDMA_NL_GET_CLIENT(cb->nlh->nlmsg_type); | |
738 | if (!iwpm_valid_client(nl_client)) { | |
739 | pr_info("%s: Invalid port mapper client = %d\n", | |
740 | __func__, nl_client); | |
741 | return ret; | |
742 | } | |
a7f2f24c | 743 | iwpm_set_registration(nl_client, IWPM_REG_INCOMPL); |
30dc5e63 | 744 | atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq); |
a7f2f24c | 745 | iwpm_user_pid = cb->nlh->nlmsg_pid; |
b0bad9ad SW |
746 | |
747 | if (iwpm_ulib_version < IWPM_UABI_VERSION) | |
748 | pr_warn_once("%s: Down level iwpmd/pid %u. Continuing...", | |
749 | __func__, iwpm_user_pid); | |
750 | ||
30dc5e63 TN |
751 | if (!iwpm_mapinfo_available()) |
752 | return 0; | |
30dc5e63 | 753 | pr_debug("%s: iWarp Port Mapper (pid = %d) is available!\n", |
a7f2f24c TN |
754 | __func__, iwpm_user_pid); |
755 | ret = iwpm_send_mapinfo(nl_client, iwpm_user_pid); | |
30dc5e63 TN |
756 | return ret; |
757 | } | |
30dc5e63 TN |
758 | |
759 | /* netlink attribute policy for the received mapping info ack */ | |
760 | static const struct nla_policy ack_mapinfo_policy[IWPM_NLA_MAPINFO_NUM_MAX] = { | |
761 | [IWPM_NLA_MAPINFO_SEQ] = { .type = NLA_U32 }, | |
762 | [IWPM_NLA_MAPINFO_SEND_NUM] = { .type = NLA_U32 }, | |
763 | [IWPM_NLA_MAPINFO_ACK_NUM] = { .type = NLA_U32 } | |
764 | }; | |
765 | ||
a2bfd708 SW |
766 | /** |
767 | * iwpm_ack_mapping_info_cb - Process the port mapper ack for | |
768 | * the provided local mapping info records | |
769 | * @skb: | |
770 | * @cb: Contains the received message (payload and netlink header) | |
30dc5e63 TN |
771 | */ |
772 | int iwpm_ack_mapping_info_cb(struct sk_buff *skb, struct netlink_callback *cb) | |
773 | { | |
774 | struct nlattr *nltb[IWPM_NLA_MAPINFO_NUM_MAX]; | |
775 | u32 mapinfo_send, mapinfo_ack; | |
776 | const char *msg_type = "Mapping Info Ack"; | |
777 | ||
778 | if (iwpm_parse_nlmsg(cb, IWPM_NLA_MAPINFO_NUM_MAX, | |
779 | ack_mapinfo_policy, nltb, msg_type)) | |
780 | return -EINVAL; | |
781 | mapinfo_send = nla_get_u32(nltb[IWPM_NLA_MAPINFO_SEND_NUM]); | |
782 | mapinfo_ack = nla_get_u32(nltb[IWPM_NLA_MAPINFO_ACK_NUM]); | |
783 | if (mapinfo_ack != mapinfo_send) | |
784 | pr_info("%s: Invalid mapinfo number (sent = %u ack-ed = %u)\n", | |
785 | __func__, mapinfo_send, mapinfo_ack); | |
786 | atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq); | |
787 | return 0; | |
788 | } | |
30dc5e63 TN |
789 | |
790 | /* netlink attribute policy for the received port mapper error message */ | |
791 | static const struct nla_policy map_error_policy[IWPM_NLA_ERR_MAX] = { | |
792 | [IWPM_NLA_ERR_SEQ] = { .type = NLA_U32 }, | |
793 | [IWPM_NLA_ERR_CODE] = { .type = NLA_U16 }, | |
794 | }; | |
795 | ||
a2bfd708 SW |
796 | /** |
797 | * iwpm_mapping_error_cb - Process port mapper notification for error | |
798 | * | |
799 | * @skb: | |
800 | * @cb: Contains the received message (payload and netlink header) | |
30dc5e63 TN |
801 | */ |
802 | int iwpm_mapping_error_cb(struct sk_buff *skb, struct netlink_callback *cb) | |
803 | { | |
804 | struct iwpm_nlmsg_request *nlmsg_request = NULL; | |
805 | int nl_client = RDMA_NL_GET_CLIENT(cb->nlh->nlmsg_type); | |
806 | struct nlattr *nltb[IWPM_NLA_ERR_MAX]; | |
807 | u32 msg_seq; | |
808 | u16 err_code; | |
809 | const char *msg_type = "Mapping Error Msg"; | |
810 | ||
811 | if (iwpm_parse_nlmsg(cb, IWPM_NLA_ERR_MAX, | |
812 | map_error_policy, nltb, msg_type)) | |
813 | return -EINVAL; | |
814 | ||
815 | msg_seq = nla_get_u32(nltb[IWPM_NLA_ERR_SEQ]); | |
816 | err_code = nla_get_u16(nltb[IWPM_NLA_ERR_CODE]); | |
817 | pr_info("%s: Received msg seq = %u err code = %u client = %d\n", | |
818 | __func__, msg_seq, err_code, nl_client); | |
819 | /* look for nlmsg_request */ | |
820 | nlmsg_request = iwpm_find_nlmsg_request(msg_seq); | |
821 | if (!nlmsg_request) { | |
822 | /* not all errors have associated requests */ | |
823 | pr_debug("Could not find matching req (seq = %u)\n", msg_seq); | |
824 | return 0; | |
825 | } | |
826 | atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq); | |
827 | nlmsg_request->err_code = err_code; | |
828 | nlmsg_request->request_done = 1; | |
829 | /* always for found request */ | |
830 | kref_put(&nlmsg_request->kref, iwpm_free_nlmsg_request); | |
831 | barrier(); | |
dafb5587 | 832 | up(&nlmsg_request->sem); |
30dc5e63 TN |
833 | return 0; |
834 | } | |
b0bad9ad SW |
835 | |
836 | /* netlink attribute policy for the received hello request */ | |
837 | static const struct nla_policy hello_policy[IWPM_NLA_HELLO_MAX] = { | |
838 | [IWPM_NLA_HELLO_ABI_VERSION] = { .type = NLA_U16 } | |
839 | }; | |
840 | ||
a2bfd708 SW |
841 | /** |
842 | * iwpm_hello_cb - Process a hello message from iwpmd | |
843 | * | |
844 | * @skb: | |
845 | * @cb: Contains the received message (payload and netlink header) | |
846 | * | |
847 | * Using the received port mapper pid, send the kernel's abi_version | |
848 | * after adjusting it to support the iwpmd version. | |
b0bad9ad SW |
849 | */ |
850 | int iwpm_hello_cb(struct sk_buff *skb, struct netlink_callback *cb) | |
851 | { | |
852 | struct nlattr *nltb[IWPM_NLA_HELLO_MAX]; | |
853 | const char *msg_type = "Hello request"; | |
854 | u8 nl_client; | |
855 | u16 abi_version; | |
856 | int ret = -EINVAL; | |
857 | ||
858 | if (iwpm_parse_nlmsg(cb, IWPM_NLA_HELLO_MAX, hello_policy, nltb, | |
859 | msg_type)) { | |
860 | pr_info("%s: Unable to parse nlmsg\n", __func__); | |
861 | return ret; | |
862 | } | |
863 | abi_version = nla_get_u16(nltb[IWPM_NLA_HELLO_ABI_VERSION]); | |
864 | nl_client = RDMA_NL_GET_CLIENT(cb->nlh->nlmsg_type); | |
865 | if (!iwpm_valid_client(nl_client)) { | |
866 | pr_info("%s: Invalid port mapper client = %d\n", | |
867 | __func__, nl_client); | |
868 | return ret; | |
869 | } | |
870 | iwpm_set_registration(nl_client, IWPM_REG_INCOMPL); | |
871 | atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq); | |
872 | iwpm_ulib_version = min_t(u16, IWPM_UABI_VERSION, abi_version); | |
873 | pr_debug("Using ABI version %u\n", iwpm_ulib_version); | |
874 | iwpm_user_pid = cb->nlh->nlmsg_pid; | |
875 | ret = iwpm_send_hello(nl_client, iwpm_user_pid, iwpm_ulib_version); | |
876 | return ret; | |
877 | } |