summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJacob Erlbeck <jerlbeck@sysmocom.de>2015-01-15 17:08:30 +0100
committerJacob Erlbeck <jerlbeck@sysmocom.de>2015-01-19 08:30:01 +0100
commit1635150f2ccfb3cba636b42ac8aa1c916e0ae8ec (patch)
tree8a36aa017edd261de9a31631eef62a878faf7c7e
parenta688976f10bfb0c14954a066aa133f28bce3a541 (diff)
gprs: Add replies for all GSUP requests
Currently, an incoming GSUP request message isn't answered at all if it is not handled due to an error or missing implementation. This patch adds GSUP error replies for these requests (and only for requests). It also adds tests for these cases. Note that several of these tests check for GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL, which will have to be changed, when the features are implemented. Sponsored-by: On-Waves ehf
-rw-r--r--openbsc/include/openbsc/gprs_gsup_messages.h4
-rw-r--r--openbsc/include/openbsc/gprs_sgsn.h3
-rw-r--r--openbsc/src/gprs/gprs_subscriber.c59
-rw-r--r--openbsc/tests/sgsn/sgsn_test.c47
4 files changed, 103 insertions, 10 deletions
diff --git a/openbsc/include/openbsc/gprs_gsup_messages.h b/openbsc/include/openbsc/gprs_gsup_messages.h
index b63f74b..9857b97 100644
--- a/openbsc/include/openbsc/gprs_gsup_messages.h
+++ b/openbsc/include/openbsc/gprs_gsup_messages.h
@@ -74,6 +74,10 @@ enum gprs_gsup_message_type {
GPRS_GSUP_MSGT_LOCATION_CANCEL_RESULT = 0b00011110,
};
+#define GPRS_GSUP_IS_MSGT_REQUEST(msgt) (((msgt) & 0b00000011) == 0b00)
+#define GPRS_GSUP_IS_MSGT_ERROR(msgt) (((msgt) & 0b00000011) == 0b01)
+#define GPRS_GSUP_TO_MSGT_ERROR(msgt) (((msgt) & 0b11111100) | 0b01)
+
enum gprs_gsup_cancel_type {
GPRS_GSUP_CANCEL_TYPE_UPDATE = 1, /* on wire: 0 */
GPRS_GSUP_CANCEL_TYPE_WITHDRAW = 2, /* on wire: 1 */
diff --git a/openbsc/include/openbsc/gprs_sgsn.h b/openbsc/include/openbsc/gprs_sgsn.h
index d6a9bda..25810ab 100644
--- a/openbsc/include/openbsc/gprs_sgsn.h
+++ b/openbsc/include/openbsc/gprs_sgsn.h
@@ -289,7 +289,8 @@ struct sgsn_subscriber_data {
};
#define LOGGSUBSCRP(level, subscr, fmt, args...) \
- LOGP(DGPRS, level, "SUBSCR(%s) " fmt, (subscr)->imsi, \
+ LOGP(DGPRS, level, "SUBSCR(%s) " fmt, \
+ (subscr) ? (subscr)->imsi : "---", \
## args)
struct sgsn_config;
diff --git a/openbsc/src/gprs/gprs_subscriber.c b/openbsc/src/gprs/gprs_subscriber.c
index 88e037e..e971210 100644
--- a/openbsc/src/gprs/gprs_subscriber.c
+++ b/openbsc/src/gprs/gprs_subscriber.c
@@ -231,12 +231,13 @@ static int gprs_subscr_tx_gsup_message(struct gsm_subscriber *subscr,
{
struct msgb *msg = gprs_gsup_msgb_alloc();
- strncpy(gsup_msg->imsi, subscr->imsi, sizeof(gsup_msg->imsi) - 1);
+ if (strlen(gsup_msg->imsi) == 0 && subscr)
+ strncpy(gsup_msg->imsi, subscr->imsi, sizeof(gsup_msg->imsi) - 1);
gprs_gsup_encode(msg, gsup_msg);
LOGGSUBSCRP(LOGL_INFO, subscr,
- "Sending GSUP, will send: %s\n", msgb_hexdump(msg));
+ "Sending GSUP, will send: %s\n", msgb_hexdump(msg));
if (!sgsn->gsup_client) {
msgb_free(msg);
@@ -246,6 +247,20 @@ static int gprs_subscr_tx_gsup_message(struct gsm_subscriber *subscr,
return gprs_gsup_client_send(sgsn->gsup_client, msg);
}
+static int gprs_subscr_tx_gsup_error_reply(struct gsm_subscriber *subscr,
+ struct gprs_gsup_message *gsup_orig,
+ enum gsm48_gmm_cause cause)
+{
+ struct gprs_gsup_message gsup_reply = {0};
+
+ strncpy(gsup_reply.imsi, gsup_orig->imsi, sizeof(gsup_reply.imsi) - 1);
+ gsup_reply.cause = cause;
+ gsup_reply.message_type =
+ GPRS_GSUP_TO_MSGT_ERROR(gsup_orig->message_type);
+
+ return gprs_subscr_tx_gsup_message(subscr, &gsup_reply);
+}
+
static int gprs_subscr_handle_gsup_auth_res(struct gsm_subscriber *subscr,
struct gprs_gsup_message *gsup_msg)
{
@@ -475,6 +490,32 @@ static int gprs_subscr_handle_gsup_purge_err(struct gsm_subscriber *subscr,
return -gsup_msg->cause;
}
+static int gprs_subscr_handle_unknown_imsi(struct gprs_gsup_message *gsup_msg)
+{
+ if (GPRS_GSUP_IS_MSGT_REQUEST(gsup_msg->message_type)) {
+ gprs_subscr_tx_gsup_error_reply(NULL, gsup_msg,
+ GMM_CAUSE_IMSI_UNKNOWN);
+ LOGP(DGPRS, LOGL_NOTICE,
+ "Unknown IMSI %s, discarding GSUP request "
+ "of type 0x%02x\n",
+ gsup_msg->imsi, gsup_msg->message_type);
+ } else if (GPRS_GSUP_IS_MSGT_ERROR(gsup_msg->message_type)) {
+ LOGP(DGPRS, LOGL_NOTICE,
+ "Unknown IMSI %s, discarding GSUP error "
+ "of type 0x%02x, cause '%s' (%d)\n",
+ gsup_msg->imsi, gsup_msg->message_type,
+ get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
+ gsup_msg->cause);
+ } else {
+ LOGP(DGPRS, LOGL_NOTICE,
+ "Unknown IMSI %s, discarding GSUP response "
+ "of type 0x%02x\n",
+ gsup_msg->imsi, gsup_msg->message_type);
+ }
+
+ return -GMM_CAUSE_IMSI_UNKNOWN;
+}
+
int gprs_subscr_rx_gsup_message(struct msgb *msg)
{
uint8_t *data = msgb_l2(msg);
@@ -500,11 +541,8 @@ int gprs_subscr_rx_gsup_message(struct msgb *msg)
else
subscr = gprs_subscr_get_by_imsi(gsup_msg.imsi);
- if (!subscr) {
- LOGP(DGPRS, LOGL_NOTICE,
- "Unknown IMSI %s, discarding GSUP message\n", gsup_msg.imsi);
- return -GMM_CAUSE_IMSI_UNKNOWN;
- }
+ if (!subscr)
+ return gprs_subscr_handle_unknown_imsi(&gsup_msg);
LOGGSUBSCRP(LOGL_INFO, subscr,
"Received GSUP message of type 0x%02x\n", gsup_msg.message_type);
@@ -545,6 +583,8 @@ int gprs_subscr_rx_gsup_message(struct msgb *msg)
LOGGSUBSCRP(LOGL_ERROR, subscr,
"Rx GSUP message type %d not yet implemented\n",
gsup_msg.message_type);
+ gprs_subscr_tx_gsup_error_reply(subscr, &gsup_msg,
+ GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL);
rc = -GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL;
break;
@@ -552,7 +592,10 @@ int gprs_subscr_rx_gsup_message(struct msgb *msg)
LOGGSUBSCRP(LOGL_ERROR, subscr,
"Rx GSUP message type %d not valid at SGSN\n",
gsup_msg.message_type);
- rc = -GMM_CAUSE_MSGT_INCOMP_P_STATE;
+ if (GPRS_GSUP_IS_MSGT_REQUEST(gsup_msg.message_type))
+ gprs_subscr_tx_gsup_error_reply(
+ subscr, &gsup_msg, GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL);
+ rc = -GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL;
break;
};
diff --git a/openbsc/tests/sgsn/sgsn_test.c b/openbsc/tests/sgsn/sgsn_test.c
index d419f0a..7050a16 100644
--- a/openbsc/tests/sgsn/sgsn_test.c
+++ b/openbsc/tests/sgsn/sgsn_test.c
@@ -468,6 +468,21 @@ static void test_subscriber_gsup(void)
0x06, 0x01, 0x00,
};
+ static const uint8_t insert_data_req[] = {
+ 0x10,
+ TEST_GSUP_IMSI1_IE,
+ 0x05, 0x11,
+ 0x10, 0x01, 0x03,
+ 0x11, 0x02, 0xf1, 0x21, /* IPv4 */
+ 0x12, 0x08, 0x03, 'b', 'a', 'r', 0x03, 'a', 'p', 'n',
+ };
+
+ static const uint8_t delete_data_req[] = {
+ 0x14,
+ TEST_GSUP_IMSI1_IE,
+ 0x10, 0x01, 0x03,
+ };
+
printf("Testing subcriber GSUP handling\n");
update_subscriber_data_cb = my_dummy_sgsn_update_subscriber_data;
@@ -527,7 +542,19 @@ static void test_subscriber_gsup(void)
/* Check authorization */
OSMO_ASSERT(s1->authorized == 0);
- /* Inject UpdateLocReq GSUP message */
+ /* Inject InsertSubscrData GSUP message */
+ last_updated_subscr = NULL;
+ rc = rx_gsup_message(insert_data_req, sizeof(insert_data_req));
+ OSMO_ASSERT(rc == -GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL);
+ OSMO_ASSERT(last_updated_subscr == NULL);
+
+ /* Inject DeleteSubscrData GSUP message */
+ last_updated_subscr = NULL;
+ rc = rx_gsup_message(delete_data_req, sizeof(delete_data_req));
+ OSMO_ASSERT(rc == -GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL);
+ OSMO_ASSERT(last_updated_subscr == NULL);
+
+ /* Inject LocCancelReq GSUP message */
rc = rx_gsup_message(location_cancellation_req,
sizeof(location_cancellation_req));
OSMO_ASSERT(rc >= 0);
@@ -543,6 +570,24 @@ static void test_subscriber_gsup(void)
OSMO_ASSERT(s1found == NULL);
gprs_llgmm_assign(llme, local_tlli, 0xffffffff, GPRS_ALGO_GEA0, NULL);
+ /* Inject InsertSubscrData GSUP message (unknown IMSI) */
+ last_updated_subscr = NULL;
+ rc = rx_gsup_message(insert_data_req, sizeof(insert_data_req));
+ /* TODO: Remove the comments when this is fixed */
+ /* OSMO_ASSERT(rc == -GMM_CAUSE_IMSI_UNKNOWN); */
+ OSMO_ASSERT(last_updated_subscr == NULL);
+
+ /* Inject DeleteSubscrData GSUP message (unknown IMSI) */
+ rc = rx_gsup_message(delete_data_req, sizeof(delete_data_req));
+ OSMO_ASSERT(rc == -GMM_CAUSE_IMSI_UNKNOWN);
+ OSMO_ASSERT(last_updated_subscr == NULL);
+
+ /* Inject LocCancelReq GSUP message (unknown IMSI) */
+ rc = rx_gsup_message(location_cancellation_req,
+ sizeof(location_cancellation_req));
+ OSMO_ASSERT(rc == -GMM_CAUSE_IMSI_UNKNOWN);
+ OSMO_ASSERT(last_updated_subscr == NULL);
+
update_subscriber_data_cb = __real_sgsn_update_subscriber_data;
}