1/*
2 * dhcpcd - DHCP client daemon
3 * Copyright (c) 2006-2011 Roy Marples <roy@marples.name>
4 * All rights reserved
5
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include <sys/types.h>
29#include <sys/ioctl.h>
30#include <sys/param.h>
31#include <sys/socket.h>
32#include <sys/time.h>
33
34#include <arpa/inet.h>
35#include <net/if.h>
36#include <net/if_arp.h>
37#ifdef AF_LINK
38#  include <net/if_dl.h>
39#  include <net/if_types.h>
40#endif
41#include <netinet/in_systm.h>
42#include <netinet/in.h>
43#include <netinet/ip.h>
44#define __FAVOR_BSD /* Nasty glibc hack so we can use BSD semantics for UDP */
45#include <netinet/udp.h>
46#undef __FAVOR_BSD
47#ifdef AF_PACKET
48#  include <netpacket/packet.h>
49#endif
50#ifdef SIOCGIFMEDIA
51#  include <net/if_media.h>
52#endif
53
54#include <ctype.h>
55#include <errno.h>
56#include <ifaddrs.h>
57#include <fnmatch.h>
58#include <stddef.h>
59#include <stdio.h>
60#include <stdlib.h>
61#include <string.h>
62#include <syslog.h>
63#include <unistd.h>
64
65#include "config.h"
66#include "common.h"
67#include "dhcp.h"
68#include "if-options.h"
69#include "ipv6rs.h"
70#include "net.h"
71#include "signals.h"
72
73static char hwaddr_buffer[(HWADDR_LEN * 3) + 1 + 1024];
74
75int socket_afnet = -1;
76
77int
78inet_ntocidr(struct in_addr address)
79{
80	int cidr = 0;
81	uint32_t mask = htonl(address.s_addr);
82
83	while (mask) {
84		cidr++;
85		mask <<= 1;
86	}
87	return cidr;
88}
89
90int
91inet_cidrtoaddr(int cidr, struct in_addr *addr)
92{
93	int ocets;
94
95	if (cidr < 1 || cidr > 32) {
96		errno = EINVAL;
97		return -1;
98	}
99	ocets = (cidr + 7) / 8;
100
101	addr->s_addr = 0;
102	if (ocets > 0) {
103		memset(&addr->s_addr, 255, (size_t)ocets - 1);
104		memset((unsigned char *)&addr->s_addr + (ocets - 1),
105		    (256 - (1 << (32 - cidr) % 8)), 1);
106	}
107
108	return 0;
109}
110
111uint32_t
112get_netmask(uint32_t addr)
113{
114	uint32_t dst;
115
116	if (addr == 0)
117		return 0;
118
119	dst = htonl(addr);
120	if (IN_CLASSA(dst))
121		return ntohl(IN_CLASSA_NET);
122	if (IN_CLASSB(dst))
123		return ntohl(IN_CLASSB_NET);
124	if (IN_CLASSC(dst))
125		return ntohl(IN_CLASSC_NET);
126
127	return 0;
128}
129
130char *
131hwaddr_ntoa(const unsigned char *hwaddr, size_t hwlen)
132{
133	char *p = hwaddr_buffer;
134	size_t i;
135
136	for (i = 0; i < hwlen; i++) {
137		if (i > 0)
138			*p ++= ':';
139		p += snprintf(p, 3, "%.2x", hwaddr[i]);
140	}
141
142	*p ++= '\0';
143
144	return hwaddr_buffer;
145}
146
147size_t
148hwaddr_aton(unsigned char *buffer, const char *addr)
149{
150	char c[3];
151	const char *p = addr;
152	unsigned char *bp = buffer;
153	size_t len = 0;
154
155	c[2] = '\0';
156	while (*p) {
157		c[0] = *p++;
158		c[1] = *p++;
159		/* Ensure that digits are hex */
160		if (isxdigit((unsigned char)c[0]) == 0 ||
161		    isxdigit((unsigned char)c[1]) == 0)
162		{
163			errno = EINVAL;
164			return 0;
165		}
166		/* We should have at least two entries 00:01 */
167		if (len == 0 && *p == '\0') {
168			errno = EINVAL;
169			return 0;
170		}
171		/* Ensure that next data is EOL or a seperator with data */
172		if (!(*p == '\0' || (*p == ':' && *(p + 1) != '\0'))) {
173			errno = EINVAL;
174			return 0;
175		}
176		if (*p)
177			p++;
178		if (bp)
179			*bp++ = (unsigned char)strtol(c, NULL, 16);
180		len++;
181	}
182	return len;
183}
184
185void
186free_interface(struct interface *iface)
187{
188	if (!iface)
189		return;
190	ipv6rs_free(iface);
191	if (iface->state) {
192		free_options(iface->state->options);
193		free(iface->state->old);
194		free(iface->state->new);
195		free(iface->state->offer);
196		free(iface->state);
197	}
198	free(iface->buffer);
199	free(iface->clientid);
200	free(iface);
201}
202
203int
204carrier_status(struct interface *iface)
205{
206	int ret;
207	struct ifreq ifr;
208#ifdef SIOCGIFMEDIA
209	struct ifmediareq ifmr;
210#endif
211#ifdef __linux__
212	char *p;
213#endif
214
215	memset(&ifr, 0, sizeof(ifr));
216	strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name));
217#ifdef __linux__
218	/* We can only test the real interface up */
219	if ((p = strchr(ifr.ifr_name, ':')))
220		*p = '\0';
221#endif
222
223	if (ioctl(socket_afnet, SIOCGIFFLAGS, &ifr) == -1)
224		return -1;
225	iface->flags = ifr.ifr_flags;
226
227	ret = -1;
228#ifdef SIOCGIFMEDIA
229	memset(&ifmr, 0, sizeof(ifmr));
230	strlcpy(ifmr.ifm_name, iface->name, sizeof(ifmr.ifm_name));
231	if (ioctl(socket_afnet, SIOCGIFMEDIA, &ifmr) != -1 &&
232	    ifmr.ifm_status & IFM_AVALID)
233		ret = (ifmr.ifm_status & IFM_ACTIVE) ? 1 : 0;
234#endif
235	if (ret == -1)
236		ret = (ifr.ifr_flags & IFF_RUNNING) ? 1 : 0;
237	return ret;
238}
239
240int
241up_interface(struct interface *iface)
242{
243	struct ifreq ifr;
244	int retval = -1;
245#ifdef __linux__
246	char *p;
247#endif
248
249	memset(&ifr, 0, sizeof(ifr));
250	strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name));
251#ifdef __linux__
252	/* We can only bring the real interface up */
253	if ((p = strchr(ifr.ifr_name, ':')))
254		*p = '\0';
255#endif
256	if (ioctl(socket_afnet, SIOCGIFFLAGS, &ifr) == 0) {
257		if ((ifr.ifr_flags & IFF_UP))
258			retval = 0;
259		else {
260			ifr.ifr_flags |= IFF_UP;
261			if (ioctl(socket_afnet, SIOCSIFFLAGS, &ifr) == 0)
262				retval = 0;
263		}
264		iface->flags = ifr.ifr_flags;
265	}
266	return retval;
267}
268
269struct interface *
270discover_interfaces(int argc, char * const *argv)
271{
272	struct ifaddrs *ifaddrs, *ifa;
273	char *p;
274	int i, sdl_type;
275	struct interface *ifp, *ifs, *ifl;
276#ifdef __linux__
277	char ifn[IF_NAMESIZE];
278#endif
279#ifdef AF_LINK
280	const struct sockaddr_dl *sdl;
281#ifdef IFLR_ACTIVE
282	struct if_laddrreq iflr;
283	int socket_aflink;
284
285	socket_aflink = socket(AF_LINK, SOCK_DGRAM, 0);
286	if (socket_aflink == -1)
287		return NULL;
288	memset(&iflr, 0, sizeof(iflr));
289#endif
290#elif AF_PACKET
291	const struct sockaddr_ll *sll;
292#endif
293
294	if (getifaddrs(&ifaddrs) == -1)
295		return NULL;
296
297	ifs = ifl = NULL;
298	for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
299		if (ifa->ifa_addr != NULL) {
300#ifdef AF_LINK
301			if (ifa->ifa_addr->sa_family != AF_LINK)
302				continue;
303#elif AF_PACKET
304			if (ifa->ifa_addr->sa_family != AF_PACKET)
305				continue;
306#endif
307		}
308
309		/* It's possible for an interface to have >1 AF_LINK.
310		 * For our purposes, we use the first one. */
311		for (ifp = ifs; ifp; ifp = ifp->next)
312			if (strcmp(ifp->name, ifa->ifa_name) == 0)
313				break;
314		if (ifp)
315			continue;
316		if (argc > 0) {
317			for (i = 0; i < argc; i++) {
318#ifdef __linux__
319				/* Check the real interface name */
320				strlcpy(ifn, argv[i], sizeof(ifn));
321				p = strchr(ifn, ':');
322				if (p)
323					*p = '\0';
324				if (strcmp(ifn, ifa->ifa_name) == 0)
325					break;
326#else
327				if (strcmp(argv[i], ifa->ifa_name) == 0)
328					break;
329#endif
330			}
331			if (i == argc)
332				continue;
333			p = argv[i];
334		} else {
335			/* -1 means we're discovering against a specific
336			 * interface, but we still need the below rules
337			 * to apply. */
338			if (argc == -1 && strcmp(argv[0], ifa->ifa_name) != 0)
339				continue;
340			for (i = 0; i < ifdc; i++)
341				if (!fnmatch(ifdv[i], ifa->ifa_name, 0))
342					break;
343			if (i < ifdc)
344				continue;
345			for (i = 0; i < ifac; i++)
346				if (!fnmatch(ifav[i], ifa->ifa_name, 0))
347					break;
348			if (ifac && i == ifac)
349				continue;
350			p = ifa->ifa_name;
351		}
352
353		ifp = xzalloc(sizeof(*ifp));
354		strlcpy(ifp->name, p, sizeof(ifp->name));
355		ifp->flags = ifa->ifa_flags;
356
357		/* Bring the interface up if not already */
358		if (!(ifp->flags & IFF_UP)
359#ifdef SIOCGIFMEDIA
360		    && carrier_status(ifp) != -1
361#endif
362		   )
363		{
364			if (up_interface(ifp) == 0)
365				options |= DHCPCD_WAITUP;
366			else
367				syslog(LOG_ERR, "%s: up_interface: %m", ifp->name);
368		}
369
370		sdl_type = 0;
371		/* Don't allow loopback unless explicit */
372		if (ifp->flags & IFF_LOOPBACK) {
373			if (argc == 0 && ifac == 0) {
374				free_interface(ifp);
375				continue;
376			}
377		} else if (ifa->ifa_addr != NULL) {
378#ifdef AF_LINK
379			sdl = (const struct sockaddr_dl *)(void *)ifa->ifa_addr;
380
381#ifdef IFLR_ACTIVE
382			/* We need to check for active address */
383			strlcpy(iflr.iflr_name, ifp->name,
384			    sizeof(iflr.iflr_name));
385			memcpy(&iflr.addr, ifa->ifa_addr,
386			    MIN(ifa->ifa_addr->sa_len, sizeof(iflr.addr)));
387			iflr.flags = IFLR_PREFIX;
388			iflr.prefixlen = sdl->sdl_alen * NBBY;
389			if (ioctl(socket_aflink, SIOCGLIFADDR, &iflr) == -1 ||
390			    !(iflr.flags & IFLR_ACTIVE))
391			{
392				free_interface(ifp);
393				continue;
394			}
395#endif
396
397			ifp->index = sdl->sdl_index;
398			sdl_type = sdl->sdl_type;
399			switch(sdl->sdl_type) {
400			case IFT_BRIDGE: /* FALLTHROUGH */
401			case IFT_L2VLAN: /* FALLTHOUGH */
402			case IFT_L3IPVLAN: /* FALLTHROUGH */
403			case IFT_ETHER:
404				ifp->family = ARPHRD_ETHER;
405				break;
406			case IFT_IEEE1394:
407				ifp->family = ARPHRD_IEEE1394;
408				break;
409#ifdef IFT_INFINIBAND
410			case IFT_INFINIBAND:
411				ifp->family = ARPHRD_INFINIBAND;
412				break;
413#endif
414			}
415			ifp->hwlen = sdl->sdl_alen;
416#ifndef CLLADDR
417#  define CLLADDR(s) ((const char *)((s)->sdl_data + (s)->sdl_nlen))
418#endif
419			memcpy(ifp->hwaddr, CLLADDR(sdl), ifp->hwlen);
420#elif AF_PACKET
421			sll = (const struct sockaddr_ll *)(void *)ifa->ifa_addr;
422			ifp->index = sll->sll_ifindex;
423			ifp->family = sdl_type = sll->sll_hatype;
424			ifp->hwlen = sll->sll_halen;
425			if (ifp->hwlen != 0)
426				memcpy(ifp->hwaddr, sll->sll_addr, ifp->hwlen);
427#endif
428		}
429
430		/* We only work on ethernet by default */
431		if (!(ifp->flags & IFF_POINTOPOINT) &&
432		    ifp->family != ARPHRD_ETHER)
433		{
434			if (argc == 0 && ifac == 0) {
435				free_interface(ifp);
436				continue;
437			}
438			switch (ifp->family) {
439			case ARPHRD_IEEE1394: /* FALLTHROUGH */
440			case ARPHRD_INFINIBAND:
441				/* We don't warn for supported families */
442				break;
443			default:
444				syslog(LOG_WARNING,
445				    "%s: unsupported interface type %.2x"
446				    ", falling back to ethernet",
447				    ifp->name, sdl_type);
448				ifp->family = ARPHRD_ETHER;
449				break;
450			}
451		}
452
453		/* Handle any platform init for the interface */
454		if (if_init(ifp) == -1) {
455			syslog(LOG_ERR, "%s: if_init: %m", p);
456			free_interface(ifp);
457			continue;
458		}
459
460		/* Ensure that the MTU is big enough for DHCP */
461		if (get_mtu(ifp->name) < MTU_MIN &&
462		    set_mtu(ifp->name, MTU_MIN) == -1)
463		{
464			syslog(LOG_ERR, "%s: set_mtu: %m", p);
465			free_interface(ifp);
466			continue;
467		}
468
469		/* We reserve the 100 range for virtual interfaces, if and when
470		 * we can work them out. */
471		ifp->metric = 200 + ifp->index;
472		if (getifssid(ifp->name, ifp->ssid) != -1) {
473			ifp->wireless = 1;
474			ifp->metric += 100;
475		}
476		snprintf(ifp->leasefile, sizeof(ifp->leasefile),
477		    LEASEFILE, ifp->name);
478		/* 0 is a valid fd, so init to -1 */
479		ifp->raw_fd = ifp->udp_fd = ifp->arp_fd = -1;
480
481		if (ifl)
482			ifl->next = ifp;
483		else
484			ifs = ifp;
485		ifl = ifp;
486	}
487	freeifaddrs(ifaddrs);
488
489#ifdef IFLR_ACTIVE
490	close(socket_aflink);
491#endif
492
493	return ifs;
494}
495
496int
497do_address(const char *ifname,
498    struct in_addr *addr, struct in_addr *net, struct in_addr *dst, int act)
499{
500	struct ifaddrs *ifaddrs, *ifa;
501	const struct sockaddr_in *a, *n, *d;
502	int retval;
503
504	if (getifaddrs(&ifaddrs) == -1)
505		return -1;
506
507	retval = 0;
508	for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
509		if (ifa->ifa_addr == NULL ||
510		    ifa->ifa_addr->sa_family != AF_INET ||
511		    strcmp(ifa->ifa_name, ifname) != 0)
512			continue;
513		a = (const struct sockaddr_in *)(void *)ifa->ifa_addr;
514		n = (const struct sockaddr_in *)(void *)ifa->ifa_netmask;
515		if (ifa->ifa_flags & IFF_POINTOPOINT)
516			d = (const struct sockaddr_in *)(void *)
517			    ifa->ifa_dstaddr;
518		else
519			d = NULL;
520		if (act == 1) {
521			addr->s_addr = a->sin_addr.s_addr;
522			net->s_addr = n->sin_addr.s_addr;
523			if (dst) {
524				if (ifa->ifa_flags & IFF_POINTOPOINT)
525					dst->s_addr = d->sin_addr.s_addr;
526				else
527					dst->s_addr = INADDR_ANY;
528			}
529			retval = 1;
530			break;
531		}
532		if (addr->s_addr == a->sin_addr.s_addr &&
533		    (net == NULL || net->s_addr == n->sin_addr.s_addr))
534		{
535			retval = 1;
536			break;
537		}
538	}
539	freeifaddrs(ifaddrs);
540	return retval;
541}
542
543int
544do_mtu(const char *ifname, short int mtu)
545{
546	struct ifreq ifr;
547	int r;
548
549	memset(&ifr, 0, sizeof(ifr));
550	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
551	ifr.ifr_mtu = mtu;
552	r = ioctl(socket_afnet, mtu ? SIOCSIFMTU : SIOCGIFMTU, &ifr);
553	if (r == -1)
554		return -1;
555	return ifr.ifr_mtu;
556}
557
558void
559free_routes(struct rt *routes)
560{
561	struct rt *r;
562
563	while (routes) {
564		r = routes->next;
565		free(routes);
566		routes = r;
567	}
568}
569
570int
571open_udp_socket(struct interface *iface)
572{
573	int s;
574	struct sockaddr_in sin;
575	int n;
576#ifdef SO_BINDTODEVICE
577	struct ifreq ifr;
578	char *p;
579#endif
580
581	if ((s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
582		return -1;
583
584	n = 1;
585	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) == -1)
586		goto eexit;
587#ifdef SO_BINDTODEVICE
588	memset(&ifr, 0, sizeof(ifr));
589	strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name));
590	/* We can only bind to the real device */
591	p = strchr(ifr.ifr_name, ':');
592	if (p)
593		*p = '\0';
594	if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, &ifr,
595		sizeof(ifr)) == -1)
596		goto eexit;
597#endif
598	/* As we don't use this socket for receiving, set the
599	 * receive buffer to 1 */
600	n = 1;
601	if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n)) == -1)
602		goto eexit;
603	memset(&sin, 0, sizeof(sin));
604	sin.sin_family = AF_INET;
605	sin.sin_port = htons(DHCP_CLIENT_PORT);
606	sin.sin_addr.s_addr = iface->addr.s_addr;
607	if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) == -1)
608		goto eexit;
609
610	iface->udp_fd = s;
611	set_cloexec(s);
612	return 0;
613
614eexit:
615	close(s);
616	return -1;
617}
618
619ssize_t
620send_packet(const struct interface *iface, struct in_addr to,
621    const uint8_t *data, ssize_t len)
622{
623	struct sockaddr_in sin;
624
625	memset(&sin, 0, sizeof(sin));
626	sin.sin_family = AF_INET;
627	sin.sin_addr.s_addr = to.s_addr;
628	sin.sin_port = htons(DHCP_SERVER_PORT);
629	return sendto(iface->udp_fd, data, len, 0,
630	    (struct sockaddr *)&sin, sizeof(sin));
631}
632
633struct udp_dhcp_packet
634{
635	struct ip ip;
636	struct udphdr udp;
637	struct dhcp_message dhcp;
638};
639const size_t udp_dhcp_len = sizeof(struct udp_dhcp_packet);
640
641static uint16_t
642checksum(const void *data, uint16_t len)
643{
644	const uint8_t *addr = data;
645	uint32_t sum = 0;
646
647	while (len > 1) {
648		sum += addr[0] * 256 + addr[1];
649		addr += 2;
650		len -= 2;
651	}
652
653	if (len == 1)
654		sum += *addr * 256;
655
656	sum = (sum >> 16) + (sum & 0xffff);
657	sum += (sum >> 16);
658
659	sum = htons(sum);
660
661	return ~sum;
662}
663
664ssize_t
665make_udp_packet(uint8_t **packet, const uint8_t *data, size_t length,
666    struct in_addr source, struct in_addr dest)
667{
668	struct udp_dhcp_packet *udpp;
669	struct ip *ip;
670	struct udphdr *udp;
671
672	udpp = xzalloc(sizeof(*udpp));
673	ip = &udpp->ip;
674	udp = &udpp->udp;
675
676	/* OK, this is important :)
677	 * We copy the data to our packet and then create a small part of the
678	 * ip structure and an invalid ip_len (basically udp length).
679	 * We then fill the udp structure and put the checksum
680	 * of the whole packet into the udp checksum.
681	 * Finally we complete the ip structure and ip checksum.
682	 * If we don't do the ordering like so then the udp checksum will be
683	 * broken, so find another way of doing it! */
684
685	memcpy(&udpp->dhcp, data, length);
686
687	ip->ip_p = IPPROTO_UDP;
688	ip->ip_src.s_addr = source.s_addr;
689	if (dest.s_addr == 0)
690		ip->ip_dst.s_addr = INADDR_BROADCAST;
691	else
692		ip->ip_dst.s_addr = dest.s_addr;
693
694	udp->uh_sport = htons(DHCP_CLIENT_PORT);
695	udp->uh_dport = htons(DHCP_SERVER_PORT);
696	udp->uh_ulen = htons(sizeof(*udp) + length);
697	ip->ip_len = udp->uh_ulen;
698	udp->uh_sum = checksum(udpp, sizeof(*udpp));
699
700	ip->ip_v = IPVERSION;
701	ip->ip_hl = sizeof(*ip) >> 2;
702	ip->ip_id = arc4random() & UINT16_MAX;
703	ip->ip_ttl = IPDEFTTL;
704	ip->ip_len = htons(sizeof(*ip) + sizeof(*udp) + length);
705	ip->ip_sum = checksum(ip, sizeof(*ip));
706
707	*packet = (uint8_t *)udpp;
708	return sizeof(*ip) + sizeof(*udp) + length;
709}
710
711ssize_t
712get_udp_data(const uint8_t **data, const uint8_t *udp)
713{
714	struct udp_dhcp_packet packet;
715
716	memcpy(&packet, udp, sizeof(packet));
717	*data = udp + offsetof(struct udp_dhcp_packet, dhcp);
718	return ntohs(packet.ip.ip_len) -
719	    sizeof(packet.ip) -
720	    sizeof(packet.udp);
721}
722
723int
724valid_udp_packet(const uint8_t *data, size_t data_len, struct in_addr *from,
725    int noudpcsum)
726{
727	struct udp_dhcp_packet packet;
728	uint16_t bytes, udpsum;
729
730	if (data_len < sizeof(packet.ip)) {
731		if (from)
732			from->s_addr = INADDR_ANY;
733		errno = EINVAL;
734		return -1;
735	}
736	memcpy(&packet, data, MIN(data_len, sizeof(packet)));
737	if (from)
738		from->s_addr = packet.ip.ip_src.s_addr;
739	if (data_len > sizeof(packet)) {
740		errno = EINVAL;
741		return -1;
742	}
743	if (checksum(&packet.ip, sizeof(packet.ip)) != 0) {
744		errno = EINVAL;
745		return -1;
746	}
747
748	bytes = ntohs(packet.ip.ip_len);
749	if (data_len < bytes) {
750		errno = EINVAL;
751		return -1;
752	}
753
754	if (noudpcsum == 0) {
755		udpsum = packet.udp.uh_sum;
756		packet.udp.uh_sum = 0;
757		packet.ip.ip_hl = 0;
758		packet.ip.ip_v = 0;
759		packet.ip.ip_tos = 0;
760		packet.ip.ip_len = packet.udp.uh_ulen;
761		packet.ip.ip_id = 0;
762		packet.ip.ip_off = 0;
763		packet.ip.ip_ttl = 0;
764		packet.ip.ip_sum = 0;
765		if (udpsum && checksum(&packet, bytes) != udpsum) {
766			errno = EINVAL;
767			return -1;
768		}
769	}
770
771	return 0;
772}
773