Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/networking/udhcp/packet.c
- Timestamp:
- Feb 25, 2011, 9:26:54 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/2.2.9/mindi-busybox/networking/udhcp/packet.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 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 */ 3 9 #include <netinet/in.h> 4 10 #if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined _NEWLIB_VERSION 5 # include <netpacket/packet.h>6 # include <net/ethernet.h>11 # include <netpacket/packet.h> 12 # include <net/ethernet.h> 7 13 #else 8 # include <asm/types.h>9 # include <linux/if_packet.h>10 # include <linux/if_ether.h>14 # include <asm/types.h> 15 # include <linux/if_packet.h> 16 # include <linux/if_ether.h> 11 17 #endif 12 18 13 19 #include "common.h" 14 20 #include "dhcpd.h" 15 #include "options.h" 16 17 18 void udhcp_init_header(struct dhcpMessage *packet, char type) 19 { 20 memset(packet, 0, sizeof(struct dhcpMessage)); 21 22 void FAST_FUNC udhcp_init_header(struct dhcp_packet *packet, char type) 23 { 24 memset(packet, 0, sizeof(*packet)); 25 packet->op = BOOTREQUEST; /* if client to a server */ 21 26 switch (type) { 22 case DHCPDISCOVER:23 case DHCPREQUEST:24 case DHCPRELEASE:25 case DHCPINFORM:26 packet->op = BOOTREQUEST;27 break;28 27 case DHCPOFFER: 29 28 case DHCPACK: 30 29 case DHCPNAK: 31 packet->op = BOOTREPLY; 32 } 33 packet->htype = ETH_10MB;34 packet->hlen = ETH_10MB_LEN;30 packet->op = BOOTREPLY; /* if server to client */ 31 } 32 packet->htype = 1; /* ethernet */ 33 packet->hlen = 6; 35 34 packet->cookie = htonl(DHCP_MAGIC); 36 packet->options[0] = DHCP_END; 37 add_simple_option(packet->options, DHCP_MESSAGE_TYPE, type); 38 } 39 40 41 /* read a packet from socket fd, return -1 on read error, -2 on packet error */ 42 int udhcp_get_packet(struct dhcpMessage *packet, int fd) 43 { 44 #if 0 45 static const char broken_vendors[][8] = { 46 "MSFT 98", 47 "" 48 }; 35 if (DHCP_END != 0) 36 packet->options[0] = DHCP_END; 37 udhcp_add_simple_option(packet, DHCP_MESSAGE_TYPE, type); 38 } 39 40 #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2 41 void FAST_FUNC udhcp_dump_packet(struct dhcp_packet *packet) 42 { 43 char buf[sizeof(packet->chaddr)*2 + 1]; 44 45 if (dhcp_verbose < 2) 46 return; 47 48 bb_info_msg( 49 //" op %x" 50 //" htype %x" 51 " hlen %x" 52 //" hops %x" 53 " xid %x" 54 //" secs %x" 55 //" flags %x" 56 " ciaddr %x" 57 " yiaddr %x" 58 " siaddr %x" 59 " giaddr %x" 60 //" chaddr %s" 61 //" sname %s" 62 //" file %s" 63 //" cookie %x" 64 //" options %s" 65 //, packet->op 66 //, packet->htype 67 , packet->hlen 68 //, packet->hops 69 , packet->xid 70 //, packet->secs 71 //, packet->flags 72 , packet->ciaddr 73 , packet->yiaddr 74 , packet->siaddr_nip 75 , packet->gateway_nip 76 //, packet->chaddr[16] 77 //, packet->sname[64] 78 //, packet->file[128] 79 //, packet->cookie 80 //, packet->options[] 81 ); 82 *bin2hex(buf, (void *) packet->chaddr, sizeof(packet->chaddr)) = '\0'; 83 bb_info_msg(" chaddr %s", buf); 84 } 49 85 #endif 86 87 /* Read a packet from socket fd, return -1 on read error, -2 on packet error */ 88 int FAST_FUNC udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd) 89 { 50 90 int bytes; 51 91 unsigned char *vendor; 52 92 53 93 memset(packet, 0, sizeof(*packet)); 54 bytes = read(fd, packet, sizeof(*packet));94 bytes = safe_read(fd, packet, sizeof(*packet)); 55 95 if (bytes < 0) { 56 DEBUG("cannot read on listening socket, ignoring");57 return -1;58 } 59 60 if ( ntohl(packet->cookie) != DHCP_MAGIC) {61 bb_ error_msg("received bogus message, ignoring");96 log1("Packet read error, ignoring"); 97 return bytes; /* returns -1 */ 98 } 99 100 if (packet->cookie != htonl(DHCP_MAGIC)) { 101 bb_info_msg("Packet with bad magic, ignoring"); 62 102 return -2; 63 103 } 64 DEBUG("Received a packet"); 104 log1("Received a packet"); 105 udhcp_dump_packet(packet); 65 106 66 107 if (packet->op == BOOTREQUEST) { 67 vendor = get_option(packet, DHCP_VENDOR);108 vendor = udhcp_get_option(packet, DHCP_VENDOR); 68 109 if (vendor) { 69 110 #if 0 111 static const char broken_vendors[][8] = { 112 "MSFT 98", 113 "" 114 }; 70 115 int i; 71 116 for (i = 0; broken_vendors[i][0]; i++) { 72 if (vendor[OPT_LEN - 2] == (uint8_t)strlen(broken_vendors[i])73 && !strncmp((char*)vendor, broken_vendors[i], vendor[OPT_LEN - 2])117 if (vendor[OPT_LEN - OPT_DATA] == (uint8_t)strlen(broken_vendors[i]) 118 && strncmp((char*)vendor, broken_vendors[i], vendor[OPT_LEN - OPT_DATA]) == 0 74 119 ) { 75 DEBUG("broken client (%s), forcing broadcast",120 log1("Broken client (%s), forcing broadcast replies", 76 121 broken_vendors[i]); 77 122 packet->flags |= htons(BROADCAST_FLAG); … … 79 124 } 80 125 #else 81 if (vendor[OPT_LEN - 2] == (uint8_t)(sizeof("MSFT 98")-1)126 if (vendor[OPT_LEN - OPT_DATA] == (uint8_t)(sizeof("MSFT 98")-1) 82 127 && memcmp(vendor, "MSFT 98", sizeof("MSFT 98")-1) == 0 83 128 ) { 84 DEBUG("broken client (%s), forcing broadcast", "MSFT 98");129 log1("Broken client (%s), forcing broadcast replies", "MSFT 98"); 85 130 packet->flags |= htons(BROADCAST_FLAG); 86 131 } … … 92 137 } 93 138 94 95 uint16_t udhcp_checksum(void *addr, int count) 139 uint16_t FAST_FUNC udhcp_checksum(void *addr, int count) 96 140 { 97 141 /* Compute Internet Checksum for "count" bytes 98 * 142 * beginning at location "addr". 99 143 */ 100 144 int32_t sum = 0; … … 112 156 * with little and big endian hosts */ 113 157 uint16_t tmp = 0; 114 *(uint8_t *) (&tmp) = * (uint8_t *)source;158 *(uint8_t*)&tmp = *(uint8_t*)source; 115 159 sum += tmp; 116 160 } … … 122 166 } 123 167 124 125 /* Construct a ip/udp header for a packet, and specify the source and dest hardware address */ 126 void BUG_sizeof_struct_udp_dhcp_packet_must_be_576(void); 127 int udhcp_raw_packet(struct dhcpMessage *payload, 128 uint32_t source_ip, int source_port, 129 uint32_t dest_ip, int dest_port, const uint8_t *dest_arp, int ifindex) 130 { 168 /* Construct a ip/udp header for a packet, send packet */ 169 int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt, 170 uint32_t source_nip, int source_port, 171 uint32_t dest_nip, int dest_port, const uint8_t *dest_arp, 172 int ifindex) 173 { 174 struct sockaddr_ll dest_sll; 175 struct ip_udp_dhcp_packet packet; 176 unsigned padding; 131 177 int fd; 132 int result; 133 struct sockaddr_ll dest; 134 struct udp_dhcp_packet packet; 178 int result = -1; 179 const char *msg; 135 180 136 181 fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP)); 137 182 if (fd < 0) { 138 bb_perror_msg("socket"); 139 return -1; 140 } 141 142 memset(&dest, 0, sizeof(dest)); 143 memset(&packet, 0, sizeof(packet)); 144 145 dest.sll_family = AF_PACKET; 146 dest.sll_protocol = htons(ETH_P_IP); 147 dest.sll_ifindex = ifindex; 148 dest.sll_halen = 6; 149 memcpy(dest.sll_addr, dest_arp, 6); 150 if (bind(fd, (struct sockaddr *)&dest, sizeof(struct sockaddr_ll)) < 0) { 151 bb_perror_msg("bind"); 152 close(fd); 153 return -1; 154 } 183 msg = "socket(%s)"; 184 goto ret_msg; 185 } 186 187 memset(&dest_sll, 0, sizeof(dest_sll)); 188 memset(&packet, 0, offsetof(struct ip_udp_dhcp_packet, data)); 189 packet.data = *dhcp_pkt; /* struct copy */ 190 191 dest_sll.sll_family = AF_PACKET; 192 dest_sll.sll_protocol = htons(ETH_P_IP); 193 dest_sll.sll_ifindex = ifindex; 194 dest_sll.sll_halen = 6; 195 memcpy(dest_sll.sll_addr, dest_arp, 6); 196 197 if (bind(fd, (struct sockaddr *)&dest_sll, sizeof(dest_sll)) < 0) { 198 msg = "bind(%s)"; 199 goto ret_close; 200 } 201 202 /* We were sending full-sized DHCP packets (zero padded), 203 * but some badly configured servers were seen dropping them. 204 * Apparently they drop all DHCP packets >576 *ethernet* octets big, 205 * whereas they may only drop packets >576 *IP* octets big 206 * (which for typical Ethernet II means 590 octets: 6+6+2 + 576). 207 * 208 * In order to work with those buggy servers, 209 * we truncate packets after end option byte. 210 */ 211 padding = DHCP_OPTIONS_BUFSIZE - 1 - udhcp_end_option(packet.data.options); 155 212 156 213 packet.ip.protocol = IPPROTO_UDP; 157 packet.ip.saddr = source_ ip;158 packet.ip.daddr = dest_ ip;214 packet.ip.saddr = source_nip; 215 packet.ip.daddr = dest_nip; 159 216 packet.udp.source = htons(source_port); 160 217 packet.udp.dest = htons(dest_port); 161 packet.udp.len = htons(sizeof(packet.udp) + sizeof(struct dhcpMessage)); /* cheat on the psuedo-header */ 218 /* size, excluding IP header: */ 219 packet.udp.len = htons(UDP_DHCP_SIZE - padding); 220 /* for UDP checksumming, ip.len is set to UDP packet len */ 162 221 packet.ip.tot_len = packet.udp.len; 163 memcpy(&(packet.data), payload, sizeof(struct dhcpMessage)); 164 packet.udp.check = udhcp_checksum(&packet, sizeof(struct udp_dhcp_packet)); 165 166 packet.ip.tot_len = htons(sizeof(struct udp_dhcp_packet)); 222 packet.udp.check = udhcp_checksum(&packet, IP_UDP_DHCP_SIZE - padding); 223 /* but for sending, it is set to IP packet len */ 224 packet.ip.tot_len = htons(IP_UDP_DHCP_SIZE - padding); 167 225 packet.ip.ihl = sizeof(packet.ip) >> 2; 168 226 packet.ip.version = IPVERSION; 169 227 packet.ip.ttl = IPDEFTTL; 170 packet.ip.check = udhcp_checksum(&(packet.ip), sizeof(packet.ip)); 171 172 if (sizeof(struct udp_dhcp_packet) != 576) 173 BUG_sizeof_struct_udp_dhcp_packet_must_be_576(); 174 175 result = sendto(fd, &packet, sizeof(struct udp_dhcp_packet), 0, 176 (struct sockaddr *) &dest, sizeof(dest)); 177 if (result <= 0) { 178 bb_perror_msg("sendto"); 179 } 228 packet.ip.check = udhcp_checksum(&packet.ip, sizeof(packet.ip)); 229 230 udhcp_dump_packet(dhcp_pkt); 231 result = sendto(fd, &packet, IP_UDP_DHCP_SIZE - padding, /*flags:*/ 0, 232 (struct sockaddr *) &dest_sll, sizeof(dest_sll)); 233 msg = "sendto"; 234 ret_close: 180 235 close(fd); 236 if (result < 0) { 237 ret_msg: 238 bb_perror_msg(msg, "PACKET"); 239 } 181 240 return result; 182 241 } 183 242 184 185 243 /* Let the kernel do all the work for packet generation */ 186 int udhcp_kernel_packet(struct dhcpMessage *payload, 187 uint32_t source_ip, int source_port, 188 uint32_t dest_ip, int dest_port) 189 { 190 int fd, result; 244 int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt, 245 uint32_t source_nip, int source_port, 246 uint32_t dest_nip, int dest_port) 247 { 191 248 struct sockaddr_in client; 249 unsigned padding; 250 int fd; 251 int result = -1; 252 const char *msg; 192 253 193 254 fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); 194 if (fd < 0) 195 return -1; 196 255 if (fd < 0) { 256 msg = "socket(%s)"; 257 goto ret_msg; 258 } 197 259 setsockopt_reuseaddr(fd); 198 260 … … 200 262 client.sin_family = AF_INET; 201 263 client.sin_port = htons(source_port); 202 client.sin_addr.s_addr = source_ip; 203 264 client.sin_addr.s_addr = source_nip; 204 265 if (bind(fd, (struct sockaddr *)&client, sizeof(client)) == -1) { 205 close(fd);206 return -1;266 msg = "bind(%s)"; 267 goto ret_close; 207 268 } 208 269 … … 210 271 client.sin_family = AF_INET; 211 272 client.sin_port = htons(dest_port); 212 client.sin_addr.s_addr = dest_ip; 213 214 if (connect(fd, (struct sockaddr *)&client, sizeof(struct sockaddr)) == -1) { 215 close(fd); 216 return -1; 217 } 218 219 result = write(fd, payload, sizeof(struct dhcpMessage)); 273 client.sin_addr.s_addr = dest_nip; 274 if (connect(fd, (struct sockaddr *)&client, sizeof(client)) == -1) { 275 msg = "connect"; 276 goto ret_close; 277 } 278 279 udhcp_dump_packet(dhcp_pkt); 280 281 padding = DHCP_OPTIONS_BUFSIZE - 1 - udhcp_end_option(dhcp_pkt->options); 282 result = safe_write(fd, dhcp_pkt, DHCP_SIZE - padding); 283 msg = "write"; 284 ret_close: 220 285 close(fd); 286 if (result < 0) { 287 ret_msg: 288 bb_perror_msg(msg, "UDP"); 289 } 221 290 return result; 222 291 }
Note:
See TracChangeset
for help on using the changeset viewer.