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