diff options
-rw-r--r-- | networking/udhcp/Config.src | 7 | ||||
-rw-r--r-- | networking/udhcp/common.c | 10 | ||||
-rw-r--r-- | networking/udhcp/common.h | 14 | ||||
-rw-r--r-- | networking/udhcp/dhcpc.c | 2 | ||||
-rw-r--r-- | networking/udhcp/dhcpd.c | 49 | ||||
-rw-r--r-- | networking/udhcp/packet.c | 9 |
6 files changed, 76 insertions, 15 deletions
diff --git a/networking/udhcp/Config.src b/networking/udhcp/Config.src index 7ba7f48..d9c501c 100644 --- a/networking/udhcp/Config.src +++ b/networking/udhcp/Config.src @@ -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 diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c index ae818db..ad580f3 100644 --- a/networking/udhcp/common.c +++ b/networking/udhcp/common.c @@ -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? */ diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h index 49a0b59..3ef371a 100644 --- a/networking/udhcp/common.h +++ b/networking/udhcp/common.h @@ -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 */ diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index c757fb3..200a2fb 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c @@ -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; } diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c index 66750e2..2904119 100644 --- a/networking/udhcp/dhcpd.c +++ b/networking/udhcp/dhcpd.c @@ -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: diff --git a/networking/udhcp/packet.c b/networking/udhcp/packet.c index 5299781..f9dc11d 100644 --- a/networking/udhcp/packet.c +++ b/networking/udhcp/packet.c @@ -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; |