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