gprs: Add encoder/decoder for the Subscriber Update Protocol

This patch adds functions to encode and decode GSUP messages. This
does not include the layer 1 framing (IPA). The messages so far
supported are: send_auth_info_*, update_location_*,
location_cancellation_*.

Sponsored-by: On-Waves ehf
This commit is contained in:
Jacob Erlbeck 2014-12-11 16:54:14 +01:00 committed by Holger Hans Peter Freyther
parent 46684dcfd2
commit f3a271fa73
7 changed files with 662 additions and 4 deletions

View File

@ -15,7 +15,7 @@ noinst_HEADERS = abis_nm.h abis_rsl.h db.h gsm_04_08.h gsm_data.h \
bss.h gsm_data_shared.h ipaccess.h mncc_int.h \
arfcn_range_encode.h nat_rewrite_trie.h bsc_nat_callstats.h \
osmux.h mgcp_transcode.h rtp.h gprs_utils.h \
gprs_gb_parse.h smpp.h meas_feed.h
gprs_gb_parse.h smpp.h meas_feed.h gprs_gsup_messages.h
openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h
openbscdir = $(includedir)/openbsc

View File

@ -0,0 +1,103 @@
/* GPRS Subscriber Update Protocol message encoder/decoder */
/* (C) 2014 by Sysmocom s.f.m.c. GmbH
* All Rights Reserved
*
* Author: Jacob Erlbeck
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#pragma once
#include <stdint.h>
#include <openbsc/gsm_04_08_gprs.h>
#include <openbsc/gsm_data.h>
/* Needed for GSM_IMSI_LENGTH: */
#include <openbsc/gsm_subscriber.h>
#define GPRS_GSUP_MAX_NUM_PDP_INFO 10 /* GSM 09.02 limits this to 50 */
#define GPRS_GSUP_MAX_NUM_AUTH_INFO 5
#define GPRS_GSUP_PDP_TYPE_SIZE 2
enum gprs_gsup_iei {
GPRS_GSUP_IMSI_IE = 0x01,
GPRS_GSUP_CAUSE_IE = 0x02,
GPRS_GSUP_AUTH_TUPLE_IE = 0x03,
GPRS_GSUP_PDP_INFO_COMPL_IE = 0x04,
GPRS_GSUP_PDP_INFO_IE = 0x05,
GPRS_GSUP_CANCEL_TYPE_IE = 0x06,
GPRS_GSUP_PDP_CONTEXT_ID_IE = 0x10,
GPRS_GSUP_PDP_TYPE_IE = 0x11,
GPRS_GSUP_ACCESS_POINT_NAME_IE = 0x12,
GPRS_GSUP_RAND_IE = 0x20,
GPRS_GSUP_SRES_IE = 0x21,
GPRS_GSUP_KC_IE = 0x22
};
enum gprs_gsup_message_type {
GPRS_GSUP_MSGT_UPDATE_LOCATION_REQUEST = 0b00000100,
GPRS_GSUP_MSGT_UPDATE_LOCATION_ERROR = 0b00000101,
GPRS_GSUP_MSGT_UPDATE_LOCATION_RESULT = 0b00000110,
GPRS_GSUP_MSGT_SEND_AUTH_INFO_REQUEST = 0b00001000,
GPRS_GSUP_MSGT_SEND_AUTH_INFO_ERROR = 0b00001001,
GPRS_GSUP_MSGT_SEND_AUTH_INFO_RESULT = 0b00001010,
GPRS_GSUP_MSGT_PURGE_MS_REQUEST = 0b00001100,
GPRS_GSUP_MSGT_PURGE_MS_ERROR = 0b00001101,
GPRS_GSUP_MSGT_PURGE_MS_RESULT = 0b00001110,
GPRS_GSUP_MSGT_INSERT_DATA_REQUEST = 0b00010000,
GPRS_GSUP_MSGT_INSERT_DATA_ERROR = 0b00010001,
GPRS_GSUP_MSGT_INSERT_DATA_RESULT = 0b00010010,
GPRS_GSUP_MSGT_DELETE_DATA_REQUEST = 0b00010100,
GPRS_GSUP_MSGT_DELETE_DATA_ERROR = 0b00010101,
GPRS_GSUP_MSGT_DELETE_DATA_RESULT = 0b00010110,
GPRS_GSUP_MSGT_LOCATION_CANCEL_REQUEST = 0b00011100,
GPRS_GSUP_MSGT_LOCATION_CANCEL_ERROR = 0b00011101,
GPRS_GSUP_MSGT_LOCATION_CANCEL_RESULT = 0b00011110,
};
enum gprs_gsup_cancel_type {
GPRS_GSUP_CANCEL_TYPE_UPDATE = 1, /* on wire: 0 */
GPRS_GSUP_CANCEL_TYPE_WITHDRAW = 2, /* on wire: 1 */
};
struct gprs_gsup_pdp_info {
unsigned int context_id;
int have_info;
uint16_t pdp_type;
const uint8_t *apn_enc;
size_t apn_enc_len;
};
struct gprs_gsup_message {
enum gprs_gsup_message_type message_type;
char imsi[GSM_IMSI_LENGTH];
enum gsm48_gmm_cause cause;
enum gprs_gsup_cancel_type cancel_type;
int pdp_info_compl;
struct gsm_auth_tuple auth_tuples[GPRS_GSUP_MAX_NUM_AUTH_INFO];
size_t num_auth_tuples;
struct gprs_gsup_pdp_info pdp_infos[GPRS_GSUP_MAX_NUM_PDP_INFO];
size_t num_pdp_infos;
};
int gprs_gsup_decode(const uint8_t *data, size_t data_len,
struct gprs_gsup_message *gsup_msg);
void gprs_gsup_encode(struct msgb *msg, const struct gprs_gsup_message *gsup_msg);

