aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src/gprs/gb_proxy.c
diff options
context:
space:
mode:
Diffstat (limited to 'openbsc/src/gprs/gb_proxy.c')
-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);