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