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) } } -/* get an option with bounds checking (warning, result is not aligned). */ +/* Get an option with bounds checking (warning, result is not aligned) */ uint8_t* FAST_FUNC udhcp_get_option(struct dhcp_packet *packet, int code) { uint8_t *optionptr; @@ -240,7 +240,7 @@ uint8_t* FAST_FUNC udhcp_get_option(struct dhcp_packet *packet, int code) return NULL; } -/* return the position of the 'end' option (no bounds checking) */ +/* Return the position of the 'end' option (no bounds checking) */ int FAST_FUNC udhcp_end_option(uint8_t *optionptr) { 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 { struct dhcp_packet data; } PACKED; +struct udp_dhcp_packet { + struct udphdr udp; + struct dhcp_packet data; +} PACKED; + +enum { + IP_UPD_DHCP_SIZE = sizeof(struct ip_udp_dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS, + UPD_DHCP_SIZE = sizeof(struct udp_dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS, + DHCP_SIZE = sizeof(struct dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS, +}; + /* Let's see whether compiler understood us right */ struct BUG_bad_sizeof_struct_ip_udp_dhcp_packet { - char BUG_bad_sizeof_struct_ip_udp_dhcp_packet - [(sizeof(struct ip_udp_dhcp_packet) != 576 + CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS) ? -1 : 1]; + char c[IP_UPD_DHCP_SIZE == 576 ? 1 : -1]; }; 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_ /* put all the parameters into the environment */ static char **fill_envp(struct dhcp_packet *packet) { - int num_options = 0; + int envc; int i; char **envp, **curr; const char *opt_name; uint8_t *temp; - uint8_t over = 0; + uint8_t overload = 0; + /* We need 6 elements for: + * "interface=IFACE" + * "ip=N.N.N.N" from packet->yiaddr + * "siaddr=IP" from packet->siaddr_nip (unless 0) + * "boot_file=FILE" from packet->file (unless overloaded) + * "sname=SERVER_HOSTNAME" from packet->sname (unless overloaded) + * terminating NULL + */ + envc = 6; + /* +1 element for each option, +2 for subnet option: */ if (packet) { for (i = 0; dhcp_optflags[i].code; i++) { if (udhcp_get_option(packet, dhcp_optflags[i].code)) { - num_options++; if (dhcp_optflags[i].code == DHCP_SUBNET) - num_options++; /* for mton */ + envc++; /* for mton */ + envc++; } } - if (packet->siaddr_nip) - num_options++; temp = udhcp_get_option(packet, DHCP_OPTION_OVERLOAD); if (temp) - over = *temp; - if (!(over & FILE_FIELD) && packet->file[0]) - num_options++; - if (!(over & SNAME_FIELD) && packet->sname[0]) - num_options++; + overload = *temp; } + curr = envp = xzalloc(sizeof(char *) * envc); - curr = envp = xzalloc(sizeof(char *) * (num_options + 3)); *curr = xasprintf("interface=%s", client_config.interface); putenv(*curr++); - if (packet == NULL) + if (!packet) return envp; *curr = xmalloc(sizeof("ip=255.255.255.255")); @@ -274,9 +278,8 @@ static char **fill_envp(struct dhcp_packet *packet) goto next; *curr = xmalloc_optname_optval(temp, &dhcp_optflags[i], opt_name); putenv(*curr++); - - /* Fill in a subnet bits option for things like /24 */ if (dhcp_optflags[i].code == DHCP_SUBNET) { + /* Subnet option: make things like "$ip/$mask" possible */ uint32_t subnet; move_from_unaligned32(subnet, temp); *curr = xasprintf("mask=%d", mton(subnet)); @@ -291,12 +294,12 @@ static char **fill_envp(struct dhcp_packet *packet) sprint_nip(*curr, "siaddr=", (uint8_t *) &packet->siaddr_nip); putenv(*curr++); } - if (!(over & FILE_FIELD) && packet->file[0]) { + if (!(overload & FILE_FIELD) && packet->file[0]) { /* watch out for invalid packets */ *curr = xasprintf("boot_file=%."DHCP_PKT_FILE_LEN_STR"s", packet->file); putenv(*curr++); } - if (!(over & SNAME_FIELD) && packet->sname[0]) { + if (!(overload & SNAME_FIELD) && packet->sname[0]) { /* watch out for invalid packets */ *curr = xasprintf("sname=%."DHCP_PKT_SNAME_LEN_STR"s", packet->sname); 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) /* Construct a ip/udp header for a packet, send packet */ int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt, - uint32_t source_ip, int source_port, - uint32_t dest_ip, int dest_port, const uint8_t *dest_arp, + uint32_t source_nip, int source_port, + uint32_t dest_nip, int dest_port, const uint8_t *dest_arp, int ifindex) { - struct sockaddr_ll dest; + struct sockaddr_ll dest_sll; struct ip_udp_dhcp_packet packet; int fd; int result = -1; const char *msg; - enum { - IP_UPD_DHCP_SIZE = sizeof(struct ip_udp_dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS, - UPD_DHCP_SIZE = IP_UPD_DHCP_SIZE - offsetof(struct ip_udp_dhcp_packet, udp), - }; - fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP)); if (fd < 0) { msg = "socket(%s)"; goto ret_msg; } - memset(&dest, 0, sizeof(dest)); - memset(&packet, 0, sizeof(packet)); + memset(&dest_sll, 0, sizeof(dest_sll)); + memset(&packet, 0, offsetof(struct ip_udp_dhcp_packet, data)); packet.data = *dhcp_pkt; /* struct copy */ - dest.sll_family = AF_PACKET; - dest.sll_protocol = htons(ETH_P_IP); - dest.sll_ifindex = ifindex; - dest.sll_halen = 6; - memcpy(dest.sll_addr, dest_arp, 6); - if (bind(fd, (struct sockaddr *)&dest, sizeof(dest)) < 0) { + dest_sll.sll_family = AF_PACKET; + dest_sll.sll_protocol = htons(ETH_P_IP); + dest_sll.sll_ifindex = ifindex; + dest_sll.sll_halen = 6; + memcpy(dest_sll.sll_addr, dest_arp, 6); + + if (bind(fd, (struct sockaddr *)&dest_sll, sizeof(dest_sll)) < 0) { msg = "bind(%s)"; goto ret_close; } packet.ip.protocol = IPPROTO_UDP; - packet.ip.saddr = source_ip; - packet.ip.daddr = dest_ip; + packet.ip.saddr = source_nip; + packet.ip.daddr = dest_nip; packet.udp.source = htons(source_port); packet.udp.dest = htons(dest_port); /* size, excluding IP header: */ @@ -225,7 +221,7 @@ int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt, */ udhcp_dump_packet(dhcp_pkt); result = sendto(fd, &packet, IP_UPD_DHCP_SIZE, 0, - (struct sockaddr *) &dest, sizeof(dest)); + (struct sockaddr *) &dest_sll, sizeof(dest_sll)); msg = "sendto"; ret_close: close(fd); @@ -239,18 +235,14 @@ int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt, /* Let the kernel do all the work for packet generation */ int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt, - uint32_t source_ip, int source_port, - uint32_t dest_ip, int dest_port) + uint32_t source_nip, int source_port, + uint32_t dest_nip, int dest_port) { struct sockaddr_in client; int fd; int result = -1; const char *msg; - enum { - DHCP_SIZE = sizeof(struct dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS, - }; - fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); if (fd < 0) { msg = "socket(%s)"; @@ -261,7 +253,7 @@ int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt, memset(&client, 0, sizeof(client)); client.sin_family = AF_INET; client.sin_port = htons(source_port); - client.sin_addr.s_addr = source_ip; + client.sin_addr.s_addr = source_nip; if (bind(fd, (struct sockaddr *)&client, sizeof(client)) == -1) { msg = "bind(%s)"; goto ret_close; @@ -270,7 +262,7 @@ int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt, memset(&client, 0, sizeof(client)); client.sin_family = AF_INET; client.sin_port = htons(dest_port); - client.sin_addr.s_addr = dest_ip; + client.sin_addr.s_addr = dest_nip; if (connect(fd, (struct sockaddr *)&client, sizeof(client)) == -1) { msg = "connect"; goto ret_close;