/* 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 #include #include #include #include #include #include #include #include #include #include #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;anconfig.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;anconfig.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;anconfig.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 }