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