linux/drivers/infiniband/core/iwpm_util.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2014 Chelsio, Inc. All rights reserved.
   3 * Copyright (c) 2014 Intel Corporation. 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#define IWPM_MAPINFO_HASH_SIZE  512
  37#define IWPM_MAPINFO_HASH_MASK  (IWPM_MAPINFO_HASH_SIZE - 1)
  38#define IWPM_REMINFO_HASH_SIZE  64
  39#define IWPM_REMINFO_HASH_MASK  (IWPM_REMINFO_HASH_SIZE - 1)
  40#define IWPM_MSG_SIZE           512
  41
  42static LIST_HEAD(iwpm_nlmsg_req_list);
  43static DEFINE_SPINLOCK(iwpm_nlmsg_req_lock);
  44
  45static struct hlist_head *iwpm_hash_bucket;
  46static DEFINE_SPINLOCK(iwpm_mapinfo_lock);
  47
  48static struct hlist_head *iwpm_reminfo_bucket;
  49static DEFINE_SPINLOCK(iwpm_reminfo_lock);
  50
  51static DEFINE_MUTEX(iwpm_admin_lock);
  52static struct iwpm_admin_data iwpm_admin;
  53
  54/**
  55 * iwpm_init - Allocate resources for the iwarp port mapper
  56 * @nl_client: The index of the netlink client
  57 *
  58 * Should be called when network interface goes up.
  59 */
  60int iwpm_init(u8 nl_client)
  61{
  62        int ret = 0;
  63        mutex_lock(&iwpm_admin_lock);
  64        if (atomic_read(&iwpm_admin.refcount) == 0) {
  65                iwpm_hash_bucket = kcalloc(IWPM_MAPINFO_HASH_SIZE,
  66                                           sizeof(struct hlist_head),
  67                                           GFP_KERNEL);
  68                if (!iwpm_hash_bucket) {
  69                        ret = -ENOMEM;
  70                        goto init_exit;
  71                }
  72                iwpm_reminfo_bucket = kcalloc(IWPM_REMINFO_HASH_SIZE,
  73                                              sizeof(struct hlist_head),
  74                                              GFP_KERNEL);
  75                if (!iwpm_reminfo_bucket) {
  76                        kfree(iwpm_hash_bucket);
  77                        ret = -ENOMEM;
  78                        goto init_exit;
  79                }
  80        }
  81        atomic_inc(&iwpm_admin.refcount);
  82init_exit:
  83        mutex_unlock(&iwpm_admin_lock);
  84        if (!ret) {
  85                iwpm_set_valid(nl_client, 1);
  86                iwpm_set_registration(nl_client, IWPM_REG_UNDEF);
  87                pr_debug("%s: Mapinfo and reminfo tables are created\n",
  88                                __func__);
  89        }
  90        return ret;
  91}
  92
  93static void free_hash_bucket(void);
  94static void free_reminfo_bucket(void);
  95
  96/**
  97 * iwpm_exit - Deallocate resources for the iwarp port mapper
  98 * @nl_client: The index of the netlink client
  99 *
 100 * Should be called when network interface goes down.
 101 */
 102int iwpm_exit(u8 nl_client)
 103{
 104
 105        if (!iwpm_valid_client(nl_client))
 106                return -EINVAL;
 107        mutex_lock(&iwpm_admin_lock);
 108        if (atomic_read(&iwpm_admin.refcount) == 0) {
 109                mutex_unlock(&iwpm_admin_lock);
 110                pr_err("%s Incorrect usage - negative refcount\n", __func__);
 111                return -EINVAL;
 112        }
 113        if (atomic_dec_and_test(&iwpm_admin.refcount)) {
 114                free_hash_bucket();
 115                free_reminfo_bucket();
 116                pr_debug("%s: Resources are destroyed\n", __func__);
 117        }
 118        mutex_unlock(&iwpm_admin_lock);
 119        iwpm_set_valid(nl_client, 0);
 120        iwpm_set_registration(nl_client, IWPM_REG_UNDEF);
 121        return 0;
 122}
 123
 124static struct hlist_head *get_mapinfo_hash_bucket(struct sockaddr_storage *,
 125                                               struct sockaddr_storage *);
 126
 127/**
 128 * iwpm_create_mapinfo - Store local and mapped IPv4/IPv6 address
 129 *                       info in a hash table
 130 * @local_addr: Local ip/tcp address
 131 * @mapped_addr: Mapped local ip/tcp address
 132 * @nl_client: The index of the netlink client
 133 * @map_flags: IWPM mapping flags
 134 */
 135int iwpm_create_mapinfo(struct sockaddr_storage *local_sockaddr,
 136                        struct sockaddr_storage *mapped_sockaddr,
 137                        u8 nl_client, u32 map_flags)
 138{
 139        struct hlist_head *hash_bucket_head = NULL;
 140        struct iwpm_mapping_info *map_info;
 141        unsigned long flags;
 142        int ret = -EINVAL;
 143
 144        if (!iwpm_valid_client(nl_client))
 145                return ret;
 146        map_info = kzalloc(sizeof(struct iwpm_mapping_info), GFP_KERNEL);
 147        if (!map_info)
 148                return -ENOMEM;
 149
 150        memcpy(&map_info->local_sockaddr, local_sockaddr,
 151               sizeof(struct sockaddr_storage));
 152        memcpy(&map_info->mapped_sockaddr, mapped_sockaddr,
 153               sizeof(struct sockaddr_storage));
 154        map_info->nl_client = nl_client;
 155        map_info->map_flags = map_flags;
 156
 157        spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
 158        if (iwpm_hash_bucket) {
 159                hash_bucket_head = get_mapinfo_hash_bucket(
 160                                        &map_info->local_sockaddr,
 161                                        &map_info->mapped_sockaddr);
 162                if (hash_bucket_head) {
 163                        hlist_add_head(&map_info->hlist_node, hash_bucket_head);
 164                        ret = 0;
 165                }
 166        }
 167        spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags);
 168
 169        if (!hash_bucket_head)
 170                kfree(map_info);
 171        return ret;
 172}
 173
 174/**
 175 * iwpm_remove_mapinfo - Remove local and mapped IPv4/IPv6 address
 176 *                       info from the hash table
 177 * @local_addr: Local ip/tcp address
 178 * @mapped_local_addr: Mapped local ip/tcp address
 179 *
 180 * Returns err code if mapping info is not found in the hash table,
 181 * otherwise returns 0
 182 */
 183int iwpm_remove_mapinfo(struct sockaddr_storage *local_sockaddr,
 184                        struct sockaddr_storage *mapped_local_addr)
 185{
 186        struct hlist_node *tmp_hlist_node;
 187        struct hlist_head *hash_bucket_head;
 188        struct iwpm_mapping_info *map_info = NULL;
 189        unsigned long flags;
 190        int ret = -EINVAL;
 191
 192        spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
 193        if (iwpm_hash_bucket) {
 194                hash_bucket_head = get_mapinfo_hash_bucket(
 195                                        local_sockaddr,
 196                                        mapped_local_addr);
 197                if (!hash_bucket_head)
 198                        goto remove_mapinfo_exit;
 199
 200                hlist_for_each_entry_safe(map_info, tmp_hlist_node,
 201                                        hash_bucket_head, hlist_node) {
 202
 203                        if (!iwpm_compare_sockaddr(&map_info->mapped_sockaddr,
 204                                                mapped_local_addr)) {
 205
 206                                hlist_del_init(&map_info->hlist_node);
 207                                kfree(map_info);
 208                                ret = 0;
 209                                break;
 210                        }
 211                }
 212        }
 213remove_mapinfo_exit:
 214        spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags);
 215        return ret;
 216}
 217
 218static void free_hash_bucket(void)
 219{
 220        struct hlist_node *tmp_hlist_node;
 221        struct iwpm_mapping_info *map_info;
 222        unsigned long flags;
 223        int i;
 224
 225        /* remove all the mapinfo data from the list */
 226        spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
 227        for (i = 0; i < IWPM_MAPINFO_HASH_SIZE; i++) {
 228                hlist_for_each_entry_safe(map_info, tmp_hlist_node,
 229                        &iwpm_hash_bucket[i], hlist_node) {
 230
 231                                hlist_del_init(&map_info->hlist_node);
 232                                kfree(map_info);
 233                        }
 234        }
 235        /* free the hash list */
 236        kfree(iwpm_hash_bucket);
 237        iwpm_hash_bucket = NULL;
 238        spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags);
 239}
 240
 241static void free_reminfo_bucket(void)
 242{
 243        struct hlist_node *tmp_hlist_node;
 244        struct iwpm_remote_info *rem_info;
 245        unsigned long flags;
 246        int i;
 247
 248        /* remove all the remote info from the list */
 249        spin_lock_irqsave(&iwpm_reminfo_lock, flags);
 250        for (i = 0; i < IWPM_REMINFO_HASH_SIZE; i++) {
 251                hlist_for_each_entry_safe(rem_info, tmp_hlist_node,
 252                        &iwpm_reminfo_bucket[i], hlist_node) {
 253
 254                                hlist_del_init(&rem_info->hlist_node);
 255                                kfree(rem_info);
 256                        }
 257        }
 258        /* free the hash list */
 259        kfree(iwpm_reminfo_bucket);
 260        iwpm_reminfo_bucket = NULL;
 261        spin_unlock_irqrestore(&iwpm_reminfo_lock, flags);
 262}
 263
 264static struct hlist_head *get_reminfo_hash_bucket(struct sockaddr_storage *,
 265                                                struct sockaddr_storage *);
 266
 267void iwpm_add_remote_info(struct iwpm_remote_info *rem_info)
 268{
 269        struct hlist_head *hash_bucket_head;
 270        unsigned long flags;
 271
 272        spin_lock_irqsave(&iwpm_reminfo_lock, flags);
 273        if (iwpm_reminfo_bucket) {
 274                hash_bucket_head = get_reminfo_hash_bucket(
 275                                        &rem_info->mapped_loc_sockaddr,
 276                                        &rem_info->mapped_rem_sockaddr);
 277                if (hash_bucket_head)
 278                        hlist_add_head(&rem_info->hlist_node, hash_bucket_head);
 279        }
 280        spin_unlock_irqrestore(&iwpm_reminfo_lock, flags);
 281}
 282
 283/**
 284 * iwpm_get_remote_info - Get the remote connecting peer address info
 285 *
 286 * @mapped_loc_addr: Mapped local address of the listening peer
 287 * @mapped_rem_addr: Mapped remote address of the connecting peer
 288 * @remote_addr: To store the remote address of the connecting peer
 289 * @nl_client: The index of the netlink client
 290 *
 291 * The remote address info is retrieved and provided to the client in
 292 * the remote_addr. After that it is removed from the hash table
 293 */
 294int iwpm_get_remote_info(struct sockaddr_storage *mapped_loc_addr,
 295                         struct sockaddr_storage *mapped_rem_addr,
 296                         struct sockaddr_storage *remote_addr,
 297                         u8 nl_client)
 298{
 299        struct hlist_node *tmp_hlist_node;
 300        struct hlist_head *hash_bucket_head;
 301        struct iwpm_remote_info *rem_info = NULL;
 302        unsigned long flags;
 303        int ret = -EINVAL;
 304
 305        if (!iwpm_valid_client(nl_client)) {
 306                pr_info("%s: Invalid client = %d\n", __func__, nl_client);
 307                return ret;
 308        }
 309        spin_lock_irqsave(&iwpm_reminfo_lock, flags);
 310        if (iwpm_reminfo_bucket) {
 311                hash_bucket_head = get_reminfo_hash_bucket(
 312                                        mapped_loc_addr,
 313                                        mapped_rem_addr);
 314                if (!hash_bucket_head)
 315                        goto get_remote_info_exit;
 316                hlist_for_each_entry_safe(rem_info, tmp_hlist_node,
 317                                        hash_bucket_head, hlist_node) {
 318
 319                        if (!iwpm_compare_sockaddr(&rem_info->mapped_loc_sockaddr,
 320                                mapped_loc_addr) &&
 321                                !iwpm_compare_sockaddr(&rem_info->mapped_rem_sockaddr,
 322                                mapped_rem_addr)) {
 323
 324                                memcpy(remote_addr, &rem_info->remote_sockaddr,
 325                                        sizeof(struct sockaddr_storage));
 326                                iwpm_print_sockaddr(remote_addr,
 327                                                "get_remote_info: Remote sockaddr:");
 328
 329                                hlist_del_init(&rem_info->hlist_node);
 330                                kfree(rem_info);
 331                                ret = 0;
 332                                break;
 333                        }
 334                }
 335        }
 336get_remote_info_exit:
 337        spin_unlock_irqrestore(&iwpm_reminfo_lock, flags);
 338        return ret;
 339}
 340
 341struct iwpm_nlmsg_request *iwpm_get_nlmsg_request(__u32 nlmsg_seq,
 342                                        u8 nl_client, gfp_t gfp)
 343{
 344        struct iwpm_nlmsg_request *nlmsg_request = NULL;
 345        unsigned long flags;
 346
 347        nlmsg_request = kzalloc(sizeof(struct iwpm_nlmsg_request), gfp);
 348        if (!nlmsg_request)
 349                return NULL;
 350
 351        spin_lock_irqsave(&iwpm_nlmsg_req_lock, flags);
 352        list_add_tail(&nlmsg_request->inprocess_list, &iwpm_nlmsg_req_list);
 353        spin_unlock_irqrestore(&iwpm_nlmsg_req_lock, flags);
 354
 355        kref_init(&nlmsg_request->kref);
 356        kref_get(&nlmsg_request->kref);
 357        nlmsg_request->nlmsg_seq = nlmsg_seq;
 358        nlmsg_request->nl_client = nl_client;
 359        nlmsg_request->request_done = 0;
 360        nlmsg_request->err_code = 0;
 361        sema_init(&nlmsg_request->sem, 1);
 362        down(&nlmsg_request->sem);
 363        return nlmsg_request;
 364}
 365
 366void iwpm_free_nlmsg_request(struct kref *kref)
 367{
 368        struct iwpm_nlmsg_request *nlmsg_request;
 369        unsigned long flags;
 370
 371        nlmsg_request = container_of(kref, struct iwpm_nlmsg_request, kref);
 372
 373        spin_lock_irqsave(&iwpm_nlmsg_req_lock, flags);
 374        list_del_init(&nlmsg_request->inprocess_list);
 375        spin_unlock_irqrestore(&iwpm_nlmsg_req_lock, flags);
 376
 377        if (!nlmsg_request->request_done)
 378                pr_debug("%s Freeing incomplete nlmsg request (seq = %u).\n",
 379                        __func__, nlmsg_request->nlmsg_seq);
 380        kfree(nlmsg_request);
 381}
 382
 383struct iwpm_nlmsg_request *iwpm_find_nlmsg_request(__u32 echo_seq)
 384{
 385        struct iwpm_nlmsg_request *nlmsg_request;
 386        struct iwpm_nlmsg_request *found_request = NULL;
 387        unsigned long flags;
 388
 389        spin_lock_irqsave(&iwpm_nlmsg_req_lock, flags);
 390        list_for_each_entry(nlmsg_request, &iwpm_nlmsg_req_list,
 391                            inprocess_list) {
 392                if (nlmsg_request->nlmsg_seq == echo_seq) {
 393                        found_request = nlmsg_request;
 394                        kref_get(&nlmsg_request->kref);
 395                        break;
 396                }
 397        }
 398        spin_unlock_irqrestore(&iwpm_nlmsg_req_lock, flags);
 399        return found_request;
 400}
 401
 402int iwpm_wait_complete_req(struct iwpm_nlmsg_request *nlmsg_request)
 403{
 404        int ret;
 405
 406        ret = down_timeout(&nlmsg_request->sem, IWPM_NL_TIMEOUT);
 407        if (ret) {
 408                ret = -EINVAL;
 409                pr_info("%s: Timeout %d sec for netlink request (seq = %u)\n",
 410                        __func__, (IWPM_NL_TIMEOUT/HZ), nlmsg_request->nlmsg_seq);
 411        } else {
 412                ret = nlmsg_request->err_code;
 413        }
 414        kref_put(&nlmsg_request->kref, iwpm_free_nlmsg_request);
 415        return ret;
 416}
 417
 418int iwpm_get_nlmsg_seq(void)
 419{
 420        return atomic_inc_return(&iwpm_admin.nlmsg_seq);
 421}
 422
 423int iwpm_valid_client(u8 nl_client)
 424{
 425        return iwpm_admin.client_list[nl_client];
 426}
 427
 428void iwpm_set_valid(u8 nl_client, int valid)
 429{
 430        iwpm_admin.client_list[nl_client] = valid;
 431}
 432
 433/* valid client */
 434u32 iwpm_get_registration(u8 nl_client)
 435{
 436        return iwpm_admin.reg_list[nl_client];
 437}
 438
 439/* valid client */
 440void iwpm_set_registration(u8 nl_client, u32 reg)
 441{
 442        iwpm_admin.reg_list[nl_client] = reg;
 443}
 444
 445/* valid client */
 446u32 iwpm_check_registration(u8 nl_client, u32 reg)
 447{
 448        return (iwpm_get_registration(nl_client) & reg);
 449}
 450
 451int iwpm_compare_sockaddr(struct sockaddr_storage *a_sockaddr,
 452                                struct sockaddr_storage *b_sockaddr)
 453{
 454        if (a_sockaddr->ss_family != b_sockaddr->ss_family)
 455                return 1;
 456        if (a_sockaddr->ss_family == AF_INET) {
 457                struct sockaddr_in *a4_sockaddr =
 458                        (struct sockaddr_in *)a_sockaddr;
 459                struct sockaddr_in *b4_sockaddr =
 460                        (struct sockaddr_in *)b_sockaddr;
 461                if (!memcmp(&a4_sockaddr->sin_addr,
 462                        &b4_sockaddr->sin_addr, sizeof(struct in_addr))
 463                        && a4_sockaddr->sin_port == b4_sockaddr->sin_port)
 464                                return 0;
 465
 466        } else if (a_sockaddr->ss_family == AF_INET6) {
 467                struct sockaddr_in6 *a6_sockaddr =
 468                        (struct sockaddr_in6 *)a_sockaddr;
 469                struct sockaddr_in6 *b6_sockaddr =
 470                        (struct sockaddr_in6 *)b_sockaddr;
 471                if (!memcmp(&a6_sockaddr->sin6_addr,
 472                        &b6_sockaddr->sin6_addr, sizeof(struct in6_addr))
 473                        && a6_sockaddr->sin6_port == b6_sockaddr->sin6_port)
 474                                return 0;
 475
 476        } else {
 477                pr_err("%s: Invalid sockaddr family\n", __func__);
 478        }
 479        return 1;
 480}
 481
 482struct sk_buff *iwpm_create_nlmsg(u32 nl_op, struct nlmsghdr **nlh,
 483                                                int nl_client)
 484{
 485        struct sk_buff *skb = NULL;
 486
 487        skb = dev_alloc_skb(IWPM_MSG_SIZE);
 488        if (!skb)
 489                goto create_nlmsg_exit;
 490
 491        if (!(ibnl_put_msg(skb, nlh, 0, 0, nl_client, nl_op,
 492                           NLM_F_REQUEST))) {
 493                pr_warn("%s: Unable to put the nlmsg header\n", __func__);
 494                dev_kfree_skb(skb);
 495                skb = NULL;
 496        }
 497create_nlmsg_exit:
 498        return skb;
 499}
 500
 501int iwpm_parse_nlmsg(struct netlink_callback *cb, int policy_max,
 502                                   const struct nla_policy *nlmsg_policy,
 503                                   struct nlattr *nltb[], const char *msg_type)
 504{
 505        int nlh_len = 0;
 506        int ret;
 507        const char *err_str = "";
 508
 509        ret = nlmsg_validate_deprecated(cb->nlh, nlh_len, policy_max - 1,
 510                                        nlmsg_policy, NULL);
 511        if (ret) {
 512                err_str = "Invalid attribute";
 513                goto parse_nlmsg_error;
 514        }
 515        ret = nlmsg_parse_deprecated(cb->nlh, nlh_len, nltb, policy_max - 1,
 516                                     nlmsg_policy, NULL);
 517        if (ret) {
 518                err_str = "Unable to parse the nlmsg";
 519                goto parse_nlmsg_error;
 520        }
 521        ret = iwpm_validate_nlmsg_attr(nltb, policy_max);
 522        if (ret) {
 523                err_str = "Invalid NULL attribute";
 524                goto parse_nlmsg_error;
 525        }
 526        return 0;
 527parse_nlmsg_error:
 528        pr_warn("%s: %s (msg type %s ret = %d)\n",
 529                        __func__, err_str, msg_type, ret);
 530        return ret;
 531}
 532
 533void iwpm_print_sockaddr(struct sockaddr_storage *sockaddr, char *msg)
 534{
 535        struct sockaddr_in6 *sockaddr_v6;
 536        struct sockaddr_in *sockaddr_v4;
 537
 538        switch (sockaddr->ss_family) {
 539        case AF_INET:
 540                sockaddr_v4 = (struct sockaddr_in *)sockaddr;
 541                pr_debug("%s IPV4 %pI4: %u(0x%04X)\n",
 542                        msg, &sockaddr_v4->sin_addr,
 543                        ntohs(sockaddr_v4->sin_port),
 544                        ntohs(sockaddr_v4->sin_port));
 545                break;
 546        case AF_INET6:
 547                sockaddr_v6 = (struct sockaddr_in6 *)sockaddr;
 548                pr_debug("%s IPV6 %pI6: %u(0x%04X)\n",
 549                        msg, &sockaddr_v6->sin6_addr,
 550                        ntohs(sockaddr_v6->sin6_port),
 551                        ntohs(sockaddr_v6->sin6_port));
 552                break;
 553        default:
 554                break;
 555        }
 556}
 557
 558static u32 iwpm_ipv6_jhash(struct sockaddr_in6 *ipv6_sockaddr)
 559{
 560        u32 ipv6_hash = jhash(&ipv6_sockaddr->sin6_addr, sizeof(struct in6_addr), 0);
 561        u32 hash = jhash_2words(ipv6_hash, (__force u32) ipv6_sockaddr->sin6_port, 0);
 562        return hash;
 563}
 564
 565static u32 iwpm_ipv4_jhash(struct sockaddr_in *ipv4_sockaddr)
 566{
 567        u32 ipv4_hash = jhash(&ipv4_sockaddr->sin_addr, sizeof(struct in_addr), 0);
 568        u32 hash = jhash_2words(ipv4_hash, (__force u32) ipv4_sockaddr->sin_port, 0);
 569        return hash;
 570}
 571
 572static int get_hash_bucket(struct sockaddr_storage *a_sockaddr,
 573                                struct sockaddr_storage *b_sockaddr, u32 *hash)
 574{
 575        u32 a_hash, b_hash;
 576
 577        if (a_sockaddr->ss_family == AF_INET) {
 578                a_hash = iwpm_ipv4_jhash((struct sockaddr_in *) a_sockaddr);
 579                b_hash = iwpm_ipv4_jhash((struct sockaddr_in *) b_sockaddr);
 580
 581        } else if (a_sockaddr->ss_family == AF_INET6) {
 582                a_hash = iwpm_ipv6_jhash((struct sockaddr_in6 *) a_sockaddr);
 583                b_hash = iwpm_ipv6_jhash((struct sockaddr_in6 *) b_sockaddr);
 584        } else {
 585                pr_err("%s: Invalid sockaddr family\n", __func__);
 586                return -EINVAL;
 587        }
 588
 589        if (a_hash == b_hash) /* if port mapper isn't available */
 590                *hash = a_hash;
 591        else
 592                *hash = jhash_2words(a_hash, b_hash, 0);
 593        return 0;
 594}
 595
 596static struct hlist_head *get_mapinfo_hash_bucket(struct sockaddr_storage
 597                                *local_sockaddr, struct sockaddr_storage
 598                                *mapped_sockaddr)
 599{
 600        u32 hash;
 601        int ret;
 602
 603        ret = get_hash_bucket(local_sockaddr, mapped_sockaddr, &hash);
 604        if (ret)
 605                return NULL;
 606        return &iwpm_hash_bucket[hash & IWPM_MAPINFO_HASH_MASK];
 607}
 608
 609static struct hlist_head *get_reminfo_hash_bucket(struct sockaddr_storage
 610                                *mapped_loc_sockaddr, struct sockaddr_storage
 611                                *mapped_rem_sockaddr)
 612{
 613        u32 hash;
 614        int ret;
 615
 616        ret = get_hash_bucket(mapped_loc_sockaddr, mapped_rem_sockaddr, &hash);
 617        if (ret)
 618                return NULL;
 619        return &iwpm_reminfo_bucket[hash & IWPM_REMINFO_HASH_MASK];
 620}
 621
 622static int send_mapinfo_num(u32 mapping_num, u8 nl_client, int iwpm_pid)
 623{
 624        struct sk_buff *skb = NULL;
 625        struct nlmsghdr *nlh;
 626        u32 msg_seq;
 627        const char *err_str = "";
 628        int ret = -EINVAL;
 629
 630        skb = iwpm_create_nlmsg(RDMA_NL_IWPM_MAPINFO_NUM, &nlh, nl_client);
 631        if (!skb) {
 632                err_str = "Unable to create a nlmsg";
 633                goto mapinfo_num_error;
 634        }
 635        nlh->nlmsg_seq = iwpm_get_nlmsg_seq();
 636        msg_seq = 0;
 637        err_str = "Unable to put attribute of mapinfo number nlmsg";
 638        ret = ibnl_put_attr(skb, nlh, sizeof(u32), &msg_seq, IWPM_NLA_MAPINFO_SEQ);
 639        if (ret)
 640                goto mapinfo_num_error;
 641        ret = ibnl_put_attr(skb, nlh, sizeof(u32),
 642                                &mapping_num, IWPM_NLA_MAPINFO_SEND_NUM);
 643        if (ret)
 644                goto mapinfo_num_error;
 645
 646        nlmsg_end(skb, nlh);
 647
 648        ret = rdma_nl_unicast(skb, iwpm_pid);
 649        if (ret) {
 650                skb = NULL;
 651                err_str = "Unable to send a nlmsg";
 652                goto mapinfo_num_error;
 653        }
 654        pr_debug("%s: Sent mapping number = %d\n", __func__, mapping_num);
 655        return 0;
 656mapinfo_num_error:
 657        pr_info("%s: %s\n", __func__, err_str);
 658        if (skb)
 659                dev_kfree_skb(skb);
 660        return ret;
 661}
 662
 663static int send_nlmsg_done(struct sk_buff *skb, u8 nl_client, int iwpm_pid)
 664{
 665        struct nlmsghdr *nlh = NULL;
 666        int ret = 0;
 667
 668        if (!skb)
 669                return ret;
 670        if (!(ibnl_put_msg(skb, &nlh, 0, 0, nl_client,
 671                           RDMA_NL_IWPM_MAPINFO, NLM_F_MULTI))) {
 672                pr_warn("%s Unable to put NLMSG_DONE\n", __func__);
 673                dev_kfree_skb(skb);
 674                return -ENOMEM;
 675        }
 676        nlh->nlmsg_type = NLMSG_DONE;
 677        ret = rdma_nl_unicast(skb, iwpm_pid);
 678        if (ret)
 679                pr_warn("%s Unable to send a nlmsg\n", __func__);
 680        return ret;
 681}
 682
 683int iwpm_send_mapinfo(u8 nl_client, int iwpm_pid)
 684{
 685        struct iwpm_mapping_info *map_info;
 686        struct sk_buff *skb = NULL;
 687        struct nlmsghdr *nlh;
 688        int skb_num = 0, mapping_num = 0;
 689        int i = 0, nlmsg_bytes = 0;
 690        unsigned long flags;
 691        const char *err_str = "";
 692        int ret;
 693
 694        skb = dev_alloc_skb(NLMSG_GOODSIZE);
 695        if (!skb) {
 696                ret = -ENOMEM;
 697                err_str = "Unable to allocate skb";
 698                goto send_mapping_info_exit;
 699        }
 700        skb_num++;
 701        spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
 702        ret = -EINVAL;
 703        for (i = 0; i < IWPM_MAPINFO_HASH_SIZE; i++) {
 704                hlist_for_each_entry(map_info, &iwpm_hash_bucket[i],
 705                                     hlist_node) {
 706                        if (map_info->nl_client != nl_client)
 707                                continue;
 708                        nlh = NULL;
 709                        if (!(ibnl_put_msg(skb, &nlh, 0, 0, nl_client,
 710                                        RDMA_NL_IWPM_MAPINFO, NLM_F_MULTI))) {
 711                                ret = -ENOMEM;
 712                                err_str = "Unable to put the nlmsg header";
 713                                goto send_mapping_info_unlock;
 714                        }
 715                        err_str = "Unable to put attribute of the nlmsg";
 716                        ret = ibnl_put_attr(skb, nlh,
 717                                        sizeof(struct sockaddr_storage),
 718                                        &map_info->local_sockaddr,
 719                                        IWPM_NLA_MAPINFO_LOCAL_ADDR);
 720                        if (ret)
 721                                goto send_mapping_info_unlock;
 722
 723                        ret = ibnl_put_attr(skb, nlh,
 724                                        sizeof(struct sockaddr_storage),
 725                                        &map_info->mapped_sockaddr,
 726                                        IWPM_NLA_MAPINFO_MAPPED_ADDR);
 727                        if (ret)
 728                                goto send_mapping_info_unlock;
 729
 730                        if (iwpm_ulib_version > IWPM_UABI_VERSION_MIN) {
 731                                ret = ibnl_put_attr(skb, nlh, sizeof(u32),
 732                                                &map_info->map_flags,
 733                                                IWPM_NLA_MAPINFO_FLAGS);
 734                                if (ret)
 735                                        goto send_mapping_info_unlock;
 736                        }
 737
 738                        nlmsg_end(skb, nlh);
 739
 740                        iwpm_print_sockaddr(&map_info->local_sockaddr,
 741                                "send_mapping_info: Local sockaddr:");
 742                        iwpm_print_sockaddr(&map_info->mapped_sockaddr,
 743                                "send_mapping_info: Mapped local sockaddr:");
 744                        mapping_num++;
 745                        nlmsg_bytes += nlh->nlmsg_len;
 746
 747                        /* check if all mappings can fit in one skb */
 748                        if (NLMSG_GOODSIZE - nlmsg_bytes < nlh->nlmsg_len * 2) {
 749                                /* and leave room for NLMSG_DONE */
 750                                nlmsg_bytes = 0;
 751                                skb_num++;
 752                                spin_unlock_irqrestore(&iwpm_mapinfo_lock,
 753                                                       flags);
 754                                /* send the skb */
 755                                ret = send_nlmsg_done(skb, nl_client, iwpm_pid);
 756                                skb = NULL;
 757                                if (ret) {
 758                                        err_str = "Unable to send map info";
 759                                        goto send_mapping_info_exit;
 760                                }
 761                                if (skb_num == IWPM_MAPINFO_SKB_COUNT) {
 762                                        ret = -ENOMEM;
 763                                        err_str = "Insufficient skbs for map info";
 764                                        goto send_mapping_info_exit;
 765                                }
 766                                skb = dev_alloc_skb(NLMSG_GOODSIZE);
 767                                if (!skb) {
 768                                        ret = -ENOMEM;
 769                                        err_str = "Unable to allocate skb";
 770                                        goto send_mapping_info_exit;
 771                                }
 772                                spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
 773                        }
 774                }
 775        }
 776send_mapping_info_unlock:
 777        spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags);
 778send_mapping_info_exit:
 779        if (ret) {
 780                pr_warn("%s: %s (ret = %d)\n", __func__, err_str, ret);
 781                if (skb)
 782                        dev_kfree_skb(skb);
 783                return ret;
 784        }
 785        send_nlmsg_done(skb, nl_client, iwpm_pid);
 786        return send_mapinfo_num(mapping_num, nl_client, iwpm_pid);
 787}
 788
 789int iwpm_mapinfo_available(void)
 790{
 791        unsigned long flags;
 792        int full_bucket = 0, i = 0;
 793
 794        spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
 795        if (iwpm_hash_bucket) {
 796                for (i = 0; i < IWPM_MAPINFO_HASH_SIZE; i++) {
 797                        if (!hlist_empty(&iwpm_hash_bucket[i])) {
 798                                full_bucket = 1;
 799                                break;
 800                        }
 801                }
 802        }
 803        spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags);
 804        return full_bucket;
 805}
 806
 807int iwpm_send_hello(u8 nl_client, int iwpm_pid, u16 abi_version)
 808{
 809        struct sk_buff *skb = NULL;
 810        struct nlmsghdr *nlh;
 811        const char *err_str = "";
 812        int ret = -EINVAL;
 813
 814        skb = iwpm_create_nlmsg(RDMA_NL_IWPM_HELLO, &nlh, nl_client);
 815        if (!skb) {
 816                err_str = "Unable to create a nlmsg";
 817                goto hello_num_error;
 818        }
 819        nlh->nlmsg_seq = iwpm_get_nlmsg_seq();
 820        err_str = "Unable to put attribute of abi_version into nlmsg";
 821        ret = ibnl_put_attr(skb, nlh, sizeof(u16), &abi_version,
 822                            IWPM_NLA_HELLO_ABI_VERSION);
 823        if (ret)
 824                goto hello_num_error;
 825        nlmsg_end(skb, nlh);
 826
 827        ret = rdma_nl_unicast(skb, iwpm_pid);
 828        if (ret) {
 829                skb = NULL;
 830                err_str = "Unable to send a nlmsg";
 831                goto hello_num_error;
 832        }
 833        pr_debug("%s: Sent hello abi_version = %u\n", __func__, abi_version);
 834        return 0;
 835hello_num_error:
 836        pr_info("%s: %s\n", __func__, err_str);
 837        if (skb)
 838                dev_kfree_skb(skb);
 839        return ret;
 840}
 841