addr.c revision 273246
12061Sjkh/* 218362Sjkh * Copyright (c) 2005 Voltaire Inc. All rights reserved. 32061Sjkh * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. 42061Sjkh * Copyright (c) 1999-2005, Mellanox Technologies, Inc. All rights reserved. 515603Smarkm * Copyright (c) 2005 Intel Corporation. All rights reserved. 62061Sjkh * 72061Sjkh * This software is available to you under a choice of one of two 83197Scsgr * licenses. You may choose to be licensed under the terms of the GNU 93197Scsgr * General Public License (GPL) Version 2, available from the file 102061Sjkh * COPYING in the main directory of this source tree, or the 1112483Speter * OpenIB.org BSD license below: 122160Scsgr * 132834Swollman * Redistribution and use in source and binary forms, with or 142061Sjkh * without modification, are permitted provided that the following 152061Sjkh * conditions are met: 162160Scsgr * 1717308Speter * - Redistributions of source code must retain the above 181594Srgrimes * copyright notice, this list of conditions and the following 1917308Speter * disclaimer. 2017308Speter * 2117308Speter * - Redistributions in binary form must reproduce the above 2217308Speter * copyright notice, this list of conditions and the following 2317308Speter * disclaimer in the documentation and/or other materials 2417308Speter * provided with the distribution. 2517308Speter * 2617308Speter * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2717308Speter * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2817308Speter * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2917308Speter * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 302061Sjkh * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 312061Sjkh * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 321594Srgrimes * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 337407Srgrimes * SOFTWARE. 347407Srgrimes */ 357108Sphk 367108Sphk#include <linux/mutex.h> 377108Sphk#include <linux/inetdevice.h> 387407Srgrimes#include <linux/slab.h> 397407Srgrimes#include <linux/workqueue.h> 407407Srgrimes#include <linux/module.h> 417108Sphk#include <linux/notifier.h> 422061Sjkh#include <net/route.h> 432061Sjkh#include <net/netevent.h> 442061Sjkh#include <rdma/ib_addr.h> 4517308Speter#include <netinet/if_ether.h> 462061Sjkh 472061Sjkh 482061SjkhMODULE_AUTHOR("Sean Hefty"); 492061SjkhMODULE_DESCRIPTION("IB Address Translation"); 502061SjkhMODULE_LICENSE("Dual BSD/GPL"); 513197Scsgr 522626Scsgrstruct addr_req { 532626Scsgr struct list_head list; 542061Sjkh struct sockaddr_storage src_addr; 552061Sjkh struct sockaddr_storage dst_addr; 562061Sjkh struct rdma_dev_addr *addr; 572061Sjkh struct rdma_addr_client *client; 582061Sjkh void *context; 592061Sjkh void (*callback)(int status, struct sockaddr *src_addr, 602061Sjkh struct rdma_dev_addr *addr, void *context); 612061Sjkh unsigned long timeout; 622061Sjkh int status; 632061Sjkh}; 642061Sjkh 652061Sjkhstatic void process_req(struct work_struct *work); 662061Sjkh 672061Sjkhstatic DEFINE_MUTEX(lock); 682061Sjkhstatic LIST_HEAD(req_list); 692061Sjkhstatic struct delayed_work work; 702061Sjkhstatic struct workqueue_struct *addr_wq; 712061Sjkh 722834Swollmanvoid rdma_addr_register_client(struct rdma_addr_client *client) 732834Swollman{ 742834Swollman atomic_set(&client->refcount, 1); 752834Swollman init_completion(&client->comp); 762834Swollman} 772834SwollmanEXPORT_SYMBOL(rdma_addr_register_client); 781594Srgrimes 794486Sphkstatic inline void put_client(struct rdma_addr_client *client) 804486Sphk{ 814486Sphk if (atomic_dec_and_test(&client->refcount)) 824486Sphk complete(&client->comp); 834486Sphk} 842061Sjkh 852061Sjkhvoid rdma_addr_unregister_client(struct rdma_addr_client *client) 862061Sjkh{ 872061Sjkh put_client(client); 882061Sjkh wait_for_completion(&client->comp); 892061Sjkh} 902061SjkhEXPORT_SYMBOL(rdma_addr_unregister_client); 912061Sjkh 922061Sjkh#ifdef __linux__ 9317308Speterint rdma_copy_addr(struct rdma_dev_addr *dev_addr, struct net_device *dev, 942061Sjkh const unsigned char *dst_dev_addr) 952061Sjkh{ 962061Sjkh dev_addr->dev_type = dev->type; 972061Sjkh memcpy(dev_addr->src_dev_addr, dev->dev_addr, MAX_ADDR_LEN); 982061Sjkh memcpy(dev_addr->broadcast, dev->broadcast, MAX_ADDR_LEN); 9912483Speter if (dst_dev_addr) 10012483Speter memcpy(dev_addr->dst_dev_addr, dst_dev_addr, MAX_ADDR_LEN); 10112483Speter dev_addr->bound_dev_if = dev->ifindex; 10212483Speter return 0; 1032061Sjkh} 1042061Sjkh#else 1058854Srgrimesint rdma_copy_addr(struct rdma_dev_addr *dev_addr, struct ifnet *dev, 1062061Sjkh const unsigned char *dst_dev_addr) 1072061Sjkh{ 10812483Speter if (dev->if_type == IFT_INFINIBAND) 1092061Sjkh dev_addr->dev_type = ARPHRD_INFINIBAND; 11017308Speter else if (dev->if_type == IFT_ETHER) 11117308Speter dev_addr->dev_type = ARPHRD_ETHER; 11217308Speter else 11317308Speter dev_addr->dev_type = 0; 11415603Smarkm memcpy(dev_addr->src_dev_addr, IF_LLADDR(dev), dev->if_addrlen); 11515603Smarkm memcpy(dev_addr->broadcast, __DECONST(char *, dev->if_broadcastaddr), 11617308Speter dev->if_addrlen); 11717308Speter if (dst_dev_addr) 11817308Speter memcpy(dev_addr->dst_dev_addr, dst_dev_addr, dev->if_addrlen); 11917308Speter dev_addr->bound_dev_if = dev->if_index; 12017308Speter return 0; 12117308Speter} 12217308Speter#endif 12317308SpeterEXPORT_SYMBOL(rdma_copy_addr); 12417308Speter 12518362Sjkhint rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr) 12618362Sjkh{ 12718362Sjkh struct net_device *dev; 12817308Speter int ret = -EADDRNOTAVAIL; 12917308Speter 13017308Speter if (dev_addr->bound_dev_if) { 13117308Speter dev = dev_get_by_index(&init_net, dev_addr->bound_dev_if); 13217308Speter if (!dev) 13317308Speter return -ENODEV; 13416550Sjkh ret = rdma_copy_addr(dev_addr, dev, NULL); 1352061Sjkh dev_put(dev); 13617308Speter return ret; 1372061Sjkh } 13817308Speter 1392061Sjkh switch (addr->sa_family) { 14017308Speter#ifdef INET 14117308Speter case AF_INET: 14217308Speter dev = ip_dev_find(NULL, 14317308Speter ((struct sockaddr_in *) addr)->sin_addr.s_addr); 14417308Speter 14517308Speter if (!dev) 14617308Speter return ret; 14717308Speter 14817308Speter ret = rdma_copy_addr(dev_addr, dev, NULL); 14917308Speter dev_put(dev); 15017308Speter break; 15117466Speter#endif 15217308Speter 15317308Speter#if defined(INET6) 15417466Speter case AF_INET6: 15517308Speter#ifdef __linux__ 15617308Speter read_lock(&dev_base_lock); 15717308Speter for_each_netdev(&init_net, dev) { 15817308Speter if (ipv6_chk_addr(&init_net, 15917466Speter &((struct sockaddr_in6 *) addr)->sin6_addr, 16017308Speter dev, 1)) { 16117308Speter ret = rdma_copy_addr(dev_addr, dev, NULL); 16217308Speter break; 16317308Speter } 16417308Speter } 16517308Speter read_unlock(&dev_base_lock); 16617308Speter#else 16717308Speter { 16817308Speter struct sockaddr_in6 *sin6; 16917308Speter struct ifaddr *ifa; 17017308Speter in_port_t port; 17117308Speter 17217308Speter sin6 = (struct sockaddr_in6 *)addr; 17317308Speter port = sin6->sin6_port; 17417308Speter sin6->sin6_port = 0; 17517308Speter ifa = ifa_ifwithaddr(addr); 17617308Speter sin6->sin6_port = port; 17717308Speter if (ifa == NULL) { 17817308Speter ret = -ENODEV; 17917308Speter break; 18017308Speter } 18117308Speter ret = rdma_copy_addr(dev_addr, ifa->ifa_ifp, NULL); 18217308Speter ifa_free(ifa); 18317308Speter break; 18417308Speter } 18517308Speter#endif 18617308Speter break; 18717308Speter#endif 18817308Speter } 18917308Speter return ret; 19017308Speter} 19117308SpeterEXPORT_SYMBOL(rdma_translate_ip); 19217962Speter 19317308Speterstatic void set_timeout(unsigned long time) 19417962Speter{ 19517962Speter unsigned long delay; 19617962Speter 19717962Speter delay = time - jiffies; 19817962Speter if ((long)delay <= 0) 19917962Speter delay = 1; 20017962Speter 20117962Speter mod_delayed_work(addr_wq, &work, delay); 20217962Speter} 20317962Speter 20417962Speterstatic void queue_req(struct addr_req *req) 20517962Speter{ 20617962Speter struct addr_req *temp_req; 20717962Speter 20817962Speter mutex_lock(&lock); 20917308Speter list_for_each_entry_reverse(temp_req, &req_list, list) { 21016550Sjkh if (time_after_eq(req->timeout, temp_req->timeout)) 21117308Speter break; 21217308Speter } 21317308Speter 21417308Speter list_add(&req->list, &temp_req->list); 21516550Sjkh 21616550Sjkh if (req_list.next == &req->list) 21717308Speter set_timeout(req->timeout); 21817308Speter mutex_unlock(&lock); 21914545Sjkh} 22017962Speter 2212061Sjkh#ifdef __linux__ 22217308Speterstatic int addr4_resolve(struct sockaddr_in *src_in, 22317308Speter struct sockaddr_in *dst_in, 22417308Speter struct rdma_dev_addr *addr) 22517308Speter{ 22617308Speter __be32 src_ip = src_in->sin_addr.s_addr; 22717308Speter __be32 dst_ip = dst_in->sin_addr.s_addr; 22817308Speter struct flowi fl; 22917308Speter struct rtable *rt; 23012483Speter struct neighbour *neigh; 23117308Speter int ret; 23212483Speter 23317308Speter memset(&fl, 0, sizeof fl); 23412483Speter fl.nl_u.ip4_u.daddr = dst_ip; 2352061Sjkh fl.nl_u.ip4_u.saddr = src_ip; 23617308Speter fl.oif = addr->bound_dev_if; 2372061Sjkh 23817308Speter ret = ip_route_output_key(&init_net, &rt, &fl); 23917308Speter if (ret) 24017308Speter goto out; 24117308Speter 24217308Speter src_in->sin_family = AF_INET; 24317308Speter src_in->sin_addr.s_addr = rt->rt_src; 24417308Speter 24517308Speter if (rt->idev->dev->flags & IFF_LOOPBACK) { 24617962Speter ret = rdma_translate_ip((struct sockaddr *) dst_in, addr); 24717308Speter if (!ret) 24817962Speter memcpy(addr->dst_dev_addr, addr->src_dev_addr, MAX_ADDR_LEN); 24917308Speter goto put; 25017962Speter } 25117962Speter 25217962Speter /* If the device does ARP internally, return 'done' */ 25317962Speter if (rt->idev->dev->flags & IFF_NOARP) { 25417962Speter rdma_copy_addr(addr, rt->idev->dev, NULL); 25517962Speter goto put; 25617962Speter } 25717962Speter 25817308Speter neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, rt->idev->dev); 25917962Speter if (!neigh || !(neigh->nud_state & NUD_VALID)) { 26017962Speter neigh_event_send(rt->u.dst.neighbour, NULL); 26117962Speter ret = -ENODATA; 26217962Speter if (neigh) 26317308Speter goto release; 2642061Sjkh goto put; 26517308Speter } 26617308Speter 26717308Speter ret = rdma_copy_addr(addr, neigh->dev, neigh->ha); 26817308Speterrelease: 26917308Speter neigh_release(neigh); 27017308Speterput: 27117308Speter ip_rt_put(rt); 2722302Spaulout: 2732302Spaul return ret; 2742302Spaul} 2752302Spaul 2762302Spaul#if defined(INET6) 2772302Spaulstatic int addr6_resolve(struct sockaddr_in6 *src_in, 27810760Sache struct sockaddr_in6 *dst_in, 27910760Sache struct rdma_dev_addr *addr) 2802302Spaul{ 28110760Sache struct flowi fl; 28210760Sache struct neighbour *neigh; 28310760Sache struct dst_entry *dst; 28410760Sache int ret; 2852302Spaul 2862302Spaul memset(&fl, 0, sizeof fl); 2872302Spaul ipv6_addr_copy(&fl.fl6_dst, &dst_in->sin6_addr); 2882302Spaul ipv6_addr_copy(&fl.fl6_src, &src_in->sin6_addr); 28916591Spst fl.oif = addr->bound_dev_if; 2902302Spaul 2912302Spaul dst = ip6_route_output(&init_net, NULL, &fl); 29217308Speter if ((ret = dst->error)) 29317308Speter goto put; 29417308Speter 29517308Speter if (ipv6_addr_any(&fl.fl6_src)) { 29617308Speter ret = ipv6_dev_get_saddr(&init_net, ip6_dst_idev(dst)->dev, 29717308Speter &fl.fl6_dst, 0, &fl.fl6_src); 29817308Speter if (ret) 2992061Sjkh goto put; 30017308Speter 3012061Sjkh src_in->sin6_family = AF_INET6; 30217308Speter ipv6_addr_copy(&src_in->sin6_addr, &fl.fl6_src); 30317308Speter } 30417308Speter 30517308Speter if (dst->dev->flags & IFF_LOOPBACK) { 30617308Speter ret = rdma_translate_ip((struct sockaddr *) dst_in, addr); 30717308Speter if (!ret) 30817308Speter memcpy(addr->dst_dev_addr, addr->src_dev_addr, MAX_ADDR_LEN); 30917308Speter goto put; 31017308Speter } 31117308Speter 31217308Speter /* If the device does ARP internally, return 'done' */ 31317308Speter if (dst->dev->flags & IFF_NOARP) { 31417308Speter ret = rdma_copy_addr(addr, dst->dev, NULL); 31517308Speter goto put; 3162061Sjkh } 31717308Speter 31817308Speter neigh = dst->neighbour; 31917308Speter if (!neigh || !(neigh->nud_state & NUD_VALID)) { 32017308Speter neigh_event_send(dst->neighbour, NULL); 32117308Speter ret = -ENODATA; 32217308Speter goto put; 3233626Swollman } 3243626Swollman 3253626Swollman ret = rdma_copy_addr(addr, dst->dev, neigh->ha); 3263626Swollmanput: 3273626Swollman dst_release(dst); 3283626Swollman return ret; 3293626Swollman} 3303626Swollman#else 3313626Swollmanstatic int addr6_resolve(struct sockaddr_in6 *src_in, 3323626Swollman struct sockaddr_in6 *dst_in, 3333626Swollman struct rdma_dev_addr *addr) 3347059Sroberto{ 3353626Swollman return -EADDRNOTAVAIL; 3363626Swollman} 3373626Swollman#endif 3383626Swollman 3393626Swollman#else 3403626Swollman#include <netinet/if_ether.h> 3413626Swollman 34217308Speterstatic int addr_resolve(struct sockaddr *src_in, 34317308Speter struct sockaddr *dst_in, 34417308Speter struct rdma_dev_addr *addr) 34517308Speter{ 34617308Speter struct sockaddr_in *sin; 34717308Speter struct sockaddr_in6 *sin6; 34817308Speter struct ifaddr *ifa; 34917308Speter struct ifnet *ifp; 35017308Speter#if defined(INET) || defined(INET6) 35117308Speter struct llentry *lle; 3523626Swollman#endif 35317308Speter struct rtentry *rte; 35417308Speter in_port_t port; 35517308Speter u_char edst[MAX_ADDR_LEN]; 35617308Speter int multi; 35717308Speter int bcast; 35817308Speter int error = 0; 35917308Speter 36017308Speter /* 36117308Speter * Determine whether the address is unicast, multicast, or broadcast 3622061Sjkh * and whether the source interface is valid. 36316663Sjkh */ 3642061Sjkh multi = 0; 36517308Speter bcast = 0; 36617308Speter sin = NULL; 36717308Speter sin6 = NULL; 36817308Speter ifp = NULL; 36917308Speter rte = NULL; 37017308Speter switch (dst_in->sa_family) { 37117820Sjkh#ifdef INET 37217308Speter case AF_INET: 37317820Sjkh sin = (struct sockaddr_in *)dst_in; 37417308Speter if (sin->sin_addr.s_addr == INADDR_BROADCAST) 37517820Sjkh bcast = 1; 37617467Speter if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) 37717308Speter multi = 1; 37817308Speter sin = (struct sockaddr_in *)src_in; 37917308Speter if (sin->sin_addr.s_addr != INADDR_ANY) { 38017308Speter /* 38117308Speter * Address comparison fails if the port is set 38217308Speter * cache it here to be restored later. 38317308Speter */ 38417308Speter port = sin->sin_port; 38517820Sjkh sin->sin_port = 0; 38617820Sjkh memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); 38717308Speter } else 38817308Speter src_in = NULL; 38917308Speter break; 39017308Speter#endif 39114119Speter#ifdef INET6 3922061Sjkh case AF_INET6: 3937130Srgrimes sin6 = (struct sockaddr_in6 *)dst_in; 3947130Srgrimes if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 3957130Srgrimes multi = 1; 3962061Sjkh sin6 = (struct sockaddr_in6 *)src_in; 39717962Speter if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 3982061Sjkh port = sin6->sin6_port; 39917308Speter sin6->sin6_port = 0; 4002685Srgrimes } else 4016927Snate src_in = NULL; 4022685Srgrimes break; 4033518Sache#endif 4043197Scsgr default: 4053197Scsgr return -EINVAL; 40612166Sjkh } 40712485Sjkh /* 4083197Scsgr * If we have a source address to use look it up first and verify 4092061Sjkh * that it is a local interface. 4102061Sjkh */ 4112061Sjkh if (src_in) { 41216786Snate ifa = ifa_ifwithaddr(src_in); 4132883Sphk if (sin) 41417308Speter sin->sin_port = port; 41517308Speter if (sin6) 4167281Srgrimes sin6->sin6_port = port; 4173242Spaul if (ifa == NULL) 4183242Spaul return -ENETUNREACH; 4197171Sats ifp = ifa->ifa_ifp; 4202061Sjkh ifa_free(ifa); 4213213Spst if (bcast || multi) 42217308Speter goto mcast; 42317308Speter } 4245749Swollman /* 4255772Swollman * Make sure the route exists and has a valid link. 42617308Speter */ 42717308Speter rte = rtalloc1(dst_in, 1, 0); 4282061Sjkh if (rte == NULL || rte->rt_ifp == NULL || !RT_LINK_IS_UP(rte->rt_ifp)) { 42917308Speter if (rte) 43017308Speter RTFREE_LOCKED(rte); 43117308Speter return -EHOSTUNREACH; 4325366Snate } 43317820Sjkh /* 43417467Speter * If it's not multicast or broadcast and the route doesn't match the 43517820Sjkh * requested interface return unreachable. Otherwise fetch the 43617308Speter * correct interface pointer and unlock the route. 43717820Sjkh */ 43817308Speter if (multi || bcast) { 43917820Sjkh if (ifp == NULL) 44017308Speter ifp = rte->rt_ifp; 44117820Sjkh RTFREE_LOCKED(rte); 44217308Speter } else if (ifp && ifp != rte->rt_ifp) { 44317820Sjkh RTFREE_LOCKED(rte); 44417308Speter return -ENETUNREACH; 44517820Sjkh } else { 44617308Speter if (ifp == NULL) 4475728Swollman ifp = rte->rt_ifp; 44817820Sjkh RT_UNLOCK(rte); 44917308Speter } 4505366Snatemcast: 45117308Speter if (bcast) 45217308Speter return rdma_copy_addr(addr, ifp, ifp->if_broadcastaddr); 45317308Speter if (multi) { 4542061Sjkh struct sockaddr *llsa; 4558295Srgrimes 45617820Sjkh error = ifp->if_resolvemulti(ifp, &llsa, dst_in); 45717308Speter if (error) 4588295Srgrimes return -error; 4598489Srgrimes error = rdma_copy_addr(addr, ifp, 46017820Sjkh LLADDR((struct sockaddr_dl *)llsa)); 46117308Speter free(llsa, M_IFMADDR); 4628489Srgrimes return error; 4638489Srgrimes } 46417820Sjkh /* 46517308Speter * Resolve the link local address. 4668489Srgrimes */ 46717308Speter switch (dst_in->sa_family) { 46817820Sjkh#ifdef INET 46917308Speter case AF_INET: 47017308Speter error = arpresolve(ifp, rte, NULL, dst_in, edst, &lle); 4718295Srgrimes break; 47217820Sjkh#endif 47317308Speter#ifdef INET6 47417820Sjkh case AF_INET6: 47517308Speter error = nd6_storelladdr(ifp, NULL, dst_in, (u_char *)edst, &lle); 4768295Srgrimes break; 4772160Scsgr#endif 47817820Sjkh default: 47917308Speter /* XXX: Shouldn't happen. */ 4802160Scsgr error = -EINVAL; 4812279Spaul } 48217820Sjkh RTFREE(rte); 48317308Speter if (error == 0) 4842279Spaul return rdma_copy_addr(addr, ifp, edst); 48517234Sjraynard if (error == EWOULDBLOCK) 48617820Sjkh return -ENODATA; 48717308Speter return -error; 48811772Snate} 4893197Scsgr 49017820Sjkh#endif 49117308Speter 4922626Scsgrstatic void process_req(struct work_struct *work) 4938304Srgrimes{ 49417820Sjkh struct addr_req *req, *temp_req; 49517308Speter struct sockaddr *src_in, *dst_in; 4968304Srgrimes struct list_head done_list; 4972061Sjkh 49817308Speter INIT_LIST_HEAD(&done_list); 49917308Speter 50017308Speter mutex_lock(&lock); 50117308Speter list_for_each_entry_safe(req, temp_req, &req_list, list) { 50211806Sphk if (req->status == -ENODATA) { 50317820Sjkh src_in = (struct sockaddr *) &req->src_addr; 50417308Speter dst_in = (struct sockaddr *) &req->dst_addr; 50517820Sjkh req->status = addr_resolve(src_in, dst_in, req->addr); 50617308Speter if (req->status && time_after_eq(jiffies, req->timeout)) 50718204Sjfieber req->status = -ETIMEDOUT; 50818204Sjfieber else if (req->status == -ENODATA) 50917820Sjkh continue; 51017308Speter } 51117820Sjkh list_move_tail(&req->list, &done_list); 51217308Speter } 51317820Sjkh 51417308Speter if (!list_empty(&req_list)) { 51518362Sjkh req = list_entry(req_list.next, struct addr_req, list); 51618362Sjkh set_timeout(req->timeout); 5172061Sjkh } 5181594Srgrimes mutex_unlock(&lock); 519 520 list_for_each_entry_safe(req, temp_req, &done_list, list) { 521 list_del(&req->list); 522 req->callback(req->status, (struct sockaddr *) &req->src_addr, 523 req->addr, req->context); 524 put_client(req->client); 525 kfree(req); 526 } 527} 528 529int rdma_resolve_ip(struct rdma_addr_client *client, 530 struct sockaddr *src_addr, struct sockaddr *dst_addr, 531 struct rdma_dev_addr *addr, int timeout_ms, 532 void (*callback)(int status, struct sockaddr *src_addr, 533 struct rdma_dev_addr *addr, void *context), 534 void *context) 535{ 536 struct sockaddr *src_in, *dst_in; 537 struct addr_req *req; 538 int ret = 0; 539 540 req = kzalloc(sizeof *req, GFP_KERNEL); 541 if (!req) 542 return -ENOMEM; 543 544 src_in = (struct sockaddr *) &req->src_addr; 545 dst_in = (struct sockaddr *) &req->dst_addr; 546 547 if (src_addr) { 548 if (src_addr->sa_family != dst_addr->sa_family) { 549 ret = -EINVAL; 550 goto err; 551 } 552 553 memcpy(src_in, src_addr, ip_addr_size(src_addr)); 554 } else { 555 src_in->sa_family = dst_addr->sa_family; 556 } 557 558 memcpy(dst_in, dst_addr, ip_addr_size(dst_addr)); 559 req->addr = addr; 560 req->callback = callback; 561 req->context = context; 562 req->client = client; 563 atomic_inc(&client->refcount); 564 565 req->status = addr_resolve(src_in, dst_in, addr); 566 switch (req->status) { 567 case 0: 568 req->timeout = jiffies; 569 queue_req(req); 570 break; 571 case -ENODATA: 572 req->timeout = msecs_to_jiffies(timeout_ms) + jiffies; 573 queue_req(req); 574 break; 575 default: 576 ret = req->status; 577 atomic_dec(&client->refcount); 578 goto err; 579 } 580 return ret; 581err: 582 kfree(req); 583 return ret; 584} 585EXPORT_SYMBOL(rdma_resolve_ip); 586 587void rdma_addr_cancel(struct rdma_dev_addr *addr) 588{ 589 struct addr_req *req, *temp_req; 590 591 mutex_lock(&lock); 592 list_for_each_entry_safe(req, temp_req, &req_list, list) { 593 if (req->addr == addr) { 594 req->status = -ECANCELED; 595 req->timeout = jiffies; 596 list_move(&req->list, &req_list); 597 set_timeout(req->timeout); 598 break; 599 } 600 } 601 mutex_unlock(&lock); 602} 603EXPORT_SYMBOL(rdma_addr_cancel); 604 605static int netevent_callback(struct notifier_block *self, unsigned long event, 606 void *ctx) 607{ 608 if (event == NETEVENT_NEIGH_UPDATE) { 609#ifdef __linux__ 610 struct neighbour *neigh = ctx; 611 612 if (neigh->nud_state & NUD_VALID) { 613 set_timeout(jiffies); 614 } 615#else 616 set_timeout(jiffies); 617#endif 618 } 619 return 0; 620} 621 622static struct notifier_block nb = { 623 .notifier_call = netevent_callback 624}; 625 626static int __init addr_init(void) 627{ 628 INIT_DELAYED_WORK(&work, process_req); 629 addr_wq = create_singlethread_workqueue("ib_addr"); 630 if (!addr_wq) 631 return -ENOMEM; 632 633 register_netevent_notifier(&nb); 634 return 0; 635} 636 637static void __exit addr_cleanup(void) 638{ 639 unregister_netevent_notifier(&nb); 640 destroy_workqueue(addr_wq); 641} 642 643module_init(addr_init); 644module_exit(addr_cleanup); 645