On Thursday 02 July 2009 06:45:48 Harald Welte wrote:
Hi Holger,
On Mon, Jun 29, 2009 at 05:27:28PM +0200, Holger Freyther wrote:
did you have this in mind when mentioning that
the parsing of the data
derived informations could be driven by a struct?
yes, I had something like this in mind. It somehow reduces the readability
of the code to those not familiar with this decoding scheme, but well, it
reduces the number of lines quite significantly on the other side.
A revised patch. I have moved the struct with all known parsers to one place,
created an enum of known decoders... I think this an improvement over the
previous patch but we are not there yet.
Things that I think I should do:
- Maybe nuke the PARSE_FLAG and flag attribute? If we get a response that
contains an attribute that should not be there our tlvp_parse will have
already parsed it. Does it hurt to copy the value to the gsm_mncc? In one way
we would like to be strict, in another it can be nice to see what incorrect
messages we receive?
- Kill the enum with the PARSE_ flags, I can use the MNCC ones
directly..
comments are more than welcome
z.
From 47f155d62b41df0bcd94c610617d39f9eb678f57 Mon Sep 17 00:00:00 2001
From: Holger Hans Peter Freyther <zecke(a)selfish.org>
Date: Mon, 29 Jun 2009 17:21:37 +0200
Subject: [PATCH] Generic data derived informations parsing...
Parse everything that was found during the tlvp_parse and
assign it to members of the gsm_mncc. This would even parse
elements that are not present/part of the specification.
---
openbsc/src/msc_mncc.c | 304
++++++++++++++----------------------------------
1 files changed, 85 insertions(+), 219 deletions(-)
diff --git a/openbsc/src/msc_mncc.c b/openbsc/src/msc_mncc.c
index 90354c0..3dcb6a0 100644
--- a/openbsc/src/msc_mncc.c
+++ b/openbsc/src/msc_mncc.c
@@ -587,6 +587,67 @@ static int encode_more(struct msgb *msg)
return 0;
}
+#define DECLARE_DECODER3(IE_NAME, M_NAME, name) \
+ [PARSE_##M_NAME] = \
+ { .information_element = GSM48_IE_##IE_NAME, \
+ .mncc_field = MNCC_F_##M_NAME, \
+ .offset = offsetof(struct gsm_mncc, name), \
+ .decoder = (dd_decoder)decode_##name, \
+ }
+
+#define DECLARE_DECODER(NAME, name) \
+ DECLARE_DECODER3(NAME, NAME, name)
+
+typedef int (*dd_decoder)(void* data, const u_int8_t *lv);
+
+struct dd_parser {
+ int information_element;
+ int mncc_field;
+ int offset;
+ dd_decoder decoder;
+};
+
+enum {
+ PARSE_CAUSE,
+ PARSE_FACILITY,
+ PARSE_USERUSER,
+ PARSE_SSVERSION,
+ PARSE_KEYPAD,
+ PARSE_BEARER_CAP,
+ PARSE_CALLED,
+ PARSE_CCCAP,
+ PARSE_PROGRESS,
+ PARSE_LAST_ITEM,
+};
+
+#define PARSE_FLAG(flag) (1<<PARSE_##flag)
+
+static const struct dd_parser dd_parsers [PARSE_LAST_ITEM] = {
+ DECLARE_DECODER(CAUSE, cause),
+ DECLARE_DECODER(FACILITY, facility),
+ DECLARE_DECODER3(USER_USER, USERUSER, useruser),
+ DECLARE_DECODER3(SS_VERS, SSVERSION, ssversion),
+ DECLARE_DECODER3(KPD_FACILITY, KEYPAD, keypad),
+ DECLARE_DECODER(BEARER_CAP, bearer_cap),
+ DECLARE_DECODER3(CALLED_BCD, CALLED, called),
+ DECLARE_DECODER3(CC_CAP, CCCAP, cccap),
+ DECLARE_DECODER3(PROGR_IND, PROGRESS, progress),
+};
+
+static void parse_data_derived_information(struct tlv_parsed *tp, struct
gsm_mncc *rel, int flags)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dd_parsers); ++i) {
+ if (flags & (1<<i) == (1<<i) && TLVP_PRESENT(tp,
dd_parsers[i].information_element)) {
+ rel->fields |= dd_parsers[i].mncc_field;
+ dd_parsers[i].decoder(rel + dd_parsers[i].offset,
+ TLVP_VAL(tp, dd_parsers[i].information_element)-1);
+ }
+ }
+}
+
+
/* map two ipaccess RTP streams onto each other */
static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan)
{
@@ -1013,48 +1074,16 @@ static int msc_cc_rx_setup(struct gsm_trans *trans,
struct msgb *msg)
strncpy(setup.imsi, trans->subscr->imsi,
sizeof(setup.imsi)-1);
}
- /* bearer capability */
- if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
- setup.fields |= MNCC_F_BEARER_CAP;
- decode_bearer_cap(&setup.bearer_cap,
- TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
- }
- /* facility */
- if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
- setup.fields |= MNCC_F_FACILITY;
- decode_facility(&setup.facility,
- TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
- }
- /* called party bcd number */
- if (TLVP_PRESENT(&tp, GSM48_IE_CALLED_BCD)) {
- setup.fields |= MNCC_F_CALLED;
- decode_called(&setup.called,
- TLVP_VAL(&tp, GSM48_IE_CALLED_BCD)-1);
- }
- /* user-user */
- if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
- setup.fields |= MNCC_F_USERUSER;
- decode_useruser(&setup.useruser,
- TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
- }
- /* ss-version */
- if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
- setup.fields |= MNCC_F_SSVERSION;
- decode_ssversion(&setup.ssversion,
- TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
- }
+
+ parse_data_derived_information(&tp, &setup, PARSE_FLAG(BEARER_CAP) |
PARSE_FLAG(FACILITY) |
+ PARSE_FLAG(CALLED) | PARSE_FLAG(USERUSER) | PARSE_FLAG(SSVERSION) );
+
/* CLIR suppression */
if (TLVP_PRESENT(&tp, GSM48_IE_CLIR_SUPP))
setup.clir.sup = 1;
/* CLIR invocation */
if (TLVP_PRESENT(&tp, GSM48_IE_CLIR_INVOC))
setup.clir.inv = 1;
- /* cc cap */
- if (TLVP_PRESENT(&tp, GSM48_IE_CC_CAP)) {
- setup.fields |= MNCC_F_CCCAP;
- decode_cccap(&setup.cccap,
- TLVP_VAL(&tp, GSM48_IE_CC_CAP)-1);
- }
if (is_ipaccess_bts(msg->trx->bts))
rsl_ipacc_bind(msg->lchan);
@@ -1171,24 +1200,9 @@ static int msc_cc_rx_call_conf(struct gsm_trans *trans,
struct msgb *msg)
if (TLVP_PRESENT(&tp, GSM48_IE_REPEAT_SEQ))
call_conf.repeat = 2;
#endif
- /* bearer capability */
- if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
- call_conf.fields |= MNCC_F_BEARER_CAP;
- decode_bearer_cap(&call_conf.bearer_cap,
- TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
- }
- /* cause */
- if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
- call_conf.fields |= MNCC_F_CAUSE;
- decode_cause(&call_conf.cause,
- TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
- }
- /* cc cap */
- if (TLVP_PRESENT(&tp, GSM48_IE_CC_CAP)) {
- call_conf.fields |= MNCC_F_CCCAP;
- decode_cccap(&call_conf.cccap,
- TLVP_VAL(&tp, GSM48_IE_CC_CAP)-1);
- }
+
+ parse_data_derived_information(&tp, &call_conf, PARSE_FLAG(BEARER_CAP) |
PARSE_FLAG(CAUSE) |
+ PARSE_FLAG(CCCAP));
new_cc_state(trans, GSM_CSTATE_MO_TERM_CALL_CONF);
@@ -1233,25 +1247,8 @@ static int msc_cc_rx_alerting(struct gsm_trans *trans,
struct msgb *msg)
memset(&alerting, 0, sizeof(struct gsm_mncc));
alerting.callref = trans->callref;
tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
- /* facility */
- if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
- alerting.fields |= MNCC_F_FACILITY;
- decode_facility(&alerting.facility,
- TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
- }
-
- /* progress */
- if (TLVP_PRESENT(&tp, GSM48_IE_PROGR_IND)) {
- alerting.fields |= MNCC_F_PROGRESS;
- decode_progress(&alerting.progress,
- TLVP_VAL(&tp, GSM48_IE_PROGR_IND)-1);
- }
- /* ss-version */
- if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
- alerting.fields |= MNCC_F_SSVERSION;
- decode_ssversion(&alerting.ssversion,
- TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
- }
+ parse_data_derived_information(&tp, &alerting, PARSE_FLAG(FACILITY) |
PARSE_FLAG(PROGRESS) |
+ PARSE_FLAG(SSVERSION));
new_cc_state(trans, GSM_CSTATE_CALL_RECEIVED);
@@ -1353,25 +1350,9 @@ static int msc_cc_rx_connect(struct gsm_trans *trans,
struct msgb *msg)
strncpy(connect.imsi, trans->subscr->imsi,
sizeof(connect.imsi)-1);
}
- /* facility */
- if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
- connect.fields |= MNCC_F_FACILITY;
- decode_facility(&connect.facility,
- TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
- }
- /* user-user */
- if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
- connect.fields |= MNCC_F_USERUSER;
- decode_useruser(&connect.useruser,
- TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
- }
- /* ss-version */
- if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
- connect.fields |= MNCC_F_SSVERSION;
- decode_ssversion(&connect.ssversion,
- TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
- }
+ parse_data_derived_information(&tp, &connect, PARSE_FLAG(FACILITY) |
PARSE_FLAG(USERUSER) |
+ PARSE_FLAG(SSVERSION));
new_cc_state(trans, GSM_CSTATE_CONNECT_REQUEST);
return mncc_recvmsg(trans->network, trans, MNCC_SETUP_CNF, &connect);
@@ -1420,31 +1401,8 @@ static int msc_cc_rx_disconnect(struct gsm_trans
*trans, struct msgb *msg)
memset(&disc, 0, sizeof(struct gsm_mncc));
disc.callref = trans->callref;
tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_CAUSE, 0);
- /* cause */
- if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
- disc.fields |= MNCC_F_CAUSE;
- decode_cause(&disc.cause,
- TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
- }
- /* facility */
- if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
- disc.fields |= MNCC_F_FACILITY;
- decode_facility(&disc.facility,
- TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
- }
- /* user-user */
- if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
- disc.fields |= MNCC_F_USERUSER;
- decode_useruser(&disc.useruser,
- TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
- }
- /* ss-version */
- if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
- disc.fields |= MNCC_F_SSVERSION;
- decode_ssversion(&disc.ssversion,
- TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
- }
-
+ parse_data_derived_information(&tp, &disc, PARSE_FLAG(CAUSE) |
PARSE_FLAG(FACILITY) |
+ PARSE_FLAG(USERUSER) | PARSE_FLAG(SSVERSION));
return mncc_recvmsg(trans->network, trans, MNCC_DISC_IND, &disc);
}
@@ -1509,30 +1467,8 @@ static int msc_cc_rx_release(struct gsm_trans *trans,
struct msgb *msg)
memset(&rel, 0, sizeof(struct gsm_mncc));
rel.callref = trans->callref;
tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
- /* cause */
- if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
- rel.fields |= MNCC_F_CAUSE;
- decode_cause(&rel.cause,
- TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
- }
- /* facility */
- if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
- rel.fields |= MNCC_F_FACILITY;
- decode_facility(&rel.facility,
- TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
- }
- /* user-user */
- if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
- rel.fields |= MNCC_F_USERUSER;
- decode_useruser(&rel.useruser,
- TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
- }
- /* ss-version */
- if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
- rel.fields |= MNCC_F_SSVERSION;
- decode_ssversion(&rel.ssversion,
- TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
- }
+ parse_data_derived_information(&tp, &rel, PARSE_FLAG(CAUSE) |
PARSE_FLAG(FACILITY) |
+ PARSE_FLAG(USERUSER) | PARSE_FLAG(SSVERSION));
if (trans->state == GSM_CSTATE_RELEASE_REQ) {
/* release collision 5.4.5 */
@@ -1598,30 +1534,8 @@ static int msc_cc_rx_release_compl(struct gsm_trans
*trans, struct msgb *msg)
memset(&rel, 0, sizeof(struct gsm_mncc));
rel.callref = trans->callref;
tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
- /* cause */
- if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
- rel.fields |= MNCC_F_CAUSE;
- decode_cause(&rel.cause,
- TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
- }
- /* facility */
- if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
- rel.fields |= MNCC_F_FACILITY;
- decode_facility(&rel.facility,
- TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
- }
- /* user-user */
- if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
- rel.fields |= MNCC_F_USERUSER;
- decode_useruser(&rel.useruser,
- TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
- }
- /* ss-version */
- if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
- rel.fields |= MNCC_F_SSVERSION;
- decode_ssversion(&rel.ssversion,
- TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
- }
+ parse_data_derived_information(&tp, &rel, PARSE_FLAG(CAUSE) |
PARSE_FLAG(FACILITY) |
+ PARSE_FLAG(USERUSER) | PARSE_FLAG(SSVERSION));
if (trans->callref) {
switch (trans->state) {
@@ -1684,19 +1598,7 @@ static int msc_cc_rx_facility(struct gsm_trans *trans,
struct msgb *msg)
memset(&fac, 0, sizeof(struct gsm_mncc));
fac.callref = trans->callref;
tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_FACILITY,
0);
- /* facility */
- if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
- fac.fields |= MNCC_F_FACILITY;
- decode_facility(&fac.facility,
- TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
- }
- /* ss-version */
- if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) {
- fac.fields |= MNCC_F_SSVERSION;
- decode_ssversion(&fac.ssversion,
- TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1);
- }
-
+ parse_data_derived_information(&tp, &fac, PARSE_FLAG(FACILITY) |
PARSE_FLAG(SSVERSION));
return mncc_recvmsg(trans->network, trans, MNCC_FACILITY_IND, &fac);
}
@@ -1806,13 +1708,7 @@ static int msc_cc_rx_start_dtmf(struct gsm_trans
*trans, struct msgb *msg)
memset(&dtmf, 0, sizeof(struct gsm_mncc));
dtmf.callref = trans->callref;
tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
- /* keypad facility */
- if (TLVP_PRESENT(&tp, GSM48_IE_KPD_FACILITY)) {
- dtmf.fields |= MNCC_F_KEYPAD;
- decode_keypad(&dtmf.keypad,
- TLVP_VAL(&tp, GSM48_IE_KPD_FACILITY)-1);
- }
-
+ parse_data_derived_information(&tp, &dtmf, PARSE_FLAG(KEYPAD));
return mncc_recvmsg(trans->network, trans, MNCC_START_DTMF_IND, &dtmf);
}
@@ -1884,15 +1780,8 @@ static int msc_cc_rx_modify(struct gsm_trans *trans,
struct msgb *msg)
memset(&modify, 0, sizeof(struct gsm_mncc));
modify.callref = trans->callref;
tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP,
0);
- /* bearer capability */
- if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
- modify.fields |= MNCC_F_BEARER_CAP;
- decode_bearer_cap(&modify.bearer_cap,
- TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
- }
-
+ parse_data_derived_information(&tp, &modify, PARSE_FLAG(BEARER_CAP));
new_cc_state(trans, GSM_CSTATE_MO_ORIG_MODIFY);
-
return mncc_recvmsg(trans->network, trans, MNCC_MODIFY_IND, &modify);
}
@@ -1928,15 +1817,8 @@ static int msc_cc_rx_modify_complete(struct gsm_trans
*trans, struct msgb *msg)
memset(&modify, 0, sizeof(struct gsm_mncc));
modify.callref = trans->callref;
tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP,
0);
- /* bearer capability */
- if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
- modify.fields |= MNCC_F_BEARER_CAP;
- decode_bearer_cap(&modify.bearer_cap,
- TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
- }
-
+ parse_data_derived_information(&tp, &modify, PARSE_FLAG(BEARER_CAP));
new_cc_state(trans, GSM_CSTATE_ACTIVE);
-
return mncc_recvmsg(trans->network, trans, MNCC_MODIFY_CNF, &modify);
}
@@ -1970,19 +1852,7 @@ static int msc_cc_rx_modify_reject(struct gsm_trans
*trans, struct msgb *msg)
memset(&modify, 0, sizeof(struct gsm_mncc));
modify.callref = trans->callref;
tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP,
GSM48_IE_CAUSE);
- /* bearer capability */
- if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
- modify.fields |= GSM48_IE_BEARER_CAP;
- decode_bearer_cap(&modify.bearer_cap,
- TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
- }
- /* cause */
- if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
- modify.fields |= MNCC_F_CAUSE;
- decode_cause(&modify.cause,
- TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
- }
-
+ parse_data_derived_information(&tp, &modify, PARSE_FLAG(BEARER_CAP) |
PARSE_FLAG(CAUSE));
new_cc_state(trans, GSM_CSTATE_ACTIVE);
return mncc_recvmsg(trans->network, trans, MNCC_MODIFY_REJ, &modify);
@@ -2070,12 +1940,8 @@ static int msc_cc_rx_userinfo(struct gsm_trans *trans,
struct msgb *msg)
memset(&user, 0, sizeof(struct gsm_mncc));
user.callref = trans->callref;
tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_USER_USER,
0);
- /* user-user */
- if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
- user.fields |= MNCC_F_USERUSER;
- decode_useruser(&user.useruser,
- TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
- }
+ parse_data_derived_information(&tp, &user, PARSE_FLAG(USERUSER));
+
/* more data */
if (TLVP_PRESENT(&tp, GSM48_IE_MORE_DATA))
user.more = 1;
--
1.6.3.3