mbed-os/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_eapol_pdu.c

355 lines
11 KiB
C

/*
* Copyright (c) 2018-2021, Pelion and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "nsconfig.h"
#include <string.h>
#include "ns_types.h"
#include "ns_list.h"
#include "ns_trace.h"
#include "nsdynmemLIB.h"
#include "fhss_config.h"
#include "NWK_INTERFACE/Include/protocol.h"
#include "mac_api.h"
#include "mac_mcps.h"
#include "Common_Protocols/ipv6_constants.h"
#include "socket_api.h"
#include "6LoWPAN/MAC/mac_helper.h"
#include "6LoWPAN/MAC/mpx_api.h"
#include "6LoWPAN/ws/ws_config.h"
#include "6LoWPAN/ws/ws_eapol_pdu.h"
#include "6LoWPAN/ws/ws_llc.h"
#ifdef HAVE_WS
#define TRACE_GROUP "wsep"
typedef struct {
void *data_ptr;
void *buffer;
ws_eapol_pdu_tx_status *tx_status;
uint8_t tx_identifier;
uint8_t handle;
ns_list_link_t link;
} eapol_pdu_msdu_t;
typedef NS_LIST_HEAD(eapol_pdu_msdu_t, link) eapol_pdu_msdu_list_t;
typedef struct {
uint8_t priority;
bool filter_requsted: 1;
ws_eapol_pdu_address_check *addr_check;
ws_eapol_pdu_receive *receive;
ns_list_link_t link;
} eapol_pdu_recv_cb_t;
typedef NS_LIST_HEAD(eapol_pdu_recv_cb_t, link) eapol_pdu_recv_cb_list_t;
typedef struct {
eapol_pdu_recv_cb_list_t recv_cb_list; /**< List of receive callbacks */
eapol_pdu_msdu_list_t msdu_list; /**< MSDU list */
ws_eapol_pdu_receive *receive; /**< data receive callback */
protocol_interface_info_entry_t *interface_ptr; /**< Interface pointer */
mpx_api_t *mpx_api; /**< MPX api */
uint16_t mpx_user_id; /**< MPX user identifier */
uint8_t msdu_handle; /**< MSDU handle */
ns_list_link_t link; /**< Link */
} eapol_pdu_data_t;
static void ws_eapol_pdu_mpx_data_confirm(const mpx_api_t *api, const struct mcps_data_conf_s *data);
static void ws_eapol_pdu_mpx_data_indication(const mpx_api_t *api, const struct mcps_data_ind_s *data);
static void ws_eapol_pdu_data_request_primitiv_set(mcps_data_req_t *dataReq, protocol_interface_info_entry_t *cur);
static eapol_pdu_data_t *ws_eapol_pdu_data_get(protocol_interface_info_entry_t *interface_ptr);
static NS_LIST_DEFINE(eapol_pdu_data_list, eapol_pdu_data_t, link);
int8_t ws_eapol_pdu_init(protocol_interface_info_entry_t *interface_ptr)
{
if (!interface_ptr) {
return -1;
}
if (ws_eapol_pdu_data_get(interface_ptr) != NULL) {
return 0;
}
eapol_pdu_data_t *eapol_pdu_data = ns_dyn_mem_alloc(sizeof(eapol_pdu_data_t));
if (!eapol_pdu_data) {
return -1;
}
eapol_pdu_data->interface_ptr = interface_ptr;
ns_list_init(&eapol_pdu_data->recv_cb_list);
ns_list_init(&eapol_pdu_data->msdu_list);
eapol_pdu_data->msdu_handle = 0;
ns_list_add_to_end(&eapol_pdu_data_list, eapol_pdu_data);
return 0;
}
int8_t ws_eapol_pdu_delete(protocol_interface_info_entry_t *interface_ptr)
{
if (!interface_ptr) {
return -1;
}
eapol_pdu_data_t *eapol_pdu_data = ws_eapol_pdu_data_get(interface_ptr);
if (!eapol_pdu_data) {
return -1;
}
ns_list_foreach_safe(eapol_pdu_recv_cb_t, cb_entry, &eapol_pdu_data->recv_cb_list) {
ns_list_remove(&eapol_pdu_data->recv_cb_list, cb_entry);
ns_dyn_mem_free(cb_entry);
}
ns_list_foreach_safe(eapol_pdu_msdu_t, msdu_entry, &eapol_pdu_data->msdu_list) {
ns_list_remove(&eapol_pdu_data->msdu_list, msdu_entry);
ns_dyn_mem_free(msdu_entry);
}
ns_list_remove(&eapol_pdu_data_list, eapol_pdu_data);
ns_dyn_mem_free(eapol_pdu_data);
return 0;
}
int8_t ws_eapol_pdu_cb_register(protocol_interface_info_entry_t *interface_ptr, const eapol_pdu_recv_cb_data_t *cb_data)
{
if (!interface_ptr || !cb_data) {
return -1;
}
eapol_pdu_data_t *eapol_pdu_data = ws_eapol_pdu_data_get(interface_ptr);
if (!eapol_pdu_data) {
return -1;
}
eapol_pdu_recv_cb_t *new_cb = ns_dyn_mem_alloc(sizeof(eapol_pdu_recv_cb_t));
if (!new_cb) {
return -1;
}
new_cb->priority = cb_data->priority;
new_cb->addr_check = cb_data->addr_check;
new_cb->receive = cb_data->receive;
new_cb->filter_requsted = cb_data->filter_requsted;
ns_list_foreach(eapol_pdu_recv_cb_t, entry, &eapol_pdu_data->recv_cb_list) {
if (new_cb->priority <= entry->priority) {
ns_list_add_before(&eapol_pdu_data->recv_cb_list, entry, new_cb);
return 0;
}
}
ns_list_add_to_end(&eapol_pdu_data->recv_cb_list, new_cb);
return 0;
}
int8_t ws_eapol_pdu_cb_unregister(protocol_interface_info_entry_t *interface_ptr, const eapol_pdu_recv_cb_data_t *cb_data)
{
if (!interface_ptr || !cb_data) {
return -1;
}
eapol_pdu_data_t *eapol_pdu_data = ws_eapol_pdu_data_get(interface_ptr);
if (!eapol_pdu_data) {
return -1;
}
ns_list_foreach_safe(eapol_pdu_recv_cb_t, entry, &eapol_pdu_data->recv_cb_list) {
if (entry->receive == cb_data->receive) {
ns_list_remove(&eapol_pdu_data->recv_cb_list, entry);
ns_dyn_mem_free(entry);
return 0;
}
}
return -1;
}
int8_t ws_eapol_pdu_send_to_mpx(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64, void *data, uint16_t size, void *buffer, ws_eapol_pdu_tx_status *tx_status, uint8_t tx_identifier)
{
eapol_pdu_data_t *eapol_pdu_data = ws_eapol_pdu_data_get(interface_ptr);
if (!eapol_pdu_data) {
return -1;
}
mcps_data_req_t data_request;
ws_eapol_pdu_data_request_primitiv_set(&data_request, eapol_pdu_data->interface_ptr);
eapol_pdu_msdu_t *msdu_entry = ns_dyn_mem_temporary_alloc(sizeof(eapol_pdu_msdu_t));
if (!msdu_entry) {
return -1;
}
msdu_entry->data_ptr = data;
msdu_entry->buffer = buffer;
msdu_entry->handle = eapol_pdu_data->msdu_handle;
msdu_entry->tx_status = tx_status;
msdu_entry->tx_identifier = tx_identifier;
ns_list_add_to_start(&eapol_pdu_data->msdu_list, msdu_entry);
memcpy(data_request.DstAddr, eui_64, 8);
data_request.msdu = data;
data_request.msduLength = size;
data_request.msduHandle = eapol_pdu_data->msdu_handle;
eapol_pdu_data->msdu_handle++;
eapol_pdu_data->mpx_api->mpx_data_request(eapol_pdu_data->mpx_api, &data_request, eapol_pdu_data->mpx_user_id, MAC_DATA_NORMAL_PRIORITY);
return 0;
}
int8_t ws_eapol_pdu_mpx_eui64_purge(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64)
{
eapol_pdu_data_t *eapol_pdu_data = ws_eapol_pdu_data_get(interface_ptr);
if (!eapol_pdu_data) {
return -1;
}
eapol_pdu_data->mpx_api->mpx_eui64_purge(eapol_pdu_data->mpx_api, eui_64);
return 0;
}
static void ws_eapol_pdu_data_request_primitiv_set(mcps_data_req_t *dataReq, protocol_interface_info_entry_t *cur)
{
memset(dataReq, 0, sizeof(mcps_data_req_t));
dataReq->InDirectTx = false;
dataReq->TxAckReq = true;
dataReq->SrcAddrMode = ADDR_802_15_4_LONG;
dataReq->DstAddrMode = ADDR_802_15_4_LONG;
dataReq->DstPANId = mac_helper_panid_get(cur);
}
int8_t ws_eapol_pdu_mpx_register(protocol_interface_info_entry_t *interface_ptr, struct mpx_api_s *mpx_api, uint16_t mpx_user_id)
{
if (!interface_ptr) {
return -1;
}
eapol_pdu_data_t *eapol_pdu_data = ws_eapol_pdu_data_get(interface_ptr);
if (!eapol_pdu_data) {
return -1;
}
if (!mpx_api && eapol_pdu_data->mpx_api) {
//Disable Data Callbacks from MPX Class
eapol_pdu_data->mpx_api->mpx_user_registration(eapol_pdu_data->mpx_api, NULL, NULL, eapol_pdu_data->mpx_user_id);
}
eapol_pdu_data->mpx_api = mpx_api;
eapol_pdu_data->mpx_user_id = mpx_user_id;
if (eapol_pdu_data->mpx_api) {
eapol_pdu_data->mpx_api->mpx_user_registration(eapol_pdu_data->mpx_api, ws_eapol_pdu_mpx_data_confirm, ws_eapol_pdu_mpx_data_indication, eapol_pdu_data->mpx_user_id);
}
return 0;
}
static void ws_eapol_pdu_mpx_data_confirm(const mpx_api_t *api, const struct mcps_data_conf_s *data)
{
eapol_pdu_data_t *eapol_pdu_data = NULL;
ns_list_foreach(eapol_pdu_data_t, entry, &eapol_pdu_data_list) {
if (entry->mpx_api == api) {
eapol_pdu_data = entry;
break;
}
}
if (!eapol_pdu_data) {
return;
}
ns_list_foreach(eapol_pdu_msdu_t, msdu, &eapol_pdu_data->msdu_list) {
if (msdu->handle == data->msduHandle) {
if (msdu->tx_status) {
eapol_pdu_tx_status_e status = EAPOL_PDU_TX_ERR_UNSPEC;
if (data->status == MLME_SUCCESS) {
status = EAPOL_PDU_TX_OK;
} else if (data->status == MLME_TX_NO_ACK) {
status = EAPOL_PDU_TX_ERR_TX_NO_ACK;
tr_error("EAPOL TX err no ack");
} else {
tr_error("EAPOL TX err");
}
msdu->tx_status(eapol_pdu_data->interface_ptr, status, msdu->tx_identifier);
}
ns_dyn_mem_free(msdu->buffer);
ns_list_remove(&eapol_pdu_data->msdu_list, msdu);
ns_dyn_mem_free(msdu);
return;
}
}
}
static void ws_eapol_pdu_mpx_data_indication(const mpx_api_t *api, const struct mcps_data_ind_s *data)
{
if (!data || !data->msduLength || !data->msdu_ptr) {
return;
}
eapol_pdu_data_t *eapol_pdu_data = NULL;
ns_list_foreach(eapol_pdu_data_t, entry, &eapol_pdu_data_list) {
if (entry->mpx_api == api) {
eapol_pdu_data = entry;
break;
}
}
if (!eapol_pdu_data) {
return;
}
ns_list_foreach(eapol_pdu_recv_cb_t, entry, &eapol_pdu_data->recv_cb_list) {
if (entry->addr_check(eapol_pdu_data->interface_ptr, data->SrcAddr) >= 0) {
if (entry->filter_requsted && !ws_llc_eapol_relay_forward_filter(eapol_pdu_data->interface_ptr, data->SrcAddr, data->DSN, data->timestamp)) {
tr_info("EAPOL relay filter drop");
return;
}
entry->receive(eapol_pdu_data->interface_ptr, data->SrcAddr, data->msdu_ptr, data->msduLength);
break;
}
}
}
static eapol_pdu_data_t *ws_eapol_pdu_data_get(protocol_interface_info_entry_t *interface_ptr)
{
eapol_pdu_data_t *eapol_pdu_data = NULL;
ns_list_foreach(eapol_pdu_data_t, entry, &eapol_pdu_data_list) {
if (entry->interface_ptr == interface_ptr) {
eapol_pdu_data = entry;
break;
}
}
return eapol_pdu_data;
}
#endif /* HAVE_WS */