summaryrefslogtreecommitdiff
path: root/cesar/cp/beacon/src/beacon.c
diff options
context:
space:
mode:
authorYacine Belkadi2013-04-03 13:11:05 +0200
committerYacine Belkadi2013-05-23 09:07:13 +0200
commite4b7731e1827efcc1af0a721cb5415039ae6f459 (patch)
tree7fb89129008aaca5551f888a90fb10ad49f7e74c /cesar/cp/beacon/src/beacon.c
parenta5821e5b218bb56400f0ef888a47ad9651484df2 (diff)
cesar/{bsu,cp,mac/pbproc}: change NEK management
Two slots were used to store the NEKs. One for the current NEK, the other for the next NEK. The CP could update any slot at any time, by setting the EKS to MAC_EKS_CLEAR first. One problem is that the pbproc doesn't expect someone to change a key that it is in use. If the cp sets the EKS to MAC_EKS_CLEAR for a key that is in use, may make the pbproc send data unencrypted, which is a problem. Another problem may occur during a NEK change, if the new NEK is not received via the SET_KEY_CNF. In that case, when the countdown starts, the cp sends a GET_KEY_CNF to get the new NEK. When it receives it, it puts the new key in the next slot. To identify the next slot the cp uses bsu_nek_index_next(). This is not reliable around a NEK change: - the cp receives the new NEK - the cp starts setting the new NEK - the cp is suspended - the bsu changes nek_switch - the cp is resumed and calls bsu_nek_index_next() which returns the index of the current NEK instead of the next NEK - the cp writes the new NEK in the current slot instead of the next slot - the pbproc may send packets unencrypted - the NEK change occurs - the new NEK is used in Rx (because the new NEK is in one of the two slots) but not in Tx (because it's not the in the current slot) To fix that, change the way the NEKs are managed: Use pointers and indirection to be able to atomically change a NEK transparently from the pbproc's point of view. Make the cp store the NEKs and set the current NEK, but let the bsu grab the next NEK if it's available.
Diffstat (limited to 'cesar/cp/beacon/src/beacon.c')
-rw-r--r--cesar/cp/beacon/src/beacon.c109
1 files changed, 77 insertions, 32 deletions
diff --git a/cesar/cp/beacon/src/beacon.c b/cesar/cp/beacon/src/beacon.c
index f1385de89a..086253b8e1 100644
--- a/cesar/cp/beacon/src/beacon.c
+++ b/cesar/cp/beacon/src/beacon.c
@@ -570,12 +570,15 @@ cp_beacon_process_bmi_eks (cp_t *ctx, const bsu_beacon_t *beacon)
if (beacon->bmis.eks.present)
{
- if ((beacon->bmis.eks.kbc == BSU_BEACON_EKS_KBC_NEK)
- && (ctx->mac_config->nek[bsu_nek_index_next (ctx->bsu)].eks
- != beacon->bmis.eks.new_eks))
+ if ((beacon->bmis.eks.kbc == BSU_BEACON_EKS_KBC_NEK))
{
- /* We don't have the new NEK. We need to ask for it. */
- cp_fsm_post_new_event (ctx, bare, nek_request);
+ if ((ctx->mac_config->nek_mgr.next_nek == NULL)
+ || (ctx->mac_config->nek_mgr.next_nek->eks
+ != beacon->bmis.eks.new_eks))
+ {
+ /* We don't have the new NEK. We need to ask for it. */
+ cp_fsm_post_new_event (ctx, bare, nek_request);
+ }
}
ctx->beacon.eks.kccd = beacon->bmis.eks.kccd;
@@ -588,12 +591,13 @@ cp_beacon_process_bmi_eks (cp_t *ctx, const bsu_beacon_t *beacon)
{
if (ctx->beacon.eks.kbc == BSU_BEACON_EKS_KBC_NEK)
{
- if (ctx->mac_config->nek[
- bsu_nek_index_current (ctx->bsu)].eks == MAC_EKS_CLEAR)
- /* Countdown elapsed and no NEK is available */
+ mac_nek_t *nek = bsu_nek_get_current (ctx->bsu);
+ if (nek->eks != ctx->beacon.eks.new_eks)
+ {
+ /* The countdown elapsed and we are not using the new NEK.
+ */
cp_fsm_trigger_new_event (ctx, bare, to_leave);
-
- ctx->beacon.eks.kbc = BSU_BEACON_EKS_KBC_NB;
+ }
}
}
ctx->beacon.eks.kccd = 0;
@@ -708,7 +712,6 @@ cp_beacon_process_beacon_central (
beacon->bmis.handover.hcd;
ctx->beacon.hoip.cco = beacon->bmis.handover.tei;
}
-
cp_beacon_process_bmi_eks (ctx, beacon);
/** Update the schedules. */
@@ -905,25 +908,78 @@ cp_beacon_beacon_not_received (cp_t *ctx)
}
/**
- * Set the nek in the beacon module.
- * \param ctx the CP context.
- * \param eks the eks tu use.
- * \param nek the nek key.
- * \param now indicate if the nek shall be use right now.
+ * Store a NEK.
+ * \param nek_mgr the NEK management structure.
+ * \param eks The eks of the NEK to store.
+ * \param nek_enc The encryption part of the NEK to store.
+ * \param nek_dec The decryption part of the NEK to store.
+ * \return A pointer to the stored NEK, or NULL if the storage failed.
*/
+PRIVATE mac_nek_t *
+cp_beacon_store_nek (mac_nek_mgr_t *nek_mgr, u8 eks, const u32 *nek_enc,
+ const u32 *nek_dec)
+{
+ /* Find a free slot. i.e. A slot that is neither in use, nor containing the
+ * next key. */
+ /* arch_dsr_lock() is not necessary for the search, because even if this
+ * function is interrupted, a free slot will remain free, because only the
+ * cp fills slots, and this function is called by the cp, and the cp doesn't
+ * interrupt the cp.
+ * */
+ mac_nek_t *nek = NULL;
+ uint i;
+ for (i = 0; i < MAC_NEK_STORE_NB; i++)
+ {
+ if ((nek_mgr->store[i].in_use == false)
+ && (&nek_mgr->store[i] != nek_mgr->next_nek))
+ {
+ nek = &nek_mgr->store[i];
+ break;
+ }
+ }
+
+ if (nek == NULL)
+ return NULL;
+
+ /* Put the key in the free slot. */
+ nek->eks = eks;
+ for (i = 0; i < COUNT (nek->nek_enc); i++)
+ {
+ nek->nek_enc[i] = nek_enc[i];
+ nek->nek_dec[i] = nek_dec[i];
+ }
+
+ /* Ensure the storage of the NEK is over, before returning.
+ * Probably not necessary before returning from a function, but seems safer
+ * in case this is inlined, for example (?) */
+ arch_reorder_barrier ();
+
+ return nek;
+}
+
void
-cp_beacon_change_nek (cp_t *ctx, uint eks, cp_key_t nek, bool now)
+cp_beacon_change_nek (cp_t *ctx, uint eks, cp_key_t nek_enc, bool now)
{
- cp_key_t rnek;
- uint i,index;
+ cp_key_t nek_dec;
dbg_assert (ctx);
dbg_assert (ctx->mac_config);
+ cp_secu_pbb_dec_gen (nek_enc, &nek_dec);
+
+ mac_nek_t *nek = cp_beacon_store_nek (&ctx->mac_config->nek_mgr, eks,
+ nek_enc.key, nek_dec.key);
+
+ /* Failing to store the NEK should not happen (See MAC_NEK_STORE_NB). */
+ dbg_assert (nek);
+
if (now)
- index = bsu_nek_index_current (ctx->bsu);
+ {
+ bsu_nek_use (ctx->bsu, nek);
+ }
else
{
- index = bsu_nek_index_next (ctx->bsu);
+ bsu_nek_set_next (ctx->bsu, nek);
+
if (cp_sta_own_data_get_cco_status (ctx))
{
/* Initiate key change countdown. */
@@ -932,17 +988,6 @@ cp_beacon_change_nek (cp_t *ctx, uint eks, cp_key_t nek, bool now)
ctx->beacon.eks.new_eks = eks;
}
}
-
- cp_secu_pbb_dec_gen (nek, &rnek);
- ctx->mac_config->nek[index].eks = MAC_EKS_CLEAR;
- arch_reorder_barrier ();
- for (i = 0; i < COUNT(nek.key); i++)
- {
- ctx->mac_config->nek[index].nek_enc[i] = nek.key[i];
- ctx->mac_config->nek[index].nek_dec[i] = rnek.key[i];
- }
- arch_reorder_barrier ();
- ctx->mac_config->nek[index].eks = eks;
}
/**