summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/Kconfig10
-rw-r--r--net/arp.c7
-rw-r--r--net/arp.h2
-rw-r--r--net/bootp.c123
-rw-r--r--net/eth.c53
-rw-r--r--net/net.c6
-rw-r--r--net/tftp.c17
7 files changed, 142 insertions, 76 deletions
diff --git a/net/Kconfig b/net/Kconfig
index 77a2f7e..a44a783 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -22,4 +22,14 @@ config NETCONSOLE
Support the 'nc' input/output device for networked console.
See README.NetConsole for details.
+config NET_TFTP_VARS
+ bool "Control TFTP timeout and count through environment"
+ default y
+ help
+ If set, allows controlling the TFTP timeout through the
+ environment variable tftptimeout, and the TFTP maximum
+ timeout count through the variable tftptimeoutcountmax.
+ If unset, timeout and maximum are hard-defined as 1 second
+ and 10 timouts per TFTP transfer.
+
endif # if NET
diff --git a/net/arp.c b/net/arp.c
index b865570..824d2e9 100644
--- a/net/arp.c
+++ b/net/arp.c
@@ -96,12 +96,12 @@ void arp_request(void)
arp_raw_request(net_ip, net_null_ethaddr, net_arp_wait_reply_ip);
}
-void arp_timeout_check(void)
+int arp_timeout_check(void)
{
ulong t;
if (!net_arp_wait_packet_ip.s_addr)
- return;
+ return 0;
t = get_timer(0);
@@ -112,12 +112,13 @@ void arp_timeout_check(void)
if (arp_wait_try >= ARP_TIMEOUT_COUNT) {
puts("\nARP Retry count exceeded; starting again\n");
arp_wait_try = 0;
- net_start_again();
+ net_set_state(NETLOOP_FAIL);
} else {
arp_wait_timer_start = t;
arp_request();
}
}
+ return 1;
}
void arp_receive(struct ethernet_hdr *et, struct ip_udp_hdr *ip, int len)
diff --git a/net/arp.h b/net/arp.h
index 43c6296..a288d61 100644
--- a/net/arp.h
+++ b/net/arp.h
@@ -25,7 +25,7 @@ void arp_init(void);
void arp_request(void);
void arp_raw_request(struct in_addr source_ip, const uchar *targetEther,
struct in_addr target_ip);
-void arp_timeout_check(void);
+int arp_timeout_check(void);
void arp_receive(struct ethernet_hdr *et, struct ip_udp_hdr *ip, int len);
#endif /* __ARP_H__ */
diff --git a/net/bootp.c b/net/bootp.c
index b2f8ad4..8aeddb0 100644
--- a/net/bootp.c
+++ b/net/bootp.c
@@ -64,6 +64,9 @@ char net_root_path[64] = {0,}; /* Our bootpath */
static dhcp_state_t dhcp_state = INIT;
static u32 dhcp_leasetime;
static struct in_addr dhcp_server_ip;
+static u8 dhcp_option_overload;
+#define OVERLOAD_FILE 1
+#define OVERLOAD_SNAME 2
static void dhcp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
unsigned src, unsigned len);
@@ -109,7 +112,8 @@ static bool bootp_match_id(ulong id)
return false;
}
-static int check_packet(uchar *pkt, unsigned dest, unsigned src, unsigned len)
+static int check_reply_packet(uchar *pkt, unsigned dest, unsigned src,
+ unsigned len)
{
struct bootp_hdr *bp = (struct bootp_hdr *)pkt;
int retval = 0;
@@ -118,11 +122,7 @@ static int check_packet(uchar *pkt, unsigned dest, unsigned src, unsigned len)
retval = -1;
else if (len < sizeof(struct bootp_hdr) - OPT_FIELD_SIZE)
retval = -2;
- else if (bp->bp_op != OP_BOOTREQUEST &&
- bp->bp_op != OP_BOOTREPLY &&
- bp->bp_op != DHCP_OFFER &&
- bp->bp_op != DHCP_ACK &&
- bp->bp_op != DHCP_NAK)
+ else if (bp->bp_op != OP_BOOTREPLY)
retval = -3;
else if (bp->bp_htype != HWT_ETHER)
retval = -4;
@@ -149,9 +149,14 @@ static void store_net_params(struct bootp_hdr *bp)
net_copy_ip(&net_server_ip, &bp->bp_siaddr);
memcpy(net_server_ethaddr,
((struct ethernet_hdr *)net_rx_packet)->et_src, 6);
- if (strlen(bp->bp_file) > 0)
+ if (
+#if defined(CONFIG_CMD_DHCP)
+ !(dhcp_option_overload & OVERLOAD_FILE) &&
+#endif
+ (strlen(bp->bp_file) > 0)) {
copy_filename(net_boot_file_name, bp->bp_file,
sizeof(net_boot_file_name));
+ }
debug("net_boot_file_name: %s\n", net_boot_file_name);
@@ -343,13 +348,13 @@ static void bootp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
bp = (struct bootp_hdr *)pkt;
/* Filter out pkts we don't want */
- if (check_packet(pkt, dest, src, len))
+ if (check_reply_packet(pkt, dest, src, len))
return;
/*
* Got a good BOOTP reply. Copy the data into our variables.
*/
-#ifdef CONFIG_STATUS_LED
+#if defined(CONFIG_STATUS_LED) && defined(STATUS_LED_BOOT)
status_led_set(STATUS_LED_BOOT, STATUS_LED_OFF);
#endif
@@ -498,7 +503,9 @@ static int dhcp_extended(u8 *e, int message_type, struct in_addr server_ip,
}
#endif
-#ifdef CONFIG_BOOTP_VCI_STRING
+#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_NET_VCI_STRING)
+ put_vci(e, CONFIG_SPL_NET_VCI_STRING);
+#elif defined(CONFIG_BOOTP_VCI_STRING)
put_vci(e, CONFIG_BOOTP_VCI_STRING);
#endif
@@ -712,7 +719,11 @@ void bootp_request(void)
bp->bp_htype = HWT_ETHER;
bp->bp_hlen = HWL_ETHER;
bp->bp_hops = 0;
- bp->bp_secs = htons(get_timer(0) / 1000);
+ /*
+ * according to RFC1542, should be 0 on first request, secs since
+ * first request otherwise
+ */
+ bp->bp_secs = htons(get_timer(bootp_start) / 1000);
zero_ip.s_addr = 0;
net_write_ip(&bp->bp_ciaddr, zero_ip);
net_write_ip(&bp->bp_yiaddr, zero_ip);
@@ -762,9 +773,8 @@ void bootp_request(void)
}
#if defined(CONFIG_CMD_DHCP)
-static void dhcp_process_options(uchar *popt, struct bootp_hdr *bp)
+static void dhcp_process_options(uchar *popt, uchar *end)
{
- uchar *end = popt + BOOTP_HDR_SIZE;
int oplen, size;
#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_TIMEOFFSET)
int *to_ptr;
@@ -773,6 +783,9 @@ static void dhcp_process_options(uchar *popt, struct bootp_hdr *bp)
while (popt < end && *popt != 0xff) {
oplen = *(popt + 1);
switch (*popt) {
+ case 0:
+ oplen = -1; /* Pad omits len byte */
+ break;
case 1:
net_copy_ip(&net_netmask, (popt + 2));
break;
@@ -817,6 +830,9 @@ static void dhcp_process_options(uchar *popt, struct bootp_hdr *bp)
case 51:
net_copy_u32(&dhcp_leasetime, (u32 *)(popt + 2));
break;
+ case 52:
+ dhcp_option_overload = popt[2];
+ break;
case 53: /* Ignore Message Type Option */
break;
case 54:
@@ -828,31 +844,11 @@ static void dhcp_process_options(uchar *popt, struct bootp_hdr *bp)
break;
case 66: /* Ignore TFTP server name */
break;
- case 67: /* vendor opt bootfile */
- /*
- * I can't use dhcp_vendorex_proc here because I need
- * to write into the bootp packet - even then I had to
- * pass the bootp packet pointer into here as the
- * second arg
- */
- size = truncate_sz("Opt Boot File",
- sizeof(bp->bp_file),
- oplen);
- if (bp->bp_file[0] == '\0' && size > 0) {
- /*
- * only use vendor boot file if we didn't
- * receive a boot file in the main non-vendor
- * part of the packet - god only knows why
- * some vendors chose not to use this perfectly
- * good spot to store the boot file (join on
- * Tru64 Unix) it seems mind bogglingly crazy
- * to me
- */
- printf("*** WARNING: using vendor "
- "optional boot file\n");
- memcpy(bp->bp_file, popt + 2, size);
- bp->bp_file[size] = '\0';
- }
+ case 67: /* Bootfile option */
+ size = truncate_sz("Bootfile",
+ sizeof(net_boot_file_name), oplen);
+ memcpy(&net_boot_file_name, popt + 2, size);
+ net_boot_file_name[size] = 0;
break;
default:
#if defined(CONFIG_BOOTP_VENDOREX)
@@ -867,6 +863,35 @@ static void dhcp_process_options(uchar *popt, struct bootp_hdr *bp)
}
}
+static void dhcp_packet_process_options(struct bootp_hdr *bp)
+{
+ uchar *popt = (uchar *)&bp->bp_vend[4];
+ uchar *end = popt + BOOTP_HDR_SIZE;
+
+ if (net_read_u32((u32 *)&bp->bp_vend[0]) != htonl(BOOTP_VENDOR_MAGIC))
+ return;
+
+ dhcp_option_overload = 0;
+
+ /*
+ * The 'options' field MUST be interpreted first, 'file' next,
+ * 'sname' last.
+ */
+ dhcp_process_options(popt, end);
+
+ if (dhcp_option_overload & OVERLOAD_FILE) {
+ popt = (uchar *)bp->bp_file;
+ end = popt + sizeof(bp->bp_file);
+ dhcp_process_options(popt, end);
+ }
+
+ if (dhcp_option_overload & OVERLOAD_SNAME) {
+ popt = (uchar *)bp->bp_sname;
+ end = popt + sizeof(bp->bp_sname);
+ dhcp_process_options(popt, end);
+ }
+}
+
static int dhcp_message_type(unsigned char *popt)
{
if (net_read_u32((u32 *)popt) != htonl(BOOTP_VENDOR_MAGIC))
@@ -876,7 +901,13 @@ static int dhcp_message_type(unsigned char *popt)
while (*popt != 0xff) {
if (*popt == 53) /* DHCP Message Type */
return *(popt + 2);
- popt += *(popt + 1) + 2; /* Scan through all options */
+ if (*popt == 0) {
+ /* Pad */
+ popt += 1;
+ } else {
+ /* Scan through all options */
+ popt += *(popt + 1) + 2;
+ }
}
return -1;
}
@@ -906,7 +937,7 @@ static void dhcp_send_request_packet(struct bootp_hdr *bp_offer)
bp->bp_htype = HWT_ETHER;
bp->bp_hlen = HWL_ETHER;
bp->bp_hops = 0;
- bp->bp_secs = htons(get_timer(0) / 1000);
+ bp->bp_secs = htons(get_timer(bootp_start) / 1000);
/* Do not set the client IP, your IP, or server IP yet, since it
* hasn't been ACK'ed by the server yet */
@@ -958,7 +989,7 @@ static void dhcp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
src, dest, len, dhcp_state);
/* Filter out pkts we don't want */
- if (check_packet(pkt, dest, src, len))
+ if (check_reply_packet(pkt, dest, src, len))
return;
debug("DHCPHandler: got DHCP packet: (src=%d, dst=%d, len=%d) state: "
@@ -978,14 +1009,11 @@ static void dhcp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
CONFIG_SYS_BOOTFILE_PREFIX,
strlen(CONFIG_SYS_BOOTFILE_PREFIX)) == 0) {
#endif /* CONFIG_SYS_BOOTFILE_PREFIX */
+ dhcp_packet_process_options(bp);
debug("TRANSITIONING TO REQUESTING STATE\n");
dhcp_state = REQUESTING;
- if (net_read_u32((u32 *)&bp->bp_vend[0]) ==
- htonl(BOOTP_VENDOR_MAGIC))
- dhcp_process_options((u8 *)&bp->bp_vend[4], bp);
-
net_set_timeout_handler(5000, bootp_timeout_handler);
dhcp_send_request_packet(bp);
#ifdef CONFIG_SYS_BOOTFILE_PREFIX
@@ -998,14 +1026,13 @@ static void dhcp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
debug("DHCP State: REQUESTING\n");
if (dhcp_message_type((u8 *)bp->bp_vend) == DHCP_ACK) {
- if (net_read_u32((u32 *)&bp->bp_vend[0]) ==
- htonl(BOOTP_VENDOR_MAGIC))
- dhcp_process_options((u8 *)&bp->bp_vend[4], bp);
+ dhcp_packet_process_options(bp);
/* Store net params from reply */
store_net_params(bp);
dhcp_state = BOUND;
printf("DHCP client bound to address %pI4 (%lu ms)\n",
&net_ip, get_timer(bootp_start));
+ net_set_timeout_handler(0, (thand_f *)0);
bootstage_mark_name(BOOTSTAGE_ID_BOOTP_STOP,
"bootp_stop");
diff --git a/net/eth.c b/net/eth.c
index 2e24b55..c542f4a 100644
--- a/net/eth.c
+++ b/net/eth.c
@@ -31,13 +31,13 @@ void eth_parse_enetaddr(const char *addr, uchar *enetaddr)
}
}
-int eth_getenv_enetaddr(char *name, uchar *enetaddr)
+int eth_getenv_enetaddr(const char *name, uchar *enetaddr)
{
eth_parse_enetaddr(getenv(name), enetaddr);
return is_valid_ethaddr(enetaddr);
}
-int eth_setenv_enetaddr(char *name, const uchar *enetaddr)
+int eth_setenv_enetaddr(const char *name, const uchar *enetaddr)
{
char buf[20];
@@ -179,8 +179,12 @@ struct udevice *eth_get_dev(void)
*/
static void eth_set_dev(struct udevice *dev)
{
- if (dev && !device_active(dev))
+ if (dev && !device_active(dev)) {
eth_errno = device_probe(dev);
+ if (eth_errno)
+ dev = NULL;
+ }
+
eth_get_uclass_priv()->current = dev;
}
@@ -213,10 +217,9 @@ struct udevice *eth_get_dev_by_name(const char *devname)
* match an alias or it will match a literal name and we'll pick
* up the error when we try to probe again in eth_set_dev().
*/
- device_probe(it);
- /*
- * Check for the name or the sequence number to match
- */
+ if (device_probe(it))
+ continue;
+ /* Check for the name or the sequence number to match */
if (strcmp(it->name, devname) == 0 ||
(endp > startp && it->seq == seq))
return it;
@@ -346,23 +349,27 @@ int eth_init(void)
old_current = current;
do {
- debug("Trying %s\n", current->name);
-
- if (device_active(current)) {
- ret = eth_get_ops(current)->start(current);
- if (ret >= 0) {
- struct eth_device_priv *priv =
- current->uclass_priv;
-
- priv->state = ETH_STATE_ACTIVE;
- return 0;
+ if (current) {
+ debug("Trying %s\n", current->name);
+
+ if (device_active(current)) {
+ ret = eth_get_ops(current)->start(current);
+ if (ret >= 0) {
+ struct eth_device_priv *priv =
+ current->uclass_priv;
+
+ priv->state = ETH_STATE_ACTIVE;
+ return 0;
+ }
+ } else {
+ ret = eth_errno;
}
+
+ debug("FAIL\n");
} else {
- ret = eth_errno;
+ debug("PROBE FAIL\n");
}
- debug("FAIL\n");
-
/*
* If ethrotate is enabled, this will change "current",
* otherwise we will drop out of this while loop immediately
@@ -575,8 +582,13 @@ static int eth_post_probe(struct udevice *dev)
static int eth_pre_remove(struct udevice *dev)
{
+ struct eth_pdata *pdata = dev->platdata;
+
eth_get_ops(dev)->stop(dev);
+ /* clear the MAC address */
+ memset(pdata->enetaddr, 0, 6);
+
return 0;
}
@@ -691,6 +703,7 @@ static int on_ethaddr(const char *name, const char *value, enum env_op op,
memset(dev->enetaddr, 0, 6);
}
}
+ dev = dev->next;
} while (dev != eth_devices);
return 0;
diff --git a/net/net.c b/net/net.c
index a115ce2..2926bce 100644
--- a/net/net.c
+++ b/net/net.c
@@ -164,7 +164,7 @@ ushort net_our_vlan = 0xFFFF;
ushort net_native_vlan = 0xFFFF;
/* Boot File name */
-char net_boot_file_name[128];
+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 */
@@ -569,7 +569,9 @@ restart:
goto done;
}
- arp_timeout_check();
+ if (arp_timeout_check() > 0) {
+ time_start = get_timer(0);
+ }
/*
* Check for a timeout, and run the timeout handler
diff --git a/net/tftp.c b/net/tftp.c
index 1a51131..f2889fe 100644
--- a/net/tftp.c
+++ b/net/tftp.c
@@ -602,7 +602,7 @@ static void tftp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
}
tftp_prev_block = tftp_cur_block;
- timeout_count_max = TIMEOUT_COUNT;
+ timeout_count_max = tftp_timeout_count_max;
net_set_timeout_handler(timeout_ms, tftp_timeout_handler);
store_block(tftp_cur_block - 1, pkt + 2, len);
@@ -697,12 +697,14 @@ static void tftp_timeout_handler(void)
void tftp_start(enum proto_t protocol)
{
+#if CONFIG_NET_TFTP_VARS
char *ep; /* Environment pointer */
/*
* Allow the user to choose TFTP blocksize and timeout.
* TFTP protocol has a minimal timeout of 1 second.
*/
+
ep = getenv("tftpblocksize");
if (ep != NULL)
tftp_block_size_option = simple_strtol(ep, NULL, 10);
@@ -717,6 +719,17 @@ void tftp_start(enum proto_t protocol)
timeout_ms = 1000;
}
+ ep = getenv("tftptimeoutcountmax");
+ if (ep != NULL)
+ tftp_timeout_count_max = simple_strtol(ep, NULL, 10);
+
+ if (tftp_timeout_count_max < 0) {
+ printf("TFTP timeout count max (%d ms) negative, set to 0\n",
+ tftp_timeout_count_max);
+ tftp_timeout_count_max = 0;
+ }
+#endif
+
debug("TFTP blocksize = %i, timeout = %ld ms\n",
tftp_block_size_option, timeout_ms);
@@ -842,7 +855,7 @@ void tftp_start_server(void)
puts("Loading: *\b");
- timeout_count_max = TIMEOUT_COUNT;
+ timeout_count_max = tftp_timeout_count_max;
timeout_count = 0;
timeout_ms = TIMEOUT;
net_set_timeout_handler(timeout_ms, tftp_timeout_handler);