pespin submitted this change.

View Change

Approvals: Jenkins Builder: Verified laforge: Looks good to me, but someone else must approve fixeria: Looks good to me, but someone else must approve pespin: Looks good to me, approved
llc: Initial support for GRR-UNITDATA.ind/req

This allows forwarding GRR-UNITDATA.ind/req up & down the stack, to be
on pair with the BSSGP LLC SAP.

Change-Id: I6a4454b4aa2c96e1f4ce7e2a5d5aba8ec1cf3f60
---
M include/osmocom/gprs/llc/llc_prim.h
M include/osmocom/gprs/llc/llc_private.h
M src/llc/llc.c
M src/llc/llc_bssgp.c
M src/llc/llc_grr.c
M tests/llc/llc_prim_test.c
M tests/llc/llc_prim_test.err
M tests/llc/llc_prim_test.ok
8 files changed, 316 insertions(+), 156 deletions(-)

diff --git a/include/osmocom/gprs/llc/llc_prim.h b/include/osmocom/gprs/llc/llc_prim.h
index 23b41cf..22ee7b7 100644
--- a/include/osmocom/gprs/llc/llc_prim.h
+++ b/include/osmocom/gprs/llc/llc_prim.h
@@ -204,13 +204,20 @@
size_t ll_pdu_len;
/* Specific fields */
union {
- /* OSMO_GPRS_LLC_GRR_[UNIT]DATA | Req */
+ /* OSMO_GPRS_LLC_GRR_DATA | Req */
struct {
- uint8_t qos_params[3];
- uint8_t radio_prio;
- uint8_t cause; /* only for OSMO_GPRS_LLC_GRR_UNITDATA | Req */
uint8_t sapi;
+ uint8_t radio_prio;
+ uint8_t qos_params[3];
+
} data_req;
+ /* OSMO_GPRS_LLC_GRR_UNITDATA| Req */
+ struct {
+ uint8_t sapi;
+ uint8_t radio_prio;
+ uint8_t qos_params[3];
+ uint8_t cause;
+ } unitdata_req;
};
};

@@ -286,3 +293,7 @@
/* Alloc primitive for BSSGP SAP: */
struct osmo_gprs_llc_prim *osmo_gprs_llc_prim_alloc_bssgp_ul_unitdata_ind(
uint32_t tlli, uint8_t *ll_pdu, size_t ll_pdu_len);
+
+/* Alloc primitive for GRR SAP: */
+struct osmo_gprs_llc_prim *osmo_gprs_llc_prim_alloc_grr_unitdata_ind(
+ uint32_t tlli, uint8_t *ll_pdu, size_t ll_pdu_len);
diff --git a/include/osmocom/gprs/llc/llc_private.h b/include/osmocom/gprs/llc/llc_private.h
index 4d44b74..1db33b6 100644
--- a/include/osmocom/gprs/llc/llc_private.h
+++ b/include/osmocom/gprs/llc/llc_private.h
@@ -282,6 +282,8 @@

/* llc_grr.c */
int gprs_llc_prim_lower_up_grr(struct osmo_gprs_llc_prim *llc_prim);
+struct osmo_gprs_llc_prim *gprs_llc_prim_alloc_grr_unitdata_req(
+ uint32_t tlli, uint8_t *ll_pdu, size_t ll_pdu_len);

/* llc_ll.c */
int gprs_llc_prim_ll_upper_down(struct osmo_gprs_llc_prim *llc_prim);
@@ -307,7 +309,8 @@
struct gprs_llc_lle *gprs_llc_find_lle_by_tlli_sapi(uint32_t tlli, uint8_t sapi);
struct gprs_llc_lle *gprs_llc_lle_for_rx_by_tlli_sapi(const uint32_t tlli,
uint8_t sapi, enum gprs_llc_frame_func cmd);
-int gprs_llc_lle_hdr_rx(struct gprs_llc_lle *lle, struct gprs_llc_pdu_decoded *pdu_dec);
+int gprs_llc_lle_rx_unitdata_ind(struct gprs_llc_lle *lle, uint8_t *ll_pdu, size_t ll_pdu_len,
+ struct gprs_llc_pdu_decoded *pdu_dec);
void gprs_llc_llme_free(struct gprs_llc_llme *llme);
int gprs_llc_lle_tx_xid(const struct gprs_llc_lle *lle, uint8_t *xid_payload, unsigned int xid_payload_len, bool is_cmd);
int gprs_llc_lle_tx_xid_req(struct gprs_llc_lle *lle, uint8_t *l3par, unsigned int l3par_len);
diff --git a/src/llc/llc.c b/src/llc/llc.c
index 1f52851..1c572d6 100644
--- a/src/llc/llc.c
+++ b/src/llc/llc.c
@@ -309,7 +309,10 @@
/* TODO: we are probably missing the ciphering enc part, see osmo-sgsn apply_gea() */

