summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2011-10-16 18:49:05 +0200
committerHarald Welte <laforge@gnumonks.org>2011-10-16 18:58:30 +0200
commit0c1a30312defe524309d548166cd60716be3f692 (patch)
treeed52d36fcf0d1c60d68ca88d60b97842a2cdd36f
parent37a63ca34ad911f870c9d5dfb87205c13f302cba (diff)
LLC: Add minimal LLGMM-RESET.req implementation
Using LLGMM-RESET.req, the GMM can request the LLC of the MS to reset all its parameters, particularly the sequence numbers. We don't yet do XID RESET retransmissions, and we don't yet generate a LLGMM-RESET.conf primitive back to GMM.
-rw-r--r--openbsc/include/openbsc/gprs_llc.h20
-rw-r--r--openbsc/src/gprs/gprs_llc.c78
2 files changed, 87 insertions, 11 deletions
diff --git a/openbsc/include/openbsc/gprs_llc.h b/openbsc/include/openbsc/gprs_llc.h
index 9f1760573..f905473a1 100644
--- a/openbsc/include/openbsc/gprs_llc.h
+++ b/openbsc/include/openbsc/gprs_llc.h
@@ -27,6 +27,23 @@ enum gprs_llc_u_cmd {
GPRS_LLC_U_NULL_CMD = 0x00,
};
+/* Section 6.4.1.6 / Table 6 */
+enum gprs_llc_xid_type {
+ GPRS_LLC_XID_T_VERSION = 0,
+ GPRS_LLC_XID_T_IOV_UI = 1,
+ GPRS_LLC_XID_T_IOV_I = 2,
+ GPRS_LLC_XID_T_T200 = 3,
+ GPRS_LLC_XID_T_N200 = 4,
+ GPRS_LLC_XID_T_N201_U = 5,
+ GPRS_LLC_XID_T_N201_I = 6,
+ GPRS_LLC_XID_T_mD = 7,
+ GPRS_LLC_XID_T_mU = 8,
+ GPRS_LLC_XID_T_kD = 9,
+ GPRS_LLC_XID_T_kU = 10,
+ GPRS_LLC_XID_T_L3_PAR = 11,
+ GPRS_LLC_XID_T_RESET = 12,
+};
+
/* 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 {
@@ -151,6 +168,9 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv);
int gprs_llc_tx_ui(struct msgb *msg, uint8_t sapi, int command,
void *mmctx);
+/* Chapter 7.2.1.2 LLGMM-RESET.req */
+int gprs_llgmm_reset(struct gprs_llc_llme *llme);
+
/* 04.64 Chapter 7.2.1.1 LLGMM-ASSIGN */
int gprs_llgmm_assign(struct gprs_llc_llme *llme,
uint32_t old_tlli, uint32_t new_tlli,
diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c
index 3d4e98688..83db28c74 100644
--- a/openbsc/src/gprs/gprs_llc.c
+++ b/openbsc/src/gprs/gprs_llc.c
@@ -312,14 +312,15 @@ int gprs_llc_tx_u(struct msgb *msg, uint8_t sapi, int command,
}
/* Send XID response to LLE */
-static int gprs_llc_tx_xid(struct gprs_llc_lle *lle, struct msgb *msg)
+static int gprs_llc_tx_xid(struct gprs_llc_lle *lle, struct msgb *msg,
+ int command)
{
/* copy identifiers from LLE to ensure lower layers can route */
msgb_tlli(msg) = lle->llme->tlli;
msgb_bvci(msg) = lle->llme->bvci;
msgb_nsei(msg) = lle->llme->nsei;
- return gprs_llc_tx_u(msg, lle->sapi, 0, GPRS_LLC_U_XID, 1);
+ return gprs_llc_tx_u(msg, lle->sapi, command, GPRS_LLC_U_XID, 1);
}
/* Transmit a UI frame over the given SAPI */
@@ -422,6 +423,54 @@ int gprs_llc_tx_ui(struct msgb *msg, uint8_t sapi, int command,
return gprs_bssgp_tx_dl_ud(msg, mmctx);
}
+/* According to 6.4.1.6 / Figure 11 */
+static int msgb_put_xid_par(struct msgb *msg, uint8_t type, uint8_t length, uint8_t *data)
+{
+ uint8_t header_len = 1;
+ uint8_t *cur;
+
+ /* type is a 5-bit field... */
+ if (type > 0x1f)
+ return -EINVAL;
+
+ if (length > 3)
+ header_len = 2;
+
+ cur = msgb_put(msg, length + header_len);
+
+ /* build the header without or with XL bit */
+ if (length <= 3) {
+ *cur++ = (type << 2) | (length & 3);
+ } else {
+ *cur++ = 0x80 | (type << 2) | (length >> 6);
+ *cur++ = (length << 2);
+ }
+
+ /* copy over the payload of the parameter*/
+ memcpy(cur, data, length);
+
+ return length + header_len;
+}
+
+static void rx_llc_xid(struct gprs_llc_lle *lle,
+ struct gprs_llc_hdr_parsed *gph)
+{
+ /* FIXME: 8.5.3.3: check if XID is invalid */
+ if (gph->is_cmd) {
+ /* FIXME: implement XID negotiation using SNDCP */
+ struct msgb *resp;
+ uint8_t *xid;
+ resp = msgb_alloc_headroom(4096, 1024, "LLC_XID");
+ xid = msgb_put(resp, gph->data_len);
+ memcpy(xid, gph->data, gph->data_len);
+ gprs_llc_tx_xid(lle, resp, 0);
+ } else {
+ /* FIXME: if we had sent a XID reset, send
+ * LLGMM-RESET.conf to GMM */
+ /* FIXME: implement XID negotiation using SNDCP */
+ }
+}
+
static void gprs_llc_hdr_dump(struct gprs_llc_hdr_parsed *gph)
{
DEBUGP(DLLC, "LLC SAPI=%u %c %c FCS=0x%06x",
@@ -466,15 +515,7 @@ static int gprs_llc_hdr_rx(struct gprs_llc_hdr_parsed *gph,
case GPRS_LLC_FRMR: /* Section 6.4.1.5 */
break;
case GPRS_LLC_XID: /* Section 6.4.1.6 */
- /* FIXME: implement XID negotiation using SNDCP */
- {
- struct msgb *resp;
- uint8_t *xid;
- resp = msgb_alloc_headroom(4096, 1024, "LLC_XID");
- xid = msgb_put(resp, gph->data_len);
- memcpy(xid, gph->data, gph->data_len);
- gprs_llc_tx_xid(lle, resp);
- }
+ rx_llc_xid(lle, gph);
break;
case GPRS_LLC_UI:
if (gph->seq_tx < lle->vu_recv) {
@@ -846,6 +887,21 @@ int gprs_llgmm_assign(struct gprs_llc_llme *llme,
return 0;
}
+/* Chapter 7.2.1.2 LLGMM-RESET.req */
+int gprs_llgmm_reset(struct gprs_llc_llme *llme)
+{
+ struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_XID");
+ int random = rand();
+
+ /* First XID component must be RESET */
+ msgb_put_xid_par(msg, GPRS_LLC_XID_T_RESET, 0, NULL);
+ /* randomly select new IOV-UI */
+ msgb_put_xid_par(msg, GPRS_LLC_XID_T_IOV_UI, 4, &random);
+
+ /* FIXME: Start T200, wait for XID response */
+ return gprs_llc_tx_xid(&llme->lle[1], msg, 1);
+}
+
int gprs_llc_init(const char *cipher_plugin_path)
{
return gprs_cipher_load(cipher_plugin_path);