X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=net%2Fbootp.c;h=81066015f1c2ed28a4fb0ea1ec4bbeecec08047f;hb=f94a1bed07e2af1c46ddcf2046cddd979ebfd994;hp=d0a7da248e4e9c57251548bbafb82b5568384698;hpb=8fa3d2b8161bb73b759c9db5c811c885ca5ec60c;p=oweals%2Fu-boot.git diff --git a/net/bootp.c b/net/bootp.c index d0a7da248e..81066015f1 100644 --- a/net/bootp.c +++ b/net/bootp.c @@ -17,16 +17,28 @@ #ifdef CONFIG_STATUS_LED #include #endif -#include +#ifdef CONFIG_BOOTP_RANDOM_DELAY +#include "net_rand.h" +#endif #define BOOTP_VENDOR_MAGIC 0x63825363 /* RFC1048 Magic Cookie */ -#define TIMEOUT 5000UL /* Milliseconds before trying BOOTP again */ +/* + * The timeout for the initial BOOTP/DHCP request used to be described by a + * counter of fixed-length timeout periods. TIMEOUT_COUNT represents + * that counter + * + * Now that the timeout periods are variable (exponential backoff and retry) + * we convert the timeout count to the absolute time it would have take to + * execute that many retries, and keep sending retry packets until that time + * is reached. + */ #ifndef CONFIG_NET_RETRY_COUNT # define TIMEOUT_COUNT 5 /* # of timeouts before giving up */ #else # define TIMEOUT_COUNT (CONFIG_NET_RETRY_COUNT) #endif +#define TIMEOUT_MS ((3 + (TIMEOUT_COUNT * 5)) * 1000) #define PORT_BOOTPS 67 /* BOOTP server UDP port */ #define PORT_BOOTPC 68 /* BOOTP client UDP port */ @@ -35,16 +47,20 @@ #define CONFIG_DHCP_MIN_EXT_LEN 64 #endif -ulong BootpID; -int BootpTry; -#ifdef CONFIG_BOOTP_RANDOM_DELAY -ulong seed1, seed2; +#ifndef CONFIG_BOOTP_ID_CACHE_SIZE +#define CONFIG_BOOTP_ID_CACHE_SIZE 4 #endif +ulong bootp_ids[CONFIG_BOOTP_ID_CACHE_SIZE]; +unsigned int bootp_num_ids; +int BootpTry; +ulong bootp_start; +ulong bootp_timeout; + #if defined(CONFIG_CMD_DHCP) -dhcp_state_t dhcp_state = INIT; -unsigned long dhcp_leasetime; -IPaddr_t NetDHCPServerIP; +static dhcp_state_t dhcp_state = INIT; +static unsigned long dhcp_leasetime; +static IPaddr_t NetDHCPServerIP; static void DhcpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, unsigned len); @@ -66,6 +82,30 @@ static char *dhcpmsg2str(int type) #endif #endif +static void bootp_add_id(ulong id) +{ + if (bootp_num_ids >= ARRAY_SIZE(bootp_ids)) { + size_t size = sizeof(bootp_ids) - sizeof(id); + + memmove(bootp_ids, &bootp_ids[1], size); + bootp_ids[bootp_num_ids - 1] = id; + } else { + bootp_ids[bootp_num_ids] = id; + bootp_num_ids++; + } +} + +static bool bootp_match_id(ulong id) +{ + unsigned int i; + + for (i = 0; i < bootp_num_ids; i++) + if (bootp_ids[i] == id) + return true; + + return false; +} + static int BootpCheckPkt(uchar *pkt, unsigned dest, unsigned src, unsigned len) { struct Bootp_t *bp = (struct Bootp_t *) pkt; @@ -73,7 +113,7 @@ static int BootpCheckPkt(uchar *pkt, unsigned dest, unsigned src, unsigned len) if (dest != PORT_BOOTPC || src != PORT_BOOTPS) retval = -1; - else if (len < sizeof(struct Bootp_t) - OPT_SIZE) + else if (len < sizeof(struct Bootp_t) - OPT_FIELD_SIZE) retval = -2; else if (bp->bp_op != OP_BOOTREQUEST && bp->bp_op != OP_BOOTREPLY && @@ -85,7 +125,7 @@ static int BootpCheckPkt(uchar *pkt, unsigned dest, unsigned src, unsigned len) retval = -4; else if (bp->bp_hlen != HWL_ETHER) retval = -5; - else if (NetReadLong((ulong *)&bp->bp_id) != BootpID) + else if (!bootp_match_id(NetReadLong((ulong *)&bp->bp_id))) retval = -6; debug("Filtering pkt = %d\n", retval); @@ -98,15 +138,13 @@ static int BootpCheckPkt(uchar *pkt, unsigned dest, unsigned src, unsigned len) */ static void BootpCopyNetParams(struct Bootp_t *bp) { - __maybe_unused IPaddr_t tmp_ip; - - NetCopyIP(&NetOurIP, &bp->bp_yiaddr); #if !defined(CONFIG_BOOTP_SERVERIP) + IPaddr_t tmp_ip; + NetCopyIP(&tmp_ip, &bp->bp_siaddr); if (tmp_ip != 0) NetCopyIP(&NetServerIP, &bp->bp_siaddr); - memcpy(NetServerEther, ((Ethernet_t *)NetRxPacket)->et_src, 6); -#endif + memcpy(NetServerEther, ((struct ethernet_hdr *)NetRxPacket)->et_src, 6); if (strlen(bp->bp_file) > 0) copy_filename(BootFile, bp->bp_file, sizeof(BootFile)); @@ -118,6 +156,8 @@ static void BootpCopyNetParams(struct Bootp_t *bp) */ if (*BootFile) setenv("bootfile", BootFile); +#endif + NetCopyIP(&NetOurIP, &bp->bp_yiaddr); } static int truncate_sz(const char *name, int maxlen, int curlen) @@ -328,15 +368,34 @@ BootpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, static void BootpTimeout(void) { - if (BootpTry >= TIMEOUT_COUNT) { - puts("\nRetry count exceeded; starting again\n"); + ulong time_taken = get_timer(bootp_start); + + if (time_taken >= TIMEOUT_MS) { +#ifdef CONFIG_BOOTP_MAY_FAIL + puts("\nRetry time exceeded\n"); + net_set_state(NETLOOP_FAIL); +#else + puts("\nRetry time exceeded; starting again\n"); NetStartAgain(); +#endif } else { - NetSetTimeout(TIMEOUT, BootpTimeout); + bootp_timeout *= 2; + if (bootp_timeout > 2000) + bootp_timeout = 2000; + NetSetTimeout(bootp_timeout, BootpTimeout); BootpRequest(); } } +#define put_vci(e, str) \ + do { \ + size_t vci_strlen = strlen(str); \ + *e++ = 60; /* Vendor Class Identifier */ \ + *e++ = vci_strlen; \ + memcpy(e, str, vci_strlen); \ + e += vci_strlen; \ + } while (0) + /* * Initialize BOOTP extension fields in the request. */ @@ -348,7 +407,6 @@ static int DhcpExtended(u8 *e, int message_type, IPaddr_t ServerID, u8 *cnt; #if defined(CONFIG_BOOTP_PXE) char *uuid; - size_t vci_strlen; u16 clientarch; #endif @@ -370,8 +428,8 @@ static int DhcpExtended(u8 *e, int message_type, IPaddr_t ServerID, *e++ = 57; /* Maximum DHCP Message Size */ *e++ = 2; - *e++ = (576 - 312 + OPT_SIZE) >> 8; - *e++ = (576 - 312 + OPT_SIZE) & 0xff; + *e++ = (576 - 312 + OPT_FIELD_SIZE) >> 8; + *e++ = (576 - 312 + OPT_FIELD_SIZE) & 0xff; if (ServerID) { int tmp = ntohl(ServerID); @@ -427,18 +485,16 @@ static int DhcpExtended(u8 *e, int message_type, IPaddr_t ServerID, *e++ = 17; *e++ = 0; /* type 0 - UUID */ - uuid_str_to_bin(uuid, e); + uuid_str_to_bin(uuid, e, UUID_STR_FORMAT_STD); e += 16; } else { printf("Invalid pxeuuid: %s\n", uuid); } } +#endif - *e++ = 60; /* Vendor Class Identifier */ - vci_strlen = strlen(CONFIG_BOOTP_VCI_STRING); - *e++ = vci_strlen; - memcpy(e, CONFIG_BOOTP_VCI_STRING, vci_strlen); - e += vci_strlen; +#ifdef CONFIG_BOOTP_VCI_STRING + put_vci(e, CONFIG_BOOTP_VCI_STRING); #endif #if defined(CONFIG_BOOTP_VENDOREX) @@ -521,8 +577,17 @@ static int BootpExtended(u8 *e) *e++ = 57; /* Maximum DHCP Message Size */ *e++ = 2; - *e++ = (576 - 312 + OPT_SIZE) >> 16; - *e++ = (576 - 312 + OPT_SIZE) & 0xff; + *e++ = (576 - 312 + OPT_FIELD_SIZE) >> 16; + *e++ = (576 - 312 + OPT_FIELD_SIZE) & 0xff; +#endif + +#if defined(CONFIG_BOOTP_VCI_STRING) || \ + (defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_NET_VCI_STRING)) +#ifdef CONFIG_SPL_BUILD + put_vci(e, CONFIG_SPL_NET_VCI_STRING); +#else + put_vci(e, CONFIG_BOOTP_VCI_STRING); +#endif #endif #if defined(CONFIG_BOOTP_SUBNETMASK) @@ -578,12 +643,25 @@ static int BootpExtended(u8 *e) } #endif +void BootpReset(void) +{ + bootp_num_ids = 0; + BootpTry = 0; + bootp_start = get_timer(0); + bootp_timeout = 250; +} + void BootpRequest(void) { uchar *pkt, *iphdr; struct Bootp_t *bp; - int ext_len, pktlen, iplen; + int extlen, pktlen, iplen; + int eth_hdr_size; +#ifdef CONFIG_BOOTP_RANDOM_DELAY + ulong rand_ms; +#endif + ulong BootpID; bootstage_mark_name(BOOTSTAGE_ID_BOOTP_START, "bootp_start"); #if defined(CONFIG_CMD_DHCP) @@ -591,61 +669,16 @@ BootpRequest(void) #endif #ifdef CONFIG_BOOTP_RANDOM_DELAY /* Random BOOTP delay */ - unsigned char bi_enetaddr[6]; - int reg; - ulong tst1, tst2, sum, m_mask, m_value = 0; - - if (BootpTry == 0) { - /* get our mac */ - eth_getenv_enetaddr("ethaddr", bi_enetaddr); - - debug("BootpRequest => Our Mac: "); - for (reg = 0; reg < 6; reg++) - debug("%x%c", bi_enetaddr[reg], reg == 5 ? '\n' : ':'); - - /* Mac-Manipulation 2 get seed1 */ - tst1 = 0; - tst2 = 0; - for (reg = 2; reg < 6; reg++) { - tst1 = tst1 << 8; - tst1 = tst1 | bi_enetaddr[reg]; - } - for (reg = 0; reg < 2; reg++) { - tst2 = tst2 | bi_enetaddr[reg]; - tst2 = tst2 << 8; - } - - seed1 = tst1^tst2; - - /* Mirror seed1*/ - m_mask = 0x1; - for (reg = 1; reg <= 32; reg++) { - m_value |= (m_mask & seed1); - seed1 = seed1 >> 1; - m_value = m_value << 1; - } - seed1 = m_value; - seed2 = 0xB78D0945; - } + if (BootpTry == 0) + srand_mac(); - /* Random Number Generator */ - for (reg = 0; reg <= 0; reg++) { - sum = seed1 + seed2; - if (sum < seed1 || sum < seed2) - sum++; - seed2 = seed1; - seed1 = sum; - - if (BootpTry <= 2) { /* Start with max 1024 * 1ms */ - sum = sum >> (22-BootpTry); - } else { /*After 3rd BOOTP request max 8192 * 1ms */ - sum = sum >> 19; - } - } + if (BootpTry <= 2) /* Start with max 1024 * 1ms */ + rand_ms = rand() >> (22 - BootpTry); + else /* After 3rd BOOTP request max 8192 * 1ms */ + rand_ms = rand() >> 19; - printf("Random delay: %ld ms...\n", sum); - for (reg = 0; reg < sum; reg++) - udelay(1000); /*Wait 1ms*/ + printf("Random delay: %ld ms...\n", rand_ms); + mdelay(rand_ms); #endif /* CONFIG_BOOTP_RANDOM_DELAY */ @@ -653,7 +686,8 @@ BootpRequest(void) pkt = NetTxPacket; memset((void *)pkt, 0, PKTSIZE); - pkt += NetSetEther(pkt, NetBcastAddr, PROT_IP); + eth_hdr_size = NetSetEther(pkt, NetBcastAddr, PROT_IP); + pkt += eth_hdr_size; /* * Next line results in incorrect packet size being transmitted, @@ -662,10 +696,10 @@ BootpRequest(void) * determined. * C. Hallinan, DS4.COM, Inc. */ - /* NetSetIP(pkt, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, + /* net_set_udp_header(pkt, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, sizeof (struct Bootp_t)); */ - iphdr = pkt; /* We need this later for NetSetIP() */ - pkt += IP_HDR_SIZE; + iphdr = pkt; /* We need this later for net_set_udp_header() */ + pkt += IP_UDP_HDR_SIZE; bp = (struct Bootp_t *)pkt; bp->bp_op = OP_BOOTREQUEST; @@ -682,9 +716,9 @@ BootpRequest(void) /* Request additional information from the BOOTP/DHCP server */ #if defined(CONFIG_CMD_DHCP) - ext_len = DhcpExtended((u8 *)bp->bp_vend, DHCP_DISCOVER, 0, 0); + extlen = DhcpExtended((u8 *)bp->bp_vend, DHCP_DISCOVER, 0, 0); #else - ext_len = BootpExtended((u8 *)bp->bp_vend); + extlen = BootpExtended((u8 *)bp->bp_vend); #endif /* @@ -696,24 +730,24 @@ BootpRequest(void) | ((ulong)NetOurEther[4] << 8) | (ulong)NetOurEther[5]; BootpID += get_timer(0); - BootpID = htonl(BootpID); + BootpID = htonl(BootpID); + bootp_add_id(BootpID); NetCopyLong(&bp->bp_id, &BootpID); /* * Calculate proper packet lengths taking into account the * variable size of the options field */ - pktlen = ((int)(pkt-NetTxPacket)) + BOOTP_HDR_SIZE - - sizeof(bp->bp_vend) + ext_len; - iplen = BOOTP_HDR_SIZE - sizeof(bp->bp_vend) + ext_len; - NetSetIP(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen); - NetSetTimeout(SELECT_TIMEOUT, BootpTimeout); + iplen = BOOTP_HDR_SIZE - OPT_FIELD_SIZE + extlen; + pktlen = eth_hdr_size + IP_UDP_HDR_SIZE + iplen; + net_set_udp_header(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen); + NetSetTimeout(bootp_timeout, BootpTimeout); #if defined(CONFIG_CMD_DHCP) dhcp_state = SELECTING; - NetSetHandler(DhcpHandler); + net_set_udp_handler(DhcpHandler); #else - NetSetHandler(BootpHandler); + net_set_udp_handler(BootpHandler); #endif NetSendPacket(NetTxPacket, pktlen); } @@ -764,6 +798,8 @@ static void DhcpOptionsProcess(uchar *popt, struct Bootp_t *bp) memcpy(&NetOurRootPath, popt + 2, size); NetOurRootPath[size] = 0; break; + case 28: /* Ignore Broadcast Address Option */ + break; #if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_NTPSERVER) case 42: /* NTP server IP */ NetCopyIP(&NetNtpServerIP, (popt + 2)); @@ -841,16 +877,18 @@ static void DhcpSendRequestPkt(struct Bootp_t *bp_offer) uchar *pkt, *iphdr; struct Bootp_t *bp; int pktlen, iplen, extlen; + int eth_hdr_size; IPaddr_t OfferedIP; debug("DhcpSendRequestPkt: Sending DHCPREQUEST\n"); pkt = NetTxPacket; memset((void *)pkt, 0, PKTSIZE); - pkt += NetSetEther(pkt, NetBcastAddr, PROT_IP); + eth_hdr_size = NetSetEther(pkt, NetBcastAddr, PROT_IP); + pkt += eth_hdr_size; iphdr = pkt; /* We'll need this later to set proper pkt size */ - pkt += IP_HDR_SIZE; + pkt += IP_UDP_HDR_SIZE; bp = (struct Bootp_t *)pkt; bp->bp_op = OP_BOOTREQUEST; @@ -884,15 +922,14 @@ static void DhcpSendRequestPkt(struct Bootp_t *bp_offer) extlen = DhcpExtended((u8 *)bp->bp_vend, DHCP_REQUEST, NetDHCPServerIP, OfferedIP); - pktlen = ((int)(pkt-NetTxPacket)) + BOOTP_HDR_SIZE - - sizeof(bp->bp_vend) + extlen; - iplen = BOOTP_HDR_SIZE - sizeof(bp->bp_vend) + extlen; - NetSetIP(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen); + iplen = BOOTP_HDR_SIZE - OPT_FIELD_SIZE + extlen; + pktlen = eth_hdr_size + IP_UDP_HDR_SIZE + iplen; + net_set_udp_header(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen); - debug("Transmitting DHCPREQUEST packet: len = %d\n", pktlen); #ifdef CONFIG_BOOTP_DHCP_REQUEST_DELAY udelay(CONFIG_BOOTP_DHCP_REQUEST_DELAY); #endif /* CONFIG_BOOTP_DHCP_REQUEST_DELAY */ + debug("Transmitting DHCPREQUEST packet: len = %d\n", pktlen); NetSendPacket(NetTxPacket, pktlen); } @@ -937,7 +974,7 @@ DhcpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, htonl(BOOTP_VENDOR_MAGIC)) DhcpOptionsProcess((u8 *)&bp->bp_vend[4], bp); - NetSetTimeout(TIMEOUT, BootpTimeout); + NetSetTimeout(5000, BootpTimeout); DhcpSendRequestPkt(bp); #ifdef CONFIG_SYS_BOOTFILE_PREFIX } @@ -955,8 +992,8 @@ DhcpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, /* Store net params from reply */ BootpCopyNetParams(bp); dhcp_state = BOUND; - printf("DHCP client bound to address %pI4\n", - &NetOurIP); + printf("DHCP client bound to address %pI4 (%lu ms)\n", + &NetOurIP, get_timer(bootp_start)); bootstage_mark_name(BOOTSTAGE_ID_BOOTP_STOP, "bootp_stop");