2 * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
23 #include <wifi-aware.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
29 #include "vine-constants.h"
30 #include "vine-disc-plugin.h"
32 #include "vine-utils.h"
33 #include "nan-plugin.h"
36 void *disc_handle; // vine_disc handle
37 wifi_aware_publish_h publish_config;
38 wifi_aware_subscribe_h subscribe_config;
39 wifi_aware_session_h session;
40 std::map<string, wifi_aware_peer_h> peers; // <mac, peer>
41 std::map<wifi_aware_peer_h, wifi_aware_data_path_h> ndps; // <peer, ndp>
43 char published_service_name[VINE_MAX_NAN_SERVICE_NAME_LEN + 1];
44 char service_type[VINE_MAX_NAN_SERVICE_TYPE_LEN + 1];
48 static vine_disc_plugin_callbacks event_callbacks;
50 static vine_disc_error __convert_nan_error_to_vine_disc_error(int error)
52 return VINE_DISC_ERROR_NONE;
55 static bool __is_data_path_request_message(const unsigned char *message, size_t len)
57 RET_VAL_IF(len != strlen(VINE_FOLLOWUP_MESSAGE), false, "Wrong message");
58 return memcmp(message, VINE_FOLLOWUP_MESSAGE, strlen(VINE_FOLLOWUP_MESSAGE)) == 0;
61 static void __add_ndp(vine_nan_s *nan_handle,
62 wifi_aware_data_path_h ndp, wifi_aware_peer_h peer)
64 VINE_LOGD("Add NDP[%p]. peer[%p]", ndp, peer);
65 auto v = nan_handle->ndps.find(peer);
66 if (v == nan_handle->ndps.end()) {
67 // TODO: Can the same peer request NAN data path?
69 nan_handle->ndps[peer] = ndp;
72 static void __terminated_cb(wifi_aware_data_path_h ndp,
73 wifi_aware_termination_reason_e reason, void *user_data)
75 VINE_LOGD("NDP is terminated [%p]. reason[%d]", ndp, (int)reason);
77 vine_nan_s *nan_handle = (vine_nan_s *)user_data;
78 if (event_callbacks.ip_resolved_cb)
79 event_callbacks.ip_resolved_cb(nan_handle, false,
80 nullptr, VINE_DISC_ADDR_FAMILY_IPV6, nan_handle->disc_handle);
83 static void __open_cb(wifi_aware_data_path_h ndp,
84 wifi_aware_error_e error, void *user_data)
86 RET_IF(!event_callbacks.ip_resolved_cb, "No callbacks");
89 if (wifi_aware_data_path_get_peer_ipv6_address(ndp, &ipv6) != WIFI_AWARE_ERROR_NONE) {
90 VINE_LOGE("wifi_aware_data_path_get_peer_ipv6_address() fails");
94 vine_nan_s *nan_handle = (vine_nan_s *)user_data;
96 event_callbacks.ip_resolved_cb(nan_handle, true,
97 ipv6, VINE_DISC_ADDR_FAMILY_IPV6, nan_handle->disc_handle);
101 static void __open_nan_data_path(wifi_aware_session_h session,
102 wifi_aware_peer_h peer, vine_nan_s *nan_handle)
104 VINE_LOGD("Open NAN data path. session[%p]", session);
109 for (const auto &kv : nan_handle->peers) {
110 if (kv.second == peer) {
118 VINE_LOGE("Invalid peer");
123 wifi_aware_data_path_h ndp;
124 if (wifi_aware_data_path_create(session, peer, &ndp) != WIFI_AWARE_ERROR_NONE) {
125 VINE_LOGE("wifi_aware_data_path_create() fails");
129 if (wifi_aware_data_path_set_terminated_cb(ndp, __terminated_cb, nan_handle)
130 != WIFI_AWARE_ERROR_NONE) {
131 VINE_LOGE("wifi_aware_data_path_set_terminated_cb() fails");
135 if (wifi_aware_data_path_open(ndp, __open_cb, nan_handle) != WIFI_AWARE_ERROR_NONE) {
136 VINE_LOGE("wifi_aware_data_path_open() fails");
140 // TODO: Need to maintain ndp list?
141 __add_ndp(nan_handle, ndp, peer);
144 static void __received_cb(wifi_aware_session_h session, wifi_aware_peer_h peer,
145 const unsigned char *message, size_t len, void *user_data)
147 RET_IF(!user_data, "user_data is NULL");
148 VINE_LOGD("NAN message is received. session[%p], peer[%p], nan_handle[%p]",
149 session, peer, user_data);
151 if (!__is_data_path_request_message(message, len)) {
152 VINE_LOGD("This message will be not used");
156 __open_nan_data_path(session, peer, (vine_nan_s *)user_data);
159 static void __message_result_cb(wifi_aware_session_h session,
160 wifi_aware_error_e error, void *user_data)
162 if (error == WIFI_AWARE_ERROR_NONE) {
163 VINE_LOGD("Message is successfully sent");
168 // How can inform the failure to app?
169 // Use ip_resolved_cb with nullptr IP address?
170 // Then, in terminated_cb, I think ip_resolved_cb is called with ip address (add is false)
173 static int __send_nan_dp_request(wifi_aware_session_h session,
174 wifi_aware_peer_h peer, vine_nan_s *nan_handle)
176 VINE_LOGD("Send NAN Datapath request message");
177 return wifi_aware_session_send_message(session, peer,
178 (unsigned char *)VINE_FOLLOWUP_MESSAGE, strlen(VINE_FOLLOWUP_MESSAGE),
179 __message_result_cb, nan_handle);
182 vine_disc_error nan_resolve_ip(void *plugin_handle,
183 const char *service_type, const char *service_name,
184 const char *host_name, const char *mac, const char *iface_name, int family)
186 RET_VAL_IF(!plugin_handle, VINE_DISC_ERROR_INVALID_PARAMETER, "plugin_handle is NULL");
187 RET_VAL_IF(!service_type, VINE_DISC_ERROR_INVALID_PARAMETER, "service_type is NULL");
188 RET_VAL_IF(!service_name, VINE_DISC_ERROR_INVALID_PARAMETER, "service_name is NULL");
189 RET_VAL_IF(!mac, VINE_DISC_ERROR_INVALID_PARAMETER, "mac is NULL");
190 // Ignore host_name and iface_name
191 RET_VAL_IF(family == VINE_DISC_ADDR_FAMILY_IPV4, VINE_DISC_ERROR_NOT_SUPPORTED,
192 "Only IPv6 is allowed for NAN");
194 vine_nan_s *nan_handle = (vine_nan_s *)plugin_handle;
195 RET_VAL_IF(nan_handle->peers.find(mac) == nan_handle->peers.end(),
196 VINE_DISC_ERROR_INVALID_PARAMETER, "Invalid mac[%s]", mac);
198 VINE_LOGD("Start to resolve IP. plugin_handle[%p]\n", plugin_handle);
199 VINE_LOGD("type[%s] name[%s] mac[%s]", service_type, service_name, mac);
201 int ret = wifi_aware_session_set_message_received_cb(nan_handle->session,
202 __received_cb, nan_handle);
203 if (ret != WIFI_AWARE_ERROR_NONE) {
204 VINE_LOGE("wifi_aware_session_set_message_received_cb() fails");
205 return __convert_nan_error_to_vine_disc_error(ret);
208 ret = __send_nan_dp_request(nan_handle->session, nan_handle->peers[mac], nan_handle);
209 if (ret != WIFI_AWARE_ERROR_NONE)
210 VINE_LOGE("__send_nan_dp_request() fails");
212 return __convert_nan_error_to_vine_disc_error(ret);
215 vine_disc_error nan_cancel_resolve_ip(void *plugin_handle)
217 RET_VAL_IF(!plugin_handle, VINE_DISC_ERROR_INVALID_PARAMETER, "plugin_handle is NULL");
218 VINE_LOGD("Cancel resolving IP. plugin_handle[%p]\n", plugin_handle);
220 return VINE_DISC_ERROR_NONE;
224 vine_disc_error nan_init(void **plugin_handle, void *disc_handle)
226 int ret = wifi_aware_initialize();
227 if (ret != WIFI_AWARE_ERROR_NONE && ret != WIFI_AWARE_ERROR_ALREADY_INITIALIZED) {
228 VINE_LOGE("wifi_aware_initialize() fails");
229 return __convert_nan_error_to_vine_disc_error(ret);
232 vine_nan_s *handle = new vine_nan_s;
233 VINE_LOGD("Create plugin_handle[%p]", handle);
235 handle->disc_handle = disc_handle;
236 handle->publish_config = nullptr;
237 handle->subscribe_config = nullptr;
238 handle->session = nullptr;
242 *plugin_handle = handle;
243 // NAN will be enabled when publish() or subscribe()
244 // because enable function works asynchronously.
246 return VINE_DISC_ERROR_NONE;
249 void nan_deinit(void *plugin_handle)
251 RET_IF(plugin_handle == NULL, "Plugin handle is null");
252 vine_nan_s *nan_handle = (vine_nan_s *)plugin_handle;
256 // However, we have to check if NAN is used for data path or not
257 // , and if NAN data path is broken or not when NAN is disabled.
260 wifi_aware_deinitialize();
263 static void __published_cb(wifi_aware_session_h session,
264 wifi_aware_error_e error, void *user_data)
266 VINE_LOGD("Service is published");
267 vine_nan_s *nan_handle = (vine_nan_s *)user_data;
269 if (event_callbacks.published_cb)
270 event_callbacks.published_cb(nan_handle,
271 nan_handle->published_service_name, __convert_nan_error_to_vine_disc_error(error),
272 nan_handle->disc_handle);
275 static void __publish(vine_nan_s *nan_handle)
277 wifi_aware_session_h session;
278 int ret = wifi_aware_session_create(WIFI_AWARE_SESSION_PUBLISH, &session);
279 RET_IF(ret != WIFI_AWARE_ERROR_NONE, "wifi_aware_session_create() fails");
281 ret = wifi_aware_session_set_message_received_cb(session, __received_cb, nan_handle);
282 if (ret != WIFI_AWARE_ERROR_NONE) {
283 VINE_LOGE("wifi_aware_session_publish() fails");
287 VINE_LOGD("Publish a NAN service");
289 ret = wifi_aware_session_publish(session, nan_handle->publish_config,
290 __published_cb, nan_handle);
291 if (ret != WIFI_AWARE_ERROR_NONE) {
292 VINE_LOGE("wifi_aware_session_publish() fails");
296 nan_handle->session = session;
299 wifi_aware_session_destroy(session);
302 static bool __get_attributes(const unsigned char *info, size_t len, map<string, string> &attr)
304 VINE_LOGD("Get Attributes");
306 const unsigned char *ptr = &info[VINE_MAX_NAN_SERVICE_NAME_LEN];
307 const unsigned char *max = info + len;
308 char key_buf[MAX_SPECIFIC_INFO_LEN + 1];
309 char value_buf[MAX_SPECIFIC_INFO_LEN + 1];
312 const unsigned char *const end = ptr + 1 + ptr[0];
314 VINE_LOGE("Invalid attribute");
317 char *buf = &key_buf[0];
318 while (++ptr < end) {
328 VINE_LOGD("Key[%s] Value[%s]", key_buf, value_buf);
330 string value(value_buf);
336 static void __add_peer(vine_nan_s *nan_handle, wifi_aware_peer_h peer, const char *mac)
338 VINE_LOGD("Add peer[%p]. mac[%s]", peer, mac);
339 nan_handle->peers[mac] = peer;
342 static void __discovered_cb(wifi_aware_session_h session,
343 wifi_aware_peer_h peer, const unsigned char *service_specific_info, size_t len,
344 int distance, void *user_data)
346 VINE_LOGD("Service Discovered. session[%p] peer[%p]", session, peer);
347 RET_IF(event_callbacks.discovered_cb == NULL, "discovered_cb is NULL");
349 if (len > MAX_SPECIFIC_INFO_LEN || len < VINE_MAX_NAN_SERVICE_NAME_LEN) {
350 VINE_LOGE("Invalid info len[%d]", len);
354 char service_name[VINE_MAX_SERVICE_NAME_LEN + 1];
355 memcpy(service_name, service_specific_info, VINE_MAX_NAN_SERVICE_NAME_LEN);
356 service_name[VINE_MAX_NAN_SERVICE_NAME_LEN] = 0;
358 map<string, string> attributes;
359 if (__get_attributes(service_specific_info, len, attributes) == false)
363 int ret = wifi_aware_peer_get_mac(peer, (unsigned char **)&mac);
364 RET_IF(ret != WIFI_AWARE_ERROR_NONE, "wifi_aware_peer_get_mac() fails");
366 vine_nan_s *nan_handle = (vine_nan_s *)user_data;
367 __add_peer(nan_handle, peer, mac);
369 event_callbacks.discovered_cb(nan_handle, true,
370 nan_handle->service_type, service_name, nullptr,
371 mac, -1, attributes, nullptr, 0,
372 nan_handle->disc_handle);
377 * When NAN subscription is failed, it is informed with discovered_cb.
378 * If service_type and service_name are nullptr, it is considered as an error.
379 * vine_session_discovered_cb will be called with NULL vine_service_h.
381 static void __subscribe_failed(vine_nan_s *nan_handle)
383 if (event_callbacks.discovered_cb) {
384 std::map<string, string> empty_map;
385 event_callbacks.discovered_cb(nan_handle, false,
386 nullptr, nullptr, nullptr, nullptr, -1, empty_map, nullptr, 0,
387 nan_handle->disc_handle);
391 static void __subscribed_cb(wifi_aware_session_h session,
392 wifi_aware_error_e error, void *user_data)
394 if (error == WIFI_AWARE_ERROR_NONE) {
395 VINE_LOGD("No error");
399 VINE_LOGE("Fails to subscribe. error: %d", __convert_nan_error_to_vine_disc_error(error));
400 __subscribe_failed((vine_nan_s *)user_data);
403 static void __subscribe(vine_nan_s *nan_handle)
405 wifi_aware_session_h session;
406 int ret = wifi_aware_session_create(WIFI_AWARE_SESSION_SUBSCRIBE, &session);
407 RET_IF(ret != WIFI_AWARE_ERROR_NONE, "wifi_aware_session_create() fails");
409 VINE_LOGD("Subscribe a NAN service");
411 ret = wifi_aware_session_set_service_discovered_cb(session, __discovered_cb, nan_handle);
412 if (ret != WIFI_AWARE_ERROR_NONE) {
413 VINE_LOGE("wifi_aware_session_publish() fails");
417 ret = wifi_aware_session_subscribe(session,
418 nan_handle->subscribe_config, __subscribed_cb, nan_handle);
419 if (ret != WIFI_AWARE_ERROR_NONE) {
420 VINE_LOGE("wifi_aware_session_publish() fails");
424 nan_handle->session = session;
428 wifi_aware_session_destroy(session);
429 __subscribe_failed(nan_handle);
432 static void __start_session(vine_nan_s *nan_handle)
434 if (nan_handle->publish_config)
435 __publish(nan_handle);
436 else if (nan_handle->subscribe_config)
437 __subscribe(nan_handle);
439 VINE_LOGE("Invalid operation");
442 static void __stop_session(vine_nan_s *nan_handle)
444 if (nan_handle->session) {
445 VINE_LOGD("Stop NAN session");
446 wifi_aware_session_stop(nan_handle->session);
447 wifi_aware_session_destroy(nan_handle->session);
451 static void __enabled_cb(wifi_aware_error_e error, void *user_data)
453 RET_IF(!user_data, "nan_handle is NULL");
455 VINE_LOGD("NAN is enabled. nan_handle[%p]", user_data);
456 __start_session((vine_nan_s *)user_data);
459 static bool __check_attr_len(const map<string, string> &attributes)
461 int info_len = VINE_MAX_NAN_SERVICE_NAME_LEN;
462 for (const auto &kv : attributes) {
464 auto val = kv.second;
465 info_len += key.size() + val.size() + 1;
466 if (info_len > MAX_SPECIFIC_INFO_LEN)
472 static void __fill_specific_info(unsigned char *info, const char *service_name,
473 const map<string, string> &attributes)
475 int service_name_len = strlen(service_name);
476 memcpy(info, service_name, service_name_len);
477 info[service_name_len] = 0;
479 unsigned char *ptr = &info[VINE_MAX_NAN_SERVICE_NAME_LEN];
480 for (const auto &kv : attributes) {
482 auto val = kv.second;
483 int key_len = key.size();
484 int val_len = val.size();
485 *ptr = (unsigned char)(key_len + val_len + 1);
487 memcpy(ptr, key.c_str(), key_len);
490 memcpy(ptr, val.c_str(), val_len);
495 vine_disc_error nan_publish(void *plugin_handle, const char *service_type,
496 const char *service_name, int port, const map<string, string> &attributes,
497 const char *iface_name)
499 RET_VAL_IF(!plugin_handle, VINE_DISC_ERROR_INVALID_PARAMETER, "plugin_handle is NULL");
500 RET_VAL_IF(!service_type, VINE_DISC_ERROR_INVALID_PARAMETER, "service_type is NULL");
501 RET_VAL_IF(!service_name, VINE_DISC_ERROR_INVALID_PARAMETER, "service_name is NULL");
502 RET_VAL_IF(strlen(service_type) > NAN_MAX_SERVICE_NAME_LEN, VINE_DISC_ERROR_INVALID_PARAMETER,
503 "Too long service type");
504 RET_VAL_IF(strlen(service_name) > VINE_MAX_NAN_SERVICE_NAME_LEN, VINE_DISC_ERROR_INVALID_PARAMETER,
505 "Too long service name");
506 RET_VAL_IF(__check_attr_len(attributes) == false, VINE_DISC_ERROR_INVALID_PARAMETER,
507 "Too long attributes");
509 vine_nan_s *nan_handle = (vine_nan_s *)plugin_handle;
510 VINE_LOGD("Publish. plugin_handle[%p], service_type[%s], service_name[%s], port[%d]",
511 plugin_handle, service_type, service_name, port);
513 wifi_aware_publish_h config = nullptr;
514 int ret = wifi_aware_publish_create(&config);
515 RET_VAL_IF(ret != WIFI_AWARE_ERROR_NONE, __convert_nan_error_to_vine_disc_error(ret),
516 "wifi_aware_publish_create() fails");
518 unsigned char info[MAX_SPECIFIC_INFO_LEN + 1] = {0, };
520 ret = wifi_aware_publish_set_type(config, WIFI_AWARE_PUBLISH_TYPE_UNSOLICITED);
521 if (ret != WIFI_AWARE_ERROR_NONE) {
522 VINE_LOGE("wifi_aware_publish_set_type() fails");
526 ret = wifi_aware_publish_set_service_name(config, service_type);
527 if (ret != WIFI_AWARE_ERROR_NONE) {
528 VINE_LOGE("wifi_aware_publish_set_service_name() fails");
532 __fill_specific_info(info, service_name, attributes);
534 ret = wifi_aware_enable(__enabled_cb, nan_handle);
535 if (ret != WIFI_AWARE_ERROR_NONE) {
536 VINE_LOGE("wifi_aware_enable() fails");
540 nan_handle->publish_config = config;
541 nan_handle->port = port; // port will be set for NAN data path
542 strncpy(nan_handle->published_service_name, service_name, VINE_MAX_SERVICE_NAME_LEN);
544 return VINE_DISC_ERROR_NONE;
547 wifi_aware_publish_destroy(config);
548 return __convert_nan_error_to_vine_disc_error(ret);
551 vine_disc_error nan_stop_publish(void *plugin_handle)
553 RET_VAL_IF(!plugin_handle, VINE_DISC_ERROR_INVALID_PARAMETER, "plugin_handle is NULL");
555 VINE_LOGD("Stop publish. plugin_handle[%p]", plugin_handle);
556 vine_nan_s *nan_handle = (vine_nan_s *)plugin_handle;
557 __stop_session(nan_handle);
559 if (nan_handle->publish_config)
560 wifi_aware_publish_destroy(nan_handle->publish_config);
562 return VINE_DISC_ERROR_NONE;
565 vine_disc_error nan_subscribe(void *plugin_handle,
566 const char *service_type, const char *iface_name)
568 RET_VAL_IF(!plugin_handle, VINE_DISC_ERROR_INVALID_PARAMETER, "plugin_handle is NULL");
569 RET_VAL_IF(!service_type, VINE_DISC_ERROR_INVALID_PARAMETER, "service_type is NULL");
570 RET_VAL_IF(strlen(service_type) > NAN_MAX_SERVICE_NAME_LEN, VINE_DISC_ERROR_INVALID_PARAMETER,
571 "Too long service type");
573 vine_nan_s *nan_handle = (vine_nan_s *)plugin_handle;
574 VINE_LOGD("Subscribe. plugin_handle[%p], service_type[%s]",
575 plugin_handle, service_type);
577 wifi_aware_subscribe_h config = nullptr;
578 int ret = wifi_aware_subscribe_create(&config);
579 RET_VAL_IF(ret != WIFI_AWARE_ERROR_NONE, __convert_nan_error_to_vine_disc_error(ret),
580 "wifi_aware_subscribe_create() fails");
582 ret = wifi_aware_subscribe_set_type(config, WIFI_AWARE_SUBSCRIBE_TYPE_ACTIVE);
583 if (ret != WIFI_AWARE_ERROR_NONE) {
584 VINE_LOGE("wifi_aware_subscribe_set_type() fails");
588 ret = wifi_aware_subscribe_set_service_name(config, service_type);
589 if (ret != WIFI_AWARE_ERROR_NONE) {
590 VINE_LOGE("wifi_aware_subscribe_set_service_name() fails");
594 nan_handle->subscribe_config = config;
596 ret = wifi_aware_enable(__enabled_cb, nan_handle);
597 if (ret != WIFI_AWARE_ERROR_NONE) {
598 VINE_LOGE("wifi_aware_enable() fails");
602 return VINE_DISC_ERROR_NONE;
605 wifi_aware_subscribe_destroy(config);
606 return __convert_nan_error_to_vine_disc_error(ret);
609 vine_disc_error nan_stop_subscribe(void *plugin_handle)
611 RET_VAL_IF(!plugin_handle, VINE_DISC_ERROR_INVALID_PARAMETER, "plugin_handle is NULL");
613 VINE_LOGD("Stop subscribe. plugin_handle[%p]", plugin_handle);
614 vine_nan_s *nan_handle = (vine_nan_s *)plugin_handle;
615 __stop_session(nan_handle);
617 if (nan_handle->subscribe_config)
618 wifi_aware_subscribe_destroy(nan_handle->subscribe_config);
620 return VINE_DISC_ERROR_NONE;
624 void nan_register_callbacks(vine_disc_plugin_callbacks callbacks)
626 event_callbacks.published_cb = callbacks.published_cb;
627 event_callbacks.discovered_cb = callbacks.discovered_cb;
628 event_callbacks.ip_resolved_cb = callbacks.ip_resolved_cb;
629 event_callbacks.fd_added_cb = nullptr;
630 event_callbacks.fd_removed_cb = nullptr;
633 vine_disc_error nan_process_event(void *plugin_handle, int fd)
635 VINE_LOGE("Not supported function");
636 return VINE_DISC_ERROR_NOT_SUPPORTED;
639 void vine_disc_plugin_init(vine_disc_plugin_fn *fn)
642 fn->deinit = nan_deinit;
643 fn->publish = nan_publish;
644 fn->stop_publish = nan_stop_publish;
645 fn->subscribe = nan_subscribe;
646 fn->stop_subscribe = nan_stop_subscribe;
647 fn->resolve_ip = nan_resolve_ip;
648 fn->cancel_resolve_ip = nan_cancel_resolve_ip;
649 fn->register_callbacks = nan_register_callbacks;
650 fn->process_event = nan_process_event;