/* Cesar project {{{ * * Copyright (C) 2007 Spidcom * * <<>> * * }}} */ /** * \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); } }