AnqpEvent.java revision 65d8ba5dd551cd132789e8feb270dfc7998dfbdc
1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server.wifi.hotspot2; 18 19import android.util.Log; 20 21import com.android.server.wifi.hotspot2.anqp.ANQPElement; 22import com.android.server.wifi.hotspot2.anqp.ANQPParser; 23import com.android.server.wifi.hotspot2.anqp.Constants; 24 25import java.io.BufferedReader; 26import java.io.IOException; 27import java.io.StringReader; 28import java.net.ProtocolException; 29import java.nio.BufferUnderflowException; 30import java.nio.ByteBuffer; 31import java.util.HashMap; 32import java.util.Map; 33 34/** 35 * This class carries the response of an ANQP request. 36 */ 37public class AnqpEvent { 38 private static final String TAG = "AnqpEvent"; 39 private static final Map<String, Constants.ANQPElementType> sWpsNames = new HashMap<>(); 40 41 static { 42 sWpsNames.put("anqp_venue_name", Constants.ANQPElementType.ANQPVenueName); 43 sWpsNames.put("anqp_roaming_consortium", Constants.ANQPElementType.ANQPRoamingConsortium); 44 sWpsNames.put("anqp_ip_addr_type_availability", 45 Constants.ANQPElementType.ANQPIPAddrAvailability); 46 sWpsNames.put("anqp_nai_realm", Constants.ANQPElementType.ANQPNAIRealm); 47 sWpsNames.put("anqp_3gpp", Constants.ANQPElementType.ANQP3GPPNetwork); 48 sWpsNames.put("anqp_domain_name", Constants.ANQPElementType.ANQPDomName); 49 sWpsNames.put("hs20_operator_friendly_name", Constants.ANQPElementType.HSFriendlyName); 50 sWpsNames.put("hs20_wan_metrics", Constants.ANQPElementType.HSWANMetrics); 51 sWpsNames.put("hs20_connection_capability", Constants.ANQPElementType.HSConnCapability); 52 sWpsNames.put("hs20_osu_providers_list", Constants.ANQPElementType.HSOSUProviders); 53 } 54 55 /** 56 * Bssid of the access point. 57 */ 58 private final long mBssid; 59 /** 60 * Map of ANQP element type to the data retrieved from the access point. 61 */ 62 private final Map<Constants.ANQPElementType, ANQPElement> mElements; 63 64 public AnqpEvent(long bssid, Map<Constants.ANQPElementType, ANQPElement> elements) { 65 mBssid = bssid; 66 mElements = elements; 67 } 68 69 /** 70 * Creates an ANQP result instance using the passed in scan result data. 71 * 72 * @param bssid BSSID of the access point. 73 * @param bssData Scan results fetched from wpa_supplicant after ANQP query. 74 */ 75 public static AnqpEvent buildAnqpEvent(long bssid, String bssData) { 76 Map<Constants.ANQPElementType, ANQPElement> elements = null; 77 try { 78 elements = parseWPSData(bssData); 79 Log.d(TAG, 80 String.format("Successful ANQP response for %012x: %s", 81 bssid, elements)); 82 } catch (IOException | BufferUnderflowException e) { 83 Log.e(TAG, "Failed to parse ANQP: " + e.toString() + ": " + bssData); 84 return null; 85 } 86 return new AnqpEvent(bssid, elements); 87 } 88 89 private static Map<Constants.ANQPElementType, ANQPElement> parseWPSData(String bssInfo) 90 throws IOException { 91 Map<Constants.ANQPElementType, ANQPElement> elements = new HashMap<>(); 92 if (bssInfo == null) { 93 return elements; 94 } 95 BufferedReader lineReader = new BufferedReader(new StringReader(bssInfo)); 96 String line; 97 while ((line = lineReader.readLine()) != null) { 98 ANQPElement element = buildElement(line); 99 if (element != null) { 100 elements.put(element.getID(), element); 101 } 102 } 103 return elements; 104 } 105 106 private static ANQPElement buildElement(String text) throws ProtocolException { 107 int separator = text.indexOf('='); 108 if (separator < 0 || separator + 1 == text.length()) { 109 return null; 110 } 111 112 String elementName = text.substring(0, separator); 113 Constants.ANQPElementType elementType = sWpsNames.get(elementName); 114 if (elementType == null) { 115 return null; 116 } 117 118 byte[] payload; 119 try { 120 payload = Utils.hexToBytes(text.substring(separator + 1)); 121 } catch (NumberFormatException nfe) { 122 Log.e(Utils.hs2LogTag(PasspointEventHandler.class), 123 "Failed to parse hex string"); 124 return null; 125 } 126 // Wrap the payload inside a ByteBuffer. 127 ByteBuffer buffer = ByteBuffer.wrap(payload); 128 129 return Constants.getANQPElementID(elementType) != null 130 ? ANQPParser.parseElement(elementType, buffer) 131 : ANQPParser.parseHS20Element(elementType, buffer); 132 } 133 134 /** 135 * Get the bssid of the access point from which this ANQP result was created. 136 */ 137 public long getBssid() { 138 return mBssid; 139 } 140 141 /** 142 * Get the map of ANQP elements retrieved from the access point. 143 */ 144 public Map<Constants.ANQPElementType, ANQPElement> getElements() { 145 return mElements; 146 } 147 148} 149