-int device_type;
-char *device_fname;
-char *device_info;
-
-int device_total_in = 0;
-int device_total_out = 0;
-
-int setup_device(void)
-{
- int ip_fd = -1, if_fd = -1;
- int ppa;
- char *ptr;
-
-cp
- if(!get_config_string(lookup_config(config_tree, "Device"), &device_fname)))
- device_fname = DEFAULT_DEVICE;
-
-cp
- if((device_fd = open(device_fname, O_RDWR | O_NONBLOCK)) < 0)
- {
- syslog(LOG_ERR, _("Could not open %s: %m"), device_fname);
- return -1;
- }
-cp
- ppa = 0;
-
- ptr = fname;
- while(*ptr && !isdigit((int)*ptr)) ptr++;
- ppa = atoi(ptr);
-
- if( (ip_fd = open("/dev/ip", O_RDWR, 0)) < 0){
- syslog(LOG_ERR, _("Could not open /dev/ip: %m"));
- return -1;
- }
-
- /* Assign a new PPA and get its unit number. */
- if( (ppa = ioctl(fd, TUNNEWPPA, ppa)) < 0){
- syslog(LOG_ERR, _("Can't assign new interface: %m"));
- return -1;
- }
-
- if( (if_fd = open(fname, O_RDWR, 0)) < 0){
- syslog(LOG_ERR, _("Could not open %s twice: %m"), fname);
- return -1;
- }
-
- if(ioctl(if_fd, I_PUSH, "ip") < 0){
- syslog(LOG_ERR, _("Can't push IP module: %m"));
- return -1;
- }
-
- /* Assign ppa according to the unit number returned by tun device */
- if(ioctl(if_fd, IF_UNITSEL, (char *)&ppa) < 0){
- syslog(LOG_ERR, _("Can't set PPA %d: %m"), ppa);
- return -1;
- }
-
- if(ioctl(ip_fd, I_LINK, if_fd) < 0){
- syslog(LOG_ERR, _("Can't link TUN device to IP: %m"));
- return -1;
- }
-
- device_info = _("Solaris tun device");
-
- /* Set default MAC address for ethertap devices */
-
- mymac.type = SUBNET_MAC;
- mymac.net.mac.address.x[0] = 0xfe;
- mymac.net.mac.address.x[1] = 0xfd;
- mymac.net.mac.address.x[2] = 0x00;
- mymac.net.mac.address.x[3] = 0x00;
- mymac.net.mac.address.x[4] = 0x00;
- mymac.net.mac.address.x[5] = 0x00;
-
- syslog(LOG_INFO, _("%s is a %s"), device_fname, device_info);
-cp
- return 0;
+static int if_fd = -1;
+static int ip_fd = -1;
+char *device = NULL;
+char *iface = NULL;
+static const char *device_info = NULL;
+
+uint64_t device_total_in = 0;
+uint64_t device_total_out = 0;
+
+static bool setup_device(void) {
+ char *type;
+
+ if(!get_config_string(lookup_config(config_tree, "Device"), &device)) {
+ if(routing_mode == RMODE_ROUTER) {
+ device = xstrdup(DEFAULT_TUN_DEVICE);
+ } else {
+ device = xstrdup(DEFAULT_TAP_DEVICE);
+ }
+ }
+
+ if(get_config_string(lookup_config(config_tree, "DeviceType"), &type)) {
+ if(!strcasecmp(type, "tun"))
+ /* use default */;
+ else if(!strcasecmp(type, "tap")) {
+ device_type = DEVICE_TYPE_TAP;
+ } else {
+ logger(LOG_ERR, "Unknown device type %s!", type);
+ return false;
+ }
+ } else {
+ if(strstr(device, "tap") || routing_mode != RMODE_ROUTER) {
+ device_type = DEVICE_TYPE_TAP;
+ }
+ }
+
+ if(device_type == DEVICE_TYPE_TUN) {
+ device_info = "Solaris tun device";
+ } else {
+ device_info = "Solaris tap device";
+ }
+
+ if(device_type == DEVICE_TYPE_TAP && routing_mode == RMODE_ROUTER) {
+ overwrite_mac = true;
+ }
+
+ /* The following is black magic copied from OpenVPN. */
+
+ if((ip_fd = open(IP_DEVICE, O_RDWR, 0)) < 0) {
+ logger(LOG_ERR, "Could not open %s: %s\n", IP_DEVICE, strerror(errno));
+ return false;
+ }
+
+ if((device_fd = open(device, O_RDWR, 0)) < 0) {
+ logger(LOG_ERR, "Could not open %s: %s\n", device, strerror(errno));
+ return false;
+ }
+
+ /* Get unit number. */
+
+ char *ptr = device;
+ get_config_string(lookup_config(config_tree, "Interface"), &ptr);
+
+ while(*ptr && !isdigit(*ptr)) {
+ ptr++;
+ }
+
+ int ppa = atoi(ptr);
+
+ /* Assign a new PPA and get its unit number. */
+
+ struct strioctl strioc_ppa = {
+ .ic_cmd = TUNNEWPPA,
+ .ic_len = sizeof(ppa),
+ .ic_dp = (char *) &ppa,
+ };
+
+ if(!*ptr) { /* no number given, try dynamic */
+ bool found = false;
+
+ while(!found && ppa < 64) {
+ int new_ppa = ioctl(device_fd, I_STR, &strioc_ppa);
+
+ if(new_ppa >= 0) {
+ ppa = new_ppa;
+ found = true;
+ break;
+ }
+
+ ppa++;
+ }
+
+ if(!found) {
+ logger(LOG_ERR, "Could not find free PPA for %s %s!", device_info, device);
+ return false;
+ }
+ } else { /* try this particular one */
+ if((ppa = ioctl(device_fd, I_STR, &strioc_ppa)) < 0) {
+ logger(LOG_ERR, "Could not assign PPA %d for %s %s!", ppa, device_info, device);
+ return false;
+ }
+ }
+
+ if((if_fd = open(device, O_RDWR, 0)) < 0) {
+ logger(LOG_ERR, "Could not open %s: %s\n", device, strerror(errno));
+ return false;
+ }
+
+ if(ioctl(if_fd, I_PUSH, "ip") < 0) {
+ logger(LOG_ERR, "Could not push IP module onto %s %s!", device_info, device);
+ return false;
+ }
+
+ xasprintf(&iface, "%s%d", device_type == DEVICE_TYPE_TUN ? "tun" : "tap", ppa);
+
+ {
+ /* Remove muxes just in case they are left over from a crashed tincd */
+ struct lifreq ifr = {};
+ strncpy(ifr.lifr_name, iface, sizeof(ifr.lifr_name));
+
+ if(ioctl(ip_fd, SIOCGLIFMUXID, &ifr) >= 0) {
+ int muxid = ifr.lifr_arp_muxid;
+ ioctl(ip_fd, I_PUNLINK, muxid);
+ muxid = ifr.lifr_ip_muxid;
+ ioctl(ip_fd, I_PUNLINK, muxid);
+ }
+ }
+
+ if(device_type == DEVICE_TYPE_TUN) {
+ /* Assign ppa according to the unit number returned by tun device */
+ if(ioctl(if_fd, IF_UNITSEL, (char *)&ppa) < 0) {
+ logger(LOG_ERR, "Could not set PPA %d on %s %s!", ppa, device_info, device);
+ return false;
+ }
+ }
+
+ int arp_fd = -1;
+
+ if(device_type == DEVICE_TYPE_TAP) {
+ struct lifreq ifr = {};
+
+ if(ioctl(if_fd, SIOCGLIFFLAGS, &ifr) < 0) {
+ logger(LOG_ERR, "Could not set flags on %s %s!", device_info, device);
+ return false;
+ }
+
+ strncpy(ifr.lifr_name, iface, sizeof(ifr.lifr_name));
+ ifr.lifr_ppa = ppa;
+
+ /* Assign ppa according to the unit number returned by tun device */
+ if(ioctl(if_fd, SIOCSLIFNAME, &ifr) < 0) {
+ logger(LOG_ERR, "Could not set PPA %d on %s %s!", ppa, device_info, device);
+ return false;
+ }
+
+ if(ioctl(if_fd, SIOCGLIFFLAGS, &ifr) < 0) {
+ logger(LOG_ERR, "Could not set flags on %s %s!", device_info, device);
+ return false;
+ }
+
+ /* Push arp module to if_fd */
+ if(ioctl(if_fd, I_PUSH, "arp") < 0) {
+ logger(LOG_ERR, "Could not push ARP module onto %s %s!", device_info, device);
+ return false;
+ }
+
+ /* Pop any modules on the stream */
+ while(true) {
+ if(ioctl(ip_fd, I_POP, NULL) < 0) {
+ break;
+ }
+ }
+
+ /* Push arp module to ip_fd */
+ if(ioctl(ip_fd, I_PUSH, "arp") < 0) {
+ logger(LOG_ERR, "Could not push ARP module onto %s!", IP_DEVICE);
+ return false;
+ }
+
+ /* Open arp_fd */
+ if((arp_fd = open(device, O_RDWR, 0)) < 0) {
+ logger(LOG_ERR, "Could not open %s: %s\n", device, strerror(errno));
+ return false;
+ }
+
+ /* Push arp module to arp_fd */
+ if(ioctl(arp_fd, I_PUSH, "arp") < 0) {
+ logger(LOG_ERR, "Could not push ARP module onto %s %s!", device_info, device);
+ return false;
+ }
+
+ /* Set ifname to arp */
+ struct strioctl strioc_if = {
+ .ic_cmd = SIOCSLIFNAME,
+ .ic_len = sizeof(ifr),
+ .ic_dp = (char *) &ifr,
+ };
+
+ if(ioctl(arp_fd, I_STR, &strioc_if) < 0) {
+ logger(LOG_ERR, "Could not set ifname to %s %s", device_info, device);
+ return false;
+ }
+ }
+
+ int ip_muxid, arp_muxid;
+
+ if((ip_muxid = ioctl(ip_fd, I_PLINK, if_fd)) < 0) {
+ logger(LOG_ERR, "Could not link %s %s to IP", device_info, device);
+ return false;
+ }
+
+ if(device_type == DEVICE_TYPE_TAP) {
+ if((arp_muxid = ioctl(ip_fd, I_PLINK, arp_fd)) < 0) {
+ logger(LOG_ERR, "Could not link %s %s to ARP", device_info, device);
+ return false;
+ }
+
+ close(arp_fd);
+ }
+
+ struct lifreq ifr = {};
+
+ strncpy(ifr.lifr_name, iface, sizeof(ifr.lifr_name));
+
+ ifr.lifr_ip_muxid = ip_muxid;
+
+ if(device_type == DEVICE_TYPE_TAP) {
+ ifr.lifr_arp_muxid = arp_muxid;
+ }
+
+ if(ioctl(ip_fd, SIOCSLIFMUXID, &ifr) < 0) {
+ if(device_type == DEVICE_TYPE_TAP) {
+ ioctl(ip_fd, I_PUNLINK, arp_muxid);
+ }
+
+ ioctl(ip_fd, I_PUNLINK, ip_muxid);
+ logger(LOG_ERR, "Could not set multiplexor id for %s %s", device_info, device);
+ return false;
+ }
+
+ close(if_fd);
+
+#ifdef FD_CLOEXEC
+ fcntl(device_fd, F_SETFD, FD_CLOEXEC);
+ fcntl(ip_fd, F_SETFD, FD_CLOEXEC);
+#endif
+
+ logger(LOG_INFO, "%s is a %s", device, device_info);
+
+ return true;
+}
+
+static void close_device(void) {
+ if(iface) {
+ struct lifreq ifr = {};
+ strncpy(ifr.lifr_name, iface, sizeof(ifr.lifr_name));
+
+ if(ioctl(ip_fd, SIOCGLIFMUXID, &ifr) >= 0) {
+ int muxid = ifr.lifr_arp_muxid;
+ ioctl(ip_fd, I_PUNLINK, muxid);
+ muxid = ifr.lifr_ip_muxid;
+ ioctl(ip_fd, I_PUNLINK, muxid);
+ }
+ }
+
+ close(ip_fd);
+ close(device_fd);
+
+ free(device);
+ free(iface);