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