1187938Semax/* $NetBSD: tap.c,v 1.1 2008/08/17 13:20:57 plunky Exp $ */ 2187938Semax 3187938Semax/*- 4187938Semax * Copyright (c) 2008 Iain Hibbert 5187938Semax * All rights reserved. 6187938Semax * 7187938Semax * Redistribution and use in source and binary forms, with or without 8187938Semax * modification, are permitted provided that the following conditions 9187938Semax * are met: 10187938Semax * 1. Redistributions of source code must retain the above copyright 11187938Semax * notice, this list of conditions and the following disclaimer. 12187938Semax * 2. Redistributions in binary form must reproduce the above copyright 13187938Semax * notice, this list of conditions and the following disclaimer in the 14187938Semax * documentation and/or other materials provided with the distribution. 15187938Semax * 16187938Semax * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17187938Semax * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18187938Semax * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19187938Semax * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20187938Semax * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21187938Semax * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22187938Semax * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23187938Semax * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24187938Semax * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25187938Semax * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26187938Semax */ 27187938Semax 28187938Semax/* $FreeBSD$ */ 29187938Semax 30187938Semax#include <sys/cdefs.h> 31187938Semax__RCSID("$NetBSD: tap.c,v 1.1 2008/08/17 13:20:57 plunky Exp $"); 32187938Semax 33187938Semax#include <sys/types.h> 34187938Semax#include <sys/param.h> 35187938Semax#include <sys/ioctl.h> 36187938Semax#include <sys/uio.h> 37187938Semax 38187938Semax#include <net/if_tap.h> 39187938Semax 40187938Semax#include <fcntl.h> 41187938Semax#include <libutil.h> 42187938Semax#include <paths.h> 43187938Semax#include <stdio.h> 44187938Semax#include <unistd.h> 45187938Semax 46187938Semax#include "btpand.h" 47187938Semax 48187938Semaxstatic bool tap_send(channel_t *, packet_t *); 49187938Semaxstatic bool tap_recv(packet_t *); 50187938Semax 51187938Semaxvoid 52187938Semaxtap_init(void) 53187938Semax{ 54187938Semax channel_t *chan; 55187938Semax struct ifreq ifr; 56187938Semax int fd, s; 57187938Semax char pidfile[PATH_MAX]; 58187938Semax 59187938Semax fd = open(interface_name, O_RDWR); 60187938Semax if (fd == -1) { 61187938Semax log_err("Could not open \"%s\": %m", interface_name); 62187938Semax exit(EXIT_FAILURE); 63187938Semax } 64187938Semax 65187938Semax memset(&ifr, 0, sizeof(ifr)); 66187938Semax if (ioctl(fd, TAPGIFNAME, &ifr) == -1) { 67187938Semax log_err("Could not get interface name: %m"); 68187938Semax exit(EXIT_FAILURE); 69187938Semax } 70187938Semax 71187938Semax s = socket(AF_INET, SOCK_DGRAM, 0); 72187938Semax if (s == -1) { 73187938Semax log_err("Could not open PF_LINK socket: %m"); 74187938Semax exit(EXIT_FAILURE); 75187938Semax } 76187938Semax 77187938Semax ifr.ifr_addr.sa_family = AF_LINK; 78187938Semax ifr.ifr_addr.sa_len = ETHER_ADDR_LEN; 79187938Semax b2eaddr(ifr.ifr_addr.sa_data, &local_bdaddr); 80187938Semax 81187938Semax if (ioctl(s, SIOCSIFLLADDR, &ifr) == -1) { 82187938Semax log_err("Could not set %s physical address: %m", ifr.ifr_name); 83187938Semax exit(EXIT_FAILURE); 84187938Semax } 85187938Semax 86187938Semax if (ioctl(s, SIOCGIFFLAGS, &ifr) == -1) { 87187938Semax log_err("Could not get interface flags: %m"); 88187938Semax exit(EXIT_FAILURE); 89187938Semax } 90187938Semax 91187938Semax if ((ifr.ifr_flags & IFF_UP) == 0) { 92187938Semax ifr.ifr_flags |= IFF_UP; 93187938Semax 94187938Semax if (ioctl(s, SIOCSIFFLAGS, &ifr) == -1) { 95187938Semax log_err("Could not set IFF_UP: %m"); 96187938Semax exit(EXIT_FAILURE); 97187938Semax } 98187938Semax } 99187938Semax 100187938Semax close(s); 101187938Semax 102187938Semax log_info("Using interface %s with addr %s", ifr.ifr_name, 103187938Semax ether_ntoa((struct ether_addr *)&ifr.ifr_addr.sa_data)); 104187938Semax 105187938Semax chan = channel_alloc(); 106187938Semax if (chan == NULL) 107187938Semax exit(EXIT_FAILURE); 108187938Semax 109187938Semax chan->send = tap_send; 110187938Semax chan->recv = tap_recv; 111187938Semax chan->mru = ETHER_HDR_LEN + ETHER_MAX_LEN; 112187938Semax memcpy(chan->raddr, ifr.ifr_addr.sa_data, ETHER_ADDR_LEN); 113187938Semax memcpy(chan->laddr, ifr.ifr_addr.sa_data, ETHER_ADDR_LEN); 114187938Semax chan->state = CHANNEL_OPEN; 115187938Semax if (!channel_open(chan, fd)) 116187938Semax exit(EXIT_FAILURE); 117187938Semax 118187938Semax snprintf(pidfile, sizeof(pidfile), "%s/%s.pid", 119187938Semax _PATH_VARRUN, ifr.ifr_name); 120187938Semax chan->pfh = pidfile_open(pidfile, 0600, NULL); 121187938Semax if (chan->pfh == NULL) 122187938Semax log_err("can't create pidfile"); 123187938Semax else if (pidfile_write(chan->pfh) < 0) { 124187938Semax log_err("can't write pidfile"); 125187938Semax pidfile_remove(chan->pfh); 126187938Semax chan->pfh = NULL; 127187938Semax } 128187938Semax} 129187938Semax 130187938Semaxstatic bool 131187938Semaxtap_send(channel_t *chan, packet_t *pkt) 132187938Semax{ 133187938Semax struct iovec iov[4]; 134187938Semax ssize_t nw; 135187938Semax 136187938Semax iov[0].iov_base = pkt->dst; 137187938Semax iov[0].iov_len = ETHER_ADDR_LEN; 138187938Semax iov[1].iov_base = pkt->src; 139187938Semax iov[1].iov_len = ETHER_ADDR_LEN; 140187938Semax iov[2].iov_base = pkt->type; 141187938Semax iov[2].iov_len = ETHER_TYPE_LEN; 142187938Semax iov[3].iov_base = pkt->ptr; 143187938Semax iov[3].iov_len = pkt->len; 144187938Semax 145187938Semax /* tap device write never fails */ 146187938Semax nw = writev(chan->fd, iov, __arraycount(iov)); 147187938Semax assert(nw > 0); 148187938Semax 149187938Semax return true; 150187938Semax} 151187938Semax 152187938Semaxstatic bool 153187938Semaxtap_recv(packet_t *pkt) 154187938Semax{ 155187938Semax 156187938Semax if (pkt->len < ETHER_HDR_LEN) 157187938Semax return false; 158187938Semax 159187938Semax pkt->dst = pkt->ptr; 160187938Semax packet_adj(pkt, ETHER_ADDR_LEN); 161187938Semax pkt->src = pkt->ptr; 162187938Semax packet_adj(pkt, ETHER_ADDR_LEN); 163187938Semax pkt->type = pkt->ptr; 164187938Semax packet_adj(pkt, ETHER_TYPE_LEN); 165187938Semax 166187938Semax return true; 167187938Semax} 168