| 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 |
|
| 36 | static const char iwpm_ulib_name[IWPM_ULIBNAME_SIZE] = "iWarpPortMapperUser";
|
| 37 | u16 iwpm_ulib_version = IWPM_UABI_VERSION_MIN;
|
| 38 | static int iwpm_user_pid = IWPM_PID_UNDEFINED;
|
| 39 | static atomic_t echo_nlmsg_seq;
|
| 40 |
|
| 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 |
|
| 46 | int iwpm_valid_pid(void)
|
| 47 | {
|
| 48 | return iwpm_user_pid > 0;
|
| 49 | }
|
| 50 |
|
| 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
|
| 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_check_registration(nl_client, IWPM_REG_VALID) ||
|
| 73 | iwpm_user_pid == IWPM_PID_UNAVAILABLE)
|
| 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 |
|
| 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;
|
| 93 | ret = ibnl_put_attr(skb, nlh, IFNAMSIZ,
|
| 94 | pm_msg->if_name, IWPM_NLA_REG_IF_NAME);
|
| 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 |
|
| 106 | nlmsg_end(skb, nlh);
|
| 107 |
|
| 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 |
|
| 111 | ret = rdma_nl_multicast(&init_net, skb, RDMA_NL_GROUP_IWPM, GFP_KERNEL);
|
| 112 | if (ret) {
|
| 113 | skb = NULL;
|
| 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:
|
| 122 | pr_info("%s: %s (client = %u)\n", __func__, err_str, nl_client);
|
| 123 | dev_kfree_skb(skb);
|
| 124 | if (nlmsg_request)
|
| 125 | iwpm_free_nlmsg_request(&nlmsg_request->kref);
|
| 126 | return ret;
|
| 127 | }
|
| 128 |
|
| 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 | *
|
| 135 | * nlmsg attributes:
|
| 136 | * [IWPM_NLA_MANAGE_MAPPING_SEQ]
|
| 137 | * [IWPM_NLA_MANAGE_ADDR]
|
| 138 | * [IWPM_NLA_MANAGE_FLAGS]
|
| 139 | *
|
| 140 | * If the request is successful, the pm_msg stores
|
| 141 | * the port mapper response (mapped address info)
|
| 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 |
|
| 152 | if (!iwpm_valid_pid())
|
| 153 | return 0;
|
| 154 | if (!iwpm_check_registration(nl_client, IWPM_REG_VALID)) {
|
| 155 | err_str = "Unregistered port mapper client";
|
| 156 | goto add_mapping_error;
|
| 157 | }
|
| 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 |
|
| 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;
|
| 180 |
|
| 181 |
|
| 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 |
|
| 193 | nlmsg_end(skb, nlh);
|
| 194 | nlmsg_request->req_buffer = pm_msg;
|
| 195 |
|
| 196 | ret = rdma_nl_unicast_wait(&init_net, skb, iwpm_user_pid);
|
| 197 | if (ret) {
|
| 198 | skb = NULL;
|
| 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:
|
| 206 | pr_info("%s: %s (client = %u)\n", __func__, err_str, nl_client);
|
| 207 | add_mapping_error_nowarn:
|
| 208 | dev_kfree_skb(skb);
|
| 209 | if (nlmsg_request)
|
| 210 | iwpm_free_nlmsg_request(&nlmsg_request->kref);
|
| 211 | return ret;
|
| 212 | }
|
| 213 |
|
| 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 | *
|
| 220 | * nlmsg attributes:
|
| 221 | * [IWPM_NLA_QUERY_MAPPING_SEQ]
|
| 222 | * [IWPM_NLA_QUERY_LOCAL_ADDR]
|
| 223 | * [IWPM_NLA_QUERY_REMOTE_ADDR]
|
| 224 | * [IWPM_NLA_QUERY_FLAGS]
|
| 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 |
|
| 235 | if (!iwpm_valid_pid())
|
| 236 | return 0;
|
| 237 | if (!iwpm_check_registration(nl_client, IWPM_REG_VALID)) {
|
| 238 | err_str = "Unregistered port mapper client";
|
| 239 | goto query_mapping_error;
|
| 240 | }
|
| 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 |
|
| 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;
|
| 270 |
|
| 271 |
|
| 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 |
|
| 283 | nlmsg_end(skb, nlh);
|
| 284 | nlmsg_request->req_buffer = pm_msg;
|
| 285 |
|
| 286 | ret = rdma_nl_unicast_wait(&init_net, skb, iwpm_user_pid);
|
| 287 | if (ret) {
|
| 288 | skb = NULL;
|
| 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:
|
| 295 | pr_info("%s: %s (client = %u)\n", __func__, err_str, nl_client);
|
| 296 | query_mapping_error_nowarn:
|
| 297 | dev_kfree_skb(skb);
|
| 298 | if (nlmsg_request)
|
| 299 | iwpm_free_nlmsg_request(&nlmsg_request->kref);
|
| 300 | return ret;
|
| 301 | }
|
| 302 |
|
| 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 | *
|
| 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 |
|
| 322 | if (!iwpm_valid_pid())
|
| 323 | return 0;
|
| 324 | if (iwpm_check_registration(nl_client, IWPM_REG_UNDEF)) {
|
| 325 | err_str = "Unregistered port mapper client";
|
| 326 | goto remove_mapping_error;
|
| 327 | }
|
| 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 |
|
| 346 | nlmsg_end(skb, nlh);
|
| 347 |
|
| 348 | ret = rdma_nl_unicast_wait(&init_net, skb, iwpm_user_pid);
|
| 349 | if (ret) {
|
| 350 | skb = NULL;
|
| 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:
|
| 359 | pr_info("%s: %s (client = %u)\n", __func__, err_str, nl_client);
|
| 360 | if (skb)
|
| 361 | dev_kfree_skb_any(skb);
|
| 362 | return ret;
|
| 363 | }
|
| 364 |
|
| 365 |
|
| 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_NUL_STRING,
|
| 369 | .len = IWPM_DEVNAME_SIZE - 1 },
|
| 370 | [IWPM_NLA_RREG_ULIB_NAME] = { .type = NLA_NUL_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 |
|
| 376 | |
| 377 | * iwpm_register_pid_cb - Process the port mapper response to
|
| 378 | * iwpm_register_pid query
|
| 379 | * @skb: The socket buffer
|
| 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
|
| 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 |
|
| 414 | if (strcmp(pm_msg->dev_name, dev_name) ||
|
| 415 | strcmp(iwpm_ulib_name, iwpm_name) ||
|
| 416 | iwpm_version < IWPM_UABI_VERSION_MIN) {
|
| 417 |
|
| 418 | pr_info("%s: Incorrect info (dev = %s name = %s version = %u)\n",
|
| 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;
|
| 424 | iwpm_ulib_version = iwpm_version;
|
| 425 | if (iwpm_ulib_version < IWPM_UABI_VERSION)
|
| 426 | pr_warn_once("%s: Down level iwpmd/pid %d. Continuing...",
|
| 427 | __func__, iwpm_user_pid);
|
| 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);
|
| 431 | iwpm_set_registration(nl_client, IWPM_REG_VALID);
|
| 432 | register_pid_response_exit:
|
| 433 | nlmsg_request->request_done = 1;
|
| 434 |
|
| 435 | kref_put(&nlmsg_request->kref, iwpm_free_nlmsg_request);
|
| 436 | barrier();
|
| 437 | up(&nlmsg_request->sem);
|
| 438 | return 0;
|
| 439 | }
|
| 440 |
|
| 441 |
|
| 442 | static const struct nla_policy resp_add_policy[IWPM_NLA_RMANAGE_MAPPING_MAX] = {
|
| 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 }
|
| 449 | };
|
| 450 |
|
| 451 | |
| 452 | * iwpm_add_mapping_cb - Process the port mapper response to
|
| 453 | * iwpm_add_mapping request
|
| 454 | * @skb: The socket buffer
|
| 455 | * @cb: Contains the received message (payload and netlink header)
|
| 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 |
|
| 474 | msg_seq = nla_get_u32(nltb[IWPM_NLA_RMANAGE_MAPPING_SEQ]);
|
| 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 *)
|
| 483 | nla_data(nltb[IWPM_NLA_RMANAGE_ADDR]);
|
| 484 | mapped_sockaddr = (struct sockaddr_storage *)
|
| 485 | nla_data(nltb[IWPM_NLA_RMANAGE_MAPPED_LOC_ADDR]);
|
| 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 |
|
| 507 | kref_put(&nlmsg_request->kref, iwpm_free_nlmsg_request);
|
| 508 | barrier();
|
| 509 | up(&nlmsg_request->sem);
|
| 510 | return 0;
|
| 511 | }
|
| 512 |
|
| 513 | |
| 514 | * and response with remote address info
|
| 515 |
|
| 516 | static const struct nla_policy resp_query_policy[IWPM_NLA_RQUERY_MAPPING_MAX] = {
|
| 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) },
|
| 526 | [IWPM_NLA_RQUERY_MAPPING_ERR] = { .type = NLA_U16 }
|
| 527 | };
|
| 528 |
|
| 529 | |
| 530 | * iwpm_add_and_query_mapping_cb - Process the port mapper response to
|
| 531 | * iwpm_add_and_query_mapping request
|
| 532 | * @skb: The socket buffer
|
| 533 | * @cb: Contains the received message (payload and netlink header)
|
| 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 |
|
| 553 | msg_seq = nla_get_u32(nltb[IWPM_NLA_RQUERY_MAPPING_SEQ]);
|
| 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);
|
| 558 | return -EINVAL;
|
| 559 | }
|
| 560 | pm_msg = nlmsg_request->req_buffer;
|
| 561 | local_sockaddr = (struct sockaddr_storage *)
|
| 562 | nla_data(nltb[IWPM_NLA_RQUERY_LOCAL_ADDR]);
|
| 563 | remote_sockaddr = (struct sockaddr_storage *)
|
| 564 | nla_data(nltb[IWPM_NLA_RQUERY_REMOTE_ADDR]);
|
| 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 |
|
| 605 | kref_put(&nlmsg_request->kref, iwpm_free_nlmsg_request);
|
| 606 | barrier();
|
| 607 | up(&nlmsg_request->sem);
|
| 608 | return 0;
|
| 609 | }
|
| 610 |
|
| 611 | |
| 612 | * iwpm_remote_info_cb - Process remote connecting peer address info, which
|
| 613 | * the port mapper has received from the connecting peer
|
| 614 | * @skb: The socket buffer
|
| 615 | * @cb: Contains the received message (payload and netlink header)
|
| 616 | *
|
| 617 | * Stores the IPv4/IPv6 address info in a hash table
|
| 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);
|
| 635 | atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
|
| 636 |
|
| 637 | local_sockaddr = (struct sockaddr_storage *)
|
| 638 | nla_data(nltb[IWPM_NLA_RQUERY_LOCAL_ADDR]);
|
| 639 | remote_sockaddr = (struct sockaddr_storage *)
|
| 640 | nla_data(nltb[IWPM_NLA_RQUERY_REMOTE_ADDR]);
|
| 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_obj(struct iwpm_remote_info, GFP_ATOMIC);
|
| 653 | if (!rem_info) {
|
| 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 | }
|
| 677 |
|
| 678 |
|
| 679 | static const struct nla_policy resp_mapinfo_policy[IWPM_NLA_MAPINFO_REQ_MAX] = {
|
| 680 | [IWPM_NLA_MAPINFO_ULIB_NAME] = { .type = NLA_NUL_STRING,
|
| 681 | .len = IWPM_ULIBNAME_SIZE - 1 },
|
| 682 | [IWPM_NLA_MAPINFO_ULIB_VER] = { .type = NLA_U16 }
|
| 683 | };
|
| 684 |
|
| 685 | |
| 686 | * iwpm_mapping_info_cb - Process a notification that the userspace
|
| 687 | * port mapper daemon is started
|
| 688 | * @skb: The socket buffer
|
| 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
|
| 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";
|
| 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) ||
|
| 711 | iwpm_version < IWPM_UABI_VERSION_MIN) {
|
| 712 | pr_info("%s: Invalid port mapper name = %s version = %u\n",
|
| 713 | __func__, iwpm_name, iwpm_version);
|
| 714 | return ret;
|
| 715 | }
|
| 716 | nl_client = RDMA_NL_GET_CLIENT(cb->nlh->nlmsg_type);
|
| 717 | iwpm_set_registration(nl_client, IWPM_REG_INCOMPL);
|
| 718 | atomic_set(&echo_nlmsg_seq, cb->nlh->nlmsg_seq);
|
| 719 | iwpm_user_pid = cb->nlh->nlmsg_pid;
|
| 720 |
|
| 721 | if (iwpm_ulib_version < IWPM_UABI_VERSION)
|
| 722 | pr_warn_once("%s: Down level iwpmd/pid %d. Continuing...",
|
| 723 | __func__, iwpm_user_pid);
|
| 724 |
|
| 725 | if (!iwpm_mapinfo_available())
|
| 726 | return 0;
|
| 727 | pr_debug("%s: iWarp Port Mapper (pid = %d) is available!\n",
|
| 728 | __func__, iwpm_user_pid);
|
| 729 | ret = iwpm_send_mapinfo(nl_client, iwpm_user_pid);
|
| 730 | return ret;
|
| 731 | }
|
| 732 |
|
| 733 |
|
| 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 |
|
| 740 | |
| 741 | * iwpm_ack_mapping_info_cb - Process the port mapper ack for
|
| 742 | * the provided local mapping info records
|
| 743 | * @skb: The socket buffer
|
| 744 | * @cb: Contains the received message (payload and netlink header)
|
| 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 | }
|
| 763 |
|
| 764 |
|
| 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 |
|
| 770 | |
| 771 | * iwpm_mapping_error_cb - Process port mapper notification for error
|
| 772 | *
|
| 773 | * @skb: The socket buffer
|
| 774 | * @cb: Contains the received message (payload and netlink header)
|
| 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 |
|
| 794 | nlmsg_request = iwpm_find_nlmsg_request(msg_seq);
|
| 795 | if (!nlmsg_request) {
|
| 796 |
|
| 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 |
|
| 804 | kref_put(&nlmsg_request->kref, iwpm_free_nlmsg_request);
|
| 805 | barrier();
|
| 806 | up(&nlmsg_request->sem);
|
| 807 | return 0;
|
| 808 | }
|
| 809 |
|
| 810 |
|
| 811 | static const struct nla_policy hello_policy[IWPM_NLA_HELLO_MAX] = {
|
| 812 | [IWPM_NLA_HELLO_ABI_VERSION] = { .type = NLA_U16 }
|
| 813 | };
|
| 814 |
|
| 815 | |
| 816 | * iwpm_hello_cb - Process a hello message from iwpmd
|
| 817 | *
|
| 818 | * @skb: The socket buffer
|
| 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.
|
| 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);
|
| 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 | }
|