From 0c1a30312defe524309d548166cd60716be3f692 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 16 Oct 2011 18:49:05 +0200 Subject: 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. --- openbsc/include/openbsc/gprs_llc.h | 20 ++++++++++ openbsc/src/gprs/gprs_llc.c | 78 ++++++++++++++++++++++++++++++++------ 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); -- cgit v1.2.3