4087 lines
125 KiB
C
4087 lines
125 KiB
C
/* ipmacsec_secy_mgmt.c - MACsec SecY Management implementation */
|
|
|
|
/*
|
|
* Copyright (c) 2010 Wind River Systems, Inc.
|
|
*
|
|
* The right to copy, distribute, modify, or otherwise make use
|
|
* of this software may be licensed only pursuant to the terms
|
|
* of an applicable Wind River license agreement.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
modification history
|
|
--------------------
|
|
01a,24feb10,mry Created
|
|
*/
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 1 DESCRIPTION
|
|
****************************************************************************
|
|
*/
|
|
/*
|
|
* Implements the MACsec SecY management related functions for SC/SA/SAK
|
|
* creation, lookup and deletion. Also implements netlink based SecY command
|
|
* handling and notification generation, and related management functions.
|
|
*/
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 2 INCLUDE FILES
|
|
****************************************************************************
|
|
*/
|
|
|
|
#define IPCOM_USE_CLIB_PROTO
|
|
#include <ipcom_type.h>
|
|
#include <ipcom_cstyle.h>
|
|
#include <ipcom_clib.h>
|
|
#include <ipcom_time.h>
|
|
#include <ipcom_err.h>
|
|
#include <ipcom_sock.h>
|
|
#include <ipcom_syslog.h>
|
|
#include <ipcom_sysvar.h>
|
|
#include <ipcom_errno.h>
|
|
#include <ipcom_err.h>
|
|
#include <ipcom_os.h>
|
|
|
|
#include "ipmacsec_debug.h"
|
|
#include "ipmacsec_sysvar.h"
|
|
#include "ipmacsec_secy_mgmt.h"
|
|
#include "ipmacsec_h.h"
|
|
#include "ipmacsec.h"
|
|
#include "ipmacsec_netlink.h"
|
|
#include "ipmacsec_crypto_if.h"
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 3 CONFIGURATION
|
|
****************************************************************************
|
|
*/
|
|
#include "ipmacsec_config.h"
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 4 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
/* Time bound (in ms) in which a receiver can accept interleaved RX SAs on a particular SC */
|
|
#define IPMACSEC_RX_SA_INTERLEAVE_PERIOD 500
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 5 TYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/* For now, the Keydb is implemented as a simple array instead of a hash.
|
|
* Due to the limited number of supported SAs/SCs and thus small Keydb size,
|
|
* the lookup/insert is not costly.
|
|
*/
|
|
typedef struct Ipmacsec_keydb_struct {
|
|
Ipmacsec_secy_key *key[IPMACSEC_SECY_KEYDB_SIZE]; /* Array of key pointers */
|
|
int iterator; /* used for iterative retrieval. value of -1 ==> not initialized. */
|
|
} Ipmacsec_keydb;
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 6 EXTERN PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 7 LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
IP_STATIC int ipmacsec_secy_delete_sa(Ipnet_secy *secy, Ipmacsec_secy_sa *sa, Ipmacsec_dir dir);
|
|
IPMACSEC_PRIVATE int ipmacsec_secy_update_sa_nextPN(Ipnet_secy *secy, Ipmacsec_secy_sa *sa, Ip_u32 nextPN);
|
|
IPMACSEC_PRIVATE int ipmacsec_secy_update_rx_sa_PNs(Ipnet_secy *secy, Ipmacsec_secy_sa *sa, Ip_u32 rxPN);
|
|
IPMACSEC_PRIVATE int ipmacsec_secy_handle_nlcmd(Ipnet_secy *secy, struct Ip_nlmsghdr *nlmsg,
|
|
Ip_bool non_blocking, Ipmacsec_buffer *reply, Ip_pid_t src_pid);
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 8 INLINE FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/* Timer Utility functions */
|
|
IP_INLINE void ipmacsec_secy_set_current_time(Ipnet_secy *secy, Ipmacsec_time *tm) {
|
|
IPCOM_UNUSED_ARG(secy);
|
|
ipcom_time(tm);
|
|
}
|
|
|
|
IP_INLINE void ipmacsec_secy_copy_time(Ipnet_secy *secy, Ipmacsec_time *toTime, Ipmacsec_time *fromTime) {
|
|
IPCOM_UNUSED_ARG(secy);
|
|
*toTime = *fromTime;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_fill_sc_info
|
|
*===========================================================================
|
|
* Description: Fill in the SC Info structure for the specified SC
|
|
* Parameters:
|
|
* Returns: 0 upon success, <0 upon error
|
|
*
|
|
*/
|
|
IP_INLINE int
|
|
ipmacsec_secy_fill_sc_info(Ipnet_secy *secy, Ipmacsec_secy_sc *sc, Ipmacsec_secy_sc_info *sc_info) {
|
|
ip_assert(secy);
|
|
ip_assert(sc);
|
|
ip_assert(sc_info);
|
|
|
|
ipcom_memset(sc_info, 0, sizeof(Ipmacsec_secy_sc_info));
|
|
if (sc->dir == IPMACSEC_TX) {
|
|
sc_info->status.tx.transmitting = sc->oper.transmitting;
|
|
sc_info->status.tx.encodingSA = (Ip_u8)sc->encodingSA;
|
|
sc_info->status.tx.encipheringSA = (Ip_u8)sc->encipheringSA;
|
|
} else if (sc->dir == IPMACSEC_RX) {
|
|
sc_info->status.rx.receiving = sc->oper.receiving;
|
|
} else {
|
|
return -1;
|
|
}
|
|
IPMACSEC_COPY_SCI(sc_info->sci, sc->sci);
|
|
sc_info->dir = sc->dir;
|
|
ipmacsec_secy_copy_time(secy, &sc_info->createdTime, &sc->createdTime);
|
|
ipmacsec_secy_copy_time(secy, &sc_info->startedTime, &sc->startedTime);
|
|
ipmacsec_secy_copy_time(secy, &sc_info->stoppedTime, &sc->stoppedTime);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_fill_sa_descriptor
|
|
*===========================================================================
|
|
* Description: Fill in the SA descriptor structure for the specified SA
|
|
* Parameters:
|
|
* Returns: 0 upon success, <0 upon error
|
|
*
|
|
*/
|
|
IP_INLINE int
|
|
ipmacsec_secy_fill_sa_descriptor(Ipnet_secy *secy, Ipmacsec_secy_sa *sa, Ipmacsec_secy_sa_descriptor *sa_desc) {
|
|
IPCOM_UNUSED_ARG(secy);
|
|
|
|
ip_assert(secy);
|
|
ip_assert(sa);
|
|
ip_assert(sa->sc);
|
|
ip_assert(sa_desc);
|
|
|
|
ipcom_memset(sa_desc, 0, sizeof(Ipmacsec_secy_sa_descriptor));
|
|
sa_desc->an = (Ip_u8)sa->an;
|
|
if (sa->key)
|
|
sa_desc->key_id = sa->key->key_id;
|
|
sa_desc->ref = sa->ref;
|
|
sa_desc->dir = sa->sc->dir;
|
|
IPMACSEC_COPY_SCI(sa_desc->sci, sa->sc->sci);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_fill_sa_info
|
|
*===========================================================================
|
|
* Description: Fill in the SA Info structure for the specified SA
|
|
* Parameters:
|
|
* Returns: 0 upon success, <0 upon error
|
|
*
|
|
*/
|
|
IP_INLINE int
|
|
ipmacsec_secy_fill_sa_info(Ipnet_secy *secy, Ipmacsec_secy_sa *sa, Ipmacsec_secy_sa_info *sa_info) {
|
|
ip_assert(secy);
|
|
ip_assert(sa);
|
|
ip_assert(sa->sc);
|
|
ip_assert(sa_info);
|
|
|
|
ipcom_memset(sa_info, 0, sizeof(Ipmacsec_secy_sa_info));
|
|
if (sa->sc->dir == IPMACSEC_TX) {
|
|
sa_info->config.tx.confidentiality =
|
|
(sa->confidentiality ? IPMACSEC_CONFIDENTIALITY_ON : IPMACSEC_CONFIDENTIALITY_OFF);
|
|
sa_info->config.tx.nextPN = sa->nextPN;
|
|
} else if (sa->sc->dir == IPMACSEC_RX) {
|
|
sa_info->config.rx.lowestPN = sa->lowestPN;
|
|
sa_info->config.rx.nextPN = sa->nextPN;
|
|
} else {
|
|
return -1;
|
|
}
|
|
sa_info->inUse = sa->inUse;
|
|
ipmacsec_secy_copy_time(secy, &sa_info->createdTime, &sa->createdTime);
|
|
ipmacsec_secy_copy_time(secy, &sa_info->startedTime, &sa->startedTime);
|
|
ipmacsec_secy_copy_time(secy, &sa_info->stoppedTime, &sa->stoppedTime);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_retrieve_key_info
|
|
*===========================================================================
|
|
* Description: Retrieve information for the specified key and update the
|
|
* key descriptor accordingly.
|
|
* Parameters:
|
|
* Returns: Pointer to key upon success
|
|
*
|
|
*/
|
|
IP_INLINE Ipmacsec_secy_key *
|
|
ipmacsec_secy_retrieve_key_info(Ipnet_secy *secy, Ipmacsec_secy_key *key, Ipmacsec_secy_key_descriptor *key_desc) {
|
|
IPCOM_UNUSED_ARG(secy);
|
|
|
|
ip_assert(secy);
|
|
ip_assert(key);
|
|
ip_assert(key_desc);
|
|
ip_assert(key->sak.buf && key->sak.num_octets);
|
|
|
|
ipcom_memset(key_desc, 0, sizeof(Ipmacsec_secy_key_descriptor));
|
|
key_desc->key_id.val = key->key_id.val;
|
|
key_desc->created_time = key->createdTime;
|
|
key_desc->inUse = key->inUse;
|
|
if (key->receives)
|
|
key_desc->key_type |= IPMACSEC_KEYTYPE_RECEIVE;
|
|
if (key->transmits)
|
|
key_desc->key_type |= IPMACSEC_KEYTYPE_TRANSMIT;
|
|
key_desc->key_size = key->sak.num_octets;
|
|
return key;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_sc_create_notify
|
|
*===========================================================================
|
|
* Description: Send notification of SC creation
|
|
* Parameters:
|
|
* Returns: 0 upon success, <0 upon error
|
|
*
|
|
*/
|
|
IP_INLINE int
|
|
ipmacsec_secy_sc_create_notify(Ipnet_secy *secy, Ipmacsec_secy_sc *sc) {
|
|
Ipmacsec_secy_sc_info sc_info;
|
|
|
|
ip_assert(secy);
|
|
ip_assert(sc);
|
|
|
|
if (secy->config.info_notify) {
|
|
(void)ipmacsec_secy_fill_sc_info(secy, sc, &sc_info);
|
|
return ipmacsec_secy_info_notify(secy, IPMACSEC_INFO_SECY_SC_CREATED, &sc_info, sizeof(sc_info));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_sc_delete_notify
|
|
*===========================================================================
|
|
* Description: Send notification of SC deletion
|
|
* Parameters:
|
|
* Returns: 0 upon success, <0 upon error
|
|
*
|
|
*/
|
|
IP_INLINE int
|
|
ipmacsec_secy_sc_delete_notify(Ipnet_secy *secy, Ipmacsec_secy_sc *sc) {
|
|
ip_assert(secy);
|
|
ip_assert(sc);
|
|
|
|
if (secy->config.info_notify) {
|
|
return ipmacsec_secy_info_notify(secy, IPMACSEC_INFO_SECY_SC_DELETED, &sc->sci, sizeof(sc->sci));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_sc_change_notify
|
|
*===========================================================================
|
|
* Description: Send notification of SC status change
|
|
* Parameters:
|
|
* Returns: 0 upon success, <0 upon error
|
|
*
|
|
*/
|
|
IP_INLINE int
|
|
ipmacsec_secy_sc_change_notify(Ipnet_secy *secy, Ipmacsec_secy_sc *sc) {
|
|
Ipmacsec_secy_sc_info sc_info;
|
|
|
|
ip_assert(secy);
|
|
ip_assert(sc);
|
|
|
|
if (secy->config.info_notify) {
|
|
(void)ipmacsec_secy_fill_sc_info(secy, sc, &sc_info);
|
|
return ipmacsec_secy_info_notify(secy, IPMACSEC_INFO_SECY_SC_STATUS_CHANGED, &sc_info, sizeof(sc_info));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_sa_create_notify
|
|
*===========================================================================
|
|
* Description: Send notification of SA creation
|
|
* Parameters:
|
|
* Returns: 0 upon success, <0 upon error
|
|
*
|
|
*/
|
|
IP_INLINE int
|
|
ipmacsec_secy_sa_create_notify(Ipnet_secy *secy, Ipmacsec_secy_sa *sa) {
|
|
struct {
|
|
Ipmacsec_secy_sa_descriptor sa_desc;
|
|
Ipmacsec_secy_sa_info sa_info;
|
|
} param;
|
|
|
|
ip_assert(secy);
|
|
ip_assert(sa);
|
|
|
|
if (secy->config.info_notify) {
|
|
(void)ipmacsec_secy_fill_sa_descriptor(secy, sa, ¶m.sa_desc);
|
|
(void)ipmacsec_secy_fill_sa_info(secy, sa, ¶m.sa_info);
|
|
return ipmacsec_secy_info_notify(secy, IPMACSEC_INFO_SECY_SA_CREATED, ¶m, sizeof(param));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_sa_delete_notify
|
|
*===========================================================================
|
|
* Description: Send notification of SA deletion
|
|
* Parameters:
|
|
* Returns: 0 upon success, <0 upon error
|
|
*
|
|
*/
|
|
IP_INLINE int
|
|
ipmacsec_secy_sa_delete_notify(Ipnet_secy *secy, Ipmacsec_secy_sa *sa) {
|
|
Ipmacsec_secy_sa_descriptor sa_desc;
|
|
|
|
ip_assert(secy);
|
|
ip_assert(sa);
|
|
|
|
if (secy->config.info_notify) {
|
|
(void)ipmacsec_secy_fill_sa_descriptor(secy, sa, &sa_desc);
|
|
return ipmacsec_secy_info_notify(secy, IPMACSEC_INFO_SECY_SA_DELETED, &sa_desc, sizeof(sa_desc));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_sa_change_notify
|
|
*===========================================================================
|
|
* Description: Send notification of SA status change
|
|
* Parameters:
|
|
* Returns: 0 upon success, <0 upon error
|
|
*
|
|
*/
|
|
IP_INLINE int
|
|
ipmacsec_secy_sa_change_notify(Ipnet_secy *secy, Ipmacsec_secy_sa *sa) {
|
|
struct {
|
|
Ipmacsec_secy_sa_descriptor sa_desc;
|
|
Ipmacsec_secy_sa_info sa_info;
|
|
Ipmacsec_secy_sa_ctrl sa_ctrl;
|
|
} param;
|
|
|
|
ip_assert(secy);
|
|
ip_assert(sa);
|
|
|
|
if (secy->config.info_notify) {
|
|
(void)ipmacsec_secy_fill_sa_descriptor(secy, sa, ¶m.sa_desc);
|
|
(void)ipmacsec_secy_fill_sa_info(secy, sa, ¶m.sa_info);
|
|
ipcom_memcpy(¶m.sa_ctrl, &sa->ctrl, sizeof(Ipmacsec_secy_sa_ctrl));
|
|
return ipmacsec_secy_info_notify(secy, IPMACSEC_INFO_SECY_SA_STATUS_CHANGED, ¶m, sizeof(param));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_key_install_notify
|
|
*===========================================================================
|
|
* Description: Send notification of key installation
|
|
* Parameters:
|
|
* Returns: 0 upon success, <0 upon error
|
|
*
|
|
*/
|
|
IP_INLINE int
|
|
ipmacsec_secy_key_install_notify(Ipnet_secy *secy, Ipmacsec_secy_key *key) {
|
|
Ipmacsec_secy_key_descriptor key_desc;
|
|
|
|
ip_assert(secy);
|
|
ip_assert(key);
|
|
|
|
if (secy->config.info_notify) {
|
|
(void)ipmacsec_secy_retrieve_key_info(secy, key, &key_desc);
|
|
return ipmacsec_secy_info_notify(secy, IPMACSEC_INFO_SECY_KEY_INSTALLED, &key_desc, sizeof(key_desc));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_key_remove_notify
|
|
*===========================================================================
|
|
* Description: Send notification of key removal
|
|
* Parameters:
|
|
* Returns: 0 upon success, <0 upon error
|
|
*
|
|
*/
|
|
IP_INLINE int
|
|
ipmacsec_secy_key_remove_notify(Ipnet_secy *secy, Ipmacsec_secy_key *key) {
|
|
Ipmacsec_secy_key_descriptor key_desc;
|
|
|
|
ip_assert(secy);
|
|
ip_assert(key);
|
|
|
|
if (secy->config.info_notify) {
|
|
(void)ipmacsec_secy_retrieve_key_info(secy, key, &key_desc);
|
|
return ipmacsec_secy_info_notify(secy, IPMACSEC_INFO_SECY_KEY_REMOVED, &key_desc, sizeof(key_desc));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 9 STATIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_keydb_find_key
|
|
*===========================================================================
|
|
* Description: Find a key with the specified key_id
|
|
* (Later retrieve from keydb hash table - hashkey = key_id)
|
|
* Parameters:
|
|
* Returns: Pointer to retrieved key,
|
|
* or IP_NULL upon failure, or if key is not found.
|
|
*
|
|
*/
|
|
IP_STATIC Ipmacsec_secy_key *
|
|
ipmacsec_secy_keydb_find_key(Ipnet_secy *secy, Ipmacsec_secy_key_id *key_id) {
|
|
Ip_u32 i;
|
|
Ipmacsec_secy_key *k = IP_NULL;
|
|
|
|
ip_assert(secy);
|
|
ip_assert(key_id);
|
|
|
|
if (secy->priv.keydb == IP_NULL) {
|
|
IPCOM_LOG1(CRIT, "IPMACSEC-KEYDB: Failed to retrieve key from keydb for interface %s (keydb not initialized)",
|
|
secy->netif->ipcom.name);
|
|
return IP_NULL;
|
|
}
|
|
for (i=0; i < IPMACSEC_SECY_KEYDB_SIZE; i++) {
|
|
k = secy->priv.keydb->key[i];
|
|
if (k == IP_NULL)
|
|
continue;
|
|
if (k->key_id.val == key_id->val) {
|
|
return k;
|
|
}
|
|
}
|
|
return IP_NULL;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_keydb_add_key
|
|
*===========================================================================
|
|
* Description: Add the specified key.
|
|
* Adding fails if matching key already exists.
|
|
* (Later add to keydb hash table - hashkey = key_id)
|
|
* Parameters:
|
|
* Returns: 0 upon success, <0 upon error
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipmacsec_secy_keydb_add_key(Ipnet_secy *secy, Ipmacsec_secy_key *key) {
|
|
Ip_u32 i;
|
|
Ipmacsec_secy_key *k = IP_NULL;
|
|
|
|
ip_assert(secy);
|
|
ip_assert(key);
|
|
|
|
if (secy->priv.keydb == IP_NULL) {
|
|
IPCOM_LOG1(CRIT, "IPMACSEC-KEYDB: Failed to add key to keydb for interface %s (keydb not initialized)",
|
|
secy->netif->ipcom.name);
|
|
return -1;
|
|
}
|
|
if (ipmacsec_secy_keydb_find_key(secy, &key->key_id) != IP_NULL) {
|
|
IPCOM_LOG1(ERR, "IPMACSEC-KEYDB: Failed to add key to keydb for interface %s (already exists)",
|
|
secy->netif->ipcom.name);
|
|
return -1;
|
|
}
|
|
|
|
for (i=0; i < IPMACSEC_SECY_KEYDB_SIZE; i++) {
|
|
k = secy->priv.keydb->key[i];
|
|
if (k == IP_NULL) {
|
|
k = secy->priv.keydb->key[i] = key;
|
|
break;
|
|
}
|
|
}
|
|
if (k != key) {
|
|
IPCOM_LOG2(CRIT, "IPMACSEC-KEYDB: Failed to add key (key_id=0x%llx) to keydb for interface %s (keydb full)",
|
|
key->key_id.val, secy->netif->ipcom.name);
|
|
return -1;
|
|
}
|
|
(void)ipmacsec_secy_key_install_notify(secy, key);
|
|
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG5(DEBUG, "IPMACSEC-KEYDB: Successfully installed key in keydb or interface %s "
|
|
"(key_id=0x%llx, transmits=%s, receives=%s, size=%u)",
|
|
secy->netif->ipcom.name, key->key_id.val, IPMACSEC_BOOL_STRING(key->transmits),
|
|
IPMACSEC_BOOL_STRING(key->receives), key->sak.num_octets);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_keydb_remove_key
|
|
*===========================================================================
|
|
* Description: Remove the specified key
|
|
* (Later remove from hash table - hashkey = key_id))
|
|
* Parameters:
|
|
* Returns: 0 upon success, <0 upon error.
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipmacsec_secy_keydb_remove_key(Ipnet_secy *secy, Ipmacsec_secy_key *key) {
|
|
Ip_u32 i;
|
|
Ipmacsec_secy_key *k = IP_NULL;
|
|
|
|
ip_assert(secy);
|
|
ip_assert(key);
|
|
|
|
if (secy->priv.keydb == IP_NULL) {
|
|
IPCOM_LOG1(CRIT, "IPMACSEC-KEYDB: Failed to remove key from keydb for interface %s (keydb not initialized)",
|
|
secy->netif->ipcom.name);
|
|
return -1;
|
|
}
|
|
|
|
for (i=0; i < IPMACSEC_SECY_KEYDB_SIZE; i++) {
|
|
k = secy->priv.keydb->key[i];
|
|
if (k == key) {
|
|
secy->priv.keydb->key[i] = IP_NULL;
|
|
break;
|
|
}
|
|
}
|
|
if (i == IPMACSEC_SECY_KEYDB_SIZE) {
|
|
IPCOM_LOG2(ERR, "IPMACSEC-KEYDB: Failed to remove key (key_id=0x%llx) from keydb for interface %s (does not exist)",
|
|
key->key_id.val, secy->netif->ipcom.name);
|
|
return -1;
|
|
}
|
|
(void)ipmacsec_secy_key_remove_notify(secy, key);
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG6(DEBUG, "IPMACSEC-KEYDB: Successfully removed key from keydb or interface %s "
|
|
"(key_id=0x%llx, transmits=%s, receives=%s, size=%u, inUse=%s)",
|
|
secy->netif->ipcom.name, key->key_id.val, IPMACSEC_BOOL_STRING(key->transmits),
|
|
IPMACSEC_BOOL_STRING(key->receives), key->sak.num_octets, IPMACSEC_BOOL_STRING(key->inUse));
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_keydb_iter_init
|
|
*===========================================================================
|
|
* Description: Initialize the iterator so that all keys in the db can be
|
|
* subsequently retrieved.
|
|
* (Later init hash table iterator)
|
|
* Parameters:
|
|
* Returns: 0 upon success, <0 upon error.
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipmacsec_secy_keydb_iter_init(Ipnet_secy *secy) {
|
|
ip_assert(secy);
|
|
|
|
if (secy->priv.keydb == IP_NULL) {
|
|
IPCOM_LOG1(CRIT, "IPMACSEC-KEYDB: Failed to initialize keydb iterator for interface %s (keydb not initialized)",
|
|
secy->netif->ipcom.name);
|
|
return -1;
|
|
}
|
|
secy->priv.keydb->iterator = 0;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_keydb_get_next_key
|
|
*===========================================================================
|
|
* Description: retrieve next entry in keydb based on iterator value
|
|
* (and update iterator)
|
|
* MUST call ipmacsec_secy_keydb_iter_init() before calling
|
|
* this iteratively in order to get correct results.
|
|
* (Later iterate the hash table)
|
|
* Parameters: secy - pointer to SecY instance
|
|
* pkey - pointer to variable to hold the retrieved key ptr
|
|
* Returns: 0 upon success, <0 upon error.
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipmacsec_secy_keydb_get_next_key(Ipnet_secy *secy, Ipmacsec_secy_key **pkey) {
|
|
|
|
ip_assert(secy);
|
|
ip_assert(pkey);
|
|
|
|
*pkey = IP_NULL;
|
|
|
|
if (secy->priv.keydb == IP_NULL) {
|
|
IPCOM_LOG1(CRIT, "IPMACSEC-KEYDB: Failed to get next key from keydb for interface %s (keydb not initialized)",
|
|
secy->netif->ipcom.name);
|
|
return -1;
|
|
}
|
|
|
|
if ((secy->priv.keydb->iterator < 0) || (secy->priv.keydb->iterator > IPMACSEC_SECY_KEYDB_SIZE)) {
|
|
IPCOM_LOG2(ERR, "IPMACSEC-KEYDB: Failed to get next key from keydb for interface %s (invalid iterator %d)",
|
|
secy->netif->ipcom.name, secy->priv.keydb->iterator);
|
|
secy->priv.keydb->iterator = -1;
|
|
return -1;
|
|
}
|
|
while (!*pkey && (secy->priv.keydb->iterator < IPMACSEC_SECY_KEYDB_SIZE)) {
|
|
*pkey = secy->priv.keydb->key[secy->priv.keydb->iterator];
|
|
secy->priv.keydb->iterator++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_retrieve_key
|
|
*===========================================================================
|
|
* Description: Retrieve the key whose key_id is specified and
|
|
update the key descriptor accordingly.
|
|
* Parameters: secy - pointer to SecY instance
|
|
* key_id - identified for key to retrieve
|
|
* key_desc - (optional) pointer to a key descriptor structure
|
|
* to be updated with key info for retrieved key
|
|
* Returns: Pointer to retrieved key on success,
|
|
* IP_NULL upon failure or if key is not found.
|
|
*
|
|
*/
|
|
IP_STATIC Ipmacsec_secy_key *
|
|
ipmacsec_secy_retrieve_key(Ipnet_secy *secy, Ipmacsec_secy_key_id *key_id, Ipmacsec_secy_key_descriptor *key_desc) {
|
|
Ipmacsec_secy_key *key = ipmacsec_secy_keydb_find_key(secy, key_id);
|
|
|
|
if (!key) {
|
|
return IP_NULL;
|
|
}
|
|
ip_assert(key->sak.buf && key->sak.num_octets);
|
|
|
|
if (key_desc) {
|
|
return ipmacsec_secy_retrieve_key_info(secy, key, key_desc);
|
|
}
|
|
return key;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_sa_exhaust_notify
|
|
*===========================================================================
|
|
* Description: Send notification of PN Exhaustion for specified SA
|
|
* Parameters:
|
|
* Returns: 0 upon success, <0 upon error.
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipmacsec_secy_sa_exhaust_notify(Ipnet_secy *secy, Ipmacsec_secy_sa *sa) {
|
|
Ipmacsec_secy_sa_descriptor sa_desc;
|
|
|
|
ip_assert(secy);
|
|
ip_assert(sa);
|
|
ip_assert(sa->sc);
|
|
|
|
(void)ipmacsec_secy_fill_sa_descriptor(secy, sa, &sa_desc);
|
|
return ipmacsec_secy_status_notify(secy, IPMACSEC_STATUS_SECY_PN_EXHAUSTED, &sa_desc, sizeof(sa_desc));
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_sa_near_exhaust_notify
|
|
*===========================================================================
|
|
* Description: Send notification of PN Near Exhaustion for specified SA
|
|
* Parameters:
|
|
* Returns: 0 upon success, <0 upon error.
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipmacsec_secy_sa_near_exhaust_notify(Ipnet_secy *secy, Ipmacsec_secy_sa *sa) {
|
|
int ret = 0;
|
|
struct {
|
|
Ipmacsec_secy_sa_descriptor sa_desc;
|
|
Ipmacsec_secy_sa_info sa_info;
|
|
} param;
|
|
|
|
ip_assert(secy);
|
|
ip_assert(sa);
|
|
ip_assert(sa->sc);
|
|
|
|
(void)ipmacsec_secy_fill_sa_descriptor(secy, sa, ¶m.sa_desc);
|
|
(void)ipmacsec_secy_fill_sa_info(secy, sa, ¶m.sa_info);
|
|
ret = ipmacsec_secy_status_notify(secy, IPMACSEC_STATUS_SECY_PN_NEARLY_EXHAUSTED, ¶m, sizeof(param));
|
|
if (ret == 0) {
|
|
sa->pn_near_exhaust_notify = IP_TRUE;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_update_sc_sa_stats
|
|
*===========================================================================
|
|
* Description: Called whenever an SA is deleted so that the deleted SA stats
|
|
* are preserved in the SC stats.
|
|
* Parameters:
|
|
* Returns: 0
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipmacsec_secy_update_sc_sa_stats(Ipnet_secy *secy, Ipmacsec_secy_sc *sc, Ipmacsec_secy_sa *sa) {
|
|
#ifndef IPMACSEC_USE_STATS
|
|
IPCOM_UNUSED_ARG(secy);
|
|
IPCOM_UNUSED_ARG(sa);
|
|
#endif
|
|
|
|
ip_assert(secy);
|
|
ip_assert(sc);
|
|
ip_assert(sa);
|
|
|
|
if (sc->dir == IPMACSEC_TX) {
|
|
IPMACSEC_SC_STATS_INC(aggr.tx.OutPktsEncrypted, IPMACSEC_SA_STATS(tx.OutPktsEncrypted));
|
|
IPMACSEC_SC_STATS_INC(aggr.tx.OutPktsProtected, IPMACSEC_SA_STATS(tx.OutPktsProtected));
|
|
}
|
|
if (sc->dir == IPMACSEC_RX) {
|
|
IPMACSEC_SC_STATS_INC(aggr.rx.InPktsOK, IPMACSEC_SA_STATS(rx.InPktsOK));
|
|
IPMACSEC_SC_STATS_INC(aggr.rx.InPktsInvalid, IPMACSEC_SA_STATS(rx.InPktsInvalid));
|
|
IPMACSEC_SC_STATS_INC(aggr.rx.InPktsNotValid, IPMACSEC_SA_STATS(rx.InPktsNotValid));
|
|
IPMACSEC_SC_STATS_INC(aggr.rx.InPktsNotUsingSA, IPMACSEC_SA_STATS(rx.InPktsNotUsingSA));
|
|
IPMACSEC_SC_STATS_INC(aggr.rx.InPktsUnusedSA, IPMACSEC_SA_STATS(rx.InPktsUnusedSA));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#ifdef IPMACSEC_USE_STATS
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_sc_add_sa_stats
|
|
*===========================================================================
|
|
* Description: Called whenever an SC stats are being retrieved so that the
|
|
* SA stats are added to the SC stats.
|
|
* Parameters:
|
|
* Returns: 0
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipmacsec_secy_sc_add_sa_stats(Ipnet_secy *secy, IP_CONST Ipmacsec_secy_sc *sc, Ipmacsec_secy_sc_stats *sc_stats) {
|
|
Ip_u8 an;
|
|
|
|
ip_assert(secy);
|
|
ip_assert(sc);
|
|
ip_assert(sc_stats);
|
|
|
|
for (an=0;an<secy->config.maxTxKeys;an++) {
|
|
IP_CONST Ipmacsec_secy_sa *sa = &sc->sa[an];
|
|
if (sc->dir == IPMACSEC_TX) {
|
|
sc_stats->aggr.tx.OutPktsEncrypted += IPMACSEC_SA_STATS(tx.OutPktsEncrypted);
|
|
sc_stats->aggr.tx.OutPktsProtected += IPMACSEC_SA_STATS(tx.OutPktsProtected);
|
|
}
|
|
if (sc->dir == IPMACSEC_RX) {
|
|
sc_stats->aggr.rx.InPktsOK += IPMACSEC_SA_STATS(rx.InPktsOK);
|
|
sc_stats->aggr.rx.InPktsInvalid += IPMACSEC_SA_STATS(rx.InPktsInvalid);
|
|
sc_stats->aggr.rx.InPktsNotValid += IPMACSEC_SA_STATS(rx.InPktsNotValid);
|
|
sc_stats->aggr.rx.InPktsNotUsingSA += IPMACSEC_SA_STATS(rx.InPktsNotUsingSA);
|
|
sc_stats->aggr.rx.InPktsUnusedSA += IPMACSEC_SA_STATS(rx.InPktsUnusedSA);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_rx_sc_iter_init
|
|
*===========================================================================
|
|
* Description: Initialize the RX SC iterator.
|
|
* Parameters:
|
|
* Returns: 0
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipmacsec_secy_rx_sc_iter_init(Ipnet_secy *secy) {
|
|
ip_assert(secy);
|
|
|
|
/* Simple for now. Later init hash table iterator */
|
|
secy->priv.rx_sc_iter = 0;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_get_next_rx_sc
|
|
*===========================================================================
|
|
* Description: retrieve next RX SC based on iterator value
|
|
* (and update iterator)
|
|
* MUST call ipmacsec_secy_rx_sc_iter_init() before calling
|
|
* this iteratively in order to get correct results.
|
|
* Parameters:
|
|
* Returns: 0 upon success, <0 upon error.
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipmacsec_secy_get_next_rx_sc(Ipnet_secy *secy, Ipmacsec_secy_sc **sc) {
|
|
ip_assert(secy);
|
|
ip_assert(sc);
|
|
|
|
*sc = IP_NULL;
|
|
|
|
/* Simple for now since we have just 1 rx SC, later need hash table traversal */
|
|
if (secy->priv.rx_sc_iter > 1) {
|
|
IPCOM_LOG2(ERR, "IPMACSEC-MGMT: Failed to get next Rx SC for interface %s (invalid iterator %d)",
|
|
secy->netif->ipcom.name, secy->priv.rx_sc_iter);
|
|
return -1;
|
|
}
|
|
if (secy->priv.rx_sc_iter == 1) {
|
|
secy->priv.rx_sc_iter = 2;
|
|
return 0;
|
|
}
|
|
secy->priv.rx_sc_iter++;
|
|
*sc = secy->priv.rx_sc;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_create_sc
|
|
*===========================================================================
|
|
* Description: SC Constructor
|
|
* Parameters:
|
|
* Returns: Pointer to created SC upon success,
|
|
* IP_NULL upon failure.
|
|
*
|
|
*/
|
|
IP_STATIC Ipmacsec_secy_sc *
|
|
ipmacsec_secy_create_sc(Ipnet_secy *secy, IP_CONST Ip_u8 *sci, Ipmacsec_dir dir) {
|
|
Ipmacsec_secy_sc *sc;
|
|
|
|
ip_assert(secy);
|
|
ip_assert(sci);
|
|
ip_assert((dir == IPMACSEC_TX) || (dir == IPMACSEC_RX));
|
|
|
|
if (IPMACSEC_INVALID_SCI(sci)) {
|
|
IPCOM_LOG2(CRIT, "IPMACSEC-MGMT: Failed to created SecY %s SC for interface %s (invalid SCI)",
|
|
IPMACSEC_DIR_STRING(dir), secy->netif->ipcom.name);
|
|
return IP_NULL;
|
|
}
|
|
|
|
sc = ipcom_malloc(sizeof(Ipmacsec_secy_sc));
|
|
if (!sc) {
|
|
IPCOM_LOG2(CRIT, "IPMACSEC-MGMT: Failed to alloc SecY %s SC for interface %s",
|
|
IPMACSEC_DIR_STRING(dir), secy->netif->ipcom.name);
|
|
return IP_NULL;
|
|
}
|
|
ipcom_memset(sc, 0, sizeof(Ipmacsec_secy_sc));
|
|
|
|
sc->crypto = ipmacsec_crypto_create(secy);
|
|
if (sc->crypto == IP_NULL) {
|
|
IPCOM_LOG2(CRIT, "IPMACSEC-CRYPTO: Failed to create Crypto interface of SecY %s SC for interface %s",
|
|
IPMACSEC_DIR_STRING(dir), secy->netif->ipcom.name);
|
|
ipcom_free(sc);
|
|
return IP_NULL;
|
|
}
|
|
|
|
IPMACSEC_COPY_SCI(sc->sci, sci);
|
|
sc->dir = dir;
|
|
sc->newAN = sc->oldAN = IPMACSEC_MAX_SA; /* init to invalid value */
|
|
|
|
ipmacsec_secy_set_current_time(secy, &sc->createdTime);
|
|
ipmacsec_secy_copy_time(secy, &sc->startedTime, &sc->createdTime);
|
|
ipmacsec_secy_copy_time(secy, &sc->stoppedTime, &sc->createdTime);
|
|
|
|
sc->enabled = IP_TRUE;
|
|
(void)ipmacsec_secy_sc_create_notify(secy, sc);
|
|
return sc;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_delete_sc
|
|
*===========================================================================
|
|
* Description: SC Destructor
|
|
* Parameters:
|
|
* Returns: 0
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipmacsec_secy_delete_sc(Ipnet_secy *secy, Ipmacsec_secy_sc *sc) {
|
|
Ipmacsec_dir dir;
|
|
Ip_u8 an;
|
|
Ip_u16 maxAN;
|
|
|
|
ip_assert(secy);
|
|
ip_assert(sc);
|
|
|
|
dir = sc->dir;
|
|
if (dir == IPMACSEC_RX) {
|
|
maxAN = secy->config.maxRxKeys;
|
|
} else {
|
|
maxAN = secy->config.maxTxKeys;
|
|
}
|
|
ip_assert(maxAN <= IPMACSEC_MAX_SA);
|
|
|
|
for (an = 0; an < maxAN; an++) {
|
|
Ipmacsec_secy_sa *sa = &sc->sa[an];
|
|
(void)ipmacsec_secy_delete_sa(secy, sa, dir);
|
|
}
|
|
sc->enabled = IP_FALSE;
|
|
/* Delete the crypto interface */
|
|
(void)ipmacsec_crypto_delete(secy, sc->crypto);
|
|
/* Now update the CP stats so that historic SC stats are preserved */
|
|
(void)ipmacsec_secy_cp_update_statistics(secy->netif);
|
|
/* Send Delete notification */
|
|
(void)ipmacsec_secy_sc_delete_notify(secy, sc);
|
|
ipcom_free(sc);
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG2(INFO, "IPMACSEC-MGMT: Deleted SecY %s SC for interface %s",
|
|
IPMACSEC_DIR_STRING(dir), secy->netif->ipcom.name);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_create_sa
|
|
*===========================================================================
|
|
* Description: SA Constructor
|
|
* Parameters:
|
|
* Returns: Pointer to created SA upon success,
|
|
* IP_NULL upon failure.
|
|
*
|
|
*/
|
|
IP_STATIC Ipmacsec_secy_sa *
|
|
ipmacsec_secy_create_sa(Ipnet_secy *secy, Ipmacsec_secy_sc *sc,
|
|
Ip_u8 an, Ipmacsec_secy_sa_ref ref,
|
|
Ip_u32 nextPN, Ip_u32 lowestPN,
|
|
Ipmacsec_confidentiality confidentiality,
|
|
Ipmacsec_secy_key *key, Ipmacsec_dir dir) {
|
|
Ipmacsec_secy_sa *sa;
|
|
|
|
ip_assert(secy);
|
|
ip_assert(secy->config.maxTxKeys <= IPMACSEC_MAX_SA);
|
|
ip_assert(secy->config.maxRxKeys <= IPMACSEC_MAX_SA);
|
|
ip_assert(sc);
|
|
ip_assert(sc->enabled);
|
|
ip_assert(sc->crypto);
|
|
ip_assert(an < IPMACSEC_MAX_SA);
|
|
ip_assert(IPMACSEC_CONFIDENTIALITY_VALID(confidentiality));
|
|
ip_assert((dir == IPMACSEC_TX) || (dir == IPMACSEC_RX));
|
|
ip_assert(sc->dir == dir);
|
|
|
|
if ((dir == IPMACSEC_TX) && (an >= secy->config.maxTxKeys)){
|
|
IPCOM_LOG3(ERR, "IPMACSEC-MGMT: Cannot create Tx SA %u (> maxTxKeys=%u) for interface %s.",
|
|
an, secy->config.maxTxKeys, secy->netif->ipcom.name);
|
|
return IP_NULL;
|
|
}
|
|
if ((dir == IPMACSEC_RX) && (an >= secy->config.maxRxKeys)) {
|
|
IPCOM_LOG3(ERR, "IPMACSEC-MGMT: Cannot create Rx SA %u (> maxTxKeys=%u) for interface %s.",
|
|
an, secy->config.maxRxKeys, secy->netif->ipcom.name);
|
|
return IP_NULL;
|
|
}
|
|
if (!key) {
|
|
IPCOM_LOG3(ERR, "IPMACSEC-MGMT: Cannot create %s SA %u (Key not supplied) for interface %s.",
|
|
IPMACSEC_DIR_STRING(dir), an, secy->netif->ipcom.name);
|
|
return IP_NULL;
|
|
}
|
|
if (key->inUse) {
|
|
IPCOM_LOG4(ERR, "IPMACSEC-MGMT: Cannot create %s SA %u (Key %llu in use) for interface %s.",
|
|
IPMACSEC_DIR_STRING(dir), an, key->key_id.val, secy->netif->ipcom.name);
|
|
return IP_NULL;
|
|
}
|
|
if ((dir == IPMACSEC_TX) && !key->transmits) {
|
|
IPCOM_LOG2(ERR, "IPMACSEC-MGMT: Cannot create Tx SA %u (Key not properly installed) for interface %s.",
|
|
an, secy->netif->ipcom.name);
|
|
return IP_NULL;
|
|
}
|
|
if ((dir == IPMACSEC_RX) && !key->receives) {
|
|
IPCOM_LOG2(ERR, "IPMACSEC-MGMT: Cannot create Rx SA %u (Key not properly installed) for interface %s.",
|
|
an, secy->netif->ipcom.name);
|
|
return IP_NULL;
|
|
}
|
|
if (lowestPN > nextPN) {
|
|
IPCOM_LOG5(INFO, "IPMACSEC-MGMT: Cannot create %s SA %u (lowestPN %u > nextPN %u) for interface %s",
|
|
IPMACSEC_DIR_STRING(dir), an, lowestPN, nextPN,secy->netif->ipcom.name);
|
|
return IP_NULL;
|
|
}
|
|
|
|
sa = &sc->sa[an];
|
|
(void)ipmacsec_secy_delete_sa(secy, sa, dir);
|
|
|
|
/* Init the crypto context */
|
|
if (sc->crypto->init_cipher(sc->crypto, an, &key->sak) != 0) {
|
|
IPCOM_LOG3(INFO, "IPMACSEC-MGMT: Cannot initialize crypto of %s SA %u for interface %s",
|
|
IPMACSEC_DIR_STRING(dir), an, secy->netif->ipcom.name);
|
|
return IP_NULL;
|
|
}
|
|
|
|
sa->sc = sc;
|
|
sa->an = an;
|
|
if (nextPN == 0) {
|
|
/* Not supplied, so start at 1 */
|
|
sa->nextPN = 1;
|
|
} else {
|
|
sa->nextPN = nextPN;
|
|
}
|
|
sa->lowestPN = lowestPN;
|
|
if (dir == IPMACSEC_TX) {
|
|
if (confidentiality == IPMACSEC_CONFIDENTIALITY_UNSPECIFIED) {
|
|
sa->confidentiality = ipcom_sysvar_get_as_int(IPMACSEC_SYSVAR_SECY_CONFIDENTIALITY, 0);
|
|
} else {
|
|
sa->confidentiality = ((confidentiality == IPMACSEC_CONFIDENTIALITY_ON) ? 1 : 0);
|
|
}
|
|
}
|
|
sa->key = key;
|
|
key->inUse = IP_TRUE;
|
|
sa->ref = ref;
|
|
sa->pn_threshold = secy->config.pn_threshold;
|
|
|
|
ipmacsec_secy_set_current_time(secy, &sa->createdTime);
|
|
ipmacsec_secy_copy_time(secy, &sa->startedTime, &sa->createdTime);
|
|
ipmacsec_secy_copy_time(secy, &sa->stoppedTime, &sa->createdTime);
|
|
|
|
(void)ipmacsec_secy_sa_create_notify(secy, sa);
|
|
|
|
return sa;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_delete_sa
|
|
*===========================================================================
|
|
* Description: SA Destructor
|
|
* Parameters:
|
|
* Returns: 0
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipmacsec_secy_delete_sa(Ipnet_secy *secy, Ipmacsec_secy_sa *sa, Ipmacsec_dir dir) {
|
|
Ip_u8 an;
|
|
#ifndef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_UNUSED_ARG(dir);
|
|
#endif
|
|
|
|
ip_assert(secy);
|
|
ip_assert(sa);
|
|
|
|
if (!sa->sc) {
|
|
goto delete_done; /* Already deleted, never created, or partially created/deleted. Finish it */
|
|
}
|
|
/* Before deleting, add old sa count to sc counts */
|
|
(void)ipmacsec_secy_update_sc_sa_stats(secy, sa->sc, sa); /* 10.7.9; 10.7.18 */
|
|
/* We also need to update SA/SC status (so counts are updated) */
|
|
if (sa->sc->dir == IPMACSEC_RX) {
|
|
(void)ipmacsec_secy_enable_rx_sa(secy, sa, IP_FALSE);
|
|
if (sa->sc->oldAN == sa->an) {
|
|
sa->sc->oldAN = IPMACSEC_MAX_SA; /* Invalidate oldAN */
|
|
sa->sc->interleave_time = 0;
|
|
}
|
|
} else
|
|
(void)ipmacsec_secy_enable_tx_sa(secy, sa, IP_FALSE);
|
|
/* destroy the crypto context */
|
|
if (sa->sc->crypto)
|
|
(void)sa->sc->crypto->destroy_cipher(sa->sc->crypto, (Ip_u8)sa->an);
|
|
|
|
(void)ipmacsec_secy_sa_delete_notify(secy, sa);
|
|
an = (Ip_u8)sa->an;
|
|
if (sa->key) {
|
|
sa->key->inUse = IP_FALSE;
|
|
}
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG3(INFO, "IPMACSEC-MGMT: Deleted SecY %s SA %u for interface %s",
|
|
IPMACSEC_DIR_STRING(dir), an, secy->netif->ipcom.name);
|
|
#endif
|
|
delete_done:
|
|
ipcom_memset(sa, 0, sizeof(Ipmacsec_secy_sa));
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_start_tx_sc
|
|
*===========================================================================
|
|
* Description: Start the Tx SC if not already started
|
|
* Parameters:
|
|
* Returns: 0
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipmacsec_secy_start_tx_sc(Ipnet_secy *secy, Ipmacsec_secy_sc *sc, Ip_u8 an) {
|
|
ip_assert(secy);
|
|
ip_assert(sc);
|
|
ip_assert(sc == secy->priv.tx_sc);
|
|
ip_assert(sc->dir == IPMACSEC_TX);
|
|
|
|
sc->encodingSA = an; /* 10.5.1 */
|
|
if (!sc->oper.transmitting) {
|
|
ipmacsec_secy_set_current_time(secy, &sc->startedTime);
|
|
sc->oper.transmitting = IP_TRUE;
|
|
(void)ipmacsec_secy_sc_change_notify(secy, sc);
|
|
(void)ipmacsec_secy_cp_update_status(secy, IPMACSEC_SECY_MAC_OPER_DEFAULT); /* Possible CP Status Change */
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_stop_tx_sc
|
|
*===========================================================================
|
|
* Description: Stop the Tx SC is the encoding SA matches supplied AN
|
|
* Parameters:
|
|
* Returns: 0
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipmacsec_secy_stop_tx_sc(Ipnet_secy *secy, Ipmacsec_secy_sc *sc, Ip_u8 an) {
|
|
ip_assert(secy);
|
|
ip_assert(sc);
|
|
ip_assert(sc == secy->priv.tx_sc);
|
|
ip_assert(sc->dir == IPMACSEC_TX);
|
|
|
|
if (sc->oper.transmitting && sc->encodingSA == an) {
|
|
ipmacsec_secy_set_current_time(secy, &sc->stoppedTime);
|
|
sc->oper.transmitting = IP_FALSE;
|
|
(void)ipmacsec_secy_sc_change_notify(secy, sc);
|
|
(void)ipmacsec_secy_cp_update_status(secy, IPMACSEC_SECY_MAC_OPER_DEFAULT); /* Possible CP Status Change */
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_start_rx_sc
|
|
*===========================================================================
|
|
* Description: Start the Rx SC if not already started
|
|
* Parameters:
|
|
* Returns: 0
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipmacsec_secy_start_rx_sc(Ipnet_secy *secy, Ipmacsec_secy_sc *sc, Ip_u8 an) {
|
|
IPCOM_UNUSED_ARG(an);
|
|
|
|
ip_assert(secy);
|
|
ip_assert(sc);
|
|
ip_assert(sc->dir == IPMACSEC_RX);
|
|
|
|
sc->numActiveRxSAs++;
|
|
ip_assert(sc->numActiveRxSAs <= secy->config.maxRxKeys);
|
|
if (!sc->oper.receiving) {
|
|
ipmacsec_secy_set_current_time(secy, &sc->startedTime);
|
|
sc->oper.receiving = IP_TRUE;
|
|
(void)ipmacsec_secy_sc_change_notify(secy, sc);
|
|
secy->oper.numActiveRxSCs++;
|
|
if (secy->oper.numActiveRxSCs == 1) {
|
|
(void)ipmacsec_secy_cp_update_status(secy, IPMACSEC_SECY_MAC_OPER_DEFAULT); /* Possible CP Status Change */
|
|
}
|
|
ip_assert(secy->oper.numActiveRxSCs <= secy->config.maxRxSCs);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_stop_rx_sc
|
|
*===========================================================================
|
|
* Description: Stop the Rx SC is the encoding SA matches supplied AN
|
|
* Parameters:
|
|
* Returns: 0
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipmacsec_secy_stop_rx_sc(Ipnet_secy *secy, Ipmacsec_secy_sc *sc, Ip_u8 an) {
|
|
IPCOM_UNUSED_ARG(an);
|
|
|
|
ip_assert(secy);
|
|
ip_assert(sc);
|
|
ip_assert(sc->dir == IPMACSEC_RX);
|
|
|
|
ip_assert(sc->numActiveRxSAs);
|
|
sc->numActiveRxSAs--;
|
|
if (sc->numActiveRxSAs == 0) {
|
|
ip_assert(sc->oper.receiving);
|
|
ipmacsec_secy_set_current_time(secy, &sc->stoppedTime);
|
|
sc->oper.receiving = IP_FALSE;
|
|
(void)ipmacsec_secy_sc_change_notify(secy, sc);
|
|
ip_assert(secy->oper.numActiveRxSCs);
|
|
secy->oper.numActiveRxSCs--;
|
|
if (secy->oper.numActiveRxSCs == 0) {
|
|
/* Possible CP Status Change */
|
|
(void)ipmacsec_secy_cp_update_status(secy, IPMACSEC_SECY_MAC_OPER_DEFAULT);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef IPMACSEC_USE_STATS
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_reset_stats
|
|
*===========================================================================
|
|
* Description: Reset the SecY and CP statistics
|
|
* Parameters:
|
|
* Returns: 0 upon success, <0 upon error
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipmacsec_secy_reset_stats(Ipnet_secy *secy) {
|
|
ip_assert(secy);
|
|
|
|
ipcom_memset(&secy->stats, 0, sizeof(secy->stats));
|
|
ipcom_memset(&secy->controlled_port.stats, 0, sizeof(secy->controlled_port.stats));
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_update_rx_sa_lowestPN
|
|
*===========================================================================
|
|
* Description: Update Rx SA lowestPN based on replayWindow and new nextPN value
|
|
* Parameters:
|
|
* Returns: 0
|
|
*
|
|
*/
|
|
IP_INLINE int
|
|
ipmacsec_secy_update_rx_sa_lowestPN(Ipnet_secy *secy, Ipmacsec_secy_sa *sa) {
|
|
ip_assert(secy);
|
|
ip_assert(sa);
|
|
|
|
/* 10.6.5 */
|
|
if (sa->nextPN > secy->ctrl.replayWindow) {
|
|
sa->lowestPN = IP_MAX(sa->lowestPN, (sa->nextPN - secy->ctrl.replayWindow));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 PRIVATE FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_keydb_init
|
|
*===========================================================================
|
|
* Description: see "ipmacsec_secy_mgmt.h"
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE int
|
|
ipmacsec_secy_keydb_init(Ipnet_secy *secy) {
|
|
ip_assert(secy);
|
|
|
|
if (secy->priv.keydb == IP_NULL) {
|
|
secy->priv.keydb = ipcom_malloc(sizeof(Ipmacsec_keydb));
|
|
}
|
|
if (secy->priv.keydb == IP_NULL) {
|
|
IPCOM_LOG0(CRIT, "IPMACSEC-KEYDB: Failed to allocate keydb");
|
|
return -1;
|
|
}
|
|
ipcom_memset(secy->priv.keydb, 0, sizeof(Ipmacsec_keydb));
|
|
secy->priv.keydb->iterator = -1;
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG0(DEBUG2, "IPMACSEC-MGMT: Successfully created keydb");
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_keydb_destroy
|
|
*===========================================================================
|
|
* Description: see "ipmacsec_secy_mgmt.h"
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE int
|
|
ipmacsec_secy_keydb_destroy(Ipnet_secy *secy) {
|
|
ip_assert(secy);
|
|
|
|
if (secy->priv.keydb == IP_NULL) {
|
|
ipcom_free(secy->priv.keydb);
|
|
}
|
|
secy->priv.keydb = IP_NULL;
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG0(DEBUG2, "IPMACSEC-MGMT: Successfully destroyed keydb");
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_create_tx_sc
|
|
*===========================================================================
|
|
* Description: see "ipmacsec_secy_mgmt.h"
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE Ipmacsec_secy_sc *
|
|
ipmacsec_secy_create_tx_sc(Ipnet_secy *secy) {
|
|
Ipmacsec_secy_sc *sc;
|
|
|
|
ip_assert(secy);
|
|
|
|
sc = secy->priv.tx_sc;
|
|
if (sc) {
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG1(DEBUG, "IPMACSEC-MGMT: SecY Tx SC already created for interface %s", secy->netif->ipcom.name);
|
|
#endif
|
|
return sc;
|
|
}
|
|
|
|
if (IPMACSEC_INVALID_SCI(secy->config.sci)) {
|
|
if (secy->ctrl.useES) {
|
|
/* Init SCI from MAC address and default port 00-01. (A5(SCI); 8.2.1; 9.5) */
|
|
IPNET_SET_ETHADDR(secy->config.sci, secy->netif->ipcom.link_addr);
|
|
secy->config.sci[6] = 0x00;
|
|
secy->config.sci[7] = (Ip_u8)(secy->ctrl.useSCB ? 0x00 : 0x01); /* 9.5 */
|
|
IPCOM_LOG9(WARNING,
|
|
"IPMACSEC-MGMT: SecY SCI value (%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x) used for interface %s ",
|
|
secy->config.sci[0], secy->config.sci[1], secy->config.sci[2], secy->config.sci[3],
|
|
secy->config.sci[4], secy->config.sci[5], secy->config.sci[6], secy->config.sci[7],
|
|
secy->netif->ipcom.name);
|
|
} else {
|
|
IPCOM_LOG1(CRIT, "IPMACSEC-MGMT: SecY SCI not configured for interface %s ",
|
|
secy->netif->ipcom.name);
|
|
return IP_NULL;
|
|
}
|
|
}
|
|
|
|
sc = ipmacsec_secy_create_sc(secy, secy->config.sci, IPMACSEC_TX);
|
|
if (!sc) {
|
|
IPCOM_LOG1(CRIT, "IPMACSEC-MGMT: Failed to create SecY Tx SC for interface %s", secy->netif->ipcom.name);
|
|
return IP_NULL;
|
|
}
|
|
secy->priv.tx_sc = sc;
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG1(INFO, "IPMACSEC-MGMT: Successfully created SecY Tx SC for interface %s", secy->netif->ipcom.name);
|
|
#endif
|
|
return sc;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_delete_tx_sc
|
|
*===========================================================================
|
|
* Description: see "ipmacsec_secy_mgmt.h"
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE
|
|
int ipmacsec_secy_delete_tx_sc(Ipnet_secy *secy) {
|
|
ip_assert(secy);
|
|
|
|
if (!secy->priv.tx_sc) {
|
|
return -1;
|
|
}
|
|
ip_assert(secy->priv.tx_sc->dir == IPMACSEC_TX);
|
|
(void)ipmacsec_secy_delete_sc(secy, secy->priv.tx_sc);
|
|
secy->priv.tx_sc = IP_NULL;
|
|
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG1(INFO, "IPMACSEC-MGMT: Deleted SecY Tx SC for interface %s", secy->netif->ipcom.name);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_create_tx_sa
|
|
*===========================================================================
|
|
* Description: see "ipmacsec_secy_mgmt.h"
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE Ipmacsec_secy_sa *
|
|
ipmacsec_secy_create_tx_sa(Ipnet_secy *secy, Ip_u8 an, Ipmacsec_secy_sa_ref ref,
|
|
Ip_u32 nextPN, Ipmacsec_confidentiality confidentiality,
|
|
Ipmacsec_secy_key *key) {
|
|
Ipmacsec_secy_sc *sc;
|
|
Ipmacsec_secy_sa *sa;
|
|
|
|
ip_assert(secy);
|
|
|
|
sc = ipmacsec_secy_get_tx_sc(secy);
|
|
if (!sc) {
|
|
IPCOM_LOG2(ERR, "IPMACSEC-MGMT: Cannot create Tx SA %u (No Tx SC) for interface %s.",
|
|
an, secy->netif->ipcom.name);
|
|
return IP_NULL;
|
|
}
|
|
ip_assert(sc->dir == IPMACSEC_TX);
|
|
|
|
sa = ipmacsec_secy_create_sa(secy, sc, an, ref, nextPN, 0 /* no lowestPN */,
|
|
confidentiality, key, IPMACSEC_TX);
|
|
if (!sa) {
|
|
IPCOM_LOG2(ERR, "IPMACSEC-MGMT: Failed to create Tx SA %u for interface %s.",
|
|
an, secy->netif->ipcom.name);
|
|
return IP_NULL;
|
|
}
|
|
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG2(INFO, "IPMACSEC-MGMT: Successfully created SecY Tx SA %u for interface %s",
|
|
an, secy->netif->ipcom.name);
|
|
#endif
|
|
return sa;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_delete_tx_sa
|
|
*===========================================================================
|
|
* Description: see "ipmacsec_secy_mgmt.h"
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE int
|
|
ipmacsec_secy_delete_tx_sa(Ipnet_secy *secy, Ipmacsec_secy_sa *sa) {
|
|
return ipmacsec_secy_delete_sa(secy, sa, IPMACSEC_TX);
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_enable_tx_sa
|
|
*===========================================================================
|
|
* Description: see "ipmacsec_secy_mgmt.h"
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE int
|
|
ipmacsec_secy_enable_tx_sa(Ipnet_secy *secy, Ipmacsec_secy_sa *sa, Ip_bool enableTransmit) {
|
|
Ipmacsec_secy_sc *sc;
|
|
|
|
ip_assert(secy);
|
|
ip_assert(sa);
|
|
|
|
sc = sa->sc;
|
|
ip_assert(sc);
|
|
ip_assert(sc->dir == IPMACSEC_TX);
|
|
|
|
sa->ctrl.tx.enableTx = (enableTransmit ? IPMACSEC_ENABLEFLAG_ON : IPMACSEC_ENABLEFLAG_OFF);
|
|
if (enableTransmit) {
|
|
if (!sa->inUse) {
|
|
Ip_u8 an;
|
|
if (!sa->key || (sa->nextPN == 0)) {
|
|
IPCOM_LOG3(ERR, "IPMACSEC-MGMT: Cannot set enableTransmit for Tx SA %u (Invalid SA %s) for interface %s.",
|
|
sa->an, (!sa->key ? "key" : "nextPN"), secy->netif->ipcom.name);
|
|
return -1;
|
|
}
|
|
/* enable this SA */
|
|
sa->inUse = IP_TRUE;
|
|
(void)ipmacsec_secy_sa_change_notify(secy, sa);
|
|
ipmacsec_secy_set_current_time(secy, &sa->startedTime);
|
|
ipmacsec_secy_start_tx_sc(secy, sc, (Ip_u8)sa->an);
|
|
/* Now disable any other enabled SAs, since only 1 tx SA can be enabled at one time */
|
|
for (an=0;an<secy->config.maxTxKeys;an++) {
|
|
if ((an == sa->an) || (!sc->sa[an].inUse))
|
|
continue;
|
|
(void)ipmacsec_secy_enable_tx_sa(secy, &sc->sa[an], IP_FALSE);
|
|
}
|
|
}
|
|
} else {
|
|
if (sa->inUse) {
|
|
sa->inUse = IP_FALSE;
|
|
(void)ipmacsec_secy_sa_change_notify(secy, sa);
|
|
ipmacsec_secy_set_current_time(secy, &sa->stoppedTime);
|
|
ipmacsec_secy_stop_tx_sc(secy, sc, (Ip_u8)sa->an);
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG3(INFO, "IPMACSEC-MGMT: enableTransmit set to %s for SecY Tx SA %u for interface %s",
|
|
IPMACSEC_BOOL_STRING(enableTransmit), sa->an, secy->netif->ipcom.name);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_create_rx_sc
|
|
*===========================================================================
|
|
* Description: see "ipmacsec_secy_mgmt.h"
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE Ipmacsec_secy_sc *
|
|
ipmacsec_secy_create_rx_sc(Ipnet_secy *secy, IP_CONST Ip_u8 *sci) {
|
|
Ipmacsec_secy_sc *sc;
|
|
|
|
ip_assert(secy);
|
|
ip_assert(secy->oper.numCreatedRxSCs <= secy->config.maxRxSCs);
|
|
|
|
sc = ipmacsec_secy_lookup_rx_sc(secy, sci);
|
|
if (sc) {
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG1(ERR, "IPMACSEC-MGMT: Failed to create RX SC (already exists) for interface %s",
|
|
secy->netif->ipcom.name);
|
|
#endif
|
|
return IP_NULL;
|
|
}
|
|
|
|
if (secy->oper.numCreatedRxSCs == secy->config.maxRxSCs) {
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG2(ERR, "IPMACSEC-MGMT: Failed to create RX SC (maxRxSCs %u reached) for interface %s",
|
|
secy->config.maxRxSCs, secy->netif->ipcom.name);
|
|
#endif
|
|
return IP_NULL;
|
|
|
|
}
|
|
|
|
sc = ipmacsec_secy_create_sc(secy, sci, IPMACSEC_RX);
|
|
if (!sc) {
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG1(ERR, "IPMACSEC-MGMT: Failed to create SecY Rx SC (alloc failed) for interface %s", secy->netif->ipcom.name);
|
|
#endif
|
|
return IP_NULL;
|
|
}
|
|
/* For now we support only one rx SC, so this is simple. Later we need a hash lookup/insert */
|
|
secy->oper.numCreatedRxSCs++;
|
|
secy->priv.rx_sc = sc;
|
|
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG2(INFO, "IPMACSEC-MGMT: Successfully created SecY Rx SC (#%u) for interface %s",
|
|
secy->oper.numCreatedRxSCs, secy->netif->ipcom.name);
|
|
#endif
|
|
return sc;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_delete_rx_sc
|
|
*===========================================================================
|
|
* Description: see "ipmacsec_secy_mgmt.h"
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE int
|
|
ipmacsec_secy_delete_rx_sc(Ipnet_secy *secy, Ipmacsec_secy_sc *sc) {
|
|
int rc = 0;
|
|
|
|
ip_assert(secy);
|
|
ip_assert(secy->oper.numCreatedRxSCs);
|
|
|
|
secy->oper.numCreatedRxSCs--;
|
|
/* Only 1 rx_sc for now. Later need to remove from hash */
|
|
ip_assert(secy->priv.rx_sc == sc);
|
|
rc = ipmacsec_secy_delete_sc(secy, sc);
|
|
secy->priv.rx_sc = IP_NULL;
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_delete_rx_sc_all
|
|
*===========================================================================
|
|
* Description: see "ipmacsec_secy_mgmt.h"
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE int
|
|
ipmacsec_secy_delete_rx_sc_all(Ipnet_secy *secy) {
|
|
int rc =0;
|
|
|
|
ip_assert(secy);
|
|
|
|
/* Only 1 rx_sc for now. Later need to delete each and every one */
|
|
if (secy->priv.rx_sc)
|
|
rc = ipmacsec_secy_delete_rx_sc(secy, secy->priv.rx_sc);
|
|
|
|
ip_assert(secy->oper.numCreatedRxSCs == 0);
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_create_rx_sa
|
|
*===========================================================================
|
|
* Description: see "ipmacsec_secy_mgmt.h"
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE Ipmacsec_secy_sa *
|
|
ipmacsec_secy_create_rx_sa(Ipnet_secy *secy, Ipmacsec_secy_sc *sc,
|
|
Ip_u8 an, Ipmacsec_secy_sa_ref ref,
|
|
Ip_u32 nextPN, Ip_u32 lowestPN,
|
|
Ipmacsec_secy_key *key) {
|
|
Ipmacsec_secy_sa *sa;
|
|
|
|
ip_assert(secy);
|
|
ip_assert(sc);
|
|
ip_assert(sc->dir == IPMACSEC_RX);
|
|
|
|
|
|
sa = ipmacsec_secy_create_sa(secy, sc, an, ref, nextPN, lowestPN,
|
|
IPMACSEC_CONFIDENTIALITY_UNSPECIFIED, key, IPMACSEC_RX);
|
|
if (!sa) {
|
|
IPCOM_LOG2(ERR, "IPMACSEC-MGMT: Failed to create Rx SA %u for interface %s.",
|
|
an, secy->netif->ipcom.name);
|
|
return IP_NULL;
|
|
}
|
|
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG2(INFO, "IPMACSEC-MGMT: Successfully created SecY Rx SA %u for interface %s",
|
|
an, secy->netif->ipcom.name);
|
|
#endif
|
|
return sa;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_delete_rx_sa
|
|
*===========================================================================
|
|
* Description: see "ipmacsec_secy_mgmt.h"
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE int
|
|
ipmacsec_secy_delete_rx_sa(Ipnet_secy *secy, Ipmacsec_secy_sa *sa) {
|
|
return ipmacsec_secy_delete_sa(secy, sa, IPMACSEC_RX);
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_enable_rx_sa
|
|
*===========================================================================
|
|
* Description: see "ipmacsec_secy_mgmt.h"
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE int
|
|
ipmacsec_secy_enable_rx_sa(Ipnet_secy *secy, Ipmacsec_secy_sa *sa, Ip_bool enableReceive) {
|
|
Ipmacsec_secy_sc *sc;
|
|
|
|
ip_assert(secy);
|
|
ip_assert(sa);
|
|
|
|
sc = sa->sc;
|
|
ip_assert(sc);
|
|
ip_assert(sc->dir == IPMACSEC_RX);
|
|
|
|
sa->ctrl.rx.enableRx = (enableReceive ? IPMACSEC_ENABLEFLAG_ON : IPMACSEC_ENABLEFLAG_OFF);
|
|
if (enableReceive) {
|
|
if (!sa->inUse) {
|
|
if (!sa->key || (sa->nextPN == 0)) {
|
|
IPCOM_LOG3(ERR, "IPMACSEC-MGMT: Cannot set enableReceive for Rx SA %u (Invalid SA %s) for interface %s.",
|
|
sa->an, (!sa->key ? "key" : "nextPN"), secy->netif->ipcom.name);
|
|
return -1;
|
|
}
|
|
sa->inUse = IP_TRUE;
|
|
(void)ipmacsec_secy_sa_change_notify(secy, sa);
|
|
ipmacsec_secy_set_current_time(secy, &sa->startedTime);
|
|
ipmacsec_secy_start_rx_sc(secy, sc, (Ip_u8)sa->an);
|
|
}
|
|
} else {
|
|
if (sa->inUse) {
|
|
sa->inUse = IP_FALSE;
|
|
(void)ipmacsec_secy_sa_change_notify(secy, sa);
|
|
ipmacsec_secy_set_current_time(secy, &sa->stoppedTime);
|
|
ipmacsec_secy_stop_rx_sc(secy, sc, (Ip_u8)sa->an);
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG3(INFO, "IPMACSEC-MGMT: enableReceive set to %s for SecY Tx SA %u for interface %s",
|
|
IPMACSEC_BOOL_STRING(enableReceive), sa->an, secy->netif->ipcom.name);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_update_sa_nextPN
|
|
*===========================================================================
|
|
* Description: Update SA nextPN based on supplied new nextPN value
|
|
* Parameters:
|
|
* Returns: 0 upon success, <0 upon error.
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE int
|
|
ipmacsec_secy_update_sa_nextPN(Ipnet_secy *secy, Ipmacsec_secy_sa *sa, Ip_u32 nextPN) {
|
|
ip_assert(secy);
|
|
ip_assert(sa);
|
|
ip_assert(sa->sc);
|
|
|
|
sa->nextPN = nextPN;
|
|
if (sa->nextPN == 0) {
|
|
if ((sa->sc->dir == IPMACSEC_TX) && secy->ctrl.protectFrames) {
|
|
/* A.8(GEN-5); 7.1.3; 10.5.2 */
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG3(DEBUG2,
|
|
"IPMACSEC-MGMT: nextPN 0 for %s SA (%u), CP MAC_Operational now set to FALSE for interface %s",
|
|
IPMACSEC_DIR_STRING(sa->sc->dir), sa->an, secy->netif->ipcom.name);
|
|
#endif
|
|
/* Notify via LMI of SA PN exhaustion */
|
|
(void)ipmacsec_secy_sa_exhaust_notify(secy, sa);
|
|
/* MAC_Operational should transition to FALSE for the CP */
|
|
(void)ipmacsec_secy_cp_update_status(secy, IPMACSEC_SECY_MAC_OPER_OFF);
|
|
return -1;
|
|
} else {
|
|
sa->nextPN = 1;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if ((sa->sc->dir == IPMACSEC_TX) && !sa->pn_near_exhaust_notify && (sa->nextPN >= sa->pn_threshold)) {
|
|
/* (A.11-KAY-9, 8.2.7) */
|
|
(void)ipmacsec_secy_sa_near_exhaust_notify(secy, sa);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_update_rx_sa_PNs
|
|
*===========================================================================
|
|
* Description: Update Rx SA nextPN and/or lowestPN based on Rx PN value
|
|
* Parameters: rxPN value of 0 means do not update
|
|
* Returns: 0
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE int
|
|
ipmacsec_secy_update_rx_sa_PNs(Ipnet_secy *secy, Ipmacsec_secy_sa *sa, Ip_u32 rxPN) {
|
|
ip_assert(secy);
|
|
ip_assert(sa);
|
|
ip_assert(rxPN);
|
|
ip_assert(rxPN >= sa->lowestPN);
|
|
ip_assert(sa->sc);
|
|
ip_assert(sa->sc->dir == IPMACSEC_RX);
|
|
|
|
/* 10.6.5 */
|
|
if (rxPN >= sa->nextPN) {
|
|
(void)ipmacsec_secy_update_sa_nextPN(secy, sa, rxPN+1);
|
|
}
|
|
(void)ipmacsec_secy_update_rx_sa_lowestPN(secy, sa);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_update_rx_sa
|
|
*===========================================================================
|
|
* Description: see "ipmacsec_secy_mgmt.h"
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE int
|
|
ipmacsec_secy_update_rx_sa(Ipnet_secy *secy, Ipmacsec_secy_sa *sa,
|
|
Ip_u32 nextPN, Ip_u32 lowestPN) {
|
|
ip_assert(secy);
|
|
ip_assert(sa);
|
|
|
|
if (!nextPN && !lowestPN) {
|
|
/* What are we trying to update here?! */
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG2(INFO, "IPMACSEC-MGMT: Both nextPN and lowestPN are 0 for SecY Rx SA %u for interface %s",
|
|
sa->an, secy->netif->ipcom.name);
|
|
#endif
|
|
return -1;
|
|
}
|
|
|
|
if (lowestPN && (lowestPN > nextPN)) {
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG4(INFO, "IPMACSEC-MGMT: Invalid lowestPN (%u > nextPN %u) SecY Rx SA %u for interface %s",
|
|
lowestPN, nextPN, sa->an, secy->netif->ipcom.name);
|
|
#endif
|
|
return -1;
|
|
}
|
|
/* 10.7.15 */
|
|
if (lowestPN > sa->lowestPN) {
|
|
sa->lowestPN = sa->ctrl.rx.updtLowestPN = lowestPN;
|
|
}
|
|
if (nextPN > sa->nextPN) {
|
|
sa->nextPN = sa->ctrl.rx.updtNextPN = nextPN;
|
|
if (!lowestPN) {
|
|
(void)ipmacsec_secy_update_rx_sa_lowestPN(secy, sa);
|
|
}
|
|
}
|
|
(void)ipmacsec_secy_sa_change_notify(secy, sa);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_sak_copy
|
|
*===========================================================================
|
|
* Description: see "ipmacsec_h.h"
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE int
|
|
ipmacsec_sak_copy(Ipmacsec_secy_sak *to_sak, IP_CONST Ipmacsec_secy_sak *from_sak) {
|
|
if (!to_sak)
|
|
return -1;
|
|
to_sak->buf = IP_NULL;
|
|
to_sak->num_octets = 0;
|
|
if (!from_sak)
|
|
return -1;
|
|
to_sak->buf = ipcom_malloc(from_sak->num_octets);
|
|
if (!to_sak->buf) {
|
|
to_sak->num_octets = 0;
|
|
return -1;
|
|
}
|
|
to_sak->num_octets = from_sak->num_octets;
|
|
ipcom_memcpy(to_sak->buf, from_sak->buf, to_sak->num_octets);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_sak_delete
|
|
*===========================================================================
|
|
* Description: see "ipmacsec_h.h"
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE int
|
|
ipmacsec_sak_delete(Ipmacsec_secy_sak *sak) {
|
|
if (!sak) {
|
|
return -1;
|
|
}
|
|
if (sak->buf) {
|
|
/* For security reasons, erase the SAK keying material before freeing it up */
|
|
ipcom_memset(sak->buf, 0, sak->num_octets);
|
|
ipcom_free(sak->buf);
|
|
sak->buf = IP_NULL;
|
|
}
|
|
sak->num_octets = 0;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_create_key
|
|
*===========================================================================
|
|
* Description: see "ipmacsec_secy_mgmt.h"
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE Ipmacsec_secy_key *
|
|
ipmacsec_secy_create_key(Ipnet_secy *secy,
|
|
Ipmacsec_secy_sak *sak, Ipmacsec_secy_key_id *key_id) {
|
|
Ipmacsec_secy_key *key;
|
|
|
|
ip_assert(secy);
|
|
|
|
if (!sak) {
|
|
return IP_NULL;
|
|
}
|
|
if (!sak->buf || !sak->num_octets) {
|
|
return IP_NULL;
|
|
}
|
|
key = ipcom_malloc(sizeof(Ipmacsec_secy_key));
|
|
if (!key) {
|
|
return IP_NULL;
|
|
}
|
|
ipcom_memset(key, 0, sizeof(Ipmacsec_secy_key));
|
|
|
|
key->sak.buf = sak->buf;
|
|
key->sak.num_octets = sak->num_octets;
|
|
ipmacsec_secy_set_current_time(secy, &key->createdTime);
|
|
if (key_id) {
|
|
key->key_id.val = key_id->val;
|
|
}
|
|
return key;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_delete_key
|
|
*===========================================================================
|
|
* Description: see "ipmacsec_secy_mgmt.h"
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE int
|
|
ipmacsec_secy_delete_key(Ipnet_secy *secy, Ipmacsec_secy_key *key) {
|
|
IPCOM_UNUSED_ARG(secy);
|
|
|
|
ip_assert(secy);
|
|
ip_assert(key);
|
|
ip_assert(!key->inUse);
|
|
|
|
(void)ipmacsec_sak_delete(&key->sak);
|
|
ipcom_memset(key, 0, sizeof(Ipmacsec_secy_key));
|
|
ipcom_free(key);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_install_key
|
|
*===========================================================================
|
|
* Description: see "ipmacsec_secy_mgmt.h"
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE int
|
|
ipmacsec_secy_install_key(Ipnet_secy *secy, Ipmacsec_secy_key *key, Ipmacsec_keytype keytype) {
|
|
ip_assert(secy);
|
|
ip_assert(key);
|
|
|
|
if ((keytype & (IPMACSEC_KEYTYPE_TRANSMIT | IPMACSEC_KEYTYPE_RECEIVE)) == 0) {
|
|
return -1;
|
|
}
|
|
if (!key->sak.buf || !key->sak.num_octets) {
|
|
return -1;
|
|
}
|
|
if (keytype & IPMACSEC_KEYTYPE_TRANSMIT)
|
|
key->transmits = IP_TRUE;
|
|
if (keytype & IPMACSEC_KEYTYPE_RECEIVE)
|
|
key->receives = IP_TRUE;
|
|
|
|
return ipmacsec_secy_keydb_add_key(secy, key);
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_remove_key
|
|
*===========================================================================
|
|
* Description: see "ipmacsec_secy_mgmt.h"
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE Ipmacsec_secy_key *
|
|
ipmacsec_secy_remove_key(Ipnet_secy *secy, Ipmacsec_secy_key_id *key_id) {
|
|
Ipmacsec_secy_key *key;
|
|
|
|
ip_assert(secy);
|
|
|
|
/* retrieve key from keydb (fail if it doesn't exist) */
|
|
key = ipmacsec_secy_keydb_find_key(secy, key_id);
|
|
if (!key) {
|
|
return IP_NULL;
|
|
}
|
|
|
|
if (key->inUse) {
|
|
return IP_NULL;
|
|
}
|
|
key->transmits = IP_FALSE;
|
|
key->receives = IP_FALSE;
|
|
key->inUse = IP_FALSE; /* redundant */
|
|
|
|
if (ipmacsec_secy_keydb_remove_key(secy, key) != 0) {
|
|
return IP_NULL;
|
|
}
|
|
|
|
return key;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_delete_all_keys
|
|
*===========================================================================
|
|
* Description: see "ipmacsec_secy_mgmt.h"
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE int
|
|
ipmacsec_secy_delete_all_keys(Ipnet_secy *secy, Ip_bool ignore_in_use) {
|
|
Ipmacsec_secy_key *key;
|
|
|
|
ip_assert(secy);
|
|
|
|
/* Delete all keys in hash table and clear hash table */
|
|
if (ipmacsec_secy_keydb_iter_init(secy) < 0) {
|
|
return -1;
|
|
}
|
|
for (;;) {
|
|
key = IP_NULL;
|
|
if (ipmacsec_secy_keydb_get_next_key(secy, &key) < 0) {
|
|
return -1;
|
|
}
|
|
if (!key)
|
|
break; /* No more keys */
|
|
if (!key->inUse || ignore_in_use) {
|
|
(void)ipmacsec_secy_keydb_remove_key(secy, key);
|
|
(void)ipmacsec_secy_delete_key(secy, key);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_get_tx_sc
|
|
*===========================================================================
|
|
* Description: see "ipmacsec_secy_mgmt.h"
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE Ipmacsec_secy_sc *
|
|
ipmacsec_secy_get_tx_sc(Ipnet_secy *secy) {
|
|
Ipmacsec_secy_sc *sc;
|
|
|
|
ip_assert(secy);
|
|
|
|
sc = secy->priv.tx_sc;
|
|
return sc;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_get_tx_sa
|
|
*===========================================================================
|
|
* Description: see "ipmacsec_secy_mgmt.h"
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE Ipmacsec_secy_sa *
|
|
ipmacsec_secy_get_tx_sa(Ipnet_secy *secy) {
|
|
Ipmacsec_secy_sc *sc;
|
|
Ipmacsec_secy_sa *sa;
|
|
|
|
ip_assert(secy);
|
|
|
|
sc = ipmacsec_secy_get_tx_sc(secy);
|
|
if (!sc || !sc->enabled) {
|
|
return IP_NULL;
|
|
}
|
|
if (sc->encodingSA >= IPMACSEC_MAX_SA) {
|
|
return IP_NULL;
|
|
}
|
|
if (!secy->config.maxTxKeys || (sc->encodingSA > (Ip_u32)(secy->config.maxTxKeys-1))){
|
|
return IP_NULL;
|
|
}
|
|
sa = &sc->sa[sc->encodingSA];
|
|
if (sa->sc != sc) {
|
|
return IP_NULL; /* Invalid SA */
|
|
}
|
|
return sa;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_lookup_tx_sa
|
|
*===========================================================================
|
|
* Description: see "ipmacsec_secy_mgmt.h"
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE Ipmacsec_secy_sa *
|
|
ipmacsec_secy_lookup_tx_sa(Ipnet_secy *secy, IP_CONST Ip_u8 an) {
|
|
Ipmacsec_secy_sc *sc;
|
|
Ipmacsec_secy_sa *sa;
|
|
|
|
ip_assert(secy);
|
|
|
|
sc = ipmacsec_secy_get_tx_sc(secy);
|
|
if (!sc || !sc->enabled) {
|
|
return IP_NULL;
|
|
}
|
|
if (sc->encodingSA >= IPMACSEC_MAX_SA){
|
|
return IP_NULL;
|
|
}
|
|
if (!secy->config.maxTxKeys || (an > (secy->config.maxTxKeys-1))){
|
|
return IP_NULL;
|
|
}
|
|
sa = &sc->sa[an];
|
|
if (sa->sc != sc) {
|
|
return IP_NULL; /* Invalid SA */
|
|
}
|
|
return sa;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_lookup_rx_sc
|
|
*===========================================================================
|
|
* Description: see "ipmacsec_secy_mgmt.h"
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE Ipmacsec_secy_sc *
|
|
ipmacsec_secy_lookup_rx_sc(Ipnet_secy *secy, IP_CONST Ip_u8 *sci) {
|
|
Ipmacsec_secy_sc *sc;
|
|
|
|
ip_assert(secy);
|
|
ip_assert(sci);
|
|
|
|
|
|
/* For now we support only one rx SC, so this is simple. Later we need a hash lookup */
|
|
sc = secy->priv.rx_sc;
|
|
if (!sc) {
|
|
return IP_NULL;
|
|
}
|
|
#ifndef IPMACSEC_UNIT_TEST_INLINE_HARDCODED_CONFIG
|
|
if (!IPMACSEC_SCI_MATCH(sci, sc->sci)) {
|
|
return IP_NULL;
|
|
}
|
|
#endif
|
|
return sc;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_lookup_rx_sa
|
|
*===========================================================================
|
|
* Description: see "ipmacsec_secy_mgmt.h"
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE Ipmacsec_secy_sa *
|
|
ipmacsec_secy_lookup_rx_sa(Ipnet_secy *secy, Ipmacsec_secy_sc *sc, IP_CONST Ip_u8 an) {
|
|
Ipmacsec_secy_sa *sa;
|
|
|
|
ip_assert(secy);
|
|
ip_assert(sc);
|
|
|
|
if (an >= IPMACSEC_MAX_SA){
|
|
return IP_NULL;
|
|
}
|
|
if (!secy->config.maxRxKeys || (an > (secy->config.maxRxKeys-1))) {
|
|
return IP_NULL;
|
|
}
|
|
if (!sc->enabled) {
|
|
return IP_NULL;
|
|
}
|
|
sa = &sc->sa[an];
|
|
if (sa->sc != sc) {
|
|
return IP_NULL; /* Invalid SA */
|
|
}
|
|
return sa;
|
|
|
|
/*
|
|
* The following is not very clear in the standard. Nothing is currently done
|
|
* to enforce this:
|
|
* (7.1.3): If any of the current SAs for inbound SCs are not usable, then the
|
|
* MAC_Operational status parameter (6.4) will transition to FALSE.
|
|
*
|
|
*/
|
|
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_lookup_rx_sa_sai
|
|
*===========================================================================
|
|
* Description: see "ipmacsec_secy_mgmt.h"
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE Ipmacsec_secy_sa *
|
|
ipmacsec_secy_lookup_rx_sa_sai(Ipnet_secy *secy, IP_CONST Ip_u8 *sci, IP_CONST Ip_u8 an) {
|
|
Ipmacsec_secy_sc *sc;
|
|
Ipmacsec_secy_sa *sa;
|
|
|
|
ip_assert(secy);
|
|
ip_assert(sci);
|
|
|
|
sc = ipmacsec_secy_lookup_rx_sc(secy, sci);
|
|
if (!sc) {
|
|
return IP_NULL;
|
|
}
|
|
sa = ipmacsec_secy_lookup_rx_sa(secy, sc, an);
|
|
return sa;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_check_rx_sa_interleave
|
|
*===========================================================================
|
|
* Description: see "ipmacsec_secy_mgmt.h"
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE int
|
|
ipmacsec_secy_check_rx_sa_interleave(Ipnet_secy *secy, Ipmacsec_secy_sa *sa) {
|
|
Ipmacsec_secy_sc *sc;
|
|
|
|
ip_assert(secy);
|
|
ip_assert(sa);
|
|
ip_assert(sa->inUse);
|
|
ip_assert(sa->key);
|
|
|
|
sc = sa->sc;
|
|
ip_assert(sc);
|
|
ip_assert(sc->dir == IPMACSEC_RX);
|
|
|
|
if (IPMACSEC_INVALID_AN(sc->newAN)) {
|
|
/* 1st ever received frame on this SC */
|
|
sc->newAN = sa->an;
|
|
return 0;
|
|
}
|
|
|
|
if ((sc->interleave_time) && ((ipnet_msec_now()- sc->interleave_time) >= IPMACSEC_RX_SA_INTERLEAVE_PERIOD)) {
|
|
/* Check if we exceed the interleave time (0.5 sec). If so, delete old SA/SAK */
|
|
Ipmacsec_secy_sa *old_sa = ipmacsec_secy_lookup_rx_sa(secy, sc, (Ip_u8)sc->oldAN);
|
|
if (old_sa) {
|
|
Ipmacsec_secy_key *key = old_sa->key;
|
|
(void)ipmacsec_secy_delete_rx_sa(secy, old_sa);
|
|
(void)ipmacsec_secy_remove_key(secy, &key->key_id);
|
|
(void)ipmacsec_secy_delete_key(secy, key);
|
|
}
|
|
sc->oldAN = IPMACSEC_MAX_SA; /* invalidate old SA */
|
|
sc->interleave_time = 0;
|
|
}
|
|
|
|
if (sa->an == sc->newAN) {
|
|
return 0;
|
|
}
|
|
/* Different than latest rcvd AN */
|
|
|
|
if (IPMACSEC_INVALID_AN(sc->oldAN)) {
|
|
/* 1st one that is different */
|
|
sc->oldAN = sc->newAN;
|
|
sc->newAN = sa->an;
|
|
sc->interleave_time = ipnet_msec_now();
|
|
return 0;
|
|
}
|
|
if (sa->an == sc->oldAN) {
|
|
return 0;
|
|
}
|
|
|
|
return -1; /* Neither old, nor new. Something is wrong */
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_cp_enable
|
|
*===========================================================================
|
|
* Description: see "ipmacsec_secy_mgmt.h"
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE int
|
|
ipmacsec_secy_cp_enable(Ipnet_secy *secy, Ip_bool enable) {
|
|
ip_assert(secy);
|
|
|
|
if (secy->controlled_port.ctrl.cp_enabled != enable){
|
|
secy->controlled_port.ctrl.cp_enabled = enable;
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG2(DEBUG2,"IPMACSEC-SECY_CRTL: ControlledPortEnabled set to %s for interface %s",
|
|
IPMACSEC_BOOL_STRING(enable), secy->netif->ipcom.name);
|
|
#endif
|
|
IPMACSEC_SECY_STATUS_NOTIFY(secy,
|
|
(enable ? IPMACSEC_STATUS_SECY_CP_ENABLED_ON : IPMACSEC_STATUS_SECY_CP_ENABLED_OFF));
|
|
}
|
|
(void)ipmacsec_secy_cp_update_status(secy, IPMACSEC_SECY_MAC_OPER_DEFAULT);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_cp_set_adminP2pMac
|
|
*===========================================================================
|
|
* Description: see "ipmacsec_secy_mgmt.h"
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE int
|
|
ipmacsec_secy_cp_set_adminP2pMac(Ipnet_secy *secy, Ip_portif_admin_ptp_mac_val admin_p2p_mac) {
|
|
ip_assert(secy);
|
|
|
|
secy->controlled_port.status.admin_ptp_mac = admin_p2p_mac;
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG3(DEBUG2,"IPMACSEC-SECY_CRTL: Controlled Port admin_ptp_mac set to %s (%d) for interface %s",
|
|
ipmacsec_secy_cp_adminPointToPointMAC_name(admin_p2p_mac), admin_p2p_mac, secy->netif->ipcom.name);
|
|
#endif
|
|
(void)ipmacsec_secy_cp_update_status(secy, IPMACSEC_SECY_MAC_OPER_DEFAULT);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_ucp_update_status_ext
|
|
*===========================================================================
|
|
* Description: see "ipmacsec_secy_mgmt.h"
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE int
|
|
ipmacsec_secy_ucp_update_status_ext(Ipnet_netif *netif) {
|
|
ip_assert(netif);
|
|
|
|
if (netif->secy) {
|
|
return ipmacsec_secy_ucp_update_status(netif->secy);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_ucp_update_status
|
|
*===========================================================================
|
|
* Description: see "ipmacsec_secy_mgmt.h"
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE int
|
|
ipmacsec_secy_ucp_update_status(Ipnet_secy *secy) {
|
|
ip_assert(secy);
|
|
|
|
/* 10.7.2 */
|
|
/* Retrieve from Common Port */
|
|
secy->uncontrolled_port.status.mac_enabled = IP_BIT_ISSET(secy->netif->ipcom.flags, IP_IFF_UP);
|
|
secy->uncontrolled_port.status.mac_oper = IP_BIT_ISSET(secy->netif->ipcom.flags, IP_IFF_RUNNING);
|
|
secy->uncontrolled_port.status.oper_ptp_mac = IP_BIT_ISSET(secy->netif->ipcom.flags, IP_IFF_POINTOPOINT);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_ucp_update_statistics
|
|
*===========================================================================
|
|
* Description: see "ipmacsec_secy_mgmt.h"
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE int
|
|
ipmacsec_secy_ucp_update_statistics(Ipnet_netif *netif) {
|
|
ip_assert(netif);
|
|
|
|
if (!netif->secy) {
|
|
return -1;
|
|
}
|
|
|
|
/* 10.7.3 */
|
|
#ifdef IPCOM_USE_MIB2
|
|
IPMACSEC_UCP_STATS(ifInOctets) = netif->ipcom.mib2.ifInOctets;
|
|
IPMACSEC_UCP_STATS(ifInUcastPkts) = netif->ipcom.mib2.ifInUcastPkts;
|
|
IPMACSEC_UCP_STATS(ifInMulticastPkts) = netif->ipcom.mib2.ifInMulticastPkts;
|
|
IPMACSEC_UCP_STATS(ifInBroadcastPkts) = netif->ipcom.mib2.ifInBroadcastPkts;
|
|
IPMACSEC_UCP_STATS(ifOutOctets) = netif->ipcom.mib2.ifOutOctets;
|
|
IPMACSEC_UCP_STATS(ifOutUcastPkts) = netif->ipcom.mib2.ifOutUcastPkts;
|
|
IPMACSEC_UCP_STATS(ifOutMulticastPkts) = netif->ipcom.mib2.ifOutMulticastPkts;
|
|
IPMACSEC_UCP_STATS(ifOutBroadcastPkts) = netif->ipcom.mib2.ifOutBroadcastPkts;
|
|
/* ifInDiscards, ifInErrors, ifOutErrors are always 0 for UCP */
|
|
return 0;
|
|
#else
|
|
return -1; /* Cannot retrieve Common Port stats since not kept */
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_cp_update_status_ext
|
|
*===========================================================================
|
|
* Description: see "ipmacsec_secy_mgmt.h"
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE int
|
|
ipmacsec_secy_cp_update_status_ext(Ipnet_netif *netif) {
|
|
ip_assert(netif);
|
|
|
|
if (netif->secy) {
|
|
return ipmacsec_secy_cp_update_status(netif->secy, IPMACSEC_SECY_MAC_OPER_DEFAULT);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_cp_update_status
|
|
*===========================================================================
|
|
* Description: see "ipmacsec_secy_mgmt.h"
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE int
|
|
ipmacsec_secy_cp_update_status(Ipnet_secy *secy, Ip_bool mac_oper_off) {
|
|
Ipnet_portif *cp;
|
|
Ipmacsec_secy_sc *sc;
|
|
Ip_bool transmitting = IP_FALSE, receiving = IP_FALSE, updated = IP_FALSE;
|
|
struct {
|
|
Ip_bool mac_enabled; /* MAC_Enabled */
|
|
Ip_bool mac_oper; /* MAC_Operational */
|
|
Ip_bool oper_ptp_mac; /* operPointToPointMAC */
|
|
} orig_status;
|
|
|
|
ip_assert(secy);
|
|
|
|
cp = &secy->controlled_port;
|
|
|
|
orig_status.mac_enabled = cp->status.mac_enabled;
|
|
orig_status.mac_oper = cp->status.mac_oper;
|
|
orig_status.oper_ptp_mac = cp->status.oper_ptp_mac;
|
|
|
|
/* 6.7; 10.7.4; A.7 */
|
|
sc = ipmacsec_secy_get_tx_sc(secy);
|
|
if (sc) {
|
|
transmitting = sc->oper.transmitting;
|
|
}
|
|
receiving = (secy->oper.numActiveRxSCs != 0);
|
|
|
|
cp->status.mac_enabled = IP_FALSE;
|
|
cp->status.mac_oper = IP_FALSE;
|
|
if (cp->ctrl.cp_enabled) {
|
|
Ip_bool secy_cp_mac_oper = IP_FALSE;
|
|
Ip_bool common_port_mac_enabled = IP_BIT_ISSET(secy->netif->ipcom.flags, IP_IFF_UP);
|
|
Ipmacsec_secy_sa *sa = ipmacsec_secy_get_tx_sa(secy);
|
|
if (sa) {
|
|
secy_cp_mac_oper = (sa->nextPN != 0);
|
|
}
|
|
cp->status.mac_enabled = common_port_mac_enabled && transmitting && receiving ;
|
|
if (!mac_oper_off && cp->status.mac_enabled && secy_cp_mac_oper) {
|
|
Ip_bool common_port_mac_oper = IP_BIT_ISSET(secy->netif->ipcom.flags, IP_IFF_RUNNING);
|
|
cp->status.mac_oper = common_port_mac_oper ;
|
|
}
|
|
}
|
|
|
|
if (cp->status.admin_ptp_mac == IP_PORTIF_ADMIN_PTP_MAC_FORCE_TRUE) {
|
|
cp->status.oper_ptp_mac = IP_TRUE;
|
|
goto done;
|
|
}
|
|
cp->status.oper_ptp_mac = IP_FALSE;
|
|
if (cp->status.admin_ptp_mac == IP_PORTIF_ADMIN_PTP_MAC_FORCE_FALSE) {
|
|
goto done;
|
|
}
|
|
if (cp->status.mac_oper && (cp->status.admin_ptp_mac == IP_PORTIF_ADMIN_PTP_MAC_FORCE_AUTO)) {
|
|
if (secy->ctrl.validateFrames == IPMACSEC_SECY_VALIDATEFRAMES_STRICT) {
|
|
cp->status.oper_ptp_mac = (secy->oper.numActiveRxSCs <= 1);
|
|
} else {
|
|
Ip_bool common_port_oper_ptp_mac = IP_BIT_ISSET(secy->netif->ipcom.flags, IP_IFF_POINTOPOINT);
|
|
cp->status.oper_ptp_mac = common_port_oper_ptp_mac;
|
|
}
|
|
}
|
|
done:
|
|
/* Need to notify KaY via LMI of any Controlled Port status changes */
|
|
if (orig_status.mac_enabled != cp->status.mac_enabled) {
|
|
IPMACSEC_SECY_STATUS_NOTIFY(secy,
|
|
((cp->status.mac_enabled) ? IPMACSEC_STATUS_SECY_CP_MAC_ENABLED_ON : IPMACSEC_STATUS_SECY_CP_MAC_ENABLED_OFF));
|
|
updated = IP_TRUE;
|
|
}
|
|
if (orig_status.mac_oper != cp->status.mac_oper) {
|
|
IPMACSEC_SECY_STATUS_NOTIFY(secy,
|
|
((cp->status.mac_oper) ? IPMACSEC_STATUS_SECY_CP_MAC_OPER_ON : IPMACSEC_STATUS_SECY_CP_MAC_OPER_OFF));
|
|
updated = IP_TRUE;
|
|
}
|
|
if (orig_status.oper_ptp_mac != cp->status.oper_ptp_mac) {
|
|
IPMACSEC_SECY_STATUS_NOTIFY(secy,
|
|
((cp->status.oper_ptp_mac) ? IPMACSEC_STATUS_SECY_CP_OPER_PTP_MAC_ON : IPMACSEC_STATUS_SECY_CP_OPER_PTP_MAC_OFF));
|
|
updated = IP_TRUE;
|
|
}
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
if (updated)
|
|
IPCOM_LOG5(DEBUG2,
|
|
"IPMACSEC-MGMT: CP status updated (cp_enabled %s, mac_enabled %s, mac_oper %s, oper_ptp_mac %s) for interface %s",
|
|
IPMACSEC_BOOL_STRING(cp->ctrl.cp_enabled), IPMACSEC_BOOL_STRING(cp->status.mac_enabled),
|
|
IPMACSEC_BOOL_STRING(cp->status.mac_oper), IPMACSEC_BOOL_STRING(cp->status.oper_ptp_mac), secy->netif->ipcom.name);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_cp_update_statistics
|
|
*===========================================================================
|
|
* Description: see "ipmacsec_secy_mgmt.h"
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE int
|
|
ipmacsec_secy_cp_update_statistics(Ipnet_netif *netif) {
|
|
int rc;
|
|
Ipnet_secy *secy;
|
|
|
|
ip_assert(netif);
|
|
|
|
secy = netif->secy;
|
|
if (!secy) {
|
|
rc = -1;
|
|
} else
|
|
#ifdef IPMACSEC_USE_STATS
|
|
/* 10.7.6 */
|
|
{
|
|
Ip_u8 an;
|
|
Ipmacsec_secy_sc *sc;
|
|
Ipmacsec_secy_counter64 inDisc=0, inErr=0;
|
|
if (ipmacsec_secy_rx_sc_iter_init(secy) < 0) {
|
|
return -1;
|
|
}
|
|
|
|
inDisc += IPMACSEC_SECY_STATS(InPktsNoTag) + IPMACSEC_SECY_STATS(InPktsOverrun);
|
|
inErr += IPMACSEC_SECY_STATS(InPktsBadTag) + IPMACSEC_SECY_STATS(InPktsNoSCI);
|
|
/* Add all RX SC stats */
|
|
for (;;) {
|
|
rc = ipmacsec_secy_get_next_rx_sc(secy, &sc);
|
|
if (rc < 0) {
|
|
return -1;
|
|
}
|
|
if (sc == IP_NULL) {
|
|
rc = 0;
|
|
break; /* No more SCs */
|
|
}
|
|
inDisc += IPMACSEC_SC_STATS(in.InPktsLate);
|
|
inErr += IPMACSEC_SC_STATS(aggr.rx.InPktsNotUsingSA) + IPMACSEC_SC_STATS(aggr.rx.InPktsNotValid);
|
|
for (an = 0; an < secy->config.maxRxKeys; an++) {
|
|
Ipmacsec_secy_sa *sa = &sc->sa[an];
|
|
inErr += IPMACSEC_SA_STATS(rx.InPktsNotUsingSA) + IPMACSEC_SA_STATS(rx.InPktsNotValid);
|
|
}
|
|
}
|
|
IPMACSEC_CP_STATS_SET(ifInDiscards, inDisc);
|
|
IPMACSEC_CP_STATS_SET(ifInErrors, inErr);
|
|
IPMACSEC_CP_STATS_SET(ifOutErrors, secy->stats.OutPktsTooLong);
|
|
rc = 0;
|
|
}
|
|
#else
|
|
{
|
|
rc = -1; /* CP stats not kept */
|
|
}
|
|
#endif
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_status_notify
|
|
*===========================================================================
|
|
* Description: see "ipmacsec_secy_mgmt.h"
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE int
|
|
ipmacsec_secy_status_notify(Ipnet_secy *secy, Ipmacsec_secy_status status, void *param, Ip_u32 param_size) {
|
|
Ipmacsec_buffer note;
|
|
Ipmacsec_secy_status theStatus = status;
|
|
struct Ip_nlmsghdr *nlmsg = IP_NULL;
|
|
int rc = 0;
|
|
|
|
ip_assert(secy);
|
|
ip_assert(secy->netif);
|
|
|
|
if (!IPMACSEC_SECY_STATUS_IS_VALID(theStatus)) {
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG2(ERR, "IPMACSEC-MGMT: Invalid status %u (interface %s)", theStatus, secy->netif->ipcom.name);
|
|
#endif
|
|
return -1;
|
|
}
|
|
|
|
IPMACSEC_BUF_INIT(¬e);
|
|
if (ipmacsec_nlmsg_alloc(¬e) == IP_NULL) {
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG1(ERR, "IPMACSEC-MGMT: note nlmsg alloc failed (interface %s)", secy->netif->ipcom.name);
|
|
#endif
|
|
rc = -1;
|
|
goto err_out;
|
|
}
|
|
nlmsg = ipmacsec_nlnote_add(¬e, IPMACSEC_NLTYPE_NOTIFY, IPMACSEC_LMINOTE_STATUS, secy->netif->ipcom.name);
|
|
if (nlmsg == IP_NULL) {
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG1(ERR, "IPMACSEC-MGMT: failed to add status note (interface %s)", secy->netif->ipcom.name);
|
|
#endif
|
|
rc = -1;
|
|
goto err_out;
|
|
}
|
|
if (ipmacsec_nlnote_add_param(¬e, nlmsg, &theStatus, sizeof(theStatus)) == IP_NULL) {
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG1(ERR, "IPMACSEC-MGMT: failed to add status param (interface %s)", secy->netif->ipcom.name);
|
|
#endif
|
|
rc = -1;
|
|
goto err_out;
|
|
}
|
|
if (param && param_size) {
|
|
if (ipmacsec_nlnote_add_param(¬e, nlmsg, param, param_size) == IP_NULL) {
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG1(ERR, "IPMACSEC-MGMT: failed to add optional status param (interface %s)", secy->netif->ipcom.name);
|
|
#endif
|
|
rc = -1;
|
|
goto err_out;
|
|
}
|
|
}
|
|
|
|
rc = ipmacsec_netlink_broadcast(secy, (Ip_u8 *)IP_NLMSG_DATA(nlmsg), (Ip_u32)IP_NLMSG_PAYLOAD(nlmsg, 0),
|
|
IPMACSEC_NLTYPE_NOTIFY, 0, IPMACSEC_NLGRP_NOTIFY);
|
|
|
|
err_out:
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
if (rc != 0) {
|
|
IPCOM_LOG3(ERR, "IPMACSEC-MGMT: failed to send status notification %s (%u) for interface %s",
|
|
ipmacsec_secy_status_name(theStatus), theStatus, secy->netif->ipcom.name);
|
|
} else {
|
|
IPCOM_LOG3(DEBUG2, "IPMACSEC-MGMT: successfully sent status notification %s (%u) for interface %s",
|
|
ipmacsec_secy_status_name(theStatus), theStatus, secy->netif->ipcom.name);
|
|
}
|
|
#endif
|
|
ipmacsec_nlmsg_free(¬e);
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_info_notify
|
|
*===========================================================================
|
|
* Description: see "ipmacsec_secy_mgmt.h"
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE int
|
|
ipmacsec_secy_info_notify(Ipnet_secy *secy, Ipmacsec_secy_info info, void *param, Ip_u32 param_size) {
|
|
Ipmacsec_buffer note;
|
|
Ipmacsec_secy_info theInfo = info;
|
|
struct Ip_nlmsghdr *nlmsg = IP_NULL;
|
|
int rc = 0;
|
|
|
|
ip_assert(secy);
|
|
ip_assert(secy->netif);
|
|
|
|
if (!IPMACSEC_SECY_INFO_IS_VALID(theInfo)) {
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG2(ERR, "IPMACSEC-MGMT: Invalid info %u (interface %s)", theInfo, secy->netif->ipcom.name);
|
|
#endif
|
|
return -1;
|
|
}
|
|
|
|
if (!secy->config.info_notify) {
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG3(DEBUG2, "IPMACSEC-MGMT: info_notify disabled, not sending info notification %s (%u) for interface %s",
|
|
ipmacsec_secy_info_name(theInfo), theInfo, secy->netif->ipcom.name);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
IPMACSEC_BUF_INIT(¬e);
|
|
if (ipmacsec_nlmsg_alloc(¬e) == IP_NULL) {
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG1(ERR, "IPMACSEC-MGMT: note nlmsg alloc failed (interface %s)", secy->netif->ipcom.name);
|
|
#endif
|
|
rc = -1;
|
|
goto err_out;
|
|
}
|
|
nlmsg = ipmacsec_nlnote_add(¬e, IPMACSEC_NLTYPE_NOTIFY, IPMACSEC_LMINOTE_INFO, secy->netif->ipcom.name);
|
|
if (nlmsg == IP_NULL) {
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG1(ERR, "IPMACSEC-MGMT: failed to add info note (interface %s)", secy->netif->ipcom.name);
|
|
#endif
|
|
rc = -1;
|
|
goto err_out;
|
|
}
|
|
if (ipmacsec_nlnote_add_param(¬e, nlmsg, &theInfo, sizeof(theInfo)) == IP_NULL) {
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG1(ERR, "IPMACSEC-MGMT: failed to add info param (interface %s)", secy->netif->ipcom.name);
|
|
#endif
|
|
rc = -1;
|
|
goto err_out;
|
|
}
|
|
if (param && param_size) {
|
|
if (ipmacsec_nlnote_add_param(¬e, nlmsg, param, param_size) == IP_NULL) {
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG1(ERR, "IPMACSEC-MGMT: failed to add optional info param (interface %s)", secy->netif->ipcom.name);
|
|
#endif
|
|
rc = -1;
|
|
goto err_out;
|
|
}
|
|
}
|
|
|
|
rc = ipmacsec_netlink_broadcast(secy, (Ip_u8 *)IP_NLMSG_DATA(nlmsg), (Ip_u32)IP_NLMSG_PAYLOAD(nlmsg, 0),
|
|
IPMACSEC_NLTYPE_NOTIFY, 0, IPMACSEC_NLGRP_MONITOR);
|
|
|
|
err_out:
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
if (rc != 0) {
|
|
IPCOM_LOG3(ERR, "IPMACSEC-MGMT: failed to send info notification %s (%u) for interface %s",
|
|
ipmacsec_secy_info_name(theInfo), theInfo, secy->netif->ipcom.name);
|
|
} else {
|
|
IPCOM_LOG3(DEBUG2, "IPMACSEC-MGMT: successfully sent info notification %s (%u) for interface %s",
|
|
ipmacsec_secy_info_name(theInfo), theInfo, secy->netif->ipcom.name);
|
|
}
|
|
#endif
|
|
ipmacsec_nlmsg_free(¬e);
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmacsec_secy_handle_nlcmd
|
|
*===========================================================================
|
|
* Description: Handler for MACsec netlink commands received from apps via
|
|
* netlink sockets.
|
|
* Parameters:
|
|
* Returns: 0 upon success, < 0 on error
|
|
*
|
|
*/
|
|
IPMACSEC_PRIVATE int
|
|
ipmacsec_secy_handle_nlcmd(Ipnet_secy *secy, struct Ip_nlmsghdr *nlmsg, Ip_bool non_blocking,
|
|
Ipmacsec_buffer *reply, Ip_pid_t src_pid) {
|
|
Ipmacsec_nlcmd_hdr *nlcmd;
|
|
Ip_bool isGet = IP_FALSE;
|
|
Ip_u32 param_size = 0;
|
|
int ret = -1;
|
|
IPCOM_UNUSED_ARG(non_blocking);
|
|
|
|
ip_assert(secy);
|
|
ip_assert(nlmsg);
|
|
|
|
nlcmd = ipmacsec_nlcmd_get(nlmsg);
|
|
if (!nlcmd) {
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG0(ERR, "IPMACSEC-MGMT: Failed to get MACsec netlink cmd");
|
|
#endif
|
|
return -1;
|
|
}
|
|
if (nlcmd->get) {
|
|
ip_assert(reply);
|
|
isGet = IP_TRUE;
|
|
}
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT_VERBOSE
|
|
IPCOM_LOG4(DEBUG2, "IPMACSEC-MGMT: Processing MACsec netlink cmd %d (%s), nltype %d (%s)",
|
|
nlcmd->command, ipmacsec_lmi_cmd_name(nlcmd->command),
|
|
nlmsg->nlmsg_type, ipmacsec_netlink_type_name(nlmsg->nlmsg_type));
|
|
#endif
|
|
if (nlmsg->nlmsg_type == IPMACSEC_NLTYPE_SECY_COMMAND) {
|
|
switch (nlcmd->command) {
|
|
case IPMACSEC_LMICMD_SECY_EXISTS:
|
|
if (!isGet) {
|
|
goto no_set;
|
|
} else {
|
|
/* "I receive, therefore I am" */
|
|
if (ipmacsec_nlcmd_response_add(reply, nlmsg, IP_NULL, 0, src_pid) == IP_NULL) {
|
|
ret = -1;
|
|
goto reply_fail;
|
|
}
|
|
ret = 0;
|
|
}
|
|
break;
|
|
case IPMACSEC_LMICMD_SECY_ENABLED:
|
|
if (isGet) {
|
|
Ip_bool enabled = secy->ctrl.enabled;
|
|
if (ipmacsec_nlcmd_response_add(reply, nlmsg, &enabled, sizeof(enabled), src_pid) == IP_NULL) {
|
|
ret = -1;
|
|
goto reply_fail;
|
|
}
|
|
ret = 0;
|
|
} else {
|
|
Ip_bool enable;
|
|
(void)ipmacsec_nlcmd_retrieve_init(nlmsg);
|
|
param_size = sizeof(enable);
|
|
ret = ipmacsec_nlcmd_retrieve_param(nlmsg, &enable, param_size);
|
|
if (ret < 0) {
|
|
goto param_ret_fail;
|
|
}
|
|
if (enable)
|
|
ret = ipmacsec_secy_enable(secy);
|
|
else
|
|
ret = ipmacsec_secy_disable(secy);
|
|
}
|
|
break;
|
|
case IPMACSEC_LMICMD_SECY_PROTECT_FRAMES:
|
|
case IPMACSEC_LMICMD_SECY_ALWAYS_INC_SCI:
|
|
case IPMACSEC_LMICMD_SECY_USE_ES:
|
|
case IPMACSEC_LMICMD_SECY_USE_SCB:
|
|
case IPMACSEC_LMICMD_SECY_REPLAY_PROTECT:
|
|
if (isGet) {
|
|
Ip_bool val;
|
|
if (nlcmd->command == IPMACSEC_LMICMD_SECY_PROTECT_FRAMES)
|
|
val = secy->ctrl.protectFrames;
|
|
else if (nlcmd->command == IPMACSEC_LMICMD_SECY_ALWAYS_INC_SCI)
|
|
val = secy->ctrl.alwaysIncludeSCI;
|
|
else if (nlcmd->command == IPMACSEC_LMICMD_SECY_USE_ES)
|
|
val = secy->ctrl.useES;
|
|
else if (nlcmd->command == IPMACSEC_LMICMD_SECY_USE_SCB)
|
|
val = secy->ctrl.useSCB;
|
|
else if (nlcmd->command == IPMACSEC_LMICMD_SECY_REPLAY_PROTECT)
|
|
val = secy->ctrl.replayProtect;
|
|
else {
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
if (ipmacsec_nlcmd_response_add(reply, nlmsg, &val, sizeof(val), src_pid) == IP_NULL) {
|
|
ret = -1;
|
|
goto reply_fail;
|
|
}
|
|
ret = 0;
|
|
} else {
|
|
Ip_bool val;
|
|
if (secy->ctrl.enabled) {
|
|
goto no_exec_enabled;
|
|
}
|
|
(void)ipmacsec_nlcmd_retrieve_init(nlmsg);
|
|
param_size = sizeof(val);
|
|
ret = ipmacsec_nlcmd_retrieve_param(nlmsg, &val, param_size);
|
|
if (ret < 0) {
|
|
goto param_ret_fail;
|
|
}
|
|
if (nlcmd->command == IPMACSEC_LMICMD_SECY_PROTECT_FRAMES) {
|
|
secy->ctrl.protectFrames = val;
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG2(DEBUG2,"IPMACSEC-SECY_CRTL: protectFrames set to %s for interface %s",
|
|
IPMACSEC_BOOL_STRING(secy->ctrl.protectFrames), secy->netif->ipcom.name);
|
|
#endif
|
|
} else if (nlcmd->command == IPMACSEC_LMICMD_SECY_ALWAYS_INC_SCI) {
|
|
secy->ctrl.alwaysIncludeSCI = val;
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG2(DEBUG2,"IPMACSEC-SECY_CRTL: alwaysIncludeSCI set to %s for interface %s",
|
|
IPMACSEC_BOOL_STRING(secy->ctrl.alwaysIncludeSCI), secy->netif->ipcom.name);
|
|
#endif
|
|
} else if (nlcmd->command == IPMACSEC_LMICMD_SECY_USE_ES) {
|
|
secy->ctrl.useES = val;
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG2(DEBUG2,"IPMACSEC-SECY_CRTL: useES set to %s for interface %s",
|
|
IPMACSEC_BOOL_STRING(secy->ctrl.useES), secy->netif->ipcom.name);
|
|
#endif
|
|
} else if (nlcmd->command == IPMACSEC_LMICMD_SECY_USE_SCB) {
|
|
secy->ctrl.useSCB = val;
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG2(DEBUG2,"IPMACSEC-SECY_CRTL: useSCB set to %s for interface %s",
|
|
IPMACSEC_BOOL_STRING(secy->ctrl.useSCB), secy->netif->ipcom.name);
|
|
#endif
|
|
} else if (nlcmd->command == IPMACSEC_LMICMD_SECY_REPLAY_PROTECT) {
|
|
secy->ctrl.replayProtect = val;
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG2(DEBUG2,"IPMACSEC-SECY_CRTL: replayProtect set to %s for interface %s",
|
|
IPMACSEC_BOOL_STRING(secy->ctrl.replayProtect), secy->netif->ipcom.name);
|
|
#endif
|
|
} else {
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
ret = 0;
|
|
}
|
|
break;
|
|
case IPMACSEC_LMICMD_SECY_VALIDATE_FRAMES:
|
|
if (isGet) {
|
|
Ipmacsec_validateFrames_type val;
|
|
val = secy->ctrl.validateFrames;
|
|
if (ipmacsec_nlcmd_response_add(reply, nlmsg, &val, sizeof(val), src_pid) == IP_NULL) {
|
|
ret = -1;
|
|
goto reply_fail;
|
|
}
|
|
ret = 0;
|
|
} else {
|
|
Ipmacsec_validateFrames_type val;
|
|
if (secy->ctrl.enabled) {
|
|
goto no_exec_enabled;
|
|
}
|
|
(void)ipmacsec_nlcmd_retrieve_init(nlmsg);
|
|
param_size = sizeof(val);
|
|
ret = ipmacsec_nlcmd_retrieve_param(nlmsg, &val, param_size);
|
|
if (ret < 0) {
|
|
goto param_ret_fail;
|
|
}
|
|
if (!IPMACSEC_VALIDATEFRAMES_VALID(val)) {
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG1(DEBUG2, "IPMACSEC-MGMT: Invalid validateFrames value %u.", (Ip_u32)val);
|
|
#endif
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
secy->ctrl.validateFrames = val;
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG3(DEBUG2, "IPMACSEC-MGMT: validateFrames set to %s (%d) for interface %s",
|
|
ipmacsec_secy_validateFrames_name(secy->ctrl.validateFrames), secy->ctrl.validateFrames,
|
|
secy->netif->ipcom.name);
|
|
#endif
|
|
ret = 0;
|
|
}
|
|
break;
|
|
case IPMACSEC_LMICMD_SECY_REPLAY_WINDOW:
|
|
if (isGet) {
|
|
Ip_u32 val;
|
|
val = secy->ctrl.replayWindow;
|
|
if (ipmacsec_nlcmd_response_add(reply, nlmsg, &val, sizeof(val), src_pid) == IP_NULL) {
|
|
ret = -1;
|
|
goto reply_fail;
|
|
}
|
|
ret = 0;
|
|
} else {
|
|
Ip_u32 val;
|
|
if (secy->ctrl.enabled) {
|
|
goto no_exec_enabled;
|
|
}
|
|
(void)ipmacsec_nlcmd_retrieve_init(nlmsg);
|
|
param_size = sizeof(val);
|
|
ret = ipmacsec_nlcmd_retrieve_param(nlmsg, &val, param_size);
|
|
if (ret < 0) {
|
|
goto param_ret_fail;
|
|
}
|
|
secy->ctrl.replayWindow = val;
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG2(DEBUG2,"IPMACSEC-SECY_CRTL: replayWindow set to %u for interface %s",
|
|
secy->ctrl.replayWindow, secy->netif->ipcom.name);
|
|
#endif
|
|
ret = 0;
|
|
}
|
|
break;
|
|
case IPMACSEC_LMICMD_SECY_TX_SCI:
|
|
if (isGet) {
|
|
if (ipmacsec_nlcmd_response_add(reply, nlmsg, secy->config.sci, sizeof(secy->config.sci), src_pid) == IP_NULL) {
|
|
ret = -1;
|
|
goto reply_fail;
|
|
}
|
|
ret = 0;
|
|
} else {
|
|
Ip_u8 sci[IPMACSEC_SCI_LEN];
|
|
Ipmacsec_secy_sc *tx_sc = IP_NULL;
|
|
if (secy->ctrl.enabled) {
|
|
goto no_exec_enabled;
|
|
}
|
|
(void)ipmacsec_nlcmd_retrieve_init(nlmsg);
|
|
param_size = sizeof(sci);
|
|
ret = ipmacsec_nlcmd_retrieve_param(nlmsg, sci, param_size);
|
|
if (ret < 0) {
|
|
goto param_ret_fail;
|
|
}
|
|
tx_sc = ipmacsec_secy_get_tx_sc(secy);
|
|
if (tx_sc && (!IPMACSEC_SCI_MATCH(sci, tx_sc->sci))) {
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG9(ERR,
|
|
"IPMACSEC-MGMT: Cannot set SecY SCI value (%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x) for interface %s "
|
|
"(mismatch with existing TX SC SCI)",
|
|
sci[0], sci[1], sci[2], sci[3], sci[4], sci[5], sci[6], sci[7],
|
|
secy->netif->ipcom.name);
|
|
#endif
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
IPMACSEC_COPY_SCI(secy->config.sci, sci);
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG9(INFO,
|
|
"IPMACSEC-MGMT: SecY SCI value (%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x) set for interface %s ",
|
|
secy->config.sci[0], secy->config.sci[1], secy->config.sci[2], secy->config.sci[3],
|
|
secy->config.sci[4], secy->config.sci[5], secy->config.sci[6], secy->config.sci[7],
|
|
secy->netif->ipcom.name);
|
|
#endif
|
|
ret = 0;
|
|
}
|
|
break;
|
|
case IPMACSEC_LMICMD_SECY_MAX_RX_SC:
|
|
case IPMACSEC_LMICMD_SECY_MAX_RX_KEYS:
|
|
case IPMACSEC_LMICMD_SECY_MAX_TX_KEYS:
|
|
if (!isGet) {
|
|
goto no_set;
|
|
} else {
|
|
Ip_u16 val;
|
|
if (nlcmd->command == IPMACSEC_LMICMD_SECY_MAX_RX_SC)
|
|
val = secy->config.maxRxSCs;
|
|
else if (nlcmd->command == IPMACSEC_LMICMD_SECY_MAX_RX_KEYS)
|
|
val = secy->config.maxRxKeys;
|
|
else if (nlcmd->command == IPMACSEC_LMICMD_SECY_MAX_TX_KEYS)
|
|
val = secy->config.maxTxKeys;
|
|
else {
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
if (ipmacsec_nlcmd_response_add(reply, nlmsg, &val, sizeof(val), src_pid) == IP_NULL) {
|
|
ret = -1;
|
|
goto reply_fail;
|
|
}
|
|
ret = 0;
|
|
}
|
|
break;
|
|
case IPMACSEC_LMICMD_SECY_PN_THRESHOLD:
|
|
if (isGet) {
|
|
Ip_u32 threshold = secy->config.pn_threshold;
|
|
if (ipmacsec_nlcmd_response_add(reply, nlmsg, &threshold, sizeof(threshold), src_pid) == IP_NULL) {
|
|
ret = -1;
|
|
goto reply_fail;
|
|
}
|
|
ret = 0;
|
|
} else {
|
|
Ip_u32 threshold;
|
|
(void)ipmacsec_nlcmd_retrieve_init(nlmsg);
|
|
param_size = sizeof(threshold);
|
|
ret = ipmacsec_nlcmd_retrieve_param(nlmsg, &threshold, param_size);
|
|
if (ret < 0) {
|
|
goto param_ret_fail;
|
|
}
|
|
if (threshold == 0) {
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
secy->config.pn_threshold = threshold;
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG2(DEBUG2,"IPMACSEC-SECY_CRTL: pn_threshold set to %u for interface %s",
|
|
secy->config.pn_threshold, secy->netif->ipcom.name);
|
|
#endif
|
|
ret = 0;
|
|
}
|
|
break;
|
|
case IPMACSEC_LMICMD_SECY_INFO_NOTIFY:
|
|
if (isGet) {
|
|
Ip_bool info_notify = secy->config.info_notify;
|
|
if (ipmacsec_nlcmd_response_add(reply, nlmsg, &info_notify, sizeof(info_notify), src_pid) == IP_NULL) {
|
|
ret = -1;
|
|
goto reply_fail;
|
|
}
|
|
ret = 0;
|
|
} else {
|
|
Ip_bool info_notify;
|
|
(void)ipmacsec_nlcmd_retrieve_init(nlmsg);
|
|
param_size = sizeof(info_notify);
|
|
ret = ipmacsec_nlcmd_retrieve_param(nlmsg, &info_notify, param_size);
|
|
if (ret < 0) {
|
|
goto param_ret_fail;
|
|
}
|
|
secy->config.info_notify = info_notify;
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG2(DEBUG2,"IPMACSEC-SECY_CRTL: info_notify set to %s for interface %s",
|
|
IPMACSEC_BOOL_STRING(secy->config.info_notify), secy->netif->ipcom.name);
|
|
#endif
|
|
ret = 0;
|
|
}
|
|
break;
|
|
case IPMACSEC_LMICMD_SECY_CONFIDENTIALITY_OFFSET:
|
|
if (isGet) {
|
|
Ip_u16 confidentialityOffset = secy->config.confidentialityOffset;
|
|
if (ipmacsec_nlcmd_response_add(reply, nlmsg, &confidentialityOffset,
|
|
sizeof(confidentialityOffset), src_pid) == IP_NULL) {
|
|
ret = -1;
|
|
goto reply_fail;
|
|
}
|
|
ret = 0;
|
|
} else {
|
|
Ip_u16 confidentialityOffset;
|
|
if (secy->ctrl.enabled) {
|
|
goto no_exec_enabled;
|
|
}
|
|
(void)ipmacsec_nlcmd_retrieve_init(nlmsg);
|
|
param_size = sizeof(confidentialityOffset);
|
|
ret = ipmacsec_nlcmd_retrieve_param(nlmsg, &confidentialityOffset, param_size);
|
|
if (ret < 0) {
|
|
goto param_ret_fail;
|
|
}
|
|
if (!IPMACSEC_SECY_VERIFY_CONFIDENTIALITY_OFFSET(confidentialityOffset)) {
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
secy->config.confidentialityOffset = confidentialityOffset;
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG2(DEBUG2,"IPMACSEC-SECY_CRTL: confidentialityOffset set to %u for interface %s",
|
|
secy->config.confidentialityOffset, secy->netif->ipcom.name);
|
|
#endif
|
|
ret = 0;
|
|
}
|
|
break;
|
|
case IPMACSEC_LMICMD_SECY_CURRENT_CIPHER_SUITE:
|
|
if (isGet) {
|
|
Ipmacsec_ciphersuite_descriptor descriptor;
|
|
Ipmacsec_cipher_suite_index indx = secy->config.cipher_suite_index;
|
|
ret = ipmacsec_crypto_cipher_suite_get_info(indx, &descriptor);
|
|
if (ret != 0) {
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
if (ipmacsec_nlcmd_response_add(reply, nlmsg, &descriptor, sizeof(descriptor), src_pid) == IP_NULL) {
|
|
ret = -1;
|
|
goto reply_fail;
|
|
}
|
|
ret = 0;
|
|
} else {
|
|
Ipmacsec_cipher_suite_index indx;
|
|
if (secy->ctrl.enabled) {
|
|
goto no_exec_enabled;
|
|
}
|
|
if (secy->oper.numCreatedRxSCs || ipmacsec_secy_get_tx_sc(secy)) {
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG2(ERR,"IPMACSEC-SECY_CRTL: Cannot set cipher_suite_index %u for interface %s"
|
|
" (one or more SCs already created)",
|
|
indx, secy->netif->ipcom.name);
|
|
#endif
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
(void)ipmacsec_nlcmd_retrieve_init(nlmsg);
|
|
param_size = sizeof(indx);
|
|
ret = ipmacsec_nlcmd_retrieve_param(nlmsg, &indx, param_size);
|
|
if (ret < 0) {
|
|
goto param_ret_fail;
|
|
}
|
|
if (!ipmacsec_crypto_cipher_suite_supported(indx)) {
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
secy->config.cipher_suite_index = indx;
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG2(DEBUG2,"IPMACSEC-SECY_CRTL: cipher_suite_index set to %u for interface %s",
|
|
secy->config.cipher_suite_index, secy->netif->ipcom.name);
|
|
#endif
|
|
ret = 0;
|
|
}
|
|
break;
|
|
case IPMACSEC_LMICMD_SECY_CIPHER_SUITE_LIST:
|
|
case IPMACSEC_LMICMD_SECY_CIPHER_SUITE_INFO:
|
|
if (!isGet) {
|
|
goto no_set;
|
|
} else {
|
|
Ipmacsec_cipher_suite_index index_start = __IPMACSEC_CIPHERSUITE_INVALID+1;
|
|
Ipmacsec_cipher_suite_index index_end = __IPMACSEC_CIPHERSUITE_MAX;
|
|
Ipmacsec_cipher_suite_index indx;
|
|
struct Ip_nlmsghdr *nlresp = IP_NULL;
|
|
if (nlcmd->command == IPMACSEC_LMICMD_SECY_CIPHER_SUITE_INFO) {
|
|
(void)ipmacsec_nlcmd_retrieve_init(nlmsg);
|
|
param_size = sizeof(indx);
|
|
ret = ipmacsec_nlcmd_retrieve_param(nlmsg, &indx, param_size);
|
|
if (ret < 0) {
|
|
goto param_ret_fail;
|
|
}
|
|
index_start = indx;
|
|
index_end = index_start+1;
|
|
}
|
|
nlresp = ipmacsec_nlcmd_response_add(reply, nlmsg, IP_NULL, 0, src_pid);
|
|
if (nlresp == IP_NULL) {
|
|
ret = -1;
|
|
goto reply_fail;
|
|
}
|
|
for (indx = index_start; indx < index_end; indx++) {
|
|
Ipmacsec_ciphersuite_descriptor descriptor;
|
|
ret = ipmacsec_crypto_cipher_suite_get_info(indx, &descriptor);
|
|
if (ret != 0) {
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
ret = ipmacsec_nlcmd_add_param(reply, nlresp, &descriptor, sizeof(descriptor));
|
|
if (ret < (int)sizeof(descriptor)) {
|
|
ret = -1;
|
|
goto reply_fail;
|
|
}
|
|
}
|
|
ret = 0;
|
|
}
|
|
break;
|
|
case IPMACSEC_LMICMD_SECY_NUM_RX_SC_ACTIVE:
|
|
case IPMACSEC_LMICMD_SECY_NUM_RX_SC_CREATED:
|
|
if (!isGet) {
|
|
goto no_set;
|
|
} else {
|
|
Ip_u16 val;
|
|
if (nlcmd->command == IPMACSEC_LMICMD_SECY_NUM_RX_SC_ACTIVE)
|
|
val = secy->oper.numActiveRxSCs;
|
|
else if (nlcmd->command == IPMACSEC_LMICMD_SECY_NUM_RX_SC_CREATED)
|
|
val = secy->oper.numCreatedRxSCs;
|
|
else {
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
if (ipmacsec_nlcmd_response_add(reply, nlmsg, &val, sizeof(val), src_pid) == IP_NULL) {
|
|
ret = -1;
|
|
goto reply_fail;
|
|
}
|
|
ret = 0;
|
|
}
|
|
break;
|
|
case IPMACSEC_LMICMD_SECY_KEY_INSTALL:
|
|
if (isGet) {
|
|
goto no_get;
|
|
} else {
|
|
Ipmacsec_secy_key *key;
|
|
Ipmacsec_secy_sak sak;
|
|
Ipmacsec_secy_key_descriptor key_desc;
|
|
(void)ipmacsec_nlcmd_retrieve_init(nlmsg);
|
|
param_size = sizeof(key_desc);
|
|
ret = ipmacsec_nlcmd_retrieve_param(nlmsg, &key_desc, param_size);
|
|
if (ret < 0) {
|
|
goto param_ret_fail;
|
|
}
|
|
sak.num_octets = key_desc.key_size;
|
|
sak.buf = ipcom_malloc(sak.num_octets);
|
|
if (sak.buf == IP_NULL) {
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
param_size = sak.num_octets;
|
|
ret = ipmacsec_nlcmd_retrieve_param(nlmsg, sak.buf, param_size);
|
|
if (ret < 0) {
|
|
goto param_ret_fail;
|
|
}
|
|
key = ipmacsec_secy_create_key(secy, &sak, &key_desc.key_id);
|
|
if (!key) {
|
|
ipcom_free(sak.buf);
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
ret = ipmacsec_secy_install_key(secy, key, key_desc.key_type);
|
|
}
|
|
break;
|
|
case IPMACSEC_LMICMD_SECY_KEY_REMOVE:
|
|
if (isGet) {
|
|
goto no_get;
|
|
} else {
|
|
Ipmacsec_secy_key *key;
|
|
Ipmacsec_secy_key_descriptor key_desc;
|
|
(void)ipmacsec_nlcmd_retrieve_init(nlmsg);
|
|
param_size = sizeof(key_desc);
|
|
ret = ipmacsec_nlcmd_retrieve_param(nlmsg, &key_desc, param_size);
|
|
if (ret < 0) {
|
|
goto param_ret_fail;
|
|
}
|
|
key = ipmacsec_secy_remove_key(secy, &key_desc.key_id);
|
|
if (key == IP_NULL) {
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
ret = ipmacsec_secy_delete_key(secy, key);
|
|
if (ret != 0) {
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
ret = 0;
|
|
}
|
|
break;
|
|
case IPMACSEC_LMICMD_SECY_KEY_PURGE:
|
|
if (isGet) {
|
|
goto no_get;
|
|
} else {
|
|
ret = ipmacsec_secy_delete_all_keys(secy, IP_FALSE);
|
|
if (ret != 0) {
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
ret = 0;
|
|
}
|
|
break;
|
|
case IPMACSEC_LMICMD_SECY_KEY_INFO:
|
|
if (!isGet) {
|
|
goto no_set;
|
|
} else {
|
|
Ipmacsec_secy_key *key;
|
|
Ipmacsec_secy_key_descriptor key_desc;
|
|
(void)ipmacsec_nlcmd_retrieve_init(nlmsg);
|
|
param_size = sizeof(key_desc);
|
|
ret = ipmacsec_nlcmd_retrieve_param(nlmsg, &key_desc, param_size);
|
|
if (ret < 0) {
|
|
goto param_ret_fail;
|
|
}
|
|
key = ipmacsec_secy_retrieve_key(secy, &key_desc.key_id, &key_desc);
|
|
if (!key) {
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
if (ipmacsec_nlcmd_response_add(reply, nlmsg, &key_desc, sizeof(key_desc), src_pid) == IP_NULL) {
|
|
ret = -1;
|
|
goto reply_fail;
|
|
}
|
|
ret = 0;
|
|
}
|
|
break;
|
|
case IPMACSEC_LMICMD_SECY_KEY_LIST:
|
|
if (!isGet) {
|
|
goto no_set;
|
|
} else {
|
|
Ipmacsec_secy_key *key;
|
|
Ipmacsec_secy_key_descriptor key_desc;
|
|
struct Ip_nlmsghdr *nlresp = IP_NULL;
|
|
/* Retrieve all keys in hash table and return info */
|
|
if (ipmacsec_secy_keydb_iter_init(secy) < 0) {
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
nlresp = ipmacsec_nlcmd_response_add(reply, nlmsg, IP_NULL, 0, src_pid);
|
|
if (nlresp == IP_NULL) {
|
|
ret = -1;
|
|
goto reply_fail;
|
|
}
|
|
for (;;) {
|
|
key = IP_NULL;
|
|
ret = ipmacsec_secy_keydb_get_next_key(secy, &key);
|
|
if (ret < 0) {
|
|
goto exec_fail;
|
|
}
|
|
if (key == IP_NULL) {
|
|
ret = 0;
|
|
break; /* No more keys */
|
|
}
|
|
if (ipmacsec_secy_retrieve_key_info(secy, key, &key_desc) == IP_NULL) {
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
ret = ipmacsec_nlcmd_add_param(reply, nlresp, &key_desc, sizeof(key_desc));
|
|
if (ret < (int)sizeof(key_desc)) {
|
|
ret = -1;
|
|
goto reply_fail;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case IPMACSEC_LMICMD_SECY_RX_SC_CREATE:
|
|
case IPMACSEC_LMICMD_SECY_RX_SC_DELETE:
|
|
if (isGet) {
|
|
goto no_get;
|
|
} else {
|
|
Ip_u8 sci[IPMACSEC_SCI_LEN];
|
|
(void)ipmacsec_nlcmd_retrieve_init(nlmsg);
|
|
param_size = sizeof(sci);
|
|
ret = ipmacsec_nlcmd_retrieve_param(nlmsg, sci, param_size);
|
|
if (ret < 0) {
|
|
goto param_ret_fail;
|
|
}
|
|
if (nlcmd->command == IPMACSEC_LMICMD_SECY_RX_SC_CREATE) {
|
|
if (ipmacsec_secy_create_rx_sc(secy, sci) == IP_NULL) {
|
|
ret = -1;
|
|
} else {
|
|
ret = 0 ;
|
|
}
|
|
} else {
|
|
Ipmacsec_secy_sc *sc;
|
|
sc = ipmacsec_secy_lookup_rx_sc(secy, sci);
|
|
if (!sc) {
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG8(ERR, "IPMACSEC-MGMT: RX SC not found. Cannot delete RX SC (SCI = "
|
|
"%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x)",
|
|
sci[0],sci[1],sci[2],sci[3],sci[4],sci[5],sci[6],sci[7]);
|
|
#endif
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
ret = ipmacsec_secy_delete_rx_sc(secy, sc);
|
|
}
|
|
if (ret < 0) {
|
|
goto exec_fail;
|
|
}
|
|
ret = 0;
|
|
}
|
|
break;
|
|
case IPMACSEC_LMICMD_SECY_TX_SC_CREATE:
|
|
case IPMACSEC_LMICMD_SECY_TX_SC_DELETE:
|
|
if (isGet) {
|
|
goto no_get;
|
|
} else {
|
|
if (nlcmd->command == IPMACSEC_LMICMD_SECY_TX_SC_CREATE) {
|
|
if (ipmacsec_secy_create_tx_sc(secy) == IP_NULL) {
|
|
ret = -1;
|
|
} else {
|
|
ret = 0 ;
|
|
}
|
|
} else {
|
|
ret = ipmacsec_secy_delete_tx_sc(secy);
|
|
}
|
|
if (ret < 0) {
|
|
goto exec_fail;
|
|
}
|
|
ret = 0;
|
|
}
|
|
break;
|
|
case IPMACSEC_LMICMD_SECY_RX_SC_STATUS:
|
|
case IPMACSEC_LMICMD_SECY_TX_SC_STATUS:
|
|
if (!isGet) {
|
|
goto no_set;
|
|
} else {
|
|
Ip_u8 sci[IPMACSEC_SCI_LEN];
|
|
Ipmacsec_secy_sc *sc;
|
|
Ipmacsec_secy_sc_info sc_info;
|
|
if (nlcmd->command == IPMACSEC_LMICMD_SECY_RX_SC_STATUS) {
|
|
(void)ipmacsec_nlcmd_retrieve_init(nlmsg);
|
|
param_size = sizeof(sci);
|
|
ret = ipmacsec_nlcmd_retrieve_param(nlmsg, sci, param_size);
|
|
if (ret < 0) {
|
|
goto param_ret_fail;
|
|
}
|
|
sc = ipmacsec_secy_lookup_rx_sc(secy, sci);
|
|
} else /* IPMACSEC_LMICMD_SECY_TX_SC_STATUS */ {
|
|
sc = ipmacsec_secy_get_tx_sc(secy);
|
|
}
|
|
if (!sc) {
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
if (nlcmd->command == IPMACSEC_LMICMD_SECY_RX_SC_STATUS) {
|
|
IPCOM_LOG8(ERR, "IPMACSEC-MGMT: RX SC not found (SCI = "
|
|
"%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x)",
|
|
sci[0],sci[1],sci[2],sci[3],
|
|
sci[4],sci[5],sci[6],sci[7]);
|
|
}
|
|
#endif
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
(void)ipmacsec_secy_fill_sc_info(secy, sc, &sc_info);
|
|
if (ipmacsec_nlcmd_response_add(reply, nlmsg, &sc_info, sizeof(sc_info), src_pid) == IP_NULL) {
|
|
ret = -1;
|
|
goto reply_fail;
|
|
}
|
|
ret = 0;
|
|
}
|
|
break;
|
|
case IPMACSEC_LMICMD_SECY_RX_SC_LIST:
|
|
if (!isGet) {
|
|
goto no_set;
|
|
} else {
|
|
struct Ip_nlmsghdr *nlresp = IP_NULL;
|
|
/* Retrieve all Rx SCs and return info */
|
|
if (ipmacsec_secy_rx_sc_iter_init(secy) < 0) {
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
nlresp = ipmacsec_nlcmd_response_add(reply, nlmsg, IP_NULL, 0, src_pid);
|
|
if (nlresp == IP_NULL) {
|
|
ret = -1;
|
|
goto reply_fail;
|
|
}
|
|
for (;;) {
|
|
Ipmacsec_secy_sc_info sc_info;
|
|
Ipmacsec_secy_sc *sc= IP_NULL;
|
|
ret = ipmacsec_secy_get_next_rx_sc(secy, &sc);
|
|
if (ret < 0) {
|
|
goto exec_fail;
|
|
}
|
|
if (sc == IP_NULL) {
|
|
ret = 0;
|
|
break; /* No more SCs */
|
|
}
|
|
(void)ipmacsec_secy_fill_sc_info(secy, sc, &sc_info);
|
|
ret = ipmacsec_nlcmd_add_param(reply, nlresp, &sc_info, sizeof(sc_info));
|
|
if (ret < (int)sizeof(sc_info)) {
|
|
ret = -1;
|
|
goto reply_fail;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case IPMACSEC_LMICMD_SECY_RX_SA_CREATE:
|
|
case IPMACSEC_LMICMD_SECY_RX_SA_DELETE:
|
|
case IPMACSEC_LMICMD_SECY_RX_SA_CONTROL:
|
|
case IPMACSEC_LMICMD_SECY_TX_SA_CREATE:
|
|
case IPMACSEC_LMICMD_SECY_TX_SA_DELETE:
|
|
case IPMACSEC_LMICMD_SECY_TX_SA_CONTROL:
|
|
if (isGet) {
|
|
goto no_get;
|
|
} else {
|
|
Ipmacsec_secy_sa_descriptor sa_desc;
|
|
Ipmacsec_secy_sa_info sa_info;
|
|
Ipmacsec_secy_sa_ctrl sa_ctrl;
|
|
Ipmacsec_secy_sc *sc = IP_NULL;
|
|
Ipmacsec_dir dir;
|
|
ipcom_memset(&sa_info, 0, sizeof(sa_info));
|
|
ipcom_memset(&sa_ctrl, 0, sizeof(sa_ctrl));
|
|
(void)ipmacsec_nlcmd_retrieve_init(nlmsg);
|
|
param_size = sizeof(sa_desc);
|
|
ret = ipmacsec_nlcmd_retrieve_param(nlmsg, &sa_desc, param_size);
|
|
if (ret < 0) {
|
|
goto param_ret_fail;
|
|
}
|
|
if ((nlcmd->command == IPMACSEC_LMICMD_SECY_RX_SA_CREATE) ||
|
|
(nlcmd->command == IPMACSEC_LMICMD_SECY_RX_SA_DELETE) ||
|
|
(nlcmd->command == IPMACSEC_LMICMD_SECY_RX_SA_CONTROL)) {
|
|
dir = IPMACSEC_RX;
|
|
sc = ipmacsec_secy_lookup_rx_sc(secy, sa_desc.sci);
|
|
if (!sc) {
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG8(ERR, "IPMACSEC-MGMT: RX SC not found (SCI = "
|
|
"%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x)",
|
|
sa_desc.sci[0],sa_desc.sci[1],sa_desc.sci[2],sa_desc.sci[3],
|
|
sa_desc.sci[4],sa_desc.sci[5],sa_desc.sci[6],sa_desc.sci[7]);
|
|
#endif
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
} else if ((nlcmd->command == IPMACSEC_LMICMD_SECY_TX_SA_CREATE) ||
|
|
(nlcmd->command == IPMACSEC_LMICMD_SECY_TX_SA_DELETE) ||
|
|
(nlcmd->command == IPMACSEC_LMICMD_SECY_TX_SA_CONTROL)) {
|
|
dir = IPMACSEC_TX;
|
|
} else {
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
(void)ipmacsec_nlcmd_retrieve_init(nlmsg);
|
|
param_size = sizeof(sa_desc);
|
|
ret = ipmacsec_nlcmd_retrieve_param(nlmsg, &sa_desc, param_size);
|
|
if (ret < 0) {
|
|
goto param_ret_fail;
|
|
}
|
|
if ((nlcmd->command == IPMACSEC_LMICMD_SECY_RX_SA_CREATE) ||
|
|
(nlcmd->command == IPMACSEC_LMICMD_SECY_TX_SA_CREATE)) {
|
|
Ipmacsec_secy_key_descriptor key_desc;
|
|
Ipmacsec_secy_key *key = ipmacsec_secy_retrieve_key(secy, &sa_desc.key_id, &key_desc);
|
|
if (!key) {
|
|
ret = -1;
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG1(ERR, "IPMACSEC-MGMT: Cannot create RX SA. Key not found (key_id = 0x%llx)",
|
|
sa_desc.key_id.val);
|
|
#endif
|
|
goto exec_fail;
|
|
}
|
|
param_size = sizeof(sa_info);
|
|
ret = ipmacsec_nlcmd_retrieve_param(nlmsg, &sa_info, param_size);
|
|
if (ret < 0) {
|
|
goto param_ret_fail;
|
|
}
|
|
if (nlcmd->command == IPMACSEC_LMICMD_SECY_RX_SA_CREATE) {
|
|
Ipmacsec_secy_sa *sa = ipmacsec_secy_lookup_rx_sa(secy, sc, sa_desc.an);
|
|
if (sa) {
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG1(ERR, "IPMACSEC-MGMT: Cannot create RX SA. SA Exists (an = %u)",
|
|
sa_desc.an);
|
|
#endif
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
sa = ipmacsec_secy_create_rx_sa(secy, sc, sa_desc.an, sa_desc.ref, sa_info.config.rx.nextPN,
|
|
sa_info.config.rx.lowestPN, key);
|
|
if (!sa) {
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
ret = 0;
|
|
} else if (nlcmd->command == IPMACSEC_LMICMD_SECY_TX_SA_CREATE) {
|
|
Ipmacsec_secy_sa *sa = ipmacsec_secy_lookup_tx_sa(secy, sa_desc.an);
|
|
if (sa) {
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG1(ERR, "IPMACSEC-MGMT: Cannot create TX SA. SA Exists (an = %u)",
|
|
sa_desc.an);
|
|
#endif
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
sa = ipmacsec_secy_create_tx_sa(secy, sa_desc.an, sa_desc.ref, sa_info.config.tx.nextPN,
|
|
sa_info.config.tx.confidentiality, key);
|
|
if (!sa) {
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG1(ERR, "IPMACSEC-MGMT: Cannot create TX SA. SA Exists (an = %u)",
|
|
sa_desc.an);
|
|
#endif
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
ret = 0;
|
|
} else {
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
} else if ((nlcmd->command == IPMACSEC_LMICMD_SECY_RX_SA_DELETE) ||
|
|
(nlcmd->command == IPMACSEC_LMICMD_SECY_TX_SA_DELETE)) {
|
|
Ipmacsec_secy_sa *sa = IP_NULL;
|
|
if (nlcmd->command == IPMACSEC_LMICMD_SECY_RX_SA_DELETE)
|
|
sa = ipmacsec_secy_lookup_rx_sa(secy, sc, sa_desc.an);
|
|
else if (nlcmd->command == IPMACSEC_LMICMD_SECY_TX_SA_DELETE)
|
|
sa = ipmacsec_secy_lookup_tx_sa(secy, sa_desc.an);
|
|
if (!sa || sa->ref != sa_desc.ref) {
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG3(ERR, "IPMACSEC-MGMT: Cannot delete %s SA. SA not found (an: %u, ref: 0x%x)",
|
|
IPMACSEC_DIR_STRING(dir), sa_desc.an, sa_desc.ref);
|
|
#endif
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
ret = -1;
|
|
if (nlcmd->command == IPMACSEC_LMICMD_SECY_RX_SA_DELETE)
|
|
ret = ipmacsec_secy_delete_rx_sa(secy, sa);
|
|
else if (nlcmd->command == IPMACSEC_LMICMD_SECY_TX_SA_DELETE)
|
|
ret = ipmacsec_secy_delete_tx_sa(secy, sa);
|
|
} else if ((nlcmd->command == IPMACSEC_LMICMD_SECY_RX_SA_CONTROL) ||
|
|
(nlcmd->command == IPMACSEC_LMICMD_SECY_TX_SA_CONTROL)) {
|
|
Ipmacsec_secy_sa *sa = IP_NULL;
|
|
if (nlcmd->command == IPMACSEC_LMICMD_SECY_RX_SA_CONTROL)
|
|
sa = ipmacsec_secy_lookup_rx_sa(secy, sc, sa_desc.an);
|
|
else if (nlcmd->command == IPMACSEC_LMICMD_SECY_TX_SA_CONTROL)
|
|
sa = ipmacsec_secy_lookup_tx_sa(secy, sa_desc.an);
|
|
if (!sa || (sa->ref != sa_desc.ref)) {
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG3(ERR, "IPMACSEC-MGMT: Cannot control %s SA. SA not found (an: %u, ref: 0x%x)",
|
|
IPMACSEC_DIR_STRING(dir), sa_desc.an, sa_desc.ref);
|
|
#endif
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
param_size = sizeof(sa_ctrl);
|
|
ret = ipmacsec_nlcmd_retrieve_param(nlmsg, &sa_ctrl, param_size);
|
|
if (ret < 0) {
|
|
goto param_ret_fail;
|
|
}
|
|
if (nlcmd->command == IPMACSEC_LMICMD_SECY_RX_SA_CONTROL) {
|
|
ret = -1;
|
|
if (sa_ctrl.rx.updtNextPN || sa_ctrl.rx.updtLowestPN) {
|
|
ret = ipmacsec_secy_update_rx_sa(secy, sa, sa_ctrl.rx.updtNextPN, sa_ctrl.rx.updtLowestPN);
|
|
if (ret < 0) {
|
|
goto exec_fail;
|
|
}
|
|
}
|
|
if (sa_ctrl.rx.enableRx != IPMACSEC_ENABLEFLAG_IGNORE) {
|
|
ret = ipmacsec_secy_enable_rx_sa(secy, sa, (sa_ctrl.rx.enableRx == IPMACSEC_ENABLEFLAG_ON));
|
|
}
|
|
} else if (nlcmd->command == IPMACSEC_LMICMD_SECY_TX_SA_CONTROL) {
|
|
ret = -1;
|
|
if (sa_ctrl.tx.enableTx != IPMACSEC_ENABLEFLAG_IGNORE) {
|
|
ret = ipmacsec_secy_enable_tx_sa(secy, sa, (sa_ctrl.tx.enableTx == IPMACSEC_ENABLEFLAG_ON));
|
|
}
|
|
}
|
|
} else {
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
}
|
|
break;
|
|
case IPMACSEC_LMICMD_SECY_RX_SA_STATUS:
|
|
case IPMACSEC_LMICMD_SECY_TX_SA_STATUS:
|
|
if (!isGet) {
|
|
goto no_set;
|
|
} else {
|
|
Ipmacsec_secy_sa_descriptor sa_desc;
|
|
struct {
|
|
Ipmacsec_secy_sa_descriptor sa_desc;
|
|
Ipmacsec_secy_sa_info sa_info;
|
|
Ipmacsec_secy_sa_ctrl sa_ctrl;
|
|
} param;
|
|
Ipmacsec_secy_sa *sa;
|
|
(void)ipmacsec_nlcmd_retrieve_init(nlmsg);
|
|
param_size = sizeof(sa_desc);
|
|
ret = ipmacsec_nlcmd_retrieve_param(nlmsg, &sa_desc, param_size);
|
|
if (ret < 0) {
|
|
goto param_ret_fail;
|
|
}
|
|
if (nlcmd->command == IPMACSEC_LMICMD_SECY_RX_SA_STATUS) {
|
|
/* for RX SA, retrieve the specified RX SC */
|
|
Ipmacsec_secy_sc *rx_sc = ipmacsec_secy_lookup_rx_sc(secy, sa_desc.sci);
|
|
if (!rx_sc) {
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG8(ERR, "IPMACSEC-MGMT: RX SC not found (SCI = "
|
|
"%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x)",
|
|
sa_desc.sci[0],sa_desc.sci[1],sa_desc.sci[2],sa_desc.sci[3],
|
|
sa_desc.sci[4],sa_desc.sci[5],sa_desc.sci[6],sa_desc.sci[7]);
|
|
#endif
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
sa = ipmacsec_secy_lookup_rx_sa(secy, rx_sc, sa_desc.an);
|
|
} else /* IPMACSEC_LMICMD_SECY_TX_SA_STATUS */ {
|
|
sa = ipmacsec_secy_lookup_tx_sa(secy, sa_desc.an);
|
|
}
|
|
if (!sa || (sa->ref != sa_desc.ref)) {
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
(void)ipmacsec_secy_fill_sa_descriptor(secy, sa, ¶m.sa_desc); /* Update missing fields */
|
|
(void)ipmacsec_secy_fill_sa_info(secy, sa, ¶m.sa_info);
|
|
ipcom_memcpy(¶m.sa_ctrl, &sa->ctrl, sizeof(Ipmacsec_secy_sa_ctrl));
|
|
if (ipmacsec_nlcmd_response_add(reply, nlmsg, ¶m, sizeof(param), src_pid) == IP_NULL) {
|
|
ret = -1;
|
|
goto reply_fail;
|
|
}
|
|
ret = 0;
|
|
}
|
|
break;
|
|
case IPMACSEC_LMICMD_SECY_RX_SA_LIST:
|
|
case IPMACSEC_LMICMD_SECY_TX_SA_LIST:
|
|
if (!isGet) {
|
|
goto no_set;
|
|
} else {
|
|
struct Ip_nlmsghdr *nlresp = IP_NULL;
|
|
Ipmacsec_secy_sc *rx_sc = IP_NULL;
|
|
Ip_u8 an;
|
|
/* for RX SA, retrieve the specified RX SC */
|
|
if (nlcmd->command == IPMACSEC_LMICMD_SECY_RX_SA_LIST) {
|
|
Ip_u8 sci[IPMACSEC_SCI_LEN];
|
|
(void)ipmacsec_nlcmd_retrieve_init(nlmsg);
|
|
param_size = sizeof(sci);
|
|
ret = ipmacsec_nlcmd_retrieve_param(nlmsg, sci, param_size);
|
|
if (ret < 0) {
|
|
goto param_ret_fail;
|
|
}
|
|
rx_sc = ipmacsec_secy_lookup_rx_sc(secy, sci);
|
|
if (!rx_sc) {
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG8(ERR, "IPMACSEC-MGMT: RX SC not found (SCI = "
|
|
"%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x)",
|
|
sci[0],sci[1],sci[2],sci[3],
|
|
sci[4],sci[5],sci[6],sci[7]);
|
|
#endif
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
}
|
|
/* Retrieve all SAs for specified SC and return info */
|
|
nlresp = ipmacsec_nlcmd_response_add(reply, nlmsg, IP_NULL, 0, src_pid);
|
|
if (nlresp == IP_NULL) {
|
|
ret = -1;
|
|
goto reply_fail;
|
|
}
|
|
for (an=0;an<secy->config.maxRxKeys;an++) {
|
|
Ipmacsec_secy_sa_info sa_info;
|
|
Ipmacsec_secy_sa_descriptor sa_desc;
|
|
Ipmacsec_secy_sa *sa = IP_NULL;
|
|
if (nlcmd->command == IPMACSEC_LMICMD_SECY_RX_SA_LIST) {
|
|
sa = ipmacsec_secy_lookup_rx_sa(secy, rx_sc, an);
|
|
} else /* IPMACSEC_LMICMD_SECY_TX_SA_LIST */ {
|
|
sa = ipmacsec_secy_lookup_tx_sa(secy, an);
|
|
}
|
|
if (sa == IP_NULL) {
|
|
continue;
|
|
}
|
|
(void)ipmacsec_secy_fill_sa_descriptor(secy, sa, &sa_desc);
|
|
ret = ipmacsec_nlcmd_add_param(reply, nlresp, &sa_desc, sizeof(sa_desc));
|
|
if (ret < (int)sizeof(sa_desc)) {
|
|
ret = -1;
|
|
goto reply_fail;
|
|
}
|
|
(void)ipmacsec_secy_fill_sa_info(secy, sa, &sa_info);
|
|
ret = ipmacsec_nlcmd_add_param(reply, nlresp, &sa_info, sizeof(sa_info));
|
|
if (ret < (int)sizeof(sa_info)) {
|
|
ret = -1;
|
|
goto reply_fail;
|
|
}
|
|
ret = ipmacsec_nlcmd_add_param(reply, nlresp, &sa->ctrl, sizeof(sa->ctrl));
|
|
if (ret < (int)sizeof(sa->ctrl)) {
|
|
ret = -1;
|
|
goto reply_fail;
|
|
}
|
|
}
|
|
ret = 0;
|
|
}
|
|
break;
|
|
case IPMACSEC_LMICMD_SECY_STATS:
|
|
if (!isGet) {
|
|
goto no_set;
|
|
} else {
|
|
#ifdef IPMACSEC_USE_STATS
|
|
if (ipmacsec_nlcmd_response_add(reply, nlmsg, &secy->stats, sizeof(secy->stats), src_pid) == IP_NULL) {
|
|
ret = -1;
|
|
goto reply_fail;
|
|
}
|
|
ret = 0;
|
|
break;
|
|
#else
|
|
goto no_stats;
|
|
#endif
|
|
}
|
|
case IPMACSEC_LMICMD_SECY_RX_SC_STATS:
|
|
case IPMACSEC_LMICMD_SECY_TX_SC_STATS:
|
|
if (!isGet) {
|
|
goto no_set;
|
|
} else {
|
|
#ifdef IPMACSEC_USE_STATS
|
|
Ip_u8 sci[IPMACSEC_SCI_LEN];
|
|
Ipmacsec_secy_sc *sc;
|
|
Ipmacsec_secy_sc_stats sc_stats;
|
|
if (nlcmd->command == IPMACSEC_LMICMD_SECY_RX_SC_STATS) {
|
|
(void)ipmacsec_nlcmd_retrieve_init(nlmsg);
|
|
param_size = sizeof(sci);
|
|
ret = ipmacsec_nlcmd_retrieve_param(nlmsg, sci, param_size);
|
|
if (ret < 0) {
|
|
goto param_ret_fail;
|
|
}
|
|
sc = ipmacsec_secy_lookup_rx_sc(secy, sci);
|
|
} else /* IPMACSEC_LMICMD_SECY_TX_SC_STATS */ {
|
|
sc = ipmacsec_secy_get_tx_sc(secy);
|
|
}
|
|
if (!sc) {
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
if (nlcmd->command == IPMACSEC_LMICMD_SECY_RX_SC_STATS) {
|
|
IPCOM_LOG8(ERR, "IPMACSEC-MGMT: RX SC not found (SCI = "
|
|
"%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x)",
|
|
sci[0],sci[1],sci[2],sci[3],
|
|
sci[4],sci[5],sci[6],sci[7]);
|
|
}
|
|
#endif
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
ipcom_memcpy(&sc_stats, &sc->stats, sizeof(Ipmacsec_secy_sc_stats));
|
|
ret = ipmacsec_secy_sc_add_sa_stats(secy, sc, &sc_stats);
|
|
if (ret != 0) {
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
if (ipmacsec_nlcmd_response_add(reply, nlmsg, &sc_stats, sizeof(sc_stats), src_pid) == IP_NULL) {
|
|
ret = -1;
|
|
goto reply_fail;
|
|
}
|
|
ret = 0;
|
|
break;
|
|
#else
|
|
goto no_stats;
|
|
#endif
|
|
}
|
|
case IPMACSEC_LMICMD_SECY_RX_SA_STATS:
|
|
case IPMACSEC_LMICMD_SECY_TX_SA_STATS:
|
|
if (!isGet) {
|
|
goto no_set;
|
|
} else {
|
|
#ifdef IPMACSEC_USE_STATS
|
|
Ipmacsec_secy_sa *sa;
|
|
Ipmacsec_secy_sa_descriptor sa_desc;
|
|
(void)ipmacsec_nlcmd_retrieve_init(nlmsg);
|
|
param_size = sizeof(sa_desc);
|
|
ret = ipmacsec_nlcmd_retrieve_param(nlmsg, &sa_desc, param_size);
|
|
if (ret < 0) {
|
|
goto param_ret_fail;
|
|
}
|
|
if (nlcmd->command == IPMACSEC_LMICMD_SECY_RX_SA_STATS) {
|
|
/* for RX SA, retrieve the specified RX SC */
|
|
Ipmacsec_secy_sc *rx_sc = ipmacsec_secy_lookup_rx_sc(secy, sa_desc.sci);
|
|
if (!rx_sc) {
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG8(ERR, "IPMACSEC-MGMT: RX SC not found (SCI = "
|
|
"%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x)",
|
|
sa_desc.sci[0],sa_desc.sci[1],sa_desc.sci[2],sa_desc.sci[3],
|
|
sa_desc.sci[4],sa_desc.sci[5],sa_desc.sci[6],sa_desc.sci[7]);
|
|
#endif
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
sa = ipmacsec_secy_lookup_rx_sa(secy, rx_sc, sa_desc.an);
|
|
} else /* IPMACSEC_LMICMD_SECY_TX_SA_STATS */ {
|
|
sa = ipmacsec_secy_lookup_tx_sa(secy, sa_desc.an);
|
|
}
|
|
if (!sa || (sa->ref != sa_desc.ref)) {
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
if (ipmacsec_nlcmd_response_add(reply, nlmsg, &sa->stats, sizeof(sa->stats), src_pid) == IP_NULL) {
|
|
ret = -1;
|
|
goto reply_fail;
|
|
}
|
|
ret = 0;
|
|
break;
|
|
#else
|
|
goto no_stats;
|
|
#endif
|
|
}
|
|
case IPMACSEC_LMICMD_CONTROLLED_PORT_ENABLED:
|
|
case IPMACSEC_LMICMD_PORT_ADMIN_PTP_MAC:
|
|
if (isGet) {
|
|
ret = secy->controlled_port.update_status(secy->netif);
|
|
if (ret != 0) {
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
if (nlcmd->command == IPMACSEC_LMICMD_CONTROLLED_PORT_ENABLED) {
|
|
if (ipmacsec_nlcmd_response_add(reply, nlmsg, &secy->controlled_port.ctrl.cp_enabled,
|
|
sizeof(secy->controlled_port.ctrl.cp_enabled), src_pid) == IP_NULL) {
|
|
ret = -1;
|
|
goto reply_fail;
|
|
}
|
|
ret = 0;
|
|
} else {
|
|
if (ipmacsec_nlcmd_response_add(reply, nlmsg, &secy->controlled_port.status.admin_ptp_mac,
|
|
sizeof(secy->controlled_port.status.admin_ptp_mac), src_pid) == IP_NULL) {
|
|
ret = -1;
|
|
goto reply_fail;
|
|
}
|
|
ret = 0;
|
|
}
|
|
} else {
|
|
if (nlcmd->command == IPMACSEC_LMICMD_CONTROLLED_PORT_ENABLED) {
|
|
Ip_bool cp_enabled;
|
|
(void)ipmacsec_nlcmd_retrieve_init(nlmsg);
|
|
param_size = sizeof(cp_enabled);
|
|
ret = ipmacsec_nlcmd_retrieve_param(nlmsg, &cp_enabled, param_size);
|
|
if (ret < 0) {
|
|
goto param_ret_fail;
|
|
}
|
|
ret = ipmacsec_secy_cp_enable(secy, cp_enabled);
|
|
} else if (nlcmd->command == IPMACSEC_LMICMD_PORT_ADMIN_PTP_MAC) {
|
|
Ip_portif_admin_ptp_mac_val admin_p2p_mac;
|
|
(void)ipmacsec_nlcmd_retrieve_init(nlmsg);
|
|
param_size = sizeof(admin_p2p_mac);
|
|
ret = ipmacsec_nlcmd_retrieve_param(nlmsg, &admin_p2p_mac, param_size);
|
|
if (ret < 0) {
|
|
goto param_ret_fail;
|
|
}
|
|
ret = ipmacsec_secy_cp_set_adminP2pMac(secy, admin_p2p_mac);
|
|
}
|
|
if (ret != 0) {
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
}
|
|
break;
|
|
case IPMACSEC_LMICMD_PORT_MAC_ENABLED:
|
|
case IPMACSEC_LMICMD_PORT_MAC_OPER:
|
|
case IPMACSEC_LMICMD_PORT_OPER_PTP_MAC:
|
|
if (!isGet) {
|
|
goto no_set;
|
|
} else {
|
|
Ip_bool cp, boolval;
|
|
Ipnet_portif *port = IP_FALSE;
|
|
(void)ipmacsec_nlcmd_retrieve_init(nlmsg);
|
|
param_size = sizeof(cp);
|
|
ret = ipmacsec_nlcmd_retrieve_param(nlmsg, &cp, param_size);
|
|
if (ret < 0) {
|
|
goto param_ret_fail;
|
|
}
|
|
if (cp) {
|
|
port = &secy->controlled_port;
|
|
} else {
|
|
port = &secy->uncontrolled_port;
|
|
}
|
|
ret = port->update_status(secy->netif);
|
|
if (ret != 0) {
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
ip_assert(port);
|
|
if (nlcmd->command == IPMACSEC_LMICMD_PORT_MAC_ENABLED) {
|
|
boolval = port->status.mac_enabled;
|
|
} else if (nlcmd->command == IPMACSEC_LMICMD_PORT_MAC_OPER) {
|
|
boolval = port->status.mac_oper;
|
|
} else if (nlcmd->command == IPMACSEC_LMICMD_PORT_OPER_PTP_MAC) {
|
|
boolval = port->status.oper_ptp_mac;
|
|
} else {
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
if (ipmacsec_nlcmd_response_add(reply, nlmsg, &boolval, sizeof(boolval), src_pid) == IP_NULL) {
|
|
ret = -1;
|
|
goto reply_fail;
|
|
}
|
|
ret = 0;
|
|
}
|
|
break;
|
|
case IPMACSEC_LMICMD_PORT_STATISTICS:
|
|
if (!isGet) {
|
|
goto no_set;
|
|
} else {
|
|
#ifdef IPMACSEC_USE_STATS
|
|
Ip_bool cp;
|
|
Ipnet_portif *port = IP_FALSE;
|
|
(void)ipmacsec_nlcmd_retrieve_init(nlmsg);
|
|
param_size = sizeof(cp);
|
|
ret = ipmacsec_nlcmd_retrieve_param(nlmsg, &cp, param_size);
|
|
if (ret < 0) {
|
|
goto param_ret_fail;
|
|
}
|
|
if (cp) {
|
|
port = &secy->controlled_port;
|
|
} else {
|
|
port = &secy->uncontrolled_port;
|
|
}
|
|
ret = port->update_stats(secy->netif);
|
|
if (ret != 0) {
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
ip_assert(port);
|
|
if (ipmacsec_nlcmd_response_add(reply, nlmsg, &port->stats, sizeof(port->stats), src_pid) == IP_NULL) {
|
|
ret = -1;
|
|
goto reply_fail;
|
|
}
|
|
ret = 0;
|
|
break;
|
|
#else
|
|
goto no_stats;
|
|
#endif
|
|
}
|
|
case IPMACSEC_LMICMD_SECY_RESET_STATISTICS:
|
|
if (isGet) {
|
|
goto no_get;
|
|
} else {
|
|
#ifdef IPMACSEC_USE_STATS
|
|
if (secy->ctrl.enabled) {
|
|
goto no_exec_enabled;
|
|
}
|
|
ret = ipmacsec_secy_reset_stats(secy);
|
|
if (ret != 0) {
|
|
ret = -1;
|
|
goto exec_fail;
|
|
}
|
|
ret = 0;
|
|
break;
|
|
#else
|
|
goto no_stats;
|
|
#endif
|
|
}
|
|
default:
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG4(ERR, "IPMACSEC-MGMT: Invalid MACsec netlink cmd %d (%s) for nltype %d (%s)",
|
|
nlcmd->command, ipmacsec_lmi_cmd_name(nlcmd->command),
|
|
nlmsg->nlmsg_type, ipmacsec_netlink_type_name(nlmsg->nlmsg_type));
|
|
#endif
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if (ret < 0)
|
|
goto exec_fail;
|
|
return ret;
|
|
|
|
|
|
param_ret_fail:
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG6(ERR, "IPMACSEC-MGMT: Failed to retrieve MACsec netlink cmd parameter for cmd %d (%s), nltype %d (%s)."
|
|
"param_size=%u, ret=%d",
|
|
nlcmd->command, ipmacsec_lmi_cmd_name(nlcmd->command),
|
|
nlmsg->nlmsg_type, ipmacsec_netlink_type_name(nlmsg->nlmsg_type), param_size, ret);
|
|
#endif
|
|
return ret;
|
|
|
|
reply_fail:
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG5(ERR, "IPMACSEC-MGMT: Failed to create MACsec netlink reply for cmd %d (%s), nltype %d (%s). ret=%d",
|
|
nlcmd->command, ipmacsec_lmi_cmd_name(nlcmd->command),
|
|
nlmsg->nlmsg_type, ipmacsec_netlink_type_name(nlmsg->nlmsg_type), ret);
|
|
#endif
|
|
return ret;
|
|
|
|
exec_fail:
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG5(ERR, "IPMACSEC-MGMT: Failed to execute MACsec netlink cmd %d (%s), nltype %d (%s). ret=%d",
|
|
nlcmd->command, ipmacsec_lmi_cmd_name(nlcmd->command),
|
|
nlmsg->nlmsg_type, ipmacsec_netlink_type_name(nlmsg->nlmsg_type), ret);
|
|
#endif
|
|
return ret;
|
|
|
|
no_exec_enabled:
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG4(ERR, "IPMACSEC-MGMT: Cannot execute cmd %d (%s) when SecY is enabled. nltype %d (%s)",
|
|
nlcmd->command, ipmacsec_lmi_cmd_name(nlcmd->command),
|
|
nlmsg->nlmsg_type, ipmacsec_netlink_type_name(nlmsg->nlmsg_type));
|
|
#endif
|
|
return -1;
|
|
|
|
no_get:
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG5(ERR, "IPMACSEC-MGMT: Get not allowed for MACsec netlink cmd %d (%s), nltype %d (%s). ret=%d",
|
|
nlcmd->command, ipmacsec_lmi_cmd_name(nlcmd->command),
|
|
nlmsg->nlmsg_type, ipmacsec_netlink_type_name(nlmsg->nlmsg_type), ret);
|
|
#endif
|
|
return -1;
|
|
|
|
no_set:
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG5(ERR, "IPMACSEC-MGMT: Set not allowed for MACsec netlink cmd %d (%s), nltype %d (%s). ret=%d",
|
|
nlcmd->command, ipmacsec_lmi_cmd_name(nlcmd->command),
|
|
nlmsg->nlmsg_type, ipmacsec_netlink_type_name(nlmsg->nlmsg_type), ret);
|
|
#endif
|
|
return -1;
|
|
|
|
#ifndef IPMACSEC_USE_STATS
|
|
no_stats:
|
|
#ifdef IPMACSEC_DEBUG_SECY_MGMT
|
|
IPCOM_LOG5(ERR, "IPMACSEC-MGMT: MACsec Statistics not supported. Failing netlink cmd %d (%s), nltype %d (%s). ret=%d",
|
|
nlcmd->command, ipmacsec_lmi_cmd_name(nlcmd->command),
|
|
nlmsg->nlmsg_type, ipmacsec_netlink_type_name(nlmsg->nlmsg_type), ret);
|
|
#endif
|
|
return -1;
|
|
#endif
|
|
}
|