mirror of
				https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw.git
				synced 2025-11-03 21:43:32 +00:00 
			
		
		
		
	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:
		
				
					committed by
					
						
						Holger Hans Peter Freyther
					
				
			
			
				
	
			
			
			
						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);
 | 
								    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);
 | 
					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);
 | 
					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_tmsi(const uint8_t *value, size_t value_len);
 | 
				
			||||||
int gprs_is_mi_imsi(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);
 | 
					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_2SECONDS	= 0 << 5,
 | 
				
			||||||
	GPRS_TMR_MINUTE		= 1 << 5,
 | 
						GPRS_TMR_MINUTE		= 1 << 5,
 | 
				
			||||||
	GPRS_TMR_6MINUTE	= 2 << 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 */
 | 
					/* Chapter 9.4.2 / Table 9.4.2 */
 | 
				
			||||||
struct gsm48_attach_ack {
 | 
					struct gsm48_attach_ack {
 | 
				
			||||||
	uint8_t att_result:4,	/* 10.5.5.7 */
 | 
						uint8_t att_result:4,	/* 10.5.5.7 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,6 +20,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#include <openbsc/gprs_utils.h>
 | 
					#include <openbsc/gprs_utils.h>
 | 
				
			||||||
 | 
					#include <openbsc/gsm_04_08_gprs.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <osmocom/core/msgb.h>
 | 
					#include <osmocom/core/msgb.h>
 | 
				
			||||||
#include <osmocom/gprs/gprs_ns.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;
 | 
						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 */
 | 
					/* GSM 04.08, 10.5.1.4 */
 | 
				
			||||||
int gprs_is_mi_tmsi(const uint8_t *value, size_t value_len)
 | 
					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[] = {
 | 
					const struct log_info_cat default_categories[] = {
 | 
				
			||||||
	[DGPRS] = {
 | 
						[DGPRS] = {
 | 
				
			||||||
		.name = "DGPRS",
 | 
							.name = "DGPRS",
 | 
				
			||||||
@@ -635,6 +702,7 @@ int main(int argc, char **argv)
 | 
				
			|||||||
	test_gsm_03_03_apn();
 | 
						test_gsm_03_03_apn();
 | 
				
			||||||
	test_tlv_shift_functions();
 | 
						test_tlv_shift_functions();
 | 
				
			||||||
	test_gsup_messages_dec_enc();
 | 
						test_gsup_messages_dec_enc();
 | 
				
			||||||
 | 
						test_gprs_timer_enc_dec();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printf("Done.\n");
 | 
						printf("Done.\n");
 | 
				
			||||||
	return EXIT_SUCCESS;
 | 
						return EXIT_SUCCESS;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,4 +27,5 @@ Test GSUP message decoding/encoding
 | 
				
			|||||||
  Testing Purge MS Request
 | 
					  Testing Purge MS Request
 | 
				
			||||||
  Testing Purge MS Error
 | 
					  Testing Purge MS Error
 | 
				
			||||||
  Testing Purge MS Result
 | 
					  Testing Purge MS Result
 | 
				
			||||||
 | 
					Test GPRS timer decoding/encoding
 | 
				
			||||||
Done.
 | 
					Done.
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user