177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistpackage com.android.server.wifi.hotspot2; 277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport android.util.Log; 477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport com.android.server.wifi.ScanDetail; 6d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpandeimport com.android.server.wifi.WifiConfigStore; 777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport com.android.server.wifi.WifiNative; 877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport com.android.server.wifi.anqp.ANQPElement; 977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport com.android.server.wifi.anqp.ANQPFactory; 1077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport com.android.server.wifi.anqp.Constants; 1177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport com.android.server.wifi.anqp.eap.AuthParam; 1277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport com.android.server.wifi.anqp.eap.EAP; 1377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport com.android.server.wifi.anqp.eap.EAPMethod; 1477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport com.android.server.wifi.hotspot2.pps.Credential; 1577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 1677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport java.io.BufferedReader; 1777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport java.io.IOException; 1877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport java.io.StringReader; 1977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport java.net.ProtocolException; 207ec7de9f415179e38a39e7b1be917ba77e3b68ebJan Nordqvistimport java.nio.BufferUnderflowException; 2177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport java.nio.ByteBuffer; 2277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport java.nio.ByteOrder; 2377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport java.nio.CharBuffer; 2477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport java.nio.charset.CharacterCodingException; 2577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport java.nio.charset.StandardCharsets; 2677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport java.util.ArrayList; 2777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport java.util.HashMap; 2877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport java.util.List; 2977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvistimport java.util.Map; 3077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 31ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvistpublic class SupplicantBridge { 3277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist private final WifiNative mSupplicantHook; 33d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande private final WifiConfigStore mConfigStore; 34ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist private final Map<Long, ScanDetail> mRequestMap = new HashMap<>(); 3577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 36ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist private static final Map<String, Constants.ANQPElementType> sWpsNames = new HashMap<>(); 3777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 3877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist static { 3977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist sWpsNames.put("anqp_venue_name", Constants.ANQPElementType.ANQPVenueName); 4077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist sWpsNames.put("anqp_network_auth_type", Constants.ANQPElementType.ANQPNwkAuthType); 4177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist sWpsNames.put("anqp_roaming_consortium", Constants.ANQPElementType.ANQPRoamingConsortium); 4277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist sWpsNames.put("anqp_ip_addr_type_availability", 4377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist Constants.ANQPElementType.ANQPIPAddrAvailability); 4477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist sWpsNames.put("anqp_nai_realm", Constants.ANQPElementType.ANQPNAIRealm); 4577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist sWpsNames.put("anqp_3gpp", Constants.ANQPElementType.ANQP3GPPNetwork); 4677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist sWpsNames.put("anqp_domain_name", Constants.ANQPElementType.ANQPDomName); 4777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist sWpsNames.put("hs20_operator_friendly_name", Constants.ANQPElementType.HSFriendlyName); 4877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist sWpsNames.put("hs20_wan_metrics", Constants.ANQPElementType.HSWANMetrics); 4977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist sWpsNames.put("hs20_connection_capability", Constants.ANQPElementType.HSConnCapability); 5077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist sWpsNames.put("hs20_operating_class", Constants.ANQPElementType.HSOperatingclass); 5177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist sWpsNames.put("hs20_osu_providers_list", Constants.ANQPElementType.HSOSUProviders); 5277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 5377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 5477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist public static boolean isAnqpAttribute(String line) { 5577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist int split = line.indexOf('='); 5677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist return split >= 0 && sWpsNames.containsKey(line.substring(0, split)); 5777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 5877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 59d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande public SupplicantBridge(WifiNative supplicantHook, WifiConfigStore configStore) { 6077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist mSupplicantHook = supplicantHook; 61d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande mConfigStore = configStore; 6277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 6377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 6477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist public static Map<Constants.ANQPElementType, ANQPElement> parseANQPLines(List<String> lines) { 6577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist if (lines == null) { 6677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist return null; 6777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 6831891afce40b903ada9b24ec12e3648ae6aa27b2Jan Nordqvist Map<Constants.ANQPElementType, ANQPElement> elements = new HashMap<>(lines.size()); 6977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist for (String line : lines) { 7077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist try { 7177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist ANQPElement element = buildElement(line); 7277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist if (element != null) { 7377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist elements.put(element.getID(), element); 7477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 7577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 7677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist catch (ProtocolException pe) { 771c03d75c73b9f5fa24a795a0d546f4f56b82ab9bJan Nordqvist Log.e(Utils.hs2LogTag(SupplicantBridge.class), "Failed to parse ANQP: " + pe); 7877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 7977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 8077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist return elements; 8177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 8277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 8377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist public void startANQP(ScanDetail scanDetail) { 8477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist String anqpGet = buildWPSQueryRequest(scanDetail.getNetworkDetail()); 85ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist synchronized (mRequestMap) { 86ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist mRequestMap.put(scanDetail.getNetworkDetail().getBSSID(), scanDetail); 8777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 88ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist String result = mSupplicantHook.doCustomCommand(anqpGet); 895ef40f88bab7e645a5a9e42aeae768d3b916c02cJan Nordqvist if (result != null && result.startsWith("OK")) { 905bee0e4616e2f8025d60cbfe3eec3e274a68a452Jan Nordqvist Log.d(Utils.hs2LogTag(getClass()), "ANQP initiated on " + scanDetail); 9131891afce40b903ada9b24ec12e3648ae6aa27b2Jan Nordqvist } 9231891afce40b903ada9b24ec12e3648ae6aa27b2Jan Nordqvist else { 9331891afce40b903ada9b24ec12e3648ae6aa27b2Jan Nordqvist Log.d(Utils.hs2LogTag(getClass()), "ANQP failed on " + 945bee0e4616e2f8025d60cbfe3eec3e274a68a452Jan Nordqvist scanDetail + ": " + result); 9577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 9677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 9777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 98ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist public void notifyANQPDone(Long bssid, boolean success) { 99ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist ScanDetail scanDetail; 100ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist synchronized (mRequestMap) { 101ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist scanDetail = mRequestMap.remove(bssid); 102ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist } 103ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist if (scanDetail == null) { 1045bee0e4616e2f8025d60cbfe3eec3e274a68a452Jan Nordqvist Log.d(Utils.hs2LogTag(getClass()), String.format("Spurious %s ANQP response for %012x", 1055bee0e4616e2f8025d60cbfe3eec3e274a68a452Jan Nordqvist success ? "successful" : "failed", bssid)); 106ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist return; 107ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist } 10877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 109ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist String bssData = mSupplicantHook.scanResult(scanDetail.getBSSIDString()); 11077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist try { 11177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist Map<Constants.ANQPElementType, ANQPElement> elements = parseWPSData(bssData); 1125bee0e4616e2f8025d60cbfe3eec3e274a68a452Jan Nordqvist Log.d(Utils.hs2LogTag(getClass()), String.format("%s ANQP response for %012x: %s", 1135bee0e4616e2f8025d60cbfe3eec3e274a68a452Jan Nordqvist success ? "successful" : "failed", bssid, elements)); 11442a1bf5e9b21288524d9a5fe90556abefc035879Jan Nordqvist mConfigStore.notifyANQPResponse(scanDetail, success ? elements : null); 11577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 11677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist catch (IOException ioe) { 1177ec7de9f415179e38a39e7b1be917ba77e3b68ebJan Nordqvist Log.e(Utils.hs2LogTag(getClass()), "Failed to parse ANQP: " + 1187ec7de9f415179e38a39e7b1be917ba77e3b68ebJan Nordqvist ioe.toString() + ": " + bssData); 1197ec7de9f415179e38a39e7b1be917ba77e3b68ebJan Nordqvist } 1207ec7de9f415179e38a39e7b1be917ba77e3b68ebJan Nordqvist catch (RuntimeException rte) { 1217ec7de9f415179e38a39e7b1be917ba77e3b68ebJan Nordqvist Log.e(Utils.hs2LogTag(getClass()), "Failed to parse ANQP: " + 1227ec7de9f415179e38a39e7b1be917ba77e3b68ebJan Nordqvist rte.toString() + ": " + bssData, rte); 12377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 124d3fb9cbb12d013dd70e672ace5c41ab18a3679a0Vinit Deshpande mConfigStore.notifyANQPResponse(scanDetail, null); 12577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 12677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 127ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist /* 12877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist public boolean addCredential(HomeSP homeSP, NetworkDetail networkDetail) { 12977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist Credential credential = homeSP.getCredential(); 13077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist if (credential == null) 13177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist return false; 13277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 13377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist String nwkID = null; 13477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist if (mLastSSID != null) { 13577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist String nwkList = mSupplicantHook.doCustomCommand("LIST_NETWORKS"); 13677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 13777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist BufferedReader reader = new BufferedReader(new StringReader(nwkList)); 13877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist String line; 13977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist try { 14077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist while ((line = reader.readLine()) != null) { 14177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist String[] tokens = line.split("\\t"); 14277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist if (tokens.length < 2 || ! Utils.isDecimal(tokens[0])) { 14377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist continue; 14477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 14577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist if (unescapeSSID(tokens[1]).equals(mLastSSID)) { 14677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist nwkID = tokens[0]; 14777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist Log.d("HS2J", "Network " + tokens[0] + 14877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist " matches last SSID '" + mLastSSID + "'"); 14977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist break; 15077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 15177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 15277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 15377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist catch (IOException ioe) { 154ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist // 15577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 15677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 15777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 15877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist if (nwkID == null) { 15977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist nwkID = mSupplicantHook.doCustomCommand("ADD_NETWORK"); 16077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist Log.d("HS2J", "add_network: '" + nwkID + "'"); 16177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist if (! Utils.isDecimal(nwkID)) { 16277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist return false; 16377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 16477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 16577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 16677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist List<String> credCommand = getWPSNetCommands(nwkID, networkDetail, credential); 16777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist for (String command : credCommand) { 16877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist String status = mSupplicantHook.doCustomCommand(command); 16977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist Log.d("HS2J", "Status of '" + command + "': '" + status + "'"); 17077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 17177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 17277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist if (! networkDetail.getSSID().equals(mLastSSID)) { 17377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist mLastSSID = networkDetail.getSSID(); 17477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist PrintWriter out = null; 17577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist try { 17677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist out = new PrintWriter(new OutputStreamWriter( 17777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist new FileOutputStream(mLastSSIDFile, false), StandardCharsets.UTF_8)); 17877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist out.println(mLastSSID); 17977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } catch (IOException ioe) { 180ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist // 18177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } finally { 18277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist if (out != null) { 18377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist out.close(); 18477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 18577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 18677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 18777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 18877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist return true; 18977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 190ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist */ 19177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 19277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist private static String escapeSSID(NetworkDetail networkDetail) { 19377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist return escapeString(networkDetail.getSSID(), networkDetail.isSSID_UTF8()); 19477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 19577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 19677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist private static String escapeString(String s, boolean utf8) { 19777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist boolean asciiOnly = true; 19877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist for (int n = 0; n < s.length(); n++) { 19977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist char ch = s.charAt(n); 20077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist if (ch > 127) { 20177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist asciiOnly = false; 20277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist break; 20377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 20477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 20577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 20677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist if (asciiOnly) { 207ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist return '"' + s + '"'; 20877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 20977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist else { 21077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist byte[] octets = s.getBytes(utf8 ? StandardCharsets.UTF_8 : StandardCharsets.ISO_8859_1); 21177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 21277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist StringBuilder sb = new StringBuilder(); 21377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist for (byte octet : octets) { 21477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist sb.append(String.format("%02x", octet & Constants.BYTE_MASK)); 21577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 21677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist return sb.toString(); 21777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 21877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 21977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 22077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist private static String buildWPSQueryRequest(NetworkDetail networkDetail) { 22177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist StringBuilder sb = new StringBuilder(); 22277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist sb.append("ANQP_GET ").append(networkDetail.getBSSIDString()).append(' '); 22377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 22477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist boolean first = true; 22577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist for (Constants.ANQPElementType elementType : ANQPFactory.getBaseANQPSet()) { 22677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist if (networkDetail.getAnqpOICount() == 0 && 22777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist elementType == Constants.ANQPElementType.ANQPRoamingConsortium) { 22877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist continue; 22977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 23077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist if (first) { 23177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist first = false; 23277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 23377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist else { 23477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist sb.append(','); 23577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 23677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist sb.append(Constants.getANQPElementID(elementType)); 23777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 23877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist if (networkDetail.getHSRelease() != null) { 23977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist for (Constants.ANQPElementType elementType : ANQPFactory.getHS20ANQPSet()) { 24077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist sb.append(",hs20:").append(Constants.getHS20ElementID(elementType)); 24177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 24277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 24377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist return sb.toString(); 24477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 24577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 24677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist private static List<String> getWPSNetCommands(String netID, NetworkDetail networkDetail, 24777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist Credential credential) { 24877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 24977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist List<String> commands = new ArrayList<String>(); 25077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 25177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist EAPMethod eapMethod = credential.getEAPMethod(); 25277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist commands.add(String.format("SET_NETWORK %s key_mgmt WPA-EAP", netID)); 25377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist commands.add(String.format("SET_NETWORK %s ssid %s", netID, escapeSSID(networkDetail))); 25477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist commands.add(String.format("SET_NETWORK %s bssid %s", 25577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist netID, networkDetail.getBSSIDString())); 25677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist commands.add(String.format("SET_NETWORK %s eap %s", 25777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist netID, mapEAPMethodName(eapMethod.getEAPMethodID()))); 25877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 25977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist AuthParam authParam = credential.getEAPMethod().getAuthParam(); 26077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist if (authParam == null) { 26177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist return null; // TLS or SIM/AKA 26277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 26377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist switch (authParam.getAuthInfoID()) { 26477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist case NonEAPInnerAuthType: 26577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist case InnerAuthEAPMethodType: 26677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist commands.add(String.format("SET_NETWORK %s identity %s", 26777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist netID, escapeString(credential.getUserName(), true))); 26877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist commands.add(String.format("SET_NETWORK %s password %s", 26977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist netID, escapeString(credential.getPassword(), true))); 27077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist commands.add(String.format("SET_NETWORK %s anonymous_identity \"anonymous\"", 27177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist netID)); 27277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist break; 27377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist default: // !!! Needs work. 27477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist return null; 27577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 27677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist commands.add(String.format("SET_NETWORK %s priority 0", netID)); 27777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist commands.add(String.format("ENABLE_NETWORK %s", netID)); 27877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist commands.add(String.format("SAVE_CONFIG")); 27977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist return commands; 28077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 28177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 28277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist private static Map<Constants.ANQPElementType, ANQPElement> parseWPSData(String bssInfo) 28377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist throws IOException { 284ef1567e413c9ed5f5c4fdb9e354861632f7b2f87Jan Nordqvist Map<Constants.ANQPElementType, ANQPElement> elements = new HashMap<>(); 28577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist if (bssInfo == null) { 28677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist return elements; 28777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 28877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist BufferedReader lineReader = new BufferedReader(new StringReader(bssInfo)); 28977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist String line; 29077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist while ((line=lineReader.readLine()) != null) { 29177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist ANQPElement element = buildElement(line); 29277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist if (element != null) { 29377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist elements.put(element.getID(), element); 29477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 29577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 29677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist return elements; 29777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 29877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 29977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist private static ANQPElement buildElement(String text) throws ProtocolException { 30077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist int separator = text.indexOf('='); 30177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist if (separator < 0) { 30277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist return null; 30377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 30477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 30577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist String elementName = text.substring(0, separator); 30677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist Constants.ANQPElementType elementType = sWpsNames.get(elementName); 30777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist if (elementType == null) { 30877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist return null; 30977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 31077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 31177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist byte[] payload; 31277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist try { 31377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist payload = Utils.hexToBytes(text.substring(separator + 1)); 31477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 31577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist catch (NumberFormatException nfe) { 3161c03d75c73b9f5fa24a795a0d546f4f56b82ab9bJan Nordqvist Log.e(Utils.hs2LogTag(SupplicantBridge.class), "Failed to parse hex string"); 31777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist return null; 31877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 31977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist return Constants.getANQPElementID(elementType) != null ? 32077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist ANQPFactory.buildElement(ByteBuffer.wrap(payload), elementType, payload.length) : 32177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist ANQPFactory.buildHS20Element(elementType, 32277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist ByteBuffer.wrap(payload).order(ByteOrder.LITTLE_ENDIAN)); 32377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 32477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 32577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist private static String mapEAPMethodName(EAP.EAPMethodID eapMethodID) { 32677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist switch (eapMethodID) { 32777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist case EAP_AKA: 32877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist return "AKA"; 32977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist case EAP_AKAPrim: 33077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist return "AKA'"; // eap.c:1514 33177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist case EAP_SIM: 33277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist return "SIM"; 33377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist case EAP_TLS: 33477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist return "TLS"; 33577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist case EAP_TTLS: 33677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist return "TTLS"; 33777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist default: 33877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist throw new IllegalArgumentException("No mapping for " + eapMethodID); 33977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 34077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 34177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 34277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist private static final Map<Character,Integer> sMappings = new HashMap<Character, Integer>(); 34377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 34477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist static { 34577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist sMappings.put('\\', (int)'\\'); 34677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist sMappings.put('"', (int)'"'); 34777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist sMappings.put('e', 0x1b); 34877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist sMappings.put('n', (int)'\n'); 34977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist sMappings.put('r', (int)'\n'); 35077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist sMappings.put('t', (int)'\t'); 35177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 35277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 35377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist public static String unescapeSSID(String ssid) { 35477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 35577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist CharIterator chars = new CharIterator(ssid); 35677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist byte[] octets = new byte[ssid.length()]; 35777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist int bo = 0; 35877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 35977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist while (chars.hasNext()) { 36077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist char ch = chars.next(); 36177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist if (ch != '\\' || ! chars.hasNext()) { 36277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist octets[bo++] = (byte)ch; 36377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 36477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist else { 36577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist char suffix = chars.next(); 36677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist Integer mapped = sMappings.get(suffix); 36777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist if (mapped != null) { 36877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist octets[bo++] = mapped.byteValue(); 36977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 37077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist else if (suffix == 'x' && chars.hasDoubleHex()) { 37177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist octets[bo++] = (byte)chars.nextDoubleHex(); 37277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 37377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist else { 37477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist octets[bo++] = '\\'; 37577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist octets[bo++] = (byte)suffix; 37677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 37777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 37877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 37977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 38077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist boolean asciiOnly = true; 38177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist for (byte b : octets) { 38277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist if ((b&0x80) != 0) { 38377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist asciiOnly = false; 38477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist break; 38577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 38677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 38777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist if (asciiOnly) { 38877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist return new String(octets, 0, bo, StandardCharsets.UTF_8); 38977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } else { 39077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist try { 39177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist // If UTF-8 decoding is successful it is almost certainly UTF-8 39277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist CharBuffer cb = StandardCharsets.UTF_8.newDecoder().decode( 39377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist ByteBuffer.wrap(octets, 0, bo)); 39477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist return cb.toString(); 39577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } catch (CharacterCodingException cce) { 39677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist return new String(octets, 0, bo, StandardCharsets.ISO_8859_1); 39777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 39877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 39977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 40077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 40177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist private static class CharIterator { 40277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist private final String mString; 40377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist private int mPosition; 40477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist private int mHex; 40577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 40677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist private CharIterator(String s) { 40777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist mString = s; 40877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 40977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 41077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist private boolean hasNext() { 41177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist return mPosition < mString.length(); 41277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 41377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 41477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist private char next() { 41577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist return mString.charAt(mPosition++); 41677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 41777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 41877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist private boolean hasDoubleHex() { 41977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist if (mString.length() - mPosition < 2) { 42077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist return false; 42177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 42277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist int nh = Utils.fromHex(mString.charAt(mPosition), true); 42377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist if (nh < 0) { 42477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist return false; 42577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 42677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist int nl = Utils.fromHex(mString.charAt(mPosition + 1), true); 42777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist if (nl < 0) { 42877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist return false; 42977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 43077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist mPosition += 2; 43177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist mHex = (nh << 4) | nl; 43277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist return true; 43377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 43477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 43577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist private int nextDoubleHex() { 43677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist return mHex; 43777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 43877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 43977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 44077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist private static final String[] TestStrings = { 44177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist "test-ssid", 44277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist "test\\nss\\tid", 44377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist "test\\x2d\\x5f\\nss\\tid", 44477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist "test\\x2d\\x5f\\nss\\tid\\\\", 44577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist "test\\x2d\\x5f\\nss\\tid\\n", 44677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist "test\\x2d\\x5f\\nss\\tid\\x4a", 44777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist "another\\", 44877f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist "an\\other", 44977f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist "another\\x2" 45077f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist }; 45177f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist 45277f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist public static void main(String[] args) { 45377f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist for (String string : TestStrings) { 45477f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist System.out.println(unescapeSSID(string)); 45577f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 45677f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist } 45777f2b82a2e80af8da52c22d69a76def6d4209757Jan Nordqvist} 458