1 /* $NetBSD: llc_input.c,v 1.14 2005/02/26 22:45:10 perry 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.14 2005/02/26 22:45:10 perry 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 llc_input(struct mbuf *m, ...)
348 {
349 int frame_kind;
350 int pollfinal;
351 int action = 0;
352 struct llc *frame;
353 struct llc_linkcb *linkp;
354 u_int cmdrsp;
355 va_list ap;
356
357 va_start(ap, m);
358 linkp = va_arg(ap, struct llc_linkcb *);
359 cmdrsp = va_arg(ap, u_int);
360 va_end(ap);
361
362
363 if ((frame = mtod(m, struct llc *)) == (struct llc *) 0) {
364 m_freem(m);
365 return 0;
366 }
367 pollfinal = ((frame->llc_control & 0x03) == 0x03) ?
368 LLCGBITS(frame->llc_control, u_pf) :
369 LLCGBITS(frame->llc_control_ext, s_pf);
370
371 /*
372 * first decode the frame
373 */
374 frame_kind = llc_decode(frame, linkp);
375
376 switch (action = llc_statehandler(linkp, frame, frame_kind, cmdrsp,
377 pollfinal)) {
378 case LLC_DATA_INDICATION:
379 m_adj(m, LLC_ISFRAMELEN);
380 if ((m = m_pullup(m, NLHDRSIZEGUESS)) != NULL) {
381 m->m_pkthdr.rcvif = (struct ifnet *)linkp->llcl_nlnext;
382 (*linkp->llcl_sapinfo->si_input)(m, NULL, NULL, NULL);
383 }
384 break;
385 }
386
387 /* release mbuf if not an info frame */
388 if (action != LLC_DATA_INDICATION && m)
389 m_freem(m);
390
391 /* try to get frames out ... */
392 llc_start(linkp);
393
394 return 0;
395 }
396
397 /*
398 * This routine is called by configuration setup. It sets up a station control
399 * block and notifies all registered upper level protocols.
400 */
401 void *
402 llc_ctlinput(prc, addr, info)
403 int prc;
404 struct sockaddr *addr;
405 void *info;
406 {
407 struct ifnet *ifp = NULL;
408 struct ifaddr *ifa;
409 struct dll_ctlinfo *ctlinfo = (struct dll_ctlinfo *)info;
410 u_char sap;
411 struct dllconfig *config;
412 caddr_t pcb;
413 struct rtentry *nlrt;
414 struct rtentry *llrt = NULL;
415 struct llc_linkcb *linkp = NULL;
416 int i;
417
418 /* info must point to something valid at all times */
419 if (info == 0)
420 return 0;
421
422 if (prc == PRC_IFUP || prc == PRC_IFDOWN) {
423 /* we use either this set ... */
424 ifa = ifa_ifwithaddr(addr);
425 if (ifa == NULL)
426 return (0);
427 ifp = ifa->ifa_ifp;
428 if (ifp == NULL)
429 return (0);
430
431 sap = ctlinfo->dlcti_lsap;
432 config = ctlinfo->dlcti_cfg;
433 pcb = (caddr_t) 0;
434 nlrt = (struct rtentry *) 0;
435 } else {
436 /* or this one */
437 sap = 0;
438 config = (struct dllconfig *) 0;
439 pcb = ctlinfo->dlcti_pcb;
440 nlrt = ctlinfo->dlcti_rt;
441
442 if ((llrt = rtalloc1(nlrt->rt_gateway, 0)))
443 llrt->rt_refcnt--;
444 else return 0;
445
446 linkp = ((struct npaidbentry *)llrt->rt_llinfo)->np_link;
447 }
448
449 switch (prc) {
450 case PRC_IFUP:
451 (void) llc_setsapinfo(ifp, addr->sa_family, sap, config);
452 return 0;
453
454 case PRC_IFDOWN: {
455 struct llc_linkcb *linkp;
456 struct llc_linkcb *nlinkp;
457 int i;
458
459 /*
460 * All links are accessible over the doubly linked list llccb_q
461 */
462 if (!LQEMPTY) {
463 /*
464 * A for-loop is not that great an idea as the linkp
465 * will get deleted by llc_timer()
466 */
467 linkp = LQFIRST;
468 while (LQVALID(linkp)) {
469 nlinkp = LQNEXT(linkp);
470 if ((linkp->llcl_if = ifp) != NULL) {
471 i = splnet();
472 (void)llc_statehandler(linkp, (struct llc *)0,
473 NL_DISCONNECT_REQUEST,
474 0, 1);
475 splx(i);
476 }
477 linkp = nlinkp;
478 }
479 }
480 }
481
482 case PRC_CONNECT_REQUEST:
483 if (linkp == 0) {
484 if ((linkp = llc_newlink((struct sockaddr_dl *) nlrt->rt_gateway,
485 nlrt->rt_ifp, nlrt,
486 pcb, llrt)) == 0)
487 return (0);
488 ((struct npaidbentry *)llrt->rt_llinfo)->np_link = linkp;
489 i = splnet();
490 (void)llc_statehandler(linkp, (struct llc *) 0,
491 NL_CONNECT_REQUEST, 0, 1);
492 splx(i);
493 }
494 return ((caddr_t)linkp);
495
496 case PRC_DISCONNECT_REQUEST:
497 if (linkp == 0)
498 panic("no link control block!");
499
500 i = splnet();
501 (void)llc_statehandler(linkp, (struct llc *) 0,
502 NL_DISCONNECT_REQUEST, 0, 1);
503 splx(i);
504
505 /*
506 * The actual removal of the link control block is done by the
507 * cleaning neutrum (i.e. llc_timer()).
508 */
509 break;
510
511 case PRC_RESET_REQUEST:
512 if (linkp == 0)
513 panic("no link control block!");
514
515 i = splnet();
516 (void)llc_statehandler(linkp, (struct llc *) 0,
517 NL_RESET_REQUEST, 0, 1);
518 splx(i);
519
520 break;
521
522 }
523
524 return 0;
525 }
Cache object: 03f3e2747d686b7704a2cdd84c946310
|