141703Ssklower /* 241703Ssklower * Copyright (c) University of British Columbia, 1984 341703Ssklower * Copyright (c) 1990 The Regents of the University of California. 441703Ssklower * All rights reserved. 541703Ssklower * 641703Ssklower * This code is derived from software contributed to Berkeley by 741703Ssklower * the Laboratory for Computation Vision and the Computer Science Department 841703Ssklower * of the University of British Columbia. 941703Ssklower * 1041703Ssklower * %sccs.include.redist.c% 1141703Ssklower * 12*43361Ssklower * @(#)hd_output.c 7.3 (Berkeley) 06/21/90 1341703Ssklower */ 1441587Ssklower 1541587Ssklower #include "../h/param.h" 1641587Ssklower #include "../h/systm.h" 1741587Ssklower #include "../h/mbuf.h" 1841587Ssklower #include "../h/domain.h" 1941587Ssklower #include "../h/socket.h" 2041587Ssklower #include "../h/protosw.h" 2141587Ssklower #include "../h/errno.h" 2241587Ssklower #include "../h/time.h" 2341587Ssklower #include "../h/kernel.h" 2441587Ssklower #include "../net/if.h" 2541587Ssklower 2641587Ssklower #include "../netccitt/hdlc.h" 2741587Ssklower #include "../netccitt/hd_var.h" 2841587Ssklower #include "../netccitt/x25.h" 2941587Ssklower 3041587Ssklower /* 3141587Ssklower * HDLC OUTPUT INTERFACE 3241587Ssklower * 3341587Ssklower * This routine is called when the X.25 packet layer output routine 3441587Ssklower * has a information frame (iframe) to write. It is also called 3541587Ssklower * by the input and control routines of the HDLC layer. 3641587Ssklower */ 3741587Ssklower 38*43361Ssklower hd_output (m, info) 3941587Ssklower register struct mbuf *m; 40*43361Ssklower caddr_t info; 4141587Ssklower { 42*43361Ssklower register struct hdcb *hdp = (struct hdcb *)info; 43*43361Ssklower struct x25config *xcp; 4441587Ssklower 4541587Ssklower if (m == NULL) 4641587Ssklower panic ("hd_output"); 4741587Ssklower 4841587Ssklower if (hdp->hd_state != ABM) { 4941587Ssklower m_freem (m); 5041587Ssklower return; 5141587Ssklower } 5241587Ssklower 5341587Ssklower /* 5441587Ssklower * Make room for the hdlc header either by prepending 5541587Ssklower * another mbuf, or by adjusting the offset and length 5641587Ssklower * of the first mbuf in the mbuf chain. 5741587Ssklower */ 5841587Ssklower 59*43361Ssklower M_PREPEND(m, M_DONTWAIT, HDHEADERLN); 60*43361Ssklower if (m == NULL) 61*43361Ssklower return; 6241587Ssklower 6341587Ssklower hd_append (&hdp->hd_txq, m); 6441587Ssklower hd_start (hdp); 6541587Ssklower } 6641587Ssklower 6741587Ssklower hd_start (hdp) 6841587Ssklower register struct hdcb *hdp; 6941587Ssklower { 7041587Ssklower register struct mbuf *m; 7141587Ssklower 7241587Ssklower /* 7341587Ssklower * The iframe is only transmitted if all these conditions are FALSE. 7441587Ssklower * The iframe remains queued (hdp->hd_txq) however and will be 7541587Ssklower * transmitted as soon as these conditions are cleared. 7641587Ssklower */ 7741587Ssklower 7841587Ssklower while (!(hdp->hd_condition & (TIMER_RECOVERY_CONDITION | REMOTE_RNR_CONDITION | REJ_CONDITION))) { 7941587Ssklower if (hdp->hd_vs == (hdp->hd_lastrxnr + hdp->hd_xcp->xc_lwsize) % MODULUS) { 8041587Ssklower 8141587Ssklower /* We have now exceeded the maximum number of 8241587Ssklower outstanding iframes. Therefore, we must wait 8341587Ssklower until at least one is acknowledged if this 8441587Ssklower condition is not turned off before we are 8541587Ssklower requested to write another iframe. */ 8641587Ssklower hdp->hd_window_condition++; 8741587Ssklower break; 8841587Ssklower } 8941587Ssklower 9041587Ssklower /* hd_remove top iframe from transmit queue. */ 9141587Ssklower if ((m = hd_remove (&hdp->hd_txq)) == NULL) 9241587Ssklower break; 9341587Ssklower 9441587Ssklower hd_send_iframe (hdp, m, POLLOFF); 9541587Ssklower } 9641587Ssklower } 9741587Ssklower 9841587Ssklower /* 9941587Ssklower * This procedure is passed a buffer descriptor for an iframe. It builds 10041587Ssklower * the rest of the control part of the frame and then writes it out. It 10141587Ssklower * also starts the acknowledgement timer and keeps the iframe in the 10241587Ssklower * Retransmit queue (Retxq) just in case we have to do this again. 10341587Ssklower * 10441587Ssklower * Note: This routine is also called from hd_input.c when retransmission 10541587Ssklower * of old frames is required. 10641587Ssklower */ 10741587Ssklower 10841587Ssklower hd_send_iframe (hdp, buf, poll_bit) 10941587Ssklower register struct hdcb *hdp; 11041587Ssklower register struct mbuf *buf; 11141587Ssklower int poll_bit; 11241587Ssklower { 11341587Ssklower register struct Hdlc_iframe *iframe; 11441587Ssklower struct mbuf *m; 115*43361Ssklower int s 11641587Ssklower 11741587Ssklower KILL_TIMER (hdp); 11841587Ssklower 11941587Ssklower if (buf == 0) { 12041587Ssklower printf ("hd_send_iframe: zero arg\n"); 12141587Ssklower #ifdef HDLCDEBUG 12241587Ssklower hd_status (hdp); 12341587Ssklower hd_dumptrace (hdp); 12441587Ssklower #endif 12541587Ssklower hdp->hd_vs = (hdp->hd_vs + 7) % MODULUS; 12641587Ssklower return; 12741587Ssklower } 12841587Ssklower iframe = mtod (buf, struct Hdlc_iframe *); 12941587Ssklower 13041587Ssklower iframe -> hdlc_0 = 0; 13141587Ssklower iframe -> nr = hdp->hd_vr; 13241587Ssklower iframe -> pf = poll_bit; 13341587Ssklower iframe -> ns = hdp->hd_vs; 13441587Ssklower iframe -> address = ADDRESS_B; 13541587Ssklower hdp->hd_lasttxnr = hdp->hd_vr; 13641587Ssklower hdp->hd_rrtimer = 0; 13741587Ssklower 13841587Ssklower if (hdp->hd_vs == hdp->hd_retxqi) { 13941587Ssklower /* Check for retransmissions. */ 14041587Ssklower /* Put iframe only once in the Retransmission queue. */ 14141587Ssklower hdp->hd_retxq[hdp->hd_retxqi] = buf; 14241587Ssklower hdp->hd_retxqi = (hdp->hd_retxqi + 1) % MODULUS; 14341587Ssklower hdp->hd_iframes_out++; 14441587Ssklower } 14541587Ssklower 14641587Ssklower hdp->hd_vs = (hdp->hd_vs + 1) % MODULUS; 14741587Ssklower 14841587Ssklower hd_trace (hdp, TX, (struct Hdlc_frame *)iframe); 14941587Ssklower 15041587Ssklower /* Write buffer on device. */ 15141587Ssklower m = hdp->hd_dontcopy ? buf : m_copy(buf, 0, (int)M_COPYALL); 15241587Ssklower if (m == 0) { 15341587Ssklower printf("hdlc: out of mbufs\n"); 15441587Ssklower return; 15541587Ssklower } 156*43361Ssklower (*hdp->hd_output)(hdp, m); 15741587Ssklower SET_TIMER (hdp); 15841587Ssklower } 15941587Ssklower 160*43361Ssklower hd_ifoutput(hdp, m) 161*43361Ssklower register struct hdcb *hdp; 162*43361Ssklower register struct mbuf *m; 163*43361Ssklower { 164*43361Ssklower /* 165*43361Ssklower * Queue message on interface, and start output if interface 166*43361Ssklower * not yet active. 167*43361Ssklower */ 168*43361Ssklower register struct ifnet *ifp = hdp->hdp_ifp; 169*43361Ssklower int s = splimp(); 170*43361Ssklower if (IF_QFULL(&ifp->if_snd)) { 171*43361Ssklower IF_DROP(&ifp->if_snd); 172*43361Ssklower printf("%s%d: HDLC says OK to send but queue full, may hang\n", 173*43361Ssklower ifp->if_name, ifp->if_unit); 174*43361Ssklower m_freem(m); 175*43361Ssklower } else { 176*43361Ssklower IF_ENQUEUE(&ifp->if_snd, m); 177*43361Ssklower if ((ifp->if_flags & IFF_OACTIVE) == 0) 178*43361Ssklower (*ifp->if_start)(ifp); 179*43361Ssklower } 180*43361Ssklower splx(s); 181*43361Ssklower } 182*43361Ssklower 183*43361Ssklower 18441587Ssklower /* 18541587Ssklower * This routine gets control when the timer expires because we have not 18641587Ssklower * received an acknowledgement for a iframe. 18741587Ssklower */ 18841587Ssklower 18941587Ssklower hd_resend_iframe (hdp) 19041587Ssklower register struct hdcb *hdp; 19141587Ssklower { 19241587Ssklower 19341587Ssklower if (hdp->hd_retxcnt++ < hd_n2) { 19441587Ssklower if (!(hdp->hd_condition & TIMER_RECOVERY_CONDITION)) { 19541587Ssklower hdp->hd_xx = hdp->hd_vs; 19641587Ssklower hdp->hd_condition |= TIMER_RECOVERY_CONDITION; 19741587Ssklower } 19841587Ssklower 19941587Ssklower hdp->hd_vs = hdp->hd_lastrxnr; 20041587Ssklower hd_send_iframe (hdp, hdp->hd_retxq[hdp->hd_vs], POLLON); 20141587Ssklower } else { 20241587Ssklower /* At this point we have not received a RR even after N2 20341587Ssklower retries - attempt to reset link. */ 20441587Ssklower 20541587Ssklower hd_initvars (hdp); 20641587Ssklower hd_writeinternal (hdp, SABM, POLLOFF); 20741587Ssklower hdp->hd_state = WAIT_UA; 20841587Ssklower SET_TIMER (hdp); 20941587Ssklower hd_message (hdp, "Timer recovery failed: link down"); 21041587Ssklower (void) pk_ctlinput (PRC_LINKDOWN, hdp->hd_xcp); 21141587Ssklower } 21241587Ssklower } 213