1 /* $NetBSD: llc_input.c,v 1.12 2003/08/07 16:33:01 agc Exp $ */
2
3 /*
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
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 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * @(#)llc_input.c 8.1 (Berkeley) 6/10/93
36 */
37
38 /*
39 * Copyright (c) 1990, 1991, 1992
40 * Dirk Husemann, Computer Science Department IV,
41 * University of Erlangen-Nuremberg, Germany.
42 *
43 * This code is derived from software contributed to Berkeley by
44 * Dirk Husemann and the Computer Science Department (IV) of
45 * the University of Erlangen-Nuremberg, Germany.
46 *
47 * Redistribution and use in source and binary forms, with or without
48 * modification, are permitted provided that the following conditions
49 * are met:
50 * 1. Redistributions of source code must retain the above copyright
51 * notice, this list of conditions and the following disclaimer.
52 * 2. Redistributions in binary form must reproduce the above copyright
53 * notice, this list of conditions and the following disclaimer in the
54 * documentation and/or other materials provided with the distribution.
55 * 3. All advertising materials mentioning features or use of this software
56 * must display the following acknowledgement:
57 * This product includes software developed by the University of
58 * California, Berkeley and its contributors.
59 * 4. Neither the name of the University nor the names of its contributors
60 * may be used to endorse or promote products derived from this software
61 * without specific prior written permission.
62 *
63 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
64 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
65 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
66 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
67 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
68 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
69 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
70 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
71 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
72 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
73 * SUCH DAMAGE.
74 *
75 * @(#)llc_input.c 8.1 (Berkeley) 6/10/93
76 */
77
78 #include <sys/cdefs.h>
79 __KERNEL_RCSID(0, "$NetBSD: llc_input.c,v 1.12 2003/08/07 16:33:01 agc Exp $");
80
81 #include <sys/param.h>
82 #include <sys/systm.h>
83 #include <sys/mbuf.h>
84 #include <sys/domain.h>
85 #include <sys/socket.h>
86 #include <sys/protosw.h>
87 #include <sys/errno.h>
88 #include <sys/time.h>
89 #include <sys/kernel.h>
90
91 #include <net/if.h>
92 #include <net/if_dl.h>
93 #include <net/if_llc.h>
94 #include <net/route.h>
95
96 #include <netccitt/dll.h>
97 #include <netccitt/llc_var.h>
98
99 #include <machine/stdarg.h>
100
101 struct ifqueue llcintrq;
102
103 /*
104 * This module implements LLC as specified by ISO 8802-2.
105 */
106
107
108 /*
109 * llcintr() handles all LLC frames (except ISO CLNS ones for the time being)
110 * and tries to pass them on to the appropriate network layer entity.
111 */
112 void
113 llcintr()
114 {
115 struct mbuf *m;
116 int i;
117 int frame_kind;
118 u_char cmdrsp;
119 struct llc_linkcb *linkp;
120 struct npaidbentry *sapinfo = NULL;
121 struct sdl_hdr *sdlhdr;
122 struct llc *frame;
123 long expected_len;
124
125 struct ifnet *ifp;
126 struct rtentry *llrt;
127 struct rtentry *nlrt;
128
129 for (;;) {
130 i = splnet();
131 IF_DEQUEUE(&llcintrq, m);
132 splx(i);
133 if (m == 0)
134 break;
135 #ifdef DIAGNOSTIC
136 if ((m->m_flags & M_PKTHDR) == 0)
137 panic("llcintr no HDR");
138 #endif
139 /*
140 * Get ifp this packet was received on
141 */
142 ifp = m->m_pkthdr.rcvif;
143
144 sdlhdr = mtod(m, struct sdl_hdr *);
145
146 /*
147 * [Copied from net/ip_input.c]
148 *
149 * Check that the amount of data in the buffers is
150 * at least as much as the LLC header tells us.
151 * Trim mbufs if longer than expected.
152 * Drop packets if shorter than we think they are.
153 *
154 * Layout of mbuf chain at this point:
155 *
156 * +-------------------------------+----+ -\
157 * | sockaddr_dl src - sdlhdr_src | 20 | \
158 * +-------------------------------+----+ |
159 * | sockaddr_dl dst - sdlhdr_dst | 20 | > sizeof(struct sdl_hdr) == 44
160 * +-------------------------------+----+ |
161 * | LLC frame len - sdlhdr_len | 04 | /
162 * +-------------------------------+----+ -/
163 * /
164 * | m_next
165 * \
166 * +----------------------------+----+ -\
167 * | llc DSAP | 01 | \
168 * +----------------------------+----+ |
169 * | llc SSAP | 01 | |
170 * +----------------------------+----+ > sdlhdr_len
171 * | llc control | 01 | |
172 * +----------------------------+----+ |
173 * | ... | | /
174 * -/
175 *
176 * Thus the we expect to have exactly
177 * (sdlhdr->sdlhdr_len+sizeof(struct sdl_hdr)) in the mbuf chain
178 */
179 expected_len = sdlhdr->sdlhdr_len + sizeof(struct sdl_hdr);
180
181 if (m->m_pkthdr.len < expected_len) {
182 m_freem(m);
183 continue;
184 }
185 if (m->m_pkthdr.len > expected_len) {
186 if (m->m_len == m->m_pkthdr.len) {
187 m->m_len = expected_len;
188 m->m_pkthdr.len = expected_len;
189 } else
190 m_adj(m, expected_len - m->m_pkthdr.len);
191 }
192
193 /*
194 * Get llc header
195 */
196 if (m->m_len > sizeof(struct sdl_hdr))
197 frame = mtod((struct mbuf *)((struct sdl_hdr*)(m+1)),
198 struct llc *);
199 else frame = mtod(m->m_next, struct llc *);
200 if (frame == (struct llc *) NULL)
201 panic("llcintr no llc header");
202
203 /*
204 * Now check for bogus I/S frame, i.e. those with a control
205 * field telling us they're an I/S frame yet their length
206 * is less than the established I/S frame length (DSAP + SSAP +
207 * control + N(R)&P/F = 4) --- we drop those suckers
208 */
209 if (((frame->llc_control & 0x03) != 0x03)
210 && ((expected_len - sizeof(struct sdl_hdr)) < LLC_ISFRAMELEN)) {
211 m_freem(m);
212 printf("llc: hurz error\n");
213 continue;
214 }
215
216 /*
217 * Get link control block for the addressed link connection.
218 * If there is none we take care of it later on.
219 */
220 cmdrsp = (frame->llc_ssap & 0x01);
221 frame->llc_ssap &= ~0x01;
222 llrt = rtalloc1((struct sockaddr *)&sdlhdr->sdlhdr_src, 0);
223 if (llrt)
224 llrt->rt_refcnt--;
225 #ifdef notyet
226 else
227 llrt = npaidb_enter(&sdlhdr->sdlhdr_src, 0, 0, 0);
228 #endif /* notyet */
229 else {
230 /*
231 * We cannot do anything currently here as we
232 * don't `know' this link --- drop it
233 */
234 m_freem(m);
235 continue;
236 }
237 linkp = ((struct npaidbentry *)(llrt->rt_llinfo))->np_link;
238 nlrt = ((struct npaidbentry *)(llrt->rt_llinfo))->np_rt;
239
240 /*
241 * If the link is not existing right now, we can try and look up
242 * the SAP info block.
243 */
244 if ((linkp == 0) && frame->llc_ssap)
245 sapinfo = llc_getsapinfo(frame->llc_dsap, ifp);
246
247 /*
248 * Handle XID and TEST frames
249 * XID: if DLSAP == 0, return type-of-services
250 * window-0
251 * DLSAP-0
252 * format-identifier-?
253 * if DLSAP != 0, locate sapcb and return
254 * type-of-services
255 * SAP-window
256 * format-identifier-?
257 * TEST: swap (snpah_dst, snpah_src) and return frame
258 *
259 * Also toggle the CMD/RESP bit
260 *
261 * Is this behaviour correct? Check ISO 8802-2 (90)!
262 */
263 frame_kind = llc_decode(frame, (struct llc_linkcb *)0);
264 switch(frame_kind) {
265 case LLCFT_XID:
266 if (linkp || sapinfo) {
267 if (linkp)
268 frame->llc_window = linkp->llcl_window;
269 else frame->llc_window = sapinfo->si_window;
270 frame->llc_fid = 9; /* XXX */
271 frame->llc_class = sapinfo->si_class;
272 frame->llc_ssap = frame->llc_dsap;
273 } else {
274 frame->llc_window = 0;
275 frame->llc_fid = 9;
276 frame->llc_class = 1;
277 frame->llc_dsap = frame->llc_ssap = 0;
278 }
279
280 /* fall thru to */
281 case LLCFT_TEST:
282 sdl_swapaddr(&(mtod(m, struct sdl_hdr *)->sdlhdr_dst),
283 &(mtod(m, struct sdl_hdr *)->sdlhdr_src));
284
285 /* Now set the CMD/RESP bit */
286 frame->llc_ssap |= (cmdrsp == 0x0 ? 0x1 : 0x0);
287
288 /* Ship it out again */
289 (*ifp->if_output)(ifp, m,
290 (struct sockaddr *) &(mtod(m, struct sdl_hdr *)->sdlhdr_dst),
291 (struct rtentry *) 0);
292 continue;
293 }
294
295 /*
296 * Create link control block in case it is not existing
297 */
298 if (linkp == 0 && sapinfo) {
299 if ((linkp = llc_newlink(&sdlhdr->sdlhdr_src, ifp, nlrt,
300 (nlrt == 0) ? 0 : nlrt->rt_llinfo,
301 llrt)) == 0) {
302 printf("llcintr: couldn't create new link\n");
303 m_freem(m);
304 continue;
305 }
306 ((struct npaidbentry *)llrt->rt_llinfo)->np_link = linkp;
307 } else if (linkp == 0) {
308 /* The link is not known to us, drop the frame and continue */
309 m_freem(m);
310 continue;
311 }
312
313 /*
314 * Drop SNPA header and get rid of empty mbuf at the
315 * front of the mbuf chain (I don't like 'em)
316 */
317 m_adj(m, sizeof(struct sdl_hdr));
318 /*
319 * LLC_UFRAMELEN is sufficient, m_pullup() will pull up
320 * the min(m->m_len, maxprotohdr_len [=40]) thus doing
321 * the trick ...
322 */
323 if ((m = m_pullup(m, LLC_UFRAMELEN)))
324 /*
325 * Pass it on thru the elements of procedure
326 */
327 llc_input(m, linkp, cmdrsp);
328 }
329 return;
330 }
331
332 /*
333 * llc_input() --- We deal with the various incoming frames here.
334 * Basically we (indirectly) call the appropriate
335 * state handler function that's pointed to by
336 * llcl_statehandler.
337 *
338 * The statehandler returns an action code ---
339 * further actions like
340 * o notify network layer
341 * o block further sending
342 * o deblock link
343 * o ...
344 * are then enacted accordingly.
345 */
346 int
347 #if __STDC__
348 llc_input(struct mbuf *m, ...)
349 #else
350 llc_input(m, va_alist)
351 struct mbuf *m;
352 va_dcl
353 #endif
354 {
355 int frame_kind;
356 int pollfinal;
357 int action = 0;
358 struct llc *frame;
359 struct llc_linkcb *linkp;
360 u_int cmdrsp;
361 va_list ap;
362
363 va_start(ap, m);
364 linkp = va_arg(ap, struct llc_linkcb *);
365 cmdrsp = va_arg(ap, u_int);
366 va_end(ap);
367
368
369 if ((frame = mtod(m, struct llc *)) == (struct llc *) 0) {
370 m_freem(m);
371 return 0;
372 }
373 pollfinal = ((frame->llc_control & 0x03) == 0x03) ?
374 LLCGBITS(frame->llc_control, u_pf) :
375 LLCGBITS(frame->llc_control_ext, s_pf);
376
377 /*
378 * first decode the frame
379 */
380 frame_kind = llc_decode(frame, linkp);
381
382 switch (action = llc_statehandler(linkp, frame, frame_kind, cmdrsp,
383 pollfinal)) {
384 case LLC_DATA_INDICATION:
385 m_adj(m, LLC_ISFRAMELEN);
386 if ((m = m_pullup(m, NLHDRSIZEGUESS)) != NULL) {
387 m->m_pkthdr.rcvif = (struct ifnet *)linkp->llcl_nlnext;
388 (*linkp->llcl_sapinfo->si_input)(m, NULL, NULL, NULL);
389 }
390 break;
391 }
392
393 /* release mbuf if not an info frame */
394 if (action != LLC_DATA_INDICATION && m)
395 m_freem(m);
396
397 /* try to get frames out ... */
398 llc_start(linkp);
399
400 return 0;
401 }
402
403 /*
404 * This routine is called by configuration setup. It sets up a station control
405 * block and notifies all registered upper level protocols.
406 */
407 void *
408 llc_ctlinput(prc, addr, info)
409 int prc;
410 struct sockaddr *addr;
411 void *info;
412 {
413 struct ifnet *ifp = NULL;
414 struct ifaddr *ifa;
415 struct dll_ctlinfo *ctlinfo = (struct dll_ctlinfo *)info;
416 u_char sap;
417 struct dllconfig *config;
418 caddr_t pcb;
419 struct rtentry *nlrt;
420 struct rtentry *llrt = NULL;
421 struct llc_linkcb *linkp = NULL;
422 int i;
423
424 /* info must point to something valid at all times */
425 if (info == 0)
426 return 0;
427
428 if (prc == PRC_IFUP || prc == PRC_IFDOWN) {
429 /* we use either this set ... */
430 ifa = ifa_ifwithaddr(addr);
431 if (ifa == NULL)
432 return (0);
433 ifp = ifa->ifa_ifp;
434 if (ifp == NULL)
435 return (0);
436
437 sap = ctlinfo->dlcti_lsap;
438 config = ctlinfo->dlcti_cfg;
439 pcb = (caddr_t) 0;
440 nlrt = (struct rtentry *) 0;
441 } else {
442 /* or this one */
443 sap = 0;
444 config = (struct dllconfig *) 0;
445 pcb = ctlinfo->dlcti_pcb;
446 nlrt = ctlinfo->dlcti_rt;
447
448 if ((llrt = rtalloc1(nlrt->rt_gateway, 0)))
449 llrt->rt_refcnt--;
450 else return 0;
451
452 linkp = ((struct npaidbentry *)llrt->rt_llinfo)->np_link;
453 }
454
455 switch (prc) {
456 case PRC_IFUP:
457 (void) llc_setsapinfo(ifp, addr->sa_family, sap, config);
458 return 0;
459
460 case PRC_IFDOWN: {
461 struct llc_linkcb *linkp;
462 struct llc_linkcb *nlinkp;
463 int i;
464
465 /*
466 * All links are accessible over the doubly linked list llccb_q
467 */
468 if (!LQEMPTY) {
469 /*
470 * A for-loop is not that great an idea as the linkp
471 * will get deleted by llc_timer()
472 */
473 linkp = LQFIRST;
474 while (LQVALID(linkp)) {
475 nlinkp = LQNEXT(linkp);
476 if ((linkp->llcl_if = ifp) != NULL) {
477 i = splnet();
478 (void)llc_statehandler(linkp, (struct llc *)0,
479 NL_DISCONNECT_REQUEST,
480 0, 1);
481 splx(i);
482 }
483 linkp = nlinkp;
484 }
485 }
486 }
487
488 case PRC_CONNECT_REQUEST:
489 if (linkp == 0) {
490 if ((linkp = llc_newlink((struct sockaddr_dl *) nlrt->rt_gateway,
491 nlrt->rt_ifp, nlrt,
492 pcb, llrt)) == 0)
493 return (0);
494 ((struct npaidbentry *)llrt->rt_llinfo)->np_link = linkp;
495 i = splnet();
496 (void)llc_statehandler(linkp, (struct llc *) 0,
497 NL_CONNECT_REQUEST, 0, 1);
498 splx(i);
499 }
500 return ((caddr_t)linkp);
501
502 case PRC_DISCONNECT_REQUEST:
503 if (linkp == 0)
504 panic("no link control block!");
505
506 i = splnet();
507 (void)llc_statehandler(linkp, (struct llc *) 0,
508 NL_DISCONNECT_REQUEST, 0, 1);
509 splx(i);
510
511 /*
512 * The actual removal of the link control block is done by the
513 * cleaning neutrum (i.e. llc_timer()).
514 */
515 break;
516
517 case PRC_RESET_REQUEST:
518 if (linkp == 0)
519 panic("no link control block!");
520
521 i = splnet();
522 (void)llc_statehandler(linkp, (struct llc *) 0,
523 NL_RESET_REQUEST, 0, 1);
524 splx(i);
525
526 break;
527
528 }
529
530 return 0;
531 }
Cache object: 0557e34910a4a53cf484dd563c7e98e3
|