from Mike Hibler
[unix-history] / usr / src / sys / netccitt / llc_output.c
CommitLineData
c91dccbd
KS
1/*
2 * Copyright (C) Dirk Husemann, Computer Science Department IV,
3 * University of Erlangen-Nuremberg, Germany, 1990, 1991, 1992
e7a3707f
KB
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
c91dccbd
KS
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Dirk Husemann and the Computer Science Department (IV) of
9 * the University of Erlangen-Nuremberg, Germany.
10 *
11 * %sccs.include.redist.c%
12 *
e7a3707f 13 * @(#)llc_output.c 8.1 (Berkeley) %G%
c91dccbd
KS
14 */
15
16#include <sys/param.h>
17#include <sys/systm.h>
18#include <sys/mbuf.h>
19#include <sys/domain.h>
20#include <sys/socket.h>
21#include <sys/protosw.h>
22#include <sys/errno.h>
23#include <sys/time.h>
24#include <sys/kernel.h>
25
26#include <net/if.h>
27#include <net/if_dl.h>
28#include <net/if_llc.h>
29#include <net/route.h>
30
31#include <netccitt/dll.h>
32#include <netccitt/llc_var.h>
33
34/*
35 * llc_output() --- called by an upper layer (network layer) entity whenever
36 * there is an INFO frame to be transmitted. We enqueue the
37 * info frame and call llc_start() to do the actual sending.
38 */
39
40llc_output(struct llc_linkcb *linkp, struct mbuf *m)
41{
42 register int i;
43
44 i = splimp();
45 LLC_ENQUEUE(linkp, m);
46 llc_start(linkp);
47 splx(i);
48
49}
50
51
52/*
53 * llc_start() --- We try to subsequently dequeue all the frames available and
54 * send them out.
55 */
56void
57llc_start(struct llc_linkcb *linkp)
58{
59 register int i;
60 register struct mbuf *m;
61 int action;
62
63 while ((LLC_STATEEQ(linkp, NORMAL) || LLC_STATEEQ(linkp, BUSY) ||
64 LLC_STATEEQ(linkp, REJECT)) &&
65 (linkp->llcl_slotsfree > 0) &&
66 (LLC_GETFLAG(linkp, REMOTE_BUSY) == 0)) {
67 LLC_DEQUEUE(linkp, m);
68 if (m == NULL)
69 break;
70 LLC_SETFRAME(linkp, m);
71 (void)llc_statehandler(linkp, (struct llc *) 0, NL_DATA_REQUEST,
72 0, 0);
73 }
74}
75
76
77/*
78 * llc_send() --- Handles single frames. If dealing with INFO frames we need to
79 * prepend the LLC header, otherwise we just allocate an mbuf.
80 * In both cases the actual send is done by llc_rawsend().
81 */
82llc_send(struct llc_linkcb *linkp, int frame_kind, int cmdrsp, int pollfinal)
83{
84 register struct mbuf *m = (struct mbuf *)0;
85 register struct llc *frame;
86
87 if (frame_kind == LLCFT_INFO)
88 m = linkp->llcl_output_buffers[llc_seq2slot(linkp,
89 linkp->llcl_vs)];
90 LLC_GETHDR(frame, m);
91
92 /* pass it on to llc_rawsend() */
93 llc_rawsend(linkp, m, frame, frame_kind, linkp->llcl_vs, cmdrsp, pollfinal);
94
95 if (frame_kind == LLCFT_INFO)
96 LLC_INC(linkp->llcl_vs);
97
98 return 0;
99}
100
101/*
102 * llc_resend() --- llc_resend() retransmits all unacknowledged INFO frames.
103 */
104llc_resend(struct llc_linkcb *linkp, int cmdrsp, int pollfinal)
105{
106 register struct llc *frame;
107 register struct mbuf *m;
108 register int seq, slot;
109
110 if (linkp->llcl_slotsfree < linkp->llcl_window)
111 /* assert lock between nr_received & V(S) */
112 if (linkp->llcl_nr_received != linkp->llcl_vs)
113 panic("llc: V(S) != N(R) received\n");
114
115 for (slot = llc_seq2slot(linkp, linkp->llcl_vs);
116 slot != linkp->llcl_freeslot;
117 LLC_INC(linkp->llcl_vs),
118 slot = llc_seq2slot(linkp, linkp->llcl_vs)) {
119 m = linkp->llcl_output_buffers[slot];
120 LLC_GETHDR(frame, m);
121 llc_rawsend(linkp, m, frame, LLCFT_INFO, linkp->llcl_vs,
122 cmdrsp, pollfinal);
123 pollfinal = 0;
124 }
125
126 return 0;
127}
128
129/*
130 * llc_rawsend() --- constructs an LLC frame and sends it out via the
131 * associated interface of the link control block.
132 *
133 * We need to make sure that outgoing frames have the correct length,
134 * in particular the 4 byte ones (RR, RNR, REJ) as LLC_GETHDR() will
135 * set the mbuf len to 3 as default len for non INFO frames ...
136 *
137 * Frame kind Length (w/o MAC header, {D,S}SAP incl.)
138 * --------------------------------------------------------------
139 * DISC, SABME, UA, DM 3 bytes ({D,S}SAP + CONTROL)
140 * RR, RNR, REJ 4 bytes ({D,S}SAP + CONTROL0 + CONTROL1)
141 * XID 6 bytes ({D,S}SAP + CONTROL0 + FI,CLASS,WINDOW)
142 * FRMR 7 bytes ({D,S}SAP + CONTROL0 + REJ CONTROL,V(S),V(R),CAUSE)
143 * INFO 4 -- MTU
144 * UI, TEST 3 -- MTU
145 *
146 */
147#define LLC_SETLEN(m, l) (m)->m_pkthdr.len = (m)->m_len = (l)
148
149llc_rawsend(struct llc_linkcb *linkp, struct mbuf *m, struct llc *frame,
150 int frame_kind, int vs, int cmdrsp, int pollfinal)
151{
152 register short adjust = LLC_UFRAMELEN;
153 struct ifnet *ifp;
154
155 switch (frame_kind) {
156 /* supervisory and information frames */
157 case LLCFT_INFO:
158 frame->llc_control = LLC_INFO;
159 LLCSBITS(frame->llc_control, i_ns, vs);
160 LLCSBITS(frame->llc_control_ext, i_nr, linkp->llcl_vr);
161 adjust = LLC_ISFRAMELEN;
162 break;
163 case LLCFT_RR:
164 frame->llc_control = LLC_RR;
165 LLC_SETLEN(m, LLC_ISFRAMELEN);
166 LLCSBITS(frame->llc_control_ext, s_nr, linkp->llcl_vr);
167 adjust = LLC_ISFRAMELEN;
168 break;
169 case LLCFT_RNR:
170 frame->llc_control = LLC_RNR;
171 LLC_SETLEN(m, LLC_ISFRAMELEN);
172 LLCSBITS(frame->llc_control_ext, s_nr, linkp->llcl_vr);
173 adjust = LLC_ISFRAMELEN;
174 break;
175 case LLCFT_REJ:
176 frame->llc_control = LLC_REJ;
177 LLC_SETLEN(m, LLC_ISFRAMELEN);
178 LLCSBITS(frame->llc_control_ext, s_nr, linkp->llcl_vr);
179 adjust = LLC_ISFRAMELEN;
180 break;
181 /* unnumbered frames */
182 case LLCFT_DM:
183 frame->llc_control = LLC_DM;
184 break;
185 case LLCFT_SABME:
186 frame->llc_control = LLC_SABME;
187 break;
188 case LLCFT_DISC:
189 frame->llc_control = LLC_DISC;
190 break;
191 case LLCFT_UA:
192 frame->llc_control = LLC_UA;
193 break;
194 case LLCFT_UI:
195 frame->llc_control = LLC_UI;
196 break;
197 case LLCFT_FRMR:
198 frame->llc_control = LLC_FRMR;
199 /* get more space --- FRMR frame are longer then usual */
200 LLC_SETLEN(m, LLC_FRMRLEN);
201 bcopy((caddr_t) &linkp->llcl_frmrinfo,
202 (caddr_t) &frame->llc_frmrinfo,
203 sizeof(struct frmrinfo));
204 break;
205 default:
206 /*
207 * We don't send {XID, TEST} frames
208 */
209 if (m)
210 m_freem(m);
211 return;
212 }
213
214 /*
215 * Fill in DSAP/SSAP
216 */
217 frame->llc_dsap = frame->llc_ssap = LLSAPADDR(&linkp->llcl_addr);
218 frame->llc_ssap |= cmdrsp;
219
220 /*
221 * Check for delayed action pending. ISO 8802-2, 7.9.2 (5)
222 * and ISO 8802-2, 7.9.2.3 (32), (34), (36) pertain to this
223 * piece of code --- hopefully we got it right here (i.e.
224 * in the spirit of (32), (34), and (36) ...
225 */
226 switch (frame_kind) {
227 case LLCFT_RR:
228 case LLCFT_RNR:
229 case LLCFT_REJ:
230 case LLCFT_INFO:
231 switch (LLC_GETFLAG(linkp, DACTION)) {
232 case LLC_DACKCMD:
233 case LLC_DACKRSP:
234 LLC_STOPTIMER(linkp, DACTION);
235 break;
236 case LLC_DACKCMDPOLL:
237 if (cmdrsp == LLC_CMD) {
238 pollfinal = 1;
239 LLC_STOPTIMER(linkp, DACTION);
240 }
241 break;
242 case LLC_DACKRSPFINAL:
243 if (cmdrsp == LLC_RSP) {
244 pollfinal = 1;
245 LLC_STOPTIMER(linkp, DACTION);
246 }
247 break;
248 }
249 break;
250 }
251
252 if (adjust == LLC_UFRAMELEN)
253 LLCSBITS(frame->llc_control, u_pf, pollfinal);
254 else LLCSBITS(frame->llc_control_ext, s_pf, pollfinal);
255
256 /*
257 * Get interface to send frame onto
258 */
259 ifp = linkp->llcl_if;
260 if (frame_kind == LLCFT_INFO) {
261 /*
262 * send out a copy of the frame, retain the
263 * original
264 */
265 (*ifp->if_output)(ifp, m_copy(m, 0, (int)M_COPYALL),
266 rt_key(linkp->llcl_nlrt),
267 linkp->llcl_nlrt);
268 /*
269 * Account for the LLC header and let it ``disappear''
270 * as the raw info frame payload is what we hold in
271 * the output_buffers of the link.
272 */
273 m_adj(m, LLC_ISFRAMELEN);
274 } else (*ifp->if_output)(ifp, m,
275 rt_key(linkp->llcl_nlrt),
276 linkp->llcl_nlrt);
277}
278