$NetBSD: patch-ac,v 1.7 2008/10/09 10:57:23 sborrill Exp $
--- tun.c.orig	2008-10-06 08:22:21.000000000 +0100
+++ tun.c	2008-10-09 10:06:50.000000000 +0100
@@ -63,6 +63,7 @@
 
 #ifdef TARGET_SOLARIS
 static void solaris_error_close (struct tuntap *tt, const struct env_set *es, const char *actual);
+#include <stropts.h>
 #endif
 
 bool
@@ -720,7 +721,12 @@
 			    );
 	}
       else
-	no_tap_ifconfig ();
+	openvpn_snprintf (command_line, sizeof (command_line),
+			  IFCONFIG_PATH " %s %s netmask %s broadcast + up",
+			  actual,
+			  ifconfig_local,
+			  ifconfig_remote_netmask
+			  );
 
       argv_msg (M_INFO, &argv);
       if (!openvpn_execve_check (&argv, es, 0, "Solaris ifconfig phase-2 failed"))
@@ -1020,7 +1026,37 @@
 	  if (dynamic && !has_digit((unsigned char *)dev))
 	    {
 	      int i;
-	      for (i = 0; i < 256; ++i)
+#if defined(TAPGIFNAME)
+	      /*
+	       * Perhaps we have a cloning device.  Try opening
+	       * the device without any appended digits,
+	       * and use ioctl(,TAPGIFNAME,) to get the resulting
+	       * interface name.
+	       */
+	      openvpn_snprintf (tunname, sizeof (tunname), "/dev/%s", dev);
+	      if ((tt->fd = open (tunname, O_RDWR)) > 0)
+		{
+		  struct ifreq ifr;
+ 		  if (ioctl (tt->fd, TAPGIFNAME, (void*)&ifr) < 0)
+		    {
+		      msg (D_READ_WRITE | M_ERRNO,
+			   "ioctl(,TAPGIFNAME,) failed for %s", tunname);
+		      close(tt->fd);
+		    }
+		  else
+		    {
+		      strlcpy (dynamic_name, ifr.ifr_name,
+			       sizeof (dynamic_name));
+		      dynamic_opened = true;
+		      msg (M_INFO, "TUN/TAP dynamic interface %s opened",
+			   dynamic_name);
+		    }
+		}
+	      if (!dynamic_opened)
+ 		msg (D_READ_WRITE | M_ERRNO, "Tried opening %s (failed)",
+		     tunname);
+#endif /* TAPGIFNAME */
+	      for (i = 0; i < 256 && !dynamic_opened; ++i)
 		{
 		  openvpn_snprintf (tunname, sizeof (tunname),
 				    "/dev/%s%d", dev, i);
@@ -1403,13 +1439,16 @@
 void
 open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt)
 {
-  int if_fd, muxid, ppa = -1;
-  struct ifreq ifr;
+  int if_fd, ip_muxid, arp_muxid, arp_fd, ppa = -1;
+  struct lifreq ifr;
   const char *ptr;
-  const char *ip_node;
+  const char *ip_node, *arp_node;
   const char *dev_tuntap_type;
   int link_type;
   bool is_tun;
+  struct strioctl strioc_if, strioc_ppa;
+
+  memset(&ifr, 0x0, sizeof(ifr));
 
   ipv6_support (ipv6, false, tt);
 
@@ -1430,9 +1469,10 @@
     }
   else if (tt->type == DEV_TYPE_TAP)
     {
-      ip_node = "/dev/ip";
+      ip_node = "/dev/udp";
       if (!dev_node)
 	dev_node = "/dev/tap";
+      arp_node = dev_node;
       dev_tuntap_type = "tap";
       link_type = I_PLINK; /* was: I_LINK */
       is_tun = false;
@@ -1459,7 +1499,11 @@
     msg (M_ERR, "Can't open %s", dev_node);
 
   /* Assign a new PPA and get its unit number. */
-  if ((ppa = ioctl (tt->fd, TUNNEWPPA, ppa)) < 0)
+  strioc_ppa.ic_cmd = TUNNEWPPA;
+  strioc_ppa.ic_timout = 0;
+  strioc_ppa.ic_len = sizeof(ppa);
+  strioc_ppa.ic_dp = (char *)&ppa;
+  if ((ppa = ioctl (tt->fd, I_STR, &strioc_ppa)) < 0)
     msg (M_ERR, "Can't assign new interface");
 
   if ((if_fd = open (dev_node, O_RDWR, 0)) < 0)
@@ -1468,27 +1512,81 @@
   if (ioctl (if_fd, I_PUSH, "ip") < 0)
     msg (M_ERR, "Can't push IP module");
 
-  /* Assign ppa according to the unit number returned by tun device */
-  if (ioctl (if_fd, IF_UNITSEL, (char *) &ppa) < 0)
-    msg (M_ERR, "Can't set PPA %d", ppa);
-
-  if ((muxid = ioctl (tt->ip_fd, link_type, if_fd)) < 0)
-    msg (M_ERR, "Can't link %s device to IP", dev_tuntap_type);
-
-  close (if_fd);
+  if (tt->type == DEV_TYPE_TUN) 
+    {
+      /* Assign ppa according to the unit number returned by tun device */
+      if (ioctl (if_fd, IF_UNITSEL, (char *) &ppa) < 0)
+	msg (M_ERR, "Can't set PPA %d", ppa);
+    }
 
   tt->actual_name = (char *) malloc (32);
   check_malloc_return (tt->actual_name);
 
   openvpn_snprintf (tt->actual_name, 32, "%s%d", dev_tuntap_type, ppa);
 
-  CLEAR (ifr);
-  strncpynt (ifr.ifr_name, tt->actual_name, sizeof (ifr.ifr_name));
-  ifr.ifr_ip_muxid = muxid;
+  if (tt->type == DEV_TYPE_TAP) 
+    {
+      if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) < 0)
+	msg (M_ERR, "Can't get flags\n");
+      strncpynt (ifr.lifr_name, tt->actual_name, 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)
+	msg (M_ERR, "Can't set PPA %d", ppa);              
+      if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) <0)
+	msg (M_ERR, "Can't get flags\n");
+      /* Push arp module to if_fd */
+      if (ioctl (if_fd, I_PUSH, "arp") < 0)
+	msg (M_ERR, "Can't push ARP module");
+
+      /* Push arp module to ip_fd */
+      if (ioctl (tt->ip_fd, I_POP, NULL) < 0)
+	msg (M_ERR, "I_POP failed\n");  
+      if (ioctl (tt->ip_fd, I_PUSH, "arp") < 0) 
+	msg (M_ERR, "Can't push ARP module\n");
+
+      /* Open arp_fd */
+      if ((arp_fd = open (arp_node, O_RDWR, 0)) < 0)
+	msg (M_ERR, "Can't open %s\n", arp_node);
+      /* Push arp module to arp_fd */          
+      if (ioctl (arp_fd, I_PUSH, "arp") < 0)
+	msg (M_ERR, "Can't push ARP module\n");
+
+      /* Set ifname to arp */
+      strioc_if.ic_cmd = SIOCSLIFNAME;
+      strioc_if.ic_timout = 0;
+      strioc_if.ic_len = sizeof(ifr);
+      strioc_if.ic_dp = (char *)&ifr;
+      if (ioctl(arp_fd, I_STR, &strioc_if) < 0){
+	msg (M_ERR, "Can't set ifname to arp\n");
+      }
+    }
+  
+  if ((ip_muxid = ioctl (tt->ip_fd, link_type, if_fd)) < 0)
+    msg (M_ERR, "Can't link %s device to IP", dev_tuntap_type);
+
+  if (tt->type == DEV_TYPE_TAP) {
+    if ((arp_muxid = ioctl (tt->ip_fd, link_type, arp_fd)) < 0)
+      msg (M_ERR, "Can't link %s device to ARP", dev_tuntap_type);
+    close (arp_fd);
+  }
 
