/* Uplink RLC Window as per 3GPP TS 44.060 */ /* * (C) 2012 Ivan Klyuchnikov * (C) 2012 Andreas Eversberg * (C) 2023 by sysmocom - s.f.m.c. GmbH * * All Rights Reserved * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include #include #include #include #include #include #include #include static inline bool gprs_rlcmac_rlc_v_n_is_state(const struct gprs_rlcmac_rlc_v_n *v_n, int bsn, enum gprs_rlcmac_rlc_dl_bsn_state type) { return v_n->v_n[bsn & mod_sns_half()] == type; } static inline void gprs_rlcmac_rlc_v_n_mark(struct gprs_rlcmac_rlc_v_n *v_n, int bsn, enum gprs_rlcmac_rlc_dl_bsn_state type) { v_n->v_n[bsn & mod_sns_half()] = type; } void gprs_rlcmac_rlc_v_n_reset(struct gprs_rlcmac_rlc_v_n *v_n) { unsigned int i; for (i = 0; i < ARRAY_SIZE(v_n->v_n); i++) v_n->v_n[i] = GPRS_RLCMAC_RLC_DL_BSN_INVALID; } /* Check for an individual frame */ bool gprs_rlcmac_rlc_v_n_is_received(const struct gprs_rlcmac_rlc_v_n *v_n, int bsn) { return gprs_rlcmac_rlc_v_n_is_state(v_n, bsn, GPRS_RLCMAC_RLC_DL_BSN_RECEIVED); } enum gprs_rlcmac_rlc_dl_bsn_state gprs_rlcmac_rlc_v_n_get_state(const struct gprs_rlcmac_rlc_v_n *v_n, int bsn) { return v_n->v_n[bsn & mod_sns_half()]; } /* Mark a RLC frame for something */ void gprs_rlcmac_rlc_v_n_mark_received(struct gprs_rlcmac_rlc_v_n *v_n, int bsn) { return gprs_rlcmac_rlc_v_n_mark(v_n, bsn, GPRS_RLCMAC_RLC_DL_BSN_RECEIVED); } void gprs_rlcmac_rlc_v_n_mark_missing(struct gprs_rlcmac_rlc_v_n *v_n, int bsn) { return gprs_rlcmac_rlc_v_n_mark(v_n, bsn, GPRS_RLCMAC_RLC_DL_BSN_MISSING); } void gprs_rlcmac_rlc_v_n_mark_invalid(struct gprs_rlcmac_rlc_v_n *v_n, int bsn) { return gprs_rlcmac_rlc_v_n_mark(v_n, bsn, GPRS_RLCMAC_RLC_DL_BSN_INVALID); } /************* * UL WINDOW *************/ struct gprs_rlcmac_rlc_dl_window *gprs_rlcmac_rlc_dl_window_alloc(struct gprs_rlcmac_dl_tbf *dl_tbf) { struct gprs_rlcmac_rlc_dl_window *dlw; dlw = talloc_zero(dl_tbf, struct gprs_rlcmac_rlc_dl_window); if (!dlw) return NULL; gprs_rlcmac_rlc_window_constructor(rlc_dlw_as_w(dlw)); dlw->dl_tbf = dl_tbf; gprs_rlcmac_rlc_dl_window_reset(dlw); return dlw; } void gprs_rlcmac_rlc_dl_window_free(struct gprs_rlcmac_rlc_dl_window *dlw) { if (!dlw) return; gprs_rlcmac_rlc_window_destructor(rlc_dlw_as_w(dlw)); talloc_free(dlw); } static void gprs_rlcmac_rlc_dl_window_reset_state(struct gprs_rlcmac_rlc_dl_window *dlw) { dlw->v_r = 0; dlw->v_q = 0; } void gprs_rlcmac_rlc_dl_window_reset(struct gprs_rlcmac_rlc_dl_window *dlw) { gprs_rlcmac_rlc_dl_window_reset_state(dlw); gprs_rlcmac_rlc_v_n_reset(&dlw->v_n); } uint16_t gprs_rlcmac_rlc_dl_window_v_r(const struct gprs_rlcmac_rlc_dl_window *dlw) { return dlw->v_r; } uint16_t gprs_rlcmac_rlc_dl_window_v_q(const struct gprs_rlcmac_rlc_dl_window *dlw) { return dlw->v_q; } void gprs_rlcmac_rlc_dl_window_set_v_r(struct gprs_rlcmac_rlc_dl_window *dlw, uint16_t v_r) { dlw->v_r = v_r; } void gprs_rlcmac_rlc_dl_window_set_v_q(struct gprs_rlcmac_rlc_dl_window *dlw, uint16_t v_q) { dlw->v_q = v_q; } bool gprs_rlcmac_rlc_dl_window_is_in_window(const struct gprs_rlcmac_rlc_dl_window *dlw, uint16_t bsn) { const struct gprs_rlcmac_rlc_window *w = rlc_dlw_as_w_const(dlw); uint16_t offset_v_q; /* current block relative to lowest unreceived block */ offset_v_q = (bsn - dlw->v_q) & gprs_rlcmac_rlc_window_mod_sns(w); /* If out of window (may happen if blocks below V(Q) are received * again. */ return offset_v_q < gprs_rlcmac_rlc_window_ws(w); } bool gprs_rlcmac_rlc_dl_window_is_received(const struct gprs_rlcmac_rlc_dl_window *dlw, uint16_t bsn) { const struct gprs_rlcmac_rlc_window *w = rlc_dlw_as_w_const(dlw); uint16_t offset_v_r; /* Offset to the end of the received window */ offset_v_r = (dlw->v_r - 1 - bsn) & gprs_rlcmac_rlc_window_mod_sns(w); return gprs_rlcmac_rlc_dl_window_is_in_window(dlw, bsn) && gprs_rlcmac_rlc_v_n_is_received(&dlw->v_n, bsn) && offset_v_r < gprs_rlcmac_rlc_window_ws(w); } void gprs_rlcmac_rlc_dl_window_update_rbb(const struct gprs_rlcmac_rlc_dl_window *dlw, char *rbb) { const struct gprs_rlcmac_rlc_window *w = rlc_dlw_as_w_const(dlw); uint16_t mod_sns = gprs_rlcmac_rlc_window_mod_sns(w); uint16_t ws = gprs_rlcmac_rlc_window_ws(w); uint16_t ssn = gprs_rlcmac_rlc_dl_window_ssn(dlw); unsigned int i; for (i = 0; i < ws; i++) { if (gprs_rlcmac_rlc_v_n_is_received(&dlw->v_n, (ssn - 1 - i) & mod_sns)) rbb[ws - 1 - i] = 'R'; else rbb[ws - 1 - i] = 'I'; } } /* Update the receive block bitmap */ uint16_t gprs_rlcmac_rlc_dl_window_update_rbb_egprs(const struct gprs_rlcmac_rlc_dl_window *dlw, uint8_t *rbb) { const struct gprs_rlcmac_rlc_window *w = rlc_dlw_as_w_const(dlw); uint16_t ws = gprs_rlcmac_rlc_window_ws(w); uint16_t i; uint16_t bsn; uint16_t bitmask = 0x80; int8_t pos = 0; int8_t bit_pos = 0; for (i = 0, bsn = (dlw->v_q + 1); ((bsn < (dlw->v_r)) && (i < ws)); i++, bsn = gprs_rlcmac_rlc_window_mod_sns_bsn(w, bsn + 1)) { if (gprs_rlcmac_rlc_v_n_is_received(&dlw->v_n, bsn)) rbb[pos] = rbb[pos] | bitmask; else rbb[pos] = rbb[pos] & (~bitmask); bitmask = bitmask >> 1; bit_pos++; bit_pos = bit_pos % 8; if (bit_pos == 0) { pos++; bitmask = 0x80; } } return i; } void gprs_rlcmac_rlc_dl_window_raise_v_r_to(struct gprs_rlcmac_rlc_dl_window *dlw, int moves) { struct gprs_rlcmac_rlc_window *w = rlc_dlw_as_w(dlw); dlw->v_r = gprs_rlcmac_rlc_window_mod_sns_bsn(w, dlw->v_r + moves); } void gprs_rlcmac_rlc_dl_window_raise_v_q_to(struct gprs_rlcmac_rlc_dl_window *dlw, int incr) { struct gprs_rlcmac_rlc_window *w = rlc_dlw_as_w(dlw); dlw->v_q = gprs_rlcmac_rlc_window_mod_sns_bsn(w, dlw->v_q + incr); } /* Raise V(R) to highest received sequence number not received. */ void gprs_rlcmac_rlc_dl_window_raise_v_r(struct gprs_rlcmac_rlc_dl_window *dlw, uint16_t bsn) { struct gprs_rlcmac_rlc_window *w = rlc_dlw_as_w(dlw); uint16_t offset_v_r; offset_v_r = gprs_rlcmac_rlc_window_mod_sns_bsn(w, bsn + 1 - gprs_rlcmac_rlc_dl_window_v_r(dlw)); /* Positive offset, so raise. */ if (offset_v_r < (gprs_rlcmac_rlc_window_sns(w) >> 1)) { while (offset_v_r--) { const uint16_t v_r = gprs_rlcmac_rlc_dl_window_v_r(dlw); const uint16_t bsn_no_longer_in_ws = gprs_rlcmac_rlc_window_mod_sns_bsn(w, v_r - gprs_rlcmac_rlc_window_ws(w)); LOGRLCMAC(LOGL_DEBUG, "- Mark BSN %u as INVALID\n", bsn_no_longer_in_ws); gprs_rlcmac_rlc_v_n_mark_invalid(&dlw->v_n, bsn_no_longer_in_ws); if (offset_v_r) {/* all except the received block */ LOGRLCMAC(LOGL_DEBUG, "- Mark BSN %u as MISSING\n", v_r); gprs_rlcmac_rlc_v_n_mark_missing(&dlw->v_n, v_r); } gprs_rlcmac_rlc_dl_window_raise_v_r_to(dlw, 1); } LOGRLCMAC(LOGL_DEBUG, "- Raising V(R) to %d\n", gprs_rlcmac_rlc_dl_window_v_r(dlw)); } } /* * Raise V(Q) if possible. This is looped until there is a gap * (non received block) or the window is empty. */ uint16_t gprs_rlcmac_rlc_dl_window_raise_v_q(struct gprs_rlcmac_rlc_dl_window *dlw) { struct gprs_rlcmac_rlc_window *w = rlc_dlw_as_w(dlw); uint16_t count = 0; while (gprs_rlcmac_rlc_dl_window_v_q(dlw) != gprs_rlcmac_rlc_dl_window_v_r(dlw)) { if (!gprs_rlcmac_rlc_v_n_is_received(&dlw->v_n, gprs_rlcmac_rlc_dl_window_v_q(dlw))) break; LOGRLCMAC(LOGL_DEBUG, "- Taking block %d out, raising V(Q) to %d\n", gprs_rlcmac_rlc_dl_window_v_q(dlw), gprs_rlcmac_rlc_window_mod_sns_bsn(w, gprs_rlcmac_rlc_dl_window_v_q(dlw) + 1)); gprs_rlcmac_rlc_dl_window_raise_v_q_to(dlw, 1); count += 1; } return count; } void gprs_rlcmac_rlc_dl_window_receive_bsn(struct gprs_rlcmac_rlc_dl_window *dlw, uint16_t bsn) { gprs_rlcmac_rlc_v_n_mark_received(&dlw->v_n, bsn); gprs_rlcmac_rlc_dl_window_raise_v_r(dlw, bsn); }