/* LLC payload is put directly below: */
- llc_prim = gprs_llc_prim_alloc_bssgp_dl_unitdata_req(lle->llme->tlli, NULL, 4096 - sizeof(llc_prim));
+ if (g_ctx->location == OSMO_GPRS_LLC_LOCATION_SGSN)
+ llc_prim = gprs_llc_prim_alloc_bssgp_dl_unitdata_req(lle->llme->tlli, NULL, 4096 - sizeof(llc_prim));
+ else
+ llc_prim = gprs_llc_prim_alloc_grr_unitdata_req(lle->llme->tlli, NULL, 4096 - sizeof(llc_prim));
msg = llc_prim->oph.msg;
msg->l3h = msg->tail;

@@ -319,8 +322,15 @@
msgb_free(msg);
return rc;
}
- llc_prim->bssgp.ll_pdu = msgb_l3(msg);
- llc_prim->bssgp.ll_pdu_len = msgb_l3len(msg);
+
+ if (g_ctx->location == OSMO_GPRS_LLC_LOCATION_SGSN) {
+ llc_prim->bssgp.ll_pdu = msgb_l3(msg);
+ llc_prim->bssgp.ll_pdu_len = msgb_l3len(msg);
+ } else {
+ llc_prim->grr.ll_pdu = msgb_l3(msg);
+ llc_prim->grr.ll_pdu_len = msgb_l3len(msg);
+ llc_prim->grr.unitdata_req.sapi = lle->sapi;
+ }

/* Increment V(U) */
lle->vu_send = (lle->vu_send + 1) % 512;
@@ -328,7 +338,7 @@
if ((lle->vu_send + 1) / 512)
lle->oc_ui_send += 512;

- /* Send BSSGP-DL-UNITDATA.req */
+ /* Send BSSGP-DL-UNITDATA.req (SGSN) / GRR-UNITDATA.req (MS) */
rc = gprs_llc_prim_call_down_cb(llc_prim);
return rc;
}
@@ -593,7 +603,7 @@
}

