Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 2014 Chelsio, Inc. All rights reserved.
0003  * Copyright (c) 2014 Intel Corporation. All rights reserved.
0004  *
0005  * This software is available to you under a choice of one of two
0006  * licenses.  You may choose to be licensed under the terms of the GNU
0007  * General Public License (GPL) Version 2, available from the file
0008  * COPYING in the main directory of this source tree, or the
0009  * OpenIB.org BSD license below:
0010  *
0011  *     Redistribution and use in source and binary forms, with or
0012  *     without modification, are permitted provided that the following
0013  *     conditions are met:
0014  *
0015  *      - Redistributions of source code must retain the above
0016  *    copyright notice, this list of conditions and the following
0017  *    disclaimer.
0018  *
0019  *      - Redistributions in binary form must reproduce the above
0020  *    copyright notice, this list of conditions and the following
0021  *    disclaimer in the documentation and/or other materials
0022  *    provided with the distribution.
0023  *
0024  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
0025  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
0026  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
0027  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
0028  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
0029  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
0030  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
0031  * SOFTWARE.
0032  */
0033 
0034 #include "iwpm_util.h"
0035 
0036 #define IWPM_MAPINFO_HASH_SIZE  512
0037 #define IWPM_MAPINFO_HASH_MASK  (IWPM_MAPINFO_HASH_SIZE - 1)
0038 #define IWPM_REMINFO_HASH_SIZE  64
0039 #define IWPM_REMINFO_HASH_MASK  (IWPM_REMINFO_HASH_SIZE - 1)
0040 #define IWPM_MSG_SIZE       512
0041 
0042 static LIST_HEAD(iwpm_nlmsg_req_list);
0043 static DEFINE_SPINLOCK(iwpm_nlmsg_req_lock);
0044 
0045 static struct hlist_head *iwpm_hash_bucket;
0046 static DEFINE_SPINLOCK(iwpm_mapinfo_lock);
0047 
0048 static struct hlist_head *iwpm_reminfo_bucket;
0049 static DEFINE_SPINLOCK(iwpm_reminfo_lock);
0050 
0051 static struct iwpm_admin_data iwpm_admin;
0052 
0053 /**
0054  * iwpm_init - Allocate resources for the iwarp port mapper
0055  * @nl_client: The index of the netlink client
0056  *
0057  * Should be called when network interface goes up.
0058  */
0059 int iwpm_init(u8 nl_client)
0060 {
0061     iwpm_hash_bucket = kcalloc(IWPM_MAPINFO_HASH_SIZE,
0062                    sizeof(struct hlist_head), GFP_KERNEL);
0063     if (!iwpm_hash_bucket)
0064         return -ENOMEM;
0065 
0066     iwpm_reminfo_bucket = kcalloc(IWPM_REMINFO_HASH_SIZE,
0067                       sizeof(struct hlist_head), GFP_KERNEL);
0068     if (!iwpm_reminfo_bucket) {
0069         kfree(iwpm_hash_bucket);
0070         return -ENOMEM;
0071     }
0072 
0073     iwpm_set_registration(nl_client, IWPM_REG_UNDEF);
0074     pr_debug("%s: Mapinfo and reminfo tables are created\n", __func__);
0075     return 0;
0076 }
0077 
0078 static void free_hash_bucket(void);
0079 static void free_reminfo_bucket(void);
0080 
0081 /**
0082  * iwpm_exit - Deallocate resources for the iwarp port mapper
0083  * @nl_client: The index of the netlink client
0084  *
0085  * Should be called when network interface goes down.
0086  */
0087 int iwpm_exit(u8 nl_client)
0088 {
0089     free_hash_bucket();
0090     free_reminfo_bucket();
0091     pr_debug("%s: Resources are destroyed\n", __func__);
0092     iwpm_set_registration(nl_client, IWPM_REG_UNDEF);
0093     return 0;
0094 }
0095 
0096 static struct hlist_head *get_mapinfo_hash_bucket(struct sockaddr_storage *,
0097                            struct sockaddr_storage *);
0098 
0099 /**
0100  * iwpm_create_mapinfo - Store local and mapped IPv4/IPv6 address
0101  *                       info in a hash table
0102  * @local_sockaddr: Local ip/tcp address
0103  * @mapped_sockaddr: Mapped local ip/tcp address
0104  * @nl_client: The index of the netlink client
0105  * @map_flags: IWPM mapping flags
0106  */
0107 int iwpm_create_mapinfo(struct sockaddr_storage *local_sockaddr,
0108             struct sockaddr_storage *mapped_sockaddr,
0109             u8 nl_client, u32 map_flags)
0110 {
0111     struct hlist_head *hash_bucket_head = NULL;
0112     struct iwpm_mapping_info *map_info;
0113     unsigned long flags;
0114     int ret = -EINVAL;
0115 
0116     map_info = kzalloc(sizeof(struct iwpm_mapping_info), GFP_KERNEL);
0117     if (!map_info)
0118         return -ENOMEM;
0119 
0120     memcpy(&map_info->local_sockaddr, local_sockaddr,
0121            sizeof(struct sockaddr_storage));
0122     memcpy(&map_info->mapped_sockaddr, mapped_sockaddr,
0123            sizeof(struct sockaddr_storage));
0124     map_info->nl_client = nl_client;
0125     map_info->map_flags = map_flags;
0126 
0127     spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
0128     if (iwpm_hash_bucket) {
0129         hash_bucket_head = get_mapinfo_hash_bucket(
0130                     &map_info->local_sockaddr,
0131                     &map_info->mapped_sockaddr);
0132         if (hash_bucket_head) {
0133             hlist_add_head(&map_info->hlist_node, hash_bucket_head);
0134             ret = 0;
0135         }
0136     }
0137     spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags);
0138 
0139     if (!hash_bucket_head)
0140         kfree(map_info);
0141     return ret;
0142 }
0143 
0144 /**
0145  * iwpm_remove_mapinfo - Remove local and mapped IPv4/IPv6 address
0146  *                       info from the hash table
0147  * @local_sockaddr: Local ip/tcp address
0148  * @mapped_local_addr: Mapped local ip/tcp address
0149  *
0150  * Returns err code if mapping info is not found in the hash table,
0151  * otherwise returns 0
0152  */
0153 int iwpm_remove_mapinfo(struct sockaddr_storage *local_sockaddr,
0154             struct sockaddr_storage *mapped_local_addr)
0155 {
0156     struct hlist_node *tmp_hlist_node;
0157     struct hlist_head *hash_bucket_head;
0158     struct iwpm_mapping_info *map_info = NULL;
0159     unsigned long flags;
0160     int ret = -EINVAL;
0161 
0162     spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
0163     if (iwpm_hash_bucket) {
0164         hash_bucket_head = get_mapinfo_hash_bucket(
0165                     local_sockaddr,
0166                     mapped_local_addr);
0167         if (!hash_bucket_head)
0168             goto remove_mapinfo_exit;
0169 
0170         hlist_for_each_entry_safe(map_info, tmp_hlist_node,
0171                     hash_bucket_head, hlist_node) {
0172 
0173             if (!iwpm_compare_sockaddr(&map_info->mapped_sockaddr,
0174                         mapped_local_addr)) {
0175 
0176                 hlist_del_init(&map_info->hlist_node);
0177                 kfree(map_info);
0178                 ret = 0;
0179                 break;
0180             }
0181         }
0182     }
0183 remove_mapinfo_exit:
0184     spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags);
0185     return ret;
0186 }
0187 
0188 static void free_hash_bucket(void)
0189 {
0190     struct hlist_node *tmp_hlist_node;
0191     struct iwpm_mapping_info *map_info;
0192     unsigned long flags;
0193     int i;
0194 
0195     /* remove all the mapinfo data from the list */
0196     spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
0197     for (i = 0; i < IWPM_MAPINFO_HASH_SIZE; i++) {
0198         hlist_for_each_entry_safe(map_info, tmp_hlist_node,
0199             &iwpm_hash_bucket[i], hlist_node) {
0200 
0201                 hlist_del_init(&map_info->hlist_node);
0202                 kfree(map_info);
0203             }
0204     }
0205     /* free the hash list */
0206     kfree(iwpm_hash_bucket);
0207     iwpm_hash_bucket = NULL;
0208     spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags);
0209 }
0210 
0211 static void free_reminfo_bucket(void)
0212 {
0213     struct hlist_node *tmp_hlist_node;
0214     struct iwpm_remote_info *rem_info;
0215     unsigned long flags;
0216     int i;
0217 
0218     /* remove all the remote info from the list */
0219     spin_lock_irqsave(&iwpm_reminfo_lock, flags);
0220     for (i = 0; i < IWPM_REMINFO_HASH_SIZE; i++) {
0221         hlist_for_each_entry_safe(rem_info, tmp_hlist_node,
0222             &iwpm_reminfo_bucket[i], hlist_node) {
0223 
0224                 hlist_del_init(&rem_info->hlist_node);
0225                 kfree(rem_info);
0226             }
0227     }
0228     /* free the hash list */
0229     kfree(iwpm_reminfo_bucket);
0230     iwpm_reminfo_bucket = NULL;
0231     spin_unlock_irqrestore(&iwpm_reminfo_lock, flags);
0232 }
0233 
0234 static struct hlist_head *get_reminfo_hash_bucket(struct sockaddr_storage *,
0235                         struct sockaddr_storage *);
0236 
0237 void iwpm_add_remote_info(struct iwpm_remote_info *rem_info)
0238 {
0239     struct hlist_head *hash_bucket_head;
0240     unsigned long flags;
0241 
0242     spin_lock_irqsave(&iwpm_reminfo_lock, flags);
0243     if (iwpm_reminfo_bucket) {
0244         hash_bucket_head = get_reminfo_hash_bucket(
0245                     &rem_info->mapped_loc_sockaddr,
0246                     &rem_info->mapped_rem_sockaddr);
0247         if (hash_bucket_head)
0248             hlist_add_head(&rem_info->hlist_node, hash_bucket_head);
0249     }
0250     spin_unlock_irqrestore(&iwpm_reminfo_lock, flags);
0251 }
0252 
0253 /**
0254  * iwpm_get_remote_info - Get the remote connecting peer address info
0255  *
0256  * @mapped_loc_addr: Mapped local address of the listening peer
0257  * @mapped_rem_addr: Mapped remote address of the connecting peer
0258  * @remote_addr: To store the remote address of the connecting peer
0259  * @nl_client: The index of the netlink client
0260  *
0261  * The remote address info is retrieved and provided to the client in
0262  * the remote_addr. After that it is removed from the hash table
0263  */
0264 int iwpm_get_remote_info(struct sockaddr_storage *mapped_loc_addr,
0265              struct sockaddr_storage *mapped_rem_addr,
0266              struct sockaddr_storage *remote_addr,
0267              u8 nl_client)
0268 {
0269     struct hlist_node *tmp_hlist_node;
0270     struct hlist_head *hash_bucket_head;
0271     struct iwpm_remote_info *rem_info = NULL;
0272     unsigned long flags;
0273     int ret = -EINVAL;
0274 
0275     spin_lock_irqsave(&iwpm_reminfo_lock, flags);
0276     if (iwpm_reminfo_bucket) {
0277         hash_bucket_head = get_reminfo_hash_bucket(
0278                     mapped_loc_addr,
0279                     mapped_rem_addr);
0280         if (!hash_bucket_head)
0281             goto get_remote_info_exit;
0282         hlist_for_each_entry_safe(rem_info, tmp_hlist_node,
0283                     hash_bucket_head, hlist_node) {
0284 
0285             if (!iwpm_compare_sockaddr(&rem_info->mapped_loc_sockaddr,
0286                 mapped_loc_addr) &&
0287                 !iwpm_compare_sockaddr(&rem_info->mapped_rem_sockaddr,
0288                 mapped_rem_addr)) {
0289 
0290                 memcpy(remote_addr, &rem_info->remote_sockaddr,
0291                     sizeof(struct sockaddr_storage));
0292                 iwpm_print_sockaddr(remote_addr,
0293                         "get_remote_info: Remote sockaddr:");
0294 
0295                 hlist_del_init(&rem_info->hlist_node);
0296                 kfree(rem_info);
0297                 ret = 0;
0298                 break;
0299             }
0300         }
0301     }
0302 get_remote_info_exit:
0303     spin_unlock_irqrestore(&iwpm_reminfo_lock, flags);
0304     return ret;
0305 }
0306 
0307 struct iwpm_nlmsg_request *iwpm_get_nlmsg_request(__u32 nlmsg_seq,
0308                     u8 nl_client, gfp_t gfp)
0309 {
0310     struct iwpm_nlmsg_request *nlmsg_request = NULL;
0311     unsigned long flags;
0312 
0313     nlmsg_request = kzalloc(sizeof(struct iwpm_nlmsg_request), gfp);
0314     if (!nlmsg_request)
0315         return NULL;
0316 
0317     spin_lock_irqsave(&iwpm_nlmsg_req_lock, flags);
0318     list_add_tail(&nlmsg_request->inprocess_list, &iwpm_nlmsg_req_list);
0319     spin_unlock_irqrestore(&iwpm_nlmsg_req_lock, flags);
0320 
0321     kref_init(&nlmsg_request->kref);
0322     kref_get(&nlmsg_request->kref);
0323     nlmsg_request->nlmsg_seq = nlmsg_seq;
0324     nlmsg_request->nl_client = nl_client;
0325     nlmsg_request->request_done = 0;
0326     nlmsg_request->err_code = 0;
0327     sema_init(&nlmsg_request->sem, 1);
0328     down(&nlmsg_request->sem);
0329     return nlmsg_request;
0330 }
0331 
0332 void iwpm_free_nlmsg_request(struct kref *kref)
0333 {
0334     struct iwpm_nlmsg_request *nlmsg_request;
0335     unsigned long flags;
0336 
0337     nlmsg_request = container_of(kref, struct iwpm_nlmsg_request, kref);
0338 
0339     spin_lock_irqsave(&iwpm_nlmsg_req_lock, flags);
0340     list_del_init(&nlmsg_request->inprocess_list);
0341     spin_unlock_irqrestore(&iwpm_nlmsg_req_lock, flags);
0342 
0343     if (!nlmsg_request->request_done)
0344         pr_debug("%s Freeing incomplete nlmsg request (seq = %u).\n",
0345             __func__, nlmsg_request->nlmsg_seq);
0346     kfree(nlmsg_request);
0347 }
0348 
0349 struct iwpm_nlmsg_request *iwpm_find_nlmsg_request(__u32 echo_seq)
0350 {
0351     struct iwpm_nlmsg_request *nlmsg_request;
0352     struct iwpm_nlmsg_request *found_request = NULL;
0353     unsigned long flags;
0354 
0355     spin_lock_irqsave(&iwpm_nlmsg_req_lock, flags);
0356     list_for_each_entry(nlmsg_request, &iwpm_nlmsg_req_list,
0357                 inprocess_list) {
0358         if (nlmsg_request->nlmsg_seq == echo_seq) {
0359             found_request = nlmsg_request;
0360             kref_get(&nlmsg_request->kref);
0361             break;
0362         }
0363     }
0364     spin_unlock_irqrestore(&iwpm_nlmsg_req_lock, flags);
0365     return found_request;
0366 }
0367 
0368 int iwpm_wait_complete_req(struct iwpm_nlmsg_request *nlmsg_request)
0369 {
0370     int ret;
0371 
0372     ret = down_timeout(&nlmsg_request->sem, IWPM_NL_TIMEOUT);
0373     if (ret) {
0374         ret = -EINVAL;
0375         pr_info("%s: Timeout %d sec for netlink request (seq = %u)\n",
0376             __func__, (IWPM_NL_TIMEOUT/HZ), nlmsg_request->nlmsg_seq);
0377     } else {
0378         ret = nlmsg_request->err_code;
0379     }
0380     kref_put(&nlmsg_request->kref, iwpm_free_nlmsg_request);
0381     return ret;
0382 }
0383 
0384 int iwpm_get_nlmsg_seq(void)
0385 {
0386     return atomic_inc_return(&iwpm_admin.nlmsg_seq);
0387 }
0388 
0389 /* valid client */
0390 u32 iwpm_get_registration(u8 nl_client)
0391 {
0392     return iwpm_admin.reg_list[nl_client];
0393 }
0394 
0395 /* valid client */
0396 void iwpm_set_registration(u8 nl_client, u32 reg)
0397 {
0398     iwpm_admin.reg_list[nl_client] = reg;
0399 }
0400 
0401 /* valid client */
0402 u32 iwpm_check_registration(u8 nl_client, u32 reg)
0403 {
0404     return (iwpm_get_registration(nl_client) & reg);
0405 }
0406 
0407 int iwpm_compare_sockaddr(struct sockaddr_storage *a_sockaddr,
0408                 struct sockaddr_storage *b_sockaddr)
0409 {
0410     if (a_sockaddr->ss_family != b_sockaddr->ss_family)
0411         return 1;
0412     if (a_sockaddr->ss_family == AF_INET) {
0413         struct sockaddr_in *a4_sockaddr =
0414             (struct sockaddr_in *)a_sockaddr;
0415         struct sockaddr_in *b4_sockaddr =
0416             (struct sockaddr_in *)b_sockaddr;
0417         if (!memcmp(&a4_sockaddr->sin_addr,
0418             &b4_sockaddr->sin_addr, sizeof(struct in_addr))
0419             && a4_sockaddr->sin_port == b4_sockaddr->sin_port)
0420                 return 0;
0421 
0422     } else if (a_sockaddr->ss_family == AF_INET6) {
0423         struct sockaddr_in6 *a6_sockaddr =
0424             (struct sockaddr_in6 *)a_sockaddr;
0425         struct sockaddr_in6 *b6_sockaddr =
0426             (struct sockaddr_in6 *)b_sockaddr;
0427         if (!memcmp(&a6_sockaddr->sin6_addr,
0428             &b6_sockaddr->sin6_addr, sizeof(struct in6_addr))
0429             && a6_sockaddr->sin6_port == b6_sockaddr->sin6_port)
0430                 return 0;
0431 
0432     } else {
0433         pr_err("%s: Invalid sockaddr family\n", __func__);
0434     }
0435     return 1;
0436 }
0437 
0438 struct sk_buff *iwpm_create_nlmsg(u32 nl_op, struct nlmsghdr **nlh,
0439                         int nl_client)
0440 {
0441     struct sk_buff *skb = NULL;
0442 
0443     skb = dev_alloc_skb(IWPM_MSG_SIZE);
0444     if (!skb)
0445         goto create_nlmsg_exit;
0446 
0447     if (!(ibnl_put_msg(skb, nlh, 0, 0, nl_client, nl_op,
0448                NLM_F_REQUEST))) {
0449         pr_warn("%s: Unable to put the nlmsg header\n", __func__);
0450         dev_kfree_skb(skb);
0451         skb = NULL;
0452     }
0453 create_nlmsg_exit:
0454     return skb;
0455 }
0456 
0457 int iwpm_parse_nlmsg(struct netlink_callback *cb, int policy_max,
0458                    const struct nla_policy *nlmsg_policy,
0459                    struct nlattr *nltb[], const char *msg_type)
0460 {
0461     int nlh_len = 0;
0462     int ret;
0463     const char *err_str = "";
0464 
0465     ret = nlmsg_validate_deprecated(cb->nlh, nlh_len, policy_max - 1,
0466                     nlmsg_policy, NULL);
0467     if (ret) {
0468         err_str = "Invalid attribute";
0469         goto parse_nlmsg_error;
0470     }
0471     ret = nlmsg_parse_deprecated(cb->nlh, nlh_len, nltb, policy_max - 1,
0472                      nlmsg_policy, NULL);
0473     if (ret) {
0474         err_str = "Unable to parse the nlmsg";
0475         goto parse_nlmsg_error;
0476     }
0477     ret = iwpm_validate_nlmsg_attr(nltb, policy_max);
0478     if (ret) {
0479         err_str = "Invalid NULL attribute";
0480         goto parse_nlmsg_error;
0481     }
0482     return 0;
0483 parse_nlmsg_error:
0484     pr_warn("%s: %s (msg type %s ret = %d)\n",
0485             __func__, err_str, msg_type, ret);
0486     return ret;
0487 }
0488 
0489 void iwpm_print_sockaddr(struct sockaddr_storage *sockaddr, char *msg)
0490 {
0491     struct sockaddr_in6 *sockaddr_v6;
0492     struct sockaddr_in *sockaddr_v4;
0493 
0494     switch (sockaddr->ss_family) {
0495     case AF_INET:
0496         sockaddr_v4 = (struct sockaddr_in *)sockaddr;
0497         pr_debug("%s IPV4 %pI4: %u(0x%04X)\n",
0498             msg, &sockaddr_v4->sin_addr,
0499             ntohs(sockaddr_v4->sin_port),
0500             ntohs(sockaddr_v4->sin_port));
0501         break;
0502     case AF_INET6:
0503         sockaddr_v6 = (struct sockaddr_in6 *)sockaddr;
0504         pr_debug("%s IPV6 %pI6: %u(0x%04X)\n",
0505             msg, &sockaddr_v6->sin6_addr,
0506             ntohs(sockaddr_v6->sin6_port),
0507             ntohs(sockaddr_v6->sin6_port));
0508         break;
0509     default:
0510         break;
0511     }
0512 }
0513 
0514 static u32 iwpm_ipv6_jhash(struct sockaddr_in6 *ipv6_sockaddr)
0515 {
0516     u32 ipv6_hash = jhash(&ipv6_sockaddr->sin6_addr, sizeof(struct in6_addr), 0);
0517     u32 hash = jhash_2words(ipv6_hash, (__force u32) ipv6_sockaddr->sin6_port, 0);
0518     return hash;
0519 }
0520 
0521 static u32 iwpm_ipv4_jhash(struct sockaddr_in *ipv4_sockaddr)
0522 {
0523     u32 ipv4_hash = jhash(&ipv4_sockaddr->sin_addr, sizeof(struct in_addr), 0);
0524     u32 hash = jhash_2words(ipv4_hash, (__force u32) ipv4_sockaddr->sin_port, 0);
0525     return hash;
0526 }
0527 
0528 static int get_hash_bucket(struct sockaddr_storage *a_sockaddr,
0529                 struct sockaddr_storage *b_sockaddr, u32 *hash)
0530 {
0531     u32 a_hash, b_hash;
0532 
0533     if (a_sockaddr->ss_family == AF_INET) {
0534         a_hash = iwpm_ipv4_jhash((struct sockaddr_in *) a_sockaddr);
0535         b_hash = iwpm_ipv4_jhash((struct sockaddr_in *) b_sockaddr);
0536 
0537     } else if (a_sockaddr->ss_family == AF_INET6) {
0538         a_hash = iwpm_ipv6_jhash((struct sockaddr_in6 *) a_sockaddr);
0539         b_hash = iwpm_ipv6_jhash((struct sockaddr_in6 *) b_sockaddr);
0540     } else {
0541         pr_err("%s: Invalid sockaddr family\n", __func__);
0542         return -EINVAL;
0543     }
0544 
0545     if (a_hash == b_hash) /* if port mapper isn't available */
0546         *hash = a_hash;
0547     else
0548         *hash = jhash_2words(a_hash, b_hash, 0);
0549     return 0;
0550 }
0551 
0552 static struct hlist_head *get_mapinfo_hash_bucket(struct sockaddr_storage
0553                 *local_sockaddr, struct sockaddr_storage
0554                 *mapped_sockaddr)
0555 {
0556     u32 hash;
0557     int ret;
0558 
0559     ret = get_hash_bucket(local_sockaddr, mapped_sockaddr, &hash);
0560     if (ret)
0561         return NULL;
0562     return &iwpm_hash_bucket[hash & IWPM_MAPINFO_HASH_MASK];
0563 }
0564 
0565 static struct hlist_head *get_reminfo_hash_bucket(struct sockaddr_storage
0566                 *mapped_loc_sockaddr, struct sockaddr_storage
0567                 *mapped_rem_sockaddr)
0568 {
0569     u32 hash;
0570     int ret;
0571 
0572     ret = get_hash_bucket(mapped_loc_sockaddr, mapped_rem_sockaddr, &hash);
0573     if (ret)
0574         return NULL;
0575     return &iwpm_reminfo_bucket[hash & IWPM_REMINFO_HASH_MASK];
0576 }
0577 
0578 static int send_mapinfo_num(u32 mapping_num, u8 nl_client, int iwpm_pid)
0579 {
0580     struct sk_buff *skb = NULL;
0581     struct nlmsghdr *nlh;
0582     u32 msg_seq;
0583     const char *err_str = "";
0584     int ret = -EINVAL;
0585 
0586     skb = iwpm_create_nlmsg(RDMA_NL_IWPM_MAPINFO_NUM, &nlh, nl_client);
0587     if (!skb) {
0588         err_str = "Unable to create a nlmsg";
0589         goto mapinfo_num_error;
0590     }
0591     nlh->nlmsg_seq = iwpm_get_nlmsg_seq();
0592     msg_seq = 0;
0593     err_str = "Unable to put attribute of mapinfo number nlmsg";
0594     ret = ibnl_put_attr(skb, nlh, sizeof(u32), &msg_seq, IWPM_NLA_MAPINFO_SEQ);
0595     if (ret)
0596         goto mapinfo_num_error;
0597     ret = ibnl_put_attr(skb, nlh, sizeof(u32),
0598                 &mapping_num, IWPM_NLA_MAPINFO_SEND_NUM);
0599     if (ret)
0600         goto mapinfo_num_error;
0601 
0602     nlmsg_end(skb, nlh);
0603 
0604     ret = rdma_nl_unicast(&init_net, skb, iwpm_pid);
0605     if (ret) {
0606         skb = NULL;
0607         err_str = "Unable to send a nlmsg";
0608         goto mapinfo_num_error;
0609     }
0610     pr_debug("%s: Sent mapping number = %u\n", __func__, mapping_num);
0611     return 0;
0612 mapinfo_num_error:
0613     pr_info("%s: %s\n", __func__, err_str);
0614     dev_kfree_skb(skb);
0615     return ret;
0616 }
0617 
0618 static int send_nlmsg_done(struct sk_buff *skb, u8 nl_client, int iwpm_pid)
0619 {
0620     struct nlmsghdr *nlh = NULL;
0621     int ret = 0;
0622 
0623     if (!skb)
0624         return ret;
0625     if (!(ibnl_put_msg(skb, &nlh, 0, 0, nl_client,
0626                RDMA_NL_IWPM_MAPINFO, NLM_F_MULTI))) {
0627         pr_warn("%s Unable to put NLMSG_DONE\n", __func__);
0628         dev_kfree_skb(skb);
0629         return -ENOMEM;
0630     }
0631     nlh->nlmsg_type = NLMSG_DONE;
0632     ret = rdma_nl_unicast(&init_net, skb, iwpm_pid);
0633     if (ret)
0634         pr_warn("%s Unable to send a nlmsg\n", __func__);
0635     return ret;
0636 }
0637 
0638 int iwpm_send_mapinfo(u8 nl_client, int iwpm_pid)
0639 {
0640     struct iwpm_mapping_info *map_info;
0641     struct sk_buff *skb = NULL;
0642     struct nlmsghdr *nlh;
0643     int skb_num = 0, mapping_num = 0;
0644     int i = 0, nlmsg_bytes = 0;
0645     unsigned long flags;
0646     const char *err_str = "";
0647     int ret;
0648 
0649     skb = dev_alloc_skb(NLMSG_GOODSIZE);
0650     if (!skb) {
0651         ret = -ENOMEM;
0652         err_str = "Unable to allocate skb";
0653         goto send_mapping_info_exit;
0654     }
0655     skb_num++;
0656     spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
0657     ret = -EINVAL;
0658     for (i = 0; i < IWPM_MAPINFO_HASH_SIZE; i++) {
0659         hlist_for_each_entry(map_info, &iwpm_hash_bucket[i],
0660                      hlist_node) {
0661             if (map_info->nl_client != nl_client)
0662                 continue;
0663             nlh = NULL;
0664             if (!(ibnl_put_msg(skb, &nlh, 0, 0, nl_client,
0665                     RDMA_NL_IWPM_MAPINFO, NLM_F_MULTI))) {
0666                 ret = -ENOMEM;
0667                 err_str = "Unable to put the nlmsg header";
0668                 goto send_mapping_info_unlock;
0669             }
0670             err_str = "Unable to put attribute of the nlmsg";
0671             ret = ibnl_put_attr(skb, nlh,
0672                     sizeof(struct sockaddr_storage),
0673                     &map_info->local_sockaddr,
0674                     IWPM_NLA_MAPINFO_LOCAL_ADDR);
0675             if (ret)
0676                 goto send_mapping_info_unlock;
0677 
0678             ret = ibnl_put_attr(skb, nlh,
0679                     sizeof(struct sockaddr_storage),
0680                     &map_info->mapped_sockaddr,
0681                     IWPM_NLA_MAPINFO_MAPPED_ADDR);
0682             if (ret)
0683                 goto send_mapping_info_unlock;
0684 
0685             if (iwpm_ulib_version > IWPM_UABI_VERSION_MIN) {
0686                 ret = ibnl_put_attr(skb, nlh, sizeof(u32),
0687                         &map_info->map_flags,
0688                         IWPM_NLA_MAPINFO_FLAGS);
0689                 if (ret)
0690                     goto send_mapping_info_unlock;
0691             }
0692 
0693             nlmsg_end(skb, nlh);
0694 
0695             iwpm_print_sockaddr(&map_info->local_sockaddr,
0696                 "send_mapping_info: Local sockaddr:");
0697             iwpm_print_sockaddr(&map_info->mapped_sockaddr,
0698                 "send_mapping_info: Mapped local sockaddr:");
0699             mapping_num++;
0700             nlmsg_bytes += nlh->nlmsg_len;
0701 
0702             /* check if all mappings can fit in one skb */
0703             if (NLMSG_GOODSIZE - nlmsg_bytes < nlh->nlmsg_len * 2) {
0704                 /* and leave room for NLMSG_DONE */
0705                 nlmsg_bytes = 0;
0706                 skb_num++;
0707                 spin_unlock_irqrestore(&iwpm_mapinfo_lock,
0708                                flags);
0709                 /* send the skb */
0710                 ret = send_nlmsg_done(skb, nl_client, iwpm_pid);
0711                 skb = NULL;
0712                 if (ret) {
0713                     err_str = "Unable to send map info";
0714                     goto send_mapping_info_exit;
0715                 }
0716                 if (skb_num == IWPM_MAPINFO_SKB_COUNT) {
0717                     ret = -ENOMEM;
0718                     err_str = "Insufficient skbs for map info";
0719                     goto send_mapping_info_exit;
0720                 }
0721                 skb = dev_alloc_skb(NLMSG_GOODSIZE);
0722                 if (!skb) {
0723                     ret = -ENOMEM;
0724                     err_str = "Unable to allocate skb";
0725                     goto send_mapping_info_exit;
0726                 }
0727                 spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
0728             }
0729         }
0730     }
0731 send_mapping_info_unlock:
0732     spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags);
0733 send_mapping_info_exit:
0734     if (ret) {
0735         pr_warn("%s: %s (ret = %d)\n", __func__, err_str, ret);
0736         dev_kfree_skb(skb);
0737         return ret;
0738     }
0739     send_nlmsg_done(skb, nl_client, iwpm_pid);
0740     return send_mapinfo_num(mapping_num, nl_client, iwpm_pid);
0741 }
0742 
0743 int iwpm_mapinfo_available(void)
0744 {
0745     unsigned long flags;
0746     int full_bucket = 0, i = 0;
0747 
0748     spin_lock_irqsave(&iwpm_mapinfo_lock, flags);
0749     if (iwpm_hash_bucket) {
0750         for (i = 0; i < IWPM_MAPINFO_HASH_SIZE; i++) {
0751             if (!hlist_empty(&iwpm_hash_bucket[i])) {
0752                 full_bucket = 1;
0753                 break;
0754             }
0755         }
0756     }
0757     spin_unlock_irqrestore(&iwpm_mapinfo_lock, flags);
0758     return full_bucket;
0759 }
0760 
0761 int iwpm_send_hello(u8 nl_client, int iwpm_pid, u16 abi_version)
0762 {
0763     struct sk_buff *skb = NULL;
0764     struct nlmsghdr *nlh;
0765     const char *err_str;
0766     int ret = -EINVAL;
0767 
0768     skb = iwpm_create_nlmsg(RDMA_NL_IWPM_HELLO, &nlh, nl_client);
0769     if (!skb) {
0770         err_str = "Unable to create a nlmsg";
0771         goto hello_num_error;
0772     }
0773     nlh->nlmsg_seq = iwpm_get_nlmsg_seq();
0774     err_str = "Unable to put attribute of abi_version into nlmsg";
0775     ret = ibnl_put_attr(skb, nlh, sizeof(u16), &abi_version,
0776                 IWPM_NLA_HELLO_ABI_VERSION);
0777     if (ret)
0778         goto hello_num_error;
0779     nlmsg_end(skb, nlh);
0780 
0781     ret = rdma_nl_unicast(&init_net, skb, iwpm_pid);
0782     if (ret) {
0783         skb = NULL;
0784         err_str = "Unable to send a nlmsg";
0785         goto hello_num_error;
0786     }
0787     pr_debug("%s: Sent hello abi_version = %u\n", __func__, abi_version);
0788     return 0;
0789 hello_num_error:
0790     pr_info("%s: %s\n", __func__, err_str);
0791     dev_kfree_skb(skb);
0792     return ret;
0793 }