xref: /haiku/src/add-ons/kernel/network/stack/link.cpp (revision 9261b129886d285ddb488b27b608efb25c733e88)
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 <lock.h>
20 #include <util/AutoLock.h>
21 
22 #include <KernelExport.h>
23 
24 #include <net/if_types.h>
25 #include <new>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/sockio.h>
29 
30 
31 class LinkProtocol : public net_protocol {
32 public:
33 	LinkProtocol();
34 	~LinkProtocol();
35 
36 	status_t InitCheck() const;
37 
38 	status_t StartMonitoring(const char *);
39 	status_t StopMonitoring();
40 
41 	ssize_t ReadData(size_t numBytes, uint32 flags, net_buffer **_buffer);
42 	ssize_t ReadAvail() const;
43 
44 private:
45 	status_t _Enqueue(net_buffer *buffer);
46 	status_t _Unregister();
47 
48 	mutable benaphore	fLock;
49 	Fifo				fFifo;
50 
51 	net_device_monitor	fMonitor;
52 	net_device_interface *fMonitoredDevice;
53 
54 	static status_t _MonitorData(net_device_monitor *monitor, net_buffer *buffer);
55 	static void _MonitorEvent(net_device_monitor *monitor, int32 event);
56 };
57 
58 
59 struct net_domain *sDomain;
60 
61 
62 LinkProtocol::LinkProtocol()
63 	: fFifo("packet monitor fifo", 65536)
64 {
65 	benaphore_init(&fLock, "packet monitor lock");
66 
67 	fMonitor.cookie = this;
68 	fMonitor.receive = _MonitorData;
69 	fMonitor.event = _MonitorEvent;
70 	fMonitoredDevice = NULL;
71 }
72 
73 
74 LinkProtocol::~LinkProtocol()
75 {
76 	if (fMonitoredDevice) {
77 		unregister_device_monitor(fMonitoredDevice->device, &fMonitor);
78 		put_device_interface(fMonitoredDevice);
79 	}
80 
81 	benaphore_destroy(&fLock);
82 }
83 
84 
85 status_t
86 LinkProtocol::InitCheck() const
87 {
88 	return fLock.sem >= 0 && fFifo.InitCheck();
89 }
90 
91 
92 status_t
93 LinkProtocol::StartMonitoring(const char *deviceName)
94 {
95 	BenaphoreLocker _(fLock);
96 
97 	if (fMonitoredDevice)
98 		return B_BUSY;
99 
100 	net_device_interface *interface = get_device_interface(deviceName);
101 	if (interface == NULL)
102 		return ENODEV;
103 
104 	status_t status = register_device_monitor(interface->device, &fMonitor);
105 	if (status < B_OK) {
106 		put_device_interface(interface);
107 		return status;
108 	}
109 
110 	fMonitoredDevice = interface;
111 	return B_OK;
112 }
113 
114 
115 status_t
116 LinkProtocol::StopMonitoring()
117 {
118 	BenaphoreLocker _(fLock);
119 
120 	// TODO compare our device with the supplied device name?
121 	return _Unregister();
122 }
123 
124 
125 ssize_t
126 LinkProtocol::ReadData(size_t numBytes, uint32 flags, net_buffer **_buffer)
127 {
128 	BenaphoreLocker _(fLock);
129 
130 	bigtime_t timeout = socket->receive.timeout;
131 
132 	if (timeout == 0)
133 		flags |= MSG_DONTWAIT;
134 	else if (timeout != B_INFINITE_TIMEOUT)
135 		timeout += system_time();
136 
137 	while (fFifo.IsEmpty()) {
138 		if (fMonitoredDevice == NULL)
139 			return ENODEV;
140 
141 		status_t status = B_WOULD_BLOCK;
142 		if ((flags & MSG_DONTWAIT) == 0)
143 			status = fFifo.Wait(&fLock, timeout);
144 
145 		if (status < B_OK)
146 			return status;
147 	}
148 
149 	*_buffer = fFifo.Dequeue(flags & MSG_PEEK);
150 	return *_buffer ? B_OK : B_NO_MEMORY;
151 }
152 
153 
154 ssize_t
155 LinkProtocol::ReadAvail() const
156 {
157 	BenaphoreLocker _(fLock);
158 	if (fMonitoredDevice == NULL)
159 		return ENODEV;
160 	return fFifo.current_bytes;
161 }
162 
163 
164 status_t
165 LinkProtocol::_Unregister()
166 {
167 	if (fMonitoredDevice == NULL)
168 		return B_BAD_VALUE;
169 
170 	status_t status = unregister_device_monitor(fMonitoredDevice->device,
171 		&fMonitor);
172 	put_device_interface(fMonitoredDevice);
173 	fMonitoredDevice = NULL;
174 
175 	return status;
176 }
177 
178 
179 status_t
180 LinkProtocol::_Enqueue(net_buffer *buffer)
181 {
182 	BenaphoreLocker _(fLock);
183 	return fFifo.EnqueueAndNotify(buffer, socket, B_SELECT_READ);
184 }
185 
186 
187 status_t
188 LinkProtocol::_MonitorData(net_device_monitor *monitor, net_buffer *packet)
189 {
190 	return ((LinkProtocol *)monitor->cookie)->_Enqueue(packet);
191 }
192 
193 
194 void
195 LinkProtocol::_MonitorEvent(net_device_monitor *monitor, int32 event)
196 {
197 	LinkProtocol *protocol = (LinkProtocol *)monitor->cookie;
198 
199 	if (event == B_DEVICE_GOING_DOWN) {
200 		BenaphoreLocker _(protocol->fLock);
201 
202 		protocol->_Unregister();
203 		if (protocol->fFifo.IsEmpty()) {
204 			protocol->fFifo.WakeAll();
205 			notify_socket(protocol->socket, B_SELECT_READ, ENODEV);
206 		}
207 	}
208 }
209 
210 
211 //	#pragma mark -
212 
213 
214 net_protocol *
215 link_init_protocol(net_socket *socket)
216 {
217 	LinkProtocol *protocol = new (std::nothrow) LinkProtocol();
218 	if (protocol && protocol->InitCheck() < B_OK) {
219 		delete protocol;
220 		return NULL;
221 	}
222 
223 	return protocol;
224 }
225 
226 
227 status_t
228 link_uninit_protocol(net_protocol *protocol)
229 {
230 	delete (LinkProtocol *)protocol;
231 	return B_OK;
232 }
233 
234 
235 status_t
236 link_open(net_protocol *protocol)
237 {
238 	return B_OK;
239 }
240 
241 
242 status_t
243 link_close(net_protocol *protocol)
244 {
245 	return B_OK;
246 }
247 
248 
249 status_t
250 link_free(net_protocol *protocol)
251 {
252 	return B_OK;
253 }
254 
255 
256 status_t
257 link_connect(net_protocol *protocol, const struct sockaddr *address)
258 {
259 	return EOPNOTSUPP;
260 }
261 
262 
263 status_t
264 link_accept(net_protocol *protocol, struct net_socket **_acceptedSocket)
265 {
266 	return EOPNOTSUPP;
267 }
268 
269 
270 status_t
271 link_control(net_protocol *_protocol, int level, int option, void *value,
272 	size_t *_length)
273 {
274 	LinkProtocol *protocol = (LinkProtocol *)_protocol;
275 
276 	// TODO All of this common functionality should be elsewhere
277 
278 	switch (option) {
279 		case SIOCGIFINDEX:
280 		{
281 			// get index of interface
282 			struct ifreq request;
283 			if (user_memcpy(&request, value, IF_NAMESIZE) < B_OK)
284 				return B_BAD_ADDRESS;
285 
286 			net_device_interface *interface = get_device_interface(request.ifr_name);
287 			if (interface != NULL) {
288 				request.ifr_index = interface->device->index;
289 				put_device_interface(interface);
290 			} else
291 				request.ifr_index = 0;
292 
293 			return user_memcpy(value, &request, sizeof(struct ifreq));
294 		}
295 		case SIOCGIFNAME:
296 		{
297 			// get name of interface via index
298 			struct ifreq request;
299 			if (user_memcpy(&request, value, sizeof(struct ifreq)) < B_OK)
300 				return B_BAD_ADDRESS;
301 
302 			net_device_interface *interface = get_device_interface(request.ifr_index);
303 			if (interface != NULL) {
304 				strlcpy(request.ifr_name, interface->name, IF_NAMESIZE);
305 				put_device_interface(interface);
306 			} else
307 				return ENODEV;
308 
309 			return user_memcpy(value, &request, sizeof(struct ifreq));
310 		}
311 
312 		case SIOCGIFCOUNT:
313 		{
314 			// count number of interfaces
315 			struct ifconf config;
316 			config.ifc_value = count_device_interfaces();
317 
318 			return user_memcpy(value, &config, sizeof(struct ifconf));
319 		}
320 
321 		case SIOCGIFCONF:
322 		{
323 			// retrieve available interfaces
324 			struct ifconf config;
325 			if (user_memcpy(&config, value, sizeof(struct ifconf)) < B_OK)
326 				return B_BAD_ADDRESS;
327 
328 			status_t result = list_device_interfaces(config.ifc_buf,
329 				(size_t *)&config.ifc_len);
330 			if (result != B_OK)
331 				return result;
332 
333 			return user_memcpy(value, &config, sizeof(struct ifconf));
334 		}
335 
336 		case SIOCGIFADDR:
337 		{
338 			// get address of interface
339 			struct ifreq request;
340 			if (user_memcpy(&request, value, IF_NAMESIZE) < B_OK)
341 				return B_BAD_ADDRESS;
342 
343 			net_device_interface *interface = get_device_interface(request.ifr_name);
344 			if (interface != NULL) {
345 				get_device_interface_address(interface, &request.ifr_addr);
346 				put_device_interface(interface);
347 			} else
348 				return ENODEV;
349 
350 			return user_memcpy(&((struct ifreq *)value)->ifr_addr,
351 				&request.ifr_addr, request.ifr_addr.sa_len);
352 		}
353 
354 		case SIOCSPACKETCAP:
355 		{
356 			struct ifreq request;
357 			if (user_memcpy(&request, value, IF_NAMESIZE) < B_OK)
358 				return B_BAD_ADDRESS;
359 
360 			return protocol->StartMonitoring(request.ifr_name);
361 		}
362 
363 		case SIOCCPACKETCAP:
364 			return protocol->StopMonitoring();
365 	}
366 
367 	return datalink_control(sDomain, option, value, _length);
368 }
369 
370 
371 status_t
372 link_bind(net_protocol *protocol, struct sockaddr *address)
373 {
374 	// TODO: bind to a specific interface and ethernet type
375 	return B_ERROR;
376 }
377 
378 
379 status_t
380 link_unbind(net_protocol *protocol, struct sockaddr *address)
381 {
382 	return B_ERROR;
383 }
384 
385 
386 status_t
387 link_listen(net_protocol *protocol, int count)
388 {
389 	return EOPNOTSUPP;
390 }
391 
392 
393 status_t
394 link_shutdown(net_protocol *protocol, int direction)
395 {
396 	return EOPNOTSUPP;
397 }
398 
399 
400 status_t
401 link_send_data(net_protocol *protocol, net_buffer *buffer)
402 {
403 	return B_NOT_ALLOWED;
404 }
405 
406 
407 status_t
408 link_send_routed_data(net_protocol *protocol, struct net_route *route,
409 	net_buffer *buffer)
410 {
411 	return B_NOT_ALLOWED;
412 }
413 
414 
415 ssize_t
416 link_send_avail(net_protocol *protocol)
417 {
418 	return B_ERROR;
419 }
420 
421 
422 status_t
423 link_read_data(net_protocol *protocol, size_t numBytes, uint32 flags,
424 	net_buffer **_buffer)
425 {
426 	return ((LinkProtocol *)protocol)->ReadData(numBytes, flags, _buffer);
427 }
428 
429 
430 ssize_t
431 link_read_avail(net_protocol *protocol)
432 {
433 	return ((LinkProtocol *)protocol)->ReadAvail();
434 }
435 
436 
437 struct net_domain *
438 link_get_domain(net_protocol *protocol)
439 {
440 	return sDomain;
441 }
442 
443 
444 size_t
445 link_get_mtu(net_protocol *protocol, const struct sockaddr *address)
446 {
447 	// TODO: for now
448 	return 0;
449 }
450 
451 
452 status_t
453 link_receive_data(net_buffer *buffer)
454 {
455 	return B_ERROR;
456 }
457 
458 
459 status_t
460 link_error(uint32 code, net_buffer *data)
461 {
462 	return B_ERROR;
463 }
464 
465 
466 status_t
467 link_error_reply(net_protocol *protocol, net_buffer *causedError, uint32 code,
468 	void *errorData)
469 {
470 	return B_ERROR;
471 }
472 
473 
474 static status_t
475 link_std_ops(int32 op, ...)
476 {
477 	switch (op) {
478 		case B_MODULE_INIT:
479 			return register_domain(AF_LINK, "link", NULL, NULL, &sDomain);
480 
481 		case B_MODULE_UNINIT:
482 			unregister_domain(sDomain);
483 			return B_OK;
484 
485 		default:
486 			return B_ERROR;
487 	}
488 }
489 
490 
491 //	#pragma mark -
492 
493 
494 void
495 link_init()
496 {
497 	register_domain_protocols(AF_LINK, SOCK_DGRAM, 0, "network/stack/link/v1", NULL);
498 
499 	register_domain_datalink_protocols(AF_LINK, IFT_ETHER,
500 		"network/datalink_protocols/ethernet_frame/v1",
501 		NULL);
502 }
503 
504 
505 net_protocol_module_info gLinkModule = {
506 	{
507 		"network/stack/link/v1",
508 		0,
509 		link_std_ops
510 	},
511 	link_init_protocol,
512 	link_uninit_protocol,
513 	link_open,
514 	link_close,
515 	link_free,
516 	link_connect,
517 	link_accept,
518 	link_control,
519 	link_bind,
520 	link_unbind,
521 	link_listen,
522 	link_shutdown,
523 	link_send_data,
524 	link_send_routed_data,
525 	link_send_avail,
526 	link_read_data,
527 	link_read_avail,
528 	link_get_domain,
529 	link_get_mtu,
530 	link_receive_data,
531 	link_error,
532 	link_error_reply,
533 };
534