~ubuntu-branches/ubuntu/trusty/libpri/trusty

« back to all changes in this revision

Viewing changes to pri_aoc.c

  • Committer: Package Import Robot
  • Author(s): Faidon Liambotis
  • Date: 2011-11-26 17:25:59 UTC
  • mfrom: (1.3.11)
  • Revision ID: package-import@ubuntu.com-20111126172559-f6c5r81fgkn0krlb
Tags: 1.4.12-1
* New upstream release. 
  - Drop patch gcc-4.6-werror, not needed anymore.
  - Adapt patch enable-gcc-optimizations.
  - Updated symbols file with (a lot of) new symbols.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 */
 
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
 */
 
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
 */
 
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
 */
 
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
 */
 
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
 */
 
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
 */
 
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
 */
 
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
 */
 
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
 */
 
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
 */
 
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
 */
 
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
 */
 
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
 */
 
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
 */
 
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
 */
 
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
 */
 
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
 */
 
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
 */
 
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
 */
 
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
 */
 
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
 */
 
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
 
 
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
 */
 
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
 */
 
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
 */
 
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
 */
 
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
 */
 
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
 */
 
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
 */
 
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
 */
 
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
 */
 
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
 */
 
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
 */
 
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
 */
 
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
 */
 
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
 */
 
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
 */
 
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
 
 
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
 
 
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
 */
 
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
 
 
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
 
 
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
 
 
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
 
 
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 */