1/*
2 * Copyright 2013, 2018, J��r��me Duval, jerome.duval@gmail.com.
3 * Copyright 2017, Philippe Houdoin, philippe.houdoin@gmail.com.
4 * Distributed under the terms of the MIT License.
5 */
6
7
8#include <net/if_media.h>
9#include <new>
10
11#include <ethernet.h>
12#include <lock.h>
13#include <util/DoublyLinkedList.h>
14#include <virtio.h>
15
16#include "ether_driver.h"
17#define ETHER_ADDR_LEN	ETHER_ADDRESS_LENGTH
18#include "virtio_net.h"
19
20
21#define VIRTIO_NET_DRIVER_MODULE_NAME "drivers/network/virtio_net/driver_v1"
22#define VIRTIO_NET_DEVICE_MODULE_NAME "drivers/network/virtio_net/device_v1"
23#define VIRTIO_NET_DEVICE_ID_GENERATOR	"virtio_net/device_id"
24
25#define BUFFER_SIZE	2048
26#define MAX_FRAME_SIZE 1536
27
28
29struct virtio_net_rx_hdr {
30	struct virtio_net_hdr	hdr;
31	uint8					pad[4];
32} _PACKED;
33
34
35struct virtio_net_tx_hdr {
36	union {
37		struct virtio_net_hdr			hdr;
38		struct virtio_net_hdr_mrg_rxbuf mhdr;
39	};
40} _PACKED;
41
42
43struct BufInfo : DoublyLinkedListLinkImpl<BufInfo> {
44	char*					buffer;
45	struct virtio_net_hdr*	hdr;
46	physical_entry			entry;
47	physical_entry			hdrEntry;
48	uint32					rxUsedLength;
49};
50
51
52typedef DoublyLinkedList<BufInfo> BufInfoList;
53
54
55typedef struct {
56	device_node*			node;
57	::virtio_device			virtio_device;
58	virtio_device_interface*	virtio;
59
60	uint64 					features;
61
62	uint32					pairsCount;
63
64	::virtio_queue*			rxQueues;
65	uint16*					rxSizes;
66
67	BufInfo**				rxBufInfos;
68	sem_id					rxDone;
69	area_id					rxArea;
70	BufInfoList				rxFullList;
71	mutex					rxLock;
72
73	::virtio_queue*			txQueues;
74	uint16*					txSizes;
75
76	BufInfo**				txBufInfos;
77	sem_id					txDone;
78	area_id					txArea;
79	BufInfoList				txFreeList;
80	mutex					txLock;
81
82	::virtio_queue			ctrlQueue;
83
84	bool					nonblocking;
85	bool					promiscuous;
86	uint32					maxframesize;
87	ether_address_t			macaddr;
88
89#define MAX_MULTI 128
90	uint32					multiCount;
91	ether_address_t			multi[MAX_MULTI];
92
93} virtio_net_driver_info;
94
95
96typedef struct {
97	virtio_net_driver_info*		info;
98} virtio_net_handle;
99
100
101#include <stdio.h>
102#include <string.h>
103#include <stdlib.h>
104
105#include <fs/devfs.h>
106
107
108//#define TRACE_VIRTIO_NET
109#ifdef TRACE_VIRTIO_NET
110#	define TRACE(x...) dprintf("virtio_net: " x)
111#else
112#	define TRACE(x...) ;
113#endif
114#define ERROR(x...)			dprintf("\33[33mvirtio_net:\33[0m " x)
115#define CALLED() 			TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
116
117
118static device_manager_info* sDeviceManager;
119
120
121static void virtio_net_rxDone(void* driverCookie, void* cookie);
122static void virtio_net_txDone(void* driverCookie, void* cookie);
123
124
125const char*
126get_feature_name(uint64 feature)
127{
128	switch (feature) {
129		case VIRTIO_NET_F_CSUM:
130			return "host checksum";
131		case VIRTIO_NET_F_GUEST_CSUM:
132			return "guest checksum";
133		case VIRTIO_NET_F_MTU:
134			return "mtu";
135		case VIRTIO_NET_F_MAC:
136			return "macaddress";
137		case VIRTIO_NET_F_GSO:
138			return "host allgso";
139		case VIRTIO_NET_F_GUEST_TSO4:
140			return "guest tso4";
141		case VIRTIO_NET_F_GUEST_TSO6:
142			return "guest tso6";
143		case VIRTIO_NET_F_GUEST_ECN:
144			return "guest tso6+ecn";
145		case VIRTIO_NET_F_GUEST_UFO:
146			return "guest ufo";
147		case VIRTIO_NET_F_HOST_TSO4:
148			return "host tso4";
149		case VIRTIO_NET_F_HOST_TSO6:
150			return "host tso6";
151		case VIRTIO_NET_F_HOST_ECN:
152			return "host tso6+ecn";
153		case VIRTIO_NET_F_HOST_UFO:
154			return "host UFO";
155		case VIRTIO_NET_F_MRG_RXBUF:
156			return "host mergerxbuffers";
157		case VIRTIO_NET_F_STATUS:
158			return "status";
159		case VIRTIO_NET_F_CTRL_VQ:
160			return "control vq";
161		case VIRTIO_NET_F_CTRL_RX:
162			return "rx mode";
163		case VIRTIO_NET_F_CTRL_VLAN:
164			return "vlan filter";
165		case VIRTIO_NET_F_CTRL_RX_EXTRA:
166			return "rx mode extra";
167		case VIRTIO_NET_F_GUEST_ANNOUNCE:
168			return "guest announce";
169		case VIRTIO_NET_F_MQ:
170			return "multiqueue";
171		case VIRTIO_NET_F_CTRL_MAC_ADDR:
172			return "set macaddress";
173	}
174	return NULL;
175}
176
177
178static status_t
179virtio_net_drain_queues(virtio_net_driver_info* info)
180{
181	BufInfo* buf = NULL;
182	while (info->virtio->queue_dequeue(info->txQueues[0], (void**)&buf, NULL))
183		info->txFreeList.Add(buf);
184
185	while (info->virtio->queue_dequeue(info->rxQueues[0], NULL, NULL))
186		;
187
188	while (info->rxFullList.RemoveHead() != NULL)
189		;
190
191	return B_OK;
192}
193
194
195static status_t
196virtio_net_rx_enqueue_buf(virtio_net_driver_info* info, BufInfo* buf)
197{
198	CALLED();
199	physical_entry entries[2];
200	entries[0] = buf->hdrEntry;
201	entries[1] = buf->entry;
202
203	memset(buf->hdr, 0, sizeof(struct virtio_net_hdr));
204
205	// queue the rx buffer
206	status_t status = info->virtio->queue_request_v(info->rxQueues[0],
207		entries, 0, 2, buf);
208	if (status != B_OK) {
209		ERROR("rx queueing on queue %d failed (%s)\n", 0, strerror(status));
210		return status;
211	}
212
213	return B_OK;
214}
215
216
217static status_t
218virtio_net_ctrl_exec_cmd(virtio_net_driver_info* info, int cmd, int value)
219{
220	struct {
221		struct virtio_net_ctrl_hdr hdr;
222		uint8 pad1;
223		uint8 onoff;
224		uint8 pad2;
225		uint8 ack;
226	} s __attribute__((aligned(2)));
227
228	s.hdr.net_class = VIRTIO_NET_CTRL_RX;
229	s.hdr.cmd = cmd;
230	s.onoff = value == 0;
231	s.ack = VIRTIO_NET_ERR;
232
233	physical_entry entries[3];
234	status_t status = get_memory_map(&s.hdr, sizeof(s.hdr), &entries[0], 1);
235	if (status != B_OK)
236		return status;
237	status = get_memory_map(&s.onoff, sizeof(s.onoff), &entries[1], 1);
238	if (status != B_OK)
239		return status;
240	status = get_memory_map(&s.ack, sizeof(s.ack), &entries[2], 1);
241	if (status != B_OK)
242		return status;
243
244	if (!info->virtio->queue_is_empty(info->ctrlQueue))
245		return B_ERROR;
246
247	status = info->virtio->queue_request_v(info->ctrlQueue, entries, 2, 1,
248		NULL);
249	if (status != B_OK)
250		return status;
251
252	while (!info->virtio->queue_dequeue(info->ctrlQueue, NULL, NULL))
253		spin(10);
254
255	return s.ack == VIRTIO_NET_OK ? B_OK : B_IO_ERROR;
256}
257
258
259static status_t
260virtio_net_set_promisc(virtio_net_driver_info* info, int value)
261{
262	return virtio_net_ctrl_exec_cmd(info, VIRTIO_NET_CTRL_RX_PROMISC, value);
263}
264
265
266static int
267vtnet_set_allmulti(virtio_net_driver_info* info, int value)
268{
269	return virtio_net_ctrl_exec_cmd(info, VIRTIO_NET_CTRL_RX_ALLMULTI, value);
270}
271
272
273#define ROUND_TO_PAGE_SIZE(x) (((x) + (B_PAGE_SIZE) - 1) & ~((B_PAGE_SIZE) - 1))
274
275
276//	#pragma mark - device module API
277
278
279static status_t
280virtio_net_init_device(void* _info, void** _cookie)
281{
282	CALLED();
283	virtio_net_driver_info* info = (virtio_net_driver_info*)_info;
284
285	device_node* parent = sDeviceManager->get_parent_node(info->node);
286	sDeviceManager->get_driver(parent, (driver_module_info**)&info->virtio,
287		(void**)&info->virtio_device);
288	sDeviceManager->put_node(parent);
289
290	info->virtio->negotiate_features(info->virtio_device,
291		VIRTIO_NET_F_STATUS | VIRTIO_NET_F_MAC | VIRTIO_NET_F_MTU
292		| VIRTIO_NET_F_CTRL_VQ | VIRTIO_NET_F_CTRL_RX
293		/* | VIRTIO_NET_F_MQ */,
294		 &info->features, &get_feature_name);
295
296	if ((info->features & VIRTIO_NET_F_MQ) != 0
297			&& (info->features & VIRTIO_NET_F_CTRL_VQ) != 0
298			&& info->virtio->read_device_config(info->virtio_device,
299				offsetof(struct virtio_net_config, max_virtqueue_pairs),
300				&info->pairsCount, sizeof(info->pairsCount)) == B_OK) {
301		system_info sysinfo;
302		if (get_system_info(&sysinfo) == B_OK
303			&& info->pairsCount > sysinfo.cpu_count) {
304			info->pairsCount = sysinfo.cpu_count;
305		}
306	} else
307		info->pairsCount = 1;
308
309	// TODO read config
310
311	// Setup queues
312	uint32 queueCount = info->pairsCount * 2;
313	if ((info->features & VIRTIO_NET_F_CTRL_VQ) != 0)
314		queueCount++;
315	::virtio_queue virtioQueues[queueCount];
316	status_t status = info->virtio->alloc_queues(info->virtio_device, queueCount,
317		virtioQueues);
318	if (status != B_OK) {
319		ERROR("queue allocation failed (%s)\n", strerror(status));
320		return status;
321	}
322
323	char* rxBuffer;
324	char* txBuffer;
325
326	info->rxQueues = new(std::nothrow) virtio_queue[info->pairsCount];
327	info->txQueues = new(std::nothrow) virtio_queue[info->pairsCount];
328	info->rxSizes = new(std::nothrow) uint16[info->pairsCount];
329	info->txSizes = new(std::nothrow) uint16[info->pairsCount];
330	if (info->rxQueues == NULL || info->txQueues == NULL
331		|| info->rxSizes == NULL || info->txSizes == NULL) {
332		status = B_NO_MEMORY;
333		goto err1;
334	}
335	for (uint32 i = 0; i < info->pairsCount; i++) {
336		info->rxQueues[i] = virtioQueues[i * 2];
337		info->txQueues[i] = virtioQueues[i * 2 + 1];
338		info->rxSizes[i] = info->virtio->queue_size(info->rxQueues[i]) / 2;
339		info->txSizes[i] = info->virtio->queue_size(info->txQueues[i]) / 2;
340	}
341	if ((info->features & VIRTIO_NET_F_CTRL_VQ) != 0)
342		info->ctrlQueue = virtioQueues[info->pairsCount * 2];
343
344	info->rxBufInfos = new(std::nothrow) BufInfo*[info->rxSizes[0]];
345	info->txBufInfos = new(std::nothrow) BufInfo*[info->txSizes[0]];
346	if (info->rxBufInfos == NULL || info->txBufInfos == NULL) {
347		status = B_NO_MEMORY;
348		goto err2;
349	}
350	memset(info->rxBufInfos, 0, sizeof(BufInfo*) * info->rxSizes[0]);
351	memset(info->txBufInfos, 0, sizeof(BufInfo*) * info->txSizes[0]);
352
353	// create receive buffer area
354	info->rxArea = create_area("virtionet rx buffer", (void**)&rxBuffer,
355		B_ANY_KERNEL_BLOCK_ADDRESS, ROUND_TO_PAGE_SIZE(
356			BUFFER_SIZE * info->rxSizes[0]),
357		B_FULL_LOCK, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
358	if (info->rxArea < B_OK) {
359		status = info->rxArea;
360		goto err3;
361	}
362
363	// initialize receive buffer descriptors
364	for (int i = 0; i < info->rxSizes[0]; i++) {
365		BufInfo* buf = new(std::nothrow) BufInfo;
366		if (buf == NULL) {
367			status = B_NO_MEMORY;
368			goto err4;
369		}
370
371		info->rxBufInfos[i] = buf;
372		buf->hdr = (struct virtio_net_hdr*)((addr_t)rxBuffer
373			+ i * BUFFER_SIZE);
374		buf->buffer = (char*)((addr_t)buf->hdr + sizeof(virtio_net_rx_hdr));
375
376		status = get_memory_map(buf->buffer,
377			BUFFER_SIZE - sizeof(virtio_net_rx_hdr), &buf->entry, 1);
378		if (status != B_OK)
379			goto err4;
380
381		status = get_memory_map(buf->hdr, sizeof(struct virtio_net_hdr),
382			&buf->hdrEntry, 1);
383		if (status != B_OK)
384			goto err4;
385	}
386
387	// create transmit buffer area
388	info->txArea = create_area("virtionet tx buffer", (void**)&txBuffer,
389		B_ANY_KERNEL_BLOCK_ADDRESS, ROUND_TO_PAGE_SIZE(
390			BUFFER_SIZE * info->txSizes[0]),
391		B_FULL_LOCK, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
392	if (info->txArea < B_OK) {
393		status = info->txArea;
394		goto err5;
395	}
396
397	// initialize transmit buffer descriptors
398	for (int i = 0; i < info->txSizes[0]; i++) {
399		BufInfo* buf = new(std::nothrow) BufInfo;
400		if (buf == NULL) {
401			status = B_NO_MEMORY;
402			goto err6;
403		}
404
405		info->txBufInfos[i] = buf;
406		buf->hdr = (struct virtio_net_hdr*)((addr_t)txBuffer
407			+ i * BUFFER_SIZE);
408		buf->buffer = (char*)((addr_t)buf->hdr + sizeof(virtio_net_tx_hdr));
409
410		status = get_memory_map(buf->buffer,
411			BUFFER_SIZE - sizeof(virtio_net_tx_hdr), &buf->entry, 1);
412		if (status != B_OK)
413			goto err6;
414
415		status = get_memory_map(buf->hdr, sizeof(struct virtio_net_hdr),
416			&buf->hdrEntry, 1);
417		if (status != B_OK)
418			goto err6;
419
420		info->txFreeList.Add(buf);
421	}
422
423	mutex_init(&info->rxLock, "virtionet rx lock");
424	mutex_init(&info->txLock, "virtionet tx lock");
425
426	// Setup interrupt
427	status = info->virtio->setup_interrupt(info->virtio_device, NULL, info);
428	if (status != B_OK) {
429		ERROR("interrupt setup failed (%s)\n", strerror(status));
430		goto err6;
431	}
432
433	status = info->virtio->queue_setup_interrupt(info->rxQueues[0],
434		virtio_net_rxDone, info);
435	if (status != B_OK) {
436		ERROR("queue interrupt setup failed (%s)\n", strerror(status));
437		goto err6;
438	}
439
440	status = info->virtio->queue_setup_interrupt(info->txQueues[0],
441		virtio_net_txDone, info);
442	if (status != B_OK) {
443		ERROR("queue interrupt setup failed (%s)\n", strerror(status));
444		goto err6;
445	}
446
447	if ((info->features & VIRTIO_NET_F_CTRL_VQ) != 0) {
448		status = info->virtio->queue_setup_interrupt(info->ctrlQueue,
449			NULL, info);
450		if (status != B_OK) {
451			ERROR("queue interrupt setup failed (%s)\n", strerror(status));
452			goto err6;
453		}
454	}
455
456	*_cookie = info;
457	return B_OK;
458
459err6:
460	for (int i = 0; i < info->txSizes[0]; i++)
461		delete info->txBufInfos[i];
462err5:
463	delete_area(info->txArea);
464err4:
465	for (int i = 0; i < info->rxSizes[0]; i++)
466		delete info->rxBufInfos[i];
467err3:
468	delete_area(info->rxArea);
469err2:
470	delete[] info->rxBufInfos;
471	delete[] info->txBufInfos;
472err1:
473	delete[] info->rxQueues;
474	delete[] info->txQueues;
475	delete[] info->rxSizes;
476	delete[] info->txSizes;
477	return status;
478}
479
480
481static void
482virtio_net_uninit_device(void* _cookie)
483{
484	CALLED();
485	virtio_net_driver_info* info = (virtio_net_driver_info*)_cookie;
486
487	info->virtio->free_interrupts(info->virtio_device);
488
489	mutex_destroy(&info->rxLock);
490	mutex_destroy(&info->txLock);
491
492	while (true) {
493		BufInfo* buf = info->txFreeList.RemoveHead();
494		if (buf == NULL)
495			break;
496	}
497
498	for (int i = 0; i < info->rxSizes[0]; i++) {
499		delete info->rxBufInfos[i];
500	}
501	for (int i = 0; i < info->txSizes[0]; i++) {
502		delete info->txBufInfos[i];
503	}
504	delete_area(info->rxArea);
505	delete_area(info->txArea);
506	delete[] info->rxBufInfos;
507	delete[] info->txBufInfos;
508	delete[] info->rxSizes;
509	delete[] info->txSizes;
510	delete[] info->rxQueues;
511	delete[] info->txQueues;
512
513	info->virtio->free_queues(info->virtio_device);
514}
515
516
517static status_t
518virtio_net_open(void* _info, const char* path, int openMode, void** _cookie)
519{
520	CALLED();
521	virtio_net_driver_info* info = (virtio_net_driver_info*)_info;
522
523	virtio_net_handle* handle = (virtio_net_handle*)malloc(
524		sizeof(virtio_net_handle));
525	if (handle == NULL)
526		return B_NO_MEMORY;
527
528	info->nonblocking = (openMode & O_NONBLOCK) != 0;
529	info->maxframesize = MAX_FRAME_SIZE;
530	info->rxDone = create_sem(0, "virtio_net_rx");
531	info->txDone = create_sem(1, "virtio_net_tx");
532	if (info->rxDone < B_OK || info->txDone < B_OK)
533		goto error;
534	handle->info = info;
535
536	if ((info->features & VIRTIO_NET_F_MAC) != 0) {
537		info->virtio->read_device_config(info->virtio_device,
538			offsetof(struct virtio_net_config, mac),
539			&info->macaddr, sizeof(info->macaddr));
540	}
541
542	if ((info->features & VIRTIO_NET_F_MTU) != 0) {
543		dprintf("mtu feature\n");
544		uint16 mtu;
545		info->virtio->read_device_config(info->virtio_device,
546			offsetof(struct virtio_net_config, mtu),
547			&mtu, sizeof(mtu));
548		// check against minimum MTU
549		if (mtu > 68)
550			info->maxframesize = mtu;
551		else
552			info->virtio->clear_feature(info->virtio_device, VIRTIO_NET_F_MTU);
553	} else {
554		dprintf("no mtu feature\n");
555	}
556
557	for (int i = 0; i < info->rxSizes[0]; i++)
558		virtio_net_rx_enqueue_buf(info, info->rxBufInfos[i]);
559
560	*_cookie = handle;
561	return B_OK;
562
563error:
564	delete_sem(info->rxDone);
565	delete_sem(info->txDone);
566	info->rxDone = info->txDone = -1;
567	free(handle);
568	return B_ERROR;
569}
570
571
572static status_t
573virtio_net_close(void* cookie)
574{
575	virtio_net_handle* handle = (virtio_net_handle*)cookie;
576	CALLED();
577
578	virtio_net_driver_info* info = handle->info;
579	delete_sem(info->rxDone);
580	delete_sem(info->txDone);
581	info->rxDone = info->txDone = -1;
582
583	return B_OK;
584}
585
586
587static status_t
588virtio_net_free(void* cookie)
589{
590	CALLED();
591	virtio_net_handle* handle = (virtio_net_handle*)cookie;
592
593	virtio_net_driver_info* info = handle->info;
594	virtio_net_drain_queues(info);
595	free(handle);
596	return B_OK;
597}
598
599
600static void
601virtio_net_rxDone(void* driverCookie, void* cookie)
602{
603	CALLED();
604	virtio_net_driver_info* info = (virtio_net_driver_info*)cookie;
605
606	release_sem_etc(info->rxDone, 1, B_DO_NOT_RESCHEDULE);
607}
608
609
610static status_t
611virtio_net_read(void* cookie, off_t pos, void* buffer, size_t* _length)
612{
613	CALLED();
614	virtio_net_handle* handle = (virtio_net_handle*)cookie;
615	virtio_net_driver_info* info = handle->info;
616
617	mutex_lock(&info->rxLock);
618	while (info->rxFullList.Head() == NULL) {
619		mutex_unlock(&info->rxLock);
620
621		if (info->nonblocking)
622			return B_WOULD_BLOCK;
623		TRACE("virtio_net_read: waiting\n");
624		status_t status = acquire_sem(info->rxDone);
625		if (status != B_OK) {
626			ERROR("acquire_sem(rxDone) failed (%s)\n", strerror(status));
627			return status;
628		}
629		int32 semCount = 0;
630		get_sem_count(info->rxDone, &semCount);
631		if (semCount > 0)
632			acquire_sem_etc(info->rxDone, semCount, B_RELATIVE_TIMEOUT, 0);
633
634		mutex_lock(&info->rxLock);
635		while (info->rxDone != -1) {
636			uint32 usedLength = 0;
637			BufInfo* buf = NULL;
638			if (!info->virtio->queue_dequeue(info->rxQueues[0], (void**)&buf,
639					&usedLength) || buf == NULL) {
640				break;
641			}
642
643			buf->rxUsedLength = usedLength;
644			info->rxFullList.Add(buf);
645		}
646		TRACE("virtio_net_read: finished waiting\n");
647	}
648
649	BufInfo* buf = info->rxFullList.RemoveHead();
650	*_length = MIN(buf->rxUsedLength, *_length);
651	memcpy(buffer, buf->buffer, *_length);
652	virtio_net_rx_enqueue_buf(info, buf);
653	mutex_unlock(&info->rxLock);
654	return B_OK;
655}
656
657
658static void
659virtio_net_txDone(void* driverCookie, void* cookie)
660{
661	CALLED();
662	virtio_net_driver_info* info = (virtio_net_driver_info*)cookie;
663
664	release_sem_etc(info->txDone, 1, B_DO_NOT_RESCHEDULE);
665}
666
667
668static status_t
669virtio_net_write(void* cookie, off_t pos, const void* buffer,
670	size_t* _length)
671{
672	CALLED();
673	virtio_net_handle* handle = (virtio_net_handle*)cookie;
674	virtio_net_driver_info* info = handle->info;
675
676	mutex_lock(&info->txLock);
677	while (info->txFreeList.Head() == NULL) {
678		mutex_unlock(&info->txLock);
679		if (info->nonblocking)
680			return B_WOULD_BLOCK;
681
682		status_t status = acquire_sem(info->txDone);
683		if (status != B_OK) {
684			ERROR("acquire_sem(txDone) failed (%s)\n", strerror(status));
685			return status;
686		}
687
688		int32 semCount = 0;
689		get_sem_count(info->txDone, &semCount);
690		if (semCount > 0)
691			acquire_sem_etc(info->txDone, semCount, B_RELATIVE_TIMEOUT, 0);
692
693		mutex_lock(&info->txLock);
694		while (info->txDone != -1) {
695			BufInfo* buf = NULL;
696			if (!info->virtio->queue_dequeue(info->txQueues[0], (void**)&buf,
697					NULL) || buf == NULL) {
698				break;
699			}
700
701			info->txFreeList.Add(buf);
702		}
703	}
704	BufInfo* buf = info->txFreeList.RemoveHead();
705
706	TRACE("virtio_net_write: copying %lu\n", MIN(MAX_FRAME_SIZE, *_length));
707	memcpy(buf->buffer, buffer, MIN(MAX_FRAME_SIZE, *_length));
708	memset(buf->hdr, 0, sizeof(virtio_net_hdr));
709
710	physical_entry entries[2];
711	entries[0] = buf->hdrEntry;
712	entries[0].size = sizeof(virtio_net_hdr);
713	entries[1] = buf->entry;
714	entries[1].size = MIN(MAX_FRAME_SIZE, *_length);
715
716	// queue the virtio_net_hdr + buffer data
717	status_t status = info->virtio->queue_request_v(info->txQueues[0],
718		entries, 2, 0, buf);
719	mutex_unlock(&info->txLock);
720	if (status != B_OK) {
721		ERROR("tx queueing on queue %d failed (%s)\n", 0, strerror(status));
722		return status;
723	}
724
725	return B_OK;
726}
727
728
729static status_t
730virtio_net_ioctl(void* cookie, uint32 op, void* buffer, size_t length)
731{
732	// CALLED();
733	virtio_net_handle* handle = (virtio_net_handle*)cookie;
734	virtio_net_driver_info* info = handle->info;
735
736	// TRACE("ioctl(op = %lx)\n", op);
737
738	switch (op) {
739		case ETHER_GETADDR:
740			TRACE("ioctl: get macaddr\n");
741			return user_memcpy(buffer, &info->macaddr, sizeof(info->macaddr));
742
743		case ETHER_INIT:
744			TRACE("ioctl: init\n");
745			return B_OK;
746
747		case ETHER_GETFRAMESIZE:
748			TRACE("ioctl: get frame size\n");
749			if (length != sizeof(info->maxframesize))
750				return B_BAD_VALUE;
751
752			return user_memcpy(buffer, &info->maxframesize,
753				sizeof(info->maxframesize));
754
755		case ETHER_SETPROMISC:
756		{
757			TRACE("ioctl: set promisc\n");
758			int32 value;
759			if (length != sizeof(value))
760				return B_BAD_VALUE;
761			if (user_memcpy(&value, buffer, sizeof(value)) != B_OK)
762				return B_BAD_ADDRESS;
763			if (info->promiscuous == value)
764				return B_OK;
765			info->promiscuous = value;
766			return virtio_net_set_promisc(info, value);
767		}
768		case ETHER_NONBLOCK:
769		{
770			TRACE("ioctl: non blocking ? %s\n",
771				info->nonblocking ? "yes" : "no");
772			int32 value;
773			if (length != sizeof(value))
774				return B_BAD_VALUE;
775			if (user_memcpy(&value, buffer, sizeof(value)) != B_OK)
776				return B_BAD_ADDRESS;
777			info->nonblocking = value == 0;
778			return B_OK;
779		}
780		case ETHER_ADDMULTI:
781		{
782			uint32 i, multiCount = info->multiCount;
783			TRACE("ioctl: add multicast\n");
784
785			if ((info->features & VIRTIO_NET_F_CTRL_RX) == 0)
786				return B_NOT_SUPPORTED;
787
788			if (multiCount == MAX_MULTI)
789				return B_ERROR;
790
791			for (i = 0; i < multiCount; i++) {
792				if (memcmp(&info->multi[i], buffer,
793					sizeof(info->multi[0])) == 0) {
794					break;
795				}
796			}
797
798			if (i == multiCount) {
799				memcpy(&info->multi[i], buffer, sizeof(info->multi[i]));
800				info->multiCount++;
801			}
802			if (info->multiCount == 1) {
803				TRACE("Enabling multicast\n");
804				vtnet_set_allmulti(info, 1);
805			}
806
807			return B_OK;
808		}
809		case ETHER_REMMULTI:
810		{
811			uint32 i, multiCount = info->multiCount;
812			TRACE("ioctl: remove multicast\n");
813
814			if ((info->features & VIRTIO_NET_F_CTRL_RX) == 0)
815				return B_NOT_SUPPORTED;
816
817			for (i = 0; i < multiCount; i++) {
818				if (memcmp(&info->multi[i], buffer,
819					sizeof(info->multi[0])) == 0) {
820					break;
821				}
822			}
823
824			if (i != multiCount) {
825				if (i < multiCount - 1) {
826					memmove(&info->multi[i], &info->multi[i + 1],
827						sizeof(info->multi[i]) * (multiCount - i - 1));
828				}
829				info->multiCount--;
830				if (info->multiCount == 0) {
831					TRACE("Disabling multicast\n");
832					vtnet_set_allmulti(info, 0);
833				}
834				return B_OK;
835			}
836			return B_BAD_VALUE;
837		}
838		case ETHER_GET_LINK_STATE:
839		{
840			TRACE("ioctl: get link state\n");
841			ether_link_state_t state;
842			uint16 status = VIRTIO_NET_S_LINK_UP;
843			if ((info->features & VIRTIO_NET_F_STATUS) != 0) {
844				info->virtio->read_device_config(info->virtio_device,
845					offsetof(struct virtio_net_config, status),
846					&status, sizeof(status));
847			}
848			state.media = ((status & VIRTIO_NET_S_LINK_UP) != 0 ? IFM_ACTIVE : 0)
849				| IFM_ETHER | IFM_FULL_DUPLEX | IFM_10G_T;
850			state.speed = 10000000000ULL;
851			state.quality = 1000;
852
853			return user_memcpy(buffer, &state, sizeof(ether_link_state_t));
854		}
855
856		default:
857			ERROR("ioctl: unknown message %" B_PRIx32 "\n", op);
858			break;
859	}
860
861
862	return B_DEV_INVALID_IOCTL;
863}
864
865
866//	#pragma mark - driver module API
867
868
869static float
870virtio_net_supports_device(device_node* parent)
871{
872	CALLED();
873	const char* bus;
874	uint16 deviceType;
875
876	// make sure parent is really the Virtio bus manager
877	if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
878		return -1;
879
880	if (strcmp(bus, "virtio"))
881		return 0.0;
882
883	// check whether it's really a Direct Access Device
884	if (sDeviceManager->get_attr_uint16(parent, VIRTIO_DEVICE_TYPE_ITEM,
885			&deviceType, true) != B_OK || deviceType != VIRTIO_DEVICE_ID_NETWORK)
886		return 0.0;
887
888	TRACE("Virtio network device found!\n");
889
890	return 0.6;
891}
892
893
894static status_t
895virtio_net_register_device(device_node* node)
896{
897	CALLED();
898
899	device_attr attrs[] = {
900		{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = "Virtio Network"} },
901		{ NULL }
902	};
903
904	return sDeviceManager->register_node(node, VIRTIO_NET_DRIVER_MODULE_NAME,
905		attrs, NULL, NULL);
906}
907
908
909static status_t
910virtio_net_init_driver(device_node* node, void** cookie)
911{
912	CALLED();
913
914	virtio_net_driver_info* info = (virtio_net_driver_info*)malloc(
915		sizeof(virtio_net_driver_info));
916	if (info == NULL)
917		return B_NO_MEMORY;
918
919	memset(info, 0, sizeof(*info));
920
921	info->node = node;
922
923	*cookie = info;
924	return B_OK;
925}
926
927
928static void
929virtio_net_uninit_driver(void* _cookie)
930{
931	CALLED();
932	virtio_net_driver_info* info = (virtio_net_driver_info*)_cookie;
933	free(info);
934}
935
936
937static status_t
938virtio_net_register_child_devices(void* _cookie)
939{
940	CALLED();
941	virtio_net_driver_info* info = (virtio_net_driver_info*)_cookie;
942	status_t status;
943
944	int32 id = sDeviceManager->create_id(VIRTIO_NET_DEVICE_ID_GENERATOR);
945	if (id < 0)
946		return id;
947
948	char name[64];
949	snprintf(name, sizeof(name), "net/virtio/%" B_PRId32,
950		id);
951
952	status = sDeviceManager->publish_device(info->node, name,
953		VIRTIO_NET_DEVICE_MODULE_NAME);
954
955	return status;
956}
957
958
959//	#pragma mark -
960
961
962module_dependency module_dependencies[] = {
963	{B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&sDeviceManager},
964	{}
965};
966
967struct device_module_info sVirtioNetDevice = {
968	{
969		VIRTIO_NET_DEVICE_MODULE_NAME,
970		0,
971		NULL
972	},
973
974	virtio_net_init_device,
975	virtio_net_uninit_device,
976	NULL, // remove,
977
978	virtio_net_open,
979	virtio_net_close,
980	virtio_net_free,
981	virtio_net_read,
982	virtio_net_write,
983	NULL,	// io
984	virtio_net_ioctl,
985
986	NULL,	// select
987	NULL,	// deselect
988};
989
990struct driver_module_info sVirtioNetDriver = {
991	{
992		VIRTIO_NET_DRIVER_MODULE_NAME,
993		0,
994		NULL
995	},
996
997	virtio_net_supports_device,
998	virtio_net_register_device,
999	virtio_net_init_driver,
1000	virtio_net_uninit_driver,
1001	virtio_net_register_child_devices,
1002	NULL,	// rescan
1003	NULL,	// removed
1004};
1005
1006module_info* modules[] = {
1007	(module_info*)&sVirtioNetDriver,
1008	(module_info*)&sVirtioNetDevice,
1009	NULL
1010};
1011