summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYacine Belkadi2013-04-02 17:27:57 +0200
committerYacine Belkadi2013-05-22 10:53:36 +0200
commite981d61d72c4d29f5bac7c7139ab50e98a0e625d (patch)
treef5843523e5211a039a7f6756a9b8f18131b777a2
parent96e8bd48bd068f01a8c00649328c554677e756f2 (diff)
cesar/{bsu{,beacon},cp}: let the bsu decrease KCCD on each beacon, closes #3794
When announcing a key change (e.g. NEK), the countdown field (KCCD) must decrease on each sent beacon. (c.f. HPAV Specification: 4.4.3.15.4.8.1 Key Change Countdown (KCCD) KCCD values were managed by the cp. But the cp is not assured to run on time to prepare each beacon. The bsu tried to compensate that in bsu_beacon_countdown() and the cp in cp_beacon_countdowns(). So both of them were touching KCCD, each one somehow guessing the appropriate current value. That seems fragile. In addition, cp_beacon_countdowns() has a bug which may prevent KCCD from being updated: Suppose that we are in beacon period b0. Suppose that the function is called just before the start of the next beacon period b1 (returned by bsu_aclf_beacon_period_start_date_next()). It enters the main if, and updates KCCD (for b0). Then it goes to update last_countdown_call_date, but the beacon period b1 has started. So bsu_aclf_beacon_period_start_date_next() returns b2, and last_countdown_call_date is set to b2. Because of this, when the function is called in b1, the main if will not be entered and KCCD will not be updated for b1. If the same scenario happens again, i.e. the function runs just before b2 but b3 starts just before updating last_countdown_call_date, then KCCD will not be updated in b2 neither. So KCCD may have the same value on consecutive beacons, which is a problem. Fix this by letting the bsu handle the decrease of the KCCD value. On the CCo, the cp decides when to initiate a key change. It tells sets the initial value of KCCD in one and only one beacon passed to the bsu. When the bsu sees that a key bentry is present in the beacon prepared by the cp, it knows that it has to handle the countdown. For each consecutive beacon, the bsu takes care of decreasing KCCD appropriately. The cp on the CCo doesn't need to know about it.
-rw-r--r--cesar/bsu/beacon/src/beacon.c6
-rw-r--r--cesar/bsu/beacon/test/utest/src/beacon.c11
-rw-r--r--cesar/bsu/src/bsu.c24
-rw-r--r--cesar/bsu/test/utest/src/bsut.c148
-rw-r--r--cesar/bsu/test/utest/src/countdown.c15
-rw-r--r--cesar/bsu/test/utest/src/tests.c5
-rw-r--r--cesar/cp/beacon/src/beacon.c24
-rw-r--r--cesar/test_general/station/scenario/av/py/sc08_bentry_change.py2
8 files changed, 205 insertions, 30 deletions
diff --git a/cesar/bsu/beacon/src/beacon.c b/cesar/bsu/beacon/src/beacon.c
index 3dad9bd382..0f8f6e8927 100644
--- a/cesar/bsu/beacon/src/beacon.c
+++ b/cesar/bsu/beacon/src/beacon.c
@@ -1055,12 +1055,6 @@ bsu_beacon_countdown (bsu_beacon_t *beacon)
&& beacon->bmis.ps.ps[nb].cscd)
beacon->bmis.ps.ps[nb].cscd--;
}
- /* Encryption key change. */
- if (beacon->bmis.eks.present)
- {
- beacon->bmis.eks.kccd --;
- beacon->bmis.eks.present = beacon->bmis.eks.kccd;
- }
/* CCo handover. */
if (beacon->bmis.handover.present)
{
diff --git a/cesar/bsu/beacon/test/utest/src/beacon.c b/cesar/bsu/beacon/test/utest/src/beacon.c
index d267463960..1aea072b62 100644
--- a/cesar/bsu/beacon/test/utest/src/beacon.c
+++ b/cesar/bsu/beacon/test/utest/src/beacon.c
@@ -102,17 +102,6 @@ test_case_countdown (test_t t)
test_fail_unless (beacon.bmis.ps.ps[0].cscd == 4);
}
test_end;
- test_begin (t, "Encryption key change countdown")
- {
- beacon.bmis.eks.present = true;
- beacon.bmis.eks.kccd = 2;
- bsu_beacon_countdown (&beacon);
- test_fail_unless (beacon.bmis.eks.present == true);
- test_fail_unless (beacon.bmis.eks.kccd == 1);
- bsu_beacon_countdown (&beacon);
- test_fail_unless (beacon.bmis.eks.present == false);
- }
- test_end;
test_begin (t, "CCo handover countdown")
{
beacon.bmis.handover.present = true;
diff --git a/cesar/bsu/src/bsu.c b/cesar/bsu/src/bsu.c
index 59c6c97b5b..f81fb12b36 100644
--- a/cesar/bsu/src/bsu.c
+++ b/cesar/bsu/src/bsu.c
@@ -1258,6 +1258,22 @@ bsu_update (bsu_t *ctx, bsu_beacon_t *beacon, bsu_update_sta_type_t is_sta)
&& beacon->bmis.ps.ps[0].pscd
< beacon->bmis.ps.ps[1].pscd));
dbg_assert (beacon->vf.hm < MAC_COEXISTENCE_NB);
+
+ bool restore_bmi_eks = false;
+ bsu_beacon_bmi_eks_t bmi_eks;
+ if (ctx->is_sta == BSU_UPDATE_STA_TYPE_CCO
+ && ctx->sta_avln->beacon.bmis.eks.present)
+ {
+ /* 1) The cp should only set eks.present once, just to inform the bsu.
+ * 2) There shouldn't be a key change in the middle of another key
+ * change. */
+ dbg_assert (!beacon->bmis.eks.present);
+
+ /* Backup the current key change data. */
+ bmi_eks = ctx->sta_avln->beacon.bmis.eks;
+ restore_bmi_eks = true;
+ }
+
/* If the data provided are for the next beacon period. */
if (lesseq_mod2p32 (bsu_aclf_beacon_period_start_date_next (ctx->aclf),
beacon->beacon_period_start_date)
@@ -1285,9 +1301,7 @@ bsu_update (bsu_t *ctx, bsu_beacon_t *beacon, bsu_update_sta_type_t is_sta)
ctx->sta_avln->beacon.bmis.region = beacon->bmis.region;
/* Process the beacon entry with countdowns. */
bsu_update__persistent_schedules (ctx, beacon);
- if (beacon->bmis.eks.present
- && !ctx->sta_avln->beacon.bmis.eks.present)
- ctx->sta_avln->beacon.bmis.eks = beacon->bmis.eks;
+ ctx->sta_avln->beacon.bmis.eks = beacon->bmis.eks;
if (beacon->bmis.handover.present
&& !ctx->sta_avln->beacon.bmis.handover.present)
ctx->sta_avln->beacon.bmis.handover = beacon->bmis.handover;
@@ -1314,6 +1328,10 @@ bsu_update (bsu_t *ctx, bsu_beacon_t *beacon, bsu_update_sta_type_t is_sta)
ctx->sta_avln->beacon.bmis.discover_info =
beacon->bmis.discover_info;
}
+
+ if (restore_bmi_eks)
+ ctx->sta_avln->beacon.bmis.eks = bmi_eks;
+
arch_dsr_unlock ();
}
diff --git a/cesar/bsu/test/utest/src/bsut.c b/cesar/bsu/test/utest/src/bsut.c
index 6a90df5d57..e82cb6b761 100644
--- a/cesar/bsu/test/utest/src/bsut.c
+++ b/cesar/bsu/test/utest/src/bsut.c
@@ -447,7 +447,6 @@ test_case_bsu_update (test_t test)
test_begin (test, "Beacon entries with countdown.")
{
test_case_bsu_update_init (&t, &beacon);
- t.bsu->sta_avln->beacon.bmis.eks.present = false;
t.bsu->sta_avln->beacon.bmis.handover.present = false;
t.bsu->sta_avln->beacon.bmis.relocation.present = false;
t.bsu->sta_avln->beacon.bmis.aclsc.present = false;
@@ -456,7 +455,6 @@ test_case_bsu_update (test_t test)
t.bsu->sta_avln->beacon.bmis.change_snid.present = false;
t.bsu->sta_avln->beacon.bmis.mac_address.present = false;
bsu_update (t.bsu, &beacon, true /* is station. */);
- test_fail_unless (t.bsu->sta_avln->beacon.bmis.eks.present == true);
test_fail_unless (t.bsu->sta_avln->beacon.bmis.handover.present == true);
test_fail_unless (t.bsu->sta_avln->beacon.bmis.relocation.present == true);
test_fail_unless (t.bsu->sta_avln->beacon.bmis.aclsc.present == true);
@@ -467,6 +465,152 @@ test_case_bsu_update (test_t test)
== true);
}
test_end;
+ test_begin (test, "bmi eks update:Sta:On time")
+ {
+ test_case_bsu_update_init (&t, &beacon);
+ beacon.beacon_period_start_date
+ = bsu_aclf_beacon_period_start_date_next (t.bsu->aclf);
+
+ t.bsu->sta_avln->beacon.bmis.eks.present = true;
+ t.bsu->sta_avln->beacon.bmis.eks.kccd = 3;
+ t.bsu->sta_avln->beacon.bmis.eks.kbc = BSU_BEACON_EKS_KBC_NEK;
+ t.bsu->sta_avln->beacon.bmis.eks.new_eks = 6;
+
+ beacon.bmis.eks.present = false;
+ beacon.bmis.eks.kccd = 0;
+ beacon.bmis.eks.kbc = BSU_BEACON_EKS_KBC_NB;
+ beacon.bmis.eks.new_eks = MAC_EKS_NB;
+
+ bsu_update (t.bsu, &beacon, BSU_UPDATE_STA_TYPE_STA);
+
+ test_fail_unless (t.bsu->sta_avln->beacon.bmis.eks.present == false);
+ test_fail_unless (t.bsu->sta_avln->beacon.bmis.eks.kccd == 0);
+ test_fail_unless (t.bsu->sta_avln->beacon.bmis.eks.kbc
+ == BSU_BEACON_EKS_KBC_NB);
+ test_fail_unless (t.bsu->sta_avln->beacon.bmis.eks.new_eks
+ == MAC_EKS_NB);
+ }
+ test_end;
+ test_begin (test, "bmi eks update:Sta:Late")
+ {
+ test_case_bsu_update_init (&t, &beacon);
+
+ t.bsu->sta_avln->beacon.bmis.eks.present = true;
+ t.bsu->sta_avln->beacon.bmis.eks.kccd = 3;
+ t.bsu->sta_avln->beacon.bmis.eks.kbc = BSU_BEACON_EKS_KBC_NEK;
+ t.bsu->sta_avln->beacon.bmis.eks.new_eks = 6;
+
+ beacon.bmis.eks.present = false;
+ beacon.bmis.eks.kccd = 0;
+ beacon.bmis.eks.kbc = BSU_BEACON_EKS_KBC_NB;
+ beacon.bmis.eks.new_eks = MAC_EKS_NB;
+
+ bsu_update (t.bsu, &beacon, BSU_UPDATE_STA_TYPE_STA);
+
+ test_fail_unless (t.bsu->sta_avln->beacon.bmis.eks.present == false);
+ test_fail_unless (t.bsu->sta_avln->beacon.bmis.eks.kccd == 0);
+ test_fail_unless (t.bsu->sta_avln->beacon.bmis.eks.kbc
+ == BSU_BEACON_EKS_KBC_NB);
+ test_fail_unless (t.bsu->sta_avln->beacon.bmis.eks.new_eks
+ == MAC_EKS_NB);
+ }
+ test_end;
+ test_begin (test, "bmi eks update:CCo:On time:New countdown")
+ {
+ test_case_bsu_update_init (&t, &beacon);
+ beacon.beacon_period_start_date
+ = bsu_aclf_beacon_period_start_date_next (t.bsu->aclf);
+
+ t.bsu->sta_avln->beacon.bmis.eks.present = false;
+ t.bsu->sta_avln->beacon.bmis.eks.kccd = 0;
+ t.bsu->sta_avln->beacon.bmis.eks.kbc = BSU_BEACON_EKS_KBC_NB;
+ t.bsu->sta_avln->beacon.bmis.eks.new_eks = MAC_EKS_NB;
+
+ beacon.bmis.eks.present = true;
+ beacon.bmis.eks.kccd = 5;
+ beacon.bmis.eks.kbc = BSU_BEACON_EKS_KBC_NEK;
+ beacon.bmis.eks.new_eks = 4;
+
+ bsu_update (t.bsu, &beacon, BSU_UPDATE_STA_TYPE_CCO);
+
+ test_fail_unless (t.bsu->sta_avln->beacon.bmis.eks.present == true);
+ test_fail_unless (t.bsu->sta_avln->beacon.bmis.eks.kccd == 5);
+ test_fail_unless (t.bsu->sta_avln->beacon.bmis.eks.kbc
+ == BSU_BEACON_EKS_KBC_NEK);
+ test_fail_unless (t.bsu->sta_avln->beacon.bmis.eks.new_eks == 4);
+ }
+ test_end;
+ test_begin (test, "bmi eks update:CCo:Late:New countdown")
+ {
+ test_case_bsu_update_init (&t, &beacon);
+
+ t.bsu->sta_avln->beacon.bmis.eks.present = false;
+ t.bsu->sta_avln->beacon.bmis.eks.kccd = 0;
+ t.bsu->sta_avln->beacon.bmis.eks.kbc = BSU_BEACON_EKS_KBC_NB;
+ t.bsu->sta_avln->beacon.bmis.eks.new_eks = MAC_EKS_NB;
+
+ beacon.bmis.eks.present = true;
+ beacon.bmis.eks.kccd = 5;
+ beacon.bmis.eks.kbc = BSU_BEACON_EKS_KBC_NEK;
+ beacon.bmis.eks.new_eks = 4;
+
+ bsu_update (t.bsu, &beacon, BSU_UPDATE_STA_TYPE_CCO);
+
+ test_fail_unless (t.bsu->sta_avln->beacon.bmis.eks.present == true);
+ test_fail_unless (t.bsu->sta_avln->beacon.bmis.eks.kccd == 5);
+ test_fail_unless (t.bsu->sta_avln->beacon.bmis.eks.kbc
+ == BSU_BEACON_EKS_KBC_NEK);
+ test_fail_unless (t.bsu->sta_avln->beacon.bmis.eks.new_eks == 4);
+ }
+ test_end;
+ test_begin (test, "bmi eks update:CCo:On time:Preserve countdown")
+ {
+ test_case_bsu_update_init (&t, &beacon);
+ beacon.beacon_period_start_date =
+ bsu_aclf_beacon_period_start_date_next (t.bsu->aclf);
+
+ t.bsu->sta_avln->beacon.bmis.eks.present = true;
+ t.bsu->sta_avln->beacon.bmis.eks.kccd = 3;
+ t.bsu->sta_avln->beacon.bmis.eks.kbc = BSU_BEACON_EKS_KBC_NEK;
+ t.bsu->sta_avln->beacon.bmis.eks.new_eks = 4;
+
+ beacon.bmis.eks.present = false;
+ beacon.bmis.eks.kccd = 0;
+ beacon.bmis.eks.kbc = BSU_BEACON_EKS_KBC_NB;
+ beacon.bmis.eks.new_eks = MAC_EKS_NB;
+
+ bsu_update (t.bsu, &beacon, BSU_UPDATE_STA_TYPE_CCO);
+
+ test_fail_unless (t.bsu->sta_avln->beacon.bmis.eks.present == true);
+ test_fail_unless (t.bsu->sta_avln->beacon.bmis.eks.kccd == 3);
+ test_fail_unless (t.bsu->sta_avln->beacon.bmis.eks.kbc
+ == BSU_BEACON_EKS_KBC_NEK);
+ test_fail_unless (t.bsu->sta_avln->beacon.bmis.eks.new_eks == 4);
+ }
+ test_end;
+ test_begin (test, "bmi eks update:CCo:Late:Preserve countdown")
+ {
+ test_case_bsu_update_init (&t, &beacon);
+
+ t.bsu->sta_avln->beacon.bmis.eks.present = true;
+ t.bsu->sta_avln->beacon.bmis.eks.kccd = 3;
+ t.bsu->sta_avln->beacon.bmis.eks.kbc = BSU_BEACON_EKS_KBC_NEK;
+ t.bsu->sta_avln->beacon.bmis.eks.new_eks = 4;
+
+ beacon.bmis.eks.present = false;
+ beacon.bmis.eks.kccd = 0;
+ beacon.bmis.eks.kbc = BSU_BEACON_EKS_KBC_NB;
+ beacon.bmis.eks.new_eks = MAC_EKS_NB;
+
+ bsu_update (t.bsu, &beacon, BSU_UPDATE_STA_TYPE_CCO);
+
+ test_fail_unless (t.bsu->sta_avln->beacon.bmis.eks.present == true);
+ test_fail_unless (t.bsu->sta_avln->beacon.bmis.eks.kccd == 3);
+ test_fail_unless (t.bsu->sta_avln->beacon.bmis.eks.kbc
+ == BSU_BEACON_EKS_KBC_NEK);
+ test_fail_unless (t.bsu->sta_avln->beacon.bmis.eks.new_eks == 4);
+ }
+ test_end;
bsu_test_uninit (&t);
}
diff --git a/cesar/bsu/test/utest/src/countdown.c b/cesar/bsu/test/utest/src/countdown.c
index da930c4928..1317b5419e 100644
--- a/cesar/bsu/test/utest/src/countdown.c
+++ b/cesar/bsu/test/utest/src/countdown.c
@@ -210,6 +210,13 @@ test_case_bsu_schedules_countdowns_sta (test_t t, bool beacon_reception)
bsu_test_t ctx;
bsu_beacon_t beacon;
bsu_test_create_beacon (&ctx, &beacon);
+
+ /* Encryption key change. */
+ beacon.bmis.eks.present = true;
+ beacon.bmis.eks.kccd = 4;
+ beacon.bmis.eks.kbc = 1;
+ beacon.bmis.eks.new_eks = 2;
+
test_case_bsu_schedules_countdown_init (t, &ctx, &beacon);
ctx.bsu->is_sta = BSU_UPDATE_STA_TYPE_STA;
pbproc_rx_beacon_params_t params;
@@ -247,9 +254,15 @@ test_case_bsu_schedules_countdowns_cco (test_t t)
bsu_test_t ctx;
bsu_beacon_t beacon;
bsu_test_create_beacon (&ctx, &beacon);
+
+ /* Encryption key change. */
+ beacon.bmis.eks.present = true;
+ beacon.bmis.eks.kccd = 3;
+ beacon.bmis.eks.kbc = 1;
+ beacon.bmis.eks.new_eks = 2;
+
beacon.bmis.change_snid.snidccd--;
beacon.bmis.change_hm.hmccd--;
- beacon.bmis.eks.kccd--;
test_case_bsu_schedules_countdown_init (t, &ctx, &beacon);
ctx.bsu->is_sta = BSU_UPDATE_STA_TYPE_CCO;
ctx.bsu->sta_avln->beacon = beacon;
diff --git a/cesar/bsu/test/utest/src/tests.c b/cesar/bsu/test/utest/src/tests.c
index 0aebedb5af..376305ba57 100644
--- a/cesar/bsu/test/utest/src/tests.c
+++ b/cesar/bsu/test/utest/src/tests.c
@@ -182,11 +182,6 @@ bsu_test_create_beacon (bsu_test_t *ctx, bsu_beacon_t *beacon)
/* Discover info. */
beacon->bmis.discover_info.present = true;
beacon->bmis.discover_info.info_data = 0xcafecafe;
- /* Encryption key change. */
- beacon->bmis.eks.present = true;
- beacon->bmis.eks.kccd = 4;
- beacon->bmis.eks.kbc = 1;
- beacon->bmis.eks.new_eks = 2;
/* Handover. */
beacon->bmis.handover.present = true;
beacon->bmis.handover.hcd = true;
diff --git a/cesar/cp/beacon/src/beacon.c b/cesar/cp/beacon/src/beacon.c
index 636f4ad0fe..afdf81d046 100644
--- a/cesar/cp/beacon/src/beacon.c
+++ b/cesar/cp/beacon/src/beacon.c
@@ -451,7 +451,8 @@ cp_beacon_countdowns (cp_t *ctx)
ctx->beacon.hoip.hoipcd -= bp_nb;
}
/* EKS ... */
- if (ctx->beacon.eks.kccd)
+ if (!cp_sta_own_data_get_cco_status (ctx)
+ && ctx->beacon.eks.kccd)
{
if (ctx->beacon.eks.kccd <= bp_nb)
ctx->beacon.eks.kccd = 0;
@@ -535,11 +536,32 @@ cp_beacon_cco_update_beacon_data (cp_t *ctx)
cp_beacon_countdowns (ctx);
/** Generate the beacon and send. */
cp_beacon_fill (ctx, &beacon);
+
+ /* Either:
+ * - There is no key change.
+ * or
+ * - The bsu should start a key change countdown. The cp informs the bsu by
+ * setting kccd once. */
+ dbg_assert (!beacon.bmis.eks.present
+ || (beacon.bmis.eks.kccd == CP_BEACON_COUNTDOWN_EKS));
+
/** Program the timer to awake and send another central beacon. */
cp_beacon_reconfigure_timer (ctx, true /* CCo */);
GPIO_TOGGLE (LED_BEACON_TX_RX);
if (!hoip_ended)
+ {
bsu_update (ctx->bsu, &beacon, BSU_UPDATE_STA_TYPE_CCO);
+
+ if (ctx->beacon.eks.kccd)
+ {
+ /* Reset KCCD, because we only want to set it once.
+ * Setting it (once) tells the bsu to start the countdown.
+ * The bsu will take care of decrementing it. */
+ ctx->beacon.eks.kccd = 0;
+ ctx->beacon.eks.kbc = BSU_BEACON_EKS_KBC_NB;
+ ctx->beacon.eks.new_eks = MAC_EKS_NB;
+ }
+ }
}
void
diff --git a/cesar/test_general/station/scenario/av/py/sc08_bentry_change.py b/cesar/test_general/station/scenario/av/py/sc08_bentry_change.py
index 6d33247ad6..5bb9d6ac29 100644
--- a/cesar/test_general/station/scenario/av/py/sc08_bentry_change.py
+++ b/cesar/test_general/station/scenario/av/py/sc08_bentry_change.py
@@ -298,7 +298,7 @@ class TestBentryChange (unittest.TestCase):
self.failUnless (beacons)
bentry = BEntryEncryptionKeyChange (
header = scammer.BENTRY_HDR['ENCRYPTION_KEY_CHANGE'],
- length = 2, kccd = 4, kbc = 0, neweks = 1)
+ length = 2, kccd = 5, kbc = 0, neweks = 1)
for i in beacons:
vs_sniffer_ind = Ether (i.get ())
beacon = scammer.get_sniffed_mme (vs_sniffer_ind)