/* Receive and process decoded LLC PDU from lower layer (GRR/BSSGP): */
-int gprs_llc_lle_hdr_rx(struct gprs_llc_lle *lle, struct gprs_llc_pdu_decoded *pdu_dec)
+static int gprs_llc_lle_hdr_rx(struct gprs_llc_lle *lle, struct gprs_llc_pdu_decoded *pdu_dec)
{
const char *llc_pdu_name = gprs_llc_pdu_hdr_dump(pdu_dec);

@@ -649,3 +659,129 @@

return 0;
}
+
+/* encrypt information field + FCS, if needed! */
+static int apply_gea(const struct gprs_llc_lle *lle, uint16_t crypt_len, uint16_t nu,
+ uint32_t oc, uint8_t sapi, uint8_t *fcs, uint8_t *data)
+{
+ uint8_t cipher_out[GSM0464_CIPH_MAX_BLOCK];
+
+ if (lle->llme->algo == GPRS_ALGO_GEA0)
+ return -EINVAL;
+
+ /* Compute the 'Input' Paraemeter */
+ uint32_t fcs_calc, iv = gprs_cipher_gen_input_ui(lle->llme->iov_ui, sapi,
+ nu, oc);
+ /* Compute gamma that we need to XOR with the data */
+ int r = gprs_cipher_run(cipher_out, crypt_len, lle->llme->algo,
+ lle->llme->kc, iv,
+ fcs ? GPRS_CIPH_SGSN2MS : GPRS_CIPH_MS2SGSN);
+ if (r < 0) {
+ LOGLLC(LOGL_ERROR, "Error producing %s gamma for UI "
+ "frame: %d\n", get_value_string(gprs_cipher_names,
+ lle->llme->algo), r);
+ return -ENOMSG;
+ }
+
+ if (fcs) {
+ /* Mark frame as encrypted and update FCS */
+ data[2] |= 0x02;
+ fcs_calc = gprs_llc_fcs(data, fcs - data);
+ fcs[0] = fcs_calc & 0xff;
+ fcs[1] = (fcs_calc >> 8) & 0xff;
+ fcs[2] = (fcs_calc >> 16) & 0xff;
+ data += 3;
+ }
+
+ /* XOR the cipher output with the data */
+ for (r = 0; r < crypt_len; r++)
+ *(data + r) ^= cipher_out[r];
+
+ return 0;
+}
+
+/* Shared upper part handling of BSSGP-UNITDATA.ind and GRR-UNITDATA.ind */
+int gprs_llc_lle_rx_unitdata_ind(struct gprs_llc_lle *lle, uint8_t *ll_pdu, size_t ll_pdu_len, struct gprs_llc_pdu_decoded *pdu_dec)
+{
+ struct osmo_gprs_llc_prim *llc_prim_tx;
+ bool drop_cipherable = false;
+ int rc;
+
+ /* reset age computation */
+ lle->llme->age_timestamp = GPRS_LLME_RESET_AGE;
+
+ /* decrypt information field + FCS, if needed! */
+ if (pdu_dec->flags & OSMO_GPRS_LLC_PDU_F_ENC_MODE) {
+ if (lle->llme->algo != GPRS_ALGO_GEA0) {
+ rc = apply_gea(lle, pdu_dec->data_len + 3, pdu_dec->seq_tx,
+ lle->oc_ui_recv, lle->sapi, NULL,
+ (uint8_t *)pdu_dec->data); /*TODO: either copy buffer or remove "const" from pdu_dec field "data" */
+ if (rc < 0)
+ return rc;
+ pdu_dec->fcs = *(pdu_dec->data + pdu_dec->data_len);
+ pdu_dec->fcs |= *(pdu_dec->data + pdu_dec->data_len + 1) << 8;
+ pdu_dec->fcs |= *(pdu_dec->data + pdu_dec->data_len + 2) << 16;
+ } else {
+ LOGLLME(lle->llme, LOGL_NOTICE, "encrypted frame for LLC that "
+ "has no KC/Algo! Dropping.\n");
+ return 0;
+ }
+ } else {
+ if (lle->llme->algo != GPRS_ALGO_GEA0 &&
+ lle->llme->cksn != GSM_KEY_SEQ_INVAL)
+ drop_cipherable = true;
+ }
+
+ /* We have to do the FCS check _after_ decryption */
+ uint16_t crc_length = ll_pdu_len - CRC24_LENGTH;
+ if (~pdu_dec->flags & OSMO_GPRS_LLC_PDU_F_PROT_MODE)
+ crc_length = OSMO_MIN(crc_length, UI_HDR_LEN + N202);
+ if (pdu_dec->fcs != gprs_llc_fcs(ll_pdu, crc_length)) {
+ LOGLLE(lle, LOGL_INFO, "Dropping frame with invalid FCS\n");
+ return -EIO;
+ }
+
+ /* Receive and Process the actual LLC frame */
+ rc = gprs_llc_lle_hdr_rx(lle, pdu_dec);
+ if (rc < 0)
+ return rc;
+
+ /* pdu_dec->data is only set when we need to send LL_[UNIT]DATA_IND up */
+ if (pdu_dec->func == OSMO_GPRS_LLC_FUNC_UI && pdu_dec->data && pdu_dec->data_len) {
+ switch (pdu_dec->sapi) {
+ case OSMO_GPRS_LLC_SAPI_GMM:
+ /* send LL-UNITDATA-IND to GMM */
+ llc_prim_tx = gprs_llc_prim_alloc_ll_unitdata_ind(lle->llme->tlli,
+ pdu_dec->sapi,
+ pdu_dec->data,
+ pdu_dec->data_len);
+ llc_prim_tx->ll.unitdata_ind.apply_gea = !drop_cipherable; /* TODO: is this correct? */
+ llc_prim_tx->ll.unitdata_ind.apply_gia = false; /* TODO: how to set this? */
+ gprs_llc_prim_call_up_cb(llc_prim_tx);
+ break;
+ case OSMO_GPRS_LLC_SAPI_SNDCP3:
+ case OSMO_GPRS_LLC_SAPI_SNDCP5:
+ case OSMO_GPRS_LLC_SAPI_SNDCP9:
+ case OSMO_GPRS_LLC_SAPI_SNDCP11:
+ /* send LL_DATA_IND/LL_UNITDATA_IND to SNDCP */
+ llc_prim_tx = gprs_llc_prim_alloc_ll_unitdata_ind(lle->llme->tlli,
+ pdu_dec->sapi,
+ pdu_dec->data,
+ pdu_dec->data_len);
+ llc_prim_tx->ll.unitdata_ind.apply_gea = !drop_cipherable; /* TODO: is this correct? */
+ llc_prim_tx->ll.unitdata_ind.apply_gia = false; /* TODO: how to set this? */
+ gprs_llc_prim_call_up_cb(llc_prim_tx);
+ break;
+ case OSMO_GPRS_LLC_SAPI_SMS:
+ /* FIXME */
+ case OSMO_GPRS_LLC_SAPI_TOM2:
+ case OSMO_GPRS_LLC_SAPI_TOM8:
+ /* FIXME: send LL_DATA_IND/LL_UNITDATA_IND to TOM */
+ default:
+ LOGLLC(LOGL_NOTICE, "Unsupported SAPI %u\n", pdu_dec->sapi);
+ rc = -EINVAL;
+ break;
+ }
+ }
+ return rc;
+}
diff --git a/src/llc/llc_bssgp.c b/src/llc/llc_bssgp.c
index 48d4cde..a6fd308 100644
--- a/src/llc/llc_bssgp.c
+++ b/src/llc/llc_bssgp.c
@@ -78,58 +78,14 @@
* Handling from lower layers:
********************************/

