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