1 1.4 christos /* $NetBSD: main.c,v 1.4 2015/06/16 22:54:10 christos 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.4 christos 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.4 christos err(EXIT_FAILURE, "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.4 christos err(EXIT_FAILURE, "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.4 christos errx(EXIT_FAILURE, "timed out waiting for response"); 144 1.1 pooka case -1: 145 1.4 christos err(EXIT_FAILURE, "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.4 christos errx(EXIT_FAILURE, "got NAK from dhcp server"); 201 1.1 pooka default: 202 1.4 christos errx(EXIT_FAILURE, "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.4 christos errx(EXIT_FAILURE, "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.4 christos err(EXIT_FAILURE, "init failed"); 242 1.1 pooka 243 1.1 pooka if (init_sockets() == -1) 244 1.4 christos err(EXIT_FAILURE, "failed to init sockets"); 245 1.1 pooka if ((ifp = init_interface(argv[1])) == NULL) 246 1.4 christos err(EXIT_FAILURE, "cannot init %s", argv[1]); 247 1.1 pooka ifaces = ifp; 248 1.1 pooka if (open_socket(ifp, ETHERTYPE_IP) == -1) 249 1.4 christos err(EXIT_FAILURE, "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.4 christos err(EXIT_FAILURE, "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