main.c revision 1.3 1 1.3 joerg /* $NetBSD: main.c,v 1.3 2011/09/16 15:39:28 joerg Exp $ */
2 1.1 pooka
3 1.1 pooka /*-
4 1.1 pooka * Copyright (c) 2011 Antti Kantee. All Rights Reserved.
5 1.1 pooka *
6 1.1 pooka * Redistribution and use in source and binary forms, with or without
7 1.1 pooka * modification, are permitted provided that the following conditions
8 1.1 pooka * are met:
9 1.1 pooka * 1. Redistributions of source code must retain the above copyright
10 1.1 pooka * notice, this list of conditions and the following disclaimer.
11 1.1 pooka * 2. Redistributions in binary form must reproduce the above copyright
12 1.1 pooka * notice, this list of conditions and the following disclaimer in the
13 1.1 pooka * documentation and/or other materials provided with the distribution.
14 1.1 pooka *
15 1.1 pooka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 1.1 pooka * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 1.1 pooka * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 1.1 pooka * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 1.1 pooka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 1.1 pooka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 1.1 pooka * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 1.1 pooka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 1.1 pooka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 1.1 pooka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 1.1 pooka * SUCH DAMAGE.
26 1.1 pooka */
27 1.1 pooka
28 1.1 pooka #include <sys/types.h>
29 1.1 pooka #include <sys/ioctl.h>
30 1.1 pooka #include <sys/socket.h>
31 1.1 pooka #include <sys/sysctl.h>
32 1.1 pooka
33 1.1 pooka #include <net/if.h>
34 1.1 pooka #include <net/if_dl.h>
35 1.1 pooka
36 1.1 pooka #include <err.h>
37 1.1 pooka #include <errno.h>
38 1.1 pooka #include <poll.h>
39 1.1 pooka #include <stdlib.h>
40 1.1 pooka #include <string.h>
41 1.1 pooka
42 1.1 pooka #include <rump/rump_syscalls.h>
43 1.1 pooka #include <rump/rumpclient.h>
44 1.1 pooka
45 1.1 pooka #include "configure.h"
46 1.1 pooka #include "dhcp.h"
47 1.1 pooka #include "net.h"
48 1.1 pooka
49 1.1 pooka struct interface *ifaces;
50 1.1 pooka
51 1.3 joerg __dead static void
52 1.1 pooka usage(void)
53 1.1 pooka {
54 1.1 pooka
55 1.1 pooka fprintf(stderr, "usage: %s ifname\n", getprogname());
56 1.1 pooka exit(1);
57 1.1 pooka }
58 1.1 pooka
59 1.1 pooka int
60 1.1 pooka get_hwaddr(struct interface *ifp)
61 1.1 pooka {
62 1.1 pooka struct if_laddrreq iflr;
63 1.1 pooka struct sockaddr_dl *sdl;
64 1.1 pooka int s, sverrno;
65 1.1 pooka
66 1.1 pooka memset(&iflr, 0, sizeof(iflr));
67 1.1 pooka strlcpy(iflr.iflr_name, ifp->name, sizeof(iflr.iflr_name));
68 1.1 pooka iflr.addr.ss_family = AF_LINK;
69 1.1 pooka
70 1.1 pooka sdl = satosdl(&iflr.addr);
71 1.1 pooka sdl->sdl_alen = ETHER_ADDR_LEN;
72 1.1 pooka
73 1.1 pooka if ((s = rump_sys_socket(AF_LINK, SOCK_DGRAM, 0)) == -1)
74 1.1 pooka return -1;
75 1.1 pooka
76 1.1 pooka if (rump_sys_ioctl(s, SIOCGLIFADDR, &iflr) == -1) {
77 1.1 pooka sverrno = errno;
78 1.1 pooka rump_sys_close(s);
79 1.1 pooka errno = sverrno;
80 1.1 pooka return -1;
81 1.1 pooka }
82 1.1 pooka
83 1.1 pooka /* XXX: is that the right way to copy the link address? */
84 1.1 pooka memcpy(ifp->hwaddr, sdl->sdl_data+strlen(ifp->name), ETHER_ADDR_LEN);
85 1.1 pooka ifp->hwlen = ETHER_ADDR_LEN;
86 1.1 pooka ifp->family = ARPHRD_ETHER;
87 1.1 pooka
88 1.1 pooka rump_sys_close(s);
89 1.1 pooka return 0;
90 1.1 pooka }
91 1.1 pooka
92 1.1 pooka static void
93 1.1 pooka send_discover(struct interface *ifp)
94 1.1 pooka {
95 1.1 pooka struct dhcp_message *dhcp;
96 1.1 pooka uint8_t *udp;
97 1.1 pooka ssize_t mlen, ulen;
98 1.1 pooka struct in_addr ia;
99 1.1 pooka
100 1.1 pooka memset(&ia, 0, sizeof(ia));
101 1.1 pooka
102 1.1 pooka mlen = make_message(&dhcp, ifp, DHCP_DISCOVER);
103 1.1 pooka ulen = make_udp_packet(&udp, (void *)dhcp, mlen, ia, ia);
104 1.1 pooka if (send_raw_packet(ifp, ETHERTYPE_IP, udp, ulen) == -1)
105 1.1 pooka err(1, "sending discover failed");
106 1.1 pooka }
107 1.1 pooka
108 1.1 pooka static void
109 1.1 pooka send_request(struct interface *ifp)
110 1.1 pooka {
111 1.1 pooka struct dhcp_message *dhcp;
112 1.1 pooka uint8_t *udp;
113 1.1 pooka ssize_t mlen, ulen;
114 1.1 pooka struct in_addr ia;
115 1.1 pooka
116 1.1 pooka memset(&ia, 0, sizeof(ia));
117 1.1 pooka
118 1.1 pooka mlen = make_message(&dhcp, ifp, DHCP_REQUEST);
119 1.1 pooka ulen = make_udp_packet(&udp, (void *)dhcp, mlen, ia, ia);
120 1.1 pooka if (send_raw_packet(ifp, ETHERTYPE_IP, udp, ulen) == -1)
121 1.1 pooka err(1, "sending discover failed");
122 1.1 pooka }
123 1.1 pooka
124 1.1 pooka /* wait for 5s by default */
125 1.1 pooka #define RESPWAIT 5000
126 1.1 pooka static void
127 1.1 pooka get_network(struct interface *ifp, uint8_t **rawp,
128 1.1 pooka const struct dhcp_message **dhcpp)
129 1.1 pooka {
130 1.1 pooka struct pollfd pfd;
131 1.1 pooka const struct dhcp_message *dhcp;
132 1.1 pooka const uint8_t *data;
133 1.1 pooka uint8_t *raw;
134 1.1 pooka ssize_t n;
135 1.1 pooka
136 1.1 pooka pfd.fd = ifp->raw_fd;
137 1.1 pooka pfd.events = POLLIN;
138 1.1 pooka
139 1.1 pooka raw = xmalloc(udp_dhcp_len);
140 1.1 pooka for (;;) {
141 1.1 pooka switch (rump_sys_poll(&pfd, 1, RESPWAIT)) {
142 1.1 pooka case 0:
143 1.1 pooka errx(1, "timed out waiting for response");
144 1.1 pooka case -1:
145 1.1 pooka err(1, "poll failed");
146 1.1 pooka default:
147 1.1 pooka break;
148 1.1 pooka }
149 1.1 pooka
150 1.1 pooka if ((n = get_raw_packet(ifp, ETHERTYPE_IP,
151 1.1 pooka raw, udp_dhcp_len)) < 1)
152 1.1 pooka continue;
153 1.1 pooka
154 1.1 pooka if (valid_udp_packet(raw, n, NULL) == -1) {
155 1.1 pooka fprintf(stderr, "invalid packet received. retrying\n");
156 1.1 pooka continue;
157 1.1 pooka }
158 1.1 pooka
159 1.1 pooka n = get_udp_data(&data, raw);
160 1.1 pooka if ((size_t)n > sizeof(*dhcp)) {
161 1.1 pooka fprintf(stderr, "invalid packet size. retrying\n");
162 1.1 pooka continue;
163 1.1 pooka }
164 1.1 pooka dhcp = (const void *)data;
165 1.1 pooka
166 1.1 pooka /* XXX: what if packet is too small? */
167 1.1 pooka
168 1.1 pooka /* some sanity checks */
169 1.1 pooka if (dhcp->cookie != htonl(MAGIC_COOKIE)) {
170 1.1 pooka /* ignore */
171 1.1 pooka continue;
172 1.1 pooka }
173 1.1 pooka
174 1.1 pooka if (ifp->state->xid != dhcp->xid) {
175 1.1 pooka fprintf(stderr, "invalid transaction. retrying\n");
176 1.1 pooka continue;
177 1.1 pooka }
178 1.1 pooka
179 1.1 pooka break;
180 1.1 pooka }
181 1.1 pooka
182 1.1 pooka *rawp = raw;
183 1.1 pooka *dhcpp = dhcp;
184 1.1 pooka }
185 1.1 pooka
186 1.1 pooka static void
187 1.1 pooka get_offer(struct interface *ifp)
188 1.1 pooka {
189 1.1 pooka const struct dhcp_message *dhcp;
190 1.1 pooka uint8_t *raw;
191 1.1 pooka uint8_t type;
192 1.1 pooka
193 1.1 pooka get_network(ifp, &raw, &dhcp);
194 1.1 pooka
195 1.1 pooka get_option_uint8(&type, dhcp, DHO_MESSAGETYPE);
196 1.1 pooka switch (type) {
197 1.1 pooka case DHCP_OFFER:
198 1.1 pooka break;
199 1.1 pooka case DHCP_NAK:
200 1.1 pooka errx(1, "got NAK from dhcp server");
201 1.1 pooka default:
202 1.1 pooka errx(1, "didn't receive offer");
203 1.1 pooka }
204 1.1 pooka
205 1.1 pooka ifp->state->offer = xzalloc(sizeof(*ifp->state->offer));
206 1.1 pooka memcpy(ifp->state->offer, dhcp, sizeof(*ifp->state->offer));
207 1.2 pooka ifp->state->lease.addr.s_addr = dhcp->yiaddr;
208 1.2 pooka ifp->state->lease.cookie = dhcp->cookie;
209 1.1 pooka free(raw);
210 1.1 pooka }
211 1.1 pooka
212 1.1 pooka static void
213 1.1 pooka get_ack(struct interface *ifp)
214 1.1 pooka {
215 1.1 pooka const struct dhcp_message *dhcp;
216 1.1 pooka uint8_t *raw;
217 1.1 pooka uint8_t type;
218 1.1 pooka
219 1.1 pooka get_network(ifp, &raw, &dhcp);
220 1.1 pooka get_option_uint8(&type, dhcp, DHO_MESSAGETYPE);
221 1.1 pooka if (type != DHCP_ACK)
222 1.1 pooka errx(1, "didn't receive ack");
223 1.1 pooka
224 1.1 pooka ifp->state->new = ifp->state->offer;
225 1.1 pooka get_lease(&ifp->state->lease, ifp->state->new);
226 1.1 pooka }
227 1.1 pooka
228 1.1 pooka int
229 1.1 pooka main(int argc, char *argv[])
230 1.1 pooka {
231 1.1 pooka struct interface *ifp;
232 1.1 pooka struct if_options *ifo;
233 1.1 pooka const int mib[] = { CTL_KERN, KERN_HOSTNAME };
234 1.1 pooka size_t hlen;
235 1.1 pooka
236 1.1 pooka setprogname(argv[0]);
237 1.1 pooka if (argc != 2)
238 1.1 pooka usage();
239 1.1 pooka
240 1.1 pooka if (rumpclient_init() == -1)
241 1.1 pooka err(1, "init failed");
242 1.1 pooka
243 1.1 pooka if (init_sockets() == -1)
244 1.1 pooka err(1, "failed to init sockets");
245 1.1 pooka if ((ifp = init_interface(argv[1])) == NULL)
246 1.1 pooka err(1, "cannot init %s\n", argv[1]);
247 1.1 pooka ifaces = ifp;
248 1.1 pooka if (open_socket(ifp, ETHERTYPE_IP) == -1)
249 1.1 pooka err(1, "bpf");
250 1.1 pooka up_interface(ifp);
251 1.1 pooka
252 1.1 pooka ifp->state = xzalloc(sizeof(*ifp->state));
253 1.1 pooka ifp->state->options = ifo = xzalloc(sizeof(*ifp->state->options));
254 1.1 pooka ifp->state->xid = arc4random();
255 1.1 pooka
256 1.1 pooka hlen = sizeof(ifo->hostname);
257 1.1 pooka if (rump_sys___sysctl(mib, __arraycount(mib), ifo->hostname, &hlen,
258 1.1 pooka NULL, 0) == -1)
259 1.1 pooka snprintf(ifo->hostname, sizeof(ifo->hostname),
260 1.1 pooka "unknown.hostname");
261 1.1 pooka ifo->options = DHCPCD_GATEWAY | DHCPCD_HOSTNAME;
262 1.1 pooka
263 1.1 pooka if (get_hwaddr(ifp) == -1)
264 1.1 pooka err(1, "failed to get hwaddr for %s", ifp->name);
265 1.1 pooka
266 1.1 pooka send_discover(ifp);
267 1.1 pooka get_offer(ifp);
268 1.1 pooka send_request(ifp);
269 1.1 pooka get_ack(ifp);
270 1.1 pooka
271 1.1 pooka configure(ifp);
272 1.1 pooka
273 1.1 pooka return 0;
274 1.1 pooka }
275