aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc
diff options
context:
space:
mode:
authorJacob Erlbeck <jerlbeck@sysmocom.de>2014-09-11 10:30:21 +0200
committerJacob Erlbeck <jerlbeck@sysmocom.de>2014-09-18 08:49:21 +0200
commit0b243a106a45c1b47a1e389eda98e025b6950214 (patch)
treee093904e66c38a1190a38c7360751817b7b6f78d /openbsc
parentee11bc0f5c69d8ffa78b5de1de0ec365e4de4a12 (diff)
gbproxy: Refactor gbprox_process_bssgp_ul into smaller functions
gbprox_process_bssgp_ul has grown quite large mainly by the addition of IMSI acquisition. This patch moves that code into several smaller functions. In addition, the peer resolution which is similar to that in gbprox_process_bssgp_dl is moved into a separate function, too. Sponsored-by: On-Waves ehf
Diffstat (limited to 'openbsc')
-rw-r--r--openbsc/src/gprs/gb_proxy.c327
1 files changed, 195 insertions, 132 deletions
diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c
index f7afe947d..514898a59 100644
--- a/openbsc/src/gprs/gb_proxy.c
+++ b/openbsc/src/gprs/gb_proxy.c
@@ -254,14 +254,16 @@ uint32_t gbproxy_make_sgsn_tlli(struct gbproxy_peer *peer,
}
/* Returns != 0 iff IMSI acquisition was in progress */
-int gbproxy_reset_imsi_acquisition(struct gbproxy_tlli_info* tlli_info)
+static int gbproxy_restart_imsi_acquisition(struct gbproxy_tlli_info* tlli_info)
{
int in_progress = 0;
if (!tlli_info)
return 0;
- if (tlli_info->imsi_acq_pending)
+ if (tlli_info->imsi_acq_pending) {
in_progress = 1;
+ tlli_info->imsi_acq_retries += 1;
+ }
gbproxy_tlli_info_discard_messages(tlli_info);
tlli_info->imsi_acq_pending = 0;
@@ -269,6 +271,187 @@ int gbproxy_reset_imsi_acquisition(struct gbproxy_tlli_info* tlli_info)
return in_progress;
}
+static void gbproxy_reset_imsi_acquisition(struct gbproxy_tlli_info* tlli_info)
+{
+ gbproxy_restart_imsi_acquisition(tlli_info);
+ tlli_info->imsi_acq_retries = 0;
+}
+
+static void gbproxy_flush_stored_messages(struct gbproxy_peer *peer,
+ struct msgb *msg,
+ uint16_t sgsn_nsei,
+ time_t now,
+ struct gbproxy_tlli_info* tlli_info,
+ struct gprs_gb_parse_context *parse_ctx)
+{
+ int rc;
+ struct msgb *stored_msg;
+ /* Got identity response with IMSI, assuming the request had
+ * been generated by the gbproxy */
+
+ LOGP(DLLC, LOGL_DEBUG,
+ "NSEI=%d(BSS) IMSI acquisition succeeded, "
+ "flushing stored messages\n",
+ msgb_nsei(msg));
+
+ /* Patch and flush stored messages towards the SGSN */
+ while ((stored_msg = msgb_dequeue(&tlli_info->stored_msgs))) {
+ struct gprs_gb_parse_context tmp_parse_ctx = {0};
+ tmp_parse_ctx.to_bss = 0;
+ int len_change = 0;
+
+ gprs_gb_parse_bssgp(msgb_bssgph(stored_msg),
+ msgb_bssgp_len(stored_msg),
+ &tmp_parse_ctx);
+ gbproxy_patch_bssgp(msg, msgb_bssgph(stored_msg),
+ msgb_bssgp_len(stored_msg),
+ peer, tlli_info, &len_change,
+ &tmp_parse_ctx);
+
+ gbproxy_update_tlli_state_after(peer, tlli_info, now,
+ &tmp_parse_ctx);
+
+ rc = gbprox_relay2sgsn(peer->cfg, stored_msg,
+ msgb_bvci(msg), sgsn_nsei);
+
+ if (rc < 0)
+ LOGP(DLLC, LOGL_ERROR,
+ "NSEI=%d(BSS) failed to send stored message "
+ "(%s)\n",
+ msgb_nsei(msg),
+ parse_ctx->llc_msg_name ?
+ parse_ctx->llc_msg_name : "BSSGP");
+ msgb_free(stored_msg);
+ }
+}
+
+static void gbproxy_acquire_imsi(struct gbproxy_peer *peer,
+ struct gbproxy_tlli_info* tlli_info,
+ uint16_t bvci)
+{
+ struct msgb *idreq_msg;
+
+ /* Send IDENT REQ */
+ idreq_msg = gsm48_msgb_alloc();
+ gprs_put_identity_req(idreq_msg, GSM_MI_TYPE_IMSI);
+ /* Workaround to avoid N(U) collisions and to enable a restart
+ * of the IMSI acquisition procedure. This will work unless the
+ * SGSN has an initial V(UT) within [256-32, 256+n_retries]
+ * (see GSM 04.64, 8.4.2).
+ * TODO: Check whether it is sensible to rely on this, it might
+ * be an issue when P-TMSI patching is _not_ enabled and the SGSN
+ * doesn't reset V(UT) after a detach. */
+ gprs_push_llc_ui(idreq_msg, 0, GPRS_SAPI_GMM,
+ (tlli_info->imsi_acq_retries + 256) % 512);
+ gprs_push_bssgp_dl_unitdata(idreq_msg, tlli_info->tlli.current);
+ gbprox_relay2peer(idreq_msg, peer, bvci);
+ msgb_free(idreq_msg);
+}
+
+
+/* Return != 0 iff msg still needs to be processed */
+static int gbproxy_imsi_acquisition(struct gbproxy_peer *peer,
+ struct msgb *msg,
+ uint16_t sgsn_nsei,
+ time_t now,
+ struct gbproxy_tlli_info* tlli_info,
+ struct gprs_gb_parse_context *parse_ctx)
+{
+ if (!tlli_info)
+ return 1;
+
+ if (parse_ctx->g48_hdr &&
+ parse_ctx->g48_hdr->msg_type == GSM48_MT_GMM_ATTACH_REQ)
+ {
+ if (gbproxy_restart_imsi_acquisition(tlli_info)) {
+ LOGP(DLLC, LOGL_INFO,
+ "NSEI=%d(BSS) IMSI acquisition was in progress "
+ "when receiving an ATTACH_REQ.\n",
+ msgb_nsei(msg));
+ }
+ }
+
+ if (tlli_info->imsi_acq_pending && parse_ctx->g48_hdr &&
+ parse_ctx->g48_hdr->proto_discr == GSM48_PDISC_MM_GPRS &&
+ parse_ctx->g48_hdr->msg_type == GSM48_MT_GMM_ID_RESP &&
+ parse_ctx->imsi_len > 0) {
+ /* The IMSI is now available */
+ gbproxy_flush_stored_messages(peer, msg, sgsn_nsei, now,
+ tlli_info, parse_ctx);
+
+ gbproxy_reset_imsi_acquisition(tlli_info);
+ return 0;
+ }
+
+ if (tlli_info->imsi_acq_pending) {
+ struct msgb *stored_msg;
+
+ LOGP(DLLC, LOGL_DEBUG,
+ "NSEI=%d(BSS) IMSI acquisition in progess, "
+ "storing message (%s)\n",
+ msgb_nsei(msg),
+ parse_ctx->llc_msg_name ? parse_ctx->llc_msg_name : "BSSGP");
+
+ /* Enqueue unpatched messages */
+ stored_msg = gprs_msgb_copy(msg, "process_bssgp_ul");
+ msgb_enqueue(&tlli_info->stored_msgs, stored_msg);
+
+ return 0;
+ }
+
+ if (tlli_info->mi_data_len == 0) {
+ struct msgb *stored_msg = gprs_msgb_copy(msg, "process_bssgp_ul");
+
+ LOGP(DLLC, LOGL_DEBUG,
+ "NSEI=%d(BSS) IMSI is required but not available, "
+ "storing message (%s)\n",
+ msgb_nsei(msg),
+ parse_ctx->llc_msg_name ? parse_ctx->llc_msg_name : "BSSGP");
+
+ /* Enqueue message */
+ msgb_enqueue(&tlli_info->stored_msgs, stored_msg);
+
+ gbproxy_acquire_imsi(peer, tlli_info, msgb_bvci(msg));
+
+ tlli_info->imsi_acq_pending = 1;
+
+ /* There is no explicit retransmission handling, the
+ * implementation relies on the MS doing proper retransmissions
+ * of the triggering message instead */
+
+ return 0;
+ }
+
+ return 1;
+}
+
+struct gbproxy_peer *gbproxy_find_peer(struct gbproxy_config *cfg,
+ struct msgb *msg,
+ struct gprs_gb_parse_context *parse_ctx)
+{
+ struct gbproxy_peer *peer = NULL;
+
+ if (msgb_bvci(msg) >= 2)
+ peer = gbproxy_peer_by_bvci(cfg, msgb_bvci(msg));
+
+ if (!peer && !parse_ctx->to_bss)
+ peer = gbproxy_peer_by_nsei(cfg, msgb_nsei(msg));
+
+ if (!peer)
+ peer = gbproxy_peer_by_bssgp_tlv(cfg, &parse_ctx->bssgp_tp);
+
+ if (!peer) {
+ LOGP(DLLC, LOGL_INFO,
+ "NSEI=%d(%s) patching: didn't find peer for message, "
+ "PDU %d\n",
+ msgb_nsei(msg), parse_ctx->to_bss ? "BSS" : "SGSN",
+ parse_ctx->pdu_type);
+ /* Increment counter */
+ rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_PATCH_PEER_ERR]);
+ }
+ return peer;
+}
+
/* patch BSSGP message */
static int gbprox_process_bssgp_ul(struct gbproxy_config *cfg,
struct msgb *msg,
@@ -303,24 +486,11 @@ static int gbprox_process_bssgp_ul(struct gbproxy_config *cfg,
}
/* Get peer */
- if (!peer && msgb_bvci(msg) >= 2)
- peer = gbproxy_peer_by_bvci(cfg, msgb_bvci(msg));
-
if (!peer)
- peer = gbproxy_peer_by_nsei(cfg, msgb_nsei(msg));
+ peer = gbproxy_find_peer(cfg, msg, &parse_ctx);
if (!peer)
- peer = gbproxy_peer_by_bssgp_tlv(cfg, &parse_ctx.bssgp_tp);
-
- if (!peer) {
- LOGP(DLLC, LOGL_INFO,
- "NSEI=%d(BSS) patching: didn't find peer for message, "
- "PDU %d\n",
- msgb_nsei(msg), parse_ctx.pdu_type);
- /* Increment counter */
- rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_PATCH_PEER_ERR]);
return 0;
- }
now = time(NULL);
@@ -339,13 +509,6 @@ static int gbprox_process_bssgp_ul(struct gbproxy_config *cfg,
switch (parse_ctx.g48_hdr->msg_type) {
case GSM48_MT_GMM_ATTACH_REQ:
rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_ATTACH_REQS]);
- if (gbproxy_reset_imsi_acquisition(tlli_info)) {
- LOGP(DLLC, LOGL_INFO,
- "NSEI=%d(BSS) IMSI acquisition was in progress "
- "when receiving an ATTACH_REQ.\n",
- msgb_nsei(msg));
- tlli_info->imsi_acq_retries += 1;
- }
break;
default:
@@ -358,105 +521,14 @@ static int gbprox_process_bssgp_ul(struct gbproxy_config *cfg,
send_msg_directly = 1;
}
- if (tlli_info && tlli_info->imsi_acq_pending && parse_ctx.g48_hdr &&
- parse_ctx.g48_hdr->proto_discr == GSM48_PDISC_MM_GPRS &&
- parse_ctx.g48_hdr->msg_type == GSM48_MT_GMM_ID_RESP &&
- parse_ctx.imsi_len > 0) {
- struct msgb *stored_msg;
- /* Got identity response with IMSI, assuming the request had
- * been generated by the gbproxy */
-
- LOGP(DLLC, LOGL_DEBUG,
- "NSEI=%d(BSS) IMSI acquisition succeeded, "
- "flushing stored messages\n",
- msgb_nsei(msg));
-
- /* TODO: Patch and flush stored messages towards the SGSN */
- while ((stored_msg = msgb_dequeue(&tlli_info->stored_msgs))) {
- struct gprs_gb_parse_context tmp_parse_ctx = {0};
- tmp_parse_ctx.to_bss = 0;
- len_change = 0;
-
- gprs_gb_parse_bssgp(msgb_bssgph(stored_msg),
- msgb_bssgp_len(stored_msg),
- &tmp_parse_ctx);
- gbproxy_patch_bssgp(msg, msgb_bssgph(stored_msg),
- msgb_bssgp_len(stored_msg),
- peer, tlli_info, &len_change,
- &tmp_parse_ctx);
-
- gbproxy_update_tlli_state_after(peer, tlli_info, now,
- &tmp_parse_ctx);
-
- rc = gbprox_relay2sgsn(cfg, stored_msg, msgb_bvci(msg),
- sgsn_nsei);
-
- if (rc < 0)
- LOGP(DLLC, LOGL_ERROR,
- "NSEI=%d(BSS) failed to send stored message "
- "(%s)\n",
- msgb_nsei(msg),
- parse_ctx.llc_msg_name ? parse_ctx.llc_msg_name : "BSSGP");
- msgb_free(stored_msg);
- }
-
- tlli_info->imsi_acq_pending = 0;
-
- return 0;
- }
-
- if (tlli_info && tlli_info->imsi_acq_pending) {
- struct msgb *stored_msg;
-
- LOGP(DLLC, LOGL_DEBUG,
- "NSEI=%d(BSS) IMSI acquisition in progess, "
- "storing message (%s)\n",
- msgb_nsei(msg),
- parse_ctx.llc_msg_name ? parse_ctx.llc_msg_name : "BSSGP");
-
- /* Enqueue unpatched messages */
- stored_msg = gprs_msgb_copy(msg, "process_bssgp_ul");
- msgb_enqueue(&tlli_info->stored_msgs, stored_msg);
-
- /* TODO: Timeout, retransmit IDENT REQ if expired */
- return 0;
- }
-
- if (cfg->acquire_imsi && tlli_info && tlli_info->mi_data_len == 0) {
- struct msgb *idreq_msg;
- struct msgb *stored_msg = gprs_msgb_copy(msg, "process_bssgp_ul");
-
- LOGP(DLLC, LOGL_DEBUG,
- "NSEI=%d(BSS) IMSI is required but not available, "
- "storing message (%s)\n",
- msgb_nsei(msg),
- parse_ctx.llc_msg_name ? parse_ctx.llc_msg_name : "BSSGP");
-
- /* Enqueue message */
- msgb_enqueue(&tlli_info->stored_msgs, stored_msg);
-
- /* Send IDENT REQ */
- idreq_msg = gsm48_msgb_alloc();
- gprs_put_identity_req(idreq_msg, GSM_MI_TYPE_IMSI);
- /* Workaround to avoid N(U) collisions and to enable a restart
- * of the IMSI acquisition procedure. This will work unless the
- * SGSN has an initial V(UT) within [256-32, 256+n_retries]
- * (see GSM 04.64, 8.4.2).
- * TODO: Check whether it is sensible to rely on this, it might
- * be an issue when P-TMSI patching is _not_ enabled and the SGSN
- * doesn't reset V(UT) after a detach. */
- gprs_push_llc_ui(idreq_msg, 0, GPRS_SAPI_GMM,
- (tlli_info->imsi_acq_retries + 256) % 512);
- gprs_push_bssgp_dl_unitdata(idreq_msg, tlli_info->tlli.current);
- gbprox_relay2peer(idreq_msg, peer, msgb_bvci(msg));
- msgb_free(idreq_msg);
-
- tlli_info->imsi_acq_pending = 1;
-
- return 0;
+ /* Handle IMSI acquisition */
+ if (cfg->acquire_imsi) {
+ rc = gbproxy_imsi_acquisition(peer, msg, sgsn_nsei, now,
+ tlli_info, &parse_ctx);
+ if (rc <= 0)
+ return rc;
}
-
gbproxy_patch_bssgp(msg, msgb_bssgph(msg), msgb_bssgp_len(msg),
peer, tlli_info, &len_change, &parse_ctx);
@@ -502,21 +574,12 @@ static void gbprox_process_bssgp_dl(struct gbproxy_config *cfg,
}
}
- if (!peer && msgb_bvci(msg) >= 2)
- peer = gbproxy_peer_by_bvci(cfg, msgb_bvci(msg));
-
+ /* Get peer */
if (!peer)
- peer = gbproxy_peer_by_bssgp_tlv(cfg, &parse_ctx.bssgp_tp);
+ peer = gbproxy_find_peer(cfg, msg, &parse_ctx);
- if (!peer) {
- LOGP(DLLC, LOGL_INFO,
- "NSEI=%d(SGSN) patching: didn't find peer for message, "
- "PDU %d\n",
- msgb_nsei(msg), parse_ctx.pdu_type);
- /* Increment counter */
- rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_PATCH_PEER_ERR]);
+ if (!peer)
return;
- }
now = time(NULL);