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