xref: /haiku/src/add-ons/kernel/network/stack/datalink.cpp (revision 820dca4df6c7bf955c46e8f6521b9408f50b2900)
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 				} else {
806 					// Find first address for family
807 					address = interface->FirstForFamily(
808 						protocol->domain->family);
809 				}
810 
811 				request.ifra_index = interface->IndexOfAddress(address);
812 			} else
813 				address = interface->AddressAt(request.ifra_index);
814 			if (address == NULL)
815 				return B_BAD_VALUE;
816 
817 			// Copy index (in case none was specified)
818 			status_t status = user_memcpy(
819 				&((struct ifaliasreq*)argument)->ifra_index,
820 				&request.ifra_index, sizeof(request.ifra_index));
821 
822 			// Copy address info
823 			if (status == B_OK) {
824 				status = fill_address(address->local,
825 					(sockaddr*)&((struct ifaliasreq*)argument)->ifra_addr,
826 					sizeof(sockaddr_storage));
827 			}
828 			if (status == B_OK) {
829 				status = fill_address(address->mask,
830 					(sockaddr*)&((struct ifaliasreq*)argument)->ifra_mask,
831 					sizeof(sockaddr_storage));
832 			}
833 			if (status == B_OK) {
834 				status = fill_address(address->destination,
835 					(sockaddr*)&((struct ifaliasreq*)argument)
836 						->ifra_destination,
837 					sizeof(sockaddr_storage));
838 			}
839 
840 			address->ReleaseReference();
841 
842 			return status;
843 		}
844 
845 		case SIOCGIFFLAGS:
846 		{
847 			// get flags
848 			struct ifreq request;
849 			request.ifr_flags = interface->flags | interface->device->flags;
850 
851 			return user_memcpy(&((struct ifreq*)argument)->ifr_flags,
852 				&request.ifr_flags, sizeof(request.ifr_flags));
853 		}
854 
855 		case SIOCGIFSTATS:
856 		{
857 			// get stats
858 			return user_memcpy(&((struct ifreq*)argument)->ifr_stats,
859 				&interface->DeviceInterface()->device->stats,
860 				sizeof(struct ifreq_stats));
861 		}
862 
863 		case SIOCGIFTYPE:
864 		{
865 			// get type
866 			struct ifreq request;
867 			request.ifr_type = interface->type;
868 
869 			return user_memcpy(&((struct ifreq*)argument)->ifr_type,
870 				&request.ifr_type, sizeof(request.ifr_type));
871 		}
872 
873 		case SIOCGIFMTU:
874 		{
875 			// get MTU
876 			struct ifreq request;
877 			request.ifr_mtu = interface->mtu;
878 
879 			return user_memcpy(&((struct ifreq*)argument)->ifr_mtu,
880 				&request.ifr_mtu, sizeof(request.ifr_mtu));
881 		}
882 		case SIOCSIFMTU:
883 		{
884 			// set MTU
885 			struct ifreq request;
886 			if (user_memcpy(&request, argument, sizeof(struct ifreq)) < B_OK)
887 				return B_BAD_ADDRESS;
888 
889 			// check for valid bounds
890 			if (request.ifr_mtu < 100
891 				|| (uint32)request.ifr_mtu > interface->device->mtu)
892 				return B_BAD_VALUE;
893 
894 			interface->mtu = request.ifr_mtu;
895 			notify_interface_changed(interface);
896 			return B_OK;
897 		}
898 
899 		case SIOCSIFMEDIA:
900 		{
901 			// set media
902 			struct ifreq request;
903 			if (user_memcpy(&request, argument, sizeof(struct ifreq)) != B_OK)
904 				return B_BAD_ADDRESS;
905 
906 			status_t status
907 				= interface->device->module->set_media(
908 					interface->device, request.ifr_media);
909 			if (status == B_NOT_SUPPORTED) {
910 				// TODO: this isn't so nice, and should be solved differently
911 				// (for example by removing the set_media() call altogether, or
912 				// making it able to deal properly with FreeBSD drivers as well)
913 				// try driver directly
914 				status = interface->device->module->control(
915 					interface->device, SIOCSIFMEDIA, &request, sizeof(request));
916 			}
917 
918 			return status;
919 		}
920 		case SIOCGIFMEDIA:
921 		{
922 			// get media
923 			if (length < sizeof(ifmediareq))
924 				return B_BAD_VALUE;
925 
926 			struct ifmediareq request;
927 			if (user_memcpy(&request, argument, sizeof(ifmediareq)) != B_OK)
928 				return B_BAD_ADDRESS;
929 
930 			// TODO: see above.
931 			if (interface->device->module->control(interface->device,
932 					SIOCGIFMEDIA, &request,
933 					sizeof(struct ifmediareq)) != B_OK) {
934 				memset(&request, 0, sizeof(struct ifmediareq));
935 				request.ifm_active = request.ifm_current
936 					= interface->device->media;
937 			}
938 
939 			return user_memcpy(argument, &request, sizeof(struct ifmediareq));
940 		}
941 
942 		case SIOCGIFMETRIC:
943 		{
944 			// get metric
945 			struct ifreq request;
946 			request.ifr_metric = interface->metric;
947 
948 			return user_memcpy(&((struct ifreq*)argument)->ifr_metric,
949 				&request.ifr_metric, sizeof(request.ifr_metric));
950 		}
951 		case SIOCSIFMETRIC:
952 		{
953 			// set metric
954 			struct ifreq request;
955 			if (user_memcpy(&request, argument, sizeof(struct ifreq)) < B_OK)
956 				return B_BAD_ADDRESS;
957 
958 			interface->metric = request.ifr_metric;
959 			notify_interface_changed(interface);
960 			return B_OK;
961 		}
962 
963 		case SIOCADDRT:
964 		case SIOCDELRT:
965 			// interface related route options
966 			return control_routes(interface, protocol->domain, option, argument,
967 				length);
968 	}
969 
970 	return protocol->device_module->control(protocol->device,
971 		option, argument, length);
972 }
973 
974 
975 static status_t
976 interface_protocol_join_multicast(net_datalink_protocol* _protocol,
977 	const sockaddr* address)
978 {
979 	interface_protocol* protocol = (interface_protocol*)_protocol;
980 
981 	return protocol->device_module->add_multicast(protocol->device, address);
982 }
983 
984 
985 static status_t
986 interface_protocol_leave_multicast(net_datalink_protocol* _protocol,
987 	const sockaddr* address)
988 {
989 	interface_protocol* protocol = (interface_protocol*)_protocol;
990 
991 	return protocol->device_module->remove_multicast(protocol->device,
992 		address);
993 }
994 
995 
996 net_datalink_module_info gNetDatalinkModule = {
997 	{
998 		NET_DATALINK_MODULE_NAME,
999 		0,
1000 		datalink_std_ops
1001 	},
1002 
1003 	datalink_control,
1004 	datalink_send_routed_data,
1005 	datalink_send_data,
1006 
1007 	datalink_is_local_address,
1008 	datalink_is_local_link_address,
1009 
1010 	datalink_get_interface,
1011 	datalink_get_interface_with_address,
1012 	datalink_put_interface,
1013 
1014 	datalink_get_interface_address,
1015 	datalink_get_next_interface_address,
1016 	datalink_put_interface_address,
1017 
1018 	datalink_join_multicast,
1019 	datalink_leave_multicast,
1020 
1021 	add_route,
1022 	remove_route,
1023 	get_route,
1024 	get_buffer_route,
1025 	put_route,
1026 	register_route_info,
1027 	unregister_route_info,
1028 	update_route_info
1029 };
1030 
1031 net_datalink_protocol_module_info gDatalinkInterfaceProtocolModule = {
1032 	{
1033 		NULL,
1034 		0,
1035 		NULL
1036 	},
1037 	interface_protocol_init,
1038 	interface_protocol_uninit,
1039 	interface_protocol_send_data,
1040 	interface_protocol_up,
1041 	interface_protocol_down,
1042 	interface_protocol_change_address,
1043 	interface_protocol_control,
1044 	interface_protocol_join_multicast,
1045 	interface_protocol_leave_multicast,
1046 };
1047