};
/* GSM 04.07 9.2.2 */
-#define MMCC_EST_REQ 0x9110
-#define MMCC_EST_IND 0x9112
-#define MMCC_EST_CNF 0x9111
-#define MMCC_REL_REQ 0x9120
-#define MMCC_REL_IND 0x9122
-#define MMCC_DATA_REQ 0x9130
-#define MMCC_DATA_IND 0x9132
-#define MMCC_UNIT_DATA_REQ 0x9140
-#define MMCC_UNIT_DATA_IND 0x9142
-#define MMCC_SYNC_IND 0x9152
-#define MMCC_REEST_REQ 0x9160
-#define MMCC_REEST_CNF 0x9161
-#define MMCC_ERR_IND 0x9172
-#define MMCC_PROMPT_IND 0x9182
-#define MMCC_PROMPT_REJ 0x9184
-#define MMSS_EST_REQ 0x9210
-#define MMSS_EST_IND 0x9212
-#define MMSS_EST_CNF 0x9211
-#define MMSS_REL_REQ 0x9220
-#define MMSS_REL_IND 0x9222
-#define MMSS_DATA_REQ 0x9230
-#define MMSS_DATA_IND 0x9232
-#define MMSS_UNIT_DATA_REQ 0x9240
-#define MMSS_UNIT_DATA_IND 0x9242
-#define MMSS_REEST_REQ 0x9260
-#define MMSS_REEST_CNF 0x9261
-#define MMSS_ERR_IND 0x9272
-#define MMSS_PROMPT_IND 0x9282
-#define MMSS_PROMPT_REJ 0x9284
-#define MMSMS_EST_REQ 0x9310
-#define MMSMS_EST_IND 0x9312
-#define MMSMS_EST_CNF 0x9311
-#define MMSMS_REL_REQ 0x9320
-#define MMSMS_REL_IND 0x9322
-#define MMSMS_DATA_REQ 0x9330
-#define MMSMS_DATA_IND 0x9332
-#define MMSMS_UNIT_DATA_REQ 0x9340
-#define MMSMS_UNIT_DATA_IND 0x9342
-#define MMSMS_REEST_REQ 0x9360
-#define MMSMS_REEST_CNF 0x9361
-#define MMSMS_ERR_IND 0x9372
-#define MMSMS_PROMPT_IND 0x9382
-#define MMSMS_PROMPT_REJ 0x9384
+#define GSM48_MMCC_EST_REQ 0x9110 todo: renumber
+#define GSM48_MMCC_EST_IND 0x9112
+#define GSM48_MMCC_EST_CNF 0x9111
+#define GSM48_MMCC_REL_REQ 0x9120
+#define GSM48_MMCC_REL_IND 0x9122
+#define GSM48_MMCC_DATA_REQ 0x9130
+#define GSM48_MMCC_DATA_IND 0x9132
+#define GSM48_MMCC_UNIT_DATA_REQ 0x9140
+#define GSM48_MMCC_UNIT_DATA_IND 0x9142
+#define GSM48_MMCC_SYNC_IND 0x9152
+#define GSM48_MMCC_REEST_REQ 0x9160
+#define GSM48_MMCC_REEST_CNF 0x9161
+#define GSM48_MMCC_ERR_IND 0x9172
+#define GSM48_MMCC_PROMPT_IND 0x9182
+#define GSM48_MMCC_PROMPT_REJ 0x9184
+#define GSM48_MMSS_EST_REQ 0x9210
+#define GSM48_MMSS_EST_IND 0x9212
+#define GSM48_MMSS_EST_CNF 0x9211
+#define GSM48_MMSS_REL_REQ 0x9220
+#define GSM48_MMSS_REL_IND 0x9222
+#define GSM48_MMSS_DATA_REQ 0x9230
+#define GSM48_MMSS_DATA_IND 0x9232
+#define GSM48_MMSS_UNIT_DATA_REQ 0x9240
+#define GSM48_MMSS_UNIT_DATA_IND 0x9242
+#define GSM48_MMSS_REEST_REQ 0x9260
+#define GSM48_MMSS_REEST_CNF 0x9261
+#define GSM48_MMSS_ERR_IND 0x9272
+#define GSM48_MMSS_PROMPT_IND 0x9282
+#define GSM48_MMSS_PROMPT_REJ 0x9284
+#define GSM48_MMSMS_EST_REQ 0x9310
+#define GSM48_MMSMS_EST_IND 0x9312
+#define GSM48_MMSMS_EST_CNF 0x9311
+#define GSM48_MMSMS_REL_REQ 0x9320
+#define GSM48_MMSMS_REL_IND 0x9322
+#define GSM48_MMSMS_DATA_REQ 0x9330
+#define GSM48_MMSMS_DATA_IND 0x9332
+#define GSM48_MMSMS_UNIT_DATA_REQ 0x9340
+#define GSM48_MMSMS_UNIT_DATA_IND 0x9342
+#define GSM48_MMSMS_REEST_REQ 0x9360
+#define GSM48_MMSMS_REEST_CNF 0x9361
+#define GSM48_MMSMS_ERR_IND 0x9372
+#define GSM48_MMSMS_PROMPT_IND 0x9382
+#define GSM48_MMSMS_PROMPT_REJ 0x9384
/* GSM 04.07 9.1.1 */
#define GSM_RRSTATE_IDLE 0
/* MM sublayer instance */
-struct gsm_mmlayer {
+struct gsm48_mmlayer {
struct osmocom_ms *ms;
int state;
int substate;
struct timer_list t3212;
struct timer_list t3213;
int t3212_value;
+ struct llist_head mm_conn;
};
+/* MM connection types */
+#define GSM48_MM_CONN_TYPE_CC 1
+#define GSM48_MM_CONN_TYPE_SS 2
+#define GSM48_MM_CONN_TYPE_SMS 3
+
+/* MM connection entry */
+struct gsm48_mm_conn {
+ struct llist_head list;
+
+ unsigned int ref;
+ int type;
+};
+
+
/* GSM 04.08 RR timers */
#define GSM_T3126_MS 5, 0
* messages
*/
-/* allocate GSM 04.08 mobility management message (betreen MM and RR) */
-static struct msgb *gsm48_mm_msgb_alloc(void)
+/* allocate GSM 04.08 rr-sap message (between MM and RR) */
+static struct msgb *gsm48_rr_msgb_alloc(void)
{
struct msgb *msg;
/* release MM connection and proceed with IMSI detach */
static int gsm48_mm_imsi_detach_release(struct osmocom_ms *ms, void *arg)
{
- release all connections
+ /* release all connections */
+ gsm48_mm_release_mm_conn(ms);
/* wait for release of RR */
if (!s->att_allowed) {
return 0;
}
+/* support function to release all ongoing MM connections */
+static int gsm48_mm_release_conn(struct osmocom_ms *ms)
+{
+ struct gsm48_mmlayer *mm = &ms->mm;
+ struct gsm48_mm_conn *conn;
+ struct msgb *nmsg;
+ int msg_type;
+
+ /* loop until all transactions gone */
+ while (!llist_empty(&mm->mm_conn)) {
+ conn = llist_entry(mm->mm_conn->next, struct gsm48_mm_conn,
+ entry);
+
+ /* send the appropiate release message */
+ switch (conn->type) {
+ case GSM48_MM_CONN_TYPE_CC:
+ msg_type = GSM48_MMCC_REL_IND;
+ break;
+ case GSM48_MM_CONN_TYPE_SS:
+ msg_type = GSM48_MMSS_REL_IND;
+ break;
+ case GSM48_MM_CONN_TYPE_SMS:
+ msg_type = GSM48_MMSMS_REL_IND;
+ break;
+ }
+ nmsg = gsm48_mm_msgb_alloc(msg_type, conn->ref);
+ if (!nmsg)
+ return -ENOMEM;
+ gsm48_mmxx_upmsg(ms, nmsg);
+
+ /* detach from list and free */
+ llist_del(&conn->entry);
+ free(conn);
+ }
+
+ return 0;
+}
+
+/* 4.3.5.2 ABORT is received */
+static int gsm48_mm_rx_abort(struct osmocom_ms *ms, struct msgb *msg)
+{
+ struct gsm48_mmlayer *mm = &ms->mm;
+ struct gsm48_hdr *gh = msgb_l3(msg);
+ unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
+
+ if (payload_len < 1) {
+ DEBUGP(DMM, "Short read of location updating reject message error.\n");
+ return -EINVAL;
+ }
+
+ reject_cause = *gh->data;
+
+ if (llist_empty(&mm->mm_conn)) {
+ DEBUGP(DMM, "Abort (cause #%d) while no MM connection is established.\n", reject_cause);
+ return gsm48_mm_tx_mm_status(ms,
+ GSM48_REJECT_MSG_NOT_COMPATIBLE);
+ } else {
+ DEBUGP(DMM, "Abort (cause #%d) while MM connection is established.\n", reject_cause);
+ gsm48_mm_release_mm_conn(ms);
+ }
+
+ if (reject_cause == GSM48_REJECT_ILLEGAL_ME) {
+ /* SIM invalid */
+ subscr->sim_valid = 0;
+
+ /* TMSI and LAI invalid */
+ subscr->tmsi_valid = 0;
+
+ /* key is invalid */
+ subscr->key_seq = 7;
+
+ /* update status */
+ new_sim_ustate(ms, GSM_MMUSTATE_U3_ROAMING_NA);
+
+#ifdef TODO
+ sim: delete tmsi
+ sim: delete key seq number
+ sim: apply update state
+#endif
+
+ /* return to MM IDLE / No SIM */
+ gsm48_mm_return_idle(ms);
+ }
+
+ return 0;
+}
+
todo set cause
reject:
switch(msg_type) {
- case MMCC_EST_REQ:
+ case GSM48_MMCC_EST_REQ:
mmmsg->cause = cause;
return mm_recvmsg(ms, trans, MMCC_REL_IND, mmmsg);
- case MMSS_EST_REQ:
+ case GSM48_MMSS_EST_REQ:
mmmsg->cause = cause;
return mm_recvmsg(ms, trans, MMSS_REL_IND, mmmsg);
- case MMSMS_EST_REQ:
+ case GSM48_MMSMS_EST_REQ:
mmmsg->cause = cause;
return mm_recvmsg(ms, trans, MMSMS_REL_IND, mmmsg);
default:
struct gsm_trans *trans = mmmsg->trans;
switch(msg_type) {
- case MMCC_EST_REQ:
+ case GSM48_MMCC_EST_REQ:
mmmsg->cause = cause;
- return mm_recvmsg(ms, trans, MMCC_REL_IND, mmmsg);
- case MMSS_EST_REQ:
+ return mm_recvmsg(ms, trans, GSM48_MMCC_REL_IND, mmmsg);
+ case GSM48_MMSS_EST_REQ:
mmmsg->cause = cause;
- return mm_recvmsg(ms, trans, MMSS_REL_IND, mmmsg);
- case MMSMS_EST_REQ:
+ return mm_recvmsg(ms, trans, GSM48_MMSS_REL_IND, mmmsg);
+ case GSM48_MMSMS_EST_REQ:
mmmsg->cause = cause;
- return mm_recvmsg(ms, trans, MMSMS_REL_IND, mmmsg);
+ return mm_recvmsg(ms, trans, GSM48_MMSMS_REL_IND, mmmsg);
default:
return 0;
}
u_int32_t states;
u_int32_t substates;
int type;
- int (*rout) (struct gsm_trans *trans, void *arg);
+ int (*rout) (struct osmocom_ms *ms, struct msgb *msg);
} eventstatelist[] = {
/* 4.2.2.1 Normal service */
** todo: check if there is a senders of every event
}
}
-/* location updating reject is received from lower layer */
-static int gsm48_mm_rx_abort(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
-
- if (payload_len < 1) {
- DEBUGP(DMM, "Short read of location updating reject message error.\n");
- return -EINVAL;
- }
-
- reject_cause = *gh->data;
-
- if (llist_empty(ms->trans)) {
- DEBUGP(DMM, "Abort (cause #%d) while no MM connection is established.\n", reject_cause);
- return 0;
- } else {
- DEBUGP(DMM, "Abort (cause #%d) while MM connection is established.\n", reject_cause);
- while(translist not empty)
- release trans
- todo: release trans must send a release to it's application entitity
- todo: release must cause release of state 6 and transfer to state 9
- }
-
- if (reject_cause == 6) {
- new_sim_ustate(ms, GSM_MMUSTATE_U3_ROAMING_NA);
-#ifdef TODO
- sim: delete tmsi
- sim: delete key seq number
- sim: apply update state
-#endif
- }
-}
/* location updating accept is received from lower layer */
static int gsm48_mm_rx_loc_upd_acc(struct osmocom_ms *ms, struct msgb *msg)
static struct mmdatastate {
u_int32_t states;
int type;
- int (*rout) (struct gsm_trans *trans, struct msgb *msg);
+ int (*rout) (struct osmocom_ms *ms, struct msgb *msg);
} mmdatastatelist[] = {
{ALL_STATES, /* 4.3.1.2 */
GSM48_MT_MM_TMSI_REALL_CMD, gsm48_mm_rx_tmsi_realloc_cmd},
/* new status */
switch (mm->lupd_rej_cause) {
- case 11:
- case 12:
- case 13:
+ case GSM48_REJECT_PLMN_NOT_ALLOWED:
+ case GSM48_REJECT_LOC_NOT_ALLOWED:
+ case GSM48_REJECT_ROAMING_NOT_ALLOWED:
attempt_counter = 0;
// fall through
- case 2:
- case 3:
- case 6:
+ case GSM48_REJECT_IMSI_UNKNOWN_IN_HLR:
+ case GSM48_REJECT_IMSI_UNKNOWN_IN_HLR:
+ case GSM48_REJECT_ILLEGAL_ME:
new_sim_ustate(ms, GSM_MMUSTATE_U3_ROAMING_NA);
#ifdef TODO
sim: delete tmsi
/* forbidden list */
switch (mm->lupd_rej_cause) {
- case 2:
- case 3:
- case 6:
+ case GSM48_REJECT_IMSI_UNKNOWN_IN_HLR:
+ case GSM48_REJECT_IMSI_UNKNOWN_IN_HLR:
+ case GSM48_REJECT_ILLEGAL_ME:
/* sim becomes invalid */
subscr->sim_valid = 0;
break;
- case 11:
+ case GSM48_REJECT_PLMN_NOT_ALLOWED:
add_forbidden_list(ms, FORBIDDEN_PLMN, lai);
break;
- case 12:
+ case GSM48_REJECT_LOC_NOT_ALLOWED:
add_forbidden_list(ms, FORBIDDEN_LOC_AREA_RPOS, lai);
break;
- case 13:
+ case GSM48_REJECT_ROAMING_NOT_ALLOWED:
add_forbidden_list(ms, FORBIDDEN_LOC_AREA_ROAM, lai);
break;
default:
static struct rrdatastate {
u_int32_t states;
int type;
- int (*rout) (struct gsm_trans *trans, struct gsm_rr *msg);
+ int (*rout) (struct osmocom_ms *ms, struct msgb *msg);
} rrdatastatelist[] = {
{SBIT(GSM48_MM_ST_WAIT_RR_CONN_LUPD), /* 4.4.4.1 */
RR_ESTAB_CNF, gsm48_mm_est_loc_upd},
return rc;
}
-/* dequeue messages from RR */
-int gsm48_mm_queue(struct osmocom_ms *ms)
+/* dequeue messages from rr-sap */
+int gsm48_mm_dequeue_rr(struct osmocom_ms *ms)
{
- struct gsm48_mmlayer *mm = &ms->mmlayer;
+ struct gsm48_rrlayer *rr = &ms->rrlayer;
struct msgb *msg;
int work = 0;
- while ((msg = msgb_dequeue(&mm->up_queue))) {
+ while ((msg = msgb_dequeue(&rr->rr_upqueue))) {
/* message is also freed here */
gsm48_rcv_rr(ms, msg);
work = 1; /* work done */
}
+/* queue message to upper layer at mmxx-sap */
+int gsm48_mmxx_upmsg(struct osmocom_ms *ms, struct msgb *msg)
+{
+ struct gsm48_mmlayer *mm = &ms->mmlayer;
+
+ msgb_enqueue(&mm->mmxx_upqueue, msg);
+}
+
+
wichtig: nur eine MM connection zur zeit, da ja auch nur ein cm-service-request laufen kann. die anderen werden dann als "waiting" deklariert.