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/* \summary: Frame Relay printer */
23
24#ifdef HAVE_CONFIG_H
25#include <config.h>
26#endif
27
28#include "netdissect-stdinc.h"
29
30#include <stdio.h>
31#include <string.h>
32
33#include "netdissect.h"
34#include "addrtoname.h"
35#include "ethertype.h"
36#include "llc.h"
37#include "nlpid.h"
38#include "extract.h"
39
40static void frf15_print(netdissect_options *ndo, const u_char *, u_int);
41
42/*
43 * the frame relay header has a variable length
44 *
45 * the EA bit determines if there is another byte
46 * in the header
47 *
48 * minimum header length is 2 bytes
49 * maximum header length is 4 bytes
50 *
51 *      7    6    5    4    3    2    1    0
52 *    +----+----+----+----+----+----+----+----+
53 *    |        DLCI (6 bits)        | CR | EA |
54 *    +----+----+----+----+----+----+----+----+
55 *    |   DLCI (4 bits)   |FECN|BECN| DE | EA |
56 *    +----+----+----+----+----+----+----+----+
57 *    |           DLCI (7 bits)          | EA |
58 *    +----+----+----+----+----+----+----+----+
59 *    |        DLCI (6 bits)        |SDLC| EA |
60 *    +----+----+----+----+----+----+----+----+
61 */
62
63#define FR_EA_BIT	0x01
64
65#define FR_CR_BIT       0x02000000
66#define FR_DE_BIT	0x00020000
67#define FR_BECN_BIT	0x00040000
68#define FR_FECN_BIT	0x00080000
69#define FR_SDLC_BIT	0x00000002
70
71
72static const struct tok fr_header_flag_values[] = {
73    { FR_CR_BIT, "C!" },
74    { FR_DE_BIT, "DE" },
75    { FR_BECN_BIT, "BECN" },
76    { FR_FECN_BIT, "FECN" },
77    { FR_SDLC_BIT, "sdlcore" },
78    { 0, NULL }
79};
80
81/* FRF.15 / FRF.16 */
82#define MFR_B_BIT 0x80
83#define MFR_E_BIT 0x40
84#define MFR_C_BIT 0x20
85#define MFR_BEC_MASK    (MFR_B_BIT | MFR_E_BIT | MFR_C_BIT)
86#define MFR_CTRL_FRAME  (MFR_B_BIT | MFR_E_BIT | MFR_C_BIT)
87#define MFR_FRAG_FRAME  (MFR_B_BIT | MFR_E_BIT )
88
89static const struct tok frf_flag_values[] = {
90    { MFR_B_BIT, "Begin" },
91    { MFR_E_BIT, "End" },
92    { MFR_C_BIT, "Control" },
93    { 0, NULL }
94};
95
96/* Finds out Q.922 address length, DLCI and flags. Returns 1 on success,
97 * 0 on invalid address, -1 on truncated packet
98 * save the flags dep. on address length
99 */
100static int parse_q922_header(netdissect_options *ndo,
101                           const u_char *p, u_int *dlci,
102                           u_int *addr_len, uint32_t *flags, u_int length)
103{
104	if (!ND_TTEST_1(p) || length < 1)
105		return -1;
106	if ((GET_U_1(p) & FR_EA_BIT))
107		return 0;
108
109	if (!ND_TTEST_1(p + 1) || length < 2)
110		return -1;
111	*addr_len = 2;
112	*dlci = ((GET_U_1(p) & 0xFC) << 2) | ((GET_U_1(p + 1) & 0xF0) >> 4);
113
114	*flags = ((GET_U_1(p) & 0x02) << 24) |	/* CR flag */
115		 ((GET_U_1(p + 1) & 0x0e) << 16);	/* FECN,BECN,DE flags */
116
117	if (GET_U_1(p + 1) & FR_EA_BIT)
118		return 1;	/* 2-byte Q.922 address */
119
120	p += 2;
121	length -= 2;
122	if (!ND_TTEST_1(p) || length < 1)
123		return -1;
124	(*addr_len)++;		/* 3- or 4-byte Q.922 address */
125	if ((GET_U_1(p) & FR_EA_BIT) == 0) {
126		*dlci = (*dlci << 7) | (GET_U_1(p) >> 1);
127		(*addr_len)++;	/* 4-byte Q.922 address */
128		p++;
129		length--;
130	}
131
132	if (!ND_TTEST_1(p) || length < 1)
133		return -1;
134	if ((GET_U_1(p) & FR_EA_BIT) == 0)
135		return 0; /* more than 4 bytes of Q.922 address? */
136
137	*flags = *flags | (GET_U_1(p) & 0x02);	/* SDLC flag */
138
139        *dlci = (*dlci << 6) | (GET_U_1(p) >> 2);
140
141	return 1;
142}
143
144const char *
145q922_string(netdissect_options *ndo, const u_char *p, u_int length)
146{
147
148    static u_int dlci, addr_len;
149    static uint32_t flags;
150    static char buffer[sizeof("parse_q922_header() returned XXXXXXXXXXX")];
151    int ret;
152    memset(buffer, 0, sizeof(buffer));
153
154    ret = parse_q922_header(ndo, p, &dlci, &addr_len, &flags, length);
155    if (ret == 1) {
156        snprintf(buffer, sizeof(buffer), "DLCI %u", dlci);
157        return buffer;
158    } else if (ret == 0) {
159        return "<Invalid DLCI>";
160    } else if (ret == -1) {
161        return "<Truncated>";
162    } else {
163        snprintf(buffer, sizeof(buffer), "parse_q922_header() returned %d", ret);
164        return buffer;
165    }
166}
167
168
169/* Frame Relay packet structure, with flags and CRC removed
170
171                  +---------------------------+
172                  |       Q.922 Address*      |
173                  +--                       --+
174                  |                           |
175                  +---------------------------+
176                  | Control (UI = 0x03)       |
177                  +---------------------------+
178                  | Optional Pad      (0x00)  |
179                  +---------------------------+
180                  | NLPID                     |
181                  +---------------------------+
182                  |             .             |
183                  |             .             |
184                  |             .             |
185                  |           Data            |
186                  |             .             |
187                  |             .             |
188                  +---------------------------+
189
190           * Q.922 addresses, as presently defined, are two octets and
191             contain a 10-bit DLCI.  In some networks Q.922 addresses
192             may optionally be increased to three or four octets.
193*/
194
195static void
196fr_hdr_print(netdissect_options *ndo, int length, u_int addr_len,
197	     u_int dlci, uint32_t flags, uint16_t nlpid)
198{
199    if (ndo->ndo_qflag) {
200        ND_PRINT("Q.922, DLCI %u, length %u: ",
201                     dlci,
202                     length);
203    } else {
204        if (nlpid <= 0xff) /* if its smaller than 256 then its a NLPID */
205            ND_PRINT("Q.922, hdr-len %u, DLCI %u, Flags [%s], NLPID %s (0x%02x), length %u: ",
206                         addr_len,
207                         dlci,
208                         bittok2str(fr_header_flag_values, "none", flags),
209                         tok2str(nlpid_values,"unknown", nlpid),
210                         nlpid,
211                         length);
212        else /* must be an ethertype */
213            ND_PRINT("Q.922, hdr-len %u, DLCI %u, Flags [%s], cisco-ethertype %s (0x%04x), length %u: ",
214                         addr_len,
215                         dlci,
216                         bittok2str(fr_header_flag_values, "none", flags),
217                         tok2str(ethertype_values, "unknown", nlpid),
218                         nlpid,
219                         length);
220    }
221}
222
223/* Frame Relay */
224void
225fr_if_print(netdissect_options *ndo,
226            const struct pcap_pkthdr *h, const u_char *p)
227{
228	u_int length = h->len;
229	u_int caplen = h->caplen;
230
231	ndo->ndo_protocol = "fr";
232	if (caplen < 4) {	/* minimum frame header length */
233		nd_print_trunc(ndo);
234		ndo->ndo_ll_hdr_len += caplen;
235		return;
236	}
237
238	ndo->ndo_ll_hdr_len += fr_print(ndo, p, length);
239}
240
241u_int
242fr_print(netdissect_options *ndo,
243         const u_char *p, u_int length)
244{
245	int ret;
246	uint16_t extracted_ethertype;
247	u_int dlci;
248	u_int addr_len;
249	uint16_t nlpid;
250	u_int hdr_len;
251	uint32_t flags;
252
253	ndo->ndo_protocol = "fr";
254	ret = parse_q922_header(ndo, p, &dlci, &addr_len, &flags, length);
255	if (ret == -1)
256		goto trunc;
257	if (ret == 0) {
258		ND_PRINT("Q.922, invalid address");
259		return 0;
260	}
261
262	ND_TCHECK_1(p + addr_len);
263	if (length < addr_len + 1)
264		goto trunc;
265
266	if (GET_U_1(p + addr_len) != LLC_UI && dlci != 0) {
267                /*
268                 * Let's figure out if we have Cisco-style encapsulation,
269                 * with an Ethernet type (Cisco HDLC type?) following the
270                 * address.
271                 */
272		if (!ND_TTEST_2(p + addr_len) || length < addr_len + 2) {
273                        /* no Ethertype */
274                        ND_PRINT("UI %02x! ", GET_U_1(p + addr_len));
275                } else {
276                        extracted_ethertype = GET_BE_U_2(p + addr_len);
277
278                        if (ndo->ndo_eflag)
279                                fr_hdr_print(ndo, length, addr_len, dlci,
280                                    flags, extracted_ethertype);
281
282                        if (ethertype_print(ndo, extracted_ethertype,
283                                            p+addr_len+ETHERTYPE_LEN,
284                                            length-addr_len-ETHERTYPE_LEN,
285                                            ND_BYTES_AVAILABLE_AFTER(p)-addr_len-ETHERTYPE_LEN,
286                                            NULL, NULL) == 0)
287                                /* ether_type not known, probably it wasn't one */
288                                ND_PRINT("UI %02x! ", GET_U_1(p + addr_len));
289                        else
290                                return addr_len + 2;
291                }
292        }
293
294	ND_TCHECK_1(p + addr_len + 1);
295	if (length < addr_len + 2)
296		goto trunc;
297
298	if (GET_U_1(p + addr_len + 1) == 0) {
299		/*
300		 * Assume a pad byte after the control (UI) byte.
301		 * A pad byte should only be used with 3-byte Q.922.
302		 */
303		if (addr_len != 3)
304			ND_PRINT("Pad! ");
305		hdr_len = addr_len + 1 /* UI */ + 1 /* pad */ + 1 /* NLPID */;
306	} else {
307		/*
308		 * Not a pad byte.
309		 * A pad byte should be used with 3-byte Q.922.
310		 */
311		if (addr_len == 3)
312			ND_PRINT("No pad! ");
313		hdr_len = addr_len + 1 /* UI */ + 1 /* NLPID */;
314	}
315
316        ND_TCHECK_1(p + hdr_len - 1);
317	if (length < hdr_len)
318		goto trunc;
319	nlpid = GET_U_1(p + hdr_len - 1);
320
321	if (ndo->ndo_eflag)
322		fr_hdr_print(ndo, length, addr_len, dlci, flags, nlpid);
323	p += hdr_len;
324	length -= hdr_len;
325
326	switch (nlpid) {
327	case NLPID_IP:
328	        ip_print(ndo, p, length);
329		break;
330
331	case NLPID_IP6:
332		ip6_print(ndo, p, length);
333		break;
334
335	case NLPID_CLNP:
336	case NLPID_ESIS:
337	case NLPID_ISIS:
338		isoclns_print(ndo, p - 1, length + 1); /* OSI printers need the NLPID field */
339		break;
340
341	case NLPID_SNAP:
342		if (snap_print(ndo, p, length, ND_BYTES_AVAILABLE_AFTER(p), NULL, NULL, 0) == 0) {
343			/* ether_type not known, print raw packet */
344                        if (!ndo->ndo_eflag)
345                            fr_hdr_print(ndo, length + hdr_len, hdr_len,
346                                         dlci, flags, nlpid);
347			if (!ndo->ndo_suppress_default_print)
348				ND_DEFAULTPRINT(p - hdr_len, length + hdr_len);
349		}
350		break;
351
352        case NLPID_Q933:
353		q933_print(ndo, p, length);
354		break;
355
356        case NLPID_MFR:
357                frf15_print(ndo, p, length);
358                break;
359
360        case NLPID_PPP:
361                ppp_print(ndo, p, length);
362                break;
363
364	default:
365		if (!ndo->ndo_eflag)
366                    fr_hdr_print(ndo, length + hdr_len, addr_len,
367				     dlci, flags, nlpid);
368		if (!ndo->ndo_xflag)
369			ND_DEFAULTPRINT(p, length);
370	}
371
372	return hdr_len;
373
374trunc:
375        nd_print_trunc(ndo);
376        return 0;
377
378}
379
380/* Multi Link Frame Relay (FRF.16) */
381void
382mfr_if_print(netdissect_options *ndo,
383             const struct pcap_pkthdr *h, const u_char *p)
384{
385	u_int length = h->len;
386	u_int caplen = h->caplen;
387
388	ndo->ndo_protocol = "mfr";
389	if (caplen < 2) {	/* minimum frame header length */
390		nd_print_trunc(ndo);
391		ndo->ndo_ll_hdr_len += caplen;
392		return;
393	}
394
395	ndo->ndo_ll_hdr_len += mfr_print(ndo, p, length);
396}
397
398
399#define MFR_CTRL_MSG_ADD_LINK        1
400#define MFR_CTRL_MSG_ADD_LINK_ACK    2
401#define MFR_CTRL_MSG_ADD_LINK_REJ    3
402#define MFR_CTRL_MSG_HELLO           4
403#define MFR_CTRL_MSG_HELLO_ACK       5
404#define MFR_CTRL_MSG_REMOVE_LINK     6
405#define MFR_CTRL_MSG_REMOVE_LINK_ACK 7
406
407static const struct tok mfr_ctrl_msg_values[] = {
408    { MFR_CTRL_MSG_ADD_LINK, "Add Link" },
409    { MFR_CTRL_MSG_ADD_LINK_ACK, "Add Link ACK" },
410    { MFR_CTRL_MSG_ADD_LINK_REJ, "Add Link Reject" },
411    { MFR_CTRL_MSG_HELLO, "Hello" },
412    { MFR_CTRL_MSG_HELLO_ACK, "Hello ACK" },
413    { MFR_CTRL_MSG_REMOVE_LINK, "Remove Link" },
414    { MFR_CTRL_MSG_REMOVE_LINK_ACK, "Remove Link ACK" },
415    { 0, NULL }
416};
417
418#define MFR_CTRL_IE_BUNDLE_ID  1
419#define MFR_CTRL_IE_LINK_ID    2
420#define MFR_CTRL_IE_MAGIC_NUM  3
421#define MFR_CTRL_IE_TIMESTAMP  5
422#define MFR_CTRL_IE_VENDOR_EXT 6
423#define MFR_CTRL_IE_CAUSE      7
424
425static const struct tok mfr_ctrl_ie_values[] = {
426    { MFR_CTRL_IE_BUNDLE_ID, "Bundle ID"},
427    { MFR_CTRL_IE_LINK_ID, "Link ID"},
428    { MFR_CTRL_IE_MAGIC_NUM, "Magic Number"},
429    { MFR_CTRL_IE_TIMESTAMP, "Timestamp"},
430    { MFR_CTRL_IE_VENDOR_EXT, "Vendor Extension"},
431    { MFR_CTRL_IE_CAUSE, "Cause"},
432    { 0, NULL }
433};
434
435#define MFR_ID_STRING_MAXLEN 50
436
437struct ie_tlv_header_t {
438    uint8_t ie_type;
439    uint8_t ie_len;
440};
441
442u_int
443mfr_print(netdissect_options *ndo,
444          const u_char *p, u_int length)
445{
446    u_int tlen,idx,hdr_len = 0;
447    uint16_t sequence_num;
448    uint8_t ie_type,ie_len;
449    const uint8_t *tptr;
450
451
452/*
453 * FRF.16 Link Integrity Control Frame
454 *
455 *      7    6    5    4    3    2    1    0
456 *    +----+----+----+----+----+----+----+----+
457 *    | B  | E  | C=1| 0    0    0    0  | EA |
458 *    +----+----+----+----+----+----+----+----+
459 *    | 0    0    0    0    0    0    0    0  |
460 *    +----+----+----+----+----+----+----+----+
461 *    |              message type             |
462 *    +----+----+----+----+----+----+----+----+
463 */
464
465    ndo->ndo_protocol = "mfr";
466
467    if (length < 4) {	/* minimum frame header length */
468        ND_PRINT("[length %u < 4]", length);
469        nd_print_invalid(ndo);
470        return length;
471    }
472    ND_TCHECK_4(p);
473
474    if ((GET_U_1(p) & MFR_BEC_MASK) == MFR_CTRL_FRAME && GET_U_1(p + 1) == 0) {
475        ND_PRINT("FRF.16 Control, Flags [%s], %s, length %u",
476               bittok2str(frf_flag_values,"none",(GET_U_1(p) & MFR_BEC_MASK)),
477               tok2str(mfr_ctrl_msg_values,"Unknown Message (0x%02x)",GET_U_1(p + 2)),
478               length);
479        tptr = p + 3;
480        tlen = length -3;
481        hdr_len = 3;
482
483        if (!ndo->ndo_vflag)
484            return hdr_len;
485
486        while (tlen>sizeof(struct ie_tlv_header_t)) {
487            ND_TCHECK_LEN(tptr, sizeof(struct ie_tlv_header_t));
488            ie_type=GET_U_1(tptr);
489            ie_len=GET_U_1(tptr + 1);
490
491            ND_PRINT("\n\tIE %s (%u), length %u: ",
492                   tok2str(mfr_ctrl_ie_values,"Unknown",ie_type),
493                   ie_type,
494                   ie_len);
495
496            /* infinite loop check */
497            if (ie_type == 0 || ie_len <= sizeof(struct ie_tlv_header_t))
498                return hdr_len;
499
500            ND_TCHECK_LEN(tptr, ie_len);
501            tptr+=sizeof(struct ie_tlv_header_t);
502            /* tlv len includes header */
503            ie_len-=sizeof(struct ie_tlv_header_t);
504            tlen-=sizeof(struct ie_tlv_header_t);
505
506            switch (ie_type) {
507
508            case MFR_CTRL_IE_MAGIC_NUM:
509                /* FRF.16.1 Section 3.4.3 Magic Number Information Element */
510                if (ie_len != 4) {
511                    ND_PRINT("[IE data length %d != 4]", ie_len);
512                    nd_print_invalid(ndo);
513                    break;
514                }
515                ND_PRINT("0x%08x", GET_BE_U_4(tptr));
516                break;
517
518            case MFR_CTRL_IE_BUNDLE_ID: /* same message format */
519            case MFR_CTRL_IE_LINK_ID:
520                for (idx = 0; idx < ie_len && idx < MFR_ID_STRING_MAXLEN; idx++) {
521                    if (GET_U_1(tptr + idx) != 0) /* don't print null termination */
522                        fn_print_char(ndo, GET_U_1(tptr + idx));
523                    else
524                        break;
525                }
526                break;
527
528            case MFR_CTRL_IE_TIMESTAMP:
529                if (ie_len == sizeof(struct timeval)) {
530                    ts_print(ndo, (const struct timeval *)tptr);
531                    break;
532                }
533                /* fall through and hexdump if no unix timestamp */
534                ND_FALL_THROUGH;
535
536                /*
537                 * FIXME those are the defined IEs that lack a decoder
538                 * you are welcome to contribute code ;-)
539                 */
540
541            case MFR_CTRL_IE_VENDOR_EXT:
542            case MFR_CTRL_IE_CAUSE:
543
544            default:
545                if (ndo->ndo_vflag <= 1)
546                    print_unknown_data(ndo, tptr, "\n\t  ", ie_len);
547                break;
548            }
549
550            /* do we want to see a hexdump of the IE ? */
551            if (ndo->ndo_vflag > 1 )
552                print_unknown_data(ndo, tptr, "\n\t  ", ie_len);
553
554            tlen-=ie_len;
555            tptr+=ie_len;
556        }
557        return hdr_len;
558    }
559/*
560 * FRF.16 Fragmentation Frame
561 *
562 *      7    6    5    4    3    2    1    0
563 *    +----+----+----+----+----+----+----+----+
564 *    | B  | E  | C=0|seq. (high 4 bits) | EA |
565 *    +----+----+----+----+----+----+----+----+
566 *    |        sequence  (low 8 bits)         |
567 *    +----+----+----+----+----+----+----+----+
568 *    |        DLCI (6 bits)        | CR | EA |
569 *    +----+----+----+----+----+----+----+----+
570 *    |   DLCI (4 bits)   |FECN|BECN| DE | EA |
571 *    +----+----+----+----+----+----+----+----+
572 */
573
574    sequence_num = (GET_U_1(p)&0x1e)<<7 | GET_U_1(p + 1);
575    /* whole packet or first fragment ? */
576    if ((GET_U_1(p) & MFR_BEC_MASK) == MFR_FRAG_FRAME ||
577        (GET_U_1(p) & MFR_BEC_MASK) == MFR_B_BIT) {
578        ND_PRINT("FRF.16 Frag, seq %u, Flags [%s], ",
579               sequence_num,
580               bittok2str(frf_flag_values,"none",(GET_U_1(p) & MFR_BEC_MASK)));
581        hdr_len = 2;
582        fr_print(ndo, p+hdr_len,length-hdr_len);
583        return hdr_len;
584    }
585
586    /* must be a middle or the last fragment */
587    ND_PRINT("FRF.16 Frag, seq %u, Flags [%s]",
588           sequence_num,
589           bittok2str(frf_flag_values,"none",(GET_U_1(p) & MFR_BEC_MASK)));
590    print_unknown_data(ndo, p, "\n\t", length);
591
592    return hdr_len;
593
594trunc:
595    nd_print_trunc(ndo);
596    return length;
597}
598
599/* an NLPID of 0xb1 indicates a 2-byte
600 * FRF.15 header
601 *
602 *      7    6    5    4    3    2    1    0
603 *    +----+----+----+----+----+----+----+----+
604 *    ~              Q.922 header             ~
605 *    +----+----+----+----+----+----+----+----+
606 *    |             NLPID (8 bits)            | NLPID=0xb1
607 *    +----+----+----+----+----+----+----+----+
608 *    | B  | E  | C  |seq. (high 4 bits) | R  |
609 *    +----+----+----+----+----+----+----+----+
610 *    |        sequence  (low 8 bits)         |
611 *    +----+----+----+----+----+----+----+----+
612 */
613
614#define FR_FRF15_FRAGTYPE 0x01
615
616static void
617frf15_print(netdissect_options *ndo,
618            const u_char *p, u_int length)
619{
620    uint16_t sequence_num, flags;
621
622    if (length < 2)
623        goto trunc;
624
625    flags = GET_U_1(p)&MFR_BEC_MASK;
626    sequence_num = (GET_U_1(p)&0x1e)<<7 | GET_U_1(p + 1);
627
628    ND_PRINT("FRF.15, seq 0x%03x, Flags [%s],%s Fragmentation, length %u",
629           sequence_num,
630           bittok2str(frf_flag_values,"none",flags),
631           GET_U_1(p)&FR_FRF15_FRAGTYPE ? "Interface" : "End-to-End",
632           length);
633
634/* TODO:
635 * depending on all permutations of the B, E and C bit
636 * dig as deep as we can - e.g. on the first (B) fragment
637 * there is enough payload to print the IP header
638 * on non (B) fragments it depends if the fragmentation
639 * model is end-to-end or interface based whether we want to print
640 * another Q.922 header
641 */
642    return;
643
644trunc:
645    nd_print_trunc(ndo);
646}
647
648/*
649 * Q.933 decoding portion for framerelay specific.
650 */
651
652/* Q.933 packet format
653                      Format of Other Protocols
654                          using Q.933 NLPID
655                  +-------------------------------+
656                  |        Q.922 Address          |
657                  +---------------+---------------+
658                  |Control  0x03  | NLPID   0x08  |
659                  +---------------+---------------+
660                  |          L2 Protocol ID       |
661                  | octet 1       |  octet 2      |
662                  +-------------------------------+
663                  |          L3 Protocol ID       |
664                  | octet 2       |  octet 2      |
665                  +-------------------------------+
666                  |         Protocol Data         |
667                  +-------------------------------+
668                  | FCS                           |
669                  +-------------------------------+
670 */
671
672/* L2 (Octet 1)- Call Reference Usually is 0x0 */
673
674/*
675 * L2 (Octet 2)- Message Types definition 1 byte long.
676 */
677/* Call Establish */
678#define MSG_TYPE_ESC_TO_NATIONAL  0x00
679#define MSG_TYPE_ALERT            0x01
680#define MSG_TYPE_CALL_PROCEEDING  0x02
681#define MSG_TYPE_CONNECT          0x07
682#define MSG_TYPE_CONNECT_ACK      0x0F
683#define MSG_TYPE_PROGRESS         0x03
684#define MSG_TYPE_SETUP            0x05
685/* Call Clear */
686#define MSG_TYPE_DISCONNECT       0x45
687#define MSG_TYPE_RELEASE          0x4D
688#define MSG_TYPE_RELEASE_COMPLETE 0x5A
689#define MSG_TYPE_RESTART          0x46
690#define MSG_TYPE_RESTART_ACK      0x4E
691/* Status */
692#define MSG_TYPE_STATUS           0x7D
693#define MSG_TYPE_STATUS_ENQ       0x75
694
695static const struct tok fr_q933_msg_values[] = {
696    { MSG_TYPE_ESC_TO_NATIONAL, "ESC to National" },
697    { MSG_TYPE_ALERT, "Alert" },
698    { MSG_TYPE_CALL_PROCEEDING, "Call proceeding" },
699    { MSG_TYPE_CONNECT, "Connect" },
700    { MSG_TYPE_CONNECT_ACK, "Connect ACK" },
701    { MSG_TYPE_PROGRESS, "Progress" },
702    { MSG_TYPE_SETUP, "Setup" },
703    { MSG_TYPE_DISCONNECT, "Disconnect" },
704    { MSG_TYPE_RELEASE, "Release" },
705    { MSG_TYPE_RELEASE_COMPLETE, "Release Complete" },
706    { MSG_TYPE_RESTART, "Restart" },
707    { MSG_TYPE_RESTART_ACK, "Restart ACK" },
708    { MSG_TYPE_STATUS, "Status Reply" },
709    { MSG_TYPE_STATUS_ENQ, "Status Enquiry" },
710    { 0, NULL }
711};
712
713#define IE_IS_SINGLE_OCTET(iecode)	((iecode) & 0x80)
714#define IE_IS_SHIFT(iecode)		(((iecode) & 0xF0) == 0x90)
715#define IE_SHIFT_IS_NON_LOCKING(iecode)	((iecode) & 0x08)
716#define IE_SHIFT_IS_LOCKING(iecode)	(!(IE_SHIFT_IS_NON_LOCKING(iecode)))
717#define IE_SHIFT_CODESET(iecode)	((iecode) & 0x07)
718
719#define FR_LMI_ANSI_REPORT_TYPE_IE	0x01
720#define FR_LMI_ANSI_LINK_VERIFY_IE_91	0x19 /* details? */
721#define FR_LMI_ANSI_LINK_VERIFY_IE	0x03
722#define FR_LMI_ANSI_PVC_STATUS_IE	0x07
723
724#define FR_LMI_CCITT_REPORT_TYPE_IE	0x51
725#define FR_LMI_CCITT_LINK_VERIFY_IE	0x53
726#define FR_LMI_CCITT_PVC_STATUS_IE	0x57
727
728static const struct tok fr_q933_ie_values_codeset_0_5[] = {
729    { FR_LMI_ANSI_REPORT_TYPE_IE, "ANSI Report Type" },
730    { FR_LMI_ANSI_LINK_VERIFY_IE_91, "ANSI Link Verify" },
731    { FR_LMI_ANSI_LINK_VERIFY_IE, "ANSI Link Verify" },
732    { FR_LMI_ANSI_PVC_STATUS_IE, "ANSI PVC Status" },
733    { FR_LMI_CCITT_REPORT_TYPE_IE, "CCITT Report Type" },
734    { FR_LMI_CCITT_LINK_VERIFY_IE, "CCITT Link Verify" },
735    { FR_LMI_CCITT_PVC_STATUS_IE, "CCITT PVC Status" },
736    { 0, NULL }
737};
738
739#define FR_LMI_REPORT_TYPE_IE_FULL_STATUS 0
740#define FR_LMI_REPORT_TYPE_IE_LINK_VERIFY 1
741#define FR_LMI_REPORT_TYPE_IE_ASYNC_PVC   2
742
743static const struct tok fr_lmi_report_type_ie_values[] = {
744    { FR_LMI_REPORT_TYPE_IE_FULL_STATUS, "Full Status" },
745    { FR_LMI_REPORT_TYPE_IE_LINK_VERIFY, "Link verify" },
746    { FR_LMI_REPORT_TYPE_IE_ASYNC_PVC, "Async PVC Status" },
747    { 0, NULL }
748};
749
750/* array of 16 codesets - currently we only support codepage 0 and 5 */
751static const struct tok *fr_q933_ie_codesets[] = {
752    fr_q933_ie_values_codeset_0_5,
753    NULL,
754    NULL,
755    NULL,
756    NULL,
757    fr_q933_ie_values_codeset_0_5,
758    NULL,
759    NULL,
760    NULL,
761    NULL,
762    NULL,
763    NULL,
764    NULL,
765    NULL,
766    NULL,
767    NULL
768};
769
770static int fr_q933_print_ie_codeset_0_5(netdissect_options *ndo, u_int iecode,
771    u_int ielength, const u_char *p);
772
773typedef int (*codeset_pr_func_t)(netdissect_options *, u_int iecode,
774    u_int ielength, const u_char *p);
775
776/* array of 16 codesets - currently we only support codepage 0 and 5 */
777static const codeset_pr_func_t fr_q933_print_ie_codeset[] = {
778    fr_q933_print_ie_codeset_0_5,
779    NULL,
780    NULL,
781    NULL,
782    NULL,
783    fr_q933_print_ie_codeset_0_5,
784    NULL,
785    NULL,
786    NULL,
787    NULL,
788    NULL,
789    NULL,
790    NULL,
791    NULL,
792    NULL,
793    NULL
794};
795
796/*
797 * ITU-T Q.933.
798 *
799 * p points to octet 2, the octet containing the length of the
800 * call reference value, so p[n] is octet n+2 ("octet X" is as
801 * used in Q.931/Q.933).
802 *
803 * XXX - actually used both for Q.931 and Q.933.
804 */
805void
806q933_print(netdissect_options *ndo,
807           const u_char *p, u_int length)
808{
809	u_int olen;
810	u_int call_ref_length, i;
811	uint8_t call_ref[15];	/* maximum length - length field is 4 bits */
812	u_int msgtype;
813	u_int iecode;
814	u_int ielength;
815	u_int codeset = 0;
816	u_int is_ansi = 0;
817	u_int ie_is_known;
818	u_int non_locking_shift;
819	u_int unshift_codeset;
820
821	ndo->ndo_protocol = "q.933";
822	ND_PRINT("%s", ndo->ndo_eflag ? "" : "Q.933");
823
824	if (length == 0 || !ND_TTEST_1(p)) {
825		if (!ndo->ndo_eflag)
826			ND_PRINT(", ");
827		ND_PRINT("length %u", length);
828		goto trunc;
829	}
830
831	/*
832	 * Get the length of the call reference value.
833	 */
834	olen = length; /* preserve the original length for display */
835	call_ref_length = GET_U_1(p) & 0x0f;
836	p++;
837	length--;
838
839	/*
840	 * Get the call reference value.
841	 */
842	for (i = 0; i < call_ref_length; i++) {
843		if (length == 0 || !ND_TTEST_1(p)) {
844			if (!ndo->ndo_eflag)
845				ND_PRINT(", ");
846			ND_PRINT("length %u", olen);
847			goto trunc;
848		}
849		call_ref[i] = GET_U_1(p);
850		p++;
851		length--;
852	}
853
854	/*
855	 * Get the message type.
856	 */
857	if (length == 0 || !ND_TTEST_1(p)) {
858		if (!ndo->ndo_eflag)
859			ND_PRINT(", ");
860		ND_PRINT("length %u", olen);
861		goto trunc;
862	}
863	msgtype = GET_U_1(p);
864	p++;
865	length--;
866
867	/*
868	 * Peek ahead to see if we start with a shift.
869	 */
870	non_locking_shift = 0;
871	unshift_codeset = codeset;
872	if (length != 0) {
873		if (!ND_TTEST_1(p)) {
874			if (!ndo->ndo_eflag)
875				ND_PRINT(", ");
876			ND_PRINT("length %u", olen);
877			goto trunc;
878		}
879		iecode = GET_U_1(p);
880		if (IE_IS_SHIFT(iecode)) {
881			/*
882			 * It's a shift.  Skip over it.
883			 */
884			p++;
885			length--;
886
887			/*
888			 * Get the codeset.
889			 */
890			codeset = IE_SHIFT_CODESET(iecode);
891
892			/*
893			 * If it's a locking shift to codeset 5,
894			 * mark this as ANSI.  (XXX - 5 is actually
895			 * for national variants in general, not
896			 * the US variant in particular, but maybe
897			 * this is more American exceptionalism. :-))
898			 */
899			if (IE_SHIFT_IS_LOCKING(iecode)) {
900				/*
901				 * It's a locking shift.
902				 */
903				if (codeset == 5) {
904					/*
905					 * It's a locking shift to
906					 * codeset 5, so this is
907					 * T1.617 Annex D.
908					 */
909					is_ansi = 1;
910				}
911			} else {
912				/*
913				 * It's a non-locking shift.
914				 * Remember the current codeset, so we
915				 * can revert to it after the next IE.
916				 */
917				non_locking_shift = 1;
918				unshift_codeset = 0;
919			}
920		}
921	}
922
923	/* printing out header part */
924	if (!ndo->ndo_eflag)
925		ND_PRINT(", ");
926	ND_PRINT("%s, codeset %u", is_ansi ? "ANSI" : "CCITT", codeset);
927
928	if (call_ref_length != 0) {
929		if (call_ref_length > 1 || GET_U_1(p) != 0) {
930			/*
931			 * Not a dummy call reference.
932			 */
933			ND_PRINT(", Call Ref: 0x");
934			for (i = 0; i < call_ref_length; i++)
935				ND_PRINT("%02x", call_ref[i]);
936		}
937	}
938	if (ndo->ndo_vflag) {
939		ND_PRINT(", %s (0x%02x), length %u",
940		   tok2str(fr_q933_msg_values,
941			"unknown message", msgtype),
942		   msgtype,
943		   olen);
944	} else {
945		ND_PRINT(", %s",
946		       tok2str(fr_q933_msg_values,
947			       "unknown message 0x%02x", msgtype));
948	}
949
950	/* Loop through the rest of the IEs */
951	while (length != 0) {
952		/*
953		 * What's the state of any non-locking shifts?
954		 */
955		if (non_locking_shift == 1) {
956			/*
957			 * There's a non-locking shift in effect for
958			 * this IE.  Count it, so we reset the codeset
959			 * before the next IE.
960			 */
961			non_locking_shift = 2;
962		} else if (non_locking_shift == 2) {
963			/*
964			 * Unshift.
965			 */
966			codeset = unshift_codeset;
967			non_locking_shift = 0;
968		}
969
970		/*
971		 * Get the first octet of the IE.
972		 */
973		if (!ND_TTEST_1(p)) {
974			if (!ndo->ndo_vflag) {
975				ND_PRINT(", length %u", olen);
976			}
977			goto trunc;
978		}
979		iecode = GET_U_1(p);
980		p++;
981		length--;
982
983		/* Single-octet IE? */
984		if (IE_IS_SINGLE_OCTET(iecode)) {
985			/*
986			 * Yes.  Is it a shift?
987			 */
988			if (IE_IS_SHIFT(iecode)) {
989				/*
990				 * Yes.  Is it locking?
991				 */
992				if (IE_SHIFT_IS_LOCKING(iecode)) {
993					/*
994					 * Yes.
995					 */
996					non_locking_shift = 0;
997				} else {
998					/*
999					 * No.  Remember the current
1000					 * codeset, so we can revert
1001					 * to it after the next IE.
1002					 */
1003					non_locking_shift = 1;
1004					unshift_codeset = codeset;
1005				}
1006
1007				/*
1008				 * Get the codeset.
1009				 */
1010				codeset = IE_SHIFT_CODESET(iecode);
1011			}
1012		} else {
1013			/*
1014			 * No.  Get the IE length.
1015			 */
1016			if (length == 0 || !ND_TTEST_1(p)) {
1017				if (!ndo->ndo_vflag) {
1018					ND_PRINT(", length %u", olen);
1019				}
1020				goto trunc;
1021			}
1022			ielength = GET_U_1(p);
1023			p++;
1024			length--;
1025
1026			/* lets do the full IE parsing only in verbose mode
1027			 * however some IEs (DLCI Status, Link Verify)
1028			 * are also interesting in non-verbose mode */
1029			if (ndo->ndo_vflag) {
1030				ND_PRINT("\n\t%s IE (0x%02x), length %u: ",
1031				    tok2str(fr_q933_ie_codesets[codeset],
1032					"unknown", iecode),
1033				    iecode,
1034				    ielength);
1035			}
1036
1037			/* sanity checks */
1038			if (iecode == 0 || ielength == 0) {
1039				return;
1040			}
1041			if (length < ielength || !ND_TTEST_LEN(p, ielength)) {
1042				if (!ndo->ndo_vflag) {
1043					ND_PRINT(", length %u", olen);
1044				}
1045				goto trunc;
1046			}
1047
1048			ie_is_known = 0;
1049			if (fr_q933_print_ie_codeset[codeset] != NULL) {
1050				ie_is_known = fr_q933_print_ie_codeset[codeset](ndo, iecode, ielength, p);
1051			}
1052
1053			if (ie_is_known) {
1054				/*
1055				 * Known IE; do we want to see a hexdump
1056				 * of it?
1057				 */
1058				if (ndo->ndo_vflag > 1) {
1059					/* Yes. */
1060					print_unknown_data(ndo, p, "\n\t  ", ielength);
1061				}
1062			} else {
1063				/*
1064				 * Unknown IE; if we're printing verbosely,
1065				 * print its content in hex.
1066				 */
1067				if (ndo->ndo_vflag >= 1) {
1068					print_unknown_data(ndo, p, "\n\t", ielength);
1069				}
1070			}
1071
1072			length -= ielength;
1073			p += ielength;
1074		}
1075	}
1076	if (!ndo->ndo_vflag) {
1077	    ND_PRINT(", length %u", olen);
1078	}
1079	return;
1080
1081trunc:
1082	nd_print_trunc(ndo);
1083}
1084
1085static int
1086fr_q933_print_ie_codeset_0_5(netdissect_options *ndo, u_int iecode,
1087                          u_int ielength, const u_char *p)
1088{
1089        u_int dlci;
1090
1091        switch (iecode) {
1092
1093        case FR_LMI_ANSI_REPORT_TYPE_IE: /* fall through */
1094        case FR_LMI_CCITT_REPORT_TYPE_IE:
1095            if (ielength < 1) {
1096                if (!ndo->ndo_vflag) {
1097                    ND_PRINT(", ");
1098	        }
1099                ND_PRINT("Invalid REPORT TYPE IE");
1100                return 1;
1101            }
1102            if (ndo->ndo_vflag) {
1103                ND_PRINT("%s (%u)",
1104                       tok2str(fr_lmi_report_type_ie_values,"unknown",GET_U_1(p)),
1105                       GET_U_1(p));
1106	    }
1107            return 1;
1108
1109        case FR_LMI_ANSI_LINK_VERIFY_IE: /* fall through */
1110        case FR_LMI_CCITT_LINK_VERIFY_IE:
1111        case FR_LMI_ANSI_LINK_VERIFY_IE_91:
1112            if (!ndo->ndo_vflag) {
1113                ND_PRINT(", ");
1114	    }
1115            if (ielength < 2) {
1116                ND_PRINT("Invalid LINK VERIFY IE");
1117                return 1;
1118            }
1119            ND_PRINT("TX Seq: %3d, RX Seq: %3d", GET_U_1(p), GET_U_1(p + 1));
1120            return 1;
1121
1122        case FR_LMI_ANSI_PVC_STATUS_IE: /* fall through */
1123        case FR_LMI_CCITT_PVC_STATUS_IE:
1124            if (!ndo->ndo_vflag) {
1125                ND_PRINT(", ");
1126	    }
1127            /* now parse the DLCI information element. */
1128            if ((ielength < 3) ||
1129                (GET_U_1(p) & 0x80) ||
1130                ((ielength == 3) && !(GET_U_1(p + 1) & 0x80)) ||
1131                ((ielength == 4) &&
1132                  ((GET_U_1(p + 1) & 0x80) || !(GET_U_1(p + 2) & 0x80))) ||
1133                ((ielength == 5) &&
1134                  ((GET_U_1(p + 1) & 0x80) || (GET_U_1(p + 2) & 0x80) ||
1135                   !(GET_U_1(p + 3) & 0x80))) ||
1136                (ielength > 5) ||
1137                !(GET_U_1(p + ielength - 1) & 0x80)) {
1138                ND_PRINT("Invalid DLCI in PVC STATUS IE");
1139                return 1;
1140	    }
1141
1142            dlci = ((GET_U_1(p) & 0x3F) << 4) | ((GET_U_1(p + 1) & 0x78) >> 3);
1143            if (ielength == 4) {
1144                dlci = (dlci << 6) | ((GET_U_1(p + 2) & 0x7E) >> 1);
1145	    }
1146            else if (ielength == 5) {
1147                dlci = (dlci << 13) | (GET_U_1(p + 2) & 0x7F) | ((GET_U_1(p + 3) & 0x7E) >> 1);
1148	    }
1149
1150            ND_PRINT("DLCI %u: status %s%s", dlci,
1151                    GET_U_1(p + ielength - 1) & 0x8 ? "New, " : "",
1152                    GET_U_1(p + ielength - 1) & 0x2 ? "Active" : "Inactive");
1153            return 1;
1154	}
1155
1156        return 0;
1157}
1158