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 <asm/types.h> /* Needed for 2.4 kernels */
29d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
30d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <sys/types.h>
31d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <sys/socket.h>
32d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <sys/ioctl.h>
33d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <sys/param.h>
34d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
35d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <linux/if_addr.h>
36d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <linux/if_link.h>
37d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <linux/if_packet.h>
38d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <linux/filter.h>
39d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <linux/netlink.h>
40d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <linux/rtnetlink.h>
41d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
42d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <arpa/inet.h>
43d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <net/if.h>
44d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <netinet/if_ether.h>
45d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <netinet/in_systm.h>
46d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <netinet/in.h>
47d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <net/route.h>
48d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
49d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan/* Support older kernels */
50d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifndef IFLA_WIRELESS
51d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan# define IFLA_WIRELESS (IFLA_MASTER + 1)
52d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
53d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
54d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan/* Linux has these in an enum and there is just no way to work
55d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * out of they exist at compile time. Silly silly silly. */
56d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define IFLA_AF_SPEC			26
57d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define IFLA_INET6_ADDR_GEN_MODE	8
58d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define IN6_ADDR_GEN_MODE_NONE		1
59d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
60d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan/* For some reason, glibc doesn't include newer flags from linux/if.h
61d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * However, we cannot include linux/if.h directly as it conflicts
62d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * with the glibc version. D'oh! */
63d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifndef IFF_LOWER_UP
64d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define IFF_LOWER_UP	0x10000		/* driver signals L1 up		*/
65d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
66d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
67d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <errno.h>
68d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <fcntl.h>
69d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <ctype.h>
70d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <stddef.h>
71d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <stdio.h>
72d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <stdlib.h>
73d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <string.h>
74d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <time.h>
75d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <unistd.h>
76d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
77d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "config.h"
78d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "common.h"
79d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "dev.h"
80d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "dhcp.h"
81d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "if.h"
82d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "ipv4.h"
83d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "ipv6.h"
84d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "ipv6nd.h"
85d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
86d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef HAVE_NL80211_H
87d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <linux/genetlink.h>
88d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <linux/nl80211.h>
89d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
90d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint if_getssid_wext(const char *ifname, uint8_t *ssid);
91d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
92d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define bpf_insn		sock_filter
93d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define BPF_SKIPTYPE
94d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define BPF_ETHCOOK		-ETH_HLEN
95d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define BPF_WHOLEPACKET	0x0fffffff /* work around buggy LPF filters */
96d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
97d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "bpf-filter.h"
98d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
99d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan/* Broadcast address for IPoIB */
100d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic const uint8_t ipv4_bcast_addr[] = {
101d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	0x00, 0xff, 0xff, 0xff,
102d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	0xff, 0x12, 0x40, 0x1b, 0x00, 0x00, 0x00, 0x00,
103d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff
104d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan};
105d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
106d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define PROC_INET6	"/proc/net/if_inet6"
107d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define PROC_PROMOTE	"/proc/sys/net/ipv4/conf/%s/promote_secondaries"
108d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define SYS_LAYER2	"/sys/class/net/%s/device/layer2"
109d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
110d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic const char *mproc =
111d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#if defined(__alpha__)
112d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	"system type"
113d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#elif defined(__arm__)
114d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	"Hardware"
115d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#elif defined(__avr32__)
116d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	"cpu family"
117d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#elif defined(__bfin__)
118d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	"BOARD Name"
119d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#elif defined(__cris__)
120d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	"cpu model"
121d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#elif defined(__frv__)
122d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	"System"
123d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#elif defined(__i386__) || defined(__x86_64__)
124d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	"vendor_id"
125d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#elif defined(__ia64__)
126d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	"vendor"
127d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#elif defined(__hppa__)
128d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	"model"
129d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#elif defined(__m68k__)
130d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	"MMU"
131d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#elif defined(__mips__)
132d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	"system type"
133d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#elif defined(__powerpc__) || defined(__powerpc64__)
134d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	"machine"
135d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#elif defined(__s390__) || defined(__s390x__)
136d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	"Manufacturer"
137d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#elif defined(__sh__)
138d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	"machine"
139d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#elif defined(sparc) || defined(__sparc__)
140d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	"cpu"
141d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#elif defined(__vax__)
142d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	"cpu"
143d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#else
144d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	NULL
145d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
146d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	;
147d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
148d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint
149d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanif_machinearch(char *str, size_t len)
150d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
151d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	FILE *fp;
152d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	char buf[256];
153d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
154d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (mproc == NULL) {
155d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		errno = EINVAL;
156d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
157d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
158d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
159d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	fp = fopen("/proc/cpuinfo", "r");
160d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (fp == NULL)
161d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
162d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
163d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	while (fscanf(fp, "%255s : ", buf) != EOF) {
164d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (strncmp(buf, mproc, strlen(mproc)) == 0 &&
165d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    fscanf(fp, "%255s", buf) == 1)
166d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		{
167d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		        fclose(fp);
168d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return snprintf(str, len, ":%s", buf);
169d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
170d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
171d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	fclose(fp);
172d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	errno = ESRCH;
173d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return -1;
174d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
175d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
176d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
177d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tancheck_proc_int(const char *path)
178d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
179d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	FILE *fp;
180d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int i;
181d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
182d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	fp = fopen(path, "r");
183d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (fp == NULL)
184d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
185d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (fscanf(fp, "%d", &i) != 1)
186d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		i = -1;
187d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	fclose(fp);
188d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return i;
189d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
190d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
191d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic ssize_t
192d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanwrite_path(const char *path, const char *val)
193d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
194d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	FILE *fp;
195d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ssize_t r;
196d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
197d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	fp = fopen(path, "w");
198d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (fp == NULL)
199d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
200d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	r = fprintf(fp, "%s\n", val);
201d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	fclose(fp);
202d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return r;
203d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
204d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
205d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint
206d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanif_init(struct interface *ifp)
207d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
208d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	char path[sizeof(PROC_PROMOTE) + IF_NAMESIZE];
209d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int n;
210d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
211d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* We enable promote_secondaries so that we can do this
212d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * add 192.168.1.2/24
213d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * add 192.168.1.3/24
214d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * del 192.168.1.2/24
215d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * and the subnet mask moves onto 192.168.1.3/24
216d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * This matches the behaviour of BSD which makes coding dhcpcd
217d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * a little easier as there's just one behaviour. */
218d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	snprintf(path, sizeof(path), PROC_PROMOTE, ifp->name);
219d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	n = check_proc_int(path);
220d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (n == -1)
221d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return errno == ENOENT ? 0 : -1;
222d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (n == 1)
223d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return 0;
224d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return write_path(path, "1") == -1 ? -1 : 0;
225d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
226d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
227d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint
228d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanif_conf(struct interface *ifp)
229d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
230d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	char path[sizeof(SYS_LAYER2) + IF_NAMESIZE];
231d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int n;
232d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
233d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Some qeth setups require the use of the broadcast flag. */
234d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	snprintf(path, sizeof(path), SYS_LAYER2, ifp->name);
235d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	n = check_proc_int(path);
236d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (n == -1)
237d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return errno == ENOENT ? 0 : -1;
238d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (n == 0)
239d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ifp->options->options |= DHCPCD_BROADCAST;
240d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return 0;
241d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
242d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
243d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan/* XXX work out Virtal Interface Masters */
244d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint
245d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanif_vimaster(__unused const char *ifname)
246d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
247d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
248d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return 0;
249d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
250d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
251d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
252d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan_open_link_socket(struct sockaddr_nl *nl, int flags, int protocol)
253d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
254d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int fd;
255d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
256d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef SOCK_CLOEXEC
257d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (flags)
258d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		flags = SOCK_CLOEXEC;
259d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	fd = socket(AF_NETLINK, SOCK_RAW | flags, protocol);
260d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (fd == -1)
261d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
262d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#else
263d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
264d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (fd == -1)
265d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
266d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (flags &&
267d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    (flags = fcntl(fd, F_GETFD, 0)) == -1 ||
268d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
269d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	{
270d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		close(fd);
271d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	        return -1;
272d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
273d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
274d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nl->nl_family = AF_NETLINK;
275d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (bind(fd, (struct sockaddr *)nl, sizeof(*nl)) == -1) {
276d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		close(fd);
277d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
278d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
279d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return fd;
280d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
281d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
282d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint
283d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanif_openlinksocket(void)
284d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
285d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct sockaddr_nl snl;
286d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
287d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	memset(&snl, 0, sizeof(snl));
288d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	snl.nl_groups = RTMGRP_LINK;
289d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
290d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef INET
291d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	snl.nl_groups |= RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR;
292d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
293d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef INET6
294d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	snl.nl_groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR | RTMGRP_NEIGH;
295d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
296d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
297d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return _open_link_socket(&snl, 1, NETLINK_ROUTE);
298d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
299d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
300d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
301d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanerr_netlink(struct nlmsghdr *nlm)
302d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
303d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct nlmsgerr *err;
304d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t len;
305d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
306d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (nlm->nlmsg_type != NLMSG_ERROR)
307d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return 0;
308d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	len = nlm->nlmsg_len - sizeof(*nlm);
309d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (len < sizeof(*err)) {
310d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		errno = EBADMSG;
311d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
312d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
313d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	err = (struct nlmsgerr *)NLMSG_DATA(nlm);
314d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (err->error == 0)
315d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return (int)len;
316d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	errno = -err->error;
317d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return -1;
318d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
319d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
320d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
321d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanget_netlink(struct dhcpcd_ctx *ctx, struct interface *ifp, int fd, int flags,
322d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    int (*callback)(struct dhcpcd_ctx *, struct interface *, struct nlmsghdr *))
323d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
324d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	char *buf = NULL, *nbuf;
325d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ssize_t bytes;
326d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t buflen;
327d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct nlmsghdr *nlm;
328d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct sockaddr_nl nladdr;
329d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	socklen_t nladdr_len;
330d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int r;
331d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
332d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	buflen = 0;
333d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	r = -1;
334d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	for (;;) {
335d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		bytes = recv(fd, NULL, 0,
336d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    flags | MSG_PEEK | MSG_DONTWAIT | MSG_TRUNC);
337d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (bytes == -1)
338d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			goto eexit;
339d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if ((size_t)bytes == buflen) {
340d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			/* Support kernels older than 2.6.22 */
341d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (bytes == 0)
342d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				bytes = 512;
343d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			else
344d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				bytes *= 2;
345d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
346d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (buflen < (size_t)bytes) {
347d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			/* Alloc 1 more so we work with older kernels */
348d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			buflen = (size_t)bytes + 1;
349d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			nbuf = realloc(buf, buflen);
350d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (nbuf == NULL)
351d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				goto eexit;
352d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			buf = nbuf;
353d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
354d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		nladdr_len = sizeof(nladdr);
355d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		bytes = recvfrom(fd, buf, buflen, flags,
356d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    (struct sockaddr *)&nladdr, &nladdr_len);
357d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (bytes == -1 || bytes == 0)
358d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			goto eexit;
359d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
360d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* Check sender */
361d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (nladdr_len != sizeof(nladdr)) {
362d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			errno = EINVAL;
363d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			goto eexit;
364d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
365d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* Ignore message if it is not from kernel */
366d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (nladdr.nl_pid != 0) {
367d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			r = 0;
368d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			continue;
369d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
370d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
371d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		for (nlm = (struct nlmsghdr *)(void *)buf;
372d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		     nlm && NLMSG_OK(nlm, (size_t)bytes);
373d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		     nlm = NLMSG_NEXT(nlm, bytes))
374d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		{
375d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			r = err_netlink(nlm);
376d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (r == -1)
377d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				goto eexit;
378d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (r)
379d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				continue;
380d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (callback) {
381d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				r = callback(ctx, ifp, nlm);
382d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				if (r != 0)
383d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					goto eexit;
384d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
385d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
386d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
387d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
388d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Taneexit:
389d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	free(buf);
390d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return r;
391d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
392d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
393d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef INET
394d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
395d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanif_copyrt(struct dhcpcd_ctx *ctx, struct rt *rt, struct nlmsghdr *nlm)
396d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
397d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t len;
398d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct rtmsg *rtm;
399d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct rtattr *rta;
400d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct in_addr prefsrc;
401d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
402d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	len = nlm->nlmsg_len - sizeof(*nlm);
403d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (len < sizeof(*rtm)) {
404d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		errno = EBADMSG;
405d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
406d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
407d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	rtm = (struct rtmsg *)NLMSG_DATA(nlm);
408d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (rtm->rtm_table != RT_TABLE_MAIN || rtm->rtm_family != AF_INET)
409d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
410d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
411d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	memset(rt, 0, sizeof(*rt));
412d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (rtm->rtm_type == RTN_UNREACHABLE)
413d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		rt->flags = RTF_REJECT;
414d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (rtm->rtm_scope == RT_SCOPE_HOST)
415d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		rt->flags |= RTF_HOST;
416d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
417d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	prefsrc.s_addr = INADDR_ANY;
418d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	rta = (struct rtattr *)RTM_RTA(rtm);
419d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	len = RTM_PAYLOAD(nlm);
420d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	while (RTA_OK(rta, len)) {
421d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		switch (rta->rta_type) {
422d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		case RTA_DST:
423d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			memcpy(&rt->dest.s_addr, RTA_DATA(rta),
424d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    sizeof(rt->dest.s_addr));
425d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			break;
426d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		case RTA_GATEWAY:
427d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			memcpy(&rt->gate.s_addr, RTA_DATA(rta),
428d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    sizeof(rt->gate.s_addr));
429d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			break;
430d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		case RTA_PREFSRC:
431d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			memcpy(&prefsrc.s_addr, RTA_DATA(rta),
432d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    sizeof(prefsrc.s_addr));
433d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			break;
434d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		case RTA_OIF:
435d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			rt->iface = if_findindex(ctx->ifaces,
436d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    *(unsigned int *)RTA_DATA(rta));
437d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			break;
438d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		case RTA_PRIORITY:
439d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			rt->metric = *(unsigned int *)RTA_DATA(rta);
440d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			break;
441d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
442d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		rta = RTA_NEXT(rta, len);
443d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
444d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
445d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	inet_cidrtoaddr(rtm->rtm_dst_len, &rt->net);
446d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (rt->iface == NULL && prefsrc.s_addr != INADDR_ANY) {
447d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		struct ipv4_addr *ap;
448d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
449d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* For some reason the default route comes back with the
450d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		 * loopback interface in RTA_OIF? Lets find it by
451d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		 * preferred source address */
452d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if ((ap = ipv4_findaddr(ctx, &prefsrc)))
453d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			rt->iface = ap->iface;
454d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
455d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return 0;
456d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
457d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
458d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
459d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef INET6
460d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
461d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanif_copyrt6(struct dhcpcd_ctx *ctx, struct rt6 *rt, struct nlmsghdr *nlm)
462d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
463d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t len;
464d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct rtmsg *rtm;
465d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct rtattr *rta;
466d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
467d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	len = nlm->nlmsg_len - sizeof(*nlm);
468d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (len < sizeof(*rtm)) {
469d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		errno = EBADMSG;
470d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
471d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
472d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	rtm = (struct rtmsg *)NLMSG_DATA(nlm);
473d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (rtm->rtm_table != RT_TABLE_MAIN || rtm->rtm_family != AF_INET6)
474d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
475d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
476d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	memset(rt, 0, sizeof(*rt));
477d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (rtm->rtm_type == RTN_UNREACHABLE)
478d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		rt->flags = RTF_REJECT;
479d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (rtm->rtm_scope == RT_SCOPE_HOST)
480d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		rt->flags |= RTF_HOST;
481d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ipv6_mask(&rt->net, rtm->rtm_dst_len);
482d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
483d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	rta = (struct rtattr *)RTM_RTA(rtm);
484d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	len = RTM_PAYLOAD(nlm);
485d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	while (RTA_OK(rta, len)) {
486d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		switch (rta->rta_type) {
487d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		case RTA_DST:
488d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			memcpy(&rt->dest.s6_addr, RTA_DATA(rta),
489d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    sizeof(rt->dest.s6_addr));
490d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			break;
491d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		case RTA_GATEWAY:
492d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			memcpy(&rt->gate.s6_addr, RTA_DATA(rta),
493d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    sizeof(rt->gate.s6_addr));
494d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			break;
495d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		case RTA_OIF:
496d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			rt->iface = if_findindex(ctx->ifaces,
497d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    *(unsigned int *)RTA_DATA(rta));
498d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			break;
499d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		case RTA_PRIORITY:
500d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			rt->metric = *(unsigned int *)RTA_DATA(rta);
501d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			break;
502d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
503d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		rta = RTA_NEXT(rta, len);
504d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
505d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
506d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return 0;
507d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
508d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
509d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
510d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan/* Work out the maximum pid size */
511d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic inline long long
512d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanget_max_pid_t()
513d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
514d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
515d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (sizeof(pid_t) == sizeof(short))		return SHRT_MAX;
516d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (sizeof(pid_t) == sizeof(int))		return INT_MAX;
517d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (sizeof(pid_t) == sizeof(long))		return LONG_MAX;
518d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (sizeof(pid_t) == sizeof(long long))		return LLONG_MAX;
519d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	abort();
520d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
521d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
522d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
523d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanlink_route(struct dhcpcd_ctx *ctx, __unused struct interface *ifp,
524d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    struct nlmsghdr *nlm)
525d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
526d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t len;
527d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct rtmsg *rtm;
528d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int cmd;
529d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef INET
530d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct rt rt;
531d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
532d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef INET6
533d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct rt6 rt6;
534d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
535d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	switch (nlm->nlmsg_type) {
536d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	case RTM_NEWROUTE:
537d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		cmd = RTM_ADD;
538d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		break;
539d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	case RTM_DELROUTE:
540d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		cmd = RTM_DELETE;
541d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		break;
542d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	default:
543d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return 0;
544d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
545d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
546d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	len = nlm->nlmsg_len - sizeof(*nlm);
547d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (len < sizeof(*rtm)) {
548d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		errno = EBADMSG;
549d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
550d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
551d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
552d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Ignore messages generated by us.
553d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * For some reason we get messages generated by us
554d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * with a very large value in nlmsg_pid that seems to be
555d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * sequentially changing. Is there a better test for this? */
556d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (nlm->nlmsg_pid > get_max_pid_t())
557d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return 1;
558d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
559d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	rtm = NLMSG_DATA(nlm);
560d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	switch (rtm->rtm_family) {
561d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef INET
562d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	case AF_INET:
563d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (if_copyrt(ctx, &rt, nlm) == 0)
564d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			ipv4_handlert(ctx, cmd, &rt);
565d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		break;
566d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
567d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef INET6
568d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	case AF_INET6:
569d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (if_copyrt6(ctx, &rt6, nlm) == 0)
570d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			ipv6_handlert(ctx, cmd, &rt6);
571d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		break;
572d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
573d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
574d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
575d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return 0;
576d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
577d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
578d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
579d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanlink_addr(struct dhcpcd_ctx *ctx, struct interface *ifp, struct nlmsghdr *nlm)
580d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
581d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t len;
582d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct rtattr *rta;
583d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct ifaddrmsg *ifa;
584d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef INET
585d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct in_addr addr, net, dest;
586d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
587d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef INET6
588d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct in6_addr addr6;
589d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
590d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
591d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (nlm->nlmsg_type != RTM_DELADDR && nlm->nlmsg_type != RTM_NEWADDR)
592d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return 0;
593d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
594d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	len = nlm->nlmsg_len - sizeof(*nlm);
595d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (len < sizeof(*ifa)) {
596d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		errno = EBADMSG;
597d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
598d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
599d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ifa = NLMSG_DATA(nlm);
600d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if ((ifp = if_findindex(ctx->ifaces, ifa->ifa_index)) == NULL) {
601d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* We don't know about the interface the address is for
602d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		 * so it's not really an error */
603d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return 1;
604d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
605d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	rta = (struct rtattr *)IFA_RTA(ifa);
606d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	len = NLMSG_PAYLOAD(nlm, sizeof(*ifa));
607d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	switch (ifa->ifa_family) {
608d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef INET
609d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	case AF_INET:
610d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		addr.s_addr = dest.s_addr = INADDR_ANY;
611d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		dest.s_addr = INADDR_ANY;
612d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		inet_cidrtoaddr(ifa->ifa_prefixlen, &net);
613d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		while (RTA_OK(rta, len)) {
614d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			switch (rta->rta_type) {
615d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			case IFA_ADDRESS:
616d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				if (ifp->flags & IFF_POINTOPOINT) {
617d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					memcpy(&dest.s_addr, RTA_DATA(rta),
618d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					       sizeof(addr.s_addr));
619d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				}
620d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				break;
621d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			case IFA_LOCAL:
622d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				memcpy(&addr.s_addr, RTA_DATA(rta),
623d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				       sizeof(addr.s_addr));
624d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				break;
625d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
626d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			rta = RTA_NEXT(rta, len);
627d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
628d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ipv4_handleifa(ctx, nlm->nlmsg_type, NULL, ifp->name,
629d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    &addr, &net, &dest, ifa->ifa_flags);
630d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		break;
631d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
632d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef INET6
633d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	case AF_INET6:
634d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		memset(&addr6, 0, sizeof(addr6));
635d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		while (RTA_OK(rta, len)) {
636d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			switch (rta->rta_type) {
637d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			case IFA_ADDRESS:
638d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				memcpy(&addr6.s6_addr, RTA_DATA(rta),
639d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				       sizeof(addr6.s6_addr));
640d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				break;
641d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
642d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			rta = RTA_NEXT(rta, len);
643d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
644d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ipv6_handleifa(ctx, nlm->nlmsg_type, NULL, ifp->name,
645d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    &addr6, ifa->ifa_prefixlen, ifa->ifa_flags);
646d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		break;
647d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
648d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
649d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return 0;
650d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
651d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
652d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic uint8_t
653d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanl2addr_len(unsigned short if_type)
654d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
655d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
656d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	switch (if_type) {
657d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	case ARPHRD_ETHER: /* FALLTHROUGH */
658d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	case ARPHRD_IEEE802: /*FALLTHROUGH */
659d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	case ARPHRD_IEEE80211:
660d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return 6;
661d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	case ARPHRD_IEEE1394:
662d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return 8;
663d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	case ARPHRD_INFINIBAND:
664d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return 20;
665d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
666d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
667d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Impossible */
668d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return 0;
669d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
670d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
671d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
672d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanhandle_rename(struct dhcpcd_ctx *ctx, unsigned int ifindex, const char *ifname)
673d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
674d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct interface *ifp;
675d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
676d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	TAILQ_FOREACH(ifp, ctx->ifaces, next) {
677d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (ifp->index == ifindex && strcmp(ifp->name, ifname)) {
678d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			dhcpcd_handleinterface(ctx, -1, ifp->name);
679d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			/* Let dev announce the interface for renaming */
680d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (!dev_listening(ctx))
681d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				dhcpcd_handleinterface(ctx, 1, ifname);
682d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return 1;
683d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
684d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
685d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return 0;
686d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
687d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
688d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef INET6
689d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
690d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanlink_neigh(struct dhcpcd_ctx *ctx, __unused struct interface *ifp,
691d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    struct nlmsghdr *nlm)
692d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
693d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct ndmsg *r;
694d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct rtattr *rta;
695d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t len;
696d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct in6_addr addr6;
697d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int flags;
698d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
699d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (nlm->nlmsg_type != RTM_NEWNEIGH && nlm->nlmsg_type != RTM_DELNEIGH)
700d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return 0;
701d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (nlm->nlmsg_len < sizeof(*r))
702d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
703d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
704d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	r = NLMSG_DATA(nlm);
705d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	rta = (struct rtattr *)RTM_RTA(r);
706d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	len = RTM_PAYLOAD(nlm);
707d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan        if (r->ndm_family == AF_INET6) {
708d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		flags = 0;
709d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (r->ndm_flags & NTF_ROUTER)
710d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			flags |= IPV6ND_ROUTER;
711d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (nlm->nlmsg_type == RTM_NEWNEIGH &&
712d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    r->ndm_state &
713d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    (NUD_REACHABLE | NUD_STALE | NUD_DELAY | NUD_PROBE |
714d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		     NUD_PERMANENT))
715d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		        flags |= IPV6ND_REACHABLE;
716d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		memset(&addr6, 0, sizeof(addr6));
717d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		while (RTA_OK(rta, len)) {
718d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			switch (rta->rta_type) {
719d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			case NDA_DST:
720d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				memcpy(&addr6.s6_addr, RTA_DATA(rta),
721d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				       sizeof(addr6.s6_addr));
722d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				break;
723d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
724d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			rta = RTA_NEXT(rta, len);
725d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
726d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ipv6nd_neighbour(ctx, &addr6, flags);
727d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
728d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
729d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return 0;
730d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
731d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
732d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
733d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
734d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanlink_netlink(struct dhcpcd_ctx *ctx, struct interface *ifp,
735d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    struct nlmsghdr *nlm)
736d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
737d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int r;
738d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t len;
739d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct rtattr *rta, *hwaddr;
740d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct ifinfomsg *ifi;
741d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	char ifn[IF_NAMESIZE + 1];
742d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
743d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	r = link_route(ctx, ifp, nlm);
744d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (r != 0)
745d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return r;
746d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	r = link_addr(ctx, ifp, nlm);
747d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (r != 0)
748d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return r;
749d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef INET6
750d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	r = link_neigh(ctx, ifp, nlm);
751d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (r != 0)
752d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return r;
753d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
754d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
755d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (nlm->nlmsg_type != RTM_NEWLINK && nlm->nlmsg_type != RTM_DELLINK)
756d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return 0;
757d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	len = nlm->nlmsg_len - sizeof(*nlm);
758d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if ((size_t)len < sizeof(*ifi)) {
759d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		errno = EBADMSG;
760d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
761d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
762d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ifi = NLMSG_DATA(nlm);
763d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifi->ifi_flags & IFF_LOOPBACK)
764d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return 0;
765d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	rta = (struct rtattr *)(void *)((char *)ifi +NLMSG_ALIGN(sizeof(*ifi)));
766d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	len = NLMSG_PAYLOAD(nlm, sizeof(*ifi));
767d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	*ifn = '\0';
768d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	hwaddr = NULL;
769d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
770d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	while (RTA_OK(rta, len)) {
771d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		switch (rta->rta_type) {
772d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		case IFLA_WIRELESS:
773d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			/* Ignore wireless messages */
774d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (nlm->nlmsg_type == RTM_NEWLINK &&
775d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    ifi->ifi_change == 0)
776d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				return 0;
777d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			break;
778d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		case IFLA_IFNAME:
779d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			strlcpy(ifn, RTA_DATA(rta), sizeof(ifn));
780d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			break;
781d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		case IFLA_ADDRESS:
782d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			hwaddr = rta;
783d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			break;
784d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
785d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		rta = RTA_NEXT(rta, len);
786d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
787d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
788d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (nlm->nlmsg_type == RTM_DELLINK) {
789d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		dhcpcd_handleinterface(ctx, -1, ifn);
790d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return 0;
791d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
792d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
793d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Virtual interfaces may not get a valid hardware address
794d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * at this point.
795d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * To trigger a valid hardware address pickup we need to pretend
796d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	 * that that don't exist until they have one. */
797d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifi->ifi_flags & IFF_MASTER && !hwaddr) {
798d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		dhcpcd_handleinterface(ctx, -1, ifn);
799d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return 0;
800d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
801d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
802d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Check for interface name change */
803d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (handle_rename(ctx, (unsigned int)ifi->ifi_index, ifn))
804d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return 0;
805d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
806d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Check for a new interface */
807d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if ((ifp = if_find(ctx->ifaces, ifn)) == NULL) {
808d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* If are listening to a dev manager, let that announce
809d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		 * the interface rather than the kernel. */
810d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (dev_listening(ctx) < 1)
811d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			dhcpcd_handleinterface(ctx, 1, ifn);
812d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return 0;
813d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
814d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
815d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Re-read hardware address and friends */
816d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (!(ifi->ifi_flags & IFF_UP) && hwaddr) {
817d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		uint8_t l;
818d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
819d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		l = l2addr_len(ifi->ifi_type);
820d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (hwaddr->rta_len == RTA_LENGTH(l))
821d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			dhcpcd_handlehwaddr(ctx, ifn, RTA_DATA(hwaddr), l);
822d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
823d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
824d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	dhcpcd_handlecarrier(ctx,
825d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    ifi->ifi_flags & IFF_RUNNING ? LINK_UP : LINK_DOWN,
826d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    ifi->ifi_flags, ifn);
827d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return 0;
828d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
829d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
830d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint
831d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanif_managelink(struct dhcpcd_ctx *ctx)
832d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
833d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
834d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return get_netlink(ctx, NULL,
835d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    ctx->link_fd, MSG_DONTWAIT, &link_netlink);
836d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
837d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
838d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
839d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tansend_netlink(struct dhcpcd_ctx *ctx, struct interface *ifp,
840d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    int protocol, struct nlmsghdr *hdr,
841d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    int (*callback)(struct dhcpcd_ctx *, struct interface *, struct nlmsghdr *))
842d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
843d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int s, r;
844d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct sockaddr_nl snl;
845d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct iovec iov;
846d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct msghdr msg;
847d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	static unsigned int seq;
848d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
849d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	memset(&snl, 0, sizeof(snl));
850d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if ((s = _open_link_socket(&snl, 0, protocol)) == -1)
851d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
852d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	memset(&iov, 0, sizeof(iov));
853d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	iov.iov_base = hdr;
854d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	iov.iov_len = hdr->nlmsg_len;
855d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	memset(&msg, 0, sizeof(msg));
856d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	msg.msg_name = &snl;
857d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	msg.msg_namelen = sizeof(snl);
858d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	msg.msg_iov = &iov;
859d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	msg.msg_iovlen = 1;
860d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Request a reply */
861d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	hdr->nlmsg_flags |= NLM_F_ACK;
862d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	hdr->nlmsg_seq = ++seq;
863d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
864d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (sendmsg(s, &msg, 0) != -1)
865d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		r = get_netlink(ctx, ifp, s, 0, callback);
866d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else
867d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		r = -1;
868d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	close(s);
869d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return r;
870d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
871d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
872d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define NLMSG_TAIL(nmsg)						\
873d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	((struct rtattr *)(((ptrdiff_t)(nmsg))+NLMSG_ALIGN((nmsg)->nlmsg_len)))
874d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
875d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
876d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanadd_attr_l(struct nlmsghdr *n, unsigned short maxlen, unsigned short type,
877d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    const void *data, unsigned short alen)
878d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
879d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	unsigned short len = (unsigned short)RTA_LENGTH(alen);
880d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct rtattr *rta;
881d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
882d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) {
883d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		errno = ENOBUFS;
884d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
885d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
886d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
887d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	rta = NLMSG_TAIL(n);
888d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	rta->rta_type = type;
889d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	rta->rta_len = len;
890d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (alen)
891d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		memcpy(RTA_DATA(rta), data, alen);
892d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
893d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
894d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return 0;
895d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
896d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
897d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
898d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanadd_attr_32(struct nlmsghdr *n, unsigned short maxlen, unsigned short type,
899d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    uint32_t data)
900d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
901d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	unsigned short len = RTA_LENGTH(sizeof(data));
902d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct rtattr *rta;
903d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
904d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) {
905d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		errno = ENOBUFS;
906d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
907d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
908d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
909d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	rta = NLMSG_TAIL(n);
910d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	rta->rta_type = type;
911d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	rta->rta_len = len;
912d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	memcpy(RTA_DATA(rta), &data, sizeof(data));
913d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
914d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
915d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return 0;
916d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
917d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
918d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef HAVE_NL80211_H
919d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic struct nlattr *
920d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tannla_next(struct nlattr *nla, size_t *rem)
921d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
922d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
923d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	*rem -= NLA_ALIGN(nla->nla_len);
924d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return (struct nlattr *)(void *)((char *)nla + NLA_ALIGN(nla->nla_len));
925d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
926d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
927d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define NLA_TYPE(nla) ((nla)->nla_type & NLA_TYPE_MASK)
928d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define NLA_LEN(nla) (unsigned int)((nla)->nla_len - NLA_HDRLEN)
929d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define NLA_OK(nla, rem) \
930d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	((rem) >= sizeof(struct nlattr) && \
931d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	(nla)->nla_len >= sizeof(struct nlattr) && \
932d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	(nla)->nla_len <= rem)
933d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define NLA_DATA(nla) ((char *)(nla) + NLA_HDRLEN)
934d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define NLA_FOR_EACH_ATTR(pos, head, len, rem) \
935d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	for (pos = head, rem = len; NLA_OK(pos, rem); pos = nla_next(pos, &(rem)))
936d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
937d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstruct nlmg
938d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
939d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct nlmsghdr hdr;
940d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct genlmsghdr ghdr;
941d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	char buffer[64];
942d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan};
943d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
944d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
945d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tannla_put_32(struct nlmsghdr *n, unsigned short maxlen,
946d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    unsigned short type, uint32_t data)
947d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
948d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	unsigned short len;
949d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct nlattr *nla;
950d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
951d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	len = NLA_ALIGN(NLA_HDRLEN + sizeof(data));
952d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) {
953d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		errno = ENOBUFS;
954d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
955d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
956d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
957d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nla = (struct nlattr *)NLMSG_TAIL(n);
958d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nla->nla_type = type;
959d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nla->nla_len = len;
960d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	memcpy(NLA_DATA(nla), &data, sizeof(data));
961d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
962d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
963d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return 0;
964d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
965d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
966d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
967d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tannla_put_string(struct nlmsghdr *n, unsigned short maxlen,
968d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    unsigned short type, const char *data)
969d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
970d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct nlattr *nla;
971d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t len, sl;
972d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
973d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	sl = strlen(data) + 1;
974d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	len = NLA_ALIGN(NLA_HDRLEN + sl);
975d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) {
976d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		errno = ENOBUFS;
977d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
978d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
979d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
980d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nla = (struct nlattr *)NLMSG_TAIL(n);
981d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nla->nla_type = type;
982d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nla->nla_len = (unsigned short)len;
983d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	memcpy(NLA_DATA(nla), data, sl);
984d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + (unsigned short)len;
985d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return 0;
986d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
987d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
988d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
989d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tangnl_parse(struct nlmsghdr *nlm, struct nlattr *tb[], int maxtype)
990d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
991d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct genlmsghdr *ghdr;
992d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct nlattr *head, *nla;
993d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	size_t len, rem;
994d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int type;
995d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
996d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	memset(tb, 0, sizeof(*tb) * ((unsigned int)maxtype + 1));
997d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ghdr = NLMSG_DATA(nlm);
998d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	head = (struct nlattr *)(void *)((char *) ghdr + GENL_HDRLEN);
999d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	len = nlm->nlmsg_len - GENL_HDRLEN - NLMSG_HDRLEN;
1000d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	NLA_FOR_EACH_ATTR(nla, head, len, rem) {
1001d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		type = NLA_TYPE(nla);
1002d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (type > maxtype)
1003d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			continue;
1004d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		tb[type] = nla;
1005d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1006d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return 0;
1007d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1008d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1009d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
1010d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan_gnl_getfamily(__unused struct dhcpcd_ctx *ctx, __unused struct interface *ifp,
1011d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    struct nlmsghdr *nlm)
1012d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1013d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct nlattr *tb[CTRL_ATTR_FAMILY_ID + 1];
1014d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint16_t family;
1015d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1016d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (gnl_parse(nlm, tb, CTRL_ATTR_FAMILY_ID) == -1)
1017d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
1018d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (tb[CTRL_ATTR_FAMILY_ID] == NULL) {
1019d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		errno = ENOENT;
1020d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
1021d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1022d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	family = *(uint16_t *)(void *)NLA_DATA(tb[CTRL_ATTR_FAMILY_ID]);
1023d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return (int)family;
1024d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1025d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1026d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
1027d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tangnl_getfamily(struct dhcpcd_ctx *ctx, const char *name)
1028d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1029d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct nlmg nlm;
1030d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1031d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	memset(&nlm, 0, sizeof(nlm));
1032d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct genlmsghdr));
1033d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.hdr.nlmsg_type = GENL_ID_CTRL;
1034d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.hdr.nlmsg_flags = NLM_F_REQUEST;
1035d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.ghdr.cmd = CTRL_CMD_GETFAMILY;
1036d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.ghdr.version = 1;
1037d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (nla_put_string(&nlm.hdr, sizeof(nlm),
1038d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    CTRL_ATTR_FAMILY_NAME, name) == -1)
1039d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
1040d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return send_netlink(ctx, NULL, NETLINK_GENERIC, &nlm.hdr,
1041d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    &_gnl_getfamily);
1042d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1043d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1044d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
1045d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan_if_getssid(__unused struct dhcpcd_ctx *ctx, struct interface *ifp,
1046d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    struct nlmsghdr *nlm)
1047d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1048d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct nlattr *tb[NL80211_ATTR_SSID + 1];
1049d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1050d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (gnl_parse(nlm, tb, NL80211_ATTR_SSID) == -1)
1051d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
1052d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1053d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (tb[NL80211_ATTR_SSID] == NULL) {
1054d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* If the SSID is not found then it means that
1055d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		 * we're not associated to an AP. */
1056d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ifp->ssid_len = 0;
1057d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		goto out;
1058d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1059d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1060d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ifp->ssid_len = NLA_LEN(tb[NL80211_ATTR_SSID]);
1061d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifp->ssid_len > sizeof(ifp->ssid)) {
1062d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		errno = ENOBUFS;
1063d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ifp->ssid_len = 0;
1064d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
1065d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1066d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	memcpy(ifp->ssid, NLA_DATA(tb[NL80211_ATTR_SSID]), ifp->ssid_len);
1067d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1068d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanout:
1069d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ifp->ssid[ifp->ssid_len] = '\0';
1070d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return (int)ifp->ssid_len;
1071d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1072d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1073d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
1074d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanif_getssid_nl80211(struct interface *ifp)
1075d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1076d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int family;
1077d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct nlmg nlm;
1078d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1079d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	errno = 0;
1080d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	family = gnl_getfamily(ifp->ctx, "nl80211");
1081d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (family == -1)
1082d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
1083d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	memset(&nlm, 0, sizeof(nlm));
1084d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct genlmsghdr));
1085d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.hdr.nlmsg_type = (unsigned short)family;
1086d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.hdr.nlmsg_flags = NLM_F_REQUEST;
1087d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.ghdr.cmd = NL80211_CMD_GET_INTERFACE;
1088d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nla_put_32(&nlm.hdr, sizeof(nlm), NL80211_ATTR_IFINDEX, ifp->index);
1089d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1090d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return send_netlink(ifp->ctx, ifp,
1091d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    NETLINK_GENERIC, &nlm.hdr, &_if_getssid);
1092d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1093d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
1094d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1095d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint
1096d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanif_getssid(struct interface *ifp)
1097d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1098d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int r;
1099d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1100d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	r = if_getssid_wext(ifp->name, ifp->ssid);
1101d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (r != -1)
1102d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ifp->ssid_len = (unsigned int)r;
1103d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef HAVE_NL80211_H
1104d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else if (r == -1)
1105d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		r = if_getssid_nl80211(ifp);
1106d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
1107d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return r;
1108d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1109d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1110d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstruct nlma
1111d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1112d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct nlmsghdr hdr;
1113d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct ifaddrmsg ifa;
1114d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	char buffer[64];
1115d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan};
1116d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1117d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstruct nlmr
1118d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1119d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct nlmsghdr hdr;
1120d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct rtmsg rt;
1121d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	char buffer[256];
1122d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan};
1123d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1124d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef INET
1125d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanconst char *if_pfname = "Packet Socket";
1126d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1127d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint
1128d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanif_openrawsocket(struct interface *ifp, uint16_t protocol)
1129d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1130d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int s;
1131d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	union sockunion {
1132d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		struct sockaddr sa;
1133d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		struct sockaddr_ll sll;
1134d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		struct sockaddr_storage ss;
1135d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	} su;
1136d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct sock_fprog pf;
1137d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef PACKET_AUXDATA
1138d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int n;
1139d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
1140d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1141d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef SOCK_CLOEXEC
1142d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if ((s = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
1143d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    htons(protocol))) == -1)
1144d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
1145d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#else
1146d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int flags;
1147d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1148d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if ((s = socket(PF_PACKET, SOCK_DGRAM, htons(protocol))) == -1)
1149d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
1150d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if ((flags = fcntl(s, F_GETFD, 0)) == -1 ||
1151d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    fcntl(s, F_SETFD, flags | FD_CLOEXEC) == -1)
1152d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	{
1153d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		close(s);
1154d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	        return -1;
1155d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1156d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if ((flags = fcntl(s, F_GETFL, 0)) == -1 ||
1157d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1)
1158d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	{
1159d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		close(s);
1160d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	        return -1;
1161d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1162d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
1163d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Install the DHCP filter */
1164d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	memset(&pf, 0, sizeof(pf));
1165d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (protocol == ETHERTYPE_ARP) {
1166d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		pf.filter = UNCONST(arp_bpf_filter);
1167d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		pf.len = arp_bpf_filter_len;
1168d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	} else {
1169d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		pf.filter = UNCONST(dhcp_bpf_filter);
1170d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		pf.len = dhcp_bpf_filter_len;
1171d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1172d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &pf, sizeof(pf)) != 0)
1173d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		goto eexit;
1174d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef PACKET_AUXDATA
1175d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	n = 1;
1176d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (setsockopt(s, SOL_PACKET, PACKET_AUXDATA, &n, sizeof(n)) != 0) {
1177d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (errno != ENOPROTOOPT)
1178d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			goto eexit;
1179d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1180d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
1181d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1182d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	memset(&su, 0, sizeof(su));
1183d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	su.sll.sll_family = PF_PACKET;
1184d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	su.sll.sll_protocol = htons(protocol);
1185d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	su.sll.sll_ifindex = (int)ifp->index;
1186d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (bind(s, &su.sa, sizeof(su.sll)) == -1)
1187d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		goto eexit;
1188d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return s;
1189d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1190d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Taneexit:
1191d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	close(s);
1192d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return -1;
1193d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1194d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1195d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanssize_t
1196d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanif_sendrawpacket(const struct interface *ifp, uint16_t protocol,
1197f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan    const void *data, size_t len, const uint8_t *dest_hw_addr)
1198d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1199d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const struct dhcp_state *state;
1200d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	union sockunion {
1201d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		struct sockaddr sa;
1202d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		struct sockaddr_ll sll;
1203d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		struct sockaddr_storage ss;
1204d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	} su;
1205d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int fd;
1206d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1207d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	memset(&su, 0, sizeof(su));
1208d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	su.sll.sll_family = AF_PACKET;
1209d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	su.sll.sll_protocol = htons(protocol);
1210d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	su.sll.sll_ifindex = (int)ifp->index;
1211d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	su.sll.sll_hatype = htons(ifp->family);
1212d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	su.sll.sll_halen = (unsigned char)ifp->hwlen;
1213d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifp->family == ARPHRD_INFINIBAND)
1214d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		memcpy(&su.sll.sll_addr,
1215d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    &ipv4_bcast_addr, sizeof(ipv4_bcast_addr));
1216f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	else {
1217f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan		if (dest_hw_addr)
1218f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan			memcpy(&su.sll.sll_addr, dest_hw_addr, ifp->hwlen);
1219f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan		else
1220f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan			memset(&su.sll.sll_addr, 0xff, ifp->hwlen);
1221f20514bf582d08567217a3b06171bab5a11458eaSamuel Tan	}
1222d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state = D_CSTATE(ifp);
1223d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (protocol == ETHERTYPE_ARP)
1224d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		fd = state->arp_fd;
1225d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else
1226d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		fd = state->raw_fd;
1227d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1228d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return sendto(fd, data, len, 0, &su.sa, sizeof(su.sll));
1229d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1230d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1231d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanssize_t
1232d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanif_readrawpacket(struct interface *ifp, uint16_t protocol,
1233d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    void *data, size_t len, int *flags)
1234d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1235d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct iovec iov = {
1236d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		.iov_base = data,
1237d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		.iov_len = len,
1238d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	};
1239d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct msghdr msg = {
1240d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		.msg_iov = &iov,
1241d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		.msg_iovlen = 1,
1242d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	};
1243d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_state *state;
1244d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef PACKET_AUXDATA
1245d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	unsigned char cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
1246d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct cmsghdr *cmsg;
1247d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct tpacket_auxdata *aux;
1248d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
1249d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1250d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ssize_t bytes;
1251d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int fd = -1;
1252d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1253d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef PACKET_AUXDATA
1254d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	msg.msg_control = cmsgbuf;
1255d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	msg.msg_controllen = sizeof(cmsgbuf);
1256d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
1257d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1258d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state = D_STATE(ifp);
1259d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (protocol == ETHERTYPE_ARP)
1260d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		fd = state->arp_fd;
1261d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else
1262d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		fd = state->raw_fd;
1263d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	bytes = recvmsg(fd, &msg, 0);
1264d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (bytes == -1)
1265d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
1266d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	*flags = RAW_EOF; /* We only ever read one packet */
1267d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (bytes) {
1268d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef PACKET_AUXDATA
1269d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		for (cmsg = CMSG_FIRSTHDR(&msg);
1270d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		     cmsg;
1271d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		     cmsg = CMSG_NXTHDR(&msg, cmsg))
1272d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		{
1273d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			if (cmsg->cmsg_level == SOL_PACKET &&
1274d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    cmsg->cmsg_type == PACKET_AUXDATA) {
1275d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				aux = (void *)CMSG_DATA(cmsg);
1276d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan				if (aux->tp_status & TP_STATUS_CSUMNOTREADY)
1277d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan					*flags |= RAW_PARTIALCSUM;
1278d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			}
1279d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
1280d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
1281d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1282d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return bytes;
1283d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1284d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1285d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint
1286d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanif_address(const struct interface *iface,
1287d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    const struct in_addr *address, const struct in_addr *netmask,
1288d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    const struct in_addr *broadcast, int action)
1289d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1290d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct nlma nlm;
1291d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int retval = 0;
1292d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1293d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	memset(&nlm, 0, sizeof(nlm));
1294d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
1295d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.hdr.nlmsg_flags = NLM_F_REQUEST;
1296d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (action >= 0) {
1297d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		nlm.hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
1298d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		nlm.hdr.nlmsg_type = RTM_NEWADDR;
1299d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	} else
1300d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		nlm.hdr.nlmsg_type = RTM_DELADDR;
1301d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.ifa.ifa_index = iface->index;
1302d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.ifa.ifa_family = AF_INET;
1303d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.ifa.ifa_prefixlen = inet_ntocidr(*netmask);
1304d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* This creates the aliased interface */
1305d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	add_attr_l(&nlm.hdr, sizeof(nlm), IFA_LABEL,
1306d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    iface->alias, (unsigned short)(strlen(iface->alias) + 1));
1307d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	add_attr_l(&nlm.hdr, sizeof(nlm), IFA_LOCAL,
1308d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    &address->s_addr, sizeof(address->s_addr));
1309d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (action >= 0 && broadcast)
1310d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		add_attr_l(&nlm.hdr, sizeof(nlm), IFA_BROADCAST,
1311d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    &broadcast->s_addr, sizeof(broadcast->s_addr));
1312d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1313d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (send_netlink(iface->ctx, NULL, NETLINK_ROUTE, &nlm.hdr, NULL) == -1)
1314d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		retval = -1;
1315d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return retval;
1316d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1317d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1318d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint
1319d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanif_route(unsigned char cmd, const struct rt *rt)
1320d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1321d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct nlmr nlm;
1322d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int retval = 0;
1323d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct dhcp_state *state;
1324d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1325d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	memset(&nlm, 0, sizeof(nlm));
1326d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
1327d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	switch (cmd) {
1328d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	case RTM_CHANGE:
1329d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		nlm.hdr.nlmsg_type = RTM_NEWROUTE;
1330d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		nlm.hdr.nlmsg_flags = NLM_F_CREATE | NLM_F_REPLACE;
1331d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		break;
1332d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	case RTM_ADD:
1333d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		nlm.hdr.nlmsg_type = RTM_NEWROUTE;
1334d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		nlm.hdr.nlmsg_flags = NLM_F_CREATE | NLM_F_EXCL;
1335d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		break;
1336d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	case RTM_DELETE:
1337d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		nlm.hdr.nlmsg_type = RTM_DELROUTE;
1338d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		break;
1339d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1340d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.hdr.nlmsg_flags |= NLM_F_REQUEST;
1341d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.rt.rtm_family = AF_INET;
1342d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.rt.rtm_table = RT_TABLE_MAIN;
1343d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1344d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	state = D_STATE(rt->iface);
1345d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (cmd == RTM_DELETE)
1346d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		nlm.rt.rtm_scope = RT_SCOPE_NOWHERE;
1347d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else {
1348d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* We only change route metrics for kernel routes */
1349d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (rt->dest.s_addr ==
1350d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    (state->addr.s_addr & state->net.s_addr) &&
1351d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    rt->net.s_addr == state->net.s_addr)
1352d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			nlm.rt.rtm_protocol = RTPROT_KERNEL;
1353d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		else
1354d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			nlm.rt.rtm_protocol = RTPROT_BOOT;
1355d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (rt->iface->flags & IFF_LOOPBACK)
1356d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			nlm.rt.rtm_scope = RT_SCOPE_HOST;
1357d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		else if (rt->gate.s_addr == INADDR_ANY ||
1358d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    (rt->gate.s_addr == rt->dest.s_addr &&
1359d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			rt->net.s_addr == INADDR_BROADCAST))
1360d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			nlm.rt.rtm_scope = RT_SCOPE_LINK;
1361d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		else
1362d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			nlm.rt.rtm_scope = RT_SCOPE_UNIVERSE;
1363d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		nlm.rt.rtm_type = RTN_UNICAST;
1364d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1365d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1366d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.rt.rtm_dst_len = inet_ntocidr(rt->net);
1367d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	add_attr_l(&nlm.hdr, sizeof(nlm), RTA_DST,
1368d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    &rt->dest.s_addr, sizeof(rt->dest.s_addr));
1369d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (nlm.rt.rtm_protocol == RTPROT_KERNEL) {
1370d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		add_attr_l(&nlm.hdr, sizeof(nlm), RTA_PREFSRC,
1371d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    &state->addr.s_addr, sizeof(state->addr.s_addr));
1372d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1373d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* If a host route then don't add the gateway */
1374d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if ((cmd == RTM_ADD || cmd == RTM_CHANGE) &&
1375d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    rt->net.s_addr != INADDR_BROADCAST)
1376d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		add_attr_l(&nlm.hdr, sizeof(nlm), RTA_GATEWAY,
1377d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    &rt->gate.s_addr, sizeof(rt->gate.s_addr));
1378d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1379d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (rt->gate.s_addr != htonl(INADDR_LOOPBACK))
1380d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		add_attr_32(&nlm.hdr, sizeof(nlm), RTA_OIF, rt->iface->index);
1381d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (rt->metric)
1382d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		add_attr_32(&nlm.hdr, sizeof(nlm), RTA_PRIORITY, rt->metric);
1383d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1384d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (send_netlink(rt->iface->ctx, NULL,
1385d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    NETLINK_ROUTE, &nlm.hdr, NULL) == -1)
1386d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		retval = -1;
1387d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return retval;
1388d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1389d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1390d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
1391d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan_if_initrt(struct dhcpcd_ctx *ctx, __unused struct interface *ifp,
1392d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    struct nlmsghdr *nlm)
1393d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1394d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct rt rt;
1395d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1396d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (if_copyrt(ctx, &rt, nlm) == 0)
1397d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ipv4_handlert(ctx, RTM_ADD, &rt);
1398d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return 0;
1399d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1400d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1401d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint
1402d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanif_initrt(struct interface *ifp)
1403d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1404d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct nlmr nlm;
1405d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1406d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ipv4_freerts(ifp->ctx->ipv4_kroutes);
1407d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1408d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	memset(&nlm, 0, sizeof(nlm));
1409d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
1410d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.hdr.nlmsg_type = RTM_GETROUTE;
1411d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH;
1412d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.hdr.nlmsg_flags |= NLM_F_REQUEST;
1413d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.rt.rtm_family = AF_INET;
1414d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.rt.rtm_table = RT_TABLE_MAIN;
1415d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	add_attr_32(&nlm.hdr, sizeof(nlm), RTA_OIF, ifp->index);
1416d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1417d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return send_netlink(ifp->ctx, ifp,
1418d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    NETLINK_ROUTE, &nlm.hdr, &_if_initrt);
1419d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1420d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1421d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint
1422d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanif_addrflags(__unused const struct in_addr *addr,
1423d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    __unused const struct interface *ifp)
1424d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1425d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1426d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Linux has no support for IPv4 address flags */
1427d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return 0;
1428d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1429d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
1430d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1431d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef INET6
1432d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint
1433d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanif_address6(const struct ipv6_addr *ap, int action)
1434d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1435d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct nlma nlm;
1436d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct ifa_cacheinfo cinfo;
1437d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int retval = 0;
1438d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan/* IFA_FLAGS is not a define, but is was added at the same time
1439d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * IFA_F_NOPREFIXROUTE was do use that. */
1440d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#if defined(IFA_F_NOPREFIXROUTE) || defined(IFA_F_MANAGETEMPADDR)
1441d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	uint32_t flags = 0;
1442d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
1443d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1444d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	memset(&nlm, 0, sizeof(nlm));
1445d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
1446d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.hdr.nlmsg_flags = NLM_F_REQUEST;
1447d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (action >= 0) {
1448d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		nlm.hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
1449d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		nlm.hdr.nlmsg_type = RTM_NEWADDR;
1450d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	} else
1451d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		nlm.hdr.nlmsg_type = RTM_DELADDR;
1452d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.ifa.ifa_index = ap->iface->index;
1453d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.ifa.ifa_family = AF_INET6;
1454d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ap->addr_flags & IFA_F_TEMPORARY) {
1455d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef IFA_F_NOPREFIXROUTE
1456d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		flags |= IFA_F_TEMPORARY;
1457d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#else
1458d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		nlm.ifa.ifa_flags |= IFA_F_TEMPORARY;
1459d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
1460d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1461d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef IFA_F_MANAGETEMPADDR
1462d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else if (ap->flags & IPV6_AF_AUTOCONF &&
1463d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    ip6_use_tempaddr(ap->iface->name))
1464d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		flags |= IFA_F_MANAGETEMPADDR;
1465d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
1466d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1467d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* Add as /128 if no IFA_F_NOPREFIXROUTE ? */
1468d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.ifa.ifa_prefixlen = ap->prefix_len;
1469d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* This creates the aliased interface */
1470d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	add_attr_l(&nlm.hdr, sizeof(nlm), IFA_LABEL,
1471d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    ap->iface->alias, (unsigned short)(strlen(ap->iface->alias) + 1));
1472d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	add_attr_l(&nlm.hdr, sizeof(nlm), IFA_LOCAL,
1473d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    &ap->addr.s6_addr, sizeof(ap->addr.s6_addr));
1474d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1475d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (action >= 0) {
1476d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		memset(&cinfo, 0, sizeof(cinfo));
1477d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		cinfo.ifa_prefered = ap->prefix_pltime;
1478d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		cinfo.ifa_valid = ap->prefix_vltime;
1479d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		add_attr_l(&nlm.hdr, sizeof(nlm), IFA_CACHEINFO,
1480d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    &cinfo, sizeof(cinfo));
1481d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1482d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1483d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef IFA_F_NOPREFIXROUTE
1484d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (!IN6_IS_ADDR_LINKLOCAL(&ap->addr))
1485d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		flags |= IFA_F_NOPREFIXROUTE;
1486d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
1487d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#if defined(IFA_F_NOPREFIXROUTE) || defined(IFA_F_MANAGETEMPADDR)
1488d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (flags)
1489d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		add_attr_32(&nlm.hdr, sizeof(nlm), IFA_FLAGS, flags);
1490d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif
1491d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1492d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (send_netlink(ap->iface->ctx, NULL, NETLINK_ROUTE, &nlm.hdr,
1493d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    NULL) == -1)
1494d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		retval = -1;
1495d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return retval;
1496d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1497d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1498d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
1499d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanrta_add_attr_32(struct rtattr *rta, unsigned short maxlen,
1500d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    unsigned short type, uint32_t data)
1501d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1502d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	unsigned short len = RTA_LENGTH(sizeof(data));
1503d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct rtattr *subrta;
1504d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1505d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
1506d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		errno = ENOBUFS;
1507d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
1508d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1509d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1510d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	subrta = (struct rtattr*)(void *)
1511d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    (((char*)rta) + RTA_ALIGN(rta->rta_len));
1512d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	subrta->rta_type = type;
1513d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	subrta->rta_len = len;
1514d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	memcpy(RTA_DATA(subrta), &data, sizeof(data));
1515d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	rta->rta_len = (unsigned short)(NLMSG_ALIGN(rta->rta_len) + len);
1516d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return 0;
1517d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1518d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1519d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint
1520d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanif_route6(unsigned char cmd, const struct rt6 *rt)
1521d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1522d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct nlmr nlm;
1523d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int retval = 0;
1524d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1525d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	memset(&nlm, 0, sizeof(nlm));
1526d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
1527d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	switch (cmd) {
1528d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	case RTM_CHANGE:
1529d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		nlm.hdr.nlmsg_type = RTM_NEWROUTE;
1530d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		nlm.hdr.nlmsg_flags = NLM_F_CREATE | NLM_F_REPLACE;
1531d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		break;
1532d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	case RTM_ADD:
1533d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		nlm.hdr.nlmsg_type = RTM_NEWROUTE;
1534d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		nlm.hdr.nlmsg_flags = NLM_F_CREATE | NLM_F_EXCL;
1535d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		break;
1536d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	case RTM_DELETE:
1537d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		nlm.hdr.nlmsg_type = RTM_DELROUTE;
1538d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		break;
1539d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1540d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.hdr.nlmsg_flags |= NLM_F_REQUEST;
1541d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.rt.rtm_family = AF_INET6;
1542d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.rt.rtm_table = RT_TABLE_MAIN;
1543d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1544d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (cmd == RTM_DELETE)
1545d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		nlm.rt.rtm_scope = RT_SCOPE_NOWHERE;
1546d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else {
1547d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* None interface subnet routes are static. */
1548d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (rt->iface->flags & IFF_LOOPBACK)
1549d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			nlm.rt.rtm_scope = RT_SCOPE_HOST;
1550d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		else if (IN6_IS_ADDR_UNSPECIFIED(&rt->gate)) {
1551d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			nlm.rt.rtm_protocol = RTPROT_KERNEL;
1552d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			nlm.rt.rtm_scope = RT_SCOPE_LINK;
1553d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		} else
1554d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			nlm.rt.rtm_protocol = RTPROT_BOOT;
1555d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (rt->flags & RTF_REJECT)
1556d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			nlm.rt.rtm_type = RTN_UNREACHABLE;
1557d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		else
1558d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			nlm.rt.rtm_type = RTN_UNICAST;
1559d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1560d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1561d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.rt.rtm_dst_len = ipv6_prefixlen(&rt->net);
1562d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	add_attr_l(&nlm.hdr, sizeof(nlm), RTA_DST,
1563d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    &rt->dest.s6_addr, sizeof(rt->dest.s6_addr));
1564d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1565d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (cmd == RTM_ADD && !IN6_IS_ADDR_UNSPECIFIED(&rt->gate))
1566d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		add_attr_l(&nlm.hdr, sizeof(nlm), RTA_GATEWAY,
1567d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    &rt->gate.s6_addr, sizeof(rt->gate.s6_addr));
1568d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1569d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (!(rt->flags & RTF_REJECT)) {
1570d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		add_attr_32(&nlm.hdr, sizeof(nlm), RTA_OIF, rt->iface->index);
1571d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (rt->metric)
1572d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			add_attr_32(&nlm.hdr, sizeof(nlm),
1573d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    RTA_PRIORITY, rt->metric);
1574d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1575d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (cmd == RTM_ADD && rt->mtu) {
1576d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		char metricsbuf[32];
1577d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		struct rtattr *metrics = (void *)metricsbuf;
1578d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1579d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		metrics->rta_type = RTA_METRICS;
1580d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		metrics->rta_len = RTA_LENGTH(0);
1581d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		rta_add_attr_32(metrics, sizeof(metricsbuf), RTAX_MTU, rt->mtu);
1582d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		add_attr_l(&nlm.hdr, sizeof(nlm), RTA_METRICS,
1583d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    RTA_DATA(metrics), (unsigned short)RTA_PAYLOAD(metrics));
1584d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1585d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1586d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (send_netlink(rt->iface->ctx, NULL,
1587d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    NETLINK_ROUTE, &nlm.hdr, NULL) == -1)
1588d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		retval = -1;
1589d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return retval;
1590d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1591d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1592d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
1593d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan_if_initrt6(struct dhcpcd_ctx *ctx, __unused struct interface *ifp,
1594d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    struct nlmsghdr *nlm)
1595d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1596d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct rt6 rt;
1597d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1598d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (if_copyrt6(ctx, &rt, nlm) == 0)
1599d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ipv6_handlert(ctx, RTM_ADD, &rt);
1600d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return 0;
1601d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1602d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1603d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint
1604d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanif_initrt6(struct interface *ifp)
1605d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1606d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct nlmr nlm;
1607d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1608d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ipv6_freerts(&ifp->ctx->ipv6->kroutes);
1609d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1610d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	memset(&nlm, 0, sizeof(nlm));
1611d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
1612d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.hdr.nlmsg_type = RTM_GETROUTE;
1613d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH;
1614d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.hdr.nlmsg_flags |= NLM_F_REQUEST;
1615d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.rt.rtm_family = AF_INET6;
1616d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.rt.rtm_table = RT_TABLE_MAIN;
1617d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	add_attr_32(&nlm.hdr, sizeof(nlm), RTA_OIF, ifp->index);
1618d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1619d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return send_netlink(ifp->ctx, ifp,
1620d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    NETLINK_ROUTE, &nlm.hdr, &_if_initrt6);
1621d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1622d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1623d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint
1624d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanif_addrflags6(const struct in6_addr *addr, const struct interface *ifp)
1625d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1626d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	FILE *fp;
1627d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	char *p, ifaddress[33], address[33], name[IF_NAMESIZE + 1];
1628d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	unsigned int ifindex;
1629d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int prefix, scope, flags, i;
1630d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1631d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	fp = fopen(PROC_INET6, "r");
1632d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (fp == NULL)
1633d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return -1;
1634d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1635d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	p = ifaddress;
1636d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	for (i = 0; i < (int)sizeof(addr->s6_addr); i++) {
1637d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		p += snprintf(p, 3, "%.2x", addr->s6_addr[i]);
1638d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1639d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	*p = '\0';
1640d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1641d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	while (fscanf(fp, "%32[a-f0-9] %x %x %x %x %"TOSTRING(IF_NAMESIZE)"s\n",
1642d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    address, &ifindex, &prefix, &scope, &flags, name) == 6)
1643d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	{
1644d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (strlen(address) != 32) {
1645d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			fclose(fp);
1646d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			errno = ENOTSUP;
1647d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return -1;
1648d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
1649d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (strcmp(name, ifp->name) == 0 &&
1650d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    strcmp(ifaddress, address) == 0)
1651d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		{
1652d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			fclose(fp);
1653d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return flags;
1654d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
1655d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1656d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1657d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	fclose(fp);
1658d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	errno = ESRCH;
1659d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return -1;
1660d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1661d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1662d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint
1663d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanif_getlifetime6(__unused struct ipv6_addr *ia)
1664d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1665d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1666d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	/* God knows how to work out address lifetimes on Linux */
1667d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	errno = ENOTSUP;
1668d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return -1;
1669d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1670d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1671d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstruct nlml
1672d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1673d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct nlmsghdr hdr;
1674d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct ifinfomsg i;
1675d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	char buffer[32];
1676d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan};
1677d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1678d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
1679d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanadd_attr_8(struct nlmsghdr *n, unsigned short maxlen, unsigned short type,
1680d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan    uint8_t data)
1681d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1682d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1683d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return add_attr_l(n, maxlen, type, &data, sizeof(data));
1684d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1685d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1686d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic struct rtattr *
1687d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanadd_attr_nest(struct nlmsghdr *n, unsigned short maxlen, unsigned short type)
1688d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1689d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct rtattr *nest;
1690d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1691d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nest = NLMSG_TAIL(n);
1692d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	add_attr_l(n, maxlen, type, NULL, 0);
1693d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return nest;
1694d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1695d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1696d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void
1697d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanadd_attr_nest_end(struct nlmsghdr *n, struct rtattr *nest)
1698d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1699d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1700d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nest->rta_len = (unsigned short)((char *)NLMSG_TAIL(n) - (char *)nest);
1701d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1702d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1703d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int
1704d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanif_disable_autolinklocal(struct dhcpcd_ctx *ctx, int ifindex)
1705d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1706d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct nlml nlm;
1707d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	struct rtattr *afs, *afs6;
1708d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1709d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	memset(&nlm, 0, sizeof(nlm));
1710d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
1711d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.hdr.nlmsg_type = RTM_NEWLINK;
1712d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.hdr.nlmsg_flags = NLM_F_REQUEST;
1713d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.i.ifi_family = AF_INET6;
1714d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	nlm.i.ifi_index = ifindex;
1715d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	afs = add_attr_nest(&nlm.hdr, sizeof(nlm), IFLA_AF_SPEC);
1716d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	afs6 = add_attr_nest(&nlm.hdr, sizeof(nlm), AF_INET6);
1717d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	add_attr_8(&nlm.hdr, sizeof(nlm), IFLA_INET6_ADDR_GEN_MODE,
1718d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    IN6_ADDR_GEN_MODE_NONE);
1719d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	add_attr_nest_end(&nlm.hdr, afs6);
1720d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	add_attr_nest_end(&nlm.hdr, afs);
1721d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1722d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return send_netlink(ctx, NULL, NETLINK_ROUTE, &nlm.hdr, NULL);
1723d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1724d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1725d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic const char *prefix = "/proc/sys/net/ipv6/conf";
1726d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1727d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint
1728d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanif_checkipv6(struct dhcpcd_ctx *ctx, const struct interface *ifp, int own)
1729d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1730d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	const char *ifname;
1731d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int ra;
1732d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	char path[256];
1733d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1734d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifp == NULL)
1735d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ifname = "all";
1736d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else if (own) {
1737d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (if_disable_autolinklocal(ctx, (int)ifp->index) == -1)
1738d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ctx, LOG_DEBUG,
1739d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    "%s: if_disable_autolinklocal: %m", ifp->name);
1740d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1741d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifp)
1742d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ifname = ifp->name;
1743d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1744d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	snprintf(path, sizeof(path), "%s/%s/autoconf", prefix, ifname);
1745d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ra = check_proc_int(path);
1746d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ra != 1) {
1747d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (!own)
1748d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ctx, LOG_WARNING,
1749d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			    "%s: IPv6 kernel autoconf disabled", ifname);
1750d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	} else if (ra != -1 && own) {
1751d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (write_path(path, "0") == -1) {
1752d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ctx, LOG_ERR, "write_path: %s: %m", path);
1753d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return -1;
1754d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
1755d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1756d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1757d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	snprintf(path, sizeof(path), "%s/%s/accept_ra", prefix, ifname);
1758d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	ra = check_proc_int(path);
1759d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ra == -1)
1760d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		/* The sysctl probably doesn't exist, but this isn't an
1761d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		 * error as such so just log it and continue */
1762d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		logger(ctx, errno == ENOENT ? LOG_DEBUG : LOG_WARNING,
1763d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    "%s: %m", path);
1764d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	else if (ra != 0 && own) {
1765d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		logger(ctx, LOG_DEBUG, "%s: disabling kernel IPv6 RA support",
1766d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		    ifname);
1767d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		if (write_path(path, "0") == -1) {
1768d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			logger(ctx, LOG_ERR, "write_path: %s: %m", path);
1769d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan			return ra;
1770d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		}
1771d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		return 0;
1772d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	}
1773d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1774d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return ra;
1775d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1776d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1777d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef IPV6_MANAGETEMPADDR
1778d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint
1779d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanip6_use_tempaddr(const char *ifname)
1780d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1781d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	char path[256];
1782d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int val;
1783d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1784d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifname == NULL)
1785d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ifname = "all";
1786d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	snprintf(path, sizeof(path), "%s/%s/use_tempaddr", prefix, ifname);
1787d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	val = check_proc_int(path);
1788d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return val == -1 ? 0 : val;
1789d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1790d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1791d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint
1792d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanip6_temp_preferred_lifetime(const char *ifname)
1793d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1794d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	char path[256];
1795d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int val;
1796d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1797d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifname == NULL)
1798d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ifname = "all";
1799d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	snprintf(path, sizeof(path), "%s/%s/temp_prefered_lft", prefix,
1800d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	    ifname);
1801d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	val = check_proc_int(path);
1802d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return val < 0 ? TEMP_PREFERRED_LIFETIME : val;
1803d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1804d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1805d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint
1806d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanip6_temp_valid_lifetime(const char *ifname)
1807d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{
1808d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	char path[256];
1809d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	int val;
1810d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan
1811d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	if (ifname == NULL)
1812d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan		ifname = "all";
1813d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	snprintf(path, sizeof(path), "%s/%s/temp_valid_lft", prefix, ifname);
1814d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	val = check_proc_int(path);
1815d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan	return val < 0 ? TEMP_VALID_LIFETIME : val;
1816d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan}
1817d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif /* IPV6_MANAGETEMPADDR */
1818d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif /* INET6 */
1819