aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHolger Hans Peter Freyther <holger@moiji-mobile.com>2013-07-30 09:29:27 +0200
committerHolger Hans Peter Freyther <holger@moiji-mobile.com>2013-07-31 14:57:21 +0200
commit964a9b3e20b67bebf8d1878ee5c651c10fdd2a94 (patch)
tree86fb4252fc7f8dc7c0062be961e8b57c6b41c1a3
parent012a7eec2903444765e7a005850665c98868aa21 (diff)
gprs_llc: Work on finding the right LLE/LLME in case of routing area update
Attempt to solve what f0901f0067e363c0ced6254db1b45a9771640412 tried to solve without breaking the case of someone with a foreign TLLI from a different network. Lookup with the foreign TLLI converted to a local one in case we did not find the TLLI and only then create a LLE/LLME on the fly for the RX path.
-rw-r--r--openbsc/src/gprs/gprs_llc.c159
1 files changed, 94 insertions, 65 deletions
diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c
index 57e557ae3..5a74a6343 100644
--- a/openbsc/src/gprs/gprs_llc.c
+++ b/openbsc/src/gprs/gprs_llc.c
@@ -36,6 +36,54 @@
#include <openbsc/crc24.h>
#include <openbsc/sgsn.h>
+enum gprs_llc_cmd {
+ GPRS_LLC_NULL,
+ GPRS_LLC_RR,
+ GPRS_LLC_ACK,
+ GPRS_LLC_RNR,
+ GPRS_LLC_SACK,
+ GPRS_LLC_DM,
+ GPRS_LLC_DISC,
+ GPRS_LLC_UA,
+ GPRS_LLC_SABM,
+ GPRS_LLC_FRMR,
+ GPRS_LLC_XID,
+ GPRS_LLC_UI,
+};
+
+static const struct value_string llc_cmd_strs[] = {
+ { GPRS_LLC_NULL, "NULL" },
+ { GPRS_LLC_RR, "RR" },
+ { GPRS_LLC_ACK, "ACK" },
+ { GPRS_LLC_RNR, "RNR" },
+ { GPRS_LLC_SACK, "SACK" },
+ { GPRS_LLC_DM, "DM" },
+ { GPRS_LLC_DISC, "DISC" },
+ { GPRS_LLC_UA, "UA" },
+ { GPRS_LLC_SABM, "SABM" },
+ { GPRS_LLC_FRMR, "FRMR" },
+ { GPRS_LLC_XID, "XID" },
+ { GPRS_LLC_UI, "UI" },
+ { 0, NULL }
+};
+
+struct gprs_llc_hdr_parsed {
+ uint8_t sapi;
+ uint8_t is_cmd:1,
+ ack_req:1,
+ is_encrypted:1;
+ uint32_t seq_rx;
+ uint32_t seq_tx;
+ uint32_t fcs;
+ uint32_t fcs_calc;
+ uint8_t *data;
+ uint16_t data_len;
+ uint16_t crc_length;
+ enum gprs_llc_cmd cmd;
+};
+
+static struct gprs_llc_llme *llme_alloc(uint32_t tlli);
+
/* Entry function from upper level (LLC), asking us to transmit a BSSGP PDU
* to a remote MS (identified by TLLI) at a BTS identified by its BVCI and NSEI */
static int _bssgp_tx_dl_ud(struct msgb *msg, struct sgsn_mm_ctx *mmctx)
@@ -158,6 +206,47 @@ static struct gprs_llc_lle *lle_by_tlli_sapi(const uint32_t tlli, uint8_t sapi)
return NULL;
}
+/* lookup LLC Entity for RX based on DLCI (TLLI+SAPI tuple) */
+static struct gprs_llc_lle *lle_for_rx_by_tlli_sapi(const uint32_t tlli,
+ uint8_t sapi, enum gprs_llc_cmd cmd)
+{
+ struct gprs_llc_lle *lle;
+
+ /* We already know about this TLLI */
+ lle = lle_by_tlli_sapi(tlli, sapi);
+ if (lle)
+ return lle;
+
+ /* Maybe it is a routing area update but we already know this sapi? */
+ if (gprs_tlli_type(tlli) == TLLI_FOREIGN) {
+ lle = lle_by_tlli_sapi(tlli_foreign2local(tlli), sapi);
+ if (lle) {
+ LOGP(DLLC, LOGL_NOTICE,
+ "LLC RX: Found a local entry for TLLI 0x%08x\n",
+ tlli);
+ return lle;
+ }
+ }
+
+ /* 7.2.1.1 LLC belonging to unassigned TLLI+SAPI shall be discarded,
+ * except UID and XID frames with SAPI=1 */
+ if (sapi == GPRS_SAPI_GMM &&
+ (cmd == GPRS_LLC_XID || cmd == GPRS_LLC_UI)) {
+ struct gprs_llc_llme *llme;
+ /* FIXME: don't use the TLLI but the 0xFFFF unassigned? */
+ llme = llme_alloc(tlli);
+ LOGP(DLLC, LOGL_DEBUG, "LLC RX: unknown TLLI 0x%08x, "
+ "creating LLME on the fly\n", tlli);
+ lle = &llme->lle[sapi];
+ return lle;
+ }
+
+ LOGP(DLLC, LOGL_NOTICE,
+ "unknown TLLI(0x%08x)/SAPI(%d): Silently dropping\n",
+ tlli, sapi);
+ return NULL;
+}
+
static void lle_init(struct gprs_llc_llme *llme, uint8_t sapi)
{
struct gprs_llc_lle *lle = &llme->lle[sapi];
@@ -197,52 +286,6 @@ static void llme_free(struct gprs_llc_llme *llme)
talloc_free(llme);
}
-enum gprs_llc_cmd {
- GPRS_LLC_NULL,
- GPRS_LLC_RR,
- GPRS_LLC_ACK,
- GPRS_LLC_RNR,
- GPRS_LLC_SACK,
- GPRS_LLC_DM,
- GPRS_LLC_DISC,
- GPRS_LLC_UA,
- GPRS_LLC_SABM,
- GPRS_LLC_FRMR,
- GPRS_LLC_XID,
- GPRS_LLC_UI,
-};
-
-static const struct value_string llc_cmd_strs[] = {
- { GPRS_LLC_NULL, "NULL" },
- { GPRS_LLC_RR, "RR" },
- { GPRS_LLC_ACK, "ACK" },
- { GPRS_LLC_RNR, "RNR" },
- { GPRS_LLC_SACK, "SACK" },
- { GPRS_LLC_DM, "DM" },
- { GPRS_LLC_DISC, "DISC" },
- { GPRS_LLC_UA, "UA" },
- { GPRS_LLC_SABM, "SABM" },
- { GPRS_LLC_FRMR, "FRMR" },
- { GPRS_LLC_XID, "XID" },
- { GPRS_LLC_UI, "UI" },
- { 0, NULL }
-};
-
-struct gprs_llc_hdr_parsed {
- uint8_t sapi;
- uint8_t is_cmd:1,
- ack_req:1,
- is_encrypted:1;
- uint32_t seq_rx;
- uint32_t seq_tx;
- uint32_t fcs;
- uint32_t fcs_calc;
- uint8_t *data;
- uint16_t data_len;
- uint16_t crc_length;
- enum gprs_llc_cmd cmd;
-};
-
#define LLC_ALLOC_SIZE 16384
#define UI_HDR_LEN 3
#define N202 4
@@ -360,6 +403,8 @@ int gprs_llc_tx_ui(struct msgb *msg, uint8_t sapi, int command,
/* look-up or create the LL Entity for this (TLLI, SAPI) tuple */
lle = lle_by_tlli_sapi(msgb_tlli(msg), sapi);
+ if (!lle)
+ lle = lle_by_tlli_sapi(tlli_foreign2local(msgb_tlli(msg)), sapi);
if (!lle) {
struct gprs_llc_llme *llme;
LOGP(DLLC, LOGL_ERROR, "LLC TX: unknown TLLI 0x%08x, "
@@ -766,25 +811,9 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv)
}
/* find the LLC Entity for this TLLI+SAPI tuple */
- lle = lle_by_tlli_sapi(msgb_tlli(msg), llhp.sapi);
-
- /* 7.2.1.1 LLC belonging to unassigned TLLI+SAPI shall be discarded,
- * except UID and XID frames with SAPI=1 */
- if (!lle) {
- if (llhp.sapi == GPRS_SAPI_GMM &&
- (llhp.cmd == GPRS_LLC_XID || llhp.cmd == GPRS_LLC_UI)) {
- struct gprs_llc_llme *llme;
- /* FIXME: don't use the TLLI but the 0xFFFF unassigned? */
- llme = llme_alloc(msgb_tlli(msg));
- LOGP(DLLC, LOGL_DEBUG, "LLC RX: unknown TLLI 0x%08x, "
- "creating LLME on the fly\n", msgb_tlli(msg));
- lle = &llme->lle[llhp.sapi];
- } else {
- LOGP(DLLC, LOGL_NOTICE,
- "unknown TLLI/SAPI: Silently dropping\n");
- return 0;
- }
- }
+ lle = lle_for_rx_by_tlli_sapi(msgb_tlli(msg), llhp.sapi, llhp.cmd);
+ if (!lle)
+ return 0;
/* decrypt information field + FCS, if needed! */
if (llhp.is_encrypted) {