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