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