summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Eversberg <jolly@eversberg.eu>2011-10-31 18:08:12 +0100
committerSylvain Munaut <tnt@246tNt.com>2011-11-13 20:25:20 +0100
commitcf55219d45b13f8103c54746d61ce4a77e7f5703 (patch)
tree6607c3acf49e2abb981b04dd13c1d8007b7f28b2
parent928b2245391bee667f46a5338edd46a6054826eb (diff)
host/mobile/sms: Adding SAPI 3 support to MM and RR layers
RR now handles SAPI 3 datalink. MM connections now have and individual sapi, so MM can use right SAPI for communication with other layers, as well as releasing the right MM connections in case of link release. Written-by: Andreas Eversberg <jolly@eversberg.eu> Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
-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 afdcf02..fb62aae 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 118848b..b7280fb 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 da47874..38dfab0 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 4b435ac..77fa7cf 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 547fd18..188e545 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)