Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / bsd / dhcpcd / dist / if-bsd.c
blob58c405f83d8b33f35e1c3beeb0d1bc6ac46908c1
1 /*
2 * dhcpcd - DHCP client daemon
3 * Copyright (c) 2006-2009 Roy Marples <roy@marples.name>
4 * All rights reserved
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
28 #include <sys/ioctl.h>
29 #include <sys/param.h>
30 #include <sys/socket.h>
31 #include <sys/stat.h>
32 #include <sys/sysctl.h>
33 #include <sys/types.h>
35 #include <arpa/inet.h>
36 #include <net/if.h>
37 #include <net/if_dl.h>
38 #include <net/route.h>
39 #include <netinet/in.h>
40 #ifdef __DragonFly__
41 # include <netproto/802_11/ieee80211_ioctl.h>
42 #else
43 # include <net80211/ieee80211_ioctl.h>
44 #endif
46 #include <errno.h>
47 #include <fnmatch.h>
48 #include <stddef.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <syslog.h>
53 #include <unistd.h>
55 #include "config.h"
56 #include "common.h"
57 #include "configure.h"
58 #include "dhcp.h"
59 #include "if-options.h"
60 #include "net.h"
62 #define ROUNDUP(a) \
63 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
64 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
66 /* FIXME: Why do we need to check for sa_family 255 */
67 #define COPYOUT(sin, sa) \
68 sin.s_addr = ((sa) != NULL && ((sa)->sa_family == AF_INET || \
69 (sa)->sa_family == 255)) \
70 ? \
71 (((struct sockaddr_in *)(void *)sa)->sin_addr).s_addr : 0
73 static int r_fd = -1;
75 int
76 init_sockets(void)
78 if ((socket_afnet = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
79 return -1;
80 set_cloexec(socket_afnet);
81 if ((r_fd = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
82 return -1;
83 set_cloexec(r_fd);
84 return 0;
87 int
88 getifssid(const char *ifname, char *ssid)
90 int retval = -1;
91 #if defined(SIOCG80211NWID)
92 struct ifreq ifr;
93 struct ieee80211_nwid nwid;
94 #elif defined(IEEE80211_IOC_SSID)
95 struct ieee80211req ireq;
96 char nwid[IEEE80211_NWID_LEN + 1];
97 #endif
99 #if defined(SIOCG80211NWID) /* NetBSD */
100 memset(&ifr, 0, sizeof(ifr));
101 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
102 memset(&nwid, 0, sizeof(nwid));
103 ifr.ifr_data = (void *)&nwid;
104 if (ioctl(socket_afnet, SIOCG80211NWID, &ifr) == 0) {
105 retval = nwid.i_len;
106 memcpy(ssid, nwid.i_nwid, nwid.i_len);
107 ssid[nwid.i_len] = '\0';
109 #elif defined(IEEE80211_IOC_SSID) /* FreeBSD */
110 memset(&ireq, 0, sizeof(ireq));
111 strlcpy(ireq.i_name, ifname, sizeof(ireq.i_name));
112 ireq.i_type = IEEE80211_IOC_SSID;
113 ireq.i_val = -1;
114 ireq.i_data = &nwid;
115 if (ioctl(socket_afnet, SIOCG80211, &ireq) == 0) {
116 retval = ireq.i_len;
117 memcpy(ssid, nwid, ireq.i_len);
118 ssid[ireq.i_len] = '\0';
120 #endif
121 return retval;
125 if_address(const struct interface *iface, const struct in_addr *address,
126 const struct in_addr *netmask, const struct in_addr *broadcast,
127 int action)
129 int retval;
130 struct ifaliasreq ifa;
131 union {
132 struct sockaddr *sa;
133 struct sockaddr_in *sin;
134 } _s;
136 memset(&ifa, 0, sizeof(ifa));
137 strlcpy(ifa.ifra_name, iface->name, sizeof(ifa.ifra_name));
139 #define ADDADDR(_var, _addr) { \
140 _s.sa = &_var; \
141 _s.sin->sin_family = AF_INET; \
142 _s.sin->sin_len = sizeof(*_s.sin); \
143 memcpy(&_s.sin->sin_addr, _addr, sizeof(_s.sin->sin_addr)); \
146 ADDADDR(ifa.ifra_addr, address);
147 ADDADDR(ifa.ifra_mask, netmask);
148 if (action >= 0 && broadcast) {
149 ADDADDR(ifa.ifra_broadaddr, broadcast);
151 #undef ADDADDR
153 if (action < 0)
154 retval = ioctl(socket_afnet, SIOCDIFADDR, &ifa);
155 else
156 retval = ioctl(socket_afnet, SIOCAIFADDR, &ifa);
157 return retval;
160 /* ARGSUSED4 */
162 if_route(const struct interface *iface, const struct in_addr *dest,
163 const struct in_addr *net, const struct in_addr *gate,
164 _unused int metric, int action)
166 union sockunion {
167 struct sockaddr sa;
168 struct sockaddr_in sin;
169 #ifdef INET6
170 struct sockaddr_in6 sin6;
171 #endif
172 struct sockaddr_dl sdl;
173 struct sockaddr_storage ss;
174 } su;
175 struct rtm
177 struct rt_msghdr hdr;
178 char buffer[sizeof(su) * 4];
179 } rtm;
180 char *bp = rtm.buffer, *p;
181 size_t l;
182 int retval = 0;
184 #define ADDSU(_su) { \
185 l = ROUNDUP(_su.sa.sa_len); \
186 memcpy(bp, &(_su), l); \
187 bp += l; \
189 #define ADDADDR(_a) { \
190 memset (&su, 0, sizeof(su)); \
191 su.sin.sin_family = AF_INET; \
192 su.sin.sin_len = sizeof(su.sin); \
193 memcpy (&su.sin.sin_addr, _a, sizeof(su.sin.sin_addr)); \
194 ADDSU(su); \
197 memset(&rtm, 0, sizeof(rtm));
198 rtm.hdr.rtm_version = RTM_VERSION;
199 rtm.hdr.rtm_seq = 1;
200 if (action == 0)
201 rtm.hdr.rtm_type = RTM_CHANGE;
202 else if (action > 0)
203 rtm.hdr.rtm_type = RTM_ADD;
204 else
205 rtm.hdr.rtm_type = RTM_DELETE;
206 rtm.hdr.rtm_flags = RTF_UP;
207 /* None interface subnet routes are static. */
208 if (gate->s_addr != INADDR_ANY ||
209 net->s_addr != iface->net.s_addr ||
210 dest->s_addr != (iface->addr.s_addr & iface->net.s_addr))
211 rtm.hdr.rtm_flags |= RTF_STATIC;
212 rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
213 if (dest->s_addr == gate->s_addr && net->s_addr == INADDR_BROADCAST)
214 rtm.hdr.rtm_flags |= RTF_HOST;
215 else {
216 rtm.hdr.rtm_addrs |= RTA_NETMASK;
217 if (rtm.hdr.rtm_flags & RTF_STATIC)
218 rtm.hdr.rtm_flags |= RTF_GATEWAY;
219 if (action >= 0)
220 rtm.hdr.rtm_addrs |= RTA_IFA;
223 ADDADDR(dest);
224 if (rtm.hdr.rtm_flags & RTF_HOST ||
225 !(rtm.hdr.rtm_flags & RTF_STATIC))
227 /* Make us a link layer socket for the host gateway */
228 memset(&su, 0, sizeof(su));
229 su.sdl.sdl_len = sizeof(struct sockaddr_dl);
230 link_addr(iface->name, &su.sdl);
231 ADDSU(su);
232 } else
233 ADDADDR(gate);
235 if (rtm.hdr.rtm_addrs & RTA_NETMASK) {
236 /* Ensure that netmask is set correctly */
237 memset(&su, 0, sizeof(su));
238 su.sin.sin_family = AF_INET;
239 su.sin.sin_len = sizeof(su.sin);
240 memcpy(&su.sin.sin_addr, &net->s_addr, sizeof(su.sin.sin_addr));
241 p = su.sa.sa_len + (char *)&su;
242 for (su.sa.sa_len = 0; p > (char *)&su;)
243 if (*--p != 0) {
244 su.sa.sa_len = 1 + p - (char *)&su;
245 break;
247 ADDSU(su);
250 if (rtm.hdr.rtm_addrs & RTA_IFA)
251 ADDADDR(&iface->addr);
253 rtm.hdr.rtm_msglen = l = bp - (char *)&rtm;
254 if (write(r_fd, &rtm, l) == -1)
255 retval = -1;
256 return retval;
260 open_link_socket(void)
262 int fd;
264 fd = socket(PF_ROUTE, SOCK_RAW, 0);
265 if (fd != -1) {
266 set_cloexec(fd);
267 set_nonblock(fd);
269 return fd;
272 static void
273 get_addrs(int type, char *cp, struct sockaddr **sa)
275 int i;
277 for (i = 0; i < RTAX_MAX; i++) {
278 if (type & (1 << i)) {
279 sa[i] = (struct sockaddr *)cp;
280 #ifdef DEBUG
281 printf ("got %d %d %s\n", i, sa[i]->sa_family,
282 inet_ntoa(((struct sockaddr_in *)sa[i])->
283 sin_addr));
284 #endif
285 ADVANCE(cp, sa[i]);
286 } else
287 sa[i] = NULL;
291 #define BUFFER_LEN 2048
293 manage_link(int fd)
295 char buffer[2048], *p, *e, *cp;
296 char ifname[IF_NAMESIZE];
297 ssize_t bytes;
298 struct rt_msghdr *rtm;
299 struct if_announcemsghdr *ifan;
300 struct if_msghdr *ifm;
301 struct ifa_msghdr *ifam;
302 struct rt rt;
303 struct sockaddr *sa, *rti_info[RTAX_MAX];
305 for (;;) {
306 bytes = read(fd, buffer, BUFFER_LEN);
307 if (bytes == -1) {
308 if (errno == EAGAIN)
309 return 0;
310 if (errno == EINTR)
311 continue;
312 return -1;
314 e = buffer + bytes;
315 for (p = buffer; p < e; p += rtm->rtm_msglen) {
316 rtm = (struct rt_msghdr *)(void *)p;
317 switch(rtm->rtm_type) {
318 case RTM_IFANNOUNCE:
319 ifan = (struct if_announcemsghdr *)(void *)p;
320 switch(ifan->ifan_what) {
321 case IFAN_ARRIVAL:
322 handle_interface(1, ifan->ifan_name);
323 break;
324 case IFAN_DEPARTURE:
325 handle_interface(-1, ifan->ifan_name);
326 break;
328 break;
329 case RTM_IFINFO:
330 ifm = (struct if_msghdr *)(void *)p;
331 memset(ifname, 0, sizeof(ifname));
332 if (if_indextoname(ifm->ifm_index, ifname))
333 handle_interface(0, ifname);
334 break;
335 case RTM_DELETE:
336 if (!(rtm->rtm_addrs & RTA_DST) ||
337 !(rtm->rtm_addrs & RTA_GATEWAY) ||
338 !(rtm->rtm_addrs & RTA_NETMASK))
339 break;
340 if (rtm->rtm_pid == getpid())
341 break;
342 cp = (char *)(void *)(rtm + 1);
343 sa = (struct sockaddr *)(void *)cp;
344 if (sa->sa_family != AF_INET)
345 break;
346 get_addrs(rtm->rtm_addrs, cp, rti_info);
347 rt.iface = NULL;
348 rt.next = NULL;
349 COPYOUT(rt.dest, rti_info[RTAX_DST]);
350 COPYOUT(rt.net, rti_info[RTAX_NETMASK]);
351 COPYOUT(rt.gate, rti_info[RTAX_GATEWAY]);
352 route_deleted(&rt);
353 break;
354 case RTM_DELADDR:
355 case RTM_NEWADDR:
356 ifam = (struct ifa_msghdr *)(void *)p;
357 cp = (char *)(void *)(ifam + 1);
358 get_addrs(ifam->ifam_addrs, cp, rti_info);
359 COPYOUT(rt.dest, rti_info[RTAX_IFA]);
360 COPYOUT(rt.net, rti_info[RTAX_NETMASK]);
361 COPYOUT(rt.gate, rti_info[RTAX_BRD]);
362 if (if_indextoname(ifam->ifam_index, ifname))
363 handle_ifa(rtm->rtm_type, ifname,
364 &rt.dest, &rt.net, &rt.gate);
365 break;