1 1.1 pooka /* 2 1.1 pooka * dhcpcd - DHCP client daemon 3 1.1 pooka * Copyright (c) 2006-2010 Roy Marples <roy (at) marples.name> 4 1.1 pooka * All rights reserved 5 1.1 pooka 6 1.1 pooka * Redistribution and use in source and binary forms, with or without 7 1.1 pooka * modification, are permitted provided that the following conditions 8 1.1 pooka * are met: 9 1.1 pooka * 1. Redistributions of source code must retain the above copyright 10 1.1 pooka * notice, this list of conditions and the following disclaimer. 11 1.1 pooka * 2. Redistributions in binary form must reproduce the above copyright 12 1.1 pooka * notice, this list of conditions and the following disclaimer in the 13 1.1 pooka * documentation and/or other materials provided with the distribution. 14 1.1 pooka * 15 1.1 pooka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 1.1 pooka * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 1.1 pooka * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 1.1 pooka * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 1.1 pooka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 1.1 pooka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 1.1 pooka * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 1.1 pooka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 1.1 pooka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 1.1 pooka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 1.1 pooka * SUCH DAMAGE. 26 1.1 pooka */ 27 1.1 pooka 28 1.1 pooka #include <sys/types.h> 29 1.1 pooka #include <sys/ioctl.h> 30 1.1 pooka #include <sys/param.h> 31 1.1 pooka #include <sys/socket.h> 32 1.1 pooka #include <sys/time.h> 33 1.1 pooka 34 1.1 pooka #include <arpa/inet.h> 35 1.1 pooka #include <net/if.h> 36 1.1 pooka #include <net/if_arp.h> 37 1.1 pooka #ifdef AF_LINK 38 1.1 pooka # include <net/if_dl.h> 39 1.1 pooka # include <net/if_types.h> 40 1.1 pooka #endif 41 1.1 pooka #include <netinet/in_systm.h> 42 1.1 pooka #include <netinet/in.h> 43 1.1 pooka #include <netinet/ip.h> 44 1.1 pooka #define __FAVOR_BSD /* Nasty glibc hack so we can use BSD semantics for UDP */ 45 1.1 pooka #include <netinet/udp.h> 46 1.1 pooka #undef __FAVOR_BSD 47 1.1 pooka #ifdef AF_PACKET 48 1.1 pooka # include <netpacket/packet.h> 49 1.1 pooka #endif 50 1.1 pooka #ifdef SIOCGIFMEDIA 51 1.1 pooka # include <net/if_media.h> 52 1.1 pooka #endif 53 1.1 pooka 54 1.1 pooka #include <ctype.h> 55 1.1 pooka #include <errno.h> 56 1.1 pooka #include <ifaddrs.h> 57 1.1 pooka #include <fnmatch.h> 58 1.1 pooka #include <stddef.h> 59 1.1 pooka #include <stdio.h> 60 1.1 pooka #include <stdlib.h> 61 1.1 pooka #include <string.h> 62 1.1 pooka #include <unistd.h> 63 1.1 pooka 64 1.1 pooka #include "common.h" 65 1.1 pooka #include "dhcp.h" 66 1.1 pooka #include "if-options.h" 67 1.1 pooka #include "net.h" 68 1.1 pooka 69 1.1 pooka #include <rump/rump_syscalls.h> 70 1.1 pooka 71 1.1 pooka static char hwaddr_buffer[(HWADDR_LEN * 3) + 1]; 72 1.1 pooka 73 1.1 pooka int socket_afnet = -1; 74 1.1 pooka 75 1.1 pooka int 76 1.1 pooka inet_ntocidr(struct in_addr address) 77 1.1 pooka { 78 1.1 pooka int cidr = 0; 79 1.1 pooka uint32_t mask = htonl(address.s_addr); 80 1.1 pooka 81 1.1 pooka while (mask) { 82 1.1 pooka cidr++; 83 1.1 pooka mask <<= 1; 84 1.1 pooka } 85 1.1 pooka return cidr; 86 1.1 pooka } 87 1.1 pooka 88 1.1 pooka int 89 1.1 pooka inet_cidrtoaddr(int cidr, struct in_addr *addr) 90 1.1 pooka { 91 1.1 pooka int ocets; 92 1.1 pooka 93 1.1 pooka if (cidr < 1 || cidr > 32) { 94 1.1 pooka errno = EINVAL; 95 1.1 pooka return -1; 96 1.1 pooka } 97 1.1 pooka ocets = (cidr + 7) / 8; 98 1.1 pooka 99 1.1 pooka addr->s_addr = 0; 100 1.1 pooka if (ocets > 0) { 101 1.1 pooka memset(&addr->s_addr, 255, (size_t)ocets - 1); 102 1.1 pooka memset((unsigned char *)&addr->s_addr + (ocets - 1), 103 1.1 pooka (256 - (1 << (32 - cidr) % 8)), 1); 104 1.1 pooka } 105 1.1 pooka 106 1.1 pooka return 0; 107 1.1 pooka } 108 1.1 pooka 109 1.1 pooka uint32_t 110 1.1 pooka get_netmask(uint32_t addr) 111 1.1 pooka { 112 1.1 pooka uint32_t dst; 113 1.1 pooka 114 1.1 pooka if (addr == 0) 115 1.1 pooka return 0; 116 1.1 pooka 117 1.1 pooka dst = htonl(addr); 118 1.1 pooka if (IN_CLASSA(dst)) 119 1.1 pooka return ntohl(IN_CLASSA_NET); 120 1.1 pooka if (IN_CLASSB(dst)) 121 1.1 pooka return ntohl(IN_CLASSB_NET); 122 1.1 pooka if (IN_CLASSC(dst)) 123 1.1 pooka return ntohl(IN_CLASSC_NET); 124 1.1 pooka 125 1.1 pooka return 0; 126 1.1 pooka } 127 1.1 pooka 128 1.1 pooka char * 129 1.1 pooka hwaddr_ntoa(const unsigned char *hwaddr, size_t hwlen) 130 1.1 pooka { 131 1.1 pooka char *p = hwaddr_buffer; 132 1.1 pooka size_t i; 133 1.1 pooka 134 1.1 pooka for (i = 0; i < hwlen && i < HWADDR_LEN; i++) { 135 1.1 pooka if (i > 0) 136 1.1 pooka *p ++= ':'; 137 1.1 pooka p += snprintf(p, 3, "%.2x", hwaddr[i]); 138 1.1 pooka } 139 1.1 pooka 140 1.1 pooka *p ++= '\0'; 141 1.1 pooka 142 1.1 pooka return hwaddr_buffer; 143 1.1 pooka } 144 1.1 pooka 145 1.1 pooka size_t 146 1.1 pooka hwaddr_aton(unsigned char *buffer, const char *addr) 147 1.1 pooka { 148 1.1 pooka char c[3]; 149 1.1 pooka const char *p = addr; 150 1.1 pooka unsigned char *bp = buffer; 151 1.1 pooka size_t len = 0; 152 1.1 pooka 153 1.1 pooka c[2] = '\0'; 154 1.1 pooka while (*p) { 155 1.1 pooka c[0] = *p++; 156 1.1 pooka c[1] = *p++; 157 1.1 pooka /* Ensure that digits are hex */ 158 1.1 pooka if (isxdigit((unsigned char)c[0]) == 0 || 159 1.1 pooka isxdigit((unsigned char)c[1]) == 0) 160 1.1 pooka { 161 1.1 pooka errno = EINVAL; 162 1.1 pooka return 0; 163 1.1 pooka } 164 1.1 pooka /* We should have at least two entries 00:01 */ 165 1.1 pooka if (len == 0 && *p == '\0') { 166 1.1 pooka errno = EINVAL; 167 1.1 pooka return 0; 168 1.1 pooka } 169 1.2 andvar /* Ensure that next data is EOL or a separator with data */ 170 1.1 pooka if (!(*p == '\0' || (*p == ':' && *(p + 1) != '\0'))) { 171 1.1 pooka errno = EINVAL; 172 1.1 pooka return 0; 173 1.1 pooka } 174 1.1 pooka if (*p) 175 1.1 pooka p++; 176 1.1 pooka if (bp) 177 1.1 pooka *bp++ = (unsigned char)strtol(c, NULL, 16); 178 1.1 pooka len++; 179 1.1 pooka } 180 1.1 pooka return len; 181 1.1 pooka } 182 1.1 pooka 183 1.1 pooka struct interface * 184 1.1 pooka init_interface(const char *ifname) 185 1.1 pooka { 186 1.1 pooka struct ifreq ifr; 187 1.1 pooka struct interface *iface = NULL; 188 1.1 pooka 189 1.1 pooka memset(&ifr, 0, sizeof(ifr)); 190 1.1 pooka strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 191 1.1 pooka if (rump_sys_ioctl(socket_afnet, SIOCGIFFLAGS, &ifr) == -1) 192 1.1 pooka goto eexit; 193 1.1 pooka 194 1.1 pooka iface = xzalloc(sizeof(*iface)); 195 1.1 pooka strlcpy(iface->name, ifname, sizeof(iface->name)); 196 1.1 pooka iface->flags = ifr.ifr_flags; 197 1.1 pooka /* We reserve the 100 range for virtual interfaces, if and when 198 1.1 pooka * we can work them out. */ 199 1.1 pooka iface->metric = 200 + if_nametoindex(iface->name); 200 1.1 pooka if (getifssid(ifname, iface->ssid) != -1) { 201 1.1 pooka iface->wireless = 1; 202 1.1 pooka iface->metric += 100; 203 1.1 pooka } 204 1.1 pooka 205 1.1 pooka if (rump_sys_ioctl(socket_afnet, SIOCGIFMTU, &ifr) == -1) 206 1.1 pooka goto eexit; 207 1.1 pooka /* Ensure that the MTU is big enough for DHCP */ 208 1.1 pooka if (ifr.ifr_mtu < MTU_MIN) { 209 1.1 pooka ifr.ifr_mtu = MTU_MIN; 210 1.1 pooka strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 211 1.1 pooka if (rump_sys_ioctl(socket_afnet, SIOCSIFMTU, &ifr) == -1) 212 1.1 pooka goto eexit; 213 1.1 pooka } 214 1.1 pooka 215 1.1 pooka /* 0 is a valid fd, so init to -1 */ 216 1.1 pooka iface->raw_fd = -1; 217 1.1 pooka iface->udp_fd = -1; 218 1.1 pooka iface->arp_fd = -1; 219 1.1 pooka goto exit; 220 1.1 pooka 221 1.1 pooka eexit: 222 1.1 pooka free(iface); 223 1.1 pooka iface = NULL; 224 1.1 pooka exit: 225 1.1 pooka return iface; 226 1.1 pooka } 227 1.1 pooka 228 1.1 pooka int 229 1.1 pooka carrier_status(struct interface *iface) 230 1.1 pooka { 231 1.1 pooka int ret; 232 1.1 pooka struct ifreq ifr; 233 1.1 pooka #ifdef SIOCGIFMEDIA 234 1.1 pooka struct ifmediareq ifmr; 235 1.1 pooka #endif 236 1.1 pooka #ifdef __linux__ 237 1.1 pooka char *p; 238 1.1 pooka #endif 239 1.1 pooka 240 1.1 pooka memset(&ifr, 0, sizeof(ifr)); 241 1.1 pooka strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name)); 242 1.1 pooka #ifdef __linux__ 243 1.1 pooka /* We can only test the real interface up */ 244 1.1 pooka if ((p = strchr(ifr.ifr_name, ':'))) 245 1.1 pooka *p = '\0'; 246 1.1 pooka #endif 247 1.1 pooka 248 1.1 pooka if (rump_sys_ioctl(socket_afnet, SIOCGIFFLAGS, &ifr) == -1) 249 1.1 pooka return -1; 250 1.1 pooka iface->flags = ifr.ifr_flags; 251 1.1 pooka 252 1.1 pooka ret = -1; 253 1.1 pooka #ifdef SIOCGIFMEDIA 254 1.1 pooka memset(&ifmr, 0, sizeof(ifmr)); 255 1.1 pooka strlcpy(ifmr.ifm_name, iface->name, sizeof(ifmr.ifm_name)); 256 1.1 pooka if (rump_sys_ioctl(socket_afnet, SIOCGIFMEDIA, &ifmr) != -1 && 257 1.1 pooka ifmr.ifm_status & IFM_AVALID) 258 1.1 pooka ret = (ifmr.ifm_status & IFM_ACTIVE) ? 1 : 0; 259 1.1 pooka #endif 260 1.1 pooka if (ret == -1) 261 1.1 pooka ret = (ifr.ifr_flags & IFF_RUNNING) ? 1 : 0; 262 1.1 pooka return ret; 263 1.1 pooka } 264 1.1 pooka 265 1.1 pooka int 266 1.1 pooka up_interface(struct interface *iface) 267 1.1 pooka { 268 1.1 pooka struct ifreq ifr; 269 1.1 pooka int retval = -1; 270 1.1 pooka #ifdef __linux__ 271 1.1 pooka char *p; 272 1.1 pooka #endif 273 1.1 pooka 274 1.1 pooka memset(&ifr, 0, sizeof(ifr)); 275 1.1 pooka strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name)); 276 1.1 pooka #ifdef __linux__ 277 1.1 pooka /* We can only bring the real interface up */ 278 1.1 pooka if ((p = strchr(ifr.ifr_name, ':'))) 279 1.1 pooka *p = '\0'; 280 1.1 pooka #endif 281 1.1 pooka if (rump_sys_ioctl(socket_afnet, SIOCGIFFLAGS, &ifr) == 0) { 282 1.1 pooka if ((ifr.ifr_flags & IFF_UP)) 283 1.1 pooka retval = 0; 284 1.1 pooka else { 285 1.1 pooka ifr.ifr_flags |= IFF_UP; 286 1.1 pooka if (rump_sys_ioctl(socket_afnet, SIOCSIFFLAGS, &ifr) == 0) 287 1.1 pooka retval = 0; 288 1.1 pooka } 289 1.1 pooka iface->flags = ifr.ifr_flags; 290 1.1 pooka } 291 1.1 pooka return retval; 292 1.1 pooka } 293 1.1 pooka 294 1.1 pooka int 295 1.1 pooka do_address(const char *ifname, 296 1.1 pooka struct in_addr *addr, struct in_addr *net, struct in_addr *dst, int act) 297 1.1 pooka { 298 1.1 pooka struct ifaddrs *ifaddrs, *ifa; 299 1.1 pooka const struct sockaddr_in *a, *n, *d; 300 1.1 pooka int retval; 301 1.1 pooka 302 1.1 pooka if (getifaddrs(&ifaddrs) == -1) 303 1.1 pooka return -1; 304 1.1 pooka 305 1.1 pooka retval = 0; 306 1.1 pooka for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) { 307 1.1 pooka if (ifa->ifa_addr == NULL || 308 1.1 pooka ifa->ifa_addr->sa_family != AF_INET || 309 1.1 pooka strcmp(ifa->ifa_name, ifname) != 0) 310 1.1 pooka continue; 311 1.1 pooka a = (const struct sockaddr_in *)(void *)ifa->ifa_addr; 312 1.1 pooka n = (const struct sockaddr_in *)(void *)ifa->ifa_netmask; 313 1.1 pooka if (ifa->ifa_flags & IFF_POINTOPOINT) 314 1.1 pooka d = (const struct sockaddr_in *)(void *) 315 1.1 pooka ifa->ifa_dstaddr; 316 1.1 pooka else 317 1.1 pooka d = NULL; 318 1.1 pooka if (act == 1) { 319 1.1 pooka addr->s_addr = a->sin_addr.s_addr; 320 1.1 pooka net->s_addr = n->sin_addr.s_addr; 321 1.1 pooka if (dst) { 322 1.1 pooka if (ifa->ifa_flags & IFF_POINTOPOINT) 323 1.1 pooka dst->s_addr = d->sin_addr.s_addr; 324 1.1 pooka else 325 1.1 pooka dst->s_addr = INADDR_ANY; 326 1.1 pooka } 327 1.1 pooka retval = 1; 328 1.1 pooka break; 329 1.1 pooka } 330 1.1 pooka if (addr->s_addr == a->sin_addr.s_addr && 331 1.1 pooka (net == NULL || net->s_addr == n->sin_addr.s_addr)) 332 1.1 pooka { 333 1.1 pooka retval = 1; 334 1.1 pooka break; 335 1.1 pooka } 336 1.1 pooka } 337 1.1 pooka freeifaddrs(ifaddrs); 338 1.1 pooka return retval; 339 1.1 pooka } 340 1.1 pooka 341 1.1 pooka int 342 1.1 pooka do_mtu(const char *ifname, short int mtu) 343 1.1 pooka { 344 1.1 pooka struct ifreq ifr; 345 1.1 pooka int r; 346 1.1 pooka 347 1.1 pooka memset(&ifr, 0, sizeof(ifr)); 348 1.1 pooka strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 349 1.1 pooka ifr.ifr_mtu = mtu; 350 1.1 pooka r = rump_sys_ioctl(socket_afnet, mtu ? SIOCSIFMTU : SIOCGIFMTU, &ifr); 351 1.1 pooka if (r == -1) 352 1.1 pooka return -1; 353 1.1 pooka return ifr.ifr_mtu; 354 1.1 pooka } 355 1.1 pooka 356 1.1 pooka void 357 1.1 pooka free_routes(struct rt *routes) 358 1.1 pooka { 359 1.1 pooka struct rt *r; 360 1.1 pooka 361 1.1 pooka while (routes) { 362 1.1 pooka r = routes->next; 363 1.1 pooka free(routes); 364 1.1 pooka routes = r; 365 1.1 pooka } 366 1.1 pooka } 367 1.1 pooka 368 1.1 pooka struct udp_dhcp_packet 369 1.1 pooka { 370 1.1 pooka struct ip ip; 371 1.1 pooka struct udphdr udp; 372 1.1 pooka struct dhcp_message dhcp; 373 1.1 pooka }; 374 1.1 pooka const size_t udp_dhcp_len = sizeof(struct udp_dhcp_packet); 375 1.1 pooka 376 1.1 pooka static uint16_t 377 1.1 pooka checksum(const void *data, uint16_t len) 378 1.1 pooka { 379 1.1 pooka const uint8_t *addr = data; 380 1.1 pooka uint32_t sum = 0; 381 1.1 pooka 382 1.1 pooka while (len > 1) { 383 1.1 pooka sum += addr[0] * 256 + addr[1]; 384 1.1 pooka addr += 2; 385 1.1 pooka len -= 2; 386 1.1 pooka } 387 1.1 pooka 388 1.1 pooka if (len == 1) 389 1.1 pooka sum += *addr * 256; 390 1.1 pooka 391 1.1 pooka sum = (sum >> 16) + (sum & 0xffff); 392 1.1 pooka sum += (sum >> 16); 393 1.1 pooka 394 1.1 pooka sum = htons(sum); 395 1.1 pooka 396 1.1 pooka return ~sum; 397 1.1 pooka } 398 1.1 pooka 399 1.1 pooka ssize_t 400 1.1 pooka make_udp_packet(uint8_t **packet, const uint8_t *data, size_t length, 401 1.1 pooka struct in_addr source, struct in_addr dest) 402 1.1 pooka { 403 1.1 pooka struct udp_dhcp_packet *udpp; 404 1.1 pooka struct ip *ip; 405 1.1 pooka struct udphdr *udp; 406 1.1 pooka 407 1.1 pooka udpp = xzalloc(sizeof(*udpp)); 408 1.1 pooka ip = &udpp->ip; 409 1.1 pooka udp = &udpp->udp; 410 1.1 pooka 411 1.1 pooka /* OK, this is important :) 412 1.1 pooka * We copy the data to our packet and then create a small part of the 413 1.1 pooka * ip structure and an invalid ip_len (basically udp length). 414 1.1 pooka * We then fill the udp structure and put the checksum 415 1.1 pooka * of the whole packet into the udp checksum. 416 1.1 pooka * Finally we complete the ip structure and ip checksum. 417 1.1 pooka * If we don't do the ordering like so then the udp checksum will be 418 1.1 pooka * broken, so find another way of doing it! */ 419 1.1 pooka 420 1.1 pooka memcpy(&udpp->dhcp, data, length); 421 1.1 pooka 422 1.1 pooka ip->ip_p = IPPROTO_UDP; 423 1.1 pooka ip->ip_src.s_addr = source.s_addr; 424 1.1 pooka if (dest.s_addr == 0) 425 1.1 pooka ip->ip_dst.s_addr = INADDR_BROADCAST; 426 1.1 pooka else 427 1.1 pooka ip->ip_dst.s_addr = dest.s_addr; 428 1.1 pooka 429 1.1 pooka udp->uh_sport = htons(DHCP_CLIENT_PORT); 430 1.1 pooka udp->uh_dport = htons(DHCP_SERVER_PORT); 431 1.1 pooka udp->uh_ulen = htons(sizeof(*udp) + length); 432 1.1 pooka ip->ip_len = udp->uh_ulen; 433 1.1 pooka udp->uh_sum = checksum(udpp, sizeof(*udpp)); 434 1.1 pooka 435 1.1 pooka ip->ip_v = IPVERSION; 436 1.1 pooka ip->ip_hl = sizeof(*ip) >> 2; 437 1.1 pooka ip->ip_id = arc4random() & UINT16_MAX; 438 1.1 pooka ip->ip_ttl = IPDEFTTL; 439 1.1 pooka ip->ip_len = htons(sizeof(*ip) + sizeof(*udp) + length); 440 1.1 pooka ip->ip_sum = checksum(ip, sizeof(*ip)); 441 1.1 pooka 442 1.1 pooka *packet = (uint8_t *)udpp; 443 1.1 pooka return sizeof(*ip) + sizeof(*udp) + length; 444 1.1 pooka } 445 1.1 pooka 446 1.1 pooka ssize_t 447 1.1 pooka get_udp_data(const uint8_t **data, const uint8_t *udp) 448 1.1 pooka { 449 1.1 pooka struct udp_dhcp_packet packet; 450 1.1 pooka 451 1.1 pooka memcpy(&packet, udp, sizeof(packet)); 452 1.1 pooka *data = udp + offsetof(struct udp_dhcp_packet, dhcp); 453 1.1 pooka return ntohs(packet.ip.ip_len) - 454 1.1 pooka sizeof(packet.ip) - 455 1.1 pooka sizeof(packet.udp); 456 1.1 pooka } 457 1.1 pooka 458 1.1 pooka int 459 1.1 pooka valid_udp_packet(const uint8_t *data, size_t data_len, struct in_addr *from) 460 1.1 pooka { 461 1.1 pooka struct udp_dhcp_packet packet; 462 1.1 pooka uint16_t bytes, udpsum; 463 1.1 pooka 464 1.1 pooka if (data_len < sizeof(packet.ip)) { 465 1.1 pooka if (from) 466 1.1 pooka from->s_addr = INADDR_ANY; 467 1.1 pooka errno = EINVAL; 468 1.1 pooka return -1; 469 1.1 pooka } 470 1.1 pooka memcpy(&packet, data, MIN(data_len, sizeof(packet))); 471 1.1 pooka if (from) 472 1.1 pooka from->s_addr = packet.ip.ip_src.s_addr; 473 1.1 pooka if (data_len > sizeof(packet)) { 474 1.1 pooka errno = EINVAL; 475 1.1 pooka return -1; 476 1.1 pooka } 477 1.1 pooka if (checksum(&packet.ip, sizeof(packet.ip)) != 0) { 478 1.1 pooka errno = EINVAL; 479 1.1 pooka return -1; 480 1.1 pooka } 481 1.1 pooka 482 1.1 pooka bytes = ntohs(packet.ip.ip_len); 483 1.1 pooka if (data_len < bytes) { 484 1.1 pooka errno = EINVAL; 485 1.1 pooka return -1; 486 1.1 pooka } 487 1.1 pooka udpsum = packet.udp.uh_sum; 488 1.1 pooka packet.udp.uh_sum = 0; 489 1.1 pooka packet.ip.ip_hl = 0; 490 1.1 pooka packet.ip.ip_v = 0; 491 1.1 pooka packet.ip.ip_tos = 0; 492 1.1 pooka packet.ip.ip_len = packet.udp.uh_ulen; 493 1.1 pooka packet.ip.ip_id = 0; 494 1.1 pooka packet.ip.ip_off = 0; 495 1.1 pooka packet.ip.ip_ttl = 0; 496 1.1 pooka packet.ip.ip_sum = 0; 497 1.1 pooka if (udpsum && checksum(&packet, bytes) != udpsum) { 498 1.1 pooka errno = EINVAL; 499 1.1 pooka return -1; 500 1.1 pooka } 501 1.1 pooka 502 1.1 pooka return 0; 503 1.1 pooka } 504