1 /*
2 * libpri: An implementation of Primary Rate ISDN
3 *
4 * Copyright (C) 2010 Digium, Inc.
5 *
6 * Richard Mudgett <rmudgett@digium.com>
7 * David Vossel <dvossel@digium.com>
8 *
9 * See http://www.asterisk.org for more information about
10 * the Asterisk project. Please do not directly contact
11 * any of the maintainers of this project for assistance;
12 * the project provides a web site, mailing lists and IRC
13 * channels for your use.
14 *
15 * This program is free software, distributed under the terms of
16 * the GNU General Public License Version 2 as published by the
17 * Free Software Foundation. See the LICENSE file included with
18 * this program for more details.
19 *
20 * In addition, when this program is distributed with Asterisk in
21 * any form that would qualify as a 'combined work' or as a
22 * 'derivative work' (but not mere aggregation), you can redistribute
23 * and/or modify the combination under the terms of the license
24 * provided with that copy of Asterisk, instead of the license
25 * terms granted here.
26 */
27
28 /*!
29 * \file
30 * \brief Advice Of Charge (AOC) facility support.
31 *
32 * \author Richard Mudgett <rmudgett@digium.com>
33 */
34
35
36 #include "compat.h"
37 #include "libpri.h"
38 #include "pri_internal.h"
39 #include "pri_facility.h"
40
41
42 /* ------------------------------------------------------------------- */
43
44 /*!
45 * \internal
46 * \brief Fill in the AOC subcmd amount from the ETSI amount.
47 *
48 * \param subcmd_amount AOC subcmd amount.
49 * \param etsi_amount AOC ETSI amount.
50 *
51 * \return Nothing
52 */
aoc_etsi_subcmd_amount(struct pri_aoc_amount * subcmd_amount,const struct roseEtsiAOCAmount * etsi_amount)53 static void aoc_etsi_subcmd_amount(struct pri_aoc_amount *subcmd_amount, const struct roseEtsiAOCAmount *etsi_amount)
54 {
55 subcmd_amount->cost = etsi_amount->currency;
56 subcmd_amount->multiplier = etsi_amount->multiplier;
57 }
58
59 /*!
60 * \internal
61 * \brief Fill in the ETSI amount from the AOC subcmd amount.
62 *
63 * \param subcmd_amount AOC subcmd amount.
64 * \param etsi_amount AOC ETSI amount.
65 *
66 * \return Nothing
67 */
aoc_enc_etsi_subcmd_amount(const struct pri_aoc_amount * subcmd_amount,struct roseEtsiAOCAmount * etsi_amount)68 static void aoc_enc_etsi_subcmd_amount(const struct pri_aoc_amount *subcmd_amount, struct roseEtsiAOCAmount *etsi_amount)
69 {
70 etsi_amount->currency = subcmd_amount->cost;
71 etsi_amount->multiplier = subcmd_amount->multiplier;
72 }
73
74 /*!
75 * \internal
76 * \brief Fill in the AOC subcmd time from the ETSI time.
77 *
78 * \param subcmd_time AOC subcmd time.
79 * \param etsi_time AOC ETSI time.
80 *
81 * \return Nothing
82 */
aoc_etsi_subcmd_time(struct pri_aoc_time * subcmd_time,const struct roseEtsiAOCTime * etsi_time)83 static void aoc_etsi_subcmd_time(struct pri_aoc_time *subcmd_time, const struct roseEtsiAOCTime *etsi_time)
84 {
85 subcmd_time->length = etsi_time->length;
86 subcmd_time->scale = etsi_time->scale;
87 }
88
89 /*!
90 * \internal
91 * \brief Fill in the ETSI Time from the AOC subcmd time.
92 *
93 * \param subcmd_time AOC subcmd time.
94 * \param etsi_time AOC ETSI time.
95 *
96 * \return Nothing
97 */
aoc_enc_etsi_subcmd_time(const struct pri_aoc_time * subcmd_time,struct roseEtsiAOCTime * etsi_time)98 static void aoc_enc_etsi_subcmd_time(const struct pri_aoc_time *subcmd_time, struct roseEtsiAOCTime *etsi_time)
99 {
100 etsi_time->length = subcmd_time->length;
101 etsi_time->scale = subcmd_time->scale;
102 }
103
104 /*!
105 * \internal
106 * \brief Fill in the AOC subcmd recorded currency from the ETSI recorded currency.
107 *
108 * \param subcmd_recorded AOC subcmd recorded currency.
109 * \param etsi_recorded AOC ETSI recorded currency.
110 *
111 * \return Nothing
112 */
aoc_etsi_subcmd_recorded_currency(struct pri_aoc_recorded_currency * subcmd_recorded,const struct roseEtsiAOCRecordedCurrency * etsi_recorded)113 static void aoc_etsi_subcmd_recorded_currency(struct pri_aoc_recorded_currency *subcmd_recorded, const struct roseEtsiAOCRecordedCurrency *etsi_recorded)
114 {
115 aoc_etsi_subcmd_amount(&subcmd_recorded->amount, &etsi_recorded->amount);
116 libpri_copy_string(subcmd_recorded->currency, (char *) etsi_recorded->currency,
117 sizeof(subcmd_recorded->currency));
118 }
119
120 /*!
121 * \internal
122 * \brief Fill in the the ETSI recorded currency from the subcmd currency info
123 *
124 * \param subcmd_recorded AOC subcmd recorded currency.
125 * \param etsi_recorded AOC ETSI recorded currency.
126 *
127 * \return Nothing
128 */
aoc_enc_etsi_subcmd_recorded_currency(const struct pri_aoc_recorded_currency * subcmd_recorded,struct roseEtsiAOCRecordedCurrency * etsi_recorded)129 static void aoc_enc_etsi_subcmd_recorded_currency(const struct pri_aoc_recorded_currency *subcmd_recorded, struct roseEtsiAOCRecordedCurrency *etsi_recorded)
130 {
131 aoc_enc_etsi_subcmd_amount(&subcmd_recorded->amount, &etsi_recorded->amount);
132 libpri_copy_string((char *) etsi_recorded->currency,
133 subcmd_recorded->currency,
134 sizeof(etsi_recorded->currency));
135 }
136
137 /*!
138 * \internal
139 * \brief Fill in the AOC subcmd recorded units from the ETSI recorded units.
140 *
141 * \param subcmd_recorded AOC subcmd recorded units list.
142 * \param etsi_recorded AOC ETSI recorded units list.
143 *
144 * \return Nothing
145 */
aoc_etsi_subcmd_recorded_units(struct pri_aoc_recorded_units * subcmd_recorded,const struct roseEtsiAOCRecordedUnitsList * etsi_recorded)146 static void aoc_etsi_subcmd_recorded_units(struct pri_aoc_recorded_units *subcmd_recorded, const struct roseEtsiAOCRecordedUnitsList *etsi_recorded)
147 {
148 int idx;
149
150 /* Fill in the itemized list of recorded units. */
151 for (idx = 0; idx < etsi_recorded->num_records
152 && idx < ARRAY_LEN(subcmd_recorded->item); ++idx) {
153 if (etsi_recorded->list[idx].not_available) {
154 subcmd_recorded->item[idx].number = -1;
155 } else {
156 subcmd_recorded->item[idx].number = etsi_recorded->list[idx].number_of_units;
157 }
158 if (etsi_recorded->list[idx].type_of_unit_present) {
159 subcmd_recorded->item[idx].type = etsi_recorded->list[idx].type_of_unit;
160 } else {
161 subcmd_recorded->item[idx].type = -1;
162 }
163 }
164 subcmd_recorded->num_items = idx;
165 }
166
167 /*!
168 * \internal
169 * \brief Fill in the ETSI recorded units from the AOC subcmd recorded units.
170 *
171 * \param subcmd_recorded AOC subcmd recorded units list.
172 * \param etsi_recorded AOC ETSI recorded units list.
173 *
174 * \return Nothing
175 */
aoc_enc_etsi_subcmd_recorded_units(const struct pri_aoc_recorded_units * subcmd_recorded,struct roseEtsiAOCRecordedUnitsList * etsi_recorded)176 static void aoc_enc_etsi_subcmd_recorded_units(const struct pri_aoc_recorded_units *subcmd_recorded, struct roseEtsiAOCRecordedUnitsList *etsi_recorded)
177 {
178 int i;
179
180 /* Fill in the itemized list of recorded units. */
181 for (i = 0; i < subcmd_recorded->num_items; i++) {
182 if (subcmd_recorded->item[i].number >= 0) {
183 etsi_recorded->list[i].number_of_units = subcmd_recorded->item[i].number;
184 } else {
185 etsi_recorded->list[i].not_available = 1;
186 }
187 if (subcmd_recorded->item[i].type > 0) {
188 etsi_recorded->list[i].type_of_unit = subcmd_recorded->item[i].type;
189 etsi_recorded->list[i].type_of_unit_present = 1;
190 }
191 }
192 etsi_recorded->num_records = i;
193
194 if (!etsi_recorded->num_records) {
195 etsi_recorded->list[0].not_available = 1;
196 etsi_recorded->list[0].type_of_unit_present = 0;
197 etsi_recorded->num_records = 1;
198 }
199 }
200
201 /*!
202 * \brief Handle the ETSI ChargingRequest.
203 *
204 * \param ctrl D channel controller for diagnostic messages or global options.
205 * \param call Q.931 call leg.
206 * \param invoke Decoded ROSE invoke message contents.
207 *
208 * \return Nothing
209 */
aoc_etsi_aoc_request(struct pri * ctrl,q931_call * call,const struct rose_msg_invoke * invoke)210 void aoc_etsi_aoc_request(struct pri *ctrl, q931_call *call, const struct rose_msg_invoke *invoke)
211 {
212 struct pri_subcommand *subcmd;
213 int request;
214
215 if (!ctrl->aoc_support) {
216 send_facility_error(ctrl, call, invoke->invoke_id, ROSE_ERROR_Gen_NotSubscribed);
217 return;
218 }
219 switch (invoke->args.etsi.ChargingRequest.charging_case) {
220 case 0:/* chargingInformationAtCallSetup */
221 request = PRI_AOC_REQUEST_S;
222 break;
223 case 1:/* chargingDuringACall */
224 request = PRI_AOC_REQUEST_D;
225 break;
226 case 2:/* chargingAtTheEndOfACall */
227 request = PRI_AOC_REQUEST_E;
228 break;
229 default:
230 send_facility_error(ctrl, call, invoke->invoke_id, ROSE_ERROR_Gen_NotImplemented);
231 return;
232 }
233
234 subcmd = q931_alloc_subcommand(ctrl);
235 if (!subcmd) {
236 send_facility_error(ctrl, call, invoke->invoke_id, ROSE_ERROR_Gen_NotAvailable);
237 return;
238 }
239
240 subcmd->cmd = PRI_SUBCMD_AOC_CHARGING_REQ;
241 subcmd->u.aoc_request.invoke_id = invoke->invoke_id;
242 subcmd->u.aoc_request.charging_request = request;
243 }
244
245 /*!
246 * \internal
247 * \brief Fill in the AOC-S subcmd currency info list of chargeable items.
248 *
249 * \param aoc_s AOC-S info list of chargeable items.
250 * \param info ETSI info list of chargeable items.
251 *
252 * \return Nothing
253 */
aoc_etsi_subcmd_aoc_s_currency_info(struct pri_subcmd_aoc_s * aoc_s,const struct roseEtsiAOCSCurrencyInfoList * info)254 static void aoc_etsi_subcmd_aoc_s_currency_info(struct pri_subcmd_aoc_s *aoc_s, const struct roseEtsiAOCSCurrencyInfoList *info)
255 {
256 int idx;
257
258 /* Fill in the itemized list of chargeable items. */
259 for (idx = 0; idx < info->num_records && idx < ARRAY_LEN(aoc_s->item); ++idx) {
260 /* What is being charged. */
261 switch (info->list[idx].charged_item) {
262 case 0:/* basicCommunication */
263 aoc_s->item[idx].chargeable = PRI_AOC_CHARGED_ITEM_BASIC_COMMUNICATION;
264 break;
265 case 1:/* callAttempt */
266 aoc_s->item[idx].chargeable = PRI_AOC_CHARGED_ITEM_CALL_ATTEMPT;
267 break;
268 case 2:/* callSetup */
269 aoc_s->item[idx].chargeable = PRI_AOC_CHARGED_ITEM_CALL_SETUP;
270 break;
271 case 3:/* userToUserInfo */
272 aoc_s->item[idx].chargeable = PRI_AOC_CHARGED_ITEM_USER_USER_INFO;
273 break;
274 case 4:/* operationOfSupplementaryServ */
275 aoc_s->item[idx].chargeable = PRI_AOC_CHARGED_ITEM_SUPPLEMENTARY_SERVICE;
276 break;
277 default:
278 aoc_s->item[idx].chargeable = PRI_AOC_CHARGED_ITEM_NOT_AVAILABLE;
279 break;
280 }
281
282 /* Rate method being used. */
283 switch (info->list[idx].currency_type) {
284 case 0:/* specialChargingCode */
285 aoc_s->item[idx].rate_type = PRI_AOC_RATE_TYPE_SPECIAL_CODE;
286 aoc_s->item[idx].rate.special = info->list[idx].u.special_charging_code;
287 break;
288 case 1:/* durationCurrency */
289 aoc_s->item[idx].rate_type = PRI_AOC_RATE_TYPE_DURATION;
290 aoc_etsi_subcmd_amount(&aoc_s->item[idx].rate.duration.amount,
291 &info->list[idx].u.duration.amount);
292 aoc_etsi_subcmd_time(&aoc_s->item[idx].rate.duration.time,
293 &info->list[idx].u.duration.time);
294 if (info->list[idx].u.duration.granularity_present) {
295 aoc_etsi_subcmd_time(&aoc_s->item[idx].rate.duration.granularity,
296 &info->list[idx].u.duration.granularity);
297 } else {
298 aoc_s->item[idx].rate.duration.granularity.length = 0;
299 aoc_s->item[idx].rate.duration.granularity.scale =
300 PRI_AOC_TIME_SCALE_HUNDREDTH_SECOND;
301 }
302 aoc_s->item[idx].rate.duration.charging_type =
303 info->list[idx].u.duration.charging_type;
304 libpri_copy_string(aoc_s->item[idx].rate.duration.currency,
305 (char *) info->list[idx].u.duration.currency,
306 sizeof(aoc_s->item[idx].rate.duration.currency));
307 break;
308 case 2:/* flatRateCurrency */
309 aoc_s->item[idx].rate_type = PRI_AOC_RATE_TYPE_FLAT;
310 aoc_etsi_subcmd_amount(&aoc_s->item[idx].rate.flat.amount,
311 &info->list[idx].u.flat_rate.amount);
312 libpri_copy_string(aoc_s->item[idx].rate.flat.currency,
313 (char *) info->list[idx].u.flat_rate.currency,
314 sizeof(aoc_s->item[idx].rate.flat.currency));
315 break;
316 case 3:/* volumeRateCurrency */
317 aoc_s->item[idx].rate_type = PRI_AOC_RATE_TYPE_VOLUME;
318 aoc_etsi_subcmd_amount(&aoc_s->item[idx].rate.volume.amount,
319 &info->list[idx].u.volume_rate.amount);
320 aoc_s->item[idx].rate.volume.unit = info->list[idx].u.volume_rate.unit;
321 libpri_copy_string(aoc_s->item[idx].rate.volume.currency,
322 (char *) info->list[idx].u.volume_rate.currency,
323 sizeof(aoc_s->item[idx].rate.volume.currency));
324 break;
325 case 4:/* freeOfCharge */
326 aoc_s->item[idx].rate_type = PRI_AOC_RATE_TYPE_FREE;
327 break;
328 default:
329 case 5:/* currencyInfoNotAvailable */
330 aoc_s->item[idx].rate_type = PRI_AOC_RATE_TYPE_NOT_AVAILABLE;
331 break;
332 }
333 }
334 aoc_s->num_items = idx;
335 }
336
337 /*!
338 * \internal
339 * \brief Fill in the currency info list of chargeable items from a aoc_s subcmd
340 *
341 * \param aoc_s AOC-S info list of chargeable items.
342 * \param info ETSI info list of chargeable items.
343 *
344 * \return Nothing
345 */
enc_etsi_subcmd_aoc_s_currency_info(const struct pri_subcmd_aoc_s * aoc_s,struct roseEtsiAOCSCurrencyInfoList * info)346 static void enc_etsi_subcmd_aoc_s_currency_info(const struct pri_subcmd_aoc_s *aoc_s, struct roseEtsiAOCSCurrencyInfoList *info)
347 {
348 int idx;
349
350 for (idx = 0; idx < aoc_s->num_items && idx < ARRAY_LEN(info->list); ++idx) {
351 /* What is being charged. */
352 switch (aoc_s->item[idx].chargeable) {
353 default:
354 case PRI_AOC_CHARGED_ITEM_BASIC_COMMUNICATION:
355 info->list[idx].charged_item = 0;/* basicCommunication */
356 break;
357 case PRI_AOC_CHARGED_ITEM_CALL_ATTEMPT:
358 info->list[idx].charged_item = 1;/* callAttempt */
359 break;
360 case PRI_AOC_CHARGED_ITEM_CALL_SETUP:
361 info->list[idx].charged_item = 2;/* callSetup */
362 break;
363 case PRI_AOC_CHARGED_ITEM_USER_USER_INFO:
364 info->list[idx].charged_item = 3;/* userToUserInfo */
365 break;
366 case PRI_AOC_CHARGED_ITEM_SUPPLEMENTARY_SERVICE:
367 info->list[idx].charged_item = 4;/* operationOfSupplementaryServ */
368 break;
369 }
370
371 /* Rate method being used. */
372 switch (aoc_s->item[idx].rate_type) {
373 case PRI_AOC_RATE_TYPE_SPECIAL_CODE:
374 info->list[idx].currency_type = 0;/* specialChargingCode */
375 info->list[idx].u.special_charging_code = aoc_s->item[idx].rate.special;
376 break;
377 case PRI_AOC_RATE_TYPE_DURATION:
378 info->list[idx].currency_type = 1;/* durationCurrency */
379 aoc_enc_etsi_subcmd_amount(&aoc_s->item[idx].rate.duration.amount,
380 &info->list[idx].u.duration.amount);
381 aoc_enc_etsi_subcmd_time(&aoc_s->item[idx].rate.duration.time,
382 &info->list[idx].u.duration.time);
383 if (aoc_s->item[idx].rate.duration.granularity.length) {
384 info->list[idx].u.duration.granularity_present = 1;
385 aoc_enc_etsi_subcmd_time(&aoc_s->item[idx].rate.duration.granularity,
386 &info->list[idx].u.duration.granularity);
387 } else {
388 info->list[idx].u.duration.granularity_present = 0;
389 }
390 info->list[idx].u.duration.charging_type = aoc_s->item[idx].rate.duration.charging_type;
391 libpri_copy_string((char *) info->list[idx].u.duration.currency,
392 aoc_s->item[idx].rate.duration.currency,
393 sizeof((char *) info->list[idx].u.duration.currency));
394 break;
395 case PRI_AOC_RATE_TYPE_FLAT:
396 info->list[idx].currency_type = 2;/* flatRateCurrency */
397 aoc_enc_etsi_subcmd_amount(&aoc_s->item[idx].rate.flat.amount,
398 &info->list[idx].u.flat_rate.amount);
399 libpri_copy_string((char *) info->list[idx].u.flat_rate.currency,
400 aoc_s->item[idx].rate.flat.currency,
401 sizeof((char *) info->list[idx].u.flat_rate.currency));
402 break;
403 case PRI_AOC_RATE_TYPE_VOLUME:
404 info->list[idx].currency_type = 3;/* volumeRateCurrency */
405 aoc_enc_etsi_subcmd_amount(&aoc_s->item[idx].rate.volume.amount,
406 &info->list[idx].u.volume_rate.amount);
407 info->list[idx].u.volume_rate.unit = aoc_s->item[idx].rate.volume.unit;
408 libpri_copy_string((char *) info->list[idx].u.volume_rate.currency,
409 aoc_s->item[idx].rate.volume.currency,
410 sizeof((char *) info->list[idx].u.volume_rate.currency));
411 break;
412 case PRI_AOC_RATE_TYPE_FREE:
413 info->list[idx].currency_type = 4;/* freeOfCharge */
414 break;
415 default:
416 case PRI_AOC_RATE_TYPE_NOT_AVAILABLE:
417 info->list[idx].currency_type = 5;/* currencyInfoNotAvailable */
418 break;
419 }
420 }
421 if (!idx) {
422 /* We cannot send an empty list so create a dummy list element. */
423 info->list[idx].charged_item = 0;/* basicCommunication */
424 info->list[idx].currency_type = 5;/* currencyInfoNotAvailable */
425 ++idx;
426 }
427 info->num_records = idx;
428 }
429
430 /*!
431 * \brief Handle the ETSI AOCSCurrency message.
432 *
433 * \param ctrl D channel controller for diagnostic messages or global options.
434 * \param invoke Decoded ROSE invoke message contents.
435 *
436 * \return Nothing
437 */
aoc_etsi_aoc_s_currency(struct pri * ctrl,const struct rose_msg_invoke * invoke)438 void aoc_etsi_aoc_s_currency(struct pri *ctrl, const struct rose_msg_invoke *invoke)
439 {
440 struct pri_subcommand *subcmd;
441
442 if (!ctrl->aoc_support) {
443 return;
444 }
445 subcmd = q931_alloc_subcommand(ctrl);
446 if (!subcmd) {
447 return;
448 }
449
450 subcmd->cmd = PRI_SUBCMD_AOC_S;
451 if (!invoke->args.etsi.AOCSCurrency.type) {
452 subcmd->u.aoc_s.num_items = 0;
453 return;
454 }
455
456 /* Fill in the itemized list of chargeable items. */
457 aoc_etsi_subcmd_aoc_s_currency_info(&subcmd->u.aoc_s,
458 &invoke->args.etsi.AOCSCurrency.currency_info);
459 }
460
461 /*!
462 * \brief Handle the ETSI AOCSSpecialArr message.
463 *
464 * \param ctrl D channel controller for diagnostic messages or global options.
465 * \param invoke Decoded ROSE invoke message contents.
466 *
467 * \return Nothing
468 */
aoc_etsi_aoc_s_special_arrangement(struct pri * ctrl,const struct rose_msg_invoke * invoke)469 void aoc_etsi_aoc_s_special_arrangement(struct pri *ctrl, const struct rose_msg_invoke *invoke)
470 {
471 struct pri_subcommand *subcmd;
472
473 if (!ctrl->aoc_support) {
474 return;
475 }
476 subcmd = q931_alloc_subcommand(ctrl);
477 if (!subcmd) {
478 return;
479 }
480 subcmd->cmd = PRI_SUBCMD_AOC_S;
481 if (!invoke->args.etsi.AOCSSpecialArr.type) {
482 subcmd->u.aoc_s.num_items = 0;
483 return;
484 }
485 subcmd->u.aoc_s.num_items = 1;
486 subcmd->u.aoc_s.item[0].chargeable = PRI_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT;
487 subcmd->u.aoc_s.item[0].rate_type = PRI_AOC_RATE_TYPE_SPECIAL_CODE;
488 subcmd->u.aoc_s.item[0].rate.special =
489 invoke->args.etsi.AOCSSpecialArr.special_arrangement;
490 }
491
492 /*!
493 * \internal
494 * \brief Determine the AOC-D subcmd billing_id value.
495 *
496 * \param billing_id_present TRUE if billing_id valid.
497 * \param billing_id ETSI billing id from ROSE.
498 *
499 * \return enum PRI_AOC_D_BILLING_ID value
500 */
aoc_etsi_subcmd_aoc_d_billing_id(int billing_id_present,int billing_id)501 static enum PRI_AOC_D_BILLING_ID aoc_etsi_subcmd_aoc_d_billing_id(int billing_id_present, int billing_id)
502 {
503 enum PRI_AOC_D_BILLING_ID value;
504
505 if (billing_id_present) {
506 switch (billing_id) {
507 case 0:/* normalCharging */
508 value = PRI_AOC_D_BILLING_ID_NORMAL;
509 break;
510 case 1:/* reverseCharging */
511 value = PRI_AOC_D_BILLING_ID_REVERSE;
512 break;
513 case 2:/* creditCardCharging */
514 value = PRI_AOC_D_BILLING_ID_CREDIT_CARD;
515 break;
516 default:
517 value = PRI_AOC_D_BILLING_ID_NOT_AVAILABLE;
518 break;
519 }
520 } else {
521 value = PRI_AOC_D_BILLING_ID_NOT_AVAILABLE;
522 }
523 return value;
524 }
525
526 /*!
527 * \brief Handle the ETSI AOCDCurrency message.
528 *
529 * \param ctrl D channel controller for diagnostic messages or global options.
530 * \param invoke Decoded ROSE invoke message contents.
531 *
532 * \return Nothing
533 */
aoc_etsi_aoc_d_currency(struct pri * ctrl,const struct rose_msg_invoke * invoke)534 void aoc_etsi_aoc_d_currency(struct pri *ctrl, const struct rose_msg_invoke *invoke)
535 {
536 struct pri_subcommand *subcmd;
537
538 if (!ctrl->aoc_support) {
539 return;
540 }
541 subcmd = q931_alloc_subcommand(ctrl);
542 if (!subcmd) {
543 return;
544 }
545
546 subcmd->cmd = PRI_SUBCMD_AOC_D;
547 switch (invoke->args.etsi.AOCDCurrency.type) {
548 default:
549 case 0:/* charge_not_available */
550 subcmd->u.aoc_d.charge = PRI_AOC_DE_CHARGE_NOT_AVAILABLE;
551 break;
552 case 1:/* free_of_charge */
553 subcmd->u.aoc_d.charge = PRI_AOC_DE_CHARGE_FREE;
554 break;
555 case 2:/* specific_currency */
556 subcmd->u.aoc_d.charge = PRI_AOC_DE_CHARGE_CURRENCY;
557 aoc_etsi_subcmd_recorded_currency(&subcmd->u.aoc_d.recorded.money,
558 &invoke->args.etsi.AOCDCurrency.specific.recorded);
559 subcmd->u.aoc_d.billing_accumulation =
560 invoke->args.etsi.AOCDCurrency.specific.type_of_charging_info;
561 subcmd->u.aoc_d.billing_id = aoc_etsi_subcmd_aoc_d_billing_id(
562 invoke->args.etsi.AOCDCurrency.specific.billing_id_present,
563 invoke->args.etsi.AOCDCurrency.specific.billing_id);
564 break;
565 }
566 }
567
568 /*!
569 * \brief Handle the ETSI AOCDChargingUnit message.
570 *
571 * \param ctrl D channel controller for diagnostic messages or global options.
572 * \param invoke Decoded ROSE invoke message contents.
573 *
574 * \return Nothing
575 */
aoc_etsi_aoc_d_charging_unit(struct pri * ctrl,const struct rose_msg_invoke * invoke)576 void aoc_etsi_aoc_d_charging_unit(struct pri *ctrl, const struct rose_msg_invoke *invoke)
577 {
578 struct pri_subcommand *subcmd;
579
580 if (!ctrl->aoc_support) {
581 return;
582 }
583 subcmd = q931_alloc_subcommand(ctrl);
584 if (!subcmd) {
585 return;
586 }
587
588 subcmd->cmd = PRI_SUBCMD_AOC_D;
589 switch (invoke->args.etsi.AOCDChargingUnit.type) {
590 default:
591 case 0:/* charge_not_available */
592 subcmd->u.aoc_d.charge = PRI_AOC_DE_CHARGE_NOT_AVAILABLE;
593 break;
594 case 1:/* free_of_charge */
595 subcmd->u.aoc_d.charge = PRI_AOC_DE_CHARGE_FREE;
596 break;
597 case 2:/* specific_charging_units */
598 subcmd->u.aoc_d.charge = PRI_AOC_DE_CHARGE_UNITS;
599 aoc_etsi_subcmd_recorded_units(&subcmd->u.aoc_d.recorded.unit,
600 &invoke->args.etsi.AOCDChargingUnit.specific.recorded);
601 subcmd->u.aoc_d.billing_accumulation =
602 invoke->args.etsi.AOCDChargingUnit.specific.type_of_charging_info;
603 subcmd->u.aoc_d.billing_id = aoc_etsi_subcmd_aoc_d_billing_id(
604 invoke->args.etsi.AOCDChargingUnit.specific.billing_id_present,
605 invoke->args.etsi.AOCDChargingUnit.specific.billing_id);
606 break;
607 }
608 }
609
610 /*!
611 * \internal
612 * \brief Fill in the AOC-E subcmd charging association from the ETSI charging association.
613 *
614 * \param ctrl D channel controller for diagnostic messages or global options.
615 * \param subcmd_association AOC-E subcmd charging association.
616 * \param etsi_association AOC-E ETSI charging association.
617 *
618 * \return Nothing
619 */
aoc_etsi_subcmd_aoc_e_charging_association(struct pri * ctrl,struct pri_aoc_e_charging_association * subcmd_association,const struct roseEtsiAOCChargingAssociation * etsi_association)620 static void aoc_etsi_subcmd_aoc_e_charging_association(struct pri *ctrl, struct pri_aoc_e_charging_association *subcmd_association, const struct roseEtsiAOCChargingAssociation *etsi_association)
621 {
622 struct q931_party_number q931_number;
623
624 switch (etsi_association->type) {
625 case 0:/* charge_identifier */
626 subcmd_association->charging_type = PRI_AOC_E_CHARGING_ASSOCIATION_ID;
627 subcmd_association->charge.id = etsi_association->id;
628 break;
629 case 1:/* charged_number */
630 subcmd_association->charging_type = PRI_AOC_E_CHARGING_ASSOCIATION_NUMBER;
631 q931_party_number_init(&q931_number);
632 rose_copy_number_to_q931(ctrl, &q931_number, &etsi_association->number);
633 q931_party_number_copy_to_pri(&subcmd_association->charge.number, &q931_number);
634 break;
635 default:
636 subcmd_association->charging_type = PRI_AOC_E_CHARGING_ASSOCIATION_NOT_AVAILABLE;
637 break;
638 }
639 }
640
641 /*!
642 * \internal
643 * \brief Determine the AOC-E subcmd billing_id value.
644 *
645 * \param billing_id_present TRUE if billing_id valid.
646 * \param billing_id ETSI billing id from ROSE.
647 *
648 * \return enum PRI_AOC_E_BILLING_ID value
649 */
aoc_etsi_subcmd_aoc_e_billing_id(int billing_id_present,int billing_id)650 static enum PRI_AOC_E_BILLING_ID aoc_etsi_subcmd_aoc_e_billing_id(int billing_id_present, int billing_id)
651 {
652 enum PRI_AOC_E_BILLING_ID value;
653
654 if (billing_id_present) {
655 switch (billing_id) {
656 case 0:/* normalCharging */
657 value = PRI_AOC_E_BILLING_ID_NORMAL;
658 break;
659 case 1:/* reverseCharging */
660 value = PRI_AOC_E_BILLING_ID_REVERSE;
661 break;
662 case 2:/* creditCardCharging */
663 value = PRI_AOC_E_BILLING_ID_CREDIT_CARD;
664 break;
665 case 3:/* callForwardingUnconditional */
666 value = PRI_AOC_E_BILLING_ID_CALL_FORWARDING_UNCONDITIONAL;
667 break;
668 case 4:/* callForwardingBusy */
669 value = PRI_AOC_E_BILLING_ID_CALL_FORWARDING_BUSY;
670 break;
671 case 5:/* callForwardingNoReply */
672 value = PRI_AOC_E_BILLING_ID_CALL_FORWARDING_NO_REPLY;
673 break;
674 case 6:/* callDeflection */
675 value = PRI_AOC_E_BILLING_ID_CALL_DEFLECTION;
676 break;
677 case 7:/* callTransfer */
678 value = PRI_AOC_E_BILLING_ID_CALL_TRANSFER;
679 break;
680 default:
681 value = PRI_AOC_E_BILLING_ID_NOT_AVAILABLE;
682 break;
683 }
684 } else {
685 value = PRI_AOC_E_BILLING_ID_NOT_AVAILABLE;
686 }
687 return value;
688 }
689
690 /*!
691 * \internal
692 * \brief Determine the ETSI AOC-E billing_id value from the subcmd.
693 *
694 * \param billing_id from upper layer.
695 *
696 * \retval -1 failure
697 * \retval etsi billing id
698 */
aoc_subcmd_aoc_e_etsi_billing_id(enum PRI_AOC_E_BILLING_ID billing_id)699 static int aoc_subcmd_aoc_e_etsi_billing_id(enum PRI_AOC_E_BILLING_ID billing_id)
700 {
701 switch (billing_id) {
702 case PRI_AOC_E_BILLING_ID_NORMAL:
703 return 0;/* normalCharging */
704 case PRI_AOC_E_BILLING_ID_REVERSE:
705 return 1;/* reverseCharging */
706 case PRI_AOC_E_BILLING_ID_CREDIT_CARD:
707 return 2;/* creditCardCharging */
708 case PRI_AOC_E_BILLING_ID_CALL_FORWARDING_UNCONDITIONAL:
709 return 3;/* callForwardingUnconditional */
710 case PRI_AOC_E_BILLING_ID_CALL_FORWARDING_BUSY:
711 return 4;/* callForwardingBusy */
712 case PRI_AOC_E_BILLING_ID_CALL_FORWARDING_NO_REPLY:
713 return 5;/* callForwardingNoReply */
714 case PRI_AOC_E_BILLING_ID_CALL_DEFLECTION:
715 return 6;/* callDeflection */
716 case PRI_AOC_E_BILLING_ID_CALL_TRANSFER:
717 return 7;/* callTransfer */
718 case PRI_AOC_E_BILLING_ID_NOT_AVAILABLE:
719 break;
720 }
721
722 return -1;
723 }
724
725 /*!
726 * \internal
727 * \brief Determine the ETSI AOC-D billing_id value from the subcmd.
728 *
729 * \param billing_id from upper layer.
730 *
731 * \retval -1 failure
732 * \retval etsi billing id
733 */
aoc_subcmd_aoc_d_etsi_billing_id(enum PRI_AOC_D_BILLING_ID billing_id)734 static int aoc_subcmd_aoc_d_etsi_billing_id(enum PRI_AOC_D_BILLING_ID billing_id)
735 {
736 switch (billing_id) {
737 case PRI_AOC_D_BILLING_ID_NORMAL:
738 return 0;/* normalCharging */
739 case PRI_AOC_D_BILLING_ID_REVERSE:
740 return 1;/* reverseCharging */
741 case PRI_AOC_D_BILLING_ID_CREDIT_CARD:
742 return 2;/* creditCardCharging */
743 case PRI_AOC_D_BILLING_ID_NOT_AVAILABLE:
744 break;
745 }
746
747 return -1;
748 }
749
750 /*!
751 * \brief Handle the ETSI AOCECurrency message.
752 *
753 * \param ctrl D channel controller for diagnostic messages or global options.
754 * \param call Q.931 call leg.
755 * \param invoke Decoded ROSE invoke message contents.
756 *
757 * \return Nothing
758 */
aoc_etsi_aoc_e_currency(struct pri * ctrl,q931_call * call,const struct rose_msg_invoke * invoke)759 void aoc_etsi_aoc_e_currency(struct pri *ctrl, q931_call *call, const struct rose_msg_invoke *invoke)
760 {
761 struct pri_subcommand *subcmd;
762
763 if (!ctrl->aoc_support) {
764 return;
765 }
766 subcmd = q931_alloc_subcommand(ctrl);
767 if (!subcmd) {
768 return;
769 }
770
771 subcmd->cmd = PRI_SUBCMD_AOC_E;
772 subcmd->u.aoc_e.associated.charging_type =
773 PRI_AOC_E_CHARGING_ASSOCIATION_NOT_AVAILABLE;
774
775 if (!invoke->args.etsi.AOCECurrency.type) {
776 subcmd->u.aoc_e.charge = PRI_AOC_DE_CHARGE_NOT_AVAILABLE;
777 return;
778 }
779
780 /* Fill in charging association if present. */
781 if (invoke->args.etsi.AOCECurrency.currency_info.charging_association_present) {
782 aoc_etsi_subcmd_aoc_e_charging_association(ctrl, &subcmd->u.aoc_e.associated,
783 &invoke->args.etsi.AOCECurrency.currency_info.charging_association);
784 }
785
786 /* Call was free of charge. */
787 if (invoke->args.etsi.AOCECurrency.currency_info.free_of_charge) {
788 subcmd->u.aoc_e.charge = PRI_AOC_DE_CHARGE_FREE;
789 return;
790 }
791
792 /* Fill in currency cost of call. */
793 subcmd->u.aoc_e.charge = PRI_AOC_DE_CHARGE_CURRENCY;
794 aoc_etsi_subcmd_recorded_currency(&subcmd->u.aoc_e.recorded.money,
795 &invoke->args.etsi.AOCECurrency.currency_info.specific.recorded);
796 subcmd->u.aoc_e.billing_id = aoc_etsi_subcmd_aoc_e_billing_id(
797 invoke->args.etsi.AOCECurrency.currency_info.specific.billing_id_present,
798 invoke->args.etsi.AOCECurrency.currency_info.specific.billing_id);
799 }
800
801 /*!
802 * \brief Handle the ETSI AOCEChargingUnit message.
803 *
804 * \param ctrl D channel controller for diagnostic messages or global options.
805 * \param call Q.931 call leg.
806 * \param invoke Decoded ROSE invoke message contents.
807 *
808 * \return Nothing
809 */
aoc_etsi_aoc_e_charging_unit(struct pri * ctrl,q931_call * call,const struct rose_msg_invoke * invoke)810 void aoc_etsi_aoc_e_charging_unit(struct pri *ctrl, q931_call *call, const struct rose_msg_invoke *invoke)
811 {
812 struct pri_subcommand *subcmd;
813 unsigned idx;
814
815 /* Fill in legacy stuff. */
816 call->aoc_units = 0;
817 if (invoke->args.etsi.AOCEChargingUnit.type == 1
818 && !invoke->args.etsi.AOCEChargingUnit.charging_unit.free_of_charge) {
819 for (idx =
820 invoke->args.etsi.AOCEChargingUnit.charging_unit.specific.recorded.num_records;
821 idx--;) {
822 if (!invoke->args.etsi.AOCEChargingUnit.charging_unit.specific.recorded.
823 list[idx].not_available) {
824 call->aoc_units +=
825 invoke->args.etsi.AOCEChargingUnit.charging_unit.specific.
826 recorded.list[idx].number_of_units;
827 }
828 }
829 }
830
831 if (!ctrl->aoc_support) {
832 return;
833 }
834 subcmd = q931_alloc_subcommand(ctrl);
835 if (!subcmd) {
836 return;
837 }
838
839 subcmd->cmd = PRI_SUBCMD_AOC_E;
840 subcmd->u.aoc_e.associated.charging_type =
841 PRI_AOC_E_CHARGING_ASSOCIATION_NOT_AVAILABLE;
842
843 if (!invoke->args.etsi.AOCEChargingUnit.type) {
844 subcmd->u.aoc_e.charge = PRI_AOC_DE_CHARGE_NOT_AVAILABLE;
845 return;
846 }
847
848 /* Fill in charging association if present. */
849 if (invoke->args.etsi.AOCEChargingUnit.charging_unit.charging_association_present) {
850 aoc_etsi_subcmd_aoc_e_charging_association(ctrl, &subcmd->u.aoc_e.associated,
851 &invoke->args.etsi.AOCEChargingUnit.charging_unit.charging_association);
852 }
853
854 /* Call was free of charge. */
855 if (invoke->args.etsi.AOCEChargingUnit.charging_unit.free_of_charge) {
856 subcmd->u.aoc_e.charge = PRI_AOC_DE_CHARGE_FREE;
857 return;
858 }
859
860 /* Fill in unit cost of call. */
861 subcmd->u.aoc_e.charge = PRI_AOC_DE_CHARGE_UNITS;
862 aoc_etsi_subcmd_recorded_units(&subcmd->u.aoc_e.recorded.unit,
863 &invoke->args.etsi.AOCEChargingUnit.charging_unit.specific.recorded);
864 subcmd->u.aoc_e.billing_id = aoc_etsi_subcmd_aoc_e_billing_id(
865 invoke->args.etsi.AOCEChargingUnit.charging_unit.specific.billing_id_present,
866 invoke->args.etsi.AOCEChargingUnit.charging_unit.specific.billing_id);
867 }
868
pri_aoc_events_enable(struct pri * ctrl,int enable)869 void pri_aoc_events_enable(struct pri *ctrl, int enable)
870 {
871 if (ctrl) {
872 ctrl->aoc_support = enable ? 1 : 0;
873 }
874 }
875
876 /*!
877 * \internal
878 * \brief Encode the ETSI AOCECurrency invoke message.
879 *
880 * \param ctrl D channel controller for diagnostic messages or global options.
881 * \param pos Starting position to encode the facility ie contents.
882 * \param end End of facility ie contents encoding data buffer.
883 * \param aoc_e the AOC-E data to encode.
884 *
885 * \retval Start of the next ASN.1 component to encode on success.
886 * \retval NULL on error.
887 */
enc_etsi_aoce_currency(struct pri * ctrl,unsigned char * pos,unsigned char * end,const struct pri_subcmd_aoc_e * aoc_e)888 static unsigned char *enc_etsi_aoce_currency(struct pri *ctrl, unsigned char *pos,
889 unsigned char *end, const struct pri_subcmd_aoc_e *aoc_e)
890 {
891 struct rose_msg_invoke msg;
892 struct q931_party_number q931_number;
893
894 pos = facility_encode_header(ctrl, pos, end, NULL);
895 if (!pos) {
896 return NULL;
897 }
898
899 memset(&msg, 0, sizeof(msg));
900 msg.operation = ROSE_ETSI_AOCECurrency;
901 msg.invoke_id = get_invokeid(ctrl);
902
903 if (aoc_e->charge == PRI_AOC_DE_CHARGE_FREE) {
904 msg.args.etsi.AOCECurrency.type = 1; /* currency_info */
905 msg.args.etsi.AOCECurrency.currency_info.free_of_charge = 1;
906 } else if ((aoc_e->charge == PRI_AOC_DE_CHARGE_CURRENCY) && (aoc_e->recorded.money.amount.cost >= 0)) {
907 msg.args.etsi.AOCECurrency.type = 1; /* currency_info */
908 aoc_enc_etsi_subcmd_recorded_currency(&aoc_e->recorded.money,
909 &msg.args.etsi.AOCECurrency.currency_info.specific.recorded);
910 } else {
911 msg.args.etsi.AOCECurrency.type = 0; /* charge_not_available */
912 }
913
914 if (aoc_subcmd_aoc_e_etsi_billing_id(aoc_e->billing_id) != -1) {
915 msg.args.etsi.AOCECurrency.currency_info.specific.billing_id_present = 1;
916 msg.args.etsi.AOCECurrency.currency_info.specific.billing_id =
917 aoc_subcmd_aoc_e_etsi_billing_id(aoc_e->billing_id);
918 }
919
920 switch (aoc_e->associated.charging_type) {
921 case PRI_AOC_E_CHARGING_ASSOCIATION_NUMBER:
922 msg.args.etsi.AOCECurrency.currency_info.charging_association_present = 1;
923 msg.args.etsi.AOCECurrency.currency_info.charging_association.type = 1; /* charged_number */
924 pri_copy_party_number_to_q931(&q931_number, &aoc_e->associated.charge.number);
925 q931_copy_number_to_rose(ctrl,
926 &msg.args.etsi.AOCECurrency.currency_info.charging_association.number,
927 &q931_number);
928 break;
929 case PRI_AOC_E_CHARGING_ASSOCIATION_ID:
930 msg.args.etsi.AOCECurrency.currency_info.charging_association_present = 1;
931 msg.args.etsi.AOCECurrency.currency_info.charging_association.type = 0; /* charge_identifier */
932 msg.args.etsi.AOCECurrency.currency_info.charging_association.id =
933 aoc_e->associated.charge.id;
934 break;
935 default:
936 /* do nothing */
937 break;
938 }
939
940 pos = rose_encode_invoke(ctrl, pos, end, &msg);
941
942 return pos;
943 }
944
945 /*!
946 * \internal
947 * \brief Encode the ETSI AOCEChargingUnit invoke message.
948 *
949 * \param ctrl D channel controller for diagnostic messages or global options.
950 * \param pos Starting position to encode the facility ie contents.
951 * \param end End of facility ie contents encoding data buffer.
952 * \param aoc_e the AOC-E data to encode.
953 *
954 * \retval Start of the next ASN.1 component to encode on success.
955 * \retval NULL on error.
956 */
enc_etsi_aoce_charging_unit(struct pri * ctrl,unsigned char * pos,unsigned char * end,const struct pri_subcmd_aoc_e * aoc_e)957 static unsigned char *enc_etsi_aoce_charging_unit(struct pri *ctrl, unsigned char *pos,
958 unsigned char *end, const struct pri_subcmd_aoc_e *aoc_e)
959 {
960 struct rose_msg_invoke msg;
961 struct q931_party_number q931_number;
962
963 pos = facility_encode_header(ctrl, pos, end, NULL);
964 if (!pos) {
965 return NULL;
966 }
967
968 memset(&msg, 0, sizeof(msg));
969 msg.operation = ROSE_ETSI_AOCEChargingUnit;
970 msg.invoke_id = get_invokeid(ctrl);
971
972 if (aoc_e->charge == PRI_AOC_DE_CHARGE_FREE) {
973 msg.args.etsi.AOCEChargingUnit.type = 1; /* charging_unit */
974 msg.args.etsi.AOCEChargingUnit.charging_unit.free_of_charge = 1;
975
976 } else if ((aoc_e->charge == PRI_AOC_DE_CHARGE_UNITS) && (aoc_e->recorded.unit.num_items > 0)) {
977 msg.args.etsi.AOCEChargingUnit.type = 1; /* charging_unit */
978 aoc_enc_etsi_subcmd_recorded_units(&aoc_e->recorded.unit,
979 &msg.args.etsi.AOCEChargingUnit.charging_unit.specific.recorded);
980 } else {
981 msg.args.etsi.AOCEChargingUnit.type = 0; /* charge_not_available */
982 }
983
984 if (aoc_subcmd_aoc_e_etsi_billing_id(aoc_e->billing_id) != -1) {
985 msg.args.etsi.AOCEChargingUnit.charging_unit.specific.billing_id_present = 1;
986 msg.args.etsi.AOCEChargingUnit.charging_unit.specific.billing_id =
987 aoc_subcmd_aoc_e_etsi_billing_id(aoc_e->billing_id);
988 }
989
990 switch (aoc_e->associated.charging_type) {
991 case PRI_AOC_E_CHARGING_ASSOCIATION_NUMBER:
992 msg.args.etsi.AOCEChargingUnit.charging_unit.charging_association_present = 1;
993 msg.args.etsi.AOCEChargingUnit.charging_unit.charging_association.type = 1; /* charged_number */
994 pri_copy_party_number_to_q931(&q931_number, &aoc_e->associated.charge.number);
995 q931_copy_number_to_rose(ctrl,
996 &msg.args.etsi.AOCEChargingUnit.charging_unit.charging_association.number,
997 &q931_number);
998 break;
999 case PRI_AOC_E_CHARGING_ASSOCIATION_ID:
1000 msg.args.etsi.AOCEChargingUnit.charging_unit.charging_association_present = 1;
1001 msg.args.etsi.AOCEChargingUnit.charging_unit.charging_association.type = 0; /* charge_identifier */
1002 msg.args.etsi.AOCEChargingUnit.charging_unit.charging_association.id =
1003 aoc_e->associated.charge.id;
1004 break;
1005 default:
1006 /* do nothing */
1007 break;
1008 }
1009
1010 pos = rose_encode_invoke(ctrl, pos, end, &msg);
1011
1012 return pos;
1013 }
1014
1015 /*!
1016 * \internal
1017 * \brief Encode the ETSI AOCDChargingUnit invoke message.
1018 *
1019 * \param ctrl D channel controller for diagnostic messages or global options.
1020 * \param pos Starting position to encode the facility ie contents.
1021 * \param end End of facility ie contents encoding data buffer.
1022 * \param aoc_d the AOC-D data to encode.
1023 *
1024 * \retval Start of the next ASN.1 component to encode on success.
1025 * \retval NULL on error.
1026 */
enc_etsi_aocd_charging_unit(struct pri * ctrl,unsigned char * pos,unsigned char * end,const struct pri_subcmd_aoc_d * aoc_d)1027 static unsigned char *enc_etsi_aocd_charging_unit(struct pri *ctrl, unsigned char *pos,
1028 unsigned char *end, const struct pri_subcmd_aoc_d *aoc_d)
1029 {
1030 struct rose_msg_invoke msg;
1031
1032 pos = facility_encode_header(ctrl, pos, end, NULL);
1033 if (!pos) {
1034 return NULL;
1035 }
1036
1037 memset(&msg, 0, sizeof(msg));
1038 msg.operation = ROSE_ETSI_AOCDChargingUnit;
1039 msg.invoke_id = get_invokeid(ctrl);
1040
1041 if (aoc_d->charge == PRI_AOC_DE_CHARGE_FREE) {
1042 msg.args.etsi.AOCDChargingUnit.type = 1; /* free_of_charge */
1043 } else if ((aoc_d->charge == PRI_AOC_DE_CHARGE_UNITS) && (aoc_d->recorded.unit.num_items > 0)) {
1044 msg.args.etsi.AOCDChargingUnit.type = 2; /* specific_charging_units */
1045 aoc_enc_etsi_subcmd_recorded_units(&aoc_d->recorded.unit,
1046 &msg.args.etsi.AOCDChargingUnit.specific.recorded);
1047 } else {
1048 msg.args.etsi.AOCDChargingUnit.type = 0; /* charge_not_available */
1049 }
1050
1051 if (aoc_subcmd_aoc_d_etsi_billing_id(aoc_d->billing_id) != -1) {
1052 msg.args.etsi.AOCDChargingUnit.specific.billing_id_present = 1;
1053 msg.args.etsi.AOCDChargingUnit.specific.billing_id =
1054 aoc_subcmd_aoc_d_etsi_billing_id(aoc_d->billing_id);
1055 }
1056
1057 pos = rose_encode_invoke(ctrl, pos, end, &msg);
1058
1059 return pos;
1060 }
1061
1062 /*!
1063 * \internal
1064 * \brief Encode the ETSI AOCDCurrency invoke message.
1065 *
1066 * \param ctrl D channel controller for diagnostic messages or global options.
1067 * \param pos Starting position to encode the facility ie contents.
1068 * \param end End of facility ie contents encoding data buffer.
1069 * \param aoc_d the AOC-D data to encode.
1070 *
1071 * \retval Start of the next ASN.1 component to encode on success.
1072 * \retval NULL on error.
1073 */
enc_etsi_aocd_currency(struct pri * ctrl,unsigned char * pos,unsigned char * end,const struct pri_subcmd_aoc_d * aoc_d)1074 static unsigned char *enc_etsi_aocd_currency(struct pri *ctrl, unsigned char *pos,
1075 unsigned char *end, const struct pri_subcmd_aoc_d *aoc_d)
1076 {
1077 struct rose_msg_invoke msg;
1078
1079 pos = facility_encode_header(ctrl, pos, end, NULL);
1080 if (!pos) {
1081 return NULL;
1082 }
1083
1084 memset(&msg, 0, sizeof(msg));
1085 msg.operation = ROSE_ETSI_AOCDCurrency;
1086 msg.invoke_id = get_invokeid(ctrl);
1087
1088 if (aoc_d->charge == PRI_AOC_DE_CHARGE_FREE) {
1089 msg.args.etsi.AOCDCurrency.type = 1; /* free_of_charge */
1090 } else if ((aoc_d->charge == PRI_AOC_DE_CHARGE_CURRENCY) && (aoc_d->recorded.money.amount.cost >= 0)) {
1091 msg.args.etsi.AOCDCurrency.type = 2; /* specific_currency */
1092 aoc_enc_etsi_subcmd_recorded_currency(&aoc_d->recorded.money,
1093 &msg.args.etsi.AOCDCurrency.specific.recorded);
1094 } else {
1095 msg.args.etsi.AOCDCurrency.type = 0; /* charge_not_available */
1096 }
1097
1098 if (aoc_subcmd_aoc_d_etsi_billing_id(aoc_d->billing_id) != -1) {
1099 msg.args.etsi.AOCDCurrency.specific.billing_id_present = 1;
1100 msg.args.etsi.AOCDCurrency.specific.billing_id =
1101 aoc_subcmd_aoc_d_etsi_billing_id(aoc_d->billing_id);
1102 }
1103
1104 pos = rose_encode_invoke(ctrl, pos, end, &msg);
1105
1106 return pos;
1107 }
1108
1109 /*!
1110 * \internal
1111 * \brief Encode the ETSI AOCSSpecialArr invoke message.
1112 *
1113 * \param ctrl D channel controller for diagnostic messages or global options.
1114 * \param pos Starting position to encode the facility ie contents.
1115 * \param end End of facility ie contents encoding data buffer.
1116 * \param aoc_s the AOC-S data to encode.
1117 *
1118 * \retval Start of the next ASN.1 component to encode on success.
1119 * \retval NULL on error.
1120 */
enc_etsi_aocs_special_arrangement(struct pri * ctrl,unsigned char * pos,unsigned char * end,const struct pri_subcmd_aoc_s * aoc_s)1121 static unsigned char *enc_etsi_aocs_special_arrangement(struct pri *ctrl, unsigned char *pos,
1122 unsigned char *end, const struct pri_subcmd_aoc_s *aoc_s)
1123 {
1124 struct rose_msg_invoke msg;
1125
1126 pos = facility_encode_header(ctrl, pos, end, NULL);
1127 if (!pos) {
1128 return NULL;
1129 }
1130
1131 memset(&msg, 0, sizeof(msg));
1132 msg.operation = ROSE_ETSI_AOCSSpecialArr;
1133 msg.invoke_id = get_invokeid(ctrl);
1134
1135 if (!aoc_s->num_items || (aoc_s->item[0].rate_type != PRI_AOC_RATE_TYPE_SPECIAL_CODE)) {
1136 msg.args.etsi.AOCSSpecialArr.type = 0;/* charge_not_available */
1137 } else {
1138 msg.args.etsi.AOCSSpecialArr.type = 1;/* special_arrangement_info */
1139 msg.args.etsi.AOCSSpecialArr.special_arrangement = aoc_s->item[0].rate.special;
1140 }
1141
1142 pos = rose_encode_invoke(ctrl, pos, end, &msg);
1143
1144 return pos;
1145 }
1146
1147 /*!
1148 * \internal
1149 * \brief Encode the ETSI AOCSCurrency invoke message.
1150 *
1151 * \param ctrl D channel controller for diagnostic messages or global options.
1152 * \param pos Starting position to encode the facility ie contents.
1153 * \param end End of facility ie contents encoding data buffer.
1154 * \param aoc_s the AOC-S data to encode.
1155 *
1156 * \retval Start of the next ASN.1 component to encode on success.
1157 * \retval NULL on error.
1158 */
enc_etsi_aocs_currency(struct pri * ctrl,unsigned char * pos,unsigned char * end,const struct pri_subcmd_aoc_s * aoc_s)1159 static unsigned char *enc_etsi_aocs_currency(struct pri *ctrl, unsigned char *pos,
1160 unsigned char *end, const struct pri_subcmd_aoc_s *aoc_s)
1161 {
1162 struct rose_msg_invoke msg;
1163
1164 pos = facility_encode_header(ctrl, pos, end, NULL);
1165 if (!pos) {
1166 return NULL;
1167 }
1168
1169 memset(&msg, 0, sizeof(msg));
1170 msg.operation = ROSE_ETSI_AOCSCurrency;
1171 msg.invoke_id = get_invokeid(ctrl);
1172
1173 if (aoc_s->num_items) {
1174 msg.args.etsi.AOCSCurrency.type = 1; /* currency_info_list */
1175 enc_etsi_subcmd_aoc_s_currency_info(aoc_s, &msg.args.etsi.AOCSCurrency.currency_info);
1176 } else {
1177 msg.args.etsi.AOCSCurrency.type = 0; /* charge_not_available */
1178 }
1179
1180 pos = rose_encode_invoke(ctrl, pos, end, &msg);
1181
1182 return pos;
1183 }
1184
1185 /*!
1186 * \internal
1187 * \brief Encode the ETSI ChargingRequest Response message
1188 *
1189 * \param ctrl D channel controller for diagnostic messages or global options.
1190 * \param pos Starting position to encode the facility ie contents.
1191 * \param end End of facility ie contents encoding data buffer.
1192 * \param response the response to the request
1193 * \param invoke_id the request's invoke id
1194 * \param aoc_s the rate list associated with a response to AOC-S request
1195 * Could be NULL.
1196 *
1197 * \retval Start of the next ASN.1 component to encode on success.
1198 * \retval NULL on error.
1199 */
enc_etsi_aoc_request_response(struct pri * ctrl,unsigned char * pos,unsigned char * end,enum PRI_AOC_REQ_RSP response,int invoke_id,const struct pri_subcmd_aoc_s * aoc_s)1200 static unsigned char *enc_etsi_aoc_request_response(struct pri *ctrl, unsigned char *pos,
1201 unsigned char *end, enum PRI_AOC_REQ_RSP response, int invoke_id, const struct pri_subcmd_aoc_s *aoc_s)
1202 {
1203 struct rose_msg_result msg_result = { 0, };
1204 struct rose_msg_error msg_error = { 0, };
1205 int is_error = 0;
1206
1207 pos = facility_encode_header(ctrl, pos, end, NULL);
1208 if (!pos) {
1209 return NULL;
1210 }
1211
1212 switch (response) {
1213 case PRI_AOC_REQ_RSP_CURRENCY_INFO_LIST:
1214 if (!aoc_s) {
1215 return NULL;
1216 }
1217 enc_etsi_subcmd_aoc_s_currency_info(aoc_s, &msg_result.args.etsi.ChargingRequest.u.currency_info);
1218 msg_result.args.etsi.ChargingRequest.type = 0;/* currency_info_list */
1219 break;
1220 case PRI_AOC_REQ_RSP_SPECIAL_ARR:
1221 if (!aoc_s) {
1222 return NULL;
1223 }
1224 msg_result.args.etsi.ChargingRequest.type = 1;/* special_arrangement_info */
1225 msg_result.args.etsi.ChargingRequest.u.special_arrangement = aoc_s->item[0].rate.special;
1226 break;
1227 case PRI_AOC_REQ_RSP_CHARGING_INFO_FOLLOWS:
1228 msg_result.args.etsi.ChargingRequest.type = 2;/* charging_info_follows */
1229 break;
1230 case PRI_AOC_REQ_RSP_ERROR_NOT_IMPLEMENTED:
1231 msg_error.code = ROSE_ERROR_Gen_NotImplemented;
1232 is_error = 1;
1233 break;
1234 default:
1235 case PRI_AOC_REQ_RSP_ERROR_NOT_AVAILABLE:
1236 is_error = 1;
1237 msg_error.code = ROSE_ERROR_Gen_NotAvailable;
1238 break;
1239 }
1240
1241 if (is_error) {
1242 msg_error.invoke_id = invoke_id;
1243 pos = rose_encode_error(ctrl, pos, end, &msg_error);
1244 } else {
1245 msg_result.operation = ROSE_ETSI_ChargingRequest;
1246 msg_result.invoke_id = invoke_id;
1247 pos = rose_encode_result(ctrl, pos, end, &msg_result);
1248 }
1249
1250 return pos;
1251 }
1252
1253 /*!
1254 * \internal
1255 * \brief Encode the ETSI ChargingRequest invoke message.
1256 *
1257 * \param ctrl D channel controller for diagnostic messages or global options.
1258 * \param pos Starting position to encode the facility ie contents.
1259 * \param end End of facility ie contents encoding data buffer.
1260 * \param aoc_request the aoc charging request data to encode.
1261 *
1262 * \retval Start of the next ASN.1 component to encode on success.
1263 * \retval NULL on error.
1264 */
enc_etsi_aoc_request(struct pri * ctrl,unsigned char * pos,unsigned char * end,enum PRI_AOC_REQUEST request)1265 static unsigned char *enc_etsi_aoc_request(struct pri *ctrl, unsigned char *pos,
1266 unsigned char *end, enum PRI_AOC_REQUEST request)
1267 {
1268 struct rose_msg_invoke msg;
1269
1270 pos = facility_encode_header(ctrl, pos, end, NULL);
1271 if (!pos) {
1272 return NULL;
1273 }
1274
1275 memset(&msg, 0, sizeof(msg));
1276 msg.operation = ROSE_ETSI_ChargingRequest;
1277 msg.invoke_id = get_invokeid(ctrl);
1278
1279 switch (request) {
1280 case PRI_AOC_REQUEST_S:
1281 msg.args.etsi.ChargingRequest.charging_case = 0;/* chargingInformationAtCallSetup */
1282 break;
1283 case PRI_AOC_REQUEST_D:
1284 msg.args.etsi.ChargingRequest.charging_case = 1;/* chargingDuringACall */
1285 break;
1286 case PRI_AOC_REQUEST_E:
1287 msg.args.etsi.ChargingRequest.charging_case = 2;/* chargingAtTheEndOfACall */
1288 break;
1289 default:
1290 /* no valid request parameters are present */
1291 return NULL;
1292 }
1293
1294 pos = rose_encode_invoke(ctrl, pos, end, &msg);
1295
1296 return pos;
1297 }
1298
1299 /*!
1300 * \internal
1301 * \brief Send the ETSI AOC Request Response message for an AOC-S request
1302 *
1303 * \param ctrl D channel controller for diagnostic messages or global options.
1304 * \param call Call leg from which to encode AOC.
1305 * \param invoke_id the request's invoke id
1306 * \param aoc_s Optional AOC-S rate list for response
1307 *
1308 * \note if aoc_s is NULL, then a response will be sent back as AOC-S not available.
1309 *
1310 * \retval 0 on success.
1311 * \retval -1 on error.
1312 */
aoc_s_request_response_encode(struct pri * ctrl,q931_call * call,int invoke_id,const struct pri_subcmd_aoc_s * aoc_s)1313 static int aoc_s_request_response_encode(struct pri *ctrl, q931_call *call, int invoke_id, const struct pri_subcmd_aoc_s *aoc_s)
1314 {
1315 unsigned char buffer[255];
1316 unsigned char *end = NULL;
1317 int response;
1318
1319 if (!aoc_s) {
1320 response = PRI_AOC_REQ_RSP_ERROR_NOT_AVAILABLE;
1321 } else if (aoc_s->num_items
1322 && aoc_s->item[0].chargeable == PRI_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT) {
1323 response = PRI_AOC_REQ_RSP_SPECIAL_ARR;
1324 } else {
1325 response = PRI_AOC_REQ_RSP_CURRENCY_INFO_LIST;
1326 }
1327
1328 end = enc_etsi_aoc_request_response(ctrl, buffer, buffer + sizeof(buffer), response, invoke_id, aoc_s);
1329 if (!end) {
1330 return -1;
1331 }
1332
1333 /* Remember that if we queue a facility IE for a facility message we
1334 * have to explicitly send the facility message ourselves */
1335 if (pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL)
1336 || q931_facility(call->pri, call)) {
1337 pri_message(ctrl, "Could not schedule aoc request response facility message for call %d\n", call->cr);
1338 return -1;
1339 }
1340
1341 return 0;
1342 }
1343
1344 /*!
1345 * \internal
1346 * \brief Send the ETSI AOC Request Response message for AOC-D and AOC-E requests
1347 *
1348 * \param ctrl D channel controller for diagnostic messages or global options.
1349 * \param call Call leg from which to encode AOC.
1350 * \param response the response to the request
1351 * \param invoke_id the request's invoke id
1352 *
1353 * \retval 0 on success.
1354 * \retval -1 on error.
1355 */
aoc_de_request_response_encode(struct pri * ctrl,q931_call * call,enum PRI_AOC_REQ_RSP response,int invoke_id)1356 static int aoc_de_request_response_encode(struct pri *ctrl, q931_call *call, enum PRI_AOC_REQ_RSP response, int invoke_id)
1357 {
1358 unsigned char buffer[255];
1359 unsigned char *end = NULL;
1360
1361 end = enc_etsi_aoc_request_response(ctrl, buffer, buffer + sizeof(buffer), response, invoke_id, NULL);
1362 if (!end) {
1363 return -1;
1364 }
1365
1366 /* Remember that if we queue a facility IE for a facility message we
1367 * have to explicitly send the facility message ourselves */
1368 if (pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL)
1369 || q931_facility(call->pri, call)) {
1370 pri_message(ctrl, "Could not schedule aoc request response facility message for call %d\n", call->cr);
1371 return -1;
1372 }
1373
1374 return 0;
1375 }
1376
1377 /*!
1378 * \internal
1379 * \brief AOC-Request response callback function.
1380 *
1381 * \param reason Reason callback is called.
1382 * \param ctrl D channel controller.
1383 * \param call Q.931 call leg.
1384 * \param apdu APDU queued entry. Do not change!
1385 * \param msg APDU response message data. (NULL if was not the reason called.)
1386 *
1387 * \return TRUE if no more responses are expected.
1388 */
pri_aoc_request_get_response(enum APDU_CALLBACK_REASON reason,struct pri * ctrl,struct q931_call * call,struct apdu_event * apdu,const struct apdu_msg_data * msg)1389 static int pri_aoc_request_get_response(enum APDU_CALLBACK_REASON reason, struct pri *ctrl, struct q931_call *call, struct apdu_event *apdu, const struct apdu_msg_data *msg)
1390 {
1391 struct pri_subcommand *subcmd;
1392
1393 if ((reason == APDU_CALLBACK_REASON_ERROR) ||
1394 (reason == APDU_CALLBACK_REASON_CLEANUP)) {
1395 return 1;
1396 }
1397
1398 subcmd = q931_alloc_subcommand(ctrl);
1399 if (!subcmd) {
1400 return 1;
1401 }
1402
1403 memset(&subcmd->u.aoc_request_response, 0, sizeof(subcmd->u.aoc_request_response));
1404 subcmd->u.aoc_request_response.charging_request = apdu->response.user.value;
1405 subcmd->cmd = PRI_SUBCMD_AOC_CHARGING_REQ_RSP;
1406
1407 switch (reason) {
1408 case APDU_CALLBACK_REASON_MSG_ERROR:
1409 switch (msg->response.error->code) {
1410 case ROSE_ERROR_Gen_NotImplemented:
1411 subcmd->u.aoc_request_response.charging_response = PRI_AOC_REQ_RSP_ERROR_NOT_IMPLEMENTED;
1412 break;
1413 case ROSE_ERROR_Gen_NotAvailable:
1414 subcmd->u.aoc_request_response.charging_response = PRI_AOC_REQ_RSP_ERROR_NOT_AVAILABLE;
1415 break;
1416 default:
1417 subcmd->u.aoc_request_response.charging_response = PRI_AOC_REQ_RSP_ERROR;
1418 break;
1419 }
1420 break;
1421 case APDU_CALLBACK_REASON_MSG_REJECT:
1422 subcmd->u.aoc_request_response.charging_response = PRI_AOC_REQ_RSP_ERROR_REJECT;
1423 break;
1424 case APDU_CALLBACK_REASON_TIMEOUT:
1425 subcmd->u.aoc_request_response.charging_response = PRI_AOC_REQ_RSP_ERROR_TIMEOUT;
1426 break;
1427 case APDU_CALLBACK_REASON_MSG_RESULT:
1428 switch (msg->response.result->args.etsi.ChargingRequest.type) {
1429 case 0:/* currency_info_list */
1430 subcmd->u.aoc_request_response.valid_aoc_s = 1;
1431 subcmd->u.aoc_request_response.charging_response = PRI_AOC_REQ_RSP_CURRENCY_INFO_LIST;
1432 aoc_etsi_subcmd_aoc_s_currency_info(&subcmd->u.aoc_request_response.aoc_s,
1433 &msg->response.result->args.etsi.ChargingRequest.u.currency_info);
1434 break;
1435 case 1:/* special_arrangement_info */
1436 subcmd->u.aoc_request_response.valid_aoc_s = 1;
1437 subcmd->u.aoc_request_response.charging_response = PRI_AOC_REQ_RSP_SPECIAL_ARR;
1438 subcmd->u.aoc_request_response.aoc_s.num_items = 1;
1439 subcmd->u.aoc_request_response.aoc_s.item[0].chargeable = PRI_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT;
1440 subcmd->u.aoc_request_response.aoc_s.item[0].rate_type = PRI_AOC_RATE_TYPE_SPECIAL_CODE;
1441 subcmd->u.aoc_request_response.aoc_s.item[0].rate.special =
1442 msg->response.result->args.etsi.ChargingRequest.u.special_arrangement;
1443 break;
1444 case 2:/* charging_info_follows */
1445 subcmd->u.aoc_request_response.charging_response = PRI_AOC_REQ_RSP_CHARGING_INFO_FOLLOWS;
1446 break;
1447 default:
1448 subcmd->u.aoc_request_response.charging_response = PRI_AOC_REQ_RSP_ERROR;
1449 break;
1450 }
1451 break;
1452 default:
1453 subcmd->u.aoc_request_response.charging_response = PRI_AOC_REQ_RSP_ERROR;
1454 break;
1455 }
1456
1457 return 1;
1458 }
1459
1460 /*!
1461 * \internal
1462 * \brief Send the ETSI AOC Request invoke message.
1463 *
1464 * \param ctrl D channel controller for diagnostic messages or global options.
1465 * \param call Call leg from which to encode AOC.
1466 * \param aoc_request the aoc charging request payload data to encode.
1467 *
1468 * \retval 0 on success.
1469 * \retval -1 on error.
1470 */
aoc_charging_request_encode(struct pri * ctrl,q931_call * call,enum PRI_AOC_REQUEST request)1471 static int aoc_charging_request_encode(struct pri *ctrl, q931_call *call, enum PRI_AOC_REQUEST request)
1472 {
1473 unsigned char buffer[255];
1474 unsigned char *end = NULL;
1475 struct apdu_callback_data response;
1476
1477 end = enc_etsi_aoc_request(ctrl, buffer, buffer + sizeof(buffer), request);
1478 if (!end) {
1479 return -1;
1480 }
1481
1482 memset(&response, 0, sizeof(response));
1483 response.invoke_id = ctrl->last_invoke;
1484 response.timeout_time = APDU_TIMEOUT_MSGS_ONLY;
1485 response.num_messages = 1;
1486 response.message_type[0] = Q931_CONNECT;
1487 response.callback = pri_aoc_request_get_response;
1488 response.user.value = request;
1489
1490 /* in the case of an AOC request message, we queue this on a SETUP message and
1491 * do not have to send it ourselves in this function */
1492 return pri_call_apdu_queue(call, Q931_SETUP, buffer, end - buffer, &response);
1493 }
1494
1495 /*!
1496 * \internal
1497 * \brief Send the ETSI AOCS invoke message.
1498 *
1499 * \param ctrl D channel controller for diagnostic messages or global options.
1500 * \param call Call leg from which to encode AOC.
1501 * \param aoc_s the AOC-S payload data to encode.
1502 *
1503 * \retval 0 on success.
1504 * \retval -1 on error.
1505 */
aoc_s_encode(struct pri * ctrl,q931_call * call,const struct pri_subcmd_aoc_s * aoc_s)1506 static int aoc_s_encode(struct pri *ctrl, q931_call *call, const struct pri_subcmd_aoc_s *aoc_s)
1507 {
1508 unsigned char buffer[255];
1509 unsigned char *end = NULL;
1510
1511 if (aoc_s->item[0].chargeable == PRI_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT) {
1512 end = enc_etsi_aocs_special_arrangement(ctrl, buffer, buffer + sizeof(buffer), aoc_s);
1513 } else {
1514 end = enc_etsi_aocs_currency(ctrl, buffer, buffer + sizeof(buffer), aoc_s);
1515 }
1516 if (!end) {
1517 return -1;
1518 }
1519
1520 /* Remember that if we queue a facility IE for a facility message we
1521 * have to explicitly send the facility message ourselves */
1522 if (pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL)
1523 || q931_facility(call->pri, call)) {
1524 pri_message(ctrl, "Could not schedule aoc-s facility message for call %d\n", call->cr);
1525 return -1;
1526 }
1527
1528 return 0;
1529 }
1530
1531 /*!
1532 * \internal
1533 * \brief Send the ETSI AOCD invoke message.
1534 *
1535 * \param ctrl D channel controller for diagnostic messages or global options.
1536 * \param call Call leg from which to encode AOC.
1537 * \param aoc_d the AOC-D payload data to encode.
1538 *
1539 * \retval 0 on success.
1540 * \retval -1 on error.
1541 */
aoc_d_encode(struct pri * ctrl,q931_call * call,const struct pri_subcmd_aoc_d * aoc_d)1542 static int aoc_d_encode(struct pri *ctrl, q931_call *call, const struct pri_subcmd_aoc_d *aoc_d)
1543 {
1544 unsigned char buffer[255];
1545 unsigned char *end = NULL;
1546
1547 switch (aoc_d->charge) {
1548 case PRI_AOC_DE_CHARGE_NOT_AVAILABLE:
1549 case PRI_AOC_DE_CHARGE_FREE:
1550 case PRI_AOC_DE_CHARGE_CURRENCY:
1551 end = enc_etsi_aocd_currency(ctrl, buffer, buffer + sizeof(buffer), aoc_d);
1552 break;
1553 case PRI_AOC_DE_CHARGE_UNITS:
1554 end = enc_etsi_aocd_charging_unit(ctrl, buffer, buffer + sizeof(buffer), aoc_d);
1555 break;
1556 }
1557 if (!end) {
1558 return -1;
1559 }
1560
1561 /* Remember that if we queue a facility IE for a facility message we
1562 * have to explicitly send the facility message ourselves */
1563 if (pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL)
1564 || q931_facility(call->pri, call)) {
1565 pri_message(ctrl, "Could not schedule aoc-d facility message for call %d\n", call->cr);
1566 return -1;
1567 }
1568
1569 return 0;
1570 }
1571
1572 /*!
1573 * \internal
1574 * \brief Send the ETSI AOCE invoke message.
1575 *
1576 * \param ctrl D channel controller for diagnostic messages or global options.
1577 * \param call Call leg from which to encode AOC.
1578 * \param aoc_e the AOC-E payload data to encode.
1579 *
1580 * \retval 0 on success.
1581 * \retval -1 on error.
1582 */
aoc_e_encode(struct pri * ctrl,q931_call * call,const struct pri_subcmd_aoc_e * aoc_e)1583 static int aoc_e_encode(struct pri *ctrl, q931_call *call, const struct pri_subcmd_aoc_e *aoc_e)
1584 {
1585 unsigned char buffer[255];
1586 unsigned char *end = NULL;
1587
1588 switch (aoc_e->charge) {
1589 case PRI_AOC_DE_CHARGE_NOT_AVAILABLE:
1590 case PRI_AOC_DE_CHARGE_FREE:
1591 case PRI_AOC_DE_CHARGE_CURRENCY:
1592 end = enc_etsi_aoce_currency(ctrl, buffer, buffer + sizeof(buffer), aoc_e);
1593 break;
1594 case PRI_AOC_DE_CHARGE_UNITS:
1595 end = enc_etsi_aoce_charging_unit(ctrl, buffer, buffer + sizeof(buffer), aoc_e);
1596 break;
1597 }
1598 if (!end) {
1599 return -1;
1600 }
1601
1602 if (pri_call_apdu_queue(call, Q931_ANY_MESSAGE, buffer, end - buffer, NULL)) {
1603 pri_message(ctrl, "Could not schedule aoc-e facility message for call %d\n", call->cr);
1604 return -1;
1605 }
1606
1607 return 0;
1608 }
1609
pri_aoc_de_request_response_send(struct pri * ctrl,q931_call * call,int response,int invoke_id)1610 int pri_aoc_de_request_response_send(struct pri *ctrl, q931_call *call, int response, int invoke_id)
1611 {
1612 if (!ctrl || !pri_is_call_valid(ctrl, call)) {
1613 return -1;
1614 }
1615
1616 switch (ctrl->switchtype) {
1617 case PRI_SWITCH_EUROISDN_E1:
1618 case PRI_SWITCH_EUROISDN_T1:
1619 return aoc_de_request_response_encode(ctrl, call, response, invoke_id);
1620 case PRI_SWITCH_QSIG:
1621 break;
1622 default:
1623 return -1;
1624 }
1625
1626 return 0;
1627 }
1628
pri_aoc_s_request_response_send(struct pri * ctrl,q931_call * call,int invoke_id,const struct pri_subcmd_aoc_s * aoc_s)1629 int pri_aoc_s_request_response_send(struct pri *ctrl, q931_call *call, int invoke_id, const struct pri_subcmd_aoc_s *aoc_s)
1630 {
1631 if (!ctrl || !pri_is_call_valid(ctrl, call)) {
1632 return -1;
1633 }
1634
1635 switch (ctrl->switchtype) {
1636 case PRI_SWITCH_EUROISDN_E1:
1637 case PRI_SWITCH_EUROISDN_T1:
1638 return aoc_s_request_response_encode(ctrl, call, invoke_id, aoc_s);
1639 case PRI_SWITCH_QSIG:
1640 break;
1641 default:
1642 return -1;
1643 }
1644
1645 return 0;
1646 }
1647
1648 /*!
1649 * \brief Send AOC request message.
1650 *
1651 * \param ctrl D channel controller.
1652 * \param call Q.931 call leg.
1653 * \param aoc types to request
1654 *
1655 * \retval 0 on success
1656 * \retval -1 on failure
1657 */
aoc_charging_request_send(struct pri * ctrl,q931_call * call,enum PRI_AOC_REQUEST aoc_request_flag)1658 int aoc_charging_request_send(struct pri *ctrl, q931_call *call, enum PRI_AOC_REQUEST aoc_request_flag)
1659 {
1660 int res;
1661
1662 switch (ctrl->switchtype) {
1663 case PRI_SWITCH_EUROISDN_E1:
1664 case PRI_SWITCH_EUROISDN_T1:
1665 if (BRI_NT_PTMP(ctrl)) {
1666 /*
1667 * We are not setup to handle responses from multiple phones.
1668 * Besides, it is silly to ask for AOC from a phone.
1669 */
1670 return -1;
1671 }
1672 res = 0;
1673 if (aoc_request_flag & PRI_AOC_REQUEST_S) {
1674 res |= aoc_charging_request_encode(ctrl, call, PRI_AOC_REQUEST_S);
1675 }
1676 if (aoc_request_flag & PRI_AOC_REQUEST_D) {
1677 res |= aoc_charging_request_encode(ctrl, call, PRI_AOC_REQUEST_D);
1678 }
1679 if (aoc_request_flag & PRI_AOC_REQUEST_E) {
1680 res |= aoc_charging_request_encode(ctrl, call, PRI_AOC_REQUEST_E);
1681 }
1682 return res;
1683 case PRI_SWITCH_QSIG:
1684 break;
1685 default:
1686 return -1;
1687 }
1688
1689 return 0;
1690 }
1691
pri_aoc_s_send(struct pri * ctrl,q931_call * call,const struct pri_subcmd_aoc_s * aoc_s)1692 int pri_aoc_s_send(struct pri *ctrl, q931_call *call, const struct pri_subcmd_aoc_s *aoc_s)
1693 {
1694 if (!ctrl || !pri_is_call_valid(ctrl, call)) {
1695 return -1;
1696 }
1697
1698 switch (ctrl->switchtype) {
1699 case PRI_SWITCH_EUROISDN_E1:
1700 case PRI_SWITCH_EUROISDN_T1:
1701 return aoc_s_encode(ctrl, call, aoc_s);
1702 case PRI_SWITCH_QSIG:
1703 break;
1704 default:
1705 return -1;
1706 }
1707
1708 return 0;
1709 }
1710
pri_aoc_d_send(struct pri * ctrl,q931_call * call,const struct pri_subcmd_aoc_d * aoc_d)1711 int pri_aoc_d_send(struct pri *ctrl, q931_call *call, const struct pri_subcmd_aoc_d *aoc_d)
1712 {
1713 if (!ctrl || !pri_is_call_valid(ctrl, call)) {
1714 return -1;
1715 }
1716
1717 switch (ctrl->switchtype) {
1718 case PRI_SWITCH_EUROISDN_E1:
1719 case PRI_SWITCH_EUROISDN_T1:
1720 return aoc_d_encode(ctrl, call, aoc_d);
1721 case PRI_SWITCH_QSIG:
1722 break;
1723 default:
1724 return -1;
1725 }
1726 return 0;
1727 }
1728
pri_aoc_e_send(struct pri * ctrl,q931_call * call,const struct pri_subcmd_aoc_e * aoc_e)1729 int pri_aoc_e_send(struct pri *ctrl, q931_call *call, const struct pri_subcmd_aoc_e *aoc_e)
1730 {
1731 if (!ctrl || !pri_is_call_valid(ctrl, call)) {
1732 return -1;
1733 }
1734
1735 switch (ctrl->switchtype) {
1736 case PRI_SWITCH_EUROISDN_E1:
1737 case PRI_SWITCH_EUROISDN_T1:
1738 return aoc_e_encode(ctrl, call, aoc_e);
1739 case PRI_SWITCH_QSIG:
1740 break;
1741 default:
1742 return -1;
1743 }
1744
1745 return 0;
1746 }
1747
pri_sr_set_aoc_charging_request(struct pri_sr * sr,int charging_request)1748 int pri_sr_set_aoc_charging_request(struct pri_sr *sr, int charging_request)
1749 {
1750 if (charging_request & PRI_AOC_REQUEST_S) {
1751 sr->aoc_charging_request |= PRI_AOC_REQUEST_S;
1752 }
1753 if (charging_request & PRI_AOC_REQUEST_D) {
1754 sr->aoc_charging_request |= PRI_AOC_REQUEST_D;
1755 }
1756 if (charging_request & PRI_AOC_REQUEST_E) {
1757 sr->aoc_charging_request |= PRI_AOC_REQUEST_E;
1758 }
1759
1760 return 0;
1761 }
1762
1763 /* ------------------------------------------------------------------- */
1764 /* end pri_aoc.c */
1765