xref: /haiku/src/add-ons/kernel/network/stack/domains.cpp (revision c64fecca780b8dcf6ce2cb5994977a79e14ce936)
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"
13c22d69bfSAxel Dörfler 
149206bb37SAxel Dörfler #include <net_device.h>
15c22d69bfSAxel Dörfler 
16c22d69bfSAxel Dörfler #include <lock.h>
17c22d69bfSAxel Dörfler #include <util/AutoLock.h>
18c22d69bfSAxel Dörfler 
199206bb37SAxel Dörfler #include <KernelExport.h>
209206bb37SAxel Dörfler 
219206bb37SAxel Dörfler #include <net/if_media.h>
22c22d69bfSAxel Dörfler #include <new>
23c22d69bfSAxel Dörfler #include <string.h>
24c22d69bfSAxel Dörfler 
25c22d69bfSAxel Dörfler 
26c22d69bfSAxel Dörfler #define TRACE_DOMAINS
27c22d69bfSAxel Dörfler #ifdef TRACE_DOMAINS
28c22d69bfSAxel Dörfler #	define TRACE(x) dprintf x
29c22d69bfSAxel Dörfler #else
30c22d69bfSAxel Dörfler #	define TRACE(x) ;
31c22d69bfSAxel Dörfler #endif
32c22d69bfSAxel Dörfler 
33c22d69bfSAxel Dörfler static benaphore sDomainLock;
34c22d69bfSAxel Dörfler static list sDomains;
35c22d69bfSAxel Dörfler 
36c22d69bfSAxel Dörfler 
37c22d69bfSAxel Dörfler /*!
38c22d69bfSAxel Dörfler 	Scans the domain list for the specified family.
39c22d69bfSAxel Dörfler 	You need to hold the sDomainLock when calling this function.
40c22d69bfSAxel Dörfler */
41c22d69bfSAxel Dörfler static net_domain_private *
42c22d69bfSAxel Dörfler lookup_domain(int family)
43c22d69bfSAxel Dörfler {
44c22d69bfSAxel Dörfler 	net_domain_private *domain = NULL;
45c22d69bfSAxel Dörfler 	while (true) {
46c22d69bfSAxel Dörfler 		domain = (net_domain_private *)list_get_next_item(&sDomains, domain);
47c22d69bfSAxel Dörfler 		if (domain == NULL)
48c22d69bfSAxel Dörfler 			break;
49c22d69bfSAxel Dörfler 
50c22d69bfSAxel Dörfler 		if (domain->family == family)
51c22d69bfSAxel Dörfler 			return domain;
52c22d69bfSAxel Dörfler 	}
53c22d69bfSAxel Dörfler 
54c22d69bfSAxel Dörfler 	return NULL;
55c22d69bfSAxel Dörfler }
56c22d69bfSAxel Dörfler 
57c22d69bfSAxel Dörfler 
58c22d69bfSAxel Dörfler //	#pragma mark -
59c22d69bfSAxel Dörfler 
60c22d69bfSAxel Dörfler 
61c22d69bfSAxel Dörfler /*!
62c22d69bfSAxel 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 {
67c22d69bfSAxel Dörfler 	BenaphoreLocker 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 {
75c22d69bfSAxel Dörfler 	BenaphoreLocker 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 {
108c22d69bfSAxel Dörfler 	BenaphoreLocker 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 
1189206bb37SAxel Dörfler 		BenaphoreLocker 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;
157c22d69bfSAxel Dörfler 	net_device_interface *deviceInterface = get_device_interface(deviceName);
158c22d69bfSAxel Dörfler 	if (deviceInterface == NULL)
159c22d69bfSAxel Dörfler 		return ENODEV;
160c22d69bfSAxel Dörfler 
161c22d69bfSAxel Dörfler 	BenaphoreLocker locker(domain->lock);
162c22d69bfSAxel Dörfler 
163c22d69bfSAxel Dörfler 	if (find_interface(domain, request.ifr_name) != NULL)
164c22d69bfSAxel Dörfler 		return B_NAME_IN_USE;
165c22d69bfSAxel Dörfler 
166c22d69bfSAxel Dörfler 	net_interface_private *interface;
167c22d69bfSAxel Dörfler 	status_t status = create_interface(domain,
168c22d69bfSAxel Dörfler 		request.ifr_name, request.ifr_parameter.base_name[0]
169c22d69bfSAxel Dörfler 			? request.ifr_parameter.base_name : request.ifr_name,
170c22d69bfSAxel Dörfler 		deviceInterface, &interface);
171c22d69bfSAxel Dörfler 	if (status < B_OK) {
172c22d69bfSAxel Dörfler 		put_device_interface(deviceInterface);
173c22d69bfSAxel Dörfler 		return status;
174c22d69bfSAxel Dörfler 	}
175c22d69bfSAxel Dörfler 
176c22d69bfSAxel Dörfler 	list_add_item(&domain->interfaces, interface);
177c22d69bfSAxel Dörfler 	return B_OK;
178c22d69bfSAxel Dörfler }
179c22d69bfSAxel Dörfler 
180c22d69bfSAxel Dörfler 
181c22d69bfSAxel Dörfler /*!
182c22d69bfSAxel Dörfler 	Removes the interface from its domain, and deletes it.
183c22d69bfSAxel Dörfler 	You need to hold the domain's lock when calling this function.
184c22d69bfSAxel Dörfler */
185c22d69bfSAxel Dörfler status_t
186c22d69bfSAxel Dörfler remove_interface_from_domain(net_interface *interface)
187c22d69bfSAxel Dörfler {
188c22d69bfSAxel Dörfler 	net_domain_private *domain = (net_domain_private *)interface->domain;
189c22d69bfSAxel Dörfler 
190c22d69bfSAxel Dörfler 	list_remove_item(&domain->interfaces, interface);
191c22d69bfSAxel Dörfler 	delete_interface((net_interface_private *)interface);
192c22d69bfSAxel Dörfler 	return B_OK;
193c22d69bfSAxel Dörfler }
194c22d69bfSAxel Dörfler 
195c22d69bfSAxel Dörfler 
1969206bb37SAxel Dörfler void
1979206bb37SAxel Dörfler domain_interfaces_link_changed(net_device *device)
1989206bb37SAxel Dörfler {
1999206bb37SAxel Dörfler 	// TODO: notify listeners about this!
2009206bb37SAxel Dörfler 
2019206bb37SAxel Dörfler 	BenaphoreLocker locker(sDomainLock);
2029206bb37SAxel Dörfler 
2039206bb37SAxel Dörfler 	net_domain_private *domain = NULL;
2049206bb37SAxel Dörfler 	while (true) {
2059206bb37SAxel Dörfler 		domain = (net_domain_private *)list_get_next_item(&sDomains, domain);
2069206bb37SAxel Dörfler 		if (domain == NULL)
2079206bb37SAxel Dörfler 			break;
2089206bb37SAxel Dörfler 
2099206bb37SAxel Dörfler 		BenaphoreLocker locker(domain->lock);
2109206bb37SAxel Dörfler 
2119206bb37SAxel Dörfler 		net_interface *interface = NULL;
2129206bb37SAxel Dörfler 		while (true) {
2139206bb37SAxel Dörfler 			interface = (net_interface *)list_get_next_item(&domain->interfaces,
2149206bb37SAxel Dörfler 				interface);
2159206bb37SAxel Dörfler 			if (interface == NULL)
2169206bb37SAxel Dörfler 				break;
2179206bb37SAxel Dörfler 
2189206bb37SAxel Dörfler 			if (interface->device == device) {
2199206bb37SAxel Dörfler 				// update IFF_LINK flag
2209206bb37SAxel Dörfler 				interface->flags = (interface->flags & ~IFF_LINK)
2219206bb37SAxel Dörfler 					| (device->media & IFM_ACTIVE ? IFF_LINK : 0);
2229206bb37SAxel Dörfler 			}
2239206bb37SAxel Dörfler 		}
2249206bb37SAxel Dörfler 	}
2259206bb37SAxel Dörfler }
2269206bb37SAxel Dörfler 
2279206bb37SAxel Dörfler 
228*c64feccaSHugo Santos void
229*c64feccaSHugo Santos domain_interface_went_down(net_interface *interface)
230*c64feccaSHugo Santos {
231*c64feccaSHugo Santos 	// the domain should be locked here. always check
232*c64feccaSHugo Santos 	// all callers to be sure. We get here via
233*c64feccaSHugo Santos 	// interface_set_down().
234*c64feccaSHugo Santos 
235*c64feccaSHugo Santos 	dprintf("domain_interface_went_down(%i, %s)\n",
236*c64feccaSHugo Santos 		interface->domain->family, interface->name);
237*c64feccaSHugo Santos 
238*c64feccaSHugo Santos 	// domain might have been locked by:
239*c64feccaSHugo Santos 	//  - domain_removed_device_interface() <--- here
240*c64feccaSHugo Santos 	//     remove_interface_from_domain()
241*c64feccaSHugo Santos 	//      delete_interface()
242*c64feccaSHugo Santos 	//       interface_set_down()
243*c64feccaSHugo Santos 	//  - datalink_control() <--- here
244*c64feccaSHugo Santos 	//     interface_set_down()
245*c64feccaSHugo Santos 	invalidate_routes(interface->domain, interface);
246*c64feccaSHugo Santos }
247*c64feccaSHugo Santos 
248*c64feccaSHugo Santos 
249*c64feccaSHugo Santos void
250*c64feccaSHugo Santos domain_removed_device_interface(net_device_interface *interface)
251*c64feccaSHugo Santos {
252*c64feccaSHugo Santos 	BenaphoreLocker locker(sDomainLock);
253*c64feccaSHugo Santos 
254*c64feccaSHugo Santos 	net_domain_private *domain = NULL;
255*c64feccaSHugo Santos 	while (true) {
256*c64feccaSHugo Santos 		domain = (net_domain_private *)list_get_next_item(&sDomains, domain);
257*c64feccaSHugo Santos 		if (domain == NULL)
258*c64feccaSHugo Santos 			break;
259*c64feccaSHugo Santos 
260*c64feccaSHugo Santos 		BenaphoreLocker locker(domain->lock);
261*c64feccaSHugo Santos 
262*c64feccaSHugo Santos 		net_interface_private *priv = find_interface(domain, interface->name);
263*c64feccaSHugo Santos 		if (priv == NULL)
264*c64feccaSHugo Santos 			continue;
265*c64feccaSHugo Santos 
266*c64feccaSHugo Santos 		remove_interface_from_domain(priv);
267*c64feccaSHugo Santos 	}
268*c64feccaSHugo Santos }
269*c64feccaSHugo Santos 
270*c64feccaSHugo Santos 
271c22d69bfSAxel Dörfler status_t
272c22d69bfSAxel Dörfler register_domain(int family, const char *name,
273c22d69bfSAxel Dörfler 	struct net_protocol_module_info *module,
274c22d69bfSAxel Dörfler 	struct net_address_module_info *addressModule,
275c22d69bfSAxel Dörfler 	net_domain **_domain)
276c22d69bfSAxel Dörfler {
277c22d69bfSAxel Dörfler 	TRACE(("register_domain(%d, %s)\n", family, name));
278c22d69bfSAxel Dörfler 	BenaphoreLocker locker(sDomainLock);
279c22d69bfSAxel Dörfler 
280c22d69bfSAxel Dörfler 	struct net_domain_private *domain = lookup_domain(family);
281c22d69bfSAxel Dörfler 	if (domain != NULL)
282c22d69bfSAxel Dörfler 		return B_NAME_IN_USE;
283c22d69bfSAxel Dörfler 
284c22d69bfSAxel Dörfler 	domain = new (std::nothrow) net_domain_private;
285c22d69bfSAxel Dörfler 	if (domain == NULL)
286c22d69bfSAxel Dörfler 		return B_NO_MEMORY;
287c22d69bfSAxel Dörfler 
288c22d69bfSAxel Dörfler 	status_t status = benaphore_init(&domain->lock, name);
289c22d69bfSAxel Dörfler 	if (status < B_OK) {
290c22d69bfSAxel Dörfler 		delete domain;
291c22d69bfSAxel Dörfler 		return status;
292c22d69bfSAxel Dörfler 	}
293c22d69bfSAxel Dörfler 
294c22d69bfSAxel Dörfler 	domain->family = family;
295c22d69bfSAxel Dörfler 	domain->name = name;
296c22d69bfSAxel Dörfler 	domain->module = module;
297c22d69bfSAxel Dörfler 	domain->address_module = addressModule;
298c22d69bfSAxel Dörfler 
299c22d69bfSAxel Dörfler 	list_init(&domain->interfaces);
300c22d69bfSAxel Dörfler 
301c22d69bfSAxel Dörfler 	list_add_item(&sDomains, domain);
302c22d69bfSAxel Dörfler 
303c22d69bfSAxel Dörfler 	*_domain = domain;
304c22d69bfSAxel Dörfler 	return B_OK;
305c22d69bfSAxel Dörfler }
306c22d69bfSAxel Dörfler 
307c22d69bfSAxel Dörfler 
308c22d69bfSAxel Dörfler status_t
309c22d69bfSAxel Dörfler unregister_domain(net_domain *_domain)
310c22d69bfSAxel Dörfler {
311c22d69bfSAxel Dörfler 	TRACE(("unregister_domain(%p, %d, %s)\n", _domain, _domain->family, _domain->name));
312c22d69bfSAxel Dörfler 
313c22d69bfSAxel Dörfler 	net_domain_private *domain = (net_domain_private *)_domain;
314c22d69bfSAxel Dörfler 	BenaphoreLocker locker(sDomainLock);
315c22d69bfSAxel Dörfler 
316c22d69bfSAxel Dörfler 	list_remove_item(&sDomains, domain);
317c22d69bfSAxel Dörfler 
318c22d69bfSAxel Dörfler 	net_interface_private *interface = NULL;
319c22d69bfSAxel Dörfler 	while (true) {
320c22d69bfSAxel Dörfler 		interface = (net_interface_private *)list_remove_head_item(&domain->interfaces);
321c22d69bfSAxel Dörfler 		if (interface == NULL)
322c22d69bfSAxel Dörfler 			break;
323c22d69bfSAxel Dörfler 
324c22d69bfSAxel Dörfler 		delete_interface(interface);
325c22d69bfSAxel Dörfler 	}
326c22d69bfSAxel Dörfler 
327c22d69bfSAxel Dörfler 	benaphore_destroy(&domain->lock);
328c22d69bfSAxel Dörfler 	delete domain;
329c22d69bfSAxel Dörfler 	return B_OK;
330c22d69bfSAxel Dörfler }
331c22d69bfSAxel Dörfler 
332c22d69bfSAxel Dörfler 
333c22d69bfSAxel Dörfler status_t
334c22d69bfSAxel Dörfler init_domains()
335c22d69bfSAxel Dörfler {
336c22d69bfSAxel Dörfler 	if (benaphore_init(&sDomainLock, "net domains") < B_OK)
337c22d69bfSAxel Dörfler 		return B_ERROR;
338c22d69bfSAxel Dörfler 
339c22d69bfSAxel Dörfler 	list_init_etc(&sDomains, offsetof(struct net_domain_private, link));
340c22d69bfSAxel Dörfler 	return B_OK;
341c22d69bfSAxel Dörfler }
342c22d69bfSAxel Dörfler 
343c22d69bfSAxel Dörfler 
344c22d69bfSAxel Dörfler status_t
345c22d69bfSAxel Dörfler uninit_domains()
346c22d69bfSAxel Dörfler {
347c22d69bfSAxel Dörfler 	benaphore_destroy(&sDomainLock);
348c22d69bfSAxel Dörfler 	return B_OK;
349c22d69bfSAxel Dörfler }
350c22d69bfSAxel Dörfler 
351