udhcpd: optional BOOTP support
No binary (build failed)
—
(log yok)
| @@ -10,6 +10,13 @@ config UDHCPD | |
| udhcpd is a DHCP server geared primarily toward embedded systems, | |
| while striving to be fully functional and RFC compliant. | |
| + | config FEATURE_UDHCPD_BOOTP |
| + | bool "Answer to BOOTP requests as well" |
| + | default y |
| + | depends on UDHCPD |
| + | help |
| + | Support old BOOTP protocol too. |
| + | |
| config FEATURE_UDHCPD_BASE_IP_ON_MAC | |
| bool "Select IP address based on client MAC" | |
| default n | |
| @@ -252,6 +252,14 @@ uint8_t* FAST_FUNC udhcp_scan_options(struct dhcp_packet *packet, struct dhcp_sc | |
| /* option bytes: [code][len][data1][data2]..[dataLEN] */ | |
| while (1) { | |
| if (scan_state->rem <= 0) { | |
| + | if (ENABLE_FEATURE_UDHCPD_BOOTP && scan_state->rem == 0) { |
| + | /* DHCP requires END option to be present. |
| + | * We are here if packet fails this condition |
| + | * (options[] are zero-padded to the end). |
| + | * Assume BOOTP packet without further checks. |
| + | */ |
| + | break; /* return NULL */ |
| + | } |
| complain: | |
| bb_simple_error_msg("bad packet, malformed option field"); | |
| return NULL; | |
| @@ -278,7 +286,7 @@ uint8_t* FAST_FUNC udhcp_scan_options(struct dhcp_packet *packet, struct dhcp_sc | |
| scan_state->rem = sizeof(packet->sname); | |
| continue; | |
| } | |
| - | break; |
| + | break; /* return NULL */ |
| } | |
| if (scan_state->rem <= OPT_LEN) /* [len] byte exists? */ | |
| @@ -20,8 +20,11 @@ extern const uint8_t MAC_BCAST_ADDR[6] ALIGN2; /* six all-ones */ | |
| /*** DHCP packet ***/ | |
| + | #define RFC1048_MAGIC 0x63825363 |
| + | /* RFC 1048 still uses BOOTP's small buffer (4 byte cookie + 60 the rest) */ |
| + | #define RFC1048_OPTIONS_BUFSIZE 60 |
| + | |
| /* DHCP protocol. See RFC 2131 */ | |
| - | #define DHCP_MAGIC 0x63825363 |
| #define DHCP_OPTIONS_BUFSIZE 308 | |
| #define BOOTREQUEST 1 | |
| #define BOOTREPLY 2 | |
| @@ -57,8 +60,10 @@ struct dhcp_packet { | |
| * such as 'unix' or 'gateway'; this means 'boot the named program | |
| * configured for my machine'" | |
| */ | |
| - | /* BOOTP fields end here, BOOTP says optional uint8_t vend[64] follows */ |
| - | uint32_t cookie; /* DHCP magic bytes: 99,130,83,99 decimal */ |
| + | /* BOOTP fields end here, BOOTP says optional uint8_t vend[64] follows. */ |
| + | /* RFC 1048 defined this cookie value and options 0-12 and 255. */ |
| + | /* DHCP extended it and required option 255 (END) to be always present. */ |
| + | uint32_t cookie; /* RFC 1048 magic bytes: 99,130,83,99 decimal */ |
| uint8_t options[DHCP_OPTIONS_BUFSIZE + CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS]; | |
| }; | |
| #define DHCP_PKT_SNAME_LEN 64 | |
| @@ -200,6 +205,9 @@ struct dhcp_scan_state { | |
| #define SNAME_FIELD 2 | |
| /* DHCP_MESSAGE_TYPE values */ | |
| + | #if ENABLE_FEATURE_UDHCPD_BOOTP |
| + | #define MSGTYPE_BOOTP 0 /* there was no TYPE option in client's packet, assuming BOOTP */ |
| + | #endif |
| #define DHCPDISCOVER 1 /* client -> server */ | |
| #define DHCPOFFER 2 /* client <- server */ | |
| #define DHCPREQUEST 3 /* client -> server */ | |
| @@ -971,7 +971,7 @@ static NOINLINE int d4_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) | |
| } | |
| skip_udp_sum_check: | |
| - | if (packet.data.cookie != htonl(DHCP_MAGIC)) { |
| + | if (packet.data.cookie != htonl(RFC1048_MAGIC)) { |
| log1s("packet with bad magic, ignoring"); | |
| return -2; | |
| } | |
| @@ -649,7 +649,8 @@ static void init_packet(struct dhcp_packet *packet, struct dhcp_packet *oldpacke | |
| packet->flags = oldpacket->flags; | |
| packet->gateway_nip = oldpacket->gateway_nip; | |
| packet->ciaddr = oldpacket->ciaddr; | |
| - | udhcp_add_simple_option(packet, DHCP_SERVER_ID, server_data.server_nip); |
| + | IF_FEATURE_UDHCPD_BOOTP(if (type != MSGTYPE_BOOTP)) |
| + | udhcp_add_simple_option(packet, DHCP_SERVER_ID, server_data.server_nip); |
| } | |
| /* Fill options field, siaddr_nip, and sname and boot_file fields. | |
| @@ -725,7 +726,12 @@ static uint32_t select_lease_time(struct dhcp_packet *packet) | |
| /* We got a DHCP DISCOVER. Send an OFFER. */ | |
| /* NOINLINE: limit stack usage in caller */ | |
| - | static NOINLINE void send_offer(struct dhcp_packet *oldpacket, |
| + | #if !ENABLE_FEATURE_UDHCPD_BOOTP |
| + | #define send_offer(is_dhcp_client, ...) \ |
| + | send_offer(__VA_ARGS__) |
| + | #endif |
| + | static NOINLINE void send_offer(void *is_dhcp_client, |
| + | struct dhcp_packet *oldpacket, |
| uint32_t static_lease_nip, | |
| struct dyn_lease *lease, | |
| uint32_t requested_nip, | |
| @@ -734,7 +740,12 @@ static NOINLINE void send_offer(struct dhcp_packet *oldpacket, | |
| struct dhcp_packet packet; | |
| uint32_t lease_time_sec; | |
| + | #if ENABLE_FEATURE_UDHCPD_BOOTP |
| + | init_packet(&packet, oldpacket, is_dhcp_client ? DHCPOFFER : MSGTYPE_BOOTP); |
| + | #else |
| + | enum { is_dhcp_client = 1 }; |
| init_packet(&packet, oldpacket, DHCPOFFER); | |
| + | #endif |
| /* If it is a static lease, use its IP */ | |
| packet.yiaddr = static_lease_nip; | |
| @@ -784,9 +795,16 @@ static NOINLINE void send_offer(struct dhcp_packet *oldpacket, | |
| } | |
| } | |
| - | lease_time_sec = select_lease_time(oldpacket); |
| - | udhcp_add_simple_option(&packet, DHCP_LEASE_TIME, htonl(lease_time_sec)); |
| + | if (is_dhcp_client) { |
| + | lease_time_sec = select_lease_time(oldpacket); |
| + | udhcp_add_simple_option(&packet, DHCP_LEASE_TIME, htonl(lease_time_sec)); |
| + | } |
| + | /* TODO: pass "is_dhcp_client" to add_server_options(), avoid adding confusing options to BOOTP clients? */ |
| add_server_options(&packet); | |
| + | if (!is_dhcp_client && udhcp_end_option(packet.options) >= RFC1048_OPTIONS_BUFSIZE) { |
| + | bb_simple_error_msg("BOOTP reply too large, not sending"); |
| + | return; |
| + | } |
| /* send_packet emits error message itself if it detects failure */ | |
| send_packet_verbose(&packet, "sending OFFER to %s"); | |
| @@ -1050,8 +1068,12 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) | |
| continue; | |
| } | |
| msg_type = udhcp_get_option(&packet, DHCP_MESSAGE_TYPE); | |
| - | if (!msg_type || msg_type[0] < DHCP_MINTYPE || msg_type[0] > DHCP_MAXTYPE) { |
| - | bb_info_msg("no or bad message type option%s", ", ignoring packet"); |
| + | if ( |
| + | IF_FEATURE_UDHCPD_BOOTP( msg_type && ) |
| + | IF_NOT_FEATURE_UDHCPD_BOOTP( !msg_type || ) |
| + | (msg_type[0] < DHCP_MINTYPE || msg_type[0] > DHCP_MAXTYPE) |
| + | ) { |
| + | bb_info_msg("bad message type option%s", ", ignoring packet"); |
| continue; | |
| } | |
| @@ -1086,12 +1108,25 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) | |
| move_from_unaligned32(requested_nip, requested_ip_opt); | |
| } | |
| + | #if ENABLE_FEATURE_UDHCPD_BOOTP |
| + | /* Handle old BOOTP clients */ |
| + | if (!msg_type) { |
| + | log1("received %s", "BOOTP BOOTREQUEST"); |
| + | if (!static_lease_nip) { |
| + | bb_info_msg("no static lease for BOOTP client%s", ", ignoring packet"); |
| + | continue; |
| + | } |
| + | send_offer(msg_type, &packet, static_lease_nip, lease, requested_nip, arpping_ms); |
| + | continue; |
| + | } |
| + | #endif |
| + | |
| switch (msg_type[0]) { | |
| case DHCPDISCOVER: | |
| log1("received %s", "DISCOVER"); | |
| - | send_offer(&packet, static_lease_nip, lease, requested_nip, arpping_ms); |
| + | send_offer(msg_type, &packet, static_lease_nip, lease, requested_nip, arpping_ms); |
| break; | |
| case DHCPREQUEST: | |
| @@ -18,6 +18,8 @@ void FAST_FUNC udhcp_init_header(struct dhcp_packet *packet, char type) | |
| memset(packet, 0, sizeof(*packet)); | |
| packet->op = BOOTREQUEST; /* if client to a server */ | |
| switch (type) { | |
| + | IF_FEATURE_UDHCPD_BOOTP(case MSGTYPE_BOOTP:) |
| + | /* reply to a BOOTP (not DHCP) client */ |
| case DHCPOFFER: | |
| case DHCPACK: | |
| case DHCPNAK: | |
| @@ -25,10 +27,11 @@ void FAST_FUNC udhcp_init_header(struct dhcp_packet *packet, char type) | |
| } | |
| packet->htype = 1; /* ethernet */ | |
| packet->hlen = 6; | |
| - | packet->cookie = htonl(DHCP_MAGIC); |
| + | packet->cookie = htonl(RFC1048_MAGIC); |
| if (DHCP_END != 0) | |
| packet->options[0] = DHCP_END; | |
| - | udhcp_add_simple_option(packet, DHCP_MESSAGE_TYPE, type); |
| + | IF_FEATURE_UDHCPD_BOOTP(if (type != MSGTYPE_BOOTP)) |
| + | udhcp_add_simple_option(packet, DHCP_MESSAGE_TYPE, type); |
| } | |
| #endif | |
| @@ -90,7 +93,7 @@ int FAST_FUNC udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd) | |
| } | |
| if (bytes < offsetof(struct dhcp_packet, options) | |
| - | || packet->cookie != htonl(DHCP_MAGIC) |
| + | || packet->cookie != htonl(RFC1048_MAGIC) |
| ) { | |
| bb_simple_info_msg("packet with bad magic, ignoring"); | |
| return -2; | |