Added ability to load an arbitrary binary from an ethernet server and launch it
[akaros.git] / kern / src / rl8168.c
1 #ifdef __DEPUTY__
2 #pragma nodeputy
3 #endif
4
5 #include <arch/mmu.h>
6 #include <arch/x86.h>
7 #include <arch/smp.h>
8 #include <arch/apic.h>
9
10 #include <ros/memlayout.h>
11
12 #include <atomic.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <rl8168.h>
16 #include <trap.h>
17 #include <kmalloc.h>
18
19 #include <pmap.h>
20
21 /* RealTek 8168d (8111d) NIC Driver
22  *
23  * Written by Paul Pearce.
24  *
25  * This is a really rough "driver". Really, its not a driver, just a kernel hack to give
26  * the kernel a way to receive and send packets. The basis of the init code is the OSDEV
27  * page on the 8169 chipset, which is a varient of this chipset (most 8169 drivers work 
28  * on the 8168d). http://wiki.osdev.org/RTL8169
29  * 
30  * Basic ideas (although no direct code) were gleamed from the OpenBSD re(4) driver,
31  * which can be found in sys/dev/ic/re.c. sys/dev/ic/rtl81x9reg.h is needed to make
32  * sense of the constants used in re.c.
33  *
34  * This is an ongoing work in progress. Main thing is we need a kernel interface for PCI
35  * devices and network devices, that we can hook into, instead of providing arbitary functions
36  * 
37  * TODO: Remove hacky syscall hack stuff (once we get a real stack).
38  * TODO: Jumbo frame support
39  * TODO: Use high priority transmit ring for syscall stuff.
40  * TODO: Discuss panic conditions.
41  * TODO: Shutdown cleanup kfrees()
42  * TODO: Use onboard timer interrupt to check for packets, instead of writing a bit each time we have a packet.
43  * TODO: CONCURRENCY!
44  */
45
46
47
48 struct Descriptor
49 {
50     unsigned int command,  /* command/status dword */
51                  vlan,     /* currently unused */
52                  low_buf,  /* low 32-bits of physical buffer address */
53                  high_buf; /* high 32-bits of physical buffer address */
54 };
55
56
57 uint32_t io_base_addr = 0;
58 uint32_t irq = 0;
59 char device_mac[6];
60
61 struct Descriptor *rx_des_kva;
62 struct Descriptor *rx_des_pa;
63
64 struct Descriptor *tx_des_kva;
65 struct Descriptor *tx_des_pa;
66
67 uint32_t rx_des_cur = 0;
68 uint32_t tx_des_cur = 0;
69
70 uint8_t eth_up = 0;
71
72 // Hacky stuff for syscall hack. Go away.
73 int packet_waiting;
74 int packet_buffer_size;
75 char* packet_buffer;
76 char* packet_buffer_orig;
77 int packet_buffer_pos = 0;
78 // End hacky stuff
79
80 void init_nic() {
81         
82         if (scan_pci() < 0) return;
83         read_mac();
84         setup_descriptors();
85         configure_nic();
86         setup_interrupts();
87         eth_up = 1;
88         
89         //Trigger sw based nic interrupt
90         //outb(io_base_addr + 0x38, 0x1);
91         //udelay(3000000);
92         
93         return;
94 }
95
96
97 int scan_pci() {
98         
99         uint32_t address;
100         uint32_t lbus = 0;
101         uint32_t ldev = 0;
102         uint32_t lfunc = 0; // We only look at function 0 for now.
103         uint32_t lreg = 0; 
104         uint32_t result  = 0;
105  
106         cprintf("Searching for RealTek 8168 Network device......");
107
108         for (int i = 0; i < PCI_MAX_BUS; i++)
109                 for (int j = 0; j < PCI_MAX_DEV; j++) {
110
111                 lbus = i;
112                 ldev = j;
113                 lreg = 0; // PCI REGISTER 0
114
115                 address = MK_CONFIG_ADDR(lbus, ldev, lfunc, lreg); 
116
117                 // Probe current bus/dev
118                 outl(PCI_CONFIG_ADDR, address);
119                 result = inl(PCI_CONFIG_DATA);
120         
121                 uint16_t dev_id = result >> PCI_DEVICE_OFFSET;
122                 uint16_t ven_id = result & PCI_VENDOR_MASK;
123
124                 // Vender DNE
125                 if (ven_id == INVALID_VENDOR_ID) 
126                         continue;
127
128                 // Ignore non RealTek 8168 Devices
129                 if (ven_id != REALTEK_VENDOR_ID || dev_id != REALTEK_DEV_ID)
130                         continue;
131                 cprintf(" found on BUS %x DEV %x\n", i, j);
132
133                 // Find the IRQ
134                 address = MK_CONFIG_ADDR(lbus, ldev, lfunc, PCI_IRQ_REG);
135                 outl(PCI_CONFIG_ADDR, address);
136                 irq = inl(PCI_CONFIG_DATA) & PCI_IRQ_MASK;
137                 nic_debug("-->IRQ: %u\n", irq);
138
139                 // Loop over the BARs
140                 for (int k = 0; k <= 5; k++) {
141                         lreg = 4 + k;
142                         address = MK_CONFIG_ADDR(lbus, ldev, lfunc, lreg << 2); 
143                 outl(PCI_CONFIG_ADDR, address);
144                 result = inl(PCI_CONFIG_DATA);
145                                         
146                         if (result == 0) // (0 denotes no valid data)
147                                 continue;
148
149                         // Read the bottom bit of the BAR. 
150                         if (result & PCI_BAR_IO_MASK) {
151                                 result = result & PCI_IO_MASK;
152                                 nic_debug("-->BAR%u: %s --> %x\n", k, "IO", result);
153                         } else {
154                                 result = result & PCI_MEM_MASK;
155                                 nic_debug("-->BAR%u: %s --> %x\n", k, "MEM", result);
156                         }
157                         
158                         // TODO Switch to memory mapped instead of IO?
159                         if (k == 0) // BAR0 denotes the IO Addr for the device
160                                 io_base_addr = result;                                          
161                 }
162                 
163                 nic_debug("-->hwrev: %x\n", inl(io_base_addr + RL_HWREV_REG) & RL_HWREV_MASK);
164                 
165                 return 0;
166         }
167         cprintf(" not found. No device configured.\n");
168         
169         return -1;
170 }
171
172 void read_mac() {
173         
174         for (int i = 0; i < 6; i++)
175            device_mac[i] = inb(io_base_addr + RL_MAC_OFFSET + i); 
176         
177         nic_debug("-->DEVICE MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", 0xFF & device_mac[0], 0xFF & device_mac[1], 
178                                                                     0xFF & device_mac[2], 0xFF & device_mac[3], 
179                                                                 0xFF & device_mac[4], 0xFF & device_mac[5]);
180         return;
181 }
182
183 /*
184 void setup_descriptors() {
185         
186         nic_debug("-->Setting up tx/rx descriptors.\n");
187         
188         page_t *rx_des_page = NULL, *tx_des_page = NULL;
189                         
190         if (page_alloc(&rx_des_page) < 0) panic("Can't allocate page for RX Ring");
191         
192         if (page_alloc(&tx_des_page) < 0) panic("Can't allocate page for TX Ring");
193         
194         if (page2pa(tx_des_page) == 0x1000)
195                 if (page_alloc(&tx_des_page) < 0) panic("Can't allocate page for TX Ring");
196         
197         // extra page_alloc needed because of the strange page_alloc thing
198         if (page_alloc(&tx_des_page) < 0) panic("Can't allocate page for TX Ring");
199         
200         rx_des_kva = page2kva(rx_des_page);
201         tx_des_kva = page2kva(tx_des_page);
202         
203         rx_des_pa = page2pa(rx_des_page);
204         tx_des_pa = page2pa(tx_des_page);
205
206         cprintf("rx_des_page: %x\n", rx_des_pa);
207         cprintf("tx_des_page: %x\n", tx_des_pa);
208         
209     for (int i = 0; i < num_of_rx_descriptors; i++) 
210                 set_rx_descriptor(i);
211                 
212         for (int i = 0; i < num_of_tx_descriptors; i++) 
213                 set_tx_descriptor(i);
214 }
215 */
216
217 void setup_descriptors() {
218         
219         nic_debug("-->Setting up tx/rx descriptors.\n");
220                         
221         // Allocate room for the buffers. Include an extra ALIGN space.
222         // Buffers need to be on 256 byte boundries.
223         // Note: Buffers are alligned by kmalloc automatically to powers of 2 less than the size requested
224         // We request more than 256, thus they are aligned on 256 byte boundries
225         rx_des_kva = kmalloc(NUM_RX_DESCRIPTORS * sizeof(struct Descriptor), 0);
226         tx_des_kva = kmalloc(NUM_TX_DESCRIPTORS * sizeof(struct Descriptor), 0);
227         
228         if (rx_des_kva == NULL) panic("Can't allocate page for RX Ring");
229         if (tx_des_kva == NULL) panic("Can't allocate page for TX Ring");
230         
231         rx_des_pa = (struct Descriptor *)PADDR(rx_des_kva);
232         tx_des_pa = (struct Descriptor *)PADDR(tx_des_kva);
233         
234     for (int i = 0; i < NUM_RX_DESCRIPTORS; i++) 
235                 set_rx_descriptor(i, TRUE); // Allocate memory for the descriptor
236                 
237         for (int i = 0; i < NUM_TX_DESCRIPTORS; i++) 
238                 set_tx_descriptor(i);
239                 
240         return;
241 }
242
243
244 void set_rx_descriptor(uint32_t des_num, uint8_t reset_buffer) {
245         
246         // Set the OWN bit on all descriptors. Also set the buffer size.
247         rx_des_kva[des_num].command = (DES_OWN_MASK | (RL_RX_MAX_BUFFER_SIZE & DES_RX_SIZE_MASK));
248         
249         if (des_num == (NUM_RX_DESCRIPTORS - 1)) 
250                 rx_des_kva[des_num].command = rx_des_kva[des_num].command | DES_EOR_MASK;
251         
252         if (reset_buffer) {
253                 // Must be aligned on 8 byte boundries. Taken care of by kmalloc.
254                 char *rx_buffer = kmalloc(RL_RX_MAX_BUFFER_SIZE, 0);
255         
256                 if (rx_buffer == NULL) panic ("Can't allocate page for RX Buffer");
257
258                 rx_des_kva[des_num].low_buf = PADDR(rx_buffer);
259                 //.high_buf used if we do 64bit.
260         }
261         
262         return;
263 }
264
265 void set_tx_descriptor(uint32_t des_num) {
266         
267         // Clear the command bits.
268         tx_des_kva[des_num].command = 0;
269         
270         // Set EOR bit on last descriptor
271         if (des_num == (NUM_TX_DESCRIPTORS - 1))
272                 tx_des_kva[des_num].command = DES_EOR_MASK;     
273                 
274         char *tx_buffer = kmalloc(RL_TX_MAX_BUFFER_SIZE, 0);
275
276         if (tx_buffer == NULL) panic ("Can't allocate page for TX Buffer");
277
278         tx_des_kva[des_num].low_buf = PADDR(tx_buffer);
279         //.high_buf used if we do 64bit.
280                 
281         return;
282 }
283
284 void configure_nic() {
285         
286         // TODO: Weigh resetting the nic. Not really needed. Remove?
287         // TODO Check ordering of what we set.
288         // TODO Remove C+ register setting?
289         
290         nic_debug("-->Configuring Device.\n");
291         reset_nic();
292
293         // Magic to handle the C+ register. Completely undocumented, ripped from the BSE RE driver.
294         outl(io_base_addr + RL_CP_CTRL_REG, RL_CP_MAGIC_MASK);
295
296         // Unlock EPPROM CTRL REG
297         outb(io_base_addr + RL_EP_CTRL_REG, RL_EP_CTRL_UL_MASK);        
298         
299         // Set max RX Packet Size
300     outw(io_base_addr + RL_RX_MXPKT_REG, RL_RX_MAX_SIZE);       
301                 
302         // Set max TX Packet Size
303     outb(io_base_addr + RL_TX_MXPKT_REG, RL_TX_MAX_SIZE);                       
304
305         // Set TX Des Ring Start Addr
306     outl(io_base_addr + RL_TX_DES_REG, (unsigned long)tx_des_pa); 
307         
308         // Set RX Des Ring Start Addr
309     outl(io_base_addr + RL_RX_DES_REG, (unsigned long)rx_des_pa);       
310
311         // Configure TX
312         outl(io_base_addr + RL_TX_CFG_REG, RL_TX_CFG_MASK); 
313         
314         // Configure RX
315         outl(io_base_addr + RL_TX_CFG_REG, RL_RX_CFG_MASK);                     
316
317         // Enable RX and TX in the CTRL Reg
318         outb(io_base_addr + RL_CTRL_REG, RL_CTRL_RXTX_MASK);                    
319
320         // Lock the EPPROM Ctrl REG
321     outl(io_base_addr + RL_EP_CTRL_REG, RL_EP_CTRL_L_MASK);             
322         
323         return;
324 }
325
326 void reset_nic() {
327         
328         nic_debug("-->Resetting device..... ");
329         outb(io_base_addr + RL_CTRL_REG, RL_CTRL_RESET_MASK);
330         
331         // Wait for NIC to answer "done resetting" before continuing on
332         while (inb(io_base_addr + RL_CTRL_REG) & RL_CTRL_RESET_MASK);
333         nic_debug(" done.\n");
334         
335         return;
336 }
337
338 void setup_interrupts() {
339         
340         extern handler_t interrupt_handlers[];
341         
342         nic_debug("-->Setting interrupts.\n");
343         
344         // Enable NIC interrupts
345         outw(io_base_addr + RL_IM_REG, RL_INTERRUPT_MASK);
346         
347         //Clear the current interrupts.
348         outw(io_base_addr + RL_IS_REG, RL_INTRRUPT_CLEAR);
349         
350         // Kernel based interrupt stuff
351         register_interrupt_handler(interrupt_handlers, KERNEL_IRQ_OFFSET + irq, nic_interrupt_handler, 0);
352         pic_unmask_irq(irq);
353         unmask_lapic_lvt(LAPIC_LVT_LINT0);
354         
355         return;
356 }
357
358 // We need to evaluate this routine in terms of concurrency.
359 // We also need to figure out whats up with different core interrupts
360 void nic_interrupt_handler(trapframe_t *tf, void* data) {
361         
362         nic_interrupt_debug("\nNic interrupt on core %u!\n", lapic_get_id());
363                                 
364         // Read the offending interrupt(s)
365         uint16_t interrupt_status = inw(io_base_addr + RL_IS_REG);
366
367         // We can have multiple interrupts fire at once. I've personally seen this.
368         // This means we need to handle this as a series of independent if's
369         if (interrupt_status & RL_INT_ROK) {
370                 nic_interrupt_debug("-->RX OK\n");
371                 nic_handle_rx_packet();
372         }       
373         
374         if (interrupt_status & RL_INT_RERR) {
375                 nic_interrupt_debug("-->RX ERR\n");
376         }
377         
378         if (interrupt_status & RL_INT_TOK) {
379                 nic_interrupt_debug("-->TX OK\n");
380         }
381         
382         if (interrupt_status & RL_INT_TERR) {
383                 nic_interrupt_debug("-->TX ERR\n");
384         }
385         
386         if (interrupt_status & RL_INT_RDU) {
387                 nic_interrupt_debug("-->RX Descriptor Unavailable\n");
388         }
389         
390         if (interrupt_status & RL_INT_LINKCHG) {
391                 nic_interrupt_debug("-->Link Status Changed\n");
392         }
393         
394         if (interrupt_status & RL_INT_FOVW) {
395                 nic_interrupt_debug("-->RX Fifo Overflow\n");
396         }
397         
398         if (interrupt_status & RL_INT_TDU) {
399                 nic_interrupt_debug("-->TX Descriptor Unavailable\n");
400         }
401         
402         if (interrupt_status & RL_INT_SWINT) {
403                 nic_interrupt_debug("-->Software Generated Interrupt\n");
404         }
405         
406         if (interrupt_status & RL_INT_TIMEOUT) {
407                 nic_interrupt_debug("-->Timer Expired\n");
408         }
409         
410         if (interrupt_status & RL_INT_SERR) {
411                 nic_interrupt_debug("-->PCI Bus System Error\n");
412         }
413         
414         nic_interrupt_debug("\n");
415                 
416         // Clear interrupts     
417         outw(io_base_addr + RL_IS_REG, RL_INTRRUPT_CLEAR);
418         
419         return;
420 }
421
422 // TODO: Does a packet too large get dropped or just set the error bits in the descriptor? Find out.
423 void nic_handle_rx_packet() {
424         
425         uint32_t current_command = rx_des_kva[rx_des_cur].command;
426         uint16_t packet_size;
427                 
428         nic_frame_debug("-->RX Des: %u\n", rx_des_cur);
429         
430         // Make sure we are processing from the start of a packet segment
431         if (!(current_command & DES_FS_MASK)) {
432                 nic_frame_debug("-->ERR: Current RX descriptor not marked with FS mask. Panic!");
433                 panic("RX Descriptor Ring FS out of sync");
434         }
435         
436         // NOTE: We are currently configured that the max packet size is large enough to fit inside 1 descriptor buffer,
437         // So we should never be in a situation where a packet spans multiple descriptors.
438         // When we change this, this should operate in a loop until the LS mask is found
439         // Loop would begin here.
440         
441         uint32_t rx_des_loop_cur = rx_des_cur;
442         uint32_t frame_size = 0;
443         uint32_t fragment_size = 0;
444         uint32_t num_frags = 0;
445         
446         char *rx_buffer = kmalloc(MAX_FRAME_SIZE, 0);
447         
448         if (rx_buffer == NULL) panic ("Can't allocate page for incoming packet.");
449         
450         do {
451                 current_command =  rx_des_kva[rx_des_loop_cur].command;
452                 fragment_size = rx_des_kva[rx_des_loop_cur].command & DES_RX_SIZE_MASK;
453                 
454                 // If we've looped through the entire ring and not found a terminating packet, bad nic state.
455                 // Panic or clear all descriptors? This is a nic hardware error. 
456                 if (num_frags && (rx_des_loop_cur == rx_des_cur)) {
457                         //for (int i = 0; i < NUM_RX_DESCRIPTORS; i++) 
458                         //      set_rx_descriptor(i, FALSE); // Dont reallocate memory for the descriptor
459                         // rx_des_cur = 0;
460                         // return;
461                         nic_frame_debug("-->ERR: No ending segment found in RX buffer.\n");
462                         panic("RX Descriptor Ring out of sync.");
463                 }
464                 
465                 num_frags++;
466                 
467                 
468                 // Make sure we own the current packet. Kernel ownership is denoted by a 0. Nic by a 1.
469                 if (current_command & DES_OWN_MASK) {
470                         nic_frame_debug("-->ERR: Current RX descriptor not owned by kernel. Panic!");
471                         panic("RX Descriptor Ring OWN out of sync");
472                 }
473                 
474                 // Make sure if we are at the end of the buffer, the des is marked as end
475                 if ((rx_des_loop_cur == (NUM_RX_DESCRIPTORS - 1)) && !(current_command & DES_EOR_MASK)) {
476                         nic_frame_debug("-->ERR: Last RX descriptor not marked with EOR mask. Panic!\n");
477                         panic("RX Descriptor Ring EOR Missing");
478                 }
479                 
480                 // We set a max frame size and the nic violated that. 
481                 // Panic or clear all desriptors?
482                 if ((frame_size + fragment_size) > MAX_FRAME_SIZE) {
483                         //for (int i = 0; i < NUM_RX_DESCRIPTORS; i++) 
484                         //      set_rx_descriptor(i, FALSE); // Dont reallocate memory for the descriptor
485                         // rx_des_cur = 0;
486                         // return;
487                         nic_frame_debug("-->ERR: Nic sent %u byte packet. Max is %u\n", frame_size, MAX_FRAME_SIZE);
488                         panic("NIC Sent packets larger than configured.");
489                 }
490                 
491                 // Move the fragment data into the buffer
492                 memcpy(rx_buffer + frame_size, KADDR(rx_des_kva[rx_des_loop_cur].low_buf), fragment_size);
493                 
494                 // Reset the descriptor. No reuse buffer.
495                 set_rx_descriptor(rx_des_loop_cur, FALSE);
496                 
497                 // Note: We mask out fragment sizes at 0x3FFFF. There can be at most 1024 of them.
498                 // This can not overflow the uint32_t we allocated for frame size, so
499                 // we dont need to worry about mallocing too little then overflowing when we read.
500                 frame_size = frame_size + fragment_size;
501                 
502                 // Advance to the next descriptor
503                 rx_des_loop_cur = (rx_des_loop_cur + 1) % NUM_RX_DESCRIPTORS;
504                 
505         } while (!(current_command & DES_LS_MASK));
506         
507         // Hack for UDP syscall hack. 
508         // This is a quick hack to let us deal with where to put packets coming in. This is not concurrency friendly
509         // In the event that we get 2 incoming frames for our syscall test (shouldnt happen)
510         // We cant process more until another packet comes in. This is ugly, but this code goes away as soon as we integrate a real stack.
511         // This keys off the source port, fix it for dest port. 
512         // Also this may access packet regions that are wrong. If someone addresses empty packet for our interface
513         // and the bits that happened to be in memory before are the right port, this will trigger. this is bad
514         // but since syscalls are a hack for only 1 machine connected, we dont care for now.
515         
516         if ((current_command & DES_PAM_MASK) && (*((uint16_t*)(rx_buffer + 36)) == 0x9bad)) {
517                 
518                 if (packet_waiting) return;
519
520                 packet_buffer = rx_buffer + PACKET_HEADER_SIZE;
521                 
522                 // So ugly I want to cry
523                 packet_buffer_size = *((uint16_t*)(rx_buffer + 38)); 
524                 packet_buffer_size = (((uint16_t)packet_buffer_size & 0xff00) >> 8) |  (((uint16_t)packet_buffer_size & 0x00ff) << 8);          
525                 packet_buffer_size = packet_buffer_size - 8;
526
527                 packet_buffer_orig = rx_buffer;
528                 packet_buffer_pos = 0;
529                 
530                 packet_waiting = 1;
531                 
532                 process_frame(rx_buffer, frame_size, current_command);
533                 
534                 rx_des_cur = rx_des_loop_cur;
535                 
536                 return;
537         }
538         
539         // END HACKY STUFF
540         
541         // Chew on the frame data. Command bits should be the same for all frags.
542         process_frame(rx_buffer, frame_size, current_command);
543
544         rx_des_cur = rx_des_loop_cur;
545         
546         kfree(rx_buffer);
547         
548         return;
549 }
550
551 // This is really more of a debug level function. Will probably go away once we get a stack going.
552 void process_frame(char *frame_buffer, uint32_t frame_size, uint32_t command) {
553                 
554         nic_frame_debug("-->Command: %x\n", command);
555         nic_frame_debug("-->Size: %u\n", frame_size);
556         
557         if (frame_buffer == NULL)
558                 return;
559         
560         // This is hacky. Once we know what our stack will look like, change this.
561         // Once remove check for 0 size.
562         if (frame_size < MINIMUM_PACKET_SIZE) {
563                 nic_frame_debug("-->Packet too small. Discarding.\n");
564                 return;
565         }
566         
567         char dest_mac[6];
568         char source_mac[6];
569         char eth_type[2];
570         
571         for (int i = 0; i < 6; i++) {
572                 dest_mac[i] = frame_buffer[i];
573         }
574         
575         for (int i = 0; i < 6; i++) {
576                 source_mac[i] = frame_buffer[i+6];
577         }
578         
579         eth_type[0] = frame_buffer[12];
580         eth_type[1] = frame_buffer[13];
581         
582         if (command & DES_MAR_MASK) {
583                 nic_frame_debug("-->Multicast Packet.\n");
584         }
585         
586         if (command & DES_PAM_MASK) {
587                 nic_frame_debug("-->Physical Address Matched.\n");
588         }
589         
590         if (command & DES_BAR_MASK) {
591                 nic_frame_debug("-->Broadcast Packet.\n");
592         }
593         
594         // Note: DEST comes before SRC in the ethernet frame, but that 
595         
596         nic_frame_debug("-->DEST   MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", 0xFF & dest_mac[0], 0xFF & dest_mac[1],       
597                                                                            0xFF & dest_mac[2], 0xFF & dest_mac[3],      
598                                                                        0xFF & dest_mac[4], 0xFF & dest_mac[5]);
599         
600         nic_frame_debug("-->SOURCE MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", 0xFF & source_mac[0], 0xFF & source_mac[1],   
601                                                                            0xFF & source_mac[2], 0xFF & source_mac[3],  
602                                                                        0xFF & source_mac[4], 0xFF & source_mac[5]);
603
604         nic_frame_debug("-->ETHR MODE: %02x%02x\n", 0xFF & eth_type[0], 0xFF & eth_type[1]);
605                 
606         return;
607 }
608
609 // Main routine to send a frame. Just sends it and goes.
610 // Card supports sending across multiple fragments.
611 // Would we want to write a function that takes a larger packet and generates fragments?
612 // This seems like the stacks responsibility. Leave this for now. may in future
613 // Remove the max size cap and generate multiple packets.
614 int send_frame(const char *data, size_t len) {
615
616         if (data == NULL)
617                 return -1;
618         if (len == 0)
619                 return 0;
620
621         if (tx_des_kva[tx_des_cur].command & DES_OWN_MASK) {
622                 nic_frame_debug("-->TX Ring Buffer Full!\n");
623                 return -1;
624         }
625         
626         if (len > MAX_FRAME_SIZE) {
627                 nic_frame_debug("-->Frame Too Large!\n");
628                 return -1;
629         }
630         
631         memcpy(KADDR(tx_des_kva[tx_des_cur].low_buf), data, len);
632
633         tx_des_kva[tx_des_cur].command = tx_des_kva[tx_des_cur].command | len | DES_OWN_MASK | DES_FS_MASK | DES_LS_MASK;
634
635         // For this revision of the NIC, the checksum bits get set in the vlan field not the command field.
636         // THIS IS A HACK: Need to reach inside the frame we are sending and detect if its of type ip/udp/tcp and set right flag
637         // For now, for the syscall hack, force ip checksum on. (we dont care about udp checksum).
638         // Add an argument to function to specify packet type?
639         tx_des_kva[tx_des_cur].vlan = DES_TX_IP_CHK_MASK;
640         
641         tx_des_cur = (tx_des_cur + 1) % NUM_TX_DESCRIPTORS;
642         
643         //nic_frame_debug("-->Sent packet.\n");
644         
645         outb(io_base_addr + RL_TX_CTRL_REG, RL_TX_SEND_MASK);
646         
647         return len;
648 }
649
650 // This function is a complete hack for syscalls until we get a stack.
651 // the day I delete this monstrosity of code I will be a happy man --Paul
652 const char *packet_wrap(const char* data, size_t len) {
653         
654         #define htons(A) ((((uint16_t)(A) & 0xff00) >> 8) | \
655                             (((uint16_t)(A) & 0x00ff) << 8))
656         #define htonl(A) ((((uint32_t)(A) & 0xff000000) >> 24) | \
657                             (((uint32_t)(A) & 0x00ff0000) >> 8)  | \
658                             (((uint32_t)(A) & 0x0000ff00) << 8)  | \
659                             (((uint32_t)(A) & 0x000000ff) << 24))
660
661         #define ntohs  htons
662         #define ntohl  htohl
663
664         if ((len == 0) || (data == NULL))
665                 return NULL;
666         
667         struct ETH_Header
668         {
669                 char dest_mac[6];
670                 char source_mac[6];
671                 uint16_t eth_type;
672         };
673
674         
675         struct IP_Header
676         {
677                 uint32_t ip_opts0;
678                 uint32_t ip_opts1;
679                 uint32_t ip_opts2;
680                 uint32_t source_ip;
681                 uint32_t dest_ip;
682         };
683         
684         struct UDP_Header
685         {
686                 uint16_t source_port;
687                 uint16_t dest_port;
688                 uint16_t length;
689                 uint16_t checksum;
690         };      
691         
692         // Hard coded to paul's laptop's mac
693         //Format for Makelocal file: -DUSER_MAC_ADDRESS="{0x00, 0x23, 0x32, 0xd5, 0xae, 0x82}"
694         char dest_mac_address[6] = USER_MAC_ADDRESS;
695         
696         
697         uint32_t source_ip = 0xC0A8000A; // 192.168.0.10
698         uint32_t dest_ip   = 0xC0A8000B; // 192.168.0.11
699  
700         
701         if (len > MAX_PACKET_DATA) {
702                 nic_frame_debug("Bad packet size for packet wrapping");
703                 return NULL;
704         }
705         
706         char* wrap_buffer = kmalloc(MAX_PACKET_SIZE, 0);
707         
708         if (wrap_buffer == NULL) {
709                 nic_frame_debug("Can't allocate page for packet wrapping");
710                 return NULL;
711         }
712         
713         struct ETH_Header *eth_header = (struct ETH_Header*) wrap_buffer;
714         struct IP_Header *ip_header = (struct IP_Header*) (wrap_buffer + sizeof(struct ETH_Header));
715         struct UDP_Header *udp_header = (struct UDP_Header*) (wrap_buffer + sizeof(struct ETH_Header) + sizeof(struct IP_Header));
716         
717         // Setup eth data
718         for (int i = 0; i < 6; i++) 
719                 eth_header->dest_mac[i] = dest_mac_address[i];
720                 
721         for (int i = 0; i < 6; i++) 
722                 eth_header->source_mac[i] = device_mac[i];
723                 
724         eth_header->eth_type = htons(0x0800);
725         
726         // Setup IP data
727         ip_header->ip_opts0 = htonl((4<<28) | (5 << 24) | (len + 28));
728         ip_header->ip_opts1 = 0;
729         ip_header->ip_opts2 = 0x00110a;
730         ip_header->source_ip = htonl(source_ip);
731         ip_header->dest_ip = htonl(dest_ip);
732         
733         // Setup UDP Data
734         udp_header->source_port = htons(44443);
735         udp_header->dest_port = htons(44444);
736         udp_header->length = htons(8 + len);
737         udp_header->checksum = 0;
738         
739         memcpy (wrap_buffer + PACKET_HEADER_SIZE, data, len);
740         
741         return wrap_buffer;     
742 }