aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHolger Hans Peter Freyther <holger@moiji-mobile.com>2014-03-10 15:00:20 +0100
committerHolger Hans Peter Freyther <holger@moiji-mobile.com>2014-03-10 15:00:20 +0100
commit4b3de6840ef08b0630bafb9d4d19fc2d10aacdd1 (patch)
tree3d9ffc8100b1bdb4350bd1bea206f0eeae133f4c
parent10f0bdecad8d711ccc5fcc04bb0be0adf11a7902 (diff)
parent8dac4159adb7377f016317808e3a6b0c79df7fa1 (diff)
Merge branch 'jerlbeck/fixes/ladp-sms'
-rw-r--r--include/osmocom/core/msgb.h16
-rw-r--r--src/gsm/lapdm.c41
-rw-r--r--src/msgb.c49
-rw-r--r--tests/lapd/lapd_test.c100
-rw-r--r--tests/lapd/lapd_test.ok18
5 files changed, 165 insertions, 59 deletions
diff --git a/include/osmocom/core/msgb.h b/include/osmocom/core/msgb.h
index fe2733b..33e8081 100644
--- a/include/osmocom/core/msgb.h
+++ b/include/osmocom/core/msgb.h
@@ -73,6 +73,7 @@ extern void msgb_enqueue(struct llist_head *queue, struct msgb *msg);
extern struct msgb *msgb_dequeue(struct llist_head *queue);
extern void msgb_reset(struct msgb *m);
uint16_t msgb_length(const struct msgb *msg);
+extern const char *msgb_hexdump(const struct msgb *msg);
#ifdef MSGB_DEBUG
#include <osmocom/core/panic.h>
@@ -299,6 +300,21 @@ static inline unsigned char *msgb_pull(struct msgb *msgb, unsigned int len)
return msgb->data += len;
}
+/*! \brief remove (pull) all headers in front of l3h from the message buffer.
+ * \param[in] msgb message buffer with a valid l3h
+ * \returns pointer to new start of msgb (l3h)
+ *
+ * This function moves the \a data pointer of the \ref msgb further back
+ * in the message, thereby shrinking the size of the message.
+ * l1h and l2h will be cleared.
+ */
+static inline unsigned char *msgb_pull_to_l3(struct msgb *msg)
+{
+ unsigned char *ret = msgb_pull(msg, msg->l3h - msg->data);
+ msg->l1h = msg->l2h = NULL;
+ return ret;
+}
+
/*! \brief remove uint8 from front of message
* \param[in] msgb message buffer
* \returns 8bit value taken from end of msgb
diff --git a/src/gsm/lapdm.c b/src/gsm/lapdm.c
index 19f78a1..41f4be7 100644
--- a/src/gsm/lapdm.c
+++ b/src/gsm/lapdm.c
@@ -193,14 +193,6 @@ static struct lapdm_datalink *datalink_for_sapi(struct lapdm_entity *le, uint8_t
}
}
-/* remove the L2 header from a MSGB */
-static inline unsigned char *msgb_pull_l2h(struct msgb *msg)
-{
- unsigned char *ret = msgb_pull(msg, msg->l3h - msg->l2h);
- msg->l2h = NULL;
- return ret;
-}
-
/* Append padding (if required) */
static void lapdm_pad_msgb(struct msgb *msg, uint8_t n201)
{
@@ -611,7 +603,7 @@ static int l2_ph_data_ind(struct msgb *msg, struct lapdm_entity *le,
lctx.length = n201;
lctx.more = 0;
msg->l3h = msg->l2h + 2;
- msgb_pull_l2h(msg);
+ msgb_pull_to_l3(msg);
} else {
/* length field */
if (!(msg->l2h[2] & LAPDm_EL)) {
@@ -629,7 +621,7 @@ static int l2_ph_data_ind(struct msgb *msg, struct lapdm_entity *le,
lctx.length = msg->l2h[2] >> 2;
lctx.more = !!(msg->l2h[2] & LAPDm_MORE);
msg->l3h = msg->l2h + 3;
- msgb_pull_l2h(msg);
+ msgb_pull_to_l3(msg);
}
/* store context for messages from lapd */
memcpy(&mctx.dl->mctx, &mctx, sizeof(mctx.dl->mctx));
@@ -644,7 +636,7 @@ static int l2_ph_data_ind(struct msgb *msg, struct lapdm_entity *le,
/* directly pass up to layer3 */
LOGP(DLLAPD, LOGL_INFO, "fmt=Bbis UI\n");
msg->l3h = msg->l2h;
- msgb_pull_l2h(msg);
+ msgb_pull_to_l3(msg);
rc = send_rslms_rll_l3(RSL_MT_UNIT_DATA_IND, &mctx, msg);
break;
default:
@@ -807,9 +799,8 @@ static int rslms_rx_rll_est_req(struct msgb *msg, struct lapdm_datalink *dl)
}
/* Remove RLL header from msgb and set length to L3-info */
- msgb_pull_l2h(msg);
- msg->len = length;
- msg->tail = msg->l3h + length;
+ msgb_pull_to_l3(msg);
+ msgb_trim(msg, length);
/* prepare prim */
osmo_prim_init(&dp.oph, 0, PRIM_DL_EST, PRIM_OP_REQUEST, msg);
@@ -861,9 +852,8 @@ static int rslms_rx_rll_udata_req(struct msgb *msg, struct lapdm_datalink *dl)
le->tx_power, le->ta);
/* Remove RLL header from msgb and set length to L3-info */
- msgb_pull_l2h(msg);
- msg->len = length;
- msg->tail = msg->l3h + length;
+ msgb_pull_to_l3(msg);
+ msgb_trim(msg, length);
/* Push L1 + LAPDm header on msgb */
msg->l2h = msgb_push(msg, 2 + !ui_bts);
@@ -900,9 +890,8 @@ static int rslms_rx_rll_data_req(struct msgb *msg, struct lapdm_datalink *dl)
length = TLVP_LEN(&tv, RSL_IE_L3_INFO);
/* Remove RLL header from msgb and set length to L3-info */
- msgb_pull_l2h(msg);
- msg->len = length;
- msg->tail = msg->l3h + length;
+ msgb_pull_to_l3(msg);
+ msgb_trim(msg, length);
/* prepare prim */
osmo_prim_init(&dp.oph, 0, PRIM_DL_DATA, PRIM_OP_REQUEST, msg);
@@ -957,9 +946,8 @@ static int rslms_rx_rll_res_req(struct msgb *msg, struct lapdm_datalink *dl)
length = TLVP_LEN(&tv, RSL_IE_L3_INFO);
/* Remove RLL header from msgb and set length to L3-info */
- msgb_pull_l2h(msg);
- msg->len = length;
- msg->tail = msg->l3h + length;
+ msgb_pull_to_l3(msg);
+ msgb_trim(msg, length);
/* prepare prim */
osmo_prim_init(&dp.oph, 0, (msg_type == RSL_MT_RES_REQ) ? PRIM_DL_RES
@@ -981,12 +969,11 @@ static int rslms_rx_rll_rel_req(struct msgb *msg, struct lapdm_datalink *dl)
mode = rllh->data[1] & 1;
/* Pull rllh */
- msgb_pull_l2h(msg);
+ msgb_pull_to_l3(msg);
/* 04.06 3.8.3: No information field is permitted with the DISC
* command. */
- msg->len = 0;
- msg->tail = msg->l3h = msg->data;
+ msgb_trim(msg, 0);
/* prepare prim */
osmo_prim_init(&dp.oph, 0, PRIM_DL_REL, PRIM_OP_REQUEST, msg);
@@ -1045,7 +1032,7 @@ static int l2_ph_chan_conf(struct msgb *msg, struct lapdm_entity *le, uint32_t f
gsm_fn2gsmtime(&tm, frame_nr);
- msgb_pull_l2h(msg);
+ msgb_pull_to_l3(msg);
msg->l2h = msgb_push(msg, sizeof(*ch) + sizeof(*ref));
ch = (struct abis_rsl_cchan_hdr *)msg->l2h;
rsl_init_cchan_hdr(ch, RSL_MT_CHAN_CONF);
diff --git a/src/msgb.c b/src/msgb.c
index 359a545..b2fe1d2 100644
--- a/src/msgb.c
+++ b/src/msgb.c
@@ -153,4 +153,53 @@ void msgb_set_talloc_ctx(void *ctx)
tall_msgb_ctx = ctx;
}
+/*! \brief Return a (static) buffer containing a hexdump of the msg
+ * \param[in] msg message buffer
+ * \returns a pointer to a static char array
+ */
+const char *msgb_hexdump(const struct msgb *msg)
+{
+ static char buf[4100];
+ int buf_offs = 0;
+ int nchars;
+ const unsigned char *start = msg->data;
+ const unsigned char *lxhs[4];
+ int i;
+
+ lxhs[0] = msg->l1h;
+ lxhs[1] = msg->l2h;
+ lxhs[2] = msg->l3h;
+ lxhs[3] = msg->l4h;
+
+ for (i = 0; i < ARRAY_SIZE(lxhs); i++) {
+ if (!lxhs[i])
+ continue;
+
+ if (lxhs[i] < msg->data)
+ goto out_of_range;
+ if (lxhs[i] > msg->tail)
+ goto out_of_range;
+ nchars = snprintf(buf + buf_offs, sizeof(buf) - buf_offs,
+ "%s[L%d]> ",
+ osmo_hexdump(start, lxhs[i] - start),
+ i+1);
+ if (nchars < 0 || nchars + buf_offs >= sizeof(buf))
+ return "ERROR";
+
+ buf_offs += nchars;
+ start = lxhs[i];
+ }
+ nchars = snprintf(buf + buf_offs, sizeof(buf) - buf_offs,
+ "%s", osmo_hexdump(start, msg->tail - start));
+ if (nchars < 0 || nchars + buf_offs >= sizeof(buf))
+ return "ERROR";
+
+ return buf;
+
+out_of_range:
+ nchars = snprintf(buf, sizeof(buf) - buf_offs,
+ "!!! L%d out of range", i+1);
+ return buf;
+}
+
/*! @} */
diff --git a/tests/lapd/lapd_test.c b/tests/lapd/lapd_test.c
index b4594de..6b5cfd3 100644
--- a/tests/lapd/lapd_test.c
+++ b/tests/lapd/lapd_test.c
@@ -36,6 +36,7 @@
}
static struct log_info info = {};
+static int dummy_l1_header_len = 0;
struct lapdm_polling_state {
struct lapdm_channel *bts;
@@ -94,6 +95,7 @@ static struct msgb *create_cm_serv_req(void)
msg = msgb_from_array(cm, sizeof(cm));
rsl_rll_push_l3(msg, RSL_MT_EST_REQ, 0, 0, 1);
+ msgb_push(msg, dummy_l1_header_len);
return msg;
}
@@ -106,6 +108,7 @@ static struct msgb *create_mm_id_req(void)
OSMO_ASSERT(msgb_l2len(msg) == 12);
msg->l3h = msg->l2h + 6;
OSMO_ASSERT(msgb_l3len(msg) == 6);
+ msgb_push(msg, dummy_l1_header_len);
return msg;
}
@@ -117,6 +120,7 @@ static struct msgb *create_empty_msg(void)
msg = msgb_from_array(NULL, 0);
OSMO_ASSERT(msgb_l3len(msg) == 0);
rsl_rll_push_l3(msg, RSL_MT_DATA_REQ, 0, 0, 1);
+ msgb_push(msg, dummy_l1_header_len);
return msg;
}
@@ -126,6 +130,7 @@ static struct msgb *create_dummy_data_req(void)
msg = msgb_from_array(dummy1, sizeof(dummy1));
rsl_rll_push_l3(msg, RSL_MT_DATA_REQ, 0, 0, 1);
+ msgb_push(msg, dummy_l1_header_len);
return msg;
}
@@ -135,6 +140,7 @@ static struct msgb *create_rel_req(void)
msg = msgb_from_array(rel_req, sizeof(rel_req));
msg->l2h = msg->data;
+ msgb_push(msg, dummy_l1_header_len);
msg->l3h = msg->l2h + sizeof(struct abis_rsl_rll_hdr);
return msg;
}
@@ -145,6 +151,7 @@ static struct msgb *create_est_req(const uint8_t *est_req, size_t est_req_size)
msg = msgb_from_array(est_req, est_req_size);
msg->l2h = msg->data;
+ msgb_push(msg, dummy_l1_header_len);
msg->l3h = msg->l2h + sizeof(struct abis_rsl_rll_hdr);
return msg;
}
@@ -240,6 +247,51 @@ static int ms_to_bts_l1_cb(struct osmo_prim_hdr *oph, void *_ctx)
return rc;
}
+static int dequeue_prim(struct lapdm_entity *le, struct osmo_phsap_prim *pp,
+ const char *queue_name)
+{
+ int rc;
+ int l2_header_len;
+ int l3_len = 0;
+
+ /* Take message from queue */
+ rc = lapdm_phsap_dequeue_prim(le, pp);
+
+ fprintf(stderr, "dequeue: got rc %d: %s\n", rc,
+ rc <= 0 ? strerror(-rc) : "-");
+
+ if (rc < 0)
+ return rc;
+
+ l2_header_len = msgb_l2len(pp->oph.msg);
+ if (msgb_l3(pp->oph.msg)) {
+ l3_len = msgb_l3len(pp->oph.msg);
+ l2_header_len -= l3_len;
+ } else
+ fprintf(stderr, "MSGB: L3 is undefined\n");
+
+ if (l2_header_len < 0 || l2_header_len > pp->oph.msg->data_len) {
+ fprintf(stderr,
+ "MSGB inconsistent: data = %p, l2 = %p, l3 = %p, tail = %p\n",
+ pp->oph.msg->data,
+ pp->oph.msg->l2h,
+ pp->oph.msg->l3h,
+ pp->oph.msg->tail);
+ l2_header_len = -1;
+ }
+
+ printf("Took message from %s queue: "
+ "L2 header size %d, L3 size %d, "
+ "SAP %#x, %d/%d, Link 0x%02x\n",
+ queue_name,
+ l2_header_len, l3_len,
+ pp->oph.sap, pp->oph.primitive, pp->oph.operation,
+ pp->u.data.link_id);
+ printf("Message: %s\n", msgb_hexdump(pp->oph.msg));
+
+ return rc;
+}
+
static int ms_to_bts_tx_cb(struct msgb *msg, struct lapdm_entity *le, void *_ctx)
{
struct lapdm_polling_state *state = _ctx;
@@ -315,7 +367,7 @@ static void test_lapdm_polling()
/* 2. Poll on the BTS for sending out a confirmation */
printf("\nConfirming\n");
OSMO_ASSERT(test_state.bts_read == 1);
- rc = lapdm_phsap_dequeue_prim(&bts_to_ms_channel.lapdm_dcch, &pp);
+ rc = dequeue_prim(&bts_to_ms_channel.lapdm_dcch, &pp, "DCCH");
CHECK_RC(rc);
OSMO_ASSERT(pp.oph.msg->data == pp.oph.msg->l2h);
send(pp.oph.msg, &ms_to_bts_channel);
@@ -325,14 +377,14 @@ static void test_lapdm_polling()
/* 3. Send some data to the MS */
printf("\nSending back to MS\n");
lapdm_rslms_recvmsg(create_mm_id_req(), &bts_to_ms_channel);
- rc = lapdm_phsap_dequeue_prim(&bts_to_ms_channel.lapdm_dcch, &pp);
+ rc = dequeue_prim(&bts_to_ms_channel.lapdm_dcch, &pp, "DCCH");
CHECK_RC(rc);
send(pp.oph.msg, &ms_to_bts_channel);
msgb_free(pp.oph.msg);
OSMO_ASSERT(test_state.ms_read == 2);
/* verify that there is nothing more to poll */
- rc = lapdm_phsap_dequeue_prim(&bts_to_ms_channel.lapdm_dcch, &pp);
+ rc = dequeue_prim(&bts_to_ms_channel.lapdm_dcch, &pp, "DCCH");
OSMO_ASSERT(rc < 0);
/* 3. And back to the BTS */
@@ -344,14 +396,16 @@ static void test_lapdm_polling()
/* 4. And back to the MS, but let's move data/l2h apart */
OSMO_ASSERT(test_state.bts_read == 2);
OSMO_ASSERT(test_state.ms_read == 2);
- rc = lapdm_phsap_dequeue_prim(&bts_to_ms_channel.lapdm_dcch, &pp);
+ rc = dequeue_prim(&bts_to_ms_channel.lapdm_dcch, &pp, "DCCH");
CHECK_RC(rc);
send(pp.oph.msg, &ms_to_bts_channel);
OSMO_ASSERT(test_state.ms_read == 2);
msgb_free(pp.oph.msg);
/* verify that there is nothing more to poll */
- rc = lapdm_phsap_dequeue_prim(&bts_to_ms_channel.lapdm_dcch, &pp);
+ rc = dequeue_prim(&bts_to_ms_channel.lapdm_dcch, &pp, "DCCH");
+ OSMO_ASSERT(rc < 0);
+ rc = dequeue_prim(&bts_to_ms_channel.lapdm_acch, &pp, "ACCH");
OSMO_ASSERT(rc < 0);
/* check sending an empty L3 message fails */
@@ -392,18 +446,18 @@ static void test_lapdm_contention_resolution()
/* Send SABM MS 1, we must get UA */
send_sabm(&bts_to_ms_channel, 0);
- rc = lapdm_phsap_dequeue_prim(&bts_to_ms_channel.lapdm_dcch, &pp);
+ rc = dequeue_prim(&bts_to_ms_channel.lapdm_dcch, &pp, "DCCH");
CHECK_RC(rc);
OSMO_ASSERT(memcmp(pp.oph.msg->l2h, ua, ARRAY_SIZE(ua)) == 0);
/* Send SABM MS 2, we must get nothing, due to collision */
send_sabm(&bts_to_ms_channel, 1);
- rc = lapdm_phsap_dequeue_prim(&bts_to_ms_channel.lapdm_dcch, &pp);
+ rc = dequeue_prim(&bts_to_ms_channel.lapdm_dcch, &pp, "DCCH");
OSMO_ASSERT(rc == -ENODEV);
/* Send SABM MS 1 again, we must get UA gain */
send_sabm(&bts_to_ms_channel, 0);
- rc = lapdm_phsap_dequeue_prim(&bts_to_ms_channel.lapdm_dcch, &pp);
+ rc = dequeue_prim(&bts_to_ms_channel.lapdm_dcch, &pp, "DCCH");
CHECK_RC(rc);
OSMO_ASSERT(memcmp(pp.oph.msg->l2h, ua, ARRAY_SIZE(ua)) == 0);
@@ -451,7 +505,6 @@ static void lapdm_establish(const uint8_t *est_req, size_t est_req_size)
struct lapdm_polling_state test_state;
struct osmo_phsap_prim pp;
struct msgb *msg;
- const char *queue_name;
/* Configure LAPDm on both sides */
struct lapdm_channel bts_to_ms_channel;
@@ -473,31 +526,17 @@ static void lapdm_establish(const uint8_t *est_req, size_t est_req_size)
OSMO_ASSERT(rc == 0);
/* Take message from queue */
- rc = lapdm_phsap_dequeue_prim(&bts_to_ms_channel.lapdm_dcch, &pp);
- if (rc >= 0)
- queue_name = "DCCH";
- else {
- rc = lapdm_phsap_dequeue_prim(&bts_to_ms_channel.lapdm_acch, &pp);
- if (rc >= 0)
- queue_name = "ACCH";
- }
+ rc = dequeue_prim(&bts_to_ms_channel.lapdm_dcch, &pp, "DCCH");
+ if (rc < 0)
+ rc = dequeue_prim(&bts_to_ms_channel.lapdm_acch, &pp, "ACCH");
- fprintf(stderr, "dequeue: got rc %d: %s\n", rc,
- rc <= 0 ? strerror(-rc) : "-");
CHECK_RC(rc);
- printf("Took message from %s queue: L2 header size %d, "
- "SAP %#x, %d/%d, Link 0x%02x\n",
- queue_name, msgb_l2len(pp.oph.msg) - msgb_l3len(pp.oph.msg),
- pp.oph.sap, pp.oph.primitive, pp.oph.operation,
- pp.u.data.link_id);
- printf("Message: %s\n", osmo_hexdump(pp.oph.msg->data, pp.oph.msg->len));
-
OSMO_ASSERT(pp.oph.msg->data == msgb_l2(pp.oph.msg));
- rc = lapdm_phsap_dequeue_prim(&bts_to_ms_channel.lapdm_dcch, &pp);
+ rc = dequeue_prim(&bts_to_ms_channel.lapdm_dcch, &pp, "DCCH");
OSMO_ASSERT(rc < 0);
- rc = lapdm_phsap_dequeue_prim(&bts_to_ms_channel.lapdm_acch, &pp);
+ rc = dequeue_prim(&bts_to_ms_channel.lapdm_acch, &pp, "ACCH");
OSMO_ASSERT(rc < 0);
/* clean up */
@@ -520,10 +559,15 @@ int main(int argc, char **argv)
{
osmo_init_logging(&info);
+ /* Prevent the test from segfaulting */
+ dummy_l1_header_len = 0;
test_lapdm_polling();
+
+ dummy_l1_header_len = 3;
test_lapdm_early_release();
test_lapdm_contention_resolution();
test_lapdm_establishment();
+
printf("Success.\n");
return 0;
diff --git a/tests/lapd/lapd_test.ok b/tests/lapd/lapd_test.ok
index e4b1359..9fb58e0 100644
--- a/tests/lapd/lapd_test.ok
+++ b/tests/lapd/lapd_test.ok
@@ -5,10 +5,14 @@ bts_to_ms_tx_cb: MS->BTS(us) message 25
BTS: Verifying CM request.
Confirming
+Took message from DCCH queue: L2 header size 3, L3 size 20, SAP 0x1000000, 0/0, Link 0x00
+Message: [L2]> 01 73 41 [L3]> 05 24 31 03 50 18 93 08 29 47 80 00 00 00 00 80 2b 2b 2b 2b
ms_to_bts_tx_cb: BTS->MS(us) message 9
MS: Verifying incoming primitive.
Sending back to MS
+Took message from DCCH queue: L2 header size 3, L3 size 20, SAP 0x1000000, 0/0, Link 0x00
+Message: [L2]> 03 00 0d [L3]> 05 04 0d 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b
ms_to_bts_tx_cb: BTS->MS(us) message 12
MS: Verifying incoming MM message: 3
ms_to_bts_l1_cb: MS(us) -> BTS prim message
@@ -17,15 +21,21 @@ Sending back to BTS
ms_to_bts_l1_cb: MS(us) -> BTS prim message
bts_to_ms_tx_cb: MS->BTS(us) message 14
BTS: Verifying dummy message.
+Took message from DCCH queue: L2 header size 23, L3 size 0, SAP 0x1000000, 0/0, Link 0x00
+Message: [L2]> 01 21 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b
I test RF channel release of an unestablished channel.
I test contention resultion by having two mobiles collide and first mobile repeating SABM.
bts_to_ms_tx_cb: MS->BTS(us) message 25
BTS: Verifying CM request.
+Took message from DCCH queue: L2 header size 3, L3 size 20, SAP 0x1000000, 0/0, Link 0x00
+Message: [L2]> 01 73 41 [L3]> 05 24 31 03 50 18 93 08 29 47 80 00 00 00 00 80 2b 2b 2b 2b
+Took message from DCCH queue: L2 header size 3, L3 size 20, SAP 0x1000000, 0/0, Link 0x00
+Message: [L2]> 01 73 41 [L3]> 05 24 31 03 50 18 93 08 29 47 80 00 00 00 00 80 2b 2b 2b 2b
I test RF channel establishment.
Testing SAPI3/SDCCH
-Took message from DCCH queue: L2 header size 3, SAP 0x1000000, 0/0, Link 0x03
-Message: 0f 3f 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b
+Took message from DCCH queue: L2 header size 3, L3 size 20, SAP 0x1000000, 0/0, Link 0x03
+Message: [L2]> 0f 3f 01 [L3]> 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b
Testing SAPI3/SACCH
-Took message from ACCH queue: L2 header size 5, SAP 0x1000000, 0/0, Link 0x43
-Message: 00 00 0f 3f 01 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b
+Took message from ACCH queue: L2 header size 5, L3 size 18, SAP 0x1000000, 0/0, Link 0x43
+Message: [L2]> 00 00 0f 3f 01 [L3]> 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b
Success.