print-fr.c revision 313537
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: 332313537Sglebius isoclns_print(ndo, p - 1, length + 1, ndo->ndo_snapend - p + 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 */ 460162021Ssam 461162021Ssam if ((p[0] & MFR_BEC_MASK) == MFR_CTRL_FRAME && p[1] == 0) { 462276788Sdelphij ND_PRINT((ndo, "FRF.16 Control, Flags [%s], %s, length %u", 463162021Ssam bittok2str(frf_flag_values,"none",(p[0] & MFR_BEC_MASK)), 464162021Ssam tok2str(mfr_ctrl_msg_values,"Unknown Message (0x%02x)",p[2]), 465276788Sdelphij length)); 466162021Ssam tptr = p + 3; 467162021Ssam tlen = length -3; 468162021Ssam hdr_len = 3; 469162021Ssam 470276788Sdelphij if (!ndo->ndo_vflag) 471162021Ssam return hdr_len; 472162021Ssam 473162021Ssam while (tlen>sizeof(struct ie_tlv_header_t)) { 474276788Sdelphij ND_TCHECK2(*tptr, sizeof(struct ie_tlv_header_t)); 475162021Ssam ie_type=tptr[0]; 476162021Ssam ie_len=tptr[1]; 477162021Ssam 478276788Sdelphij ND_PRINT((ndo, "\n\tIE %s (%u), length %u: ", 479162021Ssam tok2str(mfr_ctrl_ie_values,"Unknown",ie_type), 480162021Ssam ie_type, 481276788Sdelphij ie_len)); 482162021Ssam 483162021Ssam /* infinite loop check */ 484162021Ssam if (ie_type == 0 || ie_len <= sizeof(struct ie_tlv_header_t)) 485162021Ssam return hdr_len; 486162021Ssam 487276788Sdelphij ND_TCHECK2(*tptr, ie_len); 488162021Ssam tptr+=sizeof(struct ie_tlv_header_t); 489162021Ssam /* tlv len includes header */ 490162021Ssam ie_len-=sizeof(struct ie_tlv_header_t); 491162021Ssam tlen-=sizeof(struct ie_tlv_header_t); 492162021Ssam 493162021Ssam switch (ie_type) { 494162021Ssam 495162021Ssam case MFR_CTRL_IE_MAGIC_NUM: 496276788Sdelphij ND_PRINT((ndo, "0x%08x", EXTRACT_32BITS(tptr))); 497162021Ssam break; 498162021Ssam 499162021Ssam case MFR_CTRL_IE_BUNDLE_ID: /* same message format */ 500162021Ssam case MFR_CTRL_IE_LINK_ID: 501162021Ssam for (idx = 0; idx < ie_len && idx < MFR_ID_STRING_MAXLEN; idx++) { 502162021Ssam if (*(tptr+idx) != 0) /* don't print null termination */ 503276788Sdelphij safeputchar(ndo, *(tptr + idx)); 504162021Ssam else 505162021Ssam break; 506162021Ssam } 507162021Ssam break; 508162021Ssam 509162021Ssam case MFR_CTRL_IE_TIMESTAMP: 510162021Ssam if (ie_len == sizeof(struct timeval)) { 511276788Sdelphij ts_print(ndo, (const struct timeval *)tptr); 512162021Ssam break; 513162021Ssam } 514162021Ssam /* fall through and hexdump if no unix timestamp */ 515162021Ssam 516162021Ssam /* 517162021Ssam * FIXME those are the defined IEs that lack a decoder 518162021Ssam * you are welcome to contribute code ;-) 519162021Ssam */ 520162021Ssam 521162021Ssam case MFR_CTRL_IE_VENDOR_EXT: 522162021Ssam case MFR_CTRL_IE_CAUSE: 523162021Ssam 524162021Ssam default: 525276788Sdelphij if (ndo->ndo_vflag <= 1) 526276788Sdelphij print_unknown_data(ndo, tptr, "\n\t ", ie_len); 527162021Ssam break; 528162021Ssam } 529162021Ssam 530162021Ssam /* do we want to see a hexdump of the IE ? */ 531276788Sdelphij if (ndo->ndo_vflag > 1 ) 532276788Sdelphij print_unknown_data(ndo, tptr, "\n\t ", ie_len); 533276788Sdelphij 534162021Ssam tlen-=ie_len; 535162021Ssam tptr+=ie_len; 536162021Ssam } 537162021Ssam return hdr_len; 538162021Ssam } 539162021Ssam/* 540162021Ssam * FRF.16 Fragmentation Frame 541276788Sdelphij * 542162021Ssam * 7 6 5 4 3 2 1 0 543162021Ssam * +----+----+----+----+----+----+----+----+ 544162021Ssam * | B | E | C=0|seq. (high 4 bits) | EA | 545162021Ssam * +----+----+----+----+----+----+----+----+ 546162021Ssam * | sequence (low 8 bits) | 547162021Ssam * +----+----+----+----+----+----+----+----+ 548162021Ssam * | DLCI (6 bits) | CR | EA | 549162021Ssam * +----+----+----+----+----+----+----+----+ 550162021Ssam * | DLCI (4 bits) |FECN|BECN| DE | EA | 551162021Ssam * +----+----+----+----+----+----+----+----+ 552162021Ssam */ 553162021Ssam 554162021Ssam sequence_num = (p[0]&0x1e)<<7 | p[1]; 555162021Ssam /* whole packet or first fragment ? */ 556162021Ssam if ((p[0] & MFR_BEC_MASK) == MFR_FRAG_FRAME || 557162021Ssam (p[0] & MFR_BEC_MASK) == MFR_B_BIT) { 558276788Sdelphij ND_PRINT((ndo, "FRF.16 Frag, seq %u, Flags [%s], ", 559162021Ssam sequence_num, 560276788Sdelphij bittok2str(frf_flag_values,"none",(p[0] & MFR_BEC_MASK)))); 561162021Ssam hdr_len = 2; 562276788Sdelphij fr_print(ndo, p+hdr_len,length-hdr_len); 563162021Ssam return hdr_len; 564162021Ssam } 565162021Ssam 566162021Ssam /* must be a middle or the last fragment */ 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)))); 570276788Sdelphij print_unknown_data(ndo, p, "\n\t", length); 571162021Ssam 572162021Ssam return hdr_len; 573162021Ssam 574162021Ssam trunc: 575276788Sdelphij ND_PRINT((ndo, "[|mfr]")); 576162021Ssam return length; 577162021Ssam} 578162021Ssam 579146778Ssam/* an NLPID of 0xb1 indicates a 2-byte 580146778Ssam * FRF.15 header 581276788Sdelphij * 582146778Ssam * 7 6 5 4 3 2 1 0 583146778Ssam * +----+----+----+----+----+----+----+----+ 584146778Ssam * ~ Q.922 header ~ 585146778Ssam * +----+----+----+----+----+----+----+----+ 586146778Ssam * | NLPID (8 bits) | NLPID=0xb1 587146778Ssam * +----+----+----+----+----+----+----+----+ 588146778Ssam * | B | E | C |seq. (high 4 bits) | R | 589146778Ssam * +----+----+----+----+----+----+----+----+ 590146778Ssam * | sequence (low 8 bits) | 591146778Ssam * +----+----+----+----+----+----+----+----+ 592146778Ssam */ 59332145Spst 594146778Ssam#define FR_FRF15_FRAGTYPE 0x01 595146778Ssam 596146778Ssamstatic void 597276788Sdelphijfrf15_print(netdissect_options *ndo, 598285275Spkelsey const u_char *p, u_int length) 599285275Spkelsey{ 600276788Sdelphij uint16_t sequence_num, flags; 601276788Sdelphij 602313537Sglebius if (length < 2) 603313537Sglebius goto trunc; 604313537Sglebius ND_TCHECK2(*p, 2); 605313537Sglebius 606162021Ssam flags = p[0]&MFR_BEC_MASK; 607146778Ssam sequence_num = (p[0]&0x1e)<<7 | p[1]; 608146778Ssam 609276788Sdelphij ND_PRINT((ndo, "FRF.15, seq 0x%03x, Flags [%s],%s Fragmentation, length %u", 610146778Ssam sequence_num, 611162021Ssam bittok2str(frf_flag_values,"none",flags), 612162021Ssam p[0]&FR_FRF15_FRAGTYPE ? "Interface" : "End-to-End", 613276788Sdelphij length)); 614146778Ssam 615146778Ssam/* TODO: 616146778Ssam * depending on all permutations of the B, E and C bit 617146778Ssam * dig as deep as we can - e.g. on the first (B) fragment 618146778Ssam * there is enough payload to print the IP header 619146778Ssam * on non (B) fragments it depends if the fragmentation 620146778Ssam * model is end-to-end or interface based wether we want to print 621146778Ssam * another Q.922 header 622146778Ssam */ 623313537Sglebius return; 624146778Ssam 625313537Sglebiustrunc: 626313537Sglebius ND_PRINT((ndo, "[|frf.15]")); 62732145Spst} 62832145Spst 62932145Spst/* 63032145Spst * Q.933 decoding portion for framerelay specific. 63132145Spst */ 63232145Spst 63332145Spst/* Q.933 packet format 634276788Sdelphij Format of Other Protocols 63532145Spst using Q.933 NLPID 636276788Sdelphij +-------------------------------+ 637276788Sdelphij | Q.922 Address | 63832145Spst +---------------+---------------+ 639276788Sdelphij |Control 0x03 | NLPID 0x08 | 640276788Sdelphij +---------------+---------------+ 64132145Spst | L2 Protocol ID | 64232145Spst | octet 1 | octet 2 | 64332145Spst +-------------------------------+ 64432145Spst | L3 Protocol ID | 64532145Spst | octet 2 | octet 2 | 64632145Spst +-------------------------------+ 64732145Spst | Protocol Data | 64832145Spst +-------------------------------+ 64932145Spst | FCS | 65032145Spst +-------------------------------+ 65132145Spst */ 65232145Spst 65332145Spst/* L2 (Octet 1)- Call Reference Usually is 0x0 */ 65432145Spst 65532145Spst/* 65632145Spst * L2 (Octet 2)- Message Types definition 1 byte long. 65732145Spst */ 65832145Spst/* Call Establish */ 65932145Spst#define MSG_TYPE_ESC_TO_NATIONAL 0x00 66032145Spst#define MSG_TYPE_ALERT 0x01 66132145Spst#define MSG_TYPE_CALL_PROCEEDING 0x02 66232145Spst#define MSG_TYPE_CONNECT 0x07 66332145Spst#define MSG_TYPE_CONNECT_ACK 0x0F 66432145Spst#define MSG_TYPE_PROGRESS 0x03 66532145Spst#define MSG_TYPE_SETUP 0x05 66632145Spst/* Call Clear */ 66732145Spst#define MSG_TYPE_DISCONNECT 0x45 66832145Spst#define MSG_TYPE_RELEASE 0x4D 66932145Spst#define MSG_TYPE_RELEASE_COMPLETE 0x5A 67032145Spst#define MSG_TYPE_RESTART 0x46 67132145Spst#define MSG_TYPE_RESTART_ACK 0x4E 67232145Spst/* Status */ 67332145Spst#define MSG_TYPE_STATUS 0x7D 67432145Spst#define MSG_TYPE_STATUS_ENQ 0x75 67532145Spst 676276788Sdelphijstatic const struct tok fr_q933_msg_values[] = { 677146778Ssam { MSG_TYPE_ESC_TO_NATIONAL, "ESC to National" }, 678146778Ssam { MSG_TYPE_ALERT, "Alert" }, 679146778Ssam { MSG_TYPE_CALL_PROCEEDING, "Call proceeding" }, 680146778Ssam { MSG_TYPE_CONNECT, "Connect" }, 681146778Ssam { MSG_TYPE_CONNECT_ACK, "Connect ACK" }, 682146778Ssam { MSG_TYPE_PROGRESS, "Progress" }, 683146778Ssam { MSG_TYPE_SETUP, "Setup" }, 684146778Ssam { MSG_TYPE_DISCONNECT, "Disconnect" }, 685146778Ssam { MSG_TYPE_RELEASE, "Release" }, 686146778Ssam { MSG_TYPE_RELEASE_COMPLETE, "Release Complete" }, 687146778Ssam { MSG_TYPE_RESTART, "Restart" }, 688146778Ssam { MSG_TYPE_RESTART_ACK, "Restart ACK" }, 689146778Ssam { MSG_TYPE_STATUS, "Status Reply" }, 690146778Ssam { MSG_TYPE_STATUS_ENQ, "Status Enquiry" }, 691146778Ssam { 0, NULL } 692146778Ssam}; 69332145Spst 694313537Sglebius#define IE_IS_SINGLE_OCTET(iecode) ((iecode) & 0x80) 695313537Sglebius#define IE_IS_SHIFT(iecode) (((iecode) & 0xF0) == 0x90) 696313537Sglebius#define IE_SHIFT_IS_NON_LOCKING(iecode) ((iecode) & 0x08) 697313537Sglebius#define IE_SHIFT_IS_LOCKING(iecode) (!(IE_SHIFT_IS_NON_LOCKING(iecode))) 698313537Sglebius#define IE_SHIFT_CODESET(iecode) ((iecode) & 0x07) 699146778Ssam 700146778Ssam#define FR_LMI_ANSI_REPORT_TYPE_IE 0x01 701146778Ssam#define FR_LMI_ANSI_LINK_VERIFY_IE_91 0x19 /* details? */ 702146778Ssam#define FR_LMI_ANSI_LINK_VERIFY_IE 0x03 703146778Ssam#define FR_LMI_ANSI_PVC_STATUS_IE 0x07 704146778Ssam 705146778Ssam#define FR_LMI_CCITT_REPORT_TYPE_IE 0x51 706146778Ssam#define FR_LMI_CCITT_LINK_VERIFY_IE 0x53 707146778Ssam#define FR_LMI_CCITT_PVC_STATUS_IE 0x57 708146778Ssam 709313537Sglebiusstatic const struct tok fr_q933_ie_values_codeset_0_5[] = { 710146778Ssam { FR_LMI_ANSI_REPORT_TYPE_IE, "ANSI Report Type" }, 711146778Ssam { FR_LMI_ANSI_LINK_VERIFY_IE_91, "ANSI Link Verify" }, 712146778Ssam { FR_LMI_ANSI_LINK_VERIFY_IE, "ANSI Link Verify" }, 713146778Ssam { FR_LMI_ANSI_PVC_STATUS_IE, "ANSI PVC Status" }, 714146778Ssam { FR_LMI_CCITT_REPORT_TYPE_IE, "CCITT Report Type" }, 715146778Ssam { FR_LMI_CCITT_LINK_VERIFY_IE, "CCITT Link Verify" }, 716146778Ssam { FR_LMI_CCITT_PVC_STATUS_IE, "CCITT PVC Status" }, 717146778Ssam { 0, NULL } 71832145Spst}; 71932145Spst 720146778Ssam#define FR_LMI_REPORT_TYPE_IE_FULL_STATUS 0 721146778Ssam#define FR_LMI_REPORT_TYPE_IE_LINK_VERIFY 1 722146778Ssam#define FR_LMI_REPORT_TYPE_IE_ASYNC_PVC 2 72332145Spst 724276788Sdelphijstatic const struct tok fr_lmi_report_type_ie_values[] = { 725146778Ssam { FR_LMI_REPORT_TYPE_IE_FULL_STATUS, "Full Status" }, 726146778Ssam { FR_LMI_REPORT_TYPE_IE_LINK_VERIFY, "Link verify" }, 727146778Ssam { FR_LMI_REPORT_TYPE_IE_ASYNC_PVC, "Async PVC Status" }, 728146778Ssam { 0, NULL } 729146778Ssam}; 73032145Spst 731313537Sglebius/* array of 16 codesets - currently we only support codepage 0 and 5 */ 732276788Sdelphijstatic const struct tok *fr_q933_ie_codesets[] = { 733313537Sglebius fr_q933_ie_values_codeset_0_5, 734146778Ssam NULL, 735146778Ssam NULL, 736146778Ssam NULL, 737146778Ssam NULL, 738313537Sglebius fr_q933_ie_values_codeset_0_5, 739146778Ssam NULL, 740146778Ssam NULL, 741146778Ssam NULL, 742146778Ssam NULL, 743146778Ssam NULL, 744146778Ssam NULL, 745146778Ssam NULL, 746146778Ssam NULL, 747146778Ssam NULL, 748146778Ssam NULL 74932145Spst}; 75032145Spst 751313537Sglebiusstatic int fr_q933_print_ie_codeset_0_5(netdissect_options *ndo, u_int iecode, 752313537Sglebius u_int ielength, const u_char *p); 753147904Ssam 754313537Sglebiustypedef int (*codeset_pr_func_t)(netdissect_options *, u_int iecode, 755313537Sglebius u_int ielength, const u_char *p); 756147904Ssam 757313537Sglebius/* array of 16 codesets - currently we only support codepage 0 and 5 */ 758276788Sdelphijstatic const codeset_pr_func_t fr_q933_print_ie_codeset[] = { 759313537Sglebius fr_q933_print_ie_codeset_0_5, 760147904Ssam NULL, 761147904Ssam NULL, 762147904Ssam NULL, 763147904Ssam NULL, 764313537Sglebius fr_q933_print_ie_codeset_0_5, 765147904Ssam NULL, 766147904Ssam NULL, 767147904Ssam NULL, 768147904Ssam NULL, 769147904Ssam NULL, 770147904Ssam NULL, 771147904Ssam NULL, 772147904Ssam NULL, 773147904Ssam NULL, 774147904Ssam NULL 775147904Ssam}; 776147904Ssam 777313537Sglebius/* 778313537Sglebius * ITU-T Q.933. 779313537Sglebius * 780313537Sglebius * p points to octet 2, the octet containing the length of the 781313537Sglebius * call reference value, so p[n] is octet n+2 ("octet X" is as 782313537Sglebius * used in Q.931/Q.933). 783313537Sglebius * 784313537Sglebius * XXX - actually used both for Q.931 and Q.933. 785313537Sglebius */ 78632145Spstvoid 787276788Sdelphijq933_print(netdissect_options *ndo, 788276788Sdelphij const u_char *p, u_int length) 78932145Spst{ 790313537Sglebius u_int olen; 791313537Sglebius u_int call_ref_length, i; 792313537Sglebius uint8_t call_ref[15]; /* maximum length - length field is 4 bits */ 793313537Sglebius u_int msgtype; 794313537Sglebius u_int iecode; 795313537Sglebius u_int ielength; 796313537Sglebius u_int codeset = 0; 797313537Sglebius u_int is_ansi = 0; 798313537Sglebius u_int ie_is_known; 799313537Sglebius u_int non_locking_shift; 800313537Sglebius u_int unshift_codeset; 801146778Ssam 802313537Sglebius ND_PRINT((ndo, "%s", ndo->ndo_eflag ? "" : "Q.933")); 803313537Sglebius 804313537Sglebius if (length == 0 || !ND_TTEST(*p)) { 805313537Sglebius if (!ndo->ndo_eflag) 806313537Sglebius ND_PRINT((ndo, ", ")); 807313537Sglebius ND_PRINT((ndo, "length %u", length)); 808313537Sglebius goto trunc; 809146778Ssam } 810146778Ssam 811313537Sglebius /* 812313537Sglebius * Get the length of the call reference value. 813313537Sglebius */ 814313537Sglebius olen = length; /* preserve the original length for display */ 815313537Sglebius call_ref_length = (*p) & 0x0f; 816313537Sglebius p++; 817313537Sglebius length--; 818146778Ssam 819313537Sglebius /* 820313537Sglebius * Get the call reference value. 821313537Sglebius */ 822313537Sglebius for (i = 0; i < call_ref_length; i++) { 823313537Sglebius if (length == 0 || !ND_TTEST(*p)) { 824313537Sglebius if (!ndo->ndo_eflag) 825313537Sglebius ND_PRINT((ndo, ", ")); 826313537Sglebius ND_PRINT((ndo, "length %u", olen)); 827313537Sglebius goto trunc; 828313537Sglebius } 829313537Sglebius call_ref[i] = *p; 830313537Sglebius p++; 831313537Sglebius length--; 832190207Srpaulo } 83332145Spst 834313537Sglebius /* 835313537Sglebius * Get the message type. 836313537Sglebius */ 837313537Sglebius if (length == 0 || !ND_TTEST(*p)) { 838313537Sglebius if (!ndo->ndo_eflag) 839313537Sglebius ND_PRINT((ndo, ", ")); 840313537Sglebius ND_PRINT((ndo, "length %u", olen)); 841313537Sglebius goto trunc; 842313537Sglebius } 843313537Sglebius msgtype = *p; 844313537Sglebius p++; 845313537Sglebius length--; 846276788Sdelphij 847313537Sglebius /* 848313537Sglebius * Peek ahead to see if we start with a shift. 849313537Sglebius */ 850313537Sglebius non_locking_shift = 0; 851313537Sglebius unshift_codeset = codeset; 852313537Sglebius if (length != 0) { 853313537Sglebius if (!ND_TTEST(*p)) { 854313537Sglebius if (!ndo->ndo_eflag) 855313537Sglebius ND_PRINT((ndo, ", ")); 856313537Sglebius ND_PRINT((ndo, "length %u", olen)); 857313537Sglebius goto trunc; 858313537Sglebius } 859313537Sglebius iecode = *p; 860313537Sglebius if (IE_IS_SHIFT(iecode)) { 861313537Sglebius /* 862313537Sglebius * It's a shift. Skip over it. 863313537Sglebius */ 864313537Sglebius p++; 865313537Sglebius length--; 866313537Sglebius 867313537Sglebius /* 868313537Sglebius * Get the codeset. 869313537Sglebius */ 870313537Sglebius codeset = IE_SHIFT_CODESET(iecode); 871313537Sglebius 872313537Sglebius /* 873313537Sglebius * If it's a locking shift to codeset 5, 874313537Sglebius * mark this as ANSI. (XXX - 5 is actually 875313537Sglebius * for national variants in general, not 876313537Sglebius * the US variant in particular, but maybe 877313537Sglebius * this is more American exceptionalism. :-)) 878313537Sglebius */ 879313537Sglebius if (IE_SHIFT_IS_LOCKING(iecode)) { 880313537Sglebius /* 881313537Sglebius * It's a locking shift. 882313537Sglebius */ 883313537Sglebius if (codeset == 5) { 884313537Sglebius /* 885313537Sglebius * It's a locking shift to 886313537Sglebius * codeset 5, so this is 887313537Sglebius * T1.617 Annex D. 888313537Sglebius */ 889313537Sglebius is_ansi = 1; 890313537Sglebius } 891313537Sglebius } else { 892313537Sglebius /* 893313537Sglebius * It's a non-locking shift. 894313537Sglebius * Remember the current codeset, so we 895313537Sglebius * can revert to it after the next IE. 896313537Sglebius */ 897313537Sglebius non_locking_shift = 1; 898313537Sglebius unshift_codeset = 0; 899313537Sglebius } 900313537Sglebius } 901313537Sglebius } 902313537Sglebius 90332145Spst /* printing out header part */ 904313537Sglebius if (!ndo->ndo_eflag) 905313537Sglebius ND_PRINT((ndo, ", ")); 906276788Sdelphij ND_PRINT((ndo, "%s, codeset %u", is_ansi ? "ANSI" : "CCITT", codeset)); 907146778Ssam 908313537Sglebius if (call_ref_length != 0) { 909313537Sglebius ND_TCHECK(p[0]); 910313537Sglebius if (call_ref_length > 1 || p[0] != 0) { 911313537Sglebius /* 912313537Sglebius * Not a dummy call reference. 913313537Sglebius */ 914313537Sglebius ND_PRINT((ndo, ", Call Ref: 0x")); 915313537Sglebius for (i = 0; i < call_ref_length; i++) 916313537Sglebius ND_PRINT((ndo, "%02x", call_ref[i])); 917313537Sglebius } 918190207Srpaulo } 919313537Sglebius if (ndo->ndo_vflag) { 920313537Sglebius ND_PRINT((ndo, ", %s (0x%02x), length %u", 921313537Sglebius tok2str(fr_q933_msg_values, 922313537Sglebius "unknown message", msgtype), 923313537Sglebius msgtype, 924313537Sglebius olen)); 925313537Sglebius } else { 926313537Sglebius ND_PRINT((ndo, ", %s", 927190207Srpaulo tok2str(fr_q933_msg_values, 928313537Sglebius "unknown message 0x%02x", msgtype))); 929190207Srpaulo } 930146778Ssam 931313537Sglebius /* Loop through the rest of the IEs */ 932313537Sglebius while (length != 0) { 933313537Sglebius /* 934313537Sglebius * What's the state of any non-locking shifts? 935313537Sglebius */ 936313537Sglebius if (non_locking_shift == 1) { 937313537Sglebius /* 938313537Sglebius * There's a non-locking shift in effect for 939313537Sglebius * this IE. Count it, so we reset the codeset 940313537Sglebius * before the next IE. 941313537Sglebius */ 942313537Sglebius non_locking_shift = 2; 943313537Sglebius } else if (non_locking_shift == 2) { 944313537Sglebius /* 945313537Sglebius * Unshift. 946313537Sglebius */ 947313537Sglebius codeset = unshift_codeset; 948313537Sglebius non_locking_shift = 0; 94932145Spst } 95032145Spst 951313537Sglebius /* 952313537Sglebius * Get the first octet of the IE. 953313537Sglebius */ 954313537Sglebius if (!ND_TTEST(*p)) { 955313537Sglebius if (!ndo->ndo_vflag) { 956313537Sglebius ND_PRINT((ndo, ", length %u", olen)); 957313537Sglebius } 958313537Sglebius goto trunc; 959190207Srpaulo } 960313537Sglebius iecode = *p; 961313537Sglebius p++; 962313537Sglebius length--; 963190207Srpaulo 964313537Sglebius /* Single-octet IE? */ 965313537Sglebius if (IE_IS_SINGLE_OCTET(iecode)) { 966313537Sglebius /* 967313537Sglebius * Yes. Is it a shift? 968313537Sglebius */ 969313537Sglebius if (IE_IS_SHIFT(iecode)) { 970313537Sglebius /* 971313537Sglebius * Yes. Is it locking? 972313537Sglebius */ 973313537Sglebius if (IE_SHIFT_IS_LOCKING(iecode)) { 974313537Sglebius /* 975313537Sglebius * Yes. 976313537Sglebius */ 977313537Sglebius non_locking_shift = 0; 978313537Sglebius } else { 979313537Sglebius /* 980313537Sglebius * No. Remember the current 981313537Sglebius * codeset, so we can revert 982313537Sglebius * to it after the next IE. 983313537Sglebius */ 984313537Sglebius non_locking_shift = 1; 985313537Sglebius unshift_codeset = codeset; 986313537Sglebius } 98732145Spst 988313537Sglebius /* 989313537Sglebius * Get the codeset. 990313537Sglebius */ 991313537Sglebius codeset = IE_SHIFT_CODESET(iecode); 992313537Sglebius } 993313537Sglebius } else { 994313537Sglebius /* 995313537Sglebius * No. Get the IE length. 996313537Sglebius */ 997313537Sglebius if (length == 0 || !ND_TTEST(*p)) { 998313537Sglebius if (!ndo->ndo_vflag) { 999313537Sglebius ND_PRINT((ndo, ", length %u", olen)); 1000313537Sglebius } 1001313537Sglebius goto trunc; 1002313537Sglebius } 1003313537Sglebius ielength = *p; 1004313537Sglebius p++; 1005313537Sglebius length--; 1006190207Srpaulo 1007313537Sglebius /* lets do the full IE parsing only in verbose mode 1008313537Sglebius * however some IEs (DLCI Status, Link Verify) 1009313537Sglebius * are also interesting in non-verbose mode */ 1010313537Sglebius if (ndo->ndo_vflag) { 1011313537Sglebius ND_PRINT((ndo, "\n\t%s IE (0x%02x), length %u: ", 1012313537Sglebius tok2str(fr_q933_ie_codesets[codeset], 1013313537Sglebius "unknown", iecode), 1014313537Sglebius iecode, 1015313537Sglebius ielength)); 1016313537Sglebius } 1017162021Ssam 1018313537Sglebius /* sanity checks */ 1019313537Sglebius if (iecode == 0 || ielength == 0) { 1020313537Sglebius return; 1021313537Sglebius } 1022313537Sglebius if (length < ielength || !ND_TTEST2(*p, ielength)) { 1023313537Sglebius if (!ndo->ndo_vflag) { 1024313537Sglebius ND_PRINT((ndo, ", length %u", olen)); 1025313537Sglebius } 1026313537Sglebius goto trunc; 1027313537Sglebius } 1028313537Sglebius 1029313537Sglebius ie_is_known = 0; 1030313537Sglebius if (fr_q933_print_ie_codeset[codeset] != NULL) { 1031313537Sglebius ie_is_known = fr_q933_print_ie_codeset[codeset](ndo, iecode, ielength, p); 1032313537Sglebius } 1033313537Sglebius 1034313537Sglebius if (ie_is_known) { 1035313537Sglebius /* 1036313537Sglebius * Known IE; do we want to see a hexdump 1037313537Sglebius * of it? 1038313537Sglebius */ 1039313537Sglebius if (ndo->ndo_vflag > 1) { 1040313537Sglebius /* Yes. */ 1041313537Sglebius print_unknown_data(ndo, p, "\n\t ", ielength); 1042313537Sglebius } 1043313537Sglebius } else { 1044313537Sglebius /* 1045313537Sglebius * Unknown IE; if we're printing verbosely, 1046313537Sglebius * print its content in hex. 1047313537Sglebius */ 1048313537Sglebius if (ndo->ndo_vflag >= 1) { 1049313537Sglebius print_unknown_data(ndo, p, "\n\t", ielength); 1050313537Sglebius } 1051313537Sglebius } 1052313537Sglebius 1053313537Sglebius length -= ielength; 1054313537Sglebius p += ielength; 1055190207Srpaulo } 1056146778Ssam } 1057313537Sglebius if (!ndo->ndo_vflag) { 1058313537Sglebius ND_PRINT((ndo, ", length %u", olen)); 1059190207Srpaulo } 1060313537Sglebius return; 1061313537Sglebius 1062313537Sglebiustrunc: 1063313537Sglebius ND_PRINT((ndo, "[|q.933]")); 1064146778Ssam} 1065147904Ssam 1066147904Ssamstatic int 1067313537Sglebiusfr_q933_print_ie_codeset_0_5(netdissect_options *ndo, u_int iecode, 1068313537Sglebius u_int ielength, const u_char *p) 1069147904Ssam{ 1070147904Ssam u_int dlci; 1071147904Ssam 1072313537Sglebius switch (iecode) { 1073147904Ssam 1074147904Ssam case FR_LMI_ANSI_REPORT_TYPE_IE: /* fall through */ 1075147904Ssam case FR_LMI_CCITT_REPORT_TYPE_IE: 1076313537Sglebius if (ielength < 1) { 1077313537Sglebius if (!ndo->ndo_vflag) { 1078313537Sglebius ND_PRINT((ndo, ", ")); 1079313537Sglebius } 1080313537Sglebius ND_PRINT((ndo, "Invalid REPORT TYPE IE")); 1081313537Sglebius return 1; 1082313537Sglebius } 1083276788Sdelphij if (ndo->ndo_vflag) { 1084276788Sdelphij ND_PRINT((ndo, "%s (%u)", 1085313537Sglebius tok2str(fr_lmi_report_type_ie_values,"unknown",p[0]), 1086313537Sglebius p[0])); 1087190207Srpaulo } 1088147904Ssam return 1; 1089147904Ssam 1090147904Ssam case FR_LMI_ANSI_LINK_VERIFY_IE: /* fall through */ 1091147904Ssam case FR_LMI_CCITT_LINK_VERIFY_IE: 1092147904Ssam case FR_LMI_ANSI_LINK_VERIFY_IE_91: 1093276788Sdelphij if (!ndo->ndo_vflag) { 1094276788Sdelphij ND_PRINT((ndo, ", ")); 1095190207Srpaulo } 1096313537Sglebius if (ielength < 2) { 1097313537Sglebius ND_PRINT((ndo, "Invalid LINK VERIFY IE")); 1098313537Sglebius return 1; 1099313537Sglebius } 1100313537Sglebius ND_PRINT((ndo, "TX Seq: %3d, RX Seq: %3d", p[0], p[1])); 1101147904Ssam return 1; 1102147904Ssam 1103147904Ssam case FR_LMI_ANSI_PVC_STATUS_IE: /* fall through */ 1104147904Ssam case FR_LMI_CCITT_PVC_STATUS_IE: 1105276788Sdelphij if (!ndo->ndo_vflag) { 1106276788Sdelphij ND_PRINT((ndo, ", ")); 1107190207Srpaulo } 1108276788Sdelphij /* now parse the DLCI information element. */ 1109313537Sglebius if ((ielength < 3) || 1110313537Sglebius (p[0] & 0x80) || 1111313537Sglebius ((ielength == 3) && !(p[1] & 0x80)) || 1112313537Sglebius ((ielength == 4) && ((p[1] & 0x80) || !(p[2] & 0x80))) || 1113313537Sglebius ((ielength == 5) && ((p[1] & 0x80) || (p[2] & 0x80) || 1114313537Sglebius !(p[3] & 0x80))) || 1115313537Sglebius (ielength > 5) || 1116313537Sglebius !(p[ielength - 1] & 0x80)) { 1117313537Sglebius ND_PRINT((ndo, "Invalid DLCI in PVC STATUS IE")); 1118313537Sglebius return 1; 1119190207Srpaulo } 1120276788Sdelphij 1121313537Sglebius dlci = ((p[0] & 0x3F) << 4) | ((p[1] & 0x78) >> 3); 1122313537Sglebius if (ielength == 4) { 1123313537Sglebius dlci = (dlci << 6) | ((p[2] & 0x7E) >> 1); 1124190207Srpaulo } 1125313537Sglebius else if (ielength == 5) { 1126313537Sglebius dlci = (dlci << 13) | (p[2] & 0x7F) | ((p[3] & 0x7E) >> 1); 1127190207Srpaulo } 1128147904Ssam 1129276788Sdelphij ND_PRINT((ndo, "DLCI %u: status %s%s", dlci, 1130313537Sglebius p[ielength - 1] & 0x8 ? "New, " : "", 1131313537Sglebius p[ielength - 1] & 0x2 ? "Active" : "Inactive")); 1132147904Ssam return 1; 1133147904Ssam } 1134147904Ssam 1135147904Ssam return 0; 1136147904Ssam} 1137276788Sdelphij/* 1138276788Sdelphij * Local Variables: 1139276788Sdelphij * c-style: whitesmith 1140276788Sdelphij * c-basic-offset: 8 1141276788Sdelphij * End: 1142276788Sdelphij */ 1143