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> 38273246Shselasky#include <linux/slab.h> 39219820Sjeff#include <linux/workqueue.h> 40273246Shselasky#include <linux/module.h> 41273246Shselasky#include <linux/notifier.h> 42219820Sjeff#include <net/route.h> 43219820Sjeff#include <net/netevent.h> 44219820Sjeff#include <rdma/ib_addr.h> 45273246Shselasky#include <netinet/if_ether.h> 46219820Sjeff 47273246Shselasky 48219820SjeffMODULE_AUTHOR("Sean Hefty"); 49219820SjeffMODULE_DESCRIPTION("IB Address Translation"); 50219820SjeffMODULE_LICENSE("Dual BSD/GPL"); 51219820Sjeff 52219820Sjeffstruct addr_req { 53219820Sjeff struct list_head list; 54219820Sjeff struct sockaddr_storage src_addr; 55219820Sjeff struct sockaddr_storage dst_addr; 56219820Sjeff struct rdma_dev_addr *addr; 57219820Sjeff struct rdma_addr_client *client; 58219820Sjeff void *context; 59219820Sjeff void (*callback)(int status, struct sockaddr *src_addr, 60219820Sjeff struct rdma_dev_addr *addr, void *context); 61219820Sjeff unsigned long timeout; 62219820Sjeff int status; 63219820Sjeff}; 64219820Sjeff 65219820Sjeffstatic void process_req(struct work_struct *work); 66219820Sjeff 67219820Sjeffstatic DEFINE_MUTEX(lock); 68219820Sjeffstatic LIST_HEAD(req_list); 69219820Sjeffstatic struct delayed_work work; 70219820Sjeffstatic struct workqueue_struct *addr_wq; 71219820Sjeff 72219820Sjeffvoid rdma_addr_register_client(struct rdma_addr_client *client) 73219820Sjeff{ 74219820Sjeff atomic_set(&client->refcount, 1); 75219820Sjeff init_completion(&client->comp); 76219820Sjeff} 77219820SjeffEXPORT_SYMBOL(rdma_addr_register_client); 78219820Sjeff 79219820Sjeffstatic inline void put_client(struct rdma_addr_client *client) 80219820Sjeff{ 81219820Sjeff if (atomic_dec_and_test(&client->refcount)) 82219820Sjeff complete(&client->comp); 83219820Sjeff} 84219820Sjeff 85219820Sjeffvoid rdma_addr_unregister_client(struct rdma_addr_client *client) 86219820Sjeff{ 87219820Sjeff put_client(client); 88219820Sjeff wait_for_completion(&client->comp); 89219820Sjeff} 90219820SjeffEXPORT_SYMBOL(rdma_addr_unregister_client); 91219820Sjeff 92219820Sjeff#ifdef __linux__ 93219820Sjeffint rdma_copy_addr(struct rdma_dev_addr *dev_addr, struct net_device *dev, 94219820Sjeff const unsigned char *dst_dev_addr) 95219820Sjeff{ 96219820Sjeff dev_addr->dev_type = dev->type; 97219820Sjeff memcpy(dev_addr->src_dev_addr, dev->dev_addr, MAX_ADDR_LEN); 98219820Sjeff memcpy(dev_addr->broadcast, dev->broadcast, MAX_ADDR_LEN); 99219820Sjeff if (dst_dev_addr) 100219820Sjeff memcpy(dev_addr->dst_dev_addr, dst_dev_addr, MAX_ADDR_LEN); 101219820Sjeff dev_addr->bound_dev_if = dev->ifindex; 102219820Sjeff return 0; 103219820Sjeff} 104219820Sjeff#else 105219820Sjeffint rdma_copy_addr(struct rdma_dev_addr *dev_addr, struct ifnet *dev, 106219820Sjeff const unsigned char *dst_dev_addr) 107219820Sjeff{ 108219820Sjeff if (dev->if_type == IFT_INFINIBAND) 109219820Sjeff dev_addr->dev_type = ARPHRD_INFINIBAND; 110219820Sjeff else if (dev->if_type == IFT_ETHER) 111219820Sjeff dev_addr->dev_type = ARPHRD_ETHER; 112219820Sjeff else 113219820Sjeff dev_addr->dev_type = 0; 114219820Sjeff memcpy(dev_addr->src_dev_addr, IF_LLADDR(dev), dev->if_addrlen); 115219820Sjeff memcpy(dev_addr->broadcast, __DECONST(char *, dev->if_broadcastaddr), 116219820Sjeff dev->if_addrlen); 117219820Sjeff if (dst_dev_addr) 118219820Sjeff memcpy(dev_addr->dst_dev_addr, dst_dev_addr, dev->if_addrlen); 119219820Sjeff dev_addr->bound_dev_if = dev->if_index; 120219820Sjeff return 0; 121219820Sjeff} 122219820Sjeff#endif 123219820SjeffEXPORT_SYMBOL(rdma_copy_addr); 124219820Sjeff 125219820Sjeffint rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr) 126219820Sjeff{ 127219820Sjeff struct net_device *dev; 128219820Sjeff int ret = -EADDRNOTAVAIL; 129219820Sjeff 130219820Sjeff if (dev_addr->bound_dev_if) { 131219820Sjeff dev = dev_get_by_index(&init_net, dev_addr->bound_dev_if); 132219820Sjeff if (!dev) 133219820Sjeff return -ENODEV; 134219820Sjeff ret = rdma_copy_addr(dev_addr, dev, NULL); 135219820Sjeff dev_put(dev); 136219820Sjeff return ret; 137219820Sjeff } 138219820Sjeff 139219820Sjeff switch (addr->sa_family) { 140234183Sjhb#ifdef INET 141219820Sjeff case AF_INET: 142219820Sjeff dev = ip_dev_find(NULL, 143219820Sjeff ((struct sockaddr_in *) addr)->sin_addr.s_addr); 144219820Sjeff 145219820Sjeff if (!dev) 146219820Sjeff return ret; 147219820Sjeff 148219820Sjeff ret = rdma_copy_addr(dev_addr, dev, NULL); 149219820Sjeff dev_put(dev); 150219820Sjeff break; 151234183Sjhb#endif 152219820Sjeff 153219820Sjeff#if defined(INET6) 154219820Sjeff case AF_INET6: 155219820Sjeff#ifdef __linux__ 156219820Sjeff read_lock(&dev_base_lock); 157219820Sjeff for_each_netdev(&init_net, dev) { 158219820Sjeff if (ipv6_chk_addr(&init_net, 159219820Sjeff &((struct sockaddr_in6 *) addr)->sin6_addr, 160219820Sjeff dev, 1)) { 161219820Sjeff ret = rdma_copy_addr(dev_addr, dev, NULL); 162219820Sjeff break; 163219820Sjeff } 164219820Sjeff } 165219820Sjeff read_unlock(&dev_base_lock); 166219820Sjeff#else 167219820Sjeff { 168219820Sjeff struct sockaddr_in6 *sin6; 169219820Sjeff struct ifaddr *ifa; 170219820Sjeff in_port_t port; 171219820Sjeff 172219820Sjeff sin6 = (struct sockaddr_in6 *)addr; 173219820Sjeff port = sin6->sin6_port; 174219820Sjeff sin6->sin6_port = 0; 175219820Sjeff ifa = ifa_ifwithaddr(addr); 176219820Sjeff sin6->sin6_port = port; 177219820Sjeff if (ifa == NULL) { 178219820Sjeff ret = -ENODEV; 179219820Sjeff break; 180219820Sjeff } 181219820Sjeff ret = rdma_copy_addr(dev_addr, ifa->ifa_ifp, NULL); 182219820Sjeff ifa_free(ifa); 183219820Sjeff break; 184219820Sjeff } 185219820Sjeff#endif 186219820Sjeff break; 187219820Sjeff#endif 188219820Sjeff } 189219820Sjeff return ret; 190219820Sjeff} 191219820SjeffEXPORT_SYMBOL(rdma_translate_ip); 192219820Sjeff 193219820Sjeffstatic void set_timeout(unsigned long time) 194219820Sjeff{ 195219820Sjeff unsigned long delay; 196219820Sjeff 197219820Sjeff delay = time - jiffies; 198219820Sjeff if ((long)delay <= 0) 199219820Sjeff delay = 1; 200219820Sjeff 201273246Shselasky mod_delayed_work(addr_wq, &work, delay); 202219820Sjeff} 203219820Sjeff 204219820Sjeffstatic void queue_req(struct addr_req *req) 205219820Sjeff{ 206219820Sjeff struct addr_req *temp_req; 207219820Sjeff 208219820Sjeff mutex_lock(&lock); 209219820Sjeff list_for_each_entry_reverse(temp_req, &req_list, list) { 210219820Sjeff if (time_after_eq(req->timeout, temp_req->timeout)) 211219820Sjeff break; 212219820Sjeff } 213219820Sjeff 214219820Sjeff list_add(&req->list, &temp_req->list); 215219820Sjeff 216219820Sjeff if (req_list.next == &req->list) 217219820Sjeff set_timeout(req->timeout); 218219820Sjeff mutex_unlock(&lock); 219219820Sjeff} 220219820Sjeff 221219820Sjeff#ifdef __linux__ 222219820Sjeffstatic int addr4_resolve(struct sockaddr_in *src_in, 223219820Sjeff struct sockaddr_in *dst_in, 224219820Sjeff struct rdma_dev_addr *addr) 225219820Sjeff{ 226219820Sjeff __be32 src_ip = src_in->sin_addr.s_addr; 227219820Sjeff __be32 dst_ip = dst_in->sin_addr.s_addr; 228219820Sjeff struct flowi fl; 229219820Sjeff struct rtable *rt; 230219820Sjeff struct neighbour *neigh; 231219820Sjeff int ret; 232219820Sjeff 233219820Sjeff memset(&fl, 0, sizeof fl); 234219820Sjeff fl.nl_u.ip4_u.daddr = dst_ip; 235219820Sjeff fl.nl_u.ip4_u.saddr = src_ip; 236219820Sjeff fl.oif = addr->bound_dev_if; 237219820Sjeff 238219820Sjeff ret = ip_route_output_key(&init_net, &rt, &fl); 239219820Sjeff if (ret) 240219820Sjeff goto out; 241219820Sjeff 242219820Sjeff src_in->sin_family = AF_INET; 243219820Sjeff src_in->sin_addr.s_addr = rt->rt_src; 244219820Sjeff 245219820Sjeff if (rt->idev->dev->flags & IFF_LOOPBACK) { 246219820Sjeff ret = rdma_translate_ip((struct sockaddr *) dst_in, addr); 247219820Sjeff if (!ret) 248219820Sjeff memcpy(addr->dst_dev_addr, addr->src_dev_addr, MAX_ADDR_LEN); 249219820Sjeff goto put; 250219820Sjeff } 251219820Sjeff 252219820Sjeff /* If the device does ARP internally, return 'done' */ 253219820Sjeff if (rt->idev->dev->flags & IFF_NOARP) { 254219820Sjeff rdma_copy_addr(addr, rt->idev->dev, NULL); 255219820Sjeff goto put; 256219820Sjeff } 257219820Sjeff 258219820Sjeff neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, rt->idev->dev); 259219820Sjeff if (!neigh || !(neigh->nud_state & NUD_VALID)) { 260219820Sjeff neigh_event_send(rt->u.dst.neighbour, NULL); 261219820Sjeff ret = -ENODATA; 262219820Sjeff if (neigh) 263219820Sjeff goto release; 264219820Sjeff goto put; 265219820Sjeff } 266219820Sjeff 267219820Sjeff ret = rdma_copy_addr(addr, neigh->dev, neigh->ha); 268219820Sjeffrelease: 269219820Sjeff neigh_release(neigh); 270219820Sjeffput: 271219820Sjeff ip_rt_put(rt); 272219820Sjeffout: 273219820Sjeff return ret; 274219820Sjeff} 275219820Sjeff 276219820Sjeff#if defined(INET6) 277219820Sjeffstatic int addr6_resolve(struct sockaddr_in6 *src_in, 278219820Sjeff struct sockaddr_in6 *dst_in, 279219820Sjeff struct rdma_dev_addr *addr) 280219820Sjeff{ 281219820Sjeff struct flowi fl; 282219820Sjeff struct neighbour *neigh; 283219820Sjeff struct dst_entry *dst; 284219820Sjeff int ret; 285219820Sjeff 286219820Sjeff memset(&fl, 0, sizeof fl); 287219820Sjeff ipv6_addr_copy(&fl.fl6_dst, &dst_in->sin6_addr); 288219820Sjeff ipv6_addr_copy(&fl.fl6_src, &src_in->sin6_addr); 289219820Sjeff fl.oif = addr->bound_dev_if; 290219820Sjeff 291219820Sjeff dst = ip6_route_output(&init_net, NULL, &fl); 292219820Sjeff if ((ret = dst->error)) 293219820Sjeff goto put; 294219820Sjeff 295219820Sjeff if (ipv6_addr_any(&fl.fl6_src)) { 296219820Sjeff ret = ipv6_dev_get_saddr(&init_net, ip6_dst_idev(dst)->dev, 297219820Sjeff &fl.fl6_dst, 0, &fl.fl6_src); 298219820Sjeff if (ret) 299219820Sjeff goto put; 300219820Sjeff 301219820Sjeff src_in->sin6_family = AF_INET6; 302219820Sjeff ipv6_addr_copy(&src_in->sin6_addr, &fl.fl6_src); 303219820Sjeff } 304219820Sjeff 305219820Sjeff if (dst->dev->flags & IFF_LOOPBACK) { 306219820Sjeff ret = rdma_translate_ip((struct sockaddr *) dst_in, addr); 307219820Sjeff if (!ret) 308219820Sjeff memcpy(addr->dst_dev_addr, addr->src_dev_addr, MAX_ADDR_LEN); 309219820Sjeff goto put; 310219820Sjeff } 311219820Sjeff 312219820Sjeff /* If the device does ARP internally, return 'done' */ 313219820Sjeff if (dst->dev->flags & IFF_NOARP) { 314219820Sjeff ret = rdma_copy_addr(addr, dst->dev, NULL); 315219820Sjeff goto put; 316219820Sjeff } 317219820Sjeff 318219820Sjeff neigh = dst->neighbour; 319219820Sjeff if (!neigh || !(neigh->nud_state & NUD_VALID)) { 320219820Sjeff neigh_event_send(dst->neighbour, NULL); 321219820Sjeff ret = -ENODATA; 322219820Sjeff goto put; 323219820Sjeff } 324219820Sjeff 325219820Sjeff ret = rdma_copy_addr(addr, dst->dev, neigh->ha); 326219820Sjeffput: 327219820Sjeff dst_release(dst); 328219820Sjeff return ret; 329219820Sjeff} 330219820Sjeff#else 331219820Sjeffstatic int addr6_resolve(struct sockaddr_in6 *src_in, 332219820Sjeff struct sockaddr_in6 *dst_in, 333219820Sjeff struct rdma_dev_addr *addr) 334219820Sjeff{ 335219820Sjeff return -EADDRNOTAVAIL; 336219820Sjeff} 337219820Sjeff#endif 338219820Sjeff 339219820Sjeff#else 340219820Sjeff#include <netinet/if_ether.h> 341219820Sjeff 342219820Sjeffstatic int addr_resolve(struct sockaddr *src_in, 343219820Sjeff struct sockaddr *dst_in, 344219820Sjeff struct rdma_dev_addr *addr) 345219820Sjeff{ 346219820Sjeff struct sockaddr_in *sin; 347219820Sjeff struct sockaddr_in6 *sin6; 348219820Sjeff struct ifaddr *ifa; 349219820Sjeff struct ifnet *ifp; 350234183Sjhb#if defined(INET) || defined(INET6) 351219820Sjeff struct llentry *lle; 352234183Sjhb#endif 353219820Sjeff struct rtentry *rte; 354219820Sjeff in_port_t port; 355219820Sjeff u_char edst[MAX_ADDR_LEN]; 356219820Sjeff int multi; 357219820Sjeff int bcast; 358255932Salfred int error = 0; 359219820Sjeff 360219820Sjeff /* 361219820Sjeff * Determine whether the address is unicast, multicast, or broadcast 362219820Sjeff * and whether the source interface is valid. 363219820Sjeff */ 364219820Sjeff multi = 0; 365219820Sjeff bcast = 0; 366219820Sjeff sin = NULL; 367219820Sjeff sin6 = NULL; 368219820Sjeff ifp = NULL; 369219820Sjeff rte = NULL; 370219820Sjeff switch (dst_in->sa_family) { 371234183Sjhb#ifdef INET 372219820Sjeff case AF_INET: 373219820Sjeff sin = (struct sockaddr_in *)dst_in; 374219820Sjeff if (sin->sin_addr.s_addr == INADDR_BROADCAST) 375219820Sjeff bcast = 1; 376219820Sjeff if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) 377219820Sjeff multi = 1; 378219820Sjeff sin = (struct sockaddr_in *)src_in; 379219820Sjeff if (sin->sin_addr.s_addr != INADDR_ANY) { 380219820Sjeff /* 381219820Sjeff * Address comparison fails if the port is set 382219820Sjeff * cache it here to be restored later. 383219820Sjeff */ 384219820Sjeff port = sin->sin_port; 385219820Sjeff sin->sin_port = 0; 386219820Sjeff memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); 387219820Sjeff } else 388219820Sjeff src_in = NULL; 389219820Sjeff break; 390234183Sjhb#endif 391219820Sjeff#ifdef INET6 392219820Sjeff case AF_INET6: 393219820Sjeff sin6 = (struct sockaddr_in6 *)dst_in; 394219820Sjeff if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 395219820Sjeff multi = 1; 396219820Sjeff sin6 = (struct sockaddr_in6 *)src_in; 397219820Sjeff if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 398219820Sjeff port = sin6->sin6_port; 399219820Sjeff sin6->sin6_port = 0; 400219820Sjeff } else 401219820Sjeff src_in = NULL; 402219820Sjeff break; 403219820Sjeff#endif 404219820Sjeff default: 405219820Sjeff return -EINVAL; 406219820Sjeff } 407219820Sjeff /* 408219820Sjeff * If we have a source address to use look it up first and verify 409219820Sjeff * that it is a local interface. 410219820Sjeff */ 411219820Sjeff if (src_in) { 412219820Sjeff ifa = ifa_ifwithaddr(src_in); 413219820Sjeff if (sin) 414219820Sjeff sin->sin_port = port; 415219820Sjeff if (sin6) 416219820Sjeff sin6->sin6_port = port; 417219820Sjeff if (ifa == NULL) 418219820Sjeff return -ENETUNREACH; 419219820Sjeff ifp = ifa->ifa_ifp; 420219820Sjeff ifa_free(ifa); 421219820Sjeff if (bcast || multi) 422219820Sjeff goto mcast; 423219820Sjeff } 424219820Sjeff /* 425219820Sjeff * Make sure the route exists and has a valid link. 426219820Sjeff */ 427219820Sjeff rte = rtalloc1(dst_in, 1, 0); 428219820Sjeff if (rte == NULL || rte->rt_ifp == NULL || !RT_LINK_IS_UP(rte->rt_ifp)) { 429219820Sjeff if (rte) 430219820Sjeff RTFREE_LOCKED(rte); 431219820Sjeff return -EHOSTUNREACH; 432219820Sjeff } 433219820Sjeff /* 434219820Sjeff * If it's not multicast or broadcast and the route doesn't match the 435219820Sjeff * requested interface return unreachable. Otherwise fetch the 436219820Sjeff * correct interface pointer and unlock the route. 437219820Sjeff */ 438219820Sjeff if (multi || bcast) { 439219820Sjeff if (ifp == NULL) 440219820Sjeff ifp = rte->rt_ifp; 441219820Sjeff RTFREE_LOCKED(rte); 442219820Sjeff } else if (ifp && ifp != rte->rt_ifp) { 443219820Sjeff RTFREE_LOCKED(rte); 444219820Sjeff return -ENETUNREACH; 445219820Sjeff } else { 446219820Sjeff if (ifp == NULL) 447219820Sjeff ifp = rte->rt_ifp; 448219820Sjeff RT_UNLOCK(rte); 449219820Sjeff } 450219820Sjeffmcast: 451219820Sjeff if (bcast) 452219820Sjeff return rdma_copy_addr(addr, ifp, ifp->if_broadcastaddr); 453219820Sjeff if (multi) { 454219820Sjeff struct sockaddr *llsa; 455219820Sjeff 456219820Sjeff error = ifp->if_resolvemulti(ifp, &llsa, dst_in); 457219820Sjeff if (error) 458219820Sjeff return -error; 459219820Sjeff error = rdma_copy_addr(addr, ifp, 460219820Sjeff LLADDR((struct sockaddr_dl *)llsa)); 461219820Sjeff free(llsa, M_IFMADDR); 462219820Sjeff return error; 463219820Sjeff } 464219820Sjeff /* 465219820Sjeff * Resolve the link local address. 466219820Sjeff */ 467234183Sjhb switch (dst_in->sa_family) { 468234183Sjhb#ifdef INET 469234183Sjhb case AF_INET: 470234183Sjhb error = arpresolve(ifp, rte, NULL, dst_in, edst, &lle); 471234183Sjhb break; 472234183Sjhb#endif 473219820Sjeff#ifdef INET6 474234183Sjhb case AF_INET6: 475233040Sjhb error = nd6_storelladdr(ifp, NULL, dst_in, (u_char *)edst, &lle); 476234183Sjhb break; 477219820Sjeff#endif 478234183Sjhb default: 479234183Sjhb /* XXX: Shouldn't happen. */ 480234183Sjhb error = -EINVAL; 481234183Sjhb } 482219820Sjeff RTFREE(rte); 483219820Sjeff if (error == 0) 484219820Sjeff return rdma_copy_addr(addr, ifp, edst); 485219820Sjeff if (error == EWOULDBLOCK) 486219820Sjeff return -ENODATA; 487219820Sjeff return -error; 488219820Sjeff} 489219820Sjeff 490219820Sjeff#endif 491219820Sjeff 492219820Sjeffstatic void process_req(struct work_struct *work) 493219820Sjeff{ 494219820Sjeff struct addr_req *req, *temp_req; 495219820Sjeff struct sockaddr *src_in, *dst_in; 496219820Sjeff struct list_head done_list; 497219820Sjeff 498219820Sjeff INIT_LIST_HEAD(&done_list); 499219820Sjeff 500219820Sjeff mutex_lock(&lock); 501219820Sjeff list_for_each_entry_safe(req, temp_req, &req_list, list) { 502219820Sjeff if (req->status == -ENODATA) { 503219820Sjeff src_in = (struct sockaddr *) &req->src_addr; 504219820Sjeff dst_in = (struct sockaddr *) &req->dst_addr; 505219820Sjeff req->status = addr_resolve(src_in, dst_in, req->addr); 506219820Sjeff if (req->status && time_after_eq(jiffies, req->timeout)) 507219820Sjeff req->status = -ETIMEDOUT; 508219820Sjeff else if (req->status == -ENODATA) 509219820Sjeff continue; 510219820Sjeff } 511219820Sjeff list_move_tail(&req->list, &done_list); 512219820Sjeff } 513219820Sjeff 514219820Sjeff if (!list_empty(&req_list)) { 515219820Sjeff req = list_entry(req_list.next, struct addr_req, list); 516219820Sjeff set_timeout(req->timeout); 517219820Sjeff } 518219820Sjeff mutex_unlock(&lock); 519219820Sjeff 520219820Sjeff list_for_each_entry_safe(req, temp_req, &done_list, list) { 521219820Sjeff list_del(&req->list); 522219820Sjeff req->callback(req->status, (struct sockaddr *) &req->src_addr, 523219820Sjeff req->addr, req->context); 524219820Sjeff put_client(req->client); 525219820Sjeff kfree(req); 526219820Sjeff } 527219820Sjeff} 528219820Sjeff 529219820Sjeffint rdma_resolve_ip(struct rdma_addr_client *client, 530219820Sjeff struct sockaddr *src_addr, struct sockaddr *dst_addr, 531219820Sjeff struct rdma_dev_addr *addr, int timeout_ms, 532219820Sjeff void (*callback)(int status, struct sockaddr *src_addr, 533219820Sjeff struct rdma_dev_addr *addr, void *context), 534219820Sjeff void *context) 535219820Sjeff{ 536219820Sjeff struct sockaddr *src_in, *dst_in; 537219820Sjeff struct addr_req *req; 538219820Sjeff int ret = 0; 539219820Sjeff 540219820Sjeff req = kzalloc(sizeof *req, GFP_KERNEL); 541219820Sjeff if (!req) 542219820Sjeff return -ENOMEM; 543219820Sjeff 544219820Sjeff src_in = (struct sockaddr *) &req->src_addr; 545219820Sjeff dst_in = (struct sockaddr *) &req->dst_addr; 546219820Sjeff 547219820Sjeff if (src_addr) { 548219820Sjeff if (src_addr->sa_family != dst_addr->sa_family) { 549219820Sjeff ret = -EINVAL; 550219820Sjeff goto err; 551219820Sjeff } 552219820Sjeff 553219820Sjeff memcpy(src_in, src_addr, ip_addr_size(src_addr)); 554219820Sjeff } else { 555219820Sjeff src_in->sa_family = dst_addr->sa_family; 556219820Sjeff } 557219820Sjeff 558219820Sjeff memcpy(dst_in, dst_addr, ip_addr_size(dst_addr)); 559219820Sjeff req->addr = addr; 560219820Sjeff req->callback = callback; 561219820Sjeff req->context = context; 562219820Sjeff req->client = client; 563219820Sjeff atomic_inc(&client->refcount); 564219820Sjeff 565219820Sjeff req->status = addr_resolve(src_in, dst_in, addr); 566219820Sjeff switch (req->status) { 567219820Sjeff case 0: 568219820Sjeff req->timeout = jiffies; 569219820Sjeff queue_req(req); 570219820Sjeff break; 571219820Sjeff case -ENODATA: 572219820Sjeff req->timeout = msecs_to_jiffies(timeout_ms) + jiffies; 573219820Sjeff queue_req(req); 574219820Sjeff break; 575219820Sjeff default: 576219820Sjeff ret = req->status; 577219820Sjeff atomic_dec(&client->refcount); 578219820Sjeff goto err; 579219820Sjeff } 580219820Sjeff return ret; 581219820Sjefferr: 582219820Sjeff kfree(req); 583219820Sjeff return ret; 584219820Sjeff} 585219820SjeffEXPORT_SYMBOL(rdma_resolve_ip); 586219820Sjeff 587219820Sjeffvoid rdma_addr_cancel(struct rdma_dev_addr *addr) 588219820Sjeff{ 589219820Sjeff struct addr_req *req, *temp_req; 590219820Sjeff 591219820Sjeff mutex_lock(&lock); 592219820Sjeff list_for_each_entry_safe(req, temp_req, &req_list, list) { 593219820Sjeff if (req->addr == addr) { 594219820Sjeff req->status = -ECANCELED; 595219820Sjeff req->timeout = jiffies; 596219820Sjeff list_move(&req->list, &req_list); 597219820Sjeff set_timeout(req->timeout); 598219820Sjeff break; 599219820Sjeff } 600219820Sjeff } 601219820Sjeff mutex_unlock(&lock); 602219820Sjeff} 603219820SjeffEXPORT_SYMBOL(rdma_addr_cancel); 604219820Sjeff 605219820Sjeffstatic int netevent_callback(struct notifier_block *self, unsigned long event, 606219820Sjeff void *ctx) 607219820Sjeff{ 608219820Sjeff if (event == NETEVENT_NEIGH_UPDATE) { 609219820Sjeff#ifdef __linux__ 610219820Sjeff struct neighbour *neigh = ctx; 611219820Sjeff 612219820Sjeff if (neigh->nud_state & NUD_VALID) { 613219820Sjeff set_timeout(jiffies); 614219820Sjeff } 615219820Sjeff#else 616219820Sjeff set_timeout(jiffies); 617219820Sjeff#endif 618219820Sjeff } 619219820Sjeff return 0; 620219820Sjeff} 621219820Sjeff 622219820Sjeffstatic struct notifier_block nb = { 623219820Sjeff .notifier_call = netevent_callback 624219820Sjeff}; 625219820Sjeff 626273246Shselaskystatic int __init addr_init(void) 627219820Sjeff{ 628219820Sjeff INIT_DELAYED_WORK(&work, process_req); 629219820Sjeff addr_wq = create_singlethread_workqueue("ib_addr"); 630219820Sjeff if (!addr_wq) 631219820Sjeff return -ENOMEM; 632219820Sjeff 633219820Sjeff register_netevent_notifier(&nb); 634219820Sjeff return 0; 635219820Sjeff} 636219820Sjeff 637273246Shselaskystatic void __exit addr_cleanup(void) 638219820Sjeff{ 639219820Sjeff unregister_netevent_notifier(&nb); 640219820Sjeff destroy_workqueue(addr_wq); 641219820Sjeff} 642219820Sjeff 643219820Sjeffmodule_init(addr_init); 644219820Sjeffmodule_exit(addr_cleanup); 645