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: releng/11.0/contrib/tcpdump/print-fr.c 285275 2015-07-08 16:19:32Z pkelsey $ 2232145Spst */ 2332145Spst 24276788Sdelphij#define NETDISSECT_REWORKED 25146778Ssam#ifdef HAVE_CONFIG_H 26146778Ssam#include "config.h" 2732145Spst#endif 2832145Spst 29146778Ssam#include <tcpdump-stdinc.h> 3032145Spst 31146778Ssam#include <stdio.h> 32146778Ssam#include <string.h> 3332145Spst 34276788Sdelphij#include "interface.h" 35146778Ssam#include "addrtoname.h" 3632145Spst#include "ethertype.h" 37285275Spkelsey#include "llc.h" 38146778Ssam#include "nlpid.h" 39146778Ssam#include "extract.h" 40146778Ssam#include "oui.h" 4132145Spst 42276788Sdelphijstatic void frf15_print(netdissect_options *ndo, const u_char *, u_int); 4332145Spst 44146778Ssam/* 45146778Ssam * the frame relay header has a variable length 46146778Ssam * 47146778Ssam * the EA bit determines if there is another byte 48146778Ssam * in the header 49146778Ssam * 50146778Ssam * minimum header length is 2 bytes 51146778Ssam * maximum header length is 4 bytes 52146778Ssam * 53146778Ssam * 7 6 5 4 3 2 1 0 54146778Ssam * +----+----+----+----+----+----+----+----+ 55146778Ssam * | DLCI (6 bits) | CR | EA | 56146778Ssam * +----+----+----+----+----+----+----+----+ 57146778Ssam * | DLCI (4 bits) |FECN|BECN| DE | EA | 58146778Ssam * +----+----+----+----+----+----+----+----+ 59146778Ssam * | DLCI (7 bits) | EA | 60146778Ssam * +----+----+----+----+----+----+----+----+ 61146778Ssam * | DLCI (6 bits) |SDLC| EA | 62146778Ssam * +----+----+----+----+----+----+----+----+ 63146778Ssam */ 6432145Spst 65146778Ssam#define FR_EA_BIT 0x01 6632145Spst 67146778Ssam#define FR_CR_BIT 0x02000000 68146778Ssam#define FR_DE_BIT 0x00020000 69146778Ssam#define FR_BECN_BIT 0x00040000 70146778Ssam#define FR_FECN_BIT 0x00080000 71146778Ssam#define FR_SDLC_BIT 0x00000002 7232145Spst 73146778Ssam 74276788Sdelphijstatic const struct tok fr_header_flag_values[] = { 75146778Ssam { FR_CR_BIT, "C!" }, 76146778Ssam { FR_DE_BIT, "DE" }, 77146778Ssam { FR_BECN_BIT, "BECN" }, 78146778Ssam { FR_FECN_BIT, "FECN" }, 79146778Ssam { FR_SDLC_BIT, "sdlcore" }, 80146778Ssam { 0, NULL } 8132145Spst}; 8232145Spst 83162021Ssam/* FRF.15 / FRF.16 */ 84162021Ssam#define MFR_B_BIT 0x80 85162021Ssam#define MFR_E_BIT 0x40 86162021Ssam#define MFR_C_BIT 0x20 87162021Ssam#define MFR_BEC_MASK (MFR_B_BIT | MFR_E_BIT | MFR_C_BIT) 88162021Ssam#define MFR_CTRL_FRAME (MFR_B_BIT | MFR_E_BIT | MFR_C_BIT) 89162021Ssam#define MFR_FRAG_FRAME (MFR_B_BIT | MFR_E_BIT ) 90146778Ssam 91276788Sdelphijstatic const struct tok frf_flag_values[] = { 92162021Ssam { MFR_B_BIT, "Begin" }, 93162021Ssam { MFR_E_BIT, "End" }, 94162021Ssam { MFR_C_BIT, "Control" }, 95162021Ssam { 0, NULL } 96162021Ssam}; 97162021Ssam 98285275Spkelsey/* Finds out Q.922 address length, DLCI and flags. Returns 1 on success, 99285275Spkelsey * 0 on invalid address, -1 on truncated packet 100146778Ssam * save the flags dep. on address length 101146778Ssam */ 102285275Spkelseystatic int parse_q922_addr(netdissect_options *ndo, 103285275Spkelsey const u_char *p, u_int *dlci, 104285275Spkelsey u_int *addr_len, uint8_t *flags, u_int length) 10532145Spst{ 106285275Spkelsey if (!ND_TTEST(p[0]) || length < 1) 107285275Spkelsey return -1; 108146778Ssam if ((p[0] & FR_EA_BIT)) 109285275Spkelsey return 0; 110285275Spkelsey 111285275Spkelsey if (!ND_TTEST(p[1]) || length < 2) 112146778Ssam return -1; 113146778Ssam *addr_len = 2; 114146778Ssam *dlci = ((p[0] & 0xFC) << 2) | ((p[1] & 0xF0) >> 4); 11532145Spst 116146778Ssam flags[0] = p[0] & 0x02; /* populate the first flag fields */ 117146778Ssam flags[1] = p[1] & 0x0c; 118172686Smlaier flags[2] = 0; /* clear the rest of the flags */ 119172686Smlaier flags[3] = 0; 12032145Spst 121146778Ssam if (p[1] & FR_EA_BIT) 122285275Spkelsey return 1; /* 2-byte Q.922 address */ 12332145Spst 124146778Ssam p += 2; 125285275Spkelsey length -= 2; 126285275Spkelsey if (!ND_TTEST(p[0]) || length < 1) 127285275Spkelsey return -1; 128146778Ssam (*addr_len)++; /* 3- or 4-byte Q.922 address */ 129146778Ssam if ((p[0] & FR_EA_BIT) == 0) { 130146778Ssam *dlci = (*dlci << 7) | (p[0] >> 1); 131146778Ssam (*addr_len)++; /* 4-byte Q.922 address */ 132146778Ssam p++; 133285275Spkelsey length--; 134146778Ssam } 13532145Spst 136285275Spkelsey if (!ND_TTEST(p[0]) || length < 1) 137285275Spkelsey return -1; 138146778Ssam if ((p[0] & FR_EA_BIT) == 0) 139285275Spkelsey return 0; /* more than 4 bytes of Q.922 address? */ 140146778Ssam 141146778Ssam flags[3] = p[0] & 0x02; 142146778Ssam 143190207Srpaulo *dlci = (*dlci << 6) | (p[0] >> 2); 144146778Ssam 145285275Spkelsey return 1; 14632145Spst} 14732145Spst 148285275Spkelseychar * 149285275Spkelseyq922_string(netdissect_options *ndo, const u_char *p, u_int length) 150285275Spkelsey{ 151190207Srpaulo 152190207Srpaulo static u_int dlci, addr_len; 153276788Sdelphij static uint8_t flags[4]; 154190207Srpaulo static char buffer[sizeof("DLCI xxxxxxxxxx")]; 155190207Srpaulo memset(buffer, 0, sizeof(buffer)); 156190207Srpaulo 157285275Spkelsey if (parse_q922_addr(ndo, p, &dlci, &addr_len, flags, length) == 1){ 158190207Srpaulo snprintf(buffer, sizeof(buffer), "DLCI %u", dlci); 159190207Srpaulo } 160190207Srpaulo 161190207Srpaulo return buffer; 162190207Srpaulo} 163190207Srpaulo 164190207Srpaulo 165146778Ssam/* Frame Relay packet structure, with flags and CRC removed 16632145Spst 16732145Spst +---------------------------+ 16832145Spst | Q.922 Address* | 16932145Spst +-- --+ 17032145Spst | | 17132145Spst +---------------------------+ 17232145Spst | Control (UI = 0x03) | 17332145Spst +---------------------------+ 17432145Spst | Optional Pad (0x00) | 17532145Spst +---------------------------+ 17632145Spst | NLPID | 17732145Spst +---------------------------+ 17832145Spst | . | 17932145Spst | . | 18032145Spst | . | 18132145Spst | Data | 18232145Spst | . | 18332145Spst | . | 18432145Spst +---------------------------+ 18532145Spst 18632145Spst * Q.922 addresses, as presently defined, are two octets and 18732145Spst contain a 10-bit DLCI. In some networks Q.922 addresses 18832145Spst may optionally be increased to three or four octets. 18932145Spst*/ 19032145Spst 191146778Ssamstatic void 192276788Sdelphijfr_hdr_print(netdissect_options *ndo, 193276788Sdelphij int length, u_int addr_len, u_int dlci, uint8_t *flags, uint16_t nlpid) 19432145Spst{ 195276788Sdelphij if (ndo->ndo_qflag) { 196276788Sdelphij ND_PRINT((ndo, "Q.922, DLCI %u, length %u: ", 197146778Ssam dlci, 198276788Sdelphij length)); 199146778Ssam } else { 200146778Ssam if (nlpid <= 0xff) /* if its smaller than 256 then its a NLPID */ 201276788Sdelphij ND_PRINT((ndo, "Q.922, hdr-len %u, DLCI %u, Flags [%s], NLPID %s (0x%02x), length %u: ", 202146778Ssam addr_len, 203146778Ssam dlci, 204146778Ssam bittok2str(fr_header_flag_values, "none", EXTRACT_32BITS(flags)), 205146778Ssam tok2str(nlpid_values,"unknown", nlpid), 206146778Ssam nlpid, 207276788Sdelphij length)); 208146778Ssam else /* must be an ethertype */ 209276788Sdelphij ND_PRINT((ndo, "Q.922, hdr-len %u, DLCI %u, Flags [%s], cisco-ethertype %s (0x%04x), length %u: ", 210146778Ssam addr_len, 211146778Ssam dlci, 212146778Ssam bittok2str(fr_header_flag_values, "none", EXTRACT_32BITS(flags)), 213146778Ssam tok2str(ethertype_values, "unknown", nlpid), 214146778Ssam nlpid, 215276788Sdelphij length)); 216146778Ssam } 21732145Spst} 21832145Spst 219146778Ssamu_int 220276788Sdelphijfr_if_print(netdissect_options *ndo, 221276788Sdelphij const struct pcap_pkthdr *h, register const u_char *p) 22232145Spst{ 22332145Spst register u_int length = h->len; 22432145Spst register u_int caplen = h->caplen; 225147904Ssam 226276788Sdelphij ND_TCHECK2(*p, 4); /* minimum frame header length */ 227147904Ssam 228276788Sdelphij if ((length = fr_print(ndo, p, length)) == 0) 229147904Ssam return (0); 230147904Ssam else 231147904Ssam return length; 232147904Ssam trunc: 233276788Sdelphij ND_PRINT((ndo, "[|fr]")); 234147904Ssam return caplen; 235147904Ssam} 236147904Ssam 237147904Ssamu_int 238276788Sdelphijfr_print(netdissect_options *ndo, 239276788Sdelphij register const u_char *p, u_int length) 240147904Ssam{ 241285275Spkelsey int ret; 242276788Sdelphij uint16_t extracted_ethertype; 243146778Ssam u_int dlci; 244146778Ssam u_int addr_len; 245276788Sdelphij uint16_t nlpid; 246146778Ssam u_int hdr_len; 247276788Sdelphij uint8_t flags[4]; 24832145Spst 249285275Spkelsey ret = parse_q922_addr(ndo, p, &dlci, &addr_len, flags, length); 250285275Spkelsey if (ret == -1) 251285275Spkelsey goto trunc; 252285275Spkelsey if (ret == 0) { 253276788Sdelphij ND_PRINT((ndo, "Q.922, invalid address")); 254147904Ssam return 0; 255146778Ssam } 25632145Spst 257285275Spkelsey ND_TCHECK(p[addr_len]); 258285275Spkelsey if (length < addr_len + 1) 259285275Spkelsey goto trunc; 260146778Ssam 261285275Spkelsey if (p[addr_len] != LLC_UI && dlci != 0) { 262285275Spkelsey /* 263285275Spkelsey * Let's figure out if we have Cisco-style encapsulation, 264285275Spkelsey * with an Ethernet type (Cisco HDLC type?) following the 265285275Spkelsey * address. 266285275Spkelsey */ 267285275Spkelsey if (!ND_TTEST2(p[addr_len], 2) || length < addr_len + 2) { 268285275Spkelsey /* no Ethertype */ 269285275Spkelsey ND_PRINT((ndo, "UI %02x! ", p[addr_len])); 270285275Spkelsey } else { 271285275Spkelsey extracted_ethertype = EXTRACT_16BITS(p+addr_len); 27232145Spst 273285275Spkelsey if (ndo->ndo_eflag) 274285275Spkelsey fr_hdr_print(ndo, length, addr_len, dlci, 275285275Spkelsey flags, extracted_ethertype); 276146778Ssam 277285275Spkelsey if (ethertype_print(ndo, extracted_ethertype, 278285275Spkelsey p+addr_len+ETHERTYPE_LEN, 279285275Spkelsey length-addr_len-ETHERTYPE_LEN, 280285275Spkelsey length-addr_len-ETHERTYPE_LEN) == 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: 332276788Sdelphij isoclns_print(ndo, p - 1, length + 1, length + 1); /* OSI printers need the NLPID field */ 33332145Spst break; 334146778Ssam 335146778Ssam case NLPID_SNAP: 336276788Sdelphij if (snap_print(ndo, p, length, length, 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 602162021Ssam flags = p[0]&MFR_BEC_MASK; 603146778Ssam sequence_num = (p[0]&0x1e)<<7 | p[1]; 604146778Ssam 605276788Sdelphij ND_PRINT((ndo, "FRF.15, seq 0x%03x, Flags [%s],%s Fragmentation, length %u", 606146778Ssam sequence_num, 607162021Ssam bittok2str(frf_flag_values,"none",flags), 608162021Ssam p[0]&FR_FRF15_FRAGTYPE ? "Interface" : "End-to-End", 609276788Sdelphij length)); 610146778Ssam 611146778Ssam/* TODO: 612146778Ssam * depending on all permutations of the B, E and C bit 613146778Ssam * dig as deep as we can - e.g. on the first (B) fragment 614146778Ssam * there is enough payload to print the IP header 615146778Ssam * on non (B) fragments it depends if the fragmentation 616146778Ssam * model is end-to-end or interface based wether we want to print 617146778Ssam * another Q.922 header 618146778Ssam */ 619146778Ssam 62032145Spst} 62132145Spst 62232145Spst/* 62332145Spst * Q.933 decoding portion for framerelay specific. 62432145Spst */ 62532145Spst 62632145Spst/* Q.933 packet format 627276788Sdelphij Format of Other Protocols 62832145Spst using Q.933 NLPID 629276788Sdelphij +-------------------------------+ 630276788Sdelphij | Q.922 Address | 63132145Spst +---------------+---------------+ 632276788Sdelphij |Control 0x03 | NLPID 0x08 | 633276788Sdelphij +---------------+---------------+ 63432145Spst | L2 Protocol ID | 63532145Spst | octet 1 | octet 2 | 63632145Spst +-------------------------------+ 63732145Spst | L3 Protocol ID | 63832145Spst | octet 2 | octet 2 | 63932145Spst +-------------------------------+ 64032145Spst | Protocol Data | 64132145Spst +-------------------------------+ 64232145Spst | FCS | 64332145Spst +-------------------------------+ 64432145Spst */ 64532145Spst 64632145Spst/* L2 (Octet 1)- Call Reference Usually is 0x0 */ 64732145Spst 64832145Spst/* 64932145Spst * L2 (Octet 2)- Message Types definition 1 byte long. 65032145Spst */ 65132145Spst/* Call Establish */ 65232145Spst#define MSG_TYPE_ESC_TO_NATIONAL 0x00 65332145Spst#define MSG_TYPE_ALERT 0x01 65432145Spst#define MSG_TYPE_CALL_PROCEEDING 0x02 65532145Spst#define MSG_TYPE_CONNECT 0x07 65632145Spst#define MSG_TYPE_CONNECT_ACK 0x0F 65732145Spst#define MSG_TYPE_PROGRESS 0x03 65832145Spst#define MSG_TYPE_SETUP 0x05 65932145Spst/* Call Clear */ 66032145Spst#define MSG_TYPE_DISCONNECT 0x45 66132145Spst#define MSG_TYPE_RELEASE 0x4D 66232145Spst#define MSG_TYPE_RELEASE_COMPLETE 0x5A 66332145Spst#define MSG_TYPE_RESTART 0x46 66432145Spst#define MSG_TYPE_RESTART_ACK 0x4E 66532145Spst/* Status */ 66632145Spst#define MSG_TYPE_STATUS 0x7D 66732145Spst#define MSG_TYPE_STATUS_ENQ 0x75 66832145Spst 669276788Sdelphijstatic const struct tok fr_q933_msg_values[] = { 670146778Ssam { MSG_TYPE_ESC_TO_NATIONAL, "ESC to National" }, 671146778Ssam { MSG_TYPE_ALERT, "Alert" }, 672146778Ssam { MSG_TYPE_CALL_PROCEEDING, "Call proceeding" }, 673146778Ssam { MSG_TYPE_CONNECT, "Connect" }, 674146778Ssam { MSG_TYPE_CONNECT_ACK, "Connect ACK" }, 675146778Ssam { MSG_TYPE_PROGRESS, "Progress" }, 676146778Ssam { MSG_TYPE_SETUP, "Setup" }, 677146778Ssam { MSG_TYPE_DISCONNECT, "Disconnect" }, 678146778Ssam { MSG_TYPE_RELEASE, "Release" }, 679146778Ssam { MSG_TYPE_RELEASE_COMPLETE, "Release Complete" }, 680146778Ssam { MSG_TYPE_RESTART, "Restart" }, 681146778Ssam { MSG_TYPE_RESTART_ACK, "Restart ACK" }, 682146778Ssam { MSG_TYPE_STATUS, "Status Reply" }, 683146778Ssam { MSG_TYPE_STATUS_ENQ, "Status Enquiry" }, 684146778Ssam { 0, NULL } 685146778Ssam}; 68632145Spst 687146778Ssam#define MSG_ANSI_LOCKING_SHIFT 0x95 688146778Ssam 689146778Ssam#define FR_LMI_ANSI_REPORT_TYPE_IE 0x01 690146778Ssam#define FR_LMI_ANSI_LINK_VERIFY_IE_91 0x19 /* details? */ 691146778Ssam#define FR_LMI_ANSI_LINK_VERIFY_IE 0x03 692146778Ssam#define FR_LMI_ANSI_PVC_STATUS_IE 0x07 693146778Ssam 694146778Ssam#define FR_LMI_CCITT_REPORT_TYPE_IE 0x51 695146778Ssam#define FR_LMI_CCITT_LINK_VERIFY_IE 0x53 696146778Ssam#define FR_LMI_CCITT_PVC_STATUS_IE 0x57 697146778Ssam 698276788Sdelphijstatic const struct tok fr_q933_ie_values_codeset5[] = { 699146778Ssam { FR_LMI_ANSI_REPORT_TYPE_IE, "ANSI Report Type" }, 700146778Ssam { FR_LMI_ANSI_LINK_VERIFY_IE_91, "ANSI Link Verify" }, 701146778Ssam { FR_LMI_ANSI_LINK_VERIFY_IE, "ANSI Link Verify" }, 702146778Ssam { FR_LMI_ANSI_PVC_STATUS_IE, "ANSI PVC Status" }, 703146778Ssam { FR_LMI_CCITT_REPORT_TYPE_IE, "CCITT Report Type" }, 704146778Ssam { FR_LMI_CCITT_LINK_VERIFY_IE, "CCITT Link Verify" }, 705146778Ssam { FR_LMI_CCITT_PVC_STATUS_IE, "CCITT PVC Status" }, 706146778Ssam { 0, NULL } 70732145Spst}; 70832145Spst 709146778Ssam#define FR_LMI_REPORT_TYPE_IE_FULL_STATUS 0 710146778Ssam#define FR_LMI_REPORT_TYPE_IE_LINK_VERIFY 1 711146778Ssam#define FR_LMI_REPORT_TYPE_IE_ASYNC_PVC 2 71232145Spst 713276788Sdelphijstatic const struct tok fr_lmi_report_type_ie_values[] = { 714146778Ssam { FR_LMI_REPORT_TYPE_IE_FULL_STATUS, "Full Status" }, 715146778Ssam { FR_LMI_REPORT_TYPE_IE_LINK_VERIFY, "Link verify" }, 716146778Ssam { FR_LMI_REPORT_TYPE_IE_ASYNC_PVC, "Async PVC Status" }, 717146778Ssam { 0, NULL } 718146778Ssam}; 71932145Spst 720162021Ssam/* array of 16 codepages - currently we only support codepage 1,5 */ 721276788Sdelphijstatic const struct tok *fr_q933_ie_codesets[] = { 722146778Ssam NULL, 723162021Ssam fr_q933_ie_values_codeset5, 724146778Ssam NULL, 725146778Ssam NULL, 726146778Ssam NULL, 727146778Ssam fr_q933_ie_values_codeset5, 728146778Ssam NULL, 729146778Ssam NULL, 730146778Ssam NULL, 731146778Ssam NULL, 732146778Ssam NULL, 733146778Ssam NULL, 734146778Ssam NULL, 735146778Ssam NULL, 736146778Ssam NULL, 737146778Ssam NULL 73832145Spst}; 73932145Spst 740276788Sdelphijstatic int fr_q933_print_ie_codeset5(netdissect_options *ndo, 741276788Sdelphij const struct ie_tlv_header_t *ie_p, const u_char *p); 742147904Ssam 743276788Sdelphijtypedef int (*codeset_pr_func_t)(netdissect_options *, 744276788Sdelphij const struct ie_tlv_header_t *ie_p, const u_char *p); 745147904Ssam 746162021Ssam/* array of 16 codepages - currently we only support codepage 1,5 */ 747276788Sdelphijstatic const codeset_pr_func_t fr_q933_print_ie_codeset[] = { 748147904Ssam NULL, 749162021Ssam fr_q933_print_ie_codeset5, 750147904Ssam NULL, 751147904Ssam NULL, 752147904Ssam NULL, 753147904Ssam fr_q933_print_ie_codeset5, 754147904Ssam NULL, 755147904Ssam NULL, 756147904Ssam NULL, 757147904Ssam NULL, 758147904Ssam NULL, 759147904Ssam NULL, 760147904Ssam NULL, 761147904Ssam NULL, 762147904Ssam NULL, 763147904Ssam NULL 764147904Ssam}; 765147904Ssam 76632145Spstvoid 767276788Sdelphijq933_print(netdissect_options *ndo, 768276788Sdelphij const u_char *p, u_int length) 76932145Spst{ 77032145Spst const u_char *ptemp = p; 771162021Ssam struct ie_tlv_header_t *ie_p; 772146778Ssam int olen; 773146778Ssam int is_ansi = 0; 774147904Ssam u_int codeset; 775162021Ssam u_int ie_is_known = 0; 776146778Ssam 777146778Ssam if (length < 9) { /* shortest: Q.933a LINK VERIFY */ 778276788Sdelphij ND_PRINT((ndo, "[|q.933]")); 779146778Ssam return; 780146778Ssam } 781146778Ssam 782146778Ssam codeset = p[2]&0x0f; /* extract the codeset */ 783146778Ssam 784190207Srpaulo if (p[2] == MSG_ANSI_LOCKING_SHIFT) { 785190207Srpaulo is_ansi = 1; 786190207Srpaulo } 78732145Spst 788276788Sdelphij ND_PRINT((ndo, "%s", ndo->ndo_eflag ? "" : "Q.933, ")); 789276788Sdelphij 79032145Spst /* printing out header part */ 791276788Sdelphij ND_PRINT((ndo, "%s, codeset %u", is_ansi ? "ANSI" : "CCITT", codeset)); 792146778Ssam 793190207Srpaulo if (p[0]) { 794276788Sdelphij ND_PRINT((ndo, ", Call Ref: 0x%02x", p[0])); 795190207Srpaulo } 796276788Sdelphij if (ndo->ndo_vflag) { 797276788Sdelphij ND_PRINT((ndo, ", %s (0x%02x), length %u", 798190207Srpaulo tok2str(fr_q933_msg_values, 799190207Srpaulo "unknown message", p[1]), 800190207Srpaulo p[1], 801276788Sdelphij length)); 802190207Srpaulo } else { 803276788Sdelphij ND_PRINT((ndo, ", %s", 804190207Srpaulo tok2str(fr_q933_msg_values, 805276788Sdelphij "unknown message 0x%02x", p[1]))); 806190207Srpaulo } 807146778Ssam 808146778Ssam olen = length; /* preserve the original length for non verbose mode */ 809146778Ssam 810146778Ssam if (length < (u_int)(2 - is_ansi)) { 811276788Sdelphij ND_PRINT((ndo, "[|q.933]")); 812146778Ssam return; 81332145Spst } 814190207Srpaulo length -= 2 + is_ansi; 815146778Ssam ptemp += 2 + is_ansi; 816276788Sdelphij 81732145Spst /* Loop through the rest of IE */ 818190207Srpaulo while (length > sizeof(struct ie_tlv_header_t)) { 819162021Ssam ie_p = (struct ie_tlv_header_t *)ptemp; 820190207Srpaulo if (length < sizeof(struct ie_tlv_header_t) || 821190207Srpaulo length < sizeof(struct ie_tlv_header_t) + ie_p->ie_len) { 822276788Sdelphij if (ndo->ndo_vflag) { /* not bark if there is just a trailer */ 823276788Sdelphij ND_PRINT((ndo, "\n[|q.933]")); 824190207Srpaulo } else { 825276788Sdelphij ND_PRINT((ndo, ", length %u", olen)); 826190207Srpaulo } 827146778Ssam return; 82832145Spst } 82932145Spst 830146778Ssam /* lets do the full IE parsing only in verbose mode 831146778Ssam * however some IEs (DLCI Status, Link Verify) 832190207Srpaulo * are also interestting in non-verbose mode */ 833276788Sdelphij if (ndo->ndo_vflag) { 834276788Sdelphij ND_PRINT((ndo, "\n\t%s IE (0x%02x), length %u: ", 835190207Srpaulo tok2str(fr_q933_ie_codesets[codeset], 836190207Srpaulo "unknown", ie_p->ie_type), 837162021Ssam ie_p->ie_type, 838276788Sdelphij ie_p->ie_len)); 839190207Srpaulo } 840190207Srpaulo 841162021Ssam /* sanity check */ 842190207Srpaulo if (ie_p->ie_type == 0 || ie_p->ie_len == 0) { 843162021Ssam return; 844190207Srpaulo } 84532145Spst 846190207Srpaulo if (fr_q933_print_ie_codeset[codeset] != NULL) { 847276788Sdelphij ie_is_known = fr_q933_print_ie_codeset[codeset](ndo, ie_p, ptemp); 848276788Sdelphij } 849190207Srpaulo 850276788Sdelphij if (ndo->ndo_vflag >= 1 && !ie_is_known) { 851276788Sdelphij print_unknown_data(ndo, ptemp+2, "\n\t", ie_p->ie_len); 852190207Srpaulo } 853162021Ssam 854146778Ssam /* do we want to see a hexdump of the IE ? */ 855276788Sdelphij if (ndo->ndo_vflag> 1 && ie_is_known) { 856276788Sdelphij print_unknown_data(ndo, ptemp+2, "\n\t ", ie_p->ie_len); 857190207Srpaulo } 85832145Spst 859146778Ssam length = length - ie_p->ie_len - 2; 860146778Ssam ptemp = ptemp + ie_p->ie_len + 2; 861146778Ssam } 862276788Sdelphij if (!ndo->ndo_vflag) { 863276788Sdelphij ND_PRINT((ndo, ", length %u", olen)); 864190207Srpaulo } 865146778Ssam} 866147904Ssam 867147904Ssamstatic int 868276788Sdelphijfr_q933_print_ie_codeset5(netdissect_options *ndo, 869276788Sdelphij const struct ie_tlv_header_t *ie_p, const u_char *p) 870147904Ssam{ 871147904Ssam u_int dlci; 872147904Ssam 873162021Ssam switch (ie_p->ie_type) { 874147904Ssam 875147904Ssam case FR_LMI_ANSI_REPORT_TYPE_IE: /* fall through */ 876147904Ssam case FR_LMI_CCITT_REPORT_TYPE_IE: 877276788Sdelphij if (ndo->ndo_vflag) { 878276788Sdelphij ND_PRINT((ndo, "%s (%u)", 879147904Ssam tok2str(fr_lmi_report_type_ie_values,"unknown",p[2]), 880276788Sdelphij p[2])); 881190207Srpaulo } 882147904Ssam return 1; 883147904Ssam 884147904Ssam case FR_LMI_ANSI_LINK_VERIFY_IE: /* fall through */ 885147904Ssam case FR_LMI_CCITT_LINK_VERIFY_IE: 886147904Ssam case FR_LMI_ANSI_LINK_VERIFY_IE_91: 887276788Sdelphij if (!ndo->ndo_vflag) { 888276788Sdelphij ND_PRINT((ndo, ", ")); 889190207Srpaulo } 890276788Sdelphij ND_PRINT((ndo, "TX Seq: %3d, RX Seq: %3d", p[2], p[3])); 891147904Ssam return 1; 892147904Ssam 893147904Ssam case FR_LMI_ANSI_PVC_STATUS_IE: /* fall through */ 894147904Ssam case FR_LMI_CCITT_PVC_STATUS_IE: 895276788Sdelphij if (!ndo->ndo_vflag) { 896276788Sdelphij ND_PRINT((ndo, ", ")); 897190207Srpaulo } 898276788Sdelphij /* now parse the DLCI information element. */ 899147904Ssam if ((ie_p->ie_len < 3) || 900147904Ssam (p[2] & 0x80) || 901147904Ssam ((ie_p->ie_len == 3) && !(p[3] & 0x80)) || 902147904Ssam ((ie_p->ie_len == 4) && ((p[3] & 0x80) || !(p[4] & 0x80))) || 903147904Ssam ((ie_p->ie_len == 5) && ((p[3] & 0x80) || (p[4] & 0x80) || 904147904Ssam !(p[5] & 0x80))) || 905147904Ssam (ie_p->ie_len > 5) || 906190207Srpaulo !(p[ie_p->ie_len + 1] & 0x80)) { 907276788Sdelphij ND_PRINT((ndo, "Invalid DLCI IE")); 908190207Srpaulo } 909276788Sdelphij 910147904Ssam dlci = ((p[2] & 0x3F) << 4) | ((p[3] & 0x78) >> 3); 911190207Srpaulo if (ie_p->ie_len == 4) { 912147904Ssam dlci = (dlci << 6) | ((p[4] & 0x7E) >> 1); 913190207Srpaulo } 914190207Srpaulo else if (ie_p->ie_len == 5) { 915147904Ssam dlci = (dlci << 13) | (p[4] & 0x7F) | ((p[5] & 0x7E) >> 1); 916190207Srpaulo } 917147904Ssam 918276788Sdelphij ND_PRINT((ndo, "DLCI %u: status %s%s", dlci, 919147904Ssam p[ie_p->ie_len + 1] & 0x8 ? "New, " : "", 920276788Sdelphij p[ie_p->ie_len + 1] & 0x2 ? "Active" : "Inactive")); 921147904Ssam return 1; 922147904Ssam } 923147904Ssam 924147904Ssam return 0; 925147904Ssam} 926276788Sdelphij/* 927276788Sdelphij * Local Variables: 928276788Sdelphij * c-style: whitesmith 929276788Sdelphij * c-basic-offset: 8 930276788Sdelphij * End: 931276788Sdelphij */ 932