--- ./openvpn-2.1.1-org/tun.c	Fri Nov 20 22:09:14 2009
+++ ./openvpn-2.1.1/tun.c	Thu Apr 29 11:24:48 2010
@@ -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
@@ -701,7 +702,13 @@
 			    );
 	}
       else
-	no_tap_ifconfig ();
+          argv_printf (&argv,
+                            " %s %s %s netmask %s broadcast + up",
+                            IFCONFIG_PATH,
+                            actual,
+                            ifconfig_local,
+                            ifconfig_remote_netmask
+                            );
 
       argv_msg (M_INFO, &argv);
       if (!openvpn_execve_check (&argv, es, 0, "Solaris ifconfig phase-2 failed"))
@@ -1383,15 +1390,17 @@
 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;
 
-  ipv6_support (ipv6, false, tt);
+  ipv6_support (ipv6, true, tt);
+  memset(&ifr, 0x0, sizeof(ifr));
 
   if (tt->type == DEV_TYPE_NULL)
     {
@@ -1410,9 +1419,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;
@@ -1439,7 +1449,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)
@@ -1448,27 +1462,83 @@
   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 (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);
+    }
 
-  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);
-
   tt->actual_name = (char *) malloc (32);
   check_malloc_return (tt->actual_name);
 
   openvpn_snprintf (tt->actual_name, 32, "%s%d", dev_tuntap_type, ppa);
 
+  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");
+
+          /* Pop any modules on the stream */
+          while (true)
+            {
+                 if (ioctl (tt->ip_fd, I_POP, NULL) < 0)
+                     break;
+            }
+          /* Push arp module to ip_fd */
+          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);
+  }
+
   CLEAR (ifr);
-  strncpynt (ifr.ifr_name, tt->actual_name, sizeof (ifr.ifr_name));
-  ifr.ifr_ip_muxid = muxid;
+  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, SIOCSIFMUXID, &ifr) < 0)
+  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");
     }
 
@@ -1485,20 +1555,26 @@
   if (tt)
     {
       if (tt->ip_fd >= 0)
-	{
-	  struct ifreq ifr;
-	  CLEAR (ifr);
-	  strncpynt (ifr.ifr_name, tt->actual_name, sizeof (ifr.ifr_name));
+      {
+          struct lifreq ifr;
+          CLEAR (ifr);
+          strncpynt (ifr.lifr_name, tt->actual_name, sizeof (ifr.lifr_name));
 
-	  if (ioctl (tt->ip_fd, SIOCGIFFLAGS, &ifr) < 0)
-	    msg (M_WARN | M_ERRNO, "Can't get iface flags");
+          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)
-	    msg (M_WARN | M_ERRNO, "Can't get multiplexor id");
+          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;
 	}
@@ -1751,11 +1827,11 @@
       i = tt->topology == TOP_SUBNET ? IFF_BROADCAST : IFF_POINTOPOINT;
       i |= IFF_MULTICAST;
       if (ioctl (tt->fd, TUNSIFMODE, &i) < 0) {
-	msg (M_WARN | M_ERRNO, "ioctl(TUNSIFMODE): %s", strerror(errno));
+        msg (M_WARN | M_ERRNO, "ioctl(TUNSIFMODE): %s", strerror(errno));
       }
       i = 1;
       if (ioctl (tt->fd, TUNSIFHEAD, &i) < 0) {
-	msg (M_WARN | M_ERRNO, "ioctl(TUNSIFHEAD): %s", strerror(errno));
+        msg (M_WARN | M_ERRNO, "ioctl(TUNSIFHEAD): %s", strerror(errno));
       }
     }
 }
@@ -3299,19 +3375,19 @@
   bool ret = false;
   const IP_ADAPTER_INDEX_MAP *inter = get_interface_info (adapter_index, &gc);
 
-  if (inter)
-    {
-      DWORD status = IpReleaseAddress ((IP_ADAPTER_INDEX_MAP *)inter);
-      if (status == NO_ERROR)
+      if (inter)
 	{
-	  msg (D_TUNTAP_INFO, "TAP: DHCP address released");
-	  ret = true;
+	  DWORD status = IpReleaseAddress ((IP_ADAPTER_INDEX_MAP *)inter);
+	  if (status == NO_ERROR)
+	    {
+	      msg (D_TUNTAP_INFO, "TAP: DHCP address released");
+	      ret = true;
+	    }
+	  else
+	    msg (M_WARN, "NOTE: Release of DHCP-assigned IP address lease on TAP-Win32 adapter failed: %s (code=%u)",
+		 strerror_win32 (status, &gc),
+		 (unsigned int)status);
 	}
-      else
-	msg (M_WARN, "NOTE: Release of DHCP-assigned IP address lease on TAP-Win32 adapter failed: %s (code=%u)",
-	     strerror_win32 (status, &gc),
-	     (unsigned int)status);
-    }
 
   gc_free (&gc);
   return ret;
@@ -3333,19 +3409,19 @@
   bool ret = false;
   const IP_ADAPTER_INDEX_MAP *inter = get_interface_info (adapter_index, &gc);
 
-  if (inter)
-    {
-      DWORD status = IpRenewAddress ((IP_ADAPTER_INDEX_MAP *)inter);
-      if (status == NO_ERROR)
+      if (inter)
 	{
-	  msg (D_TUNTAP_INFO, "TAP: DHCP address renewal succeeded");
-	  ret = true;
+	  DWORD status = IpRenewAddress ((IP_ADAPTER_INDEX_MAP *)inter);
+	  if (status == NO_ERROR)
+	    {
+	      msg (D_TUNTAP_INFO, "TAP: DHCP address renewal succeeded");
+	      ret = true;
+	    }
+	  else
+	    msg (M_WARN, "WARNING: Failed to renew DHCP IP address lease on TAP-Win32 adapter: %s (code=%u)",
+		 strerror_win32 (status, &gc),
+		 (unsigned int)status);
 	}
-      else
-	msg (M_WARN, "WARNING: Failed to renew DHCP IP address lease on TAP-Win32 adapter: %s (code=%u)",
-	     strerror_win32 (status, &gc),
-	     (unsigned int)status);
-    }
   gc_free (&gc);
   return ret;
 }
