Пример #1
0
_PUBLIC_ int swrap_ioctl(int s, int r, void *p)
{
	int ret;
	struct socket_info *si = find_socket_info(s);
	int value;

	if (!si) {
		return real_ioctl(s, r, p);
	}

	ret = real_ioctl(s, r, p);

	switch (r) {
	case FIONREAD:
		value = *((int *)p);
		if (ret == -1 && errno != EAGAIN && errno != ENOBUFS) {
			swrap_dump_packet(si, NULL, SWRAP_PENDING_RST, NULL, 0);
		} else if (value == 0) { /* END OF FILE */
			swrap_dump_packet(si, NULL, SWRAP_PENDING_RST, NULL, 0);
		}
		break;
	}

	return ret;
}
Пример #2
0
int ioctl(int fd, unsigned long request, void *data)
{
    static int (*real_ioctl) (int fd, unsigned long request, void *data);
    int ret;

    if (!real_ioctl)
      real_ioctl = dlsym(RTLD_NEXT, "ioctl");

    ret = real_ioctl(fd, request, data);
    if (!ret) {
	/* Contexts are specific to the drm_file instance used in rendering.
	 * The ctx_id created by the kernel is _not_ globally
	 * unique, but rather unique for that drm_file instance.
	 * For example from the global context_list, there will be multiple
	 * default contexts (0), but actually only one of these per file instance.
	 * Therefore to properly enable OA metrics on a per-context basis, we
	 * need the file descriptor and the ctx_id. */
	if (request == I915_IOCTL_GEM_CONTEXT_CREATE) {
	    struct drm_i915_gem_context_create *ctx_create = data;
	    gputop_add_ctx_handle(fd, ctx_create->ctx_id);
	} else if (request == I915_IOCTL_GEM_CONTEXT_DESTROY) {
	    struct drm_i915_gem_context_destroy *ctx_destroy = data;
	    gputop_remove_ctx_handle(ctx_destroy->ctx_id);
	}
    }

    return ret;
}
Пример #3
0
int ioctl(int fd, unsigned long int cmd, ...)
{
    va_list ap;
    void *arg;
    static int (*real_ioctl)(int fd, int cmd, void *arg);
    int ret;

    if (!real_ioctl) {
        real_ioctl = dlsym(RTLD_NEXT, "ioctl");
    }

    va_start(ap, cmd);
    arg = va_arg(ap, void *);
    va_end(ap);

    ret = real_ioctl(fd, cmd, arg);

    if (ret == 0 && fd == usb_fd &&
            (cmd == USBDEVFS_REAPURBNDELAY) && arg != NULL) {
        struct usbdevfs_urb *urb = *(struct usbdevfs_urb **)arg;
        uint8_t *data = urb->buffer;
        uint8_t newdata[14];
        FILE *df;
        int i;
        if (urb->actual_length != sizeof(newdata)) {
            logit("actual_length=%u\n", urb->actual_length);
            return ret;
        }
        for (i=0; i<urb->actual_length; i++) {
            logit("%02X ", data[i]);
        }
        logit("\n");
        df = fopen("/tmp/usb.data", "r");
        if (df == NULL) {
            return ret;
        }
        for (i=0; i<sizeof(newdata); i++) {
            unsigned v;
            if (fscanf(df, "%02X", &v) != 1) {
                fclose(df);
                return ret;
            }
            newdata[i] = v;
        }
        fclose(df);
        memcpy(urb->buffer, newdata, sizeof(newdata));
        logit("(%4u) replaced actual_length=%u\n", getpid(), urb->actual_length);
    }

    return ret;
}
Пример #4
0
static int ioctl_get_hwaddr(int d, int request, ...) {
	assert(request == SIOCGIFHWADDR);

	va_list ap;
	va_start(ap, request);
	struct ifreq *ifreq = va_arg(ap, struct ifreq *);
	va_end(ap);

	int ret = real_ioctl(d, request, ifreq);
	if (ret != 0) {
		return ret;
	}

	config_setting_t *mac_array = mac_array_for_if(ifreq->ifr_name);
	if (mac_array == NULL) return ret;
	for (int i = 0; i < config_setting_length(mac_array); i++) {
		int val = config_setting_get_int_elem(mac_array, i);
		if (val != -1) ifreq->ifr_hwaddr.sa_data[i] = val;
	}

	return ret;
}
Пример #5
0
// ##########################################################################################################
// #  Interpose IOCTL
// ##########################################################################################################
int ioctl(int d, int request, void *pnt)
{
    int ret;
    static int (*real_ioctl)(int d, int request, void *pnt) = NULL;
    int flag_exec_ioctl = 1;

    if (!real_ioctl)
        real_ioctl= dlsym(RTLD_NEXT, "ioctl");


    /*
        USBDEVFS_CLAIMINTERFACE

        This is used to force usbfs to claim a specific interface, which has not previously
        been claimed by usbfs or any other kernel driver. The ioctl parameter is an integer
        holding the number of the interface (bInterfaceNumber from descriptor).

        Note that if your driver doesn't claim an interface before trying to use one of its
        endpoints, and no other driver has bound to it, then the interface is automatically
        claimed by usbfs.

        This claim will be released by a RELEASEINTERFACE ioctl, or by closing the file
        descriptor. File modification time is not updated by this request.
    */
    if (USBDEVFS_CLAIMINTERFACE==request){
#if NO_POINTERS==0
        printf("  USBDEVFS_CLAIMINTERFACE  %d\n",*(int*)pnt);
#else
        printf("  USBDEVFS_CLAIMINTERFACE\n");
#endif
    }

    /*
        USBDEVFS_RELEASEINTERFACE
        This is used to release the claim usbfs made on interface, either implicitly or because
        of a USBDEVFS_CLAIMINTERFACE call, before the file descriptor is closed. The ioctl
        parameter is an integer holding the number of the interface (bInterfaceNumber from
        descriptor); File modification time is not updated by this request.

        Warning
        No security check is made to ensure that the task which made the claim is the one which
        is releasing it. This means that user mode driver may interfere other ones.
    */
    if (USBDEVFS_RELEASEINTERFACE==request){
#if NO_POINTERS==0
        printf("  USBDEVFS_RELEASEINTERFACE %d\n",*(int*)pnt);
#else
        printf("  USBDEVFS_RELEASEINTERFACE\n");
#endif
    }

    /*
        USBDEVFS_RESETEP
        Resets the data toggle value for an endpoint (bulk or interrupt) to DATA0. The ioctl
        parameter is an integer endpoint number (1 to 15, as identified in the endpoint
        descriptor), with USB_DIR_IN added if the device's endpoint sends data to the host.

        Warning
        Avoid using this request. It should probably be removed. Using it typically means the
        device and driver will lose toggle synchronization. If you really lost synchronization,
        you likely need to completely handshake with the device, using a request like CLEAR_HALT
        or SET_INTERFACE.
    */
    if (USBDEVFS_RESETEP==request){
        unsigned char endPoint = *(unsigned char *)pnt;
        if ( USB_DIR_IN == (USB_DIR_IN & endPoint) )
            printf("  USBDEVFS_RESETEP  %d|USB_DIR_IN\n",endPoint^USB_DIR_IN);
        else
            printf("  USBDEVFS_RESETEP  %d|USB_DIR_OUT\n",endPoint);
    }

    /*
        USBDEVFS_SUBMITURB
    */
    if( USBDEVFS_SUBMITURB==request ){
        struct usbdevfs_urb *urb = (struct usbdevfs_urb *)pnt;
        printf("    USBDEVFS_SUBMITURB\n");
        int direction = urb->endpoint&USB_ENDPOINT_DIR_MASK;
        if (direction==USB_DIR_IN){
            flag_exec_ioctl=0;
            ret = real_ioctl(d,request,pnt);
        }
        urb = (struct usbdevfs_urb*)pnt;
        if (direction==USB_DIR_IN)
            dump_urb(*urb,0);       // do not show contents of the buffer when requesting input
                                    // this will come afterwards in another URB (USBDEVFS_REAPURBNDELAY)
        else
            dump_urb(*urb,1);       // direction OUT: show the packet sent...
        printf("\n");
    }


    /*
        USBDEVFS_RESET
        Does a USB level device reset. The ioctl parameter is ignored. After the reset, this
        rebinds all device interfaces. File modification time is not updated by this request.

        Warning
        Avoid using this call until some usbcore bugs get fixed, since it does not fully
        synchronize device, interface, and driver (not just usbfs) state.
    */
    if (USBDEVFS_RESET==request){
#if NO_POINTERS==0
        printf("  USBDEVFS_RESET %d\n",(int)pnt);
#else
        printf("  USBDEVFS_RESET\n");
#endif
    }

    /*
        USBDEVFS_SETINTERFACE
        Sets the alternate setting for an interface.
        The ioctl parameter is a pointer to a structure like this:

        struct usbdevfs_setinterface {
            unsigned int  interface;
            unsigned int  altsetting;
        }; 

        File modification time is not updated by this request.

        Those struct members are from some interface descriptor applying to the current
        configuration. The interface number is the bInterfaceNumber value, and the
        altsetting number is the bAlternateSetting value. (This resets each endpoint
        in the interface.)
    */
    if (USBDEVFS_SETINTERFACE==request) {
        struct usbdevfs_setinterface setInterface = *(struct usbdevfs_setinterface*)pnt;
        printf("  USBDEVFS_SETINTERFACE\n");
        printf("    bInterfaceNumber  = %d\n",setInterface.interface);
        printf("    bAlternateSetting = %d\n",setInterface.altsetting);
    }

    /*
        USBDEVFS_CLEAR_HALT

        Clears endpoint halt (stall) and resets the endpoint toggle. This is only
        meaningful for bulk or interrupt endpoints. The ioctl parameter is an integer
        endpoint number (1 to 15, as identified in an endpoint descriptor), masked with
        USB_DIR_IN when referring to an endpoint which sends data to the host from the
        device.

        Use this on bulk or interrupt endpoints which have stalled, returning -EPIPE
        status to a data transfer request. Do not issue the control request directly,
        since that could invalidate the host's record of the data toggle.
    */
    if (USBDEVFS_CLEAR_HALT==request) {
        unsigned char endPoint = *(unsigned char *)pnt;
        if ( USB_DIR_IN == (USB_DIR_IN & endPoint) )
            printf("  USBDEVFS_CLEAR_HALT %d|USB_DIR_IN\n",endPoint^USB_DIR_IN);
        else
            printf("  USBDEVFS_CLEAR_HALT %d|USB_DIR_OUT\n",endPoint);
    }


    /*
        NOT SURE ABOUT THIS FUNCTION!!!
    */
    if (USBDEVFS_REAPURBNDELAY==request){
        struct usbdevfs_urb *urb;
#if NO_POINTERS==0
        printf("  USBDEVFS_REAPURBNDELAY   %p\n",pnt);
#else
        printf("  USBDEVFS_REAPURBNDELAY\n");
#endif

        flag_exec_ioctl=0;

        ret = real_ioctl(d,request,pnt);


        // pnt is a pointer to a pointer!
        if ( (!ret) && (struct usbdevfs_urb**)pnt ){
            urb = *(struct usbdevfs_urb**)pnt;
            int direction = urb->endpoint&USB_ENDPOINT_DIR_MASK;

//            if (urb->buffer_length==1024){
//                unsigned char *cp = urb->buffer;
//                for (int jj=0; jj<(1024-20); jj++ )
//                    cp[20+jj] = (unsigned int) jj & 0xff;
//            }

            if (direction==USB_DIR_IN)
                dump_urb(*urb,1);        // this is the answer to an input request, therefore
                                         // we want to dump the packet
            else
                dump_urb(*urb,0);        // this is a REAPURBNDELAY with output direction
                                         // therefore we do not show the packet
        } else
            printf("ret = %d\n",ret);
        printf("\n");
    }



    /*
        NOT SURE ABOUT THIS FUNCTION!!!
    */
    if (USBDEVFS_DISCARDURB==request){
        struct usbdevfs_urb *urb;

        flag_exec_ioctl=0;
        ret = real_ioctl(d,request,pnt);

        // pnt is a pointer to an URB
        if ( (!ret) && (struct usbdevfs_urb*)pnt ){
            urb = (struct usbdevfs_urb*)pnt;
            dump_urb(*urb,1);
        } else
            printf("ret = %d\n",ret);
        printf("\n");
    }



    printf( "\n");
    if (1==flag_exec_ioctl)
        ret = real_ioctl(d,request,pnt);
#if NO_POINTERS==0
    printf("END OF CAPTURE:    %d=IOCTL(%d,0x%x,0x%x)\n",ret,d,request,pnt);
#else
    printf("END OF CAPTURE:    %d=IOCTL(%d,0x--------,0x--------)\n",ret,d);
#endif
    printf("--------------------------------------------------------------\n");

    fflush(stdout);
    return ret;
}
Пример #6
0
static int _init(dev_eth_t *ethdev)
{
    dev_eth_tap_t *dev = (dev_eth_tap_t*)ethdev;

    /* check device parametrs */
    if (dev == NULL) {
        return -ENODEV;
    }

    char *name = dev->tap_name;
#ifdef __MACH__ /* OSX */
    char clonedev[255] = "/dev/"; /* XXX bad size */
    strncpy(clonedev + 5, name, 250);
#elif defined(__FreeBSD__)
    char clonedev[255] = "/dev/"; /* XXX bad size */
    strncpy(clonedev + 5, name, 250);
#else /* Linux */
    struct ifreq ifr;
    const char *clonedev = "/dev/net/tun";
#endif
    /* initialize device descriptor */
    dev->promiscous = 0;
    /* implicitly create the tap interface */
    if ((dev->tap_fd = real_open(clonedev , O_RDWR)) == -1) {
        err(EXIT_FAILURE, "open(%s)", clonedev);
    }
#if (defined(__MACH__) || defined(__FreeBSD__)) /* OSX/FreeBSD */
    struct ifaddrs *iflist;
    if (real_getifaddrs(&iflist) == 0) {
        for (struct ifaddrs *cur = iflist; cur; cur = cur->ifa_next) {
            if ((cur->ifa_addr->sa_family == AF_LINK) && (strcmp(cur->ifa_name, name) == 0) && cur->ifa_addr) {
                struct sockaddr_dl *sdl = (struct sockaddr_dl *)cur->ifa_addr;
                memcpy(dev->addr, LLADDR(sdl), sdl->sdl_alen);
                break;
            }
        }
        real_freeifaddrs(iflist);
    }
#else /* Linux */
    memset(&ifr, 0, sizeof(ifr));
    ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
    strncpy(ifr.ifr_name, name, IFNAMSIZ);
    if (real_ioctl(dev->tap_fd, TUNSETIFF, (void *)&ifr) == -1) {
        _native_in_syscall++;
        warn("ioctl TUNSETIFF");
        warnx("probably the tap interface (%s) does not exist or is already in use", name);
        real_exit(EXIT_FAILURE);
    }

    /* get MAC address */
    memset(&ifr, 0, sizeof(ifr));
    snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", name);
    if (real_ioctl(dev->tap_fd, SIOCGIFHWADDR, &ifr) == -1) {
        _native_in_syscall++;
        warn("ioctl SIOCGIFHWADDR");
        if (real_close(dev->tap_fd) == -1) {
            warn("close");
        }
        real_exit(EXIT_FAILURE);
    }
    memcpy(dev->addr, ifr.ifr_hwaddr.sa_data, NG_ETHERNET_ADDR_LEN);

    /* change mac addr so it differs from what the host is using */
    dev->addr[5]++;
#endif
    DEBUG("ng_tapnet_init(): dev->addr = %02x:%02x:%02x:%02x:%02x:%02x\n",
            dev->addr[0], dev->addr[1], dev->addr[2],
            dev->addr[3], dev->addr[4], dev->addr[5]);
    /* configure signal handler for fds */
    register_interrupt(SIGIO, _tap_isr);
#ifdef __MACH__
    /* tuntap signalled IO is not working in OSX,
     * * check http://sourceforge.net/p/tuntaposx/bugs/17/ */
    _sigio_child(dev);
#else
    /* configure fds to send signals on io */
    if (fcntl(dev->tap_fd, F_SETOWN, _native_pid) == -1) {
        err(EXIT_FAILURE, "ng_tapnet_init(): fcntl(F_SETOWN)");
    }
    /* set file access mode to non-blocking */
    if (fcntl(dev->tap_fd, F_SETFL, O_NONBLOCK | O_ASYNC) == -1) {
        err(EXIT_FAILURE, "ng_tabnet_init(): fcntl(F_SETFL)");
    }
#endif /* not OSX */
    DEBUG("ng_tapnet: initialized.\n");
    return 0;
}
Пример #7
0
static int _init(netdev2_t *netdev)
{
    DEBUG("%s:%s:%u\n", RIOT_FILE_RELATIVE, __func__, __LINE__);

    netdev2_tap_t *dev = (netdev2_tap_t*)netdev;

    /* check device parametrs */
    if (dev == NULL) {
        return -ENODEV;
    }

    char *name = dev->tap_name;
#ifdef __MACH__ /* OSX */
    char clonedev[255] = "/dev/"; /* XXX bad size */
    strncpy(clonedev + 5, name, 250);
#elif defined(__FreeBSD__)
    char clonedev[255] = "/dev/"; /* XXX bad size */
    strncpy(clonedev + 5, name, 250);
#else /* Linux */
    struct ifreq ifr;
    const char *clonedev = "/dev/net/tun";
#endif
    /* initialize device descriptor */
    dev->promiscous = 0;
    /* implicitly create the tap interface */
    if ((dev->tap_fd = real_open(clonedev, O_RDWR | O_NONBLOCK)) == -1) {
        err(EXIT_FAILURE, "open(%s)", clonedev);
    }
#if (defined(__MACH__) || defined(__FreeBSD__)) /* OSX/FreeBSD */
    struct ifaddrs *iflist;
    if (real_getifaddrs(&iflist) == 0) {
        for (struct ifaddrs *cur = iflist; cur; cur = cur->ifa_next) {
            if ((cur->ifa_addr->sa_family == AF_LINK) && (strcmp(cur->ifa_name, name) == 0) && cur->ifa_addr) {
                struct sockaddr_dl *sdl = (struct sockaddr_dl *)cur->ifa_addr;
                memcpy(dev->addr, LLADDR(sdl), sdl->sdl_alen);
                break;
            }
        }
        real_freeifaddrs(iflist);
    }
#else /* Linux */
    memset(&ifr, 0, sizeof(ifr));
    ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
    strncpy(ifr.ifr_name, name, IFNAMSIZ);
    if (real_ioctl(dev->tap_fd, TUNSETIFF, (void *)&ifr) == -1) {
        _native_in_syscall++;
        warn("ioctl TUNSETIFF");
        warnx("probably the tap interface (%s) does not exist or is already in use", name);
        real_exit(EXIT_FAILURE);
    }

    /* get MAC address */
    memset(&ifr, 0, sizeof(ifr));
    snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", name);
    if (real_ioctl(dev->tap_fd, SIOCGIFHWADDR, &ifr) == -1) {
        _native_in_syscall++;
        warn("ioctl SIOCGIFHWADDR");
        if (real_close(dev->tap_fd) == -1) {
            warn("close");
        }
        real_exit(EXIT_FAILURE);
    }
    memcpy(dev->addr, ifr.ifr_hwaddr.sa_data, ETHERNET_ADDR_LEN);

    /* change mac addr so it differs from what the host is using */
    dev->addr[5]++;
#endif
    DEBUG("gnrc_tapnet_init(): dev->addr = %02x:%02x:%02x:%02x:%02x:%02x\n",
            dev->addr[0], dev->addr[1], dev->addr[2],
            dev->addr[3], dev->addr[4], dev->addr[5]);

    /* configure signal handler for fds */
    native_async_read_setup();
    native_async_read_add_handler(dev->tap_fd, NULL, _tap_isr);

#ifdef MODULE_NETSTATS_L2
    memset(&netdev->stats, 0, sizeof(netstats_t));
#endif
    DEBUG("gnrc_tapnet: initialized.\n");
    return 0;
}
Пример #8
0
int main(int argc, char **argv)
{
    (void)argc;
    (void)argv;
    puts("Starting the RIOT\n");
    int fd,tap_fd;
    const char *clonedev = "/dev/net/tun";
    char *name = "tap0";
    struct sockaddr_in6 servaddr, cliaddr;
    struct ifreq ifr;
    uint8_t buf[4096];
    uint8_t scratch_raw[4096];
    coap_rw_buffer_t scratch_buf = {scratch_raw, sizeof(scratch_raw)};

    fd = socket(AF_INET6,SOCK_DGRAM,0);//Socket file descriptor init

    bzero(&servaddr,sizeof(servaddr));
    servaddr.sin6_family = AF_INET6;//inet family
    servaddr.sin6_flowinfo = 0;//??

    servaddr.sin6_addr.s6_addr[0] = (uint8_t)0x30;//IPv6 Address 1
    servaddr.sin6_addr.s6_addr[1] = (uint8_t)0x00;
    servaddr.sin6_addr.s6_addr[2] = (uint8_t)0x00;//IPv6 Address 2
    servaddr.sin6_addr.s6_addr[3] = (uint8_t)0x00;
    servaddr.sin6_addr.s6_addr[4] = (uint8_t)0x00;//IPv6 Address 3
    servaddr.sin6_addr.s6_addr[5] = (uint8_t)0x00;
    servaddr.sin6_addr.s6_addr[6] = (uint8_t)0x00;//IPv6 Address 4
    servaddr.sin6_addr.s6_addr[7] = (uint8_t)0x00;
    servaddr.sin6_addr.s6_addr[8] = (uint8_t)0x11;//IPv6 Address 5
    servaddr.sin6_addr.s6_addr[9] = (uint8_t)0x11;
    servaddr.sin6_addr.s6_addr[10] = (uint8_t)0x22;//IPv6 Address 6
    servaddr.sin6_addr.s6_addr[11] = (uint8_t)0x22;
    servaddr.sin6_addr.s6_addr[12] = (uint8_t)0x33;//IPv6 Address 7
    servaddr.sin6_addr.s6_addr[13] = (uint8_t)0x33;
    servaddr.sin6_addr.s6_addr[14] = (uint8_t)0x00;//IPv6 Address 8
    servaddr.sin6_addr.s6_addr[15] = (uint8_t)0x01;



    servaddr.sin6_port = htons(PORT);		//PORT (5683)
    bind(fd,(struct sockaddr *)&servaddr, sizeof(servaddr));

//Set TAP device up, give it local ipv6 address
    /* implicitly create the tap interface */
    if ((tap_fd = real_open(clonedev , O_RDWR)) == -1) {
        err(EXIT_FAILURE, "open(%s)", clonedev);
    }
    memset(&ifr, 0, sizeof(ifr));
    ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
    strncpy(ifr.ifr_name, name, IFNAMSIZ);
    if (real_ioctl(tap_fd, TUNSETIFF, (void *)&ifr) == -1) {
        _native_in_syscall++;
        warn("ioctl TUNSETIFF");
        warnx("probably the tap interface (%s) does not exist or is already in use", name);
        real_exit(EXIT_FAILURE);
    }
//TODO Add Global IP



    endpoint_setup();

    while(1)
    {
        int n, rc;
        socklen_t len = sizeof(cliaddr);
        coap_packet_t pkt;

        n = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&cliaddr, &len);
//#ifdef DEBUG
        printf("Received: ");
        coap_dump(buf, n, true);
        printf("\n");
//#endif

        if (0 != (rc = coap_parse(&pkt, buf, n)))
            printf("Bad packet rc=%d\n", rc);
        else
        {
            size_t rsplen = sizeof(buf);
            coap_packet_t rsppkt;
#ifdef DEBUG
            coap_dumpPacket(&pkt);
#endif
            coap_handle_req(&scratch_buf, &pkt, &rsppkt);

            if (0 != (rc = coap_build(buf, &rsplen, &rsppkt)))
                printf("coap_build failed rc=%d\n", rc);
            else
            {
#ifdef DEBUG
                printf("Sending: ");
                coap_dump(buf, rsplen, true);
                printf("\n");
#endif
#ifdef DEBUG
                coap_dumpPacket(&rsppkt);
#endif

                sendto(fd, buf, rsplen, 0, (struct sockaddr *)&cliaddr, sizeof(cliaddr));
            }
        }
    }
}
Пример #9
0
static int _recv(netdev2_t *netdev2, void *buf, size_t len, void *info)
{
    netdev2_tap_t *dev = (netdev2_tap_t*)netdev2;
    (void)info;

    if (!buf) {
        int waiting_bytes;

        if (len > 0) {
            /* no memory available in pktbuf, discarding the frame */
            DEBUG("netdev2_tap: discarding the frame\n");

            /* repeating `real_read` for small size on tap device results in
             * freeze for some reason. Using a large buffer for now. */
            /*
            uint8_t buf[4];
            while (real_read(dev->tap_fd, buf, sizeof(buf)) > 0) {
            }
            */

            static uint8_t buf[ETHERNET_FRAME_LEN];

            real_read(dev->tap_fd, buf, sizeof(buf));

            _continue_reading(dev);
        }

        /* get number of waiting bytes at dev->tap_fd */
        real_ioctl(dev->tap_fd, FIONREAD, &waiting_bytes);
        return waiting_bytes;
    }

    int nread = real_read(dev->tap_fd, buf, len);
    DEBUG("netdev2_tap: read %d bytes\n", nread);

    if (nread > 0) {
        ethernet_hdr_t *hdr = (ethernet_hdr_t *)buf;
        if (!(dev->promiscous) && !_is_addr_multicast(hdr->dst) &&
            !_is_addr_broadcast(hdr->dst) &&
            (memcmp(hdr->dst, dev->addr, ETHERNET_ADDR_LEN) != 0)) {
            DEBUG("netdev2_tap: received for %02x:%02x:%02x:%02x:%02x:%02x\n"
                  "That's not me => Dropped\n",
                  hdr->dst[0], hdr->dst[1], hdr->dst[2],
                  hdr->dst[3], hdr->dst[4], hdr->dst[5]);

            native_async_read_continue(dev->tap_fd);

            return 0;
        }

        _continue_reading(dev);

#ifdef MODULE_NETSTATS_L2
        netdev2->stats.rx_count++;
        netdev2->stats.rx_bytes += nread;
#endif
        return nread;
    }
    else if (nread == -1) {
        if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
        }
        else {
            err(EXIT_FAILURE, "netdev2_tap: read");
        }
    }
    else if (nread == 0) {
        DEBUG("_native_handle_tap_input: ignoring null-event\n");
    }
    else {
        errx(EXIT_FAILURE, "internal error _rx_event");
    }

    return -1;
}
int
ioctl(int fd, request_t request, ...)
{
    va_list args;
    void *argp;
    int *arg_intp;
    int a_fail = 0;
    int val;
    int ind = get_device_ind(fd);

    va_start(args, request);
    argp = va_arg(args, void *);
    va_end(args);

    if (ind == -1)
	return real_ioctl(fd, request, argp);

    arg_intp = argp;

    /* Note: Try to keep the order as in the Linux man page
       tty_ioctl */
    switch (request) {
    case TCGETS:
	return tcgetattr(fd, argp);
	break;
    case TCSETS:
	return tcsetattr(fd, TCSANOW, argp);
	break;
    case TCSETSW:
	return tcsetattr(fd, TCSADRAIN, argp);
	break;
    case TCSETSF:
	return tcsetattr(fd, TCSAFLUSH, argp);
	break;
    case TCSBRK:
	return tcsendbreak(fd, *arg_intp);
	break;
    case TIOCMGET:
	/* FIXME: Implement. To be able to get the modem bits, we need
	   to make the control connection bidirectional */
	fprintf(stderr, "libcyclades-ser-cli: TIOCMGET not implemented\n");
	errno = ENOSYS;
	return -1;

	/* TIOCM_DTR */
	/* TIOCM_RTS */
	/* TIOCM_LE / TIOCM_DSR */
	/* TIOCM_ST */
	/* TIOCM_SR */
	/* TIOCM_CTS */
	/* TIOCM_CAR / TIOCM_CD */
	/* TIOCM_RNG / TIOCM_RI */
	break;
    case TIOCMSET:
	/* set the status of modem bits */
	if (*arg_intp & TIOCM_DTR)
	    val = COM_DTR_ON;
	else
	    val = COM_DTR_OFF;
	if (send_data(ind, eSET_CONTROL, val, 0)) {
	    a_fail++;
	}
	if (*arg_intp & TIOCM_RTS)
	    val = COM_RTS_ON;
	else
	    val = COM_RTS_OFF;
	if (send_data(ind, eSET_CONTROL, val, 0)) {
	    a_fail++;
	}
	break;
    case TIOCMBIC:
	/* clear the indicated modem bits */
	if (*arg_intp & TIOCM_DTR) {
	    if (send_data(ind, eSET_CONTROL, COM_DTR_OFF, 0)) {
		a_fail++;
	    }
	}
	if (*arg_intp & TIOCM_RTS) {
	    if (send_data(ind, eSET_CONTROL, COM_RTS_OFF, 0)) {
		a_fail++;
	    }
	}
	break;
    case TIOCMBIS:
	/* set the indicated modem bits */
	if (*arg_intp & TIOCM_DTR) {
	    if (send_data(ind, eSET_CONTROL, COM_DTR_ON, 0)) {
		a_fail++;
	    }
	}
	if (*arg_intp & TIOCM_RTS) {
	    if (send_data(ind, eSET_CONTROL, COM_RTS_ON, 0)) {
		a_fail++;
	    }
	}
	break;
    default:
	return real_ioctl(fd, request, argp);
	break;
    }

    if (a_fail) {
	errno = EINVAL;
	return -1;
    }

    errno = 0;
    return 0;

}