xref: /haiku/src/add-ons/kernel/network/stack/link.cpp (revision abe1ec18ac0e70d36b0cc595fc176ea4dd9df818)
1 /*
2  * Copyright 2006-2007, 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 "datalink.h"
11 #include "domains.h"
12 #include "interfaces.h"
13 #include "link.h"
14 #include "stack_private.h"
15 #include "utility.h"
16 
17 #include <net_device.h>
18 
19 #include <KernelExport.h>
20 
21 #include <net/if_types.h>
22 #include <new>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/sockio.h>
26 
27 
28 struct link_protocol : net_protocol {
29 	net_fifo	fifo;
30 	char		registered_interface[IF_NAMESIZE];
31 	bool		registered_monitor;
32 };
33 
34 
35 struct net_domain *sDomain;
36 
37 
38 static status_t
39 link_monitor_data(void *cookie, net_buffer *packet)
40 {
41 	link_protocol *protocol = (link_protocol *)cookie;
42 
43 	// we need to make a clone for that buffer and pass it to the socket
44 	net_buffer *buffer = gNetBufferModule.clone(packet, false);
45 	if (buffer == NULL)
46 		return B_NO_MEMORY;
47 
48 	status_t status = fifo_enqueue_buffer(&protocol->fifo, buffer);
49 	if (status >= B_OK)
50 		notify_socket(protocol->socket, B_SELECT_READ,
51 						protocol->fifo.current_bytes);
52 	else
53 		gNetBufferModule.free(buffer);
54 
55 	return status;
56 }
57 
58 
59 //	#pragma mark -
60 
61 
62 net_protocol *
63 link_init_protocol(net_socket *socket)
64 {
65 	link_protocol *protocol = new (std::nothrow) link_protocol;
66 	if (protocol == NULL)
67 		return NULL;
68 
69 	if (init_fifo(&protocol->fifo, "packet monitor socket", 65536) < B_OK) {
70 		delete protocol;
71 		return NULL;
72 	}
73 
74 	protocol->registered_monitor = false;
75 	return protocol;
76 }
77 
78 
79 status_t
80 link_uninit_protocol(net_protocol *_protocol)
81 {
82 	link_protocol *protocol = (link_protocol *)_protocol;
83 
84 	if (protocol->registered_monitor) {
85 		net_device_interface *interface = get_device_interface(protocol->registered_interface);
86 		if (interface != NULL) {
87 			unregister_device_monitor(interface->device, link_monitor_data, protocol);
88 			put_device_interface(interface);
89 		}
90 	}
91 
92 	uninit_fifo(&protocol->fifo);
93 	delete protocol;
94 	return B_OK;
95 }
96 
97 
98 status_t
99 link_open(net_protocol *protocol)
100 {
101 	return B_OK;
102 }
103 
104 
105 status_t
106 link_close(net_protocol *protocol)
107 {
108 	return B_OK;
109 }
110 
111 
112 status_t
113 link_free(net_protocol *protocol)
114 {
115 	return B_OK;
116 }
117 
118 
119 status_t
120 link_connect(net_protocol *protocol, const struct sockaddr *address)
121 {
122 	return EOPNOTSUPP;
123 }
124 
125 
126 status_t
127 link_accept(net_protocol *protocol, struct net_socket **_acceptedSocket)
128 {
129 	return EOPNOTSUPP;
130 }
131 
132 
133 status_t
134 link_control(net_protocol *_protocol, int level, int option, void *value,
135 	size_t *_length)
136 {
137 	link_protocol *protocol = (link_protocol *)_protocol;
138 
139 	switch (option) {
140 		case SIOCGIFINDEX:
141 		{
142 			// get index of interface
143 			struct ifreq request;
144 			if (user_memcpy(&request, value, IF_NAMESIZE) < B_OK)
145 				return B_BAD_ADDRESS;
146 
147 			net_device_interface *interface = get_device_interface(request.ifr_name);
148 			if (interface != NULL) {
149 				request.ifr_index = interface->device->index;
150 				put_device_interface(interface);
151 			} else
152 				request.ifr_index = 0;
153 
154 			return user_memcpy(value, &request, sizeof(struct ifreq));
155 		}
156 		case SIOCGIFNAME:
157 		{
158 			// get name of interface via index
159 			struct ifreq request;
160 			if (user_memcpy(&request, value, sizeof(struct ifreq)) < B_OK)
161 				return B_BAD_ADDRESS;
162 
163 			net_device_interface *interface = get_device_interface(request.ifr_index);
164 			if (interface != NULL) {
165 				strlcpy(request.ifr_name, interface->name, IF_NAMESIZE);
166 				put_device_interface(interface);
167 			} else
168 				return ENODEV;
169 
170 			return user_memcpy(value, &request, sizeof(struct ifreq));
171 		}
172 
173 		case SIOCGIFCOUNT:
174 		{
175 			// count number of interfaces
176 			struct ifconf config;
177 			config.ifc_value = count_device_interfaces();
178 
179 			return user_memcpy(value, &config, sizeof(struct ifconf));
180 		}
181 
182 		case SIOCGIFCONF:
183 		{
184 			// retrieve available interfaces
185 			struct ifconf config;
186 			if (user_memcpy(&config, value, sizeof(struct ifconf)) < B_OK)
187 				return B_BAD_ADDRESS;
188 
189 			status_t result = list_device_interfaces(config.ifc_buf,
190 				(size_t *)&config.ifc_len);
191 			if (result != B_OK)
192 				return result;
193 
194 			return user_memcpy(value, &config, sizeof(struct ifconf));
195 		}
196 
197 		case SIOCGIFADDR:
198 		{
199 			// get address of interface
200 			struct ifreq request;
201 			if (user_memcpy(&request, value, IF_NAMESIZE) < B_OK)
202 				return B_BAD_ADDRESS;
203 
204 			net_device_interface *interface = get_device_interface(request.ifr_name);
205 			if (interface != NULL) {
206 				get_device_interface_address(interface, &request.ifr_addr);
207 				put_device_interface(interface);
208 			} else
209 				return ENODEV;
210 
211 			return user_memcpy(&((struct ifreq *)value)->ifr_addr,
212 				&request.ifr_addr, request.ifr_addr.sa_len);
213 		}
214 
215 		case SIOCSPACKETCAP:
216 		{
217 			// start packet monitoring
218 
219 			if (protocol->registered_monitor)
220 				return B_BUSY;
221 
222 			struct ifreq request;
223 			if (user_memcpy(&request, value, IF_NAMESIZE) < B_OK)
224 				return B_BAD_ADDRESS;
225 
226 			net_device_interface *interface = get_device_interface(request.ifr_name);
227 			status_t status;
228 			if (interface != NULL) {
229 				status = register_device_monitor(interface->device,
230 					link_monitor_data, protocol);
231 				if (status == B_OK) {
232 					// we're now registered
233 					strlcpy(protocol->registered_interface, request.ifr_name, IF_NAMESIZE);
234 					protocol->registered_monitor = true;
235 				}
236 				put_device_interface(interface);
237 			} else
238 				status = ENODEV;
239 
240 			return status;
241 		}
242 
243 		case SIOCCPACKETCAP:
244 		{
245 			// stop packet monitoring
246 
247 			if (!protocol->registered_monitor)
248 				return B_BAD_VALUE;
249 
250 			struct ifreq request;
251 			if (user_memcpy(&request, value, IF_NAMESIZE) < B_OK)
252 				return B_BAD_ADDRESS;
253 
254 			net_device_interface *interface = get_device_interface(request.ifr_name);
255 			status_t status;
256 			if (interface != NULL) {
257 				status = unregister_device_monitor(interface->device,
258 					link_monitor_data, protocol);
259 				if (status == B_OK) {
260 					// we're now no longer registered
261 					protocol->registered_monitor = false;
262 				}
263 				put_device_interface(interface);
264 			} else
265 				status = ENODEV;
266 
267 			return status;
268 		}
269 	}
270 
271 	return datalink_control(sDomain, option, value, _length);
272 }
273 
274 
275 status_t
276 link_bind(net_protocol *protocol, struct sockaddr *address)
277 {
278 	// TODO: bind to a specific interface and ethernet type
279 	return B_ERROR;
280 }
281 
282 
283 status_t
284 link_unbind(net_protocol *protocol, struct sockaddr *address)
285 {
286 	return B_ERROR;
287 }
288 
289 
290 status_t
291 link_listen(net_protocol *protocol, int count)
292 {
293 	return EOPNOTSUPP;
294 }
295 
296 
297 status_t
298 link_shutdown(net_protocol *protocol, int direction)
299 {
300 	return EOPNOTSUPP;
301 }
302 
303 
304 status_t
305 link_send_data(net_protocol *protocol, net_buffer *buffer)
306 {
307 	return B_NOT_ALLOWED;
308 }
309 
310 
311 status_t
312 link_send_routed_data(net_protocol *protocol, struct net_route *route,
313 	net_buffer *buffer)
314 {
315 	return B_NOT_ALLOWED;
316 }
317 
318 
319 ssize_t
320 link_send_avail(net_protocol *protocol)
321 {
322 	return B_ERROR;
323 }
324 
325 
326 status_t
327 link_read_data(net_protocol *_protocol, size_t numBytes, uint32 flags,
328 	net_buffer **_buffer)
329 {
330 	link_protocol *protocol = (link_protocol *)_protocol;
331 
332 	dprintf("link_read is waiting for data...\n");
333 
334 	net_buffer *buffer;
335 	status_t status = fifo_dequeue_buffer(&protocol->fifo,
336 		flags, protocol->socket->receive.timeout, &buffer);
337 	if (status < B_OK)
338 		return status;
339 
340 	*_buffer = buffer;
341 	return B_OK;
342 }
343 
344 
345 ssize_t
346 link_read_avail(net_protocol *_protocol)
347 {
348 	link_protocol *protocol = (link_protocol *)_protocol;
349 	return protocol->fifo.current_bytes;
350 }
351 
352 
353 struct net_domain *
354 link_get_domain(net_protocol *protocol)
355 {
356 	return sDomain;
357 }
358 
359 
360 size_t
361 link_get_mtu(net_protocol *protocol, const struct sockaddr *address)
362 {
363 	// TODO: for now
364 	return 0;
365 }
366 
367 
368 status_t
369 link_receive_data(net_buffer *buffer)
370 {
371 	return B_ERROR;
372 }
373 
374 
375 status_t
376 link_error(uint32 code, net_buffer *data)
377 {
378 	return B_ERROR;
379 }
380 
381 
382 status_t
383 link_error_reply(net_protocol *protocol, net_buffer *causedError, uint32 code,
384 	void *errorData)
385 {
386 	return B_ERROR;
387 }
388 
389 
390 static status_t
391 link_std_ops(int32 op, ...)
392 {
393 	switch (op) {
394 		case B_MODULE_INIT:
395 			return register_domain(AF_LINK, "link", NULL, NULL, &sDomain);
396 
397 		case B_MODULE_UNINIT:
398 			unregister_domain(sDomain);
399 			return B_OK;
400 
401 		default:
402 			return B_ERROR;
403 	}
404 }
405 
406 
407 //	#pragma mark -
408 
409 
410 void
411 link_init()
412 {
413 	register_domain_protocols(AF_LINK, SOCK_DGRAM, 0, "network/stack/link/v1", NULL);
414 
415 	register_domain_datalink_protocols(AF_LINK, IFT_ETHER,
416 		"network/datalink_protocols/ethernet_frame/v1",
417 		NULL);
418 }
419 
420 
421 net_protocol_module_info gLinkModule = {
422 	{
423 		"network/stack/link/v1",
424 		0,
425 		link_std_ops
426 	},
427 	link_init_protocol,
428 	link_uninit_protocol,
429 	link_open,
430 	link_close,
431 	link_free,
432 	link_connect,
433 	link_accept,
434 	link_control,
435 	link_bind,
436 	link_unbind,
437 	link_listen,
438 	link_shutdown,
439 	link_send_data,
440 	link_send_routed_data,
441 	link_send_avail,
442 	link_read_data,
443 	link_read_avail,
444 	link_get_domain,
445 	link_get_mtu,
446 	link_receive_data,
447 	link_error,
448 	link_error_reply,
449 };
450