blob: d0ff24641c7c9765c14957dcff80f38ccc9fdb4a [file] [log] [blame]
The Android Open Source Projectf7c54212009-03-03 19:29:22 -08001/*
2 * dhcpcd - DHCP client daemon
3 * Copyright 2006-2008 Roy Marples <roy@marples.name>
4 * All rights reserved
5
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include <sys/types.h>
29#include <sys/socket.h>
30#include <sys/stat.h>
31#include <sys/ioctl.h>
32#include <sys/param.h>
33
34#include <arpa/inet.h>
35#include <net/if_dl.h>
36#include <net/if_types.h>
37#include <net/route.h>
38#include <netinet/in.h>
39
40#include <errno.h>
41#include <stddef.h>
42#include <stdio.h>
43#include <stdlib.h>
44#include <string.h>
45#include <unistd.h>
46
47#include "config.h"
48#include "common.h"
49#include "dhcp.h"
50#include "net.h"
51
52/* Darwin doesn't define this for some very odd reason */
53#ifndef SA_SIZE
54# define SA_SIZE(sa) \
55 ( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \
56 sizeof(long) : \
57 1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) )
58#endif
59
60int
61if_address(const char *ifname, const struct in_addr *address,
62 const struct in_addr *netmask, const struct in_addr *broadcast,
63 int action)
64{
65 int s;
66 int retval;
67 struct ifaliasreq ifa;
68 union {
69 struct sockaddr *sa;
70 struct sockaddr_in *sin;
71 } _s;
72
73 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
74 return -1;
75
76 memset(&ifa, 0, sizeof(ifa));
77 strlcpy(ifa.ifra_name, ifname, sizeof(ifa.ifra_name));
78
79#define ADDADDR(_var, _addr) \
80 _s.sa = &_var; \
81 _s.sin->sin_family = AF_INET; \
82 _s.sin->sin_len = sizeof(*_s.sin); \
83 memcpy(&_s.sin->sin_addr, _addr, sizeof(_s.sin->sin_addr));
84
85 ADDADDR(ifa.ifra_addr, address);
86 ADDADDR(ifa.ifra_mask, netmask);
87 if (action >= 0) {
88 ADDADDR(ifa.ifra_broadaddr, broadcast);
89 }
90#undef ADDADDR
91
92 if (action < 0)
93 retval = ioctl(s, SIOCDIFADDR, &ifa);
94 else
95 retval = ioctl(s, SIOCAIFADDR, &ifa);
96 close(s);
97 return retval;
98}
99
100int
Dmitry Shmidt938bc382010-01-08 10:47:26 -0800101if_route(const struct interface *iface, const struct in_addr *dest,
102 const struct in_addr *net, const struct in_addr *gate,
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800103 _unused int metric, int action)
104{
105 int s;
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800106 union sockunion {
107 struct sockaddr sa;
108 struct sockaddr_in sin;
109#ifdef INET6
110 struct sockaddr_in6 sin6;
111#endif
112 struct sockaddr_dl sdl;
113 struct sockaddr_storage ss;
114 } su;
115 struct rtm
116 {
117 struct rt_msghdr hdr;
Dmitry Shmidt938bc382010-01-08 10:47:26 -0800118 char buffer[sizeof(su) * 4];
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800119 } rtm;
Dmitry Shmidt938bc382010-01-08 10:47:26 -0800120 char *bp = rtm.buffer, *p;
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800121 size_t l;
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800122 int retval = 0;
123
Dmitry Shmidt938bc382010-01-08 10:47:26 -0800124#define ADDSU(_su) { \
125 l = SA_SIZE(&(_su.sa)); \
126 memcpy(bp, &(_su), l); \
127 bp += l; \
128}
129#define ADDADDR(_addr) { \
130 memset (&su, 0, sizeof(su)); \
131 su.sin.sin_family = AF_INET; \
132 su.sin.sin_len = sizeof(su.sin); \
133 memcpy (&su.sin.sin_addr, _addr, sizeof(su.sin.sin_addr)); \
134 ADDSU(su); \
135}
136
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800137 if ((s = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
138 return -1;
139
140 memset(&rtm, 0, sizeof(rtm));
141 rtm.hdr.rtm_version = RTM_VERSION;
Dmitry Shmidt938bc382010-01-08 10:47:26 -0800142 rtm.hdr.rtm_seq = 1;
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800143 if (action == 0)
144 rtm.hdr.rtm_type = RTM_CHANGE;
145 else if (action > 0)
146 rtm.hdr.rtm_type = RTM_ADD;
147 else
148 rtm.hdr.rtm_type = RTM_DELETE;
Dmitry Shmidt938bc382010-01-08 10:47:26 -0800149 rtm.hdr.rtm_flags = RTF_UP;
150 /* None interface subnet routes are static. */
151 if (gate->s_addr != INADDR_ANY ||
152 net->s_addr != iface->net.s_addr ||
153 dest->s_addr != (iface->addr.s_addr & iface->net.s_addr))
154 rtm.hdr.rtm_flags |= RTF_STATIC;
155 rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
156 if (dest->s_addr == gate->s_addr && net->s_addr == INADDR_BROADCAST)
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800157 rtm.hdr.rtm_flags |= RTF_HOST;
Dmitry Shmidt938bc382010-01-08 10:47:26 -0800158 else {
159 rtm.hdr.rtm_addrs |= RTA_NETMASK;
160 if (rtm.hdr.rtm_flags & RTF_STATIC)
161 rtm.hdr.rtm_flags |= RTF_GATEWAY;
162 if (action >= 0)
163 rtm.hdr.rtm_addrs |= RTA_IFA;
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800164 }
165
Dmitry Shmidt938bc382010-01-08 10:47:26 -0800166 ADDADDR(dest);
167 if (rtm.hdr.rtm_flags & RTF_HOST ||
168 !(rtm.hdr.rtm_flags & RTF_STATIC))
169 {
170 /* Make us a link layer socket for the host gateway */
171 memset(&su, 0, sizeof(su));
172 su.sdl.sdl_len = sizeof(struct sockaddr_dl);
173 link_addr(iface->name, &su.sdl);
174 ADDSU(su);
175 } else
176 ADDADDR(gate);
177
178 if (rtm.hdr.rtm_addrs & RTA_NETMASK) {
179 /* Ensure that netmask is set correctly */
180 memset(&su, 0, sizeof(su));
181 su.sin.sin_family = AF_INET;
182 su.sin.sin_len = sizeof(su.sin);
183 memcpy(&su.sin.sin_addr, &net->s_addr, sizeof(su.sin.sin_addr));
184 p = su.sa.sa_len + (char *)&su;
185 for (su.sa.sa_len = 0; p > (char *)&su;)
186 if (*--p != 0) {
187 su.sa.sa_len = 1 + p - (char *)&su;
188 break;
189 }
190 ADDSU(su);
191 }
192
193 if (rtm.hdr.rtm_addrs & RTA_IFA)
194 ADDADDR(&iface->addr);
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800195
196 rtm.hdr.rtm_msglen = l = bp - (char *)&rtm;
197 if (write(s, &rtm, l) == -1)
198 retval = -1;
199 close(s);
200 return retval;
201}
202
203int
204open_link_socket(struct interface *iface)
205{
206 int fd;
207
208 fd = socket(PF_ROUTE, SOCK_RAW, 0);
209 if (fd == -1)
210 return -1;
211 set_cloexec(fd);
212 if (iface->link_fd != -1)
213 close(iface->link_fd);
214 iface->link_fd = fd;
215 return 0;
216}
217
218#define BUFFER_LEN 2048
219int
220link_changed(struct interface *iface)
221{
222 char buffer[2048], *p;
223 ssize_t bytes;
224 struct rt_msghdr *rtm;
225 struct if_msghdr *ifm;
226 int i;
227
228 if ((i = if_nametoindex(iface->name)) == -1)
229 return -1;
230 for (;;) {
231 bytes = recv(iface->link_fd, buffer, BUFFER_LEN, MSG_DONTWAIT);
232 if (bytes == -1) {
233 if (errno == EAGAIN)
234 return 0;
235 if (errno == EINTR)
236 continue;
237 return -1;
238 }
239 for (p = buffer; bytes > 0;
240 bytes -= ((struct rt_msghdr *)p)->rtm_msglen,
241 p += ((struct rt_msghdr *)p)->rtm_msglen)
242 {
243 rtm = (struct rt_msghdr *)p;
244 if (rtm->rtm_type != RTM_IFINFO)
245 continue;
246 ifm = (struct if_msghdr *)p;
247 if (ifm->ifm_index != i)
248 continue;
249
250 /* Link changed */
251 return 1;
252 }
253 }
254 return 0;
255}