2005-04-16 15:20:36 -07:00
/* $Id: tei.c,v 2.20.2.3 2004/01/13 14:31:26 keil Exp $
*
* Author Karsten Keil
* based on the teles driver from Jan den Ouden
* Copyright by Karsten Keil < keil @ isdn4linux . de >
*
* This software may be used and distributed according to the terms
* of the GNU General Public License , incorporated herein by reference .
*
* For changes and modifications please read
* Documentation / isdn / HiSax . cert
*
* Thanks to Jan den Ouden
* Fritz Elfert
*
*/
# include "hisax.h"
# include "isdnl2.h"
# include <linux/init.h>
# include <linux/random.h>
const char * tei_revision = " $Revision: 2.20.2.3 $ " ;
# define ID_REQUEST 1
# define ID_ASSIGNED 2
# define ID_DENIED 3
# define ID_CHK_REQ 4
# define ID_CHK_RES 5
# define ID_REMOVE 6
# define ID_VERIFY 7
# define TEI_ENTITY_ID 0xf
static struct Fsm teifsm ;
void tei_handler ( struct PStack * st , u_char pr , struct sk_buff * skb ) ;
enum {
ST_TEI_NOP ,
ST_TEI_IDREQ ,
ST_TEI_IDVERIFY ,
} ;
# define TEI_STATE_COUNT (ST_TEI_IDVERIFY+1)
static char * strTeiState [ ] =
{
" ST_TEI_NOP " ,
" ST_TEI_IDREQ " ,
" ST_TEI_IDVERIFY " ,
} ;
enum {
EV_IDREQ ,
EV_ASSIGN ,
EV_DENIED ,
EV_CHKREQ ,
EV_REMOVE ,
EV_VERIFY ,
EV_T202 ,
} ;
# define TEI_EVENT_COUNT (EV_T202+1)
static char * strTeiEvent [ ] =
{
" EV_IDREQ " ,
" EV_ASSIGN " ,
" EV_DENIED " ,
" EV_CHKREQ " ,
" EV_REMOVE " ,
" EV_VERIFY " ,
" EV_T202 " ,
} ;
2005-06-25 14:59:18 -07:00
static unsigned int
2005-04-16 15:20:36 -07:00
random_ri ( void )
{
unsigned int x ;
get_random_bytes ( & x , sizeof ( x ) ) ;
return ( x & 0xffff ) ;
}
static struct PStack *
findtei ( struct PStack * st , int tei )
{
struct PStack * ptr = * ( st - > l1 . stlistp ) ;
if ( tei = = 127 )
return ( NULL ) ;
while ( ptr )
if ( ptr - > l2 . tei = = tei )
return ( ptr ) ;
else
ptr = ptr - > next ;
return ( NULL ) ;
}
static void
put_tei_msg ( struct PStack * st , u_char m_id , unsigned int ri , u_char tei )
{
struct sk_buff * skb ;
u_char * bp ;
if ( ! ( skb = alloc_skb ( 8 , GFP_ATOMIC ) ) ) {
printk ( KERN_WARNING " HiSax: No skb for TEI manager \n " ) ;
return ;
}
bp = skb_put ( skb , 3 ) ;
bp [ 0 ] = ( TEI_SAPI < < 2 ) ;
bp [ 1 ] = ( GROUP_TEI < < 1 ) | 0x1 ;
bp [ 2 ] = UI ;
bp = skb_put ( skb , 5 ) ;
bp [ 0 ] = TEI_ENTITY_ID ;
bp [ 1 ] = ri > > 8 ;
bp [ 2 ] = ri & 0xff ;
bp [ 3 ] = m_id ;
bp [ 4 ] = ( tei < < 1 ) | 1 ;
st - > l2 . l2l1 ( st , PH_DATA | REQUEST , skb ) ;
}
static void
tei_id_request ( struct FsmInst * fi , int event , void * arg )
{
struct PStack * st = fi - > userdata ;
if ( st - > l2 . tei ! = - 1 ) {
st - > ma . tei_m . printdebug ( & st - > ma . tei_m ,
" assign request for allready asigned tei %d " ,
st - > l2 . tei ) ;
return ;
}
st - > ma . ri = random_ri ( ) ;
if ( st - > ma . debug )
st - > ma . tei_m . printdebug ( & st - > ma . tei_m ,
" assign request ri %d " , st - > ma . ri ) ;
put_tei_msg ( st , ID_REQUEST , st - > ma . ri , 127 ) ;
FsmChangeState ( & st - > ma . tei_m , ST_TEI_IDREQ ) ;
FsmAddTimer ( & st - > ma . t202 , st - > ma . T202 , EV_T202 , NULL , 1 ) ;
st - > ma . N202 = 3 ;
}
static void
tei_id_assign ( struct FsmInst * fi , int event , void * arg )
{
struct PStack * ost , * st = fi - > userdata ;
struct sk_buff * skb = arg ;
struct IsdnCardState * cs ;
int ri , tei ;
ri = ( ( unsigned int ) skb - > data [ 1 ] < < 8 ) + skb - > data [ 2 ] ;
tei = skb - > data [ 4 ] > > 1 ;
if ( st - > ma . debug )
st - > ma . tei_m . printdebug ( & st - > ma . tei_m ,
" identity assign ri %d tei %d " , ri , tei ) ;
if ( ( ost = findtei ( st , tei ) ) ) { /* same tei is in use */
if ( ri ! = ost - > ma . ri ) {
st - > ma . tei_m . printdebug ( & st - > ma . tei_m ,
" possible duplicate assignment tei %d " , tei ) ;
ost - > l2 . l2tei ( ost , MDL_ERROR | RESPONSE , NULL ) ;
}
} else if ( ri = = st - > ma . ri ) {
FsmDelTimer ( & st - > ma . t202 , 1 ) ;
FsmChangeState ( & st - > ma . tei_m , ST_TEI_NOP ) ;
st - > l3 . l3l2 ( st , MDL_ASSIGN | REQUEST , ( void * ) ( long ) tei ) ;
cs = ( struct IsdnCardState * ) st - > l1 . hardware ;
cs - > cardmsg ( cs , MDL_ASSIGN | REQUEST , NULL ) ;
}
}
static void
tei_id_test_dup ( struct FsmInst * fi , int event , void * arg )
{
struct PStack * ost , * st = fi - > userdata ;
struct sk_buff * skb = arg ;
int tei , ri ;
ri = ( ( unsigned int ) skb - > data [ 1 ] < < 8 ) + skb - > data [ 2 ] ;
tei = skb - > data [ 4 ] > > 1 ;
if ( st - > ma . debug )
st - > ma . tei_m . printdebug ( & st - > ma . tei_m ,
" foreign identity assign ri %d tei %d " , ri , tei ) ;
if ( ( ost = findtei ( st , tei ) ) ) { /* same tei is in use */
if ( ri ! = ost - > ma . ri ) { /* and it wasn't our request */
st - > ma . tei_m . printdebug ( & st - > ma . tei_m ,
" possible duplicate assignment tei %d " , tei ) ;
FsmEvent ( & ost - > ma . tei_m , EV_VERIFY , NULL ) ;
}
}
}
static void
tei_id_denied ( struct FsmInst * fi , int event , void * arg )
{
struct PStack * st = fi - > userdata ;
struct sk_buff * skb = arg ;
int ri , tei ;
ri = ( ( unsigned int ) skb - > data [ 1 ] < < 8 ) + skb - > data [ 2 ] ;
tei = skb - > data [ 4 ] > > 1 ;
if ( st - > ma . debug )
st - > ma . tei_m . printdebug ( & st - > ma . tei_m ,
" identity denied ri %d tei %d " , ri , tei ) ;
}
static void
tei_id_chk_req ( struct FsmInst * fi , int event , void * arg )
{
struct PStack * st = fi - > userdata ;
struct sk_buff * skb = arg ;
int tei ;
tei = skb - > data [ 4 ] > > 1 ;
if ( st - > ma . debug )
st - > ma . tei_m . printdebug ( & st - > ma . tei_m ,
" identity check req tei %d " , tei ) ;
if ( ( st - > l2 . tei ! = - 1 ) & & ( ( tei = = GROUP_TEI ) | | ( tei = = st - > l2 . tei ) ) ) {
FsmDelTimer ( & st - > ma . t202 , 4 ) ;
FsmChangeState ( & st - > ma . tei_m , ST_TEI_NOP ) ;
put_tei_msg ( st , ID_CHK_RES , random_ri ( ) , st - > l2 . tei ) ;
}
}
static void
tei_id_remove ( struct FsmInst * fi , int event , void * arg )
{
struct PStack * st = fi - > userdata ;
struct sk_buff * skb = arg ;
struct IsdnCardState * cs ;
int tei ;
tei = skb - > data [ 4 ] > > 1 ;
if ( st - > ma . debug )
st - > ma . tei_m . printdebug ( & st - > ma . tei_m ,
" identity remove tei %d " , tei ) ;
if ( ( st - > l2 . tei ! = - 1 ) & & ( ( tei = = GROUP_TEI ) | | ( tei = = st - > l2 . tei ) ) ) {
FsmDelTimer ( & st - > ma . t202 , 5 ) ;
FsmChangeState ( & st - > ma . tei_m , ST_TEI_NOP ) ;
st - > l3 . l3l2 ( st , MDL_REMOVE | REQUEST , NULL ) ;
cs = ( struct IsdnCardState * ) st - > l1 . hardware ;
cs - > cardmsg ( cs , MDL_REMOVE | REQUEST , NULL ) ;
}
}
static void
tei_id_verify ( struct FsmInst * fi , int event , void * arg )
{
struct PStack * st = fi - > userdata ;
if ( st - > ma . debug )
st - > ma . tei_m . printdebug ( & st - > ma . tei_m ,
" id verify request for tei %d " , st - > l2 . tei ) ;
put_tei_msg ( st , ID_VERIFY , 0 , st - > l2 . tei ) ;
FsmChangeState ( & st - > ma . tei_m , ST_TEI_IDVERIFY ) ;
FsmAddTimer ( & st - > ma . t202 , st - > ma . T202 , EV_T202 , NULL , 2 ) ;
st - > ma . N202 = 2 ;
}
static void
tei_id_req_tout ( struct FsmInst * fi , int event , void * arg )
{
struct PStack * st = fi - > userdata ;
struct IsdnCardState * cs ;
if ( - - st - > ma . N202 ) {
st - > ma . ri = random_ri ( ) ;
if ( st - > ma . debug )
st - > ma . tei_m . printdebug ( & st - > ma . tei_m ,
" assign req(%d) ri %d " , 4 - st - > ma . N202 ,
st - > ma . ri ) ;
put_tei_msg ( st , ID_REQUEST , st - > ma . ri , 127 ) ;
FsmAddTimer ( & st - > ma . t202 , st - > ma . T202 , EV_T202 , NULL , 3 ) ;
} else {
st - > ma . tei_m . printdebug ( & st - > ma . tei_m , " assign req failed " ) ;
st - > l3 . l3l2 ( st , MDL_ERROR | RESPONSE , NULL ) ;
cs = ( struct IsdnCardState * ) st - > l1 . hardware ;
cs - > cardmsg ( cs , MDL_REMOVE | REQUEST , NULL ) ;
FsmChangeState ( fi , ST_TEI_NOP ) ;
}
}
static void
tei_id_ver_tout ( struct FsmInst * fi , int event , void * arg )
{
struct PStack * st = fi - > userdata ;
struct IsdnCardState * cs ;
if ( - - st - > ma . N202 ) {
if ( st - > ma . debug )
st - > ma . tei_m . printdebug ( & st - > ma . tei_m ,
" id verify req(%d) for tei %d " ,
3 - st - > ma . N202 , st - > l2 . tei ) ;
put_tei_msg ( st , ID_VERIFY , 0 , st - > l2 . tei ) ;
FsmAddTimer ( & st - > ma . t202 , st - > ma . T202 , EV_T202 , NULL , 4 ) ;
} else {
st - > ma . tei_m . printdebug ( & st - > ma . tei_m ,
" verify req for tei %d failed " , st - > l2 . tei ) ;
st - > l3 . l3l2 ( st , MDL_REMOVE | REQUEST , NULL ) ;
cs = ( struct IsdnCardState * ) st - > l1 . hardware ;
cs - > cardmsg ( cs , MDL_REMOVE | REQUEST , NULL ) ;
FsmChangeState ( fi , ST_TEI_NOP ) ;
}
}
static void
tei_l1l2 ( struct PStack * st , int pr , void * arg )
{
struct sk_buff * skb = arg ;
int mt ;
if ( test_bit ( FLG_FIXED_TEI , & st - > l2 . flag ) ) {
dev_kfree_skb ( skb ) ;
return ;
}
if ( pr = = ( PH_DATA | INDICATION ) ) {
if ( skb - > len < 3 ) {
st - > ma . tei_m . printdebug ( & st - > ma . tei_m ,
" short mgr frame %ld/3 " , skb - > len ) ;
} else if ( ( skb - > data [ 0 ] ! = ( ( TEI_SAPI < < 2 ) | 2 ) ) | |
( skb - > data [ 1 ] ! = ( ( GROUP_TEI < < 1 ) | 1 ) ) ) {
st - > ma . tei_m . printdebug ( & st - > ma . tei_m ,
" wrong mgr sapi/tei %x/%x " ,
skb - > data [ 0 ] , skb - > data [ 1 ] ) ;
} else if ( ( skb - > data [ 2 ] & 0xef ) ! = UI ) {
st - > ma . tei_m . printdebug ( & st - > ma . tei_m ,
" mgr frame is not ui %x " , skb - > data [ 2 ] ) ;
} else {
skb_pull ( skb , 3 ) ;
if ( skb - > len < 5 ) {
st - > ma . tei_m . printdebug ( & st - > ma . tei_m ,
" short mgr frame %ld/5 " , skb - > len ) ;
} else if ( skb - > data [ 0 ] ! = TEI_ENTITY_ID ) {
/* wrong management entity identifier, ignore */
st - > ma . tei_m . printdebug ( & st - > ma . tei_m ,
" tei handler wrong entity id %x " ,
skb - > data [ 0 ] ) ;
} else {
mt = skb - > data [ 3 ] ;
if ( mt = = ID_ASSIGNED )
FsmEvent ( & st - > ma . tei_m , EV_ASSIGN , skb ) ;
else if ( mt = = ID_DENIED )
FsmEvent ( & st - > ma . tei_m , EV_DENIED , skb ) ;
else if ( mt = = ID_CHK_REQ )
FsmEvent ( & st - > ma . tei_m , EV_CHKREQ , skb ) ;
else if ( mt = = ID_REMOVE )
FsmEvent ( & st - > ma . tei_m , EV_REMOVE , skb ) ;
else {
st - > ma . tei_m . printdebug ( & st - > ma . tei_m ,
" tei handler wrong mt %x \n " , mt ) ;
}
}
}
} else {
st - > ma . tei_m . printdebug ( & st - > ma . tei_m ,
" tei handler wrong pr %x \n " , pr ) ;
}
dev_kfree_skb ( skb ) ;
}
static void
tei_l2tei ( struct PStack * st , int pr , void * arg )
{
struct IsdnCardState * cs ;
if ( test_bit ( FLG_FIXED_TEI , & st - > l2 . flag ) ) {
if ( pr = = ( MDL_ASSIGN | INDICATION ) ) {
if ( st - > ma . debug )
st - > ma . tei_m . printdebug ( & st - > ma . tei_m ,
" fixed assign tei %d " , st - > l2 . tei ) ;
st - > l3 . l3l2 ( st , MDL_ASSIGN | REQUEST , ( void * ) ( long ) st - > l2 . tei ) ;
cs = ( struct IsdnCardState * ) st - > l1 . hardware ;
cs - > cardmsg ( cs , MDL_ASSIGN | REQUEST , NULL ) ;
}
return ;
}
switch ( pr ) {
case ( MDL_ASSIGN | INDICATION ) :
FsmEvent ( & st - > ma . tei_m , EV_IDREQ , arg ) ;
break ;
case ( MDL_ERROR | REQUEST ) :
FsmEvent ( & st - > ma . tei_m , EV_VERIFY , arg ) ;
break ;
default :
break ;
}
}
static void
tei_debug ( struct FsmInst * fi , char * fmt , . . . )
{
va_list args ;
struct PStack * st = fi - > userdata ;
va_start ( args , fmt ) ;
VHiSax_putstatus ( st - > l1 . hardware , " tei " , fmt , args ) ;
va_end ( args ) ;
}
void
setstack_tei ( struct PStack * st )
{
st - > l2 . l2tei = tei_l2tei ;
st - > ma . T202 = 2000 ; /* T202 2000 milliseconds */
st - > l1 . l1tei = tei_l1l2 ;
st - > ma . debug = 1 ;
st - > ma . tei_m . fsm = & teifsm ;
st - > ma . tei_m . state = ST_TEI_NOP ;
st - > ma . tei_m . debug = 1 ;
st - > ma . tei_m . userdata = st ;
st - > ma . tei_m . userint = 0 ;
st - > ma . tei_m . printdebug = tei_debug ;
FsmInitTimer ( & st - > ma . tei_m , & st - > ma . t202 ) ;
}
void
init_tei ( struct IsdnCardState * cs , int protocol )
{
}
void
release_tei ( struct IsdnCardState * cs )
{
struct PStack * st = cs - > stlist ;
while ( st ) {
FsmDelTimer ( & st - > ma . t202 , 1 ) ;
st = st - > next ;
}
}
static struct FsmNode TeiFnList [ ] __initdata =
{
{ ST_TEI_NOP , EV_IDREQ , tei_id_request } ,
{ ST_TEI_NOP , EV_ASSIGN , tei_id_test_dup } ,
{ ST_TEI_NOP , EV_VERIFY , tei_id_verify } ,
{ ST_TEI_NOP , EV_REMOVE , tei_id_remove } ,
{ ST_TEI_NOP , EV_CHKREQ , tei_id_chk_req } ,
{ ST_TEI_IDREQ , EV_T202 , tei_id_req_tout } ,
{ ST_TEI_IDREQ , EV_ASSIGN , tei_id_assign } ,
{ ST_TEI_IDREQ , EV_DENIED , tei_id_denied } ,
{ ST_TEI_IDVERIFY , EV_T202 , tei_id_ver_tout } ,
{ ST_TEI_IDVERIFY , EV_REMOVE , tei_id_remove } ,
{ ST_TEI_IDVERIFY , EV_CHKREQ , tei_id_chk_req } ,
} ;
# define TEI_FN_COUNT (sizeof(TeiFnList) / sizeof(struct FsmNode))
int __init
TeiNew ( void )
{
teifsm . state_count = TEI_STATE_COUNT ;
teifsm . event_count = TEI_EVENT_COUNT ;
teifsm . strEvent = strTeiEvent ;
teifsm . strState = strTeiState ;
return FsmNew ( & teifsm , TeiFnList , TEI_FN_COUNT ) ;
}
void
TeiFree ( void )
{
FsmFree ( & teifsm ) ;
}