diff options
-rw-r--r-- | src/host/layer23/include/osmocom/bb/mobile/gsm48_mm.h | 7 | ||||
-rw-r--r-- | src/host/layer23/include/osmocom/bb/mobile/gsm48_rr.h | 12 | ||||
-rw-r--r-- | src/host/layer23/src/mobile/gsm48_cc.c | 7 | ||||
-rw-r--r-- | src/host/layer23/src/mobile/gsm48_mm.c | 203 | ||||
-rw-r--r-- | src/host/layer23/src/mobile/gsm48_rr.c | 498 |
5 files changed, 601 insertions, 126 deletions
diff --git a/src/host/layer23/include/osmocom/bb/mobile/gsm48_mm.h b/src/host/layer23/include/osmocom/bb/mobile/gsm48_mm.h index afdcf020..fb62aae1 100644 --- a/src/host/layer23/include/osmocom/bb/mobile/gsm48_mm.h +++ b/src/host/layer23/include/osmocom/bb/mobile/gsm48_mm.h @@ -58,6 +58,7 @@ struct gsm48_mmxx_hdr { int msg_type; /* MMxx_* primitive */ uint32_t ref; /* reference to transaction */ uint32_t transaction_id; /* transaction identifier */ + uint8_t sapi; /* sapi */ uint8_t emergency; /* emergency type of call */ uint8_t cause; /* cause used for release */ }; @@ -193,6 +194,9 @@ struct gsm48_mmlayer { uint8_t est_cause; /* cause of establishment msg */ int mr_substate; /* rem most recent substate */ uint8_t power_off_idle; /* waits for IDLE before po */ + + /* sapi 3 */ + int sapi3_link; }; /* MM connection entry */ @@ -204,6 +208,7 @@ struct gsm48_mm_conn { uint32_t ref; /* reference to trans */ uint8_t protocol; uint8_t transaction_id; + uint8_t sapi; int state; }; @@ -221,7 +226,7 @@ int gsm48_mmr_dequeue(struct osmocom_ms *ms); int gsm48_mmevent_dequeue(struct osmocom_ms *ms); int gsm48_mmxx_downmsg(struct osmocom_ms *ms, struct msgb *msg); struct msgb *gsm48_mmxx_msgb_alloc(int msg_type, uint32_t ref, - uint8_t transaction_id); + uint8_t transaction_id, uint8_t sapi); const char *get_mmr_name(int value); const char *get_mmxx_name(int value); extern const char *gsm48_mm_state_names[]; diff --git a/src/host/layer23/include/osmocom/bb/mobile/gsm48_rr.h b/src/host/layer23/include/osmocom/bb/mobile/gsm48_rr.h index 118848bf..b7280fb4 100644 --- a/src/host/layer23/include/osmocom/bb/mobile/gsm48_rr.h +++ b/src/host/layer23/include/osmocom/bb/mobile/gsm48_rr.h @@ -54,6 +54,7 @@ /* GSM 04.08 RR-SAP header */ struct gsm48_rr_hdr { uint32_t msg_type; /* RR-* primitive */ + uint8_t sapi; uint8_t cause; }; @@ -63,6 +64,12 @@ struct gsm48_rr_hdr { #define GSM48_RR_ST_DEDICATED 2 #define GSM48_RR_ST_REL_PEND 3 +/* special states for SAPI 3 link */ +#define GSM48_RR_SAPI3ST_IDLE 0 +#define GSM48_RR_SAPI3ST_WAIT_EST 1 +#define GSM48_RR_SAPI3ST_ESTAB 2 +#define GSM48_RR_SAPI3ST_WAIT_REL 3 + /* modify state */ #define GSM48_RR_MOD_NONE 0 #define GSM48_RR_MOD_IMM_ASS 1 @@ -79,7 +86,6 @@ struct gsm48_rr_cd { uint8_t maio; uint8_t hsn; uint8_t chan_nr; /* type, slot, sub slot */ - uint8_t link_id; uint8_t ind_tx_power; /* last indicated power */ uint8_t ind_ta; /* last indicated ta */ uint8_t mob_alloc_lv[9]; /* len + up to 64 bits */ @@ -176,6 +182,10 @@ struct gsm48_rrlayer { /* audio flow */ uint8_t audio_mode; + + /* sapi 3 */ + uint8_t sapi3_state; + uint8_t sapi3_link_id; }; const char *get_rr_name(int value); diff --git a/src/host/layer23/src/mobile/gsm48_cc.c b/src/host/layer23/src/mobile/gsm48_cc.c index da47874a..38dfab02 100644 --- a/src/host/layer23/src/mobile/gsm48_cc.c +++ b/src/host/layer23/src/mobile/gsm48_cc.c @@ -173,6 +173,7 @@ static int gsm48_cc_to_mm(struct msgb *msg, struct gsm_trans *trans, mmh->msg_type = msg_type; mmh->ref = trans->callref; mmh->transaction_id = trans->transaction_id; + mmh->sapi = 0; mmh->emergency = emergency; /* send message to MM */ @@ -392,7 +393,7 @@ static int gsm48_rel_null_free(struct gsm_trans *trans) /* release MM connection */ nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMCC_REL_REQ, trans->callref, - trans->transaction_id); + trans->transaction_id, 0); if (!nmsg) return -ENOMEM; LOGP(DCC, LOGL_INFO, "Sending MMCC_REL_REQ\n"); @@ -497,7 +498,7 @@ static int gsm48_cc_init_mm(struct gsm_trans *trans, void *arg) /* establish MM connection */ nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMCC_EST_REQ, trans->callref, - trans->transaction_id); + trans->transaction_id, 0); if (!nmsg) return -ENOMEM; nmmh = (struct gsm48_mmxx_hdr *) nmsg->data; @@ -514,7 +515,7 @@ static int gsm48_cc_abort_mm(struct gsm_trans *trans, void *arg) /* abort MM connection */ nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMCC_REL_REQ, trans->callref, - trans->transaction_id); + trans->transaction_id, 0); if (!nmsg) return -ENOMEM; LOGP(DCC, LOGL_INFO, "Sending MMCC_REL_REQ\n"); diff --git a/src/host/layer23/src/mobile/gsm48_mm.c b/src/host/layer23/src/mobile/gsm48_mm.c index 4b435ac7..77fa7cff 100644 --- a/src/host/layer23/src/mobile/gsm48_mm.c +++ b/src/host/layer23/src/mobile/gsm48_mm.c @@ -661,7 +661,7 @@ const char *get_mmr_name(int value) /* allocate GSM 04.08 message (MMxx-SAP) */ struct msgb *gsm48_mmxx_msgb_alloc(int msg_type, uint32_t ref, - uint8_t transaction_id) + uint8_t transaction_id, uint8_t sapi) { struct msgb *msg; struct gsm48_mmxx_hdr *mmh; @@ -675,6 +675,7 @@ struct msgb *gsm48_mmxx_msgb_alloc(int msg_type, uint32_t ref, mmh->msg_type = msg_type; mmh->ref = ref; mmh->transaction_id = transaction_id; + mmh->sapi = sapi; return msg; } @@ -760,7 +761,7 @@ int gsm48_mmxx_dequeue(struct osmocom_ms *ms) gsm48_rcv_ss(ms, msg); break; case GSM48_MMSMS_CLASS: - gsm48_rcv_sms(ms, msg); + gsm411_rcv_sms(ms, msg); break; #endif } @@ -824,8 +825,8 @@ int gsm48_mmevent_dequeue(struct osmocom_ms *ms) } /* push RR header and send to RR */ -static int gsm48_mm_to_rr(struct osmocom_ms *ms, struct msgb *msg, - int msg_type, uint8_t cause) +static int gsm48_mm_to_rr(struct osmocom_ms *ms, struct msgb *msg, int msg_type, + uint8_t sapi, uint8_t cause) { struct gsm48_rr_hdr *rrh; @@ -833,6 +834,7 @@ static int gsm48_mm_to_rr(struct osmocom_ms *ms, struct msgb *msg, msgb_push(msg, sizeof(struct gsm48_rr_hdr)); rrh = (struct gsm48_rr_hdr *) msg->data; rrh->msg_type = msg_type; + rrh->sapi = sapi; rrh->cause = cause; /* send message to RR */ @@ -1414,7 +1416,7 @@ struct gsm48_mm_conn *mm_conn_by_ref(struct gsm48_mmlayer *mm, /* create MM connection instance */ static struct gsm48_mm_conn* mm_conn_new(struct gsm48_mmlayer *mm, - int proto, uint8_t transaction_id, uint32_t ref) + int proto, uint8_t transaction_id, uint8_t sapi, uint32_t ref) { struct gsm48_mm_conn *conn = talloc_zero(l23_ctx, struct gsm48_mm_conn); @@ -1422,12 +1424,13 @@ static struct gsm48_mm_conn* mm_conn_new(struct gsm48_mmlayer *mm, return NULL; LOGP(DMM, LOGL_INFO, "New MM Connection (proto 0x%02x trans_id %d " - "ref %d)\n", proto, transaction_id, ref); + "sapi %d ref %x)\n", proto, transaction_id, sapi, ref); conn->mm = mm; conn->state = GSM48_MMXX_ST_IDLE; conn->transaction_id = transaction_id; conn->protocol = proto; + conn->sapi = sapi; conn->ref = ref; llist_add(&conn->list, &mm->mm_conn); @@ -1449,22 +1452,27 @@ void mm_conn_free(struct gsm48_mm_conn *conn) /* support function to release pending/all ongoing MM connections */ static int gsm48_mm_release_mm_conn(struct osmocom_ms *ms, int abort_any, - uint8_t cause, int error) + uint8_t cause, int error, uint8_t sapi) { struct gsm48_mmlayer *mm = &ms->mmlayer; struct gsm48_mm_conn *conn, *conn2; struct msgb *nmsg; struct gsm48_mmxx_hdr *nmmh; + /* Note: For SAPI 0 all connections are released */ + if (abort_any) - LOGP(DMM, LOGL_INFO, "Release any MM Connection\n"); + LOGP(DMM, LOGL_INFO, "Release any MM Connection " + "(sapi = %d)\n", sapi); else - LOGP(DMM, LOGL_INFO, "Release pending MM Connections\n"); + LOGP(DMM, LOGL_INFO, "Release pending MM Connections " + "(sapi = %d)\n", sapi); /* release MM connection(s) */ llist_for_each_entry_safe(conn, conn2, &mm->mm_conn, list) { /* abort any OR the pending connection */ - if (abort_any || conn->state == GSM48_MMXX_ST_CONN_PEND) { + if ((abort_any || conn->state == GSM48_MMXX_ST_CONN_PEND) + && (sapi == conn->sapi || sapi == 0)) { /* send MMxx-REL-IND */ nmsg = NULL; switch(conn->protocol) { @@ -1472,19 +1480,22 @@ static int gsm48_mm_release_mm_conn(struct osmocom_ms *ms, int abort_any, nmsg = gsm48_mmxx_msgb_alloc( error ? GSM48_MMCC_ERR_IND : GSM48_MMCC_REL_IND, conn->ref, - conn->transaction_id); + conn->transaction_id, + conn->sapi); break; case GSM48_PDISC_NC_SS: nmsg = gsm48_mmxx_msgb_alloc( error ? GSM48_MMSS_ERR_IND : GSM48_MMSS_REL_IND, conn->ref, - conn->transaction_id); + conn->transaction_id, + conn->sapi); break; case GSM48_PDISC_SMS: nmsg = gsm48_mmxx_msgb_alloc( error ? GSM48_MMSMS_ERR_IND : GSM48_MMSMS_REL_IND, conn->ref, - conn->transaction_id); + conn->transaction_id, + conn->sapi); break; } if (!nmsg) { @@ -1526,7 +1537,7 @@ static int gsm48_mm_tx_mm_status(struct osmocom_ms *ms, uint8_t cause) *reject_cause = cause; /* push RR header and send down */ - return gsm48_mm_to_rr(ms, nmsg, GSM48_RR_DATA_REQ, 0); + return gsm48_mm_to_rr(ms, nmsg, GSM48_RR_DATA_REQ, 0, 0); } /* 4.3.1.2 sending TMSI REALLOCATION COMPLETE message */ @@ -1546,7 +1557,7 @@ static int gsm48_mm_tx_tmsi_reall_cpl(struct osmocom_ms *ms) ngh->msg_type = GSM48_MT_MM_TMSI_REALL_COMPL; /* push RR header and send down */ - return gsm48_mm_to_rr(ms, nmsg, GSM48_RR_DATA_REQ, 0); + return gsm48_mm_to_rr(ms, nmsg, GSM48_RR_DATA_REQ, 0, 0); } /* 4.3.1 TMSI REALLOCATION COMMAND is received */ @@ -1662,7 +1673,7 @@ static int gsm48_mm_tx_auth_rsp(struct osmocom_ms *ms, struct msgb *msg) memcpy(sres, mme->sres, 4); /* push RR header and send down */ - return gsm48_mm_to_rr(ms, nmsg, GSM48_RR_DATA_REQ, 0); + return gsm48_mm_to_rr(ms, nmsg, GSM48_RR_DATA_REQ, 0, 0); } /* 4.3.2.5 AUTHENTICATION REJECT is received */ @@ -1767,7 +1778,7 @@ static int gsm48_mm_tx_id_rsp(struct osmocom_ms *ms, uint8_t mi_type) gsm48_encode_mi(buf, nmsg, ms, mi_type); /* push RR header and send down */ - return gsm48_mm_to_rr(ms, nmsg, GSM48_RR_DATA_REQ, 0); + return gsm48_mm_to_rr(ms, nmsg, GSM48_RR_DATA_REQ, 0, 0); } /* 4.3.4.1 sending IMSI DETACH INDICATION message */ @@ -1815,7 +1826,7 @@ static int gsm48_mm_tx_imsi_detach(struct osmocom_ms *ms, int rr_prim) /* push RR header and send down */ mm->est_cause = RR_EST_CAUSE_OTHER_SDCCH; - return gsm48_mm_to_rr(ms, nmsg, rr_prim, mm->est_cause); + return gsm48_mm_to_rr(ms, nmsg, rr_prim, 0, mm->est_cause); } /* detach has ended */ @@ -1904,7 +1915,7 @@ static int gsm48_mm_imsi_detach_release(struct osmocom_ms *ms, struct msgb *msg) stop_mm_t3230(mm); /* release all connections */ - gsm48_mm_release_mm_conn(ms, 1, 16, 0); + gsm48_mm_release_mm_conn(ms, 1, 16, 0, 0); /* wait for release of RR */ if (!s->att_allowed || !subscr->imsi_attached) { @@ -1973,7 +1984,7 @@ static int gsm48_mm_rx_abort(struct osmocom_ms *ms, struct msgb *msg) /* stop MM connection timer */ stop_mm_t3230(mm); - gsm48_mm_release_mm_conn(ms, 1, 16, 0); + gsm48_mm_release_mm_conn(ms, 1, 16, 0, 0); } if (reject_cause == GSM48_REJECT_ILLEGAL_ME) { @@ -2344,7 +2355,7 @@ static int gsm48_mm_tx_loc_upd_req(struct osmocom_ms *ms) /* push RR header and send down */ mm->est_cause = RR_EST_CAUSE_LOC_UPD; - return gsm48_mm_to_rr(ms, nmsg, GSM48_RR_EST_REQ, mm->est_cause); + return gsm48_mm_to_rr(ms, nmsg, GSM48_RR_EST_REQ, 0, mm->est_cause); } /* 4.4.4.1 RR is esablised during location update */ @@ -2808,7 +2819,7 @@ static int gsm48_mm_tx_cm_serv_req(struct osmocom_ms *ms, int rr_prim, /* prio is optional for eMLPP */ /* push RR header and send down */ - return gsm48_mm_to_rr(ms, nmsg, rr_prim, mm->est_cause); + return gsm48_mm_to_rr(ms, nmsg, rr_prim, 0, mm->est_cause); } /* cm service abort message from upper layer @@ -2830,7 +2841,7 @@ static int gsm48_mm_tx_cm_service_abort(struct osmocom_ms *ms) ngh->msg_type = GSM48_MT_MM_CM_SERV_ABORT; /* push RR header and send down */ - return gsm48_mm_to_rr(ms, nmsg, GSM48_RR_DATA_REQ, 0); + return gsm48_mm_to_rr(ms, nmsg, GSM48_RR_DATA_REQ, 0, 0); } /* cm service acknowledge is received from lower layer */ @@ -2901,7 +2912,7 @@ static int gsm48_mm_rx_cm_service_rej(struct osmocom_ms *ms, struct msgb *msg) } /* release MM connection(s) */ - gsm48_mm_release_mm_conn(ms, abort_any, 16, 0); + gsm48_mm_release_mm_conn(ms, abort_any, 16, 0, 0); /* state depends on the existance of remaining MM connections */ if (llist_empty(&mm->mm_conn)) @@ -2931,6 +2942,7 @@ static int gsm48_mm_init_mm(struct osmocom_ms *ms, struct msgb *msg, struct msgb *nmsg; struct gsm48_mmxx_hdr *nmmh; struct gsm48_mm_conn *conn, *conn_found = NULL; + uint8_t sapi = mmh->sapi; /* reset loc. upd. counter on CM service request */ mm->lupd_attempt = 0; @@ -2948,20 +2960,24 @@ static int gsm48_mm_init_mm(struct osmocom_ms *ms, struct msgb *msg, LOGP(DMM, LOGL_INFO, "Init MM Connection, but already have " "pending MM Connection.\n"); cause = 17; + /* use sapi from connection. if no connection, use sapi from + * message. + */ + sapi = conn_found->sapi; reject: nmsg = NULL; switch(msg_type) { case GSM48_MMCC_EST_REQ: nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMCC_REL_IND, - mmh->ref, mmh->transaction_id); + mmh->ref, mmh->transaction_id, sapi); break; case GSM48_MMSS_EST_REQ: nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMSS_REL_IND, - mmh->ref, mmh->transaction_id); + mmh->ref, mmh->transaction_id, sapi); break; case GSM48_MMSMS_EST_REQ: nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMSMS_REL_IND, - mmh->ref, mmh->transaction_id); + mmh->ref, mmh->transaction_id, sapi); break; } if (!nmsg) @@ -3040,7 +3056,7 @@ static int gsm48_mm_init_mm(struct osmocom_ms *ms, struct msgb *msg, } /* create MM connection instance */ - conn = mm_conn_new(mm, proto, mmh->transaction_id, mmh->ref); + conn = mm_conn_new(mm, proto, mmh->transaction_id, mmh->sapi, mmh->ref); if (!conn) return -ENOMEM; @@ -3167,6 +3183,7 @@ static int gsm48_mm_init_mm_reject(struct osmocom_ms *ms, struct msgb *msg) { struct gsm48_mmxx_hdr *mmh = (struct gsm48_mmxx_hdr *)msg->data; int msg_type = mmh->msg_type; + int sapi = mmh->sapi; struct msgb *nmsg; struct gsm48_mmxx_hdr *nmmh; @@ -3175,15 +3192,15 @@ static int gsm48_mm_init_mm_reject(struct osmocom_ms *ms, struct msgb *msg) switch(msg_type) { case GSM48_MMCC_EST_REQ: nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMCC_REL_IND, mmh->ref, - mmh->transaction_id); + mmh->transaction_id, sapi); break; case GSM48_MMSS_EST_REQ: nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMSS_REL_IND, mmh->ref, - mmh->transaction_id); + mmh->transaction_id, sapi); break; case GSM48_MMSMS_EST_REQ: nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMSMS_REL_IND, mmh->ref, - mmh->transaction_id); + mmh->transaction_id, sapi); break; } if (!nmsg) @@ -3229,22 +3246,33 @@ static int gsm48_mm_conn_go_dedic(struct osmocom_ms *ms) nmsg = NULL; switch(conn_found->protocol) { case GSM48_PDISC_CC: - nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMCC_EST_CNF, conn->ref, - conn->transaction_id); + nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMCC_EST_CNF, + conn_found->ref, conn_found->transaction_id, + conn_found->sapi); break; case GSM48_PDISC_NC_SS: - nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMSS_EST_CNF, conn->ref, - conn->transaction_id); + nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMSS_EST_CNF, + conn_found->ref, conn_found->transaction_id, + conn_found->sapi); break; case GSM48_PDISC_SMS: - nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMSMS_EST_CNF, conn->ref, - conn->transaction_id); + if (!mm->sapi3_link) { + LOGP(DMM, LOGL_INFO, "Sapi 3 link down, requesting " + "link, waiting for confirm.\n"); + nmsg = gsm48_l3_msgb_alloc(); + if (!nmsg) + return -ENOMEM; + return gsm48_mm_to_rr(ms, nmsg, GSM48_RR_EST_REQ, + conn_found->sapi, 0); + } + nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMSMS_EST_CNF, + conn_found->ref, conn_found->transaction_id, + conn_found->sapi); break; } if (!nmsg) return -ENOMEM; nmmh = (struct gsm48_mmxx_hdr *)nmsg->data; - nmmh->cause = 17; gsm48_mmxx_upmsg(ms, nmsg); return 0; @@ -3288,13 +3316,12 @@ static int gsm48_mm_sync_ind_active(struct osmocom_ms *ms, struct msgb *msg) switch(conn->protocol) { case GSM48_PDISC_CC: nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMCC_SYNC_IND, - conn->ref, conn->transaction_id); + conn->ref, conn->transaction_id, conn->sapi); break; } if (!nmsg) continue; /* skip if not of CC type */ nmmh = (struct gsm48_mmxx_hdr *)nmsg->data; - nmmh->cause = 17; /* copy L3 message */ nmsg->l3h = msgb_put(nmsg, msgb_l3len(msg)); memcpy(nmsg->l3h, msg->l3h, msgb_l3len(msg)); @@ -3332,7 +3359,7 @@ static int gsm48_mm_abort_mm_con(struct osmocom_ms *ms, struct msgb *msg) stop_mm_t3230(mm); /* release all connections */ - gsm48_mm_release_mm_conn(ms, 1, cause, 1); + gsm48_mm_release_mm_conn(ms, 1, cause, 1, 0); /* return to MM IDLE */ return gsm48_mm_return_idle(ms, NULL); @@ -3344,7 +3371,7 @@ static int gsm48_mm_timeout_mm_con(struct osmocom_ms *ms, struct msgb *msg) struct gsm48_mmlayer *mm = &ms->mmlayer; /* release pending connection */ - gsm48_mm_release_mm_conn(ms, 0, 102, 0); + gsm48_mm_release_mm_conn(ms, 0, 102, 0, 0); /* state depends on the existance of remaining MM connections */ if (llist_empty(&mm->mm_conn)) { @@ -3399,11 +3426,14 @@ static int gsm48_mm_data(struct osmocom_ms *ms, struct msgb *msg) return gsm48_mmxx_upmsg(ms, msg); } + /* set SAPI, if upper layer does not do it correctly */ + mmh->sapi = conn->sapi; + /* pull MM header */ msgb_pull(msg, sizeof(struct gsm48_mmxx_hdr)); /* push RR header and send down */ - return gsm48_mm_to_rr(ms, msg, GSM48_RR_DATA_REQ, 0); + return gsm48_mm_to_rr(ms, msg, GSM48_RR_DATA_REQ, conn->sapi, 0); } /* release of MM connection (active state) */ @@ -3527,6 +3557,50 @@ static int gsm48_mm_rel_other(struct osmocom_ms *ms, struct msgb *msg) } /* + * sapi 3 + */ + +static int gsm48_rcv_rr_sapi3(struct osmocom_ms *ms, struct msgb *msg, + int msg_type, uint8_t sapi) +{ + struct gsm48_mmlayer *mm = &ms->mmlayer; + struct gsm48_mm_conn *conn; + + switch (msg_type) { + case GSM48_RR_EST_CNF: + LOGP(DMM, LOGL_INFO, "SAPI 3 link up, confirming conns.\n"); + mm->sapi3_link = 1; + /* indicate establishment to sapi 3 connections */ + llist_for_each_entry(conn, &mm->mm_conn, list) { + if (conn->sapi == sapi + && conn->state == GSM48_MMXX_ST_DEDICATED) { + struct gsm48_mmxx_hdr *nmmh; + struct msgb *nmsg; + + nmsg = gsm48_mmxx_msgb_alloc( + GSM48_MMSMS_EST_CNF, conn->ref, + conn->transaction_id, conn->sapi); + if (!nmsg) + return -ENOMEM; + nmmh = (struct gsm48_mmxx_hdr *)nmsg->data; + gsm48_mmxx_upmsg(ms, nmsg); + } + } + break; + case GSM48_RR_DATA_IND: + return gsm48_mm_data_ind(ms, msg); + case GSM48_RR_REL_IND: + LOGP(DMM, LOGL_INFO, "SAPI 3 link down, releasing conns.\n"); + mm->sapi3_link = 0; + gsm48_mm_release_mm_conn(ms, 1, 16, 0, sapi); + break; + } + msgb_free(msg); + + return 0; +} + +/* * state machines */ @@ -3803,11 +3877,15 @@ static int gsm48_rcv_rr(struct osmocom_ms *ms, struct msgb *msg) struct gsm48_mmlayer *mm = &ms->mmlayer; struct gsm48_rr_hdr *rrh = (struct gsm48_rr_hdr *)msg->data; int msg_type = rrh->msg_type; + int sapi = rrh->sapi; int i, rc; - LOGP(DMM, LOGL_INFO, "(ms %s) Received '%s' from RR in state %s\n", - ms->name, get_rr_name(msg_type), - gsm48_mm_state_names[mm->state]); + LOGP(DMM, LOGL_INFO, "(ms %s) Received '%s' from RR in state %s " + "(sapi %d)\n", ms->name, get_rr_name(msg_type), + gsm48_mm_state_names[mm->state], sapi); + + if (sapi) + return gsm48_rcv_rr_sapi3(ms, msg, msg_type, sapi); /* find function for current state and message */ for (i = 0; i < RRDATASLLEN; i++) @@ -3871,6 +3949,8 @@ static struct mmdatastate { static int gsm48_mm_data_ind(struct osmocom_ms *ms, struct msgb *msg) { struct gsm48_mmlayer *mm = &ms->mmlayer; + struct gsm48_rr_hdr *rrh = (struct gsm48_rr_hdr *)msg->data; + int sapi = rrh->sapi; struct gsm48_hdr *gh = msgb_l3(msg); uint8_t pdisc = gh->proto_discr & 0x0f; uint8_t msg_type = gh->msg_type & 0xbf; @@ -3881,12 +3961,15 @@ static int gsm48_mm_data_ind(struct osmocom_ms *ms, struct msgb *msg) int i, rc; /* 9.2.19 */ - if (msg_type == GSM48_MT_MM_NULL) + if (msg_type == GSM48_MT_MM_NULL) { + msgb_free(msg); return 0; + } if (mm->state == GSM48_MM_ST_IMSI_DETACH_INIT) { LOGP(DMM, LOGL_NOTICE, "DATA IND ignored during IMSI " "detach.\n"); + msgb_free(msg); return 0; } /* pull the RR header */ @@ -3903,11 +3986,11 @@ static int gsm48_mm_data_ind(struct osmocom_ms *ms, struct msgb *msg) rr_prim = GSM48_MMSS_DATA_IND; rr_est = GSM48_MMSS_EST_IND; break; +#endif case GSM48_PDISC_SMS: rr_prim = GSM48_MMSMS_DATA_IND; rr_est = GSM48_MMSMS_EST_IND; break; -#endif } if (rr_prim != -1) { uint8_t transaction_id = ((gh->proto_discr & 0xf0) ^ 0x80) >> 4; @@ -3919,18 +4002,22 @@ static int gsm48_mm_data_ind(struct osmocom_ms *ms, struct msgb *msg) /* create MM connection instance */ if (!conn) { - conn = mm_conn_new(mm, pdisc, transaction_id, + conn = mm_conn_new(mm, pdisc, transaction_id, sapi, mm_conn_new_ref++); rr_prim = rr_est; } - if (!conn) + if (!conn) { + msgb_free(msg); return -ENOMEM; + } /* push new header */ msgb_push(msg, sizeof(struct gsm48_mmxx_hdr)); mmh = (struct gsm48_mmxx_hdr *)msg->data; mmh->msg_type = rr_prim; mmh->ref = conn->ref; + mmh->transaction_id = conn->transaction_id; + mmh->sapi = conn->sapi; /* go MM CONN ACTIVE state */ if (mm->state == GSM48_MM_ST_WAIT_NETWORK_CMD @@ -3951,19 +4038,27 @@ static int gsm48_mm_data_ind(struct osmocom_ms *ms, struct msgb *msg) skip_ind = (gh->proto_discr & 0xf0) >> 4; /* ignore if skip indicator is not B'0000' */ - if (skip_ind) + if (skip_ind) { + msgb_free(msg); return 0; + } break; /* follow the selection proceedure below */ case GSM48_PDISC_CC: - return gsm48_rcv_cc(ms, msg); + rc = gsm48_rcv_cc(ms, msg); + msgb_free(msg); + return rc; #if 0 case GSM48_PDISC_NC_SS: - return gsm48_rcv_ss(ms, msg); + rc = gsm48_rcv_ss(ms, msg); + msgb_free(msg); + return rc; case GSM48_PDISC_SMS: - return gsm48_rcv_sms(ms, msg); + rc = gsm411_rcv_sms(ms, msg); + msgb_free(msg); + return rc; #endif default: diff --git a/src/host/layer23/src/mobile/gsm48_rr.c b/src/host/layer23/src/mobile/gsm48_rr.c index 547fd183..188e5451 100644 --- a/src/host/layer23/src/mobile/gsm48_rr.c +++ b/src/host/layer23/src/mobile/gsm48_rr.c @@ -422,6 +422,26 @@ static void new_rr_state(struct gsm48_rrlayer *rr, int state) } } +const char *gsm48_sapi3_state_names[] = { + "idle", + "wait establishment", + "established", + "wait release", +}; + +static void new_sapi3_state(struct gsm48_rrlayer *rr, int state) +{ + if (state < 0 || state >= + (sizeof(gsm48_sapi3_state_names) / sizeof(char *))) + return; + + LOGP(DRR, LOGL_INFO, "new SAPI 3 link state %s -> %s\n", + gsm48_sapi3_state_names[rr->sapi3_state], + gsm48_sapi3_state_names[state]); + + rr->sapi3_state = state; +} + /* * messages */ @@ -504,7 +524,7 @@ int gsm48_rr_upmsg(struct osmocom_ms *ms, struct msgb *msg) /* push rsl header and send (RSL-SAP) */ static int gsm48_send_rsl(struct osmocom_ms *ms, uint8_t msg_type, - struct msgb *msg) + struct msgb *msg, uint8_t link_id) { struct gsm48_rrlayer *rr = &ms->rrlayer; @@ -512,20 +532,19 @@ static int gsm48_send_rsl(struct osmocom_ms *ms, uint8_t msg_type, LOGP(DRR, LOGL_ERROR, "FIX l3h\n"); return -EINVAL; } - rsl_rll_push_l3(msg, msg_type, rr->cd_now.chan_nr, - rr->cd_now.link_id, 1); + rsl_rll_push_l3(msg, msg_type, rr->cd_now.chan_nr, link_id, 1); return lapdm_rslms_recvmsg(msg, &ms->lapdm_channel); } -/* push rsl header + release mode and send (RSL-SAP) */ -static int gsm48_send_rsl_rel(struct osmocom_ms *ms, uint8_t msg_type, - struct msgb *msg) +/* push rsl header without L3 info and send (RSL-SAP) */ +static int gsm48_send_rsl_nol3(struct osmocom_ms *ms, uint8_t msg_type, + struct msgb *msg, uint8_t link_id) { struct gsm48_rrlayer *rr = &ms->rrlayer; rsl_rll_push_hdr(msg, msg_type, rr->cd_now.chan_nr, - rr->cd_now.link_id, 1); + link_id, 1); return lapdm_rslms_recvmsg(msg, &ms->lapdm_channel); } @@ -571,6 +590,43 @@ int gsm48_rr_stop_monitor(struct osmocom_ms *ms) return 0; } +/* release L3 link in both directions in case of main link release */ +static int gsm48_release_sapi3_link(struct osmocom_ms *ms) +{ + struct gsm48_rrlayer *rr = &ms->rrlayer; + struct gsm48_rr_hdr *nrrh; + struct msgb *nmsg; + uint8_t *mode; + + if (rr->sapi3_state == GSM48_RR_SAPI3ST_IDLE) + return 0; + + LOGP(DRR, LOGL_INFO, "Main signallin link is down, so release SAPI 3 " + "link locally.\n"); + + new_sapi3_state(rr, GSM48_RR_SAPI3ST_IDLE); + + /* disconnect the SAPI 3 signalling link */ + nmsg = gsm48_l3_msgb_alloc(); + if (!nmsg) + return -ENOMEM; + mode = msgb_put(nmsg, 2); + mode[0] = RSL_IE_RELEASE_MODE; + mode[1] = 1; /* local release */ + gsm48_send_rsl_nol3(ms, RSL_MT_REL_REQ, nmsg, rr->sapi3_link_id); + + /* send inication to upper layer */ + nmsg = gsm48_rr_msgb_alloc(GSM48_RR_REL_IND); + if (!nmsg) + return -ENOMEM; + nrrh = (struct gsm48_rr_hdr *)nmsg->data; + nrrh->cause = RR_REL_CAUSE_NORMAL; + nrrh->sapi = rr->sapi3_link_id & 7; + gsm48_rr_upmsg(ms, nmsg); + + return 0; +} + /* * timers handling */ @@ -646,7 +702,11 @@ static void timeout_rr_t_starting(void *arg) nmsg = gsm48_l3_msgb_alloc(); if (!nmsg) return; - gsm48_send_rsl(rr->ms, RSL_MT_SUSP_REQ, nmsg); + gsm48_send_rsl(rr->ms, RSL_MT_SUSP_REQ, nmsg, 0); + + /* release SAPI 3 link, if exits + * FIXME: suspend and resume afterward */ + gsm48_release_sapi3_link(rr->ms); } /* special timer to ensure that UA is sent before disconnecting channel */ @@ -679,7 +739,10 @@ static void timeout_rr_t3110(void *arg) mode = msgb_put(nmsg, 2); mode[0] = RSL_IE_RELEASE_MODE; mode[1] = 1; /* local release */ - gsm48_send_rsl_rel(ms, RSL_MT_REL_REQ, nmsg); + gsm48_send_rsl_nol3(ms, RSL_MT_REL_REQ, nmsg, 0); + + /* release SAPI 3 link, if exits */ + gsm48_release_sapi3_link(ms); return; } @@ -857,7 +920,7 @@ static int gsm48_rr_tx_rr_status(struct osmocom_ms *ms, uint8_t cause) /* rr cause */ st->rr_cause = cause; - return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg); + return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg, 0); } /* @@ -892,7 +955,7 @@ static int gsm48_rr_tx_cip_mode_cpl(struct osmocom_ms *ms, uint8_t cr) memcpy(tlv, buf, 2 + buf[1]); } - gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg); + gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg, 0); /* send RR_SYNC_IND(ciphering) */ nmsg = gsm48_rr_msgb_alloc(GSM48_RR_SYNC_IND); @@ -1224,7 +1287,7 @@ static int gsm48_rr_tx_cm_change(struct osmocom_ms *ms) memcpy(tlv, cm3, 2 + cm3[1]); } - return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg); + return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg, 0); } /* receiving classmark enquiry */ @@ -2863,7 +2926,10 @@ int gsm48_rr_los(struct osmocom_ms *ms) mode[0] = RSL_IE_RELEASE_MODE; mode[1] = 1; /* local release */ /* start release */ - return gsm48_send_rsl_rel(ms, RSL_MT_REL_REQ, nmsg); + gsm48_send_rsl_nol3(ms, RSL_MT_REL_REQ, nmsg, 0); + /* release SAPI 3 link, if exits */ + gsm48_release_sapi3_link(ms); + return 0; case GSM48_RR_ST_REL_PEND: LOGP(DRR, LOGL_INFO, "LOS during RR release procedure, release " "locally\n"); @@ -3230,7 +3296,7 @@ static int gsm48_rr_dl_est(struct osmocom_ms *ms) #endif /* start establishmnet */ - return gsm48_send_rsl(ms, RSL_MT_EST_REQ, nmsg); + return gsm48_send_rsl(ms, RSL_MT_EST_REQ, nmsg, 0); } /* the link is established */ @@ -3251,7 +3317,7 @@ static int gsm48_rr_estab_cnf(struct osmocom_ms *ms, struct msgb *msg) mode[0] = RSL_IE_RELEASE_MODE; mode[1] = 0; /* normal release */ /* start release */ - return gsm48_send_rsl_rel(ms, RSL_MT_REL_REQ, nmsg); + return gsm48_send_rsl_nol3(ms, RSL_MT_REL_REQ, nmsg, 0); } /* 3.3.1.1.4 */ @@ -3300,6 +3366,9 @@ static int gsm48_rr_rel_ind(struct osmocom_ms *ms, struct msgb *msg) /* pending release */ new_rr_state(rr, GSM48_RR_ST_REL_PEND); + /* also release SAPI 3 link, if exists */ + gsm48_release_sapi3_link(ms); + return 0; } @@ -3348,7 +3417,11 @@ static int gsm48_rr_rx_chan_rel(struct osmocom_ms *ms, struct msgb *msg) mode = msgb_put(nmsg, 2); mode[0] = RSL_IE_RELEASE_MODE; mode[1] = 0; /* normal release */ - return gsm48_send_rsl_rel(ms, RSL_MT_REL_REQ, nmsg); + gsm48_send_rsl_nol3(ms, RSL_MT_REL_REQ, nmsg, 0); + + /* release SAPI 3 link, if exits */ + gsm48_release_sapi3_link(ms); + return 0; } /* @@ -3483,7 +3556,7 @@ static int gsm48_rr_tx_chan_modify_ack(struct osmocom_ms *ms, /* mode */ cm->mode = mode; - return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg); + return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg, 0); } /* 9.1.5 CHANNEL MODE MODIFY is received */ @@ -3561,7 +3634,7 @@ static int gsm48_rr_tx_ass_cpl(struct osmocom_ms *ms, uint8_t cause) /* RR_CAUSE */ ac->rr_cause = cause; - return gsm48_send_rsl(ms, RSL_MT_RES_REQ, nmsg); + return gsm48_send_rsl(ms, RSL_MT_RES_REQ, nmsg, 0); } /* 9.1.4 sending ASSIGNMENT FAILURE */ @@ -3586,7 +3659,7 @@ static int gsm48_rr_tx_ass_fail(struct osmocom_ms *ms, uint8_t cause, /* RR_CAUSE */ af->rr_cause = cause; - return gsm48_send_rsl(ms, rsl_prim, nmsg); + return gsm48_send_rsl(ms, rsl_prim, nmsg, 0); } /* 9.1.2 ASSIGNMENT COMMAND is received */ @@ -3896,7 +3969,11 @@ static int gsm48_rr_rx_ass_cmd(struct osmocom_ms *ms, struct msgb *msg) nmsg = gsm48_l3_msgb_alloc(); if (!nmsg) return -ENOMEM; - gsm48_send_rsl(ms, RSL_MT_SUSP_REQ, nmsg); + gsm48_send_rsl(ms, RSL_MT_SUSP_REQ, nmsg, 0); + + /* release SAPI 3 link, if exits + * FIXME: suspend and resume afterward */ + gsm48_release_sapi3_link(ms); return 0; } @@ -3924,7 +4001,7 @@ static int gsm48_rr_tx_hando_cpl(struct osmocom_ms *ms, uint8_t cause) // FIXME: mobile observed time - return gsm48_send_rsl(ms, RSL_MT_RES_REQ, nmsg); + return gsm48_send_rsl(ms, RSL_MT_RES_REQ, nmsg, 0); } /* 9.1.4 sending HANDOVER FAILURE */ @@ -3949,7 +4026,7 @@ static int gsm48_rr_tx_hando_fail(struct osmocom_ms *ms, uint8_t cause, /* RR_CAUSE */ hf->rr_cause = cause; - return gsm48_send_rsl(ms, rsl_prim, nmsg); + return gsm48_send_rsl(ms, rsl_prim, nmsg, 0); } /* receiving HANDOVER COMMAND message (9.1.15) */ @@ -4282,7 +4359,11 @@ static int gsm48_rr_rx_hando_cmd(struct osmocom_ms *ms, struct msgb *msg) nmsg = gsm48_l3_msgb_alloc(); if (!nmsg) return -ENOMEM; - gsm48_send_rsl(ms, RSL_MT_SUSP_REQ, nmsg); + gsm48_send_rsl(ms, RSL_MT_SUSP_REQ, nmsg, 0); + + /* release SAPI 3 link, if exits + * FIXME: suspend and resume afterward */ + gsm48_release_sapi3_link(ms); return 0; } @@ -4294,8 +4375,16 @@ static int gsm48_rr_dequeue_down(struct osmocom_ms *ms) struct msgb *msg; while((msg = msgb_dequeue(&rr->downqueue))) { + struct gsm48_rr_hdr *rrh = (struct gsm48_rr_hdr *) msg->data; + uint8_t sapi = rrh->sapi; + LOGP(DRR, LOGL_INFO, "Sending queued message.\n"); - gsm48_send_rsl(ms, RSL_MT_DATA_REQ, msg); + if (sapi && rr->sapi3_state != GSM48_RR_SAPI3ST_ESTAB) { + LOGP(DRR, LOGL_INFO, "Dropping SAPI 3 msg, no link!\n"); + msgb_free(msg); + return 0; + } + gsm48_send_rsl(ms, RSL_MT_DATA_REQ, msg, 0); } return 0; @@ -4496,6 +4585,8 @@ static int gsm48_rr_est_req(struct osmocom_ms *ms, struct msgb *msg) static int gsm48_rr_data_req(struct osmocom_ms *ms, struct msgb *msg) { struct gsm48_rrlayer *rr = &ms->rrlayer; + struct gsm48_rr_hdr *rrh = (struct gsm48_rr_hdr *) msg->data; + uint8_t sapi = rrh->sapi; if (rr->state != GSM48_RR_ST_DEDICATED) { msgb_free(msg); @@ -4516,8 +4607,15 @@ static int gsm48_rr_data_req(struct osmocom_ms *ms, struct msgb *msg) return 0; } + if (sapi && rr->sapi3_state != GSM48_RR_SAPI3ST_ESTAB) { + LOGP(DRR, LOGL_INFO, "Dropping SAPI 3 msg, no link!\n"); + msgb_free(msg); + return 0; + } + /* forward message */ - return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, msg); + return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, msg, + sapi ? rr->sapi3_link_id : 0); } /* @@ -4779,7 +4877,11 @@ static int gsm48_rr_abort_req(struct osmocom_ms *ms, struct msgb *msg) mode = msgb_put(nmsg, 2); mode[0] = RSL_IE_RELEASE_MODE; mode[1] = 0; /* normal release */ - return gsm48_send_rsl_rel(ms, RSL_MT_REL_REQ, nmsg); + gsm48_send_rsl_nol3(ms, RSL_MT_REL_REQ, nmsg, 0); + + /* release SAPI 3 link, if exits */ + gsm48_release_sapi3_link(ms); + return 0; } LOGP(DRR, LOGL_INFO, "Abort in connection pending state, return to " @@ -4867,6 +4969,7 @@ static int gsm48_rr_mdl_error_ind(struct osmocom_ms *ms, struct msgb *msg) struct gsm48_rr_hdr *nrrh; uint8_t *mode; uint8_t cause = rllh->data[2]; + uint8_t link_id = rllh->link_id; switch (cause) { case RLL_CAUSE_SEQ_ERR: @@ -4879,14 +4982,14 @@ static int gsm48_rr_mdl_error_ind(struct osmocom_ms *ms, struct msgb *msg) LOGP(DRR, LOGL_NOTICE, "MDL-Error (cause %d) aborting\n", cause); - /* disconnect the main signalling link */ + /* disconnect the (main) signalling link */ nmsg = gsm48_l3_msgb_alloc(); if (!nmsg) return -ENOMEM; mode = msgb_put(nmsg, 2); mode[0] = RSL_IE_RELEASE_MODE; mode[1] = 1; /* local release */ - gsm48_send_rsl_rel(ms, RSL_MT_REL_REQ, nmsg); + gsm48_send_rsl_nol3(ms, RSL_MT_REL_REQ, nmsg, link_id); /* in case of modify/hando: wait for confirm */ if (rr->modify_state) @@ -4898,13 +5001,191 @@ static int gsm48_rr_mdl_error_ind(struct osmocom_ms *ms, struct msgb *msg) return -ENOMEM; nrrh = (struct gsm48_rr_hdr *)nmsg->data; nrrh->cause = RR_REL_CAUSE_LINK_FAILURE; + nrrh->sapi = link_id & 7; gsm48_rr_upmsg(ms, nmsg); - /* return idle */ - new_rr_state(rr, GSM48_RR_ST_IDLE); + /* only for main signalling link */ + if ((link_id & 7) == 0) { + /* return idle */ + new_rr_state(rr, GSM48_RR_ST_IDLE); + /* release SAPI 3 link, if exits */ + gsm48_release_sapi3_link(ms); + } else { + new_sapi3_state(rr, GSM48_RR_SAPI3ST_IDLE); + LOGP(DSUM, LOGL_INFO, "Radio link SAPI3 failed\n"); + } return 0; } +static int gsm48_rr_estab_ind_sapi3(struct osmocom_ms *ms, struct msgb *msg) +{ + struct gsm48_rrlayer *rr = &ms->rrlayer; + struct abis_rsl_rll_hdr *rllh = msgb_l2(msg); + uint8_t link_id = rllh->link_id; + struct msgb *nmsg; + struct gsm48_rr_hdr *nrrh; + + if (rr->state != GSM48_RR_ST_DEDICATED) { + /* disconnect sapi 3 link */ + gsm48_release_sapi3_link(ms); + return -EINVAL; + } + + new_sapi3_state(rr, GSM48_RR_SAPI3ST_ESTAB); + rr->sapi3_link_id = link_id; /* set link ID */ + + LOGP(DSUM, LOGL_INFO, "Radio link SAPI3 is established\n"); + + /* send inication to upper layer */ + nmsg = gsm48_rr_msgb_alloc(GSM48_RR_EST_IND); + if (!nmsg) + return -ENOMEM; + nrrh = (struct gsm48_rr_hdr *)nmsg->data; + nrrh->sapi = link_id & 7; + + return gsm48_rr_upmsg(ms, nmsg); +} + +static int gsm48_rr_estab_cnf_sapi3(struct osmocom_ms *ms, struct msgb *msg) +{ + struct gsm48_rrlayer *rr = &ms->rrlayer; + struct abis_rsl_rll_hdr *rllh = msgb_l2(msg); + uint8_t link_id = rllh->link_id; + struct msgb *nmsg; + struct gsm48_rr_hdr *nrrh; + + if (rr->state != GSM48_RR_ST_DEDICATED) { + gsm48_release_sapi3_link(ms); + return -EINVAL; + } + + new_sapi3_state(rr, GSM48_RR_SAPI3ST_ESTAB); + rr->sapi3_link_id = link_id; /* set link ID, just to be sure */ + + LOGP(DSUM, LOGL_INFO, "Radio link SAPI3 is established\n"); + + /* send inication to upper layer */ + nmsg = gsm48_rr_msgb_alloc(GSM48_RR_EST_CNF); + if (!nmsg) + return -ENOMEM; + nrrh = (struct gsm48_rr_hdr *)nmsg->data; + nrrh->sapi = link_id & 7; + + return gsm48_rr_upmsg(ms, nmsg); +} + +/* 3.4.2 data from layer 2 to RR and upper layer (sapi 3)*/ +static int gsm48_rr_data_ind_sapi3(struct osmocom_ms *ms, struct msgb *msg) +{ + struct abis_rsl_rll_hdr *rllh = msgb_l2(msg); + uint8_t sapi = rllh->link_id & 7; + struct gsm48_hdr *gh = msgb_l3(msg); + struct gsm48_rr_hdr *rrh; + uint8_t pdisc = gh->proto_discr & 0x0f; + + if (pdisc == GSM48_PDISC_RR) { + msgb_free(msg); + return -EINVAL; + } + + /* pull off RSL header up to L3 message */ + msgb_pull(msg, (long)msgb_l3(msg) - (long)msg->data); + + /* push RR header */ + msgb_push(msg, sizeof(struct gsm48_rr_hdr)); + rrh = (struct gsm48_rr_hdr *)msg->data; + rrh->msg_type = GSM48_RR_DATA_IND; + rrh->sapi = sapi; + + return gsm48_rr_upmsg(ms, msg); +} + +static int gsm48_rr_rel_ind_sapi3(struct osmocom_ms *ms, struct msgb *msg) +{ + struct gsm48_rrlayer *rr = &ms->rrlayer; + struct abis_rsl_rll_hdr *rllh = msgb_l2(msg); + uint8_t link_id = rllh->link_id; + struct msgb *nmsg; + struct gsm48_rr_hdr *nrrh; + + new_sapi3_state(rr, GSM48_RR_SAPI3ST_IDLE); + + LOGP(DSUM, LOGL_INFO, "Radio link SAPI3 is released\n"); + + /* send inication to upper layer */ + nmsg = gsm48_rr_msgb_alloc(GSM48_RR_REL_IND); + if (!nmsg) + return -ENOMEM; + nrrh = (struct gsm48_rr_hdr *)nmsg->data; + nrrh->cause = RR_REL_CAUSE_NORMAL; + nrrh->sapi = link_id & 7; + + return gsm48_rr_upmsg(ms, nmsg); +} + +/* request SAPI 3 establishment */ +static int gsm48_rr_est_req_sapi3(struct osmocom_ms *ms, struct msgb *msg) +{ + struct gsm48_rrlayer *rr = &ms->rrlayer; + uint8_t ch_type, ch_subch, ch_ts; + struct gsm48_rr_hdr *rrh = (struct gsm48_rr_hdr *) msg->data; + uint8_t sapi = rrh->sapi; + struct msgb *nmsg; + + if (rr->state != GSM48_RR_ST_DEDICATED) { + struct gsm48_rr_hdr *nrrh; + + /* send inication to upper layer */ + nmsg = gsm48_rr_msgb_alloc(GSM48_RR_REL_IND); + if (!nmsg) + return -ENOMEM; + nrrh = (struct gsm48_rr_hdr *)nmsg->data; + nrrh->cause = RR_REL_CAUSE_NORMAL; + nrrh->sapi = sapi; + return gsm48_rr_upmsg(ms, nmsg); + } + + rsl_dec_chan_nr(rr->cd_now.chan_nr, &ch_type, &ch_subch, &ch_ts); + if (ch_type != RSL_CHAN_Bm_ACCHs + && ch_type != RSL_CHAN_Lm_ACCHs) { + LOGP(DRR, LOGL_INFO, "Requesting DCCH link, because no TCH " + "(sapi %d)\n", sapi); + rr->sapi3_link_id = 0x00 | sapi; /* SAPI 3, DCCH */ + } else { + LOGP(DRR, LOGL_INFO, "Requesting ACCH link, because TCH " + "(sapi %d)\n", sapi); + rr->sapi3_link_id = 0x40 | sapi; /* SAPI 3, ACCH */ + } + + /* already established */ + new_sapi3_state(rr, GSM48_RR_SAPI3ST_WAIT_EST); + + /* send message */ + nmsg = gsm48_l3_msgb_alloc(); + if (!nmsg) + return -ENOMEM; + return gsm48_send_rsl_nol3(ms, RSL_MT_EST_REQ, nmsg, rr->sapi3_link_id); +} + +static int gsm48_rr_est_req_estab_sapi3(struct osmocom_ms *ms, struct msgb *msg) +{ + struct gsm48_rr_hdr *rrh = (struct gsm48_rr_hdr *) msg->data; + uint8_t sapi = rrh->sapi; + struct msgb *nmsg; + struct gsm48_rr_hdr *nrrh; + + LOGP(DRR, LOGL_INFO, "Radio link SAPI3 already established\n"); + + /* send inication to upper layer */ + nmsg = gsm48_rr_msgb_alloc(GSM48_RR_EST_CNF); + if (!nmsg) + return -ENOMEM; + nrrh = (struct gsm48_rr_hdr *)nmsg->data; + nrrh->sapi = sapi; + + return gsm48_rr_upmsg(ms, nmsg); +} + /* * state machines */ @@ -4915,6 +5196,8 @@ static struct dldatastate { int type; int (*rout) (struct osmocom_ms *ms, struct msgb *msg); } dldatastatelist[] = { + /* SAPI 0 on DCCH */ + /* data transfer */ {SBIT(GSM48_RR_ST_IDLE) | SBIT(GSM48_RR_ST_CONN_PEND) | @@ -4964,35 +5247,79 @@ static struct dldatastate { #define DLDATASLLEN \ (sizeof(dldatastatelist) / sizeof(struct dldatastate)) +static struct dldatastate dldatastatelists3[] = { + /* SAPI 3 on DCCH */ + + /* establish */ + {SBIT(GSM48_RR_SAPI3ST_IDLE), + RSL_MT_EST_IND, gsm48_rr_estab_ind_sapi3}, + + /* establish */ + {SBIT(GSM48_RR_SAPI3ST_IDLE) | SBIT(GSM48_RR_SAPI3ST_WAIT_EST), + RSL_MT_EST_CONF, gsm48_rr_estab_cnf_sapi3}, + + /* data transfer */ + {SBIT(GSM48_RR_SAPI3ST_ESTAB), + RSL_MT_DATA_IND, gsm48_rr_data_ind_sapi3}, + + /* release */ + {SBIT(GSM48_RR_SAPI3ST_WAIT_EST) | SBIT(GSM48_RR_SAPI3ST_ESTAB), + RSL_MT_REL_IND, gsm48_rr_rel_ind_sapi3}, + + {ALL_STATES, + RSL_MT_ERROR_IND, gsm48_rr_mdl_error_ind}, +}; + +#define DLDATASLLENS3 \ + (sizeof(dldatastatelists3) / sizeof(struct dldatastate)) + static int gsm48_rcv_rll(struct osmocom_ms *ms, struct msgb *msg) { struct gsm48_rrlayer *rr = &ms->rrlayer; struct abis_rsl_rll_hdr *rllh = msgb_l2(msg); int msg_type = rllh->c.msg_type; + int link_id = rllh->link_id; int i; int rc; - if (msg_type != RSL_MT_UNIT_DATA_IND) { - LOGP(DRSL, LOGL_INFO, "(ms %s) Received '%s' from L2 in state " - "%s\n", ms->name, rsl_msg_name(msg_type), - gsm48_rr_state_names[rr->state]); - } + LOGP(DRSL, LOGL_INFO, "(ms %s) Received '%s' from L2 in state " + "%s (link_id 0x%x)\n", ms->name, rsl_msg_name(msg_type), + gsm48_rr_state_names[rr->state], link_id); /* find function for current state and message */ - for (i = 0; i < DLDATASLLEN; i++) - if ((msg_type == dldatastatelist[i].type) - && ((1 << rr->state) & dldatastatelist[i].states)) - break; - if (i == DLDATASLLEN) { - LOGP(DRSL, LOGL_NOTICE, "RSLms message unhandled\n"); - msgb_free(msg); - return 0; - } + if (!(link_id & 7)) { + /* SAPI 0 */ + for (i = 0; i < DLDATASLLEN; i++) + if ((msg_type == dldatastatelist[i].type) + && ((1 << rr->state) & dldatastatelist[i].states)) + break; + if (i == DLDATASLLEN) { + LOGP(DRSL, LOGL_NOTICE, "RSLms message '%s' " + "unhandled\n", rsl_msg_name(msg_type)); + msgb_free(msg); + return 0; + } - rc = dldatastatelist[i].rout(ms, msg); + rc = dldatastatelist[i].rout(ms, msg); + } else { + /* SAPI 3 */ + for (i = 0; i < DLDATASLLENS3; i++) + if ((msg_type == dldatastatelists3[i].type) + && ((1 << rr->sapi3_state) & + dldatastatelists3[i].states)) + break; + if (i == DLDATASLLENS3) { + LOGP(DRSL, LOGL_NOTICE, "RSLms message '%s' " + "unhandled\n", rsl_msg_name(msg_type)); + msgb_free(msg); + return 0; + } + + rc = dldatastatelists3[i].rout(ms, msg); + } /* free msgb unless it is forwarded */ - if (dldatastatelist[i].rout != gsm48_rr_data_ind) + if (msg_type != RSL_MT_DATA_IND) msgb_free(msg); return rc; @@ -5047,12 +5374,14 @@ static int gsm48_rcv_rsl(struct osmocom_ms *ms, struct msgb *msg) return rc; } -/* state trasitions for RR-SAP messages from up */ +/* state trasitions for RR-SAP messages from up (main link) */ static struct rrdownstate { uint32_t states; int type; int (*rout) (struct osmocom_ms *ms, struct msgb *msg); } rrdownstatelist[] = { + /* SAPI 0 */ + /* NOTE: If not IDLE, it is rejected there. */ {ALL_STATES, /* 3.3.1.1 */ GSM48_RR_EST_REQ, gsm48_rr_est_req}, @@ -5068,33 +5397,69 @@ static struct rrdownstate { #define RRDOWNSLLEN \ (sizeof(rrdownstatelist) / sizeof(struct rrdownstate)) +/* state trasitions for RR-SAP messages from up with (SAPI 3) */ +static struct rrdownstate rrdownstatelists3[] = { + /* SAPI 3 */ + + {SBIT(GSM48_RR_SAPI3ST_IDLE), + GSM48_RR_EST_REQ, gsm48_rr_est_req_sapi3}, + + {SBIT(GSM48_RR_SAPI3ST_ESTAB), + GSM48_RR_EST_REQ, gsm48_rr_est_req_estab_sapi3}, + + {SBIT(GSM48_RR_SAPI3ST_ESTAB), + GSM48_RR_DATA_REQ, gsm48_rr_data_req}, /* handles SAPI 3 too */ +}; + +#define RRDOWNSLLENS3 \ + (sizeof(rrdownstatelists3) / sizeof(struct rrdownstate)) + int gsm48_rr_downmsg(struct osmocom_ms *ms, struct msgb *msg) { struct gsm48_rrlayer *rr = &ms->rrlayer; struct gsm48_rr_hdr *rrh = (struct gsm48_rr_hdr *) msg->data; int msg_type = rrh->msg_type; + int sapi = rrh->sapi; int i; int rc; - LOGP(DRR, LOGL_INFO, "(ms %s) Message '%s' received in state %s\n", - ms->name, get_rr_name(msg_type), - gsm48_rr_state_names[rr->state]); + LOGP(DRR, LOGL_INFO, "(ms %s) Message '%s' received in state %s " + "(sapi %d)\n", ms->name, get_rr_name(msg_type), + gsm48_rr_state_names[rr->state], sapi); - /* find function for current state and message */ - for (i = 0; i < RRDOWNSLLEN; i++) - if ((msg_type == rrdownstatelist[i].type) - && ((1 << rr->state) & rrdownstatelist[i].states)) - break; - if (i == RRDOWNSLLEN) { - LOGP(DRR, LOGL_NOTICE, "Message unhandled at this state.\n"); - msgb_free(msg); - return 0; - } + if (!sapi) { + /* SAPI 0: find function for current state and message */ + for (i = 0; i < RRDOWNSLLEN; i++) + if ((msg_type == rrdownstatelist[i].type) + && ((1 << rr->state) & rrdownstatelist[i].states)) + break; + if (i == RRDOWNSLLEN) { + LOGP(DRR, LOGL_NOTICE, "Message unhandled at this " + "state.\n"); + msgb_free(msg); + return 0; + } + + rc = rrdownstatelist[i].rout(ms, msg); + } else { + /* SAPI 3: find function for current state and message */ + for (i = 0; i < RRDOWNSLLENS3; i++) + if ((msg_type == rrdownstatelists3[i].type) + && ((1 << rr->sapi3_state) + & rrdownstatelists3[i].states)) + break; + if (i == RRDOWNSLLENS3) { + LOGP(DRR, LOGL_NOTICE, "Message unhandled at this " + "state.\n"); + msgb_free(msg); + return 0; + } - rc = rrdownstatelist[i].rout(ms, msg); + rc = rrdownstatelists3[i].rout(ms, msg); + } - /* free msgb uless it is forwarded */ - if (rrdownstatelist[i].rout != gsm48_rr_data_req) + /* free msgb unless it is forwarded */ + if (msg_type != GSM48_RR_DATA_REQ) msgb_free(msg); return rc; @@ -5180,7 +5545,7 @@ static void timeout_rr_t3124(void *arg) nmsg = gsm48_l3_msgb_alloc(); if (!nmsg) return -ENOMEM; - return gsm48_send_rsl(ms, RSL_MT_REEST_REQ, nmsg); + return gsm48_send_rsl(ms, RSL_MT_REEST_REQ, nmsg, 0); todo } @@ -5193,7 +5558,7 @@ static int gsm48_rr_tx_hando_access(struct osmocom_ms *ms) return -ENOMEM; *msgb_put(nmsg, 1) = rr->hando_ref; todo burst - return gsm48_send_rsl(ms, RSL_MT_RAND_ACC_REQ, nmsg); + return gsm48_send_rsl(ms, RSL_MT_RAND_ACC_REQ, nmsg, 0); } /* send next channel request in dedicated state */ @@ -5253,8 +5618,7 @@ int gsm48_rr_tx_voice(struct osmocom_ms *ms, struct msgb *msg) return -ENOTSUP; } - return l1ctl_tx_traffic_req(ms, msg, rr->cd_now.chan_nr, - rr->cd_now.link_id); + return l1ctl_tx_traffic_req(ms, msg, rr->cd_now.chan_nr, 0); } int gsm48_rr_audio_mode(struct osmocom_ms *ms, uint8_t mode) |