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