Initial load
diff --git a/test/java/net/ipv6tests/B6521014.java b/test/java/net/ipv6tests/B6521014.java
new file mode 100644
index 0000000..9834472
--- /dev/null
+++ b/test/java/net/ipv6tests/B6521014.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6521014 6543428
+ * @summary IOException thrown when Socket tries to bind to an local IPv6 address on SuSE Linux
+ */
+
+
+import java.net.*;
+import java.io.*;
+import java.util.*;
+
+
+/*
+ *
+ * What this testcase is to test is a (weird) coupling through the
+ * cached_scope_id field of java.net.Inet6Address. Native method
+ * NET_InetAddressToSockaddr as in Linux platform will try to write
+ * and read this field, therefore Inet6Address becomes 'stateful'.
+ * So the coupling. Certain executive order, e.g. two methods use
+ * the same Inet6Address instance as illustrated in this test case,
+ * will show side effect of such coupling.
+ *
+ * And on Windows, NET_InetAddressToSockaddr() did not assign appropriate
+ * sin6_scope_id value to sockaddr_in6 structure if there's no one coming
+ * with Inet6Address instance, which caused bind exception. This test use
+ * link-local address without %scope suffix, so it is also going to test
+ * that.
+ *
+ */
+public class B6521014 {
+
+    static InetAddress sin;
+
+    static Inet6Address getLocalAddr () throws Exception {
+        Enumeration e = NetworkInterface.getNetworkInterfaces();
+        while (e.hasMoreElements()) {
+            NetworkInterface ifc = (NetworkInterface) e.nextElement();
+            Enumeration addrs = ifc.getInetAddresses();
+            while (addrs.hasMoreElements()) {
+                InetAddress a = (InetAddress)addrs.nextElement();
+                if (a instanceof Inet6Address) {
+                    Inet6Address ia6 = (Inet6Address) a;
+                    if (ia6.isLinkLocalAddress()) {
+                        // remove %scope suffix
+                        return (Inet6Address)InetAddress.getByAddress(ia6.getAddress());
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    static void test1() throws Exception {
+        ServerSocket ssock;
+        Socket sock;
+        int port;
+
+        ssock = new ServerSocket(0);
+        port = ssock.getLocalPort();
+        sock = new Socket();
+        try {
+            sock.connect(new InetSocketAddress(sin, port), 100);
+        } catch (SocketTimeoutException e) {
+            // time out exception is okay
+            System.out.println("timed out when connecting.");
+        }
+    }
+
+    static void test2() throws Exception {
+        Socket sock;
+        ServerSocket ssock;
+        int port;
+        int localport;
+
+        ssock = new ServerSocket(0);
+        ssock.setSoTimeout(100);
+        port = ssock.getLocalPort();
+        localport = port + 1;
+        sock = new Socket();
+        sock.bind(new InetSocketAddress(sin, localport));
+        try {
+            sock.connect(new InetSocketAddress(sin, port), 100);
+        } catch (SocketTimeoutException e) {
+            // time out exception is okay
+            System.out.println("timed out when connecting.");
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        sin = getLocalAddr();
+        if (sin == null) {
+            System.out.println("Cannot find a link-local address.");
+            return;
+        }
+
+        try {
+            test1();
+            test2();
+        } catch (IOException e) {
+            throw new RuntimeException("Test failed: cannot create socket.", e);
+        }
+    }
+}
diff --git a/test/java/net/ipv6tests/BadIPv6Addresses.java b/test/java/net/ipv6tests/BadIPv6Addresses.java
new file mode 100644
index 0000000..44f3bbf
--- /dev/null
+++ b/test/java/net/ipv6tests/BadIPv6Addresses.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 4742177
+ * @summary Re-test IPv6 (and specifically MulticastSocket) with latest Linux & USAGI code
+ */
+import java.net.*;
+import java.util.*;
+
+
+public class BadIPv6Addresses {
+    public static void main(String[] args) throws Exception {
+        String[] badAddresses = new String[] {
+            "0:1:2:3:4:5:6:7:8",        // too many :
+            "0:1:2:3:4:5:6",            // not enough :
+            "0:1:2:3:4:5:6:x",          // bad digits
+            "0:1:2:3:4:5:6::7",         // adjacent :
+            "0:1:2:3:4:5:6:789abcdef",  // too many digits
+            "0:1:2:3::x",               // compressed, bad digits
+            "0:1:2:::3",                // compressed, too many adjacent :
+            "0:1:2:3::abcde",           // compressed, too many digits
+            "0:1",                      // compressed, not enough :
+            "0:0:0:0:0:x:10.0.0.1",     // with embeded ipv4, bad ipv6 digits
+            "0:0:0:0:0:0:10.0.0.x",     // with embeded ipv4, bad ipv4 digits
+            "0:0:0:0:0::0:10.0.0.1",    // with embeded ipv4, adjacent :
+            "0:0:0:0:0:fffff:10.0.0.1", // with embeded ipv4, too many ipv6 digits
+            "0:0:0:0:0:0:0:10.0.0.1",   // with embeded ipv4, too many :
+            "0:0:0:0:0:10.0.0.1",       // with embeded ipv4, not enough :
+            "0:0:0:0:0:0:10.0.0.0.1",   // with embeded ipv4, too many .
+            "0:0:0:0:0:0:10.0.1",       // with embeded ipv4, not enough .
+            "0:0:0:0:0:0:10..0.0.1",    // with embeded ipv4, adjacent .
+            "::fffx:192.168.0.1",       // with compressed ipv4, bad ipv6 digits
+            "::ffff:192.168.0.x",       // with compressed ipv4, bad ipv4 digits
+            ":::ffff:192.168.0.1",      // with compressed ipv4, too many adjacent :
+            "::fffff:192.168.0.1",      // with compressed ipv4, too many ipv6 digits
+            "::ffff:1923.168.0.1",      // with compressed ipv4, too many ipv4 digits
+            ":ffff:192.168.0.1",        // with compressed ipv4, not enough :
+            "::ffff:192.168.0.1.2",     // with compressed ipv4, too many .
+            "::ffff:192.168.0",         // with compressed ipv4, not enough .
+            "::ffff:192.168..0.1"       // with compressed ipv4, adjacent .
+        };
+
+        List<String> failedAddrs = new ArrayList<String>();
+        for (String addrStr : badAddresses) {
+            try {
+                InetAddress addr = InetAddress.getByName(addrStr);
+
+                // it is an error if no exception
+                failedAddrs.add(addrStr);
+            } catch (UnknownHostException e) {
+                // expected
+            }
+        }
+
+        if (failedAddrs.size() > 0) {
+            System.out.println("We should reject following ipv6 addresses, but we didn't:");
+            for (String addr : failedAddrs) {
+                System.out.println("\t" + addr);
+            }
+            throw new RuntimeException("Test failed.");
+        }
+    }
+}
diff --git a/test/java/net/ipv6tests/ScopeTests.java b/test/java/net/ipv6tests/ScopeTests.java
new file mode 100644
index 0000000..f4029d9
--- /dev/null
+++ b/test/java/net/ipv6tests/ScopeTests.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2003 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 4868820
+ * @summary IPv6 support for Windows XP and 2003 server
+ */
+
+import java.net.*;
+import java.util.*;
+
+public class ScopeTests extends Tests {
+
+    public static void main (String[] args) throws Exception {
+        checkDebug (args);
+        simpleTests();
+        complexTests();
+        System.out.println ("Tests passed: OK");
+    }
+
+    static void sassert (boolean condition, String msg) throws Exception {
+        if (!condition) {
+            throw new Exception (msg);
+        }
+    }
+
+    static void checkAddress (String a, int numeric) throws Exception {
+        Inet6Address addr = (Inet6Address) InetAddress.getByName (a);
+        if (addr.getScopeId () != numeric) {
+            throw new Exception ("wroing numeric scopeid");
+        }
+    }
+
+    static void checkAddress (String a, String str) throws Exception {
+        Inet6Address addr = (Inet6Address) InetAddress.getByName (a);
+        if (!addr.getScopedInterface().getName().equals (str)) {
+            throw new Exception ("wroing scoped interface name");
+        }
+    }
+
+    /* These tests check generic API functionality that is not
+     * dependent on scoping being implemented in the platform
+     */
+    static void simpleTests () throws Exception {
+        checkAddress ("fe80::%1", 1);
+        checkAddress ("fe80::1%1", 1);
+        checkAddress ("fec0::1:a00:20ff:feed:b08d%0", 0);
+        checkAddress ("fec0::1:a00:20ff:feed:b08d%1", 1);
+        checkAddress ("fec0::1:a00:20ff:feed:b08d%99", 99);
+        checkAddress ("fe80::", 0);
+        checkAddress ("fec0::1:a00:20ff:feed:b08d", 0);
+        checkAddress ("fec0::1:a00:20ff:feed:b08d", 0);
+        checkAddress ("fec0::1:a00:20ff:feed:b08d", 0);
+    }
+
+    /* These tests check the NetworkInterfaces for the actual scopeids
+     * configured on the system and do tests using that information
+     */
+    static void complexTests () throws Exception {
+        dprintln ("ComplexTests");
+        Enumeration e = NetworkInterface.getNetworkInterfaces();
+        while (e.hasMoreElements()) {
+            NetworkInterface nif = (NetworkInterface)e.nextElement();
+            String name = nif.getName();
+            Enumeration addrs = nif.getInetAddresses();
+            while (addrs.hasMoreElements()) {
+                InetAddress addr = (InetAddress) addrs.nextElement();
+                dprintln ("ComplexTests: "+addr);
+                if (addr instanceof Inet6Address) {
+                    Inet6Address ia6 = (Inet6Address) addr;
+                    if (ia6.getScopeId() != 0) {
+                        System.out.println ("Testing interface: " + name +
+                                            " and address: " + ia6);
+                        ctest1 (name, ia6);
+                        ctest2 (name, ia6);
+                    } else {
+                        System.out.println ("Interface: " + name +
+                                            " Address: "+ ia6 +
+                                            " does not support scope");
+                    }
+                }
+            }
+        }
+    }
+
+
+   /* check the scoped name on the Inet6Address is the same as
+    * the interface it is attached to
+    */
+    static void ctest1 (String ifname, Inet6Address ia6) throws Exception {
+        System.out.println ("ctest1:" + ia6);
+        String s = ia6.getScopedInterface().getName();
+        int scope = ia6.getScopeId();
+        sassert (ifname.equals (s), "ctest1:"+ifname+":"+s);
+
+    }
+
+    /* create an Inet6Adddress by all three methods using the ifname
+     * compare the numeric scope id with that of the Inet6Address passed in
+     */
+    static void ctest2 (String ifname, Inet6Address ia6) throws Exception {
+        System.out.println ("ctest2:" + ia6);
+        String s = ia6.getScopedInterface().getName();
+        int scope = ia6.getScopeId();
+        String s1 = ia6.getHostAddress();
+        if (s1.indexOf('%') != -1) {
+            s1 = s1.substring (0, s1.indexOf ('%'));
+        }
+        Inet6Address add = (Inet6Address) InetAddress.getByName (s1+"%"+ifname);
+        sassert (add.getScopeId() == scope, "ctest2:1:" +scope);
+    }
+}
diff --git a/test/java/net/ipv6tests/TcpTest.java b/test/java/net/ipv6tests/TcpTest.java
new file mode 100644
index 0000000..ec07a8b
--- /dev/null
+++ b/test/java/net/ipv6tests/TcpTest.java
@@ -0,0 +1,265 @@
+/*
+ * Copyright 2003 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 4868820
+ * @summary IPv6 support for Windows XP and 2003 server
+ */
+
+import java.net.*;
+import java.io.*;
+
+public class TcpTest extends Tests {
+    static ServerSocket server, server1, server2;
+    static Socket c1, c2, c3, s1, s2, s3;
+    static InetAddress s1peer, s2peer;
+
+    static InetAddress ia4any;
+    static InetAddress ia6any;
+    static Inet6Address ia6addr;
+    static InetAddress ia6bad; /* a global 6to4 IPv6 address, which cant be connected to */
+    static Inet4Address ia4addr;
+
+    static {
+        ia6addr = getFirstLocalIPv6Address ();
+        ia4addr = getFirstLocalIPv4Address ();
+        try {
+            ia4any = InetAddress.getByName ("0.0.0.0");
+            ia6any = InetAddress.getByName ("::0");
+            int scope = ia6addr.getScopeId();
+            if (scope != 0) {
+                ia6bad = InetAddress.getByName ("fe80::1:2:3:4:5:6%"+scope);
+            } else {
+                ia6bad = InetAddress.getByName ("fe80::1:2:3:4:5:6");
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    public static void main (String[] args) throws Exception {
+        checkDebug(args);
+        if (ia6addr == null) {
+            System.out.println ("No IPV6 addresses: exiting test");
+            return;
+        }
+        dprintln ("Local Addresses");
+        dprintln (ia4addr.toString());
+        dprintln (ia6addr.toString());
+        dprintln ("Bad address: " + ia6bad);
+        test1 (0);
+        test1 (5100);
+        test2();
+        test3();
+        test4();
+    }
+
+    /* basic TCP connectivity test using IPv6 only and IPv4/IPv6 together */
+
+    static void test1 (int port) throws Exception {
+        server = new ServerSocket (port);
+        if (port == 0) {
+            port = server.getLocalPort();
+        }
+        // try Ipv6 only
+        c1 = new Socket ("::1", port);
+        s1 = server.accept ();
+        simpleDataExchange (c1, s1);
+        s1.close ();
+        c1.close();
+        // try with both IPv4 and Ipv6
+        c1 = new Socket ("127.0.0.1", port);
+        c2 = new Socket ("::1", port);
+        s1 = server.accept();
+        s2 = server.accept();
+        s1peer = s1.getInetAddress();
+        s2peer = s2.getInetAddress();
+        if (s1peer instanceof Inet6Address) {
+            t_assert ((s2peer instanceof Inet4Address));
+            simpleDataExchange (c2, s1);
+            simpleDataExchange (c1, s2);
+        } else {
+            t_assert ((s2peer instanceof Inet6Address));
+            simpleDataExchange (c1, s1);
+            simpleDataExchange (c2, s2);
+        }
+        c1.close();
+        c2.close();
+        s1.close();
+        s2.close();
+        server.close ();
+        System.out.println ("Test1: OK");
+    }
+
+    /** bind tests:
+     *  1. bind to specific address IPv4 only (any port)
+     *  2. bind to specific address IPv6 only (any port)
+     *  3. bind to specific address IPv4 only (specific port)
+     *  4. bind to specific address IPv4 only (specific port)
+     *  5. bind to any address IPv4 (test collision)
+     */
+
+    static void test2 () throws Exception {
+
+        server = new ServerSocket ();
+        InetSocketAddress sadr = new InetSocketAddress (ia4addr, 0);
+        server.bind (sadr);
+        dprintln ("server bound to " + sadr);
+        int port = server.getLocalPort();
+        InetSocketAddress sadr6 = new InetSocketAddress (ia6addr, port);
+
+        c1 = new Socket (ia4addr, port);
+        try {
+            dprintln ("connecting to " + ia6addr);
+            c2 = new Socket ();
+            c2.connect (sadr6, 1000);
+            throw new RuntimeException ("connect to IPv6 address should be refused");
+        } catch (IOException e) { }
+        server.close ();
+        c1.close ();
+
+        /* now try IPv6 only */
+
+        server = new ServerSocket ();
+        sadr = new InetSocketAddress (ia6addr, 0);
+        dprintln ("binding to " + sadr);
+        server.bind (sadr);
+        port = server.getLocalPort();
+
+        c1 = new Socket (ia6addr, port);
+        try {
+            c2 = new Socket (ia4addr, port);
+            throw new RuntimeException ("connect to IPv4 address should be refused");
+        } catch (IOException e) { }
+        server.close ();
+        c1.close ();
+
+        /* now try IPv6 specific port only */
+
+        server = new ServerSocket ();
+        sadr = new InetSocketAddress (ia6addr, 5200);
+        server.bind (sadr);
+        port = server.getLocalPort();
+        t_assert (port == 5200);
+
+        c1 = new Socket (ia6addr, port);
+        try {
+            c2 = new Socket (ia4addr, port);
+            throw new RuntimeException ("connect to IPv4 address should be refused");
+        } catch (IOException e) { }
+        server.close ();
+        c1.close ();
+
+        /* now try IPv4 specific port only */
+
+        server = new ServerSocket ();
+        sadr = new InetSocketAddress (ia4addr, 5200);
+        server.bind (sadr);
+        port = server.getLocalPort();
+        t_assert (port == 5200);
+
+        c1 = new Socket (ia4addr, port);
+
+        try {
+            c2 = new Socket (ia6addr, port);
+            throw new RuntimeException ("connect to IPv6 address should be refused");
+        } catch (IOException e) { }
+        server.accept().close();
+        c1.close ();
+        server.close();
+        System.out.println ("Test2: OK");
+    }
+
+    /* Test timeouts on accept(), connect() */
+
+    static void test3 () throws Exception {
+        server = new ServerSocket (0);
+        server.setSoTimeout (5000);
+        int port = server.getLocalPort();
+        long t1 = System.currentTimeMillis();
+        try {
+            server.accept ();
+            throw new RuntimeException ("accept should not have returned");
+        } catch (SocketTimeoutException e) {}
+        t1 = System.currentTimeMillis() - t1;
+        checkTime (t1, 5000);
+
+        c1 = new Socket ();
+        c1.connect (new InetSocketAddress (ia4addr, port), 1000);
+        s1 = server.accept ();
+        simpleDataExchange (c1,s1);
+        c2 = new Socket ();
+        c2.connect (new InetSocketAddress (ia6addr, port), 1000);
+        s2 = server.accept ();
+        simpleDataExchange (c2,s2);
+        c3 = new Socket ();
+        c3.connect (new InetSocketAddress (ia6addr, port), 1000);
+        s3 = server.accept ();
+        c2.close (); s2.close();
+        server.close();
+        simpleDataExchange (c3,s3);
+        c1.close (); c2.close();
+        s1.close (); s2.close();
+
+        /* check if connect() timesout when connecting to unknown dest. */
+
+        c1 = new Socket();
+        t1 = System.currentTimeMillis();
+        InetSocketAddress ad1 = new InetSocketAddress (ia6bad, 2500);
+        try {
+            c1.connect (ad1, 5000);
+            throw new RuntimeException ("timeout exception was expected");
+        } catch (SocketTimeoutException e) {
+            t1 = System.currentTimeMillis() - t1;
+            checkTime (t1, 5000);
+        } catch (NoRouteToHostException e1) {
+        }
+        System.out.println ("Test3: OK");
+    }
+
+    /* Test: connect to IPv4 mapped address  */
+
+    static void test4 () throws Exception {
+        server = new ServerSocket (0);
+        int port = server.getLocalPort();
+
+        /* create an IPv4 mapped address corresponding to local host */
+
+        byte[] b = {0,0,0,0,0,0,0,0,0,0,(byte)0xff,(byte)0xff,0,0,0,0};
+        byte[] ia4 = ia4addr.getAddress();
+        b[12] = ia4[0];
+        b[13] = ia4[1];
+        b[14] = ia4[2];
+        b[15] = ia4[3];
+
+        InetAddress dest = InetAddress.getByAddress (b);
+        c1 = new Socket (dest, port);
+        s1 = server.accept ();
+        simpleDataExchange (c1,s1);
+        c1.close ();
+        s1.close ();
+        server.close ();
+        System.out.println ("Test4: OK");
+    }
+}
diff --git a/test/java/net/ipv6tests/Tests.java b/test/java/net/ipv6tests/Tests.java
new file mode 100644
index 0000000..4527427
--- /dev/null
+++ b/test/java/net/ipv6tests/Tests.java
@@ -0,0 +1,352 @@
+/*
+ * Copyright 2003-2005 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.net.*;
+import java.io.*;
+import java.util.*;
+
+public class Tests {
+    /**
+     * performs a simple exchange of data between the two sockets
+     * and throws an exception if there is any problem.
+     */
+    public static void simpleDataExchange (Socket s1, Socket s2)
+        throws Exception {
+
+        InputStream i1 = s1.getInputStream();
+        InputStream i2 = s2.getInputStream();
+        OutputStream o1 = s1.getOutputStream();
+        OutputStream o2 = s2.getOutputStream();
+
+        simpleWrite (o1, 100);
+        simpleWrite (o2, 200);
+        simpleRead (i2, 100);
+        simpleRead (i1, 200);
+    }
+
+    /**
+     * Send a packet from s1 to s2 (ia2/s2.localPort) and check it
+     * Send a packet from s2 to s1 (ia1/s1.localPort) and check it
+     */
+    public static void simpleDataExchange (DatagramSocket s1, InetAddress ia1,
+                                           DatagramSocket s2, InetAddress ia2)
+        throws Exception {
+
+        SocketAddress dest1 = new InetSocketAddress (ia1, s1.getLocalPort());
+        dprintln ("dest1 = " + dest1);
+        SocketAddress dest2 = new InetSocketAddress (ia2, s2.getLocalPort());
+        dprintln ("dest2 = " + dest2);
+
+        byte[] ba = "Hello world".getBytes();
+        byte[] bb = "HELLO WORLD1".getBytes();
+        DatagramPacket p1 = new DatagramPacket (ba, ba.length, dest1);
+        DatagramPacket p2 = new DatagramPacket (ba, ba.length, dest2);
+
+        DatagramPacket r1 = new DatagramPacket (new byte[256], 256);
+        DatagramPacket r2 = new DatagramPacket (new byte[256], 256);
+
+        s2.send (p1);
+        s1.send (p2);
+        s1.receive (r1);
+        s2.receive (r2);
+        comparePackets (p1, r1);
+        comparePackets (p2, r2);
+    }
+
+    /**
+     * Send a packet from s1 to s2 (ia2/s2.localPort) and send same packet
+     * back from s2 to sender. Check s1 receives original packet
+     */
+
+    public static void datagramEcho (DatagramSocket s1, DatagramSocket s2,
+                                     InetAddress ia2)
+        throws Exception {
+
+        byte[] ba = "Hello world".getBytes();
+        DatagramPacket p1;
+
+        SocketAddress dest2 = null;
+        if (ia2 != null) {
+            dest2 = new InetSocketAddress (ia2, s2.getLocalPort());
+            p1 = new DatagramPacket (ba, ba.length, dest2);
+        } else {
+            p1 = new DatagramPacket (ba, ba.length);
+        }
+
+        dprintln ("dest2 = " + dest2);
+
+
+        DatagramPacket r1 = new DatagramPacket (new byte[256], 256);
+        DatagramPacket r2 = new DatagramPacket (new byte[256], 256);
+
+        s1.send (p1);
+        s2.receive (r1);
+        s2.send (r1);
+        s1.receive (r2);
+        comparePackets (p1, r1);
+        comparePackets (p1, r2);
+    }
+
+    public static void comparePackets (DatagramPacket p1, DatagramPacket p2)
+        throws Exception {
+
+        byte[] b1 = p1.getData();
+        byte[] b2 = p2.getData();
+        int len = p1.getLength () > p2.getLength() ? p2.getLength()
+                                                   : p1.getLength();
+        for (int i=0; i<len; i++) {
+            if (b1[i] != b2[i]) {
+                throw new Exception ("packets not the same");
+            }
+        }
+    }
+
+    /* check the time got is within 20% of the time expected */
+    public static void checkTime (long got, long expected) {
+        dprintln ("checkTime: got " + got + " expected " + expected);
+        long upper = expected + (expected / 5);
+        long lower = expected - (expected / 5);
+        if (got > upper || got < lower) {
+            throw new RuntimeException ("checkTime failed: got " + got + " expected " + expected);
+        }
+    }
+
+    static boolean debug = false;
+
+    public static void checkDebug (String[] args) {
+        debug = args.length > 0 && args[0].equals("-d");
+    }
+
+    public static void dprint (String s) {
+        if (debug) {
+            System.out.print (s);
+        }
+    }
+
+    public static void dprintln (String s) {
+        if (debug) {
+            System.out.println (s);
+        }
+    }
+
+    static int numberInterfaces () {
+        try {
+            Enumeration ifs = NetworkInterface.getNetworkInterfaces();
+            int nifs=0;
+            while (ifs.hasMoreElements()) {
+                nifs++;
+                ifs.nextElement();
+            }
+            return nifs;
+        } catch (SocketException e) {
+            return 0;
+        }
+    }
+
+    public static Enumeration ipv4Addresses() {
+        return new AddrEnum (Inet4Address.class);
+    }
+
+    public static Inet4Address getFirstLocalIPv4Address () {
+        Enumeration e = ipv4Addresses();
+        if (!e.hasMoreElements()) {
+            return null;
+        }
+        return (Inet4Address)e.nextElement();
+    }
+
+    public static Inet6Address getFirstLocalIPv6Address () {
+        Enumeration e = ipv6Addresses();
+        if (!e.hasMoreElements()) {
+            return null;
+        }
+        return (Inet6Address)e.nextElement();
+    }
+
+    public static Enumeration ipv6Addresses() {
+        return new AddrEnum (Inet6Address.class);
+    }
+
+    /* enumerates the Inet4Addresses or Inet6Addresses on the system */
+
+    private static class AddrEnum implements Enumeration {
+
+        Enumeration ifs;
+        NetworkInterface currIf = null;
+        InetAddress nextAddr=null;
+        Enumeration addrs=null;
+        Class filter;
+
+        static final byte[] fe80_loopback = new byte [] {
+            (byte)0xfe,(byte)0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,1
+        };
+
+        AddrEnum (Class filter) {
+            this.filter = filter;
+            try {
+                ifs = NetworkInterface.getNetworkInterfaces();
+            } catch (SocketException e) {}
+        }
+
+        public boolean hasMoreElements () {
+            if (nextAddr == null) {
+                nextAddr = getNext();
+            }
+            return (nextAddr != null);
+        }
+
+        public Object nextElement () {
+            if (!hasMoreElements()) {
+                throw new NoSuchElementException ("no more addresses");
+            }
+            Object next = nextAddr;
+            nextAddr = null;
+            return next;
+        }
+
+        private InetAddress getNext() {
+            while (true) {
+                if (currIf == null) {
+                    currIf = getNextIf();
+                    if (currIf == null) {
+                        return null;
+                    }
+                    addrs = currIf.getInetAddresses();
+                }
+                while (addrs.hasMoreElements()) {
+                    InetAddress addr = (InetAddress) addrs.nextElement();
+                    if (filter.isInstance (addr) && !addr.isLoopbackAddress()) {
+                        if (Arrays.equals (addr.getAddress(), fe80_loopback)) {
+                            continue;
+                        }
+                        return addr;
+                    }
+                }
+                currIf = null;
+            }
+        }
+
+        private NetworkInterface getNextIf () {
+            while (ifs.hasMoreElements()) {
+                NetworkInterface nic = (NetworkInterface)ifs.nextElement();
+                try {
+                    if (nic.isUp() && !nic.isLoopback())
+                        return nic;
+                } catch (SocketException e) {
+                    // ignore
+                }
+            }
+
+            return null;
+        }
+    }
+
+    /**
+     * Throws a RuntimeException if the boolean condition is false
+     */
+    public static void t_assert (boolean assertion) {
+        if (assertion) {
+            return;
+        }
+        Throwable t = new Throwable();
+        StackTraceElement[] strace = t.getStackTrace();
+        String msg = "Assertion failed at: " + strace[1].toString();
+        throw new RuntimeException (msg);
+    }
+
+    private static void simpleRead (InputStream is, int start) throws Exception {
+        byte b[] = new byte [2];
+        for (int i=start; i<start+100; i++) {
+            int x = is.read (b);
+            if (x == 1) {
+                x += is.read (b,1,1);
+            }
+            if (x!=2) {
+                throw new Exception ("read error");
+            }
+            int r = bytes (b[0], b[1]);
+            if (r != i) {
+                throw new Exception ("read " + r + " expected " +i);
+            }
+        }
+    }
+
+    /* convert signed bytes to unisigned int */
+    private static int bytes (byte b1, byte b2) {
+        int i1 = (int)b1 & 0xFF;
+        int i2 = (int)b2 & 0xFF;
+        return i1 * 256 + i2;
+    }
+
+    static void simpleWrite (OutputStream os, int start) throws Exception {
+        byte b[] = new byte [2];
+        for (int i=start; i<start+100; i++) {
+            b[0] = (byte) (i / 256);
+            b[1] = (byte) (i % 256);
+            os.write (b);
+        }
+    }
+
+    private static class Runner extends Thread {
+        Runnable runnee;
+        long delay;
+
+        Runner (Runnable runnee, long delay) {
+            super();
+            this.runnee = runnee;
+            this.delay = delay;
+        }
+
+        public void run () {
+            try {
+                Thread.sleep (delay);
+                runnee.run ();
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    /*
+     * Take the given Runnable and run it in a spawned thread
+     * after the given time has elapsed. runAfter() returns immediately
+     */
+    public static void runAfter (long millis, Runnable runnee) {
+        Runner runner = new Runner (runnee, millis);
+        runner.start ();
+    }
+
+    static String osname;
+
+    static {
+        osname = System.getProperty ("os.name");
+    }
+
+    static boolean isLinux () {
+        return osname.equals ("Linux");
+    }
+
+    static boolean isWindows () {
+        return osname.startsWith ("Windows");
+    }
+}
diff --git a/test/java/net/ipv6tests/UdpTest.java b/test/java/net/ipv6tests/UdpTest.java
new file mode 100644
index 0000000..94f4cef
--- /dev/null
+++ b/test/java/net/ipv6tests/UdpTest.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2003 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 4868820
+ * @summary IPv6 support for Windows XP and 2003 server
+ */
+
+import java.net.*;
+import java.io.*;
+
+public class UdpTest extends Tests {
+    static DatagramSocket c3, s1, s2, s3;
+    static InetAddress s1peer, s2peer;
+
+    static InetAddress ia4any;
+    static InetAddress ia6any;
+    static Inet6Address ia6addr;
+    static InetAddress ia6bad; /* a global 6to4 IPv6 address, which cant be connected to */
+    static InetAddress ia6rem1;
+    static Inet4Address ia4addr;
+
+    static {
+        try {
+            ia4any = InetAddress.getByName ("0.0.0.0");
+            ia6any = InetAddress.getByName ("::0");
+            try {
+                ia6bad = InetAddress.getByName ("2002:819c:dc29:1:1322:33ff:fe44:5566%net0");
+            } catch (Exception e) {
+                ia6bad = InetAddress.getByName ("2002:819c:dc29:1:1322:33ff:fe44:5566");
+            }
+            //ia6rem1 = InetAddress.getByName ("fe80::a00:20ff:feed:b08d%eth0");
+            //ia6rem1 = InetAddress.getByName ("129.156.220.63");
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        ia6addr = getFirstLocalIPv6Address ();
+        ia4addr = getFirstLocalIPv4Address ();
+    }
+
+    public static void main (String[] args) throws Exception {
+        checkDebug(args);
+        if (ia6addr == null) {
+            System.out.println ("No local IPv6 addresses: exiting now");
+            return;
+        }
+        dprintln ("Local Addresses");
+        dprintln (ia4addr.toString());
+        dprintln (ia6addr.toString());
+        test1 ();
+        test2 ();
+        if (!isLinux()) {
+            test3 ();
+        }
+        test4 ();
+    }
+
+    /* basic UDP connectivity test using IPv6 only and IPv4/IPv6 together */
+
+    static void test1 () throws Exception {
+        s1 = new DatagramSocket ();
+        s2 = new DatagramSocket ();
+        simpleDataExchange (s1, ia4addr, s2, ia4addr);
+        s1.close (); s2.close ();
+
+        /* IPv6 */
+        s1 = new DatagramSocket ();
+        s2 = new DatagramSocket ();
+        simpleDataExchange (s1, ia6addr, s2, ia6addr);
+        s1.close (); s2.close ();
+
+        /* IPv6 only */
+        s1 = new DatagramSocket (0, ia6addr);
+        s2 = new DatagramSocket (0, ia6addr);
+        simpleDataExchange (s1, ia6addr, s2, ia6addr);
+        s1.close (); s2.close ();
+
+        /* IPv6 and IPv4 */
+        s1 = new DatagramSocket ();
+        s2 = new DatagramSocket ();
+        simpleDataExchange (s1, ia6addr, s2, ia4addr);
+        s1.close (); s2.close ();
+
+        /* listen on anyaddr and check receive from IPv4 and IPv6 */
+
+        s1 = new DatagramSocket ();
+        s2 = new DatagramSocket (0, ia6addr);
+        s3 = new DatagramSocket (0, ia4addr);
+        datagramEcho (s2, s1, ia6addr);
+        datagramEcho (s3, s1, ia4addr);
+        s1.close (); s2.close (); s3.close();
+
+        System.out.println ("Test1: OK");
+    }
+
+    /* check timeouts on receive */
+
+    static void test2 () throws Exception {
+        s1 = new DatagramSocket ();
+        s2 = new DatagramSocket ();
+        s1.setSoTimeout (4000);
+        long t1 = System.currentTimeMillis();
+        try {
+            s1.receive (new DatagramPacket (new byte [128], 128));
+            throw new Exception ("expected receive timeout ");
+        } catch (SocketTimeoutException e) {
+        }
+        checkTime (System.currentTimeMillis() - t1, 4000);
+
+        /* check data can be exchanged now */
+
+        simpleDataExchange (s1, ia6addr, s2, ia4addr);
+
+        /* double check timeout still works */
+        t1 = System.currentTimeMillis();
+        try {
+            s1.receive (new DatagramPacket (new byte [128], 128));
+            throw new Exception ("expected receive timeout ");
+        } catch (SocketTimeoutException e) {
+        }
+        checkTime (System.currentTimeMillis() - t1, 4000);
+
+        /* check receive works after a delay < timeout */
+
+        final DatagramSocket s = s2;
+        final InetAddress ia6 = ia6addr;
+        final int port = s1.getLocalPort();
+
+        runAfter (2000, new Runnable () {
+            public void run () {
+                try {
+                    DatagramPacket p = new DatagramPacket ("Hello 123".getBytes(), 0, 8, ia6, port);
+                    s.send (p);
+                } catch (Exception e) {}
+            }
+        });
+        t1 = System.currentTimeMillis();
+        s1.receive (new DatagramPacket (new byte [128], 128));
+        checkTime (System.currentTimeMillis() - t1, 2000);
+        s1.close ();
+        s2.close ();
+        System.out.println ("Test2: OK");
+    }
+
+    /* check connected sockets */
+
+    static void test3 () throws Exception {
+        s1 = new DatagramSocket ();
+        s2 = new DatagramSocket ();
+        s1.connect (ia6addr, s2.getLocalPort());
+        datagramEcho (s1, s2, null);
+        s1.close (); s2.close();
+        System.out.println ("Test3: OK");
+    }
+
+    /* check PortUnreachable */
+
+    static void test4 () throws Exception {
+        s1 = new DatagramSocket ();
+        s1.connect (ia6addr, 5000);
+        s1.setSoTimeout (3000);
+        try {
+            DatagramPacket p = new DatagramPacket ("HelloWorld".getBytes(), "HelloWorld".length());
+            s1.send (p);
+            p = new DatagramPacket (new byte[128], 128);
+            s1.receive (p);
+        } catch (PortUnreachableException e) {
+            System.out.println ("Test4: OK");
+            return;
+        } catch (SocketTimeoutException e) {
+            System.out.println ("Test4: failed. Never mind, it's an OS bug");
+        }
+    }
+
+}