1 /* $NetBSD: tap.c,v 1.4 2009/05/12 21:08:30 plunky Exp $ */
4 * Copyright (c) 2008 Iain Hibbert
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include <sys/cdefs.h>
29 __RCSID("$NetBSD: tap.c,v 1.4 2009/05/12 21:08:30 plunky Exp $");
31 #include <sys/ioctl.h>
34 #include <net/if_dl.h>
35 #include <net/if_tap.h>
43 static void tap_exit(void);
44 static bool tap_send(channel_t
*, packet_t
*);
45 static bool tap_recv(packet_t
*);
46 static void tap_down(channel_t
*);
52 struct sockaddr_dl
*sdl
;
53 struct if_laddrreq iflr
;
57 fd
= open(interface_name
, O_RDWR
);
59 log_err("Could not open \"%s\": %m", interface_name
);
63 memset(&ifr
, 0, sizeof(ifr
));
64 if (ioctl(fd
, TAPGIFNAME
, &ifr
) == -1) {
65 log_err("Could not get interface name: %m");
68 interface_name
= strndup(ifr
.ifr_name
, IFNAMSIZ
);
71 s
= socket(PF_LINK
, SOCK_DGRAM
, 0);
73 log_err("Could not open PF_LINK socket: %m");
77 memset(&iflr
, 0, sizeof(iflr
));
78 memcpy(iflr
.iflr_name
, ifr
.ifr_name
, IFNAMSIZ
);
79 iflr
.flags
= IFLR_ACTIVE
;
81 sdl
= satosdl(sstosa(&iflr
.addr
));
82 sdl
->sdl_family
= AF_LINK
;
83 sdl
->sdl_len
= sizeof(struct sockaddr_dl
);
84 sdl
->sdl_alen
= ETHER_ADDR_LEN
;
85 b2eaddr(LLADDR(sdl
), &local_bdaddr
);
87 if (ioctl(s
, SIOCALIFADDR
, &iflr
) == -1) {
88 log_err("Could not add %s link address: %m", iflr
.iflr_name
);
92 if (ioctl(s
, SIOCGIFFLAGS
, &ifr
) == -1) {
93 log_err("Could not get interface flags: %m");
97 if ((ifr
.ifr_flags
& IFF_UP
) == 0) {
98 ifr
.ifr_flags
|= IFF_UP
;
100 if (ioctl(s
, SIOCSIFFLAGS
, &ifr
) == -1) {
101 log_err("Could not set IFF_UP: %m");
108 log_info("Using interface %s with addr %s",
109 ifr
.ifr_name
, ether_ntoa((struct ether_addr
*)LLADDR(sdl
)));
111 chan
= channel_alloc();
115 chan
->send
= tap_send
;
116 chan
->recv
= tap_recv
;
117 chan
->down
= tap_down
;
118 chan
->mru
= ETHER_HDR_LEN
+ ETHER_MAX_LEN
;
119 memcpy(chan
->raddr
, LLADDR(sdl
), ETHER_ADDR_LEN
);
120 memcpy(chan
->laddr
, LLADDR(sdl
), ETHER_ADDR_LEN
);
121 chan
->state
= CHANNEL_OPEN
;
122 if (!channel_open(chan
, fd
))
125 if (pidfile(ifr
.ifr_name
) == -1)
126 log_err("pidfile not made");
135 s
= socket(PF_LINK
, SOCK_DGRAM
, 0);
137 log_err("Could not open PF_LINK socket: %m");
141 strncpy(ifr
.ifr_name
, interface_name
, IFNAMSIZ
);
142 if (ioctl(s
, SIOCGIFFLAGS
, &ifr
) == -1) {
143 log_err("Could not get interface flags: %m");
147 if ((ifr
.ifr_flags
& IFF_UP
)) {
148 ifr
.ifr_flags
&= ~IFF_UP
;
149 if (ioctl(s
, SIOCSIFFLAGS
, &ifr
) == -1) {
150 log_err("Could not clear IFF_UP: %m");
159 tap_send(channel_t
*chan
, packet_t
*pkt
)
164 iov
[0].iov_base
= pkt
->dst
;
165 iov
[0].iov_len
= ETHER_ADDR_LEN
;
166 iov
[1].iov_base
= pkt
->src
;
167 iov
[1].iov_len
= ETHER_ADDR_LEN
;
168 iov
[2].iov_base
= pkt
->type
;
169 iov
[2].iov_len
= ETHER_TYPE_LEN
;
170 iov
[3].iov_base
= pkt
->ptr
;
171 iov
[3].iov_len
= pkt
->len
;
173 /* tap device write never fails */
174 nw
= writev(chan
->fd
, iov
, __arraycount(iov
));
181 tap_recv(packet_t
*pkt
)
184 if (pkt
->len
< ETHER_HDR_LEN
)
188 packet_adj(pkt
, ETHER_ADDR_LEN
);
190 packet_adj(pkt
, ETHER_ADDR_LEN
);
191 pkt
->type
= pkt
->ptr
;
192 packet_adj(pkt
, ETHER_TYPE_LEN
);
198 tap_down(channel_t
*chan
)
201 /* we never close the tap channel */