1/* vi: set sw=4 ts=4: */ 2/* 3 * Packet ops 4 * 5 * Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001 6 * 7 * Licensed under GPLv2, see file LICENSE in this source tree. 8 */ 9#include "common.h" 10#include "dhcpd.h" 11#include <netinet/in.h> 12#include <netinet/if_ether.h> 13#include <netpacket/packet.h> 14 15void FAST_FUNC udhcp_init_header(struct dhcp_packet *packet, char type) 16{ 17 memset(packet, 0, sizeof(*packet)); 18 packet->op = BOOTREQUEST; /* if client to a server */ 19 switch (type) { 20 case DHCPOFFER: 21 case DHCPACK: 22 case DHCPNAK: 23 packet->op = BOOTREPLY; /* if server to client */ 24 } 25 packet->htype = 1; /* ethernet */ 26 packet->hlen = 6; 27 packet->cookie = htonl(DHCP_MAGIC); 28 if (DHCP_END != 0) 29 packet->options[0] = DHCP_END; 30 udhcp_add_simple_option(packet, DHCP_MESSAGE_TYPE, type); 31} 32 33#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2 34void FAST_FUNC udhcp_dump_packet(struct dhcp_packet *packet) 35{ 36 char buf[sizeof(packet->chaddr)*2 + 1]; 37 38 if (dhcp_verbose < 2) 39 return; 40 41 bb_info_msg( 42 //" op %x" 43 //" htype %x" 44 " hlen %x" 45 //" hops %x" 46 " xid %x" 47 //" secs %x" 48 //" flags %x" 49 " ciaddr %x" 50 " yiaddr %x" 51 " siaddr %x" 52 " giaddr %x" 53 //" chaddr %s" 54 //" sname %s" 55 //" file %s" 56 //" cookie %x" 57 //" options %s" 58 //, packet->op 59 //, packet->htype 60 , packet->hlen 61 //, packet->hops 62 , packet->xid 63 //, packet->secs 64 //, packet->flags 65 , packet->ciaddr 66 , packet->yiaddr 67 , packet->siaddr_nip 68 , packet->gateway_nip 69 //, packet->chaddr[16] 70 //, packet->sname[64] 71 //, packet->file[128] 72 //, packet->cookie 73 //, packet->options[] 74 ); 75 *bin2hex(buf, (void *) packet->chaddr, sizeof(packet->chaddr)) = '\0'; 76 bb_info_msg(" chaddr %s", buf); 77} 78#endif 79 80/* Read a packet from socket fd, return -1 on read error, -2 on packet error */ 81int FAST_FUNC udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd) 82{ 83 int bytes; 84 85 memset(packet, 0, sizeof(*packet)); 86 bytes = safe_read(fd, packet, sizeof(*packet)); 87 if (bytes < 0) { 88 log1("Packet read error, ignoring"); 89 return bytes; /* returns -1 */ 90 } 91 92 if (bytes < offsetof(struct dhcp_packet, options) 93 || packet->cookie != htonl(DHCP_MAGIC) 94 ) { 95 bb_info_msg("Packet with bad magic, ignoring"); 96 return -2; 97 } 98 log1("Received a packet"); 99 udhcp_dump_packet(packet); 100 101 return bytes; 102} 103 104/* Construct a ip/udp header for a packet, send packet */ 105int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt, 106 uint32_t source_nip, int source_port, 107 uint32_t dest_nip, int dest_port, const uint8_t *dest_arp, 108 int ifindex) 109{ 110 struct sockaddr_ll dest_sll; 111 struct ip_udp_dhcp_packet packet; 112 unsigned padding; 113 int fd; 114 int result = -1; 115 const char *msg; 116 117 fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP)); 118 if (fd < 0) { 119 msg = "socket(%s)"; 120 goto ret_msg; 121 } 122 123 memset(&dest_sll, 0, sizeof(dest_sll)); 124 memset(&packet, 0, offsetof(struct ip_udp_dhcp_packet, data)); 125 packet.data = *dhcp_pkt; /* struct copy */ 126 127 dest_sll.sll_family = AF_PACKET; 128 dest_sll.sll_protocol = htons(ETH_P_IP); 129 dest_sll.sll_ifindex = ifindex; 130 dest_sll.sll_halen = 6; 131 memcpy(dest_sll.sll_addr, dest_arp, 6); 132 133 if (bind(fd, (struct sockaddr *)&dest_sll, sizeof(dest_sll)) < 0) { 134 msg = "bind(%s)"; 135 goto ret_close; 136 } 137 138 /* We were sending full-sized DHCP packets (zero padded), 139 * but some badly configured servers were seen dropping them. 140 * Apparently they drop all DHCP packets >576 *ethernet* octets big, 141 * whereas they may only drop packets >576 *IP* octets big 142 * (which for typical Ethernet II means 590 octets: 6+6+2 + 576). 143 * 144 * In order to work with those buggy servers, 145 * we truncate packets after end option byte. 146 * 147 * However, RFC 1542 says "The IP Total Length and UDP Length 148 * must be large enough to contain the minimal BOOTP header of 300 octets". 149 * Thus, we retain enough padding to not go below 300 BOOTP bytes. 150 * Some devices have filters which drop DHCP packets shorter than that. 151 */ 152 padding = DHCP_OPTIONS_BUFSIZE - 1 - udhcp_end_option(packet.data.options); 153 if (padding > DHCP_SIZE - 300) 154 padding = DHCP_SIZE - 300; 155 156 packet.ip.protocol = IPPROTO_UDP; 157 packet.ip.saddr = source_nip; 158 packet.ip.daddr = dest_nip; 159 packet.udp.source = htons(source_port); 160 packet.udp.dest = htons(dest_port); 161 /* size, excluding IP header: */ 162 packet.udp.len = htons(UDP_DHCP_SIZE - padding); 163 /* for UDP checksumming, ip.len is set to UDP packet len */ 164 packet.ip.tot_len = packet.udp.len; 165 packet.udp.check = inet_cksum((uint16_t *)&packet, 166 IP_UDP_DHCP_SIZE - padding); 167 /* but for sending, it is set to IP packet len */ 168 packet.ip.tot_len = htons(IP_UDP_DHCP_SIZE - padding); 169 packet.ip.ihl = sizeof(packet.ip) >> 2; 170 packet.ip.version = IPVERSION; 171 packet.ip.ttl = IPDEFTTL; 172 packet.ip.check = inet_cksum((uint16_t *)&packet.ip, sizeof(packet.ip)); 173 174 udhcp_dump_packet(dhcp_pkt); 175 result = sendto(fd, &packet, IP_UDP_DHCP_SIZE - padding, /*flags:*/ 0, 176 (struct sockaddr *) &dest_sll, sizeof(dest_sll)); 177 msg = "sendto"; 178 ret_close: 179 close(fd); 180 if (result < 0) { 181 ret_msg: 182 bb_perror_msg(msg, "PACKET"); 183 } 184 return result; 185} 186 187/* Let the kernel do all the work for packet generation */ 188int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt, 189 uint32_t source_nip, int source_port, 190 uint32_t dest_nip, int dest_port) 191{ 192 struct sockaddr_in sa; 193 unsigned padding; 194 int fd; 195 int result = -1; 196 const char *msg; 197 198 fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); 199 if (fd < 0) { 200 msg = "socket(%s)"; 201 goto ret_msg; 202 } 203 setsockopt_reuseaddr(fd); 204 205 memset(&sa, 0, sizeof(sa)); 206 sa.sin_family = AF_INET; 207 sa.sin_port = htons(source_port); 208 sa.sin_addr.s_addr = source_nip; 209 if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) { 210 msg = "bind(%s)"; 211 goto ret_close; 212 } 213 214 memset(&sa, 0, sizeof(sa)); 215 sa.sin_family = AF_INET; 216 sa.sin_port = htons(dest_port); 217 sa.sin_addr.s_addr = dest_nip; 218 if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) { 219 msg = "connect"; 220 goto ret_close; 221 } 222 223 udhcp_dump_packet(dhcp_pkt); 224 padding = DHCP_OPTIONS_BUFSIZE - 1 - udhcp_end_option(dhcp_pkt->options); 225 if (padding > DHCP_SIZE - 300) 226 padding = DHCP_SIZE - 300; 227 result = safe_write(fd, dhcp_pkt, DHCP_SIZE - padding); 228 msg = "write"; 229 ret_close: 230 close(fd); 231 if (result < 0) { 232 ret_msg: 233 bb_perror_msg(msg, "UDP"); 234 } 235 return result; 236} 237