1d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan/*
2d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * dhcpcd - DHCP client daemon
3d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
4d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * All rights reserved
5d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
6d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * Redistribution and use in source and binary forms, with or without
7d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * modification, are permitted provided that the following conditions
8d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * are met:
9d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * 1. Redistributions of source code must retain the above copyright
10d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *    notice, this list of conditions and the following disclaimer.
11d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * 2. Redistributions in binary form must reproduce the above copyright
12d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *    notice, this list of conditions and the following disclaimer in the
13d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *    documentation and/or other materials provided with the distribution.
14d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *
15d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * SUCH DAMAGE.
26d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan */
27d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
28d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <sys/param.h>
29d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <sys/socket.h>
30d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <sys/stat.h>
31d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
32d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <arpa/inet.h>
33d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <net/if.h>
34d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <net/route.h>
35d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <netinet/if_ether.h>
36d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <netinet/in_systm.h>
37d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <netinet/in.h>
38d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <netinet/ip.h>
39d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define __FAVOR_BSD /* Nasty glibc hack so we can use BSD semantics for UDP */
40d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <netinet/udp.h>
41d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#undef __FAVOR_BSD
42d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
43d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <ctype.h>
44d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <errno.h>
45d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <fcntl.h>
46d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <inttypes.h>
47d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <stddef.h>
48d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <stdlib.h>
49d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <string.h>
50d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <unistd.h>
51d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
52d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define ELOOP_QUEUE 2
53d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "config.h"
54d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "arp.h"
55d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "common.h"
56d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "dhcp.h"
57d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "dhcpcd.h"
58d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "dhcp-common.h"
59d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "duid.h"
60d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "eloop.h"
61d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "if.h"
62d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "ipv4.h"
63d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "ipv4ll.h"
6423ff6edd8b4ec796a32d36a3eca8a8d8c785b565Samuel Tan#include "rpc-interface.h"
65d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "script.h"
66d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
67d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define DAD		"Duplicate address detected"
68d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define DHCP_MIN_LEASE	20
69d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
70d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define IPV4A		ADDRIPV4 | ARRAY
71d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define IPV4R		ADDRIPV4 | REQUEST
72d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
73d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan/* We should define a maximum for the NAK exponential backoff */
74d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define NAKOFF_MAX              60
75d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
76d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan/* Wait N nanoseconds between sending a RELEASE and dropping the address.
77d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * This gives the kernel enough time to actually send it. */
78d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define RELEASE_DELAY_S		0
79d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define RELEASE_DELAY_NS	10000000
80d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
81d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifndef IPDEFTTL
82d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define IPDEFTTL 64 /* RFC1340 */
83d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
84d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
85d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstruct dhcp_op {
86d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint8_t value;
87d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const char *name;
88d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan};
89d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
90d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic const struct dhcp_op dhcp_ops[] = {
91d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	{ DHCP_DISCOVER,   "DISCOVER" },
92d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	{ DHCP_OFFER,      "OFFER" },
93d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	{ DHCP_REQUEST,    "REQUEST" },
94d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	{ DHCP_DECLINE,    "DECLINE" },
95d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	{ DHCP_ACK,        "ACK" },
96d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	{ DHCP_NAK,        "NAK" },
97d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	{ DHCP_RELEASE,    "RELEASE" },
98d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	{ DHCP_INFORM,     "INFORM" },
99d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	{ DHCP_FORCERENEW, "DHCP_FORCERENEW"},
100d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	{ 0, NULL }
101d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan};
102d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
103d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic const char * const dhcp_params[] = {
104d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	"ip_address",
105d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	"subnet_cidr",
106d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	"network_number",
107d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	"filename",
108d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	"server_name",
109d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	NULL
110d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan};
111d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
112d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstruct udp_dhcp_packet
113d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
114d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct ip ip;
115d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct udphdr udp;
116d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_message dhcp;
117d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan};
118d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
119d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic const size_t udp_dhcp_len = sizeof(struct udp_dhcp_packet);
120d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
121d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int dhcp_open(struct interface *ifp);
122d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
123d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanvoid
124d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_printoptions(const struct dhcpcd_ctx *ctx,
125d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    const struct dhcp_opt *opts, size_t opts_len)
126d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
127d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const char * const *p;
128d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t i, j;
129d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const struct dhcp_opt *opt, *opt2;
130d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int cols;
131d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
132d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	for (p = dhcp_params; *p; p++)
133d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		printf("    %s\n", *p);
134d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
135d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	for (i = 0, opt = ctx->dhcp_opts; i < ctx->dhcp_opts_len; i++, opt++) {
136d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		for (j = 0, opt2 = opts; j < opts_len; j++, opt2++)
137d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (opt->option == opt2->option)
138d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				break;
139d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (j == opts_len) {
140d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			cols = printf("%03d %s", opt->option, opt->var);
141d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			dhcp_print_option_encoding(opt, cols);
142d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
143d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
144d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	for (i = 0, opt = opts; i < opts_len; i++, opt++) {
145d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		cols = printf("%03d %s", opt->option, opt->var);
146d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		dhcp_print_option_encoding(opt, cols);
147d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
148d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
149d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
150d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define get_option_raw(ctx, dhcp, opt) get_option(ctx, dhcp, opt, NULL)
151d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic const uint8_t *
152d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanget_option(struct dhcpcd_ctx *ctx,
153d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    const struct dhcp_message *dhcp, unsigned int opt, size_t *len)
154d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
155d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const uint8_t *p = dhcp->options;
156d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const uint8_t *e = p + sizeof(dhcp->options);
157d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint8_t l, ol = 0;
158d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint8_t o = 0;
159d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint8_t overl = 0;
160d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint8_t *bp = NULL;
161d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const uint8_t *op = NULL;
162d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t bl = 0;
163d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
164d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Check we have the magic cookie */
165d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (dhcp->cookie != htonl(MAGIC_COOKIE)) {
166d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		errno = ENOTSUP;
167d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return NULL;
168d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
169d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1709ae79b8946de6ac1e295417875f2ac7316dd0f80Samuel Tan	/* DHCP options are in TLV format with T and L each being a single
1719ae79b8946de6ac1e295417875f2ac7316dd0f80Samuel Tan	 * bytes.  In general, here we have p -> T, ol=p+1 -> L, op -> V.
1729ae79b8946de6ac1e295417875f2ac7316dd0f80Samuel Tan	 * We must make sure there is enough room to read both T and L.
1739ae79b8946de6ac1e295417875f2ac7316dd0f80Samuel Tan	 */
1749ae79b8946de6ac1e295417875f2ac7316dd0f80Samuel Tan	while (p + 1 < e) {
175d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		o = *p++;
176d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (o == opt) {
177d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (op) {
178d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				if (!ctx->opt_buffer) {
179d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					ctx->opt_buffer =
180d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					    malloc(DHCP_OPTION_LEN +
181d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					    BOOTFILE_LEN + SERVERNAME_LEN);
182d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					if (ctx->opt_buffer == NULL)
183d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan						return NULL;
184d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				}
185d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				if (!bp)
186d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					bp = ctx->opt_buffer;
187d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				memcpy(bp, op, ol);
188d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				bp += ol;
189d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
1909ae79b8946de6ac1e295417875f2ac7316dd0f80Samuel Tan			ol = (p + *p < e) ? *p : e - (p + 1);
191d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (p + ol > e) {
192d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				errno = EINVAL;
193d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				return NULL;
194d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
195d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			op = p + 1;
196d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			bl += ol;
197d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
198d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		switch (o) {
199d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		case DHO_PAD:
200d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			continue;
201d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		case DHO_END:
202d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (overl & 1) {
203d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				/* bit 1 set means parse boot file */
204d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				overl = (uint8_t)(overl & ~1);
205d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				p = dhcp->bootfile;
206d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				e = p + sizeof(dhcp->bootfile);
207d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			} else if (overl & 2) {
208d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				/* bit 2 set means parse server name */
209d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				overl = (uint8_t)(overl & ~2);
210d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				p = dhcp->servername;
211d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				e = p + sizeof(dhcp->servername);
212d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			} else
213d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				goto exit;
214d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			break;
215d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		case DHO_OPTIONSOVERLOADED:
216d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			/* Ensure we only get this option once by setting
217d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			 * the last bit as well as the value.
218d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			 * This is valid because only the first two bits
219d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			 * actually mean anything in RFC2132 Section 9.3 */
220d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (!overl)
221d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				overl = 0x80 | p[1];
222d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			break;
223d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
224d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		l = *p++;
225d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		p += l;
226d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
227d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
228d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanexit:
229d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (len)
230d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		*len = bl;
231d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (bp) {
232d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		memcpy(bp, op, ol);
233d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return (const uint8_t *)ctx->opt_buffer;
234d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
235d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (op)
236d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return op;
237d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	errno = ENOENT;
238d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return NULL;
239d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
240d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
241d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint
242d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanget_option_addr(struct dhcpcd_ctx *ctx,
243d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    struct in_addr *a, const struct dhcp_message *dhcp,
244d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    uint8_t option)
245d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
246d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const uint8_t *p;
247d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t len;
248d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
249d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	p = get_option(ctx, dhcp, option, &len);
250d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (!p || len < (ssize_t)sizeof(a->s_addr))
251d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
252d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	memcpy(&a->s_addr, p, sizeof(a->s_addr));
253d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return 0;
254d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
255d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
256d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
257d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanget_option_uint32(struct dhcpcd_ctx *ctx,
258d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    uint32_t *i, const struct dhcp_message *dhcp, uint8_t option)
259d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
260d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const uint8_t *p;
261d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t len;
262d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint32_t d;
263d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
264d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	p = get_option(ctx, dhcp, option, &len);
265d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (!p || len < (ssize_t)sizeof(d))
266d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
267d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	memcpy(&d, p, sizeof(d));
268d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (i)
269d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		*i = ntohl(d);
270d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return 0;
271d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
272d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
273d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
274d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanget_option_uint8(struct dhcpcd_ctx *ctx,
275d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    uint8_t *i, const struct dhcp_message *dhcp, uint8_t option)
276d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
277d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const uint8_t *p;
278d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t len;
279d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
280d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	p = get_option(ctx, dhcp, option, &len);
281d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (!p || len < (ssize_t)sizeof(*p))
282d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
283d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (i)
284d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		*i = *(p);
285d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return 0;
286d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
287d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
288d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanssize_t
289d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandecode_rfc3442(char *out, size_t len, const uint8_t *p, size_t pl)
290d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
291d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const uint8_t *e;
292d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t bytes = 0, ocets;
293d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int b;
294d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint8_t cidr;
295d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct in_addr addr;
296d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	char *o = out;
297d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
298d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Minimum is 5 -first is CIDR and a router length of 4 */
299d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (pl < 5) {
300d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		errno = EINVAL;
301d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
302d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
303d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
304d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	e = p + pl;
305d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	while (p < e) {
306d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		cidr = *p++;
307d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (cidr > 32) {
308d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			errno = EINVAL;
309d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return -1;
310d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
311d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ocets = (size_t)(cidr + 7) / NBBY;
312d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (p + 4 + ocets > e) {
313d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			errno = ERANGE;
314d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return -1;
315d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
316d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (!out) {
317d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			p += 4 + ocets;
318d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			bytes += ((4 * 4) * 2) + 4;
319d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			continue;
320d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
321d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if ((((4 * 4) * 2) + 4) > len) {
322d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			errno = ENOBUFS;
323d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return -1;
324d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
325d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (o != out) {
326d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			*o++ = ' ';
327d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			len--;
328d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
329d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* If we have ocets then we have a destination and netmask */
330d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (ocets > 0) {
331d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			addr.s_addr = 0;
332d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			memcpy(&addr.s_addr, p, ocets);
333d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			b = snprintf(o, len, "%s/%d", inet_ntoa(addr), cidr);
334d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			p += ocets;
335d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		} else
336d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			b = snprintf(o, len, "0.0.0.0/0");
337d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		o += b;
338d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		len -= (size_t)b;
339d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
340d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* Finally, snag the router */
341d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		memcpy(&addr.s_addr, p, 4);
342d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		p += 4;
343d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		b = snprintf(o, len, " %s", inet_ntoa(addr));
344d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		o += b;
345d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		len -= (size_t)b;
346d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
347d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
348d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (out)
349d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return o - out;
350d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return (ssize_t)bytes;
351d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
352d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
353d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic struct rt_head *
354d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandecode_rfc3442_rt(struct dhcpcd_ctx *ctx, const uint8_t *data, size_t dl)
355d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
356d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const uint8_t *p = data;
357d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const uint8_t *e;
358d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint8_t cidr;
359d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t ocets;
360d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct rt_head *routes;
361d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct rt *rt = NULL;
362d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
363d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Minimum is 5 -first is CIDR and a router length of 4 */
364d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (dl < 5)
365d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return NULL;
366d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
367d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	routes = malloc(sizeof(*routes));
368d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	TAILQ_INIT(routes);
369d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	e = p + dl;
370d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	while (p < e) {
371d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		cidr = *p++;
372d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (cidr > 32) {
373d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			ipv4_freeroutes(routes);
374d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			errno = EINVAL;
375d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return NULL;
376d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
377d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
378d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ocets = (size_t)(cidr + 7) / NBBY;
379d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (p + 4 + ocets > e) {
380d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			ipv4_freeroutes(routes);
381d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			errno = ERANGE;
382d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return NULL;
383d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
384d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
385d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		rt = calloc(1, sizeof(*rt));
386d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (rt == NULL) {
387d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ctx, LOG_ERR, "%s: %m", __func__);
388d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			ipv4_freeroutes(routes);
389d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return NULL;
390d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
391d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		TAILQ_INSERT_TAIL(routes, rt, next);
392d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
393d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* If we have ocets then we have a destination and netmask */
394d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (ocets > 0) {
395d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			memcpy(&rt->dest.s_addr, p, ocets);
396d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			p += ocets;
397d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			rt->net.s_addr = htonl(~0U << (32 - cidr));
398d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
399d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
400d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* Finally, snag the router */
401d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		memcpy(&rt->gate.s_addr, p, 4);
402d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		p += 4;
403d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
404d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return routes;
405d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
406d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
407d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanchar *
408d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandecode_rfc3361(const uint8_t *data, size_t dl)
409d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
410d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint8_t enc;
411d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t l;
412d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ssize_t r;
413d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	char *sip = NULL;
414d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct in_addr addr;
415d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	char *p;
416d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
417d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (dl < 2) {
418d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		errno = EINVAL;
419d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return 0;
420d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
421d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
422d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	enc = *data++;
423d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	dl--;
424d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	switch (enc) {
425d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	case 0:
426d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if ((r = decode_rfc3397(NULL, 0, data, dl)) > 0) {
427d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			l = (size_t)r;
428d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			sip = malloc(l);
429d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (sip == NULL)
430d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				return 0;
431d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			decode_rfc3397(sip, l, data, dl);
432d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
433d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		break;
434d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	case 1:
435d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (dl == 0 || dl % 4 != 0) {
436d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			errno = EINVAL;
437d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			break;
438d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
439d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		addr.s_addr = INADDR_BROADCAST;
440d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		l = ((dl / sizeof(addr.s_addr)) * ((4 * 4) + 1)) + 1;
441d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		sip = p = malloc(l);
442d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (sip == NULL)
443d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return 0;
444d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		while (dl != 0) {
445d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			memcpy(&addr.s_addr, data, sizeof(addr.s_addr));
446d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			data += sizeof(addr.s_addr);
447d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			p += snprintf(p, l - (size_t)(p - sip),
448d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    "%s ", inet_ntoa(addr));
449d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			dl -= sizeof(addr.s_addr);
450d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
451d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		*--p = '\0';
452d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		break;
453d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	default:
454d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		errno = EINVAL;
455d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return 0;
456d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
457d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
458d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return sip;
459d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
460d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
461d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan/* Decode an RFC5969 6rd order option into a space
462d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * separated string. Returns length of string (including
463d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * terminating zero) or zero on error. */
464d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanssize_t
465d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandecode_rfc5969(char *out, size_t len, const uint8_t *p, size_t pl)
466d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
467d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint8_t ipv4masklen, ipv6prefixlen;
468d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint8_t ipv6prefix[16];
469d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint8_t br[4];
470d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int i;
471d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ssize_t b, bytes = 0;
472d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
473d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (pl < 22) {
474d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		errno = EINVAL;
475d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return 0;
476d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
477d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
478d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ipv4masklen = *p++;
479d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	pl--;
480d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ipv6prefixlen = *p++;
481d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	pl--;
482d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
483d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	for (i = 0; i < 16; i++) {
484d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ipv6prefix[i] = *p++;
485d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		pl--;
486d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
487d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (out) {
488d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		b= snprintf(out, len,
489d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    "%d %d "
490d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    "%02x%02x:%02x%02x:"
491d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    "%02x%02x:%02x%02x:"
492d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    "%02x%02x:%02x%02x:"
493d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    "%02x%02x:%02x%02x",
494d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    ipv4masklen, ipv6prefixlen,
495d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    ipv6prefix[0], ipv6prefix[1], ipv6prefix[2], ipv6prefix[3],
496d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    ipv6prefix[4], ipv6prefix[5], ipv6prefix[6], ipv6prefix[7],
497d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    ipv6prefix[8], ipv6prefix[9], ipv6prefix[10],ipv6prefix[11],
498d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    ipv6prefix[12],ipv6prefix[13],ipv6prefix[14], ipv6prefix[15]
499d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		);
500d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
501d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		len -= (size_t)b;
502d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		out += b;
503d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		bytes += b;
504d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	} else {
505d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		bytes += 16 * 2 + 8 + 2 + 1 + 2;
506d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
507d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
508d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	while (pl >= 4) {
509d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		br[0] = *p++;
510d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		br[1] = *p++;
511d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		br[2] = *p++;
512d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		br[3] = *p++;
513d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		pl -= 4;
514d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
515d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (out) {
516d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			b= snprintf(out, len, " %d.%d.%d.%d",
517d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    br[0], br[1], br[2], br[3]);
518d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			len -= (size_t)b;
519d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			out += b;
520d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			bytes += b;
521d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		} else {
522d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			bytes += (4 * 4);
523d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
524d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
525d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
526d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return bytes;
527d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
528d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
529d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic char *
530d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanget_option_string(struct dhcpcd_ctx *ctx,
531d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    const struct dhcp_message *dhcp, uint8_t option)
532d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
533d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t len;
534d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const uint8_t *p;
535d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	char *s;
536d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
537d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	p = get_option(ctx, dhcp, option, &len);
538d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (!p || len == 0 || *p == '\0')
539d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return NULL;
540d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
541d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	s = malloc(sizeof(char) * (len + 1));
542d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (s) {
543d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		memcpy(s, p, len);
544d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		s[len] = '\0';
545d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
546d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return s;
547d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
548d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
549d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan/* This calculates the netmask that we should use for static routes.
550d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * This IS different from the calculation used to calculate the netmask
551d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * for an interface address. */
552d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic uint32_t
553d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanroute_netmask(uint32_t ip_in)
554d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
555d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* used to be unsigned long - check if error */
556d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint32_t p = ntohl(ip_in);
557d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint32_t t;
558d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
559d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (IN_CLASSA(p))
560d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		t = ~IN_CLASSA_NET;
561d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else {
562d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (IN_CLASSB(p))
563d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			t = ~IN_CLASSB_NET;
564d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		else {
565d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (IN_CLASSC(p))
566d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				t = ~IN_CLASSC_NET;
567d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			else
568d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				t = 0;
569d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
570d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
571d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
572d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	while (t & p)
573d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		t >>= 1;
574d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
575d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return (htonl(~t));
576d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
577d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
578d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan/* We need to obey routing options.
579d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * If we have a CSR then we only use that.
580d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * Otherwise we add static routes and then routers. */
581d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstruct rt_head *
582d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanget_option_routes(struct interface *ifp, const struct dhcp_message *dhcp)
583d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
584d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct if_options *ifo = ifp->options;
585d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const uint8_t *p;
586d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const uint8_t *e;
587d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct rt_head *routes = NULL;
588d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct rt *route = NULL;
589d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t len;
590d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const char *csr = "";
591d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
592d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* If we have CSR's then we MUST use these only */
593d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (!has_option_mask(ifo->nomask, DHO_CSR))
594d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		p = get_option(ifp->ctx, dhcp, DHO_CSR, &len);
595d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else
596d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		p = NULL;
597d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Check for crappy MS option */
598d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (!p && !has_option_mask(ifo->nomask, DHO_MSCSR)) {
599d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		p = get_option(ifp->ctx, dhcp, DHO_MSCSR, &len);
600d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (p)
601d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			csr = "MS ";
602d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
603d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (p) {
604d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		routes = decode_rfc3442_rt(ifp->ctx, p, len);
605d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (routes) {
606d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			const struct dhcp_state *state;
607d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
608d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			state = D_CSTATE(ifp);
609d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (!(ifo->options & DHCPCD_CSR_WARNED) &&
610d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    !(state->added & STATE_FAKE))
611d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			{
612d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				logger(ifp->ctx, LOG_DEBUG,
613d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    "%s: using %sClassless Static Routes",
614d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    ifp->name, csr);
615d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				ifo->options |= DHCPCD_CSR_WARNED;
616d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
617d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return routes;
618d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
619d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
620d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
621d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* OK, get our static routes first. */
622d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	routes = malloc(sizeof(*routes));
623d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (routes == NULL) {
624d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
625d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return NULL;
626d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
627d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	TAILQ_INIT(routes);
628d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (!has_option_mask(ifo->nomask, DHO_STATICROUTE))
629d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		p = get_option(ifp->ctx, dhcp, DHO_STATICROUTE, &len);
630d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else
631d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		p = NULL;
632d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* RFC 2131 Section 5.8 states length MUST be in multiples of 8 */
633d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (p && len % 8 == 0) {
634d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		e = p + len;
635d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		while (p < e) {
636d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if ((route = calloc(1, sizeof(*route))) == NULL) {
637d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
638d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				ipv4_freeroutes(routes);
639d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				return NULL;
640d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
641d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			memcpy(&route->dest.s_addr, p, 4);
642d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			p += 4;
643d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			memcpy(&route->gate.s_addr, p, 4);
644d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			p += 4;
645d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			/* RFC 2131 Section 5.8 states default route is
646d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			 * illegal */
647d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (route->dest.s_addr == htonl(INADDR_ANY)) {
648d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				errno = EINVAL;
649d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				free(route);
650d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				continue;
651d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
652d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			route->net.s_addr = route_netmask(route->dest.s_addr);
653d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			TAILQ_INSERT_TAIL(routes, route, next);
654d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
655d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
656d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
657d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Now grab our routers */
658d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (!has_option_mask(ifo->nomask, DHO_ROUTER))
659d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		p = get_option(ifp->ctx, dhcp, DHO_ROUTER, &len);
660d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else
661d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		p = NULL;
662d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (p) {
663d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		e = p + len;
664d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		while (p < e) {
665d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if ((route = calloc(1, sizeof(*route))) == NULL) {
666d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
667d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				ipv4_freeroutes(routes);
668d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				return NULL;
669d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
670d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			memcpy(&route->gate.s_addr, p, 4);
671d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			p += 4;
672d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			TAILQ_INSERT_TAIL(routes, route, next);
673d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
674d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
675d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
676d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return routes;
677d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
678d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
679d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define PUTADDR(_type, _val)						      \
680d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	{								      \
681d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		*p++ = _type;						      \
682d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		*p++ = 4;						      \
683d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		memcpy(p, &_val.s_addr, 4);				      \
684d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		p += 4;							      \
685d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
686d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
687d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint
688d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_message_add_addr(struct dhcp_message *dhcp,
689d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    uint8_t type, struct in_addr addr)
690d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
691d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint8_t *p;
692d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t len;
693d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
694d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	p = dhcp->options;
695d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	while (*p != DHO_END) {
696d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		p++;
697d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		p += *p + 1;
698d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
699d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
700d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	len = (size_t)(p - (uint8_t *)dhcp);
701d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (len + 6 > sizeof(*dhcp)) {
702d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		errno = ENOMEM;
703d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
704d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
705d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
706d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	PUTADDR(type, addr);
707d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	*p = DHO_END;
708d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return 0;
709d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
710d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
711d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanssize_t
712d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanmake_message(struct dhcp_message **message,
713d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    const struct interface *ifp,
714d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    uint8_t type)
715d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
716d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_message *dhcp;
717d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint8_t *m, *lp, *p, *auth;
718d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint8_t *n_params = NULL, auth_len;
719d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint32_t ul;
720d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint16_t sz;
721d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t len, i;
722d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const struct dhcp_opt *opt;
723d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct if_options *ifo = ifp->options;
724d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const struct dhcp_state *state = D_CSTATE(ifp);
725d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const struct dhcp_lease *lease = &state->lease;
726d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	time_t up = uptime() - state->start_uptime;
727d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	char hbuf[HOSTNAME_MAX_LEN + 1];
728d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const char *hostname;
729d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const struct vivco *vivco;
730d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
731d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	dhcp = calloc(1, sizeof (*dhcp));
732d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (dhcp == NULL)
733d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
734d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	m = (uint8_t *)dhcp;
735d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	p = dhcp->options;
736d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
737d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if ((type == DHCP_INFORM || type == DHCP_RELEASE ||
738d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		(type == DHCP_REQUEST &&
739d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    state->net.s_addr == lease->net.s_addr &&
740d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    (state->new == NULL ||
741d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			state->new->cookie == htonl(MAGIC_COOKIE)))))
742d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	{
743d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		dhcp->ciaddr = state->addr.s_addr;
744d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* In-case we haven't actually configured the address yet */
745d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (type == DHCP_INFORM && state->addr.s_addr == 0)
746d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			dhcp->ciaddr = lease->addr.s_addr;
747d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
748d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
749d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	dhcp->op = DHCP_BOOTREQUEST;
750d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	dhcp->hwtype = (uint8_t)ifp->family;
751d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	switch (ifp->family) {
752d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	case ARPHRD_ETHER:
753d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	case ARPHRD_IEEE802:
754d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		dhcp->hwlen = (uint8_t)ifp->hwlen;
755d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		memcpy(&dhcp->chaddr, &ifp->hwaddr, ifp->hwlen);
756d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		break;
757d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
758d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
759d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifo->options & DHCPCD_BROADCAST &&
760d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    dhcp->ciaddr == 0 &&
761d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    type != DHCP_DECLINE &&
762d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    type != DHCP_RELEASE)
763d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		dhcp->flags = htons(BROADCAST_FLAG);
764d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
765d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (type != DHCP_DECLINE && type != DHCP_RELEASE) {
766d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (up < 0 || up > (time_t)UINT16_MAX)
767d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			dhcp->secs = htons((uint16_t)UINT16_MAX);
768d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		else
769d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			dhcp->secs = htons((uint16_t)up);
770d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
771d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	dhcp->xid = htonl(state->xid);
772d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	dhcp->cookie = htonl(MAGIC_COOKIE);
773d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
774d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (!(ifo->options & DHCPCD_BOOTP)) {
775d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		*p++ = DHO_MESSAGETYPE;
776d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		*p++ = 1;
777d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		*p++ = type;
778d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
779d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
780d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (state->clientid) {
781d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		*p++ = DHO_CLIENTID;
782d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		memcpy(p, state->clientid, (size_t)state->clientid[0] + 1);
783d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		p += state->clientid[0] + 1;
784d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
785d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
786d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (lease->addr.s_addr && lease->cookie == htonl(MAGIC_COOKIE)) {
787d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (type == DHCP_DECLINE ||
788d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    (type == DHCP_REQUEST &&
789d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			lease->addr.s_addr != state->addr.s_addr))
790d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		{
791d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			PUTADDR(DHO_IPADDRESS, lease->addr);
792d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (lease->server.s_addr)
793d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				PUTADDR(DHO_SERVERID, lease->server);
794d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
795d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
796d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (type == DHCP_RELEASE) {
797d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (lease->server.s_addr)
798d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				PUTADDR(DHO_SERVERID, lease->server);
799d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
800d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
801d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
802d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (type == DHCP_DECLINE) {
803d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		*p++ = DHO_MESSAGE;
804d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		len = strlen(DAD);
805d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		*p++ = (uint8_t)len;
806d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		memcpy(p, DAD, len);
807d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		p += len;
808d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
809d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
810d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (type == DHCP_DISCOVER &&
811d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    !(ifp->ctx->options & DHCPCD_TEST) &&
812d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    has_option_mask(ifo->requestmask, DHO_RAPIDCOMMIT))
813d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	{
814d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* RFC 4039 Section 3 */
815d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		*p++ = DHO_RAPIDCOMMIT;
816d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		*p++ = 0;
817d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
818d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
819d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (type == DHCP_DISCOVER && ifo->options & DHCPCD_REQUEST)
820d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		PUTADDR(DHO_IPADDRESS, ifo->req_addr);
821d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
822d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* RFC 2563 Auto Configure */
823d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (type == DHCP_DISCOVER && ifo->options & DHCPCD_IPV4LL) {
824d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		*p++ = DHO_AUTOCONFIGURE;
825d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		*p++ = 1;
826d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		*p++ = 1;
827d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
828d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
829d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (type == DHCP_DISCOVER ||
830d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    type == DHCP_INFORM ||
831d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    type == DHCP_REQUEST)
832d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	{
833d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (!(ifo->options & DHCPCD_BOOTP)) {
834d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			int mtu;
835d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
836d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			*p++ = DHO_MAXMESSAGESIZE;
837d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			*p++ = 2;
838d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			mtu = if_getmtu(ifp->name);
839d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (mtu < MTU_MIN) {
840d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				if (if_setmtu(ifp->name, MTU_MIN) == 0)
841d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					sz = MTU_MIN;
842d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			} else if (mtu > MTU_MAX) {
843d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				/* Even though our MTU could be greater than
844d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				 * MTU_MAX (1500) dhcpcd does not presently
845d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				 * handle DHCP packets any bigger. */
846d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				mtu = MTU_MAX;
847d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
848d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			sz = htons((uint16_t)mtu);
849d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			memcpy(p, &sz, 2);
850d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			p += 2;
851d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
852d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
853d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (ifo->userclass[0]) {
854d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			*p++ = DHO_USERCLASS;
855d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			memcpy(p, ifo->userclass,
856d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    (size_t)ifo->userclass[0] + 1);
857d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			p += ifo->userclass[0] + 1;
858d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
859d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
860d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (ifo->vendorclassid[0]) {
861d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			*p++ = DHO_VENDORCLASSID;
862d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			memcpy(p, ifo->vendorclassid,
863d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    (size_t)ifo->vendorclassid[0] + 1);
864d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			p += ifo->vendorclassid[0] + 1;
865d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
866d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
867d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (type != DHCP_INFORM) {
868d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (ifo->leasetime != 0) {
869d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				*p++ = DHO_LEASETIME;
870d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				*p++ = 4;
871d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				ul = htonl(ifo->leasetime);
872d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				memcpy(p, &ul, 4);
873d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				p += 4;
874d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
875d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
876d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
877d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (ifo->hostname[0] == '\0')
878d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			hostname = get_hostname(hbuf, sizeof(hbuf),
879d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    ifo->options & DHCPCD_HOSTNAME_SHORT ? 1 : 0);
880d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		else
881d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			hostname = ifo->hostname;
882d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
883d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/*
884d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		 * RFC4702 3.1 States that if we send the Client FQDN option
885d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		 * then we MUST NOT also send the Host Name option.
886d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		 * Technically we could, but that is not RFC conformant and
887d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		 * also seems to break some DHCP server implemetations such as
888d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		 * Windows. On the other hand, ISC dhcpd is just as non RFC
889d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		 * conformant by not accepting a partially qualified FQDN.
890d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		 */
891d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (ifo->fqdn != FQDN_DISABLE) {
892d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			/* IETF DHC-FQDN option (81), RFC4702 */
893d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			*p++ = DHO_FQDN;
894d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			lp = p;
895d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			*p++ = 3;
896d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			/*
897d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			 * Flags: 0000NEOS
898d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			 * S: 1 => Client requests Server to update
899d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			 *         a RR in DNS as well as PTR
900d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			 * O: 1 => Server indicates to client that
901d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			 *         DNS has been updated
902d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			 * E: 1 => Name data is DNS format
903d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			 * N: 1 => Client requests Server to not
904d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			 *         update DNS
905d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			 */
906d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (hostname)
907d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				*p++ = (uint8_t)((ifo->fqdn & 0x09) | 0x04);
908d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			else
909d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				*p++ = (FQDN_NONE & 0x09) | 0x04;
910d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			*p++ = 0; /* from server for PTR RR */
911d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			*p++ = 0; /* from server for A RR if S=1 */
912d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (hostname) {
913d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				i = encode_rfc1035(hostname, p);
914d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				*lp = (uint8_t)(*lp + i);
915d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				p += i;
916d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
917d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		} else if (ifo->options & DHCPCD_HOSTNAME && hostname) {
918d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			*p++ = DHO_HOSTNAME;
919d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			len = strlen(hostname);
920d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			*p++ = (uint8_t)len;
921d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			memcpy(p, hostname, len);
922d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			p += len;
923d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
924d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
925d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* vendor is already encoded correctly, so just add it */
926d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (ifo->vendor[0]) {
927d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			*p++ = DHO_VENDOR;
928d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			memcpy(p, ifo->vendor, (size_t)ifo->vendor[0] + 1);
929d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			p += ifo->vendor[0] + 1;
930d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
931d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
932d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if ((ifo->auth.options & DHCPCD_AUTH_SENDREQUIRE) !=
933d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    DHCPCD_AUTH_SENDREQUIRE)
934d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		{
935d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			/* We support HMAC-MD5 */
936d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			*p++ = DHO_FORCERENEW_NONCE;
937d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			*p++ = 1;
938d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			*p++ = AUTH_ALG_HMAC_MD5;
939d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
940d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
941d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (ifo->vivco_len) {
942d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			*p++ = DHO_VIVCO;
943d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			lp = p++;
944d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			*lp = sizeof(ul);
945d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			ul = htonl(ifo->vivco_en);
946d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			memcpy(p, &ul, sizeof(ul));
947d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			p += sizeof(ul);
948d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			for (i = 0, vivco = ifo->vivco;
949d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    i < ifo->vivco_len;
950d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    i++, vivco++)
951d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			{
952d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				len = (size_t)(p - m) + vivco->len + 1;
953d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				if (len > sizeof(*dhcp))
954d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					goto toobig;
955d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				if (vivco->len + 2 + *lp > 255) {
956d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					logger(ifp->ctx, LOG_ERR,
957d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					    "%s: VIVCO option too big",
958d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					    ifp->name);
959d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					free(dhcp);
960d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					return -1;
961d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				}
962d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				*p++ = (uint8_t)vivco->len;
963d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				memcpy(p, vivco->data, vivco->len);
964d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				p += vivco->len;
965d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				*lp = (uint8_t)(*lp + vivco->len + 1);
966d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
967d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
968d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
969d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		len = (size_t)((p - m) + 3);
970d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (len > sizeof(*dhcp))
971d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			goto toobig;
972d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		*p++ = DHO_PARAMETERREQUESTLIST;
973d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		n_params = p;
974d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		*p++ = 0;
975d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		for (i = 0, opt = ifp->ctx->dhcp_opts;
976d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    i < ifp->ctx->dhcp_opts_len;
977d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    i++, opt++)
978d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		{
979d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (!(opt->type & REQUEST ||
980d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    has_option_mask(ifo->requestmask, opt->option)))
981d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				continue;
982d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (opt->type & NOREQ)
983d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				continue;
984d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (type == DHCP_INFORM &&
985d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    (opt->option == DHO_RENEWALTIME ||
986d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				opt->option == DHO_REBINDTIME))
987d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				continue;
988d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			len = (size_t)((p - m) + 2);
989d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (len > sizeof(*dhcp))
990d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				goto toobig;
991d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			*p++ = (uint8_t)opt->option;
992d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
993d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		for (i = 0, opt = ifo->dhcp_override;
994d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    i < ifo->dhcp_override_len;
995d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    i++, opt++)
996d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		{
997d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			/* Check if added above */
998d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			for (lp = n_params + 1; lp < p; lp++)
999d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				if (*lp == (uint8_t)opt->option)
1000d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					break;
1001d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (lp < p)
1002d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				continue;
1003d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (!(opt->type & REQUEST ||
1004d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    has_option_mask(ifo->requestmask, opt->option)))
1005d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				continue;
1006d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (opt->type & NOREQ)
1007d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				continue;
1008d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (type == DHCP_INFORM &&
1009d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    (opt->option == DHO_RENEWALTIME ||
1010d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				opt->option == DHO_REBINDTIME))
1011d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				continue;
1012d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			len = (size_t)((p - m) + 2);
1013d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (len > sizeof(*dhcp))
1014d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				goto toobig;
1015d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			*p++ = (uint8_t)opt->option;
1016d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
1017d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		*n_params = (uint8_t)(p - n_params - 1);
1018d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1019d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1020d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* silence GCC */
1021d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	auth_len = 0;
1022d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	auth = NULL;
1023d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1024d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifo->auth.options & DHCPCD_AUTH_SEND) {
1025d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ssize_t alen = dhcp_auth_encode(&ifo->auth,
1026d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    state->auth.token,
1027d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    NULL, 0, 4, type, NULL, 0);
1028d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (alen != -1 && alen > UINT8_MAX) {
1029d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			errno = ERANGE;
1030d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			alen = -1;
1031d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
1032d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (alen == -1)
1033d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ifp->ctx, LOG_ERR,
1034d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    "%s: dhcp_auth_encode: %m", ifp->name);
1035d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		else if (alen != 0) {
1036d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			auth_len = (uint8_t)alen;
1037d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			len = (size_t)((p + alen) - m);
1038d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (len > sizeof(*dhcp))
1039d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				goto toobig;
1040d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			*p++ = DHO_AUTHENTICATION;
1041d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			*p++ = auth_len;
1042d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			auth = p;
1043d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			p += auth_len;
1044d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
1045d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1046d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1047d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	*p++ = DHO_END;
1048d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1049d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Pad out to the BOOTP minimum message length.
1050d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * Some DHCP servers incorrectly require this. */
1051d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	while (p - m < BOOTP_MESSAGE_LENTH_MIN)
1052d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		*p++ = DHO_PAD;
1053d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1054d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	len = (size_t)(p - m);
1055d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifo->auth.options & DHCPCD_AUTH_SEND && auth_len != 0)
1056d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		dhcp_auth_encode(&ifo->auth, state->auth.token,
1057d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    m, len, 4, type, auth, auth_len);
1058d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1059d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	*message = dhcp;
1060d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return (ssize_t)len;
1061d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1062d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tantoobig:
1063d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	logger(ifp->ctx, LOG_ERR, "%s: DHCP messge too big", ifp->name);
1064d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	free(dhcp);
1065d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return -1;
1066d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1067d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1068d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic ssize_t
1069d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanwrite_lease(const struct interface *ifp, const struct dhcp_message *dhcp)
1070d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1071d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int fd;
1072d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t len;
1073d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ssize_t bytes;
1074d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const uint8_t *e, *p;
1075d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint8_t l;
1076d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint8_t o = 0;
1077d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const struct dhcp_state *state = D_CSTATE(ifp);
1078f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	uint8_t write_buffer[sizeof(*dhcp) + sizeof(state->server_info) + 1];
1079f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	uint8_t *w;
1080d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1081d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* We don't write BOOTP leases */
1082d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (IS_BOOTP(ifp, dhcp)) {
1083d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		unlink(state->leasefile);
1084d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return 0;
1085d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1086d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1087d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	logger(ifp->ctx, LOG_DEBUG, "%s: writing lease `%s'",
1088d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    ifp->name, state->leasefile);
1089d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1090dd90b01b5502dc66e00ea6a4d00ebdf77ea1eddcSamuel Tan	fd = open(state->leasefile, O_WRONLY | O_CREAT | O_TRUNC, 0600);
1091d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (fd == -1)
1092d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
1093d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1094d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Only write as much as we need */
1095d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	p = dhcp->options;
1096d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	e = p + sizeof(dhcp->options);
1097d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	len = sizeof(*dhcp);
1098d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	while (p < e) {
1099d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		o = *p;
1100d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (o == DHO_END) {
1101d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			len = (size_t)(p - (const uint8_t *)dhcp);
1102d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			break;
1103d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
1104d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		p++;
1105d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (o != DHO_PAD) {
1106d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			l = *p++;
1107d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			p += l;
1108d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
1109d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1110f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan
1111f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	memcpy(write_buffer, dhcp, len);
1112f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	w = write_buffer + len;
1113f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan
1114f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	/* Copy in server info if this is available. */
1115f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	if (state->server_info.gw_hwlen != 0) {
1116f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan		*w++ = DHO_END;
1117f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan		memcpy(w, &state->server_info, sizeof(state->server_info));
1118f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan		len += sizeof(state->server_info) + 1;
1119f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	}
1120f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan
1121f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	bytes = write(fd, write_buffer, len);
1122d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	close(fd);
1123d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return bytes;
1124d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1125d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1126d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic struct dhcp_message *
1127d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanread_lease(struct interface *ifp)
1128d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1129d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int fd;
1130d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_message *dhcp;
1131d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_state *state = D_STATE(ifp);
1132f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	uint8_t read_buffer[sizeof(*dhcp) + sizeof(state->server_info) + 1];
1133f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	const uint8_t *options_startp =
1134f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan			read_buffer + offsetof(struct dhcp_message, options);
1135f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	const uint8_t *options_endp = options_startp + sizeof(dhcp->options);
1136f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	uint8_t option_len;
1137f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	uint8_t option_type = 0;
1138d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ssize_t bytes;
1139d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const uint8_t *auth;
1140d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint8_t type;
1141d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t auth_len;
1142d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1143f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	memset(&state->server_info, 0, sizeof(state->server_info));
1144d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	fd = open(state->leasefile, O_RDONLY);
1145d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (fd == -1) {
1146d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (errno != ENOENT)
1147d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ifp->ctx, LOG_ERR, "%s: open `%s': %m",
1148d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    ifp->name, state->leasefile);
1149d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return NULL;
1150d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1151d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	logger(ifp->ctx, LOG_DEBUG, "%s: reading lease `%s'",
1152d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    ifp->name, state->leasefile);
1153f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	bytes = read(fd, read_buffer, sizeof(read_buffer));
1154f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	close(fd);
1155f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan
1156f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	/* Lease file should at minimum contain all fields before options. */
1157f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	if (read_buffer + bytes < options_startp)
1158f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan		return NULL;
1159f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan
1160d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	dhcp = calloc(1, sizeof(*dhcp));
1161d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (dhcp == NULL) {
1162d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return NULL;
1163d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1164f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan
1165f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	if (options_endp > read_buffer + bytes)
1166f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan		options_endp = read_buffer + bytes;
1167f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan
1168f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	while (options_startp < options_endp) {
1169f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan		option_type = *options_startp++;
1170f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan		if (option_type == DHO_END)
1171f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan			break;
1172f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan		if (option_type != DHO_PAD) {
1173f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan			option_len = *options_startp++;
1174f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan			options_startp += option_len;
1175f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan		}
1176d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1177f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	memcpy(dhcp, read_buffer, options_startp - read_buffer);
1178d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1179d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* We may have found a BOOTP server */
1180d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (get_option_uint8(ifp->ctx, &type, dhcp, DHO_MESSAGETYPE) == -1)
1181d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		type = 0;
1182d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1183d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Authenticate the message */
1184d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	auth = get_option(ifp->ctx, dhcp, DHO_AUTHENTICATION, &auth_len);
1185d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (auth) {
1186d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (dhcp_auth_validate(&state->auth, &ifp->options->auth,
1187d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    (uint8_t *)dhcp, sizeof(*dhcp), 4, type,
1188d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    auth, auth_len) == NULL)
1189d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		{
1190d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ifp->ctx, LOG_DEBUG,
1191d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    "%s: dhcp_auth_validate: %m", ifp->name);
1192d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			free(dhcp);
1193d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return NULL;
1194d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
1195d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (state->auth.token)
1196d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ifp->ctx, LOG_DEBUG,
1197d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    "%s: validated using 0x%08" PRIu32,
1198d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    ifp->name, state->auth.token->secretid);
1199d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		else
1200d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ifp->ctx, LOG_DEBUG,
1201d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    "%s: accepted reconfigure key", ifp->name);
1202d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1203d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1204f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	/*
1205f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	 * DHCP server information is stored after the DHO_END character
1206f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	 * in the lease file.  The first byte of the server information
1207f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	 * is the length of the gateway hardware address.
1208f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	 */
1209f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	options_endp = read_buffer + bytes;
1210f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	if (options_startp >= options_endp ||
1211f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	    options_startp + sizeof(state->server_info) > options_endp)
1212f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan		return dhcp;
1213f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan
1214f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	logger(ifp->ctx, LOG_DEBUG, "%s: found server info in lease '%s'",
1215f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	       ifp->name, state->leasefile);
1216f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan
1217f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	memcpy(&state->server_info, options_startp, sizeof(state->server_info));
1218f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	if (state->server_info.gw_hwlen != ifp->hwlen) {
1219f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan		logger(ifp->ctx, LOG_ERR, "%s: lease file %s has incompatible"
1220f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan		       "MAC address length %d (expected %zd)",
1221f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan		       ifp->name, state->leasefile,
1222f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan		       state->server_info.gw_hwlen, ifp->hwlen);
1223f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan		memset(&state->server_info, 0, sizeof(state->server_info));
1224f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	}
1225d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return dhcp;
1226d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1227d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1228d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic const struct dhcp_opt *
1229d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_getoverride(const struct if_options *ifo, unsigned int o)
1230d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1231d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t i;
1232d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const struct dhcp_opt *opt;
1233d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1234d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	for (i = 0, opt = ifo->dhcp_override;
1235d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    i < ifo->dhcp_override_len;
1236d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    i++, opt++)
1237d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	{
1238d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (opt->option == o)
1239d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return opt;
1240d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1241d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return NULL;
1242d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1243d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1244d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic const uint8_t *
1245d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_getoption(struct dhcpcd_ctx *ctx,
1246d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    size_t *os, unsigned int *code, size_t *len,
1247d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    const uint8_t *od, size_t ol, struct dhcp_opt **oopt)
1248d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1249d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t i;
1250d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_opt *opt;
1251d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1252d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (od) {
1253d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (ol < 2) {
1254d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			errno = EINVAL;
1255d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return NULL;
1256d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
1257d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		*os = 2; /* code + len */
1258d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		*code = (unsigned int)*od++;
1259d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		*len = (size_t)*od++;
1260b745ca9d2d2d127870e6245c50417fc778080e6aSamuel Tan		if (*len > ol - *os) {
1261d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			errno = EINVAL;
1262d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return NULL;
1263d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
1264d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1265d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1266b745ca9d2d2d127870e6245c50417fc778080e6aSamuel Tan	*oopt = NULL;
1267d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	for (i = 0, opt = ctx->dhcp_opts; i < ctx->dhcp_opts_len; i++, opt++) {
1268d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (opt->option == *code) {
1269d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			*oopt = opt;
1270d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			break;
1271d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
1272d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1273d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1274d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return od;
1275d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1276d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1277d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanssize_t
1278d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_env(char **env, const char *prefix, const struct dhcp_message *dhcp,
1279d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    const struct interface *ifp)
1280d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1281d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const struct if_options *ifo;
1282d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const uint8_t *p;
1283d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct in_addr addr;
1284d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct in_addr net;
1285d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct in_addr brd;
1286d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_opt *opt, *vo;
1287d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t e, i, pl;
1288d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	char **ep;
1289d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	char cidr[4], safe[(BOOTFILE_LEN * 4) + 1];
1290d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint8_t overl = 0;
1291d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint32_t en;
1292d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1293d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	e = 0;
1294d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ifo = ifp->options;
1295d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	get_option_uint8(ifp->ctx, &overl, dhcp, DHO_OPTIONSOVERLOADED);
1296d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1297d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (env == NULL) {
1298d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (dhcp->yiaddr || dhcp->ciaddr)
1299d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			e += 5;
1300d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (*dhcp->bootfile && !(overl & 1))
1301d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			e++;
1302d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (*dhcp->servername && !(overl & 2))
1303d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			e++;
1304d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		for (i = 0, opt = ifp->ctx->dhcp_opts;
1305d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    i < ifp->ctx->dhcp_opts_len;
1306d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    i++, opt++)
1307d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		{
1308d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (has_option_mask(ifo->nomask, opt->option))
1309d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				continue;
1310d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (dhcp_getoverride(ifo, opt->option))
1311d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				continue;
1312d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			p = get_option(ifp->ctx, dhcp, opt->option, &pl);
1313d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (!p)
1314d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				continue;
1315d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			e += dhcp_envoption(ifp->ctx, NULL, NULL, ifp->name,
1316d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    opt, dhcp_getoption, p, pl);
1317d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
1318d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		for (i = 0, opt = ifo->dhcp_override;
1319d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    i < ifo->dhcp_override_len;
1320d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    i++, opt++)
1321d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		{
1322d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (has_option_mask(ifo->nomask, opt->option))
1323d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				continue;
1324d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			p = get_option(ifp->ctx, dhcp, opt->option, &pl);
1325d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (!p)
1326d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				continue;
1327d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			e += dhcp_envoption(ifp->ctx, NULL, NULL, ifp->name,
1328d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    opt, dhcp_getoption, p, pl);
1329d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
1330d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return (ssize_t)e;
1331d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1332d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1333d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ep = env;
1334d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (dhcp->yiaddr || dhcp->ciaddr) {
1335d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* Set some useful variables that we derive from the DHCP
1336d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		 * message but are not necessarily in the options */
1337d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		addr.s_addr = dhcp->yiaddr ? dhcp->yiaddr : dhcp->ciaddr;
1338d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		setvar(ifp->ctx, &ep, prefix, "ip_address", inet_ntoa(addr));
1339d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (get_option_addr(ifp->ctx, &net,
1340d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    dhcp, DHO_SUBNETMASK) == -1) {
1341d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			net.s_addr = ipv4_getnetmask(addr.s_addr);
1342d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			setvar(ifp->ctx, &ep, prefix,
1343d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    "subnet_mask", inet_ntoa(net));
1344d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
1345d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		snprintf(cidr, sizeof(cidr), "%d", inet_ntocidr(net));
1346d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		setvar(ifp->ctx, &ep, prefix, "subnet_cidr", cidr);
1347d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (get_option_addr(ifp->ctx, &brd,
1348d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    dhcp, DHO_BROADCAST) == -1) {
1349d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			brd.s_addr = addr.s_addr | ~net.s_addr;
1350d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			setvar(ifp->ctx, &ep, prefix,
1351d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    "broadcast_address", inet_ntoa(brd));
1352d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
1353d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		addr.s_addr = dhcp->yiaddr & net.s_addr;
1354d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		setvar(ifp->ctx, &ep, prefix,
1355d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    "network_number", inet_ntoa(addr));
1356d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1357d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1358d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (*dhcp->bootfile && !(overl & 1)) {
1359d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		print_string(safe, sizeof(safe), STRING,
1360d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    dhcp->bootfile, sizeof(dhcp->bootfile));
1361d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		setvar(ifp->ctx, &ep, prefix, "filename", safe);
1362d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1363d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (*dhcp->servername && !(overl & 2)) {
1364d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		print_string(safe, sizeof(safe), STRING | DOMAIN,
1365d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    dhcp->servername, sizeof(dhcp->servername));
1366d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		setvar(ifp->ctx, &ep, prefix, "server_name", safe);
1367d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1368d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1369d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Zero our indexes */
1370d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (env) {
1371d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		for (i = 0, opt = ifp->ctx->dhcp_opts;
1372d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    i < ifp->ctx->dhcp_opts_len;
1373d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    i++, opt++)
1374d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			dhcp_zero_index(opt);
1375d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		for (i = 0, opt = ifp->options->dhcp_override;
1376d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    i < ifp->options->dhcp_override_len;
1377d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    i++, opt++)
1378d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			dhcp_zero_index(opt);
1379d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		for (i = 0, opt = ifp->ctx->vivso;
1380d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    i < ifp->ctx->vivso_len;
1381d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    i++, opt++)
1382d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			dhcp_zero_index(opt);
1383d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1384d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1385d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	for (i = 0, opt = ifp->ctx->dhcp_opts;
1386d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    i < ifp->ctx->dhcp_opts_len;
1387d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    i++, opt++)
1388d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	{
1389d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (has_option_mask(ifo->nomask, opt->option))
1390d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			continue;
1391d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (dhcp_getoverride(ifo, opt->option))
1392d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			continue;
1393d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if ((p = get_option(ifp->ctx, dhcp, opt->option, &pl))) {
1394d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			ep += dhcp_envoption(ifp->ctx, ep, prefix, ifp->name,
1395d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    opt, dhcp_getoption, p, pl);
1396d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (opt->option == DHO_VIVSO &&
1397d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    pl > (int)sizeof(uint32_t))
1398d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			{
1399d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			        memcpy(&en, p, sizeof(en));
1400d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				en = ntohl(en);
1401d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				vo = vivso_find(en, ifp);
1402d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				if (vo) {
1403d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					/* Skip over en + total size */
1404d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					p += sizeof(en) + 1;
1405d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					pl -= sizeof(en) + 1;
1406d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					ep += dhcp_envoption(ifp->ctx,
1407d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					    ep, prefix, ifp->name,
1408d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					    vo, dhcp_getoption, p, pl);
1409d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				}
1410d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
1411d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
1412d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1413d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1414d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	for (i = 0, opt = ifo->dhcp_override;
1415d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    i < ifo->dhcp_override_len;
1416d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    i++, opt++)
1417d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	{
1418d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (has_option_mask(ifo->nomask, opt->option))
1419d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			continue;
1420d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if ((p = get_option(ifp->ctx, dhcp, opt->option, &pl)))
1421d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			ep += dhcp_envoption(ifp->ctx, ep, prefix, ifp->name,
1422d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    opt, dhcp_getoption, p, pl);
1423d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1424d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1425d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return ep - env;
1426d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1427d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1428d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void
1429d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanget_lease(struct dhcpcd_ctx *ctx,
1430d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    struct dhcp_lease *lease, const struct dhcp_message *dhcp)
1431d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1432d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1433d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	lease->cookie = dhcp->cookie;
1434d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* BOOTP does not set yiaddr for replies when ciaddr is set. */
1435d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (dhcp->yiaddr)
1436d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		lease->addr.s_addr = dhcp->yiaddr;
1437d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else
1438d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		lease->addr.s_addr = dhcp->ciaddr;
1439d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (get_option_addr(ctx, &lease->net, dhcp, DHO_SUBNETMASK) == -1)
1440d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		lease->net.s_addr = ipv4_getnetmask(lease->addr.s_addr);
1441d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (get_option_addr(ctx, &lease->brd, dhcp, DHO_BROADCAST) == -1)
1442d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		lease->brd.s_addr = lease->addr.s_addr | ~lease->net.s_addr;
1443d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (get_option_uint32(ctx, &lease->leasetime, dhcp, DHO_LEASETIME) != 0)
1444d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		lease->leasetime = ~0U; /* Default to infinite lease */
1445d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (get_option_uint32(ctx, &lease->renewaltime,
1446d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    dhcp, DHO_RENEWALTIME) != 0)
1447d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		lease->renewaltime = 0;
1448d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (get_option_uint32(ctx, &lease->rebindtime,
1449d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    dhcp, DHO_REBINDTIME) != 0)
1450d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		lease->rebindtime = 0;
1451d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (get_option_addr(ctx, &lease->server, dhcp, DHO_SERVERID) != 0)
1452d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		lease->server.s_addr = INADDR_ANY;
1453d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1454d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1455d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic const char *
1456d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanget_dhcp_op(uint8_t type)
1457d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1458d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const struct dhcp_op *d;
1459d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1460d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	for (d = dhcp_ops; d->name; d++)
1461d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (d->value == type)
1462d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return d->name;
1463d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return NULL;
1464d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1465d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1466d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void
1467d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_fallback(void *arg)
1468d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1469d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct interface *iface;
1470d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1471d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	iface = (struct interface *)arg;
1472d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	dhcpcd_selectprofile(iface, iface->options->fallback);
1473d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	dhcpcd_startinterface(iface);
1474d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1475d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1476d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanuint32_t
1477d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_xid(const struct interface *ifp)
1478d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1479d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint32_t xid;
1480d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1481d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifp->options->options & DHCPCD_XID_HWADDR &&
1482d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    ifp->hwlen >= sizeof(xid))
1483d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* The lower bits are probably more unique on the network */
1484d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		memcpy(&xid, (ifp->hwaddr + ifp->hwlen) - sizeof(xid),
1485d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    sizeof(xid));
1486d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else
1487d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		xid = arc4random();
1488d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1489d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return xid;
1490d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1491d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1492d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanvoid
1493d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_close(struct interface *ifp)
1494d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1495d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_state *state = D_STATE(ifp);
1496d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1497d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (state == NULL)
1498d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
1499d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1500d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (state->raw_fd != -1) {
1501d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		eloop_event_delete(ifp->ctx->eloop, state->raw_fd, 0);
1502d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		close(state->raw_fd);
1503d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		state->raw_fd = -1;
1504d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1505d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1506d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->interval = 0;
1507d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1508d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1509d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
1510d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_openudp(struct interface *ifp)
1511d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1512d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int s;
1513d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct sockaddr_in sin;
1514d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int n;
1515d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_state *state;
1516d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef SO_BINDTODEVICE
1517d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct ifreq ifr;
1518d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	char *p;
1519d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
1520d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1521d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef SOCK_CLOEXEC
1522d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if ((s = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP)) == -1)
1523d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
1524d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#else
1525d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if ((s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
1526d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
1527d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if ((n = fcntl(s, F_GETFD, 0)) == -1 ||
1528d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    fcntl(s, F_SETFD, n | FD_CLOEXEC) == -1)
1529d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	{
1530d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		close(s);
1531d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	        return -1;
1532d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1533d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
1534d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1535d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	n = 1;
1536d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) == -1)
1537d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		goto eexit;
1538d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef SO_BINDTODEVICE
1539d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifp) {
1540d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		memset(&ifr, 0, sizeof(ifr));
1541d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
1542d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* We can only bind to the real device */
1543d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		p = strchr(ifr.ifr_name, ':');
1544d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (p)
1545d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			*p = '\0';
1546d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, &ifr,
1547d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    sizeof(ifr)) == -1)
1548d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		        goto eexit;
1549d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1550d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
1551d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	memset(&sin, 0, sizeof(sin));
1552d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	sin.sin_family = AF_INET;
1553d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	sin.sin_port = htons(DHCP_CLIENT_PORT);
1554d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifp) {
1555d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		state = D_STATE(ifp);
1556d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		sin.sin_addr.s_addr = state->addr.s_addr;
1557d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	} else
1558d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		state = NULL; /* appease gcc */
1559d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) == -1)
1560d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		goto eexit;
1561d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1562d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return s;
1563d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1564d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Taneexit:
1565d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	close(s);
1566d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return -1;
1567d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1568d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1569d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic uint16_t
1570d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanchecksum(const void *data, unsigned int len)
1571d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1572d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const uint8_t *addr = data;
1573d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint32_t sum = 0;
1574d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1575d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	while (len > 1) {
1576d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		sum += (uint32_t)(addr[0] * 256 + addr[1]);
1577d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		addr += 2;
1578d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		len -= 2;
1579d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1580d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1581d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (len == 1)
1582d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		sum += (uint32_t)(*addr * 256);
1583d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1584d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	sum = (sum >> 16) + (sum & 0xffff);
1585d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	sum += (sum >> 16);
1586d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1587d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return (uint16_t)~htons((uint16_t)sum);
1588d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1589d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1590d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic struct udp_dhcp_packet *
1591d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_makeudppacket(size_t *sz, const uint8_t *data, size_t length,
1592d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct in_addr source, struct in_addr dest)
1593d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1594d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct udp_dhcp_packet *udpp;
1595d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct ip *ip;
1596d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct udphdr *udp;
1597d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1598d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	udpp = calloc(1, sizeof(*udpp));
1599d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (udpp == NULL)
1600d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return NULL;
1601d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ip = &udpp->ip;
1602d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	udp = &udpp->udp;
1603d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1604d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* OK, this is important :)
1605d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * We copy the data to our packet and then create a small part of the
1606d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * ip structure and an invalid ip_len (basically udp length).
1607d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * We then fill the udp structure and put the checksum
1608d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * of the whole packet into the udp checksum.
1609d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * Finally we complete the ip structure and ip checksum.
1610d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * If we don't do the ordering like so then the udp checksum will be
1611d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * broken, so find another way of doing it! */
1612d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1613d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	memcpy(&udpp->dhcp, data, length);
1614d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1615d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ip->ip_p = IPPROTO_UDP;
1616d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ip->ip_src.s_addr = source.s_addr;
1617d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (dest.s_addr == 0)
1618d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ip->ip_dst.s_addr = INADDR_BROADCAST;
1619d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else
1620d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ip->ip_dst.s_addr = dest.s_addr;
1621d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1622d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	udp->uh_sport = htons(DHCP_CLIENT_PORT);
1623d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	udp->uh_dport = htons(DHCP_SERVER_PORT);
1624d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	udp->uh_ulen = htons((uint16_t)(sizeof(*udp) + length));
1625d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ip->ip_len = udp->uh_ulen;
1626d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	udp->uh_sum = checksum(udpp, sizeof(*udpp));
1627d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1628d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ip->ip_v = IPVERSION;
1629d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ip->ip_hl = sizeof(*ip) >> 2;
1630d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ip->ip_id = (uint16_t)arc4random_uniform(UINT16_MAX);
1631d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ip->ip_ttl = IPDEFTTL;
1632d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ip->ip_len = htons((uint16_t)(sizeof(*ip) + sizeof(*udp) + length));
1633d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ip->ip_sum = checksum(ip, sizeof(*ip));
1634d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1635d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	*sz = sizeof(*ip) + sizeof(*udp) + length;
1636d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return udpp;
1637d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1638d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1639d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void
1640d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tansend_message(struct interface *ifp, uint8_t type,
1641d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    void (*callback)(void *))
1642d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1643d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_state *state = D_STATE(ifp);
1644d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct if_options *ifo = ifp->options;
1645d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_message *dhcp;
1646d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct udp_dhcp_packet *udp;
1647d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t len;
1648d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ssize_t r;
1649d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct in_addr from, to;
1650d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	in_addr_t a = INADDR_ANY;
1651d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct timespec tv;
1652d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int s;
1653d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef IN_IFF_NOTUSEABLE
1654d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct ipv4_addr *ia;
1655d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
1656d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1657d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (!callback)
165824aa62eefd9284fb94820093f6088607d42c4249Samuel Tan		logger(ifp->ctx, LOG_INFO, "%s: sending %s with xid 0x%x",
1659d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    ifp->name,
1660d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    ifo->options & DHCPCD_BOOTP ? "BOOTP" : get_dhcp_op(type),
1661d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    state->xid);
1662d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else {
1663d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (state->interval == 0)
1664e942e091ac1efb0ee1916add2b12f64fdfd59476Samuel Tan			state->interval = DHCP_BASE;
1665d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		else {
1666d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			state->interval *= 2;
1667e942e091ac1efb0ee1916add2b12f64fdfd59476Samuel Tan			if (state->interval > DHCP_MAX)
1668e942e091ac1efb0ee1916add2b12f64fdfd59476Samuel Tan				state->interval = DHCP_MAX;
1669d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
1670d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		tv.tv_sec = state->interval + DHCP_RAND_MIN;
1671d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		tv.tv_nsec = (suseconds_t)arc4random_uniform(
1672d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    (DHCP_RAND_MAX - DHCP_RAND_MIN) * NSEC_PER_SEC);
1673d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		timespecnorm(&tv);
167424aa62eefd9284fb94820093f6088607d42c4249Samuel Tan		logger(ifp->ctx, LOG_INFO,
1675d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    "%s: sending %s (xid 0x%x), next in %0.1f seconds",
1676d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    ifp->name,
1677d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    ifo->options & DHCPCD_BOOTP ? "BOOTP" : get_dhcp_op(type),
1678d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    state->xid,
1679d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    timespec_to_double(&tv));
1680d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1681d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1682d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (dhcp_open(ifp) == -1)
1683d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
1684d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1685d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (state->added && !(state->added & STATE_FAKE) &&
1686d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    state->addr.s_addr != INADDR_ANY &&
1687d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    state->new != NULL &&
1688d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef IN_IFF_NOTUSEABLE
1689d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    ((ia = ipv4_iffindaddr(ifp, &state->addr, NULL)) &&
1690d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    !(ia->addr_flags & IN_IFF_NOTUSEABLE)) &&
1691d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
1692d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    (state->new->cookie == htonl(MAGIC_COOKIE) ||
1693d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    ifp->options->options & DHCPCD_INFORM))
1694d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	{
1695d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		s = dhcp_openudp(ifp);
1696d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (s == -1 && errno != EADDRINUSE)
1697d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ifp->ctx, LOG_ERR,
1698d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    "%s: dhcp_openudp: %m", ifp->name);
1699d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	} else
1700d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		s = -1;
1701d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1702d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* If we couldn't open a UDP port for our IP address
1703d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * then we cannot renew.
1704d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * This could happen if our IP was pulled out from underneath us.
1705d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * Also, we should not unicast from a BOOTP lease. */
1706d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (s == -1 ||
1707d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    (!(ifo->options & DHCPCD_INFORM) &&
1708d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    IS_BOOTP(ifp, state->new)))
1709d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	{
1710d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		a = state->addr.s_addr;
1711d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		state->addr.s_addr = INADDR_ANY;
1712d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1713d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	r = make_message(&dhcp, ifp, type);
1714d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (r == -1)
1715d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		goto fail;
1716d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	len = (size_t)r;
1717d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (a)
1718d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		state->addr.s_addr = a;
1719d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	from.s_addr = dhcp->ciaddr;
1720d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (from.s_addr)
1721d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		to.s_addr = state->lease.server.s_addr;
1722d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else
1723d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		to.s_addr = INADDR_ANY;
1724d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (to.s_addr && to.s_addr != INADDR_BROADCAST) {
1725d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		struct sockaddr_in sin;
1726d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1727d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		memset(&sin, 0, sizeof(sin));
1728d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		sin.sin_family = AF_INET;
1729d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		sin.sin_addr.s_addr = to.s_addr;
1730d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		sin.sin_port = htons(DHCP_SERVER_PORT);
1731d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		r = sendto(s, (uint8_t *)dhcp, len, 0,
1732d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    (struct sockaddr *)&sin, sizeof(sin));
1733d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (r == -1)
1734d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ifp->ctx, LOG_ERR,
1735d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    "%s: dhcp_sendpacket: %m", ifp->name);
1736d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	} else {
1737d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		size_t ulen;
1738d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1739d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		r = 0;
1740d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		udp = dhcp_makeudppacket(&ulen, (uint8_t *)dhcp, len, from, to);
1741d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (udp == NULL) {
1742d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ifp->ctx, LOG_ERR, "dhcp_makeudppacket: %m");
1743d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		} else {
1744d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			r = if_sendrawpacket(ifp, ETHERTYPE_IP,
1745f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan			    (uint8_t *)udp, ulen, NULL);
1746d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			free(udp);
1747d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
1748d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* If we failed to send a raw packet this normally means
1749d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		 * we don't have the ability to work beneath the IP layer
1750d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		 * for this interface.
1751d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		 * As such we remove it from consideration without actually
1752d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		 * stopping the interface. */
1753d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (r == -1) {
1754d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ifp->ctx, LOG_ERR,
1755d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    "%s: if_sendrawpacket: %m", ifp->name);
1756d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			switch(errno) {
1757d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			case ENETDOWN:
1758d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			case ENETRESET:
1759d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			case ENETUNREACH:
1760d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				break;
1761d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			default:
1762d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				if (!(ifp->ctx->options & DHCPCD_TEST))
1763d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					dhcp_drop(ifp, "FAIL");
1764d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				dhcp_free(ifp);
1765d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				eloop_timeout_delete(ifp->ctx->eloop,
1766d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    NULL, ifp);
1767d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				callback = NULL;
1768d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
1769d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
1770d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1771d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	free(dhcp);
1772d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1773d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanfail:
1774d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (s != -1)
1775d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		close(s);
1776d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1777d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Even if we fail to send a packet we should continue as we are
1778d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * as our failure timeouts will change out codepath when needed. */
1779d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (callback)
1780d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		eloop_timeout_add_tv(ifp->ctx->eloop, &tv, callback, ifp);
1781d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1782d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1783d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void
1784d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tansend_inform(void *arg)
1785d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1786d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1787d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	send_message((struct interface *)arg, DHCP_INFORM, send_inform);
1788d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1789d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1790d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void
1791d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tansend_discover(void *arg)
1792d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1793d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1794d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	send_message((struct interface *)arg, DHCP_DISCOVER, send_discover);
1795d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1796d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1797d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void
1798d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tansend_request(void *arg)
1799d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1800d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1801d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	send_message((struct interface *)arg, DHCP_REQUEST, send_request);
1802d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1803d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1804d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void
1805d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tansend_renew(void *arg)
1806d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1807d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1808d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	send_message((struct interface *)arg, DHCP_REQUEST, send_renew);
1809d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1810d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1811d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void
1812d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tansend_rebind(void *arg)
1813d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1814d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1815d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	send_message((struct interface *)arg, DHCP_REQUEST, send_rebind);
1816d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1817d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1818d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanvoid
1819d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_discover(void *arg)
1820d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1821d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct interface *ifp = arg;
1822d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_state *state = D_STATE(ifp);
1823d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct if_options *ifo = ifp->options;
1824d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
182523ff6edd8b4ec796a32d36a3eca8a8d8c785b565Samuel Tan	rpc_signal_status("Discover");
1826d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->state = DHS_DISCOVER;
1827d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->xid = dhcp_xid(ifp);
18285158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan	state->nak_receive_count = 0;
18295158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan	state->failed_address_offer_count = 0;
1830d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
1831d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifo->fallback)
1832d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		eloop_timeout_add_sec(ifp->ctx->eloop,
1833d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    ifo->reboot, dhcp_fallback, ifp);
1834d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else if (ifo->options & DHCPCD_IPV4LL &&
1835d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    !IN_LINKLOCAL(htonl(state->addr.s_addr)))
1836d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		eloop_timeout_add_sec(ifp->ctx->eloop,
1837d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    ifo->reboot, ipv4ll_start, ifp);
1838d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifo->options & DHCPCD_REQUEST)
1839d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		logger(ifp->ctx, LOG_INFO,
1840d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    "%s: soliciting a DHCP lease (requesting %s)",
1841d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    ifp->name, inet_ntoa(ifo->req_addr));
1842d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else
1843d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		logger(ifp->ctx, LOG_INFO,
1844d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    "%s: soliciting a %s lease",
1845d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    ifp->name, ifo->options & DHCPCD_BOOTP ? "BOOTP" : "DHCP");
1846d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	send_discover(ifp);
1847d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1848d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1849d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void
1850d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_request(void *arg)
1851d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1852d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct interface *ifp = arg;
1853d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_state *state = D_STATE(ifp);
1854d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
185524aa62eefd9284fb94820093f6088607d42c4249Samuel Tan	logger(ifp->ctx, LOG_INFO, "%s: requesting lease of %s",
185624aa62eefd9284fb94820093f6088607d42c4249Samuel Tan		ifp->name, inet_ntoa(state->lease.addr));
185724aa62eefd9284fb94820093f6088607d42c4249Samuel Tan
185823ff6edd8b4ec796a32d36a3eca8a8d8c785b565Samuel Tan	rpc_signal_status("Request");
1859d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->state = DHS_REQUEST;
18605158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan	state->nak_receive_count = 0;
1861d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	send_request(ifp);
1862d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1863d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1864d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void
1865d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_expire(void *arg)
1866d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1867d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct interface *ifp = arg;
1868d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_state *state = D_STATE(ifp);
1869d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1870d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	logger(ifp->ctx, LOG_ERR, "%s: DHCP lease expired", ifp->name);
1871d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
1872d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	dhcp_drop(ifp, "EXPIRE");
1873d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	unlink(state->leasefile);
1874d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->interval = 0;
1875d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	dhcp_discover(ifp);
1876d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1877d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1878d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void
1879d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_decline(struct interface *ifp)
1880d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1881d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1882d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	send_message(ifp, DHCP_DECLINE, NULL);
1883d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1884d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1885d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void
1886d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_renew(void *arg)
1887d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1888d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct interface *ifp = arg;
1889d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_state *state = D_STATE(ifp);
1890d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_lease *lease = &state->lease;
1891d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
189223ff6edd8b4ec796a32d36a3eca8a8d8c785b565Samuel Tan	rpc_signal_status("Renew");
189324aa62eefd9284fb94820093f6088607d42c4249Samuel Tan	logger(ifp->ctx, LOG_INFO, "%s: renewing lease of %s",
1894d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    ifp->name, inet_ntoa(lease->addr));
1895d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	logger(ifp->ctx, LOG_DEBUG, "%s: rebind in %"PRIu32" seconds,"
1896d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    " expire in %"PRIu32" seconds",
1897d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    ifp->name, lease->rebindtime - lease->renewaltime,
1898d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    lease->leasetime - lease->renewaltime);
1899d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->state = DHS_RENEW;
1900d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->xid = dhcp_xid(ifp);
19015158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan	state->nak_receive_count = 0;
1902d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	send_renew(ifp);
1903d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1904d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1905d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifndef IN_IFF_TENTATIVE
1906d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void
1907d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_arp_announced(struct arp_state *astate)
1908d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1909d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1910d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	arp_close(astate->iface);
1911d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1912d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
1913d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1914d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void
1915d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_rebind(void *arg)
1916d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1917d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct interface *ifp = arg;
1918d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_state *state = D_STATE(ifp);
1919d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_lease *lease = &state->lease;
1920d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
192123ff6edd8b4ec796a32d36a3eca8a8d8c785b565Samuel Tan	rpc_signal_status("Rebind");
1922d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	logger(ifp->ctx, LOG_WARNING,
1923d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    "%s: failed to renew DHCP, rebinding", ifp->name);
1924d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	logger(ifp->ctx, LOG_DEBUG, "%s: expire in %"PRIu32" seconds",
1925d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    ifp->name, lease->leasetime - lease->rebindtime);
1926d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->state = DHS_REBIND;
1927d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	eloop_timeout_delete(ifp->ctx->eloop, send_renew, ifp);
1928d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->lease.server.s_addr = 0;
19295158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan	state->nak_receive_count = 0;
1930d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ifp->options->options &= ~(DHCPCD_CSR_WARNED |
1931d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    DHCPCD_ROUTER_HOST_ROUTE_WARNED);
1932d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	send_rebind(ifp);
1933d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1934d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
19359177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tanstatic void
19369177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Taninit_option_iterator(const struct dhcp_message *message,
19379177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan		     struct dhcp_option_iterator *iterator)
19389177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan{
19399177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	iterator->message = message;
19409177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	iterator->ptr = message->options;
19419177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	iterator->end = iterator->ptr + sizeof(message->options);
19429177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	iterator->extra_option_locations = 0;
19439177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	iterator->extra_option_locations_set = 0;
19449177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan}
19459177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan
19469177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tanstatic int
19479177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Taniterate_next_option(struct dhcp_option_iterator *iterator,
19489177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan		    uint8_t *option, uint8_t *length, const uint8_t **value)
19499177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan{
19509177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	uint8_t option_code;
19519177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	uint8_t option_len;
19529177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan
19539177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	/* Process special DHO_PAD and DHO_END opcodes. */
19549177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	while (iterator->ptr < iterator->end) {
19559177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan		if (*iterator->ptr == DHO_PAD) {
19569177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan			iterator->ptr++;
19579177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan			continue;
19589177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan		}
19599177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan
19609177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan		if (*iterator->ptr != DHO_END)
19619177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan			break;
19629177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan
19639177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan		if (iterator->extra_option_locations &
19649177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan		    OPTION_OVERLOADED_BOOT_FILE) {
19659177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan			iterator->extra_option_locations &=
19669177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan				~OPTION_OVERLOADED_BOOT_FILE;
19679177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan			iterator->ptr = iterator->message->bootfile;
19689177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan			iterator->end = iterator->ptr +
19699177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan				sizeof(iterator->message->bootfile);
19709177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan		} else if (iterator->extra_option_locations &
19719177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan			   OPTION_OVERLOADED_SERVER_NAME) {
19729177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan			iterator->extra_option_locations &=
19739177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan				~OPTION_OVERLOADED_SERVER_NAME;
19749177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan			iterator->ptr = iterator->message->servername;
19759177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan			iterator->end = iterator->ptr +
19769177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan				sizeof(iterator->message->servername);
19779177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan		} else
19789177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan			return 0;
19799177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	}
19809177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan
19819177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	if (iterator->ptr + 2 > iterator->end)
19829177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan		return 0;
19839177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan
19849177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	option_code = *iterator->ptr++;
19859177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	option_len = *iterator->ptr++;
19869177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	if (iterator->ptr + option_len > iterator->end)
19879177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan		return 0;
19889177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan
19899177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	if (option_code == DHO_OPTIONSOVERLOADED && option_len > 0 &&
19909177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	    !iterator->extra_option_locations_set) {
19919177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan		iterator->extra_option_locations = *iterator->ptr;
19929177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan		iterator->extra_option_locations_set = 1;
19939177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	}
19949177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan
19959177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	if (option)
19969177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan		*option = option_code;
19979177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	if (length)
19989177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan		*length = option_len;
19999177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	if (value)
20009177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan		*value = iterator->ptr;
20019177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan
20029177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	iterator->ptr += option_len;
20039177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan
20049177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	return 1;
20059177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan}
20069177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan
20079177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tanstatic void
20089177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tanmerge_option_values(const struct dhcp_message *src,
20099177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan		    struct dhcp_message *dst, uint8_t *copy_options)
20109177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan{
20119177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	uint8_t supplied_options[OPTION_MASK_SIZE];
20129177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	struct dhcp_option_iterator dst_iterator;
20139177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	struct dhcp_option_iterator src_iterator;
20149177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	uint8_t option;
20159177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	const uint8_t *option_value;
20169177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	uint8_t option_length;
20179177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	uint8_t *out;
20189177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	const uint8_t *out_end;
20199177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	int added_options = 0;
20209177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan
20219177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	/* Traverse the destination message for options already supplied. */
20229177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	memset(&supplied_options, 0, sizeof(supplied_options));
20239177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	init_option_iterator(dst, &dst_iterator);
20249177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	while (iterate_next_option(&dst_iterator, &option, NULL, NULL)) {
20259177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan		add_option_mask(supplied_options, option);
20269177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	}
20279177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan
20289177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	/* We will start merging options at the end of the last block
20299177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	 * the iterator traversed to.  The const cast below is safe since
20309177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	 * this points to data within the (non-const) dst message. */
20319177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	out = (uint8_t *) dst_iterator.ptr;
20329177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	out_end = dst_iterator.end;
20339177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan
20349177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	init_option_iterator(src, &src_iterator);
20359177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	while (iterate_next_option(&src_iterator, &option, &option_length,
20369177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan				   &option_value)) {
20379177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan		if (has_option_mask(supplied_options, option) ||
20389177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan		    !has_option_mask(copy_options, option))
20399177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan			continue;
20409177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan		/* We need space for this option, plus a trailing DHO_END. */
20419177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan		if (out + option_length + 3 > out_end) {
20429177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan			syslog(LOG_ERR,
20439177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan			       "%s: unable to fit option %d (length %d)",
20449177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan			       __func__, option, option_length);
20459177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan			continue;
20469177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan		}
20479177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan		*out++ = option;
20489177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan		*out++ = option_length;
20499177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan		memcpy(out, option_value, option_length);
20509177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan		out += option_length;
20519177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan		added_options++;
20529177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	}
20539177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan
20549177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	if (added_options) {
20559177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan		*out++ = DHO_END;
20569177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan		syslog(LOG_INFO, "carrying over %d options from original offer",
20579177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan		added_options);
20589177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	}
20599177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan}
20609177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan
2061d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanvoid
2062d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_bind(struct interface *ifp, struct arp_state *astate)
2063d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
2064d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_state *state = D_STATE(ifp);
2065d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct if_options *ifo = ifp->options;
2066d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_lease *lease = &state->lease;
2067d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint8_t ipv4ll = 0;
2068d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2069d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (state->state == DHS_BOUND)
2070d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		goto applyaddr;
2071d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->reason = NULL;
2072d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	free(state->old);
2073d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->old = state->new;
2074d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->new = state->offer;
2075d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->offer = NULL;
2076d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	get_lease(ifp->ctx, lease, state->new);
2077d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifo->options & DHCPCD_STATIC) {
2078d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		logger(ifp->ctx, LOG_INFO, "%s: using static address %s/%d",
2079d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    ifp->name, inet_ntoa(lease->addr),
2080d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    inet_ntocidr(lease->net));
2081d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		lease->leasetime = ~0U;
2082d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		state->reason = "STATIC";
2083d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	} else if (state->new->cookie != htonl(MAGIC_COOKIE)) {
2084d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		logger(ifp->ctx, LOG_INFO, "%s: using IPv4LL address %s",
2085d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    ifp->name, inet_ntoa(lease->addr));
2086d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		lease->leasetime = ~0U;
2087d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		state->reason = "IPV4LL";
2088d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ipv4ll = 1;
2089d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	} else if (ifo->options & DHCPCD_INFORM) {
2090d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (ifo->req_addr.s_addr != 0)
2091d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			lease->addr.s_addr = ifo->req_addr.s_addr;
2092d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		else
2093d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			lease->addr.s_addr = state->addr.s_addr;
2094d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		logger(ifp->ctx, LOG_INFO, "%s: received approval for %s",
2095d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    ifp->name, inet_ntoa(lease->addr));
2096d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		lease->leasetime = ~0U;
2097d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		state->reason = "INFORM";
2098d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	} else {
2099d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (lease->frominfo)
2100d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			state->reason = "TIMEOUT";
2101d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (lease->leasetime == ~0U) {
2102d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			lease->renewaltime =
2103d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    lease->rebindtime =
2104d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    lease->leasetime;
2105d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ifp->ctx, LOG_INFO, "%s: leased %s for infinity",
2106d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    ifp->name, inet_ntoa(lease->addr));
2107d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		} else {
2108d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (lease->leasetime < DHCP_MIN_LEASE) {
2109d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				logger(ifp->ctx, LOG_WARNING,
2110d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    "%s: minimum lease is %d seconds",
2111d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    ifp->name, DHCP_MIN_LEASE);
2112d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				lease->leasetime = DHCP_MIN_LEASE;
2113d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
2114d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (lease->rebindtime == 0)
2115d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				lease->rebindtime =
2116d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    (uint32_t)(lease->leasetime * T2);
2117d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			else if (lease->rebindtime >= lease->leasetime) {
2118d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				lease->rebindtime =
2119d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    (uint32_t)(lease->leasetime * T2);
2120d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				logger(ifp->ctx, LOG_WARNING,
2121d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    "%s: rebind time greater than lease "
2122d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    "time, forcing to %"PRIu32" seconds",
2123d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    ifp->name, lease->rebindtime);
2124d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
2125d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (lease->renewaltime == 0)
2126d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				lease->renewaltime =
2127d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    (uint32_t)(lease->leasetime * T1);
2128d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			else if (lease->renewaltime > lease->rebindtime) {
2129d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				lease->renewaltime =
2130d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    (uint32_t)(lease->leasetime * T1);
2131d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				logger(ifp->ctx, LOG_WARNING,
2132d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    "%s: renewal time greater than rebind "
2133d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    "time, forcing to %"PRIu32" seconds",
2134d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    ifp->name, lease->renewaltime);
2135d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
2136d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ifp->ctx,
2137d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    lease->addr.s_addr == state->addr.s_addr &&
2138d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    !(state->added & STATE_FAKE) ?
2139d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    LOG_DEBUG : LOG_INFO,
2140d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    "%s: leased %s for %"PRIu32" seconds", ifp->name,
2141d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    inet_ntoa(lease->addr), lease->leasetime);
2142d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
2143d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
2144d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifp->ctx->options & DHCPCD_TEST) {
2145d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		state->reason = "TEST";
2146d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		script_runreason(ifp, state->reason);
2147d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		eloop_exit(ifp->ctx->eloop, EXIT_SUCCESS);
2148d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
2149d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
2150d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (state->reason == NULL) {
2151d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (state->old && !(state->added & STATE_FAKE)) {
2152d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (state->old->yiaddr == state->new->yiaddr &&
2153d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    lease->server.s_addr)
2154d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				state->reason = "RENEW";
2155d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			else
2156d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				state->reason = "REBIND";
2157d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		} else if (state->state == DHS_REBOOT)
2158d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			state->reason = "REBOOT";
2159d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		else
2160d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			state->reason = "BOUND";
2161d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
21629177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan
21639177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	if (state->old && state->old->yiaddr == state->new->yiaddr &&
21649177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	    (state->state == DHS_REBOOT || state->state == DHS_RENEW ||
21659177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	     state->state == DHS_REBIND)) {
21669177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan		/* Some DHCP servers respond to REQUEST with a subset
21679177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan		 * of the original requested parameters.  If they were not
21689177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan		 * supplied in the response to a renewal, we should assume
21699177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan		 * that it's reasonable to transfer them forward from the
21709177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan		 * original offer. */
21719177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan		merge_option_values(state->old, state->new, ifo->requestmask);
21729177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan	}
21739177c6fae9fb7aecf0a0d378050788ba609a5a41Samuel Tan
2174d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (lease->leasetime == ~0U)
2175d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		lease->renewaltime = lease->rebindtime = lease->leasetime;
2176d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else {
2177d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		eloop_timeout_add_sec(ifp->ctx->eloop,
2178d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    (time_t)lease->renewaltime, dhcp_renew, ifp);
2179d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		eloop_timeout_add_sec(ifp->ctx->eloop,
2180d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    (time_t)lease->rebindtime, dhcp_rebind, ifp);
2181d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		eloop_timeout_add_sec(ifp->ctx->eloop,
2182d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    (time_t)lease->leasetime, dhcp_expire, ifp);
2183d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		logger(ifp->ctx, LOG_DEBUG,
2184d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    "%s: renew in %"PRIu32" seconds, rebind in %"PRIu32
2185d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    " seconds",
2186d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    ifp->name, lease->renewaltime, lease->rebindtime);
2187d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
2188d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (!(ifo->options & DHCPCD_STATIC) &&
2189d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    state->new->cookie != htonl(MAGIC_COOKIE))
2190d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		state->state = DHS_IPV4LL_BOUND;
2191d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else
2192d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		state->state = DHS_BOUND;
2193d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (!state->lease.frominfo &&
2194d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    !(ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC)))
2195d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (write_lease(ifp, state->new) == -1)
2196d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ifp->ctx, LOG_ERR,
2197d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    "%s: write_lease: %m", __func__);
2198d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2199d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanapplyaddr:
2200d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ipv4_applyaddr(ifp);
2201d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifo->options & DHCPCD_ARP &&
2202d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    !(ifp->ctx->options & DHCPCD_FORKED))
2203d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	{
2204d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef IN_IFF_TENTATIVE
2205d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (astate)
2206d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			arp_free_but(astate);
2207d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		else if (!ipv4ll)
2208d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			arp_close(ifp);
2209d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#else
2210d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (state->added) {
2211d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (astate == NULL) {
2212d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				astate = arp_new(ifp, &state->addr);
2213d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				astate->announced_cb =
2214d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    dhcp_arp_announced;
2215d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
2216d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (astate) {
2217d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				arp_announce(astate);
2218d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				if (!ipv4ll)
2219d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					arp_free_but(astate);
2220d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
2221d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		} else if (!ipv4ll)
2222d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			arp_close(ifp);
2223d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
2224d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
2225d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
2226d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2227d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void
2228d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_timeout(void *arg)
2229d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
2230d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct interface *ifp = arg;
2231d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_state *state = D_STATE(ifp);
2232d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2233d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	dhcp_bind(ifp, NULL);
2234d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->interval = 0;
2235d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	dhcp_discover(ifp);
2236d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
2237d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2238d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstruct dhcp_message *
2239d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_message_new(const struct in_addr *addr, const struct in_addr *mask)
2240d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
2241d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_message *dhcp;
2242d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint8_t *p;
2243d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2244d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	dhcp = calloc(1, sizeof(*dhcp));
2245d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (dhcp == NULL)
2246d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return NULL;
2247d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	dhcp->yiaddr = addr->s_addr;
2248d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	p = dhcp->options;
2249d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (mask && mask->s_addr != INADDR_ANY) {
2250d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		*p++ = DHO_SUBNETMASK;
2251d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		*p++ = sizeof(mask->s_addr);
2252d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		memcpy(p, &mask->s_addr, sizeof(mask->s_addr));
2253d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		p+= sizeof(mask->s_addr);
2254d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
2255d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	*p++ = DHO_END;
2256d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return dhcp;
2257d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
2258d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2259d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void
2260d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_static(struct interface *ifp)
2261d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
2262d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct if_options *ifo;
2263d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_state *state;
2264d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2265d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state = D_STATE(ifp);
2266d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ifo = ifp->options;
2267d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifo->req_addr.s_addr == INADDR_ANY) {
2268d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		logger(ifp->ctx, LOG_INFO,
2269d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    "%s: waiting for 3rd party to "
2270d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    "configure IP address",
2271d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    ifp->name);
2272d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		state->reason = "3RDPARTY";
2273d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		script_runreason(ifp, state->reason);
2274d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
2275d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
2276d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->offer = dhcp_message_new(&ifo->req_addr, &ifo->req_mask);
2277d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (state->offer) {
2278d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
2279d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		dhcp_bind(ifp, NULL);
2280d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
2281d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
2282d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2283d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanvoid
2284d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_inform(struct interface *ifp)
2285d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
2286d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_state *state;
2287d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct if_options *ifo;
2288d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct ipv4_addr *ap;
2289d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2290d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state = D_STATE(ifp);
2291d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ifo = ifp->options;
229224aa62eefd9284fb94820093f6088607d42c4249Samuel Tan	logger(ifp->ctx, LOG_INFO, "%s: informing peers of local address",
229324aa62eefd9284fb94820093f6088607d42c4249Samuel Tan	       ifp->name);
2294d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifp->ctx->options & DHCPCD_TEST) {
2295d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		state->addr.s_addr = ifo->req_addr.s_addr;
2296d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		state->net.s_addr = ifo->req_mask.s_addr;
2297d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	} else {
2298d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (ifo->req_addr.s_addr == INADDR_ANY) {
2299d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			state = D_STATE(ifp);
2300d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			ap = ipv4_iffindaddr(ifp, NULL, NULL);
2301d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (ap == NULL) {
2302d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				logger(ifp->ctx, LOG_INFO,
2303d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    "%s: waiting for 3rd party to "
2304d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    "configure IP address",
2305d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    ifp->name);
2306d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				state->reason = "3RDPARTY";
2307d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				script_runreason(ifp, state->reason);
2308d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				return;
2309d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
2310d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			state->offer =
2311d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    dhcp_message_new(&ap->addr, &ap->net);
2312d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		} else
2313d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			state->offer =
2314d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    dhcp_message_new(&ifo->req_addr, &ifo->req_mask);
2315d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (state->offer) {
2316d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			ifo->options |= DHCPCD_STATIC;
2317d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			dhcp_bind(ifp, NULL);
2318d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			ifo->options &= ~DHCPCD_STATIC;
2319d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
2320d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
2321d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
232223ff6edd8b4ec796a32d36a3eca8a8d8c785b565Samuel Tan	rpc_signal_status("Inform");
2323d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->state = DHS_INFORM;
2324d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->xid = dhcp_xid(ifp);
2325d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	send_inform(ifp);
2326d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
2327d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2328d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanvoid
2329d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_reboot_newopts(struct interface *ifp, unsigned long long oldopts)
2330d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
2331d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct if_options *ifo;
2332d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_state *state = D_STATE(ifp);
2333d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2334d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (state == NULL)
2335d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
2336d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ifo = ifp->options;
2337d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if ((ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC) &&
2338d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		state->addr.s_addr != ifo->req_addr.s_addr) ||
2339d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    (oldopts & (DHCPCD_INFORM | DHCPCD_STATIC) &&
2340d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		!(ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC))))
2341d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	{
2342d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		dhcp_drop(ifp, "EXPIRE");
2343d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
2344d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
2345d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2346f20514bf582d08567217a3b06171bab5a11458eaSamuel Tanstatic void start_unicast_arp(struct interface *ifp);
2347f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan
2348d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void
2349d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_reboot(struct interface *ifp)
2350d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
2351d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct if_options *ifo;
2352d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_state *state = D_STATE(ifp);
2353d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2354d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (state == NULL)
2355d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
235623ff6edd8b4ec796a32d36a3eca8a8d8c785b565Samuel Tan	rpc_signal_status("Reboot");
2357d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ifo = ifp->options;
2358d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->state = DHS_REBOOT;
2359d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->interval = 0;
2360d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2361d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifo->options & DHCPCD_LINK && ifp->carrier == LINK_DOWN) {
2362d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		logger(ifp->ctx, LOG_INFO,
2363d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    "%s: waiting for carrier", ifp->name);
2364d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
2365d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
2366d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifo->options & DHCPCD_STATIC) {
2367d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		dhcp_static(ifp);
2368d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
2369d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
2370f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	if (ifo->options & DHCPCD_UNICAST_ARP) {
2371f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan		start_unicast_arp(ifp);
2372f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	}
2373d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifo->options & DHCPCD_INFORM) {
2374d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		logger(ifp->ctx, LOG_INFO, "%s: informing address of %s",
2375d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    ifp->name, inet_ntoa(state->lease.addr));
2376d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		dhcp_inform(ifp);
2377d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
2378d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
2379d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifo->reboot == 0 || state->offer == NULL) {
2380d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		dhcp_discover(ifp);
2381d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
2382d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
2383d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (state->offer->cookie == 0)
2384d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
2385d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2386d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	logger(ifp->ctx, LOG_INFO, "%s: rebinding lease of %s",
2387d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    ifp->name, inet_ntoa(state->lease.addr));
2388d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->xid = dhcp_xid(ifp);
2389d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->lease.server.s_addr = 0;
2390d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
2391d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2392d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Need to add this before dhcp_expire and friends. */
2393d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (!ifo->fallback && ifo->options & DHCPCD_IPV4LL &&
2394d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    !IN_LINKLOCAL(htonl(state->addr.s_addr)))
2395d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		eloop_timeout_add_sec(ifp->ctx->eloop,
2396d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    ifo->reboot, ipv4ll_start, ifp);
2397d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2398d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifo->options & DHCPCD_LASTLEASE && state->lease.frominfo)
2399d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		eloop_timeout_add_sec(ifp->ctx->eloop,
2400d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    ifo->reboot, dhcp_timeout, ifp);
2401d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else if (!(ifo->options & DHCPCD_INFORM))
2402d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		eloop_timeout_add_sec(ifp->ctx->eloop,
2403d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    ifo->reboot, dhcp_expire, ifp);
2404d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2405d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Don't bother ARP checking as the server could NAK us first.
2406d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * Don't call dhcp_request as that would change the state */
2407d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	send_request(ifp);
2408d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
2409d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2410d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanvoid
2411d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_drop(struct interface *ifp, const char *reason)
2412d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
2413d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_state *state;
2414d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef RELEASE_SLOW
2415d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct timespec ts;
2416d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
2417d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2418d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state = D_STATE(ifp);
2419d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* dhcp_start may just have been called and we don't yet have a state
2420d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * but we do have a timeout, so punt it. */
2421d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (state == NULL) {
2422d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
2423d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
2424d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
2425d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Don't reset DHCP state if we have an IPv4LL address and link is up,
2426d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * unless the interface is departing. */
2427d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (state->state != DHS_IPV4LL_BOUND ||
2428d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    ifp->carrier != LINK_UP ||
2429d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    ifp->options->options & DHCPCD_DEPARTED)
2430d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	{
2431d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
2432d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		dhcp_auth_reset(&state->auth);
2433d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		dhcp_close(ifp);
2434d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
2435d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2436e942e091ac1efb0ee1916add2b12f64fdfd59476Samuel Tan	if (ifp->options->options & DHCPCD_RELEASE ||
2437e942e091ac1efb0ee1916add2b12f64fdfd59476Samuel Tan	    strcmp(reason, "RELEASE") == 0) {
2438d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		unlink(state->leasefile);
2439d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (ifp->carrier != LINK_DOWN &&
2440d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    state->new != NULL &&
2441d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    state->new->cookie == htonl(MAGIC_COOKIE))
2442d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		{
2443d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ifp->ctx, LOG_INFO, "%s: releasing lease of %s",
2444d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    ifp->name, inet_ntoa(state->lease.addr));
2445d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			state->xid = dhcp_xid(ifp);
2446d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			send_message(ifp, DHCP_RELEASE, NULL);
2447d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef RELEASE_SLOW
2448d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			/* Give the packet a chance to go */
2449d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			ts.tv_sec = RELEASE_DELAY_S;
2450d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			ts.tv_nsec = RELEASE_DELAY_NS;
2451d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			nanosleep(&ts, NULL);
2452d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
2453d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
2454d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
2455d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2456d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	free(state->old);
2457d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->old = state->new;
2458d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->new = NULL;
2459d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->reason = reason;
2460d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ipv4_applyaddr(ifp);
2461d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	free(state->old);
2462d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->old = NULL;
2463d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->lease.addr.s_addr = 0;
2464d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ifp->options->options &= ~(DHCPCD_CSR_WARNED |
2465d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    DHCPCD_ROUTER_HOST_ROUTE_WARNED);
2466d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
2467d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2468d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void
2469d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanlog_dhcp1(int lvl, const char *msg,
2470d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    const struct interface *ifp, const struct dhcp_message *dhcp,
2471d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    const struct in_addr *from, int ad)
2472d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
2473d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const char *tfrom;
2474d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	char *a,  sname[sizeof(dhcp->servername) * 4];
2475d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct in_addr addr;
2476d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int r;
2477d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2478d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (strcmp(msg, "NAK:") == 0) {
2479d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		a = get_option_string(ifp->ctx, dhcp, DHO_MESSAGE);
2480d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (a) {
2481d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			char *tmp;
2482d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			size_t al, tmpl;
2483d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2484d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			al = strlen(a);
2485d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			tmpl = (al * 4) + 1;
2486d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			tmp = malloc(tmpl);
2487d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (tmp == NULL) {
2488d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
2489d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				free(a);
2490d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				return;
2491d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
2492d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			print_string(tmp, tmpl, STRING, (uint8_t *)a, al);
2493d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			free(a);
2494d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			a = tmp;
2495d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
2496d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	} else if (ad && dhcp->yiaddr != 0) {
2497d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		addr.s_addr = dhcp->yiaddr;
2498d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		a = strdup(inet_ntoa(addr));
2499d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (a == NULL) {
2500d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
2501d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return;
2502d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
2503d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	} else
2504d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		a = NULL;
2505d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2506d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	tfrom = "from";
2507d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	r = get_option_addr(ifp->ctx, &addr, dhcp, DHO_SERVERID);
2508d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (dhcp->servername[0] && r == 0) {
2509d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		print_string(sname, sizeof(sname), STRING,
2510d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    dhcp->servername, strlen((const char *)dhcp->servername));
2511d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (a == NULL)
2512d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ifp->ctx, lvl, "%s: %s %s %s `%s'",
2513d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    ifp->name, msg, tfrom, inet_ntoa(addr), sname);
2514d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		else
2515d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ifp->ctx, lvl, "%s: %s %s %s %s `%s'",
2516d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    ifp->name, msg, a, tfrom, inet_ntoa(addr), sname);
2517d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	} else {
2518d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (r != 0) {
2519d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			tfrom = "via";
2520d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			addr = *from;
2521d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
2522d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (a == NULL)
2523d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ifp->ctx, lvl, "%s: %s %s %s",
2524d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    ifp->name, msg, tfrom, inet_ntoa(addr));
2525d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		else
2526d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ifp->ctx, lvl, "%s: %s %s %s %s",
2527d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    ifp->name, msg, a, tfrom, inet_ntoa(addr));
2528d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
2529d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	free(a);
2530d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
2531d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2532d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void
2533d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanlog_dhcp(int lvl, const char *msg,
2534d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    const struct interface *ifp, const struct dhcp_message *dhcp,
2535d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    const struct in_addr *from)
2536d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
2537d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2538d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	log_dhcp1(lvl, msg, ifp, dhcp, from, 1);
2539d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
2540d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2541d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
2542d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanblacklisted_ip(const struct if_options *ifo, in_addr_t addr)
2543d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
2544d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t i;
2545d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2546d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	for (i = 0; i < ifo->blacklist_len; i += 2)
2547d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (ifo->blacklist[i] == (addr & ifo->blacklist[i + 1]))
2548d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return 1;
2549d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return 0;
2550d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
2551d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2552d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
2553d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanwhitelisted_ip(const struct if_options *ifo, in_addr_t addr)
2554d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
2555d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t i;
2556d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2557d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifo->whitelist_len == 0)
2558d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
2559d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	for (i = 0; i < ifo->whitelist_len; i += 2)
2560d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (ifo->whitelist[i] == (addr & ifo->whitelist[i + 1]))
2561d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return 1;
2562d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return 0;
2563d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
2564d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2565d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void
2566f20514bf582d08567217a3b06171bab5a11458eaSamuel Tansave_gateway_addr(struct interface *ifp, const uint8_t *gw_hwaddr)
2567f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan{
2568f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	struct dhcp_state *state = D_STATE(ifp);
2569f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	memcpy(state->server_info.gw_hwaddr, gw_hwaddr, ifp->hwlen);
2570f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	state->server_info.gw_hwlen = ifp->hwlen;
2571f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan}
2572f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan
2573f20514bf582d08567217a3b06171bab5a11458eaSamuel Tanstatic void
2574f20514bf582d08567217a3b06171bab5a11458eaSamuel Tandhcp_probe_gw_timeout(struct arp_state *astate)
2575f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan{
25761c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan	struct dhcp_state *state = D_STATE(astate->iface);
25771c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan
2578f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	/* Ignore unicast ARP failures. */
2579f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	if (astate->dest_hwlen)
2580f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan		return;
2581f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan
2582f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	/* Probegw failure, allow ourselves to fail only once this way */
25831c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan	logger(astate->iface->ctx, LOG_ERR,
25841c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan	       "%s: Probe gateway %s timed out ",
25851c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan	       astate->iface->name, inet_ntoa(astate->addr));
25861c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan	astate->iface->options->options &= ~DHCPCD_ARPGW;
25871c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan
25881c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan	unlink(state->leasefile);
25891c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan	if (!state->lease.frominfo)
25901c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan		dhcp_decline(astate->iface);
25911c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan#ifdef IN_IFF_DUPLICATED
25921c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan	ia = ipv4_iffindaddr(astate->iface, &astate->addr, NULL);
25931c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan	if (ia)
25941c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan		ipv4_deladdr(astate->iface, &ia->addr, &ia->net);
25951c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan#endif
25961c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan	eloop_timeout_delete(astate->iface->ctx->eloop, NULL,
25971c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan	    astate->iface);
25981c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan	eloop_timeout_add_sec(astate->iface->ctx->eloop,
25991c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan	    DHCP_RAND_MAX, dhcp_discover, astate->iface);
26001c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan}
26011c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan
26021c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tanstatic void
26031c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tandhcp_probe_gw_response(struct arp_state *astate, const struct arp_msg *amsg)
26041c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan{
26051c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan	/* Verify this is a response for the gateway probe. */
26061c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan	if (astate->src_addr.s_addr != 0 &&
26071c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan	    amsg &&
26081c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan	    amsg->tip.s_addr == astate->src_addr.s_addr &&
26091c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan	    amsg->sip.s_addr == astate->addr.s_addr) {
2610f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan		if (astate->dest_hwlen) {
2611f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan			/* Response to unicast ARP. */
261223ff6edd8b4ec796a32d36a3eca8a8d8c785b565Samuel Tan			rpc_notify_unicast_arp(astate->iface);
2613f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan		} else {
2614f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan			/* Response to arpgw request. */
2615f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan			save_gateway_addr(astate->iface, amsg->sha);
2616f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan
2617f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan			dhcp_close(astate->iface);
2618f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan			eloop_timeout_delete(astate->iface->ctx->eloop,
2619f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan					     NULL, astate->iface);
2620f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	#ifdef IN_IFF_TENTATIVE
2621f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan			ipv4_finaliseaddr(astate->iface);
2622f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	#else
2623f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan			dhcp_bind(astate->iface, NULL);
2624f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	#endif
2625f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan		}
26261c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan		arp_close(astate->iface);
26271c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan	}
26281c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan}
26291c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan
26301c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tanstatic int
26311c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tandhcp_probe_gw(struct interface *ifp)
26321c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan{
26331c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan	struct dhcp_state *state = D_STATE(ifp);
26341c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan	struct arp_state *astate;
26351c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan	struct in_addr gateway_addr;
26361c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan
26371c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan	if (get_option_addr(ifp->ctx, &gateway_addr,
26381c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan			    state->offer, DHO_ROUTER) == 0) {
26391c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan		astate = arp_new(ifp, &gateway_addr);
26401c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan		if (astate) {
26411c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan			astate->src_addr.s_addr = state->offer->yiaddr;
26421c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan			astate->probed_cb = dhcp_probe_gw_timeout;
26431c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan			astate->conflicted_cb = dhcp_probe_gw_response;
26441c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan			arp_probe(astate);
26451c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan			return 1;
26461c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan		}
26471c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan	}
26481c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan	return 0;
26491c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan}
26501c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan
26511c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tanstatic void
2652f20514bf582d08567217a3b06171bab5a11458eaSamuel Tanstart_unicast_arp(struct interface *ifp)
2653f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan{
2654f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	struct dhcp_state *state = D_STATE(ifp);
2655f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	struct in_addr gwa;
2656f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	struct in_addr src_addr;
2657f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	struct arp_state *astate;
2658f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan
2659f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	if (!state->offer)
2660f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan		return;
2661f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan
2662f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	if (!state->lease.frominfo)
2663f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan		return;
2664f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan
2665f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	if (state->server_info.gw_hwlen != ifp->hwlen)
2666f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan		return;
2667f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan
2668f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	if (get_option_addr(ifp->ctx, &gwa, state->offer, DHO_ROUTER))
2669f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan		return;
2670f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan
2671f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	astate = arp_new(ifp, &gwa);
2672f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	if (!astate)
2673f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan		return;
2674f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	if (state->offer->yiaddr)
2675f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan		astate->src_addr.s_addr = state->offer->yiaddr;
2676f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	else
2677f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan		astate->src_addr.s_addr = state->offer->ciaddr;
2678f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	astate->probed_cb = dhcp_probe_gw_timeout;
2679f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	astate->conflicted_cb = dhcp_probe_gw_response;
2680f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	astate->dest_hwlen = state->server_info.gw_hwlen;
2681f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	memcpy(astate->dest_hwaddr, state->server_info.gw_hwaddr,
2682f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	       state->server_info.gw_hwlen);
2683f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan
2684f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	arp_probe(astate);
2685f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan
2686f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	/* Invalidate our gateway address until the next successful PROBEGW. */
2687f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	state->server_info.gw_hwlen = 0;
2688f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan}
2689f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan
2690f20514bf582d08567217a3b06171bab5a11458eaSamuel Tanstatic void
2691d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_arp_probed(struct arp_state *astate)
2692d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
2693d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_state *state;
2694d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct if_options *ifo;
2695d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2696d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* We didn't find a profile for this
2697d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * address or hwaddr, so move to the next
2698d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * arping profile */
2699d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state = D_STATE(astate->iface);
2700d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ifo = astate->iface->options;
2701d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (state->arping_index < ifo->arping_len) {
2702d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (++state->arping_index < ifo->arping_len) {
2703d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			astate->addr.s_addr =
2704d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    ifo->arping[state->arping_index - 1];
2705d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			arp_probe(astate);
2706d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
2707d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		dhcpcd_startinterface(astate->iface);
2708d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
2709d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
27101c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan
27111c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan	/* Probe the gateway specified in the lease offer. */
27121c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan	if ((ifo->options & DHCPCD_ARPGW) && (dhcp_probe_gw(astate->iface))) {
27131c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan		return;
27141c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan	}
27151c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan
2716d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	dhcp_close(astate->iface);
2717d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	eloop_timeout_delete(astate->iface->ctx->eloop, NULL, astate->iface);
2718d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef IN_IFF_TENTATIVE
2719d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ipv4_finaliseaddr(astate->iface);
2720d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	arp_close(astate->iface);
2721d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#else
2722d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	dhcp_bind(astate->iface, astate);
2723d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
2724d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
2725d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2726d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void
2727d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_arp_conflicted(struct arp_state *astate, const struct arp_msg *amsg)
2728d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
2729d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_state *state;
2730d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct if_options *ifo;
2731d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2732d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state = D_STATE(astate->iface);
2733d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ifo = astate->iface->options;
2734d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (state->arping_index &&
2735d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    state->arping_index <= ifo->arping_len &&
2736d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    amsg &&
2737d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    (amsg->sip.s_addr == ifo->arping[state->arping_index - 1] ||
2738d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    (amsg->sip.s_addr == 0 &&
2739d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    amsg->tip.s_addr == ifo->arping[state->arping_index - 1])))
2740d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	{
2741d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		char buf[HWADDR_LEN * 3];
2742d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2743d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		astate->failed.s_addr = ifo->arping[state->arping_index - 1];
2744d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		arp_report_conflicted(astate, amsg);
2745d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		hwaddr_ntoa(amsg->sha, astate->iface->hwlen, buf, sizeof(buf));
2746d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (dhcpcd_selectprofile(astate->iface, buf) == -1 &&
2747d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    dhcpcd_selectprofile(astate->iface,
2748d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		        inet_ntoa(astate->failed)) == -1)
2749d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		{
2750d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			/* We didn't find a profile for this
2751d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			 * address or hwaddr, so move to the next
2752d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			 * arping profile */
2753d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			dhcp_arp_probed(astate);
2754d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return;
2755d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
2756d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		dhcp_close(astate->iface);
2757d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		arp_close(astate->iface);
2758d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		eloop_timeout_delete(astate->iface->ctx->eloop, NULL,
2759d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    astate->iface);
2760d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		dhcpcd_startinterface(astate->iface);
2761d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
2762d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2763d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* RFC 2131 3.1.5, Client-server interaction
2764d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * NULL amsg means IN_IFF_DUPLICATED */
2765d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (amsg == NULL || (state->offer &&
2766d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    (amsg->sip.s_addr == state->offer->yiaddr ||
2767d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    (amsg->sip.s_addr == 0 &&
2768d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    amsg->tip.s_addr == state->offer->yiaddr))))
2769d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	{
2770d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef IN_IFF_DUPLICATED
2771d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		struct ipv4_addr *ia;
2772d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
2773d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
27745158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan		if (amsg) {
2775d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			astate->failed.s_addr = state->offer->yiaddr;
27765158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan			state->failed.s_addr = state->offer->yiaddr;
27775158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan		} else {
2778d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			astate->failed = astate->addr;
27795158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan			state->failed = astate->addr;
27805158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan		}
27815158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan
2782d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		arp_report_conflicted(astate, amsg);
2783d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		unlink(state->leasefile);
2784d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (!state->lease.frominfo)
2785d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			dhcp_decline(astate->iface);
2786d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef IN_IFF_DUPLICATED
2787d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ia = ipv4_iffindaddr(astate->iface, &astate->addr, NULL);
2788d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (ia)
2789d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			ipv4_deladdr(astate->iface, &ia->addr, &ia->net);
2790d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
279111464a5b08c94f30b5e7b59731e972b8c5bd4099Samuel Tan		arp_close(astate->iface);
2792d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		eloop_timeout_delete(astate->iface->ctx->eloop, NULL,
2793d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    astate->iface);
2794d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		eloop_timeout_add_sec(astate->iface->ctx->eloop,
2795d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    DHCP_RAND_MAX, dhcp_discover, astate->iface);
2796d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
2797d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
2798d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2799d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void
2800b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tanhandle_nak(void *arg)
2801b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan{
2802b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan	struct interface *ifp = arg;
2803b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan	struct dhcp_state *state = D_STATE(ifp);
2804b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan
2805b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan	logger(ifp->ctx, LOG_INFO, "%s: Handling deferred NAK", ifp->name);
2806b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan	if (!(ifp->ctx->options & DHCPCD_TEST)) {
2807b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan		dhcp_drop(ifp, "NAK");
2808b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan		unlink(state->leasefile);
2809b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan	}
2810b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan
2811b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan	/* If we constantly get NAKS then we should slowly back off */
2812b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan	eloop_timeout_add_sec(ifp->ctx->eloop,
2813b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan	    state->nakoff, dhcp_discover, ifp);
2814b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan	if (state->nakoff == 0)
2815b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan		state->nakoff = 1;
2816b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan	else {
2817b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan		state->nakoff *= 2;
2818b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan		if (state->nakoff > NAKOFF_MAX)
2819b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan			state->nakoff = NAKOFF_MAX;
2820b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan	}
2821b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan}
2822b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan
2823b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tanstatic void
2824d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_handledhcp(struct interface *ifp, struct dhcp_message **dhcpp,
2825d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    const struct in_addr *from)
2826d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
2827d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_state *state = D_STATE(ifp);
2828d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct if_options *ifo = ifp->options;
2829d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_message *dhcp = *dhcpp;
2830d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_lease *lease = &state->lease;
2831d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint8_t type, tmp;
2832d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const uint8_t *auth;
2833d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct in_addr addr;
2834d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	unsigned int i;
2835d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t auth_len;
2836d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	char *msg;
2837d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct arp_state *astate;
2838d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct ipv4_addr *ia;
2839d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2840d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* We may have found a BOOTP server */
2841d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (get_option_uint8(ifp->ctx, &type, dhcp, DHO_MESSAGETYPE) == -1)
2842d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		type = 0;
2843d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else if (ifo->options & DHCPCD_BOOTP) {
2844d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		logger(ifp->ctx, LOG_DEBUG,
2845d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    "%s: ignoring DHCP reply (excpecting BOOTP)",
2846d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    ifp->name);
2847d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
2848d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
2849d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
285024aa62eefd9284fb94820093f6088607d42c4249Samuel Tan	logger(ifp->ctx, LOG_INFO, "%s: received %s with xid 0x%x",
285124aa62eefd9284fb94820093f6088607d42c4249Samuel Tan		ifp->name, get_dhcp_op(type), state->xid);
285224aa62eefd9284fb94820093f6088607d42c4249Samuel Tan
2853d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Authenticate the message */
2854d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	auth = get_option(ifp->ctx, dhcp, DHO_AUTHENTICATION, &auth_len);
2855d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (auth) {
2856d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (dhcp_auth_validate(&state->auth, &ifo->auth,
2857d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    (uint8_t *)*dhcpp, sizeof(**dhcpp), 4, type,
2858d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    auth, auth_len) == NULL)
2859d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		{
2860d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ifp->ctx, LOG_DEBUG,
2861d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    "%s: dhcp_auth_validate: %m", ifp->name);
2862d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			log_dhcp1(LOG_ERR, "authentication failed",
2863d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    ifp, dhcp, from, 0);
2864d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return;
2865d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
2866d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (state->auth.token)
2867d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ifp->ctx, LOG_DEBUG,
2868d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    "%s: validated using 0x%08" PRIu32,
2869d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    ifp->name, state->auth.token->secretid);
2870d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		else
2871d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ifp->ctx, LOG_DEBUG,
2872d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    "%s: accepted reconfigure key", ifp->name);
2873d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	} else if (ifo->auth.options & DHCPCD_AUTH_REQUIRE) {
2874d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		log_dhcp1(LOG_ERR, "no authentication", ifp, dhcp, from, 0);
2875d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
2876d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	} else if (ifo->auth.options & DHCPCD_AUTH_SEND)
2877d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		log_dhcp1(LOG_WARNING, "no authentication",
2878d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    ifp, dhcp, from, 0);
2879d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2880d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* RFC 3203 */
2881d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (type == DHCP_FORCERENEW) {
2882d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (from->s_addr == INADDR_ANY ||
2883d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    from->s_addr == INADDR_BROADCAST)
2884d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		{
2885d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			log_dhcp(LOG_ERR, "discarding Force Renew",
2886d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    ifp, dhcp, from);
2887d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return;
2888d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
2889d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (auth == NULL) {
2890d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			log_dhcp(LOG_ERR, "unauthenticated Force Renew",
2891d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    ifp, dhcp, from);
2892d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return;
2893d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
2894d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (state->state != DHS_BOUND && state->state != DHS_INFORM) {
2895d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			log_dhcp(LOG_DEBUG, "not bound, ignoring Force Renew",
2896d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    ifp, dhcp, from);
2897d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return;
2898d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
2899d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		log_dhcp(LOG_ERR, "Force Renew from", ifp, dhcp, from);
2900d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* The rebind and expire timings are still the same, we just
2901d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		 * enter the renew state early */
2902d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (state->state == DHS_BOUND) {
2903d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			eloop_timeout_delete(ifp->ctx->eloop,
2904d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    dhcp_renew, ifp);
2905d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			dhcp_renew(ifp);
2906d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		} else {
2907d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			eloop_timeout_delete(ifp->ctx->eloop,
2908d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    send_inform, ifp);
2909d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			dhcp_inform(ifp);
2910d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
2911d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
2912d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
2913d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2914d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (state->state == DHS_BOUND) {
2915d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* Before we supported FORCERENEW we closed off the raw
2916d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		 * port so we effectively ignored all messages.
2917d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		 * As such we'll not log by default here. */
2918d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		//log_dhcp(LOG_DEBUG, "bound, ignoring", iface, dhcp, from);
2919d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
2920d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
2921d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2922d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Ensure it's the right transaction */
2923d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (state->xid != ntohl(dhcp->xid)) {
2924d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		logger(ifp->ctx, LOG_DEBUG,
2925d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    "%s: wrong xid 0x%x (expecting 0x%x) from %s",
2926d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    ifp->name, ntohl(dhcp->xid), state->xid,
2927d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    inet_ntoa(*from));
2928d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
2929d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
2930d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* reset the message counter */
2931d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->interval = 0;
2932d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2933d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Ensure that no reject options are present */
2934d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	for (i = 1; i < 255; i++) {
2935d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (has_option_mask(ifo->rejectmask, i) &&
2936d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    get_option_uint8(ifp->ctx, &tmp, dhcp, (uint8_t)i) == 0)
2937d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		{
2938d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			log_dhcp(LOG_WARNING, "reject DHCP", ifp, dhcp, from);
2939d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return;
2940d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
2941d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
2942d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2943d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (type == DHCP_NAK) {
2944d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if ((msg = get_option_string(ifp->ctx, dhcp, DHO_MESSAGE))) {
2945d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ifp->ctx, LOG_WARNING, "%s: message: %s",
2946d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    ifp->name, msg);
2947d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			free(msg);
2948d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
2949d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (state->state == DHS_INFORM) /* INFORM should not be NAKed */
2950d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return;
2951d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2952b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan		log_dhcp(LOG_WARNING, "NAK (deferred):", ifp, dhcp, from);
295323ff6edd8b4ec796a32d36a3eca8a8d8c785b565Samuel Tan		rpc_signal_status("NakDefer");
29545158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan		if (state->nak_receive_count == 0)
29555158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan			eloop_timeout_add_sec(ifp->ctx->eloop,
29565158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan					      DHCP_BASE, handle_nak, ifp);
29575158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan		state->nak_receive_count++;
2958d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
2959d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
2960d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2961d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Ensure that all required options are present */
2962d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	for (i = 1; i < 255; i++) {
2963d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (has_option_mask(ifo->requiremask, i) &&
2964d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    get_option_uint8(ifp->ctx, &tmp, dhcp, (uint8_t)i) != 0)
2965d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		{
2966d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			/* If we are BOOTP, then ignore the need for serverid.
2967d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			 * To ignore BOOTP, require dhcp_message_type.
2968d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			 * However, nothing really stops BOOTP from providing
2969d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			 * DHCP style options as well so the above isn't
2970d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			 * always true. */
2971d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (type == 0 && i == DHO_SERVERID)
2972d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				continue;
2973d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			log_dhcp(LOG_WARNING, "reject DHCP", ifp, dhcp, from);
2974d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return;
2975d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
2976d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
2977d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
2978d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* DHCP Auto-Configure, RFC 2563 */
2979d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (type == DHCP_OFFER && dhcp->yiaddr == 0) {
2980d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		log_dhcp(LOG_WARNING, "no address given", ifp, dhcp, from);
2981d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if ((msg = get_option_string(ifp->ctx, dhcp, DHO_MESSAGE))) {
2982d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ifp->ctx, LOG_WARNING,
2983d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    "%s: message: %s", ifp->name, msg);
2984d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			free(msg);
2985d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
2986d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if ((state->state == DHS_DISCOVER ||
2987d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    state->state == DHS_IPV4LL_BOUND) &&
2988d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    get_option_uint8(ifp->ctx, &tmp, dhcp,
2989d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    DHO_AUTOCONFIGURE) == 0)
2990d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		{
2991d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			switch (tmp) {
2992d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			case 0:
2993d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				log_dhcp(LOG_WARNING, "IPv4LL disabled from",
2994d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    ifp, dhcp, from);
2995d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				dhcp_drop(ifp, "EXPIRE");
2996d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				arp_close(ifp);
2997d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				eloop_timeout_delete(ifp->ctx->eloop,
2998d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    NULL, ifp);
2999d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				eloop_timeout_add_sec(ifp->ctx->eloop,
3000d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    DHCP_MAX, dhcp_discover,
3001d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    ifp);
3002d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				break;
3003d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			case 1:
3004d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				log_dhcp(LOG_WARNING, "IPv4LL enabled from",
3005d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    ifp, dhcp, from);
3006d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				eloop_timeout_delete(ifp->ctx->eloop,
3007d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    NULL, ifp);
3008d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				if (IN_LINKLOCAL(htonl(state->addr.s_addr)))
3009d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					eloop_timeout_add_sec(ifp->ctx->eloop,
3010d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					    DHCP_MAX, dhcp_discover, ifp);
3011d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				else
3012d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					ipv4ll_start(ifp);
3013d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				break;
3014d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			default:
3015d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				logger(ifp->ctx, LOG_ERR,
3016d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    "%s: unknown auto configuration option %d",
3017d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    ifp->name, tmp);
3018d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				break;
3019d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
3020d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
3021d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
3022d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
3023d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3024d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Ensure that the address offered is valid */
3025d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if ((type == 0 || type == DHCP_OFFER || type == DHCP_ACK) &&
3026d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    (dhcp->ciaddr == INADDR_ANY || dhcp->ciaddr == INADDR_BROADCAST) &&
3027d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    (dhcp->yiaddr == INADDR_ANY || dhcp->yiaddr == INADDR_BROADCAST))
3028d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	{
302923ff6edd8b4ec796a32d36a3eca8a8d8c785b565Samuel Tan		rpc_signal_status("IgnoreInvalidOffer");
3030d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		log_dhcp(LOG_WARNING, "reject invalid address",
3031d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    ifp, dhcp, from);
3032d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
3033d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
3034d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3035d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef IN_IFF_DUPLICATED
3036d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ia = ipv4_iffindaddr(ifp, &lease->addr, NULL);
3037d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ia && ia->addr_flags & IN_IFF_DUPLICATED) {
3038d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		log_dhcp(LOG_WARNING, "declined duplicate address",
3039d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    ifp, dhcp, from);
3040d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (type)
3041d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			dhcp_decline(ifp);
3042d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ipv4_deladdr(ifp, &ia->addr, &ia->net);
3043d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
3044d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		eloop_timeout_add_sec(ifp->ctx->eloop,
3045d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    DHCP_RAND_MAX, dhcp_discover, ifp);
3046d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
3047d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
3048d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
3049d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3050d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if ((type == 0 || type == DHCP_OFFER) &&
3051d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    (state->state == DHS_DISCOVER || state->state == DHS_IPV4LL_BOUND))
3052d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	{
30535158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan		if (dhcp->yiaddr == state->failed.s_addr &&
30545158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan		    state->failed_address_offer_count == 0) {
30555158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan			log_dhcp(LOG_WARNING,
30565158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan				 "reject previously declined address",
30575158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan				 ifp, dhcp, from);
305823ff6edd8b4ec796a32d36a3eca8a8d8c785b565Samuel Tan			rpc_signal_status("IgnoreFailedOffer");
30595158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan			state->failed_address_offer_count++;
30605158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan			return;
30615158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan		}
3062d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		lease->frominfo = 0;
3063d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		lease->addr.s_addr = dhcp->yiaddr;
3064d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		lease->cookie = dhcp->cookie;
3065d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (type == 0 ||
3066d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    get_option_addr(ifp->ctx,
3067d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    &lease->server, dhcp, DHO_SERVERID) != 0)
3068d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			lease->server.s_addr = INADDR_ANY;
3069d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		log_dhcp(LOG_INFO, "offered", ifp, dhcp, from);
3070d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		free(state->offer);
3071d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		state->offer = dhcp;
3072d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		*dhcpp = NULL;
3073d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (ifp->ctx->options & DHCPCD_TEST) {
3074d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			free(state->old);
3075d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			state->old = state->new;
3076d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			state->new = state->offer;
3077d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			state->offer = NULL;
3078d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			state->reason = "TEST";
3079d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			script_runreason(ifp, state->reason);
3080d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			eloop_exit(ifp->ctx->eloop, EXIT_SUCCESS);
3081d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return;
3082d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
3083d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		eloop_timeout_delete(ifp->ctx->eloop, send_discover, ifp);
3084b2d21e6cab5a0167e9e4d0698795b38f6c790ab3Samuel Tan		eloop_timeout_delete(ifp->ctx->eloop, handle_nak, ifp);
3085d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* We don't request BOOTP addresses */
3086d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (type) {
3087d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			/* We used to ARP check here, but that seems to be in
3088d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			 * violation of RFC2131 where it only describes
3089d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			 * DECLINE after REQUEST.
3090d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			 * It also seems that some MS DHCP servers actually
3091d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			 * ignore DECLINE if no REQUEST, ie we decline a
3092d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			 * DISCOVER. */
3093d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			dhcp_request(ifp);
3094d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return;
3095d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
3096d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
3097d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3098d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (type) {
3099d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (type == DHCP_OFFER) {
3100d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			log_dhcp(LOG_WARNING, "ignoring offer of",
3101d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    ifp, dhcp, from);
310223ff6edd8b4ec796a32d36a3eca8a8d8c785b565Samuel Tan			rpc_signal_status("IgnoreAdditionalOffer");
3103d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return;
3104d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
3105d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3106d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* We should only be dealing with acks */
3107d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (type != DHCP_ACK) {
3108d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			log_dhcp(LOG_ERR, "not ACK or OFFER",
3109d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    ifp, dhcp, from);
311023ff6edd8b4ec796a32d36a3eca8a8d8c785b565Samuel Tan			rpc_signal_status("IgnoreNonOffer");
3111d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return;
3112d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
3113d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3114d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (!(ifo->options & DHCPCD_INFORM))
311524aa62eefd9284fb94820093f6088607d42c4249Samuel Tan			log_dhcp(LOG_INFO, "acknowledged", ifp, dhcp, from);
3116d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		else
3117d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    ifo->options &= ~DHCPCD_STATIC;
3118d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
3119d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3120d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3121d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* No NAK, so reset the backoff
3122d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * We don't reset on an OFFER message because the server could
3123d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * potentially NAK the REQUEST. */
3124d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->nakoff = 0;
3125d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3126d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* BOOTP could have already assigned this above, so check we still
3127d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * have a pointer. */
3128d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (*dhcpp) {
3129d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		free(state->offer);
3130d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		state->offer = dhcp;
3131d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		*dhcpp = NULL;
3132d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
3133d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3134d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	lease->frominfo = 0;
3135d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
3136d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	astate = NULL;
3137d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
313847d708b8f4e037f6f224f71ea5864c90184b4ffbSamuel Tan#ifdef IN_IFF_TENTATIVE
313947d708b8f4e037f6f224f71ea5864c90184b4ffbSamuel Tan	addr.s_addr = state->offer->yiaddr;
314047d708b8f4e037f6f224f71ea5864c90184b4ffbSamuel Tan	astate = arp_new(ifp, &addr);
314147d708b8f4e037f6f224f71ea5864c90184b4ffbSamuel Tan	if (astate) {
314247d708b8f4e037f6f224f71ea5864c90184b4ffbSamuel Tan		astate->probed_cb = dhcp_arp_probed;
314347d708b8f4e037f6f224f71ea5864c90184b4ffbSamuel Tan		astate->conflicted_cb = dhcp_arp_conflicted;
314447d708b8f4e037f6f224f71ea5864c90184b4ffbSamuel Tan		/* No need to start the probe as we'll
314547d708b8f4e037f6f224f71ea5864c90184b4ffbSamuel Tan		 * listen to the kernel stating DAD or not and
314647d708b8f4e037f6f224f71ea5864c90184b4ffbSamuel Tan		 * that action look look for our ARP state  for
314747d708b8f4e037f6f224f71ea5864c90184b4ffbSamuel Tan		 * what to do. */
314847d708b8f4e037f6f224f71ea5864c90184b4ffbSamuel Tan	}
314947d708b8f4e037f6f224f71ea5864c90184b4ffbSamuel Tan#else
31505158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan	if ((ifo->options & DHCPCD_ARP || state->nak_receive_count > 0 ||
31515158c9dfe576a285663b4ba16828fd6e9b35779cSamuel Tan	     dhcp->yiaddr == state->failed.s_addr)
3152d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    && state->addr.s_addr != state->offer->yiaddr)
3153d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	{
3154d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		addr.s_addr = state->offer->yiaddr;
3155d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* If the interface already has the address configured
3156d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		 * then we can't ARP for duplicate detection. */
3157d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ia = ipv4_findaddr(ifp->ctx, &addr);
315847d708b8f4e037f6f224f71ea5864c90184b4ffbSamuel Tan		if (ia == NULL) {
3159d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			astate = arp_new(ifp, &addr);
3160d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (astate) {
3161d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				astate->probed_cb = dhcp_arp_probed;
3162d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				astate->conflicted_cb = dhcp_arp_conflicted;
3163d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				arp_probe(astate);
316423ff6edd8b4ec796a32d36a3eca8a8d8c785b565Samuel Tan				rpc_signal_status("ArpSelf");
3165d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
3166d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return;
3167d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
3168d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
316947d708b8f4e037f6f224f71ea5864c90184b4ffbSamuel Tan#endif
3170d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
31711c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan	if ((ifo->options & DHCPCD_ARPGW) && (dhcp_probe_gw(ifp))) {
317223ff6edd8b4ec796a32d36a3eca8a8d8c785b565Samuel Tan		rpc_signal_status("ArpGateway");
31731c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan		return;
31741c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan	}
31751c4088e958ed0fded0040bcb1d67b73159acfe8cSamuel Tan
3176d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	dhcp_bind(ifp, astate);
3177d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
3178d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3179d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic size_t
3180d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanget_udp_data(const uint8_t **data, const uint8_t *udp)
3181d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
3182d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct udp_dhcp_packet p;
3183d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3184d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	memcpy(&p, udp, sizeof(p));
3185d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	*data = udp + offsetof(struct udp_dhcp_packet, dhcp);
3186d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return ntohs(p.ip.ip_len) - sizeof(p.ip) - sizeof(p.udp);
3187d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
3188d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3189d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
3190d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanvalid_udp_packet(const uint8_t *data, size_t data_len, struct in_addr *from,
3191d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    int noudpcsum)
3192d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
3193d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct udp_dhcp_packet p;
3194d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint16_t bytes, udpsum;
3195d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3196d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (data_len < sizeof(p.ip)) {
319724aa62eefd9284fb94820093f6088607d42c4249Samuel Tan		syslog(LOG_WARNING, "packet short than an ip header "
319824aa62eefd9284fb94820093f6088607d42c4249Samuel Tan			"(len=%zd)", data_len);
3199d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (from)
3200d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			from->s_addr = INADDR_ANY;
3201d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		errno = EINVAL;
3202d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
3203d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
3204d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	memcpy(&p, data, MIN(data_len, sizeof(p)));
3205d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (from)
3206d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		from->s_addr = p.ip.ip_src.s_addr;
3207d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (data_len > sizeof(p)) {
320824aa62eefd9284fb94820093f6088607d42c4249Samuel Tan		syslog(LOG_WARNING, "packet too long (%zd bytes)", data_len);
3209d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		errno = EINVAL;
3210d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
3211d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
3212d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (checksum(&p.ip, sizeof(p.ip)) != 0) {
321324aa62eefd9284fb94820093f6088607d42c4249Samuel Tan		syslog(LOG_WARNING, "packet failed ip header checksum");
3214d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		errno = EINVAL;
3215d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
3216d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
3217d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3218d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	bytes = ntohs(p.ip.ip_len);
3219d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (data_len < bytes) {
322024aa62eefd9284fb94820093f6088607d42c4249Samuel Tan		syslog(LOG_WARNING, "packet appears truncated "
322124aa62eefd9284fb94820093f6088607d42c4249Samuel Tan			"(len=%zd, ip_len=%zd)", data_len, bytes);
3222d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		errno = EINVAL;
3223d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
3224d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
3225d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3226d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (noudpcsum == 0) {
3227d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		udpsum = p.udp.uh_sum;
3228d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		p.udp.uh_sum = 0;
3229d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		p.ip.ip_hl = 0;
3230d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		p.ip.ip_v = 0;
3231d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		p.ip.ip_tos = 0;
3232d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		p.ip.ip_len = p.udp.uh_ulen;
3233d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		p.ip.ip_id = 0;
3234d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		p.ip.ip_off = 0;
3235d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		p.ip.ip_ttl = 0;
3236d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		p.ip.ip_sum = 0;
3237d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (udpsum && checksum(&p, bytes) != udpsum) {
323824aa62eefd9284fb94820093f6088607d42c4249Samuel Tan			syslog(LOG_WARNING, "packet failed udp checksum");
3239d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			errno = EINVAL;
3240d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return -1;
3241d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
3242d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
3243d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3244d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return 0;
3245d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
3246d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3247d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void
3248d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_handlepacket(void *arg)
3249d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
3250d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct interface *ifp = arg;
3251d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_message *dhcp = NULL;
3252d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const uint8_t *pp;
3253d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t bytes;
3254d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct in_addr from;
3255d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int i, flags;
3256d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const struct dhcp_state *state = D_CSTATE(ifp);
3257d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3258d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Need this API due to BPF */
3259d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	flags = 0;
3260d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	while (!(flags & RAW_EOF)) {
3261d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		bytes = (size_t)if_readrawpacket(ifp, ETHERTYPE_IP,
3262d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    ifp->ctx->packet, udp_dhcp_len, &flags);
3263d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if ((ssize_t)bytes == -1) {
3264d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ifp->ctx, LOG_ERR,
3265d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    "%s: dhcp if_readrawpacket: %m", ifp->name);
3266d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			dhcp_close(ifp);
3267d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			arp_close(ifp);
3268d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			break;
3269d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
3270d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (valid_udp_packet(ifp->ctx->packet, bytes,
3271d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    &from, flags & RAW_PARTIALCSUM) == -1)
3272d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		{
3273d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ifp->ctx, LOG_ERR,
3274d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    "%s: invalid UDP packet from %s",
3275d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    ifp->name, inet_ntoa(from));
3276d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			continue;
3277d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
3278d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		i = whitelisted_ip(ifp->options, from.s_addr);
3279d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (i == 0) {
3280d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ifp->ctx, LOG_WARNING,
3281d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    "%s: non whitelisted DHCP packet from %s",
3282d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    ifp->name, inet_ntoa(from));
3283d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			continue;
3284d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		} else if (i != 1 &&
3285d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    blacklisted_ip(ifp->options, from.s_addr) == 1)
3286d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		{
3287d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ifp->ctx, LOG_WARNING,
3288d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    "%s: blacklisted DHCP packet from %s",
3289d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    ifp->name, inet_ntoa(from));
3290d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			continue;
3291d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
3292d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (ifp->flags & IFF_POINTOPOINT &&
3293d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    state->dst.s_addr != from.s_addr)
3294d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		{
3295d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ifp->ctx, LOG_WARNING,
3296d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    "%s: server %s is not destination",
3297d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    ifp->name, inet_ntoa(from));
3298d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
3299d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		bytes = get_udp_data(&pp, ifp->ctx->packet);
3300d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (bytes > sizeof(*dhcp)) {
3301d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ifp->ctx, LOG_ERR,
3302d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    "%s: packet greater than DHCP size from %s",
3303d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    ifp->name, inet_ntoa(from));
3304d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			continue;
3305d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
3306d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (dhcp == NULL) {
3307d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		        dhcp = calloc(1, sizeof(*dhcp));
3308d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (dhcp == NULL) {
3309d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				logger(ifp->ctx, LOG_ERR,
3310d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    "%s: calloc: %m", __func__);
3311d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				break;
3312d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
3313d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
3314d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		memcpy(dhcp, pp, bytes);
3315d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (dhcp->cookie != htonl(MAGIC_COOKIE)) {
3316d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ifp->ctx, LOG_DEBUG, "%s: bogus cookie from %s",
3317d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    ifp->name, inet_ntoa(from));
3318d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			continue;
3319d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
3320d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* Ensure packet is for us */
3321d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (ifp->hwlen <= sizeof(dhcp->chaddr) &&
3322d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    memcmp(dhcp->chaddr, ifp->hwaddr, ifp->hwlen))
3323d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		{
3324d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			char buf[sizeof(dhcp->chaddr) * 3];
3325d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3326d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ifp->ctx, LOG_DEBUG,
3327d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    "%s: xid 0x%x is for hwaddr %s",
3328d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    ifp->name, ntohl(dhcp->xid),
3329d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    hwaddr_ntoa(dhcp->chaddr, sizeof(dhcp->chaddr),
3330d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				buf, sizeof(buf)));
3331d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			continue;
3332d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
3333d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		dhcp_handledhcp(ifp, &dhcp, &from);
3334d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (state->raw_fd == -1)
3335d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			break;
3336d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
3337d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	free(dhcp);
3338d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
3339d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3340d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void
3341d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_handleudp(void *arg)
3342d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
3343d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcpcd_ctx *ctx;
3344d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint8_t buffer[sizeof(struct dhcp_message)];
3345d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3346d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ctx = arg;
3347d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3348d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Just read what's in the UDP fd and discard it as we always read
3349d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * from the raw fd */
3350d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (read(ctx->udp_fd, buffer, sizeof(buffer)) == -1) {
3351d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		logger(ctx, LOG_ERR, "%s: %m", __func__);
3352d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		eloop_event_delete(ctx->eloop, ctx->udp_fd, 0);
3353d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		close(ctx->udp_fd);
3354d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ctx->udp_fd = -1;
3355d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
3356d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
3357d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3358d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
3359d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_open(struct interface *ifp)
3360d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
3361d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_state *state;
3362d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3363d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifp->ctx->packet == NULL) {
3364d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ifp->ctx->packet = malloc(udp_dhcp_len);
3365d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (ifp->ctx->packet == NULL) {
3366d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
3367d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return -1;
3368d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
3369d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
3370d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3371d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state = D_STATE(ifp);
3372d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (state->raw_fd == -1) {
3373d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		state->raw_fd = if_openrawsocket(ifp, ETHERTYPE_IP);
3374d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (state->raw_fd == -1) {
3375d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (errno == ENOENT) {
3376d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				logger(ifp->ctx, LOG_ERR,
3377d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    "%s not found", if_pfname);
3378d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				/* May as well disable IPv4 entirely at
3379d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				 * this point as we really need it. */
3380d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				ifp->options->options &= ~DHCPCD_IPV4;
3381d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			} else
3382d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				logger(ifp->ctx, LOG_ERR, "%s: %s: %m",
3383d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    __func__, ifp->name);
3384d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return -1;
3385d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
3386d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		eloop_event_add(ifp->ctx->eloop,
3387d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    state->raw_fd, dhcp_handlepacket, ifp, NULL, NULL);
3388d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
3389d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return 0;
3390d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
3391d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3392d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint
3393d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_dump(struct interface *ifp)
3394d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
3395d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_state *state;
3396d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3397d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ifp->if_data[IF_DATA_DHCP] = state = calloc(1, sizeof(*state));
3398d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (state == NULL)
3399d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		goto eexit;
3400d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->raw_fd = state->arp_fd = -1;
3401d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	TAILQ_INIT(&state->arp_states);
3402d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	dhcp_set_leasefile(state->leasefile, sizeof(state->leasefile),
3403d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    AF_INET, ifp, "");
3404d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->new = read_lease(ifp);
3405d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (state->new == NULL) {
3406d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		logger(ifp->ctx, LOG_ERR, "%s: %s: %m",
3407d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    *ifp->name ? ifp->name : state->leasefile, __func__);
3408d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
3409d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
3410d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->reason = "DUMP";
3411d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return script_runreason(ifp, state->reason);
3412d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3413d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Taneexit:
3414d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
3415d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return -1;
3416d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
3417d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3418d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanvoid
3419d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_free(struct interface *ifp)
3420d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
3421d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_state *state = D_STATE(ifp);
3422d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcpcd_ctx *ctx;
3423d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3424d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	dhcp_close(ifp);
3425d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	arp_close(ifp);
3426d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (state) {
3427d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		free(state->old);
3428d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		free(state->new);
3429d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		free(state->offer);
3430d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		free(state->buffer);
3431d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		free(state->clientid);
3432d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		free(state);
3433d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ifp->if_data[IF_DATA_DHCP] = NULL;
3434d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
3435d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3436d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ctx = ifp->ctx;
3437d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* If we don't have any more DHCP enabled interfaces,
3438d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * close the global socket and release resources */
3439d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ctx->ifaces) {
3440d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		TAILQ_FOREACH(ifp, ctx->ifaces, next) {
3441d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (D_STATE(ifp))
3442d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				break;
3443d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
3444d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
3445d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifp == NULL) {
3446d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (ctx->udp_fd != -1) {
3447d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			eloop_event_delete(ctx->eloop, ctx->udp_fd, 0);
3448d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			close(ctx->udp_fd);
3449d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			ctx->udp_fd = -1;
3450d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
3451d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3452d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		free(ctx->packet);
3453d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		free(ctx->opt_buffer);
3454d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ctx->packet = NULL;
3455d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ctx->opt_buffer = NULL;
3456d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
3457d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
3458d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3459d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
3460d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_init(struct interface *ifp)
3461d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
3462d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_state *state;
3463d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const struct if_options *ifo;
3464d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint8_t len;
3465d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	char buf[(sizeof(ifo->clientid) - 1) * 3];
3466d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3467d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state = D_STATE(ifp);
3468d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (state == NULL) {
3469d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ifp->if_data[IF_DATA_DHCP] = calloc(1, sizeof(*state));
3470d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		state = D_STATE(ifp);
3471d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (state == NULL)
3472d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return -1;
3473d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* 0 is a valid fd, so init to -1 */
3474d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		state->raw_fd = state->arp_fd = -1;
3475d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		TAILQ_INIT(&state->arp_states);
3476d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3477d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* Now is a good time to find IPv4 routes */
3478d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if_initrt(ifp);
3479d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
3480d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3481d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->state = DHS_INIT;
3482d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->reason = "PREINIT";
3483d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->nakoff = 0;
3484d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	dhcp_set_leasefile(state->leasefile, sizeof(state->leasefile),
3485d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    AF_INET, ifp, "");
3486d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3487d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ifo = ifp->options;
3488d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* We need to drop the leasefile so that dhcp_start
3489d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * doesn't load it. */
3490d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifo->options & DHCPCD_REQUEST)
3491d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		unlink(state->leasefile);
3492d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3493d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	free(state->clientid);
3494d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->clientid = NULL;
3495d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3496d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (*ifo->clientid) {
3497d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		state->clientid = malloc((size_t)(ifo->clientid[0] + 1));
3498d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (state->clientid == NULL)
3499d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			goto eexit;
3500d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		memcpy(state->clientid, ifo->clientid,
3501d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    (size_t)(ifo->clientid[0]) + 1);
3502d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	} else if (ifo->options & DHCPCD_CLIENTID) {
3503d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (ifo->options & DHCPCD_DUID) {
3504d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			state->clientid = malloc(ifp->ctx->duid_len + 6);
3505d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (state->clientid == NULL)
3506d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				goto eexit;
3507d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			state->clientid[0] =(uint8_t)(ifp->ctx->duid_len + 5);
3508d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			state->clientid[1] = 255; /* RFC 4361 */
3509d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			memcpy(state->clientid + 2, ifo->iaid, 4);
3510d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			memcpy(state->clientid + 6, ifp->ctx->duid,
3511d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    ifp->ctx->duid_len);
3512d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		} else {
3513d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			len = (uint8_t)(ifp->hwlen + 1);
3514d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			state->clientid = malloc((size_t)len + 1);
3515d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (state->clientid == NULL)
3516d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				goto eexit;
3517d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			state->clientid[0] = len;
3518d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			state->clientid[1] = (uint8_t)ifp->family;
3519d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			memcpy(state->clientid + 2, ifp->hwaddr,
3520d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    ifp->hwlen);
3521d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
3522d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
3523d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3524d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifo->options & DHCPCD_DUID)
3525d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* Don't bother logging as DUID and IAID are reported
3526d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		 * at device start. */
3527d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return 0;
3528d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3529d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifo->options & DHCPCD_CLIENTID)
3530d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		logger(ifp->ctx, LOG_DEBUG, "%s: using ClientID %s", ifp->name,
3531d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    hwaddr_ntoa(state->clientid + 1, state->clientid[0],
3532d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			buf, sizeof(buf)));
3533d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else if (ifp->hwlen)
3534d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		logger(ifp->ctx, LOG_DEBUG, "%s: using hwaddr %s", ifp->name,
3535d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    hwaddr_ntoa(ifp->hwaddr, ifp->hwlen, buf, sizeof(buf)));
3536d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return 0;
3537d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3538d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Taneexit:
3539d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	logger(ifp->ctx, LOG_ERR, "%s: error making ClientID: %m", __func__);
3540d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return -1;
3541d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
3542d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3543d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void
3544d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_start1(void *arg)
3545d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
3546d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct interface *ifp = arg;
3547d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct if_options *ifo = ifp->options;
3548d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_state *state;
3549d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct stat st;
3550d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint32_t l;
3551d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int nolease;
3552d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3553d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (!(ifo->options & DHCPCD_IPV4))
3554d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
3555d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3556d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Listen on *.*.*.*:bootpc so that the kernel never sends an
3557d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * ICMP port unreachable message back to the DHCP server */
3558d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifp->ctx->udp_fd == -1) {
3559d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ifp->ctx->udp_fd = dhcp_openudp(NULL);
3560d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (ifp->ctx->udp_fd == -1) {
3561d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			/* Don't log an error if some other process
3562d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			 * is handling this. */
3563d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (errno != EADDRINUSE)
3564d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				logger(ifp->ctx, LOG_ERR,
3565d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    "%s: dhcp_openudp: %m", __func__);
3566d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		} else
3567d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			eloop_event_add(ifp->ctx->eloop,
3568d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    ifp->ctx->udp_fd, dhcp_handleudp,
3569d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    ifp->ctx, NULL, NULL);
3570d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
3571d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3572d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (dhcp_init(ifp) == -1) {
3573d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		logger(ifp->ctx, LOG_ERR, "%s: dhcp_init: %m", ifp->name);
3574d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
3575d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
3576d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3577d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state = D_STATE(ifp);
3578d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->start_uptime = uptime();
3579d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	free(state->offer);
3580d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->offer = NULL;
3581d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3582d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (state->arping_index < ifo->arping_len) {
3583d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		struct arp_state *astate;
3584d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3585d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		astate = arp_new(ifp, NULL);
3586d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (astate) {
3587d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			astate->probed_cb = dhcp_arp_probed;
3588d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			astate->conflicted_cb = dhcp_arp_conflicted;
3589d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			dhcp_arp_probed(astate);
3590d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
3591d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
3592d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
3593d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3594d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifo->options & DHCPCD_STATIC) {
3595d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		dhcp_static(ifp);
3596d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
3597d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
3598d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3599d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifo->options & DHCPCD_DHCP && dhcp_open(ifp) == -1)
3600d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
3601d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3602d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifo->options & DHCPCD_INFORM) {
3603d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		dhcp_inform(ifp);
3604d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
3605d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
3606d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifp->hwlen == 0 && ifo->clientid[0] == '\0') {
3607d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		logger(ifp->ctx, LOG_WARNING,
3608d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    "%s: needs a clientid to configure", ifp->name);
3609d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		dhcp_drop(ifp, "FAIL");
3610d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
3611d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
3612d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
3613d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* We don't want to read the old lease if we NAK an old test */
3614d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nolease = state->offer && ifp->ctx->options & DHCPCD_TEST;
3615d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (!nolease) {
3616d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		state->offer = read_lease(ifp);
3617d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* Check the saved lease matches the type we want */
3618d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (state->offer) {
3619d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef IN_IFF_DUPLICATED
3620d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			struct in_addr addr;
3621d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			struct ipv4_addr *ia;
3622d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3623d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			addr.s_addr = state->offer->yiaddr;
3624d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			ia = ipv4_iffindaddr(ifp, &addr, NULL);
3625d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
3626d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3627d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if ((IS_BOOTP(ifp, state->offer) &&
3628d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    !(ifo->options & DHCPCD_BOOTP)) ||
3629d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef IN_IFF_DUPLICATED
3630d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    (ia && ia->addr_flags & IN_IFF_DUPLICATED) ||
3631d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
3632d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    (!IS_BOOTP(ifp, state->offer) &&
3633d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    ifo->options & DHCPCD_BOOTP))
3634d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			{
3635d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				free(state->offer);
3636d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				state->offer = NULL;
3637d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
3638d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
3639d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
3640d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (state->offer) {
3641d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		get_lease(ifp->ctx, &state->lease, state->offer);
3642d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		state->lease.frominfo = 1;
3643d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (state->new == NULL &&
3644d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    ipv4_iffindaddr(ifp, &state->lease.addr, &state->lease.net))
3645d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		{
3646d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			/* We still have the IP address from the last lease.
3647d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			 * Fake add the address and routes from it so the lease
3648d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			 * can be cleaned up. */
3649d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			state->new = malloc(sizeof(*state->new));
3650d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (state->new) {
3651d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				memcpy(state->new, state->offer,
3652d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    sizeof(*state->new));
3653d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				state->addr = state->lease.addr;
3654d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				state->net = state->lease.net;
3655d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				state->added |= STATE_ADDED | STATE_FAKE;
3656d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				ipv4_buildroutes(ifp->ctx);
3657d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			} else
3658d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
3659d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
3660d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (state->offer->cookie == 0) {
3661d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (state->offer->yiaddr == state->addr.s_addr) {
3662d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				free(state->offer);
3663d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				state->offer = NULL;
3664d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
3665d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		} else if (state->lease.leasetime != ~0U &&
3666d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    stat(state->leasefile, &st) == 0)
3667d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		{
3668d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			time_t now;
3669d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3670d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			/* Offset lease times and check expiry */
3671d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			now = time(NULL);
3672d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (now == -1 ||
3673d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    (time_t)state->lease.leasetime < now - st.st_mtime)
3674d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			{
3675d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				logger(ifp->ctx, LOG_DEBUG,
3676d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				    "%s: discarding expired lease", ifp->name);
3677d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				free(state->offer);
3678d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				state->offer = NULL;
3679d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				state->lease.addr.s_addr = 0;
3680d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				/* Technically we should discard the lease
3681d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				 * as it's expired, just as DHCPv6 addresses
3682d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				 * would be by the kernel.
3683d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				 * However, this may violate POLA so
3684d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				 * we currently leave it be.
3685d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				 * If we get a totally different lease from
3686d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				 * the DHCP server we'll drop it anyway, as
3687d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				 * we will on any other event which would
3688d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				 * trigger a lease drop.
3689d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				 * This should only happen if dhcpcd stops
3690d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				 * running and the lease expires before
3691d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				 * dhcpcd starts again. */
3692d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#if 0
3693d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				if (state->new)
3694d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					dhcp_drop(ifp, "EXPIRE");
3695d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
3696d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			} else {
3697d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				l = (uint32_t)(now - st.st_mtime);
3698d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				state->lease.leasetime -= l;
3699d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				state->lease.renewaltime -= l;
3700d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				state->lease.rebindtime -= l;
3701d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
3702d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
3703d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
3704d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3705d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (!(ifo->options & DHCPCD_DHCP)) {
3706d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (ifo->options & DHCPCD_IPV4LL) {
3707d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (state->offer && state->offer->cookie != 0) {
3708d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				free(state->offer);
3709d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				state->offer = NULL;
3710d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
3711d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			ipv4ll_start(ifp);
3712d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
3713d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
3714d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
3715d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3716d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (state->offer == NULL || state->offer->cookie == 0)
3717d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		dhcp_discover(ifp);
3718d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else
3719d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		dhcp_reboot(ifp);
3720d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
3721d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3722d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanvoid
3723d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_start(struct interface *ifp)
3724d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
3725d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct timespec tv;
3726d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3727d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (!(ifp->options->options & DHCPCD_IPV4))
3728d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
3729d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3730d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* No point in delaying a static configuration */
3731d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	tv.tv_sec = DHCP_MIN_DELAY;
3732d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	tv.tv_nsec = (suseconds_t)arc4random_uniform(
3733d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    (DHCP_MAX_DELAY - DHCP_MIN_DELAY) * NSEC_PER_SEC);
3734d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	timespecnorm(&tv);
3735d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	logger(ifp->ctx, LOG_DEBUG,
3736d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    "%s: delaying IPv4 for %0.1f seconds",
3737d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    ifp->name, timespec_to_double(&tv));
3738d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3739d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	eloop_timeout_add_tv(ifp->ctx->eloop, &tv, dhcp_start1, ifp);
3740d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
3741d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3742d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanvoid
3743d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tandhcp_handleifa(int cmd, struct interface *ifp,
3744d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const struct in_addr *addr,
3745d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const struct in_addr *net,
3746d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const struct in_addr *dst,
3747d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	__unused int flags)
3748d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
3749d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_state *state;
3750d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct if_options *ifo;
3751d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint8_t i;
3752d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3753d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state = D_STATE(ifp);
3754d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (state == NULL)
3755d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
3756d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3757d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (cmd == RTM_DELADDR) {
3758d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (state->addr.s_addr == addr->s_addr &&
3759d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    state->net.s_addr == net->s_addr)
3760d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		{
3761d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ifp->ctx, LOG_INFO,
3762d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    "%s: removing IP address %s/%d",
3763d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    ifp->name, inet_ntoa(state->addr),
3764d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    inet_ntocidr(state->net));
3765d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			dhcp_drop(ifp, "EXPIRE");
3766d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
3767d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
3768d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
3769d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3770d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (cmd != RTM_NEWADDR)
3771d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
3772d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3773d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ifo = ifp->options;
3774d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifo->options & DHCPCD_INFORM) {
3775d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (state->state != DHS_INFORM)
3776d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			dhcp_inform(ifp);
3777d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
3778d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
3779d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3780d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (!(ifo->options & DHCPCD_STATIC))
3781d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
3782d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifo->req_addr.s_addr != INADDR_ANY)
3783d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
3784d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
3785d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	free(state->old);
3786d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->old = state->new;
3787d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->new = dhcp_message_new(addr, net);
3788d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (state->new == NULL)
3789d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return;
3790d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->dst.s_addr = dst ? dst->s_addr : INADDR_ANY;
3791d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (dst) {
3792d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		for (i = 1; i < 255; i++)
3793d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (i != DHO_ROUTER && has_option_mask(ifo->dstmask,i))
3794d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				dhcp_message_add_addr(state->new, i, *dst);
3795d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
3796d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state->reason = "STATIC";
3797d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ipv4_buildroutes(ifp->ctx);
3798d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	script_runreason(ifp, state->reason);
3799d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifo->options & DHCPCD_INFORM) {
3800d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		state->state = DHS_INFORM;
3801d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		state->xid = dhcp_xid(ifp);
3802d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		state->lease.server.s_addr = dst ? dst->s_addr : INADDR_ANY;
3803d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		state->addr = *addr;
3804d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		state->net = *net;
3805d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		dhcp_inform(ifp);
3806d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
3807d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
3808