• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.aware;
18 
19 import android.net.MacAddress;
20 import android.net.wifi.aware.AwareParams;
21 import android.net.wifi.aware.ConfigRequest;
22 import android.net.wifi.aware.PublishConfig;
23 import android.net.wifi.aware.SubscribeConfig;
24 import android.net.wifi.aware.WifiAwareDataPathSecurityConfig;
25 import android.net.wifi.util.HexEncoding;
26 import android.util.ArrayMap;
27 import android.util.Log;
28 import android.util.SparseIntArray;
29 
30 import com.android.modules.utils.BasicShellCommandHandler;
31 import com.android.server.wifi.hal.WifiNanIface;
32 import com.android.server.wifi.hal.WifiNanIface.PowerParameters;
33 
34 import java.io.FileDescriptor;
35 import java.io.PrintWriter;
36 import java.util.Arrays;
37 import java.util.HashMap;
38 import java.util.Map;
39 
40 /**
41  * Translates Wi-Fi Aware requests from the framework to the HAL.
42  *
43  * Delegates the management of the NAN interface to WifiAwareNativeManager.
44  */
45 public class WifiAwareNativeApi implements WifiAwareShellCommand.DelegatedShellCommand {
46     private static final String TAG = "WifiAwareNativeApi";
47     private boolean mVdbg = false; // STOPSHIP if true
48     private boolean mVerboseLoggingEnabled = false;
49 
50     private final WifiAwareNativeManager mHal;
51     private SparseIntArray mTransactionIds; // VDBG only!
52 
WifiAwareNativeApi(WifiAwareNativeManager wifiAwareNativeManager)53     public WifiAwareNativeApi(WifiAwareNativeManager wifiAwareNativeManager) {
54         mHal = wifiAwareNativeManager;
55         onReset();
56     }
57 
58     /**
59      * Enable/Disable verbose logging.
60      *
61      */
enableVerboseLogging(boolean verboseEnabled, boolean vDbg)62     public void enableVerboseLogging(boolean verboseEnabled, boolean vDbg) {
63         mVerboseLoggingEnabled = verboseEnabled;
64         mVdbg = vDbg;
65     }
66 
recordTransactionId(int transactionId)67     private void recordTransactionId(int transactionId) {
68         if (!mVdbg) return;
69 
70         if (transactionId == 0) {
71             return; // tid == 0 is used as a placeholder transaction ID in several commands
72         }
73 
74         if (mTransactionIds == null) {
75             mTransactionIds = new SparseIntArray();
76         }
77         int count = mTransactionIds.get(transactionId);
78         if (count != 0) {
79             Log.wtf(TAG, "Repeated transaction ID == " + transactionId);
80         }
81         mTransactionIds.append(transactionId, count + 1);
82     }
83 
84     /*
85      * Parameters settable through the shell command.
86      * see wifi/1.0/types.hal NanBandSpecificConfig.discoveryWindowIntervalVal and
87      * wifi/1.2/types.hal NanConfigRequestSupplemental_1_2 for description
88      */
89     /* package */ static final String POWER_PARAM_DEFAULT_KEY = "default";
90     /* package */ static final String POWER_PARAM_INACTIVE_KEY = "inactive";
91     /* package */ static final String POWER_PARAM_IDLE_KEY = "idle";
92 
93     /* package */ static final String PARAM_DW_24GHZ = "dw_24ghz";
94     private static final int PARAM_DW_24GHZ_DEFAULT = 1; // 1 -> DW=1, latency=512ms
95     private static final int PARAM_DW_24GHZ_INACTIVE = 4; // 4 -> DW=8, latency=4s
96     private static final int PARAM_DW_24GHZ_IDLE = 4; // == inactive
97 
98     /* package */ static final String PARAM_DW_5GHZ = "dw_5ghz";
99     private static final int PARAM_DW_5GHZ_DEFAULT = 1; // 1 -> DW=1, latency=512ms
100     private static final int PARAM_DW_5GHZ_INACTIVE = 0; // 0 = disabled
101     private static final int PARAM_DW_5GHZ_IDLE = 0; // == inactive
102 
103     /* package */ static final String PARAM_DW_6GHZ = "dw_6ghz";
104     private static final int PARAM_DW_6GHZ_DEFAULT = 1; // 1 -> DW=1, latency=512ms
105     private static final int PARAM_DW_6GHZ_INACTIVE = 0; // 0 = disabled
106     private static final int PARAM_DW_6GHZ_IDLE = 0; // == inactive
107 
108     /* package */ static final String PARAM_DISCOVERY_BEACON_INTERVAL_MS =
109             "disc_beacon_interval_ms";
110     private static final int PARAM_DISCOVERY_BEACON_INTERVAL_MS_DEFAULT = 0; // Firmware defaults
111     private static final int PARAM_DISCOVERY_BEACON_INTERVAL_MS_INACTIVE = 0; // Firmware defaults
112     private static final int PARAM_DISCOVERY_BEACON_INTERVAL_MS_IDLE = 0; // Firmware defaults
113 
114     /* package */ static final String PARAM_NUM_SS_IN_DISCOVERY = "num_ss_in_discovery";
115     private static final int PARAM_NUM_SS_IN_DISCOVERY_DEFAULT = 0; // Firmware defaults
116     private static final int PARAM_NUM_SS_IN_DISCOVERY_INACTIVE = 0; // Firmware defaults
117     private static final int PARAM_NUM_SS_IN_DISCOVERY_IDLE = 0; // Firmware defaults
118 
119     /* package */ static final String PARAM_ENABLE_DW_EARLY_TERM = "enable_dw_early_term";
120     private static final int PARAM_ENABLE_DW_EARLY_TERM_DEFAULT = 0; // boolean: 0 = false
121     private static final int PARAM_ENABLE_DW_EARLY_TERM_INACTIVE = 0; // boolean: 0 = false
122     private static final int PARAM_ENABLE_DW_EARLY_TERM_IDLE = 0; // boolean: 0 = false
123 
124     /* package */ static final String PARAM_MAC_RANDOM_INTERVAL_SEC = "mac_random_interval_sec";
125     private static final int PARAM_MAC_RANDOM_INTERVAL_SEC_DEFAULT = 1800; // 30 minutes
126 
127     private final Map<String, Map<String, Integer>> mSettablePowerParameters = new HashMap<>();
128     private final Map<String, Integer> mSettableParameters = new HashMap<>();
129     private final Map<String, Integer> mExternalSetParams = new ArrayMap<>();
130 
131     /**
132      * Accept using parameter from external to config the Aware
133      */
setAwareParams(AwareParams parameters)134     public void setAwareParams(AwareParams parameters) {
135         mExternalSetParams.clear();
136         if (parameters == null) {
137             return;
138         }
139         if (mVerboseLoggingEnabled) {
140             Log.v(TAG, "setting Aware Parameters=" + parameters);
141         }
142         if (parameters.getDiscoveryWindowWakeInterval24Ghz() > 0
143                 && parameters.getDiscoveryWindowWakeInterval24Ghz() <= 5) {
144             mExternalSetParams.put(PARAM_DW_24GHZ,
145                     parameters.getDiscoveryWindowWakeInterval24Ghz());
146         }
147         if (parameters.getDiscoveryWindowWakeInterval5Ghz() >= 0
148                 && parameters.getDiscoveryWindowWakeInterval5Ghz() <= 5) {
149             mExternalSetParams.put(PARAM_DW_5GHZ, parameters.getDiscoveryWindowWakeInterval5Ghz());
150         }
151         if (parameters.getDiscoveryBeaconIntervalMillis() > 0) {
152             mExternalSetParams.put(PARAM_DISCOVERY_BEACON_INTERVAL_MS,
153                     parameters.getDiscoveryBeaconIntervalMillis());
154         }
155         if (parameters.getNumSpatialStreamsInDiscovery() > 0) {
156             mExternalSetParams.put(PARAM_NUM_SS_IN_DISCOVERY,
157                     parameters.getNumSpatialStreamsInDiscovery());
158         }
159         if (parameters.getMacRandomizationIntervalSeconds() > 0
160                 && parameters.getMacRandomizationIntervalSeconds() <= 1800) {
161             mExternalSetParams.put(PARAM_MAC_RANDOM_INTERVAL_SEC,
162                     parameters.getMacRandomizationIntervalSeconds());
163         }
164         if (parameters.isDwEarlyTerminationEnabled()) {
165             mExternalSetParams.put(PARAM_ENABLE_DW_EARLY_TERM, 1);
166         }
167     }
168 
169 
170     /**
171      * Interpreter of adb shell command 'adb shell wifiaware native_api ...'.
172      *
173      * @return -1 if parameter not recognized or invalid value, 0 otherwise.
174      */
175     @Override
onCommand(BasicShellCommandHandler parentShell)176     public int onCommand(BasicShellCommandHandler parentShell) {
177         final PrintWriter pw = parentShell.getErrPrintWriter();
178 
179         String subCmd = parentShell.getNextArgRequired();
180         if (mVdbg) Log.v(TAG, "onCommand: subCmd='" + subCmd + "'");
181         switch (subCmd) {
182             case "set": {
183                 String name = parentShell.getNextArgRequired();
184                 if (mVdbg) Log.v(TAG, "onCommand: name='" + name + "'");
185                 if (!mSettableParameters.containsKey(name)) {
186                     pw.println("Unknown parameter name -- '" + name + "'");
187                     return -1;
188                 }
189 
190                 String valueStr = parentShell.getNextArgRequired();
191                 if (mVdbg) Log.v(TAG, "onCommand: valueStr='" + valueStr + "'");
192                 int value;
193                 try {
194                     value = Integer.valueOf(valueStr);
195                 } catch (NumberFormatException e) {
196                     pw.println("Can't convert value to integer -- '" + valueStr + "'");
197                     return -1;
198                 }
199                 mSettableParameters.put(name, value);
200                 return 0;
201             }
202             case "set-power": {
203                 String mode = parentShell.getNextArgRequired();
204                 String name = parentShell.getNextArgRequired();
205                 String valueStr = parentShell.getNextArgRequired();
206 
207                 if (mVdbg) {
208                     Log.v(TAG, "onCommand: mode='" + mode + "', name='" + name + "'" + ", value='"
209                             + valueStr + "'");
210                 }
211 
212                 if (!mSettablePowerParameters.containsKey(mode)) {
213                     pw.println("Unknown mode name -- '" + mode + "'");
214                     return -1;
215                 }
216                 if (!mSettablePowerParameters.get(mode).containsKey(name)) {
217                     pw.println("Unknown parameter name '" + name + "' in mode '" + mode + "'");
218                     return -1;
219                 }
220 
221                 int value;
222                 try {
223                     value = Integer.valueOf(valueStr);
224                 } catch (NumberFormatException e) {
225                     pw.println("Can't convert value to integer -- '" + valueStr + "'");
226                     return -1;
227                 }
228                 mSettablePowerParameters.get(mode).put(name, value);
229                 return 0;
230             }
231             case "get": {
232                 String name = parentShell.getNextArgRequired();
233                 if (mVdbg) Log.v(TAG, "onCommand: name='" + name + "'");
234                 if (!mSettableParameters.containsKey(name)) {
235                     pw.println("Unknown parameter name -- '" + name + "'");
236                     return -1;
237                 }
238 
239                 parentShell.getOutPrintWriter().println((int) mSettableParameters.get(name));
240                 return 0;
241             }
242             case "get-power": {
243                 String mode = parentShell.getNextArgRequired();
244                 String name = parentShell.getNextArgRequired();
245                 if (mVdbg) Log.v(TAG, "onCommand: mode='" + mode + "', name='" + name + "'");
246                 if (!mSettablePowerParameters.containsKey(mode)) {
247                     pw.println("Unknown mode -- '" + mode + "'");
248                     return -1;
249                 }
250                 if (!mSettablePowerParameters.get(mode).containsKey(name)) {
251                     pw.println("Unknown parameter name -- '" + name + "' in mode '" + mode + "'");
252                     return -1;
253                 }
254 
255                 parentShell.getOutPrintWriter().println(
256                         (int) mSettablePowerParameters.get(mode).get(name));
257                 return 0;
258             }
259             default:
260                 pw.println("Unknown 'wifiaware native_api <cmd>'");
261         }
262 
263         return -1;
264     }
265 
266     @Override
onReset()267     public void onReset() {
268         Map<String, Integer> defaultMap = new HashMap<>();
269         defaultMap.put(PARAM_DW_24GHZ, PARAM_DW_24GHZ_DEFAULT);
270         defaultMap.put(PARAM_DW_5GHZ, PARAM_DW_5GHZ_DEFAULT);
271         defaultMap.put(PARAM_DW_6GHZ, PARAM_DW_6GHZ_DEFAULT);
272         defaultMap.put(PARAM_DISCOVERY_BEACON_INTERVAL_MS,
273                 PARAM_DISCOVERY_BEACON_INTERVAL_MS_DEFAULT);
274         defaultMap.put(PARAM_NUM_SS_IN_DISCOVERY, PARAM_NUM_SS_IN_DISCOVERY_DEFAULT);
275         defaultMap.put(PARAM_ENABLE_DW_EARLY_TERM, PARAM_ENABLE_DW_EARLY_TERM_DEFAULT);
276 
277         Map<String, Integer> inactiveMap = new HashMap<>();
278         inactiveMap.put(PARAM_DW_24GHZ, PARAM_DW_24GHZ_INACTIVE);
279         inactiveMap.put(PARAM_DW_5GHZ, PARAM_DW_5GHZ_INACTIVE);
280         inactiveMap.put(PARAM_DW_6GHZ, PARAM_DW_6GHZ_INACTIVE);
281         inactiveMap.put(PARAM_DISCOVERY_BEACON_INTERVAL_MS,
282                 PARAM_DISCOVERY_BEACON_INTERVAL_MS_INACTIVE);
283         inactiveMap.put(PARAM_NUM_SS_IN_DISCOVERY, PARAM_NUM_SS_IN_DISCOVERY_INACTIVE);
284         inactiveMap.put(PARAM_ENABLE_DW_EARLY_TERM, PARAM_ENABLE_DW_EARLY_TERM_INACTIVE);
285 
286         Map<String, Integer> idleMap = new HashMap<>();
287         idleMap.put(PARAM_DW_24GHZ, PARAM_DW_24GHZ_IDLE);
288         idleMap.put(PARAM_DW_5GHZ, PARAM_DW_5GHZ_IDLE);
289         idleMap.put(PARAM_DW_6GHZ, PARAM_DW_6GHZ_IDLE);
290         idleMap.put(PARAM_DISCOVERY_BEACON_INTERVAL_MS,
291                 PARAM_DISCOVERY_BEACON_INTERVAL_MS_IDLE);
292         idleMap.put(PARAM_NUM_SS_IN_DISCOVERY, PARAM_NUM_SS_IN_DISCOVERY_IDLE);
293         idleMap.put(PARAM_ENABLE_DW_EARLY_TERM, PARAM_ENABLE_DW_EARLY_TERM_IDLE);
294 
295         mSettablePowerParameters.put(POWER_PARAM_DEFAULT_KEY, defaultMap);
296         mSettablePowerParameters.put(POWER_PARAM_INACTIVE_KEY, inactiveMap);
297         mSettablePowerParameters.put(POWER_PARAM_IDLE_KEY, idleMap);
298 
299         mSettableParameters.put(PARAM_MAC_RANDOM_INTERVAL_SEC,
300                 PARAM_MAC_RANDOM_INTERVAL_SEC_DEFAULT);
301         mExternalSetParams.clear();
302     }
303 
304     @Override
onHelp(String command, BasicShellCommandHandler parentShell)305     public void onHelp(String command, BasicShellCommandHandler parentShell) {
306         final PrintWriter pw = parentShell.getOutPrintWriter();
307 
308         pw.println("  " + command);
309         pw.println("    set <name> <value>: sets named parameter to value. Names: "
310                 + mSettableParameters.keySet());
311         pw.println("    set-power <mode> <name> <value>: sets named power parameter to value."
312                 + " Modes: " + mSettablePowerParameters.keySet()
313                 + ", Names: " + mSettablePowerParameters.get(POWER_PARAM_DEFAULT_KEY).keySet());
314         pw.println("    get <name>: gets named parameter value. Names: "
315                 + mSettableParameters.keySet());
316         pw.println("    get-power <mode> <name>: gets named parameter value."
317                 + " Modes: " + mSettablePowerParameters.keySet()
318                 + ", Names: " + mSettablePowerParameters.get(POWER_PARAM_DEFAULT_KEY).keySet());
319     }
320 
321     /**
322      * Query the firmware's capabilities.
323      *
324      * @param transactionId Transaction ID for the transaction - used in the async callback to
325      *                      match with the original request.
326      */
getCapabilities(short transactionId)327     public boolean getCapabilities(short transactionId) {
328         if (mVerboseLoggingEnabled) Log.v(TAG, "getCapabilities: transactionId=" + transactionId);
329         recordTransactionId(transactionId);
330 
331         WifiNanIface iface = mHal.getWifiNanIface();
332         if (iface == null) {
333             Log.e(TAG, "getCapabilities: null interface");
334             return false;
335         }
336         return iface.getCapabilities(transactionId);
337     }
338 
339     /**
340      * Enable and configure Aware.
341      * @param transactionId Transaction ID for the transaction - used in the
342      *            async callback to match with the original request.
343      * @param configRequest Requested Aware configuration.
344      * @param notifyIdentityChange Indicates whether or not to get address change callbacks.
345      * @param initialConfiguration Specifies whether initial configuration
346 *            (true) or an update (false) to the configuration.
347      * @param isInteractive PowerManager.isInteractive
348      * @param isIdle PowerManager.isIdle
349      * @param rangingEnabled Indicates whether or not enable ranging.
350      * @param isInstantCommunicationEnabled Indicates whether or not enable instant communication
351      * @param instantModeChannel
352      * @param clusterId the id of the cluster to join.
353      */
enableAndConfigure(short transactionId, ConfigRequest configRequest, boolean notifyIdentityChange, boolean initialConfiguration, boolean isInteractive, boolean isIdle, boolean rangingEnabled, boolean isInstantCommunicationEnabled, int instantModeChannel, int clusterId)354     public boolean enableAndConfigure(short transactionId, ConfigRequest configRequest,
355             boolean notifyIdentityChange, boolean initialConfiguration, boolean isInteractive,
356             boolean isIdle, boolean rangingEnabled, boolean isInstantCommunicationEnabled,
357             int instantModeChannel, int clusterId) {
358         Log.d(TAG, "enableAndConfigure: transactionId=" + transactionId + ", configRequest="
359                 + configRequest + ", notifyIdentityChange=" + notifyIdentityChange
360                 + ", initialConfiguration=" + initialConfiguration
361                 + ", isInteractive=" + isInteractive + ", isIdle=" + isIdle
362                 + ", isRangingEnabled=" + rangingEnabled
363                 + ", isInstantCommunicationEnabled=" + isInstantCommunicationEnabled
364                 + ", instantModeChannel=" + instantModeChannel
365                 + ", clusterId=" + clusterId);
366         recordTransactionId(transactionId);
367 
368         WifiNanIface iface = mHal.getWifiNanIface();
369         if (iface == null) {
370             Log.e(TAG, "enableAndConfigure: null interface");
371             return false;
372         }
373         return iface.enableAndConfigure(transactionId, configRequest, notifyIdentityChange,
374                 initialConfiguration, rangingEnabled,
375                 isInstantCommunicationEnabled, instantModeChannel, clusterId,
376                 mExternalSetParams.getOrDefault(PARAM_MAC_RANDOM_INTERVAL_SEC,
377                         mSettableParameters.get(PARAM_MAC_RANDOM_INTERVAL_SEC)),
378                 getPowerParameters(isInteractive, isIdle));
379     }
380 
381     /**
382      * Disable Aware.
383      *
384      * @param transactionId transactionId Transaction ID for the transaction -
385      *            used in the async callback to match with the original request.
386      */
disable(short transactionId)387     public boolean disable(short transactionId) {
388         if (mVerboseLoggingEnabled) Log.d(TAG, "disable");
389         recordTransactionId(transactionId);
390 
391         WifiNanIface iface = mHal.getWifiNanIface();
392         if (iface == null) {
393             Log.e(TAG, "disable: null interface");
394             return false;
395         }
396         boolean result = iface.disable(transactionId);
397         return result;
398     }
399 
400     /**
401      * Start or modify a service publish session.
402      *  @param transactionId transactionId Transaction ID for the transaction -
403      *            used in the async callback to match with the original request.
404      * @param publishId ID of the requested session - 0 to request a new publish
405      *            session.
406      * @param publishConfig Configuration of the discovery session.
407      * @param nik
408      */
publish(short transactionId, byte publishId, PublishConfig publishConfig, byte[] nik)409     public boolean publish(short transactionId, byte publishId, PublishConfig publishConfig,
410             byte[] nik) {
411         if (mVerboseLoggingEnabled) {
412             Log.d(TAG, "publish: transactionId=" + transactionId + ", publishId=" + publishId
413                     + ", config=" + publishConfig);
414         }
415         recordTransactionId(transactionId);
416 
417         WifiNanIface iface = mHal.getWifiNanIface();
418         if (iface == null) {
419             Log.e(TAG, "publish: null interface");
420             return false;
421         }
422         return iface.publish(transactionId, publishId, publishConfig, nik);
423     }
424 
425     /**
426      * Start or modify a service subscription session.
427      *  @param transactionId transactionId Transaction ID for the transaction -
428      *            used in the async callback to match with the original request.
429      * @param subscribeId ID of the requested session - 0 to request a new
430      *            subscribe session.
431      * @param subscribeConfig Configuration of the discovery session.
432      * @param nik
433      */
subscribe(short transactionId, byte subscribeId, SubscribeConfig subscribeConfig, byte[] nik)434     public boolean subscribe(short transactionId, byte subscribeId,
435             SubscribeConfig subscribeConfig, byte[] nik) {
436         if (mVerboseLoggingEnabled) {
437             Log.d(TAG, "subscribe: transactionId=" + transactionId + ", subscribeId=" + subscribeId
438                     + ", config=" + subscribeConfig);
439         }
440         recordTransactionId(transactionId);
441 
442         WifiNanIface iface = mHal.getWifiNanIface();
443         if (iface == null) {
444             Log.e(TAG, "subscribe: null interface");
445             return false;
446         }
447         return iface.subscribe(transactionId, subscribeId, subscribeConfig, nik);
448     }
449 
450     /**
451      * Send a message through an existing discovery session.
452      *
453      * @param transactionId transactionId Transaction ID for the transaction -
454      *            used in the async callback to match with the original request.
455      * @param pubSubId ID of the existing publish/subscribe session.
456      * @param requestorInstanceId ID of the peer to communicate with - obtained
457      *            through a previous discovery (match) operation with that peer.
458      * @param dest MAC address of the peer to communicate with - obtained
459      *            together with requestorInstanceId.
460      * @param message Message.
461      * @param messageId Arbitary integer from host (not sent to HAL - useful for
462      *                  testing/debugging at this level)
463      */
sendMessage(short transactionId, byte pubSubId, int requestorInstanceId, byte[] dest, byte[] message, int messageId)464     public boolean sendMessage(short transactionId, byte pubSubId, int requestorInstanceId,
465             byte[] dest, byte[] message, int messageId) {
466         if (mVerboseLoggingEnabled) {
467             Log.d(TAG,
468                     "sendMessage: transactionId=" + transactionId + ", pubSubId=" + pubSubId
469                             + ", requestorInstanceId=" + requestorInstanceId + ", dest="
470                             + String.valueOf(HexEncoding.encode(dest)) + ", messageId=" + messageId
471                             + ", message=" + (message == null ? "<null>"
472                             : HexEncoding.encode(message)) + ", message.length=" + (message == null
473                             ? 0 : message.length));
474         }
475         recordTransactionId(transactionId);
476 
477         WifiNanIface iface = mHal.getWifiNanIface();
478         if (iface == null) {
479             Log.e(TAG, "sendMessage: null interface");
480             return false;
481         }
482 
483         try {
484             MacAddress destMac = MacAddress.fromBytes(dest);
485             return iface.sendMessage(
486                     transactionId, pubSubId, requestorInstanceId, destMac, message);
487         } catch (IllegalArgumentException e) {
488             Log.e(TAG, "Invalid dest mac received: " + Arrays.toString(dest));
489             return false;
490         }
491     }
492 
493     /**
494      * Terminate a publish discovery session.
495      *
496      * @param transactionId transactionId Transaction ID for the transaction -
497      *            used in the async callback to match with the original request.
498      * @param pubSubId ID of the publish/subscribe session - obtained when
499      *            creating a session.
500      */
stopPublish(short transactionId, byte pubSubId)501     public boolean stopPublish(short transactionId, byte pubSubId) {
502         if (mVerboseLoggingEnabled) {
503             Log.d(TAG, "stopPublish: transactionId=" + transactionId + ", pubSubId=" + pubSubId);
504         }
505         recordTransactionId(transactionId);
506 
507         WifiNanIface iface = mHal.getWifiNanIface();
508         if (iface == null) {
509             Log.e(TAG, "stopPublish: null interface");
510             return false;
511         }
512         return iface.stopPublish(transactionId, pubSubId);
513     }
514 
515     /**
516      * Terminate a subscribe discovery session.
517      *
518      * @param transactionId transactionId Transaction ID for the transaction -
519      *            used in the async callback to match with the original request.
520      * @param pubSubId ID of the publish/subscribe session - obtained when
521      *            creating a session.
522      */
stopSubscribe(short transactionId, byte pubSubId)523     public boolean stopSubscribe(short transactionId, byte pubSubId) {
524         if (mVerboseLoggingEnabled) {
525             Log.d(TAG, "stopSubscribe: transactionId=" + transactionId + ", pubSubId=" + pubSubId);
526         }
527         recordTransactionId(transactionId);
528 
529         WifiNanIface iface = mHal.getWifiNanIface();
530         if (iface == null) {
531             Log.e(TAG, "stopSubscribe: null interface");
532             return false;
533         }
534         return iface.stopSubscribe(transactionId, pubSubId);
535     }
536 
537     /**
538      * Create a Aware network interface. This only creates the Linux interface - it doesn't actually
539      * create the data connection.
540      *
541      * @param transactionId Transaction ID for the transaction - used in the async callback to
542      *                      match with the original request.
543      * @param interfaceName The name of the interface, e.g. "aware0".
544      */
createAwareNetworkInterface(short transactionId, String interfaceName)545     public boolean createAwareNetworkInterface(short transactionId, String interfaceName) {
546         Log.d(TAG, "createAwareNetworkInterface: transactionId=" + transactionId + ", "
547                     + "interfaceName=" + interfaceName);
548         recordTransactionId(transactionId);
549 
550         WifiNanIface iface = mHal.getWifiNanIface();
551         if (iface == null) {
552             Log.e(TAG, "createAwareNetworkInterface: null interface");
553             return false;
554         }
555         return iface.createAwareNetworkInterface(transactionId, interfaceName);
556     }
557 
558     /**
559      * Deletes a Aware network interface. The data connection can (should?) be torn down previously.
560      *
561      * @param transactionId Transaction ID for the transaction - used in the async callback to
562      *                      match with the original request.
563      * @param interfaceName The name of the interface, e.g. "aware0".
564      */
deleteAwareNetworkInterface(short transactionId, String interfaceName)565     public boolean deleteAwareNetworkInterface(short transactionId, String interfaceName) {
566         Log.d(TAG, "deleteAwareNetworkInterface: transactionId=" + transactionId + ", "
567                 + "interfaceName=" + interfaceName);
568         recordTransactionId(transactionId);
569 
570         WifiNanIface iface = mHal.getWifiNanIface();
571         if (iface == null) {
572             Log.e(TAG, "deleteAwareNetworkInterface: null interface");
573             return false;
574         }
575         return iface.deleteAwareNetworkInterface(transactionId, interfaceName);
576     }
577 
578     /**
579      * Initiates setting up a data-path between device and peer. Security is provided by either
580      * PMK or Passphrase (not both) - if both are null then an open (unencrypted) link is set up.
581      *
582      * @param transactionId      Transaction ID for the transaction - used in the async callback to
583      *                           match with the original request.
584      * @param peerId             ID of the peer ID to associate the data path with. A value of 0
585      *                           indicates that not associated with an existing session.
586      * @param channelRequestType Indicates whether the specified channel is available, if available
587      *                           requested or forced (resulting in failure if cannot be
588      *                           accommodated).
589      * @param channel            The channel on which to set up the data-path.
590      * @param peer               The MAC address of the peer to create a connection with.
591      * @param interfaceName      The interface on which to create the data connection.
592      * @param isOutOfBand        Is the data-path out-of-band (i.e. without a corresponding Aware
593      *                           discovery
594      *                           session).
595      * @param appInfo            Arbitrary binary blob transmitted to the peer.
596      * @param capabilities       The capabilities of the firmware.
597      * @param securityConfig     Security config to encrypt the data-path
598      */
initiateDataPath(short transactionId, int peerId, int channelRequestType, int channel, byte[] peer, String interfaceName, boolean isOutOfBand, byte[] appInfo, Capabilities capabilities, WifiAwareDataPathSecurityConfig securityConfig, byte pubSubId)599     public boolean initiateDataPath(short transactionId, int peerId, int channelRequestType,
600             int channel, byte[] peer, String interfaceName,
601             boolean isOutOfBand, byte[] appInfo, Capabilities capabilities,
602             WifiAwareDataPathSecurityConfig securityConfig, byte pubSubId) {
603         if (mVerboseLoggingEnabled) {
604             Log.v(TAG, "initiateDataPath: transactionId=" + transactionId + ", peerId=" + peerId
605                     + ", channelRequestType=" + channelRequestType + ", channel=" + channel
606                     + ", peer=" + String.valueOf(HexEncoding.encode(peer)) + ", interfaceName="
607                     + interfaceName + ", securityConfig=" + securityConfig
608                     + ", isOutOfBand=" + isOutOfBand + ", appInfo.length="
609                     + ((appInfo == null) ? 0 : appInfo.length) + ", capabilities=" + capabilities);
610         }
611         recordTransactionId(transactionId);
612 
613         WifiNanIface iface = mHal.getWifiNanIface();
614         if (iface == null) {
615             Log.e(TAG, "initiateDataPath: null interface");
616             return false;
617         }
618 
619         try {
620             MacAddress peerMac = MacAddress.fromBytes(peer);
621             return iface.initiateDataPath(transactionId, peerId, channelRequestType, channel,
622                     peerMac, interfaceName, isOutOfBand, appInfo, capabilities, securityConfig,
623                     pubSubId);
624         } catch (IllegalArgumentException e) {
625             Log.e(TAG, "Invalid peer mac received: " + Arrays.toString(peer));
626             return false;
627         }
628     }
629 
630     /**
631      * Responds to a data request from a peer. Security is provided by either PMK or Passphrase (not
632      * both) - if both are null then an open (unencrypted) link is set up.
633      *
634      * @param transactionId  Transaction ID for the transaction - used in the async callback to
635      *                       match with the original request.
636      * @param accept         Accept (true) or reject (false) the original call.
637      * @param ndpId          The NDP (Aware data path) ID. Obtained from the request callback.
638      * @param interfaceName  The interface on which the data path will be setup. Obtained from the
639      *                       request callback.
640      * @param appInfo        Arbitrary binary blob transmitted to the peer.
641      * @param isOutOfBand    Is the data-path out-of-band (i.e. without a corresponding Aware
642      *                       discovery
643      *                       session).
644      * @param capabilities   The capabilities of the firmware.
645      * @param securityConfig Security config to encrypt the data-path
646      */
respondToDataPathRequest(short transactionId, boolean accept, int ndpId, String interfaceName, byte[] appInfo, boolean isOutOfBand, Capabilities capabilities, WifiAwareDataPathSecurityConfig securityConfig, byte pubSubId)647     public boolean respondToDataPathRequest(short transactionId, boolean accept, int ndpId,
648             String interfaceName, byte[] appInfo,
649             boolean isOutOfBand, Capabilities capabilities,
650             WifiAwareDataPathSecurityConfig securityConfig, byte pubSubId) {
651         if (mVerboseLoggingEnabled) {
652             Log.v(TAG, "respondToDataPathRequest: transactionId=" + transactionId + ", accept="
653                     + accept + ", int ndpId=" + ndpId + ", interfaceName=" + interfaceName
654                     + ", appInfo.length=" + ((appInfo == null) ? 0 : appInfo.length)
655                     + ", securityConfig" + securityConfig);
656         }
657         recordTransactionId(transactionId);
658 
659         WifiNanIface iface = mHal.getWifiNanIface();
660         if (iface == null) {
661             Log.e(TAG, "respondToDataPathRequest: null interface");
662             return false;
663         }
664         return iface.respondToDataPathRequest(transactionId, accept, ndpId, interfaceName, appInfo,
665                 isOutOfBand, capabilities, securityConfig, pubSubId);
666     }
667 
668     /**
669      * Terminate an existing data-path (does not delete the interface).
670      *
671      * @param transactionId Transaction ID for the transaction - used in the async callback to
672      *                      match with the original request.
673      * @param ndpId The NDP (Aware data path) ID to be terminated.
674      */
endDataPath(short transactionId, int ndpId)675     public boolean endDataPath(short transactionId, int ndpId) {
676         if (mVerboseLoggingEnabled) {
677             Log.v(TAG, "endDataPath: transactionId=" + transactionId + ", ndpId=" + ndpId);
678         }
679         recordTransactionId(transactionId);
680 
681         WifiNanIface iface = mHal.getWifiNanIface();
682         if (iface == null) {
683             Log.e(TAG, "endDataPath: null interface");
684             return false;
685         }
686         return iface.endDataPath(transactionId, ndpId);
687     }
688 
689     /**
690      * Terminate an existing pairing setup
691      *
692      * @param transactionId Transaction ID for the transaction - used in the async callback to
693      *                      match with the original request.
694      * @param pairId The id of the pairing session
695      */
endPairing(short transactionId, int pairId)696     public boolean endPairing(short transactionId, int pairId) {
697         if (mVerboseLoggingEnabled) {
698             Log.v(TAG, "endPairing: transactionId=" + transactionId + ", ndpId=" + pairId);
699         }
700         recordTransactionId(transactionId);
701 
702         WifiNanIface iface = mHal.getWifiNanIface();
703         if (iface == null) {
704             Log.e(TAG, "endDataPath: null interface");
705             return false;
706         }
707         return iface.endPairing(transactionId, pairId);
708     }
709 
710     /**
711      * Initiate a NAN pairing request for this publish/subscribe session
712      *
713      * @param transactionId      Transaction ID for the transaction - used in the
714      *                           async callback to match with the original request.
715      * @param peerId             ID of the peer. Obtained through previous communication (a
716      *                           match indication).
717      * @param pairingIdentityKey NAN identity key
718      * @param requestType        Setup or verification
719      * @param pmk                credential for the pairing verification
720      * @param password           credential for the pairing setup
721      * @param akm                Key exchange method is used for pairing
722      * @return True is the request send succeed.
723      */
initiatePairing(short transactionId, int peerId, byte[] peer, byte[] pairingIdentityKey, boolean enablePairingCache, int requestType, byte[] pmk, String password, int akm, int cipherSuite)724     public boolean initiatePairing(short transactionId, int peerId, byte[] peer,
725             byte[] pairingIdentityKey, boolean enablePairingCache, int requestType, byte[] pmk,
726             String password, int akm, int cipherSuite) {
727         if (mVerboseLoggingEnabled) {
728             Log.v(TAG, "initiatePairing: transactionId=" + transactionId + ", peerId=" + peerId
729                     + ", requestType=" + requestType + ", enablePairingCache=" + enablePairingCache
730                     + ", peer=" + String.valueOf(HexEncoding.encode(peer)));
731         }
732         recordTransactionId(transactionId);
733 
734         WifiNanIface iface = mHal.getWifiNanIface();
735         if (iface == null) {
736             Log.e(TAG, "initiatePairing: null interface");
737             return false;
738         }
739 
740         try {
741             MacAddress peerMac = MacAddress.fromBytes(peer);
742             return iface.initiatePairing(transactionId, peerId, peerMac, pairingIdentityKey,
743                     enablePairingCache, requestType, pmk, password, akm, cipherSuite);
744         } catch (IllegalArgumentException e) {
745             Log.e(TAG, "Invalid peer mac received: " + Arrays.toString(peer));
746             return false;
747         }
748     }
749 
750     /**
751      * Response to a NAN pairing request for this from this session
752      *
753      * @param transactionId      Transaction ID for the transaction - used in the
754      *                           async callback to match with the original request.
755      * @param pairingId          The id of the current pairing session
756      * @param accept             True if accpect, false otherwise
757      * @param pairingIdentityKey NAN identity key
758      * @param requestType        Setup or verification
759      * @param pmk                credential for the pairing verification
760      * @param password           credential for the pairing setup
761      * @param akm                Key exchange method is used for pairing
762      * @return True is the request send succeed.
763      */
respondToPairingRequest(short transactionId, int pairingId, boolean accept, byte[] pairingIdentityKey, boolean enablePairingCache, int requestType, byte[] pmk, String password, int akm, int cipherSuite)764     public boolean respondToPairingRequest(short transactionId, int pairingId, boolean accept,
765             byte[] pairingIdentityKey, boolean enablePairingCache, int requestType, byte[] pmk,
766             String password, int akm, int cipherSuite) {
767         if (mVerboseLoggingEnabled) {
768             Log.v(
769                     TAG,
770                     "respondToPairingRequest: transactionId="
771                             + transactionId
772                             + ", accept="
773                             + accept
774                             + ", int pairingId="
775                             + pairingId
776                             + ", enablePairingCache="
777                             + enablePairingCache
778                             + ", requestType"
779                             + requestType);
780         }
781         recordTransactionId(transactionId);
782 
783         WifiNanIface iface = mHal.getWifiNanIface();
784         if (iface == null) {
785             Log.e(TAG, "respondToPairingRequest: null interface");
786             return false;
787         }
788         return iface.respondToPairingRequest(transactionId, pairingId, accept, pairingIdentityKey,
789                 enablePairingCache, requestType, pmk, password, akm, cipherSuite);
790     }
791 
792     /**
793      * Initiate a Bootstrapping request for this publish/subscribe session
794      *
795      * @param transactionId Transaction ID for the transaction - used in the
796      *                      async callback to match with the original request.
797      * @param peerId        ID of the peer. Obtained through previous communication (a match
798      *                      indication).
799      * @param peer          The MAC address of the peer to create a connection with.
800      * @param method        proposed bootstrapping method
801      * @param pubSubId      ID of the publish/subscribe session - obtained when creating a session.
802      * @param isComeBack    If the request is for a previous comeback response
803      * @return True if the request send success
804      */
initiateBootstrapping(short transactionId, int peerId, byte[] peer, int method, byte[] cookie, byte pubSubId, boolean isComeBack)805     public boolean initiateBootstrapping(short transactionId, int peerId, byte[] peer, int method,
806             byte[] cookie, byte pubSubId, boolean isComeBack) {
807         if (mVerboseLoggingEnabled) {
808             Log.v(TAG, "initiateBootstrapping: transactionId=" + transactionId
809                     + ", peerId=" + peerId + ", method=" + method
810                     + ", peer=" + String.valueOf(HexEncoding.encode(peer)));
811         }
812         recordTransactionId(transactionId);
813 
814         WifiNanIface iface = mHal.getWifiNanIface();
815         if (iface == null) {
816             Log.e(TAG, "initiateBootstrapping: null interface");
817             return false;
818         }
819 
820         try {
821             MacAddress peerMac = MacAddress.fromBytes(peer);
822             return iface.initiateBootstrapping(transactionId, peerId, peerMac, method, cookie,
823                     pubSubId, isComeBack);
824         } catch (IllegalArgumentException e) {
825             Log.e(TAG, "Invalid peer mac received: " + Arrays.toString(peer));
826             return false;
827         }
828     }
829 
830     /**
831      * Response to a bootstrapping request for this from this session
832      *
833      * @param transactionId   Transaction ID for the transaction - used in the
834      *                        async callback to match with the original request.
835      * @param bootstrappingId The id of the current boostraping session
836      * @param accept          True is proposed method is accepte
837      * @param pubSubId        ID of the publish/subscribe session - obtained when creating a
838      *                        session.
839      * @return True if the request send success
840      */
respondToBootstrappingRequest(short transactionId, int bootstrappingId, boolean accept, byte pubSubId)841     public boolean respondToBootstrappingRequest(short transactionId, int bootstrappingId,
842             boolean accept, byte pubSubId) {
843         if (mVerboseLoggingEnabled) {
844             Log.v(TAG, "respondToBootstrappingRequest: transactionId=" + transactionId);
845         }
846         recordTransactionId(transactionId);
847 
848         WifiNanIface iface = mHal.getWifiNanIface();
849         if (iface == null) {
850             Log.e(TAG, "respondToBootstrappingRequest: null interface");
851             return false;
852         }
853 
854         return iface.respondToBootstrappingRequest(transactionId, bootstrappingId, accept,
855                 pubSubId);
856     }
857 
858     /**
859      * Suspends the specified Aware session.
860      * @param transactionId transactionId Transaction ID for the transaction -
861      *            used in the async callback to match with the original request.
862      * @param pubSubId ID of the existing publish/subscribe session.
863      * @return True if the request is sent successfully.
864      */
suspendRequest(short transactionId, byte pubSubId)865     public boolean suspendRequest(short transactionId, byte pubSubId) {
866         if (mVerboseLoggingEnabled) {
867             Log.v(TAG, "suspendRequest: transactionId=" + transactionId);
868         }
869         recordTransactionId(transactionId);
870 
871         WifiNanIface iface = mHal.getWifiNanIface();
872         if (iface == null) {
873             Log.e(TAG, "suspendRequest: null interface");
874             return false;
875         }
876 
877         return iface.suspendRequest(transactionId, pubSubId);
878     }
879 
880     /**
881      * Resumes the specified (suspended) Aware session.
882      * @param transactionId transactionId Transaction ID for the transaction -
883      *            used in the async callback to match with the original request.
884      * @param pubSubId ID of the existing publish/subscribe session.
885      * @return True if the request is sent successfully.
886      */
resumeRequest(short transactionId, byte pubSubId)887     public boolean resumeRequest(short transactionId, byte pubSubId) {
888         if (mVerboseLoggingEnabled) {
889             Log.v(TAG, "resumeRequest: transactionId=" + transactionId);
890         }
891         recordTransactionId(transactionId);
892 
893         WifiNanIface iface = mHal.getWifiNanIface();
894         if (iface == null) {
895             Log.e(TAG, "resumeRequest: null interface");
896             return false;
897         }
898 
899         return iface.resumeRequest(transactionId, pubSubId);
900     }
901 
902     // utilities
903 
904     /**
905      * Create a PowerParameters object to pass our cached parameters to the HAL.
906      */
getPowerParameters( boolean isInteractive, boolean isIdle)907     private PowerParameters getPowerParameters(
908             boolean isInteractive, boolean isIdle) {
909         PowerParameters params = new PowerParameters();
910         String key = POWER_PARAM_DEFAULT_KEY;
911         if (isIdle) {
912             key = POWER_PARAM_IDLE_KEY;
913         } else if (!isInteractive) {
914             key = POWER_PARAM_INACTIVE_KEY;
915         }
916 
917         params.discoveryWindow24Ghz = getSettablePowerParameters(key, PARAM_DW_24GHZ);
918         params.discoveryWindow5Ghz = getSettablePowerParameters(key, PARAM_DW_5GHZ);
919         params.discoveryWindow6Ghz = getSettablePowerParameters(key, PARAM_DW_6GHZ);
920         params.discoveryBeaconIntervalMs = getSettablePowerParameters(key,
921                 PARAM_DISCOVERY_BEACON_INTERVAL_MS);
922         params.numberOfSpatialStreamsInDiscovery = getSettablePowerParameters(key,
923                 PARAM_NUM_SS_IN_DISCOVERY);
924         params.enableDiscoveryWindowEarlyTermination = getSettablePowerParameters(key,
925                 PARAM_ENABLE_DW_EARLY_TERM) != 0;
926         return params;
927     }
928 
getSettablePowerParameters(String state, String key)929     private int getSettablePowerParameters(String state, String key) {
930         if (mExternalSetParams.containsKey(key)) {
931             return mExternalSetParams.get(key);
932         }
933         return mSettablePowerParameters.get(state).get(key);
934     }
935 
936     /**
937      * Dump the internal state of the class.
938      */
dump(FileDescriptor fd, PrintWriter pw, String[] args)939     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
940         pw.println("WifiAwareNativeApi:");
941         pw.println("  mSettableParameters: " + mSettableParameters);
942         pw.println("  mExternalSetParams" + mExternalSetParams);
943         mHal.dump(fd, pw, args);
944     }
945 }
946