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