xref: /haiku/src/add-ons/kernel/network/stack/domains.cpp (revision 2b07b8e0f1a7f1e76f31db24a21a42cbb01d7b9c)
1c22d69bfSAxel Dörfler /*
29c4477d3SAxel Dörfler  * Copyright 2006-2007, 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 
35*2b07b8e0SIngo 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 {
69*2b07b8e0SIngo 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 {
77*2b07b8e0SIngo 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 {
110*2b07b8e0SIngo 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 
120*2b07b8e0SIngo 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 
166*2b07b8e0SIngo Weinhold 	MutexLocker locker(domain->lock);
167c22d69bfSAxel Dörfler 
16820b534cdSHugo Santos 	net_interface_private *interface = NULL;
16920b534cdSHugo Santos 	status_t status;
17020b534cdSHugo Santos 
171c22d69bfSAxel Dörfler 	if (find_interface(domain, request.ifr_name) != NULL)
17220b534cdSHugo Santos 		status = B_NAME_IN_USE;
17320b534cdSHugo Santos 	else
17420b534cdSHugo Santos 		status = create_interface(domain, request.ifr_name,
17520b534cdSHugo Santos 			baseName, deviceInterface, &interface);
176c22d69bfSAxel Dörfler 
177c22d69bfSAxel Dörfler 	put_device_interface(deviceInterface);
178c22d69bfSAxel Dörfler 
17920b534cdSHugo Santos 	if (status == B_OK)
180c22d69bfSAxel Dörfler 		list_add_item(&domain->interfaces, interface);
18120b534cdSHugo Santos 
18220b534cdSHugo Santos 	return status;
183c22d69bfSAxel Dörfler }
184c22d69bfSAxel Dörfler 
185c22d69bfSAxel Dörfler 
186c22d69bfSAxel Dörfler /*!
187c22d69bfSAxel Dörfler 	Removes the interface from its domain, and deletes it.
188c22d69bfSAxel Dörfler 	You need to hold the domain's lock when calling this function.
189c22d69bfSAxel Dörfler */
190c22d69bfSAxel Dörfler status_t
191c22d69bfSAxel Dörfler remove_interface_from_domain(net_interface *interface)
192c22d69bfSAxel Dörfler {
193c22d69bfSAxel Dörfler 	net_domain_private *domain = (net_domain_private *)interface->domain;
194c22d69bfSAxel Dörfler 
195c22d69bfSAxel Dörfler 	list_remove_item(&domain->interfaces, interface);
196c22d69bfSAxel Dörfler 	delete_interface((net_interface_private *)interface);
197c22d69bfSAxel Dörfler 	return B_OK;
198c22d69bfSAxel Dörfler }
199c22d69bfSAxel Dörfler 
200c22d69bfSAxel Dörfler 
201fb300cfdSHugo Santos status_t
202fb300cfdSHugo Santos domain_interface_control(net_domain_private *domain, int32 option,
203fb300cfdSHugo Santos 	ifreq *request)
204fb300cfdSHugo Santos {
205fb300cfdSHugo Santos 	const char *name = request->ifr_name;
206fb300cfdSHugo Santos 	status_t status = B_OK;
207fb300cfdSHugo Santos 
208fb300cfdSHugo Santos 	net_device_interface *device = get_device_interface(name, false);
209fb300cfdSHugo Santos 	if (device == NULL)
210fb300cfdSHugo Santos 		return ENODEV;
211fb300cfdSHugo Santos 	else {
212fb300cfdSHugo Santos 		// The locking protocol dictates that if both the RX lock
213fb300cfdSHugo Santos 		// and domain locks are required, we MUST obtain the RX
214fb300cfdSHugo Santos 		// lock before the domain lock. This order MUST NOT ever
215fb300cfdSHugo Santos 		// be reversed under the penalty of deadlock.
21664734690SHugo Santos 		RecursiveLocker _1(device->rx_lock);
217*2b07b8e0SIngo Weinhold 		MutexLocker _2(domain->lock);
218fb300cfdSHugo Santos 
219fb300cfdSHugo Santos 		net_interface *interface = find_interface(domain, name);
220fb300cfdSHugo Santos 		if (interface != NULL) {
221fb300cfdSHugo Santos 			switch (option) {
222fb300cfdSHugo Santos 				case SIOCDIFADDR:
223fb300cfdSHugo Santos 					remove_interface_from_domain(interface);
224fb300cfdSHugo Santos 					break;
225fb300cfdSHugo Santos 
226fb300cfdSHugo Santos 				case SIOCSIFFLAGS:
227ae074c5dSHugo Santos 				{
228ae074c5dSHugo Santos 					uint32 requestFlags = request->ifr_flags;
229ae074c5dSHugo Santos 					request->ifr_flags &= ~(IFF_UP | IFF_LINK | IFF_BROADCAST);
230ae074c5dSHugo Santos 
231ae074c5dSHugo Santos 					if ((requestFlags & IFF_UP) != (interface->flags & IFF_UP)) {
232ae074c5dSHugo Santos 						if (requestFlags & IFF_UP) {
233fb300cfdSHugo Santos 							status = interface->first_info->interface_up(
234fb300cfdSHugo Santos 								interface->first_protocol);
235ae074c5dSHugo Santos 							if (status == B_OK)
236fb300cfdSHugo Santos 								interface->flags |= IFF_UP;
237ae074c5dSHugo Santos 						} else {
238ae074c5dSHugo Santos 							interface_set_down(interface);
239fb300cfdSHugo Santos 						}
240fb300cfdSHugo Santos 					}
241fb300cfdSHugo Santos 
242fb300cfdSHugo Santos 					if (status == B_OK)
243ae074c5dSHugo Santos 						interface->flags |= request->ifr_flags;
244fb300cfdSHugo Santos 					break;
245fb300cfdSHugo Santos 				}
246fb300cfdSHugo Santos 			}
247fb300cfdSHugo Santos 		}
248ae074c5dSHugo Santos 	}
249fb300cfdSHugo Santos 
250fb300cfdSHugo Santos 	// If the SIOCDIFADDR call above removed the last interface
251fb300cfdSHugo Santos 	// associated with the device interface, this put_() will
252fb300cfdSHugo Santos 	// effectively remove the interface
253fb300cfdSHugo Santos 	put_device_interface(device);
254fb300cfdSHugo Santos 
255fb300cfdSHugo Santos 	return status;
256fb300cfdSHugo Santos }
257fb300cfdSHugo Santos 
258fb300cfdSHugo Santos 
2599206bb37SAxel Dörfler void
260c64feccaSHugo Santos domain_interface_went_down(net_interface *interface)
261c64feccaSHugo Santos {
262c64feccaSHugo Santos 	// the domain should be locked here. always check
263c64feccaSHugo Santos 	// all callers to be sure. We get here via
264c64feccaSHugo Santos 	// interface_set_down().
265c64feccaSHugo Santos 
266c64feccaSHugo Santos 	dprintf("domain_interface_went_down(%i, %s)\n",
267c64feccaSHugo Santos 		interface->domain->family, interface->name);
268c64feccaSHugo Santos 
269c64feccaSHugo Santos 	// domain might have been locked by:
270c64feccaSHugo Santos 	//  - domain_removed_device_interface() <--- here
271c64feccaSHugo Santos 	//     remove_interface_from_domain()
272c64feccaSHugo Santos 	//      delete_interface()
273c64feccaSHugo Santos 	//       interface_set_down()
274c64feccaSHugo Santos 	//  - datalink_control() <--- here
275c64feccaSHugo Santos 	//     interface_set_down()
276c64feccaSHugo Santos 	invalidate_routes(interface->domain, interface);
277c64feccaSHugo Santos }
278c64feccaSHugo Santos 
279c64feccaSHugo Santos 
280c64feccaSHugo Santos void
281c64feccaSHugo Santos domain_removed_device_interface(net_device_interface *interface)
282c64feccaSHugo Santos {
283*2b07b8e0SIngo Weinhold 	MutexLocker locker(sDomainLock);
284c64feccaSHugo Santos 
285c64feccaSHugo Santos 	net_domain_private *domain = NULL;
286c64feccaSHugo Santos 	while (true) {
287c64feccaSHugo Santos 		domain = (net_domain_private *)list_get_next_item(&sDomains, domain);
288c64feccaSHugo Santos 		if (domain == NULL)
289c64feccaSHugo Santos 			break;
290c64feccaSHugo Santos 
291*2b07b8e0SIngo Weinhold 		MutexLocker locker(domain->lock);
292c64feccaSHugo Santos 
293be2f6ac3SHugo Santos 		net_interface_private *priv = find_interface(domain,
294be2f6ac3SHugo Santos 			interface->device->name);
295c64feccaSHugo Santos 		if (priv == NULL)
296c64feccaSHugo Santos 			continue;
297c64feccaSHugo Santos 
298c64feccaSHugo Santos 		remove_interface_from_domain(priv);
299c64feccaSHugo Santos 	}
300c64feccaSHugo Santos }
301c64feccaSHugo Santos 
302c64feccaSHugo Santos 
303c22d69bfSAxel Dörfler status_t
304c22d69bfSAxel Dörfler register_domain(int family, const char *name,
305c22d69bfSAxel Dörfler 	struct net_protocol_module_info *module,
306c22d69bfSAxel Dörfler 	struct net_address_module_info *addressModule,
307c22d69bfSAxel Dörfler 	net_domain **_domain)
308c22d69bfSAxel Dörfler {
309c22d69bfSAxel Dörfler 	TRACE(("register_domain(%d, %s)\n", family, name));
310*2b07b8e0SIngo Weinhold 	MutexLocker locker(sDomainLock);
311c22d69bfSAxel Dörfler 
312c22d69bfSAxel Dörfler 	struct net_domain_private *domain = lookup_domain(family);
313c22d69bfSAxel Dörfler 	if (domain != NULL)
314c22d69bfSAxel Dörfler 		return B_NAME_IN_USE;
315c22d69bfSAxel Dörfler 
316c22d69bfSAxel Dörfler 	domain = new (std::nothrow) net_domain_private;
317c22d69bfSAxel Dörfler 	if (domain == NULL)
318c22d69bfSAxel Dörfler 		return B_NO_MEMORY;
319c22d69bfSAxel Dörfler 
320*2b07b8e0SIngo Weinhold 	mutex_init_etc(&domain->lock, name, MUTEX_FLAG_CLONE_NAME);
321c22d69bfSAxel Dörfler 
322c22d69bfSAxel Dörfler 	domain->family = family;
323c22d69bfSAxel Dörfler 	domain->name = name;
324c22d69bfSAxel Dörfler 	domain->module = module;
325c22d69bfSAxel Dörfler 	domain->address_module = addressModule;
326c22d69bfSAxel Dörfler 
327c22d69bfSAxel Dörfler 	list_init(&domain->interfaces);
328c22d69bfSAxel Dörfler 
329c22d69bfSAxel Dörfler 	list_add_item(&sDomains, domain);
330c22d69bfSAxel Dörfler 
331c22d69bfSAxel Dörfler 	*_domain = domain;
332c22d69bfSAxel Dörfler 	return B_OK;
333c22d69bfSAxel Dörfler }
334c22d69bfSAxel Dörfler 
335c22d69bfSAxel Dörfler 
336c22d69bfSAxel Dörfler status_t
337c22d69bfSAxel Dörfler unregister_domain(net_domain *_domain)
338c22d69bfSAxel Dörfler {
339c22d69bfSAxel Dörfler 	TRACE(("unregister_domain(%p, %d, %s)\n", _domain, _domain->family, _domain->name));
340c22d69bfSAxel Dörfler 
341c22d69bfSAxel Dörfler 	net_domain_private *domain = (net_domain_private *)_domain;
342*2b07b8e0SIngo Weinhold 	MutexLocker locker(sDomainLock);
343c22d69bfSAxel Dörfler 
344c22d69bfSAxel Dörfler 	list_remove_item(&sDomains, domain);
345c22d69bfSAxel Dörfler 
346c22d69bfSAxel Dörfler 	net_interface_private *interface = NULL;
347c22d69bfSAxel Dörfler 	while (true) {
348c22d69bfSAxel Dörfler 		interface = (net_interface_private *)list_remove_head_item(&domain->interfaces);
349c22d69bfSAxel Dörfler 		if (interface == NULL)
350c22d69bfSAxel Dörfler 			break;
351c22d69bfSAxel Dörfler 
352c22d69bfSAxel Dörfler 		delete_interface(interface);
353c22d69bfSAxel Dörfler 	}
354c22d69bfSAxel Dörfler 
355*2b07b8e0SIngo Weinhold 	mutex_destroy(&domain->lock);
356c22d69bfSAxel Dörfler 	delete domain;
357c22d69bfSAxel Dörfler 	return B_OK;
358c22d69bfSAxel Dörfler }
359c22d69bfSAxel Dörfler 
360c22d69bfSAxel Dörfler 
361c22d69bfSAxel Dörfler status_t
362c22d69bfSAxel Dörfler init_domains()
363c22d69bfSAxel Dörfler {
364*2b07b8e0SIngo Weinhold 	mutex_init(&sDomainLock, "net domains");
365c22d69bfSAxel Dörfler 
366c22d69bfSAxel Dörfler 	list_init_etc(&sDomains, offsetof(struct net_domain_private, link));
367c22d69bfSAxel Dörfler 	return B_OK;
368c22d69bfSAxel Dörfler }
369c22d69bfSAxel Dörfler 
370c22d69bfSAxel Dörfler 
371c22d69bfSAxel Dörfler status_t
372c22d69bfSAxel Dörfler uninit_domains()
373c22d69bfSAxel Dörfler {
374*2b07b8e0SIngo Weinhold 	mutex_destroy(&sDomainLock);
375c22d69bfSAxel Dörfler 	return B_OK;
376c22d69bfSAxel Dörfler }
377c22d69bfSAxel Dörfler 
378