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 7ba7f48fc..d9c501c18 100644 --- a/networking/udhcp/Config.src +++ b/networking/udhcp/Config.src | |||
@@ -10,6 +10,13 @@ config UDHCPD | |||
10 | udhcpd is a DHCP server geared primarily toward embedded systems, | 10 | udhcpd is a DHCP server geared primarily toward embedded systems, |
11 | while striving to be fully functional and RFC compliant. | 11 | while striving to be fully functional and RFC compliant. |
12 | 12 | ||
13 | config FEATURE_UDHCPD_BOOTP | ||
14 | bool "Answer to BOOTP requests as well" | ||
15 | default y | ||
16 | depends on UDHCPD | ||
17 | help | ||
18 | Support old BOOTP protocol too. | ||
19 | |||
13 | config FEATURE_UDHCPD_BASE_IP_ON_MAC | 20 | config FEATURE_UDHCPD_BASE_IP_ON_MAC |
14 | bool "Select IP address based on client MAC" | 21 | bool "Select IP address based on client MAC" |
15 | default n | 22 | default n |
diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c index ae818db05..ad580f38d 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 | |||
252 | /* option bytes: [code][len][data1][data2]..[dataLEN] */ | 252 | /* option bytes: [code][len][data1][data2]..[dataLEN] */ |
253 | while (1) { | 253 | while (1) { |
254 | if (scan_state->rem <= 0) { | 254 | if (scan_state->rem <= 0) { |
255 | if (ENABLE_FEATURE_UDHCPD_BOOTP && scan_state->rem == 0) { | ||
256 | /* DHCP requires END option to be present. | ||
257 | * We are here if packet fails this condition | ||
258 | * (options[] are zero-padded to the end). | ||
259 | * Assume BOOTP packet without further checks. | ||
260 | */ | ||
261 | break; /* return NULL */ | ||
262 | } | ||
255 | complain: | 263 | complain: |
256 | bb_simple_error_msg("bad packet, malformed option field"); | 264 | bb_simple_error_msg("bad packet, malformed option field"); |
257 | return NULL; | 265 | return NULL; |
@@ -278,7 +286,7 @@ uint8_t* FAST_FUNC udhcp_scan_options(struct dhcp_packet *packet, struct dhcp_sc | |||
278 | scan_state->rem = sizeof(packet->sname); | 286 | scan_state->rem = sizeof(packet->sname); |
279 | continue; | 287 | continue; |
280 | } | 288 | } |
281 | break; | 289 | break; /* return NULL */ |
282 | } | 290 | } |
283 | 291 | ||
284 | if (scan_state->rem <= OPT_LEN) /* [len] byte exists? */ | 292 | if (scan_state->rem <= OPT_LEN) /* [len] byte exists? */ |
diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h index 49a0b593d..3ef371a7c 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 */ | |||
20 | 20 | ||
21 | /*** DHCP packet ***/ | 21 | /*** DHCP packet ***/ |
22 | 22 | ||
23 | #define RFC1048_MAGIC 0x63825363 | ||
24 | /* RFC 1048 still uses BOOTP's small buffer (4 byte cookie + 60 the rest) */ | ||
25 | #define RFC1048_OPTIONS_BUFSIZE 60 | ||
26 | |||
23 | /* DHCP protocol. See RFC 2131 */ | 27 | /* DHCP protocol. See RFC 2131 */ |
24 | #define DHCP_MAGIC 0x63825363 | ||
25 | #define DHCP_OPTIONS_BUFSIZE 308 | 28 | #define DHCP_OPTIONS_BUFSIZE 308 |
26 | #define BOOTREQUEST 1 | 29 | #define BOOTREQUEST 1 |
27 | #define BOOTREPLY 2 | 30 | #define BOOTREPLY 2 |
@@ -57,8 +60,10 @@ struct dhcp_packet { | |||
57 | * such as 'unix' or 'gateway'; this means 'boot the named program | 60 | * such as 'unix' or 'gateway'; this means 'boot the named program |
58 | * configured for my machine'" | 61 | * configured for my machine'" |
59 | */ | 62 | */ |
60 | /* BOOTP fields end here, BOOTP says optional uint8_t vend[64] follows */ | 63 | /* BOOTP fields end here, BOOTP says optional uint8_t vend[64] follows. */ |
61 | uint32_t cookie; /* DHCP magic bytes: 99,130,83,99 decimal */ | 64 | /* RFC 1048 defined this cookie value and options 0-12 and 255. */ |
65 | /* DHCP extended it and required option 255 (END) to be always present. */ | ||
66 | uint32_t cookie; /* RFC 1048 magic bytes: 99,130,83,99 decimal */ | ||
62 | uint8_t options[DHCP_OPTIONS_BUFSIZE + CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS]; | 67 | uint8_t options[DHCP_OPTIONS_BUFSIZE + CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS]; |
63 | }; | 68 | }; |
64 | #define DHCP_PKT_SNAME_LEN 64 | 69 | #define DHCP_PKT_SNAME_LEN 64 |
@@ -200,6 +205,9 @@ struct dhcp_scan_state { | |||
200 | #define SNAME_FIELD 2 | 205 | #define SNAME_FIELD 2 |
201 | 206 | ||
202 | /* DHCP_MESSAGE_TYPE values */ | 207 | /* DHCP_MESSAGE_TYPE values */ |
208 | #if ENABLE_FEATURE_UDHCPD_BOOTP | ||
209 | #define MSGTYPE_BOOTP 0 /* there was no TYPE option in client's packet, assuming BOOTP */ | ||
210 | #endif | ||
203 | #define DHCPDISCOVER 1 /* client -> server */ | 211 | #define DHCPDISCOVER 1 /* client -> server */ |
204 | #define DHCPOFFER 2 /* client <- server */ | 212 | #define DHCPOFFER 2 /* client <- server */ |
205 | #define DHCPREQUEST 3 /* client -> server */ | 213 | #define DHCPREQUEST 3 /* client -> server */ |
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index c757fb37c..200a2fb8a 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) | |||
971 | } | 971 | } |
972 | skip_udp_sum_check: | 972 | skip_udp_sum_check: |
973 | 973 | ||
974 | if (packet.data.cookie != htonl(DHCP_MAGIC)) { | 974 | if (packet.data.cookie != htonl(RFC1048_MAGIC)) { |
975 | log1s("packet with bad magic, ignoring"); | 975 | log1s("packet with bad magic, ignoring"); |
976 | return -2; | 976 | return -2; |
977 | } | 977 | } |
diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c index 66750e2e6..2904119e5 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 | |||
649 | packet->flags = oldpacket->flags; | 649 | packet->flags = oldpacket->flags; |
650 | packet->gateway_nip = oldpacket->gateway_nip; | 650 | packet->gateway_nip = oldpacket->gateway_nip; |
651 | packet->ciaddr = oldpacket->ciaddr; | 651 | packet->ciaddr = oldpacket->ciaddr; |
652 | udhcp_add_simple_option(packet, DHCP_SERVER_ID, server_data.server_nip); | 652 | IF_FEATURE_UDHCPD_BOOTP(if (type != MSGTYPE_BOOTP)) |
653 | udhcp_add_simple_option(packet, DHCP_SERVER_ID, server_data.server_nip); | ||
653 | } | 654 | } |
654 | 655 | ||
655 | /* Fill options field, siaddr_nip, and sname and boot_file fields. | 656 | /* 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) | |||
725 | 726 | ||
726 | /* We got a DHCP DISCOVER. Send an OFFER. */ | 727 | /* We got a DHCP DISCOVER. Send an OFFER. */ |
727 | /* NOINLINE: limit stack usage in caller */ | 728 | /* NOINLINE: limit stack usage in caller */ |
728 | static NOINLINE void send_offer(struct dhcp_packet *oldpacket, | 729 | #if !ENABLE_FEATURE_UDHCPD_BOOTP |
730 | #define send_offer(is_dhcp_client, ...) \ | ||
731 | send_offer(__VA_ARGS__) | ||
732 | #endif | ||
733 | static NOINLINE void send_offer(void *is_dhcp_client, | ||
734 | struct dhcp_packet *oldpacket, | ||
729 | uint32_t static_lease_nip, | 735 | uint32_t static_lease_nip, |
730 | struct dyn_lease *lease, | 736 | struct dyn_lease *lease, |
731 | uint32_t requested_nip, | 737 | uint32_t requested_nip, |
@@ -734,7 +740,12 @@ static NOINLINE void send_offer(struct dhcp_packet *oldpacket, | |||
734 | struct dhcp_packet packet; | 740 | struct dhcp_packet packet; |
735 | uint32_t lease_time_sec; | 741 | uint32_t lease_time_sec; |
736 | 742 | ||
743 | #if ENABLE_FEATURE_UDHCPD_BOOTP | ||
744 | init_packet(&packet, oldpacket, is_dhcp_client ? DHCPOFFER : MSGTYPE_BOOTP); | ||
745 | #else | ||
746 | enum { is_dhcp_client = 1 }; | ||
737 | init_packet(&packet, oldpacket, DHCPOFFER); | 747 | init_packet(&packet, oldpacket, DHCPOFFER); |
748 | #endif | ||
738 | 749 | ||
739 | /* If it is a static lease, use its IP */ | 750 | /* If it is a static lease, use its IP */ |
740 | packet.yiaddr = static_lease_nip; | 751 | packet.yiaddr = static_lease_nip; |
@@ -784,9 +795,16 @@ static NOINLINE void send_offer(struct dhcp_packet *oldpacket, | |||
784 | } | 795 | } |
785 | } | 796 | } |
786 | 797 | ||
787 | lease_time_sec = select_lease_time(oldpacket); | 798 | if (is_dhcp_client) { |
788 | udhcp_add_simple_option(&packet, DHCP_LEASE_TIME, htonl(lease_time_sec)); | 799 | lease_time_sec = select_lease_time(oldpacket); |
800 | udhcp_add_simple_option(&packet, DHCP_LEASE_TIME, htonl(lease_time_sec)); | ||
801 | } | ||
802 | /* TODO: pass "is_dhcp_client" to add_server_options(), avoid adding confusing options to BOOTP clients? */ | ||
789 | add_server_options(&packet); | 803 | add_server_options(&packet); |
804 | if (!is_dhcp_client && udhcp_end_option(packet.options) >= RFC1048_OPTIONS_BUFSIZE) { | ||
805 | bb_simple_error_msg("BOOTP reply too large, not sending"); | ||
806 | return; | ||
807 | } | ||
790 | 808 | ||
791 | /* send_packet emits error message itself if it detects failure */ | 809 | /* send_packet emits error message itself if it detects failure */ |
792 | send_packet_verbose(&packet, "sending OFFER to %s"); | 810 | send_packet_verbose(&packet, "sending OFFER to %s"); |
@@ -1050,8 +1068,12 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) | |||
1050 | continue; | 1068 | continue; |
1051 | } | 1069 | } |
1052 | msg_type = udhcp_get_option(&packet, DHCP_MESSAGE_TYPE); | 1070 | msg_type = udhcp_get_option(&packet, DHCP_MESSAGE_TYPE); |
1053 | if (!msg_type || msg_type[0] < DHCP_MINTYPE || msg_type[0] > DHCP_MAXTYPE) { | 1071 | if ( |
1054 | bb_info_msg("no or bad message type option%s", ", ignoring packet"); | 1072 | IF_FEATURE_UDHCPD_BOOTP( msg_type && ) |
1073 | IF_NOT_FEATURE_UDHCPD_BOOTP( !msg_type || ) | ||
1074 | (msg_type[0] < DHCP_MINTYPE || msg_type[0] > DHCP_MAXTYPE) | ||
1075 | ) { | ||
1076 | bb_info_msg("bad message type option%s", ", ignoring packet"); | ||
1055 | continue; | 1077 | continue; |
1056 | } | 1078 | } |
1057 | 1079 | ||
@@ -1086,12 +1108,25 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) | |||
1086 | move_from_unaligned32(requested_nip, requested_ip_opt); | 1108 | move_from_unaligned32(requested_nip, requested_ip_opt); |
1087 | } | 1109 | } |
1088 | 1110 | ||
1111 | #if ENABLE_FEATURE_UDHCPD_BOOTP | ||
1112 | /* Handle old BOOTP clients */ | ||
1113 | if (!msg_type) { | ||
1114 | log1("received %s", "BOOTP BOOTREQUEST"); | ||
1115 | if (!static_lease_nip) { | ||
1116 | bb_info_msg("no static lease for BOOTP client%s", ", ignoring packet"); | ||
1117 | continue; | ||
1118 | } | ||
1119 | send_offer(msg_type, &packet, static_lease_nip, lease, requested_nip, arpping_ms); | ||
1120 | continue; | ||
1121 | } | ||
1122 | #endif | ||
1123 | |||
1089 | switch (msg_type[0]) { | 1124 | switch (msg_type[0]) { |
1090 | 1125 | ||
1091 | case DHCPDISCOVER: | 1126 | case DHCPDISCOVER: |
1092 | log1("received %s", "DISCOVER"); | 1127 | log1("received %s", "DISCOVER"); |
1093 | 1128 | ||
1094 | send_offer(&packet, static_lease_nip, lease, requested_nip, arpping_ms); | 1129 | send_offer(msg_type, &packet, static_lease_nip, lease, requested_nip, arpping_ms); |
1095 | break; | 1130 | break; |
1096 | 1131 | ||
1097 | case DHCPREQUEST: | 1132 | case DHCPREQUEST: |
diff --git a/networking/udhcp/packet.c b/networking/udhcp/packet.c index 529978189..f9dc11d01 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) | |||
18 | memset(packet, 0, sizeof(*packet)); | 18 | memset(packet, 0, sizeof(*packet)); |
19 | packet->op = BOOTREQUEST; /* if client to a server */ | 19 | packet->op = BOOTREQUEST; /* if client to a server */ |
20 | switch (type) { | 20 | switch (type) { |
21 | IF_FEATURE_UDHCPD_BOOTP(case MSGTYPE_BOOTP:) | ||
22 | /* reply to a BOOTP (not DHCP) client */ | ||
21 | case DHCPOFFER: | 23 | case DHCPOFFER: |
22 | case DHCPACK: | 24 | case DHCPACK: |
23 | case DHCPNAK: | 25 | case DHCPNAK: |
@@ -25,10 +27,11 @@ void FAST_FUNC udhcp_init_header(struct dhcp_packet *packet, char type) | |||
25 | } | 27 | } |
26 | packet->htype = 1; /* ethernet */ | 28 | packet->htype = 1; /* ethernet */ |
27 | packet->hlen = 6; | 29 | packet->hlen = 6; |
28 | packet->cookie = htonl(DHCP_MAGIC); | 30 | packet->cookie = htonl(RFC1048_MAGIC); |
29 | if (DHCP_END != 0) | 31 | if (DHCP_END != 0) |
30 | packet->options[0] = DHCP_END; | 32 | packet->options[0] = DHCP_END; |
31 | udhcp_add_simple_option(packet, DHCP_MESSAGE_TYPE, type); | 33 | IF_FEATURE_UDHCPD_BOOTP(if (type != MSGTYPE_BOOTP)) |
34 | udhcp_add_simple_option(packet, DHCP_MESSAGE_TYPE, type); | ||
32 | } | 35 | } |
33 | #endif | 36 | #endif |
34 | 37 | ||
@@ -90,7 +93,7 @@ int FAST_FUNC udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd) | |||
90 | } | 93 | } |
91 | 94 | ||
92 | if (bytes < offsetof(struct dhcp_packet, options) | 95 | if (bytes < offsetof(struct dhcp_packet, options) |
93 | || packet->cookie != htonl(DHCP_MAGIC) | 96 | || packet->cookie != htonl(RFC1048_MAGIC) |
94 | ) { | 97 | ) { |
95 | bb_simple_info_msg("packet with bad magic, ignoring"); | 98 | bb_simple_info_msg("packet with bad magic, ignoring"); |
96 | return -2; | 99 | return -2; |