+ return gsm48_mm_sendmsg(ms, nmsg, rr_prim);
+}
+
+/* detach has ended */
+static int gsm48_mm_imsi_detach_end(struct osmocom_ms *ms, void *arg)
+{
+ struct msgb *nmsg;
+
+ /* stop IMSI detach timer (if running) */
+ gsm48_stop_mm_timer(mm, 0x3210);
+
+ /* update SIM */
+#ifdef TODO
+ sim: store BA list
+ sim: what else?:
+#endif
+
+ /* SIM invalid */
+ subscr->sim_valid = 0;
+
+ /* send SIM remove event to gsm322 */
+ nmsg = gsm322_msgb_alloc(GSM322_EVENT_SIM_REMOVE);
+ if (!nmsg)
+ return -ENOMEM;
+ gsm322_sendmsg(ms, nmsg);
+
+ /* return to MM IDLE / No SIM */
+ return gsm48_mm_return_idle(ms);
+}
+
+/* start an IMSI detach in MM IDLE */
+static int gsm48_mm_imsi_detach_start(struct osmocom_ms *ms, void *arg)
+{
+ struct gsm48_sysinfo *s = &ms->sysinfo;
+ struct msgb *nmsg;
+ struct gsm48_hdr *ngh;
+
+ /* we may silently finish IMSI detach */
+ if (!s->att_allowed)
+ return gsm48_mm_imsi_detach_silent(ms, arg);
+
+ new_mm_state(ms, GSM48_MM_ST_WAIT_RR_CONN_IMSI_D, 0);
+
+ /* establish RR and send IMSI detach */
+ return gsm48_mm_tx_imsi_detach(ms, RR_EST_REQ);
+}
+
+/* IMSI detach has been sent, wait for RR release */
+static int gsm48_mm_imsi_detach_sent(struct osmocom_ms *ms, void *arg)
+{
+ /* start T3220 (4.3.4.1) */
+ gsm48_start_mm_timer(mm, 0x3220, GSM48_T3220_MS);
+
+ new_mm_state(ms, GSM48_MM_ST_IMSI_DETACH_INIT, 0);
+
+ return 0;
+}
+
+/* release MM connection and proceed with IMSI detach */
+static int gsm48_mm_imsi_detach_release(struct osmocom_ms *ms, void *arg)
+{
+ release all connections
+
+ /* wait for release of RR */
+ if (!s->att_allowed) {
+ return new_mm_state(ms, GSM48_MM_ST_WAIT_NETWORK_CMD, 0);
+
+ /* send IMSI detach */
+ gsm48_mm_tx_imsi_detach(ms, RR_DATA_REQ);
+
+ /* go to sent state */
+ return gsm48_mm_imsi_detach_sent(ms, arg);
+}
+
+/* ignore ongoing IMSI detach */
+static int gsm48_mm_imsi_detach_ignore(struct osmocom_ms *ms, void *arg)
+{
+}
+
+/* delay until state change (and then retry) */
+static int gsm48_mm_imsi_detach_delay(struct osmocom_ms *ms, void *arg)
+{
+
+ /* remember to detach later */
+ mm->delay_detach = 1;
+
+ return 0;