--- linux-2.2.20/arch/sparc64/kernel/ioctl32.c	Fri Nov  2 11:39:06 2001
+++ linux/arch/sparc64/kernel/ioctl32.c	Sat Dec 22 05:20:53 2001
@@ -29,6 +29,8 @@
 #include <linux/fd.h>
 #include <linux/ppp_defs.h>
 #include <linux/if_ppp.h>
+#include <linux/ip.h>
+#include <linux/if_tunnel.h>
 #include <linux/mtio.h>
 #include <linux/cdrom.h>
 #include <linux/loop.h>
@@ -45,6 +47,7 @@
 #include <linux/ipv6_route.h>
 #include <linux/pci.h>
 #include <net/sock.h>
+#include <linux/string.h>
 
 #include <scsi/scsi.h>
 /* Ugly hack. */
@@ -533,31 +536,46 @@
 		if (err)
 			return -EFAULT;
 		break;
-	case SIOCGPPPSTATS:
-	case SIOCGPPPCSTATS:
-	case SIOCGPPPVER:
+	case SIOCDEVPRIVATE:
+	case (SIOCDEVPRIVATE+1):
+	case (SIOCDEVPRIVATE+2):
+	case (SIOCDEVPRIVATE+3):
 	case SIOCETHTOOL:
+	{
+		int len;
+		
 		if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
 			return -EFAULT;
 		ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL);
 		if (!ifr.ifr_data)
 			return -EAGAIN;
-		if(cmd == SIOCETHTOOL) {
-			u32 data;
+		if(cmd == SIOCETHTOOL) 
+			len = sizeof(struct ethtool_cmd);
+		else if((!strncmp(ifr.ifr_name, "tunl", 4)) || 
+			(!strncmp(ifr.ifr_name, "gre", 3)))
+			len = sizeof(struct ip_tunnel_parm);
+		else
+			len = 0;
 
+		if(len) {
+			u32 data;
+			
 			__get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data));
 			if(copy_from_user(ifr.ifr_data,
 					  (char *)A(data),
-					  sizeof(struct ethtool_cmd))) {
+					  len)) {
 				free_page((unsigned long)ifr.ifr_data);
 				return -EFAULT;
 			}
 		}
+			
 		break;
+	}
 	default:
 		if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
 			return -EFAULT;
 		break;
+	
 	}
 	old_fs = get_fs();
 	set_fs (KERNEL_DS);
@@ -579,9 +597,10 @@
 			if (copy_to_user((struct ifreq32 *)arg, &ifr, sizeof(struct ifreq32)))
 				return -EFAULT;
 			break;
-		case SIOCGPPPSTATS:
-		case SIOCGPPPCSTATS:
-		case SIOCGPPPVER:
+		case SIOCDEVPRIVATE:
+		case (SIOCDEVPRIVATE+1):
+		case (SIOCDEVPRIVATE+2):
+		case (SIOCDEVPRIVATE+3):
 		case SIOCETHTOOL:
 		{
 			u32 data;
@@ -590,14 +609,20 @@
 			__get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data));
 			if(cmd == SIOCETHTOOL)
 				len = sizeof(struct ethtool_cmd);
-			if(cmd == SIOCGPPPVER)
-				len = strlen(PPP_VERSION) + 1;
-			else if(cmd == SIOCGPPPCSTATS)
-				len = sizeof(struct ppp_comp_stats);
+			if(!strncmp(ifr.ifr_name, "ppp", 3)) {
+				if(cmd == SIOCGPPPVER)
+					len = strlen(PPP_VERSION) + 1;
+				else if(cmd == SIOCGPPPCSTATS)
+					len = sizeof(struct ppp_comp_stats);
+				else
+					len = sizeof(struct ppp_stats);
+			} else if((!strncmp(ifr.ifr_name, "tunl", 4)) || 
+				  (!strncmp(ifr.ifr_name, "gre", 3)))
+				len = sizeof(struct ip_tunnel_parm);
 			else
-				len = sizeof(struct ppp_stats);
-
-			len = copy_to_user((char *)A(data), ifr.ifr_data, len);
+				len = 0;
+			if(len)
+				len = copy_to_user((char *)A(data), ifr.ifr_data, len);
 			free_page((unsigned long)ifr.ifr_data);
 			if(len)
 				return -EFAULT;
@@ -2373,9 +2398,10 @@
 	case SIOCSIFNETMASK:
 	case SIOCSIFPFLAGS:
 	case SIOCGIFPFLAGS:
-	case SIOCGPPPSTATS:
-	case SIOCGPPPCSTATS:
-	case SIOCGPPPVER:
+	case SIOCDEVPRIVATE:
+	case (SIOCDEVPRIVATE+1):
+	case (SIOCDEVPRIVATE+2):
+	case (SIOCDEVPRIVATE+3):
 	case SIOCGIFTXQLEN:
 	case SIOCSIFTXQLEN:
 	case SIOCETHTOOL:
