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