add missing files not taken with github import
This commit is contained in:
119
net/am79c874.c
Normal file
119
net/am79c874.c
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* File: am79c874.c
|
||||
* Purpose: Driver for the AMD AM79C874 10/100 Ethernet PHY
|
||||
*/
|
||||
|
||||
#include "net.h"
|
||||
#include "fec.h"
|
||||
#include "am79c874.h"
|
||||
|
||||
#include "bas_printf.h"
|
||||
|
||||
#if defined(MACHINE_FIREBEE)
|
||||
#include "firebee.h"
|
||||
#elif defined(MACHINE_M5484LITE)
|
||||
#include "m5484l.h"
|
||||
#elif defined(MACHINE_M54455)
|
||||
#include "m54455.h"
|
||||
#else
|
||||
#error "unknown machine!"
|
||||
#endif
|
||||
|
||||
#include <debug.h>
|
||||
// #define DEBUG
|
||||
|
||||
/* Initialize the AM79C874 PHY
|
||||
*
|
||||
* This function sets up the Auto-Negotiate Advertisement register
|
||||
* within the PHY and then forces the PHY to auto-negotiate for
|
||||
* it's settings.
|
||||
*
|
||||
* Params:
|
||||
* fec_ch FEC channel
|
||||
* phy_addr Address of the PHY.
|
||||
* speed Desired speed (10BaseT or 100BaseTX)
|
||||
* duplex Desired duplex (Full or Half)
|
||||
*
|
||||
* Return Value:
|
||||
* 0 if MII commands fail
|
||||
* 1 otherwise
|
||||
*/
|
||||
int am79c874_init(uint8_t fec_ch, uint8_t phy_addr, uint8_t speed, uint8_t duplex)
|
||||
{
|
||||
int timeout;
|
||||
uint16_t settings;
|
||||
if (speed); /* to do */
|
||||
if (duplex); /* to do */
|
||||
|
||||
/* Initialize the MII interface */
|
||||
fec_mii_init(fec_ch, SYSCLK / 1000);
|
||||
dbg("%s: PHY reset\r\n", __FUNCTION__);
|
||||
|
||||
/* Reset the PHY */
|
||||
if (!fec_mii_write(fec_ch, phy_addr, MII_AM79C874_CR, MII_AM79C874_CR_RESET))
|
||||
return 0;
|
||||
|
||||
/* Wait for the PHY to reset */
|
||||
for (timeout = 0; timeout < FEC_MII_TIMEOUT; timeout++)
|
||||
{
|
||||
fec_mii_read(fec_ch, phy_addr, MII_AM79C874_CR, &settings);
|
||||
if (!(settings & MII_AM79C874_CR_RESET))
|
||||
break;
|
||||
}
|
||||
|
||||
if (timeout >= FEC_MII_TIMEOUT)
|
||||
{
|
||||
dbg("%s: PHY reset failed\r\n", __FUNCTION__);
|
||||
return 0;
|
||||
};
|
||||
dbg("%s: PHY reset OK\r\n", __FUNCTION__);
|
||||
dbg("%s: PHY Enable Auto-Negotiation\r\n", __FUNCTION__);
|
||||
|
||||
/* Enable Auto-Negotiation */
|
||||
if (!fec_mii_write(fec_ch, phy_addr, MII_AM79C874_CR, MII_AM79C874_CR_AUTON | MII_AM79C874_CR_RST_NEG))
|
||||
return 0;
|
||||
|
||||
dbg("%s:PHY Wait for auto-negotiation to complete\r\n", __FUNCTION__);
|
||||
|
||||
/* Wait for auto-negotiation to complete */
|
||||
for (timeout = 0; timeout < FEC_MII_TIMEOUT; timeout++)
|
||||
{
|
||||
settings = 0;
|
||||
fec_mii_read(fec_ch, phy_addr, MII_AM79C874_SR, &settings);
|
||||
if ((settings & AUTONEGLINK) == AUTONEGLINK)
|
||||
break;
|
||||
}
|
||||
|
||||
if (timeout >= FEC_MII_TIMEOUT)
|
||||
{
|
||||
dbg("%s: Auto-negotiation failed (timeout). Set default mode (100Mbps, full duplex)\r\n", __FUNCTION__);
|
||||
|
||||
/* Set the default mode (Full duplex, 100 Mbps) */
|
||||
if (!fec_mii_write(fec_ch, phy_addr, MII_AM79C874_CR, MII_AM79C874_CR_100MB | MII_AM79C874_CR_DPLX))
|
||||
{
|
||||
dbg("%s: forced setting 100Mbps/full failed.\r\n", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DBG_AM79
|
||||
settings = 0;
|
||||
|
||||
fec_mii_read(fec_ch, phy_addr, MII_AM79C874_DR, &settings);
|
||||
|
||||
dbg("%s: PHY Mode:\r\n", __FUNCTION__);
|
||||
if (settings & MII_AM79C874_DR_DATA_RATE)
|
||||
dbg("%s: 100Mbps", __FUNCTION__);
|
||||
else
|
||||
dbg("%s: 10Mbps ", __FUNCTION__);
|
||||
|
||||
if (settings & MII_AM79C874_DR_DPLX)
|
||||
dbg("%s: Full-duplex\r\n", __FUNCTION__);
|
||||
else
|
||||
dbg("%s: Half-duplex\r\n", __FUNCTION__);
|
||||
|
||||
dbg("%s:PHY auto-negotiation complete\r\n", __FUNCTION__);
|
||||
#endif /* DBG_AM79 */
|
||||
|
||||
return 1;
|
||||
}
|
||||
486
net/arp.c
Normal file
486
net/arp.c
Normal file
@@ -0,0 +1,486 @@
|
||||
/*
|
||||
* File: arp.c
|
||||
* Purpose: Address Resolution Protocol routines.
|
||||
*
|
||||
* Notes:
|
||||
*/
|
||||
|
||||
#include "net.h"
|
||||
#include "net_timer.h"
|
||||
#include "bas_printf.h"
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
//#define DEBUG
|
||||
#include "debug.h"
|
||||
|
||||
#define TIMER_NETWORK 3
|
||||
|
||||
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 <protocol,hwa> or <protocol,pa> 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 <protocol,pa> then you get <hwa> out.
|
||||
* If you pass in <protocol,hwa> then you get <pa> 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)
|
||||
{
|
||||
dbg("could not allocate Tx buffer\n");
|
||||
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 */
|
||||
dbg("sending ARP request\r\n");
|
||||
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))
|
||||
{
|
||||
dbg("try to resolve %d.%d.%d.%d\r\n",
|
||||
pa[0], pa[1], pa[2], pa[3], pa[4]);
|
||||
if (arp_resolve_pa(nif, protocol, pa, &hwa))
|
||||
{
|
||||
dbg("resolved to %02x:%02x:%02x:%02x:%02x:%02x.\r\n",
|
||||
hwa[0], hwa[1], hwa[2], hwa[3], hwa[4], hwa[5], hwa[6]);
|
||||
|
||||
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))
|
||||
{
|
||||
dbg("received packet is not an ARP packet, discard it\r\n");
|
||||
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]) )
|
||||
{
|
||||
dbg("received ARP packet is a permanent one, store it\r\n");
|
||||
longevity = ARP_ENTRY_PERM;
|
||||
}
|
||||
else
|
||||
{
|
||||
dbg("received ARP packet was not addressed to us, keep only temporarily\r\n");
|
||||
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]) )
|
||||
{
|
||||
dbg("received arp request directed to us, replying\r\n");
|
||||
/*
|
||||
* 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
|
||||
{
|
||||
dbg("ARP request not addressed to us, discarding\r\n");
|
||||
nbuf_free(pNbuf);
|
||||
}
|
||||
break;
|
||||
|
||||
case ARP_REPLY:
|
||||
/*
|
||||
* The ARP Reply case is already taken care of
|
||||
*/
|
||||
|
||||
/* missing break is intentional */
|
||||
|
||||
default:
|
||||
nbuf_free(pNbuf);
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
178
net/bcm5222.c
Normal file
178
net/bcm5222.c
Normal file
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* File: bcm5222.c
|
||||
* Purpose: Driver for the Micrel BCM5222 10/100 Ethernet PHY
|
||||
*
|
||||
* Notes: This driver was written specifically for the M5475EVB
|
||||
* and M5485EVB. These boards use the MII signals from
|
||||
* FEC0 to control the PHY. Therefore the fec_ch parameter
|
||||
* is ignored when doing MII reads and writes.
|
||||
*/
|
||||
|
||||
#include "net.h"
|
||||
#include "fec.h"
|
||||
#include "bcm5222.h"
|
||||
|
||||
#include "bas_printf.h"
|
||||
|
||||
#if defined(MACHINE_FIREBEE)
|
||||
#include "firebee.h"
|
||||
#elif defined(MACHINE_M5484LITE)
|
||||
#include "m5484l.h"
|
||||
#elif defined(MACHINE_M54455)
|
||||
#include "m54455.h"
|
||||
#else
|
||||
#error "Unknown machine!"
|
||||
#endif
|
||||
|
||||
// #define DEBUG
|
||||
#include "debug.h"
|
||||
|
||||
/*
|
||||
* Initialize the BCM5222 PHY
|
||||
*
|
||||
* This function sets up the Auto-Negotiate Advertisement register
|
||||
* within the PHY and then forces the PHY to auto-negotiate for
|
||||
* it's settings.
|
||||
*
|
||||
* Params:
|
||||
* fec_ch FEC channel
|
||||
* phy_addr Address of the PHY.
|
||||
* speed Desired speed (10BaseT or 100BaseTX)
|
||||
* duplex Desired duplex (Full or Half)
|
||||
*
|
||||
* Return Value:
|
||||
* 0 if MII commands fail
|
||||
* 1 otherwise
|
||||
*/
|
||||
int bcm5222_init(uint8_t fec_ch, uint8_t phy_addr, uint8_t speed, uint8_t duplex)
|
||||
{
|
||||
int timeout;
|
||||
uint16_t settings;
|
||||
|
||||
/* Initialize the MII interface */
|
||||
fec_mii_init(fec_ch, SYSCLK / 1000);
|
||||
dbg("PHY reset\r\n");
|
||||
|
||||
/* Reset the PHY */
|
||||
if (!fec_mii_write(fec_ch, phy_addr, BCM5222_CTRL, BCM5222_CTRL_RESET | BCM5222_CTRL_ANE))
|
||||
return 0;
|
||||
|
||||
/* Wait for the PHY to reset */
|
||||
for (timeout = 0; timeout < FEC_MII_TIMEOUT; timeout++)
|
||||
{
|
||||
fec_mii_read(fec_ch, phy_addr, BCM5222_CTRL, &settings);
|
||||
if (!(settings & BCM5222_CTRL_RESET))
|
||||
break;
|
||||
}
|
||||
if(timeout >= FEC_MII_TIMEOUT)
|
||||
return 0;
|
||||
|
||||
dbg("PHY reset OK\r\n");
|
||||
|
||||
settings = (BCM5222_AN_ADV_NEXT_PAGE | BCM5222_AN_ADV_PAUSE);
|
||||
|
||||
if (speed == FEC_MII_10BASE_T)
|
||||
settings |= (uint16_t)((duplex == FEC_MII_FULL_DUPLEX)
|
||||
? (BCM5222_AN_ADV_10BT_FDX | BCM5222_AN_ADV_10BT)
|
||||
: BCM5222_AN_ADV_10BT);
|
||||
else /* (speed == FEC_MII_100BASE_TX) */
|
||||
settings = (uint16_t)((duplex == FEC_MII_FULL_DUPLEX)
|
||||
? (BCM5222_AN_ADV_100BTX_FDX | BCM5222_AN_ADV_100BTX
|
||||
| BCM5222_AN_ADV_10BT_FDX | BCM5222_AN_ADV_10BT)
|
||||
: (BCM5222_AN_ADV_100BTX | BCM5222_AN_ADV_10BT));
|
||||
|
||||
/* Set the Auto-Negotiation Advertisement Register */
|
||||
if (!fec_mii_write(fec_ch, phy_addr, BCM5222_AN_ADV, settings))
|
||||
return 0;
|
||||
|
||||
dbg("PHY Enable Auto-Negotiation\r\n");
|
||||
|
||||
/* Enable Auto-Negotiation */
|
||||
if (!fec_mii_write(fec_ch, phy_addr, BCM5222_CTRL, (BCM5222_CTRL_ANE | BCM5222_CTRL_RESTART_AN)))
|
||||
return 0;
|
||||
|
||||
dbg("PHY Wait for auto-negotiation to complete\r\n");
|
||||
|
||||
/* Wait for auto-negotiation to complete */
|
||||
for (timeout = 0; timeout < FEC_MII_TIMEOUT; timeout++)
|
||||
{
|
||||
if (!fec_mii_read(fec_ch, phy_addr, BCM5222_STAT, &settings))
|
||||
return 0;
|
||||
if (settings & BCM5222_STAT_AN_COMPLETE)
|
||||
break;
|
||||
}
|
||||
|
||||
if (timeout < FEC_MII_TIMEOUT)
|
||||
{
|
||||
dbg("PHY auto-negociation complete\r\n");
|
||||
|
||||
/* Read Auxiliary Control/Status Register */
|
||||
if (!fec_mii_read(fec_ch, phy_addr, BCM5222_ACSR, &settings))
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
dbg("auto negotiation failed, PHY Set the default mode\r\n");
|
||||
|
||||
/* Set the default mode (Full duplex, 100 Mbps) */
|
||||
if (!fec_mii_write(fec_ch, phy_addr, BCM5222_ACSR, settings = (BCM5222_ACSR_100BTX | BCM5222_ACSR_FDX)))
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set the proper duplex in the FEC now that we have auto-negotiated */
|
||||
if (settings & BCM5222_ACSR_FDX)
|
||||
fec_duplex(fec_ch, FEC_MII_FULL_DUPLEX);
|
||||
else
|
||||
fec_duplex(fec_ch, FEC_MII_HALF_DUPLEX);
|
||||
|
||||
dbg("PHY Mode: ");
|
||||
|
||||
if (settings & BCM5222_ACSR_100BTX)
|
||||
dbg("100Mbps\r\n");
|
||||
else
|
||||
dbg("10Mbps\r\n");
|
||||
|
||||
if (settings & BCM5222_ACSR_FDX)
|
||||
dbg("Full-duplex\r\n");
|
||||
else
|
||||
dbg("Half-duplex\r\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void bcm5222_get_reg(uint16_t* status0, uint16_t* status1)
|
||||
{
|
||||
fec_mii_read(0, 0x00, 0x00000000, &status0[0]);
|
||||
fec_mii_read(0, 0x00, 0x00000001, &status0[1]);
|
||||
fec_mii_read(0, 0x00, 0x00000004, &status0[4]);
|
||||
fec_mii_read(0, 0x00, 0x00000005, &status0[5]);
|
||||
fec_mii_read(0, 0x00, 0x00000006, &status0[6]);
|
||||
fec_mii_read(0, 0x00, 0x00000007, &status0[7]);
|
||||
fec_mii_read(0, 0x00, 0x00000008, &status0[8]);
|
||||
fec_mii_read(0, 0x00, 0x00000010, &status0[16]);
|
||||
fec_mii_read(0, 0x00, 0x00000011, &status0[17]);
|
||||
fec_mii_read(0, 0x00, 0x00000012, &status0[18]);
|
||||
fec_mii_read(0, 0x00, 0x00000013, &status0[19]);
|
||||
fec_mii_read(0, 0x00, 0x00000018, &status0[24]);
|
||||
fec_mii_read(0, 0x00, 0x00000019, &status0[25]);
|
||||
fec_mii_read(0, 0x00, 0x0000001B, &status0[27]);
|
||||
fec_mii_read(0, 0x00, 0x0000001C, &status0[28]);
|
||||
fec_mii_read(0, 0x00, 0x0000001E, &status0[30]);
|
||||
fec_mii_read(0, 0x01, 0x00000000, &status1[0]);
|
||||
fec_mii_read(0, 0x01, 0x00000001, &status1[1]);
|
||||
fec_mii_read(0, 0x01, 0x00000004, &status1[4]);
|
||||
fec_mii_read(0, 0x01, 0x00000005, &status1[5]);
|
||||
fec_mii_read(0, 0x01, 0x00000006, &status1[6]);
|
||||
fec_mii_read(0, 0x01, 0x00000007, &status1[7]);
|
||||
fec_mii_read(0, 0x01, 0x00000008, &status1[8]);
|
||||
fec_mii_read(0, 0x01, 0x00000010, &status1[16]);
|
||||
fec_mii_read(0, 0x01, 0x00000011, &status1[17]);
|
||||
fec_mii_read(0, 0x01, 0x00000012, &status1[18]);
|
||||
fec_mii_read(0, 0x01, 0x00000013, &status1[19]);
|
||||
fec_mii_read(0, 0x01, 0x00000018, &status1[24]);
|
||||
fec_mii_read(0, 0x01, 0x00000019, &status1[25]);
|
||||
fec_mii_read(0, 0x01, 0x0000001B, &status1[27]);
|
||||
fec_mii_read(0, 0x01, 0x0000001C, &status1[28]);
|
||||
fec_mii_read(0, 0x01, 0x0000001E, &status1[30]);
|
||||
}
|
||||
|
||||
114
net/bootp.c
Normal file
114
net/bootp.c
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* File: bootp.c
|
||||
* Purpose: Address Resolution Protocol routines.
|
||||
*
|
||||
* Notes:
|
||||
*/
|
||||
|
||||
#include "net.h"
|
||||
#include "bootp.h"
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include "bas_printf.h"
|
||||
|
||||
// #define DEBUG
|
||||
#include "debug.h"
|
||||
|
||||
#define TIMER_NETWORK 3 /* defines GPT3 as timer for this function */
|
||||
|
||||
static struct bootp_connection connection;
|
||||
#define XID 0x1234 /* this is arbitrary */
|
||||
#define MAX_TRIES 5 /* since UDP can fail */
|
||||
|
||||
void bootp_request(NIF *nif, uint8_t *pa)
|
||||
{
|
||||
/*
|
||||
* This function broadcasts a BOOTP request for the protocol
|
||||
* address "pa"
|
||||
*/
|
||||
uint8_t *addr;
|
||||
IP_ADDR broadcast = {255, 255, 255, 255};
|
||||
NBUF *nbuf;
|
||||
struct bootp_packet *p;
|
||||
int i, result;
|
||||
|
||||
nbuf = nbuf_alloc();
|
||||
if (nbuf == NULL)
|
||||
{
|
||||
xprintf("%s: couldn't allocate Tx buffer\r\n", __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
|
||||
p = (struct bootp_packet *) &nbuf->data[BOOTP_HDR_OFFSET];
|
||||
|
||||
/* Build the BOOTP request packet */
|
||||
p->type = BOOTP_TYPE_BOOTREQUEST;
|
||||
p->htype = BOOTP_HTYPE_ETHERNET;
|
||||
p->hlen = BOOTP_HLEN_ETHERNET;
|
||||
p->hops = 0;
|
||||
p->xid = XID;
|
||||
p->secs = 1;
|
||||
p->flags = BOOTP_FLAGS_BROADCAST;
|
||||
p->cl_addr = 0x0;
|
||||
p->yi_addr = 0x0;
|
||||
p->gi_addr = 0x0;
|
||||
|
||||
connection.nif = nif;
|
||||
addr = &nif->hwa[0];
|
||||
|
||||
for (i = 0; i < 6; i++)
|
||||
p->ch_addr[i] = addr[i];
|
||||
|
||||
nbuf->length = BOOTP_PACKET_LEN;
|
||||
|
||||
/* setup reply handler */
|
||||
udp_bind_port(BOOTP_CLIENT_PORT, bootp_handler);
|
||||
|
||||
for (i = 0; i < MAX_TRIES; i++)
|
||||
{
|
||||
/* Send the BOOTP request */
|
||||
result = udp_send(connection.nif, broadcast, BOOTP_CLIENT_PORT,
|
||||
BOOTP_SERVER_PORT, nbuf);
|
||||
dbg("sent bootp request\r\n");
|
||||
if (result == true)
|
||||
break;
|
||||
}
|
||||
|
||||
/* release handler */
|
||||
udp_free_port(BOOTP_CLIENT_PORT);
|
||||
|
||||
if (result == 0)
|
||||
nbuf_free(nbuf);
|
||||
}
|
||||
|
||||
void bootp_handler(NIF *nif, NBUF *nbuf)
|
||||
{
|
||||
/*
|
||||
* BOOTP protocol handler
|
||||
*/
|
||||
struct bootp_packet *rx_p;
|
||||
udp_frame_hdr *udpframe;
|
||||
|
||||
(void) udpframe; /* FIXME: just to avoid compiler warning */
|
||||
dbg("\r\n");
|
||||
|
||||
rx_p = (struct bootp_packet *) &nbuf->data[nbuf->offset];
|
||||
udpframe = (udp_frame_hdr *) &nbuf->data[nbuf->offset - UDP_HDR_SIZE];
|
||||
|
||||
/*
|
||||
* check packet if it is valid and if it is really intended for us
|
||||
*/
|
||||
|
||||
if (rx_p->type == BOOTP_TYPE_BOOTREPLY && rx_p->xid == XID)
|
||||
{
|
||||
dbg("received bootp reply\r\n");
|
||||
/* seems to be valid */
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
dbg("received invalid bootp reply\r\n");
|
||||
/* not valid */
|
||||
return;
|
||||
}
|
||||
}
|
||||
239
net/fecbd.c
Normal file
239
net/fecbd.c
Normal file
@@ -0,0 +1,239 @@
|
||||
/*
|
||||
* 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 <stddef.h>
|
||||
|
||||
//#define DBG_FECBD
|
||||
#ifdef DBG_FECBD
|
||||
#define dbg(format, arg...) do { xprintf("DEBUG: " format, ##arg); } while (0)
|
||||
#else
|
||||
#define dbg(format, arg...) do { ; } while (0)
|
||||
#endif /* DBG_FECBD */
|
||||
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
static FECBD unaligned_bds[(2 * NRXBD) + (2 * NTXBD) + 1];
|
||||
|
||||
/*
|
||||
* These pointers are used to reference into the chunck of data set
|
||||
* aside for buffer descriptors
|
||||
*/
|
||||
static FECBD *RxBD;
|
||||
static 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;
|
||||
|
||||
dbg("\r\n");
|
||||
|
||||
/*
|
||||
* Align Buffer Descriptors to 4-byte boundary
|
||||
*/
|
||||
RxBD = (FECBD *)(((int) unaligned_bds + 3) & 0xFFFFFFFC);
|
||||
TxBD = (FECBD *)((int) RxBD + (sizeof(FECBD) * 2 * NRXBD));
|
||||
|
||||
dbg("initialise RX buffer descriptor ring\r\n");
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
dbg("could not allocate network buffer\r\n");
|
||||
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;
|
||||
|
||||
dbg("initialise TX buffer descriptor ring\r\n");
|
||||
|
||||
/*
|
||||
* 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 DBG_FECBD
|
||||
int i;
|
||||
|
||||
xprintf("\n------------ FEC%d BDs -----------\n",ch);
|
||||
xprintf("RxBD Ring\n");
|
||||
for (i = 0; i < NRXBD; i++)
|
||||
{
|
||||
xprintf("%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);
|
||||
}
|
||||
xprintf("TxBD Ring\n");
|
||||
for (i = 0; i < NTXBD; i++)
|
||||
{
|
||||
xprintf("%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);
|
||||
}
|
||||
xprintf("--------------------------------\n\n");
|
||||
#endif /* DBG_FECBD */
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
317
net/ip.c
Normal file
317
net/ip.c
Normal file
@@ -0,0 +1,317 @@
|
||||
/*
|
||||
* File: ip.c
|
||||
* Purpose: Internet Protcol device driver
|
||||
*
|
||||
* Notes:
|
||||
*
|
||||
* Modifications:
|
||||
*/
|
||||
#include <bas_types.h>
|
||||
#include "net.h"
|
||||
#include "bas_printf.h"
|
||||
#include "bas_string.h"
|
||||
|
||||
|
||||
//#define IP_DEBUG
|
||||
#if defined(IP_DEBUG)
|
||||
#define dbg(format, arg...) do { xprintf("DEBUG: %s(): " format, __FUNCTION__, ##arg); } while (0)
|
||||
#else
|
||||
#define dbg(format, arg...) do { ; } while (0)
|
||||
#endif
|
||||
|
||||
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];
|
||||
}
|
||||
dbg("info is NULL!\n\t");
|
||||
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;
|
||||
IP_ADDR bc = { 255, 255, 255, 255 };
|
||||
int i;
|
||||
|
||||
info = nif_get_protocol_info(nif, ETH_FRM_IP);
|
||||
|
||||
if (memcmp(destip, bc, 4) == 0)
|
||||
{
|
||||
dbg("destip is broadcast address, no gateway needed\r\n");
|
||||
return destip;
|
||||
}
|
||||
|
||||
/* 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
|
||||
*/
|
||||
IP_ADDR bc = { 255, 255, 255, 255};
|
||||
if (memcmp(bc, dest, 4) != 0)
|
||||
{
|
||||
route = ip_resolve_route(nif, dest);
|
||||
if (route == NULL)
|
||||
{
|
||||
dbg("Unable to locate %d.%d.%d.%d\r\n",
|
||||
dest[0], dest[1], dest[2], dest[3]);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
route = bc;
|
||||
dbg("route = broadcast\r\n");
|
||||
dbg("nif = %p\r\n", nif);
|
||||
dbg("nif->send = %p\r\n", nif->send);
|
||||
}
|
||||
|
||||
return nif->send(nif, route, &nif->hwa[0], ETH_FRM_IP, pNbuf);
|
||||
}
|
||||
|
||||
#if defined(DEBUG_PRINT)
|
||||
void dump_ip_frame(ip_frame_hdr *ipframe)
|
||||
{
|
||||
xprintf("Version: %02X\n", ((ipframe->version_ihl & 0x00f0) >> 4));
|
||||
xprintf("IHL: %02X\n", ipframe->version_ihl & 0x000f);
|
||||
xprintf("Service: %02X\n", ipframe->service_type);
|
||||
xprintf("Length: %04X\n", ipframe->total_length);
|
||||
xprintf("Ident: %04X\n", ipframe->identification);
|
||||
xprintf("Flags: %02X\n", ((ipframe->flags_frag_offset & 0xC000) >> 14));
|
||||
xprintf("Frag: %04X\n", ipframe->flags_frag_offset & 0x3FFF);
|
||||
xprintf("TTL: %02X\n", ipframe->ttl);
|
||||
xprintf("Protocol: %02X\n", ipframe->protocol);
|
||||
xprintf("Chksum: %04X\n", ipframe->checksum);
|
||||
xprintf("Source : %d.%d.%d.%d\n",
|
||||
ipframe->source_addr[0],
|
||||
ipframe->source_addr[1],
|
||||
ipframe->source_addr[2],
|
||||
ipframe->source_addr[3]);
|
||||
xprintf("Dest : %d.%d.%d.%d\n",
|
||||
ipframe->dest_addr[0],
|
||||
ipframe->dest_addr[1],
|
||||
ipframe->dest_addr[2],
|
||||
ipframe->dest_addr[3]);
|
||||
xprintf("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;
|
||||
|
||||
dbg("packet received\r\n");
|
||||
|
||||
ipframe = (ip_frame_hdr *) &pNbuf->data[pNbuf->offset];
|
||||
|
||||
/*
|
||||
* Verify valid IP header and destination IP
|
||||
*/
|
||||
if (!validate_ip_hdr(nif, ipframe))
|
||||
{
|
||||
dbg("not a valid IP packet!\r\n");
|
||||
|
||||
nbuf_free(pNbuf);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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:
|
||||
dbg("no protocol handler registered for protocol %d\r\n",
|
||||
__FUNCTION__, IP_PROTOCOL(ipframe));
|
||||
nbuf_free(pNbuf);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
224
net/nbuf.c
Normal file
224
net/nbuf.c
Normal file
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* File: nbuf.c
|
||||
* Purpose: Implementation of network buffer scheme.
|
||||
*
|
||||
* Notes:
|
||||
*/
|
||||
#include "queue.h"
|
||||
#include "net.h"
|
||||
#include "driver_mem.h"
|
||||
#include "exceptions.h"
|
||||
#include "bas_types.h"
|
||||
#include "bas_printf.h"
|
||||
|
||||
|
||||
#define DBG_NBUF
|
||||
#if defined(DBG_NBUF)
|
||||
#define dbg(format, arg...) do { xprintf("DEBUG: %s(): " format, __FUNCTION__, ##arg); } while (0)
|
||||
#else
|
||||
#define dbg(format, arg...) do { ; } while (0)
|
||||
#endif /* DBG_NBUF */
|
||||
/*
|
||||
* Queues used for network buffer storage
|
||||
*/
|
||||
QUEUE nbuf_queue[NBUF_MAXQ];
|
||||
|
||||
/*
|
||||
* Some devices require line-aligned buffers. In order to accomplish
|
||||
* this, the nbuf data is over-allocated and adjusted. The following
|
||||
* array keeps track of the original data pointer returned by malloc
|
||||
*/
|
||||
uint8_t *unaligned_buffers[NBUF_MAX];
|
||||
|
||||
/*
|
||||
* Initialize all the network buffer queues
|
||||
*
|
||||
* Return Value:
|
||||
* 0 success
|
||||
* 1 failure
|
||||
*/
|
||||
int nbuf_init(void)
|
||||
{
|
||||
int i;
|
||||
NBUF *nbuf;
|
||||
|
||||
for (i = 0; i < NBUF_MAXQ; ++i)
|
||||
{
|
||||
/* Initialize all the queues */
|
||||
queue_init(&nbuf_queue[i]);
|
||||
}
|
||||
|
||||
dbg("Creating %d net buffers of %d bytes\r\n", NBUF_MAX, NBUF_SZ);
|
||||
|
||||
for (i = 0; i < NBUF_MAX; ++i)
|
||||
{
|
||||
/* Allocate memory for the network buffer structure */
|
||||
nbuf = (NBUF *) driver_mem_alloc(sizeof(NBUF));
|
||||
if (!nbuf)
|
||||
{
|
||||
xprintf("failed to allocate nbuf\r\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Allocate memory for the actual data */
|
||||
unaligned_buffers[i] = driver_mem_alloc(NBUF_SZ + 16);
|
||||
nbuf->data = (uint8_t *)((uint32_t)(unaligned_buffers[i] + 15) & 0xFFFFFFF0);
|
||||
if (!nbuf->data)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Initialize the network buffer */
|
||||
nbuf->offset = 0;
|
||||
nbuf->length = 0;
|
||||
|
||||
/* Add the network buffer to the free list */
|
||||
queue_add(&nbuf_queue[NBUF_FREE], (QNODE *)nbuf);
|
||||
}
|
||||
|
||||
dbg("NBUF allocation complete\r\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return all the allocated memory to the heap
|
||||
*/
|
||||
void nbuf_flush(void)
|
||||
{
|
||||
NBUF *nbuf;
|
||||
int i;
|
||||
int level = set_ipl(7);
|
||||
int n = 0;
|
||||
|
||||
for (i = 0; i < NBUF_MAX; ++i)
|
||||
driver_mem_free((uint8_t *) unaligned_buffers[i]);
|
||||
|
||||
for (i = 0; i < NBUF_MAXQ; ++i)
|
||||
{
|
||||
while ((nbuf = (NBUF *) queue_remove(&nbuf_queue[i])) != NULL)
|
||||
{
|
||||
driver_mem_free(nbuf);
|
||||
++n;
|
||||
}
|
||||
}
|
||||
set_ipl(level);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a network buffer from the free list
|
||||
*
|
||||
* Return Value:
|
||||
* Pointer to a free network buffer
|
||||
* NULL if none are available
|
||||
*/
|
||||
NBUF *nbuf_alloc(void)
|
||||
{
|
||||
NBUF *nbuf;
|
||||
int level = set_ipl(7);
|
||||
|
||||
nbuf = (NBUF *) queue_remove(&nbuf_queue[NBUF_FREE]);
|
||||
set_ipl(level);
|
||||
|
||||
return nbuf;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the specified network buffer back to the free list
|
||||
*
|
||||
* Parameters:
|
||||
* nbuf Buffer to add back to the free list
|
||||
*/
|
||||
void nbuf_free(NBUF *nbuf)
|
||||
{
|
||||
int level = set_ipl(7);
|
||||
|
||||
nbuf->offset = 0;
|
||||
nbuf->length = NBUF_SZ;
|
||||
queue_add(&nbuf_queue[NBUF_FREE],(QNODE *) nbuf);
|
||||
|
||||
set_ipl(level);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove a network buffer from the specified queue
|
||||
*
|
||||
* Parameters:
|
||||
* q The index that identifies the queue to pull the buffer from
|
||||
*/
|
||||
NBUF *nbuf_remove(int q)
|
||||
{
|
||||
NBUF *nbuf;
|
||||
int level = set_ipl(7);
|
||||
|
||||
nbuf = (NBUF *) queue_remove(&nbuf_queue[q]);
|
||||
set_ipl(level);
|
||||
|
||||
return nbuf;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a network buffer to the specified queue
|
||||
*
|
||||
* Parameters:
|
||||
* q The index that identifies the queue to add the buffer to
|
||||
*/
|
||||
void nbuf_add(int q, NBUF *nbuf)
|
||||
{
|
||||
int level = set_ipl(7);
|
||||
|
||||
queue_add(&nbuf_queue[q], (QNODE *) nbuf);
|
||||
set_ipl(level);
|
||||
}
|
||||
|
||||
/*
|
||||
* Put all the network buffers back into the free list
|
||||
*/
|
||||
void nbuf_reset(void)
|
||||
{
|
||||
NBUF *nbuf;
|
||||
int i;
|
||||
int level = set_ipl(7);
|
||||
|
||||
for (i = 1; i < NBUF_MAXQ; ++i)
|
||||
{
|
||||
while ((nbuf = nbuf_remove(i)) != NULL)
|
||||
nbuf_free(nbuf);
|
||||
}
|
||||
set_ipl(level);
|
||||
}
|
||||
|
||||
/*
|
||||
* Display all the nbuf queues
|
||||
*/
|
||||
void nbuf_debug_dump(void)
|
||||
{
|
||||
#ifdef DBG_NBUF
|
||||
NBUF *nbuf;
|
||||
int i;
|
||||
int j;
|
||||
int level;
|
||||
|
||||
level = set_ipl(7);
|
||||
|
||||
for (i = 0; i < NBUF_MAXQ; ++i)
|
||||
{
|
||||
dbg("\r\n\r\nQueue #%d\r\n\r\n", i);
|
||||
dbg("\tBuffer Location\tOffset\tLength\r\n");
|
||||
dbg("--------------------------------------\r\n");
|
||||
j = 0;
|
||||
nbuf = (NBUF *) queue_peek(&nbuf_queue[i]);
|
||||
|
||||
while (nbuf != NULL)
|
||||
{
|
||||
dbg("%d\t0x%08x\t0x%04x\t0x%04x\r\n", j++, nbuf->data,
|
||||
nbuf->offset,
|
||||
nbuf->length);
|
||||
nbuf = (NBUF *) nbuf->node.next;
|
||||
}
|
||||
}
|
||||
dbg("\r\n");
|
||||
|
||||
set_ipl(level);
|
||||
#endif /* DBG_NBUF */
|
||||
}
|
||||
202
net/net_timer.c
Normal file
202
net/net_timer.c
Normal file
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* File: net_timer.c
|
||||
* Purpose: Provide a timer use by the BaS network as a timeout
|
||||
* indicator
|
||||
*
|
||||
* Notes:
|
||||
*/
|
||||
|
||||
#include "net_timer.h"
|
||||
#include "bas_printf.h"
|
||||
#include "MCF5475.h"
|
||||
#include "interrupts.h"
|
||||
|
||||
//#define DBG_TMR
|
||||
#ifdef DBG_TMR
|
||||
#define dbg(format, arg...) do { xprintf("DEBUG: %s(): " format, __FUNCTION__, ##arg); } while (0)
|
||||
#else
|
||||
#define dbg(format, arg...) do { ; } while (0)
|
||||
#endif /* DBG_TMR */
|
||||
|
||||
|
||||
#if defined(MACHINE_FIREBEE)
|
||||
#include "firebee.h"
|
||||
#elif defined(MACHINE_M5484LITE)
|
||||
#include "m5484l.h"
|
||||
#elif defined(MACHINE_M54455)
|
||||
#include "m54455.h"
|
||||
#else
|
||||
#error unknown machine!
|
||||
#endif
|
||||
|
||||
static NET_TIMER net_timer[4] =
|
||||
{
|
||||
{0, 0, 0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
|
||||
bool timer_default_isr(void *not_used, NET_TIMER *t)
|
||||
{
|
||||
(void) not_used;
|
||||
|
||||
/*
|
||||
* Clear the pending event
|
||||
*/
|
||||
MCF_GPT_GMS(t->ch) = 0;
|
||||
|
||||
dbg("timer isr called for timer channel %d\r\n");
|
||||
|
||||
/*
|
||||
* Clear the reference - the desired seconds have expired
|
||||
*/
|
||||
t->reference = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void timer_irq_enable(uint8_t ch)
|
||||
{
|
||||
/*
|
||||
* Setup the appropriate ICR
|
||||
*/
|
||||
MCF_INTC_ICR(TIMER_VECTOR(ch) - 64) = MCF_INTC_ICR_IP(net_timer[ch].pri) |
|
||||
MCF_INTC_ICR_IL(net_timer[ch].lvl);
|
||||
|
||||
/*
|
||||
* Unmask the FEC interrupt in the interrupt controller
|
||||
*/
|
||||
if (ch == 3)
|
||||
{
|
||||
MCF_INTC_IMRH &= ~MCF_INTC_IMRH_INT_MASK59;
|
||||
}
|
||||
else if (ch == 2)
|
||||
{
|
||||
MCF_INTC_IMRH &= ~MCF_INTC_IMRH_INT_MASK60;
|
||||
}
|
||||
else if (ch == 1)
|
||||
{
|
||||
MCF_INTC_IMRH &= ~MCF_INTC_IMRH_INT_MASK61;
|
||||
}
|
||||
else
|
||||
{
|
||||
MCF_INTC_IMRH &= ~MCF_INTC_IMRH_INT_MASK62;
|
||||
}
|
||||
}
|
||||
|
||||
bool timer_set_secs(uint8_t ch, uint32_t secs)
|
||||
{
|
||||
uint16_t timeout;
|
||||
|
||||
/*
|
||||
* Reset the timer
|
||||
*/
|
||||
MCF_GPT_GMS(ch) = 0;
|
||||
|
||||
/*
|
||||
* Get the timeout in seconds
|
||||
*/
|
||||
timeout = (uint16_t)(secs * net_timer[ch].cnt);
|
||||
|
||||
/*
|
||||
* Set the reference indicating that we have not yet reached the
|
||||
* desired timeout
|
||||
*/
|
||||
net_timer[ch].reference = 1;
|
||||
|
||||
/*
|
||||
* Enable timer interrupt to the processor
|
||||
*/
|
||||
timer_irq_enable(ch);
|
||||
|
||||
/*
|
||||
* Enable the timer using the pre-calculated values
|
||||
*/
|
||||
MCF_GPT_GCIR(ch) = (0
|
||||
| MCF_GPT_GCIR_CNT(timeout)
|
||||
| MCF_GPT_GCIR_PRE(net_timer[ch].pre)
|
||||
);
|
||||
MCF_GPT_GMS(ch) = net_timer[ch].gms;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t timer_get_reference(uint8_t ch)
|
||||
{
|
||||
return (uint32_t) net_timer[ch].reference;
|
||||
}
|
||||
|
||||
bool timer_init(uint8_t ch, uint8_t lvl, uint8_t pri)
|
||||
{
|
||||
/*
|
||||
* Initialize the timer to expire after one second
|
||||
*
|
||||
* This routine should only be called by the project (board) specific
|
||||
* initialization code.
|
||||
*/
|
||||
if (!((ch <= 3) && (lvl <= 7) && (lvl >= 1) && (pri <= 7)))
|
||||
{
|
||||
dbg("illegal parameters (ch=%d, lvl=%d, pri=%d)\r\n", ch, lvl, pri);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset the timer
|
||||
*/
|
||||
MCF_GPT_GMS(ch) = 0;
|
||||
|
||||
/*
|
||||
* Save off the channel, and interrupt lvl/pri information
|
||||
*/
|
||||
net_timer[ch].ch = ch;
|
||||
net_timer[ch].lvl = lvl;
|
||||
net_timer[ch].pri = pri;
|
||||
|
||||
/*
|
||||
* Register the timer interrupt handler
|
||||
*/
|
||||
if (!isr_register_handler(TIMER_VECTOR(ch), 3, 0,
|
||||
(bool (*)(void *,void *)) timer_default_isr,
|
||||
NULL,
|
||||
(void *) &net_timer[ch])
|
||||
)
|
||||
{
|
||||
dbg("could not register timer interrupt handler\r\n");
|
||||
return false;
|
||||
}
|
||||
dbg("timer handler registered\r\n", __FUNCTION__);
|
||||
|
||||
/*
|
||||
* Calculate the require CNT value to get a 1 second timeout
|
||||
*
|
||||
* 1 sec = CNT * Clk Period * PRE
|
||||
* CNT = 1 sec / (Clk Period * PRE)
|
||||
* CNT = Clk Freq / PRE
|
||||
*
|
||||
* The system clock frequency is defined as SYSTEM_CLOCK and
|
||||
* is given in MHz. We need to multiple it by 1000000 to get the
|
||||
* true value. If we assume PRE to be the maximum of 0xFFFF,
|
||||
* then the CNT value needed to achieve a 1 second timeout is
|
||||
* given by:
|
||||
*
|
||||
* CNT = SYSTEM_CLOCK * (1000000/0xFFFF)
|
||||
*/
|
||||
net_timer[ch].pre = 0xFFFF;
|
||||
net_timer[ch].cnt = (uint16_t) ((SYSCLK / 1000) * (1000000 / 0xFFFF));
|
||||
|
||||
/*
|
||||
* Save off the appropriate mode select register value
|
||||
*/
|
||||
net_timer[ch].gms = (0
|
||||
| MCF_GPT_GMS_TMS_GPIO
|
||||
| MCF_GPT_GMS_IEN
|
||||
| MCF_GPT_GMS_SC
|
||||
| MCF_GPT_GMS_CE
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
130
net/nif.c
Normal file
130
net/nif.c
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* File: nif.c
|
||||
* Purpose: Network InterFace routines
|
||||
*
|
||||
* Notes:
|
||||
*
|
||||
* Modifications:
|
||||
*
|
||||
*/
|
||||
#include "net.h"
|
||||
#include "bas_types.h"
|
||||
#include "bas_printf.h"
|
||||
|
||||
#define DBG_NIF
|
||||
#ifdef DBG_NIF
|
||||
#define dbg(format, arg...) do { xprintf("DEBUG: %s(): " format, __FUNCTION__, ##arg); } while (0)
|
||||
#else
|
||||
#define dbg(format, arg...) do { ; } while (0)
|
||||
#endif /* DBG_NIF */
|
||||
|
||||
int nif_protocol_exist(NIF *nif, uint16_t protocol)
|
||||
{
|
||||
/*
|
||||
* This function searches the list of supported protocols
|
||||
* on the particular NIF and if a protocol handler exists,
|
||||
* true is returned. This function is useful for network cards
|
||||
* that needn't read in the entire frame but can discard frames
|
||||
* arbitrarily.
|
||||
*/
|
||||
int index;
|
||||
|
||||
for (index = 0; index < nif->num_protocol; ++index)
|
||||
{
|
||||
if (nif->protocol[index].protocol == protocol)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void nif_protocol_handler(NIF *nif, uint16_t protocol, NBUF *pNbuf)
|
||||
{
|
||||
/*
|
||||
* This function searches the list of supported protocols
|
||||
* on the particular NIF and if a protocol handler exists,
|
||||
* the protocol handler is invoked. This routine called by
|
||||
* network device driver after receiving a frame.
|
||||
*/
|
||||
int index;
|
||||
|
||||
for (index = 0; index < nif->num_protocol; ++index)
|
||||
{
|
||||
if (nif->protocol[index].protocol == protocol)
|
||||
{
|
||||
dbg("call protocol handler for protocol %d at %p\r\n", protocol,
|
||||
nif->protocol[index].handler);
|
||||
nif->protocol[index].handler(nif,pNbuf);
|
||||
return;
|
||||
}
|
||||
}
|
||||
dbg("no protocol handler found for protocol %d\r\n", protocol);
|
||||
}
|
||||
|
||||
void *nif_get_protocol_info(NIF *nif, uint16_t protocol)
|
||||
{
|
||||
/*
|
||||
* This function searches the list of supported protocols
|
||||
* on the particular NIF and returns a pointer to the
|
||||
* config info for 'protocol', otherwise NULL is returned.
|
||||
*/
|
||||
int index;
|
||||
|
||||
for (index = 0; index < nif->num_protocol; ++index)
|
||||
{
|
||||
if (nif->protocol[index].protocol == protocol)
|
||||
return (void *)nif->protocol[index].info;
|
||||
}
|
||||
return (void *)0;
|
||||
}
|
||||
|
||||
int nif_bind_protocol(NIF *nif, uint16_t protocol, void (*handler)(NIF *,NBUF *),
|
||||
void *info)
|
||||
{
|
||||
/*
|
||||
* This function registers 'protocol' as a supported
|
||||
* protocol in 'nif'.
|
||||
*/
|
||||
if (nif->num_protocol < (MAX_SUP_PROTO - 1))
|
||||
{
|
||||
nif->protocol[nif->num_protocol].protocol = protocol;
|
||||
nif->protocol[nif->num_protocol].handler = (void(*)(NIF *, NBUF *)) handler;
|
||||
nif->protocol[nif->num_protocol].info = info;
|
||||
++nif->num_protocol;
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
NIF *nif_init (NIF *nif)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ETH_ADDR_LEN; ++i)
|
||||
{
|
||||
nif->hwa[i] = 0;
|
||||
nif->broadcast[i] = 0xFF;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_SUP_PROTO; ++i)
|
||||
{
|
||||
nif->protocol[i].protocol = 0;
|
||||
nif->protocol[i].handler = 0;
|
||||
nif->protocol[i].info = 0;
|
||||
}
|
||||
nif->num_protocol = 0;
|
||||
|
||||
nif->mtu = 0;
|
||||
nif->ch = 0;
|
||||
nif->send = 0;
|
||||
|
||||
nif->f_rx = 0;
|
||||
nif->f_tx = 0;
|
||||
nif->f_rx_err = 0;
|
||||
nif->f_tx_err = 0;
|
||||
nif->f_err = 0;
|
||||
|
||||
return nif;
|
||||
}
|
||||
114
net/queue.c
Normal file
114
net/queue.c
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* File: queue.c
|
||||
* Purpose: Implement a first in, first out linked list
|
||||
*
|
||||
* Notes:
|
||||
*/
|
||||
#include "bas_string.h"
|
||||
#include "queue.h"
|
||||
|
||||
/*
|
||||
* Initialize the specified queue to an empty state
|
||||
*
|
||||
* Parameters:
|
||||
* q Pointer to queue structure
|
||||
*/
|
||||
void queue_init(QUEUE *q)
|
||||
{
|
||||
q->head = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for an empty queue
|
||||
*
|
||||
* Parameters:
|
||||
* q Pointer to queue structure
|
||||
*
|
||||
* Return Value:
|
||||
* 1 if Queue is empty
|
||||
* 0 otherwise
|
||||
*/
|
||||
int queue_isempty(QUEUE *q)
|
||||
{
|
||||
return (q->head == NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add an item to the end of the queue
|
||||
*
|
||||
* Parameters:
|
||||
* q Pointer to queue structure
|
||||
* node New node to add to the queue
|
||||
*/
|
||||
void queue_add(QUEUE *q, QNODE *node)
|
||||
{
|
||||
if (queue_isempty(q))
|
||||
{
|
||||
q->head = q->tail = node;
|
||||
}
|
||||
else
|
||||
{
|
||||
q->tail->next = node;
|
||||
q->tail = node;
|
||||
}
|
||||
|
||||
node->next = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove and return first (oldest) entry from the specified queue
|
||||
*
|
||||
* Parameters:
|
||||
* q Pointer to queue structure
|
||||
*
|
||||
* Return Value:
|
||||
* Node at head of queue - NULL if queue is empty
|
||||
*/
|
||||
QNODE *queue_remove(QUEUE *q)
|
||||
{
|
||||
QNODE *oldest;
|
||||
|
||||
if (queue_isempty(q))
|
||||
return NULL;
|
||||
|
||||
oldest = q->head;
|
||||
q->head = oldest->next;
|
||||
return oldest;
|
||||
}
|
||||
|
||||
/*
|
||||
* Peek into the queue and return pointer to first (oldest) entry.
|
||||
* The queue is not modified
|
||||
*
|
||||
* Parameters:
|
||||
* q Pointer to queue structure
|
||||
*
|
||||
* Return Value:
|
||||
* Node at head of queue - NULL if queue is empty
|
||||
*/
|
||||
QNODE *queue_peek(QUEUE *q)
|
||||
{
|
||||
return q->head;
|
||||
}
|
||||
|
||||
/*
|
||||
* Move entire contents of one queue to the other
|
||||
*
|
||||
* Parameters:
|
||||
* src Pointer to source queue
|
||||
* dst Pointer to destination queue
|
||||
*/
|
||||
void queue_move(QUEUE *dst, QUEUE *src)
|
||||
{
|
||||
if (queue_isempty(src))
|
||||
return;
|
||||
|
||||
if (queue_isempty(dst))
|
||||
dst->head = src->head;
|
||||
else
|
||||
dst->tail->next = src->head;
|
||||
|
||||
dst->tail = src->tail;
|
||||
src->head = NULL;
|
||||
return;
|
||||
}
|
||||
659
net/tftp.c
Normal file
659
net/tftp.c
Normal file
@@ -0,0 +1,659 @@
|
||||
/*
|
||||
* File: tftp.c
|
||||
* Purpose: Trivial File Transfer Protocol driver for reading a file
|
||||
* from a remote host.
|
||||
*
|
||||
* Notes: See RFC 1350
|
||||
*
|
||||
* Modifications:
|
||||
*
|
||||
*/
|
||||
|
||||
#include "bas_types.h"
|
||||
#include "bas_printf.h"
|
||||
#include "bas_string.h"
|
||||
#include "net.h"
|
||||
#include "net_timer.h"
|
||||
|
||||
#define TIMER_NETWORK 3
|
||||
|
||||
/* The one and only TFTP connection */
|
||||
static TFTP_Connection tcxn;
|
||||
|
||||
/* Progress Indicators */
|
||||
static char hash[] = {'-','\\','|','/'};
|
||||
static int ihash = 0;
|
||||
|
||||
static int tftp_rwrq(void)
|
||||
{
|
||||
NBUF *pNbuf;
|
||||
RWRQ *rwrq;
|
||||
int i, j, result;
|
||||
|
||||
pNbuf = nbuf_alloc();
|
||||
if (pNbuf == NULL)
|
||||
{
|
||||
xprintf("TFTP: tftp_rwrq() couldn't allocate Tx buffer\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
rwrq = (RWRQ *)&pNbuf->data[TFTP_HDR_OFFSET];
|
||||
|
||||
/* Indicate a R/WRQ */
|
||||
rwrq->opcode = tcxn.dir;
|
||||
|
||||
/* Copy in filename */
|
||||
strcpy(&rwrq->filename_mode[0], tcxn.file);
|
||||
i = strlen(tcxn.file) + 1;
|
||||
|
||||
/* Indicate transfer type */
|
||||
strcpy (&rwrq->filename_mode[i], OCTET);
|
||||
|
||||
for (j = 0; j < 3; ++j)
|
||||
{
|
||||
pNbuf->length = (uint16_t)(i + strlen(OCTET) + 1 + 2);
|
||||
result = udp_send(tcxn.nif,
|
||||
tcxn.server_ip,
|
||||
tcxn.my_port,
|
||||
tcxn.server_port,
|
||||
pNbuf);
|
||||
if (result == 1)
|
||||
break;
|
||||
}
|
||||
|
||||
if (result == 0)
|
||||
nbuf_free(pNbuf);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int tftp_ack(uint16_t blocknum)
|
||||
{
|
||||
ACK *ack;
|
||||
NBUF *pNbuf;
|
||||
int i, result;
|
||||
|
||||
pNbuf = nbuf_alloc();
|
||||
if (pNbuf == NULL)
|
||||
{
|
||||
xprintf("TFTP: tftp_ack() couldn't allocate Tx buffer\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ack = (ACK *)&pNbuf->data[TFTP_HDR_OFFSET];
|
||||
ack->opcode = TFTP_ACK;
|
||||
ack->blocknum = blocknum;
|
||||
|
||||
for (i = 0; i < 3; ++i)
|
||||
{
|
||||
pNbuf->length = 4;
|
||||
result = udp_send(tcxn.nif,
|
||||
tcxn.server_ip,
|
||||
tcxn.my_port,
|
||||
tcxn.server_port,
|
||||
pNbuf);
|
||||
if (result == 1)
|
||||
break;
|
||||
}
|
||||
|
||||
if (result == 0)
|
||||
nbuf_free(pNbuf);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int tftp_error(uint16_t error_code, uint16_t server_port)
|
||||
{
|
||||
ERROR *err;
|
||||
NBUF *pNbuf;
|
||||
int i, result;
|
||||
|
||||
pNbuf = nbuf_alloc();
|
||||
if (pNbuf == NULL)
|
||||
{
|
||||
xprintf("TFTP: tftp_error() couldn't allocate Tx buffer\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = (ERROR *)&pNbuf->data[TFTP_HDR_OFFSET];
|
||||
err->opcode = TFTP_ERROR;
|
||||
err->code = error_code;
|
||||
err->msg[0] = '\0';
|
||||
|
||||
for (i = 0; i < 3; ++i)
|
||||
{
|
||||
pNbuf->length = 5;
|
||||
result = udp_send(tcxn.nif,
|
||||
tcxn.server_ip,
|
||||
tcxn.my_port,
|
||||
server_port,
|
||||
pNbuf);
|
||||
if (result == 1)
|
||||
break;
|
||||
}
|
||||
|
||||
if (result == 0)
|
||||
nbuf_free(pNbuf);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void tftp_handler(NIF *nif, NBUF *pNbuf)
|
||||
{
|
||||
union TFTPpacket *tftp_pkt;
|
||||
udp_frame_hdr *udpframe;
|
||||
static int cnt;
|
||||
(void) nif;
|
||||
|
||||
tftp_pkt = (union TFTPpacket *)&pNbuf->data[pNbuf->offset];
|
||||
udpframe = (udp_frame_hdr *)&pNbuf->data[pNbuf->offset - UDP_HDR_SIZE];
|
||||
|
||||
switch (tftp_pkt->generic.opcode)
|
||||
{
|
||||
case TFTP_DATA:
|
||||
/* Is this the expected block number? */
|
||||
if (tftp_pkt->data.blocknum == tcxn.exp_blocknum)
|
||||
{
|
||||
/* Is this is the first data block received? */
|
||||
if (tftp_pkt->data.blocknum == 1)
|
||||
{
|
||||
/* Save the server's transfer ID */
|
||||
tcxn.server_port = UDP_SOURCE(udpframe);
|
||||
|
||||
/* Mark the connection as open */
|
||||
tcxn.open = true;
|
||||
|
||||
/* Start progress indicator */
|
||||
xprintf("%c", hash[0]);
|
||||
cnt = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Check the server's transfer ID */
|
||||
if (tcxn.server_port != UDP_SOURCE(udpframe))
|
||||
{
|
||||
xprintf("TFTP: Invalid server port: %d\n", \
|
||||
UDP_SOURCE(udpframe));
|
||||
|
||||
/* Send ERROR packet to source */
|
||||
tftp_error(TFTP_ERR_TID, UDP_SOURCE(udpframe));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add the buffer to the TFTP queue */
|
||||
queue_add(&tcxn.queue, (QNODE *)pNbuf);
|
||||
|
||||
/* Update number of the next block expected */
|
||||
tcxn.exp_blocknum++;
|
||||
|
||||
/* Increment number of bytes received counter */
|
||||
tcxn.bytes_recv += (pNbuf->length - 4);
|
||||
|
||||
/* Update progress indicator */
|
||||
if (++cnt == 50)
|
||||
{
|
||||
ihash = (ihash + 1) % 4;
|
||||
xprintf("\r");
|
||||
xprintf("%c", hash[ihash]);
|
||||
cnt = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tftp_pkt->data.blocknum < tcxn.exp_blocknum)
|
||||
{
|
||||
/* Re-ACK this packet */
|
||||
tftp_ack(tftp_pkt->data.blocknum);
|
||||
}
|
||||
|
||||
/* This is NOT the block expected */
|
||||
xprintf("Exp: %d, ", tcxn.exp_blocknum);
|
||||
xprintf("Rcv: %d\n", tftp_pkt->data.blocknum);
|
||||
|
||||
/* Free the network buffer */
|
||||
nbuf_free(pNbuf);
|
||||
}
|
||||
break;
|
||||
case TFTP_ERROR:
|
||||
xprintf("\nTFTP Error #%d: ",tftp_pkt->error.code);
|
||||
xprintf("%s\n",tftp_pkt->error.msg);
|
||||
tcxn.error = true;
|
||||
/* Free the network buffer */
|
||||
nbuf_free(pNbuf);
|
||||
break;
|
||||
case TFTP_ACK:
|
||||
if (tftp_pkt->ack.blocknum == tcxn.exp_blocknum)
|
||||
{
|
||||
if (tftp_pkt->data.blocknum == 0)
|
||||
{ /* This is the first ACK received */
|
||||
|
||||
/* Save the server's transfer ID */
|
||||
tcxn.server_port = UDP_SOURCE(udpframe);
|
||||
|
||||
/* Mark the connection as open */
|
||||
tcxn.open = true;
|
||||
}
|
||||
else
|
||||
{ /* Check the server's transfer ID */
|
||||
if (tcxn.server_port != UDP_SOURCE(udpframe))
|
||||
{
|
||||
xprintf("TFTP: Invalid server port: %d\n", \
|
||||
UDP_SOURCE(udpframe));
|
||||
|
||||
/*Send ERROR packet to source */
|
||||
tftp_error(TFTP_ERR_TID, UDP_SOURCE(udpframe));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tcxn.exp_blocknum++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This is NOT the block number expected */
|
||||
xprintf("ACK Exp: %d, ", tcxn.exp_blocknum);
|
||||
xprintf("ACK Rcv: %d\n", tftp_pkt->ack.blocknum);
|
||||
}
|
||||
|
||||
/* Free the network buffer */
|
||||
nbuf_free(pNbuf);
|
||||
break;
|
||||
case TFTP_RRQ:
|
||||
case TFTP_WRQ:
|
||||
default:
|
||||
/* Free the network buffer */
|
||||
nbuf_free(pNbuf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void tftp_end(int success)
|
||||
{
|
||||
/*
|
||||
* Following a successful transfer the caller should pass in
|
||||
* true, there should have been no ERROR packets received, and
|
||||
* the connection should have been marked as closed by the
|
||||
* tftp_in_char() routine.
|
||||
*/
|
||||
if (success && !tcxn.error && (tcxn.open == false))
|
||||
{
|
||||
xprintf("\bTFTP transfer completed \n");
|
||||
xprintf("Read %d bytes (%d blocks)\n", \
|
||||
tcxn.bytes_recv, tcxn.exp_blocknum - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Send error packet to stifle the server */
|
||||
tftp_error(TFTP_ERR_ILL, tcxn.server_port);
|
||||
|
||||
xprintf("\bErrors in TFTP transfer.\n");
|
||||
xprintf("Read %d bytes (%d blocks)\n", \
|
||||
tcxn.bytes_recv, tcxn.exp_blocknum - 1);
|
||||
}
|
||||
|
||||
/* Free up any buffers left in the queue */
|
||||
while (!queue_isempty(&tcxn.queue))
|
||||
nbuf_free((NBUF *)queue_remove(&tcxn.queue));
|
||||
|
||||
/* Free the UDP port */
|
||||
udp_free_port(tcxn.my_port);
|
||||
}
|
||||
|
||||
int tftp_write(NIF *nif, char *fn, IP_ADDR_P server, uint32_t begin, uint32_t end)
|
||||
{
|
||||
DATA *data;
|
||||
NBUF *pNbuf;
|
||||
|
||||
uint32_t i, retries, bytes_to_send;
|
||||
uint16_t blocknum, this_size;
|
||||
uint8_t success, *current;
|
||||
int result;
|
||||
|
||||
if (fn == 0 || server == 0 || end < begin)
|
||||
return 0;
|
||||
|
||||
/* Setup initial connection status */
|
||||
tcxn.nif = nif;
|
||||
tcxn.file = fn;
|
||||
tcxn.server_ip[0] = server[0];
|
||||
tcxn.server_ip[1] = server[1];
|
||||
tcxn.server_ip[2] = server[2];
|
||||
tcxn.server_ip[3] = server[3];
|
||||
tcxn.server_port = UDP_PORT_TFTP;
|
||||
tcxn.exp_blocknum = 0;
|
||||
tcxn.dir = TFTP_WRQ;
|
||||
tcxn.open = false;
|
||||
tcxn.bytes_sent = 0;
|
||||
tcxn.error = false;
|
||||
|
||||
/* Use Mac address as pseudo-random port */
|
||||
udp_prime_port((uint16_t)((nif->hwa[4] << 8) | nif->hwa[5]));
|
||||
tcxn.my_port = udp_obtain_free_port();
|
||||
udp_bind_port(tcxn.my_port,&tftp_handler);
|
||||
|
||||
retries = 4;
|
||||
success = false;
|
||||
|
||||
while (--retries)
|
||||
{
|
||||
/* Make the TFTP Read/Write Request */
|
||||
if (!tftp_rwrq())
|
||||
{
|
||||
xprintf("Error: Couldn't send TFTP Write Request\n");
|
||||
udp_free_port(tcxn.my_port);
|
||||
return false;
|
||||
}
|
||||
|
||||
timer_set_secs(TIMER_NETWORK, TFTP_TIMEOUT);
|
||||
while (timer_get_reference(TIMER_NETWORK))
|
||||
{
|
||||
/* Has the server responded */
|
||||
if (tcxn.open)
|
||||
{
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the connection is open, we are done here */
|
||||
if (success || tcxn.error)
|
||||
break;
|
||||
}
|
||||
if (!retries)
|
||||
{
|
||||
xprintf("TFTP could not make connection to server.\n");
|
||||
udp_free_port(tcxn.my_port);
|
||||
return false;
|
||||
}
|
||||
else if (tcxn.error)
|
||||
{
|
||||
xprintf("\bErrors in TFTP upload.\n");
|
||||
udp_free_port(tcxn.my_port);
|
||||
return false;
|
||||
}
|
||||
|
||||
bytes_to_send = end - begin;
|
||||
current = (uint8_t *)begin;
|
||||
blocknum = 1;
|
||||
retries = 4;
|
||||
success = false;
|
||||
|
||||
while (--retries)
|
||||
{
|
||||
pNbuf = nbuf_alloc();
|
||||
if (pNbuf == NULL)
|
||||
{
|
||||
xprintf("TFTP: tftp_write() couldn't allocate Tx buffer\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Build the packet */
|
||||
data = (DATA *)&pNbuf->data[TFTP_HDR_OFFSET];
|
||||
data->blocknum = blocknum;
|
||||
data->opcode = TFTP_DATA;
|
||||
|
||||
this_size = (bytes_to_send > TFTP_PKTSIZE) ? \
|
||||
TFTP_PKTSIZE : (uint16_t)bytes_to_send;
|
||||
|
||||
for (i = 0; i < this_size; i++)
|
||||
{
|
||||
data->data[i] = current[i];
|
||||
}
|
||||
|
||||
/* Set the packet length */
|
||||
pNbuf->length = (uint16_t)(4 + this_size);
|
||||
|
||||
/* Attempt to send the packet */
|
||||
for (i = 0; i < 3; ++i)
|
||||
{
|
||||
result = udp_send(tcxn.nif,
|
||||
tcxn.server_ip,
|
||||
tcxn.my_port,
|
||||
tcxn.server_port,
|
||||
pNbuf);
|
||||
|
||||
if (result == 1)
|
||||
break;
|
||||
}
|
||||
|
||||
if (result == 0)
|
||||
nbuf_free(pNbuf);
|
||||
|
||||
timer_set_secs(TIMER_NETWORK, TFTP_TIMEOUT);
|
||||
while (timer_get_reference(TIMER_NETWORK))
|
||||
{
|
||||
/* Has the server responded */
|
||||
if ((tcxn.exp_blocknum - 1) == blocknum)
|
||||
{
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* TFTP Write Compeleted successfully */
|
||||
if (success && (this_size < TFTP_PKTSIZE))
|
||||
{
|
||||
tcxn.bytes_sent += this_size;
|
||||
break;
|
||||
}
|
||||
|
||||
if (tcxn.error)
|
||||
break;
|
||||
|
||||
/* If an ACK was received, keep sending packets */
|
||||
if (success)
|
||||
{
|
||||
tcxn.bytes_sent += TFTP_PKTSIZE;
|
||||
bytes_to_send -= TFTP_PKTSIZE;
|
||||
current += TFTP_PKTSIZE;
|
||||
blocknum++;
|
||||
retries = 4;
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
if (tcxn.error)
|
||||
{
|
||||
xprintf("TFTP lost connection to server.\n");
|
||||
xprintf("Sent %d bytes (%d blocks)\n", \
|
||||
tcxn.bytes_sent, tcxn.exp_blocknum - 1);
|
||||
udp_free_port(tcxn.my_port);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
xprintf("\bTFTP upload successful\n");
|
||||
xprintf("Sent %d bytes (%d blocks)\n", \
|
||||
tcxn.bytes_sent, tcxn.exp_blocknum - 1);
|
||||
udp_free_port(tcxn.my_port);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int tftp_read(NIF *nif, char *fn, IP_ADDR_P server)
|
||||
{
|
||||
uint32_t retries;
|
||||
|
||||
if (fn == 0 || server == 0)
|
||||
return 0;
|
||||
|
||||
/* Setup initial connection status */
|
||||
tcxn.nif = nif;
|
||||
tcxn.file = fn;
|
||||
tcxn.server_ip[0] = server[0];
|
||||
tcxn.server_ip[1] = server[1];
|
||||
tcxn.server_ip[2] = server[2];
|
||||
tcxn.server_ip[3] = server[3];
|
||||
tcxn.server_port = UDP_PORT_TFTP;
|
||||
tcxn.exp_blocknum = 1;
|
||||
tcxn.last_ack = 0;
|
||||
tcxn.dir = TFTP_RRQ;
|
||||
tcxn.open = false;
|
||||
tcxn.bytes_recv = 0;
|
||||
tcxn.rem_bytes = 0;
|
||||
tcxn.next_char = NULL;
|
||||
tcxn.error = false;
|
||||
queue_init(&tcxn.queue);
|
||||
|
||||
/* Use Mac address as pseudo-random port */
|
||||
udp_prime_port((uint16_t)((nif->hwa[4] << 8) | nif->hwa[5]));
|
||||
tcxn.my_port = udp_obtain_free_port();
|
||||
udp_bind_port(tcxn.my_port,&tftp_handler);
|
||||
|
||||
retries = 4;
|
||||
|
||||
while (--retries)
|
||||
{
|
||||
/* Make the TFTP Read/Write Request */
|
||||
if (!tftp_rwrq())
|
||||
{
|
||||
xprintf("Error: Couldn't send TFTP Read Request\n");
|
||||
udp_free_port(tcxn.my_port);
|
||||
return false;
|
||||
}
|
||||
|
||||
timer_set_secs(TIMER_NETWORK, TFTP_TIMEOUT);
|
||||
while (timer_get_reference(TIMER_NETWORK))
|
||||
{
|
||||
/* Has the server responded */
|
||||
if (tcxn.open == true)
|
||||
break;
|
||||
}
|
||||
|
||||
/* If the connection is open, we are done here */
|
||||
if ((tcxn.open == true) || tcxn.error)
|
||||
break;
|
||||
}
|
||||
if (!retries)
|
||||
{
|
||||
xprintf("TFTP could not make connection to server.\n");
|
||||
udp_free_port(tcxn.my_port);
|
||||
return false;
|
||||
}
|
||||
else if (tcxn.error)
|
||||
{
|
||||
xprintf("\bErrors in TFTP download.\n");
|
||||
udp_free_port(tcxn.my_port);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
int tftp_in_char(void)
|
||||
{
|
||||
union TFTPpacket *tftp_pkt;
|
||||
int retval;
|
||||
NBUF *pNbuf;
|
||||
|
||||
if (tcxn.next_char != NULL)
|
||||
{
|
||||
/*
|
||||
* A buffer is already being worked on - grab next
|
||||
* byte from it
|
||||
*/
|
||||
retval = *tcxn.next_char++;
|
||||
if (--tcxn.rem_bytes <= 0)
|
||||
{
|
||||
/* The buffer is depleted; add it back to the free queue */
|
||||
pNbuf = (NBUF *)queue_remove(&tcxn.queue);
|
||||
|
||||
nbuf_free(pNbuf);
|
||||
tcxn.next_char = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Is the connection still open? */
|
||||
if (tcxn.open == false)
|
||||
{
|
||||
/*
|
||||
* The last packet has been received and the last data
|
||||
* buffer has been exhausted
|
||||
*/
|
||||
retval = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Get pointer to the next buffer */
|
||||
pNbuf = (NBUF *)queue_peek(&tcxn.queue);
|
||||
|
||||
if (pNbuf == NULL)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* There was no buffer in the queue */
|
||||
for (i = 0; i < 3; ++i)
|
||||
{
|
||||
timer_set_secs(TIMER_NETWORK, 1);
|
||||
while (timer_get_reference(TIMER_NETWORK))
|
||||
{
|
||||
/* Has the server sent another DATA packet? */
|
||||
if (!queue_isempty(&tcxn.queue))
|
||||
{
|
||||
pNbuf = (NBUF *)queue_peek(&tcxn.queue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pNbuf != NULL)
|
||||
break;
|
||||
|
||||
/* Ack the last packet again */
|
||||
xprintf("Re-acking %d\n",tcxn.last_ack - 1);
|
||||
retval = tftp_ack(tcxn.last_ack - 1);
|
||||
}
|
||||
}
|
||||
if (pNbuf == NULL)
|
||||
{
|
||||
/* The server didn't respond with the expected packet */
|
||||
tcxn.open = false;
|
||||
tcxn.error = true;
|
||||
xprintf("TFTP lost connection to server.\n");
|
||||
retval = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
tftp_pkt = (union TFTPpacket *)&pNbuf->data[pNbuf->offset];
|
||||
|
||||
/* Subtract the TFTP header from the data length */
|
||||
tcxn.rem_bytes = pNbuf->length - 4;
|
||||
|
||||
/* Point to first data byte in the packet */
|
||||
tcxn.next_char = tftp_pkt->data.data;
|
||||
|
||||
/* Save off the block number */
|
||||
tcxn.last_ack = tftp_pkt->data.blocknum;
|
||||
|
||||
/* Check to see if this is the last packet of the transfer */
|
||||
if (tcxn.rem_bytes < TFTP_PKTSIZE)
|
||||
tcxn.open = false;
|
||||
|
||||
/* Check for empty termination packet */
|
||||
if (tcxn.rem_bytes == 0)
|
||||
{
|
||||
pNbuf = (NBUF *)queue_remove(&tcxn.queue);
|
||||
nbuf_free(pNbuf);
|
||||
tcxn.next_char = NULL;
|
||||
retval = tftp_ack(tcxn.last_ack++);
|
||||
retval = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
retval = tftp_ack(tcxn.last_ack++);
|
||||
retval = *tcxn.next_char++;
|
||||
|
||||
/* Check for a single byte packet */
|
||||
if (--tcxn.rem_bytes == 0)
|
||||
{
|
||||
/* The buffer is depleted; add it back to the free queue */
|
||||
pNbuf = (NBUF *)queue_remove(&tcxn.queue);
|
||||
nbuf_free(pNbuf);
|
||||
tcxn.next_char = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
184
net/udp.c
Normal file
184
net/udp.c
Normal file
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* File: udp.c
|
||||
* Purpose: User Datagram Protocol driver
|
||||
*
|
||||
* Notes:
|
||||
*
|
||||
* Modifications:
|
||||
*
|
||||
*/
|
||||
#include "bas_types.h"
|
||||
#include "bas_printf.h"
|
||||
#include "net.h"
|
||||
#include <stddef.h>
|
||||
|
||||
//#define DBG_UDP
|
||||
#if defined(DBG_UDP)
|
||||
#define dbg(format, arg...) do { xprintf("DEBUG: %s(): " format, __FUNCTION__, ##arg); } while (0)
|
||||
#else
|
||||
#define dbg(format, arg...) do { ; } while (0)
|
||||
#endif /* DBG_UDP */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t port;
|
||||
void (*handler)(NIF *, NBUF *);
|
||||
} UDP_BOUND_PORT;
|
||||
|
||||
#define UDP_MAX_PORTS (5) /* plenty for this implementation */
|
||||
|
||||
|
||||
static UDP_BOUND_PORT udp_port_table[UDP_MAX_PORTS];
|
||||
|
||||
static uint16_t udp_port;
|
||||
|
||||
void udp_init(void)
|
||||
{
|
||||
int index;
|
||||
|
||||
for (index = 0; index < UDP_MAX_PORTS; ++index)
|
||||
{
|
||||
udp_port_table[index].port = 0;
|
||||
udp_port_table[index].handler = 0;
|
||||
}
|
||||
|
||||
udp_port = DEFAULT_UDP_PORT; /* next free port */
|
||||
}
|
||||
|
||||
void udp_prime_port(uint16_t init_port)
|
||||
{
|
||||
udp_port = init_port;
|
||||
}
|
||||
|
||||
void udp_bind_port(uint16_t port, void (*handler)(NIF *, NBUF *))
|
||||
{
|
||||
int index;
|
||||
|
||||
for (index = 0; index < UDP_MAX_PORTS; ++index)
|
||||
{
|
||||
if (udp_port_table[index].port == 0)
|
||||
{
|
||||
udp_port_table[index].port = port;
|
||||
udp_port_table[index].handler = handler;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void udp_free_port(uint16_t port)
|
||||
{
|
||||
int index;
|
||||
|
||||
for (index = 0; index < UDP_MAX_PORTS; ++index)
|
||||
{
|
||||
if (udp_port_table[index].port == port)
|
||||
{
|
||||
udp_port_table[index].port = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void *udp_port_handler(uint16_t port)
|
||||
{
|
||||
int index;
|
||||
|
||||
for (index = 0; index < UDP_MAX_PORTS; ++index)
|
||||
{
|
||||
if (udp_port_table[index].port == port)
|
||||
{
|
||||
return (void *) udp_port_table[index].handler;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint16_t udp_obtain_free_port(void)
|
||||
{
|
||||
uint16_t port;
|
||||
|
||||
port = udp_port;
|
||||
if (--udp_port <= 255)
|
||||
udp_port = DEFAULT_UDP_PORT;
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
int udp_send(NIF *nif, uint8_t *dest, int sport, int dport, NBUF *pNbuf)
|
||||
{
|
||||
uint8_t *myip;
|
||||
|
||||
if (nif == NULL)
|
||||
{
|
||||
dbg("nif is NULL\r\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function takes data, creates a UDP frame from it and
|
||||
* passes it onto the IP layer
|
||||
*/
|
||||
udp_frame_hdr *udpframe;
|
||||
|
||||
udpframe = (udp_frame_hdr *) &pNbuf->data[UDP_HDR_OFFSET];
|
||||
|
||||
/* Set UDP source port */
|
||||
udpframe->src_port = (uint16_t) sport;
|
||||
|
||||
/* Set UDP destination port */
|
||||
udpframe->dest_port = (uint16_t) dport;
|
||||
|
||||
/* Set length */
|
||||
udpframe->length = (uint16_t) (pNbuf->length + UDP_HDR_SIZE);
|
||||
|
||||
/* No checksum calcualation needed */
|
||||
udpframe->chksum = (uint16_t) 0;
|
||||
|
||||
/* Add the length of the UDP packet to the total length of the packet */
|
||||
pNbuf->length += 8;
|
||||
|
||||
myip = ip_get_myip(nif_get_protocol_info(nif, ETH_FRM_IP));
|
||||
|
||||
dbg("sent UDP request to %d.%d.%d.%d from %d.%d.%d.%d\r\n",
|
||||
dest[0], dest[1], dest[2], dest[3],
|
||||
myip[0], myip[1], myip[2], myip[3]);
|
||||
|
||||
return (ip_send(nif, dest, myip, IP_PROTO_UDP, pNbuf));
|
||||
|
||||
}
|
||||
|
||||
void udp_handler(NIF *nif, NBUF *pNbuf)
|
||||
{
|
||||
/*
|
||||
* This function handles incoming UDP packets
|
||||
*/
|
||||
udp_frame_hdr *udpframe;
|
||||
void (*handler)(NIF *, NBUF *);
|
||||
|
||||
udpframe = (udp_frame_hdr *) &pNbuf->data[pNbuf->offset];
|
||||
|
||||
dbg("packet received\r\n",);
|
||||
|
||||
/*
|
||||
* Adjust the length and valid data offset of the packet we are
|
||||
* passing on
|
||||
*/
|
||||
pNbuf->length -= UDP_HDR_SIZE;
|
||||
pNbuf->offset += UDP_HDR_SIZE;
|
||||
|
||||
/*
|
||||
* Traverse the list of bound ports to see if there is a higher
|
||||
* level protocol to pass the packet on to
|
||||
*/
|
||||
if ((handler = (void(*)(NIF*, NBUF*)) udp_port_handler(UDP_DEST(udpframe))) != NULL)
|
||||
handler(nif, pNbuf);
|
||||
else
|
||||
{
|
||||
dbg("received UDP packet for non-supported port\n");
|
||||
nbuf_free(pNbuf);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
Reference in New Issue
Block a user