print-fr.c revision 147904
132145Spst/* 232145Spst * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996 332145Spst * The Regents of the University of California. All rights reserved. 432145Spst * 532145Spst * Redistribution and use in source and binary forms, with or without 632145Spst * modification, are permitted provided that: (1) source code distributions 732145Spst * retain the above copyright notice and this paragraph in its entirety, (2) 832145Spst * distributions including binary code include the above copyright notice and 932145Spst * this paragraph in its entirety in the documentation or other materials 1032145Spst * provided with the distribution, and (3) all advertising materials mentioning 1132145Spst * features or use of this software display the following acknowledgement: 1232145Spst * ``This product includes software developed by the University of California, 1332145Spst * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 1432145Spst * the University nor the names of its contributors may be used to endorse 1532145Spst * or promote products derived from this software without specific prior 1632145Spst * written permission. 1732145Spst * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 1832145Spst * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 1932145Spst * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 2066644Skris * 2166644Skris * $FreeBSD: head/contrib/tcpdump/print-fr.c 147904 2005-07-11 04:14:02Z sam $ 2232145Spst */ 2332145Spst 2432145Spst#ifndef lint 25146778Ssamstatic const char rcsid[] _U_ = 26147904Ssam "@(#)$Header: /tcpdump/master/tcpdump/print-fr.c,v 1.32.2.4 2005/05/27 14:56:52 hannes Exp $ (LBL)"; 2732145Spst#endif 2832145Spst 29146778Ssam#ifdef HAVE_CONFIG_H 30146778Ssam#include "config.h" 3132145Spst#endif 3232145Spst 33146778Ssam#include <tcpdump-stdinc.h> 3432145Spst 35146778Ssam#include <stdio.h> 36146778Ssam#include <string.h> 3732145Spst#include <pcap.h> 3832145Spst 39146778Ssam#include "addrtoname.h" 40146778Ssam#include "interface.h" 4132145Spst#include "ethertype.h" 42146778Ssam#include "nlpid.h" 43146778Ssam#include "extract.h" 44146778Ssam#include "oui.h" 4532145Spst 46146778Ssamstatic void frf15_print(const u_char *, u_int); 4732145Spst 48146778Ssam/* 49146778Ssam * the frame relay header has a variable length 50146778Ssam * 51146778Ssam * the EA bit determines if there is another byte 52146778Ssam * in the header 53146778Ssam * 54146778Ssam * minimum header length is 2 bytes 55146778Ssam * maximum header length is 4 bytes 56146778Ssam * 57146778Ssam * 7 6 5 4 3 2 1 0 58146778Ssam * +----+----+----+----+----+----+----+----+ 59146778Ssam * | DLCI (6 bits) | CR | EA | 60146778Ssam * +----+----+----+----+----+----+----+----+ 61146778Ssam * | DLCI (4 bits) |FECN|BECN| DE | EA | 62146778Ssam * +----+----+----+----+----+----+----+----+ 63146778Ssam * | DLCI (7 bits) | EA | 64146778Ssam * +----+----+----+----+----+----+----+----+ 65146778Ssam * | DLCI (6 bits) |SDLC| EA | 66146778Ssam * +----+----+----+----+----+----+----+----+ 67146778Ssam */ 6832145Spst 69146778Ssam#define FR_EA_BIT 0x01 7032145Spst 71146778Ssam#define FR_CR_BIT 0x02000000 72146778Ssam#define FR_DE_BIT 0x00020000 73146778Ssam#define FR_BECN_BIT 0x00040000 74146778Ssam#define FR_FECN_BIT 0x00080000 75146778Ssam#define FR_SDLC_BIT 0x00000002 7632145Spst 77146778Ssam 78146778Ssamstruct tok fr_header_flag_values[] = { 79146778Ssam { FR_CR_BIT, "C!" }, 80146778Ssam { FR_DE_BIT, "DE" }, 81146778Ssam { FR_BECN_BIT, "BECN" }, 82146778Ssam { FR_FECN_BIT, "FECN" }, 83146778Ssam { FR_SDLC_BIT, "sdlcore" }, 84146778Ssam { 0, NULL } 8532145Spst}; 8632145Spst 87146778Ssam 88146778Ssam/* Finds out Q.922 address length, DLCI and flags. Returns 0 on success 89146778Ssam * save the flags dep. on address length 90146778Ssam */ 91146778Ssamstatic int parse_q922_addr(const u_char *p, u_int *dlci, u_int *sdlcore, 92146778Ssam u_int *addr_len, u_int8_t *flags) 9332145Spst{ 94146778Ssam if ((p[0] & FR_EA_BIT)) 95146778Ssam return -1; 9632145Spst 97146778Ssam *addr_len = 2; 98146778Ssam *dlci = ((p[0] & 0xFC) << 2) | ((p[1] & 0xF0) >> 4); 9932145Spst 100146778Ssam flags[0] = p[0] & 0x02; /* populate the first flag fields */ 101146778Ssam flags[1] = p[1] & 0x0c; 10232145Spst 103146778Ssam if (p[1] & FR_EA_BIT) 104146778Ssam return 0; /* 2-byte Q.922 address */ 10532145Spst 106146778Ssam p += 2; 107146778Ssam (*addr_len)++; /* 3- or 4-byte Q.922 address */ 108146778Ssam if ((p[0] & FR_EA_BIT) == 0) { 109146778Ssam *dlci = (*dlci << 7) | (p[0] >> 1); 110146778Ssam (*addr_len)++; /* 4-byte Q.922 address */ 111146778Ssam p++; 112146778Ssam } 11332145Spst 114146778Ssam if ((p[0] & FR_EA_BIT) == 0) 115146778Ssam return -1; /* more than 4 bytes of Q.922 address? */ 116146778Ssam 117146778Ssam flags[3] = p[0] & 0x02; 118146778Ssam 119146778Ssam if (p[0] & 0x02) 120146778Ssam *sdlcore = p[0] >> 2; 121146778Ssam else 122146778Ssam *dlci = (*dlci << 6) | (p[0] >> 2); 123146778Ssam 124146778Ssam return 0; 12532145Spst} 12632145Spst 127146778Ssam/* Frame Relay packet structure, with flags and CRC removed 12832145Spst 12932145Spst +---------------------------+ 13032145Spst | Q.922 Address* | 13132145Spst +-- --+ 13232145Spst | | 13332145Spst +---------------------------+ 13432145Spst | Control (UI = 0x03) | 13532145Spst +---------------------------+ 13632145Spst | Optional Pad (0x00) | 13732145Spst +---------------------------+ 13832145Spst | NLPID | 13932145Spst +---------------------------+ 14032145Spst | . | 14132145Spst | . | 14232145Spst | . | 14332145Spst | Data | 14432145Spst | . | 14532145Spst | . | 14632145Spst +---------------------------+ 14732145Spst 14832145Spst * Q.922 addresses, as presently defined, are two octets and 14932145Spst contain a 10-bit DLCI. In some networks Q.922 addresses 15032145Spst may optionally be increased to three or four octets. 15132145Spst*/ 15232145Spst 153146778Ssamstatic u_int 154147904Ssamfr_hdrlen(const u_char *p, u_int addr_len) 15532145Spst{ 156147904Ssam if (!p[addr_len + 1] /* pad exist */) 157146778Ssam return addr_len + 1 /* UI */ + 1 /* pad */ + 1 /* NLPID */; 15832145Spst else 159146778Ssam return addr_len + 1 /* UI */ + 1 /* NLPID */; 16032145Spst} 16132145Spst 162146778Ssamstatic void 163146778Ssamfr_hdr_print(int length, u_int addr_len, u_int dlci, u_int8_t *flags, u_int16_t nlpid) 16432145Spst{ 165146778Ssam if (qflag) { 166146778Ssam (void)printf("Q.922, DLCI %u, length %u: ", 167146778Ssam dlci, 168146778Ssam length); 169146778Ssam } else { 170146778Ssam if (nlpid <= 0xff) /* if its smaller than 256 then its a NLPID */ 171146778Ssam (void)printf("Q.922, hdr-len %u, DLCI %u, Flags [%s], NLPID %s (0x%02x), length %u: ", 172146778Ssam addr_len, 173146778Ssam dlci, 174146778Ssam bittok2str(fr_header_flag_values, "none", EXTRACT_32BITS(flags)), 175146778Ssam tok2str(nlpid_values,"unknown", nlpid), 176146778Ssam nlpid, 177146778Ssam length); 178146778Ssam else /* must be an ethertype */ 179146778Ssam (void)printf("Q.922, hdr-len %u, DLCI %u, Flags [%s], cisco-ethertype %s (0x%04x), length %u: ", 180146778Ssam addr_len, 181146778Ssam dlci, 182146778Ssam bittok2str(fr_header_flag_values, "none", EXTRACT_32BITS(flags)), 183146778Ssam tok2str(ethertype_values, "unknown", nlpid), 184146778Ssam nlpid, 185146778Ssam length); 186146778Ssam } 18732145Spst} 18832145Spst 189146778Ssamu_int 190146778Ssamfr_if_print(const struct pcap_pkthdr *h, register const u_char *p) 19132145Spst{ 19232145Spst register u_int length = h->len; 19332145Spst register u_int caplen = h->caplen; 194147904Ssam 195147904Ssam TCHECK2(*p, 4); /* minimum frame header length */ 196147904Ssam 197147904Ssam if ((length = fr_print(p, length)) == 0) 198147904Ssam return (0); 199147904Ssam else 200147904Ssam return length; 201147904Ssam trunc: 202147904Ssam printf("[|fr]"); 203147904Ssam return caplen; 204147904Ssam} 205147904Ssam 206147904Ssamu_int 207147904Ssamfr_print(register const u_char *p, u_int length) 208147904Ssam{ 209146778Ssam u_int16_t extracted_ethertype; 210146778Ssam u_int dlci; 211146778Ssam u_int sdlcore; 212146778Ssam u_int addr_len; 213146778Ssam u_int16_t nlpid; 214146778Ssam u_int hdr_len; 215146778Ssam u_int8_t flags[4]; 21632145Spst 217146778Ssam if (parse_q922_addr(p, &dlci, &sdlcore, &addr_len, flags)) { 218146778Ssam printf("Q.922, invalid address"); 219147904Ssam return 0; 220146778Ssam } 22132145Spst 222147904Ssam TCHECK2(*p,addr_len+1+1); 223147904Ssam hdr_len = fr_hdrlen(p, addr_len); 224147904Ssam TCHECK2(*p,hdr_len); 225146778Ssam 226146778Ssam if (p[addr_len] != 0x03 && dlci != 0) { 22732145Spst 228146778Ssam /* lets figure out if we have cisco style encapsulation: */ 229146778Ssam extracted_ethertype = EXTRACT_16BITS(p+addr_len); 230146778Ssam 231146778Ssam if (eflag) 232146778Ssam fr_hdr_print(length, addr_len, dlci, flags, extracted_ethertype); 233146778Ssam 234146778Ssam if (ether_encap_print(extracted_ethertype, 235146778Ssam p+addr_len+ETHERTYPE_LEN, 236146778Ssam length-addr_len-ETHERTYPE_LEN, 237147904Ssam length-addr_len-ETHERTYPE_LEN, 238146778Ssam &extracted_ethertype) == 0) 239146778Ssam /* ether_type not known, probably it wasn't one */ 240146778Ssam printf("UI %02x! ", p[addr_len]); 241146778Ssam else 242146778Ssam return hdr_len; 243146778Ssam } 244146778Ssam 245146778Ssam if (!p[addr_len + 1]) { /* pad byte should be used with 3-byte Q.922 */ 246146778Ssam if (addr_len != 3) 247146778Ssam printf("Pad! "); 248146778Ssam } else if (addr_len == 3) 249146778Ssam printf("No pad! "); 250146778Ssam 251146778Ssam nlpid = p[hdr_len - 1]; 252146778Ssam 25332145Spst if (eflag) 254146778Ssam fr_hdr_print(length, addr_len, dlci, flags, nlpid); 25532145Spst 256146778Ssam p += hdr_len; 257146778Ssam length -= hdr_len; 25832145Spst 259146778Ssam switch (nlpid) { 26032145Spst case NLPID_IP: 261146778Ssam ip_print(gndo, p, length); 26232145Spst break; 263146778Ssam 264146778Ssam#ifdef INET6 265146778Ssam case NLPID_IP6: 266146778Ssam ip6_print(p, length); 267146778Ssam break; 268146778Ssam#endif 26932145Spst case NLPID_CLNP: 27032145Spst case NLPID_ESIS: 27132145Spst case NLPID_ISIS: 272147904Ssam isoclns_print(p-1, length+1, length+1); /* OSI printers need the NLPID field */ 27332145Spst break; 274146778Ssam 275146778Ssam case NLPID_SNAP: 276147904Ssam if (snap_print(p, length, length, &extracted_ethertype, 0) == 0) { 277146778Ssam /* ether_type not known, print raw packet */ 278146778Ssam if (!eflag) 279146778Ssam fr_hdr_print(length + hdr_len, hdr_len, 280146778Ssam dlci, flags, nlpid); 281146778Ssam if (!xflag && !qflag) 282147904Ssam default_print(p - hdr_len, length + hdr_len); 283146778Ssam } 28432145Spst break; 285146778Ssam 286146778Ssam case NLPID_Q933: 287146778Ssam q933_print(p, length); 288146778Ssam break; 289146778Ssam 290146778Ssam case NLPID_MFR: 291146778Ssam frf15_print(p, length); 292146778Ssam break; 293146778Ssam 29432145Spst default: 295146778Ssam if (!eflag) 296146778Ssam fr_hdr_print(length + hdr_len, addr_len, 297146778Ssam dlci, flags, nlpid); 298146778Ssam if (!xflag) 299147904Ssam default_print(p, length); 30032145Spst } 30132145Spst 302146778Ssam return hdr_len; 303147904Ssam 304147904Ssam trunc: 305147904Ssam printf("[|fr]"); 306147904Ssam return 0; 307147904Ssam 30832145Spst} 30932145Spst 310146778Ssam/* an NLPID of 0xb1 indicates a 2-byte 311146778Ssam * FRF.15 header 312146778Ssam * 313146778Ssam * 7 6 5 4 3 2 1 0 314146778Ssam * +----+----+----+----+----+----+----+----+ 315146778Ssam * ~ Q.922 header ~ 316146778Ssam * +----+----+----+----+----+----+----+----+ 317146778Ssam * | NLPID (8 bits) | NLPID=0xb1 318146778Ssam * +----+----+----+----+----+----+----+----+ 319146778Ssam * | B | E | C |seq. (high 4 bits) | R | 320146778Ssam * +----+----+----+----+----+----+----+----+ 321146778Ssam * | sequence (low 8 bits) | 322146778Ssam * +----+----+----+----+----+----+----+----+ 323146778Ssam */ 32432145Spst 325146778Ssamstruct tok frf15_flag_values[] = { 326146778Ssam { 0x80, "Begin" }, 327146778Ssam { 0x40, "End" }, 328146778Ssam { 0x20, "Control" }, 329146778Ssam { 0, NULL } 330146778Ssam}; 331146778Ssam 332146778Ssam#define FR_FRF15_FRAGTYPE 0x01 333146778Ssam 334146778Ssamstatic void 335146778Ssamfrf15_print (const u_char *p, u_int length) { 336146778Ssam 337146778Ssam u_int16_t sequence_num, flags; 338146778Ssam 339146778Ssam flags = p[0]&0xe0; 340146778Ssam sequence_num = (p[0]&0x1e)<<7 | p[1]; 341146778Ssam 342146778Ssam printf("FRF.15, seq 0x%03x, Flags [%s],%s Fragmentation, length %u", 343146778Ssam sequence_num, 344146778Ssam bittok2str(frf15_flag_values,"none",flags), 345146778Ssam flags&FR_FRF15_FRAGTYPE ? "Interface" : "End-to-End", 346146778Ssam length); 347146778Ssam 348146778Ssam/* TODO: 349146778Ssam * depending on all permutations of the B, E and C bit 350146778Ssam * dig as deep as we can - e.g. on the first (B) fragment 351146778Ssam * there is enough payload to print the IP header 352146778Ssam * on non (B) fragments it depends if the fragmentation 353146778Ssam * model is end-to-end or interface based wether we want to print 354146778Ssam * another Q.922 header 355146778Ssam */ 356146778Ssam 35732145Spst} 35832145Spst 35932145Spst/* 36032145Spst * Q.933 decoding portion for framerelay specific. 36132145Spst */ 36232145Spst 36332145Spst/* Q.933 packet format 36432145Spst Format of Other Protocols 36532145Spst using Q.933 NLPID 36632145Spst +-------------------------------+ 36732145Spst | Q.922 Address | 36832145Spst +---------------+---------------+ 36932145Spst |Control 0x03 | NLPID 0x08 | 37032145Spst +---------------+---------------+ 37132145Spst | L2 Protocol ID | 37232145Spst | octet 1 | octet 2 | 37332145Spst +-------------------------------+ 37432145Spst | L3 Protocol ID | 37532145Spst | octet 2 | octet 2 | 37632145Spst +-------------------------------+ 37732145Spst | Protocol Data | 37832145Spst +-------------------------------+ 37932145Spst | FCS | 38032145Spst +-------------------------------+ 38132145Spst */ 38232145Spst 38332145Spst/* L2 (Octet 1)- Call Reference Usually is 0x0 */ 38432145Spst 38532145Spst/* 38632145Spst * L2 (Octet 2)- Message Types definition 1 byte long. 38732145Spst */ 38832145Spst/* Call Establish */ 38932145Spst#define MSG_TYPE_ESC_TO_NATIONAL 0x00 39032145Spst#define MSG_TYPE_ALERT 0x01 39132145Spst#define MSG_TYPE_CALL_PROCEEDING 0x02 39232145Spst#define MSG_TYPE_CONNECT 0x07 39332145Spst#define MSG_TYPE_CONNECT_ACK 0x0F 39432145Spst#define MSG_TYPE_PROGRESS 0x03 39532145Spst#define MSG_TYPE_SETUP 0x05 39632145Spst/* Call Clear */ 39732145Spst#define MSG_TYPE_DISCONNECT 0x45 39832145Spst#define MSG_TYPE_RELEASE 0x4D 39932145Spst#define MSG_TYPE_RELEASE_COMPLETE 0x5A 40032145Spst#define MSG_TYPE_RESTART 0x46 40132145Spst#define MSG_TYPE_RESTART_ACK 0x4E 40232145Spst/* Status */ 40332145Spst#define MSG_TYPE_STATUS 0x7D 40432145Spst#define MSG_TYPE_STATUS_ENQ 0x75 40532145Spst 406146778Ssamstruct tok fr_q933_msg_values[] = { 407146778Ssam { MSG_TYPE_ESC_TO_NATIONAL, "ESC to National" }, 408146778Ssam { MSG_TYPE_ALERT, "Alert" }, 409146778Ssam { MSG_TYPE_CALL_PROCEEDING, "Call proceeding" }, 410146778Ssam { MSG_TYPE_CONNECT, "Connect" }, 411146778Ssam { MSG_TYPE_CONNECT_ACK, "Connect ACK" }, 412146778Ssam { MSG_TYPE_PROGRESS, "Progress" }, 413146778Ssam { MSG_TYPE_SETUP, "Setup" }, 414146778Ssam { MSG_TYPE_DISCONNECT, "Disconnect" }, 415146778Ssam { MSG_TYPE_RELEASE, "Release" }, 416146778Ssam { MSG_TYPE_RELEASE_COMPLETE, "Release Complete" }, 417146778Ssam { MSG_TYPE_RESTART, "Restart" }, 418146778Ssam { MSG_TYPE_RESTART_ACK, "Restart ACK" }, 419146778Ssam { MSG_TYPE_STATUS, "Status Reply" }, 420146778Ssam { MSG_TYPE_STATUS_ENQ, "Status Enquiry" }, 421146778Ssam { 0, NULL } 422146778Ssam}; 42332145Spst 424146778Ssam#define MSG_ANSI_LOCKING_SHIFT 0x95 425146778Ssam 426146778Ssam#define FR_LMI_ANSI_REPORT_TYPE_IE 0x01 427146778Ssam#define FR_LMI_ANSI_LINK_VERIFY_IE_91 0x19 /* details? */ 428146778Ssam#define FR_LMI_ANSI_LINK_VERIFY_IE 0x03 429146778Ssam#define FR_LMI_ANSI_PVC_STATUS_IE 0x07 430146778Ssam 431146778Ssam#define FR_LMI_CCITT_REPORT_TYPE_IE 0x51 432146778Ssam#define FR_LMI_CCITT_LINK_VERIFY_IE 0x53 433146778Ssam#define FR_LMI_CCITT_PVC_STATUS_IE 0x57 434146778Ssam 435146778Ssamstruct tok fr_q933_ie_values_codeset5[] = { 436146778Ssam { FR_LMI_ANSI_REPORT_TYPE_IE, "ANSI Report Type" }, 437146778Ssam { FR_LMI_ANSI_LINK_VERIFY_IE_91, "ANSI Link Verify" }, 438146778Ssam { FR_LMI_ANSI_LINK_VERIFY_IE, "ANSI Link Verify" }, 439146778Ssam { FR_LMI_ANSI_PVC_STATUS_IE, "ANSI PVC Status" }, 440146778Ssam { FR_LMI_CCITT_REPORT_TYPE_IE, "CCITT Report Type" }, 441146778Ssam { FR_LMI_CCITT_LINK_VERIFY_IE, "CCITT Link Verify" }, 442146778Ssam { FR_LMI_CCITT_PVC_STATUS_IE, "CCITT PVC Status" }, 443146778Ssam { 0, NULL } 44432145Spst}; 44532145Spst 446146778Ssam#define FR_LMI_REPORT_TYPE_IE_FULL_STATUS 0 447146778Ssam#define FR_LMI_REPORT_TYPE_IE_LINK_VERIFY 1 448146778Ssam#define FR_LMI_REPORT_TYPE_IE_ASYNC_PVC 2 44932145Spst 450146778Ssamstruct tok fr_lmi_report_type_ie_values[] = { 451146778Ssam { FR_LMI_REPORT_TYPE_IE_FULL_STATUS, "Full Status" }, 452146778Ssam { FR_LMI_REPORT_TYPE_IE_LINK_VERIFY, "Link verify" }, 453146778Ssam { FR_LMI_REPORT_TYPE_IE_ASYNC_PVC, "Async PVC Status" }, 454146778Ssam { 0, NULL } 455146778Ssam}; 45632145Spst 457146778Ssam/* array of 16 codepages - currently we only support codepage 5 */ 458146778Ssamstatic struct tok *fr_q933_ie_codesets[] = { 459146778Ssam NULL, 460146778Ssam NULL, 461146778Ssam NULL, 462146778Ssam NULL, 463146778Ssam NULL, 464146778Ssam fr_q933_ie_values_codeset5, 465146778Ssam NULL, 466146778Ssam NULL, 467146778Ssam NULL, 468146778Ssam NULL, 469146778Ssam NULL, 470146778Ssam NULL, 471146778Ssam NULL, 472146778Ssam NULL, 473146778Ssam NULL, 474146778Ssam NULL 47532145Spst}; 47632145Spst 47732145Spst 478146778Ssamstruct common_ie_header { 479146778Ssam u_int8_t ie_id; 480146778Ssam u_int8_t ie_len; 481146778Ssam}; 48232145Spst 483147904Ssamstatic int fr_q933_print_ie_codeset5(const struct common_ie_header *ie_p, 484147904Ssam const u_char *p); 485147904Ssam 486147904Ssamtypedef int (*codeset_pr_func_t)(const struct common_ie_header *ie_p, 487147904Ssam const u_char *p); 488147904Ssam 489147904Ssam/* array of 16 codepages - currently we only support codepage 5 */ 490147904Ssamstatic codeset_pr_func_t fr_q933_print_ie_codeset[] = { 491147904Ssam NULL, 492147904Ssam NULL, 493147904Ssam NULL, 494147904Ssam NULL, 495147904Ssam NULL, 496147904Ssam fr_q933_print_ie_codeset5, 497147904Ssam NULL, 498147904Ssam NULL, 499147904Ssam NULL, 500147904Ssam NULL, 501147904Ssam NULL, 502147904Ssam NULL, 503147904Ssam NULL, 504147904Ssam NULL, 505147904Ssam NULL, 506147904Ssam NULL 507147904Ssam}; 508147904Ssam 50932145Spstvoid 510146778Ssamq933_print(const u_char *p, u_int length) 51132145Spst{ 51232145Spst const u_char *ptemp = p; 51332145Spst struct common_ie_header *ie_p; 514146778Ssam int olen; 515146778Ssam int is_ansi = 0; 516147904Ssam u_int codeset; 517146778Ssam 518146778Ssam if (length < 9) { /* shortest: Q.933a LINK VERIFY */ 519146778Ssam printf("[|q.933]"); 520146778Ssam return; 521146778Ssam } 522146778Ssam 523146778Ssam codeset = p[2]&0x0f; /* extract the codeset */ 524146778Ssam 525146778Ssam if (p[2] == MSG_ANSI_LOCKING_SHIFT) 526146778Ssam is_ansi = 1; 52732145Spst 528146778Ssam printf("%s", eflag ? "" : "Q.933, "); 52932145Spst 53032145Spst /* printing out header part */ 531147904Ssam printf(is_ansi ? "ANSI" : "CCITT"); 532146778Ssam 533146778Ssam if (p[0]) 534146778Ssam printf(", Call Ref: 0x%02x", p[0]); 535146778Ssam 536146778Ssam if (vflag) 537146778Ssam printf(", %s (0x%02x), length %u", 538146778Ssam tok2str(fr_q933_msg_values,"unknown message",p[1]), 539146778Ssam p[1], 540146778Ssam length); 541146778Ssam else 542146778Ssam printf(", %s", 543146778Ssam tok2str(fr_q933_msg_values,"unknown message 0x%02x",p[1])); 544146778Ssam 545146778Ssam olen = length; /* preserve the original length for non verbose mode */ 546146778Ssam 547146778Ssam if (length < (u_int)(2 - is_ansi)) { 548146778Ssam printf("[|q.933]"); 549146778Ssam return; 55032145Spst } 551146778Ssam length -= 2 - is_ansi; 552146778Ssam ptemp += 2 + is_ansi; 55332145Spst 55432145Spst /* Loop through the rest of IE */ 555146778Ssam while (length > sizeof(struct common_ie_header)) { 55632145Spst ie_p = (struct common_ie_header *)ptemp; 557146778Ssam if (length < sizeof(struct common_ie_header) || 558146778Ssam length < sizeof(struct common_ie_header) + ie_p->ie_len) { 559146778Ssam if (vflag) /* not bark if there is just a trailer */ 560146778Ssam printf("\n[|q.933]"); 561146778Ssam else 562146778Ssam printf(", length %u",olen); 563146778Ssam return; 56432145Spst } 56532145Spst 566146778Ssam /* lets do the full IE parsing only in verbose mode 567146778Ssam * however some IEs (DLCI Status, Link Verify) 568146778Ssam * are also intereststing in non-verbose mode */ 569146778Ssam if (vflag) 570146778Ssam printf("\n\t%s IE (%u), length %u: ", 571146778Ssam tok2str(fr_q933_ie_codesets[codeset],"unknown",ie_p->ie_id), 572146778Ssam ie_p->ie_id, 573146778Ssam ie_p->ie_len); 574146778Ssam 575147904Ssam if (!fr_q933_print_ie_codeset[codeset] || 576147904Ssam (*fr_q933_print_ie_codeset[codeset])(ie_p, ptemp)) { 577146778Ssam if (vflag <= 1) 578146778Ssam print_unknown_data(ptemp+2,"\n\t",ie_p->ie_len); 579146778Ssam } 58032145Spst 581146778Ssam /* do we want to see a hexdump of the IE ? */ 582146778Ssam if (vflag> 1) 583146778Ssam print_unknown_data(ptemp+2,"\n\t ",ie_p->ie_len); 58432145Spst 585146778Ssam length = length - ie_p->ie_len - 2; 586146778Ssam ptemp = ptemp + ie_p->ie_len + 2; 587146778Ssam } 588146778Ssam if (!vflag) 589146778Ssam printf(", length %u",olen); 590146778Ssam} 591147904Ssam 592147904Ssamstatic int 593147904Ssamfr_q933_print_ie_codeset5(const struct common_ie_header *ie_p, const u_char *p) 594147904Ssam{ 595147904Ssam u_int dlci; 596147904Ssam 597147904Ssam switch (ie_p->ie_id) { 598147904Ssam 599147904Ssam case FR_LMI_ANSI_REPORT_TYPE_IE: /* fall through */ 600147904Ssam case FR_LMI_CCITT_REPORT_TYPE_IE: 601147904Ssam if (vflag) 602147904Ssam printf("%s (%u)", 603147904Ssam tok2str(fr_lmi_report_type_ie_values,"unknown",p[2]), 604147904Ssam p[2]); 605147904Ssam return 1; 606147904Ssam 607147904Ssam case FR_LMI_ANSI_LINK_VERIFY_IE: /* fall through */ 608147904Ssam case FR_LMI_CCITT_LINK_VERIFY_IE: 609147904Ssam case FR_LMI_ANSI_LINK_VERIFY_IE_91: 610147904Ssam if (!vflag) 611147904Ssam printf(", "); 612147904Ssam printf("TX Seq: %3d, RX Seq: %3d", p[2], p[3]); 613147904Ssam return 1; 614147904Ssam 615147904Ssam case FR_LMI_ANSI_PVC_STATUS_IE: /* fall through */ 616147904Ssam case FR_LMI_CCITT_PVC_STATUS_IE: 617147904Ssam if (!vflag) 618147904Ssam printf(", "); 619147904Ssam /* now parse the DLCI information element. */ 620147904Ssam if ((ie_p->ie_len < 3) || 621147904Ssam (p[2] & 0x80) || 622147904Ssam ((ie_p->ie_len == 3) && !(p[3] & 0x80)) || 623147904Ssam ((ie_p->ie_len == 4) && ((p[3] & 0x80) || !(p[4] & 0x80))) || 624147904Ssam ((ie_p->ie_len == 5) && ((p[3] & 0x80) || (p[4] & 0x80) || 625147904Ssam !(p[5] & 0x80))) || 626147904Ssam (ie_p->ie_len > 5) || 627147904Ssam !(p[ie_p->ie_len + 1] & 0x80)) 628147904Ssam printf("Invalid DLCI IE"); 629147904Ssam 630147904Ssam dlci = ((p[2] & 0x3F) << 4) | ((p[3] & 0x78) >> 3); 631147904Ssam if (ie_p->ie_len == 4) 632147904Ssam dlci = (dlci << 6) | ((p[4] & 0x7E) >> 1); 633147904Ssam else if (ie_p->ie_len == 5) 634147904Ssam dlci = (dlci << 13) | (p[4] & 0x7F) | ((p[5] & 0x7E) >> 1); 635147904Ssam 636147904Ssam printf("DLCI %u: status %s%s", dlci, 637147904Ssam p[ie_p->ie_len + 1] & 0x8 ? "New, " : "", 638147904Ssam p[ie_p->ie_len + 1] & 0x2 ? "Active" : "Inactive"); 639147904Ssam return 1; 640147904Ssam } 641147904Ssam 642147904Ssam return 0; 643147904Ssam} 644