xref: /haiku/src/add-ons/kernel/network/stack/link.cpp (revision df247f1480415f8b5258df3926e5db7cf53d9938)
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 	if (numBytes < buffer->size) {
341 		// discard any data behind the amount requested
342 		gNetBufferModule.trim(buffer, numBytes);
343 	}
344 
345 	*_buffer = buffer;
346 	return B_OK;
347 }
348 
349 
350 ssize_t
351 link_read_avail(net_protocol *_protocol)
352 {
353 	link_protocol *protocol = (link_protocol *)_protocol;
354 	return protocol->fifo.current_bytes;
355 }
356 
357 
358 struct net_domain *
359 link_get_domain(net_protocol *protocol)
360 {
361 	return sDomain;
362 }
363 
364 
365 size_t
366 link_get_mtu(net_protocol *protocol, const struct sockaddr *address)
367 {
368 	// TODO: for now
369 	return 0;
370 }
371 
372 
373 status_t
374 link_receive_data(net_buffer *buffer)
375 {
376 	return B_ERROR;
377 }
378 
379 
380 status_t
381 link_error(uint32 code, net_buffer *data)
382 {
383 	return B_ERROR;
384 }
385 
386 
387 status_t
388 link_error_reply(net_protocol *protocol, net_buffer *causedError, uint32 code,
389 	void *errorData)
390 {
391 	return B_ERROR;
392 }
393 
394 
395 static status_t
396 link_std_ops(int32 op, ...)
397 {
398 	switch (op) {
399 		case B_MODULE_INIT:
400 			return register_domain(AF_LINK, "link", NULL, NULL, &sDomain);
401 
402 		case B_MODULE_UNINIT:
403 			unregister_domain(sDomain);
404 			return B_OK;
405 
406 		default:
407 			return B_ERROR;
408 	}
409 }
410 
411 
412 //	#pragma mark -
413 
414 
415 void
416 link_init()
417 {
418 	register_domain_protocols(AF_LINK, SOCK_DGRAM, 0, "network/stack/link/v1", NULL);
419 
420 	register_domain_datalink_protocols(AF_LINK, IFT_ETHER,
421 		"network/datalink_protocols/ethernet_frame/v1",
422 		NULL);
423 }
424 
425 
426 net_protocol_module_info gLinkModule = {
427 	{
428 		"network/stack/link/v1",
429 		0,
430 		link_std_ops
431 	},
432 	link_init_protocol,
433 	link_uninit_protocol,
434 	link_open,
435 	link_close,
436 	link_free,
437 	link_connect,
438 	link_accept,
439 	link_control,
440 	link_bind,
441 	link_unbind,
442 	link_listen,
443 	link_shutdown,
444 	link_send_data,
445 	link_send_routed_data,
446 	link_send_avail,
447 	link_read_data,
448 	link_read_avail,
449 	link_get_domain,
450 	link_get_mtu,
451 	link_receive_data,
452 	link_error,
453 	link_error_reply,
454 };
455