?? networkstack.c
字號(hào):
/* $Id: networkstack.c,v 1.45 2005/10/30 21:06:14 simimeie Exp $ * Basic Network Stack. Handles ARP / IP. * * I need to give some credits here: * Most of the code here is basically a port of Dave Clausen's assembler * code, at the time of writing this available under the GPL from * http://www.dclausen.net/projects/avr_ethernet/index.html * There is a lot of code in C out on the internet for using a NE2000 from * an AVR, but his assembler code was way better commented, documented and * easier to understand than anything I could find in C. */ #define BV _BV#include <avr/io.h>#include <avr/delay.h>#include <string.h>#include "networkstack.h"#include "ledmodule.h"#include "debugconsole.h"#include "dcf77.h"#include "timers.h"#include "clockface.h"#ifdef NET_NOUSELESSCRAP#define NET_NOTCPRESET#define NET_NODPORTUNREACH#endif/* Network Configuration. This gets read from EEPROM, set it in eepromdata.h */uint8_t net_ip[4];#if 0uint8_t net_mask[4];uint8_t net_gate[4];#endifuint8_t net_mac[6];uint8_t net_rconpass[9];uint8_t net_packet[1518];uint16_t net_recvdbytes;#ifdef NETWORKSTATSuint32_t net_rxbytes; /* Received Bytes */uint32_t net_txbytes; /* Transmitted Bytes */uint32_t net_pings; /* ICMP Pings */uint32_t net_ntpqs; /* NTP Queries */uint32_t net_rcons; /* Remote Control Commands */#endif/* On our board, address pin 15 on the atmel goes to address pin 9 of the ISA * bus. * So every access to a memory address above 0x8000 goes to the ISA bus, and * accesses I/O Port (0x200 + (address % 0x200)) there. * So if your NE2000 is on I/O 0x300, set this to 0x8100 or 0x8300 * or 0x8500 or ... */#define NE2KBASE 0x8300/* Register Offsets */#define NECMDR 0x00 /* Command Register (page *)*/#define NEPSTA 0x01 /* Page Start Register (page 0 = w, page 2 = r) */#define NEPAR0 0x01 /* Physical Address Register Byte 0 (page 1 = rw) */#define NEPSTO 0x02 /* Page Stop Register (page 0 = w, page 2 = r) */#define NEBNRY 0x03 /* Boundary Register (page 0 = rw) */#define NETPSR 0x04 /* Transmit Page Start Register (page 0 = w) */#define NETBCR0 0x05 /* Transmit Byte Count Register 0 (page 0 = w) */#define NETBCR1 0x06 /* Transmit Byte Count Register 1 (page 0 = w) */#define NEISR 0x07 /* Interrupt Status Register */#define NECURR 0x07 /* Current Page Register (page 1 = rw) */#define NERSAR0 0x08 /* Remote Start Address Register 0 (page 0 = w) */#define NERSAR1 0x09 /* Remote Start Address Register 1 (page 0 = w) */#define NERBCR0 0x0A /* Remote Byte Count Register 0 (page 0 = w) */#define NERBCR1 0x0B /* Remote Byte Count Register 1 (page 0 = w) */#define NERCR 0x0C /* Receive Control Register */#define NETCR 0x0D /* Transmission Control Register */#define NEDCR 0x0E /* Data Control Register */#define NEIMR 0x0F /* Interrupt Mask Register */#define NERDMA 0x10 /* Remote DMA */#define NERESET 0x1f /* Well guess, what does the "reset" register do? *//* Bit defines *//* For the command register */#define CMDR_STOP 0x01 /* Stop (Reset) NIC */#define CMDR_START 0x02 /* Start NIC */#define CMDR_TRANSMIT 0x04 /* Must be 1 to transmit packet */#define CMDR_DMAREAD 0x08 /* remote DMA read */#define CMDR_DMAWRITE 0x10 /* remote DMA write */#define CMDR_NODMA 0x20 /* abort/complete remote DMA */#define CMDR_PAGE0 0x00 /* select register page 0 */#define CMDR_PAGE1 0x40 /* select register page 1 */#define CMDR_PAGE2 0x80 /* select register page 2 *//* For the Receive Control Register */#define RCR_BCAST 0x04#define RCR_MCAST 0x08#define RCR_PROMISCUOUS 0x10#define RCR_MONITOR 0x20/* For the Data Control Register */#define DCR_BYTEDMA 0x00#define DCR_WORDDMA 0x01#define DCR_NOLPBK 0x08#define DCR_FIFO2 0x00#define DCR_FIFO4 0x20#define DCR_FIFO8 0x40#define DCR_FIFO12 0x60/* For the Transmission Control Register */#define TCR_NOLPBK 0x00#define TCR_INTLPBK 0x02#define TCR_EXTLPBK 0x04#define TCR_EXTLPBK2 0x06/* Address defines * These defines should be correct for most ne2k compatibles. * It seems they usually have RAM available between 0x4000 and 0x8000. * These values are page numbers, with a page being 256 (0x100 bytes). */#define RXSTART 0x46 /* Start of RX buffers */#define RXSTOP 0x5f /* End of RX buffers */#define TXSTART 0x40 /* Start of TX buffers */static void isareset(void) { uint16_t i; /* PortD Pin 4 is ISA RESET */ DDRD |= BV(PD4); PORTD |= BV(PD4); for (i=0; i<20000; i++) { _delay_loop_1(250); } PORTD &= (uint8_t)~BV(PD4); for (i=0; i<20000; i++) { _delay_loop_1(250); }}static void writene2kreg(uint8_t nr, uint8_t val) { *((volatile uint8_t *)(NE2KBASE + nr)) = val;}static uint8_t readne2kreg(uint8_t nr) { return *((volatile uint8_t *)(NE2KBASE + nr));}void net_sendpacket(uint8_t * packet, uint16_t len) { uint16_t i; if (len < 0x40) { len = 0x40; } i = 0; /* If there is still a packet in transmission, wait until it's done! */ while ((i < 50000) && (readne2kreg(NECMDR) & CMDR_TRANSMIT)) { i++; } /* Abort any currently running "DMA" operations */ writene2kreg(NECMDR, CMDR_PAGE0 | CMDR_START | CMDR_NODMA); writene2kreg(NERBCR0, len & 0xff); writene2kreg(NERBCR1, len >> 8); writene2kreg(NERSAR0, 0x00); writene2kreg(NERSAR1, TXSTART); writene2kreg(NECMDR, CMDR_PAGE0 | CMDR_START | CMDR_DMAWRITE); for (i = 0; i < len; i++) { writene2kreg(NERDMA, packet[i]); } /* Wait for something here? */ writene2kreg(NECMDR, CMDR_PAGE0 | CMDR_START | CMDR_NODMA); writene2kreg(NETBCR0, len & 0xff); writene2kreg(NETBCR1, len >> 8); writene2kreg(NETPSR, TXSTART); writene2kreg(NECMDR, CMDR_PAGE0 | CMDR_START | CMDR_TRANSMIT); led_statusleds |= led_status_nettx;#ifdef NETWORKSTATS net_txbytes += len;#endif}uint16_t net_receivepacket(void) { uint8_t curr, bnry; net_recvdbytes = 0; /* goto register page 1 */ writene2kreg(NECMDR, CMDR_PAGE1 | CMDR_START | CMDR_NODMA); /* read the CURRent pointer */ curr = readne2kreg(NECURR); /* goto register page 0 */ writene2kreg(NECMDR, CMDR_PAGE0 | CMDR_START | CMDR_NODMA); /* read the boundary pointer */ bnry = readne2kreg(NEBNRY) + 1; if (bnry > RXSTOP - 1) { bnry = RXSTART; } if (bnry != curr) { /* data available - read it */ uint16_t i;#if 0 debugconsole_printtext("P:"); debugconsole_printhex8(curr); debugconsole_printtext(","); debugconsole_printhex8(bnry); debugconsole_printtext("->");#endif /* i don't know how many bytes i intend to read, so just set * this to the maximum */ writene2kreg(NERBCR0, 0xff); writene2kreg(NERBCR1, 0xff); writene2kreg(NERSAR0, 0); /* low byte of start address (0) */ writene2kreg(NERSAR1, bnry); /* high byte of start address (BNRY) */ /* begin the dma read */ writene2kreg(NECMDR, CMDR_PAGE0 | CMDR_START | CMDR_DMAREAD); readne2kreg(NERDMA); /* Status flags, throw away */ bnry = readne2kreg(NERDMA) - 1; /* next-pointer */ if (bnry < RXSTART) { bnry = RXSTOP - 1; } net_recvdbytes = readne2kreg(NERDMA); /* receive byte count low */ net_recvdbytes |= (((uint16_t)readne2kreg(NERDMA)) << 8); /* receive byte count high */#if 0 debugconsole_printhex8(bnry); debugconsole_printtext(" "); debugconsole_printhex8(net_recvdbytes >> 8); debugconsole_printhex8(net_recvdbytes & 0xff); debugconsole_printtext("\r\n");#endif if (net_recvdbytes > 1518) { net_recvdbytes = 1518; } for (i = 0; i < net_recvdbytes; i++) { net_packet[i] = readne2kreg(NERDMA);#if 0 debugconsole_printhex8(net_packet[i]); if ((i % 20) == 0) { debugconsole_printtext("\r\n"); }#endif } /* debugconsole_printtext("\r\n"); */ writene2kreg(NECMDR, CMDR_PAGE0 | CMDR_START | CMDR_NODMA); /* write updated bnry pointer */ writene2kreg(NEBNRY, bnry); led_statusleds |= led_status_netrx;#ifdef NETWORKSTATS net_rxbytes += net_recvdbytes;#endif } return net_recvdbytes;}static void swapdestandsrceth(void) { uint8_t c; for (c = 0; c < 6; c++) { /* set dst to src, and src to our mac */ net_packet[c] = net_packet[c+6]; net_packet[c+6] = net_mac[c]; }}static void swapdestandsrcarp(void) { uint8_t c; for (c = 0; c < 4; c++) { net_packet[c+38] = net_packet[c+28]; net_packet[c+28] = net_ip[c]; } for (c = 0; c < 6; c++) { net_packet[c+32] = net_packet[c+22]; net_packet[c+22] = net_mac[c]; }}static void swapdestandsrcip(void) { uint8_t c; for (c = 0; c < 4; c++) { net_packet[c+30] = net_packet[c+26]; net_packet[c+26] = net_ip[c]; }}void net_handlearp(void) { /* 14 - 15 hardware type * 16 - 17 protocol * 18 hardware address size * 19 protocol address size * 20 - 21 type (0x0001 = request, 0x0002 = reply) * 22 - 27 sender hw address * 28 - 31 sender ip address * 32 - 37 target hw address * 38 - 41 target ip address */ if ((net_packet[14] == 0x00) /* Hardware type */ && (net_packet[15] == 0x01) && (net_packet[16] == 0x08) /* Protocol */ && (net_packet[17] == 0x00) && (net_packet[18] == 0x06) /* Hardware size */ && (net_packet[19] == 0x04) /* Protocol size */ && (net_packet[20] == 0x00) /* ARP Request */ && (net_packet[21] == 0x01) ) { if (memcmp(&net_packet[38], net_ip, 4)) { /* Not for us */ return; } /* OK this is a request for our IP. Send a reply. */ /* We just rewrite the existing packet */ /* It's now an ARP REPLY, not a request */ net_packet[21] = 0x02; swapdestandsrceth(); swapdestandsrcarp(); net_sendpacket(net_packet, 0x40); }}uint16_t net_calcipchecksum(uint8_t * packet, uint8_t end) { uint32_t tmp = 0; uint16_t * pp; uint8_t i; pp = (uint16_t *)packet; for (i = end; i > 1; i-=2) { tmp += *pp; pp++; } if (i > 0) { tmp += (*pp & 0xff00); } while ((tmp >> 16) > 0) { tmp = (tmp >> 16) + (tmp & 0xffffUL); } /* No idea why it works with the byte order swapped? * anyways, you will have to swap the byte order of the result! */ return (uint16_t)~tmp;}static void net_handleicmp(uint8_t hlen) { /* ICMP: IP Header + type (1 byte) + code (1 byte) + checksum (2 bytes) * + parameters (0-4 bytes) + data * type 8 code 0: echo request * type 0 code 0: echo reply * type 11 code 0: TTL exceeded */ if ((net_packet[hlen] == 8) && (net_packet[hlen+1] == 0)) { /* We have an echo request - send it back almost unmodified? */ uint16_t cs; if (net_packet[16] > 1) { /* We don't do more than 511 bytes */ return; } net_packet[hlen] = 0; swapdestandsrceth(); swapdestandsrcip(); net_packet[24] = net_packet[25] = 0; cs = net_calcipchecksum(&net_packet[14], (hlen - 14)); net_packet[24] = cs & 0xff; net_packet[25] = cs >> 8; net_packet[hlen+2] = net_packet[hlen+3] = 0; cs = net_calcipchecksum(&net_packet[hlen], (net_recvdbytes - hlen - 4)); net_packet[hlen+2] = cs & 0xff; net_packet[hlen+3] = cs >> 8; net_sendpacket(net_packet, net_recvdbytes - 4); led_statusleds |= led_status_netping;#ifdef NETWORKSTATS
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -