1*41703Ssklower /* 2*41703Ssklower * Copyright (c) University of British Columbia, 1984 3*41703Ssklower * Copyright (c) 1990 The Regents of the University of California. 4*41703Ssklower * All rights reserved. 5*41703Ssklower * 6*41703Ssklower * This code is derived from software contributed to Berkeley by 7*41703Ssklower * the Laboratory for Computation Vision and the Computer Science Department 8*41703Ssklower * of the University of British Columbia. 9*41703Ssklower * 10*41703Ssklower * %sccs.include.redist.c% 11*41703Ssklower * 12*41703Ssklower * @(#)hd_output.c 7.2 (Berkeley) 05/11/90 13*41703Ssklower */ 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 3841587Ssklower hd_output (m, xcp) 3941587Ssklower struct x25config *xcp; 4041587Ssklower register struct mbuf *m; 4141587Ssklower { 4241587Ssklower register struct hdcb *hdp; 4341587Ssklower static struct x25config *lastxcp; 4441587Ssklower static struct hdcb *lasthdp; 4541587Ssklower 4641587Ssklower if (m == NULL) 4741587Ssklower panic ("hd_output"); 4841587Ssklower 4941587Ssklower if (xcp == lastxcp) 5041587Ssklower hdp = lasthdp; 5141587Ssklower else { 5241587Ssklower for (hdp = hdcbhead; ; hdp = hdp->hd_next) { 5341587Ssklower if (hdp == 0) { 5441587Ssklower printf("hd_output: can't find hdcb for %X\n", xcp); 5541587Ssklower m_freem (m); 5641587Ssklower return; 5741587Ssklower } 5841587Ssklower if (hdp->hd_xcp == xcp) 5941587Ssklower break; 6041587Ssklower } 6141587Ssklower lastxcp = xcp; 6241587Ssklower lasthdp = hdp; 6341587Ssklower } 6441587Ssklower 6541587Ssklower if (hdp->hd_state != ABM) { 6641587Ssklower m_freem (m); 6741587Ssklower return; 6841587Ssklower } 6941587Ssklower 7041587Ssklower /* 7141587Ssklower * Make room for the hdlc header either by prepending 7241587Ssklower * another mbuf, or by adjusting the offset and length 7341587Ssklower * of the first mbuf in the mbuf chain. 7441587Ssklower */ 7541587Ssklower 7641587Ssklower if (m->m_off < MMINOFF + HDHEADERLN) { 7741587Ssklower register struct mbuf *m0; 7841587Ssklower 7941587Ssklower m0 = m_get (M_DONTWAIT, MT_DATA); 8041587Ssklower if (m0 == NULL) { 8141587Ssklower m_freem (m); 8241587Ssklower return; 8341587Ssklower } 8441587Ssklower m0->m_next = m; 8541587Ssklower m0->m_len = HDHEADERLN; 8641587Ssklower m = m0; 8741587Ssklower } else { 8841587Ssklower m->m_off -= HDHEADERLN; 8941587Ssklower m->m_len += HDHEADERLN; 9041587Ssklower } 9141587Ssklower 9241587Ssklower hd_append (&hdp->hd_txq, m); 9341587Ssklower hd_start (hdp); 9441587Ssklower } 9541587Ssklower 9641587Ssklower hd_start (hdp) 9741587Ssklower register struct hdcb *hdp; 9841587Ssklower { 9941587Ssklower register struct mbuf *m; 10041587Ssklower 10141587Ssklower /* 10241587Ssklower * The iframe is only transmitted if all these conditions are FALSE. 10341587Ssklower * The iframe remains queued (hdp->hd_txq) however and will be 10441587Ssklower * transmitted as soon as these conditions are cleared. 10541587Ssklower */ 10641587Ssklower 10741587Ssklower while (!(hdp->hd_condition & (TIMER_RECOVERY_CONDITION | REMOTE_RNR_CONDITION | REJ_CONDITION))) { 10841587Ssklower if (hdp->hd_vs == (hdp->hd_lastrxnr + hdp->hd_xcp->xc_lwsize) % MODULUS) { 10941587Ssklower 11041587Ssklower /* We have now exceeded the maximum number of 11141587Ssklower outstanding iframes. Therefore, we must wait 11241587Ssklower until at least one is acknowledged if this 11341587Ssklower condition is not turned off before we are 11441587Ssklower requested to write another iframe. */ 11541587Ssklower hdp->hd_window_condition++; 11641587Ssklower break; 11741587Ssklower } 11841587Ssklower 11941587Ssklower /* hd_remove top iframe from transmit queue. */ 12041587Ssklower if ((m = hd_remove (&hdp->hd_txq)) == NULL) 12141587Ssklower break; 12241587Ssklower 12341587Ssklower hd_send_iframe (hdp, m, POLLOFF); 12441587Ssklower } 12541587Ssklower } 12641587Ssklower 12741587Ssklower /* 12841587Ssklower * This procedure is passed a buffer descriptor for an iframe. It builds 12941587Ssklower * the rest of the control part of the frame and then writes it out. It 13041587Ssklower * also starts the acknowledgement timer and keeps the iframe in the 13141587Ssklower * Retransmit queue (Retxq) just in case we have to do this again. 13241587Ssklower * 13341587Ssklower * Note: This routine is also called from hd_input.c when retransmission 13441587Ssklower * of old frames is required. 13541587Ssklower */ 13641587Ssklower 13741587Ssklower hd_send_iframe (hdp, buf, poll_bit) 13841587Ssklower register struct hdcb *hdp; 13941587Ssklower register struct mbuf *buf; 14041587Ssklower int poll_bit; 14141587Ssklower { 14241587Ssklower register struct Hdlc_iframe *iframe; 14341587Ssklower register struct ifnet *ifp = hdp->hd_ifp; 14441587Ssklower struct mbuf *m; 14541587Ssklower 14641587Ssklower KILL_TIMER (hdp); 14741587Ssklower 14841587Ssklower if (buf == 0) { 14941587Ssklower printf ("hd_send_iframe: zero arg\n"); 15041587Ssklower #ifdef HDLCDEBUG 15141587Ssklower hd_status (hdp); 15241587Ssklower hd_dumptrace (hdp); 15341587Ssklower #endif 15441587Ssklower hdp->hd_vs = (hdp->hd_vs + 7) % MODULUS; 15541587Ssklower return; 15641587Ssklower } 15741587Ssklower iframe = mtod (buf, struct Hdlc_iframe *); 15841587Ssklower 15941587Ssklower iframe -> hdlc_0 = 0; 16041587Ssklower iframe -> nr = hdp->hd_vr; 16141587Ssklower iframe -> pf = poll_bit; 16241587Ssklower iframe -> ns = hdp->hd_vs; 16341587Ssklower iframe -> address = ADDRESS_B; 16441587Ssklower hdp->hd_lasttxnr = hdp->hd_vr; 16541587Ssklower hdp->hd_rrtimer = 0; 16641587Ssklower 16741587Ssklower if (hdp->hd_vs == hdp->hd_retxqi) { 16841587Ssklower /* Check for retransmissions. */ 16941587Ssklower /* Put iframe only once in the Retransmission queue. */ 17041587Ssklower hdp->hd_retxq[hdp->hd_retxqi] = buf; 17141587Ssklower hdp->hd_retxqi = (hdp->hd_retxqi + 1) % MODULUS; 17241587Ssklower hdp->hd_iframes_out++; 17341587Ssklower } 17441587Ssklower 17541587Ssklower hdp->hd_vs = (hdp->hd_vs + 1) % MODULUS; 17641587Ssklower 17741587Ssklower hd_trace (hdp, TX, (struct Hdlc_frame *)iframe); 17841587Ssklower 17941587Ssklower /* Write buffer on device. */ 18041587Ssklower m = hdp->hd_dontcopy ? buf : m_copy(buf, 0, (int)M_COPYALL); 18141587Ssklower if (m == 0) { 18241587Ssklower printf("hdlc: out of mbufs\n"); 18341587Ssklower return; 18441587Ssklower } 18541587Ssklower (*ifp -> if_output) (ifp, m, (struct sockaddr *)hdp->hd_xcp); 18641587Ssklower 18741587Ssklower SET_TIMER (hdp); 18841587Ssklower } 18941587Ssklower 19041587Ssklower /* 19141587Ssklower * This routine gets control when the timer expires because we have not 19241587Ssklower * received an acknowledgement for a iframe. 19341587Ssklower */ 19441587Ssklower 19541587Ssklower hd_resend_iframe (hdp) 19641587Ssklower register struct hdcb *hdp; 19741587Ssklower { 19841587Ssklower 19941587Ssklower if (hdp->hd_retxcnt++ < hd_n2) { 20041587Ssklower if (!(hdp->hd_condition & TIMER_RECOVERY_CONDITION)) { 20141587Ssklower hdp->hd_xx = hdp->hd_vs; 20241587Ssklower hdp->hd_condition |= TIMER_RECOVERY_CONDITION; 20341587Ssklower } 20441587Ssklower 20541587Ssklower hdp->hd_vs = hdp->hd_lastrxnr; 20641587Ssklower hd_send_iframe (hdp, hdp->hd_retxq[hdp->hd_vs], POLLON); 20741587Ssklower } else { 20841587Ssklower /* At this point we have not received a RR even after N2 20941587Ssklower retries - attempt to reset link. */ 21041587Ssklower 21141587Ssklower hd_initvars (hdp); 21241587Ssklower hd_writeinternal (hdp, SABM, POLLOFF); 21341587Ssklower hdp->hd_state = WAIT_UA; 21441587Ssklower SET_TIMER (hdp); 21541587Ssklower hd_message (hdp, "Timer recovery failed: link down"); 21641587Ssklower (void) pk_ctlinput (PRC_LINKDOWN, hdp->hd_xcp); 21741587Ssklower } 21841587Ssklower } 219