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