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