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