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