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