U-Boot
Threads by month
- ----- 2025 -----
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2000 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
September 2017
- 183 participants
- 756 discussions

25 Sep '17
We now require a dtc version which is not yet available in
many distros.
Indicate to the user where he will find the sources.
Signed-off-by: Heinrich Schuchardt <xypron.glpk(a)gmx.de>
---
Makefile | 1 +
1 file changed, 1 insertion(+)
diff --git a/Makefile b/Makefile
index a0d9218515..c17cca5b0d 100644
--- a/Makefile
+++ b/Makefile
@@ -1450,6 +1450,7 @@ System.map: u-boot
checkdtc:
@if test $(call dtc-version) -lt 010403; then \
echo '*** Your dtc is too old, please upgrade to dtc 1.4.3 or newer'; \
+ echo ' available at https://git.kernel.org/pub/scm/utils/dtc/dtc.git'; \
false; \
fi
--
2.11.0
3
2

25 Sep '17
From: Ashish Kumar <Ashish.Kumar(a)nxp.com>
Signed-off-by: Ashish Kumar <Ashish.Kumar(a)nxp.com>
Signed-off-by: Amrita Kumari <amrita.kumari(a)nxp.com>
Signed-off-by: Ran Wang <ran.wang_1(a)nxp.com>
---
Change in v2:
1.Adjust USB nodes position in dts to keep them sorted in
unit-address.
2.Move macro CONFIG_HAS_FSL_XHCI_USB and CONFIG_USB_XHCI_FSL
to Kconfig option.
3.Remove CONFIG_USB_MAX_CONTROLLER_COUNT.
Change in v1:
Rebased to
ba39608 ARM: DRA72x: Add support for detection of DRA71x SR 2.1
arch/arm/cpu/armv8/fsl-layerscape/Kconfig | 8 ++++++++
arch/arm/dts/fsl-ls1088a.dtsi | 14 ++++++++++++++
board/freescale/ls1088a/ls1088a.c | 1 -
configs/ls1088ardb_qspi_defconfig | 8 ++++++++
include/linux/usb/xhci-fsl.h | 2 +-
5 files changed, 31 insertions(+), 2 deletions(-)
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/Kconfig b/arch/arm/cpu/armv8/fsl-layerscape/Kconfig
index 3518d8601d..3337ff3a00 100644
--- a/arch/arm/cpu/armv8/fsl-layerscape/Kconfig
+++ b/arch/arm/cpu/armv8/fsl-layerscape/Kconfig
@@ -83,6 +83,8 @@ config ARCH_LS1088A
select FSL_TZASC_1
select ARCH_EARLY_INIT_R
select BOARD_EARLY_INIT_F
+ select HAS_FSL_XHCI_USB
+ select USB_XHCI_FSL
config ARCH_LS2080A
bool
@@ -346,6 +348,12 @@ config FSL_TZASC_1
config FSL_TZASC_2
bool
+config HAS_FSL_XHCI_USB
+ bool
+
+config USB_XHCI_FSL
+ bool
+
endmenu
menu "Layerscape clock tree configuration"
diff --git a/arch/arm/dts/fsl-ls1088a.dtsi b/arch/arm/dts/fsl-ls1088a.dtsi
index d943a9efa3..64b4fcf12b 100644
--- a/arch/arm/dts/fsl-ls1088a.dtsi
+++ b/arch/arm/dts/fsl-ls1088a.dtsi
@@ -76,6 +76,20 @@
num-cs = <4>;
};
+ usb0: usb3@3100000 {
+ compatible = "fsl,layerscape-dwc3";
+ reg = <0x0 0x3100000 0x0 0x10000>;
+ interrupts = <0 80 0x4>; /* Level high type */
+ dr_mode = "host";
+ };
+
+ usb1: usb3@3110000 {
+ compatible = "fsl,layerscape-dwc3";
+ reg = <0x0 0x3110000 0x0 0x10000>;
+ interrupts = <0 81 0x4>; /* Level high type */
+ dr_mode = "host";
+ };
+
pcie@3400000 {
compatible = "fsl,ls-pcie", "snps,dw-pcie";
reg = <0x00 0x03400000 0x0 0x80000 /* dbi registers */
diff --git a/board/freescale/ls1088a/ls1088a.c b/board/freescale/ls1088a/ls1088a.c
index 96d9ae7f1d..2156537a27 100644
--- a/board/freescale/ls1088a/ls1088a.c
+++ b/board/freescale/ls1088a/ls1088a.c
@@ -49,7 +49,6 @@ int checkboard(void)
static const char *const freq[] = {"100", "125", "156.25",
"100 separate SSCG"};
int clock;
-
#ifdef CONFIG_TARGET_LS1088AQDS
printf("Board: LS1088A-QDS, ");
#else
diff --git a/configs/ls1088ardb_qspi_defconfig b/configs/ls1088ardb_qspi_defconfig
index 2d5a134261..3034f506e2 100644
--- a/configs/ls1088ardb_qspi_defconfig
+++ b/configs/ls1088ardb_qspi_defconfig
@@ -31,3 +31,11 @@ CONFIG_FSL_DSPI=y
CONFIG_EFI_LOADER_BOUNCE_BUFFER=y
# CONFIG_DISPLAY_BOARDINFO is not set
CONFIG_FSL_LS_PPA=y
+CONFIG_USB=y
+CONFIG_USB_GADGET=y
+CONFIG_CMD_USB=y
+CONFIG_DM_USB=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_XHCI_DWC3=y
+CONFIG_USB_DWC3=y
+CONFIG_USB_STORAGE=y
diff --git a/include/linux/usb/xhci-fsl.h b/include/linux/usb/xhci-fsl.h
index bd54089722..a916afb885 100644
--- a/include/linux/usb/xhci-fsl.h
+++ b/include/linux/usb/xhci-fsl.h
@@ -58,7 +58,7 @@ struct fsl_xhci {
#define CONFIG_SYS_FSL_XHCI_USB1_ADDR CONFIG_SYS_XHCI_USB1_ADDR
#define CONFIG_SYS_FSL_XHCI_USB2_ADDR 0
#define CONFIG_SYS_FSL_XHCI_USB3_ADDR 0
-#elif defined(CONFIG_ARCH_LS2080A)
+#elif defined(CONFIG_ARCH_LS2080A) || defined(CONFIG_ARCH_LS1088A)
#define CONFIG_SYS_FSL_XHCI_USB1_ADDR CONFIG_SYS_XHCI_USB1_ADDR
#define CONFIG_SYS_FSL_XHCI_USB2_ADDR CONFIG_SYS_XHCI_USB2_ADDR
#define CONFIG_SYS_FSL_XHCI_USB3_ADDR 0
--
2.14.1
2
3
Simon & Alexander,
It appears our setjmp/longjmp prototypes and implementations are
in non-compliance with current C-standards (I checked against
both C99 and C2011).
U-Boot defines setjmp as:
int setjmp(struct jmp_buf_data *jmp_buf)
The standard however requires
int setjmp(jmp_buf env)
and has additional guidance regarding the definition of ‘jmp_buf’:
"The type declared is jmp_buf which is an array type suitable
for holding the information needed to restore a calling
environment."
Note that I just reworked the ARM versions: i.e. here we now are
in compliance. Even with this rework, I need to expose 'struct
jmp_buf_data’ (which should be an implementation detail) as this
is explicitly referenced from EFI code.
If agreeable for the EFI side, I'd like to change the remaining
implementations to also comply with the standard, which is easy
enough on by adding a 'typedef struct jmp_buf_data jmp_buf[1]'.
This would also allow us to have a single 'setjmp.h' that just
includes an arch-specific 'asm/setjmp.h' to retrieve the 'struct
jmp_buf_data' definition.
Note that this will entail changes to the EFI code by replacing
all occurrences where 'struct jmp_buf_data' is used or the
address of a 'struct jmp_buf_data' struct-member is
taken (i.e. all call-sites for setjmp/longjmp).
If this is a showstopper to the EFI implementation, let me know…
Regards,
Philipp.
3
2
Mods to:
cmd/net.cnet/Makefilenet/net.cinclude/net.hnet/wget.cnet/wget.hnet/ping.c
I do not know how to do patches, I'm a noobat this:
cmd/net.c
Additions
static int do_wget(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]){ return netboot_common(WGET, cmdtp, argc, argv);}
U_BOOT_CMD( wget, 3, 1, do_wget, "boot image via network using HTTP protocol", "[loadAddress] [[hostIPaddr:]bootfilename]");
net/Makefile addition
obj-$(CONFIG_CMD_NFS) += wget.o
net.c complete, look for #ifdef TCP
/*
* Copied from Linux Monitor (LiMon) - Networking.
*
* Copyright 1994 - 2000 Neil Russell.
* (See License)
* Copyright 2000 Roland Borde
* Copyright 2000 Paolo Scaffardi
* Copyright 2000-2002 Wolfgang Denk, wd(a)denx.de
* Copyright 2017-2018 Duncan Hare, dh(a)synoia.com
* SPDX-License-Identifier: GPL-2.0
*/
#define TCP 1
/*
* General Desription:
*
* The user interface supports commands for BOOTP, RARP, and TFTP.
* Also, we support ARP internally. Depending on available data,
* these interact as follows:
*
* BOOTP:
*
* Prerequisites: - own ethernet address
* We want: - own IP address
* - TFTP server IP address
* - name of bootfile
* Next step: ARP
*
* LINK_LOCAL:
*
* Prerequisites: - own ethernet address
* We want: - own IP address
* Next step: ARP
*
* RARP:
*
* Prerequisites: - own ethernet address
* We want: - own IP address
* - TFTP server IP address
* Next step: ARP
*
* ARP:
*
* Prerequisites: - own ethernet address
* - own IP address
* - TFTP server IP address
* We want: - TFTP server ethernet address
* Next step: TFTP
*
* DHCP:
*
* Prerequisites: - own ethernet address
* We want: - IP, Netmask, ServerIP, Gateway IP
* - bootfilename, lease time
* Next step: - TFTP
*
* TFTP:
*
* Prerequisites: - own ethernet address
* - own IP address
* - TFTP server IP address
* - TFTP server ethernet address
* - name of bootfile (if unknown, we use a default name
* derived from our own IP address)
* We want: - load the boot file
* Next step: none
*
* NFS:
*
* Prerequisites: - own ethernet address
* - own IP address
* - name of bootfile (if unknown, we use a default name
* derived from our own IP address)
* We want: - load the boot file
* Next step: none
*
* SNTP:
*
* Prerequisites: - own ethernet address
* - own IP address
* We want: - network time
* Next step: none
*
* HTTP/TCP Receiver:
*
* Prequeisites: - own ethernet adress
* - own IP address
* - Server IP address
* - HTP client
* - Bootfile path & name
* We want: - Load the Boot file
* Next Step HTTPS?
*/
#define DEBUG_DCH_PKT 1
#define DEBUG_TCP_PKT 0
#include <common.h>
#include <command.h>
#include <console.h>
#include <environment.h>
#include <errno.h>
#include <net.h>
#include <net/tftp.h>
#if defined(CONFIG_STATUS_LED)
#include <miiphy.h>
#include <status_led.h>
#endif
#include <watchdog.h>
#include <linux/compiler.h>
#include "arp.h"
#include "bootp.h"
#include "cdp.h"
#if defined(CONFIG_CMD_DNS)
#include "dns.h"
#endif
#include "link_local.h"
#include "nfs.h"
#include "wget.h"
#include "ping.h"
#include "rarp.h"
#if defined(CONFIG_CMD_SNTP)
#include "sntp.h"
#endif
DECLARE_GLOBAL_DATA_PTR;
/** BOOTP EXTENTIONS **/
/* Our subnet mask (0=unknown) */
struct in_addr net_netmask;
/* Our gateways IP address */
struct in_addr net_gateway;
/* Our DNS IP address */
struct in_addr net_dns_server;
#if defined(CONFIG_BOOTP_DNS2)
/* Our 2nd DNS IP address */
struct in_addr net_dns_server2;
#endif
#ifdef CONFIG_MCAST_TFTP /* Multicast TFTP */
struct in_addr net_mcast_addr;
#endif
/** END OF BOOTP EXTENTIONS **/
/* Our ethernet address */
u8 net_ethaddr[6];
/* Boot server enet address */
u8 net_server_ethaddr[6];
/* Our IP addr (0 = unknown) */
struct in_addr net_ip;
/* Server IP addr (0 = unknown) */
struct in_addr net_server_ip;
/* Port numbers */
int dport;
int sport;
/* Current receive packet */
uchar *net_rx_packet;
/* Current rx max packet length */
int net_rx_packet_len;
/* IP packet ID */
static unsigned net_ip_id;
/* Ethernet bcast address */
const u8 net_bcast_ethaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
const u8 net_null_ethaddr[6];
#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
void (*push_packet)(void *, int len) = 0;
#endif
/* Network loop state */
enum net_loop_state net_state;
/* Tried all network devices */
int net_restart_wrap;
/* Network loop restarted */
static int net_restarted;
/* At least one device configured */
static int net_dev_exists;
#ifdef TCP
/* TCP sliding window control */
static u32 tcp_next_expected_seq_num;
static struct tcp_sack_v tcp_lost; /* used by us to request re-TX */
struct w_manage {
struct sack_edges tcp_hole;
enum acked { FALSE, TRUE, FILLED } sent;
int age;
};
static int tcp_max_hole;
struct w_manage holes[TCP_STREAM_HOLES];
/* TCP option timestamp */
static u32 loc_timestamp;
static u32 rmt_timestamp;
/* TCP connection state */
static enum TCP_STATE tcp_state;
#endif
/* XXX in both little & big endian machines 0xFFFF == ntohs(-1) */
/* default is without VLAN */
ushort net_our_vlan = 0xFFFF;
/* ditto */
ushort net_native_vlan = 0xFFFF;
/* Boot File name */
char net_boot_file_name[1024];
/* The actual transferred size of the bootfile (in bytes) */
u32 net_boot_file_size;
/* Boot file size in blocks as reported by the DHCP server */
u32 net_boot_file_expected_size_in_blocks;
#if defined(CONFIG_CMD_SNTP)
/* NTP server IP address */
struct in_addr net_ntp_server;
/* offset time from UTC */
int net_ntp_time_offset;
#endif
static uchar net_pkt_buf[(PKTBUFSRX+1) * PKTSIZE_ALIGN + PKTALIGN];
/* Receive packets */
uchar *net_rx_packets[PKTBUFSRX];
/*
* An incoming TCP packet handler for the TCP protocol.
* There is also a dymanic function pointer for TCP based commads to
* receive incoming traffic after the TCP protocol code has done its work.
*/
void rxhand_tcp_f( union tcp_build_pkt *b, unsigned len);
/* Current TCP RX packet handler */
static rxhand_f *tcp_packet_handler;
/* Current UDP RX packet handler */
static rxhand_f *udp_packet_handler;
/* Current ARP RX packet handler */
static rxhand_f *arp_packet_handler;
#ifdef CONFIG_CMD_TFTPPUT
/* Current ICMP rx handler */
static rxhand_icmp_f *packet_icmp_handler;
#endif
/* Current timeout handler */
static thand_f *time_handler;
/* Time base value */
static ulong time_start;
/* Current timeout value */
static ulong time_delta;
/* THE transmit packet */
uchar *net_tx_packet;
static int net_check_prereq(enum proto_t protocol);
static int net_try_count;
int __maybe_unused net_busy_flag;
/**********************************************************************/
static int on_bootfile(const char *name, const char *value, enum env_op op,
int flags)
{
if (flags & H_PROGRAMMATIC)
return 0;
switch (op) {
case env_op_create:
case env_op_overwrite:
copy_filename(net_boot_file_name, value,
sizeof(net_boot_file_name));
break;
default:
break;
}
return 0;
}
U_BOOT_ENV_CALLBACK(bootfile, on_bootfile);
static int on_ipaddr(const char *name, const char *value, enum env_op op,
int flags)
{
if (flags & H_PROGRAMMATIC)
return 0;
net_ip = string_to_ip(value);
return 0;
}
U_BOOT_ENV_CALLBACK(ipaddr, on_ipaddr);
static int on_gatewayip(const char *name, const char *value, enum env_op op,
int flags)
{
if (flags & H_PROGRAMMATIC)
return 0;
net_gateway = string_to_ip(value);
return 0;
}
U_BOOT_ENV_CALLBACK(gatewayip, on_gatewayip);
static int on_netmask(const char *name, const char *value, enum env_op op,
int flags)
{
if (flags & H_PROGRAMMATIC)
return 0;
net_netmask = string_to_ip(value);
return 0;
}
U_BOOT_ENV_CALLBACK(netmask, on_netmask);
static int on_serverip(const char *name, const char *value, enum env_op op,
int flags)
{
if (flags & H_PROGRAMMATIC)
return 0;
net_server_ip = string_to_ip(value);
return 0;
}
U_BOOT_ENV_CALLBACK(serverip, on_serverip);
static int on_nvlan(const char *name, const char *value, enum env_op op,
int flags)
{
if (flags & H_PROGRAMMATIC)
return 0;
net_native_vlan = string_to_vlan(value);
return 0;
}
U_BOOT_ENV_CALLBACK(nvlan, on_nvlan);
static int on_vlan(const char *name, const char *value, enum env_op op,
int flags)
{
if (flags & H_PROGRAMMATIC)
return 0;
net_our_vlan = string_to_vlan(value);
return 0;
}
U_BOOT_ENV_CALLBACK(vlan, on_vlan);
#if defined(CONFIG_CMD_DNS)
static int on_dnsip(const char *name, const char *value, enum env_op op,
int flags)
{
if (flags & H_PROGRAMMATIC)
return 0;
net_dns_server = string_to_ip(value);
return 0;
}
U_BOOT_ENV_CALLBACK(dnsip, on_dnsip);
#endif
/*
* Check if autoload is enabled. If so, use either NFS or TFTP to download
* the boot file.
*/
void net_auto_load(void)
{
#if defined(CONFIG_CMD_NFS)
const char *s = getenv("autoload");
if (s != NULL && strcmp(s, "NFS") == 0) {
/*
* Use NFS to load the bootfile.
*/
nfs_start();
return;
}
#endif
if (getenv_yesno("autoload") == 0) {
/*
* Just use BOOTP/RARP to configure system;
* Do not use TFTP to load the bootfile.
*/
net_set_state(NETLOOP_SUCCESS);
return;
}
tftp_start(TFTPGET);
}
static void net_init_loop(void)
{
if (eth_get_dev())
memcpy(net_ethaddr, eth_get_ethaddr(), 6);
return;
}
static void net_clear_handlers(void)
{
net_set_tcp_handler(NULL);
net_set_udp_handler(NULL);
net_set_arp_handler(NULL);
net_set_timeout_handler(0, NULL);
}
static void net_cleanup_loop(void)
{
net_clear_handlers();
}
void net_set_ports( int server_port, int our_port )
{
dport = server_port;
sport = our_port;
}
#ifdef TCP
enum TCP_STATE net_get_tcp_state( void )
{
return(tcp_state);
}
void net_print_buffer( uchar raw[], int pkt_len, int payload_len, int hdr_len, bool hide )
{
int i;
for ( i = pkt_len - payload_len; i < pkt_len; i++ )
{
if ( i <= hdr_len )
{
printf("%02X", raw[i]);
}
else if (( raw[i] > 0x19 ) && ( raw[i] < 0x7f ))
{
putc( raw[i] );
}
else if (hide == 0 ) putc( raw[i] );
else printf("%02X", raw[i]);
// else printf ("%s",".");
}
printf ( "%s", "\n" );
}
int net_find_in_buffer( uchar raw[], int payload_len, uchar field[], int field_len )
{
int i,j;
for (i = 0; i < payload_len; i ++ )
{
if ( raw[i] == field[0] )
{
for (j = 1; j < field_len; j++ )
{
if ( raw[i+j] != field[j] ) break;
}
if ( j == field_len ) return( i );
}
}
return ( 0 );
}
u16 net_set_psuedo_header( uchar * pkt, struct in_addr src, struct in_addr dest, int tcp_len, int pkt_len )
{
union tcp_build_pkt *b = (union tcp_build_pkt *) pkt;
int checksum_len;
/*
* Psuedo header
*/
pkt[ pkt_len ] = 0x00;
net_copy_ip((void *)&b->ph.p_src, &src);
net_copy_ip((void *)&b->ph.p_dst, &dest);
b->ph.rsvd = 0x00;
b->ph.p = IPPROTO_TCP;
b->ph.len = htons(tcp_len);
checksum_len = tcp_len + PSUEDO_HDR_SIZE;
debug_cond(DEBUG_DEV_PKT,
"TCP Psuedo Header (to=%pI4, from=%pI4, CheckLen=%d)\n",
&b->ph.p_dst, &b->ph.p_src, checksum_len );
/*
* If the data is an odd number of bytes, zero the
* byte after the last byte so that the header checksum
* will work.
*/
return( compute_ip_checksum( pkt + PSUEDO_PAD_SIZE, checksum_len ));
}
int net_set_ack_options( union tcp_build_pkt *b )
{
b->sack.hdr.tcp_hlen = ( TCP_HDR_SIZE >>2 ) << 4;
b->sack.TSopt.kind = TCP_O_TS;
b->sack.TSopt.len = TCP_OPT_LEN_A;
b->sack.TSopt.TSsnd = htons(loc_timestamp);
b->sack.TSopt.TSrcv = rmt_timestamp;
b->sack.sack_v.kind = 0x01;
b->sack.sack_v.len = 0x00;
if ( tcp_lost.len > 0 )
{
b->sack.sack_v.len = tcp_lost.len;
b->sack.sack_v.kind = TCP_V_SACK;
b->sack.sack_v.hole[1].l = htonl(tcp_lost.hole[1].l);
b->sack.sack_v.hole[1].r = htonl(tcp_lost.hole[1].r);
/*
* These fields are initialized with NOPs to
* provide TCP header alignment padding
*/
b->sack.sack_v.hole[2].l = htonl(tcp_lost.hole[1].l);
b->sack.sack_v.hole[2].r = htonl(tcp_lost.hole[1].r);
b->sack.sack_v.hole[3].l = htonl(tcp_lost.hole[2].l);
b->sack.sack_v.hole[3].r = htonl(tcp_lost.hole[2].r);
tcp_lost.len = 0;
}
b->sack.hdr.tcp_hlen = (((TCP_HDR_SIZE + TCP_TSOPT_SIZE + tcp_lost.len + 3) >> 2) << 4);
return( b->sack.hdr.tcp_hlen >> 2);
}
void net_set_syn_options( union tcp_build_pkt *b )
{
tcp_lost.len = 0;
b->ip.hdr.tcp_hlen = 0xa0; /* hdr 10 32 bit words */
b->ip.mss.kind = TCP_O_MSS;
b->ip.mss.len = TCP_OPT_LEN_4;
b->ip.mss.mss = htons(TCP_MSS); /* tunable parameter */
b->ip.scale.kind = TCP_O_SCL;
b->ip.scale.scale = TCP_SCALE; /* tunable parameter */
b->ip.scale.len = TCP_OPT_LEN_3;
b->ip.sack_p.kind = TCP_P_SACK ; /* SACK supported */
b->ip.sack_p.len = TCP_OPT_LEN_2;
b->ip.TSopt.kind = TCP_O_TS;
b->ip.TSopt.len = TCP_OPT_LEN_A;
loc_timestamp = get_ticks() % 3072;
rmt_timestamp = 0x00000000;
b->ip.TSopt.TSsnd = 0;
b->ip.TSopt.TSrcv = 0x00000000;
b->ip.end = TCP_O_END;
}
int net_set_tcp_header(uchar *pkt, int payload_len, u8 action, u32 tcp_seq_num, u32 tcp_ack_num )
{
union tcp_build_pkt *b = (union tcp_build_pkt *) pkt;
int pkt_hdr_len;
int pkt_len;
int tcp_len;
b->ip.hdr.tcp_flags = action;
pkt_hdr_len = IP_TCP_HDR_SIZE;
b->ip.hdr.tcp_hlen = 0x50; /* Header is 5 32 bit words */
/* 4 bits TCP header Length/4 */
/* 4 bits Reserved */
switch (action) /* For options */
{
case TCP_SYN:
debug_cond(DEBUG_TCP_PKT,
"TCP Header:SYN (to=%pI4, from=%pI4, TCPseq=%d, TCPack=%d)\n",
&net_server_ip, &net_ip, tcp_seq_num, tcp_ack_num);
net_set_syn_options( b );
tcp_seq_num = 0; /* TCP sequence number */
tcp_ack_num = 0; /* TCP Ack Number */
pkt_hdr_len = IP_TCP_O_SIZE;
if ( tcp_state == TCP_SYN_SENT) /* Too many sins */
{
action = TCP_FIN;
tcp_state = TCP_FIN_WAIT_1;
}
else tcp_state = TCP_SYN_SENT;
break;
case TCP_ACK:
pkt_hdr_len = IP_HDR_SIZE + net_set_ack_options( b );
b->ip.hdr.tcp_flags = action;
debug_cond(DEBUG_TCP_PKT,
"TCP Header:ACK (to=%pI4, from=%pI4, TCPseq=%d, TCPack=%d, Action=%x)\n",
&net_server_ip, &net_ip, tcp_seq_num, tcp_ack_num, b->ip.hdr.tcp_flags);
break;
case TCP_FIN:
debug_cond(DEBUG_TCP_PKT,
"TCP Header:FIN (to=%pI4, from=%pI4, TCPseq=%d, TCPack=%d)\n",
&net_server_ip, &net_ip, tcp_seq_num, tcp_ack_num);
payload_len = 0;
pkt_hdr_len = IP_TCP_HDR_SIZE;
tcp_state = TCP_FIN_WAIT_1;
tcp_seq_num++;
break;
case (TCP_FIN + TCP_ACK):
case (TCP_FIN + TCP_ACK + TCP_PUSH):
if ( tcp_state == TCP_CLOSE_WAIT ) tcp_state = TCP_CLOSING;
default:
pkt_hdr_len = IP_HDR_SIZE + net_set_ack_options( b );
b->ip.hdr.tcp_flags = action | TCP_PUSH | TCP_ACK;
debug_cond(DEBUG_TCP_PKT,
"TCP Header:default (to=%pI4, from=%pI4, TCPseq=%d, TCPack=%d, Action=%x)\n",
&net_server_ip, &net_ip, tcp_seq_num, tcp_ack_num, b->ip.hdr.tcp_flags);
}
pkt_len = pkt_hdr_len + payload_len;
tcp_len = pkt_len - IP_HDR_SIZE;
/*
* TCP Header
*/
b->ip.hdr.tcp_ack = htonl( tcp_ack_num);
b->ip.hdr.tcp_src = htons(sport);
b->ip.hdr.tcp_dst = htons(dport);
b->ip.hdr.tcp_seq = htonl(tcp_seq_num);
tcp_seq_num = tcp_seq_num + payload_len;
/*
* TCP window size - TCP header variable tcp_win.
* Chage tcp_win only if you have an understanding of network overruun, congestion,
* TCP segment sizes, TCP windows, TCP scale, queuing theory and packet buffering.
* If there are too few buffers, there will be data loss, recovery may work or the
* sending TCP, the server, could abort the stream transmission.
* MSS is governed by maximum Ethernet frame langth.
* The number of buffers is governed by the desire to have a queue of full buffers
* to be processed at the destination to maximize throughput.
* Temporary memory use for the boot phase on modern SOCs is not considered a constraint to
* buffer space.
*/
b->ip.hdr.tcp_win = htons( PKTBUFSRX * TCP_MSS >> TCP_SCALE );
b->ip.hdr.tcp_xsum = 0x0000; /* Checksum */
b->ip.hdr.tcp_ugr = 0x0000; /* Pointer to urgent data */
b->ip.hdr.tcp_xsum = net_set_psuedo_header( pkt, net_ip, net_server_ip, tcp_len, pkt_len );
/*
* IP Header
*/
net_set_ip_header((uchar *) &b->ip, net_server_ip, net_ip, pkt_len, IPPROTO_TCP);
return ( pkt_hdr_len );
}
#endif
int net_send_ip_packet( int payload_len, int proto, u8 action, u32 tcp_seq_num, u32 tcp_ack_num )
{
uchar *pkt;
int eth_hdr_size;
int pkt_hdr_size;
uchar * ether = net_server_ethaddr;
if ( proto == IPPROTO_UDP )
{ debug_cond(DEBUG_DEV_PKT,
"UDP Send (to=%pI4, from=%pI4, len=%d)\n",
&net_server_ip, &net_ip, payload_len);
}
#ifdef TCP
else
{ debug_cond(DEBUG_TCP_PKT,
"TCP Send (to=%pI4, from=%pI4, len=%d, Action=%x)\n",
&net_server_ip, &net_ip, payload_len, action );
}
#endif
/* make sure the net_tx_packet is initialized (net_init() was called) */
assert(net_tx_packet != NULL);
if (net_tx_packet == NULL) return -1;
/* convert to new style broadcast */
if (net_server_ip.s_addr == 0) net_server_ip.s_addr = 0xFFFFFFFF;
/* if broadcast, make the ether address a broadcast and don't do ARP */
if (net_server_ip.s_addr == 0xFFFFFFFF) ether = (uchar *)net_bcast_ethaddr;
pkt = (uchar *)net_tx_packet;
/*
*Get ethernet header size and write the ethernet header
*/
eth_hdr_size = net_set_ether(pkt, ether, PROT_IP);
#ifdef TCP
if (proto == IPPROTO_UDP )
{
#endif
net_set_udp_header(pkt + eth_hdr_size, net_server_ip, dport, sport, payload_len);
pkt_hdr_size = IP_UDP_HDR_SIZE;
eth_hdr_size = eth_hdr_size + pkt_hdr_size;
#ifdef TCP
}
else pkt_hdr_size = eth_hdr_size + net_set_tcp_header(pkt + eth_hdr_size,
payload_len, action, tcp_seq_num, tcp_ack_num );
#endif
/* if MAC address was not discovered yet, do an ARP request */
if (memcmp(ether, net_null_ethaddr, 6) == 0) {
debug_cond(DEBUG_DEV_PKT, "sending ARP for %pI4\n", &net_server_ip);
/* save the ip and eth addr for the packet to send after arp */
net_arp_wait_packet_ip = net_server_ip;
arp_wait_packet_ethaddr = ether;
/* size of the waiting packet */
arp_wait_tx_packet_size = pkt_hdr_size + payload_len;
/* and do the ARP request */
arp_wait_try = 1;
arp_wait_timer_start = get_timer(0);
arp_request();
return 1; /* waiting */
} else {
debug_cond(DEBUG_DEV_PKT, "sending TCP to %pI4/%pM/%d\n",
&net_server_ip, ether, pkt_hdr_size + payload_len);
net_send_packet(net_tx_packet, pkt_hdr_size + payload_len);
return 0; /* transmitted */
}
}
#ifdef TCP
int tcp_hole_age ( int age )
{
int i, j = 0, filled = 0;
tcp_lost.len = TCP_OPT_LEN_2;
tcp_lost.hole[1].l = TCP_O_NOP;
tcp_lost.hole[1].r = TCP_O_NOP;
tcp_lost.hole[2].l = TCP_O_NOP;
tcp_lost.hole[2].r = TCP_O_NOP;
tcp_lost.kind = TCP_V_SACK;
for (i = 0; (( i == tcp_max_hole ) || ( j == 2 )) ; i++ )
{
if (( holes[i].tcp_hole.l != 0 ) && ( holes[i].sent == FALSE ))
{
if ( holes[i].age <= TCP_HOLE_AGE ) holes[i].age++;
else
{
/*
* Ask for hole to be filled by sender on next ack response.
*/
tcp_lost.len = tcp_lost.len + TCP_OPT_LEN_8;
tcp_lost.hole[j].l = holes[i].tcp_hole.l;
tcp_lost.hole[j].l = holes[i].tcp_hole.r;
holes[i].sent = TRUE;
j++;
}
}
if (( holes[i].tcp_hole.l == 0 ) || ( holes[i].sent == FILLED )) filled++;
switch (holes[i].sent)
{
case FALSE:
debug_cond( DEBUG_DCH_PKT, ".");
break;
case TRUE:
debug_cond( DEBUG_DCH_PKT, "o");
break;
case FILLED:
debug_cond( DEBUG_DCH_PKT, "|");
break;
}
}
debug_cond( DEBUG_DCH_PKT, "\n");
/*
* No holes found? Set return code.
*/
if ( tcp_lost.len == TCP_OPT_LEN_2 )
{
tcp_lost.len = 0;
return ( filled - tcp_max_hole );
}
else return ( 1 );
}
void tcp_hole_fill( u32 tcp_left, u32 tcp_right )
{
int i ,j;
for ( i = 0; (( i = tcp_max_hole ) || ( tcp_left != holes[i].tcp_hole.l )); i++ );
if ( tcp_left == holes[i].tcp_hole.l )
{
holes[i].sent = FILLED;
/*
* Move holes to down hole array as preceeding holes become filled
*/
for ( j = i; (j < tcp_max_hole); j++ )
{
holes[j] = holes[j + 1];
}
}
else debug_cond( DEBUG_DCH_PKT, "Error: Hole not found: Left=%d\n", tcp_left );
}
void tcp_hole_create( u32 tcp_left, u32 tcp_right )
{
debug_cond( 1, "Hole Created Left=%d\n", tcp_left );
tcp_lost.len = tcp_lost.len + TCP_OPT_LEN_A;
tcp_lost.hole[0].l = tcp_left;
tcp_lost.hole[0].l = tcp_right;
tcp_lost.hole[1].l = TCP_O_NOP;
tcp_lost.hole[1].r = TCP_O_NOP;
tcp_lost.hole[2].l = TCP_O_NOP;
tcp_lost.hole[2].r = TCP_O_NOP;
}
void tcp_hole_create_complex( u32 tcp_left, u32 tcp_right )
{
int i;
for (i = 0; i < TCP_STREAM_HOLES; i++ )
{
/*
* Find empty hole struct and fill it
*/
if ( holes[i].tcp_hole.l == 0 )
holes[i].tcp_hole.l = tcp_left;
holes[i].tcp_hole.r = tcp_right;
holes[i].sent = FALSE;
holes[i].age = 0;
if ( i > tcp_max_hole ) tcp_max_hole = i;
return;
}
debug_cond( 1, "Error: Too many TCP erorrs, increase TCP_STREAM_HOLES or get a better network\n");
net_set_state(NETLOOP_FAIL);
}
void init_tcp_holes( u32 tcp_seq_num )
{
int i;
for (i = 0; i < TCP_STREAM_HOLES; i++)
{
holes[i].tcp_hole.l = 0;
holes[i].tcp_hole.r = 0;
holes[i].sent = FALSE;
holes[i].age = 0;
}
tcp_next_expected_seq_num = tcp_seq_num;
/*
* // For production set to 0.
* // For testingt set to TCP_STREAM_HOLES - 1
*/
tcp_max_hole = TCP_STREAM_HOLES - 1; // For testing.
// For production set 0.
}
void tcp_parse_options( uchar *o, int o_len)
{
struct tcp_TSopt *tsopt;
uchar *p = o;
for ( p = o; p < (o + o_len); p = p + p[1])
{
if (p[1] == 0) return;
else
{
switch ( p[0] )
{
case TCP_O_END: return;
case TCP_O_MSS:
break;
case TCP_O_SCL:
break;
case TCP_P_SACK:
break;
case TCP_V_SACK:
break;
case TCP_O_TS :
tsopt = (struct tcp_TSopt *) p;
rmt_timestamp = tsopt->TSsnd;
return;
break;
}
if (p[0] == TCP_O_NOP) p++;
}
}
return;
}
u8 tcp_state_machine( u8 tcp_flags, u32 *tcp_seq_num, int payload_len )
{
u8 tcp_fin = tcp_flags & TCP_FIN;
u8 tcp_syn = tcp_flags & TCP_SYN;
u8 tcp_rst = tcp_flags & TCP_RST;
u8 tcp_push = tcp_flags & TCP_PUSH;
u8 tcp_ack = tcp_flags & TCP_ACK;
u8 tcp_urg = tcp_flags & TCP_URG;
u8 tcp_ece = tcp_flags & TCP_ECE;
u8 tcp_cwr = tcp_flags & TCP_CWR;
u8 action = TCP_DATA;
/*
* tcp_flags are examined to determine TX action in a given state
* tcp_options, if not zero, is a pointer to the TCP options,
* to extract the receive timestamp value
*/
/*
* These flags are not supported.
*/
if (tcp_urg) action = action;
if (tcp_ece) action = action;
if (tcp_cwr) action = action;
debug_cond(DEBUG_INT_STATE, "TCP STATE ENTRY (%x)\n", action);
if (tcp_rst)
{
action = TCP_DATA;
tcp_state = TCP_CLOSED;
net_set_state( NETLOOP_FAIL );
debug_cond(DEBUG_DCH_PKT, "TCP Reset (%x)\n", tcp_flags);
}
else switch (tcp_state)
{
case TCP_CLOSED: /* Should never happen */
debug_cond(DEBUG_TCP_PKT, "TCP CLOSED (%x)\n", tcp_flags);
if (tcp_fin) action = TCP_DATA;
if (tcp_syn) action = TCP_RST;
if (tcp_ack) action = TCP_DATA;
break;
case TCP_SYN_SENT:
debug_cond(DEBUG_TCP_PKT, "TCP_SYN_SENT (%x), %d\n", tcp_flags, *tcp_seq_num);
if (tcp_fin) {action = action | TCP_PUSH; tcp_state = TCP_CLOSE_WAIT;}
if (tcp_syn)
{
action = action | TCP_ACK;
if (tcp_ack)
{
*tcp_seq_num = *tcp_seq_num + 1;
tcp_state = TCP_ESTABLISHED; /* SACK */
action = action | TCP_PUSH; /* Notify app */
init_tcp_holes( *tcp_seq_num );
}
}
else
if (tcp_ack) action = TCP_DATA;
break;
case TCP_ESTABLISHED:
debug_cond(DEBUG_TCP_PKT, "TCP_ESTABLISHED (%x)\n", tcp_flags );
if (tcp_fin)
{ /*
* Check for holes !!
*/
*tcp_seq_num = *tcp_seq_num + 1;
tcp_next_expected_seq_num ++;
action = action | TCP_FIN | TCP_PUSH | TCP_ACK;
tcp_state = TCP_CLOSE_WAIT;
}
else if (tcp_ack) action = TCP_DATA;
if (tcp_push) action = action | TCP_PUSH;
if (tcp_syn) action = TCP_ACK + TCP_RST;
/* tcp_hole_age( TCP_HOLE_AGE );
if (*tcp_seq_num < tcp_next_expected_seq_num )
tcp_hole_fill( *tcp_seq_num, payload_len );
else
{
*/ if (*tcp_seq_num > tcp_next_expected_seq_num )
{
tcp_hole_create( tcp_next_expected_seq_num, *tcp_seq_num );
debug_cond(DEBUG_DCH_PKT,
"TCP_ESTABLISHED Seq In %x, Exp %x, action %x\n",
*tcp_seq_num, tcp_next_expected_seq_num, action);
}
if (*tcp_seq_num != tcp_next_expected_seq_num )
net_set_state( NETLOOP_FAIL );
else tcp_next_expected_seq_num = *tcp_seq_num + payload_len;
/* }
*/
debug_cond(DEBUG_TCP_PKT, "TCP_ESTABLISHED (%x), %d\n", action, *tcp_seq_num);
break;
case TCP_CLOSE_WAIT:
debug_cond(DEBUG_TCP_PKT, "TCP_CLOSE_WAIT (%x)\n", tcp_flags);
action = TCP_DATA; /* Wait for app */
break;
case TCP_FIN_WAIT_2:
debug_cond(DEBUG_TCP_PKT, "TCP_FIN_WAIT_2 (%x)\n", tcp_flags);
if (tcp_fin) action = TCP_DATA;
if (tcp_syn) action = TCP_DATA;
if (tcp_ack) {action = TCP_PUSH | TCP_ACK; tcp_state = TCP_CLOSED;}
break;
case TCP_FIN_WAIT_1:
debug_cond(DEBUG_DCH_PKT, "TCP_FIN_WAIT_1 (%x)\n", tcp_flags);
if (tcp_fin) action = TCP_ACK | TCP_FIN; tcp_state = TCP_FIN_WAIT_2 ;
if (tcp_syn) action = TCP_RST;
if (tcp_ack) {tcp_state = TCP_CLOSED; *tcp_seq_num = *tcp_seq_num + 1;}
net_set_state( NETLOOP_FAIL );
break;
case TCP_CLOSING:
debug_cond(DEBUG_TCP_PKT, "TCP_CLOSING (%x)\n", tcp_flags);
if (tcp_fin) action = TCP_DATA;
if (tcp_syn) action = TCP_RST;
if (tcp_ack) {action = TCP_DATA; tcp_state = TCP_CLOSED;}
break;
}
return( action );
}
void rxhand_tcp_f( union tcp_build_pkt *b, unsigned pkt_len )
{
int tcp_len = pkt_len - IP_HDR_SIZE;
u16 tcp_rx_xsum = b->ip.hdr.ip_sum;
u8 tcp_action = TCP_DATA;
u8 net_action = TCP_DATA;
u32 tcp_seq_num;
u32 tcp_ack_num;
struct in_addr action_and_state;
int tcp_hdr_len;
int payload_len;
/*
* Verify ip header
*/
debug_cond(DEBUG_TCP_PKT,
"TCP RX in RX Sum (to=%pI4, from=%pI4, len=%d)\n",
&b->ip.hdr.ip_src, &b->ip.hdr.ip_dst, pkt_len);
debug_cond(DEBUG_TCP_PKT,
"____________________________________________\n");
b->ip.hdr.ip_src = net_server_ip;
b->ip.hdr.ip_dst = net_ip;
b->ip.hdr.ip_sum = 0x0000;
if (tcp_rx_xsum != compute_ip_checksum(b, IP_HDR_SIZE))
{
debug_cond(DEBUG_TCP_PKT,
"TCP RX IP xum Error (to=%pI4, from=%pI4, len=%d)\n",
&net_ip, &net_server_ip, pkt_len);
return;
}
/*
* Build Pseudo header and Verify TCP header
*/
tcp_rx_xsum = b->ip.hdr.tcp_xsum;
b->ip.hdr.tcp_xsum = 0x0000;
if (tcp_rx_xsum != net_set_psuedo_header((uchar *)b, b->ip.hdr.ip_src,
b->ip.hdr.ip_dst, tcp_len, pkt_len ))
{
debug_cond(DEBUG_TCP_PKT,
"TCP RX TCP xSum Error (to=%pI4, from=%pI4, len=%d)\n",
&net_ip, &net_server_ip, tcp_len);
return;
}
tcp_hdr_len = ( b->ip.hdr.tcp_hlen >> 2);
payload_len = tcp_len - tcp_hdr_len;
if (tcp_hdr_len > TCP_HDR_SIZE)
tcp_parse_options((uchar *) b + IP_TCP_HDR_SIZE,
tcp_hdr_len - TCP_HDR_SIZE );
/*
* Incoming sequence and ack numbers are server's view of the numbers.
* The app must swap the numbers when responding.
*/
tcp_seq_num = ntohl(b->ip.hdr.tcp_seq);
tcp_ack_num = ntohl(b->ip.hdr.tcp_ack);
tcp_action = tcp_state_machine( b->ip.hdr.tcp_flags, &tcp_seq_num, payload_len );
/*
* State altering command to be sent.
* The packet sequence and ack numbers are in the tcp_seq_num and tcp_ack_num variables.
* The current packet, its position in the date stream, is the in the range of those variables.
*
* In the "application push" invocation the TCP header with all its information is pointed to by the
* packet pointer, and the other variable "repurposed" (or misused) to carry sequence numbers
* and TCP state.
*
* TCP_PUSH from the state machine with a payload length of 0 is a connect or disconnect event
*/
if (( tcp_action && TCP_PUSH ) || ( payload_len > 0))
{
debug_cond(DEBUG_TCP_PKT,
"TCP App Notify (action=%x, Seq=%d, Ack=%d, Payload=%d)\n",
tcp_action, tcp_seq_num, tcp_ack_num, payload_len );
action_and_state.s_addr = tcp_action;
(*tcp_packet_handler) ((uchar *) b + pkt_len - payload_len,
tcp_seq_num, action_and_state, tcp_ack_num, payload_len );
}
else if ( tcp_action != TCP_DATA )
{
debug_cond(DEBUG_TCP_PKT,
"TCP Net Action (action=%x, Seq=%d, Ack=%d,Payload=%d)\n",
tcp_action, tcp_seq_num, tcp_ack_num, payload_len );
/*
* Warning Incoming sequence number are transposed here to TX sequence numbers
*/
net_action = (tcp_action & (~ TCP_PUSH));
net_send_ip_packet( 0, IPPROTO_TCP, net_action, tcp_ack_num, tcp_seq_num );
}
}
#endif
void net_init(void)
{
static int first_call = 1;
if (first_call) {
/*
* Setup packet wbuffers, aligned correctly.
*/
int i;
net_tx_packet = &net_pkt_buf[0] + (PKTALIGN - 1);
net_tx_packet -= (ulong)net_tx_packet % PKTALIGN;
for (i = 0; i < PKTBUFSRX; i++) {
net_rx_packets[i] = net_tx_packet +
(i + 1) * PKTSIZE_ALIGN;
}
arp_init();
net_clear_handlers();
/* Only need to setup buffer pointers once. */
first_call = 0;
#ifdef TCP
tcp_state = TCP_CLOSED;
#endif
}
net_init_loop();
}
/**********************************************************************/
/*
* Main network processing loop.
*/
int net_loop(enum proto_t protocol)
{
int ret = -EINVAL;
net_restarted = 0;
net_dev_exists = 0;
net_try_count = 1;
debug_cond(DEBUG_INT_STATE, "--- net_loop Entry\n");
bootstage_mark_name(BOOTSTAGE_ID_ETH_START, "eth_start");
net_init();
if (eth_is_on_demand_init() || protocol != NETCONS) {
eth_halt();
eth_set_current();
ret = eth_init();
if (ret < 0) {
eth_halt();
return ret;
}
} else {
eth_init_state_only();
}
restart:
#ifdef CONFIG_USB_KEYBOARD
net_busy_flag = 0;
#endif
net_set_state(NETLOOP_CONTINUE);
/*
* Start the ball rolling with the given start function. From
* here on, this code is a state machine driven by received
* packets and timer events.
*/
debug_cond(DEBUG_INT_STATE, "--- net_loop Init\n");
net_init_loop();
switch (net_check_prereq(protocol)) {
case 1:
/* network not configured */
eth_halt();
return -ENODEV;
case 2:
/* network device not configured */
break;
case 0:
net_dev_exists = 1;
net_boot_file_size = 0;
switch (protocol) {
case TFTPGET:
#ifdef CONFIG_CMD_TFTPPUT
case TFTPPUT:
#endif
/* always use ARP to get server ethernet address */
tftp_start(protocol);
break;
#ifdef CONFIG_CMD_TFTPSRV
case TFTPSRV:
tftp_start_server();
break;
#endif
#if defined(CONFIG_CMD_DHCP)
case DHCP:
bootp_reset();
net_ip.s_addr = 0;
dhcp_request(); /* Basically same as BOOTP */
break;
#endif
case BOOTP:
bootp_reset();
net_ip.s_addr = 0;
bootp_request();
break;
#if defined(CONFIG_CMD_RARP)
case RARP:
rarp_try = 0;
net_ip.s_addr = 0;
rarp_request();
break;
#endif
#if defined(CONFIG_CMD_PING)
case PING:
ping_start();
break;
#endif
#if defined(CONFIG_CMD_NFS)
case NFS:
nfs_start();
break;
#endif
#if defined(CONFIG_CMD_CDP)
case CDP:
cdp_start();
break;
#endif
#if defined(CONFIG_NETCONSOLE) && !(CONFIG_SPL_BUILD)
case NETCONS:
nc_start();
break;
#endif
#if defined(CONFIG_CMD_SNTP)
case SNTP:
sntp_start();
break;
#endif
#if defined(CONFIG_CMD_DNS)
case DNS:
dns_start();
break;
#endif
#if defined(CONFIG_CMD_LINK_LOCAL)
case LINKLOCAL:
link_local_start();
break;
#endif
#ifdef TCP
//#if defined(CONFIG_CMD_WGET)
case WGET:
wget_start();
break;
//#endif
#endif
default:
break;
}
break;
}
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
#if defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN) && \
defined(CONFIG_STATUS_LED) && \
defined(STATUS_LED_RED)
/*
* Echo the inverted link state to the fault LED.
*/
if (miiphy_link(eth_get_dev()->name, CONFIG_SYS_FAULT_MII_ADDR))
status_led_set(STATUS_LED_RED, STATUS_LED_OFF);
else
status_led_set(STATUS_LED_RED, STATUS_LED_ON);
#endif /* CONFIG_SYS_FAULT_ECHO_LINK_DOWN, ... */
#endif /* CONFIG_MII, ... */
#ifdef CONFIG_USB_KEYBOARD
net_busy_flag = 1;
#endif
/*
* Main packet reception loop. Loop receiving packets until
* someone sets `net_state' to a state that terminates.
*/
for (;;) {
WATCHDOG_RESET();
#ifdef CONFIG_SHOW_ACTIVITY
show_activity(1);
#endif
if (arp_timeout_check() > 0)
time_start = get_timer(0);
/*
* Check the ethernet for a new packet. The ethernet
* receive routine will process it.
* Most drivers return the most recent packet size, but not
* errors that may have happened.
*/
eth_rx();
/*
* Abort if ctrl-c was pressed.
*/
if (ctrlc()) {
/* cancel any ARP that may not have completed */
net_arp_wait_packet_ip.s_addr = 0;
net_cleanup_loop();
eth_halt();
/* Invalidate the last protocol */
eth_set_last_protocol(BOOTP);
puts("\nAbort\n");
/* include a debug print as well incase the debug
messages are directed to stderr */
debug_cond(DEBUG_INT_STATE, "--- net_loop Abort!\n");
ret = -EINTR;
goto done;
}
/*
* Check for a timeout, and run the timeout handler
* if we have one.
*/
if (time_handler &&
((get_timer(0) - time_start) > time_delta)) {
thand_f *x;
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
#if defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN) && \
defined(CONFIG_STATUS_LED) && \
defined(STATUS_LED_RED)
/*
* Echo the inverted link state to the fault LED.
*/
if (miiphy_link(eth_get_dev()->name,
CONFIG_SYS_FAULT_MII_ADDR))
status_led_set(STATUS_LED_RED, STATUS_LED_OFF);
else
status_led_set(STATUS_LED_RED, STATUS_LED_ON);
#endif /* CONFIG_SYS_FAULT_ECHO_LINK_DOWN, ... */
#endif /* CONFIG_MII, ... */
debug_cond(DEBUG_INT_STATE, "--- net_loop timeout\n");
x = time_handler;
time_handler = (thand_f *)0;
(*x)();
}
if (net_state == NETLOOP_FAIL)
ret = net_start_again();
switch (net_state) {
case NETLOOP_RESTART:
net_restarted = 1;
goto restart;
case NETLOOP_SUCCESS:
net_cleanup_loop();
if (net_boot_file_size > 0) {
printf("Bytes transferred = %d (%x hex)\n",
net_boot_file_size, net_boot_file_size);
setenv_hex("filesize", net_boot_file_size);
setenv_hex("fileaddr", load_addr);
}
if (protocol != NETCONS)
eth_halt();
else
eth_halt_state_only();
eth_set_last_protocol(protocol);
ret = net_boot_file_size;
debug_cond(DEBUG_INT_STATE, "--- net_loop Success!\n");
goto done;
case NETLOOP_FAIL:
net_cleanup_loop();
/* Invalidate the last protocol */
eth_set_last_protocol(BOOTP);
debug_cond(DEBUG_INT_STATE, "--- net_loop Fail!\n");
goto done;
case NETLOOP_CONTINUE:
continue;
}
}
done:
#ifdef CONFIG_USB_KEYBOARD
net_busy_flag = 0;
#endif
#ifdef CONFIG_CMD_TFTPPUT
/* Clear out the handlers */
net_set_udp_handler(NULL);
net_set_icmp_handler(NULL);
#endif
return ret;
}
/**********************************************************************/
static void start_again_timeout_handler(void)
{
net_set_state(NETLOOP_RESTART);
}
int net_start_again(void)
{
char *nretry;
int retry_forever = 0;
unsigned long retrycnt = 0;
int ret;
nretry = getenv("netretry");
if (nretry) {
if (!strcmp(nretry, "yes"))
retry_forever = 1;
else if (!strcmp(nretry, "no"))
retrycnt = 0;
else if (!strcmp(nretry, "once"))
retrycnt = 1;
else
retrycnt = simple_strtoul(nretry, NULL, 0);
} else {
retrycnt = 0;
retry_forever = 0;
}
if ((!retry_forever) && (net_try_count >= retrycnt)) {
eth_halt();
net_set_state(NETLOOP_FAIL);
/*
* We don't provide a way for the protocol to return an error,
* but this is almost always the reason.
*/
return -ETIMEDOUT;
}
net_try_count++;
eth_halt();
#if !defined(CONFIG_NET_DO_NOT_TRY_ANOTHER)
eth_try_another(!net_restarted);
#endif
ret = eth_init();
if (net_restart_wrap) {
net_restart_wrap = 0;
if (net_dev_exists) {
net_set_timeout_handler(10000UL,
start_again_timeout_handler);
net_set_udp_handler(NULL);
} else {
net_set_state(NETLOOP_FAIL);
}
} else {
net_set_state(NETLOOP_RESTART);
}
return ret;
}
/**********************************************************************/
/*
* Miscelaneous bits.
*/
static void dummy_handler(uchar *pkt, unsigned dport,
struct in_addr sip, unsigned sport,
unsigned len)
{
}
rxhand_f *net_get_udp_handler(void)
{
return udp_packet_handler;
}
void net_set_tcp_handler(rxhand_f *f)
{
debug_cond(DEBUG_INT_STATE, "--- net_loop TCP handler set (%p)\n", f);
if (f == NULL)
tcp_packet_handler = dummy_handler;
else
tcp_packet_handler = f;
}
void net_set_udp_handler(rxhand_f *f)
{
debug_cond(DEBUG_INT_STATE, "--- net_loop UDP handler set (%p)\n", f);
if (f == NULL)
udp_packet_handler = dummy_handler;
else
udp_packet_handler = f;
}
rxhand_f *net_get_arp_handler(void)
{
return arp_packet_handler;
}
void net_set_arp_handler(rxhand_f *f)
{
debug_cond(DEBUG_INT_STATE, "--- net_loop ARP handler set (%p)\n", f);
if (f == NULL)
arp_packet_handler = dummy_handler;
else
arp_packet_handler = f;
}
#ifdef CONFIG_CMD_TFTPPUT
void net_set_icmp_handler(rxhand_icmp_f *f)
{
packet_icmp_handler = f;
}
#endif
void net_set_timeout_handler(ulong iv, thand_f *f)
{
if (iv == 0) {
debug_cond(DEBUG_INT_STATE,
"--- net_loop timeout handler cancelled\n");
time_handler = (thand_f *)0;
} else {
debug_cond(DEBUG_INT_STATE,
"--- net_loop timeout handler set (%p)\n", f);
time_handler = f;
time_start = get_timer(0);
time_delta = iv * CONFIG_SYS_HZ / 1000;
}
}
int net_send_udp_packet(uchar *ether, struct in_addr dest, int dport, int sport,
int payload_len)
{
// net_send_udp_orig_packet( ether, dest, dport, sport, payload_len );
// return(0);
net_set_ports( dport, sport );
return(net_send_ip_packet( payload_len, IPPROTO_UDP, IPPROTO_UDP, 0, 0));
}
#ifdef CONFIG_IP_DEFRAG
/*
* This function collects fragments in a single packet, according
* to the algorithm in RFC815. It returns NULL or the pointer to
* a complete packet, in static storage
*/
#ifndef CONFIG_NET_MAXDEFRAG
#define CONFIG_NET_MAXDEFRAG 16384
#endif
#define IP_PKTSIZE (CONFIG_NET_MAXDEFRAG)
#define IP_MAXUDP (IP_PKTSIZE - IP_HDR_SIZE)
/*
* this is the packet being assembled, either data or frag control.
* Fragments go by 8 bytes, so this union must be 8 bytes long
*/
struct hole {
/* first_byte is address of this structure */
u16 last_byte; /* last byte in this hole + 1 (begin of next hole) */
u16 next_hole; /* index of next (in 8-b blocks), 0 == none */
u16 prev_hole; /* index of prev, 0 == none */
u16 unused;
};
static struct ip_udp_hdr *__net_defragment(struct ip_udp_hdr *ip, int *lenp)
{
static uchar pkt_buff[IP_PKTSIZE] __aligned(PKTALIGN);
static u16 first_hole, total_len;
struct hole *payload, *thisfrag, *h, *newh;
struct ip_udp_hdr *localip = (struct ip_udp_hdr *)pkt_buff;
uchar *indata = (uchar *)ip;
int offset8, start, len, done = 0;
u16 ip_off = ntohs(ip->ip_off);
/* payload starts after IP header, this fragment is in there */
payload = (struct hole *)(pkt_buff + IP_HDR_SIZE);
offset8 = (ip_off & IP_OFFS);
thisfrag = payload + offset8;
start = offset8 * 8;
len = ntohs(ip->ip_len) - IP_HDR_SIZE;
if (start + len > IP_MAXUDP) /* fragment extends too far */
return NULL;
if (!total_len || localip->ip_id != ip->ip_id) {
/* new (or different) packet, reset structs */
total_len = 0xffff;
payload[0].last_byte = ~0;
payload[0].next_hole = 0;
payload[0].prev_hole = 0;
first_hole = 0;
/* any IP header will work, copy the first we received */
memcpy(localip, ip, IP_HDR_SIZE);
}
/*
* What follows is the reassembly algorithm. We use the payload
* array as a linked list of hole descriptors, as each hole starts
* at a multiple of 8 bytes. However, last byte can be whatever value,
* so it is represented as byte count, not as 8-byte blocks.
*/
h = payload + first_hole;
while (h->last_byte < start) {
if (!h->next_hole) {
/* no hole that far away */
return NULL;
}
h = payload + h->next_hole;
}
/* last fragment may be 1..7 bytes, the "+7" forces acceptance */
if (offset8 + ((len + 7) / 8) <= h - payload) {
/* no overlap with holes (dup fragment?) */
return NULL;
}
if (!(ip_off & IP_FLAGS_MFRAG)) {
/* no more fragmentss: truncate this (last) hole */
total_len = start + len;
h->last_byte = start + len;
}
/*
* There is some overlap: fix the hole list. This code doesn't
* deal with a fragment that overlaps with two different holes
* (thus being a superset of a previously-received fragment).
*/
if ((h >= thisfrag) && (h->last_byte <= start + len)) {
/* complete overlap with hole: remove hole */
if (!h->prev_hole && !h->next_hole) {
/* last remaining hole */
done = 1;
} else if (!h->prev_hole) {
/* first hole */
first_hole = h->next_hole;
payload[h->next_hole].prev_hole = 0;
} else if (!h->next_hole) {
/* last hole */
payload[h->prev_hole].next_hole = 0;
} else {
/* in the middle of the list */
payload[h->next_hole].prev_hole = h->prev_hole;
payload[h->prev_hole].next_hole = h->next_hole;
}
} else if (h->last_byte <= start + len) {
/* overlaps with final part of the hole: shorten this hole */
h->last_byte = start;
} else if (h >= thisfrag) {
/* overlaps with initial part of the hole: move this hole */
newh = thisfrag + (len / 8);
*newh = *h;
h = newh;
if (h->next_hole)
payload[h->next_hole].prev_hole = (h - payload);
if (h->prev_hole)
payload[h->prev_hole].next_hole = (h - payload);
else
first_hole = (h - payload);
} else {
/* fragment sits in the middle: split the hole */
newh = thisfrag + (len / 8);
*newh = *h;
h->last_byte = start;
h->next_hole = (newh - payload);
newh->prev_hole = (h - payload);
if (newh->next_hole)
payload[newh->next_hole].prev_hole = (newh - payload);
}
/* finally copy this fragment and possibly return whole packet */
memcpy((uchar *)thisfrag, indata + IP_HDR_SIZE, len);
if (!done)
return NULL;
localip->ip_len = htons(total_len);
*lenp = total_len + IP_HDR_SIZE;
return localip;
}
static inline struct ip_udp_hdr *net_defragment(struct ip_udp_hdr *ip,
int *lenp)
{
u16 ip_off = ntohs(ip->ip_off);
if (!(ip_off & (IP_OFFS | IP_FLAGS_MFRAG)))
return ip; /* not a fragment */
return __net_defragment(ip, lenp);
}
#else /* !CONFIG_IP_DEFRAG */
static inline struct ip_udp_hdr *net_defragment(struct ip_udp_hdr *ip,
int *lenp)
{
u16 ip_off = ntohs(ip->ip_off);
if (!(ip_off & (IP_OFFS | IP_FLAGS_MFRAG)))
return ip; /* not a fragment */
return NULL;
}
#endif
/**
* Receive an ICMP packet. We deal with REDIRECT and PING here, and silently
* drop others.
*
* @parma ip IP packet containing the ICMP
*/
static void receive_icmp(struct ip_udp_hdr *ip, int len,
struct in_addr src_ip, struct ethernet_hdr *et)
{
struct icmp_hdr *icmph = (struct icmp_hdr *)&ip->udp_src;
switch (icmph->type) {
case ICMP_REDIRECT:
if (icmph->code != ICMP_REDIR_HOST)
return;
printf(" ICMP Host Redirect to %pI4 ",
&icmph->un.gateway);
break;
default:
#if defined(CONFIG_CMD_PING)
ping_receive(et, ip, len);
#endif
#ifdef CONFIG_CMD_TFTPPUT
if (packet_icmp_handler)
packet_icmp_handler(icmph->type, icmph->code,
ntohs(ip->udp_dst), src_ip,
ntohs(ip->udp_src), icmph->un.data,
ntohs(ip->udp_len));
#endif
break;
}
}
void net_process_received_packet(uchar *in_packet, int len)
{
struct ethernet_hdr *et;
struct ip_udp_hdr *ip;
struct in_addr dst_ip;
struct in_addr src_ip;
int eth_proto;
#if defined(CONFIG_CMD_CDP)
int iscdp;
#endif
ushort cti = 0, vlanid = VLAN_NONE, myvlanid, mynvlanid;
debug_cond(DEBUG_NET_PKT, "packet received\n");
net_rx_packet = in_packet;
net_rx_packet_len = len;
et = (struct ethernet_hdr *)in_packet;
/* too small packet? */
if (len < ETHER_HDR_SIZE)
return;
#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
if (push_packet) {
(*push_packet)(in_packet, len);
return;
}
#endif
#if defined(CONFIG_CMD_CDP)
/* keep track if packet is CDP */
iscdp = is_cdp_packet(et->et_dest);
#endif
myvlanid = ntohs(net_our_vlan);
if (myvlanid == (ushort)-1)
myvlanid = VLAN_NONE;
mynvlanid = ntohs(net_native_vlan);
if (mynvlanid == (ushort)-1)
mynvlanid = VLAN_NONE;
eth_proto = ntohs(et->et_protlen);
if (eth_proto < 1514) {
struct e802_hdr *et802 = (struct e802_hdr *)et;
/*
* Got a 802.2 packet. Check the other protocol field.
* XXX VLAN over 802.2+SNAP not implemented!
*/
eth_proto = ntohs(et802->et_prot);
ip = (struct ip_udp_hdr *)(in_packet + E802_HDR_SIZE);
len -= E802_HDR_SIZE;
} else if (eth_proto != PROT_VLAN) { /* normal packet */
ip = (struct ip_udp_hdr *)(in_packet + ETHER_HDR_SIZE);
len -= ETHER_HDR_SIZE;
} else { /* VLAN packet */
struct vlan_ethernet_hdr *vet =
(struct vlan_ethernet_hdr *)et;
debug_cond(DEBUG_NET_PKT, "VLAN packet received\n");
/* too small packet? */
if (len < VLAN_ETHER_HDR_SIZE)
return;
/* if no VLAN active */
if ((ntohs(net_our_vlan) & VLAN_IDMASK) == VLAN_NONE
#if defined(CONFIG_CMD_CDP)
&& iscdp == 0
#endif
)
return;
cti = ntohs(vet->vet_tag);
vlanid = cti & VLAN_IDMASK;
eth_proto = ntohs(vet->vet_type);
ip = (struct ip_udp_hdr *)(in_packet + VLAN_ETHER_HDR_SIZE);
len -= VLAN_ETHER_HDR_SIZE;
}
debug_cond(DEBUG_NET_PKT, "Receive from protocol 0x%x\n", eth_proto);
#if defined(CONFIG_CMD_CDP)
if (iscdp) {
cdp_receive((uchar *)ip, len);
return;
}
#endif
if ((myvlanid & VLAN_IDMASK) != VLAN_NONE) {
if (vlanid == VLAN_NONE)
vlanid = (mynvlanid & VLAN_IDMASK);
/* not matched? */
if (vlanid != (myvlanid & VLAN_IDMASK))
return;
}
switch (eth_proto) {
case PROT_ARP:
arp_receive(et, ip, len);
break;
#ifdef CONFIG_CMD_RARP
case PROT_RARP:
rarp_receive(ip, len);
break;
#endif
case PROT_IP:
debug_cond(DEBUG_NET_PKT, "Got IP\n");
/* Before we start poking the header, make sure it is there */
if (len < IP_UDP_HDR_SIZE) {
debug("len bad %d < %lu\n", len,
(ulong)IP_UDP_HDR_SIZE);
return;
}
/* Check the packet length */
if (len < ntohs(ip->ip_len)) {
debug("len bad %d < %d\n", len, ntohs(ip->ip_len));
return;
}
len = ntohs(ip->ip_len);
debug_cond(DEBUG_NET_PKT, "len=%d, v=%02x\n",
len, ip->ip_hl_v & 0xff);
/* Can't deal with anything except IPv4 */
if ((ip->ip_hl_v & 0xf0) != 0x40)
return;
/* Can't deal with IP options (headers != 20 bytes) */
if ((ip->ip_hl_v & 0x0f) > 0x05)
return;
/* Check the Checksum of the header */
if (!ip_checksum_ok((uchar *)ip, IP_HDR_SIZE)) {
debug("checksum bad\n");
return;
}
/* If it is not for us, ignore it */
dst_ip = net_read_ip(&ip->ip_dst);
if (net_ip.s_addr && dst_ip.s_addr != net_ip.s_addr &&
dst_ip.s_addr != 0xFFFFFFFF) {
#ifdef CONFIG_MCAST_TFTP
if (net_mcast_addr != dst_ip)
#endif
return;
}
/* Read source IP address for later use */
src_ip = net_read_ip(&ip->ip_src);
/*
* The function returns the unchanged packet if it's not
* a fragment, and either the complete packet or NULL if
* it is a fragment (if !CONFIG_IP_DEFRAG, it returns NULL)
*/
ip = net_defragment(ip, &len);
if (!ip)
return;
/*
* watch for ICMP host redirects
*
* There is no real handler code (yet). We just watch
* for ICMP host redirect messages. In case anybody
* sees these messages: please contact me
* (wd(a)denx.de), or - even better - send me the
* necessary fixes :-)
*
* Note: in all cases where I have seen this so far
* it was a problem with the router configuration,
* for instance when a router was configured in the
* BOOTP reply, but the TFTP server was on the same
* subnet. So this is probably a warning that your
* configuration might be wrong. But I'm not really
* sure if there aren't any other situations.
*
* Simon Glass <sjg(a)chromium.org>: We get an ICMP when
* we send a tftp packet to a dead connection, or when
* there is no server at the other end.
*/
if (ip->ip_p == IPPROTO_ICMP) {
receive_icmp(ip, len, src_ip, et);
return;
} else if (ip->ip_p == IPPROTO_UDP) { /* Only UDP packets */
debug_cond(DEBUG_DEV_PKT,
"received UDP (to=%pI4, from=%pI4, len=%d)\n",
&dst_ip, &src_ip, len);
#ifdef CONFIG_UDP_CHECKSUM
if (ip->udp_xsum != 0) {
ulong xsum;
ushort *sumptr;
ushort sumlen;
xsum = ip->ip_p;
xsum += (ntohs(ip->udp_len));
xsum += (ntohl(ip->ip_src.s_addr) >> 16) & 0x0000ffff;
xsum += (ntohl(ip->ip_src.s_addr) >> 0) & 0x0000ffff;
xsum += (ntohl(ip->ip_dst.s_addr) >> 16) & 0x0000ffff;
xsum += (ntohl(ip->ip_dst.s_addr) >> 0) & 0x0000ffff;
sumlen = ntohs(ip->udp_len);
sumptr = (ushort *)&(ip->udp_src);
while (sumlen > 1) {
ushort sumdata;
sumdata = *sumptr++;
xsum += ntohs(sumdata);
sumlen -= 2;
}
if (sumlen > 0) {
ushort sumdata;
sumdata = *(unsigned char *)sumptr;
sumdata = (sumdata << 8) & 0xff00;
xsum += sumdata;
}
while ((xsum >> 16) != 0) {
xsum = (xsum & 0x0000ffff) +
((xsum >> 16) & 0x0000ffff);
}
if ((xsum != 0x00000000) && (xsum != 0x0000ffff)) {
printf(" UDP wrong checksum %08lx %08x\n",
xsum, ntohs(ip->udp_xsum));
return;
}
}
#endif
#if defined(CONFIG_NETCONSOLE) && !(CONFIG_SPL_BUILD)
nc_input_packet((uchar *)ip + IP_UDP_HDR_SIZE,
src_ip,
ntohs(ip->udp_dst),
ntohs(ip->udp_src),
ntohs(ip->udp_len) - UDP_HDR_SIZE);
#endif
/*
* IP header OK. Pass the packet to the current handler.
*/
debug_cond(DEBUG_DEV_PKT,
"UDP PH (to=%pI4, from=%pI4, len=%d)\n",
&dst_ip, &src_ip, len);
(*udp_packet_handler)((uchar *)ip + IP_UDP_HDR_SIZE,
ntohs(ip->udp_dst),
src_ip,
ntohs(ip->udp_src),
ntohs(ip->udp_len) - UDP_HDR_SIZE);
}
#ifdef TCP
else if (ip->ip_p == IPPROTO_TCP) { /* Only TCP packets */
debug_cond(DEBUG_DEV_PKT,
"TCP PH (to=%pI4, from=%pI4, len=%d)\n",
&dst_ip, &src_ip, len);
rxhand_tcp_f((union tcp_build_pkt *) ip, len);
}
#endif
}
}
/**********************************************************************/
static int net_check_prereq(enum proto_t protocol)
{
switch (protocol) {
/* Fall through */
#if defined(CONFIG_CMD_PING)
case PING:
if (net_ping_ip.s_addr == 0) {
puts("*** ERROR: ping address not given\n");
return 1;
}
goto common;
#endif
#if defined(CONFIG_CMD_SNTP)
case SNTP:
if (net_ntp_server.s_addr == 0) {
puts("*** ERROR: NTP server address not given\n");
return 1;
}
goto common;
#endif
#if defined(CONFIG_CMD_DNS)
case DNS:
if (net_dns_server.s_addr == 0) {
puts("*** ERROR: DNS server address not given\n");
return 1;
}
goto common;
#endif
#if defined(CONFIG_CMD_NFS)
case NFS:
#endif
/* Fall through */
case TFTPGET:
case TFTPPUT:
if (net_server_ip.s_addr == 0) {
puts("*** ERROR: `serverip' not set\n");
return 1;
}
#if defined(CONFIG_CMD_PING) || defined(CONFIG_CMD_SNTP) || \
defined(CONFIG_CMD_DNS)
common:
#endif
/* Fall through */
case NETCONS:
case TFTPSRV:
if (net_ip.s_addr == 0) {
puts("*** ERROR: `ipaddr' not set\n");
return 1;
}
/* Fall through */
#ifdef CONFIG_CMD_RARP
case RARP:
#endif
case BOOTP:
case CDP:
case DHCP:
case LINKLOCAL:
if (memcmp(net_ethaddr, "\0\0\0\0\0\0", 6) == 0) {
int num = eth_get_dev_index();
switch (num) {
case -1:
puts("*** ERROR: No ethernet found.\n");
return 1;
case 0:
puts("*** ERROR: `ethaddr' not set\n");
break;
default:
printf("*** ERROR: `eth%daddr' not set\n",
num);
break;
}
net_start_again();
return 2;
}
/* Fall through */
default:
return 0;
}
return 0; /* OK */
}
/**********************************************************************/
int
net_eth_hdr_size(void)
{
ushort myvlanid;
myvlanid = ntohs(net_our_vlan);
if (myvlanid == (ushort)-1)
myvlanid = VLAN_NONE;
return ((myvlanid & VLAN_IDMASK) == VLAN_NONE) ? ETHER_HDR_SIZE :
VLAN_ETHER_HDR_SIZE;
}
int net_set_ether(uchar *xet, const uchar *dest_ethaddr, uint prot)
{
struct ethernet_hdr *et = (struct ethernet_hdr *)xet;
ushort myvlanid;
myvlanid = ntohs(net_our_vlan);
if (myvlanid == (ushort)-1)
myvlanid = VLAN_NONE;
memcpy(et->et_dest, dest_ethaddr, 6);
memcpy(et->et_src, net_ethaddr, 6);
if ((myvlanid & VLAN_IDMASK) == VLAN_NONE) {
et->et_protlen = htons(prot);
return ETHER_HDR_SIZE;
} else {
struct vlan_ethernet_hdr *vet =
(struct vlan_ethernet_hdr *)xet;
vet->vet_vlan_type = htons(PROT_VLAN);
vet->vet_tag = htons((0 << 5) | (myvlanid & VLAN_IDMASK));
vet->vet_type = htons(prot);
return VLAN_ETHER_HDR_SIZE;
}
}
int net_update_ether(struct ethernet_hdr *et, uchar *addr, uint prot)
{
ushort protlen;
memcpy(et->et_dest, addr, 6);
memcpy(et->et_src, net_ethaddr, 6);
protlen = ntohs(et->et_protlen);
if (protlen == PROT_VLAN) {
struct vlan_ethernet_hdr *vet =
(struct vlan_ethernet_hdr *)et;
vet->vet_type = htons(prot);
return VLAN_ETHER_HDR_SIZE;
} else if (protlen > 1514) {
et->et_protlen = htons(prot);
return ETHER_HDR_SIZE;
} else {
/* 802.2 + SNAP */
struct e802_hdr *et802 = (struct e802_hdr *)et;
et802->et_prot = htons(prot);
return E802_HDR_SIZE;
}
}
void net_set_ip_header(uchar *pkt, struct in_addr dest, struct in_addr source,
u16 pkt_len, u8 prot)
{
struct ip_hdr *ip = (struct ip_hdr *)pkt;
/*
* Construct an IP header.
*/
/* IP_HDR_SIZE / 4 (not including UDP) */
ip->ip_hl_v = 0x45;
ip->ip_tos = 0;
ip->ip_len = htons(pkt_len);
ip->ip_id = htons(net_ip_id++);
ip->ip_off = htons(IP_FLAGS_DFRAG); /* Don't fragment */
ip->ip_ttl = 255;
ip->ip_p = prot;
ip->ip_sum = 0;
/* already in network byte order */
net_copy_ip((void *)&ip->ip_src, &source);
/* already in network byte order */
net_copy_ip((void *)&ip->ip_dst, &dest);
ip->ip_sum = compute_ip_checksum(ip, IP_HDR_SIZE);
}
void net_set_udp_header(uchar *pkt, struct in_addr dest, int dport, int sport,
int len)
{
struct ip_udp_hdr *ip = (struct ip_udp_hdr *)pkt;
/*
* If the data is an odd number of bytes, zero the
* byte after the last byte so that the checksum
* will work.
*/
if (len & 1)
pkt[IP_UDP_HDR_SIZE + len] = 0;
net_set_ip_header(pkt, dest, net_ip, IP_UDP_HDR_SIZE + len, IPPROTO_UDP);
ip->udp_src = htons(sport);
ip->udp_dst = htons(dport);
ip->udp_len = htons(UDP_HDR_SIZE + len);
ip->udp_xsum = 0;
}
void copy_filename(char *dst, const char *src, int size)
{
if (*src && (*src == '"')) {
++src;
--size;
}
while ((--size > 0) && *src && (*src != '"'))
*dst++ = *src++;
*dst = '\0';
}
#if defined(CONFIG_CMD_NFS) || \
defined(CONFIG_CMD_SNTP) || \
defined(CONFIG_CMD_DNS) || \
defined(CONFIG_CMD_WGET)
/*
* make port a little random (1024-17407)
* This keeps the math somewhat trivial to compute, and seems to work with
* all supported protocols/clients/servers
*/
unsigned int random_port(void)
{
return 1024 + (get_timer(0) % 0x4000);
}
#endif
void ip_to_string(struct in_addr x, char *s)
{
x.s_addr = ntohl(x.s_addr);
sprintf(s, "%d.%d.%d.%d",
(int) ((x.s_addr >> 24) & 0xff),
(int) ((x.s_addr >> 16) & 0xff),
(int) ((x.s_addr >> 8) & 0xff),
(int) ((x.s_addr >> 0) & 0xff)
);
}
void vlan_to_string(ushort x, char *s)
{
x = ntohs(x);
if (x == (ushort)-1)
x = VLAN_NONE;
if (x == VLAN_NONE)
strcpy(s, "none");
else
sprintf(s, "%d", x & VLAN_IDMASK);
}
ushort string_to_vlan(const char *s)
{
ushort id;
if (s == NULL)
return htons(VLAN_NONE);
if (*s < '0' || *s > '9')
id = VLAN_NONE;
else
id = (ushort)simple_strtoul(s, NULL, 10);
return htons(id);
}
ushort getenv_vlan(char *var)
{
return string_to_vlan(getenv(var));
}include/net.h
/*
* LiMon Monitor (LiMon) - Network.
*
* Copyright 1994 - 2000 Neil Russell.
* (See License)
* SPDX-License-Identifier: GPL-2.0
*
* History
* 9/16/00 bor adapted to TQM823L/STK8xxL board, RARP/TFTP boot added
* 9/20/2017 dch Added TCP listener
*/
#ifndef __NET_H__
#define __NET_H__
#if defined(CONFIG_8xx)
#include <commproc.h>
#endif /* CONFIG_8xx */
#include <asm/cache.h>
#include <asm/byteorder.h> /* for nton* / ntoh* stuff */
#define DEBUG_LL_STATE 0 /* Link local state machine changes */
#define DEBUG_DEV_PKT 0 /* Packets or info directed to the device */
#define DEBUG_NET_PKT 0 /* Packets on info on the network at large */
#define DEBUG_INT_STATE 0 /* Internal network state changes */
/*
* The number of receive packet buffers, and the required packet buffer
* alignment in memory.
*
*/
#define TCP 1
#ifdef TCP
#define CONFIG_SYS_RX_ETH_BUFFER 50 /* For TCP */
#endif
#ifdef CONFIG_SYS_RX_ETH_BUFFER
# define PKTBUFSRX CONFIG_SYS_RX_ETH_BUFFER
#else
# define PKTBUFSRX 4
#endif
#define PKTALIGN ARCH_DMA_MINALIGN
/* IPv4 addresses are always 32 bits in size */
struct in_addr {
__be32 s_addr;
};
/**
* An incoming packet handler.
* @param pkt pointer to the application packet
* @param dport destination UDP port
* @param sip source IP address
* @param sport source UDP port
* @param len packet length
*/
typedef void rxhand_f(uchar *pkt, unsigned dport,
struct in_addr sip, unsigned sport,
unsigned len);
/**
* An incoming ICMP packet handler.
* @param type ICMP type
* @param code ICMP code
* @param dport destination UDP port
* @param sip source IP address
* @param sport source UDP port
* @param pkt pointer to the ICMP packet data
* @param len packet length
*/
typedef void rxhand_icmp_f(unsigned type, unsigned code, unsigned dport,
struct in_addr sip, unsigned sport, uchar *pkt, unsigned len);
/*
* A timeout handler. Called after time interval has expired.
*/
typedef void thand_f(void);
enum eth_state_t {
ETH_STATE_INIT,
ETH_STATE_PASSIVE,
ETH_STATE_ACTIVE
};
#ifdef CONFIG_DM_ETH
/**
* struct eth_pdata - Platform data for Ethernet MAC controllers
*
* @iobase: The base address of the hardware registers
* @enetaddr: The Ethernet MAC address that is loaded from EEPROM or env
* @phy_interface: PHY interface to use - see PHY_INTERFACE_MODE_...
* @max_speed: Maximum speed of Ethernet connection supported by MAC
*/
struct eth_pdata {
phys_addr_t iobase;
unsigned char enetaddr[6];
int phy_interface;
int max_speed;
};
enum eth_recv_flags {
/*
* Check hardware device for new packets (otherwise only return those
* which are already in the memory buffer ready to process)
*/
ETH_RECV_CHECK_DEVICE = 1 << 0,
};
/**
* struct eth_ops - functions of Ethernet MAC controllers
*
* start: Prepare the hardware to send and receive packets
* send: Send the bytes passed in "packet" as a packet on the wire
* recv: Check if the hardware received a packet. If so, set the pointer to the
* packet buffer in the packetp parameter. If not, return an error or 0 to
* indicate that the hardware receive FIFO is empty. If 0 is returned, the
* network stack will not process the empty packet, but free_pkt() will be
* called if supplied
* free_pkt: Give the driver an opportunity to manage its packet buffer memory
* when the network stack is finished processing it. This will only be
* called when no error was returned from recv - optional
* stop: Stop the hardware from looking for packets - may be called even if
* state == PASSIVE
* mcast: Join or leave a multicast group (for TFTP) - optional
* write_hwaddr: Write a MAC address to the hardware (used to pass it to Linux
* on some platforms like ARM). This function expects the
* eth_pdata::enetaddr field to be populated. The method can
* return -ENOSYS to indicate that this is not implemented for
this hardware - optional.
* read_rom_hwaddr: Some devices have a backup of the MAC address stored in a
* ROM on the board. This is how the driver should expose it
* to the network stack. This function should fill in the
* eth_pdata::enetaddr field - optional
*/
struct eth_ops {
int (*start)(struct udevice *dev);
int (*send)(struct udevice *dev, void *packet, int length);
int (*recv)(struct udevice *dev, int flags, uchar **packetp);
int (*free_pkt)(struct udevice *dev, uchar *packet, int length);
void (*stop)(struct udevice *dev);
#ifdef CONFIG_MCAST_TFTP
int (*mcast)(struct udevice *dev, const u8 *enetaddr, int join);
#endif
int (*write_hwaddr)(struct udevice *dev);
int (*read_rom_hwaddr)(struct udevice *dev);
};
#define eth_get_ops(dev) ((struct eth_ops *)(dev)->driver->ops)
struct udevice *eth_get_dev(void); /* get the current device */
/*
* The devname can be either an exact name given by the driver or device tree
* or it can be an alias of the form "eth%d"
*/
struct udevice *eth_get_dev_by_name(const char *devname);
unsigned char *eth_get_ethaddr(void); /* get the current device MAC */
/* Used only when NetConsole is enabled */
int eth_is_active(struct udevice *dev); /* Test device for active state */
int eth_init_state_only(void); /* Set active state */
void eth_halt_state_only(void); /* Set passive state */
#endif
#ifndef CONFIG_DM_ETH
struct eth_device {
char name[16];
unsigned char enetaddr[6];
phys_addr_t iobase;
int state;
int (*init)(struct eth_device *, bd_t *);
int (*send)(struct eth_device *, void *packet, int length);
int (*recv)(struct eth_device *);
void (*halt)(struct eth_device *);
#ifdef CONFIG_MCAST_TFTP
int (*mcast)(struct eth_device *, const u8 *enetaddr, u8 set);
#endif
int (*write_hwaddr)(struct eth_device *);
struct eth_device *next;
int index;
void *priv;
};
int eth_register(struct eth_device *dev);/* Register network device */
int eth_unregister(struct eth_device *dev);/* Remove network device */
extern struct eth_device *eth_current;
static __always_inline struct eth_device *eth_get_dev(void)
{
return eth_current;
}
struct eth_device *eth_get_dev_by_name(const char *devname);
struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */
/* get the current device MAC */
static inline unsigned char *eth_get_ethaddr(void)
{
if (eth_current)
return eth_current->enetaddr;
return NULL;
}
/* Used only when NetConsole is enabled */
int eth_is_active(struct eth_device *dev); /* Test device for active state */
/* Set active state */
static __always_inline int eth_init_state_only(void)
{
eth_get_dev()->state = ETH_STATE_ACTIVE;
return 0;
}
/* Set passive state */
static __always_inline void eth_halt_state_only(void)
{
eth_get_dev()->state = ETH_STATE_PASSIVE;
}
/*
* Set the hardware address for an ethernet interface based on 'eth%daddr'
* environment variable (or just 'ethaddr' if eth_number is 0).
* Args:
* base_name - base name for device (normally "eth")
* eth_number - value of %d (0 for first device of this type)
* Returns:
* 0 is success, non-zero is error status from driver.
*/
int eth_write_hwaddr(struct eth_device *dev, const char *base_name,
int eth_number);
int usb_eth_initialize(bd_t *bi);
#endif
int eth_initialize(void); /* Initialize network subsystem */
void eth_try_another(int first_restart); /* Change the device */
void eth_set_current(void); /* set nterface to ethcur var */
int eth_get_dev_index(void); /* get the device index */
void eth_parse_enetaddr(const char *addr, uchar *enetaddr);
int eth_getenv_enetaddr(const char *name, uchar *enetaddr);
int eth_setenv_enetaddr(const char *name, const uchar *enetaddr);
/**
* eth_setenv_enetaddr_by_index() - set the MAC address environment variable
*
* This sets up an environment variable with the given MAC address (@enetaddr).
* The environment variable to be set is defined by <@base_name><@index>addr.
* If @index is 0 it is omitted. For common Ethernet this means ethaddr,
* eth1addr, etc.
*
* @base_name: Base name for variable, typically "eth"
* @index: Index of interface being updated (>=0)
* @enetaddr: Pointer to MAC address to put into the variable
* @return 0 if OK, other value on error
*/
int eth_setenv_enetaddr_by_index(const char *base_name, int index,
uchar *enetaddr);
/*
* Get the hardware address for an ethernet interface .
* Args:
* base_name - base name for device (normally "eth")
* index - device index number (0 for first)
* enetaddr - returns 6 byte hardware address
* Returns:
* Return true if the address is valid.
*/
int eth_getenv_enetaddr_by_index(const char *base_name, int index,
uchar *enetaddr);
int eth_init(void); /* Initialize the device */
int eth_send(void *packet, int length); /* Send a packet */
#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
int eth_receive(void *packet, int length); /* Receive a packet*/
extern void (*push_packet)(void *packet, int length);
#endif
int eth_rx(void); /* Check for received packets */
void eth_halt(void); /* stop SCC */
const char *eth_get_name(void); /* get name of current device */
#ifdef CONFIG_MCAST_TFTP
int eth_mcast_join(struct in_addr mcast_addr, int join);
u32 ether_crc(size_t len, unsigned char const *p);
#endif
/**********************************************************************/
/*
* Protocol headers.
*/
/*
* Ethernet header
*/
struct ethernet_hdr {
u8 et_dest[6]; /* Destination node */
u8 et_src[6]; /* Source node */
u16 et_protlen; /* Protocol or length */
};
/* Ethernet header size */
#define ETHER_HDR_SIZE (sizeof(struct ethernet_hdr))
#define ETH_FCS_LEN 4 /* Octets in the FCS */
struct e802_hdr {
u8 et_dest[6]; /* Destination node */
u8 et_src[6]; /* Source node */
u16 et_protlen; /* Protocol or length */
u8 et_dsap; /* 802 DSAP */
u8 et_ssap; /* 802 SSAP */
u8 et_ctl; /* 802 control */
u8 et_snap1; /* SNAP */
u8 et_snap2;
u8 et_snap3;
u16 et_prot; /* 802 protocol */
}__attribute__ ((packed));
/* 802 + SNAP + ethernet header size */
#define E802_HDR_SIZE (sizeof(struct e802_hdr))
/*
* Virtual LAN Ethernet header
*/
struct vlan_ethernet_hdr {
u8 vet_dest[6]; /* Destination node */
u8 vet_src[6]; /* Source node */
u16 vet_vlan_type; /* PROT_VLAN */
u16 vet_tag; /* TAG of VLAN */
u16 vet_type; /* protocol type */
}__attribute__ ((packed));
/* VLAN Ethernet header size */
#define VLAN_ETHER_HDR_SIZE (sizeof(struct vlan_ethernet_hdr))
#define PROT_IP 0x0800 /* IP protocol */
#define PROT_ARP 0x0806 /* IP ARP protocol */
#define PROT_RARP 0x8035 /* IP ARP protocol */
#define PROT_VLAN 0x8100 /* IEEE 802.1q protocol */
#define PROT_IPV6 0x86dd /* IPv6 over bluebook */
#define PROT_PPP_SES 0x8864 /* PPPoE session messages */
#define IPPROTO_ICMP 1 /* Internet Control Message Protocol */
#define IPPROTO_TCP 6 /* Transmission Control Protocol */
#define IPPROTO_UDP 17 /* User Datagram Protocol */
/*
* Internet Protocol (IP) header.
*/
struct ip_hdr {
u8 ip_hl_v; /* header length and version */
u8 ip_tos; /* type of service */
u16 ip_len; /* total length */
u16 ip_id; /* identification */
u16 ip_off; /* fragment offset field */
u8 ip_ttl; /* time to live */
u8 ip_p; /* protocol */
u16 ip_sum; /* checksum */
struct in_addr ip_src; /* Source IP address */
struct in_addr ip_dst; /* Destination IP address */
}__attribute__ ((packed));
#define IP_OFFS 0x1fff /* ip offset *= 8 */
#define IP_FLAGS 0xe000 /* first 3 bits */
#define IP_FLAGS_RES 0x8000 /* reserved */
#define IP_FLAGS_DFRAG 0x4000 /* don't fragment */
#define IP_FLAGS_MFRAG 0x2000 /* more fragments */
#define IP_HDR_SIZE (sizeof(struct ip_hdr))
/*
* Internet Protocol (IP) + UDP header.
*/
struct ip_udp_hdr {
u8 ip_hl_v; /* header length and version */
u8 ip_tos; /* type of service */
u16 ip_len; /* total length */
u16 ip_id; /* identification */
/* Flags first 3 bits of ip_off */
u16 ip_off; /* fragment offset field */
u8 ip_ttl; /* time to live */
u8 ip_p; /* protocol */
u16 ip_sum; /* checksum */
struct in_addr ip_src; /* Source IP address */
struct in_addr ip_dst; /* Destination IP address */
u16 udp_src; /* UDP source port */
u16 udp_dst; /* UDP destination port */
u16 udp_len; /* Length of UDP packet */
u16 udp_xsum; /* Checksum */
}__attribute__ ((packed));
#define IP_UDP_HDR_SIZE (sizeof(struct ip_udp_hdr))
#define UDP_HDR_SIZE (IP_UDP_HDR_SIZE - IP_HDR_SIZE)
/*
* Internet Protocol (IP) + TCP header.
*/
struct ip_tcp_hdr {
u8 ip_hl_v; /* header length and version */
u8 ip_tos; /* type of service */
u16 ip_len; /* total length */
u16 ip_id; /* identification */
u16 ip_off; /* fragment offset field */
u8 ip_ttl; /* time to live */
u8 ip_p; /* protocol */
u16 ip_sum; /* checksum */
struct in_addr ip_src; /* Source IP address */
struct in_addr ip_dst; /* Destination IP address */
u16 tcp_src; /* TCP source port */
u16 tcp_dst; /* TCP destination port */
u32 tcp_seq; /* TCP sequence number */
u32 tcp_ack; /* TCP Acknowledgement number */
u8 tcp_hlen; /* 4 bits TCP header Length/4 */
/* 4 bits Reserved */
/* 2 more bits reserver */
u8 tcp_flags; /* see defines */
u16 tcp_win; /* TCP windows size */
u16 tcp_xsum; /* Checksum */
u16 tcp_ugr; /* Pointer to urgent data */
}__attribute__ ((packed));
#define IP_TCP_HDR_SIZE (sizeof(struct ip_tcp_hdr))
#define TCP_HDR_SIZE (IP_TCP_HDR_SIZE - IP_HDR_SIZE)
#define TCP_DATA 0x00 /* Data Packet - internal use only */
#define TCP_FIN 0x01 /* Finish flag */
#define TCP_SYN 0x02 /* start flag */
#define TCP_RST 0x04 /* reset flag */
#define TCP_PUSH 0x08 /* Push - Notify app */
#define TCP_ACK 0x10 /* Acknowledgement of data received */
#define TCP_URG 0x20 /* Urgent */
#define TCP_ECE 0x40 /* Unknown */
#define TCP_CWR 0x80 /* Unknown */
/*
* TCP header options, Seq, MSS, and SACK
*/
#define TCP_O_END 0x00 /* End of option list */
#define TCP_1_NOP 0x01 /* Single padding NOP */
#define TCP_O_NOP 0x01010101 /* NOPs pad to 32 bit boundary */
#define TCP_O_MSS 0x02 /* MSS Size option */
#define TCP_O_SCL 0x03 /* Window Scale option */
#define TCP_P_SACK 0x04 /* SACK permitted */
#define TCP_V_SACK 0x05 /* SACK values */
#define TCP_O_TS 0x08 /* Timestanp option */
#define TCP_OPT_LEN_2 0x02
#define TCP_OPT_LEN_3 0x03
#define TCP_OPT_LEN_4 0x04
#define TCP_OPT_LEN_6 0x06
#define TCP_OPT_LEN_8 0x08
#define TCP_OPT_LEN_A 0x0a /* TimestampLength */
#define TCP_MSS 1460 /* Max segment size - 1460 */
#define TCP_SCALE 0x01 /* Scale 1 */
struct tcp_mss{ /* TCP Mex Segment size */
u8 kind ; /* 0x02 */
u8 len; /* 0x04 */
u16 mss; /* 1460 - Max segment size */
}__attribute__ ((packed));
struct tcp_scale { /* TCP Windows Scale */
u8 kind; /* 0x03 */
u8 len; /* 0x03 */
u8 scale; /* win shift fat fast networks */
}__attribute__ ((packed));
struct tcp_sack_p { /* SACK permitted */
u8 kind; /* 0x04 */
u8 len; /* Length */
}__attribute__ ((packed));
struct sack_edges {
u32 l;
u32 r;
}__attribute__ ((packed));
#define TCP_STREAM_HOLES 16
#define TCP_SAK_HOLES 3
#define TCP_HOLE_AGE 4
struct tcp_sack_v {
u8 kind; /* 0x05 */
u8 len; /* Length */
struct sack_edges hole[TCP_SAK_HOLES]; /* L & R widow edges */
}__attribute__ ((packed));
struct tcp_TSopt{ /* TCP time stamps option */
u8 kind; /* 0x08 */
u8 len; /* 0x0a */
u32 TSsnd; /* Sender timestamp */
u32 TSrcv; /* Receiver timestamp */
}__attribute__ ((packed));
#define TCP_TSOPT_SIZE (sizeof(struct tcp_TSopt))
/*
* ip tcp structure with options
*/
struct ip_tcp_hdr_o {
struct ip_tcp_hdr hdr;
struct tcp_mss mss;
struct tcp_scale scale;
struct tcp_sack_p sack_p;
struct tcp_TSopt TSopt;
u8 end;
}__attribute__ ((packed));
#define IP_TCP_O_SIZE (sizeof(struct ip_tcp_hdr_o))
struct ip_tcp_hdr_s {
struct ip_tcp_hdr hdr;
struct tcp_TSopt TSopt;
struct tcp_sack_v sack_v;
u8 end;
}__attribute__ ((packed));
#define IP_TCP_SACK_SIZE (sizeof(struct ip_tcp_hdr_s))
/*
* TCP psuedo header definitions
*/
struct psuedo_hdr{
u8 padding[8]; /* psuedo header size = ip_tcp hdr size */
struct in_addr p_src;
struct in_addr p_dst;
u8 rsvd;
u8 p;
u16 len;
}__attribute__ ((packed));
#define PSUEDO_PAD_SIZE 8
#define PSUEDO_HDR_SIZE 12
/*
* union for building IP/TCP packet.
* build Psuedo header in packed bufferfirst, calculate TCP checksum
* then build IP header in packe buffer.
*/
union tcp_build_pkt{
struct psuedo_hdr ph;
struct ip_tcp_hdr_o ip;
struct ip_tcp_hdr_s sack;
uchar raw[1600];
}__attribute__ ((packed));
/*
* TCP STATE MACHINE STATES FOR SOCKET
*/
enum TCP_STATE
{
TCP_CLOSED, /* Need to send SYN to connect */
TCP_SYN_SENT, /* Trying to connect, waiting for SYN ACK */
TCP_ESTABLISHED, /* both server and client represents an open connection */
TCP_CLOSE_WAIT, /* Received FIN, passed to app for FIN, ACK response */
TCP_CLOSING, /* Received FIN, sent FIN, ACK waiting for ACK */
TCP_FIN_WAIT_1, /* Sendt FIN waiting for response */
TCP_FIN_WAIT_2 /* Received ACK from FIN sent, waitng for FIN */
};
enum TCP_STATE net_get_tcp_state( void );
/*
* TCP incoming packet handler
*/
typedef void rxhand_tcp(uchar *pkt, unsigned dport,
struct in_addr sip, unsigned sport,
unsigned len, enum TCP_STATE tcp_state);
/*
* Address Resolution Protocol (ARP) header.
*/
struct arp_hdr {
u16 ar_hrd; /* Format of hardware address */
# define ARP_ETHER 1 /* Ethernet hardware address */
u16 ar_pro; /* Format of protocol address */
u8 ar_hln; /* Length of hardware address */
# define ARP_HLEN 6
u8 ar_pln; /* Length of protocol address */
# define ARP_PLEN 4
u16 ar_op; /* Operation */
# define ARPOP_REQUEST 1 /* Request to resolve address */
# define ARPOP_REPLY 2 /* Response to previous request */
# define RARPOP_REQUEST 3 /* Request to resolve address */
# define RARPOP_REPLY 4 /* Response to previous request */
/*
* The remaining fields are variable in size, according to
* the sizes above, and are defined as appropriate for
* specific hardware/protocol combinations.
*/
u8 ar_data[0];
#define ar_sha ar_data[0]
#define ar_spa ar_data[ARP_HLEN]
#define ar_tha ar_data[ARP_HLEN + ARP_PLEN]
#define ar_tpa ar_data[ARP_HLEN + ARP_PLEN + ARP_HLEN]
#if 0
u8 ar_sha[]; /* Sender hardware address */
u8 ar_spa[]; /* Sender protocol address */
u8 ar_tha[]; /* Target hardware address */
u8 ar_tpa[]; /* Target protocol address */
#endif /* 0 */
};
#define ARP_HDR_SIZE (8+20) /* Size assuming ethernet */
/*
* ICMP stuff (just enough to handle (host) redirect messages)
*/
#define ICMP_ECHO_REPLY 0 /* Echo reply */
#define ICMP_NOT_REACH 3 /* Detination unreachable */
#define ICMP_REDIRECT 5 /* Redirect (change route) */
#define ICMP_ECHO_REQUEST 8 /* Echo request */
/* Codes for REDIRECT. */
#define ICMP_REDIR_NET 0 /* Redirect Net */
#define ICMP_REDIR_HOST 1 /* Redirect Host */
/* Codes for NOT_REACH */
#define ICMP_NOT_REACH_PORT 3 /* Port unreachable */
struct icmp_hdr {
u8 type;
u8 code;
u16 checksum;
union {
struct {
u16 id;
u16 sequence;
} echo;
u32 gateway;
struct {
u16 unused;
u16 mtu;
} frag;
u8 data[0];
} un;
};
#define ICMP_HDR_SIZE (sizeof(struct icmp_hdr))
#define IP_ICMP_HDR_SIZE (IP_HDR_SIZE + ICMP_HDR_SIZE)
/*
* Maximum packet size; used to allocate packet storage. Use
* the maxium Ethernet frame size as specified by the Ethernet
* standard including the 802.1Q tag (VLAN tagging).
* maximum packet size = 1522
* maximum packet size and multiple of 32 bytes = 1536
*/
#define PKTSIZE 1522
#define PKTSIZE_ALIGN 1536
/*
* Maximum receive ring size; that is, the number of packets
* we can buffer before overflow happens. Basically, this just
* needs to be enough to prevent a packet being discarded while
* we are processing the previous one.
*/
#define RINGSZ 4
#define RINGSZ_LOG2 2
/**********************************************************************/
/*
* Globals.
*
* Note:
*
* All variables of type struct in_addr are stored in NETWORK byte order
* (big endian).
*/
/* net.c */
/** BOOTP EXTENTIONS **/
extern struct in_addr net_gateway; /* Our gateway IP address */
extern struct in_addr net_netmask; /* Our subnet mask (0 = unknown) */
/* Our Domain Name Server (0 = unknown) */
extern struct in_addr net_dns_server;
#if defined(CONFIG_BOOTP_DNS2)
/* Our 2nd Domain Name Server (0 = unknown) */
extern struct in_addr net_dns_server2;
#endif
extern char net_nis_domain[32]; /* Our IS domain */
extern char net_hostname[32]; /* Our hostname */
extern char net_root_path[64]; /* Our root path */
/** END OF BOOTP EXTENTIONS **/
extern u8 net_ethaddr[6]; /* Our ethernet address */
extern u8 net_server_ethaddr[6]; /* Boot server enet address */
extern struct in_addr net_ip; /* Our IP addr (0 = unknown) */
extern struct in_addr net_server_ip; /* Server IP addr (0 = unknown) */
extern uchar *net_tx_packet; /* THE transmit packet */
extern uchar *net_rx_packets[PKTBUFSRX]; /* Receive packets */
extern uchar *net_rx_packet; /* Current receive packet */
extern int net_rx_packet_len; /* Current rx packet length */
extern const u8 net_bcast_ethaddr[6]; /* Ethernet broadcast address */
extern const u8 net_null_ethaddr[6];
#define VLAN_NONE 4095 /* untagged */
#define VLAN_IDMASK 0x0fff /* mask of valid vlan id */
extern ushort net_our_vlan; /* Our VLAN */
extern ushort net_native_vlan; /* Our Native VLAN */
extern int net_restart_wrap; /* Tried all network devices */
enum proto_t {
BOOTP, RARP, ARP, TFTPGET, DHCP, PING, DNS, NFS, CDP, NETCONS, SNTP,
TFTPSRV, TFTPPUT, LINKLOCAL, WGET
};
extern char net_boot_file_name[1024];/* Boot File name */
/* The actual transferred size of the bootfile (in bytes) */
extern u32 net_boot_file_size;
/* Boot file size in blocks as reported by the DHCP server */
extern u32 net_boot_file_expected_size_in_blocks;
#if defined(CONFIG_CMD_DNS)
extern char *net_dns_resolve; /* The host to resolve */
extern char *net_dns_env_var; /* the env var to put the ip into */
#endif
#if defined(CONFIG_CMD_PING)
extern struct in_addr net_ping_ip; /* the ip address to ping */
#endif
#if defined(CONFIG_CMD_CDP)
/* when CDP completes these hold the return values */
extern ushort cdp_native_vlan; /* CDP returned native VLAN */
extern ushort cdp_appliance_vlan; /* CDP returned appliance VLAN */
/*
* Check for a CDP packet by examining the received MAC address field
*/
static inline int is_cdp_packet(const uchar *ethaddr)
{
extern const u8 net_cdp_ethaddr[6];
return memcmp(ethaddr, net_cdp_ethaddr, 6) == 0;
}
#endif
#if defined(CONFIG_CMD_SNTP)
extern struct in_addr net_ntp_server; /* the ip address to NTP */
extern int net_ntp_time_offset; /* offset time from UTC */
#endif
#if defined(CONFIG_MCAST_TFTP)
extern struct in_addr net_mcast_addr;
#endif
/* Initialize the network adapter */
void net_init(void);
int net_loop(enum proto_t);
/* Load failed. Start again. */
int net_start_again(void);
/* Get size of the ethernet header when we send */
int net_eth_hdr_size(void);
/* Set ethernet header; returns the size of the header */
int net_set_ether(uchar *xet, const uchar *dest_ethaddr, uint prot);
int net_update_ether(struct ethernet_hdr *et, uchar *addr, uint prot);
/* Set IP header */
void net_set_ip_header(uchar *pkt, struct in_addr dest, struct in_addr source,
u16 pkt_len, u8 prot );
int net_set_tcp_header(uchar *pkt, int len, u8 action, u32 tcp_seq_num, u32 tcp_ack_seq_num );
void net_set_udp_header(uchar *pkt, struct in_addr dest, int dport,
int sport, int len);
/* Set ports */
void net_set_ports( int server_port, int our_port );
/* Sequence number and SAK management */
void net_tcp_hole_contract( u32 tcp_seq_num, u32 tcp_end_num );
void net_tcp_hole_expand( u32 tcp_seq_num, u32 tcp_end_num );
/* Print packet or messsage */
void net_print_buffer( uchar raw[], int pkt_len, int payload_len,
int hdr_len, bool hide );
/* Find string in buffer */
int net_find_in_buffer( uchar raw[], int payload_len, uchar field[], int field_len );
/**
* compute_ip_checksum() - Compute IP checksum
*
* @addr: Address to check (must be 16-bit aligned)
* @nbytes: Number of bytes to check (normally a multiple of 2)
* @return 16-bit IP checksum
*/
unsigned compute_ip_checksum(const void *addr, unsigned nbytes);
/**
* add_ip_checksums() - add two IP checksums
*
* @offset: Offset of first sum (if odd we do a byte-swap)
* @sum: First checksum
* @new_sum: New checksum to add
* @return updated 16-bit IP checksum
*/
unsigned add_ip_checksums(unsigned offset, unsigned sum, unsigned new_sum);
/**
* ip_checksum_ok() - check if a checksum is correct
*
* This works by making sure the checksum sums to 0
*
* @addr: Address to check (must be 16-bit aligned)
* @nbytes: Number of bytes to check (normally a multiple of 2)
* @return true if the checksum matches, false if not
*/
int ip_checksum_ok(const void *addr, unsigned nbytes);
/* Callbacks */
rxhand_f *net_get_tcp_handler(void); /* Get TCP RX packet handler */
void net_set_tcp_handler(rxhand_f *); /* Set TCP RX packet handler */
rxhand_f *net_get_udp_handler(void); /* Get UDP RX packet handler */
void net_set_udp_handler(rxhand_f *); /* Set UDP RX packet handler */
rxhand_f *net_get_arp_handler(void); /* Get ARP RX packet handler */
void net_set_arp_handler(rxhand_f *); /* Set ARP RX packet handler */
void net_set_icmp_handler(rxhand_icmp_f *f); /* Set ICMP RX handlr*/
void net_set_timeout_handler(ulong, thand_f *); /* Set timeout handlr*/
/* Network loop state */
enum net_loop_state {
NETLOOP_CONTINUE,
NETLOOP_RESTART,
NETLOOP_SUCCESS,
NETLOOP_FAIL
};
extern enum net_loop_state net_state;
static inline void net_set_state(enum net_loop_state state)
{
debug_cond(DEBUG_INT_STATE, "--- NetState set to %d\n", state);
net_state = state;
}
/* Transmit a packet */
static inline void net_send_packet(uchar *pkt, int len)
{
/* Currently no way to return errors from eth_send() */
(void) eth_send(pkt, len);
}
/*
* Transmit "net_tx_packet" as UDP packet, performing ARP request if needed
* (ether will be populated)
*
* @param ether Raw packet buffer
* @param dest IP address to send the datagram to
* @param dport Destination UDP port
* @param sport Source UDP port
* @param payload_len Length of data after the UDP header
* Added TCP support and protocol parameter for sending ip packets, and
* shim to support existing udp interface.
*/
int net_send_ip_packet( int payload_len, int proto, u8 action, u32 tcp_seq_num, u32 tcp_ack_num );
int net_send_udp_packet(uchar *ether, struct in_addr dest, int dport,
int sport, int payload_len);
/* Processes a received packet */
void net_process_received_packet(uchar *in_packet, int len);
#ifdef CONFIG_NETCONSOLE
void nc_start(void);
int nc_input_packet(uchar *pkt, struct in_addr src_ip, unsigned dest_port,
unsigned src_port, unsigned len);
#endif
static __always_inline int eth_is_on_demand_init(void)
{
#ifdef CONFIG_NETCONSOLE
extern enum proto_t net_loop_last_protocol;
return net_loop_last_protocol != NETCONS;
#else
return 1;
#endif
}
static inline void eth_set_last_protocol(int protocol)
{
#ifdef CONFIG_NETCONSOLE
extern enum proto_t net_loop_last_protocol;
net_loop_last_protocol = protocol;
#endif
}
/*
* Check if autoload is enabled. If so, use either NFS or TFTP to download
* the boot file.
*/
void net_auto_load(void);
/*
* The following functions are a bit ugly, but necessary to deal with
* alignment restrictions on ARM.
*
* We're using inline functions, which had the smallest memory
* footprint in our tests.
*/
/* return IP *in network byteorder* */
static inline struct in_addr net_read_ip(void *from)
{
struct in_addr ip;
memcpy((void *)&ip, (void *)from, sizeof(ip));
return ip;
}
/* return ulong *in network byteorder* */
static inline u32 net_read_u32(u32 *from)
{
u32 l;
memcpy((void *)&l, (void *)from, sizeof(l));
return l;
}
/* write IP *in network byteorder* */
static inline void net_write_ip(void *to, struct in_addr ip)
{
memcpy(to, (void *)&ip, sizeof(ip));
}
/* copy IP */
static inline void net_copy_ip(void *to, void *from)
{
memcpy((void *)to, from, sizeof(struct in_addr));
}
/* copy ulong */
static inline void net_copy_u32(u32 *to, u32 *from)
{
memcpy((void *)to, (void *)from, sizeof(u32));
}
/**
* is_zero_ethaddr - Determine if give Ethernet address is all zeros.
* @addr: Pointer to a six-byte array containing the Ethernet address
*
* Return true if the address is all zeroes.
*/
static inline int is_zero_ethaddr(const u8 *addr)
{
return !(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5]);
}
/**
* is_multicast_ethaddr - Determine if the Ethernet address is a multicast.
* @addr: Pointer to a six-byte array containing the Ethernet address
*
* Return true if the address is a multicast address.
* By definition the broadcast address is also a multicast address.
*/
static inline int is_multicast_ethaddr(const u8 *addr)
{
return 0x01 & addr[0];
}
/*
* is_broadcast_ethaddr - Determine if the Ethernet address is broadcast
* @addr: Pointer to a six-byte array containing the Ethernet address
*
* Return true if the address is the broadcast address.
*/
static inline int is_broadcast_ethaddr(const u8 *addr)
{
return (addr[0] & addr[1] & addr[2] & addr[3] & addr[4] & addr[5]) ==
0xff;
}
/*
* is_valid_ethaddr - Determine if the given Ethernet address is valid
* @addr: Pointer to a six-byte array containing the Ethernet address
*
* Check that the Ethernet address (MAC) is not 00:00:00:00:00:00, is not
* a multicast address, and is not FF:FF:FF:FF:FF:FF.
*
* Return true if the address is valid.
*/
static inline int is_valid_ethaddr(const u8 *addr)
{
/* FF:FF:FF:FF:FF:FF is a multicast address so we don't need to
* explicitly check for it here. */
return !is_multicast_ethaddr(addr) && !is_zero_ethaddr(addr);
}
/**
* net_random_ethaddr - Generate software assigned random Ethernet address
* @addr: Pointer to a six-byte array containing the Ethernet address
*
* Generate a random Ethernet address (MAC) that is not multicast
* and has the local assigned bit set.
*/
static inline void net_random_ethaddr(uchar *addr)
{
int i;
unsigned int seed = get_timer(0);
for (i = 0; i < 6; i++)
addr[i] = rand_r(&seed);
addr[0] &= 0xfe; /* clear multicast bit */
addr[0] |= 0x02; /* set local assignment bit (IEEE802) */
}
/* Convert an IP address to a string */
void ip_to_string(struct in_addr x, char *s);
/* Convert a string to ip address */
struct in_addr string_to_ip(const char *s);
/* Convert a VLAN id to a string */
void vlan_to_string(ushort x, char *s);
/* Convert a string to a vlan id */
ushort string_to_vlan(const char *s);
/* read a VLAN id from an environment variable */
ushort getenv_vlan(char *);
/* copy a filename (allow for "..." notation, limit length) */
void copy_filename(char *dst, const char *src, int size);
/* get a random source port */
unsigned int random_port(void);
/**
* update_tftp - Update firmware over TFTP (via DFU)
*
* This function updates board's firmware via TFTP
*
* @param addr - memory address where data is stored
* @param interface - the DFU medium name - e.g. "mmc"
* @param devstring - the DFU medium number - e.g. "1"
*
* @return - 0 on success, other value on failure
*/
int update_tftp(ulong addr, char *interface, char *devstring);
/**********************************************************************/
#endif /* __NET_H__ */
net/wget.c
/*
* FILE support driver - based on etherboot and U-BOOT's tftp.c
*
* Duncan Hare <dh(a)synoia.com> 2017
*
*/
#include <common.h>
#include <command.h>
#include <fat.h> //FAT
#include <net.h>
#include <mapmem.h>
#ifdef TCP
#define FILE_TEST 0 /* Set to 1 for debug messges */
#define FILE_RETRY_COUNT 30
#ifndef CONFIG_FILE_TIMEOUT
# define FILE_TIMEOUT 2000UL
#define SERVER_PORT 8081
#else
# define FILE_TIMEOUT CONFIG_FILE_TIMEOUT
#endif
char bootfile[50] = "GET /r.32.test/boot/cmdline.txt HTTP/1.1\r\n\r\n";
char bootfile1[10] = "GET ";
char bootfile2[30] = "/r.32.test/boot/cmdline.txt";
char bootfile3[20] = " HTTP/1.1\r\n\r\n";
uchar content[6] = "<html>";
uchar error404[3] = "404";
static unsigned int file_timeout = FILE_TIMEOUT;
static struct in_addr file_server_ip;
static int file_timeout_count;
int packets = 0;
static u32 initial_data_seq_num;
enum FILE_STATE {
FILE_CLOSED,
FILE_CONNECTING,
FILE_CONNECTED,
FILE_TRANSFERRING,
FILE_TRANSFERRED};
static enum FILE_STATE file_state;
static char *file_filename;
static char *file_path;
static char file_path_buff[2048];
int i = 0;
static void file_timeout_handler(void);
void file_fail( char * error_message, unsigned tcp_seq_num, unsigned tcp_ack_num, u8 action );
static inline int store_block(uchar *src, unsigned offset, unsigned len)
{
ulong newsize = offset + len;
#ifdef CONFIG_SYS_DIRECT_FLASH_WGET
int i, rc = 0;
for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
/* start address in flash? */
if (load_addr + offset >= flash_info[i].start[0]) {
rc = 1;
break;
}
}
if (rc) { /* Flash is destination for this packet */
rc = flash_write((uchar *)src, (ulong)(load_addr+offset), len);
if (rc) {
flash_perror(rc);
return -1;
}
} else
#endif /* CONFIG_SYS_DIRECT_FLASH_NFS */
{
uchar *ptr = map_sysmem(load_addr + offset, len);
memcpy(ptr, src, len);
if ( i < 3 )
{
printf( "Offset %d, Length %d\n", offset, len );
net_print_buffer( src, 24, 24, 24, 0 );
i++;
net_print_buffer( src + len -24, (int)src + len -24, 24, 24, 0);
}
unmap_sysmem(ptr);
}
if (net_boot_file_size < (offset + len))
net_boot_file_size = newsize;
return 0;
}
/*
* File request dispatcher
* WARNING, This, and only this, is the place where
* SEQUENCE NUMBERS are swapped betweeen incoming (RX) and outgoing (TX)
* What is in procedure file_handler() is correct for RX traffic.
*/
static void file_send( u8 action, unsigned tcp_ack_num, unsigned tcp_seq_num, int len )
{
uchar *ptr;
uchar *offset;
tcp_ack_num = tcp_ack_num + len;
switch (file_state)
{
case FILE_CLOSED:
debug_cond( FILE_TEST, "File send: send SYN\n");
file_state = FILE_CONNECTING;
net_send_ip_packet( 0, IPPROTO_TCP, action, tcp_seq_num, tcp_ack_num );
break;
case FILE_CONNECTING:
debug_cond( FILE_TEST, "File send: send HTTP GET\n");
ptr = net_tx_packet + net_eth_hdr_size() + IP_TCP_HDR_SIZE + TCP_TSOPT_SIZE + 2;
offset = ptr;
memcpy( offset, &bootfile1, strlen(bootfile1) );
offset = offset + strlen(bootfile1);
// memcpy( offset, &bootfile2, strlen(bootfile2) );
// offset = offset + strlen(bootfile2);
memcpy( offset, file_path, strlen(file_path) );
offset = offset + strlen(file_path);
memcpy( offset, &bootfile3, strlen(bootfile3) );
offset = offset + strlen(bootfile3);
net_send_ip_packet(( offset - ptr), IPPROTO_TCP, TCP_DATA, tcp_seq_num, tcp_ack_num );
file_state = FILE_CONNECTED;
break;
case FILE_CONNECTED:
debug_cond( FILE_TEST, "File send: Header\n" );
file_state = FILE_TRANSFERRING;
break;
case FILE_TRANSFERRING:
debug_cond( FILE_TEST, "File send:Transferring \n");
net_send_ip_packet( 0, IPPROTO_TCP, action, tcp_seq_num, tcp_ack_num);
break;
case FILE_TRANSFERRED:
debug_cond( FILE_TEST, "File send:Transferred \n");
net_send_ip_packet( 0, IPPROTO_TCP, action, tcp_seq_num, tcp_ack_num);
break;
}
}
void file_success( u8 action, unsigned tcp_seq_num, unsigned tcp_ack_num, int len, int packets )
{
file_state = FILE_TRANSFERRED;
net_set_state( NETLOOP_SUCCESS );
net_set_timeout_handler( 0, NULL);
debug_cond( 1, "Packets received %d, File send:SUCCESS!!!\n", packets );
file_send( action, tcp_seq_num, tcp_ack_num, len );
}
void file_fail( char * error_message, unsigned tcp_seq_num, unsigned tcp_ack_num, u8 action )
{
debug_cond( FILE_TEST, error_message );
debug_cond( FILE_TEST, "File Fail\n" );
file_state = FILE_TRANSFERRED;
net_set_timeout_handler( 0, NULL);
net_set_state( NETLOOP_FAIL );
file_send( action | TCP_FIN, tcp_seq_num, tcp_ack_num, 0 );
}
/*
* Interfaces of U-BOOT
*/
static void file_timeout_handler(void)
{
if (++file_timeout_count > FILE_RETRY_COUNT) {
puts("\nRetry count exceeded; starting again\n");
net_start_again();
} else {
puts("T ");
net_set_timeout_handler(file_timeout +
FILE_TIMEOUT * file_timeout_count,
file_timeout_handler);
file_send( TCP_DATA, 0, 0, 0 );
}
}
/*
* In the "application push" invocation the TCP header with all its information is $
* packet pointer, and the other variable "repurposed" (or misused) to carry sequen$
* and TCP state.
*
* Parms: ((uchar *) b, tcp_ack_num, action_and_state, tcp_seq_num, payload_len );
*
*/
static void file_handler(uchar *pkt, unsigned tcp_seq_num, struct in_addr action_and_state,
unsigned tcp_ack_num, unsigned len )
{
enum TCP_STATE file_tcp_state = net_get_tcp_state();
u8 action = action_and_state.s_addr;
int offset;
net_set_timeout_handler(file_timeout, file_timeout_handler);
packets ++;
switch (file_state)
{
case FILE_CLOSED:
debug_cond( FILE_TEST, "File Handler: Error!, State wrong\n");
break;
case FILE_CONNECTING:
debug_cond(FILE_TEST, "File Connecting In len=%d, Seq=%d, Ack=%d\n",
len, tcp_seq_num, tcp_ack_num );
if ( len == 0 )
{
if ( file_tcp_state == TCP_ESTABLISHED )
{
debug_cond( FILE_TEST, "File Handler Connecting, send, len=%d\n", len );
file_send( action, tcp_seq_num, tcp_ack_num, len );
}
else file_fail( "File Handler Connected Fail\n",
tcp_seq_num, tcp_ack_num, action );
}
break;
case FILE_CONNECTED:
debug_cond(FILE_TEST, "File Connected In len=%d, seq=%d, ack=%d\n"
, len, tcp_seq_num, tcp_ack_num );
if ( len == 0 )
{
file_fail("File not found, no data returned/n" ,
tcp_seq_num, tcp_ack_num, action );
}
else if ( net_find_in_buffer( pkt, len, error404, 3) > 0 )
{
offset = net_find_in_buffer( pkt, len, content, 6 );
net_print_buffer( pkt, offset-4, offset-4, -1, 0 );
pkt[0] = 0x00;
file_fail( (char *)pkt, tcp_seq_num, tcp_ack_num, action );
}
else /* Got HTTP Header */
{
net_print_buffer( pkt, len, len, -1, 0 );
file_state = FILE_TRANSFERRING;
initial_data_seq_num = tcp_seq_num + len;
file_send( action, tcp_seq_num, tcp_ack_num, len );
}
break;
case FILE_TRANSFERRING:
debug_cond(FILE_TEST, "File Transferring, seq=%d, ack=%d,len=%d\n"
, tcp_seq_num, tcp_ack_num, len );
if ( len > 0 )
{
offset = tcp_seq_num - initial_data_seq_num;
if ( store_block( pkt, offset, len) != 0 )
file_fail( "File store error\n",
tcp_seq_num, tcp_ack_num, action );
else switch (file_tcp_state)
{
case TCP_SYN_SENT:
case TCP_CLOSING:
case TCP_FIN_WAIT_1:
case TCP_FIN_WAIT_2:
case TCP_CLOSED:
net_set_state(NETLOOP_FAIL);
break;
case TCP_ESTABLISHED:
file_send( TCP_ACK, tcp_seq_num, tcp_ack_num, len );
break;
case TCP_CLOSE_WAIT: /* End of file */
file_success( action | TCP_ACK,
tcp_seq_num, tcp_ack_num, len, packets );
break;
}
}
else file_send( action , tcp_seq_num, tcp_ack_num, len );
break;
case FILE_TRANSFERRED:
file_send( TCP_ACK, tcp_seq_num, tcp_ack_num, len );
break;
}
}
void wget_start(void)
{
debug("%s\n", __func__);
file_server_ip = net_server_ip;
file_path = (char *)file_path_buff;
if (file_path == NULL) {
net_set_state(NETLOOP_FAIL);
debug("*** ERROR: Fail allocate memory\n");
return;
}
if (net_boot_file_name[0] == '\0') {
sprintf(file_path, "/fileroot/%02X%02X%02X%02X.img",
net_ip.s_addr & 0xFF,
(net_ip.s_addr >> 8) & 0xFF,
(net_ip.s_addr >> 16) & 0xFF,
(net_ip.s_addr >> 24) & 0xFF);
debug("*** Warning: no boot file name; using '%s'\n",
file_path);
} else {
char *p = net_boot_file_name;
p = strchr(p, ':');
if (p != NULL) {
file_server_ip = string_to_ip(net_boot_file_name);
++p;
strcpy(file_path, p);
} else {
strcpy(file_path, net_boot_file_name);
}
}
debug_cond( FILE_TEST, "Using %s device\n", eth_get_name());
debug_cond( FILE_TEST, "File transfer via HTTP from server %pI4; our IP address is %pI4\n",
&file_server_ip, &net_ip);
/* Check if we need to send across this subnet */
if (net_gateway.s_addr && net_netmask.s_addr) {
struct in_addr our_net;
struct in_addr server_net;
our_net.s_addr = net_ip.s_addr & net_netmask.s_addr;
server_net.s_addr = net_server_ip.s_addr & net_netmask.s_addr;
if (our_net.s_addr != server_net.s_addr)
debug("; sending through gateway %pI4",
&net_gateway);
}
debug_cond(FILE_TEST, "Filename '%s, %s'.\n", file_path, file_filename);
if (net_boot_file_expected_size_in_blocks) {
debug(" Size is 0x%x Bytes = ",
net_boot_file_expected_size_in_blocks << 9);
print_size(net_boot_file_expected_size_in_blocks << 9, "");
}
debug("\nLoad address: 0x%lx\nLoading: *\b", load_addr);
net_set_timeout_handler(file_timeout, file_timeout_handler);
net_set_tcp_handler(file_handler);
file_timeout_count = 0;
file_state = FILE_CLOSED;
net_set_ports( SERVER_PORT, 4096 + (get_ticks() % 3072));
/* zero out server ether in case the server ip has changed */
memset(net_server_ethaddr, 0, 6);
file_send( TCP_SYN, 0, 0, 0 );
}
#endif
wget.h
/*
* Duncan Hare Copyright 2017
*/
void wget_start(void); /* Begin NFS */
net/ping.c changes
struct icmp_hdr *icmp = (struct icmp_hdr *)(pkt + IP_HDR_SIZE);
net_set_ip_header(pkt, dest, net_ip, IP_ICMP_HDR_SIZE, IPPROTO_ICMP);
icmp->type = ICMP_ECHO_REQUEST;
icmp->code = 0;
icmp->checksum = 0;
icmp->un.echo.id = 0;
icmp->un.echo.sequence = htons(ping_seq_number++);
icmp->checksum = compute_ip_checksum(icmp, ICMP_HDR_SIZE);
n Hare
714 931 7952
2
1

