gprs: Add GPRS timer conversion functions
Currently, all GPRS timer values are hard-coded. To make these values configurable in seconds and to show them, conversion functions from and to seconds are needed. This patch adds gprs_tmr_to_secs and gprs_secs_to_tmr_floor. Due to the limited number of bits used to encode GPRS timer values, only a few durations can be represented. gprs_secs_to_tmr_floor therefore always returns the timer value that represents either the exact number (if an exact representation exists) or the next lower number for that an exact representation exists. Sponsored-by: On-Waves ehf
This commit is contained in:
parent
37184900e7
commit
79af67d7c0
|
@ -31,6 +31,11 @@ int gprs_msgb_resize_area(struct msgb *msg, uint8_t *area,
|
|||
size_t old_size, size_t new_size);
|
||||
char *gprs_apn_to_str(char *out_str, const uint8_t *apn_enc, size_t rest_chars);
|
||||
int gprs_str_to_apn(uint8_t *apn_enc, size_t max_len, const char *str);
|
||||
|
||||
/* GSM 04.08, 10.5.7.3 GPRS Timer */
|
||||
int gprs_tmr_to_secs(uint8_t tmr);
|
||||
uint8_t gprs_secs_to_tmr_floor(int secs);
|
||||
|
||||
int gprs_is_mi_tmsi(const uint8_t *value, size_t value_len);
|
||||
int gprs_is_mi_imsi(const uint8_t *value, size_t value_len);
|
||||
int gprs_parse_mi_tmsi(const uint8_t *value, size_t value_len, uint32_t *tmsi);
|
||||
|
|
|
@ -116,9 +116,12 @@ enum gsm48_gprs_tmr_unit {
|
|||
GPRS_TMR_2SECONDS = 0 << 5,
|
||||
GPRS_TMR_MINUTE = 1 << 5,
|
||||
GPRS_TMR_6MINUTE = 2 << 5,
|
||||
GPRS_TMR_DEACTIVATED = 3 << 5,
|
||||
GPRS_TMR_DEACTIVATED = 7 << 5,
|
||||
};
|
||||
|
||||
#define GPRS_TMR_UNIT_MASK (7 << 5)
|
||||
#define GPRS_TMR_FACT_MASK ((1 << 5)-1)
|
||||
|
||||
/* Chapter 9.4.2 / Table 9.4.2 */
|
||||
struct gsm48_attach_ack {
|
||||
uint8_t att_result:4, /* 10.5.5.7 */
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
*
|
||||
*/
|
||||
#include <openbsc/gprs_utils.h>
|
||||
#include <openbsc/gsm_04_08_gprs.h>
|
||||
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/gprs/gprs_ns.h>
|
||||
|
@ -172,6 +173,50 @@ int gprs_str_to_apn(uint8_t *apn_enc, size_t max_len, const char *str)
|
|||
return len;
|
||||
}
|
||||
|
||||
/* GSM 04.08, 10.5.7.3 GPRS Timer */
|
||||
int gprs_tmr_to_secs(uint8_t tmr)
|
||||
{
|
||||
switch (tmr & GPRS_TMR_UNIT_MASK) {
|
||||
case GPRS_TMR_2SECONDS:
|
||||
return 2 * (tmr & GPRS_TMR_FACT_MASK);
|
||||
default:
|
||||
case GPRS_TMR_MINUTE:
|
||||
return 60 * (tmr & GPRS_TMR_FACT_MASK);
|
||||
case GPRS_TMR_6MINUTE:
|
||||
return 360 * (tmr & GPRS_TMR_FACT_MASK);
|
||||
case GPRS_TMR_DEACTIVATED:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* This functions returns a tmr value such that
|
||||
* - f is monotonic
|
||||
* - f(s) <= s
|
||||
* - f(s) == s if a tmr exists with s = gprs_tmr_to_secs(tmr)
|
||||
* - the best possible resolution is used
|
||||
* where
|
||||
* f(s) = gprs_tmr_to_secs(gprs_secs_to_tmr_floor(s))
|
||||
*/
|
||||
uint8_t gprs_secs_to_tmr_floor(int secs)
|
||||
{
|
||||
if (secs < 0)
|
||||
return GPRS_TMR_DEACTIVATED;
|
||||
if (secs < 2 * 32)
|
||||
return GPRS_TMR_2SECONDS | (secs / 2);
|
||||
if (secs < 60 * 2)
|
||||
/* Ensure monotonicity */
|
||||
return GPRS_TMR_2SECONDS | GPRS_TMR_FACT_MASK;
|
||||
if (secs < 60 * 32)
|
||||
return GPRS_TMR_MINUTE | (secs / 60);
|
||||
if (secs < 360 * 6)
|
||||
/* Ensure monotonicity */
|
||||
return GPRS_TMR_MINUTE | GPRS_TMR_FACT_MASK;
|
||||
if (secs < 360 * 32)
|
||||
return GPRS_TMR_6MINUTE | (secs / 360);
|
||||
|
||||
return GPRS_TMR_6MINUTE | GPRS_TMR_FACT_MASK;
|
||||
}
|
||||
|
||||
/* GSM 04.08, 10.5.1.4 */
|
||||
int gprs_is_mi_tmsi(const uint8_t *value, size_t value_len)
|
||||
{
|
||||
|
|
|
@ -614,6 +614,73 @@ static void test_gsup_messages_dec_enc(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void test_gprs_timer_enc_dec(void)
|
||||
{
|
||||
int i, u, secs, tmr;
|
||||
const int upper_secs_test_limit = 12000;
|
||||
int dec_secs, last_dec_secs = -1;
|
||||
|
||||
printf("Test GPRS timer decoding/encoding\n");
|
||||
|
||||
/* Check gprs_tmr_to_secs with all 256 encoded values */
|
||||
for (u = 0; u <= GPRS_TMR_DEACTIVATED; u += 32) {
|
||||
fprintf(stderr, "Testing decoding with timer value unit %u\n",
|
||||
u / 32);
|
||||
for (i = 0; i < 32; i++) {
|
||||
switch (u) {
|
||||
case GPRS_TMR_2SECONDS:
|
||||
OSMO_ASSERT(gprs_tmr_to_secs(u + i) == 2 * i);
|
||||
break;
|
||||
|
||||
default:
|
||||
case GPRS_TMR_MINUTE:
|
||||
OSMO_ASSERT(gprs_tmr_to_secs(u + i) == 60 * i);
|
||||
break;
|
||||
|
||||
case GPRS_TMR_6MINUTE:
|
||||
OSMO_ASSERT(gprs_tmr_to_secs(u + i) == 360 * i);
|
||||
break;
|
||||
|
||||
case GPRS_TMR_DEACTIVATED:
|
||||
OSMO_ASSERT(gprs_tmr_to_secs(u + i) == -1);
|
||||
break;
|
||||
}
|
||||
|
||||
OSMO_ASSERT(gprs_tmr_to_secs(u + i) < upper_secs_test_limit);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check gprs_secs_to_tmr_floor for secs that can exactly be
|
||||
* represented as GPRS timer values */
|
||||
for (i = 0; i < GPRS_TMR_DEACTIVATED; i++) {
|
||||
int j;
|
||||
secs = gprs_tmr_to_secs(i);
|
||||
tmr = gprs_secs_to_tmr_floor(secs);
|
||||
OSMO_ASSERT(secs == gprs_tmr_to_secs(tmr));
|
||||
|
||||
/* Check that the highest resolution is used */
|
||||
for (j = 0; j < tmr; j++)
|
||||
OSMO_ASSERT(secs != gprs_tmr_to_secs(j));
|
||||
}
|
||||
OSMO_ASSERT(GPRS_TMR_DEACTIVATED == gprs_secs_to_tmr_floor(-1));
|
||||
|
||||
/* Check properties of gprs_secs_to_tmr_floor */
|
||||
for (secs = 0; secs <= upper_secs_test_limit; secs++) {
|
||||
int tmr = gprs_secs_to_tmr_floor(secs);
|
||||
int delta_secs = gprs_tmr_to_secs((tmr & ~0x1f) | 1);
|
||||
dec_secs = gprs_tmr_to_secs(tmr);
|
||||
|
||||
/* Check floor */
|
||||
OSMO_ASSERT(dec_secs <= secs);
|
||||
/* Check monotonicity */
|
||||
OSMO_ASSERT(dec_secs >= last_dec_secs);
|
||||
/* Check max distance (<= resolution) */
|
||||
OSMO_ASSERT(dec_secs - last_dec_secs <= delta_secs);
|
||||
|
||||
last_dec_secs = dec_secs;
|
||||
}
|
||||
}
|
||||
|
||||
const struct log_info_cat default_categories[] = {
|
||||
[DGPRS] = {
|
||||
.name = "DGPRS",
|
||||
|
@ -635,6 +702,7 @@ int main(int argc, char **argv)
|
|||
test_gsm_03_03_apn();
|
||||
test_tlv_shift_functions();
|
||||
test_gsup_messages_dec_enc();
|
||||
test_gprs_timer_enc_dec();
|
||||
|
||||
printf("Done.\n");
|
||||
return EXIT_SUCCESS;
|
||||
|
|
|
@ -27,4 +27,5 @@ Test GSUP message decoding/encoding
|
|||
Testing Purge MS Request
|
||||
Testing Purge MS Error
|
||||
Testing Purge MS Result
|
||||
Test GPRS timer decoding/encoding
|
||||
Done.
|
||||
|
|
Loading…
Reference in New Issue