_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; }
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; }
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; }
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; }
// ########################################################################################################## // # 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; }
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; }
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; }
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)); } } } }
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; }