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