FreeBSD/Linux Kernel Cross Reference
sys/net/if_spppfr.c
1 /*-
2 * Synchronous Frame Relay link level subroutines.
3 * ANSI T1.617-compaible link management signaling
4 * implemented for Frame Relay mode.
5 * Cisco-type Frame Relay framing added, thanks Alex Tutubalin.
6 * Only one DLCI per channel for now.
7 *
8 * Copyright (C) 1994-2000 Cronyx Engineering.
9 * Author: Serge Vakulenko, <vak@cronyx.ru>
10 *
11 * Copyright (C) 1999-2005 Cronyx Engineering.
12 * Author: Kurakin Roman, <rik@cronyx.ru>
13 *
14 * This software is distributed with NO WARRANTIES, not even the implied
15 * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 *
17 * Authors grant any other persons or organisations a permission to use,
18 * modify and redistribute this software in source and binary forms,
19 * as long as this message is kept with the software, all derivative
20 * works or modified versions.
21 *
22 * $Cronyx Id: if_spppfr.c,v 1.2 2005/04/23 20:10:22 rik Exp $
23 * $FreeBSD$
24 */
25
26 #include <sys/param.h>
27
28 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
29 #include "opt_inet.h"
30 #if __FreeBSD_version >= 420000
31 # include "opt_inet6.h"
32 #endif
33 #include "opt_ipx.h"
34 #endif
35
36 #ifdef NetBSD1_3
37 # if NetBSD1_3 > 6
38 # include "opt_inet.h"
39 # include "opt_inet6.h"
40 # include "opt_iso.h"
41 # endif
42 #endif
43
44 #include <sys/systm.h>
45 #include <sys/kernel.h>
46 #include <sys/module.h>
47 #include <sys/sockio.h>
48 #include <sys/socket.h>
49 #include <sys/syslog.h>
50 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
51 #if __FreeBSD_version >= 410000
52 #include <sys/random.h>
53 #else
54 #include <machine/random.h>
55 #endif
56 #endif
57 #include <sys/malloc.h>
58 #include <sys/mbuf.h>
59
60 #if defined (__OpenBSD__)
61 #include <sys/md5k.h>
62 #else
63 #include <sys/md5.h>
64 #endif
65
66 #include <net/if.h>
67 #include <net/netisr.h>
68 #include <net/if_types.h>
69 #include <net/route.h>
70 #include <netinet/in.h>
71 #include <netinet/in_systm.h>
72 #include <netinet/ip.h>
73 #include <net/slcompress.h>
74
75 #if defined (__NetBSD__) || defined (__OpenBSD__)
76 #include <machine/cpu.h> /* XXX for softnet */
77 #endif
78
79 #include <machine/stdarg.h>
80
81 #include <netinet/in_var.h>
82 #ifdef INET
83 #include <netinet/ip.h>
84 #include <netinet/tcp.h>
85 #endif
86
87 #if defined (__FreeBSD__) || defined (__OpenBSD__)
88 # include <netinet/if_ether.h>
89 #else
90 # include <net/ethertypes.h>
91 #endif
92
93 #ifdef IPX
94 #include <netipx/ipx.h>
95 #include <netipx/ipx_if.h>
96 #endif
97
98 #if __FreeBSD_version < 501000
99 # ifdef NS
100 # include <netns/ns.h>
101 # include <netns/ns_if.h>
102 # endif
103 #endif
104
105 #include <net/if_sppp.h>
106
107 /*
108 * Frame Relay.
109 */
110 #define FR_UI 0x03 /* Unnumbered Information */
111 #define FR_IP 0xCC /* IP protocol identifier */
112 #define FR_PADDING 0x00 /* NLPID padding */
113 #define FR_SIGNALING 0x08 /* Q.933/T1.617 signaling identifier */
114 #define FR_SNAP 0x80 /* NLPID snap */
115
116 /*
117 * Header flags.
118 */
119 #define FR_DE 0x02 /* discard eligibility */
120 #define FR_FECN 0x04 /* forward notification */
121 #define FR_BECN 0x08 /* backward notification */
122
123 /*
124 * Signaling message types.
125 */
126 #define FR_MSG_ENQUIRY 0x75 /* status enquiry */
127 #define FR_MSG_STATUS 0x7d /* status */
128
129 #define FR_ENQUIRY_SIZE 14
130
131 /*
132 * Message field types.
133 */
134 #define FR_FLD_RTYPE 0x01 /* report type */
135 #define FR_FLD_VERIFY 0x03 /* link verification */
136 #define FR_FLD_PVC 0x07 /* PVC status */
137 #define FR_FLD_LSHIFT5 0x95 /* locking shift 5 */
138
139 /*
140 * Report types.
141 */
142 #define FR_RTYPE_FULL 0 /* full status */
143 #define FR_RTYPE_SHORT 1 /* link verification only */
144 #define FR_RTYPE_SINGLE 2 /* single PVC status */
145
146 /* PVC status field. */
147 #define FR_DLCI_DELETE 0x04 /* PVC is deleted */
148 #define FR_DLCI_ACTIVE 0x02 /* PVC is operational */
149 #define FR_DLCI_NEW 0x08 /* PVC is new */
150
151 struct arp_req {
152 unsigned short htype; /* hardware type = ARPHRD_FRELAY */
153 unsigned short ptype; /* protocol type = ETHERTYPE_IP */
154 unsigned char halen; /* hardware address length = 2 */
155 unsigned char palen; /* protocol address length = 4 */
156 unsigned short op; /* ARP/RARP/InARP request/reply */
157 unsigned short hsource; /* hardware source address */
158 unsigned short psource1; /* protocol source */
159 unsigned short psource2;
160 unsigned short htarget; /* hardware target address */
161 unsigned short ptarget1; /* protocol target */
162 unsigned short ptarget2;
163 #if __FreeBSD_version >= 500000
164 } __packed;
165 #else
166 } __attribute__((__packed__));
167 #endif
168
169 #if defined(__FreeBSD__) && __FreeBSD__ >= 3 && __FreeBSD_version < 501113
170 #define SPP_FMT "%s%d: "
171 #define SPP_ARGS(ifp) (ifp)->if_name, (ifp)->if_unit
172 #else
173 #define SPP_FMT "%s: "
174 #define SPP_ARGS(ifp) (ifp)->if_xname
175 #endif
176
177 /* almost every function needs these */
178 #define STDDCL \
179 struct ifnet *ifp = &sp->pp_if; \
180 int debug = ifp->if_flags & IFF_DEBUG
181
182 static void sppp_fr_arp (struct sppp *sp, struct arp_req *req, u_short addr);
183 static void sppp_fr_signal (struct sppp *sp, unsigned char *h, int len);
184
185 void sppp_fr_input (struct sppp *sp, struct mbuf *m)
186 {
187 STDDCL;
188 u_char *h = mtod (m, u_char*);
189 #if __FreeBSD_version >= 501000
190 int isr = -1;
191 #else
192 struct ifqueue *inq = 0;
193 #endif
194 int dlci, hlen, proto;
195 #if __FreeBSD_version < 500000
196 int s;
197 #endif
198 /* Get the DLCI number. */
199 if (m->m_pkthdr.len < 10) {
200 bad: m_freem (m);
201 return;
202 }
203 dlci = (h[0] << 2 & 0x3f0) | (h[1] >> 4 & 0x0f);
204
205 /* Process signaling packets. */
206 if (dlci == 0) {
207 sppp_fr_signal (sp, h, m->m_pkthdr.len);
208 m_freem (m);
209 return;
210 }
211
212 if (dlci != sp->fr_dlci) {
213 if (debug)
214 printf (SPP_FMT "Received packet from invalid DLCI %d\n",
215 SPP_ARGS(ifp), dlci);
216 goto bad;
217 }
218
219 /* Process the packet. */
220 if (ntohs (*(short*) (h+2)) == ETHERTYPE_IP) {
221 /* Prehistoric IP framing? */
222 h[2] = FR_UI;
223 h[3] = FR_IP;
224 }
225 if (h[2] != FR_UI) {
226 if (debug)
227 printf (SPP_FMT "Invalid frame relay header flag 0x%02x\n",
228 SPP_ARGS(ifp), h[2]);
229 goto bad;
230 }
231 switch (h[3]) {
232 default:
233 if (debug)
234 printf (SPP_FMT "Unsupported NLPID 0x%02x\n",
235 SPP_ARGS(ifp), h[3]);
236 goto bad;
237
238 case FR_PADDING:
239 if (h[4] != FR_SNAP) {
240 if (debug)
241 printf (SPP_FMT "Bad NLPID 0x%02x\n",
242 SPP_ARGS(ifp), h[4]);
243 goto bad;
244 }
245 if (h[5] || h[6] || h[7]) {
246 if (debug)
247 printf (SPP_FMT "Bad OID 0x%02x-0x%02x-0x%02x\n",
248 SPP_ARGS(ifp),
249 h[5], h[6], h[7]);
250 goto bad;
251 }
252 proto = ntohs (*(short*) (h+8));
253 if (proto == ETHERTYPE_ARP) {
254 /* Process the ARP request. */
255 if (m->m_pkthdr.len != 10 + sizeof (struct arp_req)) {
256 if (debug)
257 printf (SPP_FMT "Bad ARP request size = %d bytes\n",
258 SPP_ARGS(ifp),
259 m->m_pkthdr.len);
260 goto bad;
261 }
262 sppp_fr_arp (sp, (struct arp_req*) (h + 10),
263 h[0] << 8 | h[1]);
264 m_freem (m);
265 return;
266 }
267 hlen = 10;
268 break;
269
270 case FR_IP:
271 proto = ETHERTYPE_IP;
272 hlen = 4;
273 break;
274 }
275
276 /* Remove frame relay header. */
277 m_adj (m, hlen);
278
279 switch (proto) {
280 default:
281 ++ifp->if_noproto;
282 drop: ++ifp->if_ierrors;
283 ++ifp->if_iqdrops;
284 m_freem (m);
285 return;
286 #ifdef INET
287 case ETHERTYPE_IP:
288 #if __FreeBSD_version >= 501000
289 isr = NETISR_IP;
290 #else
291 schednetisr (NETISR_IP);
292 inq = &ipintrq;
293 #endif
294 break;
295 #endif
296 #ifdef IPX
297 case ETHERTYPE_IPX:
298 #if __FreeBSD_version >= 501000
299 isr = NETISR_IPX;
300 #else
301 schednetisr (NETISR_IPX);
302 inq = &ipxintrq;
303 #endif
304 break;
305 #endif
306 #if __FreeBSD_version < 501000
307 #ifdef NS
308 case 0x8137: /* Novell Ethernet_II Ethernet TYPE II */
309 schednetisr (NETISR_NS);
310 inq = &nsintrq;
311 break;
312 #endif
313 #endif
314 #ifdef NETATALK
315 case ETHERTYPE_AT:
316 #if __FreeBSD_version >= 501000
317 isr = NETISR_ATALK;
318 #else
319 schednetisr (NETISR_ATALK);
320 inq = &atintrq1;
321 #endif
322 break;
323 #endif
324 }
325
326 if (! (ifp->if_flags & IFF_UP))
327 goto drop;
328
329 /* Check queue. */
330 #if __FreeBSD_version >= 500000
331 #if __FreeBSD_version >= 501000
332 if (! netisr_queue(isr, m)) {
333 #else
334 if (! IF_HANDOFF(inq, m, NULL)) {
335 #endif
336 if (debug)
337 log(LOG_DEBUG, SPP_FMT "protocol queue overflow\n",
338 SPP_ARGS(ifp));
339 }
340 #else
341 s = splimp();
342 if (IF_QFULL (inq)) {
343 /* Queue overflow. */
344 IF_DROP(inq);
345 splx(s);
346 if (debug)
347 log(LOG_DEBUG, SPP_FMT "protocol queue overflow\n",
348 SPP_ARGS(ifp));
349 goto drop;
350 }
351 IF_ENQUEUE(inq, m);
352 splx(s);
353 #endif
354 }
355
356 /*
357 * Add the frame relay header to the packet.
358 * For IP the header length is 4 bytes,
359 * for all other protocols - 10 bytes (RFC 1490).
360 */
361 struct mbuf *sppp_fr_header (struct sppp *sp, struct mbuf *m,
362 int family)
363 {
364 STDDCL;
365 u_char *h;
366 int type, hlen;
367
368 /* Prepend the space for Frame Relay header. */
369 hlen = (family == AF_INET) ? 4 : 10;
370 M_PREPEND (m, hlen, M_DONTWAIT);
371 if (! m)
372 return 0;
373 h = mtod (m, u_char*);
374
375 /* Fill the header. */
376 h[0] = sp->fr_dlci >> 2 & 0xfc;
377 h[1] = sp->fr_dlci << 4 | 1;
378 h[2] = FR_UI;
379
380 switch (family) {
381 default:
382 if (debug)
383 printf (SPP_FMT "Cannot handle address family %d\n",
384 SPP_ARGS(ifp), family);
385 m_freem (m);
386 return 0;
387 #ifdef INET
388 case AF_INET:
389 #if 0 /* Crashes on fragmented packets */
390 /*
391 * Set the discard eligibility bit, if:
392 * 1) no fragmentation
393 * 2) length > 400 bytes
394 * 3a) the protocol is UDP or
395 * 3b) TCP data (no control bits)
396 */
397 {
398 struct ip *ip = (struct ip*) (h + hlen);
399 struct tcphdr *tcp = (struct tcphdr*) ((long*)ip + ip->ip_hl);
400
401 if (! (ip->ip_off & ~IP_DF) && ip->ip_len > 400 &&
402 (ip->ip_p == IPPROTO_UDP ||
403 ip->ip_p == IPPROTO_TCP && ! tcp->th_flags))
404 h[1] |= FR_DE;
405 }
406 #endif
407 h[3] = FR_IP;
408 return m;
409 #endif
410 #ifdef IPX
411 case AF_IPX:
412 type = ETHERTYPE_IPX;
413 break;
414 #endif
415 #ifdef NS
416 case AF_NS:
417 type = 0x8137;
418 break;
419 #endif
420 #ifdef NETATALK
421 case AF_APPLETALK:
422 type = ETHERTYPE_AT;
423 break;
424 #endif
425 }
426 h[3] = FR_PADDING;
427 h[4] = FR_SNAP;
428 h[5] = 0;
429 h[6] = 0;
430 h[7] = 0;
431 *(short*) (h+8) = htons(type);
432 return m;
433 }
434
435 /*
436 * Send periodical frame relay link verification messages via DLCI 0.
437 * Called every 10 seconds (default value of T391 timer is 10 sec).
438 * Every 6-th message is a full status request
439 * (default value of N391 counter is 6).
440 */
441 void sppp_fr_keepalive (struct sppp *sp)
442 {
443 STDDCL;
444 unsigned char *h, *p;
445 struct mbuf *m;
446
447 MGETHDR (m, M_DONTWAIT, MT_DATA);
448 if (! m)
449 return;
450 m->m_pkthdr.rcvif = 0;
451
452 h = mtod (m, u_char*);
453 p = h;
454 *p++ = 0; /* DLCI = 0 */
455 *p++ = 1;
456 *p++ = FR_UI;
457 *p++ = FR_SIGNALING; /* NLPID = UNI call control */
458
459 *p++ = 0; /* call reference length = 0 */
460 *p++ = FR_MSG_ENQUIRY; /* message type = status enquiry */
461
462 *p++ = FR_FLD_LSHIFT5; /* locking shift 5 */
463
464 *p++ = FR_FLD_RTYPE; /* report type field */
465 *p++ = 1; /* report type length = 1 */
466 if (sp->pp_seq[IDX_LCP] % 6)
467 *p++ = FR_RTYPE_SHORT; /* link verification only */
468 else
469 *p++ = FR_RTYPE_FULL; /* full status needed */
470
471 if (sp->pp_seq[IDX_LCP] >= 255)
472 sp->pp_seq[IDX_LCP] = 0;
473 *p++ = FR_FLD_VERIFY; /* link verification type field */
474 *p++ = 2; /* link verification field length = 2 */
475 *p++ = ++sp->pp_seq[IDX_LCP]; /* our sequence number */
476 *p++ = sp->pp_rseq[IDX_LCP]; /* last received sequence number */
477
478 m->m_pkthdr.len = m->m_len = p - h;
479 if (debug)
480 printf (SPP_FMT "send lmi packet, seq=%d, rseq=%d\n",
481 SPP_ARGS(ifp), (u_char) sp->pp_seq[IDX_LCP],
482 (u_char) sp->pp_rseq[IDX_LCP]);
483
484 #if __FreeBSD_version >= 500000
485 if (! IF_HANDOFF_ADJ(&sp->pp_cpq, m, ifp, 3))
486 ++ifp->if_oerrors;
487 #else
488 if (IF_QFULL (&sp->pp_cpq)) {
489 IF_DROP (&ifp->if_snd);
490 m_freem (m);
491 return;
492 } else
493 IF_ENQUEUE (&sp->pp_cpq, m);
494 if (! (ifp->if_flags & IFF_OACTIVE))
495 (*ifp->if_start) (ifp);
496 ifp->if_obytes += m->m_pkthdr.len + 3;
497 #endif
498 }
499
500 /*
501 * Process the frame relay Inverse ARP request.
502 */
503 static void sppp_fr_arp (struct sppp *sp, struct arp_req *req,
504 u_short his_hardware_address)
505 {
506 STDDCL;
507 struct mbuf *m;
508 struct arp_req *reply;
509 u_char *h;
510 u_short my_hardware_address;
511 u_long his_ip_address, my_ip_address;
512
513 if ((ntohs (req->htype) != ARPHRD_FRELAY ||
514 ntohs (req->htype) != 16) || /* for BayNetworks routers */
515 ntohs (req->ptype) != ETHERTYPE_IP) {
516 if (debug)
517 printf (SPP_FMT "Invalid ARP hardware/protocol type = 0x%x/0x%x\n",
518 SPP_ARGS(ifp),
519 ntohs (req->htype), ntohs (req->ptype));
520 return;
521 }
522 if (req->halen != 2 || req->palen != 4) {
523 if (debug)
524 printf (SPP_FMT "Invalid ARP hardware/protocol address length = %d/%d\n",
525 SPP_ARGS(ifp),
526 req->halen, req->palen);
527 return;
528 }
529 switch (ntohs (req->op)) {
530 default:
531 if (debug)
532 printf (SPP_FMT "Invalid ARP op = 0x%x\n",
533 SPP_ARGS(ifp), ntohs (req->op));
534 return;
535
536 case ARPOP_INVREPLY:
537 /* Ignore. */
538 return;
539
540 case ARPOP_INVREQUEST:
541 my_hardware_address = ntohs (req->htarget);
542 his_ip_address = ntohs (req->psource1) << 16 |
543 ntohs (req->psource2);
544 my_ip_address = ntohs (req->ptarget1) << 16 |
545 ntohs (req->ptarget2);
546 break;
547 }
548 if (debug)
549 printf (SPP_FMT "got ARP request, source=0x%04x/%d.%d.%d.%d, target=0x%04x/%d.%d.%d.%d\n",
550 SPP_ARGS(ifp), ntohs (req->hsource),
551 (unsigned char) (his_ip_address >> 24),
552 (unsigned char) (his_ip_address >> 16),
553 (unsigned char) (his_ip_address >> 8),
554 (unsigned char) his_ip_address,
555 my_hardware_address,
556 (unsigned char) (my_ip_address >> 24),
557 (unsigned char) (my_ip_address >> 16),
558 (unsigned char) (my_ip_address >> 8),
559 (unsigned char) my_ip_address);
560
561 sppp_get_ip_addrs (sp, &my_ip_address, 0, 0);
562 if (! my_ip_address)
563 return; /* nothing to reply */
564
565 if (debug)
566 printf (SPP_FMT "send ARP reply, source=0x%04x/%d.%d.%d.%d, target=0x%04x/%d.%d.%d.%d\n",
567 SPP_ARGS(ifp), my_hardware_address,
568 (unsigned char) (my_ip_address >> 24),
569 (unsigned char) (my_ip_address >> 16),
570 (unsigned char) (my_ip_address >> 8),
571 (unsigned char) my_ip_address,
572 his_hardware_address,
573 (unsigned char) (his_ip_address >> 24),
574 (unsigned char) (his_ip_address >> 16),
575 (unsigned char) (his_ip_address >> 8),
576 (unsigned char) his_ip_address);
577
578 /* Send the Inverse ARP reply. */
579 MGETHDR (m, M_DONTWAIT, MT_DATA);
580 if (! m)
581 return;
582 m->m_pkthdr.len = m->m_len = 10 + sizeof (*reply);
583 m->m_pkthdr.rcvif = 0;
584
585 h = mtod (m, u_char*);
586 reply = (struct arp_req*) (h + 10);
587
588 h[0] = his_hardware_address >> 8;
589 h[1] = his_hardware_address;
590 h[2] = FR_UI;
591 h[3] = FR_PADDING;
592 h[4] = FR_SNAP;
593 h[5] = 0;
594 h[6] = 0;
595 h[7] = 0;
596 *(short*) (h+8) = htons (ETHERTYPE_ARP);
597
598 reply->htype = htons (ARPHRD_FRELAY);
599 reply->ptype = htons (ETHERTYPE_IP);
600 reply->halen = 2;
601 reply->palen = 4;
602 reply->op = htons (ARPOP_INVREPLY);
603 reply->hsource = htons (my_hardware_address);
604 reply->psource1 = htonl (my_ip_address);
605 reply->psource2 = htonl (my_ip_address) >> 16;
606 reply->htarget = htons (his_hardware_address);
607 reply->ptarget1 = htonl (his_ip_address);
608 reply->ptarget2 = htonl (his_ip_address) >> 16;
609
610 #if __FreeBSD_version >= 500000
611 if (! IF_HANDOFF_ADJ(&sp->pp_cpq, m, ifp, 3))
612 ++ifp->if_oerrors;
613 #else
614 if (IF_QFULL (&sp->pp_cpq)) {
615 IF_DROP (&ifp->if_snd);
616 m_freem (m);
617 return;
618 } else
619 IF_ENQUEUE (&sp->pp_cpq, m);
620 if (! (ifp->if_flags & IFF_OACTIVE))
621 (*ifp->if_start) (ifp);
622 ifp->if_obytes += m->m_pkthdr.len + 3;
623 #endif
624 }
625
626 /*
627 * Process the input signaling packet (DLCI 0).
628 * The implemented protocol is ANSI T1.617 Annex D.
629 */
630 static void sppp_fr_signal (struct sppp *sp, unsigned char *h, int len)
631 {
632 STDDCL;
633 u_char *p;
634 int dlci;
635
636 if (h[2] != FR_UI || h[3] != FR_SIGNALING || h[4] != 0) {
637 if (debug)
638 printf (SPP_FMT "Invalid signaling header\n",
639 SPP_ARGS(ifp));
640 bad: if (debug) {
641 printf ("%02x", *h++);
642 while (--len > 0)
643 printf ("-%02x", *h++);
644 printf ("\n");
645 }
646 return;
647 }
648 if (h[5] == FR_MSG_ENQUIRY) {
649 if (len == FR_ENQUIRY_SIZE &&
650 h[12] == (u_char) sp->pp_seq[IDX_LCP]) {
651 sp->pp_seq[IDX_LCP] = random();
652 printf (SPP_FMT "loopback detected\n",
653 SPP_ARGS(ifp));
654 }
655 return;
656 }
657 if (h[5] != FR_MSG_STATUS) {
658 if (debug)
659 printf (SPP_FMT "Unknown signaling message: 0x%02x\n",
660 SPP_ARGS(ifp), h[5]);
661 goto bad;
662 }
663
664 /* Parse message fields. */
665 for (p=h+6; p<h+len; ) {
666 switch (*p) {
667 default:
668 if (debug)
669 printf (SPP_FMT "Unknown signaling field 0x%x\n",
670 SPP_ARGS(ifp), *p);
671 break;
672 case FR_FLD_LSHIFT5:
673 case FR_FLD_RTYPE:
674 /* Ignore. */
675 break;
676 case FR_FLD_VERIFY:
677 if (p[1] != 2) {
678 if (debug)
679 printf (SPP_FMT "Invalid signaling verify field length %d\n",
680 SPP_ARGS(ifp), p[1]);
681 break;
682 }
683 sp->pp_rseq[IDX_LCP] = p[2];
684 if (debug) {
685 printf (SPP_FMT "got lmi reply rseq=%d, seq=%d",
686 SPP_ARGS(ifp), p[2], p[3]);
687 if (p[3] != (u_char) sp->pp_seq[IDX_LCP])
688 printf (" (really %d)",
689 (u_char) sp->pp_seq[IDX_LCP]);
690 printf ("\n");
691 }
692 break;
693 case FR_FLD_PVC:
694 if (p[1] < 3) {
695 if (debug)
696 printf (SPP_FMT "Invalid PVC status length %d\n",
697 SPP_ARGS(ifp), p[1]);
698 break;
699 }
700 dlci = (p[2] << 4 & 0x3f0) | (p[3] >> 3 & 0x0f);
701 if (! sp->fr_dlci)
702 sp->fr_dlci = dlci;
703 if (sp->fr_status != p[4])
704 printf (SPP_FMT "DLCI %d %s%s\n",
705 SPP_ARGS(ifp), dlci,
706 p[4] & FR_DLCI_DELETE ? "deleted" :
707 p[4] & FR_DLCI_ACTIVE ? "active" : "passive",
708 p[4] & FR_DLCI_NEW ? ", new" : "");
709 sp->fr_status = p[4];
710 break;
711 }
712 if (*p & 0x80)
713 ++p;
714 else if (p < h+len+1 && p[1])
715 p += 2 + p[1];
716 else {
717 if (debug)
718 printf (SPP_FMT "Invalid signaling field 0x%x\n",
719 SPP_ARGS(ifp), *p);
720 goto bad;
721 }
722 }
723 }
Cache object: f1e7b79e8434fa03f25c0351d5d0bac5
|