blob: bbf1a95d0a82a3108ad530bf76189ed7c4f94694 [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
101if_route(const char *ifname, const struct in_addr *destination,
102 const struct in_addr *netmask, const struct in_addr *gateway,
103 _unused int metric, int action)
104{
105 int s;
106 static int seq;
107 union sockunion {
108 struct sockaddr sa;
109 struct sockaddr_in sin;
110#ifdef INET6
111 struct sockaddr_in6 sin6;
112#endif
113 struct sockaddr_dl sdl;
114 struct sockaddr_storage ss;
115 } su;
116 struct rtm
117 {
118 struct rt_msghdr hdr;
119 char buffer[sizeof(su) * 3];
120 } rtm;
121 char *bp = rtm.buffer;
122 size_t l;
123 unsigned char *hwaddr;
124 size_t hwlen = 0;
125 int retval = 0;
126
127 if ((s = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
128 return -1;
129
130 memset(&rtm, 0, sizeof(rtm));
131 rtm.hdr.rtm_version = RTM_VERSION;
132 rtm.hdr.rtm_seq = ++seq;
133 if (action == 0)
134 rtm.hdr.rtm_type = RTM_CHANGE;
135 else if (action > 0)
136 rtm.hdr.rtm_type = RTM_ADD;
137 else
138 rtm.hdr.rtm_type = RTM_DELETE;
139 rtm.hdr.rtm_flags = RTF_UP | RTF_STATIC;
140 if (netmask->s_addr == INADDR_BROADCAST)
141 rtm.hdr.rtm_flags |= RTF_HOST;
142
143 /* This order is important */
144 rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
145
146#define ADDADDR(_addr) \
147 memset (&su, 0, sizeof(su)); \
148 su.sin.sin_family = AF_INET; \
149 su.sin.sin_len = sizeof(su.sin); \
150 memcpy (&su.sin.sin_addr, _addr, sizeof(su.sin.sin_addr)); \
151 l = SA_SIZE (&(su.sa)); \
152 memcpy (bp, &(su), l); \
153 bp += l;
154
155 ADDADDR(destination);
156
157 if (gateway->s_addr == INADDR_ANY) {
158 /* Make us a link layer socket */
159 hwaddr = xmalloc(sizeof(unsigned char) * HWADDR_LEN);
160 do_interface(ifname, hwaddr, &hwlen, NULL, 0, 0);
161 memset(&su, 0, sizeof(su));
162 su.sdl.sdl_len = sizeof(su.sdl);
163 su.sdl.sdl_family = AF_LINK;
164 su.sdl.sdl_nlen = strlen(ifname);
165 memcpy(&su.sdl.sdl_data, ifname, (size_t)su.sdl.sdl_nlen);
166 su.sdl.sdl_alen = hwlen;
167 memcpy(((unsigned char *)&su.sdl.sdl_data) + su.sdl.sdl_nlen,
168 hwaddr, (size_t)su.sdl.sdl_alen);
169
170 l = SA_SIZE(&(su.sa));
171 memcpy(bp, &su, l);
172 bp += l;
173 free(hwaddr);
174 } else {
175 rtm.hdr.rtm_flags |= RTF_GATEWAY;
176 ADDADDR(gateway);
177 }
178
179 ADDADDR(netmask);
180#undef ADDADDR
181
182 rtm.hdr.rtm_msglen = l = bp - (char *)&rtm;
183 if (write(s, &rtm, l) == -1)
184 retval = -1;
185 close(s);
186 return retval;
187}
188
189int
190open_link_socket(struct interface *iface)
191{
192 int fd;
193
194 fd = socket(PF_ROUTE, SOCK_RAW, 0);
195 if (fd == -1)
196 return -1;
197 set_cloexec(fd);
198 if (iface->link_fd != -1)
199 close(iface->link_fd);
200 iface->link_fd = fd;
201 return 0;
202}
203
204#define BUFFER_LEN 2048
205int
206link_changed(struct interface *iface)
207{
208 char buffer[2048], *p;
209 ssize_t bytes;
210 struct rt_msghdr *rtm;
211 struct if_msghdr *ifm;
212 int i;
213
214 if ((i = if_nametoindex(iface->name)) == -1)
215 return -1;
216 for (;;) {
217 bytes = recv(iface->link_fd, buffer, BUFFER_LEN, MSG_DONTWAIT);
218 if (bytes == -1) {
219 if (errno == EAGAIN)
220 return 0;
221 if (errno == EINTR)
222 continue;
223 return -1;
224 }
225 for (p = buffer; bytes > 0;
226 bytes -= ((struct rt_msghdr *)p)->rtm_msglen,
227 p += ((struct rt_msghdr *)p)->rtm_msglen)
228 {
229 rtm = (struct rt_msghdr *)p;
230 if (rtm->rtm_type != RTM_IFINFO)
231 continue;
232 ifm = (struct if_msghdr *)p;
233 if (ifm->ifm_index != i)
234 continue;
235
236 /* Link changed */
237 return 1;
238 }
239 }
240 return 0;
241}