1178784Skmacy/*
2178784Skmacy * Copyright (c) 2005 Voltaire Inc.  All rights reserved.
3178784Skmacy * Copyright (c) 2002-2005, Network Appliance, Inc. All rights reserved.
4178784Skmacy * Copyright (c) 1999-2005, Mellanox Technologies, Inc. All rights reserved.
5178784Skmacy * Copyright (c) 2005 Intel Corporation.  All rights reserved.
6178784Skmacy *
7178784Skmacy * This Software is licensed under one of the following licenses:
8178784Skmacy *
9178784Skmacy * 1) under the terms of the "Common Public License 1.0" a copy of which is
10178784Skmacy *    available from the Open Source Initiative, see
11178784Skmacy *    http://www.opensource.org/licenses/cpl.php.
12178784Skmacy *
13178784Skmacy * 2) under the terms of the "The BSD License" a copy of which is
14178784Skmacy *    available from the Open Source Initiative, see
15178784Skmacy *    http://www.opensource.org/licenses/bsd-license.php.
16178784Skmacy *
17178784Skmacy * 3) under the terms of the "GNU General Public License (GPL) Version 2" a
18178784Skmacy *    copy of which is available from the Open Source Initiative, see
19178784Skmacy *    http://www.opensource.org/licenses/gpl-license.php.
20178784Skmacy *
21178784Skmacy * Licensee has the right to choose one of the above licenses.
22178784Skmacy *
23178784Skmacy * Redistributions of source code must retain the above copyright
24178784Skmacy * notice and one of the license notices.
25178784Skmacy *
26178784Skmacy * Redistributions in binary form must reproduce both the above copyright
27178784Skmacy * notice, one of the license notices in the documentation
28178784Skmacy * and/or other materials provided with the distribution.
29178784Skmacy *
30178784Skmacy */
31178784Skmacy
32178784Skmacy#include <sys/cdefs.h>
33178784Skmacy__FBSDID("$FreeBSD$");
34178784Skmacy
35178784Skmacy#include <sys/param.h>
36178784Skmacy#include <sys/condvar.h>
37178784Skmacy#include <sys/systm.h>
38178784Skmacy#include <sys/kernel.h>
39178784Skmacy#include <sys/socket.h>
40178784Skmacy#include <sys/module.h>
41178784Skmacy
42178784Skmacy#include <sys/lock.h>
43178784Skmacy#include <sys/condvar.h>
44178784Skmacy#include <sys/mutex.h>
45178784Skmacy#include <sys/rwlock.h>
46178784Skmacy#include <sys/queue.h>
47178784Skmacy#include <sys/taskqueue.h>
48178784Skmacy
49178784Skmacy#include <net/if.h>
50178784Skmacy#include <net/if_dl.h>
51178784Skmacy#include <net/if_var.h>
52178784Skmacy#include <net/if_arp.h>
53178784Skmacy#include <net/route.h>
54178784Skmacy
55178784Skmacy#include <net80211/ieee80211_freebsd.h>
56178784Skmacy
57178784Skmacy#include <netinet/in.h>
58178784Skmacy#include <netinet/if_ether.h>
59178784Skmacy
60178784Skmacy#include <contrib/rdma/ib_addr.h>
61178784Skmacy
62178784Skmacystruct addr_req {
63178784Skmacy	TAILQ_ENTRY(addr_req) entry;
64178784Skmacy	struct sockaddr src_addr;
65178784Skmacy	struct sockaddr dst_addr;
66178784Skmacy	struct rdma_dev_addr *addr;
67178784Skmacy	struct rdma_addr_client *client;
68178784Skmacy	void *context;
69178784Skmacy	void (*callback)(int status, struct sockaddr *src_addr,
70178784Skmacy			 struct rdma_dev_addr *addr, void *context);
71178784Skmacy	unsigned long timeout;
72178784Skmacy	int status;
73178784Skmacy};
74178784Skmacy
75178784Skmacystatic void process_req(void *ctx, int pending);
76178784Skmacy
77178784Skmacystatic struct mtx lock;
78178784Skmacy
79178784Skmacystatic TAILQ_HEAD(addr_req_list, addr_req) req_list;
80178784Skmacystatic struct task addr_task;
81178784Skmacystatic struct taskqueue *addr_taskq;
82178784Skmacystatic struct callout addr_ch;
83178784Skmacystatic eventhandler_tag route_event_tag;
84178784Skmacy
85178784Skmacystatic void addr_timeout(void *arg)
86178784Skmacy{
87178784Skmacy	taskqueue_enqueue(addr_taskq, &addr_task);
88178784Skmacy}
89178784Skmacy
90178784Skmacyvoid rdma_addr_register_client(struct rdma_addr_client *client)
91178784Skmacy{
92178784Skmacy	mtx_init(&client->lock, "rdma_addr client lock", NULL, MTX_DUPOK|MTX_DEF);
93178784Skmacy	cv_init(&client->comp, "rdma_addr cv");
94178784Skmacy	client->refcount = 1;
95178784Skmacy}
96178784Skmacy
97178784Skmacystatic inline void put_client(struct rdma_addr_client *client)
98178784Skmacy{
99178784Skmacy	mtx_lock(&client->lock);
100178784Skmacy	if (--client->refcount == 0) {
101178784Skmacy		cv_broadcast(&client->comp);
102178784Skmacy	}
103178784Skmacy	mtx_unlock(&client->lock);
104178784Skmacy}
105178784Skmacy
106178784Skmacyvoid rdma_addr_unregister_client(struct rdma_addr_client *client)
107178784Skmacy{
108178784Skmacy	put_client(client);
109178784Skmacy	mtx_lock(&client->lock);
110178784Skmacy	if (client->refcount) {
111178784Skmacy		cv_wait(&client->comp, &client->lock);
112178784Skmacy	}
113178784Skmacy	mtx_unlock(&client->lock);
114178784Skmacy}
115178784Skmacy
116178784Skmacyint rdma_copy_addr(struct rdma_dev_addr *dev_addr, struct ifnet *dev,
117178784Skmacy		     const unsigned char *dst_dev_addr)
118178784Skmacy{
119178784Skmacy	dev_addr->dev_type = RDMA_NODE_RNIC;
120252555Snp	memset(dev_addr->src_dev_addr, 0, MAX_ADDR_LEN);
121252555Snp	memcpy(dev_addr->src_dev_addr, IF_LLADDR(dev), dev->if_addrlen);
122178784Skmacy	memcpy(dev_addr->broadcast, dev->if_broadcastaddr, MAX_ADDR_LEN);
123178784Skmacy	if (dst_dev_addr)
124178784Skmacy		memcpy(dev_addr->dst_dev_addr, dst_dev_addr, MAX_ADDR_LEN);
125178784Skmacy	return 0;
126178784Skmacy}
127178784Skmacy
128178784Skmacyint rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr)
129178784Skmacy{
130178784Skmacy	struct ifaddr *ifa;
131178784Skmacy	struct sockaddr_in *sin = (struct sockaddr_in *)addr;
132178784Skmacy	uint16_t port = sin->sin_port;
133194760Srwatson	int ret;
134178784Skmacy
135178784Skmacy	sin->sin_port = 0;
136178784Skmacy	ifa = ifa_ifwithaddr(addr);
137178784Skmacy	sin->sin_port = port;
138178784Skmacy	if (!ifa)
139178784Skmacy		return (EADDRNOTAVAIL);
140194760Srwatson	ret = rdma_copy_addr(dev_addr, ifa->ifa_ifp, NULL);
141194760Srwatson	ifa_free(ifa);
142194760Srwatson	return (ret);
143178784Skmacy}
144178784Skmacy
145178784Skmacystatic void queue_req(struct addr_req *req)
146178784Skmacy{
147178784Skmacy	struct addr_req *tmp_req = NULL;
148178784Skmacy
149178784Skmacy	mtx_lock(&lock);
150178784Skmacy	TAILQ_FOREACH_REVERSE(tmp_req, &req_list, addr_req_list, entry)
151178784Skmacy	    if (time_after_eq(req->timeout, tmp_req->timeout))
152178784Skmacy		    break;
153178784Skmacy
154178784Skmacy	if (tmp_req)
155178784Skmacy		TAILQ_INSERT_AFTER(&req_list, tmp_req, req, entry);
156178784Skmacy	else
157178784Skmacy		TAILQ_INSERT_TAIL(&req_list, req, entry);
158178784Skmacy
159178784Skmacy	if (TAILQ_FIRST(&req_list) == req)
160178784Skmacy		callout_reset(&addr_ch, req->timeout - ticks, addr_timeout, NULL);
161178784Skmacy	mtx_unlock(&lock);
162178784Skmacy}
163178784Skmacy
164178784Skmacy#ifdef needed
165178784Skmacystatic void addr_send_arp(struct sockaddr_in *dst_in)
166178784Skmacy{
167178784Skmacy	struct route iproute;
168178784Skmacy	struct sockaddr_in *dst = (struct sockaddr_in *)&iproute.ro_dst;
169178784Skmacy	char dmac[ETHER_ADDR_LEN];
170186119Sqingli	struct llentry *lle;
171178784Skmacy
172178784Skmacy	bzero(&iproute, sizeof iproute);
173178784Skmacy	*dst = *dst_in;
174178784Skmacy
175178784Skmacy	rtalloc(&iproute);
176178784Skmacy	if (iproute.ro_rt == NULL);
177178784Skmacy		return;
178178784Skmacy
179178784Skmacy	arpresolve(iproute.ro_rt->rt_ifp, iproute.ro_rt, NULL,
180186119Sqingli		   rt_key(iproute.ro_rt), dmac, &lle);
181178784Skmacy
182178784Skmacy	RTFREE(iproute.ro_rt);
183178784Skmacy}
184178784Skmacy#endif
185178784Skmacy
186178784Skmacystatic int addr_resolve_remote(struct sockaddr_in *src_in,
187178784Skmacy			       struct sockaddr_in *dst_in,
188178784Skmacy			       struct rdma_dev_addr *addr)
189178784Skmacy{
190178784Skmacy	int ret = 0;
191178784Skmacy	struct route iproute;
192178784Skmacy	struct sockaddr_in *dst = (struct sockaddr_in *)&iproute.ro_dst;
193178784Skmacy	char dmac[ETHER_ADDR_LEN];
194186119Sqingli	struct llentry *lle;
195178784Skmacy
196178784Skmacy	bzero(&iproute, sizeof iproute);
197178784Skmacy	*dst = *dst_in;
198178784Skmacy
199178784Skmacy	rtalloc(&iproute);
200178784Skmacy	if (iproute.ro_rt == NULL) {
201178784Skmacy		ret = EHOSTUNREACH;
202178784Skmacy		goto out;
203178784Skmacy	}
204178784Skmacy
205178784Skmacy	/* If the device does ARP internally, return 'done' */
206178784Skmacy	if (iproute.ro_rt->rt_ifp->if_flags & IFF_NOARP) {
207178784Skmacy		rdma_copy_addr(addr, iproute.ro_rt->rt_ifp, NULL);
208178784Skmacy		goto put;
209178784Skmacy	}
210178784Skmacy 	ret = arpresolve(iproute.ro_rt->rt_ifp, iproute.ro_rt, NULL,
211252555Snp		(struct sockaddr *)dst_in, dmac, &lle);
212178784Skmacy	if (ret) {
213178784Skmacy		goto put;
214178784Skmacy	}
215178784Skmacy
216178784Skmacy	if (!src_in->sin_addr.s_addr) {
217178784Skmacy		src_in->sin_len = sizeof *src_in;
218178784Skmacy		src_in->sin_family = dst_in->sin_family;
219178784Skmacy		src_in->sin_addr.s_addr = ((struct sockaddr_in *)iproute.ro_rt->rt_ifa->ifa_addr)->sin_addr.s_addr;
220178784Skmacy	}
221178784Skmacy
222178784Skmacy	ret = rdma_copy_addr(addr, iproute.ro_rt->rt_ifp, dmac);
223178784Skmacyput:
224178784Skmacy	RTFREE(iproute.ro_rt);
225178784Skmacyout:
226178784Skmacy	return ret;
227178784Skmacy}
228178784Skmacy
229178784Skmacystatic void process_req(void *ctx, int pending)
230178784Skmacy{
231178784Skmacy	struct addr_req *req, *tmp_req;
232178784Skmacy	struct sockaddr_in *src_in, *dst_in;
233178784Skmacy	TAILQ_HEAD(, addr_req) done_list;
234178784Skmacy
235178784Skmacy	TAILQ_INIT(&done_list);
236178784Skmacy
237178784Skmacy	mtx_lock(&lock);
238178784Skmacy	TAILQ_FOREACH_SAFE(req, &req_list, entry, tmp_req) {
239178784Skmacy		if (req->status == EWOULDBLOCK) {
240178784Skmacy			src_in = (struct sockaddr_in *) &req->src_addr;
241178784Skmacy			dst_in = (struct sockaddr_in *) &req->dst_addr;
242178784Skmacy			req->status = addr_resolve_remote(src_in, dst_in,
243178784Skmacy							  req->addr);
244178784Skmacy			if (req->status && time_after_eq(ticks, req->timeout))
245178784Skmacy				req->status = ETIMEDOUT;
246178784Skmacy			else if (req->status == EWOULDBLOCK)
247178784Skmacy				continue;
248178784Skmacy		}
249178784Skmacy		TAILQ_REMOVE(&req_list, req, entry);
250178784Skmacy		TAILQ_INSERT_TAIL(&done_list, req, entry);
251178784Skmacy	}
252178784Skmacy
253178784Skmacy	if (!TAILQ_EMPTY(&req_list)) {
254178784Skmacy		req = TAILQ_FIRST(&req_list);
255178784Skmacy		callout_reset(&addr_ch, req->timeout - ticks, addr_timeout,
256178784Skmacy			NULL);
257178784Skmacy	}
258178784Skmacy	mtx_unlock(&lock);
259178784Skmacy
260178784Skmacy	TAILQ_FOREACH_SAFE(req, &done_list, entry, tmp_req) {
261178784Skmacy		TAILQ_REMOVE(&done_list, req, entry);
262178784Skmacy		req->callback(req->status, &req->src_addr, req->addr,
263178784Skmacy			      req->context);
264178784Skmacy		put_client(req->client);
265178784Skmacy		free(req, M_DEVBUF);
266178784Skmacy	}
267178784Skmacy}
268178784Skmacy
269178784Skmacyint rdma_resolve_ip(struct rdma_addr_client *client,
270178784Skmacy		    struct sockaddr *src_addr, struct sockaddr *dst_addr,
271178784Skmacy		    struct rdma_dev_addr *addr, int timeout_ms,
272178784Skmacy		    void (*callback)(int status, struct sockaddr *src_addr,
273178784Skmacy				     struct rdma_dev_addr *addr, void *context),
274178784Skmacy		    void *context)
275178784Skmacy{
276178784Skmacy	struct sockaddr_in *src_in, *dst_in;
277178784Skmacy	struct addr_req *req;
278178784Skmacy	int ret = 0;
279178784Skmacy
280178784Skmacy	req = malloc(sizeof *req, M_DEVBUF, M_NOWAIT);
281178784Skmacy	if (!req)
282178784Skmacy		return (ENOMEM);
283178784Skmacy	memset(req, 0, sizeof *req);
284178784Skmacy
285178784Skmacy	if (src_addr)
286178784Skmacy		memcpy(&req->src_addr, src_addr, ip_addr_size(src_addr));
287178784Skmacy	memcpy(&req->dst_addr, dst_addr, ip_addr_size(dst_addr));
288178784Skmacy	req->addr = addr;
289178784Skmacy	req->callback = callback;
290178784Skmacy	req->context = context;
291178784Skmacy	req->client = client;
292178784Skmacy	mtx_lock(&client->lock);
293178784Skmacy	client->refcount++;
294178784Skmacy	mtx_unlock(&client->lock);
295178784Skmacy
296178784Skmacy	src_in = (struct sockaddr_in *) &req->src_addr;
297178784Skmacy	dst_in = (struct sockaddr_in *) &req->dst_addr;
298178784Skmacy
299178784Skmacy	req->status = addr_resolve_remote(src_in, dst_in, addr);
300178784Skmacy
301178784Skmacy	switch (req->status) {
302178784Skmacy	case 0:
303178784Skmacy		req->timeout = ticks;
304178784Skmacy		queue_req(req);
305178784Skmacy		break;
306178784Skmacy	case EWOULDBLOCK:
307178784Skmacy		req->timeout = msecs_to_ticks(timeout_ms) + ticks;
308178784Skmacy		queue_req(req);
309178784Skmacy#ifdef needed
310178784Skmacy		addr_send_arp(dst_in);
311178784Skmacy#endif
312178784Skmacy		break;
313178784Skmacy	default:
314178784Skmacy		ret = req->status;
315178784Skmacy		mtx_lock(&client->lock);
316178784Skmacy		client->refcount--;
317178784Skmacy		mtx_unlock(&client->lock);
318178784Skmacy		free(req, M_DEVBUF);
319178784Skmacy		break;
320178784Skmacy	}
321178784Skmacy	return ret;
322178784Skmacy}
323178784Skmacy
324178784Skmacyvoid rdma_addr_cancel(struct rdma_dev_addr *addr)
325178784Skmacy{
326178784Skmacy	struct addr_req *req, *tmp_req;
327178784Skmacy
328178784Skmacy	mtx_lock(&lock);
329178784Skmacy	TAILQ_FOREACH_SAFE(req, &req_list, entry, tmp_req) {
330178784Skmacy		if (req->addr == addr) {
331178784Skmacy			req->status = ECANCELED;
332178784Skmacy			req->timeout = ticks;
333178784Skmacy			TAILQ_REMOVE(&req_list, req, entry);
334178784Skmacy			TAILQ_INSERT_HEAD(&req_list, req, entry);
335178784Skmacy			callout_reset(&addr_ch, req->timeout - ticks, addr_timeout, NULL);
336178784Skmacy			break;
337178784Skmacy		}
338178784Skmacy	}
339178784Skmacy	mtx_unlock(&lock);
340178784Skmacy}
341178784Skmacy
342178784Skmacystatic void
343178784Skmacyroute_event_arp_update(void *unused, struct rtentry *rt0, uint8_t *enaddr,
344178784Skmacy	struct sockaddr *sa)
345178784Skmacy{
346178784Skmacy		callout_stop(&addr_ch);
347178784Skmacy		taskqueue_enqueue(addr_taskq, &addr_task);
348178784Skmacy}
349178784Skmacy
350178784Skmacystatic int addr_init(void)
351178784Skmacy{
352178784Skmacy	TAILQ_INIT(&req_list);
353178784Skmacy	mtx_init(&lock, "rdma_addr req_list lock", NULL, MTX_DEF);
354178784Skmacy
355178784Skmacy	addr_taskq = taskqueue_create("rdma_addr_taskq", M_NOWAIT,
356178784Skmacy		taskqueue_thread_enqueue, &addr_taskq);
357178784Skmacy        if (addr_taskq == NULL) {
358178784Skmacy                printf("failed to allocate rdma_addr taskqueue\n");
359178784Skmacy                return (ENOMEM);
360178784Skmacy        }
361178784Skmacy        taskqueue_start_threads(&addr_taskq, 1, PI_NET, "rdma_addr taskq");
362178784Skmacy        TASK_INIT(&addr_task, 0, process_req, NULL);
363178784Skmacy
364178784Skmacy	callout_init(&addr_ch, TRUE);
365178784Skmacy
366178784Skmacy	route_event_tag = EVENTHANDLER_REGISTER(route_arp_update_event,
367178784Skmacy		route_event_arp_update, NULL, EVENTHANDLER_PRI_ANY);
368178784Skmacy
369178784Skmacy	return 0;
370178784Skmacy}
371178784Skmacy
372178784Skmacystatic void addr_cleanup(void)
373178784Skmacy{
374178784Skmacy	EVENTHANDLER_DEREGISTER(route_event_arp_update, route_event_tag);
375178784Skmacy	callout_stop(&addr_ch);
376178784Skmacy	taskqueue_drain(addr_taskq, &addr_task);
377178784Skmacy	taskqueue_free(addr_taskq);
378178784Skmacy}
379178784Skmacy
380178784Skmacystatic int
381178784Skmacyaddr_load(module_t mod, int cmd, void *arg)
382178784Skmacy{
383178784Skmacy        int err = 0;
384178784Skmacy
385178784Skmacy        switch (cmd) {
386178784Skmacy        case MOD_LOAD:
387178784Skmacy                printf("Loading rdma_addr.\n");
388178784Skmacy
389178784Skmacy                addr_init();
390178784Skmacy                break;
391178784Skmacy        case MOD_QUIESCE:
392178784Skmacy                break;
393178784Skmacy        case MOD_UNLOAD:
394178784Skmacy                printf("Unloading rdma_addr.\n");
395178784Skmacy		addr_cleanup();
396178784Skmacy                break;
397178784Skmacy        case MOD_SHUTDOWN:
398178784Skmacy                break;
399178784Skmacy        default:
400178784Skmacy                err = EOPNOTSUPP;
401178784Skmacy                break;
402178784Skmacy        }
403178784Skmacy
404178784Skmacy        return (err);
405178784Skmacy}
406178784Skmacy
407178784Skmacystatic moduledata_t mod_data = {
408178784Skmacy	"rdma_addr",
409178784Skmacy	addr_load,
410178784Skmacy	0
411178784Skmacy};
412178784Skmacy
413178784SkmacyMODULE_VERSION(rdma_addr, 1);
414178784SkmacyDECLARE_MODULE(rdma_addr, mod_data, SI_SUB_EXEC, SI_ORDER_ANY);
415