X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=net%2Fbootp.c;h=f2978a23ce5aaaa8074ae6bdeac950363edeaca0;hb=a0594cefb7682dc0c32084d088b3ac0a85ed7395;hp=b2f8ad4ded932ddfdb2aefc86f803e2d4f0d894f;hpb=cdc7732f3737f2bb97b77eb3d7c9da344bb73612;p=u-boot diff --git a/net/bootp.c b/net/bootp.c index b2f8ad4ded..f2978a23ce 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 */ @@ -918,6 +949,7 @@ static void dhcp_send_request_packet(struct bootp_hdr *bp_offer) net_write_ip(&bp->bp_giaddr, zero_ip); memcpy(bp->bp_chaddr, net_ethaddr, 6); + copy_filename(bp->bp_file, net_boot_file_name, sizeof(bp->bp_file)); /* * ID is the id of the OFFER packet @@ -958,12 +990,15 @@ 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: " "%d\n", src, dest, len, dhcp_state); + if (net_read_ip(&bp->bp_yiaddr).s_addr == 0) + return; + switch (dhcp_state) { case SELECTING: /* @@ -978,14 +1013,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 +1030,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");