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