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