1/*
2 * Copyright 2023, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Augustin Cavalier <waddlesplash>
7 *		Axel D��rfler, axeld@pinc-software.de
8 *		Sean Brady, swangeon@gmail.com
9 */
10
11#include <new>
12#include <string.h>
13
14#include <fs/select_sync_pool.h>
15#include <fs/devfs.h>
16#include <util/AutoLock.h>
17#include <util/Random.h>
18
19#include <net_buffer.h>
20#include <net_device.h>
21#include <net_stack.h>
22
23#include <net/if.h>
24#include <net/if_dl.h>
25#include <net/if_media.h>
26#include <net/if_types.h>
27#include <net/if_tun.h>
28#include <netinet/in.h>
29#include <ethernet.h>
30
31
32//#define TRACE_TUNNEL
33#ifdef TRACE_TUNNEL
34#	define TRACE(x...) dprintf("network/tunnel: " x)
35#else
36#   define TRACE(x...)
37#endif
38
39#define CALLED(x...)			TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
40#define TRACE_ALWAYS(x...)		dprintf("network/tunnel: " x)
41
42
43struct tunnel_device : net_device {
44	bool				is_tap;
45
46	net_fifo			send_queue, receive_queue;
47
48	int32				open_count;
49
50	mutex				select_lock;
51	select_sync_pool*	select_pool;
52};
53
54#define TUNNEL_QUEUE_MAX (ETHER_MAX_FRAME_SIZE * 32)
55
56
57struct net_buffer_module_info* gBufferModule;
58static net_stack_module_info* gStackModule;
59
60
61//	#pragma mark - devices array
62
63
64static tunnel_device* gDevices[10] = {};
65static mutex gDevicesLock = MUTEX_INITIALIZER("tunnel devices");
66
67
68static tunnel_device*
69find_tunnel_device(const char* name)
70{
71	ASSERT_LOCKED_MUTEX(&gDevicesLock);
72	for (size_t i = 0; i < B_COUNT_OF(gDevices); i++) {
73		if (gDevices[i] == NULL)
74			continue;
75
76		if (strcmp(gDevices[i]->name, name) == 0)
77			return gDevices[i];
78	}
79	return NULL;
80}
81
82
83//	#pragma mark - devfs device
84
85
86struct tunnel_cookie {
87	tunnel_device*	device;
88	uint32		flags;
89};
90
91
92status_t
93tunnel_open(const char* name, uint32 flags, void** _cookie)
94{
95	MutexLocker devicesLocker(gDevicesLock);
96	tunnel_device* device = find_tunnel_device(name);
97	if (device == NULL)
98		return ENODEV;
99	if (atomic_or(&device->open_count, 1) != 0)
100		return EBUSY;
101
102	tunnel_cookie* cookie = new(std::nothrow) tunnel_cookie;
103	if (cookie == NULL)
104		return B_NO_MEMORY;
105
106	cookie->device = device;
107	cookie->flags = flags;
108
109	*_cookie = cookie;
110	return B_OK;
111}
112
113
114status_t
115tunnel_close(void* _cookie)
116{
117	tunnel_cookie* cookie = (tunnel_cookie*)_cookie;
118
119	// Wake up the send queue, so that any threads waiting to read return at once.
120	release_sem_etc(cookie->device->send_queue.notify, B_INTERRUPTED, B_RELEASE_ALL);
121
122	return B_OK;
123}
124
125
126status_t
127tunnel_free(void* _cookie)
128{
129	tunnel_cookie* cookie = (tunnel_cookie*)_cookie;
130	atomic_and(&cookie->device->open_count, 0);
131	delete cookie;
132	return B_OK;
133}
134
135
136status_t
137tunnel_control(void* _cookie, uint32 op, void* data, size_t len)
138{
139	tunnel_cookie* cookie = (tunnel_cookie*)_cookie;
140
141	switch (op) {
142		case B_SET_NONBLOCKING_IO:
143			cookie->flags |= O_NONBLOCK;
144			return B_OK;
145		case B_SET_BLOCKING_IO:
146			cookie->flags &= ~O_NONBLOCK;
147			return B_OK;
148	}
149
150	return B_DEV_INVALID_IOCTL;
151}
152
153
154status_t
155tunnel_read(void* _cookie, off_t position, void* data, size_t* _length)
156{
157	tunnel_cookie* cookie = (tunnel_cookie*)_cookie;
158
159	net_buffer* buffer = NULL;
160	status_t status = gStackModule->fifo_dequeue_buffer(
161		&cookie->device->send_queue, 0, B_INFINITE_TIMEOUT, &buffer);
162	if (status != B_OK)
163		return status;
164
165	const size_t length = min_c(*_length, buffer->size);
166	status = gBufferModule->read(buffer, 0, data, length);
167	if (status != B_OK)
168		return status;
169	*_length = length;
170
171	gBufferModule->free(buffer);
172	return B_OK;
173}
174
175
176status_t
177tunnel_write(void* _cookie, off_t position, const void* data, size_t* _length)
178{
179	tunnel_cookie* cookie = (tunnel_cookie*)_cookie;
180
181	net_buffer* buffer = gBufferModule->create(256);
182	if (buffer == NULL)
183		return B_NO_MEMORY;
184
185	status_t status = gBufferModule->append(buffer, data, *_length);
186	if (status != B_OK) {
187		gBufferModule->free(buffer);
188		return status;
189	}
190
191	if (!cookie->device->is_tap) {
192		// TUN: Detect packet type.
193		uint8 version;
194		status = gBufferModule->read(buffer, 0, &version, 1);
195		if (status != B_OK) {
196			gBufferModule->free(buffer);
197			return status;
198		}
199
200		version = (version & 0xF0) >> 4;
201		if (version != 4 && version != 6) {
202			// Not any IP packet we recognize.
203			gBufferModule->free(buffer);
204			return B_BAD_DATA;
205		}
206		buffer->type = (version == 6) ? B_NET_FRAME_TYPE_IPV6
207			: B_NET_FRAME_TYPE_IPV4;
208
209		struct sockaddr_in& src = *(struct sockaddr_in*)buffer->source;
210		struct sockaddr_in& dst = *(struct sockaddr_in*)buffer->destination;
211		src.sin_len		= dst.sin_len		= sizeof(sockaddr_in);
212		src.sin_family	= dst.sin_family	= (version == 6) ? AF_INET6 : AF_INET;
213		src.sin_port	= dst.sin_port		= 0;
214		src.sin_addr.s_addr = dst.sin_addr.s_addr = 0;
215	}
216
217	// We use a queue and the receive_data() hook instead of device_enqueue_buffer()
218	// for two reasons: 1. listeners (e.g. packet capture) are only processed by the
219	// reader thread that calls receive_data(), and 2. device_enqueue_buffer() has
220	// to look up the device interface every time, which is inefficient.
221	status = gStackModule->fifo_enqueue_buffer(&cookie->device->receive_queue, buffer);
222	if (status != B_OK)
223		gBufferModule->free(buffer);
224
225	return status;
226}
227
228
229status_t
230tunnel_select(void* _cookie, uint8 event, uint32 ref, selectsync* sync)
231{
232	tunnel_cookie* cookie = (tunnel_cookie*)_cookie;
233
234	if (event != B_SELECT_READ && event != B_SELECT_WRITE)
235		return B_BAD_VALUE;
236
237	MutexLocker selectLocker(cookie->device->select_lock);
238	status_t status = add_select_sync_pool_entry(&cookie->device->select_pool, sync, event);
239	if (status != B_OK)
240		return B_BAD_VALUE;
241	selectLocker.Unlock();
242
243	MutexLocker fifoLocker(cookie->device->send_queue.lock);
244	if (event == B_SELECT_READ && cookie->device->send_queue.current_bytes != 0)
245		notify_select_event(sync, event);
246	if (event == B_SELECT_WRITE)
247		notify_select_event(sync, event);
248
249	return B_OK;
250}
251
252
253status_t
254tunnel_deselect(void* _cookie, uint8 event, selectsync* sync)
255{
256	tunnel_cookie* cookie = (tunnel_cookie*)_cookie;
257
258	MutexLocker selectLocker(cookie->device->select_lock);
259	if (event != B_SELECT_READ && event != B_SELECT_WRITE)
260		return B_BAD_VALUE;
261	return remove_select_sync_pool_entry(&cookie->device->select_pool, sync, event);
262}
263
264
265static device_hooks sDeviceHooks = {
266	tunnel_open,
267	tunnel_close,
268	tunnel_free,
269	tunnel_control,
270	tunnel_read,
271	tunnel_write,
272	tunnel_select,
273	tunnel_deselect,
274};
275
276
277//	#pragma mark - network stack device
278
279
280status_t
281tunnel_init(const char* name, net_device** _device)
282{
283	const bool isTAP = strncmp(name, "tap/", 4) == 0;
284	if (!isTAP && strncmp(name, "tun/", 4) != 0)
285		return B_BAD_VALUE;
286	if (strlen(name) >= sizeof(tunnel_device::name))
287		return ENAMETOOLONG;
288
289	// Make sure this device doesn't already exist.
290	MutexLocker devicesLocker(gDevicesLock);
291	if (find_tunnel_device(name) != NULL)
292		return EEXIST;
293
294	tunnel_device* device = new(std::nothrow) tunnel_device;
295	if (device == NULL)
296		return B_NO_MEMORY;
297
298	ssize_t index = -1;
299	for (size_t i = 0; i < B_COUNT_OF(gDevices); i++) {
300		if (gDevices[i] != NULL)
301			continue;
302
303		gDevices[i] = device;
304		index = i;
305		break;
306	}
307	if (index < 0) {
308		delete device;
309		return ENOSPC;
310	}
311	devicesLocker.Unlock();
312
313	memset(device, 0, sizeof(tunnel_device));
314	strcpy(device->name, name);
315
316	device->mtu = ETHER_MAX_FRAME_SIZE;
317	device->media = IFM_ACTIVE;
318
319	device->is_tap = isTAP;
320	if (device->is_tap) {
321		device->flags = IFF_BROADCAST | IFF_ALLMULTI | IFF_LINK;
322		device->type = IFT_ETHER;
323
324		// Generate a random MAC address.
325		for (int i = 0; i < ETHER_ADDRESS_LENGTH; i++)
326			device->address.data[i] = secure_get_random<uint8>();
327		device->address.data[0] &= 0xFE; // multicast
328		device->address.data[0] |= 0x02; // local assignment
329
330		device->address.length = ETHER_ADDRESS_LENGTH;
331	} else {
332		device->flags = IFF_POINTOPOINT | IFF_LINK;
333		device->type = IFT_TUNNEL;
334	}
335
336	status_t status = gStackModule->init_fifo(&device->send_queue,
337		"tunnel send queue", TUNNEL_QUEUE_MAX);
338	if (status != B_OK) {
339		delete device;
340		return status;
341	}
342
343	status = gStackModule->init_fifo(&device->receive_queue,
344		"tunnel receive queue", TUNNEL_QUEUE_MAX);
345	if (status != B_OK) {
346		gStackModule->uninit_fifo(&device->send_queue);
347		delete device;
348		return status;
349	}
350
351	mutex_init(&device->select_lock, "tunnel select lock");
352
353	status = devfs_publish_device(name, &sDeviceHooks);
354	if (status != B_OK) {
355		gStackModule->uninit_fifo(&device->send_queue);
356		gStackModule->uninit_fifo(&device->receive_queue);
357		delete device;
358		return status;
359	}
360
361	*_device = device;
362	return B_OK;
363}
364
365
366status_t
367tunnel_uninit(net_device* _device)
368{
369	tunnel_device* device = (tunnel_device*)_device;
370
371	MutexLocker devicesLocker(gDevicesLock);
372	if (atomic_get(&device->open_count) != 0)
373		return EBUSY;
374
375	for (size_t i = 0; i < B_COUNT_OF(gDevices); i++) {
376		if (gDevices[i] != device)
377			continue;
378
379		gDevices[i] = NULL;
380		break;
381	}
382	status_t status = devfs_unpublish_device(device->name, false);
383	if (status != B_OK)
384		panic("devfs_unpublish_device failed: %" B_PRId32, status);
385
386	gStackModule->uninit_fifo(&device->send_queue);
387	gStackModule->uninit_fifo(&device->receive_queue);
388	mutex_destroy(&device->select_lock);
389	delete device;
390	return B_OK;
391}
392
393
394status_t
395tunnel_up(net_device* _device)
396{
397	return B_OK;
398}
399
400
401void
402tunnel_down(net_device* _device)
403{
404	tunnel_device* device = (tunnel_device*)_device;
405
406	// Wake up the receive queue, so that the reader thread returns at once.
407	release_sem_etc(device->receive_queue.notify, B_INTERRUPTED, B_RELEASE_ALL);
408}
409
410
411status_t
412tunnel_control(net_device* device, int32 op, void* argument, size_t length)
413{
414	return B_BAD_VALUE;
415}
416
417
418status_t
419tunnel_send_data(net_device* _device, net_buffer* buffer)
420{
421	tunnel_device* device = (tunnel_device*)_device;
422
423	status_t status = B_OK;
424	if (!device->is_tap) {
425		// Ensure this is an IP frame.
426		struct sockaddr_in& dst = *(struct sockaddr_in*)buffer->destination;
427		if (dst.sin_family != AF_INET && dst.sin_family != AF_INET6)
428			return B_BAD_DATA;
429	}
430
431	status = gStackModule->fifo_enqueue_buffer(
432		&device->send_queue, buffer);
433	if (status == B_OK) {
434		MutexLocker selectLocker(device->select_lock);
435		notify_select_event_pool(device->select_pool, B_SELECT_READ);
436	}
437
438	return status;
439}
440
441
442status_t
443tunnel_receive_data(net_device* _device, net_buffer** _buffer)
444{
445	tunnel_device* device = (tunnel_device*)_device;
446	return gStackModule->fifo_dequeue_buffer(&device->receive_queue,
447		0, B_INFINITE_TIMEOUT, _buffer);
448}
449
450
451status_t
452tunnel_set_mtu(net_device* device, size_t mtu)
453{
454	if (mtu > 65536 || mtu < 16)
455		return B_BAD_VALUE;
456
457	device->mtu = mtu;
458	return B_OK;
459}
460
461
462status_t
463tunnel_set_promiscuous(net_device* device, bool promiscuous)
464{
465	return EOPNOTSUPP;
466}
467
468
469status_t
470tunnel_set_media(net_device* device, uint32 media)
471{
472	return EOPNOTSUPP;
473}
474
475
476status_t
477tunnel_add_multicast(net_device* device, const sockaddr* address)
478{
479	return B_OK;
480}
481
482
483status_t
484tunnel_remove_multicast(net_device* device, const sockaddr* address)
485{
486	return B_OK;
487}
488
489
490net_device_module_info sTunModule = {
491	{
492		"network/devices/tunnel/v1",
493		0,
494		NULL
495	},
496	tunnel_init,
497	tunnel_uninit,
498	tunnel_up,
499	tunnel_down,
500	tunnel_control,
501	tunnel_send_data,
502	tunnel_receive_data,
503	tunnel_set_mtu,
504	tunnel_set_promiscuous,
505	tunnel_set_media,
506	tunnel_add_multicast,
507	tunnel_remove_multicast,
508};
509
510module_dependency module_dependencies[] = {
511	{NET_STACK_MODULE_NAME, (module_info**)&gStackModule},
512	{NET_BUFFER_MODULE_NAME, (module_info**)&gBufferModule},
513	{}
514};
515
516module_info* modules[] = {
517	(module_info*)&sTunModule,
518	NULL
519};
520