This is merely a historical archive of years 2008-2021, before the migration to mailman3.
A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/OpenBSC@lists.osmocom.org/.
Holger Freyther zecke at selfish.orgOn 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 at 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