Udp packet can now be delivered to the application and sent correctly.
authorDavid Zhu <yuzhu@cs.berkeley.edu>
Thu, 24 Mar 2011 00:29:00 +0000 (17:29 -0700)
committerDavid Zhu <yuzhu@cs.berkeley.edu>
Mon, 2 Apr 2012 22:03:28 +0000 (15:03 -0700)
No protection for concurrency yet. Also the receiving is quite inefficient.
Need to allocate pbufs and reuse them effectively in the e1000 driver.

18 files changed:
kern/arch/i686/e1000.c
kern/arch/i686/e1000.h
kern/arch/i686/e1000_hw.h
kern/arch/i686/nic_common.c
kern/arch/i686/nic_common.h
kern/include/bits/netinet.h
kern/include/net.h
kern/include/net/ip.h
kern/include/net/pbuf.h
kern/include/net/udp.h
kern/include/socket.h
kern/src/eth_audio.c
kern/src/net.c
kern/src/net/ip.c
kern/src/net/pbuf.c
kern/src/net/udp.c
kern/src/socket.c
tests/udp_test.c

index 76e3361..000984c 100644 (file)
@@ -6,6 +6,7 @@
  * See Info below 
  *
  * @author Paul Pearce <pearce@eecs.berkeley.edu>
+ * @author David Zhu <yuzhu@cs.berkeley.edu>
  *
  */
 
@@ -33,6 +34,7 @@
 #include <frontend.h>
 #include <arch/frontend.h>
 #include <eth_audio.h>
+#include <net/ip.h>
 
 #define NUM_TX_DESCRIPTORS E1000_NUM_TX_DESCRIPTORS
 #define NUM_RX_DESCRIPTORS E1000_NUM_RX_DESCRIPTORS
