01 // vim: set ft=c:
02 
03 // Warning: terrible code ahead. this still needs a lot of work
04 
05 // In the future we'll probably have 2 FIFOs (pending frames & empty buffers)
06 // TODO: check if FIFO implementation is suitable for high throughput
07 
08 #define NET_FIFO_DEPTH      1024
09 
10 #define ETHERNET_FRAME_SIZE 1548
11 
12 #define ETHERTYPE_IPV4      0x0800
13 #define ETHERTYPE_ARP       0x0806
14 
15 class CNetFifoEntry {
16     I64 length;
17     U8  frame[ETHERNET_FRAME_SIZE];
18 };
19 
20 static CFifoI64* netfifo;
21 
22 static CNetFifoEntry* entries;
23 static I64 next_entry = 0;
24 
25 CTask* netfifo_handler_task = NULL;
26 
27 // TODO: asm optimization? or perhaps use EndianU*?
28 // These don't belong here in the first place,
29 // but it's convenient for Ethernet drivers
30 // We'll probably split it off along with ETHERTYPE_* constants
31 
32 U16 htons(U16 h) {
33     return ((h >> 8) | (h << 8)) & 0xffff;
34 }
35 
36 U16 ntohs(U16 h) {
37     return ((h >> 8) | (h << 8)) & 0xffff;
38 }
39 
40 U32 htonl(U32 h) {
41     return ((h >> 24) | ((h & 0x00ff0000) >> 8) | ((h & 0x0000ff00) << 8) | (h << 24)) & 0xffffffff;
42 }
43 
44 U32 ntohl(U32 h) {
45     return ((h >> 24) | ((h & 0x00ff0000) >> 8) | ((h & 0x0000ff00) << 8) | (h << 24)) & 0xffffffff;
46 }
47 
48 CNetFifoEntry* NetFifoPull() {
49     CNetFifoEntry* entry;
50 
51     if (FifoI64Rem(netfifo, &entry))
52         return entry;
53     else
54         return NULL;
55 }
56 
57 I64 NetFifoPushCopy(U8* data, I64 length) {
58     CNetFifoEntry* entry = &entries[next_entry];
59     next_entry = (next_entry + 1) & (NET_FIFO_DEPTH - 1);
60 
61     entry->length = length;
62     MemCpy(entry->frame, data, length);
63 
64     if (!FifoI64Ins(netfifo, entry))
65         return -1;
66 
67     // Wake up Handler Task
68     if (netfifo_handler_task)
69         LBtr(&netfifo_handler_task->task_flags, TASKf_IDLE);
70 
71     return 0;
72 }
73 
74 U0 NetFifoInit() {
75     netfifo = FifoI64New(NET_FIFO_DEPTH);
76     entries = MAlloc(NET_FIFO_DEPTH * sizeof(CNetFifoEntry));
77 }
78 
79 NetFifoInit;