NetBSD/sys/netisdn/i4b_q932fac.c

571 lines
13 KiB
C

/*
* 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.1.1.1 2001/01/05 12:50:03 martin Exp $
*
* $FreeBSD$
*
* last edit-date: [Fri Jan 5 11:33:47 2001]
*
*---------------------------------------------------------------------------*/
#ifdef __FreeBSD__
#include "i4bq931.h"
#else
#define NI4BQ931 1
#endif
#if NI4BQ931 > 0
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <net/if.h>
#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000
#include <sys/callout.h>
#endif
#ifdef __FreeBSD__
#include <machine/i4b_debug.h>
#include <machine/i4b_ioctl.h>
#else
#include <netisdn/i4b_debug.h>
#include <netisdn/i4b_ioctl.h>
#endif
#include <netisdn/i4b_isdnq931.h>
#include <netisdn/i4b_l2l3.h>
#include <netisdn/i4b_l3l4.h>
#include <netisdn/i4b_mbuf.h>
#include <netisdn/i4b_l3.h>
#include <netisdn/i4b_l3fsm.h>
#include <netisdn/i4b_q931.h>
#include <netisdn/i4b_q932fac.h>
#include <netisdn/i4b_l4.h>
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 */