lynxis lazus has uploaded this change for review. (
https://gerrit.osmocom.org/c/osmo-sgsn/+/39562?usp=email )
Change subject: Rework SGSN code to use new libvlr code
......................................................................
Rework SGSN code to use new libvlr code
The libvlr code will take most of the logic of the Routing Area handling.
By using the new libvlr code, the ACL and usage of the SGSN without the
HLR has been removed.
Change-Id: I9c5b4ec1b337c35e85c2d1a3d09b318380ae6ef8
---
M include/osmocom/sgsn/debug.h
M include/osmocom/sgsn/gprs_gmm.h
M include/osmocom/sgsn/gprs_gmm_attach.h
M include/osmocom/sgsn/gprs_gmm_fsm.h
A include/osmocom/sgsn/gprs_rau_fsm.h
M include/osmocom/sgsn/gprs_subscriber.h
M include/osmocom/sgsn/mmctx.h
M include/osmocom/sgsn/sgsn.h
M src/sgsn/Makefile.am
M src/sgsn/gprs_gmm.c
M src/sgsn/gprs_gmm_attach.c
M src/sgsn/gprs_gmm_fsm.c
M src/sgsn/gprs_ranap.c
A src/sgsn/gprs_rau_fsm.c
M src/sgsn/gprs_subscriber.c
M src/sgsn/mmctx.c
M src/sgsn/sgsn.c
M src/sgsn/sgsn_auth.c
M src/sgsn/sgsn_libgtp.c
M src/sgsn/sgsn_main.c
M src/sgsn/sgsn_vty.c
M tests/Makefile.am
M tests/gprs_routing_area/Makefile.am
M tests/sgsn/sgsn_test.c
M tests/testsuite.at
M tests/vty_test_runner.py
26 files changed, 1,305 insertions(+), 2,648 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-sgsn refs/changes/62/39562/1
diff --git a/include/osmocom/sgsn/debug.h b/include/osmocom/sgsn/debug.h
index 04ba3c0..3e43b2f 100644
--- a/include/osmocom/sgsn/debug.h
+++ b/include/osmocom/sgsn/debug.h
@@ -28,6 +28,8 @@
DOBJ,
DRIM,
DRA, /* Routing Area handling */
+ DVLR,
+ DSGS, /* only as placeholder, SGS isn't used by the SGSN */
Debug_LastEntry,
};
diff --git a/include/osmocom/sgsn/gprs_gmm.h b/include/osmocom/sgsn/gprs_gmm.h
index 900ad6a..6a2f023 100644
--- a/include/osmocom/sgsn/gprs_gmm.h
+++ b/include/osmocom/sgsn/gprs_gmm.h
@@ -7,6 +7,7 @@
#include <osmocom/gsm/gsm48.h>
#include <osmocom/crypt/auth.h>
+struct sgsn_instance;
struct sgsn_mm_ctx;
struct gprs_llc_llme;
struct osmo_routing_area_id;
@@ -14,6 +15,11 @@
int gsm48_tx_gmm_auth_ciph_req(struct sgsn_mm_ctx *mm,
const struct osmo_auth_vector *vec,
uint8_t key_seq, bool force_standby);
+int gsm48_tx_gmm_auth_ciph_rej(struct sgsn_mm_ctx *mm);
+
+int gsm48_tx_gmm_ra_upd_ack(struct sgsn_mm_ctx *mm);
+int gsm48_tx_gmm_ra_upd_rej_oldmsg(struct msgb *old_msg, uint8_t reject_cause);
+int gsm48_tx_gmm_ra_upd_rej(struct sgsn_mm_ctx *mm, uint8_t cause);
int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme,
bool drop_cipherable);
@@ -27,7 +33,8 @@
void gsm0408_gprs_access_granted(struct sgsn_mm_ctx *mmctx);
void gsm0408_gprs_access_denied(struct sgsn_mm_ctx *mmctx, int gmm_cause);
void gsm0408_gprs_access_cancelled(struct sgsn_mm_ctx *mmctx, int gmm_cause);
-void gsm0408_gprs_authenticate(struct sgsn_mm_ctx *mmctx);
+
+void gprs_gmm_service_accepted(struct sgsn_mm_ctx *ctx);
int gprs_gmm_rx_suspend(struct osmo_routing_area_id *raid, uint32_t tlli);
int gprs_gmm_rx_resume(struct osmo_routing_area_id *raid, uint32_t tlli,
@@ -44,6 +51,8 @@
int gsm48_tx_gmm_att_rej(struct sgsn_mm_ctx *mm,
uint8_t gmm_cause);
int gsm48_tx_gmm_att_ack(struct sgsn_mm_ctx *mm);
+int gsm48_tx_gmm_detach_req(struct sgsn_mm_ctx *mmctx, uint8_t detach_type, uint8_t
cause);
+int gsm48_tx_gmm_det_ack(struct sgsn_mm_ctx *mm, uint8_t force_stby);
int gprs_gmm_msg_cmp(struct msgb *a, struct msgb *b);
@@ -54,4 +63,6 @@
void msgid2mmctx(struct sgsn_mm_ctx *mm, const struct msgb *msg);
void mmctx2msgid(struct msgb *msg, const struct sgsn_mm_ctx *mm);
+
+int gmm_vlr_init(struct sgsn_instance *sgi);
#endif /* _GPRS_GMM_H */
diff --git a/include/osmocom/sgsn/gprs_gmm_attach.h
b/include/osmocom/sgsn/gprs_gmm_attach.h
index 0aa2123..e69de29 100644
--- a/include/osmocom/sgsn/gprs_gmm_attach.h
+++ b/include/osmocom/sgsn/gprs_gmm_attach.h
@@ -1,39 +0,0 @@
-#ifndef GPRS_GMM_ATTACH_H
-#define GPRS_GMM_ATTACH_H
-
-#include <osmocom/core/fsm.h>
-
-struct sgsn_mm_ctx;
-
-enum gmm_attach_req_fsm_states {
- ST_INIT,
- ST_IDENTIY,
- ST_RETRIEVE_AUTH,
- ST_AUTH,
- ST_ASK_VLR,
- ST_IU_SECURITY_CMD,
- ST_ACCEPT,
- ST_REJECT
-};
-
-enum gmm_attach_req_fsm_events {
- E_ATTACH_REQ_RECV,
- E_IDEN_RESP_RECV,
- E_AUTH_RESP_RECV_SUCCESS,
- E_AUTH_RESP_RECV_RESYNC,
- E_IU_SECURITY_CMD_COMPLETE,
- E_ATTACH_ACCEPTED,
- E_ATTACH_ACCEPT_SENT,
- E_ATTACH_COMPLETE_RECV,
- E_REJECT,
- E_VLR_ANSWERED,
-};
-
-#define GMM_DISCARD_MS_WITHOUT_REJECT -1
-
-extern const struct value_string gmm_attach_req_fsm_event_names[];
-extern struct osmo_fsm gmm_attach_req_fsm;
-
-void gmm_att_req_free(struct sgsn_mm_ctx *mm);
-
-#endif // GPRS_GMM_ATTACH_H
diff --git a/include/osmocom/sgsn/gprs_gmm_fsm.h b/include/osmocom/sgsn/gprs_gmm_fsm.h
index 2f0e81a..e2e525d 100644
--- a/include/osmocom/sgsn/gprs_gmm_fsm.h
+++ b/include/osmocom/sgsn/gprs_gmm_fsm.h
@@ -17,17 +17,22 @@
enum gmm_fsm_events {
E_GMM_COMMON_PROC_INIT_REQ,
- /* E_GMM_COMMON_PROC_FAILED, NOT USED */
+ E_GMM_COMMON_PROC_FAILED,
/* E_GMM_LOWER_LAYER_FAILED, NOT USED */
E_GMM_COMMON_PROC_SUCCESS,
E_GMM_ATTACH_SUCCESS,
- /* E_GMM_NET_INIT_DETACH_REQ, NOT USED */
- /* E_GMM_MS_INIT_DETACH_REQ, NOT USED */
- /* E_GMM_DETACH_ACCEPTED, */
+ E_GMM_ATTACH_FAILED, /* Osmocom specific */
+ E_GMM_RAU_SUCCESS,
+ E_GMM_RAU_FAILED,
+ E_GMM_NET_INIT_DETACH_REQ,
+ E_GMM_MS_INIT_DETACH_REQ,
+ E_GMM_DETACH_ACCEPTED,
E_GMM_SUSPEND,
E_GMM_RESUME,
E_GMM_CLEANUP,
E_GMM_RAT_CHANGE,
+ E_GMM_SERVICE_ACCEPT, /* When a Service Request got accepted, Osmocom specific */
+ E_GMM_SERVICE_REJECT, /* When a Service Request got rejected, Osmocom specific */
};
struct gmm_rat_change_data {
diff --git a/include/osmocom/sgsn/gprs_rau_fsm.h b/include/osmocom/sgsn/gprs_rau_fsm.h
new file mode 100644
index 0000000..8cf47f4
--- /dev/null
+++ b/include/osmocom/sgsn/gprs_rau_fsm.h
@@ -0,0 +1,51 @@
+/* Routing Area Update FSM for MMCtx to synchrozie for foreign RAU to local RAU
transistions */
+
+/* (C) 2024 by sysmocom s.f.m.c. GmbH <info(a)sysmocom.de>
+ *
+ * Author: Alexander Couzens <lynxis(a)fe80.eu>
+ * 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/>.
+ *
+ */
+
+#include <osmocom/core/utils.h>
+
+struct sgsn_mm_ctx;
+
+enum gmm_rau_state {
+ GMM_RAU_S_INIT,
+ GMM_RAU_S_WAIT_VLR_ANSWER,
+ GMM_RAU_S_WAIT_UE_RAU_COMPLETE,
+};
+
+enum gmm_rau_events {
+ GMM_RAU_E_UE_RAU_REQUEST,
+ GMM_RAU_E_UE_RAU_COMPLETE,
+ GMM_RAU_E_VLR_RAU_ACCEPT, /* Request to transmit Att/RAU Accept */
+ GMM_RAU_E_VLR_RAU_REJECT, /* Request to transmit Att/RAU Reject */
+ GMM_RAU_E_VLR_TERM_SUCCESS, /* VLR Lu FSM terminates. Inform GMM about Att/RAU Success
(including Att/RAU complete) */
+ GMM_RAU_E_VLR_TERM_FAIL, /* VLR Lu FSM terminates. Inform GMM about Att/RAU fail */
+};
+
+/* To be used as data when terminating the fsm */
+extern char *fsm_term_rau_att_req; /*! while RAU, receive a Attach Req */
+extern char *fsm_term_att_req_chg; /*! Second Attach Req with changed context */
+extern char *fsm_term_att_rej; /*! By SGSN decision, tx Reject */
+extern char *fsm_term_rau_req_chg; /*! Second Rau Req with changed context */
+extern char *fsm_term_rau_rej; /*! By SGSN decision, tx Reject */
+
+extern const struct value_string gmm_rau_event_names[];
+
+void gmm_rau_fsm_req(struct sgsn_mm_ctx *mmctx);
diff --git a/include/osmocom/sgsn/gprs_subscriber.h
b/include/osmocom/sgsn/gprs_subscriber.h
index 0d4a594..e7f63ab 100644
--- a/include/osmocom/sgsn/gprs_subscriber.h
+++ b/include/osmocom/sgsn/gprs_subscriber.h
@@ -12,6 +12,7 @@
struct sgsn_instance;
struct sgsn_mm_ctx;
+struct osmo_gsup_message;
extern struct llist_head * const gprs_subscribers;
@@ -71,6 +72,7 @@
struct gprs_subscr {
struct llist_head entry;
int use_count;
+ struct vlr_subscr *vlr_subscr;
char imsi[GSM23003_IMSI_MAX_DIGITS+1];
uint32_t tmsi;
@@ -102,7 +104,7 @@
void gprs_subscr_cancel(struct gprs_subscr *subscr);
void gprs_subscr_update(struct gprs_subscr *subscr);
void gprs_subscr_update_auth_info(struct gprs_subscr *subscr);
-int gprs_subscr_rx_gsup_message(struct msgb *msg);
+int gprs_subscr_rx_gsup_message(const struct osmo_gsup_message *gsup_msg);
#define LOGGSUBSCRP(level, subscr, fmt, args...) \
LOGP(DGPRS, level, "SUBSCR(%s) " fmt, \
diff --git a/include/osmocom/sgsn/mmctx.h b/include/osmocom/sgsn/mmctx.h
index 9fa06dc..1f1559e 100644
--- a/include/osmocom/sgsn/mmctx.h
+++ b/include/osmocom/sgsn/mmctx.h
@@ -16,6 +16,7 @@
#include <osmocom/sgsn/apn.h>
#include <osmocom/sgsn/auth.h>
#include <osmocom/sgsn/gprs_subscriber.h>
+#include <osmocom/vlr/vlr.h>
#define GSM_EXTENSION_LENGTH 15
@@ -99,9 +100,14 @@
char imsi[GSM23003_IMSI_MAX_DIGITS+1];
struct osmo_fsm_inst *gmm_fsm;
+ struct {
+ /* When a Common Procedure Succeeds, to which state do we change? */
+ bool common_proc_to_registered;
+ } gmm_priv;
+
uint32_t p_tmsi;
uint32_t p_tmsi_old; /* old P-TMSI before new is confirmed */
- uint32_t p_tmsi_sig;
+ char p_tmsi_sig[3];
char imei[GSM23003_IMEISV_NUM_DIGITS+1];
/* Opt: Software Version Numbber / TS 23.195 */
char msisdn[GSM_EXTENSION_LENGTH];
@@ -142,10 +148,25 @@
/* when a second attach req arrives while in this procedure,
* the fsm needs to compare it against old to decide what to do */
- struct msgb *attach_req;
uint32_t id_type;
unsigned int auth_reattempt; /* tracking UMTS resync auth attempts */
} gmm_att_req;
+
+ struct {
+ /* when a second attach req arrives while in this procedure,
+ * the fsm needs to compare it against old to decide what to do */
+ struct msgb *req;
+ char p_tmsi_sig[3];
+ bool p_tmsi_sig_valid;
+ struct osmo_routing_area_id old_rai;
+ struct osmo_routing_area_id new_rai;
+ struct osmo_fsm_inst *rau_fsm;
+ enum vlr_lu_type rau_type;
+ uint8_t cksq;
+ uint16_t pdp_status;
+ bool pdp_status_valid;
+ bool foreign;
+ } attach_rau;
/* VLR number */
uint32_t new_sgsn_addr;
/* Authentication Triplet */
@@ -212,6 +233,9 @@
struct sgsn_ggsn_lookup *ggsn_lookup;
struct gprs_subscr *subscr;
+ struct vlr_subscr *vsub;
+ /* to know if subscriber is doing an attach or location update */
+ bool attached;
};
static inline bool sgsn_mm_ctx_is_authenticated(struct sgsn_mm_ctx *ctx)
@@ -282,6 +306,9 @@
struct sgsn_pdp_ctx *sgsn_pdp_ctx_by_tid(const struct sgsn_mm_ctx *mm,
uint8_t tid);
+/* lookup vsub by imsi or ptmsi */
+int sgsn_mm_ctx_bind_vsub(struct sgsn_mm_ctx *mm, const char *imsi, uint32_t ptmsi);
+
bool sgsn_mm_ctx_is_r99(const struct sgsn_mm_ctx *mm);
uint32_t sgsn_alloc_ptmsi(void);
diff --git a/include/osmocom/sgsn/sgsn.h b/include/osmocom/sgsn/sgsn.h
index 9190a61..6682733 100644
--- a/include/osmocom/sgsn/sgsn.h
+++ b/include/osmocom/sgsn/sgsn.h
@@ -132,6 +132,9 @@
char *sgsn_ipa_name;
};
+struct gsup_client_mux;
+struct vlr_instance;
+
struct sgsn_instance {
char *config_file;
struct sgsn_config cfg;
@@ -143,6 +146,8 @@
struct gsn_t *gsn;
/* Subscriber */
struct osmo_gsup_client *gsup_client;
+ struct gsup_client_mux *gcm;
+ struct vlr_instance *vlr;
/* LLME inactivity timer */
struct osmo_timer_list llme_timer;
diff --git a/src/sgsn/Makefile.am b/src/sgsn/Makefile.am
index a2c6901..708e914 100644
--- a/src/sgsn/Makefile.am
+++ b/src/sgsn/Makefile.am
@@ -46,6 +46,7 @@
gprs_gmm.c \
gprs_gmm_fsm.c \
gprs_gmm_util.c \
+ gprs_rau_fsm.c \
gprs_mm_state_gb_fsm.c \
gprs_ns.c \
gprs_routing_area.c \
@@ -75,6 +76,7 @@
gprs_llc_xid.c \
v42bis.c \
$(NULL)
+
osmo_sgsn_LDADD = \
$(top_builddir)/src/gprs/gprs_llc_parse.o \
$(top_builddir)/src/gprs/crc24.o \
diff --git a/src/sgsn/gprs_gmm.c b/src/sgsn/gprs_gmm.c
index 1c457a2..83497d2 100644
--- a/src/sgsn/gprs_gmm.c
+++ b/src/sgsn/gprs_gmm.c
@@ -33,6 +33,7 @@
#include "config.h"
#include <osmocom/core/msgb.h>
+#include <osmocom/core/utils.h>
#include <osmocom/gsm/tlv.h>
#include <osmocom/gsm/gsm_utils.h>
#include <osmocom/core/signal.h>
@@ -60,12 +61,17 @@
#include <osmocom/sgsn/gprs_mm_state_iu_fsm.h>
#include <osmocom/sgsn/gprs_gmm_fsm.h>
#include <osmocom/sgsn/signal.h>
+#include <osmocom/sgsn/gprs_routing_area.h>
#include <osmocom/sgsn/gprs_sndcp.h>
#include <osmocom/sgsn/gprs_ranap.h>
#include <osmocom/sgsn/gprs_sm.h>
#include <osmocom/sgsn/gtp.h>
#include <osmocom/sgsn/pdpctx.h>
#include <osmocom/sgsn/gprs_gmm_util.h>
+#include <osmocom/sgsn/gprs_rau_fsm.h>
+
+#include <osmocom/gsupclient/gsup_client_mux.h>
+#include <osmocom/vlr/vlr.h>
#define PTMSI_ALLOC
@@ -196,7 +202,6 @@
sgsn_mm_ctx_cleanup_free(ctx);
}
-
/* 3GPP TS 24.008 § 10.5.7.1 Process PDP context status value, bit 0 corresponds to nsapi
0 */
static void process_ms_ctx_status(struct sgsn_mm_ctx *mmctx,
uint16_t pdp_status)
@@ -251,6 +256,25 @@
return (pdp_status >> 5) != 0;
}
+/* IU only: When a MO Service Request has been accepted, handle
+ * all the required state changes */
+void gprs_gmm_service_accepted(struct sgsn_mm_ctx *ctx)
+{
+#ifdef BUILD_IU
+ ctx->pending_req = 0;
+ if (ctx->ran_type != MM_CTX_T_UTRAN_Iu) {
+ LOGMMCTXP(LOGL_ERROR, ctx, "GMM handling Service Accepted, but MM ran is not
Iu");
+ return;
+ }
+
+ osmo_fsm_inst_dispatch(ctx->iu.mm_state_fsm, E_PMM_PS_CONN_ESTABLISH, NULL);
+
+ if (ctx->iu.service.type != GPRS_SERVICE_T_SIGNALLING)
+ activate_pdp_rabs(ctx);
+
+#endif /* BUILD_IU */
+}
+
/* Chapter 9.4.18 */
static int _tx_status(struct msgb *msg, uint8_t cause,
struct sgsn_mm_ctx *mmctx)
@@ -300,7 +324,7 @@
return gsm48_gmm_sendmsg(msg, 0, mmctx, true);
}
-static int gsm48_tx_gmm_detach_req(struct sgsn_mm_ctx *mmctx,
+int gsm48_tx_gmm_detach_req(struct sgsn_mm_ctx *mmctx,
uint8_t detach_type, uint8_t cause)
{
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 DET REQ");
@@ -443,7 +467,7 @@
return gsm48_gmm_sendmsg(msg, 0, mm, true);
}
-static int gsm48_tx_gmm_det_ack(struct sgsn_mm_ctx *mm, uint8_t force_stby)
+int gsm48_tx_gmm_det_ack(struct sgsn_mm_ctx *mm, uint8_t force_stby)
{
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 DET ACK");
@@ -559,7 +583,7 @@
}
/* 3GPP TS 24.008 § 9.4.11: Authentication and Ciphering Reject */
-static int gsm48_tx_gmm_auth_ciph_rej(struct sgsn_mm_ctx *mm)
+int gsm48_tx_gmm_auth_ciph_rej(struct sgsn_mm_ctx *mm)
{
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 AUTH CIPH REJ");
struct gsm48_hdr *gh;
@@ -695,6 +719,8 @@
}
memcpy(&ctx->imei, mi.imeisv, ARRAY_SIZE(ctx->imei));
+ if (ctx->vsub)
+ vlr_subscr_set_imeisv(ctx->vsub, mi.imeisv);
/* Start with the good old 4-byte SRES */
memcpy(res, TLVP_VAL(&tp, GSM48_IE_GMM_AUTH_SRES), 4);
@@ -713,6 +739,7 @@
at = &ctx->auth_triplet;
+ /* FIXME: the VLR should check the auth and not here a second time! */
LOGMMCTXP(LOGL_DEBUG, ctx, "checking auth: received %s = %s\n",
res_name, osmo_hexdump(res, res_len));
ctx->sec_ctx = check_auth_resp(ctx, false, &at->vec, res, res_len);
@@ -726,9 +753,10 @@
ctx->iu.new_key = 1;
/* FIXME: enable LLC cipheirng */
+ /* FIXME: This should _not_ trigger a FSM success */
+ osmo_fsm_inst_dispatch(ctx->gmm_fsm, E_GMM_COMMON_PROC_SUCCESS, NULL);
- /* Check if we can let the mobile station enter */
- return osmo_fsm_inst_dispatch(ctx->gmm_att_req.fsm, E_AUTH_RESP_RECV_SUCCESS, NULL);
+ return vlr_subscr_rx_auth_resp(ctx->vsub, sgsn_mm_ctx_is_r99(ctx), ctx->ran_type
== MM_CTX_T_UTRAN_Iu, res, res_len);
}
/* 3GPP TS 24.008 § 9.4.10: Authentication and Ciphering Failure */
@@ -738,12 +766,15 @@
struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
struct tlv_parsed tp;
const uint8_t gmm_cause = gh->data[0];
- const uint8_t *auts;
- int rc;
+ const uint8_t *auts = NULL;
+ int rc = 0;
LOGMMCTXP(LOGL_INFO, ctx, "-> GMM AUTH AND CIPH FAILURE (cause = %s)\n",
get_value_string(gsm48_gmm_cause_names, gmm_cause));
+ if (!ctx->vsub)
+ return -EINVAL;
+
tlv_parse(&tp, &gsm48_gmm_ie_tlvdef, gh->data+1, msg->len - 1, 0, 0);
/* Only if GMM cause is present and the AUTS is provided, we can
@@ -768,70 +799,39 @@
/* make sure we'll retry authentication after the resync */
ctx->auth_state = SGSN_AUTH_UMTS_RESYNC;
-
- /* Send AUTS to HLR and wait for new Auth Info Result */
- rc = gprs_subscr_request_auth_info(ctx, auts,
- ctx->auth_triplet.vec.rand);
- if (!rc)
- return osmo_fsm_inst_dispatch(ctx->gmm_att_req.fsm, E_AUTH_RESP_RECV_RESYNC,
NULL);
- /* on error, fall through to send a reject */
- LOGMMCTXP(LOGL_ERROR, ctx,
- "Sending AUTS to HLR failed (rc = %d)\n", rc);
}
+ /* VLR doesn't accept Auth Ciph Fail */
+ vlr_subscr_rx_auth_fail(ctx->vsub, auts);
+
LOGMMCTXP(LOGL_NOTICE, ctx, "Authentication failed\n");
- rc = gsm48_tx_gmm_auth_ciph_rej(ctx);
- mm_ctx_cleanup_free(ctx, "GMM AUTH FAILURE");
return rc;
}
void extract_subscr_msisdn(struct sgsn_mm_ctx *ctx)
{
- struct gsm_mncc_number called;
- uint8_t msisdn[sizeof(ctx->subscr->sgsn_data->msisdn) + 1];
+ osmo_static_assert(GSM_EXTENSION_LENGTH == GSM23003_MSISDN_MAX_DIGITS, gmm_msisdn_vsub)
- /* Convert MSISDN from encoded to string.. */
- if (!ctx->subscr)
- return;
-
- if (ctx->subscr->sgsn_data->msisdn_len < 1)
- return;
-
- /* prepare the data for the decoder */
- memset(&called, 0, sizeof(called));
- msisdn[0] = ctx->subscr->sgsn_data->msisdn_len;
- memcpy(&msisdn[1], ctx->subscr->sgsn_data->msisdn,
- ctx->subscr->sgsn_data->msisdn_len);
-
- /* decode the string now */
- gsm48_decode_called(&called, msisdn);
-
- /* Prepend a '+' for international numbers */
- if (called.plan == 1 && called.type == 1) {
- ctx->msisdn[0] = '+';
- osmo_strlcpy(&ctx->msisdn[1], called.number,
- sizeof(ctx->msisdn));
- } else {
- osmo_strlcpy(ctx->msisdn, called.number, sizeof(ctx->msisdn));
- }
+ if (ctx->vsub)
+ memcpy(ctx->msisdn, ctx->vsub->msisdn, GSM_EXTENSION_LENGTH);
}
void extract_subscr_hlr(struct sgsn_mm_ctx *ctx)
{
struct gsm_mncc_number called;
- uint8_t hlr_number[sizeof(ctx->subscr->sgsn_data->hlr) + 1];
+ uint8_t hlr_number[sizeof(ctx->vsub->hlr.buf) + 1];
- if (!ctx->subscr)
+ if (!ctx->vsub)
return;
- if (ctx->subscr->sgsn_data->hlr_len < 1)
+ if (ctx->vsub->hlr.len == 0 || ctx->vsub->hlr.len >
sizeof(ctx->vsub->hlr.buf))
return;
/* prepare the data for the decoder */
memset(&called, 0, sizeof(called));
- hlr_number[0] = ctx->subscr->sgsn_data->hlr_len;
- memcpy(&hlr_number[1], ctx->subscr->sgsn_data->hlr,
- ctx->subscr->sgsn_data->hlr_len);
+ hlr_number[0] = ctx->vsub->hlr.len & 0xff;
+ memcpy(&hlr_number[1], ctx->vsub->hlr.buf,
+ ctx->vsub->hlr.len);
/* decode the string now */
gsm48_decode_called(&called, hlr_number);
@@ -898,167 +898,15 @@
gmm_copy_id(msg, old_msg);
return _tx_gmm_service_rej(msg, gmm_cause, NULL);
}
-#if 0
--- currently unused --
+
static int gsm48_tx_gmm_service_rej(struct sgsn_mm_ctx *mm,
uint8_t gmm_cause)
{
+#ifdef BUILD_IU
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 SERVICE REJ");
mmctx2msgid(msg, mm);
return _tx_gmm_service_rej(msg, gmm_cause, mm);
-}
-#endif
-
-static int gsm48_tx_gmm_ra_upd_ack(struct sgsn_mm_ctx *mm);
-
-/* Check if we can already authorize a subscriber */
-int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx)
-{
-#ifdef BUILD_IU
- int rc;
-#endif
-#ifndef PTMSI_ALLOC
- struct sgsn_signal_data sig_data;
-#endif
-
- /* Request IMSI and IMEI from the MS if they are unknown */
- if (!strlen(ctx->imei)) {
- ctx->t3370_id_type = GSM_MI_TYPE_IMEI;
- mmctx_timer_start(ctx, 3370);
- return gsm48_tx_gmm_id_req(ctx, GSM_MI_TYPE_IMEI);
- }
- if (!strlen(ctx->imsi)) {
- ctx->t3370_id_type = GSM_MI_TYPE_IMSI;
- mmctx_timer_start(ctx, 3370);
- return gsm48_tx_gmm_id_req(ctx, GSM_MI_TYPE_IMSI);
- }
-
- /* All information required for authentication is available */
- ctx->t3370_id_type = GSM_MI_TYPE_NONE;
-
- if (ctx->auth_state == SGSN_AUTH_UNKNOWN) {
- /* Request authorization, this leads to a call to
- * sgsn_auth_update which in turn calls
- * gsm0408_gprs_access_granted or gsm0408_gprs_access_denied */
-
- sgsn_auth_request(ctx);
- /* Note that gsm48_gmm_authorize can be called recursively via
- * sgsn_auth_request iff ctx->auth_info changes to AUTH_ACCEPTED
- */
- return 0;
- }
-
- if (ctx->auth_state == SGSN_AUTH_AUTHENTICATE
- && !sgsn_mm_ctx_is_authenticated(ctx)) {
- struct gsm_auth_tuple *at = &ctx->auth_triplet;
-
- mmctx_timer_start(ctx, 3360);
- return gsm48_tx_gmm_auth_ciph_req(ctx, &at->vec, at->key_seq,
- false);
- }
-
- if (ctx->auth_state == SGSN_AUTH_AUTHENTICATE &&
sgsn_mm_ctx_is_authenticated(ctx) &&
- ctx->auth_triplet.key_seq != GSM_KEY_SEQ_INVAL) {
- /* Check again for authorization */
- sgsn_auth_request(ctx);
- return 0;
- }
-
- if (ctx->auth_state != SGSN_AUTH_ACCEPTED) {
- LOGMMCTXP(LOGL_NOTICE, ctx,
- "authorization is denied, aborting procedure\n");
- return -EACCES;
- }
-
- /* The MS is authorized */
-#ifdef BUILD_IU
- if (ctx->ran_type == MM_CTX_T_UTRAN_Iu &&
!ctx->iu.ue_ctx->integrity_active) {
- /* Is any encryption above UEA0 enabled? */
- bool send_ck = sgsn->cfg.uea_encryption_mask > (1 << OSMO_UTRAN_UEA0);
- LOGMMCTXP(LOGL_DEBUG, ctx, "Iu Security Mode Command: %s encryption key (UEA
encryption mask = 0x%x)\n",
- send_ck ? "sending" : "not sending",
sgsn->cfg.uea_encryption_mask);
- /* FIXME: we should send the set of allowed UEA, as in ranap_new_msg_sec_mod_cmd2().
However, this
- * is not possible in the iu_client API. See OS#5487. */
- rc = ranap_iu_tx_sec_mode_cmd(ctx->iu.ue_ctx, &ctx->auth_triplet.vec,
send_ck, ctx->iu.new_key);
- ctx->iu.new_key = 0;
- return rc;
- }
-#endif
-
- switch (ctx->pending_req) {
- case 0:
- LOGMMCTXP(LOGL_INFO, ctx,
- "no pending request, authorization completed\n");
- break;
- case GSM48_MT_GMM_ATTACH_REQ:
- ctx->pending_req = 0;
-
- extract_subscr_msisdn(ctx);
- extract_subscr_hlr(ctx);
-#ifdef PTMSI_ALLOC
- /* Start T3350 and re-transmit up to 5 times until ATTACH COMPLETE */
- mmctx_timer_start(ctx, 3350);
- ctx->t3350_mode = GMM_T3350_MODE_ATT;
-#else
- memset(&sig_data, 0, sizeof(sig_data));
- sig_data.mm = ctx;
- osmo_signal_dispatch(SS_SGSN, S_SGSN_ATTACH, &sig_data);
- osmo_fsm_inst_dispatch(ctx->gmm_fsm, E_GMM_ATTACH_SUCCESS, NULL);
-#endif
-
- return gsm48_tx_gmm_att_ack(ctx);
-#ifdef BUILD_IU
- case GSM48_MT_GMM_SERVICE_REQ:
- ctx->pending_req = 0;
- osmo_fsm_inst_dispatch(ctx->iu.mm_state_fsm, E_PMM_PS_CONN_ESTABLISH, NULL);
- rc = gsm48_tx_gmm_service_ack(ctx);
-
- if (ctx->iu.service.type != GPRS_SERVICE_T_SIGNALLING)
- activate_pdp_rabs(ctx);
-
- return rc;
-#endif
- case GSM48_MT_GMM_RA_UPD_REQ:
- ctx->pending_req = 0;
- /* Send RA UPDATE ACCEPT */
- return gsm48_tx_gmm_ra_upd_ack(ctx);
-
- default:
- LOGMMCTXP(LOGL_ERROR, ctx,
- "only Attach Request is supported yet, "
- "got request type %u\n", ctx->pending_req);
- break;
- }
-
- return 0;
-}
-
-void gsm0408_gprs_authenticate(struct sgsn_mm_ctx *ctx)
-{
- ctx->sec_ctx = OSMO_AUTH_TYPE_NONE;
-
- if (ctx->gmm_att_req.fsm->state != ST_INIT)
- osmo_fsm_inst_dispatch(ctx->gmm_att_req.fsm, E_VLR_ANSWERED, (void *) 0);
- else
- gsm48_gmm_authorize(ctx);
-}
-
-void gsm0408_gprs_access_granted(struct sgsn_mm_ctx *ctx)
-{
- switch (ctx->gmm_fsm->state) {
- case ST_GMM_COMMON_PROC_INIT:
- LOGMMCTXP(LOGL_NOTICE, ctx,
- "Authorized, continuing procedure, IMSI=%s\n",
- ctx->imsi);
- /* Continue with the authorization */
- if (ctx->gmm_att_req.fsm->state != ST_INIT)
- osmo_fsm_inst_dispatch(ctx->gmm_att_req.fsm, E_VLR_ANSWERED, (void *) 0);
- break;
- default:
- LOGMMCTXP(LOGL_INFO, ctx,
- "Authorized, ignored, IMSI=%s\n",
- ctx->imsi);
- }
+#endif /* BUILD_IU */
}
void gsm0408_gprs_access_denied(struct sgsn_mm_ctx *ctx, int gmm_cause)
@@ -1073,8 +921,6 @@
"with cause '%s' (%d)\n",
get_value_string(gsm48_gmm_cause_names, gmm_cause),
gmm_cause);
- if (ctx->gmm_att_req.fsm->state != ST_INIT)
- osmo_fsm_inst_dispatch(ctx->gmm_att_req.fsm, E_REJECT, (void *) (long) gmm_cause);
break;
case ST_GMM_REGISTERED_NORMAL:
case ST_GMM_REGISTERED_SUSPENDED:
@@ -1116,7 +962,6 @@
static int gsm48_rx_gmm_id_resp(struct sgsn_mm_ctx *ctx, struct msgb *msg)
{
struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
- long mi_typel;
char mi_log_string[32];
struct osmo_mobile_identity mi;
@@ -1133,17 +978,6 @@
LOGMMCTXP(LOGL_DEBUG, ctx, "-> GMM IDENTITY RESPONSE: MI=%s\n",
mi_log_string);
- if (ctx->t3370_id_type == GSM_MI_TYPE_NONE) {
- LOGMMCTXP(LOGL_NOTICE, ctx,
- "Got unexpected IDENTITY RESPONSE: MI=%s, "
- "ignoring message\n",
- mi_log_string);
- return -EINVAL;
- }
-
- if (mi.type == ctx->t3370_id_type)
- mmctx_timer_stop(ctx, 3370);
-
switch (mi.type) {
case GSM_MI_TYPE_IMSI:
/* we already have a mm context with current TLLI, but no
@@ -1173,9 +1007,10 @@
break;
}
- /* Check if we can let the mobile station enter */
- mi_typel = mi.type;
- return osmo_fsm_inst_dispatch(ctx->gmm_att_req.fsm, E_IDEN_RESP_RECV, (void
*)mi_typel);
+ if (ctx->vsub)
+ return vlr_subscr_rx_id_resp(ctx->vsub, &mi);
+
+ return 0;
}
/* Allocate a new P-TMSI and change context state */
@@ -1244,20 +1079,22 @@
static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
struct gprs_llc_llme *llme)
{
- struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
- uint8_t *cur = gh->data, *msnc, *mi_data, *ms_ra_acc_cap;
- uint8_t msnc_len, att_type, mi_len, ms_ra_acc_cap_len;
- uint16_t drx_par;
+ struct gprs_gmm_att_req req = {};
char mi_log_string[32];
struct osmo_routing_area_id ra_id;
uint16_t cid = 0;
enum gsm48_gmm_cause reject_cause;
- struct osmo_mobile_identity mi;
int rc;
LOGMMCTXP(LOGL_INFO, ctx, "-> GMM ATTACH REQUEST ");
rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_ATTACH_REQUEST));
+ rc = gprs_gmm_parse_att_req(msg, &req);
+ if (rc) {
+ LOGP(DMM, LOGL_ERROR, "Invalid Attach Request message received.\n");
+ goto err_inval;
+ }
+
/* As per TS 04.08 Chapter 4.7.1.4, the attach request arrives either
* with a foreign TLLI (P-TMSI that was allocated to the MS before),
* or with random TLLI. */
@@ -1274,58 +1111,23 @@
#endif
}
- /* MS network capability 10.5.5.12 */
- msnc_len = *cur++;
- msnc = cur;
- if (msnc_len > sizeof(ctx->ms_network_capa.buf))
- goto err_inval;
- cur += msnc_len;
-
/* TODO: In iu mode - handle follow-on request.
* The follow-on request can be signaled in an Attach Request on IuPS.
* This means the MS/UE asks to keep the PS connection open for further requests
* after the Attach Request succeed.
* The SGSN can decide if it close the connection or not. Both are spec conform. */
- /* aTTACH Type 10.5.5.2 */
- att_type = *cur++ & 0x07;
-
- /* DRX parameter 10.5.5.6 */
- drx_par = *cur++ << 8;
- drx_par |= *cur++;
-
- /* Mobile Identity (P-TMSI or IMSI) 10.5.1.4 */
- mi_len = *cur++;
- mi_data = cur;
- cur += mi_len;
-
- rc = osmo_mobile_identity_decode(&mi, mi_data, mi_len, false);
- if (rc)
- goto err_inval;
- osmo_mobile_identity_to_str_buf(mi_log_string, sizeof(mi_log_string), &mi);
-
- DEBUGPC(DMM, "MI(%s) type=\"%s\" ", mi_log_string,
- get_value_string(gprs_att_t_strs, att_type));
-
- /* Old routing area identification 10.5.5.15. Skip it */
- cur += 6;
-
- /* MS Radio Access Capability 10.5.5.12a */
- ms_ra_acc_cap_len = *cur++;
- ms_ra_acc_cap = cur;
- if (ms_ra_acc_cap_len > sizeof(ctx->ms_radio_access_capa.buf))
- goto err_inval;
- cur += ms_ra_acc_cap_len;
-
- LOGPC(DMM, LOGL_INFO, "\n");
+ osmo_mobile_identity_to_str_buf(mi_log_string, sizeof(mi_log_string), &req.mi);
+ LOGPC(DMM, LOGL_INFO, "MI(%s) type=\"%s\" ", mi_log_string,
+ get_value_string(gprs_att_t_strs, req.attach_type));
/* Optional: Old P-TMSI Signature, Requested READY timer, TMSI Status */
- switch (mi.type) {
+ switch (req.mi.type) {
case GSM_MI_TYPE_IMSI:
/* Try to find MM context based on IMSI */
if (!ctx)
- ctx = sgsn_mm_ctx_by_imsi(mi.imsi);
+ ctx = sgsn_mm_ctx_by_imsi(req.mi.imsi);
if (!ctx) {
if (MSG_IU_UE_CTX(msg))
ctx = sgsn_mm_ctx_alloc_iu(MSG_IU_UE_CTX(msg));
@@ -1335,13 +1137,13 @@
reject_cause = GMM_CAUSE_NET_FAIL;
goto rejected;
}
- OSMO_STRLCPY_ARRAY(ctx->imsi, mi.imsi);
+ OSMO_STRLCPY_ARRAY(ctx->imsi, req.mi.imsi);
}
break;
case GSM_MI_TYPE_TMSI:
/* Try to find MM context based on P-TMSI */
if (!ctx)
- ctx = sgsn_mm_ctx_by_ptmsi(mi.tmsi);
+ ctx = sgsn_mm_ctx_by_ptmsi(req.mi.tmsi);
if (!ctx) {
/* Allocate a context as most of our code expects one.
* Context will not have an IMSI ultil ID RESP is received */
@@ -1353,7 +1155,7 @@
reject_cause = GMM_CAUSE_NET_FAIL;
goto rejected;
}
- ctx->p_tmsi = mi.tmsi;
+ ctx->p_tmsi = req.mi.tmsi;
}
break;
default:
@@ -1363,6 +1165,16 @@
goto rejected;
}
+ /* Check if this Attach Request is a retransmission */
+ if (ctx->attach_rau.req) {
+ if (!gprs_gmm_msg_cmp(ctx->attach_rau.req, msg)) {
+ /* Retransmission of the old Attach Req */
+ /* TODO: retransmit ID Req/Resp from VLR. Currently this will run into a timeout to
retransmit */
+ osmo_fsm_inst_dispatch(ctx->attach_rau.rau_fsm, GMM_RAU_E_UE_RAU_REQUEST, (void *)
1);
+ return 0;
+ }
+ }
+
if (mmctx_did_rat_change(ctx, msg))
mmctx_handle_rat_change(ctx, msg, llme);
@@ -1377,14 +1189,15 @@
ctx->gb.cell_id = cid;
/* Update MM Context with other data */
- ctx->drx_parms = drx_par;
- ctx->ms_radio_access_capa.len = ms_ra_acc_cap_len;
- memcpy(ctx->ms_radio_access_capa.buf, ms_ra_acc_cap,
+ ctx->drx_parms = req.drx_parms;
+ ctx->ms_radio_access_capa.len = OSMO_MIN(req.ms_radio_cap_len,
sizeof(ctx->ms_radio_access_capa.buf));
+ memcpy(ctx->ms_radio_access_capa.buf, req.ms_radio_cap,
ctx->ms_radio_access_capa.len);
- ctx->ms_network_capa.len = msnc_len;
- memcpy(ctx->ms_network_capa.buf, msnc, msnc_len);
- ctx->ue_cipher_mask = gprs_ms_net_cap_gea_mask(ctx->ms_network_capa.buf,
msnc_len);
+ ctx->ms_network_capa.len = OSMO_MIN(req.ms_network_cap_len,
sizeof(ctx->ms_network_capa.buf));
+ memcpy(ctx->ms_network_capa.buf, req.ms_network_cap, ctx->ms_network_capa.len);
+
+ ctx->ue_cipher_mask = gprs_ms_net_cap_gea_mask(ctx->ms_network_capa.buf,
ctx->ms_network_capa.len);
if (!(ctx->ue_cipher_mask & sgsn->cfg.gea_encryption_mask)) {
reject_cause = GMM_CAUSE_PROTO_ERR_UNSPEC;
@@ -1404,24 +1217,29 @@
ctx->ciph_algo = gprs_ms_net_select_best_gea(ctx->ue_cipher_mask,
sgsn->cfg.gea_encryption_mask);
-#ifdef PTMSI_ALLOC
- /* Allocate a new P-TMSI (+ P-TMSI signature) and update TLLI */
- ptmsi_update(ctx);
-#endif
-
- if (ctx->ran_type == MM_CTX_T_GERAN_Gb) {
- /* Even if there is no P-TMSI allocated, the MS will
- * switch from foreign TLLI to local TLLI */
- ctx->gb.tlli_new = gprs_tmsi2tlli(ctx->p_tmsi, TLLI_LOCAL);
-
- /* Inform LLC layer about new TLLI but keep old active */
- if (sgsn_mm_ctx_is_authenticated(ctx))
- gprs_llme_copy_key(ctx, ctx->gb.llme);
-
- gprs_llgmm_assign(ctx->gb.llme, ctx->gb.tlli, ctx->gb.tlli_new);
+ if (req.mi.type == GSM_MI_TYPE_IMSI) {
+ sgsn_mm_ctx_bind_vsub(ctx, req.mi.imsi, 0);
+ } else if (req.mi.type == GSM_MI_TYPE_TMSI) {
+ sgsn_mm_ctx_bind_vsub(ctx, NULL, req.mi.tmsi);
+ } else {
+ goto err_inval;
}
- osmo_fsm_inst_dispatch(ctx->gmm_att_req.fsm, E_ATTACH_REQ_RECV, msg);
+ if (!ctx->vsub) {
+ reject_cause = GMM_CAUSE_NET_FAIL;
+ goto rejected;
+ }
+
+ if (ctx->attach_rau.rau_fsm)
+ osmo_fsm_inst_term(ctx->attach_rau.rau_fsm, OSMO_FSM_TERM_REQUEST,
fsm_term_att_req_chg);
+
+ ctx->attach_rau.cksq = req.cksq;
+ ctx->attach_rau.old_rai = req.old_rai;
+ ctx->attach_rau.rau_type = VLR_LU_TYPE_IMSI_ATTACH;
+ ctx->attach_rau.req = msgb_copy_c(ctx, msg, "GMM ATTACH REQ");
+
+ gmm_rau_fsm_req(ctx);
+
return 0;
err_inval:
@@ -1440,45 +1258,38 @@
gprs_llgmm_unassign(llme);
return rc;
-
}
/* 3GPP TS 24.008 § 9.4.3 Attach complete */
static int gsm48_rx_gmm_att_compl(struct sgsn_mm_ctx *mmctx)
{
- struct sgsn_signal_data sig_data;
+ int rc = 0;
/* only in case SGSN offered new P-TMSI */
LOGMMCTXP(LOGL_INFO, mmctx, "-> GMM ATTACH COMPLETE\n");
#ifdef BUILD_IU
+ /* TODO: check follow-on request */
if (mmctx->iu.ue_ctx) {
ranap_iu_tx_release(mmctx->iu.ue_ctx, NULL);
}
#endif
+ /* If the mmctx doesn't contain a VLR subscriber, ignore this message */
+ if (!mmctx->vsub)
+ return 0;
+
mmctx_timer_stop(mmctx, 3350);
mmctx->t3350_mode = GMM_T3350_MODE_NONE;
mmctx->p_tmsi_old = 0;
mmctx->pending_req = 0;
- osmo_fsm_inst_dispatch(mmctx->gmm_fsm, E_GMM_ATTACH_SUCCESS, NULL);
- switch(mmctx->ran_type) {
- case MM_CTX_T_UTRAN_Iu:
- osmo_fsm_inst_dispatch(mmctx->iu.mm_state_fsm, E_PMM_PS_ATTACH, NULL);
- break;
- case MM_CTX_T_GERAN_Gb:
- /* Unassign the old TLLI */
- mmctx->gb.tlli = mmctx->gb.tlli_new;
- gprs_llme_copy_key(mmctx, mmctx->gb.llme);
- gprs_llgmm_assign(mmctx->gb.llme, TLLI_UNASSIGNED,
- mmctx->gb.tlli_new);
- osmo_fsm_inst_dispatch(mmctx->gb.mm_state_fsm, E_MM_GPRS_ATTACH, NULL);
- break;
+
+ if (mmctx->attach_rau.rau_fsm) {
+ rc = osmo_fsm_inst_dispatch(mmctx->attach_rau.rau_fsm, GMM_RAU_E_UE_RAU_COMPLETE,
NULL);
}
- osmo_fsm_inst_dispatch(mmctx->gmm_att_req.fsm, E_ATTACH_COMPLETE_RECV, 0);
- memset(&sig_data, 0, sizeof(sig_data));
- sig_data.mm = mmctx;
- osmo_signal_dispatch(SS_SGSN, S_SGSN_ATTACH, &sig_data);
+ if (!mmctx->attach_rau.rau_fsm || rc != 0) {
+ /* FIXME: fail gracefully here or just ignore?! */
+ }
return 0;
}
@@ -1501,7 +1312,9 @@
static int gsm48_rx_gmm_det_req(struct sgsn_mm_ctx *ctx, struct msgb *msg)
{
struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
+ struct sgsn_signal_data sig_data;
uint8_t detach_type, power_off;
+ long data;
int rc = 0;
detach_type = gh->data[0] & 0x7;
@@ -1513,29 +1326,39 @@
msgb_tlli(msg), get_value_string(gprs_det_t_mo_strs, detach_type),
power_off ? "Power-off" : "");
+
/* Only send the Detach Accept (MO) if power off isn't indicated,
* see 04.08, 4.7.4.1.2/3 for details */
- if (!power_off) {
- /* force_stby = 0 */
- if (ctx)
- rc = gsm48_tx_gmm_det_ack(ctx, 0);
- else
+ if (!ctx) {
+ if (!power_off)
rc = gsm48_tx_gmm_det_ack_oldmsg(msg, 0);
+ return rc;
}
- if (ctx) {
- struct sgsn_signal_data sig_data;
- memset(&sig_data, 0, sizeof(sig_data));
- sig_data.mm = ctx;
- osmo_signal_dispatch(SS_SGSN, S_SGSN_DETACH, &sig_data);
- mm_ctx_cleanup_free(ctx, "GMM DETACH REQUEST");
- }
+ memset(&sig_data, 0, sizeof(sig_data));
+ sig_data.mm = ctx;
+ /* FIXME: in theory there shouldn't be a MMCTX without VLR sub */
+ if (ctx->vsub)
+ vlr_subscr_rx_imsi_detach(ctx->vsub);
+
+ data = power_off;
+ osmo_fsm_inst_dispatch(ctx->gmm_fsm, E_GMM_MS_INIT_DETACH_REQ, &data);
+ osmo_signal_dispatch(SS_SGSN, S_SGSN_DETACH, &sig_data);
+ mm_ctx_cleanup_free(ctx, "GMM DETACH REQUEST");
return rc;
}
+/* CHapter 9.4.6: MT Detach Ack */
+static int gsm48_rx_gmm_det_accept(struct sgsn_mm_ctx *ctx, struct msgb *msg)
+{
+ LOGMMCTXP(LOGL_INFO, ctx, "-> DETACH ACK\n");
+ osmo_fsm_inst_dispatch(ctx->gmm_fsm, E_GMM_DETACH_ACCEPTED, NULL);
+ return 0;
+}
+
/* Chapter 9.4.15: Routing area update accept */
-static int gsm48_tx_gmm_ra_upd_ack(struct sgsn_mm_ctx *mm)
+int gsm48_tx_gmm_ra_upd_ack(struct sgsn_mm_ctx *mm)
{
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 UPD ACK");
struct gsm48_hdr *gh;
@@ -1599,6 +1422,10 @@
/* GMM cause */
/* PDP Context Status */
uint16_t pdp_ctx_status = encode_ms_ctx_status(mm);
+ if (mm->attach_rau.pdp_status_valid && pdp_ctx_status !=
mm->attach_rau.pdp_status) {
+ process_ms_ctx_status(mm, mm->attach_rau.pdp_status);
+ pdp_ctx_status = encode_ms_ctx_status(mm);
+ }
msgb_tlv_put(msg, GSM48_IE_GMM_PDP_CTX_STATUS, 2, (uint8_t *) &pdp_ctx_status);
/* MS ID, ... */
@@ -1606,7 +1433,26 @@
}
/* Chapter 9.4.17: Routing area update reject */
-int gsm48_tx_gmm_ra_upd_rej(struct msgb *old_msg, uint8_t cause)
+int gsm48_tx_gmm_ra_upd_rej(struct sgsn_mm_ctx *mm, uint8_t cause)
+{
+ struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 RA UPD REJ");
+ struct gsm48_hdr *gh;
+
+ LOGP(DMM, LOGL_NOTICE, "<- ROUTING AREA UPDATE REJECT\n");
+ rate_ctr_inc(rate_ctr_group_get_ctr(sgsn->rate_ctrs, CTR_GPRS_ROUTING_AREA_REJECT));
+ mmctx2msgid(msg, mm);
+
+ gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 2);
+ gh->proto_discr = GSM48_PDISC_MM_GPRS;
+ gh->msg_type = GSM48_MT_GMM_RA_UPD_REJ;
+ gh->data[0] = cause;
+ gh->data[1] = 0; /* ? */
+
+ return gsm48_gmm_sendmsg(msg, 0, mm, false);
+}
+
+/* Chapter 9.4.17: Routing area update reject */
+int gsm48_tx_gmm_ra_upd_rej_oldmsg(struct msgb *old_msg, uint8_t cause)
{
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 RA UPD REJ");
struct gsm48_hdr *gh;
@@ -1635,7 +1481,13 @@
#endif
enum gsm48_gmm_cause reject_cause = GMM_CAUSE_PROTO_ERR_UNSPEC;
struct gprs_gmm_ra_upd_req req;
+ struct osmo_routing_area_id new_ra_id = {};
+ enum vlr_lu_type vlr_rau_type = VLR_LU_TYPE_REGULAR;
+ bool foreign_ra = false;
+ enum gsm48_ptsmi_type ptmsi_type = PTMSI_TYPE_NATIVE;
int rc;
+ uint32_t ptmsi = 0xffffffff;
+ uint32_t tlli = 0xffffffff;
rc = gprs_gmm_parse_ra_upd_req(msg, &req);
if (rc) {
@@ -1660,78 +1512,110 @@
reject_cause = GMM_CAUSE_PROTO_ERR_UNSPEC;
goto rejected;
case GPRS_UPD_T_RA:
+ vlr_rau_type = VLR_LU_TYPE_REGULAR;
+ break;
case GPRS_UPD_T_PERIODIC:
+ vlr_rau_type = VLR_LU_TYPE_PERIODIC;
break;
}
- if (!mmctx) {
- /* BSSGP doesn't give us an mmctx */
-
- /* TODO: Check if there is an MM CTX with old_ra_id and
- * the P-TMSI (if given, reguired for UMTS) or as last resort
- * if the TLLI matches foreign_tlli (P-TMSI). Note that this
- * is an optimization to avoid the RA reject (impl detached)
- * below, which will cause a new attach cycle. */
- /* Look-up the MM context based on old RA-ID and TLLI */
- if (!MSG_IU_UE_CTX(msg)) {
- /* Gb */
- mmctx = sgsn_mm_ctx_by_tlli_and_ptmsi(msgb_tlli(msg), &req.old_rai);
- } else if (TLVP_PRESENT(&req.tlv, GSM48_IE_GMM_ALLOC_PTMSI)) {
-#ifdef BUILD_IU
- /* In Iu mode search only for ptmsi */
- struct osmo_mobile_identity mi;
- if (osmo_mobile_identity_decode(&mi, TLVP_VAL(&req.tlv,
GSM48_IE_GMM_ALLOC_PTMSI),
- TLVP_LEN(&req.tlv, GSM48_IE_GMM_ALLOC_PTMSI), false)
- || mi.type != GSM_MI_TYPE_TMSI) {
- LOGIUP(MSG_IU_UE_CTX(msg), LOGL_ERROR, "Cannot decode P-TMSI\n");
- goto rejected;
- }
- mmctx = sgsn_mm_ctx_by_ptmsi(mi.tmsi);
-#else
- LOGIUP(MSG_IU_UE_CTX(msg), LOGL_ERROR,
- "Rejecting GMM RA Update Request: No Iu support\n");
- goto rejected;
-#endif
- }
- if (mmctx) {
- LOGMMCTXP(LOGL_INFO, mmctx,
- "Looked up by matching TLLI and P_TMSI. "
- "BSSGP TLLI: %08x, P-TMSI: %08x (%08x), "
- "TLLI: %08x (%08x), RA: %s\n",
- msgb_tlli(msg),
- mmctx->p_tmsi, mmctx->p_tmsi_old,
- mmctx->gb.tlli, mmctx->gb.tlli_new,
- osmo_rai_name2(&mmctx->ra));
- /* A RAT change will trigger the common procedure
- * below after handling the RAT change. Protect it
- * here from being called twice */
- if (!mmctx_did_rat_change(mmctx, msg))
- osmo_fsm_inst_dispatch(mmctx->gmm_fsm, E_GMM_COMMON_PROC_INIT_REQ, NULL);
-
- }
- } else if (osmo_rai_cmp(&mmctx->ra, &req.old_rai) ||
- mmctx->gmm_fsm->state == ST_GMM_DEREGISTERED)
- {
- /* We've received either a RAU for a MS which isn't registered
- * or a RAU with an unknown RA ID. As long the SGSN doesn't support
- * PS handover we treat this as invalid RAU */
- struct osmo_routing_area_id new_ra_id = {};
- char new_ra[32];
-
+ /* GERAN via Gb */
+ if (msgb_bcid(msg)) {
bssgp_parse_cell_id2(&new_ra_id, NULL, msgb_bcid(msg), 8);
- osmo_rai_name2_buf(new_ra, sizeof(new_ra), &new_ra_id);
+ tlli = msgb_tlli(msg);
+ ptmsi = gprs_tlli2tmsi(tlli);
+ }
+#ifdef BUILD_IU
+ /* UTRAN via Iu */
+ else if (MSG_IU_UE_CTX(msg)) {
+ struct osmo_mobile_identity mi;
+ gprs_rai_to_osmo(&new_ra_id, &MSG_IU_UE_CTX(msg)->ra_id);
- if (mmctx->gmm_fsm->state == ST_GMM_DEREGISTERED)
- LOGMMCTXP(LOGL_INFO, mmctx,
- "Rejecting RAU - GMM state is deregistered. Old RA: %s New RA: %s\n",
- osmo_rai_name2(&req.old_rai), new_ra);
- else
- LOGMMCTXP(LOGL_INFO, mmctx,
- "Rejecting RAU - Old RA doesn't match MM. Old RA: %s New RA: %s\n",
- osmo_rai_name2(&req.old_rai), new_ra);
+ if (!TLVP_PRESENT(&req.tlv, GSM48_IE_GMM_ALLOC_PTMSI)) {
+ LOGMMCTXP(LOGL_NOTICE, mmctx, "GMM RA UPDATE REQUEST: missing PTMSI IE on
Iu\n");
+ reject_cause = GMM_CAUSE_IE_NOTEXIST_NOTIMPL;
+ goto rejected;
+ }
+
+ if (osmo_mobile_identity_decode(&mi, TLVP_VAL(&req.tlv,
GSM48_IE_GMM_ALLOC_PTMSI),
+ TLVP_LEN(&req.tlv, GSM48_IE_GMM_ALLOC_PTMSI), false)
+ || mi.type != GSM_MI_TYPE_TMSI) {
+ LOGIUP(MSG_IU_UE_CTX(msg), LOGL_ERROR, "Cannot decode P-TMSI\n");
+ reject_cause = GMM_CAUSE_IE_NOTEXIST_NOTIMPL;
+ goto rejected;
+ }
+
+ ptmsi = mi.tmsi;
+ }
+#endif /* BUILD_IU */
+ else {
+ OSMO_ASSERT(0);
+ }
+
+ if (TLVP_PRESENT(&req.tlv, GSM48_IE_GMM_PTMSI_TYPE)) {
+ ptmsi_type = (*TLVP_VAL(&req.tlv, GSM48_IE_GMM_PTMSI_TYPE)) & 0x1;
+ }
+
+ /* TODO: Check if there is an MM CTX with old_ra_id and
+ * the P-TMSI (if given, reguired for UMTS) or as last resort
+ * if the TLLI matches foreign_tlli (P-TMSI). Note that this
+ * is an optimization to avoid the RA reject (impl detached)
+ * below, which will cause a new attach cycle. */
+ /* Look-up the MM context based on old RA-ID and TLLI */
+ if (!MSG_IU_UE_CTX(msg)) {
+ /* Gb */
+ mmctx = sgsn_mm_ctx_by_tlli_and_ptmsi(tlli, &req.old_rai);
+ } else if (TLVP_PRESENT(&req.tlv, GSM48_IE_GMM_ALLOC_PTMSI)) {
+#ifdef BUILD_IU
+ /* In Iu mode search only for ptmsi */
+ mmctx = sgsn_mm_ctx_by_ptmsi(ptmsi);
+#else
+ LOGIUP(MSG_IU_UE_CTX(msg), LOGL_ERROR,
+ "Rejecting GMM RA Update Request: No Iu support\n");
+ goto rejected;
+#endif
+ }
+
+ if (ptmsi_type == PTMSI_TYPE_MAPPED) {
+ /* the UE is transitioning from EUTRAN to GERAN/UTRAN */
+ foreign_ra = true;
reject_cause = GMM_CAUSE_IMPL_DETACHED;
+ LOGP(DGPRS, LOGL_ERROR, "UE has a mapped P-TMSI. MME-to-SGSN mobility not
implemented. Rejecting\n");
goto rejected;
+ } else { /* (ptmsi_type == PTMSI_TYPE_NATIVE) - 2G/3G PTMSI */
+ /* Check if this a local RA or a foreign */
+ struct sgsn_ra *ra;
+
+ ra = sgsn_ra_get_ra(&req.old_rai);
+ if (!ra) {
+ LOGP(DGPRS, LOGL_ERROR, "Can't find RA for native PTMSI. SGSN-to-SGSN
mobility not implemented. Rejecting\n");
+ foreign_ra = true;
+ reject_cause = GMM_CAUSE_IMPL_DETACHED;
+ goto rejected;
+ }
+
+ /* GERAN / UTRAN with local RA */
+ if (!mmctx) {
+ /* BSSGP doesn't give us an mmctx, old RAI is GERAN or UTRAN */
+
+
+ if (mmctx) {
+ LOGMMCTXP(LOGL_INFO, mmctx,
+ "Looked up by matching TLLI and P_TMSI. "
+ "BSSGP TLLI: %08x, P-TMSI: %08x (%08x), "
+ "TLLI: %08x (%08x), RA: %s\n",
+ msgb_tlli(msg),
+ mmctx->p_tmsi, mmctx->p_tmsi_old,
+ mmctx->gb.tlli, mmctx->gb.tlli_new,
+ osmo_rai_name2(&mmctx->ra));
+ /* A RAT change will trigger the common procedure
+ * below after handling the RAT change. Protect it
+ * here from being called twice */
+ if (!mmctx_did_rat_change(mmctx, msg))
+ osmo_fsm_inst_dispatch(mmctx->gmm_fsm, E_GMM_COMMON_PROC_INIT_REQ, NULL);
+ }
+ }
}
if (!mmctx) {
@@ -1764,6 +1648,52 @@
goto rejected;
}
+ /* MS Radio Capability */
+ mmctx->ms_radio_access_capa.len = OSMO_MIN(req.ms_radio_cap_len,
sizeof(mmctx->ms_radio_access_capa.buf));
+ memcpy(&mmctx->ms_radio_access_capa.buf, req.ms_radio_cap,
req.ms_radio_cap_len);
+
+ /* MS Network Capability */
+ if (TLVP_PRES_LEN(&req.tlv, GSM48_IE_GMM_MS_NET_CAPA, 1)) {
+ mmctx->ms_network_capa.len = OSMO_MIN(TLVP_LEN(&req.tlv,
GSM48_IE_GMM_MS_NET_CAPA), sizeof(mmctx->ms_network_capa.buf));
+ memcpy(&mmctx->ms_network_capa.buf, TLVP_VAL(&req.tlv,
GSM48_IE_GMM_MS_NET_CAPA), mmctx->ms_network_capa.len);
+ } else if (foreign_ra) {
+ /* If this isn't a foreign RA, we can continue to use the old network capability,
+ * the UE should have sent us its current network capability anyways */
+ mmctx->ms_network_capa.len = 0;
+ }
+
+ if (TLVP_PRES_LEN(&req.tlv, GSM48_IE_GMM_PTMSI_SIG, 3)) {
+ memcpy(mmctx->attach_rau.p_tmsi_sig, TLVP_VAL(&req.tlv, GSM48_IE_GMM_PTMSI_SIG),
sizeof(mmctx->attach_rau.p_tmsi_sig));
+ mmctx->attach_rau.p_tmsi_sig_valid = true;
+ } else {
+ mmctx->attach_rau.p_tmsi_sig_valid = false;
+ }
+
+ /* check state for local UE */
+ if (!foreign_ra &&
+ (osmo_rai_cmp(&mmctx->ra, &req.old_rai) ||
+ mmctx->gmm_fsm->state == ST_GMM_DEREGISTERED))
+ {
+ /* We've received either a RAU for a MS which isn't registered
+ * or a RAU with an unknown RA ID. As long the SGSN doesn't support
+ * PS handover we treat this as invalid RAU */
+ char new_ra[32];
+
+ osmo_rai_name2_buf(new_ra, sizeof(new_ra), &new_ra_id);
+
+ if (mmctx->gmm_fsm->state == ST_GMM_DEREGISTERED)
+ LOGMMCTXP(LOGL_INFO, mmctx,
+ "Rejecting RAU - GMM state is deregistered. Old RA: %s New RA: %s\n",
+ osmo_rai_name2(&req.old_rai), new_ra);
+ else
+ LOGMMCTXP(LOGL_INFO, mmctx,
+ "Rejecting RAU - Old RA doesn't match MM. Old RA: %s New RA: %s\n",
+ osmo_rai_name2(&req.old_rai), new_ra);
+
+ reject_cause = GMM_CAUSE_IMPL_DETACHED;
+ goto rejected;
+ }
+
if (mmctx_did_rat_change(mmctx, msg)) {
mmctx_handle_rat_change(mmctx, msg, llme);
osmo_fsm_inst_dispatch(mmctx->gmm_fsm, E_GMM_COMMON_PROC_INIT_REQ, NULL);
@@ -1784,14 +1714,9 @@
if (TLVP_PRESENT(&req.tlv, GSM48_IE_GMM_DRX_PARAM))
memcpy(&mmctx->drx_parms, TLVP_VAL(&req.tlv, GSM48_IE_GMM_DRX_PARAM),
sizeof(mmctx->drx_parms));
- /* FIXME: Update the MM context with the MS radio acc capabilities */
- /* FIXME: Update the MM context with the MS network capabilities */
-
rate_ctr_inc(rate_ctr_group_get_ctr(mmctx->ctrg, GMM_CTR_RA_UPDATE));
#ifdef PTMSI_ALLOC
- ptmsi_update(mmctx);
-
/* Start T3350 and re-transmit up to 5 times until ATTACH COMPLETE */
mmctx->t3350_mode = GMM_T3350_MODE_RAU;
mmctx_timer_start(mmctx, 3350);
@@ -1805,39 +1730,67 @@
#endif
if (mmctx->ran_type == MM_CTX_T_GERAN_Gb) {
/* Even if there is no P-TMSI allocated, the MS will switch from
- * foreign TLLI to local TLLI */
+ * foreign TLLI to local TLLI */
mmctx->gb.tlli_new = gprs_tmsi2tlli(mmctx->p_tmsi, TLLI_LOCAL);
-
- /* Inform LLC layer about new TLLI but keep accepting the old one during Rx */
- gprs_llgmm_assign(mmctx->gb.llme, mmctx->gb.tlli,
- mmctx->gb.tlli_new);
}
/* Look at PDP Context Status IE and see if MS's view of
* activated/deactivated NSAPIs agrees with our view */
- if (TLVP_PRESENT(&req.tlv, GSM48_IE_GMM_PDP_CTX_STATUS)) {
- uint16_t pdp_status = osmo_load16le(TLVP_VAL(&req.tlv,
GSM48_IE_GMM_PDP_CTX_STATUS));
- process_ms_ctx_status(mmctx, pdp_status);
+ if (TLVP_PRES_LEN(&req.tlv, GSM48_IE_GMM_PDP_CTX_STATUS, 2)) {
+ mmctx->attach_rau.pdp_status_valid = true;
+ mmctx->attach_rau.pdp_status = osmo_load16le(TLVP_VAL(&req.tlv,
GSM48_IE_GMM_PDP_CTX_STATUS));
}
/* Send RA UPDATE ACCEPT. In Iu, the RA upd request can be called from
* a new Iu connection, so we might need to re-authenticate the
* connection as well as turn on integrity protection. */
mmctx->pending_req = GSM48_MT_GMM_RA_UPD_REQ;
- return gsm48_gmm_authorize(mmctx);
+
+ bool vlr_created = false;
+ if (!mmctx->vsub) {
+ mmctx->vsub = vlr_subscr_find_or_create_by_tmsi(sgsn->vlr, ptmsi,
"mmctx", &vlr_created);
+ if (!mmctx->vsub)
+ goto rejected;
+ }
+
+ mmctx->attach_rau.old_rai = req.old_rai;
+
+ /* FIXME: copy stuff from VSUB over */
+ if (!strlen(mmctx->imsi) && strlen(mmctx->vsub->imsi)) {
+ OSMO_STRLCPY_ARRAY(mmctx->imsi, mmctx->vsub->imsi);
+ }
+
+ if (mmctx->attach_rau.req)
+ osmo_fsm_inst_term(mmctx->attach_rau.rau_fsm, OSMO_FSM_TERM_REGULAR,
fsm_term_att_req_chg);
+
+ mmctx->attach_rau.cksq = req.cksq;
+ mmctx->attach_rau.old_rai = req.old_rai;
+ mmctx->attach_rau.rau_type = vlr_rau_type;
+ mmctx->attach_rau.req = msgb_copy_c(mmctx, msg, "GMM ATTACH REQ");
+ mmctx->attach_rau.foreign = foreign_ra;
+
+ gmm_rau_fsm_req(mmctx);
+
+ return 0;
rejected:
/* Send RA UPDATE REJECT */
LOGMMCTXP(LOGL_NOTICE, mmctx,
"Rejecting RA Update Request with cause '%s' (%d)\n",
get_value_string(gsm48_gmm_cause_names, reject_cause), reject_cause);
- rc = gsm48_tx_gmm_ra_upd_rej(msg, reject_cause);
+ rc = gsm48_tx_gmm_ra_upd_rej_oldmsg(msg, reject_cause);
if (mmctx)
mm_ctx_cleanup_free(mmctx, "GMM RA UPDATE REJ");
- else if (llme)
- gprs_llgmm_unassign(llme);
+ else if (llme) {
+ /* There could be a corner case where the LLME is part of a MMCtx */
+ mmctx = sgsn_mm_ctx_by_llme(llme);
+ if (mmctx) {
+ mm_ctx_cleanup_free(mmctx, "GMM RA UPDATE REJ");
+ } else {
+ gprs_llgmm_unassign(llme);
+ }
#ifdef BUILD_IU
- else if (MSG_IU_UE_CTX(msg)) {
+ } else if (MSG_IU_UE_CTX(msg)) {
unsigned long X1001 = osmo_tdef_get(sgsn->cfg.T_defs, -1001, OSMO_TDEF_S, -1);
ranap_iu_tx_release_free(MSG_IU_UE_CTX(msg), NULL, (int) X1001);
}
@@ -1849,30 +1802,21 @@
/* 3GPP TS 24.008 § 9.4.16: Routing area update complete */
static int gsm48_rx_gmm_ra_upd_compl(struct sgsn_mm_ctx *mmctx)
{
- struct sgsn_signal_data sig_data;
+ int rc = 0;
/* only in case SGSN offered new P-TMSI */
LOGMMCTXP(LOGL_INFO, mmctx, "-> ROUTING AREA UPDATE COMPLETE\n");
mmctx_timer_stop(mmctx, 3350);
mmctx->t3350_mode = GMM_T3350_MODE_NONE;
mmctx->p_tmsi_old = 0;
mmctx->pending_req = 0;
- osmo_fsm_inst_dispatch(mmctx->gmm_fsm, E_GMM_COMMON_PROC_SUCCESS, NULL);
- switch(mmctx->ran_type) {
- case MM_CTX_T_UTRAN_Iu:
- osmo_fsm_inst_dispatch(mmctx->iu.mm_state_fsm, E_PMM_RA_UPDATE, NULL);
- break;
- case MM_CTX_T_GERAN_Gb:
- /* Unassign the old TLLI */
- mmctx->gb.tlli = mmctx->gb.tlli_new;
- gprs_llgmm_assign(mmctx->gb.llme, TLLI_UNASSIGNED,
- mmctx->gb.tlli_new);
- osmo_fsm_inst_dispatch(mmctx->gb.mm_state_fsm, E_MM_RA_UPDATE, NULL);
- break;
+
+ if (mmctx->attach_rau.rau_fsm) {
+ rc = osmo_fsm_inst_dispatch(mmctx->attach_rau.rau_fsm, GMM_RAU_E_UE_RAU_COMPLETE,
NULL);
}
- memset(&sig_data, 0, sizeof(sig_data));
- sig_data.mm = mmctx;
- osmo_signal_dispatch(SS_SGSN, S_SGSN_UPDATE, &sig_data);
+ if (!mmctx->attach_rau.rau_fsm || rc != 0) {
+ /* FIXME: fail gracefully here or just ignore?! */
+ }
return 0;
}
@@ -1903,6 +1847,7 @@
uint8_t service_type, mi_len;
struct tlv_parsed tp;
struct osmo_mobile_identity mi;
+ struct osmo_routing_area_id ra_id;
char mi_log_string[32];
enum gsm48_gmm_cause reject_cause;
int rc;
@@ -1915,8 +1860,10 @@
return -1;
}
- /* Skip Ciphering key sequence number 10.5.1.2 */
- /* uint8_t ciph_seq_nr = *cur & 0x07; */
+ gprs_rai_to_osmo(&ra_id, &MSG_IU_UE_CTX(msg)->ra_id);
+
+ /* Ciphering key sequence number 10.5.1.2 */
+ uint8_t key_seq = *cur & 0x07;
/* Service type 10.5.5.20 */
service_type = (*cur++ >> 4) & 0x07;
@@ -1968,7 +1915,6 @@
goto rejected;
}
- osmo_fsm_inst_dispatch(ctx->gmm_fsm, E_GMM_COMMON_PROC_INIT_REQ, NULL);
ctx->iu.service.type = service_type;
@@ -1977,6 +1923,8 @@
if (TLVP_PRESENT(&tp, GSM48_IE_GMM_PDP_CTX_STATUS)) {
uint16_t pdp_status = tlvp_val16be(&tp, GSM48_IE_GMM_PDP_CTX_STATUS);
+ /* FIXME: this should be done after the connection has been authenticated! */
+
process_ms_ctx_status(ctx, pdp_status);
/* 3GPP TS 24.008 § 4.7.13.4 Service request procedure not
@@ -1990,9 +1938,34 @@
}
}
+ /* FIXME: validate the information *before* requesting the vlr proc acc,
+ * because if the information can't be served, we don't need/have to
+ * respond here. E.g. PDP session doesn't exist any more */
ctx->pending_req = GSM48_MT_GMM_SERVICE_REQ;
- return gsm48_gmm_authorize(ctx);
+
+ /* FIXME: we should validate this RA_ID is correct for the UE */
+ if (ctx->vsub) {
+ vlr_proc_acc_req(ctx->gmm_fsm,
+ E_GMM_SERVICE_ACCEPT,
+ E_GMM_SERVICE_REJECT,
+ NULL,
+ sgsn->vlr, ctx,
+ VLR_PR_ARQ_T_CM_SERV_REQ, GSM48_CMSERV_MO_CALL_PACKET,
+ &mi,
+ &ra_id.lac,
+ false, /* TODO: auth is not required when we still got a valid auth key */
+ true, /* TODO: is_ciphering_to_be_attempted, rework to allow no-auth-attach */
+ true, /* TODO: is_ciphering_required, rework to allow no-auth-attach */
+ key_seq,
+ sgsn_mm_ctx_is_r99(ctx), true);
+ /* FIXME: check PMM_IDLE / PMM CONNECT for ciphering complete as implicit */
+ return 0;
+ } else {
+ reject_cause = GMM_CAUSE_NET_FAIL;
+ goto rejected;
+ }
+
err_inval:
LOGPC(DMM, LOGL_INFO, "\n");
@@ -2009,7 +1982,6 @@
}
-
static int gsm48_rx_gmm_status(struct sgsn_mm_ctx *mmctx, struct msgb *msg)
{
struct gsm48_hdr *gh = msgb_l3(msg);
@@ -2132,9 +2104,7 @@
case GSM48_MT_GMM_DETACH_ACK:
if (!mmctx)
goto null_mmctx;
- LOGMMCTXP(LOGL_INFO, mmctx, "-> DETACH ACK\n");
- mm_ctx_cleanup_free(mmctx, "GMM DETACH ACK");
- rc = 0;
+ rc = gsm48_rx_gmm_det_accept(mmctx, msg);
break;
case GSM48_MT_GMM_ATTACH_COMPL:
if (!mmctx)
@@ -2182,74 +2152,9 @@
static void mmctx_timer_cb(void *_mm)
{
struct sgsn_mm_ctx *mm = _mm;
- struct gsm_auth_tuple *at;
- int rc;
- unsigned long seconds;
-
mm->num_T_exp++;
switch (mm->T) {
- case 3350: /* waiting for ATTACH COMPLETE */
- if (mm->num_T_exp >= 5) {
- LOGMMCTXP(LOGL_NOTICE, mm, "T3350 expired >= 5 times\n");
- mm_ctx_cleanup_free(mm, "T3350");
- /* FIXME: should we return some error? */
- break;
- }
- /* re-transmit the respective msg and re-start timer */
- switch (mm->t3350_mode) {
- case GMM_T3350_MODE_ATT:
- gsm48_tx_gmm_att_ack(mm);
- break;
- case GMM_T3350_MODE_RAU:
- gsm48_tx_gmm_ra_upd_ack(mm);
- break;
- case GMM_T3350_MODE_PTMSI_REALL:
- /* FIXME */
- break;
- case GMM_T3350_MODE_NONE:
- LOGMMCTXP(LOGL_NOTICE, mm,
- "T3350 mode wasn't set, ignoring timeout\n");
- break;
- }
- seconds = osmo_tdef_get(sgsn->cfg.T_defs, 3350, OSMO_TDEF_S, -1);
- osmo_timer_schedule(&mm->timer, seconds, 0);
- break;
- case 3360: /* waiting for AUTH AND CIPH RESP */
- if (mm->num_T_exp >= 5) {
- LOGMMCTXP(LOGL_NOTICE, mm, "T3360 expired >= 5 times\n");
- mm_ctx_cleanup_free(mm, "T3360");
- break;
- }
- /* Re-transmit the respective msg and re-start timer */
- if (mm->auth_triplet.key_seq == GSM_KEY_SEQ_INVAL) {
- LOGMMCTXP(LOGL_ERROR, mm,
- "timeout: invalid auth triplet reference\n");
- mm_ctx_cleanup_free(mm, "T3360");
- break;
- }
- at = &mm->auth_triplet;
-
- rc = gsm48_tx_gmm_auth_ciph_req(mm, &at->vec, at->key_seq, false);
- if (rc < 0) {
- LOGMMCTXP(LOGL_ERROR, mm, "failed sending Auth. & Ciph. Request: %s \n",
strerror(-rc));
- } else {
- seconds = osmo_tdef_get(sgsn->cfg.T_defs, 3360, OSMO_TDEF_S, -1);
- osmo_timer_schedule(&mm->timer, seconds, 0);
- }
- break;
- case 3370: /* waiting for IDENTITY RESPONSE */
- if (mm->num_T_exp >= 5) {
- LOGMMCTXP(LOGL_NOTICE, mm, "T3370 expired >= 5 times\n");
- gsm48_tx_gmm_att_rej(mm, GMM_CAUSE_MS_ID_NOT_DERIVED);
- mm_ctx_cleanup_free(mm, "GMM ATTACH REJECT (T3370)");
- break;
- }
- /* re-tranmit IDENTITY REQUEST and re-start timer */
- gsm48_tx_gmm_id_req(mm, mm->t3370_id_type);
- seconds = osmo_tdef_get(sgsn->cfg.T_defs, 3370, OSMO_TDEF_S, -1);
- osmo_timer_schedule(&mm->timer, seconds, 0);
- break;
default:
LOGMMCTXP(LOGL_ERROR, mm, "timer expired in unknown mode %u\n",
mm->T);
@@ -2378,3 +2283,288 @@
return rc;
}
+
+static int vlr_tx_auth_req_cb(void *ref, struct vlr_auth_tuple *at, bool send_autn)
+{
+ struct sgsn_mm_ctx *mmctx = ref;
+ if (!mmctx)
+ return -EINVAL;
+
+ mmctx->auth_triplet.key_seq = at->key_seq;
+ mmctx->auth_triplet.vec = at->vec;
+ osmo_fsm_inst_dispatch(mmctx->gmm_fsm, E_GMM_COMMON_PROC_INIT_REQ, NULL);
+ return gsm48_tx_gmm_auth_ciph_req(mmctx, &at->vec, at->key_seq, false);
+}
+
+static int vlr_tx_auth_rej_cb(void *ref)
+{
+ struct sgsn_mm_ctx *mmctx = ref;
+ int rc;
+ if (!mmctx)
+ return -EINVAL;
+
+ rc = gsm48_tx_gmm_auth_ciph_rej(mmctx);
+ osmo_fsm_inst_dispatch(mmctx->gmm_fsm, E_GMM_COMMON_PROC_FAILED, NULL);
+
+ return rc;
+}
+
+static int vlr_subscr_assoc_cb(void *ref, struct vlr_subscr *vsub)
+{
+ struct sgsn_mm_ctx *mmctx = ref;
+ if (!mmctx)
+ return -EINVAL;
+
+ vlr_subscr_get(vsub, "mmctx");
+ mmctx->vsub = vsub;
+ /* FIXME: copy stuff from VSUB over */
+ if (!strlen(mmctx->imsi) && strlen(mmctx->vsub->imsi)) {
+ OSMO_STRLCPY_ARRAY(mmctx->imsi, mmctx->vsub->imsi);
+ }
+
+ return 0;
+}
+
+static void vlr_subscr_inval_cb(void *ref, struct vlr_subscr *vsub, enum
gsm48_reject_value cause, bool is_update_procedure)
+{
+ struct sgsn_mm_ctx *mmctx = ref;
+ long data = cause;
+
+ if (!mmctx)
+ return;
+
+ if (!mmctx->vsub)
+ return;
+
+ if (!mmctx->gmm_fsm)
+ return;
+
+ if (gmm_fsm_is_registered(mmctx->gmm_fsm))
+ osmo_fsm_inst_dispatch(mmctx->gmm_fsm, is_update_procedure ? E_GMM_CLEANUP :
E_GMM_NET_INIT_DETACH_REQ, &data);
+
+ /* FIXME: when loosing the VLR subscriber, we should ensure the GMM is in IDLE (same for
PMM) */
+ vlr_subscr_put(vsub, "mmctx");
+ mmctx->vsub = NULL;
+}
+
+static void vlr_subscr_update_cb(struct vlr_subscr *vsub)
+{
+ /* FIXME: update the subscriber, MSISDN, APN related infos */
+}
+
+static int vlr_tx_id_req_cb(void *ref, uint8_t mi_type)
+{
+ struct sgsn_mm_ctx *ctx = ref;
+ if (!ctx)
+ return -EINVAL;
+
+ osmo_fsm_inst_dispatch(ctx->gmm_fsm, E_GMM_COMMON_PROC_INIT_REQ, NULL);
+ return gsm48_tx_gmm_id_req(ctx, mi_type);
+}
+
+static int vlr_tx_lu_acc_cb(void *ref, uint32_t send_tmsi, enum vlr_lu_type lu_type)
+{
+ struct sgsn_mm_ctx *ctx = ref;
+ if (!ctx)
+ return -EINVAL;
+
+ /* FIXME: rethink p-tmsi relocation */
+ if (ctx->p_tmsi != send_tmsi && ctx->p_tmsi != GSM_RESERVED_TMSI
&& send_tmsi != GSM_RESERVED_TMSI)
+ {
+ ctx->p_tmsi_old = ctx->p_tmsi;
+ ctx->p_tmsi = send_tmsi;
+ ctx->gb.tlli_new = gprs_tmsi2tlli(ctx->p_tmsi, TLLI_LOCAL);
+
+ if (ctx->ran_type == MM_CTX_T_GERAN_Gb) {
+ /* Inform LLC layer about new TLLI but keep old active */
+ if (sgsn_mm_ctx_is_authenticated(ctx))
+ gprs_llme_copy_key(ctx, ctx->gb.llme);
+
+ gprs_llgmm_assign(ctx->gb.llme, ctx->gb.tlli, ctx->gb.tlli_new);
+ }
+ }
+
+ if (ctx->attach_rau.rau_fsm) {
+ osmo_fsm_inst_dispatch(ctx->attach_rau.rau_fsm, GMM_RAU_E_VLR_RAU_ACCEPT, (void *)
lu_type);
+ }
+
+ /* FIXME: maybe move this */
+ if (ctx->attach_rau.foreign) {
+ switch(ctx->ran_type) {
+ case MM_CTX_T_UTRAN_Iu:
+ osmo_fsm_inst_dispatch(ctx->iu.mm_state_fsm, E_PMM_PS_ATTACH, NULL);
+ break;
+ case MM_CTX_T_GERAN_Gb:
+ osmo_fsm_inst_dispatch(ctx->gb.mm_state_fsm, E_MM_GPRS_ATTACH, NULL);
+ break;
+ }
+ }
+
+ // inform LLC layer
+
+ /* FIXME: kick GMM FSM - only on Complete, right? */
+ /* TODO: check here if we need to send a Attach Accept or Routing Area Accept (use
update type?) */
+
+ return 0;
+}
+
+static int vlr_tx_lu_rej_cb(void *ref, enum gsm48_reject_value cause, enum vlr_lu_type
lu_type)
+{
+ struct sgsn_mm_ctx *ctx = ref;
+ if (!ctx)
+ return -EINVAL;
+
+ if (ctx->attach_rau.rau_fsm)
+ osmo_fsm_inst_dispatch(ctx->attach_rau.rau_fsm, GMM_RAU_E_VLR_RAU_REJECT, (void *)
cause);
+
+ return 0;
+}
+
+static int vlr_tx_cm_serv_acc_cb(void *ref, enum osmo_cm_service_type cm_service_type)
+{
+ struct sgsn_mm_ctx *ctx = ref;
+ if (!ctx)
+ return -EINVAL;
+
+ /* PMM_IDLE, a successful Security Command is an implicit Service Accept */
+ /* PMM_DETACHED shouldn't reached and a Service Request is checked before */
+ if (ctx->iu.mm_state_fsm->state == ST_PMM_CONNECTED) {
+ gsm48_tx_gmm_service_ack(ctx);
+ }
+
+ return 0;
+}
+
+static int vlr_tx_cm_serv_rej_cb(void *ref, enum osmo_cm_service_type cm_service_type,
enum gsm48_reject_value cause)
+{
+ struct sgsn_mm_ctx *ctx = ref;
+ if (!ctx)
+ return -EINVAL;
+
+ return gsm48_tx_gmm_service_rej(ctx, cause);
+}
+
+static int vlr_set_ciph_mode_cb(void *ref, bool umts_aka, bool retrieve_imeisv)
+{
+ struct sgsn_mm_ctx *ctx = ref;
+ struct vlr_subscr *vsub;
+ bool send_ck;
+
+ if (!ctx)
+ return -EINVAL;
+
+ // FIXME: decide if we want the VLR code to decide which ciphering
+
+ /* for geran, we do nothing right now */
+ if (ctx->ran_type == MM_CTX_T_GERAN_Gb)
+ return 0;
+
+ vsub = ctx->vsub;
+ if (!vsub || !vsub->last_tuple) {
+ LOGMMCTXP(LOGL_ERROR, ctx, "Set cipher mode callback failed with NULL vsub or
empty tuple");
+ return -EINVAL;
+ }
+
+ send_ck = sgsn->cfg.uea_encryption_mask > (1 << OSMO_UTRAN_UEA0);
+ ranap_iu_tx_sec_mode_cmd(ctx->iu.ue_ctx, &ctx->auth_triplet.vec, send_ck,
ctx->iu.new_key);
+
+ return 0;
+}
+
+static int vlr_tx_common_id_cb(void *ref)
+{
+ struct sgsn_mm_ctx *ctx = ref;
+ if (!ctx)
+ return -EINVAL;
+
+ if (ctx->ran_type == MM_CTX_T_UTRAN_Iu)
+ return ranap_iu_tx_common_id(ctx->iu.ue_ctx, ctx->imsi);
+
+ return 0;
+}
+
+static int vlr_tx_mm_info_cb(void *ref)
+{
+ return 0;
+}
+
+/* decide if the location/routing area id is within the VLR or not */
+static bool vlr_location_served_cb(struct vlr_subscr *vsub, const struct
osmo_routing_area_id *rai)
+{
+ return false;
+}
+
+int vlr_pvlr_request_cb(void *ref, const struct osmo_routing_area_id *old_rai)
+{
+ return 1;
+}
+
+
+/* Fixme: rename into gsup .client mux init */
+int gmm_vlr_init(struct sgsn_instance *sgi)
+{
+ const char *addr_str;
+ struct ipaccess_unit *ipa_dev;
+ int rc;
+
+ osmo_vlr_set_log_cat(OSMO_VLR_LOGC_VLR, DVLR);
+
+ struct vlr_ops vlr_ops = {
+ .subscr_assoc = vlr_subscr_assoc_cb,
+ .subscr_inval = vlr_subscr_inval_cb,
+ .subscr_update = vlr_subscr_update_cb,
+ .location_served = vlr_location_served_cb,
+
+ .set_ciph_mode = vlr_set_ciph_mode_cb,
+
+ .tx_id_req = vlr_tx_id_req_cb,
+ .tx_auth_req = vlr_tx_auth_req_cb,
+ .tx_auth_rej = vlr_tx_auth_rej_cb,
+
+ .tx_cm_serv_acc = vlr_tx_cm_serv_acc_cb,
+ .tx_cm_serv_rej = vlr_tx_cm_serv_rej_cb,
+ .tx_mm_info = vlr_tx_mm_info_cb,
+ .tx_lu_acc = vlr_tx_lu_acc_cb,
+ .tx_lu_rej = vlr_tx_lu_rej_cb,
+
+ .tx_common_id = vlr_tx_common_id_cb,
+
+ .tx_pvlr_request = vlr_pvlr_request_cb,
+ };
+
+ addr_str = inet_ntoa(sgi->cfg.gsup_server_addr.sin_addr);
+
+ sgi->gcm = gsup_client_mux_alloc(sgi);
+ OSMO_ASSERT(sgi->gcm);
+
+ ipa_dev = talloc_zero(sgi, struct ipaccess_unit);
+ ipa_dev->unit_name = "SGSN";
+ ipa_dev->serno = sgi->cfg.sgsn_ipa_name; /* NULL unless configured via VTY */
+ ipa_dev->swversion = PACKAGE_NAME "-" PACKAGE_VERSION;
+
+ sgi->gcm->rx_cb[OSMO_GSUP_MESSAGE_CLASS_SUBSCRIBER_MANAGEMENT] = (struct
gsup_client_mux_rx_cb){
+ .func = vlr_gsup_rx,
+ .data = sgsn->vlr,
+ };
+
+ rc = gsup_client_mux_start(sgi->gcm, addr_str, sgi->cfg.gsup_server_port,
ipa_dev);
+ if (rc)
+ return rc;
+
+ sgi->vlr = vlr_alloc(sgi, &vlr_ops, true);
+ if (!sgi->vlr)
+ return -1;
+
+ sgsn->vlr->cfg.assign_tmsi = true;
+ sgsn->vlr->cfg.auth_reuse_old_sets_on_error = false;
+ sgsn->vlr->cfg.auth_tuple_max_reuse_count = 0;
+ sgsn->vlr->cfg.is_ps = true;
+
+ rc = vlr_start(sgsn->vlr, sgsn->gcm);
+ if (rc < 0) {
+ LOGP(DGPRS, LOGL_FATAL, "Cannot set up VLR\n");
+ return rc;
+ }
+
+ return 0;
+}
diff --git a/src/sgsn/gprs_gmm_attach.c b/src/sgsn/gprs_gmm_attach.c
index 6331992..e69de29 100644
--- a/src/sgsn/gprs_gmm_attach.c
+++ b/src/sgsn/gprs_gmm_attach.c
@@ -1,478 +0,0 @@
-#include <osmocom/core/tdef.h>
-#include <osmocom/crypt/utran_cipher.h>
-
-#include <osmocom/sgsn/gprs_gmm_attach.h>
-
-#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
-#include <osmocom/sgsn/debug.h>
-#include <osmocom/sgsn/gprs_gmm.h>
-#include <osmocom/sgsn/mmctx.h>
-#include <osmocom/sgsn/sgsn.h>
-
-#define X(s) (1 << (s))
-
-static int require_identity_imei = 1;
-static int require_auth = 1;
-
-static const struct osmo_tdef_state_timeout gmm_attach_fsm_timeouts[32] = {
- [ST_IDENTIY] = { .T=3370 },
- [ST_AUTH] = { .T=3360 },
- [ST_ACCEPT] = { .T=3350 },
- [ST_ASK_VLR] = { .T=3350 },
- [ST_IU_SECURITY_CMD] = { .T=3350 },
-};
-
-#define gmm_attach_fsm_state_chg(fi, NEXT_STATE) \
- osmo_tdef_fsm_inst_state_chg(fi, NEXT_STATE, gmm_attach_fsm_timeouts,
sgsn->cfg.T_defs, -1)
-
-
-static void st_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)
-{
- struct sgsn_mm_ctx *ctx = fi->priv;
- struct msgb *attach_req = data;
-
- /* we can run st_init multiple times */
- if (ctx->gmm_att_req.attach_req)
- msgb_free(ctx->gmm_att_req.attach_req);
-
- ctx->gmm_att_req.attach_req = msgb_copy(attach_req, "Attach Request");
- ctx->auth_state = SGSN_AUTH_UNKNOWN;
- ctx->gmm_att_req.auth_reattempt = 0;
-
- /*
- * TODO: remove pending_req as soon the sgsn_auth code doesn't depend
- * on it.
- * pending_req must be set, even this fsm doesn't use it, because
- * the sgsn_auth code is using this too
- */
- ctx->pending_req = GSM48_MT_GMM_ATTACH_REQ;
-
- if (require_identity_imei) {
- ctx->gmm_att_req.id_type = GSM_MI_TYPE_IMEI;
- gmm_attach_fsm_state_chg(fi, ST_IDENTIY);
- } else if (!strlen(ctx->imsi)) {
- ctx->gmm_att_req.id_type = GSM_MI_TYPE_IMSI;
- gmm_attach_fsm_state_chg(fi, ST_IDENTIY);
- } else if (require_auth)
- gmm_attach_fsm_state_chg(fi, ST_AUTH);
- else
- gmm_attach_fsm_state_chg(fi, ST_ACCEPT);
-}
-
-static void st_identity_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
-{
- struct sgsn_mm_ctx *ctx = fi->priv;
- int ret = 0;
-
- ctx->num_T_exp = 0;
-
- switch (ctx->gmm_att_req.id_type) {
- case GSM_MI_TYPE_IMEI:
- case GSM_MI_TYPE_IMSI:
- break;
- default:
- /* TODO logging */
- osmo_fsm_inst_dispatch(fi, E_REJECT, NULL);
- return;
- }
-
- ctx->t3370_id_type = ctx->gmm_att_req.id_type;
- ret = gsm48_tx_gmm_id_req(ctx, ctx->gmm_att_req.id_type);
- if (ret < 0) {
- LOGPFSM(fi, "Can not send tx_gmm_id %d.\n", ret);
- osmo_fsm_inst_dispatch(fi, E_REJECT, NULL);
- }
-}
-
-static void st_identity(struct osmo_fsm_inst *fi, uint32_t event, void *data)
-{
- struct sgsn_mm_ctx *ctx = fi->priv;
-
- OSMO_ASSERT(event == E_IDEN_RESP_RECV);
-
- /* check if we received a identity response */
- long type = (long) data;
- switch (type) {
- case GSM_MI_TYPE_IMEI:
- case GSM_MI_TYPE_IMSI:
- break;
- default:
- LOGMMCTXP(LOGL_ERROR, ctx, "Unknown mi type: 0x%lx, rejecting MS.\n", type);
- osmo_fsm_inst_dispatch(fi, E_REJECT, (void *) GMM_CAUSE_NET_FAIL);
- return;
- }
-
- if (type != ctx->gmm_att_req.id_type) {
- /* ignore wrong package */
- /* TODO logging */
- return;
- }
-
- if (type == GSM_MI_TYPE_IMEI && !strlen(ctx->imsi)) {
- ctx->gmm_att_req.id_type = GSM_MI_TYPE_IMSI;
- gmm_attach_fsm_state_chg(fi, ST_IDENTIY);
- } else if (require_auth)
- gmm_attach_fsm_state_chg(fi, ST_AUTH);
- else
- gmm_attach_fsm_state_chg(fi, ST_ACCEPT);
-}
-
-static void st_auth_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
-{
- struct sgsn_mm_ctx *ctx = fi->priv;
- enum sgsn_auth_state auth_state;
-
- ctx->num_T_exp = 0;
-
- /* TODO: remove this layer violation. Don't parse any auth_policy here
- * The correct way would be to ask the SGSN is this mmctx has to be auth
- * regardless of the state.
- * Otherwise someone else could steal the TLLI and just use it without further
- * auth.
- */
- if (sgsn->cfg.auth_policy != SGSN_AUTH_POLICY_REMOTE) {
- /* we can "trust" sgsn_auth_state as long it's not remote */
- auth_state = sgsn_auth_state(ctx);
- } else {
- auth_state = ctx->auth_state;
- }
-
- switch(auth_state) {
- case SGSN_AUTH_UMTS_RESYNC: /* ask the vlr for a new vector to match the simcards seq
*/
- case SGSN_AUTH_UNKNOWN: /* the SGSN doesn know this MS */
- gmm_attach_fsm_state_chg(fi, ST_ASK_VLR);
- break;
- case SGSN_AUTH_REJECTED:
- /* TODO: correct GMM cause */
- osmo_fsm_inst_dispatch(fi, E_REJECT, (void *) GMM_CAUSE_GPRS_NOTALLOWED);
- break;
- case SGSN_AUTH_ACCEPTED:
- gmm_attach_fsm_state_chg(fi, ST_ACCEPT);
- break;
- case SGSN_AUTH_AUTHENTICATE:
- if (ctx->auth_triplet.key_seq == GSM_KEY_SEQ_INVAL) {
- /* invalid key material */
- gmm_attach_fsm_state_chg(fi, ST_ASK_VLR);
- }
-
- struct gsm_auth_tuple *at = &ctx->auth_triplet;
- if (gsm48_tx_gmm_auth_ciph_req(ctx, &at->vec, at->key_seq,
- false) < 0) {
- /* network failure */
- osmo_fsm_inst_dispatch(fi, E_REJECT, (void *) GMM_CAUSE_NET_FAIL);
- }
- ctx->gmm_att_req.auth_reattempt++;
- break;
- }
-}
-
-static void st_auth(struct osmo_fsm_inst *fi, uint32_t event, void *data)
-{
- struct sgsn_mm_ctx *ctx = fi->priv;
-
- switch (event) {
- case E_AUTH_RESP_RECV_SUCCESS:
- sgsn_auth_request(ctx);
-#ifdef BUILD_IU
- if (ctx->ran_type == MM_CTX_T_UTRAN_Iu &&
!ctx->iu.ue_ctx->integrity_active)
- gmm_attach_fsm_state_chg(fi, ST_IU_SECURITY_CMD);
- else
-#endif /* BUILD_IU */
- gmm_attach_fsm_state_chg(fi, ST_ACCEPT);
- break;
- case E_AUTH_RESP_RECV_RESYNC:
- if (ctx->gmm_att_req.auth_reattempt <= 1)
- gmm_attach_fsm_state_chg(fi, ST_ASK_VLR);
- else
- osmo_fsm_inst_dispatch(fi, E_REJECT, (void *) GMM_CAUSE_SYNC_FAIL);
- break;
- }
-}
-
-static void st_accept_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
-{
- struct sgsn_mm_ctx *ctx = fi->priv;
-
- ctx->num_T_exp = 0;
-
- /* TODO: remove pending_req as soon the sgsn_auth code doesn't depend on it */
- ctx->pending_req = 0;
- gsm48_tx_gmm_att_ack(ctx);
-}
-
-static void st_accept(struct osmo_fsm_inst *fi, uint32_t event, void *data)
-{
- struct sgsn_mm_ctx *ctx = fi->priv;
-
- switch(event) {
- case E_ATTACH_COMPLETE_RECV:
- /* TODO: #ifdef ! PTMSI_ALLOC is not supported */
- extract_subscr_msisdn(ctx);
- extract_subscr_hlr(ctx);
- osmo_fsm_inst_state_chg(fi, ST_INIT, 0, 0);
- break;
- case E_VLR_ANSWERED:
- extract_subscr_msisdn(ctx);
- extract_subscr_hlr(ctx);
- LOGMMCTXP(LOGL_NOTICE, ctx,
- "Unusual event: if MS got no data connection, check that it has APN
configured.\n");
- break;
- }
-}
-
-static void st_reject(struct osmo_fsm_inst *fi, uint32_t event, void *data)
-{
- struct sgsn_mm_ctx *ctx = fi->priv;
- long reject_cause = (long) data;
-
- if (reject_cause != GMM_DISCARD_MS_WITHOUT_REJECT)
- gsm48_tx_gmm_att_rej(ctx, (uint8_t) reject_cause);
-
- sgsn_mm_ctx_cleanup_free(ctx);
-}
-
-static void st_ask_vlr_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
-{
- struct sgsn_mm_ctx *ctx = fi->priv;
-
- /* FIXME: remove this layer violation.
- * The VLR should send the message to the HLR and not the rx function
- * gsm48_rx_gmm_auth_ciph_fail. Because gmm_auth_ciph_fail already send a
- * message to the HLR, we don't send here a request. */
- if (ctx->auth_state == SGSN_AUTH_UMTS_RESYNC)
- return;
-
- /* ask the auth layer for more data */
- sgsn_auth_request(ctx);
-}
-
-static void st_ask_vlr(struct osmo_fsm_inst *fi, uint32_t event, void *data)
-{
- switch(event) {
- case E_VLR_ANSWERED:
- gmm_attach_fsm_state_chg(fi, ST_AUTH);
- break;
- }
-}
-
-static void st_iu_security_cmd_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
-{
-#ifdef BUILD_IU
- struct sgsn_mm_ctx *ctx = fi->priv;
- bool send_ck;
-
- /* TODO: shouldn't this set always? not only when the integrity_active? */
- if (ctx->iu.ue_ctx->integrity_active) {
- gmm_attach_fsm_state_chg(fi, ST_ACCEPT);
- return;
- }
-
- /* Is any encryption above UEA0 enabled? */
- send_ck = sgsn->cfg.uea_encryption_mask > (1 << OSMO_UTRAN_UEA0);
- LOGMMCTXP(LOGL_DEBUG, ctx, "Iu Security Mode Command: %s encryption key (UEA
encryption mask = 0x%x)\n",
- send_ck ? "sending" : "not sending",
sgsn->cfg.uea_encryption_mask);
-
- /* FIXME: we should send the set of allowed UEA, as in ranap_new_msg_sec_mod_cmd2().
However, this
- * is not possible in the iu_client API. See OS#5487. */
- ranap_iu_tx_sec_mode_cmd(ctx->iu.ue_ctx, &ctx->auth_triplet.vec, send_ck,
ctx->iu.new_key);
- ctx->iu.new_key = 0;
-#endif
-}
-
-static void st_iu_security_cmd(struct osmo_fsm_inst *fi, uint32_t event, void *data)
-{
- switch(event) {
- case E_VLR_ANSWERED:
- /* We may receive an event due to rx
- * OSMO_GSUP_MSGT_INSERT_DATA_REQUEST here. Do nothing, update of
- * subscriber is done by lower layers before event is signalled.
- * In this state we simply wait for E_IU_SECURITY_CMD_COMPLETE
- */
- break;
- case E_IU_SECURITY_CMD_COMPLETE:
- gmm_attach_fsm_state_chg(fi, ST_ACCEPT);
- break;
- }
-}
-
-static struct osmo_fsm_state gmm_attach_req_fsm_states[] = {
- /* default state for non-DTX and DTX when SPEECH is in progress */
- [ST_INIT] = {
- .in_event_mask = X(E_ATTACH_REQ_RECV),
- .out_state_mask = X(ST_INIT) | X(ST_IDENTIY) | X(ST_AUTH) | X(ST_ACCEPT),
- .name = "Init",
- .action = st_init,
- },
- [ST_ASK_VLR] = {
- .in_event_mask = X(E_VLR_ANSWERED),
- .out_state_mask = X(ST_INIT) | X(ST_AUTH) | X(ST_ACCEPT) | X(ST_REJECT),
- .name = "AskVLR",
- .onenter = st_ask_vlr_on_enter,
- .action = st_ask_vlr,
- },
- [ST_IDENTIY] = {
- .in_event_mask = X(E_IDEN_RESP_RECV),
- .out_state_mask = X(ST_INIT) | X(ST_AUTH) | X(ST_ACCEPT) | X(ST_IDENTIY) |
X(ST_REJECT),
- .onenter = st_identity_on_enter,
- .name = "CheckIdentity",
- .action = st_identity,
- },
- [ST_AUTH] = {
- .in_event_mask = X(E_AUTH_RESP_RECV_SUCCESS) | X(E_AUTH_RESP_RECV_RESYNC),
- .out_state_mask = X(ST_INIT) | X(ST_AUTH) | X(ST_IU_SECURITY_CMD) | X(ST_ACCEPT) |
X(ST_ASK_VLR) | X(ST_REJECT),
- .name = "Authenticate",
- .onenter = st_auth_on_enter,
- .action = st_auth,
- },
- [ST_IU_SECURITY_CMD] = {
- .in_event_mask = X(E_IU_SECURITY_CMD_COMPLETE) | X(E_VLR_ANSWERED),
- .out_state_mask = X(ST_INIT) | X(ST_AUTH) | X(ST_ACCEPT) | X(ST_REJECT),
- .name = "IuSecurityCommand",
- .onenter = st_iu_security_cmd_on_enter,
- .action = st_iu_security_cmd,
- },
- [ST_ACCEPT] = {
- .in_event_mask = X(E_ATTACH_COMPLETE_RECV) | X(E_VLR_ANSWERED),
- .out_state_mask = X(ST_INIT) | X(ST_REJECT),
- .name = "WaitAttachComplete",
- .onenter = st_accept_on_enter,
- .action = st_accept,
- },
- [ST_REJECT] = {
- .in_event_mask = X(E_REJECT),
- .out_state_mask = X(ST_INIT),
- .name = "Reject",
- .action = st_reject,
- },
-};
-
-const struct value_string gmm_attach_req_fsm_event_names[] = {
- OSMO_VALUE_STRING(E_ATTACH_REQ_RECV),
- OSMO_VALUE_STRING(E_IDEN_RESP_RECV),
- OSMO_VALUE_STRING(E_AUTH_RESP_RECV_SUCCESS),
- OSMO_VALUE_STRING(E_AUTH_RESP_RECV_RESYNC),
- OSMO_VALUE_STRING(E_ATTACH_ACCEPTED),
- OSMO_VALUE_STRING(E_ATTACH_ACCEPT_SENT),
- OSMO_VALUE_STRING(E_ATTACH_COMPLETE_RECV),
- OSMO_VALUE_STRING(E_IU_SECURITY_CMD_COMPLETE),
- OSMO_VALUE_STRING(E_REJECT),
- OSMO_VALUE_STRING(E_VLR_ANSWERED),
- { 0, NULL }
-};
-
-void gmm_attach_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *data) {
- struct sgsn_mm_ctx *ctx = fi->priv;
- struct msgb *new_attach_req = data;
-
- switch (event) {
- case E_ATTACH_REQ_RECV:
- switch (fi->state) {
- case ST_INIT:
- case ST_REJECT:
- st_init(fi, event, data);
- break;
-
- case ST_ACCEPT:
- /* TODO: drop all state (e.g. PDP Ctx) and do this procedure */
- osmo_fsm_inst_state_chg(fi, ST_INIT, 0, 0);
- st_init(fi, event, data);
- break;
-
- case ST_ASK_VLR:
- case ST_AUTH:
- case ST_IDENTIY:
- case ST_RETRIEVE_AUTH:
- /* 04.08 4.7.3.1.6 d) Abnormal Case
- * Only do action if Req IEs differs. */
- if (ctx->gmm_att_req.attach_req &&
- gprs_gmm_msg_cmp(new_attach_req, ctx->gmm_att_req.attach_req)) {
- osmo_fsm_inst_state_chg(fi, ST_INIT, 0, 0);
- st_init(fi, event, data);
- }
- break;
- }
- break;
- case E_REJECT:
- if (fi->state != ST_REJECT)
- osmo_fsm_inst_state_chg(fi, ST_REJECT, 0, 0);
- st_reject(fi, event, data);
- break;
- }
-}
-
-int gmm_attach_timer_cb(struct osmo_fsm_inst *fi)
-{
- struct sgsn_mm_ctx *ctx = fi->priv;
- struct gsm_auth_tuple *at = &ctx->auth_triplet;
- unsigned long t_secs;
-
- ctx->num_T_exp++;
-
- switch(fi->state) {
- case ST_ASK_VLR:
- /* TODO: replace T3350 by a better timer or it's own
- * re-use T3350 - not defined by standard */
- LOGMMCTXP(LOGL_ERROR, ctx, "HLR did not answer in time. Rejecting.\n");
- osmo_fsm_inst_dispatch(fi, E_REJECT,
- (void *) GMM_CAUSE_NET_FAIL);
- break;
- case ST_IDENTIY:
- /* T3370 */
- if (ctx->num_T_exp >= 5) {
- osmo_fsm_inst_dispatch(fi, E_REJECT,
- (void *) GMM_CAUSE_MS_ID_NOT_DERIVED);
- break;
- }
- gsm48_tx_gmm_id_req(ctx, ctx->gmm_att_req.id_type);
- t_secs = osmo_tdef_get(sgsn->cfg.T_defs, 3370, OSMO_TDEF_S, -1);
- osmo_timer_schedule(&fi->timer, t_secs, 0);
-
- break;
- case ST_AUTH:
- /* T3360 */
- if (ctx->num_T_exp >= 5) {
- osmo_fsm_inst_dispatch(fi, E_REJECT, (void *) GMM_DISCARD_MS_WITHOUT_REJECT);
- break;
- }
- gsm48_tx_gmm_auth_ciph_req(ctx, &at->vec, at->key_seq, false);
- t_secs = osmo_tdef_get(sgsn->cfg.T_defs, 3360, OSMO_TDEF_S, -1);
- osmo_timer_schedule(&fi->timer, t_secs, 0);
- break;
- case ST_ACCEPT:
- /* T3350 */
- if (ctx->num_T_exp >= 5) {
- osmo_fsm_inst_dispatch(fi, E_REJECT, (void *) GMM_DISCARD_MS_WITHOUT_REJECT);
- break;
- }
- gsm48_tx_gmm_att_ack(ctx);
- t_secs = osmo_tdef_get(sgsn->cfg.T_defs, 3350, OSMO_TDEF_S, -1);
- osmo_timer_schedule(&fi->timer, t_secs, 0);
- break;
- }
-
- return 0;
-}
-
-struct osmo_fsm gmm_attach_req_fsm = {
- .name = "GMM_ATTACH_REQ_FSM",
- .states = gmm_attach_req_fsm_states,
- .num_states = ARRAY_SIZE(gmm_attach_req_fsm_states),
- .event_names = gmm_attach_req_fsm_event_names,
- .allstate_event_mask = X(E_REJECT) | X(E_ATTACH_REQ_RECV),
- .allstate_action = gmm_attach_allstate_action,
- .log_subsys = DMM,
- .timer_cb = gmm_attach_timer_cb,
-};
-
-static __attribute__((constructor)) void gprs_gmm_fsm_init(void)
-{
- OSMO_ASSERT(osmo_fsm_register(&gmm_attach_req_fsm) == 0);
-}
-
-void gmm_att_req_free(struct sgsn_mm_ctx *mm) {
- if (mm->gmm_att_req.fsm)
- osmo_fsm_inst_free(mm->gmm_att_req.fsm);
-
- if (mm->gmm_att_req.attach_req)
- msgb_free(mm->gmm_att_req.attach_req);
-}
diff --git a/src/sgsn/gprs_gmm_fsm.c b/src/sgsn/gprs_gmm_fsm.c
index 57e1ec3..976356f 100644
--- a/src/sgsn/gprs_gmm_fsm.c
+++ b/src/sgsn/gprs_gmm_fsm.c
@@ -22,6 +22,7 @@
*/
#include <osmocom/core/tdef.h>
+#include <osmocom/sgsn/gprs_gmm.h>
#include <osmocom/sgsn/gprs_gmm_fsm.h>
#include <osmocom/sgsn/gprs_mm_state_gb_fsm.h>
#include <osmocom/sgsn/gprs_mm_state_iu_fsm.h>
@@ -42,6 +43,14 @@
#define gmm_fsm_state_chg(fi, NEXT_STATE) \
osmo_tdef_fsm_inst_state_chg(fi, NEXT_STATE, gmm_fsm_timeouts, sgsn->cfg.T_defs, -1)
+
+void st_gmm_deregistered_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct sgsn_mm_ctx *mmctx = fi->priv;
+
+ mmctx->gmm_priv.common_proc_to_registered = false;
+}
+
static void st_gmm_deregistered(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
switch(event) {
@@ -54,28 +63,51 @@
}
}
-static void st_gmm_common_proc_init(struct osmo_fsm_inst *fi, uint32_t event, void
*data)
+static void st_gmm_common_proc_init(struct osmo_fsm_inst *fi, uint32_t event, void
*_data)
{
+ struct sgsn_mm_ctx *mmctx = fi->priv;
+
switch(event) {
case E_GMM_COMMON_PROC_INIT_REQ:
/* MS may retransmit GPRS Attach Request if for some reason
* CommonProcedure didn't go forward correctly */
break;
/* TODO: events not used
- case E_GMM_LOWER_LAYER_FAILED:
+ case E_GMM_LOWER_LAYER_FAILED: */
case E_GMM_COMMON_PROC_FAILED:
gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED);
break;
- */
- case E_GMM_COMMON_PROC_SUCCESS:
+ case E_GMM_COMMON_PROC_SUCCESS: /* FIXME: a Common Proc Success shouldn't result in
getting to Attach *if* this is part of an attach request */
+ /* ignore if a RAU or Attach is in progress */
+ if (mmctx->attach_rau.rau_fsm)
+ break;
+
+ gmm_fsm_state_chg(fi, ST_GMM_REGISTERED_NORMAL);
+ break;
+ case E_GMM_ATTACH_FAILED:
+ case E_GMM_RAU_FAILED:
+ gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED);
+ break;
case E_GMM_ATTACH_SUCCESS:
+ case E_GMM_RAU_SUCCESS:
gmm_fsm_state_chg(fi, ST_GMM_REGISTERED_NORMAL);
break;
}
}
-static void st_gmm_registered_normal(struct osmo_fsm_inst *fi, uint32_t event, void
*data)
+void st_gmm_registered_normal_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
{
+ struct sgsn_mm_ctx *mmctx = fi->priv;
+
+ mmctx->gmm_priv.common_proc_to_registered = true;
+}
+
+static void st_gmm_registered_normal(struct osmo_fsm_inst *fi, uint32_t event, void
*_data)
+{
+ struct sgsn_mm_ctx *mmctx = fi->priv;
+ long *data = (long *) _data;
+ bool poweroff;
+
switch(event) {
case E_GMM_COMMON_PROC_INIT_REQ:
gmm_fsm_state_chg(fi, ST_GMM_COMMON_PROC_INIT);
@@ -85,12 +117,22 @@
* E_GMM_ATTACH_SUCCESS instead of E_GMM_COMMON_PROC_SUCCESS then we'll receive
the latter here:
* we should simply ignore it */
break;
- /* case E_GMM_NET_INIT_DETACH_REQ:
+ case E_GMM_NET_INIT_DETACH_REQ:
+ OSMO_ASSERT(data);
+ /* data contains the gsm48 reject cause */
+ gsm48_tx_gmm_detach_req(mmctx, GPRS_DET_T_MT_IMSI, (uint8_t) (*data & 0xff));
gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED_INIT);
- break; */
- /* case E_GMM_MS_INIT_DETACH_REQ:
+ break;
+ case E_GMM_MS_INIT_DETACH_REQ:
+ if (!data)
+ poweroff = false;
+ else
+ poweroff = !!(*data);
+
+ if (!poweroff)
+ gsm48_tx_gmm_det_ack(mmctx, false);
gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED);
- break; */
+ break;
case E_GMM_SUSPEND:
gmm_fsm_state_chg(fi, ST_GMM_REGISTERED_SUSPENDED);
break;
@@ -112,8 +154,10 @@
static void st_gmm_deregistered_init(struct osmo_fsm_inst *fi, uint32_t event, void
*data)
{
switch(event) {
- /* TODO: events not used in osmo-sgsn code
case E_GMM_DETACH_ACCEPTED:
+ gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED);
+ break;
+ /* TODO: events not used in osmo-sgsn code
case E_GMM_LOWER_LAYER_FAILED:
gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED);
break;
@@ -125,7 +169,8 @@
[ST_GMM_DEREGISTERED] = {
.in_event_mask =
X(E_GMM_COMMON_PROC_INIT_REQ) |
- X(E_GMM_ATTACH_SUCCESS),
+ X(E_GMM_ATTACH_SUCCESS) |
+ X(E_GMM_ATTACH_FAILED),
.out_state_mask = X(ST_GMM_COMMON_PROC_INIT),
.name = "Deregistered",
.action = st_gmm_deregistered,
@@ -133,9 +178,12 @@
[ST_GMM_COMMON_PROC_INIT] = {
.in_event_mask =
/* X(E_GMM_LOWER_LAYER_FAILED) | */
- /* X(E_GMM_COMMON_PROC_FAILED) | */
+ X(E_GMM_COMMON_PROC_FAILED) |
X(E_GMM_COMMON_PROC_SUCCESS) |
X(E_GMM_ATTACH_SUCCESS) |
+ X(E_GMM_ATTACH_FAILED) |
+ X(E_GMM_RAU_SUCCESS) |
+ X(E_GMM_RAU_FAILED) |
X(E_GMM_COMMON_PROC_INIT_REQ),
.out_state_mask =
X(ST_GMM_DEREGISTERED) |
@@ -147,8 +195,8 @@
.in_event_mask =
X(E_GMM_COMMON_PROC_INIT_REQ) |
X(E_GMM_COMMON_PROC_SUCCESS) |
- /* X(E_GMM_NET_INIT_DETACH_REQ) | */
- /* X(E_GMM_MS_INIT_DETACH_REQ) | */
+ X(E_GMM_NET_INIT_DETACH_REQ) |
+ X(E_GMM_MS_INIT_DETACH_REQ) |
X(E_GMM_SUSPEND),
.out_state_mask =
X(ST_GMM_DEREGISTERED) |
@@ -157,10 +205,13 @@
X(ST_GMM_REGISTERED_SUSPENDED),
.name = "Registered.NORMAL",
.action = st_gmm_registered_normal,
+ .onenter = st_gmm_registered_normal_onenter,
},
[ST_GMM_REGISTERED_SUSPENDED] = {
.in_event_mask = X(E_GMM_RESUME) |
- X(E_GMM_COMMON_PROC_INIT_REQ),
+ X(E_GMM_COMMON_PROC_INIT_REQ) |
+ X(E_GMM_RAU_FAILED) |
+ X(E_GMM_RAU_SUCCESS),
.out_state_mask =
X(ST_GMM_DEREGISTERED) |
X(ST_GMM_REGISTERED_NORMAL) |
@@ -175,21 +226,27 @@
.out_state_mask = X(ST_GMM_DEREGISTERED),
.name = "DeregisteredInitiated",
.action = st_gmm_deregistered_init,
+ .onenter = st_gmm_deregistered_onenter,
},
};
const struct value_string gmm_fsm_event_names[] = {
OSMO_VALUE_STRING(E_GMM_COMMON_PROC_INIT_REQ),
- /* OSMO_VALUE_STRING(E_GMM_COMMON_PROC_FAILED), */
+ OSMO_VALUE_STRING(E_GMM_COMMON_PROC_FAILED),
/* OSMO_VALUE_STRING(E_GMM_LOWER_LAYER_FAILED), */
OSMO_VALUE_STRING(E_GMM_COMMON_PROC_SUCCESS),
OSMO_VALUE_STRING(E_GMM_ATTACH_SUCCESS),
- /* OSMO_VALUE_STRING(E_GMM_NET_INIT_DETACH_REQ), */
- /* OSMO_VALUE_STRING(E_GMM_MS_INIT_DETACH_REQ), */
+ OSMO_VALUE_STRING(E_GMM_ATTACH_FAILED),
+ OSMO_VALUE_STRING(E_GMM_RAU_SUCCESS),
+ OSMO_VALUE_STRING(E_GMM_RAU_FAILED),
+ OSMO_VALUE_STRING(E_GMM_NET_INIT_DETACH_REQ),
+ OSMO_VALUE_STRING(E_GMM_MS_INIT_DETACH_REQ),
/* OSMO_VALUE_STRING(E_GMM_DETACH_ACCEPTED), */
OSMO_VALUE_STRING(E_GMM_SUSPEND),
OSMO_VALUE_STRING(E_GMM_CLEANUP),
OSMO_VALUE_STRING(E_GMM_RAT_CHANGE),
+ OSMO_VALUE_STRING(E_GMM_SERVICE_ACCEPT),
+ OSMO_VALUE_STRING(E_GMM_SERVICE_REJECT),
{ 0, NULL }
};
@@ -202,6 +259,7 @@
switch (fi->state) {
case ST_GMM_COMMON_PROC_INIT:
+ /* fixme: this state seems to be wrong. When in COMMON_PROC_INIT, we shouldn't go
into deregistered. */
gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED);
default:
if (mmctx->ran_type == MM_CTX_T_GERAN_Gb)
@@ -216,6 +274,9 @@
}
case E_GMM_CLEANUP:
+ if (mmctx->attach_rau.rau_fsm)
+ osmo_fsm_inst_term(mmctx->attach_rau.rau_fsm, OSMO_FSM_TERM_REQUEST, NULL);
+
switch (fi->state) {
case ST_GMM_DEREGISTERED:
break;
@@ -223,6 +284,13 @@
gmm_fsm_state_chg(fi, ST_GMM_DEREGISTERED);
break;
}
+ case E_GMM_SERVICE_ACCEPT:
+ switch (fi->state) {
+ case ST_GMM_REGISTERED_NORMAL:
+ gprs_gmm_service_accepted(mmctx);
+ break;
+ }
+ break;
}
}
@@ -236,7 +304,7 @@
.states = gmm_fsm_states,
.num_states = ARRAY_SIZE(gmm_fsm_states),
.event_names = gmm_fsm_event_names,
- .allstate_event_mask = X(E_GMM_CLEANUP) | X(E_GMM_RAT_CHANGE),
+ .allstate_event_mask = X(E_GMM_CLEANUP) | X(E_GMM_RAT_CHANGE) | X(E_GMM_SERVICE_ACCEPT)
| X(E_GMM_SERVICE_REJECT),
.allstate_action = gmm_fsm_allstate_action,
.log_subsys = DMM,
.timer_cb = gmm_fsm_timer_cb,
diff --git a/src/sgsn/gprs_ranap.c b/src/sgsn/gprs_ranap.c
index af764de..ff62351 100644
--- a/src/sgsn/gprs_ranap.c
+++ b/src/sgsn/gprs_ranap.c
@@ -43,6 +43,8 @@
#include <osmocom/sgsn/pdpctx.h>
#include <osmocom/sgsn/mmctx.h>
+#include <osmocom/vlr/vlr.h>
+
/* Send RAB activation requests for all PDP contexts */
void activate_pdp_rabs(struct sgsn_mm_ctx *ctx)
{
@@ -163,9 +165,8 @@
if (rc < 0)
sgsn_ranap_iu_free(mm);
- /* TODO: move this into FSM */
- if (mm->ran_type == MM_CTX_T_UTRAN_Iu && mm->gmm_att_req.fsm->state !=
ST_INIT)
- osmo_fsm_inst_dispatch(mm->gmm_att_req.fsm, E_REJECT, (void *)
GMM_DISCARD_MS_WITHOUT_REJECT);
+ if (mm->vsub)
+ vlr_subscr_disconnected(mm->vsub);
rc = 0;
break;
case RANAP_IU_EVENT_SECURITY_MODE_COMPLETE:
@@ -176,13 +177,10 @@
*/
/* Continue authentication here */
mm->iu.ue_ctx->integrity_active = 1;
- ranap_iu_tx_common_id(mm->iu.ue_ctx, mm->imsi);
- /* FIXME: remove gmm_authorize */
- if (mm->pending_req != GSM48_MT_GMM_ATTACH_REQ)
- gsm48_gmm_authorize(mm);
- else
- osmo_fsm_inst_dispatch(mm->gmm_att_req.fsm, E_IU_SECURITY_CMD_COMPLETE, NULL);
+ if (mm->vsub)
+ vlr_subscr_rx_ciph_res(mm->vsub, VLR_CIPH_COMPL);
+
rc = 0;
break;
default:
diff --git a/src/sgsn/gprs_rau_fsm.c b/src/sgsn/gprs_rau_fsm.c
new file mode 100644
index 0000000..60ca6be
--- /dev/null
+++ b/src/sgsn/gprs_rau_fsm.c
@@ -0,0 +1,342 @@
+/* Routing Area Update FSM for MMCtx to synchrozie for foreign RAU to local RAU
transistions */
+
+/* (C) 2024 by sysmocom s.f.m.c. GmbH <info(a)sysmocom.de>
+ *
+ * Author: Alexander Couzens <lynxis(a)fe80.eu>
+ * 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/>.
+ *
+ */
+
+#include <osmocom/core/fsm.h>
+#include <osmocom/core/signal.h>
+#include <osmocom/core/tdef.h>
+#include <osmocom/gsm/gsm48.h>
+#include <osmocom/vlr/vlr.h>
+
+#include <osmocom/sgsn/gprs_llc.h>
+#include <osmocom/sgsn/gprs_mm_state_gb_fsm.h>
+#include <osmocom/sgsn/gprs_mm_state_iu_fsm.h>
+#include <osmocom/sgsn/gprs_gmm.h>
+#include <osmocom/sgsn/gprs_gmm_fsm.h>
+#include <osmocom/sgsn/gprs_rau_fsm.h>
+#include <osmocom/sgsn/gtp.h>
+#include <osmocom/sgsn/mmctx.h>
+#include <osmocom/sgsn/pdpctx.h>
+#include <osmocom/sgsn/sgsn.h>
+#include <osmocom/sgsn/signal.h>
+
+#define S(x) (1 << (x))
+
+const struct value_string gmm_rau_event_names[] = {
+ OSMO_VALUE_STRING(GMM_RAU_E_UE_RAU_REQUEST),
+ OSMO_VALUE_STRING(GMM_RAU_E_VLR_RAU_ACCEPT),
+ OSMO_VALUE_STRING(GMM_RAU_E_VLR_RAU_REJECT),
+ OSMO_VALUE_STRING(GMM_RAU_E_UE_RAU_COMPLETE),
+ OSMO_VALUE_STRING(GMM_RAU_E_VLR_TERM_FAIL),
+ OSMO_VALUE_STRING(GMM_RAU_E_VLR_TERM_SUCCESS),
+ { 0, NULL }
+};
+
+struct osmo_tdef_state_timeout gmm_rau_tdef_states[32] = {
+};
+
+struct osmo_tdef gmm_rau_tdefs[] = {
+ // { .T = 3350, .default_val = 6, .desc = "Attach/RAU Complete Reallocation
procedure" },
+ { /* terminator */ }
+};
+
+/* Terminate reason, used by osmo_fsm_term as data */
+char *fsm_term_rau_att_req = "Attach Req Rx while in RAU";
+char *fsm_term_att_req_chg = "Attach Req Changed";
+char *fsm_term_att_rej = "Attach Rej";
+char *fsm_term_att_success = "Attach Success";
+char *fsm_term_rau_req_chg = "RAU Req Changed";
+char *fsm_term_rau_rej = "RAU Rej";
+char *fsm_term_rau_success = "RAU Success";
+
+static inline struct sgsn_mm_ctx *gmm_rau_fsm_priv(struct osmo_fsm_inst *fi)
+{
+ return (struct sgsn_mm_ctx *) fi->priv;
+}
+
+
+static void gmm_rau_fsm_s_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct sgsn_mm_ctx *mmctx = gmm_rau_fsm_priv(fi);
+
+ switch (event) {
+ case GMM_RAU_E_UE_RAU_REQUEST:
+ mmctx->vsub->lu_fsm = vlr_ra_update(
+ mmctx->attach_rau.rau_fsm, GMM_RAU_E_VLR_TERM_SUCCESS, GMM_RAU_E_VLR_TERM_FAIL,
NULL,
+ sgsn->vlr,
+ mmctx,
+ mmctx->attach_rau.rau_type,
+ mmctx->p_tmsi,
+ mmctx->imsi,
+ &mmctx->attach_rau.old_rai,
+ &mmctx->ra,
+ sgsn->cfg.auth_policy == SGSN_AUTH_POLICY_REMOTE,
+ mmctx->ciph_algo != GPRS_ALGO_GEA0,
+ mmctx->ciph_algo != GPRS_ALGO_GEA0,
+ mmctx->attach_rau.cksq,
+ sgsn_mm_ctx_is_r99(mmctx),
+ mmctx->ran_type == MM_CTX_T_UTRAN_Iu,
+ true);
+
+ osmo_tdef_fsm_inst_state_chg(fi, GMM_RAU_S_WAIT_VLR_ANSWER, gmm_rau_tdef_states,
gmm_rau_tdefs, 0);
+ osmo_fsm_inst_dispatch(mmctx->gmm_fsm, E_GMM_COMMON_PROC_INIT_REQ, NULL);
+ break;
+ default:
+ OSMO_ASSERT(0);
+ break;
+ }
+}
+
+static void transmit_rau_accept(struct sgsn_mm_ctx *mmctx)
+{
+ switch (mmctx->attach_rau.rau_type) {
+ case VLR_LU_TYPE_PERIODIC:
+ case VLR_LU_TYPE_REGULAR:
+ gsm48_tx_gmm_ra_upd_ack(mmctx);
+ break;
+ case VLR_LU_TYPE_IMSI_ATTACH:
+ gsm48_tx_gmm_att_ack(mmctx);
+ break;
+ }
+
+}
+
+static void transmit_rau_reject(struct sgsn_mm_ctx *mmctx, uint8_t gmm_cause)
+{
+ if (gmm_cause == 0)
+ gmm_cause = GMM_CAUSE_PROTO_ERR_UNSPEC;
+
+ switch (mmctx->attach_rau.rau_type) {
+ case VLR_LU_TYPE_PERIODIC:
+ case VLR_LU_TYPE_REGULAR:
+ gsm48_tx_gmm_ra_upd_rej(mmctx, gmm_cause);
+ break;
+ case VLR_LU_TYPE_IMSI_ATTACH:
+ gsm48_tx_gmm_att_rej(mmctx, gmm_cause);
+ break;
+ default:
+ OSMO_ASSERT(0);
+ }
+}
+
+static void gmm_rau_fsm_s_wait_vlr(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct sgsn_mm_ctx *mmctx = gmm_rau_fsm_priv(fi);
+ uint8_t gmm_cause;
+
+ switch (event) {
+ case GMM_RAU_E_UE_RAU_REQUEST:
+ /* same RAU, a different RAU would terminate this FSM */
+ break;
+ case GMM_RAU_E_VLR_RAU_ACCEPT:
+ transmit_rau_accept(mmctx);
+ osmo_tdef_fsm_inst_state_chg(fi, GMM_RAU_S_WAIT_UE_RAU_COMPLETE, gmm_rau_tdef_states,
gmm_rau_tdefs, 0);
+ break;
+ case GMM_RAU_E_VLR_RAU_REJECT:
+ gmm_cause = (uint8_t) ((long) data & 0xff);
+ transmit_rau_reject(mmctx, gmm_cause);
+ break;
+ case GMM_RAU_E_VLR_TERM_FAIL:
+ osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, data);
+ break;
+ case GMM_RAU_E_VLR_TERM_SUCCESS:
+ break;
+ default:
+ OSMO_ASSERT(0);
+ break;
+ }
+}
+
+static void gmm_rau_fsm_s_wait_ue_rau_compl(struct osmo_fsm_inst *fi, uint32_t event,
void *data)
+{
+ struct sgsn_mm_ctx *mmctx = gmm_rau_fsm_priv(fi);
+ uint8_t cause;
+
+ switch (event) {
+ case GMM_RAU_E_UE_RAU_COMPLETE:
+ /* inform the VLR */
+ if (mmctx->vsub)
+ vlr_subscr_rx_rau_complete(mmctx->vsub);
+
+ /* We need to wait for the VLR/LU FSM to terminate */
+ break;
+ case GMM_RAU_E_VLR_TERM_SUCCESS:
+ osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);
+ break;
+ case GMM_RAU_E_VLR_TERM_FAIL:
+ osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
+ break;
+ case GMM_RAU_E_VLR_RAU_REJECT:
+ /* VLR timed out */
+ cause = ((long) data) & 0xff;
+ transmit_rau_reject(mmctx, cause);
+ osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, data);
+ break;
+ case GMM_RAU_E_VLR_RAU_ACCEPT:
+ case GMM_RAU_E_UE_RAU_REQUEST:
+ transmit_rau_accept(mmctx);
+ break;
+ default:
+ OSMO_ASSERT(0);
+ break;
+ }
+}
+static void gmm_attach_success(struct sgsn_mm_ctx *mmctx)
+{
+ struct sgsn_signal_data sig_data;
+
+ switch(mmctx->ran_type) {
+ case MM_CTX_T_UTRAN_Iu:
+ osmo_fsm_inst_dispatch(mmctx->iu.mm_state_fsm, E_PMM_PS_ATTACH, NULL);
+ break;
+ case MM_CTX_T_GERAN_Gb:
+ /* Unassign the old TLLI */
+ mmctx->gb.tlli = mmctx->gb.tlli_new;
+ gprs_llme_copy_key(mmctx, mmctx->gb.llme);
+ gprs_llgmm_assign(mmctx->gb.llme, TLLI_UNASSIGNED,
+ mmctx->gb.tlli_new);
+ osmo_fsm_inst_dispatch(mmctx->gb.mm_state_fsm, E_MM_GPRS_ATTACH, NULL);
+ break;
+ }
+
+ osmo_fsm_inst_dispatch(mmctx->gmm_fsm, E_GMM_ATTACH_SUCCESS, NULL);
+
+ memset(&sig_data, 0, sizeof(sig_data));
+ sig_data.mm = mmctx;
+ osmo_signal_dispatch(SS_SGSN, S_SGSN_ATTACH, &sig_data);
+}
+
+static void gmm_rau_success(struct sgsn_mm_ctx *mmctx)
+{
+ struct sgsn_signal_data sig_data;
+
+ switch(mmctx->ran_type) {
+ case MM_CTX_T_UTRAN_Iu:
+ osmo_fsm_inst_dispatch(mmctx->iu.mm_state_fsm, E_PMM_RA_UPDATE, NULL);
+ break;
+ case MM_CTX_T_GERAN_Gb:
+ /* Unassign the old TLLI */
+ mmctx->gb.tlli = mmctx->gb.tlli_new;
+ gprs_llgmm_assign(mmctx->gb.llme, TLLI_UNASSIGNED, mmctx->gb.tlli_new);
+ osmo_fsm_inst_dispatch(mmctx->gb.mm_state_fsm, E_MM_RA_UPDATE, NULL);
+ break;
+ }
+
+ osmo_fsm_inst_dispatch(mmctx->gmm_fsm, E_GMM_RAU_SUCCESS, NULL);
+
+ memset(&sig_data, 0, sizeof(sig_data));
+ sig_data.mm = mmctx;
+ osmo_signal_dispatch(SS_SGSN, S_SGSN_UPDATE, &sig_data);
+}
+
+static void gmm_rau_fsm_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause
cause)
+{
+ struct sgsn_mm_ctx *mmctx;
+ uint32_t event;
+
+ /* deregister ourselfs from MMCtx */
+ if (!fi->priv)
+ return;
+
+ mmctx = gmm_rau_fsm_priv(fi);
+ mmctx->attach_rau.rau_fsm = NULL;
+ fi->priv = NULL;
+
+ switch (cause) {
+ case OSMO_FSM_TERM_REGULAR:
+ /* Successful Attach or RAU */
+ switch (mmctx->attach_rau.rau_type) {
+ case VLR_LU_TYPE_IMSI_ATTACH:
+ gmm_attach_success(mmctx);
+ break;
+ case VLR_LU_TYPE_REGULAR:
+ case VLR_LU_TYPE_PERIODIC:
+ gmm_rau_success(mmctx);
+ break;
+ }
+
+ break;
+ case OSMO_FSM_TERM_ERROR:
+ case OSMO_FSM_TERM_TIMEOUT:
+ event = E_GMM_COMMON_PROC_FAILED;
+ if (mmctx->attach_rau.rau_type == VLR_LU_TYPE_IMSI_ATTACH)
+ event = E_GMM_ATTACH_FAILED;
+
+ osmo_fsm_inst_dispatch(mmctx->gmm_fsm, event, NULL);
+ break;
+ case OSMO_FSM_TERM_REQUEST:
+ /* Called when another Att/Rau Request received with different context, silenty
terminate and wait for re-creation */
+ break;
+ default:
+ break;
+ }
+
+ TALLOC_FREE(mmctx->attach_rau.req);
+ memset(&mmctx->attach_rau, 0, sizeof(mmctx->attach_rau));
+}
+
+static const struct osmo_fsm_state gmm_rau_fsm_states[] = {
+ [GMM_RAU_S_INIT] = {
+ .in_event_mask = S(GMM_RAU_E_UE_RAU_REQUEST),
+ .out_state_mask = S(GMM_RAU_S_WAIT_VLR_ANSWER),
+ .name = OSMO_STRINGIFY(GMM_RAU_S_INIT),
+ .action = gmm_rau_fsm_s_init,
+ },
+ [GMM_RAU_S_WAIT_VLR_ANSWER] = {
+ .in_event_mask = S(GMM_RAU_E_UE_RAU_REQUEST) | S(GMM_RAU_E_VLR_RAU_ACCEPT) |
S(GMM_RAU_E_VLR_RAU_REJECT) | S(GMM_RAU_E_VLR_TERM_SUCCESS)| S(GMM_RAU_E_VLR_TERM_FAIL),
+ .out_state_mask = S(GMM_RAU_S_WAIT_UE_RAU_COMPLETE),
+ .name = OSMO_STRINGIFY(GMM_RAU_S_WAIT_VLR_ANSWER),
+ .action = gmm_rau_fsm_s_wait_vlr,
+ },
+ [GMM_RAU_S_WAIT_UE_RAU_COMPLETE] = {
+ .in_event_mask = S(GMM_RAU_E_UE_RAU_COMPLETE) | S(GMM_RAU_E_VLR_RAU_REJECT) |
S(GMM_RAU_E_VLR_RAU_ACCEPT) | S(GMM_RAU_E_UE_RAU_REQUEST) | S(GMM_RAU_E_VLR_TERM_SUCCESS)|
S(GMM_RAU_E_VLR_TERM_FAIL),
+ .out_state_mask = 0,
+ .name = OSMO_STRINGIFY(GMM_RAU_S_WAIT_UE_RAU_COMPLETE),
+ .action = gmm_rau_fsm_s_wait_ue_rau_compl,
+ },
+};
+
+static struct osmo_fsm gmm_rau_fsm = {
+ .name = "gmm_rau_fsm",
+ .states = gmm_rau_fsm_states,
+ .num_states = ARRAY_SIZE(gmm_rau_fsm_states),
+ .allstate_event_mask = 0,
+ .allstate_action = NULL,
+ .log_subsys = DLGLOBAL,
+ .event_names = gmm_rau_event_names,
+ .cleanup = gmm_rau_fsm_cleanup,
+ .pre_term = NULL,
+ .timer_cb = NULL,
+};
+
+void gmm_rau_fsm_req(struct sgsn_mm_ctx *mmctx)
+{
+ OSMO_ASSERT(!mmctx->attach_rau.rau_fsm);
+
+ mmctx->attach_rau.rau_fsm = osmo_fsm_inst_alloc(&gmm_rau_fsm, mmctx, mmctx,
LOGL_INFO, NULL);
+
+ osmo_fsm_inst_dispatch(mmctx->attach_rau.rau_fsm, GMM_RAU_E_UE_RAU_REQUEST, NULL);
+}
+
+static __attribute__((constructor)) void gmm_rau_fsm_init()
+{
+ OSMO_ASSERT(osmo_fsm_register(&gmm_rau_fsm) == 0);
+}
diff --git a/src/sgsn/gprs_subscriber.c b/src/sgsn/gprs_subscriber.c
index 07ea4c2..e69de29 100644
--- a/src/sgsn/gprs_subscriber.c
+++ b/src/sgsn/gprs_subscriber.c
@@ -1,966 +0,0 @@
-/* MS subscriber data handling */
-
-/* (C) 2014 by sysmocom s.f.m.c. GmbH
- * (C) 2015 by Holger Hans Peter Freyther
- *
- * 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/>.
- *
- */
-
-#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
-#include <osmocom/gsm/gsup.h>
-#include <osmocom/gsm/apn.h>
-#include <osmocom/gsm/ipa.h>
-#include <osmocom/core/utils.h>
-#include <osmocom/core/logging.h>
-#include <osmocom/sgsn/gprs_subscriber.h>
-#include <osmocom/gsupclient/gsup_client.h>
-
-#include <osmocom/sgsn/sgsn.h>
-#include <osmocom/sgsn/mmctx.h>
-#include <osmocom/sgsn/gprs_gmm.h>
-#include <osmocom/sgsn/gprs_utils.h>
-
-#include <osmocom/sgsn/debug.h>
-
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <limits.h>
-
-#define SGSN_SUBSCR_MAX_RETRIES 3
-#define SGSN_SUBSCR_RETRY_INTERVAL 10
-
-#define LOGGSUPP(level, gsup, fmt, args...) \
- LOGP(DGPRS, level, "GSUP(%s) " fmt, \
- (gsup)->imsi, \
- ## args)
-
-LLIST_HEAD(_gprs_subscribers);
-struct llist_head * const gprs_subscribers = &_gprs_subscribers;
-
-static int gsup_read_cb(struct osmo_gsup_client *gsupc, struct msgb *msg);
-
-/* TODO: Some functions are specific to the SGSN, but this file is more general
- * (it has gprs_* name). Either move these functions elsewhere, split them and
- * move a part, or replace the gprs_ prefix by sgsn_. The applies to
- * gprs_subscr_init, gsup_read_cb, and gprs_subscr_tx_gsup_message.
- */
-
-int gprs_subscr_init(struct sgsn_instance *sgi)
-{
- const char *addr_str;
- struct ipaccess_unit *ipa_dev;
-
- if (!sgi->cfg.gsup_server_addr.sin_addr.s_addr)
- return 0;
-
- addr_str = inet_ntoa(sgi->cfg.gsup_server_addr.sin_addr);
-
- ipa_dev = talloc_zero(sgi, struct ipaccess_unit);
- ipa_dev->unit_name = "SGSN";
- ipa_dev->serno = sgi->cfg.sgsn_ipa_name; /* NULL unless configured via VTY */
-
- sgi->gsup_client = osmo_gsup_client_create2(
- sgi,
- ipa_dev,
- addr_str, sgi->cfg.gsup_server_port,
- &gsup_read_cb,
- &sgi->cfg.oap);
-
- if (!sgi->gsup_client)
- return -1;
-
- return 1;
-}
-
-static int gsup_read_cb(struct osmo_gsup_client *gsupc, struct msgb *msg)
-{
- int rc;
-
- rc = gprs_subscr_rx_gsup_message(msg);
- msgb_free(msg);
- if (rc < 0)
- return -1;
-
- return rc;
-}
-
-int gprs_subscr_purge(struct gprs_subscr *subscr);
-
-static struct sgsn_subscriber_data *sgsn_subscriber_data_alloc(void *ctx)
-{
- struct sgsn_subscriber_data *sdata;
- int idx;
-
- sdata = talloc_zero(ctx, struct sgsn_subscriber_data);
-
- sdata->error_cause = SGSN_ERROR_CAUSE_NONE;
-
- for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++)
- sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL;
-
- INIT_LLIST_HEAD(&sdata->pdp_list);
-
- return sdata;
-}
-
-struct sgsn_subscriber_pdp_data* sgsn_subscriber_pdp_data_alloc(
- struct sgsn_subscriber_data *sdata)
-{
- struct sgsn_subscriber_pdp_data* pdata;
-
- pdata = talloc_zero(sdata, struct sgsn_subscriber_pdp_data);
-
- llist_add_tail(&pdata->list, &sdata->pdp_list);
-
- return pdata;
-}
-
-struct gprs_subscr *gprs_subscr_get_by_imsi(const char *imsi)
-{
- struct gprs_subscr *gsub;
-
- if (!imsi || !*imsi)
- return NULL;
-
- llist_for_each_entry(gsub, gprs_subscribers, entry) {
- if (!strcmp(gsub->imsi, imsi))
- return gprs_subscr_get(gsub);
- }
- return NULL;
-}
-
-static struct gprs_subscr *gprs_subscr_alloc(void)
-{
- struct gprs_subscr *gsub;
- gsub = talloc_zero(tall_sgsn_ctx, struct gprs_subscr);
- if (!gsub)
- return NULL;
- llist_add_tail(&gsub->entry, gprs_subscribers);
- gsub->use_count = 1;
- gsub->tmsi = GSM_RESERVED_TMSI;
- return gsub;
-}
-
-struct gprs_subscr *gprs_subscr_get_or_create(const char *imsi)
-{
- struct gprs_subscr *gsub;
-
- gsub = gprs_subscr_get_by_imsi(imsi);
- if (!gsub) {
- gsub = gprs_subscr_alloc();
- if (!gsub)
- return NULL;
- osmo_strlcpy(gsub->imsi, imsi, sizeof(gsub->imsi));
- }
-
- if (!gsub->sgsn_data)
- gsub->sgsn_data = sgsn_subscriber_data_alloc(gsub);
- return gsub;
-}
-
-void gprs_subscr_cleanup(struct gprs_subscr *subscr)
-{
- if (subscr->sgsn_data->mm) {
- gprs_subscr_put(subscr->sgsn_data->mm->subscr);
- subscr->sgsn_data->mm->subscr = NULL;
- subscr->sgsn_data->mm = NULL;
- }
-
- if (subscr->flags & GPRS_SUBSCRIBER_ENABLE_PURGE) {
- gprs_subscr_purge(subscr);
- subscr->flags &= ~GPRS_SUBSCRIBER_ENABLE_PURGE;
- }
-}
-
-void gprs_subscr_cancel(struct gprs_subscr *subscr)
-{
- subscr->authorized = 0;
- subscr->flags |= GPRS_SUBSCRIBER_CANCELLED;
- subscr->flags &= ~GPRS_SUBSCRIBER_ENABLE_PURGE;
-
- gprs_subscr_update(subscr);
- gprs_subscr_cleanup(subscr);
-}
-
-static int gprs_subscr_tx_gsup_message(struct gprs_subscr *subscr,
- struct osmo_gsup_message *gsup_msg)
-{
- struct msgb *msg = osmo_gsup_client_msgb_alloc();
-
- if (strlen(gsup_msg->imsi) == 0 && subscr)
- osmo_strlcpy(gsup_msg->imsi, subscr->imsi,
- sizeof(gsup_msg->imsi));
- gsup_msg->cn_domain = OSMO_GSUP_CN_DOMAIN_PS;
- osmo_gsup_encode(msg, gsup_msg);
-
- LOGGSUBSCRP(LOGL_INFO, subscr,
- "Sending GSUP, will send: %s\n", msgb_hexdump(msg));
-
- if (!sgsn->gsup_client) {
- msgb_free(msg);
- return -ENOTSUP;
- }
-
- return osmo_gsup_client_send(sgsn->gsup_client, msg);
-}
-
-static int gprs_subscr_tx_gsup_error_reply(struct gprs_subscr *subscr,
- struct osmo_gsup_message *gsup_orig,
- enum gsm48_gmm_cause cause)
-{
- struct osmo_gsup_message gsup_reply = {0};
-
- osmo_strlcpy(gsup_reply.imsi, gsup_orig->imsi,
- sizeof(gsup_reply.imsi));
- gsup_reply.cause = cause;
- gsup_reply.message_type =
- OSMO_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 gprs_subscr *subscr,
- struct osmo_gsup_message *gsup_msg)
-{
- unsigned idx;
- struct sgsn_subscriber_data *sdata = subscr->sgsn_data;
-
- LOGGSUBSCRP(LOGL_INFO, subscr,
- "Got SendAuthenticationInfoResult, num_auth_vectors = %zu\n",
- gsup_msg->num_auth_vectors);
-
- if (gsup_msg->num_auth_vectors > 0) {
- memset(sdata->auth_triplets, 0, sizeof(sdata->auth_triplets));
-
- for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++)
- sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL;
- }
-
- for (idx = 0; idx < gsup_msg->num_auth_vectors; idx++) {
- size_t key_seq = idx;
- LOGGSUBSCRP(LOGL_DEBUG, subscr,
- "Adding auth tuple, cksn = %zu\n", key_seq);
- if (key_seq >= ARRAY_SIZE(sdata->auth_triplets)) {
- LOGGSUBSCRP(LOGL_NOTICE, subscr,
- "Skipping auth triplet with invalid cksn %zu\n",
- key_seq);
- continue;
- }
- sdata->auth_triplets[key_seq].vec = gsup_msg->auth_vectors[idx];
- sdata->auth_triplets[key_seq].key_seq = key_seq;
- }
-
- sdata->auth_triplets_updated = 1;
- sdata->error_cause = SGSN_ERROR_CAUSE_NONE;
-
- gprs_subscr_update_auth_info(subscr);
-
- return 0;
-}
-
-static int gprs_subscr_pdp_data_clear(struct gprs_subscr *subscr)
-{
- struct sgsn_subscriber_pdp_data *pdp, *pdp2;
- int count = 0;
-
- llist_for_each_entry_safe(pdp, pdp2, &subscr->sgsn_data->pdp_list, list) {
- llist_del(&pdp->list);
- talloc_free(pdp);
- count += 1;
- }
-
- return count;
-}
-
-static struct sgsn_subscriber_pdp_data *gprs_subscr_pdp_data_get_by_id(
- struct gprs_subscr *subscr, unsigned context_id)
-{
- struct sgsn_subscriber_pdp_data *pdp;
-
- llist_for_each_entry(pdp, &subscr->sgsn_data->pdp_list, list) {
- if (pdp->context_id == context_id)
- return pdp;
- }
-
- return NULL;
-}
-
-
-static void gprs_subscr_gsup_insert_data(struct gprs_subscr *subscr,
- struct osmo_gsup_message *gsup_msg)
-{
- struct sgsn_subscriber_data *sdata = subscr->sgsn_data;
- unsigned idx;
- int rc;
-
- if (gsup_msg->msisdn_enc) {
- if (gsup_msg->msisdn_enc_len > sizeof(sdata->msisdn)) {
- LOGP(DGPRS, LOGL_ERROR, "MSISDN too long (%zu)\n",
- gsup_msg->msisdn_enc_len);
- sdata->msisdn_len = 0;
- } else {
- memcpy(sdata->msisdn, gsup_msg->msisdn_enc,
- gsup_msg->msisdn_enc_len);
- sdata->msisdn_len = gsup_msg->msisdn_enc_len;
- }
- }
-
- if (gsup_msg->hlr_enc) {
- if (gsup_msg->hlr_enc_len > sizeof(sdata->hlr)) {
- LOGP(DGPRS, LOGL_ERROR, "HLR-Number too long (%zu)\n",
- gsup_msg->hlr_enc_len);
- sdata->hlr_len = 0;
- } else {
- memcpy(sdata->hlr, gsup_msg->hlr_enc,
- gsup_msg->hlr_enc_len);
- sdata->hlr_len = gsup_msg->hlr_enc_len;
- }
- }
-
- if (gsup_msg->pdp_charg_enc && gsup_msg->pdp_charg_enc_len >=
sizeof(sdata->pdp_charg)) {
- memcpy(&sdata->pdp_charg, gsup_msg->pdp_charg_enc,
sizeof(sdata->pdp_charg));
- sdata->has_pdp_charg = 1;
- } else {
- sdata->has_pdp_charg = 0;
- }
-
- if (gsup_msg->pdp_info_compl) {
- rc = gprs_subscr_pdp_data_clear(subscr);
- if (rc > 0)
- LOGP(DGPRS, LOGL_INFO, "Cleared existing PDP info\n");
- }
-
- for (idx = 0; idx < gsup_msg->num_pdp_infos; idx++) {
- struct osmo_gsup_pdp_info *pdp_info = &gsup_msg->pdp_infos[idx];
- size_t ctx_id = pdp_info->context_id;
- struct sgsn_subscriber_pdp_data *pdp_data;
-
- if (pdp_info->apn_enc_len >= sizeof(pdp_data->apn_str)-1) {
- LOGGSUBSCRP(LOGL_ERROR, subscr,
- "APN too long, context id = %zu, APN = %s\n",
- ctx_id, osmo_hexdump(pdp_info->apn_enc,
- pdp_info->apn_enc_len));
- continue;
- }
-
- if (pdp_info->qos_enc_len > sizeof(pdp_data->qos_subscribed)) {
- LOGGSUBSCRP(LOGL_ERROR, subscr,
- "QoS info too long (%zu)\n",
- pdp_info->qos_enc_len);
- continue;
- }
-
- LOGGSUBSCRP(LOGL_INFO, subscr,
- "Will set PDP info, context id = %zu, APN = %s\n",
- ctx_id, osmo_hexdump(pdp_info->apn_enc, pdp_info->apn_enc_len));
-
- /* Set PDP info [ctx_id] */
- pdp_data = gprs_subscr_pdp_data_get_by_id(subscr, ctx_id);
- if (!pdp_data) {
- pdp_data = sgsn_subscriber_pdp_data_alloc(subscr->sgsn_data);
- pdp_data->context_id = ctx_id;
- }
-
- OSMO_ASSERT(pdp_data != NULL);
- pdp_data->pdp_type_org = pdp_info->pdp_type_org;
- pdp_data->pdp_type_nr = pdp_info->pdp_type_nr;
- osmo_apn_to_str(pdp_data->apn_str,
- pdp_info->apn_enc, pdp_info->apn_enc_len);
-
- if (pdp_info->qos_enc) {
- memcpy(&pdp_data->qos_subscribed[0], pdp_info->qos_enc,
- pdp_info->qos_enc_len);
- }
- pdp_data->qos_subscribed_len = pdp_info->qos_enc_len;
-
- if (pdp_info->pdp_charg_enc && pdp_info->pdp_charg_enc_len >=
sizeof(pdp_data->pdp_charg)) {
- memcpy(&pdp_data->pdp_charg, pdp_info->pdp_charg_enc,
sizeof(pdp_data->pdp_charg));
- pdp_data->has_pdp_charg = 1;
- } else {
- pdp_data->has_pdp_charg = 0;
- }
- }
-}
-
-static int gprs_subscr_handle_gsup_upd_loc_res(struct gprs_subscr *subscr,
- struct osmo_gsup_message *gsup_msg)
-{
- /* contrary to MAP, we allow piggy-backing subscriber data onto
- * the UPDATE LOCATION RESULT, and don't mandate the use of a
- * separate nested INSERT SUBSCRIBER DATA transaction */
- gprs_subscr_gsup_insert_data(subscr, gsup_msg);
-
- subscr->authorized = 1;
- subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
-
- subscr->flags |= GPRS_SUBSCRIBER_ENABLE_PURGE;
-
- gprs_subscr_update(subscr);
- return 0;
-}
-
-static int gprs_subscr_handle_gsup_dsd_req(struct gprs_subscr *subscr,
- struct osmo_gsup_message *gsup_msg)
-{
- struct osmo_gsup_message gsup_reply = {0};
-
- if (gsup_msg->cn_domain != OSMO_GSUP_CN_DOMAIN_PS) {
- LOGGSUBSCRP(LOGL_ERROR, subscr,
- "Rx GSUP message %s not supported for CS\n",
- osmo_gsup_message_type_name(gsup_msg->message_type));
- gsup_reply.cause = GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL;
- gsup_reply.message_type = OSMO_GSUP_MSGT_DELETE_DATA_ERROR;
- } else {
- gsm0408_gprs_access_cancelled(subscr->sgsn_data->mm,
- GMM_CAUSE_GPRS_NOTALLOWED);
- gsup_reply.message_type = OSMO_GSUP_MSGT_DELETE_DATA_RESULT;
- }
-
- return gprs_subscr_tx_gsup_message(subscr, &gsup_reply);
-}
-
-static int gprs_subscr_handle_gsup_isd_req(struct gprs_subscr *subscr,
- struct osmo_gsup_message *gsup_msg)
-{
- struct osmo_gsup_message gsup_reply = {0};
-
- gprs_subscr_gsup_insert_data(subscr, gsup_msg);
-
- subscr->authorized = 1;
- subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
- subscr->flags |= GPRS_SUBSCRIBER_ENABLE_PURGE;
- gprs_subscr_update(subscr);
-
- gsup_reply.message_type = OSMO_GSUP_MSGT_INSERT_DATA_RESULT;
- return gprs_subscr_tx_gsup_message(subscr, &gsup_reply);
-}
-
-static int check_cause(int cause)
-{
- switch (cause) {
- case GMM_CAUSE_IMSI_UNKNOWN ... GMM_CAUSE_ILLEGAL_ME:
- case GMM_CAUSE_GPRS_NOTALLOWED ... GMM_CAUSE_NO_GPRS_PLMN:
- return EACCES;
-
- case GMM_CAUSE_MSC_TEMP_NOTREACH ... GMM_CAUSE_CONGESTION:
- return EHOSTUNREACH;
-
- case GMM_CAUSE_SEM_INCORR_MSG ... GMM_CAUSE_PROTO_ERR_UNSPEC:
- default:
- return EINVAL;
- }
-}
-
-static int gprs_subscr_handle_gsup_auth_err(struct gprs_subscr *subscr,
- struct osmo_gsup_message *gsup_msg)
-{
- unsigned idx;
- struct sgsn_subscriber_data *sdata = subscr->sgsn_data;
- int cause_err;
-
- cause_err = check_cause(gsup_msg->cause);
-
- LOGGSUBSCRP(LOGL_DEBUG, subscr,
- "Send authentication info has failed with cause %d, "
- "handled as: %s\n",
- gsup_msg->cause, strerror(cause_err));
-
- switch (cause_err) {
- case EACCES:
- LOGGSUBSCRP(LOGL_NOTICE, subscr,
- "GPRS send auth info req failed, access denied, "
- "GMM cause = '%s' (%d)\n",
- get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
- gsup_msg->cause);
- /* Clear auth tuples */
- memset(sdata->auth_triplets, 0, sizeof(sdata->auth_triplets));
- for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++)
- sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL;
-
- subscr->authorized = 0;
- sdata->error_cause = gsup_msg->cause;
- gprs_subscr_update_auth_info(subscr);
- break;
-
- case EHOSTUNREACH:
- LOGGSUBSCRP(LOGL_NOTICE, subscr,
- "GPRS send auth info req failed, GMM cause = '%s' (%d)\n",
- get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
- gsup_msg->cause);
-
- sdata->error_cause = gsup_msg->cause;
- gprs_subscr_update_auth_info(subscr);
- break;
-
- default:
- case EINVAL:
- LOGGSUBSCRP(LOGL_ERROR, subscr,
- "GSUP protocol remote error, GMM cause = '%s' (%d)\n",
- get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
- gsup_msg->cause);
- sdata->error_cause = gsup_msg->cause;
- break;
- }
-
- return -gsup_msg->cause;
-}
-
-static int gprs_subscr_handle_gsup_upd_loc_err(struct gprs_subscr *subscr,
- struct osmo_gsup_message *gsup_msg)
-{
- int cause_err;
-
- cause_err = check_cause(gsup_msg->cause);
-
- LOGGSUBSCRP(LOGL_DEBUG, subscr,
- "Update location has failed with cause %d, handled as: %s\n",
- gsup_msg->cause, strerror(cause_err));
-
- switch (cause_err) {
- case EACCES:
- LOGGSUBSCRP(LOGL_NOTICE, subscr,
- "GPRS update location failed, access denied, "
- "GMM cause = '%s' (%d)\n",
- get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
- gsup_msg->cause);
-
- subscr->authorized = 0;
- subscr->sgsn_data->error_cause = gsup_msg->cause;
- gprs_subscr_update_auth_info(subscr);
- break;
-
- case EHOSTUNREACH:
- LOGGSUBSCRP(LOGL_NOTICE, subscr,
- "GPRS update location failed, GMM cause = '%s' (%d)\n",
- get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
- gsup_msg->cause);
-
- subscr->sgsn_data->error_cause = gsup_msg->cause;
- gprs_subscr_update_auth_info(subscr);
- break;
-
- default:
- case EINVAL:
- LOGGSUBSCRP(LOGL_ERROR, subscr,
- "GSUP protocol remote error, GMM cause = '%s' (%d)\n",
- get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
- gsup_msg->cause);
- break;
- }
-
- return -gsup_msg->cause;
-}
-
-static int gprs_subscr_handle_gsup_purge_no_subscr(
- struct osmo_gsup_message *gsup_msg)
-{
- if (OSMO_GSUP_IS_MSGT_ERROR(gsup_msg->message_type)) {
- LOGGSUPP(LOGL_NOTICE, gsup_msg,
- "Purge MS has failed with cause '%s' (%d)\n",
- get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
- gsup_msg->cause);
- return -gsup_msg->cause;
- }
-
- LOGGSUPP(LOGL_INFO, gsup_msg, "Completing purge MS\n");
- return 0;
-}
-
-static int gprs_subscr_handle_gsup_purge_res(struct gprs_subscr *subscr,
- struct osmo_gsup_message *gsup_msg)
-{
- LOGGSUBSCRP(LOGL_INFO, subscr, "Completing purge MS\n");
-
- /* Force silent cancellation */
- subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
- gprs_subscr_cancel(subscr);
-
- return 0;
-}
-
-static int gprs_subscr_handle_gsup_purge_err(struct gprs_subscr *subscr,
- struct osmo_gsup_message *gsup_msg)
-{
- LOGGSUBSCRP(LOGL_NOTICE, subscr,
- "Purge MS has failed with cause '%s' (%d)\n",
- get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
- gsup_msg->cause);
-
- /* In GSM 09.02, 19.1.4.4, the text and the SDL diagram imply that
- * the subscriber data is not removed if the request has failed. On the
- * other hand, keeping the subscriber data in either error case
- * (subscriber unknown, syntactical message error, connection error)
- * doesn't seem to give any advantage, since the data will be restored
- * on the next Attach Request anyway.
- * This approach ensures, that the subscriber record will not stick if
- * an error happens.
- */
-
- /* TODO: Check whether this behaviour is acceptable and either just
- * remove this TODO-notice or change the implementation to not delete
- * the subscriber data (eventually resetting the ENABLE_PURGE flag and
- * restarting the expiry timer based on the cause).
- *
- * Subscriber Unknown: cancel subscr
- * Temporary network problems: do nothing (handled by timer based retry)
- * Message problems (syntax, nyi, ...): cancel subscr (retry won't help)
- */
-
- gprs_subscr_handle_gsup_purge_res(subscr, gsup_msg);
-
- return -gsup_msg->cause;
-}
-
-static int gprs_subscr_handle_loc_cancel_req(struct gprs_subscr *subscr,
- struct osmo_gsup_message *gsup_msg)
-{
- struct osmo_gsup_message gsup_reply = {0};
- int is_update_procedure = !gsup_msg->cancel_type ||
- gsup_msg->cancel_type == OSMO_GSUP_CANCEL_TYPE_UPDATE;
-
- LOGGSUBSCRP(LOGL_INFO, subscr, "Cancelling MS subscriber (%s)\n",
- is_update_procedure ?
- "update procedure" : "subscription withdraw");
-
- gsup_reply.message_type = OSMO_GSUP_MSGT_LOCATION_CANCEL_RESULT;
- gprs_subscr_tx_gsup_message(subscr, &gsup_reply);
-
- if (is_update_procedure)
- subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
- else
- /* Since a withdraw cause is not specified, just abort the
- * current attachment. The following re-attachment should then
- * be rejected with a proper cause value.
- */
- subscr->sgsn_data->error_cause = GMM_CAUSE_IMPL_DETACHED;
-
- gprs_subscr_cancel(subscr);
-
- return 0;
-}
-
-static int gprs_subscr_handle_unknown_imsi(struct osmo_gsup_message *gsup_msg)
-{
- if (OSMO_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 (OSMO_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);
- size_t data_len = msgb_l2len(msg);
- int rc = 0;
-
- struct osmo_gsup_message gsup_msg = {0};
- struct gprs_subscr *subscr;
-
- rc = osmo_gsup_decode(data, data_len, &gsup_msg);
- if (rc < 0) {
- LOGP(DGPRS, LOGL_ERROR,
- "decoding GSUP message fails with error '%s' (%d)\n",
- get_value_string(gsm48_gmm_cause_names, -rc), -rc);
- return rc;
- }
-
- if (!gsup_msg.imsi[0]) {
- LOGP(DGPRS, LOGL_ERROR, "Missing IMSI in GSUP message\n");
-
- if (OSMO_GSUP_IS_MSGT_REQUEST(gsup_msg.message_type))
- gprs_subscr_tx_gsup_error_reply(NULL, &gsup_msg,
- GMM_CAUSE_INV_MAND_INFO);
- return -GMM_CAUSE_INV_MAND_INFO;
- }
-
- if (!gsup_msg.cause && OSMO_GSUP_IS_MSGT_ERROR(gsup_msg.message_type))
- gsup_msg.cause = GMM_CAUSE_NET_FAIL;
-
- subscr = gprs_subscr_get_by_imsi(gsup_msg.imsi);
-
- if (!subscr) {
- switch (gsup_msg.message_type) {
- case OSMO_GSUP_MSGT_PURGE_MS_RESULT:
- case OSMO_GSUP_MSGT_PURGE_MS_ERROR:
- return gprs_subscr_handle_gsup_purge_no_subscr(&gsup_msg);
- default:
- return gprs_subscr_handle_unknown_imsi(&gsup_msg);
- }
- }
-
- LOGGSUBSCRP(LOGL_INFO, subscr,
- "Received GSUP message %s\n",
- osmo_gsup_message_type_name(gsup_msg.message_type));
-
- switch (gsup_msg.message_type) {
- case OSMO_GSUP_MSGT_LOCATION_CANCEL_REQUEST:
- rc = gprs_subscr_handle_loc_cancel_req(subscr, &gsup_msg);
- break;
-
- case OSMO_GSUP_MSGT_SEND_AUTH_INFO_RESULT:
- rc = gprs_subscr_handle_gsup_auth_res(subscr, &gsup_msg);
- break;
-
- case OSMO_GSUP_MSGT_SEND_AUTH_INFO_ERROR:
- rc = gprs_subscr_handle_gsup_auth_err(subscr, &gsup_msg);
- break;
-
- case OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT:
- rc = gprs_subscr_handle_gsup_upd_loc_res(subscr, &gsup_msg);
- break;
-
- case OSMO_GSUP_MSGT_UPDATE_LOCATION_ERROR:
- rc = gprs_subscr_handle_gsup_upd_loc_err(subscr, &gsup_msg);
- break;
-
- case OSMO_GSUP_MSGT_PURGE_MS_ERROR:
- rc = gprs_subscr_handle_gsup_purge_err(subscr, &gsup_msg);
- break;
-
- case OSMO_GSUP_MSGT_PURGE_MS_RESULT:
- rc = gprs_subscr_handle_gsup_purge_res(subscr, &gsup_msg);
- break;
-
- case OSMO_GSUP_MSGT_INSERT_DATA_REQUEST:
- rc = gprs_subscr_handle_gsup_isd_req(subscr, &gsup_msg);
- break;
-
- case OSMO_GSUP_MSGT_DELETE_DATA_REQUEST:
- rc = gprs_subscr_handle_gsup_dsd_req(subscr, &gsup_msg);
- break;
-
- default:
- LOGGSUBSCRP(LOGL_ERROR, subscr,
- "Rx GSUP message %s not valid at SGSN\n",
- osmo_gsup_message_type_name(gsup_msg.message_type));
- if (OSMO_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;
- };
-
- gprs_subscr_put(subscr);
-
- return rc;
-}
-
-int gprs_subscr_purge(struct gprs_subscr *subscr)
-{
- struct sgsn_subscriber_data *sdata = subscr->sgsn_data;
- struct osmo_gsup_message gsup_msg = {0};
-
- LOGGSUBSCRP(LOGL_INFO, subscr, "purging MS subscriber\n");
-
- gsup_msg.message_type = OSMO_GSUP_MSGT_PURGE_MS_REQUEST;
-
- /* Provide the HLR number in case it is known */
- gsup_msg.hlr_enc_len = sdata->hlr_len;
- gsup_msg.hlr_enc = sdata->hlr;
-
- return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
-}
-
-static int gprs_subscr_query_auth_info(struct gprs_subscr *subscr,
- const uint8_t *auts,
- const uint8_t *auts_rand)
-{
- struct osmo_gsup_message gsup_msg = {0};
-
- /* Make sure we have a complete resync or clearly no resync. */
- OSMO_ASSERT((auts != NULL) == (auts_rand != NULL));
-
- LOGGSUBSCRP(LOGL_INFO, subscr, "requesting auth info%s\n",
- auts ? " with AUTS (UMTS Resynch)" : "");
-
- gsup_msg.message_type = OSMO_GSUP_MSGT_SEND_AUTH_INFO_REQUEST;
- gsup_msg.auts = auts;
- gsup_msg.rand = auts_rand;
- return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
-}
-
-int gprs_subscr_location_update(struct gprs_subscr *subscr, enum sgsn_ran_type ran_type)
-{
- struct osmo_gsup_message gsup_msg = {0};
-
- LOGGSUBSCRP(LOGL_INFO, subscr,
- "subscriber data is not available\n");
-
- gsup_msg.message_type = OSMO_GSUP_MSGT_UPDATE_LOCATION_REQUEST;
-
- switch (ran_type) {
- case MM_CTX_T_GERAN_Gb:
- gsup_msg.current_rat_type = OSMO_RAT_GERAN_A;
- break;
- case MM_CTX_T_UTRAN_Iu:
- gsup_msg.current_rat_type = OSMO_RAT_UTRAN_IU;
- break;
- default:
- break;
- }
-
- return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
-}
-
-void gprs_subscr_update(struct gprs_subscr *subscr)
-{
- LOGGSUBSCRP(LOGL_DEBUG, subscr, "Updating subscriber data\n");
-
- subscr->flags &= ~GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING;
- subscr->flags &= ~GPRS_SUBSCRIBER_FIRST_CONTACT;
-
- if (subscr->sgsn_data->mm)
- sgsn_update_subscriber_data(subscr->sgsn_data->mm);
-}
-
-void gprs_subscr_update_auth_info(struct gprs_subscr *subscr)
-{
- LOGGSUBSCRP(LOGL_DEBUG, subscr,
- "Updating subscriber authentication info\n");
-
- subscr->flags &= ~GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING;
- subscr->flags &= ~GPRS_SUBSCRIBER_FIRST_CONTACT;
-
- if (subscr->sgsn_data->mm)
- sgsn_update_subscriber_data(subscr->sgsn_data->mm);
-}
-
-struct gprs_subscr *gprs_subscr_get_or_create_by_mmctx(struct sgsn_mm_ctx *mmctx)
-{
- struct gprs_subscr *subscr = NULL;
-
- if (mmctx->subscr)
- return gprs_subscr_get(mmctx->subscr);
-
- if (mmctx->imsi[0])
- subscr = gprs_subscr_get_by_imsi(mmctx->imsi);
-
- if (!subscr) {
- subscr = gprs_subscr_get_or_create(mmctx->imsi);
- if (!subscr)
- return NULL;
- subscr->flags |= GPRS_SUBSCRIBER_FIRST_CONTACT;
- subscr->flags &= ~GPRS_SUBSCRIBER_ENABLE_PURGE;
- }
-
- osmo_strlcpy(subscr->imei, mmctx->imei, sizeof(subscr->imei));
-
- if (subscr->lac != mmctx->ra.lac.lac)
- subscr->lac = mmctx->ra.lac.lac;
-
- subscr->sgsn_data->mm = mmctx;
- mmctx->subscr = gprs_subscr_get(subscr);
-
- return subscr;
-}
-
-int gprs_subscr_request_update_location(struct sgsn_mm_ctx *mmctx)
-{
- struct gprs_subscr *subscr = NULL;
- int rc;
-
- LOGMMCTXP(LOGL_DEBUG, mmctx, "Requesting subscriber data update\n");
-
- subscr = gprs_subscr_get_or_create_by_mmctx(mmctx);
- if (!subscr)
- return -ENOMEM;
-
- subscr->flags |= GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING;
-
- rc = gprs_subscr_location_update(subscr, mmctx->ran_type);
- gprs_subscr_put(subscr);
- return rc;
-}
-
-/*! \brief Send Update Auth Info request via GSUP, with or without resync.
- * \param[in] mmctx MM context to request authentication tuples for.
- * \param[in] auts 14 octet AUTS token for UMTS resync, or NULL.
- * \param[in] auts_rand 16 octet Random token for UMTS resync, or NULL.
- * In case of normal Authentication Info request, both \a auts and \a auts_rand
- * must be NULL. For resync, both must be non-NULL.
- */
-int gprs_subscr_request_auth_info(struct sgsn_mm_ctx *mmctx,
- const uint8_t *auts,
- const uint8_t *auts_rand)
-{
- struct gprs_subscr *subscr = NULL;
- int rc;
-
- LOGMMCTXP(LOGL_DEBUG, mmctx, "Requesting subscriber authentication info\n");
-
- subscr = gprs_subscr_get_or_create_by_mmctx(mmctx);
- if (!subscr)
- return -ENOMEM;
-
- subscr->flags |= GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING;
-
- rc = gprs_subscr_query_auth_info(subscr, auts, auts_rand);
- gprs_subscr_put(subscr);
- return rc;
-}
-
-static void gprs_subscr_free(struct gprs_subscr *gsub)
-{
- llist_del(&gsub->entry);
- talloc_free(gsub);
-}
-
-struct gprs_subscr *_gprs_subscr_get(struct gprs_subscr *gsub,
- const char *file, int line)
-{
- OSMO_ASSERT(gsub->use_count < INT_MAX);
- gsub->use_count++;
- LOGPSRC(DREF, LOGL_DEBUG, file, line,
- "subscr %s usage increases to: %d\n",
- gsub->imsi, gsub->use_count);
- return gsub;
-}
-
-struct gprs_subscr *_gprs_subscr_put(struct gprs_subscr *gsub,
- const char *file, int line)
-{
- gsub->use_count--;
- LOGPSRC(DREF, gsub->use_count >= 0? LOGL_DEBUG : LOGL_ERROR,
- file, line,
- "subscr %s usage decreases to: %d%s\n",
- gsub->imsi, gsub->use_count,
- gsub->keep_in_ram? ", keep-in-ram flag is set" : "");
- if (gsub->use_count > 0)
- return gsub;
- if (gsub->keep_in_ram)
- return gsub;
- gprs_subscr_free(gsub);
- return NULL;
-}
diff --git a/src/sgsn/mmctx.c b/src/sgsn/mmctx.c
index 40f902b..f314425 100644
--- a/src/sgsn/mmctx.c
+++ b/src/sgsn/mmctx.c
@@ -56,6 +56,9 @@
#include <osmocom/sgsn/gtp.h>
#include <osmocom/sgsn/pdpctx.h>
+#include <osmocom/vlr/vlr.h>
+#include <osmocom/gsupclient/gsup_client_mux.h>
+
#include <time.h>
#include "../../config.h"
@@ -204,9 +207,6 @@
ctx->gmm_fsm = osmo_fsm_inst_alloc(&gmm_fsm, ctx, ctx, LOGL_DEBUG,
"gmm_fsm");
if (!ctx->gmm_fsm)
goto out;
- ctx->gmm_att_req.fsm = osmo_fsm_inst_alloc(&gmm_attach_req_fsm, ctx, ctx,
LOGL_DEBUG, "gb_gmm_req");
- if (!ctx->gmm_att_req.fsm)
- goto out;
ctx->gb.mm_state_fsm = osmo_fsm_inst_alloc(&mm_state_gb_fsm, ctx, ctx,
LOGL_DEBUG, NULL);
if (!ctx->gb.mm_state_fsm)
goto out;
@@ -281,7 +281,6 @@
#endif
}
-
/* this is a hard _free_ function, it doesn't clean up the PDP contexts
* in libgtp! */
static void sgsn_mm_ctx_free(struct sgsn_mm_ctx *mm)
@@ -306,6 +305,12 @@
struct sgsn_pdp_ctx *pdp, *pdp2;
struct sgsn_signal_data sig_data;
+ if (mm->vsub) {
+ vlr_subscr_disconnected(mm->vsub);
+ vlr_subscr_put(mm->vsub, "mmctx");
+ mm->vsub = NULL;
+ }
+
if (mm->ran_type == MM_CTX_T_GERAN_Gb)
llme = mm->gb.llme;
else
@@ -334,23 +339,19 @@
memset(&sig_data, 0, sizeof(sig_data));
sig_data.mm = mm;
osmo_signal_dispatch(SS_SGSN, S_SGSN_MM_FREE, &sig_data);
-
-
- /* Detach from subscriber which is possibly freed then */
- if (mm->subscr) {
- struct gprs_subscr *subscr = gprs_subscr_get(mm->subscr);
- gprs_subscr_cleanup(subscr);
- gprs_subscr_put(subscr);
+ if (mm->vsub) {
+ vlr_subscr_expire(mm->vsub);
+ vlr_subscr_disconnected(mm->vsub);
+ vlr_subscr_put(mm->vsub, "mmctx");
+ mm->vsub = NULL;
}
- if (mm->gmm_att_req.fsm)
- gmm_att_req_free(mm);
if (mm->gb.mm_state_fsm)
osmo_fsm_inst_free(mm->gb.mm_state_fsm);
if (mm->iu.mm_state_fsm)
osmo_fsm_inst_free(mm->iu.mm_state_fsm);
if (mm->gmm_fsm)
- osmo_fsm_inst_free(mm->gmm_fsm);
+ osmo_fsm_inst_term(mm->gmm_fsm, OSMO_FSM_TERM_REGULAR, NULL);
sgsn_mm_ctx_free(mm);
mm = NULL;
@@ -439,14 +440,6 @@
return GSM_RESERVED_TMSI;
}
-void sgsn_update_subscriber_data(struct sgsn_mm_ctx *mmctx)
-{
- OSMO_ASSERT(mmctx != NULL);
- LOGMMCTXP(LOGL_INFO, mmctx, "Subscriber data update\n");
-
- sgsn_auth_update(mmctx);
-}
-
static void insert_extra(struct tlv_parsed *tp,
struct sgsn_subscriber_data *data,
struct sgsn_subscriber_pdp_data *pdp)
@@ -498,6 +491,7 @@
req_apn_str[0] = 0;
}
+ /* FIXME: why should the vsub ever be NULL? */
if (mmctx->subscr == NULL)
allow_any_apn = 1;
@@ -608,3 +602,23 @@
return true;
return false;
}
+
+int sgsn_mm_ctx_bind_vsub(struct sgsn_mm_ctx *mm, const char *imsi, uint32_t ptmsi)
+{
+ bool created = false;
+
+ if (imsi)
+ mm->vsub = vlr_subscr_find_or_create_by_imsi(sgsn->vlr, imsi, "mmctx",
&created);
+ else
+ mm->vsub = vlr_subscr_find_or_create_by_tmsi(sgsn->vlr, ptmsi, "mmctx",
&created);
+
+ if (!mm->vsub)
+ return -1;
+
+ /* FIXME: copy more stuff from vsub */
+ if (!strlen(mm->imsi) && strlen(mm->vsub->imsi)) {
+ OSMO_STRLCPY_ARRAY(mm->imsi, mm->vsub->imsi);
+ }
+
+ return 0;
+}
diff --git a/src/sgsn/sgsn.c b/src/sgsn/sgsn.c
index 4ebba26..fdc52be 100644
--- a/src/sgsn/sgsn.c
+++ b/src/sgsn/sgsn.c
@@ -59,6 +59,8 @@
#include <osmocom/sgsn/pdpctx.h>
#include <osmocom/sgsn/gprs_routing_area.h>
+#include <osmocom/vlr/vlr.h>
+
#include <time.h>
#define GPRS_LLME_CHECK_TICK 30
@@ -188,9 +190,9 @@
osmo_timer_setup(&inst->llme_timer, sgsn_llme_check_cb, NULL);
osmo_timer_schedule(&inst->llme_timer, GPRS_LLME_CHECK_TICK, 0);
/* These are mostly setting up stuff not related to VTY cfg, so they can be set up here:
*/
- sgsn_auth_init(inst);
sgsn_cdr_init(inst);
sgsn_ra_init(inst);
+ sgsn_auth_init(inst);
return inst;
}
@@ -213,10 +215,11 @@
return -EFAULT;
}
- rc = gprs_subscr_init(sgsn);
+ rc = gmm_vlr_init(sgsn);
if (rc < 0) {
- LOGP(DGPRS, LOGL_FATAL, "Cannot set up SGSN\n");
+ LOGP(DGPRS, LOGL_FATAL, "Cannot set up MM/VLR/GSUP\n");
return rc;
}
+
return 0;
}
diff --git a/src/sgsn/sgsn_auth.c b/src/sgsn/sgsn_auth.c
index 2f5bc8c..ab94857 100644
--- a/src/sgsn/sgsn_auth.c
+++ b/src/sgsn/sgsn_auth.c
@@ -84,229 +84,3 @@
return 0;
}
-enum sgsn_auth_state sgsn_auth_state(struct sgsn_mm_ctx *mmctx)
-{
- char mccmnc[16];
- int check_net = 0;
- int check_acl = 0;
-
- OSMO_ASSERT(mmctx);
-
- switch (sgsn->cfg.auth_policy) {
- case SGSN_AUTH_POLICY_OPEN:
- return SGSN_AUTH_ACCEPTED;
-
- case SGSN_AUTH_POLICY_CLOSED:
- check_net = 1;
- check_acl = 1;
- break;
-
- case SGSN_AUTH_POLICY_ACL_ONLY:
- check_acl = 1;
- break;
-
- case SGSN_AUTH_POLICY_REMOTE:
- if (!mmctx->subscr)
- return mmctx->auth_state;
-
- if (mmctx->subscr->flags & GPRS_SUBSCRIBER_UPDATE_PENDING_MASK)
- return mmctx->auth_state;
-
- if (sgsn->cfg.require_authentication &&
- (!sgsn_mm_ctx_is_authenticated(mmctx) ||
- mmctx->subscr->sgsn_data->auth_triplets_updated))
- return SGSN_AUTH_AUTHENTICATE;
-
- if (mmctx->subscr->authorized)
- return SGSN_AUTH_ACCEPTED;
-
- return SGSN_AUTH_REJECTED;
- }
-
- if (!strlen(mmctx->imsi)) {
- LOGMMCTXP(LOGL_NOTICE, mmctx,
- "Missing IMSI, authorization state not known\n");
- return SGSN_AUTH_UNKNOWN;
- }
-
- if (check_net) {
- /* We simply assume that the IMSI exists, as long as it is part
- * of 'our' network */
- snprintf(mccmnc, sizeof(mccmnc), "%s%s",
- osmo_mcc_name(mmctx->ra.lac.plmn.mcc),
- osmo_mnc_name(mmctx->ra.lac.plmn.mnc, mmctx->ra.lac.plmn.mnc_3_digits));
- if (strncmp(mccmnc, mmctx->imsi, mmctx->ra.lac.plmn.mnc_3_digits ? 6 : 5) == 0)
- return SGSN_AUTH_ACCEPTED;
- }
-
- if (check_acl && sgsn_acl_lookup(mmctx->imsi, &sgsn->cfg))
- return SGSN_AUTH_ACCEPTED;
-
- return SGSN_AUTH_REJECTED;
-}
-
-/*
- * This function is directly called by e.g. the GMM layer. It returns either
- * after calling sgsn_auth_update directly or after triggering an asynchronous
- * procedure which will call sgsn_auth_update later on.
- */
-int sgsn_auth_request(struct sgsn_mm_ctx *mmctx)
-{
- struct gprs_subscr *subscr;
- struct gsm_auth_tuple *at;
- int need_update_location;
- int rc;
-
- LOGMMCTXP(LOGL_DEBUG, mmctx, "Requesting authorization\n");
-
- if (sgsn->cfg.auth_policy != SGSN_AUTH_POLICY_REMOTE) {
- sgsn_auth_update(mmctx);
- return 0;
- }
-
- need_update_location = sgsn->cfg.require_update_location &&
- (mmctx->subscr == NULL ||
- mmctx->pending_req == GSM48_MT_GMM_ATTACH_REQ);
-
- /* This has the side effect of registering the subscr with the mmctx */
- subscr = gprs_subscr_get_or_create_by_mmctx(mmctx);
- gprs_subscr_put(subscr);
-
- OSMO_ASSERT(mmctx->subscr != NULL);
-
- if (sgsn->cfg.require_authentication && !sgsn_mm_ctx_is_authenticated(mmctx))
{
- /* Find next tuple */
- at = sgsn_auth_get_tuple(mmctx, mmctx->auth_triplet.key_seq);
-
- if (!at) {
- /* No valid tuple found, request fresh ones */
- mmctx->auth_triplet.key_seq = GSM_KEY_SEQ_INVAL;
- LOGMMCTXP(LOGL_INFO, mmctx,
- "Requesting authentication tuples\n");
- rc = gprs_subscr_request_auth_info(mmctx, NULL, NULL);
- if (rc >= 0)
- return 0;
-
- return rc;
- }
-
- mmctx->auth_triplet = *at;
- } else if (need_update_location) {
- LOGMMCTXP(LOGL_INFO, mmctx,
- "Missing information, requesting subscriber data\n");
- rc = gprs_subscr_request_update_location(mmctx);
- if (rc >= 0)
- return 0;
-
- return rc;
- }
-
- sgsn_auth_update(mmctx);
- return 0;
-}
-
-void sgsn_auth_update(struct sgsn_mm_ctx *mmctx)
-{
- enum sgsn_auth_state auth_state;
- struct gprs_subscr *subscr = mmctx->subscr;
- struct gsm_auth_tuple *at;
- int gmm_cause;
-
- auth_state = sgsn_auth_state(mmctx);
-
- LOGMMCTXP(LOGL_DEBUG, mmctx, "Updating authorization (%s -> %s)\n",
- get_value_string(sgsn_auth_state_names, mmctx->auth_state),
- get_value_string(sgsn_auth_state_names, auth_state));
-
- if (auth_state == SGSN_AUTH_UNKNOWN && subscr &&
- !(subscr->flags & GPRS_SUBSCRIBER_UPDATE_PENDING_MASK)) {
- /* Reject requests if gprs_subscr_request_update_location fails */
- LOGMMCTXP(LOGL_ERROR, mmctx,
- "Missing information, authorization not possible\n");
- auth_state = SGSN_AUTH_REJECTED;
- }
-
- if (auth_state == SGSN_AUTH_AUTHENTICATE &&
- mmctx->auth_triplet.key_seq == GSM_KEY_SEQ_INVAL) {
- /* The current tuple is not valid, but we are possibly called
- * because new auth tuples have been received */
- at = sgsn_auth_get_tuple(mmctx, mmctx->auth_triplet.key_seq);
- if (!at) {
- LOGMMCTXP(LOGL_ERROR, mmctx,
- "Missing auth tuples, authorization not possible\n");
- auth_state = SGSN_AUTH_REJECTED;
- } else {
- mmctx->auth_triplet = *at;
- }
- }
-
- if (mmctx->auth_state == auth_state)
- return;
-
- LOGMMCTXP(LOGL_INFO, mmctx, "Got authorization update: state %s -> %s\n",
- get_value_string(sgsn_auth_state_names, mmctx->auth_state),
- get_value_string(sgsn_auth_state_names, auth_state));
-
- mmctx->auth_state = auth_state;
-
- switch (auth_state) {
- case SGSN_AUTH_AUTHENTICATE:
- if (subscr)
- subscr->sgsn_data->auth_triplets_updated = 0;
-
- gsm0408_gprs_authenticate(mmctx);
- break;
- case SGSN_AUTH_ACCEPTED:
- gsm0408_gprs_access_granted(mmctx);
- break;
- case SGSN_AUTH_REJECTED:
- gmm_cause =
- subscr ? subscr->sgsn_data->error_cause :
- SGSN_ERROR_CAUSE_NONE;
-
- if (subscr && (subscr->flags & GPRS_SUBSCRIBER_CANCELLED) != 0)
- gsm0408_gprs_access_cancelled(mmctx, gmm_cause);
- else
- gsm0408_gprs_access_denied(mmctx, gmm_cause);
- break;
- default:
- break;
- }
-}
-
-struct gsm_auth_tuple *sgsn_auth_get_tuple(struct sgsn_mm_ctx *mmctx,
- unsigned key_seq)
-{
- unsigned count;
- unsigned idx;
- struct gsm_auth_tuple *at = NULL;
-
- struct sgsn_subscriber_data *sdata;
-
- if (!mmctx->subscr)
- return NULL;
-
- if (key_seq == GSM_KEY_SEQ_INVAL)
- /* Start with 0 after increment module array size */
- idx = ARRAY_SIZE(sdata->auth_triplets) - 1;
- else
- idx = key_seq;
-
- sdata = mmctx->subscr->sgsn_data;
-
- /* Find next tuple */
- for (count = ARRAY_SIZE(sdata->auth_triplets); count > 0; count--) {
- idx = (idx + 1) % ARRAY_SIZE(sdata->auth_triplets);
-
- if (sdata->auth_triplets[idx].key_seq == GSM_KEY_SEQ_INVAL)
- continue;
-
- if (sdata->auth_triplets[idx].use_count == 0) {
- at = &sdata->auth_triplets[idx];
- at->use_count = 1;
- return at;
- }
- }
-
- return NULL;
-}
diff --git a/src/sgsn/sgsn_libgtp.c b/src/sgsn/sgsn_libgtp.c
index af64738..4650632 100644
--- a/src/sgsn/sgsn_libgtp.c
+++ b/src/sgsn/sgsn_libgtp.c
@@ -54,7 +54,6 @@
#include <osmocom/sgsn/mmctx.h>
#include <osmocom/sgsn/gprs_gmm.h>
#include <osmocom/sgsn/gprs_sm.h>
-#include <osmocom/sgsn/gprs_subscriber.h>
#include <osmocom/sgsn/gprs_sndcp.h>
#include <osmocom/sgsn/gprs_ranap.h>
#include <osmocom/sgsn/gprs_gmm_fsm.h>
@@ -65,6 +64,9 @@
#include <osmocom/sgsn/sgsn_rim.h>
#include <osmocom/sgsn/gprs_bssgp.h>
#include <osmocom/sgsn/pdpctx.h>
+#include <osmocom/sgsn/gprs_rau_fsm.h>
+
+#include <osmocom/vlr/vlr.h>
/* TS 23.003: The MSISDN shall take the dummy MSISDN value composed of
* 15 digits set to 0 (encoded as an E.164 international number) when
@@ -186,9 +188,9 @@
LOGPDPCTXP(LOGL_NOTICE, pctx, "Create PDP Context\n");
/* Put the MSISDN in case we have it */
- if (mmctx->subscr && mmctx->subscr->sgsn_data->msisdn_len) {
- pdp->msisdn.l = OSMO_MIN(mmctx->subscr->sgsn_data->msisdn_len,
sizeof(pdp->msisdn.v));
- memcpy(pdp->msisdn.v, mmctx->subscr->sgsn_data->msisdn,
+ if (mmctx->vsub && strlen(mmctx->vsub->msisdn)) {
+ pdp->msisdn.l = OSMO_MIN(strlen(mmctx->vsub->msisdn),
sizeof(pdp->msisdn.v));
+ memcpy(pdp->msisdn.v, mmctx->vsub->msisdn,
pdp->msisdn.l);
} else {
/* use the dummy 15-digits-zero MSISDN value */
@@ -532,8 +534,9 @@
* "If the SGSN receives an Update PDP Context Response with
* a Cause value "Non-existent", it shall delete the PDP Context."
*/
- if (cause != GTPCAUSE_NON_EXIST)
- return 0; /* Nothing to do */
+ if (cause != GTPCAUSE_NON_EXIST) {
+ return 0; /* Nothing to do */
+ }
LOGPDPCTXP(LOGL_INFO, pctx, "PDP CTX we tried to update doesn't exist in
"
"the GGSN anymore, deleting it locally.\n");
diff --git a/src/sgsn/sgsn_main.c b/src/sgsn/sgsn_main.c
index 320842d..ca4e925 100644
--- a/src/sgsn/sgsn_main.c
+++ b/src/sgsn/sgsn_main.c
@@ -70,6 +70,8 @@
#include <osmocom/sgsn/gprs_subscriber.h>
#include <osmocom/sgsn/gtp.h>
+#include <osmocom/vlr/vlr.h>
+
#include <osmocom/sgsn/sgsn_rim.h>
#include "../../config.h"
@@ -355,6 +357,11 @@
.description = "Routing Area",
.enabled = 1, .loglevel = LOGL_NOTICE,
},
+ [DVLR] = {
+ .name = "VLR",
+ .description = "VLR",
+ .enabled = 1, .loglevel = LOGL_NOTICE,
+ },
};
static const struct log_info gprs_log_info = {
@@ -376,6 +383,8 @@
struct osmo_sccp_instance *sccp;
#endif
+ osmo_fsm_term_safely(true);
+
srand(time(NULL));
tall_sgsn_ctx = talloc_named_const(NULL, 0, "osmo_sgsn");
sgsn = sgsn_instance_alloc(tall_sgsn_ctx);
diff --git a/src/sgsn/sgsn_vty.c b/src/sgsn/sgsn_vty.c
index 7279167..9e71afd 100644
--- a/src/sgsn/sgsn_vty.c
+++ b/src/sgsn/sgsn_vty.c
@@ -752,7 +752,6 @@
return CMD_SUCCESS;
}
-
DEFUN(imsi_acl, cfg_imsi_acl_cmd,
"imsi-acl (add|del) IMSI",
"Access Control List of foreign IMSIs\n"
@@ -779,6 +778,7 @@
osmo_strlcpy(imsi_sanitized + GSM23003_IMSI_MAX_DIGITS - len, argv[1],
sizeof(imsi_sanitized) - (GSM23003_IMSI_MAX_DIGITS - len));
+ /* FIXME: do we still have ACLs? */
if (!strcmp(op, "add"))
rc = sgsn_acl_add(imsi, g_cfg);
else
@@ -939,113 +939,6 @@
}
/* Subscriber */
-#include <osmocom/sgsn/gprs_subscriber.h>
-
-static void subscr_dump_full_vty(struct vty *vty, struct gprs_subscr *gsub, int pending)
-{
-#if 0
- char expire_time[200];
-#endif
- struct gsm_auth_tuple *at;
- int at_idx;
- struct sgsn_subscriber_pdp_data *pdp;
-
- vty_out(vty, " Authorized: %d%s",
- gsub->authorized, VTY_NEWLINE);
- vty_out(vty, " LAC: %d/0x%x%s",
- gsub->lac, gsub->lac, VTY_NEWLINE);
- vty_out(vty, " IMSI: %s%s", gsub->imsi, VTY_NEWLINE);
- if (gsub->tmsi != GSM_RESERVED_TMSI)
- vty_out(vty, " TMSI: %08X%s", gsub->tmsi,
- VTY_NEWLINE);
- if (gsub->sgsn_data->msisdn_len > 0)
- vty_out(vty, " MSISDN (BCD): %s%s",
- osmo_hexdump(gsub->sgsn_data->msisdn,
- gsub->sgsn_data->msisdn_len),
- VTY_NEWLINE);
-
- if (strlen(gsub->imei) > 0)
- vty_out(vty, " IMEI: %s%s", gsub->imei, VTY_NEWLINE);
-
- for (at_idx = 0; at_idx < ARRAY_SIZE(gsub->sgsn_data->auth_triplets);
- at_idx++) {
- at = &gsub->sgsn_data->auth_triplets[at_idx];
- if (at->key_seq == GSM_KEY_SEQ_INVAL)
- continue;
-
- vty_out(vty, " A3A8 tuple (used %d times): ",
- at->use_count);
- vty_out(vty, " CKSN: %d, ",
- at->key_seq);
- if (at->vec.auth_types & OSMO_AUTH_TYPE_GSM) {
- vty_out(vty, "RAND: %s, ",
- osmo_hexdump_nospc(at->vec.rand,
- sizeof(at->vec.rand)));
- vty_out(vty, "SRES: %s, ",
- osmo_hexdump_nospc(at->vec.sres,
- sizeof(at->vec.sres)));
- vty_out(vty, "Kc: %s%s",
- osmo_hexdump_nospc(at->vec.kc,
- sizeof(at->vec.kc)), VTY_NEWLINE);
- }
- if (at->vec.auth_types & OSMO_AUTH_TYPE_UMTS) {
- vty_out(vty, " AUTN: %s, ",
- osmo_hexdump(at->vec.autn,
- sizeof(at->vec.autn)));
- vty_out(vty, "RES: %s, ",
- osmo_hexdump_nospc(at->vec.res, at->vec.res_len));
- vty_out(vty, "IK: %s, ",
- osmo_hexdump_nospc(at->vec.ik, sizeof(at->vec.ik)));
- vty_out(vty, "CK: %s, ",
- osmo_hexdump_nospc(at->vec.ck, sizeof(at->vec.ck)));
- }
- }
-
- llist_for_each_entry(pdp, &gsub->sgsn_data->pdp_list, list) {
- char ip_str[INET6_ADDRSTRLEN] = { 0 };
-
- vty_out(vty, " PDP info: Id: %d, Addr(Org: 0x%02x Type: 0x%02x",
- pdp->context_id, pdp->pdp_type_org, pdp->pdp_type_nr);
-
- if (pdp->pdp_address[0].u.sa.sa_family != AF_UNSPEC)
- vty_out(vty, " Addr[0]: %s",
osmo_sockaddr_ntop(&pdp->pdp_address[0].u.sa, ip_str));
- if (pdp->pdp_address[0].u.sa.sa_family != AF_UNSPEC)
- vty_out(vty, " Addr[1]: %s",
osmo_sockaddr_ntop(&pdp->pdp_address[1].u.sa, ip_str));
-
- vty_out(vty, ") APN: '%s'", pdp->apn_str);
-
- if (pdp->qos_subscribed_len)
- vty_out(vty, " QoS: %s", osmo_hexdump(pdp->qos_subscribed,
pdp->qos_subscribed_len));
-
- vty_out(vty, "%s", VTY_NEWLINE);
- }
-
-#if 0
- /* print the expiration time of a subscriber */
- if (gsub->expire_lu) {
- strftime(expire_time, sizeof(expire_time),
- "%a, %d %b %Y %T %z", localtime(&gsub->expire_lu));
- expire_time[sizeof(expire_time) - 1] = '\0';
- vty_out(vty, " Expiration Time: %s%s", expire_time, VTY_NEWLINE);
- }
-#endif
-
- if (gsub->flags)
- vty_out(vty, " Flags: %s%s%s%s%s%s",
- gsub->flags & GPRS_SUBSCRIBER_FIRST_CONTACT ?
- "FIRST_CONTACT " : "",
- gsub->flags & GPRS_SUBSCRIBER_CANCELLED ?
- "CANCELLED " : "",
- gsub->flags & GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING ?
- "UPDATE_LOCATION_PENDING " : "",
- gsub->flags & GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING ?
- "AUTH_INFO_PENDING " : "",
- gsub->flags & GPRS_SUBSCRIBER_ENABLE_PURGE ?
- "ENABLE_PURGE " : "",
- VTY_NEWLINE);
-
- vty_out(vty, " Use count: %u%s", gsub->use_count, VTY_NEWLINE);
-}
#define RESET_SGSN_STATE_STR \
"Remove all known subscribers, MM contexts and flush BSSGP queues." \
@@ -1056,7 +949,6 @@
"reset sgsn state",
RESET_SGSN_STATE_STR RESET_SGSN_STATE_STR RESET_SGSN_STATE_STR)
{
- struct gprs_subscr *subscr, *tmp_subscr;
struct sgsn_mm_ctx *mm, *tmp_mm;
llist_for_each_entry_safe(mm, tmp_mm, &sgsn->mm_list, list)
@@ -1065,12 +957,7 @@
}
vty_out(vty, "Cancelled MM Ctx. %s", VTY_NEWLINE);
- llist_for_each_entry_safe(subscr, tmp_subscr, gprs_subscribers, entry) {
- gprs_subscr_get(subscr);
- gprs_subscr_cancel(subscr);
- gprs_subscr_put(subscr);
- }
- vty_out(vty, "Removed all gprs subscribers.%s", VTY_NEWLINE);
+ /* FIXME: reset VLR */
bssgp_flush_all_queues();
vty_out(vty, "Flushed all BSSGPs queues.%s", VTY_NEWLINE);
@@ -1088,160 +975,7 @@
SHOW_STR "Show information about subscribers\n"
"Display contents of subscriber cache\n")
{
- struct gprs_subscr *subscr;
-
- llist_for_each_entry(subscr, gprs_subscribers, entry) {
- vty_out(vty, " Subscriber:%s", VTY_NEWLINE);
- subscr_dump_full_vty(vty, subscr, 0);
- }
-
- return CMD_SUCCESS;
-}
-
-#define UPDATE_SUBSCR_STR "update-subscriber imsi IMSI "
-#define UPDATE_SUBSCR_HELP "Update subscriber list\n" \
- "Use the IMSI to select the subscriber\n" \
- "The IMSI\n"
-
-#define UPDATE_SUBSCR_INSERT_HELP "Insert data into the subscriber record\n"
-
-DEFUN(update_subscr_insert_auth_triplet, update_subscr_insert_auth_triplet_cmd,
- UPDATE_SUBSCR_STR "insert auth-triplet <1-5> sres SRES rand RAND kc
KC",
- UPDATE_SUBSCR_HELP
- UPDATE_SUBSCR_INSERT_HELP
- "Update authentication triplet\n"
- "Triplet index\n"
- "Set SRES value\nSRES value (4 byte) in hex\n"
- "Set RAND value\nRAND value (16 byte) in hex\n"
- "Set Kc value\nKc value (8 byte) in hex\n")
-{
- const char *imsi = argv[0];
- const int cksn = atoi(argv[1]) - 1;
- const char *sres_str = argv[2];
- const char *rand_str = argv[3];
- const char *kc_str = argv[4];
- struct gsm_auth_tuple at = {0,};
-
- struct gprs_subscr *subscr;
-
- subscr = gprs_subscr_get_by_imsi(imsi);
- if (!subscr) {
- vty_out(vty, "%% unable get subscriber record for %s%s",
- imsi, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- OSMO_ASSERT(subscr->sgsn_data);
-
- if (osmo_hexparse(sres_str, &at.vec.sres[0], sizeof(at.vec.sres)) < 0) {
- vty_out(vty, "%% invalid SRES value '%s'%s",
- sres_str, VTY_NEWLINE);
- goto failed;
- }
- if (osmo_hexparse(rand_str, &at.vec.rand[0], sizeof(at.vec.rand)) < 0) {
- vty_out(vty, "%% invalid RAND value '%s'%s",
- rand_str, VTY_NEWLINE);
- goto failed;
- }
- if (osmo_hexparse(kc_str, &at.vec.kc[0], sizeof(at.vec.kc)) < 0) {
- vty_out(vty, "%% invalid Kc value '%s'%s",
- kc_str, VTY_NEWLINE);
- goto failed;
- }
- at.key_seq = cksn;
-
- subscr->sgsn_data->auth_triplets[cksn] = at;
- subscr->sgsn_data->auth_triplets_updated = 1;
-
- gprs_subscr_put(subscr);
-
- return CMD_SUCCESS;
-
-failed:
- gprs_subscr_put(subscr);
- return CMD_SUCCESS;
-}
-
-DEFUN(update_subscr_cancel, update_subscr_cancel_cmd,
- UPDATE_SUBSCR_STR "cancel (update-procedure|subscription-withdraw)",
- UPDATE_SUBSCR_HELP
- "Cancel (remove) subscriber record\n"
- "The MS moved to another SGSN\n"
- "The subscription is no longer valid\n")
-{
- const char *imsi = argv[0];
- const char *cancel_type = argv[1];
-
- struct gprs_subscr *subscr;
-
- subscr = gprs_subscr_get_by_imsi(imsi);
- if (!subscr) {
- vty_out(vty, "%% no subscriber record for %s%s",
- imsi, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (strcmp(cancel_type, "update-procedure") == 0)
- subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
- else
- subscr->sgsn_data->error_cause = GMM_CAUSE_IMPL_DETACHED;
-
- gprs_subscr_cancel(subscr);
- gprs_subscr_put(subscr);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(update_subscr_create, update_subscr_create_cmd,
- UPDATE_SUBSCR_STR "create",
- UPDATE_SUBSCR_HELP
- "Create a subscriber entry\n")
-{
- const char *imsi = argv[0];
-
- struct gprs_subscr *subscr;
-
- subscr = gprs_subscr_get_by_imsi(imsi);
- if (subscr) {
- vty_out(vty, "%% subscriber record already exists for %s%s",
- imsi, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- subscr = gprs_subscr_get_or_create(imsi);
- if (!subscr) {
- vty_out(vty, "Can not create subscriber. Out of memory.%s", imsi);
- return CMD_WARNING;
- }
- subscr->keep_in_ram = 1;
- gprs_subscr_put(subscr);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(update_subscr_destroy, update_subscr_destroy_cmd,
- UPDATE_SUBSCR_STR "destroy",
- UPDATE_SUBSCR_HELP
- "Destroy a subscriber entry\n")
-{
- const char *imsi = argv[0];
-
- struct gprs_subscr *subscr;
-
- subscr = gprs_subscr_get_by_imsi(imsi);
- if (!subscr) {
- vty_out(vty, "%% subscriber record does not exist for %s%s",
- imsi, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- subscr->keep_in_ram = 0;
- subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
- gprs_subscr_cancel(subscr);
- if (subscr->use_count > 1)
- vty_out(vty, "%% subscriber is still in use%s",
- VTY_NEWLINE);
- gprs_subscr_put(subscr);
+ /* FIXME list VLR or MMctx */
return CMD_SUCCESS;
}
@@ -1256,73 +990,6 @@
"Force error code UnknownSubscriber\n" \
"Force error code RoamingNotAllowed\n"
-DEFUN(update_subscr_update_location_result, update_subscr_update_location_result_cmd,
- UPDATE_SUBSCR_STR "update-location-result (ok|" UL_ERR_STR ")",
- UPDATE_SUBSCR_HELP
- "Complete the update location procedure\n"
- "The update location request succeeded\n"
- UL_ERR_HELP)
-{
- const char *imsi = argv[0];
- const char *ret_code_str = argv[1];
-
- struct gprs_subscr *subscr;
-
- const struct value_string cause_mapping[] = {
- { GMM_CAUSE_NET_FAIL, "system-failure" },
- { GMM_CAUSE_INV_MAND_INFO, "data-missing" },
- { GMM_CAUSE_PROTO_ERR_UNSPEC, "unexpected-data-value" },
- { GMM_CAUSE_IMSI_UNKNOWN, "unknown-subscriber" },
- { GMM_CAUSE_GPRS_NOTALLOWED, "roaming-not-allowed" },
- { 0, NULL }
- };
-
- subscr = gprs_subscr_get_by_imsi(imsi);
- if (!subscr) {
- vty_out(vty, "%% unable to get subscriber record for %s%s",
- imsi, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (strcmp(ret_code_str, "ok") == 0) {
- subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
- subscr->authorized = 1;
- } else {
- subscr->sgsn_data->error_cause =
- get_string_value(cause_mapping, ret_code_str);
- subscr->authorized = 0;
- }
-
- gprs_subscr_update(subscr);
-
- gprs_subscr_put(subscr);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(update_subscr_update_auth_info, update_subscr_update_auth_info_cmd,
- UPDATE_SUBSCR_STR "update-auth-info",
- UPDATE_SUBSCR_HELP
- "Complete the send authentication info procedure\n")
-{
- const char *imsi = argv[0];
-
- struct gprs_subscr *subscr;
-
- subscr = gprs_subscr_get_by_imsi(imsi);
- if (!subscr) {
- vty_out(vty, "%% unable to get subscriber record for %s%s",
- imsi, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- gprs_subscr_update_auth_info(subscr);
-
- gprs_subscr_put(subscr);
-
- return CMD_SUCCESS;
-}
-
DEFUN(page_subscr, page_subscr_info_cmd,
"page imsi IMSI",
"Send a PS paging request to subscriber\n"
@@ -1838,12 +1505,6 @@
install_element_ve(&show_timer_cmd);
install_element_ve(&show_timer_gtp_cmd);
- install_element(ENABLE_NODE, &update_subscr_insert_auth_triplet_cmd);
- install_element(ENABLE_NODE, &update_subscr_create_cmd);
- install_element(ENABLE_NODE, &update_subscr_destroy_cmd);
- install_element(ENABLE_NODE, &update_subscr_cancel_cmd);
- install_element(ENABLE_NODE, &update_subscr_update_location_result_cmd);
- install_element(ENABLE_NODE, &update_subscr_update_auth_info_cmd);
install_element(ENABLE_NODE, &page_subscr_info_cmd);
install_element(ENABLE_NODE, &reset_sgsn_state_cmd);
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 9d429d7..a613c5c 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -2,7 +2,6 @@
gprs \
gtphub \
gprs_routing_area \
- sgsn \
xid \
sndcp_xid \
slhc \
diff --git a/tests/gprs_routing_area/Makefile.am b/tests/gprs_routing_area/Makefile.am
index e15769d..897b9f8 100644
--- a/tests/gprs_routing_area/Makefile.am
+++ b/tests/gprs_routing_area/Makefile.am
@@ -44,6 +44,7 @@
$(top_builddir)/src/sgsn/gprs_sndcp.o \
$(top_builddir)/src/sgsn/gprs_gmm_attach.o \
$(top_builddir)/src/sgsn/gprs_gmm.o \
+ $(top_builddir)/src/sgsn/gprs_rau_fsm.o \
$(top_builddir)/src/sgsn/gprs_gmm_fsm.o \
$(top_builddir)/src/sgsn/gprs_gmm_util.o \
$(top_builddir)/src/sgsn/gprs_mm_state_gb_fsm.o \
diff --git a/tests/sgsn/sgsn_test.c b/tests/sgsn/sgsn_test.c
index 6dcda84..6604c86 100644
--- a/tests/sgsn/sgsn_test.c
+++ b/tests/sgsn/sgsn_test.c
@@ -438,13 +438,17 @@
static int rx_gsup_message(const uint8_t *data, size_t data_len)
{
struct msgb *msg;
+ struct osmo_gsup_message gsup_msg = {};
int rc;
msg = msgb_alloc(1024, __func__);
msg->l2h = msgb_put(msg, data_len);
OSMO_ASSERT(msg->l2h != NULL);
memcpy(msg->l2h, data, data_len);
- rc = gprs_subscr_rx_gsup_message(msg);
+ rc = osmo_gsup_decode(data, data_len, &gsup_msg);
+ OSMO_ASSERT(!rc);
+
+ rc = gprs_subscr_rx_gsup_message(&gsup_msg);
msgb_free(msg);
return rc;
@@ -1040,7 +1044,6 @@
{
struct osmo_gsup_message to_peer = {0};
struct osmo_gsup_message from_peer = {0};
- struct msgb *reply_msg;
int rc;
/* Simulate the GSUP peer */
@@ -1078,11 +1081,7 @@
return 0;
}
- reply_msg = osmo_gsup_client_msgb_alloc();
- reply_msg->l2h = reply_msg->data;
- osmo_gsup_encode(reply_msg, &from_peer);
- gprs_subscr_rx_gsup_message(reply_msg);
- msgb_free(reply_msg);
+ gprs_subscr_rx_gsup_message(&from_peer);
return 0;
};
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 242ab26..9079c84 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -7,13 +7,6 @@
AT_CHECK([$abs_top_builddir/tests/gprs/gprs_test], [], [expout], [ignore])
AT_CLEANUP
-AT_SETUP([sgsn])
-AT_KEYWORDS([sgsn])
-AT_CHECK([test "$enable_sgsn_test" != no || exit 77])
-cat $abs_srcdir/sgsn/sgsn_test.ok > expout
-AT_CHECK([$abs_top_builddir/tests/sgsn/sgsn_test], [], [expout], [ignore])
-AT_CLEANUP
-
AT_SETUP([gprs_routing_area])
AT_KEYWORDS([gprs_routing_area])
AT_CHECK([test "$enable_gprs_routing_area_test" != no || exit 77])
diff --git a/tests/vty_test_runner.py b/tests/vty_test_runner.py
index aaa76ed..8141948 100755
--- a/tests/vty_test_runner.py
+++ b/tests/vty_test_runner.py
@@ -130,25 +130,6 @@
res = self.vty.command("show running-config")
self.assertTrue(res.find('auth-policy remote') > 0)
- def testVtySubscriber(self):
- self.vty.enable()
- res = self.vty.command('show subscriber cache')
- self.assertTrue(res.find('1234567890') < 0)
- self.assertTrue(self.vty.verify('update-subscriber imsi 1234567890
create', ['']))
- res = self.vty.command('show subscriber cache')
- self.assertTrue(res.find('1234567890') >= 0)
- self.assertTrue(res.find('Authorized: 0') >= 0)
- self.assertTrue(self.vty.verify('update-subscriber imsi 1234567890
update-location-result ok', ['']))
- res = self.vty.command('show subscriber cache')
- self.assertTrue(res.find('1234567890') >= 0)
- self.assertTrue(res.find('Authorized: 1') >= 0)
- self.assertTrue(self.vty.verify('update-subscriber imsi 1234567890 cancel
update-procedure', ['']))
- res = self.vty.command('show subscriber cache')
- self.assertTrue(res.find('1234567890') >= 0)
- self.assertTrue(self.vty.verify('update-subscriber imsi 1234567890
destroy', ['']))
- res = self.vty.command('show subscriber cache')
- self.assertTrue(res.find('1234567890') < 0)
-
def testVtyGgsn(self):
self.vty.enable()
self.assertTrue(self.vty.verify('configure terminal', ['']))
--
To view, visit
https://gerrit.osmocom.org/c/osmo-sgsn/+/39562?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: newchange
Gerrit-Project: osmo-sgsn
Gerrit-Branch: master
Gerrit-Change-Id: I9c5b4ec1b337c35e85c2d1a3d09b318380ae6ef8
Gerrit-Change-Number: 39562
Gerrit-PatchSet: 1
Gerrit-Owner: lynxis lazus <lynxis(a)fe80.eu>