]> git.saurik.com Git - apple/xnu.git/blob - bsd/netccitt/llc_output.c
xnu-201.19.3.tar.gz
[apple/xnu.git] / bsd / netccitt / llc_output.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * Copyright (C) Dirk Husemann, Computer Science Department IV,
24 * University of Erlangen-Nuremberg, Germany, 1990, 1991, 1992
25 * Copyright (c) 1992, 1993
26 * The Regents of the University of California. All rights reserved.
27 *
28 * This code is derived from software contributed to Berkeley by
29 * Dirk Husemann and the Computer Science Department (IV) of
30 * the University of Erlangen-Nuremberg, Germany.
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 * must display the following acknowledgement:
42 * This product includes software developed by the University of
43 * California, Berkeley and its contributors.
44 * 4. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 *
60 * @(#)llc_output.c 8.1 (Berkeley) 6/10/93
61 */
62
63 #include <sys/param.h>
64 #include <sys/systm.h>
65 #include <sys/mbuf.h>
66 #include <sys/domain.h>
67 #include <sys/socket.h>
68 #include <sys/protosw.h>
69 #include <sys/errno.h>
70 #include <sys/time.h>
71 #include <sys/kernel.h>
72
73 #include <net/if.h>
74 #include <net/if_dl.h>
75 #include <net/if_llc.h>
76 #include <net/route.h>
77
78 #include <netccitt/dll.h>
79 #include <netccitt/llc_var.h>
80
81 /*
82 * llc_output() --- called by an upper layer (network layer) entity whenever
83 * there is an INFO frame to be transmitted. We enqueue the
84 * info frame and call llc_start() to do the actual sending.
85 */
86
87 llc_output(struct llc_linkcb *linkp, struct mbuf *m)
88 {
89 register int i;
90
91 i = splimp();
92 LLC_ENQUEUE(linkp, m);
93 llc_start(linkp);
94 splx(i);
95
96 }
97
98
99 /*
100 * llc_start() --- We try to subsequently dequeue all the frames available and
101 * send them out.
102 */
103 void
104 llc_start(struct llc_linkcb *linkp)
105 {
106 register int i;
107 register struct mbuf *m;
108 int action;
109
110 while ((LLC_STATEEQ(linkp, NORMAL) || LLC_STATEEQ(linkp, BUSY) ||
111 LLC_STATEEQ(linkp, REJECT)) &&
112 (linkp->llcl_slotsfree > 0) &&
113 (LLC_GETFLAG(linkp, REMOTE_BUSY) == 0)) {
114 LLC_DEQUEUE(linkp, m);
115 if (m == NULL)
116 break;
117 LLC_SETFRAME(linkp, m);
118 (void)llc_statehandler(linkp, (struct llc *) 0, NL_DATA_REQUEST,
119 0, 0);
120 }
121 }
122
123
124 /*
125 * llc_send() --- Handles single frames. If dealing with INFO frames we need to
126 * prepend the LLC header, otherwise we just allocate an mbuf.
127 * In both cases the actual send is done by llc_rawsend().
128 */
129 llc_send(struct llc_linkcb *linkp, int frame_kind, int cmdrsp, int pollfinal)
130 {
131 register struct mbuf *m = (struct mbuf *)0;
132 register struct llc *frame;
133
134 if (frame_kind == LLCFT_INFO)
135 m = linkp->llcl_output_buffers[llc_seq2slot(linkp,
136 linkp->llcl_vs)];
137 LLC_GETHDR(frame, m);
138
139 /* pass it on to llc_rawsend() */
140 llc_rawsend(linkp, m, frame, frame_kind, linkp->llcl_vs, cmdrsp, pollfinal);
141
142 if (frame_kind == LLCFT_INFO)
143 LLC_INC(linkp->llcl_vs);
144
145 return 0;
146 }
147
148 /*
149 * llc_resend() --- llc_resend() retransmits all unacknowledged INFO frames.
150 */
151 llc_resend(struct llc_linkcb *linkp, int cmdrsp, int pollfinal)
152 {
153 register struct llc *frame;
154 register struct mbuf *m;
155 register int seq, slot;
156
157 if (linkp->llcl_slotsfree < linkp->llcl_window)
158 /* assert lock between nr_received & V(S) */
159 if (linkp->llcl_nr_received != linkp->llcl_vs)
160 panic("llc: V(S) != N(R) received\n");
161
162 for (slot = llc_seq2slot(linkp, linkp->llcl_vs);
163 slot != linkp->llcl_freeslot;
164 LLC_INC(linkp->llcl_vs),
165 slot = llc_seq2slot(linkp, linkp->llcl_vs)) {
166 m = linkp->llcl_output_buffers[slot];
167 LLC_GETHDR(frame, m);
168 llc_rawsend(linkp, m, frame, LLCFT_INFO, linkp->llcl_vs,
169 cmdrsp, pollfinal);
170 pollfinal = 0;
171 }
172
173 return 0;
174 }
175
176 /*
177 * llc_rawsend() --- constructs an LLC frame and sends it out via the
178 * associated interface of the link control block.
179 *
180 * We need to make sure that outgoing frames have the correct length,
181 * in particular the 4 byte ones (RR, RNR, REJ) as LLC_GETHDR() will
182 * set the mbuf len to 3 as default len for non INFO frames ...
183 *
184 * Frame kind Length (w/o MAC header, {D,S}SAP incl.)
185 * --------------------------------------------------------------
186 * DISC, SABME, UA, DM 3 bytes ({D,S}SAP + CONTROL)
187 * RR, RNR, REJ 4 bytes ({D,S}SAP + CONTROL0 + CONTROL1)
188 * XID 6 bytes ({D,S}SAP + CONTROL0 + FI,CLASS,WINDOW)
189 * FRMR 7 bytes ({D,S}SAP + CONTROL0 + REJ CONTROL,V(S),V(R),CAUSE)
190 * INFO 4 -- MTU
191 * UI, TEST 3 -- MTU
192 *
193 */
194 #define LLC_SETLEN(m, l) (m)->m_pkthdr.len = (m)->m_len = (l)
195
196 llc_rawsend(struct llc_linkcb *linkp, struct mbuf *m, struct llc *frame,
197 int frame_kind, int vs, int cmdrsp, int pollfinal)
198 {
199 register short adjust = LLC_UFRAMELEN;
200 struct ifnet *ifp;
201
202 switch (frame_kind) {
203 /* supervisory and information frames */
204 case LLCFT_INFO:
205 frame->llc_control = LLC_INFO;
206 LLCSBITS(frame->llc_control, i_ns, vs);
207 LLCSBITS(frame->llc_control_ext, i_nr, linkp->llcl_vr);
208 adjust = LLC_ISFRAMELEN;
209 break;
210 case LLCFT_RR:
211 frame->llc_control = LLC_RR;
212 LLC_SETLEN(m, LLC_ISFRAMELEN);
213 LLCSBITS(frame->llc_control_ext, s_nr, linkp->llcl_vr);
214 adjust = LLC_ISFRAMELEN;
215 break;
216 case LLCFT_RNR:
217 frame->llc_control = LLC_RNR;
218 LLC_SETLEN(m, LLC_ISFRAMELEN);
219 LLCSBITS(frame->llc_control_ext, s_nr, linkp->llcl_vr);
220 adjust = LLC_ISFRAMELEN;
221 break;
222 case LLCFT_REJ:
223 frame->llc_control = LLC_REJ;
224 LLC_SETLEN(m, LLC_ISFRAMELEN);
225 LLCSBITS(frame->llc_control_ext, s_nr, linkp->llcl_vr);
226 adjust = LLC_ISFRAMELEN;
227 break;
228 /* unnumbered frames */
229 case LLCFT_DM:
230 frame->llc_control = LLC_DM;
231 break;
232 case LLCFT_SABME:
233 frame->llc_control = LLC_SABME;
234 break;
235 case LLCFT_DISC:
236 frame->llc_control = LLC_DISC;
237 break;
238 case LLCFT_UA:
239 frame->llc_control = LLC_UA;
240 break;
241 case LLCFT_UI:
242 frame->llc_control = LLC_UI;
243 break;
244 case LLCFT_FRMR:
245 frame->llc_control = LLC_FRMR;
246 /* get more space --- FRMR frame are longer then usual */
247 LLC_SETLEN(m, LLC_FRMRLEN);
248 bcopy((caddr_t) &linkp->llcl_frmrinfo,
249 (caddr_t) &frame->llc_frmrinfo,
250 sizeof(struct frmrinfo));
251 break;
252 default:
253 /*
254 * We don't send {XID, TEST} frames
255 */
256 if (m)
257 m_freem(m);
258 return;
259 }
260
261 /*
262 * Fill in DSAP/SSAP
263 */
264 frame->llc_dsap = frame->llc_ssap = LLSAPADDR(&linkp->llcl_addr);
265 frame->llc_ssap |= cmdrsp;
266
267 /*
268 * Check for delayed action pending. ISO 8802-2, 7.9.2 (5)
269 * and ISO 8802-2, 7.9.2.3 (32), (34), (36) pertain to this
270 * piece of code --- hopefully we got it right here (i.e.
271 * in the spirit of (32), (34), and (36) ...
272 */
273 switch (frame_kind) {
274 case LLCFT_RR:
275 case LLCFT_RNR:
276 case LLCFT_REJ:
277 case LLCFT_INFO:
278 switch (LLC_GETFLAG(linkp, DACTION)) {
279 case LLC_DACKCMD:
280 case LLC_DACKRSP:
281 LLC_STOPTIMER(linkp, DACTION);
282 break;
283 case LLC_DACKCMDPOLL:
284 if (cmdrsp == LLC_CMD) {
285 pollfinal = 1;
286 LLC_STOPTIMER(linkp, DACTION);
287 }
288 break;
289 case LLC_DACKRSPFINAL:
290 if (cmdrsp == LLC_RSP) {
291 pollfinal = 1;
292 LLC_STOPTIMER(linkp, DACTION);
293 }
294 break;
295 }
296 break;
297 }
298
299 if (adjust == LLC_UFRAMELEN)
300 LLCSBITS(frame->llc_control, u_pf, pollfinal);
301 else LLCSBITS(frame->llc_control_ext, s_pf, pollfinal);
302
303 /*
304 * Get interface to send frame onto
305 */
306 ifp = linkp->llcl_if;
307 if (frame_kind == LLCFT_INFO) {
308 /*
309 * send out a copy of the frame, retain the
310 * original
311 */
312 (*ifp->if_output)(ifp, m_copy(m, 0, (int)M_COPYALL),
313 rt_key(linkp->llcl_nlrt),
314 linkp->llcl_nlrt);
315 /*
316 * Account for the LLC header and let it ``disappear''
317 * as the raw info frame payload is what we hold in
318 * the output_buffers of the link.
319 */
320 m_adj(m, LLC_ISFRAMELEN);
321 } else (*ifp->if_output)(ifp, m,
322 rt_key(linkp->llcl_nlrt),
323 linkp->llcl_nlrt);
324 }
325