Synchronize selrecord()/selwakeup()
[tuntaposx.git] / tuntap / src / tuntap.cc
blob4a702cff8b5b6ec6b93fef388269a08a8bcba53a
1 /*
2 * ip tunnel/ethertap device for MacOSX. Common functionality of tap_interface and tun_interface.
4 * tuntap_interface class definition
5 */
6 /*
7 * Copyright (c) 2004, 2005, 2006, 2007, 2008 Mattias Nissler <mattias.nissler@gmx.de>
9 * Redistribution and use in source and binary forms, with or without modification, are permitted
10 * provided that the following conditions are met:
12 * 1. Redistributions of source code must retain the above copyright notice, this list of
13 * conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
15 * conditions and the following disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 * 3. The name of the author may not be used to endorse or promote products derived from this
18 * software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
21 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
23 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
24 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include "tuntap.h"
32 #if 0
33 #define dprintf(...) log(LOG_INFO, __VA_ARGS__)
34 #else
35 #define dprintf(...)
36 #endif
38 extern "C" {
40 #include <sys/conf.h>
41 #include <sys/syslog.h>
42 #include <sys/param.h>
43 #include <sys/filio.h>
44 #include <sys/sockio.h>
45 #include <sys/fcntl.h>
46 #include <sys/kpi_socket.h>
48 #include <vm/vm_kern.h>
50 #include <net/if_types.h>
51 #include <net/if_var.h>
52 #include <net/if_dl.h>
53 #include <net/if_arp.h>
55 #include <miscfs/devfs/devfs.h>
59 extern "C" {
61 /* interface service functions that delegate to the appropriate tuntap_interface instance */
62 errno_t
63 tuntap_if_output(ifnet_t ifp, mbuf_t m)
65 if (ifp != NULL) {
66 tuntap_interface *ttif = (tuntap_interface *) ifnet_softc(ifp);
67 if (ttif != NULL)
68 return ttif->if_output(m);
71 if (m != NULL)
72 mbuf_freem_list(m);
74 return ENODEV;
77 errno_t
78 tuntap_if_ioctl(ifnet_t ifp, u_int32_t cmd, void *arg)
80 if (ifp != NULL) {
81 tuntap_interface *ttif = (tuntap_interface *) ifnet_softc(ifp);
82 if (ttif != NULL)
83 return ttif->if_ioctl(cmd, arg);
86 return ENODEV;
89 errno_t
90 tuntap_if_set_bpf_tap(ifnet_t ifp, bpf_tap_mode mode, int (*cb)(ifnet_t, mbuf_t))
92 if (ifp != NULL) {
93 tuntap_interface *ttif = (tuntap_interface *) ifnet_softc(ifp);
94 if (ttif != NULL)
95 return ttif->if_set_bpf_tap(mode, cb);
98 return ENODEV;
101 errno_t
102 tuntap_if_demux(ifnet_t ifp, mbuf_t m, char *header, protocol_family_t *proto)
104 if (ifp != NULL) {
105 tuntap_interface *ttif = (tuntap_interface *) ifnet_softc(ifp);
106 if (ttif != NULL)
107 return ttif->if_demux(m, header, proto);
110 return ENODEV;
113 errno_t
114 tuntap_if_framer(ifnet_t ifp, mbuf_t *m, const struct sockaddr *dest, const char *dest_linkaddr,
115 const char *frame_type)
117 if (ifp != NULL) {
118 tuntap_interface *ttif = (tuntap_interface *) ifnet_softc(ifp);
119 if (ttif != NULL)
120 return ttif->if_framer(m, dest, dest_linkaddr, frame_type);
123 return ENODEV;
126 errno_t
127 tuntap_if_add_proto(ifnet_t ifp, protocol_family_t proto, const struct ifnet_demux_desc *ddesc,
128 u_int32_t ndesc)
130 if (ifp != NULL) {
131 tuntap_interface *ttif = (tuntap_interface *) ifnet_softc(ifp);
132 if (ttif != NULL)
133 return ttif->if_add_proto(proto, ddesc, ndesc);
136 return ENODEV;
139 errno_t
140 tuntap_if_del_proto(ifnet_t ifp, protocol_family_t proto)
142 if (ifp != NULL) {
143 tuntap_interface *ttif = (tuntap_interface *) ifnet_softc(ifp);
144 if (ttif != NULL)
145 return ttif->if_del_proto(proto);
148 return ENODEV;
151 errno_t
152 tuntap_if_check_multi(ifnet_t ifp, const struct sockaddr* maddr)
154 if (ifp != NULL)
156 tuntap_interface *ttif = (tuntap_interface *) ifnet_softc(ifp);
157 if (ttif != NULL)
158 return ttif->if_check_multi(maddr);
161 return ENODEV;
164 void
165 tuntap_if_detached(ifnet_t ifp)
167 if (ifp != NULL) {
168 tuntap_interface *ttif = (tuntap_interface *) ifnet_softc(ifp);
169 if (ttif != NULL)
170 ttif->if_detached();
174 errno_t
175 tuntap_if_noop_output(ifnet_t, mbuf_t)
177 return ENODEV;
180 errno_t
181 tuntap_if_noop_demux(ifnet_t, mbuf_t, char*, protocol_family_t*)
183 return ENODEV;
186 errno_t
187 tuntap_if_noop_add_proto(ifnet_t, protocol_family_t, const struct ifnet_demux_desc*, u_int32_t)
189 return ENODEV;
192 errno_t
193 tuntap_if_noop_del_proto(ifnet_t, protocol_family_t)
195 return ENODEV;
198 } /* extern "C" */
200 /* tuntap_mbuf_queue */
201 tuntap_mbuf_queue::tuntap_mbuf_queue()
203 head = tail = NULL;
204 size = 0;
207 tuntap_mbuf_queue::~tuntap_mbuf_queue()
209 clear();
212 bool
213 tuntap_mbuf_queue::enqueue(mbuf_t mb)
215 if (size == QUEUE_SIZE)
216 return false;
218 mbuf_setnextpkt(mb, NULL);
220 if (head == NULL)
221 head = tail = mb;
222 else {
223 mbuf_setnextpkt(tail, mb);
224 tail = mb;
226 size++;
228 return true;
231 mbuf_t
232 tuntap_mbuf_queue::dequeue()
234 mbuf_t ret;
236 /* check wether there is a packet in the queue */
237 if (head == NULL)
238 return NULL;
240 /* fetch it */
241 ret = head;
242 head = mbuf_nextpkt(head);
243 mbuf_setnextpkt(ret, NULL);
244 size--;
246 return ret;
249 void
250 tuntap_mbuf_queue::clear()
252 /* free mbufs that are in the queue */
253 if (head != NULL)
254 mbuf_freem_list(head);
256 head = NULL;
257 tail = NULL;
258 size = 0;
261 /* tuntap_interface members */
262 tuntap_interface::tuntap_interface()
264 /* initialize the members */
265 ifp = NULL;
266 open = false;
267 block_io = true;
268 dev_handle = NULL;
269 pid = 0;
270 selthreadclear(&rsel);
271 bpf_mode = BPF_MODE_DISABLED;
272 bpf_callback = NULL;
273 bzero(unique_id, UIDLEN);
276 tuntap_interface::~tuntap_interface()
280 bool
281 tuntap_interface::register_chardev(unsigned short major)
283 /* register character device */
284 dev_handle = devfs_make_node(makedev(major, unit), DEVFS_CHAR, 0, 0, 0660, "%s%d",
285 family_name, (int) unit);
287 if (dev_handle == NULL) {
288 log(LOG_ERR, "tuntap: could not make /dev/%s%d\n", family_name, (int) unit);
289 return false;
292 return true;
295 void
296 tuntap_interface::unregister_chardev()
298 dprintf("unregistering character device\n");
300 /* unregister character device */
301 if (dev_handle != NULL)
302 devfs_remove(dev_handle);
303 dev_handle = NULL;
306 bool
307 tuntap_interface::register_interface(const struct sockaddr_dl* lladdr, void *bcaddr,
308 u_int32_t bcaddrlen)
310 struct ifnet_init_params ip;
311 errno_t err;
313 dprintf("register_interface\n");
315 /* initialize an initialization info struct */
316 ip.uniqueid_len = UIDLEN;
317 ip.uniqueid = unique_id;
318 ip.name = family_name;
319 ip.unit = unit;
320 ip.family = family;
321 ip.type = type;
322 ip.output = tuntap_if_output;
323 ip.demux = tuntap_if_demux;
324 ip.add_proto = tuntap_if_add_proto;
325 ip.del_proto = tuntap_if_del_proto;
326 ip.check_multi = tuntap_if_check_multi;
327 ip.framer = tuntap_if_framer;
328 ip.softc = this;
329 ip.ioctl = tuntap_if_ioctl;
330 ip.set_bpf_tap = tuntap_if_set_bpf_tap;
331 ip.detach = tuntap_if_detached;
332 ip.event = NULL;
333 ip.broadcast_addr = bcaddr;
334 ip.broadcast_len = bcaddrlen;
336 dprintf("tuntap: tuntap_if_check_multi is at 0x%08x\n", (void*) tuntap_if_check_multi);
338 /* allocate the interface */
339 err = ifnet_allocate(&ip, &ifp);
340 if (err) {
341 log(LOG_ERR, "tuntap: could not allocate interface for %s%d: %d\n", family_name,
342 (int) unit, err);
343 ifp = NULL;
344 return false;
347 /* activate the interface */
348 err = ifnet_attach(ifp, lladdr);
349 if (err) {
350 log(LOG_ERR, "tuntap: could not attach interface %s%d: %d\n", family_name,
351 (int) unit, err);
352 ifnet_release(ifp);
353 ifp = NULL;
354 return false;
357 dprintf("setting interface flags\n");
359 /* set interface flags */
360 ifnet_set_flags(ifp, IFF_RUNNING | IFF_MULTICAST | IFF_SIMPLEX, (u_int16_t) ~0UL);
362 dprintf("flags: %x\n", ifnet_flags(ifp));
364 return true;
367 void
368 tuntap_interface::unregister_interface()
370 errno_t err;
372 dprintf("unregistering network interface\n");
374 if (ifp != NULL) {
375 interface_detached = false;
377 /* detach interface */
378 err = ifnet_detach(ifp);
379 if (err)
380 log(LOG_ERR, "tuntap: error detaching interface %s%d: %d\n",
381 family_name, unit, err);
383 dprintf("interface detaching\n");
385 /* Wait until the interface has completely been detached. */
386 detach_lock.lock();
387 while (!interface_detached)
388 detach_lock.sleep(&interface_detached, NULL);
389 detach_lock.unlock();
391 dprintf("interface detached\n");
393 /* release the interface */
394 ifnet_release(ifp);
396 ifp = NULL;
398 #if 0
399 /* Here goes another hack that we need to prevent darwin from crashing.
400 * Unfortunately, not all of the interface service function pointers are cleared on
401 * detach properly. In particular, I had crashes from calling the demux() interface
402 * function after the kernel module had been unloaded. So we need to make sure all
403 * our function pointers get out of the ifnet struct. We do that by allocating the
404 * interface again, this time passing NULLs for the optional functions and pointers
405 * to noop-dummies for the required functions. Then, we release the interface again.
407 struct ifnet_init_params ip;
408 errno_t err;
410 dprintf("re-registering interface\n");
412 /* initialize an initialization info struct */
413 ip.uniqueid_len = UIDLEN;
414 ip.uniqueid = unique_id;
415 ip.name = family_name;
416 ip.unit = unit;
417 ip.family = family;
418 ip.type = type;
419 ip.output = tuntap_if_noop_output;
420 ip.demux = tuntap_if_noop_demux;
421 ip.add_proto = tuntap_if_noop_add_proto;
422 ip.del_proto = tuntap_if_noop_del_proto;
423 ip.check_multi = NULL;
424 ip.framer = NULL;
425 ip.softc = this;
426 ip.ioctl = NULL;
427 ip.set_bpf_tap = NULL;
428 ip.detach = NULL;
429 ip.event = NULL;
430 ip.broadcast_addr = NULL;
431 ip.broadcast_len = 0;
433 /* re-register the interface */
434 err = ifnet_allocate(&ip, &ifp);
435 if (err) {
436 log(LOG_ERR, "tuntap: dummy-allocate interface for %s%d: %d\n", family_name,
437 (int) unit, err);
438 /* well, bail out. this error shouldn't occur anyway. */
440 else
442 /* give it back */
443 ifnet_release(ifp);
445 #endif
447 /* finally done. */
448 ifp = NULL;
451 dprintf("network interface unregistered\n");
454 void
455 tuntap_interface::cleanup_interface()
457 errno_t err;
458 ifaddr_t *addrs;
459 ifaddr_t *a;
460 struct ifreq ifr;
461 socket_t sock;
463 /* mark the interface down */
464 ifnet_set_flags(ifp, 0, IFF_UP | IFF_RUNNING);
466 /* Unregister all interface addresses. This works around a deficiency in the Darwin kernel.
467 * If we don't remove all IP addresses that are attached to the interface it can happen that
468 * the IP code fails to clean them up itself. When the interface is recycled, the IP code
469 * might then think some addresses are still attached to the interface...
472 err = ifnet_get_address_list(ifp, &addrs);
473 if (!err) {
475 /* Execute a SIOCDIFADDR ioctl for each address. For technical reasons, we can only
476 * do that with a socket of the appropriate family. So try to create a dummy socket.
477 * I know this is a little expensive, but better than crashing...
479 * This really sucks.
481 for (a = addrs; *a != NULL; a++) {
482 /* initialize the request parameters */
483 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d",
484 ifnet_name(ifp), ifnet_unit(ifp));
485 ifaddr_address(*a, &(ifr.ifr_addr), sizeof(ifr.ifr_addr));
487 dprintf("trying to delete address of family %d\n", ifr.ifr_addr.sa_family);
489 /* create the dummy socket. */
490 err = sock_socket(ifr.ifr_addr.sa_family, SOCK_RAW, 0, NULL, NULL, &sock);
491 if (err)
492 /* failed to create the socket? Ignore this address... */
493 continue;
495 /* issue the ioctl */
496 err = sock_ioctl(sock, SIOCDIFADDR, &ifr);
498 dprintf("ifnet_ioctl returned %d\n", err);
500 /* get rid of the socket */
501 sock_close(sock);
504 /* release the address list */
505 ifnet_free_address_list(addrs);
509 bool
510 tuntap_interface::idle()
512 return !(open);
515 void
516 tuntap_interface::notify_bpf(mbuf_t mb, bool out)
518 auto_lock l(&bpf_lock);
520 if ((out && bpf_mode == BPF_MODE_OUTPUT)
521 || (!out && bpf_mode == BPF_MODE_INPUT)
522 || (bpf_mode == BPF_MODE_INPUT_OUTPUT))
523 (*bpf_callback)(ifp, mb);
526 /* character device service methods */
528 tuntap_interface::cdev_open(int flags, int devtype, proc_t p)
530 dprintf("tuntap: cdev_open()\n");
532 /* grab the lock so that there can only be one thread inside */
533 auto_lock l(&lock);
535 /* check wether it is already open */
536 if (open)
537 return EBUSY;
539 /* bring the network interface up */
540 int error = initialize_interface();
541 if (error)
542 return error;
544 open = true;
545 pid = proc_pid(p);
547 return 0;
551 tuntap_interface::cdev_close(int flags, int devtype, proc_t p)
553 dprintf("tuntap: cdev_close()\n");
555 auto_lock l(&lock);
557 if (open) {
558 open = false;
560 /* shut down the network interface */
561 shutdown_interface();
563 /* clear the queue */
564 send_queue.clear();
566 /* wakeup the cdev thread and notify selects */
567 wakeup(this);
568 selwakeup(&rsel);
570 return 0;
573 return EBADF;
577 tuntap_interface::cdev_read(uio_t uio, int ioflag)
579 auto_lock l(&lock);
581 unsigned int nb = 0;
582 int error;
584 dprintf("tuntap: cdev read\n");
586 if (!open || ifp == NULL || !(ifnet_flags(ifp) & IFF_UP))
587 return EIO;
589 /* fetch a new mbuf from the queue if necessary */
590 mbuf_t cur_mbuf = NULL;
591 while (cur_mbuf == NULL) {
592 dprintf("tuntap: fetching new mbuf\n");
594 cur_mbuf = send_queue.dequeue();
595 if (cur_mbuf == NULL) {
596 /* nothing in queue, block or return */
597 if (!block_io) {
598 dprintf("tuntap: aborting (nbio)\n");
599 return EWOULDBLOCK;
600 } else {
601 /* block */
602 dprintf("tuntap: waiting\n");
603 /* release the lock while waiting */
604 l.unlock();
605 error = msleep(this, NULL, PZERO | PCATCH, "tuntap", NULL);
607 l.lock();
609 if (error)
610 return error;
612 /* see whether the device was closed in the meantime */
613 if (!open || ifp == NULL || !(ifnet_flags(ifp) & IFF_UP))
614 return EIO;
620 /* notify bpf */
621 notify_bpf(cur_mbuf, true);
623 /* output what we have */
624 do {
625 dprintf("tuntap: got new mbuf: %p uio_resid: %d\n", cur_mbuf, uio_resid(uio));
627 /* now we have an mbuf */
628 int chunk_len = min(mbuf_len(cur_mbuf), uio_resid(uio));
629 error = uiomove((char *) mbuf_data(cur_mbuf), chunk_len, uio);
630 if (error) {
631 mbuf_freem(cur_mbuf);
632 return error;
634 nb += chunk_len;
636 dprintf("tuntap: moved %d bytes to userspace uio_resid: %d\n", chunk_len,
637 uio_resid(uio));
639 /* update cur_mbuf */
640 cur_mbuf = mbuf_free(cur_mbuf);
642 } while (uio_resid(uio) > 0 && cur_mbuf != NULL);
644 /* update statistics */
645 ifnet_stat_increment_out(ifp, 1, nb, 0);
647 /* still data left? forget about that ;-) */
648 if (cur_mbuf != NULL)
649 mbuf_freem(cur_mbuf);
651 dprintf("tuntap: read done\n");
653 return 0;
657 tuntap_interface::cdev_write(uio_t uio, int ioflag)
659 auto_lock l(&lock);
661 if (!open || ifp == NULL || !(ifnet_flags(ifp) & IFF_UP))
662 return EIO;
664 dprintf("tuntap: cdev write. uio_resid: %d\n", uio_resid(uio));
666 /* pack the data into an mbuf chain */
667 mbuf_t first, mb;
669 /* first we need an mbuf having a header */
670 mbuf_gethdr(MBUF_WAITOK, MBUF_TYPE_DATA, &first);
671 if (first == NULL) {
672 log(LOG_ERR, "tuntap: could not get mbuf.\n");
673 return ENOMEM;
675 mbuf_setlen(first, 0);
677 unsigned int mlen = mbuf_maxlen(first);
678 unsigned int chunk_len;
679 unsigned int copied = 0;
680 int error;
682 /* stuff the data into the mbuf(s) */
683 mb = first;
684 while (uio_resid(uio) > 0) {
685 /* copy a chunk. enforce mtu (don't know if this is correct behaviour) */
686 chunk_len = min(ifnet_mtu(ifp), min(uio_resid(uio), mlen));
687 error = uiomove((caddr_t) mbuf_data(mb), chunk_len, uio);
688 if (error) {
689 log(LOG_ERR, "tuntap: could not copy data from userspace: %d\n", error);
690 mbuf_freem(first);
691 return error;
694 dprintf("tuntap: copied %d bytes, uio_resid %d\n", chunk_len,
695 uio_resid(uio));
697 mlen -= chunk_len;
698 mbuf_setlen(mb, mbuf_len(mb) + chunk_len);
699 copied += chunk_len;
701 /* if done, break the loop */
702 if (uio_resid(uio) <= 0 || copied >= ifnet_mtu(ifp))
703 break;
705 /* allocate a new mbuf if the current is filled */
706 if (mlen == 0) {
707 mbuf_t next;
708 mbuf_get(MBUF_WAITOK, MBUF_TYPE_DATA, &next);
709 if (next == NULL) {
710 log(LOG_ERR, "tuntap: could not get mbuf.\n");
711 mbuf_freem(first);
712 return ENOMEM;
714 mbuf_setnext(mb, next);
715 mb = next;
716 mbuf_setlen(mb, 0);
717 mlen = mbuf_maxlen(mb);
721 /* fill in header info */
722 mbuf_pkthdr_setrcvif(first, ifp);
723 mbuf_pkthdr_setlen(first, copied);
724 mbuf_pkthdr_setheader(first, mbuf_data(first));
725 mbuf_set_csum_performed(first, 0, 0);
727 /* update statistics */
728 ifnet_stat_increment_in(ifp, 1, copied, 0);
730 dprintf("tuntap: mbuf chain constructed. first: %p mb: %p len: %d data: %p\n",
731 first, mb, mbuf_len(first), mbuf_data(first));
733 /* notify bpf */
734 notify_bpf(first, false);
736 /* need to adjust the data pointer to point directly behind the linklevel header. The header
737 * itself is later accessed via m_pkthdr.header. Well, if something is ugly, here is it.
739 mbuf_adj(first, ifnet_hdrlen(ifp));
741 /* pass the packet over to the network stack */
742 error = ifnet_input(ifp, first, NULL);
744 if (error) {
745 log(LOG_ERR, "tuntap: could not input packet into network stack.\n");
746 mbuf_freem(first);
747 return error;
750 return 0;
754 tuntap_interface::cdev_ioctl(u_long cmd, caddr_t data, int fflag, proc_t p)
756 auto_lock l(&lock);
758 dprintf("tuntap: cdev ioctl: %d\n", (int) (cmd & 0xff));
760 switch (cmd) {
761 case FIONBIO:
762 /* set i/o mode */
763 block_io = *((int *) data) ? false : true;
764 return 0;
765 case FIOASYNC:
766 /* don't allow switching it on */
767 if (*((int *) data))
768 return ENOTTY;
769 return 0;
772 return ENOTTY;
776 tuntap_interface::cdev_select(int which, void *wql, proc_t p)
778 auto_lock l(&lock);
780 int ret = 0;
782 dprintf("tuntap: select. which: %d\n", which);
784 switch (which) {
785 case FREAD:
786 /* check wether data is available */
788 if (!send_queue.empty())
789 ret = 1;
790 else {
791 dprintf("tuntap: select: waiting\n");
792 selrecord(p, &rsel, wql);
795 break;
796 case FWRITE:
797 /* we are always writeable */
798 ret = 1;
801 return ret;
804 /* interface service methods */
805 errno_t
806 tuntap_interface::if_output(mbuf_t m)
808 mbuf_t pkt;
810 dprintf("tuntap: if output\n");
812 /* just to be sure */
813 if (m == NULL)
814 return 0;
816 if (!open || ifp == NULL || !(ifnet_flags(ifp) & IFF_UP)) {
817 mbuf_freem_list(m);
818 return EHOSTDOWN;
821 /* check whether packet has a header */
822 if ((mbuf_flags(m) & MBUF_PKTHDR) == 0) {
823 log(LOG_ERR, "tuntap: packet to be output has no mbuf header.\n");
824 mbuf_freem_list(m);
825 return EINVAL;
828 /* put the packet(s) into the output queue */
829 while (m != NULL) {
830 /* keep pointer, iterate */
831 pkt = m;
832 m = mbuf_nextpkt(m);
833 mbuf_setnextpkt(pkt, NULL);
835 auto_lock l(&lock);
837 if (!send_queue.enqueue(pkt)) {
838 mbuf_freem(pkt);
839 mbuf_freem_list(m);
840 return ENOBUFS;
844 /* protect the wakeup calls with the lock, not sure they are safe. */
846 auto_lock l(&lock);
848 /* wakeup the cdev thread and notify selects */
849 wakeup(this);
850 selwakeup(&rsel);
853 return 0;
856 errno_t
857 tuntap_interface::if_ioctl(u_int32_t cmd, void *arg)
859 dprintf("tuntap: if ioctl: %d\n", (int) (cmd & 0xff));
861 switch (cmd) {
862 case SIOCSIFADDR:
863 dprintf("tuntap: if_ioctl: SIOCSIFADDR\n");
865 /* Unfortunately, ifconfig sets the address family field of an INET netmask
866 * to zero. However, this makes mDNSresponder ignore the interface. Fix that
867 * here. This one is of the category "ugly workaround". Dumb Darwin...
869 * Btw. If you configure other network interfaces using ifconfig, you run
870 * into the same problem. I still don't know how to make the tap devices
871 * show up in the network configuration panel...
873 struct ifaddr *ifa = (struct ifaddr *) arg;
874 if (ifa != NULL && ifa->ifa_netmask != NULL && ifa->ifa_addr != NULL) {
876 dprintf("tuntap: if_ioctl: addr af %d netmask af %d\n",
877 ifa->ifa_netmask->sa_family,
878 ifa->ifa_addr->sa_family);
880 if (ifa->ifa_netmask->sa_family != ifa->ifa_addr->sa_family)
882 /* Fix the address family field of the netmask */
883 dprintf("tuntap: if_ioctl: fixing netmask af.\n");
884 ifa->ifa_netmask->sa_family = ifa->ifa_addr->sa_family;
887 return 0;
889 case SIOCSIFFLAGS:
890 return 0;
892 case SIOCGIFSTATUS:
894 struct ifstat *stat = (struct ifstat *) arg;
895 int len;
896 char *p;
898 if (stat == NULL)
899 return EINVAL;
901 /* print status */
902 len = strlen(stat->ascii);
903 p = stat->ascii + len;
904 if (open) {
905 snprintf(p, IFSTATMAX - len, "\topen (pid %u)\n", pid);
906 } else {
907 snprintf(p, IFSTATMAX - len, "\tclosed\n");
910 return 0;
913 case SIOCSIFMTU:
915 struct ifreq *ifr = (struct ifreq *) arg;
917 if (ifr == NULL)
918 return EINVAL;
920 ifnet_set_mtu(ifp, ifr->ifr_mtu);
922 return 0;
925 case SIOCDIFADDR:
926 return 0;
930 return EOPNOTSUPP;
933 errno_t
934 tuntap_interface::if_set_bpf_tap(bpf_tap_mode mode, int (*cb)(ifnet_t, mbuf_t))
936 dprintf("tuntap: mode %d\n", mode);
938 auto_lock l(&bpf_lock);
940 bpf_callback = cb;
941 bpf_mode = mode;
943 return 0;
946 errno_t
947 tuntap_interface::if_check_multi(const struct sockaddr *maddr)
949 dprintf("tuntap: if_check_multi\n");
951 return EOPNOTSUPP;
954 void
955 tuntap_interface::if_detached()
957 dprintf("tuntap: if_detached\n");
959 /* wake unregister_interface() */
960 detach_lock.lock();
961 interface_detached = true;
962 detach_lock.wakeup(&interface_detached);
963 detach_lock.unlock();
965 dprintf("if_detached done\n");