summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/host/layer23/include/osmocom/bb/mobile/gsm48_mm.h7
-rw-r--r--src/host/layer23/include/osmocom/bb/mobile/gsm48_rr.h12
-rw-r--r--src/host/layer23/src/mobile/gsm48_cc.c7
-rw-r--r--src/host/layer23/src/mobile/gsm48_mm.c203
-rw-r--r--src/host/layer23/src/mobile/gsm48_rr.c498
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)