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