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