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