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.3 (Berkeley) 06/21/90 13 */ 14 15 #include "../h/param.h" 16 #include "../h/systm.h" 17 #include "../h/mbuf.h" 18 #include "../h/domain.h" 19 #include "../h/socket.h" 20 #include "../h/protosw.h" 21 #include "../h/errno.h" 22 #include "../h/time.h" 23 #include "../h/kernel.h" 24 #include "../net/if.h" 25 26 #include "../netccitt/hdlc.h" 27 #include "../netccitt/hd_var.h" 28 #include "../netccitt/x25.h" 29 30 /* 31 * HDLC OUTPUT INTERFACE 32 * 33 * This routine is called when the X.25 packet layer output routine 34 * has a information frame (iframe) to write. It is also called 35 * by the input and control routines of the HDLC layer. 36 */ 37 38 hd_output (m, info) 39 register struct mbuf *m; 40 caddr_t info; 41 { 42 register struct hdcb *hdp = (struct hdcb *)info; 43 struct x25config *xcp; 44 45 if (m == NULL) 46 panic ("hd_output"); 47 48 if (hdp->hd_state != ABM) { 49 m_freem (m); 50 return; 51 } 52 53 /* 54 * Make room for the hdlc header either by prepending 55 * another mbuf, or by adjusting the offset and length 56 * of the first mbuf in the mbuf chain. 57 */ 58 59 M_PREPEND(m, M_DONTWAIT, HDHEADERLN); 60 if (m == NULL) 61 return; 62 63 hd_append (&hdp->hd_txq, m); 64 hd_start (hdp); 65 } 66 67 hd_start (hdp) 68 register struct hdcb *hdp; 69 { 70 register struct mbuf *m; 71 72 /* 73 * The iframe is only transmitted if all these conditions are FALSE. 74 * The iframe remains queued (hdp->hd_txq) however and will be 75 * transmitted as soon as these conditions are cleared. 76 */ 77 78 while (!(hdp->hd_condition & (TIMER_RECOVERY_CONDITION | REMOTE_RNR_CONDITION | REJ_CONDITION))) { 79 if (hdp->hd_vs == (hdp->hd_lastrxnr + hdp->hd_xcp->xc_lwsize) % MODULUS) { 80 81 /* We have now exceeded the maximum number of 82 outstanding iframes. Therefore, we must wait 83 until at least one is acknowledged if this 84 condition is not turned off before we are 85 requested to write another iframe. */ 86 hdp->hd_window_condition++; 87 break; 88 } 89 90 /* hd_remove top iframe from transmit queue. */ 91 if ((m = hd_remove (&hdp->hd_txq)) == NULL) 92 break; 93 94 hd_send_iframe (hdp, m, POLLOFF); 95 } 96 } 97 98 /* 99 * This procedure is passed a buffer descriptor for an iframe. It builds 100 * the rest of the control part of the frame and then writes it out. It 101 * also starts the acknowledgement timer and keeps the iframe in the 102 * Retransmit queue (Retxq) just in case we have to do this again. 103 * 104 * Note: This routine is also called from hd_input.c when retransmission 105 * of old frames is required. 106 */ 107 108 hd_send_iframe (hdp, buf, poll_bit) 109 register struct hdcb *hdp; 110 register struct mbuf *buf; 111 int poll_bit; 112 { 113 register struct Hdlc_iframe *iframe; 114 struct mbuf *m; 115 int s 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->hdp_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