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