View File

@ -22,7 +22,8 @@ osmo_gbproxy_LDADD = $(top_builddir)/src/libcommon/libcommon.a \
osmo_sgsn_SOURCES = gprs_gmm.c gprs_sgsn.c gprs_sndcp.c gprs_sndcp_vty.c \
sgsn_main.c sgsn_vty.c sgsn_libgtp.c \
gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c crc24.c \
sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c
sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c \
gprs_gsup_messages.c gprs_utils.c
osmo_sgsn_LDADD = \
$(top_builddir)/src/libcommon/libcommon.a \
-lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS)

View File

@ -0,0 +1,405 @@
/* GPRS Subscriber Update Protocol message encoder/decoder */
/*
* (C) 2014 by Sysmocom s.f.m.c. GmbH
* All Rights Reserved
*
* Author: Jacob Erlbeck
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <openbsc/gprs_gsup_messages.h>
#include <openbsc/debug.h>
#include <openbsc/gprs_utils.h>
#include <osmocom/gsm/tlv.h>
#include <osmocom/core/msgb.h>
#include <stdint.h>
static uint64_t decode_big_endian(const uint8_t *data, size_t data_len)
{
uint64_t value = 0;
while (data_len > 0) {
value = (value << 8) + *data;
data += 1;
data_len -= 1;
}
return value;
}
static uint8_t *encode_big_endian(uint64_t value, size_t data_len)
{
static uint8_t buf[sizeof(uint64_t)];
int idx;
OSMO_ASSERT(data_len <= ARRAY_SIZE(buf));
for (idx = data_len - 1; idx >= 0; idx--) {
buf[idx] = (uint8_t)value;
value = value >> 8;
}
return buf;
}
static int decode_pdp_info(uint8_t *data, size_t data_len,
struct gprs_gsup_pdp_info *pdp_info)
{
int rc;
uint8_t tag;
uint8_t *value;
size_t value_len;
/* specific parts */
while (data_len > 0) {
enum gprs_gsup_iei iei;
rc = gprs_shift_tlv(&data, &data_len, &tag, &value, &value_len);
if (rc < 0)
return rc;
iei = tag;
switch (iei) {
case GPRS_GSUP_PDP_CONTEXT_ID_IE:
pdp_info->context_id = decode_big_endian(value, value_len);
break;
case GPRS_GSUP_PDP_TYPE_IE:
pdp_info->pdp_type =
decode_big_endian(value, value_len) & 0x0fff;
break;
case GPRS_GSUP_ACCESS_POINT_NAME_IE:
pdp_info->apn_enc = value;
pdp_info->apn_enc_len = value_len;
break;
default:
LOGP(DGPRS, LOGL_ERROR,
"GSUP IE type %d not expected in PDP info\n", iei);
continue;
}
}
return 0;
}
static int decode_auth_info(uint8_t *data, size_t data_len,
struct gsm_auth_tuple *auth_tuple)
{
int rc;
uint8_t tag;
uint8_t *value;
size_t value_len;
enum gprs_gsup_iei iei;
/* specific parts */
while (data_len > 0) {
rc = gprs_shift_tlv(&data, &data_len, &tag, &value, &value_len);
if (rc < 0)
return rc;
iei = tag;
switch (iei) {
case GPRS_GSUP_RAND_IE:
if (value_len != sizeof(auth_tuple->rand))
goto parse_error;
memcpy(auth_tuple->rand, value, value_len);
break;
case GPRS_GSUP_SRES_IE:
if (value_len != sizeof(auth_tuple->sres))
goto parse_error;
memcpy(auth_tuple->sres, value, value_len);
break;
case GPRS_GSUP_KC_IE:
if (value_len != sizeof(auth_tuple->kc))
goto parse_error;
memcpy(auth_tuple->kc, value, value_len);
break;
default:
LOGP(DGPRS, LOGL_ERROR,
"GSUP IE type %d not expected in PDP info\n", iei);
continue;
}
}
return 0;
parse_error:
LOGP(DGPRS, LOGL_ERROR,
"GSUP IE type %d, length %d invalid in PDP info\n", iei, value_len);
return -1;
}
int gprs_gsup_decode(const uint8_t *const_data, size_t data_len,
struct gprs_gsup_message *gsup_msg)
{
int rc;
uint8_t tag;
/* the shift/match functions expect non-const pointers, but we'll
* either copy the data or cast pointers back to const before returning
* them
*/
uint8_t *data = (uint8_t *)const_data;
uint8_t *value;
size_t value_len;
static const struct gprs_gsup_pdp_info empty_pdp_info = {0};
static const struct gsm_auth_tuple empty_auth_info = {0};
/* generic part */
gprs_shift_v_fixed(&data, &data_len, 1, &value);
gsup_msg->message_type = decode_big_endian(value, 1);
rc = gprs_match_tlv(&data, &data_len, GPRS_GSUP_IMSI_IE,
&value, &value_len);
if (rc <= 0)
return -GMM_CAUSE_INV_MAND_INFO;
if (value_len * 2 + 1 > sizeof(gsup_msg->imsi))
return -GMM_CAUSE_INV_MAND_INFO;
/* Note that gsm48_decode_bcd_number expects the number of encoded IMSI
* octets in the first octet. By coincidence (the TLV encoding) the byte
* before the value part already contains this length so we can use it
* here.
*/
OSMO_ASSERT(value[-1] == value_len);
gsm48_decode_bcd_number(gsup_msg->imsi, sizeof(gsup_msg->imsi),
value - 1, 0);
/* specific parts */
while (data_len > 0) {
enum gprs_gsup_iei iei;
struct gprs_gsup_pdp_info pdp_info;
struct gsm_auth_tuple auth_info;
rc = gprs_shift_tlv(&data, &data_len, &tag, &value, &value_len);
if (rc < 0)
return -GMM_CAUSE_PROTO_ERR_UNSPEC;
iei = tag;
switch (iei) {
case GPRS_GSUP_IMSI_IE:
case GPRS_GSUP_PDP_TYPE_IE:
case GPRS_GSUP_ACCESS_POINT_NAME_IE:
case GPRS_GSUP_RAND_IE:
case GPRS_GSUP_SRES_IE:
case GPRS_GSUP_KC_IE:
LOGP(DGPRS, LOGL_NOTICE,
"GSUP IE type %d not expected (ignored)\n", iei);
continue;
case GPRS_GSUP_CAUSE_IE:
gsup_msg->cause = decode_big_endian(value, value_len);
break;
case GPRS_GSUP_CANCEL_TYPE_IE:
gsup_msg->cancel_type =
decode_big_endian(value, value_len) + 1;
break;
case GPRS_GSUP_PDP_INFO_COMPL_IE:
gsup_msg->pdp_info_compl = 1;
break;
case GPRS_GSUP_PDP_CONTEXT_ID_IE:
/* When these IE appear in the top-level part of the
* message, they are used by Delete Subscr Info to delete
* single entries. We don't have an extra list for
* these but use the PDP info list instead */
/* fall through */
case GPRS_GSUP_PDP_INFO_IE:
if (gsup_msg->num_pdp_infos >= GPRS_GSUP_MAX_NUM_PDP_INFO) {
LOGP(DGPRS, LOGL_ERROR,
"GSUP IE type %d (PDP_INFO) max exceeded\n",
iei);
return -GMM_CAUSE_COND_IE_ERR;
}
memcpy(&pdp_info, &empty_pdp_info, sizeof(pdp_info));
if (iei == GPRS_GSUP_PDP_INFO_IE) {
rc = decode_pdp_info(value, value_len, &pdp_info);
if (rc < 0)
return rc;
pdp_info.have_info = 1;
} else {
pdp_info.context_id =
decode_big_endian(value, value_len);
}
gsup_msg->pdp_infos[gsup_msg->num_pdp_infos++] =
pdp_info;
break;
case GPRS_GSUP_AUTH_TUPLE_IE:
if (gsup_msg->num_auth_tuples >= GPRS_GSUP_MAX_NUM_AUTH_INFO) {
LOGP(DGPRS, LOGL_ERROR,
"GSUP IE type %d (AUTH_INFO) max exceeded\n",
iei);
return -GMM_CAUSE_INV_MAND_INFO;
}
memcpy(&auth_info, &empty_auth_info, sizeof(auth_info));
auth_info.key_seq = gsup_msg->num_auth_tuples;
rc = decode_auth_info(value, value_len, &auth_info);
if (rc < 0)
return rc;
gsup_msg->auth_tuples[gsup_msg->num_auth_tuples++] =
auth_info;
break;
default:
LOGP(DGPRS, LOGL_NOTICE,
"GSUP IE type %d unknown\n", iei);
continue;
}
}
return 0;
}
static void encode_pdp_info(struct msgb *msg, enum gprs_gsup_iei iei,
const struct gprs_gsup_pdp_info *pdp_info)
{
uint8_t *len_field;
size_t old_len;
uint8_t u8;
len_field = msgb_tlv_put(msg, iei, 0, NULL) - 1;
old_len = msgb_length(msg);
u8 = pdp_info->context_id;
msgb_tlv_put(msg, GPRS_GSUP_PDP_CONTEXT_ID_IE, sizeof(u8), &u8);
if (pdp_info->pdp_type) {
msgb_tlv_put(msg, GPRS_GSUP_PDP_TYPE_IE,
GPRS_GSUP_PDP_TYPE_SIZE,
encode_big_endian(pdp_info->pdp_type | 0xf000,
GPRS_GSUP_PDP_TYPE_SIZE));
}
if (pdp_info->apn_enc) {
msgb_tlv_put(msg, GPRS_GSUP_ACCESS_POINT_NAME_IE,
pdp_info->apn_enc_len, pdp_info->apn_enc);
}
/* Update length field */
*len_field = msgb_length(msg) - old_len;
}
static void encode_auth_info(struct msgb *msg, enum gprs_gsup_iei iei,
const struct gsm_auth_tuple *auth_tuple)
{
uint8_t *len_field;
size_t old_len;
len_field = msgb_tlv_put(msg, iei, 0, NULL) - 1;
old_len = msgb_length(msg);
msgb_tlv_put(msg, GPRS_GSUP_RAND_IE,
sizeof(auth_tuple->rand), auth_tuple->rand);
msgb_tlv_put(msg, GPRS_GSUP_SRES_IE,
sizeof(auth_tuple->sres), auth_tuple->sres);
msgb_tlv_put(msg, GPRS_GSUP_KC_IE,
sizeof(auth_tuple->kc), auth_tuple->kc);
/* Update length field */
*len_field = msgb_length(msg) - old_len;
}
void gprs_gsup_encode(struct msgb *msg, const struct gprs_gsup_message *gsup_msg)
{
uint8_t u8;
int idx;
uint8_t bcd_buf[GSM48_MI_SIZE] = {0};
size_t bcd_len;
/* generic part */
OSMO_ASSERT(gsup_msg->message_type);
msgb_v_put(msg, gsup_msg->message_type);
bcd_len = gsm48_encode_bcd_number(bcd_buf, sizeof(bcd_buf), 0,
gsup_msg->imsi);
OSMO_ASSERT(bcd_len > 1);
/* Note that gsm48_encode_bcd_number puts the length into the first
* octet. Since msgb_tlv_put will add this length byte, we'll have to
* skip it */
msgb_tlv_put(msg, GPRS_GSUP_IMSI_IE, bcd_len - 1, &bcd_buf[1]);
/* specific parts */
if ((u8 = gsup_msg->cause))
msgb_tlv_put(msg, GPRS_GSUP_CAUSE_IE, sizeof(u8), &u8);
if ((u8 = gsup_msg->cancel_type)) {
u8 -= 1;
msgb_tlv_put(msg, GPRS_GSUP_CANCEL_TYPE_IE, sizeof(u8), &u8);
}
if (gsup_msg->pdp_info_compl)
msgb_tlv_put(msg, GPRS_GSUP_PDP_INFO_COMPL_IE, 0, &u8);
for (idx = 0; idx < gsup_msg->num_pdp_infos; idx++) {
const struct gprs_gsup_pdp_info *pdp_info;
pdp_info = &gsup_msg->pdp_infos[idx];
if (pdp_info->context_id == 0)
continue;
if (pdp_info->have_info) {
encode_pdp_info(msg, GPRS_GSUP_PDP_INFO_IE, pdp_info);
} else {
u8 = pdp_info->context_id;
msgb_tlv_put(msg, GPRS_GSUP_PDP_CONTEXT_ID_IE,
sizeof(u8), &u8);
}
}
for (idx = 0; idx < gsup_msg->num_auth_tuples; idx++) {
const struct gsm_auth_tuple *auth_info;
auth_info = &gsup_msg->auth_tuples[idx];
if (auth_info->key_seq == GSM_KEY_SEQ_INVAL)
continue;
encode_auth_info(msg, GPRS_GSUP_AUTH_TUPLE_IE, auth_info);
}
}

View File

@ -5,5 +5,7 @@ EXTRA_DIST = gprs_test.ok
noinst_PROGRAMS = gprs_test
gprs_test_SOURCES = gprs_test.c $(top_srcdir)/src/gprs/gprs_utils.c
gprs_test_LDADD = $(LIBOSMOCORE_LIBS)
gprs_test_SOURCES = gprs_test.c $(top_srcdir)/src/gprs/gprs_utils.c \
$(top_srcdir)/src/gprs/gprs_gsup_messages.c
gprs_test_LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS)

View File

@ -5,6 +5,8 @@
#include <openbsc/gprs_llc.h>
#include <openbsc/gprs_utils.h>
#include <openbsc/gprs_gsup_messages.h>
#define ASSERT_FALSE(x) if (x) { printf("Should have returned false.\n"); abort(); }
#define ASSERT_TRUE(x) if (!x) { printf("Should have returned true.\n"); abort(); }
@ -378,11 +380,146 @@ static void test_tlv_shift_functions()
}
}
/* Tests for gprs_gsup_messages.c */
#define TEST_IMSI_IE 0x01, 0x08, 0x21, 0x43, 0x65, 0x87, 0x09, 0x21, 0x43, 0xf5
#define TEST_IMSI_STR "123456789012345"
static void test_gsup_messages_dec_enc(void)
{
int test_idx;
int rc;
static const uint8_t send_auth_info_req[] = {
0x08,
TEST_IMSI_IE
};
static const uint8_t send_auth_info_err[] = {
0x09,
TEST_IMSI_IE,
0x02, 0x01, 0x07 /* GPRS no allowed */
};
static const uint8_t send_auth_info_res[] = {
0x0a,
TEST_IMSI_IE,
0x03, 0x22, /* Auth tuple */
0x20, 0x10,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
0x21, 0x04,
0x21, 0x22, 0x23, 0x24,
0x22, 0x08,
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
0x03, 0x22, /* Auth tuple */
0x20, 0x10,
0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90,
0x21, 0x04,
0xa1, 0xa2, 0xa3, 0xa4,
0x22, 0x08,
0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8,
};
static const uint8_t update_location_req[] = {
0x04,
TEST_IMSI_IE,
};
static const uint8_t update_location_err[] = {
0x05,
TEST_IMSI_IE,
0x02, 0x01, 0x07 /* GPRS no allowed */
};
static const uint8_t update_location_res[] = {
0x06,
TEST_IMSI_IE,
0x04, 0x00, /* PDP info complete */
0x05, 0x12,
0x10, 0x01, 0x01,
0x11, 0x02, 0xf1, 0x21, /* IPv4 */
0x12, 0x09, 0x04, 't', 'e', 's', 't', 0x03, 'a', 'p', 'n',
0x05, 0x11,
0x10, 0x01, 0x02,
0x11, 0x02, 0xf1, 0x21, /* IPv4 */
0x12, 0x08, 0x03, 'f', 'o', 'o', 0x03, 'a', 'p', 'n',
};
static const uint8_t location_cancellation_req[] = {
0x1c,
TEST_IMSI_IE,
0x06, 0x01, 0x00,
};
static const uint8_t location_cancellation_err[] = {
0x1d,
TEST_IMSI_IE,
0x02, 0x01, 0x03 /* Illegal MS */
};
static const uint8_t location_cancellation_res[] = {
0x1e,
TEST_IMSI_IE,
};
static const struct test {
char *name;
const uint8_t *data;
size_t data_len;
} test_messages[] = {
{"Send Authentication Info Request",
send_auth_info_req, sizeof(send_auth_info_req)},
{"Send Authentication Info Error",
send_auth_info_err, sizeof(send_auth_info_err)},
{"Send Authentication Info Result",
send_auth_info_res, sizeof(send_auth_info_res)},
{"Update Location Request",
update_location_req, sizeof(update_location_req)},
{"Update Location Error",
update_location_err, sizeof(update_location_err)},
{"Update Location Result",
update_location_res, sizeof(update_location_res)},
{"Location Cancellation Request",
location_cancellation_req, sizeof(location_cancellation_req)},
{"Location Cancellation Error",
location_cancellation_err, sizeof(location_cancellation_err)},
{"Location Cancellation Result",
location_cancellation_res, sizeof(location_cancellation_res)},
};
printf("Test GSUP message decoding/encoding\n");
for (test_idx = 0; test_idx < ARRAY_SIZE(test_messages); test_idx++) {
const struct test *t = &test_messages[test_idx];
struct gprs_gsup_message gm = {0};
struct msgb *msg = msgb_alloc(4096, "gsup_test");
printf(" Testing %s\n", t->name);
rc = gprs_gsup_decode(t->data, t->data_len, &gm);
OSMO_ASSERT(rc >= 0);
gprs_gsup_encode(msg, &gm);
fprintf(stderr, " generated message: %s\n", msgb_hexdump(msg));
fprintf(stderr, " original message: %s\n", osmo_hexdump(t->data, t->data_len));
fprintf(stderr, " IMSI: %s\n", gm.imsi);
OSMO_ASSERT(strcmp(gm.imsi, TEST_IMSI_STR) == 0);
OSMO_ASSERT(msgb_length(msg) == t->data_len);
OSMO_ASSERT(memcmp(msgb_data(msg), t->data, t->data_len) == 0);
msgb_free(msg);
}
}
int main(int argc, char **argv)
{
test_8_4_2();
test_gsm_03_03_apn();
test_tlv_shift_functions();
test_gsup_messages_dec_enc();
printf("Done.\n");
return EXIT_SUCCESS;

View File

@ -14,4 +14,14 @@ N(U) = 510, V(UR) = 511 => retransmit
N(U) = 481, V(UR) = 511 => retransmit
N(U) = 479, V(UR) = 511 => new
Test shift functions
Test GSUP message decoding/encoding
Testing Send Authentication Info Request
Testing Send Authentication Info Error
Testing Send Authentication Info Result
Testing Update Location Request
Testing Update Location Error
Testing Update Location Result
Testing Location Cancellation Request
Testing Location Cancellation Error
Testing Location Cancellation Result
Done.