]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - net/net.c
net: Move ARP out of net.c
[karo-tx-uboot.git] / net / net.c
1 /*
2  *      Copied from Linux Monitor (LiMon) - Networking.
3  *
4  *      Copyright 1994 - 2000 Neil Russell.
5  *      (See License)
6  *      Copyright 2000 Roland Borde
7  *      Copyright 2000 Paolo Scaffardi
8  *      Copyright 2000-2002 Wolfgang Denk, wd@denx.de
9  */
10
11 /*
12  * General Desription:
13  *
14  * The user interface supports commands for BOOTP, RARP, and TFTP.
15  * Also, we support ARP internally. Depending on available data,
16  * these interact as follows:
17  *
18  * BOOTP:
19  *
20  *      Prerequisites:  - own ethernet address
21  *      We want:        - own IP address
22  *                      - TFTP server IP address
23  *                      - name of bootfile
24  *      Next step:      ARP
25  *
26  * RARP:
27  *
28  *      Prerequisites:  - own ethernet address
29  *      We want:        - own IP address
30  *                      - TFTP server IP address
31  *      Next step:      ARP
32  *
33  * ARP:
34  *
35  *      Prerequisites:  - own ethernet address
36  *                      - own IP address
37  *                      - TFTP server IP address
38  *      We want:        - TFTP server ethernet address
39  *      Next step:      TFTP
40  *
41  * DHCP:
42  *
43  *     Prerequisites:   - own ethernet address
44  *     We want:         - IP, Netmask, ServerIP, Gateway IP
45  *                      - bootfilename, lease time
46  *     Next step:       - TFTP
47  *
48  * TFTP:
49  *
50  *      Prerequisites:  - own ethernet address
51  *                      - own IP address
52  *                      - TFTP server IP address
53  *                      - TFTP server ethernet address
54  *                      - name of bootfile (if unknown, we use a default name
55  *                        derived from our own IP address)
56  *      We want:        - load the boot file
57  *      Next step:      none
58  *
59  * NFS:
60  *
61  *      Prerequisites:  - own ethernet address
62  *                      - own IP address
63  *                      - name of bootfile (if unknown, we use a default name
64  *                        derived from our own IP address)
65  *      We want:        - load the boot file
66  *      Next step:      none
67  *
68  * SNTP:
69  *
70  *      Prerequisites:  - own ethernet address
71  *                      - own IP address
72  *      We want:        - network time
73  *      Next step:      none
74  */
75
76
77 #include <common.h>
78 #include <watchdog.h>
79 #include <command.h>
80 #include <linux/compiler.h>
81 #include <net.h>
82 #include "arp.h"
83 #include "bootp.h"
84 #include "tftp.h"
85 #ifdef CONFIG_CMD_RARP
86 #include "rarp.h"
87 #endif
88 #include "nfs.h"
89 #ifdef CONFIG_STATUS_LED
90 #include <status_led.h>
91 #include <miiphy.h>
92 #endif
93 #if defined(CONFIG_CMD_SNTP)
94 #include "sntp.h"
95 #endif
96 #include "cdp.h"
97 #if defined(CONFIG_CMD_DNS)
98 #include "dns.h"
99 #endif
100
101 DECLARE_GLOBAL_DATA_PTR;
102
103 /** BOOTP EXTENTIONS **/
104
105 /* Our subnet mask (0=unknown) */
106 IPaddr_t        NetOurSubnetMask;
107 /* Our gateways IP address */
108 IPaddr_t        NetOurGatewayIP;
109 /* Our DNS IP address */
110 IPaddr_t        NetOurDNSIP;
111 #if defined(CONFIG_BOOTP_DNS2)
112 /* Our 2nd DNS IP address */
113 IPaddr_t        NetOurDNS2IP;
114 #endif
115 /* Our NIS domain */
116 char            NetOurNISDomain[32] = {0,};
117 /* Our hostname */
118 char            NetOurHostName[32] = {0,};
119 /* Our bootpath */
120 char            NetOurRootPath[64] = {0,};
121 /* Our bootfile size in blocks */
122 ushort          NetBootFileSize;
123
124 #ifdef CONFIG_MCAST_TFTP        /* Multicast TFTP */
125 IPaddr_t Mcast_addr;
126 #endif
127
128 /** END OF BOOTP EXTENTIONS **/
129
130 /* The actual transferred size of the bootfile (in bytes) */
131 ulong           NetBootFileXferSize;
132 /* Our ethernet address */
133 uchar           NetOurEther[6];
134 /* Boot server enet address */
135 uchar           NetServerEther[6];
136 /* Our IP addr (0 = unknown) */
137 IPaddr_t        NetOurIP;
138 /* Server IP addr (0 = unknown) */
139 IPaddr_t        NetServerIP;
140 /* Current receive packet */
141 uchar *NetRxPacket;
142 /* Current rx packet length */
143 int             NetRxPacketLen;
144 /* IP packet ID */
145 unsigned        NetIPID;
146 /* Ethernet bcast address */
147 uchar           NetBcastAddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
148 uchar           NetEtherNullAddr[6];
149 #ifdef CONFIG_API
150 void            (*push_packet)(void *, int len) = 0;
151 #endif
152 /* Network loop state */
153 int             NetState;
154 /* Tried all network devices */
155 int             NetRestartWrap;
156 /* Network loop restarted */
157 static int      NetRestarted;
158 /* At least one device configured */
159 static int      NetDevExists;
160
161 /* XXX in both little & big endian machines 0xFFFF == ntohs(-1) */
162 /* default is without VLAN */
163 ushort          NetOurVLAN = 0xFFFF;
164 /* ditto */
165 ushort          NetOurNativeVLAN = 0xFFFF;
166
167 /* Boot File name */
168 char            BootFile[128];
169
170 #if defined(CONFIG_CMD_PING)
171 /* the ip address to ping */
172 IPaddr_t        NetPingIP;
173
174 static void PingStart(void);
175 #endif
176
177 #if defined(CONFIG_CMD_SNTP)
178 /* NTP server IP address */
179 IPaddr_t        NetNtpServerIP;
180 /* offset time from UTC */
181 int             NetTimeOffset;
182 #endif
183
184 uchar PktBuf[(PKTBUFSRX+1) * PKTSIZE_ALIGN + PKTALIGN];
185
186 /* Receive packet */
187 uchar *NetRxPackets[PKTBUFSRX];
188
189 /* Current RX packet handler */
190 static rxhand_f *packetHandler;
191 #ifdef CONFIG_CMD_TFTPPUT
192 static rxhand_icmp_f *packet_icmp_handler;      /* Current ICMP rx handler */
193 #endif
194 /* Current timeout handler */
195 static thand_f *timeHandler;
196 /* Time base value */
197 static ulong    timeStart;
198 /* Current timeout value */
199 static ulong    timeDelta;
200 /* THE transmit packet */
201 uchar *NetTxPacket;
202
203 static int net_check_prereq(enum proto_t protocol);
204
205 static int NetTryCount;
206
207 /**********************************************************************/
208
209 /*
210  * Check if autoload is enabled. If so, use either NFS or TFTP to download
211  * the boot file.
212  */
213 void net_auto_load(void)
214 {
215         const char *s = getenv("autoload");
216
217         if (s != NULL) {
218                 if (*s == 'n') {
219                         /*
220                          * Just use BOOTP/RARP to configure system;
221                          * Do not use TFTP to load the bootfile.
222                          */
223                         NetState = NETLOOP_SUCCESS;
224                         return;
225                 }
226 #if defined(CONFIG_CMD_NFS)
227                 if (strcmp(s, "NFS") == 0) {
228                         /*
229                          * Use NFS to load the bootfile.
230                          */
231                         NfsStart();
232                         return;
233                 }
234 #endif
235         }
236         TftpStart(TFTPGET);
237 }
238
239 static void NetInitLoop(enum proto_t protocol)
240 {
241         static int env_changed_id;
242         int env_id = get_env_id();
243
244         /* update only when the environment has changed */
245         if (env_changed_id != env_id) {
246                 NetOurIP = getenv_IPaddr("ipaddr");
247                 NetOurGatewayIP = getenv_IPaddr("gatewayip");
248                 NetOurSubnetMask = getenv_IPaddr("netmask");
249                 NetServerIP = getenv_IPaddr("serverip");
250                 NetOurNativeVLAN = getenv_VLAN("nvlan");
251                 NetOurVLAN = getenv_VLAN("vlan");
252 #if defined(CONFIG_CMD_DNS)
253                 NetOurDNSIP = getenv_IPaddr("dnsip");
254 #endif
255                 env_changed_id = env_id;
256         }
257
258         return;
259 }
260
261 /**********************************************************************/
262 /*
263  *      Main network processing loop.
264  */
265
266 int NetLoop(enum proto_t protocol)
267 {
268         bd_t *bd = gd->bd;
269         int ret = -1;
270
271         NetRestarted = 0;
272         NetDevExists = 0;
273
274         NetTxPacket = NULL;
275         NetTryCount = 1;
276
277         ArpInit();
278
279         if (!NetTxPacket) {
280                 int     i;
281                 /*
282                  *      Setup packet buffers, aligned correctly.
283                  */
284                 NetTxPacket = &PktBuf[0] + (PKTALIGN - 1);
285                 NetTxPacket -= (ulong)NetTxPacket % PKTALIGN;
286                 for (i = 0; i < PKTBUFSRX; i++)
287                         NetRxPackets[i] = NetTxPacket + (i+1)*PKTSIZE_ALIGN;
288         }
289
290         bootstage_mark_name(BOOTSTAGE_ID_ETH_START, "eth_start");
291         eth_halt();
292         eth_set_current();
293         if (eth_init(bd) < 0) {
294                 eth_halt();
295                 return -1;
296         }
297
298 restart:
299         memcpy(NetOurEther, eth_get_dev()->enetaddr, 6);
300
301         NetState = NETLOOP_CONTINUE;
302
303         /*
304          *      Start the ball rolling with the given start function.  From
305          *      here on, this code is a state machine driven by received
306          *      packets and timer events.
307          */
308         NetInitLoop(protocol);
309
310         switch (net_check_prereq(protocol)) {
311         case 1:
312                 /* network not configured */
313                 eth_halt();
314                 return -1;
315
316         case 2:
317                 /* network device not configured */
318                 break;
319
320         case 0:
321                 NetDevExists = 1;
322                 NetBootFileXferSize = 0;
323                 switch (protocol) {
324                 case TFTPGET:
325 #ifdef CONFIG_CMD_TFTPPUT
326                 case TFTPPUT:
327 #endif
328                         /* always use ARP to get server ethernet address */
329                         TftpStart(protocol);
330                         break;
331 #ifdef CONFIG_CMD_TFTPSRV
332                 case TFTPSRV:
333                         TftpStartServer();
334                         break;
335 #endif
336 #if defined(CONFIG_CMD_DHCP)
337                 case DHCP:
338                         BootpTry = 0;
339                         NetOurIP = 0;
340                         DhcpRequest();          /* Basically same as BOOTP */
341                         break;
342 #endif
343
344                 case BOOTP:
345                         BootpTry = 0;
346                         NetOurIP = 0;
347                         BootpRequest();
348                         break;
349
350 #if defined(CONFIG_CMD_RARP)
351                 case RARP:
352                         RarpTry = 0;
353                         NetOurIP = 0;
354                         RarpRequest();
355                         break;
356 #endif
357 #if defined(CONFIG_CMD_PING)
358                 case PING:
359                         PingStart();
360                         break;
361 #endif
362 #if defined(CONFIG_CMD_NFS)
363                 case NFS:
364                         NfsStart();
365                         break;
366 #endif
367 #if defined(CONFIG_CMD_CDP)
368                 case CDP:
369                         CDPStart();
370                         break;
371 #endif
372 #ifdef CONFIG_NETCONSOLE
373                 case NETCONS:
374                         NcStart();
375                         break;
376 #endif
377 #if defined(CONFIG_CMD_SNTP)
378                 case SNTP:
379                         SntpStart();
380                         break;
381 #endif
382 #if defined(CONFIG_CMD_DNS)
383                 case DNS:
384                         DnsStart();
385                         break;
386 #endif
387                 default:
388                         break;
389                 }
390
391                 break;
392         }
393
394 #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
395 #if     defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN)        && \
396         defined(CONFIG_STATUS_LED)                      && \
397         defined(STATUS_LED_RED)
398         /*
399          * Echo the inverted link state to the fault LED.
400          */
401         if (miiphy_link(eth_get_dev()->name, CONFIG_SYS_FAULT_MII_ADDR))
402                 status_led_set(STATUS_LED_RED, STATUS_LED_OFF);
403         else
404                 status_led_set(STATUS_LED_RED, STATUS_LED_ON);
405 #endif /* CONFIG_SYS_FAULT_ECHO_LINK_DOWN, ... */
406 #endif /* CONFIG_MII, ... */
407
408         /*
409          *      Main packet reception loop.  Loop receiving packets until
410          *      someone sets `NetState' to a state that terminates.
411          */
412         for (;;) {
413                 WATCHDOG_RESET();
414 #ifdef CONFIG_SHOW_ACTIVITY
415                 show_activity(1);
416 #endif
417                 /*
418                  *      Check the ethernet for a new packet.  The ethernet
419                  *      receive routine will process it.
420                  */
421                 eth_rx();
422
423                 /*
424                  *      Abort if ctrl-c was pressed.
425                  */
426                 if (ctrlc()) {
427                         eth_halt();
428                         puts("\nAbort\n");
429                         goto done;
430                 }
431
432                 ArpTimeoutCheck();
433
434                 /*
435                  *      Check for a timeout, and run the timeout handler
436                  *      if we have one.
437                  */
438                 if (timeHandler && ((get_timer(0) - timeStart) > timeDelta)) {
439                         thand_f *x;
440
441 #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
442 #if     defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN)        && \
443         defined(CONFIG_STATUS_LED)                      && \
444         defined(STATUS_LED_RED)
445                         /*
446                          * Echo the inverted link state to the fault LED.
447                          */
448                         if (miiphy_link(eth_get_dev()->name,
449                                        CONFIG_SYS_FAULT_MII_ADDR)) {
450                                 status_led_set(STATUS_LED_RED, STATUS_LED_OFF);
451                         } else {
452                                 status_led_set(STATUS_LED_RED, STATUS_LED_ON);
453                         }
454 #endif /* CONFIG_SYS_FAULT_ECHO_LINK_DOWN, ... */
455 #endif /* CONFIG_MII, ... */
456                         x = timeHandler;
457                         timeHandler = (thand_f *)0;
458                         (*x)();
459                 }
460
461
462                 switch (NetState) {
463
464                 case NETLOOP_RESTART:
465                         NetRestarted = 1;
466                         goto restart;
467
468                 case NETLOOP_SUCCESS:
469                         if (NetBootFileXferSize > 0) {
470                                 char buf[20];
471                                 printf("Bytes transferred = %ld (%lx hex)\n",
472                                         NetBootFileXferSize,
473                                         NetBootFileXferSize);
474                                 sprintf(buf, "%lX", NetBootFileXferSize);
475                                 setenv("filesize", buf);
476
477                                 sprintf(buf, "%lX", (unsigned long)load_addr);
478                                 setenv("fileaddr", buf);
479                         }
480                         eth_halt();
481                         ret = NetBootFileXferSize;
482                         goto done;
483
484                 case NETLOOP_FAIL:
485                         goto done;
486                 }
487         }
488
489 done:
490 #ifdef CONFIG_CMD_TFTPPUT
491         /* Clear out the handlers */
492         NetSetHandler(NULL);
493         net_set_icmp_handler(NULL);
494 #endif
495         return ret;
496 }
497
498 /**********************************************************************/
499
500 static void
501 startAgainTimeout(void)
502 {
503         NetState = NETLOOP_RESTART;
504 }
505
506 static void
507 startAgainHandler(uchar *pkt, unsigned dest, IPaddr_t sip,
508                   unsigned src, unsigned len)
509 {
510         /* Totally ignore the packet */
511 }
512
513 void NetStartAgain(void)
514 {
515         char *nretry;
516         int retry_forever = 0;
517         unsigned long retrycnt = 0;
518
519         nretry = getenv("netretry");
520         if (nretry) {
521                 if (!strcmp(nretry, "yes"))
522                         retry_forever = 1;
523                 else if (!strcmp(nretry, "no"))
524                         retrycnt = 0;
525                 else if (!strcmp(nretry, "once"))
526                         retrycnt = 1;
527                 else
528                         retrycnt = simple_strtoul(nretry, NULL, 0);
529         } else
530                 retry_forever = 1;
531
532         if ((!retry_forever) && (NetTryCount >= retrycnt)) {
533                 eth_halt();
534                 NetState = NETLOOP_FAIL;
535                 return;
536         }
537
538         NetTryCount++;
539
540         eth_halt();
541 #if !defined(CONFIG_NET_DO_NOT_TRY_ANOTHER)
542         eth_try_another(!NetRestarted);
543 #endif
544         eth_init(gd->bd);
545         if (NetRestartWrap) {
546                 NetRestartWrap = 0;
547                 if (NetDevExists) {
548                         NetSetTimeout(10000UL, startAgainTimeout);
549                         NetSetHandler(startAgainHandler);
550                 } else {
551                         NetState = NETLOOP_FAIL;
552                 }
553         } else {
554                 NetState = NETLOOP_RESTART;
555         }
556 }
557
558 /**********************************************************************/
559 /*
560  *      Miscelaneous bits.
561  */
562
563 rxhand_f *
564 NetGetHandler(void)
565 {
566         return packetHandler;
567 }
568
569
570 void
571 NetSetHandler(rxhand_f *f)
572 {
573         packetHandler = f;
574 }
575
576 #ifdef CONFIG_CMD_TFTPPUT
577 void net_set_icmp_handler(rxhand_icmp_f *f)
578 {
579         packet_icmp_handler = f;
580 }
581 #endif
582
583 void
584 NetSetTimeout(ulong iv, thand_f *f)
585 {
586         if (iv == 0) {
587                 timeHandler = (thand_f *)0;
588         } else {
589                 timeHandler = f;
590                 timeStart = get_timer(0);
591                 timeDelta = iv;
592         }
593 }
594
595
596 void
597 NetSendPacket(uchar *pkt, int len)
598 {
599         (void) eth_send(pkt, len);
600 }
601
602 int
603 NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, int sport, int len)
604 {
605         uchar *pkt;
606
607         /* convert to new style broadcast */
608         if (dest == 0)
609                 dest = 0xFFFFFFFF;
610
611         /* if broadcast, make the ether address a broadcast and don't do ARP */
612         if (dest == 0xFFFFFFFF)
613                 ether = NetBcastAddr;
614
615         /*
616          * if MAC address was not discovered yet, save the packet and do
617          * an ARP request
618          */
619         if (memcmp(ether, NetEtherNullAddr, 6) == 0) {
620
621                 debug("sending ARP for %08x\n", dest);
622
623                 NetArpWaitPacketIP = dest;
624                 NetArpWaitPacketMAC = ether;
625
626                 pkt = NetArpWaitTxPacket;
627                 pkt += NetSetEther(pkt, NetArpWaitPacketMAC, PROT_IP);
628
629                 NetSetIP(pkt, dest, dport, sport, len);
630                 memcpy(pkt + IP_HDR_SIZE, (uchar *)NetTxPacket +
631                        (pkt - (uchar *)NetArpWaitTxPacket) + IP_HDR_SIZE, len);
632
633                 /* size of the waiting packet */
634                 NetArpWaitTxPacketSize = (pkt - NetArpWaitTxPacket) +
635                         IP_HDR_SIZE + len;
636
637                 /* and do the ARP request */
638                 NetArpWaitTry = 1;
639                 NetArpWaitTimerStart = get_timer(0);
640                 ArpRequest();
641                 return 1;       /* waiting */
642         }
643
644         debug("sending UDP to %08x/%pM\n", dest, ether);
645
646         pkt = (uchar *)NetTxPacket;
647         pkt += NetSetEther(pkt, ether, PROT_IP);
648         NetSetIP(pkt, dest, dport, sport, len);
649         (void) eth_send(NetTxPacket, (pkt - NetTxPacket) + IP_HDR_SIZE + len);
650
651         return 0;       /* transmitted */
652 }
653
654 #if defined(CONFIG_CMD_PING)
655 static ushort PingSeqNo;
656
657 int PingSend(void)
658 {
659         static uchar mac[6];
660         IP_t *ip;
661         ushort *s;
662         uchar *pkt;
663
664         /* XXX always send arp request */
665
666         memcpy(mac, NetEtherNullAddr, 6);
667
668         debug("sending ARP for %08x\n", NetPingIP);
669
670         NetArpWaitPacketIP = NetPingIP;
671         NetArpWaitPacketMAC = mac;
672
673         pkt = NetArpWaitTxPacket;
674         pkt += NetSetEther(pkt, mac, PROT_IP);
675
676         ip = (IP_t *)pkt;
677
678         /*
679          * Construct an IP and ICMP header.
680          * (need to set no fragment bit - XXX)
681          */
682         /* IP_HDR_SIZE / 4 (not including UDP) */
683         ip->ip_hl_v  = 0x45;
684         ip->ip_tos   = 0;
685         ip->ip_len   = htons(IP_HDR_SIZE_NO_UDP + 8);
686         ip->ip_id    = htons(NetIPID++);
687         ip->ip_off   = htons(IP_FLAGS_DFRAG);   /* Don't fragment */
688         ip->ip_ttl   = 255;
689         ip->ip_p     = 0x01;            /* ICMP */
690         ip->ip_sum   = 0;
691         /* already in network byte order */
692         NetCopyIP((void *)&ip->ip_src, &NetOurIP);
693         /* - "" - */
694         NetCopyIP((void *)&ip->ip_dst, &NetPingIP);
695         ip->ip_sum   = ~NetCksum((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2);
696
697         s = &ip->udp_src;               /* XXX ICMP starts here */
698         s[0] = htons(0x0800);           /* echo-request, code */
699         s[1] = 0;                       /* checksum */
700         s[2] = 0;                       /* identifier */
701         s[3] = htons(PingSeqNo++);      /* sequence number */
702         s[1] = ~NetCksum((uchar *)s, 8/2);
703
704         /* size of the waiting packet */
705         NetArpWaitTxPacketSize =
706                 (pkt - NetArpWaitTxPacket) + IP_HDR_SIZE_NO_UDP + 8;
707
708         /* and do the ARP request */
709         NetArpWaitTry = 1;
710         NetArpWaitTimerStart = get_timer(0);
711         ArpRequest();
712         return 1;       /* waiting */
713 }
714
715 static void
716 PingTimeout(void)
717 {
718         eth_halt();
719         NetState = NETLOOP_FAIL;        /* we did not get the reply */
720 }
721
722 static void
723 PingHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
724             unsigned len)
725 {
726         if (sip != NetPingIP)
727                 return;
728
729         NetState = NETLOOP_SUCCESS;
730 }
731
732 static void PingStart(void)
733 {
734         printf("Using %s device\n", eth_get_name());
735         NetSetTimeout(10000UL, PingTimeout);
736         NetSetHandler(PingHandler);
737
738         PingSend();
739 }
740 #endif
741
742 #ifdef CONFIG_IP_DEFRAG
743 /*
744  * This function collects fragments in a single packet, according
745  * to the algorithm in RFC815. It returns NULL or the pointer to
746  * a complete packet, in static storage
747  */
748 #ifndef CONFIG_NET_MAXDEFRAG
749 #define CONFIG_NET_MAXDEFRAG 16384
750 #endif
751 /*
752  * MAXDEFRAG, above, is chosen in the config file and  is real data
753  * so we need to add the NFS overhead, which is more than TFTP.
754  * To use sizeof in the internal unnamed structures, we need a real
755  * instance (can't do "sizeof(struct rpc_t.u.reply))", unfortunately).
756  * The compiler doesn't complain nor allocates the actual structure
757  */
758 static struct rpc_t rpc_specimen;
759 #define IP_PKTSIZE (CONFIG_NET_MAXDEFRAG + sizeof(rpc_specimen.u.reply))
760
761 #define IP_MAXUDP (IP_PKTSIZE - IP_HDR_SIZE_NO_UDP)
762
763 /*
764  * this is the packet being assembled, either data or frag control.
765  * Fragments go by 8 bytes, so this union must be 8 bytes long
766  */
767 struct hole {
768         /* first_byte is address of this structure */
769         u16 last_byte;  /* last byte in this hole + 1 (begin of next hole) */
770         u16 next_hole;  /* index of next (in 8-b blocks), 0 == none */
771         u16 prev_hole;  /* index of prev, 0 == none */
772         u16 unused;
773 };
774
775 static IP_t *__NetDefragment(IP_t *ip, int *lenp)
776 {
777         static uchar pkt_buff[IP_PKTSIZE] __aligned(PKTALIGN);
778         static u16 first_hole, total_len;
779         struct hole *payload, *thisfrag, *h, *newh;
780         IP_t *localip = (IP_t *)pkt_buff;
781         uchar *indata = (uchar *)ip;
782         int offset8, start, len, done = 0;
783         u16 ip_off = ntohs(ip->ip_off);
784
785         /* payload starts after IP header, this fragment is in there */
786         payload = (struct hole *)(pkt_buff + IP_HDR_SIZE_NO_UDP);
787         offset8 =  (ip_off & IP_OFFS);
788         thisfrag = payload + offset8;
789         start = offset8 * 8;
790         len = ntohs(ip->ip_len) - IP_HDR_SIZE_NO_UDP;
791
792         if (start + len > IP_MAXUDP) /* fragment extends too far */
793                 return NULL;
794
795         if (!total_len || localip->ip_id != ip->ip_id) {
796                 /* new (or different) packet, reset structs */
797                 total_len = 0xffff;
798                 payload[0].last_byte = ~0;
799                 payload[0].next_hole = 0;
800                 payload[0].prev_hole = 0;
801                 first_hole = 0;
802                 /* any IP header will work, copy the first we received */
803                 memcpy(localip, ip, IP_HDR_SIZE_NO_UDP);
804         }
805
806         /*
807          * What follows is the reassembly algorithm. We use the payload
808          * array as a linked list of hole descriptors, as each hole starts
809          * at a multiple of 8 bytes. However, last byte can be whatever value,
810          * so it is represented as byte count, not as 8-byte blocks.
811          */
812
813         h = payload + first_hole;
814         while (h->last_byte < start) {
815                 if (!h->next_hole) {
816                         /* no hole that far away */
817                         return NULL;
818                 }
819                 h = payload + h->next_hole;
820         }
821
822         /* last fragment may be 1..7 bytes, the "+7" forces acceptance */
823         if (offset8 + ((len + 7) / 8) <= h - payload) {
824                 /* no overlap with holes (dup fragment?) */
825                 return NULL;
826         }
827
828         if (!(ip_off & IP_FLAGS_MFRAG)) {
829                 /* no more fragmentss: truncate this (last) hole */
830                 total_len = start + len;
831                 h->last_byte = start + len;
832         }
833
834         /*
835          * There is some overlap: fix the hole list. This code doesn't
836          * deal with a fragment that overlaps with two different holes
837          * (thus being a superset of a previously-received fragment).
838          */
839
840         if ((h >= thisfrag) && (h->last_byte <= start + len)) {
841                 /* complete overlap with hole: remove hole */
842                 if (!h->prev_hole && !h->next_hole) {
843                         /* last remaining hole */
844                         done = 1;
845                 } else if (!h->prev_hole) {
846                         /* first hole */
847                         first_hole = h->next_hole;
848                         payload[h->next_hole].prev_hole = 0;
849                 } else if (!h->next_hole) {
850                         /* last hole */
851                         payload[h->prev_hole].next_hole = 0;
852                 } else {
853                         /* in the middle of the list */
854                         payload[h->next_hole].prev_hole = h->prev_hole;
855                         payload[h->prev_hole].next_hole = h->next_hole;
856                 }
857
858         } else if (h->last_byte <= start + len) {
859                 /* overlaps with final part of the hole: shorten this hole */
860                 h->last_byte = start;
861
862         } else if (h >= thisfrag) {
863                 /* overlaps with initial part of the hole: move this hole */
864                 newh = thisfrag + (len / 8);
865                 *newh = *h;
866                 h = newh;
867                 if (h->next_hole)
868                         payload[h->next_hole].prev_hole = (h - payload);
869                 if (h->prev_hole)
870                         payload[h->prev_hole].next_hole = (h - payload);
871                 else
872                         first_hole = (h - payload);
873
874         } else {
875                 /* fragment sits in the middle: split the hole */
876                 newh = thisfrag + (len / 8);
877                 *newh = *h;
878                 h->last_byte = start;
879                 h->next_hole = (newh - payload);
880                 newh->prev_hole = (h - payload);
881                 if (newh->next_hole)
882                         payload[newh->next_hole].prev_hole = (newh - payload);
883         }
884
885         /* finally copy this fragment and possibly return whole packet */
886         memcpy((uchar *)thisfrag, indata + IP_HDR_SIZE_NO_UDP, len);
887         if (!done)
888                 return NULL;
889
890         localip->ip_len = htons(total_len);
891         *lenp = total_len + IP_HDR_SIZE_NO_UDP;
892         return localip;
893 }
894
895 static inline IP_t *NetDefragment(IP_t *ip, int *lenp)
896 {
897         u16 ip_off = ntohs(ip->ip_off);
898         if (!(ip_off & (IP_OFFS | IP_FLAGS_MFRAG)))
899                 return ip; /* not a fragment */
900         return __NetDefragment(ip, lenp);
901 }
902
903 #else /* !CONFIG_IP_DEFRAG */
904
905 static inline IP_t *NetDefragment(IP_t *ip, int *lenp)
906 {
907         u16 ip_off = ntohs(ip->ip_off);
908         if (!(ip_off & (IP_OFFS | IP_FLAGS_MFRAG)))
909                 return ip; /* not a fragment */
910         return NULL;
911 }
912 #endif
913
914 /**
915  * Receive an ICMP packet. We deal with REDIRECT and PING here, and silently
916  * drop others.
917  *
918  * @parma ip    IP packet containing the ICMP
919  */
920 static void receive_icmp(IP_t *ip, int len, IPaddr_t src_ip, Ethernet_t *et)
921 {
922         ICMP_t *icmph = (ICMP_t *)&ip->udp_src;
923
924         switch (icmph->type) {
925         case ICMP_REDIRECT:
926                 if (icmph->code != ICMP_REDIR_HOST)
927                         return;
928                 printf(" ICMP Host Redirect to %pI4 ",
929                         &icmph->un.gateway);
930                 break;
931 #if defined(CONFIG_CMD_PING)
932         case ICMP_ECHO_REPLY:
933                 /*
934                         * IP header OK.  Pass the packet to the
935                         * current handler.
936                         */
937                 /*
938                  * XXX point to ip packet - should this use
939                  * packet_icmp_handler?
940                  */
941                 (*packetHandler)((uchar *)ip, 0, src_ip, 0, 0);
942                 break;
943         case ICMP_ECHO_REQUEST:
944                 debug("Got ICMP ECHO REQUEST, return %d bytes\n",
945                         ETHER_HDR_SIZE + len);
946
947                 memcpy(&et->et_dest[0], &et->et_src[0], 6);
948                 memcpy(&et->et_src[0], NetOurEther, 6);
949
950                 ip->ip_sum = 0;
951                 ip->ip_off = 0;
952                 NetCopyIP((void *)&ip->ip_dst, &ip->ip_src);
953                 NetCopyIP((void *)&ip->ip_src, &NetOurIP);
954                 ip->ip_sum = ~NetCksum((uchar *)ip,
955                                         IP_HDR_SIZE_NO_UDP >> 1);
956
957                 icmph->type = ICMP_ECHO_REPLY;
958                 icmph->checksum = 0;
959                 icmph->checksum = ~NetCksum((uchar *)icmph,
960                         (len - IP_HDR_SIZE_NO_UDP) >> 1);
961                 (void) eth_send((uchar *)et,
962                                 ETHER_HDR_SIZE + len);
963                 break;
964 #endif
965         default:
966 #ifdef CONFIG_CMD_TFTPPUT
967                 if (packet_icmp_handler)
968                         packet_icmp_handler(icmph->type, icmph->code,
969                                 ntohs(ip->udp_dst), src_ip, ntohs(ip->udp_src),
970                                 icmph->un.data, ntohs(ip->udp_len));
971 #endif
972                 break;
973         }
974 }
975
976 void
977 NetReceive(uchar *inpkt, int len)
978 {
979         Ethernet_t *et;
980         IP_t    *ip;
981 #ifdef CONFIG_CMD_RARP
982         ARP_t   *arp;
983 #endif
984         IPaddr_t tmp;
985         IPaddr_t src_ip;
986         int     x;
987 #if defined(CONFIG_CMD_CDP)
988         int iscdp;
989 #endif
990         ushort cti = 0, vlanid = VLAN_NONE, myvlanid, mynvlanid;
991
992         debug("packet received\n");
993
994         NetRxPacket = inpkt;
995         NetRxPacketLen = len;
996         et = (Ethernet_t *)inpkt;
997
998         /* too small packet? */
999         if (len < ETHER_HDR_SIZE)
1000                 return;
1001
1002 #ifdef CONFIG_API
1003         if (push_packet) {
1004                 (*push_packet)(inpkt, len);
1005                 return;
1006         }
1007 #endif
1008
1009 #if defined(CONFIG_CMD_CDP)
1010         /* keep track if packet is CDP */
1011         iscdp = is_cdp_packet(et->et_dest);
1012 #endif
1013
1014         myvlanid = ntohs(NetOurVLAN);
1015         if (myvlanid == (ushort)-1)
1016                 myvlanid = VLAN_NONE;
1017         mynvlanid = ntohs(NetOurNativeVLAN);
1018         if (mynvlanid == (ushort)-1)
1019                 mynvlanid = VLAN_NONE;
1020
1021         x = ntohs(et->et_protlen);
1022
1023         debug("packet received\n");
1024
1025         if (x < 1514) {
1026                 /*
1027                  *      Got a 802 packet.  Check the other protocol field.
1028                  */
1029                 x = ntohs(et->et_prot);
1030
1031                 ip = (IP_t *)(inpkt + E802_HDR_SIZE);
1032                 len -= E802_HDR_SIZE;
1033
1034         } else if (x != PROT_VLAN) {    /* normal packet */
1035                 ip = (IP_t *)(inpkt + ETHER_HDR_SIZE);
1036                 len -= ETHER_HDR_SIZE;
1037
1038         } else {                        /* VLAN packet */
1039                 VLAN_Ethernet_t *vet = (VLAN_Ethernet_t *)et;
1040
1041                 debug("VLAN packet received\n");
1042
1043                 /* too small packet? */
1044                 if (len < VLAN_ETHER_HDR_SIZE)
1045                         return;
1046
1047                 /* if no VLAN active */
1048                 if ((ntohs(NetOurVLAN) & VLAN_IDMASK) == VLAN_NONE
1049 #if defined(CONFIG_CMD_CDP)
1050                                 && iscdp == 0
1051 #endif
1052                                 )
1053                         return;
1054
1055                 cti = ntohs(vet->vet_tag);
1056                 vlanid = cti & VLAN_IDMASK;
1057                 x = ntohs(vet->vet_type);
1058
1059                 ip = (IP_t *)(inpkt + VLAN_ETHER_HDR_SIZE);
1060                 len -= VLAN_ETHER_HDR_SIZE;
1061         }
1062
1063         debug("Receive from protocol 0x%x\n", x);
1064
1065 #if defined(CONFIG_CMD_CDP)
1066         if (iscdp) {
1067                 CDPHandler((uchar *)ip, len);
1068                 return;
1069         }
1070 #endif
1071
1072         if ((myvlanid & VLAN_IDMASK) != VLAN_NONE) {
1073                 if (vlanid == VLAN_NONE)
1074                         vlanid = (mynvlanid & VLAN_IDMASK);
1075                 /* not matched? */
1076                 if (vlanid != (myvlanid & VLAN_IDMASK))
1077                         return;
1078         }
1079
1080         switch (x) {
1081
1082         case PROT_ARP:
1083                 ArpReceive(et, ip, len);
1084                 break;
1085
1086 #ifdef CONFIG_CMD_RARP
1087         case PROT_RARP:
1088                 debug("Got RARP\n");
1089                 arp = (ARP_t *)ip;
1090                 if (len < ARP_HDR_SIZE) {
1091                         printf("bad length %d < %d\n", len, ARP_HDR_SIZE);
1092                         return;
1093                 }
1094
1095                 if ((ntohs(arp->ar_op) != RARPOP_REPLY) ||
1096                         (ntohs(arp->ar_hrd) != ARP_ETHER)   ||
1097                         (ntohs(arp->ar_pro) != PROT_IP)     ||
1098                         (arp->ar_hln != 6) || (arp->ar_pln != 4)) {
1099
1100                         puts("invalid RARP header\n");
1101                 } else {
1102                         NetCopyIP(&NetOurIP, &arp->ar_data[16]);
1103                         if (NetServerIP == 0)
1104                                 NetCopyIP(&NetServerIP, &arp->ar_data[6]);
1105                         memcpy(NetServerEther, &arp->ar_data[0], 6);
1106
1107                         (*packetHandler)(0, 0, 0, 0, 0);
1108                 }
1109                 break;
1110 #endif
1111         case PROT_IP:
1112                 debug("Got IP\n");
1113                 /* Before we start poking the header, make sure it is there */
1114                 if (len < IP_HDR_SIZE) {
1115                         debug("len bad %d < %lu\n", len, (ulong)IP_HDR_SIZE);
1116                         return;
1117                 }
1118                 /* Check the packet length */
1119                 if (len < ntohs(ip->ip_len)) {
1120                         printf("len bad %d < %d\n", len, ntohs(ip->ip_len));
1121                         return;
1122                 }
1123                 len = ntohs(ip->ip_len);
1124                 debug("len=%d, v=%02x\n", len, ip->ip_hl_v & 0xff);
1125
1126                 /* Can't deal with anything except IPv4 */
1127                 if ((ip->ip_hl_v & 0xf0) != 0x40)
1128                         return;
1129                 /* Can't deal with IP options (headers != 20 bytes) */
1130                 if ((ip->ip_hl_v & 0x0f) > 0x05)
1131                         return;
1132                 /* Check the Checksum of the header */
1133                 if (!NetCksumOk((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2)) {
1134                         puts("checksum bad\n");
1135                         return;
1136                 }
1137                 /* If it is not for us, ignore it */
1138                 tmp = NetReadIP(&ip->ip_dst);
1139                 if (NetOurIP && tmp != NetOurIP && tmp != 0xFFFFFFFF) {
1140 #ifdef CONFIG_MCAST_TFTP
1141                         if (Mcast_addr != tmp)
1142 #endif
1143                                 return;
1144                 }
1145                 /* Read source IP address for later use */
1146                 src_ip = NetReadIP(&ip->ip_src);
1147                 /*
1148                  * The function returns the unchanged packet if it's not
1149                  * a fragment, and either the complete packet or NULL if
1150                  * it is a fragment (if !CONFIG_IP_DEFRAG, it returns NULL)
1151                  */
1152                 ip = NetDefragment(ip, &len);
1153                 if (!ip)
1154                         return;
1155                 /*
1156                  * watch for ICMP host redirects
1157                  *
1158                  * There is no real handler code (yet). We just watch
1159                  * for ICMP host redirect messages. In case anybody
1160                  * sees these messages: please contact me
1161                  * (wd@denx.de), or - even better - send me the
1162                  * necessary fixes :-)
1163                  *
1164                  * Note: in all cases where I have seen this so far
1165                  * it was a problem with the router configuration,
1166                  * for instance when a router was configured in the
1167                  * BOOTP reply, but the TFTP server was on the same
1168                  * subnet. So this is probably a warning that your
1169                  * configuration might be wrong. But I'm not really
1170                  * sure if there aren't any other situations.
1171                  *
1172                  * Simon Glass <sjg@chromium.org>: We get an ICMP when
1173                  * we send a tftp packet to a dead connection, or when
1174                  * there is no server at the other end.
1175                  */
1176                 if (ip->ip_p == IPPROTO_ICMP) {
1177                         receive_icmp(ip, len, src_ip, et);
1178                         return;
1179                 } else if (ip->ip_p != IPPROTO_UDP) {   /* Only UDP packets */
1180                         return;
1181                 }
1182
1183 #ifdef CONFIG_UDP_CHECKSUM
1184                 if (ip->udp_xsum != 0) {
1185                         ulong   xsum;
1186                         ushort *sumptr;
1187                         ushort  sumlen;
1188
1189                         xsum  = ip->ip_p;
1190                         xsum += (ntohs(ip->udp_len));
1191                         xsum += (ntohl(ip->ip_src) >> 16) & 0x0000ffff;
1192                         xsum += (ntohl(ip->ip_src) >>  0) & 0x0000ffff;
1193                         xsum += (ntohl(ip->ip_dst) >> 16) & 0x0000ffff;
1194                         xsum += (ntohl(ip->ip_dst) >>  0) & 0x0000ffff;
1195
1196                         sumlen = ntohs(ip->udp_len);
1197                         sumptr = (ushort *) &(ip->udp_src);
1198
1199                         while (sumlen > 1) {
1200                                 ushort sumdata;
1201
1202                                 sumdata = *sumptr++;
1203                                 xsum += ntohs(sumdata);
1204                                 sumlen -= 2;
1205                         }
1206                         if (sumlen > 0) {
1207                                 ushort sumdata;
1208
1209                                 sumdata = *(unsigned char *) sumptr;
1210                                 sumdata = (sumdata << 8) & 0xff00;
1211                                 xsum += sumdata;
1212                         }
1213                         while ((xsum >> 16) != 0) {
1214                                 xsum = (xsum & 0x0000ffff) +
1215                                        ((xsum >> 16) & 0x0000ffff);
1216                         }
1217                         if ((xsum != 0x00000000) && (xsum != 0x0000ffff)) {
1218                                 printf(" UDP wrong checksum %08lx %08x\n",
1219                                         xsum, ntohs(ip->udp_xsum));
1220                                 return;
1221                         }
1222                 }
1223 #endif
1224
1225
1226 #ifdef CONFIG_NETCONSOLE
1227                 nc_input_packet((uchar *)ip + IP_HDR_SIZE,
1228                                                 ntohs(ip->udp_dst),
1229                                                 ntohs(ip->udp_src),
1230                                                 ntohs(ip->udp_len) - 8);
1231 #endif
1232                 /*
1233                  *      IP header OK.  Pass the packet to the current handler.
1234                  */
1235                 (*packetHandler)((uchar *)ip + IP_HDR_SIZE,
1236                                                 ntohs(ip->udp_dst),
1237                                                 src_ip,
1238                                                 ntohs(ip->udp_src),
1239                                                 ntohs(ip->udp_len) - 8);
1240                 break;
1241         }
1242 }
1243
1244
1245 /**********************************************************************/
1246
1247 static int net_check_prereq(enum proto_t protocol)
1248 {
1249         switch (protocol) {
1250                 /* Fall through */
1251 #if defined(CONFIG_CMD_PING)
1252         case PING:
1253                 if (NetPingIP == 0) {
1254                         puts("*** ERROR: ping address not given\n");
1255                         return 1;
1256                 }
1257                 goto common;
1258 #endif
1259 #if defined(CONFIG_CMD_SNTP)
1260         case SNTP:
1261                 if (NetNtpServerIP == 0) {
1262                         puts("*** ERROR: NTP server address not given\n");
1263                         return 1;
1264                 }
1265                 goto common;
1266 #endif
1267 #if defined(CONFIG_CMD_DNS)
1268         case DNS:
1269                 if (NetOurDNSIP == 0) {
1270                         puts("*** ERROR: DNS server address not given\n");
1271                         return 1;
1272                 }
1273                 goto common;
1274 #endif
1275 #if defined(CONFIG_CMD_NFS)
1276         case NFS:
1277 #endif
1278         case TFTPGET:
1279         case TFTPPUT:
1280                 if (NetServerIP == 0) {
1281                         puts("*** ERROR: `serverip' not set\n");
1282                         return 1;
1283                 }
1284 #if     defined(CONFIG_CMD_PING) || defined(CONFIG_CMD_SNTP) || \
1285         defined(CONFIG_CMD_DNS)
1286 common:
1287 #endif
1288                 /* Fall through */
1289
1290         case NETCONS:
1291         case TFTPSRV:
1292                 if (NetOurIP == 0) {
1293                         puts("*** ERROR: `ipaddr' not set\n");
1294                         return 1;
1295                 }
1296                 /* Fall through */
1297
1298 #ifdef CONFIG_CMD_RARP
1299         case RARP:
1300 #endif
1301         case BOOTP:
1302         case CDP:
1303         case DHCP:
1304                 if (memcmp(NetOurEther, "\0\0\0\0\0\0", 6) == 0) {
1305                         int num = eth_get_dev_index();
1306
1307                         switch (num) {
1308                         case -1:
1309                                 puts("*** ERROR: No ethernet found.\n");
1310                                 return 1;
1311                         case 0:
1312                                 puts("*** ERROR: `ethaddr' not set\n");
1313                                 break;
1314                         default:
1315                                 printf("*** ERROR: `eth%daddr' not set\n",
1316                                         num);
1317                                 break;
1318                         }
1319
1320                         NetStartAgain();
1321                         return 2;
1322                 }
1323                 /* Fall through */
1324         default:
1325                 return 0;
1326         }
1327         return 0;               /* OK */
1328 }
1329 /**********************************************************************/
1330
1331 int
1332 NetCksumOk(uchar *ptr, int len)
1333 {
1334         return !((NetCksum(ptr, len) + 1) & 0xfffe);
1335 }
1336
1337
1338 unsigned
1339 NetCksum(uchar *ptr, int len)
1340 {
1341         ulong   xsum;
1342         ushort *p = (ushort *)ptr;
1343
1344         xsum = 0;
1345         while (len-- > 0)
1346                 xsum += *p++;
1347         xsum = (xsum & 0xffff) + (xsum >> 16);
1348         xsum = (xsum & 0xffff) + (xsum >> 16);
1349         return xsum & 0xffff;
1350 }
1351
1352 int
1353 NetEthHdrSize(void)
1354 {
1355         ushort myvlanid;
1356
1357         myvlanid = ntohs(NetOurVLAN);
1358         if (myvlanid == (ushort)-1)
1359                 myvlanid = VLAN_NONE;
1360
1361         return ((myvlanid & VLAN_IDMASK) == VLAN_NONE) ? ETHER_HDR_SIZE :
1362                 VLAN_ETHER_HDR_SIZE;
1363 }
1364
1365 int
1366 NetSetEther(uchar *xet, uchar * addr, uint prot)
1367 {
1368         Ethernet_t *et = (Ethernet_t *)xet;
1369         ushort myvlanid;
1370
1371         myvlanid = ntohs(NetOurVLAN);
1372         if (myvlanid == (ushort)-1)
1373                 myvlanid = VLAN_NONE;
1374
1375         memcpy(et->et_dest, addr, 6);
1376         memcpy(et->et_src, NetOurEther, 6);
1377         if ((myvlanid & VLAN_IDMASK) == VLAN_NONE) {
1378                 et->et_protlen = htons(prot);
1379                 return ETHER_HDR_SIZE;
1380         } else {
1381                 VLAN_Ethernet_t *vet = (VLAN_Ethernet_t *)xet;
1382
1383                 vet->vet_vlan_type = htons(PROT_VLAN);
1384                 vet->vet_tag = htons((0 << 5) | (myvlanid & VLAN_IDMASK));
1385                 vet->vet_type = htons(prot);
1386                 return VLAN_ETHER_HDR_SIZE;
1387         }
1388 }
1389
1390 void
1391 NetSetIP(uchar *xip, IPaddr_t dest, int dport, int sport, int len)
1392 {
1393         IP_t *ip = (IP_t *)xip;
1394
1395         /*
1396          *      If the data is an odd number of bytes, zero the
1397          *      byte after the last byte so that the checksum
1398          *      will work.
1399          */
1400         if (len & 1)
1401                 xip[IP_HDR_SIZE + len] = 0;
1402
1403         /*
1404          *      Construct an IP and UDP header.
1405          *      (need to set no fragment bit - XXX)
1406          */
1407         /* IP_HDR_SIZE / 4 (not including UDP) */
1408         ip->ip_hl_v  = 0x45;
1409         ip->ip_tos   = 0;
1410         ip->ip_len   = htons(IP_HDR_SIZE + len);
1411         ip->ip_id    = htons(NetIPID++);
1412         ip->ip_off   = htons(IP_FLAGS_DFRAG);   /* Don't fragment */
1413         ip->ip_ttl   = 255;
1414         ip->ip_p     = 17;              /* UDP */
1415         ip->ip_sum   = 0;
1416         /* already in network byte order */
1417         NetCopyIP((void *)&ip->ip_src, &NetOurIP);
1418         /* - "" - */
1419         NetCopyIP((void *)&ip->ip_dst, &dest);
1420         ip->udp_src  = htons(sport);
1421         ip->udp_dst  = htons(dport);
1422         ip->udp_len  = htons(8 + len);
1423         ip->udp_xsum = 0;
1424         ip->ip_sum   = ~NetCksum((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2);
1425 }
1426
1427 void copy_filename(char *dst, const char *src, int size)
1428 {
1429         if (*src && (*src == '"')) {
1430                 ++src;
1431                 --size;
1432         }
1433
1434         while ((--size > 0) && *src && (*src != '"'))
1435                 *dst++ = *src++;
1436         *dst = '\0';
1437 }
1438
1439 #if     defined(CONFIG_CMD_NFS)         || \
1440         defined(CONFIG_CMD_SNTP)        || \
1441         defined(CONFIG_CMD_DNS)
1442 /*
1443  * make port a little random (1024-17407)
1444  * This keeps the math somewhat trivial to compute, and seems to work with
1445  * all supported protocols/clients/servers
1446  */
1447 unsigned int random_port(void)
1448 {
1449         return 1024 + (get_timer(0) % 0x4000);
1450 }
1451 #endif
1452
1453 void ip_to_string(IPaddr_t x, char *s)
1454 {
1455         x = ntohl(x);
1456         sprintf(s, "%d.%d.%d.%d",
1457                 (int) ((x >> 24) & 0xff),
1458                 (int) ((x >> 16) & 0xff),
1459                 (int) ((x >> 8) & 0xff), (int) ((x >> 0) & 0xff)
1460         );
1461 }
1462
1463 void VLAN_to_string(ushort x, char *s)
1464 {
1465         x = ntohs(x);
1466
1467         if (x == (ushort)-1)
1468                 x = VLAN_NONE;
1469
1470         if (x == VLAN_NONE)
1471                 strcpy(s, "none");
1472         else
1473                 sprintf(s, "%d", x & VLAN_IDMASK);
1474 }
1475
1476 ushort string_to_VLAN(const char *s)
1477 {
1478         ushort id;
1479
1480         if (s == NULL)
1481                 return htons(VLAN_NONE);
1482
1483         if (*s < '0' || *s > '9')
1484                 id = VLAN_NONE;
1485         else
1486                 id = (ushort)simple_strtoul(s, NULL, 10);
1487
1488         return htons(id);
1489 }
1490
1491 ushort getenv_VLAN(char *var)
1492 {
1493         return string_to_VLAN(getenv(var));
1494 }