1777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvistpackage com.android.server.wifi.anqp;
2777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist
3777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvistimport java.io.BufferedInputStream;
4777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvistimport java.io.BufferedOutputStream;
5777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvistimport java.io.EOFException;
6777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvistimport java.io.IOException;
7777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvistimport java.io.InputStream;
8777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvistimport java.net.InetAddress;
9777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvistimport java.net.Socket;
10777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvistimport java.nio.ByteBuffer;
11777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvistimport java.nio.ByteOrder;
12777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvistimport java.util.Arrays;
13777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvistimport java.util.HashSet;
14777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvistimport java.util.List;
15777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvistimport java.util.Set;
16777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist
17777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist/**
18777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist * Test ANQP code by talking to an ANQP server of a socket.
19777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist */
20777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvistpublic class TestDriver {
21777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist
22777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist    private static final Constants.ANQPElementType[] QueryElements = {
23777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist            Constants.ANQPElementType.ANQPCapabilityList,
24777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist            Constants.ANQPElementType.ANQPVenueName,
25777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist            Constants.ANQPElementType.ANQPEmergencyNumber,
26777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist            Constants.ANQPElementType.ANQPNwkAuthType,
27777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist            Constants.ANQPElementType.ANQPRoamingConsortium,
28777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist            Constants.ANQPElementType.ANQPIPAddrAvailability,
29777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist            Constants.ANQPElementType.ANQPNAIRealm,
30777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist            Constants.ANQPElementType.ANQP3GPPNetwork,
31777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist            Constants.ANQPElementType.ANQPGeoLoc,
32777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist            Constants.ANQPElementType.ANQPCivicLoc,
33777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist            Constants.ANQPElementType.ANQPLocURI,
34777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist            Constants.ANQPElementType.ANQPDomName,
35777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist            Constants.ANQPElementType.ANQPEmergencyAlert,
36777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist            Constants.ANQPElementType.ANQPTDLSCap,
37777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist            Constants.ANQPElementType.ANQPEmergencyNAI,
38777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist            Constants.ANQPElementType.ANQPNeighborReport,
39777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist
40777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist            Constants.ANQPElementType.HSCapabilityList,
41777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist            Constants.ANQPElementType.HSFriendlyName,
42777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist            Constants.ANQPElementType.HSWANMetrics,
43777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist            Constants.ANQPElementType.HSConnCapability,
44777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist            Constants.ANQPElementType.HSNAIHomeRealmQuery,
45777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist            Constants.ANQPElementType.HSOperatingclass,
46777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist            Constants.ANQPElementType.HSOSUProviders
47777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist    };
48777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist
49777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist    public static void runTest() throws IOException {
50777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist
51777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist        Set<Constants.ANQPElementType> elements =
52777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist                new HashSet<Constants.ANQPElementType>(QueryElements.length);
53777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist        elements.addAll(Arrays.asList(QueryElements));
54777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist
55777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist        ByteBuffer request = ByteBuffer.allocate(8192);
56777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist        request.order(ByteOrder.LITTLE_ENDIAN);
57777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist        int lenPos = request.position();
58777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist        request.putShort((short) 0);
59777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist        ANQPFactory.buildQueryRequest(elements, request);
60777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist
617b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        byte[] requestBytes = prepRequest(lenPos, request);
62777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist
63777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist        System.out.println( "Connecting...");
64777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist        Socket sock = new Socket(InetAddress.getLoopbackAddress(), 6104);
65777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist        BufferedOutputStream out = new BufferedOutputStream(sock.getOutputStream());
667b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        System.out.println(" ### Querying for " + Arrays.toString(QueryElements));
67777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist        out.write(requestBytes);
68777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist        out.flush();
69777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist
70777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist        BufferedInputStream in = new BufferedInputStream(sock.getInputStream());
717b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        ByteBuffer payload = getResponse(in);
72777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist
737b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        HSOsuProvidersElement osuProvidersElement = null;
74777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist        List<ANQPElement> anqpResult = ANQPFactory.parsePayload(payload);
75777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist        for ( ANQPElement element : anqpResult ) {
76777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist            System.out.println( element );
777b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist            if (element.getID() == Constants.ANQPElementType.HSOSUProviders) {
787b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist                osuProvidersElement = (HSOsuProvidersElement)element;
797b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist            }
807b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        }
817b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist
827b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        if ( osuProvidersElement != null ) {
837b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist            for (OSUProvider provider : osuProvidersElement.getProviders()) {
847b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist                for (IconInfo iconInfo : provider.getIcons()) {
857b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist                    sendIconRequest(iconInfo.getFileName());
867b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist                }
877b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist            }
88777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist        }
897b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        sendIconRequest("doesNotExist.noimg");
907b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist
917b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        sendHomeRealmQuery("nxdomain.abc", "jan.com");
927b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist    }
937b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist
947b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist    private static void sendIconRequest(String fileName) throws IOException {
957b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        ByteBuffer iconRequest = ByteBuffer.allocate(fileName.length()*2)
967b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist                .order(ByteOrder.LITTLE_ENDIAN);
977b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        int iconPos = iconRequest.position();
987b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        iconRequest.putShort((short) 0);
997b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        ANQPFactory.buildIconRequest(fileName, iconRequest);
1007b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        byte[] iconBytes = prepRequest(iconPos, iconRequest);
1017b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist
1027b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        System.out.println( "Connecting...");
1037b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        Socket sock = new Socket(InetAddress.getLoopbackAddress(), 6104);
1047b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        BufferedOutputStream out = new BufferedOutputStream(sock.getOutputStream());
1057b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist
1067b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        System.out.println(" ### Requesting icon '" + fileName + "'");
1077b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        out.write(iconBytes);
1087b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        out.flush();
1097b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist
1107b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        BufferedInputStream in = new BufferedInputStream(sock.getInputStream());
1117b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        ByteBuffer payload = getResponse(in);
1127b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        List<ANQPElement> anqpResult = ANQPFactory.parsePayload(payload);
1137b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        System.out.println("Icon: " + anqpResult );
1147b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist    }
1157b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist
1167b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist    private static void sendHomeRealmQuery(String ... realms) throws IOException{
1177b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        ByteBuffer request = ByteBuffer.allocate(1024).order(ByteOrder.LITTLE_ENDIAN);
1187b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        int iconPos = request.position();
1197b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        request.putShort((short) 0);
1207b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        ANQPFactory.buildHomeRealmRequest(Arrays.asList(realms), request);
1217b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        byte[] iconBytes = prepRequest(iconPos, request);
1227b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist
1237b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        System.out.println( "Connecting...");
1247b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        Socket sock = new Socket(InetAddress.getLoopbackAddress(), 6104);
1257b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        BufferedOutputStream out = new BufferedOutputStream(sock.getOutputStream());
1267b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist
1277b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        System.out.println(" ### Home realm query for " + Arrays.toString(realms));
1287b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        out.write(iconBytes);
1297b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        out.flush();
1307b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist
1317b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        BufferedInputStream in = new BufferedInputStream(sock.getInputStream());
1327b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        ByteBuffer payload = getResponse(in);
1337b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        List<ANQPElement> anqpResult = ANQPFactory.parsePayload(payload);
1347b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        System.out.println("Home realm query: " + anqpResult );
1357b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist    }
1367b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist
1377b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist    private static ByteBuffer getResponse(InputStream in) throws IOException {
1387b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        ByteBuffer lengthBuffer = read( in, 2 );
1397b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        int length = lengthBuffer.getShort() & Constants.SHORT_MASK;
1407b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        System.out.println("Length " + length);
1417b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist
1427b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        return read(in, length);
1437b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist    }
1447b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist
1457b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist    private static byte[] prepRequest(int pos0, ByteBuffer request) {
1467b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        request.putShort(pos0, (short)( request.limit() - pos0 - Constants.BYTES_IN_SHORT ));
1477b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        byte[] octets = new byte[request.remaining()];
1487b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        request.get(octets);
1497b2caa25fb57f2d95e0d0421704c49d3af4b8e6fJan Nordqvist        return octets;
150777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist    }
151777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist
152777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist    private static ByteBuffer read(InputStream in, int length) throws IOException {
153777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist        byte[] payload = new byte[length];
154777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist        int position = 0;
155777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist        while ( position < length ) {
156777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist            int amount = in.read(payload, position, length - position);
157777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist            if ( amount <= 0 ) {
158777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist                throw new EOFException("Got " + amount);
159777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist            }
160777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist            position += amount;
161777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist        }
162777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist        return ByteBuffer.wrap(payload).order(ByteOrder.LITTLE_ENDIAN);
163777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist    }
164777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist
165777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist    public static void main(String[] args) throws IOException {
166777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist        runTest();
167777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist    }
168777f4fc037d3ebd555f10041f8acfb41515b2f4bJan Nordqvist}
169