xref: /haiku/src/add-ons/kernel/network/stack/link.cpp (revision 3cb015b1ee509d69c643506e8ff573808c86dcfc)
1 /*
2  * Copyright 2006, 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 			// count number of interfaces
178 			struct ifconf config;
179 			if (user_memcpy(&config, value, sizeof(struct ifconf)) < B_OK)
180 				return B_BAD_ADDRESS;
181 
182 			return list_device_interfaces(config.ifc_buf, config.ifc_len);
183 		}
184 
185 		case SIOCGIFADDR:
186 		{
187 			// get address of interface
188 			struct ifreq request;
189 			if (user_memcpy(&request, value, IF_NAMESIZE) < B_OK)
190 				return B_BAD_ADDRESS;
191 
192 			net_device_interface *interface = get_device_interface(request.ifr_name);
193 			if (interface != NULL) {
194 				get_device_interface_address(interface, &request.ifr_addr);
195 				put_device_interface(interface);
196 			} else
197 				return ENODEV;
198 
199 			return user_memcpy(&((struct ifreq *)value)->ifr_addr,
200 				&request.ifr_addr, request.ifr_addr.sa_len);
201 		}
202 
203 		case SIOCSPACKETCAP:
204 		{
205 			// start packet monitoring
206 
207 			if (protocol->registered_monitor)
208 				return B_BUSY;
209 
210 			struct ifreq request;
211 			if (user_memcpy(&request, value, IF_NAMESIZE) < B_OK)
212 				return B_BAD_ADDRESS;
213 
214 			net_device_interface *interface = get_device_interface(request.ifr_name);
215 			status_t status;
216 			if (interface != NULL) {
217 				status = register_device_monitor(interface->device,
218 					link_monitor_data, protocol);
219 				if (status == B_OK) {
220 					// we're now registered
221 					strlcpy(protocol->registered_interface, request.ifr_name, IF_NAMESIZE);
222 					protocol->registered_monitor = true;
223 				}
224 				put_device_interface(interface);
225 			} else
226 				status = ENODEV;
227 
228 			return status;
229 		}
230 
231 		case SIOCCPACKETCAP:
232 		{
233 			// stop packet monitoring
234 
235 			if (!protocol->registered_monitor)
236 				return B_BAD_VALUE;
237 
238 			struct ifreq request;
239 			if (user_memcpy(&request, value, IF_NAMESIZE) < B_OK)
240 				return B_BAD_ADDRESS;
241 
242 			net_device_interface *interface = get_device_interface(request.ifr_name);
243 			status_t status;
244 			if (interface != NULL) {
245 				status = unregister_device_monitor(interface->device,
246 					link_monitor_data, protocol);
247 				if (status == B_OK) {
248 					// we're now no longer registered
249 					protocol->registered_monitor = false;
250 				}
251 				put_device_interface(interface);
252 			} else
253 				status = ENODEV;
254 
255 			return status;
256 		}
257 	}
258 
259 	return datalink_control(sDomain, option, value, _length);
260 }
261 
262 
263 status_t
264 link_bind(net_protocol *protocol, struct sockaddr *address)
265 {
266 	// TODO: bind to a specific interface and ethernet type
267 	return B_ERROR;
268 }
269 
270 
271 status_t
272 link_unbind(net_protocol *protocol, struct sockaddr *address)
273 {
274 	return B_ERROR;
275 }
276 
277 
278 status_t
279 link_listen(net_protocol *protocol, int count)
280 {
281 	return EOPNOTSUPP;
282 }
283 
284 
285 status_t
286 link_shutdown(net_protocol *protocol, int direction)
287 {
288 	return EOPNOTSUPP;
289 }
290 
291 
292 status_t
293 link_send_data(net_protocol *protocol, net_buffer *buffer)
294 {
295 	return B_NOT_ALLOWED;
296 }
297 
298 
299 status_t
300 link_send_routed_data(net_protocol *protocol, struct net_route *route,
301 	net_buffer *buffer)
302 {
303 	return B_NOT_ALLOWED;
304 }
305 
306 
307 ssize_t
308 link_send_avail(net_protocol *protocol)
309 {
310 	return B_ERROR;
311 }
312 
313 
314 status_t
315 link_read_data(net_protocol *_protocol, size_t numBytes, uint32 flags,
316 	net_buffer **_buffer)
317 {
318 	link_protocol *protocol = (link_protocol *)_protocol;
319 
320 	dprintf("link_read is waiting for data...\n");
321 
322 	net_buffer *buffer;
323 	status_t status = fifo_dequeue_buffer(&protocol->fifo,
324 		flags, protocol->socket->receive.timeout, &buffer);
325 	if (status < B_OK)
326 		return status;
327 
328 	if (numBytes < buffer->size) {
329 		// discard any data behind the amount requested
330 		gNetBufferModule.trim(buffer, numBytes);
331 	}
332 
333 	*_buffer = buffer;
334 	return B_OK;
335 }
336 
337 
338 ssize_t
339 link_read_avail(net_protocol *_protocol)
340 {
341 	link_protocol *protocol = (link_protocol *)_protocol;
342 	return protocol->fifo.current_bytes;
343 }
344 
345 
346 struct net_domain *
347 link_get_domain(net_protocol *protocol)
348 {
349 	return sDomain;
350 }
351 
352 
353 size_t
354 link_get_mtu(net_protocol *protocol, const struct sockaddr *address)
355 {
356 	// TODO: for now
357 	return 0;
358 }
359 
360 
361 status_t
362 link_receive_data(net_buffer *buffer)
363 {
364 	return B_ERROR;
365 }
366 
367 
368 status_t
369 link_error(uint32 code, net_buffer *data)
370 {
371 	return B_ERROR;
372 }
373 
374 
375 status_t
376 link_error_reply(net_protocol *protocol, net_buffer *causedError, uint32 code,
377 	void *errorData)
378 {
379 	return B_ERROR;
380 }
381 
382 
383 static status_t
384 link_std_ops(int32 op, ...)
385 {
386 	switch (op) {
387 		case B_MODULE_INIT:
388 			return register_domain(AF_LINK, "link", NULL, NULL, &sDomain);
389 
390 		case B_MODULE_UNINIT:
391 			unregister_domain(sDomain);
392 			return B_OK;
393 
394 		default:
395 			return B_ERROR;
396 	}
397 }
398 
399 
400 //	#pragma mark -
401 
402 
403 void
404 link_init()
405 {
406 	register_domain_protocols(AF_LINK, SOCK_DGRAM, 0, "network/stack/link/v1", NULL);
407 
408 	register_domain_datalink_protocols(AF_LINK, IFT_ETHER,
409 		"network/datalink_protocols/ethernet_frame/v1",
410 		NULL);
411 }
412 
413 
414 net_protocol_module_info gLinkModule = {
415 	{
416 		"network/stack/link/v1",
417 		0,
418 		link_std_ops
419 	},
420 	link_init_protocol,
421 	link_uninit_protocol,
422 	link_open,
423 	link_close,
424 	link_free,
425 	link_connect,
426 	link_accept,
427 	link_control,
428 	link_bind,
429 	link_unbind,
430 	link_listen,
431 	link_shutdown,
432 	link_send_data,
433 	link_send_routed_data,
434 	link_send_avail,
435 	link_read_data,
436 	link_read_avail,
437 	link_get_domain,
438 	link_get_mtu,
439 	link_receive_data,
440 	link_error,
441 	link_error_reply,
442 };
443