@@ -194,7 +196,8 @@ int e1000_scan_pci() {
                e1000_irq = pcidev->irqline;
                e1000_debug("-->IRQ: %u\n", e1000_irq);
                /* Loop over the BARs */
-               /* yz: pci layer should scan these things and put them in a pci_dev struct */
+               /* TODO: pci layer should scan these things and put them in a pci_dev struct */
+               /* SelectBars based on the IORESOURCE_MEM */
                for (int k = 0; k <= 5; k++) {
                        int reg = 4 + k;
            // resource len?
@@ -260,7 +263,6 @@ void e1000_wr32(uint32_t offset, uint32_t val) {
        }
 }
 
-
 /* E1000 Read From EEPROM
  * Read a 16 bit value from the EEPROM at the given offset 
  * in the EEPROM.
@@ -478,8 +480,9 @@ void e1000_configure() {
 
        e1000_debug("-->Configuring Device.\n");
        
-       // Clear interrupts
+       // Clear Interrupts
        e1000_wr32(E1000_IMC, E1000_IMC_ALL);
+       E1000_WRITE_FLUSH();
 
        // Disable receiver and transmitter
        e1000_wr32(E1000_RCTL, 0x00);
@@ -608,12 +611,9 @@ void e1000_reset() {
        return;
 }
 
-void enable_e1000_irq(struct trapframe *tf, uint32_t src_id, 
-                                void* a0, void* a1, void* a2)
-{
-       pic_unmask_irq(e1000_irq);
-       unmask_lapic_lvt(LAPIC_LVT_LINT0);
-       enable_irq();
+void e1000_irq_enable() {
+       e1000_wr32(E1000_IMS, IMS_ENABLE_MASK);
+       E1000_WRITE_FLUSH();
 }
 
 // Configure and enable interrupts
@@ -628,23 +628,25 @@ void e1000_setup_interrupts() {
        
        // Clear interrupts
        e1000_wr32(E1000_IMS, 0xFFFFFFFF);
-       e1000_wr32(E1000_IMC, 0xFFFFFFFF);
+       e1000_wr32(E1000_IMC, E1000_IMC_ALL);
        
        // Set interrupts
-       // TODO: Make this only enable stuff we want
-       e1000_wr32(E1000_IMS, 0xFFFFFFFF); 
+       e1000_irq_enable();
 
        // Kernel based interrupt stuff
        register_interrupt_handler(interrupt_handlers, KERNEL_IRQ_OFFSET + e1000_irq, e1000_interrupt_handler, 0);
 
        // Enable irqs for the e1000
+       // TODO: figure out where the interrupts are actually going..
 #ifdef __CONFIG_ENABLE_MPTABLES__
        /* TODO: this should be for any IOAPIC EOI, not just MPTABLES */
        ioapic_route_irq(e1000_irq, E1000_IRQ_CPU);     
 #else 
        // This will route the interrupts automatically to CORE 0
        // Call send_kernel_message if you want to route them somewhere else
-       enable_e1000_irq(NULL,0,0,0,0);
+       pic_unmask_irq(e1000_irq);
+       unmask_lapic_lvt(LAPIC_LVT_LINT0);
+       enable_irq();
 #endif
 
        return;
@@ -652,63 +654,75 @@ void e1000_setup_interrupts() {
 
 // Code that is executed when an interrupt comes in on IRQ e1000_irq
 void e1000_interrupt_handler(trapframe_t *tf, void* data) {
-
-//     printk("About to spam to mac addr: 00:14:4F:D1:EC:6C\n");
-//     while(1) {
-//             appserver_packet_t p;
-//             p.header.dst_mac[0] = 0x00;
-//             p.header.dst_mac[1] = 0x14;
-//             p.header.dst_mac[2] = 0x4f;
-//             p.header.dst_mac[3] = 0xd1;
-//             p.header.dst_mac[4] = 0xec;
-//             p.header.dst_mac[5] = 0x6c;
-//             p.header.src_mac[0] = 0x00;
-//             p.header.src_mac[1] = 0x23;
-//             p.header.src_mac[2] = 0x8b;
-//             p.header.src_mac[3] = 0x42;
-//             p.header.src_mac[4] = 0x80;
-//             p.header.src_mac[5] = 0xb8;
-//             p.header.ethertype = 0x8888;
-//             send_frame((char*)&p,0);
-//     }
-
        e1000_interrupt_debug("\nNic interrupt on core %u!\n", lapic_get_id());
-                               
+
        // Read the offending interrupt(s)
        // Note: Reading clears the interrupts
-       uint32_t interrupt_status = e1000_rr32(E1000_ICR);
-
-       // Loop to deal with TOCTOU 
-       while (interrupt_status != 0x0000) {
+       uint32_t icr = e1000_rr32(E1000_ICR);
 
-               //printk("Interrupt status: %x\n", interrupt_status);
-
-               // Check to see if the interrupt was packet based.
-               // TODO: what other kind of interrupts are there? 
-               if ((interrupt_status & E1000_ICR_INT_ASSERTED) && (interrupt_status & E1000_ICR_RXT0)) {
-                       e1000_interrupt_debug("---->Packet Received\n");
-#ifdef __CONFIG_SOCKET__
-                       e1000_recv_pbuf();
-#else
-                       e1000_handle_rx_packet();
-#endif
-               }       
-               // Clear interrupts     
-               interrupt_status = e1000_rr32(E1000_ICR);
-       }
        
-       // In the event that we got really unlucky and more data arrived after we set 
-       //  set the bit last, try one more check
-       /* What happens if handle_rx_packet is called too many times? */
+       /* Interrupt did not come from our card.., handle one interrupt per isr */
+       if (!icr) return; 
+       /* disable interrupts, this may not be necessary as AUTOMASK of interrupts
+        * is enabled on some cards
+        * but we do it anyways to be safe..
+        */
+       e1000_wr32(E1000_IMC, ~0);
+       E1000_WRITE_FLUSH();
+
+       printk("Interrupt status: %x\n", icr);
+
+       if ((icr & E1000_ICR_INT_ASSERTED) && (icr & E1000_ICR_RXT0)){
+               e1000_interrupt_debug("---->Packet Received\n");
 #ifdef __CONFIG_SOCKET__
-                       e1000_recv_pbuf();
+//#if 0
+               struct pbuf *pb = e1000_recv_pbuf();
+               schedule_pb(pb);
 #else
-                       e1000_handle_rx_packet();
+               e1000_handle_rx_packet();
 #endif
+       }       
+       e1000_irq_enable();
+}
 
-       return;
+void process_pbuf(struct trapframe *tf, uint32_t srcid, long a0, long a1, long a2){
+       if (srcid != core_id())
+               warn("pbuf came from a different core\n");
+       /* assume it is an ip packet */
+       struct pbuf* pb = (struct pbuf*) a0;
+       printk("processing pbuf \n");
+       /*TODO: check checksum and drop */
+       /*check packet type*/
+       struct ethernet_hdr *ethhdr = (struct ethernet_hdr *) pb->payload;
+       printk("start of eth %p \n", pb->payload);
+       print_pbuf(pb);
+       if (memcmp(ethhdr->dst_mac, device_mac, 6)){
+               pbuf_free(pb);
+       }
+       switch(htons(ethhdr->eth_type)){
+               case ETHTYPE_IP:
+                       if (!pbuf_header(pb, -(ETH_HDR_SZ)))
+                               ip_input(pb);
+                       else
+                               warn("moving ethernet header in pbuf failed..\n");
+                       break;
+               case ETHTYPE_ARP:
+                       break;
+               default:
+                       //warn("packet type unknown");
+                       pbuf_free(pb);
+       }
 }
 
+static void schedule_pb(struct pbuf* pb) {
+       printk("scheduled pb \n");
+       /* routine kernel message is kind of heavy weight, because it records src/dst etc */
+       /* TODO: consider a core-local chain of pbufs */
+       // using core 3 for network stuff..XXX
+       send_kernel_message(3, (amr_t) process_pbuf, (long)pb, 0, 0, KMSG_ROUTINE);
+       // send_kernel_message(core_id(), (amr_t) process_pbuf, (long)pb, 0, 0, KMSG_ROUTINE);
+       return;
+}
 // Check to see if a packet arrived, and process the packet.
 void e1000_handle_rx_packet() {
        
@@ -797,6 +811,7 @@ void e1000_handle_rx_packet() {
 
        } while ((status & E1000_RXD_STAT_EOP) == 0); // Check to see if we are at the final fragment
 
+
 #ifdef __CONFIG_APPSERVER__
        // Treat as a syscall frontend response packet if eth_type says so
        // Will eventually go away, so not too worried about elegance here...
@@ -857,26 +872,40 @@ void e1000_handle_rx_packet() {
        
        // Bump the tail pointer. It should be 1 behind where we start reading from.
        e1000_wr32(E1000_RDT, (e1000_rx_index -1) % NUM_RX_DESCRIPTORS);
+       dumppacket((unsigned char *)rx_buffer, frame_size);
                                
        // Chew on the frame data. Command bits should be the same for all frags.
        //e1000_process_frame(rx_buffer, frame_size, current_command);
        
        return;
 }
+#if 0
+static int e1000_clean_rx_irq() {
+       uint32_t i= e1000_rx_index;
+       // recv head
+       uint32_t head = e1000_rr32(E1000_RDH);
+       struct e1000_rx_desc *rx_desc, *next_rxd;
+
+       rx_desc = rx_des_kva[i];
+       buffer_info = rx_des_kva[i]
+}
+#endif
 
 struct pbuf* e1000_recv_pbuf(void) {
        uint16_t packet_size;
        uint32_t status;
+       // recv head
        uint32_t head = e1000_rr32(E1000_RDH);
 
-       //printk("Current head is: %x\n", e1000_rr32(E1000_RDH));
-       //printk("Current tail is: %x\n", e1000_rr32(E1000_RDT));
+       printk("Current head is: %x\n", e1000_rr32(E1000_RDH));
+       printk("Current tail is: %x\n", e1000_rr32(E1000_RDT));
        
        // If the HEAD is where we last processed, no new packets.
        if (head == e1000_rx_index) {
                e1000_frame_debug("-->Nothing to process. Returning.");
                return NULL;
        }
+
        
        // Set our current descriptor to where we last left off.
        uint32_t rx_des_loop_cur = e1000_rx_index;
@@ -885,21 +914,33 @@ struct pbuf* e1000_recv_pbuf(void) {
        uint32_t num_frags = 0;
 
        uint32_t top_fragment = rx_des_loop_cur; 
-       struct e1000_rx_desc rx_desc = rx_des_kva[rx_des_loop_cur];
-       // the parent function verifies STAT_DD
        struct pbuf* pb = pbuf_alloc(PBUF_RAW, 0, PBUF_MTU);
        if (!pb){
-               warn("pbuf allocation failed\n");
+               warn("pbuf allocation failed, packet dropped\n");
                return NULL;
        }
 
+       uint32_t copied = 0;
+#if ETH_PAD_SIZE
+       pbuf_header(pb, -ETH_PAD_SIZE); /* drop the padding word */
+#endif
+       // pblen is way too big? it is not an indication of the size but the allocation
+       printk("pb loc %p , pb len %d \n", pb, pb->len);
+       void* rx_buffer = pb->payload;
+
+       /* The following loop generates 1 and only 1 pbuf out of 1(likely) 
+        * or more fragments. 
+        * TODO: convert this loop to clean rx irq style which is capable of 
+        * handling multiple packet / pbuf receptions
+        */
+
        do {
                // Get the descriptor status
                status = rx_des_kva[rx_des_loop_cur].status;
 
                // If the status is 0x00, it means we are somehow trying to process 
                // a packet that hasnt been written by the NIC yet.
-               if (status == 0x0) {
+               if (status & E1000_RXD_STAT_DD) {
                        warn("ERROR: E1000: Packet owned by hardware has 0 status value\n");
                        /* It's possible we are processing a packet that is a fragment
                         * before the entire packet arrives.  The code currently assumes
@@ -911,9 +952,11 @@ struct pbuf* e1000_recv_pbuf(void) {
                                cpu_relax();
                        status = rx_des_kva[rx_des_loop_cur].status;
                }
+               printk ("got out of the dead loop \n");
        
                // See how big this fragment is.
                fragment_size = rx_des_kva[rx_des_loop_cur].length;
+               printk("fragment size %d\n",fragment_size);
                
                // If we've looped through the entire ring and not found a terminating packet, bad nic state.
                // Panic or clear all descriptors? This is a nic hardware error. 
@@ -923,22 +966,31 @@ struct pbuf* e1000_recv_pbuf(void) {
                }
                // Denote that we have at least 1 fragment.
                num_frags++;
+               if (num_frags > 1) warn ("we have fragments in the network \n");
                // Make sure ownership is correct. Packet owned by the NIC (ready for kernel reading)
                // is denoted by a 1. Packet owned by the kernel (ready for NIC use) is denoted by 0.
                if ((status & E1000_RXD_STAT_DD) == 0x0) {
                        e1000_frame_debug("-->ERR: Current RX descriptor not owned by software. Panic!");
-                       panic("RX Descriptor Ring OWN out of sync");
+                       warn("RX Descriptor Ring OWN out of sync");
                }
                
                // Deal with packets too large
                if ((frame_size + fragment_size) > MAX_FRAME_SIZE) {
                        e1000_frame_debug("-->ERR: Nic sent %u byte packet. Max is %u\n", frame_size, MAX_FRAME_SIZE);
-                       panic("NIC Sent packets larger than configured.");
+                       warn("NIC Sent packets larger than configured.");
                }
+               
+               memcpy(rx_buffer, KADDR(rx_des_kva[rx_des_loop_cur].buffer_addr), fragment_size);
+               copied += fragment_size;
+               printk("fragment size %d \n", fragment_size);
+               rx_buffer += fragment_size;
+               
+
                // Copy into pbuf allocated for this     
                // TODO: reuse the pbuf later
-               // real driver uses a pbuf allocated (MTU sized) per descriptor and recycles that
-               // real driver also does not handle fragments.. simply drops them
+               // TODO:real driver uses a pbuf allocated (MTU sized) per descriptor and recycles that
+               // TODO:real driver also does not handle fragments.. simply drops them
+
                // Reset the descriptor. Reuse current buffer (False means don't realloc).
                e1000_set_rx_descriptor(rx_des_loop_cur, FALSE);
                
@@ -947,29 +999,18 @@ struct pbuf* e1000_recv_pbuf(void) {
                // we dont need to worry about mallocing too little then overflowing when we read.
                frame_size = frame_size + fragment_size;
                
-               // Advance to the next descriptor
+               /*Advance to the next descriptor*/
                rx_des_loop_cur = (rx_des_loop_cur + 1) % NUM_RX_DESCRIPTORS;
 
        } while ((status & E1000_RXD_STAT_EOP) == 0); // Check to see if we are at the final fragment
 
-       uint32_t copied = 0;
-#if ETH_PAD_SIZE
-       pbuf_header(pb, -ETH_PAD_SIZE); /* drop the padding word */
-       copied += ETH_PAD_SIZE;
-#endif
-
-       void* rx_buffer = pb->payload;
-       
-
        // rx_des_loop_cur has gone past the top_fragment
-       while (top_fragment != rx_des_loop_cur) {
-               // TODO: if we convert the pbufs to MTU sized pbuf, don't forget to convert this copy to a pbuf copy
-               memcpy(rx_buffer, KADDR(rx_des_kva[rx_des_loop_cur].buffer_addr), fragment_size);
-               copied += fragment_size;
-               top_fragment = (top_fragment + 1) % NUM_RX_DESCRIPTORS;
-       }
-       pb->len += copied;
-       pb->tot_len += copied;
+       // printk("Copied %d bytes of data \n", copied);
+       // ethernet crc performed in hardware
+       copied -= 4;
+
+       pb->len = copied;
+       pb->tot_len = copied;
        return pb;
 }
 
index 4c77541..832a72b 100644 (file)
@@ -7,9 +7,9 @@
 #include <arch/nic_common.h>
 #include <net/pbuf.h>
 
-#define e1000_debug(...)               //printk(__VA_ARGS__)  
-#define e1000_interrupt_debug(...)     //printk(__VA_ARGS__)  
-#define e1000_frame_debug(...)         //printk(__VA_ARGS__)  
+#define e1000_debug(...)               printk(__VA_ARGS__)  
+#define e1000_interrupt_debug(...)     printk(__VA_ARGS__)  
+#define e1000_frame_debug(...)         printk(__VA_ARGS__)  
 
 #define E1000_IRQ_CPU          0
 
 #define E1000_RX_MAX_BUFFER_SIZE 2048
 #define E1000_TX_MAX_BUFFER_SIZE 2048
 
-uint32_t e1000_rr32(uint32_t offset);
-void e1000_wr32(uint32_t offset, uint32_t val);
+/* driver private functions */
+static uint32_t e1000_rr32(uint32_t offset);
+static void e1000_wr32(uint32_t offset, uint32_t val);
+#define E1000_WRITE_FLUSH() e1000_rr32(E1000_STATUS)
 
 void e1000_init(void);
 void e1000_reset(void);
@@ -55,5 +57,6 @@ int  e1000_send_frame(const char* data, size_t len);
 int e1000_send_pbuf(struct pbuf *p);
 /* returns a chain of pbuf from the driver */
 struct pbuf* e1000_recv_pbuf();
-
+void process_pbuf(struct trapframe *tf, uint32_t srcid, long a0, long a1, long a2);
+static void schedule_pb(struct pbuf* pb);
 #endif /* !ROS_INC_E1000_H */
index 5219212..c0c8e1c 100644 (file)
@@ -944,4 +944,19 @@ struct e1000_data_desc {
 /* For checksumming, the sum of all words in the EEPROM should equal 0xBABA. */
 #define EEPROM_SUM 0xBABA
 
+/* This defines the bits that are set in the Interrupt Mask
+ * Set/Read Register.  Each bit is documented below:
+ *   o RXT0   = Receiver Timer Interrupt (ring 0)
+ *   o TXDW   = Transmit Descriptor Written Back
+ *   o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
+ *   o RXSEQ  = Receive Sequence Error
+ *   o LSC    = Link Status Change
+ */
+#define IMS_ENABLE_MASK ( \
+    E1000_IMS_RXT0   |    \
+    E1000_IMS_TXDW   |    \
+    E1000_IMS_RXDMT0 |    \
+    E1000_IMS_RXSEQ  |    \
+    E1000_IMS_LSC)
+
 #endif /* _E1000_HW_H_ */
index b927c5a..c011640 100644 (file)
@@ -22,7 +22,6 @@ int (*send_pbuf)(struct pbuf *p);
 struct pbuf*  (*recv_pbuf)(void);
 
 
-
 // Global variables for managing ethernet packets over a nic
 // Again, since these are global for all network cards we are 
 // limited to only one for now
index 3bf9d26..148bcb4 100644 (file)
@@ -50,4 +50,10 @@ struct eth_frame {
        char data[MTU];
 } __attribute__((packed));
 
+static inline void print_mac (uint8_t* mac_addr) {
+       printk("%02x:%02x:%02x:%02x:%02x:%02x\n", 0xFF & mac_addr[0], 0xFF & mac_addr[1],       
+                                                                0xFF & mac_addr[2], 0xFF & mac_addr[3],        
+                                                           0xFF & mac_addr[4], 0xFF & mac_addr[5]);
+}
+
 #endif /* !ROS_INC_NIC_COMMON_H */
index be652ea..0bb8219 100644 (file)
 #define        INADDR_ANY                      (struct in_addr) {0x00000000}
 #define        INADDR_BROADCAST        (struct in_addr) {0xffffffff}   /* must be masked */
 
+/** 0.0.0.0 */
+#define IPADDR_ANY          ((uint32_t)0x00000000UL)
+/** 255.255.255.255 */
+#define IPADDR_BROADCAST    ((uint32_t)0xffffffffUL)
+
 #define        htonl(x) cpu_to_be32(x)
 #define        htons(x) cpu_to_be16(x)
 #define        ntohl(x) be32_to_cpu(x)
index 60bed3c..f521fc9 100644 (file)
@@ -9,6 +9,7 @@
 #define ROS_KERN_NET_H
 
 #include <bits/netinet.h>
+#include <net/pbuf.h>
 #include <stdio.h>
 
 /* network internal error code */
 
 /* A few other useful standard defines.  Note the IP header can change size. */
 #define ETH_HDR_SZ 14 // without padding, 16 with padding
+
+#define SIZEOF_ETH_HDR (14 + ETH_PAD_SIZE)  
+
 #define UDP_HDR_SZ 8
 #define IP_ETH_TYPE 0x0800
+#define ETHTYPE_IP IP_ETH_TYPE
+#define ETHTYPE_ARP 0x0806
+
 #define IP_HDR_SZ 20
 /* ROS defaults: They really should be netif specific*/
 #define DEFAULT_TTL 64
 /* Don't forget the bytes are in network order */
 struct ethernet_hdr {
        /* might want to pad to increase access speed? */
-       uint8_t           padding[2];
        uint8_t                                         dst_mac[6];
        uint8_t                                         src_mac[6];
        uint16_t                                        eth_type;
        /* might be an optional 802.1q tag here */
 } __attribute__((packed));
 
+#define IP_RF 0x8000        /* reserved fragment flag */
+#define IP_DF 0x4000        /* dont fragment flag */
+#define IP_MF 0x2000        /* more fragments flag */
+#define IP_OFFMASK 0x1fff   /* mask for fragmenting bits */
 
 /* For the bit-enumerated fields, note that you need to read "backwards" through
  * the byte (first bits in memory are the "LSB" of the byte).  Can't seem to be
@@ -45,7 +55,6 @@ struct ip_hdr {
        unsigned                                        hdr_len : 4;
        unsigned                                        version : 4;
        uint8_t                                         tos;
-
        uint16_t                                        packet_len;
        /* ip header id is used for fragmentation reassembly */
        uint16_t                                        id;  // 1 index this?
@@ -66,7 +75,8 @@ struct udp_hdr {
        uint16_t                                        length;
        uint16_t                                        checksum;
 };
-
+/* src and dst are in network order*/
+uint16_t inet_chksum_pseudo(struct pbuf *p, uint32_t src, uint32_t dest, uint8_t proto, uint16_t proto_len);
 uint16_t __ip_checksum(void *buf, unsigned int len, uint32_t sum);
 uint16_t ip_checksum(struct ip_hdr *ip_hdr);
 uint16_t udp_checksum(struct ip_hdr *ip_hdr, struct udp_hdr *udp_hdr);
index 408a90b..14e103a 100644 (file)
@@ -3,7 +3,12 @@
 #include <net/pbuf.h>
 #include <net.h>
 #include <bits/netinet.h>
+#define ip_addr_isany(addr1) ((addr1) == NULL || (addr1)->s_addr == IPADDR_ANY)
+#define ip_addr_cmp(addr1, addr2) ((addr1)->s_addr == (addr2)->s_addr)
+#define ip_match(addr1, addr2) (ip_addr_isany(addr1) || ip_addr_isany(addr2) || ip_addr_cmp(addr1, addr2))
+
 extern struct in_addr global_ip;
 int ip_output(struct pbuf *p, struct in_addr *src, struct in_addr *dest, uint8_t proto);
+int ip_input(struct pbuf *p);
 
 #endif // ROS_KERN_IP_H
index c2b1ffd..ae6977e 100644 (file)
@@ -3,6 +3,8 @@
 #include <kmalloc.h>
 #include <slab.h>
 #include <kref.h>
+#include <sys/queue.h>
+#include <atomic.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -11,6 +13,9 @@ extern "C" {
 /** Currently, the pbuf_custom code is only needed for one specific configuration
  * of IP_FRAG */
 #define LWIP_SUPPORT_CUSTOM_PBUF (IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF)
+/* Ensure IP address are 32-bit aligned on 32bit systems, and thus improving the speed of processing
+ * for regularly accessed fields such as IP addresses
+ */
 #define ETH_PAD_SIZE 2      // padding to ensure ip packet is longword aligned.
 #define PBUF_TRANSPORT_HLEN 20
 #define PBUF_IP_HLEN        20
@@ -32,17 +37,19 @@ typedef enum {
 } pbuf_type;
 
 
-/** indicates this packet's data should be immediately passed to the application */
-#define PBUF_FLAG_PUSH      0x01U
 /** indicates this is a custom pbuf: pbuf_free and pbuf_header handle such a
     a pbuf differently */
 #define PBUF_FLAG_IS_CUSTOM 0x02U
-/** indicates this pbuf is UDP multicast to be looped back */
-#define PBUF_FLAG_MCASTLOOP 0x04U
+struct pbuf;
+STAILQ_HEAD(pbuf_tailq, pbuf);
 
 struct pbuf {
-  /** next pbuf in singly linked pbuf chain */
-  struct pbuf *next;
+       /* Several reasons to roll own version of STAIL queue here 
+        * pbuf chain exists without a queue
+        * also pbuf chain need to be moved entirely onto a socket queue
+        */
+       STAILQ_ENTRY(pbuf) next;
+  // struct pbuf *next;
 
   /** pointer to the actual data in the buffer */
   void *payload;
@@ -52,8 +59,10 @@ struct pbuf {
   /** length of this buffer */
   uint16_t len;
 
+       uint16_t alloc_len;
+
   /** pbuf_type as u8_t instead of enum to save space */
-  uint8_t /*pbuf_type*/ type;
+  uint8_t type;
 
   /** misc flags */
   uint8_t flags;
@@ -61,20 +70,35 @@ struct pbuf {
   struct kref bufref;
 };
 
+struct pbuf_head {
+       struct pbuf_tailq pbuf_fifo;
+       uint32_t qlen;
+       spinlock_t lock; 
+};
+
+static inline void pbuf_head_init(struct pbuf_head *ph) {
+       STAILQ_INIT(&ph->pbuf_fifo);
+       ph->qlen = 0;
+       spinlock_init(&ph->lock);
+}
 extern struct kmem_cache *pbuf_kcache;
 /* Initializes the pbuf module. This call is empty for now, but may not be in future. */
 void pbuf_init(void);
 void pbuf_cat(struct pbuf *head, struct pbuf *tail);
 void pbuf_chain(struct pbuf *head, struct pbuf *tail);
 void pbuf_ref(struct pbuf *p);
+bool pbuf_deref(struct pbuf *p);
 int pbuf_header(struct pbuf *p, int header_size);
 struct pbuf *pbuf_alloc(pbuf_layer layer, uint16_t length, pbuf_type type);
 int pbuf_copy_out(struct pbuf *buf, void *dataptr, size_t len, uint16_t offset);
 void print_pbuf(struct pbuf *p);
+bool pbuf_free(struct pbuf *p);
+
+void attach_pbuf(struct pbuf *p, struct pbuf_head *buf_head);
+struct pbuf* detach_pbuf(struct pbuf_head *buf_head);
 // end
 #if 0
 void pbuf_realloc(struct pbuf *p, u16_t size); 
-u8_t pbuf_free(struct pbuf *p);
 u8_t pbuf_clen(struct pbuf *p);  
 struct pbuf *pbuf_dechain(struct pbuf *p);
 err_t pbuf_copy(struct pbuf *p_to, struct pbuf *p_from);
index 6184e8c..5b9b3ef 100644 (file)
@@ -9,6 +9,7 @@
 #define UDP_TTL 255
 
 struct udp_pcb {
+               /* ips are in network byte order */
     struct in_addr local_ip;
     struct in_addr remote_ip;
     /** ports are in host byte order */
@@ -17,12 +18,7 @@ struct udp_pcb {
     uint8_t flags;
     /* Protocol specific PCB members */
     struct udp_pcb *next;
-#if 0
-  /** receive callback function */
-  udp_recv_fn recv;
-  /** user-supplied argument for the recv callback */
-  void *recv_arg;  
-#endif
+               struct socket *pcbsock;
 };
 
 extern struct udp_pcb *udp_pcbs;
@@ -32,12 +28,14 @@ int udp_send(struct udp_pcb *pcb, struct pbuf *p);
 int udp_sendto(struct udp_pcb *pcb, struct pbuf *p,
                     struct in_addr *dst_ip, uint16_t dst_port);
 int udp_bind(struct udp_pcb *pcb, struct in_addr *ip, uint16_t port);
-#if 0
+int udp_input(struct pbuf *p);
+
 #define UDP_FLAGS_NOCHKSUM       0x01U
 #define UDP_FLAGS_UDPLITE        0x02U
 #define UDP_FLAGS_CONNECTED      0x04U
 #define UDP_FLAGS_MULTICAST_LOOP 0x08U
 
+#if 0
 
 /** Function prototype for udp pcb receive callback functions
  * addr and port are in same byte order as in the pcb
index 0f50a74..88f8c1a 100644 (file)
@@ -2,6 +2,9 @@
 #define ROS_SOCKET_H
 
 #include <ros/common.h>
+#include <sys/queue.h>
+#include <atomic.h>
+#include <net/pbuf.h>
 // Just a couple of AF types that we might support
 #define AF_UNSPEC      0
 #define AF_UNIX                1       /* Unix domain sockets          */
@@ -43,7 +46,6 @@ enum sock_type {
     SOCK_DCCP   = 6,
     SOCK_PACKET = 10,
 };
-
 struct socket{
   //int so_count;       /* (b) reference count */
   short   so_type;        /* (a) generic type, see socket.h */
@@ -54,6 +56,9 @@ struct socket{
   short   so_state;       /* (b) internal state flags SS_* */
        //int so_qstate;      /* (e) internal state flags SQ_* */
        void    *so_pcb;        /* protocol control block */
+       struct pbuf_head recv_buff;
+       struct pbuf_head send_buff;
+       
        //struct  vnet *so_vnet;      /* network stack instance */
        //struct  protosw *so_proto;  /* (a) protocol handle */
 };
index bc7bb87..cd5b1e7 100644 (file)
@@ -71,8 +71,9 @@ static void eth_audio_sendpacket(void *buf)
         * Eth-audio device shouldn't care (and Linux seems to be okay with packets
         * that have no checksum (but not a wrong checksum)).  Technically, this
         * hurts our performance a bit (and some NICs can offload this). */
-       eth_udp_out.udp_hdr.checksum = htons(udp_checksum(&eth_udp_out.ip_hdr,
-                                                         &eth_udp_out.udp_hdr));
+       eth_udp_out.udp_hdr.checksum = 0;
+       eth_udp_out.udp_hdr.checksum = udp_checksum(&eth_udp_out.ip_hdr,
+                                                         &eth_udp_out.udp_hdr);
        /* Send it out */
        retval = send_frame((const char*)&eth_udp_out, ETH_AUDIO_FRAME_SZ);
        assert(retval >= 0);
@@ -100,7 +101,8 @@ static void eth_audio_prep_response(struct ethaud_udp_packet *incoming,
        outgoing->ip_hdr.src_addr = htonl(ntohl(incoming->ip_hdr.src_addr) + 1);
        outgoing->ip_hdr.dst_addr = incoming->ip_hdr.src_addr;
        /* Since the IP header is set already, we can compute the checksum. */
-       outgoing->ip_hdr.checksum = htons(ip_checksum(&outgoing->ip_hdr));
+       outgoing->ip_hdr.checksum = 0;
+       outgoing->ip_hdr.checksum = (ip_checksum(&outgoing->ip_hdr);
        outgoing->udp_hdr.src_port = htons(ETH_AUDIO_SRC_PORT);
        outgoing->udp_hdr.dst_port = htons(ETH_AUDIO_DST_PORT);
        outgoing->udp_hdr.length = htons(ETH_AUDIO_PAYLOAD_SZ + UDP_HDR_SZ);
index cd8d98b..bdba916 100644 (file)
 
 #include <net.h>
 #include <stdio.h>
+#include <arch/types.h>
 
-uint16_t __ip_checksum(void *buf, unsigned int len, uint32_t sum)
+#ifndef FOLD_U32T
+#define FOLD_U32T(u)          (((u) >> 16) + ((u) & 0x0000ffffUL))
+#endif
+
+/* New version of ip_checksum, notice this version does not change it into 
+ * network order. It is useful to keep it in host order for further processing
+ */ 
+uint16_t __ip_checksum(void *dataptr, unsigned int len, uint32_t sum)
 {
-       /* Knock out 2 bytes at a time */
-       while (len > 1) {
-               /* Careful of endianness.  The packet is in network ordering */
-               sum += ntohs(*((uint16_t*)buf));
-               buf += sizeof(uint16_t);
-               /* In case we get close to overflowing while summing. */
-               if (sum & 0x80000000)
-                       sum = (sum & 0xFFFF) + (sum >> 16);
-               len -= 2;
-       }
-       /* Handle the last byte, if any */
-       if (len)
-               sum += *(uint8_t*)buf;
-       /* Add the top 16 bytes to the lower ones, til it is done */
-       while (sum >> 16)
-               sum = (sum & 0xFFFF) + (sum >> 16);
-       return ~sum;
+  uint8_t *pb = (uint8_t *)dataptr;
+  uint16_t *ps, t = 0;
+  int odd = ((uintptr_t)pb & 1);
+
+  /* Get aligned to uint16_t */
+       // this means pb started on some weird address..
+       // but in our world this should never happen.. since the payload should always be aligned..
+       // right..
+
+  if (odd && len > 0) {
+               // change the second half of t to what pb is
+               // and advance pb
+    ((uint8_t *)&t)[1] = *pb++;
+    len--;
+  }
+
+  /* Add the bulk of the data */
+  ps = (uint16_t *)(void *)pb;
+  while (len > 1) {
+    sum += *ps++;
+    len -= 2;
+  }
+
+  /* Consume left-over byte, if any */
+  if (len > 0) {
+    ((uint8_t *)&t)[0] = *(uint8_t *)ps;
+  }
+
+  /* Add end bytes */
+  sum += t;
+
+  /* Fold 32-bit sum to 16 bits
+     calling this twice is propably faster than if statements... */
+  sum = FOLD_U32T(sum);
+  sum = FOLD_U32T(sum);
+
+  /* Swap if alignment was odd */
+  if (odd) {
+    sum = byte_swap16(sum);
+  }
+
+  return (uint16_t)sum;
 }
 
 /* Computes the checksum for the IP header.  We could write it in, but for now
@@ -42,28 +75,67 @@ uint16_t __ip_checksum(void *buf, unsigned int len, uint32_t sum)
 uint16_t ip_checksum(struct ip_hdr *ip_hdr)
 {
        unsigned int ip_hdr_len = ip_hdr->hdr_len * sizeof(uint32_t);
-       ip_hdr->checksum = 0;
-       return __ip_checksum(ip_hdr, ip_hdr_len, 0);
+       return ~__ip_checksum(ip_hdr, ip_hdr_len, 0);
 }
 
 /* Computes the checksum for the UDP header.  We could write it in, but for now
  * we'll return the checksum (in host-ordering) and have the caller store the
  * value.  Note that the UDP header needs info from the IP header (strictly
- * speaking, just the src and destination IPs).  */
+ * speaking, just the src and destination IPs).  
+ * LEGACY: only used for packet that are not in pbuf formats*/
 uint16_t udp_checksum(struct ip_hdr *ip_hdr, struct udp_hdr *udp_hdr)
 {
        /* Add up the info for the UDP pseudo-header */
        uint32_t udp_pseudosum = 0;
        uint16_t udp_len = ntohs(udp_hdr->length);
-       udp_hdr->checksum = 0;
-       udp_pseudosum += ntohs(ip_hdr->src_addr & 0xffff);
-       udp_pseudosum += ntohs(ip_hdr->src_addr >> 16);
-       udp_pseudosum += ntohs(ip_hdr->dst_addr & 0xffff);
-       udp_pseudosum += ntohs(ip_hdr->dst_addr >> 16);
-       udp_pseudosum += ip_hdr->protocol;
-       udp_pseudosum += udp_len;
-       return __ip_checksum(udp_hdr, udp_len, udp_pseudosum);
+       udp_pseudosum += (ip_hdr->src_addr & 0xffff);
+       udp_pseudosum += (ip_hdr->src_addr >> 16);
+       udp_pseudosum += (ip_hdr->dst_addr & 0xffff);
+       udp_pseudosum += (ip_hdr->dst_addr >> 16);
+       udp_pseudosum += (ip_hdr->protocol);
+       udp_pseudosum += udp_hdr->length;
+       return ~(__ip_checksum(udp_hdr, udp_len, udp_pseudosum));
+}
+
+/* ip addresses need to be network order, protolen and proto are HO */
+uint16_t inet_chksum_pseudo(struct pbuf *p, uint32_t src, uint32_t dest, uint8_t proto, uint16_t proto_len) {
+  uint32_t acc;
+  uint32_t addr;
+  struct pbuf *q;
+  uint8_t swapped;
+
+  acc = 0;
+  swapped = 0;
+  /* iterate through all pbuf in chain */
+  for(q = p; q != NULL; q = STAILQ_NEXT(q, next)) {
+    acc += __ip_checksum(q->payload, q->len, 0);
+    acc = FOLD_U32T(acc);
+    if (q->len % 2 != 0) {
+      swapped = 1 - swapped;
+      acc = byte_swap16(acc);
+    }
+  }
+
+  if (swapped) {
+    acc = byte_swap16(acc);
+  }
+
+  addr = (src);
+  acc += (addr & 0xffffUL);
+  acc += ((addr >> 16) & 0xffffUL);
+  addr = (dest);
+  acc += (addr & 0xffffUL);
+  acc += ((addr >> 16) & 0xffffUL);
+  acc += (uint32_t)htons((uint16_t)proto);
+  acc += (uint32_t)htons(proto_len);
+
+  /* Fold 32-bit sum to 16 bits
+     calling this twice is propably faster than if statements... */
+  acc = FOLD_U32T(acc);
+  acc = FOLD_U32T(acc);
+  return (uint16_t)~(acc & 0xffffUL);
 }
+
 /* Print out a network packet in the same format as tcpdump, making it easier 
  * to compare */
 void dumppacket(unsigned char *buff, size_t len)
index 5f5cda9..b20fc99 100644 (file)
@@ -19,6 +19,7 @@ struct in_addr global_ip = {IP_ADDR};
 /* TODO: build arp table, and look up */
 int eth_send(struct pbuf *p, struct in_addr *dest) {
        uint32_t bytes_sent; 
+       printk("size of pbuf_header movement %d\n", sizeof(struct ethernet_hdr));
        if (pbuf_header(p, sizeof(struct ethernet_hdr)) != 0){
                warn("eth_send buffer ran out");
                /* unsuccessful, needs to allocate */   
@@ -34,11 +35,7 @@ int eth_send(struct pbuf *p, struct in_addr *dest) {
         * is so that we can send from multi-buffer later.
         */
        if (send_pbuf){
-       #if ETH_PAD_SIZE
-               pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
-       #endif
                bytes_sent = send_pbuf(p);
-               pbuf_header(p, ETH_PAD_SIZE); /* when do we deallocate p? */
                return bytes_sent;
        }
        else {
@@ -81,7 +78,7 @@ int ip_output(struct pbuf *p, struct in_addr *src, struct in_addr *dest, uint8_t
        ip_id++;
        iphdr->flags_frags = htons(0); // 4000  may fragment
        iphdr->protocol = proto;
-       iphdr->ttl = htons(DEFAULT_TTL);
+       iphdr->ttl = DEFAULT_TTL;
        /* Eventually if we support more than one device this may change */
        printk("src ip %x, dest ip %x \n", src->s_addr, dest->s_addr);
        iphdr->src_addr = htonl(src->s_addr);
@@ -91,11 +88,82 @@ int ip_output(struct pbuf *p, struct in_addr *src, struct in_addr *dest, uint8_t
         */
        /* Since the IP header is set already, we can compute the checksum. */
        /* TODO: Use the card to calculate the checksum */
-       iphdr->checksum = htons(ip_checksum(iphdr)); //7ab6
+       iphdr->checksum = 0;
+       iphdr->checksum = ip_checksum(iphdr); //7ab6
        if (p->tot_len > DEFAULT_MTU) /*MAX MTU? header included */
                return -1;//ip_frag(p, dest);
        else
                return eth_send(p, dest);
 }
 
+int ip_input(struct pbuf *p) {
+       uint32_t iphdr_hlen, iphdr_len;
+       struct ip_hdr *iphdr = (struct ip_hdr *)p->payload;
+       printk("start of ip %p \n", p->payload);
+       print_pbuf(p);
+       /* use that info to build arp table */
+  if (iphdr->version != 4) {
+               warn("ip version not 4!\n");
+    pbuf_free(p);
+               return -1;
+       }
+       iphdr_hlen = iphdr->hdr_len * 4;
+       iphdr_len = ntohs(iphdr->packet_len);
+       printk("ip input coming from %x of size %d", ntohs(iphdr->dst_addr), iphdr_len);
+  /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */
+  if ((iphdr_hlen > p->len) || (iphdr_len > p->tot_len)) {
+    if (iphdr_hlen > p->len) {
+        warn("IP header (len 0x%X) does not fit in first pbuf (len %X), IP packet dropped.\n",
+        iphdr_hlen, p->len);
+    }
+    if (iphdr_len > p->tot_len) {
+        warn("IP (len %X) is longer than pbuf (len %X), IP packet dropped.\n",
+        iphdr_len, p->tot_len);
+    }
+    /* free (drop) packet pbufs */
+    pbuf_free(p);
+    return -1;
+  }
+       if (ip_checksum(iphdr) != 0) {
+               warn("checksum failed \n");
+               pbuf_free(p);
+               return -1;
+       }
+
+       /* check if it is destined for me? */
+       /* XXX: IP address for the interface is IP_ANY */
+       if (ntohl(iphdr->dst_addr) != global_ip.s_addr){
+               printk("dest ip in network order%x\n", ntohl(iphdr->dst_addr));
+               printk("dest ip in network order%x\n", global_ip.s_addr);
+               warn("ip mismatch \n");
+               pbuf_free(p);
+               /* TODO:forward packets */
+               // ip_forward(p, iphdr, inp);
+       }
+
+       if ((ntohs(iphdr->flags_frags) & (IP_OFFMASK | IP_MF)) != 0){
+               panic ("ip fragment detected\n");
+               pbuf_free(p);
+       }
+
+       printk ("loc head %p, loc protocol %p\n", iphdr, &iphdr->protocol);
+       /* currently a noop, compared to the memory wasted, cutting out ipheader is not really saving much */
+       // pbuf_realloc(p, iphdr_len);
+       switch (iphdr->protocol) {
+               case IPPROTO_UDP:
+                       return udp_input(p);
+               case IPPROTO_TCP:
+               default:
+                       printk("IP protocol type %02x\n", iphdr->protocol);
+                       warn("protocol not supported! \n");
+       }
+       return -1;
+}
+
+void print_ipheader(struct ip_hdr* iph){
+
+       
+}
+
 
index 633309b..13573a4 100644 (file)
@@ -6,11 +6,19 @@
 #include <slab.h>
 #include <assert.h>
 #include <net/pbuf.h>
+#include <sys/queue.h>
+#include <net.h>
 #include <arch/nic_common.h>
 
-
+/* TODO: before running
+ * 1. pbuf_free_auto currently decrefs the next one on the chain or queue
+ * 2. copy_out currently copies out the chain following the next pointer
+ *    could be dangerous if it runs on pbufs on a send/recv socket queue
+ * 3. Tot_len could be useless at some point, especially if the max len is only two...
+ * 4. pbuf_chain and pbuf_cat, pbuf_clen has no users yet
+ */
 #define SIZEOF_STRUCT_PBUF (ROUNDUP(sizeof(struct pbuf), ROS_MEM_ALIGN))
-#define SIZEOF_STRUCT_MTU_PBUF SIZEOF_STRUCT_PBUF + ROUNDUP(sizeof(MAX_FRAME_SIZE), ROS_MEM_ALIGN)
+#define MTU_PBUF_SIZE SIZEOF_STRUCT_PBUF + MAX_FRAME_SIZE + ETH_PAD_SIZE
 
 struct kmem_cache *pbuf_kcache;
 struct kmem_cache *mtupbuf_kcache;
@@ -21,15 +29,15 @@ void pbuf_init(void){
        printk("alignment %d\n", __alignof__(struct pbuf));
        pbuf_kcache = kmem_cache_create("pbuf", sizeof(struct pbuf),
                                                                        __alignof__(struct pbuf), 0, 0, 0);
-  mtupbuf_kcache = kmem_cache_create("mtupbuf_kcache", SIZEOF_STRUCT_MTU_PBUF
+  mtupbuf_kcache = kmem_cache_create("mtupbuf_kcache", MTU_PBUF_SIZE
                                                                                __alignof__(struct pbuf), 0, 0, 0);
 }
 
-// not sure about this structure..
 static void pbuf_free_auto(struct kref *kref){
     struct pbuf *p = container_of(kref, struct pbuf, bufref);
+               if (!p) return;
+               struct pbuf *q = STAILQ_NEXT(p, next);
                printd("deleting p %p of type %d\n", p, p->type);
-               
     switch (p->type){
         case PBUF_REF:
             kmem_cache_free(pbuf_kcache, p);
@@ -39,9 +47,12 @@ static void pbuf_free_auto(struct kref *kref){
             break;
                                case PBUF_MTU:
                                                kmem_cache_free(mtupbuf_kcache,p);
+                                               break;
         default:
             panic("Invalid pbuf type");
     }
+               if (q != NULL) 
+                       pbuf_deref(q);
 }
 
 /**
@@ -113,11 +124,11 @@ struct pbuf *pbuf_alloc(pbuf_layer layer, uint16_t length, pbuf_type type)
     if (p == NULL) {
       return NULL;
     }
-               buf_size = SIZEOF_STRUCT_MTU_PBUF;
-    p->payload = PTRROUNDUP(((void *)((uint8_t *)p + SIZEOF_STRUCT_PBUF + offset)), ROS_MEM_ALIGN);
-               p->next = NULL;
+    p->payload = (void *)((uint8_t *)p + SIZEOF_STRUCT_PBUF + offset);
+               STAILQ_NEXT(p, next) = NULL;
                p->type = type;
-               p->len = p->tot_len = ROUNDUP(sizeof(MAX_FRAME_SIZE), ROS_MEM_ALIGN);
+               p->alloc_len = MTU_PBUF_SIZE;
+               p->len = p->tot_len = 0;
                break;
 
        case PBUF_RAM:
@@ -129,9 +140,9 @@ struct pbuf *pbuf_alloc(pbuf_layer layer, uint16_t length, pbuf_type type)
       return NULL;
     }
     /* Set up internal structure of the pbuf. */
-    p->payload = PTRROUNDUP(((void *)((uint8_t *)p + SIZEOF_STRUCT_PBUF + offset)), ROS_MEM_ALIGN);
-    p->len = p->tot_len = length;
-    p->next = NULL;
+    p->payload = (void *)((uint8_t *)p + SIZEOF_STRUCT_PBUF + offset);
+    p->alloc_len = p->len = p->tot_len = length;
+               STAILQ_NEXT(p, next) = NULL;
     p->type = type;
     break;
   case PBUF_REF:
@@ -141,13 +152,13 @@ struct pbuf *pbuf_alloc(pbuf_layer layer, uint16_t length, pbuf_type type)
       return NULL;
     }
     p->payload = NULL;
-    p->len = p->tot_len = length;
-    p->next = NULL;
+    p->alloc_len = p->len = p->tot_len = length;
+               STAILQ_NEXT(p, next) = NULL;
     p->type = type;
     break;
        case PBUF_POOL:
-               
-               break;  
+               warn("POOL type not supported!");       
+               return NULL;    
   default:
     warn("pbuf_alloc: wrong type", 0);
     return NULL;
@@ -160,9 +171,34 @@ struct pbuf *pbuf_alloc(pbuf_layer layer, uint16_t length, pbuf_type type)
 
 
 void pbuf_ref(struct pbuf *p){
-    kref_get(&p->bufref, 1);
+       kref_get(&p->bufref, 1);
+}
+
+/**
+ * true if the pbuf is deallocated as a result of pbuf_deref
+ * false means just a simple deref
+ */
+bool pbuf_deref(struct pbuf *p){
+       return kref_put(&p->bufref);
+}
+
+void attach_pbuf(struct pbuf *p, struct pbuf_head *ph){
+       spin_lock_irqsave(&ph->lock);
+       ph->qlen++;
+       STAILQ_INSERT_TAIL(&ph->pbuf_fifo, p, next);
+       spin_unlock_irqsave(&ph->lock);
 }
 
+struct pbuf* detach_pbuf(struct pbuf_head *ph){
+       struct pbuf* buf = NULL;
+       if (ph->qlen == 0) return NULL;
+       spin_lock_irqsave(&ph->lock);
+       ph->qlen--;
+       buf = STAILQ_FIRST(&ph->pbuf_fifo);
+       STAILQ_REMOVE_HEAD(&ph->pbuf_fifo, next);
+       spin_unlock_irqsave(&ph->lock);
+       return buf;
+}
 
 /**
  * Copy (part of) the contents of a packet buffer
@@ -188,7 +224,7 @@ int pbuf_copy_out(struct pbuf *buf, void *dataptr, size_t len, uint16_t offset)
        }
 
   left = 0;
-  for(p = buf; len != 0 && p != NULL; p = p->next) {
+  for(p = buf; len != 0 && p != NULL; p = STAILQ_NEXT(p, next)) {
     if ((offset != 0) && (offset >= p->len)) {
       /* don't copy from this buffer -> on to the next */
       offset -= p->len;
@@ -237,14 +273,14 @@ pbuf_cat(struct pbuf *h, struct pbuf *t)
 {
   struct pbuf *p;
   /* proceed to last pbuf of chain */
-  for (p = h; p->next != NULL; p = p->next) {
+  for (p = h; STAILQ_NEXT(p, next) != NULL; p = STAILQ_NEXT(p, next)) {
     /* add total length of second chain to all totals of first chain */
     p->tot_len += t->tot_len;
   }
   /* add total length of second chain to last pbuf total of first chain */
   p->tot_len += t->tot_len;
   /* chain last pbuf of head (p) with first of tail (t) */
-  p->next = t;
+       STAILQ_NEXT(p,next) = t;
 }
 
 /**
@@ -272,22 +308,21 @@ pbuf_cat(struct pbuf *h, struct pbuf *t)
 int pbuf_header(struct pbuf *p, int delta){ // increase header size
        uint8_t type = p->type;
        void *payload = p->payload;
+       printk("delta %d \n", delta);
        if (p == NULL || delta == 0)
                return 0;
-       if (delta < 0) 
-               assert(-delta < p->len);
-       type = p->type;
-  /* remember current payload pointer */
-  payload = p->payload;
+       // This assertion used to apply when len meant allocated space..
+       // assert(-delta < p->len);
 
   /* pbuf types containing payloads? */
-  if (type == PBUF_RAM || type == PBUF_POOL) {
+  if (type == PBUF_RAM || type == PBUF_POOL || type == PBUF_MTU) {
     /* set new payload pointer */
     p->payload = (uint8_t *)p->payload - delta;
     /* boundary check fails? */
     if ((uint8_t *)p->payload < (uint8_t *)p + SIZEOF_STRUCT_PBUF) {
       /* restore old payload pointer */
       p->payload = payload;
+                       warn("boundary failed \n");
       /* bail out unsuccesfully */
       return 1;
     }
@@ -316,14 +351,61 @@ int pbuf_header(struct pbuf *p, int delta){ // increase header size
 
 void print_pbuf(struct pbuf *p) {
        struct pbuf *next = p;
-       while ( next != NULL) {
-               for(int i = 0; i< next->len; i++){
-                       printk("%x", ((uint8_t*)next->payload)[i]);
-               }
+       //basically while pbuf is not on the socket queue yet, we can't use STAILQ_NEXT 
+
+       /*XXX: this is wrong.. */
+       while (next != NULL) {
+               printk("pbuf start \n");
+               dumppacket(next->payload, next->len);
                printk("\n");
-               next = next->next;
+               next = STAILQ_NEXT(next, next);
        }
 }
+
+
+/**
+ * Dereference a pbuf chain or queue and deallocate any no-longer-used
+ * pbufs at the head of this chain or queue.
+ *
+ * Decrements the pbuf reference count. If it reaches zero, the pbuf is
+ * deallocated.
+ *
+ * For a pbuf chain, this is repeated for each pbuf in the chain,
+ * up to the first pbuf which has a non-zero reference count after
+ * decrementing. So, when all reference counts are one, the whole
+ * chain is free'd.
+ *
+ * @param p The pbuf (chain) to be dereferenced.
+ *
+ * @return the number of pbufs that were de-allocated
+ * from the head of the chain.
+ *
+ *
+ */
+bool pbuf_free(struct pbuf *p) {
+       return pbuf_deref(p);
+}
+
+/**
+ * Count number of pbufs in a chain
+ *
+ * @param p first pbuf of chain
+ * @return the number of pbufs in a chain
+ */
+
+uint8_t pbuf_clen(struct pbuf *p)
+{
+  uint8_t len;
+
+  len = 0;
+  while (p != NULL) {
+    ++len;
+    p = STAILQ_NEXT(p, next);
+  }
+  return len;
+}
+
+
 #if 0
 #if LWIP_SUPPORT_CUSTOM_PBUF
 /** Initialize a custom pbuf (already allocated).
@@ -464,137 +546,6 @@ pbuf_realloc(struct pbuf *p, u16_t new_len)
 }
 
 
-/**
- * Dereference a pbuf chain or queue and deallocate any no-longer-used
- * pbufs at the head of this chain or queue.
- *
- * Decrements the pbuf reference count. If it reaches zero, the pbuf is
- * deallocated.
- *
- * For a pbuf chain, this is repeated for each pbuf in the chain,
- * up to the first pbuf which has a non-zero reference count after
- * decrementing. So, when all reference counts are one, the whole
- * chain is free'd.
- *
- * @param p The pbuf (chain) to be dereferenced.
- *
- * @return the number of pbufs that were de-allocated
- * from the head of the chain.
- *
- * @note MUST NOT be called on a packet queue (Not verified to work yet).
- * @note the reference counter of a pbuf equals the number of pointers
- * that refer to the pbuf (or into the pbuf).
- *
- * @internal examples:
- *
- * Assuming existing chains a->b->c with the following reference
- * counts, calling pbuf_free(a) results in:
- * 
- * 1->2->3 becomes ...1->3
- * 3->3->3 becomes 2->3->3
- * 1->1->2 becomes ......1
- * 2->1->1 becomes 1->1->1
- * 1->1->1 becomes .......
- *
- */
-u8_t
-pbuf_free(struct pbuf *p)
-{
-  u16_t type;
-  struct pbuf *q;
-  u8_t count;
-
-  if (p == NULL) {
-    LWIP_ASSERT("p != NULL", p != NULL);
-    /* if assertions are disabled, proceed with debug output */
-    LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
-      ("pbuf_free(p == NULL) was called.\n"));
-    return 0;
-  }
-  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free(%p)\n", (void *)p));
-
-  PERF_START;
-
-  LWIP_ASSERT("pbuf_free: sane type",
-    p->type == PBUF_RAM || p->type == PBUF_ROM ||
-    p->type == PBUF_REF || p->type == PBUF_POOL);
-
-  count = 0;
-  /* de-allocate all consecutive pbufs from the head of the chain that
-   * obtain a zero reference count after decrementing*/
-  while (p != NULL) {
-    u16_t ref;
-    SYS_ARCH_DECL_PROTECT(old_level);
-    /* Since decrementing ref cannot be guaranteed to be a single machine operation
-     * we must protect it. We put the new ref into a local variable to prevent
-     * further protection. */
-    SYS_ARCH_PROTECT(old_level);
-    /* all pbufs in a chain are referenced at least once */
-    LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0);
-    /* decrease reference count (number of pointers to pbuf) */
-    ref = --(p->ref);
-    SYS_ARCH_UNPROTECT(old_level);
-    /* this pbuf is no longer referenced to? */
-    if (ref == 0) {
-      /* remember next pbuf in chain for next iteration */
-      q = p->next;
-      LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: deallocating %p\n", (void *)p));
-      type = p->type;
-#if LWIP_SUPPORT_CUSTOM_PBUF
-      /* is this a custom pbuf? */
-      if ((p->flags & PBUF_FLAG_IS_CUSTOM) != 0) {
-        struct pbuf_custom *pc = (struct pbuf_custom*)p;
-        LWIP_ASSERT("pc->custom_free_function != NULL", pc->custom_free_function != NULL);
-        pc->custom_free_function(p);
-      } else
-#endif /* LWIP_SUPPORT_CUSTOM_PBUF */
-      {
-        /* is this a pbuf from the pool? */
-        if (type == PBUF_POOL) {
-          memp_free(MEMP_PBUF_POOL, p);
-        /* is this a ROM or RAM referencing pbuf? */
-        } else if (type == PBUF_ROM || type == PBUF_REF) {
-          memp_free(MEMP_PBUF, p);
-        /* type == PBUF_RAM */
-        } else {
-          mem_free(p);
-        }
-      }
-      count++;
-      /* proceed to next pbuf */
-      p = q;
-    /* p->ref > 0, this pbuf is still referenced to */
-    /* (and so the remaining pbufs in chain as well) */
-    } else {
-      LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, ref));
-      /* stop walking through the chain */
-      p = NULL;
-    }
-  }
-  PERF_STOP("pbuf_free");
-  /* return number of de-allocated pbufs */
-  return count;
-}
-
-/**
- * Count number of pbufs in a chain
- *
- * @param p first pbuf of chain
- * @return the number of pbufs in a chain
- */
-
-u8_t
-pbuf_clen(struct pbuf *p)
-{
-  u8_t len;
-
-  len = 0;
-  while (p != NULL) {
-    ++len;
-    p = p->next;
-  }
-  return len;
-}
 
 /**
  * Increment the reference count of the pbuf.
index 633d0ce..ce78b1e 100644 (file)
@@ -8,7 +8,7 @@
 #include <kmalloc.h>
 #include <socket.h>
 #include <net.h>
-#include <sys/queue.h> //TODO: use sys/queue.h rather than implementing
+#include <sys/queue.h>
 #include <atomic.h>
 
 #include <bits/netinet.h>
@@ -20,7 +20,6 @@
 struct udp_pcb *udp_pcbs;
 uint16_t udp_port_num = SOCKET_PORT_START;
 
-
 struct udp_pcb* udp_new(void){
        struct udp_pcb *pcb = kmem_cache_alloc(udp_pcb_kcache, 0);
     // if pcb is only tracking ttl, then no need!
@@ -38,6 +37,54 @@ int udp_send(struct udp_pcb *pcb, struct pbuf *p)
   return udp_sendto(pcb, p, &pcb->remote_ip, pcb->remote_port);
 }
 
+typedef unsigned char u16;
+typedef unsigned long u32;
+
+u16 udp_sum_calc(u16 len_udp, u16 src_addr[],u16 dest_addr[],  int padding, u16 buff[])
+{
+u16 prot_udp=17;
+u16 padd=0;
+u16 word16;
+u32 sum;
+int i;
+       
+       // Find out if the length of data is even or odd number. If odd,
+       // add a padding byte = 0 at the end of packet
+       if ((padding&1)==1){
+               padd=1;
+               buff[len_udp]=0;
+       }
+       
+       //initialize sum to zero
+       sum=0;
+       
+       // make 16 bit words out of every two adjacent 8 bit words and 
+       // calculate the sum of all 16 vit words
+       for (i=0;i<len_udp+padd;i=i+2){
+               word16 =((buff[i]<<8)&0xFF00)+(buff[i+1]&0xFF);
+               sum = sum + (unsigned long)word16;
+       }       
+       // add the UDP pseudo header which contains the IP source and destinationn addresses
+       for (i=0;i<4;i=i+2){
+               word16 =((src_addr[i]<<8)&0xFF00)+(src_addr[i+1]&0xFF);
+               sum=sum+word16; 
+       }
+       for (i=0;i<4;i=i+2){
+               word16 =((dest_addr[i]<<8)&0xFF00)+(dest_addr[i+1]&0xFF);
+               sum=sum+word16;         
+       }
+       // the protocol number and the length of the UDP packet
+       sum = sum + prot_udp + len_udp;
+
+       // keep only the last 16 bits of the 32 bit calculated sum and add the carries
+       while (sum>>16)
+               sum = (sum & 0xFFFF)+(sum >> 16);
+               
+       // Take the one's complement of sum
+       sum = ~sum;
+
+return ((u16) sum);
+}
 
 int udp_sendto(struct udp_pcb *pcb, struct pbuf *p,
                     struct in_addr *dst_ip, uint16_t dst_port){
@@ -45,7 +92,6 @@ int udp_sendto(struct udp_pcb *pcb, struct pbuf *p,
     // ip_route();
     struct udp_hdr *udphdr;
     struct pbuf *q;
-               /* TODO: utility to peform inet_ntop and        inet_pton for debugging*/
                printd("udp_sendto ip %x, port %d\n", dst_ip->s_addr, dst_port); 
     // broadcast?
     if (pcb->local_port == 0) {
@@ -67,28 +113,28 @@ int udp_sendto(struct udp_pcb *pcb, struct pbuf *p,
                                /* Successfully padded the header*/
                                q = p;
     }
+
     udphdr = (struct udp_hdr *) q->payload;
-               printd("src port %x, dst port %x \n, length %x ", pcb->local_port, dst_port, q->tot_len);
+               printd("src port %d, dst port %d \n, length %d ", pcb->local_port, ntohs(dst_port), q->tot_len);
     udphdr->src_port = htons(pcb->local_port);
     udphdr->dst_port = (dst_port);
-    udphdr->checksum = 0x0000; //either use brho's checksum or use cards' capabilities
-    udphdr->length = htons(q->tot_len); // 630
+    udphdr->length = htons(q->tot_len); 
+               udphdr->checksum = 0; // just to be sure.
+               // printd("checksum inet_chksum %x \n", udphdr->checksum);
+               printd("params src addr %x, dst addr %x, length %x \n", global_ip.s_addr, (dst_ip->s_addr), 
+                                         q->tot_len);
+
+               uint32_t checksum = udp_sum_calc(q->tot_len, &(global_ip.s_addr), &(dst_ip->s_addr), false,
+                                                                                               q->payload);
+               printd ("method theirs %x \n", checksum);
+               
+    udphdr->checksum = inet_chksum_pseudo(q, htonl(global_ip.s_addr), dst_ip->s_addr,
+                                                                                        IPPROTO_UDP, q->tot_len);
+               printd ("method ours %x\n", udphdr->checksum);
+               // 0x0000; //either use brho's checksum or use cards' capabilities
                // ip_output(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDP);
                ip_output(q, &global_ip, dst_ip, IPPROTO_UDP);
-
     return 0;
-
-    // generate checksum if we need it.. check net.c
-    //src_ip = GLOBAL_IP;
-    // ip_output(blah);
-
-    // check if there is space to operate in place (likely not)
-    // allocate additional pbuf
-    // chain the two bufs together
-    // add udp headers
-    // call ip layer
-
-    // checksum calculation?
 }
 /* TODO: use the real queues we have implemented... */
 int udp_bind(struct udp_pcb *pcb, struct in_addr *ip, uint16_t port){ 
@@ -112,6 +158,7 @@ int udp_bind(struct udp_pcb *pcb, struct in_addr *ip, uint16_t port){
     }
     /* accept data for all interfaces */
     if (ip == NULL || (ip->s_addr == INADDR_ANY.s_addr))
+               /* true right now */
         pcb->local_ip = INADDR_ANY;
     /* assign a port */
     if (port == 0) {
@@ -142,6 +189,108 @@ int udp_bind(struct udp_pcb *pcb, struct in_addr *ip, uint16_t port){
     return 0;
 }
 
+/* port are in host order, ips are in network order */
+/* Think: a pcb is here, if someone is waiting for a connection or the udp conn
+ * has been established */
+static struct udp_pcb* find_pcb(struct udp_pcb* list, uint16_t src_port, uint16_t dst_port,
+                                                               uint16_t srcip, uint16_t dstip) {
+       struct udp_pcb* uncon_pcb = NULL;
+       struct udp_pcb* pcb = NULL;
+       uint8_t local_match = 0;
 
+       for (pcb = list; pcb != NULL; pcb = pcb->next) {
+               local_match = 0;
+               if ((pcb->local_port == dst_port) 
+                       && (pcb->local_ip.s_addr == dstip 
+                       || ip_addr_isany(&pcb->local_ip))){
+                               local_match = 1;
+        if ((uncon_pcb == NULL) && 
+            ((pcb->flags & UDP_FLAGS_CONNECTED) == 0)) {
+          /* the first unconnected matching PCB */
+          uncon_pcb = pcb;
+        }
+               }
+
+               if (local_match && (pcb->remote_port == src_port) &&
+                               (ip_addr_isany(&pcb->remote_ip) ||
+                                pcb->remote_ip.s_addr == srcip))
+                       /* perfect match */
+                       return pcb;
+       }
+       return uncon_pcb;
+}
+
+#if 0 // not working yet
+// need to have pbuf queue support
+int udp_attach(struct pbuf *p, struct sock *socket) {
+       // pretend the attaching of packet is succesful
+       /*
+       recv_q->last->next = p;
+       recv_q->last=p->last
+       */ 
+}
+
+#endif 
+
+/** Process an incoming UDP datagram. 
+ * Given an incoming UDP datagram, this function finds the right PCB
+ * which links to the right socket buffer, and attaches the datagram
+ * to the right socket. 
+ * If no appropriate PCB is found, the pbuf is freed.
+ */ 
 
+/** TODO: think about combining udp_input and ip_input together */
+// TODO: figure out if we even need a PCB? or just socket buff. 
+// TODO: test out looking up pcbs.. since matching function may fail
+int udp_input(struct pbuf *p){
+       struct udp_hdr *udphdr;
 
+       struct udp_pcb *pcb, uncon_pcb;
+       struct ip_hdr *iphdr;
+       uint16_t src, dst;
+       bool local_match = 0;
+       iphdr = (struct ip_hdr *)p->payload;
+       /* Move the header to where the udp header is */
+       if (pbuf_header(p, - PBUF_IP_HLEN)){
+               warn("udp_input: Did not find a matching PCB for a udp packet\n");
+               pbuf_free(p);
+               return -1;
+       }
+       udphdr = (struct udp_hdr *)p->payload;
+       /* convert the src port and dst port to host order */
+       src = ntohs(udphdr->src_port);
+       dst = ntohs(udphdr->dst_port);
+       pcb = find_pcb(udp_pcbs, src, dst, iphdr->src_addr, iphdr->dst_addr);
+       /* TODO: Possibly adjust the pcb to the head of the queue? */
+       /* TODO: Linux uses a set of hashtables to lookup PCBs 
+        * Look at __udp4_lib_lookup function in Linux kernel 2.6.21.1
+        */
+       /* Anything that is not directed at this pcb should have been dropped */
+       if (pcb == NULL){
+               warn("udp_input: Did not find a matching PCB for a udp packet\n");
+               pbuf_free(p);
+               return -1;
+       }
+
+       /* checksum check */
+       // HERE!
+  if (udphdr->checksum != 0) {
+    if (inet_chksum_pseudo(p, (iphdr->src_addr), (iphdr->dst_addr), 
+                                IPPROTO_UDP, p->tot_len) != 0){
+                       warn("udp_input: UPD datagram discarded due to failed chksum!");
+                       pbuf_free(p);
+                       return -1;
+    }
+       }
+  /* ignore SO_REUSE */
+       if (pcb != NULL && pcb->pcbsock != NULL){
+               printk("ready to attach \n");
+               /* For each in the pbuf chain, disconnect from the chain and add it to the
+                * recv_buff of the correct socket 
+                */ 
+               attach_pbuf(p, &pcb->pcbsock->recv_buff);
+               // the attaching of pbuf should have increfed pbuf ref, so free is simply a decref
+               pbuf_free(p);
+       }
+       return 0;
+}
index 415fd8e..e378233 100644 (file)
@@ -17,6 +17,7 @@
 #include <net.h>
 #include <net/udp.h>
 #include <net/pbuf.h>
+#include <umem.h>
 /*
  *TODO: Figure out which socket.h is used where
  *There are several socket.h in kern, and a couple more in glibc. Perhaps the glibc ones
@@ -68,8 +69,13 @@ struct socket* alloc_sock(int socket_family, int socket_type, int protocol){
        newsock->so_type = socket_type;
        newsock->so_protocol = protocol;
        newsock->so_state = SS_ISDISCONNECTED;
-       if (socket_type == SOCK_DGRAM) 
+       pbuf_head_init(&newsock->recv_buff);
+       pbuf_head_init(&newsock->send_buff);
+       if (socket_type == SOCK_DGRAM){
                newsock->so_pcb = udp_new();
+               /* back link */
+               ((struct udp_pcb*) (newsock->so_pcb))->pcbsock = newsock;
+       }
        return newsock;
 
 }
@@ -223,16 +229,30 @@ intreg_t sys_sendto(struct proc *p_proc, int fd, const void *buffer, size_t leng
     error = send_iov(soc, iov, flags);
        #endif
 }
-
 intreg_t sys_recvfrom(struct proc *p, int socket, void *restrict buffer, size_t length, int flags, struct sockaddr *restrict address, socklen_t *restrict address_len){
        struct socket* sock = getsocket(p, socket);     
+       int copied = 0;
+       int returnval = 0;
        if (sock == NULL) {
                set_errno(EBADF);
                return -1;
        }
        if (sock->so_type == SOCK_DGRAM){
-
+               struct pbuf_head *ph = &(sock->recv_buff);
+               struct pbuf* buf = NULL;
+               /* TODO: busy poll the socket buffer for now */
+               while (buf == NULL){
+                       buf = detach_pbuf(ph);
+                       if (buf){
+                               copied = buf->len - sizeof(struct udp_hdr);
+                               if (copied > length)
+                                       copied = length;
+                               
+                       pbuf_header(buf, -PBUF_TRANSPORT_HLEN);
+                       // copy it to user space
+                       returnval = memcpy_to_user_errno(p, buffer, buf->payload, copied);
+                       }
+               }
        }
-
-       return -1;
+       return returnval;
 }
index f09c2d6..9e1d745 100644 (file)
@@ -8,42 +8,59 @@
 #include <errno.h>
 #include <string.h>
 #include <stdlib.h>
-//single fragment for now
 #define BUF_SIZE 16
 
+/* Test program
+ *
+ * Pings the server at argv1: argv2
+ * gets a response and prints it
+ */
+
 int main(int argc, char* argv[]) {
        struct sockaddr_in server;
        char buf[BUF_SIZE] = "hello world";
+       char recv_buf[BUF_SIZE];
        int sockfd, n;
-       struct  hostent* host;
-       if (argc != 1) {
-               printf("where is my hostname?\n");
-
+       struct hostent* host;
+       if (argc != 3){
+               printf("udp_test hostname portnum\n");
                return -1;
        }
        // ignore the host for now
-       // host = gethostbyname(argv[1]);
+       //host = gethostbyname(argv[1]); //hostname
        bzero(&server, sizeof(server));
        server.sin_family = AF_INET;
-       server.sin_port = htons(5000);
+       server.sin_port = htons(atoi(argv[2]));
        server.sin_addr.s_addr = inet_addr("10.0.0.1"); //hardcoded server
-       //server.sin_addr = *((struct in_addr *)host->h_addr);
 
-       if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) ==-1) {
+       //memcpy(&server.sin_addr.s_addr, host->h_addr, host->h_length);
+       
+       char* printbuf = (char*)&server.sin_addr.s_addr;
+       int size = sizeof(server.sin_addr.s_addr);      
+       int i;
+       for (i=0; i<size;i++) {
+               printf("%x", ((char*)printbuf)[i]); 
+       }
+
+       //server.sin_addr = *((struct in_addr *)host->h_addr);
+       sockfd = socket(AF_INET, SOCK_DGRAM, 0);        
+       if (sockfd==-1) {
                printf("socket error\n");
                return -1;
        }
+
        printf ("udp_test: sockfd %d \n", sockfd);
+       int socklen = sizeof(server);
 
-       int sendsize = sendto(sockfd, buf, BUF_SIZE, 0, (struct sockaddr*) &server, sizeof(server));
-       printf ("sendto returns %d, errno %d\n", sendsize, errno);
-/*
-       if ((n = recvfrom(sockfd, buf, BUF_SIZE, 0, NULL, NULL)< 2)){
-               printf ("recv failed\n");
-               return -1;
+       int sendsize = sendto(sockfd, buf, strlen(buf), 0, (struct sockaddr*) &server, socklen);
+       printf("sendto returns %d, errno %d\n", sendsize, errno);
+       //assume BUF_SIZE is larger than the packet.. so we will get to see what actually comes back..
+       if ((n = recvfrom(sockfd, recv_buf, BUF_SIZE, 0, (struct sockaddr*) &server, &socklen)< 0)){
+               printf("recv failed\n");
        }
 
        buf[n-2] = 0; //null terminate
-       printf("%s\n", buf);
-*/     
+
+       printf("recv from result %s\n", buf);
+       close(sockfd);
 }