xref: /haiku/src/add-ons/kernel/network/stack/domains.cpp (revision 3c13a5f5b39d02367da1ef1d6bb3740ccb2340a1)
1c22d69bfSAxel Dörfler /*
2*3c13a5f5SAxel Dörfler  * Copyright 2006-2009, Haiku, Inc. All Rights Reserved.
3c22d69bfSAxel Dörfler  * Distributed under the terms of the MIT License.
4c22d69bfSAxel Dörfler  *
5c22d69bfSAxel Dörfler  * Authors:
6c22d69bfSAxel Dörfler  *		Axel Dörfler, axeld@pinc-software.de
7c22d69bfSAxel Dörfler  */
8c22d69bfSAxel Dörfler 
9c22d69bfSAxel Dörfler 
10c22d69bfSAxel Dörfler #include "domains.h"
11c22d69bfSAxel Dörfler #include "interfaces.h"
12409b1fc0SHugo Santos #include "utility.h"
13fb300cfdSHugo Santos #include "stack_private.h"
14c22d69bfSAxel Dörfler 
159206bb37SAxel Dörfler #include <net_device.h>
16c22d69bfSAxel Dörfler 
17c22d69bfSAxel Dörfler #include <lock.h>
18c22d69bfSAxel Dörfler #include <util/AutoLock.h>
19c22d69bfSAxel Dörfler 
209206bb37SAxel Dörfler #include <KernelExport.h>
219206bb37SAxel Dörfler 
229206bb37SAxel Dörfler #include <net/if_media.h>
23c22d69bfSAxel Dörfler #include <new>
24c22d69bfSAxel Dörfler #include <string.h>
25fb300cfdSHugo Santos #include <sys/sockio.h>
26c22d69bfSAxel Dörfler 
27c22d69bfSAxel Dörfler 
28c22d69bfSAxel Dörfler #define TRACE_DOMAINS
29c22d69bfSAxel Dörfler #ifdef TRACE_DOMAINS
30c22d69bfSAxel Dörfler #	define TRACE(x) dprintf x
31c22d69bfSAxel Dörfler #else
32c22d69bfSAxel Dörfler #	define TRACE(x) ;
33c22d69bfSAxel Dörfler #endif
34c22d69bfSAxel Dörfler 
352b07b8e0SIngo Weinhold static mutex sDomainLock;
36c22d69bfSAxel Dörfler static list sDomains;
37c22d69bfSAxel Dörfler 
38c22d69bfSAxel Dörfler 
39c22d69bfSAxel Dörfler /*!
40c22d69bfSAxel Dörfler 	Scans the domain list for the specified family.
41c22d69bfSAxel Dörfler 	You need to hold the sDomainLock when calling this function.
42c22d69bfSAxel Dörfler */
43c22d69bfSAxel Dörfler static net_domain_private*
44c22d69bfSAxel Dörfler lookup_domain(int family)
45c22d69bfSAxel Dörfler {
46c22d69bfSAxel Dörfler 	net_domain_private* domain = NULL;
47c22d69bfSAxel Dörfler 	while (true) {
48c22d69bfSAxel Dörfler 		domain = (net_domain_private*)list_get_next_item(&sDomains, domain);
49c22d69bfSAxel Dörfler 		if (domain == NULL)
50c22d69bfSAxel Dörfler 			break;
51c22d69bfSAxel Dörfler 
52c22d69bfSAxel Dörfler 		if (domain->family == family)
53c22d69bfSAxel Dörfler 			return domain;
54c22d69bfSAxel Dörfler 	}
55c22d69bfSAxel Dörfler 
56c22d69bfSAxel Dörfler 	return NULL;
57c22d69bfSAxel Dörfler }
58c22d69bfSAxel Dörfler 
59c22d69bfSAxel Dörfler 
60c22d69bfSAxel Dörfler //	#pragma mark -
61c22d69bfSAxel Dörfler 
62c22d69bfSAxel Dörfler 
63c22d69bfSAxel Dörfler /*!
64c22d69bfSAxel Dörfler 	Gets the domain of the specified family.
65c22d69bfSAxel Dörfler */
66c22d69bfSAxel Dörfler net_domain*
67c22d69bfSAxel Dörfler get_domain(int family)
68c22d69bfSAxel Dörfler {
692b07b8e0SIngo Weinhold 	MutexLocker locker(sDomainLock);
70c22d69bfSAxel Dörfler 	return lookup_domain(family);
71c22d69bfSAxel Dörfler }
72c22d69bfSAxel Dörfler 
73c22d69bfSAxel Dörfler 
74c22d69bfSAxel Dörfler uint32
75c22d69bfSAxel Dörfler count_domain_interfaces()
76c22d69bfSAxel Dörfler {
772b07b8e0SIngo Weinhold 	MutexLocker locker(sDomainLock);
78c22d69bfSAxel Dörfler 
79c22d69bfSAxel Dörfler 	net_domain_private* domain = NULL;
80c22d69bfSAxel Dörfler 	uint32 count = 0;
81c22d69bfSAxel Dörfler 
82c22d69bfSAxel Dörfler 	while (true) {
83c22d69bfSAxel Dörfler 		domain = (net_domain_private*)list_get_next_item(&sDomains, domain);
84c22d69bfSAxel Dörfler 		if (domain == NULL)
85c22d69bfSAxel Dörfler 			break;
86c22d69bfSAxel Dörfler 
87c22d69bfSAxel Dörfler 		net_interface* interface = NULL;
88c22d69bfSAxel Dörfler 		while (true) {
89c22d69bfSAxel Dörfler 			interface = (net_interface*)list_get_next_item(&domain->interfaces,
90c22d69bfSAxel Dörfler 				interface);
91c22d69bfSAxel Dörfler 			if (interface == NULL)
92c22d69bfSAxel Dörfler 				break;
93c22d69bfSAxel Dörfler 
94c22d69bfSAxel Dörfler 			count++;
95c22d69bfSAxel Dörfler 		}
96c22d69bfSAxel Dörfler 	}
97c22d69bfSAxel Dörfler 
98c22d69bfSAxel Dörfler 	return count;
99c22d69bfSAxel Dörfler }
100c22d69bfSAxel Dörfler 
101c22d69bfSAxel Dörfler 
102c22d69bfSAxel Dörfler /*!
103c22d69bfSAxel Dörfler 	Dumps a list of all interfaces into the supplied userland buffer.
104c22d69bfSAxel Dörfler 	If the interfaces don't fit into the buffer, an error (\c ENOBUFS) is
105c22d69bfSAxel Dörfler 	returned.
106c22d69bfSAxel Dörfler */
107c22d69bfSAxel Dörfler status_t
108409b1fc0SHugo Santos list_domain_interfaces(void* _buffer, size_t* bufferSize)
109c22d69bfSAxel Dörfler {
1102b07b8e0SIngo Weinhold 	MutexLocker locker(sDomainLock);
111c22d69bfSAxel Dörfler 
112409b1fc0SHugo Santos 	UserBuffer buffer(_buffer, *bufferSize);
113c22d69bfSAxel Dörfler 	net_domain_private* domain = NULL;
114c22d69bfSAxel Dörfler 
115c22d69bfSAxel Dörfler 	while (true) {
116c22d69bfSAxel Dörfler 		domain = (net_domain_private*)list_get_next_item(&sDomains, domain);
117c22d69bfSAxel Dörfler 		if (domain == NULL)
118c22d69bfSAxel Dörfler 			break;
119c22d69bfSAxel Dörfler 
1202b07b8e0SIngo Weinhold 		MutexLocker locker(domain->lock);
1219206bb37SAxel Dörfler 
122c22d69bfSAxel Dörfler 		net_interface* interface = NULL;
123c22d69bfSAxel Dörfler 		while (true) {
124c22d69bfSAxel Dörfler 			interface = (net_interface*)list_get_next_item(&domain->interfaces,
125c22d69bfSAxel Dörfler 				interface);
126c22d69bfSAxel Dörfler 			if (interface == NULL)
127c22d69bfSAxel Dörfler 				break;
128c22d69bfSAxel Dörfler 
129c22d69bfSAxel Dörfler 			ifreq request;
130c22d69bfSAxel Dörfler 			strlcpy(request.ifr_name, interface->name, IF_NAMESIZE);
1319206bb37SAxel Dörfler 			if (interface->address != NULL) {
1329206bb37SAxel Dörfler 				memcpy(&request.ifr_addr, interface->address,
1339206bb37SAxel Dörfler 					interface->address->sa_len);
1349206bb37SAxel Dörfler 			} else {
135c22d69bfSAxel Dörfler 				// empty address
136c22d69bfSAxel Dörfler 				request.ifr_addr.sa_len = 2;
137c22d69bfSAxel Dörfler 				request.ifr_addr.sa_family = AF_UNSPEC;
138c22d69bfSAxel Dörfler 			}
139c22d69bfSAxel Dörfler 
140409b1fc0SHugo Santos 			if (buffer.Copy(&request, IF_NAMESIZE
141409b1fc0SHugo Santos 					+ request.ifr_addr.sa_len) == NULL)
142409b1fc0SHugo Santos 				return buffer.Status();
143c22d69bfSAxel Dörfler 		}
144c22d69bfSAxel Dörfler 	}
145c22d69bfSAxel Dörfler 
146409b1fc0SHugo Santos 	*bufferSize = buffer.ConsumedAmount();
147c22d69bfSAxel Dörfler 	return B_OK;
148c22d69bfSAxel Dörfler }
149c22d69bfSAxel Dörfler 
150c22d69bfSAxel Dörfler 
151c22d69bfSAxel Dörfler status_t
152c22d69bfSAxel Dörfler add_interface_to_domain(net_domain* _domain,
153c22d69bfSAxel Dörfler 	struct ifreq& request)
154c22d69bfSAxel Dörfler {
155c22d69bfSAxel Dörfler 	net_domain_private* domain = (net_domain_private*)_domain;
156c22d69bfSAxel Dörfler 
157c22d69bfSAxel Dörfler 	const char* deviceName = request.ifr_parameter.device[0]
158c22d69bfSAxel Dörfler 		? request.ifr_parameter.device : request.ifr_name;
15920b534cdSHugo Santos 	const char* baseName = request.ifr_parameter.base_name[0]
16020b534cdSHugo Santos 		? request.ifr_parameter.base_name : request.ifr_name;
16120b534cdSHugo Santos 
162c22d69bfSAxel Dörfler 	net_device_interface* deviceInterface = get_device_interface(deviceName);
163c22d69bfSAxel Dörfler 	if (deviceInterface == NULL)
164c22d69bfSAxel Dörfler 		return ENODEV;
165c22d69bfSAxel Dörfler 
1662b07b8e0SIngo Weinhold 	MutexLocker locker(domain->lock);
167c22d69bfSAxel Dörfler 
16820b534cdSHugo Santos 	net_interface_private* interface = NULL;
16920b534cdSHugo Santos 	status_t status;
17020b534cdSHugo Santos 
171a3513e7bSAxel Dörfler 	if (find_interface(domain, request.ifr_name) == NULL) {
172a3513e7bSAxel Dörfler 		// We must not hold the domain's link when creating the interface:
173a3513e7bSAxel Dörfler 		// this will call get_module() which might want to access a network
174a3513e7bSAxel Dörfler 		// device when booting from network.
175a3513e7bSAxel Dörfler 		locker.Unlock();
17620b534cdSHugo Santos 		status = create_interface(domain, request.ifr_name,
17720b534cdSHugo Santos 			baseName, deviceInterface, &interface);
178a3513e7bSAxel Dörfler 		locker.Lock();
179a3513e7bSAxel Dörfler 
180a3513e7bSAxel Dörfler 		if (find_interface(domain, request.ifr_name) != NULL) {
181a3513e7bSAxel Dörfler 			delete_interface(interface);
182a3513e7bSAxel Dörfler 			status = B_NAME_IN_USE;
183a3513e7bSAxel Dörfler 		}
184a3513e7bSAxel Dörfler 	} else
185a3513e7bSAxel Dörfler 		status = B_NAME_IN_USE;
186c22d69bfSAxel Dörfler 
187c22d69bfSAxel Dörfler 	put_device_interface(deviceInterface);
188c22d69bfSAxel Dörfler 
189d68ffdedSAxel Dörfler 	if (status == B_OK) {
190c22d69bfSAxel Dörfler 		list_add_item(&domain->interfaces, interface);
191d68ffdedSAxel Dörfler 		notify_interface_added(interface);
192d68ffdedSAxel Dörfler 	}
19320b534cdSHugo Santos 
19420b534cdSHugo Santos 	return status;
195c22d69bfSAxel Dörfler }
196c22d69bfSAxel Dörfler 
197c22d69bfSAxel Dörfler 
198c22d69bfSAxel Dörfler /*!
199c22d69bfSAxel Dörfler 	Removes the interface from its domain, and deletes it.
200c22d69bfSAxel Dörfler 	You need to hold the domain's lock when calling this function.
201c22d69bfSAxel Dörfler */
202c22d69bfSAxel Dörfler status_t
203c22d69bfSAxel Dörfler remove_interface_from_domain(net_interface* interface)
204c22d69bfSAxel Dörfler {
205c22d69bfSAxel Dörfler 	net_domain_private* domain = (net_domain_private*)interface->domain;
206c22d69bfSAxel Dörfler 
207c22d69bfSAxel Dörfler 	list_remove_item(&domain->interfaces, interface);
208d68ffdedSAxel Dörfler 	notify_interface_removed(interface);
209c22d69bfSAxel Dörfler 	delete_interface((net_interface_private*)interface);
210c22d69bfSAxel Dörfler 	return B_OK;
211c22d69bfSAxel Dörfler }
212c22d69bfSAxel Dörfler 
213c22d69bfSAxel Dörfler 
214fb300cfdSHugo Santos status_t
215fb300cfdSHugo Santos domain_interface_control(net_domain_private* domain, int32 option,
216fb300cfdSHugo Santos 	ifreq* request)
217fb300cfdSHugo Santos {
218fb300cfdSHugo Santos 	const char* name = request->ifr_name;
219fb300cfdSHugo Santos 	status_t status = B_OK;
220fb300cfdSHugo Santos 
221fb300cfdSHugo Santos 	net_device_interface* device = get_device_interface(name, false);
222fb300cfdSHugo Santos 	if (device == NULL)
223fb300cfdSHugo Santos 		return ENODEV;
224*3c13a5f5SAxel Dörfler 
225*3c13a5f5SAxel Dörfler 	// The locking protocol dictates that if both the receive lock
226*3c13a5f5SAxel Dörfler 	// and domain locks are required, we MUST obtain the receive
227*3c13a5f5SAxel Dörfler 	// lock before the domain lock.
228*3c13a5f5SAxel Dörfler 	RecursiveLocker _1(device->receive_lock);
2292b07b8e0SIngo Weinhold 	MutexLocker _2(domain->lock);
230fb300cfdSHugo Santos 
231fb300cfdSHugo Santos 	net_interface* interface = find_interface(domain, name);
232fb300cfdSHugo Santos 	if (interface != NULL) {
233fb300cfdSHugo Santos 		switch (option) {
234fb300cfdSHugo Santos 			case SIOCDIFADDR:
235fb300cfdSHugo Santos 				remove_interface_from_domain(interface);
236fb300cfdSHugo Santos 				break;
237fb300cfdSHugo Santos 
238fb300cfdSHugo Santos 			case SIOCSIFFLAGS:
239ae074c5dSHugo Santos 			{
240ae074c5dSHugo Santos 				uint32 requestFlags = request->ifr_flags;
241ae074c5dSHugo Santos 				request->ifr_flags &= ~(IFF_UP | IFF_LINK | IFF_BROADCAST);
242ae074c5dSHugo Santos 
243ae074c5dSHugo Santos 				if ((requestFlags & IFF_UP) != (interface->flags & IFF_UP)) {
244ae074c5dSHugo Santos 					if (requestFlags & IFF_UP) {
245fb300cfdSHugo Santos 						status = interface->first_info->interface_up(
246fb300cfdSHugo Santos 							interface->first_protocol);
247ae074c5dSHugo Santos 						if (status == B_OK)
248fb300cfdSHugo Santos 							interface->flags |= IFF_UP;
249ae074c5dSHugo Santos 					} else {
250ae074c5dSHugo Santos 						interface_set_down(interface);
251fb300cfdSHugo Santos 					}
252fb300cfdSHugo Santos 				}
253fb300cfdSHugo Santos 
25474ff314bSAxel Dörfler 				if (status == B_OK) {
25574ff314bSAxel Dörfler 					// TODO: why shouldn't we able to delete IFF_BROADCAST?
25674ff314bSAxel Dörfler 					interface->flags &= IFF_UP | IFF_LINK | IFF_BROADCAST;
257ae074c5dSHugo Santos 					interface->flags |= request->ifr_flags;
25874ff314bSAxel Dörfler 				}
259fb300cfdSHugo Santos 				break;
260fb300cfdSHugo Santos 			}
261fb300cfdSHugo Santos 		}
262fb300cfdSHugo Santos 	}
263fb300cfdSHugo Santos 
264*3c13a5f5SAxel Dörfler 	// If the SIOCDIFADDR call above removed the last interface associated with
265*3c13a5f5SAxel Dörfler 	// the device interface, this will effectively remove the interface
266fb300cfdSHugo Santos 	put_device_interface(device);
267fb300cfdSHugo Santos 
268fb300cfdSHugo Santos 	return status;
269fb300cfdSHugo Santos }
270fb300cfdSHugo Santos 
271fb300cfdSHugo Santos 
272*3c13a5f5SAxel Dörfler /*!	You need to hold the domain lock when calling this function. */
2739206bb37SAxel Dörfler void
274c64feccaSHugo Santos domain_interface_went_down(net_interface* interface)
275c64feccaSHugo Santos {
276*3c13a5f5SAxel Dörfler 	ASSERT_LOCKED_MUTEX(&((net_domain_private*)interface->domain)->lock);
277c64feccaSHugo Santos 
278*3c13a5f5SAxel Dörfler 	TRACE(("domain_interface_went_down(%i, %s)\n",
279*3c13a5f5SAxel Dörfler 		interface->domain->family, interface->name));
280c64feccaSHugo Santos 
281c64feccaSHugo Santos 	invalidate_routes(interface->domain, interface);
282c64feccaSHugo Santos }
283c64feccaSHugo Santos 
284c64feccaSHugo Santos 
285c64feccaSHugo Santos void
286*3c13a5f5SAxel Dörfler domain_removed_device_interface(net_device_interface* deviceInterface)
287c64feccaSHugo Santos {
2882b07b8e0SIngo Weinhold 	MutexLocker locker(sDomainLock);
289c64feccaSHugo Santos 
290c64feccaSHugo Santos 	net_domain_private* domain = NULL;
291c64feccaSHugo Santos 	while (true) {
292c64feccaSHugo Santos 		domain = (net_domain_private*)list_get_next_item(&sDomains, domain);
293c64feccaSHugo Santos 		if (domain == NULL)
294c64feccaSHugo Santos 			break;
295c64feccaSHugo Santos 
2962b07b8e0SIngo Weinhold 		MutexLocker locker(domain->lock);
297c64feccaSHugo Santos 
298*3c13a5f5SAxel Dörfler 		net_interface_private* interface = find_interface(domain,
299*3c13a5f5SAxel Dörfler 			deviceInterface->device->name);
300*3c13a5f5SAxel Dörfler 		if (interface == NULL)
301c64feccaSHugo Santos 			continue;
302c64feccaSHugo Santos 
303*3c13a5f5SAxel Dörfler 		remove_interface_from_domain(interface);
304c64feccaSHugo Santos 	}
305c64feccaSHugo Santos }
306c64feccaSHugo Santos 
307c64feccaSHugo Santos 
308c22d69bfSAxel Dörfler status_t
309c22d69bfSAxel Dörfler register_domain(int family, const char* name,
310c22d69bfSAxel Dörfler 	struct net_protocol_module_info* module,
311c22d69bfSAxel Dörfler 	struct net_address_module_info* addressModule,
312c22d69bfSAxel Dörfler 	net_domain** _domain)
313c22d69bfSAxel Dörfler {
314c22d69bfSAxel Dörfler 	TRACE(("register_domain(%d, %s)\n", family, name));
3152b07b8e0SIngo Weinhold 	MutexLocker locker(sDomainLock);
316c22d69bfSAxel Dörfler 
317c22d69bfSAxel Dörfler 	struct net_domain_private* domain = lookup_domain(family);
318c22d69bfSAxel Dörfler 	if (domain != NULL)
319c22d69bfSAxel Dörfler 		return B_NAME_IN_USE;
320c22d69bfSAxel Dörfler 
321c22d69bfSAxel Dörfler 	domain = new(std::nothrow) net_domain_private;
322c22d69bfSAxel Dörfler 	if (domain == NULL)
323c22d69bfSAxel Dörfler 		return B_NO_MEMORY;
324c22d69bfSAxel Dörfler 
325*3c13a5f5SAxel Dörfler 	mutex_init(&domain->lock, name);
326c22d69bfSAxel Dörfler 
327c22d69bfSAxel Dörfler 	domain->family = family;
328c22d69bfSAxel Dörfler 	domain->name = name;
329c22d69bfSAxel Dörfler 	domain->module = module;
330c22d69bfSAxel Dörfler 	domain->address_module = addressModule;
331c22d69bfSAxel Dörfler 
332c22d69bfSAxel Dörfler 	list_init(&domain->interfaces);
333c22d69bfSAxel Dörfler 
334c22d69bfSAxel Dörfler 	list_add_item(&sDomains, domain);
335c22d69bfSAxel Dörfler 
336c22d69bfSAxel Dörfler 	*_domain = domain;
337c22d69bfSAxel Dörfler 	return B_OK;
338c22d69bfSAxel Dörfler }
339c22d69bfSAxel Dörfler 
340c22d69bfSAxel Dörfler 
341c22d69bfSAxel Dörfler status_t
342c22d69bfSAxel Dörfler unregister_domain(net_domain* _domain)
343c22d69bfSAxel Dörfler {
344*3c13a5f5SAxel Dörfler 	TRACE(("unregister_domain(%p, %d, %s)\n", _domain, _domain->family,
345*3c13a5f5SAxel Dörfler 		_domain->name));
346c22d69bfSAxel Dörfler 
347c22d69bfSAxel Dörfler 	net_domain_private* domain = (net_domain_private*)_domain;
3482b07b8e0SIngo Weinhold 	MutexLocker locker(sDomainLock);
349c22d69bfSAxel Dörfler 
350c22d69bfSAxel Dörfler 	list_remove_item(&sDomains, domain);
351c22d69bfSAxel Dörfler 
352c22d69bfSAxel Dörfler 	net_interface_private* interface = NULL;
353c22d69bfSAxel Dörfler 	while (true) {
354*3c13a5f5SAxel Dörfler 		interface = (net_interface_private*)list_remove_head_item(
355*3c13a5f5SAxel Dörfler 			&domain->interfaces);
356c22d69bfSAxel Dörfler 		if (interface == NULL)
357c22d69bfSAxel Dörfler 			break;
358c22d69bfSAxel Dörfler 
359c22d69bfSAxel Dörfler 		delete_interface(interface);
360c22d69bfSAxel Dörfler 	}
361c22d69bfSAxel Dörfler 
3622b07b8e0SIngo Weinhold 	mutex_destroy(&domain->lock);
363c22d69bfSAxel Dörfler 	delete domain;
364c22d69bfSAxel Dörfler 	return B_OK;
365c22d69bfSAxel Dörfler }
366c22d69bfSAxel Dörfler 
367c22d69bfSAxel Dörfler 
368c22d69bfSAxel Dörfler status_t
369c22d69bfSAxel Dörfler init_domains()
370c22d69bfSAxel Dörfler {
3712b07b8e0SIngo Weinhold 	mutex_init(&sDomainLock, "net domains");
372c22d69bfSAxel Dörfler 
373c22d69bfSAxel Dörfler 	list_init_etc(&sDomains, offsetof(struct net_domain_private, link));
374c22d69bfSAxel Dörfler 	return B_OK;
375c22d69bfSAxel Dörfler }
376c22d69bfSAxel Dörfler 
377c22d69bfSAxel Dörfler 
378c22d69bfSAxel Dörfler status_t
379c22d69bfSAxel Dörfler uninit_domains()
380c22d69bfSAxel Dörfler {
3812b07b8e0SIngo Weinhold 	mutex_destroy(&sDomainLock);
382c22d69bfSAxel Dörfler 	return B_OK;
383c22d69bfSAxel Dörfler }
384c22d69bfSAxel Dörfler 
385