simple reliable networking over ethernet. Provides IPv4 ARP, ICMP echo reply, and UDP unicast. Does NOT provide TCP, that's not simple :-).

Revision:
0:6df0a6ed91d4
Child:
1:9c211ac06a12
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/snet.cpp	Wed Mar 04 02:04:32 2015 +0000
@@ -0,0 +1,144 @@
+#include "snet.h"
+
+//extern MODSERIAL pc;
+
+//extern void print_hex(uint8_t *p, int len);
+
+//volatile uint32_t enet_rx_cnt;
+//volatile int enet_rx_balance;
+
+extern uint8_t my_ip[4];
+
+
+//uint8_t correspondent_mac[6];    // correspondent's MAC
+const uint8_t Snet::broadcast_mac[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+//const char ourEtherType[] = { 0x82, 0x48 };
+const uint8_t Snet::ipEtherType[] = { 0x08, 0x00 };
+const uint8_t Snet::arp_req_payload_prefix[] = { 0x0, 0x1, 0x8, 0x0, 0x6, 0x4, 0x0, 0x1 };
+
+extern void interpret_inet_packet(uint8_t *buf, int len);
+extern void send_packet_to_radio(uint8_t const *, int);
+
+
+
+Snet::Snet(): eth()
+{
+    eth.address((char *) my_mac);
+    printf("MAC %02x:%02x:%02x:%02x:%02x:%02x\r\n",
+        my_mac[0], my_mac[1], my_mac[2], my_mac[3], my_mac[4], my_mac[5]);
+    printf("no IP\r\n");
+#if 0 // FIXME
+    LPC_EMAC->IntEnable = 0;                // disable all Ethernet interrupts
+    LPC_EMAC->IntClear  = ~0;                          // clear all interrupts 
+
+    //enet_rx_balance = 0;
+    // Enable Ethernet TX and RX Packet Interrupts:
+    //LPC_EMAC->IntEnable |= (ETH_RxFinishedInt | ETH_TxFinishedInt); 
+    LPC_EMAC->IntEnable |= (ETH_RxDoneInt | ETH_TxDoneInt); 
+    NVIC_SetPriority(ENET_IRQn, 0); // lower numbers have priority
+
+    // Enable the interrupt.
+    NVIC_EnableIRQ(ENET_IRQn);
+#endif    
+}
+
+Snet::Snet(const uint8_t *ip): eth()
+{
+    eth.address((char *) my_mac);
+    printf("MAC %02x:%02x:%02x:%02x:%02x:%02x\r\n",
+        my_mac[0], my_mac[1], my_mac[2], my_mac[3], my_mac[4], my_mac[5]);
+    memcpy(my_ip, ip, 4);
+    printf("IP %d.%d.%d.%d\r\n",
+        my_ip[0], my_ip[1], my_ip[2], my_ip[3]);
+#if 0 // FIXME
+    LPC_EMAC->IntEnable = 0;                // disable all Ethernet interrupts
+    LPC_EMAC->IntClear  = ~0;                          // clear all interrupts 
+
+    //enet_rx_balance = 0;
+    // Enable Ethernet TX and RX Packet Interrupts:
+    //LPC_EMAC->IntEnable |= (ETH_RxFinishedInt | ETH_TxFinishedInt); 
+    LPC_EMAC->IntEnable |= (ETH_RxDoneInt | ETH_TxDoneInt); 
+    NVIC_SetPriority(ENET_IRQn, 0); // lower numbers have priority
+
+    // Enable the interrupt.
+    NVIC_EnableIRQ(ENET_IRQn);
+#endif    
+}
+
+
+
+void Snet::handle_arp_request(uint8_t *buf, int len) {
+#if 0
+    printf("Arp from %02x:%02x:%02x:%02x:%02x:%02x ",
+            buf[ENET_SMAC_O+0], buf[ENET_SMAC_O+1],
+            buf[ENET_SMAC_O+2], buf[ENET_SMAC_O+3],
+            buf[ENET_SMAC_O+4], buf[ENET_SMAC_O+5]);*/
+#endif
+    eth.read((char *) &buf[ENET_PAYLOAD_O], len-ENET_PAYLOAD_O);
+    /*print_hex((uint8_t *) &buf[ENET_PAYLOAD_O], len-ENET_PAYLOAD_O);*/
+    if (!(memcmp(&buf[ENET_PAYLOAD_O], arp_req_payload_prefix, sizeof(arp_req_payload_prefix)) // ARP request
+            || memcmp(&buf[ENET_ARP_TPA_O], my_ip, sizeof(my_ip)))) {  // for me
+        //ARP request for me. Build reply.
+        // Ethernet packet addresses:
+        memcpy(&buf[ENET_DMAC_O], &buf[ENET_SMAC_O], 6);    // Back to sender
+        memcpy(&buf[ENET_SMAC_O], my_mac, 6);   // from me
+        // ARP protocol packet:
+        buf[ENET_ARP_OPER_O+1] = 0x02;  // we are replying
+        memcpy(&buf[ENET_ARP_THA_O], &buf[ENET_ARP_SHA_O], 6);  // to hardware address of request sender
+        memcpy(&buf[ENET_ARP_TPA_O], &buf[ENET_ARP_SPA_O], 4);  // to IP address of request sender
+        memcpy(&buf[ENET_ARP_SHA_O], my_mac, 6);  // from my hardware address
+        memcpy(&buf[ENET_ARP_SPA_O], my_ip, 4);  // and my IP address
+        //printf("ARP replying\r\n");
+        //print_hex((uint8_t *) buf, len);
+        eth.write((char *) buf, len);
+        eth.send();
+    };
+};
+
+void Snet::got_broadcast(uint8_t *buf, int len) {
+#if 0
+    printf("Broadcast from: %02x:%02x:%02x:%02x:%02x:%02x type %02x%02x count %d\r\n",
+            buf[ENET_SMAC_O+0], buf[ENET_SMAC_O+1],
+            buf[ENET_SMAC_O+2], buf[ENET_SMAC_O+3],
+            buf[ENET_SMAC_O+4], buf[ENET_SMAC_O+5],
+            buf[ENET_ETHERTYPE_O+0], buf[ENET_ETHERTYPE_O+1],
+            enet_rx_int_cnt);
+#endif
+    // ARP request?
+    if (buf[ENET_ETHERTYPE_O+0] == 0x08 && buf[ENET_ETHERTYPE_O+1] == 0x06)
+        handle_arp_request(buf, len);
+};
+
+void Snet::got_unicast(uint8_t *buf, int len) {
+    if (memcmp(&buf[ENET_ETHERTYPE_O], ipEtherType, 2)) return; // IP packets only from this point
+//    printf("Unicast from: %02x:%02x:%02x:%02x:%02x:%02x %d\r\n",
+//            buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], enet_rx_int_cnt);
+    memcpy(correspondent_mac, &buf[ENET_SMAC_O], sizeof(correspondent_mac));
+    eth.read((char *) &buf[ENET_PAYLOAD_O], len-ENET_PAYLOAD_O); // Read in the whole rest of the packet
+    interpret_inet_packet(buf, len);
+}
+
+int Snet::rx_and_process_one_packet() {
+#if 0
+    // if the damn Ethernet worked correctly:
+    uint8_t buf[0x600];
+#else
+    uint8_t buf[750+6+6+2];   // Experimentally-derived maximum packet size is 750 at the IP layer
+#endif
+    int rv = 0;
+    int len;
+    
+    while ((len = eth.receive()) > 0) {
+        eth.read((char *) buf, ENET_PAYLOAD_O);  // destination MAC, source MAC, EtherType, lengcode
+        enet_rx_cnt++;
+        if (memcmp(&buf[ENET_DMAC_O], my_mac, 6) == 0) {
+            got_unicast(buf, len);
+            rv = 1;
+        } else if (memcmp(&buf[ENET_DMAC_O], broadcast_mac, 6) == 0) {
+            got_broadcast(buf, len);
+            rv = 2;
+        }
+    }
+    return rv;
+}
+