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