com_android_server_wifi_nan_WifiNanNative.cpp revision e36f5903f5d236a29dc94c8bdb215807ae75f5a1
1/*
2 * Copyright 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#define LOG_TAG "wifinan"
18
19#include "jni.h"
20#include "JniConstants.h"
21#include <ScopedUtfChars.h>
22#include <ScopedBytes.h>
23#include <utils/misc.h>
24#include <utils/Log.h>
25#include <utils/String16.h>
26#include <ctype.h>
27#include <stdlib.h>
28#include <sys/socket.h>
29#include <linux/if.h>
30#include "wifi.h"
31#include "wifi_hal.h"
32#include "jni_helper.h"
33
34namespace android {
35
36static jint DBG = true;
37
38static jclass mCls;                             /* saved WifiNanNative object */
39static JavaVM *mVM = NULL;                      /* saved JVM pointer */
40
41wifi_handle getWifiHandle(JNIHelper &helper, jclass cls);
42wifi_interface_handle getIfaceHandle(JNIHelper &helper, jclass cls, jint index);
43
44extern wifi_hal_fn hal_fn;
45
46// Start NAN functions
47
48static void OnNanNotifyResponse(transaction_id id, NanResponseMsg* msg) {
49  ALOGD(
50      "OnNanNotifyResponse: transaction_id=%d, status=%d, value=%d, response_type=%d",
51      id, msg->status, msg->value, msg->response_type);
52
53  JNIHelper helper(mVM);
54  switch (msg->response_type) {
55    case NAN_RESPONSE_PUBLISH:
56      helper.reportEvent(mCls, "onNanNotifyResponsePublishSubscribe",
57                         "(SIIII)V", (short) id, (int) msg->response_type,
58                         (int) msg->status, (int) msg->value,
59                         msg->body.publish_response.publish_id);
60      break;
61    case NAN_RESPONSE_SUBSCRIBE:
62      helper.reportEvent(mCls, "onNanNotifyResponsePublishSubscribe",
63                         "(SIIII)V", (short) id, (int) msg->response_type,
64                         (int) msg->status, (int) msg->value,
65                         msg->body.subscribe_response.subscribe_id);
66      break;
67    case NAN_GET_CAPABILITIES: {
68      JNIObject<jobject> data = helper.createObject(
69          "com/android/server/wifi/nan/WifiNanNative$Capabilities");
70      if (data == NULL) {
71        ALOGE(
72            "Error in allocating WifiNanNative.Capabilities OnNanNotifyResponse");
73        return;
74      }
75
76      helper.setIntField(
77          data, "maxConcurrentNanClusters",
78          (int) msg->body.nan_capabilities.max_concurrent_nan_clusters);
79      helper.setIntField(data, "maxPublishes",
80                         (int) msg->body.nan_capabilities.max_publishes);
81      helper.setIntField(data, "maxSubscribes",
82                         (int) msg->body.nan_capabilities.max_subscribes);
83      helper.setIntField(data, "maxServiceNameLen",
84                         (int) msg->body.nan_capabilities.max_service_name_len);
85      helper.setIntField(data, "maxMatchFilterLen",
86                         (int) msg->body.nan_capabilities.max_match_filter_len);
87      helper.setIntField(
88          data, "maxTotalMatchFilterLen",
89          (int) msg->body.nan_capabilities.max_total_match_filter_len);
90      helper.setIntField(
91          data, "maxServiceSpecificInfoLen",
92          (int) msg->body.nan_capabilities.max_service_specific_info_len);
93      helper.setIntField(data, "maxVsaDataLen",
94                         (int) msg->body.nan_capabilities.max_vsa_data_len);
95      helper.setIntField(data, "maxMeshDataLen",
96                         (int) msg->body.nan_capabilities.max_mesh_data_len);
97      helper.setIntField(data, "maxNdiInterfaces",
98                         (int) msg->body.nan_capabilities.max_ndi_interfaces);
99      helper.setIntField(data, "maxNdpSessions",
100                         (int) msg->body.nan_capabilities.max_ndp_sessions);
101      helper.setIntField(data, "maxAppInfoLen",
102                         (int) msg->body.nan_capabilities.max_app_info_len);
103
104      helper.reportEvent(
105          mCls, "onNanNotifyResponseCapabilities",
106          "(SIILcom/android/server/wifi/nan/WifiNanNative$Capabilities;)V",
107          (short) id, (int) msg->status, (int) msg->value, data.get());
108      break;
109    }
110    default:
111      helper.reportEvent(mCls, "onNanNotifyResponse", "(SIII)V", (short) id,
112                         (int) msg->response_type, (int) msg->status,
113                         (int) msg->value);
114      break;
115  }
116}
117
118static void OnNanEventPublishTerminated(NanPublishTerminatedInd* event) {
119    ALOGD("OnNanEventPublishTerminated");
120
121    JNIHelper helper(mVM);
122    helper.reportEvent(mCls, "onPublishTerminated", "(II)V",
123                       event->publish_id, event->reason);
124}
125
126static void OnNanEventMatch(NanMatchInd* event) {
127    ALOGD("OnNanEventMatch");
128
129    JNIHelper helper(mVM);
130
131    JNIObject<jbyteArray> macBytes = helper.newByteArray(6);
132    helper.setByteArrayRegion(macBytes, 0, 6, (jbyte *) event->addr);
133
134    JNIObject<jbyteArray> ssiBytes = helper.newByteArray(event->service_specific_info_len);
135    helper.setByteArrayRegion(ssiBytes, 0, event->service_specific_info_len,
136                              (jbyte *) event->service_specific_info);
137
138    JNIObject<jbyteArray> mfBytes = helper.newByteArray(event->sdf_match_filter_len);
139    helper.setByteArrayRegion(mfBytes, 0, event->sdf_match_filter_len,
140                              (jbyte *) event->sdf_match_filter);
141
142    helper.reportEvent(mCls, "onMatchEvent", "(II[B[BI[BI)V",
143                       (int) event->publish_subscribe_id,
144                       (int) event->requestor_instance_id,
145                       macBytes.get(),
146                       ssiBytes.get(), event->service_specific_info_len,
147                       mfBytes.get(), event->sdf_match_filter_len);
148}
149
150static void OnNanEventMatchExpired(NanMatchExpiredInd* event) {
151    ALOGD("OnNanEventMatchExpired");
152}
153
154static void OnNanEventSubscribeTerminated(NanSubscribeTerminatedInd* event) {
155    ALOGD("OnNanEventSubscribeTerminated");
156
157    JNIHelper helper(mVM);
158    helper.reportEvent(mCls, "onSubscribeTerminated", "(II)V",
159                       event->subscribe_id, event->reason);
160}
161
162static void OnNanEventFollowup(NanFollowupInd* event) {
163    ALOGD("OnNanEventFollowup");
164
165    JNIHelper helper(mVM);
166
167    JNIObject<jbyteArray> macBytes = helper.newByteArray(6);
168    helper.setByteArrayRegion(macBytes, 0, 6, (jbyte *) event->addr);
169
170    JNIObject<jbyteArray> msgBytes = helper.newByteArray(event->service_specific_info_len);
171    helper.setByteArrayRegion(msgBytes, 0, event->service_specific_info_len, (jbyte *) event->service_specific_info);
172
173    helper.reportEvent(mCls, "onFollowupEvent", "(II[B[BI)V",
174                       (int) event->publish_subscribe_id,
175                       (int) event->requestor_instance_id,
176                       macBytes.get(),
177                       msgBytes.get(),
178                       (int) event->service_specific_info_len);
179}
180
181static void OnNanEventDiscEngEvent(NanDiscEngEventInd* event) {
182    ALOGD("OnNanEventDiscEngEvent called: event_type=%d", event->event_type);
183
184    JNIHelper helper(mVM);
185
186    JNIObject<jbyteArray> macBytes = helper.newByteArray(6);
187    if (event->event_type == NAN_EVENT_ID_DISC_MAC_ADDR) {
188        helper.setByteArrayRegion(macBytes, 0, 6, (jbyte *) event->data.mac_addr.addr);
189    } else {
190        helper.setByteArrayRegion(macBytes, 0, 6, (jbyte *) event->data.cluster.addr);
191    }
192
193    helper.reportEvent(mCls, "onDiscoveryEngineEvent", "(I[B)V",
194                       (int) event->event_type, macBytes.get());
195}
196
197static void OnNanEventDisabled(NanDisabledInd* event) {
198    ALOGD("OnNanEventDisabled called: reason=%d", event->reason);
199
200    JNIHelper helper(mVM);
201
202    helper.reportEvent(mCls, "onDisabledEvent", "(I)V", (int) event->reason);
203}
204
205static void OnNanEventTca(NanTCAInd* event) {
206    ALOGD("OnNanEventTca");
207}
208
209static void OnNanEventBeaconSdfPayload(NanBeaconSdfPayloadInd* event) {
210    ALOGD("OnNanEventSdfPayload");
211}
212
213static jint android_net_wifi_nan_register_handler(JNIEnv *env, jclass cls,
214                                                  jclass wifi_native_cls,
215                                                  jint iface) {
216    JNIHelper helper(env);
217    wifi_interface_handle handle = getIfaceHandle(helper, wifi_native_cls, iface);
218
219    ALOGD("android_net_wifi_nan_register_handler handle=%p", handle);
220
221    NanCallbackHandler handlers;
222    handlers.NotifyResponse = OnNanNotifyResponse;
223    handlers.EventPublishTerminated = OnNanEventPublishTerminated;
224    handlers.EventMatch = OnNanEventMatch;
225    handlers.EventMatchExpired = OnNanEventMatchExpired;
226    handlers.EventSubscribeTerminated = OnNanEventSubscribeTerminated;
227    handlers.EventFollowup = OnNanEventFollowup;
228    handlers.EventDiscEngEvent = OnNanEventDiscEngEvent;
229    handlers.EventDisabled = OnNanEventDisabled;
230    handlers.EventTca = OnNanEventTca;
231    handlers.EventBeaconSdfPayload = OnNanEventBeaconSdfPayload;
232
233    if (mVM == NULL) {
234        env->GetJavaVM(&mVM);
235        mCls = (jclass) env->NewGlobalRef(cls);
236    }
237
238    return hal_fn.wifi_nan_register_handler(handle, handlers);
239}
240
241static jint android_net_wifi_nan_enable_request(JNIEnv *env, jclass cls,
242                                                jshort transaction_id,
243                                                jclass wifi_native_cls,
244                                                jint iface,
245                                                jobject config_request) {
246    JNIHelper helper(env);
247    wifi_interface_handle handle = getIfaceHandle(helper, wifi_native_cls, iface);
248
249    ALOGD("android_net_wifi_nan_enable_request handle=%p, id=%d",
250          handle, transaction_id);
251
252    NanEnableRequest msg;
253    memset(&msg, 0, sizeof(NanEnableRequest));
254
255    /* configurable settings */
256    msg.config_support_5g = 1;
257    msg.support_5g_val = helper.getBoolField(config_request, "mSupport5gBand");
258    msg.master_pref = helper.getIntField(config_request, "mMasterPreference");
259    msg.cluster_low = helper.getIntField(config_request, "mClusterLow");
260    msg.cluster_high = helper.getIntField(config_request, "mClusterHigh");
261
262    return hal_fn.wifi_nan_enable_request(transaction_id, handle, &msg);
263}
264
265static jint android_net_wifi_nan_get_capabilities(JNIEnv *env, jclass cls,
266                                                  jshort transaction_id,
267                                                  jclass wifi_native_cls,
268                                                  jint iface) {
269  JNIHelper helper(env);
270  wifi_interface_handle handle = getIfaceHandle(helper, wifi_native_cls, iface);
271
272  ALOGD("android_net_wifi_nan_get_capabilities handle=%p, id=%d", handle,
273        transaction_id);
274
275  return hal_fn.wifi_nan_get_capabilities(transaction_id, handle);
276}
277
278static jint android_net_wifi_nan_disable_request(JNIEnv *env, jclass cls,
279                                                 jshort transaction_id,
280                                                 jclass wifi_native_cls,
281                                                 jint iface) {
282    JNIHelper helper(env);
283    wifi_interface_handle handle = getIfaceHandle(helper, wifi_native_cls, iface);
284
285    ALOGD("android_net_wifi_nan_disable_request handle=%p, id=%d",
286          handle, transaction_id);
287
288    return hal_fn.wifi_nan_disable_request(transaction_id, handle);
289}
290
291static jint android_net_wifi_nan_publish(JNIEnv *env, jclass cls,
292                                         jshort transaction_id,
293                                         jint publish_id,
294                                         jclass wifi_native_cls,
295                                         jint iface,
296                                         jobject publish_data,
297                                         jobject publish_settings) {
298    JNIHelper helper(env);
299    wifi_interface_handle handle = getIfaceHandle(helper, wifi_native_cls, iface);
300
301    ALOGD("android_net_wifi_nan_publish handle=%p, id=%d", handle, transaction_id);
302
303    NanPublishRequest msg;
304    memset(&msg, 0, sizeof(NanPublishRequest));
305
306    /* hard-coded settings - TBD: move to configurable */
307    msg.period = 500;
308    msg.publish_match_indicator = NAN_MATCH_ALG_MATCH_ONCE;
309    msg.rssi_threshold_flag = 0;
310    msg.connmap = 0;
311
312    /* configurable settings */
313    msg.publish_id = publish_id;
314
315    JNIObject<jstring> objStr1 = helper.getStringField(publish_data, "mServiceName");
316    if (objStr1 == NULL) {
317        ALOGE("Error accessing mServiceName field");
318        return 0;
319    }
320    ScopedUtfChars chars1(env, objStr1);
321    const char *serviceName = chars1.c_str();
322    if (serviceName == NULL) {
323        ALOGE("Error getting mServiceName");
324        return 0;
325    }
326    msg.service_name_len = strlen(serviceName);
327    strcpy((char*)msg.service_name, serviceName);
328
329    msg.service_specific_info_len = helper.getIntField(publish_data, "mServiceSpecificInfoLength");
330    if (msg.service_specific_info_len != 0) {
331        helper.getByteArrayField(publish_data, "mServiceSpecificInfo",
332                             msg.service_specific_info, msg.service_specific_info_len);
333    }
334
335
336    msg.tx_match_filter_len = helper.getIntField(publish_data, "mTxFilterLength");
337    if (msg.tx_match_filter_len != 0) {
338        helper.getByteArrayField(publish_data, "mTxFilter",
339                             msg.tx_match_filter, msg.tx_match_filter_len);
340    }
341
342    msg.rx_match_filter_len = helper.getIntField(publish_data, "mRxFilterLength");
343    if (msg.rx_match_filter_len != 0) {
344        helper.getByteArrayField(publish_data, "mRxFilter",
345                             msg.rx_match_filter, msg.rx_match_filter_len);
346    }
347
348    msg.publish_type = (NanPublishType)helper.getIntField(publish_settings, "mPublishType");
349    msg.publish_count = helper.getIntField(publish_settings, "mPublishCount");
350    msg.ttl = helper.getIntField(publish_settings, "mTtlSec");
351
352    msg.tx_type = NAN_TX_TYPE_BROADCAST;
353    if (msg.publish_type != NAN_PUBLISH_TYPE_UNSOLICITED)
354      msg.tx_type = NAN_TX_TYPE_UNICAST;
355
356    return hal_fn.wifi_nan_publish_request(transaction_id, handle, &msg);
357}
358
359static jint android_net_wifi_nan_subscribe(JNIEnv *env, jclass cls,
360                                           jshort transaction_id,
361                                           jint subscribe_id,
362                                           jclass wifi_native_cls,
363                                           jint iface,
364                                           jobject subscribe_data,
365                                           jobject subscribe_settings) {
366    JNIHelper helper(env);
367    wifi_interface_handle handle = getIfaceHandle(helper, wifi_native_cls, iface);
368
369    ALOGD("android_net_wifi_nan_subscribe handle=%p, id=%d", handle, transaction_id);
370
371    NanSubscribeRequest msg;
372    memset(&msg, 0, sizeof(NanSubscribeRequest));
373
374    /* hard-coded settings - TBD: move to configurable */
375    msg.period = 500;
376    msg.serviceResponseFilter = NAN_SRF_ATTR_PARTIAL_MAC_ADDR;
377    msg.serviceResponseInclude = NAN_SRF_INCLUDE_RESPOND;
378    msg.useServiceResponseFilter = NAN_DO_NOT_USE_SRF;
379    msg.ssiRequiredForMatchIndication = NAN_SSI_NOT_REQUIRED_IN_MATCH_IND;
380    msg.subscribe_match_indicator = NAN_MATCH_ALG_MATCH_ONCE;
381    msg.rssi_threshold_flag = 0;
382    msg.connmap = 0;
383    msg.num_intf_addr_present = 0;
384
385    /* configurable settings */
386    msg.subscribe_id = subscribe_id;
387
388    JNIObject<jstring> objStr1 = helper.getStringField(subscribe_data, "mServiceName");
389    if (objStr1 == NULL) {
390        ALOGE("Error accessing mServiceName field");
391        return 0;
392    }
393    ScopedUtfChars chars1(env, objStr1);
394    const char *serviceName = chars1.c_str();
395    if (serviceName == NULL) {
396        ALOGE("Error getting mServiceName");
397        return 0;
398    }
399    msg.service_name_len = strlen(serviceName);
400    strcpy((char*)msg.service_name, serviceName);
401
402    msg.service_specific_info_len = helper.getIntField(subscribe_data, "mServiceSpecificInfoLength");
403    if (msg.service_specific_info_len != 0) {
404        helper.getByteArrayField(subscribe_data, "mServiceSpecificInfo",
405                             msg.service_specific_info, msg.service_specific_info_len);
406    }
407
408    msg.tx_match_filter_len = helper.getIntField(subscribe_data, "mTxFilterLength");
409    if (msg.tx_match_filter_len != 0) {
410        helper.getByteArrayField(subscribe_data, "mTxFilter",
411                             msg.tx_match_filter, msg.tx_match_filter_len);
412    }
413
414    msg.rx_match_filter_len = helper.getIntField(subscribe_data, "mRxFilterLength");
415    if (msg.rx_match_filter_len != 0) {
416        helper.getByteArrayField(subscribe_data, "mRxFilter",
417                             msg.rx_match_filter, msg.rx_match_filter_len);
418    }
419
420    msg.subscribe_type = (NanSubscribeType)helper.getIntField(subscribe_settings, "mSubscribeType");
421    msg.subscribe_count = helper.getIntField(subscribe_settings, "mSubscribeCount");
422    msg.ttl = helper.getIntField(subscribe_settings, "mTtlSec");
423
424    return hal_fn.wifi_nan_subscribe_request(transaction_id, handle, &msg);
425}
426
427static jint android_net_wifi_nan_send_message(JNIEnv *env, jclass cls,
428                                              jshort transaction_id,
429                                              jclass wifi_native_cls,
430                                              jint iface,
431                                              jint pub_sub_id,
432                                              jint req_instance_id,
433                                              jbyteArray dest,
434                                              jbyteArray message,
435                                              jint message_length) {
436    JNIHelper helper(env);
437    wifi_interface_handle handle = getIfaceHandle(helper, wifi_native_cls, iface);
438
439    ALOGD("android_net_wifi_nan_send_message handle=%p, id=%d", handle, transaction_id);
440
441    NanTransmitFollowupRequest msg;
442    memset(&msg, 0, sizeof(NanTransmitFollowupRequest));
443
444    /* hard-coded settings - TBD: move to configurable */
445    msg.publish_subscribe_id = pub_sub_id;
446    msg.requestor_instance_id = req_instance_id;
447    msg.priority = NAN_TX_PRIORITY_NORMAL;
448    msg.dw_or_faw = NAN_TRANSMIT_IN_DW;
449
450    /* configurable settings */
451    msg.service_specific_info_len = message_length;
452
453    ScopedBytesRO messageBytes(env, message);
454    memcpy(msg.service_specific_info, (byte*) messageBytes.get(), message_length);
455
456    ScopedBytesRO destBytes(env, dest);
457    memcpy(msg.addr, (byte*) destBytes.get(), 6);
458
459    return hal_fn.wifi_nan_transmit_followup_request(transaction_id, handle, &msg);
460}
461
462static jint android_net_wifi_nan_stop_publish(JNIEnv *env, jclass cls,
463                                              jshort transaction_id,
464                                              jclass wifi_native_cls,
465                                              jint iface,
466                                              jint pub_sub_id) {
467    JNIHelper helper(env);
468    wifi_interface_handle handle = getIfaceHandle(helper, wifi_native_cls, iface);
469
470    ALOGD("android_net_wifi_nan_stop_publish handle=%p, id=%d", handle, transaction_id);
471
472    NanPublishCancelRequest msg;
473    memset(&msg, 0, sizeof(NanPublishCancelRequest));
474
475    msg.publish_id = pub_sub_id;
476
477    return hal_fn.wifi_nan_publish_cancel_request(transaction_id, handle, &msg);
478}
479
480static jint android_net_wifi_nan_stop_subscribe(JNIEnv *env, jclass cls,
481                                              jshort transaction_id,
482                                              jclass wifi_native_cls,
483                                              jint iface,
484                                              jint pub_sub_id) {
485    JNIHelper helper(env);
486    wifi_interface_handle handle = getIfaceHandle(helper, wifi_native_cls, iface);
487
488    ALOGD("android_net_wifi_nan_stop_subscribe handle=%p, id=%d", handle, transaction_id);
489
490    NanSubscribeCancelRequest msg;
491    memset(&msg, 0, sizeof(NanSubscribeCancelRequest));
492
493    msg.subscribe_id = pub_sub_id;
494
495    return hal_fn.wifi_nan_subscribe_cancel_request(transaction_id, handle, &msg);
496}
497
498// ----------------------------------------------------------------------------
499
500/*
501 * JNI registration.
502 */
503
504static JNINativeMethod gWifiNanMethods[] = {
505    /* name, signature, funcPtr */
506
507    {"initNanHandlersNative", "(Ljava/lang/Object;I)I", (void*)android_net_wifi_nan_register_handler },
508    {"getCapabilitiesNative", "(SLjava/lang/Object;I)I", (void*)android_net_wifi_nan_get_capabilities },
509    {"enableAndConfigureNative", "(SLjava/lang/Object;ILandroid/net/wifi/nan/ConfigRequest;)I", (void*)android_net_wifi_nan_enable_request },
510    {"disableNative", "(SLjava/lang/Object;I)I", (void*)android_net_wifi_nan_disable_request },
511    {"publishNative", "(SILjava/lang/Object;ILandroid/net/wifi/nan/PublishData;Landroid/net/wifi/nan/PublishSettings;)I", (void*)android_net_wifi_nan_publish },
512    {"subscribeNative", "(SILjava/lang/Object;ILandroid/net/wifi/nan/SubscribeData;Landroid/net/wifi/nan/SubscribeSettings;)I", (void*)android_net_wifi_nan_subscribe },
513    {"sendMessageNative", "(SLjava/lang/Object;III[B[BI)I", (void*)android_net_wifi_nan_send_message },
514    {"stopPublishNative", "(SLjava/lang/Object;II)I", (void*)android_net_wifi_nan_stop_publish },
515    {"stopSubscribeNative", "(SLjava/lang/Object;II)I", (void*)android_net_wifi_nan_stop_subscribe },
516};
517
518/* User to register native functions */
519extern "C"
520jint Java_com_android_server_wifi_nan_WifiNanNative_registerNanNatives(JNIEnv* env, jclass clazz) {
521    return jniRegisterNativeMethods(env,
522            "com/android/server/wifi/nan/WifiNanNative", gWifiNanMethods, NELEM(gWifiNanMethods));
523}
524
525}; // namespace android
526