1f739fcd8STom Rini // SPDX-License-Identifier: GPL-2.0
22d966958Swdenk /*
32d966958Swdenk * Copied from Linux Monitor (LiMon) - Networking.
42d966958Swdenk *
52d966958Swdenk * Copyright 1994 - 2000 Neil Russell.
62d966958Swdenk * (See License)
72d966958Swdenk * Copyright 2000 Roland Borde
82d966958Swdenk * Copyright 2000 Paolo Scaffardi
92d966958Swdenk * Copyright 2000-2002 Wolfgang Denk, wd@denx.de
102d966958Swdenk */
112d966958Swdenk
122d966958Swdenk /*
132d966958Swdenk * General Desription:
142d966958Swdenk *
152d966958Swdenk * The user interface supports commands for BOOTP, RARP, and TFTP.
162d966958Swdenk * Also, we support ARP internally. Depending on available data,
172d966958Swdenk * these interact as follows:
182d966958Swdenk *
192d966958Swdenk * BOOTP:
202d966958Swdenk *
212d966958Swdenk * Prerequisites: - own ethernet address
222d966958Swdenk * We want: - own IP address
232d966958Swdenk * - TFTP server IP address
242d966958Swdenk * - name of bootfile
252d966958Swdenk * Next step: ARP
262d966958Swdenk *
27d22c338eSJoe Hershberger * LINK_LOCAL:
28d22c338eSJoe Hershberger *
29d22c338eSJoe Hershberger * Prerequisites: - own ethernet address
30d22c338eSJoe Hershberger * We want: - own IP address
31d22c338eSJoe Hershberger * Next step: ARP
32d22c338eSJoe Hershberger *
332d966958Swdenk * RARP:
342d966958Swdenk *
352d966958Swdenk * Prerequisites: - own ethernet address
362d966958Swdenk * We want: - own IP address
372d966958Swdenk * - TFTP server IP address
382d966958Swdenk * Next step: ARP
392d966958Swdenk *
402d966958Swdenk * ARP:
412d966958Swdenk *
422d966958Swdenk * Prerequisites: - own ethernet address
432d966958Swdenk * - own IP address
442d966958Swdenk * - TFTP server IP address
452d966958Swdenk * We want: - TFTP server ethernet address
462d966958Swdenk * Next step: TFTP
472d966958Swdenk *
482d966958Swdenk * DHCP:
492d966958Swdenk *
502d966958Swdenk * Prerequisites: - own ethernet address
512d966958Swdenk * We want: - IP, Netmask, ServerIP, Gateway IP
522d966958Swdenk * - bootfilename, lease time
532d966958Swdenk * Next step: - TFTP
542d966958Swdenk *
552d966958Swdenk * TFTP:
562d966958Swdenk *
572d966958Swdenk * Prerequisites: - own ethernet address
582d966958Swdenk * - own IP address
592d966958Swdenk * - TFTP server IP address
602d966958Swdenk * - TFTP server ethernet address
612d966958Swdenk * - name of bootfile (if unknown, we use a default name
622d966958Swdenk * derived from our own IP address)
632d966958Swdenk * We want: - load the boot file
642d966958Swdenk * Next step: none
65cbd8a35cSwdenk *
66cbd8a35cSwdenk * NFS:
67cbd8a35cSwdenk *
68cbd8a35cSwdenk * Prerequisites: - own ethernet address
69cbd8a35cSwdenk * - own IP address
70cbd8a35cSwdenk * - name of bootfile (if unknown, we use a default name
71cbd8a35cSwdenk * derived from our own IP address)
72cbd8a35cSwdenk * We want: - load the boot file
73cbd8a35cSwdenk * Next step: none
74ea287debSwdenk *
75ea287debSwdenk * SNTP:
76ea287debSwdenk *
77ea287debSwdenk * Prerequisites: - own ethernet address
78ea287debSwdenk * - own IP address
79ea287debSwdenk * We want: - network time
80ea287debSwdenk * Next step: none
81d8970daeSLothar Felten *
82d8970daeSLothar Felten * WOL:
83d8970daeSLothar Felten *
84d8970daeSLothar Felten * Prerequisites: - own ethernet address
85d8970daeSLothar Felten * We want: - magic packet or timeout
86d8970daeSLothar Felten * Next step: none
872d966958Swdenk */
882d966958Swdenk
892d966958Swdenk
902d966958Swdenk #include <common.h>
912d966958Swdenk #include <command.h>
9224b852a7SSimon Glass #include <console.h>
93a9f51c9bSJoe Hershberger #include <environment.h>
9460304592SJoe Hershberger #include <errno.h>
952d966958Swdenk #include <net.h>
96f73a7df9SAlex Kiernan #include <net/fastboot.h>
9734696958SLukasz Majewski #include <net/tftp.h>
989ab23354SDylan Hung #include <net/ncsi.h>
992d8d190cSUri Mashiach #if defined(CONFIG_LED_STATUS)
1004545f4e6SJoe Hershberger #include <miiphy.h>
1014545f4e6SJoe Hershberger #include <status_led.h>
1024545f4e6SJoe Hershberger #endif
1034545f4e6SJoe Hershberger #include <watchdog.h>
1044545f4e6SJoe Hershberger #include <linux/compiler.h>
105d280d3f4SJoe Hershberger #include "arp.h"
1062d966958Swdenk #include "bootp.h"
107f575ae1fSJoe Hershberger #include "cdp.h"
1081a32bf41SRobin Getz #if defined(CONFIG_CMD_DNS)
1091a32bf41SRobin Getz #include "dns.h"
1101a32bf41SRobin Getz #endif
111d22c338eSJoe Hershberger #include "link_local.h"
1124545f4e6SJoe Hershberger #include "nfs.h"
113a36b12f9SJoe Hershberger #include "ping.h"
1144545f4e6SJoe Hershberger #include "rarp.h"
1154545f4e6SJoe Hershberger #if defined(CONFIG_CMD_SNTP)
1164545f4e6SJoe Hershberger #include "sntp.h"
1174545f4e6SJoe Hershberger #endif
118d8970daeSLothar Felten #if defined(CONFIG_CMD_WOL)
119d8970daeSLothar Felten #include "wol.h"
120d8970daeSLothar Felten #endif
1212d966958Swdenk
1222d966958Swdenk /** BOOTP EXTENTIONS **/
1232d966958Swdenk
1243e38e429SLuca Ceresoli /* Our subnet mask (0=unknown) */
125049a95a7SJoe Hershberger struct in_addr net_netmask;
1263e38e429SLuca Ceresoli /* Our gateways IP address */
127049a95a7SJoe Hershberger struct in_addr net_gateway;
1283e38e429SLuca Ceresoli /* Our DNS IP address */
129049a95a7SJoe Hershberger struct in_addr net_dns_server;
1301fe80d79SJon Loeliger #if defined(CONFIG_BOOTP_DNS2)
1313e38e429SLuca Ceresoli /* Our 2nd DNS IP address */
132049a95a7SJoe Hershberger struct in_addr net_dns_server2;
133fe389a82Sstroese #endif
1342d966958Swdenk
1352d966958Swdenk /** END OF BOOTP EXTENTIONS **/
1362d966958Swdenk
1373e38e429SLuca Ceresoli /* Our ethernet address */
1380adb5b76SJoe Hershberger u8 net_ethaddr[6];
1393e38e429SLuca Ceresoli /* Boot server enet address */
1400adb5b76SJoe Hershberger u8 net_server_ethaddr[6];
1413e38e429SLuca Ceresoli /* Our IP addr (0 = unknown) */
142049a95a7SJoe Hershberger struct in_addr net_ip;
1433e38e429SLuca Ceresoli /* Server IP addr (0 = unknown) */
144049a95a7SJoe Hershberger struct in_addr net_server_ip;
1453e38e429SLuca Ceresoli /* Current receive packet */
1461203fcceSJoe Hershberger uchar *net_rx_packet;
1473e38e429SLuca Ceresoli /* Current rx packet length */
1481203fcceSJoe Hershberger int net_rx_packet_len;
1493e38e429SLuca Ceresoli /* IP packet ID */
150bc0571fcSJoe Hershberger static unsigned net_ip_id;
1513e38e429SLuca Ceresoli /* Ethernet bcast address */
1520adb5b76SJoe Hershberger const u8 net_bcast_ethaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1530adb5b76SJoe Hershberger const u8 net_null_ethaddr[6];
1540efe1bcfSAlexander Graf #if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
155db288a96SJoe Hershberger void (*push_packet)(void *, int len) = 0;
156f85b6071SRafal Jaworowski #endif
1573e38e429SLuca Ceresoli /* Network loop state */
15822f6e99dSJoe Hershberger enum net_loop_state net_state;
1593e38e429SLuca Ceresoli /* Tried all network devices */
160bc0571fcSJoe Hershberger int net_restart_wrap;
1613e38e429SLuca Ceresoli /* Network loop restarted */
162bc0571fcSJoe Hershberger static int net_restarted;
1633e38e429SLuca Ceresoli /* At least one device configured */
164bc0571fcSJoe Hershberger static int net_dev_exists;
1652d966958Swdenk
1666e592385Swdenk /* XXX in both little & big endian machines 0xFFFF == ntohs(-1) */
1673e38e429SLuca Ceresoli /* default is without VLAN */
1684fd5055fSJoe Hershberger ushort net_our_vlan = 0xFFFF;
1693e38e429SLuca Ceresoli /* ditto */
1704fd5055fSJoe Hershberger ushort net_native_vlan = 0xFFFF;
171a3d991bdSwdenk
1723e38e429SLuca Ceresoli /* Boot File name */
17311a69ff8SJacob Stiffler char net_boot_file_name[1024];
174449312c1SAlexander Graf /* Indicates whether the file name was specified on the command line */
175449312c1SAlexander Graf bool net_boot_file_name_explicit;
1761411157dSJoe Hershberger /* The actual transferred size of the bootfile (in bytes) */
1771411157dSJoe Hershberger u32 net_boot_file_size;
1781411157dSJoe Hershberger /* Boot file size in blocks as reported by the DHCP server */
1791411157dSJoe Hershberger u32 net_boot_file_expected_size_in_blocks;
1802d966958Swdenk
181643d1ab2SJon Loeliger #if defined(CONFIG_CMD_SNTP)
1823e38e429SLuca Ceresoli /* NTP server IP address */
183049a95a7SJoe Hershberger struct in_addr net_ntp_server;
1843e38e429SLuca Ceresoli /* offset time from UTC */
185bc0571fcSJoe Hershberger int net_ntp_time_offset;
186ea287debSwdenk #endif
187ea287debSwdenk
1881203fcceSJoe Hershberger static uchar net_pkt_buf[(PKTBUFSRX+1) * PKTSIZE_ALIGN + PKTALIGN];
1892a504df0SJoe Hershberger /* Receive packets */
1902a504df0SJoe Hershberger uchar *net_rx_packets[PKTBUFSRX];
191ece223b5SJoe Hershberger /* Current UDP RX packet handler */
192ece223b5SJoe Hershberger static rxhand_f *udp_packet_handler;
193ece223b5SJoe Hershberger /* Current ARP RX packet handler */
194ece223b5SJoe Hershberger static rxhand_f *arp_packet_handler;
19539bccd21SSimon Glass #ifdef CONFIG_CMD_TFTPPUT
196ece223b5SJoe Hershberger /* Current ICMP rx handler */
197ece223b5SJoe Hershberger static rxhand_icmp_f *packet_icmp_handler;
19839bccd21SSimon Glass #endif
1993e38e429SLuca Ceresoli /* Current timeout handler */
200bc0571fcSJoe Hershberger static thand_f *time_handler;
2013e38e429SLuca Ceresoli /* Time base value */
202bc0571fcSJoe Hershberger static ulong time_start;
2033e38e429SLuca Ceresoli /* Current timeout value */
204bc0571fcSJoe Hershberger static ulong time_delta;
2053e38e429SLuca Ceresoli /* THE transmit packet */
2061203fcceSJoe Hershberger uchar *net_tx_packet;
2072d966958Swdenk
208e4bf0c5cSSimon Glass static int net_check_prereq(enum proto_t protocol);
2092d966958Swdenk
210bc0571fcSJoe Hershberger static int net_try_count;
21167b96e87SRemy Bohmer
212b63056d6SJim Lin int __maybe_unused net_busy_flag;
213b63056d6SJim Lin
2142d966958Swdenk /**********************************************************************/
21573a8b27cSwdenk
on_ipaddr(const char * name,const char * value,enum env_op op,int flags)216fd305633SJoe Hershberger static int on_ipaddr(const char *name, const char *value, enum env_op op,
217fd305633SJoe Hershberger int flags)
218fd305633SJoe Hershberger {
219fd305633SJoe Hershberger if (flags & H_PROGRAMMATIC)
220fd305633SJoe Hershberger return 0;
221fd305633SJoe Hershberger
222fd305633SJoe Hershberger net_ip = string_to_ip(value);
223fd305633SJoe Hershberger
224fd305633SJoe Hershberger return 0;
225fd305633SJoe Hershberger }
226fd305633SJoe Hershberger U_BOOT_ENV_CALLBACK(ipaddr, on_ipaddr);
227fd305633SJoe Hershberger
on_gatewayip(const char * name,const char * value,enum env_op op,int flags)228fd305633SJoe Hershberger static int on_gatewayip(const char *name, const char *value, enum env_op op,
229fd305633SJoe Hershberger int flags)
230fd305633SJoe Hershberger {
231fd305633SJoe Hershberger if (flags & H_PROGRAMMATIC)
232fd305633SJoe Hershberger return 0;
233fd305633SJoe Hershberger
234fd305633SJoe Hershberger net_gateway = string_to_ip(value);
235fd305633SJoe Hershberger
236fd305633SJoe Hershberger return 0;
237fd305633SJoe Hershberger }
238fd305633SJoe Hershberger U_BOOT_ENV_CALLBACK(gatewayip, on_gatewayip);
239fd305633SJoe Hershberger
on_netmask(const char * name,const char * value,enum env_op op,int flags)240fd305633SJoe Hershberger static int on_netmask(const char *name, const char *value, enum env_op op,
241fd305633SJoe Hershberger int flags)
242fd305633SJoe Hershberger {
243fd305633SJoe Hershberger if (flags & H_PROGRAMMATIC)
244fd305633SJoe Hershberger return 0;
245fd305633SJoe Hershberger
246fd305633SJoe Hershberger net_netmask = string_to_ip(value);
247fd305633SJoe Hershberger
248fd305633SJoe Hershberger return 0;
249fd305633SJoe Hershberger }
250fd305633SJoe Hershberger U_BOOT_ENV_CALLBACK(netmask, on_netmask);
251fd305633SJoe Hershberger
on_serverip(const char * name,const char * value,enum env_op op,int flags)252fd305633SJoe Hershberger static int on_serverip(const char *name, const char *value, enum env_op op,
253fd305633SJoe Hershberger int flags)
254fd305633SJoe Hershberger {
255fd305633SJoe Hershberger if (flags & H_PROGRAMMATIC)
256fd305633SJoe Hershberger return 0;
257fd305633SJoe Hershberger
258fd305633SJoe Hershberger net_server_ip = string_to_ip(value);
259fd305633SJoe Hershberger
260fd305633SJoe Hershberger return 0;
261fd305633SJoe Hershberger }
262fd305633SJoe Hershberger U_BOOT_ENV_CALLBACK(serverip, on_serverip);
263fd305633SJoe Hershberger
on_nvlan(const char * name,const char * value,enum env_op op,int flags)264fd305633SJoe Hershberger static int on_nvlan(const char *name, const char *value, enum env_op op,
265fd305633SJoe Hershberger int flags)
266fd305633SJoe Hershberger {
267fd305633SJoe Hershberger if (flags & H_PROGRAMMATIC)
268fd305633SJoe Hershberger return 0;
269fd305633SJoe Hershberger
270fd305633SJoe Hershberger net_native_vlan = string_to_vlan(value);
271fd305633SJoe Hershberger
272fd305633SJoe Hershberger return 0;
273fd305633SJoe Hershberger }
274fd305633SJoe Hershberger U_BOOT_ENV_CALLBACK(nvlan, on_nvlan);
275fd305633SJoe Hershberger
on_vlan(const char * name,const char * value,enum env_op op,int flags)276fd305633SJoe Hershberger static int on_vlan(const char *name, const char *value, enum env_op op,
277fd305633SJoe Hershberger int flags)
278fd305633SJoe Hershberger {
279fd305633SJoe Hershberger if (flags & H_PROGRAMMATIC)
280fd305633SJoe Hershberger return 0;
281fd305633SJoe Hershberger
282fd305633SJoe Hershberger net_our_vlan = string_to_vlan(value);
283fd305633SJoe Hershberger
284fd305633SJoe Hershberger return 0;
285fd305633SJoe Hershberger }
286fd305633SJoe Hershberger U_BOOT_ENV_CALLBACK(vlan, on_vlan);
287fd305633SJoe Hershberger
288fd305633SJoe Hershberger #if defined(CONFIG_CMD_DNS)
on_dnsip(const char * name,const char * value,enum env_op op,int flags)289fd305633SJoe Hershberger static int on_dnsip(const char *name, const char *value, enum env_op op,
290fd305633SJoe Hershberger int flags)
291fd305633SJoe Hershberger {
292fd305633SJoe Hershberger if (flags & H_PROGRAMMATIC)
293fd305633SJoe Hershberger return 0;
294fd305633SJoe Hershberger
295fd305633SJoe Hershberger net_dns_server = string_to_ip(value);
296fd305633SJoe Hershberger
297fd305633SJoe Hershberger return 0;
298fd305633SJoe Hershberger }
299fd305633SJoe Hershberger U_BOOT_ENV_CALLBACK(dnsip, on_dnsip);
300fd305633SJoe Hershberger #endif
301fd305633SJoe Hershberger
302e4a3d57dSSimon Glass /*
303e4a3d57dSSimon Glass * Check if autoload is enabled. If so, use either NFS or TFTP to download
304e4a3d57dSSimon Glass * the boot file.
305e4a3d57dSSimon Glass */
net_auto_load(void)306e4a3d57dSSimon Glass void net_auto_load(void)
307e4a3d57dSSimon Glass {
308ec8a252cSJoe Hershberger #if defined(CONFIG_CMD_NFS)
30900caae6dSSimon Glass const char *s = env_get("autoload");
310e4a3d57dSSimon Glass
311ec8a252cSJoe Hershberger if (s != NULL && strcmp(s, "NFS") == 0) {
3123855cad6SJoe Hershberger if (net_check_prereq(NFS)) {
3133855cad6SJoe Hershberger /* We aren't expecting to get a serverip, so just accept the assigned IP */
3143855cad6SJoe Hershberger #ifdef CONFIG_BOOTP_SERVERIP
3153855cad6SJoe Hershberger net_set_state(NETLOOP_SUCCESS);
3163855cad6SJoe Hershberger #else
3173855cad6SJoe Hershberger printf("Cannot autoload with NFS\n");
3183855cad6SJoe Hershberger net_set_state(NETLOOP_FAIL);
3193855cad6SJoe Hershberger #endif
3203855cad6SJoe Hershberger return;
3213855cad6SJoe Hershberger }
322e4a3d57dSSimon Glass /*
323e4a3d57dSSimon Glass * Use NFS to load the bootfile.
324e4a3d57dSSimon Glass */
32568c76a3aSJoe Hershberger nfs_start();
326e4a3d57dSSimon Glass return;
327e4a3d57dSSimon Glass }
328e4a3d57dSSimon Glass #endif
329bfebc8c9SSimon Glass if (env_get_yesno("autoload") == 0) {
330ec8a252cSJoe Hershberger /*
331ec8a252cSJoe Hershberger * Just use BOOTP/RARP to configure system;
332ec8a252cSJoe Hershberger * Do not use TFTP to load the bootfile.
333ec8a252cSJoe Hershberger */
334ec8a252cSJoe Hershberger net_set_state(NETLOOP_SUCCESS);
335ec8a252cSJoe Hershberger return;
336e4a3d57dSSimon Glass }
3373855cad6SJoe Hershberger if (net_check_prereq(TFTPGET)) {
3383855cad6SJoe Hershberger /* We aren't expecting to get a serverip, so just accept the assigned IP */
3393855cad6SJoe Hershberger #ifdef CONFIG_BOOTP_SERVERIP
3403855cad6SJoe Hershberger net_set_state(NETLOOP_SUCCESS);
3413855cad6SJoe Hershberger #else
3423855cad6SJoe Hershberger printf("Cannot autoload with TFTPGET\n");
3433855cad6SJoe Hershberger net_set_state(NETLOOP_FAIL);
3443855cad6SJoe Hershberger #endif
3453855cad6SJoe Hershberger return;
3463855cad6SJoe Hershberger }
3478885c5feSJoe Hershberger tftp_start(TFTPGET);
348e4a3d57dSSimon Glass }
349e4a3d57dSSimon Glass
net_init_loop(void)350bc0571fcSJoe Hershberger static void net_init_loop(void)
3512f70c49eSHeiko Schocher {
3527315cfd9SJim Lin if (eth_get_dev())
3530adb5b76SJoe Hershberger memcpy(net_ethaddr, eth_get_ethaddr(), 6);
3543c172c4fSMichael Zaidman
355da95427cSHeiko Schocher return;
3562f70c49eSHeiko Schocher }
3572f70c49eSHeiko Schocher
net_clear_handlers(void)358ece223b5SJoe Hershberger static void net_clear_handlers(void)
359ece223b5SJoe Hershberger {
360ece223b5SJoe Hershberger net_set_udp_handler(NULL);
361ece223b5SJoe Hershberger net_set_arp_handler(NULL);
362bc0571fcSJoe Hershberger net_set_timeout_handler(0, NULL);
363ece223b5SJoe Hershberger }
364ece223b5SJoe Hershberger
net_cleanup_loop(void)365ece223b5SJoe Hershberger static void net_cleanup_loop(void)
366ece223b5SJoe Hershberger {
367ece223b5SJoe Hershberger net_clear_handlers();
368ece223b5SJoe Hershberger }
369ece223b5SJoe Hershberger
net_init(void)37046c495d5SJoe Hershberger void net_init(void)
37146c495d5SJoe Hershberger {
37246c495d5SJoe Hershberger static int first_call = 1;
37346c495d5SJoe Hershberger
37446c495d5SJoe Hershberger if (first_call) {
37546c495d5SJoe Hershberger /*
37646c495d5SJoe Hershberger * Setup packet buffers, aligned correctly.
37746c495d5SJoe Hershberger */
37846c495d5SJoe Hershberger int i;
37946c495d5SJoe Hershberger
3801203fcceSJoe Hershberger net_tx_packet = &net_pkt_buf[0] + (PKTALIGN - 1);
3811203fcceSJoe Hershberger net_tx_packet -= (ulong)net_tx_packet % PKTALIGN;
3822a504df0SJoe Hershberger for (i = 0; i < PKTBUFSRX; i++) {
3831203fcceSJoe Hershberger net_rx_packets[i] = net_tx_packet +
3841203fcceSJoe Hershberger (i + 1) * PKTSIZE_ALIGN;
3852a504df0SJoe Hershberger }
38685d25e0eSJoe Hershberger arp_init();
38746c495d5SJoe Hershberger net_clear_handlers();
38846c495d5SJoe Hershberger
38946c495d5SJoe Hershberger /* Only need to setup buffer pointers once. */
39046c495d5SJoe Hershberger first_call = 0;
39146c495d5SJoe Hershberger }
39246c495d5SJoe Hershberger
393bc0571fcSJoe Hershberger net_init_loop();
39446c495d5SJoe Hershberger }
39546c495d5SJoe Hershberger
39673a8b27cSwdenk /**********************************************************************/
3972d966958Swdenk /*
3982d966958Swdenk * Main network processing loop.
3992d966958Swdenk */
4002d966958Swdenk
net_loop(enum proto_t protocol)401bc0571fcSJoe Hershberger int net_loop(enum proto_t protocol)
4022d966958Swdenk {
40360304592SJoe Hershberger int ret = -EINVAL;
40460177b26SLeonid Iziumtsev enum net_loop_state prev_net_state = net_state;
4052d966958Swdenk
406bc0571fcSJoe Hershberger net_restarted = 0;
407bc0571fcSJoe Hershberger net_dev_exists = 0;
408bc0571fcSJoe Hershberger net_try_count = 1;
409bc0571fcSJoe Hershberger debug_cond(DEBUG_INT_STATE, "--- net_loop Entry\n");
41073a8b27cSwdenk
4119ab23354SDylan Hung #ifdef CONFIG_PHY_NCSI
412*8731f296SCédric Le Goater if (phy_interface_is_ncsi() && protocol != NCSI && !ncsi_active()) {
413459611b1SJoel Stanley printf("Configuring NCSI\n");
4149ab23354SDylan Hung if (net_loop(NCSI) < 0)
4159ab23354SDylan Hung return ret;
4169ab23354SDylan Hung eth_init_state_only();
4179ab23354SDylan Hung goto restart;
4189ab23354SDylan Hung }
4199ab23354SDylan Hung #endif
4209ab23354SDylan Hung
421573f14feSSimon Glass bootstage_mark_name(BOOTSTAGE_ID_ETH_START, "eth_start");
42246c495d5SJoe Hershberger net_init();
423f8be7d65SJoe Hershberger if (eth_is_on_demand_init() || protocol != NETCONS) {
4242d966958Swdenk eth_halt();
425a3d991bdSwdenk eth_set_current();
42660304592SJoe Hershberger ret = eth_init();
42760304592SJoe Hershberger if (ret < 0) {
428b1bf6f2cSwdenk eth_halt();
42960304592SJoe Hershberger return ret;
430b1bf6f2cSwdenk }
431bc0571fcSJoe Hershberger } else {
432d2eaec60SJoe Hershberger eth_init_state_only();
433bc0571fcSJoe Hershberger }
4349ab23354SDylan Hung
4352d966958Swdenk restart:
436b63056d6SJim Lin #ifdef CONFIG_USB_KEYBOARD
437b63056d6SJim Lin net_busy_flag = 0;
438b63056d6SJim Lin #endif
43922f6e99dSJoe Hershberger net_set_state(NETLOOP_CONTINUE);
4402d966958Swdenk
4412d966958Swdenk /*
4422d966958Swdenk * Start the ball rolling with the given start function. From
4432d966958Swdenk * here on, this code is a state machine driven by received
4442d966958Swdenk * packets and timer events.
4452d966958Swdenk */
446bc0571fcSJoe Hershberger debug_cond(DEBUG_INT_STATE, "--- net_loop Init\n");
447bc0571fcSJoe Hershberger net_init_loop();
4482d966958Swdenk
4492d966958Swdenk switch (net_check_prereq(protocol)) {
4502d966958Swdenk case 1:
4512d966958Swdenk /* network not configured */
452b1bf6f2cSwdenk eth_halt();
45360177b26SLeonid Iziumtsev net_set_state(prev_net_state);
45460304592SJoe Hershberger return -ENODEV;
4552d966958Swdenk
4562d966958Swdenk case 2:
4572d966958Swdenk /* network device not configured */
4582d966958Swdenk break;
4592d966958Swdenk
4602d966958Swdenk case 0:
461bc0571fcSJoe Hershberger net_dev_exists = 1;
4621411157dSJoe Hershberger net_boot_file_size = 0;
4632d966958Swdenk switch (protocol) {
464e4bf0c5cSSimon Glass case TFTPGET:
4651fb7cd49SSimon Glass #ifdef CONFIG_CMD_TFTPPUT
4661fb7cd49SSimon Glass case TFTPPUT:
4671fb7cd49SSimon Glass #endif
4682d966958Swdenk /* always use ARP to get server ethernet address */
4698885c5feSJoe Hershberger tftp_start(protocol);
4702d966958Swdenk break;
4717a83af07SLuca Ceresoli #ifdef CONFIG_CMD_TFTPSRV
4727a83af07SLuca Ceresoli case TFTPSRV:
4738885c5feSJoe Hershberger tftp_start_server();
4747a83af07SLuca Ceresoli break;
4757a83af07SLuca Ceresoli #endif
476f73a7df9SAlex Kiernan #ifdef CONFIG_UDP_FUNCTION_FASTBOOT
477f73a7df9SAlex Kiernan case FASTBOOT:
478f73a7df9SAlex Kiernan fastboot_start_server();
479f73a7df9SAlex Kiernan break;
480f73a7df9SAlex Kiernan #endif
481643d1ab2SJon Loeliger #if defined(CONFIG_CMD_DHCP)
4822d966958Swdenk case DHCP:
4837044c6bbSJoe Hershberger bootp_reset();
484049a95a7SJoe Hershberger net_ip.s_addr = 0;
4857044c6bbSJoe Hershberger dhcp_request(); /* Basically same as BOOTP */
4862d966958Swdenk break;
487610f2e9cSJon Loeliger #endif
4882d966958Swdenk
4892d966958Swdenk case BOOTP:
4907044c6bbSJoe Hershberger bootp_reset();
491049a95a7SJoe Hershberger net_ip.s_addr = 0;
4927044c6bbSJoe Hershberger bootp_request();
4932d966958Swdenk break;
4942d966958Swdenk
495bf6cb247SPeter Tyser #if defined(CONFIG_CMD_RARP)
4962d966958Swdenk case RARP:
497698d78e5SJoe Hershberger rarp_try = 0;
498049a95a7SJoe Hershberger net_ip.s_addr = 0;
499698d78e5SJoe Hershberger rarp_request();
5002d966958Swdenk break;
501bf6cb247SPeter Tyser #endif
502643d1ab2SJon Loeliger #if defined(CONFIG_CMD_PING)
50373a8b27cSwdenk case PING:
504a36b12f9SJoe Hershberger ping_start();
50573a8b27cSwdenk break;
50673a8b27cSwdenk #endif
507643d1ab2SJon Loeliger #if defined(CONFIG_CMD_NFS)
508cbd8a35cSwdenk case NFS:
50968c76a3aSJoe Hershberger nfs_start();
510cbd8a35cSwdenk break;
511cbd8a35cSwdenk #endif
512643d1ab2SJon Loeliger #if defined(CONFIG_CMD_CDP)
513a3d991bdSwdenk case CDP:
5146aede5b7SJoe Hershberger cdp_start();
515a3d991bdSwdenk break;
516a3d991bdSwdenk #endif
51766c89ee3SHolger Dengler #if defined(CONFIG_NETCONSOLE) && !defined(CONFIG_SPL_BUILD)
51868ceb29eSwdenk case NETCONS:
5196a38a5f3SJoe Hershberger nc_start();
52068ceb29eSwdenk break;
52168ceb29eSwdenk #endif
522643d1ab2SJon Loeliger #if defined(CONFIG_CMD_SNTP)
523ea287debSwdenk case SNTP:
52438ba2558SJoe Hershberger sntp_start();
525ea287debSwdenk break;
526ea287debSwdenk #endif
5271a32bf41SRobin Getz #if defined(CONFIG_CMD_DNS)
5281a32bf41SRobin Getz case DNS:
529786eac5fSJoe Hershberger dns_start();
5301a32bf41SRobin Getz break;
5311a32bf41SRobin Getz #endif
532d22c338eSJoe Hershberger #if defined(CONFIG_CMD_LINK_LOCAL)
533d22c338eSJoe Hershberger case LINKLOCAL:
534d22c338eSJoe Hershberger link_local_start();
535d22c338eSJoe Hershberger break;
536d22c338eSJoe Hershberger #endif
537d8970daeSLothar Felten #if defined(CONFIG_CMD_WOL)
538d8970daeSLothar Felten case WOL:
539d8970daeSLothar Felten wol_start();
540d8970daeSLothar Felten break;
541d8970daeSLothar Felten #endif
5429ab23354SDylan Hung #if defined(CONFIG_CMD_NCSI)
5439ab23354SDylan Hung case NCSI:
5449ab23354SDylan Hung ncsi_probe_packages();
5459ab23354SDylan Hung break;
5469ab23354SDylan Hung #endif
5472d966958Swdenk default:
5482d966958Swdenk break;
5492d966958Swdenk }
5502d966958Swdenk
5512d966958Swdenk break;
5522d966958Swdenk }
5532d966958Swdenk
554643d1ab2SJon Loeliger #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
5553e38e429SLuca Ceresoli #if defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN) && \
5562d8d190cSUri Mashiach defined(CONFIG_LED_STATUS) && \
5572d8d190cSUri Mashiach defined(CONFIG_LED_STATUS_RED)
558fc3e2165Swdenk /*
559fc3e2165Swdenk * Echo the inverted link state to the fault LED.
560fc3e2165Swdenk */
561d3c65b01SLuca Ceresoli if (miiphy_link(eth_get_dev()->name, CONFIG_SYS_FAULT_MII_ADDR))
5622d8d190cSUri Mashiach status_led_set(CONFIG_LED_STATUS_RED, CONFIG_LED_STATUS_OFF);
563d3c65b01SLuca Ceresoli else
5642d8d190cSUri Mashiach status_led_set(CONFIG_LED_STATUS_RED, CONFIG_LED_STATUS_ON);
5656d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #endif /* CONFIG_SYS_FAULT_ECHO_LINK_DOWN, ... */
566fc3e2165Swdenk #endif /* CONFIG_MII, ... */
567b63056d6SJim Lin #ifdef CONFIG_USB_KEYBOARD
568b63056d6SJim Lin net_busy_flag = 1;
569b63056d6SJim Lin #endif
5702d966958Swdenk
5712d966958Swdenk /*
5722d966958Swdenk * Main packet reception loop. Loop receiving packets until
57322f6e99dSJoe Hershberger * someone sets `net_state' to a state that terminates.
5742d966958Swdenk */
5752d966958Swdenk for (;;) {
5762d966958Swdenk WATCHDOG_RESET();
5772d966958Swdenk #ifdef CONFIG_SHOW_ACTIVITY
5782d966958Swdenk show_activity(1);
5792d966958Swdenk #endif
580c5a75339SJoe Hershberger if (arp_timeout_check() > 0)
581c5a75339SJoe Hershberger time_start = get_timer(0);
582c5a75339SJoe Hershberger
5832d966958Swdenk /*
5842d966958Swdenk * Check the ethernet for a new packet. The ethernet
5852d966958Swdenk * receive routine will process it.
58660304592SJoe Hershberger * Most drivers return the most recent packet size, but not
58760304592SJoe Hershberger * errors that may have happened.
5882d966958Swdenk */
5892d966958Swdenk eth_rx();
5902d966958Swdenk
5912d966958Swdenk /*
5922d966958Swdenk * Abort if ctrl-c was pressed.
5932d966958Swdenk */
5942d966958Swdenk if (ctrlc()) {
595e94070c4SJoe Hershberger /* cancel any ARP that may not have completed */
596049a95a7SJoe Hershberger net_arp_wait_packet_ip.s_addr = 0;
597e94070c4SJoe Hershberger
598ece223b5SJoe Hershberger net_cleanup_loop();
5992d966958Swdenk eth_halt();
600f8be7d65SJoe Hershberger /* Invalidate the last protocol */
601f8be7d65SJoe Hershberger eth_set_last_protocol(BOOTP);
602f8be7d65SJoe Hershberger
6034b9206edSwdenk puts("\nAbort\n");
6044ef8d53cSJoe Hershberger /* include a debug print as well incase the debug
6054ef8d53cSJoe Hershberger messages are directed to stderr */
606bc0571fcSJoe Hershberger debug_cond(DEBUG_INT_STATE, "--- net_loop Abort!\n");
60719a4fbaaSMichal Simek ret = -EINTR;
6084793ee65SSimon Glass goto done;
6092d966958Swdenk }
6102d966958Swdenk
6112d966958Swdenk /*
6122d966958Swdenk * Check for a timeout, and run the timeout handler
6132d966958Swdenk * if we have one.
6142d966958Swdenk */
615bc0571fcSJoe Hershberger if (time_handler &&
616bc0571fcSJoe Hershberger ((get_timer(0) - time_start) > time_delta)) {
6172d966958Swdenk thand_f *x;
6182d966958Swdenk
619643d1ab2SJon Loeliger #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
6206d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN) && \
6212d8d190cSUri Mashiach defined(CONFIG_LED_STATUS) && \
6222d8d190cSUri Mashiach defined(CONFIG_LED_STATUS_RED)
623fc3e2165Swdenk /*
624fc3e2165Swdenk * Echo the inverted link state to the fault LED.
625fc3e2165Swdenk */
6263e38e429SLuca Ceresoli if (miiphy_link(eth_get_dev()->name,
627bc0571fcSJoe Hershberger CONFIG_SYS_FAULT_MII_ADDR))
6282d8d190cSUri Mashiach status_led_set(CONFIG_LED_STATUS_RED,
6292d8d190cSUri Mashiach CONFIG_LED_STATUS_OFF);
630bc0571fcSJoe Hershberger else
6312d8d190cSUri Mashiach status_led_set(CONFIG_LED_STATUS_RED,
6322d8d190cSUri Mashiach CONFIG_LED_STATUS_ON);
6336d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #endif /* CONFIG_SYS_FAULT_ECHO_LINK_DOWN, ... */
634fc3e2165Swdenk #endif /* CONFIG_MII, ... */
635bc0571fcSJoe Hershberger debug_cond(DEBUG_INT_STATE, "--- net_loop timeout\n");
636bc0571fcSJoe Hershberger x = time_handler;
637bc0571fcSJoe Hershberger time_handler = (thand_f *)0;
6382d966958Swdenk (*x)();
6392d966958Swdenk }
6402d966958Swdenk
6415c421331SJoe Hershberger if (net_state == NETLOOP_FAIL)
642bc0571fcSJoe Hershberger ret = net_start_again();
6432d966958Swdenk
64422f6e99dSJoe Hershberger switch (net_state) {
6452d966958Swdenk case NETLOOP_RESTART:
646bc0571fcSJoe Hershberger net_restarted = 1;
6472d966958Swdenk goto restart;
6482d966958Swdenk
6492d966958Swdenk case NETLOOP_SUCCESS:
650ece223b5SJoe Hershberger net_cleanup_loop();
6511411157dSJoe Hershberger if (net_boot_file_size > 0) {
6521411157dSJoe Hershberger printf("Bytes transferred = %d (%x hex)\n",
6531411157dSJoe Hershberger net_boot_file_size, net_boot_file_size);
654018f5303SSimon Glass env_set_hex("filesize", net_boot_file_size);
655018f5303SSimon Glass env_set_hex("fileaddr", load_addr);
6562d966958Swdenk }
6579ab23354SDylan Hung if (protocol != NETCONS && protocol != NCSI)
6582d966958Swdenk eth_halt();
659f8be7d65SJoe Hershberger else
660f8be7d65SJoe Hershberger eth_halt_state_only();
661f8be7d65SJoe Hershberger
662f8be7d65SJoe Hershberger eth_set_last_protocol(protocol);
663f8be7d65SJoe Hershberger
6641411157dSJoe Hershberger ret = net_boot_file_size;
665bc0571fcSJoe Hershberger debug_cond(DEBUG_INT_STATE, "--- net_loop Success!\n");
6664793ee65SSimon Glass goto done;
6672d966958Swdenk
6682d966958Swdenk case NETLOOP_FAIL:
669ece223b5SJoe Hershberger net_cleanup_loop();
670f8be7d65SJoe Hershberger /* Invalidate the last protocol */
671f8be7d65SJoe Hershberger eth_set_last_protocol(BOOTP);
672bc0571fcSJoe Hershberger debug_cond(DEBUG_INT_STATE, "--- net_loop Fail!\n");
673a735e6e9SThomas RIENOESSL ret = -ENONET;
6744793ee65SSimon Glass goto done;
67522f6e99dSJoe Hershberger
67622f6e99dSJoe Hershberger case NETLOOP_CONTINUE:
67722f6e99dSJoe Hershberger continue;
6782d966958Swdenk }
6792d966958Swdenk }
6804793ee65SSimon Glass
6814793ee65SSimon Glass done:
682b63056d6SJim Lin #ifdef CONFIG_USB_KEYBOARD
683b63056d6SJim Lin net_busy_flag = 0;
684b63056d6SJim Lin #endif
68539bccd21SSimon Glass #ifdef CONFIG_CMD_TFTPPUT
6864793ee65SSimon Glass /* Clear out the handlers */
687ece223b5SJoe Hershberger net_set_udp_handler(NULL);
6884793ee65SSimon Glass net_set_icmp_handler(NULL);
68939bccd21SSimon Glass #endif
69060177b26SLeonid Iziumtsev net_set_state(prev_net_state);
6914793ee65SSimon Glass return ret;
6922d966958Swdenk }
6932d966958Swdenk
6942d966958Swdenk /**********************************************************************/
6952d966958Swdenk
start_again_timeout_handler(void)696bc0571fcSJoe Hershberger static void start_again_timeout_handler(void)
6972d966958Swdenk {
69822f6e99dSJoe Hershberger net_set_state(NETLOOP_RESTART);
6992d966958Swdenk }
7002d966958Swdenk
net_start_again(void)701bc0571fcSJoe Hershberger int net_start_again(void)
7022d966958Swdenk {
7036e592385Swdenk char *nretry;
70467b96e87SRemy Bohmer int retry_forever = 0;
70567b96e87SRemy Bohmer unsigned long retrycnt = 0;
70660304592SJoe Hershberger int ret;
707a3d991bdSwdenk
70800caae6dSSimon Glass nretry = env_get("netretry");
70967b96e87SRemy Bohmer if (nretry) {
71067b96e87SRemy Bohmer if (!strcmp(nretry, "yes"))
71167b96e87SRemy Bohmer retry_forever = 1;
71267b96e87SRemy Bohmer else if (!strcmp(nretry, "no"))
71367b96e87SRemy Bohmer retrycnt = 0;
71467b96e87SRemy Bohmer else if (!strcmp(nretry, "once"))
71567b96e87SRemy Bohmer retrycnt = 1;
71667b96e87SRemy Bohmer else
71767b96e87SRemy Bohmer retrycnt = simple_strtoul(nretry, NULL, 0);
7185c421331SJoe Hershberger } else {
7195c421331SJoe Hershberger retrycnt = 0;
7205c421331SJoe Hershberger retry_forever = 0;
7215c421331SJoe Hershberger }
72267b96e87SRemy Bohmer
72317d413b2SLeonid Iziumtsev if ((!retry_forever) && (net_try_count > retrycnt)) {
724a3d991bdSwdenk eth_halt();
72522f6e99dSJoe Hershberger net_set_state(NETLOOP_FAIL);
72660304592SJoe Hershberger /*
72760304592SJoe Hershberger * We don't provide a way for the protocol to return an error,
72860304592SJoe Hershberger * but this is almost always the reason.
72960304592SJoe Hershberger */
73060304592SJoe Hershberger return -ETIMEDOUT;
731a3d991bdSwdenk }
73267b96e87SRemy Bohmer
733bc0571fcSJoe Hershberger net_try_count++;
73467b96e87SRemy Bohmer
7352d966958Swdenk eth_halt();
7368b0c5c12SMatthias Fuchs #if !defined(CONFIG_NET_DO_NOT_TRY_ANOTHER)
737bc0571fcSJoe Hershberger eth_try_another(!net_restarted);
7388b0c5c12SMatthias Fuchs #endif
73960304592SJoe Hershberger ret = eth_init();
740bc0571fcSJoe Hershberger if (net_restart_wrap) {
741bc0571fcSJoe Hershberger net_restart_wrap = 0;
742bc0571fcSJoe Hershberger if (net_dev_exists) {
743bc0571fcSJoe Hershberger net_set_timeout_handler(10000UL,
744bc0571fcSJoe Hershberger start_again_timeout_handler);
745ece223b5SJoe Hershberger net_set_udp_handler(NULL);
7466e592385Swdenk } else {
74722f6e99dSJoe Hershberger net_set_state(NETLOOP_FAIL);
7482d966958Swdenk }
7496e592385Swdenk } else {
75022f6e99dSJoe Hershberger net_set_state(NETLOOP_RESTART);
7512d966958Swdenk }
75260304592SJoe Hershberger return ret;
7532d966958Swdenk }
7542d966958Swdenk
7552d966958Swdenk /**********************************************************************/
7562d966958Swdenk /*
7572d966958Swdenk * Miscelaneous bits.
7582d966958Swdenk */
7592d966958Swdenk
dummy_handler(uchar * pkt,unsigned dport,struct in_addr sip,unsigned sport,unsigned len)760ece223b5SJoe Hershberger static void dummy_handler(uchar *pkt, unsigned dport,
761049a95a7SJoe Hershberger struct in_addr sip, unsigned sport,
762ece223b5SJoe Hershberger unsigned len)
763d280d3f4SJoe Hershberger {
764d280d3f4SJoe Hershberger }
765d280d3f4SJoe Hershberger
net_get_udp_handler(void)766ece223b5SJoe Hershberger rxhand_f *net_get_udp_handler(void)
7672d966958Swdenk {
768ece223b5SJoe Hershberger return udp_packet_handler;
769ece223b5SJoe Hershberger }
770ece223b5SJoe Hershberger
net_set_udp_handler(rxhand_f * f)771ece223b5SJoe Hershberger void net_set_udp_handler(rxhand_f *f)
772ece223b5SJoe Hershberger {
773bc0571fcSJoe Hershberger debug_cond(DEBUG_INT_STATE, "--- net_loop UDP handler set (%p)\n", f);
774ece223b5SJoe Hershberger if (f == NULL)
775ece223b5SJoe Hershberger udp_packet_handler = dummy_handler;
776ece223b5SJoe Hershberger else
777ece223b5SJoe Hershberger udp_packet_handler = f;
778ece223b5SJoe Hershberger }
779ece223b5SJoe Hershberger
net_get_arp_handler(void)780ece223b5SJoe Hershberger rxhand_f *net_get_arp_handler(void)
781ece223b5SJoe Hershberger {
782ece223b5SJoe Hershberger return arp_packet_handler;
783ece223b5SJoe Hershberger }
784ece223b5SJoe Hershberger
net_set_arp_handler(rxhand_f * f)785ece223b5SJoe Hershberger void net_set_arp_handler(rxhand_f *f)
786ece223b5SJoe Hershberger {
787bc0571fcSJoe Hershberger debug_cond(DEBUG_INT_STATE, "--- net_loop ARP handler set (%p)\n", f);
788ece223b5SJoe Hershberger if (f == NULL)
789ece223b5SJoe Hershberger arp_packet_handler = dummy_handler;
790ece223b5SJoe Hershberger else
791ece223b5SJoe Hershberger arp_packet_handler = f;
7922d966958Swdenk }
7932d966958Swdenk
79439bccd21SSimon Glass #ifdef CONFIG_CMD_TFTPPUT
net_set_icmp_handler(rxhand_icmp_f * f)7954793ee65SSimon Glass void net_set_icmp_handler(rxhand_icmp_f *f)
7964793ee65SSimon Glass {
7974793ee65SSimon Glass packet_icmp_handler = f;
7984793ee65SSimon Glass }
79939bccd21SSimon Glass #endif
8002d966958Swdenk
net_set_timeout_handler(ulong iv,thand_f * f)801bc0571fcSJoe Hershberger void net_set_timeout_handler(ulong iv, thand_f *f)
8022d966958Swdenk {
8032d966958Swdenk if (iv == 0) {
8044ef8d53cSJoe Hershberger debug_cond(DEBUG_INT_STATE,
805bc0571fcSJoe Hershberger "--- net_loop timeout handler cancelled\n");
806bc0571fcSJoe Hershberger time_handler = (thand_f *)0;
8072d966958Swdenk } else {
8084ef8d53cSJoe Hershberger debug_cond(DEBUG_INT_STATE,
809bc0571fcSJoe Hershberger "--- net_loop timeout handler set (%p)\n", f);
810bc0571fcSJoe Hershberger time_handler = f;
811bc0571fcSJoe Hershberger time_start = get_timer(0);
812bc0571fcSJoe Hershberger time_delta = iv * CONFIG_SYS_HZ / 1000;
8132d966958Swdenk }
8142d966958Swdenk }
8152d966958Swdenk
net_get_async_tx_pkt_buf(void)816ac3f26ccSJoe Hershberger uchar *net_get_async_tx_pkt_buf(void)
817ac3f26ccSJoe Hershberger {
818ac3f26ccSJoe Hershberger if (arp_is_waiting())
819ac3f26ccSJoe Hershberger return arp_tx_packet; /* If we are waiting, we already sent */
820ac3f26ccSJoe Hershberger else
821ac3f26ccSJoe Hershberger return net_tx_packet;
822ac3f26ccSJoe Hershberger }
823ac3f26ccSJoe Hershberger
net_send_udp_packet(uchar * ether,struct in_addr dest,int dport,int sport,int payload_len)8241203fcceSJoe Hershberger int net_send_udp_packet(uchar *ether, struct in_addr dest, int dport, int sport,
825206d07fdSJoe Hershberger int payload_len)
82673a8b27cSwdenk {
8275d457ecbSDuncan Hare return net_send_ip_packet(ether, dest, dport, sport, payload_len,
8285d457ecbSDuncan Hare IPPROTO_UDP, 0, 0, 0);
8295d457ecbSDuncan Hare }
8305d457ecbSDuncan Hare
net_send_ip_packet(uchar * ether,struct in_addr dest,int dport,int sport,int payload_len,int proto,u8 action,u32 tcp_seq_num,u32 tcp_ack_num)8315d457ecbSDuncan Hare int net_send_ip_packet(uchar *ether, struct in_addr dest, int dport, int sport,
8325d457ecbSDuncan Hare int payload_len, int proto, u8 action, u32 tcp_seq_num,
8335d457ecbSDuncan Hare u32 tcp_ack_num)
8345d457ecbSDuncan Hare {
835a3d991bdSwdenk uchar *pkt;
8369214637aSJoe Hershberger int eth_hdr_size;
8379214637aSJoe Hershberger int pkt_hdr_size;
838a3d991bdSwdenk
839bc0571fcSJoe Hershberger /* make sure the net_tx_packet is initialized (net_init() was called) */
8401203fcceSJoe Hershberger assert(net_tx_packet != NULL);
8411203fcceSJoe Hershberger if (net_tx_packet == NULL)
84246c495d5SJoe Hershberger return -1;
84346c495d5SJoe Hershberger
84473a8b27cSwdenk /* convert to new style broadcast */
845049a95a7SJoe Hershberger if (dest.s_addr == 0)
846049a95a7SJoe Hershberger dest.s_addr = 0xFFFFFFFF;
8472d966958Swdenk
84873a8b27cSwdenk /* if broadcast, make the ether address a broadcast and don't do ARP */
849049a95a7SJoe Hershberger if (dest.s_addr == 0xFFFFFFFF)
8500adb5b76SJoe Hershberger ether = (uchar *)net_bcast_ethaddr;
85173a8b27cSwdenk
8521203fcceSJoe Hershberger pkt = (uchar *)net_tx_packet;
85373a8b27cSwdenk
8541203fcceSJoe Hershberger eth_hdr_size = net_set_ether(pkt, ether, PROT_IP);
8555d457ecbSDuncan Hare
8565d457ecbSDuncan Hare switch (proto) {
8575d457ecbSDuncan Hare case IPPROTO_UDP:
8585d457ecbSDuncan Hare net_set_udp_header(pkt + eth_hdr_size, dest, dport, sport,
8595d457ecbSDuncan Hare payload_len);
8609214637aSJoe Hershberger pkt_hdr_size = eth_hdr_size + IP_UDP_HDR_SIZE;
8615d457ecbSDuncan Hare break;
8625d457ecbSDuncan Hare default:
8635d457ecbSDuncan Hare return -EINVAL;
8645d457ecbSDuncan Hare }
8650ebf04c6SRobin Getz
866e94070c4SJoe Hershberger /* if MAC address was not discovered yet, do an ARP request */
8670adb5b76SJoe Hershberger if (memcmp(ether, net_null_ethaddr, 6) == 0) {
8684ef8d53cSJoe Hershberger debug_cond(DEBUG_DEV_PKT, "sending ARP for %pI4\n", &dest);
8699214637aSJoe Hershberger
8709214637aSJoe Hershberger /* save the ip and eth addr for the packet to send after arp */
871049a95a7SJoe Hershberger net_arp_wait_packet_ip = dest;
87285d25e0eSJoe Hershberger arp_wait_packet_ethaddr = ether;
873a3d991bdSwdenk
87473a8b27cSwdenk /* size of the waiting packet */
87585d25e0eSJoe Hershberger arp_wait_tx_packet_size = pkt_hdr_size + payload_len;
87673a8b27cSwdenk
87773a8b27cSwdenk /* and do the ARP request */
87885d25e0eSJoe Hershberger arp_wait_try = 1;
87985d25e0eSJoe Hershberger arp_wait_timer_start = get_timer(0);
88085d25e0eSJoe Hershberger arp_request();
88173a8b27cSwdenk return 1; /* waiting */
8829214637aSJoe Hershberger } else {
8834ef8d53cSJoe Hershberger debug_cond(DEBUG_DEV_PKT, "sending UDP to %pI4/%pM\n",
8844ef8d53cSJoe Hershberger &dest, ether);
8851203fcceSJoe Hershberger net_send_packet(net_tx_packet, pkt_hdr_size + payload_len);
8866e592385Swdenk return 0; /* transmitted */
88773a8b27cSwdenk }
8889214637aSJoe Hershberger }
88973a8b27cSwdenk
8905cfaa4e5SAlessandro Rubini #ifdef CONFIG_IP_DEFRAG
8915cfaa4e5SAlessandro Rubini /*
8925cfaa4e5SAlessandro Rubini * This function collects fragments in a single packet, according
8935cfaa4e5SAlessandro Rubini * to the algorithm in RFC815. It returns NULL or the pointer to
8945cfaa4e5SAlessandro Rubini * a complete packet, in static storage
8955cfaa4e5SAlessandro Rubini */
8965cfaa4e5SAlessandro Rubini #ifndef CONFIG_NET_MAXDEFRAG
8975cfaa4e5SAlessandro Rubini #define CONFIG_NET_MAXDEFRAG 16384
8985cfaa4e5SAlessandro Rubini #endif
899aa7a6487SJoe Hershberger #define IP_PKTSIZE (CONFIG_NET_MAXDEFRAG)
9005cfaa4e5SAlessandro Rubini
901c5c59df0SJoe Hershberger #define IP_MAXUDP (IP_PKTSIZE - IP_HDR_SIZE)
9025cfaa4e5SAlessandro Rubini
9035cfaa4e5SAlessandro Rubini /*
9045cfaa4e5SAlessandro Rubini * this is the packet being assembled, either data or frag control.
9055cfaa4e5SAlessandro Rubini * Fragments go by 8 bytes, so this union must be 8 bytes long
9065cfaa4e5SAlessandro Rubini */
9075cfaa4e5SAlessandro Rubini struct hole {
9085cfaa4e5SAlessandro Rubini /* first_byte is address of this structure */
9095cfaa4e5SAlessandro Rubini u16 last_byte; /* last byte in this hole + 1 (begin of next hole) */
9105cfaa4e5SAlessandro Rubini u16 next_hole; /* index of next (in 8-b blocks), 0 == none */
9115cfaa4e5SAlessandro Rubini u16 prev_hole; /* index of prev, 0 == none */
9125cfaa4e5SAlessandro Rubini u16 unused;
9135cfaa4e5SAlessandro Rubini };
9145cfaa4e5SAlessandro Rubini
__net_defragment(struct ip_udp_hdr * ip,int * lenp)915bc0571fcSJoe Hershberger static struct ip_udp_hdr *__net_defragment(struct ip_udp_hdr *ip, int *lenp)
9165cfaa4e5SAlessandro Rubini {
91748522bb5SJoe Hershberger static uchar pkt_buff[IP_PKTSIZE] __aligned(PKTALIGN);
9185cfaa4e5SAlessandro Rubini static u16 first_hole, total_len;
9195cfaa4e5SAlessandro Rubini struct hole *payload, *thisfrag, *h, *newh;
920594c26f8SJoe Hershberger struct ip_udp_hdr *localip = (struct ip_udp_hdr *)pkt_buff;
9215cfaa4e5SAlessandro Rubini uchar *indata = (uchar *)ip;
9225cfaa4e5SAlessandro Rubini int offset8, start, len, done = 0;
9235cfaa4e5SAlessandro Rubini u16 ip_off = ntohs(ip->ip_off);
9245cfaa4e5SAlessandro Rubini
9255cfaa4e5SAlessandro Rubini /* payload starts after IP header, this fragment is in there */
926c5c59df0SJoe Hershberger payload = (struct hole *)(pkt_buff + IP_HDR_SIZE);
9275cfaa4e5SAlessandro Rubini offset8 = (ip_off & IP_OFFS);
9285cfaa4e5SAlessandro Rubini thisfrag = payload + offset8;
9295cfaa4e5SAlessandro Rubini start = offset8 * 8;
930c5c59df0SJoe Hershberger len = ntohs(ip->ip_len) - IP_HDR_SIZE;
9315cfaa4e5SAlessandro Rubini
9325cfaa4e5SAlessandro Rubini if (start + len > IP_MAXUDP) /* fragment extends too far */
9335cfaa4e5SAlessandro Rubini return NULL;
9345cfaa4e5SAlessandro Rubini
9355cfaa4e5SAlessandro Rubini if (!total_len || localip->ip_id != ip->ip_id) {
9365cfaa4e5SAlessandro Rubini /* new (or different) packet, reset structs */
9375cfaa4e5SAlessandro Rubini total_len = 0xffff;
9385cfaa4e5SAlessandro Rubini payload[0].last_byte = ~0;
9395cfaa4e5SAlessandro Rubini payload[0].next_hole = 0;
9405cfaa4e5SAlessandro Rubini payload[0].prev_hole = 0;
9415cfaa4e5SAlessandro Rubini first_hole = 0;
9425cfaa4e5SAlessandro Rubini /* any IP header will work, copy the first we received */
943c5c59df0SJoe Hershberger memcpy(localip, ip, IP_HDR_SIZE);
9445cfaa4e5SAlessandro Rubini }
9455cfaa4e5SAlessandro Rubini
9465cfaa4e5SAlessandro Rubini /*
9475cfaa4e5SAlessandro Rubini * What follows is the reassembly algorithm. We use the payload
9485cfaa4e5SAlessandro Rubini * array as a linked list of hole descriptors, as each hole starts
9495cfaa4e5SAlessandro Rubini * at a multiple of 8 bytes. However, last byte can be whatever value,
9505cfaa4e5SAlessandro Rubini * so it is represented as byte count, not as 8-byte blocks.
9515cfaa4e5SAlessandro Rubini */
9525cfaa4e5SAlessandro Rubini
9535cfaa4e5SAlessandro Rubini h = payload + first_hole;
9545cfaa4e5SAlessandro Rubini while (h->last_byte < start) {
9555cfaa4e5SAlessandro Rubini if (!h->next_hole) {
9565cfaa4e5SAlessandro Rubini /* no hole that far away */
9575cfaa4e5SAlessandro Rubini return NULL;
9585cfaa4e5SAlessandro Rubini }
9595cfaa4e5SAlessandro Rubini h = payload + h->next_hole;
9605cfaa4e5SAlessandro Rubini }
9615cfaa4e5SAlessandro Rubini
962e397e59eSFillod Stephane /* last fragment may be 1..7 bytes, the "+7" forces acceptance */
963e397e59eSFillod Stephane if (offset8 + ((len + 7) / 8) <= h - payload) {
9645cfaa4e5SAlessandro Rubini /* no overlap with holes (dup fragment?) */
9655cfaa4e5SAlessandro Rubini return NULL;
9665cfaa4e5SAlessandro Rubini }
9675cfaa4e5SAlessandro Rubini
9685cfaa4e5SAlessandro Rubini if (!(ip_off & IP_FLAGS_MFRAG)) {
9695cfaa4e5SAlessandro Rubini /* no more fragmentss: truncate this (last) hole */
9705cfaa4e5SAlessandro Rubini total_len = start + len;
9715cfaa4e5SAlessandro Rubini h->last_byte = start + len;
9725cfaa4e5SAlessandro Rubini }
9735cfaa4e5SAlessandro Rubini
9745cfaa4e5SAlessandro Rubini /*
9755cfaa4e5SAlessandro Rubini * There is some overlap: fix the hole list. This code doesn't
9765cfaa4e5SAlessandro Rubini * deal with a fragment that overlaps with two different holes
9775cfaa4e5SAlessandro Rubini * (thus being a superset of a previously-received fragment).
9785cfaa4e5SAlessandro Rubini */
9795cfaa4e5SAlessandro Rubini
9805cfaa4e5SAlessandro Rubini if ((h >= thisfrag) && (h->last_byte <= start + len)) {
9815cfaa4e5SAlessandro Rubini /* complete overlap with hole: remove hole */
9825cfaa4e5SAlessandro Rubini if (!h->prev_hole && !h->next_hole) {
9835cfaa4e5SAlessandro Rubini /* last remaining hole */
9845cfaa4e5SAlessandro Rubini done = 1;
9855cfaa4e5SAlessandro Rubini } else if (!h->prev_hole) {
9865cfaa4e5SAlessandro Rubini /* first hole */
9875cfaa4e5SAlessandro Rubini first_hole = h->next_hole;
9885cfaa4e5SAlessandro Rubini payload[h->next_hole].prev_hole = 0;
9895cfaa4e5SAlessandro Rubini } else if (!h->next_hole) {
9905cfaa4e5SAlessandro Rubini /* last hole */
9915cfaa4e5SAlessandro Rubini payload[h->prev_hole].next_hole = 0;
9925cfaa4e5SAlessandro Rubini } else {
9935cfaa4e5SAlessandro Rubini /* in the middle of the list */
9945cfaa4e5SAlessandro Rubini payload[h->next_hole].prev_hole = h->prev_hole;
9955cfaa4e5SAlessandro Rubini payload[h->prev_hole].next_hole = h->next_hole;
9965cfaa4e5SAlessandro Rubini }
9975cfaa4e5SAlessandro Rubini
9985cfaa4e5SAlessandro Rubini } else if (h->last_byte <= start + len) {
9995cfaa4e5SAlessandro Rubini /* overlaps with final part of the hole: shorten this hole */
10005cfaa4e5SAlessandro Rubini h->last_byte = start;
10015cfaa4e5SAlessandro Rubini
10025cfaa4e5SAlessandro Rubini } else if (h >= thisfrag) {
10035cfaa4e5SAlessandro Rubini /* overlaps with initial part of the hole: move this hole */
10045cfaa4e5SAlessandro Rubini newh = thisfrag + (len / 8);
10055cfaa4e5SAlessandro Rubini *newh = *h;
10065cfaa4e5SAlessandro Rubini h = newh;
10075cfaa4e5SAlessandro Rubini if (h->next_hole)
10085cfaa4e5SAlessandro Rubini payload[h->next_hole].prev_hole = (h - payload);
10095cfaa4e5SAlessandro Rubini if (h->prev_hole)
10105cfaa4e5SAlessandro Rubini payload[h->prev_hole].next_hole = (h - payload);
10115cfaa4e5SAlessandro Rubini else
10125cfaa4e5SAlessandro Rubini first_hole = (h - payload);
10135cfaa4e5SAlessandro Rubini
10145cfaa4e5SAlessandro Rubini } else {
10155cfaa4e5SAlessandro Rubini /* fragment sits in the middle: split the hole */
10165cfaa4e5SAlessandro Rubini newh = thisfrag + (len / 8);
10175cfaa4e5SAlessandro Rubini *newh = *h;
10185cfaa4e5SAlessandro Rubini h->last_byte = start;
10195cfaa4e5SAlessandro Rubini h->next_hole = (newh - payload);
10205cfaa4e5SAlessandro Rubini newh->prev_hole = (h - payload);
10215cfaa4e5SAlessandro Rubini if (newh->next_hole)
10225cfaa4e5SAlessandro Rubini payload[newh->next_hole].prev_hole = (newh - payload);
10235cfaa4e5SAlessandro Rubini }
10245cfaa4e5SAlessandro Rubini
10255cfaa4e5SAlessandro Rubini /* finally copy this fragment and possibly return whole packet */
1026c5c59df0SJoe Hershberger memcpy((uchar *)thisfrag, indata + IP_HDR_SIZE, len);
10275cfaa4e5SAlessandro Rubini if (!done)
10285cfaa4e5SAlessandro Rubini return NULL;
10295cfaa4e5SAlessandro Rubini
10305cfaa4e5SAlessandro Rubini localip->ip_len = htons(total_len);
1031c5c59df0SJoe Hershberger *lenp = total_len + IP_HDR_SIZE;
10325cfaa4e5SAlessandro Rubini return localip;
10335cfaa4e5SAlessandro Rubini }
10345cfaa4e5SAlessandro Rubini
net_defragment(struct ip_udp_hdr * ip,int * lenp)1035bc0571fcSJoe Hershberger static inline struct ip_udp_hdr *net_defragment(struct ip_udp_hdr *ip,
1036bc0571fcSJoe Hershberger int *lenp)
10375cfaa4e5SAlessandro Rubini {
10385cfaa4e5SAlessandro Rubini u16 ip_off = ntohs(ip->ip_off);
10395cfaa4e5SAlessandro Rubini if (!(ip_off & (IP_OFFS | IP_FLAGS_MFRAG)))
10405cfaa4e5SAlessandro Rubini return ip; /* not a fragment */
1041bc0571fcSJoe Hershberger return __net_defragment(ip, lenp);
10425cfaa4e5SAlessandro Rubini }
10435cfaa4e5SAlessandro Rubini
10445cfaa4e5SAlessandro Rubini #else /* !CONFIG_IP_DEFRAG */
10455cfaa4e5SAlessandro Rubini
net_defragment(struct ip_udp_hdr * ip,int * lenp)1046bc0571fcSJoe Hershberger static inline struct ip_udp_hdr *net_defragment(struct ip_udp_hdr *ip,
1047bc0571fcSJoe Hershberger int *lenp)
10485cfaa4e5SAlessandro Rubini {
10495cfaa4e5SAlessandro Rubini u16 ip_off = ntohs(ip->ip_off);
10505cfaa4e5SAlessandro Rubini if (!(ip_off & (IP_OFFS | IP_FLAGS_MFRAG)))
10515cfaa4e5SAlessandro Rubini return ip; /* not a fragment */
10525cfaa4e5SAlessandro Rubini return NULL;
10535cfaa4e5SAlessandro Rubini }
10545cfaa4e5SAlessandro Rubini #endif
1055a3d991bdSwdenk
10568f79bb17SSimon Glass /**
10578f79bb17SSimon Glass * Receive an ICMP packet. We deal with REDIRECT and PING here, and silently
10588f79bb17SSimon Glass * drop others.
10598f79bb17SSimon Glass *
10608f79bb17SSimon Glass * @parma ip IP packet containing the ICMP
10618f79bb17SSimon Glass */
receive_icmp(struct ip_udp_hdr * ip,int len,struct in_addr src_ip,struct ethernet_hdr * et)1062594c26f8SJoe Hershberger static void receive_icmp(struct ip_udp_hdr *ip, int len,
1063049a95a7SJoe Hershberger struct in_addr src_ip, struct ethernet_hdr *et)
10648f79bb17SSimon Glass {
1065e0a63079SJoe Hershberger struct icmp_hdr *icmph = (struct icmp_hdr *)&ip->udp_src;
10668f79bb17SSimon Glass
10678f79bb17SSimon Glass switch (icmph->type) {
10688f79bb17SSimon Glass case ICMP_REDIRECT:
10698f79bb17SSimon Glass if (icmph->code != ICMP_REDIR_HOST)
10708f79bb17SSimon Glass return;
10718f79bb17SSimon Glass printf(" ICMP Host Redirect to %pI4 ",
10728f79bb17SSimon Glass &icmph->un.gateway);
10738f79bb17SSimon Glass break;
10748f79bb17SSimon Glass default:
1075a36b12f9SJoe Hershberger #if defined(CONFIG_CMD_PING)
1076a36b12f9SJoe Hershberger ping_receive(et, ip, len);
1077a36b12f9SJoe Hershberger #endif
107839bccd21SSimon Glass #ifdef CONFIG_CMD_TFTPPUT
10794793ee65SSimon Glass if (packet_icmp_handler)
10804793ee65SSimon Glass packet_icmp_handler(icmph->type, icmph->code,
1081bc0571fcSJoe Hershberger ntohs(ip->udp_dst), src_ip,
1082bc0571fcSJoe Hershberger ntohs(ip->udp_src), icmph->un.data,
1083bc0571fcSJoe Hershberger ntohs(ip->udp_len));
108439bccd21SSimon Glass #endif
10858f79bb17SSimon Glass break;
10868f79bb17SSimon Glass }
10878f79bb17SSimon Glass }
10888f79bb17SSimon Glass
net_process_received_packet(uchar * in_packet,int len)10892a504df0SJoe Hershberger void net_process_received_packet(uchar *in_packet, int len)
10902d966958Swdenk {
1091cb487f56SJoe Hershberger struct ethernet_hdr *et;
1092594c26f8SJoe Hershberger struct ip_udp_hdr *ip;
1093049a95a7SJoe Hershberger struct in_addr dst_ip;
1094049a95a7SJoe Hershberger struct in_addr src_ip;
10958d353eb8SJoe Hershberger int eth_proto;
1096643d1ab2SJon Loeliger #if defined(CONFIG_CMD_CDP)
1097a3d991bdSwdenk int iscdp;
1098a3d991bdSwdenk #endif
1099a3d991bdSwdenk ushort cti = 0, vlanid = VLAN_NONE, myvlanid, mynvlanid;
11002d966958Swdenk
11014ef8d53cSJoe Hershberger debug_cond(DEBUG_NET_PKT, "packet received\n");
1102a3d991bdSwdenk
11031203fcceSJoe Hershberger net_rx_packet = in_packet;
11041203fcceSJoe Hershberger net_rx_packet_len = len;
11052a504df0SJoe Hershberger et = (struct ethernet_hdr *)in_packet;
1106a3d991bdSwdenk
1107a3d991bdSwdenk /* too small packet? */
1108a3d991bdSwdenk if (len < ETHER_HDR_SIZE)
1109a3d991bdSwdenk return;
1110a3d991bdSwdenk
11110efe1bcfSAlexander Graf #if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
1112f85b6071SRafal Jaworowski if (push_packet) {
11132a504df0SJoe Hershberger (*push_packet)(in_packet, len);
1114f85b6071SRafal Jaworowski return;
1115f85b6071SRafal Jaworowski }
1116f85b6071SRafal Jaworowski #endif
1117f85b6071SRafal Jaworowski
1118643d1ab2SJon Loeliger #if defined(CONFIG_CMD_CDP)
1119a3d991bdSwdenk /* keep track if packet is CDP */
112017351883SJoe Hershberger iscdp = is_cdp_packet(et->et_dest);
1121a3d991bdSwdenk #endif
1122a3d991bdSwdenk
11234fd5055fSJoe Hershberger myvlanid = ntohs(net_our_vlan);
1124a3d991bdSwdenk if (myvlanid == (ushort)-1)
1125a3d991bdSwdenk myvlanid = VLAN_NONE;
11264fd5055fSJoe Hershberger mynvlanid = ntohs(net_native_vlan);
1127a3d991bdSwdenk if (mynvlanid == (ushort)-1)
1128a3d991bdSwdenk mynvlanid = VLAN_NONE;
11292d966958Swdenk
11308d353eb8SJoe Hershberger eth_proto = ntohs(et->et_protlen);
11312d966958Swdenk
11328d353eb8SJoe Hershberger if (eth_proto < 1514) {
1133cb487f56SJoe Hershberger struct e802_hdr *et802 = (struct e802_hdr *)et;
11342d966958Swdenk /*
1135da5ebe2cSJoe Hershberger * Got a 802.2 packet. Check the other protocol field.
1136da5ebe2cSJoe Hershberger * XXX VLAN over 802.2+SNAP not implemented!
11372d966958Swdenk */
11388d353eb8SJoe Hershberger eth_proto = ntohs(et802->et_prot);
1139a3d991bdSwdenk
11402a504df0SJoe Hershberger ip = (struct ip_udp_hdr *)(in_packet + E802_HDR_SIZE);
11412d966958Swdenk len -= E802_HDR_SIZE;
1142a3d991bdSwdenk
11438d353eb8SJoe Hershberger } else if (eth_proto != PROT_VLAN) { /* normal packet */
11442a504df0SJoe Hershberger ip = (struct ip_udp_hdr *)(in_packet + ETHER_HDR_SIZE);
11452d966958Swdenk len -= ETHER_HDR_SIZE;
1146a3d991bdSwdenk
1147a3d991bdSwdenk } else { /* VLAN packet */
1148c68cca35SJoe Hershberger struct vlan_ethernet_hdr *vet =
1149c68cca35SJoe Hershberger (struct vlan_ethernet_hdr *)et;
1150a3d991bdSwdenk
11514ef8d53cSJoe Hershberger debug_cond(DEBUG_NET_PKT, "VLAN packet received\n");
11520ebf04c6SRobin Getz
1153a3d991bdSwdenk /* too small packet? */
1154a3d991bdSwdenk if (len < VLAN_ETHER_HDR_SIZE)
1155a3d991bdSwdenk return;
1156a3d991bdSwdenk
1157a3d991bdSwdenk /* if no VLAN active */
11584fd5055fSJoe Hershberger if ((ntohs(net_our_vlan) & VLAN_IDMASK) == VLAN_NONE
1159643d1ab2SJon Loeliger #if defined(CONFIG_CMD_CDP)
1160a3d991bdSwdenk && iscdp == 0
1161a3d991bdSwdenk #endif
1162a3d991bdSwdenk )
1163a3d991bdSwdenk return;
1164a3d991bdSwdenk
1165a3d991bdSwdenk cti = ntohs(vet->vet_tag);
1166a3d991bdSwdenk vlanid = cti & VLAN_IDMASK;
11678d353eb8SJoe Hershberger eth_proto = ntohs(vet->vet_type);
1168a3d991bdSwdenk
11692a504df0SJoe Hershberger ip = (struct ip_udp_hdr *)(in_packet + VLAN_ETHER_HDR_SIZE);
1170a3d991bdSwdenk len -= VLAN_ETHER_HDR_SIZE;
11712d966958Swdenk }
11722d966958Swdenk
11734ef8d53cSJoe Hershberger debug_cond(DEBUG_NET_PKT, "Receive from protocol 0x%x\n", eth_proto);
11742d966958Swdenk
1175643d1ab2SJon Loeliger #if defined(CONFIG_CMD_CDP)
1176a3d991bdSwdenk if (iscdp) {
11770b4c5ff4SJoe Hershberger cdp_receive((uchar *)ip, len);
1178a3d991bdSwdenk return;
1179a3d991bdSwdenk }
1180a3d991bdSwdenk #endif
1181a3d991bdSwdenk
1182a3d991bdSwdenk if ((myvlanid & VLAN_IDMASK) != VLAN_NONE) {
1183a3d991bdSwdenk if (vlanid == VLAN_NONE)
1184a3d991bdSwdenk vlanid = (mynvlanid & VLAN_IDMASK);
1185a3d991bdSwdenk /* not matched? */
1186a3d991bdSwdenk if (vlanid != (myvlanid & VLAN_IDMASK))
1187a3d991bdSwdenk return;
1188a3d991bdSwdenk }
1189a3d991bdSwdenk
11908d353eb8SJoe Hershberger switch (eth_proto) {
11912d966958Swdenk case PROT_ARP:
119285d25e0eSJoe Hershberger arp_receive(et, ip, len);
1193289f932cSwdenk break;
11942d966958Swdenk
1195bf6cb247SPeter Tyser #ifdef CONFIG_CMD_RARP
11962d966958Swdenk case PROT_RARP:
11978b9c5322SJoe Hershberger rarp_receive(ip, len);
11982d966958Swdenk break;
1199bf6cb247SPeter Tyser #endif
12002d966958Swdenk case PROT_IP:
12014ef8d53cSJoe Hershberger debug_cond(DEBUG_NET_PKT, "Got IP\n");
12025cfaa4e5SAlessandro Rubini /* Before we start poking the header, make sure it is there */
1203594c26f8SJoe Hershberger if (len < IP_UDP_HDR_SIZE) {
1204594c26f8SJoe Hershberger debug("len bad %d < %lu\n", len,
1205594c26f8SJoe Hershberger (ulong)IP_UDP_HDR_SIZE);
12062d966958Swdenk return;
12072d966958Swdenk }
12085cfaa4e5SAlessandro Rubini /* Check the packet length */
12092d966958Swdenk if (len < ntohs(ip->ip_len)) {
12104ef8d53cSJoe Hershberger debug("len bad %d < %d\n", len, ntohs(ip->ip_len));
12112d966958Swdenk return;
12122d966958Swdenk }
12132d966958Swdenk len = ntohs(ip->ip_len);
12144ef8d53cSJoe Hershberger debug_cond(DEBUG_NET_PKT, "len=%d, v=%02x\n",
12154ef8d53cSJoe Hershberger len, ip->ip_hl_v & 0xff);
12160ebf04c6SRobin Getz
12175cfaa4e5SAlessandro Rubini /* Can't deal with anything except IPv4 */
1218d3c65b01SLuca Ceresoli if ((ip->ip_hl_v & 0xf0) != 0x40)
12192d966958Swdenk return;
12205cfaa4e5SAlessandro Rubini /* Can't deal with IP options (headers != 20 bytes) */
1221d3c65b01SLuca Ceresoli if ((ip->ip_hl_v & 0x0f) > 0x05)
12226b52cfe1SRemy Bohmer return;
12235cfaa4e5SAlessandro Rubini /* Check the Checksum of the header */
12240da0fcd5SSimon Glass if (!ip_checksum_ok((uchar *)ip, IP_HDR_SIZE)) {
12254ef8d53cSJoe Hershberger debug("checksum bad\n");
12262d966958Swdenk return;
12272d966958Swdenk }
12285cfaa4e5SAlessandro Rubini /* If it is not for us, ignore it */
1229049a95a7SJoe Hershberger dst_ip = net_read_ip(&ip->ip_dst);
1230049a95a7SJoe Hershberger if (net_ip.s_addr && dst_ip.s_addr != net_ip.s_addr &&
1231049a95a7SJoe Hershberger dst_ip.s_addr != 0xFFFFFFFF) {
12322d966958Swdenk return;
12332d966958Swdenk }
123403eb129fSLuca Ceresoli /* Read source IP address for later use */
1235049a95a7SJoe Hershberger src_ip = net_read_ip(&ip->ip_src);
12362d966958Swdenk /*
12375cfaa4e5SAlessandro Rubini * The function returns the unchanged packet if it's not
12385cfaa4e5SAlessandro Rubini * a fragment, and either the complete packet or NULL if
12395cfaa4e5SAlessandro Rubini * it is a fragment (if !CONFIG_IP_DEFRAG, it returns NULL)
12405cfaa4e5SAlessandro Rubini */
1241bc0571fcSJoe Hershberger ip = net_defragment(ip, &len);
1242ccb9ebefSLuca Ceresoli if (!ip)
12435cfaa4e5SAlessandro Rubini return;
12445cfaa4e5SAlessandro Rubini /*
12452d966958Swdenk * watch for ICMP host redirects
12462d966958Swdenk *
12472d966958Swdenk * There is no real handler code (yet). We just watch
12482d966958Swdenk * for ICMP host redirect messages. In case anybody
12492d966958Swdenk * sees these messages: please contact me
12502d966958Swdenk * (wd@denx.de), or - even better - send me the
12512d966958Swdenk * necessary fixes :-)
12522d966958Swdenk *
12532d966958Swdenk * Note: in all cases where I have seen this so far
12542d966958Swdenk * it was a problem with the router configuration,
12552d966958Swdenk * for instance when a router was configured in the
12562d966958Swdenk * BOOTP reply, but the TFTP server was on the same
12572d966958Swdenk * subnet. So this is probably a warning that your
12582d966958Swdenk * configuration might be wrong. But I'm not really
12592d966958Swdenk * sure if there aren't any other situations.
12604793ee65SSimon Glass *
12614793ee65SSimon Glass * Simon Glass <sjg@chromium.org>: We get an ICMP when
12624793ee65SSimon Glass * we send a tftp packet to a dead connection, or when
12634793ee65SSimon Glass * there is no server at the other end.
12642d966958Swdenk */
12652d966958Swdenk if (ip->ip_p == IPPROTO_ICMP) {
12668f79bb17SSimon Glass receive_icmp(ip, len, src_ip, et);
12672d966958Swdenk return;
12682d966958Swdenk } else if (ip->ip_p != IPPROTO_UDP) { /* Only UDP packets */
12692d966958Swdenk return;
12702d966958Swdenk }
12712d966958Swdenk
12723746502fSliucheng (G) if (ntohs(ip->udp_len) < UDP_HDR_SIZE || ntohs(ip->udp_len) > ntohs(ip->ip_len))
12733746502fSliucheng (G) return;
12743746502fSliucheng (G)
12754ef8d53cSJoe Hershberger debug_cond(DEBUG_DEV_PKT,
12764ef8d53cSJoe Hershberger "received UDP (to=%pI4, from=%pI4, len=%d)\n",
12774ef8d53cSJoe Hershberger &dst_ip, &src_ip, len);
12784ef8d53cSJoe Hershberger
12798534bf9aSStefan Roese #ifdef CONFIG_UDP_CHECKSUM
12808534bf9aSStefan Roese if (ip->udp_xsum != 0) {
12818534bf9aSStefan Roese ulong xsum;
12828534bf9aSStefan Roese ushort *sumptr;
12838534bf9aSStefan Roese ushort sumlen;
12848534bf9aSStefan Roese
12858534bf9aSStefan Roese xsum = ip->ip_p;
12868534bf9aSStefan Roese xsum += (ntohs(ip->udp_len));
1287049a95a7SJoe Hershberger xsum += (ntohl(ip->ip_src.s_addr) >> 16) & 0x0000ffff;
1288049a95a7SJoe Hershberger xsum += (ntohl(ip->ip_src.s_addr) >> 0) & 0x0000ffff;
1289049a95a7SJoe Hershberger xsum += (ntohl(ip->ip_dst.s_addr) >> 16) & 0x0000ffff;
1290049a95a7SJoe Hershberger xsum += (ntohl(ip->ip_dst.s_addr) >> 0) & 0x0000ffff;
12918534bf9aSStefan Roese
12928534bf9aSStefan Roese sumlen = ntohs(ip->udp_len);
12938534bf9aSStefan Roese sumptr = (ushort *)&(ip->udp_src);
12948534bf9aSStefan Roese
12958534bf9aSStefan Roese while (sumlen > 1) {
12968534bf9aSStefan Roese ushort sumdata;
12978534bf9aSStefan Roese
12988534bf9aSStefan Roese sumdata = *sumptr++;
12998534bf9aSStefan Roese xsum += ntohs(sumdata);
13008534bf9aSStefan Roese sumlen -= 2;
13018534bf9aSStefan Roese }
13028534bf9aSStefan Roese if (sumlen > 0) {
13038534bf9aSStefan Roese ushort sumdata;
13048534bf9aSStefan Roese
13058534bf9aSStefan Roese sumdata = *(unsigned char *)sumptr;
13068534bf9aSStefan Roese sumdata = (sumdata << 8) & 0xff00;
13078534bf9aSStefan Roese xsum += sumdata;
13088534bf9aSStefan Roese }
13098534bf9aSStefan Roese while ((xsum >> 16) != 0) {
13103e38e429SLuca Ceresoli xsum = (xsum & 0x0000ffff) +
13113e38e429SLuca Ceresoli ((xsum >> 16) & 0x0000ffff);
13128534bf9aSStefan Roese }
13138534bf9aSStefan Roese if ((xsum != 0x00000000) && (xsum != 0x0000ffff)) {
13149b55a253SWolfgang Denk printf(" UDP wrong checksum %08lx %08x\n",
13159b55a253SWolfgang Denk xsum, ntohs(ip->udp_xsum));
13168534bf9aSStefan Roese return;
13178534bf9aSStefan Roese }
13188534bf9aSStefan Roese }
13198534bf9aSStefan Roese #endif
13208534bf9aSStefan Roese
132166c89ee3SHolger Dengler #if defined(CONFIG_NETCONSOLE) && !defined(CONFIG_SPL_BUILD)
1322594c26f8SJoe Hershberger nc_input_packet((uchar *)ip + IP_UDP_HDR_SIZE,
13238cab08e8SJoe Hershberger src_ip,
132468ceb29eSwdenk ntohs(ip->udp_dst),
132568ceb29eSwdenk ntohs(ip->udp_src),
1326594c26f8SJoe Hershberger ntohs(ip->udp_len) - UDP_HDR_SIZE);
132768ceb29eSwdenk #endif
13282d966958Swdenk /*
13292d966958Swdenk * IP header OK. Pass the packet to the current handler.
13302d966958Swdenk */
1331ece223b5SJoe Hershberger (*udp_packet_handler)((uchar *)ip + IP_UDP_HDR_SIZE,
13322d966958Swdenk ntohs(ip->udp_dst),
133303eb129fSLuca Ceresoli src_ip,
13342d966958Swdenk ntohs(ip->udp_src),
1335594c26f8SJoe Hershberger ntohs(ip->udp_len) - UDP_HDR_SIZE);
13362d966958Swdenk break;
1337d8970daeSLothar Felten #ifdef CONFIG_CMD_WOL
1338d8970daeSLothar Felten case PROT_WOL:
1339d8970daeSLothar Felten wol_receive(ip, len);
1340d8970daeSLothar Felten break;
1341d8970daeSLothar Felten #endif
13429ab23354SDylan Hung #ifdef CONFIG_PHY_NCSI
13439ab23354SDylan Hung case PROT_NCSI:
13449ab23354SDylan Hung ncsi_receive(et, ip, len);
13459ab23354SDylan Hung break;
13469ab23354SDylan Hung #endif
13472d966958Swdenk }
13482d966958Swdenk }
13492d966958Swdenk
13502d966958Swdenk /**********************************************************************/
13512d966958Swdenk
net_check_prereq(enum proto_t protocol)1352e4bf0c5cSSimon Glass static int net_check_prereq(enum proto_t protocol)
13532d966958Swdenk {
13542d966958Swdenk switch (protocol) {
135573a8b27cSwdenk /* Fall through */
1356643d1ab2SJon Loeliger #if defined(CONFIG_CMD_PING)
135773a8b27cSwdenk case PING:
1358049a95a7SJoe Hershberger if (net_ping_ip.s_addr == 0) {
135973a8b27cSwdenk puts("*** ERROR: ping address not given\n");
136092895de9SLuca Ceresoli return 1;
136173a8b27cSwdenk }
136273a8b27cSwdenk goto common;
136373a8b27cSwdenk #endif
1364643d1ab2SJon Loeliger #if defined(CONFIG_CMD_SNTP)
1365ea287debSwdenk case SNTP:
1366049a95a7SJoe Hershberger if (net_ntp_server.s_addr == 0) {
1367ea287debSwdenk puts("*** ERROR: NTP server address not given\n");
136892895de9SLuca Ceresoli return 1;
1369ea287debSwdenk }
1370ea287debSwdenk goto common;
1371ea287debSwdenk #endif
13721a32bf41SRobin Getz #if defined(CONFIG_CMD_DNS)
13731a32bf41SRobin Getz case DNS:
1374049a95a7SJoe Hershberger if (net_dns_server.s_addr == 0) {
13751a32bf41SRobin Getz puts("*** ERROR: DNS server address not given\n");
13761a32bf41SRobin Getz return 1;
13771a32bf41SRobin Getz }
13781a32bf41SRobin Getz goto common;
13791a32bf41SRobin Getz #endif
1380643d1ab2SJon Loeliger #if defined(CONFIG_CMD_NFS)
1381cbd8a35cSwdenk case NFS:
1382cbd8a35cSwdenk #endif
1383bc0571fcSJoe Hershberger /* Fall through */
1384e4bf0c5cSSimon Glass case TFTPGET:
13851fb7cd49SSimon Glass case TFTPPUT:
13863a66fcb7SJoe Hershberger if (net_server_ip.s_addr == 0 && !is_serverip_in_cmd()) {
13872d966958Swdenk puts("*** ERROR: `serverip' not set\n");
138892895de9SLuca Ceresoli return 1;
13892d966958Swdenk }
13909030a55eSGray Remlin #if defined(CONFIG_CMD_PING) || defined(CONFIG_CMD_SNTP) || \
13919030a55eSGray Remlin defined(CONFIG_CMD_DNS)
139273a8b27cSwdenk common:
139373a8b27cSwdenk #endif
13948b6bbe10SSimon Guinot /* Fall through */
139573a8b27cSwdenk
13968b6bbe10SSimon Guinot case NETCONS:
1397f73a7df9SAlex Kiernan case FASTBOOT:
13987a83af07SLuca Ceresoli case TFTPSRV:
1399049a95a7SJoe Hershberger if (net_ip.s_addr == 0) {
14002d966958Swdenk puts("*** ERROR: `ipaddr' not set\n");
140192895de9SLuca Ceresoli return 1;
14022d966958Swdenk }
14032d966958Swdenk /* Fall through */
14042d966958Swdenk
1405bf6cb247SPeter Tyser #ifdef CONFIG_CMD_RARP
14062d966958Swdenk case RARP:
1407bf6cb247SPeter Tyser #endif
14089ab23354SDylan Hung #ifdef CONFIG_CMD_NCSI
14099ab23354SDylan Hung case NCSI:
14109ab23354SDylan Hung #endif
14112d966958Swdenk case BOOTP:
1412a3d991bdSwdenk case CDP:
1413bf6cb247SPeter Tyser case DHCP:
1414d22c338eSJoe Hershberger case LINKLOCAL:
14150adb5b76SJoe Hershberger if (memcmp(net_ethaddr, "\0\0\0\0\0\0", 6) == 0) {
14162d966958Swdenk int num = eth_get_dev_index();
14172d966958Swdenk
14182d966958Swdenk switch (num) {
14192d966958Swdenk case -1:
14202d966958Swdenk puts("*** ERROR: No ethernet found.\n");
142192895de9SLuca Ceresoli return 1;
14222d966958Swdenk case 0:
14232d966958Swdenk puts("*** ERROR: `ethaddr' not set\n");
14242d966958Swdenk break;
14252d966958Swdenk default:
14262d966958Swdenk printf("*** ERROR: `eth%daddr' not set\n",
14272d966958Swdenk num);
14282d966958Swdenk break;
14292d966958Swdenk }
14302d966958Swdenk
1431bc0571fcSJoe Hershberger net_start_again();
143292895de9SLuca Ceresoli return 2;
14332d966958Swdenk }
14342d966958Swdenk /* Fall through */
143573a8b27cSwdenk default:
143692895de9SLuca Ceresoli return 0;
14372d966958Swdenk }
143892895de9SLuca Ceresoli return 0; /* OK */
14392d966958Swdenk }
14402d966958Swdenk /**********************************************************************/
14412d966958Swdenk
14422d966958Swdenk int
net_eth_hdr_size(void)14431203fcceSJoe Hershberger net_eth_hdr_size(void)
1444a3d991bdSwdenk {
1445a3d991bdSwdenk ushort myvlanid;
14462d966958Swdenk
14474fd5055fSJoe Hershberger myvlanid = ntohs(net_our_vlan);
1448a3d991bdSwdenk if (myvlanid == (ushort)-1)
1449a3d991bdSwdenk myvlanid = VLAN_NONE;
1450a3d991bdSwdenk
14513e38e429SLuca Ceresoli return ((myvlanid & VLAN_IDMASK) == VLAN_NONE) ? ETHER_HDR_SIZE :
14523e38e429SLuca Ceresoli VLAN_ETHER_HDR_SIZE;
1453a3d991bdSwdenk }
1454a3d991bdSwdenk
net_set_ether(uchar * xet,const uchar * dest_ethaddr,uint prot)14551203fcceSJoe Hershberger int net_set_ether(uchar *xet, const uchar *dest_ethaddr, uint prot)
14562d966958Swdenk {
1457cb487f56SJoe Hershberger struct ethernet_hdr *et = (struct ethernet_hdr *)xet;
1458a3d991bdSwdenk ushort myvlanid;
1459a3d991bdSwdenk
14604fd5055fSJoe Hershberger myvlanid = ntohs(net_our_vlan);
1461a3d991bdSwdenk if (myvlanid == (ushort)-1)
1462a3d991bdSwdenk myvlanid = VLAN_NONE;
14632d966958Swdenk
14640adb5b76SJoe Hershberger memcpy(et->et_dest, dest_ethaddr, 6);
14650adb5b76SJoe Hershberger memcpy(et->et_src, net_ethaddr, 6);
1466a3d991bdSwdenk if ((myvlanid & VLAN_IDMASK) == VLAN_NONE) {
14672d966958Swdenk et->et_protlen = htons(prot);
1468a3d991bdSwdenk return ETHER_HDR_SIZE;
1469a3d991bdSwdenk } else {
1470c68cca35SJoe Hershberger struct vlan_ethernet_hdr *vet =
1471c68cca35SJoe Hershberger (struct vlan_ethernet_hdr *)xet;
14722d966958Swdenk
1473a3d991bdSwdenk vet->vet_vlan_type = htons(PROT_VLAN);
1474a3d991bdSwdenk vet->vet_tag = htons((0 << 5) | (myvlanid & VLAN_IDMASK));
1475a3d991bdSwdenk vet->vet_type = htons(prot);
1476a3d991bdSwdenk return VLAN_ETHER_HDR_SIZE;
1477a3d991bdSwdenk }
1478a3d991bdSwdenk }
14792d966958Swdenk
net_update_ether(struct ethernet_hdr * et,uchar * addr,uint prot)1480e7111015SJoe Hershberger int net_update_ether(struct ethernet_hdr *et, uchar *addr, uint prot)
1481e7111015SJoe Hershberger {
1482e7111015SJoe Hershberger ushort protlen;
1483e7111015SJoe Hershberger
1484e7111015SJoe Hershberger memcpy(et->et_dest, addr, 6);
14850adb5b76SJoe Hershberger memcpy(et->et_src, net_ethaddr, 6);
1486e7111015SJoe Hershberger protlen = ntohs(et->et_protlen);
1487e7111015SJoe Hershberger if (protlen == PROT_VLAN) {
1488e7111015SJoe Hershberger struct vlan_ethernet_hdr *vet =
1489e7111015SJoe Hershberger (struct vlan_ethernet_hdr *)et;
1490e7111015SJoe Hershberger vet->vet_type = htons(prot);
1491e7111015SJoe Hershberger return VLAN_ETHER_HDR_SIZE;
1492e7111015SJoe Hershberger } else if (protlen > 1514) {
1493e7111015SJoe Hershberger et->et_protlen = htons(prot);
1494e7111015SJoe Hershberger return ETHER_HDR_SIZE;
1495e7111015SJoe Hershberger } else {
1496e7111015SJoe Hershberger /* 802.2 + SNAP */
1497e7111015SJoe Hershberger struct e802_hdr *et802 = (struct e802_hdr *)et;
1498e7111015SJoe Hershberger et802->et_prot = htons(prot);
1499e7111015SJoe Hershberger return E802_HDR_SIZE;
1500e7111015SJoe Hershberger }
1501e7111015SJoe Hershberger }
1502e7111015SJoe Hershberger
net_set_ip_header(uchar * pkt,struct in_addr dest,struct in_addr source,u16 pkt_len,u8 proto)15035d457ecbSDuncan Hare void net_set_ip_header(uchar *pkt, struct in_addr dest, struct in_addr source,
15045d457ecbSDuncan Hare u16 pkt_len, u8 proto)
15052d966958Swdenk {
15064b11c916SJoe Hershberger struct ip_udp_hdr *ip = (struct ip_udp_hdr *)pkt;
15074b11c916SJoe Hershberger
15084b11c916SJoe Hershberger /*
15094b11c916SJoe Hershberger * Construct an IP header.
15104b11c916SJoe Hershberger */
15114b11c916SJoe Hershberger /* IP_HDR_SIZE / 4 (not including UDP) */
15124b11c916SJoe Hershberger ip->ip_hl_v = 0x45;
15134b11c916SJoe Hershberger ip->ip_tos = 0;
15145d457ecbSDuncan Hare ip->ip_len = htons(pkt_len);
15155d457ecbSDuncan Hare ip->ip_p = proto;
1516bc0571fcSJoe Hershberger ip->ip_id = htons(net_ip_id++);
15174b11c916SJoe Hershberger ip->ip_off = htons(IP_FLAGS_DFRAG); /* Don't fragment */
15184b11c916SJoe Hershberger ip->ip_ttl = 255;
15194b11c916SJoe Hershberger ip->ip_sum = 0;
15204b11c916SJoe Hershberger /* already in network byte order */
1521049a95a7SJoe Hershberger net_copy_ip((void *)&ip->ip_src, &source);
15224b11c916SJoe Hershberger /* already in network byte order */
1523049a95a7SJoe Hershberger net_copy_ip((void *)&ip->ip_dst, &dest);
15245d457ecbSDuncan Hare
15255d457ecbSDuncan Hare ip->ip_sum = compute_ip_checksum(ip, IP_HDR_SIZE);
15264b11c916SJoe Hershberger }
15274b11c916SJoe Hershberger
net_set_udp_header(uchar * pkt,struct in_addr dest,int dport,int sport,int len)1528049a95a7SJoe Hershberger void net_set_udp_header(uchar *pkt, struct in_addr dest, int dport, int sport,
15294b11c916SJoe Hershberger int len)
15304b11c916SJoe Hershberger {
15314b11c916SJoe Hershberger struct ip_udp_hdr *ip = (struct ip_udp_hdr *)pkt;
15322d966958Swdenk
15332d966958Swdenk /*
15342d966958Swdenk * If the data is an odd number of bytes, zero the
15352d966958Swdenk * byte after the last byte so that the checksum
15362d966958Swdenk * will work.
15372d966958Swdenk */
15382d966958Swdenk if (len & 1)
15394b11c916SJoe Hershberger pkt[IP_UDP_HDR_SIZE + len] = 0;
15402d966958Swdenk
15415d457ecbSDuncan Hare net_set_ip_header(pkt, dest, net_ip, IP_UDP_HDR_SIZE + len,
15425d457ecbSDuncan Hare IPPROTO_UDP);
15434b11c916SJoe Hershberger
15442d966958Swdenk ip->udp_src = htons(sport);
15452d966958Swdenk ip->udp_dst = htons(dport);
1546594c26f8SJoe Hershberger ip->udp_len = htons(UDP_HDR_SIZE + len);
15472d966958Swdenk ip->udp_xsum = 0;
15482d966958Swdenk }
15492d966958Swdenk
copy_filename(char * dst,const char * src,int size)1550b920ee9dSMike Frysinger void copy_filename(char *dst, const char *src, int size)
15512d966958Swdenk {
155216cf145fSJoe Hershberger if (src && *src && (*src == '"')) {
15532d966958Swdenk ++src;
15542d966958Swdenk --size;
15552d966958Swdenk }
15562d966958Swdenk
155716cf145fSJoe Hershberger while ((--size > 0) && src && *src && (*src != '"'))
15582d966958Swdenk *dst++ = *src++;
15592d966958Swdenk *dst = '\0';
15602d966958Swdenk }
15612d966958Swdenk
is_serverip_in_cmd(void)15623a66fcb7SJoe Hershberger int is_serverip_in_cmd(void)
15633a66fcb7SJoe Hershberger {
15643a66fcb7SJoe Hershberger return !!strchr(net_boot_file_name, ':');
15653a66fcb7SJoe Hershberger }
15663a66fcb7SJoe Hershberger
net_parse_bootfile(struct in_addr * ipaddr,char * filename,int max_len)15676ab12830SJoe Hershberger int net_parse_bootfile(struct in_addr *ipaddr, char *filename, int max_len)
15686ab12830SJoe Hershberger {
15696ab12830SJoe Hershberger char *colon;
15706ab12830SJoe Hershberger
15716ab12830SJoe Hershberger if (net_boot_file_name[0] == '\0')
15726ab12830SJoe Hershberger return 0;
15736ab12830SJoe Hershberger
15746ab12830SJoe Hershberger colon = strchr(net_boot_file_name, ':');
15756ab12830SJoe Hershberger if (colon) {
15766ab12830SJoe Hershberger if (ipaddr)
15776ab12830SJoe Hershberger *ipaddr = string_to_ip(net_boot_file_name);
15786ab12830SJoe Hershberger strncpy(filename, colon + 1, max_len);
15796ab12830SJoe Hershberger } else {
15806ab12830SJoe Hershberger strncpy(filename, net_boot_file_name, max_len);
15816ab12830SJoe Hershberger }
15826ab12830SJoe Hershberger filename[max_len - 1] = '\0';
15836ab12830SJoe Hershberger
15846ab12830SJoe Hershberger return 1;
15856ab12830SJoe Hershberger }
15866ab12830SJoe Hershberger
15873e38e429SLuca Ceresoli #if defined(CONFIG_CMD_NFS) || \
15883e38e429SLuca Ceresoli defined(CONFIG_CMD_SNTP) || \
15893e38e429SLuca Ceresoli defined(CONFIG_CMD_DNS)
15901a32bf41SRobin Getz /*
15919739946cSRobin Getz * make port a little random (1024-17407)
15929739946cSRobin Getz * This keeps the math somewhat trivial to compute, and seems to work with
15939739946cSRobin Getz * all supported protocols/clients/servers
15941a32bf41SRobin Getz */
random_port(void)15951a32bf41SRobin Getz unsigned int random_port(void)
15961a32bf41SRobin Getz {
15979739946cSRobin Getz return 1024 + (get_timer(0) % 0x4000);
15981a32bf41SRobin Getz }
15991a32bf41SRobin Getz #endif
16001a32bf41SRobin Getz
ip_to_string(struct in_addr x,char * s)1601049a95a7SJoe Hershberger void ip_to_string(struct in_addr x, char *s)
16022d966958Swdenk {
1603049a95a7SJoe Hershberger x.s_addr = ntohl(x.s_addr);
16042d966958Swdenk sprintf(s, "%d.%d.%d.%d",
1605049a95a7SJoe Hershberger (int) ((x.s_addr >> 24) & 0xff),
1606049a95a7SJoe Hershberger (int) ((x.s_addr >> 16) & 0xff),
1607049a95a7SJoe Hershberger (int) ((x.s_addr >> 8) & 0xff),
1608049a95a7SJoe Hershberger (int) ((x.s_addr >> 0) & 0xff)
16092d966958Swdenk );
16102d966958Swdenk }
16112d966958Swdenk
vlan_to_string(ushort x,char * s)16124fd5055fSJoe Hershberger void vlan_to_string(ushort x, char *s)
1613a3d991bdSwdenk {
1614a3d991bdSwdenk x = ntohs(x);
1615a3d991bdSwdenk
1616a3d991bdSwdenk if (x == (ushort)-1)
1617a3d991bdSwdenk x = VLAN_NONE;
1618a3d991bdSwdenk
1619a3d991bdSwdenk if (x == VLAN_NONE)
1620a3d991bdSwdenk strcpy(s, "none");
1621a3d991bdSwdenk else
1622a3d991bdSwdenk sprintf(s, "%d", x & VLAN_IDMASK);
1623a3d991bdSwdenk }
1624a3d991bdSwdenk
string_to_vlan(const char * s)16254fd5055fSJoe Hershberger ushort string_to_vlan(const char *s)
1626a3d991bdSwdenk {
1627a3d991bdSwdenk ushort id;
1628a3d991bdSwdenk
1629a3d991bdSwdenk if (s == NULL)
1630b9711de1Swdenk return htons(VLAN_NONE);
1631a3d991bdSwdenk
1632a3d991bdSwdenk if (*s < '0' || *s > '9')
1633a3d991bdSwdenk id = VLAN_NONE;
1634a3d991bdSwdenk else
1635a3d991bdSwdenk id = (ushort)simple_strtoul(s, NULL, 10);
1636a3d991bdSwdenk
1637b9711de1Swdenk return htons(id);
1638a3d991bdSwdenk }
1639a3d991bdSwdenk
env_get_vlan(char * var)1640723806ccSSimon Glass ushort env_get_vlan(char *var)
1641a3d991bdSwdenk {
164200caae6dSSimon Glass return string_to_vlan(env_get(var));
1643a3d991bdSwdenk }
1644