diff options
-rw-r--r-- | networking/udhcp/common.c | 4 | ||||
-rw-r--r-- | networking/udhcp/common.h | 14 | ||||
-rw-r--r-- | networking/udhcp/dhcpc.c | 39 | ||||
-rw-r--r-- | networking/udhcp/packet.c | 46 |
4 files changed, 54 insertions, 49 deletions
diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c index 7cda34a18..90a07ed09 100644 --- a/networking/udhcp/common.c +++ b/networking/udhcp/common.c | |||
@@ -176,7 +176,7 @@ unsigned FAST_FUNC udhcp_option_idx(const char *name) | |||
176 | } | 176 | } |
177 | } | 177 | } |
178 | 178 | ||
179 | /* get an option with bounds checking (warning, result is not aligned). */ | 179 | /* Get an option with bounds checking (warning, result is not aligned) */ |
180 | uint8_t* FAST_FUNC udhcp_get_option(struct dhcp_packet *packet, int code) | 180 | uint8_t* FAST_FUNC udhcp_get_option(struct dhcp_packet *packet, int code) |
181 | { | 181 | { |
182 | uint8_t *optionptr; | 182 | uint8_t *optionptr; |
@@ -240,7 +240,7 @@ uint8_t* FAST_FUNC udhcp_get_option(struct dhcp_packet *packet, int code) | |||
240 | return NULL; | 240 | return NULL; |
241 | } | 241 | } |
242 | 242 | ||
243 | /* return the position of the 'end' option (no bounds checking) */ | 243 | /* Return the position of the 'end' option (no bounds checking) */ |
244 | int FAST_FUNC udhcp_end_option(uint8_t *optionptr) | 244 | int FAST_FUNC udhcp_end_option(uint8_t *optionptr) |
245 | { | 245 | { |
246 | int i = 0; | 246 | int i = 0; |
diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h index c9dd0bb25..75b787a80 100644 --- a/networking/udhcp/common.h +++ b/networking/udhcp/common.h | |||
@@ -57,10 +57,20 @@ struct ip_udp_dhcp_packet { | |||
57 | struct dhcp_packet data; | 57 | struct dhcp_packet data; |
58 | } PACKED; | 58 | } PACKED; |
59 | 59 | ||
60 | struct udp_dhcp_packet { | ||
61 | struct udphdr udp; | ||
62 | struct dhcp_packet data; | ||
63 | } PACKED; | ||
64 | |||
65 | enum { | ||
66 | IP_UPD_DHCP_SIZE = sizeof(struct ip_udp_dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS, | ||
67 | UPD_DHCP_SIZE = sizeof(struct udp_dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS, | ||
68 | DHCP_SIZE = sizeof(struct dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS, | ||
69 | }; | ||
70 | |||
60 | /* Let's see whether compiler understood us right */ | 71 | /* Let's see whether compiler understood us right */ |
61 | struct BUG_bad_sizeof_struct_ip_udp_dhcp_packet { | 72 | struct BUG_bad_sizeof_struct_ip_udp_dhcp_packet { |
62 | char BUG_bad_sizeof_struct_ip_udp_dhcp_packet | 73 | char c[IP_UPD_DHCP_SIZE == 576 ? 1 : -1]; |
63 | [(sizeof(struct ip_udp_dhcp_packet) != 576 + CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS) ? -1 : 1]; | ||
64 | }; | 74 | }; |
65 | 75 | ||
66 | 76 | ||
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index 24ff82d2f..c2b21c695 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c | |||
@@ -229,37 +229,41 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_ | |||
229 | /* put all the parameters into the environment */ | 229 | /* put all the parameters into the environment */ |
230 | static char **fill_envp(struct dhcp_packet *packet) | 230 | static char **fill_envp(struct dhcp_packet *packet) |
231 | { | 231 | { |
232 | int num_options = 0; | 232 | int envc; |
233 | int i; | 233 | int i; |
234 | char **envp, **curr; | 234 | char **envp, **curr; |
235 | const char *opt_name; | 235 | const char *opt_name; |
236 | uint8_t *temp; | 236 | uint8_t *temp; |
237 | uint8_t over = 0; | 237 | uint8_t overload = 0; |
238 | 238 | ||
239 | /* We need 6 elements for: | ||
240 | * "interface=IFACE" | ||
241 | * "ip=N.N.N.N" from packet->yiaddr | ||
242 | * "siaddr=IP" from packet->siaddr_nip (unless 0) | ||
243 | * "boot_file=FILE" from packet->file (unless overloaded) | ||
244 | * "sname=SERVER_HOSTNAME" from packet->sname (unless overloaded) | ||
245 | * terminating NULL | ||
246 | */ | ||
247 | envc = 6; | ||
248 | /* +1 element for each option, +2 for subnet option: */ | ||
239 | if (packet) { | 249 | if (packet) { |
240 | for (i = 0; dhcp_optflags[i].code; i++) { | 250 | for (i = 0; dhcp_optflags[i].code; i++) { |
241 | if (udhcp_get_option(packet, dhcp_optflags[i].code)) { | 251 | if (udhcp_get_option(packet, dhcp_optflags[i].code)) { |
242 | num_options++; | ||
243 | if (dhcp_optflags[i].code == DHCP_SUBNET) | 252 | if (dhcp_optflags[i].code == DHCP_SUBNET) |
244 | num_options++; /* for mton */ | 253 | envc++; /* for mton */ |
254 | envc++; | ||
245 | } | 255 | } |
246 | } | 256 | } |
247 | if (packet->siaddr_nip) | ||
248 | num_options++; | ||
249 | temp = udhcp_get_option(packet, DHCP_OPTION_OVERLOAD); | 257 | temp = udhcp_get_option(packet, DHCP_OPTION_OVERLOAD); |
250 | if (temp) | 258 | if (temp) |
251 | over = *temp; | 259 | overload = *temp; |
252 | if (!(over & FILE_FIELD) && packet->file[0]) | ||
253 | num_options++; | ||
254 | if (!(over & SNAME_FIELD) && packet->sname[0]) | ||
255 | num_options++; | ||
256 | } | 260 | } |
261 | curr = envp = xzalloc(sizeof(char *) * envc); | ||
257 | 262 | ||
258 | curr = envp = xzalloc(sizeof(char *) * (num_options + 3)); | ||
259 | *curr = xasprintf("interface=%s", client_config.interface); | 263 | *curr = xasprintf("interface=%s", client_config.interface); |
260 | putenv(*curr++); | 264 | putenv(*curr++); |
261 | 265 | ||
262 | if (packet == NULL) | 266 | if (!packet) |
263 | return envp; | 267 | return envp; |
264 | 268 | ||
265 | *curr = xmalloc(sizeof("ip=255.255.255.255")); | 269 | *curr = xmalloc(sizeof("ip=255.255.255.255")); |
@@ -274,9 +278,8 @@ static char **fill_envp(struct dhcp_packet *packet) | |||
274 | goto next; | 278 | goto next; |
275 | *curr = xmalloc_optname_optval(temp, &dhcp_optflags[i], opt_name); | 279 | *curr = xmalloc_optname_optval(temp, &dhcp_optflags[i], opt_name); |
276 | putenv(*curr++); | 280 | putenv(*curr++); |
277 | |||
278 | /* Fill in a subnet bits option for things like /24 */ | ||
279 | if (dhcp_optflags[i].code == DHCP_SUBNET) { | 281 | if (dhcp_optflags[i].code == DHCP_SUBNET) { |
282 | /* Subnet option: make things like "$ip/$mask" possible */ | ||
280 | uint32_t subnet; | 283 | uint32_t subnet; |
281 | move_from_unaligned32(subnet, temp); | 284 | move_from_unaligned32(subnet, temp); |
282 | *curr = xasprintf("mask=%d", mton(subnet)); | 285 | *curr = xasprintf("mask=%d", mton(subnet)); |
@@ -291,12 +294,12 @@ static char **fill_envp(struct dhcp_packet *packet) | |||
291 | sprint_nip(*curr, "siaddr=", (uint8_t *) &packet->siaddr_nip); | 294 | sprint_nip(*curr, "siaddr=", (uint8_t *) &packet->siaddr_nip); |
292 | putenv(*curr++); | 295 | putenv(*curr++); |
293 | } | 296 | } |
294 | if (!(over & FILE_FIELD) && packet->file[0]) { | 297 | if (!(overload & FILE_FIELD) && packet->file[0]) { |
295 | /* watch out for invalid packets */ | 298 | /* watch out for invalid packets */ |
296 | *curr = xasprintf("boot_file=%."DHCP_PKT_FILE_LEN_STR"s", packet->file); | 299 | *curr = xasprintf("boot_file=%."DHCP_PKT_FILE_LEN_STR"s", packet->file); |
297 | putenv(*curr++); | 300 | putenv(*curr++); |
298 | } | 301 | } |
299 | if (!(over & SNAME_FIELD) && packet->sname[0]) { | 302 | if (!(overload & SNAME_FIELD) && packet->sname[0]) { |
300 | /* watch out for invalid packets */ | 303 | /* watch out for invalid packets */ |
301 | *curr = xasprintf("sname=%."DHCP_PKT_SNAME_LEN_STR"s", packet->sname); | 304 | *curr = xasprintf("sname=%."DHCP_PKT_SNAME_LEN_STR"s", packet->sname); |
302 | putenv(*curr++); | 305 | putenv(*curr++); |
diff --git a/networking/udhcp/packet.c b/networking/udhcp/packet.c index 1bfe12041..c01fb7d7c 100644 --- a/networking/udhcp/packet.c +++ b/networking/udhcp/packet.c | |||
@@ -167,44 +167,40 @@ uint16_t FAST_FUNC udhcp_checksum(void *addr, int count) | |||
167 | 167 | ||
168 | /* Construct a ip/udp header for a packet, send packet */ | 168 | /* Construct a ip/udp header for a packet, send packet */ |
169 | int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt, | 169 | int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt, |
170 | uint32_t source_ip, int source_port, | 170 | uint32_t source_nip, int source_port, |
171 | uint32_t dest_ip, int dest_port, const uint8_t *dest_arp, | 171 | uint32_t dest_nip, int dest_port, const uint8_t *dest_arp, |
172 | int ifindex) | 172 | int ifindex) |
173 | { | 173 | { |
174 | struct sockaddr_ll dest; | 174 | struct sockaddr_ll dest_sll; |
175 | struct ip_udp_dhcp_packet packet; | 175 | struct ip_udp_dhcp_packet packet; |
176 | int fd; | 176 | int fd; |
177 | int result = -1; | 177 | int result = -1; |
178 | const char *msg; | 178 | const char *msg; |
179 | 179 | ||
180 | enum { | ||
181 | IP_UPD_DHCP_SIZE = sizeof(struct ip_udp_dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS, | ||
182 | UPD_DHCP_SIZE = IP_UPD_DHCP_SIZE - offsetof(struct ip_udp_dhcp_packet, udp), | ||
183 | }; | ||
184 | |||
185 | fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP)); | 180 | fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP)); |
186 | if (fd < 0) { | 181 | if (fd < 0) { |
187 | msg = "socket(%s)"; | 182 | msg = "socket(%s)"; |
188 | goto ret_msg; | 183 | goto ret_msg; |
189 | } | 184 | } |
190 | 185 | ||
191 | memset(&dest, 0, sizeof(dest)); | 186 | memset(&dest_sll, 0, sizeof(dest_sll)); |
192 | memset(&packet, 0, sizeof(packet)); | 187 | memset(&packet, 0, offsetof(struct ip_udp_dhcp_packet, data)); |
193 | packet.data = *dhcp_pkt; /* struct copy */ | 188 | packet.data = *dhcp_pkt; /* struct copy */ |
194 | 189 | ||
195 | dest.sll_family = AF_PACKET; | 190 | dest_sll.sll_family = AF_PACKET; |
196 | dest.sll_protocol = htons(ETH_P_IP); | 191 | dest_sll.sll_protocol = htons(ETH_P_IP); |
197 | dest.sll_ifindex = ifindex; | 192 | dest_sll.sll_ifindex = ifindex; |
198 | dest.sll_halen = 6; | 193 | dest_sll.sll_halen = 6; |
199 | memcpy(dest.sll_addr, dest_arp, 6); | 194 | memcpy(dest_sll.sll_addr, dest_arp, 6); |
200 | if (bind(fd, (struct sockaddr *)&dest, sizeof(dest)) < 0) { | 195 | |
196 | if (bind(fd, (struct sockaddr *)&dest_sll, sizeof(dest_sll)) < 0) { | ||
201 | msg = "bind(%s)"; | 197 | msg = "bind(%s)"; |
202 | goto ret_close; | 198 | goto ret_close; |
203 | } | 199 | } |
204 | 200 | ||
205 | packet.ip.protocol = IPPROTO_UDP; | 201 | packet.ip.protocol = IPPROTO_UDP; |
206 | packet.ip.saddr = source_ip; | 202 | packet.ip.saddr = source_nip; |
207 | packet.ip.daddr = dest_ip; | 203 | packet.ip.daddr = dest_nip; |
208 | packet.udp.source = htons(source_port); | 204 | packet.udp.source = htons(source_port); |
209 | packet.udp.dest = htons(dest_port); | 205 | packet.udp.dest = htons(dest_port); |
210 | /* size, excluding IP header: */ | 206 | /* size, excluding IP header: */ |
@@ -225,7 +221,7 @@ int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt, | |||
225 | */ | 221 | */ |
226 | udhcp_dump_packet(dhcp_pkt); | 222 | udhcp_dump_packet(dhcp_pkt); |
227 | result = sendto(fd, &packet, IP_UPD_DHCP_SIZE, 0, | 223 | result = sendto(fd, &packet, IP_UPD_DHCP_SIZE, 0, |
228 | (struct sockaddr *) &dest, sizeof(dest)); | 224 | (struct sockaddr *) &dest_sll, sizeof(dest_sll)); |
229 | msg = "sendto"; | 225 | msg = "sendto"; |
230 | ret_close: | 226 | ret_close: |
231 | close(fd); | 227 | close(fd); |
@@ -239,18 +235,14 @@ int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt, | |||
239 | 235 | ||
240 | /* Let the kernel do all the work for packet generation */ | 236 | /* Let the kernel do all the work for packet generation */ |
241 | int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt, | 237 | int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt, |
242 | uint32_t source_ip, int source_port, | 238 | uint32_t source_nip, int source_port, |
243 | uint32_t dest_ip, int dest_port) | 239 | uint32_t dest_nip, int dest_port) |
244 | { | 240 | { |
245 | struct sockaddr_in client; | 241 | struct sockaddr_in client; |
246 | int fd; | 242 | int fd; |
247 | int result = -1; | 243 | int result = -1; |
248 | const char *msg; | 244 | const char *msg; |
249 | 245 | ||
250 | enum { | ||
251 | DHCP_SIZE = sizeof(struct dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS, | ||
252 | }; | ||
253 | |||
254 | fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); | 246 | fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); |
255 | if (fd < 0) { | 247 | if (fd < 0) { |
256 | msg = "socket(%s)"; | 248 | msg = "socket(%s)"; |
@@ -261,7 +253,7 @@ int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt, | |||
261 | memset(&client, 0, sizeof(client)); | 253 | memset(&client, 0, sizeof(client)); |
262 | client.sin_family = AF_INET; | 254 | client.sin_family = AF_INET; |
263 | client.sin_port = htons(source_port); | 255 | client.sin_port = htons(source_port); |
264 | client.sin_addr.s_addr = source_ip; | 256 | client.sin_addr.s_addr = source_nip; |
265 | if (bind(fd, (struct sockaddr *)&client, sizeof(client)) == -1) { | 257 | if (bind(fd, (struct sockaddr *)&client, sizeof(client)) == -1) { |
266 | msg = "bind(%s)"; | 258 | msg = "bind(%s)"; |
267 | goto ret_close; | 259 | goto ret_close; |
@@ -270,7 +262,7 @@ int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt, | |||
270 | memset(&client, 0, sizeof(client)); | 262 | memset(&client, 0, sizeof(client)); |
271 | client.sin_family = AF_INET; | 263 | client.sin_family = AF_INET; |
272 | client.sin_port = htons(dest_port); | 264 | client.sin_port = htons(dest_port); |
273 | client.sin_addr.s_addr = dest_ip; | 265 | client.sin_addr.s_addr = dest_nip; |
274 | if (connect(fd, (struct sockaddr *)&client, sizeof(client)) == -1) { | 266 | if (connect(fd, (struct sockaddr *)&client, sizeof(client)) == -1) { |
275 | msg = "connect"; | 267 | msg = "connect"; |
276 | goto ret_close; | 268 | goto ret_close; |