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. 2032145Spst */ 2132145Spst 22313537Sglebius/* \summary: Frame Relay printer */ 23313537Sglebius 24146778Ssam#ifdef HAVE_CONFIG_H 25146778Ssam#include "config.h" 2632145Spst#endif 2732145Spst 28313537Sglebius#include <netdissect-stdinc.h> 2932145Spst 30146778Ssam#include <stdio.h> 31146778Ssam#include <string.h> 3232145Spst 33313537Sglebius#include "netdissect.h" 34146778Ssam#include "addrtoname.h" 3532145Spst#include "ethertype.h" 36285275Spkelsey#include "llc.h" 37146778Ssam#include "nlpid.h" 38146778Ssam#include "extract.h" 39146778Ssam#include "oui.h" 4032145Spst 41276788Sdelphijstatic void frf15_print(netdissect_options *ndo, const u_char *, u_int); 4232145Spst 43146778Ssam/* 44146778Ssam * the frame relay header has a variable length 45146778Ssam * 46146778Ssam * the EA bit determines if there is another byte 47146778Ssam * in the header 48146778Ssam * 49146778Ssam * minimum header length is 2 bytes 50146778Ssam * maximum header length is 4 bytes 51146778Ssam * 52146778Ssam * 7 6 5 4 3 2 1 0 53146778Ssam * +----+----+----+----+----+----+----+----+ 54146778Ssam * | DLCI (6 bits) | CR | EA | 55146778Ssam * +----+----+----+----+----+----+----+----+ 56146778Ssam * | DLCI (4 bits) |FECN|BECN| DE | EA | 57146778Ssam * +----+----+----+----+----+----+----+----+ 58146778Ssam * | DLCI (7 bits) | EA | 59146778Ssam * +----+----+----+----+----+----+----+----+ 60146778Ssam * | DLCI (6 bits) |SDLC| EA | 61146778Ssam * +----+----+----+----+----+----+----+----+ 62146778Ssam */ 6332145Spst 64146778Ssam#define FR_EA_BIT 0x01 6532145Spst 66146778Ssam#define FR_CR_BIT 0x02000000 67146778Ssam#define FR_DE_BIT 0x00020000 68146778Ssam#define FR_BECN_BIT 0x00040000 69146778Ssam#define FR_FECN_BIT 0x00080000 70146778Ssam#define FR_SDLC_BIT 0x00000002 7132145Spst 72146778Ssam 73276788Sdelphijstatic const struct tok fr_header_flag_values[] = { 74146778Ssam { FR_CR_BIT, "C!" }, 75146778Ssam { FR_DE_BIT, "DE" }, 76146778Ssam { FR_BECN_BIT, "BECN" }, 77146778Ssam { FR_FECN_BIT, "FECN" }, 78146778Ssam { FR_SDLC_BIT, "sdlcore" }, 79146778Ssam { 0, NULL } 8032145Spst}; 8132145Spst 82162021Ssam/* FRF.15 / FRF.16 */ 83162021Ssam#define MFR_B_BIT 0x80 84162021Ssam#define MFR_E_BIT 0x40 85162021Ssam#define MFR_C_BIT 0x20 86162021Ssam#define MFR_BEC_MASK (MFR_B_BIT | MFR_E_BIT | MFR_C_BIT) 87162021Ssam#define MFR_CTRL_FRAME (MFR_B_BIT | MFR_E_BIT | MFR_C_BIT) 88162021Ssam#define MFR_FRAG_FRAME (MFR_B_BIT | MFR_E_BIT ) 89146778Ssam 90276788Sdelphijstatic const struct tok frf_flag_values[] = { 91162021Ssam { MFR_B_BIT, "Begin" }, 92162021Ssam { MFR_E_BIT, "End" }, 93162021Ssam { MFR_C_BIT, "Control" }, 94162021Ssam { 0, NULL } 95162021Ssam}; 96162021Ssam 97285275Spkelsey/* Finds out Q.922 address length, DLCI and flags. Returns 1 on success, 98285275Spkelsey * 0 on invalid address, -1 on truncated packet 99146778Ssam * save the flags dep. on address length 100146778Ssam */ 101285275Spkelseystatic int parse_q922_addr(netdissect_options *ndo, 102285275Spkelsey const u_char *p, u_int *dlci, 103285275Spkelsey u_int *addr_len, uint8_t *flags, u_int length) 10432145Spst{ 105285275Spkelsey if (!ND_TTEST(p[0]) || length < 1) 106285275Spkelsey return -1; 107146778Ssam if ((p[0] & FR_EA_BIT)) 108285275Spkelsey return 0; 109285275Spkelsey 110285275Spkelsey if (!ND_TTEST(p[1]) || length < 2) 111146778Ssam return -1; 112146778Ssam *addr_len = 2; 113146778Ssam *dlci = ((p[0] & 0xFC) << 2) | ((p[1] & 0xF0) >> 4); 11432145Spst 115146778Ssam flags[0] = p[0] & 0x02; /* populate the first flag fields */ 116146778Ssam flags[1] = p[1] & 0x0c; 117172686Smlaier flags[2] = 0; /* clear the rest of the flags */ 118172686Smlaier flags[3] = 0; 11932145Spst 120146778Ssam if (p[1] & FR_EA_BIT) 121285275Spkelsey return 1; /* 2-byte Q.922 address */ 12232145Spst 123146778Ssam p += 2; 124285275Spkelsey length -= 2; 125285275Spkelsey if (!ND_TTEST(p[0]) || length < 1) 126285275Spkelsey return -1; 127146778Ssam (*addr_len)++; /* 3- or 4-byte Q.922 address */ 128146778Ssam if ((p[0] & FR_EA_BIT) == 0) { 129146778Ssam *dlci = (*dlci << 7) | (p[0] >> 1); 130146778Ssam (*addr_len)++; /* 4-byte Q.922 address */ 131146778Ssam p++; 132285275Spkelsey length--; 133146778Ssam } 13432145Spst 135285275Spkelsey if (!ND_TTEST(p[0]) || length < 1) 136285275Spkelsey return -1; 137146778Ssam if ((p[0] & FR_EA_BIT) == 0) 138285275Spkelsey return 0; /* more than 4 bytes of Q.922 address? */ 139146778Ssam 140146778Ssam flags[3] = p[0] & 0x02; 141146778Ssam 142190207Srpaulo *dlci = (*dlci << 6) | (p[0] >> 2); 143146778Ssam 144285275Spkelsey return 1; 14532145Spst} 14632145Spst 147285275Spkelseychar * 148285275Spkelseyq922_string(netdissect_options *ndo, const u_char *p, u_int length) 149285275Spkelsey{ 150190207Srpaulo 151190207Srpaulo static u_int dlci, addr_len; 152276788Sdelphij static uint8_t flags[4]; 153190207Srpaulo static char buffer[sizeof("DLCI xxxxxxxxxx")]; 154190207Srpaulo memset(buffer, 0, sizeof(buffer)); 155190207Srpaulo 156285275Spkelsey if (parse_q922_addr(ndo, p, &dlci, &addr_len, flags, length) == 1){ 157190207Srpaulo snprintf(buffer, sizeof(buffer), "DLCI %u", dlci); 158190207Srpaulo } 159190207Srpaulo 160190207Srpaulo return buffer; 161190207Srpaulo} 162190207Srpaulo 163190207Srpaulo 164146778Ssam/* Frame Relay packet structure, with flags and CRC removed 16532145Spst 16632145Spst +---------------------------+ 16732145Spst | Q.922 Address* | 16832145Spst +-- --+ 16932145Spst | | 17032145Spst +---------------------------+ 17132145Spst | Control (UI = 0x03) | 17232145Spst +---------------------------+ 17332145Spst | Optional Pad (0x00) | 17432145Spst +---------------------------+ 17532145Spst | NLPID | 17632145Spst +---------------------------+ 17732145Spst | . | 17832145Spst | . | 17932145Spst | . | 18032145Spst | Data | 18132145Spst | . | 18232145Spst | . | 18332145Spst +---------------------------+ 18432145Spst 18532145Spst * Q.922 addresses, as presently defined, are two octets and 18632145Spst contain a 10-bit DLCI. In some networks Q.922 addresses 18732145Spst may optionally be increased to three or four octets. 18832145Spst*/ 18932145Spst 190146778Ssamstatic void 191276788Sdelphijfr_hdr_print(netdissect_options *ndo, 192276788Sdelphij int length, u_int addr_len, u_int dlci, uint8_t *flags, uint16_t nlpid) 19332145Spst{ 194276788Sdelphij if (ndo->ndo_qflag) { 195276788Sdelphij ND_PRINT((ndo, "Q.922, DLCI %u, length %u: ", 196146778Ssam dlci, 197276788Sdelphij length)); 198146778Ssam } else { 199146778Ssam if (nlpid <= 0xff) /* if its smaller than 256 then its a NLPID */ 200276788Sdelphij ND_PRINT((ndo, "Q.922, hdr-len %u, DLCI %u, Flags [%s], NLPID %s (0x%02x), length %u: ", 201146778Ssam addr_len, 202146778Ssam dlci, 203146778Ssam bittok2str(fr_header_flag_values, "none", EXTRACT_32BITS(flags)), 204146778Ssam tok2str(nlpid_values,"unknown", nlpid), 205146778Ssam nlpid, 206276788Sdelphij length)); 207146778Ssam else /* must be an ethertype */ 208276788Sdelphij ND_PRINT((ndo, "Q.922, hdr-len %u, DLCI %u, Flags [%s], cisco-ethertype %s (0x%04x), length %u: ", 209146778Ssam addr_len, 210146778Ssam dlci, 211146778Ssam bittok2str(fr_header_flag_values, "none", EXTRACT_32BITS(flags)), 212146778Ssam tok2str(ethertype_values, "unknown", nlpid), 213146778Ssam nlpid, 214276788Sdelphij length)); 215146778Ssam } 21632145Spst} 21732145Spst 218146778Ssamu_int 219276788Sdelphijfr_if_print(netdissect_options *ndo, 220276788Sdelphij const struct pcap_pkthdr *h, register const u_char *p) 22132145Spst{ 22232145Spst register u_int length = h->len; 22332145Spst register u_int caplen = h->caplen; 224147904Ssam 225276788Sdelphij ND_TCHECK2(*p, 4); /* minimum frame header length */ 226147904Ssam 227276788Sdelphij if ((length = fr_print(ndo, p, length)) == 0) 228147904Ssam return (0); 229147904Ssam else 230147904Ssam return length; 231147904Ssam trunc: 232276788Sdelphij ND_PRINT((ndo, "[|fr]")); 233147904Ssam return caplen; 234147904Ssam} 235147904Ssam 236147904Ssamu_int 237276788Sdelphijfr_print(netdissect_options *ndo, 238276788Sdelphij register const u_char *p, u_int length) 239147904Ssam{ 240285275Spkelsey int ret; 241276788Sdelphij uint16_t extracted_ethertype; 242146778Ssam u_int dlci; 243146778Ssam u_int addr_len; 244276788Sdelphij uint16_t nlpid; 245146778Ssam u_int hdr_len; 246276788Sdelphij uint8_t flags[4]; 24732145Spst 248285275Spkelsey ret = parse_q922_addr(ndo, p, &dlci, &addr_len, flags, length); 249285275Spkelsey if (ret == -1) 250285275Spkelsey goto trunc; 251285275Spkelsey if (ret == 0) { 252276788Sdelphij ND_PRINT((ndo, "Q.922, invalid address")); 253147904Ssam return 0; 254146778Ssam } 25532145Spst 256285275Spkelsey ND_TCHECK(p[addr_len]); 257285275Spkelsey if (length < addr_len + 1) 258285275Spkelsey goto trunc; 259146778Ssam 260285275Spkelsey if (p[addr_len] != LLC_UI && dlci != 0) { 261285275Spkelsey /* 262285275Spkelsey * Let's figure out if we have Cisco-style encapsulation, 263285275Spkelsey * with an Ethernet type (Cisco HDLC type?) following the 264285275Spkelsey * address. 265285275Spkelsey */ 266285275Spkelsey if (!ND_TTEST2(p[addr_len], 2) || length < addr_len + 2) { 267285275Spkelsey /* no Ethertype */ 268285275Spkelsey ND_PRINT((ndo, "UI %02x! ", p[addr_len])); 269285275Spkelsey } else { 270285275Spkelsey extracted_ethertype = EXTRACT_16BITS(p+addr_len); 27132145Spst 272285275Spkelsey if (ndo->ndo_eflag) 273285275Spkelsey fr_hdr_print(ndo, length, addr_len, dlci, 274285275Spkelsey flags, extracted_ethertype); 275146778Ssam 276285275Spkelsey if (ethertype_print(ndo, extracted_ethertype, 277285275Spkelsey p+addr_len+ETHERTYPE_LEN, 278285275Spkelsey length-addr_len-ETHERTYPE_LEN, 279313537Sglebius ndo->ndo_snapend-p-addr_len-ETHERTYPE_LEN, 280313537Sglebius NULL, NULL) == 0) 281285275Spkelsey /* ether_type not known, probably it wasn't one */ 282285275Spkelsey ND_PRINT((ndo, "UI %02x! ", p[addr_len])); 283285275Spkelsey else 284285275Spkelsey return addr_len + 2; 285285275Spkelsey } 286146778Ssam } 287146778Ssam 288285275Spkelsey ND_TCHECK(p[addr_len+1]); 289285275Spkelsey if (length < addr_len + 2) 290285275Spkelsey goto trunc; 291285275Spkelsey 292285275Spkelsey if (p[addr_len + 1] == 0) { 293285275Spkelsey /* 294285275Spkelsey * Assume a pad byte after the control (UI) byte. 295285275Spkelsey * A pad byte should only be used with 3-byte Q.922. 296285275Spkelsey */ 297146778Ssam if (addr_len != 3) 298276788Sdelphij ND_PRINT((ndo, "Pad! ")); 299285275Spkelsey hdr_len = addr_len + 1 /* UI */ + 1 /* pad */ + 1 /* NLPID */; 300285275Spkelsey } else { 301285275Spkelsey /* 302285275Spkelsey * Not a pad byte. 303285275Spkelsey * A pad byte should be used with 3-byte Q.922. 304285275Spkelsey */ 305285275Spkelsey if (addr_len == 3) 306285275Spkelsey ND_PRINT((ndo, "No pad! ")); 307285275Spkelsey hdr_len = addr_len + 1 /* UI */ + 1 /* NLPID */; 308285275Spkelsey } 309146778Ssam 310285275Spkelsey ND_TCHECK(p[hdr_len - 1]); 311285275Spkelsey if (length < hdr_len) 312285275Spkelsey goto trunc; 313146778Ssam nlpid = p[hdr_len - 1]; 314146778Ssam 315276788Sdelphij if (ndo->ndo_eflag) 316276788Sdelphij fr_hdr_print(ndo, length, addr_len, dlci, flags, nlpid); 317146778Ssam p += hdr_len; 318146778Ssam length -= hdr_len; 31932145Spst 320146778Ssam switch (nlpid) { 32132145Spst case NLPID_IP: 322276788Sdelphij ip_print(ndo, p, length); 32332145Spst break; 324146778Ssam 325146778Ssam case NLPID_IP6: 326276788Sdelphij ip6_print(ndo, p, length); 327146778Ssam break; 328285275Spkelsey 32932145Spst case NLPID_CLNP: 33032145Spst case NLPID_ESIS: 33132145Spst case NLPID_ISIS: 332327234Semaste isoclns_print(ndo, p - 1, length + 1); /* OSI printers need the NLPID field */ 33332145Spst break; 334146778Ssam 335146778Ssam case NLPID_SNAP: 336313537Sglebius if (snap_print(ndo, p, length, ndo->ndo_snapend - p, NULL, NULL, 0) == 0) { 337146778Ssam /* ether_type not known, print raw packet */ 338276788Sdelphij if (!ndo->ndo_eflag) 339276788Sdelphij fr_hdr_print(ndo, length + hdr_len, hdr_len, 340146778Ssam dlci, flags, nlpid); 341276788Sdelphij if (!ndo->ndo_suppress_default_print) 342276788Sdelphij ND_DEFAULTPRINT(p - hdr_len, length + hdr_len); 343146778Ssam } 34432145Spst break; 345146778Ssam 346146778Ssam case NLPID_Q933: 347276788Sdelphij q933_print(ndo, p, length); 348146778Ssam break; 349146778Ssam 350146778Ssam case NLPID_MFR: 351276788Sdelphij frf15_print(ndo, p, length); 352146778Ssam break; 353146778Ssam 354172686Smlaier case NLPID_PPP: 355276788Sdelphij ppp_print(ndo, p, length); 356172686Smlaier break; 357172686Smlaier 35832145Spst default: 359276788Sdelphij if (!ndo->ndo_eflag) 360276788Sdelphij fr_hdr_print(ndo, length + hdr_len, addr_len, 361146778Ssam dlci, flags, nlpid); 362276788Sdelphij if (!ndo->ndo_xflag) 363276788Sdelphij ND_DEFAULTPRINT(p, length); 36432145Spst } 36532145Spst 366146778Ssam return hdr_len; 367147904Ssam 368147904Ssam trunc: 369276788Sdelphij ND_PRINT((ndo, "[|fr]")); 370147904Ssam return 0; 371147904Ssam 37232145Spst} 37332145Spst 374172686Smlaieru_int 375276788Sdelphijmfr_if_print(netdissect_options *ndo, 376276788Sdelphij const struct pcap_pkthdr *h, register const u_char *p) 377172686Smlaier{ 378172686Smlaier register u_int length = h->len; 379172686Smlaier register u_int caplen = h->caplen; 380172686Smlaier 381276788Sdelphij ND_TCHECK2(*p, 2); /* minimum frame header length */ 382172686Smlaier 383276788Sdelphij if ((length = mfr_print(ndo, p, length)) == 0) 384172686Smlaier return (0); 385172686Smlaier else 386172686Smlaier return length; 387172686Smlaier trunc: 388276788Sdelphij ND_PRINT((ndo, "[|mfr]")); 389172686Smlaier return caplen; 390172686Smlaier} 391172686Smlaier 392172686Smlaier 393162021Ssam#define MFR_CTRL_MSG_ADD_LINK 1 394162021Ssam#define MFR_CTRL_MSG_ADD_LINK_ACK 2 395162021Ssam#define MFR_CTRL_MSG_ADD_LINK_REJ 3 396162021Ssam#define MFR_CTRL_MSG_HELLO 4 397162021Ssam#define MFR_CTRL_MSG_HELLO_ACK 5 398162021Ssam#define MFR_CTRL_MSG_REMOVE_LINK 6 399162021Ssam#define MFR_CTRL_MSG_REMOVE_LINK_ACK 7 400162021Ssam 401276788Sdelphijstatic const struct tok mfr_ctrl_msg_values[] = { 402162021Ssam { MFR_CTRL_MSG_ADD_LINK, "Add Link" }, 403162021Ssam { MFR_CTRL_MSG_ADD_LINK_ACK, "Add Link ACK" }, 404162021Ssam { MFR_CTRL_MSG_ADD_LINK_REJ, "Add Link Reject" }, 405162021Ssam { MFR_CTRL_MSG_HELLO, "Hello" }, 406162021Ssam { MFR_CTRL_MSG_HELLO_ACK, "Hello ACK" }, 407162021Ssam { MFR_CTRL_MSG_REMOVE_LINK, "Remove Link" }, 408162021Ssam { MFR_CTRL_MSG_REMOVE_LINK_ACK, "Remove Link ACK" }, 409162021Ssam { 0, NULL } 410162021Ssam}; 411162021Ssam 412162021Ssam#define MFR_CTRL_IE_BUNDLE_ID 1 413162021Ssam#define MFR_CTRL_IE_LINK_ID 2 414162021Ssam#define MFR_CTRL_IE_MAGIC_NUM 3 415162021Ssam#define MFR_CTRL_IE_TIMESTAMP 5 416162021Ssam#define MFR_CTRL_IE_VENDOR_EXT 6 417162021Ssam#define MFR_CTRL_IE_CAUSE 7 418162021Ssam 419276788Sdelphijstatic const struct tok mfr_ctrl_ie_values[] = { 420162021Ssam { MFR_CTRL_IE_BUNDLE_ID, "Bundle ID"}, 421162021Ssam { MFR_CTRL_IE_LINK_ID, "Link ID"}, 422162021Ssam { MFR_CTRL_IE_MAGIC_NUM, "Magic Number"}, 423162021Ssam { MFR_CTRL_IE_TIMESTAMP, "Timestamp"}, 424162021Ssam { MFR_CTRL_IE_VENDOR_EXT, "Vendor Extension"}, 425162021Ssam { MFR_CTRL_IE_CAUSE, "Cause"}, 426162021Ssam { 0, NULL } 427162021Ssam}; 428162021Ssam 429162021Ssam#define MFR_ID_STRING_MAXLEN 50 430162021Ssam 431162021Ssamstruct ie_tlv_header_t { 432276788Sdelphij uint8_t ie_type; 433276788Sdelphij uint8_t ie_len; 434162021Ssam}; 435162021Ssam 436162021Ssamu_int 437276788Sdelphijmfr_print(netdissect_options *ndo, 438276788Sdelphij register const u_char *p, u_int length) 439162021Ssam{ 440162021Ssam u_int tlen,idx,hdr_len = 0; 441276788Sdelphij uint16_t sequence_num; 442276788Sdelphij uint8_t ie_type,ie_len; 443276788Sdelphij const uint8_t *tptr; 444162021Ssam 445162021Ssam 446162021Ssam/* 447162021Ssam * FRF.16 Link Integrity Control Frame 448276788Sdelphij * 449162021Ssam * 7 6 5 4 3 2 1 0 450162021Ssam * +----+----+----+----+----+----+----+----+ 451162021Ssam * | B | E | C=1| 0 0 0 0 | EA | 452162021Ssam * +----+----+----+----+----+----+----+----+ 453162021Ssam * | 0 0 0 0 0 0 0 0 | 454162021Ssam * +----+----+----+----+----+----+----+----+ 455162021Ssam * | message type | 456162021Ssam * +----+----+----+----+----+----+----+----+ 457162021Ssam */ 458162021Ssam 459276788Sdelphij ND_TCHECK2(*p, 4); /* minimum frame header length */ 460356341Scy if (length < 4) { 461356341Scy ND_PRINT((ndo, "Message too short (%u bytes)", length)); 462356341Scy return length; 463356341Scy } 464162021Ssam 465162021Ssam if ((p[0] & MFR_BEC_MASK) == MFR_CTRL_FRAME && p[1] == 0) { 466276788Sdelphij ND_PRINT((ndo, "FRF.16 Control, Flags [%s], %s, length %u", 467162021Ssam bittok2str(frf_flag_values,"none",(p[0] & MFR_BEC_MASK)), 468162021Ssam tok2str(mfr_ctrl_msg_values,"Unknown Message (0x%02x)",p[2]), 469276788Sdelphij length)); 470162021Ssam tptr = p + 3; 471162021Ssam tlen = length -3; 472162021Ssam hdr_len = 3; 473162021Ssam 474276788Sdelphij if (!ndo->ndo_vflag) 475162021Ssam return hdr_len; 476162021Ssam 477162021Ssam while (tlen>sizeof(struct ie_tlv_header_t)) { 478276788Sdelphij ND_TCHECK2(*tptr, sizeof(struct ie_tlv_header_t)); 479162021Ssam ie_type=tptr[0]; 480162021Ssam ie_len=tptr[1]; 481162021Ssam 482276788Sdelphij ND_PRINT((ndo, "\n\tIE %s (%u), length %u: ", 483162021Ssam tok2str(mfr_ctrl_ie_values,"Unknown",ie_type), 484162021Ssam ie_type, 485276788Sdelphij ie_len)); 486162021Ssam 487162021Ssam /* infinite loop check */ 488162021Ssam if (ie_type == 0 || ie_len <= sizeof(struct ie_tlv_header_t)) 489162021Ssam return hdr_len; 490162021Ssam 491276788Sdelphij ND_TCHECK2(*tptr, ie_len); 492162021Ssam tptr+=sizeof(struct ie_tlv_header_t); 493162021Ssam /* tlv len includes header */ 494162021Ssam ie_len-=sizeof(struct ie_tlv_header_t); 495162021Ssam tlen-=sizeof(struct ie_tlv_header_t); 496162021Ssam 497162021Ssam switch (ie_type) { 498162021Ssam 499162021Ssam case MFR_CTRL_IE_MAGIC_NUM: 500356341Scy /* FRF.16.1 Section 3.4.3 Magic Number Information Element */ 501356341Scy if (ie_len != 4) { 502356341Scy ND_PRINT((ndo, "(invalid length)")); 503356341Scy break; 504356341Scy } 505276788Sdelphij ND_PRINT((ndo, "0x%08x", EXTRACT_32BITS(tptr))); 506162021Ssam break; 507162021Ssam 508162021Ssam case MFR_CTRL_IE_BUNDLE_ID: /* same message format */ 509162021Ssam case MFR_CTRL_IE_LINK_ID: 510162021Ssam for (idx = 0; idx < ie_len && idx < MFR_ID_STRING_MAXLEN; idx++) { 511162021Ssam if (*(tptr+idx) != 0) /* don't print null termination */ 512276788Sdelphij safeputchar(ndo, *(tptr + idx)); 513162021Ssam else 514162021Ssam break; 515162021Ssam } 516162021Ssam break; 517162021Ssam 518162021Ssam case MFR_CTRL_IE_TIMESTAMP: 519162021Ssam if (ie_len == sizeof(struct timeval)) { 520276788Sdelphij ts_print(ndo, (const struct timeval *)tptr); 521162021Ssam break; 522162021Ssam } 523162021Ssam /* fall through and hexdump if no unix timestamp */ 524162021Ssam 525162021Ssam /* 526162021Ssam * FIXME those are the defined IEs that lack a decoder 527162021Ssam * you are welcome to contribute code ;-) 528162021Ssam */ 529162021Ssam 530162021Ssam case MFR_CTRL_IE_VENDOR_EXT: 531162021Ssam case MFR_CTRL_IE_CAUSE: 532162021Ssam 533162021Ssam default: 534276788Sdelphij if (ndo->ndo_vflag <= 1) 535276788Sdelphij print_unknown_data(ndo, tptr, "\n\t ", ie_len); 536162021Ssam break; 537162021Ssam } 538162021Ssam 539162021Ssam /* do we want to see a hexdump of the IE ? */ 540276788Sdelphij if (ndo->ndo_vflag > 1 ) 541276788Sdelphij print_unknown_data(ndo, tptr, "\n\t ", ie_len); 542276788Sdelphij 543162021Ssam tlen-=ie_len; 544162021Ssam tptr+=ie_len; 545162021Ssam } 546162021Ssam return hdr_len; 547162021Ssam } 548162021Ssam/* 549162021Ssam * FRF.16 Fragmentation Frame 550276788Sdelphij * 551162021Ssam * 7 6 5 4 3 2 1 0 552162021Ssam * +----+----+----+----+----+----+----+----+ 553162021Ssam * | B | E | C=0|seq. (high 4 bits) | EA | 554162021Ssam * +----+----+----+----+----+----+----+----+ 555162021Ssam * | sequence (low 8 bits) | 556162021Ssam * +----+----+----+----+----+----+----+----+ 557162021Ssam * | DLCI (6 bits) | CR | EA | 558162021Ssam * +----+----+----+----+----+----+----+----+ 559162021Ssam * | DLCI (4 bits) |FECN|BECN| DE | EA | 560162021Ssam * +----+----+----+----+----+----+----+----+ 561162021Ssam */ 562162021Ssam 563162021Ssam sequence_num = (p[0]&0x1e)<<7 | p[1]; 564162021Ssam /* whole packet or first fragment ? */ 565162021Ssam if ((p[0] & MFR_BEC_MASK) == MFR_FRAG_FRAME || 566162021Ssam (p[0] & MFR_BEC_MASK) == MFR_B_BIT) { 567276788Sdelphij ND_PRINT((ndo, "FRF.16 Frag, seq %u, Flags [%s], ", 568162021Ssam sequence_num, 569276788Sdelphij bittok2str(frf_flag_values,"none",(p[0] & MFR_BEC_MASK)))); 570162021Ssam hdr_len = 2; 571276788Sdelphij fr_print(ndo, p+hdr_len,length-hdr_len); 572162021Ssam return hdr_len; 573162021Ssam } 574162021Ssam 575162021Ssam /* must be a middle or the last fragment */ 576276788Sdelphij ND_PRINT((ndo, "FRF.16 Frag, seq %u, Flags [%s]", 577162021Ssam sequence_num, 578276788Sdelphij bittok2str(frf_flag_values,"none",(p[0] & MFR_BEC_MASK)))); 579276788Sdelphij print_unknown_data(ndo, p, "\n\t", length); 580162021Ssam 581162021Ssam return hdr_len; 582162021Ssam 583162021Ssam trunc: 584276788Sdelphij ND_PRINT((ndo, "[|mfr]")); 585162021Ssam return length; 586162021Ssam} 587162021Ssam 588146778Ssam/* an NLPID of 0xb1 indicates a 2-byte 589146778Ssam * FRF.15 header 590276788Sdelphij * 591146778Ssam * 7 6 5 4 3 2 1 0 592146778Ssam * +----+----+----+----+----+----+----+----+ 593146778Ssam * ~ Q.922 header ~ 594146778Ssam * +----+----+----+----+----+----+----+----+ 595146778Ssam * | NLPID (8 bits) | NLPID=0xb1 596146778Ssam * +----+----+----+----+----+----+----+----+ 597146778Ssam * | B | E | C |seq. (high 4 bits) | R | 598146778Ssam * +----+----+----+----+----+----+----+----+ 599146778Ssam * | sequence (low 8 bits) | 600146778Ssam * +----+----+----+----+----+----+----+----+ 601146778Ssam */ 60232145Spst 603146778Ssam#define FR_FRF15_FRAGTYPE 0x01 604146778Ssam 605146778Ssamstatic void 606276788Sdelphijfrf15_print(netdissect_options *ndo, 607285275Spkelsey const u_char *p, u_int length) 608285275Spkelsey{ 609276788Sdelphij uint16_t sequence_num, flags; 610276788Sdelphij 611313537Sglebius if (length < 2) 612313537Sglebius goto trunc; 613313537Sglebius ND_TCHECK2(*p, 2); 614313537Sglebius 615162021Ssam flags = p[0]&MFR_BEC_MASK; 616146778Ssam sequence_num = (p[0]&0x1e)<<7 | p[1]; 617146778Ssam 618276788Sdelphij ND_PRINT((ndo, "FRF.15, seq 0x%03x, Flags [%s],%s Fragmentation, length %u", 619146778Ssam sequence_num, 620162021Ssam bittok2str(frf_flag_values,"none",flags), 621162021Ssam p[0]&FR_FRF15_FRAGTYPE ? "Interface" : "End-to-End", 622276788Sdelphij length)); 623146778Ssam 624146778Ssam/* TODO: 625146778Ssam * depending on all permutations of the B, E and C bit 626146778Ssam * dig as deep as we can - e.g. on the first (B) fragment 627146778Ssam * there is enough payload to print the IP header 628146778Ssam * on non (B) fragments it depends if the fragmentation 629146778Ssam * model is end-to-end or interface based wether we want to print 630146778Ssam * another Q.922 header 631146778Ssam */ 632313537Sglebius return; 633146778Ssam 634313537Sglebiustrunc: 635313537Sglebius ND_PRINT((ndo, "[|frf.15]")); 63632145Spst} 63732145Spst 63832145Spst/* 63932145Spst * Q.933 decoding portion for framerelay specific. 64032145Spst */ 64132145Spst 64232145Spst/* Q.933 packet format 643276788Sdelphij Format of Other Protocols 64432145Spst using Q.933 NLPID 645276788Sdelphij +-------------------------------+ 646276788Sdelphij | Q.922 Address | 64732145Spst +---------------+---------------+ 648276788Sdelphij |Control 0x03 | NLPID 0x08 | 649276788Sdelphij +---------------+---------------+ 65032145Spst | L2 Protocol ID | 65132145Spst | octet 1 | octet 2 | 65232145Spst +-------------------------------+ 65332145Spst | L3 Protocol ID | 65432145Spst | octet 2 | octet 2 | 65532145Spst +-------------------------------+ 65632145Spst | Protocol Data | 65732145Spst +-------------------------------+ 65832145Spst | FCS | 65932145Spst +-------------------------------+ 66032145Spst */ 66132145Spst 66232145Spst/* L2 (Octet 1)- Call Reference Usually is 0x0 */ 66332145Spst 66432145Spst/* 66532145Spst * L2 (Octet 2)- Message Types definition 1 byte long. 66632145Spst */ 66732145Spst/* Call Establish */ 66832145Spst#define MSG_TYPE_ESC_TO_NATIONAL 0x00 66932145Spst#define MSG_TYPE_ALERT 0x01 67032145Spst#define MSG_TYPE_CALL_PROCEEDING 0x02 67132145Spst#define MSG_TYPE_CONNECT 0x07 67232145Spst#define MSG_TYPE_CONNECT_ACK 0x0F 67332145Spst#define MSG_TYPE_PROGRESS 0x03 67432145Spst#define MSG_TYPE_SETUP 0x05 67532145Spst/* Call Clear */ 67632145Spst#define MSG_TYPE_DISCONNECT 0x45 67732145Spst#define MSG_TYPE_RELEASE 0x4D 67832145Spst#define MSG_TYPE_RELEASE_COMPLETE 0x5A 67932145Spst#define MSG_TYPE_RESTART 0x46 68032145Spst#define MSG_TYPE_RESTART_ACK 0x4E 68132145Spst/* Status */ 68232145Spst#define MSG_TYPE_STATUS 0x7D 68332145Spst#define MSG_TYPE_STATUS_ENQ 0x75 68432145Spst 685276788Sdelphijstatic const struct tok fr_q933_msg_values[] = { 686146778Ssam { MSG_TYPE_ESC_TO_NATIONAL, "ESC to National" }, 687146778Ssam { MSG_TYPE_ALERT, "Alert" }, 688146778Ssam { MSG_TYPE_CALL_PROCEEDING, "Call proceeding" }, 689146778Ssam { MSG_TYPE_CONNECT, "Connect" }, 690146778Ssam { MSG_TYPE_CONNECT_ACK, "Connect ACK" }, 691146778Ssam { MSG_TYPE_PROGRESS, "Progress" }, 692146778Ssam { MSG_TYPE_SETUP, "Setup" }, 693146778Ssam { MSG_TYPE_DISCONNECT, "Disconnect" }, 694146778Ssam { MSG_TYPE_RELEASE, "Release" }, 695146778Ssam { MSG_TYPE_RELEASE_COMPLETE, "Release Complete" }, 696146778Ssam { MSG_TYPE_RESTART, "Restart" }, 697146778Ssam { MSG_TYPE_RESTART_ACK, "Restart ACK" }, 698146778Ssam { MSG_TYPE_STATUS, "Status Reply" }, 699146778Ssam { MSG_TYPE_STATUS_ENQ, "Status Enquiry" }, 700146778Ssam { 0, NULL } 701146778Ssam}; 70232145Spst 703313537Sglebius#define IE_IS_SINGLE_OCTET(iecode) ((iecode) & 0x80) 704313537Sglebius#define IE_IS_SHIFT(iecode) (((iecode) & 0xF0) == 0x90) 705313537Sglebius#define IE_SHIFT_IS_NON_LOCKING(iecode) ((iecode) & 0x08) 706313537Sglebius#define IE_SHIFT_IS_LOCKING(iecode) (!(IE_SHIFT_IS_NON_LOCKING(iecode))) 707313537Sglebius#define IE_SHIFT_CODESET(iecode) ((iecode) & 0x07) 708146778Ssam 709146778Ssam#define FR_LMI_ANSI_REPORT_TYPE_IE 0x01 710146778Ssam#define FR_LMI_ANSI_LINK_VERIFY_IE_91 0x19 /* details? */ 711146778Ssam#define FR_LMI_ANSI_LINK_VERIFY_IE 0x03 712146778Ssam#define FR_LMI_ANSI_PVC_STATUS_IE 0x07 713146778Ssam 714146778Ssam#define FR_LMI_CCITT_REPORT_TYPE_IE 0x51 715146778Ssam#define FR_LMI_CCITT_LINK_VERIFY_IE 0x53 716146778Ssam#define FR_LMI_CCITT_PVC_STATUS_IE 0x57 717146778Ssam 718313537Sglebiusstatic const struct tok fr_q933_ie_values_codeset_0_5[] = { 719146778Ssam { FR_LMI_ANSI_REPORT_TYPE_IE, "ANSI Report Type" }, 720146778Ssam { FR_LMI_ANSI_LINK_VERIFY_IE_91, "ANSI Link Verify" }, 721146778Ssam { FR_LMI_ANSI_LINK_VERIFY_IE, "ANSI Link Verify" }, 722146778Ssam { FR_LMI_ANSI_PVC_STATUS_IE, "ANSI PVC Status" }, 723146778Ssam { FR_LMI_CCITT_REPORT_TYPE_IE, "CCITT Report Type" }, 724146778Ssam { FR_LMI_CCITT_LINK_VERIFY_IE, "CCITT Link Verify" }, 725146778Ssam { FR_LMI_CCITT_PVC_STATUS_IE, "CCITT PVC Status" }, 726146778Ssam { 0, NULL } 72732145Spst}; 72832145Spst 729146778Ssam#define FR_LMI_REPORT_TYPE_IE_FULL_STATUS 0 730146778Ssam#define FR_LMI_REPORT_TYPE_IE_LINK_VERIFY 1 731146778Ssam#define FR_LMI_REPORT_TYPE_IE_ASYNC_PVC 2 73232145Spst 733276788Sdelphijstatic const struct tok fr_lmi_report_type_ie_values[] = { 734146778Ssam { FR_LMI_REPORT_TYPE_IE_FULL_STATUS, "Full Status" }, 735146778Ssam { FR_LMI_REPORT_TYPE_IE_LINK_VERIFY, "Link verify" }, 736146778Ssam { FR_LMI_REPORT_TYPE_IE_ASYNC_PVC, "Async PVC Status" }, 737146778Ssam { 0, NULL } 738146778Ssam}; 73932145Spst 740313537Sglebius/* array of 16 codesets - currently we only support codepage 0 and 5 */ 741276788Sdelphijstatic const struct tok *fr_q933_ie_codesets[] = { 742313537Sglebius fr_q933_ie_values_codeset_0_5, 743146778Ssam NULL, 744146778Ssam NULL, 745146778Ssam NULL, 746146778Ssam NULL, 747313537Sglebius fr_q933_ie_values_codeset_0_5, 748146778Ssam NULL, 749146778Ssam NULL, 750146778Ssam NULL, 751146778Ssam NULL, 752146778Ssam NULL, 753146778Ssam NULL, 754146778Ssam NULL, 755146778Ssam NULL, 756146778Ssam NULL, 757146778Ssam NULL 75832145Spst}; 75932145Spst 760313537Sglebiusstatic int fr_q933_print_ie_codeset_0_5(netdissect_options *ndo, u_int iecode, 761313537Sglebius u_int ielength, const u_char *p); 762147904Ssam 763313537Sglebiustypedef int (*codeset_pr_func_t)(netdissect_options *, u_int iecode, 764313537Sglebius u_int ielength, const u_char *p); 765147904Ssam 766313537Sglebius/* array of 16 codesets - currently we only support codepage 0 and 5 */ 767276788Sdelphijstatic const codeset_pr_func_t fr_q933_print_ie_codeset[] = { 768313537Sglebius fr_q933_print_ie_codeset_0_5, 769147904Ssam NULL, 770147904Ssam NULL, 771147904Ssam NULL, 772147904Ssam NULL, 773313537Sglebius fr_q933_print_ie_codeset_0_5, 774147904Ssam NULL, 775147904Ssam NULL, 776147904Ssam NULL, 777147904Ssam NULL, 778147904Ssam NULL, 779147904Ssam NULL, 780147904Ssam NULL, 781147904Ssam NULL, 782147904Ssam NULL, 783147904Ssam NULL 784147904Ssam}; 785147904Ssam 786313537Sglebius/* 787313537Sglebius * ITU-T Q.933. 788313537Sglebius * 789313537Sglebius * p points to octet 2, the octet containing the length of the 790313537Sglebius * call reference value, so p[n] is octet n+2 ("octet X" is as 791313537Sglebius * used in Q.931/Q.933). 792313537Sglebius * 793313537Sglebius * XXX - actually used both for Q.931 and Q.933. 794313537Sglebius */ 79532145Spstvoid 796276788Sdelphijq933_print(netdissect_options *ndo, 797276788Sdelphij const u_char *p, u_int length) 79832145Spst{ 799313537Sglebius u_int olen; 800313537Sglebius u_int call_ref_length, i; 801313537Sglebius uint8_t call_ref[15]; /* maximum length - length field is 4 bits */ 802313537Sglebius u_int msgtype; 803313537Sglebius u_int iecode; 804313537Sglebius u_int ielength; 805313537Sglebius u_int codeset = 0; 806313537Sglebius u_int is_ansi = 0; 807313537Sglebius u_int ie_is_known; 808313537Sglebius u_int non_locking_shift; 809313537Sglebius u_int unshift_codeset; 810146778Ssam 811313537Sglebius ND_PRINT((ndo, "%s", ndo->ndo_eflag ? "" : "Q.933")); 812313537Sglebius 813313537Sglebius if (length == 0 || !ND_TTEST(*p)) { 814313537Sglebius if (!ndo->ndo_eflag) 815313537Sglebius ND_PRINT((ndo, ", ")); 816313537Sglebius ND_PRINT((ndo, "length %u", length)); 817313537Sglebius goto trunc; 818146778Ssam } 819146778Ssam 820313537Sglebius /* 821313537Sglebius * Get the length of the call reference value. 822313537Sglebius */ 823313537Sglebius olen = length; /* preserve the original length for display */ 824313537Sglebius call_ref_length = (*p) & 0x0f; 825313537Sglebius p++; 826313537Sglebius length--; 827146778Ssam 828313537Sglebius /* 829313537Sglebius * Get the call reference value. 830313537Sglebius */ 831313537Sglebius for (i = 0; i < call_ref_length; i++) { 832313537Sglebius if (length == 0 || !ND_TTEST(*p)) { 833313537Sglebius if (!ndo->ndo_eflag) 834313537Sglebius ND_PRINT((ndo, ", ")); 835313537Sglebius ND_PRINT((ndo, "length %u", olen)); 836313537Sglebius goto trunc; 837313537Sglebius } 838313537Sglebius call_ref[i] = *p; 839313537Sglebius p++; 840313537Sglebius length--; 841190207Srpaulo } 84232145Spst 843313537Sglebius /* 844313537Sglebius * Get the message type. 845313537Sglebius */ 846313537Sglebius if (length == 0 || !ND_TTEST(*p)) { 847313537Sglebius if (!ndo->ndo_eflag) 848313537Sglebius ND_PRINT((ndo, ", ")); 849313537Sglebius ND_PRINT((ndo, "length %u", olen)); 850313537Sglebius goto trunc; 851313537Sglebius } 852313537Sglebius msgtype = *p; 853313537Sglebius p++; 854313537Sglebius length--; 855276788Sdelphij 856313537Sglebius /* 857313537Sglebius * Peek ahead to see if we start with a shift. 858313537Sglebius */ 859313537Sglebius non_locking_shift = 0; 860313537Sglebius unshift_codeset = codeset; 861313537Sglebius if (length != 0) { 862313537Sglebius if (!ND_TTEST(*p)) { 863313537Sglebius if (!ndo->ndo_eflag) 864313537Sglebius ND_PRINT((ndo, ", ")); 865313537Sglebius ND_PRINT((ndo, "length %u", olen)); 866313537Sglebius goto trunc; 867313537Sglebius } 868313537Sglebius iecode = *p; 869313537Sglebius if (IE_IS_SHIFT(iecode)) { 870313537Sglebius /* 871313537Sglebius * It's a shift. Skip over it. 872313537Sglebius */ 873313537Sglebius p++; 874313537Sglebius length--; 875313537Sglebius 876313537Sglebius /* 877313537Sglebius * Get the codeset. 878313537Sglebius */ 879313537Sglebius codeset = IE_SHIFT_CODESET(iecode); 880313537Sglebius 881313537Sglebius /* 882313537Sglebius * If it's a locking shift to codeset 5, 883313537Sglebius * mark this as ANSI. (XXX - 5 is actually 884313537Sglebius * for national variants in general, not 885313537Sglebius * the US variant in particular, but maybe 886313537Sglebius * this is more American exceptionalism. :-)) 887313537Sglebius */ 888313537Sglebius if (IE_SHIFT_IS_LOCKING(iecode)) { 889313537Sglebius /* 890313537Sglebius * It's a locking shift. 891313537Sglebius */ 892313537Sglebius if (codeset == 5) { 893313537Sglebius /* 894313537Sglebius * It's a locking shift to 895313537Sglebius * codeset 5, so this is 896313537Sglebius * T1.617 Annex D. 897313537Sglebius */ 898313537Sglebius is_ansi = 1; 899313537Sglebius } 900313537Sglebius } else { 901313537Sglebius /* 902313537Sglebius * It's a non-locking shift. 903313537Sglebius * Remember the current codeset, so we 904313537Sglebius * can revert to it after the next IE. 905313537Sglebius */ 906313537Sglebius non_locking_shift = 1; 907313537Sglebius unshift_codeset = 0; 908313537Sglebius } 909313537Sglebius } 910313537Sglebius } 911313537Sglebius 91232145Spst /* printing out header part */ 913313537Sglebius if (!ndo->ndo_eflag) 914313537Sglebius ND_PRINT((ndo, ", ")); 915276788Sdelphij ND_PRINT((ndo, "%s, codeset %u", is_ansi ? "ANSI" : "CCITT", codeset)); 916146778Ssam 917313537Sglebius if (call_ref_length != 0) { 918313537Sglebius ND_TCHECK(p[0]); 919313537Sglebius if (call_ref_length > 1 || p[0] != 0) { 920313537Sglebius /* 921313537Sglebius * Not a dummy call reference. 922313537Sglebius */ 923313537Sglebius ND_PRINT((ndo, ", Call Ref: 0x")); 924313537Sglebius for (i = 0; i < call_ref_length; i++) 925313537Sglebius ND_PRINT((ndo, "%02x", call_ref[i])); 926313537Sglebius } 927190207Srpaulo } 928313537Sglebius if (ndo->ndo_vflag) { 929313537Sglebius ND_PRINT((ndo, ", %s (0x%02x), length %u", 930313537Sglebius tok2str(fr_q933_msg_values, 931313537Sglebius "unknown message", msgtype), 932313537Sglebius msgtype, 933313537Sglebius olen)); 934313537Sglebius } else { 935313537Sglebius ND_PRINT((ndo, ", %s", 936190207Srpaulo tok2str(fr_q933_msg_values, 937313537Sglebius "unknown message 0x%02x", msgtype))); 938190207Srpaulo } 939146778Ssam 940313537Sglebius /* Loop through the rest of the IEs */ 941313537Sglebius while (length != 0) { 942313537Sglebius /* 943313537Sglebius * What's the state of any non-locking shifts? 944313537Sglebius */ 945313537Sglebius if (non_locking_shift == 1) { 946313537Sglebius /* 947313537Sglebius * There's a non-locking shift in effect for 948313537Sglebius * this IE. Count it, so we reset the codeset 949313537Sglebius * before the next IE. 950313537Sglebius */ 951313537Sglebius non_locking_shift = 2; 952313537Sglebius } else if (non_locking_shift == 2) { 953313537Sglebius /* 954313537Sglebius * Unshift. 955313537Sglebius */ 956313537Sglebius codeset = unshift_codeset; 957313537Sglebius non_locking_shift = 0; 95832145Spst } 95932145Spst 960313537Sglebius /* 961313537Sglebius * Get the first octet of the IE. 962313537Sglebius */ 963313537Sglebius if (!ND_TTEST(*p)) { 964313537Sglebius if (!ndo->ndo_vflag) { 965313537Sglebius ND_PRINT((ndo, ", length %u", olen)); 966313537Sglebius } 967313537Sglebius goto trunc; 968190207Srpaulo } 969313537Sglebius iecode = *p; 970313537Sglebius p++; 971313537Sglebius length--; 972190207Srpaulo 973313537Sglebius /* Single-octet IE? */ 974313537Sglebius if (IE_IS_SINGLE_OCTET(iecode)) { 975313537Sglebius /* 976313537Sglebius * Yes. Is it a shift? 977313537Sglebius */ 978313537Sglebius if (IE_IS_SHIFT(iecode)) { 979313537Sglebius /* 980313537Sglebius * Yes. Is it locking? 981313537Sglebius */ 982313537Sglebius if (IE_SHIFT_IS_LOCKING(iecode)) { 983313537Sglebius /* 984313537Sglebius * Yes. 985313537Sglebius */ 986313537Sglebius non_locking_shift = 0; 987313537Sglebius } else { 988313537Sglebius /* 989313537Sglebius * No. Remember the current 990313537Sglebius * codeset, so we can revert 991313537Sglebius * to it after the next IE. 992313537Sglebius */ 993313537Sglebius non_locking_shift = 1; 994313537Sglebius unshift_codeset = codeset; 995313537Sglebius } 99632145Spst 997313537Sglebius /* 998313537Sglebius * Get the codeset. 999313537Sglebius */ 1000313537Sglebius codeset = IE_SHIFT_CODESET(iecode); 1001313537Sglebius } 1002313537Sglebius } else { 1003313537Sglebius /* 1004313537Sglebius * No. Get the IE length. 1005313537Sglebius */ 1006313537Sglebius if (length == 0 || !ND_TTEST(*p)) { 1007313537Sglebius if (!ndo->ndo_vflag) { 1008313537Sglebius ND_PRINT((ndo, ", length %u", olen)); 1009313537Sglebius } 1010313537Sglebius goto trunc; 1011313537Sglebius } 1012313537Sglebius ielength = *p; 1013313537Sglebius p++; 1014313537Sglebius length--; 1015190207Srpaulo 1016313537Sglebius /* lets do the full IE parsing only in verbose mode 1017313537Sglebius * however some IEs (DLCI Status, Link Verify) 1018313537Sglebius * are also interesting in non-verbose mode */ 1019313537Sglebius if (ndo->ndo_vflag) { 1020313537Sglebius ND_PRINT((ndo, "\n\t%s IE (0x%02x), length %u: ", 1021313537Sglebius tok2str(fr_q933_ie_codesets[codeset], 1022313537Sglebius "unknown", iecode), 1023313537Sglebius iecode, 1024313537Sglebius ielength)); 1025313537Sglebius } 1026162021Ssam 1027313537Sglebius /* sanity checks */ 1028313537Sglebius if (iecode == 0 || ielength == 0) { 1029313537Sglebius return; 1030313537Sglebius } 1031313537Sglebius if (length < ielength || !ND_TTEST2(*p, ielength)) { 1032313537Sglebius if (!ndo->ndo_vflag) { 1033313537Sglebius ND_PRINT((ndo, ", length %u", olen)); 1034313537Sglebius } 1035313537Sglebius goto trunc; 1036313537Sglebius } 1037313537Sglebius 1038313537Sglebius ie_is_known = 0; 1039313537Sglebius if (fr_q933_print_ie_codeset[codeset] != NULL) { 1040313537Sglebius ie_is_known = fr_q933_print_ie_codeset[codeset](ndo, iecode, ielength, p); 1041313537Sglebius } 1042313537Sglebius 1043313537Sglebius if (ie_is_known) { 1044313537Sglebius /* 1045313537Sglebius * Known IE; do we want to see a hexdump 1046313537Sglebius * of it? 1047313537Sglebius */ 1048313537Sglebius if (ndo->ndo_vflag > 1) { 1049313537Sglebius /* Yes. */ 1050313537Sglebius print_unknown_data(ndo, p, "\n\t ", ielength); 1051313537Sglebius } 1052313537Sglebius } else { 1053313537Sglebius /* 1054313537Sglebius * Unknown IE; if we're printing verbosely, 1055313537Sglebius * print its content in hex. 1056313537Sglebius */ 1057313537Sglebius if (ndo->ndo_vflag >= 1) { 1058313537Sglebius print_unknown_data(ndo, p, "\n\t", ielength); 1059313537Sglebius } 1060313537Sglebius } 1061313537Sglebius 1062313537Sglebius length -= ielength; 1063313537Sglebius p += ielength; 1064190207Srpaulo } 1065146778Ssam } 1066313537Sglebius if (!ndo->ndo_vflag) { 1067313537Sglebius ND_PRINT((ndo, ", length %u", olen)); 1068190207Srpaulo } 1069313537Sglebius return; 1070313537Sglebius 1071313537Sglebiustrunc: 1072313537Sglebius ND_PRINT((ndo, "[|q.933]")); 1073146778Ssam} 1074147904Ssam 1075147904Ssamstatic int 1076313537Sglebiusfr_q933_print_ie_codeset_0_5(netdissect_options *ndo, u_int iecode, 1077313537Sglebius u_int ielength, const u_char *p) 1078147904Ssam{ 1079147904Ssam u_int dlci; 1080147904Ssam 1081313537Sglebius switch (iecode) { 1082147904Ssam 1083147904Ssam case FR_LMI_ANSI_REPORT_TYPE_IE: /* fall through */ 1084147904Ssam case FR_LMI_CCITT_REPORT_TYPE_IE: 1085313537Sglebius if (ielength < 1) { 1086313537Sglebius if (!ndo->ndo_vflag) { 1087313537Sglebius ND_PRINT((ndo, ", ")); 1088313537Sglebius } 1089313537Sglebius ND_PRINT((ndo, "Invalid REPORT TYPE IE")); 1090313537Sglebius return 1; 1091313537Sglebius } 1092276788Sdelphij if (ndo->ndo_vflag) { 1093276788Sdelphij ND_PRINT((ndo, "%s (%u)", 1094313537Sglebius tok2str(fr_lmi_report_type_ie_values,"unknown",p[0]), 1095313537Sglebius p[0])); 1096190207Srpaulo } 1097147904Ssam return 1; 1098147904Ssam 1099147904Ssam case FR_LMI_ANSI_LINK_VERIFY_IE: /* fall through */ 1100147904Ssam case FR_LMI_CCITT_LINK_VERIFY_IE: 1101147904Ssam case FR_LMI_ANSI_LINK_VERIFY_IE_91: 1102276788Sdelphij if (!ndo->ndo_vflag) { 1103276788Sdelphij ND_PRINT((ndo, ", ")); 1104190207Srpaulo } 1105313537Sglebius if (ielength < 2) { 1106313537Sglebius ND_PRINT((ndo, "Invalid LINK VERIFY IE")); 1107313537Sglebius return 1; 1108313537Sglebius } 1109313537Sglebius ND_PRINT((ndo, "TX Seq: %3d, RX Seq: %3d", p[0], p[1])); 1110147904Ssam return 1; 1111147904Ssam 1112147904Ssam case FR_LMI_ANSI_PVC_STATUS_IE: /* fall through */ 1113147904Ssam case FR_LMI_CCITT_PVC_STATUS_IE: 1114276788Sdelphij if (!ndo->ndo_vflag) { 1115276788Sdelphij ND_PRINT((ndo, ", ")); 1116190207Srpaulo } 1117276788Sdelphij /* now parse the DLCI information element. */ 1118313537Sglebius if ((ielength < 3) || 1119313537Sglebius (p[0] & 0x80) || 1120313537Sglebius ((ielength == 3) && !(p[1] & 0x80)) || 1121313537Sglebius ((ielength == 4) && ((p[1] & 0x80) || !(p[2] & 0x80))) || 1122313537Sglebius ((ielength == 5) && ((p[1] & 0x80) || (p[2] & 0x80) || 1123313537Sglebius !(p[3] & 0x80))) || 1124313537Sglebius (ielength > 5) || 1125313537Sglebius !(p[ielength - 1] & 0x80)) { 1126313537Sglebius ND_PRINT((ndo, "Invalid DLCI in PVC STATUS IE")); 1127313537Sglebius return 1; 1128190207Srpaulo } 1129276788Sdelphij 1130313537Sglebius dlci = ((p[0] & 0x3F) << 4) | ((p[1] & 0x78) >> 3); 1131313537Sglebius if (ielength == 4) { 1132313537Sglebius dlci = (dlci << 6) | ((p[2] & 0x7E) >> 1); 1133190207Srpaulo } 1134313537Sglebius else if (ielength == 5) { 1135313537Sglebius dlci = (dlci << 13) | (p[2] & 0x7F) | ((p[3] & 0x7E) >> 1); 1136190207Srpaulo } 1137147904Ssam 1138276788Sdelphij ND_PRINT((ndo, "DLCI %u: status %s%s", dlci, 1139313537Sglebius p[ielength - 1] & 0x8 ? "New, " : "", 1140313537Sglebius p[ielength - 1] & 0x2 ? "Active" : "Inactive")); 1141147904Ssam return 1; 1142147904Ssam } 1143147904Ssam 1144147904Ssam return 0; 1145147904Ssam} 1146276788Sdelphij/* 1147276788Sdelphij * Local Variables: 1148276788Sdelphij * c-style: whitesmith 1149276788Sdelphij * c-basic-offset: 8 1150276788Sdelphij * End: 1151276788Sdelphij */ 1152