summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--networking/udhcp/Config.src7
-rw-r--r--networking/udhcp/common.c10
-rw-r--r--networking/udhcp/common.h14
-rw-r--r--networking/udhcp/dhcpc.c2
-rw-r--r--networking/udhcp/dhcpd.c49
-rw-r--r--networking/udhcp/packet.c9
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;