mirror of
https://github.com/espressif/esp-idf.git
synced 2025-12-05 08:40:39 +01:00
Update wifi lib with below - 1. Create NAN Discovery SM for beaconing & cluster formation 2. Create NAN interface for Tx/Rx of beacons & action frames 3. Add commands & events for NAN Services Publish/Subscribe/Followup 4. Add NAN Datapath definitions, Events, Peer structures 5. Support for forming and parsing of Datapath related attributes 6. Modules for NDP Req, Resp, Confirm, Term, Peer management 7. NAN Interface related additions in Datapath, Data Tx Q's In addition include below changes - 1. Add netif and driver support for NAN Interface 2. Add simple examples for Publisher-Subscriber usecases 3. Add an advanced console example that supports commands for NAN Discovery, Services & Datapath 4. Add wifi_apps for providing better NAN API's and Peer management Co-authored-by: Shyamal Khachane <shyamal.khachane@espressif.com>
1037 lines
34 KiB
C
1037 lines
34 KiB
C
/*
|
|
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include "esp_wifi.h"
|
|
#include "esp_private/wifi.h"
|
|
#include "esp_wifi_netif.h"
|
|
#include "freertos/event_groups.h"
|
|
#include "lwip/netdb.h"
|
|
#include "lwip/sockets.h"
|
|
#include "esp_event.h"
|
|
#include "esp_log.h"
|
|
#include "esp_check.h"
|
|
#include "esp_mac.h"
|
|
#include "os.h"
|
|
#include "esp_nan.h"
|
|
|
|
/* NAN States */
|
|
#define NAN_STARTED_BIT BIT0
|
|
#define NAN_STOPPED_BIT BIT1
|
|
|
|
/* NAN Events */
|
|
#define NDP_INDICATION BIT2
|
|
#define NDP_CONFIRMED BIT3
|
|
#define NDP_TERMINATED BIT4
|
|
|
|
/* Macros */
|
|
#define MACADDR_LEN 6
|
|
#define MACADDR_EQUAL(a1, a2) (memcmp(a1, a2, MACADDR_LEN))
|
|
#define MACADDR_COPY(dst, src) (memcpy(dst, src, MACADDR_LEN))
|
|
|
|
/* Global Variables */
|
|
static const char *TAG = "nan_app";
|
|
static EventGroupHandle_t nan_event_group;
|
|
static bool s_app_default_handlers_set = false;
|
|
static uint8_t null_mac[MACADDR_LEN] = {0};
|
|
|
|
struct peer_svc_info {
|
|
SLIST_ENTRY(peer_svc_info) next;
|
|
uint8_t peer_svc_info[ESP_WIFI_MAX_SVC_INFO_LEN]; /**< Information for followup message */
|
|
uint8_t svc_id; /**< Identifier of peer's service */
|
|
uint8_t own_svc_id; /**< Identifier for own service */
|
|
uint8_t type; /**< Service type (Publish/Subscribe) */
|
|
uint8_t peer_nmi[MACADDR_LEN]; /**< Peer's NAN Management Interface address */
|
|
};
|
|
|
|
struct own_svc_info {
|
|
char svc_name[ESP_WIFI_MAX_SVC_NAME_LEN]; /**< Name identifying a service */
|
|
uint8_t svc_id; /**< Identifier for a service */
|
|
uint8_t type; /**< Service type (Publish/Subscribe) */
|
|
bool ndp_resp_needed; /**< If enabled, NDP response is required */
|
|
uint8_t num_peer_records; /**< Count of peer records associated with svc_id */
|
|
SLIST_HEAD(peer_list_t, peer_svc_info) peer_list; /**< List of peers matched for specific service */
|
|
};
|
|
|
|
struct ndl_info {
|
|
uint8_t ndp_id; /**< Identifier for instance of NDP */
|
|
uint8_t peer_ndi[MACADDR_LEN]; /**< Peer's NAN Data Interface address */
|
|
uint8_t peer_nmi[MACADDR_LEN]; /**< Peer's NAN Management Interface address */
|
|
uint8_t publisher_id; /**< Publisher's service identifier */
|
|
uint8_t own_role; /**< Own role (Publisher/Subscriber) */
|
|
};
|
|
|
|
typedef struct {
|
|
uint8_t state;
|
|
uint8_t event;
|
|
struct ndl_info ndl[ESP_WIFI_NAN_DATAPATH_MAX_PEERS]; /**< Record of NDL of all peers */
|
|
struct own_svc_info own_svc[ESP_WIFI_NAN_MAX_SVC_SUPPORTED]; /**< Record of own service(s) */
|
|
esp_netif_t *nan_netif;
|
|
} nan_ctx_t;
|
|
|
|
static nan_ctx_t s_nan_ctx;
|
|
|
|
void esp_wifi_nan_get_ipv6_linklocal_from_mac(ip6_addr_t *ip6, uint8_t *mac_addr)
|
|
{
|
|
if (ip6 == NULL || mac_addr == NULL)
|
|
return;
|
|
/* Link-local prefix. */
|
|
ip6->addr[0] = htonl(0xfe800000ul);
|
|
ip6->addr[1] = 0;
|
|
|
|
/* Assume hwaddr is a 48-bit IEEE 802 MAC. Convert to EUI-64 address. Complement Group bit. */
|
|
ip6->addr[2] = htonl((((uint32_t)(mac_addr[0] ^ 0x02)) << 24) |
|
|
((uint32_t)(mac_addr[1]) << 16) |
|
|
((uint32_t)(mac_addr[2]) << 8) |
|
|
(0xff));
|
|
ip6->addr[3] = htonl((uint32_t)(0xfeul << 24) |
|
|
((uint32_t)(mac_addr[3]) << 16) |
|
|
((uint32_t)(mac_addr[4]) << 8) |
|
|
(mac_addr[5]));
|
|
|
|
ip6->zone = IP6_NO_ZONE;
|
|
}
|
|
|
|
static struct own_svc_info *nan_find_own_svc(uint8_t svc_id)
|
|
{
|
|
struct own_svc_info *p_svc = NULL;
|
|
|
|
if (svc_id == 0) {
|
|
ESP_LOGE(TAG, "Service id cannot be 0!");
|
|
return NULL;
|
|
}
|
|
|
|
for (int i = 0; i < ESP_WIFI_NAN_MAX_SVC_SUPPORTED; i++) {
|
|
if (s_nan_ctx.own_svc[i].svc_id == svc_id) {
|
|
p_svc = &s_nan_ctx.own_svc[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
return p_svc;
|
|
}
|
|
|
|
static struct own_svc_info *nan_find_own_svc_by_name(const char *svc_name)
|
|
{
|
|
struct own_svc_info *p_svc = NULL;
|
|
|
|
if (!svc_name) {
|
|
ESP_LOGE(TAG, "Service name not given!");
|
|
return NULL;
|
|
}
|
|
|
|
for (int i = 0; i < ESP_WIFI_NAN_MAX_SVC_SUPPORTED; i++) {
|
|
if (s_nan_ctx.own_svc[i].svc_id && !strcmp(s_nan_ctx.own_svc[i].svc_name, svc_name)) {
|
|
p_svc = &s_nan_ctx.own_svc[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
return p_svc;
|
|
}
|
|
|
|
static struct peer_svc_info *nan_find_peer_svc(uint8_t own_svc_id, uint8_t peer_svc_id, uint8_t peer_nmi[])
|
|
{
|
|
struct peer_svc_info *p_peer_svc = NULL, *temp;
|
|
struct own_svc_info *p_own_svc = NULL;
|
|
uint8_t *peer_nmi_valid = NULL;
|
|
int idx = 0;
|
|
|
|
if (MACADDR_EQUAL(peer_nmi, null_mac)) {
|
|
/* non-zero Peer NMI given, use it */
|
|
peer_nmi_valid = peer_nmi;
|
|
}
|
|
while (idx < ESP_WIFI_NAN_MAX_SVC_SUPPORTED) {
|
|
if (own_svc_id) {
|
|
p_own_svc = nan_find_own_svc(own_svc_id);
|
|
if (!p_own_svc) {
|
|
ESP_LOGE(TAG, "Cannot find own service with id %d!", own_svc_id);
|
|
return NULL;
|
|
}
|
|
} else {
|
|
p_own_svc = &s_nan_ctx.own_svc[idx++];
|
|
}
|
|
SLIST_FOREACH(temp, &(p_own_svc->peer_list), next) {
|
|
if (peer_svc_id != 0 && peer_nmi_valid) {
|
|
if (temp->svc_id == peer_svc_id && !MACADDR_EQUAL(temp->peer_nmi, peer_nmi_valid)) {
|
|
p_peer_svc = temp;
|
|
break;
|
|
}
|
|
} else if (peer_svc_id != 0) {
|
|
if (temp->svc_id == peer_svc_id) {
|
|
p_peer_svc = temp;
|
|
break;
|
|
}
|
|
} else {
|
|
if (peer_nmi_valid && !MACADDR_EQUAL(temp->peer_nmi, peer_nmi_valid)) {
|
|
p_peer_svc = temp;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (p_peer_svc || own_svc_id) { /* If no peer found with given own_svc_id, don't search in other services */
|
|
break;
|
|
}
|
|
}
|
|
return p_peer_svc;
|
|
}
|
|
|
|
static bool nan_record_peer_svc(uint8_t own_svc_id, uint8_t peer_svc_id, uint8_t peer_nmi[])
|
|
{
|
|
struct own_svc_info *p_own_svc;
|
|
struct peer_svc_info *p_peer_svc;
|
|
|
|
p_own_svc = nan_find_own_svc(own_svc_id);
|
|
if (!p_own_svc) {
|
|
ESP_LOGE(TAG, "Unable to find own service with id %d", own_svc_id);
|
|
return false;
|
|
}
|
|
p_peer_svc = (struct peer_svc_info *)os_zalloc(sizeof(struct peer_svc_info));
|
|
if (!p_peer_svc) {
|
|
ESP_LOGE(TAG, "Unable to allocate for Peer Service");
|
|
return false;
|
|
}
|
|
p_peer_svc->svc_id = peer_svc_id;
|
|
p_peer_svc->own_svc_id = own_svc_id;
|
|
p_peer_svc->type = (p_own_svc->type == ESP_NAN_SUBSCRIBE) ? ESP_NAN_PUBLISH : ESP_NAN_SUBSCRIBE;
|
|
MACADDR_COPY(p_peer_svc->peer_nmi, peer_nmi);
|
|
|
|
if (p_own_svc->num_peer_records < NAN_MAX_PEERS_RECORD) {
|
|
SLIST_INSERT_HEAD(&(p_own_svc->peer_list), p_peer_svc, next);
|
|
p_own_svc->num_peer_records++;
|
|
} else {
|
|
struct peer_svc_info *temp;
|
|
temp = SLIST_FIRST(&(p_own_svc->peer_list));
|
|
SLIST_REMOVE_HEAD(&(p_own_svc->peer_list), next);
|
|
os_free(temp);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static void nan_reset_service(uint8_t svc_id, bool reset_all)
|
|
{
|
|
struct own_svc_info *p_own_svc = NULL;
|
|
struct peer_svc_info *p_peer_svc = NULL, *temp;
|
|
int idx = 0;
|
|
|
|
if (svc_id == 0 && !reset_all) {
|
|
return;
|
|
}
|
|
|
|
while (idx < ESP_WIFI_NAN_MAX_SVC_SUPPORTED) {
|
|
p_own_svc = &s_nan_ctx.own_svc[idx++];
|
|
if (reset_all || (svc_id && p_own_svc->svc_id == svc_id)) {
|
|
SLIST_FOREACH_SAFE(p_peer_svc, &(p_own_svc->peer_list), next, temp) {
|
|
SLIST_REMOVE(&(p_own_svc->peer_list), p_peer_svc, peer_svc_info, next);
|
|
os_free(p_peer_svc);
|
|
}
|
|
memset(p_own_svc, 0, sizeof(struct own_svc_info));
|
|
}
|
|
}
|
|
}
|
|
|
|
static void nan_reset_ndl(uint8_t ndp_id, bool reset_all)
|
|
{
|
|
struct ndl_info *ndl = NULL;
|
|
|
|
if (reset_all) {
|
|
memset(s_nan_ctx.ndl, 0, sizeof(struct ndl_info) * ESP_WIFI_NAN_DATAPATH_MAX_PEERS);
|
|
return;
|
|
}
|
|
for (int i = 0; i < ESP_WIFI_NAN_DATAPATH_MAX_PEERS; i++) {
|
|
ndl = &s_nan_ctx.ndl[i];
|
|
if (ndl->ndp_id == ndp_id) {
|
|
memset(ndl, 0, sizeof(struct ndl_info));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static bool nan_services_limit_reached(void)
|
|
{
|
|
for (int i = 0; i < ESP_WIFI_NAN_MAX_SVC_SUPPORTED; i++) {
|
|
if (s_nan_ctx.own_svc[i].svc_id == 0) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static void nan_record_own_svc(uint8_t id, uint8_t type, const char svc_name[], bool ndp_resp_needed)
|
|
{
|
|
struct own_svc_info *p_svc = NULL;
|
|
|
|
for (int i = 0; i < ESP_WIFI_NAN_MAX_SVC_SUPPORTED; i++) {
|
|
if (s_nan_ctx.own_svc[i].svc_id == 0) {
|
|
p_svc = &s_nan_ctx.own_svc[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!p_svc) {
|
|
return;
|
|
}
|
|
|
|
p_svc->svc_id = id;
|
|
p_svc->type = type;
|
|
strlcpy(p_svc->svc_name, svc_name, ESP_WIFI_MAX_SVC_NAME_LEN);
|
|
SLIST_INIT(&(p_svc->peer_list));
|
|
if (type == ESP_NAN_PUBLISH) {
|
|
p_svc->ndp_resp_needed = ndp_resp_needed;
|
|
}
|
|
}
|
|
|
|
static bool ndl_limit_reached(void)
|
|
{
|
|
for (int i = 0; i < ESP_WIFI_NAN_DATAPATH_MAX_PEERS; i++) {
|
|
if (s_nan_ctx.ndl[i].ndp_id == 0) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static void nan_record_new_ndl(uint8_t ndp_id, uint8_t publish_id, uint8_t peer_nmi[], uint8_t own_role)
|
|
{
|
|
struct ndl_info *ndl = NULL;
|
|
|
|
for (int i = 0; i < ESP_WIFI_NAN_DATAPATH_MAX_PEERS; i++) {
|
|
if (s_nan_ctx.ndl[i].ndp_id == 0) {
|
|
ndl = &s_nan_ctx.ndl[i];
|
|
break;
|
|
}
|
|
}
|
|
if (!ndl) {
|
|
return;
|
|
}
|
|
ndl->ndp_id = ndp_id;
|
|
if (peer_nmi) {
|
|
MACADDR_COPY(ndl->peer_nmi, peer_nmi);
|
|
}
|
|
ndl->publisher_id = publish_id;
|
|
ndl->own_role = own_role;
|
|
}
|
|
|
|
static struct ndl_info *nan_find_ndl(uint8_t ndp_id, uint8_t peer_nmi[])
|
|
{
|
|
struct ndl_info *ndl = NULL;
|
|
|
|
for (int i = 0; i < ESP_WIFI_NAN_DATAPATH_MAX_PEERS; i++) {
|
|
ndl = &s_nan_ctx.ndl[i];
|
|
if (ndp_id != 0 && peer_nmi) {
|
|
if (ndl->ndp_id == ndp_id && !MACADDR_EQUAL(ndl->peer_nmi, peer_nmi)) {
|
|
return ndl;
|
|
}
|
|
} else if (ndp_id != 0) {
|
|
if (ndl->ndp_id == ndp_id) {
|
|
return ndl;
|
|
}
|
|
} else if (peer_nmi) {
|
|
if (!MACADDR_EQUAL(ndl->peer_nmi, peer_nmi)) {
|
|
return ndl;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static bool nan_is_datapath_active(void)
|
|
{
|
|
for (int i = 0; i < ESP_WIFI_NAN_DATAPATH_MAX_PEERS; i++) {
|
|
if (s_nan_ctx.ndl[i].ndp_id != 0) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static void nan_fill_params_from_event(void *evt_data, uint8_t event)
|
|
{
|
|
switch (event) {
|
|
case WIFI_EVENT_NDP_INDICATION: {
|
|
wifi_event_ndp_indication_t *evt = (wifi_event_ndp_indication_t *)evt_data;
|
|
nan_record_new_ndl(evt->ndp_id, evt->publish_id, evt->peer_nmi, ESP_WIFI_NDP_ROLE_RESPONDER);
|
|
break;
|
|
}
|
|
case WIFI_EVENT_NDP_CONFIRM: {
|
|
wifi_event_ndp_confirm_t *evt = (wifi_event_ndp_confirm_t *)evt_data;
|
|
struct ndl_info *ndl = NULL;
|
|
|
|
if ((ndl = nan_find_ndl(evt->ndp_id, evt->peer_nmi)) == NULL) {
|
|
ESP_LOGE(TAG, "No NDL with ndp id %d", evt->ndp_id);
|
|
return;
|
|
}
|
|
MACADDR_COPY(ndl->peer_ndi, evt->peer_ndi);
|
|
break;
|
|
}
|
|
case WIFI_EVENT_NAN_REPLIED: {
|
|
wifi_event_nan_replied_t *evt = (wifi_event_nan_replied_t *)evt_data;
|
|
|
|
if (!nan_find_peer_svc(evt->publish_id, evt->subscribe_id, evt->sub_if_mac)) {
|
|
nan_record_peer_svc(evt->publish_id, evt->subscribe_id, evt->sub_if_mac);
|
|
}
|
|
break;
|
|
}
|
|
case WIFI_EVENT_NAN_RECEIVE: {
|
|
wifi_event_nan_receive_t *evt = (wifi_event_nan_receive_t *)evt_data;
|
|
|
|
if (!nan_find_peer_svc(evt->inst_id, evt->peer_inst_id, evt->peer_if_mac)) {
|
|
nan_record_peer_svc(evt->inst_id, evt->peer_inst_id, evt->peer_if_mac);
|
|
}
|
|
break;
|
|
}
|
|
case WIFI_EVENT_NAN_SVC_MATCH: {
|
|
wifi_event_nan_svc_match_t *evt = (wifi_event_nan_svc_match_t *)evt_data;
|
|
|
|
if (!nan_find_peer_svc(evt->subscribe_id, evt->publish_id, evt->pub_if_mac)) {
|
|
nan_record_peer_svc(evt->subscribe_id, evt->publish_id, evt->pub_if_mac);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void nan_app_action_service_match(void *arg, esp_event_base_t event_base, int32_t event_id, void *data)
|
|
{
|
|
if (data == NULL) {
|
|
return;
|
|
}
|
|
wifi_event_nan_svc_match_t *evt = (wifi_event_nan_svc_match_t *)data;
|
|
|
|
ESP_LOGI(TAG, "Service matched with "MACSTR" [Peer Publish id - %d]",
|
|
MAC2STR(evt->pub_if_mac), evt->publish_id);
|
|
nan_fill_params_from_event(evt, WIFI_EVENT_NAN_SVC_MATCH);
|
|
}
|
|
|
|
static void nan_app_action_replied(void *arg, esp_event_base_t event_base, int32_t event_id, void *data)
|
|
{
|
|
if (data == NULL) {
|
|
return;
|
|
}
|
|
wifi_event_nan_replied_t *evt = (wifi_event_nan_replied_t *)data;
|
|
|
|
ESP_LOGD(TAG, "Sent Publish to Peer "MACSTR" [Peer Subscribe id - %d]",
|
|
MAC2STR(evt->sub_if_mac), evt->subscribe_id);
|
|
nan_fill_params_from_event(evt, WIFI_EVENT_NAN_REPLIED);
|
|
}
|
|
|
|
static void nan_app_action_receive(void *arg, esp_event_base_t event_base, int32_t event_id, void *data)
|
|
{
|
|
if (data == NULL) {
|
|
return;
|
|
}
|
|
wifi_event_nan_receive_t *evt = (wifi_event_nan_receive_t *)data;
|
|
|
|
ESP_LOGI(TAG, "Received message '%s' from Peer "MACSTR" [Peer Service id - %d]",
|
|
evt->peer_svc_info, MAC2STR(evt->peer_if_mac), evt->peer_inst_id);
|
|
nan_fill_params_from_event(evt, WIFI_EVENT_NAN_RECEIVE);
|
|
}
|
|
|
|
static void nan_app_action_ndp_indication(void *arg, esp_event_base_t event_base, int32_t event_id, void *data)
|
|
{
|
|
if (data == NULL) {
|
|
return;
|
|
}
|
|
wifi_event_ndp_indication_t *evt = (wifi_event_ndp_indication_t *)data;
|
|
struct own_svc_info *p_own_svc = nan_find_own_svc(evt->publish_id);
|
|
|
|
if (!p_own_svc) {
|
|
ESP_LOGE(TAG, "No Publish found with id %d", evt->publish_id);
|
|
return;
|
|
}
|
|
if (ndl_limit_reached()) {
|
|
ESP_LOGE(TAG, "NDP limit reached");
|
|
return;
|
|
}
|
|
|
|
nan_fill_params_from_event(evt, WIFI_EVENT_NDP_INDICATION);
|
|
if (p_own_svc->ndp_resp_needed) {
|
|
ESP_LOGI(TAG, "NDP Req from "MACSTR" [NDP Id: %d], Accept OR Deny using NDP command",
|
|
MAC2STR(evt->peer_nmi), evt->ndp_id);
|
|
s_nan_ctx.event |= NDP_INDICATION;
|
|
} else {
|
|
wifi_nan_datapath_resp_t ndp_resp = {0};
|
|
ndp_resp.accept = true;
|
|
ndp_resp.ndp_id = evt->ndp_id;
|
|
MACADDR_COPY(ndp_resp.peer_mac, evt->peer_nmi);
|
|
|
|
esp_nan_internal_datapath_resp(&ndp_resp);
|
|
}
|
|
}
|
|
|
|
static void nan_app_action_ndp_confirm(void *arg, esp_event_base_t event_base, int32_t event_id, void *data)
|
|
{
|
|
if (data == NULL) {
|
|
return;
|
|
}
|
|
wifi_event_ndp_confirm_t *evt = (wifi_event_ndp_confirm_t *)data;
|
|
wifi_netif_driver_t driver = esp_netif_get_io_driver(s_nan_ctx.nan_netif);
|
|
ip_addr_t target_addr = {0};
|
|
|
|
if (!s_nan_ctx.nan_netif) {
|
|
ESP_LOGE(TAG, "%s: NAN netif is NULL", __func__);
|
|
return;
|
|
}
|
|
if (evt->status == NDP_STATUS_REJECTED) {
|
|
ESP_LOGE(TAG, "NDP request to Peer "MACSTR" rejected [NDP ID - %d]", MAC2STR(evt->peer_nmi), evt->ndp_id);
|
|
nan_reset_ndl(evt->ndp_id, false);
|
|
return;
|
|
}
|
|
|
|
// if interface not ready when started, rxcb to be registered on connection
|
|
if (esp_wifi_register_if_rxcb(driver, esp_netif_receive, s_nan_ctx.nan_netif) != ESP_OK) {
|
|
ESP_LOGE(TAG, "%s: esp_wifi_register_if_rxcb failed", __func__);
|
|
return;
|
|
}
|
|
|
|
nan_fill_params_from_event(evt, WIFI_EVENT_NDP_CONFIRM);
|
|
|
|
esp_netif_action_connected(s_nan_ctx.nan_netif, event_base, event_id, data);
|
|
|
|
esp_netif_create_ip6_linklocal(s_nan_ctx.nan_netif);
|
|
s_nan_ctx.state |= NDP_CONFIRMED;
|
|
esp_wifi_nan_get_ipv6_linklocal_from_mac(&target_addr.u_addr.ip6, evt->peer_ndi);
|
|
target_addr.type = IPADDR_TYPE_V6;
|
|
ESP_LOGI(TAG, "NDP confirmed with Peer "MACSTR" [NDP ID - %d, Peer IPv6 - %s]",
|
|
MAC2STR(evt->peer_nmi), evt->ndp_id, inet6_ntoa(*ip_2_ip6(&target_addr)));
|
|
}
|
|
|
|
static void nan_app_action_ndp_terminated(void *arg, esp_event_base_t event_base, int32_t event_id, void *data)
|
|
{
|
|
if (data == NULL) {
|
|
return;
|
|
}
|
|
wifi_event_ndp_terminated_t *evt = (wifi_event_ndp_terminated_t *)data;
|
|
|
|
if (s_nan_ctx.nan_netif && !nan_is_datapath_active()) {
|
|
esp_netif_action_disconnected(s_nan_ctx.nan_netif, event_base, event_id, data);
|
|
}
|
|
ESP_LOGI(TAG, "NDP terminated with Peer "MACSTR" [NDP ID - %d]", MAC2STR(evt->init_ndi), evt->ndp_id);
|
|
nan_reset_ndl(evt->ndp_id, false);
|
|
|
|
s_nan_ctx.state &= ~(NDP_CONFIRMED);
|
|
s_nan_ctx.event &= ~(NDP_INDICATION);
|
|
os_event_group_set_bits(nan_event_group, NDP_TERMINATED);
|
|
}
|
|
|
|
/* types of ipv6 addresses to be displayed on ipv6 events */
|
|
static const char *s_ipv6_addr_types[] = {
|
|
"UNKNOWN",
|
|
"GLOBAL",
|
|
"LINK_LOCAL",
|
|
"SITE_LOCAL",
|
|
"UNIQUE_LOCAL",
|
|
"IPV4_MAPPED_IPV6"
|
|
};
|
|
|
|
static void nan_app_action_got_ipv6(void *arg, esp_event_base_t event_base, int32_t event_id, void *data)
|
|
{
|
|
if (data == NULL) {
|
|
return;
|
|
}
|
|
ip_event_got_ip6_t *event = (ip_event_got_ip6_t *)data;
|
|
|
|
if (event->esp_netif == s_nan_ctx.nan_netif) {
|
|
esp_ip6_addr_type_t ipv6_type = esp_netif_ip6_get_addr_type(&event->ip6_info.ip);
|
|
ESP_LOGD(TAG, "NAN Data Interface ready [IPv6 - "IPV6STR", type - %s]",
|
|
IPV62STR(event->ip6_info.ip), s_ipv6_addr_types[ipv6_type]);
|
|
}
|
|
}
|
|
|
|
static esp_err_t nan_clear_app_default_handlers(void)
|
|
{
|
|
esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_NAN_SVC_MATCH, nan_app_action_service_match);
|
|
esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_NAN_REPLIED, nan_app_action_replied);
|
|
esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_NAN_RECEIVE, nan_app_action_receive);
|
|
esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_NDP_INDICATION, nan_app_action_ndp_indication);
|
|
esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_NDP_CONFIRM, nan_app_action_ndp_confirm);
|
|
esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_NDP_TERMINATED, nan_app_action_ndp_terminated);
|
|
esp_event_handler_unregister(IP_EVENT, IP_EVENT_GOT_IP6, nan_app_action_got_ipv6);
|
|
s_app_default_handlers_set = false;
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
static esp_err_t nan_set_app_default_handlers(void)
|
|
{
|
|
if (s_app_default_handlers_set) {
|
|
return ESP_OK;
|
|
}
|
|
|
|
int ret;
|
|
(void) ret;
|
|
ESP_GOTO_ON_ERROR(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_NAN_SVC_MATCH,
|
|
nan_app_action_service_match, NULL), fail, TAG, "Registering event handler failed");
|
|
|
|
ESP_GOTO_ON_ERROR(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_NAN_REPLIED,
|
|
nan_app_action_replied, NULL), fail, TAG, "Registering event handler failed");
|
|
|
|
ESP_GOTO_ON_ERROR(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_NAN_RECEIVE,
|
|
nan_app_action_receive, NULL), fail, TAG, "Registering event handler failed");
|
|
|
|
ESP_GOTO_ON_ERROR(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_NDP_INDICATION,
|
|
nan_app_action_ndp_indication, NULL), fail, TAG, "Registering event handler failed");
|
|
|
|
ESP_GOTO_ON_ERROR(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_NDP_CONFIRM,
|
|
nan_app_action_ndp_confirm, NULL), fail, TAG, "Registering event handler failed");
|
|
|
|
ESP_GOTO_ON_ERROR(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_NDP_TERMINATED,
|
|
nan_app_action_ndp_terminated, NULL), fail, TAG, "Registering event handler failed");
|
|
|
|
ESP_GOTO_ON_ERROR(esp_event_handler_register(IP_EVENT, IP_EVENT_GOT_IP6,
|
|
nan_app_action_got_ipv6, NULL), fail, TAG, "Registering event handler failed");
|
|
|
|
s_app_default_handlers_set = true;
|
|
return ESP_OK;
|
|
|
|
fail:
|
|
nan_clear_app_default_handlers();
|
|
return ESP_FAIL;
|
|
}
|
|
|
|
void esp_nan_app_init(void)
|
|
{
|
|
if (nan_event_group) {
|
|
os_event_group_delete(nan_event_group);
|
|
nan_event_group = NULL;
|
|
}
|
|
nan_event_group = os_event_group_create();
|
|
}
|
|
|
|
void esp_nan_app_deinit(void)
|
|
{
|
|
if (nan_event_group) {
|
|
os_event_group_delete(nan_event_group);
|
|
nan_event_group = NULL;
|
|
}
|
|
}
|
|
|
|
void esp_nan_action_start(esp_netif_t *nan_netif)
|
|
{
|
|
if (nan_set_app_default_handlers() != ESP_OK) {
|
|
ESP_LOGE(TAG, "Registering NAN handlers failed");
|
|
return;
|
|
}
|
|
|
|
s_nan_ctx.nan_netif = nan_netif;
|
|
|
|
s_nan_ctx.state = NAN_STARTED_BIT;
|
|
ESP_LOGI(TAG, "NAN Discovery started.");
|
|
os_event_group_set_bits(nan_event_group, NAN_STARTED_BIT);
|
|
}
|
|
|
|
void esp_nan_action_stop(void)
|
|
{
|
|
nan_clear_app_default_handlers();
|
|
|
|
if (s_nan_ctx.state & NDP_CONFIRMED) {
|
|
nan_reset_ndl(0, true);
|
|
esp_wifi_internal_reg_rxcb(WIFI_IF_NAN, NULL);
|
|
}
|
|
|
|
nan_reset_service(0, true);
|
|
s_nan_ctx.state &= ~NAN_STARTED_BIT;
|
|
s_nan_ctx.state |= NAN_STOPPED_BIT;
|
|
os_event_group_set_bits(nan_event_group, NAN_STOPPED_BIT);
|
|
}
|
|
|
|
esp_err_t esp_wifi_nan_start(const wifi_nan_config_t *nan_cfg)
|
|
{
|
|
wifi_mode_t mode;
|
|
esp_err_t ret;
|
|
wifi_config_t config = {0};
|
|
|
|
ret = esp_wifi_get_mode(&mode);
|
|
if (ret == ESP_ERR_WIFI_NOT_INIT) {
|
|
ESP_LOGE(TAG, "WiFi not initialised!");
|
|
return ret;
|
|
} else if (ret != ESP_OK) {
|
|
ESP_LOGE(TAG, "Unable to get mode");
|
|
return ret;
|
|
}
|
|
if (s_nan_ctx.state & NAN_STARTED_BIT) {
|
|
ESP_LOGI(TAG, "NAN already started");
|
|
return ESP_OK;
|
|
}
|
|
|
|
ESP_RETURN_ON_ERROR(esp_wifi_set_mode(WIFI_MODE_NAN), TAG, "Set mode NAN failed");
|
|
|
|
memcpy(&config.nan, nan_cfg, sizeof(wifi_nan_config_t));
|
|
ESP_RETURN_ON_ERROR(esp_wifi_set_config(WIFI_IF_NAN, &config), TAG, "Setting NAN config failed");
|
|
|
|
if (esp_wifi_start() != ESP_OK) {
|
|
ESP_LOGE(TAG, "Starting wifi failed");
|
|
s_nan_ctx.nan_netif = NULL;
|
|
return ESP_FAIL;
|
|
}
|
|
|
|
EventBits_t bits = os_event_group_wait_bits(nan_event_group, NAN_STARTED_BIT, pdFALSE, pdFALSE, portMAX_DELAY);
|
|
if (!(bits & NAN_STARTED_BIT)) {
|
|
s_nan_ctx.nan_netif = NULL;
|
|
return ESP_FAIL;
|
|
}
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t esp_wifi_nan_stop(void)
|
|
{
|
|
if (!(s_nan_ctx.state & NAN_STARTED_BIT)) {
|
|
ESP_LOGE(TAG, "NAN isn't started");
|
|
return ESP_FAIL;
|
|
}
|
|
|
|
if (s_nan_ctx.state & NDP_CONFIRMED) {
|
|
/* Terminate all NDP's */
|
|
wifi_nan_datapath_end_req_t ndp_end = {0};
|
|
for (int i=0; i < ESP_WIFI_NAN_DATAPATH_MAX_PEERS; i++) {
|
|
if (s_nan_ctx.ndl[i].ndp_id) {
|
|
MACADDR_COPY(ndp_end.peer_mac, s_nan_ctx.ndl[i].peer_nmi);
|
|
ndp_end.ndp_id = s_nan_ctx.ndl[i].ndp_id;
|
|
esp_nan_internal_datapath_end(&ndp_end);
|
|
}
|
|
}
|
|
nan_reset_ndl(0, true);
|
|
|
|
os_event_group_clear_bits(nan_event_group, NDP_TERMINATED);
|
|
os_event_group_wait_bits(nan_event_group, NDP_TERMINATED, pdFALSE, pdFALSE, portMAX_DELAY);
|
|
os_event_group_clear_bits(nan_event_group, NDP_TERMINATED);
|
|
/* Wait for 1 NAN DW interval (512 TU's ~= 524 mSec) for successful termination */
|
|
g_wifi_osi_funcs._task_delay(524/portTICK_PERIOD_MS);
|
|
}
|
|
|
|
ESP_RETURN_ON_ERROR(esp_wifi_stop(), TAG, "Stopping NAN failed");
|
|
|
|
EventBits_t bits = os_event_group_wait_bits(nan_event_group, NAN_STOPPED_BIT, pdFALSE, pdFALSE, portMAX_DELAY);
|
|
if (!(bits & NAN_STOPPED_BIT)) {
|
|
return ESP_FAIL;
|
|
}
|
|
|
|
memset(&s_nan_ctx, 0, sizeof(nan_ctx_t));
|
|
return ESP_OK;
|
|
}
|
|
|
|
uint8_t esp_wifi_nan_publish_service(const wifi_nan_publish_cfg_t *publish_cfg, bool ndp_resp_needed)
|
|
{
|
|
uint8_t pub_id;
|
|
|
|
if (!(s_nan_ctx.state & NAN_STARTED_BIT)) {
|
|
ESP_LOGE(TAG, "NAN not started!");
|
|
return 0;
|
|
}
|
|
if (nan_services_limit_reached()) {
|
|
ESP_LOGE(TAG, "Maximum services limit reached");
|
|
return 0;
|
|
}
|
|
|
|
if (nan_find_own_svc_by_name(publish_cfg->service_name)) {
|
|
ESP_LOGE(TAG, "Service name already used!");
|
|
return 0;
|
|
}
|
|
|
|
if (esp_nan_internal_publish_service(publish_cfg, &pub_id, false) != ESP_OK) {
|
|
ESP_LOGE(TAG, "Failed to publish service '%s'", publish_cfg->service_name);
|
|
return 0;
|
|
}
|
|
|
|
ESP_LOGI(TAG, "Started Publishing %s [Service ID - %lu]", publish_cfg->service_name, pub_id);
|
|
nan_record_own_svc(pub_id, ESP_NAN_PUBLISH, publish_cfg->service_name, ndp_resp_needed);
|
|
|
|
return pub_id;
|
|
}
|
|
|
|
uint8_t esp_wifi_nan_subscribe_service(const wifi_nan_subscribe_cfg_t *subscribe_cfg)
|
|
{
|
|
uint8_t sub_id;
|
|
|
|
if (!(s_nan_ctx.state & NAN_STARTED_BIT)) {
|
|
ESP_LOGE(TAG, "NAN not started!");
|
|
return 0;
|
|
}
|
|
if (nan_services_limit_reached()) {
|
|
ESP_LOGE(TAG, "Maximum services limit reached");
|
|
return 0;
|
|
}
|
|
|
|
if (nan_find_own_svc_by_name(subscribe_cfg->service_name)) {
|
|
ESP_LOGE(TAG, "Service name already used!");
|
|
return 0;
|
|
}
|
|
|
|
if (esp_nan_internal_subscribe_service(subscribe_cfg, &sub_id, false) != ESP_OK) {
|
|
ESP_LOGE(TAG, "Failed to subscribe to service '%s'", subscribe_cfg->service_name);
|
|
return 0;
|
|
}
|
|
|
|
ESP_LOGI(TAG, "Started Subscribing to %s [Service ID - %lu]", subscribe_cfg->service_name, sub_id);
|
|
nan_record_own_svc(sub_id, ESP_NAN_SUBSCRIBE, subscribe_cfg->service_name, false);
|
|
|
|
return sub_id;
|
|
}
|
|
|
|
esp_err_t esp_wifi_nan_send_message(wifi_nan_followup_params_t *fup_params)
|
|
{
|
|
struct peer_svc_info *p_peer_svc;
|
|
|
|
p_peer_svc = nan_find_peer_svc(fup_params->inst_id, fup_params->peer_inst_id,
|
|
fup_params->peer_mac);
|
|
if (!p_peer_svc) {
|
|
ESP_LOGE(TAG, "Cannot send Follow-up, peer not found!");
|
|
return ESP_FAIL;
|
|
}
|
|
|
|
if (!fup_params->inst_id) {
|
|
fup_params->inst_id = p_peer_svc->own_svc_id;
|
|
}
|
|
if (!MACADDR_EQUAL(fup_params->peer_mac, null_mac)) {
|
|
MACADDR_COPY(fup_params->peer_mac, p_peer_svc->peer_nmi);
|
|
}
|
|
|
|
if (esp_nan_internal_send_followup(fup_params) != ESP_OK) {
|
|
ESP_LOGE(TAG, "Failed to send Follow-up message!");
|
|
return ESP_FAIL;
|
|
}
|
|
ESP_LOGI(TAG, "Sent message '%s' to Peer "MACSTR" with Service ID %d", fup_params->svc_info,
|
|
MAC2STR(fup_params->peer_mac), fup_params->peer_inst_id);
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t esp_wifi_nan_cancel_service(uint8_t service_id)
|
|
{
|
|
struct own_svc_info *p_own_svc = nan_find_own_svc(service_id);
|
|
|
|
if (!p_own_svc) {
|
|
ESP_LOGE(TAG, "Cannot find own service with id %d!", service_id);
|
|
return ESP_FAIL;
|
|
}
|
|
|
|
if (p_own_svc->type == ESP_NAN_PUBLISH) {
|
|
if (esp_nan_internal_publish_service(NULL, &service_id, true) == ESP_OK) {
|
|
nan_reset_service(service_id, false);
|
|
ESP_LOGI(TAG, "Cancelled Publish with Service ID %d", service_id);
|
|
return ESP_OK;
|
|
}
|
|
}
|
|
|
|
if (p_own_svc->type == ESP_NAN_SUBSCRIBE) {
|
|
if (esp_nan_internal_subscribe_service(NULL, &service_id, true) == ESP_OK) {
|
|
nan_reset_service(service_id, false);
|
|
ESP_LOGI(TAG, "Cancelled Subscribe with Service ID %d", service_id);
|
|
return ESP_OK;
|
|
}
|
|
}
|
|
|
|
return ESP_FAIL;
|
|
}
|
|
|
|
uint8_t esp_wifi_nan_datapath_req(wifi_nan_datapath_req_t *req)
|
|
{
|
|
uint8_t ndp_id = 0;
|
|
struct peer_svc_info *p_peer_svc = nan_find_peer_svc(0, req->pub_id, req->peer_mac);
|
|
|
|
if (!p_peer_svc) {
|
|
ESP_LOGE(TAG, "Cannot send NDP Req, peer not found!");
|
|
return 0;
|
|
}
|
|
if (req->pub_id == 0)
|
|
req->pub_id = p_peer_svc->svc_id;
|
|
|
|
if (p_peer_svc->type != ESP_NAN_PUBLISH) {
|
|
ESP_LOGE(TAG, "Only subscriber can send an NDP Req to a Publisher");
|
|
return 0;
|
|
}
|
|
if (ndl_limit_reached()) {
|
|
ESP_LOGE(TAG, "Cannot establish new datapath, limit reached!");
|
|
return 0;
|
|
}
|
|
|
|
if (!MACADDR_EQUAL(req->peer_mac, null_mac)) {
|
|
MACADDR_COPY(req->peer_mac, p_peer_svc->peer_nmi);
|
|
}
|
|
|
|
if (esp_nan_internal_datapath_req(req, &ndp_id) != ESP_OK) {
|
|
ESP_LOGE(TAG, "Failed to initiate NDP req");
|
|
return 0;
|
|
}
|
|
nan_record_new_ndl(ndp_id, req->pub_id, req->peer_mac, ESP_WIFI_NDP_ROLE_INITIATOR);
|
|
ESP_LOGD(TAG, "Requested NDP with "MACSTR" [NDP ID - %d]", MAC2STR(req->peer_mac), ndp_id);
|
|
|
|
return ndp_id;
|
|
}
|
|
|
|
esp_err_t esp_wifi_nan_datapath_resp(wifi_nan_datapath_resp_t *resp)
|
|
{
|
|
struct ndl_info *ndl = nan_find_ndl(resp->ndp_id, NULL);
|
|
|
|
if (!ndl) {
|
|
ESP_LOGE(TAG, "No NDL with ndp id %d", resp->ndp_id);
|
|
return ESP_FAIL;
|
|
}
|
|
if (!(s_nan_ctx.event & NDP_INDICATION)) { //INDICATION of specific peer
|
|
ESP_LOGE(TAG, "Need NDP Indication before NDP Response can be sent");
|
|
return ESP_FAIL;
|
|
}
|
|
|
|
if (!MACADDR_EQUAL(resp->peer_mac, null_mac)) {
|
|
MACADDR_COPY(resp->peer_mac, ndl->peer_nmi);
|
|
}
|
|
|
|
if (esp_nan_internal_datapath_resp(resp) == ESP_OK) {
|
|
s_nan_ctx.event &= ~NDP_INDICATION;
|
|
return ESP_OK;
|
|
}
|
|
|
|
return ESP_FAIL;
|
|
}
|
|
|
|
esp_err_t esp_wifi_nan_datapath_end(wifi_nan_datapath_end_req_t *req)
|
|
{
|
|
struct ndl_info *ndl = NULL;
|
|
|
|
if (!(s_nan_ctx.state & NDP_CONFIRMED)) {
|
|
ESP_LOGE(TAG, "No Datapath active");
|
|
return ESP_FAIL;
|
|
}
|
|
|
|
ndl = nan_find_ndl(req->ndp_id, NULL);
|
|
if (!ndl) {
|
|
ESP_LOGE(TAG, "No NDL with ndp id %d", req->ndp_id);
|
|
return ESP_FAIL;
|
|
}
|
|
if (!MACADDR_EQUAL(req->peer_mac, null_mac)) {
|
|
MACADDR_COPY(req->peer_mac, ndl->peer_nmi);
|
|
}
|
|
|
|
if (esp_nan_internal_datapath_end(req) == ESP_OK) {
|
|
return ESP_OK;
|
|
}
|
|
|
|
return ESP_FAIL;
|
|
}
|
|
|
|
esp_err_t esp_wifi_nan_get_own_svc_info(uint8_t *own_svc_id, char *svc_name, int *num_peer_records)
|
|
{
|
|
struct own_svc_info *own_svc = NULL;
|
|
|
|
if (!own_svc_id || !num_peer_records || !svc_name) {
|
|
ESP_LOGE(TAG, "NULL memory address for input parameters");
|
|
return ESP_FAIL;
|
|
}
|
|
|
|
if (*own_svc_id == 0) {
|
|
own_svc = nan_find_own_svc_by_name(svc_name);
|
|
if (!own_svc) {
|
|
ESP_LOGE(TAG, "No record found for given service name %s", svc_name);
|
|
return ESP_FAIL;
|
|
}
|
|
*own_svc_id = own_svc->svc_id;
|
|
} else {
|
|
own_svc = nan_find_own_svc(*own_svc_id);
|
|
if (!own_svc) {
|
|
ESP_LOGE(TAG, "No record found for given service ID %d", *own_svc_id);
|
|
return ESP_FAIL;
|
|
}
|
|
strlcpy(svc_name, own_svc->svc_name, ESP_WIFI_MAX_SVC_NAME_LEN);
|
|
}
|
|
|
|
*num_peer_records = own_svc->num_peer_records;
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t esp_wifi_nan_get_peer_records(int *num_peer_records, uint8_t own_svc_id, struct nan_peer_record *peer_record)
|
|
{
|
|
struct own_svc_info *own_record = NULL;
|
|
struct peer_svc_info *temp = NULL;
|
|
int peer_num = 0;
|
|
|
|
if (!peer_record || !num_peer_records) {
|
|
ESP_LOGE(TAG, "NULL memory address for input parameters");
|
|
return ESP_FAIL;
|
|
}
|
|
if (own_svc_id == 0) {
|
|
ESP_LOGE(TAG, "Invalid service ID");
|
|
return ESP_FAIL;
|
|
}
|
|
if (*num_peer_records == 0) {
|
|
ESP_LOGE(TAG, "Number of peer records provided is 0");
|
|
return ESP_FAIL;
|
|
}
|
|
|
|
own_record = nan_find_own_svc(own_svc_id);
|
|
if (own_record) {
|
|
SLIST_FOREACH(temp, &(own_record->peer_list), next) {
|
|
struct ndl_info *p_ndl;
|
|
peer_record[peer_num].peer_svc_id = temp->svc_id;
|
|
peer_record[peer_num].own_svc_id = own_svc_id;
|
|
peer_record[peer_num].peer_svc_type = temp->type;
|
|
MACADDR_COPY(peer_record[peer_num].peer_nmi, temp->peer_nmi);
|
|
p_ndl = nan_find_ndl(0, temp->peer_nmi);
|
|
if (p_ndl) {
|
|
peer_record[peer_num].ndp_id = p_ndl->ndp_id;
|
|
MACADDR_COPY(peer_record[peer_num].peer_ndi, p_ndl->peer_ndi);
|
|
} else {
|
|
peer_record[peer_num].ndp_id = 0;
|
|
MACADDR_COPY(peer_record[peer_num].peer_ndi, null_mac);
|
|
}
|
|
peer_num ++;
|
|
if (peer_num == *num_peer_records) {
|
|
break;
|
|
}
|
|
}
|
|
if (*num_peer_records > peer_num) {
|
|
*num_peer_records = peer_num;
|
|
}
|
|
return ESP_OK;
|
|
} else {
|
|
*num_peer_records = 0;
|
|
ESP_LOGD(TAG, "No record found for own service id %d", own_svc_id);
|
|
return ESP_FAIL;
|
|
}
|
|
}
|
|
|
|
esp_err_t esp_wifi_nan_get_peer_info(char *svc_name, uint8_t *peer_mac, struct nan_peer_record *peer_info)
|
|
{
|
|
struct peer_svc_info *peer_svc = NULL;
|
|
uint8_t own_svc_id = 0;
|
|
|
|
if (!peer_mac || !peer_info) {
|
|
ESP_LOGE(TAG, "Invalid memory address for input parameters");
|
|
return ESP_FAIL;
|
|
}
|
|
|
|
if (svc_name) {
|
|
struct own_svc_info *own_svc = nan_find_own_svc_by_name(svc_name);
|
|
if (!own_svc) {
|
|
ESP_LOGE(TAG, "No record found for given service name %s", svc_name);
|
|
return ESP_FAIL;
|
|
}
|
|
own_svc_id = own_svc->svc_id;
|
|
}
|
|
|
|
peer_svc = nan_find_peer_svc(own_svc_id, 0, peer_mac);
|
|
if (peer_svc) {
|
|
struct ndl_info *p_ndl;
|
|
peer_info->peer_svc_id = peer_svc->svc_id;
|
|
peer_info->own_svc_id = peer_svc->own_svc_id;
|
|
peer_info->peer_svc_type = peer_svc->type;
|
|
MACADDR_COPY(peer_info->peer_nmi, peer_mac);
|
|
p_ndl = nan_find_ndl(0, peer_mac);
|
|
if (p_ndl) {
|
|
peer_info->ndp_id = p_ndl->ndp_id;
|
|
MACADDR_COPY(peer_info->peer_ndi, p_ndl->peer_ndi);
|
|
} else {
|
|
peer_info->ndp_id = 0;
|
|
MACADDR_COPY(peer_info->peer_ndi, null_mac);
|
|
}
|
|
return ESP_OK;
|
|
} else {
|
|
ESP_LOGD(TAG, "No record found for Peer "MACSTR, MAC2STR(peer_mac));
|
|
return ESP_FAIL;
|
|
}
|
|
}
|