xref: /haiku/src/add-ons/kernel/network/stack/domains.cpp (revision 55b40aa53a835472ec7952b138ae4256203d02e4)
1 /*
2  * Copyright 2006, 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  */
8 
9 
10 #include "domains.h"
11 #include "interfaces.h"
12 
13 #include <KernelExport.h>
14 
15 #include <lock.h>
16 #include <util/AutoLock.h>
17 
18 #include <new>
19 #include <string.h>
20 
21 
22 #define TRACE_DOMAINS
23 #ifdef TRACE_DOMAINS
24 #	define TRACE(x) dprintf x
25 #else
26 #	define TRACE(x) ;
27 #endif
28 
29 static benaphore sDomainLock;
30 static list sDomains;
31 
32 
33 /*!
34 	Scans the domain list for the specified family.
35 	You need to hold the sDomainLock when calling this function.
36 */
37 static net_domain_private *
38 lookup_domain(int family)
39 {
40 	net_domain_private *domain = NULL;
41 	while (true) {
42 		domain = (net_domain_private *)list_get_next_item(&sDomains, domain);
43 		if (domain == NULL)
44 			break;
45 
46 		if (domain->family == family)
47 			return domain;
48 	}
49 
50 	return NULL;
51 }
52 
53 
54 //	#pragma mark -
55 
56 
57 /*!
58 	Gets the domain of the specified family.
59 */
60 net_domain *
61 get_domain(int family)
62 {
63 	BenaphoreLocker locker(sDomainLock);
64 	return lookup_domain(family);
65 }
66 
67 
68 uint32
69 count_domain_interfaces()
70 {
71 	BenaphoreLocker locker(sDomainLock);
72 
73 	net_domain_private *domain = NULL;
74 	uint32 count = 0;
75 
76 	while (true) {
77 		domain = (net_domain_private *)list_get_next_item(&sDomains, domain);
78 		if (domain == NULL)
79 			break;
80 
81 		net_interface *interface = NULL;
82 		while (true) {
83 			interface = (net_interface *)list_get_next_item(&domain->interfaces,
84 				interface);
85 			if (interface == NULL)
86 				break;
87 
88 			count++;
89 		}
90 	}
91 
92 	return count;
93 }
94 
95 
96 /*!
97 	Dumps a list of all interfaces into the supplied userland buffer.
98 	If the interfaces don't fit into the buffer, an error (\c ENOBUFS) is
99 	returned.
100 */
101 status_t
102 list_domain_interfaces(void *buffer, size_t size)
103 {
104 	BenaphoreLocker locker(sDomainLock);
105 
106 	net_domain_private *domain = NULL;
107 	size_t spaceLeft = size;
108 
109 	while (true) {
110 		domain = (net_domain_private *)list_get_next_item(&sDomains, domain);
111 		if (domain == NULL)
112 			break;
113 
114 		net_interface *interface = NULL;
115 		while (true) {
116 			interface = (net_interface *)list_get_next_item(&domain->interfaces,
117 				interface);
118 			if (interface == NULL)
119 				break;
120 
121 			size = IF_NAMESIZE + (interface->address ? interface->address->sa_len : 1);
122 			if (spaceLeft < size)
123 				return ENOBUFS;
124 
125 			ifreq request;
126 			strlcpy(request.ifr_name, interface->name, IF_NAMESIZE);
127 			if (interface->address != NULL)
128 				memcpy(&request.ifr_addr, interface->address, interface->address->sa_len);
129 			else {
130 				// empty address
131 				request.ifr_addr.sa_len = 2;
132 				request.ifr_addr.sa_family = AF_UNSPEC;
133 			}
134 
135 			if (user_memcpy(buffer, &request, size) < B_OK)
136 				return B_BAD_ADDRESS;
137 
138 			buffer = (void *)((addr_t)buffer + size);
139 			spaceLeft -= size;
140 		}
141 	}
142 
143 	return B_OK;
144 }
145 
146 
147 status_t
148 add_interface_to_domain(net_domain *_domain,
149 	struct ifreq& request)
150 {
151 	net_domain_private *domain = (net_domain_private *)_domain;
152 
153 	const char *deviceName = request.ifr_parameter.device[0]
154 		? request.ifr_parameter.device : request.ifr_name;
155 	net_device_interface *deviceInterface = get_device_interface(deviceName);
156 	if (deviceInterface == NULL)
157 		return ENODEV;
158 
159 	BenaphoreLocker locker(domain->lock);
160 
161 	if (find_interface(domain, request.ifr_name) != NULL)
162 		return B_NAME_IN_USE;
163 
164 	net_interface_private *interface;
165 	status_t status = create_interface(domain,
166 		request.ifr_name, request.ifr_parameter.base_name[0]
167 			? request.ifr_parameter.base_name : request.ifr_name,
168 		deviceInterface, &interface);
169 	if (status < B_OK) {
170 		put_device_interface(deviceInterface);
171 		return status;
172 	}
173 
174 	list_add_item(&domain->interfaces, interface);
175 	return B_OK;
176 }
177 
178 
179 /*!
180 	Removes the interface from its domain, and deletes it.
181 	You need to hold the domain's lock when calling this function.
182 */
183 status_t
184 remove_interface_from_domain(net_interface *interface)
185 {
186 	net_domain_private *domain = (net_domain_private *)interface->domain;
187 
188 	list_remove_item(&domain->interfaces, interface);
189 	delete_interface((net_interface_private *)interface);
190 	return B_OK;
191 }
192 
193 
194 status_t
195 register_domain(int family, const char *name,
196 	struct net_protocol_module_info *module,
197 	struct net_address_module_info *addressModule,
198 	net_domain **_domain)
199 {
200 	TRACE(("register_domain(%d, %s)\n", family, name));
201 	BenaphoreLocker locker(sDomainLock);
202 
203 	struct net_domain_private *domain = lookup_domain(family);
204 	if (domain != NULL)
205 		return B_NAME_IN_USE;
206 
207 	domain = new (std::nothrow) net_domain_private;
208 	if (domain == NULL)
209 		return B_NO_MEMORY;
210 
211 	status_t status = benaphore_init(&domain->lock, name);
212 	if (status < B_OK) {
213 		delete domain;
214 		return status;
215 	}
216 
217 	domain->family = family;
218 	domain->name = name;
219 	domain->module = module;
220 	domain->address_module = addressModule;
221 
222 	list_init(&domain->interfaces);
223 
224 	list_add_item(&sDomains, domain);
225 
226 	*_domain = domain;
227 	return B_OK;
228 }
229 
230 
231 status_t
232 unregister_domain(net_domain *_domain)
233 {
234 	TRACE(("unregister_domain(%p, %d, %s)\n", _domain, _domain->family, _domain->name));
235 
236 	net_domain_private *domain = (net_domain_private *)_domain;
237 	BenaphoreLocker locker(sDomainLock);
238 
239 	list_remove_item(&sDomains, domain);
240 
241 	net_interface_private *interface = NULL;
242 	while (true) {
243 		interface = (net_interface_private *)list_remove_head_item(&domain->interfaces);
244 		if (interface == NULL)
245 			break;
246 
247 		delete_interface(interface);
248 	}
249 
250 	benaphore_destroy(&domain->lock);
251 	delete domain;
252 	return B_OK;
253 }
254 
255 
256 status_t
257 init_domains()
258 {
259 	if (benaphore_init(&sDomainLock, "net domains") < B_OK)
260 		return B_ERROR;
261 
262 	list_init_etc(&sDomains, offsetof(struct net_domain_private, link));
263 	return B_OK;
264 }
265 
266 
267 status_t
268 uninit_domains()
269 {
270 	benaphore_destroy(&sDomainLock);
271 	return B_OK;
272 }
273 
274