summaryrefslogtreecommitdiff
path: root/mac/ca/src/backoff.c
blob: 7e3b729408afc0c8197eed895d53f72e57924a73 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
/* Cesar project {{{
 *
 * Copyright (C) 2007 Spidcom
 *
 * <<<Licence>>>
 *
 * }}} */
/**
 * \file    mac/ca/src/backoff.c
 * \brief   Backoff handling.
 * \ingroup mac_ca
 */
#include "common/std.h"

#include "mac/ca/inc/context.h"

#define CA_BACKOFF_RND_INIT 0x42421664

void
ca_backoff_init (ca_t *ctx, u32 seed)
{
    dbg_assert (ctx);
    ctx->backoff.active = false;
    ctx->backoff.bpc = 0;
    ctx->backoff.cw = 0;
    ctx->backoff.bc = 0;
    ctx->backoff.dc = 0;
    lib_rnd_init (&ctx->backoff.rnd_context, CA_BACKOFF_RND_INIT ^ seed);
    CA_TRACE (BACKOFF_INIT);
}

void
ca_backoff_new (ca_t *ctx, uint cap)
{
    static const uint dc_by_pbc[4] = { 0, 1, 3, 15 };
    static const uint cw_by_capmsb_by_pbc[2][4] = {
        { 7, 15, 31, 63 }, { 7, 15, 15, 31 }
    };
    dbg_assert (ctx);
    dbg_assert (cap < 4);
    if (ctx->backoff.active)
        ca_backoff_cancel (ctx);
    if (ctx->backoff.bpc == 0 || ctx->backoff.bc == 0 || ctx->backoff.dc == 0)
    {
        uint bpcm = MIN (3u, ctx->backoff.bpc);
        ctx->backoff.dc = dc_by_pbc[bpcm];
        ctx->backoff.cw = cw_by_capmsb_by_pbc[cap >> 1][bpcm];
        ctx->backoff.bpc++;
        ctx->backoff.bc = lib_rnd32 (&ctx->backoff.rnd_context)
            & ctx->backoff.cw;
    }
    else
    {
        uint bpcm = MIN (3u, ctx->backoff.bpc - 1);
        uint cw = cw_by_capmsb_by_pbc[cap >> 1][bpcm];
        if (cw != ctx->backoff.cw)
        {
            /* Handle CAP change. */
            ctx->backoff.cw = cw;
            ctx->backoff.bc = lib_rnd32 (&ctx->backoff.rnd_context)
                & ctx->backoff.cw;
        }
        else
        {
            ctx->backoff.bc--;
        }
        ctx->backoff.dc--;
    }
    ctx->backoff.active = true;
    CA_TRACE (BACKOFF_NEW, ctx->backoff.bpc, ctx->backoff.cw, ctx->backoff.bc,
              ctx->backoff.dc);
}

void
ca_backoff_deferred (ca_t *ctx, int slot_counter)
{
    dbg_assert (ctx);
    if (ctx->backoff.active)
    {
        if (slot_counter > (int) ctx->backoff.bc)
            ctx->backoff.bc = 0;
        else if (slot_counter > 0)
            ctx->backoff.bc -= slot_counter;
        ctx->backoff.active = false;
        CA_TRACE (BACKOFF_DEFERRED, slot_counter);
    }
}

void
ca_backoff_success (ca_t *ctx)
{
    dbg_assert (ctx);
    ctx->backoff.bpc = 0;
    ctx->backoff.active = false;
    CA_TRACE (BACKOFF_SUCCESS);
}

void
ca_backoff_cancel (ca_t *ctx)
{
    dbg_assert (ctx);
    if (ctx->backoff.active)
    {
        ctx->backoff.bc++;
        ctx->backoff.dc++;
        ctx->backoff.active = false;
        CA_TRACE (BACKOFF_CANCEL);
    }
}