xref: /haiku/src/add-ons/kernel/network/stack/domains.cpp (revision 26153d0f67e36b509dade3b8aed43ba7b753578b)
1c22d69bfSAxel Dörfler /*
23c13a5f5SAxel 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 
39*26153d0fSAxel Dörfler /*!	Scans the domain list for the specified family.
40c22d69bfSAxel Dörfler 	You need to hold the sDomainLock when calling this function.
41c22d69bfSAxel Dörfler */
42c22d69bfSAxel Dörfler static net_domain_private*
43c22d69bfSAxel Dörfler lookup_domain(int family)
44c22d69bfSAxel Dörfler {
45c22d69bfSAxel Dörfler 	net_domain_private* domain = NULL;
46c22d69bfSAxel Dörfler 	while (true) {
47c22d69bfSAxel Dörfler 		domain = (net_domain_private*)list_get_next_item(&sDomains, domain);
48c22d69bfSAxel Dörfler 		if (domain == NULL)
49c22d69bfSAxel Dörfler 			break;
50c22d69bfSAxel Dörfler 
51c22d69bfSAxel Dörfler 		if (domain->family == family)
52c22d69bfSAxel Dörfler 			return domain;
53c22d69bfSAxel Dörfler 	}
54c22d69bfSAxel Dörfler 
55c22d69bfSAxel Dörfler 	return NULL;
56c22d69bfSAxel Dörfler }
57c22d69bfSAxel Dörfler 
58c22d69bfSAxel Dörfler 
59c22d69bfSAxel Dörfler //	#pragma mark -
60c22d69bfSAxel Dörfler 
61c22d69bfSAxel Dörfler 
62*26153d0fSAxel Dörfler /*!	Gets the domain of the specified family.
63c22d69bfSAxel Dörfler */
64c22d69bfSAxel Dörfler net_domain*
65c22d69bfSAxel Dörfler get_domain(int family)
66c22d69bfSAxel Dörfler {
672b07b8e0SIngo Weinhold 	MutexLocker locker(sDomainLock);
68c22d69bfSAxel Dörfler 	return lookup_domain(family);
69c22d69bfSAxel Dörfler }
70c22d69bfSAxel Dörfler 
71c22d69bfSAxel Dörfler 
72c22d69bfSAxel Dörfler uint32
73c22d69bfSAxel Dörfler count_domain_interfaces()
74c22d69bfSAxel Dörfler {
752b07b8e0SIngo Weinhold 	MutexLocker locker(sDomainLock);
76c22d69bfSAxel Dörfler 
77c22d69bfSAxel Dörfler 	net_domain_private* domain = NULL;
78c22d69bfSAxel Dörfler 	uint32 count = 0;
79c22d69bfSAxel Dörfler 
80c22d69bfSAxel Dörfler 	while (true) {
81c22d69bfSAxel Dörfler 		domain = (net_domain_private*)list_get_next_item(&sDomains, domain);
82c22d69bfSAxel Dörfler 		if (domain == NULL)
83c22d69bfSAxel Dörfler 			break;
84c22d69bfSAxel Dörfler 
85c22d69bfSAxel Dörfler 		net_interface* interface = NULL;
86c22d69bfSAxel Dörfler 		while (true) {
87c22d69bfSAxel Dörfler 			interface = (net_interface*)list_get_next_item(&domain->interfaces,
88c22d69bfSAxel Dörfler 				interface);
89c22d69bfSAxel Dörfler 			if (interface == NULL)
90c22d69bfSAxel Dörfler 				break;
91c22d69bfSAxel Dörfler 
92c22d69bfSAxel Dörfler 			count++;
93c22d69bfSAxel Dörfler 		}
94c22d69bfSAxel Dörfler 	}
95c22d69bfSAxel Dörfler 
96c22d69bfSAxel Dörfler 	return count;
97c22d69bfSAxel Dörfler }
98c22d69bfSAxel Dörfler 
99c22d69bfSAxel Dörfler 
100c22d69bfSAxel Dörfler /*!
101c22d69bfSAxel Dörfler 	Dumps a list of all interfaces into the supplied userland buffer.
102c22d69bfSAxel Dörfler 	If the interfaces don't fit into the buffer, an error (\c ENOBUFS) is
103c22d69bfSAxel Dörfler 	returned.
104c22d69bfSAxel Dörfler */
105c22d69bfSAxel Dörfler status_t
106409b1fc0SHugo Santos list_domain_interfaces(void* _buffer, size_t* bufferSize)
107c22d69bfSAxel Dörfler {
1082b07b8e0SIngo Weinhold 	MutexLocker locker(sDomainLock);
109c22d69bfSAxel Dörfler 
110409b1fc0SHugo Santos 	UserBuffer buffer(_buffer, *bufferSize);
111c22d69bfSAxel Dörfler 	net_domain_private* domain = NULL;
112c22d69bfSAxel Dörfler 
113c22d69bfSAxel Dörfler 	while (true) {
114c22d69bfSAxel Dörfler 		domain = (net_domain_private*)list_get_next_item(&sDomains, domain);
115c22d69bfSAxel Dörfler 		if (domain == NULL)
116c22d69bfSAxel Dörfler 			break;
117c22d69bfSAxel Dörfler 
118*26153d0fSAxel Dörfler 		RecursiveLocker locker(domain->lock);
1199206bb37SAxel Dörfler 
120c22d69bfSAxel Dörfler 		net_interface* interface = NULL;
121c22d69bfSAxel Dörfler 		while (true) {
122c22d69bfSAxel Dörfler 			interface = (net_interface*)list_get_next_item(&domain->interfaces,
123c22d69bfSAxel Dörfler 				interface);
124c22d69bfSAxel Dörfler 			if (interface == NULL)
125c22d69bfSAxel Dörfler 				break;
126c22d69bfSAxel Dörfler 
127c22d69bfSAxel Dörfler 			ifreq request;
128c22d69bfSAxel Dörfler 			strlcpy(request.ifr_name, interface->name, IF_NAMESIZE);
1299206bb37SAxel Dörfler 			if (interface->address != NULL) {
1309206bb37SAxel Dörfler 				memcpy(&request.ifr_addr, interface->address,
1319206bb37SAxel Dörfler 					interface->address->sa_len);
1329206bb37SAxel Dörfler 			} else {
133c22d69bfSAxel Dörfler 				// empty address
134c22d69bfSAxel Dörfler 				request.ifr_addr.sa_len = 2;
135c22d69bfSAxel Dörfler 				request.ifr_addr.sa_family = AF_UNSPEC;
136c22d69bfSAxel Dörfler 			}
137c22d69bfSAxel Dörfler 
138409b1fc0SHugo Santos 			if (buffer.Copy(&request, IF_NAMESIZE
139409b1fc0SHugo Santos 					+ request.ifr_addr.sa_len) == NULL)
140409b1fc0SHugo Santos 				return buffer.Status();
141c22d69bfSAxel Dörfler 		}
142c22d69bfSAxel Dörfler 	}
143c22d69bfSAxel Dörfler 
144409b1fc0SHugo Santos 	*bufferSize = buffer.ConsumedAmount();
145c22d69bfSAxel Dörfler 	return B_OK;
146c22d69bfSAxel Dörfler }
147c22d69bfSAxel Dörfler 
148c22d69bfSAxel Dörfler 
149c22d69bfSAxel Dörfler status_t
150c22d69bfSAxel Dörfler add_interface_to_domain(net_domain* _domain,
151c22d69bfSAxel Dörfler 	struct ifreq& request)
152c22d69bfSAxel Dörfler {
153c22d69bfSAxel Dörfler 	net_domain_private* domain = (net_domain_private*)_domain;
154c22d69bfSAxel Dörfler 
155c22d69bfSAxel Dörfler 	const char* deviceName = request.ifr_parameter.device[0]
156c22d69bfSAxel Dörfler 		? request.ifr_parameter.device : request.ifr_name;
15720b534cdSHugo Santos 	const char* baseName = request.ifr_parameter.base_name[0]
15820b534cdSHugo Santos 		? request.ifr_parameter.base_name : request.ifr_name;
15920b534cdSHugo Santos 
160c22d69bfSAxel Dörfler 	net_device_interface* deviceInterface = get_device_interface(deviceName);
161c22d69bfSAxel Dörfler 	if (deviceInterface == NULL)
162c22d69bfSAxel Dörfler 		return ENODEV;
163c22d69bfSAxel Dörfler 
164*26153d0fSAxel Dörfler 	RecursiveLocker locker(domain->lock);
165c22d69bfSAxel Dörfler 
16620b534cdSHugo Santos 	net_interface_private* interface = NULL;
16720b534cdSHugo Santos 	status_t status;
16820b534cdSHugo Santos 
169a3513e7bSAxel Dörfler 	if (find_interface(domain, request.ifr_name) == NULL) {
170a3513e7bSAxel Dörfler 		// We must not hold the domain's link when creating the interface:
171a3513e7bSAxel Dörfler 		// this will call get_module() which might want to access a network
172a3513e7bSAxel Dörfler 		// device when booting from network.
173a3513e7bSAxel Dörfler 		locker.Unlock();
17420b534cdSHugo Santos 		status = create_interface(domain, request.ifr_name,
17520b534cdSHugo Santos 			baseName, deviceInterface, &interface);
176a3513e7bSAxel Dörfler 		locker.Lock();
177a3513e7bSAxel Dörfler 
178a3513e7bSAxel Dörfler 		if (find_interface(domain, request.ifr_name) != NULL) {
179a3513e7bSAxel Dörfler 			delete_interface(interface);
180a3513e7bSAxel Dörfler 			status = B_NAME_IN_USE;
181a3513e7bSAxel Dörfler 		}
182a3513e7bSAxel Dörfler 	} else
183a3513e7bSAxel Dörfler 		status = B_NAME_IN_USE;
184c22d69bfSAxel Dörfler 
185c22d69bfSAxel Dörfler 	put_device_interface(deviceInterface);
186c22d69bfSAxel Dörfler 
187d68ffdedSAxel Dörfler 	if (status == B_OK) {
188c22d69bfSAxel Dörfler 		list_add_item(&domain->interfaces, interface);
189d68ffdedSAxel Dörfler 		notify_interface_added(interface);
190d68ffdedSAxel Dörfler 	}
19120b534cdSHugo Santos 
19220b534cdSHugo Santos 	return status;
193c22d69bfSAxel Dörfler }
194c22d69bfSAxel Dörfler 
195c22d69bfSAxel Dörfler 
196c22d69bfSAxel Dörfler /*!
197c22d69bfSAxel Dörfler 	Removes the interface from its domain, and deletes it.
198c22d69bfSAxel Dörfler 	You need to hold the domain's lock when calling this function.
199c22d69bfSAxel Dörfler */
200c22d69bfSAxel Dörfler status_t
201c22d69bfSAxel Dörfler remove_interface_from_domain(net_interface* interface)
202c22d69bfSAxel Dörfler {
203c22d69bfSAxel Dörfler 	net_domain_private* domain = (net_domain_private*)interface->domain;
204c22d69bfSAxel Dörfler 
205c22d69bfSAxel Dörfler 	list_remove_item(&domain->interfaces, interface);
206d68ffdedSAxel Dörfler 	notify_interface_removed(interface);
207c22d69bfSAxel Dörfler 	delete_interface((net_interface_private*)interface);
208c22d69bfSAxel Dörfler 	return B_OK;
209c22d69bfSAxel Dörfler }
210c22d69bfSAxel Dörfler 
211c22d69bfSAxel Dörfler 
212fb300cfdSHugo Santos status_t
213fb300cfdSHugo Santos domain_interface_control(net_domain_private* domain, int32 option,
214fb300cfdSHugo Santos 	ifreq* request)
215fb300cfdSHugo Santos {
216fb300cfdSHugo Santos 	const char* name = request->ifr_name;
217fb300cfdSHugo Santos 	status_t status = B_OK;
218fb300cfdSHugo Santos 
219fb300cfdSHugo Santos 	net_device_interface* device = get_device_interface(name, false);
220fb300cfdSHugo Santos 	if (device == NULL)
221fb300cfdSHugo Santos 		return ENODEV;
2223c13a5f5SAxel Dörfler 
2233c13a5f5SAxel Dörfler 	// The locking protocol dictates that if both the receive lock
2243c13a5f5SAxel Dörfler 	// and domain locks are required, we MUST obtain the receive
2253c13a5f5SAxel Dörfler 	// lock before the domain lock.
2263c13a5f5SAxel Dörfler 	RecursiveLocker _1(device->receive_lock);
227*26153d0fSAxel Dörfler 	RecursiveLocker _2(domain->lock);
228fb300cfdSHugo Santos 
229fb300cfdSHugo Santos 	net_interface* interface = find_interface(domain, name);
230fb300cfdSHugo Santos 	if (interface != NULL) {
231fb300cfdSHugo Santos 		switch (option) {
232fb300cfdSHugo Santos 			case SIOCDIFADDR:
233fb300cfdSHugo Santos 				remove_interface_from_domain(interface);
234fb300cfdSHugo Santos 				break;
235fb300cfdSHugo Santos 
236fb300cfdSHugo Santos 			case SIOCSIFFLAGS:
237ae074c5dSHugo Santos 			{
238ae074c5dSHugo Santos 				uint32 requestFlags = request->ifr_flags;
239ae074c5dSHugo Santos 				request->ifr_flags &= ~(IFF_UP | IFF_LINK | IFF_BROADCAST);
240ae074c5dSHugo Santos 
241ae074c5dSHugo Santos 				if ((requestFlags & IFF_UP) != (interface->flags & IFF_UP)) {
242ae074c5dSHugo Santos 					if (requestFlags & IFF_UP) {
243fb300cfdSHugo Santos 						status = interface->first_info->interface_up(
244fb300cfdSHugo Santos 							interface->first_protocol);
245ae074c5dSHugo Santos 						if (status == B_OK)
246fb300cfdSHugo Santos 							interface->flags |= IFF_UP;
247ae074c5dSHugo Santos 					} else {
248ae074c5dSHugo Santos 						interface_set_down(interface);
249fb300cfdSHugo Santos 					}
250fb300cfdSHugo Santos 				}
251fb300cfdSHugo Santos 
25274ff314bSAxel Dörfler 				if (status == B_OK) {
25374ff314bSAxel Dörfler 					// TODO: why shouldn't we able to delete IFF_BROADCAST?
25474ff314bSAxel Dörfler 					interface->flags &= IFF_UP | IFF_LINK | IFF_BROADCAST;
255ae074c5dSHugo Santos 					interface->flags |= request->ifr_flags;
25674ff314bSAxel Dörfler 				}
257fb300cfdSHugo Santos 				break;
258fb300cfdSHugo Santos 			}
259fb300cfdSHugo Santos 		}
260fb300cfdSHugo Santos 	}
261fb300cfdSHugo Santos 
2623c13a5f5SAxel Dörfler 	// If the SIOCDIFADDR call above removed the last interface associated with
2633c13a5f5SAxel Dörfler 	// the device interface, this will effectively remove the interface
264fb300cfdSHugo Santos 	put_device_interface(device);
265fb300cfdSHugo Santos 
266fb300cfdSHugo Santos 	return status;
267fb300cfdSHugo Santos }
268fb300cfdSHugo Santos 
269fb300cfdSHugo Santos 
2703c13a5f5SAxel Dörfler /*!	You need to hold the domain lock when calling this function. */
2719206bb37SAxel Dörfler void
272c64feccaSHugo Santos domain_interface_went_down(net_interface* interface)
273c64feccaSHugo Santos {
274*26153d0fSAxel Dörfler 	ASSERT_LOCKED_RECURSIVE(&((net_domain_private*)interface->domain)->lock);
275c64feccaSHugo Santos 
2763c13a5f5SAxel Dörfler 	TRACE(("domain_interface_went_down(%i, %s)\n",
2773c13a5f5SAxel Dörfler 		interface->domain->family, interface->name));
278c64feccaSHugo Santos 
279c64feccaSHugo Santos 	invalidate_routes(interface->domain, interface);
280c64feccaSHugo Santos }
281c64feccaSHugo Santos 
282c64feccaSHugo Santos 
283c64feccaSHugo Santos void
2843c13a5f5SAxel Dörfler domain_removed_device_interface(net_device_interface* deviceInterface)
285c64feccaSHugo Santos {
2862b07b8e0SIngo Weinhold 	MutexLocker locker(sDomainLock);
287c64feccaSHugo Santos 
288c64feccaSHugo Santos 	net_domain_private* domain = NULL;
289c64feccaSHugo Santos 	while (true) {
290c64feccaSHugo Santos 		domain = (net_domain_private*)list_get_next_item(&sDomains, domain);
291c64feccaSHugo Santos 		if (domain == NULL)
292c64feccaSHugo Santos 			break;
293c64feccaSHugo Santos 
294*26153d0fSAxel Dörfler 		RecursiveLocker locker(domain->lock);
295c64feccaSHugo Santos 
2963c13a5f5SAxel Dörfler 		net_interface_private* interface = find_interface(domain,
2973c13a5f5SAxel Dörfler 			deviceInterface->device->name);
2983c13a5f5SAxel Dörfler 		if (interface == NULL)
299c64feccaSHugo Santos 			continue;
300c64feccaSHugo Santos 
3013c13a5f5SAxel Dörfler 		remove_interface_from_domain(interface);
302c64feccaSHugo Santos 	}
303c64feccaSHugo Santos }
304c64feccaSHugo Santos 
305c64feccaSHugo Santos 
306c22d69bfSAxel Dörfler status_t
307c22d69bfSAxel Dörfler register_domain(int family, const char* name,
308c22d69bfSAxel Dörfler 	struct net_protocol_module_info* module,
309c22d69bfSAxel Dörfler 	struct net_address_module_info* addressModule,
310c22d69bfSAxel Dörfler 	net_domain** _domain)
311c22d69bfSAxel Dörfler {
312c22d69bfSAxel Dörfler 	TRACE(("register_domain(%d, %s)\n", family, name));
3132b07b8e0SIngo Weinhold 	MutexLocker locker(sDomainLock);
314c22d69bfSAxel Dörfler 
315c22d69bfSAxel Dörfler 	struct net_domain_private* domain = lookup_domain(family);
316c22d69bfSAxel Dörfler 	if (domain != NULL)
317c22d69bfSAxel Dörfler 		return B_NAME_IN_USE;
318c22d69bfSAxel Dörfler 
319c22d69bfSAxel Dörfler 	domain = new(std::nothrow) net_domain_private;
320c22d69bfSAxel Dörfler 	if (domain == NULL)
321c22d69bfSAxel Dörfler 		return B_NO_MEMORY;
322c22d69bfSAxel Dörfler 
323*26153d0fSAxel Dörfler 	recursive_lock_init(&domain->lock, name);
324c22d69bfSAxel Dörfler 
325c22d69bfSAxel Dörfler 	domain->family = family;
326c22d69bfSAxel Dörfler 	domain->name = name;
327c22d69bfSAxel Dörfler 	domain->module = module;
328c22d69bfSAxel Dörfler 	domain->address_module = addressModule;
329c22d69bfSAxel Dörfler 
330c22d69bfSAxel Dörfler 	list_init(&domain->interfaces);
331c22d69bfSAxel Dörfler 
332c22d69bfSAxel Dörfler 	list_add_item(&sDomains, domain);
333c22d69bfSAxel Dörfler 
334c22d69bfSAxel Dörfler 	*_domain = domain;
335c22d69bfSAxel Dörfler 	return B_OK;
336c22d69bfSAxel Dörfler }
337c22d69bfSAxel Dörfler 
338c22d69bfSAxel Dörfler 
339c22d69bfSAxel Dörfler status_t
340c22d69bfSAxel Dörfler unregister_domain(net_domain* _domain)
341c22d69bfSAxel Dörfler {
3423c13a5f5SAxel Dörfler 	TRACE(("unregister_domain(%p, %d, %s)\n", _domain, _domain->family,
3433c13a5f5SAxel Dörfler 		_domain->name));
344c22d69bfSAxel Dörfler 
345c22d69bfSAxel Dörfler 	net_domain_private* domain = (net_domain_private*)_domain;
3462b07b8e0SIngo Weinhold 	MutexLocker locker(sDomainLock);
347c22d69bfSAxel Dörfler 
348c22d69bfSAxel Dörfler 	list_remove_item(&sDomains, domain);
349c22d69bfSAxel Dörfler 
350c22d69bfSAxel Dörfler 	net_interface_private* interface = NULL;
351c22d69bfSAxel Dörfler 	while (true) {
3523c13a5f5SAxel Dörfler 		interface = (net_interface_private*)list_remove_head_item(
3533c13a5f5SAxel Dörfler 			&domain->interfaces);
354c22d69bfSAxel Dörfler 		if (interface == NULL)
355c22d69bfSAxel Dörfler 			break;
356c22d69bfSAxel Dörfler 
357c22d69bfSAxel Dörfler 		delete_interface(interface);
358c22d69bfSAxel Dörfler 	}
359c22d69bfSAxel Dörfler 
360*26153d0fSAxel Dörfler 	recursive_lock_destroy(&domain->lock);
361c22d69bfSAxel Dörfler 	delete domain;
362c22d69bfSAxel Dörfler 	return B_OK;
363c22d69bfSAxel Dörfler }
364c22d69bfSAxel Dörfler 
365c22d69bfSAxel Dörfler 
366c22d69bfSAxel Dörfler status_t
367c22d69bfSAxel Dörfler init_domains()
368c22d69bfSAxel Dörfler {
3692b07b8e0SIngo Weinhold 	mutex_init(&sDomainLock, "net domains");
370c22d69bfSAxel Dörfler 
371c22d69bfSAxel Dörfler 	list_init_etc(&sDomains, offsetof(struct net_domain_private, link));
372c22d69bfSAxel Dörfler 	return B_OK;
373c22d69bfSAxel Dörfler }
374c22d69bfSAxel Dörfler 
375c22d69bfSAxel Dörfler 
376c22d69bfSAxel Dörfler status_t
377c22d69bfSAxel Dörfler uninit_domains()
378c22d69bfSAxel Dörfler {
3792b07b8e0SIngo Weinhold 	mutex_destroy(&sDomainLock);
380c22d69bfSAxel Dörfler 	return B_OK;
381c22d69bfSAxel Dörfler }
382c22d69bfSAxel Dörfler 
383