2
* libpri: An implementation of Primary Rate ISDN
4
* Copyright (C) 2010 Digium, Inc.
6
* Richard Mudgett <rmudgett@digium.com>
7
* David Vossel <dvossel@digium.com>
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.
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.
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
30
* \brief Advice Of Charge (AOC) facility support.
32
* \author Richard Mudgett <rmudgett@digium.com>
38
#include "pri_internal.h"
39
#include "pri_facility.h"
42
/* ------------------------------------------------------------------- */
46
* \brief Fill in the AOC subcmd amount from the ETSI amount.
48
* \param subcmd_amount AOC subcmd amount.
49
* \param etsi_amount AOC ETSI amount.
53
static void aoc_etsi_subcmd_amount(struct pri_aoc_amount *subcmd_amount, const struct roseEtsiAOCAmount *etsi_amount)
55
subcmd_amount->cost = etsi_amount->currency;
56
subcmd_amount->multiplier = etsi_amount->multiplier;
61
* \brief Fill in the ETSI amount from the AOC subcmd amount.
63
* \param subcmd_amount AOC subcmd amount.
64
* \param etsi_amount AOC ETSI amount.
68
static void aoc_enc_etsi_subcmd_amount(const struct pri_aoc_amount *subcmd_amount, struct roseEtsiAOCAmount *etsi_amount)
70
etsi_amount->currency = subcmd_amount->cost;
71
etsi_amount->multiplier = subcmd_amount->multiplier;
76
* \brief Fill in the AOC subcmd time from the ETSI time.
78
* \param subcmd_time AOC subcmd time.
79
* \param etsi_time AOC ETSI time.
83
static void aoc_etsi_subcmd_time(struct pri_aoc_time *subcmd_time, const struct roseEtsiAOCTime *etsi_time)
85
subcmd_time->length = etsi_time->length;
86
subcmd_time->scale = etsi_time->scale;
91
* \brief Fill in the ETSI Time from the AOC subcmd time.
93
* \param subcmd_time AOC subcmd time.
94
* \param etsi_time AOC ETSI time.
98
static void aoc_enc_etsi_subcmd_time(const struct pri_aoc_time *subcmd_time, struct roseEtsiAOCTime *etsi_time)
100
etsi_time->length = subcmd_time->length;
101
etsi_time->scale = subcmd_time->scale;
106
* \brief Fill in the AOC subcmd recorded currency from the ETSI recorded currency.
108
* \param subcmd_recorded AOC subcmd recorded currency.
109
* \param etsi_recorded AOC ETSI recorded currency.
113
static void aoc_etsi_subcmd_recorded_currency(struct pri_aoc_recorded_currency *subcmd_recorded, const struct roseEtsiAOCRecordedCurrency *etsi_recorded)
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));
122
* \brief Fill in the the ETSI recorded currency from the subcmd currency info
124
* \param subcmd_recorded AOC subcmd recorded currency.
125
* \param etsi_recorded AOC ETSI recorded currency.
129
static void aoc_enc_etsi_subcmd_recorded_currency(const struct pri_aoc_recorded_currency *subcmd_recorded, struct roseEtsiAOCRecordedCurrency *etsi_recorded)
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));
139
* \brief Fill in the AOC subcmd recorded units from the ETSI recorded units.
141
* \param subcmd_recorded AOC subcmd recorded units list.
142
* \param etsi_recorded AOC ETSI recorded units list.
146
static void aoc_etsi_subcmd_recorded_units(struct pri_aoc_recorded_units *subcmd_recorded, const struct roseEtsiAOCRecordedUnitsList *etsi_recorded)
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;
156
subcmd_recorded->item[idx].number = etsi_recorded->list[idx].number_of_units;
158
if (etsi_recorded->list[idx].type_of_unit_present) {
159
subcmd_recorded->item[idx].type = etsi_recorded->list[idx].type_of_unit;
161
subcmd_recorded->item[idx].type = -1;
164
subcmd_recorded->num_items = idx;
169
* \brief Fill in the ETSI recorded units from the AOC subcmd recorded units.
171
* \param subcmd_recorded AOC subcmd recorded units list.
172
* \param etsi_recorded AOC ETSI recorded units list.
176
static void aoc_enc_etsi_subcmd_recorded_units(const struct pri_aoc_recorded_units *subcmd_recorded, struct roseEtsiAOCRecordedUnitsList *etsi_recorded)
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;
185
etsi_recorded->list[i].not_available = 1;
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;
192
etsi_recorded->num_records = i;
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;
202
* \brief Handle the ETSI ChargingRequest.
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.
210
void aoc_etsi_aoc_request(struct pri *ctrl, q931_call *call, const struct rose_msg_invoke *invoke)
212
struct pri_subcommand *subcmd;
215
if (!ctrl->aoc_support) {
216
send_facility_error(ctrl, call, invoke->invoke_id, ROSE_ERROR_Gen_NotSubscribed);
219
switch (invoke->args.etsi.ChargingRequest.charging_case) {
220
case 0:/* chargingInformationAtCallSetup */
221
request = PRI_AOC_REQUEST_S;
223
case 1:/* chargingDuringACall */
224
request = PRI_AOC_REQUEST_D;
226
case 2:/* chargingAtTheEndOfACall */
227
request = PRI_AOC_REQUEST_E;
230
send_facility_error(ctrl, call, invoke->invoke_id, ROSE_ERROR_Gen_NotImplemented);
234
subcmd = q931_alloc_subcommand(ctrl);
236
send_facility_error(ctrl, call, invoke->invoke_id, ROSE_ERROR_Gen_NotAvailable);
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;
247
* \brief Fill in the AOC-S subcmd currency info list of chargeable items.
249
* \param aoc_s AOC-S info list of chargeable items.
250
* \param info ETSI info list of chargeable items.
254
static void aoc_etsi_subcmd_aoc_s_currency_info(struct pri_subcmd_aoc_s *aoc_s, const struct roseEtsiAOCSCurrencyInfoList *info)
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;
265
case 1:/* callAttempt */
266
aoc_s->item[idx].chargeable = PRI_AOC_CHARGED_ITEM_CALL_ATTEMPT;
268
case 2:/* callSetup */
269
aoc_s->item[idx].chargeable = PRI_AOC_CHARGED_ITEM_CALL_SETUP;
271
case 3:/* userToUserInfo */
272
aoc_s->item[idx].chargeable = PRI_AOC_CHARGED_ITEM_USER_USER_INFO;
274
case 4:/* operationOfSupplementaryServ */
275
aoc_s->item[idx].chargeable = PRI_AOC_CHARGED_ITEM_SUPPLEMENTARY_SERVICE;
278
aoc_s->item[idx].chargeable = PRI_AOC_CHARGED_ITEM_NOT_AVAILABLE;
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;
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);
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;
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));
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));
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));
325
case 4:/* freeOfCharge */
326
aoc_s->item[idx].rate_type = PRI_AOC_RATE_TYPE_FREE;
329
case 5:/* currencyInfoNotAvailable */
330
aoc_s->item[idx].rate_type = PRI_AOC_RATE_TYPE_NOT_AVAILABLE;
334
aoc_s->num_items = idx;
339
* \brief Fill in the currency info list of chargeable items from a aoc_s subcmd
341
* \param aoc_s AOC-S info list of chargeable items.
342
* \param info ETSI info list of chargeable items.
346
static void enc_etsi_subcmd_aoc_s_currency_info(const struct pri_subcmd_aoc_s *aoc_s, struct roseEtsiAOCSCurrencyInfoList *info)
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) {
354
case PRI_AOC_CHARGED_ITEM_BASIC_COMMUNICATION:
355
info->list[idx].charged_item = 0;/* basicCommunication */
357
case PRI_AOC_CHARGED_ITEM_CALL_ATTEMPT:
358
info->list[idx].charged_item = 1;/* callAttempt */
360
case PRI_AOC_CHARGED_ITEM_CALL_SETUP:
361
info->list[idx].charged_item = 2;/* callSetup */
363
case PRI_AOC_CHARGED_ITEM_USER_USER_INFO:
364
info->list[idx].charged_item = 3;/* userToUserInfo */
366
case PRI_AOC_CHARGED_ITEM_SUPPLEMENTARY_SERVICE:
367
info->list[idx].charged_item = 4;/* operationOfSupplementaryServ */
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;
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);
388
info->list[idx].u.duration.granularity_present = 0;
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));
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));
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));
412
case PRI_AOC_RATE_TYPE_FREE:
413
info->list[idx].currency_type = 4;/* freeOfCharge */
416
case PRI_AOC_RATE_TYPE_NOT_AVAILABLE:
417
info->list[idx].currency_type = 5;/* currencyInfoNotAvailable */
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 */
427
info->num_records = idx;
431
* \brief Handle the ETSI AOCSCurrency message.
433
* \param ctrl D channel controller for diagnostic messages or global options.
434
* \param invoke Decoded ROSE invoke message contents.
438
void aoc_etsi_aoc_s_currency(struct pri *ctrl, const struct rose_msg_invoke *invoke)
440
struct pri_subcommand *subcmd;
442
if (!ctrl->aoc_support) {
445
subcmd = q931_alloc_subcommand(ctrl);
450
subcmd->cmd = PRI_SUBCMD_AOC_S;
451
if (!invoke->args.etsi.AOCSCurrency.type) {
452
subcmd->u.aoc_s.num_items = 0;
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);
462
* \brief Handle the ETSI AOCSSpecialArr message.
464
* \param ctrl D channel controller for diagnostic messages or global options.
465
* \param invoke Decoded ROSE invoke message contents.
469
void aoc_etsi_aoc_s_special_arrangement(struct pri *ctrl, const struct rose_msg_invoke *invoke)
471
struct pri_subcommand *subcmd;
473
if (!ctrl->aoc_support) {
476
subcmd = q931_alloc_subcommand(ctrl);
480
subcmd->cmd = PRI_SUBCMD_AOC_S;
481
if (!invoke->args.etsi.AOCSSpecialArr.type) {
482
subcmd->u.aoc_s.num_items = 0;
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;
494
* \brief Determine the AOC-D subcmd billing_id value.
496
* \param billing_id_present TRUE if billing_id valid.
497
* \param billing_id ETSI billing id from ROSE.
499
* \return enum PRI_AOC_D_BILLING_ID value
501
static enum PRI_AOC_D_BILLING_ID aoc_etsi_subcmd_aoc_d_billing_id(int billing_id_present, int billing_id)
503
enum PRI_AOC_D_BILLING_ID value;
505
if (billing_id_present) {
506
switch (billing_id) {
507
case 0:/* normalCharging */
508
value = PRI_AOC_D_BILLING_ID_NORMAL;
510
case 1:/* reverseCharging */
511
value = PRI_AOC_D_BILLING_ID_REVERSE;
513
case 2:/* creditCardCharging */
514
value = PRI_AOC_D_BILLING_ID_CREDIT_CARD;
517
value = PRI_AOC_D_BILLING_ID_NOT_AVAILABLE;
521
value = PRI_AOC_D_BILLING_ID_NOT_AVAILABLE;
527
* \brief Handle the ETSI AOCDCurrency message.
529
* \param ctrl D channel controller for diagnostic messages or global options.
530
* \param invoke Decoded ROSE invoke message contents.
534
void aoc_etsi_aoc_d_currency(struct pri *ctrl, const struct rose_msg_invoke *invoke)
536
struct pri_subcommand *subcmd;
538
if (!ctrl->aoc_support) {
541
subcmd = q931_alloc_subcommand(ctrl);
546
subcmd->cmd = PRI_SUBCMD_AOC_D;
547
switch (invoke->args.etsi.AOCDCurrency.type) {
549
case 0:/* charge_not_available */
550
subcmd->u.aoc_d.charge = PRI_AOC_DE_CHARGE_NOT_AVAILABLE;
552
case 1:/* free_of_charge */
553
subcmd->u.aoc_d.charge = PRI_AOC_DE_CHARGE_FREE;
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);
569
* \brief Handle the ETSI AOCDChargingUnit message.
571
* \param ctrl D channel controller for diagnostic messages or global options.
572
* \param invoke Decoded ROSE invoke message contents.
576
void aoc_etsi_aoc_d_charging_unit(struct pri *ctrl, const struct rose_msg_invoke *invoke)
578
struct pri_subcommand *subcmd;
580
if (!ctrl->aoc_support) {
583
subcmd = q931_alloc_subcommand(ctrl);
588
subcmd->cmd = PRI_SUBCMD_AOC_D;
589
switch (invoke->args.etsi.AOCDChargingUnit.type) {
591
case 0:/* charge_not_available */
592
subcmd->u.aoc_d.charge = PRI_AOC_DE_CHARGE_NOT_AVAILABLE;
594
case 1:/* free_of_charge */
595
subcmd->u.aoc_d.charge = PRI_AOC_DE_CHARGE_FREE;
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);
612
* \brief Fill in the AOC-E subcmd charging association from the ETSI charging association.
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.
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)
622
struct q931_party_number q931_number;
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;
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);
636
subcmd_association->charging_type = PRI_AOC_E_CHARGING_ASSOCIATION_NOT_AVAILABLE;
643
* \brief Determine the AOC-E subcmd billing_id value.
645
* \param billing_id_present TRUE if billing_id valid.
646
* \param billing_id ETSI billing id from ROSE.
648
* \return enum PRI_AOC_E_BILLING_ID value
650
static enum PRI_AOC_E_BILLING_ID aoc_etsi_subcmd_aoc_e_billing_id(int billing_id_present, int billing_id)
652
enum PRI_AOC_E_BILLING_ID value;
654
if (billing_id_present) {
655
switch (billing_id) {
656
case 0:/* normalCharging */
657
value = PRI_AOC_E_BILLING_ID_NORMAL;
659
case 1:/* reverseCharging */
660
value = PRI_AOC_E_BILLING_ID_REVERSE;
662
case 2:/* creditCardCharging */
663
value = PRI_AOC_E_BILLING_ID_CREDIT_CARD;
665
case 3:/* callForwardingUnconditional */
666
value = PRI_AOC_E_BILLING_ID_CALL_FORWARDING_UNCONDITIONAL;
668
case 4:/* callForwardingBusy */
669
value = PRI_AOC_E_BILLING_ID_CALL_FORWARDING_BUSY;
671
case 5:/* callForwardingNoReply */
672
value = PRI_AOC_E_BILLING_ID_CALL_FORWARDING_NO_REPLY;
674
case 6:/* callDeflection */
675
value = PRI_AOC_E_BILLING_ID_CALL_DEFLECTION;
677
case 7:/* callTransfer */
678
value = PRI_AOC_E_BILLING_ID_CALL_TRANSFER;
681
value = PRI_AOC_E_BILLING_ID_NOT_AVAILABLE;
685
value = PRI_AOC_E_BILLING_ID_NOT_AVAILABLE;
692
* \brief Determine the ETSI AOC-E billing_id value from the subcmd.
694
* \param billing_id from upper layer.
697
* \retval etsi billing id
699
static int aoc_subcmd_aoc_e_etsi_billing_id(enum PRI_AOC_E_BILLING_ID billing_id)
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:
727
* \brief Determine the ETSI AOC-D billing_id value from the subcmd.
729
* \param billing_id from upper layer.
732
* \retval etsi billing id
734
static int aoc_subcmd_aoc_d_etsi_billing_id(enum PRI_AOC_D_BILLING_ID billing_id)
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:
751
* \brief Handle the ETSI AOCECurrency message.
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.
759
void aoc_etsi_aoc_e_currency(struct pri *ctrl, q931_call *call, const struct rose_msg_invoke *invoke)
761
struct pri_subcommand *subcmd;
763
if (!ctrl->aoc_support) {
766
subcmd = q931_alloc_subcommand(ctrl);
771
subcmd->cmd = PRI_SUBCMD_AOC_E;
772
subcmd->u.aoc_e.associated.charging_type =
773
PRI_AOC_E_CHARGING_ASSOCIATION_NOT_AVAILABLE;
775
if (!invoke->args.etsi.AOCECurrency.type) {
776
subcmd->u.aoc_e.charge = PRI_AOC_DE_CHARGE_NOT_AVAILABLE;
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);
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;
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);
802
* \brief Handle the ETSI AOCEChargingUnit message.
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.
810
void aoc_etsi_aoc_e_charging_unit(struct pri *ctrl, q931_call *call, const struct rose_msg_invoke *invoke)
812
struct pri_subcommand *subcmd;
815
/* Fill in legacy stuff. */
817
if (invoke->args.etsi.AOCEChargingUnit.type == 1
818
&& !invoke->args.etsi.AOCEChargingUnit.charging_unit.free_of_charge) {
820
invoke->args.etsi.AOCEChargingUnit.charging_unit.specific.recorded.num_records;
822
if (!invoke->args.etsi.AOCEChargingUnit.charging_unit.specific.recorded.
823
list[idx].not_available) {
825
invoke->args.etsi.AOCEChargingUnit.charging_unit.specific.
826
recorded.list[idx].number_of_units;
831
if (!ctrl->aoc_support) {
834
subcmd = q931_alloc_subcommand(ctrl);
839
subcmd->cmd = PRI_SUBCMD_AOC_E;
840
subcmd->u.aoc_e.associated.charging_type =
841
PRI_AOC_E_CHARGING_ASSOCIATION_NOT_AVAILABLE;
843
if (!invoke->args.etsi.AOCEChargingUnit.type) {
844
subcmd->u.aoc_e.charge = PRI_AOC_DE_CHARGE_NOT_AVAILABLE;
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);
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;
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);
869
void pri_aoc_events_enable(struct pri *ctrl, int enable)
872
ctrl->aoc_support = enable ? 1 : 0;
878
* \brief Encode the ETSI AOCECurrency invoke message.
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.
885
* \retval Start of the next ASN.1 component to encode on success.
886
* \retval NULL on error.
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)
891
struct rose_msg_invoke msg;
892
struct q931_party_number q931_number;
894
pos = facility_encode_header(ctrl, pos, end, NULL);
899
memset(&msg, 0, sizeof(msg));
900
msg.operation = ROSE_ETSI_AOCECurrency;
901
msg.invoke_id = get_invokeid(ctrl);
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);
911
msg.args.etsi.AOCECurrency.type = 0; /* charge_not_available */
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);
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,
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;
940
pos = rose_encode_invoke(ctrl, pos, end, &msg);
947
* \brief Encode the ETSI AOCEChargingUnit invoke message.
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.
954
* \retval Start of the next ASN.1 component to encode on success.
955
* \retval NULL on error.
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)
960
struct rose_msg_invoke msg;
961
struct q931_party_number q931_number;
963
pos = facility_encode_header(ctrl, pos, end, NULL);
968
memset(&msg, 0, sizeof(msg));
969
msg.operation = ROSE_ETSI_AOCEChargingUnit;
970
msg.invoke_id = get_invokeid(ctrl);
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;
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);
981
msg.args.etsi.AOCEChargingUnit.type = 0; /* charge_not_available */
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);
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,
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;
1010
pos = rose_encode_invoke(ctrl, pos, end, &msg);
1017
* \brief Encode the ETSI AOCDChargingUnit invoke message.
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.
1024
* \retval Start of the next ASN.1 component to encode on success.
1025
* \retval NULL on error.
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)
1030
struct rose_msg_invoke msg;
1032
pos = facility_encode_header(ctrl, pos, end, NULL);
1037
memset(&msg, 0, sizeof(msg));
1038
msg.operation = ROSE_ETSI_AOCDChargingUnit;
1039
msg.invoke_id = get_invokeid(ctrl);
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);
1048
msg.args.etsi.AOCDChargingUnit.type = 0; /* charge_not_available */
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);
1057
pos = rose_encode_invoke(ctrl, pos, end, &msg);
1064
* \brief Encode the ETSI AOCDCurrency invoke message.
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.
1071
* \retval Start of the next ASN.1 component to encode on success.
1072
* \retval NULL on error.
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)
1077
struct rose_msg_invoke msg;
1079
pos = facility_encode_header(ctrl, pos, end, NULL);
1084
memset(&msg, 0, sizeof(msg));
1085
msg.operation = ROSE_ETSI_AOCDCurrency;
1086
msg.invoke_id = get_invokeid(ctrl);
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);
1095
msg.args.etsi.AOCDCurrency.type = 0; /* charge_not_available */
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);
1104
pos = rose_encode_invoke(ctrl, pos, end, &msg);
1111
* \brief Encode the ETSI AOCSSpecialArr invoke message.
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.
1118
* \retval Start of the next ASN.1 component to encode on success.
1119
* \retval NULL on error.
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)
1124
struct rose_msg_invoke msg;
1126
pos = facility_encode_header(ctrl, pos, end, NULL);
1131
memset(&msg, 0, sizeof(msg));
1132
msg.operation = ROSE_ETSI_AOCSSpecialArr;
1133
msg.invoke_id = get_invokeid(ctrl);
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 */
1138
msg.args.etsi.AOCSSpecialArr.type = 1;/* special_arrangement_info */
1139
msg.args.etsi.AOCSSpecialArr.special_arrangement = aoc_s->item[0].rate.special;
1142
pos = rose_encode_invoke(ctrl, pos, end, &msg);
1149
* \brief Encode the ETSI AOCSCurrency invoke message.
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.
1156
* \retval Start of the next ASN.1 component to encode on success.
1157
* \retval NULL on error.
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)
1162
struct rose_msg_invoke msg;
1164
pos = facility_encode_header(ctrl, pos, end, NULL);
1169
memset(&msg, 0, sizeof(msg));
1170
msg.operation = ROSE_ETSI_AOCSCurrency;
1171
msg.invoke_id = get_invokeid(ctrl);
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);
1177
msg.args.etsi.AOCSCurrency.type = 0; /* charge_not_available */
1180
pos = rose_encode_invoke(ctrl, pos, end, &msg);
1187
* \brief Encode the ETSI ChargingRequest Response message
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
1197
* \retval Start of the next ASN.1 component to encode on success.
1198
* \retval NULL on error.
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)
1203
struct rose_msg_result msg_result = { 0, };
1204
struct rose_msg_error msg_error = { 0, };
1207
pos = facility_encode_header(ctrl, pos, end, NULL);
1213
case PRI_AOC_REQ_RSP_CURRENCY_INFO_LIST:
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 */
1220
case PRI_AOC_REQ_RSP_SPECIAL_ARR:
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;
1227
case PRI_AOC_REQ_RSP_CHARGING_INFO_FOLLOWS:
1228
msg_result.args.etsi.ChargingRequest.type = 2;/* charging_info_follows */
1230
case PRI_AOC_REQ_RSP_ERROR_NOT_IMPLEMENTED:
1231
msg_error.code = ROSE_ERROR_Gen_NotImplemented;
1235
case PRI_AOC_REQ_RSP_ERROR_NOT_AVAILABLE:
1237
msg_error.code = ROSE_ERROR_Gen_NotAvailable;
1242
msg_error.invoke_id = invoke_id;
1243
pos = rose_encode_error(ctrl, pos, end, &msg_error);
1245
msg_result.operation = ROSE_ETSI_ChargingRequest;
1246
msg_result.invoke_id = invoke_id;
1247
pos = rose_encode_result(ctrl, pos, end, &msg_result);
1255
* \brief Encode the ETSI ChargingRequest invoke message.
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.
1262
* \retval Start of the next ASN.1 component to encode on success.
1263
* \retval NULL on error.
1265
static unsigned char *enc_etsi_aoc_request(struct pri *ctrl, unsigned char *pos,
1266
unsigned char *end, enum PRI_AOC_REQUEST request)
1268
struct rose_msg_invoke msg;
1270
pos = facility_encode_header(ctrl, pos, end, NULL);
1275
memset(&msg, 0, sizeof(msg));
1276
msg.operation = ROSE_ETSI_ChargingRequest;
1277
msg.invoke_id = get_invokeid(ctrl);
1280
case PRI_AOC_REQUEST_S:
1281
msg.args.etsi.ChargingRequest.charging_case = 0;/* chargingInformationAtCallSetup */
1283
case PRI_AOC_REQUEST_D:
1284
msg.args.etsi.ChargingRequest.charging_case = 1;/* chargingDuringACall */
1286
case PRI_AOC_REQUEST_E:
1287
msg.args.etsi.ChargingRequest.charging_case = 2;/* chargingAtTheEndOfACall */
1290
/* no valid request parameters are present */
1294
pos = rose_encode_invoke(ctrl, pos, end, &msg);
1301
* \brief Send the ETSI AOC Request Response message for an AOC-S request
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
1308
* \note if aoc_s is NULL, then a response will be sent back as AOC-S not available.
1310
* \retval 0 on success.
1311
* \retval -1 on error.
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)
1315
unsigned char buffer[255];
1316
unsigned char *end = NULL;
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;
1325
response = PRI_AOC_REQ_RSP_CURRENCY_INFO_LIST;
1328
end = enc_etsi_aoc_request_response(ctrl, buffer, buffer + sizeof(buffer), response, invoke_id, aoc_s);
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);
1346
* \brief Send the ETSI AOC Request Response message for AOC-D and AOC-E requests
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
1353
* \retval 0 on success.
1354
* \retval -1 on error.
1356
static int aoc_de_request_response_encode(struct pri *ctrl, q931_call *call, enum PRI_AOC_REQ_RSP response, int invoke_id)
1358
unsigned char buffer[255];
1359
unsigned char *end = NULL;
1361
end = enc_etsi_aoc_request_response(ctrl, buffer, buffer + sizeof(buffer), response, invoke_id, NULL);
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);
1379
* \brief AOC-Request response callback function.
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.)
1387
* \return TRUE if no more responses are expected.
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)
1391
struct pri_subcommand *subcmd;
1393
if ((reason == APDU_CALLBACK_REASON_ERROR) ||
1394
(reason == APDU_CALLBACK_REASON_CLEANUP)) {
1398
subcmd = q931_alloc_subcommand(ctrl);
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;
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;
1413
case ROSE_ERROR_Gen_NotAvailable:
1414
subcmd->u.aoc_request_response.charging_response = PRI_AOC_REQ_RSP_ERROR_NOT_AVAILABLE;
1417
subcmd->u.aoc_request_response.charging_response = PRI_AOC_REQ_RSP_ERROR;
1421
case APDU_CALLBACK_REASON_MSG_REJECT:
1422
subcmd->u.aoc_request_response.charging_response = PRI_AOC_REQ_RSP_ERROR_REJECT;
1424
case APDU_CALLBACK_REASON_TIMEOUT:
1425
subcmd->u.aoc_request_response.charging_response = PRI_AOC_REQ_RSP_ERROR_TIMEOUT;
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);
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;
1444
case 2:/* charging_info_follows */
1445
subcmd->u.aoc_request_response.charging_response = PRI_AOC_REQ_RSP_CHARGING_INFO_FOLLOWS;
1448
subcmd->u.aoc_request_response.charging_response = PRI_AOC_REQ_RSP_ERROR;
1453
subcmd->u.aoc_request_response.charging_response = PRI_AOC_REQ_RSP_ERROR;
1462
* \brief Send the ETSI AOC Request invoke message.
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.
1468
* \retval 0 on success.
1469
* \retval -1 on error.
1471
static int aoc_charging_request_encode(struct pri *ctrl, q931_call *call, enum PRI_AOC_REQUEST request)
1473
unsigned char buffer[255];
1474
unsigned char *end = NULL;
1475
struct apdu_callback_data response;
1477
end = enc_etsi_aoc_request(ctrl, buffer, buffer + sizeof(buffer), request);
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;
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);
1497
* \brief Send the ETSI AOCS invoke message.
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.
1503
* \retval 0 on success.
1504
* \retval -1 on error.
1506
static int aoc_s_encode(struct pri *ctrl, q931_call *call, const struct pri_subcmd_aoc_s *aoc_s)
1508
unsigned char buffer[255];
1509
unsigned char *end = NULL;
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);
1514
end = enc_etsi_aocs_currency(ctrl, buffer, buffer + sizeof(buffer), aoc_s);
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);
1533
* \brief Send the ETSI AOCD invoke message.
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.
1539
* \retval 0 on success.
1540
* \retval -1 on error.
1542
static int aoc_d_encode(struct pri *ctrl, q931_call *call, const struct pri_subcmd_aoc_d *aoc_d)
1544
unsigned char buffer[255];
1545
unsigned char *end = NULL;
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);
1553
case PRI_AOC_DE_CHARGE_UNITS:
1554
end = enc_etsi_aocd_charging_unit(ctrl, buffer, buffer + sizeof(buffer), aoc_d);
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);
1574
* \brief Send the ETSI AOCE invoke message.
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.
1580
* \retval 0 on success.
1581
* \retval -1 on error.
1583
static int aoc_e_encode(struct pri *ctrl, q931_call *call, const struct pri_subcmd_aoc_e *aoc_e)
1585
unsigned char buffer[255];
1586
unsigned char *end = NULL;
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);
1594
case PRI_AOC_DE_CHARGE_UNITS:
1595
end = enc_etsi_aoce_charging_unit(ctrl, buffer, buffer + sizeof(buffer), aoc_e);
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);
1610
int pri_aoc_de_request_response_send(struct pri *ctrl, q931_call *call, int response, int invoke_id)
1612
if (!ctrl || !pri_is_call_valid(ctrl, call)) {
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:
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)
1631
if (!ctrl || !pri_is_call_valid(ctrl, call)) {
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:
1649
* \brief Send AOC request message.
1651
* \param ctrl D channel controller.
1652
* \param call Q.931 call leg.
1653
* \param aoc types to request
1655
* \retval 0 on success
1656
* \retval -1 on failure
1658
int aoc_charging_request_send(struct pri *ctrl, q931_call *call, enum PRI_AOC_REQUEST aoc_request_flag)
1662
switch (ctrl->switchtype) {
1663
case PRI_SWITCH_EUROISDN_E1:
1664
case PRI_SWITCH_EUROISDN_T1:
1665
if (BRI_NT_PTMP(ctrl)) {
1667
* We are not setup to handle responses from multiple phones.
1668
* Besides, it is silly to ask for AOC from a phone.
1673
if (aoc_request_flag & PRI_AOC_REQUEST_S) {
1674
res |= aoc_charging_request_encode(ctrl, call, PRI_AOC_REQUEST_S);
1676
if (aoc_request_flag & PRI_AOC_REQUEST_D) {
1677
res |= aoc_charging_request_encode(ctrl, call, PRI_AOC_REQUEST_D);
1679
if (aoc_request_flag & PRI_AOC_REQUEST_E) {
1680
res |= aoc_charging_request_encode(ctrl, call, PRI_AOC_REQUEST_E);
1683
case PRI_SWITCH_QSIG:
1692
int pri_aoc_s_send(struct pri *ctrl, q931_call *call, const struct pri_subcmd_aoc_s *aoc_s)
1694
if (!ctrl || !pri_is_call_valid(ctrl, call)) {
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:
1711
int pri_aoc_d_send(struct pri *ctrl, q931_call *call, const struct pri_subcmd_aoc_d *aoc_d)
1713
if (!ctrl || !pri_is_call_valid(ctrl, call)) {
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:
1729
int pri_aoc_e_send(struct pri *ctrl, q931_call *call, const struct pri_subcmd_aoc_e *aoc_e)
1731
if (!ctrl || !pri_is_call_valid(ctrl, call)) {
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:
1748
int pri_sr_set_aoc_charging_request(struct pri_sr *sr, int charging_request)
1750
if (charging_request & PRI_AOC_REQUEST_S) {
1751
sr->aoc_charging_request |= PRI_AOC_REQUEST_S;
1753
if (charging_request & PRI_AOC_REQUEST_D) {
1754
sr->aoc_charging_request |= PRI_AOC_REQUEST_D;
1756
if (charging_request & PRI_AOC_REQUEST_E) {
1757
sr->aoc_charging_request |= PRI_AOC_REQUEST_E;
1763
/* ------------------------------------------------------------------- */