1219820Sjeff/* 2219820Sjeff * Copyright (c) 2005 Voltaire Inc. All rights reserved. 3219820Sjeff * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved. 4219820Sjeff * Copyright (c) 1999-2005, Mellanox Technologies, Inc. All rights reserved. 5219820Sjeff * Copyright (c) 2005 Intel Corporation. All rights reserved. 6219820Sjeff * 7219820Sjeff * This software is available to you under a choice of one of two 8219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 9219820Sjeff * General Public License (GPL) Version 2, available from the file 10219820Sjeff * COPYING in the main directory of this source tree, or the 11219820Sjeff * OpenIB.org BSD license below: 12219820Sjeff * 13219820Sjeff * Redistribution and use in source and binary forms, with or 14219820Sjeff * without modification, are permitted provided that the following 15219820Sjeff * conditions are met: 16219820Sjeff * 17219820Sjeff * - Redistributions of source code must retain the above 18219820Sjeff * copyright notice, this list of conditions and the following 19219820Sjeff * disclaimer. 20219820Sjeff * 21219820Sjeff * - Redistributions in binary form must reproduce the above 22219820Sjeff * copyright notice, this list of conditions and the following 23219820Sjeff * disclaimer in the documentation and/or other materials 24219820Sjeff * provided with the distribution. 25219820Sjeff * 26219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 27219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 28219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 29219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 30219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 31219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 32219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 33219820Sjeff * SOFTWARE. 34219820Sjeff */ 35219820Sjeff 36219820Sjeff#include <linux/mutex.h> 37219820Sjeff#include <linux/inetdevice.h> 38219820Sjeff#include <linux/workqueue.h> 39219820Sjeff#include <net/arp.h> 40219820Sjeff#include <net/neighbour.h> 41219820Sjeff#include <net/route.h> 42219820Sjeff#include <net/netevent.h> 43219820Sjeff#include <net/addrconf.h> 44219820Sjeff#include <net/ip6_route.h> 45219820Sjeff#include <rdma/ib_addr.h> 46219820Sjeff 47219820SjeffMODULE_AUTHOR("Sean Hefty"); 48219820SjeffMODULE_DESCRIPTION("IB Address Translation"); 49219820SjeffMODULE_LICENSE("Dual BSD/GPL"); 50219820Sjeff 51219820Sjeffstruct addr_req { 52219820Sjeff struct list_head list; 53219820Sjeff struct sockaddr_storage src_addr; 54219820Sjeff struct sockaddr_storage dst_addr; 55219820Sjeff struct rdma_dev_addr *addr; 56219820Sjeff struct rdma_addr_client *client; 57219820Sjeff void *context; 58219820Sjeff void (*callback)(int status, struct sockaddr *src_addr, 59219820Sjeff struct rdma_dev_addr *addr, void *context); 60219820Sjeff unsigned long timeout; 61219820Sjeff int status; 62219820Sjeff}; 63219820Sjeff 64219820Sjeffstatic void process_req(struct work_struct *work); 65219820Sjeff 66219820Sjeffstatic DEFINE_MUTEX(lock); 67219820Sjeffstatic LIST_HEAD(req_list); 68219820Sjeffstatic struct delayed_work work; 69219820Sjeffstatic struct workqueue_struct *addr_wq; 70219820Sjeff 71219820Sjeffvoid rdma_addr_register_client(struct rdma_addr_client *client) 72219820Sjeff{ 73219820Sjeff atomic_set(&client->refcount, 1); 74219820Sjeff init_completion(&client->comp); 75219820Sjeff} 76219820SjeffEXPORT_SYMBOL(rdma_addr_register_client); 77219820Sjeff 78219820Sjeffstatic inline void put_client(struct rdma_addr_client *client) 79219820Sjeff{ 80219820Sjeff if (atomic_dec_and_test(&client->refcount)) 81219820Sjeff complete(&client->comp); 82219820Sjeff} 83219820Sjeff 84219820Sjeffvoid rdma_addr_unregister_client(struct rdma_addr_client *client) 85219820Sjeff{ 86219820Sjeff put_client(client); 87219820Sjeff wait_for_completion(&client->comp); 88219820Sjeff} 89219820SjeffEXPORT_SYMBOL(rdma_addr_unregister_client); 90219820Sjeff 91219820Sjeff#ifdef __linux__ 92219820Sjeffint rdma_copy_addr(struct rdma_dev_addr *dev_addr, struct net_device *dev, 93219820Sjeff const unsigned char *dst_dev_addr) 94219820Sjeff{ 95219820Sjeff dev_addr->dev_type = dev->type; 96219820Sjeff memcpy(dev_addr->src_dev_addr, dev->dev_addr, MAX_ADDR_LEN); 97219820Sjeff memcpy(dev_addr->broadcast, dev->broadcast, MAX_ADDR_LEN); 98219820Sjeff if (dst_dev_addr) 99219820Sjeff memcpy(dev_addr->dst_dev_addr, dst_dev_addr, MAX_ADDR_LEN); 100219820Sjeff dev_addr->bound_dev_if = dev->ifindex; 101219820Sjeff return 0; 102219820Sjeff} 103219820Sjeff#else 104219820Sjeffint rdma_copy_addr(struct rdma_dev_addr *dev_addr, struct ifnet *dev, 105219820Sjeff const unsigned char *dst_dev_addr) 106219820Sjeff{ 107219820Sjeff if (dev->if_type == IFT_INFINIBAND) 108219820Sjeff dev_addr->dev_type = ARPHRD_INFINIBAND; 109219820Sjeff else if (dev->if_type == IFT_ETHER) 110219820Sjeff dev_addr->dev_type = ARPHRD_ETHER; 111219820Sjeff else 112219820Sjeff dev_addr->dev_type = 0; 113219820Sjeff memcpy(dev_addr->src_dev_addr, IF_LLADDR(dev), dev->if_addrlen); 114219820Sjeff memcpy(dev_addr->broadcast, __DECONST(char *, dev->if_broadcastaddr), 115219820Sjeff dev->if_addrlen); 116219820Sjeff if (dst_dev_addr) 117219820Sjeff memcpy(dev_addr->dst_dev_addr, dst_dev_addr, dev->if_addrlen); 118219820Sjeff dev_addr->bound_dev_if = dev->if_index; 119219820Sjeff return 0; 120219820Sjeff} 121219820Sjeff#endif 122219820SjeffEXPORT_SYMBOL(rdma_copy_addr); 123219820Sjeff 124219820Sjeffint rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr) 125219820Sjeff{ 126219820Sjeff struct net_device *dev; 127219820Sjeff int ret = -EADDRNOTAVAIL; 128219820Sjeff 129219820Sjeff if (dev_addr->bound_dev_if) { 130219820Sjeff dev = dev_get_by_index(&init_net, dev_addr->bound_dev_if); 131219820Sjeff if (!dev) 132219820Sjeff return -ENODEV; 133219820Sjeff ret = rdma_copy_addr(dev_addr, dev, NULL); 134219820Sjeff dev_put(dev); 135219820Sjeff return ret; 136219820Sjeff } 137219820Sjeff 138219820Sjeff switch (addr->sa_family) { 139239748Sjhb#ifdef INET 140219820Sjeff case AF_INET: 141219820Sjeff dev = ip_dev_find(NULL, 142219820Sjeff ((struct sockaddr_in *) addr)->sin_addr.s_addr); 143219820Sjeff 144219820Sjeff if (!dev) 145219820Sjeff return ret; 146219820Sjeff 147219820Sjeff ret = rdma_copy_addr(dev_addr, dev, NULL); 148219820Sjeff dev_put(dev); 149219820Sjeff break; 150239748Sjhb#endif 151219820Sjeff 152219820Sjeff#if defined(INET6) 153219820Sjeff case AF_INET6: 154219820Sjeff#ifdef __linux__ 155219820Sjeff read_lock(&dev_base_lock); 156219820Sjeff for_each_netdev(&init_net, dev) { 157219820Sjeff if (ipv6_chk_addr(&init_net, 158219820Sjeff &((struct sockaddr_in6 *) addr)->sin6_addr, 159219820Sjeff dev, 1)) { 160219820Sjeff ret = rdma_copy_addr(dev_addr, dev, NULL); 161219820Sjeff break; 162219820Sjeff } 163219820Sjeff } 164219820Sjeff read_unlock(&dev_base_lock); 165219820Sjeff#else 166219820Sjeff { 167219820Sjeff struct sockaddr_in6 *sin6; 168219820Sjeff struct ifaddr *ifa; 169219820Sjeff in_port_t port; 170219820Sjeff 171219820Sjeff sin6 = (struct sockaddr_in6 *)addr; 172219820Sjeff port = sin6->sin6_port; 173219820Sjeff sin6->sin6_port = 0; 174219820Sjeff ifa = ifa_ifwithaddr(addr); 175219820Sjeff sin6->sin6_port = port; 176219820Sjeff if (ifa == NULL) { 177219820Sjeff ret = -ENODEV; 178219820Sjeff break; 179219820Sjeff } 180219820Sjeff ret = rdma_copy_addr(dev_addr, ifa->ifa_ifp, NULL); 181219820Sjeff ifa_free(ifa); 182219820Sjeff break; 183219820Sjeff } 184219820Sjeff#endif 185219820Sjeff break; 186219820Sjeff#endif 187219820Sjeff } 188219820Sjeff return ret; 189219820Sjeff} 190219820SjeffEXPORT_SYMBOL(rdma_translate_ip); 191219820Sjeff 192219820Sjeffstatic void set_timeout(unsigned long time) 193219820Sjeff{ 194219820Sjeff unsigned long delay; 195219820Sjeff 196219820Sjeff cancel_delayed_work(&work); 197219820Sjeff 198219820Sjeff delay = time - jiffies; 199219820Sjeff if ((long)delay <= 0) 200219820Sjeff delay = 1; 201219820Sjeff 202219820Sjeff queue_delayed_work(addr_wq, &work, delay); 203219820Sjeff} 204219820Sjeff 205219820Sjeffstatic void queue_req(struct addr_req *req) 206219820Sjeff{ 207219820Sjeff struct addr_req *temp_req; 208219820Sjeff 209219820Sjeff mutex_lock(&lock); 210219820Sjeff list_for_each_entry_reverse(temp_req, &req_list, list) { 211219820Sjeff if (time_after_eq(req->timeout, temp_req->timeout)) 212219820Sjeff break; 213219820Sjeff } 214219820Sjeff 215219820Sjeff list_add(&req->list, &temp_req->list); 216219820Sjeff 217219820Sjeff if (req_list.next == &req->list) 218219820Sjeff set_timeout(req->timeout); 219219820Sjeff mutex_unlock(&lock); 220219820Sjeff} 221219820Sjeff 222219820Sjeff#ifdef __linux__ 223219820Sjeffstatic int addr4_resolve(struct sockaddr_in *src_in, 224219820Sjeff struct sockaddr_in *dst_in, 225219820Sjeff struct rdma_dev_addr *addr) 226219820Sjeff{ 227219820Sjeff __be32 src_ip = src_in->sin_addr.s_addr; 228219820Sjeff __be32 dst_ip = dst_in->sin_addr.s_addr; 229219820Sjeff struct flowi fl; 230219820Sjeff struct rtable *rt; 231219820Sjeff struct neighbour *neigh; 232219820Sjeff int ret; 233219820Sjeff 234219820Sjeff memset(&fl, 0, sizeof fl); 235219820Sjeff fl.nl_u.ip4_u.daddr = dst_ip; 236219820Sjeff fl.nl_u.ip4_u.saddr = src_ip; 237219820Sjeff fl.oif = addr->bound_dev_if; 238219820Sjeff 239219820Sjeff ret = ip_route_output_key(&init_net, &rt, &fl); 240219820Sjeff if (ret) 241219820Sjeff goto out; 242219820Sjeff 243219820Sjeff src_in->sin_family = AF_INET; 244219820Sjeff src_in->sin_addr.s_addr = rt->rt_src; 245219820Sjeff 246219820Sjeff if (rt->idev->dev->flags & IFF_LOOPBACK) { 247219820Sjeff ret = rdma_translate_ip((struct sockaddr *) dst_in, addr); 248219820Sjeff if (!ret) 249219820Sjeff memcpy(addr->dst_dev_addr, addr->src_dev_addr, MAX_ADDR_LEN); 250219820Sjeff goto put; 251219820Sjeff } 252219820Sjeff 253219820Sjeff /* If the device does ARP internally, return 'done' */ 254219820Sjeff if (rt->idev->dev->flags & IFF_NOARP) { 255219820Sjeff rdma_copy_addr(addr, rt->idev->dev, NULL); 256219820Sjeff goto put; 257219820Sjeff } 258219820Sjeff 259219820Sjeff neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, rt->idev->dev); 260219820Sjeff if (!neigh || !(neigh->nud_state & NUD_VALID)) { 261219820Sjeff neigh_event_send(rt->u.dst.neighbour, NULL); 262219820Sjeff ret = -ENODATA; 263219820Sjeff if (neigh) 264219820Sjeff goto release; 265219820Sjeff goto put; 266219820Sjeff } 267219820Sjeff 268219820Sjeff ret = rdma_copy_addr(addr, neigh->dev, neigh->ha); 269219820Sjeffrelease: 270219820Sjeff neigh_release(neigh); 271219820Sjeffput: 272219820Sjeff ip_rt_put(rt); 273219820Sjeffout: 274219820Sjeff return ret; 275219820Sjeff} 276219820Sjeff 277219820Sjeff#if defined(INET6) 278219820Sjeffstatic int addr6_resolve(struct sockaddr_in6 *src_in, 279219820Sjeff struct sockaddr_in6 *dst_in, 280219820Sjeff struct rdma_dev_addr *addr) 281219820Sjeff{ 282219820Sjeff struct flowi fl; 283219820Sjeff struct neighbour *neigh; 284219820Sjeff struct dst_entry *dst; 285219820Sjeff int ret; 286219820Sjeff 287219820Sjeff memset(&fl, 0, sizeof fl); 288219820Sjeff ipv6_addr_copy(&fl.fl6_dst, &dst_in->sin6_addr); 289219820Sjeff ipv6_addr_copy(&fl.fl6_src, &src_in->sin6_addr); 290219820Sjeff fl.oif = addr->bound_dev_if; 291219820Sjeff 292219820Sjeff dst = ip6_route_output(&init_net, NULL, &fl); 293219820Sjeff if ((ret = dst->error)) 294219820Sjeff goto put; 295219820Sjeff 296219820Sjeff if (ipv6_addr_any(&fl.fl6_src)) { 297219820Sjeff ret = ipv6_dev_get_saddr(&init_net, ip6_dst_idev(dst)->dev, 298219820Sjeff &fl.fl6_dst, 0, &fl.fl6_src); 299219820Sjeff if (ret) 300219820Sjeff goto put; 301219820Sjeff 302219820Sjeff src_in->sin6_family = AF_INET6; 303219820Sjeff ipv6_addr_copy(&src_in->sin6_addr, &fl.fl6_src); 304219820Sjeff } 305219820Sjeff 306219820Sjeff if (dst->dev->flags & IFF_LOOPBACK) { 307219820Sjeff ret = rdma_translate_ip((struct sockaddr *) dst_in, addr); 308219820Sjeff if (!ret) 309219820Sjeff memcpy(addr->dst_dev_addr, addr->src_dev_addr, MAX_ADDR_LEN); 310219820Sjeff goto put; 311219820Sjeff } 312219820Sjeff 313219820Sjeff /* If the device does ARP internally, return 'done' */ 314219820Sjeff if (dst->dev->flags & IFF_NOARP) { 315219820Sjeff ret = rdma_copy_addr(addr, dst->dev, NULL); 316219820Sjeff goto put; 317219820Sjeff } 318219820Sjeff 319219820Sjeff neigh = dst->neighbour; 320219820Sjeff if (!neigh || !(neigh->nud_state & NUD_VALID)) { 321219820Sjeff neigh_event_send(dst->neighbour, NULL); 322219820Sjeff ret = -ENODATA; 323219820Sjeff goto put; 324219820Sjeff } 325219820Sjeff 326219820Sjeff ret = rdma_copy_addr(addr, dst->dev, neigh->ha); 327219820Sjeffput: 328219820Sjeff dst_release(dst); 329219820Sjeff return ret; 330219820Sjeff} 331219820Sjeff#else 332219820Sjeffstatic int addr6_resolve(struct sockaddr_in6 *src_in, 333219820Sjeff struct sockaddr_in6 *dst_in, 334219820Sjeff struct rdma_dev_addr *addr) 335219820Sjeff{ 336219820Sjeff return -EADDRNOTAVAIL; 337219820Sjeff} 338219820Sjeff#endif 339219820Sjeff 340219820Sjeff#else 341219820Sjeff#include <netinet/if_ether.h> 342219820Sjeff 343219820Sjeffstatic int addr_resolve(struct sockaddr *src_in, 344219820Sjeff struct sockaddr *dst_in, 345219820Sjeff struct rdma_dev_addr *addr) 346219820Sjeff{ 347219820Sjeff struct sockaddr_in *sin; 348219820Sjeff struct sockaddr_in6 *sin6; 349219820Sjeff struct ifaddr *ifa; 350219820Sjeff struct ifnet *ifp; 351239748Sjhb#if defined(INET) || defined(INET6) 352219820Sjeff struct llentry *lle; 353239748Sjhb#endif 354219820Sjeff struct rtentry *rte; 355219820Sjeff in_port_t port; 356219820Sjeff u_char edst[MAX_ADDR_LEN]; 357219820Sjeff int multi; 358219820Sjeff int bcast; 359219820Sjeff int error; 360219820Sjeff 361219820Sjeff /* 362219820Sjeff * Determine whether the address is unicast, multicast, or broadcast 363219820Sjeff * and whether the source interface is valid. 364219820Sjeff */ 365219820Sjeff multi = 0; 366219820Sjeff bcast = 0; 367219820Sjeff sin = NULL; 368219820Sjeff sin6 = NULL; 369219820Sjeff ifp = NULL; 370219820Sjeff rte = NULL; 371219820Sjeff switch (dst_in->sa_family) { 372239748Sjhb#ifdef INET 373219820Sjeff case AF_INET: 374219820Sjeff sin = (struct sockaddr_in *)dst_in; 375219820Sjeff if (sin->sin_addr.s_addr == INADDR_BROADCAST) 376219820Sjeff bcast = 1; 377219820Sjeff if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) 378219820Sjeff multi = 1; 379219820Sjeff sin = (struct sockaddr_in *)src_in; 380219820Sjeff if (sin->sin_addr.s_addr != INADDR_ANY) { 381219820Sjeff /* 382219820Sjeff * Address comparison fails if the port is set 383219820Sjeff * cache it here to be restored later. 384219820Sjeff */ 385219820Sjeff port = sin->sin_port; 386219820Sjeff sin->sin_port = 0; 387219820Sjeff memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); 388219820Sjeff } else 389219820Sjeff src_in = NULL; 390219820Sjeff break; 391239748Sjhb#endif 392219820Sjeff#ifdef INET6 393219820Sjeff case AF_INET6: 394219820Sjeff sin6 = (struct sockaddr_in6 *)dst_in; 395219820Sjeff if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 396219820Sjeff multi = 1; 397219820Sjeff sin6 = (struct sockaddr_in6 *)src_in; 398219820Sjeff if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 399219820Sjeff port = sin6->sin6_port; 400219820Sjeff sin6->sin6_port = 0; 401219820Sjeff } else 402219820Sjeff src_in = NULL; 403219820Sjeff break; 404219820Sjeff#endif 405219820Sjeff default: 406219820Sjeff return -EINVAL; 407219820Sjeff } 408219820Sjeff /* 409219820Sjeff * If we have a source address to use look it up first and verify 410219820Sjeff * that it is a local interface. 411219820Sjeff */ 412219820Sjeff if (src_in) { 413219820Sjeff ifa = ifa_ifwithaddr(src_in); 414219820Sjeff if (sin) 415219820Sjeff sin->sin_port = port; 416219820Sjeff if (sin6) 417219820Sjeff sin6->sin6_port = port; 418219820Sjeff if (ifa == NULL) 419219820Sjeff return -ENETUNREACH; 420219820Sjeff ifp = ifa->ifa_ifp; 421219820Sjeff ifa_free(ifa); 422219820Sjeff if (bcast || multi) 423219820Sjeff goto mcast; 424219820Sjeff } 425219820Sjeff /* 426219820Sjeff * Make sure the route exists and has a valid link. 427219820Sjeff */ 428219820Sjeff rte = rtalloc1(dst_in, 1, 0); 429219820Sjeff if (rte == NULL || rte->rt_ifp == NULL || !RT_LINK_IS_UP(rte->rt_ifp)) { 430219820Sjeff if (rte) 431219820Sjeff RTFREE_LOCKED(rte); 432219820Sjeff return -EHOSTUNREACH; 433219820Sjeff } 434219820Sjeff /* 435219820Sjeff * If it's not multicast or broadcast and the route doesn't match the 436219820Sjeff * requested interface return unreachable. Otherwise fetch the 437219820Sjeff * correct interface pointer and unlock the route. 438219820Sjeff */ 439219820Sjeff if (multi || bcast) { 440219820Sjeff if (ifp == NULL) 441219820Sjeff ifp = rte->rt_ifp; 442219820Sjeff RTFREE_LOCKED(rte); 443219820Sjeff } else if (ifp && ifp != rte->rt_ifp) { 444219820Sjeff RTFREE_LOCKED(rte); 445219820Sjeff return -ENETUNREACH; 446219820Sjeff } else { 447219820Sjeff if (ifp == NULL) 448219820Sjeff ifp = rte->rt_ifp; 449219820Sjeff RT_UNLOCK(rte); 450219820Sjeff } 451219820Sjeffmcast: 452219820Sjeff if (bcast) 453219820Sjeff return rdma_copy_addr(addr, ifp, ifp->if_broadcastaddr); 454219820Sjeff if (multi) { 455219820Sjeff struct sockaddr *llsa; 456219820Sjeff 457219820Sjeff error = ifp->if_resolvemulti(ifp, &llsa, dst_in); 458219820Sjeff if (error) 459219820Sjeff return -error; 460219820Sjeff error = rdma_copy_addr(addr, ifp, 461219820Sjeff LLADDR((struct sockaddr_dl *)llsa)); 462219820Sjeff free(llsa, M_IFMADDR); 463219820Sjeff return error; 464219820Sjeff } 465219820Sjeff /* 466219820Sjeff * Resolve the link local address. 467219820Sjeff */ 468239748Sjhb switch (dst_in->sa_family) { 469239748Sjhb#ifdef INET 470239748Sjhb case AF_INET: 471219820Sjeff error = arpresolve(ifp, rte, NULL, dst_in, edst, &lle); 472239748Sjhb break; 473239748Sjhb#endif 474219820Sjeff#ifdef INET6 475239748Sjhb case AF_INET6: 476219820Sjeff error = nd6_storelladdr(ifp, NULL, dst_in, (u_char *)edst, &lle); 477239748Sjhb break; 478219820Sjeff#endif 479239748Sjhb default: 480239748Sjhb /* XXX: Shouldn't happen. */ 481239748Sjhb error = -EINVAL; 482239748Sjhb } 483219820Sjeff RTFREE(rte); 484219820Sjeff if (error == 0) 485219820Sjeff return rdma_copy_addr(addr, ifp, edst); 486219820Sjeff if (error == EWOULDBLOCK) 487219820Sjeff return -ENODATA; 488219820Sjeff return -error; 489219820Sjeff} 490219820Sjeff 491219820Sjeff#endif 492219820Sjeff 493219820Sjeffstatic void process_req(struct work_struct *work) 494219820Sjeff{ 495219820Sjeff struct addr_req *req, *temp_req; 496219820Sjeff struct sockaddr *src_in, *dst_in; 497219820Sjeff struct list_head done_list; 498219820Sjeff 499219820Sjeff INIT_LIST_HEAD(&done_list); 500219820Sjeff 501219820Sjeff mutex_lock(&lock); 502219820Sjeff list_for_each_entry_safe(req, temp_req, &req_list, list) { 503219820Sjeff if (req->status == -ENODATA) { 504219820Sjeff src_in = (struct sockaddr *) &req->src_addr; 505219820Sjeff dst_in = (struct sockaddr *) &req->dst_addr; 506219820Sjeff req->status = addr_resolve(src_in, dst_in, req->addr); 507219820Sjeff if (req->status && time_after_eq(jiffies, req->timeout)) 508219820Sjeff req->status = -ETIMEDOUT; 509219820Sjeff else if (req->status == -ENODATA) 510219820Sjeff continue; 511219820Sjeff } 512219820Sjeff list_move_tail(&req->list, &done_list); 513219820Sjeff } 514219820Sjeff 515219820Sjeff if (!list_empty(&req_list)) { 516219820Sjeff req = list_entry(req_list.next, struct addr_req, list); 517219820Sjeff set_timeout(req->timeout); 518219820Sjeff } 519219820Sjeff mutex_unlock(&lock); 520219820Sjeff 521219820Sjeff list_for_each_entry_safe(req, temp_req, &done_list, list) { 522219820Sjeff list_del(&req->list); 523219820Sjeff req->callback(req->status, (struct sockaddr *) &req->src_addr, 524219820Sjeff req->addr, req->context); 525219820Sjeff put_client(req->client); 526219820Sjeff kfree(req); 527219820Sjeff } 528219820Sjeff} 529219820Sjeff 530219820Sjeffint rdma_resolve_ip(struct rdma_addr_client *client, 531219820Sjeff struct sockaddr *src_addr, struct sockaddr *dst_addr, 532219820Sjeff struct rdma_dev_addr *addr, int timeout_ms, 533219820Sjeff void (*callback)(int status, struct sockaddr *src_addr, 534219820Sjeff struct rdma_dev_addr *addr, void *context), 535219820Sjeff void *context) 536219820Sjeff{ 537219820Sjeff struct sockaddr *src_in, *dst_in; 538219820Sjeff struct addr_req *req; 539219820Sjeff int ret = 0; 540219820Sjeff 541219820Sjeff req = kzalloc(sizeof *req, GFP_KERNEL); 542219820Sjeff if (!req) 543219820Sjeff return -ENOMEM; 544219820Sjeff 545219820Sjeff src_in = (struct sockaddr *) &req->src_addr; 546219820Sjeff dst_in = (struct sockaddr *) &req->dst_addr; 547219820Sjeff 548219820Sjeff if (src_addr) { 549219820Sjeff if (src_addr->sa_family != dst_addr->sa_family) { 550219820Sjeff ret = -EINVAL; 551219820Sjeff goto err; 552219820Sjeff } 553219820Sjeff 554219820Sjeff memcpy(src_in, src_addr, ip_addr_size(src_addr)); 555219820Sjeff } else { 556219820Sjeff src_in->sa_family = dst_addr->sa_family; 557219820Sjeff } 558219820Sjeff 559219820Sjeff memcpy(dst_in, dst_addr, ip_addr_size(dst_addr)); 560219820Sjeff req->addr = addr; 561219820Sjeff req->callback = callback; 562219820Sjeff req->context = context; 563219820Sjeff req->client = client; 564219820Sjeff atomic_inc(&client->refcount); 565219820Sjeff 566219820Sjeff req->status = addr_resolve(src_in, dst_in, addr); 567219820Sjeff switch (req->status) { 568219820Sjeff case 0: 569219820Sjeff req->timeout = jiffies; 570219820Sjeff queue_req(req); 571219820Sjeff break; 572219820Sjeff case -ENODATA: 573219820Sjeff req->timeout = msecs_to_jiffies(timeout_ms) + jiffies; 574219820Sjeff queue_req(req); 575219820Sjeff break; 576219820Sjeff default: 577219820Sjeff ret = req->status; 578219820Sjeff atomic_dec(&client->refcount); 579219820Sjeff goto err; 580219820Sjeff } 581219820Sjeff return ret; 582219820Sjefferr: 583219820Sjeff kfree(req); 584219820Sjeff return ret; 585219820Sjeff} 586219820SjeffEXPORT_SYMBOL(rdma_resolve_ip); 587219820Sjeff 588219820Sjeffvoid rdma_addr_cancel(struct rdma_dev_addr *addr) 589219820Sjeff{ 590219820Sjeff struct addr_req *req, *temp_req; 591219820Sjeff 592219820Sjeff mutex_lock(&lock); 593219820Sjeff list_for_each_entry_safe(req, temp_req, &req_list, list) { 594219820Sjeff if (req->addr == addr) { 595219820Sjeff req->status = -ECANCELED; 596219820Sjeff req->timeout = jiffies; 597219820Sjeff list_move(&req->list, &req_list); 598219820Sjeff set_timeout(req->timeout); 599219820Sjeff break; 600219820Sjeff } 601219820Sjeff } 602219820Sjeff mutex_unlock(&lock); 603219820Sjeff} 604219820SjeffEXPORT_SYMBOL(rdma_addr_cancel); 605219820Sjeff 606219820Sjeffstatic int netevent_callback(struct notifier_block *self, unsigned long event, 607219820Sjeff void *ctx) 608219820Sjeff{ 609219820Sjeff if (event == NETEVENT_NEIGH_UPDATE) { 610219820Sjeff#ifdef __linux__ 611219820Sjeff struct neighbour *neigh = ctx; 612219820Sjeff 613219820Sjeff if (neigh->nud_state & NUD_VALID) { 614219820Sjeff set_timeout(jiffies); 615219820Sjeff } 616219820Sjeff#else 617219820Sjeff set_timeout(jiffies); 618219820Sjeff#endif 619219820Sjeff } 620219820Sjeff return 0; 621219820Sjeff} 622219820Sjeff 623219820Sjeffstatic struct notifier_block nb = { 624219820Sjeff .notifier_call = netevent_callback 625219820Sjeff}; 626219820Sjeff 627219820Sjeffstatic int addr_init(void) 628219820Sjeff{ 629219820Sjeff INIT_DELAYED_WORK(&work, process_req); 630219820Sjeff addr_wq = create_singlethread_workqueue("ib_addr"); 631219820Sjeff if (!addr_wq) 632219820Sjeff return -ENOMEM; 633219820Sjeff 634219820Sjeff register_netevent_notifier(&nb); 635219820Sjeff return 0; 636219820Sjeff} 637219820Sjeff 638219820Sjeffstatic void addr_cleanup(void) 639219820Sjeff{ 640219820Sjeff unregister_netevent_notifier(&nb); 641219820Sjeff destroy_workqueue(addr_wq); 642219820Sjeff} 643219820Sjeff 644219820Sjeffmodule_init(addr_init); 645219820Sjeffmodule_exit(addr_cleanup); 646