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