diff options
Diffstat (limited to 'tap-mac/tuntap/src/tuntap.cc')
-rw-r--r-- | tap-mac/tuntap/src/tuntap.cc | 962 |
1 files changed, 962 insertions, 0 deletions
diff --git a/tap-mac/tuntap/src/tuntap.cc b/tap-mac/tuntap/src/tuntap.cc new file mode 100644 index 00000000..941de94c --- /dev/null +++ b/tap-mac/tuntap/src/tuntap.cc @@ -0,0 +1,962 @@ +/* + * ip tunnel/ethertap device for MacOSX. Common functionality of tap_interface and tun_interface. + * + * tuntap_interface class definition + */ +/* + * Copyright (c) 2011 Mattias Nissler <mattias.nissler@gmx.de> + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided + * with the distribution. + * 3. The name of the author may not be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "tuntap.h" + +#if 0 +#define dprintf(...) log(LOG_INFO, __VA_ARGS__) +#else +#define dprintf(...) +#endif + +extern "C" { + +#include <sys/conf.h> +#include <sys/syslog.h> +#include <sys/param.h> +#include <sys/filio.h> +#include <sys/sockio.h> +#include <sys/fcntl.h> +#include <sys/kpi_socket.h> + +#include <vm/vm_kern.h> + +#include <net/if_types.h> +#include <net/if_var.h> +#include <net/if_dl.h> +#include <net/if_arp.h> + +#include <miscfs/devfs/devfs.h> + +} + +extern "C" { + +/* interface service functions that delegate to the appropriate tuntap_interface instance */ +errno_t +tuntap_if_output(ifnet_t ifp, mbuf_t m) +{ + if (ifp != NULL) { + tuntap_interface *ttif = (tuntap_interface *) ifnet_softc(ifp); + if (ttif != NULL) + return ttif->if_output(m); + } + + if (m != NULL) + mbuf_freem_list(m); + + return ENODEV; +} + +errno_t +tuntap_if_ioctl(ifnet_t ifp, long unsigned int cmd, void *arg) +{ + if (ifp != NULL) { + tuntap_interface *ttif = (tuntap_interface *) ifnet_softc(ifp); + if (ttif != NULL) + return ttif->if_ioctl(cmd, arg); + } + + return ENODEV; +} + +errno_t +tuntap_if_set_bpf_tap(ifnet_t ifp, bpf_tap_mode mode, int (*cb)(ifnet_t, mbuf_t)) +{ + if (ifp != NULL) { + tuntap_interface *ttif = (tuntap_interface *) ifnet_softc(ifp); + if (ttif != NULL) + return ttif->if_set_bpf_tap(mode, cb); + } + + return ENODEV; +} + +errno_t +tuntap_if_demux(ifnet_t ifp, mbuf_t m, char *header, protocol_family_t *proto) +{ + if (ifp != NULL) { + tuntap_interface *ttif = (tuntap_interface *) ifnet_softc(ifp); + if (ttif != NULL) + return ttif->if_demux(m, header, proto); + } + + return ENODEV; +} + +errno_t +tuntap_if_framer(ifnet_t ifp, mbuf_t *m, const struct sockaddr *dest, const char *dest_linkaddr, + const char *frame_type) +{ + if (ifp != NULL) { + tuntap_interface *ttif = (tuntap_interface *) ifnet_softc(ifp); + if (ttif != NULL) + return ttif->if_framer(m, dest, dest_linkaddr, frame_type); + } + + return ENODEV; +} + +errno_t +tuntap_if_add_proto(ifnet_t ifp, protocol_family_t proto, const struct ifnet_demux_desc *ddesc, + u_int32_t ndesc) +{ + if (ifp != NULL) { + tuntap_interface *ttif = (tuntap_interface *) ifnet_softc(ifp); + if (ttif != NULL) + return ttif->if_add_proto(proto, ddesc, ndesc); + } + + return ENODEV; +} + +errno_t +tuntap_if_del_proto(ifnet_t ifp, protocol_family_t proto) +{ + if (ifp != NULL) { + tuntap_interface *ttif = (tuntap_interface *) ifnet_softc(ifp); + if (ttif != NULL) + return ttif->if_del_proto(proto); + } + + return ENODEV; +} + +errno_t +tuntap_if_check_multi(ifnet_t ifp, const struct sockaddr* maddr) +{ + if (ifp != NULL) + { + tuntap_interface *ttif = (tuntap_interface *) ifnet_softc(ifp); + if (ttif != NULL) + return ttif->if_check_multi(maddr); + } + + return ENODEV; +} + +void +tuntap_if_detached(ifnet_t ifp) +{ + if (ifp != NULL) { + tuntap_interface *ttif = (tuntap_interface *) ifnet_softc(ifp); + if (ttif != NULL) + ttif->if_detached(); + } +} + +errno_t +tuntap_if_noop_output(ifnet_t, mbuf_t) +{ + return ENODEV; +} + +errno_t +tuntap_if_noop_demux(ifnet_t, mbuf_t, char*, protocol_family_t*) +{ + return ENODEV; +} + +errno_t +tuntap_if_noop_add_proto(ifnet_t, protocol_family_t, const struct ifnet_demux_desc*, u_int32_t) +{ + return ENODEV; +} + +errno_t +tuntap_if_noop_del_proto(ifnet_t, protocol_family_t) +{ + return ENODEV; +} + +} /* extern "C" */ + +/* tuntap_mbuf_queue */ +tuntap_mbuf_queue::tuntap_mbuf_queue() +{ + head = tail = NULL; + size = 0; +} + +tuntap_mbuf_queue::~tuntap_mbuf_queue() +{ + clear(); +} + +bool +tuntap_mbuf_queue::enqueue(mbuf_t mb) +{ + if (size == QUEUE_SIZE) + return false; + + mbuf_setnextpkt(mb, NULL); + + if (head == NULL) + head = tail = mb; + else { + mbuf_setnextpkt(tail, mb); + tail = mb; + } + size++; + + return true; +} + +mbuf_t +tuntap_mbuf_queue::dequeue() +{ + mbuf_t ret; + + /* check wether there is a packet in the queue */ + if (head == NULL) + return NULL; + + /* fetch it */ + ret = head; + head = mbuf_nextpkt(head); + mbuf_setnextpkt(ret, NULL); + size--; + + return ret; +} + +void +tuntap_mbuf_queue::clear() +{ + /* free mbufs that are in the queue */ + if (head != NULL) + mbuf_freem_list(head); + + head = NULL; + tail = NULL; + size = 0; +} + +/* tuntap_interface members */ +tuntap_interface::tuntap_interface() +{ + /* initialize the members */ + ifp = NULL; + open = false; + block_io = true; + dev_handle = NULL; + pid = 0; + selthreadclear(&rsel); + bpf_mode = BPF_MODE_DISABLED; + bpf_callback = NULL; + bzero(unique_id, UIDLEN); + in_ioctl = false; +} + +tuntap_interface::~tuntap_interface() +{ +} + +bool +tuntap_interface::register_chardev(unsigned short major) +{ + /* register character device */ + dev_handle = devfs_make_node(makedev(major, unit), DEVFS_CHAR, 0, 0, 0660, "%s%d", + family_name, (int) unit); + + if (dev_handle == NULL) { + log(LOG_ERR, "tuntap: could not make /dev/%s%d\n", family_name, (int) unit); + return false; + } + + return true; +} + +void +tuntap_interface::unregister_chardev() +{ + dprintf("unregistering character device\n"); + + /* unregister character device */ + if (dev_handle != NULL) + devfs_remove(dev_handle); + dev_handle = NULL; +} + +bool +tuntap_interface::register_interface(const struct sockaddr_dl* lladdr, void *bcaddr, + u_int32_t bcaddrlen) +{ + struct ifnet_init_params ip; + errno_t err; + + dprintf("register_interface\n"); + + /* initialize an initialization info struct */ + ip.uniqueid_len = UIDLEN; + ip.uniqueid = unique_id; + ip.name = family_name; + ip.unit = unit; + ip.family = family; + ip.type = type; + ip.output = tuntap_if_output; + ip.demux = tuntap_if_demux; + ip.add_proto = tuntap_if_add_proto; + ip.del_proto = tuntap_if_del_proto; + ip.check_multi = tuntap_if_check_multi; + ip.framer = tuntap_if_framer; + ip.softc = this; + ip.ioctl = tuntap_if_ioctl; + ip.set_bpf_tap = tuntap_if_set_bpf_tap; + ip.detach = tuntap_if_detached; + ip.event = NULL; + ip.broadcast_addr = bcaddr; + ip.broadcast_len = bcaddrlen; + + dprintf("tuntap: tuntap_if_check_multi is at 0x%08x\n", (void*) tuntap_if_check_multi); + + /* allocate the interface */ + err = ifnet_allocate(&ip, &ifp); + if (err) { + log(LOG_ERR, "tuntap: could not allocate interface for %s%d: %d\n", family_name, + (int) unit, err); + ifp = NULL; + return false; + } + + /* activate the interface */ + err = ifnet_attach(ifp, lladdr); + if (err) { + log(LOG_ERR, "tuntap: could not attach interface %s%d: %d\n", family_name, + (int) unit, err); + ifnet_release(ifp); + ifp = NULL; + return false; + } + + dprintf("setting interface flags\n"); + + /* set interface flags */ + ifnet_set_flags(ifp, IFF_RUNNING | IFF_MULTICAST | IFF_SIMPLEX, (u_int16_t) ~0UL); + + dprintf("flags: %x\n", ifnet_flags(ifp)); + + return true; +} + +void +tuntap_interface::unregister_interface() +{ + errno_t err; + + dprintf("unregistering network interface\n"); + + if (ifp != NULL) { + interface_detached = false; + + /* detach interface */ + err = ifnet_detach(ifp); + if (err) + log(LOG_ERR, "tuntap: error detaching interface %s%d: %d\n", + family_name, unit, err); + + dprintf("interface detaching\n"); + + /* Wait until the interface has completely been detached. */ + detach_lock.lock(); + while (!interface_detached) + detach_lock.sleep(&interface_detached); + detach_lock.unlock(); + + dprintf("interface detached\n"); + + /* release the interface */ + ifnet_release(ifp); + + ifp = NULL; + } + + dprintf("network interface unregistered\n"); +} + +void +tuntap_interface::cleanup_interface() +{ + errno_t err; + ifaddr_t *addrs; + ifaddr_t *a; + struct ifreq ifr; + + /* mark the interface down */ + ifnet_set_flags(ifp, 0, IFF_UP | IFF_RUNNING); + + /* Unregister all interface addresses. This works around a deficiency in the Darwin kernel. + * If we don't remove all IP addresses that are attached to the interface it can happen that + * the IP code fails to clean them up itself. When the interface is recycled, the IP code + * might then think some addresses are still attached to the interface... + */ + + err = ifnet_get_address_list(ifp, &addrs); + if (!err) { + + /* Execute a SIOCDIFADDR ioctl for each address. For technical reasons, we can only + * do that with a socket of the appropriate family. So try to create a dummy socket. + * I know this is a little expensive, but better than crashing... + * + * This really sucks. + */ + for (a = addrs; *a != NULL; a++) { + /* initialize the request parameters */ + snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", + ifnet_name(ifp), ifnet_unit(ifp)); + ifaddr_address(*a, &(ifr.ifr_addr), sizeof(ifr.ifr_addr)); + if (ifr.ifr_addr.sa_family != AF_INET) + continue; + + dprintf("trying to delete address of family %d\n", ifr.ifr_addr.sa_family); + + do_sock_ioctl(ifr.ifr_addr.sa_family, SIOCDIFADDR, &ifr); + } + + /* release the address list */ + ifnet_free_address_list(addrs); + } +} + +bool +tuntap_interface::idle() +{ + return !(open); +} + +void +tuntap_interface::notify_bpf(mbuf_t mb, bool out) +{ + auto_lock l(&bpf_lock); + + if ((out && bpf_mode == BPF_MODE_OUTPUT) + || (!out && bpf_mode == BPF_MODE_INPUT) + || (bpf_mode == BPF_MODE_INPUT_OUTPUT)) + (*bpf_callback)(ifp, mb); +} + +void +tuntap_interface::do_sock_ioctl(sa_family_t af, unsigned long cmd, void* arg) { + if (in_ioctl) { + log(LOG_ERR, "tuntap: ioctl recursion detected, aborting.\n"); + return; + } + + socket_t sock; + errno_t err = sock_socket(af, SOCK_RAW, 0, NULL, NULL, &sock); + if (err) { + log(LOG_ERR, "tuntap: failed to create socket: %d\n", err); + return; + } + + in_ioctl = true; + + /* issue the ioctl */ + err = sock_ioctl(sock, cmd, arg); + if (err) + log(LOG_ERR, "tuntap: socket ioctl %d failed: %d\n", cmd, err); + + in_ioctl = false; + + /* get rid of the socket */ + sock_close(sock); +} + +/* character device service methods */ +int +tuntap_interface::cdev_open(int flags, int devtype, proc_t p) +{ + dprintf("tuntap: cdev_open()\n"); + + /* grab the lock so that there can only be one thread inside */ + auto_lock l(&lock); + + /* check wether it is already open */ + if (open) + return EBUSY; + + /* bring the network interface up */ + int error = initialize_interface(); + if (error) + return error; + + open = true; + pid = proc_pid(p); + + return 0; +} + +int +tuntap_interface::cdev_close(int flags, int devtype, proc_t p) +{ + dprintf("tuntap: cdev_close()\n"); + + auto_lock l(&lock); + + if (open) { + open = false; + + /* shut down the network interface */ + shutdown_interface(); + + /* clear the queue */ + send_queue.clear(); + + /* wakeup the cdev thread and notify selects */ + wakeup(this); + selwakeup(&rsel); + + return 0; + } + + return EBADF; +} + +int +tuntap_interface::cdev_read(uio_t uio, int ioflag) +{ + auto_lock l(&lock); + + unsigned int nb = 0; + int error; + + dprintf("tuntap: cdev read\n"); + + if (!open || ifp == NULL || !(ifnet_flags(ifp) & IFF_UP)) + return EIO; + + /* fetch a new mbuf from the queue if necessary */ + mbuf_t cur_mbuf = NULL; + while (cur_mbuf == NULL) { + dprintf("tuntap: fetching new mbuf\n"); + + cur_mbuf = send_queue.dequeue(); + if (cur_mbuf == NULL) { + /* nothing in queue, block or return */ + if (!block_io) { + dprintf("tuntap: aborting (nbio)\n"); + return EWOULDBLOCK; + } else { + /* block */ + dprintf("tuntap: waiting\n"); + /* release the lock while waiting */ + l.unlock(); + error = msleep(this, NULL, PZERO | PCATCH, "tuntap", NULL); + + l.lock(); + + if (error) + return error; + + /* see whether the device was closed in the meantime */ + if (!open || ifp == NULL || !(ifnet_flags(ifp) & IFF_UP)) + return EIO; + + } + } + } + + /* notify bpf */ + notify_bpf(cur_mbuf, true); + + /* output what we have */ + do { + dprintf("tuntap: got new mbuf: %p uio_resid: %d\n", cur_mbuf, uio_resid(uio)); + + /* now we have an mbuf */ + int chunk_len = min(mbuf_len(cur_mbuf), uio_resid(uio)); + error = uiomove((char *) mbuf_data(cur_mbuf), chunk_len, uio); + if (error) { + mbuf_freem(cur_mbuf); + return error; + } + nb += chunk_len; + + dprintf("tuntap: moved %d bytes to userspace uio_resid: %d\n", chunk_len, + uio_resid(uio)); + + /* update cur_mbuf */ + cur_mbuf = mbuf_free(cur_mbuf); + + } while (uio_resid(uio) > 0 && cur_mbuf != NULL); + + /* update statistics */ + ifnet_stat_increment_out(ifp, 1, nb, 0); + + /* still data left? forget about that ;-) */ + if (cur_mbuf != NULL) + mbuf_freem(cur_mbuf); + + dprintf("tuntap: read done\n"); + + return 0; +} + +int +tuntap_interface::cdev_write(uio_t uio, int ioflag) +{ + auto_lock l(&lock); + + if (!open || ifp == NULL || !(ifnet_flags(ifp) & IFF_UP)) + return EIO; + + dprintf("tuntap: cdev write. uio_resid: %d\n", uio_resid(uio)); + + /* pack the data into an mbuf chain */ + mbuf_t first, mb; + + /* first we need an mbuf having a header */ + mbuf_gethdr(MBUF_WAITOK, MBUF_TYPE_DATA, &first); + if (first == NULL) { + log(LOG_ERR, "tuntap: could not get mbuf.\n"); + return ENOMEM; + } + mbuf_setlen(first, 0); + + unsigned int mlen = mbuf_maxlen(first); + unsigned int chunk_len; + unsigned int copied = 0; + int error; + + /* stuff the data into the mbuf(s) */ + mb = first; + while (uio_resid(uio) > 0) { + /* copy a chunk. enforce mtu (don't know if this is correct behaviour) */ + chunk_len = min(ifnet_mtu(ifp), min(uio_resid(uio), mlen)); + error = uiomove((caddr_t) mbuf_data(mb), chunk_len, uio); + if (error) { + log(LOG_ERR, "tuntap: could not copy data from userspace: %d\n", error); + mbuf_freem(first); + return error; + } + + dprintf("tuntap: copied %d bytes, uio_resid %d\n", chunk_len, + uio_resid(uio)); + + mlen -= chunk_len; + mbuf_setlen(mb, mbuf_len(mb) + chunk_len); + copied += chunk_len; + + /* if done, break the loop */ + if (uio_resid(uio) <= 0 || copied >= ifnet_mtu(ifp)) + break; + + /* allocate a new mbuf if the current is filled */ + if (mlen == 0) { + mbuf_t next; + mbuf_get(MBUF_WAITOK, MBUF_TYPE_DATA, &next); + if (next == NULL) { + log(LOG_ERR, "tuntap: could not get mbuf.\n"); + mbuf_freem(first); + return ENOMEM; + } + mbuf_setnext(mb, next); + mb = next; + mbuf_setlen(mb, 0); + mlen = mbuf_maxlen(mb); + } + } + + /* fill in header info */ + mbuf_pkthdr_setrcvif(first, ifp); + mbuf_pkthdr_setlen(first, copied); + mbuf_pkthdr_setheader(first, mbuf_data(first)); + mbuf_set_csum_performed(first, 0, 0); + + /* update statistics */ + ifnet_stat_increment_in(ifp, 1, copied, 0); + + dprintf("tuntap: mbuf chain constructed. first: %p mb: %p len: %d data: %p\n", + first, mb, mbuf_len(first), mbuf_data(first)); + + /* notify bpf */ + notify_bpf(first, false); + + /* need to adjust the data pointer to point directly behind the linklevel header. The header + * itself is later accessed via m_pkthdr.header. Well, if something is ugly, here is it. + */ + mbuf_adj(first, ifnet_hdrlen(ifp)); + + /* pass the packet over to the network stack */ + error = ifnet_input(ifp, first, NULL); + + if (error) { + log(LOG_ERR, "tuntap: could not input packet into network stack.\n"); + mbuf_freem(first); + return error; + } + + return 0; +} + +int +tuntap_interface::cdev_ioctl(u_long cmd, caddr_t data, int fflag, proc_t p) +{ + auto_lock l(&lock); + + dprintf("tuntap: cdev ioctl: %d\n", (int) (cmd & 0xff)); + + switch (cmd) { + case FIONBIO: + /* set i/o mode */ + block_io = *((int *) data) ? false : true; + return 0; + case FIOASYNC: + /* don't allow switching it on */ + if (*((int *) data)) + return ENOTTY; + return 0; + } + + return ENOTTY; +} + +int +tuntap_interface::cdev_select(int which, void *wql, proc_t p) +{ + auto_lock l(&lock); + + int ret = 0; + + dprintf("tuntap: select. which: %d\n", which); + + switch (which) { + case FREAD: + /* check wether data is available */ + { + if (!send_queue.empty()) + ret = 1; + else { + dprintf("tuntap: select: waiting\n"); + selrecord(p, &rsel, wql); + } + } + break; + case FWRITE: + /* we are always writeable */ + ret = 1; + } + + return ret; +} + +/* interface service methods */ +errno_t +tuntap_interface::if_output(mbuf_t m) +{ + mbuf_t pkt; + + dprintf("tuntap: if output\n"); + + /* just to be sure */ + if (m == NULL) + return 0; + + if (!open || ifp == NULL || !(ifnet_flags(ifp) & IFF_UP)) { + mbuf_freem_list(m); + return EHOSTDOWN; + } + + /* check whether packet has a header */ + if ((mbuf_flags(m) & MBUF_PKTHDR) == 0) { + log(LOG_ERR, "tuntap: packet to be output has no mbuf header.\n"); + mbuf_freem_list(m); + return EINVAL; + } + + /* put the packet(s) into the output queue */ + while (m != NULL) { + /* keep pointer, iterate */ + pkt = m; + m = mbuf_nextpkt(m); + mbuf_setnextpkt(pkt, NULL); + + auto_lock l(&lock); + + if (!send_queue.enqueue(pkt)) { + mbuf_freem(pkt); + mbuf_freem_list(m); + return ENOBUFS; + } + } + + /* protect the wakeup calls with the lock, not sure they are safe. */ + { + auto_lock l(&lock); + + /* wakeup the cdev thread and notify selects */ + wakeup(this); + selwakeup(&rsel); + } + + return 0; +} + +errno_t +tuntap_interface::if_ioctl(u_int32_t cmd, void *arg) +{ + dprintf("tuntap: if ioctl: %d\n", (int) (cmd & 0xff)); + + switch (cmd) { + case SIOCSIFADDR: + { + dprintf("tuntap: if_ioctl: SIOCSIFADDR\n"); + + /* Unfortunately, ifconfig sets the address family field of an INET + * netmask to zero, which makes early mDNSresponder versions ignore + * the interface. Fix that here. This one is of the category "ugly + * workaround". Dumb Darwin... + * + * Meanwhile, Apple has fixed mDNSResponder, and recent versions of + * Leopard don't need this hack anymore. However, Tiger still has a + * broken version so we leave the hack in for now. + * + * TODO: Revisit when dropping Tiger support. + * + * Btw. If you configure other network interfaces using ifconfig, + * you run into the same problem. I still don't know how to make the + * tap devices show up in the network configuration panel... + */ + ifaddr_t ifa = (ifaddr_t) arg; + if (ifa == NULL) + return 0; + + sa_family_t af = ifaddr_address_family(ifa); + if (af != AF_INET) + return 0; + + struct ifaliasreq ifra; + int sa_size = sizeof(struct sockaddr); + if (ifaddr_address(ifa, &ifra.ifra_addr, sa_size) + || ifaddr_dstaddress(ifa, &ifra.ifra_broadaddr, sa_size) + || ifaddr_netmask(ifa, &ifra.ifra_mask, sa_size)) { + log(LOG_WARNING, + "tuntap: failed to parse interface address.\n"); + return 0; + } + + // Check that the address family fields match. If not, issue another + // SIOCAIFADDR to fix the entry. + if (ifra.ifra_addr.sa_family != af + || ifra.ifra_broadaddr.sa_family != af + || ifra.ifra_mask.sa_family != af) { + log(LOG_INFO, "tuntap: Fixing address family for %s%d\n", + family_name, unit); + + snprintf(ifra.ifra_name, sizeof(ifra.ifra_name), "%s%d", + family_name, unit); + ifra.ifra_addr.sa_family = af; + ifra.ifra_broadaddr.sa_family = af; + ifra.ifra_mask.sa_family = af; + + do_sock_ioctl(af, SIOCAIFADDR, &ifra); + } + + return 0; + } + + case SIOCSIFFLAGS: + return 0; + + case SIOCGIFSTATUS: + { + struct ifstat *stat = (struct ifstat *) arg; + int len; + char *p; + + if (stat == NULL) + return EINVAL; + + /* print status */ + len = strlen(stat->ascii); + p = stat->ascii + len; + if (open) { + snprintf(p, IFSTATMAX - len, "\topen (pid %u)\n", pid); + } else { + snprintf(p, IFSTATMAX - len, "\tclosed\n"); + } + + return 0; + } + + case SIOCSIFMTU: + { + struct ifreq *ifr = (struct ifreq *) arg; + + if (ifr == NULL) + return EINVAL; + + ifnet_set_mtu(ifp, ifr->ifr_mtu); + + return 0; + } + + case SIOCDIFADDR: + return 0; + + } + + return EOPNOTSUPP; +} + +errno_t +tuntap_interface::if_set_bpf_tap(bpf_tap_mode mode, int (*cb)(ifnet_t, mbuf_t)) +{ + dprintf("tuntap: mode %d\n", mode); + + auto_lock l(&bpf_lock); + + bpf_callback = cb; + bpf_mode = mode; + + return 0; +} + +errno_t +tuntap_interface::if_check_multi(const struct sockaddr *maddr) +{ + dprintf("tuntap: if_check_multi\n"); + + return EOPNOTSUPP; +} + +void +tuntap_interface::if_detached() +{ + dprintf("tuntap: if_detached\n"); + + /* wake unregister_interface() */ + detach_lock.lock(); + interface_detached = true; + detach_lock.wakeup(&interface_detached); + detach_lock.unlock(); + + dprintf("if_detached done\n"); +} + |