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