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