addr.c revision 234183
192108Sphk/* 292108Sphk * Copyright (c) 2005 Voltaire Inc. All rights reserved. 392108Sphk * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. 492108Sphk * Copyright (c) 1999-2005, Mellanox Technologies, Inc. All rights reserved. 592108Sphk * Copyright (c) 2005 Intel Corporation. All rights reserved. 692108Sphk * 792108Sphk * This software is available to you under a choice of one of two 892108Sphk * licenses. You may choose to be licensed under the terms of the GNU 992108Sphk * General Public License (GPL) Version 2, available from the file 1092108Sphk * COPYING in the main directory of this source tree, or the 1192108Sphk * OpenIB.org BSD license below: 1292108Sphk * 1392108Sphk * Redistribution and use in source and binary forms, with or 1492108Sphk * without modification, are permitted provided that the following 1592108Sphk * conditions are met: 1692108Sphk * 1792108Sphk * - Redistributions of source code must retain the above 1892108Sphk * copyright notice, this list of conditions and the following 1992108Sphk * disclaimer. 2092108Sphk * 2192108Sphk * - Redistributions in binary form must reproduce the above 2292108Sphk * copyright notice, this list of conditions and the following 2392108Sphk * disclaimer in the documentation and/or other materials 2492108Sphk * provided with the distribution. 2592108Sphk * 2692108Sphk * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2792108Sphk * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2892108Sphk * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2992108Sphk * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 3092108Sphk * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 3192108Sphk * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 3292108Sphk * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3392108Sphk * SOFTWARE. 3492108Sphk */ 3592108Sphk 3692108Sphk#include <linux/mutex.h> 3792108Sphk#include <linux/inetdevice.h> 3892108Sphk#include <linux/workqueue.h> 3992108Sphk#include <net/arp.h> 4092108Sphk#include <net/neighbour.h> 4192108Sphk#include <net/route.h> 4292108Sphk#include <net/netevent.h> 4392108Sphk#include <net/addrconf.h> 4492108Sphk#include <net/ip6_route.h> 4592108Sphk#include <rdma/ib_addr.h> 4692108Sphk 4792108SphkMODULE_AUTHOR("Sean Hefty"); 4892108SphkMODULE_DESCRIPTION("IB Address Translation"); 4992108SphkMODULE_LICENSE("Dual BSD/GPL"); 5092108Sphk 5195323Sphkstruct addr_req { 5295038Sphk struct list_head list; 5392108Sphk struct sockaddr_storage src_addr; 5492108Sphk struct sockaddr_storage dst_addr; 5592108Sphk struct rdma_dev_addr *addr; 5692108Sphk struct rdma_addr_client *client; 5792108Sphk void *context; 5892108Sphk void (*callback)(int status, struct sockaddr *src_addr, 5992108Sphk struct rdma_dev_addr *addr, void *context); 6092108Sphk unsigned long timeout; 6192108Sphk int status; 6292108Sphk}; 6392108Sphk 6492108Sphkstatic void process_req(struct work_struct *work); 6592108Sphk 6692108Sphkstatic DEFINE_MUTEX(lock); 6792108Sphkstatic LIST_HEAD(req_list); 6892108Sphkstatic struct delayed_work work; 6992108Sphkstatic struct workqueue_struct *addr_wq; 7092108Sphk 7192108Sphkvoid rdma_addr_register_client(struct rdma_addr_client *client) 7292108Sphk{ 7392108Sphk atomic_set(&client->refcount, 1); 7492108Sphk init_completion(&client->comp); 7592108Sphk} 7692108SphkEXPORT_SYMBOL(rdma_addr_register_client); 7792108Sphk 7892108Sphkstatic inline void put_client(struct rdma_addr_client *client) 7992108Sphk{ 8092108Sphk if (atomic_dec_and_test(&client->refcount)) 8193248Sphk complete(&client->comp); 8297075Sphk} 8392108Sphk 8492108Sphkvoid rdma_addr_unregister_client(struct rdma_addr_client *client) 8593248Sphk{ 8692108Sphk put_client(client); 8792108Sphk wait_for_completion(&client->comp); 8892108Sphk} 8992108SphkEXPORT_SYMBOL(rdma_addr_unregister_client); 9092108Sphk 9192108Sphk#ifdef __linux__ 9292108Sphkint rdma_copy_addr(struct rdma_dev_addr *dev_addr, struct net_device *dev, 9392108Sphk const unsigned char *dst_dev_addr) 9492108Sphk{ 9592108Sphk dev_addr->dev_type = dev->type; 9692108Sphk memcpy(dev_addr->src_dev_addr, dev->dev_addr, MAX_ADDR_LEN); 9792108Sphk memcpy(dev_addr->broadcast, dev->broadcast, MAX_ADDR_LEN); 9892108Sphk if (dst_dev_addr) 9992108Sphk memcpy(dev_addr->dst_dev_addr, dst_dev_addr, MAX_ADDR_LEN); 10092108Sphk dev_addr->bound_dev_if = dev->ifindex; 10193248Sphk return 0; 10292108Sphk} 10392108Sphk#else 10492108Sphkint rdma_copy_addr(struct rdma_dev_addr *dev_addr, struct ifnet *dev, 10592108Sphk const unsigned char *dst_dev_addr) 10692108Sphk{ 10792108Sphk if (dev->if_type == IFT_INFINIBAND) 10892108Sphk dev_addr->dev_type = ARPHRD_INFINIBAND; 10992108Sphk else if (dev->if_type == IFT_ETHER) 11092108Sphk dev_addr->dev_type = ARPHRD_ETHER; 11192108Sphk else 11292108Sphk dev_addr->dev_type = 0; 11392108Sphk memcpy(dev_addr->src_dev_addr, IF_LLADDR(dev), dev->if_addrlen); 11492108Sphk memcpy(dev_addr->broadcast, __DECONST(char *, dev->if_broadcastaddr), 11592108Sphk dev->if_addrlen); 11692108Sphk if (dst_dev_addr) 11796987Sphk memcpy(dev_addr->dst_dev_addr, dst_dev_addr, dev->if_addrlen); 11892108Sphk dev_addr->bound_dev_if = dev->if_index; 11996987Sphk return 0; 12092108Sphk} 12192108Sphk#endif 12292108SphkEXPORT_SYMBOL(rdma_copy_addr); 12392108Sphk 12492108Sphkint rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr) 12592108Sphk{ 12692108Sphk struct net_device *dev; 12793250Sphk int ret = -EADDRNOTAVAIL; 12892108Sphk 12992108Sphk if (dev_addr->bound_dev_if) { 13092108Sphk dev = dev_get_by_index(&init_net, dev_addr->bound_dev_if); 13192108Sphk if (!dev) 13296987Sphk return -ENODEV; 13392108Sphk ret = rdma_copy_addr(dev_addr, dev, NULL); 13492108Sphk dev_put(dev); 13592108Sphk return ret; 13692108Sphk } 13792108Sphk 13893248Sphk switch (addr->sa_family) { 13992108Sphk#ifdef INET 14092108Sphk case AF_INET: 14193776Sphk dev = ip_dev_find(NULL, 14292108Sphk ((struct sockaddr_in *) addr)->sin_addr.s_addr); 14396987Sphk 14496987Sphk if (!dev) 14596987Sphk return ret; 14696987Sphk 14796987Sphk ret = rdma_copy_addr(dev_addr, dev, NULL); 14896987Sphk dev_put(dev); 14996987Sphk break; 15092108Sphk#endif 15192108Sphk 15296987Sphk#if defined(INET6) 15392108Sphk case AF_INET6: 15496987Sphk#ifdef __linux__ 15596987Sphk read_lock(&dev_base_lock); 15696987Sphk for_each_netdev(&init_net, dev) { 15792108Sphk if (ipv6_chk_addr(&init_net, 15892108Sphk &((struct sockaddr_in6 *) addr)->sin6_addr, 15992108Sphk dev, 1)) { 16092108Sphk ret = rdma_copy_addr(dev_addr, dev, NULL); 16192108Sphk break; 16292108Sphk } 16392108Sphk } 16492108Sphk read_unlock(&dev_base_lock); 16592108Sphk#else 16692108Sphk { 16792108Sphk struct sockaddr_in6 *sin6; 16892108Sphk struct ifaddr *ifa; 16992108Sphk in_port_t port; 17092108Sphk 17192108Sphk sin6 = (struct sockaddr_in6 *)addr; 17292108Sphk port = sin6->sin6_port; 17392108Sphk sin6->sin6_port = 0; 17492108Sphk ifa = ifa_ifwithaddr(addr); 17592108Sphk sin6->sin6_port = port; 17692479Sphk if (ifa == NULL) { 17792108Sphk ret = -ENODEV; 17892108Sphk break; 17992108Sphk } 18092108Sphk ret = rdma_copy_addr(dev_addr, ifa->ifa_ifp, NULL); 18192108Sphk ifa_free(ifa); 18292108Sphk break; 18392108Sphk } 18492479Sphk#endif 18592108Sphk break; 18692108Sphk#endif 18792108Sphk } 18892108Sphk return ret; 18992108Sphk} 19092108SphkEXPORT_SYMBOL(rdma_translate_ip); 19192108Sphk 19292108Sphkstatic void set_timeout(unsigned long time) 19392108Sphk{ 19492108Sphk unsigned long delay; 19592108Sphk 19692108Sphk cancel_delayed_work(&work); 19792108Sphk 19892108Sphk delay = time - jiffies; 19992108Sphk if ((long)delay <= 0) 20092108Sphk delay = 1; 20192108Sphk 20292479Sphk queue_delayed_work(addr_wq, &work, delay); 20392108Sphk} 20492108Sphk 20592108Sphkstatic void queue_req(struct addr_req *req) 20692108Sphk{ 20792108Sphk struct addr_req *temp_req; 20892108Sphk 20992108Sphk mutex_lock(&lock); 21092479Sphk list_for_each_entry_reverse(temp_req, &req_list, list) { 21192108Sphk if (time_after_eq(req->timeout, temp_req->timeout)) 21292108Sphk break; 21392108Sphk } 21492108Sphk 21592108Sphk list_add(&req->list, &temp_req->list); 21692108Sphk 21792108Sphk if (req_list.next == &req->list) 21895323Sphk set_timeout(req->timeout); 21992108Sphk mutex_unlock(&lock); 22095323Sphk} 22195038Sphk 22292108Sphk#ifdef __linux__ 22395038Sphkstatic int addr4_resolve(struct sockaddr_in *src_in, 22492403Sphk struct sockaddr_in *dst_in, 22595323Sphk struct rdma_dev_addr *addr) 22692108Sphk{ 22792108Sphk __be32 src_ip = src_in->sin_addr.s_addr; 22892108Sphk __be32 dst_ip = dst_in->sin_addr.s_addr; 22995323Sphk struct flowi fl; 23095323Sphk struct rtable *rt; 23192108Sphk struct neighbour *neigh; 23292108Sphk int ret; 23392479Sphk 23492403Sphk memset(&fl, 0, sizeof fl); 23592698Sphk fl.nl_u.ip4_u.daddr = dst_ip; 23692698Sphk fl.nl_u.ip4_u.saddr = src_ip; 23792698Sphk fl.oif = addr->bound_dev_if; 23893250Sphk 23992698Sphk ret = ip_route_output_key(&init_net, &rt, &fl); 24092698Sphk if (ret) 24193250Sphk goto out; 24292698Sphk 24392698Sphk src_in->sin_family = AF_INET; 24493250Sphk src_in->sin_addr.s_addr = rt->rt_src; 24592698Sphk 24692698Sphk if (rt->idev->dev->flags & IFF_LOOPBACK) { 24793250Sphk ret = rdma_translate_ip((struct sockaddr *) dst_in, addr); 24892698Sphk if (!ret) 24994287Sphk memcpy(addr->dst_dev_addr, addr->src_dev_addr, MAX_ADDR_LEN); 25094287Sphk goto put; 25194287Sphk } 25295038Sphk 25395038Sphk /* If the device does ARP internally, return 'done' */ 25495038Sphk if (rt->idev->dev->flags & IFF_NOARP) { 25595038Sphk rdma_copy_addr(addr, rt->idev->dev, NULL); 25695038Sphk goto put; 25795038Sphk } 25895038Sphk 25995038Sphk neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, rt->idev->dev); 26095038Sphk if (!neigh || !(neigh->nud_state & NUD_VALID)) { 26195038Sphk neigh_event_send(rt->u.dst.neighbour, NULL); 26295038Sphk ret = -ENODATA; 26395038Sphk if (neigh) 26495038Sphk goto release; 26595038Sphk goto put; 26695323Sphk } 26795323Sphk 26895323Sphk ret = rdma_copy_addr(addr, neigh->dev, neigh->ha); 26995323Sphkrelease: 27095323Sphk neigh_release(neigh); 27195323Sphkput: 27295323Sphk ip_rt_put(rt); 27395323Sphkout: 27495323Sphk return ret; 27595323Sphk} 27695323Sphk 27792698Sphk#if defined(INET6) 27892698Sphkstatic int addr6_resolve(struct sockaddr_in6 *src_in, 27992698Sphk struct sockaddr_in6 *dst_in, 28092698Sphk struct rdma_dev_addr *addr) 28192698Sphk{ 28292698Sphk struct flowi fl; 28392698Sphk struct neighbour *neigh; 28492698Sphk struct dst_entry *dst; 28593250Sphk int ret; 28692698Sphk 28793250Sphk memset(&fl, 0, sizeof fl); 28892698Sphk ipv6_addr_copy(&fl.fl6_dst, &dst_in->sin6_addr); 28992698Sphk ipv6_addr_copy(&fl.fl6_src, &src_in->sin6_addr); 29092698Sphk fl.oif = addr->bound_dev_if; 29192403Sphk 29292408Sphk dst = ip6_route_output(&init_net, NULL, &fl); 29392408Sphk if ((ret = dst->error)) 29497075Sphk goto put; 29592408Sphk 29692108Sphk if (ipv6_addr_any(&fl.fl6_src)) { 29792479Sphk ret = ipv6_dev_get_saddr(&init_net, ip6_dst_idev(dst)->dev, 29892403Sphk &fl.fl6_dst, 0, &fl.fl6_src); 29992403Sphk if (ret) 30092403Sphk goto put; 30192108Sphk 30292108Sphk src_in->sin6_family = AF_INET6; 30392108Sphk ipv6_addr_copy(&src_in->sin6_addr, &fl.fl6_src); 30492108Sphk } 30592108Sphk 30692108Sphk if (dst->dev->flags & IFF_LOOPBACK) { 30792108Sphk ret = rdma_translate_ip((struct sockaddr *) dst_in, addr); 30892108Sphk if (!ret) 30992108Sphk memcpy(addr->dst_dev_addr, addr->src_dev_addr, MAX_ADDR_LEN); 31092108Sphk goto put; 31192403Sphk } 31292403Sphk 31392108Sphk /* If the device does ARP internally, return 'done' */ 31492108Sphk if (dst->dev->flags & IFF_NOARP) { 31592108Sphk ret = rdma_copy_addr(addr, dst->dev, NULL); 31692108Sphk goto put; 31792108Sphk } 31892108Sphk 31992108Sphk neigh = dst->neighbour; 32092108Sphk if (!neigh || !(neigh->nud_state & NUD_VALID)) { 32192108Sphk neigh_event_send(dst->neighbour, NULL); 32292108Sphk ret = -ENODATA; 32392108Sphk goto put; 32492108Sphk } 32592108Sphk 32692108Sphk ret = rdma_copy_addr(addr, dst->dev, neigh->ha); 32793250Sphkput: 32892108Sphk dst_release(dst); 32992108Sphk return ret; 33092108Sphk} 33192108Sphk#else 33292108Sphkstatic int addr6_resolve(struct sockaddr_in6 *src_in, 33392108Sphk struct sockaddr_in6 *dst_in, 33492108Sphk struct rdma_dev_addr *addr) 33592108Sphk{ 33692108Sphk return -EADDRNOTAVAIL; 33792108Sphk} 33892108Sphk#endif 33992108Sphk 34092108Sphk#else 34192108Sphk#include <netinet/if_ether.h> 34292108Sphk 34392108Sphkstatic int addr_resolve(struct sockaddr *src_in, 34492108Sphk struct sockaddr *dst_in, 34592108Sphk struct rdma_dev_addr *addr) 34692108Sphk{ 34792108Sphk struct sockaddr_in *sin; 34892108Sphk struct sockaddr_in6 *sin6; 34992108Sphk struct ifaddr *ifa; 35092108Sphk struct ifnet *ifp; 35192108Sphk#if defined(INET) || defined(INET6) 35292108Sphk struct llentry *lle; 35392108Sphk#endif 35492108Sphk struct rtentry *rte; 35592108Sphk in_port_t port; 35692108Sphk u_char edst[MAX_ADDR_LEN]; 35792108Sphk int multi; 35892108Sphk int bcast; 35992108Sphk int error; 36092108Sphk 36192108Sphk /* 36292108Sphk * Determine whether the address is unicast, multicast, or broadcast 36392108Sphk * and whether the source interface is valid. 36492108Sphk */ 36592108Sphk multi = 0; 36692108Sphk bcast = 0; 36792108Sphk sin = NULL; 36892108Sphk sin6 = NULL; 36992108Sphk ifp = NULL; 37092108Sphk rte = NULL; 37192108Sphk switch (dst_in->sa_family) { 37292108Sphk#ifdef INET 37392108Sphk case AF_INET: 37492108Sphk sin = (struct sockaddr_in *)dst_in; 37592108Sphk if (sin->sin_addr.s_addr == INADDR_BROADCAST) 37692108Sphk bcast = 1; 37796987Sphk if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) 37896987Sphk multi = 1; 37996987Sphk sin = (struct sockaddr_in *)src_in; 38096987Sphk if (sin->sin_addr.s_addr != INADDR_ANY) { 38196987Sphk /* 38296987Sphk * Address comparison fails if the port is set 38396987Sphk * cache it here to be restored later. 38496987Sphk */ 38596987Sphk port = sin->sin_port; 38696987Sphk sin->sin_port = 0; 38792108Sphk memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); 38892108Sphk } else 38993250Sphk src_in = NULL; 39092108Sphk break; 39192108Sphk#endif 39292108Sphk#ifdef INET6 39392108Sphk case AF_INET6: 39492108Sphk sin6 = (struct sockaddr_in6 *)dst_in; 39592108Sphk if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 39692108Sphk multi = 1; 39792108Sphk sin6 = (struct sockaddr_in6 *)src_in; 39892108Sphk if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 39992108Sphk port = sin6->sin6_port; 40095038Sphk sin6->sin6_port = 0; 40195038Sphk } else 40296987Sphk src_in = NULL; 40392108Sphk break; 40492108Sphk#endif 40592108Sphk default: 40692108Sphk return -EINVAL; 40792108Sphk } 40892108Sphk /* 40992108Sphk * If we have a source address to use look it up first and verify 41092108Sphk * that it is a local interface. 41196987Sphk */ 412 if (src_in) { 413 ifa = ifa_ifwithaddr(src_in); 414 if (sin) 415 sin->sin_port = port; 416 if (sin6) 417 sin6->sin6_port = port; 418 if (ifa == NULL) 419 return -ENETUNREACH; 420 ifp = ifa->ifa_ifp; 421 ifa_free(ifa); 422 if (bcast || multi) 423 goto mcast; 424 } 425 /* 426 * Make sure the route exists and has a valid link. 427 */ 428 rte = rtalloc1(dst_in, 1, 0); 429 if (rte == NULL || rte->rt_ifp == NULL || !RT_LINK_IS_UP(rte->rt_ifp)) { 430 if (rte) 431 RTFREE_LOCKED(rte); 432 return -EHOSTUNREACH; 433 } 434 /* 435 * If it's not multicast or broadcast and the route doesn't match the 436 * requested interface return unreachable. Otherwise fetch the 437 * correct interface pointer and unlock the route. 438 */ 439 if (multi || bcast) { 440 if (ifp == NULL) 441 ifp = rte->rt_ifp; 442 RTFREE_LOCKED(rte); 443 } else if (ifp && ifp != rte->rt_ifp) { 444 RTFREE_LOCKED(rte); 445 return -ENETUNREACH; 446 } else { 447 if (ifp == NULL) 448 ifp = rte->rt_ifp; 449 RT_UNLOCK(rte); 450 } 451mcast: 452 if (bcast) 453 return rdma_copy_addr(addr, ifp, ifp->if_broadcastaddr); 454 if (multi) { 455 struct sockaddr *llsa; 456 457 error = ifp->if_resolvemulti(ifp, &llsa, dst_in); 458 if (error) 459 return -error; 460 error = rdma_copy_addr(addr, ifp, 461 LLADDR((struct sockaddr_dl *)llsa)); 462 free(llsa, M_IFMADDR); 463 return error; 464 } 465 /* 466 * Resolve the link local address. 467 */ 468 switch (dst_in->sa_family) { 469#ifdef INET 470 case AF_INET: 471 error = arpresolve(ifp, rte, NULL, dst_in, edst, &lle); 472 break; 473#endif 474#ifdef INET6 475 case AF_INET6: 476 error = nd6_storelladdr(ifp, NULL, dst_in, (u_char *)edst, &lle); 477 break; 478#endif 479 default: 480 /* XXX: Shouldn't happen. */ 481 error = -EINVAL; 482 } 483 RTFREE(rte); 484 if (error == 0) 485 return rdma_copy_addr(addr, ifp, edst); 486 if (error == EWOULDBLOCK) 487 return -ENODATA; 488 return -error; 489} 490 491#endif 492 493static void process_req(struct work_struct *work) 494{ 495 struct addr_req *req, *temp_req; 496 struct sockaddr *src_in, *dst_in; 497 struct list_head done_list; 498 499 INIT_LIST_HEAD(&done_list); 500 501 mutex_lock(&lock); 502 list_for_each_entry_safe(req, temp_req, &req_list, list) { 503 if (req->status == -ENODATA) { 504 src_in = (struct sockaddr *) &req->src_addr; 505 dst_in = (struct sockaddr *) &req->dst_addr; 506 req->status = addr_resolve(src_in, dst_in, req->addr); 507 if (req->status && time_after_eq(jiffies, req->timeout)) 508 req->status = -ETIMEDOUT; 509 else if (req->status == -ENODATA) 510 continue; 511 } 512 list_move_tail(&req->list, &done_list); 513 } 514 515 if (!list_empty(&req_list)) { 516 req = list_entry(req_list.next, struct addr_req, list); 517 set_timeout(req->timeout); 518 } 519 mutex_unlock(&lock); 520 521 list_for_each_entry_safe(req, temp_req, &done_list, list) { 522 list_del(&req->list); 523 req->callback(req->status, (struct sockaddr *) &req->src_addr, 524 req->addr, req->context); 525 put_client(req->client); 526 kfree(req); 527 } 528} 529 530int rdma_resolve_ip(struct rdma_addr_client *client, 531 struct sockaddr *src_addr, struct sockaddr *dst_addr, 532 struct rdma_dev_addr *addr, int timeout_ms, 533 void (*callback)(int status, struct sockaddr *src_addr, 534 struct rdma_dev_addr *addr, void *context), 535 void *context) 536{ 537 struct sockaddr *src_in, *dst_in; 538 struct addr_req *req; 539 int ret = 0; 540 541 req = kzalloc(sizeof *req, GFP_KERNEL); 542 if (!req) 543 return -ENOMEM; 544 545 src_in = (struct sockaddr *) &req->src_addr; 546 dst_in = (struct sockaddr *) &req->dst_addr; 547 548 if (src_addr) { 549 if (src_addr->sa_family != dst_addr->sa_family) { 550 ret = -EINVAL; 551 goto err; 552 } 553 554 memcpy(src_in, src_addr, ip_addr_size(src_addr)); 555 } else { 556 src_in->sa_family = dst_addr->sa_family; 557 } 558 559 memcpy(dst_in, dst_addr, ip_addr_size(dst_addr)); 560 req->addr = addr; 561 req->callback = callback; 562 req->context = context; 563 req->client = client; 564 atomic_inc(&client->refcount); 565 566 req->status = addr_resolve(src_in, dst_in, addr); 567 switch (req->status) { 568 case 0: 569 req->timeout = jiffies; 570 queue_req(req); 571 break; 572 case -ENODATA: 573 req->timeout = msecs_to_jiffies(timeout_ms) + jiffies; 574 queue_req(req); 575 break; 576 default: 577 ret = req->status; 578 atomic_dec(&client->refcount); 579 goto err; 580 } 581 return ret; 582err: 583 kfree(req); 584 return ret; 585} 586EXPORT_SYMBOL(rdma_resolve_ip); 587 588void rdma_addr_cancel(struct rdma_dev_addr *addr) 589{ 590 struct addr_req *req, *temp_req; 591 592 mutex_lock(&lock); 593 list_for_each_entry_safe(req, temp_req, &req_list, list) { 594 if (req->addr == addr) { 595 req->status = -ECANCELED; 596 req->timeout = jiffies; 597 list_move(&req->list, &req_list); 598 set_timeout(req->timeout); 599 break; 600 } 601 } 602 mutex_unlock(&lock); 603} 604EXPORT_SYMBOL(rdma_addr_cancel); 605 606static int netevent_callback(struct notifier_block *self, unsigned long event, 607 void *ctx) 608{ 609 if (event == NETEVENT_NEIGH_UPDATE) { 610#ifdef __linux__ 611 struct neighbour *neigh = ctx; 612 613 if (neigh->nud_state & NUD_VALID) { 614 set_timeout(jiffies); 615 } 616#else 617 set_timeout(jiffies); 618#endif 619 } 620 return 0; 621} 622 623static struct notifier_block nb = { 624 .notifier_call = netevent_callback 625}; 626 627static int addr_init(void) 628{ 629 INIT_DELAYED_WORK(&work, process_req); 630 addr_wq = create_singlethread_workqueue("ib_addr"); 631 if (!addr_wq) 632 return -ENOMEM; 633 634 register_netevent_notifier(&nb); 635 return 0; 636} 637 638static void addr_cleanup(void) 639{ 640 unregister_netevent_notifier(&nb); 641 destroy_workqueue(addr_wq); 642} 643 644module_init(addr_init); 645module_exit(addr_cleanup); 646