diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/Kconfig | 10 | ||||
-rw-r--r-- | net/arp.c | 7 | ||||
-rw-r--r-- | net/arp.h | 2 | ||||
-rw-r--r-- | net/bootp.c | 123 | ||||
-rw-r--r-- | net/eth.c | 53 | ||||
-rw-r--r-- | net/net.c | 6 | ||||
-rw-r--r-- | net/tftp.c | 17 |
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 @@ -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) @@ -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"); @@ -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; @@ -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 @@ -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); |