add missing files not taken with github import

This commit is contained in:
Markus Fröschle
2017-12-25 10:21:08 +01:00
parent c6de494f33
commit d6a9aa14e3
260 changed files with 75195 additions and 0 deletions

119
net/am79c874.c Normal file
View 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
View 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
View 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
View 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;
}
}

1442
net/fec.c Normal file

File diff suppressed because it is too large Load Diff

239
net/fecbd.c Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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;
}