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;