#include "bootp.h"
#include "tftp.h"
#include "rarp.h"
-#include "arp.h"
#if (CONFIG_COMMANDS & CFG_CMD_NET)
+#define ARP_TIMEOUT 5 /* Seconds before trying ARP again */
+#ifndef CONFIG_NET_RETRY_COUNT
+# define ARP_TIMEOUT_COUNT 5 /* # of timeouts before giving up */
+#else
+# define ARP_TIMEOUT_COUNT (CONFIG_NET_RETRY_COUNT)
+#endif
+
#if 0
#define ET_DEBUG
#endif
IPaddr_t NetOurSubnetMask=0; /* Our subnet mask (0=unknown) */
IPaddr_t NetOurGatewayIP=0; /* Our gateways IP address */
IPaddr_t NetOurDNSIP=0; /* Our DNS IP address */
+#if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_DNS2)
+IPaddr_t NetOurDNS2IP=0; /* Our 2nd DNS IP address */
+#endif
char NetOurNISDomain[32]={0,}; /* Our NIS domain */
char NetOurHostName[32]={0,}; /* Our hostname */
char NetOurRootPath[64]={0,}; /* Our bootpath */
ulong NetBootFileXferSize; /* The actual transferred size of the bootfile (in bytes) */
uchar NetOurEther[6]; /* Our ethernet address */
uchar NetServerEther[6] = /* Boot server enet address */
- { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+ { 0, 0, 0, 0, 0, 0 };
IPaddr_t NetOurIP; /* Our IP addr (0 = unknown) */
IPaddr_t NetServerIP; /* Our IP addr (0 = unknown) */
volatile uchar *NetRxPkt; /* Current receive packet */
unsigned NetIPID; /* IP packet ID */
uchar NetBcastAddr[6] = /* Ethernet bcast address */
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+uchar NetEtherNullAddr[6] =
+ { 0, 0, 0, 0, 0, 0 };
int NetState; /* Network loop state */
#ifdef CONFIG_NET_MULTI
int NetRestartWrap = 0; /* Tried all network devices */
char BootFile[128]; /* Boot File name */
+#if (CONFIG_COMMANDS & CFG_CMD_PING)
+IPaddr_t NetPingIP; /* the ip address to ping */
+
+static void PingStart(void);
+#endif
+
volatile uchar PktBuf[(PKTBUFSRX+1) * PKTSIZE_ALIGN + PKTALIGN];
volatile uchar *NetRxPackets[PKTBUFSRX]; /* Receive packets */
static rxhand_f *packetHandler; /* Current RX packet handler */
static thand_f *timeHandler; /* Current timeout handler */
-static ulong timeValue; /* Current timeout value */
+static ulong timeStart; /* Time base value */
+static ulong timeDelta; /* Current timeout value */
volatile uchar *NetTxPacket = 0; /* THE transmit packet */
static int net_check_prereq (proto_t protocol);
+/**********************************************************************/
+
+IPaddr_t NetArpWaitPacketIP;
+IPaddr_t NetArpWaitReplyIP;
+uchar *NetArpWaitPacketMAC; /* MAC address of waiting packet's destination */
+uchar *NetArpWaitTxPacket; /* THE transmit packet */
+int NetArpWaitTxPacketSize;
+uchar NetArpWaitPacketBuf[PKTSIZE_ALIGN + PKTALIGN];
+ulong NetArpWaitTimerStart;
+int NetArpWaitTry;
+
+void ArpRequest(void)
+{
+ int i;
+ volatile uchar *pkt;
+ ARP_t * arp;
+
+#ifdef ET_DEBUG
+ printf("ARP broadcast %d\n", NetArpWaitTry);
+#endif
+ pkt = NetTxPacket;
+
+ NetSetEther(pkt, NetBcastAddr, PROT_ARP);
+ pkt += ETHER_HDR_SIZE;
+
+ arp = (ARP_t *)pkt;
+
+ arp->ar_hrd = htons(ARP_ETHER);
+ arp->ar_pro = htons(PROT_IP);
+ arp->ar_hln = 6;
+ arp->ar_pln = 4;
+ arp->ar_op = htons(ARPOP_REQUEST);
+
+ memcpy (&arp->ar_data[0], NetOurEther, 6); /* source ET addr */
+ NetWriteIP((uchar*)&arp->ar_data[6], NetOurIP); /* source IP addr */
+ for (i=10; i<16; ++i) {
+ arp->ar_data[i] = 0; /* dest ET addr = 0 */
+ }
+
+ if((NetArpWaitPacketIP & NetOurSubnetMask) != (NetOurIP & NetOurSubnetMask)) {
+ if (NetOurGatewayIP == 0) {
+ puts ("## Warning: gatewayip needed but not set\n");
+ }
+ NetArpWaitReplyIP = NetOurGatewayIP;
+ } else
+ NetArpWaitReplyIP = NetArpWaitPacketIP;
+
+ NetWriteIP((uchar*)&arp->ar_data[16], NetArpWaitReplyIP);
+ (void) eth_send(NetTxPacket, ETHER_HDR_SIZE + ARP_HDR_SIZE);
+}
+
+void ArpTimeoutCheck(void)
+{
+ ulong t;
+
+ if (!NetArpWaitPacketIP)
+ return;
+
+ t = get_timer(0);
+
+ /* check for arp timeout */
+ if ((t - NetArpWaitTimerStart) > ARP_TIMEOUT * CFG_HZ) {
+ NetArpWaitTry++;
+
+ if (NetArpWaitTry >= ARP_TIMEOUT_COUNT) {
+ puts ("\nARP Retry count exceeded; starting again\n");
+ NetArpWaitTry = 0;
+ NetStartAgain();
+ } else {
+ NetArpWaitTimerStart = t;
+ ArpRequest();
+ }
+ }
+}
+
/**********************************************************************/
/*
* Main network processing loop.
NetDevExists = 0;
#endif
+ /* XXX problem with bss workaround */
+ NetArpWaitPacketMAC = NULL;
+ NetArpWaitTxPacket = NULL;
+ NetArpWaitPacketIP = 0;
+ NetArpWaitReplyIP = 0;
+ NetArpWaitTxPacket = NULL;
+ NetTxPacket = NULL;
+
if (!NetTxPacket) {
int i;
for (i = 0; i < PKTBUFSRX; i++) {
NetRxPackets[i] = NetTxPacket + (i+1)*PKTSIZE_ALIGN;
}
+
+ }
+
+ if (!NetArpWaitTxPacket) {
+ NetArpWaitTxPacket = &NetArpWaitPacketBuf[0] + (PKTALIGN - 1);
+ NetArpWaitTxPacket -= (ulong)NetArpWaitTxPacket % PKTALIGN;
+ NetArpWaitTxPacketSize = 0;
}
eth_halt();
- eth_init(bd);
+ if(eth_init(bd) < 0)
+ return(-1);
restart:
#ifdef CONFIG_NET_MULTI
*/
switch (protocol) {
+#if (CONFIG_COMMANDS & CFG_CMD_PING)
+ case PING:
+#endif
case TFTP:
NetCopyIP(&NetOurIP, &bd->bi_ip_addr);
- NetServerIP = getenv_IPaddr ("serverip");
NetOurGatewayIP = getenv_IPaddr ("gatewayip");
NetOurSubnetMask= getenv_IPaddr ("netmask");
+
+ switch (protocol) {
+ case TFTP:
+ NetServerIP = getenv_IPaddr ("serverip");
+ break;
+#if (CONFIG_COMMANDS & CFG_CMD_PING)
+ case PING:
+ /* nothing */
+ break;
+#endif
+ default:
+ break;
+ }
+
break;
case BOOTP:
case RARP:
/*
- * initialize our IP addr to 0 in order to accept ANY
- * IP addr assigned to us by the BOOTP / RARP server
+ * initialize our IP addr to 0 in order to accept ANY
+ * IP addr assigned to us by the BOOTP / RARP server
*/
NetOurIP = 0;
NetServerIP = 0;
switch (protocol) {
case TFTP:
/* always use ARP to get server ethernet address */
- ArpTry = 0;
- ArpRequest ();
+ TftpStart();
break;
#if (CONFIG_COMMANDS & CFG_CMD_DHCP)
RarpTry = 0;
RarpRequest ();
break;
+#if (CONFIG_COMMANDS & CFG_CMD_PING)
+ case PING:
+ PingStart();
+ break;
+#endif
default:
break;
}
* Abort if ctrl-c was pressed.
*/
if (ctrlc()) {
- eth_halt();
+ eth_halt();
printf("\nAbort\n");
return (-1);
}
+ ArpTimeoutCheck();
/*
* Check for a timeout, and run the timeout handler
* if we have one.
*/
- if (timeHandler && (get_timer(0) > timeValue)) {
+ if (timeHandler && ((get_timer(0) - timeStart) > timeDelta)) {
thand_f *x;
x = timeHandler;
timeHandler = (thand_f *)0;
} else {
timeHandler = f;
- timeValue = get_timer(0) + iv;
+ timeStart = get_timer(0);
+ timeDelta = iv;
}
}
(void) eth_send(pkt, len);
}
+int
+NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, int sport, int len)
+{
+ /* convert to new style broadcast */
+ if (dest == 0)
+ dest = 0xFFFFFFFF;
+
+ /* if broadcast, make the ether address a broadcast and don't do ARP */
+ if (dest == 0xFFFFFFFF)
+ ether = NetBcastAddr;
+
+ /* if MAC address was not discovered yet, save the packet and do an ARP request */
+ if (memcmp(ether, NetEtherNullAddr, 6) == 0) {
+
+#ifdef ET_DEBUG
+ printf("sending ARP for %08lx\n", dest);
+#endif
+
+ NetArpWaitPacketIP = dest;
+ NetArpWaitPacketMAC = ether;
+ NetSetEther (NetArpWaitTxPacket, NetArpWaitPacketMAC, PROT_IP);
+ NetSetIP (NetArpWaitTxPacket + ETHER_HDR_SIZE, dest, dport, sport, len);
+ memcpy(NetArpWaitTxPacket + ETHER_HDR_SIZE + IP_HDR_SIZE,
+ (uchar *)NetTxPacket + ETHER_HDR_SIZE + IP_HDR_SIZE, len);
+
+ /* size of the waiting packet */
+ NetArpWaitTxPacketSize = ETHER_HDR_SIZE + IP_HDR_SIZE + len;
+
+ /* and do the ARP request */
+ NetArpWaitTry = 1;
+ NetArpWaitTimerStart = get_timer(0);
+ ArpRequest();
+ return 1; /* waiting */
+ }
+
+#ifdef ET_DEBUG
+ printf("sending UDP to %08lx/%02x:%02x:%02x:%02x:%02x:%02x\n",
+ dest, ether[0], ether[1], ether[2], ether[3], ether[4], ether[5]);
+#endif
+
+ NetSetEther (NetTxPacket, ether, PROT_IP);
+ NetSetIP (NetTxPacket + ETHER_HDR_SIZE, dest, dport, sport, len);
+ (void) eth_send(NetTxPacket, ETHER_HDR_SIZE + IP_HDR_SIZE + len);
+
+ return 0; /* transmited */
+}
+
+#if (CONFIG_COMMANDS & CFG_CMD_PING)
+static ushort PingSeqNo;
+
+int PingSend(void)
+{
+ static uchar mac[6];
+ volatile IP_t *ip;
+ volatile ushort *s;
+
+ /* XXX always send arp request */
+
+ memcpy(mac, NetEtherNullAddr, 6);
+
+#ifdef ET_DEBUG
+ printf("sending ARP for %08lx\n", NetPingIP);
+#endif
+
+ NetArpWaitPacketIP = NetPingIP;
+ NetArpWaitPacketMAC = mac;
+
+ NetSetEther(NetArpWaitTxPacket, mac, PROT_IP);
+
+ ip = (volatile IP_t *)(NetArpWaitTxPacket + ETHER_HDR_SIZE);
+
+ /*
+ * Construct an IP and ICMP header. (need to set no fragment bit - XXX)
+ */
+ ip->ip_hl_v = 0x45; /* IP_HDR_SIZE / 4 (not including UDP) */
+ ip->ip_tos = 0;
+ ip->ip_len = htons(IP_HDR_SIZE_NO_UDP + 8);
+ ip->ip_id = htons(NetIPID++);
+ ip->ip_off = htons(0x4000); /* No fragmentation */
+ ip->ip_ttl = 255;
+ ip->ip_p = 0x01; /* ICMP */
+ ip->ip_sum = 0;
+ NetCopyIP((void*)&ip->ip_src, &NetOurIP); /* already in network byte order */
+ NetCopyIP((void*)&ip->ip_dst, &NetPingIP); /* - "" - */
+ ip->ip_sum = ~NetCksum((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2);
+
+ s = &ip->udp_src; /* XXX ICMP starts here */
+ s[0] = htons(0x0800); /* echo-request, code */
+ s[1] = 0; /* checksum */
+ s[2] = 0; /* identifier */
+ s[3] = htons(PingSeqNo++); /* sequence number */
+ s[1] = ~NetCksum((uchar *)s, 8/2);
+
+ /* size of the waiting packet */
+ NetArpWaitTxPacketSize = ETHER_HDR_SIZE + IP_HDR_SIZE_NO_UDP + 8;
+
+ /* and do the ARP request */
+ NetArpWaitTry = 1;
+ NetArpWaitTimerStart = get_timer(0);
+ ArpRequest();
+ return 1; /* waiting */
+}
+
+static void
+PingTimeout (void)
+{
+ eth_halt();
+ NetState = NETLOOP_FAIL; /* we did not get the reply */
+}
+
+static void
+PingHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len)
+{
+ IPaddr_t tmp;
+ volatile IP_t *ip = (volatile IP_t *)pkt;
+
+ tmp = NetReadIP((void *)&ip->ip_src);
+ if (tmp != NetPingIP)
+ return;
+
+ NetState = NETLOOP_SUCCESS;
+}
+
+static void PingStart(void)
+{
+ NetSetTimeout (10 * CFG_HZ, PingTimeout);
+ NetSetHandler (PingHandler);
+ PingSend();
+}
+
+#endif
void
NetReceive(volatile uchar * pkt, int len)
IPaddr_t tmp;
int x;
-
NetRxPkt = pkt;
NetRxPktLen = len;
et = (Ethernet_t *)pkt;
case PROT_ARP:
/*
* We have to deal with two types of ARP packets:
- * - REQUEST packets will be answered by sending our
- * IP address - if we know it.
- * - REPLY packates are expected only after we asked
- * for the TFTP server's or the gateway's ethernet
- * address; so if we receive such a packet, we set
- * the server ethernet address
+ * - REQUEST packets will be answered by sending our
+ * IP address - if we know it.
+ * - REPLY packates are expected only after we asked
+ * for the TFTP server's or the gateway's ethernet
+ * address; so if we receive such a packet, we set
+ * the server ethernet address
*/
#ifdef ET_DEBUG
printf("Got ARP\n");
NetCopyIP(&arp->ar_data[16], &arp->ar_data[6]);
memcpy (&arp->ar_data[ 0], NetOurEther, 6);
NetCopyIP(&arp->ar_data[ 6], &NetOurIP);
- NetSendPacket((uchar *)et,((uchar *)arp-pkt)+ARP_HDR_SIZE);
+ (void) eth_send((uchar *)et, ((uchar *)arp-pkt) + ARP_HDR_SIZE);
return;
- case ARPOP_REPLY: /* set TFTP server eth addr */
+
+ case ARPOP_REPLY: /* arp reply */
+ /* are we waiting for a reply */
+ if (!NetArpWaitPacketIP || !NetArpWaitPacketMAC)
+ break;
+#ifdef ET_DEBUG
+ printf("Got ARP REPLY, set server/gtwy eth addr (%02x:%02x:%02x:%02x:%02x:%02x)\n",
+ arp->ar_data[0], arp->ar_data[1],
+ arp->ar_data[2], arp->ar_data[3],
+ arp->ar_data[4], arp->ar_data[5]);
+#endif
+
+ tmp = NetReadIP(&arp->ar_data[6]);
+
+ /* matched waiting packet's address */
+ if (tmp == NetArpWaitReplyIP) {
#ifdef ET_DEBUG
- printf("Got ARP REPLY, set server/gtwy eth addr\n");
+ printf("Got it\n");
#endif
- memcpy (NetServerEther, &arp->ar_data[0], 6);
- (*packetHandler)(0,0,0,0); /* start TFTP */
+ /* save address for later use */
+ memcpy(NetArpWaitPacketMAC, &arp->ar_data[0], 6);
+
+ /* modify header, and transmit it */
+ memcpy(((Ethernet_t *)NetArpWaitTxPacket)->et_dest, NetArpWaitPacketMAC, 6);
+ (void) eth_send(NetArpWaitTxPacket, NetArpWaitTxPacketSize);
+
+ /* no arp request pending now */
+ NetArpWaitPacketIP = 0;
+ NetArpWaitTxPacketSize = 0;
+ NetArpWaitPacketMAC = NULL;
+
+ }
return;
default:
#ifdef ET_DEBUG
/*
* watch for ICMP host redirects
*
- * There is no real handler code (yet). We just watch
- * for ICMP host redirect messages. In case anybody
- * sees these messages: please contact me
- * (wd@denx.de), or - even better - send me the
- * necessary fixes :-)
+ * There is no real handler code (yet). We just watch
+ * for ICMP host redirect messages. In case anybody
+ * sees these messages: please contact me
+ * (wd@denx.de), or - even better - send me the
+ * necessary fixes :-)
*
- * Note: in all cases where I have seen this so far
- * it was a problem with the router configuration,
- * for instance when a router was configured in the
- * BOOTP reply, but the TFTP server was on the same
- * subnet. So this is probably a warning that your
- * configuration might be wrong. But I'm not really
- * sure if there aren't any other situations.
+ * Note: in all cases where I have seen this so far
+ * it was a problem with the router configuration,
+ * for instance when a router was configured in the
+ * BOOTP reply, but the TFTP server was on the same
+ * subnet. So this is probably a warning that your
+ * configuration might be wrong. But I'm not really
+ * sure if there aren't any other situations.
*/
if (ip->ip_p == IPPROTO_ICMP) {
ICMP_t *icmph = (ICMP_t *)&(ip->udp_src);
- if (icmph->type != ICMP_REDIRECT)
- return;
+ switch (icmph->type) {
+ case ICMP_REDIRECT:
if (icmph->code != ICMP_REDIR_HOST)
return;
puts (" ICMP Host Redirect to ");
print_IPaddr(icmph->un.gateway);
putc(' ');
+ break;
+#if (CONFIG_COMMANDS & CFG_CMD_PING)
+ case ICMP_ECHO_REPLY:
+ /*
+ * IP header OK. Pass the packet to the current handler.
+ */
+ /* XXX point to ip packet */
+ (*packetHandler)((uchar *)ip, 0, 0, 0);
+ break;
+#endif
+ default:
+ return;
+ }
} else if (ip->ip_p != IPPROTO_UDP) { /* Only UDP packets */
return;
}
static int net_check_prereq (proto_t protocol)
{
switch (protocol) {
- case ARP: /* nothing to do */
- break;
-
+ /* Fall through */
+#if (CONFIG_COMMANDS & CFG_CMD_PING)
+ case PING:
+ if (NetPingIP == 0) {
+ puts ("*** ERROR: ping address not given\n");
+ return (1);
+ }
+ goto common;
+#endif
case TFTP:
if (NetServerIP == 0) {
puts ("*** ERROR: `serverip' not set\n");
return (1);
}
+#if (CONFIG_COMMANDS & CFG_CMD_PING)
+ common:
+#endif
+
if (NetOurIP == 0) {
puts ("*** ERROR: `ipaddr' not set\n");
return (1);
puts ("*** ERROR: `ethaddr' not set\n");
break;
default:
- printf ("*** ERROR: `eth%daddr' not set\n",
+ printf ("*** ERROR: `eth%daddr' not set\n",
num);
break;
}
#endif
}
/* Fall through */
+ default:
+ return(0);
}
return (0); /* OK */
}
{
x = ntohl(x);
sprintf (s,"%d.%d.%d.%d",
- (int)((x >> 24) & 0xff),
+ (int)((x >> 24) & 0xff),
(int)((x >> 16) & 0xff),
(int)((x >> 8) & 0xff),
(int)((x >> 0) & 0xff)
);
}
-void print_IPaddr (IPaddr_t x)
-{
- char tmp[16];
-
- ip_to_string(x, tmp);
-
- puts(tmp);
-}
-
-IPaddr_t getenv_IPaddr (char *var)
+IPaddr_t string_to_ip(char *s)
{
IPaddr_t addr;
- char *s, *e;
+ char *e;
int i;
- s = getenv (var);
+ if (s == NULL)
+ return(0);
for (addr=0, i=0; i<4; ++i) {
ulong val = s ? simple_strtoul(s, &e, 10) : 0;
return (htonl(addr));
}
+
+void print_IPaddr (IPaddr_t x)
+{
+ char tmp[16];
+
+ ip_to_string(x, tmp);
+
+ puts(tmp);
+}
+
+IPaddr_t getenv_IPaddr (char *var)
+{
+ return (string_to_ip(getenv(var)));
+}