blob: b8648bd95aace2e8069bd5bb4335367893a93c24 [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 *
Wolfgang Denkb2f50802005-08-12 23:43:12 +020043 * Prerequisites: - own ethernet address
44 * We want: - IP, Netmask, ServerIP, Gateway IP
45 * - bootfilename, lease time
46 * Next step: - TFTP
wdenk2d966952002-10-31 22:12:35 +000047 *
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
wdenkcbd8a352004-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
wdenkea287de2005-04-01 00:25:43 +000067 *
68 * SNTP:
69 *
Wolfgang Denkb2f50802005-08-12 23:43:12 +020070 * Prerequisites: - own ethernet address
wdenkea287de2005-04-01 00:25:43 +000071 * - own IP address
72 * We want: - network time
73 * Next step: none
wdenk2d966952002-10-31 22:12:35 +000074 */
75
76
77#include <common.h>
78#include <watchdog.h>
79#include <command.h>
80#include <net.h>
81#include "bootp.h"
82#include "tftp.h"
83#include "rarp.h"
wdenkcbd8a352004-02-24 02:00:03 +000084#include "nfs.h"
wdenkfc3e2162003-10-08 22:33:00 +000085#ifdef CONFIG_STATUS_LED
86#include <status_led.h>
87#include <miiphy.h>
88#endif
Jon Loeliger643d1ab2007-07-09 17:45:14 -050089#if defined(CONFIG_CMD_SNTP)
wdenkea287de2005-04-01 00:25:43 +000090#include "sntp.h"
91#endif
Peter Tyser561858e2008-11-03 09:30:59 -060092#if defined(CONFIG_CDP_VERSION)
93#include <timestamp.h>
94#endif
wdenk2d966952002-10-31 22:12:35 +000095
Jon Loeliger643d1ab2007-07-09 17:45:14 -050096#if defined(CONFIG_CMD_NET)
wdenk2d966952002-10-31 22:12:35 +000097
Wolfgang Denkd87080b2006-03-31 18:32:53 +020098DECLARE_GLOBAL_DATA_PTR;
99
Guennadi Liakhovetski40cb90e2008-04-03 17:04:19 +0200100#ifndef CONFIG_ARP_TIMEOUT
Bartlomiej Sieka49f3bdb2008-10-01 15:26:28 +0200101# define ARP_TIMEOUT 5000UL /* Milliseconds before trying ARP again */
wdenk73a8b272003-06-05 19:27:42 +0000102#else
Bartlomiej Sieka49f3bdb2008-10-01 15:26:28 +0200103# define ARP_TIMEOUT CONFIG_ARP_TIMEOUT
Guennadi Liakhovetski40cb90e2008-04-03 17:04:19 +0200104#endif
105
106
107#ifndef CONFIG_NET_RETRY_COUNT
108# define ARP_TIMEOUT_COUNT 5 /* # of timeouts before giving up */
109#else
110# define ARP_TIMEOUT_COUNT CONFIG_NET_RETRY_COUNT
wdenk73a8b272003-06-05 19:27:42 +0000111#endif
112
wdenk2d966952002-10-31 22:12:35 +0000113#if 0
114#define ET_DEBUG
115#endif
116
117/** BOOTP EXTENTIONS **/
118
119IPaddr_t NetOurSubnetMask=0; /* Our subnet mask (0=unknown) */
120IPaddr_t NetOurGatewayIP=0; /* Our gateways IP address */
121IPaddr_t NetOurDNSIP=0; /* Our DNS IP address */
Jon Loeliger1fe80d72007-07-09 22:08:34 -0500122#if defined(CONFIG_BOOTP_DNS2)
stroesefe389a82003-08-28 14:17:32 +0000123IPaddr_t NetOurDNS2IP=0; /* Our 2nd DNS IP address */
124#endif
wdenk2d966952002-10-31 22:12:35 +0000125char NetOurNISDomain[32]={0,}; /* Our NIS domain */
126char NetOurHostName[32]={0,}; /* Our hostname */
127char NetOurRootPath[64]={0,}; /* Our bootpath */
128ushort NetBootFileSize=0; /* Our bootfile size in blocks */
129
David Updegraff53a5c422007-06-11 10:41:07 -0500130#ifdef CONFIG_MCAST_TFTP /* Multicast TFTP */
131IPaddr_t Mcast_addr;
132#endif
133
wdenk2d966952002-10-31 22:12:35 +0000134/** END OF BOOTP EXTENTIONS **/
135
136ulong NetBootFileXferSize; /* The actual transferred size of the bootfile (in bytes) */
137uchar NetOurEther[6]; /* Our ethernet address */
138uchar NetServerEther[6] = /* Boot server enet address */
wdenk73a8b272003-06-05 19:27:42 +0000139 { 0, 0, 0, 0, 0, 0 };
wdenk2d966952002-10-31 22:12:35 +0000140IPaddr_t NetOurIP; /* Our IP addr (0 = unknown) */
Guennadi Liakhovetski40cb90e2008-04-03 17:04:19 +0200141IPaddr_t NetServerIP; /* Server IP addr (0 = unknown) */
wdenk2d966952002-10-31 22:12:35 +0000142volatile uchar *NetRxPkt; /* Current receive packet */
143int NetRxPktLen; /* Current rx packet length */
144unsigned NetIPID; /* IP packet ID */
145uchar NetBcastAddr[6] = /* Ethernet bcast address */
146 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
wdenk73a8b272003-06-05 19:27:42 +0000147uchar NetEtherNullAddr[6] =
148 { 0, 0, 0, 0, 0, 0 };
Rafal Jaworowskif85b6072007-12-27 18:19:02 +0100149#ifdef CONFIG_API
150void (*push_packet)(volatile void *, int len) = 0;
151#endif
Jon Loeliger643d1ab2007-07-09 17:45:14 -0500152#if defined(CONFIG_CMD_CDP)
wdenk6e592382004-04-18 17:39:38 +0000153uchar NetCDPAddr[6] = /* Ethernet bcast address */
wdenka3d991b2004-04-15 21:48:45 +0000154 { 0x01, 0x00, 0x0c, 0xcc, 0xcc, 0xcc };
155#endif
wdenk2d966952002-10-31 22:12:35 +0000156int NetState; /* Network loop state */
157#ifdef CONFIG_NET_MULTI
158int NetRestartWrap = 0; /* Tried all network devices */
159static int NetRestarted = 0; /* Network loop restarted */
160static int NetDevExists = 0; /* At least one device configured */
161#endif
162
wdenk6e592382004-04-18 17:39:38 +0000163/* XXX in both little & big endian machines 0xFFFF == ntohs(-1) */
164ushort NetOurVLAN = 0xFFFF; /* default is without VLAN */
165ushort NetOurNativeVLAN = 0xFFFF; /* ditto */
wdenka3d991b2004-04-15 21:48:45 +0000166
wdenk2d966952002-10-31 22:12:35 +0000167char BootFile[128]; /* Boot File name */
168
Jon Loeliger643d1ab2007-07-09 17:45:14 -0500169#if defined(CONFIG_CMD_PING)
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200170IPaddr_t NetPingIP; /* the ip address to ping */
wdenk73a8b272003-06-05 19:27:42 +0000171
172static void PingStart(void);
173#endif
174
Jon Loeliger643d1ab2007-07-09 17:45:14 -0500175#if defined(CONFIG_CMD_CDP)
wdenka3d991b2004-04-15 21:48:45 +0000176static void CDPStart(void);
177#endif
178
Jon Loeliger643d1ab2007-07-09 17:45:14 -0500179#if defined(CONFIG_CMD_SNTP)
wdenkea287de2005-04-01 00:25:43 +0000180IPaddr_t NetNtpServerIP; /* NTP server IP address */
181int NetTimeOffset=0; /* offset time from UTC */
182#endif
183
wdenk68ceb292004-08-02 21:11:11 +0000184#ifdef CONFIG_NETCONSOLE
185void NcStart(void);
186int nc_input_packet(uchar *pkt, unsigned dest, unsigned src, unsigned len);
187#endif
188
wdenk2d966952002-10-31 22:12:35 +0000189volatile uchar PktBuf[(PKTBUFSRX+1) * PKTSIZE_ALIGN + PKTALIGN];
190
191volatile uchar *NetRxPackets[PKTBUFSRX]; /* Receive packets */
192
193static rxhand_f *packetHandler; /* Current RX packet handler */
194static thand_f *timeHandler; /* Current timeout handler */
wdenke0ac62d2003-08-17 18:55:18 +0000195static ulong timeStart; /* Time base value */
196static ulong timeDelta; /* Current timeout value */
wdenk2d966952002-10-31 22:12:35 +0000197volatile uchar *NetTxPacket = 0; /* THE transmit packet */
198
199static int net_check_prereq (proto_t protocol);
200
201/**********************************************************************/
wdenk73a8b272003-06-05 19:27:42 +0000202
203IPaddr_t NetArpWaitPacketIP;
204IPaddr_t NetArpWaitReplyIP;
205uchar *NetArpWaitPacketMAC; /* MAC address of waiting packet's destination */
Wolfgang Denkb2f50802005-08-12 23:43:12 +0200206uchar *NetArpWaitTxPacket; /* THE transmit packet */
wdenk73a8b272003-06-05 19:27:42 +0000207int NetArpWaitTxPacketSize;
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200208uchar NetArpWaitPacketBuf[PKTSIZE_ALIGN + PKTALIGN];
wdenk73a8b272003-06-05 19:27:42 +0000209ulong NetArpWaitTimerStart;
210int NetArpWaitTry;
211
Heiko Schocher2f70c492009-02-10 09:38:52 +0100212int env_changed_id = 0;
213
wdenk6e592382004-04-18 17:39:38 +0000214void ArpRequest (void)
wdenk73a8b272003-06-05 19:27:42 +0000215{
216 int i;
217 volatile uchar *pkt;
wdenk6e592382004-04-18 17:39:38 +0000218 ARP_t *arp;
wdenk73a8b272003-06-05 19:27:42 +0000219
220#ifdef ET_DEBUG
wdenk6e592382004-04-18 17:39:38 +0000221 printf ("ARP broadcast %d\n", NetArpWaitTry);
wdenk73a8b272003-06-05 19:27:42 +0000222#endif
223 pkt = NetTxPacket;
224
wdenk6e592382004-04-18 17:39:38 +0000225 pkt += NetSetEther (pkt, NetBcastAddr, PROT_ARP);
wdenk73a8b272003-06-05 19:27:42 +0000226
wdenk6e592382004-04-18 17:39:38 +0000227 arp = (ARP_t *) pkt;
wdenk73a8b272003-06-05 19:27:42 +0000228
wdenk6e592382004-04-18 17:39:38 +0000229 arp->ar_hrd = htons (ARP_ETHER);
230 arp->ar_pro = htons (PROT_IP);
wdenk73a8b272003-06-05 19:27:42 +0000231 arp->ar_hln = 6;
232 arp->ar_pln = 4;
wdenk6e592382004-04-18 17:39:38 +0000233 arp->ar_op = htons (ARPOP_REQUEST);
wdenk73a8b272003-06-05 19:27:42 +0000234
Wolfgang Denkb2f50802005-08-12 23:43:12 +0200235 memcpy (&arp->ar_data[0], NetOurEther, 6); /* source ET addr */
236 NetWriteIP ((uchar *) & arp->ar_data[6], NetOurIP); /* source IP addr */
wdenk6e592382004-04-18 17:39:38 +0000237 for (i = 10; i < 16; ++i) {
238 arp->ar_data[i] = 0; /* dest ET addr = 0 */
wdenk73a8b272003-06-05 19:27:42 +0000239 }
240
wdenk6e592382004-04-18 17:39:38 +0000241 if ((NetArpWaitPacketIP & NetOurSubnetMask) !=
242 (NetOurIP & NetOurSubnetMask)) {
243 if (NetOurGatewayIP == 0) {
244 puts ("## Warning: gatewayip needed but not set\n");
Wolfgang Denkd509b812006-03-12 01:13:30 +0100245 NetArpWaitReplyIP = NetArpWaitPacketIP;
246 } else {
247 NetArpWaitReplyIP = NetOurGatewayIP;
wdenk6e592382004-04-18 17:39:38 +0000248 }
wdenk6e592382004-04-18 17:39:38 +0000249 } else {
250 NetArpWaitReplyIP = NetArpWaitPacketIP;
251 }
wdenk73a8b272003-06-05 19:27:42 +0000252
wdenk6e592382004-04-18 17:39:38 +0000253 NetWriteIP ((uchar *) & arp->ar_data[16], NetArpWaitReplyIP);
254 (void) eth_send (NetTxPacket, (pkt - NetTxPacket) + ARP_HDR_SIZE);
wdenk73a8b272003-06-05 19:27:42 +0000255}
256
257void ArpTimeoutCheck(void)
258{
259 ulong t;
260
261 if (!NetArpWaitPacketIP)
262 return;
263
264 t = get_timer(0);
265
266 /* check for arp timeout */
Bartlomiej Sieka49f3bdb2008-10-01 15:26:28 +0200267 if ((t - NetArpWaitTimerStart) > ARP_TIMEOUT) {
wdenk73a8b272003-06-05 19:27:42 +0000268 NetArpWaitTry++;
269
270 if (NetArpWaitTry >= ARP_TIMEOUT_COUNT) {
271 puts ("\nARP Retry count exceeded; starting again\n");
272 NetArpWaitTry = 0;
273 NetStartAgain();
274 } else {
275 NetArpWaitTimerStart = t;
276 ArpRequest();
277 }
278 }
279}
280
Heiko Schocher2f70c492009-02-10 09:38:52 +0100281int
282NetInitLoop(proto_t protocol)
283{
284 bd_t *bd = gd->bd;
285 int env_id = get_env_id ();
286
287 /* update only when the environment has changed */
Michael Zaidman3c172c42009-04-04 01:43:00 +0300288 if (env_changed_id != env_id) {
Heiko Schocher2f70c492009-02-10 09:38:52 +0100289 NetCopyIP(&NetOurIP, &bd->bi_ip_addr);
290 NetOurGatewayIP = getenv_IPaddr ("gatewayip");
291 NetOurSubnetMask= getenv_IPaddr ("netmask");
Heiko Schocher2f70c492009-02-10 09:38:52 +0100292 NetServerIP = getenv_IPaddr ("serverip");
Heiko Schocher2f70c492009-02-10 09:38:52 +0100293 NetOurNativeVLAN = getenv_VLAN("nvlan");
Michael Zaidman3c172c42009-04-04 01:43:00 +0300294 NetOurVLAN = getenv_VLAN("vlan");
295 env_changed_id = env_id;
Heiko Schocher2f70c492009-02-10 09:38:52 +0100296 }
Michael Zaidman3c172c42009-04-04 01:43:00 +0300297
Heiko Schocher2f70c492009-02-10 09:38:52 +0100298 return 0;
299}
300
wdenk73a8b272003-06-05 19:27:42 +0000301/**********************************************************************/
wdenk2d966952002-10-31 22:12:35 +0000302/*
303 * Main network processing loop.
304 */
305
306int
307NetLoop(proto_t protocol)
308{
wdenk2d966952002-10-31 22:12:35 +0000309 bd_t *bd = gd->bd;
310
311#ifdef CONFIG_NET_MULTI
312 NetRestarted = 0;
313 NetDevExists = 0;
314#endif
315
wdenk73a8b272003-06-05 19:27:42 +0000316 /* XXX problem with bss workaround */
317 NetArpWaitPacketMAC = NULL;
318 NetArpWaitTxPacket = NULL;
319 NetArpWaitPacketIP = 0;
320 NetArpWaitReplyIP = 0;
321 NetArpWaitTxPacket = NULL;
322 NetTxPacket = NULL;
323
wdenk2d966952002-10-31 22:12:35 +0000324 if (!NetTxPacket) {
325 int i;
wdenk2d966952002-10-31 22:12:35 +0000326 /*
327 * Setup packet buffers, aligned correctly.
328 */
329 NetTxPacket = &PktBuf[0] + (PKTALIGN - 1);
330 NetTxPacket -= (ulong)NetTxPacket % PKTALIGN;
331 for (i = 0; i < PKTBUFSRX; i++) {
332 NetRxPackets[i] = NetTxPacket + (i+1)*PKTSIZE_ALIGN;
333 }
wdenk73a8b272003-06-05 19:27:42 +0000334 }
335
336 if (!NetArpWaitTxPacket) {
337 NetArpWaitTxPacket = &NetArpWaitPacketBuf[0] + (PKTALIGN - 1);
338 NetArpWaitTxPacket -= (ulong)NetArpWaitTxPacket % PKTALIGN;
339 NetArpWaitTxPacketSize = 0;
wdenk2d966952002-10-31 22:12:35 +0000340 }
341
342 eth_halt();
wdenk6e592382004-04-18 17:39:38 +0000343#ifdef CONFIG_NET_MULTI
wdenka3d991b2004-04-15 21:48:45 +0000344 eth_set_current();
wdenk6e592382004-04-18 17:39:38 +0000345#endif
wdenkb1bf6f22005-04-03 14:52:59 +0000346 if (eth_init(bd) < 0) {
347 eth_halt();
wdenk6e592382004-04-18 17:39:38 +0000348 return(-1);
wdenkb1bf6f22005-04-03 14:52:59 +0000349 }
wdenk2d966952002-10-31 22:12:35 +0000350
351restart:
352#ifdef CONFIG_NET_MULTI
353 memcpy (NetOurEther, eth_get_dev()->enetaddr, 6);
354#else
Mike Frysinger95823ca2009-02-11 18:23:48 -0500355 eth_getenv_enetaddr("ethaddr", NetOurEther);
wdenk2d966952002-10-31 22:12:35 +0000356#endif
357
358 NetState = NETLOOP_CONTINUE;
359
360 /*
361 * Start the ball rolling with the given start function. From
362 * here on, this code is a state machine driven by received
363 * packets and timer events.
364 */
Heiko Schocher2f70c492009-02-10 09:38:52 +0100365 NetInitLoop(protocol);
wdenk2d966952002-10-31 22:12:35 +0000366
367 switch (net_check_prereq (protocol)) {
368 case 1:
369 /* network not configured */
wdenkb1bf6f22005-04-03 14:52:59 +0000370 eth_halt();
wdenk1d0350e2002-11-11 21:14:20 +0000371 return (-1);
wdenk2d966952002-10-31 22:12:35 +0000372
373#ifdef CONFIG_NET_MULTI
374 case 2:
375 /* network device not configured */
376 break;
377#endif /* CONFIG_NET_MULTI */
378
379 case 0:
380#ifdef CONFIG_NET_MULTI
381 NetDevExists = 1;
382#endif
383 switch (protocol) {
384 case TFTP:
385 /* always use ARP to get server ethernet address */
wdenk73a8b272003-06-05 19:27:42 +0000386 TftpStart();
wdenk2d966952002-10-31 22:12:35 +0000387 break;
388
Jon Loeliger643d1ab2007-07-09 17:45:14 -0500389#if defined(CONFIG_CMD_DHCP)
wdenk2d966952002-10-31 22:12:35 +0000390 case DHCP:
wdenkd407bf52004-10-11 22:51:13 +0000391 BootpTry = 0;
wdenk2d966952002-10-31 22:12:35 +0000392 DhcpRequest(); /* Basically same as BOOTP */
393 break;
Jon Loeliger610f2e92007-07-10 11:05:02 -0500394#endif
wdenk2d966952002-10-31 22:12:35 +0000395
396 case BOOTP:
397 BootpTry = 0;
398 BootpRequest ();
399 break;
400
401 case RARP:
402 RarpTry = 0;
403 RarpRequest ();
404 break;
Jon Loeliger643d1ab2007-07-09 17:45:14 -0500405#if defined(CONFIG_CMD_PING)
wdenk73a8b272003-06-05 19:27:42 +0000406 case PING:
407 PingStart();
408 break;
409#endif
Jon Loeliger643d1ab2007-07-09 17:45:14 -0500410#if defined(CONFIG_CMD_NFS)
wdenkcbd8a352004-02-24 02:00:03 +0000411 case NFS:
412 NfsStart();
413 break;
414#endif
Jon Loeliger643d1ab2007-07-09 17:45:14 -0500415#if defined(CONFIG_CMD_CDP)
wdenka3d991b2004-04-15 21:48:45 +0000416 case CDP:
417 CDPStart();
418 break;
419#endif
wdenk68ceb292004-08-02 21:11:11 +0000420#ifdef CONFIG_NETCONSOLE
421 case NETCONS:
422 NcStart();
423 break;
424#endif
Jon Loeliger643d1ab2007-07-09 17:45:14 -0500425#if defined(CONFIG_CMD_SNTP)
wdenkea287de2005-04-01 00:25:43 +0000426 case SNTP:
427 SntpStart();
428 break;
429#endif
wdenk2d966952002-10-31 22:12:35 +0000430 default:
431 break;
432 }
433
434 NetBootFileXferSize = 0;
435 break;
436 }
437
Jon Loeliger643d1ab2007-07-09 17:45:14 -0500438#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200439#if defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN) && defined(CONFIG_STATUS_LED) && defined(STATUS_LED_RED)
wdenkfc3e2162003-10-08 22:33:00 +0000440 /*
wdenk42d1f032003-10-15 23:53:47 +0000441 * Echo the inverted link state to the fault LED.
wdenkfc3e2162003-10-08 22:33:00 +0000442 */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200443 if(miiphy_link(eth_get_dev()->name, CONFIG_SYS_FAULT_MII_ADDR)) {
wdenkfc3e2162003-10-08 22:33:00 +0000444 status_led_set (STATUS_LED_RED, STATUS_LED_OFF);
445 } else {
446 status_led_set (STATUS_LED_RED, STATUS_LED_ON);
447 }
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200448#endif /* CONFIG_SYS_FAULT_ECHO_LINK_DOWN, ... */
wdenkfc3e2162003-10-08 22:33:00 +0000449#endif /* CONFIG_MII, ... */
wdenk2d966952002-10-31 22:12:35 +0000450
451 /*
452 * Main packet reception loop. Loop receiving packets until
wdenk59acc292005-04-03 14:18:51 +0000453 * someone sets `NetState' to a state that terminates.
wdenk2d966952002-10-31 22:12:35 +0000454 */
455 for (;;) {
456 WATCHDOG_RESET();
457#ifdef CONFIG_SHOW_ACTIVITY
458 {
459 extern void show_activity(int arg);
460 show_activity(1);
461 }
462#endif
463 /*
464 * Check the ethernet for a new packet. The ethernet
465 * receive routine will process it.
466 */
Guennadi Liakhovetski40cb90e2008-04-03 17:04:19 +0200467 eth_rx();
wdenk2d966952002-10-31 22:12:35 +0000468
469 /*
470 * Abort if ctrl-c was pressed.
471 */
472 if (ctrlc()) {
wdenk8bde7f72003-06-27 21:31:46 +0000473 eth_halt();
wdenk4b9206e2004-03-23 22:14:11 +0000474 puts ("\nAbort\n");
wdenk1d0350e2002-11-11 21:14:20 +0000475 return (-1);
wdenk2d966952002-10-31 22:12:35 +0000476 }
477
wdenk73a8b272003-06-05 19:27:42 +0000478 ArpTimeoutCheck();
wdenk2d966952002-10-31 22:12:35 +0000479
480 /*
481 * Check for a timeout, and run the timeout handler
482 * if we have one.
483 */
wdenke0ac62d2003-08-17 18:55:18 +0000484 if (timeHandler && ((get_timer(0) - timeStart) > timeDelta)) {
wdenk2d966952002-10-31 22:12:35 +0000485 thand_f *x;
486
Jon Loeliger643d1ab2007-07-09 17:45:14 -0500487#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200488# if defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN) && \
wdenk63153492005-04-03 20:55:38 +0000489 defined(CONFIG_STATUS_LED) && \
wdenk59acc292005-04-03 14:18:51 +0000490 defined(STATUS_LED_RED)
wdenkfc3e2162003-10-08 22:33:00 +0000491 /*
wdenk42d1f032003-10-15 23:53:47 +0000492 * Echo the inverted link state to the fault LED.
wdenkfc3e2162003-10-08 22:33:00 +0000493 */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200494 if(miiphy_link(eth_get_dev()->name, CONFIG_SYS_FAULT_MII_ADDR)) {
wdenkfc3e2162003-10-08 22:33:00 +0000495 status_led_set (STATUS_LED_RED, STATUS_LED_OFF);
496 } else {
497 status_led_set (STATUS_LED_RED, STATUS_LED_ON);
498 }
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200499# endif /* CONFIG_SYS_FAULT_ECHO_LINK_DOWN, ... */
wdenkfc3e2162003-10-08 22:33:00 +0000500#endif /* CONFIG_MII, ... */
wdenk2d966952002-10-31 22:12:35 +0000501 x = timeHandler;
502 timeHandler = (thand_f *)0;
503 (*x)();
504 }
505
506
507 switch (NetState) {
508
509 case NETLOOP_RESTART:
510#ifdef CONFIG_NET_MULTI
511 NetRestarted = 1;
512#endif
513 goto restart;
514
515 case NETLOOP_SUCCESS:
516 if (NetBootFileXferSize > 0) {
Wolfgang Denkf34024d2007-09-12 00:48:57 +0200517 char buf[20];
wdenk2d966952002-10-31 22:12:35 +0000518 printf("Bytes transferred = %ld (%lx hex)\n",
519 NetBootFileXferSize,
520 NetBootFileXferSize);
Wolfgang Denkf34024d2007-09-12 00:48:57 +0200521 sprintf(buf, "%lX", NetBootFileXferSize);
wdenk2d966952002-10-31 22:12:35 +0000522 setenv("filesize", buf);
wdenka3d991b2004-04-15 21:48:45 +0000523
524 sprintf(buf, "%lX", (unsigned long)load_addr);
525 setenv("fileaddr", buf);
wdenk2d966952002-10-31 22:12:35 +0000526 }
527 eth_halt();
528 return NetBootFileXferSize;
529
530 case NETLOOP_FAIL:
wdenk1d0350e2002-11-11 21:14:20 +0000531 return (-1);
wdenk2d966952002-10-31 22:12:35 +0000532 }
533 }
534}
535
536/**********************************************************************/
537
538static void
539startAgainTimeout(void)
540{
541 NetState = NETLOOP_RESTART;
542}
543
544static void
545startAgainHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len)
546{
547 /* Totally ignore the packet */
548}
549
wdenk6e592382004-04-18 17:39:38 +0000550void NetStartAgain (void)
wdenk2d966952002-10-31 22:12:35 +0000551{
wdenk6e592382004-04-18 17:39:38 +0000552 char *nretry;
553 int noretry = 0, once = 0;
wdenka3d991b2004-04-15 21:48:45 +0000554
wdenk6e592382004-04-18 17:39:38 +0000555 if ((nretry = getenv ("netretry")) != NULL) {
556 noretry = (strcmp (nretry, "no") == 0);
557 once = (strcmp (nretry, "once") == 0);
558 }
559 if (noretry) {
560 eth_halt ();
wdenka3d991b2004-04-15 21:48:45 +0000561 NetState = NETLOOP_FAIL;
562 return;
563 }
wdenk2d966952002-10-31 22:12:35 +0000564#ifndef CONFIG_NET_MULTI
Bartlomiej Sieka49f3bdb2008-10-01 15:26:28 +0200565 NetSetTimeout (10000UL, startAgainTimeout);
wdenk6e592382004-04-18 17:39:38 +0000566 NetSetHandler (startAgainHandler);
567#else /* !CONFIG_NET_MULTI*/
568 eth_halt ();
Matthias Fuchs8b0c5c12007-12-27 16:58:41 +0100569#if !defined(CONFIG_NET_DO_NOT_TRY_ANOTHER)
wdenk6e592382004-04-18 17:39:38 +0000570 eth_try_another (!NetRestarted);
Matthias Fuchs8b0c5c12007-12-27 16:58:41 +0100571#endif
wdenk6e592382004-04-18 17:39:38 +0000572 eth_init (gd->bd);
573 if (NetRestartWrap) {
wdenk2d966952002-10-31 22:12:35 +0000574 NetRestartWrap = 0;
wdenk6e592382004-04-18 17:39:38 +0000575 if (NetDevExists && !once) {
Bartlomiej Sieka49f3bdb2008-10-01 15:26:28 +0200576 NetSetTimeout (10000UL, startAgainTimeout);
wdenk6e592382004-04-18 17:39:38 +0000577 NetSetHandler (startAgainHandler);
578 } else {
wdenk2d966952002-10-31 22:12:35 +0000579 NetState = NETLOOP_FAIL;
580 }
wdenk6e592382004-04-18 17:39:38 +0000581 } else {
wdenk2d966952002-10-31 22:12:35 +0000582 NetState = NETLOOP_RESTART;
583 }
wdenk6e592382004-04-18 17:39:38 +0000584#endif /* CONFIG_NET_MULTI */
wdenk2d966952002-10-31 22:12:35 +0000585}
586
587/**********************************************************************/
588/*
589 * Miscelaneous bits.
590 */
591
592void
593NetSetHandler(rxhand_f * f)
594{
595 packetHandler = f;
596}
597
598
599void
wdenk3e01d752004-10-09 21:56:21 +0000600NetSetTimeout(ulong iv, thand_f * f)
wdenk2d966952002-10-31 22:12:35 +0000601{
602 if (iv == 0) {
603 timeHandler = (thand_f *)0;
604 } else {
605 timeHandler = f;
wdenke0ac62d2003-08-17 18:55:18 +0000606 timeStart = get_timer(0);
607 timeDelta = iv;
wdenk2d966952002-10-31 22:12:35 +0000608 }
609}
610
611
612void
613NetSendPacket(volatile uchar * pkt, int len)
614{
615 (void) eth_send(pkt, len);
616}
617
wdenk73a8b272003-06-05 19:27:42 +0000618int
619NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, int sport, int len)
620{
wdenka3d991b2004-04-15 21:48:45 +0000621 uchar *pkt;
622
wdenk73a8b272003-06-05 19:27:42 +0000623 /* convert to new style broadcast */
624 if (dest == 0)
625 dest = 0xFFFFFFFF;
wdenk2d966952002-10-31 22:12:35 +0000626
wdenk73a8b272003-06-05 19:27:42 +0000627 /* if broadcast, make the ether address a broadcast and don't do ARP */
628 if (dest == 0xFFFFFFFF)
629 ether = NetBcastAddr;
630
631 /* if MAC address was not discovered yet, save the packet and do an ARP request */
632 if (memcmp(ether, NetEtherNullAddr, 6) == 0) {
633
634#ifdef ET_DEBUG
635 printf("sending ARP for %08lx\n", dest);
636#endif
wdenk73a8b272003-06-05 19:27:42 +0000637 NetArpWaitPacketIP = dest;
638 NetArpWaitPacketMAC = ether;
wdenka3d991b2004-04-15 21:48:45 +0000639
640 pkt = NetArpWaitTxPacket;
641 pkt += NetSetEther (pkt, NetArpWaitPacketMAC, PROT_IP);
642
643 NetSetIP (pkt, dest, dport, sport, len);
644 memcpy(pkt + IP_HDR_SIZE, (uchar *)NetTxPacket + (pkt - (uchar *)NetArpWaitTxPacket) + IP_HDR_SIZE, len);
wdenk73a8b272003-06-05 19:27:42 +0000645
646 /* size of the waiting packet */
wdenka3d991b2004-04-15 21:48:45 +0000647 NetArpWaitTxPacketSize = (pkt - NetArpWaitTxPacket) + IP_HDR_SIZE + len;
wdenk73a8b272003-06-05 19:27:42 +0000648
649 /* and do the ARP request */
650 NetArpWaitTry = 1;
651 NetArpWaitTimerStart = get_timer(0);
652 ArpRequest();
653 return 1; /* waiting */
654 }
655
656#ifdef ET_DEBUG
Mike Frysinger95823ca2009-02-11 18:23:48 -0500657 printf("sending UDP to %08lx/%pM\n", dest, ether);
wdenk73a8b272003-06-05 19:27:42 +0000658#endif
659
wdenka3d991b2004-04-15 21:48:45 +0000660 pkt = (uchar *)NetTxPacket;
661 pkt += NetSetEther (pkt, ether, PROT_IP);
662 NetSetIP (pkt, dest, dport, sport, len);
663 (void) eth_send(NetTxPacket, (pkt - NetTxPacket) + IP_HDR_SIZE + len);
wdenk73a8b272003-06-05 19:27:42 +0000664
wdenk6e592382004-04-18 17:39:38 +0000665 return 0; /* transmitted */
wdenk73a8b272003-06-05 19:27:42 +0000666}
667
Jon Loeliger643d1ab2007-07-09 17:45:14 -0500668#if defined(CONFIG_CMD_PING)
wdenk73a8b272003-06-05 19:27:42 +0000669static ushort PingSeqNo;
670
671int PingSend(void)
672{
673 static uchar mac[6];
674 volatile IP_t *ip;
675 volatile ushort *s;
wdenka3d991b2004-04-15 21:48:45 +0000676 uchar *pkt;
wdenk73a8b272003-06-05 19:27:42 +0000677
678 /* XXX always send arp request */
679
680 memcpy(mac, NetEtherNullAddr, 6);
681
682#ifdef ET_DEBUG
683 printf("sending ARP for %08lx\n", NetPingIP);
684#endif
685
686 NetArpWaitPacketIP = NetPingIP;
687 NetArpWaitPacketMAC = mac;
688
wdenka3d991b2004-04-15 21:48:45 +0000689 pkt = NetArpWaitTxPacket;
690 pkt += NetSetEther(pkt, mac, PROT_IP);
wdenk73a8b272003-06-05 19:27:42 +0000691
wdenka3d991b2004-04-15 21:48:45 +0000692 ip = (volatile IP_t *)pkt;
wdenk73a8b272003-06-05 19:27:42 +0000693
694 /*
695 * Construct an IP and ICMP header. (need to set no fragment bit - XXX)
696 */
697 ip->ip_hl_v = 0x45; /* IP_HDR_SIZE / 4 (not including UDP) */
698 ip->ip_tos = 0;
699 ip->ip_len = htons(IP_HDR_SIZE_NO_UDP + 8);
700 ip->ip_id = htons(NetIPID++);
Peter Tysere0c07b82008-12-01 16:26:20 -0600701 ip->ip_off = htons(IP_FLAGS_DFRAG); /* Don't fragment */
wdenk73a8b272003-06-05 19:27:42 +0000702 ip->ip_ttl = 255;
703 ip->ip_p = 0x01; /* ICMP */
704 ip->ip_sum = 0;
705 NetCopyIP((void*)&ip->ip_src, &NetOurIP); /* already in network byte order */
706 NetCopyIP((void*)&ip->ip_dst, &NetPingIP); /* - "" - */
707 ip->ip_sum = ~NetCksum((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2);
708
709 s = &ip->udp_src; /* XXX ICMP starts here */
710 s[0] = htons(0x0800); /* echo-request, code */
711 s[1] = 0; /* checksum */
Wolfgang Denk53677ef2008-05-20 16:00:29 +0200712 s[2] = 0; /* identifier */
wdenk73a8b272003-06-05 19:27:42 +0000713 s[3] = htons(PingSeqNo++); /* sequence number */
714 s[1] = ~NetCksum((uchar *)s, 8/2);
715
716 /* size of the waiting packet */
wdenka3d991b2004-04-15 21:48:45 +0000717 NetArpWaitTxPacketSize = (pkt - NetArpWaitTxPacket) + IP_HDR_SIZE_NO_UDP + 8;
wdenk73a8b272003-06-05 19:27:42 +0000718
719 /* and do the ARP request */
720 NetArpWaitTry = 1;
721 NetArpWaitTimerStart = get_timer(0);
722 ArpRequest();
723 return 1; /* waiting */
724}
725
726static void
727PingTimeout (void)
728{
729 eth_halt();
730 NetState = NETLOOP_FAIL; /* we did not get the reply */
731}
732
733static void
734PingHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len)
735{
736 IPaddr_t tmp;
737 volatile IP_t *ip = (volatile IP_t *)pkt;
738
739 tmp = NetReadIP((void *)&ip->ip_src);
740 if (tmp != NetPingIP)
741 return;
742
743 NetState = NETLOOP_SUCCESS;
744}
745
746static void PingStart(void)
747{
wdenka3d991b2004-04-15 21:48:45 +0000748#if defined(CONFIG_NET_MULTI)
749 printf ("Using %s device\n", eth_get_name());
wdenk6e592382004-04-18 17:39:38 +0000750#endif /* CONFIG_NET_MULTI */
Bartlomiej Sieka49f3bdb2008-10-01 15:26:28 +0200751 NetSetTimeout (10000UL, PingTimeout);
wdenk73a8b272003-06-05 19:27:42 +0000752 NetSetHandler (PingHandler);
753
754 PingSend();
755}
Jon Loeliger610f2e92007-07-10 11:05:02 -0500756#endif
wdenk2d966952002-10-31 22:12:35 +0000757
Jon Loeliger643d1ab2007-07-09 17:45:14 -0500758#if defined(CONFIG_CMD_CDP)
wdenka3d991b2004-04-15 21:48:45 +0000759
760#define CDP_DEVICE_ID_TLV 0x0001
761#define CDP_ADDRESS_TLV 0x0002
762#define CDP_PORT_ID_TLV 0x0003
763#define CDP_CAPABILITIES_TLV 0x0004
764#define CDP_VERSION_TLV 0x0005
765#define CDP_PLATFORM_TLV 0x0006
766#define CDP_NATIVE_VLAN_TLV 0x000a
767#define CDP_APPLIANCE_VLAN_TLV 0x000e
768#define CDP_TRIGGER_TLV 0x000f
769#define CDP_POWER_CONSUMPTION_TLV 0x0010
770#define CDP_SYSNAME_TLV 0x0014
771#define CDP_SYSOBJECT_TLV 0x0015
772#define CDP_MANAGEMENT_ADDRESS_TLV 0x0016
773
Bartlomiej Sieka49f3bdb2008-10-01 15:26:28 +0200774#define CDP_TIMEOUT 250UL /* one packet every 250ms */
wdenka3d991b2004-04-15 21:48:45 +0000775
776static int CDPSeq;
777static int CDPOK;
778
779ushort CDPNativeVLAN;
780ushort CDPApplianceVLAN;
781
782static const uchar CDP_SNAP_hdr[8] = { 0xAA, 0xAA, 0x03, 0x00, 0x00, 0x0C, 0x20, 0x00 };
783
784static ushort CDP_compute_csum(const uchar *buff, ushort len)
785{
786 ushort csum;
787 int odd;
788 ulong result = 0;
789 ushort leftover;
Wolfgang Denk77ddac92005-10-13 16:45:02 +0200790 ushort *p;
wdenka3d991b2004-04-15 21:48:45 +0000791
792 if (len > 0) {
793 odd = 1 & (ulong)buff;
794 if (odd) {
795 result = *buff << 8;
796 len--;
797 buff++;
798 }
799 while (len > 1) {
Wolfgang Denk77ddac92005-10-13 16:45:02 +0200800 p = (ushort *)buff;
801 result += *p++;
802 buff = (uchar *)p;
wdenka3d991b2004-04-15 21:48:45 +0000803 if (result & 0x80000000)
804 result = (result & 0xFFFF) + (result >> 16);
805 len -= 2;
806 }
807 if (len) {
808 leftover = (signed short)(*(const signed char *)buff);
Wolfgang Denk3ada8342005-11-10 20:59:46 +0100809 /* CISCO SUCKS big time! (and blows too):
810 * CDP uses the IP checksum algorithm with a twist;
811 * for the last byte it *sign* extends and sums.
812 */
wdenka3d991b2004-04-15 21:48:45 +0000813 result = (result & 0xffff0000) | ((result + leftover) & 0x0000ffff);
814 }
815 while (result >> 16)
816 result = (result & 0xFFFF) + (result >> 16);
817
818 if (odd)
819 result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
820 }
821
822 /* add up 16-bit and 17-bit words for 17+c bits */
823 result = (result & 0xffff) + (result >> 16);
824 /* add up 16-bit and 2-bit for 16+c bit */
825 result = (result & 0xffff) + (result >> 16);
826 /* add up carry.. */
827 result = (result & 0xffff) + (result >> 16);
828
829 /* negate */
830 csum = ~(ushort)result;
831
832 /* run time endian detection */
833 if (csum != htons(csum)) /* little endian */
834 csum = htons(csum);
835
836 return csum;
837}
838
839int CDPSendTrigger(void)
840{
841 volatile uchar *pkt;
842 volatile ushort *s;
843 volatile ushort *cp;
844 Ethernet_t *et;
wdenka3d991b2004-04-15 21:48:45 +0000845 int len;
846 ushort chksum;
wdenk6e592382004-04-18 17:39:38 +0000847#if defined(CONFIG_CDP_DEVICE_ID) || defined(CONFIG_CDP_PORT_ID) || \
848 defined(CONFIG_CDP_VERSION) || defined(CONFIG_CDP_PLATFORM)
849 char buf[32];
850#endif
wdenka3d991b2004-04-15 21:48:45 +0000851
852 pkt = NetTxPacket;
853 et = (Ethernet_t *)pkt;
854
855 /* NOTE: trigger sent not on any VLAN */
856
857 /* form ethernet header */
858 memcpy(et->et_dest, NetCDPAddr, 6);
859 memcpy(et->et_src, NetOurEther, 6);
860
861 pkt += ETHER_HDR_SIZE;
862
863 /* SNAP header */
864 memcpy((uchar *)pkt, CDP_SNAP_hdr, sizeof(CDP_SNAP_hdr));
865 pkt += sizeof(CDP_SNAP_hdr);
866
867 /* CDP header */
868 *pkt++ = 0x02; /* CDP version 2 */
869 *pkt++ = 180; /* TTL */
870 s = (volatile ushort *)pkt;
871 cp = s;
872 *s++ = htons(0); /* checksum (0 for later calculation) */
873
874 /* CDP fields */
875#ifdef CONFIG_CDP_DEVICE_ID
876 *s++ = htons(CDP_DEVICE_ID_TLV);
877 *s++ = htons(CONFIG_CDP_DEVICE_ID);
Mike Frysinger95823ca2009-02-11 18:23:48 -0500878 sprintf(buf, CONFIG_CDP_DEVICE_ID_PREFIX "%pm", NetOurEther);
wdenka3d991b2004-04-15 21:48:45 +0000879 memcpy((uchar *)s, buf, 16);
880 s += 16 / 2;
881#endif
882
883#ifdef CONFIG_CDP_PORT_ID
884 *s++ = htons(CDP_PORT_ID_TLV);
885 memset(buf, 0, sizeof(buf));
886 sprintf(buf, CONFIG_CDP_PORT_ID, eth_get_dev_index());
887 len = strlen(buf);
888 if (len & 1) /* make it even */
889 len++;
890 *s++ = htons(len + 4);
891 memcpy((uchar *)s, buf, len);
892 s += len / 2;
893#endif
894
895#ifdef CONFIG_CDP_CAPABILITIES
896 *s++ = htons(CDP_CAPABILITIES_TLV);
897 *s++ = htons(8);
898 *(ulong *)s = htonl(CONFIG_CDP_CAPABILITIES);
899 s += 2;
900#endif
901
902#ifdef CONFIG_CDP_VERSION
903 *s++ = htons(CDP_VERSION_TLV);
904 memset(buf, 0, sizeof(buf));
905 strcpy(buf, CONFIG_CDP_VERSION);
906 len = strlen(buf);
907 if (len & 1) /* make it even */
908 len++;
909 *s++ = htons(len + 4);
910 memcpy((uchar *)s, buf, len);
911 s += len / 2;
912#endif
913
914#ifdef CONFIG_CDP_PLATFORM
915 *s++ = htons(CDP_PLATFORM_TLV);
916 memset(buf, 0, sizeof(buf));
917 strcpy(buf, CONFIG_CDP_PLATFORM);
918 len = strlen(buf);
919 if (len & 1) /* make it even */
920 len++;
921 *s++ = htons(len + 4);
922 memcpy((uchar *)s, buf, len);
923 s += len / 2;
924#endif
925
926#ifdef CONFIG_CDP_TRIGGER
927 *s++ = htons(CDP_TRIGGER_TLV);
928 *s++ = htons(8);
929 *(ulong *)s = htonl(CONFIG_CDP_TRIGGER);
930 s += 2;
931#endif
932
933#ifdef CONFIG_CDP_POWER_CONSUMPTION
934 *s++ = htons(CDP_POWER_CONSUMPTION_TLV);
935 *s++ = htons(6);
936 *s++ = htons(CONFIG_CDP_POWER_CONSUMPTION);
937#endif
938
939 /* length of ethernet packet */
940 len = (uchar *)s - ((uchar *)NetTxPacket + ETHER_HDR_SIZE);
941 et->et_protlen = htons(len);
942
943 len = ETHER_HDR_SIZE + sizeof(CDP_SNAP_hdr);
944 chksum = CDP_compute_csum((uchar *)NetTxPacket + len, (uchar *)s - (NetTxPacket + len));
945 if (chksum == 0)
946 chksum = 0xFFFF;
947 *cp = htons(chksum);
948
949 (void) eth_send(NetTxPacket, (uchar *)s - NetTxPacket);
950 return 0;
951}
952
953static void
954CDPTimeout (void)
955{
956 CDPSeq++;
957
958 if (CDPSeq < 3) {
959 NetSetTimeout (CDP_TIMEOUT, CDPTimeout);
960 CDPSendTrigger();
961 return;
962 }
963
964 /* if not OK try again */
965 if (!CDPOK)
966 NetStartAgain();
967 else
968 NetState = NETLOOP_SUCCESS;
969}
970
971static void
972CDPDummyHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len)
973{
974 /* nothing */
975}
976
977static void
978CDPHandler(const uchar * pkt, unsigned len)
979{
980 const uchar *t;
981 const ushort *ss;
982 ushort type, tlen;
983 uchar applid;
984 ushort vlan, nvlan;
985
986 /* minimum size? */
987 if (len < sizeof(CDP_SNAP_hdr) + 4)
988 goto pkt_short;
989
990 /* check for valid CDP SNAP header */
991 if (memcmp(pkt, CDP_SNAP_hdr, sizeof(CDP_SNAP_hdr)) != 0)
992 return;
993
994 pkt += sizeof(CDP_SNAP_hdr);
995 len -= sizeof(CDP_SNAP_hdr);
996
997 /* Version of CDP protocol must be >= 2 and TTL != 0 */
998 if (pkt[0] < 0x02 || pkt[1] == 0)
999 return;
1000
1001 /* if version is greater than 0x02 maybe we'll have a problem; output a warning */
1002 if (pkt[0] != 0x02)
1003 printf("** WARNING: CDP packet received with a protocol version %d > 2\n",
1004 pkt[0] & 0xff);
1005
1006 if (CDP_compute_csum(pkt, len) != 0)
1007 return;
1008
1009 pkt += 4;
1010 len -= 4;
1011
1012 vlan = htons(-1);
1013 nvlan = htons(-1);
1014 while (len > 0) {
1015 if (len < 4)
1016 goto pkt_short;
1017
1018 ss = (const ushort *)pkt;
1019 type = ntohs(ss[0]);
1020 tlen = ntohs(ss[1]);
1021 if (tlen > len) {
1022 goto pkt_short;
1023 }
1024
1025 pkt += tlen;
1026 len -= tlen;
1027
1028 ss += 2; /* point ss to the data of the TLV */
1029 tlen -= 4;
1030
1031 switch (type) {
1032 case CDP_DEVICE_ID_TLV:
1033 break;
1034 case CDP_ADDRESS_TLV:
1035 break;
1036 case CDP_PORT_ID_TLV:
1037 break;
1038 case CDP_CAPABILITIES_TLV:
1039 break;
1040 case CDP_VERSION_TLV:
1041 break;
1042 case CDP_PLATFORM_TLV:
1043 break;
1044 case CDP_NATIVE_VLAN_TLV:
1045 nvlan = *ss;
1046 break;
1047 case CDP_APPLIANCE_VLAN_TLV:
1048 t = (const uchar *)ss;
1049 while (tlen > 0) {
1050 if (tlen < 3)
1051 goto pkt_short;
1052
1053 applid = t[0];
1054 ss = (const ushort *)(t + 1);
1055
1056#ifdef CONFIG_CDP_APPLIANCE_VLAN_TYPE
1057 if (applid == CONFIG_CDP_APPLIANCE_VLAN_TYPE)
1058 vlan = *ss;
1059#else
1060 vlan = ntohs(*ss); /* XXX will this work; dunno */
1061#endif
1062 t += 3; tlen -= 3;
1063 }
1064 break;
1065 case CDP_TRIGGER_TLV:
1066 break;
1067 case CDP_POWER_CONSUMPTION_TLV:
1068 break;
1069 case CDP_SYSNAME_TLV:
1070 break;
1071 case CDP_SYSOBJECT_TLV:
1072 break;
1073 case CDP_MANAGEMENT_ADDRESS_TLV:
1074 break;
1075 }
1076 }
1077
1078 CDPApplianceVLAN = vlan;
1079 CDPNativeVLAN = nvlan;
1080
1081 CDPOK = 1;
1082 return;
1083
1084 pkt_short:
1085 printf("** CDP packet is too short\n");
1086 return;
1087}
1088
1089static void CDPStart(void)
1090{
1091#if defined(CONFIG_NET_MULTI)
1092 printf ("Using %s device\n", eth_get_name());
1093#endif
1094 CDPSeq = 0;
1095 CDPOK = 0;
1096
1097 CDPNativeVLAN = htons(-1);
1098 CDPApplianceVLAN = htons(-1);
1099
1100 NetSetTimeout (CDP_TIMEOUT, CDPTimeout);
1101 NetSetHandler (CDPDummyHandler);
1102
1103 CDPSendTrigger();
1104}
Jon Loeliger610f2e92007-07-10 11:05:02 -05001105#endif
wdenka3d991b2004-04-15 21:48:45 +00001106
1107
wdenk2d966952002-10-31 22:12:35 +00001108void
wdenka3d991b2004-04-15 21:48:45 +00001109NetReceive(volatile uchar * inpkt, int len)
wdenk2d966952002-10-31 22:12:35 +00001110{
1111 Ethernet_t *et;
1112 IP_t *ip;
1113 ARP_t *arp;
1114 IPaddr_t tmp;
1115 int x;
wdenka3d991b2004-04-15 21:48:45 +00001116 uchar *pkt;
Jon Loeliger643d1ab2007-07-09 17:45:14 -05001117#if defined(CONFIG_CMD_CDP)
wdenka3d991b2004-04-15 21:48:45 +00001118 int iscdp;
1119#endif
1120 ushort cti = 0, vlanid = VLAN_NONE, myvlanid, mynvlanid;
wdenk2d966952002-10-31 22:12:35 +00001121
wdenka3d991b2004-04-15 21:48:45 +00001122#ifdef ET_DEBUG
1123 printf("packet received\n");
1124#endif
1125
1126 NetRxPkt = inpkt;
wdenk2d966952002-10-31 22:12:35 +00001127 NetRxPktLen = len;
wdenka3d991b2004-04-15 21:48:45 +00001128 et = (Ethernet_t *)inpkt;
1129
1130 /* too small packet? */
1131 if (len < ETHER_HDR_SIZE)
1132 return;
1133
Rafal Jaworowskif85b6072007-12-27 18:19:02 +01001134#ifdef CONFIG_API
1135 if (push_packet) {
1136 (*push_packet)(inpkt, len);
1137 return;
1138 }
1139#endif
1140
Jon Loeliger643d1ab2007-07-09 17:45:14 -05001141#if defined(CONFIG_CMD_CDP)
wdenka3d991b2004-04-15 21:48:45 +00001142 /* keep track if packet is CDP */
1143 iscdp = memcmp(et->et_dest, NetCDPAddr, 6) == 0;
1144#endif
1145
1146 myvlanid = ntohs(NetOurVLAN);
1147 if (myvlanid == (ushort)-1)
1148 myvlanid = VLAN_NONE;
1149 mynvlanid = ntohs(NetOurNativeVLAN);
1150 if (mynvlanid == (ushort)-1)
1151 mynvlanid = VLAN_NONE;
wdenk2d966952002-10-31 22:12:35 +00001152
1153 x = ntohs(et->et_protlen);
1154
wdenka3d991b2004-04-15 21:48:45 +00001155#ifdef ET_DEBUG
1156 printf("packet received\n");
1157#endif
1158
wdenk2d966952002-10-31 22:12:35 +00001159 if (x < 1514) {
1160 /*
1161 * Got a 802 packet. Check the other protocol field.
1162 */
1163 x = ntohs(et->et_prot);
wdenka3d991b2004-04-15 21:48:45 +00001164
1165 ip = (IP_t *)(inpkt + E802_HDR_SIZE);
wdenk2d966952002-10-31 22:12:35 +00001166 len -= E802_HDR_SIZE;
wdenka3d991b2004-04-15 21:48:45 +00001167
1168 } else if (x != PROT_VLAN) { /* normal packet */
1169 ip = (IP_t *)(inpkt + ETHER_HDR_SIZE);
wdenk2d966952002-10-31 22:12:35 +00001170 len -= ETHER_HDR_SIZE;
wdenka3d991b2004-04-15 21:48:45 +00001171
1172 } else { /* VLAN packet */
1173 VLAN_Ethernet_t *vet = (VLAN_Ethernet_t *)et;
1174
1175#ifdef ET_DEBUG
1176 printf("VLAN packet received\n");
1177#endif
1178 /* too small packet? */
1179 if (len < VLAN_ETHER_HDR_SIZE)
1180 return;
1181
1182 /* if no VLAN active */
1183 if ((ntohs(NetOurVLAN) & VLAN_IDMASK) == VLAN_NONE
Jon Loeliger643d1ab2007-07-09 17:45:14 -05001184#if defined(CONFIG_CMD_CDP)
wdenka3d991b2004-04-15 21:48:45 +00001185 && iscdp == 0
1186#endif
1187 )
1188 return;
1189
1190 cti = ntohs(vet->vet_tag);
1191 vlanid = cti & VLAN_IDMASK;
1192 x = ntohs(vet->vet_type);
1193
1194 ip = (IP_t *)(inpkt + VLAN_ETHER_HDR_SIZE);
1195 len -= VLAN_ETHER_HDR_SIZE;
wdenk2d966952002-10-31 22:12:35 +00001196 }
1197
1198#ifdef ET_DEBUG
1199 printf("Receive from protocol 0x%x\n", x);
1200#endif
1201
Jon Loeliger643d1ab2007-07-09 17:45:14 -05001202#if defined(CONFIG_CMD_CDP)
wdenka3d991b2004-04-15 21:48:45 +00001203 if (iscdp) {
1204 CDPHandler((uchar *)ip, len);
1205 return;
1206 }
1207#endif
1208
1209 if ((myvlanid & VLAN_IDMASK) != VLAN_NONE) {
1210 if (vlanid == VLAN_NONE)
1211 vlanid = (mynvlanid & VLAN_IDMASK);
1212 /* not matched? */
1213 if (vlanid != (myvlanid & VLAN_IDMASK))
1214 return;
1215 }
1216
wdenk2d966952002-10-31 22:12:35 +00001217 switch (x) {
1218
1219 case PROT_ARP:
1220 /*
1221 * We have to deal with two types of ARP packets:
wdenk8bde7f72003-06-27 21:31:46 +00001222 * - REQUEST packets will be answered by sending our
1223 * IP address - if we know it.
1224 * - REPLY packates are expected only after we asked
1225 * for the TFTP server's or the gateway's ethernet
1226 * address; so if we receive such a packet, we set
1227 * the server ethernet address
wdenk2d966952002-10-31 22:12:35 +00001228 */
1229#ifdef ET_DEBUG
wdenk4b9206e2004-03-23 22:14:11 +00001230 puts ("Got ARP\n");
wdenk2d966952002-10-31 22:12:35 +00001231#endif
1232 arp = (ARP_t *)ip;
1233 if (len < ARP_HDR_SIZE) {
1234 printf("bad length %d < %d\n", len, ARP_HDR_SIZE);
1235 return;
1236 }
1237 if (ntohs(arp->ar_hrd) != ARP_ETHER) {
1238 return;
1239 }
1240 if (ntohs(arp->ar_pro) != PROT_IP) {
1241 return;
1242 }
1243 if (arp->ar_hln != 6) {
1244 return;
1245 }
1246 if (arp->ar_pln != 4) {
1247 return;
1248 }
1249
1250 if (NetOurIP == 0) {
1251 return;
1252 }
1253
1254 if (NetReadIP(&arp->ar_data[16]) != NetOurIP) {
1255 return;
1256 }
1257
1258 switch (ntohs(arp->ar_op)) {
1259 case ARPOP_REQUEST: /* reply with our IP address */
1260#ifdef ET_DEBUG
wdenk4b9206e2004-03-23 22:14:11 +00001261 puts ("Got ARP REQUEST, return our IP\n");
wdenk2d966952002-10-31 22:12:35 +00001262#endif
wdenka3d991b2004-04-15 21:48:45 +00001263 pkt = (uchar *)et;
1264 pkt += NetSetEther(pkt, et->et_src, PROT_ARP);
wdenk2d966952002-10-31 22:12:35 +00001265 arp->ar_op = htons(ARPOP_REPLY);
1266 memcpy (&arp->ar_data[10], &arp->ar_data[0], 6);
1267 NetCopyIP(&arp->ar_data[16], &arp->ar_data[6]);
1268 memcpy (&arp->ar_data[ 0], NetOurEther, 6);
1269 NetCopyIP(&arp->ar_data[ 6], &NetOurIP);
wdenka3d991b2004-04-15 21:48:45 +00001270 (void) eth_send((uchar *)et, (pkt - (uchar *)et) + ARP_HDR_SIZE);
wdenk2d966952002-10-31 22:12:35 +00001271 return;
wdenk73a8b272003-06-05 19:27:42 +00001272
1273 case ARPOP_REPLY: /* arp reply */
1274 /* are we waiting for a reply */
1275 if (!NetArpWaitPacketIP || !NetArpWaitPacketMAC)
1276 break;
wdenk2d966952002-10-31 22:12:35 +00001277#ifdef ET_DEBUG
Mike Frysinger95823ca2009-02-11 18:23:48 -05001278 printf("Got ARP REPLY, set server/gtwy eth addr (%pM)\n",
1279 arp->ar_data);
wdenk2d966952002-10-31 22:12:35 +00001280#endif
wdenk73a8b272003-06-05 19:27:42 +00001281
1282 tmp = NetReadIP(&arp->ar_data[6]);
1283
1284 /* matched waiting packet's address */
1285 if (tmp == NetArpWaitReplyIP) {
1286#ifdef ET_DEBUG
wdenk4b9206e2004-03-23 22:14:11 +00001287 puts ("Got it\n");
wdenk73a8b272003-06-05 19:27:42 +00001288#endif
1289 /* save address for later use */
1290 memcpy(NetArpWaitPacketMAC, &arp->ar_data[0], 6);
1291
wdenk68ceb292004-08-02 21:11:11 +00001292#ifdef CONFIG_NETCONSOLE
1293 (*packetHandler)(0,0,0,0);
1294#endif
wdenk73a8b272003-06-05 19:27:42 +00001295 /* modify header, and transmit it */
1296 memcpy(((Ethernet_t *)NetArpWaitTxPacket)->et_dest, NetArpWaitPacketMAC, 6);
1297 (void) eth_send(NetArpWaitTxPacket, NetArpWaitTxPacketSize);
1298
1299 /* no arp request pending now */
1300 NetArpWaitPacketIP = 0;
1301 NetArpWaitTxPacketSize = 0;
1302 NetArpWaitPacketMAC = NULL;
1303
1304 }
wdenk2d966952002-10-31 22:12:35 +00001305 return;
1306 default:
1307#ifdef ET_DEBUG
1308 printf("Unexpected ARP opcode 0x%x\n", ntohs(arp->ar_op));
1309#endif
1310 return;
1311 }
wdenk289f9322005-01-12 00:15:14 +00001312 break;
wdenk2d966952002-10-31 22:12:35 +00001313
1314 case PROT_RARP:
1315#ifdef ET_DEBUG
wdenk4b9206e2004-03-23 22:14:11 +00001316 puts ("Got RARP\n");
wdenk2d966952002-10-31 22:12:35 +00001317#endif
1318 arp = (ARP_t *)ip;
1319 if (len < ARP_HDR_SIZE) {
1320 printf("bad length %d < %d\n", len, ARP_HDR_SIZE);
1321 return;
1322 }
1323
1324 if ((ntohs(arp->ar_op) != RARPOP_REPLY) ||
1325 (ntohs(arp->ar_hrd) != ARP_ETHER) ||
1326 (ntohs(arp->ar_pro) != PROT_IP) ||
1327 (arp->ar_hln != 6) || (arp->ar_pln != 4)) {
1328
wdenk4b9206e2004-03-23 22:14:11 +00001329 puts ("invalid RARP header\n");
wdenk2d966952002-10-31 22:12:35 +00001330 } else {
1331 NetCopyIP(&NetOurIP, &arp->ar_data[16]);
wdenk3d3befa2004-03-14 15:06:13 +00001332 if (NetServerIP == 0)
1333 NetCopyIP(&NetServerIP, &arp->ar_data[ 6]);
wdenk2d966952002-10-31 22:12:35 +00001334 memcpy (NetServerEther, &arp->ar_data[ 0], 6);
1335
1336 (*packetHandler)(0,0,0,0);
1337 }
1338 break;
1339
1340 case PROT_IP:
1341#ifdef ET_DEBUG
wdenk4b9206e2004-03-23 22:14:11 +00001342 puts ("Got IP\n");
wdenk2d966952002-10-31 22:12:35 +00001343#endif
1344 if (len < IP_HDR_SIZE) {
Wolfgang Denk25dbe982008-07-13 23:07:35 +02001345 debug ("len bad %d < %lu\n", len, (ulong)IP_HDR_SIZE);
wdenk2d966952002-10-31 22:12:35 +00001346 return;
1347 }
1348 if (len < ntohs(ip->ip_len)) {
1349 printf("len bad %d < %d\n", len, ntohs(ip->ip_len));
1350 return;
1351 }
1352 len = ntohs(ip->ip_len);
1353#ifdef ET_DEBUG
1354 printf("len=%d, v=%02x\n", len, ip->ip_hl_v & 0xff);
1355#endif
1356 if ((ip->ip_hl_v & 0xf0) != 0x40) {
1357 return;
1358 }
Peter Tyserd32c5be2008-12-01 16:26:21 -06001359 /* Can't deal with fragments */
1360 if (ip->ip_off & htons(IP_OFFS | IP_FLAGS_MFRAG)) {
wdenk2d966952002-10-31 22:12:35 +00001361 return;
1362 }
Remy Bohmer6b52cfe2008-06-03 15:48:17 +02001363 /* can't deal with headers > 20 bytes */
1364 if ((ip->ip_hl_v & 0x0f) > 0x05) {
1365 return;
1366 }
wdenk2d966952002-10-31 22:12:35 +00001367 if (!NetCksumOk((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2)) {
wdenk4b9206e2004-03-23 22:14:11 +00001368 puts ("checksum bad\n");
wdenk2d966952002-10-31 22:12:35 +00001369 return;
1370 }
1371 tmp = NetReadIP(&ip->ip_dst);
1372 if (NetOurIP && tmp != NetOurIP && tmp != 0xFFFFFFFF) {
David Updegraff53a5c422007-06-11 10:41:07 -05001373#ifdef CONFIG_MCAST_TFTP
Wolfgang Denk85eb5ca2007-08-14 09:47:27 +02001374 if (Mcast_addr != tmp)
David Updegraff53a5c422007-06-11 10:41:07 -05001375#endif
wdenk2d966952002-10-31 22:12:35 +00001376 return;
1377 }
1378 /*
1379 * watch for ICMP host redirects
1380 *
wdenk8bde7f72003-06-27 21:31:46 +00001381 * There is no real handler code (yet). We just watch
1382 * for ICMP host redirect messages. In case anybody
1383 * sees these messages: please contact me
1384 * (wd@denx.de), or - even better - send me the
1385 * necessary fixes :-)
wdenk2d966952002-10-31 22:12:35 +00001386 *
wdenk8bde7f72003-06-27 21:31:46 +00001387 * Note: in all cases where I have seen this so far
1388 * it was a problem with the router configuration,
1389 * for instance when a router was configured in the
1390 * BOOTP reply, but the TFTP server was on the same
1391 * subnet. So this is probably a warning that your
1392 * configuration might be wrong. But I'm not really
1393 * sure if there aren't any other situations.
wdenk2d966952002-10-31 22:12:35 +00001394 */
1395 if (ip->ip_p == IPPROTO_ICMP) {
1396 ICMP_t *icmph = (ICMP_t *)&(ip->udp_src);
1397
wdenk73a8b272003-06-05 19:27:42 +00001398 switch (icmph->type) {
1399 case ICMP_REDIRECT:
wdenk90dc6702005-05-03 14:12:25 +00001400 if (icmph->code != ICMP_REDIR_HOST)
1401 return;
Mike Frysingerb6446b62009-02-17 00:00:53 -05001402 printf (" ICMP Host Redirect to %pI4 ", &icmph->un.gateway);
Stefan Roese8534bf92005-08-12 20:06:52 +02001403 return;
Jon Loeliger643d1ab2007-07-09 17:45:14 -05001404#if defined(CONFIG_CMD_PING)
wdenk73a8b272003-06-05 19:27:42 +00001405 case ICMP_ECHO_REPLY:
1406 /*
1407 * IP header OK. Pass the packet to the current handler.
1408 */
1409 /* XXX point to ip packet */
1410 (*packetHandler)((uchar *)ip, 0, 0, 0);
Stefan Roese8534bf92005-08-12 20:06:52 +02001411 return;
Ed Swarthout83853172007-03-07 12:14:50 -06001412 case ICMP_ECHO_REQUEST:
1413#ifdef ET_DEBUG
1414 printf ("Got ICMP ECHO REQUEST, return %d bytes \n",
1415 ETHER_HDR_SIZE + len);
1416#endif
1417 memcpy (&et->et_dest[0], &et->et_src[0], 6);
1418 memcpy (&et->et_src[ 0], NetOurEther, 6);
1419
1420 ip->ip_sum = 0;
1421 ip->ip_off = 0;
1422 NetCopyIP((void*)&ip->ip_dst, &ip->ip_src);
1423 NetCopyIP((void*)&ip->ip_src, &NetOurIP);
1424 ip->ip_sum = ~NetCksum((uchar *)ip, IP_HDR_SIZE_NO_UDP >> 1);
1425
1426 icmph->type = ICMP_ECHO_REPLY;
1427 icmph->checksum = 0;
1428 icmph->checksum = ~NetCksum((uchar *)icmph,
1429 (len - IP_HDR_SIZE_NO_UDP) >> 1);
1430 (void) eth_send((uchar *)et, ETHER_HDR_SIZE + len);
1431 return;
wdenk73a8b272003-06-05 19:27:42 +00001432#endif
1433 default:
1434 return;
1435 }
wdenk2d966952002-10-31 22:12:35 +00001436 } else if (ip->ip_p != IPPROTO_UDP) { /* Only UDP packets */
1437 return;
1438 }
1439
Stefan Roese8534bf92005-08-12 20:06:52 +02001440#ifdef CONFIG_UDP_CHECKSUM
1441 if (ip->udp_xsum != 0) {
Wolfgang Denkb2f50802005-08-12 23:43:12 +02001442 ulong xsum;
Stefan Roese8534bf92005-08-12 20:06:52 +02001443 ushort *sumptr;
1444 ushort sumlen;
1445
1446 xsum = ip->ip_p;
1447 xsum += (ntohs(ip->udp_len));
1448 xsum += (ntohl(ip->ip_src) >> 16) & 0x0000ffff;
1449 xsum += (ntohl(ip->ip_src) >> 0) & 0x0000ffff;
1450 xsum += (ntohl(ip->ip_dst) >> 16) & 0x0000ffff;
1451 xsum += (ntohl(ip->ip_dst) >> 0) & 0x0000ffff;
1452
1453 sumlen = ntohs(ip->udp_len);
1454 sumptr = (ushort *) &(ip->udp_src);
1455
1456 while (sumlen > 1) {
Wolfgang Denkb2f50802005-08-12 23:43:12 +02001457 ushort sumdata;
Stefan Roese8534bf92005-08-12 20:06:52 +02001458
1459 sumdata = *sumptr++;
1460 xsum += ntohs(sumdata);
1461 sumlen -= 2;
1462 }
1463 if (sumlen > 0) {
Wolfgang Denkb2f50802005-08-12 23:43:12 +02001464 ushort sumdata;
Stefan Roese8534bf92005-08-12 20:06:52 +02001465
1466 sumdata = *(unsigned char *) sumptr;
Wolfgang Denkb2f50802005-08-12 23:43:12 +02001467 sumdata = (sumdata << 8) & 0xff00;
Stefan Roese8534bf92005-08-12 20:06:52 +02001468 xsum += sumdata;
1469 }
1470 while ((xsum >> 16) != 0) {
Wolfgang Denkb2f50802005-08-12 23:43:12 +02001471 xsum = (xsum & 0x0000ffff) + ((xsum >> 16) & 0x0000ffff);
Stefan Roese8534bf92005-08-12 20:06:52 +02001472 }
1473 if ((xsum != 0x00000000) && (xsum != 0x0000ffff)) {
Wolfgang Denk9b55a252008-07-11 01:16:00 +02001474 printf(" UDP wrong checksum %08lx %08x\n",
1475 xsum, ntohs(ip->udp_xsum));
Stefan Roese8534bf92005-08-12 20:06:52 +02001476 return;
1477 }
1478 }
1479#endif
1480
David Updegraff53a5c422007-06-11 10:41:07 -05001481
wdenk68ceb292004-08-02 21:11:11 +00001482#ifdef CONFIG_NETCONSOLE
1483 nc_input_packet((uchar *)ip +IP_HDR_SIZE,
1484 ntohs(ip->udp_dst),
1485 ntohs(ip->udp_src),
1486 ntohs(ip->udp_len) - 8);
1487#endif
wdenk2d966952002-10-31 22:12:35 +00001488 /*
1489 * IP header OK. Pass the packet to the current handler.
1490 */
1491 (*packetHandler)((uchar *)ip +IP_HDR_SIZE,
1492 ntohs(ip->udp_dst),
1493 ntohs(ip->udp_src),
1494 ntohs(ip->udp_len) - 8);
wdenk2d966952002-10-31 22:12:35 +00001495 break;
1496 }
1497}
1498
1499
1500/**********************************************************************/
1501
1502static int net_check_prereq (proto_t protocol)
1503{
1504 switch (protocol) {
wdenk6e592382004-04-18 17:39:38 +00001505 /* Fall through */
Jon Loeliger643d1ab2007-07-09 17:45:14 -05001506#if defined(CONFIG_CMD_PING)
wdenk73a8b272003-06-05 19:27:42 +00001507 case PING:
wdenk6e592382004-04-18 17:39:38 +00001508 if (NetPingIP == 0) {
1509 puts ("*** ERROR: ping address not given\n");
1510 return (1);
1511 }
1512 goto common;
wdenk73a8b272003-06-05 19:27:42 +00001513#endif
Jon Loeliger643d1ab2007-07-09 17:45:14 -05001514#if defined(CONFIG_CMD_SNTP)
wdenkea287de2005-04-01 00:25:43 +00001515 case SNTP:
1516 if (NetNtpServerIP == 0) {
1517 puts ("*** ERROR: NTP server address not given\n");
1518 return (1);
1519 }
1520 goto common;
1521#endif
Jon Loeliger643d1ab2007-07-09 17:45:14 -05001522#if defined(CONFIG_CMD_NFS)
wdenkcbd8a352004-02-24 02:00:03 +00001523 case NFS:
1524#endif
wdenk68ceb292004-08-02 21:11:11 +00001525 case NETCONS:
wdenk2d966952002-10-31 22:12:35 +00001526 case TFTP:
wdenk6e592382004-04-18 17:39:38 +00001527 if (NetServerIP == 0) {
1528 puts ("*** ERROR: `serverip' not set\n");
1529 return (1);
1530 }
Jon Loeliger643d1ab2007-07-09 17:45:14 -05001531#if defined(CONFIG_CMD_PING) || defined(CONFIG_CMD_SNTP)
Wolfgang Denkb2f50802005-08-12 23:43:12 +02001532 common:
wdenk73a8b272003-06-05 19:27:42 +00001533#endif
1534
wdenk6e592382004-04-18 17:39:38 +00001535 if (NetOurIP == 0) {
1536 puts ("*** ERROR: `ipaddr' not set\n");
1537 return (1);
1538 }
1539 /* Fall through */
wdenk2d966952002-10-31 22:12:35 +00001540
1541 case DHCP:
1542 case RARP:
1543 case BOOTP:
wdenka3d991b2004-04-15 21:48:45 +00001544 case CDP:
wdenk6e592382004-04-18 17:39:38 +00001545 if (memcmp (NetOurEther, "\0\0\0\0\0\0", 6) == 0) {
wdenk2d966952002-10-31 22:12:35 +00001546#ifdef CONFIG_NET_MULTI
wdenk6e592382004-04-18 17:39:38 +00001547 extern int eth_get_dev_index (void);
1548 int num = eth_get_dev_index ();
wdenk2d966952002-10-31 22:12:35 +00001549
wdenk6e592382004-04-18 17:39:38 +00001550 switch (num) {
1551 case -1:
wdenk2d966952002-10-31 22:12:35 +00001552 puts ("*** ERROR: No ethernet found.\n");
1553 return (1);
wdenk6e592382004-04-18 17:39:38 +00001554 case 0:
wdenk2d966952002-10-31 22:12:35 +00001555 puts ("*** ERROR: `ethaddr' not set\n");
1556 break;
wdenk6e592382004-04-18 17:39:38 +00001557 default:
wdenk8bde7f72003-06-27 21:31:46 +00001558 printf ("*** ERROR: `eth%daddr' not set\n",
wdenk2d966952002-10-31 22:12:35 +00001559 num);
1560 break;
wdenk2d966952002-10-31 22:12:35 +00001561 }
wdenk6e592382004-04-18 17:39:38 +00001562
1563 NetStartAgain ();
1564 return (2);
1565#else
1566 puts ("*** ERROR: `ethaddr' not set\n");
1567 return (1);
1568#endif
1569 }
1570 /* Fall through */
1571 default:
1572 return (0);
wdenk2d966952002-10-31 22:12:35 +00001573 }
wdenk6e592382004-04-18 17:39:38 +00001574 return (0); /* OK */
wdenk2d966952002-10-31 22:12:35 +00001575}
1576/**********************************************************************/
1577
1578int
1579NetCksumOk(uchar * ptr, int len)
1580{
1581 return !((NetCksum(ptr, len) + 1) & 0xfffe);
1582}
1583
1584
1585unsigned
1586NetCksum(uchar * ptr, int len)
1587{
1588 ulong xsum;
Stefan Roese9d2a8732005-08-31 12:55:50 +02001589 ushort *p = (ushort *)ptr;
wdenk2d966952002-10-31 22:12:35 +00001590
1591 xsum = 0;
1592 while (len-- > 0)
Wolfgang Denk7bc5ee02005-08-26 01:36:03 +02001593 xsum += *p++;
wdenk2d966952002-10-31 22:12:35 +00001594 xsum = (xsum & 0xffff) + (xsum >> 16);
1595 xsum = (xsum & 0xffff) + (xsum >> 16);
1596 return (xsum & 0xffff);
1597}
1598
wdenka3d991b2004-04-15 21:48:45 +00001599int
1600NetEthHdrSize(void)
1601{
1602 ushort myvlanid;
wdenk2d966952002-10-31 22:12:35 +00001603
wdenka3d991b2004-04-15 21:48:45 +00001604 myvlanid = ntohs(NetOurVLAN);
1605 if (myvlanid == (ushort)-1)
1606 myvlanid = VLAN_NONE;
1607
1608 return ((myvlanid & VLAN_IDMASK) == VLAN_NONE) ? ETHER_HDR_SIZE : VLAN_ETHER_HDR_SIZE;
1609}
1610
1611int
wdenk2d966952002-10-31 22:12:35 +00001612NetSetEther(volatile uchar * xet, uchar * addr, uint prot)
1613{
1614 Ethernet_t *et = (Ethernet_t *)xet;
wdenka3d991b2004-04-15 21:48:45 +00001615 ushort myvlanid;
1616
1617 myvlanid = ntohs(NetOurVLAN);
1618 if (myvlanid == (ushort)-1)
1619 myvlanid = VLAN_NONE;
wdenk2d966952002-10-31 22:12:35 +00001620
1621 memcpy (et->et_dest, addr, 6);
1622 memcpy (et->et_src, NetOurEther, 6);
wdenka3d991b2004-04-15 21:48:45 +00001623 if ((myvlanid & VLAN_IDMASK) == VLAN_NONE) {
wdenk2d966952002-10-31 22:12:35 +00001624 et->et_protlen = htons(prot);
wdenka3d991b2004-04-15 21:48:45 +00001625 return ETHER_HDR_SIZE;
1626 } else {
1627 VLAN_Ethernet_t *vet = (VLAN_Ethernet_t *)xet;
wdenk2d966952002-10-31 22:12:35 +00001628
wdenka3d991b2004-04-15 21:48:45 +00001629 vet->vet_vlan_type = htons(PROT_VLAN);
1630 vet->vet_tag = htons((0 << 5) | (myvlanid & VLAN_IDMASK));
1631 vet->vet_type = htons(prot);
1632 return VLAN_ETHER_HDR_SIZE;
1633 }
1634}
wdenk2d966952002-10-31 22:12:35 +00001635
1636void
1637NetSetIP(volatile uchar * xip, IPaddr_t dest, int dport, int sport, int len)
1638{
Olav Morkenaf8626e2009-01-23 12:56:26 +01001639 IP_t *ip = (IP_t *)xip;
wdenk2d966952002-10-31 22:12:35 +00001640
1641 /*
1642 * If the data is an odd number of bytes, zero the
1643 * byte after the last byte so that the checksum
1644 * will work.
1645 */
1646 if (len & 1)
1647 xip[IP_HDR_SIZE + len] = 0;
1648
1649 /*
1650 * Construct an IP and UDP header.
wdenk6e592382004-04-18 17:39:38 +00001651 * (need to set no fragment bit - XXX)
wdenk2d966952002-10-31 22:12:35 +00001652 */
1653 ip->ip_hl_v = 0x45; /* IP_HDR_SIZE / 4 (not including UDP) */
1654 ip->ip_tos = 0;
1655 ip->ip_len = htons(IP_HDR_SIZE + len);
1656 ip->ip_id = htons(NetIPID++);
Peter Tysere0c07b82008-12-01 16:26:20 -06001657 ip->ip_off = htons(IP_FLAGS_DFRAG); /* Don't fragment */
wdenk2d966952002-10-31 22:12:35 +00001658 ip->ip_ttl = 255;
1659 ip->ip_p = 17; /* UDP */
1660 ip->ip_sum = 0;
1661 NetCopyIP((void*)&ip->ip_src, &NetOurIP); /* already in network byte order */
1662 NetCopyIP((void*)&ip->ip_dst, &dest); /* - "" - */
1663 ip->udp_src = htons(sport);
1664 ip->udp_dst = htons(dport);
1665 ip->udp_len = htons(8 + len);
1666 ip->udp_xsum = 0;
1667 ip->ip_sum = ~NetCksum((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2);
1668}
1669
Wolfgang Denk77ddac92005-10-13 16:45:02 +02001670void copy_filename (char *dst, char *src, int size)
wdenk2d966952002-10-31 22:12:35 +00001671{
1672 if (*src && (*src == '"')) {
1673 ++src;
1674 --size;
1675 }
1676
1677 while ((--size > 0) && *src && (*src != '"')) {
1678 *dst++ = *src++;
1679 }
1680 *dst = '\0';
1681}
1682
Jon Loeliger610f2e92007-07-10 11:05:02 -05001683#endif
wdenk2d966952002-10-31 22:12:35 +00001684
1685void ip_to_string (IPaddr_t x, char *s)
1686{
wdenka3d991b2004-04-15 21:48:45 +00001687 x = ntohl (x);
1688 sprintf (s, "%d.%d.%d.%d",
1689 (int) ((x >> 24) & 0xff),
1690 (int) ((x >> 16) & 0xff),
1691 (int) ((x >> 8) & 0xff), (int) ((x >> 0) & 0xff)
wdenk6e592382004-04-18 17:39:38 +00001692 );
wdenk2d966952002-10-31 22:12:35 +00001693}
1694
wdenk73a8b272003-06-05 19:27:42 +00001695IPaddr_t string_to_ip(char *s)
wdenk2d966952002-10-31 22:12:35 +00001696{
1697 IPaddr_t addr;
wdenk73a8b272003-06-05 19:27:42 +00001698 char *e;
wdenk2d966952002-10-31 22:12:35 +00001699 int i;
1700
wdenk73a8b272003-06-05 19:27:42 +00001701 if (s == NULL)
1702 return(0);
wdenk2d966952002-10-31 22:12:35 +00001703
1704 for (addr=0, i=0; i<4; ++i) {
1705 ulong val = s ? simple_strtoul(s, &e, 10) : 0;
1706 addr <<= 8;
1707 addr |= (val & 0xFF);
1708 if (s) {
1709 s = (*e) ? e+1 : e;
1710 }
1711 }
1712
1713 return (htonl(addr));
1714}
wdenk73a8b272003-06-05 19:27:42 +00001715
wdenka3d991b2004-04-15 21:48:45 +00001716void VLAN_to_string(ushort x, char *s)
1717{
1718 x = ntohs(x);
1719
1720 if (x == (ushort)-1)
1721 x = VLAN_NONE;
1722
1723 if (x == VLAN_NONE)
1724 strcpy(s, "none");
1725 else
1726 sprintf(s, "%d", x & VLAN_IDMASK);
1727}
1728
1729ushort string_to_VLAN(char *s)
1730{
1731 ushort id;
1732
1733 if (s == NULL)
wdenkb9711de2004-04-25 13:18:40 +00001734 return htons(VLAN_NONE);
wdenka3d991b2004-04-15 21:48:45 +00001735
1736 if (*s < '0' || *s > '9')
1737 id = VLAN_NONE;
1738 else
1739 id = (ushort)simple_strtoul(s, NULL, 10);
1740
wdenkb9711de2004-04-25 13:18:40 +00001741 return htons(id);
wdenka3d991b2004-04-15 21:48:45 +00001742}
1743
wdenk73a8b272003-06-05 19:27:42 +00001744IPaddr_t getenv_IPaddr (char *var)
1745{
1746 return (string_to_ip(getenv(var)));
1747}
wdenka3d991b2004-04-15 21:48:45 +00001748
1749ushort getenv_VLAN(char *var)
1750{
1751 return (string_to_VLAN(getenv(var)));
1752}