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