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