/* * Copyright (c) 1997, 2000 Hellmuth Michaelis. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * *--------------------------------------------------------------------------- * * i4b_q932fac.c - Q932 facility handling * -------------------------------------- * * $Id: i4b_q932fac.c,v 1.5 2005/12/11 12:25:06 christos Exp $ * * $FreeBSD$ * * last edit-date: [Fri Jan 5 11:33:47 2001] * *---------------------------------------------------------------------------*/ #include __KERNEL_RCSID(0, "$NetBSD: i4b_q932fac.c,v 1.5 2005/12/11 12:25:06 christos Exp $"); #ifdef __FreeBSD__ #include "i4bq931.h" #else #define NI4BQ931 1 #endif #if NI4BQ931 > 0 #include #include #include #include #include #include #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000 #include #endif #ifdef __FreeBSD__ #include #include #else #include #include #endif #include #include #include #include #include #include #include #include static int do_component(int length); static void next_state(int class, int form, int code, int val); static int byte_len; static unsigned char *byte_buf; static int state; static int units; static int operation_value; /*---------------------------------------------------------------------------* * decode Q.931/Q.932 facility info element *---------------------------------------------------------------------------*/ int i4b_aoc(unsigned char *buf, call_desc_t *cd) { int len; cd->units_type = CHARGE_INVALID; cd->units = -1; buf++; /* length */ len = *buf; buf++; /* protocol profile */ switch(*buf & 0x1f) { case FAC_PROTO_ROP: break; case FAC_PROTO_CMIP: NDBGL3(L3_A_MSG, "CMIP Protocol (Q.941), UNSUPPORTED"); return(-1); break; case FAC_PROTO_ACSE: NDBGL3(L3_A_MSG, "ACSE Protocol (X.217/X.227), UNSUPPORTED!"); return(-1); break; default: NDBGL3(L3_A_ERR, "Unknown Protocol, UNSUPPORTED!"); return(-1); break; } NDBGL3(L3_A_MSG, "Remote Operations Protocol"); /* next byte */ buf++; len--; /* initialize variables for do_component */ byte_len = 0; byte_buf = buf; state = ST_EXP_COMP_TYP; /* decode facility */ do_component(len); switch(operation_value) { case FAC_OPVAL_AOC_D_CUR: cd->units_type = CHARGE_AOCD; cd->units = 0; return(0); break; case FAC_OPVAL_AOC_D_UNIT: cd->units_type = CHARGE_AOCD; cd->units = units; return(0); break; case FAC_OPVAL_AOC_E_CUR: cd->units_type = CHARGE_AOCE; cd->units = 0; return(0); break; case FAC_OPVAL_AOC_E_UNIT: cd->units_type = CHARGE_AOCE; cd->units = units; return(0); break; default: cd->units_type = CHARGE_INVALID; cd->units = -1; return(-1); break; } return(-1); } /*---------------------------------------------------------------------------* * handle a component recursively *---------------------------------------------------------------------------*/ static int do_component(int length) { int comp_tag_class; /* component tag class */ int comp_tag_form; /* component form: constructor or primitive */ int comp_tag_code; /* component code depending on class */ int comp_length = 0; /* component length */ again: /*----------------------------------------*/ /* first component element: component tag */ /*----------------------------------------*/ /* tag class bits */ comp_tag_class = (*byte_buf & 0xc0) >> 6; switch(comp_tag_class) { case FAC_TAGCLASS_UNI: break; case FAC_TAGCLASS_APW: break; case FAC_TAGCLASS_COS: break; case FAC_TAGCLASS_PRU: break; } /* tag form bit */ comp_tag_form = (*byte_buf & 0x20) > 5; /* tag code bits */ comp_tag_code = *byte_buf & 0x1f; if(comp_tag_code == 0x1f) { comp_tag_code = 0; byte_buf++; byte_len++; while(*byte_buf & 0x80) { comp_tag_code += (*byte_buf & 0x7f); byte_buf++; byte_len++; } comp_tag_code += (*byte_buf & 0x7f); } else { comp_tag_code = (*byte_buf & 0x1f); } byte_buf++; byte_len++; /*--------------------------------------------*/ /* second component element: component length */ /*--------------------------------------------*/ comp_length = 0; if(*byte_buf & 0x80) { int i = *byte_buf & 0x7f; byte_len += i; for(;i > 0;i++) { byte_buf++; comp_length += (*byte_buf * (i*256)); } } else { comp_length = *byte_buf & 0x7f; } next_state(comp_tag_class, comp_tag_form, comp_tag_code, -1); byte_len++; byte_buf++; /*---------------------------------------------*/ /* third component element: component contents */ /*---------------------------------------------*/ if(comp_tag_form) /* == constructor */ { do_component(comp_length); } else { int val = 0; if(comp_tag_class == FAC_TAGCLASS_UNI) { switch(comp_tag_code) { case FAC_CODEUNI_INT: case FAC_CODEUNI_ENUM: case FAC_CODEUNI_BOOL: if(comp_length) { int i; for(i = comp_length-1; i >= 0; i--) { val += (*byte_buf + (i*255)); byte_buf++; byte_len++; } } break; default: if(comp_length) { int i; for(i = comp_length-1; i >= 0; i--) { byte_buf++; byte_len++; } } break; } } else /* comp_tag_class != FAC_TAGCLASS_UNI */ { if(comp_length) { int i; for(i = comp_length-1; i >= 0; i--) { val += (*byte_buf + (i*255)); byte_buf++; byte_len++; } } } next_state(comp_tag_class, comp_tag_form, comp_tag_code, val); } if(byte_len < length) goto again; return(byte_len); } /*---------------------------------------------------------------------------* * invoke component *---------------------------------------------------------------------------*/ static void F_1_1(int val) { if(val == -1) { state = ST_EXP_INV_ID; } } /*---------------------------------------------------------------------------* * return result *---------------------------------------------------------------------------*/ static void F_1_2(int val) { if(val == -1) state = ST_EXP_NIX; } /*---------------------------------------------------------------------------* * return error *---------------------------------------------------------------------------*/ static void F_1_3(int val) { if(val == -1) state = ST_EXP_NIX; } /*---------------------------------------------------------------------------* * reject *---------------------------------------------------------------------------*/ static void F_1_4(int val) { if(val == -1) state = ST_EXP_NIX; } /*---------------------------------------------------------------------------* * invoke id *---------------------------------------------------------------------------*/ static void F_2(int val) { if(val != -1) { NDBGL3(L3_A_MSG, "Invoke ID = %d", val); state = ST_EXP_OP_VAL; } } /*---------------------------------------------------------------------------* * operation value *---------------------------------------------------------------------------*/ static void F_3(int val) { if(val != -1) { NDBGL3(L3_A_MSG, "Operation Value = %d", val); operation_value = val; if((val == FAC_OPVAL_AOC_D_UNIT) || (val == FAC_OPVAL_AOC_E_UNIT)) { units = 0; state = ST_EXP_INFO; } else { state = ST_EXP_NIX; } } } /*---------------------------------------------------------------------------* * specific charging units *---------------------------------------------------------------------------*/ static void F_4(int val) { if(val == -1) state = ST_EXP_RUL; } /*---------------------------------------------------------------------------* * free of charge *---------------------------------------------------------------------------*/ static void F_4_1(int val) { if(val == -1) { NDBGL3(L3_A_MSG, "Free of Charge"); /* units = 0; XXXX */ state = ST_EXP_NIX; } } /*---------------------------------------------------------------------------* * charge not available *---------------------------------------------------------------------------*/ static void F_4_2(int val) { if(val == -1) { NDBGL3(L3_A_MSG, "Charge not available"); /* units = -1; XXXXXX ??? */ state = ST_EXP_NIX; } } /*---------------------------------------------------------------------------* * recorded units list *---------------------------------------------------------------------------*/ static void F_5(int val) { if(val == -1) state = ST_EXP_RU; } /*---------------------------------------------------------------------------* * recorded units *---------------------------------------------------------------------------*/ static void F_6(int val) { if(val == -1) state = ST_EXP_RNOU; } /*---------------------------------------------------------------------------* * number of units *---------------------------------------------------------------------------*/ static void F_7(int val) { if(val != -1) { NDBGL3(L3_A_MSG, "Number of Units = %d", val); units = val; state = ST_EXP_TOCI; } } /*---------------------------------------------------------------------------* * subtotal/total *---------------------------------------------------------------------------*/ static void F_8(int val) { if(val != -1) { NDBGL3(L3_A_MSG, "Subtotal/Total = %d", val); /* type_of_charge = val; */ state = ST_EXP_DBID; } } /*---------------------------------------------------------------------------* * billing_id *---------------------------------------------------------------------------*/ static void F_9(int val) { if(val != -1) { NDBGL3(L3_A_MSG, "Billing ID = %d", val); /* billing_id = val; */ state = ST_EXP_NIX; } } /*---------------------------------------------------------------------------* * *---------------------------------------------------------------------------*/ static struct statetab { int currstate; /* input: current state we are in */ int form; /* input: current tag form */ int class; /* input: current tag class */ int code; /* input: current tag code */ void (*func)(int); /* output: func to exec */ } statetab[] = { /* current state tag form tag class tag code function */ /* --------------------- ---------------------- ---------------------- ---------------------- ----------------*/ {ST_EXP_COMP_TYP, FAC_TAGFORM_CON, FAC_TAGCLASS_COS, 1, F_1_1 }, {ST_EXP_COMP_TYP, FAC_TAGFORM_CON, FAC_TAGCLASS_COS, 2, F_1_2 }, {ST_EXP_COMP_TYP, FAC_TAGFORM_CON, FAC_TAGCLASS_COS, 3, F_1_3 }, {ST_EXP_COMP_TYP, FAC_TAGFORM_CON, FAC_TAGCLASS_COS, 4, F_1_4 }, {ST_EXP_INV_ID, FAC_TAGFORM_PRI, FAC_TAGCLASS_UNI, FAC_CODEUNI_INT, F_2 }, {ST_EXP_OP_VAL, FAC_TAGFORM_PRI, FAC_TAGCLASS_UNI, FAC_CODEUNI_INT, F_3 }, {ST_EXP_INFO, FAC_TAGFORM_CON, FAC_TAGCLASS_UNI, FAC_CODEUNI_SEQ, F_4 }, {ST_EXP_INFO, FAC_TAGFORM_PRI, FAC_TAGCLASS_UNI, FAC_CODEUNI_NULL, F_4_1 }, {ST_EXP_INFO, FAC_TAGFORM_PRI, FAC_TAGCLASS_COS, 1, F_4_2 }, {ST_EXP_RUL, FAC_TAGFORM_CON, FAC_TAGCLASS_COS, 1, F_5 }, {ST_EXP_RU, FAC_TAGFORM_CON, FAC_TAGCLASS_UNI, FAC_CODEUNI_SEQ, F_6 }, {ST_EXP_RNOU, FAC_TAGFORM_PRI, FAC_TAGCLASS_UNI, FAC_CODEUNI_INT, F_7 }, {ST_EXP_TOCI, FAC_TAGFORM_PRI, FAC_TAGCLASS_COS, 2, F_8 }, {ST_EXP_DBID, FAC_TAGFORM_PRI, FAC_TAGCLASS_COS, 3, F_9 }, {-1, -1, -1, -1, NULL } }; /*---------------------------------------------------------------------------* * state decode for do_component *---------------------------------------------------------------------------*/ static void next_state(int class, int form, int code, int val) { int i; for(i=0; ; i++) { if((statetab[i].currstate > state) || (statetab[i].currstate == -1)) { break; } if((statetab[i].currstate == state) && (statetab[i].form == form) && (statetab[i].class == class) && (statetab[i].code == code)) { (*statetab[i].func)(val); break; } } } #endif /* NI4BQ931 > 0 */