mbed-os/source/Security/kmp/kmp_eapol_pdu_if.c

165 lines
4.6 KiB
C

/*
* Copyright (c) 2016-2019, Arm Limited 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 "6LoWPAN/ws/ws_config.h"
#include "NWK_INTERFACE/Include/protocol.h"
#include "Security/kmp/kmp_addr.h"
#include "Security/kmp/kmp_api.h"
#include "Security/kmp/kmp_eapol_pdu_if.h"
#include "6LoWPAN/MAC/mpx_api.h"
#include "6LoWPAN/ws/ws_eapol_pdu.h"
#ifdef HAVE_WS
#define TRACE_GROUP "kmep"
#define EAPOL_PDU_IF_HEADER_SIZE 1
typedef struct {
uint8_t kmp_id; /**< Kmp id */
uint8_t kmp_data; /**< Kmp data e.g. eapol frame */
} eapol_kmp_pdu_t;
typedef struct {
kmp_service_t *kmp_service; /**< KMP service */
protocol_interface_info_entry_t *interface_ptr; /**< Interface pointer */
ns_list_link_t link; /**< Link */
} kmp_eapol_pdu_if_t;
static NS_LIST_DEFINE(kmp_eapol_pdu_if_list, kmp_eapol_pdu_if_t, link);
static int8_t kmp_eapol_pdu_if_send(kmp_service_t *service, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size);
int8_t kmp_eapol_pdu_if_register(kmp_service_t *service, protocol_interface_info_entry_t *interface_ptr)
{
if (!service || !interface_ptr) {
return -1;
}
ns_list_foreach(kmp_eapol_pdu_if_t, entry, &kmp_eapol_pdu_if_list) {
if (entry->kmp_service == service || entry->interface_ptr == interface_ptr) {
return -1;
}
}
kmp_eapol_pdu_if_t *eapol_pdu_if = ns_dyn_mem_alloc(sizeof(kmp_eapol_pdu_if_t));
if (!eapol_pdu_if) {
return -1;
}
eapol_pdu_if->kmp_service = service;
eapol_pdu_if->interface_ptr = interface_ptr;
if (kmp_service_msg_if_register(service, kmp_eapol_pdu_if_send, EAPOL_PDU_IF_HEADER_SIZE) < 0) {
ns_dyn_mem_free(eapol_pdu_if);
return -1;
}
ns_list_add_to_end(&kmp_eapol_pdu_if_list, eapol_pdu_if);
return 0;
}
int8_t kmp_eapol_pdu_if_unregister(kmp_service_t *service)
{
if (!service) {
return -1;
}
ns_list_foreach_safe(kmp_eapol_pdu_if_t, entry, &kmp_eapol_pdu_if_list) {
if (entry->kmp_service == service) {
ns_list_remove(&kmp_eapol_pdu_if_list, entry);
ns_dyn_mem_free(entry);
kmp_service_msg_if_register(service, NULL, 0);
}
}
return 0;
}
static int8_t kmp_eapol_pdu_if_send(kmp_service_t *service, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size)
{
if (!service || !addr || !pdu) {
return -1;
}
protocol_interface_info_entry_t *interface_ptr = NULL;
ns_list_foreach(kmp_eapol_pdu_if_t, entry, &kmp_eapol_pdu_if_list) {
if (entry->kmp_service == service) {
interface_ptr = entry->interface_ptr;
break;
}
}
if (!interface_ptr) {
return -1;
}
const uint8_t *eui_64 = kmp_address_eui_64_get(addr);
if (!eui_64) {
return -1;
}
uint8_t *ptr = pdu;
*ptr = kmp_id;
int8_t ret = ws_eapol_pdu_send_to_mpx(interface_ptr, eui_64, pdu, size, pdu);
return ret;
}
int8_t kmp_eapol_pdu_if_receive(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64, void *pdu, uint16_t size)
{
kmp_service_t *service = NULL;
ns_list_foreach(kmp_eapol_pdu_if_t, entry, &kmp_eapol_pdu_if_list) {
if (entry->interface_ptr == interface_ptr) {
service = entry->kmp_service;
break;
}
}
if (!service) {
return -1;
}
kmp_addr_t addr;
kmp_address_init(KMP_ADDR_EUI_64, &addr, eui_64);
eapol_kmp_pdu_t *eapol_kmp_pdu = pdu;
uint16_t data_pdu_size = size - sizeof(uint8_t);
void *data_pdu = &eapol_kmp_pdu->kmp_data;
kmp_type_e type = kmp_api_type_from_id_get(eapol_kmp_pdu->kmp_id);
if (type == INVALID_KMP_TYPE) {
return -1;
}
int8_t ret = kmp_service_msg_if_receive(service, type, &addr, data_pdu, data_pdu_size);
return ret;
}
#endif /* HAVE_WS */