📄 mnpllvl.c
字号:
/*=============================================================================
The Microcom MNP Library
(Microsoft C Version)
-------------------------------------------------------------------------------
MNPLLVL - MNP Link Level Routines
-------------------------------------------------------------------------------
Modification History
3/25/87 - Compuserve V1.0
=============================================================================*/
/* Header files
*/
#include <dos.h>
#include <mnpdat.h>
#include <llvl.h>
/* External references
*/
extern USIGN_16 sb_cnt;
/* Global buffers
*/
struct link_ctl_blk lcb;
struct BUFFER rb, ftb, lkb, rlkb;
struct BLST lkblst[2],
rlkblst[2],
iatblst[8];
USIGN_8 lkbuff[MAX_LPDU_SZ * 2];
USIGN_8 rlkbuff[MAX_LPDU_SZ * 2];
USIGN_8 iatbuff[(64+5)*8];
USIGN_16 tbcnt;
USIGN_16 g_tm,
ack_tm,
fcw_tm,
lr_tm,
lt_tm,
ln_tm;
USIGN_16 port_add,
chan_no,
iir_add;
USIGN_8 linestat;
/* Function declarations
*/
void as_disconnect();
SIGN_16 acking();
SIGN_16 credit_chk();
SIGN_16 lpdu_send();
SIGN_16 parse_lr();
SIGN_16 receive_wait();
SIGN_16 retran_lt();
SIGN_16 send_la();
SIGN_16 send_pdu();
SIGN_16 send_wait();
/*GLOBAL********************************************************************
as_connect - establish an MNP link-connection
***************************************************************************/
SIGN_16 as_connect (mnpcb,mode)
struct MNP_CB *mnpcb;
USIGN_16 mode;
{
SIGN_16 lr_cnt,
la_cnt,
retcode,
link_state;
/* Initialize
*/
lcb.lpdu_type = 0;
link_state = IDLE;
for (;;)
{
switch (link_state)
{
case IDLE:
link_init(mnpcb);
link_reset();
if (L_ACCEPTOR)
{
SETBIT1(MODE)
link_state = LR_WAIT;
}
else
{
suspend(5);
if (retcode = lpdu_send(LR,WAIT))
link_state = LNK_ERROR;
else
link_state = LR_RESP_WAIT;
}
break;
case LR_RESP_WAIT:
lr_cnt = LR_RETRAN_CNT;
retcode = SUCCESS;
while ((retcode = receive_wait()) || !lcb.lpdu_type)
{
if (retcode == NO_PHYSICAL)
{
link_state = LNK_ERROR;
break;
}
if (lr_cnt--)
{
if (retcode = lpdu_send(LR,WAIT))
{
link_state = LNK_ERROR;
break;
}
}
else
{
retcode = TIME_OUT;
link_state = LNK_ERROR;
break;
}
}
if (retcode == SUCCESS)
link_state = PARMS_NEGO;
break;
case PARMS_NEGO:
if (retcode = parse_lr())
{
as_disconnect(retcode,NULL);
return(retcode + LR_CODE);
}
if (retcode = lpdu_send(LA,WAIT))
link_state = LNK_ERROR;
else
link_state = LNK_CONNECTED;
break;
case LR_WAIT:
lr_cnt = 2;
while ((retcode = receive_wait()) || !lcb.lpdu_type)
{
if (retcode == NO_PHYSICAL)
{
link_state = LNK_ERROR;
break;
}
if (!(--lr_cnt))
{
retcode = TIME_OUT;
link_state = LNK_ERROR;
break;
}
}
if (link_state != LR_WAIT)
break;
if (retcode = parse_lr())
{
as_disconnect(retcode,NULL);
return(retcode + LR_CODE);
}
lr_cnt = LR_TRAN_CNT;
link_state = CONNECT_REQ_WAIT;
break;
case CONNECT_REQ_WAIT:
if (lr_cnt == NULL)
{
retcode = FAILURE;
link_state = LNK_ERROR;
break;
}
if (retcode = lpdu_send(LR,WAIT))
link_state = LNK_ERROR;
else
{
lr_cnt--;
la_cnt = LA_WAIT_CNT;
link_state = LA_WAIT;
}
break;
case LA_WAIT:
while ((retcode = receive_wait()) || !lcb.lpdu_type)
{
if (retcode == NO_PHYSICAL)
{
link_state = LNK_ERROR;
break;
}
if (--la_cnt)
{
if (retcode = lpdu_send(LR,WAIT))
{
link_state = LNK_ERROR;
break;
}
}
else
{
retcode = TIME_OUT;
link_state = LNK_ERROR;
break;
}
}
if (link_state != LA_WAIT)
break;
switch (lcb.lpdu_type)
{
case LA:
lcb.lt_rsn = NULL;
case LT:
link_state = LNK_CONNECTED;
break;
case LR:
ret_b (&rlkb,rlkb.used_lst);
link_state = CONNECT_REQ_WAIT;
break;
default:
retcode = FAILURE;
link_state = LNK_ERROR;
}
break;
case LNK_ERROR:
as_disconnect(NULL,NULL);
return(retcode);
case LNK_CONNECTED:
dphase_init();
SETBIT1(LINK_EST)
return(SUCCESS);
}
}
}
/*GLOBAL***********************************************************************
as_disconnect - terminate a link-connection
******************************************************************************/
void as_disconnect(lreason,ureason)
SIGN_16 lreason,
ureason;
{
/* If the link is still up, send an LD LPDU to the other side. If the
** caller has supplied a reason code (in ureason) then save this code
** in the lcb so that it will be sent in the LD. Wait for the LD to
** actually be sent (to the very last byte...).
*/
if (BIT1SET(LINK_EST))
{
if ((lcb.l_disc_code = lreason) == 255)
lcb.u_disc_code = ureason;
lpdu_send(LD,NOWAIT);
while (!lne_stat() && modem_out_busy)
;
CLRBIT1(LINK_EST);
}
/* In any case, wait a bit.
*/
suspend(10);
/* Now remove interrupt handlers - link driver and timers.
*/
drvr_rem();
timerrem();
}
/*GLOBAL********************************************************************
as_link - maintain a link-connection
***************************************************************************/
SIGN_16 as_link()
{
SIGN_16 retcode;
/* If the link-connection has failed, return reporting link down.
*/
if (!BIT1SET(LINK_EST))
return (LNK_DOWN);
/* If the physical connection has been lost, return reporting p-conn down.
*/
if (lne_stat())
return (NO_PHYSICAL);
/* If we support attention service, go see if we have any to process.
*/
if (lcb.prot_level == 2)
{
if (retcode = attn_process())
return(retcode);
}
/* Go see if it's time to send an ack.
*/
if (retcode = acking())
return(retcode);
/* Try to free up any transmit buffers which have been acked.
*/
tb_free();
/* Go see if we have to retransmit.
*/
if (retcode = retran_lt())
return(retcode);
/* Make sure link is still up one more time
*/
if (!BIT1SET(LINK_EST))
return(LNK_DOWN);
/* Exit
*/
return(SUCCESS);
}
/*LOCAL------------------------------------------------------------------------
acking - send an LA LPDU if an ack condition is present
-----------------------------------------------------------------------------*/
SIGN_16 acking()
{
SIGN_16 retcode, /* return code */
lt_unacked; /* number of unacked LTs */
/* If the force ack flag is set, send an LA right away.
*/
clr_int(); /* protect flag access */
if (BIT2SET(FORCE_ACK)) /* reset flag if set */
{
CLRBIT2(FORCE_ACK)
set_int();
return(send_la()); /* send LA and return */
}
set_int();
/* If the window timer is enabled and has expired, send an LA.
*/
if (BIT2SET(WNDW_TIMER) && (fcw_tm == 0))
return(send_la());
/* If there are unacknowledged LT's, it may be time to send an LA.
*/
if (lt_unacked = lcb.lt_rsn - lcb.ltrsn_acked)
{
/* If there is no user data to send (i.e. no reason to put it off)
** send an LA.
*/
if (sb_cnt == 0)
return(send_la());
/* If the acknowledgment threshold has been reached, send an LA.
*/
if (lt_unacked >= lcb.ack_threshold)
return(send_la());
/* If the ack timer has elapsed, send an LA. Otherwise, set the timer.
*/
if (BIT1SET(ACK_TIMER))
{
if (ack_tm)
return(SUCCESS);
else
return(send_la());
}
else
{
SETBIT1(ACK_TIMER)
ack_tm = lcb.ack_timer;
return(SUCCESS);
}
}
/* If there are no unacknowledged LT's, handle the 'zero window
** opening' case.
*/
else
{
if (BIT2SET(ZERO_WNDW) && credit_chk())
{
CLRBIT2(ZERO_WNDW)
return(send_la());
}
}
/* Exit
*/
return(SUCCESS);
}
/*LOCAL------------------------------------------------------------------------
attn_process - handle break signalling
-----------------------------------------------------------------------------*/
attn_process()
{
SIGN_16 retcode;
/* If the LN timer is set and has expired, it is time to retransmit the
** last LN LPDU sent. However, if the retransmission limit has been
** reached, then the link is unusable. Terminate the link and return
** with a function value=retran limit reached.
*/
if (BIT3SET(LN_TIMER) && (ln_tm == 0))
{
if (lcb.ln_ret_cnt == RET_LIMIT)
{
as_disconnect(RETRAN_TMR_EXP,NULL);
return(-67);
}
if (retcode = lpdu_send(LN,NOWAIT))
return(retcode);
++lcb.ln_ret_cnt;
SETBIT3(LN_SENT)
clr_int();
SETBIT3(LN_TIMER)
ln_tm=lcb.lt_tmr;
set_int();
}
/* If an LN has been received, check its type for a destructive break
** signal. Reset the link on receipt of a destructive break.
*/
clr_int();
if (BIT3SET(LN_RECEIVED))
{
CLRBIT3(LN_RECEIVED)
if (lcb.ln_rtype == 1)
{
link_reset();
dphase_init();
}
set_int();
if (retcode = lpdu_send(LNA,NOWAIT))
return(retcode);
}
set_int();
/* Check for need to send an LNA
*/
if (BIT3SET(FORCE_LNA))
{
CLRBIT3(FORCE_LNA)
if (retcode = lpdu_send(LNA,NOWAIT))
return(retcode);
}
/* Exit
*/
return(SUCCESS);
}
/*LOCAL------------------------------------------------------------------------
credit_chk - determine local ability to receive
-----------------------------------------------------------------------------*/
SIGN_16 credit_chk()
{
extern USIGN_16 rb_cnt;
/* Compute the number of LT LPDUs which can be received. This is
** the number of max sized LT's which will fit into the receive
** ring buffer. This number can not be larger than maximum window
** (8 for this implementation).
*/
lcb.lcl_credit = (RBUF_LEN - rb_cnt) / lcb.max_data_sz;
if (lcb.lcl_credit > lcb.window_sz)
lcb.lcl_credit = lcb.window_sz;
/* Exit. Function value is receive credit.
*/
return(lcb.lcl_credit);
}
/*LOCAL------------------------------------------------------------------------
dphase_init - perform data phase initialization
-----------------------------------------------------------------------------*/
dphase_init()
{
SIGN_16 i;
/* Set initial credits equal to negotiated maximum credit.
*/
lcb.lcl_credit = lcb.rem_credit = lcb.window_sz;
/* Compute ack threshold
*/
lcb.ack_threshold = (i = lcb.window_sz / 2) ? i : 1;
/* Be sure that ack conditions are reset.
*/
CLRBIT1(LA_RECEIVED)
CLRBIT2(FORCE_ACK)
/* If window == 1, lt retran timer is specified to be 8 seconds
*/
if (lcb.window_sz == 1)
lcb.lt_tmr = 8;
else
{
SETBIT2(WNDW_TIMER)
fcw_tm = lcb.window_tmr;
}
}
/*LOCAL------------------------------------------------------------------------
link_init - perform one-time link initialization
-----------------------------------------------------------------------------*/
link_init(mnpcb)
register struct MNP_CB *mnpcb;
{
/* Initialize link control block values
*/
lcb.status_1 = lcb.status_2 = lcb.status_3 = NULL;
ftb.num = lcb.window_sz = STRM_WNDW_SZ;
lcb.max_data_sz = STRM_DATA_SZ;
lcb.prot_level = 2;
lcb.srv_class = LCL_SCLASS;
lcb.ln_rsn = lcb.ln_ssn = lcb.ln_ret_cnt = ln_tm = NULL;
switch (lcb.baud_rate = baudrate)
{
case B_1200:
lcb.lt_tmr = LTTMR_12;
lcb.window_tmr = W_TMR_12;
break;
case B_300:
lcb.lt_tmr = LTTMR_3;
lcb.window_tmr = W_TMR_3;
break;
case B_110:
lcb.lt_tmr = LTTMR_110;
lcb.window_tmr = W_TMR_110;
break;
case B_2400:
default:
lcb.lt_tmr = LTTMR_24;
lcb.window_tmr = W_TMR_24;
break;
}
lcb.ack_timer = (lcb.lt_tmr/2)+1;
/* Initialize receive and transmit buffers
*/
rlkb.list = rlkblst;
rlkb.num = 2;
lkb.list = lkblst;
lkb.num = 2;
init_blst(mnpcb->rlkb = &rlkb, MAX_LPDU_SZ, rlkbuff);
init_blst(mnpcb->lkb = &lkb, MAX_LPDU_SZ, lkbuff);
ftb.list = iatblst;
init_blst(mnpcb->ftb = &ftb,64+5, iatbuff);
/* Initialize async driver variables, too
*/
p_mnpcb = mnpcb;
timerins();
drvr_ins();
}
/*LOCAL------------------------------------------------------------------------
link_reset -
-----------------------------------------------------------------------------*/
link_reset()
{
/* Disable interrupts while reseting the link.
*/
clr_int();
/* Reset lcb values - note that attention sequence numbers are not
** reintialized.
*/
lcb.lt_rsn = lcb.lt_ssn = lcb.ltrsn_acked = lcb.ltssn_acked = NULL;
lcb.lt_ret_cnt = lcb.lpdu_type = NULL;
lcb.status_1 &= ~(DATA_READY | ACK_TIMER | RET_TIMER);
lcb.status_2 &= ~(FORCE_ACK | FORCE_RET | ZERO_WNDW | WNDW_TIMER);
lcb.status_3 &= ~(DUP_IGNORED);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -