home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / MODEM / MNPC12.ZIP / MNPLLVL.C < prev    next >
Encoding:
C/C++ Source or Header  |  1987-12-28  |  25.4 KB  |  1,308 lines

  1. /*=============================================================================
  2.  
  3.                      The Microcom MNP Library
  4.                     (Microsoft C Version)
  5.  
  6. -------------------------------------------------------------------------------
  7.  
  8.                  MNPLLVL - MNP Link Level Routines
  9.  
  10. -------------------------------------------------------------------------------
  11.  
  12.      Modification History
  13.  
  14.     3/25/87 - Compuserve V1.0
  15.  
  16. =============================================================================*/
  17.  
  18. /* Header files 
  19. */
  20. #include <dos.h>
  21. #include <mnpdat.h>
  22. #include <llvl.h>
  23.  
  24. /* External references
  25. */
  26. extern USIGN_16 sb_cnt;
  27.  
  28. /* Global buffers 
  29. */
  30. struct link_ctl_blk lcb;
  31.  
  32. struct BUFFER rb, ftb, lkb, rlkb;
  33.  
  34. struct BLST lkblst[2],
  35.         rlkblst[2],
  36.         iatblst[8];
  37.  
  38. USIGN_8 lkbuff[MAX_LPDU_SZ * 2];
  39. USIGN_8 rlkbuff[MAX_LPDU_SZ * 2];
  40. USIGN_8 iatbuff[(64+5)*8];
  41.  
  42. USIGN_16 tbcnt;
  43.  
  44. USIGN_16 g_tm,
  45.     ack_tm,
  46.     fcw_tm,
  47.     lr_tm,
  48.     lt_tm,
  49.     ln_tm;
  50.  
  51. USIGN_16 port_add,
  52.     chan_no,
  53.     iir_add;
  54.  
  55. USIGN_8 linestat;
  56.  
  57. /* Function declarations
  58. */
  59. void as_disconnect();
  60. SIGN_16 acking();
  61. SIGN_16 credit_chk();
  62. SIGN_16 lpdu_send();
  63. SIGN_16 parse_lr();
  64. SIGN_16 receive_wait();
  65. SIGN_16 retran_lt();
  66. SIGN_16 send_la();
  67. SIGN_16 send_pdu();
  68. SIGN_16 send_wait();
  69.  
  70. /*GLOBAL********************************************************************
  71.  
  72.     as_connect - establish an MNP link-connection
  73.  
  74. ***************************************************************************/
  75.  
  76. SIGN_16 as_connect (mnpcb,mode)
  77.  
  78. struct MNP_CB *mnpcb;
  79. USIGN_16 mode;
  80. {
  81.  
  82. SIGN_16 lr_cnt,
  83.     la_cnt,
  84.     retcode,
  85.     link_state;
  86.  
  87. /* Initialize
  88. */
  89. lcb.lpdu_type = 0;
  90. link_state = IDLE;
  91.  
  92. for (;;)
  93.     {
  94.  
  95.     switch (link_state)
  96.         {
  97.  
  98.         case IDLE:
  99.             link_init(mnpcb);
  100.             link_reset();
  101.             if (L_ACCEPTOR)
  102.                 {
  103.                 SETBIT1(MODE)
  104.                 link_state = LR_WAIT;
  105.                 }
  106.             else
  107.                 {
  108.                 suspend(5);
  109.                 if (retcode = lpdu_send(LR,WAIT))
  110.                     link_state = LNK_ERROR;
  111.                 else
  112.                     link_state = LR_RESP_WAIT;
  113.                 }
  114.             break;
  115.  
  116.         case LR_RESP_WAIT:
  117.             lr_cnt = LR_RETRAN_CNT;
  118.             retcode = SUCCESS;
  119.             while ((retcode = receive_wait()) || !lcb.lpdu_type)
  120.                 {
  121.                 if (retcode == NO_PHYSICAL)
  122.                     {
  123.                     link_state = LNK_ERROR;
  124.                     break;
  125.                     }
  126.                 if (lr_cnt--)
  127.                     {
  128.                     if (retcode = lpdu_send(LR,WAIT))
  129.                         {
  130.                         link_state = LNK_ERROR;
  131.                         break;
  132.                         }
  133.                     }
  134.                 else
  135.                     {
  136.                     retcode = TIME_OUT;
  137.                     link_state = LNK_ERROR;
  138.                     break;
  139.                     }
  140.                 }
  141.  
  142.             if (retcode == SUCCESS) 
  143.                 link_state = PARMS_NEGO;
  144.             break;
  145.  
  146.         case PARMS_NEGO:
  147.             if (retcode = parse_lr())
  148.                 {
  149.                 as_disconnect(retcode,NULL);
  150.                 return(retcode + LR_CODE);
  151.                 }
  152.  
  153.             if (retcode = lpdu_send(LA,WAIT))
  154.                 link_state = LNK_ERROR;
  155.             else
  156.                 link_state = LNK_CONNECTED;
  157.             break;
  158.  
  159.         case LR_WAIT:
  160.             lr_cnt = 2;
  161.             while ((retcode = receive_wait()) || !lcb.lpdu_type)
  162.                 {
  163.                 if (retcode == NO_PHYSICAL)
  164.                     {
  165.                     link_state = LNK_ERROR;
  166.                     break;
  167.                     }
  168.                 if (!(--lr_cnt))
  169.                     {
  170.                     retcode = TIME_OUT;
  171.                     link_state = LNK_ERROR;
  172.                     break;
  173.                     }
  174.                 }
  175.  
  176.             if (link_state != LR_WAIT)
  177.                 break;
  178.  
  179.             if (retcode = parse_lr())
  180.                 {
  181.                 as_disconnect(retcode,NULL);
  182.                 return(retcode + LR_CODE);
  183.                 }
  184.  
  185.             lr_cnt = LR_TRAN_CNT;
  186.             link_state = CONNECT_REQ_WAIT;
  187.             break;
  188.  
  189.         case CONNECT_REQ_WAIT:
  190.             if (lr_cnt == NULL)
  191.                 {
  192.                 retcode = FAILURE;
  193.                 link_state = LNK_ERROR;
  194.                 break;
  195.                 }
  196.  
  197.             if (retcode = lpdu_send(LR,WAIT))
  198.                 link_state = LNK_ERROR;
  199.             else
  200.                 {
  201.                 lr_cnt--;
  202.                 la_cnt = LA_WAIT_CNT;
  203.                 link_state = LA_WAIT;
  204.                 }
  205.             break;
  206.  
  207.         case LA_WAIT:
  208.             while ((retcode = receive_wait()) || !lcb.lpdu_type)
  209.                 {
  210.                 if (retcode == NO_PHYSICAL)
  211.                     {
  212.                     link_state = LNK_ERROR;
  213.                     break;
  214.                     }
  215.                     if (--la_cnt)
  216.                     {
  217.                     if (retcode = lpdu_send(LR,WAIT))
  218.                         {
  219.                         link_state = LNK_ERROR;
  220.                         break;
  221.                         }
  222.                     }
  223.                 else
  224.                     {
  225.                     retcode = TIME_OUT;
  226.                     link_state = LNK_ERROR;
  227.                     break;
  228.                     }
  229.                 }
  230.  
  231.             if (link_state != LA_WAIT)
  232.                 break;
  233.  
  234.             switch (lcb.lpdu_type)
  235.                 {
  236.                 case LA:
  237.                     lcb.lt_rsn = NULL;
  238.  
  239.                 case LT:
  240.                     link_state = LNK_CONNECTED;
  241.                     break;
  242.  
  243.                 case LR:
  244.                     ret_b (&rlkb,rlkb.used_lst);
  245.                     link_state = CONNECT_REQ_WAIT;
  246.                     break;
  247.     
  248.                 default:
  249.                     retcode = FAILURE;
  250.                     link_state = LNK_ERROR;
  251.                 }
  252.  
  253.             break;
  254.  
  255.         case LNK_ERROR:
  256.             as_disconnect(NULL,NULL);
  257.             return(retcode);
  258.  
  259.         case LNK_CONNECTED:
  260.             dphase_init();
  261.             SETBIT1(LINK_EST)
  262.             return(SUCCESS);
  263.         }
  264.     }
  265. }
  266.  
  267. /*GLOBAL***********************************************************************
  268.  
  269.     as_disconnect - terminate a link-connection
  270.  
  271. ******************************************************************************/
  272.  
  273. void as_disconnect(lreason,ureason)
  274.  
  275. SIGN_16 lreason,
  276.     ureason;
  277. {
  278.  
  279. /* If the link is still up, send an LD LPDU to the other side.  If the
  280. ** caller has supplied a reason code (in ureason) then save this code
  281. ** in the lcb so that it will be sent in the LD.  Wait for the LD to 
  282. ** actually be sent (to the very last byte...). 
  283. */
  284. if (BIT1SET(LINK_EST))
  285.     {
  286.     if ((lcb.l_disc_code = lreason) == 255)
  287.         lcb.u_disc_code = ureason;
  288.     lpdu_send(LD,NOWAIT);
  289.     while (!lne_stat() && modem_out_busy)
  290.         ;
  291.     CLRBIT1(LINK_EST);
  292.     }
  293.  
  294. /* In any case, wait a bit.
  295. */
  296. suspend(10);
  297.  
  298. /* Now remove interrupt handlers - link driver and timers. 
  299. */
  300. drvr_rem();
  301. timerrem();
  302.  
  303. }
  304.  
  305. /*GLOBAL********************************************************************
  306.  
  307.     as_link - maintain a link-connection
  308.  
  309. ***************************************************************************/
  310.  
  311. SIGN_16 as_link()
  312. {
  313.  
  314. SIGN_16 retcode;
  315.  
  316. /* If the link-connection has failed, return reporting link down. 
  317. */
  318. if (!BIT1SET(LINK_EST))
  319.     return (LNK_DOWN);
  320.  
  321. /* If the physical connection has been lost, return reporting p-conn down. 
  322. */
  323. if (lne_stat())
  324.     return (NO_PHYSICAL);
  325.  
  326. /* If we support attention service, go see if we have any to process. 
  327. */
  328. if (lcb.prot_level == 2)
  329.     {
  330.     if (retcode = attn_process())
  331.         return(retcode);
  332.     }
  333.  
  334. /* Go see if it's time to send an ack. 
  335. */
  336. if (retcode = acking())
  337.     return(retcode);
  338.  
  339. /* Try to free up any transmit buffers which have been acked. 
  340. */
  341. tb_free();
  342.  
  343. /* Go see if we have to retransmit. 
  344. */
  345. if (retcode = retran_lt())
  346.     return(retcode);
  347.  
  348. /* Make sure link is still up one more time 
  349. */
  350. if (!BIT1SET(LINK_EST))
  351.     return(LNK_DOWN);
  352.  
  353. /* Exit 
  354. */
  355. return(SUCCESS);
  356. }
  357.  
  358. /*LOCAL------------------------------------------------------------------------
  359.  
  360.     acking - send an LA LPDU if an ack condition is present
  361.  
  362. -----------------------------------------------------------------------------*/
  363.  
  364. SIGN_16 acking()
  365. {
  366.  
  367. SIGN_16 retcode,                /* return code */
  368.     lt_unacked;                 /* number of unacked LTs */
  369.  
  370. /* If the force ack flag is set, send an LA right away.
  371. */
  372. clr_int();                    /* protect flag access */
  373. if (BIT2SET(FORCE_ACK))            /* reset flag if set */
  374.     {
  375.     CLRBIT2(FORCE_ACK)
  376.     set_int();
  377.     return(send_la());            /* send LA and return */
  378.     }
  379. set_int();
  380.  
  381. /* If the window timer is enabled and has expired, send an LA. 
  382. */
  383. if (BIT2SET(WNDW_TIMER) && (fcw_tm == 0))
  384.     return(send_la());
  385.  
  386. /* If there are unacknowledged LT's, it may be time to send an LA. 
  387. */
  388. if (lt_unacked = lcb.lt_rsn - lcb.ltrsn_acked)
  389.     {
  390.  
  391. /* If there is no user data to send (i.e. no reason to put it off)
  392. ** send an LA.
  393. */
  394.     if (sb_cnt == 0)
  395.         return(send_la());
  396.  
  397. /* If the acknowledgment threshold has been reached, send an LA.
  398. */
  399.     if (lt_unacked >= lcb.ack_threshold)
  400.         return(send_la());
  401.  
  402. /* If the ack timer has elapsed, send an LA.  Otherwise, set the timer.
  403. */
  404.     if (BIT1SET(ACK_TIMER))
  405.         {
  406.         if (ack_tm)
  407.             return(SUCCESS);
  408.         else
  409.             return(send_la());
  410.         }
  411.     else
  412.         {
  413.         SETBIT1(ACK_TIMER)
  414.         ack_tm = lcb.ack_timer;
  415.         return(SUCCESS);
  416.         }
  417.     }
  418.  
  419. /* If there are no unacknowledged LT's, handle the 'zero window
  420. ** opening' case.
  421. */
  422. else
  423.     {
  424.     if (BIT2SET(ZERO_WNDW) && credit_chk())
  425.         {
  426.         CLRBIT2(ZERO_WNDW)
  427.         return(send_la());
  428.         }
  429.     }
  430.  
  431. /* Exit 
  432. */
  433. return(SUCCESS);
  434. }
  435.  
  436. /*LOCAL------------------------------------------------------------------------
  437.  
  438.     attn_process - handle break signalling
  439.  
  440. -----------------------------------------------------------------------------*/
  441.  
  442. attn_process()
  443. {
  444.  
  445. SIGN_16 retcode;
  446.  
  447. /* If the LN timer is set and has expired, it is time to retransmit the
  448. ** last LN LPDU sent.  However, if the retransmission limit has been
  449. ** reached, then the link is unusable.  Terminate the link and return
  450. ** with a function value=retran limit reached.
  451. */
  452. if (BIT3SET(LN_TIMER) && (ln_tm == 0))
  453.     {
  454.     if (lcb.ln_ret_cnt == RET_LIMIT)
  455.         {
  456.         as_disconnect(RETRAN_TMR_EXP,NULL);
  457.         return(-67);
  458.         }
  459.     if (retcode = lpdu_send(LN,NOWAIT))
  460.         return(retcode);
  461.     ++lcb.ln_ret_cnt;
  462.     SETBIT3(LN_SENT)
  463.  
  464.     clr_int();
  465.     SETBIT3(LN_TIMER)
  466.     ln_tm=lcb.lt_tmr;
  467.     set_int();
  468.     }
  469.  
  470. /* If an LN has been received, check its type for a destructive break
  471. ** signal.  Reset the link on receipt of a destructive break.
  472. */
  473. clr_int();
  474. if (BIT3SET(LN_RECEIVED))
  475.     {
  476.     CLRBIT3(LN_RECEIVED)            
  477.     if (lcb.ln_rtype == 1)
  478.         {
  479.         link_reset();
  480.         dphase_init();
  481.         }
  482.     set_int();
  483.     if (retcode = lpdu_send(LNA,NOWAIT))
  484.         return(retcode);
  485.     }
  486. set_int();
  487.  
  488. /* Check for need to send an LNA
  489. */
  490. if (BIT3SET(FORCE_LNA))
  491.     {
  492.     CLRBIT3(FORCE_LNA)
  493.     if (retcode = lpdu_send(LNA,NOWAIT))
  494.         return(retcode);
  495.     }
  496.  
  497. /* Exit 
  498. */
  499. return(SUCCESS);
  500. }
  501.  
  502. /*LOCAL------------------------------------------------------------------------
  503.  
  504.     credit_chk - determine local ability to receive
  505.  
  506. -----------------------------------------------------------------------------*/
  507.  
  508. SIGN_16 credit_chk()
  509. {
  510.  
  511. extern USIGN_16 rb_cnt;
  512.  
  513. /* Compute the number of LT LPDUs which can be received.  This is
  514. ** the number of max sized LT's which will fit into the receive
  515. ** ring buffer.  This number can not be larger than maximum window
  516. ** (8 for this implementation).
  517. */
  518. lcb.lcl_credit = (RBUF_LEN - rb_cnt) / lcb.max_data_sz;
  519. if (lcb.lcl_credit > lcb.window_sz)
  520.     lcb.lcl_credit = lcb.window_sz;
  521.  
  522. /* Exit.  Function value is receive credit. 
  523. */
  524. return(lcb.lcl_credit);
  525. }
  526.  
  527. /*LOCAL------------------------------------------------------------------------
  528.  
  529.     dphase_init - perform data phase initialization
  530.  
  531. -----------------------------------------------------------------------------*/
  532.  
  533. dphase_init()
  534. {
  535.  
  536. SIGN_16 i;
  537.  
  538. /* Set initial credits equal to negotiated maximum credit. 
  539. */
  540. lcb.lcl_credit = lcb.rem_credit = lcb.window_sz;
  541.  
  542. /* Compute ack threshold 
  543. */
  544. lcb.ack_threshold = (i = lcb.window_sz / 2) ? i : 1;
  545.  
  546. /* Be sure that ack conditions are reset. 
  547. */
  548. CLRBIT1(LA_RECEIVED)
  549. CLRBIT2(FORCE_ACK)
  550.  
  551. /* If window == 1, lt retran timer is specified to be 8 seconds
  552. */
  553. if (lcb.window_sz == 1)
  554.     lcb.lt_tmr = 8;
  555. else
  556.     {
  557.     SETBIT2(WNDW_TIMER)
  558.     fcw_tm = lcb.window_tmr;
  559.     }
  560. }
  561.  
  562. /*LOCAL------------------------------------------------------------------------
  563.  
  564.     link_init - perform one-time link initialization
  565.  
  566. -----------------------------------------------------------------------------*/
  567.  
  568. link_init(mnpcb)
  569.  
  570. register struct MNP_CB *mnpcb;
  571. {
  572.  
  573. /* Initialize link control block values 
  574. */
  575. lcb.status_1 = lcb.status_2 = lcb.status_3 = NULL;
  576.  
  577. ftb.num = lcb.window_sz = STRM_WNDW_SZ;
  578. lcb.max_data_sz = STRM_DATA_SZ;
  579.  
  580. lcb.prot_level = 2;
  581. lcb.srv_class = LCL_SCLASS;
  582.  
  583. lcb.ln_rsn = lcb.ln_ssn = lcb.ln_ret_cnt = ln_tm = NULL;
  584.  
  585. switch (lcb.baud_rate = baudrate)
  586.     {
  587.     case B_1200:
  588.         lcb.lt_tmr = LTTMR_12;
  589.         lcb.window_tmr = W_TMR_12;
  590.         break;
  591.  
  592.     case B_300:
  593.         lcb.lt_tmr = LTTMR_3;
  594.         lcb.window_tmr = W_TMR_3;
  595.         break;
  596.  
  597.     case B_110:
  598.         lcb.lt_tmr = LTTMR_110;
  599.         lcb.window_tmr = W_TMR_110;
  600.         break;
  601.  
  602.     case B_2400:
  603.     default:
  604.         lcb.lt_tmr = LTTMR_24;
  605.         lcb.window_tmr = W_TMR_24;
  606.         break;
  607.     }
  608.  
  609. lcb.ack_timer = (lcb.lt_tmr/2)+1;
  610.  
  611. /* Initialize receive and transmit buffers 
  612. */
  613. rlkb.list = rlkblst;
  614. rlkb.num = 2;
  615. lkb.list = lkblst;
  616. lkb.num = 2;
  617.  
  618. init_blst(mnpcb->rlkb = &rlkb, MAX_LPDU_SZ, rlkbuff);
  619. init_blst(mnpcb->lkb = &lkb, MAX_LPDU_SZ, lkbuff);
  620.  
  621. ftb.list = iatblst;
  622. init_blst(mnpcb->ftb = &ftb,64+5, iatbuff);
  623.  
  624. /* Initialize async driver variables, too 
  625. */
  626. p_mnpcb = mnpcb;
  627. timerins();
  628. drvr_ins();
  629.  
  630. }
  631.  
  632. /*LOCAL------------------------------------------------------------------------
  633.  
  634.     link_reset - 
  635.  
  636. -----------------------------------------------------------------------------*/
  637.  
  638. link_reset()
  639. {
  640.  
  641. /* Disable interrupts while reseting the link.
  642. */
  643. clr_int();
  644.  
  645. /* Reset lcb values - note that attention sequence numbers are not
  646. ** reintialized.
  647. */
  648. lcb.lt_rsn = lcb.lt_ssn = lcb.ltrsn_acked = lcb.ltssn_acked = NULL;
  649. lcb.lt_ret_cnt = lcb.lpdu_type = NULL;
  650.  
  651. lcb.status_1 &= ~(DATA_READY | ACK_TIMER | RET_TIMER);
  652. lcb.status_2 &= ~(FORCE_ACK | FORCE_RET | ZERO_WNDW | WNDW_TIMER);
  653. lcb.status_3 &= ~(DUP_IGNORED);
  654.  
  655. /* Reset_timers 
  656. */
  657. ack_tm = fcw_tm = lr_tm = lt_tm  = NULL;
  658.  
  659. /* Reset send and receive framers 
  660. */
  661. sf_busy = sf_lt = modem_out_busy = NULL;
  662. rdle_flg = frame_snt = frame_rcvd = frame_dne =NULL;
  663. sf_state = SF_INIT;
  664. rf_state = RF_INIT;
  665.  
  666. /* Reset transmit and receive buffers 
  667. */
  668. reset_blst(&rb);
  669. reset_blst(&ftb);
  670. reset_blst(&lkb);
  671. reset_blst(&rlkb);
  672.  
  673. tbcnt = 0;
  674.  
  675. p_mnpcb->ld_reason = NULL;
  676.  
  677. /* Re-enable interrupts.
  678. */
  679. set_int();
  680.  
  681. }
  682.  
  683. /*LOCAL------------------------------------------------------------------------
  684.  
  685.     lpdu_send - send an LPDU other than an LT
  686.  
  687. -----------------------------------------------------------------------------*/
  688.  
  689. SIGN_16 lpdu_send(type,wait)
  690.  
  691. SIGN_16 type,
  692.     wait;
  693. {
  694.  
  695. SIGN_16 retcode;                 /* return code */
  696. struct BLST *snd_struct;            /* LPDU structure */
  697.  
  698. /* Get a buffer for the LPDU, send the LPDU, then release buffer. 
  699. */
  700. get_b(&lkb,&snd_struct);
  701. retcode = send_pdu(type,wait,snd_struct);
  702. ret_b(&lkb,snd_struct);
  703.  
  704. /* Exit 
  705. */
  706. return(retcode);
  707. }
  708.  
  709. /*LOCAL------------------------------------------------------------------------
  710.  
  711.     parse_lr - parse an LR LPDU and perform parameter negotiation
  712.  
  713. -----------------------------------------------------------------------------*/
  714.  
  715. SIGN_16 parse_lr()
  716.  
  717. {
  718.  
  719. register USIGN_8 *p;            /* header pointer */
  720. register USIGN_16 len,
  721.             *pi;
  722.  
  723. /* Initialize 
  724. */
  725. lcb.lr_parm = 0;
  726. p = (rlkb.used_lst)->bptr;
  727. len = *p++ - 2;
  728.  
  729. /* Process fixed fields 
  730. */
  731. if (*p++ != LR)
  732.     {
  733.     ret_b(&rlkb,rlkb.used_lst);
  734.     return(PROT_ERR);
  735.     }
  736.  
  737. lcb.prot_level = min(lcb.prot_level,*p);
  738. p++;
  739.  
  740. /* Process variable part 
  741. */
  742. while (len > 0)
  743.     {
  744.     if (*p == 1)            /* skip parm 1 - serial no. */
  745.         {
  746.         len -= 8;
  747.         p += 8;
  748.         continue;
  749.         }
  750.  
  751.     if (*p == 2)            /* take min of service class values */
  752.         {
  753.         len -= 3;
  754.         p += 2;
  755.         lcb.lr_parm |= LR_SRV_CLASS;
  756.         lcb.srv_class = min(LCL_SCLASS, *p);
  757.         p++;
  758.         if (lcb.srv_class == 1)
  759.             SETBIT1(HDUPLEX)
  760.         continue;
  761.         }
  762.  
  763.     if (*p == 3)            /* take min of window size */
  764.         {
  765.         len -= 3;
  766.         p += 2;
  767.         lcb.lr_parm |= LR_WNDW_SZ;
  768.         lcb.window_sz = min (lcb.window_sz, *p);
  769.         p++;
  770.         continue;
  771.         }
  772.  
  773.     if (*p == 4)
  774.         {
  775.         len -= 4;
  776.         pi = (SIGN_16 *) (p += 2);
  777.         lcb.lr_parm |= LR_DATA_SZ;
  778.         lcb.max_data_sz = max (lcb.max_data_sz, *pi);
  779.         p += 2;
  780.         continue;
  781.         }
  782.  
  783.     if (*p > 4)            /* ignore anything else */
  784.         {
  785.         len -= *++p + 2;
  786.         p += *p++;
  787.         break;
  788.         }
  789.     }
  790.  
  791. /* All done with LR in buffer, return the buffer 
  792. */
  793. ret_b(&rlkb,rlkb.used_lst);
  794.  
  795. /* Now check for parms not received and set default values 
  796. */
  797. if (!(lcb.lr_parm & LR_SRV_CLASS))
  798.     lcb.srv_class = 1;
  799.  
  800. if (!(lcb.lr_parm & LR_WNDW_SZ))
  801.     lcb.window_sz = 1;
  802.  
  803. if (!(lcb.lr_parm & LR_DATA_SZ))
  804.     lcb.max_data_sz = BLK_DATA_SZ;
  805.  
  806. /* There is such a thing as a block-mode MNP link-connection, but
  807. ** this implementation will not talk to one (block mode links are
  808. ** for use with higher-level MNP protocols). 
  809. */
  810. if (lcb.max_data_sz == BLK_DATA_SZ)
  811.     return(BAD_LR_PARMS);
  812.  
  813. /* Adjust the credit for any receive buffers already used.
  814. */
  815. lcb.lcl_credit = lcb.window_sz - rb.used;
  816.  
  817. /* Exit 
  818. */
  819. return(SUCCESS);
  820. }
  821.  
  822. /*LOCAL------------------------------------------------------------------------
  823.  
  824.     receive_wait -  wait for an LPDU during link establishment
  825.  
  826. -----------------------------------------------------------------------------*/
  827.  
  828. SIGN_16 receive_wait ()
  829. {
  830.  
  831. /* Wait for an LPDU to be received or 2 seconds to go by, which ever
  832. ** occurs first.
  833. */
  834. clr_int();
  835. return(event_wait(20,FRAME_RCV));
  836.  
  837. }
  838.  
  839. /*LOCAL------------------------------------------------------------------------
  840.  
  841.     retran_lt - handle LT LPDU retransmission
  842.  
  843. -----------------------------------------------------------------------------*/
  844.  
  845. SIGN_16 retran_lt()
  846. {
  847.  
  848. SIGN_16 i,
  849.     retcode,
  850.     not_done;
  851. register USIGN_16 lts_unacked;
  852. register struct BLST *snd_struct;
  853.  
  854. not_done = 1;
  855. while (not_done)
  856.     {
  857.  
  858. /* If there are no buffers in use, there is nothing to retransmit. 
  859. */
  860.     if (ftb.used == 0)
  861.         {
  862.         CLRBIT2(FORCE_RET)            /* reset force flag */
  863.         return(SUCCESS);            /* and just exit */
  864.         }
  865.  
  866. /* Check for forced retransmission.  If so, clear flag and go right at
  867. ** it.  Otherwise, retransmit only when retran timer set and expired.
  868. */
  869.     clr_int();
  870.     if (BIT2SET(FORCE_RET))
  871.         {
  872.         CLRBIT2(FORCE_RET)
  873.         set_int();
  874.         }
  875.     else
  876.         {
  877.         set_int();
  878.         if (!BIT1SET(RET_TIMER))
  879.                 return(SUCCESS);
  880.     if (lt_tm)
  881.         return (SUCCESS);
  882.     }
  883.  
  884. /* It's time to retransmit. But if we have retransmitted to the limit
  885. ** count, terminate the link.
  886. */
  887.     if (lcb.lt_ret_cnt == RET_LIMIT)
  888.         {
  889.         as_disconnect(RETRAN_TMR_EXP,NULL);
  890.         return(FAILURE);
  891.         }
  892.  
  893. /* It's OK to still retransmit if there is remote credit (no need to
  894. ** check when window is only 1).
  895. */
  896.     if (lcb.window_sz == 1)
  897.         lcb.rem_credit = 0;
  898.     else
  899.         if (lcb.rem_credit == 0)
  900.             return(SUCCESS);
  901.  
  902. /* Retransmit ALL unacknowledged LT's.
  903. */
  904.     snd_struct = ftb.used_lst;
  905.     not_done--;
  906.  
  907.     if (lcb.lt_ssn >= lcb.ltssn_acked)
  908.         lts_unacked = lcb.lt_ssn - lcb.ltssn_acked;
  909.     else
  910.         lts_unacked = (256 - lcb.ltssn_acked) + lcb.lt_ssn;
  911.  
  912.     while (lts_unacked)
  913.         {
  914.         lts_unacked--;
  915.         if (retcode = send_pdu(LT,NOWAIT,snd_struct))
  916.             return(retcode);
  917.  
  918.         if (lcb.window_sz == 1) 
  919.             event_wait(100,FRAME_SND);
  920.  
  921.         if (retcode = acking())
  922.             return(retcode);
  923.         if (lcb.prot_level == 2)
  924.             {
  925.                 if (retcode = attn_process())
  926.                 return(retcode);
  927.             }
  928.  
  929.         snd_struct = snd_struct->next_b;
  930.  
  931. /* If forced retransmission, i.e., LA received, we may have received
  932. ** another LA acknowledging frames that we would retransmit next.  If
  933. ** this happened, free up acked transmit buffer(s), then go back to
  934. ** beginning.  note: if there are buffers in use, say 3 & 4, & if after
  935. ** 3 & 4 are retransmitted, we receive an LA for 3, then this logic will
  936. ** retransmit 4 again. The last 4 will be ignored by receiver as an 
  937. ** immediate duplicate.
  938. */
  939.         if (BIT2SET(FORCE_RET) || BIT1SET(LA_RECEIVED))
  940.             {
  941.             i = ftb.used;
  942.             tb_free();
  943.             if (i != ftb.used)
  944.                 {
  945. /* Something has been freed.  If all buffers were freed, then we're
  946. ** all done.  If not, reset flags and do it over again.
  947. */
  948.                     if (ftb.used)
  949.                     {
  950.                     SETBIT2(FORCE_RET)
  951.                     not_done++;
  952.                     break;
  953.                     }
  954.                     }
  955.             }
  956.         }
  957.  
  958.     if (!not_done)
  959.         {
  960.         lcb.lt_ret_cnt++;
  961.         lt_tm = lcb.lt_tmr;
  962.         }
  963.     }
  964.     return(SUCCESS);
  965. }
  966.  
  967. /*LOCAL------------------------------------------------------------------------
  968.  
  969.     send_la - send an LA LPDU
  970.  
  971. -----------------------------------------------------------------------------*/
  972.  
  973. SIGN_16 send_la()
  974. {
  975.  
  976. SIGN_16 retcode;
  977.  
  978. /* Check for a zero window.  We want to remember sending a zero credit.
  979. ** We don't send zero credit, however, when the window is one. 
  980. */
  981. if (!credit_chk())
  982.     {
  983.     SETBIT2(ZERO_WNDW)
  984.     if (lcb.window_sz == 1)
  985.         return(SUCCESS);
  986.     }
  987.  
  988. /* Send an LA LPDU.  Return if link-connection is lost. 
  989. */
  990. if (retcode = lpdu_send(LA,NOWAIT))
  991.     return(retcode);
  992.  
  993. /* Reset ack and flow control timers. 
  994. */
  995. clr_int();
  996. CLRBIT1(ACK_TIMER)
  997. ack_tm = NULL;
  998. fcw_tm = lcb.window_tmr;
  999. set_int();
  1000.  
  1001. /* Exit 
  1002. */
  1003. return(SUCCESS);
  1004. }
  1005.  
  1006. /*LOCAL------------------------------------------------------------------------
  1007.  
  1008.     send_pdu - send an LPDU
  1009.  
  1010. -----------------------------------------------------------------------------*/
  1011.  
  1012. SIGN_16 send_pdu(type,wait,snd_struct)
  1013.  
  1014. SIGN_16 type,                    /* LPDU type */
  1015.     wait;                        /* wait for send to complete */
  1016. register struct BLST *snd_struct;
  1017. {
  1018.  
  1019. register USIGN_8 *p;
  1020. USIGN_8 *pli;
  1021. USIGN_16 *pi;
  1022. SIGN_16 i;
  1023.  
  1024. /* Just return if there is no physical connection. 
  1025. */
  1026. if (lne_stat())
  1027.     return(NO_PHYSICAL);
  1028.  
  1029. /* If the lpdu is an LD, then we want to expedite it.  If an lpdu is being
  1030. ** sent, wait a bit then truncate it.  This wait is necessary so that an
  1031. ** empty frame (which is illegal) is not sent. 
  1032. */
  1033. if (type == LD && sf_busy)
  1034.     {
  1035.     switch (lcb.baud_rate)
  1036.         {    
  1037.         case B_1200:
  1038.             i = 10;
  1039.             break;
  1040.  
  1041.         case B_300:
  1042.             i = 20;
  1043.             break;
  1044.  
  1045.         case B_110:
  1046.             i = 30;
  1047.             break;
  1048.  
  1049.         default:
  1050.             i = 5;
  1051.         }
  1052.  
  1053.     suspend(i);
  1054.     sf_len = 0;
  1055.     
  1056.     while (sf_busy)
  1057.         ;
  1058.     }
  1059.  
  1060. /* Wait for the send framer to finish if a frame is in progress.  
  1061. */
  1062. clr_int();
  1063. while (sf_busy)
  1064.     if (send_wait())
  1065.         return(TIME_OUT);
  1066.  
  1067. /* Now prepare the requested LPDU.
  1068. */
  1069. p = snd_struct->bptr;
  1070.  
  1071. switch (type)
  1072.     {
  1073.     case LT:
  1074.         break;
  1075.  
  1076.     case LA:
  1077.         *p++ = LA_LEN;
  1078.         *p++ = LA;
  1079.         *p++ = 1;
  1080.         *p++ = 1;
  1081.         clr_int();
  1082.         *p++ = lcb.ltrsn_acked = lcb.lt_rsn;
  1083.         *p++ = 2;
  1084.         *p++ = 1;
  1085.         *p  = (USIGN_8) credit_chk();
  1086.         set_int();
  1087.         break;
  1088.  
  1089.     case LN:
  1090.         *p++ = LN_LEN;
  1091.         *p++ = LN;
  1092.         *p++ = 1;
  1093.         *p++ = 1;
  1094.         *p++ = lcb.ln_ssn;
  1095.         *p++ = 2;
  1096.         *p++ = 1;
  1097.         *p = lcb.ln_stype;
  1098.         break;
  1099.  
  1100.     case LNA:
  1101.         *p++ = LNA_LEN;
  1102.         *p++ = LNA;
  1103.         *p++ = 1;
  1104.         *p++ = 1;
  1105.         *p = lcb.ln_rsn;
  1106.         break;
  1107.  
  1108.     case LR:
  1109.         pli = p++;
  1110.         *p++ = LR;
  1111.         *p++ = lcb.prot_level;
  1112.         *p++ = 1;
  1113.         *p++ = 6;
  1114.         *p++ = 1;
  1115.         *p++ = 0;
  1116.         *p++ = 0;
  1117.         *p++ = 0;
  1118.         *p++ = 0;
  1119.         *p++ = 255;
  1120.         if (BIT1SET(MODE))
  1121.             {
  1122.                 *pli = LR_ALEN;
  1123.             if (lcb.lr_parm & LR_SRV_CLASS)
  1124.                 {
  1125.                 *p++ = 2;
  1126.                 *p++ = 1;
  1127.                 *p++ = lcb.srv_class;
  1128.                 *pli += 3;
  1129.                 
  1130.                 if (lcb.lr_parm & LR_WNDW_SZ)
  1131.                     {
  1132.                         *p++ = 3;
  1133.                         *p++ = 1;
  1134.                         *p++ = lcb.window_sz;
  1135.                         *pli += 3;
  1136.             
  1137.                     if (lcb.lr_parm & LR_DATA_SZ)
  1138.                         {
  1139.                         *p++ = 4;
  1140.                         *p++ = 2;
  1141.                         pi = (USIGN_16 *) p;
  1142.                         *pi = lcb.max_data_sz;
  1143.                         *pli += 4;
  1144.                         }
  1145.                         }
  1146.                 }
  1147.                 }
  1148.         else
  1149.             {
  1150.             *pli = LR_ILEN;
  1151.             *p++ = 2;
  1152.             *p++ = 1;
  1153.             *p++ = LCL_SCLASS;
  1154.             *p++ = 3;
  1155.             *p++ = 1;
  1156.             *p++ = lcb.window_sz;
  1157.             *p++ = 4;
  1158.             *p++ = 2;
  1159.             pi = (USIGN_16 *) p;
  1160.             *pi = lcb.max_data_sz;
  1161.             }
  1162.         break;
  1163.  
  1164.     case LD:
  1165.         *p++ = LD_LEN;
  1166.         *p++ = LD;
  1167.         *p++ = 1;
  1168.         *p++ = 1;
  1169.         if ((*p = lcb.l_disc_code) == 255)
  1170.             {
  1171.             p++;
  1172.                 *p++ = 2;
  1173.                 *p++ = 1;
  1174.                 *p = lcb.u_disc_code;
  1175.                 *(snd_struct->bptr) += 3;
  1176.                 }
  1177.         break;
  1178.     }
  1179.  
  1180. /* Pause a bit if this is a class 1 connection (hardly likely...)
  1181. */
  1182. if (BIT1SET(HDUPLEX))
  1183.     suspend (20);
  1184.  
  1185. /* Set up the interrupt-driven send framer to send the lpdu.
  1186. */
  1187. clr_int();
  1188. if (type == LT)
  1189.     sf_len = snd_struct->len;
  1190. else
  1191.     sf_len = *(snd_struct->bptr) + 1;
  1192.  
  1193. sf_ptr = snd_struct->bptr;
  1194. sf_busy = 1;
  1195. trigger_sf();
  1196. set_int();
  1197.  
  1198. /* Wait for the lpdu to get out, if that was what the caller wanted.
  1199. */
  1200. if (wait)
  1201.     if (send_wait()) 
  1202.         return(TIME_OUT);
  1203.  
  1204. /* Exit
  1205. */
  1206. return(SUCCESS);
  1207. }
  1208.  
  1209. /*LOCAL------------------------------------------------------------------------
  1210.  
  1211.     send_wait - wait for transmission of an LPDU or timeout
  1212.  
  1213. -----------------------------------------------------------------------------*/
  1214.  
  1215. SIGN_16 send_wait()
  1216. {
  1217.  
  1218. /* Wait 55 seconds (arbitrary number which is larger than the time
  1219. ** needed to send a long LPDU), or until the LPDU is sent. If the time
  1220. ** expires and frame send has not completed, return time out.  This
  1221. ** means, effectively, that the hardware is broken.
  1222. */
  1223. clr_int();
  1224. return(event_wait(550,FRAME_SND));
  1225.  
  1226. }
  1227.  
  1228. /*LOCAL------------------------------------------------------------------------
  1229.  
  1230.     tb_free - process acknowledged LT LPDUs
  1231.  
  1232. -----------------------------------------------------------------------------*/
  1233.  
  1234. tb_free()
  1235. {
  1236.  
  1237. register struct BLST *bp;
  1238. register USIGN_16 acked_lts;        /* to hold value between 0 and 65535 */
  1239. register USIGN_16 head_ssn;
  1240.  
  1241. /* If there are no LT LPDUs unacknowledged, just clear force retransmission
  1242. ** flag and return. 
  1243. */
  1244. if (!tbcnt)
  1245.     {
  1246.     CLRBIT2(FORCE_RET)
  1247.     return;
  1248.     }
  1249.  
  1250. /* Some LT LPDU's have been sent.  However, only try to free up transmit
  1251. ** buffers if an LA has been received. 
  1252. */
  1253. clr_int();
  1254. if (BIT1SET(LA_RECEIVED))    
  1255.     {
  1256.     CLRBIT1(LA_RECEIVED)
  1257.     set_int();
  1258.  
  1259. /* Start freeing at the head of the list of buffers in use.  Free until
  1260. ** the buffer just freed contains the LT with the same seq number as
  1261. ** that of the last LT positively acked 
  1262. */
  1263.     bp = ftb.used_lst;
  1264.  
  1265.     head_ssn = (USIGN_8)*(bp->bptr + LT_SEQ);
  1266.  
  1267.     if (head_ssn <= lcb.ltssn_acked)
  1268.         acked_lts = lcb.ltssn_acked - head_ssn +1;
  1269.     else
  1270.         acked_lts = (256 - head_ssn) + lcb.ltssn_acked + 1;
  1271.  
  1272.     while (acked_lts)
  1273.         {
  1274.         ret_b(&ftb,bp);
  1275.         bp = bp->next_b;
  1276.         acked_lts--;
  1277.         tbcnt--;
  1278.         }
  1279.     if (tbcnt < 0)
  1280.         tbcnt=0;
  1281.  
  1282. /* Clear force retransmission flag 
  1283. */
  1284.     CLRBIT2(FORCE_RET)
  1285.  
  1286. /* If any LTs remain outstanding, reset the retransmission timer for them.
  1287. ** Otherwise, be sure that the timer is cancelled. Since something has been
  1288. ** acknowledged, the retransmission count can also be reset to 0. 
  1289. */
  1290.     if (tbcnt)
  1291.         {
  1292.         SETBIT1(RET_TIMER)
  1293.         lt_tm = lcb.lt_tmr;
  1294.         ftb.used_lst = bp;
  1295.         }
  1296.     else
  1297.         {
  1298.         CLRBIT1(RET_TIMER)
  1299.         lt_tm = 0;
  1300.         }
  1301.     lcb.lt_ret_cnt = 0;
  1302.     }
  1303. else
  1304.     {
  1305.     set_int();
  1306.         }
  1307. }
  1308.