Move osmo_gsup_messages.[ch] to libosmocore

This requires the corresponding commit in libosmocore.
This commit is contained in:
Harald Welte 2016-04-25 19:07:34 +02:00
parent 50f1c0af56
commit 23d77d56ea
10 changed files with 14 additions and 877 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 gprs_utils.h \
gprs_gb_parse.h smpp.h meas_feed.h osmo_gsup_messages.h \
gprs_gb_parse.h smpp.h meas_feed.h \
gprs_gsup_client.h bsc_msg_filter.h \
oap.h oap_messages.h \
gtphub.h

View File

@ -1,139 +0,0 @@
/* Osmocom Subscriber Update Protocol message encoder/decoder */
/* (C) 2014 by Sysmocom s.f.m.c. GmbH, Author: Jacob Erlbeck
* (C) 2016 by Harald Welte <laforge@gnumonks.org>
* All Rights Reserved
*
* 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 <osmocom/core/msgb.h>
#include <osmocom/gsm/protocol/gsm_23_003.h>
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
#include <osmocom/crypt/auth.h>
/*! Maximum nubmer of PDP inside \ref osmo_gsup_message */
#define OSMO_GSUP_MAX_NUM_PDP_INFO 10 /* GSM 09.02 limits this to 50 */
/*! Maximum number of auth info inside \ref osmo_gsup_message */
#define OSMO_GSUP_MAX_NUM_AUTH_INFO 5
/*! Maximum number of octets encoding MSISDN in BCD format */
#define OSMO_GSUP_MAX_MSISDN_LEN 9
#define OSMO_GSUP_PDP_TYPE_SIZE 2
/*! Information Element Identifiers for GSUP IEs */
enum osmo_gsup_iei {
OSMO_GSUP_IMSI_IE = 0x01,
OSMO_GSUP_CAUSE_IE = 0x02,
OSMO_GSUP_AUTH_TUPLE_IE = 0x03,
OSMO_GSUP_PDP_INFO_COMPL_IE = 0x04,
OSMO_GSUP_PDP_INFO_IE = 0x05,
OSMO_GSUP_CANCEL_TYPE_IE = 0x06,
OSMO_GSUP_FREEZE_PTMSI_IE = 0x07,
OSMO_GSUP_MSISDN_IE = 0x08,
OSMO_GSUP_HLR_NUMBER_IE = 0x09,
OSMO_GSUP_PDP_CONTEXT_ID_IE = 0x10,
OSMO_GSUP_PDP_TYPE_IE = 0x11,
OSMO_GSUP_ACCESS_POINT_NAME_IE = 0x12,
OSMO_GSUP_PDP_QOS_IE = 0x13,
OSMO_GSUP_RAND_IE = 0x20,
OSMO_GSUP_SRES_IE = 0x21,
OSMO_GSUP_KC_IE = 0x22,
/* 3G support */
OSMO_GSUP_IK_IE = 0x23,
OSMO_GSUP_CK_IE = 0x24,
OSMO_GSUP_AUTN_IE = 0x25,
OSMO_GSUP_AUTS_IE = 0x26,
OSMO_GSUP_RES_IE = 0x27,
};
/*! GSUP message type */
enum osmo_gsup_message_type {
OSMO_GSUP_MSGT_UPDATE_LOCATION_REQUEST = 0b00000100,
OSMO_GSUP_MSGT_UPDATE_LOCATION_ERROR = 0b00000101,
OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT = 0b00000110,
OSMO_GSUP_MSGT_SEND_AUTH_INFO_REQUEST = 0b00001000,
OSMO_GSUP_MSGT_SEND_AUTH_INFO_ERROR = 0b00001001,
OSMO_GSUP_MSGT_SEND_AUTH_INFO_RESULT = 0b00001010,
OSMO_GSUP_MSGT_PURGE_MS_REQUEST = 0b00001100,
OSMO_GSUP_MSGT_PURGE_MS_ERROR = 0b00001101,
OSMO_GSUP_MSGT_PURGE_MS_RESULT = 0b00001110,
OSMO_GSUP_MSGT_INSERT_DATA_REQUEST = 0b00010000,
OSMO_GSUP_MSGT_INSERT_DATA_ERROR = 0b00010001,
OSMO_GSUP_MSGT_INSERT_DATA_RESULT = 0b00010010,
OSMO_GSUP_MSGT_DELETE_DATA_REQUEST = 0b00010100,
OSMO_GSUP_MSGT_DELETE_DATA_ERROR = 0b00010101,
OSMO_GSUP_MSGT_DELETE_DATA_RESULT = 0b00010110,
OSMO_GSUP_MSGT_LOCATION_CANCEL_REQUEST = 0b00011100,
OSMO_GSUP_MSGT_LOCATION_CANCEL_ERROR = 0b00011101,
OSMO_GSUP_MSGT_LOCATION_CANCEL_RESULT = 0b00011110,
};
#define OSMO_GSUP_IS_MSGT_REQUEST(msgt) (((msgt) & 0b00000011) == 0b00)
#define OSMO_GSUP_IS_MSGT_ERROR(msgt) (((msgt) & 0b00000011) == 0b01)
#define OSMO_GSUP_TO_MSGT_ERROR(msgt) (((msgt) & 0b11111100) | 0b01)
enum osmo_gsup_cancel_type {
OSMO_GSUP_CANCEL_TYPE_UPDATE = 1, /* on wire: 0 */
OSMO_GSUP_CANCEL_TYPE_WITHDRAW = 2, /* on wire: 1 */
};
/*! parsed/decoded PDP context information */
struct osmo_gsup_pdp_info {
unsigned int context_id;
int have_info;
/*! Type of PDP context */
uint16_t pdp_type;
/*! APN information, still in encoded form. Can be NULL if no
* APN information included */
const uint8_t *apn_enc;
/*! length (in octets) of apn_enc */
size_t apn_enc_len;
/*! QoS information, still in encoded form. Can be NULL if no
* QoS information included */
const uint8_t *qos_enc;
/*! length (in octets) of qos_enc */
size_t qos_enc_len;
};
/*! parsed/decoded GSUP protocol message */
struct osmo_gsup_message {
enum osmo_gsup_message_type message_type;
char imsi[GSM23003_IMSI_MAX_DIGITS+2];
enum gsm48_gmm_cause cause;
enum osmo_gsup_cancel_type cancel_type;
int pdp_info_compl;
int freeze_ptmsi;
struct osmo_auth_vector auth_vectors[OSMO_GSUP_MAX_NUM_AUTH_INFO];
size_t num_auth_vectors;
struct osmo_gsup_pdp_info pdp_infos[OSMO_GSUP_MAX_NUM_PDP_INFO];
size_t num_pdp_infos;
const uint8_t *msisdn_enc;
size_t msisdn_enc_len;
const uint8_t *hlr_enc;
size_t hlr_enc_len;
const uint8_t *auts;
};
int osmo_gsup_decode(const uint8_t *data, size_t data_len,
struct osmo_gsup_message *gsup_msg);
void osmo_gsup_encode(struct msgb *msg, const struct osmo_gsup_message *gsup_msg);

View File

@ -26,7 +26,7 @@ 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 \
osmo_gsup_messages.c gprs_utils.c gprs_gsup_client.c \
gprs_utils.c gprs_gsup_client.c \
sgsn_cdr.c sgsn_ares.c \
oap.c oap_messages.c
osmo_sgsn_LDADD = \

View File

@ -21,13 +21,13 @@
*/
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
#include <osmocom/gsm/gsup.h>
#include <openbsc/gsm_subscriber.h>
#include <openbsc/gprs_gsup_client.h>
#include <openbsc/sgsn.h>
#include <openbsc/gprs_sgsn.h>
#include <openbsc/gprs_gmm.h>
#include <openbsc/osmo_gsup_messages.h>
#include <openbsc/gprs_utils.h>
#include <openbsc/debug.h>

View File

@ -1,472 +0,0 @@
/* Osmocom Subscriber Update Protocol message encoder/decoder */
/*
* (C) 2014 by Sysmocom s.f.m.c. GmbH
* (C) 2015 by Holger Hans Peter Freyther
* (C) 2016 by Harald Welte <laforge@gnumonks.org>
* 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/osmo_gsup_messages.h>
#include <openbsc/debug.h>
#include <openbsc/utils.h>
#include <osmocom/gsm/tlv.h>
#include <osmocom/core/msgb.h>
#include <osmocom/gsm/gsm48_ie.h>
#include <stdint.h>
static int decode_pdp_info(uint8_t *data, size_t data_len,
struct osmo_gsup_pdp_info *pdp_info)
{
int rc;
uint8_t tag;
uint8_t *value;
size_t value_len;
/* specific parts */
while (data_len > 0) {
enum osmo_gsup_iei iei;
rc = osmo_shift_tlv(&data, &data_len, &tag, &value, &value_len);
if (rc < 0)
return -GMM_CAUSE_PROTO_ERR_UNSPEC;
iei = tag;
switch (iei) {
case OSMO_GSUP_PDP_CONTEXT_ID_IE:
pdp_info->context_id = decode_big_endian(value, value_len);
break;
case OSMO_GSUP_PDP_TYPE_IE:
pdp_info->pdp_type =
decode_big_endian(value, value_len) & 0x0fff;
break;
case OSMO_GSUP_ACCESS_POINT_NAME_IE:
pdp_info->apn_enc = value;
pdp_info->apn_enc_len = value_len;
break;
case OSMO_GSUP_PDP_QOS_IE:
pdp_info->qos_enc = value;
pdp_info->qos_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 osmo_auth_vector *auth_vector)
{
int rc;
uint8_t tag;
uint8_t *value;
size_t value_len;
enum osmo_gsup_iei iei;
uint8_t presence = 0;
/* specific parts */
while (data_len > 0) {
rc = osmo_shift_tlv(&data, &data_len, &tag, &value, &value_len);
if (rc < 0)
return -GMM_CAUSE_PROTO_ERR_UNSPEC;
iei = tag;
switch (iei) {
case OSMO_GSUP_RAND_IE:
if (value_len != sizeof(auth_vector->rand))
goto parse_error;
memcpy(auth_vector->rand, value, value_len);
presence |= (1 << 0);
break;
case OSMO_GSUP_SRES_IE:
if (value_len != sizeof(auth_vector->sres))
goto parse_error;
memcpy(auth_vector->sres, value, value_len);
presence |= (1 << 1);
break;
case OSMO_GSUP_KC_IE:
if (value_len != sizeof(auth_vector->kc))
goto parse_error;
memcpy(auth_vector->kc, value, value_len);
presence |= (1 << 2);
break;
case OSMO_GSUP_IK_IE:
if (value_len != sizeof(auth_vector->ik))
goto parse_error;
memcpy(auth_vector->ik, value, value_len);
presence |= (1 << 4);
break;
case OSMO_GSUP_CK_IE:
if (value_len != sizeof(auth_vector->ck))
goto parse_error;
memcpy(auth_vector->ck, value, value_len);
presence |= (1 << 5);
break;
case OSMO_GSUP_AUTN_IE:
if (value_len != sizeof(auth_vector->autn))
goto parse_error;
memcpy(auth_vector->autn, value, value_len);
presence |= (1 << 6);
break;
case OSMO_GSUP_RES_IE:
if (value_len > sizeof(auth_vector->res))
goto parse_error;
memcpy(auth_vector->res, value, value_len);
auth_vector->res_len = value_len;
presence |= (1 << 7);
break;
default:
LOGP(DGPRS, LOGL_ERROR,
"GSUP IE type %d not expected in PDP info\n", iei);
continue;
}
}
if (presence & 0x07)
auth_vector->auth_types |= OSMO_AUTH_TYPE_GSM;
if (presence & 0xf0)
auth_vector->auth_types |= OSMO_AUTH_TYPE_UMTS;
return 0;
parse_error:
LOGP(DGPRS, LOGL_ERROR,
"GSUP IE type %d, length %zu invalid in PDP info\n", iei, value_len);
return -1;
}
/*! Decode (parse) a GSUP message
* \param[in] const_data input data to be parsed
* \param[in] data_len length of input (\a const_data)
* \param[out] gsup_msg callee-allocated output data structure
* \returns 0 on success; negative otherwise
*/
int osmo_gsup_decode(const uint8_t *const_data, size_t data_len,
struct osmo_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 osmo_gsup_pdp_info empty_pdp_info = {0};
static const struct osmo_auth_vector empty_auth_info = {0};
static const struct osmo_gsup_message empty_gsup_message = {0};
*gsup_msg = empty_gsup_message;
/* generic part */
rc = osmo_shift_v_fixed(&data, &data_len, 1, &value);
if (rc < 0)
return -GMM_CAUSE_INV_MAND_INFO;
gsup_msg->message_type = decode_big_endian(value, 1);
rc = osmo_match_shift_tlv(&data, &data_len, OSMO_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 osmo_gsup_iei iei;
struct osmo_gsup_pdp_info pdp_info;
struct osmo_auth_vector auth_info;
rc = osmo_shift_tlv(&data, &data_len, &tag, &value, &value_len);
if (rc < 0)
return -GMM_CAUSE_PROTO_ERR_UNSPEC;
iei = tag;
switch (iei) {
case OSMO_GSUP_IMSI_IE:
case OSMO_GSUP_PDP_TYPE_IE:
case OSMO_GSUP_ACCESS_POINT_NAME_IE:
case OSMO_GSUP_RAND_IE:
case OSMO_GSUP_SRES_IE:
case OSMO_GSUP_KC_IE:
LOGP(DGPRS, LOGL_NOTICE,
"GSUP IE type %d not expected (ignored)\n", iei);
continue;
case OSMO_GSUP_CAUSE_IE:
gsup_msg->cause = decode_big_endian(value, value_len);
break;
case OSMO_GSUP_CANCEL_TYPE_IE:
gsup_msg->cancel_type =
decode_big_endian(value, value_len) + 1;
break;
case OSMO_GSUP_PDP_INFO_COMPL_IE:
gsup_msg->pdp_info_compl = 1;
break;
case OSMO_GSUP_FREEZE_PTMSI_IE:
gsup_msg->freeze_ptmsi = 1;
break;
case OSMO_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 OSMO_GSUP_PDP_INFO_IE:
if (gsup_msg->num_pdp_infos >= OSMO_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;
}
pdp_info = empty_pdp_info;
if (iei == OSMO_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 OSMO_GSUP_AUTH_TUPLE_IE:
if (gsup_msg->num_auth_vectors >= OSMO_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;
}
auth_info = empty_auth_info;
rc = decode_auth_info(value, value_len, &auth_info);
if (rc < 0)
return rc;
gsup_msg->auth_vectors[gsup_msg->num_auth_vectors++] =
auth_info;
break;
case OSMO_GSUP_AUTS_IE:
if (value_len != 16) {
LOGP(DGPRS, LOGL_ERROR,
"AUTS length != 16 received\n");
return -GMM_CAUSE_COND_IE_ERR;
}
gsup_msg->auts = value;
break;
case OSMO_GSUP_MSISDN_IE:
gsup_msg->msisdn_enc = value;
gsup_msg->msisdn_enc_len = value_len;
break;
case OSMO_GSUP_HLR_NUMBER_IE:
gsup_msg->hlr_enc = value;
gsup_msg->hlr_enc_len = value_len;
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 osmo_gsup_iei iei,
const struct osmo_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, OSMO_GSUP_PDP_CONTEXT_ID_IE, sizeof(u8), &u8);
if (pdp_info->pdp_type) {
msgb_tlv_put(msg, OSMO_GSUP_PDP_TYPE_IE,
OSMO_GSUP_PDP_TYPE_SIZE,
encode_big_endian(pdp_info->pdp_type | 0xf000,
OSMO_GSUP_PDP_TYPE_SIZE));
}
if (pdp_info->apn_enc) {
msgb_tlv_put(msg, OSMO_GSUP_ACCESS_POINT_NAME_IE,
pdp_info->apn_enc_len, pdp_info->apn_enc);
}
if (pdp_info->qos_enc) {
msgb_tlv_put(msg, OSMO_GSUP_PDP_QOS_IE,
pdp_info->qos_enc_len, pdp_info->qos_enc);
}
/* Update length field */
*len_field = msgb_length(msg) - old_len;
}
static void encode_auth_info(struct msgb *msg, enum osmo_gsup_iei iei,
const struct osmo_auth_vector *auth_vector)
{
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, OSMO_GSUP_RAND_IE,
sizeof(auth_vector->rand), auth_vector->rand);
msgb_tlv_put(msg, OSMO_GSUP_SRES_IE,
sizeof(auth_vector->sres), auth_vector->sres);
msgb_tlv_put(msg, OSMO_GSUP_KC_IE,
sizeof(auth_vector->kc), auth_vector->kc);
/* Update length field */
*len_field = msgb_length(msg) - old_len;
}
/*! Encode a GSUP message
* \param[out] msg message buffer to which encoded message is written
* \param[in] gsup_msg \ref osmo_gsup_message data to be encoded
*/
void osmo_gsup_encode(struct msgb *msg, const struct osmo_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, OSMO_GSUP_IMSI_IE, bcd_len - 1, &bcd_buf[1]);
/* specific parts */
if (gsup_msg->msisdn_enc)
msgb_tlv_put(msg, OSMO_GSUP_MSISDN_IE,
gsup_msg->msisdn_enc_len, gsup_msg->msisdn_enc);
if (gsup_msg->hlr_enc)
msgb_tlv_put(msg, OSMO_GSUP_HLR_NUMBER_IE,
gsup_msg->hlr_enc_len, gsup_msg->hlr_enc);
if ((u8 = gsup_msg->cause))
msgb_tlv_put(msg, OSMO_GSUP_CAUSE_IE, sizeof(u8), &u8);
if ((u8 = gsup_msg->cancel_type)) {
u8 -= 1;
msgb_tlv_put(msg, OSMO_GSUP_CANCEL_TYPE_IE, sizeof(u8), &u8);
}
if (gsup_msg->pdp_info_compl)
msgb_tlv_put(msg, OSMO_GSUP_PDP_INFO_COMPL_IE, 0, &u8);
if (gsup_msg->freeze_ptmsi)
msgb_tlv_put(msg, OSMO_GSUP_FREEZE_PTMSI_IE, 0, &u8);
for (idx = 0; idx < gsup_msg->num_pdp_infos; idx++) {
const struct osmo_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, OSMO_GSUP_PDP_INFO_IE, pdp_info);
} else {
u8 = pdp_info->context_id;
msgb_tlv_put(msg, OSMO_GSUP_PDP_CONTEXT_ID_IE,
sizeof(u8), &u8);
}
}
for (idx = 0; idx < gsup_msg->num_auth_vectors; idx++) {
const struct osmo_auth_vector *auth_vector;
auth_vector = &gsup_msg->auth_vectors[idx];
encode_auth_info(msg, OSMO_GSUP_AUTH_TUPLE_IE, auth_vector);
}
}

