Harald Welte | 474fd7d | 2017-12-29 16:01:39 +0100 | [diff] [blame] | 1 | #include "mncc.h" |
| 2 | #include "MNCC_Types.hh" |
| 3 | |
| 4 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) |
| 5 | |
| 6 | namespace MNCC__Types { |
| 7 | |
| 8 | static void enc_bcap(struct gsm_mncc_bearer_cap *out, const MNCC__bearer__cap& in) |
| 9 | { |
| 10 | out->transfer = in.transfer(); |
| 11 | out->mode = in.mode(); |
| 12 | out->coding = in.coding(); |
| 13 | out->radio = in.radio(); |
| 14 | out->speech_ctm = in.speech__ctm(); |
| 15 | |
| 16 | for (int i = 0; i < in.speech__ver().lengthof(); i++) |
| 17 | out->speech_ver[i] = in.speech__ver()[i]; |
| 18 | |
| 19 | if (in.data().is_value()) { |
| 20 | MNCC__bearer__cap__data data = in.data(); |
| 21 | out->data.rate_adaption = (gsm48_bcap_ra) (int) data.rate__adaptation(); |
| 22 | out->data.sig_access = (gsm48_bcap_sig_access) (int) data.sig__access(); |
| 23 | out->data.async = data.async(); |
| 24 | out->data.nr_stop_bits = data.nr__stop__bits(); |
| 25 | out->data.nr_data_bits = data.nr__data__bits(); |
| 26 | out->data.user_rate = (gsm48_bcap_user_rate) (int) data.user__rate(); |
| 27 | out->data.parity = (gsm48_bcap_parity) (int) data.parity(); |
| 28 | out->data.interm_rate = (gsm48_bcap_interm_rate) (int) data.interm__rate(); |
| 29 | out->data.transp = (gsm48_bcap_transp) (int) data.transp(); |
| 30 | out->data.modem_type = (gsm48_bcap_modem_type) (int) data.modem__type(); |
| 31 | } |
| 32 | |
| 33 | } |
| 34 | |
| 35 | static MNCC__bearer__cap dec_bcap(const struct gsm_mncc_bearer_cap *in) |
| 36 | { |
| 37 | MNCC__bearer__cap__data data; |
| 38 | MNCC__speech__vers vers; |
| 39 | data = MNCC__bearer__cap__data((GSM48__bcap__ra) in->data.rate_adaption, |
| 40 | (GSM48__bcap__sig__access) in->data.sig_access, |
| 41 | in->data.async, |
| 42 | in->data.nr_stop_bits, |
| 43 | in->data.nr_data_bits, |
| 44 | (GSM48__bcap__user__rate) in->data.user_rate, |
| 45 | (GSM48__bcap__parity) in->data.parity, |
| 46 | (GSM48__bcap__interm__rate) in->data.interm_rate, |
| 47 | (GSM48__bcap__transp) in->data.transp, |
| 48 | (GSM48__bcap__modem__type) in->data.modem_type); |
| 49 | |
| 50 | for (unsigned int i = 0; i < ARRAY_SIZE(in->speech_ver); i++) |
| 51 | vers[0] = in->speech_ver[0]; |
| 52 | |
| 53 | return MNCC__bearer__cap(in->transfer, in->mode, in->coding, in->radio, in->speech_ctm, |
| 54 | vers, data); |
| 55 | } |
| 56 | |
| 57 | |
| 58 | static void enc_number(struct gsm_mncc_number *num, const MNCC__number& in) |
| 59 | { |
| 60 | num->type = in.number__type(); |
| 61 | num->plan = in.plan(); |
| 62 | num->present = in.presence(); |
| 63 | num->screen = in.screen(); |
| 64 | strncpy(num->number, in.number(), sizeof(num->number)); |
| 65 | } |
| 66 | |
| 67 | static MNCC__number dec_number(const struct gsm_mncc_number *num) |
| 68 | { |
| 69 | return MNCC__number(num->type, num->plan,num->present, num->screen, num->number); |
| 70 | } |
| 71 | |
| 72 | OCTETSTRING enc__MNCC__PDU(const MNCC__PDU& in) |
| 73 | { |
| 74 | const MNCC__PDU__Signal& in_sig = in.u().signal(); |
| 75 | struct gsm_mncc mncc; |
| 76 | OCTETSTRING ret_val; |
| 77 | |
| 78 | memset(&mncc, 0, sizeof(mncc)); |
| 79 | mncc.msg_type = in.msg__type(); |
| 80 | |
| 81 | if (in_sig.is_value()) { |
| 82 | mncc.callref = in_sig.callref(); |
| 83 | if (in_sig.bearer__cap().is_value()) { |
| 84 | enc_bcap(&mncc.bearer_cap, in_sig.bearer__cap()); |
| 85 | mncc.fields |= MNCC_F_BEARER_CAP; |
| 86 | } |
| 87 | if (in_sig.called().is_value()) { |
| 88 | enc_number(&mncc.called, in_sig.called()); |
| 89 | mncc.fields |= MNCC_F_CALLED; |
| 90 | } |
| 91 | if (in_sig.calling().is_value()) { |
| 92 | enc_number(&mncc.calling, in_sig.calling()); |
| 93 | mncc.fields |= MNCC_F_CALLING; |
| 94 | } |
| 95 | if (in_sig.redirecting().is_value()) { |
| 96 | enc_number(&mncc.redirecting, in_sig.redirecting()); |
| 97 | mncc.fields |= MNCC_F_REDIRECTING; |
| 98 | } |
| 99 | if (in_sig.connected().is_value()) { |
| 100 | enc_number(&mncc.connected, in_sig.connected()); |
| 101 | mncc.fields |= MNCC_F_CONNECTED; |
| 102 | } |
| 103 | if (in_sig.cause().is_value()) { |
| 104 | const MNCC__cause &cause = in_sig.cause(); |
| 105 | TTCN_Buffer ttcn_buffer(cause.diag()); |
| 106 | mncc.cause.location = cause.location(); |
| 107 | mncc.cause.coding = cause.coding(); |
| 108 | mncc.cause.rec = cause.rec(); |
| 109 | mncc.cause.rec_val = cause.rec__val(); |
| 110 | mncc.cause.value = cause.val(); |
| 111 | mncc.cause.diag_len = ttcn_buffer.get_len(); |
| 112 | if (mncc.cause.diag_len > (int) sizeof(mncc.cause.diag)) { |
| 113 | TTCN_error("MNCC diagnostics length %u too long", mncc.cause.diag_len); |
| 114 | mncc.cause.diag_len = sizeof(mncc.cause.diag); |
| 115 | } |
| 116 | memcpy(mncc.cause.diag, ttcn_buffer.get_data(), ttcn_buffer.get_len()); |
| 117 | mncc.fields |= MNCC_F_CAUSE; |
| 118 | } |
| 119 | if (in_sig.progress().is_value()) { |
| 120 | const MNCC__progress &progress = in_sig.progress(); |
| 121 | mncc.progress.coding = progress.coding(); |
| 122 | mncc.progress.location = progress.location(); |
| 123 | mncc.progress.descr = progress.descr(); |
| 124 | mncc.fields |= MNCC_F_PROGRESS; |
| 125 | } |
| 126 | if (in_sig.useruser().is_value()) { |
| 127 | const MNCC__useruser &useruser = in_sig.useruser(); |
| 128 | mncc.useruser.proto = useruser.proto(); |
| 129 | strncpy(mncc.useruser.info, useruser.info(), sizeof(mncc.useruser.info)); |
| 130 | mncc.fields |= MNCC_F_USERUSER; |
| 131 | } |
| 132 | if (in_sig.facility().is_value()) { |
| 133 | const CHARSTRING &fac = in_sig.facility(); |
| 134 | strncpy(mncc.facility.info, fac, sizeof(mncc.facility.info)); |
| 135 | mncc.facility.len = strlen(mncc.facility.info); |
| 136 | mncc.fields |= MNCC_F_FACILITY; |
| 137 | } |
| 138 | if (in_sig.cccap().is_value()) { |
| 139 | const MNCC__cccap &cccap = in_sig.cccap(); |
| 140 | mncc.cccap.dtmf = cccap.dtmf(); |
| 141 | mncc.cccap.pcp = cccap.pcp(); |
| 142 | mncc.fields |= MNCC_F_CCCAP; |
| 143 | } |
| 144 | if (in_sig.ssversion().is_value()) { |
| 145 | const CHARSTRING &ssv = in_sig.ssversion(); |
| 146 | strncpy(mncc.ssversion.info, ssv, sizeof(mncc.ssversion.info)); |
| 147 | mncc.ssversion.len = strlen(mncc.ssversion.info); |
| 148 | mncc.fields |= MNCC_F_SSVERSION; |
| 149 | } |
| 150 | mncc.clir.sup = in_sig.clir__sup(); |
| 151 | mncc.clir.inv = in_sig.clir__inv(); |
| 152 | if (in_sig.signal().is_value()) { |
| 153 | const INTEGER &sig = in_sig.signal(); |
| 154 | mncc.signal = sig; |
| 155 | mncc.fields |= MNCC_F_SIGNAL; |
| 156 | } |
| 157 | if (in_sig.keypad().is_value()) { |
| 158 | const INTEGER &kpd = in_sig.keypad(); |
| 159 | mncc.signal = kpd; |
| 160 | mncc.fields |= MNCC_F_KEYPAD; |
| 161 | } |
| 162 | mncc.more = in_sig.more(); |
| 163 | mncc.notify = in_sig.notify(); |
| 164 | if (in_sig.emergency().is_value()) { |
| 165 | const INTEGER &emerg = in_sig.emergency(); |
| 166 | mncc.emergency = emerg; |
| 167 | mncc.fields |= MNCC_F_EMERGENCY; |
| 168 | } |
| 169 | strncpy(mncc.imsi, in_sig.imsi(), sizeof(mncc.imsi)); |
| 170 | mncc.lchan_type = in_sig.lchan__type(); |
| 171 | mncc.lchan_mode = in_sig.lchan__mode(); |
| 172 | ret_val = OCTETSTRING(sizeof(mncc), (uint8_t *)&mncc); |
| 173 | } else if (in.u().data().is_value()) { |
| 174 | struct gsm_data_frame data; |
| 175 | memset(&data, 0, sizeof(data)); |
| 176 | data.msg_type = in.msg__type(); |
| 177 | ret_val = OCTETSTRING(sizeof(data), (uint8_t *)&data); |
| 178 | ret_val = ret_val & in.u().data().data(); |
| 179 | } else if (in.u().rtp().is_value()) { |
| 180 | struct gsm_mncc_rtp rtp; |
| 181 | memset(&rtp, 0, sizeof(rtp)); |
| 182 | rtp.msg_type = in.msg__type(); |
| 183 | rtp.callref = in.u().rtp().callref(); |
| 184 | rtp.ip = in.u().rtp().ip(); |
| 185 | rtp.port = in.u().rtp().rtp__port(); |
| 186 | rtp.payload_type = in.u().rtp().payload__type(); |
| 187 | rtp.payload_msg_type = in.u().rtp().payload__msg__type(); |
| 188 | ret_val = OCTETSTRING(sizeof(rtp), (uint8_t *) &rtp); |
| 189 | } else if (in.u().hello().is_value()) { |
| 190 | struct gsm_mncc_hello hello; |
| 191 | memset(&hello, 0, sizeof(hello)); |
| 192 | hello.msg_type = in.msg__type(); |
| 193 | hello.version = in.u().hello().version(); |
| 194 | hello.mncc_size = in.u().hello().mncc__size(); |
| 195 | hello.data_frame_size = in.u().hello().data__frame__size(); |
| 196 | hello.called_offset = in.u().hello().called__offset(); |
| 197 | hello.signal_offset = in.u().hello().signal__offset(); |
| 198 | hello.emergency_offset = in.u().hello().emergency__offset(); |
| 199 | hello.lchan_type_offset = in.u().hello().lchan__type__offset(); |
| 200 | ret_val = OCTETSTRING(sizeof(hello), (uint8_t *) &hello); |
| 201 | } |
| 202 | |
| 203 | return ret_val; |
| 204 | } |
| 205 | |
| 206 | MNCC__PDU dec__MNCC__PDU(const OCTETSTRING& in) |
| 207 | { |
| 208 | TTCN_Buffer ttcn_buffer(in); |
| 209 | const struct gsm_mncc *in_mncc; |
| 210 | MNCC__PDU__Signal sign; |
| 211 | const struct gsm_mncc_hello *in_hello; |
| 212 | MNCC__PDU__Hello hello; |
| 213 | const struct gsm_data_frame *in_data; |
| 214 | MNCC__PDU__Data data; |
| 215 | const struct gsm_mncc_rtp *in_rtp; |
| 216 | MNCC__PDU__Rtp rtp; |
| 217 | MNCC__MsgUnion u; |
| 218 | |
| 219 | in_mncc = (struct gsm_mncc *) ttcn_buffer.get_read_data(); |
| 220 | |
| 221 | switch (in_mncc->msg_type) { |
| 222 | case MNCC_SOCKET_HELLO: |
| 223 | in_hello = (const struct gsm_mncc_hello *) in_mncc; |
| 224 | hello = MNCC__PDU__Hello(in_hello->version, |
| 225 | in_hello->mncc_size, |
| 226 | in_hello->data_frame_size, |
| 227 | in_hello->called_offset, |
| 228 | in_hello->signal_offset, |
| 229 | in_hello->emergency_offset, |
| 230 | in_hello->lchan_type_offset); |
| 231 | u.hello() = hello; |
| 232 | break; |
| 233 | case GSM_TCHF_FRAME: |
| 234 | case GSM_TCHF_FRAME_EFR: |
| 235 | case GSM_TCHH_FRAME: |
| 236 | case GSM_TCH_FRAME_AMR: |
| 237 | case GSM_BAD_FRAME: |
| 238 | in_data = (const struct gsm_data_frame *) in_mncc; |
| 239 | u.data() = MNCC__PDU__Data(in_data->callref, |
| 240 | substr(in, offsetof(struct gsm_data_frame, data), |
| 241 | in.lengthof() - offsetof(struct gsm_data_frame, data))); |
| 242 | break; |
| 243 | case MNCC_RTP_CREATE: |
| 244 | case MNCC_RTP_CONNECT: |
| 245 | case MNCC_RTP_FREE: |
| 246 | in_rtp = (const struct gsm_mncc_rtp *) in_mncc; |
| 247 | rtp = MNCC__PDU__Rtp(in_rtp->callref, in_rtp->ip, in_rtp->port, in_rtp->payload_type, |
| 248 | in_rtp->payload_msg_type); |
| 249 | u.rtp() = rtp; |
| 250 | break; |
| 251 | default: |
| 252 | sign.callref() = in_mncc->callref; |
| 253 | if (in_mncc->fields & MNCC_F_BEARER_CAP) { |
| 254 | sign.bearer__cap() = dec_bcap(&in_mncc->bearer_cap); |
| 255 | } |
| 256 | if (in_mncc->fields & MNCC_F_CALLED) |
| 257 | sign.called() = dec_number(&in_mncc->called); |
| 258 | if (in_mncc->fields & MNCC_F_CALLING) |
| 259 | sign.calling() = dec_number(&in_mncc->calling); |
| 260 | if (in_mncc->fields & MNCC_F_REDIRECTING) |
| 261 | sign.redirecting() = dec_number(&in_mncc->redirecting); |
| 262 | if (in_mncc->fields & MNCC_F_CONNECTED) |
| 263 | sign.connected() = dec_number(&in_mncc->connected); |
| 264 | if (in_mncc->fields & MNCC_F_CAUSE) { |
| 265 | sign.cause() = MNCC__cause(in_mncc->cause.location, |
| 266 | in_mncc->cause.coding, |
| 267 | in_mncc->cause.rec, |
| 268 | in_mncc->cause.rec_val, |
| 269 | in_mncc->cause.value, |
| 270 | OCTETSTRING(in_mncc->cause.diag_len, |
| 271 | (const uint8_t *)in_mncc->cause.diag)); |
| 272 | } |
| 273 | if (in_mncc->fields & MNCC_F_USERUSER) { |
| 274 | sign.useruser() = MNCC__useruser(in_mncc->useruser.proto, |
| 275 | CHARSTRING(in_mncc->useruser.info)); |
| 276 | } |
| 277 | if (in_mncc->fields & MNCC_F_PROGRESS) { |
| 278 | sign.progress() = MNCC__progress(in_mncc->progress.coding, |
| 279 | in_mncc->progress.location, |
| 280 | in_mncc->progress.descr); |
| 281 | } |
| 282 | if (in_mncc->fields & MNCC_F_EMERGENCY) |
| 283 | sign.emergency() = in_mncc->emergency; |
| 284 | if (in_mncc->fields & MNCC_F_FACILITY) |
| 285 | sign.facility() = CHARSTRING(in_mncc->facility.info); |
| 286 | if (in_mncc->fields & MNCC_F_SSVERSION) |
| 287 | sign.ssversion() = CHARSTRING(in_mncc->ssversion.info); |
| 288 | if (in_mncc->fields & MNCC_F_CCCAP) |
| 289 | sign.cccap() = MNCC__cccap(in_mncc->cccap.dtmf, in_mncc->cccap.pcp); |
| 290 | if (in_mncc->fields & MNCC_F_KEYPAD) |
| 291 | sign.keypad() = in_mncc->keypad; |
| 292 | if (in_mncc->fields & MNCC_F_SIGNAL) |
| 293 | sign.signal() = in_mncc->signal; |
| 294 | |
| 295 | sign.clir__sup() = in_mncc->clir.sup; |
| 296 | sign.clir__inv() = in_mncc->clir.inv; |
| 297 | sign.more() = in_mncc->more; |
| 298 | sign.notify() = in_mncc->notify; |
| 299 | sign.imsi() = CHARSTRING(in_mncc->imsi); |
| 300 | sign.lchan__type() = in_mncc->lchan_type; |
| 301 | sign.lchan__mode() = in_mncc->lchan_mode; |
| 302 | u.signal() = sign; |
| 303 | break; |
| 304 | } |
| 305 | return MNCC__PDU(in_mncc->msg_type, u); |
| 306 | } |
| 307 | |
| 308 | } |