1package com.android.server.wifi.anqp;
2
3import java.net.ProtocolException;
4import java.nio.ByteBuffer;
5import java.nio.ByteOrder;
6import java.nio.charset.Charset;
7import java.util.Collection;
8import java.util.EnumMap;
9import java.util.HashMap;
10import java.util.List;
11import java.util.Map;
12
13/**
14 * ANQP related constants (802.11-2012)
15 */
16public class Constants {
17
18    public static final int NIBBLE_MASK = 0x0f;
19    public static final int BYTE_MASK = 0xff;
20    public static final int SHORT_MASK = 0xffff;
21    public static final long INT_MASK = 0xffffffffL;
22    public static final int BYTES_IN_SHORT = 2;
23    public static final int BYTES_IN_INT = 4;
24    public static final int BYTES_IN_EUI48 = 6;
25    public static final long MILLIS_IN_A_SEC = 1000L;
26
27    public static final int HS20_PREFIX = 0x119a6f50;   // Note that this is represented as a LE int
28    public static final int HS20_FRAME_PREFIX = 0x109a6f50;
29    public static final int UTF8_INDICATOR = 1;
30
31    public static final int LANG_CODE_LENGTH = 3;
32
33    public static final int ANQP_QUERY_LIST = 256;
34    public static final int ANQP_CAPABILITY_LIST = 257;
35    public static final int ANQP_VENUE_NAME = 258;
36    public static final int ANQP_EMERGENCY_NUMBER = 259;
37    public static final int ANQP_NWK_AUTH_TYPE = 260;
38    public static final int ANQP_ROAMING_CONSORTIUM = 261;
39    public static final int ANQP_IP_ADDR_AVAILABILITY = 262;
40    public static final int ANQP_NAI_REALM = 263;
41    public static final int ANQP_3GPP_NETWORK = 264;
42    public static final int ANQP_GEO_LOC = 265;
43    public static final int ANQP_CIVIC_LOC = 266;
44    public static final int ANQP_LOC_URI = 267;
45    public static final int ANQP_DOM_NAME = 268;
46    public static final int ANQP_EMERGENCY_ALERT = 269;
47    public static final int ANQP_TDLS_CAP = 270;
48    public static final int ANQP_EMERGENCY_NAI = 271;
49    public static final int ANQP_NEIGHBOR_REPORT = 272;
50    public static final int ANQP_VENDOR_SPEC = 56797;
51
52    public static final int HS_QUERY_LIST = 1;
53    public static final int HS_CAPABILITY_LIST = 2;
54    public static final int HS_FRIENDLY_NAME = 3;
55    public static final int HS_WAN_METRICS = 4;
56    public static final int HS_CONN_CAPABILITY = 5;
57    public static final int HS_NAI_HOME_REALM_QUERY = 6;
58    public static final int HS_OPERATING_CLASS = 7;
59    public static final int HS_OSU_PROVIDERS = 8;
60    public static final int HS_ICON_REQUEST = 10;
61    public static final int HS_ICON_FILE = 11;
62
63    public enum ANQPElementType {
64        ANQPQueryList,
65        ANQPCapabilityList,
66        ANQPVenueName,
67        ANQPEmergencyNumber,
68        ANQPNwkAuthType,
69        ANQPRoamingConsortium,
70        ANQPIPAddrAvailability,
71        ANQPNAIRealm,
72        ANQP3GPPNetwork,
73        ANQPGeoLoc,
74        ANQPCivicLoc,
75        ANQPLocURI,
76        ANQPDomName,
77        ANQPEmergencyAlert,
78        ANQPTDLSCap,
79        ANQPEmergencyNAI,
80        ANQPNeighborReport,
81        ANQPVendorSpec,
82        HSQueryList,
83        HSCapabilityList,
84        HSFriendlyName,
85        HSWANMetrics,
86        HSConnCapability,
87        HSNAIHomeRealmQuery,
88        HSOperatingclass,
89        HSOSUProviders,
90        HSIconRequest,
91        HSIconFile
92    }
93
94    private static final Map<Integer, ANQPElementType> sAnqpMap = new HashMap<>();
95    private static final Map<Integer, ANQPElementType> sHs20Map = new HashMap<>();
96    private static final Map<ANQPElementType, Integer> sRevAnqpmap =
97            new EnumMap<>(ANQPElementType.class);
98    private static final Map<ANQPElementType, Integer> sRevHs20map =
99            new EnumMap<>(ANQPElementType.class);
100
101    static {
102        sAnqpMap.put(ANQP_QUERY_LIST, ANQPElementType.ANQPQueryList);
103        sAnqpMap.put(ANQP_CAPABILITY_LIST, ANQPElementType.ANQPCapabilityList);
104        sAnqpMap.put(ANQP_VENUE_NAME, ANQPElementType.ANQPVenueName);
105        sAnqpMap.put(ANQP_EMERGENCY_NUMBER, ANQPElementType.ANQPEmergencyNumber);
106        sAnqpMap.put(ANQP_NWK_AUTH_TYPE, ANQPElementType.ANQPNwkAuthType);
107        sAnqpMap.put(ANQP_ROAMING_CONSORTIUM, ANQPElementType.ANQPRoamingConsortium);
108        sAnqpMap.put(ANQP_IP_ADDR_AVAILABILITY, ANQPElementType.ANQPIPAddrAvailability);
109        sAnqpMap.put(ANQP_NAI_REALM, ANQPElementType.ANQPNAIRealm);
110        sAnqpMap.put(ANQP_3GPP_NETWORK, ANQPElementType.ANQP3GPPNetwork);
111        sAnqpMap.put(ANQP_GEO_LOC, ANQPElementType.ANQPGeoLoc);
112        sAnqpMap.put(ANQP_CIVIC_LOC, ANQPElementType.ANQPCivicLoc);
113        sAnqpMap.put(ANQP_LOC_URI, ANQPElementType.ANQPLocURI);
114        sAnqpMap.put(ANQP_DOM_NAME, ANQPElementType.ANQPDomName);
115        sAnqpMap.put(ANQP_EMERGENCY_ALERT, ANQPElementType.ANQPEmergencyAlert);
116        sAnqpMap.put(ANQP_TDLS_CAP, ANQPElementType.ANQPTDLSCap);
117        sAnqpMap.put(ANQP_EMERGENCY_NAI, ANQPElementType.ANQPEmergencyNAI);
118        sAnqpMap.put(ANQP_NEIGHBOR_REPORT, ANQPElementType.ANQPNeighborReport);
119        sAnqpMap.put(ANQP_VENDOR_SPEC, ANQPElementType.ANQPVendorSpec);
120
121        sHs20Map.put(HS_QUERY_LIST, ANQPElementType.HSQueryList);
122        sHs20Map.put(HS_CAPABILITY_LIST, ANQPElementType.HSCapabilityList);
123        sHs20Map.put(HS_FRIENDLY_NAME, ANQPElementType.HSFriendlyName);
124        sHs20Map.put(HS_WAN_METRICS, ANQPElementType.HSWANMetrics);
125        sHs20Map.put(HS_CONN_CAPABILITY, ANQPElementType.HSConnCapability);
126        sHs20Map.put(HS_NAI_HOME_REALM_QUERY, ANQPElementType.HSNAIHomeRealmQuery);
127        sHs20Map.put(HS_OPERATING_CLASS, ANQPElementType.HSOperatingclass);
128        sHs20Map.put(HS_OSU_PROVIDERS, ANQPElementType.HSOSUProviders);
129        sHs20Map.put(HS_ICON_REQUEST, ANQPElementType.HSIconRequest);
130        sHs20Map.put(HS_ICON_FILE, ANQPElementType.HSIconFile);
131
132        for (Map.Entry<Integer, ANQPElementType> entry : sAnqpMap.entrySet()) {
133            sRevAnqpmap.put(entry.getValue(), entry.getKey());
134        }
135        for (Map.Entry<Integer, ANQPElementType> entry : sHs20Map.entrySet()) {
136            sRevHs20map.put(entry.getValue(), entry.getKey());
137        }
138    }
139
140    public static ANQPElementType mapANQPElement(int id) {
141        return sAnqpMap.get(id);
142    }
143
144    public static ANQPElementType mapHS20Element(int id) {
145        return sHs20Map.get(id);
146    }
147
148    public static Integer getANQPElementID(ANQPElementType elementType) {
149        return sRevAnqpmap.get(elementType);
150    }
151
152    public static Integer getHS20ElementID(ANQPElementType elementType) {
153        return sRevHs20map.get(elementType);
154    }
155
156    public static boolean hasBaseANQPElements(Collection<ANQPElementType> elements) {
157        if (elements == null) {
158            return false;
159        }
160        for (ANQPElementType element : elements) {
161            if (sRevAnqpmap.containsKey(element)) {
162                return true;
163            }
164        }
165        return false;
166    }
167
168    public static boolean hasR2Elements(List<ANQPElementType> elements) {
169        return elements.contains(ANQPElementType.HSOSUProviders);
170    }
171
172    public static long getInteger(ByteBuffer payload, ByteOrder bo, int size) {
173        byte[] octets = new byte[size];
174        payload.get(octets);
175        long value = 0;
176        if (bo == ByteOrder.LITTLE_ENDIAN) {
177            for (int n = octets.length - 1; n >= 0; n--) {
178                value = (value << Byte.SIZE) | (octets[n] & BYTE_MASK);
179            }
180        }
181        else {
182            for (byte octet : octets) {
183                value = (value << Byte.SIZE) | (octet & BYTE_MASK);
184            }
185        }
186        return value;
187    }
188
189    public static String getPrefixedString(ByteBuffer payload, int lengthLength, Charset charset)
190            throws ProtocolException {
191        return getPrefixedString(payload, lengthLength, charset, false);
192    }
193
194    public static String getPrefixedString(ByteBuffer payload, int lengthLength, Charset charset,
195                                           boolean useNull) throws ProtocolException {
196        if (payload.remaining() < lengthLength) {
197            throw new ProtocolException("Runt string: " + payload.remaining());
198        }
199        return getString(payload, (int) getInteger(payload, ByteOrder.LITTLE_ENDIAN,
200                lengthLength), charset, useNull);
201    }
202
203    public static String getTrimmedString(ByteBuffer payload, int length, Charset charset)
204            throws ProtocolException {
205        String s = getString(payload, length, charset, false);
206        int zero = length - 1;
207        while (zero >= 0) {
208            if (s.charAt(zero) != 0) {
209                break;
210            }
211            zero--;
212        }
213        return zero < length - 1 ? s.substring(0, zero + 1) : s;
214    }
215
216    public static String getString(ByteBuffer payload, int length, Charset charset)
217            throws ProtocolException {
218        return getString(payload, length, charset, false);
219    }
220
221    public static String getString(ByteBuffer payload, int length, Charset charset, boolean useNull)
222            throws ProtocolException {
223        if (length > payload.remaining()) {
224            throw new ProtocolException("Bad string length: " + length);
225        }
226        if (useNull && length == 0) {
227            return null;
228        }
229        byte[] octets = new byte[length];
230        payload.get(octets);
231        return new String(octets, charset);
232    }
233}
234