print-fr.c revision 147904
132145Spst/*
232145Spst * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996
332145Spst *	The Regents of the University of California.  All rights reserved.
432145Spst *
532145Spst * Redistribution and use in source and binary forms, with or without
632145Spst * modification, are permitted provided that: (1) source code distributions
732145Spst * retain the above copyright notice and this paragraph in its entirety, (2)
832145Spst * distributions including binary code include the above copyright notice and
932145Spst * this paragraph in its entirety in the documentation or other materials
1032145Spst * provided with the distribution, and (3) all advertising materials mentioning
1132145Spst * features or use of this software display the following acknowledgement:
1232145Spst * ``This product includes software developed by the University of California,
1332145Spst * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1432145Spst * the University nor the names of its contributors may be used to endorse
1532145Spst * or promote products derived from this software without specific prior
1632145Spst * written permission.
1732145Spst * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1832145Spst * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1932145Spst * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2066644Skris *
2166644Skris * $FreeBSD: head/contrib/tcpdump/print-fr.c 147904 2005-07-11 04:14:02Z sam $
2232145Spst */
2332145Spst
2432145Spst#ifndef lint
25146778Ssamstatic const char rcsid[] _U_ =
26147904Ssam	"@(#)$Header: /tcpdump/master/tcpdump/print-fr.c,v 1.32.2.4 2005/05/27 14:56:52 hannes Exp $ (LBL)";
2732145Spst#endif
2832145Spst
29146778Ssam#ifdef HAVE_CONFIG_H
30146778Ssam#include "config.h"
3132145Spst#endif
3232145Spst
33146778Ssam#include <tcpdump-stdinc.h>
3432145Spst
35146778Ssam#include <stdio.h>
36146778Ssam#include <string.h>
3732145Spst#include <pcap.h>
3832145Spst
39146778Ssam#include "addrtoname.h"
40146778Ssam#include "interface.h"
4132145Spst#include "ethertype.h"
42146778Ssam#include "nlpid.h"
43146778Ssam#include "extract.h"
44146778Ssam#include "oui.h"
4532145Spst
46146778Ssamstatic void frf15_print(const u_char *, u_int);
4732145Spst
48146778Ssam/*
49146778Ssam * the frame relay header has a variable length
50146778Ssam *
51146778Ssam * the EA bit determines if there is another byte
52146778Ssam * in the header
53146778Ssam *
54146778Ssam * minimum header length is 2 bytes
55146778Ssam * maximum header length is 4 bytes
56146778Ssam *
57146778Ssam *      7    6    5    4    3    2    1    0
58146778Ssam *    +----+----+----+----+----+----+----+----+
59146778Ssam *    |        DLCI (6 bits)        | CR | EA |
60146778Ssam *    +----+----+----+----+----+----+----+----+
61146778Ssam *    |   DLCI (4 bits)   |FECN|BECN| DE | EA |
62146778Ssam *    +----+----+----+----+----+----+----+----+
63146778Ssam *    |           DLCI (7 bits)          | EA |
64146778Ssam *    +----+----+----+----+----+----+----+----+
65146778Ssam *    |        DLCI (6 bits)        |SDLC| EA |
66146778Ssam *    +----+----+----+----+----+----+----+----+
67146778Ssam */
6832145Spst
69146778Ssam#define FR_EA_BIT	0x01
7032145Spst
71146778Ssam#define FR_CR_BIT       0x02000000
72146778Ssam#define FR_DE_BIT	0x00020000
73146778Ssam#define FR_BECN_BIT	0x00040000
74146778Ssam#define FR_FECN_BIT	0x00080000
75146778Ssam#define FR_SDLC_BIT	0x00000002
7632145Spst
77146778Ssam
78146778Ssamstruct tok fr_header_flag_values[] = {
79146778Ssam    { FR_CR_BIT, "C!" },
80146778Ssam    { FR_DE_BIT, "DE" },
81146778Ssam    { FR_BECN_BIT, "BECN" },
82146778Ssam    { FR_FECN_BIT, "FECN" },
83146778Ssam    { FR_SDLC_BIT, "sdlcore" },
84146778Ssam    { 0, NULL }
8532145Spst};
8632145Spst
87146778Ssam
88146778Ssam/* Finds out Q.922 address length, DLCI and flags. Returns 0 on success
89146778Ssam * save the flags dep. on address length
90146778Ssam */
91146778Ssamstatic int parse_q922_addr(const u_char *p, u_int *dlci, u_int *sdlcore,
92146778Ssam                           u_int *addr_len, u_int8_t *flags)
9332145Spst{
94146778Ssam	if ((p[0] & FR_EA_BIT))
95146778Ssam		return -1;
9632145Spst
97146778Ssam	*addr_len = 2;
98146778Ssam	*dlci = ((p[0] & 0xFC) << 2) | ((p[1] & 0xF0) >> 4);
9932145Spst
100146778Ssam        flags[0] = p[0] & 0x02; /* populate the first flag fields */
101146778Ssam        flags[1] = p[1] & 0x0c;
10232145Spst
103146778Ssam	if (p[1] & FR_EA_BIT)
104146778Ssam		return 0;	/* 2-byte Q.922 address */
10532145Spst
106146778Ssam	p += 2;
107146778Ssam	(*addr_len)++;		/* 3- or 4-byte Q.922 address */
108146778Ssam	if ((p[0] & FR_EA_BIT) == 0) {
109146778Ssam		*dlci = (*dlci << 7) | (p[0] >> 1);
110146778Ssam		(*addr_len)++;	/* 4-byte Q.922 address */
111146778Ssam		p++;
112146778Ssam	}
11332145Spst
114146778Ssam	if ((p[0] & FR_EA_BIT) == 0)
115146778Ssam		return -1; /* more than 4 bytes of Q.922 address? */
116146778Ssam
117146778Ssam        flags[3] = p[0] & 0x02;
118146778Ssam
119146778Ssam	if (p[0] & 0x02)
120146778Ssam                *sdlcore =  p[0] >> 2;
121146778Ssam	else
122146778Ssam		*dlci = (*dlci << 6) | (p[0] >> 2);
123146778Ssam
124146778Ssam	return 0;
12532145Spst}
12632145Spst
127146778Ssam/* Frame Relay packet structure, with flags and CRC removed
12832145Spst
12932145Spst                  +---------------------------+
13032145Spst                  |       Q.922 Address*      |
13132145Spst                  +--                       --+
13232145Spst                  |                           |
13332145Spst                  +---------------------------+
13432145Spst                  | Control (UI = 0x03)       |
13532145Spst                  +---------------------------+
13632145Spst                  | Optional Pad      (0x00)  |
13732145Spst                  +---------------------------+
13832145Spst                  | NLPID                     |
13932145Spst                  +---------------------------+
14032145Spst                  |             .             |
14132145Spst                  |             .             |
14232145Spst                  |             .             |
14332145Spst                  |           Data            |
14432145Spst                  |             .             |
14532145Spst                  |             .             |
14632145Spst                  +---------------------------+
14732145Spst
14832145Spst           * Q.922 addresses, as presently defined, are two octets and
14932145Spst             contain a 10-bit DLCI.  In some networks Q.922 addresses
15032145Spst             may optionally be increased to three or four octets.
15132145Spst*/
15232145Spst
153146778Ssamstatic u_int
154147904Ssamfr_hdrlen(const u_char *p, u_int addr_len)
15532145Spst{
156147904Ssam	if (!p[addr_len + 1] /* pad exist */)
157146778Ssam		return addr_len + 1 /* UI */ + 1 /* pad */ + 1 /* NLPID */;
15832145Spst	else
159146778Ssam		return addr_len + 1 /* UI */ + 1 /* NLPID */;
16032145Spst}
16132145Spst
162146778Ssamstatic void
163146778Ssamfr_hdr_print(int length, u_int addr_len, u_int dlci, u_int8_t *flags, u_int16_t nlpid)
16432145Spst{
165146778Ssam    if (qflag) {
166146778Ssam        (void)printf("Q.922, DLCI %u, length %u: ",
167146778Ssam                     dlci,
168146778Ssam                     length);
169146778Ssam    } else {
170146778Ssam        if (nlpid <= 0xff) /* if its smaller than 256 then its a NLPID */
171146778Ssam            (void)printf("Q.922, hdr-len %u, DLCI %u, Flags [%s], NLPID %s (0x%02x), length %u: ",
172146778Ssam                         addr_len,
173146778Ssam                         dlci,
174146778Ssam                         bittok2str(fr_header_flag_values, "none", EXTRACT_32BITS(flags)),
175146778Ssam                         tok2str(nlpid_values,"unknown", nlpid),
176146778Ssam                         nlpid,
177146778Ssam                         length);
178146778Ssam        else /* must be an ethertype */
179146778Ssam            (void)printf("Q.922, hdr-len %u, DLCI %u, Flags [%s], cisco-ethertype %s (0x%04x), length %u: ",
180146778Ssam                         addr_len,
181146778Ssam                         dlci,
182146778Ssam                         bittok2str(fr_header_flag_values, "none", EXTRACT_32BITS(flags)),
183146778Ssam                         tok2str(ethertype_values, "unknown", nlpid),
184146778Ssam                         nlpid,
185146778Ssam                         length);
186146778Ssam    }
18732145Spst}
18832145Spst
189146778Ssamu_int
190146778Ssamfr_if_print(const struct pcap_pkthdr *h, register const u_char *p)
19132145Spst{
19232145Spst	register u_int length = h->len;
19332145Spst	register u_int caplen = h->caplen;
194147904Ssam
195147904Ssam        TCHECK2(*p, 4); /* minimum frame header length */
196147904Ssam
197147904Ssam        if ((length = fr_print(p, length)) == 0)
198147904Ssam            return (0);
199147904Ssam        else
200147904Ssam            return length;
201147904Ssam trunc:
202147904Ssam        printf("[|fr]");
203147904Ssam        return caplen;
204147904Ssam}
205147904Ssam
206147904Ssamu_int
207147904Ssamfr_print(register const u_char *p, u_int length)
208147904Ssam{
209146778Ssam	u_int16_t extracted_ethertype;
210146778Ssam	u_int dlci;
211146778Ssam        u_int sdlcore;
212146778Ssam	u_int addr_len;
213146778Ssam	u_int16_t nlpid;
214146778Ssam	u_int hdr_len;
215146778Ssam	u_int8_t flags[4];
21632145Spst
217146778Ssam	if (parse_q922_addr(p, &dlci, &sdlcore, &addr_len, flags)) {
218146778Ssam		printf("Q.922, invalid address");
219147904Ssam		return 0;
220146778Ssam	}
22132145Spst
222147904Ssam        TCHECK2(*p,addr_len+1+1);
223147904Ssam	hdr_len = fr_hdrlen(p, addr_len);
224147904Ssam        TCHECK2(*p,hdr_len);
225146778Ssam
226146778Ssam	if (p[addr_len] != 0x03 && dlci != 0) {
22732145Spst
228146778Ssam                /* lets figure out if we have cisco style encapsulation: */
229146778Ssam                extracted_ethertype = EXTRACT_16BITS(p+addr_len);
230146778Ssam
231146778Ssam                if (eflag)
232146778Ssam                    fr_hdr_print(length, addr_len, dlci, flags, extracted_ethertype);
233146778Ssam
234146778Ssam                if (ether_encap_print(extracted_ethertype,
235146778Ssam                                      p+addr_len+ETHERTYPE_LEN,
236146778Ssam                                      length-addr_len-ETHERTYPE_LEN,
237147904Ssam                                      length-addr_len-ETHERTYPE_LEN,
238146778Ssam                                      &extracted_ethertype) == 0)
239146778Ssam                    /* ether_type not known, probably it wasn't one */
240146778Ssam                    printf("UI %02x! ", p[addr_len]);
241146778Ssam                else
242146778Ssam                    return hdr_len;
243146778Ssam        }
244146778Ssam
245146778Ssam	if (!p[addr_len + 1]) {	/* pad byte should be used with 3-byte Q.922 */
246146778Ssam		if (addr_len != 3)
247146778Ssam			printf("Pad! ");
248146778Ssam	} else if (addr_len == 3)
249146778Ssam		printf("No pad! ");
250146778Ssam
251146778Ssam	nlpid = p[hdr_len - 1];
252146778Ssam
25332145Spst	if (eflag)
254146778Ssam		fr_hdr_print(length, addr_len, dlci, flags, nlpid);
25532145Spst
256146778Ssam	p += hdr_len;
257146778Ssam	length -= hdr_len;
25832145Spst
259146778Ssam	switch (nlpid) {
26032145Spst	case NLPID_IP:
261146778Ssam	        ip_print(gndo, p, length);
26232145Spst		break;
263146778Ssam
264146778Ssam#ifdef INET6
265146778Ssam	case NLPID_IP6:
266146778Ssam		ip6_print(p, length);
267146778Ssam		break;
268146778Ssam#endif
26932145Spst	case NLPID_CLNP:
27032145Spst	case NLPID_ESIS:
27132145Spst	case NLPID_ISIS:
272147904Ssam                isoclns_print(p-1, length+1, length+1); /* OSI printers need the NLPID field */
27332145Spst		break;
274146778Ssam
275146778Ssam	case NLPID_SNAP:
276147904Ssam		if (snap_print(p, length, length, &extracted_ethertype, 0) == 0) {
277146778Ssam			/* ether_type not known, print raw packet */
278146778Ssam                        if (!eflag)
279146778Ssam                            fr_hdr_print(length + hdr_len, hdr_len,
280146778Ssam                                         dlci, flags, nlpid);
281146778Ssam			if (!xflag && !qflag)
282147904Ssam                            default_print(p - hdr_len, length + hdr_len);
283146778Ssam		}
28432145Spst		break;
285146778Ssam
286146778Ssam        case NLPID_Q933:
287146778Ssam		q933_print(p, length);
288146778Ssam		break;
289146778Ssam
290146778Ssam        case NLPID_MFR:
291146778Ssam                frf15_print(p, length);
292146778Ssam                break;
293146778Ssam
29432145Spst	default:
295146778Ssam		if (!eflag)
296146778Ssam                    fr_hdr_print(length + hdr_len, addr_len,
297146778Ssam				     dlci, flags, nlpid);
298146778Ssam		if (!xflag)
299147904Ssam			default_print(p, length);
30032145Spst	}
30132145Spst
302146778Ssam	return hdr_len;
303147904Ssam
304147904Ssam trunc:
305147904Ssam        printf("[|fr]");
306147904Ssam        return 0;
307147904Ssam
30832145Spst}
30932145Spst
310146778Ssam/* an NLPID of 0xb1 indicates a 2-byte
311146778Ssam * FRF.15 header
312146778Ssam *
313146778Ssam *      7    6    5    4    3    2    1    0
314146778Ssam *    +----+----+----+----+----+----+----+----+
315146778Ssam *    ~              Q.922 header             ~
316146778Ssam *    +----+----+----+----+----+----+----+----+
317146778Ssam *    |             NLPID (8 bits)            | NLPID=0xb1
318146778Ssam *    +----+----+----+----+----+----+----+----+
319146778Ssam *    | B  | E  | C  |seq. (high 4 bits) | R  |
320146778Ssam *    +----+----+----+----+----+----+----+----+
321146778Ssam *    |        sequence  (low 8 bits)         |
322146778Ssam *    +----+----+----+----+----+----+----+----+
323146778Ssam */
32432145Spst
325146778Ssamstruct tok frf15_flag_values[] = {
326146778Ssam    { 0x80, "Begin" },
327146778Ssam    { 0x40, "End" },
328146778Ssam    { 0x20, "Control" },
329146778Ssam    { 0, NULL }
330146778Ssam};
331146778Ssam
332146778Ssam#define FR_FRF15_FRAGTYPE 0x01
333146778Ssam
334146778Ssamstatic void
335146778Ssamfrf15_print (const u_char *p, u_int length) {
336146778Ssam
337146778Ssam    u_int16_t sequence_num, flags;
338146778Ssam
339146778Ssam    flags = p[0]&0xe0;
340146778Ssam    sequence_num = (p[0]&0x1e)<<7 | p[1];
341146778Ssam
342146778Ssam    printf("FRF.15, seq 0x%03x, Flags [%s],%s Fragmentation, length %u",
343146778Ssam           sequence_num,
344146778Ssam           bittok2str(frf15_flag_values,"none",flags),
345146778Ssam           flags&FR_FRF15_FRAGTYPE ? "Interface" : "End-to-End",
346146778Ssam           length);
347146778Ssam
348146778Ssam/* TODO:
349146778Ssam * depending on all permutations of the B, E and C bit
350146778Ssam * dig as deep as we can - e.g. on the first (B) fragment
351146778Ssam * there is enough payload to print the IP header
352146778Ssam * on non (B) fragments it depends if the fragmentation
353146778Ssam * model is end-to-end or interface based wether we want to print
354146778Ssam * another Q.922 header
355146778Ssam */
356146778Ssam
35732145Spst}
35832145Spst
35932145Spst/*
36032145Spst * Q.933 decoding portion for framerelay specific.
36132145Spst */
36232145Spst
36332145Spst/* Q.933 packet format
36432145Spst                      Format of Other Protocols
36532145Spst                          using Q.933 NLPID
36632145Spst                  +-------------------------------+
36732145Spst                  |        Q.922 Address          |
36832145Spst                  +---------------+---------------+
36932145Spst                  |Control  0x03  | NLPID   0x08  |
37032145Spst                  +---------------+---------------+
37132145Spst                  |          L2 Protocol ID       |
37232145Spst                  | octet 1       |  octet 2      |
37332145Spst                  +-------------------------------+
37432145Spst                  |          L3 Protocol ID       |
37532145Spst                  | octet 2       |  octet 2      |
37632145Spst                  +-------------------------------+
37732145Spst                  |         Protocol Data         |
37832145Spst                  +-------------------------------+
37932145Spst                  | FCS                           |
38032145Spst                  +-------------------------------+
38132145Spst */
38232145Spst
38332145Spst/* L2 (Octet 1)- Call Reference Usually is 0x0 */
38432145Spst
38532145Spst/*
38632145Spst * L2 (Octet 2)- Message Types definition 1 byte long.
38732145Spst */
38832145Spst/* Call Establish */
38932145Spst#define MSG_TYPE_ESC_TO_NATIONAL  0x00
39032145Spst#define MSG_TYPE_ALERT            0x01
39132145Spst#define MSG_TYPE_CALL_PROCEEDING  0x02
39232145Spst#define MSG_TYPE_CONNECT          0x07
39332145Spst#define MSG_TYPE_CONNECT_ACK      0x0F
39432145Spst#define MSG_TYPE_PROGRESS         0x03
39532145Spst#define MSG_TYPE_SETUP            0x05
39632145Spst/* Call Clear */
39732145Spst#define MSG_TYPE_DISCONNECT       0x45
39832145Spst#define MSG_TYPE_RELEASE          0x4D
39932145Spst#define MSG_TYPE_RELEASE_COMPLETE 0x5A
40032145Spst#define MSG_TYPE_RESTART          0x46
40132145Spst#define MSG_TYPE_RESTART_ACK      0x4E
40232145Spst/* Status */
40332145Spst#define MSG_TYPE_STATUS           0x7D
40432145Spst#define MSG_TYPE_STATUS_ENQ       0x75
40532145Spst
406146778Ssamstruct tok fr_q933_msg_values[] = {
407146778Ssam    { MSG_TYPE_ESC_TO_NATIONAL, "ESC to National" },
408146778Ssam    { MSG_TYPE_ALERT, "Alert" },
409146778Ssam    { MSG_TYPE_CALL_PROCEEDING, "Call proceeding" },
410146778Ssam    { MSG_TYPE_CONNECT, "Connect" },
411146778Ssam    { MSG_TYPE_CONNECT_ACK, "Connect ACK" },
412146778Ssam    { MSG_TYPE_PROGRESS, "Progress" },
413146778Ssam    { MSG_TYPE_SETUP, "Setup" },
414146778Ssam    { MSG_TYPE_DISCONNECT, "Disconnect" },
415146778Ssam    { MSG_TYPE_RELEASE, "Release" },
416146778Ssam    { MSG_TYPE_RELEASE_COMPLETE, "Release Complete" },
417146778Ssam    { MSG_TYPE_RESTART, "Restart" },
418146778Ssam    { MSG_TYPE_RESTART_ACK, "Restart ACK" },
419146778Ssam    { MSG_TYPE_STATUS, "Status Reply" },
420146778Ssam    { MSG_TYPE_STATUS_ENQ, "Status Enquiry" },
421146778Ssam    { 0, NULL }
422146778Ssam};
42332145Spst
424146778Ssam#define MSG_ANSI_LOCKING_SHIFT	0x95
425146778Ssam
426146778Ssam#define FR_LMI_ANSI_REPORT_TYPE_IE	0x01
427146778Ssam#define FR_LMI_ANSI_LINK_VERIFY_IE_91	0x19 /* details? */
428146778Ssam#define FR_LMI_ANSI_LINK_VERIFY_IE	0x03
429146778Ssam#define FR_LMI_ANSI_PVC_STATUS_IE	0x07
430146778Ssam
431146778Ssam#define FR_LMI_CCITT_REPORT_TYPE_IE	0x51
432146778Ssam#define FR_LMI_CCITT_LINK_VERIFY_IE	0x53
433146778Ssam#define FR_LMI_CCITT_PVC_STATUS_IE	0x57
434146778Ssam
435146778Ssamstruct tok fr_q933_ie_values_codeset5[] = {
436146778Ssam    { FR_LMI_ANSI_REPORT_TYPE_IE, "ANSI Report Type" },
437146778Ssam    { FR_LMI_ANSI_LINK_VERIFY_IE_91, "ANSI Link Verify" },
438146778Ssam    { FR_LMI_ANSI_LINK_VERIFY_IE, "ANSI Link Verify" },
439146778Ssam    { FR_LMI_ANSI_PVC_STATUS_IE, "ANSI PVC Status" },
440146778Ssam    { FR_LMI_CCITT_REPORT_TYPE_IE, "CCITT Report Type" },
441146778Ssam    { FR_LMI_CCITT_LINK_VERIFY_IE, "CCITT Link Verify" },
442146778Ssam    { FR_LMI_CCITT_PVC_STATUS_IE, "CCITT PVC Status" },
443146778Ssam    { 0, NULL }
44432145Spst};
44532145Spst
446146778Ssam#define FR_LMI_REPORT_TYPE_IE_FULL_STATUS 0
447146778Ssam#define FR_LMI_REPORT_TYPE_IE_LINK_VERIFY 1
448146778Ssam#define FR_LMI_REPORT_TYPE_IE_ASYNC_PVC   2
44932145Spst
450146778Ssamstruct tok fr_lmi_report_type_ie_values[] = {
451146778Ssam    { FR_LMI_REPORT_TYPE_IE_FULL_STATUS, "Full Status" },
452146778Ssam    { FR_LMI_REPORT_TYPE_IE_LINK_VERIFY, "Link verify" },
453146778Ssam    { FR_LMI_REPORT_TYPE_IE_ASYNC_PVC, "Async PVC Status" },
454146778Ssam    { 0, NULL }
455146778Ssam};
45632145Spst
457146778Ssam/* array of 16 codepages - currently we only support codepage 5 */
458146778Ssamstatic struct tok *fr_q933_ie_codesets[] = {
459146778Ssam    NULL,
460146778Ssam    NULL,
461146778Ssam    NULL,
462146778Ssam    NULL,
463146778Ssam    NULL,
464146778Ssam    fr_q933_ie_values_codeset5,
465146778Ssam    NULL,
466146778Ssam    NULL,
467146778Ssam    NULL,
468146778Ssam    NULL,
469146778Ssam    NULL,
470146778Ssam    NULL,
471146778Ssam    NULL,
472146778Ssam    NULL,
473146778Ssam    NULL,
474146778Ssam    NULL
47532145Spst};
47632145Spst
47732145Spst
478146778Ssamstruct common_ie_header {
479146778Ssam    u_int8_t ie_id;
480146778Ssam    u_int8_t ie_len;
481146778Ssam};
48232145Spst
483147904Ssamstatic int fr_q933_print_ie_codeset5(const struct common_ie_header *ie_p,
484147904Ssam    const u_char *p);
485147904Ssam
486147904Ssamtypedef int (*codeset_pr_func_t)(const struct common_ie_header *ie_p,
487147904Ssam    const u_char *p);
488147904Ssam
489147904Ssam/* array of 16 codepages - currently we only support codepage 5 */
490147904Ssamstatic codeset_pr_func_t fr_q933_print_ie_codeset[] = {
491147904Ssam    NULL,
492147904Ssam    NULL,
493147904Ssam    NULL,
494147904Ssam    NULL,
495147904Ssam    NULL,
496147904Ssam    fr_q933_print_ie_codeset5,
497147904Ssam    NULL,
498147904Ssam    NULL,
499147904Ssam    NULL,
500147904Ssam    NULL,
501147904Ssam    NULL,
502147904Ssam    NULL,
503147904Ssam    NULL,
504147904Ssam    NULL,
505147904Ssam    NULL,
506147904Ssam    NULL
507147904Ssam};
508147904Ssam
50932145Spstvoid
510146778Ssamq933_print(const u_char *p, u_int length)
51132145Spst{
51232145Spst	const u_char *ptemp = p;
51332145Spst	struct common_ie_header *ie_p;
514146778Ssam        int olen;
515146778Ssam	int is_ansi = 0;
516147904Ssam        u_int codeset;
517146778Ssam
518146778Ssam	if (length < 9) {	/* shortest: Q.933a LINK VERIFY */
519146778Ssam		printf("[|q.933]");
520146778Ssam		return;
521146778Ssam	}
522146778Ssam
523146778Ssam        codeset = p[2]&0x0f;   /* extract the codeset */
524146778Ssam
525146778Ssam	if (p[2] == MSG_ANSI_LOCKING_SHIFT)
526146778Ssam		is_ansi = 1;
52732145Spst
528146778Ssam        printf("%s", eflag ? "" : "Q.933, ");
52932145Spst
53032145Spst	/* printing out header part */
531147904Ssam	printf(is_ansi ? "ANSI" : "CCITT");
532146778Ssam
533146778Ssam	if (p[0])
534146778Ssam		printf(", Call Ref: 0x%02x", p[0]);
535146778Ssam
536146778Ssam        if (vflag)
537146778Ssam            printf(", %s (0x%02x), length %u",
538146778Ssam                   tok2str(fr_q933_msg_values,"unknown message",p[1]),
539146778Ssam                   p[1],
540146778Ssam                   length);
541146778Ssam        else
542146778Ssam            printf(", %s",
543146778Ssam                   tok2str(fr_q933_msg_values,"unknown message 0x%02x",p[1]));
544146778Ssam
545146778Ssam        olen = length; /* preserve the original length for non verbose mode */
546146778Ssam
547146778Ssam	if (length < (u_int)(2 - is_ansi)) {
548146778Ssam		printf("[|q.933]");
549146778Ssam		return;
55032145Spst	}
551146778Ssam	length -= 2 - is_ansi;
552146778Ssam	ptemp += 2 + is_ansi;
55332145Spst
55432145Spst	/* Loop through the rest of IE */
555146778Ssam	while (length > sizeof(struct common_ie_header)) {
55632145Spst		ie_p = (struct common_ie_header *)ptemp;
557146778Ssam		if (length < sizeof(struct common_ie_header) ||
558146778Ssam		    length < sizeof(struct common_ie_header) + ie_p->ie_len) {
559146778Ssam                    if (vflag) /* not bark if there is just a trailer */
560146778Ssam                        printf("\n[|q.933]");
561146778Ssam                    else
562146778Ssam                        printf(", length %u",olen);
563146778Ssam                    return;
56432145Spst		}
56532145Spst
566146778Ssam                /* lets do the full IE parsing only in verbose mode
567146778Ssam                 * however some IEs (DLCI Status, Link Verify)
568146778Ssam                 * are also intereststing in non-verbose mode */
569146778Ssam                if (vflag)
570146778Ssam                    printf("\n\t%s IE (%u), length %u: ",
571146778Ssam                           tok2str(fr_q933_ie_codesets[codeset],"unknown",ie_p->ie_id),
572146778Ssam                           ie_p->ie_id,
573146778Ssam                           ie_p->ie_len);
574146778Ssam
575147904Ssam                if (!fr_q933_print_ie_codeset[codeset] ||
576147904Ssam                    (*fr_q933_print_ie_codeset[codeset])(ie_p, ptemp)) {
577146778Ssam                    if (vflag <= 1)
578146778Ssam                        print_unknown_data(ptemp+2,"\n\t",ie_p->ie_len);
579146778Ssam                }
58032145Spst
581146778Ssam                /* do we want to see a hexdump of the IE ? */
582146778Ssam                if (vflag> 1)
583146778Ssam                    print_unknown_data(ptemp+2,"\n\t  ",ie_p->ie_len);
58432145Spst
585146778Ssam		length = length - ie_p->ie_len - 2;
586146778Ssam		ptemp = ptemp + ie_p->ie_len + 2;
587146778Ssam	}
588146778Ssam        if (!vflag)
589146778Ssam            printf(", length %u",olen);
590146778Ssam}
591147904Ssam
592147904Ssamstatic int
593147904Ssamfr_q933_print_ie_codeset5(const struct common_ie_header *ie_p, const u_char *p)
594147904Ssam{
595147904Ssam        u_int dlci;
596147904Ssam
597147904Ssam        switch (ie_p->ie_id) {
598147904Ssam
599147904Ssam        case FR_LMI_ANSI_REPORT_TYPE_IE: /* fall through */
600147904Ssam        case FR_LMI_CCITT_REPORT_TYPE_IE:
601147904Ssam            if (vflag)
602147904Ssam                printf("%s (%u)",
603147904Ssam                       tok2str(fr_lmi_report_type_ie_values,"unknown",p[2]),
604147904Ssam                       p[2]);
605147904Ssam            return 1;
606147904Ssam
607147904Ssam        case FR_LMI_ANSI_LINK_VERIFY_IE: /* fall through */
608147904Ssam        case FR_LMI_CCITT_LINK_VERIFY_IE:
609147904Ssam        case FR_LMI_ANSI_LINK_VERIFY_IE_91:
610147904Ssam            if (!vflag)
611147904Ssam                printf(", ");
612147904Ssam            printf("TX Seq: %3d, RX Seq: %3d", p[2], p[3]);
613147904Ssam            return 1;
614147904Ssam
615147904Ssam        case FR_LMI_ANSI_PVC_STATUS_IE: /* fall through */
616147904Ssam        case FR_LMI_CCITT_PVC_STATUS_IE:
617147904Ssam            if (!vflag)
618147904Ssam                printf(", ");
619147904Ssam            /* now parse the DLCI information element. */
620147904Ssam            if ((ie_p->ie_len < 3) ||
621147904Ssam                (p[2] & 0x80) ||
622147904Ssam                ((ie_p->ie_len == 3) && !(p[3] & 0x80)) ||
623147904Ssam                ((ie_p->ie_len == 4) && ((p[3] & 0x80) || !(p[4] & 0x80))) ||
624147904Ssam                ((ie_p->ie_len == 5) && ((p[3] & 0x80) || (p[4] & 0x80) ||
625147904Ssam                                   !(p[5] & 0x80))) ||
626147904Ssam                (ie_p->ie_len > 5) ||
627147904Ssam                !(p[ie_p->ie_len + 1] & 0x80))
628147904Ssam                printf("Invalid DLCI IE");
629147904Ssam
630147904Ssam            dlci = ((p[2] & 0x3F) << 4) | ((p[3] & 0x78) >> 3);
631147904Ssam            if (ie_p->ie_len == 4)
632147904Ssam                dlci = (dlci << 6) | ((p[4] & 0x7E) >> 1);
633147904Ssam            else if (ie_p->ie_len == 5)
634147904Ssam                dlci = (dlci << 13) | (p[4] & 0x7F) | ((p[5] & 0x7E) >> 1);
635147904Ssam
636147904Ssam            printf("DLCI %u: status %s%s", dlci,
637147904Ssam                    p[ie_p->ie_len + 1] & 0x8 ? "New, " : "",
638147904Ssam                    p[ie_p->ie_len + 1] & 0x2 ? "Active" : "Inactive");
639147904Ssam            return 1;
640147904Ssam	}
641147904Ssam
642147904Ssam        return 0;
643147904Ssam}
644