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