diff options
author | Holger Hans Peter Freyther <holger@moiji-mobile.com> | 2014-03-10 15:00:20 +0100 |
---|---|---|
committer | Holger Hans Peter Freyther <holger@moiji-mobile.com> | 2014-03-10 15:00:20 +0100 |
commit | 4b3de6840ef08b0630bafb9d4d19fc2d10aacdd1 (patch) | |
tree | 3d9ffc8100b1bdb4350bd1bea206f0eeae133f4c | |
parent | 10f0bdecad8d711ccc5fcc04bb0be0adf11a7902 (diff) | |
parent | 8dac4159adb7377f016317808e3a6b0c79df7fa1 (diff) |
Merge branch 'jerlbeck/fixes/ladp-sms'
-rw-r--r-- | include/osmocom/core/msgb.h | 16 | ||||
-rw-r--r-- | src/gsm/lapdm.c | 41 | ||||
-rw-r--r-- | src/msgb.c | 49 | ||||
-rw-r--r-- | tests/lapd/lapd_test.c | 100 | ||||
-rw-r--r-- | tests/lapd/lapd_test.ok | 18 |
5 files changed, 165 insertions, 59 deletions
diff --git a/include/osmocom/core/msgb.h b/include/osmocom/core/msgb.h index fe2733b7..33e8081f 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 19f78a1a..41f4be71 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); @@ -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 b4594dea..6b5cfd36 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 e4b13597..9fb58e0c 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. |