1*41587Ssklower /* Copyright (c) University of British Columbia, 1984 */ 2*41587Ssklower 3*41587Ssklower #include "../h/param.h" 4*41587Ssklower #include "../h/systm.h" 5*41587Ssklower #include "../h/mbuf.h" 6*41587Ssklower #include "../h/domain.h" 7*41587Ssklower #include "../h/socket.h" 8*41587Ssklower #include "../h/protosw.h" 9*41587Ssklower #include "../h/errno.h" 10*41587Ssklower #include "../h/time.h" 11*41587Ssklower #include "../h/kernel.h" 12*41587Ssklower #include "../net/if.h" 13*41587Ssklower 14*41587Ssklower #include "../netccitt/hdlc.h" 15*41587Ssklower #include "../netccitt/hd_var.h" 16*41587Ssklower #include "../netccitt/x25.h" 17*41587Ssklower 18*41587Ssklower /* 19*41587Ssklower * HDLC OUTPUT INTERFACE 20*41587Ssklower * 21*41587Ssklower * This routine is called when the X.25 packet layer output routine 22*41587Ssklower * has a information frame (iframe) to write. It is also called 23*41587Ssklower * by the input and control routines of the HDLC layer. 24*41587Ssklower */ 25*41587Ssklower 26*41587Ssklower hd_output (m, xcp) 27*41587Ssklower struct x25config *xcp; 28*41587Ssklower register struct mbuf *m; 29*41587Ssklower { 30*41587Ssklower register struct hdcb *hdp; 31*41587Ssklower static struct x25config *lastxcp; 32*41587Ssklower static struct hdcb *lasthdp; 33*41587Ssklower 34*41587Ssklower if (m == NULL) 35*41587Ssklower panic ("hd_output"); 36*41587Ssklower 37*41587Ssklower if (xcp == lastxcp) 38*41587Ssklower hdp = lasthdp; 39*41587Ssklower else { 40*41587Ssklower for (hdp = hdcbhead; ; hdp = hdp->hd_next) { 41*41587Ssklower if (hdp == 0) { 42*41587Ssklower printf("hd_output: can't find hdcb for %X\n", xcp); 43*41587Ssklower m_freem (m); 44*41587Ssklower return; 45*41587Ssklower } 46*41587Ssklower if (hdp->hd_xcp == xcp) 47*41587Ssklower break; 48*41587Ssklower } 49*41587Ssklower lastxcp = xcp; 50*41587Ssklower lasthdp = hdp; 51*41587Ssklower } 52*41587Ssklower 53*41587Ssklower if (hdp->hd_state != ABM) { 54*41587Ssklower m_freem (m); 55*41587Ssklower return; 56*41587Ssklower } 57*41587Ssklower 58*41587Ssklower /* 59*41587Ssklower * Make room for the hdlc header either by prepending 60*41587Ssklower * another mbuf, or by adjusting the offset and length 61*41587Ssklower * of the first mbuf in the mbuf chain. 62*41587Ssklower */ 63*41587Ssklower 64*41587Ssklower if (m->m_off < MMINOFF + HDHEADERLN) { 65*41587Ssklower register struct mbuf *m0; 66*41587Ssklower 67*41587Ssklower m0 = m_get (M_DONTWAIT, MT_DATA); 68*41587Ssklower if (m0 == NULL) { 69*41587Ssklower m_freem (m); 70*41587Ssklower return; 71*41587Ssklower } 72*41587Ssklower m0->m_next = m; 73*41587Ssklower m0->m_len = HDHEADERLN; 74*41587Ssklower m = m0; 75*41587Ssklower } else { 76*41587Ssklower m->m_off -= HDHEADERLN; 77*41587Ssklower m->m_len += HDHEADERLN; 78*41587Ssklower } 79*41587Ssklower 80*41587Ssklower hd_append (&hdp->hd_txq, m); 81*41587Ssklower hd_start (hdp); 82*41587Ssklower } 83*41587Ssklower 84*41587Ssklower hd_start (hdp) 85*41587Ssklower register struct hdcb *hdp; 86*41587Ssklower { 87*41587Ssklower register struct mbuf *m; 88*41587Ssklower 89*41587Ssklower /* 90*41587Ssklower * The iframe is only transmitted if all these conditions are FALSE. 91*41587Ssklower * The iframe remains queued (hdp->hd_txq) however and will be 92*41587Ssklower * transmitted as soon as these conditions are cleared. 93*41587Ssklower */ 94*41587Ssklower 95*41587Ssklower while (!(hdp->hd_condition & (TIMER_RECOVERY_CONDITION | REMOTE_RNR_CONDITION | REJ_CONDITION))) { 96*41587Ssklower if (hdp->hd_vs == (hdp->hd_lastrxnr + hdp->hd_xcp->xc_lwsize) % MODULUS) { 97*41587Ssklower 98*41587Ssklower /* We have now exceeded the maximum number of 99*41587Ssklower outstanding iframes. Therefore, we must wait 100*41587Ssklower until at least one is acknowledged if this 101*41587Ssklower condition is not turned off before we are 102*41587Ssklower requested to write another iframe. */ 103*41587Ssklower hdp->hd_window_condition++; 104*41587Ssklower break; 105*41587Ssklower } 106*41587Ssklower 107*41587Ssklower /* hd_remove top iframe from transmit queue. */ 108*41587Ssklower if ((m = hd_remove (&hdp->hd_txq)) == NULL) 109*41587Ssklower break; 110*41587Ssklower 111*41587Ssklower hd_send_iframe (hdp, m, POLLOFF); 112*41587Ssklower } 113*41587Ssklower } 114*41587Ssklower 115*41587Ssklower /* 116*41587Ssklower * This procedure is passed a buffer descriptor for an iframe. It builds 117*41587Ssklower * the rest of the control part of the frame and then writes it out. It 118*41587Ssklower * also starts the acknowledgement timer and keeps the iframe in the 119*41587Ssklower * Retransmit queue (Retxq) just in case we have to do this again. 120*41587Ssklower * 121*41587Ssklower * Note: This routine is also called from hd_input.c when retransmission 122*41587Ssklower * of old frames is required. 123*41587Ssklower */ 124*41587Ssklower 125*41587Ssklower hd_send_iframe (hdp, buf, poll_bit) 126*41587Ssklower register struct hdcb *hdp; 127*41587Ssklower register struct mbuf *buf; 128*41587Ssklower int poll_bit; 129*41587Ssklower { 130*41587Ssklower register struct Hdlc_iframe *iframe; 131*41587Ssklower register struct ifnet *ifp = hdp->hd_ifp; 132*41587Ssklower struct mbuf *m; 133*41587Ssklower 134*41587Ssklower KILL_TIMER (hdp); 135*41587Ssklower 136*41587Ssklower if (buf == 0) { 137*41587Ssklower printf ("hd_send_iframe: zero arg\n"); 138*41587Ssklower #ifdef HDLCDEBUG 139*41587Ssklower hd_status (hdp); 140*41587Ssklower hd_dumptrace (hdp); 141*41587Ssklower #endif 142*41587Ssklower hdp->hd_vs = (hdp->hd_vs + 7) % MODULUS; 143*41587Ssklower return; 144*41587Ssklower } 145*41587Ssklower iframe = mtod (buf, struct Hdlc_iframe *); 146*41587Ssklower 147*41587Ssklower iframe -> hdlc_0 = 0; 148*41587Ssklower iframe -> nr = hdp->hd_vr; 149*41587Ssklower iframe -> pf = poll_bit; 150*41587Ssklower iframe -> ns = hdp->hd_vs; 151*41587Ssklower iframe -> address = ADDRESS_B; 152*41587Ssklower hdp->hd_lasttxnr = hdp->hd_vr; 153*41587Ssklower hdp->hd_rrtimer = 0; 154*41587Ssklower 155*41587Ssklower if (hdp->hd_vs == hdp->hd_retxqi) { 156*41587Ssklower /* Check for retransmissions. */ 157*41587Ssklower /* Put iframe only once in the Retransmission queue. */ 158*41587Ssklower hdp->hd_retxq[hdp->hd_retxqi] = buf; 159*41587Ssklower hdp->hd_retxqi = (hdp->hd_retxqi + 1) % MODULUS; 160*41587Ssklower hdp->hd_iframes_out++; 161*41587Ssklower } 162*41587Ssklower 163*41587Ssklower hdp->hd_vs = (hdp->hd_vs + 1) % MODULUS; 164*41587Ssklower 165*41587Ssklower hd_trace (hdp, TX, (struct Hdlc_frame *)iframe); 166*41587Ssklower 167*41587Ssklower /* Write buffer on device. */ 168*41587Ssklower m = hdp->hd_dontcopy ? buf : m_copy(buf, 0, (int)M_COPYALL); 169*41587Ssklower if (m == 0) { 170*41587Ssklower printf("hdlc: out of mbufs\n"); 171*41587Ssklower return; 172*41587Ssklower } 173*41587Ssklower (*ifp -> if_output) (ifp, m, (struct sockaddr *)hdp->hd_xcp); 174*41587Ssklower 175*41587Ssklower SET_TIMER (hdp); 176*41587Ssklower } 177*41587Ssklower 178*41587Ssklower /* 179*41587Ssklower * This routine gets control when the timer expires because we have not 180*41587Ssklower * received an acknowledgement for a iframe. 181*41587Ssklower */ 182*41587Ssklower 183*41587Ssklower hd_resend_iframe (hdp) 184*41587Ssklower register struct hdcb *hdp; 185*41587Ssklower { 186*41587Ssklower 187*41587Ssklower if (hdp->hd_retxcnt++ < hd_n2) { 188*41587Ssklower if (!(hdp->hd_condition & TIMER_RECOVERY_CONDITION)) { 189*41587Ssklower hdp->hd_xx = hdp->hd_vs; 190*41587Ssklower hdp->hd_condition |= TIMER_RECOVERY_CONDITION; 191*41587Ssklower } 192*41587Ssklower 193*41587Ssklower hdp->hd_vs = hdp->hd_lastrxnr; 194*41587Ssklower hd_send_iframe (hdp, hdp->hd_retxq[hdp->hd_vs], POLLON); 195*41587Ssklower } else { 196*41587Ssklower /* At this point we have not received a RR even after N2 197*41587Ssklower retries - attempt to reset link. */ 198*41587Ssklower 199*41587Ssklower hd_initvars (hdp); 200*41587Ssklower hd_writeinternal (hdp, SABM, POLLOFF); 201*41587Ssklower hdp->hd_state = WAIT_UA; 202*41587Ssklower SET_TIMER (hdp); 203*41587Ssklower hd_message (hdp, "Timer recovery failed: link down"); 204*41587Ssklower (void) pk_ctlinput (PRC_LINKDOWN, hdp->hd_xcp); 205*41587Ssklower } 206*41587Ssklower } 207