xref: /netbsd-src/external/bsd/tcpdump/dist/print-fr.c (revision 26ba0b503b498a5194a71ac319838b7f5497f3fe)
10f74e101Schristos /*
20f74e101Schristos  * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996
30f74e101Schristos  *	The Regents of the University of California.  All rights reserved.
40f74e101Schristos  *
50f74e101Schristos  * Redistribution and use in source and binary forms, with or without
60f74e101Schristos  * modification, are permitted provided that: (1) source code distributions
70f74e101Schristos  * retain the above copyright notice and this paragraph in its entirety, (2)
80f74e101Schristos  * distributions including binary code include the above copyright notice and
90f74e101Schristos  * this paragraph in its entirety in the documentation or other materials
100f74e101Schristos  * provided with the distribution, and (3) all advertising materials mentioning
110f74e101Schristos  * features or use of this software display the following acknowledgement:
120f74e101Schristos  * ``This product includes software developed by the University of California,
130f74e101Schristos  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
140f74e101Schristos  * the University nor the names of its contributors may be used to endorse
150f74e101Schristos  * or promote products derived from this software without specific prior
160f74e101Schristos  * written permission.
170f74e101Schristos  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
180f74e101Schristos  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
190f74e101Schristos  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
200f74e101Schristos  */
210f74e101Schristos 
2211b3aaa1Schristos #include <sys/cdefs.h>
230f74e101Schristos #ifndef lint
24*26ba0b50Schristos __RCSID("$NetBSD: print-fr.c,v 1.12 2024/09/02 16:15:31 christos Exp $");
250f74e101Schristos #endif
260f74e101Schristos 
27dc860a36Sspz /* \summary: Frame Relay printer */
28dc860a36Sspz 
29c74ad251Schristos #include <config.h>
300f74e101Schristos 
31c74ad251Schristos #include "netdissect-stdinc.h"
320f74e101Schristos 
330f74e101Schristos #include <stdio.h>
340f74e101Schristos #include <string.h>
350f74e101Schristos 
36fdccd7e4Schristos #include "netdissect.h"
37b3a00663Schristos #include "addrtoname.h"
380f74e101Schristos #include "ethertype.h"
39ba2ff121Schristos #include "llc.h"
400f74e101Schristos #include "nlpid.h"
410f74e101Schristos #include "extract.h"
420f74e101Schristos 
43b3a00663Schristos static void frf15_print(netdissect_options *ndo, const u_char *, u_int);
440f74e101Schristos 
450f74e101Schristos /*
460f74e101Schristos  * the frame relay header has a variable length
470f74e101Schristos  *
480f74e101Schristos  * the EA bit determines if there is another byte
490f74e101Schristos  * in the header
500f74e101Schristos  *
510f74e101Schristos  * minimum header length is 2 bytes
520f74e101Schristos  * maximum header length is 4 bytes
530f74e101Schristos  *
540f74e101Schristos  *      7    6    5    4    3    2    1    0
550f74e101Schristos  *    +----+----+----+----+----+----+----+----+
560f74e101Schristos  *    |        DLCI (6 bits)        | CR | EA |
570f74e101Schristos  *    +----+----+----+----+----+----+----+----+
580f74e101Schristos  *    |   DLCI (4 bits)   |FECN|BECN| DE | EA |
590f74e101Schristos  *    +----+----+----+----+----+----+----+----+
600f74e101Schristos  *    |           DLCI (7 bits)          | EA |
610f74e101Schristos  *    +----+----+----+----+----+----+----+----+
620f74e101Schristos  *    |        DLCI (6 bits)        |SDLC| EA |
630f74e101Schristos  *    +----+----+----+----+----+----+----+----+
640f74e101Schristos  */
650f74e101Schristos 
660f74e101Schristos #define FR_EA_BIT	0x01
670f74e101Schristos 
680f74e101Schristos #define FR_CR_BIT       0x02000000
690f74e101Schristos #define FR_DE_BIT	0x00020000
700f74e101Schristos #define FR_BECN_BIT	0x00040000
710f74e101Schristos #define FR_FECN_BIT	0x00080000
720f74e101Schristos #define FR_SDLC_BIT	0x00000002
730f74e101Schristos 
740f74e101Schristos 
75870189d2Schristos static const struct tok fr_header_flag_values[] = {
760f74e101Schristos     { FR_CR_BIT, "C!" },
770f74e101Schristos     { FR_DE_BIT, "DE" },
780f74e101Schristos     { FR_BECN_BIT, "BECN" },
790f74e101Schristos     { FR_FECN_BIT, "FECN" },
800f74e101Schristos     { FR_SDLC_BIT, "sdlcore" },
810f74e101Schristos     { 0, NULL }
820f74e101Schristos };
830f74e101Schristos 
840f74e101Schristos /* FRF.15 / FRF.16 */
850f74e101Schristos #define MFR_B_BIT 0x80
860f74e101Schristos #define MFR_E_BIT 0x40
870f74e101Schristos #define MFR_C_BIT 0x20
880f74e101Schristos #define MFR_BEC_MASK    (MFR_B_BIT | MFR_E_BIT | MFR_C_BIT)
890f74e101Schristos #define MFR_CTRL_FRAME  (MFR_B_BIT | MFR_E_BIT | MFR_C_BIT)
900f74e101Schristos #define MFR_FRAG_FRAME  (MFR_B_BIT | MFR_E_BIT )
910f74e101Schristos 
92870189d2Schristos static const struct tok frf_flag_values[] = {
930f74e101Schristos     { MFR_B_BIT, "Begin" },
940f74e101Schristos     { MFR_E_BIT, "End" },
950f74e101Schristos     { MFR_C_BIT, "Control" },
960f74e101Schristos     { 0, NULL }
970f74e101Schristos };
980f74e101Schristos 
99ba2ff121Schristos /* Finds out Q.922 address length, DLCI and flags. Returns 1 on success,
100ba2ff121Schristos  * 0 on invalid address, -1 on truncated packet
1010f74e101Schristos  * save the flags dep. on address length
1020f74e101Schristos  */
103c74ad251Schristos static int parse_q922_header(netdissect_options *ndo,
104ba2ff121Schristos                            const u_char *p, u_int *dlci,
105c74ad251Schristos                            u_int *addr_len, uint32_t *flags, u_int length)
1060f74e101Schristos {
107c74ad251Schristos 	if (!ND_TTEST_1(p) || length < 1)
1080f74e101Schristos 		return -1;
109c74ad251Schristos 	if ((GET_U_1(p) & FR_EA_BIT))
110ba2ff121Schristos 		return 0;
1110f74e101Schristos 
112c74ad251Schristos 	if (!ND_TTEST_1(p + 1) || length < 2)
113ba2ff121Schristos 		return -1;
1140f74e101Schristos 	*addr_len = 2;
115c74ad251Schristos 	*dlci = ((GET_U_1(p) & 0xFC) << 2) | ((GET_U_1(p + 1) & 0xF0) >> 4);
1160f74e101Schristos 
117c74ad251Schristos 	*flags = ((GET_U_1(p) & 0x02) << 24) |	/* CR flag */
118c74ad251Schristos 		 ((GET_U_1(p + 1) & 0x0e) << 16);	/* FECN,BECN,DE flags */
1190f74e101Schristos 
120c74ad251Schristos 	if (GET_U_1(p + 1) & FR_EA_BIT)
121ba2ff121Schristos 		return 1;	/* 2-byte Q.922 address */
1220f74e101Schristos 
1230f74e101Schristos 	p += 2;
124ba2ff121Schristos 	length -= 2;
125c74ad251Schristos 	if (!ND_TTEST_1(p) || length < 1)
126ba2ff121Schristos 		return -1;
1270f74e101Schristos 	(*addr_len)++;		/* 3- or 4-byte Q.922 address */
128c74ad251Schristos 	if ((GET_U_1(p) & FR_EA_BIT) == 0) {
129c74ad251Schristos 		*dlci = (*dlci << 7) | (GET_U_1(p) >> 1);
1300f74e101Schristos 		(*addr_len)++;	/* 4-byte Q.922 address */
1310f74e101Schristos 		p++;
132ba2ff121Schristos 		length--;
1330f74e101Schristos 	}
1340f74e101Schristos 
135c74ad251Schristos 	if (!ND_TTEST_1(p) || length < 1)
136ba2ff121Schristos 		return -1;
137c74ad251Schristos 	if ((GET_U_1(p) & FR_EA_BIT) == 0)
138ba2ff121Schristos 		return 0; /* more than 4 bytes of Q.922 address? */
1390f74e101Schristos 
140c74ad251Schristos 	*flags = *flags | (GET_U_1(p) & 0x02);	/* SDLC flag */
1410f74e101Schristos 
142c74ad251Schristos         *dlci = (*dlci << 6) | (GET_U_1(p) >> 2);
1430f74e101Schristos 
144ba2ff121Schristos 	return 1;
1450f74e101Schristos }
1460f74e101Schristos 
147c74ad251Schristos const char *
148ba2ff121Schristos q922_string(netdissect_options *ndo, const u_char *p, u_int length)
149ba2ff121Schristos {
1500f74e101Schristos 
1510f74e101Schristos     static u_int dlci, addr_len;
152c74ad251Schristos     static uint32_t flags;
153c74ad251Schristos     static char buffer[sizeof("parse_q922_header() returned XXXXXXXXXXX")];
154c74ad251Schristos     int ret;
1550f74e101Schristos     memset(buffer, 0, sizeof(buffer));
1560f74e101Schristos 
157c74ad251Schristos     ret = parse_q922_header(ndo, p, &dlci, &addr_len, &flags, length);
158c74ad251Schristos     if (ret == 1) {
1590f74e101Schristos         snprintf(buffer, sizeof(buffer), "DLCI %u", dlci);
1600f74e101Schristos         return buffer;
161c74ad251Schristos     } else if (ret == 0) {
162c74ad251Schristos         return "<Invalid DLCI>";
163c74ad251Schristos     } else if (ret == -1) {
164c74ad251Schristos         return "<Truncated>";
165c74ad251Schristos     } else {
166c74ad251Schristos         snprintf(buffer, sizeof(buffer), "parse_q922_header() returned %d", ret);
167c74ad251Schristos         return buffer;
168c74ad251Schristos     }
1690f74e101Schristos }
1700f74e101Schristos 
1710f74e101Schristos 
1720f74e101Schristos /* Frame Relay packet structure, with flags and CRC removed
1730f74e101Schristos 
1740f74e101Schristos                   +---------------------------+
1750f74e101Schristos                   |       Q.922 Address*      |
1760f74e101Schristos                   +--                       --+
1770f74e101Schristos                   |                           |
1780f74e101Schristos                   +---------------------------+
1790f74e101Schristos                   | Control (UI = 0x03)       |
1800f74e101Schristos                   +---------------------------+
1810f74e101Schristos                   | Optional Pad      (0x00)  |
1820f74e101Schristos                   +---------------------------+
1830f74e101Schristos                   | NLPID                     |
1840f74e101Schristos                   +---------------------------+
1850f74e101Schristos                   |             .             |
1860f74e101Schristos                   |             .             |
1870f74e101Schristos                   |             .             |
1880f74e101Schristos                   |           Data            |
1890f74e101Schristos                   |             .             |
1900f74e101Schristos                   |             .             |
1910f74e101Schristos                   +---------------------------+
1920f74e101Schristos 
1930f74e101Schristos            * Q.922 addresses, as presently defined, are two octets and
1940f74e101Schristos              contain a 10-bit DLCI.  In some networks Q.922 addresses
1950f74e101Schristos              may optionally be increased to three or four octets.
1960f74e101Schristos */
1970f74e101Schristos 
1980f74e101Schristos static void
199c74ad251Schristos fr_hdr_print(netdissect_options *ndo, int length, u_int addr_len,
200c74ad251Schristos 	     u_int dlci, uint32_t flags, uint16_t nlpid)
2010f74e101Schristos {
202b3a00663Schristos     if (ndo->ndo_qflag) {
203c74ad251Schristos         ND_PRINT("Q.922, DLCI %u, length %u: ",
2040f74e101Schristos                      dlci,
205c74ad251Schristos                      length);
2060f74e101Schristos     } else {
2070f74e101Schristos         if (nlpid <= 0xff) /* if its smaller than 256 then its a NLPID */
208c74ad251Schristos             ND_PRINT("Q.922, hdr-len %u, DLCI %u, Flags [%s], NLPID %s (0x%02x), length %u: ",
2090f74e101Schristos                          addr_len,
2100f74e101Schristos                          dlci,
211c74ad251Schristos                          bittok2str(fr_header_flag_values, "none", flags),
2120f74e101Schristos                          tok2str(nlpid_values,"unknown", nlpid),
2130f74e101Schristos                          nlpid,
214c74ad251Schristos                          length);
2150f74e101Schristos         else /* must be an ethertype */
216c74ad251Schristos             ND_PRINT("Q.922, hdr-len %u, DLCI %u, Flags [%s], cisco-ethertype %s (0x%04x), length %u: ",
2170f74e101Schristos                          addr_len,
2180f74e101Schristos                          dlci,
219c74ad251Schristos                          bittok2str(fr_header_flag_values, "none", flags),
2200f74e101Schristos                          tok2str(ethertype_values, "unknown", nlpid),
2210f74e101Schristos                          nlpid,
222c74ad251Schristos                          length);
2230f74e101Schristos     }
2240f74e101Schristos }
2250f74e101Schristos 
226c74ad251Schristos /* Frame Relay */
227c74ad251Schristos void
228b3a00663Schristos fr_if_print(netdissect_options *ndo,
229c74ad251Schristos             const struct pcap_pkthdr *h, const u_char *p)
2300f74e101Schristos {
231c74ad251Schristos 	u_int length = h->len;
232c74ad251Schristos 	u_int caplen = h->caplen;
2330f74e101Schristos 
234c74ad251Schristos 	ndo->ndo_protocol = "fr";
235c74ad251Schristos 	if (caplen < 4) {	/* minimum frame header length */
236c74ad251Schristos 		nd_print_trunc(ndo);
237c74ad251Schristos 		ndo->ndo_ll_hdr_len += caplen;
238c74ad251Schristos 		return;
239c74ad251Schristos 	}
2400f74e101Schristos 
241c74ad251Schristos 	ndo->ndo_ll_hdr_len += fr_print(ndo, p, length);
2420f74e101Schristos }
2430f74e101Schristos 
2440f74e101Schristos u_int
245b3a00663Schristos fr_print(netdissect_options *ndo,
246c74ad251Schristos          const u_char *p, u_int length)
2470f74e101Schristos {
248ba2ff121Schristos 	int ret;
249b3a00663Schristos 	uint16_t extracted_ethertype;
2500f74e101Schristos 	u_int dlci;
2510f74e101Schristos 	u_int addr_len;
252b3a00663Schristos 	uint16_t nlpid;
2530f74e101Schristos 	u_int hdr_len;
254c74ad251Schristos 	uint32_t flags;
2550f74e101Schristos 
256c74ad251Schristos 	ndo->ndo_protocol = "fr";
257c74ad251Schristos 	ret = parse_q922_header(ndo, p, &dlci, &addr_len, &flags, length);
258ba2ff121Schristos 	if (ret == -1)
259ba2ff121Schristos 		goto trunc;
260ba2ff121Schristos 	if (ret == 0) {
261c74ad251Schristos 		ND_PRINT("Q.922, invalid address");
2620f74e101Schristos 		return 0;
2630f74e101Schristos 	}
2640f74e101Schristos 
265c74ad251Schristos 	ND_TCHECK_1(p + addr_len);
266ba2ff121Schristos 	if (length < addr_len + 1)
267ba2ff121Schristos 		goto trunc;
2680f74e101Schristos 
269c74ad251Schristos 	if (GET_U_1(p + addr_len) != LLC_UI && dlci != 0) {
270ba2ff121Schristos                 /*
271ba2ff121Schristos                  * Let's figure out if we have Cisco-style encapsulation,
272ba2ff121Schristos                  * with an Ethernet type (Cisco HDLC type?) following the
273ba2ff121Schristos                  * address.
274ba2ff121Schristos                  */
275c74ad251Schristos 		if (!ND_TTEST_2(p + addr_len) || length < addr_len + 2) {
276ba2ff121Schristos                         /* no Ethertype */
277c74ad251Schristos                         ND_PRINT("UI %02x! ", GET_U_1(p + addr_len));
278ba2ff121Schristos                 } else {
279c74ad251Schristos                         extracted_ethertype = GET_BE_U_2(p + addr_len);
2800f74e101Schristos 
281b3a00663Schristos                         if (ndo->ndo_eflag)
282ba2ff121Schristos                                 fr_hdr_print(ndo, length, addr_len, dlci,
283ba2ff121Schristos                                     flags, extracted_ethertype);
2840f74e101Schristos 
285b3a00663Schristos                         if (ethertype_print(ndo, extracted_ethertype,
2860f74e101Schristos                                             p+addr_len+ETHERTYPE_LEN,
2870f74e101Schristos                                             length-addr_len-ETHERTYPE_LEN,
288c74ad251Schristos                                             ND_BYTES_AVAILABLE_AFTER(p)-addr_len-ETHERTYPE_LEN,
289dc860a36Sspz                                             NULL, NULL) == 0)
2900f74e101Schristos                                 /* ether_type not known, probably it wasn't one */
291c74ad251Schristos                                 ND_PRINT("UI %02x! ", GET_U_1(p + addr_len));
2920f74e101Schristos                         else
293ba2ff121Schristos                                 return addr_len + 2;
294ba2ff121Schristos                 }
2950f74e101Schristos         }
2960f74e101Schristos 
297c74ad251Schristos 	ND_TCHECK_1(p + addr_len + 1);
298ba2ff121Schristos 	if (length < addr_len + 2)
299ba2ff121Schristos 		goto trunc;
300ba2ff121Schristos 
301c74ad251Schristos 	if (GET_U_1(p + addr_len + 1) == 0) {
302ba2ff121Schristos 		/*
303ba2ff121Schristos 		 * Assume a pad byte after the control (UI) byte.
304ba2ff121Schristos 		 * A pad byte should only be used with 3-byte Q.922.
305ba2ff121Schristos 		 */
3060f74e101Schristos 		if (addr_len != 3)
307c74ad251Schristos 			ND_PRINT("Pad! ");
308ba2ff121Schristos 		hdr_len = addr_len + 1 /* UI */ + 1 /* pad */ + 1 /* NLPID */;
309ba2ff121Schristos 	} else {
310ba2ff121Schristos 		/*
311ba2ff121Schristos 		 * Not a pad byte.
312ba2ff121Schristos 		 * A pad byte should be used with 3-byte Q.922.
313ba2ff121Schristos 		 */
314ba2ff121Schristos 		if (addr_len == 3)
315c74ad251Schristos 			ND_PRINT("No pad! ");
316ba2ff121Schristos 		hdr_len = addr_len + 1 /* UI */ + 1 /* NLPID */;
317ba2ff121Schristos 	}
3180f74e101Schristos 
319c74ad251Schristos         ND_TCHECK_1(p + hdr_len - 1);
320ba2ff121Schristos 	if (length < hdr_len)
321ba2ff121Schristos 		goto trunc;
322c74ad251Schristos 	nlpid = GET_U_1(p + hdr_len - 1);
3230f74e101Schristos 
324b3a00663Schristos 	if (ndo->ndo_eflag)
325b3a00663Schristos 		fr_hdr_print(ndo, length, addr_len, dlci, flags, nlpid);
3260f74e101Schristos 	p += hdr_len;
3270f74e101Schristos 	length -= hdr_len;
3280f74e101Schristos 
3290f74e101Schristos 	switch (nlpid) {
3300f74e101Schristos 	case NLPID_IP:
331b3a00663Schristos 	        ip_print(ndo, p, length);
3320f74e101Schristos 		break;
3330f74e101Schristos 
3340f74e101Schristos 	case NLPID_IP6:
335b3a00663Schristos 		ip6_print(ndo, p, length);
3360f74e101Schristos 		break;
337ba2ff121Schristos 
3380f74e101Schristos 	case NLPID_CLNP:
3390f74e101Schristos 	case NLPID_ESIS:
3400f74e101Schristos 	case NLPID_ISIS:
34172c96ff3Schristos 		isoclns_print(ndo, p - 1, length + 1); /* OSI printers need the NLPID field */
3420f74e101Schristos 		break;
3430f74e101Schristos 
3440f74e101Schristos 	case NLPID_SNAP:
345c74ad251Schristos 		if (snap_print(ndo, p, length, ND_BYTES_AVAILABLE_AFTER(p), NULL, NULL, 0) == 0) {
3460f74e101Schristos 			/* ether_type not known, print raw packet */
347b3a00663Schristos                         if (!ndo->ndo_eflag)
348b3a00663Schristos                             fr_hdr_print(ndo, length + hdr_len, hdr_len,
3490f74e101Schristos                                          dlci, flags, nlpid);
350b3a00663Schristos 			if (!ndo->ndo_suppress_default_print)
351b3a00663Schristos 				ND_DEFAULTPRINT(p - hdr_len, length + hdr_len);
3520f74e101Schristos 		}
3530f74e101Schristos 		break;
3540f74e101Schristos 
3550f74e101Schristos         case NLPID_Q933:
356b3a00663Schristos 		q933_print(ndo, p, length);
3570f74e101Schristos 		break;
3580f74e101Schristos 
3590f74e101Schristos         case NLPID_MFR:
360b3a00663Schristos                 frf15_print(ndo, p, length);
3610f74e101Schristos                 break;
3620f74e101Schristos 
3630f74e101Schristos         case NLPID_PPP:
364b3a00663Schristos                 ppp_print(ndo, p, length);
3650f74e101Schristos                 break;
3660f74e101Schristos 
3670f74e101Schristos 	default:
368b3a00663Schristos 		if (!ndo->ndo_eflag)
369b3a00663Schristos                     fr_hdr_print(ndo, length + hdr_len, addr_len,
3700f74e101Schristos 				     dlci, flags, nlpid);
371b3a00663Schristos 		if (!ndo->ndo_xflag)
372b3a00663Schristos 			ND_DEFAULTPRINT(p, length);
3730f74e101Schristos 	}
3740f74e101Schristos 
3750f74e101Schristos 	return hdr_len;
3760f74e101Schristos 
3770f74e101Schristos trunc:
378c74ad251Schristos         nd_print_trunc(ndo);
3790f74e101Schristos         return 0;
3800f74e101Schristos 
3810f74e101Schristos }
3820f74e101Schristos 
383c74ad251Schristos /* Multi Link Frame Relay (FRF.16) */
384c74ad251Schristos void
385b3a00663Schristos mfr_if_print(netdissect_options *ndo,
386c74ad251Schristos              const struct pcap_pkthdr *h, const u_char *p)
3870f74e101Schristos {
388c74ad251Schristos 	u_int length = h->len;
389c74ad251Schristos 	u_int caplen = h->caplen;
3900f74e101Schristos 
391c74ad251Schristos 	ndo->ndo_protocol = "mfr";
392c74ad251Schristos 	if (caplen < 2) {	/* minimum frame header length */
393c74ad251Schristos 		nd_print_trunc(ndo);
394c74ad251Schristos 		ndo->ndo_ll_hdr_len += caplen;
395c74ad251Schristos 		return;
396c74ad251Schristos 	}
3970f74e101Schristos 
398c74ad251Schristos 	ndo->ndo_ll_hdr_len += mfr_print(ndo, p, length);
3990f74e101Schristos }
4000f74e101Schristos 
4010f74e101Schristos 
4020f74e101Schristos #define MFR_CTRL_MSG_ADD_LINK        1
4030f74e101Schristos #define MFR_CTRL_MSG_ADD_LINK_ACK    2
4040f74e101Schristos #define MFR_CTRL_MSG_ADD_LINK_REJ    3
4050f74e101Schristos #define MFR_CTRL_MSG_HELLO           4
4060f74e101Schristos #define MFR_CTRL_MSG_HELLO_ACK       5
4070f74e101Schristos #define MFR_CTRL_MSG_REMOVE_LINK     6
4080f74e101Schristos #define MFR_CTRL_MSG_REMOVE_LINK_ACK 7
4090f74e101Schristos 
410870189d2Schristos static const struct tok mfr_ctrl_msg_values[] = {
4110f74e101Schristos     { MFR_CTRL_MSG_ADD_LINK, "Add Link" },
4120f74e101Schristos     { MFR_CTRL_MSG_ADD_LINK_ACK, "Add Link ACK" },
4130f74e101Schristos     { MFR_CTRL_MSG_ADD_LINK_REJ, "Add Link Reject" },
4140f74e101Schristos     { MFR_CTRL_MSG_HELLO, "Hello" },
4150f74e101Schristos     { MFR_CTRL_MSG_HELLO_ACK, "Hello ACK" },
4160f74e101Schristos     { MFR_CTRL_MSG_REMOVE_LINK, "Remove Link" },
4170f74e101Schristos     { MFR_CTRL_MSG_REMOVE_LINK_ACK, "Remove Link ACK" },
4180f74e101Schristos     { 0, NULL }
4190f74e101Schristos };
4200f74e101Schristos 
4210f74e101Schristos #define MFR_CTRL_IE_BUNDLE_ID  1
4220f74e101Schristos #define MFR_CTRL_IE_LINK_ID    2
4230f74e101Schristos #define MFR_CTRL_IE_MAGIC_NUM  3
4240f74e101Schristos #define MFR_CTRL_IE_TIMESTAMP  5
4250f74e101Schristos #define MFR_CTRL_IE_VENDOR_EXT 6
4260f74e101Schristos #define MFR_CTRL_IE_CAUSE      7
4270f74e101Schristos 
428870189d2Schristos static const struct tok mfr_ctrl_ie_values[] = {
4290f74e101Schristos     { MFR_CTRL_IE_BUNDLE_ID, "Bundle ID"},
4300f74e101Schristos     { MFR_CTRL_IE_LINK_ID, "Link ID"},
4310f74e101Schristos     { MFR_CTRL_IE_MAGIC_NUM, "Magic Number"},
4320f74e101Schristos     { MFR_CTRL_IE_TIMESTAMP, "Timestamp"},
4330f74e101Schristos     { MFR_CTRL_IE_VENDOR_EXT, "Vendor Extension"},
4340f74e101Schristos     { MFR_CTRL_IE_CAUSE, "Cause"},
4350f74e101Schristos     { 0, NULL }
4360f74e101Schristos };
4370f74e101Schristos 
4380f74e101Schristos #define MFR_ID_STRING_MAXLEN 50
4390f74e101Schristos 
4400f74e101Schristos struct ie_tlv_header_t {
441b3a00663Schristos     uint8_t ie_type;
442b3a00663Schristos     uint8_t ie_len;
4430f74e101Schristos };
4440f74e101Schristos 
4450f74e101Schristos u_int
446b3a00663Schristos mfr_print(netdissect_options *ndo,
447c74ad251Schristos           const u_char *p, u_int length)
4480f74e101Schristos {
4490f74e101Schristos     u_int tlen,idx,hdr_len = 0;
450b3a00663Schristos     uint16_t sequence_num;
451b3a00663Schristos     uint8_t ie_type,ie_len;
452b3a00663Schristos     const uint8_t *tptr;
4530f74e101Schristos 
4540f74e101Schristos 
4550f74e101Schristos /*
4560f74e101Schristos  * FRF.16 Link Integrity Control Frame
4570f74e101Schristos  *
4580f74e101Schristos  *      7    6    5    4    3    2    1    0
4590f74e101Schristos  *    +----+----+----+----+----+----+----+----+
4600f74e101Schristos  *    | B  | E  | C=1| 0    0    0    0  | EA |
4610f74e101Schristos  *    +----+----+----+----+----+----+----+----+
4620f74e101Schristos  *    | 0    0    0    0    0    0    0    0  |
4630f74e101Schristos  *    +----+----+----+----+----+----+----+----+
4640f74e101Schristos  *    |              message type             |
4650f74e101Schristos  *    +----+----+----+----+----+----+----+----+
4660f74e101Schristos  */
4670f74e101Schristos 
468c74ad251Schristos     ndo->ndo_protocol = "mfr";
469c74ad251Schristos 
470c74ad251Schristos     if (length < 4) {	/* minimum frame header length */
471c74ad251Schristos         ND_PRINT("[length %u < 4]", length);
472c74ad251Schristos         nd_print_invalid(ndo);
473817e9a7eSchristos         return length;
474817e9a7eSchristos     }
475c74ad251Schristos     ND_TCHECK_4(p);
4760f74e101Schristos 
477c74ad251Schristos     if ((GET_U_1(p) & MFR_BEC_MASK) == MFR_CTRL_FRAME && GET_U_1(p + 1) == 0) {
478c74ad251Schristos         ND_PRINT("FRF.16 Control, Flags [%s], %s, length %u",
479c74ad251Schristos                bittok2str(frf_flag_values,"none",(GET_U_1(p) & MFR_BEC_MASK)),
480c74ad251Schristos                tok2str(mfr_ctrl_msg_values,"Unknown Message (0x%02x)",GET_U_1(p + 2)),
481c74ad251Schristos                length);
4820f74e101Schristos         tptr = p + 3;
4830f74e101Schristos         tlen = length -3;
4840f74e101Schristos         hdr_len = 3;
4850f74e101Schristos 
486b3a00663Schristos         if (!ndo->ndo_vflag)
4870f74e101Schristos             return hdr_len;
4880f74e101Schristos 
4890f74e101Schristos         while (tlen>sizeof(struct ie_tlv_header_t)) {
490c74ad251Schristos             ND_TCHECK_LEN(tptr, sizeof(struct ie_tlv_header_t));
491c74ad251Schristos             ie_type=GET_U_1(tptr);
492c74ad251Schristos             ie_len=GET_U_1(tptr + 1);
4930f74e101Schristos 
494c74ad251Schristos             ND_PRINT("\n\tIE %s (%u), length %u: ",
4950f74e101Schristos                    tok2str(mfr_ctrl_ie_values,"Unknown",ie_type),
4960f74e101Schristos                    ie_type,
497c74ad251Schristos                    ie_len);
4980f74e101Schristos 
4990f74e101Schristos             /* infinite loop check */
5000f74e101Schristos             if (ie_type == 0 || ie_len <= sizeof(struct ie_tlv_header_t))
5010f74e101Schristos                 return hdr_len;
5020f74e101Schristos 
503c74ad251Schristos             ND_TCHECK_LEN(tptr, ie_len);
5040f74e101Schristos             tptr+=sizeof(struct ie_tlv_header_t);
5050f74e101Schristos             /* tlv len includes header */
5060f74e101Schristos             ie_len-=sizeof(struct ie_tlv_header_t);
5070f74e101Schristos             tlen-=sizeof(struct ie_tlv_header_t);
5080f74e101Schristos 
5090f74e101Schristos             switch (ie_type) {
5100f74e101Schristos 
5110f74e101Schristos             case MFR_CTRL_IE_MAGIC_NUM:
512817e9a7eSchristos                 /* FRF.16.1 Section 3.4.3 Magic Number Information Element */
513817e9a7eSchristos                 if (ie_len != 4) {
514c74ad251Schristos                     ND_PRINT("[IE data length %d != 4]", ie_len);
515c74ad251Schristos                     nd_print_invalid(ndo);
516817e9a7eSchristos                     break;
517817e9a7eSchristos                 }
518c74ad251Schristos                 ND_PRINT("0x%08x", GET_BE_U_4(tptr));
5190f74e101Schristos                 break;
5200f74e101Schristos 
5210f74e101Schristos             case MFR_CTRL_IE_BUNDLE_ID: /* same message format */
5220f74e101Schristos             case MFR_CTRL_IE_LINK_ID:
5230f74e101Schristos                 for (idx = 0; idx < ie_len && idx < MFR_ID_STRING_MAXLEN; idx++) {
524c74ad251Schristos                     if (GET_U_1(tptr + idx) != 0) /* don't print null termination */
525c74ad251Schristos                         fn_print_char(ndo, GET_U_1(tptr + idx));
5260f74e101Schristos                     else
5270f74e101Schristos                         break;
5280f74e101Schristos                 }
5290f74e101Schristos                 break;
5300f74e101Schristos 
5310f74e101Schristos             case MFR_CTRL_IE_TIMESTAMP:
532*26ba0b50Schristos                 /*
533*26ba0b50Schristos                  * FRF.16.1 Section 3.4.4 Timestamp Information Element
534*26ba0b50Schristos                  *
535*26ba0b50Schristos                  * The maximum length is 14 octets. Format is implementation
536*26ba0b50Schristos                  * specific.
537*26ba0b50Schristos                  */
538*26ba0b50Schristos                 if (ie_len > 14) {
539*26ba0b50Schristos                     ND_PRINT("[Timestamp IE length %d > 14]", ie_len);
540*26ba0b50Schristos                     nd_print_invalid(ndo);
5410f74e101Schristos                     break;
5420f74e101Schristos                 }
543*26ba0b50Schristos                 /* fall through and hexdump */
544c74ad251Schristos                 ND_FALL_THROUGH;
5450f74e101Schristos 
5460f74e101Schristos                 /*
5470f74e101Schristos                  * FIXME those are the defined IEs that lack a decoder
5480f74e101Schristos                  * you are welcome to contribute code ;-)
5490f74e101Schristos                  */
5500f74e101Schristos 
5510f74e101Schristos             case MFR_CTRL_IE_VENDOR_EXT:
5520f74e101Schristos             case MFR_CTRL_IE_CAUSE:
5530f74e101Schristos 
5540f74e101Schristos             default:
555b3a00663Schristos                 if (ndo->ndo_vflag <= 1)
556b3a00663Schristos                     print_unknown_data(ndo, tptr, "\n\t  ", ie_len);
5570f74e101Schristos                 break;
5580f74e101Schristos             }
5590f74e101Schristos 
5600f74e101Schristos             /* do we want to see a hexdump of the IE ? */
561b3a00663Schristos             if (ndo->ndo_vflag > 1 )
562b3a00663Schristos                 print_unknown_data(ndo, tptr, "\n\t  ", ie_len);
5630f74e101Schristos 
5640f74e101Schristos             tlen-=ie_len;
5650f74e101Schristos             tptr+=ie_len;
5660f74e101Schristos         }
5670f74e101Schristos         return hdr_len;
5680f74e101Schristos     }
5690f74e101Schristos /*
5700f74e101Schristos  * FRF.16 Fragmentation Frame
5710f74e101Schristos  *
5720f74e101Schristos  *      7    6    5    4    3    2    1    0
5730f74e101Schristos  *    +----+----+----+----+----+----+----+----+
5740f74e101Schristos  *    | B  | E  | C=0|seq. (high 4 bits) | EA |
5750f74e101Schristos  *    +----+----+----+----+----+----+----+----+
5760f74e101Schristos  *    |        sequence  (low 8 bits)         |
5770f74e101Schristos  *    +----+----+----+----+----+----+----+----+
5780f74e101Schristos  *    |        DLCI (6 bits)        | CR | EA |
5790f74e101Schristos  *    +----+----+----+----+----+----+----+----+
5800f74e101Schristos  *    |   DLCI (4 bits)   |FECN|BECN| DE | EA |
5810f74e101Schristos  *    +----+----+----+----+----+----+----+----+
5820f74e101Schristos  */
5830f74e101Schristos 
584c74ad251Schristos     sequence_num = (GET_U_1(p)&0x1e)<<7 | GET_U_1(p + 1);
5850f74e101Schristos     /* whole packet or first fragment ? */
586c74ad251Schristos     if ((GET_U_1(p) & MFR_BEC_MASK) == MFR_FRAG_FRAME ||
587c74ad251Schristos         (GET_U_1(p) & MFR_BEC_MASK) == MFR_B_BIT) {
588c74ad251Schristos         ND_PRINT("FRF.16 Frag, seq %u, Flags [%s], ",
5890f74e101Schristos                sequence_num,
590c74ad251Schristos                bittok2str(frf_flag_values,"none",(GET_U_1(p) & MFR_BEC_MASK)));
5910f74e101Schristos         hdr_len = 2;
592b3a00663Schristos         fr_print(ndo, p+hdr_len,length-hdr_len);
5930f74e101Schristos         return hdr_len;
5940f74e101Schristos     }
5950f74e101Schristos 
5960f74e101Schristos     /* must be a middle or the last fragment */
597c74ad251Schristos     ND_PRINT("FRF.16 Frag, seq %u, Flags [%s]",
5980f74e101Schristos            sequence_num,
599c74ad251Schristos            bittok2str(frf_flag_values,"none",(GET_U_1(p) & MFR_BEC_MASK)));
600b3a00663Schristos     print_unknown_data(ndo, p, "\n\t", length);
6010f74e101Schristos 
6020f74e101Schristos     return hdr_len;
6030f74e101Schristos 
6040f74e101Schristos trunc:
605c74ad251Schristos     nd_print_trunc(ndo);
6060f74e101Schristos     return length;
6070f74e101Schristos }
6080f74e101Schristos 
6090f74e101Schristos /* an NLPID of 0xb1 indicates a 2-byte
6100f74e101Schristos  * FRF.15 header
6110f74e101Schristos  *
6120f74e101Schristos  *      7    6    5    4    3    2    1    0
6130f74e101Schristos  *    +----+----+----+----+----+----+----+----+
6140f74e101Schristos  *    ~              Q.922 header             ~
6150f74e101Schristos  *    +----+----+----+----+----+----+----+----+
6160f74e101Schristos  *    |             NLPID (8 bits)            | NLPID=0xb1
6170f74e101Schristos  *    +----+----+----+----+----+----+----+----+
6180f74e101Schristos  *    | B  | E  | C  |seq. (high 4 bits) | R  |
6190f74e101Schristos  *    +----+----+----+----+----+----+----+----+
6200f74e101Schristos  *    |        sequence  (low 8 bits)         |
6210f74e101Schristos  *    +----+----+----+----+----+----+----+----+
6220f74e101Schristos  */
6230f74e101Schristos 
6240f74e101Schristos #define FR_FRF15_FRAGTYPE 0x01
6250f74e101Schristos 
6260f74e101Schristos static void
627b3a00663Schristos frf15_print(netdissect_options *ndo,
628ba2ff121Schristos             const u_char *p, u_int length)
629ba2ff121Schristos {
630b3a00663Schristos     uint16_t sequence_num, flags;
6310f74e101Schristos 
632fdccd7e4Schristos     if (length < 2)
633fdccd7e4Schristos         goto trunc;
634fdccd7e4Schristos 
635c74ad251Schristos     flags = GET_U_1(p)&MFR_BEC_MASK;
636c74ad251Schristos     sequence_num = (GET_U_1(p)&0x1e)<<7 | GET_U_1(p + 1);
6370f74e101Schristos 
638c74ad251Schristos     ND_PRINT("FRF.15, seq 0x%03x, Flags [%s],%s Fragmentation, length %u",
6390f74e101Schristos            sequence_num,
6400f74e101Schristos            bittok2str(frf_flag_values,"none",flags),
641c74ad251Schristos            GET_U_1(p)&FR_FRF15_FRAGTYPE ? "Interface" : "End-to-End",
642c74ad251Schristos            length);
6430f74e101Schristos 
6440f74e101Schristos /* TODO:
6450f74e101Schristos  * depending on all permutations of the B, E and C bit
6460f74e101Schristos  * dig as deep as we can - e.g. on the first (B) fragment
6470f74e101Schristos  * there is enough payload to print the IP header
6480f74e101Schristos  * on non (B) fragments it depends if the fragmentation
649c74ad251Schristos  * model is end-to-end or interface based whether we want to print
6500f74e101Schristos  * another Q.922 header
6510f74e101Schristos  */
652fdccd7e4Schristos     return;
6530f74e101Schristos 
654fdccd7e4Schristos trunc:
655c74ad251Schristos     nd_print_trunc(ndo);
6560f74e101Schristos }
6570f74e101Schristos 
6580f74e101Schristos /*
6590f74e101Schristos  * Q.933 decoding portion for framerelay specific.
6600f74e101Schristos  */
6610f74e101Schristos 
6620f74e101Schristos /* Q.933 packet format
6630f74e101Schristos                       Format of Other Protocols
6640f74e101Schristos                           using Q.933 NLPID
6650f74e101Schristos                   +-------------------------------+
6660f74e101Schristos                   |        Q.922 Address          |
6670f74e101Schristos                   +---------------+---------------+
6680f74e101Schristos                   |Control  0x03  | NLPID   0x08  |
6690f74e101Schristos                   +---------------+---------------+
6700f74e101Schristos                   |          L2 Protocol ID       |
6710f74e101Schristos                   | octet 1       |  octet 2      |
6720f74e101Schristos                   +-------------------------------+
6730f74e101Schristos                   |          L3 Protocol ID       |
6740f74e101Schristos                   | octet 2       |  octet 2      |
6750f74e101Schristos                   +-------------------------------+
6760f74e101Schristos                   |         Protocol Data         |
6770f74e101Schristos                   +-------------------------------+
6780f74e101Schristos                   | FCS                           |
6790f74e101Schristos                   +-------------------------------+
6800f74e101Schristos  */
6810f74e101Schristos 
6820f74e101Schristos /* L2 (Octet 1)- Call Reference Usually is 0x0 */
6830f74e101Schristos 
6840f74e101Schristos /*
6850f74e101Schristos  * L2 (Octet 2)- Message Types definition 1 byte long.
6860f74e101Schristos  */
6870f74e101Schristos /* Call Establish */
6880f74e101Schristos #define MSG_TYPE_ESC_TO_NATIONAL  0x00
6890f74e101Schristos #define MSG_TYPE_ALERT            0x01
6900f74e101Schristos #define MSG_TYPE_CALL_PROCEEDING  0x02
6910f74e101Schristos #define MSG_TYPE_CONNECT          0x07
6920f74e101Schristos #define MSG_TYPE_CONNECT_ACK      0x0F
6930f74e101Schristos #define MSG_TYPE_PROGRESS         0x03
6940f74e101Schristos #define MSG_TYPE_SETUP            0x05
6950f74e101Schristos /* Call Clear */
6960f74e101Schristos #define MSG_TYPE_DISCONNECT       0x45
6970f74e101Schristos #define MSG_TYPE_RELEASE          0x4D
6980f74e101Schristos #define MSG_TYPE_RELEASE_COMPLETE 0x5A
6990f74e101Schristos #define MSG_TYPE_RESTART          0x46
7000f74e101Schristos #define MSG_TYPE_RESTART_ACK      0x4E
7010f74e101Schristos /* Status */
7020f74e101Schristos #define MSG_TYPE_STATUS           0x7D
7030f74e101Schristos #define MSG_TYPE_STATUS_ENQ       0x75
7040f74e101Schristos 
705870189d2Schristos static const struct tok fr_q933_msg_values[] = {
7060f74e101Schristos     { MSG_TYPE_ESC_TO_NATIONAL, "ESC to National" },
7070f74e101Schristos     { MSG_TYPE_ALERT, "Alert" },
7080f74e101Schristos     { MSG_TYPE_CALL_PROCEEDING, "Call proceeding" },
7090f74e101Schristos     { MSG_TYPE_CONNECT, "Connect" },
7100f74e101Schristos     { MSG_TYPE_CONNECT_ACK, "Connect ACK" },
7110f74e101Schristos     { MSG_TYPE_PROGRESS, "Progress" },
7120f74e101Schristos     { MSG_TYPE_SETUP, "Setup" },
7130f74e101Schristos     { MSG_TYPE_DISCONNECT, "Disconnect" },
7140f74e101Schristos     { MSG_TYPE_RELEASE, "Release" },
7150f74e101Schristos     { MSG_TYPE_RELEASE_COMPLETE, "Release Complete" },
7160f74e101Schristos     { MSG_TYPE_RESTART, "Restart" },
7170f74e101Schristos     { MSG_TYPE_RESTART_ACK, "Restart ACK" },
7180f74e101Schristos     { MSG_TYPE_STATUS, "Status Reply" },
7190f74e101Schristos     { MSG_TYPE_STATUS_ENQ, "Status Enquiry" },
7200f74e101Schristos     { 0, NULL }
7210f74e101Schristos };
7220f74e101Schristos 
723dc860a36Sspz #define IE_IS_SINGLE_OCTET(iecode)	((iecode) & 0x80)
724dc860a36Sspz #define IE_IS_SHIFT(iecode)		(((iecode) & 0xF0) == 0x90)
725dc860a36Sspz #define IE_SHIFT_IS_NON_LOCKING(iecode)	((iecode) & 0x08)
726dc860a36Sspz #define IE_SHIFT_IS_LOCKING(iecode)	(!(IE_SHIFT_IS_NON_LOCKING(iecode)))
727dc860a36Sspz #define IE_SHIFT_CODESET(iecode)	((iecode) & 0x07)
7280f74e101Schristos 
7290f74e101Schristos #define FR_LMI_ANSI_REPORT_TYPE_IE	0x01
7300f74e101Schristos #define FR_LMI_ANSI_LINK_VERIFY_IE_91	0x19 /* details? */
7310f74e101Schristos #define FR_LMI_ANSI_LINK_VERIFY_IE	0x03
7320f74e101Schristos #define FR_LMI_ANSI_PVC_STATUS_IE	0x07
7330f74e101Schristos 
7340f74e101Schristos #define FR_LMI_CCITT_REPORT_TYPE_IE	0x51
7350f74e101Schristos #define FR_LMI_CCITT_LINK_VERIFY_IE	0x53
7360f74e101Schristos #define FR_LMI_CCITT_PVC_STATUS_IE	0x57
7370f74e101Schristos 
738dc860a36Sspz static const struct tok fr_q933_ie_values_codeset_0_5[] = {
7390f74e101Schristos     { FR_LMI_ANSI_REPORT_TYPE_IE, "ANSI Report Type" },
7400f74e101Schristos     { FR_LMI_ANSI_LINK_VERIFY_IE_91, "ANSI Link Verify" },
7410f74e101Schristos     { FR_LMI_ANSI_LINK_VERIFY_IE, "ANSI Link Verify" },
7420f74e101Schristos     { FR_LMI_ANSI_PVC_STATUS_IE, "ANSI PVC Status" },
7430f74e101Schristos     { FR_LMI_CCITT_REPORT_TYPE_IE, "CCITT Report Type" },
7440f74e101Schristos     { FR_LMI_CCITT_LINK_VERIFY_IE, "CCITT Link Verify" },
7450f74e101Schristos     { FR_LMI_CCITT_PVC_STATUS_IE, "CCITT PVC Status" },
7460f74e101Schristos     { 0, NULL }
7470f74e101Schristos };
7480f74e101Schristos 
7490f74e101Schristos #define FR_LMI_REPORT_TYPE_IE_FULL_STATUS 0
7500f74e101Schristos #define FR_LMI_REPORT_TYPE_IE_LINK_VERIFY 1
7510f74e101Schristos #define FR_LMI_REPORT_TYPE_IE_ASYNC_PVC   2
7520f74e101Schristos 
753870189d2Schristos static const struct tok fr_lmi_report_type_ie_values[] = {
7540f74e101Schristos     { FR_LMI_REPORT_TYPE_IE_FULL_STATUS, "Full Status" },
7550f74e101Schristos     { FR_LMI_REPORT_TYPE_IE_LINK_VERIFY, "Link verify" },
7560f74e101Schristos     { FR_LMI_REPORT_TYPE_IE_ASYNC_PVC, "Async PVC Status" },
7570f74e101Schristos     { 0, NULL }
7580f74e101Schristos };
7590f74e101Schristos 
760dc860a36Sspz /* array of 16 codesets - currently we only support codepage 0 and 5 */
761870189d2Schristos static const struct tok *fr_q933_ie_codesets[] = {
762dc860a36Sspz     fr_q933_ie_values_codeset_0_5,
7630f74e101Schristos     NULL,
7640f74e101Schristos     NULL,
7650f74e101Schristos     NULL,
766dc860a36Sspz     NULL,
767dc860a36Sspz     fr_q933_ie_values_codeset_0_5,
7680f74e101Schristos     NULL,
7690f74e101Schristos     NULL,
7700f74e101Schristos     NULL,
7710f74e101Schristos     NULL,
7720f74e101Schristos     NULL,
7730f74e101Schristos     NULL,
7740f74e101Schristos     NULL,
7750f74e101Schristos     NULL,
7760f74e101Schristos     NULL,
7770f74e101Schristos     NULL
7780f74e101Schristos };
7790f74e101Schristos 
780dc860a36Sspz static int fr_q933_print_ie_codeset_0_5(netdissect_options *ndo, u_int iecode,
781dc860a36Sspz     u_int ielength, const u_char *p);
7820f74e101Schristos 
783dc860a36Sspz typedef int (*codeset_pr_func_t)(netdissect_options *, u_int iecode,
784dc860a36Sspz     u_int ielength, const u_char *p);
7850f74e101Schristos 
786dc860a36Sspz /* array of 16 codesets - currently we only support codepage 0 and 5 */
787b3a00663Schristos static const codeset_pr_func_t fr_q933_print_ie_codeset[] = {
788dc860a36Sspz     fr_q933_print_ie_codeset_0_5,
7890f74e101Schristos     NULL,
7900f74e101Schristos     NULL,
7910f74e101Schristos     NULL,
792dc860a36Sspz     NULL,
793dc860a36Sspz     fr_q933_print_ie_codeset_0_5,
7940f74e101Schristos     NULL,
7950f74e101Schristos     NULL,
7960f74e101Schristos     NULL,
7970f74e101Schristos     NULL,
7980f74e101Schristos     NULL,
7990f74e101Schristos     NULL,
8000f74e101Schristos     NULL,
8010f74e101Schristos     NULL,
8020f74e101Schristos     NULL,
8030f74e101Schristos     NULL
8040f74e101Schristos };
8050f74e101Schristos 
806dc860a36Sspz /*
807dc860a36Sspz  * ITU-T Q.933.
808dc860a36Sspz  *
809dc860a36Sspz  * p points to octet 2, the octet containing the length of the
810dc860a36Sspz  * call reference value, so p[n] is octet n+2 ("octet X" is as
811dc860a36Sspz  * used in Q.931/Q.933).
812dc860a36Sspz  *
813dc860a36Sspz  * XXX - actually used both for Q.931 and Q.933.
814dc860a36Sspz  */
8150f74e101Schristos void
816b3a00663Schristos q933_print(netdissect_options *ndo,
817b3a00663Schristos            const u_char *p, u_int length)
8180f74e101Schristos {
819dc860a36Sspz 	u_int olen;
820dc860a36Sspz 	u_int call_ref_length, i;
821dc860a36Sspz 	uint8_t call_ref[15];	/* maximum length - length field is 4 bits */
822dc860a36Sspz 	u_int msgtype;
823dc860a36Sspz 	u_int iecode;
824dc860a36Sspz 	u_int ielength;
825dc860a36Sspz 	u_int codeset = 0;
826dc860a36Sspz 	u_int is_ansi = 0;
827dc860a36Sspz 	u_int ie_is_known;
828dc860a36Sspz 	u_int non_locking_shift;
829dc860a36Sspz 	u_int unshift_codeset;
8300f74e101Schristos 
831c74ad251Schristos 	ndo->ndo_protocol = "q.933";
832c74ad251Schristos 	ND_PRINT("%s", ndo->ndo_eflag ? "" : "Q.933");
833dc860a36Sspz 
834c74ad251Schristos 	if (length == 0 || !ND_TTEST_1(p)) {
835dc860a36Sspz 		if (!ndo->ndo_eflag)
836c74ad251Schristos 			ND_PRINT(", ");
837c74ad251Schristos 		ND_PRINT("length %u", length);
838fdccd7e4Schristos 		goto trunc;
8390f74e101Schristos 	}
8400f74e101Schristos 
841dc860a36Sspz 	/*
842dc860a36Sspz 	 * Get the length of the call reference value.
843dc860a36Sspz 	 */
844dc860a36Sspz 	olen = length; /* preserve the original length for display */
845c74ad251Schristos 	call_ref_length = GET_U_1(p) & 0x0f;
846dc860a36Sspz 	p++;
847dc860a36Sspz 	length--;
848dc860a36Sspz 
849dc860a36Sspz 	/*
850dc860a36Sspz 	 * Get the call reference value.
851dc860a36Sspz 	 */
852dc860a36Sspz 	for (i = 0; i < call_ref_length; i++) {
853c74ad251Schristos 		if (length == 0 || !ND_TTEST_1(p)) {
854dc860a36Sspz 			if (!ndo->ndo_eflag)
855c74ad251Schristos 				ND_PRINT(", ");
856c74ad251Schristos 			ND_PRINT("length %u", olen);
857dc860a36Sspz 			goto trunc;
858dc860a36Sspz 		}
859c74ad251Schristos 		call_ref[i] = GET_U_1(p);
860dc860a36Sspz 		p++;
861dc860a36Sspz 		length--;
862dc860a36Sspz 	}
863dc860a36Sspz 
864dc860a36Sspz 	/*
865dc860a36Sspz 	 * Get the message type.
866dc860a36Sspz 	 */
867c74ad251Schristos 	if (length == 0 || !ND_TTEST_1(p)) {
868dc860a36Sspz 		if (!ndo->ndo_eflag)
869c74ad251Schristos 			ND_PRINT(", ");
870c74ad251Schristos 		ND_PRINT("length %u", olen);
871dc860a36Sspz 		goto trunc;
872dc860a36Sspz 	}
873c74ad251Schristos 	msgtype = GET_U_1(p);
874dc860a36Sspz 	p++;
875dc860a36Sspz 	length--;
876dc860a36Sspz 
877dc860a36Sspz 	/*
878dc860a36Sspz 	 * Peek ahead to see if we start with a shift.
879dc860a36Sspz 	 */
880dc860a36Sspz 	non_locking_shift = 0;
881dc860a36Sspz 	unshift_codeset = codeset;
882dc860a36Sspz 	if (length != 0) {
883c74ad251Schristos 		if (!ND_TTEST_1(p)) {
884dc860a36Sspz 			if (!ndo->ndo_eflag)
885c74ad251Schristos 				ND_PRINT(", ");
886c74ad251Schristos 			ND_PRINT("length %u", olen);
887dc860a36Sspz 			goto trunc;
888dc860a36Sspz 		}
889c74ad251Schristos 		iecode = GET_U_1(p);
890dc860a36Sspz 		if (IE_IS_SHIFT(iecode)) {
891dc860a36Sspz 			/*
892dc860a36Sspz 			 * It's a shift.  Skip over it.
893dc860a36Sspz 			 */
894dc860a36Sspz 			p++;
895dc860a36Sspz 			length--;
896dc860a36Sspz 
897dc860a36Sspz 			/*
898dc860a36Sspz 			 * Get the codeset.
899dc860a36Sspz 			 */
900dc860a36Sspz 			codeset = IE_SHIFT_CODESET(iecode);
901dc860a36Sspz 
902dc860a36Sspz 			/*
903dc860a36Sspz 			 * If it's a locking shift to codeset 5,
904dc860a36Sspz 			 * mark this as ANSI.  (XXX - 5 is actually
905dc860a36Sspz 			 * for national variants in general, not
906dc860a36Sspz 			 * the US variant in particular, but maybe
907dc860a36Sspz 			 * this is more American exceptionalism. :-))
908dc860a36Sspz 			 */
909dc860a36Sspz 			if (IE_SHIFT_IS_LOCKING(iecode)) {
910dc860a36Sspz 				/*
911dc860a36Sspz 				 * It's a locking shift.
912dc860a36Sspz 				 */
913dc860a36Sspz 				if (codeset == 5) {
914dc860a36Sspz 					/*
915dc860a36Sspz 					 * It's a locking shift to
916dc860a36Sspz 					 * codeset 5, so this is
917dc860a36Sspz 					 * T1.617 Annex D.
918dc860a36Sspz 					 */
919dc860a36Sspz 					is_ansi = 1;
920dc860a36Sspz 				}
921dc860a36Sspz 			} else {
922dc860a36Sspz 				/*
923dc860a36Sspz 				 * It's a non-locking shift.
924dc860a36Sspz 				 * Remember the current codeset, so we
925dc860a36Sspz 				 * can revert to it after the next IE.
926dc860a36Sspz 				 */
927dc860a36Sspz 				non_locking_shift = 1;
928dc860a36Sspz 				unshift_codeset = 0;
929dc860a36Sspz 			}
930dc860a36Sspz 		}
931dc860a36Sspz 	}
9320f74e101Schristos 
9330f74e101Schristos 	/* printing out header part */
934dc860a36Sspz 	if (!ndo->ndo_eflag)
935c74ad251Schristos 		ND_PRINT(", ");
936c74ad251Schristos 	ND_PRINT("%s, codeset %u", is_ansi ? "ANSI" : "CCITT", codeset);
9370f74e101Schristos 
938dc860a36Sspz 	if (call_ref_length != 0) {
939c74ad251Schristos 		if (call_ref_length > 1 || GET_U_1(p) != 0) {
940dc860a36Sspz 			/*
941dc860a36Sspz 			 * Not a dummy call reference.
942dc860a36Sspz 			 */
943c74ad251Schristos 			ND_PRINT(", Call Ref: 0x");
944dc860a36Sspz 			for (i = 0; i < call_ref_length; i++)
945c74ad251Schristos 				ND_PRINT("%02x", call_ref[i]);
946dc860a36Sspz 		}
9470f74e101Schristos 	}
948b3a00663Schristos 	if (ndo->ndo_vflag) {
949c74ad251Schristos 		ND_PRINT(", %s (0x%02x), length %u",
9500f74e101Schristos 		   tok2str(fr_q933_msg_values,
951dc860a36Sspz 			"unknown message", msgtype),
952dc860a36Sspz 		   msgtype,
953c74ad251Schristos 		   olen);
9540f74e101Schristos 	} else {
955c74ad251Schristos 		ND_PRINT(", %s",
9560f74e101Schristos 		       tok2str(fr_q933_msg_values,
957c74ad251Schristos 			       "unknown message 0x%02x", msgtype));
9580f74e101Schristos 	}
9590f74e101Schristos 
960dc860a36Sspz 	/* Loop through the rest of the IEs */
961dc860a36Sspz 	while (length != 0) {
962dc860a36Sspz 		/*
963dc860a36Sspz 		 * What's the state of any non-locking shifts?
964dc860a36Sspz 		 */
965dc860a36Sspz 		if (non_locking_shift == 1) {
966dc860a36Sspz 			/*
967dc860a36Sspz 			 * There's a non-locking shift in effect for
968dc860a36Sspz 			 * this IE.  Count it, so we reset the codeset
969dc860a36Sspz 			 * before the next IE.
970dc860a36Sspz 			 */
971dc860a36Sspz 			non_locking_shift = 2;
972dc860a36Sspz 		} else if (non_locking_shift == 2) {
973dc860a36Sspz 			/*
974dc860a36Sspz 			 * Unshift.
975dc860a36Sspz 			 */
976dc860a36Sspz 			codeset = unshift_codeset;
977dc860a36Sspz 			non_locking_shift = 0;
9780f74e101Schristos 		}
9790f74e101Schristos 
980dc860a36Sspz 		/*
981dc860a36Sspz 		 * Get the first octet of the IE.
982dc860a36Sspz 		 */
983c74ad251Schristos 		if (!ND_TTEST_1(p)) {
984dc860a36Sspz 			if (!ndo->ndo_vflag) {
985c74ad251Schristos 				ND_PRINT(", length %u", olen);
9860f74e101Schristos 			}
987dc860a36Sspz 			goto trunc;
9880f74e101Schristos 		}
989c74ad251Schristos 		iecode = GET_U_1(p);
990dc860a36Sspz 		p++;
991dc860a36Sspz 		length--;
992dc860a36Sspz 
993dc860a36Sspz 		/* Single-octet IE? */
994dc860a36Sspz 		if (IE_IS_SINGLE_OCTET(iecode)) {
995dc860a36Sspz 			/*
996dc860a36Sspz 			 * Yes.  Is it a shift?
997dc860a36Sspz 			 */
998dc860a36Sspz 			if (IE_IS_SHIFT(iecode)) {
999dc860a36Sspz 				/*
1000dc860a36Sspz 				 * Yes.  Is it locking?
1001dc860a36Sspz 				 */
1002dc860a36Sspz 				if (IE_SHIFT_IS_LOCKING(iecode)) {
1003dc860a36Sspz 					/*
1004dc860a36Sspz 					 * Yes.
1005dc860a36Sspz 					 */
1006dc860a36Sspz 					non_locking_shift = 0;
1007dc860a36Sspz 				} else {
1008dc860a36Sspz 					/*
1009dc860a36Sspz 					 * No.  Remember the current
1010dc860a36Sspz 					 * codeset, so we can revert
1011dc860a36Sspz 					 * to it after the next IE.
1012dc860a36Sspz 					 */
1013dc860a36Sspz 					non_locking_shift = 1;
1014dc860a36Sspz 					unshift_codeset = codeset;
1015fdccd7e4Schristos 				}
10160f74e101Schristos 
1017dc860a36Sspz 				/*
1018dc860a36Sspz 				 * Get the codeset.
1019dc860a36Sspz 				 */
1020dc860a36Sspz 				codeset = IE_SHIFT_CODESET(iecode);
1021dc860a36Sspz 			}
1022dc860a36Sspz 		} else {
1023dc860a36Sspz 			/*
1024dc860a36Sspz 			 * No.  Get the IE length.
1025dc860a36Sspz 			 */
1026c74ad251Schristos 			if (length == 0 || !ND_TTEST_1(p)) {
1027dc860a36Sspz 				if (!ndo->ndo_vflag) {
1028c74ad251Schristos 					ND_PRINT(", length %u", olen);
1029dc860a36Sspz 				}
1030dc860a36Sspz 				goto trunc;
1031dc860a36Sspz 			}
1032c74ad251Schristos 			ielength = GET_U_1(p);
1033dc860a36Sspz 			p++;
1034dc860a36Sspz 			length--;
1035dc860a36Sspz 
10360f74e101Schristos 			/* lets do the full IE parsing only in verbose mode
10370f74e101Schristos 			 * however some IEs (DLCI Status, Link Verify)
1038dc860a36Sspz 			 * are also interesting in non-verbose mode */
1039b3a00663Schristos 			if (ndo->ndo_vflag) {
1040c74ad251Schristos 				ND_PRINT("\n\t%s IE (0x%02x), length %u: ",
10410f74e101Schristos 				    tok2str(fr_q933_ie_codesets[codeset],
1042dc860a36Sspz 					"unknown", iecode),
1043dc860a36Sspz 				    iecode,
1044c74ad251Schristos 				    ielength);
10450f74e101Schristos 			}
10460f74e101Schristos 
1047fdccd7e4Schristos 			/* sanity checks */
1048dc860a36Sspz 			if (iecode == 0 || ielength == 0) {
10490f74e101Schristos 				return;
10500f74e101Schristos 			}
1051c74ad251Schristos 			if (length < ielength || !ND_TTEST_LEN(p, ielength)) {
1052dc860a36Sspz 				if (!ndo->ndo_vflag) {
1053c74ad251Schristos 					ND_PRINT(", length %u", olen);
1054dc860a36Sspz 				}
1055fdccd7e4Schristos 				goto trunc;
1056fdccd7e4Schristos 			}
10570f74e101Schristos 
1058dc860a36Sspz 			ie_is_known = 0;
10590f74e101Schristos 			if (fr_q933_print_ie_codeset[codeset] != NULL) {
1060dc860a36Sspz 				ie_is_known = fr_q933_print_ie_codeset[codeset](ndo, iecode, ielength, p);
10610f74e101Schristos 			}
10620f74e101Schristos 
1063dc860a36Sspz 			if (ie_is_known) {
1064dc860a36Sspz 				/*
1065dc860a36Sspz 				 * Known IE; do we want to see a hexdump
1066dc860a36Sspz 				 * of it?
1067dc860a36Sspz 				 */
1068dc860a36Sspz 				if (ndo->ndo_vflag > 1) {
1069dc860a36Sspz 					/* Yes. */
1070dc860a36Sspz 					print_unknown_data(ndo, p, "\n\t  ", ielength);
1071dc860a36Sspz 				}
1072dc860a36Sspz 			} else {
1073dc860a36Sspz 				/*
1074dc860a36Sspz 				 * Unknown IE; if we're printing verbosely,
1075dc860a36Sspz 				 * print its content in hex.
1076dc860a36Sspz 				 */
1077dc860a36Sspz 				if (ndo->ndo_vflag >= 1) {
1078dc860a36Sspz 					print_unknown_data(ndo, p, "\n\t", ielength);
1079dc860a36Sspz 				}
10800f74e101Schristos 			}
10810f74e101Schristos 
1082dc860a36Sspz 			length -= ielength;
1083dc860a36Sspz 			p += ielength;
10840f74e101Schristos 		}
10850f74e101Schristos 	}
1086b3a00663Schristos 	if (!ndo->ndo_vflag) {
1087c74ad251Schristos 	    ND_PRINT(", length %u", olen);
10880f74e101Schristos 	}
1089fdccd7e4Schristos 	return;
1090fdccd7e4Schristos 
1091fdccd7e4Schristos trunc:
1092c74ad251Schristos 	nd_print_trunc(ndo);
10930f74e101Schristos }
10940f74e101Schristos 
10950f74e101Schristos static int
1096dc860a36Sspz fr_q933_print_ie_codeset_0_5(netdissect_options *ndo, u_int iecode,
1097dc860a36Sspz                           u_int ielength, const u_char *p)
10980f74e101Schristos {
10990f74e101Schristos         u_int dlci;
11000f74e101Schristos 
1101dc860a36Sspz         switch (iecode) {
11020f74e101Schristos 
11030f74e101Schristos         case FR_LMI_ANSI_REPORT_TYPE_IE: /* fall through */
11040f74e101Schristos         case FR_LMI_CCITT_REPORT_TYPE_IE:
1105dc860a36Sspz             if (ielength < 1) {
1106dc860a36Sspz                 if (!ndo->ndo_vflag) {
1107c74ad251Schristos                     ND_PRINT(", ");
1108dc860a36Sspz 	        }
1109c74ad251Schristos                 ND_PRINT("Invalid REPORT TYPE IE");
1110dc860a36Sspz                 return 1;
1111dc860a36Sspz             }
1112b3a00663Schristos             if (ndo->ndo_vflag) {
1113c74ad251Schristos                 ND_PRINT("%s (%u)",
1114c74ad251Schristos                        tok2str(fr_lmi_report_type_ie_values,"unknown",GET_U_1(p)),
1115c74ad251Schristos                        GET_U_1(p));
11160f74e101Schristos 	    }
11170f74e101Schristos             return 1;
11180f74e101Schristos 
11190f74e101Schristos         case FR_LMI_ANSI_LINK_VERIFY_IE: /* fall through */
11200f74e101Schristos         case FR_LMI_CCITT_LINK_VERIFY_IE:
11210f74e101Schristos         case FR_LMI_ANSI_LINK_VERIFY_IE_91:
1122b3a00663Schristos             if (!ndo->ndo_vflag) {
1123c74ad251Schristos                 ND_PRINT(", ");
11240f74e101Schristos 	    }
1125dc860a36Sspz             if (ielength < 2) {
1126c74ad251Schristos                 ND_PRINT("Invalid LINK VERIFY IE");
1127dc860a36Sspz                 return 1;
1128dc860a36Sspz             }
1129c74ad251Schristos             ND_PRINT("TX Seq: %3d, RX Seq: %3d", GET_U_1(p), GET_U_1(p + 1));
11300f74e101Schristos             return 1;
11310f74e101Schristos 
11320f74e101Schristos         case FR_LMI_ANSI_PVC_STATUS_IE: /* fall through */
11330f74e101Schristos         case FR_LMI_CCITT_PVC_STATUS_IE:
1134b3a00663Schristos             if (!ndo->ndo_vflag) {
1135c74ad251Schristos                 ND_PRINT(", ");
11360f74e101Schristos 	    }
11370f74e101Schristos             /* now parse the DLCI information element. */
1138dc860a36Sspz             if ((ielength < 3) ||
1139c74ad251Schristos                 (GET_U_1(p) & 0x80) ||
1140c74ad251Schristos                 ((ielength == 3) && !(GET_U_1(p + 1) & 0x80)) ||
1141c74ad251Schristos                 ((ielength == 4) &&
1142c74ad251Schristos                   ((GET_U_1(p + 1) & 0x80) || !(GET_U_1(p + 2) & 0x80))) ||
1143c74ad251Schristos                 ((ielength == 5) &&
1144c74ad251Schristos                   ((GET_U_1(p + 1) & 0x80) || (GET_U_1(p + 2) & 0x80) ||
1145c74ad251Schristos                    !(GET_U_1(p + 3) & 0x80))) ||
1146dc860a36Sspz                 (ielength > 5) ||
1147c74ad251Schristos                 !(GET_U_1(p + ielength - 1) & 0x80)) {
1148c74ad251Schristos                 ND_PRINT("Invalid DLCI in PVC STATUS IE");
1149dc860a36Sspz                 return 1;
11500f74e101Schristos 	    }
11510f74e101Schristos 
1152c74ad251Schristos             dlci = ((GET_U_1(p) & 0x3F) << 4) | ((GET_U_1(p + 1) & 0x78) >> 3);
1153dc860a36Sspz             if (ielength == 4) {
1154c74ad251Schristos                 dlci = (dlci << 6) | ((GET_U_1(p + 2) & 0x7E) >> 1);
1155*26ba0b50Schristos 	    } else if (ielength == 5) {
1156c74ad251Schristos                 dlci = (dlci << 13) | (GET_U_1(p + 2) & 0x7F) | ((GET_U_1(p + 3) & 0x7E) >> 1);
11570f74e101Schristos 	    }
11580f74e101Schristos 
1159c74ad251Schristos             ND_PRINT("DLCI %u: status %s%s", dlci,
1160c74ad251Schristos                     GET_U_1(p + ielength - 1) & 0x8 ? "New, " : "",
1161c74ad251Schristos                     GET_U_1(p + ielength - 1) & 0x2 ? "Active" : "Inactive");
11620f74e101Schristos             return 1;
11630f74e101Schristos 	}
11640f74e101Schristos 
11650f74e101Schristos         return 0;
11660f74e101Schristos }
1167