Home | History | Annotate | Line # | Download | only in dist
      1 /*
      2  * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996
      3  *	The Regents of the University of California.  All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that: (1) source code distributions
      7  * retain the above copyright notice and this paragraph in its entirety, (2)
      8  * distributions including binary code include the above copyright notice and
      9  * this paragraph in its entirety in the documentation or other materials
     10  * provided with the distribution, and (3) all advertising materials mentioning
     11  * features or use of this software display the following acknowledgement:
     12  * ``This product includes software developed by the University of California,
     13  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
     14  * the University nor the names of its contributors may be used to endorse
     15  * or promote products derived from this software without specific prior
     16  * written permission.
     17  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
     18  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
     19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
     20  */
     21 
     22 #include <sys/cdefs.h>
     23 #ifndef lint
     24 __RCSID("$NetBSD: print-fr.c,v 1.12 2024/09/02 16:15:31 christos Exp $");
     25 #endif
     26 
     27 /* \summary: Frame Relay printer */
     28 
     29 #include <config.h>
     30 
     31 #include "netdissect-stdinc.h"
     32 
     33 #include <stdio.h>
     34 #include <string.h>
     35 
     36 #include "netdissect.h"
     37 #include "addrtoname.h"
     38 #include "ethertype.h"
     39 #include "llc.h"
     40 #include "nlpid.h"
     41 #include "extract.h"
     42 
     43 static void frf15_print(netdissect_options *ndo, const u_char *, u_int);
     44 
     45 /*
     46  * the frame relay header has a variable length
     47  *
     48  * the EA bit determines if there is another byte
     49  * in the header
     50  *
     51  * minimum header length is 2 bytes
     52  * maximum header length is 4 bytes
     53  *
     54  *      7    6    5    4    3    2    1    0
     55  *    +----+----+----+----+----+----+----+----+
     56  *    |        DLCI (6 bits)        | CR | EA |
     57  *    +----+----+----+----+----+----+----+----+
     58  *    |   DLCI (4 bits)   |FECN|BECN| DE | EA |
     59  *    +----+----+----+----+----+----+----+----+
     60  *    |           DLCI (7 bits)          | EA |
     61  *    +----+----+----+----+----+----+----+----+
     62  *    |        DLCI (6 bits)        |SDLC| EA |
     63  *    +----+----+----+----+----+----+----+----+
     64  */
     65 
     66 #define FR_EA_BIT	0x01
     67 
     68 #define FR_CR_BIT       0x02000000
     69 #define FR_DE_BIT	0x00020000
     70 #define FR_BECN_BIT	0x00040000
     71 #define FR_FECN_BIT	0x00080000
     72 #define FR_SDLC_BIT	0x00000002
     73 
     74 
     75 static const struct tok fr_header_flag_values[] = {
     76     { FR_CR_BIT, "C!" },
     77     { FR_DE_BIT, "DE" },
     78     { FR_BECN_BIT, "BECN" },
     79     { FR_FECN_BIT, "FECN" },
     80     { FR_SDLC_BIT, "sdlcore" },
     81     { 0, NULL }
     82 };
     83 
     84 /* FRF.15 / FRF.16 */
     85 #define MFR_B_BIT 0x80
     86 #define MFR_E_BIT 0x40
     87 #define MFR_C_BIT 0x20
     88 #define MFR_BEC_MASK    (MFR_B_BIT | MFR_E_BIT | MFR_C_BIT)
     89 #define MFR_CTRL_FRAME  (MFR_B_BIT | MFR_E_BIT | MFR_C_BIT)
     90 #define MFR_FRAG_FRAME  (MFR_B_BIT | MFR_E_BIT )
     91 
     92 static const struct tok frf_flag_values[] = {
     93     { MFR_B_BIT, "Begin" },
     94     { MFR_E_BIT, "End" },
     95     { MFR_C_BIT, "Control" },
     96     { 0, NULL }
     97 };
     98 
     99 /* Finds out Q.922 address length, DLCI and flags. Returns 1 on success,
    100  * 0 on invalid address, -1 on truncated packet
    101  * save the flags dep. on address length
    102  */
    103 static int parse_q922_header(netdissect_options *ndo,
    104                            const u_char *p, u_int *dlci,
    105                            u_int *addr_len, uint32_t *flags, u_int length)
    106 {
    107 	if (!ND_TTEST_1(p) || length < 1)
    108 		return -1;
    109 	if ((GET_U_1(p) & FR_EA_BIT))
    110 		return 0;
    111 
    112 	if (!ND_TTEST_1(p + 1) || length < 2)
    113 		return -1;
    114 	*addr_len = 2;
    115 	*dlci = ((GET_U_1(p) & 0xFC) << 2) | ((GET_U_1(p + 1) & 0xF0) >> 4);
    116 
    117 	*flags = ((GET_U_1(p) & 0x02) << 24) |	/* CR flag */
    118 		 ((GET_U_1(p + 1) & 0x0e) << 16);	/* FECN,BECN,DE flags */
    119 
    120 	if (GET_U_1(p + 1) & FR_EA_BIT)
    121 		return 1;	/* 2-byte Q.922 address */
    122 
    123 	p += 2;
    124 	length -= 2;
    125 	if (!ND_TTEST_1(p) || length < 1)
    126 		return -1;
    127 	(*addr_len)++;		/* 3- or 4-byte Q.922 address */
    128 	if ((GET_U_1(p) & FR_EA_BIT) == 0) {
    129 		*dlci = (*dlci << 7) | (GET_U_1(p) >> 1);
    130 		(*addr_len)++;	/* 4-byte Q.922 address */
    131 		p++;
    132 		length--;
    133 	}
    134 
    135 	if (!ND_TTEST_1(p) || length < 1)
    136 		return -1;
    137 	if ((GET_U_1(p) & FR_EA_BIT) == 0)
    138 		return 0; /* more than 4 bytes of Q.922 address? */
    139 
    140 	*flags = *flags | (GET_U_1(p) & 0x02);	/* SDLC flag */
    141 
    142         *dlci = (*dlci << 6) | (GET_U_1(p) >> 2);
    143 
    144 	return 1;
    145 }
    146 
    147 const char *
    148 q922_string(netdissect_options *ndo, const u_char *p, u_int length)
    149 {
    150 
    151     static u_int dlci, addr_len;
    152     static uint32_t flags;
    153     static char buffer[sizeof("parse_q922_header() returned XXXXXXXXXXX")];
    154     int ret;
    155     memset(buffer, 0, sizeof(buffer));
    156 
    157     ret = parse_q922_header(ndo, p, &dlci, &addr_len, &flags, length);
    158     if (ret == 1) {
    159         snprintf(buffer, sizeof(buffer), "DLCI %u", dlci);
    160         return buffer;
    161     } else if (ret == 0) {
    162         return "<Invalid DLCI>";
    163     } else if (ret == -1) {
    164         return "<Truncated>";
    165     } else {
    166         snprintf(buffer, sizeof(buffer), "parse_q922_header() returned %d", ret);
    167         return buffer;
    168     }
    169 }
    170 
    171 
    172 /* Frame Relay packet structure, with flags and CRC removed
    173 
    174                   +---------------------------+
    175                   |       Q.922 Address*      |
    176                   +--                       --+
    177                   |                           |
    178                   +---------------------------+
    179                   | Control (UI = 0x03)       |
    180                   +---------------------------+
    181                   | Optional Pad      (0x00)  |
    182                   +---------------------------+
    183                   | NLPID                     |
    184                   +---------------------------+
    185                   |             .             |
    186                   |             .             |
    187                   |             .             |
    188                   |           Data            |
    189                   |             .             |
    190                   |             .             |
    191                   +---------------------------+
    192 
    193            * Q.922 addresses, as presently defined, are two octets and
    194              contain a 10-bit DLCI.  In some networks Q.922 addresses
    195              may optionally be increased to three or four octets.
    196 */
    197 
    198 static void
    199 fr_hdr_print(netdissect_options *ndo, int length, u_int addr_len,
    200 	     u_int dlci, uint32_t flags, uint16_t nlpid)
    201 {
    202     if (ndo->ndo_qflag) {
    203         ND_PRINT("Q.922, DLCI %u, length %u: ",
    204                      dlci,
    205                      length);
    206     } else {
    207         if (nlpid <= 0xff) /* if its smaller than 256 then its a NLPID */
    208             ND_PRINT("Q.922, hdr-len %u, DLCI %u, Flags [%s], NLPID %s (0x%02x), length %u: ",
    209                          addr_len,
    210                          dlci,
    211                          bittok2str(fr_header_flag_values, "none", flags),
    212                          tok2str(nlpid_values,"unknown", nlpid),
    213                          nlpid,
    214                          length);
    215         else /* must be an ethertype */
    216             ND_PRINT("Q.922, hdr-len %u, DLCI %u, Flags [%s], cisco-ethertype %s (0x%04x), length %u: ",
    217                          addr_len,
    218                          dlci,
    219                          bittok2str(fr_header_flag_values, "none", flags),
    220                          tok2str(ethertype_values, "unknown", nlpid),
    221                          nlpid,
    222                          length);
    223     }
    224 }
    225 
    226 /* Frame Relay */
    227 void
    228 fr_if_print(netdissect_options *ndo,
    229             const struct pcap_pkthdr *h, const u_char *p)
    230 {
    231 	u_int length = h->len;
    232 	u_int caplen = h->caplen;
    233 
    234 	ndo->ndo_protocol = "fr";
    235 	if (caplen < 4) {	/* minimum frame header length */
    236 		nd_print_trunc(ndo);
    237 		ndo->ndo_ll_hdr_len += caplen;
    238 		return;
    239 	}
    240 
    241 	ndo->ndo_ll_hdr_len += fr_print(ndo, p, length);
    242 }
    243 
    244 u_int
    245 fr_print(netdissect_options *ndo,
    246          const u_char *p, u_int length)
    247 {
    248 	int ret;
    249 	uint16_t extracted_ethertype;
    250 	u_int dlci;
    251 	u_int addr_len;
    252 	uint16_t nlpid;
    253 	u_int hdr_len;
    254 	uint32_t flags;
    255 
    256 	ndo->ndo_protocol = "fr";
    257 	ret = parse_q922_header(ndo, p, &dlci, &addr_len, &flags, length);
    258 	if (ret == -1)
    259 		goto trunc;
    260 	if (ret == 0) {
    261 		ND_PRINT("Q.922, invalid address");
    262 		return 0;
    263 	}
    264 
    265 	ND_TCHECK_1(p + addr_len);
    266 	if (length < addr_len + 1)
    267 		goto trunc;
    268 
    269 	if (GET_U_1(p + addr_len) != LLC_UI && dlci != 0) {
    270                 /*
    271                  * Let's figure out if we have Cisco-style encapsulation,
    272                  * with an Ethernet type (Cisco HDLC type?) following the
    273                  * address.
    274                  */
    275 		if (!ND_TTEST_2(p + addr_len) || length < addr_len + 2) {
    276                         /* no Ethertype */
    277                         ND_PRINT("UI %02x! ", GET_U_1(p + addr_len));
    278                 } else {
    279                         extracted_ethertype = GET_BE_U_2(p + addr_len);
    280 
    281                         if (ndo->ndo_eflag)
    282                                 fr_hdr_print(ndo, length, addr_len, dlci,
    283                                     flags, extracted_ethertype);
    284 
    285                         if (ethertype_print(ndo, extracted_ethertype,
    286                                             p+addr_len+ETHERTYPE_LEN,
    287                                             length-addr_len-ETHERTYPE_LEN,
    288                                             ND_BYTES_AVAILABLE_AFTER(p)-addr_len-ETHERTYPE_LEN,
    289                                             NULL, NULL) == 0)
    290                                 /* ether_type not known, probably it wasn't one */
    291                                 ND_PRINT("UI %02x! ", GET_U_1(p + addr_len));
    292                         else
    293                                 return addr_len + 2;
    294                 }
    295         }
    296 
    297 	ND_TCHECK_1(p + addr_len + 1);
    298 	if (length < addr_len + 2)
    299 		goto trunc;
    300 
    301 	if (GET_U_1(p + addr_len + 1) == 0) {
    302 		/*
    303 		 * Assume a pad byte after the control (UI) byte.
    304 		 * A pad byte should only be used with 3-byte Q.922.
    305 		 */
    306 		if (addr_len != 3)
    307 			ND_PRINT("Pad! ");
    308 		hdr_len = addr_len + 1 /* UI */ + 1 /* pad */ + 1 /* NLPID */;
    309 	} else {
    310 		/*
    311 		 * Not a pad byte.
    312 		 * A pad byte should be used with 3-byte Q.922.
    313 		 */
    314 		if (addr_len == 3)
    315 			ND_PRINT("No pad! ");
    316 		hdr_len = addr_len + 1 /* UI */ + 1 /* NLPID */;
    317 	}
    318 
    319         ND_TCHECK_1(p + hdr_len - 1);
    320 	if (length < hdr_len)
    321 		goto trunc;
    322 	nlpid = GET_U_1(p + hdr_len - 1);
    323 
    324 	if (ndo->ndo_eflag)
    325 		fr_hdr_print(ndo, length, addr_len, dlci, flags, nlpid);
    326 	p += hdr_len;
    327 	length -= hdr_len;
    328 
    329 	switch (nlpid) {
    330 	case NLPID_IP:
    331 	        ip_print(ndo, p, length);
    332 		break;
    333 
    334 	case NLPID_IP6:
    335 		ip6_print(ndo, p, length);
    336 		break;
    337 
    338 	case NLPID_CLNP:
    339 	case NLPID_ESIS:
    340 	case NLPID_ISIS:
    341 		isoclns_print(ndo, p - 1, length + 1); /* OSI printers need the NLPID field */
    342 		break;
    343 
    344 	case NLPID_SNAP:
    345 		if (snap_print(ndo, p, length, ND_BYTES_AVAILABLE_AFTER(p), NULL, NULL, 0) == 0) {
    346 			/* ether_type not known, print raw packet */
    347                         if (!ndo->ndo_eflag)
    348                             fr_hdr_print(ndo, length + hdr_len, hdr_len,
    349                                          dlci, flags, nlpid);
    350 			if (!ndo->ndo_suppress_default_print)
    351 				ND_DEFAULTPRINT(p - hdr_len, length + hdr_len);
    352 		}
    353 		break;
    354 
    355         case NLPID_Q933:
    356 		q933_print(ndo, p, length);
    357 		break;
    358 
    359         case NLPID_MFR:
    360                 frf15_print(ndo, p, length);
    361                 break;
    362 
    363         case NLPID_PPP:
    364                 ppp_print(ndo, p, length);
    365                 break;
    366 
    367 	default:
    368 		if (!ndo->ndo_eflag)
    369                     fr_hdr_print(ndo, length + hdr_len, addr_len,
    370 				     dlci, flags, nlpid);
    371 		if (!ndo->ndo_xflag)
    372 			ND_DEFAULTPRINT(p, length);
    373 	}
    374 
    375 	return hdr_len;
    376 
    377 trunc:
    378         nd_print_trunc(ndo);
    379         return 0;
    380 
    381 }
    382 
    383 /* Multi Link Frame Relay (FRF.16) */
    384 void
    385 mfr_if_print(netdissect_options *ndo,
    386              const struct pcap_pkthdr *h, const u_char *p)
    387 {
    388 	u_int length = h->len;
    389 	u_int caplen = h->caplen;
    390 
    391 	ndo->ndo_protocol = "mfr";
    392 	if (caplen < 2) {	/* minimum frame header length */
    393 		nd_print_trunc(ndo);
    394 		ndo->ndo_ll_hdr_len += caplen;
    395 		return;
    396 	}
    397 
    398 	ndo->ndo_ll_hdr_len += mfr_print(ndo, p, length);
    399 }
    400 
    401 
    402 #define MFR_CTRL_MSG_ADD_LINK        1
    403 #define MFR_CTRL_MSG_ADD_LINK_ACK    2
    404 #define MFR_CTRL_MSG_ADD_LINK_REJ    3
    405 #define MFR_CTRL_MSG_HELLO           4
    406 #define MFR_CTRL_MSG_HELLO_ACK       5
    407 #define MFR_CTRL_MSG_REMOVE_LINK     6
    408 #define MFR_CTRL_MSG_REMOVE_LINK_ACK 7
    409 
    410 static const struct tok mfr_ctrl_msg_values[] = {
    411     { MFR_CTRL_MSG_ADD_LINK, "Add Link" },
    412     { MFR_CTRL_MSG_ADD_LINK_ACK, "Add Link ACK" },
    413     { MFR_CTRL_MSG_ADD_LINK_REJ, "Add Link Reject" },
    414     { MFR_CTRL_MSG_HELLO, "Hello" },
    415     { MFR_CTRL_MSG_HELLO_ACK, "Hello ACK" },
    416     { MFR_CTRL_MSG_REMOVE_LINK, "Remove Link" },
    417     { MFR_CTRL_MSG_REMOVE_LINK_ACK, "Remove Link ACK" },
    418     { 0, NULL }
    419 };
    420 
    421 #define MFR_CTRL_IE_BUNDLE_ID  1
    422 #define MFR_CTRL_IE_LINK_ID    2
    423 #define MFR_CTRL_IE_MAGIC_NUM  3
    424 #define MFR_CTRL_IE_TIMESTAMP  5
    425 #define MFR_CTRL_IE_VENDOR_EXT 6
    426 #define MFR_CTRL_IE_CAUSE      7
    427 
    428 static const struct tok mfr_ctrl_ie_values[] = {
    429     { MFR_CTRL_IE_BUNDLE_ID, "Bundle ID"},
    430     { MFR_CTRL_IE_LINK_ID, "Link ID"},
    431     { MFR_CTRL_IE_MAGIC_NUM, "Magic Number"},
    432     { MFR_CTRL_IE_TIMESTAMP, "Timestamp"},
    433     { MFR_CTRL_IE_VENDOR_EXT, "Vendor Extension"},
    434     { MFR_CTRL_IE_CAUSE, "Cause"},
    435     { 0, NULL }
    436 };
    437 
    438 #define MFR_ID_STRING_MAXLEN 50
    439 
    440 struct ie_tlv_header_t {
    441     uint8_t ie_type;
    442     uint8_t ie_len;
    443 };
    444 
    445 u_int
    446 mfr_print(netdissect_options *ndo,
    447           const u_char *p, u_int length)
    448 {
    449     u_int tlen,idx,hdr_len = 0;
    450     uint16_t sequence_num;
    451     uint8_t ie_type,ie_len;
    452     const uint8_t *tptr;
    453 
    454 
    455 /*
    456  * FRF.16 Link Integrity Control Frame
    457  *
    458  *      7    6    5    4    3    2    1    0
    459  *    +----+----+----+----+----+----+----+----+
    460  *    | B  | E  | C=1| 0    0    0    0  | EA |
    461  *    +----+----+----+----+----+----+----+----+
    462  *    | 0    0    0    0    0    0    0    0  |
    463  *    +----+----+----+----+----+----+----+----+
    464  *    |              message type             |
    465  *    +----+----+----+----+----+----+----+----+
    466  */
    467 
    468     ndo->ndo_protocol = "mfr";
    469 
    470     if (length < 4) {	/* minimum frame header length */
    471         ND_PRINT("[length %u < 4]", length);
    472         nd_print_invalid(ndo);
    473         return length;
    474     }
    475     ND_TCHECK_4(p);
    476 
    477     if ((GET_U_1(p) & MFR_BEC_MASK) == MFR_CTRL_FRAME && GET_U_1(p + 1) == 0) {
    478         ND_PRINT("FRF.16 Control, Flags [%s], %s, length %u",
    479                bittok2str(frf_flag_values,"none",(GET_U_1(p) & MFR_BEC_MASK)),
    480                tok2str(mfr_ctrl_msg_values,"Unknown Message (0x%02x)",GET_U_1(p + 2)),
    481                length);
    482         tptr = p + 3;
    483         tlen = length -3;
    484         hdr_len = 3;
    485 
    486         if (!ndo->ndo_vflag)
    487             return hdr_len;
    488 
    489         while (tlen>sizeof(struct ie_tlv_header_t)) {
    490             ND_TCHECK_LEN(tptr, sizeof(struct ie_tlv_header_t));
    491             ie_type=GET_U_1(tptr);
    492             ie_len=GET_U_1(tptr + 1);
    493 
    494             ND_PRINT("\n\tIE %s (%u), length %u: ",
    495                    tok2str(mfr_ctrl_ie_values,"Unknown",ie_type),
    496                    ie_type,
    497                    ie_len);
    498 
    499             /* infinite loop check */
    500             if (ie_type == 0 || ie_len <= sizeof(struct ie_tlv_header_t))
    501                 return hdr_len;
    502 
    503             ND_TCHECK_LEN(tptr, ie_len);
    504             tptr+=sizeof(struct ie_tlv_header_t);
    505             /* tlv len includes header */
    506             ie_len-=sizeof(struct ie_tlv_header_t);
    507             tlen-=sizeof(struct ie_tlv_header_t);
    508 
    509             switch (ie_type) {
    510 
    511             case MFR_CTRL_IE_MAGIC_NUM:
    512                 /* FRF.16.1 Section 3.4.3 Magic Number Information Element */
    513                 if (ie_len != 4) {
    514                     ND_PRINT("[IE data length %d != 4]", ie_len);
    515                     nd_print_invalid(ndo);
    516                     break;
    517                 }
    518                 ND_PRINT("0x%08x", GET_BE_U_4(tptr));
    519                 break;
    520 
    521             case MFR_CTRL_IE_BUNDLE_ID: /* same message format */
    522             case MFR_CTRL_IE_LINK_ID:
    523                 for (idx = 0; idx < ie_len && idx < MFR_ID_STRING_MAXLEN; idx++) {
    524                     if (GET_U_1(tptr + idx) != 0) /* don't print null termination */
    525                         fn_print_char(ndo, GET_U_1(tptr + idx));
    526                     else
    527                         break;
    528                 }
    529                 break;
    530 
    531             case MFR_CTRL_IE_TIMESTAMP:
    532                 /*
    533                  * FRF.16.1 Section 3.4.4 Timestamp Information Element
    534                  *
    535                  * The maximum length is 14 octets. Format is implementation
    536                  * specific.
    537                  */
    538                 if (ie_len > 14) {
    539                     ND_PRINT("[Timestamp IE length %d > 14]", ie_len);
    540                     nd_print_invalid(ndo);
    541                     break;
    542                 }
    543                 /* fall through and hexdump */
    544                 ND_FALL_THROUGH;
    545 
    546                 /*
    547                  * FIXME those are the defined IEs that lack a decoder
    548                  * you are welcome to contribute code ;-)
    549                  */
    550 
    551             case MFR_CTRL_IE_VENDOR_EXT:
    552             case MFR_CTRL_IE_CAUSE:
    553 
    554             default:
    555                 if (ndo->ndo_vflag <= 1)
    556                     print_unknown_data(ndo, tptr, "\n\t  ", ie_len);
    557                 break;
    558             }
    559 
    560             /* do we want to see a hexdump of the IE ? */
    561             if (ndo->ndo_vflag > 1 )
    562                 print_unknown_data(ndo, tptr, "\n\t  ", ie_len);
    563 
    564             tlen-=ie_len;
    565             tptr+=ie_len;
    566         }
    567         return hdr_len;
    568     }
    569 /*
    570  * FRF.16 Fragmentation Frame
    571  *
    572  *      7    6    5    4    3    2    1    0
    573  *    +----+----+----+----+----+----+----+----+
    574  *    | B  | E  | C=0|seq. (high 4 bits) | EA |
    575  *    +----+----+----+----+----+----+----+----+
    576  *    |        sequence  (low 8 bits)         |
    577  *    +----+----+----+----+----+----+----+----+
    578  *    |        DLCI (6 bits)        | CR | EA |
    579  *    +----+----+----+----+----+----+----+----+
    580  *    |   DLCI (4 bits)   |FECN|BECN| DE | EA |
    581  *    +----+----+----+----+----+----+----+----+
    582  */
    583 
    584     sequence_num = (GET_U_1(p)&0x1e)<<7 | GET_U_1(p + 1);
    585     /* whole packet or first fragment ? */
    586     if ((GET_U_1(p) & MFR_BEC_MASK) == MFR_FRAG_FRAME ||
    587         (GET_U_1(p) & MFR_BEC_MASK) == MFR_B_BIT) {
    588         ND_PRINT("FRF.16 Frag, seq %u, Flags [%s], ",
    589                sequence_num,
    590                bittok2str(frf_flag_values,"none",(GET_U_1(p) & MFR_BEC_MASK)));
    591         hdr_len = 2;
    592         fr_print(ndo, p+hdr_len,length-hdr_len);
    593         return hdr_len;
    594     }
    595 
    596     /* must be a middle or the last fragment */
    597     ND_PRINT("FRF.16 Frag, seq %u, Flags [%s]",
    598            sequence_num,
    599            bittok2str(frf_flag_values,"none",(GET_U_1(p) & MFR_BEC_MASK)));
    600     print_unknown_data(ndo, p, "\n\t", length);
    601 
    602     return hdr_len;
    603 
    604 trunc:
    605     nd_print_trunc(ndo);
    606     return length;
    607 }
    608 
    609 /* an NLPID of 0xb1 indicates a 2-byte
    610  * FRF.15 header
    611  *
    612  *      7    6    5    4    3    2    1    0
    613  *    +----+----+----+----+----+----+----+----+
    614  *    ~              Q.922 header             ~
    615  *    +----+----+----+----+----+----+----+----+
    616  *    |             NLPID (8 bits)            | NLPID=0xb1
    617  *    +----+----+----+----+----+----+----+----+
    618  *    | B  | E  | C  |seq. (high 4 bits) | R  |
    619  *    +----+----+----+----+----+----+----+----+
    620  *    |        sequence  (low 8 bits)         |
    621  *    +----+----+----+----+----+----+----+----+
    622  */
    623 
    624 #define FR_FRF15_FRAGTYPE 0x01
    625 
    626 static void
    627 frf15_print(netdissect_options *ndo,
    628             const u_char *p, u_int length)
    629 {
    630     uint16_t sequence_num, flags;
    631 
    632     if (length < 2)
    633         goto trunc;
    634 
    635     flags = GET_U_1(p)&MFR_BEC_MASK;
    636     sequence_num = (GET_U_1(p)&0x1e)<<7 | GET_U_1(p + 1);
    637 
    638     ND_PRINT("FRF.15, seq 0x%03x, Flags [%s],%s Fragmentation, length %u",
    639            sequence_num,
    640            bittok2str(frf_flag_values,"none",flags),
    641            GET_U_1(p)&FR_FRF15_FRAGTYPE ? "Interface" : "End-to-End",
    642            length);
    643 
    644 /* TODO:
    645  * depending on all permutations of the B, E and C bit
    646  * dig as deep as we can - e.g. on the first (B) fragment
    647  * there is enough payload to print the IP header
    648  * on non (B) fragments it depends if the fragmentation
    649  * model is end-to-end or interface based whether we want to print
    650  * another Q.922 header
    651  */
    652     return;
    653 
    654 trunc:
    655     nd_print_trunc(ndo);
    656 }
    657 
    658 /*
    659  * Q.933 decoding portion for framerelay specific.
    660  */
    661 
    662 /* Q.933 packet format
    663                       Format of Other Protocols
    664                           using Q.933 NLPID
    665                   +-------------------------------+
    666                   |        Q.922 Address          |
    667                   +---------------+---------------+
    668                   |Control  0x03  | NLPID   0x08  |
    669                   +---------------+---------------+
    670                   |          L2 Protocol ID       |
    671                   | octet 1       |  octet 2      |
    672                   +-------------------------------+
    673                   |          L3 Protocol ID       |
    674                   | octet 2       |  octet 2      |
    675                   +-------------------------------+
    676                   |         Protocol Data         |
    677                   +-------------------------------+
    678                   | FCS                           |
    679                   +-------------------------------+
    680  */
    681 
    682 /* L2 (Octet 1)- Call Reference Usually is 0x0 */
    683 
    684 /*
    685  * L2 (Octet 2)- Message Types definition 1 byte long.
    686  */
    687 /* Call Establish */
    688 #define MSG_TYPE_ESC_TO_NATIONAL  0x00
    689 #define MSG_TYPE_ALERT            0x01
    690 #define MSG_TYPE_CALL_PROCEEDING  0x02
    691 #define MSG_TYPE_CONNECT          0x07
    692 #define MSG_TYPE_CONNECT_ACK      0x0F
    693 #define MSG_TYPE_PROGRESS         0x03
    694 #define MSG_TYPE_SETUP            0x05
    695 /* Call Clear */
    696 #define MSG_TYPE_DISCONNECT       0x45
    697 #define MSG_TYPE_RELEASE          0x4D
    698 #define MSG_TYPE_RELEASE_COMPLETE 0x5A
    699 #define MSG_TYPE_RESTART          0x46
    700 #define MSG_TYPE_RESTART_ACK      0x4E
    701 /* Status */
    702 #define MSG_TYPE_STATUS           0x7D
    703 #define MSG_TYPE_STATUS_ENQ       0x75
    704 
    705 static const struct tok fr_q933_msg_values[] = {
    706     { MSG_TYPE_ESC_TO_NATIONAL, "ESC to National" },
    707     { MSG_TYPE_ALERT, "Alert" },
    708     { MSG_TYPE_CALL_PROCEEDING, "Call proceeding" },
    709     { MSG_TYPE_CONNECT, "Connect" },
    710     { MSG_TYPE_CONNECT_ACK, "Connect ACK" },
    711     { MSG_TYPE_PROGRESS, "Progress" },
    712     { MSG_TYPE_SETUP, "Setup" },
    713     { MSG_TYPE_DISCONNECT, "Disconnect" },
    714     { MSG_TYPE_RELEASE, "Release" },
    715     { MSG_TYPE_RELEASE_COMPLETE, "Release Complete" },
    716     { MSG_TYPE_RESTART, "Restart" },
    717     { MSG_TYPE_RESTART_ACK, "Restart ACK" },
    718     { MSG_TYPE_STATUS, "Status Reply" },
    719     { MSG_TYPE_STATUS_ENQ, "Status Enquiry" },
    720     { 0, NULL }
    721 };
    722 
    723 #define IE_IS_SINGLE_OCTET(iecode)	((iecode) & 0x80)
    724 #define IE_IS_SHIFT(iecode)		(((iecode) & 0xF0) == 0x90)
    725 #define IE_SHIFT_IS_NON_LOCKING(iecode)	((iecode) & 0x08)
    726 #define IE_SHIFT_IS_LOCKING(iecode)	(!(IE_SHIFT_IS_NON_LOCKING(iecode)))
    727 #define IE_SHIFT_CODESET(iecode)	((iecode) & 0x07)
    728 
    729 #define FR_LMI_ANSI_REPORT_TYPE_IE	0x01
    730 #define FR_LMI_ANSI_LINK_VERIFY_IE_91	0x19 /* details? */
    731 #define FR_LMI_ANSI_LINK_VERIFY_IE	0x03
    732 #define FR_LMI_ANSI_PVC_STATUS_IE	0x07
    733 
    734 #define FR_LMI_CCITT_REPORT_TYPE_IE	0x51
    735 #define FR_LMI_CCITT_LINK_VERIFY_IE	0x53
    736 #define FR_LMI_CCITT_PVC_STATUS_IE	0x57
    737 
    738 static const struct tok fr_q933_ie_values_codeset_0_5[] = {
    739     { FR_LMI_ANSI_REPORT_TYPE_IE, "ANSI Report Type" },
    740     { FR_LMI_ANSI_LINK_VERIFY_IE_91, "ANSI Link Verify" },
    741     { FR_LMI_ANSI_LINK_VERIFY_IE, "ANSI Link Verify" },
    742     { FR_LMI_ANSI_PVC_STATUS_IE, "ANSI PVC Status" },
    743     { FR_LMI_CCITT_REPORT_TYPE_IE, "CCITT Report Type" },
    744     { FR_LMI_CCITT_LINK_VERIFY_IE, "CCITT Link Verify" },
    745     { FR_LMI_CCITT_PVC_STATUS_IE, "CCITT PVC Status" },
    746     { 0, NULL }
    747 };
    748 
    749 #define FR_LMI_REPORT_TYPE_IE_FULL_STATUS 0
    750 #define FR_LMI_REPORT_TYPE_IE_LINK_VERIFY 1
    751 #define FR_LMI_REPORT_TYPE_IE_ASYNC_PVC   2
    752 
    753 static const struct tok fr_lmi_report_type_ie_values[] = {
    754     { FR_LMI_REPORT_TYPE_IE_FULL_STATUS, "Full Status" },
    755     { FR_LMI_REPORT_TYPE_IE_LINK_VERIFY, "Link verify" },
    756     { FR_LMI_REPORT_TYPE_IE_ASYNC_PVC, "Async PVC Status" },
    757     { 0, NULL }
    758 };
    759 
    760 /* array of 16 codesets - currently we only support codepage 0 and 5 */
    761 static const struct tok *fr_q933_ie_codesets[] = {
    762     fr_q933_ie_values_codeset_0_5,
    763     NULL,
    764     NULL,
    765     NULL,
    766     NULL,
    767     fr_q933_ie_values_codeset_0_5,
    768     NULL,
    769     NULL,
    770     NULL,
    771     NULL,
    772     NULL,
    773     NULL,
    774     NULL,
    775     NULL,
    776     NULL,
    777     NULL
    778 };
    779 
    780 static int fr_q933_print_ie_codeset_0_5(netdissect_options *ndo, u_int iecode,
    781     u_int ielength, const u_char *p);
    782 
    783 typedef int (*codeset_pr_func_t)(netdissect_options *, u_int iecode,
    784     u_int ielength, const u_char *p);
    785 
    786 /* array of 16 codesets - currently we only support codepage 0 and 5 */
    787 static const codeset_pr_func_t fr_q933_print_ie_codeset[] = {
    788     fr_q933_print_ie_codeset_0_5,
    789     NULL,
    790     NULL,
    791     NULL,
    792     NULL,
    793     fr_q933_print_ie_codeset_0_5,
    794     NULL,
    795     NULL,
    796     NULL,
    797     NULL,
    798     NULL,
    799     NULL,
    800     NULL,
    801     NULL,
    802     NULL,
    803     NULL
    804 };
    805 
    806 /*
    807  * ITU-T Q.933.
    808  *
    809  * p points to octet 2, the octet containing the length of the
    810  * call reference value, so p[n] is octet n+2 ("octet X" is as
    811  * used in Q.931/Q.933).
    812  *
    813  * XXX - actually used both for Q.931 and Q.933.
    814  */
    815 void
    816 q933_print(netdissect_options *ndo,
    817            const u_char *p, u_int length)
    818 {
    819 	u_int olen;
    820 	u_int call_ref_length, i;
    821 	uint8_t call_ref[15];	/* maximum length - length field is 4 bits */
    822 	u_int msgtype;
    823 	u_int iecode;
    824 	u_int ielength;
    825 	u_int codeset = 0;
    826 	u_int is_ansi = 0;
    827 	u_int ie_is_known;
    828 	u_int non_locking_shift;
    829 	u_int unshift_codeset;
    830 
    831 	ndo->ndo_protocol = "q.933";
    832 	ND_PRINT("%s", ndo->ndo_eflag ? "" : "Q.933");
    833 
    834 	if (length == 0 || !ND_TTEST_1(p)) {
    835 		if (!ndo->ndo_eflag)
    836 			ND_PRINT(", ");
    837 		ND_PRINT("length %u", length);
    838 		goto trunc;
    839 	}
    840 
    841 	/*
    842 	 * Get the length of the call reference value.
    843 	 */
    844 	olen = length; /* preserve the original length for display */
    845 	call_ref_length = GET_U_1(p) & 0x0f;
    846 	p++;
    847 	length--;
    848 
    849 	/*
    850 	 * Get the call reference value.
    851 	 */
    852 	for (i = 0; i < call_ref_length; i++) {
    853 		if (length == 0 || !ND_TTEST_1(p)) {
    854 			if (!ndo->ndo_eflag)
    855 				ND_PRINT(", ");
    856 			ND_PRINT("length %u", olen);
    857 			goto trunc;
    858 		}
    859 		call_ref[i] = GET_U_1(p);
    860 		p++;
    861 		length--;
    862 	}
    863 
    864 	/*
    865 	 * Get the message type.
    866 	 */
    867 	if (length == 0 || !ND_TTEST_1(p)) {
    868 		if (!ndo->ndo_eflag)
    869 			ND_PRINT(", ");
    870 		ND_PRINT("length %u", olen);
    871 		goto trunc;
    872 	}
    873 	msgtype = GET_U_1(p);
    874 	p++;
    875 	length--;
    876 
    877 	/*
    878 	 * Peek ahead to see if we start with a shift.
    879 	 */
    880 	non_locking_shift = 0;
    881 	unshift_codeset = codeset;
    882 	if (length != 0) {
    883 		if (!ND_TTEST_1(p)) {
    884 			if (!ndo->ndo_eflag)
    885 				ND_PRINT(", ");
    886 			ND_PRINT("length %u", olen);
    887 			goto trunc;
    888 		}
    889 		iecode = GET_U_1(p);
    890 		if (IE_IS_SHIFT(iecode)) {
    891 			/*
    892 			 * It's a shift.  Skip over it.
    893 			 */
    894 			p++;
    895 			length--;
    896 
    897 			/*
    898 			 * Get the codeset.
    899 			 */
    900 			codeset = IE_SHIFT_CODESET(iecode);
    901 
    902 			/*
    903 			 * If it's a locking shift to codeset 5,
    904 			 * mark this as ANSI.  (XXX - 5 is actually
    905 			 * for national variants in general, not
    906 			 * the US variant in particular, but maybe
    907 			 * this is more American exceptionalism. :-))
    908 			 */
    909 			if (IE_SHIFT_IS_LOCKING(iecode)) {
    910 				/*
    911 				 * It's a locking shift.
    912 				 */
    913 				if (codeset == 5) {
    914 					/*
    915 					 * It's a locking shift to
    916 					 * codeset 5, so this is
    917 					 * T1.617 Annex D.
    918 					 */
    919 					is_ansi = 1;
    920 				}
    921 			} else {
    922 				/*
    923 				 * It's a non-locking shift.
    924 				 * Remember the current codeset, so we
    925 				 * can revert to it after the next IE.
    926 				 */
    927 				non_locking_shift = 1;
    928 				unshift_codeset = 0;
    929 			}
    930 		}
    931 	}
    932 
    933 	/* printing out header part */
    934 	if (!ndo->ndo_eflag)
    935 		ND_PRINT(", ");
    936 	ND_PRINT("%s, codeset %u", is_ansi ? "ANSI" : "CCITT", codeset);
    937 
    938 	if (call_ref_length != 0) {
    939 		if (call_ref_length > 1 || GET_U_1(p) != 0) {
    940 			/*
    941 			 * Not a dummy call reference.
    942 			 */
    943 			ND_PRINT(", Call Ref: 0x");
    944 			for (i = 0; i < call_ref_length; i++)
    945 				ND_PRINT("%02x", call_ref[i]);
    946 		}
    947 	}
    948 	if (ndo->ndo_vflag) {
    949 		ND_PRINT(", %s (0x%02x), length %u",
    950 		   tok2str(fr_q933_msg_values,
    951 			"unknown message", msgtype),
    952 		   msgtype,
    953 		   olen);
    954 	} else {
    955 		ND_PRINT(", %s",
    956 		       tok2str(fr_q933_msg_values,
    957 			       "unknown message 0x%02x", msgtype));
    958 	}
    959 
    960 	/* Loop through the rest of the IEs */
    961 	while (length != 0) {
    962 		/*
    963 		 * What's the state of any non-locking shifts?
    964 		 */
    965 		if (non_locking_shift == 1) {
    966 			/*
    967 			 * There's a non-locking shift in effect for
    968 			 * this IE.  Count it, so we reset the codeset
    969 			 * before the next IE.
    970 			 */
    971 			non_locking_shift = 2;
    972 		} else if (non_locking_shift == 2) {
    973 			/*
    974 			 * Unshift.
    975 			 */
    976 			codeset = unshift_codeset;
    977 			non_locking_shift = 0;
    978 		}
    979 
    980 		/*
    981 		 * Get the first octet of the IE.
    982 		 */
    983 		if (!ND_TTEST_1(p)) {
    984 			if (!ndo->ndo_vflag) {
    985 				ND_PRINT(", length %u", olen);
    986 			}
    987 			goto trunc;
    988 		}
    989 		iecode = GET_U_1(p);
    990 		p++;
    991 		length--;
    992 
    993 		/* Single-octet IE? */
    994 		if (IE_IS_SINGLE_OCTET(iecode)) {
    995 			/*
    996 			 * Yes.  Is it a shift?
    997 			 */
    998 			if (IE_IS_SHIFT(iecode)) {
    999 				/*
   1000 				 * Yes.  Is it locking?
   1001 				 */
   1002 				if (IE_SHIFT_IS_LOCKING(iecode)) {
   1003 					/*
   1004 					 * Yes.
   1005 					 */
   1006 					non_locking_shift = 0;
   1007 				} else {
   1008 					/*
   1009 					 * No.  Remember the current
   1010 					 * codeset, so we can revert
   1011 					 * to it after the next IE.
   1012 					 */
   1013 					non_locking_shift = 1;
   1014 					unshift_codeset = codeset;
   1015 				}
   1016 
   1017 				/*
   1018 				 * Get the codeset.
   1019 				 */
   1020 				codeset = IE_SHIFT_CODESET(iecode);
   1021 			}
   1022 		} else {
   1023 			/*
   1024 			 * No.  Get the IE length.
   1025 			 */
   1026 			if (length == 0 || !ND_TTEST_1(p)) {
   1027 				if (!ndo->ndo_vflag) {
   1028 					ND_PRINT(", length %u", olen);
   1029 				}
   1030 				goto trunc;
   1031 			}
   1032 			ielength = GET_U_1(p);
   1033 			p++;
   1034 			length--;
   1035 
   1036 			/* lets do the full IE parsing only in verbose mode
   1037 			 * however some IEs (DLCI Status, Link Verify)
   1038 			 * are also interesting in non-verbose mode */
   1039 			if (ndo->ndo_vflag) {
   1040 				ND_PRINT("\n\t%s IE (0x%02x), length %u: ",
   1041 				    tok2str(fr_q933_ie_codesets[codeset],
   1042 					"unknown", iecode),
   1043 				    iecode,
   1044 				    ielength);
   1045 			}
   1046 
   1047 			/* sanity checks */
   1048 			if (iecode == 0 || ielength == 0) {
   1049 				return;
   1050 			}
   1051 			if (length < ielength || !ND_TTEST_LEN(p, ielength)) {
   1052 				if (!ndo->ndo_vflag) {
   1053 					ND_PRINT(", length %u", olen);
   1054 				}
   1055 				goto trunc;
   1056 			}
   1057 
   1058 			ie_is_known = 0;
   1059 			if (fr_q933_print_ie_codeset[codeset] != NULL) {
   1060 				ie_is_known = fr_q933_print_ie_codeset[codeset](ndo, iecode, ielength, p);
   1061 			}
   1062 
   1063 			if (ie_is_known) {
   1064 				/*
   1065 				 * Known IE; do we want to see a hexdump
   1066 				 * of it?
   1067 				 */
   1068 				if (ndo->ndo_vflag > 1) {
   1069 					/* Yes. */
   1070 					print_unknown_data(ndo, p, "\n\t  ", ielength);
   1071 				}
   1072 			} else {
   1073 				/*
   1074 				 * Unknown IE; if we're printing verbosely,
   1075 				 * print its content in hex.
   1076 				 */
   1077 				if (ndo->ndo_vflag >= 1) {
   1078 					print_unknown_data(ndo, p, "\n\t", ielength);
   1079 				}
   1080 			}
   1081 
   1082 			length -= ielength;
   1083 			p += ielength;
   1084 		}
   1085 	}
   1086 	if (!ndo->ndo_vflag) {
   1087 	    ND_PRINT(", length %u", olen);
   1088 	}
   1089 	return;
   1090 
   1091 trunc:
   1092 	nd_print_trunc(ndo);
   1093 }
   1094 
   1095 static int
   1096 fr_q933_print_ie_codeset_0_5(netdissect_options *ndo, u_int iecode,
   1097                           u_int ielength, const u_char *p)
   1098 {
   1099         u_int dlci;
   1100 
   1101         switch (iecode) {
   1102 
   1103         case FR_LMI_ANSI_REPORT_TYPE_IE: /* fall through */
   1104         case FR_LMI_CCITT_REPORT_TYPE_IE:
   1105             if (ielength < 1) {
   1106                 if (!ndo->ndo_vflag) {
   1107                     ND_PRINT(", ");
   1108 	        }
   1109                 ND_PRINT("Invalid REPORT TYPE IE");
   1110                 return 1;
   1111             }
   1112             if (ndo->ndo_vflag) {
   1113                 ND_PRINT("%s (%u)",
   1114                        tok2str(fr_lmi_report_type_ie_values,"unknown",GET_U_1(p)),
   1115                        GET_U_1(p));
   1116 	    }
   1117             return 1;
   1118 
   1119         case FR_LMI_ANSI_LINK_VERIFY_IE: /* fall through */
   1120         case FR_LMI_CCITT_LINK_VERIFY_IE:
   1121         case FR_LMI_ANSI_LINK_VERIFY_IE_91:
   1122             if (!ndo->ndo_vflag) {
   1123                 ND_PRINT(", ");
   1124 	    }
   1125             if (ielength < 2) {
   1126                 ND_PRINT("Invalid LINK VERIFY IE");
   1127                 return 1;
   1128             }
   1129             ND_PRINT("TX Seq: %3d, RX Seq: %3d", GET_U_1(p), GET_U_1(p + 1));
   1130             return 1;
   1131 
   1132         case FR_LMI_ANSI_PVC_STATUS_IE: /* fall through */
   1133         case FR_LMI_CCITT_PVC_STATUS_IE:
   1134             if (!ndo->ndo_vflag) {
   1135                 ND_PRINT(", ");
   1136 	    }
   1137             /* now parse the DLCI information element. */
   1138             if ((ielength < 3) ||
   1139                 (GET_U_1(p) & 0x80) ||
   1140                 ((ielength == 3) && !(GET_U_1(p + 1) & 0x80)) ||
   1141                 ((ielength == 4) &&
   1142                   ((GET_U_1(p + 1) & 0x80) || !(GET_U_1(p + 2) & 0x80))) ||
   1143                 ((ielength == 5) &&
   1144                   ((GET_U_1(p + 1) & 0x80) || (GET_U_1(p + 2) & 0x80) ||
   1145                    !(GET_U_1(p + 3) & 0x80))) ||
   1146                 (ielength > 5) ||
   1147                 !(GET_U_1(p + ielength - 1) & 0x80)) {
   1148                 ND_PRINT("Invalid DLCI in PVC STATUS IE");
   1149                 return 1;
   1150 	    }
   1151 
   1152             dlci = ((GET_U_1(p) & 0x3F) << 4) | ((GET_U_1(p + 1) & 0x78) >> 3);
   1153             if (ielength == 4) {
   1154                 dlci = (dlci << 6) | ((GET_U_1(p + 2) & 0x7E) >> 1);
   1155 	    } else if (ielength == 5) {
   1156                 dlci = (dlci << 13) | (GET_U_1(p + 2) & 0x7F) | ((GET_U_1(p + 3) & 0x7E) >> 1);
   1157 	    }
   1158 
   1159             ND_PRINT("DLCI %u: status %s%s", dlci,
   1160                     GET_U_1(p + ielength - 1) & 0x8 ? "New, " : "",
   1161                     GET_U_1(p + ielength - 1) & 0x2 ? "Active" : "Inactive");
   1162             return 1;
   1163 	}
   1164 
   1165         return 0;
   1166 }
   1167