gbproxy: Implement IMSI acquisition

To modify or route messages based on the IMSI the latter must be known
when the action shall take place.

This patch modifies the gbproxy to optionally retain and enqueue
messages from the MS while initiating an identification procedure.
Further message processing of the LLC PTP link towards the SGSN will
be done, when the identity of the MS has been acquired.

Note that the N(U) of the LLC GMM SAPI are not adjusted, so it is
possible that adjacent messages of a single LLC link arriving either
at the BSS or the SGSN have the same N(U) and might get discarded,
leading to retransmissions and additional delay.

Note also that retransmissions and packet loss are not yet handled
explicitely. If for instance the generated IDENT REQ gets lost, the
gbproxy will not act on its own. In this case, the MS will time out
and eventually resend the Attach Request on which the gbproxy will
act exactly like before (thus having two Attach Req messages in its
queue, which will both be sent after the Ident Resp arrives).

This has been tested successfully with an E71, needing one
retransmission by the SGSN due to an N(U) collision.

Ticket: OW#1261
Sponsored-by: On-Waves ehf
This commit is contained in:
Jacob Erlbeck 2014-08-22 17:10:01 +02:00
parent 28fe98891f
commit 5f4ef321a6
6 changed files with 264 additions and 23 deletions

View File

@ -82,7 +82,10 @@ struct gbproxy_config {
enum gbproxy_patch_mode patch_mode;
int tlli_max_age;
int tlli_max_len;
/* Experimental config */
int patch_ptmsi;
int acquire_imsi;
/* IMSI checking/matching */
int check_imsi;
@ -143,6 +146,8 @@ struct gbproxy_tlli_info {
uint8_t *mi_data;
size_t mi_data_len;
int imsi_acq_pending;
struct llist_head stored_msgs;
int enable_patching;
};

View File

@ -72,6 +72,11 @@ static const struct rate_ctr_group_desc global_ctrg_desc = {
.ctr_desc = global_ctr_description,
};
static int gbprox_relay2peer(struct msgb *old_msg, struct gbproxy_peer *peer,
uint16_t ns_bvci);
static int gbprox_relay2sgsn(struct gbproxy_config *cfg, struct msgb *old_msg,
uint16_t ns_bvci);
static int check_peer_nsei(struct gbproxy_peer *peer, uint16_t nsei)
{
if (peer->nsei != nsei) {
@ -92,6 +97,81 @@ static void strip_ns_hdr(struct msgb *msg)
msgb_pull(msg, strip_len);
}
/* Transmit Chapter 9.2.10 Identity Request */
static void gprs_put_identity_req(struct msgb *msg, uint8_t id_type)
{
struct gsm48_hdr *gh;
id_type &= GSM_MI_TYPE_MASK;
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
gh->proto_discr = GSM48_PDISC_MM_GPRS;
gh->msg_type = GSM48_MT_GMM_ID_REQ;
gh->data[0] = id_type;
}
static void gprs_push_llc_ui(struct msgb *msg,
int is_uplink, unsigned sapi, unsigned nu)
{
const uint8_t e_bit = 0;
const uint8_t pm_bit = 1;
const uint8_t cr_bit = is_uplink ? 0 : 1;
size_t msg_size = msgb_length(msg);
uint8_t *llc;
uint8_t *fcs_field;
uint32_t fcs;
nu &= 0x01ff; /* 9 Bit */
llc = msgb_push(msg, 3);
llc[0] = (cr_bit << 6) | (sapi & 0x0f);
llc[1] = 0xc0 | (nu >> 6); /* UI frame */
llc[2] = (nu << 2) | ((e_bit & 1) << 1) | (pm_bit & 1);
fcs = gprs_llc_fcs(llc, msgb_length(msg));
fcs_field = msgb_put(msg, 3);
fcs_field[0] = (uint8_t)(fcs >> 0);
fcs_field[1] = (uint8_t)(fcs >> 8);
fcs_field[2] = (uint8_t)(fcs >> 16);
}
static void gprs_push_bssgp_dl_unitdata(struct msgb *msg,
uint32_t tlli)
{
struct bssgp_ud_hdr *budh;
uint8_t *llc = msgb_data(msg);
size_t llc_size = msgb_length(msg);
const size_t llc_ie_hdr_size = 3;
const uint8_t qos_profile[] = {0x00, 0x50, 0x20}; /* hard-coded */
const uint8_t lifetime[] = {0x02, 0x58}; /* 6s hard-coded */
const size_t bssgp_overhead = sizeof(*budh) +
TVLV_GROSS_LEN(sizeof(lifetime)) + llc_ie_hdr_size;
uint8_t *ie;
uint32_t tlli_be = htonl(tlli);
budh = (struct bssgp_ud_hdr *)msgb_push(msg, bssgp_overhead);
budh->pdu_type = BSSGP_PDUT_DL_UNITDATA;
memcpy(&budh->tlli, &tlli_be, sizeof(budh->tlli));
memcpy(&budh->qos_profile, qos_profile, sizeof(budh->qos_profile));
ie = budh->data;
tvlv_put(ie, BSSGP_IE_PDU_LIFETIME, sizeof(lifetime), lifetime);
ie += TVLV_GROSS_LEN(sizeof(lifetime));
/* Note: Add alignment before the LLC IE if inserting other IE */
*(ie++) = BSSGP_IE_LLC_PDU;
*(ie++) = llc_size / 256;
*(ie++) = llc_size % 256;
OSMO_ASSERT(ie == llc);
msgb_bssgph(msg) = (uint8_t *)budh;
msgb_tlli(msg) = tlli;
}
/* update peer according to the BSS message */
static void gbprox_update_current_raid(uint8_t *raid_enc,
struct gbproxy_peer *peer,
@ -175,9 +255,9 @@ uint32_t gbproxy_make_sgsn_tlli(struct gbproxy_peer *peer,
}
/* patch BSSGP message */
static void gbprox_process_bssgp_ul(struct gbproxy_config *cfg,
struct msgb *msg,
struct gbproxy_peer *peer)
static int gbprox_process_bssgp_ul(struct gbproxy_config *cfg,
struct msgb *msg,
struct gbproxy_peer *peer)
{
struct gprs_gb_parse_context parse_ctx = {0};
int rc;
@ -185,8 +265,9 @@ static void gbprox_process_bssgp_ul(struct gbproxy_config *cfg,
time_t now;
struct gbproxy_tlli_info *tlli_info = NULL;
if (!cfg->core_mcc && !cfg->core_mnc && !cfg->core_apn)
return;
if (!cfg->core_mcc && !cfg->core_mnc && !cfg->core_apn &&
!cfg->acquire_imsi)
return 1;
parse_ctx.to_bss = 0;
@ -200,7 +281,7 @@ static void gbprox_process_bssgp_ul(struct gbproxy_config *cfg,
"NSEI=%u(BSS) patching: "
"failed to parse BSSGP/GMM message\n",
msgb_nsei(msg));
return;
return 0;
}
}
@ -221,7 +302,7 @@ static void gbprox_process_bssgp_ul(struct gbproxy_config *cfg,
msgb_nsei(msg), parse_ctx.pdu_type);
/* Increment counter */
rate_ctr_inc(&cfg->ctrg->ctr[GBPROX_GLOB_CTR_PATCH_PEER_ERR]);
return;
return 0;
}
now = time(NULL);
@ -248,12 +329,103 @@ static void gbprox_process_bssgp_ul(struct gbproxy_config *cfg,
tlli_info = gbproxy_update_tlli_state_ul(peer, now, &parse_ctx);
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));
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);
gprs_push_llc_ui(idreq_msg, 0, GPRS_SAPI_GMM,
/* TODO: use a real N(U) */0);
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;
}
gbproxy_patch_bssgp(msg, msgb_bssgph(msg), msgb_bssgp_len(msg),
peer, tlli_info, &len_change, &parse_ctx);
gbproxy_update_tlli_state_after(peer, tlli_info, now, &parse_ctx);
return;
return 1;
}
/* patch BSSGP message to use core_mcc/mnc on the SGSN side */
@ -428,13 +600,16 @@ static int gbprox_rx_ptp_from_bss(struct gbproxy_config *cfg,
uint16_t nsvci, uint16_t ns_bvci)
{
struct gbproxy_peer *peer;
int rc;
peer = gbproxy_peer_by_bvci(cfg, ns_bvci);
if (peer)
check_peer_nsei(peer, nsei);
gbprox_process_bssgp_ul(cfg, msg, peer);
rc = gbprox_process_bssgp_ul(cfg, msg, peer);
if (!rc)
return 0;
return gbprox_relay2sgsn(cfg, msg, ns_bvci);
}

