
Wolfang Hi.
In U-boot currently ARP is use for the single purpose, of providing the MAC address of the TFTP server.
This make it impossible to use ARP for communicating with any other host or protocol.
Also it muddles the tftp code since in order to begin the TFTP request, we don't call TftpStart rather we call ArpRequest and the tftp request is started explicitly upon reception of the ARP reply.
The following patch fixes these problems.
Instead of the TFTP code using NetSendPacket it uses now a new function called NetSendUDPPacket.
int NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, int sport, int len);
The argument are as follows;
uchar *ether - pointer to MAC address of the server/or gateway.
If the MAC address is zero, an ARP request is made and the packet is saved for transmition upon the reception of the ARP reply. Must point to a global or static variable for proper operation.
IPaddr_t dest - destination ip address int dport - destination port int sport - source port int len - the length of the data.
The actual contents of the transmitted packet are expected to be at NetTxPacket + ETHER_HDR_SIZE + IP_HDR_SIZE.
The major change of this patch is the elimination of the files arp.c & arp.h.
ARP is not really a proper protocol, and their functionality is placed directly in net.c
Tested both in manual tftp mode and DHCP auto-start mode...
Awaiting comments...
Regards
Pantelis
diff -ruNb u-boot-0.3.0-orig/include/net.h u-boot-0.3.0/include/net.h --- u-boot-0.3.0-orig/include/net.h Mon Apr 21 10:10:04 2003 +++ u-boot-0.3.0/include/net.h Tue Apr 22 12:37:48 2003 @@ -326,6 +326,9 @@ /* Transmit "NetTxPacket" */ extern void NetSendPacket(volatile uchar *, int);
+/* Transmit UDP packet, performing ARP request if needed */ +extern int NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, int sport, int len); + /* Processes a received packet */ extern void NetReceive(volatile uchar *, int);
diff -ruNb u-boot-0.3.0-orig/net/Makefile u-boot-0.3.0/net/Makefile --- u-boot-0.3.0-orig/net/Makefile Mon Apr 21 10:10:04 2003 +++ u-boot-0.3.0/net/Makefile Tue Apr 22 12:32:44 2003 @@ -27,7 +27,7 @@
LIB = libnet.a
-OBJS = net.o tftp.o bootp.o rarp.o arp.o eth.o +OBJS = net.o tftp.o bootp.o rarp.o eth.o all: $(LIB)
$(LIB): $(START) $(OBJS) diff -ruNb u-boot-0.3.0-orig/net/arp.c u-boot-0.3.0/net/arp.c --- u-boot-0.3.0-orig/net/arp.c Mon Apr 21 10:10:04 2003 +++ u-boot-0.3.0/net/arp.c Thu Jan 1 02:00:00 1970 @@ -1,120 +0,0 @@ -/* - * (C) Copyright 2000 - * Wolfgang Denk, DENX Software Engineering, wd@denx.de. - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#include <common.h> -#include <command.h> -#include <net.h> -#include "bootp.h" -#include "tftp.h" -#include "arp.h" - -#if (CONFIG_COMMANDS & CFG_CMD_NET) - -#define TIMEOUT 5 /* Seconds before trying ARP again */ -#ifndef CONFIG_NET_RETRY_COUNT -# define TIMEOUT_COUNT 5 /* # of timeouts before giving up */ -#else -# define TIMEOUT_COUNT (CONFIG_NET_RETRY_COUNT) -#endif - -static void ArpHandler(uchar *pkt, unsigned dest, unsigned src, unsigned len); -static void ArpTimeout(void); - -int ArpTry = 0; - -/* - * Handle a ARP received packet. - */ -static void -ArpHandler(uchar *pkt, unsigned dest, unsigned src, unsigned len) -{ - /* Check if the frame is really an ARP reply */ - if (memcmp (NetServerEther, NetBcastAddr, 6) != 0) { -#ifdef DEBUG - printf("Got good ARP - start TFTP\n"); -#endif - TftpStart (); - } -} - - -/* - * Timeout on ARP request. - */ -static void -ArpTimeout(void) -{ - if (ArpTry >= TIMEOUT_COUNT) { - puts ("\nRetry count exceeded; starting again\n"); - NetStartAgain (); - } else { - NetSetTimeout (TIMEOUT * CFG_HZ, ArpTimeout); - ArpRequest (); - } -} - - -void -ArpRequest (void) -{ - int i; - volatile uchar *pkt; - ARP_t * arp; - - printf("ARP broadcast %d\n", ++ArpTry); - 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((NetServerIP & NetOurSubnetMask) != (NetOurIP & NetOurSubnetMask)) { - if (NetOurGatewayIP == 0) { - puts ("## Warning: gatewayip needed but not set\n"); - } - NetWriteIP((uchar*)&arp->ar_data[16], NetOurGatewayIP); - } else { - NetWriteIP((uchar*)&arp->ar_data[16], NetServerIP); - } - - - NetSendPacket(NetTxPacket, ETHER_HDR_SIZE + ARP_HDR_SIZE); - - NetSetTimeout(TIMEOUT * CFG_HZ, ArpTimeout); - NetSetHandler(ArpHandler); -} - -#endif /* CFG_CMD_NET */ diff -ruNb u-boot-0.3.0-orig/net/arp.h u-boot-0.3.0/net/arp.h --- u-boot-0.3.0-orig/net/arp.h Mon Apr 21 10:10:04 2003 +++ u-boot-0.3.0/net/arp.h Thu Jan 1 02:00:00 1970 @@ -1,40 +0,0 @@ -/* - * (C) Copyright 2000 - * Wolfgang Denk, DENX Software Engineering, wd@denx.de. - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - - -#ifndef __ARP_H__ -#define __ARP_H__ - -/**********************************************************************/ -/* - * Global functions and variables. - */ - -extern int ArpTry; - -extern void ArpRequest (void); /* Send a ARP request */ - -/**********************************************************************/ - -#endif /* __ARP_H__ */ - diff -ruNb u-boot-0.3.0-orig/net/bootp.c u-boot-0.3.0/net/bootp.c --- u-boot-0.3.0-orig/net/bootp.c Mon Apr 21 10:10:04 2003 +++ u-boot-0.3.0/net/bootp.c Tue Apr 22 12:32:45 2003 @@ -24,7 +24,6 @@ #include <net.h> #include "bootp.h" #include "tftp.h" -#include "arp.h" #ifdef CONFIG_STATUS_LED #include <status_led.h> #endif @@ -335,10 +334,7 @@ return; }
- /* Send ARP request to get TFTP server ethernet address. - * This automagically starts TFTP, too. - */ - ArpRequest(); + TftpStart(); } #endif /* !CFG_CMD_DHCP */
@@ -866,10 +862,7 @@ NetState = NETLOOP_SUCCESS; return; } - /* Send ARP request to get TFTP server ethernet address. - * This automagically starts TFTP, too. - */ - ArpRequest(); + TftpStart(); return; } break; diff -ruNb u-boot-0.3.0-orig/net/net.c u-boot-0.3.0/net/net.c --- u-boot-0.3.0-orig/net/net.c Mon Apr 21 10:10:04 2003 +++ u-boot-0.3.0/net/net.c Tue Apr 22 12:32:45 2003 @@ -65,10 +65,16 @@ #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 @@ -88,7 +94,7 @@ 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 */ @@ -96,6 +102,8 @@ 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 */ @@ -117,6 +125,78 @@ static int net_check_prereq (proto_t protocol);
/**********************************************************************/ + +IPaddr_t NetArpWaitPacketIP; +uchar *NetArpWaitPacketMAC; /* MAC address of waiting packet's destination */ +uchar *NetArpWaitTxPacket = 0; /* 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; + + printf("ARP broadcast %d\n", NetArpWaitTry); + 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"); + } + NetWriteIP((uchar*)&arp->ar_data[16], NetOurGatewayIP); + } else { + NetWriteIP((uchar*)&arp->ar_data[16], NetArpWaitPacketIP); + } + + (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. */ @@ -144,6 +224,13 @@ 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(); @@ -202,8 +289,7 @@ switch (protocol) { case TFTP: /* always use ARP to get server ethernet address */ - ArpTry = 0; - ArpRequest (); + TftpStart(); break;
#if (CONFIG_COMMANDS & CFG_CMD_DHCP) @@ -260,6 +346,7 @@ return (-1); }
+ ArpTimeoutCheck();
/* * Check for a timeout, and run the timeout handler @@ -376,7 +463,44 @@ (void) eth_send(pkt, len); }
+int +NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, int sport, int len) +{ + /* 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 */ +}
void NetReceive(volatile uchar * pkt, int len) @@ -462,14 +586,40 @@ 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) + break; #ifdef ET_DEBUG - printf("Got ARP REPLY, set server/gtwy eth addr\n"); + 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 - memcpy (NetServerEther, &arp->ar_data[0], 6); - (*packetHandler)(0,0,0,0); /* start TFTP */ + + tmp = NetReadIP(&arp->ar_data[6]); + + /* matched waiting packet's address */ + if (tmp == NetArpWaitPacketIP) { +#ifdef ET_DEBUG + printf("Got it\n"); +#endif + /* 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 diff -ruNb u-boot-0.3.0-orig/net/tftp.c u-boot-0.3.0/net/tftp.c --- u-boot-0.3.0-orig/net/tftp.c Mon Apr 21 10:10:04 2003 +++ u-boot-0.3.0/net/tftp.c Tue Apr 22 12:40:41 2003 @@ -142,10 +142,7 @@ break; }
- NetSetEther (NetTxPacket, NetServerEther, PROT_IP); - NetSetIP (NetTxPacket + ETHER_HDR_SIZE, NetServerIP, - TftpServerPort, TftpOurPort, len); - NetSendPacket (NetTxPacket, ETHER_HDR_SIZE + IP_HDR_SIZE + len); + NetSendUDPPacket(NetServerEther, NetServerIP, TftpServerPort, TftpOurPort, len); }
@@ -257,17 +254,6 @@ void TftpStart (void) { -#ifdef ET_DEBUG - printf ("\nServer ethernet address %02x:%02x:%02x:%02x:%02x:%02x\n", - NetServerEther[0], - NetServerEther[1], - NetServerEther[2], - NetServerEther[3], - NetServerEther[4], - NetServerEther[5] - ); -#endif /* DEBUG */ - if (BootFile[0] == '\0') { IPaddr_t OurIP = ntohl(NetOurIP);