gbproxy/test: Save and check received messages

Currently the only way to check, whether the right message have been
generated is to look into the generated text output. This is
error-prone if there are many messages.

This patch adds a way to optionally store all received messages into
a FIFO. They can then be checked by calling expect_msg() which
removes the first message from the FIFO and returns a pointer to it
or NULL if there is none. The pointer is only valid until the next
call to this function.

A few convenience functions are added to check for common message
types:

  - expect_gmm_msg checks for certain GSM 04.08 messages in LLC/GMM
  - expect_llc_msg checks for arbitrary LLC messages in BSSGP/UD
  - expect_bssgp_msg checks for arbitrary BSSG messages

Each of their arguments can be set by MATCH_ANY to ignore it while
matching. On success, they return a pointer to a statically
allocated struct containing the pointer to the msg and the full parse
context.

Recording is enabled by setting the global variable received_messages
to a pointer to a struct llist_head. It can be disabled again by
setting it to NULL.

Sponsored-by: On-Waves ehf
This commit is contained in:
Jacob Erlbeck 2014-09-22 18:54:34 +02:00 committed by Holger Hans Peter Freyther
parent 7e31f847af
commit acfaff38db
1 changed files with 155 additions and 0 deletions

View File

@ -33,6 +33,8 @@
#include <openbsc/gb_proxy.h>
#include <openbsc/gprs_utils.h>
#include <openbsc/gprs_llc.h>
#include <openbsc/gprs_gb_parse.h>
#include <openbsc/gsm_04_08_gprs.h>
#include <openbsc/debug.h>
#define REMOTE_BSS_ADDR 0x01020304
@ -43,8 +45,12 @@
#define REMOTE_SGSN2_ADDR 0x15161718
#define SGSN2_NSEI 0x0102
#define MATCH_ANY (-1)
struct gbproxy_config gbcfg = {0};
struct llist_head *received_messages = NULL;
static int dump_global(FILE *stream, int indent)
{
unsigned int i;
@ -955,9 +961,158 @@ int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg)
"msg length %d (%s)\n",
bvci, len, __func__);
if (received_messages) {
struct msgb *msg_copy;
msg_copy = gprs_msgb_copy(msg, "received_messages");
llist_add_tail(&msg_copy->list, received_messages);
}
return real_gprs_ns_sendmsg(nsi, msg);
}
/* Get the next message from the receive FIFO
*
* \returns a pointer to the message which will be invalidated at the next call
* to expect_msg. Returns NULL, if there is no message left.
*/
static struct msgb *expect_msg(void)
{
static struct msgb *msg = NULL;
msgb_free(msg);
msg = NULL;
if (!received_messages)
return NULL;
if (llist_empty(received_messages))
return NULL;
msg = llist_entry(received_messages->next, struct msgb, list);
llist_del(&msg->list);
return msg;
}
struct expect_result {
struct msgb *msg;
struct gprs_gb_parse_context parse_ctx;
};
static struct expect_result *expect_bssgp_msg(
int match_nsei, int match_bvci, int match_pdu_type)
{
static struct expect_result result;
static const struct expect_result empty_result = {0,};
static struct msgb *msg;
uint16_t nsei;
int rc;
memcpy(&result, &empty_result, sizeof(result));
msg = expect_msg();
if (!msg)
return NULL;
nsei = msgb_nsei(msg);
if (match_nsei != MATCH_ANY && match_nsei != nsei) {
fprintf(stderr, "%s: NSEI mismatch (expected %u, got %u)\n",
__func__, match_nsei, nsei);
return NULL;
}
if (match_bvci != MATCH_ANY && match_bvci != msgb_bvci(msg)) {
fprintf(stderr, "%s: BVCI mismatch (expected %u, got %u)\n",
__func__, match_bvci, msgb_bvci(msg));
return NULL;
}
result.msg = msg;
result.parse_ctx.to_bss = nsei != SGSN_NSEI && nsei != SGSN2_NSEI;
result.parse_ctx.peer_nsei = nsei;
if (!msgb_bssgph(msg)) {
fprintf(stderr, "%s: Expected BSSGP\n", __func__);
return NULL;
}
rc = gprs_gb_parse_bssgp(msgb_bssgph(msg), msgb_bssgp_len(msg),
&result.parse_ctx);
if (!rc) {
fprintf(stderr, "%s: Failed to parse message\n", __func__);
return NULL;
}
if (match_pdu_type != MATCH_ANY &&
match_pdu_type != result.parse_ctx.pdu_type) {
fprintf(stderr, "%s: PDU type mismatch (expected %u, got %u)\n",
__func__, match_pdu_type, result.parse_ctx.pdu_type);
return NULL;
}
return &result;
}
static struct expect_result *expect_llc_msg(
int match_nsei, int match_bvci, int match_sapi, int match_type)
{
static struct expect_result *result;
result = expect_bssgp_msg(match_nsei, match_bvci, MATCH_ANY);
if (!result)
return NULL;
if (!result->parse_ctx.llc) {
fprintf(stderr, "%s: Expected LLC message\n", __func__);
return NULL;
}
if (match_sapi != MATCH_ANY &&
match_sapi != result->parse_ctx.llc_hdr_parsed.sapi) {
fprintf(stderr, "%s: LLC SAPI mismatch (expected %u, got %u)\n",
__func__, match_sapi, result->parse_ctx.llc_hdr_parsed.sapi);
return NULL;
}
if (match_type != MATCH_ANY &&
match_type != result->parse_ctx.llc_hdr_parsed.cmd) {
fprintf(stderr,
"%s: LLC command/type mismatch (expected %u, got %u)\n",
__func__, match_type, result->parse_ctx.llc_hdr_parsed.cmd);
return NULL;
}
return result;
}
static struct expect_result *expect_gmm_msg(int match_nsei, int match_bvci,
int match_type)
{
static struct expect_result *result;
result = expect_llc_msg(match_nsei, match_bvci, GPRS_SAPI_GMM, GPRS_LLC_UI);
if (!result)
return NULL;
if (!result->parse_ctx.g48_hdr) {
fprintf(stderr, "%s: Expected GSM 04.08 message\n", __func__);
return NULL;
}
if (match_type != MATCH_ANY &&
match_type != result->parse_ctx.g48_hdr->msg_type) {
fprintf(stderr,
"%s: GSM 04.08 message type mismatch (expected %u, got %u)\n",
__func__, match_type, result->parse_ctx.g48_hdr->msg_type);
return NULL;
}
return result;
}
static void dump_rate_ctr_group(FILE *stream, const char *prefix,
struct rate_ctr_group *ctrg)
{