View File

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

View File

@ -5,17 +5,14 @@
#include <openbsc/gprs_llc.h>
#include <openbsc/gprs_utils.h>
#include <openbsc/gprs_gsup_messages.h>
#include <openbsc/debug.h>
#include <osmocom/core/application.h>
#include <osmocom/gsm/gsup.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(); }
#define VERBOSE_FPRINTF(...)
/**
* GSM 04.64 8.4.2 Receipt of unacknowledged information
*/
@ -146,239 +143,6 @@ static void test_gsm_03_03_apn(void)
}
}
/* Tests for osmo_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;
uint8_t buf[1024];
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,
0x08, 0x07, /* MSISDN of the subscriber */
0x91, 0x94, 0x61, 0x46, 0x32, 0x24, 0x43,
0x09, 0x07, /* HLR-Number of the subscriber */
0x91, 0x83, 0x52, 0x38, 0x48, 0x83, 0x93,
0x04, 0x00, /* PDP info complete */
0x05, 0x15,
0x10, 0x01, 0x01,
0x11, 0x02, 0xf1, 0x21, /* IPv4 */
0x12, 0x09, 0x04, 't', 'e', 's', 't', 0x03, 'a', 'p', 'n',
0x13, 0x01, 0x02,
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 uint8_t purge_ms_req[] = {
0x0c,
TEST_IMSI_IE,
};
static const uint8_t purge_ms_err[] = {
0x0d,
TEST_IMSI_IE,
0x02, 0x01, 0x03, /* Illegal MS */
};
static const uint8_t purge_ms_res[] = {
0x0e,
TEST_IMSI_IE,
0x07, 0x00,
};
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)},
{"Purge MS Request",
purge_ms_req, sizeof(purge_ms_req)},
{"Purge MS Error",
purge_ms_err, sizeof(purge_ms_err)},
{"Purge MS Result",
purge_ms_res, sizeof(purge_ms_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);
}
/* simple truncation test */
for (test_idx = 0; test_idx < ARRAY_SIZE(test_messages); test_idx++) {
int j;
const struct test *t = &test_messages[test_idx];
int ie_end = t->data_len;
struct gprs_gsup_message gm = {0};
int counter = 0;
int parse_err = 0;
for (j = t->data_len - 1; j >= 0; --j) {
rc = gprs_gsup_decode(t->data, j, &gm);
counter += 1;
VERBOSE_FPRINTF(stderr,
" partial message decoding: "
"orig_len = %d, trunc = %d, rc = %d, ie_end = %d\n",
t->data_len, j, rc, ie_end);
if (rc >= 0) {
VERBOSE_FPRINTF(stderr,
" remaing partial message: %s\n",
osmo_hexdump(t->data + j, ie_end - j));
OSMO_ASSERT(j <= ie_end - 2);
OSMO_ASSERT(t->data[j+0] <= GPRS_GSUP_KC_IE);
OSMO_ASSERT(t->data[j+1] <= ie_end - j - 2);
ie_end = j;
} else {
parse_err += 1;
}
}
fprintf(stderr,
" message %d: tested %d truncations, %d parse failures\n",
test_idx, counter, parse_err);
}
/* message modification test (relies on ASAN or valgrind being used) */
for (test_idx = 0; test_idx < ARRAY_SIZE(test_messages); test_idx++) {
int j;
const struct test *t = &test_messages[test_idx];
struct gprs_gsup_message gm = {0};
uint8_t val;
int counter = 0;
int parse_err = 0;
OSMO_ASSERT(sizeof(buf) >= t->data_len);
for (j = t->data_len - 1; j >= 0; --j) {
memcpy(buf, t->data, t->data_len);
val = 0;
do {
VERBOSE_FPRINTF(stderr,
"t = %d, len = %d, val = %d\n",
test_idx, j, val);
buf[j] = val;
rc = gprs_gsup_decode(buf, t->data_len, &gm);
counter += 1;
if (rc < 0)
parse_err += 1;
val += 1;
} while (val != (uint8_t)256);
}
fprintf(stderr,
" message %d: tested %d modifications, %d parse failures\n",
test_idx, counter, parse_err);
}
}
static void test_gprs_timer_enc_dec(void)
{
int i, u, secs, tmr;
@ -465,7 +229,6 @@ int main(int argc, char **argv)
test_8_4_2();
test_gsm_03_03_apn();
test_gsup_messages_dec_enc();
test_gprs_timer_enc_dec();
printf("Done.\n");

View File

@ -13,18 +13,5 @@ N(U) = 511, V(UR) = 511 => new
N(U) = 510, V(UR) = 511 => retransmit
N(U) = 481, V(UR) = 511 => retransmit
N(U) = 479, V(UR) = 511 => new
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
Testing Purge MS Request
Testing Purge MS Error
Testing Purge MS Result
Test GPRS timer decoding/encoding
Done.

View File

@ -23,7 +23,6 @@ sgsn_test_LDADD = \
$(top_builddir)/src/gprs/sgsn_libgtp.o \
$(top_builddir)/src/gprs/sgsn_auth.o \
$(top_builddir)/src/gprs/sgsn_ares.o \
$(top_builddir)/src/gprs/gprs_gsup_messages.o \
$(top_builddir)/src/gprs/gprs_gsup_client.o \
$(top_builddir)/src/gprs/gprs_utils.o \
$(top_builddir)/src/gprs/gprs_subscriber.o \

View File

@ -24,7 +24,7 @@
#include <openbsc/gprs_gmm.h>
#include <openbsc/debug.h>
#include <openbsc/gsm_subscriber.h>
#include <openbsc/gprs_gsup_messages.h>
#include <osmocom/gsm/gsup.h>
#include <openbsc/gprs_gsup_client.h>
#include <openbsc/gprs_utils.h>
#include <openbsc/gprs_gb_parse.h>
@ -1266,13 +1266,13 @@ static void test_gmm_attach_subscr_gsup_auth(int retry)
int my_gprs_gsup_client_send(struct gprs_gsup_client *gsupc, struct msgb *msg)
{
struct gprs_gsup_message to_peer = {0};
struct gprs_gsup_message from_peer = {0};
struct osmo_gsup_message to_peer = {0};
struct osmo_gsup_message from_peer = {0};
struct msgb *reply_msg;
int rc;
/* Simulate the GSUP peer */
rc = gprs_gsup_decode(msgb_data(msg), msgb_length(msg), &to_peer);
rc = osmo_gsup_decode(msgb_data(msg), msgb_length(msg), &to_peer);
OSMO_ASSERT(rc >= 0);
OSMO_ASSERT(to_peer.imsi[0] != 0);
strncpy(from_peer.imsi, to_peer.imsi, sizeof(from_peer.imsi));
@ -1281,16 +1281,16 @@ int my_gprs_gsup_client_send(struct gprs_gsup_client *gsupc, struct msgb *msg)
msgb_free(msg);
switch (to_peer.message_type) {
case GPRS_GSUP_MSGT_UPDATE_LOCATION_REQUEST:
case OSMO_GSUP_MSGT_UPDATE_LOCATION_REQUEST:
/* Send UPDATE_LOCATION_RESULT */
return my_subscr_request_update_gsup_auth(NULL);
case GPRS_GSUP_MSGT_SEND_AUTH_INFO_REQUEST:
case OSMO_GSUP_MSGT_SEND_AUTH_INFO_REQUEST:
/* Send SEND_AUTH_INFO_RESULT */
return my_subscr_request_auth_info_gsup_auth(NULL);
case GPRS_GSUP_MSGT_PURGE_MS_REQUEST:
from_peer.message_type = GPRS_GSUP_MSGT_PURGE_MS_RESULT;
case OSMO_GSUP_MSGT_PURGE_MS_REQUEST:
from_peer.message_type = OSMO_GSUP_MSGT_PURGE_MS_RESULT;
break;
default:
@ -1308,7 +1308,7 @@ int my_gprs_gsup_client_send(struct gprs_gsup_client *gsupc, struct msgb *msg)
reply_msg = gprs_gsup_msgb_alloc();
reply_msg->l2h = reply_msg->data;
gprs_gsup_encode(reply_msg, &from_peer);
osmo_gsup_encode(reply_msg, &from_peer);
gprs_subscr_rx_gsup_message(reply_msg);
msgb_free(reply_msg);