1 1.5 plunky /* $NetBSD: tap.c,v 1.5 2009/05/12 21:21:23 plunky Exp $ */ 2 1.1 plunky 3 1.1 plunky /*- 4 1.1 plunky * Copyright (c) 2008 Iain Hibbert 5 1.1 plunky * All rights reserved. 6 1.1 plunky * 7 1.1 plunky * Redistribution and use in source and binary forms, with or without 8 1.1 plunky * modification, are permitted provided that the following conditions 9 1.1 plunky * are met: 10 1.1 plunky * 1. Redistributions of source code must retain the above copyright 11 1.1 plunky * notice, this list of conditions and the following disclaimer. 12 1.1 plunky * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 plunky * notice, this list of conditions and the following disclaimer in the 14 1.1 plunky * documentation and/or other materials provided with the distribution. 15 1.1 plunky * 16 1.1 plunky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 1.1 plunky * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 1.1 plunky * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 1.1 plunky * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 1.1 plunky * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 1.1 plunky * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 1.1 plunky * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 1.1 plunky * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 1.1 plunky * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 1.1 plunky * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 1.1 plunky */ 27 1.1 plunky 28 1.1 plunky #include <sys/cdefs.h> 29 1.5 plunky __RCSID("$NetBSD: tap.c,v 1.5 2009/05/12 21:21:23 plunky Exp $"); 30 1.1 plunky 31 1.1 plunky #include <sys/ioctl.h> 32 1.1 plunky #include <sys/uio.h> 33 1.1 plunky 34 1.1 plunky #include <net/if_dl.h> 35 1.1 plunky #include <net/if_tap.h> 36 1.1 plunky 37 1.1 plunky #include <fcntl.h> 38 1.1 plunky #include <unistd.h> 39 1.1 plunky #include <util.h> 40 1.1 plunky 41 1.1 plunky #include "btpand.h" 42 1.1 plunky 43 1.5 plunky static void tap_exit(void); 44 1.1 plunky static bool tap_send(channel_t *, packet_t *); 45 1.1 plunky static bool tap_recv(packet_t *); 46 1.4 plunky static void tap_down(channel_t *); 47 1.1 plunky 48 1.1 plunky void 49 1.1 plunky tap_init(void) 50 1.1 plunky { 51 1.1 plunky channel_t *chan; 52 1.1 plunky struct sockaddr_dl *sdl; 53 1.2 plunky struct if_laddrreq iflr; 54 1.1 plunky struct ifreq ifr; 55 1.1 plunky int fd, s; 56 1.1 plunky 57 1.1 plunky fd = open(interface_name, O_RDWR); 58 1.1 plunky if (fd == -1) { 59 1.1 plunky log_err("Could not open \"%s\": %m", interface_name); 60 1.1 plunky exit(EXIT_FAILURE); 61 1.1 plunky } 62 1.1 plunky 63 1.1 plunky memset(&ifr, 0, sizeof(ifr)); 64 1.1 plunky if (ioctl(fd, TAPGIFNAME, &ifr) == -1) { 65 1.1 plunky log_err("Could not get interface name: %m"); 66 1.1 plunky exit(EXIT_FAILURE); 67 1.1 plunky } 68 1.5 plunky interface_name = strndup(ifr.ifr_name, IFNAMSIZ); 69 1.5 plunky atexit(tap_exit); 70 1.1 plunky 71 1.1 plunky s = socket(PF_LINK, SOCK_DGRAM, 0); 72 1.1 plunky if (s == -1) { 73 1.1 plunky log_err("Could not open PF_LINK socket: %m"); 74 1.1 plunky exit(EXIT_FAILURE); 75 1.1 plunky } 76 1.1 plunky 77 1.2 plunky memset(&iflr, 0, sizeof(iflr)); 78 1.2 plunky memcpy(iflr.iflr_name, ifr.ifr_name, IFNAMSIZ); 79 1.2 plunky iflr.flags = IFLR_ACTIVE; 80 1.1 plunky 81 1.2 plunky sdl = satosdl(sstosa(&iflr.addr)); 82 1.1 plunky sdl->sdl_family = AF_LINK; 83 1.1 plunky sdl->sdl_len = sizeof(struct sockaddr_dl); 84 1.1 plunky sdl->sdl_alen = ETHER_ADDR_LEN; 85 1.1 plunky b2eaddr(LLADDR(sdl), &local_bdaddr); 86 1.1 plunky 87 1.2 plunky if (ioctl(s, SIOCALIFADDR, &iflr) == -1) { 88 1.2 plunky log_err("Could not add %s link address: %m", iflr.iflr_name); 89 1.1 plunky exit(EXIT_FAILURE); 90 1.1 plunky } 91 1.1 plunky 92 1.1 plunky if (ioctl(s, SIOCGIFFLAGS, &ifr) == -1) { 93 1.1 plunky log_err("Could not get interface flags: %m"); 94 1.1 plunky exit(EXIT_FAILURE); 95 1.1 plunky } 96 1.1 plunky 97 1.1 plunky if ((ifr.ifr_flags & IFF_UP) == 0) { 98 1.1 plunky ifr.ifr_flags |= IFF_UP; 99 1.1 plunky 100 1.1 plunky if (ioctl(s, SIOCSIFFLAGS, &ifr) == -1) { 101 1.1 plunky log_err("Could not set IFF_UP: %m"); 102 1.1 plunky exit(EXIT_FAILURE); 103 1.1 plunky } 104 1.1 plunky } 105 1.1 plunky 106 1.1 plunky close(s); 107 1.1 plunky 108 1.1 plunky log_info("Using interface %s with addr %s", 109 1.1 plunky ifr.ifr_name, ether_ntoa((struct ether_addr *)LLADDR(sdl))); 110 1.1 plunky 111 1.1 plunky chan = channel_alloc(); 112 1.1 plunky if (chan == NULL) 113 1.1 plunky exit(EXIT_FAILURE); 114 1.1 plunky 115 1.1 plunky chan->send = tap_send; 116 1.1 plunky chan->recv = tap_recv; 117 1.4 plunky chan->down = tap_down; 118 1.1 plunky chan->mru = ETHER_HDR_LEN + ETHER_MAX_LEN; 119 1.1 plunky memcpy(chan->raddr, LLADDR(sdl), ETHER_ADDR_LEN); 120 1.1 plunky memcpy(chan->laddr, LLADDR(sdl), ETHER_ADDR_LEN); 121 1.1 plunky chan->state = CHANNEL_OPEN; 122 1.1 plunky if (!channel_open(chan, fd)) 123 1.1 plunky exit(EXIT_FAILURE); 124 1.1 plunky 125 1.1 plunky if (pidfile(ifr.ifr_name) == -1) 126 1.1 plunky log_err("pidfile not made"); 127 1.1 plunky } 128 1.1 plunky 129 1.5 plunky static void 130 1.5 plunky tap_exit(void) 131 1.5 plunky { 132 1.5 plunky struct ifreq ifr; 133 1.5 plunky int s; 134 1.5 plunky 135 1.5 plunky s = socket(PF_LINK, SOCK_DGRAM, 0); 136 1.5 plunky if (s == -1) { 137 1.5 plunky log_err("Could not open PF_LINK socket: %m"); 138 1.5 plunky return; 139 1.5 plunky } 140 1.5 plunky 141 1.5 plunky strncpy(ifr.ifr_name, interface_name, IFNAMSIZ); 142 1.5 plunky if (ioctl(s, SIOCGIFFLAGS, &ifr) == -1) { 143 1.5 plunky log_err("Could not get interface flags: %m"); 144 1.5 plunky return; 145 1.5 plunky } 146 1.5 plunky 147 1.5 plunky if ((ifr.ifr_flags & IFF_UP)) { 148 1.5 plunky ifr.ifr_flags &= ~IFF_UP; 149 1.5 plunky if (ioctl(s, SIOCSIFFLAGS, &ifr) == -1) { 150 1.5 plunky log_err("Could not clear IFF_UP: %m"); 151 1.5 plunky return; 152 1.5 plunky } 153 1.5 plunky } 154 1.5 plunky 155 1.5 plunky close(s); 156 1.5 plunky } 157 1.5 plunky 158 1.1 plunky static bool 159 1.1 plunky tap_send(channel_t *chan, packet_t *pkt) 160 1.1 plunky { 161 1.1 plunky struct iovec iov[4]; 162 1.1 plunky ssize_t nw; 163 1.1 plunky 164 1.1 plunky iov[0].iov_base = pkt->dst; 165 1.1 plunky iov[0].iov_len = ETHER_ADDR_LEN; 166 1.1 plunky iov[1].iov_base = pkt->src; 167 1.1 plunky iov[1].iov_len = ETHER_ADDR_LEN; 168 1.1 plunky iov[2].iov_base = pkt->type; 169 1.1 plunky iov[2].iov_len = ETHER_TYPE_LEN; 170 1.1 plunky iov[3].iov_base = pkt->ptr; 171 1.1 plunky iov[3].iov_len = pkt->len; 172 1.1 plunky 173 1.1 plunky /* tap device write never fails */ 174 1.1 plunky nw = writev(chan->fd, iov, __arraycount(iov)); 175 1.3 plunky assert(nw > 0); 176 1.1 plunky 177 1.1 plunky return true; 178 1.1 plunky } 179 1.1 plunky 180 1.1 plunky static bool 181 1.1 plunky tap_recv(packet_t *pkt) 182 1.1 plunky { 183 1.1 plunky 184 1.1 plunky if (pkt->len < ETHER_HDR_LEN) 185 1.1 plunky return false; 186 1.1 plunky 187 1.1 plunky pkt->dst = pkt->ptr; 188 1.1 plunky packet_adj(pkt, ETHER_ADDR_LEN); 189 1.1 plunky pkt->src = pkt->ptr; 190 1.1 plunky packet_adj(pkt, ETHER_ADDR_LEN); 191 1.1 plunky pkt->type = pkt->ptr; 192 1.1 plunky packet_adj(pkt, ETHER_TYPE_LEN); 193 1.1 plunky 194 1.1 plunky return true; 195 1.1 plunky } 196 1.4 plunky 197 1.4 plunky static void 198 1.4 plunky tap_down(channel_t *chan) 199 1.4 plunky { 200 1.4 plunky 201 1.4 plunky /* we never close the tap channel */ 202 1.4 plunky } 203