xref: /netbsd-src/external/bsd/tcpdump/dist/print-fr.c (revision 26ba0b503b498a5194a71ac319838b7f5497f3fe)
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