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