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