xref: /haiku/src/add-ons/kernel/network/stack/routes.cpp (revision 26d22ee8dc5db3cea88354d0536f5dd9950b6bcf)
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 	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 
393 status_t
394 control_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 
444 status_t
445 add_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 
523 status_t
524 remove_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 
553 status_t
554 get_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 
584 void
585 invalidate_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 
602 void
603 invalidate_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 
622 struct net_route*
623 get_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 
632 status_t
633 get_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 
650 status_t
651 get_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 
682 void
683 put_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 
695 status_t
696 register_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 
708 status_t
709 unregister_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 
722 status_t
723 update_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