xref: /haiku/src/add-ons/kernel/network/stack/datalink.cpp (revision e0ef64750f3169cd634bb2f7a001e22488b05231)
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  *		Hugo Santos, hugosantos@gmail.com
8  */
9 
10 
11 #include <net/if.h>
12 #include <net/if_dl.h>
13 #include <net/if_media.h>
14 #include <net/route.h>
15 #include <new>
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <sys/sockio.h>
20 
21 #include <KernelExport.h>
22 
23 #include <net_datalink.h>
24 #include <net_device.h>
25 #include <NetUtilities.h>
26 
27 #include "device_interfaces.h"
28 #include "domains.h"
29 #include "interfaces.h"
30 #include "routes.h"
31 #include "stack_private.h"
32 #include "utility.h"
33 
34 
35 //#define TRACE_DATALINK
36 #ifdef TRACE_DATALINK
37 #	define TRACE(x...) dprintf(STACK_DEBUG_PREFIX x)
38 #else
39 #	define TRACE(x...) ;
40 #endif
41 
42 
43 struct datalink_protocol : net_protocol {
44 	struct net_domain_private* domain;
45 };
46 
47 struct interface_protocol : net_datalink_protocol {
48 	struct net_device_module_info* device_module;
49 	struct net_device* device;
50 };
51 
52 
53 #ifdef TRACE_DATALINK
54 
55 
56 static const char*
57 option_to_string(int32 option)
58 {
59 #	define CODE(x) case x: return #x;
60 	switch (option) {
61 		CODE(SIOCADDRT)			/* add route */
62 		CODE(SIOCDELRT)			/* delete route */
63 		CODE(SIOCSIFADDR)		/* set interface address */
64 		CODE(SIOCGIFADDR)		/* get interface address */
65 		CODE(SIOCSIFDSTADDR)	/* set point-to-point address */
66 		CODE(SIOCGIFDSTADDR)	/* get point-to-point address */
67 		CODE(SIOCSIFFLAGS)		/* set interface flags */
68 		CODE(SIOCGIFFLAGS)		/* get interface flags */
69 		CODE(SIOCGIFBRDADDR)	/* get broadcast address */
70 		CODE(SIOCSIFBRDADDR)	/* set broadcast address */
71 		CODE(SIOCGIFCOUNT)		/* count interfaces */
72 		CODE(SIOCGIFCONF)		/* get interface list */
73 		CODE(SIOCGIFINDEX)		/* interface name -> index */
74 		CODE(SIOCGIFNAME)		/* interface index -> name */
75 		CODE(SIOCGIFNETMASK)	/* get net address mask */
76 		CODE(SIOCSIFNETMASK)	/* set net address mask */
77 		CODE(SIOCGIFMETRIC)		/* get interface metric */
78 		CODE(SIOCSIFMETRIC)		/* set interface metric */
79 		CODE(SIOCDIFADDR)		/* delete interface address */
80 		CODE(SIOCAIFADDR)		/* configure interface alias */
81 		CODE(SIOCADDMULTI)		/* add multicast address */
82 		CODE(SIOCDELMULTI)		/* delete multicast address */
83 		CODE(SIOCGIFMTU)		/* get interface MTU */
84 		CODE(SIOCSIFMTU)		/* set interface MTU */
85 		CODE(SIOCSIFMEDIA)		/* set net media */
86 		CODE(SIOCGIFMEDIA)		/* get net media */
87 
88 		CODE(SIOCGRTSIZE)		/* get route table size */
89 		CODE(SIOCGRTTABLE)		/* get route table */
90 		CODE(SIOCGETRT)			/* get route information for destination */
91 
92 		CODE(SIOCGIFSTATS)		/* get interface stats */
93 		CODE(SIOCGIFTYPE)		/* get interface type */
94 
95 		CODE(SIOCSPACKETCAP)	/* Start capturing packets on an interface */
96 		CODE(SIOCCPACKETCAP)	/* Stop capturing packets on an interface */
97 
98 		CODE(SIOCSHIWAT)		/* set high watermark */
99 		CODE(SIOCGHIWAT)		/* get high watermark */
100 		CODE(SIOCSLOWAT)		/* set low watermark */
101 		CODE(SIOCGLOWAT)		/* get low watermark */
102 		CODE(SIOCATMARK)		/* at out-of-band mark? */
103 		CODE(SIOCSPGRP)			/* set process group */
104 		CODE(SIOCGPGRP)			/* get process group */
105 
106 		CODE(SIOCGPRIVATE_0)	/* device private 0 */
107 		CODE(SIOCGPRIVATE_1)	/* device private 1 */
108 		CODE(SIOCSDRVSPEC)		/* set driver-specific parameters */
109 		CODE(SIOCGDRVSPEC)		/* get driver-specific parameters */
110 
111 		CODE(SIOCSIFGENERIC)	/* generic IF set op */
112 		CODE(SIOCGIFGENERIC)	/* generic IF get op */
113 
114 		CODE(B_SOCKET_SET_ALIAS)		/* set interface alias, ifaliasreq */
115 		CODE(B_SOCKET_GET_ALIAS)		/* get interface alias, ifaliasreq */
116 		CODE(B_SOCKET_COUNT_ALIASES)	/* count interface aliases */
117 
118 		default:
119 			static char buffer[24];
120 			snprintf(buffer, sizeof(buffer), "%" B_PRId32, option);
121 			return buffer;
122 	}
123 #	undef CODE
124 }
125 
126 
127 #endif	// TRACE_DATALINK
128 
129 
130 static status_t
131 get_interface_name_or_index(net_domain* domain, int32 option, void* value,
132 	size_t* _length)
133 {
134 	ASSERT(option == SIOCGIFINDEX || option == SIOCGIFNAME);
135 
136 	size_t expected = option == SIOCGIFINDEX ? IF_NAMESIZE : sizeof(ifreq);
137 	if (*_length < expected)
138 		return B_BAD_VALUE;
139 
140 	ifreq request;
141 	memset(&request, 0, sizeof(request));
142 
143 	if (user_memcpy(&request, value, expected) < B_OK)
144 		return B_BAD_ADDRESS;
145 
146 	Interface* interface = NULL;
147 	if (option == SIOCGIFINDEX)
148 		interface = get_interface(domain, request.ifr_name);
149 	else
150 		interface = get_interface(domain, request.ifr_index);
151 
152 	if (interface == NULL)
153 		return B_BAD_VALUE;
154 
155 	if (option == SIOCGIFINDEX)
156 		request.ifr_index = interface->index;
157 	else
158 		strlcpy(request.ifr_name, interface->name, IF_NAMESIZE);
159 
160 	*_length = sizeof(ifreq);
161 	interface->ReleaseReference();
162 
163 	return user_memcpy(value, &request, sizeof(ifreq));
164 }
165 
166 
167 static void
168 set_interface_address(net_interface_address*& target, InterfaceAddress* address)
169 {
170 	if (target != NULL)
171 		static_cast<InterfaceAddress*>(target)->ReleaseReference();
172 
173 	target = address;
174 }
175 
176 
177 static status_t
178 fill_address(const sockaddr* from, sockaddr* to, size_t maxLength)
179 {
180 	if (from != NULL) {
181 		// Copy address over
182 		return user_memcpy(to, from, min_c(from->sa_len, maxLength));
183 	}
184 
185 	// Fill in empty address
186 	sockaddr empty;
187 	empty.sa_len = 2;
188 	empty.sa_family = AF_UNSPEC;
189 
190 	return user_memcpy(to, &empty, min_c(2, maxLength));
191 }
192 
193 
194 //	#pragma mark - datalink module
195 
196 
197 static status_t
198 datalink_control(net_domain* _domain, int32 option, void* value,
199 	size_t* _length)
200 {
201 	TRACE("%s(domain %p, option %s, value %p, length %zu)\n", __FUNCTION__,
202 		_domain, option_to_string(option), value, *_length);
203 
204 	net_domain_private* domain = (net_domain_private*)_domain;
205 	if (domain == NULL || domain->family == AF_LINK) {
206 		// the AF_LINK family is already handled completely in the link protocol
207 		return B_BAD_VALUE;
208 	}
209 
210 	switch (option) {
211 		case SIOCGIFINDEX:
212 		case SIOCGIFNAME:
213 			return get_interface_name_or_index(domain, option, value, _length);
214 
215 		case SIOCAIFADDR:	/* same as B_SOCKET_ADD_ALIAS */
216 		{
217 			// add new interface address
218 			if (*_length < sizeof(struct ifaliasreq))
219 				return B_BAD_VALUE;
220 
221 			struct ifaliasreq request;
222 			if (user_memcpy(&request, value, sizeof(struct ifaliasreq)) != B_OK)
223 				return B_BAD_ADDRESS;
224 
225 			Interface* interface = get_interface(domain, request.ifra_name);
226 			if (interface != NULL) {
227 				// A new alias is added to this interface
228 				status_t status = add_interface_address(interface, domain,
229 					request);
230 				notify_interface_changed(interface);
231 				interface->ReleaseReference();
232 
233 				return status;
234 			}
235 
236 			// A new interface needs to be added
237 			net_device_interface* deviceInterface
238 				= get_device_interface(request.ifra_name);
239 			if (deviceInterface == NULL)
240 				return B_DEVICE_NOT_FOUND;
241 
242 			status_t status = add_interface(request.ifra_name, domain, request,
243 				deviceInterface);
244 
245 			put_device_interface(deviceInterface);
246 			return status;
247 		}
248 
249 		case SIOCDIFADDR:	/* same as B_SOCKET_REMOVE_ALIAS */
250 		{
251 			// remove interface (address)
252 			struct ifreq request;
253 			if (user_memcpy(&request, value, sizeof(struct ifreq)) != B_OK)
254 				return B_BAD_ADDRESS;
255 
256 			Interface* interface = get_interface(domain, request.ifr_name);
257 			if (interface == NULL)
258 				return B_BAD_VALUE;
259 
260 			status_t status = B_OK;
261 
262 			if (request.ifr_addr.sa_family != AF_UNSPEC
263 				&& request.ifr_addr.sa_len != 0) {
264 				status = interface->Control(domain, SIOCDIFADDR, request,
265 					(ifreq*)value, *_length);
266 			} else
267 				remove_interface(interface);
268 
269 			interface->ReleaseReference();
270 
271 			return status;
272 		}
273 
274 		case SIOCGIFCOUNT:
275 		{
276 			// count number of interfaces
277 			struct ifconf config;
278 			config.ifc_value = count_interfaces();
279 
280 			return user_memcpy(value, &config, sizeof(struct ifconf));
281 		}
282 
283 		case SIOCGIFCONF:
284 		{
285 			// retrieve ifreqs for all interfaces
286 			struct ifconf config;
287 			if (user_memcpy(&config, value, sizeof(struct ifconf)) < B_OK)
288 				return B_BAD_ADDRESS;
289 
290 			size_t size = config.ifc_len;
291 			status_t status
292 				= list_interfaces(domain->family, config.ifc_buf, &size);
293 			if (status != B_OK)
294 				return status;
295 
296 			config.ifc_len = (int)size;
297 			return user_memcpy(value, &config, sizeof(struct ifconf));
298 		}
299 
300 		case SIOCGRTSIZE:
301 		{
302 			// determine size of buffer to hold the routing table
303 			struct ifconf config;
304 			config.ifc_value = route_table_size(domain);
305 
306 			return user_memcpy(value, &config, sizeof(struct ifconf));
307 		}
308 		case SIOCGRTTABLE:
309 		{
310 			// retrieve all routes for this domain
311 			struct ifconf config;
312 			if (user_memcpy(&config, value, sizeof(struct ifconf)) < B_OK)
313 				return B_BAD_ADDRESS;
314 
315 			return list_routes(domain, config.ifc_buf, config.ifc_len);
316 		}
317 		case SIOCGETRT:
318 			return get_route_information(domain, value, *_length);
319 
320 		default:
321 		{
322 			// We also accept partial ifreqs as long as the name is complete.
323 			if (*_length < IF_NAMESIZE)
324 				return B_BAD_VALUE;
325 
326 			size_t length = min_c(sizeof(struct ifreq), *_length);
327 
328 			// try to pass the request to an existing interface
329 			struct ifreq request;
330 			if (user_memcpy(&request, value, length) != B_OK)
331 				return B_BAD_ADDRESS;
332 
333 			Interface* interface = get_interface(domain, request.ifr_name);
334 			if (interface == NULL)
335 				return B_BAD_VALUE;
336 
337 			status_t status = interface->Control(domain, option, request,
338 				(ifreq*)value, *_length);
339 
340 			interface->ReleaseReference();
341 			return status;
342 		}
343 	}
344 	return B_BAD_VALUE;
345 }
346 
347 
348 static status_t
349 datalink_send_routed_data(struct net_route* route, net_buffer* buffer)
350 {
351 	TRACE("%s(route %p, buffer %p)\n", __FUNCTION__, route, buffer);
352 
353 	InterfaceAddress* address = (InterfaceAddress*)route->interface_address;
354 	Interface* interface = (Interface*)address->interface;
355 
356 	//dprintf("send buffer (%ld bytes) to interface %s (route flags %lx)\n",
357 	//	buffer->size, interface->name, route->flags);
358 
359 	if ((route->flags & RTF_REJECT) != 0) {
360 		TRACE("  rejected route\n");
361 		return ENETUNREACH;
362 	}
363 
364 	if ((route->flags & RTF_LOCAL) != 0) {
365 		TRACE("  local route\n");
366 
367 		// We set the interface address here, so the buffer is delivered
368 		// directly to the domain in interfaces.cpp:device_consumer_thread()
369 		address->AcquireReference();
370 		set_interface_address(buffer->interface_address, address);
371 
372 		// this one goes back to the domain directly
373 		return fifo_enqueue_buffer(
374 			&interface->DeviceInterface()->receive_queue, buffer);
375 	}
376 
377 	if ((route->flags & RTF_GATEWAY) != 0) {
378 		TRACE("  gateway route\n");
379 
380 		// This route involves a gateway, we need to use the gateway address
381 		// instead of the destination address:
382 		if (route->gateway == NULL)
383 			return B_MISMATCHED_VALUES;
384 		memcpy(buffer->destination, route->gateway, route->gateway->sa_len);
385 	}
386 
387 	// this goes out to the datalink protocols
388 	domain_datalink* datalink
389 		= interface->DomainDatalink(address->domain->family);
390 	return datalink->first_info->send_data(datalink->first_protocol, buffer);
391 }
392 
393 
394 /*!	Finds a route for the given \a buffer in the given \a domain, and calls
395 	net_protocol_info::send_routed_data() on either the \a protocol (if
396 	non-NULL), or the domain.
397 */
398 static status_t
399 datalink_send_data(net_protocol* protocol, net_domain* domain,
400 	net_buffer* buffer)
401 {
402 	TRACE("%s(%p, domain %p, buffer %p)\n", __FUNCTION__, protocol, domain,
403 		buffer);
404 
405 	if (protocol == NULL && domain == NULL)
406 		return B_BAD_VALUE;
407 
408 	net_protocol_module_info* module = protocol != NULL
409 		? protocol->module : domain->module;
410 
411 	if (domain == NULL)
412 		domain = protocol->module->get_domain(protocol);
413 
414 	net_route* route = NULL;
415 	status_t status;
416 	if (protocol != NULL && protocol->socket != NULL
417 		&& protocol->socket->bound_to_device > 0) {
418 		status = get_device_route(domain, protocol->socket->bound_to_device,
419 			&route);
420 	} else
421 		status = get_buffer_route(domain, buffer, &route);
422 
423 	TRACE("  route status: %s\n", strerror(status));
424 
425 	if (status != B_OK)
426 		return status;
427 
428 	status = module->send_routed_data(protocol, route, buffer);
429 	put_route(domain, route);
430 	return status;
431 }
432 
433 
434 /*!	Tests if \a address is a local address in the domain.
435 
436 	\param _interfaceAddress will be set to the interface address belonging to
437 		that address if non-NULL. If the address \a _interfaceAddress points to
438 		is not NULL, it is assumed that it already points to an address, which
439 		is then released before the new address is assigned.
440 	\param _matchedType will be set to either zero or MSG_BCAST if non-NULL.
441 */
442 static bool
443 datalink_is_local_address(net_domain* domain, const struct sockaddr* address,
444 	net_interface_address** _interfaceAddress, uint32* _matchedType)
445 {
446 	TRACE("%s(domain %p, address %s)\n", __FUNCTION__, domain,
447 		AddressString(domain, address).Data());
448 
449 	if (domain == NULL || address == NULL
450 		|| domain->family != address->sa_family)
451 		return false;
452 
453 	uint32 matchedType = 0;
454 
455 	InterfaceAddress* interfaceAddress = get_interface_address(address);
456 	if (interfaceAddress == NULL) {
457 		// Check for matching broadcast address
458 		if ((domain->address_module->flags
459 				& NET_ADDRESS_MODULE_FLAG_BROADCAST_ADDRESS) != 0) {
460 			interfaceAddress
461 				= get_interface_address_for_destination(domain, address);
462 			matchedType = MSG_BCAST;
463 		}
464 		if (interfaceAddress == NULL) {
465 			TRACE("  no\n");
466 			return false;
467 		}
468 	}
469 
470 	TRACE("  it is, interface address %p\n", interfaceAddress);
471 
472 	if (_interfaceAddress != NULL)
473 		set_interface_address(*_interfaceAddress, interfaceAddress);
474 	else
475 		interfaceAddress->ReleaseReference();
476 
477 	if (_matchedType != NULL)
478 		*_matchedType = matchedType;
479 
480 	return true;
481 }
482 
483 
484 /*!	Tests if \a address is a local link address in the domain.
485 
486 	\param unconfiguredOnly only unconfigured interfaces are taken into account.
487 	\param _interfaceAddress will be set to the first address of the interface
488 		and domain belonging to that address if non-NULL. If the address
489 		\a _interfaceAddress points to is not NULL, it is assumed that it
490 		already points to an address, which is then released before the new
491 		address is assigned.
492 */
493 static bool
494 datalink_is_local_link_address(net_domain* domain, bool unconfiguredOnly,
495 	const struct sockaddr* address, net_interface_address** _interfaceAddress)
496 {
497 	if (domain == NULL || address == NULL || address->sa_family != AF_LINK)
498 		return false;
499 
500 #ifdef TRACE_DATALINK
501 	uint8* data = LLADDR((sockaddr_dl*)address);
502 	TRACE("%s(domain %p, unconfiguredOnly %d, address %02x:%02x:%02x:%02x:%02x"
503 		":%02x)\n", __FUNCTION__, domain, unconfiguredOnly, data[0], data[1],
504 		data[2], data[3], data[4], data[5]);
505 #endif
506 
507 	InterfaceAddress* interfaceAddress = get_interface_address_for_link(domain,
508 		address, unconfiguredOnly);
509 	if (interfaceAddress == NULL) {
510 		TRACE("  no\n");
511 		return false;
512 	}
513 
514 	if (_interfaceAddress != NULL)
515 		set_interface_address(*_interfaceAddress, interfaceAddress);
516 	else
517 		interfaceAddress->ReleaseReference();
518 
519 	return true;
520 }
521 
522 
523 static net_interface*
524 datalink_get_interface(net_domain* domain, uint32 index)
525 {
526 	return get_interface(domain, index);
527 }
528 
529 
530 static net_interface*
531 datalink_get_interface_with_address(const sockaddr* address)
532 {
533 	InterfaceAddress* interfaceAddress = get_interface_address(address);
534 	if (interfaceAddress == NULL)
535 		return NULL;
536 
537 	Interface* interface = static_cast<Interface*>(interfaceAddress->interface);
538 
539 	interface->AcquireReference();
540 	interfaceAddress->ReleaseReference();
541 
542 	return interface;
543 }
544 
545 
546 static void
547 datalink_put_interface(net_interface* interface)
548 {
549 	if (interface == NULL)
550 		return;
551 
552 	((Interface*)interface)->ReleaseReference();
553 }
554 
555 
556 static net_interface_address*
557 datalink_get_interface_address(const struct sockaddr* address)
558 {
559 	return get_interface_address(address);
560 }
561 
562 
563 /*!	Returns a reference to the next address of the given interface in
564 	\a _address. When you call this function the first time, \a _address must
565 	point to a NULL address. Upon the next call, the reference to the previous
566 	address is taken over again.
567 
568 	If you do not traverse the list to the end, you'll have to manually release
569 	the reference to the address where you stopped.
570 
571 	\param interface The interface whose address list should be iterated over.
572 	\param _address A pointer to the location where the next address should
573 		be stored.
574 
575 	\return \c true if an address reference was returned, \c false if not.
576 */
577 static bool
578 datalink_get_next_interface_address(net_interface* _interface,
579 	net_interface_address** _address)
580 {
581 	Interface* interface = (Interface*)_interface;
582 
583 	InterfaceAddress* address = (InterfaceAddress*)*_address;
584 	bool gotOne = interface->GetNextAddress(&address);
585 	*_address = address;
586 
587 	return gotOne;
588 }
589 
590 
591 static void
592 datalink_put_interface_address(net_interface_address* address)
593 {
594 	if (address == NULL)
595 		return;
596 
597 	((InterfaceAddress*)address)->ReleaseReference();
598 }
599 
600 
601 static status_t
602 datalink_join_multicast(net_interface* _interface, net_domain* domain,
603 	const struct sockaddr* address)
604 {
605 	Interface* interface = (Interface*)_interface;
606 	domain_datalink* datalink = interface->DomainDatalink(domain->family);
607 
608 	return datalink->first_info->join_multicast(datalink->first_protocol,
609 		address);
610 }
611 
612 
613 static status_t
614 datalink_leave_multicast(net_interface* _interface, net_domain* domain,
615 	const struct sockaddr* address)
616 {
617 	Interface* interface = (Interface*)_interface;
618 	domain_datalink* datalink = interface->DomainDatalink(domain->family);
619 
620 	return datalink->first_info->leave_multicast(datalink->first_protocol,
621 		address);
622 }
623 
624 
625 static status_t
626 datalink_std_ops(int32 op, ...)
627 {
628 	switch (op) {
629 		case B_MODULE_INIT:
630 		case B_MODULE_UNINIT:
631 			return B_OK;
632 
633 		default:
634 			return B_ERROR;
635 	}
636 }
637 
638 
639 //	#pragma mark - net_datalink_protocol
640 
641 
642 static status_t
643 interface_protocol_init(net_interface* interface, net_domain* domain,
644 	net_datalink_protocol** _protocol)
645 {
646 	interface_protocol* protocol = new(std::nothrow) interface_protocol;
647 	if (protocol == NULL)
648 		return B_NO_MEMORY;
649 
650 	TRACE("%s(%p, interface %p - %s, domain %p)\n", __FUNCTION__, protocol,
651 		interface, interface->name, domain);
652 
653 	protocol->device_module = interface->device->module;
654 	protocol->device = interface->device;
655 
656 	*_protocol = protocol;
657 	return B_OK;
658 }
659 
660 
661 static status_t
662 interface_protocol_uninit(net_datalink_protocol* protocol)
663 {
664 	TRACE("%s(%p)\n", __FUNCTION__, protocol);
665 
666 	delete protocol;
667 	return B_OK;
668 }
669 
670 
671 static status_t
672 interface_protocol_send_data(net_datalink_protocol* _protocol,
673 	net_buffer* buffer)
674 {
675 	TRACE("%s(%p, buffer %p)\n", __FUNCTION__, _protocol, buffer);
676 
677 	interface_protocol* protocol = (interface_protocol*)_protocol;
678 	Interface* interface = (Interface*)protocol->interface;
679 
680 	if (atomic_get(&interface->DeviceInterface()->monitor_count) > 0)
681 		device_interface_monitor_receive(interface->DeviceInterface(), buffer);
682 
683 	return protocol->device_module->send_data(protocol->device, buffer);
684 }
685 
686 
687 static status_t
688 interface_protocol_up(net_datalink_protocol* protocol)
689 {
690 	TRACE("%s(%p)\n", __FUNCTION__, protocol);
691 	return B_OK;
692 }
693 
694 
695 static void
696 interface_protocol_down(net_datalink_protocol* _protocol)
697 {
698 	TRACE("%s(%p)\n", __FUNCTION__, _protocol);
699 
700 	interface_protocol* protocol = (interface_protocol*)_protocol;
701 	Interface* interface = (Interface*)protocol->interface;
702 	net_device_interface* deviceInterface = interface->DeviceInterface();
703 
704 	if (deviceInterface->up_count == 0)
705 		return;
706 
707 	deviceInterface->up_count--;
708 
709 	interface->WentDown();
710 
711 	if (deviceInterface->up_count > 0)
712 		return;
713 
714 	down_device_interface(deviceInterface);
715 }
716 
717 
718 static status_t
719 interface_protocol_change_address(net_datalink_protocol* protocol,
720 	net_interface_address* interfaceAddress, int32 option,
721 	const struct sockaddr* oldAddress, const struct sockaddr* newAddress)
722 {
723 	TRACE("%s(%p, interface address %p, option %s, old %p, new %p)\n",
724 		__FUNCTION__, protocol, interfaceAddress, option_to_string(option),
725 		oldAddress, newAddress);
726 
727 	switch (option) {
728 		case SIOCSIFADDR:
729 		case SIOCSIFNETMASK:
730 		case SIOCSIFBRDADDR:
731 		case SIOCSIFDSTADDR:
732 		case SIOCDIFADDR:
733 			return update_interface_address((InterfaceAddress*)interfaceAddress,
734 				option, oldAddress, newAddress);
735 	}
736 
737 	return B_OK;
738 }
739 
740 
741 static status_t
742 interface_protocol_control(net_datalink_protocol* _protocol, int32 option,
743 	void* argument, size_t length)
744 {
745 	TRACE("%s(%p, option %s, argument %p, length %zu)\n", __FUNCTION__,
746 		_protocol, option_to_string(option), argument, length);
747 
748 	interface_protocol* protocol = (interface_protocol*)_protocol;
749 	Interface* interface = (Interface*)protocol->interface;
750 
751 	switch (option) {
752 		case SIOCGIFADDR:
753 		case SIOCGIFNETMASK:
754 		case SIOCGIFBRDADDR:
755 		case SIOCGIFDSTADDR:
756 		{
757 			if (length < sizeof(ifreq))
758 				return B_BAD_VALUE;
759 
760 			ifreq request;
761 			if (user_memcpy(&request, argument, sizeof(struct ifreq)) != B_OK)
762 				return B_BAD_ADDRESS;
763 
764 			InterfaceAddress* interfaceAddress
765 				= get_interface_address(&request.ifr_addr);
766 			if (interfaceAddress == NULL) {
767 				interfaceAddress
768 					= interface->FirstForFamily(protocol->domain->family);
769 				if (interfaceAddress == NULL)
770 					return B_BAD_VALUE;
771 			}
772 
773 			size_t maxLength = length - offsetof(ifreq, ifr_addr);
774 
775 			status_t status = fill_address(
776 				*interfaceAddress->AddressFor(option),
777 				&((struct ifreq*)argument)->ifr_addr, maxLength);
778 
779 			interfaceAddress->ReleaseReference();
780 			return status;
781 		}
782 
783 		case B_SOCKET_COUNT_ALIASES:
784 		{
785 			ifreq request;
786 			request.ifr_count = interface->CountAddresses();
787 
788 			return user_memcpy(&((struct ifreq*)argument)->ifr_count,
789 				&request.ifr_count, sizeof(request.ifr_count));
790 		}
791 
792 		case B_SOCKET_GET_ALIAS:
793 		{
794 			ifaliasreq request;
795 			if (user_memcpy(&request, argument, sizeof(ifaliasreq)) != B_OK)
796 				return B_BAD_ADDRESS;
797 
798 			InterfaceAddress* address = NULL;
799 			if (request.ifra_index < 0) {
800 				if (!protocol->domain->address_module->is_empty_address(
801 						(const sockaddr*)&request.ifra_addr, false)) {
802 					// Find first address that matches the local address
803 					address = interface->AddressForLocal(protocol->domain,
804 						(const sockaddr*)&request.ifra_addr);
805 				}
806 				if (address == NULL) {
807 					// Find first address for family
808 					address = interface->FirstForFamily(
809 						protocol->domain->family);
810 				}
811 
812 				request.ifra_index = interface->IndexOfAddress(address);
813 			} else
814 				address = interface->AddressAt(request.ifra_index);
815 			if (address == NULL)
816 				return B_BAD_VALUE;
817 
818 			// Copy index (in case none was specified)
819 			status_t status = user_memcpy(
820 				&((struct ifaliasreq*)argument)->ifra_index,
821 				&request.ifra_index, sizeof(request.ifra_index));
822 
823 			// Copy address info
824 			if (status == B_OK) {
825 				status = fill_address(address->local,
826 					(sockaddr*)&((struct ifaliasreq*)argument)->ifra_addr,
827 					sizeof(sockaddr_storage));
828 			}
829 			if (status == B_OK) {
830 				status = fill_address(address->mask,
831 					(sockaddr*)&((struct ifaliasreq*)argument)->ifra_mask,
832 					sizeof(sockaddr_storage));
833 			}
834 			if (status == B_OK) {
835 				status = fill_address(address->destination,
836 					(sockaddr*)&((struct ifaliasreq*)argument)
837 						->ifra_destination,
838 					sizeof(sockaddr_storage));
839 			}
840 
841 			address->ReleaseReference();
842 
843 			return status;
844 		}
845 
846 		case SIOCGIFFLAGS:
847 		{
848 			// get flags
849 			struct ifreq request;
850 			request.ifr_flags = interface->flags | interface->device->flags;
851 
852 			return user_memcpy(&((struct ifreq*)argument)->ifr_flags,
853 				&request.ifr_flags, sizeof(request.ifr_flags));
854 		}
855 
856 		case SIOCGIFSTATS:
857 		{
858 			// get stats
859 			return user_memcpy(&((struct ifreq*)argument)->ifr_stats,
860 				&interface->DeviceInterface()->device->stats,
861 				sizeof(struct ifreq_stats));
862 		}
863 
864 		case SIOCGIFTYPE:
865 		{
866 			// get type
867 			struct ifreq request;
868 			request.ifr_type = interface->type;
869 
870 			return user_memcpy(&((struct ifreq*)argument)->ifr_type,
871 				&request.ifr_type, sizeof(request.ifr_type));
872 		}
873 
874 		case SIOCGIFMTU:
875 		{
876 			// get MTU
877 			struct ifreq request;
878 			request.ifr_mtu = interface->mtu;
879 
880 			return user_memcpy(&((struct ifreq*)argument)->ifr_mtu,
881 				&request.ifr_mtu, sizeof(request.ifr_mtu));
882 		}
883 		case SIOCSIFMTU:
884 		{
885 			// set MTU
886 			struct ifreq request;
887 			if (user_memcpy(&request, argument, sizeof(struct ifreq)) < B_OK)
888 				return B_BAD_ADDRESS;
889 
890 			// check for valid bounds
891 			if (request.ifr_mtu < 100
892 				|| (uint32)request.ifr_mtu > interface->device->mtu)
893 				return B_BAD_VALUE;
894 
895 			interface->mtu = request.ifr_mtu;
896 			notify_interface_changed(interface);
897 			return B_OK;
898 		}
899 
900 		case SIOCSIFMEDIA:
901 		{
902 			// set media
903 			struct ifreq request;
904 			if (user_memcpy(&request, argument, sizeof(struct ifreq)) < B_OK)
905 				return B_BAD_ADDRESS;
906 
907 			return interface->DeviceInterface()->device->module->set_media(
908 				interface->device, request.ifr_media);
909 		}
910 		case SIOCGIFMEDIA:
911 		{
912 			// get media
913 			struct ifreq request;
914 			request.ifr_media = interface->device->media;
915 
916 			return user_memcpy(&((struct ifreq*)argument)->ifr_media,
917 				&request.ifr_media, sizeof(request.ifr_media));
918 		}
919 
920 		case SIOCGIFMETRIC:
921 		{
922 			// get metric
923 			struct ifreq request;
924 			request.ifr_metric = interface->metric;
925 
926 			return user_memcpy(&((struct ifreq*)argument)->ifr_metric,
927 				&request.ifr_metric, sizeof(request.ifr_metric));
928 		}
929 		case SIOCSIFMETRIC:
930 		{
931 			// set metric
932 			struct ifreq request;
933 			if (user_memcpy(&request, argument, sizeof(struct ifreq)) < B_OK)
934 				return B_BAD_ADDRESS;
935 
936 			interface->metric = request.ifr_metric;
937 			notify_interface_changed(interface);
938 			return B_OK;
939 		}
940 
941 		case SIOCADDRT:
942 		case SIOCDELRT:
943 			// interface related route options
944 			return control_routes(interface, protocol->domain, option, argument,
945 				length);
946 	}
947 
948 	return protocol->device_module->control(protocol->device,
949 		option, argument, length);
950 }
951 
952 
953 static status_t
954 interface_protocol_join_multicast(net_datalink_protocol* _protocol,
955 	const sockaddr* address)
956 {
957 	interface_protocol* protocol = (interface_protocol*)_protocol;
958 
959 	return protocol->device_module->add_multicast(protocol->device, address);
960 }
961 
962 
963 static status_t
964 interface_protocol_leave_multicast(net_datalink_protocol* _protocol,
965 	const sockaddr* address)
966 {
967 	interface_protocol* protocol = (interface_protocol*)_protocol;
968 
969 	return protocol->device_module->remove_multicast(protocol->device,
970 		address);
971 }
972 
973 
974 net_datalink_module_info gNetDatalinkModule = {
975 	{
976 		NET_DATALINK_MODULE_NAME,
977 		0,
978 		datalink_std_ops
979 	},
980 
981 	datalink_control,
982 	datalink_send_routed_data,
983 	datalink_send_data,
984 
985 	datalink_is_local_address,
986 	datalink_is_local_link_address,
987 
988 	datalink_get_interface,
989 	datalink_get_interface_with_address,
990 	datalink_put_interface,
991 
992 	datalink_get_interface_address,
993 	datalink_get_next_interface_address,
994 	datalink_put_interface_address,
995 
996 	datalink_join_multicast,
997 	datalink_leave_multicast,
998 
999 	add_route,
1000 	remove_route,
1001 	get_route,
1002 	get_buffer_route,
1003 	put_route,
1004 	register_route_info,
1005 	unregister_route_info,
1006 	update_route_info
1007 };
1008 
1009 net_datalink_protocol_module_info gDatalinkInterfaceProtocolModule = {
1010 	{
1011 		NULL,
1012 		0,
1013 		NULL
1014 	},
1015 	interface_protocol_init,
1016 	interface_protocol_uninit,
1017 	interface_protocol_send_data,
1018 	interface_protocol_up,
1019 	interface_protocol_down,
1020 	interface_protocol_change_address,
1021 	interface_protocol_control,
1022 	interface_protocol_join_multicast,
1023 	interface_protocol_leave_multicast,
1024 };
1025