1/*
2 * Copyright 2006-2010, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Axel D��rfler, axeld@pinc-software.de
7 */
8
9
10#include "domains.h"
11#include "interfaces.h"
12#include "routes.h"
13#include "stack_private.h"
14#include "utility.h"
15
16#include <net_device.h>
17#include <NetUtilities.h>
18
19#include <lock.h>
20#include <util/AutoLock.h>
21
22#include <KernelExport.h>
23
24#include <net/if_dl.h>
25#include <net/route.h>
26#include <new>
27#include <stdlib.h>
28#include <string.h>
29#include <sys/sockio.h>
30
31
32//#define TRACE_ROUTES
33#ifdef TRACE_ROUTES
34#	define TRACE(x...) dprintf(STACK_DEBUG_PREFIX x)
35#else
36#	define TRACE(x...) ;
37#endif
38
39
40net_route_private::net_route_private()
41{
42	destination = mask = gateway = NULL;
43}
44
45
46net_route_private::~net_route_private()
47{
48	free(destination);
49	free(mask);
50	free(gateway);
51}
52
53
54//	#pragma mark - private functions
55
56
57static status_t
58user_copy_address(const sockaddr* from, sockaddr** to)
59{
60	if (from == NULL) {
61		*to = NULL;
62		return B_OK;
63	}
64
65	sockaddr address;
66	if (user_memcpy(&address, from, sizeof(struct sockaddr)) < B_OK)
67		return B_BAD_ADDRESS;
68
69	*to = (sockaddr*)malloc(address.sa_len);
70	if (*to == NULL)
71		return B_NO_MEMORY;
72
73	if (address.sa_len > sizeof(struct sockaddr)) {
74		if (user_memcpy(*to, from, address.sa_len) < B_OK)
75			return B_BAD_ADDRESS;
76	} else
77		memcpy(*to, &address, address.sa_len);
78
79	return B_OK;
80}
81
82
83static status_t
84user_copy_address(const sockaddr* from, sockaddr_storage* to)
85{
86	if (from == NULL)
87		return B_BAD_ADDRESS;
88
89	if (user_memcpy(to, from, sizeof(sockaddr)) < B_OK)
90		return B_BAD_ADDRESS;
91
92	if (to->ss_len > sizeof(sockaddr)) {
93		if (to->ss_len > sizeof(sockaddr_storage))
94			return B_BAD_VALUE;
95		if (user_memcpy(to, from, to->ss_len) < B_OK)
96			return B_BAD_ADDRESS;
97	}
98
99	return B_OK;
100}
101
102
103static net_route_private*
104find_route(struct net_domain* _domain, const net_route* description)
105{
106	struct net_domain_private* domain = (net_domain_private*)_domain;
107	RouteList::Iterator iterator = domain->routes.GetIterator();
108
109	while (iterator.HasNext()) {
110		net_route_private* route = iterator.Next();
111
112		if ((route->flags & RTF_DEFAULT) != 0
113			&& (description->flags & RTF_DEFAULT) != 0) {
114			// there can only be one default route per interface address family
115			// TODO: check this better
116			if (route->interface_address == description->interface_address)
117				return route;
118
119			continue;
120		}
121
122		if ((route->flags & (RTF_GATEWAY | RTF_HOST | RTF_LOCAL | RTF_DEFAULT))
123				== (description->flags
124					& (RTF_GATEWAY | RTF_HOST | RTF_LOCAL | RTF_DEFAULT))
125			&& domain->address_module->equal_masked_addresses(
126				route->destination, description->destination, description->mask)
127			&& domain->address_module->equal_addresses(route->mask,
128				description->mask)
129			&& domain->address_module->equal_addresses(route->gateway,
130				description->gateway)
131			&& (description->interface_address == NULL
132				|| description->interface_address == route->interface_address))
133			return route;
134	}
135
136	return NULL;
137}
138
139
140static net_route_private*
141find_route(net_domain* _domain, const sockaddr* address)
142{
143	net_domain_private* domain = (net_domain_private*)_domain;
144
145	// find last matching route
146
147	RouteList::Iterator iterator = domain->routes.GetIterator();
148	net_route_private* candidate = NULL;
149
150	TRACE("test address %s for routes...\n",
151		AddressString(domain, address).Data());
152
153	// TODO: alternate equal default routes
154
155	while (iterator.HasNext()) {
156		net_route_private* route = iterator.Next();
157
158		if (route->mask) {
159			sockaddr maskedAddress;
160			domain->address_module->mask_address(address, route->mask,
161				&maskedAddress);
162			if (!domain->address_module->equal_addresses(&maskedAddress,
163					route->destination))
164				continue;
165		} else if (!domain->address_module->equal_addresses(address,
166				route->destination))
167			continue;
168
169		// neglect routes that point to devices that have no link
170		if ((route->interface_address->interface->device->flags & IFF_LINK)
171				== 0) {
172			if (candidate == NULL) {
173				TRACE("  found candidate: %s, flags %lx\n", AddressString(
174					domain, route->destination).Data(), route->flags);
175				candidate = route;
176			}
177			continue;
178		}
179
180		TRACE("  found route: %s, flags %lx\n",
181			AddressString(domain, route->destination).Data(), route->flags);
182
183		return route;
184	}
185
186	return candidate;
187}
188
189
190static void
191put_route_internal(struct net_domain_private* domain, net_route* _route)
192{
193	ASSERT_LOCKED_RECURSIVE(&domain->lock);
194
195	net_route_private* route = (net_route_private*)_route;
196	if (route == NULL || atomic_add(&route->ref_count, -1) != 1)
197		return;
198
199	// delete route - it must already have been removed at this point
200	if (route->interface_address != NULL)
201		((InterfaceAddress*)route->interface_address)->ReleaseReference();
202
203	delete route;
204}
205
206
207static struct net_route*
208get_route_internal(struct net_domain_private* domain,
209	const struct sockaddr* address)
210{
211	ASSERT_LOCKED_RECURSIVE(&domain->lock);
212	net_route_private* route = NULL;
213
214	if (address->sa_family == AF_LINK) {
215		// special address to find an interface directly
216		RouteList::Iterator iterator = domain->routes.GetIterator();
217		const sockaddr_dl* link = (const sockaddr_dl*)address;
218
219		while (iterator.HasNext()) {
220			route = iterator.Next();
221
222			net_device* device = route->interface_address->interface->device;
223
224			if ((link->sdl_nlen > 0
225					&& !strncmp(device->name, (const char*)link->sdl_data,
226							IF_NAMESIZE))
227				|| (link->sdl_nlen == 0 && link->sdl_alen > 0
228					&& !memcmp(LLADDR(link), device->address.data,
229							device->address.length)))
230				break;
231		}
232	} else
233		route = find_route(domain, address);
234
235	if (route != NULL && atomic_add(&route->ref_count, 1) == 0) {
236		// route has been deleted already
237		route = NULL;
238	}
239
240	return route;
241}
242
243
244static void
245update_route_infos(struct net_domain_private* domain)
246{
247	ASSERT_LOCKED_RECURSIVE(&domain->lock);
248	RouteInfoList::Iterator iterator = domain->route_infos.GetIterator();
249
250	while (iterator.HasNext()) {
251		net_route_info* info = iterator.Next();
252
253		put_route_internal(domain, info->route);
254		info->route = get_route_internal(domain, &info->address);
255	}
256}
257
258
259static sockaddr*
260copy_address(UserBuffer& buffer, sockaddr* address)
261{
262	if (address == NULL)
263		return NULL;
264
265	return (sockaddr*)buffer.Push(address, address->sa_len);
266}
267
268
269static status_t
270fill_route_entry(route_entry* target, void* _buffer, size_t bufferSize,
271	net_route* route)
272{
273	UserBuffer buffer(((uint8*)_buffer) + sizeof(route_entry),
274		bufferSize - sizeof(route_entry));
275
276	target->destination = copy_address(buffer, route->destination);
277	target->mask = copy_address(buffer, route->mask);
278	target->gateway = copy_address(buffer, route->gateway);
279	target->source = copy_address(buffer, route->interface_address->local);
280	target->flags = route->flags;
281	target->mtu = route->mtu;
282
283	return buffer.Status();
284}
285
286
287//	#pragma mark - exported functions
288
289
290/*!	Determines the size of a buffer large enough to contain the whole
291	routing table.
292*/
293uint32
294route_table_size(net_domain_private* domain)
295{
296	RecursiveLocker locker(domain->lock);
297	uint32 size = 0;
298
299	RouteList::Iterator iterator = domain->routes.GetIterator();
300	while (iterator.HasNext()) {
301		net_route_private* route = iterator.Next();
302		size += IF_NAMESIZE + sizeof(route_entry);
303
304		if (route->destination)
305			size += route->destination->sa_len;
306		if (route->mask)
307			size += route->mask->sa_len;
308		if (route->gateway)
309			size += route->gateway->sa_len;
310	}
311
312	return size;
313}
314
315
316/*!	Dumps a list of all routes into the supplied userland buffer.
317	If the routes don't fit into the buffer, an error (\c ENOBUFS) is
318	returned.
319*/
320status_t
321list_routes(net_domain_private* domain, void* buffer, size_t size)
322{
323	RecursiveLocker _(domain->lock);
324
325	RouteList::Iterator iterator = domain->routes.GetIterator();
326	const size_t kBaseSize = IF_NAMESIZE + sizeof(route_entry);
327	size_t spaceLeft = size;
328
329	sockaddr zeros;
330	memset(&zeros, 0, sizeof(sockaddr));
331	zeros.sa_family = domain->family;
332	zeros.sa_len = sizeof(sockaddr);
333
334	while (iterator.HasNext()) {
335		net_route* route = iterator.Next();
336
337		size = kBaseSize;
338
339		sockaddr* destination = NULL;
340		sockaddr* mask = NULL;
341		sockaddr* gateway = NULL;
342		uint8* next = (uint8*)buffer + size;
343
344		if (route->destination != NULL) {
345			destination = (sockaddr*)next;
346			next += route->destination->sa_len;
347			size += route->destination->sa_len;
348		}
349		if (route->mask != NULL) {
350			mask = (sockaddr*)next;
351			next += route->mask->sa_len;
352			size += route->mask->sa_len;
353		}
354		if (route->gateway != NULL) {
355			gateway = (sockaddr*)next;
356			next += route->gateway->sa_len;
357			size += route->gateway->sa_len;
358		}
359
360		if (spaceLeft < size)
361			return ENOBUFS;
362
363		ifreq request;
364		memset(&request, 0, sizeof(request));
365
366		strlcpy(request.ifr_name, route->interface_address->interface->name,
367			IF_NAMESIZE);
368		request.ifr_route.destination = destination;
369		request.ifr_route.mask = mask;
370		request.ifr_route.gateway = gateway;
371		request.ifr_route.mtu = route->mtu;
372		request.ifr_route.flags = route->flags;
373
374		// copy data into userland buffer
375		if (user_memcpy(buffer, &request, kBaseSize) < B_OK
376			|| (route->destination != NULL
377				&& user_memcpy(request.ifr_route.destination,
378					route->destination, route->destination->sa_len) < B_OK)
379			|| (route->mask != NULL && user_memcpy(request.ifr_route.mask,
380					route->mask, route->mask->sa_len) < B_OK)
381			|| (route->gateway != NULL && user_memcpy(request.ifr_route.gateway,
382					route->gateway, route->gateway->sa_len) < B_OK))
383			return B_BAD_ADDRESS;
384
385		buffer = (void*)next;
386		spaceLeft -= size;
387	}
388
389	return B_OK;
390}
391
392
393status_t
394control_routes(struct net_interface* _interface, net_domain* domain,
395	int32 option, void* argument, size_t length)
396{
397	TRACE("control_routes(interface %p, domain %p, option %" B_PRId32 ")\n",
398		_interface, domain, option);
399	Interface* interface = (Interface*)_interface;
400
401	switch (option) {
402		case SIOCADDRT:
403		case SIOCDELRT:
404		{
405			// add or remove a route
406			if (length != sizeof(struct ifreq))
407				return B_BAD_VALUE;
408
409			route_entry entry;
410			if (user_memcpy(&entry, &((ifreq*)argument)->ifr_route,
411					sizeof(route_entry)) != B_OK)
412				return B_BAD_ADDRESS;
413
414			net_route_private route;
415			status_t status;
416			if ((status = user_copy_address(entry.destination,
417					&route.destination)) != B_OK
418				|| (status = user_copy_address(entry.mask, &route.mask)) != B_OK
419				|| (status = user_copy_address(entry.gateway, &route.gateway))
420					!= B_OK)
421				return status;
422
423			InterfaceAddress* address
424				= interface->FirstForFamily(domain->family);
425
426			route.mtu = entry.mtu;
427			route.flags = entry.flags;
428			route.interface_address = address;
429
430			if (option == SIOCADDRT)
431				status = add_route(domain, &route);
432			else
433				status = remove_route(domain, &route);
434
435			if (address != NULL)
436				address->ReleaseReference();
437			return status;
438		}
439	}
440	return B_BAD_VALUE;
441}
442
443
444status_t
445add_route(struct net_domain* _domain, const struct net_route* newRoute)
446{
447	struct net_domain_private* domain = (net_domain_private*)_domain;
448
449	TRACE("add route to domain %s: dest %s, mask %s, gw %s, flags %lx\n",
450		domain->name,
451		AddressString(domain, newRoute->destination
452			? newRoute->destination : NULL).Data(),
453		AddressString(domain, newRoute->mask ? newRoute->mask : NULL).Data(),
454		AddressString(domain, newRoute->gateway
455			? newRoute->gateway : NULL).Data(),
456		newRoute->flags);
457
458	if (domain == NULL || newRoute == NULL
459		|| newRoute->interface_address == NULL
460		|| ((newRoute->flags & RTF_HOST) != 0 && newRoute->mask != NULL)
461		|| ((newRoute->flags & RTF_DEFAULT) == 0
462			&& newRoute->destination == NULL)
463		|| ((newRoute->flags & RTF_GATEWAY) != 0 && newRoute->gateway == NULL)
464		|| !domain->address_module->check_mask(newRoute->mask))
465		return B_BAD_VALUE;
466
467	RecursiveLocker _(domain->lock);
468
469	net_route_private* route = find_route(domain, newRoute);
470	if (route != NULL)
471		return B_FILE_EXISTS;
472
473	route = new (std::nothrow) net_route_private;
474	if (route == NULL)
475		return B_NO_MEMORY;
476
477	if (domain->address_module->copy_address(newRoute->destination,
478			&route->destination, (newRoute->flags & RTF_DEFAULT) != 0,
479			newRoute->mask) != B_OK
480		|| domain->address_module->copy_address(newRoute->mask, &route->mask,
481			(newRoute->flags & RTF_DEFAULT) != 0, NULL) != B_OK
482		|| domain->address_module->copy_address(newRoute->gateway,
483			&route->gateway, false, NULL) != B_OK) {
484		delete route;
485		return B_NO_MEMORY;
486	}
487
488	route->flags = newRoute->flags;
489	route->interface_address = newRoute->interface_address;
490	((InterfaceAddress*)route->interface_address)->AcquireReference();
491	route->mtu = 0;
492	route->ref_count = 1;
493
494	// Insert the route sorted by completeness of its mask
495
496	RouteList::Iterator iterator = domain->routes.GetIterator();
497	net_route_private* before = NULL;
498
499	while ((before = iterator.Next()) != NULL) {
500		// if the before mask is less specific than the one of the route,
501		// we can insert it before that route.
502		if (domain->address_module->first_mask_bit(before->mask)
503				> domain->address_module->first_mask_bit(route->mask))
504			break;
505
506		if ((route->flags & RTF_DEFAULT) != 0
507			&& (before->flags & RTF_DEFAULT) != 0) {
508			// both routes are equal - let the link speed decide the
509			// order
510			if (before->interface_address->interface->device->link_speed
511					< route->interface_address->interface->device->link_speed)
512				break;
513		}
514	}
515
516	domain->routes.InsertBefore(before, route);
517	update_route_infos(domain);
518
519	return B_OK;
520}
521
522
523status_t
524remove_route(struct net_domain* _domain, const struct net_route* removeRoute)
525{
526	struct net_domain_private* domain = (net_domain_private*)_domain;
527
528	TRACE("remove route from domain %s: dest %s, mask %s, gw %s, flags %lx\n",
529		domain->name,
530		AddressString(domain, removeRoute->destination
531			? removeRoute->destination : NULL).Data(),
532		AddressString(domain, removeRoute->mask
533			? removeRoute->mask : NULL).Data(),
534		AddressString(domain, removeRoute->gateway
535			? removeRoute->gateway : NULL).Data(),
536		removeRoute->flags);
537
538	RecursiveLocker locker(domain->lock);
539
540	net_route_private* route = find_route(domain, removeRoute);
541	if (route == NULL)
542		return B_ENTRY_NOT_FOUND;
543
544	domain->routes.Remove(route);
545
546	put_route_internal(domain, route);
547	update_route_infos(domain);
548
549	return B_OK;
550}
551
552
553status_t
554get_route_information(struct net_domain* _domain, void* value, size_t length)
555{
556	struct net_domain_private* domain = (net_domain_private*)_domain;
557
558	if (length < sizeof(route_entry))
559		return B_BAD_VALUE;
560
561	route_entry entry;
562	if (user_memcpy(&entry, value, sizeof(route_entry)) < B_OK)
563		return B_BAD_ADDRESS;
564
565	sockaddr_storage destination;
566	status_t status = user_copy_address(entry.destination, &destination);
567	if (status != B_OK)
568		return status;
569
570	RecursiveLocker locker(domain->lock);
571
572	net_route_private* route = find_route(domain, (sockaddr*)&destination);
573	if (route == NULL)
574		return B_ENTRY_NOT_FOUND;
575
576	status = fill_route_entry(&entry, value, length, route);
577	if (status != B_OK)
578		return status;
579
580	return user_memcpy(value, &entry, sizeof(route_entry));
581}
582
583
584void
585invalidate_routes(net_domain* _domain, net_interface* interface)
586{
587	net_domain_private* domain = (net_domain_private*)_domain;
588	RecursiveLocker locker(domain->lock);
589
590	TRACE("invalidate_routes(%i, %s)\n", domain->family, interface->name);
591
592	RouteList::Iterator iterator = domain->routes.GetIterator();
593	while (iterator.HasNext()) {
594		net_route* route = iterator.Next();
595
596		if (route->interface_address->interface == interface)
597			remove_route(domain, route);
598	}
599}
600
601
602void
603invalidate_routes(InterfaceAddress* address)
604{
605	net_domain_private* domain = (net_domain_private*)address->domain;
606
607	TRACE("invalidate_routes(%s)\n",
608		AddressString(domain, address->local).Data());
609
610	RecursiveLocker locker(domain->lock);
611
612	RouteList::Iterator iterator = domain->routes.GetIterator();
613	while (iterator.HasNext()) {
614		net_route* route = iterator.Next();
615
616		if (route->interface_address == address)
617			remove_route(domain, route);
618	}
619}
620
621
622struct net_route*
623get_route(struct net_domain* _domain, const struct sockaddr* address)
624{
625	struct net_domain_private* domain = (net_domain_private*)_domain;
626	RecursiveLocker locker(domain->lock);
627
628	return get_route_internal(domain, address);
629}
630
631
632status_t
633get_device_route(struct net_domain* domain, uint32 index, net_route** _route)
634{
635	Interface* interface = get_interface_for_device(domain, index);
636	if (interface == NULL)
637		return ENETUNREACH;
638
639	net_route_private* route
640		= &interface->DomainDatalink(domain->family)->direct_route;
641
642	atomic_add(&route->ref_count, 1);
643	*_route = route;
644
645	interface->ReleaseReference();
646	return B_OK;
647}
648
649
650status_t
651get_buffer_route(net_domain* _domain, net_buffer* buffer, net_route** _route)
652{
653	net_domain_private* domain = (net_domain_private*)_domain;
654
655	RecursiveLocker _(domain->lock);
656
657	net_route* route = get_route_internal(domain, buffer->destination);
658	if (route == NULL)
659		return ENETUNREACH;
660
661	status_t status = B_OK;
662	sockaddr* source = buffer->source;
663
664	// TODO: we are quite relaxed in the address checking here
665	// as we might proceed with source = INADDR_ANY.
666
667	if (route->interface_address != NULL
668		&& route->interface_address->local != NULL) {
669		status = domain->address_module->update_to(source,
670			route->interface_address->local);
671	}
672
673	if (status != B_OK)
674		put_route_internal(domain, route);
675	else
676		*_route = route;
677
678	return status;
679}
680
681
682void
683put_route(struct net_domain* _domain, net_route* route)
684{
685	struct net_domain_private* domain = (net_domain_private*)_domain;
686	if (domain == NULL || route == NULL)
687		return;
688
689	RecursiveLocker locker(domain->lock);
690
691	put_route_internal(domain, (net_route*)route);
692}
693
694
695status_t
696register_route_info(struct net_domain* _domain, struct net_route_info* info)
697{
698	struct net_domain_private* domain = (net_domain_private*)_domain;
699	RecursiveLocker locker(domain->lock);
700
701	domain->route_infos.Add(info);
702	info->route = get_route_internal(domain, &info->address);
703
704	return B_OK;
705}
706
707
708status_t
709unregister_route_info(struct net_domain* _domain, struct net_route_info* info)
710{
711	struct net_domain_private* domain = (net_domain_private*)_domain;
712	RecursiveLocker locker(domain->lock);
713
714	domain->route_infos.Remove(info);
715	if (info->route != NULL)
716		put_route_internal(domain, info->route);
717
718	return B_OK;
719}
720
721
722status_t
723update_route_info(struct net_domain* _domain, struct net_route_info* info)
724{
725	struct net_domain_private* domain = (net_domain_private*)_domain;
726	RecursiveLocker locker(domain->lock);
727
728	put_route_internal(domain, info->route);
729	info->route = get_route_internal(domain, &info->address);
730	return B_OK;
731}
732
733