print-fr.c revision 162021
1139823Simp/*
275374Sbp * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996
375374Sbp *	The Regents of the University of California.  All rights reserved.
475374Sbp *
575374Sbp * Redistribution and use in source and binary forms, with or without
675374Sbp * modification, are permitted provided that: (1) source code distributions
775374Sbp * retain the above copyright notice and this paragraph in its entirety, (2)
875374Sbp * distributions including binary code include the above copyright notice and
975374Sbp * this paragraph in its entirety in the documentation or other materials
1075374Sbp * provided with the distribution, and (3) all advertising materials mentioning
1175374Sbp * features or use of this software display the following acknowledgement:
1275374Sbp * ``This product includes software developed by the University of California,
1375374Sbp * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1475374Sbp * the University nor the names of its contributors may be used to endorse
1575374Sbp * or promote products derived from this software without specific prior
1675374Sbp * written permission.
1775374Sbp * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1875374Sbp * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1975374Sbp * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2075374Sbp *
2175374Sbp * $FreeBSD: head/contrib/tcpdump/print-fr.c 162021 2006-09-04 20:25:04Z sam $
2275374Sbp */
2375374Sbp
2475374Sbp#ifndef lint
2575374Sbpstatic const char rcsid[] _U_ =
2675374Sbp	"@(#)$Header: /tcpdump/master/tcpdump/print-fr.c,v 1.32.2.12 2005/08/23 03:15:51 guy Exp $ (LBL)";
2775374Sbp#endif
2875374Sbp
2975374Sbp#ifdef HAVE_CONFIG_H
3075374Sbp#include "config.h"
3175374Sbp#endif
3275374Sbp
3375374Sbp#include <tcpdump-stdinc.h>
3475374Sbp
3575374Sbp#include <stdio.h>
3675374Sbp#include <string.h>
3775374Sbp#include <pcap.h>
3875374Sbp
3975374Sbp#include "addrtoname.h"
4075374Sbp#include "interface.h"
4175374Sbp#include "ethertype.h"
4275374Sbp#include "nlpid.h"
4375374Sbp#include "extract.h"
4475374Sbp#include "oui.h"
4587599Sobrien
4687599Sobrienstatic void frf15_print(const u_char *, u_int);
4775374Sbp
4875374Sbp/*
4987599Sobrien * the frame relay header has a variable length
5075374Sbp *
5175374Sbp * the EA bit determines if there is another byte
5275374Sbp * in the header
5375374Sbp *
5475374Sbp * minimum header length is 2 bytes
5587599Sobrien * maximum header length is 4 bytes
5675374Sbp *
5775374Sbp *      7    6    5    4    3    2    1    0
5875374Sbp *    +----+----+----+----+----+----+----+----+
5975374Sbp *    |        DLCI (6 bits)        | CR | EA |
6075374Sbp *    +----+----+----+----+----+----+----+----+
6175374Sbp *    |   DLCI (4 bits)   |FECN|BECN| DE | EA |
6275374Sbp *    +----+----+----+----+----+----+----+----+
6375374Sbp *    |           DLCI (7 bits)          | EA |
6475374Sbp *    +----+----+----+----+----+----+----+----+
6575374Sbp *    |        DLCI (6 bits)        |SDLC| EA |
6675374Sbp *    +----+----+----+----+----+----+----+----+
6775374Sbp */
6875374Sbp
6975374Sbp#define FR_EA_BIT	0x01
7075374Sbp
7193593Sjhb#define FR_CR_BIT       0x02000000
7275374Sbp#define FR_DE_BIT	0x00020000
7375374Sbp#define FR_BECN_BIT	0x00040000
7475374Sbp#define FR_FECN_BIT	0x00080000
7575374Sbp#define FR_SDLC_BIT	0x00000002
7675374Sbp
77102481Sbde
7875374Sbpstruct tok fr_header_flag_values[] = {
7975374Sbp    { FR_CR_BIT, "C!" },
8075374Sbp    { FR_DE_BIT, "DE" },
8193818Sjhb    { FR_BECN_BIT, "BECN" },
8275374Sbp    { FR_FECN_BIT, "FECN" },
8375374Sbp    { FR_SDLC_BIT, "sdlcore" },
8475374Sbp    { 0, NULL }
8575374Sbp};
8675374Sbp
8775374Sbp/* FRF.15 / FRF.16 */
8875374Sbp#define MFR_B_BIT 0x80
8975374Sbp#define MFR_E_BIT 0x40
9075374Sbp#define MFR_C_BIT 0x20
9175374Sbp#define MFR_BEC_MASK    (MFR_B_BIT | MFR_E_BIT | MFR_C_BIT)
9275374Sbp#define MFR_CTRL_FRAME  (MFR_B_BIT | MFR_E_BIT | MFR_C_BIT)
9375374Sbp#define MFR_FRAG_FRAME  (MFR_B_BIT | MFR_E_BIT )
9475374Sbp
9575374Sbpstruct tok frf_flag_values[] = {
9687192Sbp    { MFR_B_BIT, "Begin" },
9775374Sbp    { MFR_E_BIT, "End" },
9875374Sbp    { MFR_C_BIT, "Control" },
9975374Sbp    { 0, NULL }
10075374Sbp};
10175374Sbp
10275374Sbp/* Finds out Q.922 address length, DLCI and flags. Returns 0 on success
10375374Sbp * save the flags dep. on address length
10475374Sbp */
10575374Sbpstatic int parse_q922_addr(const u_char *p, u_int *dlci, u_int *sdlcore,
10687192Sbp                           u_int *addr_len, u_int8_t *flags)
107112888Sjeff{
10875374Sbp	if ((p[0] & FR_EA_BIT))
10975374Sbp		return -1;
11075374Sbp
11175374Sbp	*addr_len = 2;
11275374Sbp	*dlci = ((p[0] & 0xFC) << 2) | ((p[1] & 0xF0) >> 4);
11375374Sbp
11475374Sbp        flags[0] = p[0] & 0x02; /* populate the first flag fields */
11575374Sbp        flags[1] = p[1] & 0x0c;
11675374Sbp
117124087Stjr	if (p[1] & FR_EA_BIT)
11875374Sbp		return 0;	/* 2-byte Q.922 address */
11975374Sbp
12075374Sbp	p += 2;
12175374Sbp	(*addr_len)++;		/* 3- or 4-byte Q.922 address */
12275374Sbp	if ((p[0] & FR_EA_BIT) == 0) {
12375374Sbp		*dlci = (*dlci << 7) | (p[0] >> 1);
12475374Sbp		(*addr_len)++;	/* 4-byte Q.922 address */
12575374Sbp		p++;
12675374Sbp	}
127124087Stjr
128124087Stjr	if ((p[0] & FR_EA_BIT) == 0)
12975374Sbp		return -1; /* more than 4 bytes of Q.922 address? */
13075374Sbp
131        flags[3] = p[0] & 0x02;
132
133	if (p[0] & 0x02)
134                *sdlcore =  p[0] >> 2;
135	else
136		*dlci = (*dlci << 6) | (p[0] >> 2);
137
138	return 0;
139}
140
141/* Frame Relay packet structure, with flags and CRC removed
142
143                  +---------------------------+
144                  |       Q.922 Address*      |
145                  +--                       --+
146                  |                           |
147                  +---------------------------+
148                  | Control (UI = 0x03)       |
149                  +---------------------------+
150                  | Optional Pad      (0x00)  |
151                  +---------------------------+
152                  | NLPID                     |
153                  +---------------------------+
154                  |             .             |
155                  |             .             |
156                  |             .             |
157                  |           Data            |
158                  |             .             |
159                  |             .             |
160                  +---------------------------+
161
162           * Q.922 addresses, as presently defined, are two octets and
163             contain a 10-bit DLCI.  In some networks Q.922 addresses
164             may optionally be increased to three or four octets.
165*/
166
167static u_int
168fr_hdrlen(const u_char *p, u_int addr_len)
169{
170	if (!p[addr_len + 1] /* pad exist */)
171		return addr_len + 1 /* UI */ + 1 /* pad */ + 1 /* NLPID */;
172	else
173		return addr_len + 1 /* UI */ + 1 /* NLPID */;
174}
175
176static void
177fr_hdr_print(int length, u_int addr_len, u_int dlci, u_int8_t *flags, u_int16_t nlpid)
178{
179    if (qflag) {
180        (void)printf("Q.922, DLCI %u, length %u: ",
181                     dlci,
182                     length);
183    } else {
184        if (nlpid <= 0xff) /* if its smaller than 256 then its a NLPID */
185            (void)printf("Q.922, hdr-len %u, DLCI %u, Flags [%s], NLPID %s (0x%02x), length %u: ",
186                         addr_len,
187                         dlci,
188                         bittok2str(fr_header_flag_values, "none", EXTRACT_32BITS(flags)),
189                         tok2str(nlpid_values,"unknown", nlpid),
190                         nlpid,
191                         length);
192        else /* must be an ethertype */
193            (void)printf("Q.922, hdr-len %u, DLCI %u, Flags [%s], cisco-ethertype %s (0x%04x), length %u: ",
194                         addr_len,
195                         dlci,
196                         bittok2str(fr_header_flag_values, "none", EXTRACT_32BITS(flags)),
197                         tok2str(ethertype_values, "unknown", nlpid),
198                         nlpid,
199                         length);
200    }
201}
202
203u_int
204fr_if_print(const struct pcap_pkthdr *h, register const u_char *p)
205{
206	register u_int length = h->len;
207	register u_int caplen = h->caplen;
208
209        TCHECK2(*p, 4); /* minimum frame header length */
210
211        if ((length = fr_print(p, length)) == 0)
212            return (0);
213        else
214            return length;
215 trunc:
216        printf("[|fr]");
217        return caplen;
218}
219
220u_int
221fr_print(register const u_char *p, u_int length)
222{
223	u_int16_t extracted_ethertype;
224	u_int dlci;
225        u_int sdlcore;
226	u_int addr_len;
227	u_int16_t nlpid;
228	u_int hdr_len;
229	u_int8_t flags[4];
230
231	if (parse_q922_addr(p, &dlci, &sdlcore, &addr_len, flags)) {
232		printf("Q.922, invalid address");
233		return 0;
234	}
235
236        TCHECK2(*p,addr_len+1+1);
237	hdr_len = fr_hdrlen(p, addr_len);
238        TCHECK2(*p,hdr_len);
239
240	if (p[addr_len] != 0x03 && dlci != 0) {
241
242                /* lets figure out if we have cisco style encapsulation: */
243                extracted_ethertype = EXTRACT_16BITS(p+addr_len);
244
245                if (eflag)
246                    fr_hdr_print(length, addr_len, dlci, flags, extracted_ethertype);
247
248                if (ether_encap_print(extracted_ethertype,
249                                      p+addr_len+ETHERTYPE_LEN,
250                                      length-addr_len-ETHERTYPE_LEN,
251                                      length-addr_len-ETHERTYPE_LEN,
252                                      &extracted_ethertype) == 0)
253                    /* ether_type not known, probably it wasn't one */
254                    printf("UI %02x! ", p[addr_len]);
255                else
256                    return hdr_len;
257        }
258
259	if (!p[addr_len + 1]) {	/* pad byte should be used with 3-byte Q.922 */
260		if (addr_len != 3)
261			printf("Pad! ");
262	} else if (addr_len == 3)
263		printf("No pad! ");
264
265	nlpid = p[hdr_len - 1];
266
267	if (eflag)
268		fr_hdr_print(length, addr_len, dlci, flags, nlpid);
269	p += hdr_len;
270	length -= hdr_len;
271
272	switch (nlpid) {
273	case NLPID_IP:
274	        ip_print(gndo, p, length);
275		break;
276
277#ifdef INET6
278	case NLPID_IP6:
279		ip6_print(p, length);
280		break;
281#endif
282	case NLPID_CLNP:
283	case NLPID_ESIS:
284	case NLPID_ISIS:
285                isoclns_print(p-1, length+1, length+1); /* OSI printers need the NLPID field */
286		break;
287
288	case NLPID_SNAP:
289		if (snap_print(p, length, length, &extracted_ethertype, 0) == 0) {
290			/* ether_type not known, print raw packet */
291                        if (!eflag)
292                            fr_hdr_print(length + hdr_len, hdr_len,
293                                         dlci, flags, nlpid);
294			if (!suppress_default_print)
295                            default_print(p - hdr_len, length + hdr_len);
296		}
297		break;
298
299        case NLPID_Q933:
300		q933_print(p, length);
301		break;
302
303        case NLPID_MFR:
304                frf15_print(p, length);
305                break;
306
307	default:
308		if (!eflag)
309                    fr_hdr_print(length + hdr_len, addr_len,
310				     dlci, flags, nlpid);
311		if (!xflag)
312			default_print(p, length);
313	}
314
315	return hdr_len;
316
317 trunc:
318        printf("[|fr]");
319        return 0;
320
321}
322
323#define MFR_CTRL_MSG_ADD_LINK        1
324#define MFR_CTRL_MSG_ADD_LINK_ACK    2
325#define MFR_CTRL_MSG_ADD_LINK_REJ    3
326#define MFR_CTRL_MSG_HELLO           4
327#define MFR_CTRL_MSG_HELLO_ACK       5
328#define MFR_CTRL_MSG_REMOVE_LINK     6
329#define MFR_CTRL_MSG_REMOVE_LINK_ACK 7
330
331struct tok mfr_ctrl_msg_values[] = {
332    { MFR_CTRL_MSG_ADD_LINK, "Add Link" },
333    { MFR_CTRL_MSG_ADD_LINK_ACK, "Add Link ACK" },
334    { MFR_CTRL_MSG_ADD_LINK_REJ, "Add Link Reject" },
335    { MFR_CTRL_MSG_HELLO, "Hello" },
336    { MFR_CTRL_MSG_HELLO_ACK, "Hello ACK" },
337    { MFR_CTRL_MSG_REMOVE_LINK, "Remove Link" },
338    { MFR_CTRL_MSG_REMOVE_LINK_ACK, "Remove Link ACK" },
339    { 0, NULL }
340};
341
342#define MFR_CTRL_IE_BUNDLE_ID  1
343#define MFR_CTRL_IE_LINK_ID    2
344#define MFR_CTRL_IE_MAGIC_NUM  3
345#define MFR_CTRL_IE_TIMESTAMP  5
346#define MFR_CTRL_IE_VENDOR_EXT 6
347#define MFR_CTRL_IE_CAUSE      7
348
349struct tok mfr_ctrl_ie_values[] = {
350    { MFR_CTRL_IE_BUNDLE_ID, "Bundle ID"},
351    { MFR_CTRL_IE_LINK_ID, "Link ID"},
352    { MFR_CTRL_IE_MAGIC_NUM, "Magic Number"},
353    { MFR_CTRL_IE_TIMESTAMP, "Timestamp"},
354    { MFR_CTRL_IE_VENDOR_EXT, "Vendor Extension"},
355    { MFR_CTRL_IE_CAUSE, "Cause"},
356    { 0, NULL }
357};
358
359#define MFR_ID_STRING_MAXLEN 50
360
361struct ie_tlv_header_t {
362    u_int8_t ie_type;
363    u_int8_t ie_len;
364};
365
366u_int
367mfr_print(register const u_char *p, u_int length)
368{
369    u_int tlen,idx,hdr_len = 0;
370    u_int16_t sequence_num;
371    u_int8_t ie_type,ie_len;
372    const u_int8_t *tptr;
373
374
375/*
376 * FRF.16 Link Integrity Control Frame
377 *
378 *      7    6    5    4    3    2    1    0
379 *    +----+----+----+----+----+----+----+----+
380 *    | B  | E  | C=1| 0    0    0    0  | EA |
381 *    +----+----+----+----+----+----+----+----+
382 *    | 0    0    0    0    0    0    0    0  |
383 *    +----+----+----+----+----+----+----+----+
384 *    |              message type             |
385 *    +----+----+----+----+----+----+----+----+
386 */
387
388    TCHECK2(*p, 4); /* minimum frame header length */
389
390    if ((p[0] & MFR_BEC_MASK) == MFR_CTRL_FRAME && p[1] == 0) {
391        printf("FRF.16 Control, Flags [%s], %s, length %u",
392               bittok2str(frf_flag_values,"none",(p[0] & MFR_BEC_MASK)),
393               tok2str(mfr_ctrl_msg_values,"Unknown Message (0x%02x)",p[2]),
394               length);
395        tptr = p + 3;
396        tlen = length -3;
397        hdr_len = 3;
398
399        if (!vflag)
400            return hdr_len;
401
402        while (tlen>sizeof(struct ie_tlv_header_t)) {
403            TCHECK2(*tptr, sizeof(struct ie_tlv_header_t));
404            ie_type=tptr[0];
405            ie_len=tptr[1];
406
407            printf("\n\tIE %s (%u), length %u: ",
408                   tok2str(mfr_ctrl_ie_values,"Unknown",ie_type),
409                   ie_type,
410                   ie_len);
411
412            /* infinite loop check */
413            if (ie_type == 0 || ie_len <= sizeof(struct ie_tlv_header_t))
414                return hdr_len;
415
416            TCHECK2(*tptr,ie_len);
417            tptr+=sizeof(struct ie_tlv_header_t);
418            /* tlv len includes header */
419            ie_len-=sizeof(struct ie_tlv_header_t);
420            tlen-=sizeof(struct ie_tlv_header_t);
421
422            switch (ie_type) {
423
424            case MFR_CTRL_IE_MAGIC_NUM:
425                printf("0x%08x",EXTRACT_32BITS(tptr));
426                break;
427
428            case MFR_CTRL_IE_BUNDLE_ID: /* same message format */
429            case MFR_CTRL_IE_LINK_ID:
430                for (idx = 0; idx < ie_len && idx < MFR_ID_STRING_MAXLEN; idx++) {
431                    if (*(tptr+idx) != 0) /* don't print null termination */
432                        safeputchar(*(tptr+idx));
433                    else
434                        break;
435                }
436                break;
437
438            case MFR_CTRL_IE_TIMESTAMP:
439                if (ie_len == sizeof(struct timeval)) {
440                    ts_print((const struct timeval *)tptr);
441                    break;
442                }
443                /* fall through and hexdump if no unix timestamp */
444
445                /*
446                 * FIXME those are the defined IEs that lack a decoder
447                 * you are welcome to contribute code ;-)
448                 */
449
450            case MFR_CTRL_IE_VENDOR_EXT:
451            case MFR_CTRL_IE_CAUSE:
452
453            default:
454                if (vflag <= 1)
455                    print_unknown_data(tptr,"\n\t  ",ie_len);
456                break;
457            }
458
459            /* do we want to see a hexdump of the IE ? */
460            if (vflag > 1 )
461                print_unknown_data(tptr,"\n\t  ",ie_len);
462
463            tlen-=ie_len;
464            tptr+=ie_len;
465        }
466        return hdr_len;
467    }
468/*
469 * FRF.16 Fragmentation Frame
470 *
471 *      7    6    5    4    3    2    1    0
472 *    +----+----+----+----+----+----+----+----+
473 *    | B  | E  | C=0|seq. (high 4 bits) | EA  |
474 *    +----+----+----+----+----+----+----+----+
475 *    |        sequence  (low 8 bits)         |
476 *    +----+----+----+----+----+----+----+----+
477 *    |        DLCI (6 bits)        | CR | EA  |
478 *    +----+----+----+----+----+----+----+----+
479 *    |   DLCI (4 bits)   |FECN|BECN| DE | EA |
480 *    +----+----+----+----+----+----+----+----+
481 */
482
483    sequence_num = (p[0]&0x1e)<<7 | p[1];
484    /* whole packet or first fragment ? */
485    if ((p[0] & MFR_BEC_MASK) == MFR_FRAG_FRAME ||
486        (p[0] & MFR_BEC_MASK) == MFR_B_BIT) {
487        printf("FRF.16 Frag, seq %u, Flags [%s], ",
488               sequence_num,
489               bittok2str(frf_flag_values,"none",(p[0] & MFR_BEC_MASK)));
490        hdr_len = 2;
491        fr_print(p+hdr_len,length-hdr_len);
492        return hdr_len;
493    }
494
495    /* must be a middle or the last fragment */
496    printf("FRF.16 Frag, seq %u, Flags [%s]",
497           sequence_num,
498           bittok2str(frf_flag_values,"none",(p[0] & MFR_BEC_MASK)));
499    print_unknown_data(p,"\n\t",length);
500
501    return hdr_len;
502
503 trunc:
504    printf("[|mfr]");
505    return length;
506}
507
508/* an NLPID of 0xb1 indicates a 2-byte
509 * FRF.15 header
510 *
511 *      7    6    5    4    3    2    1    0
512 *    +----+----+----+----+----+----+----+----+
513 *    ~              Q.922 header             ~
514 *    +----+----+----+----+----+----+----+----+
515 *    |             NLPID (8 bits)            | NLPID=0xb1
516 *    +----+----+----+----+----+----+----+----+
517 *    | B  | E  | C  |seq. (high 4 bits) | R  |
518 *    +----+----+----+----+----+----+----+----+
519 *    |        sequence  (low 8 bits)         |
520 *    +----+----+----+----+----+----+----+----+
521 */
522
523#define FR_FRF15_FRAGTYPE 0x01
524
525static void
526frf15_print (const u_char *p, u_int length) {
527
528    u_int16_t sequence_num, flags;
529
530    flags = p[0]&MFR_BEC_MASK;
531    sequence_num = (p[0]&0x1e)<<7 | p[1];
532
533    printf("FRF.15, seq 0x%03x, Flags [%s],%s Fragmentation, length %u",
534           sequence_num,
535           bittok2str(frf_flag_values,"none",flags),
536           p[0]&FR_FRF15_FRAGTYPE ? "Interface" : "End-to-End",
537           length);
538
539/* TODO:
540 * depending on all permutations of the B, E and C bit
541 * dig as deep as we can - e.g. on the first (B) fragment
542 * there is enough payload to print the IP header
543 * on non (B) fragments it depends if the fragmentation
544 * model is end-to-end or interface based wether we want to print
545 * another Q.922 header
546 */
547
548}
549
550/*
551 * Q.933 decoding portion for framerelay specific.
552 */
553
554/* Q.933 packet format
555                      Format of Other Protocols
556                          using Q.933 NLPID
557                  +-------------------------------+
558                  |        Q.922 Address          |
559                  +---------------+---------------+
560                  |Control  0x03  | NLPID   0x08  |
561                  +---------------+---------------+
562                  |          L2 Protocol ID       |
563                  | octet 1       |  octet 2      |
564                  +-------------------------------+
565                  |          L3 Protocol ID       |
566                  | octet 2       |  octet 2      |
567                  +-------------------------------+
568                  |         Protocol Data         |
569                  +-------------------------------+
570                  | FCS                           |
571                  +-------------------------------+
572 */
573
574/* L2 (Octet 1)- Call Reference Usually is 0x0 */
575
576/*
577 * L2 (Octet 2)- Message Types definition 1 byte long.
578 */
579/* Call Establish */
580#define MSG_TYPE_ESC_TO_NATIONAL  0x00
581#define MSG_TYPE_ALERT            0x01
582#define MSG_TYPE_CALL_PROCEEDING  0x02
583#define MSG_TYPE_CONNECT          0x07
584#define MSG_TYPE_CONNECT_ACK      0x0F
585#define MSG_TYPE_PROGRESS         0x03
586#define MSG_TYPE_SETUP            0x05
587/* Call Clear */
588#define MSG_TYPE_DISCONNECT       0x45
589#define MSG_TYPE_RELEASE          0x4D
590#define MSG_TYPE_RELEASE_COMPLETE 0x5A
591#define MSG_TYPE_RESTART          0x46
592#define MSG_TYPE_RESTART_ACK      0x4E
593/* Status */
594#define MSG_TYPE_STATUS           0x7D
595#define MSG_TYPE_STATUS_ENQ       0x75
596
597struct tok fr_q933_msg_values[] = {
598    { MSG_TYPE_ESC_TO_NATIONAL, "ESC to National" },
599    { MSG_TYPE_ALERT, "Alert" },
600    { MSG_TYPE_CALL_PROCEEDING, "Call proceeding" },
601    { MSG_TYPE_CONNECT, "Connect" },
602    { MSG_TYPE_CONNECT_ACK, "Connect ACK" },
603    { MSG_TYPE_PROGRESS, "Progress" },
604    { MSG_TYPE_SETUP, "Setup" },
605    { MSG_TYPE_DISCONNECT, "Disconnect" },
606    { MSG_TYPE_RELEASE, "Release" },
607    { MSG_TYPE_RELEASE_COMPLETE, "Release Complete" },
608    { MSG_TYPE_RESTART, "Restart" },
609    { MSG_TYPE_RESTART_ACK, "Restart ACK" },
610    { MSG_TYPE_STATUS, "Status Reply" },
611    { MSG_TYPE_STATUS_ENQ, "Status Enquiry" },
612    { 0, NULL }
613};
614
615#define MSG_ANSI_LOCKING_SHIFT	0x95
616
617#define FR_LMI_ANSI_REPORT_TYPE_IE	0x01
618#define FR_LMI_ANSI_LINK_VERIFY_IE_91	0x19 /* details? */
619#define FR_LMI_ANSI_LINK_VERIFY_IE	0x03
620#define FR_LMI_ANSI_PVC_STATUS_IE	0x07
621
622#define FR_LMI_CCITT_REPORT_TYPE_IE	0x51
623#define FR_LMI_CCITT_LINK_VERIFY_IE	0x53
624#define FR_LMI_CCITT_PVC_STATUS_IE	0x57
625
626struct tok fr_q933_ie_values_codeset5[] = {
627    { FR_LMI_ANSI_REPORT_TYPE_IE, "ANSI Report Type" },
628    { FR_LMI_ANSI_LINK_VERIFY_IE_91, "ANSI Link Verify" },
629    { FR_LMI_ANSI_LINK_VERIFY_IE, "ANSI Link Verify" },
630    { FR_LMI_ANSI_PVC_STATUS_IE, "ANSI PVC Status" },
631    { FR_LMI_CCITT_REPORT_TYPE_IE, "CCITT Report Type" },
632    { FR_LMI_CCITT_LINK_VERIFY_IE, "CCITT Link Verify" },
633    { FR_LMI_CCITT_PVC_STATUS_IE, "CCITT PVC Status" },
634    { 0, NULL }
635};
636
637#define FR_LMI_REPORT_TYPE_IE_FULL_STATUS 0
638#define FR_LMI_REPORT_TYPE_IE_LINK_VERIFY 1
639#define FR_LMI_REPORT_TYPE_IE_ASYNC_PVC   2
640
641struct tok fr_lmi_report_type_ie_values[] = {
642    { FR_LMI_REPORT_TYPE_IE_FULL_STATUS, "Full Status" },
643    { FR_LMI_REPORT_TYPE_IE_LINK_VERIFY, "Link verify" },
644    { FR_LMI_REPORT_TYPE_IE_ASYNC_PVC, "Async PVC Status" },
645    { 0, NULL }
646};
647
648/* array of 16 codepages - currently we only support codepage 1,5 */
649static struct tok *fr_q933_ie_codesets[] = {
650    NULL,
651    fr_q933_ie_values_codeset5,
652    NULL,
653    NULL,
654    NULL,
655    fr_q933_ie_values_codeset5,
656    NULL,
657    NULL,
658    NULL,
659    NULL,
660    NULL,
661    NULL,
662    NULL,
663    NULL,
664    NULL,
665    NULL
666};
667
668static int fr_q933_print_ie_codeset5(const struct ie_tlv_header_t  *ie_p,
669    const u_char *p);
670
671typedef int (*codeset_pr_func_t)(const struct ie_tlv_header_t  *ie_p,
672    const u_char *p);
673
674/* array of 16 codepages - currently we only support codepage 1,5 */
675static codeset_pr_func_t fr_q933_print_ie_codeset[] = {
676    NULL,
677    fr_q933_print_ie_codeset5,
678    NULL,
679    NULL,
680    NULL,
681    fr_q933_print_ie_codeset5,
682    NULL,
683    NULL,
684    NULL,
685    NULL,
686    NULL,
687    NULL,
688    NULL,
689    NULL,
690    NULL,
691    NULL
692};
693
694void
695q933_print(const u_char *p, u_int length)
696{
697	const u_char *ptemp = p;
698	struct ie_tlv_header_t  *ie_p;
699        int olen;
700	int is_ansi = 0;
701        u_int codeset;
702        u_int ie_is_known = 0;
703
704	if (length < 9) {	/* shortest: Q.933a LINK VERIFY */
705		printf("[|q.933]");
706		return;
707	}
708
709        codeset = p[2]&0x0f;   /* extract the codeset */
710
711	if (p[2] == MSG_ANSI_LOCKING_SHIFT)
712		is_ansi = 1;
713
714        printf("%s", eflag ? "" : "Q.933, ");
715
716	/* printing out header part */
717	printf("%s, codeset %u", is_ansi ? "ANSI" : "CCITT", codeset);
718
719	if (p[0])
720		printf(", Call Ref: 0x%02x", p[0]);
721
722        if (vflag)
723            printf(", %s (0x%02x), length %u",
724                   tok2str(fr_q933_msg_values,"unknown message",p[1]),
725                   p[1],
726                   length);
727        else
728            printf(", %s",
729                   tok2str(fr_q933_msg_values,"unknown message 0x%02x",p[1]));
730
731        olen = length; /* preserve the original length for non verbose mode */
732
733	if (length < (u_int)(2 - is_ansi)) {
734		printf("[|q.933]");
735		return;
736	}
737	length -= 2 - is_ansi;
738	ptemp += 2 + is_ansi;
739
740	/* Loop through the rest of IE */
741	while (length > sizeof(struct ie_tlv_header_t )) {
742		ie_p = (struct ie_tlv_header_t  *)ptemp;
743		if (length < sizeof(struct ie_tlv_header_t ) ||
744		    length < sizeof(struct ie_tlv_header_t ) + ie_p->ie_len) {
745                    if (vflag) /* not bark if there is just a trailer */
746                        printf("\n[|q.933]");
747                    else
748                        printf(", length %u",olen);
749                    return;
750		}
751
752                /* lets do the full IE parsing only in verbose mode
753                 * however some IEs (DLCI Status, Link Verify)
754                 * are also intereststing in non-verbose mode */
755                if (vflag)
756                    printf("\n\t%s IE (0x%02x), length %u: ",
757                           tok2str(fr_q933_ie_codesets[codeset],"unknown",ie_p->ie_type),
758                           ie_p->ie_type,
759                           ie_p->ie_len);
760
761                /* sanity check */
762                if (ie_p->ie_type == 0 || ie_p->ie_len == 0)
763                    return;
764
765                if (fr_q933_print_ie_codeset[codeset] != NULL)
766                    ie_is_known = fr_q933_print_ie_codeset[codeset](ie_p, ptemp);
767
768                if (vflag >= 1 && !ie_is_known)
769                    print_unknown_data(ptemp+2,"\n\t",ie_p->ie_len);
770
771                /* do we want to see a hexdump of the IE ? */
772                if (vflag> 1 && ie_is_known)
773                    print_unknown_data(ptemp+2,"\n\t  ",ie_p->ie_len);
774
775		length = length - ie_p->ie_len - 2;
776		ptemp = ptemp + ie_p->ie_len + 2;
777	}
778        if (!vflag)
779            printf(", length %u",olen);
780}
781
782static int
783fr_q933_print_ie_codeset5(const struct ie_tlv_header_t  *ie_p, const u_char *p)
784{
785        u_int dlci;
786
787        switch (ie_p->ie_type) {
788
789        case FR_LMI_ANSI_REPORT_TYPE_IE: /* fall through */
790        case FR_LMI_CCITT_REPORT_TYPE_IE:
791            if (vflag)
792                printf("%s (%u)",
793                       tok2str(fr_lmi_report_type_ie_values,"unknown",p[2]),
794                       p[2]);
795            return 1;
796
797        case FR_LMI_ANSI_LINK_VERIFY_IE: /* fall through */
798        case FR_LMI_CCITT_LINK_VERIFY_IE:
799        case FR_LMI_ANSI_LINK_VERIFY_IE_91:
800            if (!vflag)
801                printf(", ");
802            printf("TX Seq: %3d, RX Seq: %3d", p[2], p[3]);
803            return 1;
804
805        case FR_LMI_ANSI_PVC_STATUS_IE: /* fall through */
806        case FR_LMI_CCITT_PVC_STATUS_IE:
807            if (!vflag)
808                printf(", ");
809            /* now parse the DLCI information element. */
810            if ((ie_p->ie_len < 3) ||
811                (p[2] & 0x80) ||
812                ((ie_p->ie_len == 3) && !(p[3] & 0x80)) ||
813                ((ie_p->ie_len == 4) && ((p[3] & 0x80) || !(p[4] & 0x80))) ||
814                ((ie_p->ie_len == 5) && ((p[3] & 0x80) || (p[4] & 0x80) ||
815                                   !(p[5] & 0x80))) ||
816                (ie_p->ie_len > 5) ||
817                !(p[ie_p->ie_len + 1] & 0x80))
818                printf("Invalid DLCI IE");
819
820            dlci = ((p[2] & 0x3F) << 4) | ((p[3] & 0x78) >> 3);
821            if (ie_p->ie_len == 4)
822                dlci = (dlci << 6) | ((p[4] & 0x7E) >> 1);
823            else if (ie_p->ie_len == 5)
824                dlci = (dlci << 13) | (p[4] & 0x7F) | ((p[5] & 0x7E) >> 1);
825
826            printf("DLCI %u: status %s%s", dlci,
827                    p[ie_p->ie_len + 1] & 0x8 ? "New, " : "",
828                    p[ie_p->ie_len + 1] & 0x2 ? "Active" : "Inactive");
829            return 1;
830	}
831
832        return 0;
833}
834