aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--openbsc/include/openbsc/gprs_llc.h36
-rw-r--r--openbsc/src/gprs/gprs_llc.c55
2 files changed, 78 insertions, 13 deletions
diff --git a/openbsc/include/openbsc/gprs_llc.h b/openbsc/include/openbsc/gprs_llc.h
index 5a6682d80..608fb0578 100644
--- a/openbsc/include/openbsc/gprs_llc.h
+++ b/openbsc/include/openbsc/gprs_llc.h
@@ -26,7 +26,43 @@ enum gprs_llc_u_cmd {
GPRS_LLC_U_NULL_CMD = 0x00,
};
+/* TS 04.64 Section 7.1.2 Table 7: LLC layer primitives (GMM/SNDCP/SMS/TOM) */
+/* TS 04.65 Section 5.1.2 Table 2: Service primitives used by SNDCP */
+enum gprs_llc_primitive {
+ /* GMM <-> LLME */
+ LLGMM_ASSIGN_REQ, /* GMM tells us new TLLI: TLLI old, TLLI new, Kc, CiphAlg */
+ LLGMM_RESET_REQ, /* GMM tells us to perform XID negotiation: TLLI */
+ LLGMM_RESET_CNF, /* LLC informs GMM that XID has completed: TLLI */
+ LLGMM_SUSPEND_REQ, /* GMM tells us MS has suspended: TLLI, Page */
+ LLGMM_RESUME_REQ, /* GMM tells us MS has resumed: TLLI */
+ LLGMM_PAGE_IND, /* LLC asks GMM to page MS: TLLI */
+ LLGMM_IOV_REQ, /* GMM tells us to perform XID: TLLI */
+ LLGMM_STATUS_IND, /* LLC informs GMM about error: TLLI, Cause */
+ /* LLE <-> (GMM/SNDCP/SMS/TOM) */
+ LL_RESET_IND, /* TLLI */
+ LL_ESTABLISH_REQ, /* TLLI, XID Req */
+ LL_ESTABLISH_IND, /* TLLI, XID Req, N201-I, N201-U */
+ LL_ESTABLISH_RESP, /* TLLI, XID Negotiated */
+ LL_ESTABLISH_CONF, /* TLLI, XID Neg, N201-i, N201-U */
+ LL_RELEASE_REQ, /* TLLI, Local */
+ LL_RELEASE_IND, /* TLLI, Cause */
+ LL_RELEASE_CONF, /* TLLI */
+ LL_XID_REQ, /* TLLI, XID Requested */
+ LL_XID_IND, /* TLLI, XID Req, N201-I, N201-U */
+ LL_XID_RESP, /* TLLI, XID Negotiated */
+ LL_XID_CONF, /* TLLI, XID Neg, N201-I, N201-U */
+ LL_DATA_REQ, /* TLLI, SN-PDU, Ref, QoS, Radio Prio, Ciph */
+ LL_DATA_IND, /* TLLI, SN-PDU */
+ LL_DATA_CONF, /* TLLI, Ref */
+ LL_UNITDATA_REQ, /* TLLI, SN-PDU, Ref, QoS, Radio Prio, Ciph */
+ LL_UNITDATA_IND, /* TLLI, SN-PDU */
+ LL_STATUS_IND, /* TLLI, Cause */
+};
+
+/* BSSGP-UL-UNITDATA.ind */
int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv);
+
+/* LL-UNITDATA.req */
int gprs_llc_tx_ui(struct msgb *msg, uint8_t sapi, int command);
#endif
diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c
index 9c75a3d4e..c3df01352 100644
--- a/openbsc/src/gprs/gprs_llc.c
+++ b/openbsc/src/gprs/gprs_llc.c
@@ -111,6 +111,7 @@ enum gprs_llc_cmd {
GPRS_LLC_SABM,
GPRS_LLC_FRMR,
GPRS_LLC_XID,
+ GPRS_LLC_UI,
};
struct gprs_llc_hdr_parsed {
@@ -156,13 +157,13 @@ static void t200_expired(void *data)
switch (lle->state) {
case GPRS_LLS_LOCAL_EST:
- /* retransmit SABM */
- /* re-start T200 */
+ /* FIXME: retransmit SABM */
+ /* FIXME: re-start T200 */
lle->retrans_ctr++;
break;
case GPRS_LLS_LOCAL_REL:
- /* retransmit DISC */
- /* re-start T200 */
+ /* FIXME: retransmit DISC */
+ /* FIXME: re-start T200 */
lle->retrans_ctr++;
break;
}
@@ -174,8 +175,8 @@ static void t201_expired(void *data)
struct gprs_llc_lle *lle = data;
if (lle->retrans_ctr < lle->n200) {
- /* transmit apropriate supervisory frame (8.6.4.1) */
- /* set timer T201 */
+ /* FIXME: transmit apropriate supervisory frame (8.6.4.1) */
+ /* FIXME: set timer T201 */
lle->retrans_ctr++;
}
}
@@ -213,6 +214,7 @@ int gprs_llc_tx_u(struct msgb *msg, uint8_t sapi, int command,
/* Identifiers passed down: (BVCI, NSEI) */
+ /* Send BSSGP-DL-UNITDATA.req */
return gprs_bssgp_tx_dl_ud(msg);
}
@@ -272,6 +274,7 @@ int gprs_llc_tx_ui(struct msgb *msg, uint8_t sapi, int command)
/* Identifiers passed down: (BVCI, NSEI) */
+ /* Send BSSGP-DL-UNITDATA.req */
return gprs_bssgp_tx_dl_ud(msg);
}
@@ -437,6 +440,7 @@ static int gprs_llc_hdr_parse(struct gprs_llc_hdr_parsed *ghp,
}
} else if ((ctrl[0] & 0xe0) == 0xc0) {
/* UI (Unconfirmed Inforamtion) format */
+ ghp->cmd = GPRS_LLC_UI;
ghp->data = ctrl + 2;
ghp->data_len = (llc_hdr + len - 3) - ghp->data;
@@ -491,6 +495,12 @@ static int gprs_llc_hdr_parse(struct gprs_llc_hdr_parsed *ghp,
ghp->fcs_calc = gprs_llc_fcs(llc_hdr, crc_length);
/* FIXME: parse sack frame */
+ if (ghp->cmd == GPRS_LLC_SACK) {
+ DEBUGP(DGPRS, "Unsupported SACK frame\n");
+ return -EIO;
+ }
+
+ return 0;
}
/* receive an incoming LLC PDU (BSSGP-UL-UNITDATA-IND, 7.2.4.2) */
@@ -505,37 +515,56 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv)
/* Identifiers from DOWN: NSEI, BVCI, TLLI */
rc = gprs_llc_hdr_parse(&llhp, lh, TLVP_LEN(tv, BSSGP_IE_LLC_PDU));
- /* FIXME */
-
gprs_llc_hdr_dump(&llhp);
+ if (rc < 0) {
+ DEBUGP(DGPRS, "Error during LLC header parsing\n");
+ return rc;
+ }
+
+ if (llhp.fcs != llhp.fcs_calc) {
+ DEBUGP(DGPRS, "Dropping frame with invalid FCS\n");
+ return -EIO;
+ }
/* find the LLC Entity for this TLLI+SAPI tuple */
lle = lle_by_tlli_sapi(msgb_tlli(msg), llhp.sapi);
- /* allocate a new LLE if needed */
- if (!lle)
+
+ /* 7.2.1.1 LLC belonging to unassigned TLLI+SAPI shall be discarded,
+ * except UID and XID frames with SAPI=1 */
+ if (!lle && llhp.sapi == GPRS_SAPI_GMM &&
+ (llhp.cmd == GPRS_LLC_XID || llhp.cmd == GPRS_LLC_UI)) {
+ /* FIXME: don't use the TLLI but the 0xFFFF unassigned? */
lle = lle_alloc(msgb_tlli(msg), llhp.sapi);
+ } else {
+ DEBUGP(DGPRS, "unknown TLLI/SAPI: Silently dropping\n");
+ return 0;
+ }
/* Update LLE's (BVCI, NSEI) tuple */
lle->bvci = msgb_bvci(msg);
lle->nsei = msgb_nsei(msg);
+ /* Receive and Process the actual LLC frame */
rc = gprs_llc_hdr_rx(&llhp, lle);
- /* FIXME */
+ if (rc < 0)
+ return rc;
+ /* llhp.data is only set when we need to send LL_[UNIT]DATA_IND up */
if (llhp.data) {
msgb_gmmh(msg) = llhp.data;
switch (llhp.sapi) {
case GPRS_SAPI_GMM:
+ /* send LL_UNITDATA_IND to GMM */
rc = gsm0408_gprs_rcvmsg(msg);
break;
case GPRS_SAPI_TOM2:
case GPRS_SAPI_TOM8:
- /* FIXME */
+ /* FIXME: send LL_DATA_IND/LL_UNITDATA_IND to TOM */
case GPRS_SAPI_SNDCP3:
case GPRS_SAPI_SNDCP5:
case GPRS_SAPI_SNDCP9:
case GPRS_SAPI_SNDCP11:
- /* FIXME */
+ /* FIXME: send LL_DATA_IND/LL_UNITDATA_IND to SNDCP */
case GPRS_SAPI_SMS:
/* FIXME */
default: