1/*
2 * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the University of California,
13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
16 * written permission.
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 */
21
22#ifndef lint
23static const char rcsid[] _U_ =
24	"@(#)$Header: /tcpdump/master/tcpdump/print-fr.c,v 1.32.2.15 2006/02/01 14:39:56 hannes Exp $ (LBL)";
25#endif
26
27#ifdef HAVE_CONFIG_H
28#include "config.h"
29#endif
30
31#include <tcpdump-stdinc.h>
32
33#include <stdio.h>
34#include <string.h>
35#include <pcap.h>
36
37#include "addrtoname.h"
38#include "interface.h"
39#include "ethertype.h"
40#include "nlpid.h"
41#include "extract.h"
42#include "oui.h"
43
44static void frf15_print(const u_char *, u_int);
45
46/*
47 * the frame relay header has a variable length
48 *
49 * the EA bit determines if there is another byte
50 * in the header
51 *
52 * minimum header length is 2 bytes
53 * maximum header length is 4 bytes
54 *
55 *      7    6    5    4    3    2    1    0
56 *    +----+----+----+----+----+----+----+----+
57 *    |        DLCI (6 bits)        | CR | EA |
58 *    +----+----+----+----+----+----+----+----+
59 *    |   DLCI (4 bits)   |FECN|BECN| DE | EA |
60 *    +----+----+----+----+----+----+----+----+
61 *    |           DLCI (7 bits)          | EA |
62 *    +----+----+----+----+----+----+----+----+
63 *    |        DLCI (6 bits)        |SDLC| EA |
64 *    +----+----+----+----+----+----+----+----+
65 */
66
67#define FR_EA_BIT	0x01
68
69#define FR_CR_BIT       0x02000000
70#define FR_DE_BIT	0x00020000
71#define FR_BECN_BIT	0x00040000
72#define FR_FECN_BIT	0x00080000
73#define FR_SDLC_BIT	0x00000002
74
75
76struct tok fr_header_flag_values[] = {
77    { FR_CR_BIT, "C!" },
78    { FR_DE_BIT, "DE" },
79    { FR_BECN_BIT, "BECN" },
80    { FR_FECN_BIT, "FECN" },
81    { FR_SDLC_BIT, "sdlcore" },
82    { 0, NULL }
83};
84
85/* FRF.15 / FRF.16 */
86#define MFR_B_BIT 0x80
87#define MFR_E_BIT 0x40
88#define MFR_C_BIT 0x20
89#define MFR_BEC_MASK    (MFR_B_BIT | MFR_E_BIT | MFR_C_BIT)
90#define MFR_CTRL_FRAME  (MFR_B_BIT | MFR_E_BIT | MFR_C_BIT)
91#define MFR_FRAG_FRAME  (MFR_B_BIT | MFR_E_BIT )
92
93struct tok frf_flag_values[] = {
94    { MFR_B_BIT, "Begin" },
95    { MFR_E_BIT, "End" },
96    { MFR_C_BIT, "Control" },
97    { 0, NULL }
98};
99
100/* Finds out Q.922 address length, DLCI and flags. Returns 0 on success
101 * save the flags dep. on address length
102 */
103static int parse_q922_addr(const u_char *p, u_int *dlci, u_int *sdlcore,
104                           u_int *addr_len, u_int8_t *flags)
105{
106	if ((p[0] & FR_EA_BIT))
107		return -1;
108
109	*addr_len = 2;
110	*dlci = ((p[0] & 0xFC) << 2) | ((p[1] & 0xF0) >> 4);
111
112        flags[0] = p[0] & 0x02; /* populate the first flag fields */
113        flags[1] = p[1] & 0x0c;
114        flags[2] = 0;           /* clear the rest of the flags */
115        flags[3] = 0;
116
117	if (p[1] & FR_EA_BIT)
118		return 0;	/* 2-byte Q.922 address */
119
120	p += 2;
121	(*addr_len)++;		/* 3- or 4-byte Q.922 address */
122	if ((p[0] & FR_EA_BIT) == 0) {
123		*dlci = (*dlci << 7) | (p[0] >> 1);
124		(*addr_len)++;	/* 4-byte Q.922 address */
125		p++;
126	}
127
128	if ((p[0] & FR_EA_BIT) == 0)
129		return -1; /* more than 4 bytes of Q.922 address? */
130
131        flags[3] = p[0] & 0x02;
132
133	if (p[0] & 0x02)
134                *sdlcore =  p[0] >> 2;
135	else
136		*dlci = (*dlci << 6) | (p[0] >> 2);
137
138	return 0;
139}
140
141/* Frame Relay packet structure, with flags and CRC removed
142
143                  +---------------------------+
144                  |       Q.922 Address*      |
145                  +--                       --+
146                  |                           |
147                  +---------------------------+
148                  | Control (UI = 0x03)       |
149                  +---------------------------+
150                  | Optional Pad      (0x00)  |
151                  +---------------------------+
152                  | NLPID                     |
153                  +---------------------------+
154                  |             .             |
155                  |             .             |
156                  |             .             |
157                  |           Data            |
158                  |             .             |
159                  |             .             |
160                  +---------------------------+
161
162           * Q.922 addresses, as presently defined, are two octets and
163             contain a 10-bit DLCI.  In some networks Q.922 addresses
164             may optionally be increased to three or four octets.
165*/
166
167static u_int
168fr_hdrlen(const u_char *p, u_int addr_len)
169{
170	if (!p[addr_len + 1] /* pad exist */)
171		return addr_len + 1 /* UI */ + 1 /* pad */ + 1 /* NLPID */;
172	else
173		return addr_len + 1 /* UI */ + 1 /* NLPID */;
174}
175
176static void
177fr_hdr_print(int length, u_int addr_len, u_int dlci, u_int8_t *flags, u_int16_t nlpid)
178{
179    if (qflag) {
180        (void)printf("Q.922, DLCI %u, length %u: ",
181                     dlci,
182                     length);
183    } else {
184        if (nlpid <= 0xff) /* if its smaller than 256 then its a NLPID */
185            (void)printf("Q.922, hdr-len %u, DLCI %u, Flags [%s], NLPID %s (0x%02x), length %u: ",
186                         addr_len,
187                         dlci,
188                         bittok2str(fr_header_flag_values, "none", EXTRACT_32BITS(flags)),
189                         tok2str(nlpid_values,"unknown", nlpid),
190                         nlpid,
191                         length);
192        else /* must be an ethertype */
193            (void)printf("Q.922, hdr-len %u, DLCI %u, Flags [%s], cisco-ethertype %s (0x%04x), length %u: ",
194                         addr_len,
195                         dlci,
196                         bittok2str(fr_header_flag_values, "none", EXTRACT_32BITS(flags)),
197                         tok2str(ethertype_values, "unknown", nlpid),
198                         nlpid,
199                         length);
200    }
201}
202
203u_int
204fr_if_print(const struct pcap_pkthdr *h, register const u_char *p)
205{
206	register u_int length = h->len;
207	register u_int caplen = h->caplen;
208
209        TCHECK2(*p, 4); /* minimum frame header length */
210
211        if ((length = fr_print(p, length)) == 0)
212            return (0);
213        else
214            return length;
215 trunc:
216        printf("[|fr]");
217        return caplen;
218}
219
220u_int
221fr_print(register const u_char *p, u_int length)
222{
223	u_int16_t extracted_ethertype;
224	u_int dlci;
225        u_int sdlcore;
226	u_int addr_len;
227	u_int16_t nlpid;
228	u_int hdr_len;
229	u_int8_t flags[4];
230
231	if (parse_q922_addr(p, &dlci, &sdlcore, &addr_len, flags)) {
232		printf("Q.922, invalid address");
233		return 0;
234	}
235
236        TCHECK2(*p,addr_len+1+1);
237	hdr_len = fr_hdrlen(p, addr_len);
238        TCHECK2(*p,hdr_len);
239
240	if (p[addr_len] != 0x03 && dlci != 0) {
241
242                /* lets figure out if we have cisco style encapsulation: */
243                extracted_ethertype = EXTRACT_16BITS(p+addr_len);
244
245                if (eflag)
246                    fr_hdr_print(length, addr_len, dlci, flags, extracted_ethertype);
247
248                if (ether_encap_print(extracted_ethertype,
249                                      p+addr_len+ETHERTYPE_LEN,
250                                      length-addr_len-ETHERTYPE_LEN,
251                                      length-addr_len-ETHERTYPE_LEN,
252                                      &extracted_ethertype) == 0)
253                    /* ether_type not known, probably it wasn't one */
254                    printf("UI %02x! ", p[addr_len]);
255                else
256                    return hdr_len;
257        }
258
259	if (!p[addr_len + 1]) {	/* pad byte should be used with 3-byte Q.922 */
260		if (addr_len != 3)
261			printf("Pad! ");
262	} else if (addr_len == 3)
263		printf("No pad! ");
264
265	nlpid = p[hdr_len - 1];
266
267	if (eflag)
268		fr_hdr_print(length, addr_len, dlci, flags, nlpid);
269	p += hdr_len;
270	length -= hdr_len;
271
272	switch (nlpid) {
273	case NLPID_IP:
274	        ip_print(gndo, p, length);
275		break;
276
277#ifdef INET6
278	case NLPID_IP6:
279		ip6_print(p, length);
280		break;
281#endif
282	case NLPID_CLNP:
283	case NLPID_ESIS:
284	case NLPID_ISIS:
285                isoclns_print(p-1, length+1, length+1); /* OSI printers need the NLPID field */
286		break;
287
288	case NLPID_SNAP:
289		if (snap_print(p, length, length, &extracted_ethertype, 0) == 0) {
290			/* ether_type not known, print raw packet */
291                        if (!eflag)
292                            fr_hdr_print(length + hdr_len, hdr_len,
293                                         dlci, flags, nlpid);
294			if (!suppress_default_print)
295                            default_print(p - hdr_len, length + hdr_len);
296		}
297		break;
298
299        case NLPID_Q933:
300		q933_print(p, length);
301		break;
302
303        case NLPID_MFR:
304                frf15_print(p, length);
305                break;
306
307        case NLPID_PPP:
308                ppp_print(p, length);
309                break;
310
311	default:
312		if (!eflag)
313                    fr_hdr_print(length + hdr_len, addr_len,
314				     dlci, flags, nlpid);
315		if (!xflag)
316			default_print(p, length);
317	}
318
319	return hdr_len;
320
321 trunc:
322        printf("[|fr]");
323        return 0;
324
325}
326
327u_int
328mfr_if_print(const struct pcap_pkthdr *h, register const u_char *p)
329{
330	register u_int length = h->len;
331	register u_int caplen = h->caplen;
332
333        TCHECK2(*p, 2); /* minimum frame header length */
334
335        if ((length = mfr_print(p, length)) == 0)
336            return (0);
337        else
338            return length;
339 trunc:
340        printf("[|mfr]");
341        return caplen;
342}
343
344
345#define MFR_CTRL_MSG_ADD_LINK        1
346#define MFR_CTRL_MSG_ADD_LINK_ACK    2
347#define MFR_CTRL_MSG_ADD_LINK_REJ    3
348#define MFR_CTRL_MSG_HELLO           4
349#define MFR_CTRL_MSG_HELLO_ACK       5
350#define MFR_CTRL_MSG_REMOVE_LINK     6
351#define MFR_CTRL_MSG_REMOVE_LINK_ACK 7
352
353struct tok mfr_ctrl_msg_values[] = {
354    { MFR_CTRL_MSG_ADD_LINK, "Add Link" },
355    { MFR_CTRL_MSG_ADD_LINK_ACK, "Add Link ACK" },
356    { MFR_CTRL_MSG_ADD_LINK_REJ, "Add Link Reject" },
357    { MFR_CTRL_MSG_HELLO, "Hello" },
358    { MFR_CTRL_MSG_HELLO_ACK, "Hello ACK" },
359    { MFR_CTRL_MSG_REMOVE_LINK, "Remove Link" },
360    { MFR_CTRL_MSG_REMOVE_LINK_ACK, "Remove Link ACK" },
361    { 0, NULL }
362};
363
364#define MFR_CTRL_IE_BUNDLE_ID  1
365#define MFR_CTRL_IE_LINK_ID    2
366#define MFR_CTRL_IE_MAGIC_NUM  3
367#define MFR_CTRL_IE_TIMESTAMP  5
368#define MFR_CTRL_IE_VENDOR_EXT 6
369#define MFR_CTRL_IE_CAUSE      7
370
371struct tok mfr_ctrl_ie_values[] = {
372    { MFR_CTRL_IE_BUNDLE_ID, "Bundle ID"},
373    { MFR_CTRL_IE_LINK_ID, "Link ID"},
374    { MFR_CTRL_IE_MAGIC_NUM, "Magic Number"},
375    { MFR_CTRL_IE_TIMESTAMP, "Timestamp"},
376    { MFR_CTRL_IE_VENDOR_EXT, "Vendor Extension"},
377    { MFR_CTRL_IE_CAUSE, "Cause"},
378    { 0, NULL }
379};
380
381#define MFR_ID_STRING_MAXLEN 50
382
383struct ie_tlv_header_t {
384    u_int8_t ie_type;
385    u_int8_t ie_len;
386};
387
388u_int
389mfr_print(register const u_char *p, u_int length)
390{
391    u_int tlen,idx,hdr_len = 0;
392    u_int16_t sequence_num;
393    u_int8_t ie_type,ie_len;
394    const u_int8_t *tptr;
395
396
397/*
398 * FRF.16 Link Integrity Control Frame
399 *
400 *      7    6    5    4    3    2    1    0
401 *    +----+----+----+----+----+----+----+----+
402 *    | B  | E  | C=1| 0    0    0    0  | EA |
403 *    +----+----+----+----+----+----+----+----+
404 *    | 0    0    0    0    0    0    0    0  |
405 *    +----+----+----+----+----+----+----+----+
406 *    |              message type             |
407 *    +----+----+----+----+----+----+----+----+
408 */
409
410    TCHECK2(*p, 4); /* minimum frame header length */
411
412    if ((p[0] & MFR_BEC_MASK) == MFR_CTRL_FRAME && p[1] == 0) {
413        printf("FRF.16 Control, Flags [%s], %s, length %u",
414               bittok2str(frf_flag_values,"none",(p[0] & MFR_BEC_MASK)),
415               tok2str(mfr_ctrl_msg_values,"Unknown Message (0x%02x)",p[2]),
416               length);
417        tptr = p + 3;
418        tlen = length -3;
419        hdr_len = 3;
420
421        if (!vflag)
422            return hdr_len;
423
424        while (tlen>sizeof(struct ie_tlv_header_t)) {
425            TCHECK2(*tptr, sizeof(struct ie_tlv_header_t));
426            ie_type=tptr[0];
427            ie_len=tptr[1];
428
429            printf("\n\tIE %s (%u), length %u: ",
430                   tok2str(mfr_ctrl_ie_values,"Unknown",ie_type),
431                   ie_type,
432                   ie_len);
433
434            /* infinite loop check */
435            if (ie_type == 0 || ie_len <= sizeof(struct ie_tlv_header_t))
436                return hdr_len;
437
438            TCHECK2(*tptr,ie_len);
439            tptr+=sizeof(struct ie_tlv_header_t);
440            /* tlv len includes header */
441            ie_len-=sizeof(struct ie_tlv_header_t);
442            tlen-=sizeof(struct ie_tlv_header_t);
443
444            switch (ie_type) {
445
446            case MFR_CTRL_IE_MAGIC_NUM:
447                printf("0x%08x",EXTRACT_32BITS(tptr));
448                break;
449
450            case MFR_CTRL_IE_BUNDLE_ID: /* same message format */
451            case MFR_CTRL_IE_LINK_ID:
452                for (idx = 0; idx < ie_len && idx < MFR_ID_STRING_MAXLEN; idx++) {
453                    if (*(tptr+idx) != 0) /* don't print null termination */
454                        safeputchar(*(tptr+idx));
455                    else
456                        break;
457                }
458                break;
459
460            case MFR_CTRL_IE_TIMESTAMP:
461                if (ie_len == sizeof(struct timeval)) {
462                    ts_print((const struct timeval *)tptr);
463                    break;
464                }
465                /* fall through and hexdump if no unix timestamp */
466
467                /*
468                 * FIXME those are the defined IEs that lack a decoder
469                 * you are welcome to contribute code ;-)
470                 */
471
472            case MFR_CTRL_IE_VENDOR_EXT:
473            case MFR_CTRL_IE_CAUSE:
474
475            default:
476                if (vflag <= 1)
477                    print_unknown_data(tptr,"\n\t  ",ie_len);
478                break;
479            }
480
481            /* do we want to see a hexdump of the IE ? */
482            if (vflag > 1 )
483                print_unknown_data(tptr,"\n\t  ",ie_len);
484
485            tlen-=ie_len;
486            tptr+=ie_len;
487        }
488        return hdr_len;
489    }
490/*
491 * FRF.16 Fragmentation Frame
492 *
493 *      7    6    5    4    3    2    1    0
494 *    +----+----+----+----+----+----+----+----+
495 *    | B  | E  | C=0|seq. (high 4 bits) | EA  |
496 *    +----+----+----+----+----+----+----+----+
497 *    |        sequence  (low 8 bits)         |
498 *    +----+----+----+----+----+----+----+----+
499 *    |        DLCI (6 bits)        | CR | EA  |
500 *    +----+----+----+----+----+----+----+----+
501 *    |   DLCI (4 bits)   |FECN|BECN| DE | EA |
502 *    +----+----+----+----+----+----+----+----+
503 */
504
505    sequence_num = (p[0]&0x1e)<<7 | p[1];
506    /* whole packet or first fragment ? */
507    if ((p[0] & MFR_BEC_MASK) == MFR_FRAG_FRAME ||
508        (p[0] & MFR_BEC_MASK) == MFR_B_BIT) {
509        printf("FRF.16 Frag, seq %u, Flags [%s], ",
510               sequence_num,
511               bittok2str(frf_flag_values,"none",(p[0] & MFR_BEC_MASK)));
512        hdr_len = 2;
513        fr_print(p+hdr_len,length-hdr_len);
514        return hdr_len;
515    }
516
517    /* must be a middle or the last fragment */
518    printf("FRF.16 Frag, seq %u, Flags [%s]",
519           sequence_num,
520           bittok2str(frf_flag_values,"none",(p[0] & MFR_BEC_MASK)));
521    print_unknown_data(p,"\n\t",length);
522
523    return hdr_len;
524
525 trunc:
526    printf("[|mfr]");
527    return length;
528}
529
530/* an NLPID of 0xb1 indicates a 2-byte
531 * FRF.15 header
532 *
533 *      7    6    5    4    3    2    1    0
534 *    +----+----+----+----+----+----+----+----+
535 *    ~              Q.922 header             ~
536 *    +----+----+----+----+----+----+----+----+
537 *    |             NLPID (8 bits)            | NLPID=0xb1
538 *    +----+----+----+----+----+----+----+----+
539 *    | B  | E  | C  |seq. (high 4 bits) | R  |
540 *    +----+----+----+----+----+----+----+----+
541 *    |        sequence  (low 8 bits)         |
542 *    +----+----+----+----+----+----+----+----+
543 */
544
545#define FR_FRF15_FRAGTYPE 0x01
546
547static void
548frf15_print (const u_char *p, u_int length) {
549
550    u_int16_t sequence_num, flags;
551
552    flags = p[0]&MFR_BEC_MASK;
553    sequence_num = (p[0]&0x1e)<<7 | p[1];
554
555    printf("FRF.15, seq 0x%03x, Flags [%s],%s Fragmentation, length %u",
556           sequence_num,
557           bittok2str(frf_flag_values,"none",flags),
558           p[0]&FR_FRF15_FRAGTYPE ? "Interface" : "End-to-End",
559           length);
560
561/* TODO:
562 * depending on all permutations of the B, E and C bit
563 * dig as deep as we can - e.g. on the first (B) fragment
564 * there is enough payload to print the IP header
565 * on non (B) fragments it depends if the fragmentation
566 * model is end-to-end or interface based wether we want to print
567 * another Q.922 header
568 */
569
570}
571
572/*
573 * Q.933 decoding portion for framerelay specific.
574 */
575
576/* Q.933 packet format
577                      Format of Other Protocols
578                          using Q.933 NLPID
579                  +-------------------------------+
580                  |        Q.922 Address          |
581                  +---------------+---------------+
582                  |Control  0x03  | NLPID   0x08  |
583                  +---------------+---------------+
584                  |          L2 Protocol ID       |
585                  | octet 1       |  octet 2      |
586                  +-------------------------------+
587                  |          L3 Protocol ID       |
588                  | octet 2       |  octet 2      |
589                  +-------------------------------+
590                  |         Protocol Data         |
591                  +-------------------------------+
592                  | FCS                           |
593                  +-------------------------------+
594 */
595
596/* L2 (Octet 1)- Call Reference Usually is 0x0 */
597
598/*
599 * L2 (Octet 2)- Message Types definition 1 byte long.
600 */
601/* Call Establish */
602#define MSG_TYPE_ESC_TO_NATIONAL  0x00
603#define MSG_TYPE_ALERT            0x01
604#define MSG_TYPE_CALL_PROCEEDING  0x02
605#define MSG_TYPE_CONNECT          0x07
606#define MSG_TYPE_CONNECT_ACK      0x0F
607#define MSG_TYPE_PROGRESS         0x03
608#define MSG_TYPE_SETUP            0x05
609/* Call Clear */
610#define MSG_TYPE_DISCONNECT       0x45
611#define MSG_TYPE_RELEASE          0x4D
612#define MSG_TYPE_RELEASE_COMPLETE 0x5A
613#define MSG_TYPE_RESTART          0x46
614#define MSG_TYPE_RESTART_ACK      0x4E
615/* Status */
616#define MSG_TYPE_STATUS           0x7D
617#define MSG_TYPE_STATUS_ENQ       0x75
618
619struct tok fr_q933_msg_values[] = {
620    { MSG_TYPE_ESC_TO_NATIONAL, "ESC to National" },
621    { MSG_TYPE_ALERT, "Alert" },
622    { MSG_TYPE_CALL_PROCEEDING, "Call proceeding" },
623    { MSG_TYPE_CONNECT, "Connect" },
624    { MSG_TYPE_CONNECT_ACK, "Connect ACK" },
625    { MSG_TYPE_PROGRESS, "Progress" },
626    { MSG_TYPE_SETUP, "Setup" },
627    { MSG_TYPE_DISCONNECT, "Disconnect" },
628    { MSG_TYPE_RELEASE, "Release" },
629    { MSG_TYPE_RELEASE_COMPLETE, "Release Complete" },
630    { MSG_TYPE_RESTART, "Restart" },
631    { MSG_TYPE_RESTART_ACK, "Restart ACK" },
632    { MSG_TYPE_STATUS, "Status Reply" },
633    { MSG_TYPE_STATUS_ENQ, "Status Enquiry" },
634    { 0, NULL }
635};
636
637#define MSG_ANSI_LOCKING_SHIFT	0x95
638
639#define FR_LMI_ANSI_REPORT_TYPE_IE	0x01
640#define FR_LMI_ANSI_LINK_VERIFY_IE_91	0x19 /* details? */
641#define FR_LMI_ANSI_LINK_VERIFY_IE	0x03
642#define FR_LMI_ANSI_PVC_STATUS_IE	0x07
643
644#define FR_LMI_CCITT_REPORT_TYPE_IE	0x51
645#define FR_LMI_CCITT_LINK_VERIFY_IE	0x53
646#define FR_LMI_CCITT_PVC_STATUS_IE	0x57
647
648struct tok fr_q933_ie_values_codeset5[] = {
649    { FR_LMI_ANSI_REPORT_TYPE_IE, "ANSI Report Type" },
650    { FR_LMI_ANSI_LINK_VERIFY_IE_91, "ANSI Link Verify" },
651    { FR_LMI_ANSI_LINK_VERIFY_IE, "ANSI Link Verify" },
652    { FR_LMI_ANSI_PVC_STATUS_IE, "ANSI PVC Status" },
653    { FR_LMI_CCITT_REPORT_TYPE_IE, "CCITT Report Type" },
654    { FR_LMI_CCITT_LINK_VERIFY_IE, "CCITT Link Verify" },
655    { FR_LMI_CCITT_PVC_STATUS_IE, "CCITT PVC Status" },
656    { 0, NULL }
657};
658
659#define FR_LMI_REPORT_TYPE_IE_FULL_STATUS 0
660#define FR_LMI_REPORT_TYPE_IE_LINK_VERIFY 1
661#define FR_LMI_REPORT_TYPE_IE_ASYNC_PVC   2
662
663struct tok fr_lmi_report_type_ie_values[] = {
664    { FR_LMI_REPORT_TYPE_IE_FULL_STATUS, "Full Status" },
665    { FR_LMI_REPORT_TYPE_IE_LINK_VERIFY, "Link verify" },
666    { FR_LMI_REPORT_TYPE_IE_ASYNC_PVC, "Async PVC Status" },
667    { 0, NULL }
668};
669
670/* array of 16 codepages - currently we only support codepage 1,5 */
671static struct tok *fr_q933_ie_codesets[] = {
672    NULL,
673    fr_q933_ie_values_codeset5,
674    NULL,
675    NULL,
676    NULL,
677    fr_q933_ie_values_codeset5,
678    NULL,
679    NULL,
680    NULL,
681    NULL,
682    NULL,
683    NULL,
684    NULL,
685    NULL,
686    NULL,
687    NULL
688};
689
690static int fr_q933_print_ie_codeset5(const struct ie_tlv_header_t  *ie_p,
691    const u_char *p);
692
693typedef int (*codeset_pr_func_t)(const struct ie_tlv_header_t  *ie_p,
694    const u_char *p);
695
696/* array of 16 codepages - currently we only support codepage 1,5 */
697static codeset_pr_func_t fr_q933_print_ie_codeset[] = {
698    NULL,
699    fr_q933_print_ie_codeset5,
700    NULL,
701    NULL,
702    NULL,
703    fr_q933_print_ie_codeset5,
704    NULL,
705    NULL,
706    NULL,
707    NULL,
708    NULL,
709    NULL,
710    NULL,
711    NULL,
712    NULL,
713    NULL
714};
715
716void
717q933_print(const u_char *p, u_int length)
718{
719	const u_char *ptemp = p;
720	struct ie_tlv_header_t  *ie_p;
721        int olen;
722	int is_ansi = 0;
723        u_int codeset;
724        u_int ie_is_known = 0;
725
726	if (length < 9) {	/* shortest: Q.933a LINK VERIFY */
727		printf("[|q.933]");
728		return;
729	}
730
731        codeset = p[2]&0x0f;   /* extract the codeset */
732
733	if (p[2] == MSG_ANSI_LOCKING_SHIFT)
734		is_ansi = 1;
735
736        printf("%s", eflag ? "" : "Q.933, ");
737
738	/* printing out header part */
739	printf("%s, codeset %u", is_ansi ? "ANSI" : "CCITT", codeset);
740
741	if (p[0])
742		printf(", Call Ref: 0x%02x", p[0]);
743
744        if (vflag)
745            printf(", %s (0x%02x), length %u",
746                   tok2str(fr_q933_msg_values,"unknown message",p[1]),
747                   p[1],
748                   length);
749        else
750            printf(", %s",
751                   tok2str(fr_q933_msg_values,"unknown message 0x%02x",p[1]));
752
753        olen = length; /* preserve the original length for non verbose mode */
754
755	if (length < (u_int)(2 - is_ansi)) {
756		printf("[|q.933]");
757		return;
758	}
759	length -= 2 - is_ansi;
760	ptemp += 2 + is_ansi;
761
762	/* Loop through the rest of IE */
763	while (length > sizeof(struct ie_tlv_header_t )) {
764		ie_p = (struct ie_tlv_header_t  *)ptemp;
765		if (length < sizeof(struct ie_tlv_header_t ) ||
766		    length < sizeof(struct ie_tlv_header_t ) + ie_p->ie_len) {
767                    if (vflag) /* not bark if there is just a trailer */
768                        printf("\n[|q.933]");
769                    else
770                        printf(", length %u",olen);
771                    return;
772		}
773
774                /* lets do the full IE parsing only in verbose mode
775                 * however some IEs (DLCI Status, Link Verify)
776                 * are also intereststing in non-verbose mode */
777                if (vflag)
778                    printf("\n\t%s IE (0x%02x), length %u: ",
779                           tok2str(fr_q933_ie_codesets[codeset],"unknown",ie_p->ie_type),
780                           ie_p->ie_type,
781                           ie_p->ie_len);
782
783                /* sanity check */
784                if (ie_p->ie_type == 0 || ie_p->ie_len == 0)
785                    return;
786
787                if (fr_q933_print_ie_codeset[codeset] != NULL)
788                    ie_is_known = fr_q933_print_ie_codeset[codeset](ie_p, ptemp);
789
790                if (vflag >= 1 && !ie_is_known)
791                    print_unknown_data(ptemp+2,"\n\t",ie_p->ie_len);
792
793                /* do we want to see a hexdump of the IE ? */
794                if (vflag> 1 && ie_is_known)
795                    print_unknown_data(ptemp+2,"\n\t  ",ie_p->ie_len);
796
797		length = length - ie_p->ie_len - 2;
798		ptemp = ptemp + ie_p->ie_len + 2;
799	}
800        if (!vflag)
801            printf(", length %u",olen);
802}
803
804static int
805fr_q933_print_ie_codeset5(const struct ie_tlv_header_t  *ie_p, const u_char *p)
806{
807        u_int dlci;
808
809        switch (ie_p->ie_type) {
810
811        case FR_LMI_ANSI_REPORT_TYPE_IE: /* fall through */
812        case FR_LMI_CCITT_REPORT_TYPE_IE:
813            if (vflag)
814                printf("%s (%u)",
815                       tok2str(fr_lmi_report_type_ie_values,"unknown",p[2]),
816                       p[2]);
817            return 1;
818
819        case FR_LMI_ANSI_LINK_VERIFY_IE: /* fall through */
820        case FR_LMI_CCITT_LINK_VERIFY_IE:
821        case FR_LMI_ANSI_LINK_VERIFY_IE_91:
822            if (!vflag)
823                printf(", ");
824            printf("TX Seq: %3d, RX Seq: %3d", p[2], p[3]);
825            return 1;
826
827        case FR_LMI_ANSI_PVC_STATUS_IE: /* fall through */
828        case FR_LMI_CCITT_PVC_STATUS_IE:
829            if (!vflag)
830                printf(", ");
831            /* now parse the DLCI information element. */
832            if ((ie_p->ie_len < 3) ||
833                (p[2] & 0x80) ||
834                ((ie_p->ie_len == 3) && !(p[3] & 0x80)) ||
835                ((ie_p->ie_len == 4) && ((p[3] & 0x80) || !(p[4] & 0x80))) ||
836                ((ie_p->ie_len == 5) && ((p[3] & 0x80) || (p[4] & 0x80) ||
837                                   !(p[5] & 0x80))) ||
838                (ie_p->ie_len > 5) ||
839                !(p[ie_p->ie_len + 1] & 0x80))
840                printf("Invalid DLCI IE");
841
842            dlci = ((p[2] & 0x3F) << 4) | ((p[3] & 0x78) >> 3);
843            if (ie_p->ie_len == 4)
844                dlci = (dlci << 6) | ((p[4] & 0x7E) >> 1);
845            else if (ie_p->ie_len == 5)
846                dlci = (dlci << 13) | (p[4] & 0x7F) | ((p[5] & 0x7E) >> 1);
847
848            printf("DLCI %u: status %s%s", dlci,
849                    p[ie_p->ie_len + 1] & 0x8 ? "New, " : "",
850                    p[ie_p->ie_len + 1] & 0x2 ? "Active" : "Inactive");
851            return 1;
852	}
853
854        return 0;
855}
856