[U-Boot] [PATCH 1/1] efi_loader: call EFI_EXIT in efi_copy_mem, efi_set_mem
by Heinrich Schuchardt 25 Sep '17
by Heinrich Schuchardt 25 Sep '17
25 Sep '17
EFI_ENTRY and EFI_EXIT calls must match.
Signed-off-by: Heinrich Schuchardt <xypron.glpk(a)gmx.de>
---
lib/efi_loader/efi_boottime.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index cbc4007f7b..2c2620a46d 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -1882,6 +1882,7 @@ static void EFIAPI efi_copy_mem(void *destination, void *source,
{
EFI_ENTRY("%p, %p, %ld", destination, source, length);
memcpy(destination, source, length);
+ EFI_EXIT(EFI_SUCCESS);
}
/*
@@ -1899,6 +1900,7 @@ static void EFIAPI efi_set_mem(void *buffer, unsigned long size, uint8_t value)
{
EFI_ENTRY("%p, %ld, 0x%x", buffer, size, value);
memset(buffer, value, size);
+ EFI_EXIT(EFI_SUCCESS);
}
/*
--
2.11.0
2
1

[U-Boot] [PATCH v3 0/2] power: Add a driver to handle the PBIAS cell of the TI SOCs
by Jean-Jacques Hiblot 25 Sep '17
by Jean-Jacques Hiblot 25 Sep '17
25 Sep '17
In the TI SOCs a PBIAS cell exists to provide a bias voltage to the MMC1
IO cells. Without this bias voltage these I/O cells can not function
properly. This bias voltage is either 1.8v or 3.0v.
The first patch adds 2 functions to the DM core: to count strings in a
stringlist and get a string from a stringlist based on its position in the
list.
The second patch implements the support for this PBIAS cell as a regulator
driver.
Jean-Jacques
changes since v2:
* rebased on u-boot/master
* automatically select REGMAP and SYSCON if PBIAS is selected.
changes since v1:
- add new functions to get strings from a stringlist in DM core
- use the dev_read_*() API to access the DT
- automatically select the PBIAS driver if DM_REGULATOR, DM_MMC and
MMC_OMAP_HS are set.
- removed the patch touching the DRA7 and AM57 config files.
Jean-Jacques Hiblot (2):
dm: core: Add functions to get strings and the string count from a
stringlist
regulator: pbias: Add PBIAS regulator for proper voltage switching on
MMC1
drivers/core/read.c | 11 ++
drivers/mmc/Kconfig | 1 +
drivers/power/regulator/Kconfig | 13 ++
drivers/power/regulator/Makefile | 1 +
drivers/power/regulator/pbias_regulator.c | 301 ++++++++++++++++++++++++++++++
include/dm/read.h | 36 ++++
6 files changed, 363 insertions(+)
create mode 100644 drivers/power/regulator/pbias_regulator.c
--
1.9.1
3
4

[U-Boot] cmd/bootefi.c:285:3: error: ‘loaded_image_info’ undeclared
by Heinrich Schuchardt 25 Sep '17
by Heinrich Schuchardt 25 Sep '17
25 Sep '17
Hello Rob, hello Alex,
when I try to compile efi-next I get
CC cmd/bootefi.o
cmd/bootefi.c: In function ‘do_bootefi’:
cmd/bootefi.c:285:3: error: ‘loaded_image_info’ undeclared (first use in
this function)
loaded_image_info.device_handle = bootefi_device_path;
^~~~~~~~~~~~~~~~~
cmd/bootefi.c:285:3: note: each undeclared identifier is reported only
once for each function it appears in
scripts/Makefile.build:280: recipe for target 'cmd/bootefi.o' failed
make[3]: *** [cmd/bootefi.o] Error 1
Makefile:1279: recipe for target 'cmd' failed
when compiling with CONFIG_CMD_BOOTEFI_SELFTEST=y.
I guess we should enable this option in qemu-x86_defconfig to make such
errors visible in Travis CI.
This seems to be the problematic patch:
ad503ffe9c6: efi_loader: refactor boot device and loaded_image handling
Best regards
Heinrich
3
8

[U-Boot] [PATCH v2 1/1] test/py: provide example scripts for integrating qemu
by Heinrich Schuchardt 25 Sep '17
by Heinrich Schuchardt 25 Sep '17
25 Sep '17
The necessary parameters for running Python tests on qemu are
tedious to find.
The patch adds examples for u-boot-test-console and
u-boot-test-reset.
Signed-off-by: Heinrich Schuchardt <xypron.glpk(a)gmx.de>
---
v2
Include all necessary information to run tests for qemu-x86_defconfig
in a separate chapter.
---
test/py/README.md | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 86 insertions(+)
diff --git a/test/py/README.md b/test/py/README.md
index 829c7efbb2..f71f59fdc5 100644
--- a/test/py/README.md
+++ b/test/py/README.md
@@ -252,6 +252,92 @@ https://github.com/swarren/uboot-test-hooks contains some working example hook
scripts, and may be useful as a reference when implementing hook scripts for
your platform. These scripts are not considered part of U-Boot itself.
+##### Running tests for qemu-x86\_defconfig
+
+We build u-boot.rom with
+
+ export BUILD_ROM=y
+ make mrproper
+ make qemu-x86_defconfig
+ make
+
+We create directory `../u-boot-test` for the script files below and `../tftp`
+for the tftp server.
+
+We copy helloworld.efi to the tftp directory.
+
+ cp lib/efi_loader/helloworld.efi ../tftp.
+
+In the script directory we create:
+
+File `u-boot-test-console` chmod 755
+
+ #!/bin/sh
+ touch /tmp/u-boot-monitor-socket
+ qemu-system-x86_64 -bios u-boot.rom -nographic -netdev \
+ user,id=eth0,tftp=../tftp,net=192.168.76.0/24,dhcpstart=192.168.76.9 \
+ -device e1000,netdev=eth0 -machine pc-i440fx-2.8 \
+ -monitor unix:/tmp/u-boot-monitor-socket,server,nowait
+
+This script is executed when the tests commence. It starts qemu with a network
+and a tftp server enabled. The control console is directed to the Unix socket
+`/tmp/u-boot-monitor-socket`.
+
+File `u-boot-test-flash` chmod 755
+
+ #!/bin/sh
+ echo ... u-boot-test-flash ...
+
+This script serves to initialize the board. Nothing needs to be done here as we
+pass u-boot.rom as a parameter in `u-boot-test-console`.
+
+File `u-boot-test-quit` chmod 755
+
+ #!/bin/sh
+ echo quit | socat - UNIX-CONNECT:/tmp/u-boot-monitor-socket
+
+This script is called when all tests are completed. The `quit` command is
+passed to the qemu control console to terminate the qemu session.
+
+File `u-boot-test-reset` chmod 755
+
+ #!/bin/sh
+ echo QEMU resetting >> a
+ echo system_reset | socat - UNIX-CONNECT:/tmp/u-boot-monitor-socket
+ sleep 1
+ true
+
+This script is called when a board reset is needed. The `system_reset` command
+is passed to the qemu control console to reboot the qemu instance. The `sleep`
+command ensures that the system reset is completed before the Python test script
+continues. The script must return true (0) to signal success.
+
+Empty file `__init__.py`
+
+This file makes Python recognize the directory as a package directory.
+
+File `u_boot_boardenv_qemu_x86.py`
+
+ env__net_dhcp_server = True
+ env__efi_loader_helloworld_file = {
+ "fn": "helloworld.efi",
+ "size": 4298,
+ "crc32": "55d96ef8",
+ }
+
+The parameter `env__net_dhcp_server` enables the network tests. The parameter
+`env__efi_loader_helloworld_file` is needed to make the file `helloworld.efi`
+available which is loaded from the tftp server in `test_efi_loader.py`.
+
+The fields size and crc32 have to be updated to match the actual values. The
+`crc32` command can be used to determine the latter.
+
+We now can run the Python tests with
+
+ export PATH=$(pwd)/../u-boot-test:/usr/bin:/bin
+ export PYTHONPATH=$(pwd)/../u-boot-test
+ ./test/py/test.py --bd=qemu-x86 --build-dir=.
+
### Board-type-specific configuration
Each board has a different configuration and behaviour. Many of these
--
2.11.0
2
1
This is needed to run 'bootefi' from sandbox. I suspect StartImage()
must have been broken too on x86.
Signed-off-by: Rob Clark <robdclark(a)gmail.com>
---
cmd/bootefi.c | 2 +-
include/efi.h | 2 +-
lib/efi_loader/efi_boottime.c | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/cmd/bootefi.c b/cmd/bootefi.c
index fb8ba9be6a..3c9a466e20 100644
--- a/cmd/bootefi.c
+++ b/cmd/bootefi.c
@@ -96,7 +96,7 @@ static void *copy_fdt(void *fdt)
static ulong efi_do_enter(void *image_handle,
struct efi_system_table *st,
- asmlinkage ulong (*entry)(void *image_handle,
+ EFIAPI ulong (*entry)(void *image_handle,
struct efi_system_table *st))
{
efi_status_t ret = EFI_LOAD_ERROR;
diff --git a/include/efi.h b/include/efi.h
index 04e83220b4..47c2c8f398 100644
--- a/include/efi.h
+++ b/include/efi.h
@@ -19,7 +19,7 @@
#include <linux/string.h>
#include <linux/types.h>
-#ifdef CONFIG_EFI_STUB_64BIT
+#if defined(CONFIG_EFI_STUB_64BIT) || defined(CONFIG_SANDBOX)
/* EFI uses the Microsoft ABI which is not the default for GCC */
#define EFIAPI __attribute__((ms_abi))
#else
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index 22bb95d738..3e10e6f6b5 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -950,7 +950,7 @@ static efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
unsigned long *exit_data_size,
s16 **exit_data)
{
- ulong (*entry)(void *image_handle, struct efi_system_table *st);
+ EFIAPI ulong (*entry)(void *image_handle, struct efi_system_table *st);
struct efi_loaded_image *info = image_handle;
EFI_ENTRY("%p, %p, %p", image_handle, exit_data_size, exit_data);
--
2.13.5
3
4

[U-Boot] [PATCH v2 0/5] rockchip: back-to-bootrom: replace assembly-implementation with C-code
by Philipp Tomsich 25 Sep '17
by Philipp Tomsich 25 Sep '17
25 Sep '17
Recent discussions confirmed (what the code always assumed): the
Rockchip BROM always enters U-Boot with the stack-pointer valid
(i.e. the U-Boot startup code is running off the BROM stack).
We can thus replace the back-to-bootrom code (i.e. both the
save_boot_params and back_to_bootrom implementations) using C-code
based on setjmp/longjmp. The new implementation is already structured
to allow an easy drop-in of Andy's changes to enter download-mode when
returning to the BROM.
This entails one minor tweak to asm/system.h, which only exported
the save_boot_params_ret prototype for ARMv7, but not for AArch64.
For v2, we force bootrom.o to alway be emitted as A32 (not T32), so we
can safely call save_boot_params_ret().
It also turned out that I had not caught the RK3188 in my earlier
series... and my luck being what it is, the RK3188 needed some extra
handholding to adapt to the new regime: instead of passing the context
address (for returning to the BROM) from the TPL to the SPL, the SPL
now returns to the TPL and the TPL then returns to the BROM.
Changes in v2:
- [added in v2] chain back_to_bootrom calls for SPL, first returning
to the TPL (using the same mechanism) and further calling through
to the BROM from the TPL by invoking back_to_bootrom again
- adapt the RK3188 spl support file (that I had originally missed)
Philipp Tomsich (5):
arm: make save_boot_params_ret prototype visible for AArch64
rockchip: back-to-bootrom: replace assembly-implementation with C-code
rockchip: back-to-bootrom: rk3188: chain from SPL via TPL to the BROM
rockchip: back-to-bootrom: allow passing a cmd to the bootrom
rockchip: back-to-bootrom: do not compile bootrom.o in thumb mode
arch/arm/include/asm/arch-rockchip/bootrom.h | 30 +++++++++---
arch/arm/include/asm/system.h | 62 ++++++++++++-------------
arch/arm/mach-rockchip/Makefile | 10 +++-
arch/arm/mach-rockchip/bootrom.c | 54 +++++++++++++++++++++-
arch/arm/mach-rockchip/rk3036-board-spl.c | 2 +-
arch/arm/mach-rockchip/rk3188-board-spl.c | 14 +-----
arch/arm/mach-rockchip/rk3188-board-tpl.c | 19 ++++----
arch/arm/mach-rockchip/rk322x-board-spl.c | 2 +-
arch/arm/mach-rockchip/rk3288-board-spl.c | 4 +-
arch/arm/mach-rockchip/rk3368-board-tpl.c | 2 +-
arch/arm/mach-rockchip/rk3399-board-spl.c | 2 +-
arch/arm/mach-rockchip/save_boot_param.S | 69 ----------------------------
12 files changed, 133 insertions(+), 137 deletions(-)
delete mode 100644 arch/arm/mach-rockchip/save_boot_param.S
--
2.1.4
6
16