/* * ioctl-based device configuration */ #include #include #include #include #include #include #include #include #include #include #include #include #include "netdev.h" static int cfd = -1; static void copy_name(struct netdev *dev, struct ifreq *ifr) { strncpy(ifr->ifr_name, dev->name, sizeof(ifr->ifr_name)); ifr->ifr_name[sizeof(ifr->ifr_name) - 1] = '\0'; } int netdev_getflags(struct netdev *dev, short *flags) { struct ifreq ifr; copy_name(dev, &ifr); if (ioctl(cfd, SIOCGIFFLAGS, &ifr) == -1) { perror("SIOCGIFFLAGS"); return -1; } *flags = ifr.ifr_flags; return 0; } static int netdev_sif_addr(struct ifreq *ifr, int cmd, uint32_t addr) { struct sockaddr_in sin; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = addr; memcpy(&ifr->ifr_addr, &sin, sizeof sin); return ioctl(cfd, cmd, ifr); } int netdev_setaddress(struct netdev *dev) { struct ifreq ifr; copy_name(dev, &ifr); if (dev->ip_addr != INADDR_ANY && netdev_sif_addr(&ifr, SIOCSIFADDR, dev->ip_addr) == -1) { perror("SIOCSIFADDR"); return -1; } if (dev->ip_broadcast != INADDR_ANY && netdev_sif_addr(&ifr, SIOCSIFBRDADDR, dev->ip_broadcast) == -1) { perror("SIOCSIFBRDADDR"); return -1; } if (dev->ip_netmask != INADDR_ANY && netdev_sif_addr(&ifr, SIOCSIFNETMASK, dev->ip_netmask) == -1) { perror("SIOCSIFNETMASK"); return -1; } return 0; } static void set_s_addr(struct sockaddr *saddr, uint32_t ipaddr) { struct sockaddr_in sin = { .sin_family = AF_INET, .sin_addr.s_addr = ipaddr, }; memcpy(saddr, &sin, sizeof sin); } int netdev_setdefaultroute(struct netdev *dev) { struct rtentry r; if (dev->ip_gateway == INADDR_ANY) return 0; memset(&r, 0, sizeof(r)); set_s_addr(&r.rt_dst, INADDR_ANY); set_s_addr(&r.rt_gateway, dev->ip_gateway); set_s_addr(&r.rt_genmask, INADDR_ANY); r.rt_flags = RTF_UP | RTF_GATEWAY; if (ioctl(cfd, SIOCADDRT, &r) == -1 && errno != EEXIST) { perror("SIOCADDRT"); return -1; } return 0; } int netdev_setmtu(struct netdev *dev) { struct ifreq ifr; copy_name(dev, &ifr); ifr.ifr_mtu = dev->mtu; return ioctl(cfd, SIOCSIFMTU, &ifr); } static int netdev_gif_addr(struct ifreq *ifr, int cmd, uint32_t * ptr) { struct sockaddr_in *sin = (struct sockaddr_in *)&ifr->ifr_addr; if (ioctl(cfd, cmd, ifr) == -1) return -1; *ptr = sin->sin_addr.s_addr; return 0; } int netdev_up(struct netdev *dev) { struct ifreq ifr; copy_name(dev, &ifr); if (ioctl(cfd, SIOCGIFFLAGS, &ifr) == -1) { perror("SIOCGIFFLAGS"); return -1; } ifr.ifr_flags |= IFF_UP; if (ioctl(cfd, SIOCSIFFLAGS, &ifr) == -1) { perror("SIOCSIFFLAGS"); return -1; } return 0; } int netdev_down(struct netdev *dev) { struct ifreq ifr; copy_name(dev, &ifr); if (ioctl(cfd, SIOCGIFFLAGS, &ifr) == -1) { perror("SIOCGIFFLAGS"); return -1; } ifr.ifr_flags &= ~IFF_UP; if (ioctl(cfd, SIOCSIFFLAGS, &ifr) == -1) { perror("SIOCSIFFLAGS"); return -1; } return 0; } int netdev_init_if(struct netdev *dev) { struct ifreq ifr; if (cfd == -1) cfd = socket(AF_INET, SOCK_DGRAM, 0); if (cfd == -1) { fprintf(stderr, "ipconfig: %s: socket(AF_INET): %s\n", dev->name, strerror(errno)); return -1; } copy_name(dev, &ifr); if (ioctl(cfd, SIOCGIFINDEX, &ifr) == -1) { fprintf(stderr, "ipconfig: %s: SIOCGIFINDEX: %s\n", dev->name, strerror(errno)); return -1; } dev->ifindex = ifr.ifr_ifindex; if (ioctl(cfd, SIOCGIFMTU, &ifr) == -1) { fprintf(stderr, "ipconfig: %s: SIOCGIFMTU: %s\n", dev->name, strerror(errno)); return -1; } dev->mtu = ifr.ifr_mtu; if (ioctl(cfd, SIOCGIFHWADDR, &ifr) == -1) { fprintf(stderr, "ipconfig: %s: SIOCGIFHWADDR: %s\n", dev->name, strerror(errno)); return -1; } dev->hwtype = ifr.ifr_hwaddr.sa_family; dev->hwlen = 0; switch (dev->hwtype) { case ARPHRD_ETHER: dev->hwlen = 6; break; case ARPHRD_EUI64: dev->hwlen = 8; break; case ARPHRD_LOOPBACK: dev->hwlen = 0; break; default: return -1; } memcpy(dev->hwaddr, ifr.ifr_hwaddr.sa_data, dev->hwlen); memset(dev->hwbrd, 0xff, dev->hwlen); /* * Try to get the current interface information. */ if (dev->ip_addr == INADDR_NONE && netdev_gif_addr(&ifr, SIOCGIFADDR, &dev->ip_addr) == -1) { fprintf(stderr, "ipconfig: %s: SIOCGIFADDR: %s\n", dev->name, strerror(errno)); dev->ip_addr = 0; dev->ip_broadcast = 0; dev->ip_netmask = 0; return 0; } if (dev->ip_broadcast == INADDR_NONE && netdev_gif_addr(&ifr, SIOCGIFBRDADDR, &dev->ip_broadcast) == -1) { fprintf(stderr, "ipconfig: %s: SIOCGIFBRDADDR: %s\n", dev->name, strerror(errno)); dev->ip_broadcast = 0; } if (dev->ip_netmask == INADDR_NONE && netdev_gif_addr(&ifr, SIOCGIFNETMASK, &dev->ip_netmask) == -1) { fprintf(stderr, "ipconfig: %s: SIOCGIFNETMASK: %s\n", dev->name, strerror(errno)); dev->ip_netmask = 0; } return 0; }