From 62db6515c9fcfbbca36db162322e28af44fa4c96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Fr=C3=B6schle?= Date: Tue, 24 Dec 2013 08:23:01 +0000 Subject: [PATCH] reformatted sources, added start of bootp protocol implementation --- Makefile | 1 + include/arp.h | 198 +++++------ include/bootp.h | 58 +++ net/arp.c | 924 ++++++++++++++++++++++++------------------------ net/bootp.c | 205 +++++++++-- net/fec.c | 128 ++++--- net/fecbd.c | 452 +++++++++++------------ net/ip.c | 586 +++++++++++++++--------------- 8 files changed, 1383 insertions(+), 1169 deletions(-) create mode 100644 include/bootp.h diff --git a/Makefile b/Makefile index a4ae3ed..cf95730 100644 --- a/Makefile +++ b/Makefile @@ -100,6 +100,7 @@ CSRCS= \ ip.c \ udp.c \ arp.c \ + bootp.c \ \ basflash.c \ basflash_start.c diff --git a/include/arp.h b/include/arp.h index d4f78e9..9f8a846 100644 --- a/include/arp.h +++ b/include/arp.h @@ -1,99 +1,99 @@ -/* - * File: arp.h - * Purpose: ARP definitions. - * - * Notes: - */ - -#ifndef _ARP_H -#define _ARP_H - -/********************************************************************/ - -/* - * This data definition is defined for Ethernet only! - */ -typedef struct -{ - uint16_t ar_hrd; - uint16_t ar_pro; - uint8_t ar_hln; - uint8_t ar_pln; - uint16_t opcode; - uint8_t ar_sha[6]; /* ethernet hw address */ - uint8_t ar_spa[4]; /* ip address */ - uint8_t ar_tha[6]; /* ethernet hw address */ - uint8_t ar_tpa[4]; /* ip address */ -} arp_frame_hdr; - -#define ARP_HDR_LEN sizeof(arp_frame_hdr) - -/* - * ARP table entry definition. Note that this table only designed - * with Ethernet and IP in mind. - */ -#define MAX_HWA_SIZE (6) /* 6 is enough for Ethernet address */ -#define MAX_PA_SIZE (4) /* 4 is enough for Protocol address */ -typedef struct -{ - uint16_t protocol; - uint8_t hwa_size; - uint8_t hwa[MAX_HWA_SIZE]; - uint8_t pa_size; - uint8_t pa[MAX_PA_SIZE]; - int longevity; -} ARPENTRY; -#define MAX_ARP_ENTRY (10) - -typedef struct -{ - unsigned int tab_size; - ARPENTRY table[MAX_ARP_ENTRY]; -} ARP_INFO; - -#define ARP_ENTRY_EMPTY (0) -#define ARP_ENTRY_PERM (1) -#define ARP_ENTRY_TEMP (2) - - -#define ETHERNET (1) -#define ARP_REQUEST (1) -#define ARP_REPLY (2) - -#define ARP_TIMEOUT (1) /* Timeout in seconds */ - -/* Protocol Header information */ -#define ARP_HDR_OFFSET ETH_HDR_LEN - -/********************************************************************/ - -uint8_t * -arp_get_mypa (void); - -uint8_t * -arp_get_myha (void); - -uint8_t * -arp_get_broadcast (void); - -void -arp_merge (ARP_INFO *, uint16_t, int, uint8_t *, int, uint8_t *, int); - -void -arp_remove (ARP_INFO *, uint16_t, uint8_t *, uint8_t *); - -void -arp_request (NIF *, uint8_t *); - -void -arp_handler (NIF *, NBUF *); - -uint8_t * -arp_resolve (NIF *, uint16_t, uint8_t *); - -void -arp_init (ARP_INFO *); - -/********************************************************************/ - -#endif /* _ARP_H */ +/* + * File: arp.h + * Purpose: ARP definitions. + * + * Notes: + */ + +#ifndef _ARP_H +#define _ARP_H + +/********************************************************************/ + +/* + * This data definition is defined for Ethernet only! + */ +typedef struct +{ + uint16_t ar_hrd; + uint16_t ar_pro; + uint8_t ar_hln; + uint8_t ar_pln; + uint16_t opcode; + uint8_t ar_sha[6]; /* ethernet hw address */ + uint8_t ar_spa[4]; /* ip address */ + uint8_t ar_tha[6]; /* ethernet hw address */ + uint8_t ar_tpa[4]; /* ip address */ +} arp_frame_hdr; + +#define ARP_HDR_LEN sizeof(arp_frame_hdr) + +/* + * ARP table entry definition. Note that this table only designed + * with Ethernet and IP in mind. + */ +#define MAX_HWA_SIZE (6) /* 6 is enough for Ethernet address */ +#define MAX_PA_SIZE (4) /* 4 is enough for Protocol address */ +typedef struct +{ + uint16_t protocol; + uint8_t hwa_size; + uint8_t hwa[MAX_HWA_SIZE]; + uint8_t pa_size; + uint8_t pa[MAX_PA_SIZE]; + int longevity; +} ARPENTRY; +#define MAX_ARP_ENTRY (10) + +typedef struct +{ + unsigned int tab_size; + ARPENTRY table[MAX_ARP_ENTRY]; +} ARP_INFO; + +#define ARP_ENTRY_EMPTY (0) +#define ARP_ENTRY_PERM (1) +#define ARP_ENTRY_TEMP (2) + + +#define ETHERNET (1) +#define ARP_REQUEST (1) +#define ARP_REPLY (2) + +#define ARP_TIMEOUT (1) /* Timeout in seconds */ + +/* Protocol Header information */ +#define ARP_HDR_OFFSET ETH_HDR_LEN + +/********************************************************************/ + +uint8_t * +arp_get_mypa (void); + +uint8_t * +arp_get_myha (void); + +uint8_t * +arp_get_broadcast (void); + +void +arp_merge (ARP_INFO *, uint16_t, int, uint8_t *, int, uint8_t *, int); + +void +arp_remove (ARP_INFO *, uint16_t, uint8_t *, uint8_t *); + +void +arp_request (NIF *, uint8_t *); + +void +arp_handler (NIF *, NBUF *); + +uint8_t * +arp_resolve (NIF *, uint16_t, uint8_t *); + +void +arp_init (ARP_INFO *); + +/********************************************************************/ + +#endif /* _ARP_H */ diff --git a/include/bootp.h b/include/bootp.h new file mode 100644 index 0000000..08eaa17 --- /dev/null +++ b/include/bootp.h @@ -0,0 +1,58 @@ +/* + * File: bootp.h + * Purpose: BOOTP definitions. + * + * Notes: + */ + +#ifndef _BOOTP_H_ +#define _BOOTP_H_ + +/********************************************************************/ + +/* + * This data definition is defined for Ethernet only! + */ +typedef struct +{ + uint8_t type; /* bootp operation type */ + uint8_t htype; /* hardware type */ + uint8_t hlen; /* hardware address length */ + uint8_t hops; /* hops */ + uint32_t xid; /* transaction identifier */ + uint16_t secs; /* seconds since trying to boot */ + uint16_t flags; /* only broadcast flag in use */ + uint32_t cl_addr; /* client ip address. Set to all 0 on request */ + uint32_t yi_addr; /* this field contains the new IP */ + uint32_t gi_addr; /* gateway address */ + uint8_t ch_addr[16]; /* client hw address */ + uint8_t sname[64]; /* server name */ + uint8_t file[128]; /* name of bootfile */ + uint8_t vend[64]; /* vendor specific (see below) */ +} bootp_frame_hdr; + +#define BOOTP_HDR_LEN sizeof(bootp_frame_hdr) + +/* possible values for type field */ +#define BOOTP_TYPE_BOOTREQUEST 1 +#define BOOTP_TYPE_BOOTREPLY 2 + +/* values for hardware type - we only use ethernet */ +#define BOOTP_HTYPE_ETHERNET 1 + +/* values for hlen - again only ethernet defined */ +#define BOOTP_HLEN_ETHERNET 6 + +/* values for flags - only broadcast flag in use */ +#define BOOTP_FLAGS_BROADCAST 1 + +#define BOOTP_TIMEOUT (1) /* Timeout in seconds */ + +/* Protocol Header information */ +#define BOOTP_HDR_OFFSET ETH_HDR_LEN + +extern void bootp_request(NIF *, uint8_t *); +extern void bootp_handler(NIF *, NBUF *); +//extern void bootp_init(BOOTP_INFO *); + +#endif /* _BOOTP_H_ */ diff --git a/net/arp.c b/net/arp.c index 93acd4f..07072d6 100644 --- a/net/arp.c +++ b/net/arp.c @@ -1,462 +1,462 @@ -/* - * File: arp.c - * Purpose: Address Resolution Protocol routines. - * - * Notes: - */ - -#include "net.h" -#include -#include - -#define TIMER_NETWORK 0 - -static uint8_t *arp_find_pair(ARP_INFO *arptab, uint16_t protocol, uint8_t *hwa, uint8_t *pa) -{ - /* - * This function searches through the ARP table for the - * specified or address pair. - * If it is found, then a a pointer to the non-specified - * address is returned. Otherwise NULL is returned. - * If you pass in then you get out. - * If you pass in then you get out. - */ - int slot, i, match = false; - uint8_t *rvalue; - - if (((hwa == 0) && (pa == 0)) || (arptab == 0)) - return NULL; - - rvalue = NULL; - - /* - * Check each protocol address for a match - */ - for (slot = 0; slot < arptab->tab_size; slot++) - { - if ((arptab->table[slot].longevity != ARP_ENTRY_EMPTY) && - (arptab->table[slot].protocol == protocol)) - { - match = true; - if (hwa != 0) - { - /* - * Check the Hardware Address field - */ - rvalue = &arptab->table[slot].pa[0]; - for (i = 0; i < arptab->table[slot].hwa_size; i++) - { - if (arptab->table[slot].hwa[i] != hwa[i]) - { - match = false; - break; - } - } - } - else - { - /* - * Check the Protocol Address field - */ - rvalue = &arptab->table[slot].hwa[0]; - for (i = 0; i < arptab->table[slot].pa_size; i++) - { - if (arptab->table[slot].pa[i] != pa[i]) - { - match = false; - break; - } - } - } - if (match) - { - break; - } - } - } - - if (match) - return rvalue; - else - return NULL; -} - -void arp_merge(ARP_INFO *arptab, uint16_t protocol, int hwa_size, uint8_t *hwa, - int pa_size, uint8_t *pa, int longevity) -{ - /* - * This function merges an entry into the ARP table. If - * either piece is NULL, the function exits, otherwise - * the entry is merged or added, provided there is space. - */ - int i, slot; - uint8_t *ta; - - if ((hwa == NULL) || (pa == NULL) || (arptab == NULL) || - ((longevity != ARP_ENTRY_TEMP) && - (longevity != ARP_ENTRY_PERM))) - { - return; - } - - /* First search ARP table for existing entry */ - if ((ta = arp_find_pair(arptab,protocol,NULL,pa)) != 0) - { - /* Update hardware address */ - for (i = 0; i < hwa_size; i++) - ta[i] = hwa[i]; - return; - } - - /* Next try to find an empty slot */ - slot = -1; - for (i = 0; i < MAX_ARP_ENTRY; i++) - { - if (arptab->table[i].longevity == ARP_ENTRY_EMPTY) - { - slot = i; - break; - } - } - - /* if no empty slot was found, pick a temp slot */ - if (slot == -1) - { - for (i = 0; i < MAX_ARP_ENTRY; i++) - { - if (arptab->table[i].longevity == ARP_ENTRY_TEMP) - { - slot = i; - break; - } - } - } - - /* if after all this, still no slot found, add in last slot */ - if (slot == -1) - slot = (MAX_ARP_ENTRY -1); - - /* add the entry into the slot */ - arptab->table[slot].protocol = protocol; - - arptab->table[slot].hwa_size = (uint8_t) hwa_size; - for (i = 0; i < hwa_size; i++) - arptab->table[slot].hwa[i] = hwa[i]; - - arptab->table[slot].pa_size = (uint8_t) pa_size; - for (i = 0; i < pa_size; i++) - arptab->table[slot].pa[i] = pa[i]; - - arptab->table[slot].longevity = longevity; -} - - -void arp_remove(ARP_INFO *arptab, uint16_t protocol, uint8_t *hwa, uint8_t *pa) -{ - /* - * This function removes an entry from the ARP table. The - * ARP table is searched according to the non-NULL address - * that is provided. - */ - int slot, i, match; - - if (((hwa == 0) && (pa == 0)) || (arptab == 0)) - return; - - /* check each hardware adress for a match */ - for (slot = 0; slot < arptab->tab_size; slot++) - { - if ((arptab->table[slot].longevity != ARP_ENTRY_EMPTY) && - (arptab->table[slot].protocol == protocol)) - { - match = true; - if (hwa != 0) - { - /* Check Hardware Address field */ - for (i = 0; i < arptab->table[slot].hwa_size; i++) - { - if (arptab->table[slot].hwa[i] != hwa[i]) - { - match = false; - break; - } - } - } - else - { - /* Check Protocol Address field */ - for (i = 0; i < arptab->table[slot].pa_size; i++) - { - if (arptab->table[slot].pa[i] != pa[i]) - { - match = false; - break; - } - } - } - if (match) - { - for (i = 0; i < arptab->table[slot].hwa_size; i++) - arptab->table[slot].hwa[i] = 0; - for (i = 0; i < arptab->table[slot].pa_size; i++) - arptab->table[slot].pa[i] = 0; - arptab->table[slot].longevity = ARP_ENTRY_EMPTY; - break; - } - } - } -} - -void arp_request(NIF *nif, uint8_t *pa) -{ - /* - * This function broadcasts an ARP request for the protocol - * address "pa" - */ - uint8_t *addr; - NBUF *pNbuf; - arp_frame_hdr *arpframe; - int i, result; - - pNbuf = nbuf_alloc(); - if (pNbuf == NULL) - { - #if defined(DEBUG_PRINT) - printf("ARP: arp_request couldn't allocate Tx buffer\n"); - #endif - return; - } - - arpframe = (arp_frame_hdr *)&pNbuf->data[ARP_HDR_OFFSET]; - - /* Build the ARP request packet */ - arpframe->ar_hrd = ETHERNET; - arpframe->ar_pro = ETH_FRM_IP; - arpframe->ar_hln = 6; - arpframe->ar_pln = 4; - arpframe->opcode = ARP_REQUEST; - - addr = &nif->hwa[0]; - for (i = 0; i < 6; i++) - arpframe->ar_sha[i] = addr[i]; - - addr = ip_get_myip(nif_get_protocol_info(nif,ETH_FRM_IP)); - for (i = 0; i < 4; i++) - arpframe->ar_spa[i] = addr[i]; - - for (i = 0; i < 6; i++) - arpframe->ar_tha[i] = 0x00; - - for (i = 0; i < 4; i++) - arpframe->ar_tpa[i] = pa[i]; - - pNbuf->length = ARP_HDR_LEN; - - /* Send the ARP request */ - result = nif->send(nif, nif->broadcast, nif->hwa, ETH_FRM_ARP, pNbuf); - - if (result == 0) - nbuf_free(pNbuf); -} - -static int arp_resolve_pa(NIF *nif, uint16_t protocol, uint8_t *pa, uint8_t **ha) -{ - /* - * This function accepts a pointer to a protocol address and - * searches the ARP table for a hardware address match. If no - * no match found, false is returned. - */ - ARP_INFO *arptab; - - if ((pa == NULL) || (nif == NULL) || (protocol == 0)) - return 0; - - arptab = nif_get_protocol_info (nif,ETH_FRM_ARP); - *ha = arp_find_pair(arptab,protocol,0,pa); - - if (*ha == NULL) - return 0; - else - return 1; -} - -uint8_t *arp_resolve(NIF *nif, uint16_t protocol, uint8_t *pa) -{ - int i; - uint8_t *hwa; - - /* - * Check to see if the necessary MAC-to-IP translation information - * is in table already - */ - if (arp_resolve_pa (nif, protocol, pa, &hwa)) - return hwa; - - /* - * Ok, it's not, so we need to try to obtain it by broadcasting - * an ARP request. Hopefully the desired host is listening and - * will respond with it's MAC address - */ - for (i = 0; i < 3; i++) - { - arp_request (nif, pa); - - timer_set_secs(TIMER_NETWORK, ARP_TIMEOUT); - while (timer_get_reference(TIMER_NETWORK)) - { - if (arp_resolve_pa (nif, protocol, pa, &hwa)) - return hwa; - } - } - - return NULL; -} - -void arp_init(ARP_INFO *arptab) -{ - int slot, i; - - arptab->tab_size = MAX_ARP_ENTRY; - for (slot = 0; slot < arptab->tab_size; slot++) - { - for (i = 0; i < MAX_HWA_SIZE; i++) - arptab->table[slot].hwa[i] = 0; - for (i = 0; i < MAX_PA_SIZE; i++) - arptab->table[slot].pa[i] = 0; - arptab->table[slot].longevity = ARP_ENTRY_EMPTY; - arptab->table[slot].hwa_size = 0; - arptab->table[slot].pa_size = 0; - } -} - -void arp_handler(NIF *nif, NBUF *pNbuf) -{ - /* - * ARP protocol handler - */ - uint8_t *addr; - ARP_INFO *arptab; - int longevity; - arp_frame_hdr *rx_arpframe, *tx_arpframe; - - arptab = nif_get_protocol_info(nif, ETH_FRM_ARP); - rx_arpframe = (arp_frame_hdr *) &pNbuf->data[pNbuf->offset]; - - /* - * Check for an appropriate ARP packet - */ - if ((pNbuf->length < ARP_HDR_LEN) || - (rx_arpframe->ar_hrd != ETHERNET) || - (rx_arpframe->ar_hln != 6) || - (rx_arpframe->ar_pro != ETH_FRM_IP) || - (rx_arpframe->ar_pln != 4)) - { - nbuf_free(pNbuf); - return; - } - - /* - * Check to see if it was addressed to me - if it was, keep this - * ARP entry in the table permanently; if not, mark it so that it - * can be displaced later if necessary - */ - addr = ip_get_myip(nif_get_protocol_info(nif,ETH_FRM_IP)); - if ((rx_arpframe->ar_tpa[0] == addr[0]) && - (rx_arpframe->ar_tpa[1] == addr[1]) && - (rx_arpframe->ar_tpa[2] == addr[2]) && - (rx_arpframe->ar_tpa[3] == addr[3]) ) - { - longevity = ARP_ENTRY_PERM; - } - else - longevity = ARP_ENTRY_TEMP; - - /* - * Add ARP info into the table - */ - arp_merge(arptab, - rx_arpframe->ar_pro, - rx_arpframe->ar_hln, - &rx_arpframe->ar_sha[0], - rx_arpframe->ar_pln, - &rx_arpframe->ar_spa[0], - longevity - ); - - switch (rx_arpframe->opcode) - { - case ARP_REQUEST: - /* - * Check to see if request is directed to me - */ - if ((rx_arpframe->ar_tpa[0] == addr[0]) && - (rx_arpframe->ar_tpa[1] == addr[1]) && - (rx_arpframe->ar_tpa[2] == addr[2]) && - (rx_arpframe->ar_tpa[3] == addr[3]) ) - { - /* - * Reuse the current network buffer to assemble an ARP reply - */ - tx_arpframe = (arp_frame_hdr *)&pNbuf->data[ARP_HDR_OFFSET]; - - /* - * Build new ARP frame from the received data - */ - tx_arpframe->ar_hrd = ETHERNET; - tx_arpframe->ar_pro = ETH_FRM_IP; - tx_arpframe->ar_hln = 6; - tx_arpframe->ar_pln = 4; - tx_arpframe->opcode = ARP_REPLY; - tx_arpframe->ar_tha[0] = rx_arpframe->ar_sha[0]; - tx_arpframe->ar_tha[1] = rx_arpframe->ar_sha[1]; - tx_arpframe->ar_tha[2] = rx_arpframe->ar_sha[2]; - tx_arpframe->ar_tha[3] = rx_arpframe->ar_sha[3]; - tx_arpframe->ar_tha[4] = rx_arpframe->ar_sha[4]; - tx_arpframe->ar_tha[5] = rx_arpframe->ar_sha[5]; - tx_arpframe->ar_tpa[0] = rx_arpframe->ar_spa[0]; - tx_arpframe->ar_tpa[1] = rx_arpframe->ar_spa[1]; - tx_arpframe->ar_tpa[2] = rx_arpframe->ar_spa[2]; - tx_arpframe->ar_tpa[3] = rx_arpframe->ar_spa[3]; - - /* - * Now copy in the new information - */ - addr = &nif->hwa[0]; - tx_arpframe->ar_sha[0] = addr[0]; - tx_arpframe->ar_sha[1] = addr[1]; - tx_arpframe->ar_sha[2] = addr[2]; - tx_arpframe->ar_sha[3] = addr[3]; - tx_arpframe->ar_sha[4] = addr[4]; - tx_arpframe->ar_sha[5] = addr[5]; - - addr = ip_get_myip(nif_get_protocol_info(nif,ETH_FRM_IP)); - tx_arpframe->ar_spa[0] = addr[0]; - tx_arpframe->ar_spa[1] = addr[1]; - tx_arpframe->ar_spa[2] = addr[2]; - tx_arpframe->ar_spa[3] = addr[3]; - - /* - * Save the length of my packet in the buffer structure - */ - pNbuf->length = ARP_HDR_LEN; - - nif->send(nif, - &tx_arpframe->ar_tha[0], - &tx_arpframe->ar_sha[0], - ETH_FRM_ARP, - pNbuf); - } - else - nbuf_free(pNbuf); - break; - case ARP_REPLY: - /* - * The ARP Reply case is already taken care of - */ - default: - nbuf_free(pNbuf); - break; - } - - return; -} +/* + * File: arp.c + * Purpose: Address Resolution Protocol routines. + * + * Notes: + */ + +#include "net.h" +#include +#include + +#define TIMER_NETWORK 0 + +static uint8_t *arp_find_pair(ARP_INFO *arptab, uint16_t protocol, uint8_t *hwa, uint8_t *pa) +{ + /* + * This function searches through the ARP table for the + * specified or address pair. + * If it is found, then a a pointer to the non-specified + * address is returned. Otherwise NULL is returned. + * If you pass in then you get out. + * If you pass in then you get out. + */ + int slot, i, match = false; + uint8_t *rvalue; + + if (((hwa == 0) && (pa == 0)) || (arptab == 0)) + return NULL; + + rvalue = NULL; + + /* + * Check each protocol address for a match + */ + for (slot = 0; slot < arptab->tab_size; slot++) + { + if ((arptab->table[slot].longevity != ARP_ENTRY_EMPTY) && + (arptab->table[slot].protocol == protocol)) + { + match = true; + if (hwa != 0) + { + /* + * Check the Hardware Address field + */ + rvalue = &arptab->table[slot].pa[0]; + for (i = 0; i < arptab->table[slot].hwa_size; i++) + { + if (arptab->table[slot].hwa[i] != hwa[i]) + { + match = false; + break; + } + } + } + else + { + /* + * Check the Protocol Address field + */ + rvalue = &arptab->table[slot].hwa[0]; + for (i = 0; i < arptab->table[slot].pa_size; i++) + { + if (arptab->table[slot].pa[i] != pa[i]) + { + match = false; + break; + } + } + } + if (match) + { + break; + } + } + } + + if (match) + return rvalue; + else + return NULL; +} + +void arp_merge(ARP_INFO *arptab, uint16_t protocol, int hwa_size, uint8_t *hwa, + int pa_size, uint8_t *pa, int longevity) +{ + /* + * This function merges an entry into the ARP table. If + * either piece is NULL, the function exits, otherwise + * the entry is merged or added, provided there is space. + */ + int i, slot; + uint8_t *ta; + + if ((hwa == NULL) || (pa == NULL) || (arptab == NULL) || + ((longevity != ARP_ENTRY_TEMP) && + (longevity != ARP_ENTRY_PERM))) + { + return; + } + + /* First search ARP table for existing entry */ + if ((ta = arp_find_pair(arptab,protocol,NULL,pa)) != 0) + { + /* Update hardware address */ + for (i = 0; i < hwa_size; i++) + ta[i] = hwa[i]; + return; + } + + /* Next try to find an empty slot */ + slot = -1; + for (i = 0; i < MAX_ARP_ENTRY; i++) + { + if (arptab->table[i].longevity == ARP_ENTRY_EMPTY) + { + slot = i; + break; + } + } + + /* if no empty slot was found, pick a temp slot */ + if (slot == -1) + { + for (i = 0; i < MAX_ARP_ENTRY; i++) + { + if (arptab->table[i].longevity == ARP_ENTRY_TEMP) + { + slot = i; + break; + } + } + } + + /* if after all this, still no slot found, add in last slot */ + if (slot == -1) + slot = (MAX_ARP_ENTRY - 1); + + /* add the entry into the slot */ + arptab->table[slot].protocol = protocol; + + arptab->table[slot].hwa_size = (uint8_t) hwa_size; + for (i = 0; i < hwa_size; i++) + arptab->table[slot].hwa[i] = hwa[i]; + + arptab->table[slot].pa_size = (uint8_t) pa_size; + for (i = 0; i < pa_size; i++) + arptab->table[slot].pa[i] = pa[i]; + + arptab->table[slot].longevity = longevity; +} + + +void arp_remove(ARP_INFO *arptab, uint16_t protocol, uint8_t *hwa, uint8_t *pa) +{ + /* + * This function removes an entry from the ARP table. The + * ARP table is searched according to the non-NULL address + * that is provided. + */ + int slot, i, match; + + if (((hwa == 0) && (pa == 0)) || (arptab == 0)) + return; + + /* check each hardware adress for a match */ + for (slot = 0; slot < arptab->tab_size; slot++) + { + if ((arptab->table[slot].longevity != ARP_ENTRY_EMPTY) && + (arptab->table[slot].protocol == protocol)) + { + match = true; + if (hwa != 0) + { + /* Check Hardware Address field */ + for (i = 0; i < arptab->table[slot].hwa_size; i++) + { + if (arptab->table[slot].hwa[i] != hwa[i]) + { + match = false; + break; + } + } + } + else + { + /* Check Protocol Address field */ + for (i = 0; i < arptab->table[slot].pa_size; i++) + { + if (arptab->table[slot].pa[i] != pa[i]) + { + match = false; + break; + } + } + } + if (match) + { + for (i = 0; i < arptab->table[slot].hwa_size; i++) + arptab->table[slot].hwa[i] = 0; + for (i = 0; i < arptab->table[slot].pa_size; i++) + arptab->table[slot].pa[i] = 0; + arptab->table[slot].longevity = ARP_ENTRY_EMPTY; + break; + } + } + } +} + +void arp_request(NIF *nif, uint8_t *pa) +{ + /* + * This function broadcasts an ARP request for the protocol + * address "pa" + */ + uint8_t *addr; + NBUF *pNbuf; + arp_frame_hdr *arpframe; + int i, result; + + pNbuf = nbuf_alloc(); + if (pNbuf == NULL) + { + #if defined(DEBUG_PRINT) + printf("ARP: arp_request couldn't allocate Tx buffer\n"); + #endif + return; + } + + arpframe = (arp_frame_hdr *)&pNbuf->data[ARP_HDR_OFFSET]; + + /* Build the ARP request packet */ + arpframe->ar_hrd = ETHERNET; + arpframe->ar_pro = ETH_FRM_IP; + arpframe->ar_hln = 6; + arpframe->ar_pln = 4; + arpframe->opcode = ARP_REQUEST; + + addr = &nif->hwa[0]; + for (i = 0; i < 6; i++) + arpframe->ar_sha[i] = addr[i]; + + addr = ip_get_myip(nif_get_protocol_info(nif,ETH_FRM_IP)); + for (i = 0; i < 4; i++) + arpframe->ar_spa[i] = addr[i]; + + for (i = 0; i < 6; i++) + arpframe->ar_tha[i] = 0x00; + + for (i = 0; i < 4; i++) + arpframe->ar_tpa[i] = pa[i]; + + pNbuf->length = ARP_HDR_LEN; + + /* Send the ARP request */ + result = nif->send(nif, nif->broadcast, nif->hwa, ETH_FRM_ARP, pNbuf); + + if (result == 0) + nbuf_free(pNbuf); +} + +static int arp_resolve_pa(NIF *nif, uint16_t protocol, uint8_t *pa, uint8_t **ha) +{ + /* + * This function accepts a pointer to a protocol address and + * searches the ARP table for a hardware address match. If no + * no match found, false is returned. + */ + ARP_INFO *arptab; + + if ((pa == NULL) || (nif == NULL) || (protocol == 0)) + return 0; + + arptab = nif_get_protocol_info (nif,ETH_FRM_ARP); + *ha = arp_find_pair(arptab,protocol,0,pa); + + if (*ha == NULL) + return 0; + else + return 1; +} + +uint8_t *arp_resolve(NIF *nif, uint16_t protocol, uint8_t *pa) +{ + int i; + uint8_t *hwa; + + /* + * Check to see if the necessary MAC-to-IP translation information + * is in table already + */ + if (arp_resolve_pa (nif, protocol, pa, &hwa)) + return hwa; + + /* + * Ok, it's not, so we need to try to obtain it by broadcasting + * an ARP request. Hopefully the desired host is listening and + * will respond with it's MAC address + */ + for (i = 0; i < 3; i++) + { + arp_request (nif, pa); + + timer_set_secs(TIMER_NETWORK, ARP_TIMEOUT); + while (timer_get_reference(TIMER_NETWORK)) + { + if (arp_resolve_pa (nif, protocol, pa, &hwa)) + return hwa; + } + } + + return NULL; +} + +void arp_init(ARP_INFO *arptab) +{ + int slot, i; + + arptab->tab_size = MAX_ARP_ENTRY; + for (slot = 0; slot < arptab->tab_size; slot++) + { + for (i = 0; i < MAX_HWA_SIZE; i++) + arptab->table[slot].hwa[i] = 0; + for (i = 0; i < MAX_PA_SIZE; i++) + arptab->table[slot].pa[i] = 0; + arptab->table[slot].longevity = ARP_ENTRY_EMPTY; + arptab->table[slot].hwa_size = 0; + arptab->table[slot].pa_size = 0; + } +} + +void arp_handler(NIF *nif, NBUF *pNbuf) +{ + /* + * ARP protocol handler + */ + uint8_t *addr; + ARP_INFO *arptab; + int longevity; + arp_frame_hdr *rx_arpframe, *tx_arpframe; + + arptab = nif_get_protocol_info(nif, ETH_FRM_ARP); + rx_arpframe = (arp_frame_hdr *) &pNbuf->data[pNbuf->offset]; + + /* + * Check for an appropriate ARP packet + */ + if ((pNbuf->length < ARP_HDR_LEN) || + (rx_arpframe->ar_hrd != ETHERNET) || + (rx_arpframe->ar_hln != 6) || + (rx_arpframe->ar_pro != ETH_FRM_IP) || + (rx_arpframe->ar_pln != 4)) + { + nbuf_free(pNbuf); + return; + } + + /* + * Check to see if it was addressed to me - if it was, keep this + * ARP entry in the table permanently; if not, mark it so that it + * can be displaced later if necessary + */ + addr = ip_get_myip(nif_get_protocol_info(nif,ETH_FRM_IP)); + if ((rx_arpframe->ar_tpa[0] == addr[0]) && + (rx_arpframe->ar_tpa[1] == addr[1]) && + (rx_arpframe->ar_tpa[2] == addr[2]) && + (rx_arpframe->ar_tpa[3] == addr[3]) ) + { + longevity = ARP_ENTRY_PERM; + } + else + longevity = ARP_ENTRY_TEMP; + + /* + * Add ARP info into the table + */ + arp_merge(arptab, + rx_arpframe->ar_pro, + rx_arpframe->ar_hln, + &rx_arpframe->ar_sha[0], + rx_arpframe->ar_pln, + &rx_arpframe->ar_spa[0], + longevity + ); + + switch (rx_arpframe->opcode) + { + case ARP_REQUEST: + /* + * Check to see if request is directed to me + */ + if ((rx_arpframe->ar_tpa[0] == addr[0]) && + (rx_arpframe->ar_tpa[1] == addr[1]) && + (rx_arpframe->ar_tpa[2] == addr[2]) && + (rx_arpframe->ar_tpa[3] == addr[3]) ) + { + /* + * Reuse the current network buffer to assemble an ARP reply + */ + tx_arpframe = (arp_frame_hdr *)&pNbuf->data[ARP_HDR_OFFSET]; + + /* + * Build new ARP frame from the received data + */ + tx_arpframe->ar_hrd = ETHERNET; + tx_arpframe->ar_pro = ETH_FRM_IP; + tx_arpframe->ar_hln = 6; + tx_arpframe->ar_pln = 4; + tx_arpframe->opcode = ARP_REPLY; + tx_arpframe->ar_tha[0] = rx_arpframe->ar_sha[0]; + tx_arpframe->ar_tha[1] = rx_arpframe->ar_sha[1]; + tx_arpframe->ar_tha[2] = rx_arpframe->ar_sha[2]; + tx_arpframe->ar_tha[3] = rx_arpframe->ar_sha[3]; + tx_arpframe->ar_tha[4] = rx_arpframe->ar_sha[4]; + tx_arpframe->ar_tha[5] = rx_arpframe->ar_sha[5]; + tx_arpframe->ar_tpa[0] = rx_arpframe->ar_spa[0]; + tx_arpframe->ar_tpa[1] = rx_arpframe->ar_spa[1]; + tx_arpframe->ar_tpa[2] = rx_arpframe->ar_spa[2]; + tx_arpframe->ar_tpa[3] = rx_arpframe->ar_spa[3]; + + /* + * Now copy in the new information + */ + addr = &nif->hwa[0]; + tx_arpframe->ar_sha[0] = addr[0]; + tx_arpframe->ar_sha[1] = addr[1]; + tx_arpframe->ar_sha[2] = addr[2]; + tx_arpframe->ar_sha[3] = addr[3]; + tx_arpframe->ar_sha[4] = addr[4]; + tx_arpframe->ar_sha[5] = addr[5]; + + addr = ip_get_myip(nif_get_protocol_info(nif,ETH_FRM_IP)); + tx_arpframe->ar_spa[0] = addr[0]; + tx_arpframe->ar_spa[1] = addr[1]; + tx_arpframe->ar_spa[2] = addr[2]; + tx_arpframe->ar_spa[3] = addr[3]; + + /* + * Save the length of my packet in the buffer structure + */ + pNbuf->length = ARP_HDR_LEN; + + nif->send(nif, + &tx_arpframe->ar_tha[0], + &tx_arpframe->ar_sha[0], + ETH_FRM_ARP, + pNbuf); + } + else + nbuf_free(pNbuf); + break; + case ARP_REPLY: + /* + * The ARP Reply case is already taken care of + */ + default: + nbuf_free(pNbuf); + break; + } + + return; +} diff --git a/net/bootp.c b/net/bootp.c index b15eab3..8d9b5b8 100644 --- a/net/bootp.c +++ b/net/bootp.c @@ -1,33 +1,190 @@ -#include "bas_types.h" -#include -#include - -static bool bootp_initialized = false; - /* - * bootp client state + * File: arp.c + * Purpose: Address Resolution Protocol routines. + * + * Notes: */ -struct bootp_client -{ - uint8_t state; - uint8_t mode; - uint8_t socket_handle; - uint16_t timer_handle; - uint16_t boot_secs; -}; +#include "net.h" +#include "bootp.h" +#include +#include -static struct bootp_client client; +#define TIMER_NETWORK 0 -int bootpc_init(int mode) +void bootp_request(NIF *nif, uint8_t *pa) { - if (bootp_initialized) - { - return true; - } - /* - * get socket handle + * This function broadcasts a BOOTP request for the protocol + * address "pa" */ - client.socket_handle = udp_getsocket + uint8_t *addr; + NBUF *pNbuf; + bootp_frame_hdr *bootpframe; + int i, result; + pNbuf = nbuf_alloc(); + if (pNbuf == NULL) + { + #if defined(DEBUG_PRINT) + xprintf("%s: arp_request couldn't allocate Tx buffer\r\n", __FUNCTION__); + #endif + return; + } + + bootpframe = (bootp_frame_hdr *) &pNbuf->data[BOOTP_HDR_OFFSET]; + + /* Build the BOOTP request packet */ + bootpframe->type = BOOTP_TYPE_BOOTREQUEST; + bootpframe->htype = BOOTP_HTYPE_ETHERNET; + bootpframe->hlen = BOOTP_HLEN_ETHERNET; + bootpframe->hops = 0; + bootpframe->xid = 0x1234; + bootpframe->secs = 1; + bootpframe->flags = BOOTP_FLAGS_BROADCAST; + bootpframe->cl_addr = 0x0; + bootpframe->yi_addr = 0x0; + bootpframe->gi_addr = 0x0; + + addr = &nif->hwa[0]; + for (i = 0; i < 6; i++) + bootpframe->ch_addr[i] = addr[i]; + + pNbuf->length = BOOTP_HDR_LEN; + + /* Send the BOOTP request */ + result = nif->send(nif, nif->broadcast, nif->hwa, ETH_FRM_IP, pNbuf); + + if (result == 0) + nbuf_free(pNbuf); +} + +void bootp_handler(NIF *nif, NBUF *pNbuf) +{ + /* + * ARP protocol handler + */ + uint8_t *addr; + bootp_frame_hdr *rx_bootpframe, *tx_bootpframe; + + rx_bootpframe = (bootp_frame_hdr *) &pNbuf->data[pNbuf->offset]; + +#ifdef _NOT_USED_ + /* + * Check for an appropriate ARP packet + */ + if ((pNbuf->length < ARP_HDR_LEN) || + (rx_arpframe->ar_hrd != ETHERNET) || + (rx_arpframe->ar_hln != 6) || + (rx_arpframe->ar_pro != ETH_FRM_IP) || + (rx_arpframe->ar_pln != 4)) + { + nbuf_free(pNbuf); + return; + } + + /* + * Check to see if it was addressed to me - if it was, keep this + * ARP entry in the table permanently; if not, mark it so that it + * can be displaced later if necessary + */ + addr = ip_get_myip(nif_get_protocol_info(nif,ETH_FRM_IP)); + if ((rx_arpframe->ar_tpa[0] == addr[0]) && + (rx_arpframe->ar_tpa[1] == addr[1]) && + (rx_arpframe->ar_tpa[2] == addr[2]) && + (rx_arpframe->ar_tpa[3] == addr[3]) ) + { + longevity = ARP_ENTRY_PERM; + } + else + longevity = ARP_ENTRY_TEMP; + + /* + * Add ARP info into the table + */ + arp_merge(arptab, + rx_arpframe->ar_pro, + rx_arpframe->ar_hln, + &rx_arpframe->ar_sha[0], + rx_arpframe->ar_pln, + &rx_arpframe->ar_spa[0], + longevity + ); + + switch (rx_arpframe->opcode) + { + case ARP_REQUEST: + /* + * Check to see if request is directed to me + */ + if ((rx_arpframe->ar_tpa[0] == addr[0]) && + (rx_arpframe->ar_tpa[1] == addr[1]) && + (rx_arpframe->ar_tpa[2] == addr[2]) && + (rx_arpframe->ar_tpa[3] == addr[3]) ) + { + /* + * Reuse the current network buffer to assemble an ARP reply + */ + tx_arpframe = (arp_frame_hdr *)&pNbuf->data[ARP_HDR_OFFSET]; + + /* + * Build new ARP frame from the received data + */ + tx_arpframe->ar_hrd = ETHERNET; + tx_arpframe->ar_pro = ETH_FRM_IP; + tx_arpframe->ar_hln = 6; + tx_arpframe->ar_pln = 4; + tx_arpframe->opcode = ARP_REPLY; + tx_arpframe->ar_tha[0] = rx_arpframe->ar_sha[0]; + tx_arpframe->ar_tha[1] = rx_arpframe->ar_sha[1]; + tx_arpframe->ar_tha[2] = rx_arpframe->ar_sha[2]; + tx_arpframe->ar_tha[3] = rx_arpframe->ar_sha[3]; + tx_arpframe->ar_tha[4] = rx_arpframe->ar_sha[4]; + tx_arpframe->ar_tha[5] = rx_arpframe->ar_sha[5]; + tx_arpframe->ar_tpa[0] = rx_arpframe->ar_spa[0]; + tx_arpframe->ar_tpa[1] = rx_arpframe->ar_spa[1]; + tx_arpframe->ar_tpa[2] = rx_arpframe->ar_spa[2]; + tx_arpframe->ar_tpa[3] = rx_arpframe->ar_spa[3]; + + /* + * Now copy in the new information + */ + addr = &nif->hwa[0]; + tx_arpframe->ar_sha[0] = addr[0]; + tx_arpframe->ar_sha[1] = addr[1]; + tx_arpframe->ar_sha[2] = addr[2]; + tx_arpframe->ar_sha[3] = addr[3]; + tx_arpframe->ar_sha[4] = addr[4]; + tx_arpframe->ar_sha[5] = addr[5]; + + addr = ip_get_myip(nif_get_protocol_info(nif,ETH_FRM_IP)); + tx_arpframe->ar_spa[0] = addr[0]; + tx_arpframe->ar_spa[1] = addr[1]; + tx_arpframe->ar_spa[2] = addr[2]; + tx_arpframe->ar_spa[3] = addr[3]; + + /* + * Save the length of my packet in the buffer structure + */ + pNbuf->length = ARP_HDR_LEN; + + nif->send(nif, + &tx_arpframe->ar_tha[0], + &tx_arpframe->ar_sha[0], + ETH_FRM_ARP, + pNbuf); + } + else + nbuf_free(pNbuf); + break; + case ARP_REPLY: + /* + * The ARP Reply case is already taken care of + */ + default: + nbuf_free(pNbuf); + break; + } +#endif /* _NOT_USED_ */ + return; +} diff --git a/net/fec.c b/net/fec.c index d48a6f0..f3db7fe 100644 --- a/net/fec.c +++ b/net/fec.c @@ -28,8 +28,6 @@ #endif -/********************************************************************/ - FEC_EVENT_LOG fec_log[2]; /********************************************************************/ @@ -184,7 +182,7 @@ void fec_mii_init(uint8_t ch, uint32_t sys_clk) * MII Speed Setting = System_Clock / (2.5MHz * 2) * (plus 1 to make sure we round up) */ - MCF_FEC_MSCR(ch) = MCF_FEC_MSCR_MII_SPEED((sys_clk/5)+1); + MCF_FEC_MSCR(ch) = MCF_FEC_MSCR_MII_SPEED((sys_clk / 5) + 1); } /********************************************************************/ @@ -217,7 +215,7 @@ void fec_mib_dump(uint8_t ch) */ void fec_log_init(uint8_t ch) { - memset(&fec_log[ch],0,sizeof(FEC_EVENT_LOG)); + memset(&fec_log[ch], 0, sizeof(FEC_EVENT_LOG)); } /********************************************************************/ @@ -229,30 +227,30 @@ void fec_log_init(uint8_t ch) void fec_log_dump(uint8_t ch) { xprintf("\n FEC%d Log\n---------------\n",ch); - xprintf("Total: %4d\n",fec_log[ch].total); - xprintf("hberr: %4d\n",fec_log[ch].hberr); - xprintf("babr: %4d\n",fec_log[ch].babr); - xprintf("babt: %4d\n",fec_log[ch].babt); - xprintf("gra: %4d\n",fec_log[ch].gra); - xprintf("txf: %4d\n",fec_log[ch].txf); - xprintf("mii: %4d\n",fec_log[ch].mii); - xprintf("lc: %4d\n",fec_log[ch].lc); - xprintf("rl: %4d\n",fec_log[ch].rl); - xprintf("xfun: %4d\n",fec_log[ch].xfun); - xprintf("xferr: %4d\n",fec_log[ch].xferr); - xprintf("rferr: %4d\n",fec_log[ch].rferr); - xprintf("dtxf: %4d\n",fec_log[ch].dtxf); - xprintf("drxf: %4d\n",fec_log[ch].drxf); + xprintf("Total: %4d\n", fec_log[ch].total); + xprintf("hberr: %4d\n", fec_log[ch].hberr); + xprintf("babr: %4d\n", fec_log[ch].babr); + xprintf("babt: %4d\n", fec_log[ch].babt); + xprintf("gra: %4d\n", fec_log[ch].gra); + xprintf("txf: %4d\n", fec_log[ch].txf); + xprintf("mii: %4d\n", fec_log[ch].mii); + xprintf("lc: %4d\n", fec_log[ch].lc); + xprintf("rl: %4d\n", fec_log[ch].rl); + xprintf("xfun: %4d\n", fec_log[ch].xfun); + xprintf("xferr: %4d\n", fec_log[ch].xferr); + xprintf("rferr: %4d\n", fec_log[ch].rferr); + xprintf("dtxf: %4d\n", fec_log[ch].dtxf); + xprintf("drxf: %4d\n", fec_log[ch].drxf); xprintf("\nRFSW:\n"); - xprintf("inv: %4d\n",fec_log[ch].rfsw_inv); - xprintf("m: %4d\n",fec_log[ch].rfsw_m); - xprintf("bc: %4d\n",fec_log[ch].rfsw_bc); - xprintf("mc: %4d\n",fec_log[ch].rfsw_mc); - xprintf("lg: %4d\n",fec_log[ch].rfsw_lg); - xprintf("no: %4d\n",fec_log[ch].rfsw_no); - xprintf("cr: %4d\n",fec_log[ch].rfsw_cr); - xprintf("ov: %4d\n",fec_log[ch].rfsw_ov); - xprintf("tr: %4d\n",fec_log[ch].rfsw_tr); + xprintf("inv: %4d\n", fec_log[ch].rfsw_inv); + xprintf("m: %4d\n", fec_log[ch].rfsw_m); + xprintf("bc: %4d\n", fec_log[ch].rfsw_bc); + xprintf("mc: %4d\n", fec_log[ch].rfsw_mc); + xprintf("lg: %4d\n", fec_log[ch].rfsw_lg); + xprintf("no: %4d\n", fec_log[ch].rfsw_no); + xprintf("cr: %4d\n", fec_log[ch].rfsw_cr); + xprintf("ov: %4d\n", fec_log[ch].rfsw_ov); + xprintf("tr: %4d\n", fec_log[ch].rfsw_tr); xprintf("---------------\n\n"); } @@ -266,28 +264,28 @@ void fec_log_dump(uint8_t ch) void fec_debug_dump(uint8_t ch) { xprintf("\n------------- FEC%d -------------\n",ch); - xprintf("EIR %08x \n",MCF_FEC_EIR(ch)); - xprintf("EIMR %08x \n",MCF_FEC_EIMR(ch)); - xprintf("ECR %08x \n",MCF_FEC_ECR(ch)); - xprintf("RCR %08x \n",MCF_FEC_RCR(ch)); - xprintf("R_HASH %08x \n",MCF_FEC_RHR_HASH(ch)); - xprintf("TCR %08x \n",MCF_FEC_TCR(ch)); - xprintf("FECTFWR %08x \n",MCF_FEC_FECTFWR(ch)); - xprintf("FECRFSR %08x \n",MCF_FEC_FECRFSR(ch)); - xprintf("FECRFCR %08x \n",MCF_FEC_FECRFCR(ch)); - xprintf("FECRLRFP %08x \n",MCF_FEC_FECRLRFP(ch)); - xprintf("FECRLWFP %08x \n",MCF_FEC_FECRLWFP(ch)); - xprintf("FECRFAR %08x \n",MCF_FEC_FECRFAR(ch)); - xprintf("FECRFRP %08x \n",MCF_FEC_FECRFRP(ch)); - xprintf("FECRFWP %08x \n",MCF_FEC_FECRFWP(ch)); - xprintf("FECTFSR %08x \n",MCF_FEC_FECTFSR(ch)); - xprintf("FECTFCR %08x \n",MCF_FEC_FECTFCR(ch)); - xprintf("FECTLRFP %08x \n",MCF_FEC_FECTLRFP(ch)); - xprintf("FECTLWFP %08x \n",MCF_FEC_FECTLWFP(ch)); - xprintf("FECTFAR %08x \n",MCF_FEC_FECTFAR(ch)); - xprintf("FECTFRP %08x \n",MCF_FEC_FECTFRP(ch)); - xprintf("FECTFWP %08x \n",MCF_FEC_FECTFWP(ch)); - xprintf("FRST %08x \n",MCF_FEC_FECFRST(ch)); + xprintf("EIR %08x \n", MCF_FEC_EIR(ch)); + xprintf("EIMR %08x \n", MCF_FEC_EIMR(ch)); + xprintf("ECR %08x \n", MCF_FEC_ECR(ch)); + xprintf("RCR %08x \n", MCF_FEC_RCR(ch)); + xprintf("R_HASH %08x \n", MCF_FEC_RHR_HASH(ch)); + xprintf("TCR %08x \n", MCF_FEC_TCR(ch)); + xprintf("FECTFWR %08x \n", MCF_FEC_FECTFWR(ch)); + xprintf("FECRFSR %08x \n", MCF_FEC_FECRFSR(ch)); + xprintf("FECRFCR %08x \n", MCF_FEC_FECRFCR(ch)); + xprintf("FECRLRFP %08x \n", MCF_FEC_FECRLRFP(ch)); + xprintf("FECRLWFP %08x \n", MCF_FEC_FECRLWFP(ch)); + xprintf("FECRFAR %08x \n", MCF_FEC_FECRFAR(ch)); + xprintf("FECRFRP %08x \n", MCF_FEC_FECRFRP(ch)); + xprintf("FECRFWP %08x \n", MCF_FEC_FECRFWP(ch)); + xprintf("FECTFSR %08x \n", MCF_FEC_FECTFSR(ch)); + xprintf("FECTFCR %08x \n", MCF_FEC_FECTFCR(ch)); + xprintf("FECTLRFP %08x \n", MCF_FEC_FECTLRFP(ch)); + xprintf("FECTLWFP %08x \n", MCF_FEC_FECTLWFP(ch)); + xprintf("FECTFAR %08x \n", MCF_FEC_FECTFAR(ch)); + xprintf("FECTFRP %08x \n", MCF_FEC_FECTFRP(ch)); + xprintf("FECTFWP %08x \n", MCF_FEC_FECTFWP(ch)); + xprintf("FRST %08x \n", MCF_FEC_FECFRST(ch)); xprintf("--------------------------------\n\n"); } @@ -305,11 +303,11 @@ void fec_duplex (uint8_t ch, uint8_t duplex) { case FEC_MII_HALF_DUPLEX: MCF_FEC_RCR(ch) |= MCF_FEC_RCR_DRT; - MCF_FEC_TCR(ch) &= (uint32_t)~MCF_FEC_TCR_FDEN; + MCF_FEC_TCR(ch) &= (uint32_t) ~MCF_FEC_TCR_FDEN; break; case FEC_MII_FULL_DUPLEX: default: - MCF_FEC_RCR(ch) &= (uint32_t)~MCF_FEC_RCR_DRT; + MCF_FEC_RCR(ch) &= (uint32_t) ~MCF_FEC_RCR_DRT; MCF_FEC_TCR(ch) |= MCF_FEC_TCR_FDEN; break; } @@ -332,12 +330,12 @@ uint8_t fec_hash_address(const uint8_t *addr) int i, j; crc = 0xFFFFFFFF; - for(i=0; i<6; ++i) + for (i = 0; i < 6; ++i) { byte = addr[i]; - for(j=0; j<8; ++j) + for (j = 0; j < 8; ++j) { - if((byte & 0x01)^(crc & 0x01)) + if ((byte & 0x01)^(crc & 0x01)) { crc >>= 1; crc = crc ^ 0xEDB88320; @@ -366,8 +364,8 @@ void fec_set_address (uint8_t ch, const uint8_t *pa) /* * Set the Physical Address */ - MCF_FEC_PALR(ch) = (uint32_t)((pa[0]<<24) | (pa[1]<<16) | (pa[2]<<8) | pa[3]); - MCF_FEC_PAHR(ch) = (uint32_t)((pa[4]<<24) | (pa[5]<<16)); + MCF_FEC_PALR(ch) = (uint32_t)((pa[0] << 24) | (pa[1] << 16) | (pa[2] << 8) | pa[3]); + MCF_FEC_PAHR(ch) = (uint32_t)((pa[4] << 24) | (pa[5] << 16)); /* * Calculate and set the hash for given Physical Address @@ -555,9 +553,6 @@ void fec_rx_start(uint8_t ch, int8_t *rxbd) channel = dma_set_channel(DMA_FEC_RX(ch), (ch == 0) ? fec0_rx_frame : fec1_rx_frame); - /* - * Start the Rx DMA task - */ /* * Start the Rx DMA task */ @@ -729,6 +724,7 @@ void fec_rx_frame(uint8_t ch, NIF *nif) #ifdef DEBUG_PRINT xprintf("nbuf_alloc() failed\n"); #endif + /* * Can't allocate a new network buffer, so we * have to trash the received data and reuse the buffer @@ -811,12 +807,14 @@ void fec_rx_frame(uint8_t ch, NIF *nif) void fec0_rx_frame(void) { extern NIF nif1; + fec_rx_frame(0, &nif1); } void fec1_rx_frame(void) { extern NIF nif1; + fec_rx_frame(1, &nif1); } @@ -1078,6 +1076,7 @@ int fec1_send(NIF *nif, uint8_t *dst, uint8_t *src, uint16_t type, NBUF *nbuf) { return fec_send(1, nif, dst, src, type, nbuf); } + /********************************************************************/ /* * Enable interrupts on the selected FEC @@ -1163,7 +1162,7 @@ static void fec_irq_handler(uint8_t ch) #ifdef DEBUG if (event != eir) - xprintf("Pending but not enabled: 0x%08X\n",(event ^ eir)); + xprintf("Pending but not enabled: 0x%08X\n", (event ^ eir)); #endif /* @@ -1177,7 +1176,7 @@ static void fec_irq_handler(uint8_t ch) fec_log[ch].rferr++; #ifdef DEBUG xprintf("RFERR\n"); - xprintf("FECRFSR%d = 0x%08x\n",ch,MCF_FEC_FECRFSR(ch)); + xprintf("FECRFSR%d = 0x%08x\n", ch, MCF_FEC_FECRFSR(ch)); fec_eth_stop(ch); #endif } @@ -1319,8 +1318,8 @@ void fec_eth_setup(uint8_t ch, uint8_t trcvr, uint8_t speed, uint8_t duplex, con /* * Enable the multi-channel DMA tasks */ - fec_rx_start(ch, (int8_t*) fecbd_get_start(ch,Rx)); - fec_tx_start(ch, (int8_t*) fecbd_get_start(ch,Tx)); + fec_rx_start(ch, (int8_t*) fecbd_get_start(ch, Rx)); + fec_tx_start(ch, (int8_t*) fecbd_get_start(ch, Tx)); /* * Enable the FEC channel @@ -1337,7 +1336,7 @@ void fec_eth_setup(uint8_t ch, uint8_t trcvr, uint8_t speed, uint8_t duplex, con */ void fec_eth_reset(uint8_t ch) { -// To do + // To do } /********************************************************************/ @@ -1387,5 +1386,4 @@ void fec_eth_stop(uint8_t ch) */ set_ipl(level); } -/********************************************************************/ diff --git a/net/fecbd.c b/net/fecbd.c index 63ed476..2598ca4 100644 --- a/net/fecbd.c +++ b/net/fecbd.c @@ -1,226 +1,226 @@ -/* - * File: fecbd.c - * Purpose: Provide a simple buffer management driver - * - * Notes: - */ -#include "MCD_dma.h" -#include "fecbd.h" -#include "nbuf.h" -#include "eth.h" -#include "bas_printf.h" -#include - -/* - * This implements a simple static buffer descriptor - * ring for each channel and each direction - * - * FEC Buffer Descriptors need to be aligned to a 4-byte boundary. - * In order to accomplish this, data is over-allocated and manually - * aligned at runtime - * - * Enough space is allocated for each of the two FEC channels to have - * NRXBD Rx BDs and NTXBD Tx BDs - * - */ - -FECBD unaligned_bds[(2 * NRXBD) + (2 * NTXBD) + 1]; - -/* - * These pointers are used to reference into the chunck of data set - * aside for buffer descriptors - */ -FECBD *RxBD; -FECBD *TxBD; - -/* - * Macros to easier access to the BD ring - */ -#define RxBD(ch,i) RxBD[(ch * NRXBD) + i] -#define TxBD(ch,i) TxBD[(ch * NTXBD) + i] - -/* - * Buffer descriptor indexes - */ -static int iTxbd_new; -static int iTxbd_old; -static int iRxbd; - -/* - * Initialize the FEC Buffer Descriptor ring - * Buffer Descriptor format is defined by the MCDAPI - * - * Parameters: - * ch FEC channel - */ -void fecbd_init(uint8_t ch) -{ - NBUF *nbuf; - int i; - - /* - * Align Buffer Descriptors to 4-byte boundary - */ - RxBD = (FECBD *)(((int)unaligned_bds + 3) & 0xFFFFFFFC); - TxBD = (FECBD *)((int)RxBD + (sizeof(FECBD) * 2 * NRXBD)); - - /* - * Initialize the Rx Buffer Descriptor ring - */ - for (i = 0; i < NRXBD; ++i) - { - /* Grab a network buffer from the free list */ - nbuf = nbuf_alloc(); - if (nbuf == NULL) - { - xprintf("%s: could not allocate network buffer\r\n", __FUNCTION__); - return; - } - - /* Initialize the BD */ - RxBD(ch,i).status = RX_BD_E | RX_BD_INTERRUPT; - RxBD(ch,i).length = RX_BUF_SZ; - RxBD(ch,i).data = nbuf->data; - - /* Add the network buffer to the Rx queue */ - nbuf_add(NBUF_RX_RING, nbuf); - } - - /* - * Set the WRAP bit on the last one - */ - RxBD(ch,i-1).status |= RX_BD_W; - - /* - * Initialize the Tx Buffer Descriptor ring - */ - for (i = 0; i < NTXBD; ++i) - { - TxBD(ch,i).status = TX_BD_INTERRUPT; - TxBD(ch,i).length = 0; - TxBD(ch,i).data = NULL; - } - - /* - * Set the WRAP bit on the last one - */ - TxBD(ch,i-1).status |= TX_BD_W; - - /* - * Initialize the buffer descriptor indexes - */ - iTxbd_new = iTxbd_old = iRxbd = 0; -} - -void fecbd_dump(uint8_t ch) -{ - #ifdef DEBUG_PRINT - int i; - - printf("\n------------ FEC%d BDs -----------\n",ch); - printf("RxBD Ring\n"); - for (i=0; i + +/* + * This implements a simple static buffer descriptor + * ring for each channel and each direction + * + * FEC Buffer Descriptors need to be aligned to a 4-byte boundary. + * In order to accomplish this, data is over-allocated and manually + * aligned at runtime + * + * Enough space is allocated for each of the two FEC channels to have + * NRXBD Rx BDs and NTXBD Tx BDs + * + */ + +FECBD unaligned_bds[(2 * NRXBD) + (2 * NTXBD) + 1]; + +/* + * These pointers are used to reference into the chunck of data set + * aside for buffer descriptors + */ +FECBD *RxBD; +FECBD *TxBD; + +/* + * Macros to easier access to the BD ring + */ +#define RxBD(ch,i) RxBD[(ch * NRXBD) + i] +#define TxBD(ch,i) TxBD[(ch * NTXBD) + i] + +/* + * Buffer descriptor indexes + */ +static int iTxbd_new; +static int iTxbd_old; +static int iRxbd; + +/* + * Initialize the FEC Buffer Descriptor ring + * Buffer Descriptor format is defined by the MCDAPI + * + * Parameters: + * ch FEC channel + */ +void fecbd_init(uint8_t ch) +{ + NBUF *nbuf; + int i; + + /* + * Align Buffer Descriptors to 4-byte boundary + */ + RxBD = (FECBD *)(((int) unaligned_bds + 3) & 0xFFFFFFFC); + TxBD = (FECBD *)((int) RxBD + (sizeof(FECBD) * 2 * NRXBD)); + + /* + * Initialize the Rx Buffer Descriptor ring + */ + for (i = 0; i < NRXBD; ++i) + { + /* Grab a network buffer from the free list */ + nbuf = nbuf_alloc(); + if (nbuf == NULL) + { + xprintf("%s: could not allocate network buffer\r\n", __FUNCTION__); + return; + } + + /* Initialize the BD */ + RxBD(ch,i).status = RX_BD_E | RX_BD_INTERRUPT; + RxBD(ch,i).length = RX_BUF_SZ; + RxBD(ch,i).data = nbuf->data; + + /* Add the network buffer to the Rx queue */ + nbuf_add(NBUF_RX_RING, nbuf); + } + + /* + * Set the WRAP bit on the last one + */ + RxBD(ch,i-1).status |= RX_BD_W; + + /* + * Initialize the Tx Buffer Descriptor ring + */ + for (i = 0; i < NTXBD; ++i) + { + TxBD(ch, i).status = TX_BD_INTERRUPT; + TxBD(ch, i).length = 0; + TxBD(ch, i).data = NULL; + } + + /* + * Set the WRAP bit on the last one + */ + TxBD(ch,i-1).status |= TX_BD_W; + + /* + * Initialize the buffer descriptor indexes + */ + iTxbd_new = iTxbd_old = iRxbd = 0; +} + +void fecbd_dump(uint8_t ch) +{ + #ifdef DEBUG_PRINT + int i; + + printf("\n------------ FEC%d BDs -----------\n",ch); + printf("RxBD Ring\n"); + for (i = 0; i < NRXBD; i++) + { + printf("%02d: BD Addr=0x%08x, Ctrl=0x%04x, Lgth=%04d, DataPtr=0x%08x\n", + i, &RxBD(ch, i), + RxBD(ch, i).status, + RxBD(ch, i).length, + RxBD(ch, i).data); + } + printf("TxBD Ring\n"); + for (i = 0; i < NTXBD; i++) + { + printf("%02d: BD Addr=0x%08x, Ctrl=0x%04x, Lgth=%04d, DataPtr=0x%08x\n", + i, &TxBD(ch, i), + TxBD(ch, i).status, + TxBD(ch, i).length, + TxBD(ch, i).data); + } + printf("--------------------------------\n\n"); + #endif +} + +/* + * Return the address of the first buffer descriptor in the ring. + * + * Parameters: + * ch FEC channel + * direction Rx or Tx Macro + * + * Return Value: + * The start address of the selected Buffer Descriptor ring + */ +uint32_t fecbd_get_start(uint8_t ch, uint8_t direction) +{ + switch (direction) + { + case Rx: + return (uint32_t)((int)RxBD + (ch * sizeof(FECBD) * NRXBD)); + case Tx: + default: + return (uint32_t)((int)TxBD + (ch * sizeof(FECBD) * NTXBD)); + } +} + +FECBD *fecbd_rx_alloc(uint8_t ch) +{ + int i = iRxbd; + + /* Check to see if the ring of BDs is full */ + if (RxBD(ch, i).status & RX_BD_E) + return NULL; + + /* Increment the circular index */ + iRxbd = (uint8_t)((iRxbd + 1) % NRXBD); + + return &RxBD(ch, i); +} + +/* + * This function keeps track of the next available Tx BD in the ring + * + * Parameters: + * ch FEC channel + * + * Return Value: + * Pointer to next available buffer descriptor. + * NULL if the BD ring is full + */ +FECBD *fecbd_tx_alloc(uint8_t ch) +{ + int i = iTxbd_new; + + /* Check to see if the ring of BDs is full */ + if (TxBD(ch, i).status & TX_BD_R) + return NULL; + + /* Increment the circular index */ + iTxbd_new = (uint8_t)((iTxbd_new + 1) % NTXBD); + + return &TxBD(ch, i); +} + +/* + * This function keeps track of the Tx BDs that have already been + * processed by the FEC + * + * Parameters: + * ch FEC channel + * + * Return Value: + * Pointer to the oldest buffer descriptor that has already been sent + * by the FEC, NULL if the BD ring is empty + */ +FECBD *fecbd_tx_free(uint8_t ch) +{ + int i = iTxbd_old; + + /* Check to see if the ring of BDs is empty */ + if ((TxBD(ch, i).data == NULL) || (TxBD(ch, i).status & TX_BD_R)) + return NULL; + + /* Increment the circular index */ + iTxbd_old = (uint8_t)((iTxbd_old + 1) % NTXBD); + + return &TxBD(ch, i); +} diff --git a/net/ip.c b/net/ip.c index 7af7e44..e285183 100644 --- a/net/ip.c +++ b/net/ip.c @@ -1,293 +1,293 @@ -/* - * File: ip.c - * Purpose: Internet Protcol device driver - * - * Notes: - * - * Modifications: - */ -#include "net.h" -#include -#include - - -void ip_init(IP_INFO *info, IP_ADDR_P myip, IP_ADDR_P gateway, IP_ADDR_P netmask) -{ - int index; - - for (index = 0; index < sizeof(IP_ADDR); index++) - { - info->myip[index] = myip[index]; - info->gateway[index] = gateway[index]; - info->netmask[index] = netmask[index]; - info->broadcast[index] = 0xFF; - } - - info->rx = 0; - info->rx_unsup = 0; - info->tx = 0; - info->err = 0; -} - -uint8_t *ip_get_myip(IP_INFO *info) -{ - if (info != 0) - { - return (uint8_t *) &info->myip[0]; - } - return 0; -} - -int ip_addr_compare(IP_ADDR_P addr1, IP_ADDR_P addr2) -{ - int i; - - for (i = 0; i < sizeof(IP_ADDR); i++) - { - if (addr1[i] != addr2[i]) - return 0; - } - return 1; -} - -uint8_t *ip_resolve_route(NIF *nif, IP_ADDR_P destip) -{ - /* - * This function determines whether or not an outgoing IP - * packet needs to be transmitted on the local net or sent - * to the router for transmission. - */ - IP_INFO *info; - IP_ADDR mask,result; - int i; - - info = nif_get_protocol_info(nif,ETH_FRM_IP); - - /* create mask for local IP */ - for (i = 0; i < sizeof(IP_ADDR); i++) - { - mask[i] = info->myip[i] & info->netmask[i]; - } - - /* apply mask to the destination IP */ - for (i = 0; i < sizeof(IP_ADDR); i++) - { - result[i] = mask[i] & destip[i]; - } - - /* See if destination IP is local or not */ - if (ip_addr_compare(mask,result)) - { - /* The destination IP is on the local net */ - return arp_resolve(nif,ETH_FRM_IP,destip); - } - else - { - /* The destination IP is not on the local net */ - return arp_resolve(nif,ETH_FRM_IP,info->gateway); - } -} - -int ip_send(NIF *nif, uint8_t *dest, uint8_t *src, uint8_t protocol, NBUF *pNbuf) -{ - /* - * This function assembles an IP datagram and passes it - * onto the hardware to be sent over the network. - */ - uint8_t *route; - ip_frame_hdr *ipframe; - - /* - * Construct the IP header - */ - ipframe = (ip_frame_hdr*) &pNbuf->data[IP_HDR_OFFSET]; - - /* IP version 4, Internet Header Length of 5 32-bit words */ - ipframe->version_ihl = 0x45; - - /* Type of Service == 0, normal and routine */ - ipframe->service_type = 0x00; - - /* Total length of data */ - ipframe->total_length = (uint16_t) (pNbuf->length + IP_HDR_SIZE); - - /* User defined identification */ - ipframe->identification = 0x0000; - - /* Fragment Flags and Offset -- Don't fragment, last frag */ - ipframe->flags_frag_offset = 0x0000; - - /* Time To Live */ - ipframe->ttl = 0xFF; - - /* Protocol */ - ipframe->protocol = protocol; - - /* Checksum, computed later, zeroed for computation */ - ipframe->checksum = 0x0000; - - /* source IP address */ - ipframe->source_addr[0] = src[0]; - ipframe->source_addr[1] = src[1]; - ipframe->source_addr[2] = src[2]; - ipframe->source_addr[3] = src[3]; - - /* dest IP address */ - ipframe->dest_addr[0] = dest[0]; - ipframe->dest_addr[1] = dest[1]; - ipframe->dest_addr[2] = dest[2]; - ipframe->dest_addr[3] = dest[3]; - - /* Compute checksum */ - ipframe->checksum = ip_chksum((uint16_t *) ipframe, IP_HDR_SIZE); - - /* Increment the packet length by the size of the IP header */ - pNbuf->length += IP_HDR_SIZE; - - /* - * Determine the hardware address of the recipient - */ - route = ip_resolve_route(nif, dest); - if (route == NULL) - { - xprintf("Unable to locate %d.%d.%d.%d\n", - dest[0],dest[1],dest[2],dest[3]); - return 0; - } - - return nif->send(nif, - route, - &nif->hwa[0], - ETH_FRM_IP, - pNbuf - ); -} - -#if defined(DEBUG_PRINT) -void -dump_ip_frame (ip_frame_hdr *ipframe) -{ - printf("Version: %02X\n", ((ipframe->version_ihl & 0x00f0) >> 4)); - printf("IHL: %02X\n", ipframe->version_ihl & 0x000f); - printf("Service: %02X\n", ipframe->service_type); - printf("Length: %04X\n", ipframe->total_length); - printf("Ident: %04X\n", ipframe->identification); - printf("Flags: %02X\n", ((ipframe->flags_frag_offset & 0xC000) >> 14)); - printf("Frag: %04X\n", ipframe->flags_frag_offset & 0x3FFF); - printf("TTL: %02X\n", ipframe->ttl); - printf("Protocol: %02X\n", ipframe->protocol); - printf("Chksum: %04X\n", ipframe->checksum); - printf("Source : %d.%d.%d.%d\n", - ipframe->source_addr[0], - ipframe->source_addr[1], - ipframe->source_addr[2], - ipframe->source_addr[3]); - printf("Dest : %d.%d.%d.%d\n", - ipframe->dest_addr[0], - ipframe->dest_addr[1], - ipframe->dest_addr[2], - ipframe->dest_addr[3]); - printf("Options: %08X\n", ipframe->options); -} -#endif - - -uint16_t ip_chksum(uint16_t *data, int num) -{ - int chksum, ichksum; - uint16_t temp; - - chksum = 0; - num = num >> 1; /* from bytes to words */ - for (; num; num--, data++) - { - temp = *data; - ichksum = chksum + temp; - ichksum = ichksum & 0x0000FFFF; - if ((ichksum < temp) || (ichksum < chksum)) - { - ichksum += 1; - ichksum = ichksum & 0x0000FFFF; - } - chksum = ichksum; - } - return (uint16_t) ~chksum; -} - -static int validate_ip_hdr(NIF *nif, ip_frame_hdr *ipframe) -{ - int index, chksum; - IP_INFO *info; - - /* - * Check the IP Version - */ - if (IP_VERSION(ipframe) != 4) - return 0; - - /* - * Check Internet Header Length - */ - if (IP_IHL(ipframe) < 5) - return 0; - - /* - * Check the destination IP address - */ - info = nif_get_protocol_info(nif,ETH_FRM_IP); - for (index = 0; index < sizeof(IP_ADDR); index++) - if (info->myip[index] != ipframe->dest_addr[index]) - return 0; - - /* - * Check the checksum - */ - chksum = (int)((uint16_t) IP_CHKSUM(ipframe)); - IP_CHKSUM(ipframe) = 0; - - if (ip_chksum((uint16_t *) ipframe,IP_IHL(ipframe)*4) != chksum) - return 0; - - IP_CHKSUM(ipframe) = (uint16_t) chksum; - - return 1; -} - -void ip_handler(NIF *nif, NBUF *pNbuf) -{ - /* - * IP packet handler - */ - ip_frame_hdr *ipframe; - - ipframe = (ip_frame_hdr *)&pNbuf->data[pNbuf->offset]; - - /* - * Verify valid IP header and destination IP - */ - if (!validate_ip_hdr(nif,ipframe)) - { - nbuf_free(pNbuf); - return; - } - - pNbuf->offset += (IP_IHL(ipframe) * 4); - pNbuf->length = (uint16_t)(IP_LENGTH(ipframe) - (IP_IHL(ipframe) * 4)); - - /* - * Call the appriopriate handler - */ - switch (IP_PROTOCOL(ipframe)) - { - case IP_PROTO_ICMP: - // FIXME: icmp_handler(nif,pNbuf); - break; - case IP_PROTO_UDP: - udp_handler(nif,pNbuf); - break; - default: - nbuf_free(pNbuf); - break; - } - return; -} +/* + * File: ip.c + * Purpose: Internet Protcol device driver + * + * Notes: + * + * Modifications: + */ +#include "net.h" +#include +#include + + +void ip_init(IP_INFO *info, IP_ADDR_P myip, IP_ADDR_P gateway, IP_ADDR_P netmask) +{ + int index; + + for (index = 0; index < sizeof(IP_ADDR); index++) + { + info->myip[index] = myip[index]; + info->gateway[index] = gateway[index]; + info->netmask[index] = netmask[index]; + info->broadcast[index] = 0xFF; + } + + info->rx = 0; + info->rx_unsup = 0; + info->tx = 0; + info->err = 0; +} + +uint8_t *ip_get_myip(IP_INFO *info) +{ + if (info != 0) + { + return (uint8_t *) &info->myip[0]; + } + return 0; +} + +int ip_addr_compare(IP_ADDR_P addr1, IP_ADDR_P addr2) +{ + int i; + + for (i = 0; i < sizeof(IP_ADDR); i++) + { + if (addr1[i] != addr2[i]) + return 0; + } + return 1; +} + +uint8_t *ip_resolve_route(NIF *nif, IP_ADDR_P destip) +{ + /* + * This function determines whether or not an outgoing IP + * packet needs to be transmitted on the local net or sent + * to the router for transmission. + */ + IP_INFO *info; + IP_ADDR mask, result; + int i; + + info = nif_get_protocol_info(nif, ETH_FRM_IP); + + /* create mask for local IP */ + for (i = 0; i < sizeof(IP_ADDR); i++) + { + mask[i] = info->myip[i] & info->netmask[i]; + } + + /* apply mask to the destination IP */ + for (i = 0; i < sizeof(IP_ADDR); i++) + { + result[i] = mask[i] & destip[i]; + } + + /* See if destination IP is local or not */ + if (ip_addr_compare(mask, result)) + { + /* The destination IP is on the local net */ + return arp_resolve(nif, ETH_FRM_IP, destip); + } + else + { + /* The destination IP is not on the local net */ + return arp_resolve(nif, ETH_FRM_IP, info->gateway); + } +} + +int ip_send(NIF *nif, uint8_t *dest, uint8_t *src, uint8_t protocol, NBUF *pNbuf) +{ + /* + * This function assembles an IP datagram and passes it + * onto the hardware to be sent over the network. + */ + uint8_t *route; + ip_frame_hdr *ipframe; + + /* + * Construct the IP header + */ + ipframe = (ip_frame_hdr*) &pNbuf->data[IP_HDR_OFFSET]; + + /* IP version 4, Internet Header Length of 5 32-bit words */ + ipframe->version_ihl = 0x45; + + /* Type of Service == 0, normal and routine */ + ipframe->service_type = 0x00; + + /* Total length of data */ + ipframe->total_length = (uint16_t) (pNbuf->length + IP_HDR_SIZE); + + /* User defined identification */ + ipframe->identification = 0x0000; + + /* Fragment Flags and Offset -- Don't fragment, last frag */ + ipframe->flags_frag_offset = 0x0000; + + /* Time To Live */ + ipframe->ttl = 0xFF; + + /* Protocol */ + ipframe->protocol = protocol; + + /* Checksum, computed later, zeroed for computation */ + ipframe->checksum = 0x0000; + + /* source IP address */ + ipframe->source_addr[0] = src[0]; + ipframe->source_addr[1] = src[1]; + ipframe->source_addr[2] = src[2]; + ipframe->source_addr[3] = src[3]; + + /* dest IP address */ + ipframe->dest_addr[0] = dest[0]; + ipframe->dest_addr[1] = dest[1]; + ipframe->dest_addr[2] = dest[2]; + ipframe->dest_addr[3] = dest[3]; + + /* Compute checksum */ + ipframe->checksum = ip_chksum((uint16_t *) ipframe, IP_HDR_SIZE); + + /* Increment the packet length by the size of the IP header */ + pNbuf->length += IP_HDR_SIZE; + + /* + * Determine the hardware address of the recipient + */ + route = ip_resolve_route(nif, dest); + if (route == NULL) + { + xprintf("Unable to locate %d.%d.%d.%d\n", + dest[0], dest[1], dest[2], dest[3]); + return 0; + } + + return nif->send(nif, + route, + &nif->hwa[0], + ETH_FRM_IP, + pNbuf + ); +} + +#if defined(DEBUG_PRINT) +void +dump_ip_frame (ip_frame_hdr *ipframe) +{ + printf("Version: %02X\n", ((ipframe->version_ihl & 0x00f0) >> 4)); + printf("IHL: %02X\n", ipframe->version_ihl & 0x000f); + printf("Service: %02X\n", ipframe->service_type); + printf("Length: %04X\n", ipframe->total_length); + printf("Ident: %04X\n", ipframe->identification); + printf("Flags: %02X\n", ((ipframe->flags_frag_offset & 0xC000) >> 14)); + printf("Frag: %04X\n", ipframe->flags_frag_offset & 0x3FFF); + printf("TTL: %02X\n", ipframe->ttl); + printf("Protocol: %02X\n", ipframe->protocol); + printf("Chksum: %04X\n", ipframe->checksum); + printf("Source : %d.%d.%d.%d\n", + ipframe->source_addr[0], + ipframe->source_addr[1], + ipframe->source_addr[2], + ipframe->source_addr[3]); + printf("Dest : %d.%d.%d.%d\n", + ipframe->dest_addr[0], + ipframe->dest_addr[1], + ipframe->dest_addr[2], + ipframe->dest_addr[3]); + printf("Options: %08X\n", ipframe->options); +} +#endif + + +uint16_t ip_chksum(uint16_t *data, int num) +{ + int chksum, ichksum; + uint16_t temp; + + chksum = 0; + num = num >> 1; /* from bytes to words */ + for (; num; num--, data++) + { + temp = *data; + ichksum = chksum + temp; + ichksum = ichksum & 0x0000FFFF; + if ((ichksum < temp) || (ichksum < chksum)) + { + ichksum += 1; + ichksum = ichksum & 0x0000FFFF; + } + chksum = ichksum; + } + return (uint16_t) ~chksum; +} + +static int validate_ip_hdr(NIF *nif, ip_frame_hdr *ipframe) +{ + int index, chksum; + IP_INFO *info; + + /* + * Check the IP Version + */ + if (IP_VERSION(ipframe) != 4) + return 0; + + /* + * Check Internet Header Length + */ + if (IP_IHL(ipframe) < 5) + return 0; + + /* + * Check the destination IP address + */ + info = nif_get_protocol_info(nif,ETH_FRM_IP); + for (index = 0; index < sizeof(IP_ADDR); index++) + if (info->myip[index] != ipframe->dest_addr[index]) + return 0; + + /* + * Check the checksum + */ + chksum = (int)((uint16_t) IP_CHKSUM(ipframe)); + IP_CHKSUM(ipframe) = 0; + + if (ip_chksum((uint16_t *) ipframe, IP_IHL(ipframe) * 4) != chksum) + return 0; + + IP_CHKSUM(ipframe) = (uint16_t) chksum; + + return 1; +} + +void ip_handler(NIF *nif, NBUF *pNbuf) +{ + /* + * IP packet handler + */ + ip_frame_hdr *ipframe; + + ipframe = (ip_frame_hdr *)&pNbuf->data[pNbuf->offset]; + + /* + * Verify valid IP header and destination IP + */ + if (!validate_ip_hdr(nif, ipframe)) + { + nbuf_free(pNbuf); + return; + } + + pNbuf->offset += (IP_IHL(ipframe) * 4); + pNbuf->length = (uint16_t)(IP_LENGTH(ipframe) - (IP_IHL(ipframe) * 4)); + + /* + * Call the appriopriate handler + */ + switch (IP_PROTOCOL(ipframe)) + { + case IP_PROTO_ICMP: + // FIXME: icmp_handler(nif,pNbuf); + break; + case IP_PROTO_UDP: + udp_handler(nif,pNbuf); + break; + default: + nbuf_free(pNbuf); + break; + } + return; +}