xref: /haiku/src/add-ons/kernel/network/stack/routes.cpp (revision 99d027cd0238c1d86da86d7c3f4200509ccc61a6)
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 
40 net_route_private::net_route_private()
41 {
42 	destination = mask = gateway = NULL;
43 }
44 
45 
46 net_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 
57 static status_t
58 user_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 
83 static status_t
84 user_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 
103 static net_route_private*
104 find_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 
140 static net_route_private*
141 find_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 
190 static void
191 put_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 
207 static struct net_route*
208 get_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 
244 static void
245 update_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 
259 static sockaddr*
260 copy_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 
269 static status_t
270 fill_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 */
293 uint32
294 route_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 */
320 status_t
321 list_routes(net_domain_private* domain, void* buffer, size_t size)
322 {
323 	RecursiveLocker _(domain->lock);
324 
325 	RouteList::Iterator iterator = domain->routes.GetIterator();
326 	size_t spaceLeft = size;
327 
328 	sockaddr zeros;
329 	memset(&zeros, 0, sizeof(sockaddr));
330 	zeros.sa_family = domain->family;
331 	zeros.sa_len = sizeof(sockaddr);
332 
333 	while (iterator.HasNext()) {
334 		net_route* route = iterator.Next();
335 
336 		size = IF_NAMESIZE + sizeof(route_entry);
337 
338 		sockaddr* destination = NULL;
339 		sockaddr* mask = NULL;
340 		sockaddr* gateway = NULL;
341 		uint8* next = (uint8*)buffer + size;
342 
343 		if (route->destination != NULL) {
344 			destination = (sockaddr*)next;
345 			next += route->destination->sa_len;
346 			size += route->destination->sa_len;
347 		}
348 		if (route->mask != NULL) {
349 			mask = (sockaddr*)next;
350 			next += route->mask->sa_len;
351 			size += route->mask->sa_len;
352 		}
353 		if (route->gateway != NULL) {
354 			gateway = (sockaddr*)next;
355 			next += route->gateway->sa_len;
356 			size += route->gateway->sa_len;
357 		}
358 
359 		if (spaceLeft < size)
360 			return ENOBUFS;
361 
362 		ifreq request;
363 		strlcpy(request.ifr_name, route->interface_address->interface->name,
364 			IF_NAMESIZE);
365 		request.ifr_route.destination = destination;
366 		request.ifr_route.mask = mask;
367 		request.ifr_route.gateway = gateway;
368 		request.ifr_route.mtu = route->mtu;
369 		request.ifr_route.flags = route->flags;
370 
371 		// copy data into userland buffer
372 		if (user_memcpy(buffer, &request, size) < B_OK
373 			|| (route->destination != NULL
374 				&& user_memcpy(request.ifr_route.destination,
375 					route->destination, route->destination->sa_len) < B_OK)
376 			|| (route->mask != NULL && user_memcpy(request.ifr_route.mask,
377 					route->mask, route->mask->sa_len) < B_OK)
378 			|| (route->gateway != NULL && user_memcpy(request.ifr_route.gateway,
379 					route->gateway, route->gateway->sa_len) < B_OK))
380 			return B_BAD_ADDRESS;
381 
382 		buffer = (void*)next;
383 		spaceLeft -= size;
384 	}
385 
386 	return B_OK;
387 }
388 
389 
390 status_t
391 control_routes(struct net_interface* _interface, net_domain* domain,
392 	int32 option, void* argument, size_t length)
393 {
394 	TRACE("control_routes(interface %p, domain %p, option %" B_PRId32 ")\n",
395 		_interface, domain, option);
396 	Interface* interface = (Interface*)_interface;
397 
398 	switch (option) {
399 		case SIOCADDRT:
400 		case SIOCDELRT:
401 		{
402 			// add or remove a route
403 			if (length != sizeof(struct ifreq))
404 				return B_BAD_VALUE;
405 
406 			route_entry entry;
407 			if (user_memcpy(&entry, &((ifreq*)argument)->ifr_route,
408 					sizeof(route_entry)) != B_OK)
409 				return B_BAD_ADDRESS;
410 
411 			net_route_private route;
412 			status_t status;
413 			if ((status = user_copy_address(entry.destination,
414 					&route.destination)) != B_OK
415 				|| (status = user_copy_address(entry.mask, &route.mask)) != B_OK
416 				|| (status = user_copy_address(entry.gateway, &route.gateway))
417 					!= B_OK)
418 				return status;
419 
420 			InterfaceAddress* address
421 				= interface->FirstForFamily(domain->family);
422 
423 			route.mtu = entry.mtu;
424 			route.flags = entry.flags;
425 			route.interface_address = address;
426 
427 			if (option == SIOCADDRT)
428 				status = add_route(domain, &route);
429 			else
430 				status = remove_route(domain, &route);
431 
432 			if (address != NULL)
433 				address->ReleaseReference();
434 			return status;
435 		}
436 	}
437 	return B_BAD_VALUE;
438 }
439 
440 
441 status_t
442 add_route(struct net_domain* _domain, const struct net_route* newRoute)
443 {
444 	struct net_domain_private* domain = (net_domain_private*)_domain;
445 
446 	TRACE("add route to domain %s: dest %s, mask %s, gw %s, flags %lx\n",
447 		domain->name,
448 		AddressString(domain, newRoute->destination
449 			? newRoute->destination : NULL).Data(),
450 		AddressString(domain, newRoute->mask ? newRoute->mask : NULL).Data(),
451 		AddressString(domain, newRoute->gateway
452 			? newRoute->gateway : NULL).Data(),
453 		newRoute->flags);
454 
455 	if (domain == NULL || newRoute == NULL
456 		|| newRoute->interface_address == NULL
457 		|| ((newRoute->flags & RTF_HOST) != 0 && newRoute->mask != NULL)
458 		|| ((newRoute->flags & RTF_DEFAULT) == 0
459 			&& newRoute->destination == NULL)
460 		|| ((newRoute->flags & RTF_GATEWAY) != 0 && newRoute->gateway == NULL)
461 		|| !domain->address_module->check_mask(newRoute->mask))
462 		return B_BAD_VALUE;
463 
464 	RecursiveLocker _(domain->lock);
465 
466 	net_route_private* route = find_route(domain, newRoute);
467 	if (route != NULL)
468 		return B_FILE_EXISTS;
469 
470 	route = new (std::nothrow) net_route_private;
471 	if (route == NULL)
472 		return B_NO_MEMORY;
473 
474 	if (domain->address_module->copy_address(newRoute->destination,
475 			&route->destination, (newRoute->flags & RTF_DEFAULT) != 0,
476 			newRoute->mask) != B_OK
477 		|| domain->address_module->copy_address(newRoute->mask, &route->mask,
478 			(newRoute->flags & RTF_DEFAULT) != 0, NULL) != B_OK
479 		|| domain->address_module->copy_address(newRoute->gateway,
480 			&route->gateway, false, NULL) != B_OK) {
481 		delete route;
482 		return B_NO_MEMORY;
483 	}
484 
485 	route->flags = newRoute->flags;
486 	route->interface_address = newRoute->interface_address;
487 	((InterfaceAddress*)route->interface_address)->AcquireReference();
488 	route->mtu = 0;
489 	route->ref_count = 1;
490 
491 	// Insert the route sorted by completeness of its mask
492 
493 	RouteList::Iterator iterator = domain->routes.GetIterator();
494 	net_route_private* before = NULL;
495 
496 	while ((before = iterator.Next()) != NULL) {
497 		// if the before mask is less specific than the one of the route,
498 		// we can insert it before that route.
499 		if (domain->address_module->first_mask_bit(before->mask)
500 				> domain->address_module->first_mask_bit(route->mask))
501 			break;
502 
503 		if ((route->flags & RTF_DEFAULT) != 0
504 			&& (before->flags & RTF_DEFAULT) != 0) {
505 			// both routes are equal - let the link speed decide the
506 			// order
507 			if (before->interface_address->interface->device->link_speed
508 					< route->interface_address->interface->device->link_speed)
509 				break;
510 		}
511 	}
512 
513 	domain->routes.Insert(before, route);
514 	update_route_infos(domain);
515 
516 	return B_OK;
517 }
518 
519 
520 status_t
521 remove_route(struct net_domain* _domain, const struct net_route* removeRoute)
522 {
523 	struct net_domain_private* domain = (net_domain_private*)_domain;
524 
525 	TRACE("remove route from domain %s: dest %s, mask %s, gw %s, flags %lx\n",
526 		domain->name,
527 		AddressString(domain, removeRoute->destination
528 			? removeRoute->destination : NULL).Data(),
529 		AddressString(domain, removeRoute->mask
530 			? removeRoute->mask : NULL).Data(),
531 		AddressString(domain, removeRoute->gateway
532 			? removeRoute->gateway : NULL).Data(),
533 		removeRoute->flags);
534 
535 	RecursiveLocker locker(domain->lock);
536 
537 	net_route_private* route = find_route(domain, removeRoute);
538 	if (route == NULL)
539 		return B_ENTRY_NOT_FOUND;
540 
541 	domain->routes.Remove(route);
542 
543 	put_route_internal(domain, route);
544 	update_route_infos(domain);
545 
546 	return B_OK;
547 }
548 
549 
550 status_t
551 get_route_information(struct net_domain* _domain, void* value, size_t length)
552 {
553 	struct net_domain_private* domain = (net_domain_private*)_domain;
554 
555 	if (length < sizeof(route_entry))
556 		return B_BAD_VALUE;
557 
558 	route_entry entry;
559 	if (user_memcpy(&entry, value, sizeof(route_entry)) < B_OK)
560 		return B_BAD_ADDRESS;
561 
562 	sockaddr_storage destination;
563 	status_t status = user_copy_address(entry.destination, &destination);
564 	if (status != B_OK)
565 		return status;
566 
567 	RecursiveLocker locker(domain->lock);
568 
569 	net_route_private* route = find_route(domain, (sockaddr*)&destination);
570 	if (route == NULL)
571 		return B_ENTRY_NOT_FOUND;
572 
573 	status = fill_route_entry(&entry, value, length, route);
574 	if (status != B_OK)
575 		return status;
576 
577 	return user_memcpy(value, &entry, sizeof(route_entry));
578 }
579 
580 
581 void
582 invalidate_routes(net_domain* _domain, net_interface* interface)
583 {
584 	net_domain_private* domain = (net_domain_private*)_domain;
585 	RecursiveLocker locker(domain->lock);
586 
587 	TRACE("invalidate_routes(%i, %s)\n", domain->family, interface->name);
588 
589 	RouteList::Iterator iterator = domain->routes.GetIterator();
590 	while (iterator.HasNext()) {
591 		net_route* route = iterator.Next();
592 
593 		if (route->interface_address->interface == interface)
594 			remove_route(domain, route);
595 	}
596 }
597 
598 
599 void
600 invalidate_routes(InterfaceAddress* address)
601 {
602 	net_domain_private* domain = (net_domain_private*)address->domain;
603 
604 	TRACE("invalidate_routes(%s)\n",
605 		AddressString(domain, address->local).Data());
606 
607 	RecursiveLocker locker(domain->lock);
608 
609 	RouteList::Iterator iterator = domain->routes.GetIterator();
610 	while (iterator.HasNext()) {
611 		net_route* route = iterator.Next();
612 
613 		if (route->interface_address == address)
614 			remove_route(domain, route);
615 	}
616 }
617 
618 
619 struct net_route*
620 get_route(struct net_domain* _domain, const struct sockaddr* address)
621 {
622 	struct net_domain_private* domain = (net_domain_private*)_domain;
623 	RecursiveLocker locker(domain->lock);
624 
625 	return get_route_internal(domain, address);
626 }
627 
628 
629 status_t
630 get_device_route(struct net_domain* domain, uint32 index, net_route** _route)
631 {
632 	Interface* interface = get_interface_for_device(domain, index);
633 	if (interface == NULL)
634 		return ENETUNREACH;
635 
636 	net_route_private* route
637 		= &interface->DomainDatalink(domain->family)->direct_route;
638 
639 	atomic_add(&route->ref_count, 1);
640 	*_route = route;
641 
642 	interface->ReleaseReference();
643 	return B_OK;
644 }
645 
646 
647 status_t
648 get_buffer_route(net_domain* _domain, net_buffer* buffer, net_route** _route)
649 {
650 	net_domain_private* domain = (net_domain_private*)_domain;
651 
652 	RecursiveLocker _(domain->lock);
653 
654 	net_route* route = get_route_internal(domain, buffer->destination);
655 	if (route == NULL)
656 		return ENETUNREACH;
657 
658 	status_t status = B_OK;
659 	sockaddr* source = buffer->source;
660 
661 	// TODO: we are quite relaxed in the address checking here
662 	// as we might proceed with source = INADDR_ANY.
663 
664 	if (route->interface_address != NULL
665 		&& route->interface_address->local != NULL) {
666 		status = domain->address_module->update_to(source,
667 			route->interface_address->local);
668 	}
669 
670 	if (status != B_OK)
671 		put_route_internal(domain, route);
672 	else
673 		*_route = route;
674 
675 	return status;
676 }
677 
678 
679 void
680 put_route(struct net_domain* _domain, net_route* route)
681 {
682 	struct net_domain_private* domain = (net_domain_private*)_domain;
683 	if (domain == NULL || route == NULL)
684 		return;
685 
686 	RecursiveLocker locker(domain->lock);
687 
688 	put_route_internal(domain, (net_route*)route);
689 }
690 
691 
692 status_t
693 register_route_info(struct net_domain* _domain, struct net_route_info* info)
694 {
695 	struct net_domain_private* domain = (net_domain_private*)_domain;
696 	RecursiveLocker locker(domain->lock);
697 
698 	domain->route_infos.Add(info);
699 	info->route = get_route_internal(domain, &info->address);
700 
701 	return B_OK;
702 }
703 
704 
705 status_t
706 unregister_route_info(struct net_domain* _domain, struct net_route_info* info)
707 {
708 	struct net_domain_private* domain = (net_domain_private*)_domain;
709 	RecursiveLocker locker(domain->lock);
710 
711 	domain->route_infos.Remove(info);
712 	if (info->route != NULL)
713 		put_route_internal(domain, info->route);
714 
715 	return B_OK;
716 }
717 
718 
719 status_t
720 update_route_info(struct net_domain* _domain, struct net_route_info* info)
721 {
722 	struct net_domain_private* domain = (net_domain_private*)_domain;
723 	RecursiveLocker locker(domain->lock);
724 
725 	put_route_internal(domain, info->route);
726 	info->route = get_route_internal(domain, &info->address);
727 	return B_OK;
728 }
729 
730