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

snet.cpp

Committer:
altasoul
Date:
2015-03-04
Revision:
0:6df0a6ed91d4
Child:
1:9c211ac06a12

File content as of revision 0:6df0a6ed91d4:

#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;
}