diff options
| -rw-r--r-- | include/osmocom/gsm/gsm0808_utils.h | 11 | ||||
| -rw-r--r-- | include/osmocom/gsm/protocol/gsm_08_08.h | 3 | ||||
| -rw-r--r-- | src/gsm/gsm0808_utils.c | 143 | ||||
| -rw-r--r-- | src/gsm/libosmogsm.map | 6 | ||||
| -rw-r--r-- | tests/gsm0808/gsm0808_test.c | 61 | ||||
| -rw-r--r-- | tests/gsm0808/gsm0808_test.ok | 90 | 
6 files changed, 216 insertions, 98 deletions
diff --git a/include/osmocom/gsm/gsm0808_utils.h b/include/osmocom/gsm/gsm0808_utils.h index 8e71b43c..8cdb74bb 100644 --- a/include/osmocom/gsm/gsm0808_utils.h +++ b/include/osmocom/gsm/gsm0808_utils.h @@ -55,6 +55,17 @@ struct gsm0808_cell_id_list2 {  	unsigned int id_list_len;  }; +extern const struct value_string gsm0808_cell_id_discr_names[]; +static inline const char *gsm0808_cell_id_discr_name(enum CELL_IDENT id_discr) +{ return get_value_string(gsm0808_cell_id_discr_names, id_discr); } + +const char *gsm0808_cell_id_name(const struct gsm0808_cell_id *cid); +const char *gsm0808_cell_id_name2(const struct gsm0808_cell_id *cid); +const char *gsm0808_cell_id_list_name(const struct gsm0808_cell_id_list2 *cil); +int gsm0808_cell_id_list_name_buf(char *buf, size_t buflen, const struct gsm0808_cell_id_list2 *cil); +int gsm0808_cell_id_u_name(char *buf, size_t buflen, +			   enum CELL_IDENT id_discr, const union gsm0808_cell_id_u *u); +  uint8_t gsm0808_enc_aoip_trasp_addr(struct msgb *msg,  				    const struct sockaddr_storage *ss);  int gsm0808_dec_aoip_trasp_addr(struct sockaddr_storage *ss, diff --git a/include/osmocom/gsm/protocol/gsm_08_08.h b/include/osmocom/gsm/protocol/gsm_08_08.h index 4539b960..5d2864ff 100644 --- a/include/osmocom/gsm/protocol/gsm_08_08.h +++ b/include/osmocom/gsm/protocol/gsm_08_08.h @@ -10,7 +10,8 @@  /*   * this is from GSM 03.03 CGI but is copied in GSM 08.08 - * in § 3.2.2.27 for Cell Identifier List + * in § 3.2.2.27 for Cell Identifier List. + * See gsm0808_cell_id_discr_name() for a human readable representation.   */  enum CELL_IDENT {  	CELL_IDENT_WHOLE_GLOBAL		= 0, diff --git a/src/gsm/gsm0808_utils.c b/src/gsm/gsm0808_utils.c index 73d9362e..8ef8e240 100644 --- a/src/gsm/gsm0808_utils.c +++ b/src/gsm/gsm0808_utils.c @@ -1130,4 +1130,147 @@ int gsm0808_speech_codec_from_chan_type(struct gsm0808_speech_codec *sc,  	return 0;  } +/*! Print a human readable name of the cell identifier to the char buffer. + * This is useful both for struct gsm0808_cell_id and struct gsm0808_cell_id_list2. + * See also gsm0808_cell_id_name() and gsm0808_cell_id_list_name(). + * \param[out] buf  Destination buffer to write string representation to. + * \param[in] buflen  Amount of memory available in \a buf. + * \param[in] id_discr  Cell Identifier type. + * \param[in] u  Cell Identifer value. + * \returns Like snprintf(): the amount of characters (excluding terminating nul) written, + *          or that would have been written if the buffer were large enough. + */ +int gsm0808_cell_id_u_name(char *buf, size_t buflen, +			   enum CELL_IDENT id_discr, const union gsm0808_cell_id_u *u) +{ +	switch (id_discr) { +	case CELL_IDENT_LAC: +		return snprintf(buf, buflen, "%u", u->lac); +	case CELL_IDENT_CI: +		return snprintf(buf, buflen, "%u", u->ci); +	case CELL_IDENT_LAC_AND_CI: +		return snprintf(buf, buflen, "%u-%u", u->lac_and_ci.lac, u->lac_and_ci.ci); +	case CELL_IDENT_LAI_AND_LAC: +		return snprintf(buf, buflen, "%s", osmo_lai_name(&u->lai_and_lac)); +	case CELL_IDENT_WHOLE_GLOBAL: +		return snprintf(buf, buflen, "%s", osmo_cgi_name(&u->global)); +	default: +		/* For CELL_IDENT_BSS and CELL_IDENT_NO_CELL, just print the discriminator. +		 * Same for kinds we have no string representation of yet. */ +		return snprintf(buf, buflen, "%s", gsm0808_cell_id_discr_name(id_discr)); +	} +} + +/*! value_string[] for enum CELL_IDENT. */ +const struct value_string gsm0808_cell_id_discr_names[] = { +	{ CELL_IDENT_WHOLE_GLOBAL, "CGI" }, +	{ CELL_IDENT_LAC_AND_CI, "LAC-CI" }, +	{ CELL_IDENT_CI, "CI" }, +	{ CELL_IDENT_NO_CELL, "NO-CELL" }, +	{ CELL_IDENT_LAI_AND_LAC, "LAI" }, +	{ CELL_IDENT_LAC, "LAC" }, +	{ CELL_IDENT_BSS, "BSS" }, +	{ CELL_IDENT_UTRAN_PLMN_LAC_RNC, "UTRAN-PLMN-LAC-RNC" }, +	{ CELL_IDENT_UTRAN_RNC, "UTRAN-RNC" }, +	{ CELL_IDENT_UTRAN_LAC_RNC, "UTRAN-LAC-RNC" }, +	{ 0, NULL } +}; + +#define APPEND_THING(func, args...) do { \ +		int remain = buflen - (pos - buf); \ +		int l = func(pos, remain, ##args); \ +		if (l < 0 || l > remain) \ +			pos = buf + buflen; \ +		else \ +			pos += l; \ +		if (l > 0) \ +			total_len += l; \ +	} while(0) +#define APPEND_STR(fmt, args...) APPEND_THING(snprintf, fmt, ##args) +#define APPEND_CELL_ID_U(DISCR, U) APPEND_THING(gsm0808_cell_id_u_name, DISCR, U) + +static const char *gsm0808_cell_id_name_buf(const struct gsm0808_cell_id *cid, +					    char *buf, size_t buflen) +{ +	char *pos = buf; +	int total_len = 0; +	APPEND_STR("%s:", gsm0808_cell_id_discr_name(cid->id_discr)); +	APPEND_CELL_ID_U(cid->id_discr, &cid->id); +	return buf; +} + +/*! Return a human readable representation of a Cell Identifier, like "LAC:123" + * or "CGI:001-01-42-23". + * \param[in] cid  Cell Identifer. + * \returns String in a static buffer. + */ +const char *gsm0808_cell_id_name(const struct gsm0808_cell_id *cid) +{ +	static char buf[64]; +	return gsm0808_cell_id_name_buf(cid, buf, sizeof(buf)); +} + +/*! Like gsm0808_cell_id_name() but uses a different static buffer. + * \param[in] cid  Cell Identifer. + * \returns String in a static buffer. + */ +const char *gsm0808_cell_id_name2(const struct gsm0808_cell_id *cid) +{ +	static char buf[64]; +	return gsm0808_cell_id_name_buf(cid, buf, sizeof(buf)); +} + +/*! Return a human readable representation of the Cell Identifier List, like + * "LAC[2]:{123, 456}". + * The return value semantics are like snprintf() and thus allow ensuring a complete + * untruncated string by determining the required string length from the return value. + * If buflen > 0, always nul-terminate the string in buf, also when it is truncated. + * If buflen == 0, do not modify buf, just return the would-be length. + * \param[out] buf  Destination buffer to write string representation to. + * \param[in] buflen  Amount of memory available in \a buf. + * \param[in] cil  Cell Identifer List. + * \returns Like snprintf(): the amount of characters (excluding terminating nul) written, + *          or that would have been written if the buffer were large enough. + */ +int gsm0808_cell_id_list_name_buf(char *buf, size_t buflen, const struct gsm0808_cell_id_list2 *cil) +{ +	char *pos = buf; +	int total_len = 0; +	int i; + +	APPEND_STR("%s[%u]", gsm0808_cell_id_discr_name(cil->id_discr), cil->id_list_len); + +	switch (cil->id_discr) { +	case CELL_IDENT_BSS: +	case CELL_IDENT_NO_CELL: +		return total_len; +	default: +		break; +	} + +	APPEND_STR(":{"); + +	for (i = 0; i < cil->id_list_len; i++) { +		if (i) +			APPEND_STR(", "); +		APPEND_CELL_ID_U(cil->id_discr, &cil->id_list[i]); +	} + +	APPEND_STR("}"); +	return total_len; +} + +/*! Return a human-readable representation of \a cil in a static buffer. + * If the list is too long, the output may be truncated. + * See also gsm0808_cell_id_list_name_buf(). */ +const char *gsm0808_cell_id_list_name(const struct gsm0808_cell_id_list2 *cil) +{ +	static char buf[1024]; +	gsm0808_cell_id_list_name_buf(buf, sizeof(buf), cil); +	return buf; +} + +#undef APPEND_STR +#undef APPEND_CELL_ID_U +  /*! @} */ diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map index 388fcc04..f04fd58c 100644 --- a/src/gsm/libosmogsm.map +++ b/src/gsm/libosmogsm.map @@ -179,6 +179,12 @@ gsm0808_dec_cell_id_list2;  gsm0808_cell_id_list_add;  gsm0808_enc_cell_id;  gsm0808_dec_cell_id; +gsm0808_cell_id_name; +gsm0808_cell_id_name2; +gsm0808_cell_id_list_name; +gsm0808_cell_id_list_name_buf; +gsm0808_cell_id_discr_names; +gsm0808_cell_id_u_name;  gsm0808_chan_type_to_speech_codec;  gsm0808_speech_codec_from_chan_type;  gsm0808_speech_codec_type_names; diff --git a/tests/gsm0808/gsm0808_test.c b/tests/gsm0808/gsm0808_test.c index 49673fe4..78238ff3 100644 --- a/tests/gsm0808/gsm0808_test.c +++ b/tests/gsm0808/gsm0808_test.c @@ -1073,36 +1073,12 @@ static void test_gsm0808_enc_dec_cell_id_list_multi_global()  static void print_cil(const struct gsm0808_cell_id_list2 *cil)  { -	unsigned int i; -	if (!cil) { -		printf("     cell_id_list == NULL\n"); -		return; -	} -	switch (cil->id_discr) { -	case CELL_IDENT_WHOLE_GLOBAL: -		printf("     cell_id_list cgi[%u] = {\n", cil->id_list_len); -		for (i = 0; i < cil->id_list_len; i++) -			printf("       %2d: %s\n", i, osmo_cgi_name(&cil->id_list[i].global)); -		printf("     }\n"); -		break; -	case CELL_IDENT_LAC: -		printf("     cell_id_list lac[%u] = {\n", cil->id_list_len); -		for (i = 0; i < cil->id_list_len; i++) -			printf("      %2d: %u\n", i, cil->id_list[i].lac); -		printf("     }\n"); -		break; -	case CELL_IDENT_BSS: -		printf("     cell_id_list bss[%u]\n", cil->id_list_len); -		break; -	case CELL_IDENT_NO_CELL: -		printf("     cell_id_list no_cell[%u]\n", cil->id_list_len); -		break; -	default: -		printf("     Unimplemented id_disc\n"); -	} +	printf("     cell_id_list == %s\n", gsm0808_cell_id_list_name(cil));  }  void test_cell_id_list_add() { +	size_t zu; +  	const struct gsm0808_cell_id_list2 cgi1 = {  		.id_discr = CELL_IDENT_WHOLE_GLOBAL,  		.id_list_len = 1, @@ -1220,7 +1196,7 @@ void test_cell_id_list_add() {  #define ADD_QUIET(other_cil, expect_rc) do { \  		int rc = gsm0808_cell_id_list_add(&cil, &other_cil); \ -		printf("\ngsm0808_cell_id_list_add(&cil, &" #other_cil ") --> rc = %d\n", rc); \ +		printf("gsm0808_cell_id_list_add(&cil, &" #other_cil ") --> rc = %d\n", rc); \  		OSMO_ASSERT(rc == expect_rc); \  	} while(0) @@ -1233,13 +1209,13 @@ void test_cell_id_list_add() {  	ADD(cil, 0);  	ADD(cgi1, -EINVAL); -	printf("\ncan't add to BSS list\n"); +	printf("* can't add to BSS list\n");  	cil.id_list_len = 0;  	cil.id_discr = CELL_IDENT_BSS;  	print_cil(&cil);  	ADD(lac1, -EINVAL); -	printf("\nother types (including NO_CELL) take on new type iff empty\n"); +	printf("* other types (including NO_CELL) take on new type iff empty\n");  	cil.id_list_len = 0;  	cil.id_discr = CELL_IDENT_NO_CELL;  	print_cil(&cil); @@ -1248,15 +1224,34 @@ void test_cell_id_list_add() {  	ADD(cgi2, 2);  	ADD(cgi2, 0); +	printf("* test gsm0808_cell_id_list_name_buf()'s return val\n"); +	zu = strlen(gsm0808_cell_id_list_name(&cil)); +	printf("  strlen(gsm0808_cell_id_list_name(cil)) == %zu\n", zu); +	zu ++; +	while (1) { +		char buf[128] = "?"; +		int rc; +		OSMO_ASSERT(zu < sizeof(buf)); +		buf[zu] = '#'; +		rc = gsm0808_cell_id_list_name_buf(buf, zu, &cil); +		printf("  gsm0808_cell_id_list_name_buf(buf, %zu, cil)) == %d \"%s\"\n", +		       zu, rc, buf); +		OSMO_ASSERT(buf[zu] == '#'); +		if (!zu) +			break; +		zu /= 2; +	} + +	printf("* list-full behavior\n");  	cil.id_list_len = GSM0808_CELL_ID_LIST2_MAXLEN - 1; -	printf("\ncil.id_list_len = %u", cil.id_list_len); +	printf("cil.id_list_len = %u\n", cil.id_list_len);  	ADD_QUIET(cgi2a, 1);  	printf("cil.id_list_len = %u\n", cil.id_list_len);  	cil.id_list_len = GSM0808_CELL_ID_LIST2_MAXLEN - 1; -	printf("\ncil.id_list_len = %u", cil.id_list_len); +	printf("cil.id_list_len = %u\n", cil.id_list_len);  	ADD_QUIET(cgi3, -ENOSPC); -	printf("cil.id_list_len = %u", cil.id_list_len); +	printf("cil.id_list_len = %u\n", cil.id_list_len);  	ADD_QUIET(cgi2a, -ENOSPC);  	printf("cil.id_list_len = %u\n", cil.id_list_len); diff --git a/tests/gsm0808/gsm0808_test.ok b/tests/gsm0808/gsm0808_test.ok index 34d7ebfd..6cd7982b 100644 --- a/tests/gsm0808/gsm0808_test.ok +++ b/tests/gsm0808/gsm0808_test.ok @@ -21,84 +21,46 @@ Testing creating DTAP  Testing prepend DTAP  test_gsm0808_enc_dec_cell_id_list_lac: encoded: 1a 07 05 01 24 ab cd 56 78 (rc = 9)  ------- test_cell_id_list_add -     cell_id_list cgi[0] = { -     } - +     cell_id_list == CGI[0]:{}  gsm0808_cell_id_list_add(&cil, &lac1) --> rc = 1 -     cell_id_list lac[1] = { -       0: 123 -     } - +     cell_id_list == LAC[1]:{123}  gsm0808_cell_id_list_add(&cil, &lac1) --> rc = 0 -     cell_id_list lac[1] = { -       0: 123 -     } - +     cell_id_list == LAC[1]:{123}  gsm0808_cell_id_list_add(&cil, &lac2) --> rc = 2 -     cell_id_list lac[3] = { -       0: 123 -       1: 456 -       2: 789 -     } - +     cell_id_list == LAC[3]:{123, 456, 789}  gsm0808_cell_id_list_add(&cil, &lac2) --> rc = 0 -     cell_id_list lac[3] = { -       0: 123 -       1: 456 -       2: 789 -     } - +     cell_id_list == LAC[3]:{123, 456, 789}  gsm0808_cell_id_list_add(&cil, &cil) --> rc = 0 -     cell_id_list lac[3] = { -       0: 123 -       1: 456 -       2: 789 -     } - +     cell_id_list == LAC[3]:{123, 456, 789}  gsm0808_cell_id_list_add(&cil, &cgi1) --> rc = -22 -     cell_id_list lac[3] = { -       0: 123 -       1: 456 -       2: 789 -     } - -can't add to BSS list -     cell_id_list bss[0] - +     cell_id_list == LAC[3]:{123, 456, 789} +* can't add to BSS list +     cell_id_list == BSS[0]  gsm0808_cell_id_list_add(&cil, &lac1) --> rc = -22 -     cell_id_list bss[0] - -other types (including NO_CELL) take on new type iff empty -     cell_id_list no_cell[0] - +     cell_id_list == BSS[0] +* other types (including NO_CELL) take on new type iff empty +     cell_id_list == NO-CELL[0]  gsm0808_cell_id_list_add(&cil, &cgi1) --> rc = 1 -     cell_id_list cgi[1] = { -        0: 001-02-3-4 -     } - +     cell_id_list == CGI[1]:{001-02-3-4}  gsm0808_cell_id_list_add(&cil, &cgi1) --> rc = 0 -     cell_id_list cgi[1] = { -        0: 001-02-3-4 -     } - +     cell_id_list == CGI[1]:{001-02-3-4}  gsm0808_cell_id_list_add(&cil, &cgi2) --> rc = 2 -     cell_id_list cgi[3] = { -        0: 001-02-3-4 -        1: 001-002-3-4 -        2: 005-006-7-8 -     } - +     cell_id_list == CGI[3]:{001-02-3-4, 001-002-3-4, 005-006-7-8}  gsm0808_cell_id_list_add(&cil, &cgi2) --> rc = 0 -     cell_id_list cgi[3] = { -        0: 001-02-3-4 -        1: 001-002-3-4 -        2: 005-006-7-8 -     } - +     cell_id_list == CGI[3]:{001-02-3-4, 001-002-3-4, 005-006-7-8} +* test gsm0808_cell_id_list_name_buf()'s return val +  strlen(gsm0808_cell_id_list_name(cil)) == 45 +  gsm0808_cell_id_list_name_buf(buf, 46, cil)) == 45 "CGI[3]:{001-02-3-4, 001-002-3-4, 005-006-7-8}" +  gsm0808_cell_id_list_name_buf(buf, 23, cil)) == 45 "CGI[3]:{001-02-3-4, 00" +  gsm0808_cell_id_list_name_buf(buf, 11, cil)) == 45 "CGI[3]:{00" +  gsm0808_cell_id_list_name_buf(buf, 5, cil)) == 45 "CGI[" +  gsm0808_cell_id_list_name_buf(buf, 2, cil)) == 45 "C" +  gsm0808_cell_id_list_name_buf(buf, 1, cil)) == 45 "" +  gsm0808_cell_id_list_name_buf(buf, 0, cil)) == 45 "#" +* list-full behavior  cil.id_list_len = 126  gsm0808_cell_id_list_add(&cil, &cgi2a) --> rc = 1  cil.id_list_len = 127 -  cil.id_list_len = 126  gsm0808_cell_id_list_add(&cil, &cgi3) --> rc = -28  cil.id_list_len = 127  | 
