Folks, I am pulling what little hair I have left out over trying to read packets from the TUN/TAP interface on uCLinux.
I have the following code that creates my tap0 interface.. /* * */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <fcntl.h> #include <unistd.h> #include <pwd.h> #include <grp.h> #include <net/if.h> #include <sys/ioctl.h> #include <linux/if_tun.h> /* TUNSETGROUP appeared in 2.6.23 */ #ifndef TUNSETGROUP #define TUNSETGROUP _IOW('T', 206, int) #endif static void Usage(char *name) { fprintf(stderr, "Create: %s [-b] [-u owner] [-g group] [-t device-name] " "[-f tun-clone-device]\n", name); fprintf(stderr, "Delete: %s -d device-name [-f tun-clone-device]\n\n", name); fprintf(stderr, "The default tun clone device is /dev/net/tun - some systems" " use\n/dev/misc/net/tun instead\n\n"); fprintf(stderr, "-b will result in brief output (just the device name)\n"); exit(1); } int main(int argc, char **argv) { struct ifreq ifr; struct passwd *pw; struct group *gr; uid_t owner = -1; gid_t group = -1; int tap_fd, opt, delete = 0, brief = 0; char *tun = "", *file = "/dev/net/tun", *name = argv[0], *end; while ((opt = getopt(argc, argv, "bd:f:t:u:g:")) > 0) { switch (opt) { case 'b': brief = 1; break; case 'd': delete = 1; tun = optarg; break; case 'f': file = optarg; break; case 'u': pw = getpwnam(optarg); if (pw != NULL) { owner = pw->pw_uid; break; } owner = strtol(optarg, &end, 0); if (*end != '\0') { fprintf(stderr, "'%s' is neither a username nor a numeric uid.\n", optarg); Usage(name); } break; case 'g': gr = getgrnam(optarg); if (gr != NULL) { group = gr->gr_gid; break; } group = strtol(optarg, &end, 0); if (*end != '\0') { fprintf(stderr, "'%s' is neither a groupname nor a numeric group.\n", optarg); Usage(name); } break; case 't': tun = optarg; break; case 'h': default: Usage(name); } } argv += optind; argc -= optind; if (argc > 0) Usage(name); if ((tap_fd = open(file, O_RDWR)) < 0) { fprintf(stderr, "Failed to open '%s' : ", file); perror(""); exit(1); } memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TAP | IFF_NO_PI; strncpy(ifr.ifr_name, tun, sizeof(ifr.ifr_name) - 1); if (ioctl(tap_fd, TUNSETIFF, (void *) &ifr) < 0) { perror("TUNSETIFF"); exit(1); } if (delete) { if (ioctl(tap_fd, TUNSETPERSIST, 0) < 0) { perror("disabling TUNSETPERSIST"); exit(1); } printf("Set '%s' nonpersistent\n", ifr.ifr_name); } else { /* emulate behaviour prior to TUNSETGROUP */ if (owner == (uid_t) - 1 && group == (gid_t) - 1) { owner = geteuid(); } if (owner != (uid_t) - 1) { if (ioctl(tap_fd, TUNSETOWNER, owner) < 0) { perror("TUNSETOWNER"); exit(1); } } if (group != (gid_t) - 1) { if (ioctl(tap_fd, TUNSETGROUP, group) < 0) { perror("TUNSETGROUP"); exit(1); } } if (ioctl(tap_fd, TUNSETPERSIST, 1) < 0) { perror("enabling TUNSETPERSIST"); exit(1); } if (brief) printf("%s\n", ifr.ifr_name); else { printf("Set '%s' persistent and owned by", ifr.ifr_name); if (owner != (uid_t) - 1) printf(" uid %d", owner); if (group != (gid_t) - 1) printf(" gid %d", group); printf("\n"); } } return(0); } Pretty standard stuff.... I create my TAP interface using the following command. /tmp # ./tunctl -t tap0 Then I plumb the interface using the following command. /tmp # ifconfig tap0 inet 192.168.0.65 -arp At this point, everyting looks good.. I can ping the tap0 interface and it seems to work correctly. I can also ssh into my uclinux box over the tap0 iinterface. But, the following code works great on standard Linux but will not work correctly on my uclinux box. It seems to hang at the read() call and nothing gets returned.. /* * */ #include <net/if.h> #include <linux/if_tun.h> #include <sys/types.h> #include <sys/select.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <sys/stat.h> #include <sys/select.h> #include <errno.h> #include <stdarg.h> #include <unistd.h> #include <string.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> int tun_alloc(char *dev, int flags) { struct ifreq ifr; int fd, err; char *clonedev = "/dev/net/tun"; /* Arguments taken by the function: * * char *dev: the name of an interface (or '\0'). MUST have enough * space to hold the interface name if '\0' is passed * int flags: interface flags (eg, IFF_TUN etc.) */ /* open the clone device */ if ((fd = open(clonedev, O_RDWR | O_NONBLOCK)) < 0) { fprintf(stderr, "Tunnel open.. %d", errno); return fd; } /* preparation of the struct ifr, of type "struct ifreq" */ memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = flags; /* IFF_TUN or IFF_TAP, plus maybe IFF_NO_PI */ if (*dev) { /* if a device name was specified, put it in the structure; otherwise, * the kernel will try to allocate the "next" device of the * specified type */ strncpy(ifr.ifr_name, dev, IFNAMSIZ); } /* try to create the device */ if ((err = ioctl(fd, TUNSETIFF, (void *) &ifr)) == -1) { fprintf(stderr, "Tunnel set if.. %d", err); close(fd); return err; } /* if the operation was successful, write back the name of the * interface to the variable "dev", so the caller can know * it. Note that the caller MUST reserve space in *dev (see calling * code below) */ strcpy(dev, ifr.ifr_name); printf("fd = %d\n", fd); /* this is the special file descriptor that the caller will use to talk * with the virtual interface */ return fd; } int main(int argc, char **argv) { int tuntap_fd; unsigned int features; int nread; unsigned char buffer[2048]; char tun_name[IFNAMSIZ]; fd_set readfs; int rval; /* Connect to the device */ strcpy(tun_name, "tap0"); tuntap_fd = tun_alloc(tun_name, IFF_TAP | IFF_NO_PI); /* tun interface */ if (tuntap_fd == -1) { fprintf(stderr, "tun_alloc: error %d\n", tuntap_fd); exit(tuntap_fd); } if (ioctl(tuntap_fd, TUNGETFEATURES, (void *) &features) == -1) { perror("Tunnel get features"); close(tuntap_fd); return errno; } printf("Device %s features = 0x%x\n", tun_name, features); while (1) { FD_ZERO(&readfs); FD_SET(tuntap_fd, &readfs); /* set testing for source tun/tap */ printf("starting select..\n"); /* block until input becomes available */ select(tuntap_fd + 1, &readfs, NULL, NULL, NULL); printf("finished select..\n"); if (FD_ISSET(tuntap_fd, &readfs)) { if ((rval = read(tuntap_fd, buffer, sizeof(buffer))) > 0) { fprintf(stdout, "read %d bytes\n", rval); fflush(stdout); } } } exit(0); } Any suggestions about why this is acting this way and how to fix it are MOST APPRECIATED!! Thanks. -brad w.
_______________________________________________ uClinux-dev mailing list uClinux-dev@uclinux.org http://mailman.uclinux.org/mailman/listinfo/uclinux-dev This message was resent by uclinux-dev@uclinux.org To unsubscribe see: http://mailman.uclinux.org/mailman/options/uclinux-dev