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