-/* encrypt information field + FCS, if needed! */
-static int apply_gea(const struct gprs_llc_lle *lle, uint16_t crypt_len, uint16_t nu,
- uint32_t oc, uint8_t sapi, uint8_t *fcs, uint8_t *data)
-{
- uint8_t cipher_out[GSM0464_CIPH_MAX_BLOCK];
-
- if (lle->llme->algo == GPRS_ALGO_GEA0)
- return -EINVAL;
-
- /* Compute the 'Input' Paraemeter */
- uint32_t fcs_calc, iv = gprs_cipher_gen_input_ui(lle->llme->iov_ui, sapi,
- nu, oc);
- /* Compute gamma that we need to XOR with the data */
- int r = gprs_cipher_run(cipher_out, crypt_len, lle->llme->algo,
- lle->llme->kc, iv,
- fcs ? GPRS_CIPH_SGSN2MS : GPRS_CIPH_MS2SGSN);
- if (r < 0) {
- LOGLLC(LOGL_ERROR, "Error producing %s gamma for UI "
- "frame: %d\n", get_value_string(gprs_cipher_names,
- lle->llme->algo), r);
- return -ENOMSG;
- }
-
- if (fcs) {
- /* Mark frame as encrypted and update FCS */
- data[2] |= 0x02;
- fcs_calc = gprs_llc_fcs(data, fcs - data);
- fcs[0] = fcs_calc & 0xff;
- fcs[1] = (fcs_calc >> 8) & 0xff;
- fcs[2] = (fcs_calc >> 16) & 0xff;
- data += 3;
- }
-
- /* XOR the cipher output with the data */
- for (r = 0; r < crypt_len; r++)
- *(data + r) ^= cipher_out[r];
-
- return 0;
-}
-
-
static int gprs_llc_prim_handle_bssgp_ul_unitdata_ind(struct osmo_gprs_llc_prim *llc_prim)
{
int rc;
- struct gprs_llc_hdr *lh = (struct gprs_llc_hdr *) llc_prim->bssgp.ll_pdu;
struct gprs_llc_pdu_decoded pdu_dec = {0};
const char *llc_pdu_name = NULL;
struct gprs_llc_lle *lle = NULL;
- bool drop_cipherable = false;
- struct osmo_gprs_llc_prim *llc_prim_tx;

- rc = gprs_llc_pdu_decode(&pdu_dec, (uint8_t *)lh, llc_prim->bssgp.ll_pdu_len);
+ rc = gprs_llc_pdu_decode(&pdu_dec, llc_prim->bssgp.ll_pdu, llc_prim->bssgp.ll_pdu_len);
if (rc < 0) {
LOGLLC(LOGL_ERROR, "%s: Error parsing LLC header\n", osmo_gprs_llc_prim_name(llc_prim));
return rc;
@@ -166,82 +122,7 @@
}
return 0;
}
- /* reset age computation */
- lle->llme->age_timestamp = GPRS_LLME_RESET_AGE;
-
- /* decrypt information field + FCS, if needed! */
- if (pdu_dec.flags & OSMO_GPRS_LLC_PDU_F_ENC_MODE) {
- if (lle->llme->algo != GPRS_ALGO_GEA0) {
- rc = apply_gea(lle, pdu_dec.data_len + 3, pdu_dec.seq_tx,
- lle->oc_ui_recv, lle->sapi, NULL,
- (uint8_t *)pdu_dec.data); /*TODO: either copy buffer or remove "const" from pdu_dec field "data" */
- if (rc < 0)
- return rc;
- pdu_dec.fcs = *(pdu_dec.data + pdu_dec.data_len);
- pdu_dec.fcs |= *(pdu_dec.data + pdu_dec.data_len + 1) << 8;
- pdu_dec.fcs |= *(pdu_dec.data + pdu_dec.data_len + 2) << 16;
- } else {
- LOGLLME(lle->llme, LOGL_NOTICE, "encrypted frame for LLC that "
- "has no KC/Algo! Dropping.\n");
- return 0;
- }
- } else {
- if (lle->llme->algo != GPRS_ALGO_GEA0 &&
- lle->llme->cksn != GSM_KEY_SEQ_INVAL)
- drop_cipherable = true;
- }
-
- /* We have to do the FCS check _after_ decryption */
- uint16_t crc_length = llc_prim->bssgp.ll_pdu_len - CRC24_LENGTH;
- if (~pdu_dec.flags & OSMO_GPRS_LLC_PDU_F_PROT_MODE)
- crc_length = OSMO_MIN(crc_length, UI_HDR_LEN + N202);
- if (pdu_dec.fcs != gprs_llc_fcs((uint8_t *)lh, crc_length)) {
- LOGLLE(lle, LOGL_INFO, "Dropping frame with invalid FCS\n");
- return -EIO;
- }
-
- /* Receive and Process the actual LLC frame */
- rc = gprs_llc_lle_hdr_rx(lle, &pdu_dec);
- if (rc < 0)
- return rc;
-
- /* pdu_dec.data is only set when we need to send LL_[UNIT]DATA_IND up */
- if (pdu_dec.func == OSMO_GPRS_LLC_FUNC_UI && pdu_dec.data && pdu_dec.data_len) {
- switch (pdu_dec.sapi) {
- case OSMO_GPRS_LLC_SAPI_GMM:
- /* send LL-UNITDATA-IND to GMM */
- llc_prim_tx = gprs_llc_prim_alloc_ll_unitdata_ind(lle->llme->tlli,
- pdu_dec.sapi,
- pdu_dec.data,
- pdu_dec.data_len);
- llc_prim_tx->ll.unitdata_ind.apply_gea = !drop_cipherable; /* TODO: is this correct? */
- llc_prim_tx->ll.unitdata_ind.apply_gia = false; /* TODO: how to set this? */
- gprs_llc_prim_call_up_cb(llc_prim_tx);
- break;
- case OSMO_GPRS_LLC_SAPI_SNDCP3:
- case OSMO_GPRS_LLC_SAPI_SNDCP5:
- case OSMO_GPRS_LLC_SAPI_SNDCP9:
- case OSMO_GPRS_LLC_SAPI_SNDCP11:
- /* send LL_DATA_IND/LL_UNITDATA_IND to SNDCP */
- llc_prim_tx = gprs_llc_prim_alloc_ll_unitdata_ind(lle->llme->tlli,
- pdu_dec.sapi,
- pdu_dec.data,
- pdu_dec.data_len);
- llc_prim_tx->ll.unitdata_ind.apply_gea = !drop_cipherable; /* TODO: is this correct? */
- llc_prim_tx->ll.unitdata_ind.apply_gia = false; /* TODO: how to set this? */
- gprs_llc_prim_call_up_cb(llc_prim_tx);
- break;
- case OSMO_GPRS_LLC_SAPI_SMS:
- /* FIXME */
- case OSMO_GPRS_LLC_SAPI_TOM2:
- case OSMO_GPRS_LLC_SAPI_TOM8:
- /* FIXME: send LL_DATA_IND/LL_UNITDATA_IND to TOM */
- default:
- LOGLLC(LOGL_NOTICE, "Unsupported SAPI %u\n", pdu_dec.sapi);
- rc = -EINVAL;
- break;
- }
- }
+ rc = gprs_llc_lle_rx_unitdata_ind(lle, llc_prim->bssgp.ll_pdu, llc_prim->bssgp.ll_pdu_len, &pdu_dec);

