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: releng/11.0/contrib/tcpdump/print-fr.c 285275 2015-07-08 16:19:32Z pkelsey $
2232145Spst */
2332145Spst
24276788Sdelphij#define NETDISSECT_REWORKED
25146778Ssam#ifdef HAVE_CONFIG_H
26146778Ssam#include "config.h"
2732145Spst#endif
2832145Spst
29146778Ssam#include <tcpdump-stdinc.h>
3032145Spst
31146778Ssam#include <stdio.h>
32146778Ssam#include <string.h>
3332145Spst
34276788Sdelphij#include "interface.h"
35146778Ssam#include "addrtoname.h"
3632145Spst#include "ethertype.h"
37285275Spkelsey#include "llc.h"
38146778Ssam#include "nlpid.h"
39146778Ssam#include "extract.h"
40146778Ssam#include "oui.h"
4132145Spst
42276788Sdelphijstatic void frf15_print(netdissect_options *ndo, const u_char *, u_int);
4332145Spst
44146778Ssam/*
45146778Ssam * the frame relay header has a variable length
46146778Ssam *
47146778Ssam * the EA bit determines if there is another byte
48146778Ssam * in the header
49146778Ssam *
50146778Ssam * minimum header length is 2 bytes
51146778Ssam * maximum header length is 4 bytes
52146778Ssam *
53146778Ssam *      7    6    5    4    3    2    1    0
54146778Ssam *    +----+----+----+----+----+----+----+----+
55146778Ssam *    |        DLCI (6 bits)        | CR | EA |
56146778Ssam *    +----+----+----+----+----+----+----+----+
57146778Ssam *    |   DLCI (4 bits)   |FECN|BECN| DE | EA |
58146778Ssam *    +----+----+----+----+----+----+----+----+
59146778Ssam *    |           DLCI (7 bits)          | EA |
60146778Ssam *    +----+----+----+----+----+----+----+----+
61146778Ssam *    |        DLCI (6 bits)        |SDLC| EA |
62146778Ssam *    +----+----+----+----+----+----+----+----+
63146778Ssam */
6432145Spst
65146778Ssam#define FR_EA_BIT	0x01
6632145Spst
67146778Ssam#define FR_CR_BIT       0x02000000
68146778Ssam#define FR_DE_BIT	0x00020000
69146778Ssam#define FR_BECN_BIT	0x00040000
70146778Ssam#define FR_FECN_BIT	0x00080000
71146778Ssam#define FR_SDLC_BIT	0x00000002
7232145Spst
73146778Ssam
74276788Sdelphijstatic const struct tok fr_header_flag_values[] = {
75146778Ssam    { FR_CR_BIT, "C!" },
76146778Ssam    { FR_DE_BIT, "DE" },
77146778Ssam    { FR_BECN_BIT, "BECN" },
78146778Ssam    { FR_FECN_BIT, "FECN" },
79146778Ssam    { FR_SDLC_BIT, "sdlcore" },
80146778Ssam    { 0, NULL }
8132145Spst};
8232145Spst
83162021Ssam/* FRF.15 / FRF.16 */
84162021Ssam#define MFR_B_BIT 0x80
85162021Ssam#define MFR_E_BIT 0x40
86162021Ssam#define MFR_C_BIT 0x20
87162021Ssam#define MFR_BEC_MASK    (MFR_B_BIT | MFR_E_BIT | MFR_C_BIT)
88162021Ssam#define MFR_CTRL_FRAME  (MFR_B_BIT | MFR_E_BIT | MFR_C_BIT)
89162021Ssam#define MFR_FRAG_FRAME  (MFR_B_BIT | MFR_E_BIT )
90146778Ssam
91276788Sdelphijstatic const struct tok frf_flag_values[] = {
92162021Ssam    { MFR_B_BIT, "Begin" },
93162021Ssam    { MFR_E_BIT, "End" },
94162021Ssam    { MFR_C_BIT, "Control" },
95162021Ssam    { 0, NULL }
96162021Ssam};
97162021Ssam
98285275Spkelsey/* Finds out Q.922 address length, DLCI and flags. Returns 1 on success,
99285275Spkelsey * 0 on invalid address, -1 on truncated packet
100146778Ssam * save the flags dep. on address length
101146778Ssam */
102285275Spkelseystatic int parse_q922_addr(netdissect_options *ndo,
103285275Spkelsey                           const u_char *p, u_int *dlci,
104285275Spkelsey                           u_int *addr_len, uint8_t *flags, u_int length)
10532145Spst{
106285275Spkelsey	if (!ND_TTEST(p[0]) || length < 1)
107285275Spkelsey		return -1;
108146778Ssam	if ((p[0] & FR_EA_BIT))
109285275Spkelsey		return 0;
110285275Spkelsey
111285275Spkelsey	if (!ND_TTEST(p[1]) || length < 2)
112146778Ssam		return -1;
113146778Ssam	*addr_len = 2;
114146778Ssam	*dlci = ((p[0] & 0xFC) << 2) | ((p[1] & 0xF0) >> 4);
11532145Spst
116146778Ssam        flags[0] = p[0] & 0x02; /* populate the first flag fields */
117146778Ssam        flags[1] = p[1] & 0x0c;
118172686Smlaier        flags[2] = 0;           /* clear the rest of the flags */
119172686Smlaier        flags[3] = 0;
12032145Spst
121146778Ssam	if (p[1] & FR_EA_BIT)
122285275Spkelsey		return 1;	/* 2-byte Q.922 address */
12332145Spst
124146778Ssam	p += 2;
125285275Spkelsey	length -= 2;
126285275Spkelsey	if (!ND_TTEST(p[0]) || length < 1)
127285275Spkelsey		return -1;
128146778Ssam	(*addr_len)++;		/* 3- or 4-byte Q.922 address */
129146778Ssam	if ((p[0] & FR_EA_BIT) == 0) {
130146778Ssam		*dlci = (*dlci << 7) | (p[0] >> 1);
131146778Ssam		(*addr_len)++;	/* 4-byte Q.922 address */
132146778Ssam		p++;
133285275Spkelsey		length--;
134146778Ssam	}
13532145Spst
136285275Spkelsey	if (!ND_TTEST(p[0]) || length < 1)
137285275Spkelsey		return -1;
138146778Ssam	if ((p[0] & FR_EA_BIT) == 0)
139285275Spkelsey		return 0; /* more than 4 bytes of Q.922 address? */
140146778Ssam
141146778Ssam        flags[3] = p[0] & 0x02;
142146778Ssam
143190207Srpaulo        *dlci = (*dlci << 6) | (p[0] >> 2);
144146778Ssam
145285275Spkelsey	return 1;
14632145Spst}
14732145Spst
148285275Spkelseychar *
149285275Spkelseyq922_string(netdissect_options *ndo, const u_char *p, u_int length)
150285275Spkelsey{
151190207Srpaulo
152190207Srpaulo    static u_int dlci, addr_len;
153276788Sdelphij    static uint8_t flags[4];
154190207Srpaulo    static char buffer[sizeof("DLCI xxxxxxxxxx")];
155190207Srpaulo    memset(buffer, 0, sizeof(buffer));
156190207Srpaulo
157285275Spkelsey    if (parse_q922_addr(ndo, p, &dlci, &addr_len, flags, length) == 1){
158190207Srpaulo        snprintf(buffer, sizeof(buffer), "DLCI %u", dlci);
159190207Srpaulo    }
160190207Srpaulo
161190207Srpaulo    return buffer;
162190207Srpaulo}
163190207Srpaulo
164190207Srpaulo
165146778Ssam/* Frame Relay packet structure, with flags and CRC removed
16632145Spst
16732145Spst                  +---------------------------+
16832145Spst                  |       Q.922 Address*      |
16932145Spst                  +--                       --+
17032145Spst                  |                           |
17132145Spst                  +---------------------------+
17232145Spst                  | Control (UI = 0x03)       |
17332145Spst                  +---------------------------+
17432145Spst                  | Optional Pad      (0x00)  |
17532145Spst                  +---------------------------+
17632145Spst                  | NLPID                     |
17732145Spst                  +---------------------------+
17832145Spst                  |             .             |
17932145Spst                  |             .             |
18032145Spst                  |             .             |
18132145Spst                  |           Data            |
18232145Spst                  |             .             |
18332145Spst                  |             .             |
18432145Spst                  +---------------------------+
18532145Spst
18632145Spst           * Q.922 addresses, as presently defined, are two octets and
18732145Spst             contain a 10-bit DLCI.  In some networks Q.922 addresses
18832145Spst             may optionally be increased to three or four octets.
18932145Spst*/
19032145Spst
191146778Ssamstatic void
192276788Sdelphijfr_hdr_print(netdissect_options *ndo,
193276788Sdelphij             int length, u_int addr_len, u_int dlci, uint8_t *flags, uint16_t nlpid)
19432145Spst{
195276788Sdelphij    if (ndo->ndo_qflag) {
196276788Sdelphij        ND_PRINT((ndo, "Q.922, DLCI %u, length %u: ",
197146778Ssam                     dlci,
198276788Sdelphij                     length));
199146778Ssam    } else {
200146778Ssam        if (nlpid <= 0xff) /* if its smaller than 256 then its a NLPID */
201276788Sdelphij            ND_PRINT((ndo, "Q.922, hdr-len %u, DLCI %u, Flags [%s], NLPID %s (0x%02x), length %u: ",
202146778Ssam                         addr_len,
203146778Ssam                         dlci,
204146778Ssam                         bittok2str(fr_header_flag_values, "none", EXTRACT_32BITS(flags)),
205146778Ssam                         tok2str(nlpid_values,"unknown", nlpid),
206146778Ssam                         nlpid,
207276788Sdelphij                         length));
208146778Ssam        else /* must be an ethertype */
209276788Sdelphij            ND_PRINT((ndo, "Q.922, hdr-len %u, DLCI %u, Flags [%s], cisco-ethertype %s (0x%04x), length %u: ",
210146778Ssam                         addr_len,
211146778Ssam                         dlci,
212146778Ssam                         bittok2str(fr_header_flag_values, "none", EXTRACT_32BITS(flags)),
213146778Ssam                         tok2str(ethertype_values, "unknown", nlpid),
214146778Ssam                         nlpid,
215276788Sdelphij                         length));
216146778Ssam    }
21732145Spst}
21832145Spst
219146778Ssamu_int
220276788Sdelphijfr_if_print(netdissect_options *ndo,
221276788Sdelphij            const struct pcap_pkthdr *h, register const u_char *p)
22232145Spst{
22332145Spst	register u_int length = h->len;
22432145Spst	register u_int caplen = h->caplen;
225147904Ssam
226276788Sdelphij        ND_TCHECK2(*p, 4); /* minimum frame header length */
227147904Ssam
228276788Sdelphij        if ((length = fr_print(ndo, p, length)) == 0)
229147904Ssam            return (0);
230147904Ssam        else
231147904Ssam            return length;
232147904Ssam trunc:
233276788Sdelphij        ND_PRINT((ndo, "[|fr]"));
234147904Ssam        return caplen;
235147904Ssam}
236147904Ssam
237147904Ssamu_int
238276788Sdelphijfr_print(netdissect_options *ndo,
239276788Sdelphij         register const u_char *p, u_int length)
240147904Ssam{
241285275Spkelsey	int ret;
242276788Sdelphij	uint16_t extracted_ethertype;
243146778Ssam	u_int dlci;
244146778Ssam	u_int addr_len;
245276788Sdelphij	uint16_t nlpid;
246146778Ssam	u_int hdr_len;
247276788Sdelphij	uint8_t flags[4];
24832145Spst
249285275Spkelsey	ret = parse_q922_addr(ndo, p, &dlci, &addr_len, flags, length);
250285275Spkelsey	if (ret == -1)
251285275Spkelsey		goto trunc;
252285275Spkelsey	if (ret == 0) {
253276788Sdelphij		ND_PRINT((ndo, "Q.922, invalid address"));
254147904Ssam		return 0;
255146778Ssam	}
25632145Spst
257285275Spkelsey	ND_TCHECK(p[addr_len]);
258285275Spkelsey	if (length < addr_len + 1)
259285275Spkelsey		goto trunc;
260146778Ssam
261285275Spkelsey	if (p[addr_len] != LLC_UI && dlci != 0) {
262285275Spkelsey                /*
263285275Spkelsey                 * Let's figure out if we have Cisco-style encapsulation,
264285275Spkelsey                 * with an Ethernet type (Cisco HDLC type?) following the
265285275Spkelsey                 * address.
266285275Spkelsey                 */
267285275Spkelsey		if (!ND_TTEST2(p[addr_len], 2) || length < addr_len + 2) {
268285275Spkelsey                        /* no Ethertype */
269285275Spkelsey                        ND_PRINT((ndo, "UI %02x! ", p[addr_len]));
270285275Spkelsey                } else {
271285275Spkelsey                        extracted_ethertype = EXTRACT_16BITS(p+addr_len);
27232145Spst
273285275Spkelsey                        if (ndo->ndo_eflag)
274285275Spkelsey                                fr_hdr_print(ndo, length, addr_len, dlci,
275285275Spkelsey                                    flags, extracted_ethertype);
276146778Ssam
277285275Spkelsey                        if (ethertype_print(ndo, extracted_ethertype,
278285275Spkelsey                                            p+addr_len+ETHERTYPE_LEN,
279285275Spkelsey                                            length-addr_len-ETHERTYPE_LEN,
280285275Spkelsey                                            length-addr_len-ETHERTYPE_LEN) == 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:
332276788Sdelphij		isoclns_print(ndo, p - 1, length + 1, length + 1); /* OSI printers need the NLPID field */
33332145Spst		break;
334146778Ssam
335146778Ssam	case NLPID_SNAP:
336276788Sdelphij		if (snap_print(ndo, p, length, length, 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
602162021Ssam    flags = p[0]&MFR_BEC_MASK;
603146778Ssam    sequence_num = (p[0]&0x1e)<<7 | p[1];
604146778Ssam
605276788Sdelphij    ND_PRINT((ndo, "FRF.15, seq 0x%03x, Flags [%s],%s Fragmentation, length %u",
606146778Ssam           sequence_num,
607162021Ssam           bittok2str(frf_flag_values,"none",flags),
608162021Ssam           p[0]&FR_FRF15_FRAGTYPE ? "Interface" : "End-to-End",
609276788Sdelphij           length));
610146778Ssam
611146778Ssam/* TODO:
612146778Ssam * depending on all permutations of the B, E and C bit
613146778Ssam * dig as deep as we can - e.g. on the first (B) fragment
614146778Ssam * there is enough payload to print the IP header
615146778Ssam * on non (B) fragments it depends if the fragmentation
616146778Ssam * model is end-to-end or interface based wether we want to print
617146778Ssam * another Q.922 header
618146778Ssam */
619146778Ssam
62032145Spst}
62132145Spst
62232145Spst/*
62332145Spst * Q.933 decoding portion for framerelay specific.
62432145Spst */
62532145Spst
62632145Spst/* Q.933 packet format
627276788Sdelphij                      Format of Other Protocols
62832145Spst                          using Q.933 NLPID
629276788Sdelphij                  +-------------------------------+
630276788Sdelphij                  |        Q.922 Address          |
63132145Spst                  +---------------+---------------+
632276788Sdelphij                  |Control  0x03  | NLPID   0x08  |
633276788Sdelphij                  +---------------+---------------+
63432145Spst                  |          L2 Protocol ID       |
63532145Spst                  | octet 1       |  octet 2      |
63632145Spst                  +-------------------------------+
63732145Spst                  |          L3 Protocol ID       |
63832145Spst                  | octet 2       |  octet 2      |
63932145Spst                  +-------------------------------+
64032145Spst                  |         Protocol Data         |
64132145Spst                  +-------------------------------+
64232145Spst                  | FCS                           |
64332145Spst                  +-------------------------------+
64432145Spst */
64532145Spst
64632145Spst/* L2 (Octet 1)- Call Reference Usually is 0x0 */
64732145Spst
64832145Spst/*
64932145Spst * L2 (Octet 2)- Message Types definition 1 byte long.
65032145Spst */
65132145Spst/* Call Establish */
65232145Spst#define MSG_TYPE_ESC_TO_NATIONAL  0x00
65332145Spst#define MSG_TYPE_ALERT            0x01
65432145Spst#define MSG_TYPE_CALL_PROCEEDING  0x02
65532145Spst#define MSG_TYPE_CONNECT          0x07
65632145Spst#define MSG_TYPE_CONNECT_ACK      0x0F
65732145Spst#define MSG_TYPE_PROGRESS         0x03
65832145Spst#define MSG_TYPE_SETUP            0x05
65932145Spst/* Call Clear */
66032145Spst#define MSG_TYPE_DISCONNECT       0x45
66132145Spst#define MSG_TYPE_RELEASE          0x4D
66232145Spst#define MSG_TYPE_RELEASE_COMPLETE 0x5A
66332145Spst#define MSG_TYPE_RESTART          0x46
66432145Spst#define MSG_TYPE_RESTART_ACK      0x4E
66532145Spst/* Status */
66632145Spst#define MSG_TYPE_STATUS           0x7D
66732145Spst#define MSG_TYPE_STATUS_ENQ       0x75
66832145Spst
669276788Sdelphijstatic const struct tok fr_q933_msg_values[] = {
670146778Ssam    { MSG_TYPE_ESC_TO_NATIONAL, "ESC to National" },
671146778Ssam    { MSG_TYPE_ALERT, "Alert" },
672146778Ssam    { MSG_TYPE_CALL_PROCEEDING, "Call proceeding" },
673146778Ssam    { MSG_TYPE_CONNECT, "Connect" },
674146778Ssam    { MSG_TYPE_CONNECT_ACK, "Connect ACK" },
675146778Ssam    { MSG_TYPE_PROGRESS, "Progress" },
676146778Ssam    { MSG_TYPE_SETUP, "Setup" },
677146778Ssam    { MSG_TYPE_DISCONNECT, "Disconnect" },
678146778Ssam    { MSG_TYPE_RELEASE, "Release" },
679146778Ssam    { MSG_TYPE_RELEASE_COMPLETE, "Release Complete" },
680146778Ssam    { MSG_TYPE_RESTART, "Restart" },
681146778Ssam    { MSG_TYPE_RESTART_ACK, "Restart ACK" },
682146778Ssam    { MSG_TYPE_STATUS, "Status Reply" },
683146778Ssam    { MSG_TYPE_STATUS_ENQ, "Status Enquiry" },
684146778Ssam    { 0, NULL }
685146778Ssam};
68632145Spst
687146778Ssam#define MSG_ANSI_LOCKING_SHIFT	0x95
688146778Ssam
689146778Ssam#define FR_LMI_ANSI_REPORT_TYPE_IE	0x01
690146778Ssam#define FR_LMI_ANSI_LINK_VERIFY_IE_91	0x19 /* details? */
691146778Ssam#define FR_LMI_ANSI_LINK_VERIFY_IE	0x03
692146778Ssam#define FR_LMI_ANSI_PVC_STATUS_IE	0x07
693146778Ssam
694146778Ssam#define FR_LMI_CCITT_REPORT_TYPE_IE	0x51
695146778Ssam#define FR_LMI_CCITT_LINK_VERIFY_IE	0x53
696146778Ssam#define FR_LMI_CCITT_PVC_STATUS_IE	0x57
697146778Ssam
698276788Sdelphijstatic const struct tok fr_q933_ie_values_codeset5[] = {
699146778Ssam    { FR_LMI_ANSI_REPORT_TYPE_IE, "ANSI Report Type" },
700146778Ssam    { FR_LMI_ANSI_LINK_VERIFY_IE_91, "ANSI Link Verify" },
701146778Ssam    { FR_LMI_ANSI_LINK_VERIFY_IE, "ANSI Link Verify" },
702146778Ssam    { FR_LMI_ANSI_PVC_STATUS_IE, "ANSI PVC Status" },
703146778Ssam    { FR_LMI_CCITT_REPORT_TYPE_IE, "CCITT Report Type" },
704146778Ssam    { FR_LMI_CCITT_LINK_VERIFY_IE, "CCITT Link Verify" },
705146778Ssam    { FR_LMI_CCITT_PVC_STATUS_IE, "CCITT PVC Status" },
706146778Ssam    { 0, NULL }
70732145Spst};
70832145Spst
709146778Ssam#define FR_LMI_REPORT_TYPE_IE_FULL_STATUS 0
710146778Ssam#define FR_LMI_REPORT_TYPE_IE_LINK_VERIFY 1
711146778Ssam#define FR_LMI_REPORT_TYPE_IE_ASYNC_PVC   2
71232145Spst
713276788Sdelphijstatic const struct tok fr_lmi_report_type_ie_values[] = {
714146778Ssam    { FR_LMI_REPORT_TYPE_IE_FULL_STATUS, "Full Status" },
715146778Ssam    { FR_LMI_REPORT_TYPE_IE_LINK_VERIFY, "Link verify" },
716146778Ssam    { FR_LMI_REPORT_TYPE_IE_ASYNC_PVC, "Async PVC Status" },
717146778Ssam    { 0, NULL }
718146778Ssam};
71932145Spst
720162021Ssam/* array of 16 codepages - currently we only support codepage 1,5 */
721276788Sdelphijstatic const struct tok *fr_q933_ie_codesets[] = {
722146778Ssam    NULL,
723162021Ssam    fr_q933_ie_values_codeset5,
724146778Ssam    NULL,
725146778Ssam    NULL,
726146778Ssam    NULL,
727146778Ssam    fr_q933_ie_values_codeset5,
728146778Ssam    NULL,
729146778Ssam    NULL,
730146778Ssam    NULL,
731146778Ssam    NULL,
732146778Ssam    NULL,
733146778Ssam    NULL,
734146778Ssam    NULL,
735146778Ssam    NULL,
736146778Ssam    NULL,
737146778Ssam    NULL
73832145Spst};
73932145Spst
740276788Sdelphijstatic int fr_q933_print_ie_codeset5(netdissect_options *ndo,
741276788Sdelphij    const struct ie_tlv_header_t  *ie_p, const u_char *p);
742147904Ssam
743276788Sdelphijtypedef int (*codeset_pr_func_t)(netdissect_options *,
744276788Sdelphij    const struct ie_tlv_header_t  *ie_p, const u_char *p);
745147904Ssam
746162021Ssam/* array of 16 codepages - currently we only support codepage 1,5 */
747276788Sdelphijstatic const codeset_pr_func_t fr_q933_print_ie_codeset[] = {
748147904Ssam    NULL,
749162021Ssam    fr_q933_print_ie_codeset5,
750147904Ssam    NULL,
751147904Ssam    NULL,
752147904Ssam    NULL,
753147904Ssam    fr_q933_print_ie_codeset5,
754147904Ssam    NULL,
755147904Ssam    NULL,
756147904Ssam    NULL,
757147904Ssam    NULL,
758147904Ssam    NULL,
759147904Ssam    NULL,
760147904Ssam    NULL,
761147904Ssam    NULL,
762147904Ssam    NULL,
763147904Ssam    NULL
764147904Ssam};
765147904Ssam
76632145Spstvoid
767276788Sdelphijq933_print(netdissect_options *ndo,
768276788Sdelphij           const u_char *p, u_int length)
76932145Spst{
77032145Spst	const u_char *ptemp = p;
771162021Ssam	struct ie_tlv_header_t  *ie_p;
772146778Ssam        int olen;
773146778Ssam	int is_ansi = 0;
774147904Ssam        u_int codeset;
775162021Ssam        u_int ie_is_known = 0;
776146778Ssam
777146778Ssam	if (length < 9) {	/* shortest: Q.933a LINK VERIFY */
778276788Sdelphij		ND_PRINT((ndo, "[|q.933]"));
779146778Ssam		return;
780146778Ssam	}
781146778Ssam
782146778Ssam        codeset = p[2]&0x0f;   /* extract the codeset */
783146778Ssam
784190207Srpaulo	if (p[2] == MSG_ANSI_LOCKING_SHIFT) {
785190207Srpaulo	        is_ansi = 1;
786190207Srpaulo	}
78732145Spst
788276788Sdelphij        ND_PRINT((ndo, "%s", ndo->ndo_eflag ? "" : "Q.933, "));
789276788Sdelphij
79032145Spst	/* printing out header part */
791276788Sdelphij	ND_PRINT((ndo, "%s, codeset %u", is_ansi ? "ANSI" : "CCITT", codeset));
792146778Ssam
793190207Srpaulo	if (p[0]) {
794276788Sdelphij	        ND_PRINT((ndo, ", Call Ref: 0x%02x", p[0]));
795190207Srpaulo	}
796276788Sdelphij        if (ndo->ndo_vflag) {
797276788Sdelphij                ND_PRINT((ndo, ", %s (0x%02x), length %u",
798190207Srpaulo		       tok2str(fr_q933_msg_values,
799190207Srpaulo			       "unknown message", p[1]),
800190207Srpaulo		       p[1],
801276788Sdelphij		       length));
802190207Srpaulo        } else {
803276788Sdelphij                ND_PRINT((ndo, ", %s",
804190207Srpaulo		       tok2str(fr_q933_msg_values,
805276788Sdelphij			       "unknown message 0x%02x", p[1])));
806190207Srpaulo	}
807146778Ssam
808146778Ssam        olen = length; /* preserve the original length for non verbose mode */
809146778Ssam
810146778Ssam	if (length < (u_int)(2 - is_ansi)) {
811276788Sdelphij		ND_PRINT((ndo, "[|q.933]"));
812146778Ssam		return;
81332145Spst	}
814190207Srpaulo	length -= 2 + is_ansi;
815146778Ssam	ptemp += 2 + is_ansi;
816276788Sdelphij
81732145Spst	/* Loop through the rest of IE */
818190207Srpaulo	while (length > sizeof(struct ie_tlv_header_t)) {
819162021Ssam		ie_p = (struct ie_tlv_header_t  *)ptemp;
820190207Srpaulo		if (length < sizeof(struct ie_tlv_header_t) ||
821190207Srpaulo		    length < sizeof(struct ie_tlv_header_t) + ie_p->ie_len) {
822276788Sdelphij                    if (ndo->ndo_vflag) { /* not bark if there is just a trailer */
823276788Sdelphij                        ND_PRINT((ndo, "\n[|q.933]"));
824190207Srpaulo                    } else {
825276788Sdelphij                        ND_PRINT((ndo, ", length %u", olen));
826190207Srpaulo		    }
827146778Ssam                    return;
82832145Spst		}
82932145Spst
830146778Ssam                /* lets do the full IE parsing only in verbose mode
831146778Ssam                 * however some IEs (DLCI Status, Link Verify)
832190207Srpaulo                 * are also interestting in non-verbose mode */
833276788Sdelphij                if (ndo->ndo_vflag) {
834276788Sdelphij                    ND_PRINT((ndo, "\n\t%s IE (0x%02x), length %u: ",
835190207Srpaulo                           tok2str(fr_q933_ie_codesets[codeset],
836190207Srpaulo				   "unknown", ie_p->ie_type),
837162021Ssam                           ie_p->ie_type,
838276788Sdelphij                           ie_p->ie_len));
839190207Srpaulo		}
840190207Srpaulo
841162021Ssam                /* sanity check */
842190207Srpaulo                if (ie_p->ie_type == 0 || ie_p->ie_len == 0) {
843162021Ssam                    return;
844190207Srpaulo		}
84532145Spst
846190207Srpaulo                if (fr_q933_print_ie_codeset[codeset] != NULL) {
847276788Sdelphij                    ie_is_known = fr_q933_print_ie_codeset[codeset](ndo, ie_p, ptemp);
848276788Sdelphij		}
849190207Srpaulo
850276788Sdelphij                if (ndo->ndo_vflag >= 1 && !ie_is_known) {
851276788Sdelphij                    print_unknown_data(ndo, ptemp+2, "\n\t", ie_p->ie_len);
852190207Srpaulo		}
853162021Ssam
854146778Ssam                /* do we want to see a hexdump of the IE ? */
855276788Sdelphij                if (ndo->ndo_vflag> 1 && ie_is_known) {
856276788Sdelphij                    print_unknown_data(ndo, ptemp+2, "\n\t  ", ie_p->ie_len);
857190207Srpaulo		}
85832145Spst
859146778Ssam		length = length - ie_p->ie_len - 2;
860146778Ssam		ptemp = ptemp + ie_p->ie_len + 2;
861146778Ssam	}
862276788Sdelphij        if (!ndo->ndo_vflag) {
863276788Sdelphij            ND_PRINT((ndo, ", length %u", olen));
864190207Srpaulo	}
865146778Ssam}
866147904Ssam
867147904Ssamstatic int
868276788Sdelphijfr_q933_print_ie_codeset5(netdissect_options *ndo,
869276788Sdelphij                          const struct ie_tlv_header_t  *ie_p, const u_char *p)
870147904Ssam{
871147904Ssam        u_int dlci;
872147904Ssam
873162021Ssam        switch (ie_p->ie_type) {
874147904Ssam
875147904Ssam        case FR_LMI_ANSI_REPORT_TYPE_IE: /* fall through */
876147904Ssam        case FR_LMI_CCITT_REPORT_TYPE_IE:
877276788Sdelphij            if (ndo->ndo_vflag) {
878276788Sdelphij                ND_PRINT((ndo, "%s (%u)",
879147904Ssam                       tok2str(fr_lmi_report_type_ie_values,"unknown",p[2]),
880276788Sdelphij                       p[2]));
881190207Srpaulo	    }
882147904Ssam            return 1;
883147904Ssam
884147904Ssam        case FR_LMI_ANSI_LINK_VERIFY_IE: /* fall through */
885147904Ssam        case FR_LMI_CCITT_LINK_VERIFY_IE:
886147904Ssam        case FR_LMI_ANSI_LINK_VERIFY_IE_91:
887276788Sdelphij            if (!ndo->ndo_vflag) {
888276788Sdelphij                ND_PRINT((ndo, ", "));
889190207Srpaulo	    }
890276788Sdelphij            ND_PRINT((ndo, "TX Seq: %3d, RX Seq: %3d", p[2], p[3]));
891147904Ssam            return 1;
892147904Ssam
893147904Ssam        case FR_LMI_ANSI_PVC_STATUS_IE: /* fall through */
894147904Ssam        case FR_LMI_CCITT_PVC_STATUS_IE:
895276788Sdelphij            if (!ndo->ndo_vflag) {
896276788Sdelphij                ND_PRINT((ndo, ", "));
897190207Srpaulo	    }
898276788Sdelphij            /* now parse the DLCI information element. */
899147904Ssam            if ((ie_p->ie_len < 3) ||
900147904Ssam                (p[2] & 0x80) ||
901147904Ssam                ((ie_p->ie_len == 3) && !(p[3] & 0x80)) ||
902147904Ssam                ((ie_p->ie_len == 4) && ((p[3] & 0x80) || !(p[4] & 0x80))) ||
903147904Ssam                ((ie_p->ie_len == 5) && ((p[3] & 0x80) || (p[4] & 0x80) ||
904147904Ssam                                   !(p[5] & 0x80))) ||
905147904Ssam                (ie_p->ie_len > 5) ||
906190207Srpaulo                !(p[ie_p->ie_len + 1] & 0x80)) {
907276788Sdelphij                ND_PRINT((ndo, "Invalid DLCI IE"));
908190207Srpaulo	    }
909276788Sdelphij
910147904Ssam            dlci = ((p[2] & 0x3F) << 4) | ((p[3] & 0x78) >> 3);
911190207Srpaulo            if (ie_p->ie_len == 4) {
912147904Ssam                dlci = (dlci << 6) | ((p[4] & 0x7E) >> 1);
913190207Srpaulo	    }
914190207Srpaulo            else if (ie_p->ie_len == 5) {
915147904Ssam                dlci = (dlci << 13) | (p[4] & 0x7F) | ((p[5] & 0x7E) >> 1);
916190207Srpaulo	    }
917147904Ssam
918276788Sdelphij            ND_PRINT((ndo, "DLCI %u: status %s%s", dlci,
919147904Ssam                    p[ie_p->ie_len + 1] & 0x8 ? "New, " : "",
920276788Sdelphij                    p[ie_p->ie_len + 1] & 0x2 ? "Active" : "Inactive"));
921147904Ssam            return 1;
922147904Ssam	}
923147904Ssam
924147904Ssam        return 0;
925147904Ssam}
926276788Sdelphij/*
927276788Sdelphij * Local Variables:
928276788Sdelphij * c-style: whitesmith
929276788Sdelphij * c-basic-offset: 8
930276788Sdelphij * End:
931276788Sdelphij */
932