print-fr.c revision 313537
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.
2032145Spst */
2132145Spst
22313537Sglebius/* \summary: Frame Relay printer */
23313537Sglebius
24146778Ssam#ifdef HAVE_CONFIG_H
25146778Ssam#include "config.h"
2632145Spst#endif
2732145Spst
28313537Sglebius#include <netdissect-stdinc.h>
2932145Spst
30146778Ssam#include <stdio.h>
31146778Ssam#include <string.h>
3232145Spst
33313537Sglebius#include "netdissect.h"
34146778Ssam#include "addrtoname.h"
3532145Spst#include "ethertype.h"
36285275Spkelsey#include "llc.h"
37146778Ssam#include "nlpid.h"
38146778Ssam#include "extract.h"
39146778Ssam#include "oui.h"
4032145Spst
41276788Sdelphijstatic void frf15_print(netdissect_options *ndo, const u_char *, u_int);
4232145Spst
43146778Ssam/*
44146778Ssam * the frame relay header has a variable length
45146778Ssam *
46146778Ssam * the EA bit determines if there is another byte
47146778Ssam * in the header
48146778Ssam *
49146778Ssam * minimum header length is 2 bytes
50146778Ssam * maximum header length is 4 bytes
51146778Ssam *
52146778Ssam *      7    6    5    4    3    2    1    0
53146778Ssam *    +----+----+----+----+----+----+----+----+
54146778Ssam *    |        DLCI (6 bits)        | CR | EA |
55146778Ssam *    +----+----+----+----+----+----+----+----+
56146778Ssam *    |   DLCI (4 bits)   |FECN|BECN| DE | EA |
57146778Ssam *    +----+----+----+----+----+----+----+----+
58146778Ssam *    |           DLCI (7 bits)          | EA |
59146778Ssam *    +----+----+----+----+----+----+----+----+
60146778Ssam *    |        DLCI (6 bits)        |SDLC| EA |
61146778Ssam *    +----+----+----+----+----+----+----+----+
62146778Ssam */
6332145Spst
64146778Ssam#define FR_EA_BIT	0x01
6532145Spst
66146778Ssam#define FR_CR_BIT       0x02000000
67146778Ssam#define FR_DE_BIT	0x00020000
68146778Ssam#define FR_BECN_BIT	0x00040000
69146778Ssam#define FR_FECN_BIT	0x00080000
70146778Ssam#define FR_SDLC_BIT	0x00000002
7132145Spst
72146778Ssam
73276788Sdelphijstatic const struct tok fr_header_flag_values[] = {
74146778Ssam    { FR_CR_BIT, "C!" },
75146778Ssam    { FR_DE_BIT, "DE" },
76146778Ssam    { FR_BECN_BIT, "BECN" },
77146778Ssam    { FR_FECN_BIT, "FECN" },
78146778Ssam    { FR_SDLC_BIT, "sdlcore" },
79146778Ssam    { 0, NULL }
8032145Spst};
8132145Spst
82162021Ssam/* FRF.15 / FRF.16 */
83162021Ssam#define MFR_B_BIT 0x80
84162021Ssam#define MFR_E_BIT 0x40
85162021Ssam#define MFR_C_BIT 0x20
86162021Ssam#define MFR_BEC_MASK    (MFR_B_BIT | MFR_E_BIT | MFR_C_BIT)
87162021Ssam#define MFR_CTRL_FRAME  (MFR_B_BIT | MFR_E_BIT | MFR_C_BIT)
88162021Ssam#define MFR_FRAG_FRAME  (MFR_B_BIT | MFR_E_BIT )
89146778Ssam
90276788Sdelphijstatic const struct tok frf_flag_values[] = {
91162021Ssam    { MFR_B_BIT, "Begin" },
92162021Ssam    { MFR_E_BIT, "End" },
93162021Ssam    { MFR_C_BIT, "Control" },
94162021Ssam    { 0, NULL }
95162021Ssam};
96162021Ssam
97285275Spkelsey/* Finds out Q.922 address length, DLCI and flags. Returns 1 on success,
98285275Spkelsey * 0 on invalid address, -1 on truncated packet
99146778Ssam * save the flags dep. on address length
100146778Ssam */
101285275Spkelseystatic int parse_q922_addr(netdissect_options *ndo,
102285275Spkelsey                           const u_char *p, u_int *dlci,
103285275Spkelsey                           u_int *addr_len, uint8_t *flags, u_int length)
10432145Spst{
105285275Spkelsey	if (!ND_TTEST(p[0]) || length < 1)
106285275Spkelsey		return -1;
107146778Ssam	if ((p[0] & FR_EA_BIT))
108285275Spkelsey		return 0;
109285275Spkelsey
110285275Spkelsey	if (!ND_TTEST(p[1]) || length < 2)
111146778Ssam		return -1;
112146778Ssam	*addr_len = 2;
113146778Ssam	*dlci = ((p[0] & 0xFC) << 2) | ((p[1] & 0xF0) >> 4);
11432145Spst
115146778Ssam        flags[0] = p[0] & 0x02; /* populate the first flag fields */
116146778Ssam        flags[1] = p[1] & 0x0c;
117172686Smlaier        flags[2] = 0;           /* clear the rest of the flags */
118172686Smlaier        flags[3] = 0;
11932145Spst
120146778Ssam	if (p[1] & FR_EA_BIT)
121285275Spkelsey		return 1;	/* 2-byte Q.922 address */
12232145Spst
123146778Ssam	p += 2;
124285275Spkelsey	length -= 2;
125285275Spkelsey	if (!ND_TTEST(p[0]) || length < 1)
126285275Spkelsey		return -1;
127146778Ssam	(*addr_len)++;		/* 3- or 4-byte Q.922 address */
128146778Ssam	if ((p[0] & FR_EA_BIT) == 0) {
129146778Ssam		*dlci = (*dlci << 7) | (p[0] >> 1);
130146778Ssam		(*addr_len)++;	/* 4-byte Q.922 address */
131146778Ssam		p++;
132285275Spkelsey		length--;
133146778Ssam	}
13432145Spst
135285275Spkelsey	if (!ND_TTEST(p[0]) || length < 1)
136285275Spkelsey		return -1;
137146778Ssam	if ((p[0] & FR_EA_BIT) == 0)
138285275Spkelsey		return 0; /* more than 4 bytes of Q.922 address? */
139146778Ssam
140146778Ssam        flags[3] = p[0] & 0x02;
141146778Ssam
142190207Srpaulo        *dlci = (*dlci << 6) | (p[0] >> 2);
143146778Ssam
144285275Spkelsey	return 1;
14532145Spst}
14632145Spst
147285275Spkelseychar *
148285275Spkelseyq922_string(netdissect_options *ndo, const u_char *p, u_int length)
149285275Spkelsey{
150190207Srpaulo
151190207Srpaulo    static u_int dlci, addr_len;
152276788Sdelphij    static uint8_t flags[4];
153190207Srpaulo    static char buffer[sizeof("DLCI xxxxxxxxxx")];
154190207Srpaulo    memset(buffer, 0, sizeof(buffer));
155190207Srpaulo
156285275Spkelsey    if (parse_q922_addr(ndo, p, &dlci, &addr_len, flags, length) == 1){
157190207Srpaulo        snprintf(buffer, sizeof(buffer), "DLCI %u", dlci);
158190207Srpaulo    }
159190207Srpaulo
160190207Srpaulo    return buffer;
161190207Srpaulo}
162190207Srpaulo
163190207Srpaulo
164146778Ssam/* Frame Relay packet structure, with flags and CRC removed
16532145Spst
16632145Spst                  +---------------------------+
16732145Spst                  |       Q.922 Address*      |
16832145Spst                  +--                       --+
16932145Spst                  |                           |
17032145Spst                  +---------------------------+
17132145Spst                  | Control (UI = 0x03)       |
17232145Spst                  +---------------------------+
17332145Spst                  | Optional Pad      (0x00)  |
17432145Spst                  +---------------------------+
17532145Spst                  | NLPID                     |
17632145Spst                  +---------------------------+
17732145Spst                  |             .             |
17832145Spst                  |             .             |
17932145Spst                  |             .             |
18032145Spst                  |           Data            |
18132145Spst                  |             .             |
18232145Spst                  |             .             |
18332145Spst                  +---------------------------+
18432145Spst
18532145Spst           * Q.922 addresses, as presently defined, are two octets and
18632145Spst             contain a 10-bit DLCI.  In some networks Q.922 addresses
18732145Spst             may optionally be increased to three or four octets.
18832145Spst*/
18932145Spst
190146778Ssamstatic void
191276788Sdelphijfr_hdr_print(netdissect_options *ndo,
192276788Sdelphij             int length, u_int addr_len, u_int dlci, uint8_t *flags, uint16_t nlpid)
19332145Spst{
194276788Sdelphij    if (ndo->ndo_qflag) {
195276788Sdelphij        ND_PRINT((ndo, "Q.922, DLCI %u, length %u: ",
196146778Ssam                     dlci,
197276788Sdelphij                     length));
198146778Ssam    } else {
199146778Ssam        if (nlpid <= 0xff) /* if its smaller than 256 then its a NLPID */
200276788Sdelphij            ND_PRINT((ndo, "Q.922, hdr-len %u, DLCI %u, Flags [%s], NLPID %s (0x%02x), length %u: ",
201146778Ssam                         addr_len,
202146778Ssam                         dlci,
203146778Ssam                         bittok2str(fr_header_flag_values, "none", EXTRACT_32BITS(flags)),
204146778Ssam                         tok2str(nlpid_values,"unknown", nlpid),
205146778Ssam                         nlpid,
206276788Sdelphij                         length));
207146778Ssam        else /* must be an ethertype */
208276788Sdelphij            ND_PRINT((ndo, "Q.922, hdr-len %u, DLCI %u, Flags [%s], cisco-ethertype %s (0x%04x), length %u: ",
209146778Ssam                         addr_len,
210146778Ssam                         dlci,
211146778Ssam                         bittok2str(fr_header_flag_values, "none", EXTRACT_32BITS(flags)),
212146778Ssam                         tok2str(ethertype_values, "unknown", nlpid),
213146778Ssam                         nlpid,
214276788Sdelphij                         length));
215146778Ssam    }
21632145Spst}
21732145Spst
218146778Ssamu_int
219276788Sdelphijfr_if_print(netdissect_options *ndo,
220276788Sdelphij            const struct pcap_pkthdr *h, register const u_char *p)
22132145Spst{
22232145Spst	register u_int length = h->len;
22332145Spst	register u_int caplen = h->caplen;
224147904Ssam
225276788Sdelphij        ND_TCHECK2(*p, 4); /* minimum frame header length */
226147904Ssam
227276788Sdelphij        if ((length = fr_print(ndo, p, length)) == 0)
228147904Ssam            return (0);
229147904Ssam        else
230147904Ssam            return length;
231147904Ssam trunc:
232276788Sdelphij        ND_PRINT((ndo, "[|fr]"));
233147904Ssam        return caplen;
234147904Ssam}
235147904Ssam
236147904Ssamu_int
237276788Sdelphijfr_print(netdissect_options *ndo,
238276788Sdelphij         register const u_char *p, u_int length)
239147904Ssam{
240285275Spkelsey	int ret;
241276788Sdelphij	uint16_t extracted_ethertype;
242146778Ssam	u_int dlci;
243146778Ssam	u_int addr_len;
244276788Sdelphij	uint16_t nlpid;
245146778Ssam	u_int hdr_len;
246276788Sdelphij	uint8_t flags[4];
24732145Spst
248285275Spkelsey	ret = parse_q922_addr(ndo, p, &dlci, &addr_len, flags, length);
249285275Spkelsey	if (ret == -1)
250285275Spkelsey		goto trunc;
251285275Spkelsey	if (ret == 0) {
252276788Sdelphij		ND_PRINT((ndo, "Q.922, invalid address"));
253147904Ssam		return 0;
254146778Ssam	}
25532145Spst
256285275Spkelsey	ND_TCHECK(p[addr_len]);
257285275Spkelsey	if (length < addr_len + 1)
258285275Spkelsey		goto trunc;
259146778Ssam
260285275Spkelsey	if (p[addr_len] != LLC_UI && dlci != 0) {
261285275Spkelsey                /*
262285275Spkelsey                 * Let's figure out if we have Cisco-style encapsulation,
263285275Spkelsey                 * with an Ethernet type (Cisco HDLC type?) following the
264285275Spkelsey                 * address.
265285275Spkelsey                 */
266285275Spkelsey		if (!ND_TTEST2(p[addr_len], 2) || length < addr_len + 2) {
267285275Spkelsey                        /* no Ethertype */
268285275Spkelsey                        ND_PRINT((ndo, "UI %02x! ", p[addr_len]));
269285275Spkelsey                } else {
270285275Spkelsey                        extracted_ethertype = EXTRACT_16BITS(p+addr_len);
27132145Spst
272285275Spkelsey                        if (ndo->ndo_eflag)
273285275Spkelsey                                fr_hdr_print(ndo, length, addr_len, dlci,
274285275Spkelsey                                    flags, extracted_ethertype);
275146778Ssam
276285275Spkelsey                        if (ethertype_print(ndo, extracted_ethertype,
277285275Spkelsey                                            p+addr_len+ETHERTYPE_LEN,
278285275Spkelsey                                            length-addr_len-ETHERTYPE_LEN,
279313537Sglebius                                            ndo->ndo_snapend-p-addr_len-ETHERTYPE_LEN,
280313537Sglebius                                            NULL, NULL) == 0)
281285275Spkelsey                                /* ether_type not known, probably it wasn't one */
282285275Spkelsey                                ND_PRINT((ndo, "UI %02x! ", p[addr_len]));
283285275Spkelsey                        else
284285275Spkelsey                                return addr_len + 2;
285285275Spkelsey                }
286146778Ssam        }
287146778Ssam
288285275Spkelsey	ND_TCHECK(p[addr_len+1]);
289285275Spkelsey	if (length < addr_len + 2)
290285275Spkelsey		goto trunc;
291285275Spkelsey
292285275Spkelsey	if (p[addr_len + 1] == 0) {
293285275Spkelsey		/*
294285275Spkelsey		 * Assume a pad byte after the control (UI) byte.
295285275Spkelsey		 * A pad byte should only be used with 3-byte Q.922.
296285275Spkelsey		 */
297146778Ssam		if (addr_len != 3)
298276788Sdelphij			ND_PRINT((ndo, "Pad! "));
299285275Spkelsey		hdr_len = addr_len + 1 /* UI */ + 1 /* pad */ + 1 /* NLPID */;
300285275Spkelsey	} else {
301285275Spkelsey		/*
302285275Spkelsey		 * Not a pad byte.
303285275Spkelsey		 * A pad byte should be used with 3-byte Q.922.
304285275Spkelsey		 */
305285275Spkelsey		if (addr_len == 3)
306285275Spkelsey			ND_PRINT((ndo, "No pad! "));
307285275Spkelsey		hdr_len = addr_len + 1 /* UI */ + 1 /* NLPID */;
308285275Spkelsey	}
309146778Ssam
310285275Spkelsey        ND_TCHECK(p[hdr_len - 1]);
311285275Spkelsey	if (length < hdr_len)
312285275Spkelsey		goto trunc;
313146778Ssam	nlpid = p[hdr_len - 1];
314146778Ssam
315276788Sdelphij	if (ndo->ndo_eflag)
316276788Sdelphij		fr_hdr_print(ndo, length, addr_len, dlci, flags, nlpid);
317146778Ssam	p += hdr_len;
318146778Ssam	length -= hdr_len;
31932145Spst
320146778Ssam	switch (nlpid) {
32132145Spst	case NLPID_IP:
322276788Sdelphij	        ip_print(ndo, p, length);
32332145Spst		break;
324146778Ssam
325146778Ssam	case NLPID_IP6:
326276788Sdelphij		ip6_print(ndo, p, length);
327146778Ssam		break;
328285275Spkelsey
32932145Spst	case NLPID_CLNP:
33032145Spst	case NLPID_ESIS:
33132145Spst	case NLPID_ISIS:
332313537Sglebius		isoclns_print(ndo, p - 1, length + 1, ndo->ndo_snapend - p + 1); /* OSI printers need the NLPID field */
33332145Spst		break;
334146778Ssam
335146778Ssam	case NLPID_SNAP:
336313537Sglebius		if (snap_print(ndo, p, length, ndo->ndo_snapend - p, NULL, NULL, 0) == 0) {
337146778Ssam			/* ether_type not known, print raw packet */
338276788Sdelphij                        if (!ndo->ndo_eflag)
339276788Sdelphij                            fr_hdr_print(ndo, length + hdr_len, hdr_len,
340146778Ssam                                         dlci, flags, nlpid);
341276788Sdelphij			if (!ndo->ndo_suppress_default_print)
342276788Sdelphij				ND_DEFAULTPRINT(p - hdr_len, length + hdr_len);
343146778Ssam		}
34432145Spst		break;
345146778Ssam
346146778Ssam        case NLPID_Q933:
347276788Sdelphij		q933_print(ndo, p, length);
348146778Ssam		break;
349146778Ssam
350146778Ssam        case NLPID_MFR:
351276788Sdelphij                frf15_print(ndo, p, length);
352146778Ssam                break;
353146778Ssam
354172686Smlaier        case NLPID_PPP:
355276788Sdelphij                ppp_print(ndo, p, length);
356172686Smlaier                break;
357172686Smlaier
35832145Spst	default:
359276788Sdelphij		if (!ndo->ndo_eflag)
360276788Sdelphij                    fr_hdr_print(ndo, length + hdr_len, addr_len,
361146778Ssam				     dlci, flags, nlpid);
362276788Sdelphij		if (!ndo->ndo_xflag)
363276788Sdelphij			ND_DEFAULTPRINT(p, length);
36432145Spst	}
36532145Spst
366146778Ssam	return hdr_len;
367147904Ssam
368147904Ssam trunc:
369276788Sdelphij        ND_PRINT((ndo, "[|fr]"));
370147904Ssam        return 0;
371147904Ssam
37232145Spst}
37332145Spst
374172686Smlaieru_int
375276788Sdelphijmfr_if_print(netdissect_options *ndo,
376276788Sdelphij             const struct pcap_pkthdr *h, register const u_char *p)
377172686Smlaier{
378172686Smlaier	register u_int length = h->len;
379172686Smlaier	register u_int caplen = h->caplen;
380172686Smlaier
381276788Sdelphij        ND_TCHECK2(*p, 2); /* minimum frame header length */
382172686Smlaier
383276788Sdelphij        if ((length = mfr_print(ndo, p, length)) == 0)
384172686Smlaier            return (0);
385172686Smlaier        else
386172686Smlaier            return length;
387172686Smlaier trunc:
388276788Sdelphij        ND_PRINT((ndo, "[|mfr]"));
389172686Smlaier        return caplen;
390172686Smlaier}
391172686Smlaier
392172686Smlaier
393162021Ssam#define MFR_CTRL_MSG_ADD_LINK        1
394162021Ssam#define MFR_CTRL_MSG_ADD_LINK_ACK    2
395162021Ssam#define MFR_CTRL_MSG_ADD_LINK_REJ    3
396162021Ssam#define MFR_CTRL_MSG_HELLO           4
397162021Ssam#define MFR_CTRL_MSG_HELLO_ACK       5
398162021Ssam#define MFR_CTRL_MSG_REMOVE_LINK     6
399162021Ssam#define MFR_CTRL_MSG_REMOVE_LINK_ACK 7
400162021Ssam
401276788Sdelphijstatic const struct tok mfr_ctrl_msg_values[] = {
402162021Ssam    { MFR_CTRL_MSG_ADD_LINK, "Add Link" },
403162021Ssam    { MFR_CTRL_MSG_ADD_LINK_ACK, "Add Link ACK" },
404162021Ssam    { MFR_CTRL_MSG_ADD_LINK_REJ, "Add Link Reject" },
405162021Ssam    { MFR_CTRL_MSG_HELLO, "Hello" },
406162021Ssam    { MFR_CTRL_MSG_HELLO_ACK, "Hello ACK" },
407162021Ssam    { MFR_CTRL_MSG_REMOVE_LINK, "Remove Link" },
408162021Ssam    { MFR_CTRL_MSG_REMOVE_LINK_ACK, "Remove Link ACK" },
409162021Ssam    { 0, NULL }
410162021Ssam};
411162021Ssam
412162021Ssam#define MFR_CTRL_IE_BUNDLE_ID  1
413162021Ssam#define MFR_CTRL_IE_LINK_ID    2
414162021Ssam#define MFR_CTRL_IE_MAGIC_NUM  3
415162021Ssam#define MFR_CTRL_IE_TIMESTAMP  5
416162021Ssam#define MFR_CTRL_IE_VENDOR_EXT 6
417162021Ssam#define MFR_CTRL_IE_CAUSE      7
418162021Ssam
419276788Sdelphijstatic const struct tok mfr_ctrl_ie_values[] = {
420162021Ssam    { MFR_CTRL_IE_BUNDLE_ID, "Bundle ID"},
421162021Ssam    { MFR_CTRL_IE_LINK_ID, "Link ID"},
422162021Ssam    { MFR_CTRL_IE_MAGIC_NUM, "Magic Number"},
423162021Ssam    { MFR_CTRL_IE_TIMESTAMP, "Timestamp"},
424162021Ssam    { MFR_CTRL_IE_VENDOR_EXT, "Vendor Extension"},
425162021Ssam    { MFR_CTRL_IE_CAUSE, "Cause"},
426162021Ssam    { 0, NULL }
427162021Ssam};
428162021Ssam
429162021Ssam#define MFR_ID_STRING_MAXLEN 50
430162021Ssam
431162021Ssamstruct ie_tlv_header_t {
432276788Sdelphij    uint8_t ie_type;
433276788Sdelphij    uint8_t ie_len;
434162021Ssam};
435162021Ssam
436162021Ssamu_int
437276788Sdelphijmfr_print(netdissect_options *ndo,
438276788Sdelphij          register const u_char *p, u_int length)
439162021Ssam{
440162021Ssam    u_int tlen,idx,hdr_len = 0;
441276788Sdelphij    uint16_t sequence_num;
442276788Sdelphij    uint8_t ie_type,ie_len;
443276788Sdelphij    const uint8_t *tptr;
444162021Ssam
445162021Ssam
446162021Ssam/*
447162021Ssam * FRF.16 Link Integrity Control Frame
448276788Sdelphij *
449162021Ssam *      7    6    5    4    3    2    1    0
450162021Ssam *    +----+----+----+----+----+----+----+----+
451162021Ssam *    | B  | E  | C=1| 0    0    0    0  | EA |
452162021Ssam *    +----+----+----+----+----+----+----+----+
453162021Ssam *    | 0    0    0    0    0    0    0    0  |
454162021Ssam *    +----+----+----+----+----+----+----+----+
455162021Ssam *    |              message type             |
456162021Ssam *    +----+----+----+----+----+----+----+----+
457162021Ssam */
458162021Ssam
459276788Sdelphij    ND_TCHECK2(*p, 4); /* minimum frame header length */
460162021Ssam
461162021Ssam    if ((p[0] & MFR_BEC_MASK) == MFR_CTRL_FRAME && p[1] == 0) {
462276788Sdelphij        ND_PRINT((ndo, "FRF.16 Control, Flags [%s], %s, length %u",
463162021Ssam               bittok2str(frf_flag_values,"none",(p[0] & MFR_BEC_MASK)),
464162021Ssam               tok2str(mfr_ctrl_msg_values,"Unknown Message (0x%02x)",p[2]),
465276788Sdelphij               length));
466162021Ssam        tptr = p + 3;
467162021Ssam        tlen = length -3;
468162021Ssam        hdr_len = 3;
469162021Ssam
470276788Sdelphij        if (!ndo->ndo_vflag)
471162021Ssam            return hdr_len;
472162021Ssam
473162021Ssam        while (tlen>sizeof(struct ie_tlv_header_t)) {
474276788Sdelphij            ND_TCHECK2(*tptr, sizeof(struct ie_tlv_header_t));
475162021Ssam            ie_type=tptr[0];
476162021Ssam            ie_len=tptr[1];
477162021Ssam
478276788Sdelphij            ND_PRINT((ndo, "\n\tIE %s (%u), length %u: ",
479162021Ssam                   tok2str(mfr_ctrl_ie_values,"Unknown",ie_type),
480162021Ssam                   ie_type,
481276788Sdelphij                   ie_len));
482162021Ssam
483162021Ssam            /* infinite loop check */
484162021Ssam            if (ie_type == 0 || ie_len <= sizeof(struct ie_tlv_header_t))
485162021Ssam                return hdr_len;
486162021Ssam
487276788Sdelphij            ND_TCHECK2(*tptr, ie_len);
488162021Ssam            tptr+=sizeof(struct ie_tlv_header_t);
489162021Ssam            /* tlv len includes header */
490162021Ssam            ie_len-=sizeof(struct ie_tlv_header_t);
491162021Ssam            tlen-=sizeof(struct ie_tlv_header_t);
492162021Ssam
493162021Ssam            switch (ie_type) {
494162021Ssam
495162021Ssam            case MFR_CTRL_IE_MAGIC_NUM:
496276788Sdelphij                ND_PRINT((ndo, "0x%08x", EXTRACT_32BITS(tptr)));
497162021Ssam                break;
498162021Ssam
499162021Ssam            case MFR_CTRL_IE_BUNDLE_ID: /* same message format */
500162021Ssam            case MFR_CTRL_IE_LINK_ID:
501162021Ssam                for (idx = 0; idx < ie_len && idx < MFR_ID_STRING_MAXLEN; idx++) {
502162021Ssam                    if (*(tptr+idx) != 0) /* don't print null termination */
503276788Sdelphij                        safeputchar(ndo, *(tptr + idx));
504162021Ssam                    else
505162021Ssam                        break;
506162021Ssam                }
507162021Ssam                break;
508162021Ssam
509162021Ssam            case MFR_CTRL_IE_TIMESTAMP:
510162021Ssam                if (ie_len == sizeof(struct timeval)) {
511276788Sdelphij                    ts_print(ndo, (const struct timeval *)tptr);
512162021Ssam                    break;
513162021Ssam                }
514162021Ssam                /* fall through and hexdump if no unix timestamp */
515162021Ssam
516162021Ssam                /*
517162021Ssam                 * FIXME those are the defined IEs that lack a decoder
518162021Ssam                 * you are welcome to contribute code ;-)
519162021Ssam                 */
520162021Ssam
521162021Ssam            case MFR_CTRL_IE_VENDOR_EXT:
522162021Ssam            case MFR_CTRL_IE_CAUSE:
523162021Ssam
524162021Ssam            default:
525276788Sdelphij                if (ndo->ndo_vflag <= 1)
526276788Sdelphij                    print_unknown_data(ndo, tptr, "\n\t  ", ie_len);
527162021Ssam                break;
528162021Ssam            }
529162021Ssam
530162021Ssam            /* do we want to see a hexdump of the IE ? */
531276788Sdelphij            if (ndo->ndo_vflag > 1 )
532276788Sdelphij                print_unknown_data(ndo, tptr, "\n\t  ", ie_len);
533276788Sdelphij
534162021Ssam            tlen-=ie_len;
535162021Ssam            tptr+=ie_len;
536162021Ssam        }
537162021Ssam        return hdr_len;
538162021Ssam    }
539162021Ssam/*
540162021Ssam * FRF.16 Fragmentation Frame
541276788Sdelphij *
542162021Ssam *      7    6    5    4    3    2    1    0
543162021Ssam *    +----+----+----+----+----+----+----+----+
544162021Ssam *    | B  | E  | C=0|seq. (high 4 bits) | EA  |
545162021Ssam *    +----+----+----+----+----+----+----+----+
546162021Ssam *    |        sequence  (low 8 bits)         |
547162021Ssam *    +----+----+----+----+----+----+----+----+
548162021Ssam *    |        DLCI (6 bits)        | CR | EA  |
549162021Ssam *    +----+----+----+----+----+----+----+----+
550162021Ssam *    |   DLCI (4 bits)   |FECN|BECN| DE | EA |
551162021Ssam *    +----+----+----+----+----+----+----+----+
552162021Ssam */
553162021Ssam
554162021Ssam    sequence_num = (p[0]&0x1e)<<7 | p[1];
555162021Ssam    /* whole packet or first fragment ? */
556162021Ssam    if ((p[0] & MFR_BEC_MASK) == MFR_FRAG_FRAME ||
557162021Ssam        (p[0] & MFR_BEC_MASK) == MFR_B_BIT) {
558276788Sdelphij        ND_PRINT((ndo, "FRF.16 Frag, seq %u, Flags [%s], ",
559162021Ssam               sequence_num,
560276788Sdelphij               bittok2str(frf_flag_values,"none",(p[0] & MFR_BEC_MASK))));
561162021Ssam        hdr_len = 2;
562276788Sdelphij        fr_print(ndo, p+hdr_len,length-hdr_len);
563162021Ssam        return hdr_len;
564162021Ssam    }
565162021Ssam
566162021Ssam    /* must be a middle or the last fragment */
567276788Sdelphij    ND_PRINT((ndo, "FRF.16 Frag, seq %u, Flags [%s]",
568162021Ssam           sequence_num,
569276788Sdelphij           bittok2str(frf_flag_values,"none",(p[0] & MFR_BEC_MASK))));
570276788Sdelphij    print_unknown_data(ndo, p, "\n\t", length);
571162021Ssam
572162021Ssam    return hdr_len;
573162021Ssam
574162021Ssam trunc:
575276788Sdelphij    ND_PRINT((ndo, "[|mfr]"));
576162021Ssam    return length;
577162021Ssam}
578162021Ssam
579146778Ssam/* an NLPID of 0xb1 indicates a 2-byte
580146778Ssam * FRF.15 header
581276788Sdelphij *
582146778Ssam *      7    6    5    4    3    2    1    0
583146778Ssam *    +----+----+----+----+----+----+----+----+
584146778Ssam *    ~              Q.922 header             ~
585146778Ssam *    +----+----+----+----+----+----+----+----+
586146778Ssam *    |             NLPID (8 bits)            | NLPID=0xb1
587146778Ssam *    +----+----+----+----+----+----+----+----+
588146778Ssam *    | B  | E  | C  |seq. (high 4 bits) | R  |
589146778Ssam *    +----+----+----+----+----+----+----+----+
590146778Ssam *    |        sequence  (low 8 bits)         |
591146778Ssam *    +----+----+----+----+----+----+----+----+
592146778Ssam */
59332145Spst
594146778Ssam#define FR_FRF15_FRAGTYPE 0x01
595146778Ssam
596146778Ssamstatic void
597276788Sdelphijfrf15_print(netdissect_options *ndo,
598285275Spkelsey            const u_char *p, u_int length)
599285275Spkelsey{
600276788Sdelphij    uint16_t sequence_num, flags;
601276788Sdelphij
602313537Sglebius    if (length < 2)
603313537Sglebius        goto trunc;
604313537Sglebius    ND_TCHECK2(*p, 2);
605313537Sglebius
606162021Ssam    flags = p[0]&MFR_BEC_MASK;
607146778Ssam    sequence_num = (p[0]&0x1e)<<7 | p[1];
608146778Ssam
609276788Sdelphij    ND_PRINT((ndo, "FRF.15, seq 0x%03x, Flags [%s],%s Fragmentation, length %u",
610146778Ssam           sequence_num,
611162021Ssam           bittok2str(frf_flag_values,"none",flags),
612162021Ssam           p[0]&FR_FRF15_FRAGTYPE ? "Interface" : "End-to-End",
613276788Sdelphij           length));
614146778Ssam
615146778Ssam/* TODO:
616146778Ssam * depending on all permutations of the B, E and C bit
617146778Ssam * dig as deep as we can - e.g. on the first (B) fragment
618146778Ssam * there is enough payload to print the IP header
619146778Ssam * on non (B) fragments it depends if the fragmentation
620146778Ssam * model is end-to-end or interface based wether we want to print
621146778Ssam * another Q.922 header
622146778Ssam */
623313537Sglebius    return;
624146778Ssam
625313537Sglebiustrunc:
626313537Sglebius    ND_PRINT((ndo, "[|frf.15]"));
62732145Spst}
62832145Spst
62932145Spst/*
63032145Spst * Q.933 decoding portion for framerelay specific.
63132145Spst */
63232145Spst
63332145Spst/* Q.933 packet format
634276788Sdelphij                      Format of Other Protocols
63532145Spst                          using Q.933 NLPID
636276788Sdelphij                  +-------------------------------+
637276788Sdelphij                  |        Q.922 Address          |
63832145Spst                  +---------------+---------------+
639276788Sdelphij                  |Control  0x03  | NLPID   0x08  |
640276788Sdelphij                  +---------------+---------------+
64132145Spst                  |          L2 Protocol ID       |
64232145Spst                  | octet 1       |  octet 2      |
64332145Spst                  +-------------------------------+
64432145Spst                  |          L3 Protocol ID       |
64532145Spst                  | octet 2       |  octet 2      |
64632145Spst                  +-------------------------------+
64732145Spst                  |         Protocol Data         |
64832145Spst                  +-------------------------------+
64932145Spst                  | FCS                           |
65032145Spst                  +-------------------------------+
65132145Spst */
65232145Spst
65332145Spst/* L2 (Octet 1)- Call Reference Usually is 0x0 */
65432145Spst
65532145Spst/*
65632145Spst * L2 (Octet 2)- Message Types definition 1 byte long.
65732145Spst */
65832145Spst/* Call Establish */
65932145Spst#define MSG_TYPE_ESC_TO_NATIONAL  0x00
66032145Spst#define MSG_TYPE_ALERT            0x01
66132145Spst#define MSG_TYPE_CALL_PROCEEDING  0x02
66232145Spst#define MSG_TYPE_CONNECT          0x07
66332145Spst#define MSG_TYPE_CONNECT_ACK      0x0F
66432145Spst#define MSG_TYPE_PROGRESS         0x03
66532145Spst#define MSG_TYPE_SETUP            0x05
66632145Spst/* Call Clear */
66732145Spst#define MSG_TYPE_DISCONNECT       0x45
66832145Spst#define MSG_TYPE_RELEASE          0x4D
66932145Spst#define MSG_TYPE_RELEASE_COMPLETE 0x5A
67032145Spst#define MSG_TYPE_RESTART          0x46
67132145Spst#define MSG_TYPE_RESTART_ACK      0x4E
67232145Spst/* Status */
67332145Spst#define MSG_TYPE_STATUS           0x7D
67432145Spst#define MSG_TYPE_STATUS_ENQ       0x75
67532145Spst
676276788Sdelphijstatic const struct tok fr_q933_msg_values[] = {
677146778Ssam    { MSG_TYPE_ESC_TO_NATIONAL, "ESC to National" },
678146778Ssam    { MSG_TYPE_ALERT, "Alert" },
679146778Ssam    { MSG_TYPE_CALL_PROCEEDING, "Call proceeding" },
680146778Ssam    { MSG_TYPE_CONNECT, "Connect" },
681146778Ssam    { MSG_TYPE_CONNECT_ACK, "Connect ACK" },
682146778Ssam    { MSG_TYPE_PROGRESS, "Progress" },
683146778Ssam    { MSG_TYPE_SETUP, "Setup" },
684146778Ssam    { MSG_TYPE_DISCONNECT, "Disconnect" },
685146778Ssam    { MSG_TYPE_RELEASE, "Release" },
686146778Ssam    { MSG_TYPE_RELEASE_COMPLETE, "Release Complete" },
687146778Ssam    { MSG_TYPE_RESTART, "Restart" },
688146778Ssam    { MSG_TYPE_RESTART_ACK, "Restart ACK" },
689146778Ssam    { MSG_TYPE_STATUS, "Status Reply" },
690146778Ssam    { MSG_TYPE_STATUS_ENQ, "Status Enquiry" },
691146778Ssam    { 0, NULL }
692146778Ssam};
69332145Spst
694313537Sglebius#define IE_IS_SINGLE_OCTET(iecode)	((iecode) & 0x80)
695313537Sglebius#define IE_IS_SHIFT(iecode)		(((iecode) & 0xF0) == 0x90)
696313537Sglebius#define IE_SHIFT_IS_NON_LOCKING(iecode)	((iecode) & 0x08)
697313537Sglebius#define IE_SHIFT_IS_LOCKING(iecode)	(!(IE_SHIFT_IS_NON_LOCKING(iecode)))
698313537Sglebius#define IE_SHIFT_CODESET(iecode)	((iecode) & 0x07)
699146778Ssam
700146778Ssam#define FR_LMI_ANSI_REPORT_TYPE_IE	0x01
701146778Ssam#define FR_LMI_ANSI_LINK_VERIFY_IE_91	0x19 /* details? */
702146778Ssam#define FR_LMI_ANSI_LINK_VERIFY_IE	0x03
703146778Ssam#define FR_LMI_ANSI_PVC_STATUS_IE	0x07
704146778Ssam
705146778Ssam#define FR_LMI_CCITT_REPORT_TYPE_IE	0x51
706146778Ssam#define FR_LMI_CCITT_LINK_VERIFY_IE	0x53
707146778Ssam#define FR_LMI_CCITT_PVC_STATUS_IE	0x57
708146778Ssam
709313537Sglebiusstatic const struct tok fr_q933_ie_values_codeset_0_5[] = {
710146778Ssam    { FR_LMI_ANSI_REPORT_TYPE_IE, "ANSI Report Type" },
711146778Ssam    { FR_LMI_ANSI_LINK_VERIFY_IE_91, "ANSI Link Verify" },
712146778Ssam    { FR_LMI_ANSI_LINK_VERIFY_IE, "ANSI Link Verify" },
713146778Ssam    { FR_LMI_ANSI_PVC_STATUS_IE, "ANSI PVC Status" },
714146778Ssam    { FR_LMI_CCITT_REPORT_TYPE_IE, "CCITT Report Type" },
715146778Ssam    { FR_LMI_CCITT_LINK_VERIFY_IE, "CCITT Link Verify" },
716146778Ssam    { FR_LMI_CCITT_PVC_STATUS_IE, "CCITT PVC Status" },
717146778Ssam    { 0, NULL }
71832145Spst};
71932145Spst
720146778Ssam#define FR_LMI_REPORT_TYPE_IE_FULL_STATUS 0
721146778Ssam#define FR_LMI_REPORT_TYPE_IE_LINK_VERIFY 1
722146778Ssam#define FR_LMI_REPORT_TYPE_IE_ASYNC_PVC   2
72332145Spst
724276788Sdelphijstatic const struct tok fr_lmi_report_type_ie_values[] = {
725146778Ssam    { FR_LMI_REPORT_TYPE_IE_FULL_STATUS, "Full Status" },
726146778Ssam    { FR_LMI_REPORT_TYPE_IE_LINK_VERIFY, "Link verify" },
727146778Ssam    { FR_LMI_REPORT_TYPE_IE_ASYNC_PVC, "Async PVC Status" },
728146778Ssam    { 0, NULL }
729146778Ssam};
73032145Spst
731313537Sglebius/* array of 16 codesets - currently we only support codepage 0 and 5 */
732276788Sdelphijstatic const struct tok *fr_q933_ie_codesets[] = {
733313537Sglebius    fr_q933_ie_values_codeset_0_5,
734146778Ssam    NULL,
735146778Ssam    NULL,
736146778Ssam    NULL,
737146778Ssam    NULL,
738313537Sglebius    fr_q933_ie_values_codeset_0_5,
739146778Ssam    NULL,
740146778Ssam    NULL,
741146778Ssam    NULL,
742146778Ssam    NULL,
743146778Ssam    NULL,
744146778Ssam    NULL,
745146778Ssam    NULL,
746146778Ssam    NULL,
747146778Ssam    NULL,
748146778Ssam    NULL
74932145Spst};
75032145Spst
751313537Sglebiusstatic int fr_q933_print_ie_codeset_0_5(netdissect_options *ndo, u_int iecode,
752313537Sglebius    u_int ielength, const u_char *p);
753147904Ssam
754313537Sglebiustypedef int (*codeset_pr_func_t)(netdissect_options *, u_int iecode,
755313537Sglebius    u_int ielength, const u_char *p);
756147904Ssam
757313537Sglebius/* array of 16 codesets - currently we only support codepage 0 and 5 */
758276788Sdelphijstatic const codeset_pr_func_t fr_q933_print_ie_codeset[] = {
759313537Sglebius    fr_q933_print_ie_codeset_0_5,
760147904Ssam    NULL,
761147904Ssam    NULL,
762147904Ssam    NULL,
763147904Ssam    NULL,
764313537Sglebius    fr_q933_print_ie_codeset_0_5,
765147904Ssam    NULL,
766147904Ssam    NULL,
767147904Ssam    NULL,
768147904Ssam    NULL,
769147904Ssam    NULL,
770147904Ssam    NULL,
771147904Ssam    NULL,
772147904Ssam    NULL,
773147904Ssam    NULL,
774147904Ssam    NULL
775147904Ssam};
776147904Ssam
777313537Sglebius/*
778313537Sglebius * ITU-T Q.933.
779313537Sglebius *
780313537Sglebius * p points to octet 2, the octet containing the length of the
781313537Sglebius * call reference value, so p[n] is octet n+2 ("octet X" is as
782313537Sglebius * used in Q.931/Q.933).
783313537Sglebius *
784313537Sglebius * XXX - actually used both for Q.931 and Q.933.
785313537Sglebius */
78632145Spstvoid
787276788Sdelphijq933_print(netdissect_options *ndo,
788276788Sdelphij           const u_char *p, u_int length)
78932145Spst{
790313537Sglebius	u_int olen;
791313537Sglebius	u_int call_ref_length, i;
792313537Sglebius	uint8_t call_ref[15];	/* maximum length - length field is 4 bits */
793313537Sglebius	u_int msgtype;
794313537Sglebius	u_int iecode;
795313537Sglebius	u_int ielength;
796313537Sglebius	u_int codeset = 0;
797313537Sglebius	u_int is_ansi = 0;
798313537Sglebius	u_int ie_is_known;
799313537Sglebius	u_int non_locking_shift;
800313537Sglebius	u_int unshift_codeset;
801146778Ssam
802313537Sglebius	ND_PRINT((ndo, "%s", ndo->ndo_eflag ? "" : "Q.933"));
803313537Sglebius
804313537Sglebius	if (length == 0 || !ND_TTEST(*p)) {
805313537Sglebius		if (!ndo->ndo_eflag)
806313537Sglebius			ND_PRINT((ndo, ", "));
807313537Sglebius		ND_PRINT((ndo, "length %u", length));
808313537Sglebius		goto trunc;
809146778Ssam	}
810146778Ssam
811313537Sglebius	/*
812313537Sglebius	 * Get the length of the call reference value.
813313537Sglebius	 */
814313537Sglebius	olen = length; /* preserve the original length for display */
815313537Sglebius	call_ref_length = (*p) & 0x0f;
816313537Sglebius	p++;
817313537Sglebius	length--;
818146778Ssam
819313537Sglebius	/*
820313537Sglebius	 * Get the call reference value.
821313537Sglebius	 */
822313537Sglebius	for (i = 0; i < call_ref_length; i++) {
823313537Sglebius		if (length == 0 || !ND_TTEST(*p)) {
824313537Sglebius			if (!ndo->ndo_eflag)
825313537Sglebius				ND_PRINT((ndo, ", "));
826313537Sglebius			ND_PRINT((ndo, "length %u", olen));
827313537Sglebius			goto trunc;
828313537Sglebius		}
829313537Sglebius		call_ref[i] = *p;
830313537Sglebius		p++;
831313537Sglebius		length--;
832190207Srpaulo	}
83332145Spst
834313537Sglebius	/*
835313537Sglebius	 * Get the message type.
836313537Sglebius	 */
837313537Sglebius	if (length == 0 || !ND_TTEST(*p)) {
838313537Sglebius		if (!ndo->ndo_eflag)
839313537Sglebius			ND_PRINT((ndo, ", "));
840313537Sglebius		ND_PRINT((ndo, "length %u", olen));
841313537Sglebius		goto trunc;
842313537Sglebius	}
843313537Sglebius	msgtype = *p;
844313537Sglebius	p++;
845313537Sglebius	length--;
846276788Sdelphij
847313537Sglebius	/*
848313537Sglebius	 * Peek ahead to see if we start with a shift.
849313537Sglebius	 */
850313537Sglebius	non_locking_shift = 0;
851313537Sglebius	unshift_codeset = codeset;
852313537Sglebius	if (length != 0) {
853313537Sglebius		if (!ND_TTEST(*p)) {
854313537Sglebius			if (!ndo->ndo_eflag)
855313537Sglebius				ND_PRINT((ndo, ", "));
856313537Sglebius			ND_PRINT((ndo, "length %u", olen));
857313537Sglebius			goto trunc;
858313537Sglebius		}
859313537Sglebius		iecode = *p;
860313537Sglebius		if (IE_IS_SHIFT(iecode)) {
861313537Sglebius			/*
862313537Sglebius			 * It's a shift.  Skip over it.
863313537Sglebius			 */
864313537Sglebius			p++;
865313537Sglebius			length--;
866313537Sglebius
867313537Sglebius			/*
868313537Sglebius			 * Get the codeset.
869313537Sglebius			 */
870313537Sglebius			codeset = IE_SHIFT_CODESET(iecode);
871313537Sglebius
872313537Sglebius			/*
873313537Sglebius			 * If it's a locking shift to codeset 5,
874313537Sglebius			 * mark this as ANSI.  (XXX - 5 is actually
875313537Sglebius			 * for national variants in general, not
876313537Sglebius			 * the US variant in particular, but maybe
877313537Sglebius			 * this is more American exceptionalism. :-))
878313537Sglebius			 */
879313537Sglebius			if (IE_SHIFT_IS_LOCKING(iecode)) {
880313537Sglebius				/*
881313537Sglebius				 * It's a locking shift.
882313537Sglebius				 */
883313537Sglebius				if (codeset == 5) {
884313537Sglebius					/*
885313537Sglebius					 * It's a locking shift to
886313537Sglebius					 * codeset 5, so this is
887313537Sglebius					 * T1.617 Annex D.
888313537Sglebius					 */
889313537Sglebius					is_ansi = 1;
890313537Sglebius				}
891313537Sglebius			} else {
892313537Sglebius				/*
893313537Sglebius				 * It's a non-locking shift.
894313537Sglebius				 * Remember the current codeset, so we
895313537Sglebius				 * can revert to it after the next IE.
896313537Sglebius				 */
897313537Sglebius				non_locking_shift = 1;
898313537Sglebius				unshift_codeset = 0;
899313537Sglebius			}
900313537Sglebius		}
901313537Sglebius	}
902313537Sglebius
90332145Spst	/* printing out header part */
904313537Sglebius	if (!ndo->ndo_eflag)
905313537Sglebius		ND_PRINT((ndo, ", "));
906276788Sdelphij	ND_PRINT((ndo, "%s, codeset %u", is_ansi ? "ANSI" : "CCITT", codeset));
907146778Ssam
908313537Sglebius	if (call_ref_length != 0) {
909313537Sglebius		ND_TCHECK(p[0]);
910313537Sglebius		if (call_ref_length > 1 || p[0] != 0) {
911313537Sglebius			/*
912313537Sglebius			 * Not a dummy call reference.
913313537Sglebius			 */
914313537Sglebius			ND_PRINT((ndo, ", Call Ref: 0x"));
915313537Sglebius			for (i = 0; i < call_ref_length; i++)
916313537Sglebius				ND_PRINT((ndo, "%02x", call_ref[i]));
917313537Sglebius		}
918190207Srpaulo	}
919313537Sglebius	if (ndo->ndo_vflag) {
920313537Sglebius		ND_PRINT((ndo, ", %s (0x%02x), length %u",
921313537Sglebius		   tok2str(fr_q933_msg_values,
922313537Sglebius			"unknown message", msgtype),
923313537Sglebius		   msgtype,
924313537Sglebius		   olen));
925313537Sglebius	} else {
926313537Sglebius		ND_PRINT((ndo, ", %s",
927190207Srpaulo		       tok2str(fr_q933_msg_values,
928313537Sglebius			       "unknown message 0x%02x", msgtype)));
929190207Srpaulo	}
930146778Ssam
931313537Sglebius	/* Loop through the rest of the IEs */
932313537Sglebius	while (length != 0) {
933313537Sglebius		/*
934313537Sglebius		 * What's the state of any non-locking shifts?
935313537Sglebius		 */
936313537Sglebius		if (non_locking_shift == 1) {
937313537Sglebius			/*
938313537Sglebius			 * There's a non-locking shift in effect for
939313537Sglebius			 * this IE.  Count it, so we reset the codeset
940313537Sglebius			 * before the next IE.
941313537Sglebius			 */
942313537Sglebius			non_locking_shift = 2;
943313537Sglebius		} else if (non_locking_shift == 2) {
944313537Sglebius			/*
945313537Sglebius			 * Unshift.
946313537Sglebius			 */
947313537Sglebius			codeset = unshift_codeset;
948313537Sglebius			non_locking_shift = 0;
94932145Spst		}
95032145Spst
951313537Sglebius		/*
952313537Sglebius		 * Get the first octet of the IE.
953313537Sglebius		 */
954313537Sglebius		if (!ND_TTEST(*p)) {
955313537Sglebius			if (!ndo->ndo_vflag) {
956313537Sglebius				ND_PRINT((ndo, ", length %u", olen));
957313537Sglebius			}
958313537Sglebius			goto trunc;
959190207Srpaulo		}
960313537Sglebius		iecode = *p;
961313537Sglebius		p++;
962313537Sglebius		length--;
963190207Srpaulo
964313537Sglebius		/* Single-octet IE? */
965313537Sglebius		if (IE_IS_SINGLE_OCTET(iecode)) {
966313537Sglebius			/*
967313537Sglebius			 * Yes.  Is it a shift?
968313537Sglebius			 */
969313537Sglebius			if (IE_IS_SHIFT(iecode)) {
970313537Sglebius				/*
971313537Sglebius				 * Yes.  Is it locking?
972313537Sglebius				 */
973313537Sglebius				if (IE_SHIFT_IS_LOCKING(iecode)) {
974313537Sglebius					/*
975313537Sglebius					 * Yes.
976313537Sglebius					 */
977313537Sglebius					non_locking_shift = 0;
978313537Sglebius				} else {
979313537Sglebius					/*
980313537Sglebius					 * No.  Remember the current
981313537Sglebius					 * codeset, so we can revert
982313537Sglebius					 * to it after the next IE.
983313537Sglebius					 */
984313537Sglebius					non_locking_shift = 1;
985313537Sglebius					unshift_codeset = codeset;
986313537Sglebius				}
98732145Spst
988313537Sglebius				/*
989313537Sglebius				 * Get the codeset.
990313537Sglebius				 */
991313537Sglebius				codeset = IE_SHIFT_CODESET(iecode);
992313537Sglebius			}
993313537Sglebius		} else {
994313537Sglebius			/*
995313537Sglebius			 * No.  Get the IE length.
996313537Sglebius			 */
997313537Sglebius			if (length == 0 || !ND_TTEST(*p)) {
998313537Sglebius				if (!ndo->ndo_vflag) {
999313537Sglebius					ND_PRINT((ndo, ", length %u", olen));
1000313537Sglebius				}
1001313537Sglebius				goto trunc;
1002313537Sglebius			}
1003313537Sglebius			ielength = *p;
1004313537Sglebius			p++;
1005313537Sglebius			length--;
1006190207Srpaulo
1007313537Sglebius			/* lets do the full IE parsing only in verbose mode
1008313537Sglebius			 * however some IEs (DLCI Status, Link Verify)
1009313537Sglebius			 * are also interesting in non-verbose mode */
1010313537Sglebius			if (ndo->ndo_vflag) {
1011313537Sglebius				ND_PRINT((ndo, "\n\t%s IE (0x%02x), length %u: ",
1012313537Sglebius				    tok2str(fr_q933_ie_codesets[codeset],
1013313537Sglebius					"unknown", iecode),
1014313537Sglebius				    iecode,
1015313537Sglebius				    ielength));
1016313537Sglebius			}
1017162021Ssam
1018313537Sglebius			/* sanity checks */
1019313537Sglebius			if (iecode == 0 || ielength == 0) {
1020313537Sglebius				return;
1021313537Sglebius			}
1022313537Sglebius			if (length < ielength || !ND_TTEST2(*p, ielength)) {
1023313537Sglebius				if (!ndo->ndo_vflag) {
1024313537Sglebius					ND_PRINT((ndo, ", length %u", olen));
1025313537Sglebius				}
1026313537Sglebius				goto trunc;
1027313537Sglebius			}
1028313537Sglebius
1029313537Sglebius			ie_is_known = 0;
1030313537Sglebius			if (fr_q933_print_ie_codeset[codeset] != NULL) {
1031313537Sglebius				ie_is_known = fr_q933_print_ie_codeset[codeset](ndo, iecode, ielength, p);
1032313537Sglebius			}
1033313537Sglebius
1034313537Sglebius			if (ie_is_known) {
1035313537Sglebius				/*
1036313537Sglebius				 * Known IE; do we want to see a hexdump
1037313537Sglebius				 * of it?
1038313537Sglebius				 */
1039313537Sglebius				if (ndo->ndo_vflag > 1) {
1040313537Sglebius					/* Yes. */
1041313537Sglebius					print_unknown_data(ndo, p, "\n\t  ", ielength);
1042313537Sglebius				}
1043313537Sglebius			} else {
1044313537Sglebius				/*
1045313537Sglebius				 * Unknown IE; if we're printing verbosely,
1046313537Sglebius				 * print its content in hex.
1047313537Sglebius				 */
1048313537Sglebius				if (ndo->ndo_vflag >= 1) {
1049313537Sglebius					print_unknown_data(ndo, p, "\n\t", ielength);
1050313537Sglebius				}
1051313537Sglebius			}
1052313537Sglebius
1053313537Sglebius			length -= ielength;
1054313537Sglebius			p += ielength;
1055190207Srpaulo		}
1056146778Ssam	}
1057313537Sglebius	if (!ndo->ndo_vflag) {
1058313537Sglebius	    ND_PRINT((ndo, ", length %u", olen));
1059190207Srpaulo	}
1060313537Sglebius	return;
1061313537Sglebius
1062313537Sglebiustrunc:
1063313537Sglebius	ND_PRINT((ndo, "[|q.933]"));
1064146778Ssam}
1065147904Ssam
1066147904Ssamstatic int
1067313537Sglebiusfr_q933_print_ie_codeset_0_5(netdissect_options *ndo, u_int iecode,
1068313537Sglebius                          u_int ielength, const u_char *p)
1069147904Ssam{
1070147904Ssam        u_int dlci;
1071147904Ssam
1072313537Sglebius        switch (iecode) {
1073147904Ssam
1074147904Ssam        case FR_LMI_ANSI_REPORT_TYPE_IE: /* fall through */
1075147904Ssam        case FR_LMI_CCITT_REPORT_TYPE_IE:
1076313537Sglebius            if (ielength < 1) {
1077313537Sglebius                if (!ndo->ndo_vflag) {
1078313537Sglebius                    ND_PRINT((ndo, ", "));
1079313537Sglebius	        }
1080313537Sglebius                ND_PRINT((ndo, "Invalid REPORT TYPE IE"));
1081313537Sglebius                return 1;
1082313537Sglebius            }
1083276788Sdelphij            if (ndo->ndo_vflag) {
1084276788Sdelphij                ND_PRINT((ndo, "%s (%u)",
1085313537Sglebius                       tok2str(fr_lmi_report_type_ie_values,"unknown",p[0]),
1086313537Sglebius                       p[0]));
1087190207Srpaulo	    }
1088147904Ssam            return 1;
1089147904Ssam
1090147904Ssam        case FR_LMI_ANSI_LINK_VERIFY_IE: /* fall through */
1091147904Ssam        case FR_LMI_CCITT_LINK_VERIFY_IE:
1092147904Ssam        case FR_LMI_ANSI_LINK_VERIFY_IE_91:
1093276788Sdelphij            if (!ndo->ndo_vflag) {
1094276788Sdelphij                ND_PRINT((ndo, ", "));
1095190207Srpaulo	    }
1096313537Sglebius            if (ielength < 2) {
1097313537Sglebius                ND_PRINT((ndo, "Invalid LINK VERIFY IE"));
1098313537Sglebius                return 1;
1099313537Sglebius            }
1100313537Sglebius            ND_PRINT((ndo, "TX Seq: %3d, RX Seq: %3d", p[0], p[1]));
1101147904Ssam            return 1;
1102147904Ssam
1103147904Ssam        case FR_LMI_ANSI_PVC_STATUS_IE: /* fall through */
1104147904Ssam        case FR_LMI_CCITT_PVC_STATUS_IE:
1105276788Sdelphij            if (!ndo->ndo_vflag) {
1106276788Sdelphij                ND_PRINT((ndo, ", "));
1107190207Srpaulo	    }
1108276788Sdelphij            /* now parse the DLCI information element. */
1109313537Sglebius            if ((ielength < 3) ||
1110313537Sglebius                (p[0] & 0x80) ||
1111313537Sglebius                ((ielength == 3) && !(p[1] & 0x80)) ||
1112313537Sglebius                ((ielength == 4) && ((p[1] & 0x80) || !(p[2] & 0x80))) ||
1113313537Sglebius                ((ielength == 5) && ((p[1] & 0x80) || (p[2] & 0x80) ||
1114313537Sglebius                                   !(p[3] & 0x80))) ||
1115313537Sglebius                (ielength > 5) ||
1116313537Sglebius                !(p[ielength - 1] & 0x80)) {
1117313537Sglebius                ND_PRINT((ndo, "Invalid DLCI in PVC STATUS IE"));
1118313537Sglebius                return 1;
1119190207Srpaulo	    }
1120276788Sdelphij
1121313537Sglebius            dlci = ((p[0] & 0x3F) << 4) | ((p[1] & 0x78) >> 3);
1122313537Sglebius            if (ielength == 4) {
1123313537Sglebius                dlci = (dlci << 6) | ((p[2] & 0x7E) >> 1);
1124190207Srpaulo	    }
1125313537Sglebius            else if (ielength == 5) {
1126313537Sglebius                dlci = (dlci << 13) | (p[2] & 0x7F) | ((p[3] & 0x7E) >> 1);
1127190207Srpaulo	    }
1128147904Ssam
1129276788Sdelphij            ND_PRINT((ndo, "DLCI %u: status %s%s", dlci,
1130313537Sglebius                    p[ielength - 1] & 0x8 ? "New, " : "",
1131313537Sglebius                    p[ielength - 1] & 0x2 ? "Active" : "Inactive"));
1132147904Ssam            return 1;
1133147904Ssam	}
1134147904Ssam
1135147904Ssam        return 0;
1136147904Ssam}
1137276788Sdelphij/*
1138276788Sdelphij * Local Variables:
1139276788Sdelphij * c-style: whitesmith
1140276788Sdelphij * c-basic-offset: 8
1141276788Sdelphij * End:
1142276788Sdelphij */
1143