View File

@ -198,6 +198,8 @@ static struct gbproxy_tlli_info *gbproxy_tlli_info_alloc(
tlli_info->tlli.ptmsi = GSM_RESERVED_TMSI;
tlli_info->sgsn_tlli.ptmsi = GSM_RESERVED_TMSI;
INIT_LLIST_HEAD(&tlli_info->stored_msgs);
return tlli_info;
}

View File

@ -295,6 +295,28 @@ DEFUN(cfg_gbproxy_no_patch_ptmsi,
return CMD_SUCCESS;
}
#define GBPROXY_ACQUIRE_IMSI_STR "Acquire the IMSI before establishing a LLC connection (Experimental)\n"
DEFUN(cfg_gbproxy_acquire_imsi,
cfg_gbproxy_acquire_imsi_cmd,
"acquire-imsi",
GBPROXY_ACQUIRE_IMSI_STR)
{
g_cfg->acquire_imsi = 1;
return CMD_SUCCESS;
}
DEFUN(cfg_gbproxy_no_acquire_imsi,
cfg_gbproxy_no_acquire_imsi_cmd,
"no acquire-imsi",
NO_STR GBPROXY_ACQUIRE_IMSI_STR)
{
g_cfg->acquire_imsi = 0;
return CMD_SUCCESS;
}
#define GBPROXY_TLLI_LIST_STR "Set TLLI list parameters\n"
#define GBPROXY_MAX_AGE_STR "Limit maximum age\n"
@ -604,12 +626,14 @@ int gbproxy_vty_init(void)
install_element(GBPROXY_NODE, &cfg_gbproxy_core_apn_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_core_apn_match_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_patch_ptmsi_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_acquire_imsi_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_tlli_list_max_age_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_tlli_list_max_len_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_no_core_mcc_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_no_core_mnc_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_no_core_apn_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_no_patch_ptmsi_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_no_acquire_imsi_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_tlli_list_no_max_age_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_tlli_list_no_max_len_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_patch_mode_cmd);

