1999-10-06 18:16:21 +00:00
|
|
|
/* $Id: access.c,v 1.3 1999/10/06 18:16:22 he Exp $ */
|
1999-06-30 17:13:44 +00:00
|
|
|
/* Copyright 1997 by Henner Eisen
|
|
|
|
|
|
|
|
This code is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Library General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This code is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Library General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Library General Public
|
|
|
|
License along with this library; if not, write to the Free
|
|
|
|
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
|
|
|
|
*/
|
|
|
|
#include <tdu_user.h>
|
|
|
|
#include "tdu.h"
|
|
|
|
|
|
|
|
/*
|
|
|
|
* access regime event handler used during transfer regime by receiver
|
|
|
|
* while loading (reading) data from peer.
|
|
|
|
*/
|
|
|
|
int tdu_access_loading( struct tdu_fsm *fsm, int event, struct tdu_buf * tb)
|
|
|
|
{
|
|
|
|
|
|
|
|
tdu_printf( TDU_LOG_TRC, " tdu_access_loading(): unexpected event %s received"
|
|
|
|
" while transfer regime is established\n",
|
|
|
|
tdu_cmd_descr(event) );
|
|
|
|
switch (event) {
|
|
|
|
case TDU_CI_T_ABORT:
|
|
|
|
fsm->assoc.handler (fsm, event, tb);
|
|
|
|
break;
|
|
|
|
case TDU_CI_RESPONSE_TIMEOUT:
|
|
|
|
tdu_p_except_req( fsm,TDU_RE_DELAY_EXPIRED);
|
|
|
|
break;
|
|
|
|
case TDU_CI_T_P_EXCEPTION:
|
|
|
|
default:
|
|
|
|
tdu_printf( TDU_LOG_ERR, "tdu_access_loading(): unexpected command received by receiver\n" );
|
|
|
|
tdu_transfer_abort(fsm);
|
|
|
|
};
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* access regime event handler used during transfer regime by sender
|
|
|
|
* while saving (writing) data to peer.
|
|
|
|
*/
|
|
|
|
int tdu_access_saving( struct tdu_fsm *fsm, int event, struct tdu_buf * tb)
|
|
|
|
{
|
|
|
|
|
|
|
|
tdu_printf( TDU_LOG_TRC, " tdu_access_saving(): unexpected event %s received"
|
|
|
|
" while transfer regime is established\n",
|
|
|
|
tdu_cmd_descr(event) );
|
|
|
|
switch (event) {
|
|
|
|
case TDU_CI_T_ABORT:
|
|
|
|
fsm->assoc.handler (fsm, event, tb);
|
|
|
|
break;
|
|
|
|
case TDU_CI_RESPONSE_TIMEOUT:
|
|
|
|
tdu_p_except_req( fsm,TDU_RE_DELAY_EXPIRED);
|
|
|
|
break;
|
|
|
|
case TDU_CI_T_P_EXCEPTION:
|
|
|
|
default:
|
|
|
|
tdu_printf( TDU_LOG_ERR, "tdu_access_saving(): unexpected command received by sender\n" );
|
|
|
|
tdu_transfer_abort(fsm);
|
|
|
|
};
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int tdu_p_except_req( struct tdu_fsm * fsm, int reason )
|
|
|
|
{
|
|
|
|
tdu_send_p_exception(fsm,reason);
|
|
|
|
if( fsm->regime_handler == & fsm->transfer.handler )
|
|
|
|
tdu_transfer_abort(fsm);
|
|
|
|
tdu_access_set_idle(fsm);
|
|
|
|
return reason>0 ? reason : -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if in idle state of access regime. returns 1 if in idle state,
|
|
|
|
* 0 if not, but a negative value if the idle state is known never to be
|
|
|
|
* reachable without user intervention.
|
|
|
|
*/
|
|
|
|
static int in_idle_access_regime( struct tdu_fsm * fsm )
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
/* somewhat ugly, but we need this */
|
|
|
|
if ( (fsm -> regime_handler == & fsm->access.handler) &&
|
|
|
|
(fsm -> access.handler == tdu_await_end_access) ) return -2;
|
|
|
|
|
|
|
|
ret = ( fsm -> regime_handler == & fsm->access.handler )
|
|
|
|
&& ( fsm->access.handler == fsm->access.idle_handler );
|
|
|
|
|
|
|
|
if( ret ) return ret;
|
|
|
|
/* From the following states, the idle access regime cannot be reached
|
|
|
|
* without additional local user intervention*/
|
|
|
|
if ( fsm->regime_handler == &fsm->idle.handler ) return -3;
|
|
|
|
if ( (fsm->regime_handler == &fsm->assoc.handler ) &&
|
|
|
|
(fsm->assoc.handler == fsm->assoc.master_handler)) return -2;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* process events until the access regime's idle state is reached again.
|
|
|
|
*/
|
|
|
|
int tdu_wait_for_idle(struct tdu_fsm * fsm, struct timeval * timeout)
|
|
|
|
{
|
|
|
|
return tdu_wait( fsm, timeout, in_idle_access_regime );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void tdu_access_set_idle(struct tdu_fsm * fsm)
|
|
|
|
{
|
|
|
|
fsm -> access.handler = fsm->access.idle_handler;
|
|
|
|
fsm -> regime_handler = & fsm->access.handler;
|
|
|
|
tdu_del_timer(fsm);
|
|
|
|
fsm->wait=0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* access regime handler, waiting for confirmation of t_end_access
|
|
|
|
*/
|
|
|
|
int tdu_await_end_access( struct tdu_fsm *fsm, int event, struct tdu_buf *tb)
|
|
|
|
{
|
|
|
|
int err, pi;
|
|
|
|
|
|
|
|
tdu_printf(TDU_LOG_TRC, "tdu_await_end_access(), event = %s\n",
|
|
|
|
tdu_cmd_descr(event) );
|
|
|
|
switch (event) {
|
|
|
|
case TDU_CI_T_RESPONSE_POSITIVE:
|
|
|
|
pi = tdu_get_next_pi(tb);
|
|
|
|
err = tdu_check_response(tb,pi,fsm->wait);
|
|
|
|
if( err ) goto error;
|
|
|
|
fsm->assoc.handler = tdu_assoc_master;
|
|
|
|
/* now fall through */
|
|
|
|
case TDU_CI_T_END_ACCESS:
|
|
|
|
/* if t_end_acces_req conflict, no change of
|
|
|
|
role ./. association event handler handler */
|
|
|
|
fsm -> regime_handler = & fsm->assoc.handler ;
|
|
|
|
tdu_del_timer(fsm);
|
|
|
|
break;
|
|
|
|
case TDU_CI_RESPONSE_TIMEOUT:
|
|
|
|
tdu_printf(TDU_LOG_ERR, "timeout while waiting for t_end_access confirmation\n");
|
|
|
|
tdu_abort_req(fsm,TDU_RE_DELAY_EXPIRED,NULL);
|
|
|
|
break;
|
|
|
|
case TDU_CI_T_ABORT:
|
|
|
|
default:
|
|
|
|
error:
|
|
|
|
tdu_printf(TDU_LOG_ERR, "unexpected event %s while waiting for t_end_access confirmation"
|
|
|
|
" confirmation\n", tdu_cmd_descr(event) );
|
|
|
|
tdu_abort_req(fsm,TDU_RE_PROTOCOL_CONFLICT,NULL);
|
|
|
|
};
|
|
|
|
fsm->wait = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Request termination of access regime.
|
|
|
|
* Specifying user data and non-default reason parameter not yet supported.
|
|
|
|
*/
|
|
|
|
int tdu_end_access_req(struct tdu_fsm * fsm)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
struct tdu_buf tb[1];
|
|
|
|
|
|
|
|
tdu_init_tb(tb);
|
|
|
|
|
|
|
|
tdu_printf(TDU_LOG_TRC, "tdu_end_access_req(),\n" );
|
|
|
|
|
|
|
|
ret = in_idle_access_regime( fsm );
|
|
|
|
|
|
|
|
if( ret == 0 ) {
|
|
|
|
tdu_printf( TDU_LOG_ERR, "tdu_end_access_req: not in idle state of "
|
|
|
|
"access regime\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( ret < 0 ) return ret;
|
|
|
|
|
|
|
|
tdu_add_reason( tb, 0, TDU_RE_OTHER_REASON, "%");
|
|
|
|
tdu_add_ci_header( tb, TDU_CI_T_END_ACCESS);
|
|
|
|
ret = tdu_send_packet(tb,fsm);
|
|
|
|
if ( ret < 0 ) {
|
|
|
|
perror("tdu_end_access_req:send_packet");
|
|
|
|
tdu_abort(fsm);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
fsm->access.handler = tdu_await_end_access;
|
|
|
|
tdu_start_timer( fsm );
|
|
|
|
fsm->wait = TDU_CI_T_END_ACCESS;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Fill in parameters in a t_access request packet
|
|
|
|
*/
|
|
|
|
int tdu_add_access_params( struct tdu_buf * tb, struct tdu_access_param * par)
|
|
|
|
{
|
|
|
|
unsigned char byte = 0;
|
|
|
|
int ret=0;
|
|
|
|
|
|
|
|
if( par->udata && (par->udata_len >= 0) )
|
|
|
|
ret += tdu_add_string_par(tb, TDU_PI_USER_DATA, par->udata
|
|
|
|
, LIMIT(par->udata_len,TDU_PLEN_UDATA) );
|
|
|
|
|
|
|
|
ret += tdu_add_byte_par(tb,TDU_PI_TRANSFER_MODE,
|
|
|
|
par->transfer_mode);
|
|
|
|
|
|
|
|
byte = par->recovery ? 1 : 0;
|
|
|
|
byte |= ( ( (par->transfer_size) >> 9 ) & 0x0e );
|
|
|
|
byte |= ( ( (par->window - 1 ) << 5 ) & 0xe0 );
|
|
|
|
ret += tdu_add_byte_par(tb,TDU_PI_SIZE_RECOVERY_WINDOW,byte);
|
|
|
|
|
|
|
|
byte = par->role? TDU_ROLE_MASTER : TDU_ROLE_SLAVE;
|
|
|
|
byte |= (par->functions) & 0xfe; /* functions supported by us */
|
|
|
|
ret += tdu_add_byte_par(tb,TDU_PI_ROLE_FUNCTION,byte);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int tdu_send_access( struct tdu_fsm * fsm, int resp )
|
|
|
|
{
|
|
|
|
struct tdu_buf tb[1];
|
|
|
|
|
|
|
|
tdu_printf(TDU_LOG_TRC, "tdu_send_access()\n");
|
|
|
|
|
|
|
|
tdu_init_tb(tb);
|
|
|
|
tdu_add_access_params( tb, & fsm->access.local );
|
|
|
|
if( resp ) {
|
|
|
|
/*FIXME: the Role should be removed*/
|
|
|
|
tdu_add_reason(tb, TDU_CI_T_ACCESS, 0, NULL);
|
|
|
|
tdu_add_ci_header( tb, TDU_CI_T_RESPONSE_POSITIVE );
|
|
|
|
} else {
|
|
|
|
tdu_add_ci_header( tb, TDU_CI_T_ACCESS );
|
|
|
|
}
|
|
|
|
return tdu_send_packet( tb, fsm );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Parse parameters of an access_request or positive response message.
|
|
|
|
* returns:
|
|
|
|
* 0 on success
|
|
|
|
* an integer reason code from the TDU_RE_* set when an error is detected.
|
|
|
|
*/
|
|
|
|
int tdu_parse_access( struct tdu_access_param *par, struct tdu_buf *tb)
|
|
|
|
{
|
|
|
|
int pi, pv;
|
|
|
|
|
|
|
|
tdu_printf(TDU_LOG_TRC, "tdu_parse_access()\n");
|
|
|
|
do {
|
|
|
|
tdu_printf(TDU_LOG_DBG, "parsing parameter %d=%s\n",*tb->data,
|
|
|
|
tdu_param_descr(*tb->data) );
|
|
|
|
pi = tdu_get_next_pi(tb);
|
|
|
|
if( pi < 0 ) return -pi;
|
|
|
|
switch( pi ){
|
|
|
|
case TDU_PI_RESULT_REASON:
|
|
|
|
tdu_printf(TDU_LOG_DBG, "result/reason\n");
|
|
|
|
if( *tb->ci == TDU_CI_T_RESPONSE_POSITIVE ){
|
|
|
|
if( (pv=tdu_parse_byte(tb)) < 0 )
|
|
|
|
return TDU_RE_SYNTAX_ERROR;
|
|
|
|
if( pv != TDU_CI_T_ACCESS )
|
|
|
|
return TDU_RE_PROTOCOL_CONFLICT;
|
|
|
|
};
|
|
|
|
tb->data = tb->pn;
|
|
|
|
break;
|
|
|
|
case TDU_PI_ROLE_FUNCTION:
|
|
|
|
if( (pv=tdu_parse_byte(tb)) < 0 ){
|
|
|
|
if( tb->data + 1 == tb->pn ){
|
|
|
|
tb->data++;
|
|
|
|
} else {
|
|
|
|
return TDU_RE_SYNTAX_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
par->role = pv & TDU_BIT_ROLE;
|
|
|
|
par->functions = pv & (~TDU_BIT_ROLE);
|
|
|
|
break;
|
|
|
|
case TDU_PI_SIZE_RECOVERY_WINDOW:
|
|
|
|
tdu_printf(TDU_LOG_DBG, "size/recov/win\n");
|
|
|
|
if( (pv=tdu_parse_byte(tb)) < 0 )
|
|
|
|
return TDU_RE_SYNTAX_ERROR;
|
|
|
|
par->transfer_size = 512 << ((pv & TDU_MASK_SIZE) >>1);
|
|
|
|
par->window = 1 + ((pv & TDU_MASK_WINDOW) >>5);
|
|
|
|
par->recovery = TDU_MASK_RECOVERY;
|
|
|
|
tdu_printf(TDU_LOG_DBG,"peer's window size is %d\n",
|
|
|
|
par->window);
|
|
|
|
break;
|
|
|
|
case TDU_PI_TRANSFER_MODE:
|
|
|
|
tdu_printf(TDU_LOG_DBG, "transfer mode\n");
|
|
|
|
if( (pv=tdu_parse_byte(tb)) < 0 )
|
|
|
|
return TDU_RE_SYNTAX_ERROR;
|
|
|
|
par->transfer_mode = pv & TDU_BIT_TRANSFER_MODE;
|
|
|
|
break;
|
|
|
|
case TDU_PI_USER_DATA:
|
|
|
|
tdu_printf(TDU_LOG_DBG, "user data\n");
|
|
|
|
par->udata_len =
|
|
|
|
tdu_parse_string(tb, par->udata,
|
|
|
|
TDU_PLEN_UDATA);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
tdu_printf(TDU_LOG_LOG, "tdu_parse_access(): unexpected"
|
|
|
|
" parameter '%s' ignored\n",
|
|
|
|
tdu_param_descr(pi) );
|
|
|
|
tb->data = tb->pn;
|
|
|
|
};
|
|
|
|
} while( tb->pn < tb->tail );
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* access regime handler, waiting for t_access confirmation
|
|
|
|
*/
|
|
|
|
int tdu_await_access( struct tdu_fsm *fsm, int event, struct tdu_buf *tb)
|
|
|
|
{
|
|
|
|
int err, pi;
|
|
|
|
|
|
|
|
tdu_printf(TDU_LOG_TRC, "tdu_await_access(), event = %s\n",
|
|
|
|
tdu_cmd_descr(event) );
|
|
|
|
switch (event) {
|
|
|
|
case TDU_CI_T_RESPONSE_POSITIVE:
|
|
|
|
tdu_del_timer(fsm);
|
|
|
|
err = tdu_parse_access( & fsm->access.remote, tb );
|
|
|
|
if( err ) {
|
|
|
|
tdu_abort_req( fsm, err, NULL );
|
|
|
|
} else {
|
|
|
|
if( fsm->access.local.role == TDU_ROLE_SLAVE ) {
|
|
|
|
/* requested new role is slave */
|
|
|
|
fsm->assoc.handler
|
|
|
|
= fsm->assoc.slave_handler;
|
|
|
|
fsm->access.idle_handler
|
|
|
|
= fsm->access.idle_slave_handler;
|
|
|
|
} else {
|
|
|
|
/* requested new role is master */
|
|
|
|
fsm->assoc.handler
|
|
|
|
= fsm->assoc.master_handler;
|
|
|
|
fsm->access.idle_handler
|
|
|
|
= fsm->access.idle_master_handler;
|
|
|
|
}
|
|
|
|
tdu_access_set_idle(fsm);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TDU_CI_T_RESPONSE_NEGATIVE:
|
|
|
|
pi = tdu_get_next_pi(tb);
|
|
|
|
err = tdu_check_response(tb,pi,fsm->wait);
|
|
|
|
if( err ) goto error;
|
|
|
|
tdu_del_timer(fsm);
|
|
|
|
fsm->assoc.handler = fsm->assoc.master_handler;
|
|
|
|
break;
|
|
|
|
case TDU_CI_T_ABORT:
|
|
|
|
tdu_abort(fsm);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
error:
|
|
|
|
tdu_printf(TDU_LOG_ERR,"unexpected event %s while waiting for t_access"
|
|
|
|
" confirmation\n", tdu_cmd_descr(event) );
|
|
|
|
tdu_abort_req(fsm,TDU_RE_PROTOCOL_CONFLICT,NULL);
|
|
|
|
};
|
|
|
|
fsm->wait = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* establish access regime
|
|
|
|
*/
|
|
|
|
int tdu_access_req( struct tdu_fsm * fsm, struct tdu_access_param * par )
|
|
|
|
{
|
|
|
|
|
|
|
|
if ( ! in_idle_assoc_regime_master( fsm ) ){
|
|
|
|
tdu_printf(TDU_LOG_TRC, "tdu_access_req(): no idle association master state\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
fsm->access.local = *par;
|
|
|
|
/* FIXME: contents of *par needs checking */
|
|
|
|
|
|
|
|
if( tdu_send_access( fsm, 0 ) > 0 ){
|
|
|
|
fsm->assoc.handler = tdu_await_access;
|
|
|
|
tdu_start_timer( fsm );
|
|
|
|
fsm->wait = TDU_CI_T_ACCESS;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void tdu_set_default_access_param( struct tdu_access_param * par, struct tdu_user *usr, struct tdu_stream * st )
|
|
|
|
{
|
|
|
|
par->functions = 0;
|
|
|
|
if( usr ){
|
|
|
|
if( usr->t_typed_data ) par->functions |= TDU_BIT_TYPED_DATA;
|
|
|
|
if( usr->t_dir ) par->functions |= TDU_BIT_DIRECTORY;
|
|
|
|
if( usr->t_load) par->functions |= TDU_BIT_LOAD;
|
|
|
|
if( usr->t_save) par->functions |= TDU_BIT_SAVE;
|
|
|
|
if( usr->t_delete) par->functions |= TDU_BIT_DELETE;
|
|
|
|
if( usr->t_rename) par->functions |= TDU_BIT_RENAME;
|
|
|
|
}
|
|
|
|
if( st && st->t_read_restart ){
|
|
|
|
par->functions |= TDU_BIT_READ_RESTART;
|
|
|
|
}
|
|
|
|
par->transfer_size = 1024;
|
|
|
|
par->window = 1;
|
|
|
|
par->recovery = 0;
|
|
|
|
par->transfer_mode = 0;
|
|
|
|
par->udata_len = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* process events until the association regime's idle master state is reached.
|
|
|
|
*/
|
|
|
|
int tdu_wait_for_end_access(struct tdu_fsm * fsm, struct timeval * timeout)
|
|
|
|
{
|
|
|
|
tdu_printf(TDU_LOG_TRC, "tdu_wait_for_end_access()\n");
|
|
|
|
|
|
|
|
return tdu_wait( fsm, timeout, in_idle_assoc_regime_master );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* perform the work requierd by a t_end_access request
|
|
|
|
*/
|
|
|
|
int tdu_end_access_received(struct tdu_fsm *fsm)
|
|
|
|
{
|
|
|
|
tdu_printf(TDU_LOG_TRC, "tdu_end_access_received()\n");
|
|
|
|
if( fsm->assoc.slave_handler ){
|
|
|
|
tdu_send_response_pos(fsm,TDU_CI_T_END_ACCESS);
|
|
|
|
fsm->assoc.handler = fsm->assoc.slave_handler;
|
|
|
|
fsm->regime_handler = & fsm -> assoc.handler;
|
|
|
|
} else {
|
|
|
|
/* FIXME? is this the proper error code? */
|
|
|
|
tdu_abort_req( fsm, TDU_RE_ROLE_REFUSED_U, NULL );
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void tdu_access_set_master(struct tdu_fsm * fsm)
|
|
|
|
{
|
|
|
|
fsm->access.idle_handler = fsm->access.idle_master_handler;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void tdu_access_set_slave(struct tdu_fsm * fsm)
|
|
|
|
{
|
|
|
|
fsm->access.idle_handler = fsm->access.idle_slave_handler;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* perform the work required upon reception of a t_access_req tdu
|
|
|
|
*/
|
|
|
|
int tdu_access_received(struct tdu_fsm *fsm, struct tdu_buf * tb)
|
|
|
|
{
|
|
|
|
struct tdu_param par;
|
|
|
|
|
|
|
|
tdu_printf(TDU_LOG_TRC, "tdu_access_received()\n");
|
|
|
|
par.reason = TDU_RE_ROLE_REFUSED_U;
|
|
|
|
par.other_reason[0] = 0;
|
|
|
|
|
|
|
|
tdu_set_default_access_param( &fsm->access.remote, 0, 0);
|
|
|
|
tdu_set_default_access_param( &fsm->access.local, fsm->user,
|
|
|
|
fsm->stream);
|
|
|
|
|
|
|
|
par.reason = tdu_parse_access(&fsm->access.remote,tb);
|
|
|
|
if ( par.reason ) goto refuse;
|
|
|
|
|
|
|
|
if( fsm->access.remote.role == TDU_ROLE_SLAVE ){
|
|
|
|
fsm->access.local.role = TDU_ROLE_MASTER;
|
|
|
|
} else {
|
|
|
|
fsm->access.local.role = TDU_ROLE_SLAVE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( fsm->user->t_access){
|
|
|
|
par.par.access = &fsm->access.remote;
|
|
|
|
par.res.access = &fsm->access.local;
|
|
|
|
par.reason = fsm->user->t_access(fsm->user,&par);
|
|
|
|
if( par.reason ) goto refuse;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( (! fsm->access.idle_slave_handler) &&
|
|
|
|
(fsm->access.local.role == TDU_ROLE_SLAVE) ) goto refuse;
|
|
|
|
if( (! fsm->access.idle_master_handler) &&
|
|
|
|
(fsm->access.local.role == TDU_ROLE_MASTER) ) goto refuse;
|
|
|
|
|
|
|
|
if( tdu_send_access(fsm, 1) > 0 ){
|
|
|
|
if (fsm->access.local.role == TDU_ROLE_SLAVE){
|
|
|
|
tdu_access_set_slave(fsm);
|
|
|
|
} else {
|
|
|
|
tdu_access_set_master(fsm);
|
|
|
|
}
|
|
|
|
tdu_access_set_idle(fsm);
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
tdu_abort(fsm);
|
|
|
|
return -3;
|
|
|
|
}
|
|
|
|
|
|
|
|
refuse:
|
|
|
|
tdu_send_response_neg(fsm,TDU_CI_T_ACCESS,
|
|
|
|
par.reason,par.other_reason);
|
|
|
|
/* FIXME: is aborting here really appropriate ? */
|
|
|
|
tdu_abort(fsm);
|
|
|
|
return -3;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Parse udata parameter of an arbitrary tdu.
|
|
|
|
* returns:
|
|
|
|
* 0 on success
|
|
|
|
* an integer reason code from the TDU_RE_* set when an error is detected.
|
|
|
|
*/
|
|
|
|
int tdu_parse_udata( struct tdu_udata_param *par, struct tdu_buf *tb)
|
|
|
|
{
|
|
|
|
int pi;
|
|
|
|
|
|
|
|
tdu_printf(TDU_LOG_TRC, "tdu_parse_udata()\n");
|
|
|
|
do {
|
|
|
|
tdu_printf(TDU_LOG_DBG, "parsing parameter %d=%s\n",*tb->data,
|
|
|
|
tdu_param_descr(*tb->data) );
|
|
|
|
pi = tdu_get_next_pi(tb);
|
|
|
|
if( pi < 0 ) return -pi;
|
|
|
|
switch( pi ){
|
|
|
|
case TDU_PI_USER_DATA:
|
|
|
|
tdu_printf(TDU_LOG_DBG, "user data\n");
|
|
|
|
par->udata_len =
|
|
|
|
tdu_parse_string(tb, par->udata,
|
|
|
|
TDU_PLEN_UDATA);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
tdu_printf(TDU_LOG_LOG, "tdu_parse_udata(): unexpected"
|
|
|
|
" parameter '%s' ignored\n",
|
|
|
|
tdu_param_descr(pi) );
|
|
|
|
tb->data = tb->pn;
|
|
|
|
};
|
|
|
|
} while( tb->pn < tb->tail );
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int tdu_typed_data_received(struct tdu_fsm * fsm, struct tdu_buf * tb)
|
|
|
|
{
|
|
|
|
struct tdu_param param;
|
|
|
|
struct tdu_udata_param udata;
|
|
|
|
|
|
|
|
tdu_parse_udata(&udata,tb);
|
|
|
|
param.par.udata = &udata;
|
|
|
|
|
|
|
|
if( (fsm->access.local.functions & TDU_BIT_TYPED_DATA) &&
|
|
|
|
fsm->user->t_typed_data )
|
|
|
|
fsm->user->t_typed_data(fsm->user, ¶m);
|
|
|
|
return( param.reason );
|
|
|
|
}
|
|
|
|
|
|
|
|
int tdu_typed_data_req( struct tdu_fsm * fsm, unsigned char * msg){
|
|
|
|
struct tdu_buf tb[1];
|
|
|
|
|
|
|
|
tdu_init_tb(tb);
|
|
|
|
tdu_printf(TDU_LOG_TRC,"typed data request\n");
|
|
|
|
if( fsm->access.remote.functions & TDU_BIT_TYPED_DATA ){
|
|
|
|
tdu_add_string_par(tb,TDU_PI_USER_DATA, msg,
|
|
|
|
LIMIT(strlen(msg),254));
|
|
|
|
tdu_add_ci_header(tb,TDU_CI_T_TYPED_DATA);
|
|
|
|
tdu_send_packet(tb,fsm);
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
return TDU_RE_PRIMITIVE_NOT_HANDLED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* send a t_p_execption report tdu to peer
|
|
|
|
*/
|
|
|
|
int tdu_send_p_exception(struct tdu_fsm *fsm, int reason)
|
|
|
|
{
|
|
|
|
struct tdu_buf tb[1];
|
|
|
|
|
|
|
|
tdu_printf(TDU_LOG_TRC, "tdu_send_p_execption()\n");
|
|
|
|
|
|
|
|
tdu_init_tb(tb);
|
|
|
|
|
|
|
|
tdu_add_reason( tb, 0, reason, 0);
|
|
|
|
tdu_add_ci_header( tb, TDU_CI_T_P_EXCEPTION);
|
|
|
|
return tdu_send_packet(tb,fsm);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* check a generic positive or negative response for correctness
|
|
|
|
* and requests a t_p_execption if errors are detected.
|
|
|
|
* (semantics of pi as returned from first tdu_get_next_pi())
|
|
|
|
*/
|
|
|
|
int tdu_generic_response_received (struct tdu_fsm *fsm, struct tdu_buf * tb)
|
|
|
|
{
|
|
|
|
int pi, err=0;
|
|
|
|
|
|
|
|
tdu_printf(TDU_LOG_TRC, "tdu_generic_response_received");
|
|
|
|
|
|
|
|
pi = tdu_get_next_pi(tb);
|
|
|
|
err = tdu_check_response(tb,pi,fsm->wait);
|
|
|
|
if( err ) {
|
|
|
|
/* tb->data points to the parameter value of first pi */
|
|
|
|
tdu_printf(TDU_LOG_ERR
|
|
|
|
, "Bad response %s(%s) does not match request %s!\n"
|
|
|
|
, tdu_cmd_descr(*tb->ci)
|
|
|
|
, tdu_cmd_descr(*tb->data)
|
|
|
|
, tdu_cmd_descr(fsm->wait)
|
|
|
|
);
|
|
|
|
err = tdu_p_except_req(fsm,err);
|
|
|
|
}
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|