]> git.saurik.com Git - apple/xnu.git/blob - bsd/netccitt/llc_input.c
aacbce91c7ea75a2a3fb2f8e3e7b91807fac7437
[apple/xnu.git] / bsd / netccitt / llc_input.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_input.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 * This module implements LLC as specified by ISO 8802-2.
83 */
84
85
86 /*
87 * llcintr() handles all LLC frames (except ISO CLNS ones for the time being)
88 * and tries to pass them on to the appropriate network layer entity.
89 */
90 void
91 llcintr()
92 {
93 register struct mbuf *m;
94 register int i;
95 register int frame_kind;
96 register u_char cmdrsp;
97 struct llc_linkcb *linkp;
98 struct rtentry *sirt;
99 struct npaidbentry *sapinfo;
100 struct sdl_hdr *sdlhdr;
101 struct llc *frame;
102 char *c;
103 long expected_len;
104
105 struct ifnet *ifp;
106 struct rtentry *llrt;
107 struct rtentry *nlrt;
108
109 for (;;) {
110 i = splimp();
111 IF_DEQUEUE(&llcintrq, m);
112 splx(i);
113 if (m == 0)
114 break;
115 #if DIAGNOSTIC
116 if ((m->m_flags & M_PKTHDR) == 0)
117 panic("llcintr no HDR");
118 #endif
119 /*
120 * Get ifp this packet was received on
121 */
122 ifp = m->m_pkthdr.rcvif;
123
124 sdlhdr = mtod(m, struct sdl_hdr *);
125
126 /*
127 * [Copied from net/ip_input.c]
128 *
129 * Check that the amount of data in the buffers is
130 * at least as much as the LLC header tells us.
131 * Trim mbufs if longer than expected.
132 * Drop packets if shorter than we think they are.
133 *
134 * Layout of mbuf chain at this point:
135 *
136 * +-------------------------------+----+ -\
137 * | sockaddr_dl src - sdlhdr_src | 20 | \
138 * +-------------------------------+----+ |
139 * | sockaddr_dl dst - sdlhdr_dst | 20 | > sizeof(struct sdl_hdr) == 44
140 * +-------------------------------+----+ |
141 * | LLC frame len - sdlhdr_len | 04 | /
142 * +-------------------------------+----+ -/
143 * /
144 * | m_next
145 * \
146 * +----------------------------+----+ -\
147 * | llc DSAP | 01 | \
148 * +----------------------------+----+ |
149 * | llc SSAP | 01 | |
150 * +----------------------------+----+ > sdlhdr_len
151 * | llc control | 01 | |
152 * +----------------------------+----+ |
153 * | ... | | /
154 * -/
155 *
156 * Thus the we expect to have exactly
157 * (sdlhdr->sdlhdr_len+sizeof(struct sdl_hdr)) in the mbuf chain
158 */
159 expected_len = sdlhdr->sdlhdr_len + sizeof(struct sdl_hdr);
160
161 if (m->m_pkthdr.len < expected_len) {
162 m_freem(m);
163 continue;
164 }
165 if (m->m_pkthdr.len > expected_len) {
166 if (m->m_len == m->m_pkthdr.len) {
167 m->m_len = expected_len;
168 m->m_pkthdr.len = expected_len;
169 } else
170 m_adj(m, expected_len - m->m_pkthdr.len);
171 }
172
173 /*
174 * Get llc header
175 */
176 if (m->m_len > sizeof(struct sdl_hdr))
177 frame = mtod((struct mbuf *)((struct sdl_hdr*)(m+1)),
178 struct llc *);
179 else frame = mtod(m->m_next, struct llc *);
180 if (frame == (struct llc *) NULL)
181 panic("llcintr no llc header");
182
183 /*
184 * Now check for bogus I/S frame, i.e. those with a control
185 * field telling us they're an I/S frame yet their length
186 * is less than the established I/S frame length (DSAP + SSAP +
187 * control + N(R)&P/F = 4) --- we drop those suckers
188 */
189 if (((frame->llc_control & 0x03) != 0x03)
190 && ((expected_len - sizeof(struct sdl_hdr)) < LLC_ISFRAMELEN)) {
191 m_freem(m);
192 printf("llc: hurz error\n");
193 continue;
194 }
195
196 /*
197 * Get link control block for the addressed link connection.
198 * If there is none we take care of it later on.
199 */
200 cmdrsp = (frame->llc_ssap & 0x01);
201 frame->llc_ssap &= ~0x01;
202 if (llrt = rtalloc1((struct sockaddr *)&sdlhdr->sdlhdr_src, 0))
203 llrt->rt_refcnt--;
204 #ifdef notyet
205 else llrt = npaidb_enter(&sdlhdr->sdlhdr_src, 0, 0, 0);
206 #endif /* notyet */
207 else {
208 /*
209 * We cannot do anything currently here as we
210 * don't `know' this link --- drop it
211 */
212 m_freem(m);
213 continue;
214 }
215 linkp = ((struct npaidbentry *)(llrt->rt_llinfo))->np_link;
216 nlrt = ((struct npaidbentry *)(llrt->rt_llinfo))->np_rt;
217
218 /*
219 * If the link is not existing right now, we can try and look up
220 * the SAP info block.
221 */
222 if ((linkp == 0) && frame->llc_ssap)
223 sapinfo = llc_getsapinfo(frame->llc_dsap, ifp);
224
225 /*
226 * Handle XID and TEST frames
227 * XID: if DLSAP == 0, return type-of-services
228 * window-0
229 * DLSAP-0
230 * format-identifier-?
231 * if DLSAP != 0, locate sapcb and return
232 * type-of-services
233 * SAP-window
234 * format-identifier-?
235 * TEST: swap (snpah_dst, snpah_src) and return frame
236 *
237 * Also toggle the CMD/RESP bit
238 *
239 * Is this behaviour correct? Check ISO 8802-2 (90)!
240 */
241 frame_kind = llc_decode(frame, (struct llc_linkcb *)0);
242 switch(frame_kind) {
243 case LLCFT_XID:
244 if (linkp || sapinfo) {
245 if (linkp)
246 frame->llc_window = linkp->llcl_window;
247 else frame->llc_window = sapinfo->si_window;
248 frame->llc_fid = 9; /* XXX */
249 frame->llc_class = sapinfo->si_class;
250 frame->llc_ssap = frame->llc_dsap;
251 } else {
252 frame->llc_window = 0;
253 frame->llc_fid = 9;
254 frame->llc_class = 1;
255 frame->llc_dsap = frame->llc_ssap = 0;
256 }
257
258 /* fall thru to */
259 case LLCFT_TEST:
260 sdl_swapaddr(&(mtod(m, struct sdl_hdr *)->sdlhdr_dst),
261 &(mtod(m, struct sdl_hdr *)->sdlhdr_src));
262
263 /* Now set the CMD/RESP bit */
264 frame->llc_ssap |= (cmdrsp == 0x0 ? 0x1 : 0x0);
265
266 /* Ship it out again */
267 (*ifp->if_output)(ifp, m,
268 (struct sockaddr *) &(mtod(m, struct sdl_hdr *)->sdlhdr_dst),
269 (struct rtentry *) 0);
270 continue;
271 }
272
273 /*
274 * Create link control block in case it is not existing
275 */
276 if (linkp == 0 && sapinfo) {
277 if ((linkp = llc_newlink(&sdlhdr->sdlhdr_src, ifp, nlrt,
278 (nlrt == 0) ? 0 : nlrt->rt_llinfo,
279 llrt)) == 0) {
280 printf("llcintr: couldn't create new link\n");
281 m_freem(m);
282 continue;
283 }
284 ((struct npaidbentry *)llrt->rt_llinfo)->np_link = linkp;
285 } else if (linkp == 0) {
286 /* The link is not known to us, drop the frame and continue */
287 m_freem(m);
288 continue;
289 }
290
291 /*
292 * Drop SNPA header and get rid of empty mbuf at the
293 * front of the mbuf chain (I don't like 'em)
294 */
295 m_adj(m, sizeof(struct sdl_hdr));
296 /*
297 * LLC_UFRAMELEN is sufficient, m_pullup() will pull up
298 * the min(m->m_len, maxprotohdr_len [=40]) thus doing
299 * the trick ...
300 */
301 if ((m = m_pullup(m, LLC_UFRAMELEN)))
302 /*
303 * Pass it on thru the elements of procedure
304 */
305 llc_input(linkp, m, cmdrsp);
306 }
307 return;
308 }
309
310 /*
311 * llc_input() --- We deal with the various incoming frames here.
312 * Basically we (indirectly) call the appropriate
313 * state handler function that's pointed to by
314 * llcl_statehandler.
315 *
316 * The statehandler returns an action code ---
317 * further actions like
318 * o notify network layer
319 * o block further sending
320 * o deblock link
321 * o ...
322 * are then enacted accordingly.
323 */
324 llc_input(struct llc_linkcb *linkp, struct mbuf *m, u_char cmdrsp)
325 {
326 int frame_kind;
327 int pollfinal;
328 int action = 0;
329 struct llc *frame;
330 struct ifnet *ifp = linkp->llcl_if;
331
332 if ((frame = mtod(m, struct llc *)) == (struct llc *) 0) {
333 m_freem(m);
334 return 0;
335 }
336 pollfinal = ((frame->llc_control & 0x03) == 0x03) ?
337 LLCGBITS(frame->llc_control, u_pf) :
338 LLCGBITS(frame->llc_control_ext, s_pf);
339
340 /*
341 * first decode the frame
342 */
343 frame_kind = llc_decode(frame, linkp);
344
345 switch (action = llc_statehandler(linkp, frame, frame_kind, cmdrsp,
346 pollfinal)) {
347 case LLC_DATA_INDICATION:
348 m_adj(m, LLC_ISFRAMELEN);
349 if (m = m_pullup(m, NLHDRSIZEGUESS)) {
350 m->m_pkthdr.rcvif = (struct ifnet *)linkp->llcl_nlnext;
351 (*linkp->llcl_sapinfo->si_input)(m);
352 }
353 break;
354 }
355
356 /* release mbuf if not an info frame */
357 if (action != LLC_DATA_INDICATION && m)
358 m_freem(m);
359
360 /* try to get frames out ... */
361 llc_start(linkp);
362
363 return 0;
364 }
365
366 /*
367 * This routine is called by configuration setup. It sets up a station control
368 * block and notifies all registered upper level protocols.
369 */
370 caddr_t
371 llc_ctlinput(int prc, struct sockaddr *addr, caddr_t info)
372 {
373 struct ifnet *ifp;
374 struct ifaddr *ifa;
375 struct dll_ctlinfo *ctlinfo = (struct dll_ctlinfo *)info;
376 u_char sap;
377 struct dllconfig *config;
378 caddr_t pcb;
379 struct rtentry *nlrt;
380 struct rtentry *llrt;
381 struct llc_linkcb *linkp;
382 register int i;
383
384 /* info must point to something valid at all times */
385 if (info == 0)
386 return 0;
387
388 if (prc == PRC_IFUP || prc == PRC_IFDOWN) {
389 /* we use either this set ... */
390 ifa = ifa_ifwithaddr(addr);
391 ifp = ifa ? ifa->ifa_ifp : 0;
392 if (ifp == 0)
393 return 0;
394
395 sap = ctlinfo->dlcti_lsap;
396 config = ctlinfo->dlcti_cfg;
397 pcb = (caddr_t) 0;
398 nlrt = (struct rtentry *) 0;
399 } else {
400 /* or this one */
401 sap = 0;
402 config = (struct dllconfig *) 0;
403 pcb = ctlinfo->dlcti_pcb;
404 nlrt = ctlinfo->dlcti_rt;
405
406 if ((llrt = rtalloc1(nlrt->rt_gateway, 0)))
407 llrt->rt_refcnt--;
408 else return 0;
409
410 linkp = ((struct npaidbentry *)llrt->rt_llinfo)->np_link;
411 }
412
413 switch (prc) {
414 case PRC_IFUP:
415 (void) llc_setsapinfo(ifp, addr->sa_family, sap, config);
416 return 0;
417
418 case PRC_IFDOWN: {
419 register struct llc_linkcb *linkp;
420 register struct llc_linkcb *nlinkp;
421 register int i;
422
423 /*
424 * All links are accessible over the doubly linked list llccb_q
425 */
426 if (!LQEMPTY) {
427 /*
428 * A for-loop is not that great an idea as the linkp
429 * will get deleted by llc_timer()
430 */
431 linkp = LQFIRST;
432 while (LQVALID(linkp)) {
433 nlinkp = LQNEXT(linkp);
434 if (linkp->llcl_if = ifp) {
435 i = splimp();
436 (void)llc_statehandler(linkp, (struct llc *)0,
437 NL_DISCONNECT_REQUEST,
438 0, 1);
439 splx(i);
440 }
441 linkp = nlinkp;
442 }
443 }
444 }
445
446 case PRC_CONNECT_REQUEST:
447 if (linkp == 0) {
448 if ((linkp = llc_newlink((struct sockaddr_dl *) nlrt->rt_gateway,
449 nlrt->rt_ifp, nlrt,
450 pcb, llrt)) == 0)
451 return (0);
452 ((struct npaidbentry *)llrt->rt_llinfo)->np_link = linkp;
453 i = splimp();
454 (void)llc_statehandler(linkp, (struct llc *) 0,
455 NL_CONNECT_REQUEST, 0, 1);
456 splx(i);
457 }
458 return ((caddr_t)linkp);
459
460 case PRC_DISCONNECT_REQUEST:
461 if (linkp == 0)
462 panic("no link control block!");
463
464 i = splimp();
465 (void)llc_statehandler(linkp, (struct llc *) 0,
466 NL_DISCONNECT_REQUEST, 0, 1);
467 splx(i);
468
469 /*
470 * The actual removal of the link control block is done by the
471 * cleaning neutrum (i.e. llc_timer()).
472 */
473 break;
474
475 case PRC_RESET_REQUEST:
476 if (linkp == 0)
477 panic("no link control block!");
478
479 i = splimp();
480 (void)llc_statehandler(linkp, (struct llc *) 0,
481 NL_RESET_REQUEST, 0, 1);
482 splx(i);
483
484 break;
485
486 }
487
488 return 0;
489 }