View File

@ -137,8 +137,16 @@ static int dump_peers(FILE *stream, int indent, time_t now,
fprintf(stream, "/%08x",
tlli_info->sgsn_tlli.assigned);
}
rc = fprintf(stream, ", IMSI %s, AGE %d\n",
mi_buf, (int)age);
fprintf(stream, ", IMSI %s, AGE %d",
mi_buf, (int)age);
if (tlli_info->imsi_acq_pending)
fprintf(stream, ", IMSI acquisition in progress");
if (!llist_empty(&tlli_info->stored_msgs))
fprintf(stream, ", stored messages");
rc = fprintf(stream, "\n");
if (rc < 0)
return rc;
}
@ -1659,6 +1667,7 @@ static void test_gbproxy_imsi_acquisition()
gbcfg.core_apn = talloc_zero_size(NULL, 100);
gbcfg.core_apn_size = gprs_str_to_apn(gbcfg.core_apn, 100, "foo.bar");
gbcfg.patch_ptmsi = 1;
gbcfg.acquire_imsi = 1;
gbcfg.bss_ptmsi_state = 0;
gbcfg.sgsn_tlli_state = 1;
@ -1693,6 +1702,13 @@ static void test_gbproxy_imsi_acquisition()
dump_peers(stdout, 0, 0, &gbcfg);
send_llc_ul_ui(nsi, "IDENT RESPONSE", &bss_peer[0], 0x1002,
foreign_bss_tlli, &rai_bss, cell_id,
GPRS_SAPI_GMM, bss_nu++,
dtap_identity_resp, sizeof(dtap_identity_resp));
dump_peers(stdout, 0, 0, &gbcfg);
send_llc_dl_ui(nsi, "IDENT REQUEST", &sgsn_peer, 0x1002,
random_sgsn_tlli, 0, NULL, 0,
GPRS_SAPI_GMM, sgsn_nu++,

View File

@ -2469,11 +2469,30 @@ PROCESSING ATTACH REQUEST from 0x01020304:1111
CALLBACK, event 0, msg length 75, bvci 0x1002
00 00 10 02 01 80 00 de ad 00 00 04 08 88 00 f1 99 00 63 60 12 34 00 80 0e 00 34 01 c0 01 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 16 6d 01
NS UNITDATA MESSAGE to BSS, BVCI 0x1002, msg length 24 (gprs_ns_sendmsg)
MESSAGE to BSS at 0x01020304:1111, msg length 28
00 00 10 02 00 80 00 de ad 00 50 20 16 82 02 58 0e 00 09 41 c0 01 08 15 01 ff 6c ba
result (ATTACH REQUEST) = 0
Peers:
NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96
RAID patched (BSS ): 1
Attach Request count : 1
TLLI cache size : 1
TLLI-Cache: 1
TLLI 8000dead -> 7c69fb81, IMSI (none), AGE 0, IMSI acquisition in progress, stored messages
PROCESSING IDENT RESPONSE from 0x01020304:1111
00 00 10 02 01 80 00 de ad 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 05 08 16 08 11 12 13 14 15 16 17 18 ad 05 28
CALLBACK, event 0, msg length 40, bvci 0x1002
00 00 10 02 01 80 00 de ad 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 05 08 16 08 11 12 13 14 15 16 17 18 ad 05 28
NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 75 (gprs_ns_sendmsg)
MESSAGE to SGSN at 0x05060708:32000, msg length 79
00 00 10 02 01 7c 69 fb 81 00 00 04 08 88 21 63 54 00 63 60 12 34 00 80 0e 00 34 01 c0 01 08 01 02 f5 e0 21 08 02 05 f4 fb c5 46 79 11 22 33 40 50 60 19 18 b3 43 2b 25 96 62 00 60 80 9a c2 c6 62 00 60 80 ba c8 c6 62 00 60 80 00 16 6d 01
result (ATTACH REQUEST) = 79
result (IDENT RESPONSE) = 0
Peers:
NSEI 4096, BVCI 4098, not blocked, RAI 112-332-16464-96
@ -2482,7 +2501,7 @@ Peers:
Attach Request count : 1
TLLI cache size : 1
TLLI-Cache: 1
TLLI 8000dead -> 7c69fb81, IMSI (none), AGE 0
TLLI 8000dead -> 7c69fb81, IMSI 12131415161718, AGE 0
PROCESSING IDENT REQUEST from 0x05060708:32000
00 00 10 02 00 7c 69 fb 81 00 50 20 16 82 02 58 0e 89 41 c0 01 08 15 01 ff 6c ba
@ -2503,16 +2522,16 @@ Peers:
Attach Request count : 1
TLLI cache size : 1
TLLI-Cache: 1
TLLI 8000dead -> 7c69fb81, IMSI (none), AGE 0
TLLI 8000dead -> 7c69fb81, IMSI 12131415161718, AGE 0
PROCESSING IDENT RESPONSE from 0x01020304:1111
00 00 10 02 01 80 00 de ad 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 05 08 16 08 11 12 13 14 15 16 17 18 ad 05 28
00 00 10 02 01 80 00 de ad 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 09 08 16 08 11 12 13 14 15 16 17 18 ba 14 c3
CALLBACK, event 0, msg length 40, bvci 0x1002
00 00 10 02 01 80 00 de ad 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 05 08 16 08 11 12 13 14 15 16 17 18 ad 05 28
00 00 10 02 01 80 00 de ad 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 11 01 c0 09 08 16 08 11 12 13 14 15 16 17 18 ba 14 c3
NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 40 (gprs_ns_sendmsg)
MESSAGE to SGSN at 0x05060708:32000, msg length 44
00 00 10 02 01 7c 69 fb 81 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 11 01 c0 05 08 16 08 11 12 13 14 15 16 17 18 ad 05 28
00 00 10 02 01 7c 69 fb 81 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 11 01 c0 09 08 16 08 11 12 13 14 15 16 17 18 ba 14 c3
result (IDENT RESPONSE) = 44
@ -2549,14 +2568,14 @@ Peers:
TLLI-Cache: 1
TLLI 8000dead/c00f7304 -> 7c69fb81/efe2b700, IMSI 12131415161718, AGE 0
PROCESSING ATTACH COMPLETE from 0x01020304:1111
00 00 10 02 01 c0 0f 73 04 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 09 08 03 39 d7 bc
00 00 10 02 01 c0 0f 73 04 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 0d 08 03 55 1c ea
CALLBACK, event 0, msg length 31, bvci 0x1002
00 00 10 02 01 c0 0f 73 04 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 09 08 03 39 d7 bc
00 00 10 02 01 c0 0f 73 04 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 08 01 c0 0d 08 03 55 1c ea
NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 31 (gprs_ns_sendmsg)
MESSAGE to SGSN at 0x05060708:32000, msg length 35
00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 08 01 c0 09 08 03 39 d7 bc
00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 08 01 c0 0d 08 03 55 1c ea
result (ATTACH COMPLETE) = 35
@ -2792,14 +2811,14 @@ Gbproxy global:
BSSGP protocol error (SGSN): 1
Patch error: no peer : 1
PROCESSING DETACH REQ from 0x01020304:1111
00 00 10 02 01 c0 0f 73 04 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 15 01 c0 0d 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 37 67 c6
00 00 10 02 01 c0 0f 73 04 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 15 01 c0 11 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 6d b1 de
CALLBACK, event 0, msg length 44, bvci 0x1002
00 00 10 02 01 c0 0f 73 04 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 15 01 c0 0d 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 37 67 c6
00 00 10 02 01 c0 0f 73 04 00 00 04 08 88 11 22 33 40 50 60 12 34 00 80 0e 00 15 01 c0 11 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 6d b1 de
NS UNITDATA MESSAGE to SGSN, BVCI 0x1002, msg length 44 (gprs_ns_sendmsg)
MESSAGE to SGSN at 0x05060708:32000, msg length 48
00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 15 01 c0 0d 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 37 67 c6
00 00 10 02 01 ef e2 b7 00 00 00 04 08 88 21 63 54 40 50 60 12 34 00 80 0e 00 15 01 c0 11 08 05 01 18 05 f4 ef e2 b7 00 19 03 b9 97 cb 6d b1 de
result (DETACH REQ) = 48