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 17 package com.android.server.wifi.hotspot2; 18 19 import android.util.Log; 20 import android.util.Pair; 21 22 import com.android.server.wifi.WifiInjector; 23 import com.android.server.wifi.hotspot2.anqp.ANQPElement; 24 import com.android.server.wifi.hotspot2.anqp.Constants; 25 26 import java.util.HashSet; 27 import java.util.List; 28 import java.util.Map; 29 import java.util.Set; 30 31 /** 32 * This class handles passpoint specific interactions with the AP, such as ANQP 33 * elements requests, passpoint icon requests, and wireless network management 34 * event notifications. 35 */ 36 public class PasspointEventHandler { 37 private final WifiInjector mWifiInjector; 38 private final Callbacks mCallbacks; 39 40 /** 41 * Interface to be implemented by the client to receive callbacks for passpoint 42 * related events. 43 */ 44 public interface Callbacks { 45 /** 46 * Invoked on received of ANQP response. |anqpElements| will be null on failure. 47 * @param bssid BSSID of the AP 48 * @param anqpElements ANQP elements to be queried 49 */ onANQPResponse(long bssid, Map<Constants.ANQPElementType, ANQPElement> anqpElements)50 void onANQPResponse(long bssid, 51 Map<Constants.ANQPElementType, ANQPElement> anqpElements); 52 53 /** 54 * Invoked on received of icon response. |filename| and |data| will be null 55 * on failure. 56 * @param bssid BSSID of the AP 57 * @param filename Name of the icon file 58 * @data icon data bytes 59 */ onIconResponse(long bssid, String filename, byte[] data)60 void onIconResponse(long bssid, String filename, byte[] data); 61 62 /** 63 * Invoked on received of Hotspot 2.0 Wireless Network Management frame. 64 * @param data Wireless Network Management frame data 65 */ onWnmFrameReceived(WnmData data)66 void onWnmFrameReceived(WnmData data); 67 } 68 PasspointEventHandler(WifiInjector wifiInjector, Callbacks callbacks)69 public PasspointEventHandler(WifiInjector wifiInjector, Callbacks callbacks) { 70 mWifiInjector = wifiInjector; 71 mCallbacks = callbacks; 72 } 73 74 /** 75 * Request the specified ANQP elements |elements| from the specified AP |bssid|. 76 * @param bssid BSSID of the AP 77 * @param elements ANQP elements to be queried 78 * @return true if request is sent successfully, false otherwise. 79 */ requestANQP(long bssid, List<Constants.ANQPElementType> elements)80 public boolean requestANQP(long bssid, List<Constants.ANQPElementType> elements) { 81 Pair<Set<Integer>, Set<Integer>> querySets = buildAnqpIdSet(elements); 82 if (bssid == 0 || querySets == null) return false; 83 if (!mWifiInjector.getActiveModeWarden().getPrimaryClientModeManager().requestAnqp( 84 Utils.macToString(bssid), querySets.first, querySets.second)) { 85 Log.d(Utils.hs2LogTag(getClass()), "ANQP failed on " + Utils.macToString(bssid)); 86 return false; 87 } 88 Log.d(Utils.hs2LogTag(getClass()), "ANQP initiated on " + Utils.macToString(bssid)); 89 return true; 90 } 91 92 /** 93 * Request the Venue URL ANQP element from the specified AP |bssid|. 94 * @param bssid BSSID of the AP 95 * @return true if request is sent successfully, false otherwise 96 */ requestVenueUrlAnqp(long bssid)97 public boolean requestVenueUrlAnqp(long bssid) { 98 if (bssid == 0) return false; 99 return mWifiInjector.getActiveModeWarden().getPrimaryClientModeManager() 100 .requestVenueUrlAnqp(Utils.macToString(bssid)); 101 } 102 103 /** 104 * Request a passpoint icon file |filename| from the specified AP |bssid|. 105 * @param bssid BSSID of the AP 106 * @param fileName name of the icon file 107 * @return true if request is sent successfully, false otherwise 108 */ requestIcon(long bssid, String fileName)109 public boolean requestIcon(long bssid, String fileName) { 110 if (bssid == 0 || fileName == null) return false; 111 return mWifiInjector.getActiveModeWarden().getPrimaryClientModeManager() 112 .requestIcon(Utils.macToString(bssid), fileName); 113 } 114 115 /** 116 * Invoked when ANQP query is completed. 117 * TODO(zqiu): currently ANQP completion notification is through WifiMonitor, 118 * this shouldn't be needed once we switch over to wificond for ANQP requests. 119 * @param anqpEvent ANQP result data retrieved. ANQP elements could be empty in the event to 120 * indicate any failures. 121 */ notifyANQPDone(AnqpEvent anqpEvent)122 public void notifyANQPDone(AnqpEvent anqpEvent) { 123 if (anqpEvent == null) return; 124 mCallbacks.onANQPResponse(anqpEvent.getBssid(), anqpEvent.getElements()); 125 } 126 127 /** 128 * Invoked when icon query is completed. 129 * TODO(zqiu): currently icon completion notification is through WifiMonitor, 130 * this shouldn't be needed once we switch over to wificond for icon requests. 131 * @param iconEvent icon event data 132 */ notifyIconDone(IconEvent iconEvent)133 public void notifyIconDone(IconEvent iconEvent) { 134 if (iconEvent == null) return; 135 mCallbacks.onIconResponse( 136 iconEvent.getBSSID(), iconEvent.getFileName(), iconEvent.getData()); 137 } 138 139 /** 140 * Invoked when a Wireless Network Management (WNM) frame is received. 141 * 142 * @param data WNM frame data 143 */ notifyWnmFrameReceived(WnmData data)144 public void notifyWnmFrameReceived(WnmData data) { 145 mCallbacks.onWnmFrameReceived(data); 146 } 147 148 /** 149 * Create the set of ANQP ID's to query. 150 * 151 * @param querySet elements to query 152 * @return Pair of <set of ANQP ID's, set of HS20 subtypes> 153 */ buildAnqpIdSet( List<Constants.ANQPElementType> querySet)154 private static Pair<Set<Integer>, Set<Integer>> buildAnqpIdSet( 155 List<Constants.ANQPElementType> querySet) { 156 Set<Integer> anqpIds = new HashSet<>(); 157 Set<Integer> hs20Subtypes = new HashSet<>(); 158 for (Constants.ANQPElementType elementType : querySet) { 159 Integer id = Constants.getANQPElementID(elementType); 160 if (id != null) { 161 anqpIds.add(id); 162 } else { 163 id = Constants.getHS20ElementID(elementType); 164 hs20Subtypes.add(id); 165 } 166 } 167 return Pair.create(anqpIds, hs20Subtypes); 168 } 169 170 } 171