1 package com.android.anqp;
2 
3 import java.net.ProtocolException;
4 import java.nio.ByteBuffer;
5 import java.nio.ByteOrder;
6 import java.nio.charset.Charset;
7 import java.util.Collection;
8 import java.util.EnumMap;
9 import java.util.HashMap;
10 import java.util.List;
11 import java.util.Map;
12 
13 /**
14  * ANQP related constants (802.11-2012)
15  */
16 public 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 {
sAnqpMap.put(ANQP_QUERY_LIST, ANQPElementType.ANQPQueryList)102         sAnqpMap.put(ANQP_QUERY_LIST, ANQPElementType.ANQPQueryList);
sAnqpMap.put(ANQP_CAPABILITY_LIST, ANQPElementType.ANQPCapabilityList)103         sAnqpMap.put(ANQP_CAPABILITY_LIST, ANQPElementType.ANQPCapabilityList);
sAnqpMap.put(ANQP_VENUE_NAME, ANQPElementType.ANQPVenueName)104         sAnqpMap.put(ANQP_VENUE_NAME, ANQPElementType.ANQPVenueName);
sAnqpMap.put(ANQP_EMERGENCY_NUMBER, ANQPElementType.ANQPEmergencyNumber)105         sAnqpMap.put(ANQP_EMERGENCY_NUMBER, ANQPElementType.ANQPEmergencyNumber);
sAnqpMap.put(ANQP_NWK_AUTH_TYPE, ANQPElementType.ANQPNwkAuthType)106         sAnqpMap.put(ANQP_NWK_AUTH_TYPE, ANQPElementType.ANQPNwkAuthType);
sAnqpMap.put(ANQP_ROAMING_CONSORTIUM, ANQPElementType.ANQPRoamingConsortium)107         sAnqpMap.put(ANQP_ROAMING_CONSORTIUM, ANQPElementType.ANQPRoamingConsortium);
sAnqpMap.put(ANQP_IP_ADDR_AVAILABILITY, ANQPElementType.ANQPIPAddrAvailability)108         sAnqpMap.put(ANQP_IP_ADDR_AVAILABILITY, ANQPElementType.ANQPIPAddrAvailability);
sAnqpMap.put(ANQP_NAI_REALM, ANQPElementType.ANQPNAIRealm)109         sAnqpMap.put(ANQP_NAI_REALM, ANQPElementType.ANQPNAIRealm);
sAnqpMap.put(ANQP_3GPP_NETWORK, ANQPElementType.ANQP3GPPNetwork)110         sAnqpMap.put(ANQP_3GPP_NETWORK, ANQPElementType.ANQP3GPPNetwork);
sAnqpMap.put(ANQP_GEO_LOC, ANQPElementType.ANQPGeoLoc)111         sAnqpMap.put(ANQP_GEO_LOC, ANQPElementType.ANQPGeoLoc);
sAnqpMap.put(ANQP_CIVIC_LOC, ANQPElementType.ANQPCivicLoc)112         sAnqpMap.put(ANQP_CIVIC_LOC, ANQPElementType.ANQPCivicLoc);
sAnqpMap.put(ANQP_LOC_URI, ANQPElementType.ANQPLocURI)113         sAnqpMap.put(ANQP_LOC_URI, ANQPElementType.ANQPLocURI);
sAnqpMap.put(ANQP_DOM_NAME, ANQPElementType.ANQPDomName)114         sAnqpMap.put(ANQP_DOM_NAME, ANQPElementType.ANQPDomName);
sAnqpMap.put(ANQP_EMERGENCY_ALERT, ANQPElementType.ANQPEmergencyAlert)115         sAnqpMap.put(ANQP_EMERGENCY_ALERT, ANQPElementType.ANQPEmergencyAlert);
sAnqpMap.put(ANQP_TDLS_CAP, ANQPElementType.ANQPTDLSCap)116         sAnqpMap.put(ANQP_TDLS_CAP, ANQPElementType.ANQPTDLSCap);
sAnqpMap.put(ANQP_EMERGENCY_NAI, ANQPElementType.ANQPEmergencyNAI)117         sAnqpMap.put(ANQP_EMERGENCY_NAI, ANQPElementType.ANQPEmergencyNAI);
sAnqpMap.put(ANQP_NEIGHBOR_REPORT, ANQPElementType.ANQPNeighborReport)118         sAnqpMap.put(ANQP_NEIGHBOR_REPORT, ANQPElementType.ANQPNeighborReport);
sAnqpMap.put(ANQP_VENDOR_SPEC, ANQPElementType.ANQPVendorSpec)119         sAnqpMap.put(ANQP_VENDOR_SPEC, ANQPElementType.ANQPVendorSpec);
120 
sHs20Map.put(HS_QUERY_LIST, ANQPElementType.HSQueryList)121         sHs20Map.put(HS_QUERY_LIST, ANQPElementType.HSQueryList);
sHs20Map.put(HS_CAPABILITY_LIST, ANQPElementType.HSCapabilityList)122         sHs20Map.put(HS_CAPABILITY_LIST, ANQPElementType.HSCapabilityList);
sHs20Map.put(HS_FRIENDLY_NAME, ANQPElementType.HSFriendlyName)123         sHs20Map.put(HS_FRIENDLY_NAME, ANQPElementType.HSFriendlyName);
sHs20Map.put(HS_WAN_METRICS, ANQPElementType.HSWANMetrics)124         sHs20Map.put(HS_WAN_METRICS, ANQPElementType.HSWANMetrics);
sHs20Map.put(HS_CONN_CAPABILITY, ANQPElementType.HSConnCapability)125         sHs20Map.put(HS_CONN_CAPABILITY, ANQPElementType.HSConnCapability);
sHs20Map.put(HS_NAI_HOME_REALM_QUERY, ANQPElementType.HSNAIHomeRealmQuery)126         sHs20Map.put(HS_NAI_HOME_REALM_QUERY, ANQPElementType.HSNAIHomeRealmQuery);
sHs20Map.put(HS_OPERATING_CLASS, ANQPElementType.HSOperatingclass)127         sHs20Map.put(HS_OPERATING_CLASS, ANQPElementType.HSOperatingclass);
sHs20Map.put(HS_OSU_PROVIDERS, ANQPElementType.HSOSUProviders)128         sHs20Map.put(HS_OSU_PROVIDERS, ANQPElementType.HSOSUProviders);
sHs20Map.put(HS_ICON_REQUEST, ANQPElementType.HSIconRequest)129         sHs20Map.put(HS_ICON_REQUEST, ANQPElementType.HSIconRequest);
sHs20Map.put(HS_ICON_FILE, ANQPElementType.HSIconFile)130         sHs20Map.put(HS_ICON_FILE, ANQPElementType.HSIconFile);
131 
132         for (Map.Entry<Integer, ANQPElementType> entry : sAnqpMap.entrySet()) {
entry.getKey()133             sRevAnqpmap.put(entry.getValue(), entry.getKey());
134         }
135         for (Map.Entry<Integer, ANQPElementType> entry : sHs20Map.entrySet()) {
entry.getKey()136             sRevHs20map.put(entry.getValue(), entry.getKey());
137         }
138     }
139 
mapANQPElement(int id)140     public static ANQPElementType mapANQPElement(int id) {
141         return sAnqpMap.get(id);
142     }
143 
mapHS20Element(int id)144     public static ANQPElementType mapHS20Element(int id) {
145         return sHs20Map.get(id);
146     }
147 
getANQPElementID(ANQPElementType elementType)148     public static Integer getANQPElementID(ANQPElementType elementType) {
149         return sRevAnqpmap.get(elementType);
150     }
151 
getHS20ElementID(ANQPElementType elementType)152     public static Integer getHS20ElementID(ANQPElementType elementType) {
153         return sRevHs20map.get(elementType);
154     }
155 
hasBaseANQPElements(Collection<ANQPElementType> elements)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 
hasR2Elements(List<ANQPElementType> elements)168     public static boolean hasR2Elements(List<ANQPElementType> elements) {
169         return elements.contains(ANQPElementType.HSOSUProviders);
170     }
171 
getInteger(ByteBuffer payload, ByteOrder bo, int size)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 
getPrefixedString(ByteBuffer payload, int lengthLength, Charset charset)189     public static String getPrefixedString(ByteBuffer payload, int lengthLength, Charset charset)
190             throws ProtocolException {
191         return getPrefixedString(payload, lengthLength, charset, false);
192     }
193 
getPrefixedString(ByteBuffer payload, int lengthLength, Charset charset, boolean useNull)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 
getTrimmedString(ByteBuffer payload, int length, Charset charset)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 
getString(ByteBuffer payload, int length, Charset charset)216     public static String getString(ByteBuffer payload, int length, Charset charset)
217             throws ProtocolException {
218         return getString(payload, length, charset, false);
219     }
220 
getString(ByteBuffer payload, int length, Charset charset, boolean useNull)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