📄 mnpllvl.c
字号:
/* Reset_timers
*/
ack_tm = fcw_tm = lr_tm = lt_tm = NULL;
/* Reset send and receive framers
*/
sf_busy = sf_lt = modem_out_busy = NULL;
rdle_flg = frame_snt = frame_rcvd = frame_dne =NULL;
sf_state = SF_INIT;
rf_state = RF_INIT;
/* Reset transmit and receive buffers
*/
reset_blst(&rb);
reset_blst(&ftb);
reset_blst(&lkb);
reset_blst(&rlkb);
tbcnt = 0;
p_mnpcb->ld_reason = NULL;
/* Re-enable interrupts.
*/
set_int();
}
/*LOCAL------------------------------------------------------------------------
lpdu_send - send an LPDU other than an LT
-----------------------------------------------------------------------------*/
SIGN_16 lpdu_send(type,wait)
SIGN_16 type,
wait;
{
SIGN_16 retcode; /* return code */
struct BLST *snd_struct; /* LPDU structure */
/* Get a buffer for the LPDU, send the LPDU, then release buffer.
*/
get_b(&lkb,&snd_struct);
retcode = send_pdu(type,wait,snd_struct);
ret_b(&lkb,snd_struct);
/* Exit
*/
return(retcode);
}
/*LOCAL------------------------------------------------------------------------
parse_lr - parse an LR LPDU and perform parameter negotiation
-----------------------------------------------------------------------------*/
SIGN_16 parse_lr()
{
register USIGN_8 *p; /* header pointer */
register USIGN_16 len,
*pi;
/* Initialize
*/
lcb.lr_parm = 0;
p = (rlkb.used_lst)->bptr;
len = *p++ - 2;
/* Process fixed fields
*/
if (*p++ != LR)
{
ret_b(&rlkb,rlkb.used_lst);
return(PROT_ERR);
}
lcb.prot_level = min(lcb.prot_level,*p);
p++;
/* Process variable part
*/
while (len > 0)
{
if (*p == 1) /* skip parm 1 - serial no. */
{
len -= 8;
p += 8;
continue;
}
if (*p == 2) /* take min of service class values */
{
len -= 3;
p += 2;
lcb.lr_parm |= LR_SRV_CLASS;
lcb.srv_class = min(LCL_SCLASS, *p);
p++;
if (lcb.srv_class == 1)
SETBIT1(HDUPLEX)
continue;
}
if (*p == 3) /* take min of window size */
{
len -= 3;
p += 2;
lcb.lr_parm |= LR_WNDW_SZ;
lcb.window_sz = min (lcb.window_sz, *p);
p++;
continue;
}
if (*p == 4)
{
len -= 4;
pi = (SIGN_16 *) (p += 2);
lcb.lr_parm |= LR_DATA_SZ;
lcb.max_data_sz = max (lcb.max_data_sz, *pi);
p += 2;
continue;
}
if (*p > 4) /* ignore anything else */
{
len -= *++p + 2;
p += *p++;
break;
}
}
/* All done with LR in buffer, return the buffer
*/
ret_b(&rlkb,rlkb.used_lst);
/* Now check for parms not received and set default values
*/
if (!(lcb.lr_parm & LR_SRV_CLASS))
lcb.srv_class = 1;
if (!(lcb.lr_parm & LR_WNDW_SZ))
lcb.window_sz = 1;
if (!(lcb.lr_parm & LR_DATA_SZ))
lcb.max_data_sz = BLK_DATA_SZ;
/* There is such a thing as a block-mode MNP link-connection, but
** this implementation will not talk to one (block mode links are
** for use with higher-level MNP protocols).
*/
if (lcb.max_data_sz == BLK_DATA_SZ)
return(BAD_LR_PARMS);
/* Adjust the credit for any receive buffers already used.
*/
lcb.lcl_credit = lcb.window_sz - rb.used;
/* Exit
*/
return(SUCCESS);
}
/*LOCAL------------------------------------------------------------------------
receive_wait - wait for an LPDU during link establishment
-----------------------------------------------------------------------------*/
SIGN_16 receive_wait ()
{
/* Wait for an LPDU to be received or 2 seconds to go by, which ever
** occurs first.
*/
clr_int();
return(event_wait(20,FRAME_RCV));
}
/*LOCAL------------------------------------------------------------------------
retran_lt - handle LT LPDU retransmission
-----------------------------------------------------------------------------*/
SIGN_16 retran_lt()
{
SIGN_16 i,
retcode,
not_done;
register USIGN_16 lts_unacked;
register struct BLST *snd_struct;
not_done = 1;
while (not_done)
{
/* If there are no buffers in use, there is nothing to retransmit.
*/
if (ftb.used == 0)
{
CLRBIT2(FORCE_RET) /* reset force flag */
return(SUCCESS); /* and just exit */
}
/* Check for forced retransmission. If so, clear flag and go right at
** it. Otherwise, retransmit only when retran timer set and expired.
*/
clr_int();
if (BIT2SET(FORCE_RET))
{
CLRBIT2(FORCE_RET)
set_int();
}
else
{
set_int();
if (!BIT1SET(RET_TIMER))
return(SUCCESS);
if (lt_tm)
return (SUCCESS);
}
/* It's time to retransmit. But if we have retransmitted to the limit
** count, terminate the link.
*/
if (lcb.lt_ret_cnt == RET_LIMIT)
{
as_disconnect(RETRAN_TMR_EXP,NULL);
return(FAILURE);
}
/* It's OK to still retransmit if there is remote credit (no need to
** check when window is only 1).
*/
if (lcb.window_sz == 1)
lcb.rem_credit = 0;
else
if (lcb.rem_credit == 0)
return(SUCCESS);
/* Retransmit ALL unacknowledged LT's.
*/
snd_struct = ftb.used_lst;
not_done--;
if (lcb.lt_ssn >= lcb.ltssn_acked)
lts_unacked = lcb.lt_ssn - lcb.ltssn_acked;
else
lts_unacked = (256 - lcb.ltssn_acked) + lcb.lt_ssn;
while (lts_unacked)
{
lts_unacked--;
if (retcode = send_pdu(LT,NOWAIT,snd_struct))
return(retcode);
if (lcb.window_sz == 1)
event_wait(100,FRAME_SND);
if (retcode = acking())
return(retcode);
if (lcb.prot_level == 2)
{
if (retcode = attn_process())
return(retcode);
}
snd_struct = snd_struct->next_b;
/* If forced retransmission, i.e., LA received, we may have received
** another LA acknowledging frames that we would retransmit next. If
** this happened, free up acked transmit buffer(s), then go back to
** beginning. note: if there are buffers in use, say 3 & 4, & if after
** 3 & 4 are retransmitted, we receive an LA for 3, then this logic will
** retransmit 4 again. The last 4 will be ignored by receiver as an
** immediate duplicate.
*/
if (BIT2SET(FORCE_RET) || BIT1SET(LA_RECEIVED))
{
i = ftb.used;
tb_free();
if (i != ftb.used)
{
/* Something has been freed. If all buffers were freed, then we're
** all done. If not, reset flags and do it over again.
*/
if (ftb.used)
{
SETBIT2(FORCE_RET)
not_done++;
break;
}
}
}
}
if (!not_done)
{
lcb.lt_ret_cnt++;
lt_tm = lcb.lt_tmr;
}
}
return(SUCCESS);
}
/*LOCAL------------------------------------------------------------------------
send_la - send an LA LPDU
-----------------------------------------------------------------------------*/
SIGN_16 send_la()
{
SIGN_16 retcode;
/* Check for a zero window. We want to remember sending a zero credit.
** We don't send zero credit, however, when the window is one.
*/
if (!credit_chk())
{
SETBIT2(ZERO_WNDW)
if (lcb.window_sz == 1)
return(SUCCESS);
}
/* Send an LA LPDU. Return if link-connection is lost.
*/
if (retcode = lpdu_send(LA,NOWAIT))
return(retcode);
/* Reset ack and flow control timers.
*/
clr_int();
CLRBIT1(ACK_TIMER)
ack_tm = NULL;
fcw_tm = lcb.window_tmr;
set_int();
/* Exit
*/
return(SUCCESS);
}
/*LOCAL------------------------------------------------------------------------
send_pdu - send an LPDU
-----------------------------------------------------------------------------*/
SIGN_16 send_pdu(type,wait,snd_struct)
SIGN_16 type, /* LPDU type */
wait; /* wait for send to complete */
register struct BLST *snd_struct;
{
register USIGN_8 *p;
USIGN_8 *pli;
USIGN_16 *pi;
SIGN_16 i;
/* Just return if there is no physical connection.
*/
if (lne_stat())
return(NO_PHYSICAL);
/* If the lpdu is an LD, then we want to expedite it. If an lpdu is being
** sent, wait a bit then truncate it. This wait is necessary so that an
** empty frame (which is illegal) is not sent.
*/
if (type == LD && sf_busy)
{
switch (lcb.baud_rate)
{
case B_1200:
i = 10;
break;
case B_300:
i = 20;
break;
case B_110:
i = 30;
break;
default:
i = 5;
}
suspend(i);
sf_len = 0;
while (sf_busy)
;
}
/* Wait for the send framer to finish if a frame is in progress.
*/
clr_int();
while (sf_busy)
if (send_wait())
return(TIME_OUT);
/* Now prepare the requested LPDU.
*/
p = snd_struct->bptr;
switch (type)
{
case LT:
break;
case LA:
*p++ = LA_LEN;
*p++ = LA;
*p++ = 1;
*p++ = 1;
clr_int();
*p++ = lcb.ltrsn_acked = lcb.lt_rsn;
*p++ = 2;
*p++ = 1;
*p = (USIGN_8) credit_chk();
set_int();
break;
case LN:
*p++ = LN_LEN;
*p++ = LN;
*p++ = 1;
*p++ = 1;
*p++ = lcb.ln_ssn;
*p++ = 2;
*p++ = 1;
*p = lcb.ln_stype;
break;
case LNA:
*p++ = LNA_LEN;
*p++ = LNA;
*p++ = 1;
*p++ = 1;
*p = lcb.ln_rsn;
break;
case LR:
pli = p++;
*p++ = LR;
*p++ = lcb.prot_level;
*p++ = 1;
*p++ = 6;
*p++ = 1;
*p++ = 0;
*p++ = 0;
*p++ = 0;
*p++ = 0;
*p++ = 255;
if (BIT1SET(MODE))
{
*pli = LR_ALEN;
if (lcb.lr_parm & LR_SRV_CLASS)
{
*p++ = 2;
*p++ = 1;
*p++ = lcb.srv_class;
*pli += 3;
if (lcb.lr_parm & LR_WNDW_SZ)
{
*p++ = 3;
*p++ = 1;
*p++ = lcb.window_sz;
*pli += 3;
if (lcb.lr_parm & LR_DATA_SZ)
{
*p++ = 4;
*p++ = 2;
pi = (USIGN_16 *) p;
*pi = lcb.max_data_sz;
*pli += 4;
}
}
}
}
else
{
*pli = LR_ILEN;
*p++ = 2;
*p++ = 1;
*p++ = LCL_SCLASS;
*p++ = 3;
*p++ = 1;
*p++ = lcb.window_sz;
*p++ = 4;
*p++ = 2;
pi = (USIGN_16 *) p;
*pi = lcb.max_data_sz;
}
break;
case LD:
*p++ = LD_LEN;
*p++ = LD;
*p++ = 1;
*p++ = 1;
if ((*p = lcb.l_disc_code) == 255)
{
p++;
*p++ = 2;
*p++ = 1;
*p = lcb.u_disc_code;
*(snd_struct->bptr) += 3;
}
break;
}
/* Pause a bit if this is a class 1 connection (hardly likely...)
*/
if (BIT1SET(HDUPLEX))
suspend (20);
/* Set up the interrupt-driven send framer to send the lpdu.
*/
clr_int();
if (type == LT)
sf_len = snd_struct->len;
else
sf_len = *(snd_struct->bptr) + 1;
sf_ptr = snd_struct->bptr;
sf_busy = 1;
trigger_sf();
set_int();
/* Wait for the lpdu to get out, if that was what the caller wanted.
*/
if (wait)
if (send_wait())
return(TIME_OUT);
/* Exit
*/
return(SUCCESS);
}
/*LOCAL------------------------------------------------------------------------
send_wait - wait for transmission of an LPDU or timeout
-----------------------------------------------------------------------------*/
SIGN_16 send_wait()
{
/* Wait 55 seconds (arbitrary number which is larger than the time
** needed to send a long LPDU), or until the LPDU is sent. If the time
** expires and frame send has not completed, return time out. This
** means, effectively, that the hardware is broken.
*/
clr_int();
return(event_wait(550,FRAME_SND));
}
/*LOCAL------------------------------------------------------------------------
tb_free - process acknowledged LT LPDUs
-----------------------------------------------------------------------------*/
tb_free()
{
register struct BLST *bp;
register USIGN_16 acked_lts; /* to hold value between 0 and 65535 */
register USIGN_16 head_ssn;
/* If there are no LT LPDUs unacknowledged, just clear force retransmission
** flag and return.
*/
if (!tbcnt)
{
CLRBIT2(FORCE_RET)
return;
}
/* Some LT LPDU's have been sent. However, only try to free up transmit
** buffers if an LA has been received.
*/
clr_int();
if (BIT1SET(LA_RECEIVED))
{
CLRBIT1(LA_RECEIVED)
set_int();
/* Start freeing at the head of the list of buffers in use. Free until
** the buffer just freed contains the LT with the same seq number as
** that of the last LT positively acked
*/
bp = ftb.used_lst;
head_ssn = (USIGN_8)*(bp->bptr + LT_SEQ);
if (head_ssn <= lcb.ltssn_acked)
acked_lts = lcb.ltssn_acked - head_ssn +1;
else
acked_lts = (256 - head_ssn) + lcb.ltssn_acked + 1;
while (acked_lts)
{
ret_b(&ftb,bp);
bp = bp->next_b;
acked_lts--;
tbcnt--;
}
if (tbcnt < 0)
tbcnt=0;
/* Clear force retransmission flag
*/
CLRBIT2(FORCE_RET)
/* If any LTs remain outstanding, reset the retransmission timer for them.
** Otherwise, be sure that the timer is cancelled. Since something has been
** acknowledged, the retransmission count can also be reset to 0.
*/
if (tbcnt)
{
SETBIT1(RET_TIMER)
lt_tm = lcb.lt_tmr;
ftb.used_lst = bp;
}
else
{
CLRBIT1(RET_TIMER)
lt_tm = 0;
}
lcb.lt_ret_cnt = 0;
}
else
{
set_int();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -