aboutsummaryrefslogtreecommitdiffstats
path: root/src/libmsc/gsm_04_08.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libmsc/gsm_04_08.c')
-rw-r--r--src/libmsc/gsm_04_08.c102
1 files changed, 64 insertions, 38 deletions
diff --git a/src/libmsc/gsm_04_08.c b/src/libmsc/gsm_04_08.c
index f29c0b68e..b51fd16b5 100644
--- a/src/libmsc/gsm_04_08.c
+++ b/src/libmsc/gsm_04_08.c
@@ -329,7 +329,6 @@ int mm_rx_loc_upd_req(struct gsm_subscriber_connection *conn, struct msgb *msg)
struct osmo_location_area_id old_lai, new_lai;
struct osmo_fsm_inst *lu_fsm;
bool is_utran;
- int rc;
lu = (struct gsm48_loc_upd_req *) gh->data;
@@ -337,10 +336,21 @@ int mm_rx_loc_upd_req(struct gsm_subscriber_connection *conn, struct msgb *msg)
gsm48_mi_to_string(mi_string, sizeof(mi_string), lu->mi, lu->mi_len);
- rc = msc_create_conn_fsm(conn, mi_string);
- if (rc)
- /* logging already happened in msc_create_conn_fsm() */
- return rc;
+ if (msc_subscr_conn_is_establishing_auth_ciph(conn)) {
+ LOGP(DMM, LOGL_ERROR,
+ "Cannot accept another LU, conn already busy establishing authenticity;"
+ " extraneous LOCATION UPDATING REQUEST: MI(%s)=%s type=%s\n",
+ gsm48_mi_type_name(mi_type), mi_string, get_value_string(lupd_names, lu->type));
+ return -EINVAL;
+ }
+
+ if (msc_subscr_conn_is_accepted(conn)) {
+ LOGP(DMM, LOGL_ERROR,
+ "Cannot accept another LU, conn already established;"
+ " extraneous LOCATION UPDATING REQUEST: MI(%s)=%s type=%s\n",
+ gsm48_mi_type_name(mi_type), mi_string, get_value_string(lupd_names, lu->type));
+ return -EINVAL;
+ }
msc_subscr_conn_update_id(conn, COMPLETE_LAYER3_LU, mi_string);
@@ -420,6 +430,7 @@ int mm_rx_loc_upd_req(struct gsm_subscriber_connection *conn, struct msgb *msg)
return -EIO;
}
+ msc_subscr_conn_complete_layer_3(conn);
return 0;
}
@@ -670,7 +681,11 @@ static int cm_serv_reuse_conn(struct gsm_subscriber_connection *conn, const uint
accept_reuse:
DEBUGP(DMM, "%s: re-using already accepted connection\n",
vlr_subscr_name(conn->vsub));
- conn->received_cm_service_request = true;
+
+ if (!conn->received_cm_service_request) {
+ conn->received_cm_service_request = true;
+ msc_subscr_conn_get(conn, MSC_CONN_USE_CM_SERVICE);
+ }
msc_subscr_conn_update_id(conn, conn->complete_layer3_type, mi_string);
return conn->network->vlr->ops.tx_cm_serv_acc(conn);
}
@@ -698,32 +713,31 @@ int gsm48_rx_mm_serv_req(struct gsm_subscriber_connection *conn, struct msgb *ms
/* unfortunately in Phase1 the classmark2 length is variable */
uint8_t classmark2_len = gh->data[1];
uint8_t *classmark2 = gh->data+2;
- uint8_t mi_len = *(classmark2 + classmark2_len);
- uint8_t *mi = (classmark2 + classmark2_len + 1);
+ uint8_t *mi_p = classmark2 + classmark2_len;
+ uint8_t mi_len = *mi_p;
+ uint8_t *mi = mi_p + 1;
struct osmo_location_area_id lai;
bool is_utran;
- int rc;
lai.plmn = conn->network->plmn;
lai.lac = conn->lac;
- DEBUGP(DMM, "<- CM SERVICE REQUEST ");
if (msg->data_len < sizeof(struct gsm48_service_request*)) {
- DEBUGPC(DMM, "wrong sized message\n");
+ LOGP(DMM, LOGL_ERROR, "<- CM SERVICE REQUEST wrong sized message\n");
return msc_gsm48_tx_mm_serv_rej(conn,
GSM48_REJECT_INCORRECT_MESSAGE);
}
if (msg->data_len < req->mi_len + 6) {
- DEBUGPC(DMM, "does not fit in packet\n");
+ LOGP(DMM, LOGL_ERROR, "<- CM SERVICE REQUEST does not fit in packet\n");
return msc_gsm48_tx_mm_serv_rej(conn,
GSM48_REJECT_INCORRECT_MESSAGE);
}
gsm48_mi_to_string(mi_string, sizeof(mi_string), mi, mi_len);
mi_type = mi[0] & GSM_MI_TYPE_MASK;
- DEBUGPC(DMM, "serv_type=0x%02x MI(%s)=%s\n",
- req->cm_service_type, gsm48_mi_type_name(mi_type), mi_string);
+ DEBUGP(DMM, "<- CM SERVICE REQUEST serv_type=0x%02x MI(%s)=%s\n",
+ req->cm_service_type, gsm48_mi_type_name(mi_type), mi_string);
switch (mi_type) {
case GSM_MI_TYPE_IMSI:
@@ -754,27 +768,23 @@ int gsm48_rx_mm_serv_req(struct gsm_subscriber_connection *conn, struct msgb *ms
return msc_gsm48_tx_mm_serv_rej(conn, GSM48_REJECT_SRV_OPT_NOT_SUPPORTED);
}
- osmo_signal_dispatch(SS_SUBSCR, S_SUBSCR_IDENTITY, (classmark2 + classmark2_len));
- memcpy(conn->classmark.classmark2, classmark2, classmark2_len);
- conn->classmark.classmark2_len = classmark2_len;
+ if (msc_subscr_conn_is_accepted(conn))
+ return cm_serv_reuse_conn(conn, mi_p);
- if (conn->fi) {
- if (msc_subscr_conn_is_accepted(conn))
- return cm_serv_reuse_conn(conn, mi-1);
- LOGP(DMM, LOGL_ERROR, "%s: connection already in use\n",
- vlr_subscr_name(conn->vsub));
+ if (msc_subscr_conn_is_establishing_auth_ciph(conn)) {
+ LOGP(DMM, LOGL_ERROR,
+ "Cannot accept CM Service Request, conn already busy establishing authenticity\n");
msc_vlr_tx_cm_serv_rej(conn, VLR_PR_ARQ_RES_UNKNOWN_ERROR);
return -EINVAL;
+ /* or should we accept and note down the service request anyway? */
}
- rc = msc_create_conn_fsm(conn, mi_string);
- if (rc) {
- msc_vlr_tx_cm_serv_rej(conn, VLR_PR_ARQ_RES_UNKNOWN_ERROR);
- /* logging already happened in msc_create_conn_fsm() */
- return rc;
- }
msc_subscr_conn_update_id(conn, COMPLETE_LAYER3_CM_SERVICE_REQ, mi_string);
+ osmo_signal_dispatch(SS_SUBSCR, S_SUBSCR_IDENTITY, mi_p);
+ memcpy(conn->classmark.classmark2, classmark2, classmark2_len);
+ conn->classmark.classmark2_len = classmark2_len;
+
is_utran = (conn->via_ran == RAN_UTRAN_IU);
vlr_proc_acc_req(conn->fi,
SUBSCR_CONN_E_ACCEPTED, SUBSCR_CONN_E_CN_CLOSE, NULL,
@@ -785,6 +795,7 @@ int gsm48_rx_mm_serv_req(struct gsm_subscriber_connection *conn, struct msgb *ms
classmark_is_r99(&conn->classmark),
is_utran);
+ msc_subscr_conn_complete_layer_3(conn);
return 0;
}
@@ -1149,7 +1160,6 @@ static int gsm48_rx_rr_pag_resp(struct gsm_subscriber_connection *conn, struct m
uint8_t *mi_lv;
uint8_t mi_type;
char mi_string[GSM48_MI_SIZE];
- int rc = 0;
struct osmo_location_area_id lai;
bool is_utran;
@@ -1159,19 +1169,26 @@ static int gsm48_rx_rr_pag_resp(struct gsm_subscriber_connection *conn, struct m
resp = (struct gsm48_pag_resp *) &gh->data[0];
gsm48_paging_extract_mi(resp, msgb_l3len(msg) - sizeof(*gh),
mi_string, &mi_type);
- DEBUGP(DRR, "PAGING RESPONSE: MI(%s)=%s\n",
- gsm48_mi_type_name(mi_type), mi_string);
+
+ if (msc_subscr_conn_is_establishing_auth_ciph(conn)) {
+ LOGP(DMM, LOGL_ERROR,
+ "Ignoring Paging Response, conn already busy establishing authenticity\n");
+ return 0;
+ }
+
+ if (msc_subscr_conn_is_accepted(conn)) {
+ LOGP(DMM, LOGL_ERROR, "Ignoring Paging Response, conn already established\n");
+ return 0;
+ }
+
+ DEBUGP(DRR, "PAGING RESPONSE: MI(%s)=%s\n", gsm48_mi_type_name(mi_type), mi_string);
mi_lv = gsm48_cm2_get_mi(classmark2_lv, msgb_l3len(msg) - sizeof(*gh));
if (!mi_lv) {
- /* FIXME */
+ LOGP(DRR, LOGL_ERROR, "PAGING RESPONSE: invalid Mobile Identity\n");
return -1;
}
- rc = msc_create_conn_fsm(conn, mi_string);
- if (rc)
- /* logging already happened in msc_create_conn_fsm() */
- return rc;
msc_subscr_conn_update_id(conn, COMPLETE_LAYER3_PAGING_RESP, mi_string);
memcpy(conn->classmark.classmark2, classmark2_lv+1, *classmark2_lv);
@@ -1187,6 +1204,7 @@ static int gsm48_rx_rr_pag_resp(struct gsm_subscriber_connection *conn, struct m
classmark_is_r99(&conn->classmark),
is_utran);
+ msc_subscr_conn_complete_layer_3(conn);
return 0;
}
@@ -3347,6 +3365,7 @@ void cm_service_request_concludes(struct gsm_subscriber_connection *conn,
gsm48_pdisc_msgtype_name(pdisc, msg_type));
}
conn->received_cm_service_request = false;
+ msc_subscr_conn_put(conn, MSC_CONN_USE_CM_SERVICE);
}
/* TS 24.007 11.2.3.2.3 Message Type Octet / Duplicate Detection */
@@ -3590,7 +3609,7 @@ static int msc_vlr_tx_cm_serv_rej(void *msc_conn_ref, enum vlr_proc_arq_result r
{
uint8_t cause;
struct gsm_subscriber_connection *conn = msc_conn_ref;
- conn->received_cm_service_request = false;
+ int rc;
switch (result) {
default:
@@ -3616,7 +3635,14 @@ static int msc_vlr_tx_cm_serv_rej(void *msc_conn_ref, enum vlr_proc_arq_result r
break;
};
- return msc_gsm48_tx_mm_serv_rej(conn, cause);
+ rc = msc_gsm48_tx_mm_serv_rej(conn, cause);
+
+ if (conn->received_cm_service_request) {
+ conn->received_cm_service_request = false;
+ msc_subscr_conn_put(conn, MSC_CONN_USE_CM_SERVICE);
+ }
+
+ return rc;
}
/* For msc_vlr_set_ciph_mode() */