diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2010-03-21 06:15:28 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2010-03-21 06:15:28 +0100 |
commit | c7dc79e71ddbc1498736a2bbf65a3da179557f83 (patch) | |
tree | ab470e39f11f432b2099d3ebbe779d224bc1efba | |
parent | 2e7aa928360eb9b1c90fa2356734cee794b66516 (diff) | |
download | busybox-w32-c7dc79e71ddbc1498736a2bbf65a3da179557f83.tar.gz busybox-w32-c7dc79e71ddbc1498736a2bbf65a3da179557f83.tar.bz2 busybox-w32-c7dc79e71ddbc1498736a2bbf65a3da179557f83.zip |
udhcpd: untangle incredibly messy handling of DHCPREQUEST
Also fixes attacks possible via DHCPDECLINE / DHCPRELEASE
function old new delta
udhcpd_main 1846 1949 +103
send_renew 105 142 +37
send_NAK 61 - -61
send_ACK 180 - -180
------------------------------------------------------------------------------
(add/remove: 0/2 grow/shrink: 2/0 up/down: 140/-241) Total: -101 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | networking/udhcp/clientpacket.c | 52 | ||||
-rw-r--r-- | networking/udhcp/common.h | 75 | ||||
-rw-r--r-- | networking/udhcp/dhcpc.h | 1 | ||||
-rw-r--r-- | networking/udhcp/dhcpd.c | 264 | ||||
-rw-r--r-- | networking/udhcp/files.c | 14 | ||||
-rw-r--r-- | networking/udhcp/options.c | 2 | ||||
-rw-r--r-- | networking/udhcp/options.h | 30 | ||||
-rw-r--r-- | networking/udhcp/packet.c | 11 | ||||
-rw-r--r-- | networking/udhcp/script.c | 2 |
9 files changed, 267 insertions, 184 deletions
diff --git a/networking/udhcp/clientpacket.c b/networking/udhcp/clientpacket.c index a255d6e84..a0be42885 100644 --- a/networking/udhcp/clientpacket.c +++ b/networking/udhcp/clientpacket.c | |||
@@ -109,24 +109,6 @@ static int raw_bcast_from_client_config_ifindex(struct dhcp_packet *packet) | |||
109 | } | 109 | } |
110 | 110 | ||
111 | 111 | ||
112 | #if ENABLE_FEATURE_UDHCPC_ARPING | ||
113 | /* Broadcast a DHCP decline message */ | ||
114 | int FAST_FUNC send_decline(uint32_t xid, uint32_t server, uint32_t requested) | ||
115 | { | ||
116 | struct dhcp_packet packet; | ||
117 | |||
118 | init_packet(&packet, DHCPDECLINE); | ||
119 | packet.xid = xid; | ||
120 | add_simple_option(packet.options, DHCP_REQUESTED_IP, requested); | ||
121 | add_simple_option(packet.options, DHCP_SERVER_ID, server); | ||
122 | |||
123 | bb_info_msg("Sending decline..."); | ||
124 | |||
125 | return raw_bcast_from_client_config_ifindex(&packet); | ||
126 | } | ||
127 | #endif | ||
128 | |||
129 | |||
130 | /* Broadcast a DHCP discover packet to the network, with an optionally requested IP */ | 112 | /* Broadcast a DHCP discover packet to the network, with an optionally requested IP */ |
131 | int FAST_FUNC send_discover(uint32_t xid, uint32_t requested) | 113 | int FAST_FUNC send_discover(uint32_t xid, uint32_t requested) |
132 | { | 114 | { |
@@ -136,11 +118,9 @@ int FAST_FUNC send_discover(uint32_t xid, uint32_t requested) | |||
136 | packet.xid = xid; | 118 | packet.xid = xid; |
137 | if (requested) | 119 | if (requested) |
138 | add_simple_option(packet.options, DHCP_REQUESTED_IP, requested); | 120 | add_simple_option(packet.options, DHCP_REQUESTED_IP, requested); |
139 | |||
140 | /* Explicitly saying that we want RFC-compliant packets helps | 121 | /* Explicitly saying that we want RFC-compliant packets helps |
141 | * some buggy DHCP servers to NOT send bigger packets */ | 122 | * some buggy DHCP servers to NOT send bigger packets */ |
142 | add_simple_option(packet.options, DHCP_MAX_SIZE, htons(576)); | 123 | add_simple_option(packet.options, DHCP_MAX_SIZE, htons(576)); |
143 | |||
144 | add_param_req_option(&packet); | 124 | add_param_req_option(&packet); |
145 | 125 | ||
146 | bb_info_msg("Sending discover..."); | 126 | bb_info_msg("Sending discover..."); |
@@ -159,7 +139,6 @@ int FAST_FUNC send_select(uint32_t xid, uint32_t server, uint32_t requested) | |||
159 | 139 | ||
160 | init_packet(&packet, DHCPREQUEST); | 140 | init_packet(&packet, DHCPREQUEST); |
161 | packet.xid = xid; | 141 | packet.xid = xid; |
162 | |||
163 | add_simple_option(packet.options, DHCP_REQUESTED_IP, requested); | 142 | add_simple_option(packet.options, DHCP_REQUESTED_IP, requested); |
164 | add_simple_option(packet.options, DHCP_SERVER_ID, server); | 143 | add_simple_option(packet.options, DHCP_SERVER_ID, server); |
165 | add_param_req_option(&packet); | 144 | add_param_req_option(&packet); |
@@ -177,17 +156,46 @@ int FAST_FUNC send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) | |||
177 | 156 | ||
178 | init_packet(&packet, DHCPREQUEST); | 157 | init_packet(&packet, DHCPREQUEST); |
179 | packet.xid = xid; | 158 | packet.xid = xid; |
159 | /* RFC 2131: | ||
160 | * "3.2 Client-server interaction - reusing a previously | ||
161 | * allocated network address"... | ||
162 | * The client broadcasts a DHCPREQUEST message on its local subnet. | ||
163 | * The message includes the client's network address in the | ||
164 | * REQUESTED_IP option. As the client has not received its | ||
165 | * network address, it MUST NOT fill in the 'ciaddr' field." | ||
166 | * | ||
167 | * FIXME: we seem to not follow this, we do set ciaddr. | ||
168 | */ | ||
180 | packet.ciaddr = ciaddr; | 169 | packet.ciaddr = ciaddr; |
181 | 170 | add_simple_option(packet.options, DHCP_REQUESTED_IP, ciaddr); | |
171 | if (server) | ||
172 | add_simple_option(packet.options, DHCP_SERVER_ID, server); | ||
182 | add_param_req_option(&packet); | 173 | add_param_req_option(&packet); |
174 | |||
183 | bb_info_msg("Sending renew..."); | 175 | bb_info_msg("Sending renew..."); |
184 | if (server) | 176 | if (server) |
185 | return udhcp_send_kernel_packet(&packet, | 177 | return udhcp_send_kernel_packet(&packet, |
186 | ciaddr, CLIENT_PORT, | 178 | ciaddr, CLIENT_PORT, |
187 | server, SERVER_PORT); | 179 | server, SERVER_PORT); |
180 | return raw_bcast_from_client_config_ifindex(&packet); | ||
181 | } | ||
182 | |||
183 | |||
184 | #if ENABLE_FEATURE_UDHCPC_ARPING | ||
185 | /* Broadcast a DHCP decline message */ | ||
186 | int FAST_FUNC send_decline(uint32_t xid, uint32_t server, uint32_t requested) | ||
187 | { | ||
188 | struct dhcp_packet packet; | ||
189 | |||
190 | init_packet(&packet, DHCPDECLINE); | ||
191 | packet.xid = xid; | ||
192 | add_simple_option(packet.options, DHCP_REQUESTED_IP, requested); | ||
193 | add_simple_option(packet.options, DHCP_SERVER_ID, server); | ||
188 | 194 | ||
195 | bb_info_msg("Sending decline..."); | ||
189 | return raw_bcast_from_client_config_ifindex(&packet); | 196 | return raw_bcast_from_client_config_ifindex(&packet); |
190 | } | 197 | } |
198 | #endif | ||
191 | 199 | ||
192 | 200 | ||
193 | /* Unicast a DHCP release message */ | 201 | /* Unicast a DHCP release message */ |
diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h index d7c874e5b..cf3e0cd39 100644 --- a/networking/udhcp/common.h +++ b/networking/udhcp/common.h | |||
@@ -21,11 +21,17 @@ extern const uint8_t MAC_BCAST_ADDR[6]; /* six all-ones */ | |||
21 | 21 | ||
22 | /*** packet.h ***/ | 22 | /*** packet.h ***/ |
23 | 23 | ||
24 | #define DHCP_OPTIONS_BUFSIZE 308 | 24 | /* DHCP protocol. See RFC 2131 */ |
25 | #define DHCP_MAGIC 0x63825363 | ||
26 | |||
27 | #define DHCP_OPTIONS_BUFSIZE 308 | ||
28 | |||
29 | #define BOOTREQUEST 1 | ||
30 | #define BOOTREPLY 2 | ||
25 | 31 | ||
26 | //TODO: rename ciaddr/yiaddr/chaddr | 32 | //TODO: rename ciaddr/yiaddr/chaddr |
27 | struct dhcp_packet { | 33 | struct dhcp_packet { |
28 | uint8_t op; /* 1 = BOOTREQUEST, 2 = BOOTREPLY */ | 34 | uint8_t op; /* BOOTREQUEST or BOOTREPLY */ |
29 | uint8_t htype; /* hardware address type. 1 = 10mb ethernet */ | 35 | uint8_t htype; /* hardware address type. 1 = 10mb ethernet */ |
30 | uint8_t hlen; /* hardware address length */ | 36 | uint8_t hlen; /* hardware address length */ |
31 | uint8_t hops; /* used by relay agents only */ | 37 | uint8_t hops; /* used by relay agents only */ |
@@ -61,6 +67,71 @@ struct BUG_bad_sizeof_struct_ip_udp_dhcp_packet { | |||
61 | [(sizeof(struct ip_udp_dhcp_packet) != 576 + CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS) ? -1 : 1]; | 67 | [(sizeof(struct ip_udp_dhcp_packet) != 576 + CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS) ? -1 : 1]; |
62 | }; | 68 | }; |
63 | 69 | ||
70 | // RFC 2131 Table 5: Fields and options used by DHCP clients | ||
71 | // | ||
72 | // Field DHCPDISCOVER DHCPREQUEST DHCPDECLINE, | ||
73 | // DHCPINFORM DHCPRELEASE | ||
74 | // ----- ------------ ----------- ----------- | ||
75 | // 'op' BOOTREQUEST BOOTREQUEST BOOTREQUEST | ||
76 | // 'hops' 0 0 0 | ||
77 | // 'xid' selected by client 'xid' from server selected by | ||
78 | // DHCPOFFER message client | ||
79 | // 'secs' 0 or seconds since 0 or seconds since 0 | ||
80 | // DHCP process started DHCP process started | ||
81 | // 'flags' Set 'BROADCAST' Set 'BROADCAST' 0 | ||
82 | // flag if client flag if client | ||
83 | // requires broadcast requires broadcast | ||
84 | // reply reply | ||
85 | // 'ciaddr' 0 (DHCPDISCOVER) 0 or client's 0 (DHCPDECLINE) | ||
86 | // client's network address client's network | ||
87 | // network address (BOUND/RENEW/REBIND) address | ||
88 | // (DHCPINFORM) (DHCPRELEASE) | ||
89 | // 'yiaddr' 0 0 0 | ||
90 | // 'siaddr' 0 0 0 | ||
91 | // 'giaddr' 0 0 0 | ||
92 | // 'chaddr' client's hardware client's hardware client's hardware | ||
93 | // address address address | ||
94 | // 'sname' options, if options, if (unused) | ||
95 | // indicated in indicated in | ||
96 | // 'sname/file' 'sname/file' | ||
97 | // option; otherwise option; otherwise | ||
98 | // unused unused | ||
99 | // 'file' options, if options, if (unused) | ||
100 | // indicated in indicated in | ||
101 | // 'sname/file' 'sname/file' | ||
102 | // option; otherwise option; otherwise | ||
103 | // unused unused | ||
104 | // 'options' options options (unused) | ||
105 | // | ||
106 | // Option DHCPDISCOVER DHCPREQUEST DHCPDECLINE, | ||
107 | // DHCPINFORM DHCPRELEASE | ||
108 | // ------ ------------ ----------- ----------- | ||
109 | // Requested IP address MAY MUST (in MUST | ||
110 | // (DISCOVER) SELECTING or (DHCPDECLINE), | ||
111 | // MUST NOT INIT-REBOOT) MUST NOT | ||
112 | // (INFORM) MUST NOT (in (DHCPRELEASE) | ||
113 | // BOUND or | ||
114 | // RENEWING) | ||
115 | // IP address lease time MAY MAY MUST NOT | ||
116 | // (DISCOVER) | ||
117 | // MUST NOT | ||
118 | // (INFORM) | ||
119 | // Use 'file'/'sname' fields MAY MAY MAY | ||
120 | // Client identifier MAY MAY MAY | ||
121 | // Vendor class identifier MAY MAY MUST NOT | ||
122 | // Server identifier MUST NOT MUST (after MUST | ||
123 | // SELECTING) | ||
124 | // MUST NOT (after | ||
125 | // INIT-REBOOT, | ||
126 | // BOUND, RENEWING | ||
127 | // or REBINDING) | ||
128 | // Parameter request list MAY MAY MUST NOT | ||
129 | // Maximum message size MAY MAY MUST NOT | ||
130 | // Message SHOULD NOT SHOULD NOT SHOULD | ||
131 | // Site-specific MAY MAY MUST NOT | ||
132 | // All others MAY MAY MUST NOT | ||
133 | |||
134 | |||
64 | uint16_t udhcp_checksum(void *addr, int count) FAST_FUNC; | 135 | uint16_t udhcp_checksum(void *addr, int count) FAST_FUNC; |
65 | 136 | ||
66 | void udhcp_init_header(struct dhcp_packet *packet, char type) FAST_FUNC; | 137 | void udhcp_init_header(struct dhcp_packet *packet, char type) FAST_FUNC; |
diff --git a/networking/udhcp/dhcpc.h b/networking/udhcp/dhcpc.h index dfab2368c..c9827b6e7 100644 --- a/networking/udhcp/dhcpc.h +++ b/networking/udhcp/dhcpc.h | |||
@@ -40,7 +40,6 @@ int send_select(uint32_t xid, uint32_t server, uint32_t requested) FAST_FUNC; | |||
40 | int send_decline(uint32_t xid, uint32_t server, uint32_t requested) FAST_FUNC; | 40 | int send_decline(uint32_t xid, uint32_t server, uint32_t requested) FAST_FUNC; |
41 | #endif | 41 | #endif |
42 | int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) FAST_FUNC; | 42 | int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) FAST_FUNC; |
43 | int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) FAST_FUNC; | ||
44 | int send_release(uint32_t server, uint32_t ciaddr) FAST_FUNC; | 43 | int send_release(uint32_t server, uint32_t ciaddr) FAST_FUNC; |
45 | 44 | ||
46 | int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) FAST_FUNC; | 45 | int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) FAST_FUNC; |
diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c index f594bad66..a529e1b58 100644 --- a/networking/udhcp/dhcpd.c +++ b/networking/udhcp/dhcpd.c | |||
@@ -28,18 +28,8 @@ | |||
28 | #include "options.h" | 28 | #include "options.h" |
29 | 29 | ||
30 | 30 | ||
31 | /* send a packet to gateway_nip using the kernel ip stack */ | 31 | /* Send a packet to a specific mac address and ip address by creating our own ip packet */ |
32 | static int send_packet_to_relay(struct dhcp_packet *dhcp_pkt) | 32 | static void send_packet_to_client(struct dhcp_packet *dhcp_pkt, int force_broadcast) |
33 | { | ||
34 | log1("Forwarding packet to relay"); | ||
35 | |||
36 | return udhcp_send_kernel_packet(dhcp_pkt, | ||
37 | server_config.server_nip, SERVER_PORT, | ||
38 | dhcp_pkt->gateway_nip, SERVER_PORT); | ||
39 | } | ||
40 | |||
41 | /* send a packet to a specific mac address and ip address by creating our own ip packet */ | ||
42 | static int send_packet_to_client(struct dhcp_packet *dhcp_pkt, int force_broadcast) | ||
43 | { | 33 | { |
44 | const uint8_t *chaddr; | 34 | const uint8_t *chaddr; |
45 | uint32_t ciaddr; | 35 | uint32_t ciaddr; |
@@ -69,25 +59,36 @@ static int send_packet_to_client(struct dhcp_packet *dhcp_pkt, int force_broadca | |||
69 | chaddr = dhcp_pkt->chaddr; | 59 | chaddr = dhcp_pkt->chaddr; |
70 | } | 60 | } |
71 | 61 | ||
72 | return udhcp_send_raw_packet(dhcp_pkt, | 62 | udhcp_send_raw_packet(dhcp_pkt, |
73 | /*src*/ server_config.server_nip, SERVER_PORT, | 63 | /*src*/ server_config.server_nip, SERVER_PORT, |
74 | /*dst*/ ciaddr, CLIENT_PORT, chaddr, | 64 | /*dst*/ ciaddr, CLIENT_PORT, chaddr, |
75 | server_config.ifindex); | 65 | server_config.ifindex); |
76 | } | 66 | } |
77 | 67 | ||
78 | /* Send the dhcp packet. | 68 | /* Send a packet to gateway_nip using the kernel ip stack */ |
79 | * If force broadcast is set, the packet will be broadcast. | 69 | static void send_packet_to_relay(struct dhcp_packet *dhcp_pkt) |
80 | */ | 70 | { |
81 | static int send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast) | 71 | log1("Forwarding packet to relay"); |
72 | |||
73 | udhcp_send_kernel_packet(dhcp_pkt, | ||
74 | server_config.server_nip, SERVER_PORT, | ||
75 | dhcp_pkt->gateway_nip, SERVER_PORT); | ||
76 | } | ||
77 | |||
78 | static void send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast) | ||
82 | { | 79 | { |
83 | if (dhcp_pkt->gateway_nip) | 80 | if (dhcp_pkt->gateway_nip) |
84 | return send_packet_to_relay(dhcp_pkt); | 81 | send_packet_to_relay(dhcp_pkt); |
85 | return send_packet_to_client(dhcp_pkt, force_broadcast); | 82 | else |
83 | send_packet_to_client(dhcp_pkt, force_broadcast); | ||
86 | } | 84 | } |
87 | 85 | ||
88 | static void init_packet(struct dhcp_packet *packet, struct dhcp_packet *oldpacket, char type) | 86 | static void init_packet(struct dhcp_packet *packet, struct dhcp_packet *oldpacket, char type) |
89 | { | 87 | { |
88 | /* Sets op, htype, hlen, cookie fields | ||
89 | * and adds DHCP_MESSAGE_TYPE option */ | ||
90 | udhcp_init_header(packet, type); | 90 | udhcp_init_header(packet, type); |
91 | |||
91 | packet->xid = oldpacket->xid; | 92 | packet->xid = oldpacket->xid; |
92 | memcpy(packet->chaddr, oldpacket->chaddr, sizeof(oldpacket->chaddr)); | 93 | memcpy(packet->chaddr, oldpacket->chaddr, sizeof(oldpacket->chaddr)); |
93 | packet->flags = oldpacket->flags; | 94 | packet->flags = oldpacket->flags; |
@@ -132,26 +133,32 @@ static uint32_t select_lease_time(struct dhcp_packet *packet) | |||
132 | return lease_time_sec; | 133 | return lease_time_sec; |
133 | } | 134 | } |
134 | 135 | ||
135 | /* send a DHCP OFFER to a DHCP DISCOVER */ | 136 | /* We got a DHCP DISCOVER. Send an OFFER. */ |
136 | static int send_offer(struct dhcp_packet *oldpacket, uint32_t static_lease_nip, struct dyn_lease *lease) | 137 | static void send_offer(struct dhcp_packet *oldpacket, uint32_t static_lease_nip, struct dyn_lease *lease) |
137 | { | 138 | { |
138 | struct dhcp_packet packet; | 139 | struct dhcp_packet packet; |
139 | uint32_t lease_time_sec = server_config.max_lease_sec; | 140 | uint32_t lease_time_sec; |
140 | const char *p_host_name; | ||
141 | struct in_addr addr; | 141 | struct in_addr addr; |
142 | 142 | ||
143 | init_packet(&packet, oldpacket, DHCPOFFER); | 143 | init_packet(&packet, oldpacket, DHCPOFFER); |
144 | 144 | ||
145 | /* ADDME: if static, short circuit */ | 145 | /* If it is a static lease, use its IP */ |
146 | packet.yiaddr = static_lease_nip; | ||
147 | /* Else: */ | ||
146 | if (!static_lease_nip) { | 148 | if (!static_lease_nip) { |
149 | /* We have no static lease for client's chaddr */ | ||
147 | uint32_t req_nip; | 150 | uint32_t req_nip; |
148 | uint8_t *req_ip_opt; | 151 | uint8_t *req_ip_opt; |
152 | const char *p_host_name; | ||
149 | 153 | ||
150 | /* The client is in our lease/offered table */ | ||
151 | if (lease) { | 154 | if (lease) { |
155 | /* We have a dynamic lease for client's chaddr. | ||
156 | * Reuse its IP (even if lease is expired). | ||
157 | * Note that we ignore requested IP in this case. | ||
158 | */ | ||
152 | packet.yiaddr = lease->lease_nip; | 159 | packet.yiaddr = lease->lease_nip; |
153 | } | 160 | } |
154 | /* Or the client has requested an IP */ | 161 | /* Or: if client has requested an IP */ |
155 | else if ((req_ip_opt = get_option(oldpacket, DHCP_REQUESTED_IP)) != NULL | 162 | else if ((req_ip_opt = get_option(oldpacket, DHCP_REQUESTED_IP)) != NULL |
156 | /* (read IP) */ | 163 | /* (read IP) */ |
157 | && (move_from_unaligned32(req_nip, req_ip_opt), 1) | 164 | && (move_from_unaligned32(req_nip, req_ip_opt), 1) |
@@ -165,50 +172,49 @@ static int send_offer(struct dhcp_packet *oldpacket, uint32_t static_lease_nip, | |||
165 | ) { | 172 | ) { |
166 | packet.yiaddr = req_nip; | 173 | packet.yiaddr = req_nip; |
167 | } | 174 | } |
168 | /* Otherwise, find a free IP */ | ||
169 | else { | 175 | else { |
176 | /* Otherwise, find a free IP */ | ||
170 | packet.yiaddr = find_free_or_expired_nip(oldpacket->chaddr); | 177 | packet.yiaddr = find_free_or_expired_nip(oldpacket->chaddr); |
171 | } | 178 | } |
172 | 179 | ||
173 | if (!packet.yiaddr) { | 180 | if (!packet.yiaddr) { |
174 | bb_error_msg("no IP addresses to give - OFFER abandoned"); | 181 | bb_error_msg("no free IP addresses. OFFER abandoned"); |
175 | return -1; | 182 | return; |
176 | } | 183 | } |
184 | /* Reserve the IP for a short time hoping to get DHCPREQUEST soon */ | ||
177 | p_host_name = (const char*) get_option(oldpacket, DHCP_HOST_NAME); | 185 | p_host_name = (const char*) get_option(oldpacket, DHCP_HOST_NAME); |
178 | if (add_lease(packet.chaddr, packet.yiaddr, | 186 | lease = add_lease(packet.chaddr, packet.yiaddr, |
179 | server_config.offer_time, | 187 | server_config.offer_time, |
180 | p_host_name, | 188 | p_host_name, |
181 | p_host_name ? (unsigned char)p_host_name[OPT_LEN - OPT_DATA] : 0 | 189 | p_host_name ? (unsigned char)p_host_name[OPT_LEN - OPT_DATA] : 0 |
182 | ) == 0 | 190 | ); |
183 | ) { | 191 | if (!lease) { |
184 | bb_error_msg("lease pool is full - OFFER abandoned"); | 192 | bb_error_msg("no free IP addresses. OFFER abandoned"); |
185 | return -1; | 193 | return; |
186 | } | 194 | } |
187 | lease_time_sec = select_lease_time(oldpacket); | ||
188 | } else { | ||
189 | /* It is a static lease... use it */ | ||
190 | packet.yiaddr = static_lease_nip; | ||
191 | } | 195 | } |
192 | 196 | ||
197 | lease_time_sec = select_lease_time(oldpacket); | ||
193 | add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_sec)); | 198 | add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_sec)); |
194 | add_server_options(&packet); | 199 | add_server_options(&packet); |
195 | 200 | ||
196 | addr.s_addr = packet.yiaddr; | 201 | addr.s_addr = packet.yiaddr; |
197 | bb_info_msg("Sending OFFER of %s", inet_ntoa(addr)); | 202 | bb_info_msg("Sending OFFER of %s", inet_ntoa(addr)); |
198 | return send_packet(&packet, /*force_bcast:*/ 0); | 203 | /* send_packet emits error message itself if it detects failure */ |
204 | send_packet(&packet, /*force_bcast:*/ 0); | ||
199 | } | 205 | } |
200 | 206 | ||
201 | static int send_NAK(struct dhcp_packet *oldpacket) | 207 | static void send_NAK(struct dhcp_packet *oldpacket) |
202 | { | 208 | { |
203 | struct dhcp_packet packet; | 209 | struct dhcp_packet packet; |
204 | 210 | ||
205 | init_packet(&packet, oldpacket, DHCPNAK); | 211 | init_packet(&packet, oldpacket, DHCPNAK); |
206 | 212 | ||
207 | log1("Sending NAK"); | 213 | log1("Sending NAK"); |
208 | return send_packet(&packet, /*force_bcast:*/ 1); | 214 | send_packet(&packet, /*force_bcast:*/ 1); |
209 | } | 215 | } |
210 | 216 | ||
211 | static int send_ACK(struct dhcp_packet *oldpacket, uint32_t yiaddr) | 217 | static void send_ACK(struct dhcp_packet *oldpacket, uint32_t yiaddr) |
212 | { | 218 | { |
213 | struct dhcp_packet packet; | 219 | struct dhcp_packet packet; |
214 | uint32_t lease_time_sec; | 220 | uint32_t lease_time_sec; |
@@ -219,15 +225,13 @@ static int send_ACK(struct dhcp_packet *oldpacket, uint32_t yiaddr) | |||
219 | packet.yiaddr = yiaddr; | 225 | packet.yiaddr = yiaddr; |
220 | 226 | ||
221 | lease_time_sec = select_lease_time(oldpacket); | 227 | lease_time_sec = select_lease_time(oldpacket); |
222 | |||
223 | add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_sec)); | 228 | add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_sec)); |
229 | |||
224 | add_server_options(&packet); | 230 | add_server_options(&packet); |
225 | 231 | ||
226 | addr.s_addr = packet.yiaddr; | 232 | addr.s_addr = yiaddr; |
227 | bb_info_msg("Sending ACK to %s", inet_ntoa(addr)); | 233 | bb_info_msg("Sending ACK to %s", inet_ntoa(addr)); |
228 | 234 | send_packet(&packet, /*force_bcast:*/ 0); | |
229 | if (send_packet(&packet, /*force_bcast:*/ 0) < 0) | ||
230 | return -1; | ||
231 | 235 | ||
232 | p_host_name = (const char*) get_option(oldpacket, DHCP_HOST_NAME); | 236 | p_host_name = (const char*) get_option(oldpacket, DHCP_HOST_NAME); |
233 | add_lease(packet.chaddr, packet.yiaddr, | 237 | add_lease(packet.chaddr, packet.yiaddr, |
@@ -239,18 +243,21 @@ static int send_ACK(struct dhcp_packet *oldpacket, uint32_t yiaddr) | |||
239 | /* rewrite the file with leases at every new acceptance */ | 243 | /* rewrite the file with leases at every new acceptance */ |
240 | write_leases(); | 244 | write_leases(); |
241 | } | 245 | } |
242 | |||
243 | return 0; | ||
244 | } | 246 | } |
245 | 247 | ||
246 | static int send_inform(struct dhcp_packet *oldpacket) | 248 | static void send_inform(struct dhcp_packet *oldpacket) |
247 | { | 249 | { |
248 | struct dhcp_packet packet; | 250 | struct dhcp_packet packet; |
249 | 251 | ||
252 | /* "The server responds to a DHCPINFORM message by sending a DHCPACK | ||
253 | * message directly to the address given in the 'ciaddr' field | ||
254 | * of the DHCPINFORM message. The server MUST NOT send a lease | ||
255 | * expiration time to the client and SHOULD NOT fill in 'yiaddr'." | ||
256 | */ | ||
250 | init_packet(&packet, oldpacket, DHCPACK); | 257 | init_packet(&packet, oldpacket, DHCPACK); |
251 | add_server_options(&packet); | 258 | add_server_options(&packet); |
252 | 259 | ||
253 | return send_packet(&packet, /*force_bcast:*/ 0); | 260 | send_packet(&packet, /*force_bcast:*/ 0); |
254 | } | 261 | } |
255 | 262 | ||
256 | 263 | ||
@@ -352,6 +359,9 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) | |||
352 | while (1) { /* loop until universe collapses */ | 359 | while (1) { /* loop until universe collapses */ |
353 | int bytes; | 360 | int bytes; |
354 | struct timeval tv; | 361 | struct timeval tv; |
362 | uint8_t *server_id_opt; | ||
363 | uint8_t *requested_opt; | ||
364 | uint32_t requested_nip = requested_nip; /* for compiler */ | ||
355 | 365 | ||
356 | if (server_socket < 0) { | 366 | if (server_socket < 0) { |
357 | server_socket = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT, | 367 | server_socket = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT, |
@@ -404,124 +414,126 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) | |||
404 | } | 414 | } |
405 | continue; | 415 | continue; |
406 | } | 416 | } |
407 | |||
408 | if (packet.hlen != 6) { | 417 | if (packet.hlen != 6) { |
409 | bb_error_msg("MAC length != 6, ignoring packet"); | 418 | bb_error_msg("MAC length != 6, ignoring packet"); |
410 | continue; | 419 | continue; |
411 | } | 420 | } |
412 | 421 | if (packet.op != BOOTREQUEST) { | |
422 | bb_error_msg("not a REQUEST, ignoring packet"); | ||
423 | continue; | ||
424 | } | ||
413 | state = get_option(&packet, DHCP_MESSAGE_TYPE); | 425 | state = get_option(&packet, DHCP_MESSAGE_TYPE); |
414 | if (state == NULL) { | 426 | if (state == NULL || state[0] < DHCP_MINTYPE || state[0] > DHCP_MAXTYPE) { |
415 | bb_error_msg("no message type option, ignoring packet"); | 427 | bb_error_msg("no or bad message type option, ignoring packet"); |
416 | continue; | 428 | continue; |
417 | } | 429 | } |
418 | 430 | ||
419 | /* Look for a static lease */ | 431 | /* Look for a static/dynamic lease */ |
420 | static_lease_nip = get_static_nip_by_mac(server_config.static_leases, &packet.chaddr); | 432 | static_lease_nip = get_static_nip_by_mac(server_config.static_leases, &packet.chaddr); |
421 | if (static_lease_nip) { | 433 | if (static_lease_nip) { |
422 | bb_info_msg("Found static lease: %x", static_lease_nip); | 434 | bb_info_msg("Found static lease: %x", static_lease_nip); |
423 | |||
424 | memcpy(&fake_lease.lease_mac, &packet.chaddr, 6); | 435 | memcpy(&fake_lease.lease_mac, &packet.chaddr, 6); |
425 | fake_lease.lease_nip = static_lease_nip; | 436 | fake_lease.lease_nip = static_lease_nip; |
426 | fake_lease.expires = 0; | 437 | fake_lease.expires = 0; |
427 | |||
428 | lease = &fake_lease; | 438 | lease = &fake_lease; |
429 | } else { | 439 | } else { |
430 | lease = find_lease_by_mac(packet.chaddr); | 440 | lease = find_lease_by_mac(packet.chaddr); |
431 | } | 441 | } |
432 | 442 | ||
443 | /* Get REQUESTED_IP and SERVER_ID if present */ | ||
444 | server_id_opt = get_option(&packet, DHCP_SERVER_ID); | ||
445 | if (server_id_opt) { | ||
446 | uint32_t server_id_net; | ||
447 | move_from_unaligned32(server_id_net, server_id_opt); | ||
448 | if (server_id_net != server_config.server_nip) { | ||
449 | /* client talks to somebody else */ | ||
450 | log1("server ID doesn't match, ignoring"); | ||
451 | continue; | ||
452 | } | ||
453 | } | ||
454 | requested_opt = get_option(&packet, DHCP_REQUESTED_IP); | ||
455 | if (requested_opt) { | ||
456 | move_from_unaligned32(requested_nip, requested_opt); | ||
457 | } | ||
458 | |||
433 | switch (state[0]) { | 459 | switch (state[0]) { |
460 | |||
434 | case DHCPDISCOVER: | 461 | case DHCPDISCOVER: |
435 | log1("Received DISCOVER"); | 462 | log1("Received DISCOVER"); |
436 | 463 | ||
437 | if (send_offer(&packet, static_lease_nip, lease) < 0) { | 464 | send_offer(&packet, static_lease_nip, lease); |
438 | bb_error_msg("send OFFER failed"); | ||
439 | } | ||
440 | break; | 465 | break; |
441 | case DHCPREQUEST: { | ||
442 | uint8_t *server_id_opt, *requested_opt; | ||
443 | uint32_t server_id_net = server_id_net; /* for compiler */ | ||
444 | uint32_t requested_nip = requested_nip; /* for compiler */ | ||
445 | 466 | ||
467 | case DHCPREQUEST: | ||
446 | log1("Received REQUEST"); | 468 | log1("Received REQUEST"); |
447 | 469 | ||
448 | requested_opt = get_option(&packet, DHCP_REQUESTED_IP); | 470 | /* RFC 2131: "The REQUESTED_IP option MUST be set |
449 | server_id_opt = get_option(&packet, DHCP_SERVER_ID); | 471 | * to the value of 'yiaddr' in the DHCPOFFER message |
450 | if (requested_opt) | 472 | * from the server." */ |
451 | move_from_unaligned32(requested_nip, requested_opt); | 473 | if (!requested_opt) { |
452 | if (server_id_opt) | 474 | log1("no requested IP, ignoring"); |
453 | move_from_unaligned32(server_id_net, server_id_opt); | 475 | break; |
454 | 476 | } | |
455 | if (lease) { | 477 | if (lease && requested_nip == lease->lease_nip) { |
456 | if (server_id_opt) { | 478 | /* client requests IP which matches the lease. |
457 | /* SELECTING State */ | 479 | * ACK it, and bump lease expiration time. */ |
458 | if (server_id_net == server_config.server_nip | 480 | send_ACK(&packet, lease->lease_nip); |
459 | && requested_opt | 481 | break; |
460 | && requested_nip == lease->lease_nip | 482 | } |
461 | ) { | 483 | if (server_id_opt) { |
462 | send_ACK(&packet, lease->lease_nip); | 484 | /* client was talking specifically to us. |
463 | } | 485 | * "No, we don't have this IP for you". */ |
464 | } else if (requested_opt) { | 486 | send_NAK(&packet); |
465 | /* INIT-REBOOT State */ | ||
466 | if (lease->lease_nip == requested_nip) | ||
467 | send_ACK(&packet, lease->lease_nip); | ||
468 | else | ||
469 | send_NAK(&packet); | ||
470 | } else if (lease->lease_nip == packet.ciaddr) { | ||
471 | /* RENEWING or REBINDING State */ | ||
472 | send_ACK(&packet, lease->lease_nip); | ||
473 | } else { /* don't know what to do!!!! */ | ||
474 | send_NAK(&packet); | ||
475 | } | ||
476 | |||
477 | /* what to do if we have no record of the client */ | ||
478 | } else if (server_id_opt) { | ||
479 | /* SELECTING State */ | ||
480 | |||
481 | } else if (requested_opt) { | ||
482 | /* INIT-REBOOT State */ | ||
483 | lease = find_lease_by_nip(requested_nip); | ||
484 | if (lease) { | ||
485 | if (is_expired_lease(lease)) { | ||
486 | /* probably best if we drop this lease */ | ||
487 | memset(lease->lease_mac, 0, sizeof(lease->lease_mac)); | ||
488 | } else { | ||
489 | /* make some contention for this address */ | ||
490 | send_NAK(&packet); | ||
491 | } | ||
492 | } else { | ||
493 | uint32_t r = ntohl(requested_nip); | ||
494 | if (r < server_config.start_ip | ||
495 | || r > server_config.end_ip | ||
496 | ) { | ||
497 | send_NAK(&packet); | ||
498 | } | ||
499 | /* else remain silent */ | ||
500 | } | ||
501 | |||
502 | } else { | ||
503 | /* RENEWING or REBINDING State */ | ||
504 | } | 487 | } |
505 | break; | 488 | break; |
506 | } | 489 | |
507 | case DHCPDECLINE: | 490 | case DHCPDECLINE: |
491 | /* RFC 2131: | ||
492 | * "If the server receives a DHCPDECLINE message, | ||
493 | * the client has discovered through some other means | ||
494 | * that the suggested network address is already | ||
495 | * in use. The server MUST mark the network address | ||
496 | * as not available and SHOULD notify the local | ||
497 | * sysadmin of a possible configuration problem." | ||
498 | * | ||
499 | * SERVER_ID must be present, | ||
500 | * REQUESTED_IP must be present, | ||
501 | * chaddr must be filled in, | ||
502 | * ciaddr must be 0 (we do not check this) | ||
503 | */ | ||
508 | log1("Received DECLINE"); | 504 | log1("Received DECLINE"); |
509 | if (lease) { | 505 | if (server_id_opt |
506 | && requested_opt | ||
507 | && lease /* chaddr matches this lease */ | ||
508 | && requested_nip == lease->lease_nip | ||
509 | ) { | ||
510 | memset(lease->lease_mac, 0, sizeof(lease->lease_mac)); | 510 | memset(lease->lease_mac, 0, sizeof(lease->lease_mac)); |
511 | lease->expires = time(NULL) + server_config.decline_time; | 511 | lease->expires = time(NULL) + server_config.decline_time; |
512 | } | 512 | } |
513 | break; | 513 | break; |
514 | |||
514 | case DHCPRELEASE: | 515 | case DHCPRELEASE: |
516 | /* "Upon receipt of a DHCPRELEASE message, the server | ||
517 | * marks the network address as not allocated." | ||
518 | * | ||
519 | * SERVER_ID must be present, | ||
520 | * REQUESTED_IP must not be present (we do not check this), | ||
521 | * chaddr must be filled in, | ||
522 | * ciaddr must be filled in | ||
523 | */ | ||
515 | log1("Received RELEASE"); | 524 | log1("Received RELEASE"); |
516 | if (lease) | 525 | if (server_id_opt |
526 | && lease /* chaddr matches this lease */ | ||
527 | && packet.ciaddr == lease->lease_nip | ||
528 | ) { | ||
517 | lease->expires = time(NULL); | 529 | lease->expires = time(NULL); |
530 | } | ||
518 | break; | 531 | break; |
532 | |||
519 | case DHCPINFORM: | 533 | case DHCPINFORM: |
520 | log1("Received INFORM"); | 534 | log1("Received INFORM"); |
521 | send_inform(&packet); | 535 | send_inform(&packet); |
522 | break; | 536 | break; |
523 | default: | ||
524 | bb_info_msg("Unsupported DHCP message (%02x) - ignoring", state[0]); | ||
525 | } | 537 | } |
526 | } | 538 | } |
527 | ret0: | 539 | ret0: |
diff --git a/networking/udhcp/files.c b/networking/udhcp/files.c index 40cfe9fd2..62f4a388f 100644 --- a/networking/udhcp/files.c +++ b/networking/udhcp/files.c | |||
@@ -99,7 +99,7 @@ static void attach_option(struct option_set **opt_list, | |||
99 | log2("Attaching option %02x to list", option->code); | 99 | log2("Attaching option %02x to list", option->code); |
100 | 100 | ||
101 | #if ENABLE_FEATURE_UDHCP_RFC3397 | 101 | #if ENABLE_FEATURE_UDHCP_RFC3397 |
102 | if ((option->flags & TYPE_MASK) == OPTION_STR1035) | 102 | if ((option->flags & OPTION_TYPE_MASK) == OPTION_STR1035) |
103 | /* reuse buffer and length for RFC1035-formatted string */ | 103 | /* reuse buffer and length for RFC1035-formatted string */ |
104 | buffer = (char *)dname_enc(NULL, 0, buffer, &length); | 104 | buffer = (char *)dname_enc(NULL, 0, buffer, &length); |
105 | #endif | 105 | #endif |
@@ -118,7 +118,7 @@ static void attach_option(struct option_set **opt_list, | |||
118 | new->next = *curr; | 118 | new->next = *curr; |
119 | *curr = new; | 119 | *curr = new; |
120 | #if ENABLE_FEATURE_UDHCP_RFC3397 | 120 | #if ENABLE_FEATURE_UDHCP_RFC3397 |
121 | if ((option->flags & TYPE_MASK) == OPTION_STR1035 && buffer != NULL) | 121 | if ((option->flags & OPTION_TYPE_MASK) == OPTION_STR1035 && buffer != NULL) |
122 | free(buffer); | 122 | free(buffer); |
123 | #endif | 123 | #endif |
124 | return; | 124 | return; |
@@ -128,7 +128,7 @@ static void attach_option(struct option_set **opt_list, | |||
128 | log1("Attaching option %02x to existing member of list", option->code); | 128 | log1("Attaching option %02x to existing member of list", option->code); |
129 | if (option->flags & OPTION_LIST) { | 129 | if (option->flags & OPTION_LIST) { |
130 | #if ENABLE_FEATURE_UDHCP_RFC3397 | 130 | #if ENABLE_FEATURE_UDHCP_RFC3397 |
131 | if ((option->flags & TYPE_MASK) == OPTION_STR1035) | 131 | if ((option->flags & OPTION_TYPE_MASK) == OPTION_STR1035) |
132 | /* reuse buffer and length for RFC1035-formatted string */ | 132 | /* reuse buffer and length for RFC1035-formatted string */ |
133 | buffer = (char *)dname_enc(existing->data + 2, | 133 | buffer = (char *)dname_enc(existing->data + 2, |
134 | existing->data[OPT_LEN], buffer, &length); | 134 | existing->data[OPT_LEN], buffer, &length); |
@@ -136,7 +136,7 @@ static void attach_option(struct option_set **opt_list, | |||
136 | if (existing->data[OPT_LEN] + length <= 255) { | 136 | if (existing->data[OPT_LEN] + length <= 255) { |
137 | existing->data = xrealloc(existing->data, | 137 | existing->data = xrealloc(existing->data, |
138 | existing->data[OPT_LEN] + length + 3); | 138 | existing->data[OPT_LEN] + length + 3); |
139 | if ((option->flags & TYPE_MASK) == OPTION_STRING) { | 139 | if ((option->flags & OPTION_TYPE_MASK) == OPTION_STRING) { |
140 | /* ' ' can bring us to 256 - bad */ | 140 | /* ' ' can bring us to 256 - bad */ |
141 | if (existing->data[OPT_LEN] + length >= 255) | 141 | if (existing->data[OPT_LEN] + length >= 255) |
142 | return; | 142 | return; |
@@ -148,7 +148,7 @@ static void attach_option(struct option_set **opt_list, | |||
148 | existing->data[OPT_LEN] += length; | 148 | existing->data[OPT_LEN] += length; |
149 | } /* else, ignore the data, we could put this in a second option in the future */ | 149 | } /* else, ignore the data, we could put this in a second option in the future */ |
150 | #if ENABLE_FEATURE_UDHCP_RFC3397 | 150 | #if ENABLE_FEATURE_UDHCP_RFC3397 |
151 | if ((option->flags & TYPE_MASK) == OPTION_STR1035 && buffer != NULL) | 151 | if ((option->flags & OPTION_TYPE_MASK) == OPTION_STR1035 && buffer != NULL) |
152 | free(buffer); | 152 | free(buffer); |
153 | #endif | 153 | #endif |
154 | } /* else, ignore the new data */ | 154 | } /* else, ignore the new data */ |
@@ -182,10 +182,10 @@ static int FAST_FUNC read_opt(const char *const_line, void *arg) | |||
182 | do { | 182 | do { |
183 | val = strtok(NULL, ", \t"); | 183 | val = strtok(NULL, ", \t"); |
184 | if (!val) break; | 184 | if (!val) break; |
185 | length = dhcp_option_lengths[option->flags & TYPE_MASK]; | 185 | length = dhcp_option_lengths[option->flags & OPTION_TYPE_MASK]; |
186 | retval = 0; | 186 | retval = 0; |
187 | opt = buffer; /* new meaning for variable opt */ | 187 | opt = buffer; /* new meaning for variable opt */ |
188 | switch (option->flags & TYPE_MASK) { | 188 | switch (option->flags & OPTION_TYPE_MASK) { |
189 | case OPTION_IP: | 189 | case OPTION_IP: |
190 | retval = read_nip(val, buffer); | 190 | retval = read_nip(val, buffer); |
191 | break; | 191 | break; |
diff --git a/networking/udhcp/options.c b/networking/udhcp/options.c index 5bef985bc..29a264047 100644 --- a/networking/udhcp/options.c +++ b/networking/udhcp/options.c | |||
@@ -252,7 +252,7 @@ void FAST_FUNC add_simple_option(uint8_t *optionptr, uint8_t code, uint32_t data | |||
252 | uint8_t option[6], len; | 252 | uint8_t option[6], len; |
253 | 253 | ||
254 | option[OPT_CODE] = code; | 254 | option[OPT_CODE] = code; |
255 | len = dhcp_option_lengths[dh->flags & TYPE_MASK]; | 255 | len = dhcp_option_lengths[dh->flags & OPTION_TYPE_MASK]; |
256 | option[OPT_LEN] = len; | 256 | option[OPT_LEN] = len; |
257 | if (BB_BIG_ENDIAN) | 257 | if (BB_BIG_ENDIAN) |
258 | data <<= 8 * (4 - len); | 258 | data <<= 8 * (4 - len); |
diff --git a/networking/udhcp/options.h b/networking/udhcp/options.h index 05090f12e..3ca4dc42d 100644 --- a/networking/udhcp/options.h +++ b/networking/udhcp/options.h | |||
@@ -5,7 +5,6 @@ | |||
5 | 5 | ||
6 | PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN | 6 | PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN |
7 | 7 | ||
8 | #define TYPE_MASK 0x0F | ||
9 | 8 | ||
10 | enum { | 9 | enum { |
11 | OPTION_IP = 1, | 10 | OPTION_IP = 1, |
@@ -21,19 +20,13 @@ enum { | |||
21 | OPTION_U32, | 20 | OPTION_U32, |
22 | OPTION_S32, | 21 | OPTION_S32, |
23 | OPTION_STATIC_ROUTES, | 22 | OPTION_STATIC_ROUTES, |
24 | }; | ||
25 | |||
26 | /* Client requests this option by default */ | ||
27 | #define OPTION_REQ 0x10 | ||
28 | /* There can be a list of 1 or more of these */ | ||
29 | #define OPTION_LIST 0x20 | ||
30 | 23 | ||
31 | /*****************************************************************/ | 24 | OPTION_TYPE_MASK = 0x0f, |
32 | /* Do not modify below here unless you know what you are doing!! */ | 25 | /* Client requests this option by default */ |
33 | /*****************************************************************/ | 26 | OPTION_REQ = 0x10, |
34 | 27 | /* There can be a list of 1 or more of these */ | |
35 | /* DHCP protocol. See RFC 2131 */ | 28 | OPTION_LIST = 0x20, |
36 | #define DHCP_MAGIC 0x63825363 | 29 | }; |
37 | 30 | ||
38 | /* DHCP option codes (partial list). See RFC 2132 and | 31 | /* DHCP option codes (partial list). See RFC 2132 and |
39 | * http://www.iana.org/assignments/bootp-dhcp-parameters/ | 32 | * http://www.iana.org/assignments/bootp-dhcp-parameters/ |
@@ -81,7 +74,6 @@ enum { | |||
81 | //#define DHCP_WPAD 0xfc /* MSIE's Web Proxy Autodiscovery Protocol */ | 74 | //#define DHCP_WPAD 0xfc /* MSIE's Web Proxy Autodiscovery Protocol */ |
82 | #define DHCP_END 0xff | 75 | #define DHCP_END 0xff |
83 | 76 | ||
84 | |||
85 | /* Offsets in option byte sequence */ | 77 | /* Offsets in option byte sequence */ |
86 | #define OPT_CODE 0 | 78 | #define OPT_CODE 0 |
87 | #define OPT_LEN 1 | 79 | #define OPT_LEN 1 |
@@ -91,12 +83,7 @@ enum { | |||
91 | #define FILE_FIELD 1 | 83 | #define FILE_FIELD 1 |
92 | #define SNAME_FIELD 2 | 84 | #define SNAME_FIELD 2 |
93 | 85 | ||
94 | #define BOOTREQUEST 1 | 86 | /* DHCP_MESSAGE_TYPE values */ |
95 | #define BOOTREPLY 2 | ||
96 | |||
97 | #define ETH_10MB 1 | ||
98 | #define ETH_10MB_LEN 6 | ||
99 | |||
100 | #define DHCPDISCOVER 1 /* client -> server */ | 87 | #define DHCPDISCOVER 1 /* client -> server */ |
101 | #define DHCPOFFER 2 /* client <- server */ | 88 | #define DHCPOFFER 2 /* client <- server */ |
102 | #define DHCPREQUEST 3 /* client -> server */ | 89 | #define DHCPREQUEST 3 /* client -> server */ |
@@ -105,6 +92,9 @@ enum { | |||
105 | #define DHCPNAK 6 /* client <- server */ | 92 | #define DHCPNAK 6 /* client <- server */ |
106 | #define DHCPRELEASE 7 /* client -> server */ | 93 | #define DHCPRELEASE 7 /* client -> server */ |
107 | #define DHCPINFORM 8 /* client -> server */ | 94 | #define DHCPINFORM 8 /* client -> server */ |
95 | #define DHCP_MINTYPE DHCPDISCOVER | ||
96 | #define DHCP_MAXTYPE DHCPINFORM | ||
97 | |||
108 | 98 | ||
109 | struct dhcp_option { | 99 | struct dhcp_option { |
110 | uint8_t flags; | 100 | uint8_t flags; |
diff --git a/networking/udhcp/packet.c b/networking/udhcp/packet.c index 90410cbc0..84d83098c 100644 --- a/networking/udhcp/packet.c +++ b/networking/udhcp/packet.c | |||
@@ -21,7 +21,7 @@ | |||
21 | 21 | ||
22 | void FAST_FUNC udhcp_init_header(struct dhcp_packet *packet, char type) | 22 | void FAST_FUNC udhcp_init_header(struct dhcp_packet *packet, char type) |
23 | { | 23 | { |
24 | memset(packet, 0, sizeof(struct dhcp_packet)); | 24 | memset(packet, 0, sizeof(*packet)); |
25 | packet->op = BOOTREQUEST; /* if client to a server */ | 25 | packet->op = BOOTREQUEST; /* if client to a server */ |
26 | switch (type) { | 26 | switch (type) { |
27 | case DHCPOFFER: | 27 | case DHCPOFFER: |
@@ -29,10 +29,11 @@ void FAST_FUNC udhcp_init_header(struct dhcp_packet *packet, char type) | |||
29 | case DHCPNAK: | 29 | case DHCPNAK: |
30 | packet->op = BOOTREPLY; /* if server to client */ | 30 | packet->op = BOOTREPLY; /* if server to client */ |
31 | } | 31 | } |
32 | packet->htype = ETH_10MB; | 32 | packet->htype = 1; /* ethernet */ |
33 | packet->hlen = ETH_10MB_LEN; | 33 | packet->hlen = 6; |
34 | packet->cookie = htonl(DHCP_MAGIC); | 34 | packet->cookie = htonl(DHCP_MAGIC); |
35 | packet->options[0] = DHCP_END; | 35 | if (DHCP_END != 0) |
36 | packet->options[0] = DHCP_END; | ||
36 | add_simple_option(packet->options, DHCP_MESSAGE_TYPE, type); | 37 | add_simple_option(packet->options, DHCP_MESSAGE_TYPE, type); |
37 | } | 38 | } |
38 | 39 | ||
@@ -228,6 +229,7 @@ int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt, | |||
228 | msg = "sendto"; | 229 | msg = "sendto"; |
229 | ret_close: | 230 | ret_close: |
230 | close(fd); | 231 | close(fd); |
232 | /* FIXME: and if result >= 0 but != IP_UPD_DHCP_SIZE? */ | ||
231 | if (result < 0) { | 233 | if (result < 0) { |
232 | ret_msg: | 234 | ret_msg: |
233 | bb_perror_msg(msg, "PACKET"); | 235 | bb_perror_msg(msg, "PACKET"); |
@@ -280,6 +282,7 @@ int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt, | |||
280 | msg = "write"; | 282 | msg = "write"; |
281 | ret_close: | 283 | ret_close: |
282 | close(fd); | 284 | close(fd); |
285 | /* FIXME: and if result >= 0 but != DHCP_SIZE? */ | ||
283 | if (result < 0) { | 286 | if (result < 0) { |
284 | ret_msg: | 287 | ret_msg: |
285 | bb_perror_msg(msg, "UDP"); | 288 | bb_perror_msg(msg, "UDP"); |
diff --git a/networking/udhcp/script.c b/networking/udhcp/script.c index b4413fa16..400fd2b9b 100644 --- a/networking/udhcp/script.c +++ b/networking/udhcp/script.c | |||
@@ -64,7 +64,7 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_ | |||
64 | 64 | ||
65 | /* option points to OPT_DATA, need to go back and get OPT_LEN */ | 65 | /* option points to OPT_DATA, need to go back and get OPT_LEN */ |
66 | len = option[OPT_LEN - OPT_DATA]; | 66 | len = option[OPT_LEN - OPT_DATA]; |
67 | type = type_p->flags & TYPE_MASK; | 67 | type = type_p->flags & OPTION_TYPE_MASK; |
68 | optlen = dhcp_option_lengths[type]; | 68 | optlen = dhcp_option_lengths[type]; |
69 | upper_length = len_of_option_as_string[type] * (len / optlen); | 69 | upper_length = len_of_option_as_string[type] * (len / optlen); |
70 | 70 | ||