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