assign SCCS numbers for ``June'' beta tape; not yet tested.
[unix-history] / usr / src / sys / netccitt / hd_output.c
CommitLineData
21e3a7bd
KS
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 *
b84e7ca8 12 * @(#)hd_output.c 7.3 (Berkeley) %G%
21e3a7bd 13 */
edc74019
KS
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
b84e7ca8 38hd_output (m, info)
edc74019 39register struct mbuf *m;
b84e7ca8 40caddr_t info;
edc74019 41{
b84e7ca8
KS
42 register struct hdcb *hdp = (struct hdcb *)info;
43 struct x25config *xcp;
edc74019
KS
44
45 if (m == NULL)
46 panic ("hd_output");
47
edc74019
KS
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
b84e7ca8
KS
59 M_PREPEND(m, M_DONTWAIT, HDHEADERLN);
60 if (m == NULL)
61 return;
edc74019
KS
62
63 hd_append (&hdp->hd_txq, m);
64 hd_start (hdp);
65}
66
67hd_start (hdp)
68register 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
108hd_send_iframe (hdp, buf, poll_bit)
109register struct hdcb *hdp;
110register struct mbuf *buf;
111int poll_bit;
112{
113 register struct Hdlc_iframe *iframe;
edc74019 114 struct mbuf *m;
b84e7ca8 115 int s
edc74019
KS
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 }
b84e7ca8 156 (*hdp->hd_output)(hdp, m);
edc74019
KS
157 SET_TIMER (hdp);
158}
159
b84e7ca8
KS
160hd_ifoutput(hdp, m)
161register struct hdcb *hdp;
162register 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
edc74019
KS
184/*
185 * This routine gets control when the timer expires because we have not
186 * received an acknowledgement for a iframe.
187 */
188
189hd_resend_iframe (hdp)
190register 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}