-  if (ioctl (tt->ip_fd, SIOCSIFMUXID, &ifr) < 0)
+  close (if_fd);
+
+  CLEAR (ifr);
+  strncpynt (ifr.lifr_name, tt->actual_name, sizeof (ifr.lifr_name));
+  ifr.lifr_ip_muxid  = ip_muxid;
+  if (tt->type == DEV_TYPE_TAP) {
+    ifr.lifr_arp_muxid = arp_muxid;
+  }
+  
+  if (ioctl (tt->ip_fd, SIOCSLIFMUXID, &ifr) < 0)
     {
-      ioctl (tt->ip_fd, I_PUNLINK, muxid);
+      if (tt->type == DEV_TYPE_TAP) 
+        {
+	  ioctl (tt->ip_fd, I_PUNLINK , arp_muxid);
+        }
+      ioctl (tt->ip_fd, I_PUNLINK, ip_muxid);
       msg (M_ERR, "Can't set multiplexor id");
     }
 
@@ -1506,18 +1604,24 @@
     {
       if (tt->ip_fd >= 0)
 	{
-	  struct ifreq ifr;
+	  struct lifreq ifr;
 	  CLEAR (ifr);
-	  strncpynt (ifr.ifr_name, tt->actual_name, sizeof (ifr.ifr_name));
+	  strncpynt (ifr.lifr_name, tt->actual_name, sizeof (ifr.lifr_name));
 
-	  if (ioctl (tt->ip_fd, SIOCGIFFLAGS, &ifr) < 0)
+	  if (ioctl (tt->ip_fd, SIOCGLIFFLAGS, &ifr) < 0)
 	    msg (M_WARN | M_ERRNO, "Can't get iface flags");
 
-	  if (ioctl (tt->ip_fd, SIOCGIFMUXID, &ifr) < 0)
+	  if (ioctl (tt->ip_fd, SIOCGLIFMUXID, &ifr) < 0)
 	    msg (M_WARN | M_ERRNO, "Can't get multiplexor id");
 
-	  if (ioctl (tt->ip_fd, I_PUNLINK, ifr.ifr_ip_muxid) < 0)
-	    msg (M_WARN | M_ERRNO, "Can't unlink interface");
+	  if (tt->type == DEV_TYPE_TAP)
+            {
+	      if (ioctl (tt->ip_fd, I_PUNLINK, ifr.lifr_arp_muxid) < 0)
+		msg (M_WARN | M_ERRNO, "Can't unlink interface(arp)");
+	    }
+
+	  if (ioctl (tt->ip_fd, I_PUNLINK, ifr.lifr_ip_muxid) < 0)
+	    msg (M_WARN | M_ERRNO, "Can't unlink interface(ip)");
 
 	  close (tt->ip_fd);
 	  tt->ip_fd = -1;