return rc;
}
diff --git a/src/llc/llc_grr.c b/src/llc/llc_grr.c
index 8486a53..e6d1cf7 100644
--- a/src/llc/llc_grr.c
+++ b/src/llc/llc_grr.c
@@ -1,6 +1,6 @@
-/* GPRS LLC LLGM SAP as per 3GPP TS 44.064 7.2.3 */
+/* GPRS LLC GRR SAP as per 3GPP TS 44.064 7.2.3, 3GPP TS 24.007 */
/*
- * (C) 2022 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ * (C) 2022-2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
*
* All Rights Reserved
*
@@ -38,6 +38,42 @@
{ 0, NULL }
};

+/********************************
+ * Primitive allocation:
+ ********************************/
+
+static inline struct osmo_gprs_llc_prim *llc_prim_grr_alloc(enum osmo_gprs_llc_grr_prim_type type,
+ enum osmo_prim_operation operation,
+ unsigned int l3_len)
+{
+ return gprs_llc_prim_alloc(OSMO_GPRS_LLC_SAP_GRR, type, operation, l3_len);
+}
+
+/* 7.2.3.2 GRR-UNITDATA.ind (MS):*/
+struct osmo_gprs_llc_prim *osmo_gprs_llc_prim_alloc_grr_unitdata_ind(
+ uint32_t tlli, uint8_t *ll_pdu,
+ size_t ll_pdu_len)
+{
+ struct osmo_gprs_llc_prim *llc_prim;
+ llc_prim = llc_prim_grr_alloc(OSMO_GPRS_LLC_GRR_UNITDATA, PRIM_OP_INDICATION, ll_pdu_len);
+ llc_prim->grr.tlli = tlli;
+ llc_prim->grr.ll_pdu = ll_pdu;
+ llc_prim->grr.ll_pdu_len = ll_pdu_len;
+ return llc_prim;
+}
+
+/* 7.2.3.2 GRR-UL-UNITDATA.req (MS):*/
+struct osmo_gprs_llc_prim *gprs_llc_prim_alloc_grr_unitdata_req(
+ uint32_t tlli, uint8_t *ll_pdu, size_t ll_pdu_len)
+{
+ struct osmo_gprs_llc_prim *llc_prim;
+ llc_prim = llc_prim_grr_alloc(OSMO_GPRS_LLC_GRR_UNITDATA, PRIM_OP_REQUEST, ll_pdu_len);
+ llc_prim->grr.tlli = tlli;
+ llc_prim->grr.ll_pdu = ll_pdu;
+ llc_prim->grr.ll_pdu_len = ll_pdu_len;
+ return llc_prim;
+}
+
static int llc_prim_handle_grr_data_ind(struct osmo_gprs_llc_prim *llc_prim)
{
int rc = gprs_llc_prim_handle_unsupported(llc_prim);
@@ -46,7 +82,50 @@

static int llc_prim_handle_grr_unitdata_ind(struct osmo_gprs_llc_prim *llc_prim)
{
- int rc = gprs_llc_prim_handle_unsupported(llc_prim);
+ int rc;
+ struct gprs_llc_pdu_decoded pdu_dec = {0};
+ const char *llc_pdu_name = NULL;
+ struct gprs_llc_lle *lle = NULL;
+
+ rc = gprs_llc_pdu_decode(&pdu_dec, llc_prim->grr.ll_pdu, llc_prim->grr.ll_pdu_len);
+ if (rc < 0) {
+ LOGLLC(LOGL_ERROR, "%s: Error parsing LLC header\n", osmo_gprs_llc_prim_name(llc_prim));
+ return rc;
+ }
+ llc_pdu_name = gprs_llc_pdu_hdr_dump(&pdu_dec);
+
+ LOGLLC(LOGL_DEBUG, "Rx %s: %s\n", osmo_gprs_llc_prim_name(llc_prim), llc_pdu_name);
+
+ switch (gprs_tlli_type(llc_prim->bssgp.tlli)) {
+ case TLLI_LOCAL:
+ case TLLI_FOREIGN:
+ case TLLI_RANDOM:
+ case TLLI_AUXILIARY:
+ break;
+ default:
+ LOGLLC(LOGL_ERROR, "%s: Discarding frame with strange TLLI type\n", llc_pdu_name);
+ return -EINVAL;
+ }
+
+ lle = gprs_llc_lle_for_rx_by_tlli_sapi(llc_prim->grr.tlli, pdu_dec.sapi, pdu_dec.func);
+ if (!lle) {
+ switch (pdu_dec.sapi) {
+ case OSMO_GPRS_LLC_SAPI_SNDCP3:
+ case OSMO_GPRS_LLC_SAPI_SNDCP5:
+ case OSMO_GPRS_LLC_SAPI_SNDCP9:
+ case OSMO_GPRS_LLC_SAPI_SNDCP11:
+#if 0
+/* TODO: probaby send some primitive to the upper layers (GMM) */
+ /* Ask an upper layer for help. */
+ return gsm0408_gprs_force_reattach_oldmsg(msg, NULL);
+#endif
+ default:
+ break;
+ }
+ return 0;
+ }
+ rc = gprs_llc_lle_rx_unitdata_ind(lle, llc_prim->grr.ll_pdu, llc_prim->grr.ll_pdu_len, &pdu_dec);
+
return rc;
}

diff --git a/tests/llc/llc_prim_test.c b/tests/llc/llc_prim_test.c
index ab3bf65..3e3dc82 100644
--- a/tests/llc/llc_prim_test.c
+++ b/tests/llc/llc_prim_test.c
@@ -65,7 +65,8 @@

switch (llc_prim->oph.sap) {
case OSMO_GPRS_LLC_SAP_GRR:
- printf("%s(): Rx %s l3=[%s]\n", __func__, pdu_name, osmo_hexdump(llc_prim->grr.ll_pdu, llc_prim->grr.ll_pdu_len));
+ printf("%s(): Rx %s l3=[%s]\n", __func__, pdu_name,
+ osmo_hexdump(llc_prim->grr.ll_pdu, llc_prim->grr.ll_pdu_len));
break;
case OSMO_GPRS_LLC_SAP_BSSGP:
printf("%s(): Rx %s TLLI=0x%08x l3=[%s]\n", __func__, pdu_name,
@@ -78,27 +79,39 @@
return 0;
}

-static void test_llc_prim_ms(void)
-{
- //struct osmo_gprs_llc_prim *llc_prim;
- //uint32_t tlli = 0x11223344;
- int rc;
-
- printf("==== %s() [start] ====\n", __func__);
-
- rc = osmo_gprs_llc_init(OSMO_GPRS_LLC_LOCATION_MS, NULL);
- OSMO_ASSERT(rc == 0);
-
- osmo_gprs_llc_prim_set_up_cb(test_llc_prim_up_cb, NULL);
- osmo_gprs_llc_prim_set_down_cb(test_llc_prim_down_cb, NULL);
-
- //llc_prim = osmo_gprs_llc_prim_alloc_llgm_reset_req(tlli);
- //OSMO_ASSERT(llc_prim);
- //rc = osmo_gprs_llc_prim_upper_down(llc_prim);
- //OSMO_ASSERT(rc == 0);
-
- printf("==== %s() [end] ====\n", __func__);
-}
+/*
+GSM A-I/F DTAP - Attach Request
+ Protocol Discriminator: GPRS mobility management messages (8)
+ DTAP GPRS Mobility Management Message Type: Attach Request (0x01)
+ MS Network Capability
+ Length: 2
+ 1... .... = GEA/1: Encryption algorithm available
+ .1.. .... = SM capabilities via dedicated channels: Mobile station supports mobile terminated point to point SMS via dedicated signalling channels
+ ..1. .... = SM capabilities via GPRS channels: Mobile station supports mobile terminated point to point SMS via GPRS packet data channels
+ ...0 .... = UCS2 support: The ME has a preference for the default alphabet (defined in 3GPP TS 23.038 [8b]) over UCS2
+ .... 01.. = SS Screening Indicator: capability of handling of ellipsis notation and phase 2 error handling (0x1)
+ .... ..0. = SoLSA Capability: The ME does not support SoLSA
+ .... ...1 = Revision level indicator: Used by a mobile station supporting R99 or later versions of the protocol
+ 1... .... = PFC feature mode: Mobile station does support BSS packet flow procedures
+ .110 000. = Extended GEA bits: 0x30
+ .... ...0 = LCS VA capability: LCS value added location request notification capability not supported
+ Attach Type
+ Ciphering Key Sequence Number
+ DRX Parameter
+ Mobile Identity - TMSI/P-TMSI (0xf43cec71)
+ Routing Area Identification - Old routing area identification - RAI: 234-70-5-0
+ MS Radio Access Capability
+ GPRS Timer - Ready Timer
+ Element ID: 0x17
+ GPRS Timer: 10 sec
+ 000. .... = Unit: value is incremented in multiples of 2 seconds (0)
+ ...0 0101 = Timer value: 5
+*/
+static uint8_t pdu_gmmm_attach_req[] = {
+ 0x08, 0x01, 0x02, 0xe5, 0xe0, 0x01, 0x0a, 0x00, 0x05, 0xf4, 0xf4, 0x3c, 0xec, 0x71, 0x32, 0xf4,
+ 0x07, 0x00, 0x05, 0x00, 0x17, 0x19, 0x33, 0x43, 0x2b, 0x37, 0x15, 0x9e, 0xf9, 0x88, 0x79, 0xcb,
+ 0xa2, 0x8c, 0x66, 0x21, 0xe7, 0x26, 0x88, 0xb1, 0x98, 0x87, 0x9c, 0x00, 0x17, 0x05
+};

/**
MS-SGSN LLC (Mobile Station - Serving GPRS Support Node Logical Link Control) SAPI: GPRS Mobility Management
@@ -139,6 +152,36 @@
*/
static uint8_t pdu_gmm_id_req[] = { 0x08, 0x15, 0x02 };

+static void test_llc_prim_ms(void)
+{
+ struct osmo_gprs_llc_prim *llc_prim;
+ uint32_t tlli = 0xf43cec71;
+ int rc;
+
+ printf("==== %s() [start] ====\n", __func__);
+
+ rc = osmo_gprs_llc_init(OSMO_GPRS_LLC_LOCATION_MS, NULL);
+ OSMO_ASSERT(rc == 0);
+
+ osmo_gprs_llc_prim_set_up_cb(test_llc_prim_up_cb, NULL);
+ osmo_gprs_llc_prim_set_down_cb(test_llc_prim_down_cb, NULL);
+
+ /* Tx GMM Attach Request */
+ llc_prim = osmo_gprs_llc_prim_alloc_ll_unitdata_req(tlli, OSMO_GPRS_LLC_SAPI_GMM, (uint8_t *)pdu_gmmm_attach_req, sizeof(pdu_gmmm_attach_req));
+ OSMO_ASSERT(llc_prim);
+ rc = osmo_gprs_llc_prim_upper_down(llc_prim);
+ OSMO_ASSERT(rc == 0);
+
+ /* Rx LLC-GMM-Attach-Req at MS from SGSN (should be a response message
+ * but we don't care about upper layers here): */
+ llc_prim = osmo_gprs_llc_prim_alloc_grr_unitdata_ind(tlli, pdu_llc_gmm_att_req, sizeof(pdu_llc_gmm_att_req));
+ OSMO_ASSERT(llc_prim);
+ rc = osmo_gprs_llc_prim_lower_up(llc_prim);
+ OSMO_ASSERT(rc == 0);
+
+ printf("==== %s() [end] ====\n", __func__);
+}
+
static void test_llc_prim_sgsn(void)
{
struct osmo_gprs_llc_prim *llc_prim;
diff --git a/tests/llc/llc_prim_test.err b/tests/llc/llc_prim_test.err
index 5bc0481..2c38469 100644
--- a/tests/llc/llc_prim_test.err
+++ b/tests/llc/llc_prim_test.err
@@ -1,3 +1,8 @@
+DLGLOBAL INFO Rx from upper layers: LL-UNITDATA.request
+DLGLOBAL NOTICE Rx LL-UNITDATA.request: unknown TLLI 0xf43cec71, creating LLME on the fly
+DLGLOBAL INFO Rx from lower layers: GRR-UNITDATA.indication
+DLGLOBAL DEBUG Rx GRR-UNITDATA.indication: SAPI=1 (GMM), UI func=UI C/R=0 PM=0 E=0 IP=0 N(U)=0 FCS=f218e2
+DLGLOBAL DEBUG LLE(ffffffff/f43cec71,GMM){UNASSIGNED} Rx SAPI=1 (GMM), UI func=UI C/R=0 PM=0 E=0 IP=0 N(U)=0 FCS=f218e2
DLGLOBAL INFO Rx from lower layers: BSSGP-UL-UNITDATA.indication
DLGLOBAL DEBUG Rx BSSGP-UL-UNITDATA.indication: SAPI=1 (GMM), UI func=UI C/R=0 PM=0 E=0 IP=0 N(U)=0 FCS=f218e2
DLGLOBAL NOTICE LLME(ffffffff/e1c5d364){UNASSIGNED} LLC RX: unknown TLLI 0xe1c5d364, creating LLME on the fly
diff --git a/tests/llc/llc_prim_test.ok b/tests/llc/llc_prim_test.ok
index 3193fed..4534568 100644
--- a/tests/llc/llc_prim_test.ok
+++ b/tests/llc/llc_prim_test.ok
@@ -1,4 +1,6 @@
==== test_llc_prim_ms() [start] ====
+test_llc_prim_down_cb(): Rx GRR-UNITDATA.request l3=[01 c0 01 08 01 02 e5 e0 01 0a 00 05 f4 f4 3c ec 71 32 f4 07 00 05 00 17 19 33 43 2b 37 15 9e f9 88 79 cb a2 8c 66 21 e7 26 88 b1 98 87 9c 00 17 05 22 96 cc ]
+test_llc_prim_up_cb(): Rx LL-UNITDATA.indication TLLI=0xf43cec71 SAPI=GMM l3=[08 01 01 d5 71 00 00 08 29 26 24 00 00 00 00 71 62 f2 24 6c 84 44 04 11 e5 10 00 ]
==== test_llc_prim_ms() [end] ====
==== test_llc_prim_sgsn() [start] ====
test_llc_prim_up_cb(): Rx LL-UNITDATA.indication TLLI=0xe1c5d364 SAPI=GMM l3=[08 01 01 d5 71 00 00 08 29 26 24 00 00 00 00 71 62 f2 24 6c 84 44 04 11 e5 10 00 ]

To view, visit change 31049. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: libosmo-gprs
Gerrit-Branch: master
Gerrit-Change-Id: I6a4454b4aa2c96e1f4ce7e2a5d5aba8ec1cf3f60
Gerrit-Change-Number: 31049
Gerrit-PatchSet: 2
Gerrit-Owner: pespin <pespin@sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <vyanitskiy@sysmocom.de>
Gerrit-Reviewer: laforge <laforge@osmocom.org>
Gerrit-Reviewer: pespin <pespin@sysmocom.de>
Gerrit-CC: arehbein <arehbein@sysmocom.de>
Gerrit-MessageType: merged