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
43struct datalink_protocol : net_protocol {
44	struct net_domain_private* domain;
45};
46
47struct 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
56static const char*
57option_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
130static status_t
131get_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
167static void
168set_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
177static status_t
178fill_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
194static void
195update_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
212static status_t
213datalink_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
362static status_t
363datalink_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*/
427static status_t
428datalink_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*/
471static bool
472datalink_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*/
522static bool
523datalink_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
552static net_interface*
553datalink_get_interface(net_domain* domain, uint32 index)
554{
555	return get_interface(domain, index);
556}
557
558
559static net_interface*
560datalink_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
575static void
576datalink_put_interface(net_interface* interface)
577{
578	if (interface == NULL)
579		return;
580
581	((Interface*)interface)->ReleaseReference();
582}
583
584
585static net_interface_address*
586datalink_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*/
606static bool
607datalink_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
620static void
621datalink_put_interface_address(net_interface_address* address)
622{
623	if (address == NULL)
624		return;
625
626	((InterfaceAddress*)address)->ReleaseReference();
627}
628
629
630static status_t
631datalink_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
642static status_t
643datalink_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
654static status_t
655datalink_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
671static status_t
672interface_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
690static status_t
691interface_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
700static status_t
701interface_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
719static status_t
720interface_protocol_up(net_datalink_protocol* protocol)
721{
722	TRACE("%s(%p)\n", __FUNCTION__, protocol);
723	return B_OK;
724}
725
726
727static void
728interface_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
750static status_t
751interface_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
773static status_t
774interface_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
999static status_t
1000interface_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
1009static status_t
1010interface_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
1020net_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
1055net_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