blob: 6e0288dc0676cc7f2cd427d26b6add770eb58d0c [file] [log] [blame]
wdenk2d966952002-10-31 22:12:35 +00001/*
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
wdenkbe9c1cb2004-02-24 02:00:03 +000058 *
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
wdenk2d966952002-10-31 22:12:35 +000067 */
68
69
70#include <common.h>
71#include <watchdog.h>
72#include <command.h>
73#include <net.h>
74#include "bootp.h"
75#include "tftp.h"
76#include "rarp.h"
wdenkbe9c1cb2004-02-24 02:00:03 +000077#include "nfs.h"
wdenk49c3f672003-10-08 22:33:00 +000078#ifdef CONFIG_STATUS_LED
79#include <status_led.h>
80#include <miiphy.h>
81#endif
wdenk2d966952002-10-31 22:12:35 +000082
83#if (CONFIG_COMMANDS & CFG_CMD_NET)
84
wdenke6466f62003-06-05 19:27:42 +000085#define ARP_TIMEOUT 5 /* Seconds before trying ARP again */
86#ifndef CONFIG_NET_RETRY_COUNT
87# define ARP_TIMEOUT_COUNT 5 /* # of timeouts before giving up */
88#else
89# define ARP_TIMEOUT_COUNT (CONFIG_NET_RETRY_COUNT)
90#endif
91
wdenk2d966952002-10-31 22:12:35 +000092#if 0
93#define ET_DEBUG
94#endif
95
96/** BOOTP EXTENTIONS **/
97
98IPaddr_t NetOurSubnetMask=0; /* Our subnet mask (0=unknown) */
99IPaddr_t NetOurGatewayIP=0; /* Our gateways IP address */
100IPaddr_t NetOurDNSIP=0; /* Our DNS IP address */
stroesee0aadfb2003-08-28 14:17:32 +0000101#if (CONFIG_BOOTP_MASK & CONFIG_BOOTP_DNS2)
102IPaddr_t NetOurDNS2IP=0; /* Our 2nd DNS IP address */
103#endif
wdenk2d966952002-10-31 22:12:35 +0000104char NetOurNISDomain[32]={0,}; /* Our NIS domain */
105char NetOurHostName[32]={0,}; /* Our hostname */
106char NetOurRootPath[64]={0,}; /* Our bootpath */
107ushort NetBootFileSize=0; /* Our bootfile size in blocks */
108
109/** END OF BOOTP EXTENTIONS **/
110
111ulong NetBootFileXferSize; /* The actual transferred size of the bootfile (in bytes) */
112uchar NetOurEther[6]; /* Our ethernet address */
113uchar NetServerEther[6] = /* Boot server enet address */
wdenke6466f62003-06-05 19:27:42 +0000114 { 0, 0, 0, 0, 0, 0 };
wdenk2d966952002-10-31 22:12:35 +0000115IPaddr_t NetOurIP; /* Our IP addr (0 = unknown) */
116IPaddr_t NetServerIP; /* Our IP addr (0 = unknown) */
117volatile uchar *NetRxPkt; /* Current receive packet */
118int NetRxPktLen; /* Current rx packet length */
119unsigned NetIPID; /* IP packet ID */
120uchar NetBcastAddr[6] = /* Ethernet bcast address */
121 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
wdenke6466f62003-06-05 19:27:42 +0000122uchar NetEtherNullAddr[6] =
123 { 0, 0, 0, 0, 0, 0 };
wdenk145d2c12004-04-15 21:48:45 +0000124#if (CONFIG_COMMANDS & CFG_CMD_CDP)
wdenk05939202004-04-18 17:39:38 +0000125uchar NetCDPAddr[6] = /* Ethernet bcast address */
wdenk145d2c12004-04-15 21:48:45 +0000126 { 0x01, 0x00, 0x0c, 0xcc, 0xcc, 0xcc };
127#endif
wdenk2d966952002-10-31 22:12:35 +0000128int NetState; /* Network loop state */
129#ifdef CONFIG_NET_MULTI
130int NetRestartWrap = 0; /* Tried all network devices */
131static int NetRestarted = 0; /* Network loop restarted */
132static int NetDevExists = 0; /* At least one device configured */
133#endif
134
wdenk05939202004-04-18 17:39:38 +0000135/* XXX in both little & big endian machines 0xFFFF == ntohs(-1) */
136ushort NetOurVLAN = 0xFFFF; /* default is without VLAN */
137ushort NetOurNativeVLAN = 0xFFFF; /* ditto */
wdenk145d2c12004-04-15 21:48:45 +0000138
wdenk2d966952002-10-31 22:12:35 +0000139char BootFile[128]; /* Boot File name */
140
wdenke6466f62003-06-05 19:27:42 +0000141#if (CONFIG_COMMANDS & CFG_CMD_PING)
142IPaddr_t NetPingIP; /* the ip address to ping */
143
144static void PingStart(void);
145#endif
146
wdenk145d2c12004-04-15 21:48:45 +0000147#if (CONFIG_COMMANDS & CFG_CMD_CDP)
148static void CDPStart(void);
149#endif
150
wdenk2d966952002-10-31 22:12:35 +0000151volatile uchar PktBuf[(PKTBUFSRX+1) * PKTSIZE_ALIGN + PKTALIGN];
152
153volatile uchar *NetRxPackets[PKTBUFSRX]; /* Receive packets */
154
155static rxhand_f *packetHandler; /* Current RX packet handler */
156static thand_f *timeHandler; /* Current timeout handler */
wdenk5d841732003-08-17 18:55:18 +0000157static ulong timeStart; /* Time base value */
158static ulong timeDelta; /* Current timeout value */
wdenk2d966952002-10-31 22:12:35 +0000159volatile uchar *NetTxPacket = 0; /* THE transmit packet */
160
161static int net_check_prereq (proto_t protocol);
162
163/**********************************************************************/
wdenke6466f62003-06-05 19:27:42 +0000164
165IPaddr_t NetArpWaitPacketIP;
166IPaddr_t NetArpWaitReplyIP;
167uchar *NetArpWaitPacketMAC; /* MAC address of waiting packet's destination */
168uchar *NetArpWaitTxPacket; /* THE transmit packet */
169int NetArpWaitTxPacketSize;
170uchar NetArpWaitPacketBuf[PKTSIZE_ALIGN + PKTALIGN];
171ulong NetArpWaitTimerStart;
172int NetArpWaitTry;
173
wdenk05939202004-04-18 17:39:38 +0000174void ArpRequest (void)
wdenke6466f62003-06-05 19:27:42 +0000175{
176 int i;
177 volatile uchar *pkt;
wdenk05939202004-04-18 17:39:38 +0000178 ARP_t *arp;
wdenke6466f62003-06-05 19:27:42 +0000179
180#ifdef ET_DEBUG
wdenk05939202004-04-18 17:39:38 +0000181 printf ("ARP broadcast %d\n", NetArpWaitTry);
wdenke6466f62003-06-05 19:27:42 +0000182#endif
183 pkt = NetTxPacket;
184
wdenk05939202004-04-18 17:39:38 +0000185 pkt += NetSetEther (pkt, NetBcastAddr, PROT_ARP);
wdenke6466f62003-06-05 19:27:42 +0000186
wdenk05939202004-04-18 17:39:38 +0000187 arp = (ARP_t *) pkt;
wdenke6466f62003-06-05 19:27:42 +0000188
wdenk05939202004-04-18 17:39:38 +0000189 arp->ar_hrd = htons (ARP_ETHER);
190 arp->ar_pro = htons (PROT_IP);
wdenke6466f62003-06-05 19:27:42 +0000191 arp->ar_hln = 6;
192 arp->ar_pln = 4;
wdenk05939202004-04-18 17:39:38 +0000193 arp->ar_op = htons (ARPOP_REQUEST);
wdenke6466f62003-06-05 19:27:42 +0000194
wdenk05939202004-04-18 17:39:38 +0000195 memcpy (&arp->ar_data[0], NetOurEther, 6); /* source ET addr */
196 NetWriteIP ((uchar *) & arp->ar_data[6], NetOurIP); /* source IP addr */
197 for (i = 10; i < 16; ++i) {
198 arp->ar_data[i] = 0; /* dest ET addr = 0 */
wdenke6466f62003-06-05 19:27:42 +0000199 }
200
wdenk05939202004-04-18 17:39:38 +0000201 if ((NetArpWaitPacketIP & NetOurSubnetMask) !=
202 (NetOurIP & NetOurSubnetMask)) {
203 if (NetOurGatewayIP == 0) {
204 puts ("## Warning: gatewayip needed but not set\n");
205 }
206 NetArpWaitReplyIP = NetOurGatewayIP;
207 } else {
208 NetArpWaitReplyIP = NetArpWaitPacketIP;
209 }
wdenke6466f62003-06-05 19:27:42 +0000210
wdenk05939202004-04-18 17:39:38 +0000211 NetWriteIP ((uchar *) & arp->ar_data[16], NetArpWaitReplyIP);
212 (void) eth_send (NetTxPacket, (pkt - NetTxPacket) + ARP_HDR_SIZE);
wdenke6466f62003-06-05 19:27:42 +0000213}
214
215void ArpTimeoutCheck(void)
216{
217 ulong t;
218
219 if (!NetArpWaitPacketIP)
220 return;
221
222 t = get_timer(0);
223
224 /* check for arp timeout */
225 if ((t - NetArpWaitTimerStart) > ARP_TIMEOUT * CFG_HZ) {
226 NetArpWaitTry++;
227
228 if (NetArpWaitTry >= ARP_TIMEOUT_COUNT) {
229 puts ("\nARP Retry count exceeded; starting again\n");
230 NetArpWaitTry = 0;
231 NetStartAgain();
232 } else {
233 NetArpWaitTimerStart = t;
234 ArpRequest();
235 }
236 }
237}
238
239/**********************************************************************/
wdenk2d966952002-10-31 22:12:35 +0000240/*
241 * Main network processing loop.
242 */
243
244int
245NetLoop(proto_t protocol)
246{
247 DECLARE_GLOBAL_DATA_PTR;
248
249 bd_t *bd = gd->bd;
250
251#ifdef CONFIG_NET_MULTI
252 NetRestarted = 0;
253 NetDevExists = 0;
254#endif
255
wdenke6466f62003-06-05 19:27:42 +0000256 /* XXX problem with bss workaround */
257 NetArpWaitPacketMAC = NULL;
258 NetArpWaitTxPacket = NULL;
259 NetArpWaitPacketIP = 0;
260 NetArpWaitReplyIP = 0;
261 NetArpWaitTxPacket = NULL;
262 NetTxPacket = NULL;
263
wdenk2d966952002-10-31 22:12:35 +0000264 if (!NetTxPacket) {
265 int i;
wdenk2d966952002-10-31 22:12:35 +0000266 /*
267 * Setup packet buffers, aligned correctly.
268 */
269 NetTxPacket = &PktBuf[0] + (PKTALIGN - 1);
270 NetTxPacket -= (ulong)NetTxPacket % PKTALIGN;
271 for (i = 0; i < PKTBUFSRX; i++) {
272 NetRxPackets[i] = NetTxPacket + (i+1)*PKTSIZE_ALIGN;
273 }
wdenke6466f62003-06-05 19:27:42 +0000274 }
275
276 if (!NetArpWaitTxPacket) {
277 NetArpWaitTxPacket = &NetArpWaitPacketBuf[0] + (PKTALIGN - 1);
278 NetArpWaitTxPacket -= (ulong)NetArpWaitTxPacket % PKTALIGN;
279 NetArpWaitTxPacketSize = 0;
wdenk2d966952002-10-31 22:12:35 +0000280 }
281
282 eth_halt();
wdenk05939202004-04-18 17:39:38 +0000283#ifdef CONFIG_NET_MULTI
wdenk145d2c12004-04-15 21:48:45 +0000284 eth_set_current();
wdenk05939202004-04-18 17:39:38 +0000285#endif
286 if (eth_init(bd) < 0)
287 return(-1);
wdenk2d966952002-10-31 22:12:35 +0000288
289restart:
290#ifdef CONFIG_NET_MULTI
291 memcpy (NetOurEther, eth_get_dev()->enetaddr, 6);
292#else
293 memcpy (NetOurEther, bd->bi_enetaddr, 6);
294#endif
295
296 NetState = NETLOOP_CONTINUE;
297
298 /*
299 * Start the ball rolling with the given start function. From
300 * here on, this code is a state machine driven by received
301 * packets and timer events.
302 */
303
304 switch (protocol) {
wdenkbe9c1cb2004-02-24 02:00:03 +0000305#if (CONFIG_COMMANDS & CFG_CMD_NFS)
306 case NFS:
307#endif
wdenke6466f62003-06-05 19:27:42 +0000308#if (CONFIG_COMMANDS & CFG_CMD_PING)
309 case PING:
310#endif
wdenk2d966952002-10-31 22:12:35 +0000311 case TFTP:
312 NetCopyIP(&NetOurIP, &bd->bi_ip_addr);
wdenk2d966952002-10-31 22:12:35 +0000313 NetOurGatewayIP = getenv_IPaddr ("gatewayip");
314 NetOurSubnetMask= getenv_IPaddr ("netmask");
wdenk145d2c12004-04-15 21:48:45 +0000315 NetOurVLAN = getenv_VLAN("vlan");
316 NetOurNativeVLAN = getenv_VLAN("nvlan");
wdenke6466f62003-06-05 19:27:42 +0000317
318 switch (protocol) {
wdenkbe9c1cb2004-02-24 02:00:03 +0000319#if (CONFIG_COMMANDS & CFG_CMD_NFS)
320 case NFS:
321#endif
wdenke6466f62003-06-05 19:27:42 +0000322 case TFTP:
323 NetServerIP = getenv_IPaddr ("serverip");
324 break;
325#if (CONFIG_COMMANDS & CFG_CMD_PING)
326 case PING:
327 /* nothing */
328 break;
329#endif
330 default:
331 break;
332 }
333
wdenk2d966952002-10-31 22:12:35 +0000334 break;
335 case BOOTP:
336 case RARP:
337 /*
wdenk57b2d802003-06-27 21:31:46 +0000338 * initialize our IP addr to 0 in order to accept ANY
339 * IP addr assigned to us by the BOOTP / RARP server
wdenk2d966952002-10-31 22:12:35 +0000340 */
341 NetOurIP = 0;
wdenk4989f872004-03-14 15:06:13 +0000342 NetServerIP = getenv_IPaddr ("serverip");
wdenk145d2c12004-04-15 21:48:45 +0000343 NetOurVLAN = getenv_VLAN("vlan"); /* VLANs must be read */
344 NetOurNativeVLAN = getenv_VLAN("nvlan");
345 case CDP:
346 NetOurVLAN = getenv_VLAN("vlan"); /* VLANs must be read */
347 NetOurNativeVLAN = getenv_VLAN("nvlan");
wdenk2d966952002-10-31 22:12:35 +0000348 break;
349 default:
350 break;
351 }
352
353 switch (net_check_prereq (protocol)) {
354 case 1:
355 /* network not configured */
wdenk2582f6b2002-11-11 21:14:20 +0000356 return (-1);
wdenk2d966952002-10-31 22:12:35 +0000357
358#ifdef CONFIG_NET_MULTI
359 case 2:
360 /* network device not configured */
361 break;
362#endif /* CONFIG_NET_MULTI */
363
364 case 0:
365#ifdef CONFIG_NET_MULTI
366 NetDevExists = 1;
367#endif
368 switch (protocol) {
369 case TFTP:
370 /* always use ARP to get server ethernet address */
wdenke6466f62003-06-05 19:27:42 +0000371 TftpStart();
wdenk2d966952002-10-31 22:12:35 +0000372 break;
373
374#if (CONFIG_COMMANDS & CFG_CMD_DHCP)
375 case DHCP:
376 /* Start with a clean slate... */
377 NetOurIP = 0;
wdenk4989f872004-03-14 15:06:13 +0000378 NetServerIP = getenv_IPaddr ("serverip");
wdenk2d966952002-10-31 22:12:35 +0000379 DhcpRequest(); /* Basically same as BOOTP */
380 break;
381#endif /* CFG_CMD_DHCP */
382
383 case BOOTP:
384 BootpTry = 0;
385 BootpRequest ();
386 break;
387
388 case RARP:
389 RarpTry = 0;
390 RarpRequest ();
391 break;
wdenke6466f62003-06-05 19:27:42 +0000392#if (CONFIG_COMMANDS & CFG_CMD_PING)
393 case PING:
394 PingStart();
395 break;
396#endif
wdenkbe9c1cb2004-02-24 02:00:03 +0000397#if (CONFIG_COMMANDS & CFG_CMD_NFS)
398 case NFS:
399 NfsStart();
400 break;
401#endif
wdenk145d2c12004-04-15 21:48:45 +0000402#if (CONFIG_COMMANDS & CFG_CMD_CDP)
403 case CDP:
404 CDPStart();
405 break;
406#endif
wdenk2d966952002-10-31 22:12:35 +0000407 default:
408 break;
409 }
410
411 NetBootFileXferSize = 0;
412 break;
413 }
414
wdenk49c3f672003-10-08 22:33:00 +0000415#if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII)
416#if defined(CFG_FAULT_ECHO_LINK_DOWN) && defined(CONFIG_STATUS_LED) && defined(STATUS_LED_RED)
417 /*
wdenk9c53f402003-10-15 23:53:47 +0000418 * Echo the inverted link state to the fault LED.
wdenk49c3f672003-10-08 22:33:00 +0000419 */
420 if(miiphy_link(CFG_FAULT_MII_ADDR)) {
421 status_led_set (STATUS_LED_RED, STATUS_LED_OFF);
422 } else {
423 status_led_set (STATUS_LED_RED, STATUS_LED_ON);
424 }
425#endif /* CFG_FAULT_ECHO_LINK_DOWN, ... */
426#endif /* CONFIG_MII, ... */
wdenk2d966952002-10-31 22:12:35 +0000427
428 /*
429 * Main packet reception loop. Loop receiving packets until
430 * someone sets `NetQuit'.
431 */
432 for (;;) {
433 WATCHDOG_RESET();
434#ifdef CONFIG_SHOW_ACTIVITY
435 {
436 extern void show_activity(int arg);
437 show_activity(1);
438 }
439#endif
440 /*
441 * Check the ethernet for a new packet. The ethernet
442 * receive routine will process it.
443 */
444 eth_rx();
445
446 /*
447 * Abort if ctrl-c was pressed.
448 */
449 if (ctrlc()) {
wdenk57b2d802003-06-27 21:31:46 +0000450 eth_halt();
wdenk42c05472004-03-23 22:14:11 +0000451 puts ("\nAbort\n");
wdenk2582f6b2002-11-11 21:14:20 +0000452 return (-1);
wdenk2d966952002-10-31 22:12:35 +0000453 }
454
wdenke6466f62003-06-05 19:27:42 +0000455 ArpTimeoutCheck();
wdenk2d966952002-10-31 22:12:35 +0000456
457 /*
458 * Check for a timeout, and run the timeout handler
459 * if we have one.
460 */
wdenk5d841732003-08-17 18:55:18 +0000461 if (timeHandler && ((get_timer(0) - timeStart) > timeDelta)) {
wdenk2d966952002-10-31 22:12:35 +0000462 thand_f *x;
463
wdenk49c3f672003-10-08 22:33:00 +0000464#if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII)
465#if defined(CFG_FAULT_ECHO_LINK_DOWN) && defined(CONFIG_STATUS_LED) && defined(STATUS_LED_RED)
466 /*
wdenk9c53f402003-10-15 23:53:47 +0000467 * Echo the inverted link state to the fault LED.
wdenk49c3f672003-10-08 22:33:00 +0000468 */
469 if(miiphy_link(CFG_FAULT_MII_ADDR)) {
470 status_led_set (STATUS_LED_RED, STATUS_LED_OFF);
471 } else {
472 status_led_set (STATUS_LED_RED, STATUS_LED_ON);
473 }
474#endif /* CFG_FAULT_ECHO_LINK_DOWN, ... */
475#endif /* CONFIG_MII, ... */
wdenk2d966952002-10-31 22:12:35 +0000476 x = timeHandler;
477 timeHandler = (thand_f *)0;
478 (*x)();
479 }
480
481
482 switch (NetState) {
483
484 case NETLOOP_RESTART:
485#ifdef CONFIG_NET_MULTI
486 NetRestarted = 1;
487#endif
488 goto restart;
489
490 case NETLOOP_SUCCESS:
491 if (NetBootFileXferSize > 0) {
492 char buf[10];
493 printf("Bytes transferred = %ld (%lx hex)\n",
494 NetBootFileXferSize,
495 NetBootFileXferSize);
496 sprintf(buf, "%lx", NetBootFileXferSize);
497 setenv("filesize", buf);
wdenk145d2c12004-04-15 21:48:45 +0000498
499 sprintf(buf, "%lX", (unsigned long)load_addr);
500 setenv("fileaddr", buf);
wdenk2d966952002-10-31 22:12:35 +0000501 }
502 eth_halt();
503 return NetBootFileXferSize;
504
505 case NETLOOP_FAIL:
wdenk2582f6b2002-11-11 21:14:20 +0000506 return (-1);
wdenk2d966952002-10-31 22:12:35 +0000507 }
508 }
509}
510
511/**********************************************************************/
512
513static void
514startAgainTimeout(void)
515{
516 NetState = NETLOOP_RESTART;
517}
518
519static void
520startAgainHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len)
521{
522 /* Totally ignore the packet */
523}
524
wdenk05939202004-04-18 17:39:38 +0000525void NetStartAgain (void)
wdenk2d966952002-10-31 22:12:35 +0000526{
wdenk05939202004-04-18 17:39:38 +0000527#ifdef CONFIG_NET_MULTI
wdenk145d2c12004-04-15 21:48:45 +0000528 DECLARE_GLOBAL_DATA_PTR;
wdenk05939202004-04-18 17:39:38 +0000529#endif
530 char *nretry;
531 int noretry = 0, once = 0;
wdenk145d2c12004-04-15 21:48:45 +0000532
wdenk05939202004-04-18 17:39:38 +0000533 if ((nretry = getenv ("netretry")) != NULL) {
534 noretry = (strcmp (nretry, "no") == 0);
535 once = (strcmp (nretry, "once") == 0);
536 }
537 if (noretry) {
538 eth_halt ();
wdenk145d2c12004-04-15 21:48:45 +0000539 NetState = NETLOOP_FAIL;
540 return;
541 }
wdenk2d966952002-10-31 22:12:35 +0000542#ifndef CONFIG_NET_MULTI
wdenk05939202004-04-18 17:39:38 +0000543 NetSetTimeout (10 * CFG_HZ, startAgainTimeout);
544 NetSetHandler (startAgainHandler);
545#else /* !CONFIG_NET_MULTI*/
546 eth_halt ();
547 eth_try_another (!NetRestarted);
548 eth_init (gd->bd);
549 if (NetRestartWrap) {
wdenk2d966952002-10-31 22:12:35 +0000550 NetRestartWrap = 0;
wdenk05939202004-04-18 17:39:38 +0000551 if (NetDevExists && !once) {
552 NetSetTimeout (10 * CFG_HZ, startAgainTimeout);
553 NetSetHandler (startAgainHandler);
554 } else {
wdenk2d966952002-10-31 22:12:35 +0000555 NetState = NETLOOP_FAIL;
556 }
wdenk05939202004-04-18 17:39:38 +0000557 } else {
wdenk2d966952002-10-31 22:12:35 +0000558 NetState = NETLOOP_RESTART;
559 }
wdenk05939202004-04-18 17:39:38 +0000560#endif /* CONFIG_NET_MULTI */
wdenk2d966952002-10-31 22:12:35 +0000561}
562
563/**********************************************************************/
564/*
565 * Miscelaneous bits.
566 */
567
568void
569NetSetHandler(rxhand_f * f)
570{
571 packetHandler = f;
572}
573
574
575void
576NetSetTimeout(int iv, thand_f * f)
577{
578 if (iv == 0) {
579 timeHandler = (thand_f *)0;
580 } else {
581 timeHandler = f;
wdenk5d841732003-08-17 18:55:18 +0000582 timeStart = get_timer(0);
583 timeDelta = iv;
wdenk2d966952002-10-31 22:12:35 +0000584 }
585}
586
587
588void
589NetSendPacket(volatile uchar * pkt, int len)
590{
591 (void) eth_send(pkt, len);
592}
593
wdenke6466f62003-06-05 19:27:42 +0000594int
595NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, int sport, int len)
596{
wdenk145d2c12004-04-15 21:48:45 +0000597 uchar *pkt;
598
wdenke6466f62003-06-05 19:27:42 +0000599 /* convert to new style broadcast */
600 if (dest == 0)
601 dest = 0xFFFFFFFF;
602
603 /* if broadcast, make the ether address a broadcast and don't do ARP */
604 if (dest == 0xFFFFFFFF)
605 ether = NetBcastAddr;
606
607 /* if MAC address was not discovered yet, save the packet and do an ARP request */
608 if (memcmp(ether, NetEtherNullAddr, 6) == 0) {
609
610#ifdef ET_DEBUG
611 printf("sending ARP for %08lx\n", dest);
612#endif
wdenke6466f62003-06-05 19:27:42 +0000613 NetArpWaitPacketIP = dest;
614 NetArpWaitPacketMAC = ether;
wdenk145d2c12004-04-15 21:48:45 +0000615
616 pkt = NetArpWaitTxPacket;
617 pkt += NetSetEther (pkt, NetArpWaitPacketMAC, PROT_IP);
618
619 NetSetIP (pkt, dest, dport, sport, len);
620 memcpy(pkt + IP_HDR_SIZE, (uchar *)NetTxPacket + (pkt - (uchar *)NetArpWaitTxPacket) + IP_HDR_SIZE, len);
wdenke6466f62003-06-05 19:27:42 +0000621
622 /* size of the waiting packet */
wdenk145d2c12004-04-15 21:48:45 +0000623 NetArpWaitTxPacketSize = (pkt - NetArpWaitTxPacket) + IP_HDR_SIZE + len;
wdenke6466f62003-06-05 19:27:42 +0000624
625 /* and do the ARP request */
626 NetArpWaitTry = 1;
627 NetArpWaitTimerStart = get_timer(0);
628 ArpRequest();
629 return 1; /* waiting */
630 }
631
632#ifdef ET_DEBUG
633 printf("sending UDP to %08lx/%02x:%02x:%02x:%02x:%02x:%02x\n",
wdenk05939202004-04-18 17:39:38 +0000634 dest, ether[0], ether[1], ether[2], ether[3], ether[4], ether[5]);
wdenke6466f62003-06-05 19:27:42 +0000635#endif
636
wdenk145d2c12004-04-15 21:48:45 +0000637 pkt = (uchar *)NetTxPacket;
638 pkt += NetSetEther (pkt, ether, PROT_IP);
639 NetSetIP (pkt, dest, dport, sport, len);
640 (void) eth_send(NetTxPacket, (pkt - NetTxPacket) + IP_HDR_SIZE + len);
wdenke6466f62003-06-05 19:27:42 +0000641
wdenk05939202004-04-18 17:39:38 +0000642 return 0; /* transmitted */
wdenke6466f62003-06-05 19:27:42 +0000643}
644
645#if (CONFIG_COMMANDS & CFG_CMD_PING)
646static ushort PingSeqNo;
647
648int PingSend(void)
649{
650 static uchar mac[6];
651 volatile IP_t *ip;
652 volatile ushort *s;
wdenk145d2c12004-04-15 21:48:45 +0000653 uchar *pkt;
wdenke6466f62003-06-05 19:27:42 +0000654
655 /* XXX always send arp request */
656
657 memcpy(mac, NetEtherNullAddr, 6);
658
659#ifdef ET_DEBUG
660 printf("sending ARP for %08lx\n", NetPingIP);
661#endif
662
663 NetArpWaitPacketIP = NetPingIP;
664 NetArpWaitPacketMAC = mac;
665
wdenk145d2c12004-04-15 21:48:45 +0000666 pkt = NetArpWaitTxPacket;
667 pkt += NetSetEther(pkt, mac, PROT_IP);
wdenke6466f62003-06-05 19:27:42 +0000668
wdenk145d2c12004-04-15 21:48:45 +0000669 ip = (volatile IP_t *)pkt;
wdenke6466f62003-06-05 19:27:42 +0000670
671 /*
672 * Construct an IP and ICMP header. (need to set no fragment bit - XXX)
673 */
674 ip->ip_hl_v = 0x45; /* IP_HDR_SIZE / 4 (not including UDP) */
675 ip->ip_tos = 0;
676 ip->ip_len = htons(IP_HDR_SIZE_NO_UDP + 8);
677 ip->ip_id = htons(NetIPID++);
678 ip->ip_off = htons(0x4000); /* No fragmentation */
679 ip->ip_ttl = 255;
680 ip->ip_p = 0x01; /* ICMP */
681 ip->ip_sum = 0;
682 NetCopyIP((void*)&ip->ip_src, &NetOurIP); /* already in network byte order */
683 NetCopyIP((void*)&ip->ip_dst, &NetPingIP); /* - "" - */
684 ip->ip_sum = ~NetCksum((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2);
685
686 s = &ip->udp_src; /* XXX ICMP starts here */
687 s[0] = htons(0x0800); /* echo-request, code */
688 s[1] = 0; /* checksum */
689 s[2] = 0; /* identifier */
690 s[3] = htons(PingSeqNo++); /* sequence number */
691 s[1] = ~NetCksum((uchar *)s, 8/2);
692
693 /* size of the waiting packet */
wdenk145d2c12004-04-15 21:48:45 +0000694 NetArpWaitTxPacketSize = (pkt - NetArpWaitTxPacket) + IP_HDR_SIZE_NO_UDP + 8;
wdenke6466f62003-06-05 19:27:42 +0000695
696 /* and do the ARP request */
697 NetArpWaitTry = 1;
698 NetArpWaitTimerStart = get_timer(0);
699 ArpRequest();
700 return 1; /* waiting */
701}
702
703static void
704PingTimeout (void)
705{
706 eth_halt();
707 NetState = NETLOOP_FAIL; /* we did not get the reply */
708}
709
710static void
711PingHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len)
712{
713 IPaddr_t tmp;
714 volatile IP_t *ip = (volatile IP_t *)pkt;
715
716 tmp = NetReadIP((void *)&ip->ip_src);
717 if (tmp != NetPingIP)
718 return;
719
720 NetState = NETLOOP_SUCCESS;
721}
722
723static void PingStart(void)
724{
wdenk145d2c12004-04-15 21:48:45 +0000725#if defined(CONFIG_NET_MULTI)
726 printf ("Using %s device\n", eth_get_name());
wdenk05939202004-04-18 17:39:38 +0000727#endif /* CONFIG_NET_MULTI */
wdenke6466f62003-06-05 19:27:42 +0000728 NetSetTimeout (10 * CFG_HZ, PingTimeout);
729 NetSetHandler (PingHandler);
730
731 PingSend();
732}
wdenk05939202004-04-18 17:39:38 +0000733#endif /* CFG_CMD_PING */
wdenk145d2c12004-04-15 21:48:45 +0000734
735#if (CONFIG_COMMANDS & CFG_CMD_CDP)
736
737#define CDP_DEVICE_ID_TLV 0x0001
738#define CDP_ADDRESS_TLV 0x0002
739#define CDP_PORT_ID_TLV 0x0003
740#define CDP_CAPABILITIES_TLV 0x0004
741#define CDP_VERSION_TLV 0x0005
742#define CDP_PLATFORM_TLV 0x0006
743#define CDP_NATIVE_VLAN_TLV 0x000a
744#define CDP_APPLIANCE_VLAN_TLV 0x000e
745#define CDP_TRIGGER_TLV 0x000f
746#define CDP_POWER_CONSUMPTION_TLV 0x0010
747#define CDP_SYSNAME_TLV 0x0014
748#define CDP_SYSOBJECT_TLV 0x0015
749#define CDP_MANAGEMENT_ADDRESS_TLV 0x0016
750
751#define CDP_TIMEOUT (CFG_HZ/4) /* one packet every 250ms */
752
753static int CDPSeq;
754static int CDPOK;
755
756ushort CDPNativeVLAN;
757ushort CDPApplianceVLAN;
758
759static const uchar CDP_SNAP_hdr[8] = { 0xAA, 0xAA, 0x03, 0x00, 0x00, 0x0C, 0x20, 0x00 };
760
761static ushort CDP_compute_csum(const uchar *buff, ushort len)
762{
763 ushort csum;
764 int odd;
765 ulong result = 0;
766 ushort leftover;
767
768 if (len > 0) {
769 odd = 1 & (ulong)buff;
770 if (odd) {
771 result = *buff << 8;
772 len--;
773 buff++;
774 }
775 while (len > 1) {
776 result += *((const ushort *)buff)++;
777 if (result & 0x80000000)
778 result = (result & 0xFFFF) + (result >> 16);
779 len -= 2;
780 }
781 if (len) {
782 leftover = (signed short)(*(const signed char *)buff);
783 /* * XXX CISCO SUCKS big time! (and blows too) */
784 result = (result & 0xffff0000) | ((result + leftover) & 0x0000ffff);
785 }
786 while (result >> 16)
787 result = (result & 0xFFFF) + (result >> 16);
788
789 if (odd)
790 result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
791 }
792
793 /* add up 16-bit and 17-bit words for 17+c bits */
794 result = (result & 0xffff) + (result >> 16);
795 /* add up 16-bit and 2-bit for 16+c bit */
796 result = (result & 0xffff) + (result >> 16);
797 /* add up carry.. */
798 result = (result & 0xffff) + (result >> 16);
799
800 /* negate */
801 csum = ~(ushort)result;
802
803 /* run time endian detection */
804 if (csum != htons(csum)) /* little endian */
805 csum = htons(csum);
806
807 return csum;
808}
809
810int CDPSendTrigger(void)
811{
812 volatile uchar *pkt;
813 volatile ushort *s;
814 volatile ushort *cp;
815 Ethernet_t *et;
wdenk145d2c12004-04-15 21:48:45 +0000816 int len;
817 ushort chksum;
wdenk05939202004-04-18 17:39:38 +0000818#if defined(CONFIG_CDP_DEVICE_ID) || defined(CONFIG_CDP_PORT_ID) || \
819 defined(CONFIG_CDP_VERSION) || defined(CONFIG_CDP_PLATFORM)
820 char buf[32];
821#endif
wdenk145d2c12004-04-15 21:48:45 +0000822
823 pkt = NetTxPacket;
824 et = (Ethernet_t *)pkt;
825
826 /* NOTE: trigger sent not on any VLAN */
827
828 /* form ethernet header */
829 memcpy(et->et_dest, NetCDPAddr, 6);
830 memcpy(et->et_src, NetOurEther, 6);
831
832 pkt += ETHER_HDR_SIZE;
833
834 /* SNAP header */
835 memcpy((uchar *)pkt, CDP_SNAP_hdr, sizeof(CDP_SNAP_hdr));
836 pkt += sizeof(CDP_SNAP_hdr);
837
838 /* CDP header */
839 *pkt++ = 0x02; /* CDP version 2 */
840 *pkt++ = 180; /* TTL */
841 s = (volatile ushort *)pkt;
842 cp = s;
843 *s++ = htons(0); /* checksum (0 for later calculation) */
844
845 /* CDP fields */
846#ifdef CONFIG_CDP_DEVICE_ID
847 *s++ = htons(CDP_DEVICE_ID_TLV);
848 *s++ = htons(CONFIG_CDP_DEVICE_ID);
849 memset(buf, 0, sizeof(buf));
850 sprintf(buf, CONFIG_CDP_DEVICE_ID_PREFIX "%02X%02X%02X%02X%02X%02X",
851 NetOurEther[0] & 0xff, NetOurEther[1] & 0xff,
852 NetOurEther[2] & 0xff, NetOurEther[3] & 0xff,
853 NetOurEther[4] & 0xff, NetOurEther[5] & 0xff);
854 memcpy((uchar *)s, buf, 16);
855 s += 16 / 2;
856#endif
857
858#ifdef CONFIG_CDP_PORT_ID
859 *s++ = htons(CDP_PORT_ID_TLV);
860 memset(buf, 0, sizeof(buf));
861 sprintf(buf, CONFIG_CDP_PORT_ID, eth_get_dev_index());
862 len = strlen(buf);
863 if (len & 1) /* make it even */
864 len++;
865 *s++ = htons(len + 4);
866 memcpy((uchar *)s, buf, len);
867 s += len / 2;
868#endif
869
870#ifdef CONFIG_CDP_CAPABILITIES
871 *s++ = htons(CDP_CAPABILITIES_TLV);
872 *s++ = htons(8);
873 *(ulong *)s = htonl(CONFIG_CDP_CAPABILITIES);
874 s += 2;
875#endif
876
877#ifdef CONFIG_CDP_VERSION
878 *s++ = htons(CDP_VERSION_TLV);
879 memset(buf, 0, sizeof(buf));
880 strcpy(buf, CONFIG_CDP_VERSION);
881 len = strlen(buf);
882 if (len & 1) /* make it even */
883 len++;
884 *s++ = htons(len + 4);
885 memcpy((uchar *)s, buf, len);
886 s += len / 2;
887#endif
888
889#ifdef CONFIG_CDP_PLATFORM
890 *s++ = htons(CDP_PLATFORM_TLV);
891 memset(buf, 0, sizeof(buf));
892 strcpy(buf, CONFIG_CDP_PLATFORM);
893 len = strlen(buf);
894 if (len & 1) /* make it even */
895 len++;
896 *s++ = htons(len + 4);
897 memcpy((uchar *)s, buf, len);
898 s += len / 2;
899#endif
900
901#ifdef CONFIG_CDP_TRIGGER
902 *s++ = htons(CDP_TRIGGER_TLV);
903 *s++ = htons(8);
904 *(ulong *)s = htonl(CONFIG_CDP_TRIGGER);
905 s += 2;
906#endif
907
908#ifdef CONFIG_CDP_POWER_CONSUMPTION
909 *s++ = htons(CDP_POWER_CONSUMPTION_TLV);
910 *s++ = htons(6);
911 *s++ = htons(CONFIG_CDP_POWER_CONSUMPTION);
912#endif
913
914 /* length of ethernet packet */
915 len = (uchar *)s - ((uchar *)NetTxPacket + ETHER_HDR_SIZE);
916 et->et_protlen = htons(len);
917
918 len = ETHER_HDR_SIZE + sizeof(CDP_SNAP_hdr);
919 chksum = CDP_compute_csum((uchar *)NetTxPacket + len, (uchar *)s - (NetTxPacket + len));
920 if (chksum == 0)
921 chksum = 0xFFFF;
922 *cp = htons(chksum);
923
924 (void) eth_send(NetTxPacket, (uchar *)s - NetTxPacket);
925 return 0;
926}
927
928static void
929CDPTimeout (void)
930{
931 CDPSeq++;
932
933 if (CDPSeq < 3) {
934 NetSetTimeout (CDP_TIMEOUT, CDPTimeout);
935 CDPSendTrigger();
936 return;
937 }
938
939 /* if not OK try again */
940 if (!CDPOK)
941 NetStartAgain();
942 else
943 NetState = NETLOOP_SUCCESS;
944}
945
946static void
947CDPDummyHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len)
948{
949 /* nothing */
950}
951
952static void
953CDPHandler(const uchar * pkt, unsigned len)
954{
955 const uchar *t;
956 const ushort *ss;
957 ushort type, tlen;
958 uchar applid;
959 ushort vlan, nvlan;
960
961 /* minimum size? */
962 if (len < sizeof(CDP_SNAP_hdr) + 4)
963 goto pkt_short;
964
965 /* check for valid CDP SNAP header */
966 if (memcmp(pkt, CDP_SNAP_hdr, sizeof(CDP_SNAP_hdr)) != 0)
967 return;
968
969 pkt += sizeof(CDP_SNAP_hdr);
970 len -= sizeof(CDP_SNAP_hdr);
971
972 /* Version of CDP protocol must be >= 2 and TTL != 0 */
973 if (pkt[0] < 0x02 || pkt[1] == 0)
974 return;
975
976 /* if version is greater than 0x02 maybe we'll have a problem; output a warning */
977 if (pkt[0] != 0x02)
978 printf("** WARNING: CDP packet received with a protocol version %d > 2\n",
979 pkt[0] & 0xff);
980
981 if (CDP_compute_csum(pkt, len) != 0)
982 return;
983
984 pkt += 4;
985 len -= 4;
986
987 vlan = htons(-1);
988 nvlan = htons(-1);
989 while (len > 0) {
990 if (len < 4)
991 goto pkt_short;
992
993 ss = (const ushort *)pkt;
994 type = ntohs(ss[0]);
995 tlen = ntohs(ss[1]);
996 if (tlen > len) {
997 goto pkt_short;
998 }
999
1000 pkt += tlen;
1001 len -= tlen;
1002
1003 ss += 2; /* point ss to the data of the TLV */
1004 tlen -= 4;
1005
1006 switch (type) {
1007 case CDP_DEVICE_ID_TLV:
1008 break;
1009 case CDP_ADDRESS_TLV:
1010 break;
1011 case CDP_PORT_ID_TLV:
1012 break;
1013 case CDP_CAPABILITIES_TLV:
1014 break;
1015 case CDP_VERSION_TLV:
1016 break;
1017 case CDP_PLATFORM_TLV:
1018 break;
1019 case CDP_NATIVE_VLAN_TLV:
1020 nvlan = *ss;
1021 break;
1022 case CDP_APPLIANCE_VLAN_TLV:
1023 t = (const uchar *)ss;
1024 while (tlen > 0) {
1025 if (tlen < 3)
1026 goto pkt_short;
1027
1028 applid = t[0];
1029 ss = (const ushort *)(t + 1);
1030
1031#ifdef CONFIG_CDP_APPLIANCE_VLAN_TYPE
1032 if (applid == CONFIG_CDP_APPLIANCE_VLAN_TYPE)
1033 vlan = *ss;
1034#else
1035 vlan = ntohs(*ss); /* XXX will this work; dunno */
1036#endif
1037 t += 3; tlen -= 3;
1038 }
1039 break;
1040 case CDP_TRIGGER_TLV:
1041 break;
1042 case CDP_POWER_CONSUMPTION_TLV:
1043 break;
1044 case CDP_SYSNAME_TLV:
1045 break;
1046 case CDP_SYSOBJECT_TLV:
1047 break;
1048 case CDP_MANAGEMENT_ADDRESS_TLV:
1049 break;
1050 }
1051 }
1052
1053 CDPApplianceVLAN = vlan;
1054 CDPNativeVLAN = nvlan;
1055
1056 CDPOK = 1;
1057 return;
1058
1059 pkt_short:
1060 printf("** CDP packet is too short\n");
1061 return;
1062}
1063
1064static void CDPStart(void)
1065{
1066#if defined(CONFIG_NET_MULTI)
1067 printf ("Using %s device\n", eth_get_name());
wdenke6466f62003-06-05 19:27:42 +00001068#endif
wdenk145d2c12004-04-15 21:48:45 +00001069 CDPSeq = 0;
1070 CDPOK = 0;
1071
1072 CDPNativeVLAN = htons(-1);
1073 CDPApplianceVLAN = htons(-1);
1074
1075 NetSetTimeout (CDP_TIMEOUT, CDPTimeout);
1076 NetSetHandler (CDPDummyHandler);
1077
1078 CDPSendTrigger();
1079}
wdenk05939202004-04-18 17:39:38 +00001080#endif /* CFG_CMD_CDP */
wdenk145d2c12004-04-15 21:48:45 +00001081
wdenk2d966952002-10-31 22:12:35 +00001082
1083void
wdenk145d2c12004-04-15 21:48:45 +00001084NetReceive(volatile uchar * inpkt, int len)
wdenk2d966952002-10-31 22:12:35 +00001085{
1086 Ethernet_t *et;
1087 IP_t *ip;
1088 ARP_t *arp;
1089 IPaddr_t tmp;
1090 int x;
wdenk145d2c12004-04-15 21:48:45 +00001091 uchar *pkt;
1092#if (CONFIG_COMMANDS & CFG_CMD_CDP)
1093 int iscdp;
1094#endif
1095 ushort cti = 0, vlanid = VLAN_NONE, myvlanid, mynvlanid;
wdenk2d966952002-10-31 22:12:35 +00001096
wdenk145d2c12004-04-15 21:48:45 +00001097#ifdef ET_DEBUG
1098 printf("packet received\n");
1099#endif
1100
1101 NetRxPkt = inpkt;
wdenk2d966952002-10-31 22:12:35 +00001102 NetRxPktLen = len;
wdenk145d2c12004-04-15 21:48:45 +00001103 et = (Ethernet_t *)inpkt;
1104
1105 /* too small packet? */
1106 if (len < ETHER_HDR_SIZE)
1107 return;
1108
1109#if (CONFIG_COMMANDS & CFG_CMD_CDP)
1110 /* keep track if packet is CDP */
1111 iscdp = memcmp(et->et_dest, NetCDPAddr, 6) == 0;
1112#endif
1113
1114 myvlanid = ntohs(NetOurVLAN);
1115 if (myvlanid == (ushort)-1)
1116 myvlanid = VLAN_NONE;
1117 mynvlanid = ntohs(NetOurNativeVLAN);
1118 if (mynvlanid == (ushort)-1)
1119 mynvlanid = VLAN_NONE;
wdenk2d966952002-10-31 22:12:35 +00001120
1121 x = ntohs(et->et_protlen);
1122
wdenk145d2c12004-04-15 21:48:45 +00001123#ifdef ET_DEBUG
1124 printf("packet received\n");
1125#endif
1126
wdenk2d966952002-10-31 22:12:35 +00001127 if (x < 1514) {
1128 /*
1129 * Got a 802 packet. Check the other protocol field.
1130 */
1131 x = ntohs(et->et_prot);
wdenk145d2c12004-04-15 21:48:45 +00001132
1133 ip = (IP_t *)(inpkt + E802_HDR_SIZE);
wdenk2d966952002-10-31 22:12:35 +00001134 len -= E802_HDR_SIZE;
wdenk145d2c12004-04-15 21:48:45 +00001135
1136 } else if (x != PROT_VLAN) { /* normal packet */
1137 ip = (IP_t *)(inpkt + ETHER_HDR_SIZE);
wdenk2d966952002-10-31 22:12:35 +00001138 len -= ETHER_HDR_SIZE;
wdenk145d2c12004-04-15 21:48:45 +00001139
1140 } else { /* VLAN packet */
1141 VLAN_Ethernet_t *vet = (VLAN_Ethernet_t *)et;
1142
1143#ifdef ET_DEBUG
1144 printf("VLAN packet received\n");
1145#endif
1146 /* too small packet? */
1147 if (len < VLAN_ETHER_HDR_SIZE)
1148 return;
1149
1150 /* if no VLAN active */
1151 if ((ntohs(NetOurVLAN) & VLAN_IDMASK) == VLAN_NONE
1152#if (CONFIG_COMMANDS & CFG_CMD_CDP)
1153 && iscdp == 0
1154#endif
1155 )
1156 return;
1157
1158 cti = ntohs(vet->vet_tag);
1159 vlanid = cti & VLAN_IDMASK;
1160 x = ntohs(vet->vet_type);
1161
1162 ip = (IP_t *)(inpkt + VLAN_ETHER_HDR_SIZE);
1163 len -= VLAN_ETHER_HDR_SIZE;
wdenk2d966952002-10-31 22:12:35 +00001164 }
1165
1166#ifdef ET_DEBUG
1167 printf("Receive from protocol 0x%x\n", x);
1168#endif
1169
wdenk145d2c12004-04-15 21:48:45 +00001170#if (CONFIG_COMMANDS & CFG_CMD_CDP)
1171 if (iscdp) {
1172 CDPHandler((uchar *)ip, len);
1173 return;
1174 }
1175#endif
1176
1177 if ((myvlanid & VLAN_IDMASK) != VLAN_NONE) {
1178 if (vlanid == VLAN_NONE)
1179 vlanid = (mynvlanid & VLAN_IDMASK);
1180 /* not matched? */
1181 if (vlanid != (myvlanid & VLAN_IDMASK))
1182 return;
1183 }
1184
wdenk2d966952002-10-31 22:12:35 +00001185 switch (x) {
1186
1187 case PROT_ARP:
1188 /*
1189 * We have to deal with two types of ARP packets:
wdenk57b2d802003-06-27 21:31:46 +00001190 * - REQUEST packets will be answered by sending our
1191 * IP address - if we know it.
1192 * - REPLY packates are expected only after we asked
1193 * for the TFTP server's or the gateway's ethernet
1194 * address; so if we receive such a packet, we set
1195 * the server ethernet address
wdenk2d966952002-10-31 22:12:35 +00001196 */
1197#ifdef ET_DEBUG
wdenk42c05472004-03-23 22:14:11 +00001198 puts ("Got ARP\n");
wdenk2d966952002-10-31 22:12:35 +00001199#endif
1200 arp = (ARP_t *)ip;
1201 if (len < ARP_HDR_SIZE) {
1202 printf("bad length %d < %d\n", len, ARP_HDR_SIZE);
1203 return;
1204 }
1205 if (ntohs(arp->ar_hrd) != ARP_ETHER) {
1206 return;
1207 }
1208 if (ntohs(arp->ar_pro) != PROT_IP) {
1209 return;
1210 }
1211 if (arp->ar_hln != 6) {
1212 return;
1213 }
1214 if (arp->ar_pln != 4) {
1215 return;
1216 }
1217
1218 if (NetOurIP == 0) {
1219 return;
1220 }
1221
1222 if (NetReadIP(&arp->ar_data[16]) != NetOurIP) {
1223 return;
1224 }
1225
1226 switch (ntohs(arp->ar_op)) {
1227 case ARPOP_REQUEST: /* reply with our IP address */
1228#ifdef ET_DEBUG
wdenk42c05472004-03-23 22:14:11 +00001229 puts ("Got ARP REQUEST, return our IP\n");
wdenk2d966952002-10-31 22:12:35 +00001230#endif
wdenk145d2c12004-04-15 21:48:45 +00001231 pkt = (uchar *)et;
1232 pkt += NetSetEther(pkt, et->et_src, PROT_ARP);
wdenk2d966952002-10-31 22:12:35 +00001233 arp->ar_op = htons(ARPOP_REPLY);
1234 memcpy (&arp->ar_data[10], &arp->ar_data[0], 6);
1235 NetCopyIP(&arp->ar_data[16], &arp->ar_data[6]);
1236 memcpy (&arp->ar_data[ 0], NetOurEther, 6);
1237 NetCopyIP(&arp->ar_data[ 6], &NetOurIP);
wdenk145d2c12004-04-15 21:48:45 +00001238 (void) eth_send((uchar *)et, (pkt - (uchar *)et) + ARP_HDR_SIZE);
wdenk2d966952002-10-31 22:12:35 +00001239 return;
wdenke6466f62003-06-05 19:27:42 +00001240
1241 case ARPOP_REPLY: /* arp reply */
1242 /* are we waiting for a reply */
1243 if (!NetArpWaitPacketIP || !NetArpWaitPacketMAC)
1244 break;
1245#ifdef ET_DEBUG
1246 printf("Got ARP REPLY, set server/gtwy eth addr (%02x:%02x:%02x:%02x:%02x:%02x)\n",
1247 arp->ar_data[0], arp->ar_data[1],
1248 arp->ar_data[2], arp->ar_data[3],
1249 arp->ar_data[4], arp->ar_data[5]);
1250#endif
1251
1252 tmp = NetReadIP(&arp->ar_data[6]);
1253
1254 /* matched waiting packet's address */
1255 if (tmp == NetArpWaitReplyIP) {
wdenk2d966952002-10-31 22:12:35 +00001256#ifdef ET_DEBUG
wdenk42c05472004-03-23 22:14:11 +00001257 puts ("Got it\n");
wdenk2d966952002-10-31 22:12:35 +00001258#endif
wdenke6466f62003-06-05 19:27:42 +00001259 /* save address for later use */
1260 memcpy(NetArpWaitPacketMAC, &arp->ar_data[0], 6);
1261
1262 /* modify header, and transmit it */
1263 memcpy(((Ethernet_t *)NetArpWaitTxPacket)->et_dest, NetArpWaitPacketMAC, 6);
1264 (void) eth_send(NetArpWaitTxPacket, NetArpWaitTxPacketSize);
1265
1266 /* no arp request pending now */
1267 NetArpWaitPacketIP = 0;
1268 NetArpWaitTxPacketSize = 0;
1269 NetArpWaitPacketMAC = NULL;
1270
1271 }
wdenk2d966952002-10-31 22:12:35 +00001272 return;
1273 default:
1274#ifdef ET_DEBUG
1275 printf("Unexpected ARP opcode 0x%x\n", ntohs(arp->ar_op));
1276#endif
1277 return;
1278 }
1279
1280 case PROT_RARP:
1281#ifdef ET_DEBUG
wdenk42c05472004-03-23 22:14:11 +00001282 puts ("Got RARP\n");
wdenk2d966952002-10-31 22:12:35 +00001283#endif
1284 arp = (ARP_t *)ip;
1285 if (len < ARP_HDR_SIZE) {
1286 printf("bad length %d < %d\n", len, ARP_HDR_SIZE);
1287 return;
1288 }
1289
1290 if ((ntohs(arp->ar_op) != RARPOP_REPLY) ||
1291 (ntohs(arp->ar_hrd) != ARP_ETHER) ||
1292 (ntohs(arp->ar_pro) != PROT_IP) ||
1293 (arp->ar_hln != 6) || (arp->ar_pln != 4)) {
1294
wdenk42c05472004-03-23 22:14:11 +00001295 puts ("invalid RARP header\n");
wdenk2d966952002-10-31 22:12:35 +00001296 } else {
1297 NetCopyIP(&NetOurIP, &arp->ar_data[16]);
wdenk4989f872004-03-14 15:06:13 +00001298 if (NetServerIP == 0)
1299 NetCopyIP(&NetServerIP, &arp->ar_data[ 6]);
wdenk2d966952002-10-31 22:12:35 +00001300 memcpy (NetServerEther, &arp->ar_data[ 0], 6);
1301
1302 (*packetHandler)(0,0,0,0);
1303 }
1304 break;
1305
1306 case PROT_IP:
1307#ifdef ET_DEBUG
wdenk42c05472004-03-23 22:14:11 +00001308 puts ("Got IP\n");
wdenk2d966952002-10-31 22:12:35 +00001309#endif
1310 if (len < IP_HDR_SIZE) {
1311 debug ("len bad %d < %d\n", len, IP_HDR_SIZE);
1312 return;
1313 }
1314 if (len < ntohs(ip->ip_len)) {
1315 printf("len bad %d < %d\n", len, ntohs(ip->ip_len));
1316 return;
1317 }
1318 len = ntohs(ip->ip_len);
1319#ifdef ET_DEBUG
1320 printf("len=%d, v=%02x\n", len, ip->ip_hl_v & 0xff);
1321#endif
1322 if ((ip->ip_hl_v & 0xf0) != 0x40) {
1323 return;
1324 }
1325 if (ip->ip_off & htons(0x1fff)) { /* Can't deal w/ fragments */
1326 return;
1327 }
1328 if (!NetCksumOk((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2)) {
wdenk42c05472004-03-23 22:14:11 +00001329 puts ("checksum bad\n");
wdenk2d966952002-10-31 22:12:35 +00001330 return;
1331 }
1332 tmp = NetReadIP(&ip->ip_dst);
1333 if (NetOurIP && tmp != NetOurIP && tmp != 0xFFFFFFFF) {
1334 return;
1335 }
1336 /*
1337 * watch for ICMP host redirects
1338 *
wdenk57b2d802003-06-27 21:31:46 +00001339 * There is no real handler code (yet). We just watch
1340 * for ICMP host redirect messages. In case anybody
1341 * sees these messages: please contact me
1342 * (wd@denx.de), or - even better - send me the
1343 * necessary fixes :-)
wdenk2d966952002-10-31 22:12:35 +00001344 *
wdenk57b2d802003-06-27 21:31:46 +00001345 * Note: in all cases where I have seen this so far
1346 * it was a problem with the router configuration,
1347 * for instance when a router was configured in the
1348 * BOOTP reply, but the TFTP server was on the same
1349 * subnet. So this is probably a warning that your
1350 * configuration might be wrong. But I'm not really
1351 * sure if there aren't any other situations.
wdenk2d966952002-10-31 22:12:35 +00001352 */
1353 if (ip->ip_p == IPPROTO_ICMP) {
1354 ICMP_t *icmph = (ICMP_t *)&(ip->udp_src);
1355
wdenke6466f62003-06-05 19:27:42 +00001356 switch (icmph->type) {
1357 case ICMP_REDIRECT:
wdenk2d966952002-10-31 22:12:35 +00001358 if (icmph->code != ICMP_REDIR_HOST)
1359 return;
1360 puts (" ICMP Host Redirect to ");
1361 print_IPaddr(icmph->un.gateway);
1362 putc(' ');
wdenke6466f62003-06-05 19:27:42 +00001363 break;
1364#if (CONFIG_COMMANDS & CFG_CMD_PING)
1365 case ICMP_ECHO_REPLY:
1366 /*
1367 * IP header OK. Pass the packet to the current handler.
1368 */
1369 /* XXX point to ip packet */
1370 (*packetHandler)((uchar *)ip, 0, 0, 0);
1371 break;
1372#endif
1373 default:
1374 return;
1375 }
wdenk2d966952002-10-31 22:12:35 +00001376 } else if (ip->ip_p != IPPROTO_UDP) { /* Only UDP packets */
1377 return;
1378 }
1379
1380 /*
1381 * IP header OK. Pass the packet to the current handler.
1382 */
1383 (*packetHandler)((uchar *)ip +IP_HDR_SIZE,
1384 ntohs(ip->udp_dst),
1385 ntohs(ip->udp_src),
1386 ntohs(ip->udp_len) - 8);
wdenk2d966952002-10-31 22:12:35 +00001387 break;
1388 }
1389}
1390
1391
1392/**********************************************************************/
1393
1394static int net_check_prereq (proto_t protocol)
1395{
1396 switch (protocol) {
wdenk05939202004-04-18 17:39:38 +00001397 /* Fall through */
wdenke6466f62003-06-05 19:27:42 +00001398#if (CONFIG_COMMANDS & CFG_CMD_PING)
1399 case PING:
wdenk05939202004-04-18 17:39:38 +00001400 if (NetPingIP == 0) {
1401 puts ("*** ERROR: ping address not given\n");
1402 return (1);
1403 }
1404 goto common;
wdenke6466f62003-06-05 19:27:42 +00001405#endif
wdenkbe9c1cb2004-02-24 02:00:03 +00001406#if (CONFIG_COMMANDS & CFG_CMD_NFS)
1407 case NFS:
1408#endif
wdenk2d966952002-10-31 22:12:35 +00001409 case TFTP:
wdenk05939202004-04-18 17:39:38 +00001410 if (NetServerIP == 0) {
1411 puts ("*** ERROR: `serverip' not set\n");
1412 return (1);
1413 }
wdenke6466f62003-06-05 19:27:42 +00001414#if (CONFIG_COMMANDS & CFG_CMD_PING)
wdenk05939202004-04-18 17:39:38 +00001415 common:
wdenke6466f62003-06-05 19:27:42 +00001416#endif
1417
wdenk05939202004-04-18 17:39:38 +00001418 if (NetOurIP == 0) {
1419 puts ("*** ERROR: `ipaddr' not set\n");
1420 return (1);
1421 }
1422 /* Fall through */
wdenk2d966952002-10-31 22:12:35 +00001423
1424 case DHCP:
1425 case RARP:
1426 case BOOTP:
wdenk145d2c12004-04-15 21:48:45 +00001427 case CDP:
wdenk05939202004-04-18 17:39:38 +00001428 if (memcmp (NetOurEther, "\0\0\0\0\0\0", 6) == 0) {
wdenk2d966952002-10-31 22:12:35 +00001429#ifdef CONFIG_NET_MULTI
wdenk05939202004-04-18 17:39:38 +00001430 extern int eth_get_dev_index (void);
1431 int num = eth_get_dev_index ();
wdenk2d966952002-10-31 22:12:35 +00001432
wdenk05939202004-04-18 17:39:38 +00001433 switch (num) {
1434 case -1:
wdenk2d966952002-10-31 22:12:35 +00001435 puts ("*** ERROR: No ethernet found.\n");
1436 return (1);
wdenk05939202004-04-18 17:39:38 +00001437 case 0:
wdenk2d966952002-10-31 22:12:35 +00001438 puts ("*** ERROR: `ethaddr' not set\n");
1439 break;
wdenk05939202004-04-18 17:39:38 +00001440 default:
wdenk57b2d802003-06-27 21:31:46 +00001441 printf ("*** ERROR: `eth%daddr' not set\n",
wdenk2d966952002-10-31 22:12:35 +00001442 num);
1443 break;
wdenk05939202004-04-18 17:39:38 +00001444 }
wdenk2d966952002-10-31 22:12:35 +00001445
wdenk05939202004-04-18 17:39:38 +00001446 NetStartAgain ();
1447 return (2);
wdenk2d966952002-10-31 22:12:35 +00001448#else
wdenk05939202004-04-18 17:39:38 +00001449 puts ("*** ERROR: `ethaddr' not set\n");
1450 return (1);
wdenk2d966952002-10-31 22:12:35 +00001451#endif
wdenk05939202004-04-18 17:39:38 +00001452 }
1453 /* Fall through */
1454 default:
1455 return (0);
wdenk2d966952002-10-31 22:12:35 +00001456 }
wdenk05939202004-04-18 17:39:38 +00001457 return (0); /* OK */
wdenk2d966952002-10-31 22:12:35 +00001458}
1459/**********************************************************************/
1460
1461int
1462NetCksumOk(uchar * ptr, int len)
1463{
1464 return !((NetCksum(ptr, len) + 1) & 0xfffe);
1465}
1466
1467
1468unsigned
1469NetCksum(uchar * ptr, int len)
1470{
1471 ulong xsum;
1472
1473 xsum = 0;
1474 while (len-- > 0)
1475 xsum += *((ushort *)ptr)++;
1476 xsum = (xsum & 0xffff) + (xsum >> 16);
1477 xsum = (xsum & 0xffff) + (xsum >> 16);
1478 return (xsum & 0xffff);
1479}
1480
wdenk145d2c12004-04-15 21:48:45 +00001481int
1482NetEthHdrSize(void)
1483{
1484 ushort myvlanid;
1485
1486 myvlanid = ntohs(NetOurVLAN);
1487 if (myvlanid == (ushort)-1)
1488 myvlanid = VLAN_NONE;
wdenk2d966952002-10-31 22:12:35 +00001489
wdenk145d2c12004-04-15 21:48:45 +00001490 return ((myvlanid & VLAN_IDMASK) == VLAN_NONE) ? ETHER_HDR_SIZE : VLAN_ETHER_HDR_SIZE;
1491}
1492
1493int
wdenk2d966952002-10-31 22:12:35 +00001494NetSetEther(volatile uchar * xet, uchar * addr, uint prot)
1495{
1496 Ethernet_t *et = (Ethernet_t *)xet;
wdenk145d2c12004-04-15 21:48:45 +00001497 ushort myvlanid;
1498
1499 myvlanid = ntohs(NetOurVLAN);
1500 if (myvlanid == (ushort)-1)
1501 myvlanid = VLAN_NONE;
wdenk2d966952002-10-31 22:12:35 +00001502
1503 memcpy (et->et_dest, addr, 6);
1504 memcpy (et->et_src, NetOurEther, 6);
wdenk145d2c12004-04-15 21:48:45 +00001505 if ((myvlanid & VLAN_IDMASK) == VLAN_NONE) {
wdenk2d966952002-10-31 22:12:35 +00001506 et->et_protlen = htons(prot);
wdenk145d2c12004-04-15 21:48:45 +00001507 return ETHER_HDR_SIZE;
1508 } else {
1509 VLAN_Ethernet_t *vet = (VLAN_Ethernet_t *)xet;
wdenk2d966952002-10-31 22:12:35 +00001510
wdenk145d2c12004-04-15 21:48:45 +00001511 vet->vet_vlan_type = htons(PROT_VLAN);
1512 vet->vet_tag = htons((0 << 5) | (myvlanid & VLAN_IDMASK));
1513 vet->vet_type = htons(prot);
1514 return VLAN_ETHER_HDR_SIZE;
1515 }
1516}
wdenk2d966952002-10-31 22:12:35 +00001517
1518void
1519NetSetIP(volatile uchar * xip, IPaddr_t dest, int dport, int sport, int len)
1520{
1521 volatile IP_t *ip = (IP_t *)xip;
1522
1523 /*
1524 * If the data is an odd number of bytes, zero the
1525 * byte after the last byte so that the checksum
1526 * will work.
1527 */
1528 if (len & 1)
1529 xip[IP_HDR_SIZE + len] = 0;
1530
1531 /*
1532 * Construct an IP and UDP header.
wdenk05939202004-04-18 17:39:38 +00001533 * (need to set no fragment bit - XXX)
wdenk2d966952002-10-31 22:12:35 +00001534 */
1535 ip->ip_hl_v = 0x45; /* IP_HDR_SIZE / 4 (not including UDP) */
1536 ip->ip_tos = 0;
1537 ip->ip_len = htons(IP_HDR_SIZE + len);
1538 ip->ip_id = htons(NetIPID++);
1539 ip->ip_off = htons(0x4000); /* No fragmentation */
1540 ip->ip_ttl = 255;
1541 ip->ip_p = 17; /* UDP */
1542 ip->ip_sum = 0;
1543 NetCopyIP((void*)&ip->ip_src, &NetOurIP); /* already in network byte order */
1544 NetCopyIP((void*)&ip->ip_dst, &dest); /* - "" - */
1545 ip->udp_src = htons(sport);
1546 ip->udp_dst = htons(dport);
1547 ip->udp_len = htons(8 + len);
1548 ip->udp_xsum = 0;
1549 ip->ip_sum = ~NetCksum((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2);
1550}
1551
1552void copy_filename (uchar *dst, uchar *src, int size)
1553{
1554 if (*src && (*src == '"')) {
1555 ++src;
1556 --size;
1557 }
1558
1559 while ((--size > 0) && *src && (*src != '"')) {
1560 *dst++ = *src++;
1561 }
1562 *dst = '\0';
1563}
1564
1565#endif /* CFG_CMD_NET */
1566
1567void ip_to_string (IPaddr_t x, char *s)
1568{
wdenk145d2c12004-04-15 21:48:45 +00001569 x = ntohl (x);
1570 sprintf (s, "%d.%d.%d.%d",
1571 (int) ((x >> 24) & 0xff),
1572 (int) ((x >> 16) & 0xff),
1573 (int) ((x >> 8) & 0xff), (int) ((x >> 0) & 0xff)
wdenk05939202004-04-18 17:39:38 +00001574 );
wdenk2d966952002-10-31 22:12:35 +00001575}
1576
wdenke6466f62003-06-05 19:27:42 +00001577IPaddr_t string_to_ip(char *s)
wdenk2d966952002-10-31 22:12:35 +00001578{
1579 IPaddr_t addr;
wdenke6466f62003-06-05 19:27:42 +00001580 char *e;
wdenk2d966952002-10-31 22:12:35 +00001581 int i;
1582
wdenke6466f62003-06-05 19:27:42 +00001583 if (s == NULL)
1584 return(0);
wdenk2d966952002-10-31 22:12:35 +00001585
1586 for (addr=0, i=0; i<4; ++i) {
1587 ulong val = s ? simple_strtoul(s, &e, 10) : 0;
1588 addr <<= 8;
1589 addr |= (val & 0xFF);
1590 if (s) {
1591 s = (*e) ? e+1 : e;
1592 }
1593 }
1594
1595 return (htonl(addr));
1596}
wdenke6466f62003-06-05 19:27:42 +00001597
wdenk145d2c12004-04-15 21:48:45 +00001598void VLAN_to_string(ushort x, char *s)
1599{
1600 x = ntohs(x);
1601
1602 if (x == (ushort)-1)
1603 x = VLAN_NONE;
1604
1605 if (x == VLAN_NONE)
1606 strcpy(s, "none");
1607 else
1608 sprintf(s, "%d", x & VLAN_IDMASK);
1609}
1610
1611ushort string_to_VLAN(char *s)
1612{
1613 ushort id;
1614
1615 if (s == NULL)
wdenk656140b2004-04-25 13:18:40 +00001616 return htons(VLAN_NONE);
wdenk145d2c12004-04-15 21:48:45 +00001617
1618 if (*s < '0' || *s > '9')
1619 id = VLAN_NONE;
1620 else
1621 id = (ushort)simple_strtoul(s, NULL, 10);
1622
wdenk656140b2004-04-25 13:18:40 +00001623 return htons(id);
wdenk145d2c12004-04-15 21:48:45 +00001624}
1625
wdenke6466f62003-06-05 19:27:42 +00001626void print_IPaddr (IPaddr_t x)
1627{
wdenk145d2c12004-04-15 21:48:45 +00001628 char tmp[16];
wdenke6466f62003-06-05 19:27:42 +00001629
wdenk145d2c12004-04-15 21:48:45 +00001630 ip_to_string (x, tmp);
wdenke6466f62003-06-05 19:27:42 +00001631
wdenk145d2c12004-04-15 21:48:45 +00001632 puts (tmp);
wdenke6466f62003-06-05 19:27:42 +00001633}
1634
1635IPaddr_t getenv_IPaddr (char *var)
1636{
1637 return (string_to_ip(getenv(var)));
1638}
wdenk145d2c12004-04-15 21:48:45 +00001639
1640ushort getenv_VLAN(char *var)
1641{
1642 return (string_to_VLAN(getenv(var)));
1643}