xref: /original-bsd/sys/netccitt/hd_output.c (revision 5e1b3b90)
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