print-fr.c revision 190207
132145Spst/* 232145Spst * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996 332145Spst * The Regents of the University of California. All rights reserved. 432145Spst * 532145Spst * Redistribution and use in source and binary forms, with or without 632145Spst * modification, are permitted provided that: (1) source code distributions 732145Spst * retain the above copyright notice and this paragraph in its entirety, (2) 832145Spst * distributions including binary code include the above copyright notice and 932145Spst * this paragraph in its entirety in the documentation or other materials 1032145Spst * provided with the distribution, and (3) all advertising materials mentioning 1132145Spst * features or use of this software display the following acknowledgement: 1232145Spst * ``This product includes software developed by the University of California, 1332145Spst * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 1432145Spst * the University nor the names of its contributors may be used to endorse 1532145Spst * or promote products derived from this software without specific prior 1632145Spst * written permission. 1732145Spst * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 1832145Spst * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 1932145Spst * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 2066644Skris * 2166644Skris * $FreeBSD: head/contrib/tcpdump/print-fr.c 190207 2009-03-21 18:30:25Z rpaulo $ 2232145Spst */ 2332145Spst 2432145Spst#ifndef lint 25146778Ssamstatic const char rcsid[] _U_ = 26190207Srpaulo "@(#)$Header: /tcpdump/master/tcpdump/print-fr.c,v 1.51 2006-06-23 22:20:32 hannes Exp $ (LBL)"; 2732145Spst#endif 2832145Spst 29146778Ssam#ifdef HAVE_CONFIG_H 30146778Ssam#include "config.h" 3132145Spst#endif 3232145Spst 33146778Ssam#include <tcpdump-stdinc.h> 3432145Spst 35146778Ssam#include <stdio.h> 36146778Ssam#include <string.h> 3732145Spst#include <pcap.h> 3832145Spst 39146778Ssam#include "addrtoname.h" 40146778Ssam#include "interface.h" 4132145Spst#include "ethertype.h" 42146778Ssam#include "nlpid.h" 43146778Ssam#include "extract.h" 44146778Ssam#include "oui.h" 4532145Spst 46146778Ssamstatic void frf15_print(const u_char *, u_int); 4732145Spst 48146778Ssam/* 49146778Ssam * the frame relay header has a variable length 50146778Ssam * 51146778Ssam * the EA bit determines if there is another byte 52146778Ssam * in the header 53146778Ssam * 54146778Ssam * minimum header length is 2 bytes 55146778Ssam * maximum header length is 4 bytes 56146778Ssam * 57146778Ssam * 7 6 5 4 3 2 1 0 58146778Ssam * +----+----+----+----+----+----+----+----+ 59146778Ssam * | DLCI (6 bits) | CR | EA | 60146778Ssam * +----+----+----+----+----+----+----+----+ 61146778Ssam * | DLCI (4 bits) |FECN|BECN| DE | EA | 62146778Ssam * +----+----+----+----+----+----+----+----+ 63146778Ssam * | DLCI (7 bits) | EA | 64146778Ssam * +----+----+----+----+----+----+----+----+ 65146778Ssam * | DLCI (6 bits) |SDLC| EA | 66146778Ssam * +----+----+----+----+----+----+----+----+ 67146778Ssam */ 6832145Spst 69146778Ssam#define FR_EA_BIT 0x01 7032145Spst 71146778Ssam#define FR_CR_BIT 0x02000000 72146778Ssam#define FR_DE_BIT 0x00020000 73146778Ssam#define FR_BECN_BIT 0x00040000 74146778Ssam#define FR_FECN_BIT 0x00080000 75146778Ssam#define FR_SDLC_BIT 0x00000002 7632145Spst 77146778Ssam 78146778Ssamstruct tok fr_header_flag_values[] = { 79146778Ssam { FR_CR_BIT, "C!" }, 80146778Ssam { FR_DE_BIT, "DE" }, 81146778Ssam { FR_BECN_BIT, "BECN" }, 82146778Ssam { FR_FECN_BIT, "FECN" }, 83146778Ssam { FR_SDLC_BIT, "sdlcore" }, 84146778Ssam { 0, NULL } 8532145Spst}; 8632145Spst 87162021Ssam/* FRF.15 / FRF.16 */ 88162021Ssam#define MFR_B_BIT 0x80 89162021Ssam#define MFR_E_BIT 0x40 90162021Ssam#define MFR_C_BIT 0x20 91162021Ssam#define MFR_BEC_MASK (MFR_B_BIT | MFR_E_BIT | MFR_C_BIT) 92162021Ssam#define MFR_CTRL_FRAME (MFR_B_BIT | MFR_E_BIT | MFR_C_BIT) 93162021Ssam#define MFR_FRAG_FRAME (MFR_B_BIT | MFR_E_BIT ) 94146778Ssam 95162021Ssamstruct tok frf_flag_values[] = { 96162021Ssam { MFR_B_BIT, "Begin" }, 97162021Ssam { MFR_E_BIT, "End" }, 98162021Ssam { MFR_C_BIT, "Control" }, 99162021Ssam { 0, NULL } 100162021Ssam}; 101162021Ssam 102146778Ssam/* Finds out Q.922 address length, DLCI and flags. Returns 0 on success 103146778Ssam * save the flags dep. on address length 104146778Ssam */ 105190207Srpaulostatic int parse_q922_addr(const u_char *p, u_int *dlci, 106146778Ssam u_int *addr_len, u_int8_t *flags) 10732145Spst{ 108146778Ssam if ((p[0] & FR_EA_BIT)) 109146778Ssam return -1; 11032145Spst 111146778Ssam *addr_len = 2; 112146778Ssam *dlci = ((p[0] & 0xFC) << 2) | ((p[1] & 0xF0) >> 4); 11332145Spst 114146778Ssam flags[0] = p[0] & 0x02; /* populate the first flag fields */ 115146778Ssam flags[1] = p[1] & 0x0c; 116172686Smlaier flags[2] = 0; /* clear the rest of the flags */ 117172686Smlaier flags[3] = 0; 11832145Spst 119146778Ssam if (p[1] & FR_EA_BIT) 120146778Ssam return 0; /* 2-byte Q.922 address */ 12132145Spst 122146778Ssam p += 2; 123146778Ssam (*addr_len)++; /* 3- or 4-byte Q.922 address */ 124146778Ssam if ((p[0] & FR_EA_BIT) == 0) { 125146778Ssam *dlci = (*dlci << 7) | (p[0] >> 1); 126146778Ssam (*addr_len)++; /* 4-byte Q.922 address */ 127146778Ssam p++; 128146778Ssam } 12932145Spst 130146778Ssam if ((p[0] & FR_EA_BIT) == 0) 131146778Ssam return -1; /* more than 4 bytes of Q.922 address? */ 132146778Ssam 133146778Ssam flags[3] = p[0] & 0x02; 134146778Ssam 135190207Srpaulo *dlci = (*dlci << 6) | (p[0] >> 2); 136146778Ssam 137146778Ssam return 0; 13832145Spst} 13932145Spst 140190207Srpaulochar *q922_string(const u_char *p) { 141190207Srpaulo 142190207Srpaulo static u_int dlci, addr_len; 143190207Srpaulo static u_int8_t flags[4]; 144190207Srpaulo static char buffer[sizeof("DLCI xxxxxxxxxx")]; 145190207Srpaulo memset(buffer, 0, sizeof(buffer)); 146190207Srpaulo 147190207Srpaulo if (parse_q922_addr(p, &dlci, &addr_len, flags) == 0){ 148190207Srpaulo snprintf(buffer, sizeof(buffer), "DLCI %u", dlci); 149190207Srpaulo } 150190207Srpaulo 151190207Srpaulo return buffer; 152190207Srpaulo} 153190207Srpaulo 154190207Srpaulo 155146778Ssam/* Frame Relay packet structure, with flags and CRC removed 15632145Spst 15732145Spst +---------------------------+ 15832145Spst | Q.922 Address* | 15932145Spst +-- --+ 16032145Spst | | 16132145Spst +---------------------------+ 16232145Spst | Control (UI = 0x03) | 16332145Spst +---------------------------+ 16432145Spst | Optional Pad (0x00) | 16532145Spst +---------------------------+ 16632145Spst | NLPID | 16732145Spst +---------------------------+ 16832145Spst | . | 16932145Spst | . | 17032145Spst | . | 17132145Spst | Data | 17232145Spst | . | 17332145Spst | . | 17432145Spst +---------------------------+ 17532145Spst 17632145Spst * Q.922 addresses, as presently defined, are two octets and 17732145Spst contain a 10-bit DLCI. In some networks Q.922 addresses 17832145Spst may optionally be increased to three or four octets. 17932145Spst*/ 18032145Spst 181146778Ssamstatic u_int 182147904Ssamfr_hdrlen(const u_char *p, u_int addr_len) 18332145Spst{ 184147904Ssam if (!p[addr_len + 1] /* pad exist */) 185146778Ssam return addr_len + 1 /* UI */ + 1 /* pad */ + 1 /* NLPID */; 18632145Spst else 187146778Ssam return addr_len + 1 /* UI */ + 1 /* NLPID */; 18832145Spst} 18932145Spst 190146778Ssamstatic void 191146778Ssamfr_hdr_print(int length, u_int addr_len, u_int dlci, u_int8_t *flags, u_int16_t nlpid) 19232145Spst{ 193146778Ssam if (qflag) { 194146778Ssam (void)printf("Q.922, DLCI %u, length %u: ", 195146778Ssam dlci, 196146778Ssam length); 197146778Ssam } else { 198146778Ssam if (nlpid <= 0xff) /* if its smaller than 256 then its a NLPID */ 199146778Ssam (void)printf("Q.922, hdr-len %u, DLCI %u, Flags [%s], NLPID %s (0x%02x), length %u: ", 200146778Ssam addr_len, 201146778Ssam dlci, 202146778Ssam bittok2str(fr_header_flag_values, "none", EXTRACT_32BITS(flags)), 203146778Ssam tok2str(nlpid_values,"unknown", nlpid), 204146778Ssam nlpid, 205146778Ssam length); 206146778Ssam else /* must be an ethertype */ 207146778Ssam (void)printf("Q.922, hdr-len %u, DLCI %u, Flags [%s], cisco-ethertype %s (0x%04x), length %u: ", 208146778Ssam addr_len, 209146778Ssam dlci, 210146778Ssam bittok2str(fr_header_flag_values, "none", EXTRACT_32BITS(flags)), 211146778Ssam tok2str(ethertype_values, "unknown", nlpid), 212146778Ssam nlpid, 213146778Ssam length); 214146778Ssam } 21532145Spst} 21632145Spst 217146778Ssamu_int 218146778Ssamfr_if_print(const struct pcap_pkthdr *h, register const u_char *p) 21932145Spst{ 22032145Spst register u_int length = h->len; 22132145Spst register u_int caplen = h->caplen; 222147904Ssam 223147904Ssam TCHECK2(*p, 4); /* minimum frame header length */ 224147904Ssam 225147904Ssam if ((length = fr_print(p, length)) == 0) 226147904Ssam return (0); 227147904Ssam else 228147904Ssam return length; 229147904Ssam trunc: 230147904Ssam printf("[|fr]"); 231147904Ssam return caplen; 232147904Ssam} 233147904Ssam 234147904Ssamu_int 235147904Ssamfr_print(register const u_char *p, u_int length) 236147904Ssam{ 237146778Ssam u_int16_t extracted_ethertype; 238146778Ssam u_int dlci; 239146778Ssam u_int addr_len; 240146778Ssam u_int16_t nlpid; 241146778Ssam u_int hdr_len; 242146778Ssam u_int8_t flags[4]; 24332145Spst 244190207Srpaulo if (parse_q922_addr(p, &dlci, &addr_len, flags)) { 245146778Ssam printf("Q.922, invalid address"); 246147904Ssam return 0; 247146778Ssam } 24832145Spst 249147904Ssam TCHECK2(*p,addr_len+1+1); 250147904Ssam hdr_len = fr_hdrlen(p, addr_len); 251147904Ssam TCHECK2(*p,hdr_len); 252146778Ssam 253146778Ssam if (p[addr_len] != 0x03 && dlci != 0) { 25432145Spst 255146778Ssam /* lets figure out if we have cisco style encapsulation: */ 256146778Ssam extracted_ethertype = EXTRACT_16BITS(p+addr_len); 257146778Ssam 258146778Ssam if (eflag) 259146778Ssam fr_hdr_print(length, addr_len, dlci, flags, extracted_ethertype); 260146778Ssam 261146778Ssam if (ether_encap_print(extracted_ethertype, 262146778Ssam p+addr_len+ETHERTYPE_LEN, 263146778Ssam length-addr_len-ETHERTYPE_LEN, 264147904Ssam length-addr_len-ETHERTYPE_LEN, 265146778Ssam &extracted_ethertype) == 0) 266146778Ssam /* ether_type not known, probably it wasn't one */ 267146778Ssam printf("UI %02x! ", p[addr_len]); 268146778Ssam else 269146778Ssam return hdr_len; 270146778Ssam } 271146778Ssam 272146778Ssam if (!p[addr_len + 1]) { /* pad byte should be used with 3-byte Q.922 */ 273146778Ssam if (addr_len != 3) 274146778Ssam printf("Pad! "); 275146778Ssam } else if (addr_len == 3) 276146778Ssam printf("No pad! "); 277146778Ssam 278146778Ssam nlpid = p[hdr_len - 1]; 279146778Ssam 28032145Spst if (eflag) 281146778Ssam fr_hdr_print(length, addr_len, dlci, flags, nlpid); 282146778Ssam p += hdr_len; 283146778Ssam length -= hdr_len; 28432145Spst 285146778Ssam switch (nlpid) { 28632145Spst case NLPID_IP: 287146778Ssam ip_print(gndo, p, length); 28832145Spst break; 289146778Ssam 290146778Ssam#ifdef INET6 291146778Ssam case NLPID_IP6: 292146778Ssam ip6_print(p, length); 293146778Ssam break; 294146778Ssam#endif 29532145Spst case NLPID_CLNP: 29632145Spst case NLPID_ESIS: 29732145Spst case NLPID_ISIS: 298147904Ssam isoclns_print(p-1, length+1, length+1); /* OSI printers need the NLPID field */ 29932145Spst break; 300146778Ssam 301146778Ssam case NLPID_SNAP: 302147904Ssam if (snap_print(p, length, length, &extracted_ethertype, 0) == 0) { 303146778Ssam /* ether_type not known, print raw packet */ 304146778Ssam if (!eflag) 305146778Ssam fr_hdr_print(length + hdr_len, hdr_len, 306146778Ssam dlci, flags, nlpid); 307162021Ssam if (!suppress_default_print) 308147904Ssam default_print(p - hdr_len, length + hdr_len); 309146778Ssam } 31032145Spst break; 311146778Ssam 312146778Ssam case NLPID_Q933: 313146778Ssam q933_print(p, length); 314146778Ssam break; 315146778Ssam 316146778Ssam case NLPID_MFR: 317146778Ssam frf15_print(p, length); 318146778Ssam break; 319146778Ssam 320172686Smlaier case NLPID_PPP: 321172686Smlaier ppp_print(p, length); 322172686Smlaier break; 323172686Smlaier 32432145Spst default: 325146778Ssam if (!eflag) 326146778Ssam fr_hdr_print(length + hdr_len, addr_len, 327146778Ssam dlci, flags, nlpid); 328146778Ssam if (!xflag) 329147904Ssam default_print(p, length); 33032145Spst } 33132145Spst 332146778Ssam return hdr_len; 333147904Ssam 334147904Ssam trunc: 335147904Ssam printf("[|fr]"); 336147904Ssam return 0; 337147904Ssam 33832145Spst} 33932145Spst 340172686Smlaieru_int 341172686Smlaiermfr_if_print(const struct pcap_pkthdr *h, register const u_char *p) 342172686Smlaier{ 343172686Smlaier register u_int length = h->len; 344172686Smlaier register u_int caplen = h->caplen; 345172686Smlaier 346172686Smlaier TCHECK2(*p, 2); /* minimum frame header length */ 347172686Smlaier 348172686Smlaier if ((length = mfr_print(p, length)) == 0) 349172686Smlaier return (0); 350172686Smlaier else 351172686Smlaier return length; 352172686Smlaier trunc: 353172686Smlaier printf("[|mfr]"); 354172686Smlaier return caplen; 355172686Smlaier} 356172686Smlaier 357172686Smlaier 358162021Ssam#define MFR_CTRL_MSG_ADD_LINK 1 359162021Ssam#define MFR_CTRL_MSG_ADD_LINK_ACK 2 360162021Ssam#define MFR_CTRL_MSG_ADD_LINK_REJ 3 361162021Ssam#define MFR_CTRL_MSG_HELLO 4 362162021Ssam#define MFR_CTRL_MSG_HELLO_ACK 5 363162021Ssam#define MFR_CTRL_MSG_REMOVE_LINK 6 364162021Ssam#define MFR_CTRL_MSG_REMOVE_LINK_ACK 7 365162021Ssam 366162021Ssamstruct tok mfr_ctrl_msg_values[] = { 367162021Ssam { MFR_CTRL_MSG_ADD_LINK, "Add Link" }, 368162021Ssam { MFR_CTRL_MSG_ADD_LINK_ACK, "Add Link ACK" }, 369162021Ssam { MFR_CTRL_MSG_ADD_LINK_REJ, "Add Link Reject" }, 370162021Ssam { MFR_CTRL_MSG_HELLO, "Hello" }, 371162021Ssam { MFR_CTRL_MSG_HELLO_ACK, "Hello ACK" }, 372162021Ssam { MFR_CTRL_MSG_REMOVE_LINK, "Remove Link" }, 373162021Ssam { MFR_CTRL_MSG_REMOVE_LINK_ACK, "Remove Link ACK" }, 374162021Ssam { 0, NULL } 375162021Ssam}; 376162021Ssam 377162021Ssam#define MFR_CTRL_IE_BUNDLE_ID 1 378162021Ssam#define MFR_CTRL_IE_LINK_ID 2 379162021Ssam#define MFR_CTRL_IE_MAGIC_NUM 3 380162021Ssam#define MFR_CTRL_IE_TIMESTAMP 5 381162021Ssam#define MFR_CTRL_IE_VENDOR_EXT 6 382162021Ssam#define MFR_CTRL_IE_CAUSE 7 383162021Ssam 384162021Ssamstruct tok mfr_ctrl_ie_values[] = { 385162021Ssam { MFR_CTRL_IE_BUNDLE_ID, "Bundle ID"}, 386162021Ssam { MFR_CTRL_IE_LINK_ID, "Link ID"}, 387162021Ssam { MFR_CTRL_IE_MAGIC_NUM, "Magic Number"}, 388162021Ssam { MFR_CTRL_IE_TIMESTAMP, "Timestamp"}, 389162021Ssam { MFR_CTRL_IE_VENDOR_EXT, "Vendor Extension"}, 390162021Ssam { MFR_CTRL_IE_CAUSE, "Cause"}, 391162021Ssam { 0, NULL } 392162021Ssam}; 393162021Ssam 394162021Ssam#define MFR_ID_STRING_MAXLEN 50 395162021Ssam 396162021Ssamstruct ie_tlv_header_t { 397162021Ssam u_int8_t ie_type; 398162021Ssam u_int8_t ie_len; 399162021Ssam}; 400162021Ssam 401162021Ssamu_int 402162021Ssammfr_print(register const u_char *p, u_int length) 403162021Ssam{ 404162021Ssam u_int tlen,idx,hdr_len = 0; 405162021Ssam u_int16_t sequence_num; 406162021Ssam u_int8_t ie_type,ie_len; 407162021Ssam const u_int8_t *tptr; 408162021Ssam 409162021Ssam 410162021Ssam/* 411162021Ssam * FRF.16 Link Integrity Control Frame 412162021Ssam * 413162021Ssam * 7 6 5 4 3 2 1 0 414162021Ssam * +----+----+----+----+----+----+----+----+ 415162021Ssam * | B | E | C=1| 0 0 0 0 | EA | 416162021Ssam * +----+----+----+----+----+----+----+----+ 417162021Ssam * | 0 0 0 0 0 0 0 0 | 418162021Ssam * +----+----+----+----+----+----+----+----+ 419162021Ssam * | message type | 420162021Ssam * +----+----+----+----+----+----+----+----+ 421162021Ssam */ 422162021Ssam 423162021Ssam TCHECK2(*p, 4); /* minimum frame header length */ 424162021Ssam 425162021Ssam if ((p[0] & MFR_BEC_MASK) == MFR_CTRL_FRAME && p[1] == 0) { 426162021Ssam printf("FRF.16 Control, Flags [%s], %s, length %u", 427162021Ssam bittok2str(frf_flag_values,"none",(p[0] & MFR_BEC_MASK)), 428162021Ssam tok2str(mfr_ctrl_msg_values,"Unknown Message (0x%02x)",p[2]), 429162021Ssam length); 430162021Ssam tptr = p + 3; 431162021Ssam tlen = length -3; 432162021Ssam hdr_len = 3; 433162021Ssam 434162021Ssam if (!vflag) 435162021Ssam return hdr_len; 436162021Ssam 437162021Ssam while (tlen>sizeof(struct ie_tlv_header_t)) { 438162021Ssam TCHECK2(*tptr, sizeof(struct ie_tlv_header_t)); 439162021Ssam ie_type=tptr[0]; 440162021Ssam ie_len=tptr[1]; 441162021Ssam 442162021Ssam printf("\n\tIE %s (%u), length %u: ", 443162021Ssam tok2str(mfr_ctrl_ie_values,"Unknown",ie_type), 444162021Ssam ie_type, 445162021Ssam ie_len); 446162021Ssam 447162021Ssam /* infinite loop check */ 448162021Ssam if (ie_type == 0 || ie_len <= sizeof(struct ie_tlv_header_t)) 449162021Ssam return hdr_len; 450162021Ssam 451162021Ssam TCHECK2(*tptr,ie_len); 452162021Ssam tptr+=sizeof(struct ie_tlv_header_t); 453162021Ssam /* tlv len includes header */ 454162021Ssam ie_len-=sizeof(struct ie_tlv_header_t); 455162021Ssam tlen-=sizeof(struct ie_tlv_header_t); 456162021Ssam 457162021Ssam switch (ie_type) { 458162021Ssam 459162021Ssam case MFR_CTRL_IE_MAGIC_NUM: 460162021Ssam printf("0x%08x",EXTRACT_32BITS(tptr)); 461162021Ssam break; 462162021Ssam 463162021Ssam case MFR_CTRL_IE_BUNDLE_ID: /* same message format */ 464162021Ssam case MFR_CTRL_IE_LINK_ID: 465162021Ssam for (idx = 0; idx < ie_len && idx < MFR_ID_STRING_MAXLEN; idx++) { 466162021Ssam if (*(tptr+idx) != 0) /* don't print null termination */ 467162021Ssam safeputchar(*(tptr+idx)); 468162021Ssam else 469162021Ssam break; 470162021Ssam } 471162021Ssam break; 472162021Ssam 473162021Ssam case MFR_CTRL_IE_TIMESTAMP: 474162021Ssam if (ie_len == sizeof(struct timeval)) { 475162021Ssam ts_print((const struct timeval *)tptr); 476162021Ssam break; 477162021Ssam } 478162021Ssam /* fall through and hexdump if no unix timestamp */ 479162021Ssam 480162021Ssam /* 481162021Ssam * FIXME those are the defined IEs that lack a decoder 482162021Ssam * you are welcome to contribute code ;-) 483162021Ssam */ 484162021Ssam 485162021Ssam case MFR_CTRL_IE_VENDOR_EXT: 486162021Ssam case MFR_CTRL_IE_CAUSE: 487162021Ssam 488162021Ssam default: 489162021Ssam if (vflag <= 1) 490162021Ssam print_unknown_data(tptr,"\n\t ",ie_len); 491162021Ssam break; 492162021Ssam } 493162021Ssam 494162021Ssam /* do we want to see a hexdump of the IE ? */ 495162021Ssam if (vflag > 1 ) 496162021Ssam print_unknown_data(tptr,"\n\t ",ie_len); 497162021Ssam 498162021Ssam tlen-=ie_len; 499162021Ssam tptr+=ie_len; 500162021Ssam } 501162021Ssam return hdr_len; 502162021Ssam } 503162021Ssam/* 504162021Ssam * FRF.16 Fragmentation Frame 505162021Ssam * 506162021Ssam * 7 6 5 4 3 2 1 0 507162021Ssam * +----+----+----+----+----+----+----+----+ 508162021Ssam * | B | E | C=0|seq. (high 4 bits) | EA | 509162021Ssam * +----+----+----+----+----+----+----+----+ 510162021Ssam * | sequence (low 8 bits) | 511162021Ssam * +----+----+----+----+----+----+----+----+ 512162021Ssam * | DLCI (6 bits) | CR | EA | 513162021Ssam * +----+----+----+----+----+----+----+----+ 514162021Ssam * | DLCI (4 bits) |FECN|BECN| DE | EA | 515162021Ssam * +----+----+----+----+----+----+----+----+ 516162021Ssam */ 517162021Ssam 518162021Ssam sequence_num = (p[0]&0x1e)<<7 | p[1]; 519162021Ssam /* whole packet or first fragment ? */ 520162021Ssam if ((p[0] & MFR_BEC_MASK) == MFR_FRAG_FRAME || 521162021Ssam (p[0] & MFR_BEC_MASK) == MFR_B_BIT) { 522162021Ssam printf("FRF.16 Frag, seq %u, Flags [%s], ", 523162021Ssam sequence_num, 524162021Ssam bittok2str(frf_flag_values,"none",(p[0] & MFR_BEC_MASK))); 525162021Ssam hdr_len = 2; 526162021Ssam fr_print(p+hdr_len,length-hdr_len); 527162021Ssam return hdr_len; 528162021Ssam } 529162021Ssam 530162021Ssam /* must be a middle or the last fragment */ 531162021Ssam printf("FRF.16 Frag, seq %u, Flags [%s]", 532162021Ssam sequence_num, 533162021Ssam bittok2str(frf_flag_values,"none",(p[0] & MFR_BEC_MASK))); 534162021Ssam print_unknown_data(p,"\n\t",length); 535162021Ssam 536162021Ssam return hdr_len; 537162021Ssam 538162021Ssam trunc: 539162021Ssam printf("[|mfr]"); 540162021Ssam return length; 541162021Ssam} 542162021Ssam 543146778Ssam/* an NLPID of 0xb1 indicates a 2-byte 544146778Ssam * FRF.15 header 545146778Ssam * 546146778Ssam * 7 6 5 4 3 2 1 0 547146778Ssam * +----+----+----+----+----+----+----+----+ 548146778Ssam * ~ Q.922 header ~ 549146778Ssam * +----+----+----+----+----+----+----+----+ 550146778Ssam * | NLPID (8 bits) | NLPID=0xb1 551146778Ssam * +----+----+----+----+----+----+----+----+ 552146778Ssam * | B | E | C |seq. (high 4 bits) | R | 553146778Ssam * +----+----+----+----+----+----+----+----+ 554146778Ssam * | sequence (low 8 bits) | 555146778Ssam * +----+----+----+----+----+----+----+----+ 556146778Ssam */ 55732145Spst 558146778Ssam#define FR_FRF15_FRAGTYPE 0x01 559146778Ssam 560146778Ssamstatic void 561146778Ssamfrf15_print (const u_char *p, u_int length) { 562146778Ssam 563146778Ssam u_int16_t sequence_num, flags; 564146778Ssam 565162021Ssam flags = p[0]&MFR_BEC_MASK; 566146778Ssam sequence_num = (p[0]&0x1e)<<7 | p[1]; 567146778Ssam 568146778Ssam printf("FRF.15, seq 0x%03x, Flags [%s],%s Fragmentation, length %u", 569146778Ssam sequence_num, 570162021Ssam bittok2str(frf_flag_values,"none",flags), 571162021Ssam p[0]&FR_FRF15_FRAGTYPE ? "Interface" : "End-to-End", 572146778Ssam length); 573146778Ssam 574146778Ssam/* TODO: 575146778Ssam * depending on all permutations of the B, E and C bit 576146778Ssam * dig as deep as we can - e.g. on the first (B) fragment 577146778Ssam * there is enough payload to print the IP header 578146778Ssam * on non (B) fragments it depends if the fragmentation 579146778Ssam * model is end-to-end or interface based wether we want to print 580146778Ssam * another Q.922 header 581146778Ssam */ 582146778Ssam 58332145Spst} 58432145Spst 58532145Spst/* 58632145Spst * Q.933 decoding portion for framerelay specific. 58732145Spst */ 58832145Spst 58932145Spst/* Q.933 packet format 59032145Spst Format of Other Protocols 59132145Spst using Q.933 NLPID 59232145Spst +-------------------------------+ 59332145Spst | Q.922 Address | 59432145Spst +---------------+---------------+ 59532145Spst |Control 0x03 | NLPID 0x08 | 59632145Spst +---------------+---------------+ 59732145Spst | L2 Protocol ID | 59832145Spst | octet 1 | octet 2 | 59932145Spst +-------------------------------+ 60032145Spst | L3 Protocol ID | 60132145Spst | octet 2 | octet 2 | 60232145Spst +-------------------------------+ 60332145Spst | Protocol Data | 60432145Spst +-------------------------------+ 60532145Spst | FCS | 60632145Spst +-------------------------------+ 60732145Spst */ 60832145Spst 60932145Spst/* L2 (Octet 1)- Call Reference Usually is 0x0 */ 61032145Spst 61132145Spst/* 61232145Spst * L2 (Octet 2)- Message Types definition 1 byte long. 61332145Spst */ 61432145Spst/* Call Establish */ 61532145Spst#define MSG_TYPE_ESC_TO_NATIONAL 0x00 61632145Spst#define MSG_TYPE_ALERT 0x01 61732145Spst#define MSG_TYPE_CALL_PROCEEDING 0x02 61832145Spst#define MSG_TYPE_CONNECT 0x07 61932145Spst#define MSG_TYPE_CONNECT_ACK 0x0F 62032145Spst#define MSG_TYPE_PROGRESS 0x03 62132145Spst#define MSG_TYPE_SETUP 0x05 62232145Spst/* Call Clear */ 62332145Spst#define MSG_TYPE_DISCONNECT 0x45 62432145Spst#define MSG_TYPE_RELEASE 0x4D 62532145Spst#define MSG_TYPE_RELEASE_COMPLETE 0x5A 62632145Spst#define MSG_TYPE_RESTART 0x46 62732145Spst#define MSG_TYPE_RESTART_ACK 0x4E 62832145Spst/* Status */ 62932145Spst#define MSG_TYPE_STATUS 0x7D 63032145Spst#define MSG_TYPE_STATUS_ENQ 0x75 63132145Spst 632146778Ssamstruct tok fr_q933_msg_values[] = { 633146778Ssam { MSG_TYPE_ESC_TO_NATIONAL, "ESC to National" }, 634146778Ssam { MSG_TYPE_ALERT, "Alert" }, 635146778Ssam { MSG_TYPE_CALL_PROCEEDING, "Call proceeding" }, 636146778Ssam { MSG_TYPE_CONNECT, "Connect" }, 637146778Ssam { MSG_TYPE_CONNECT_ACK, "Connect ACK" }, 638146778Ssam { MSG_TYPE_PROGRESS, "Progress" }, 639146778Ssam { MSG_TYPE_SETUP, "Setup" }, 640146778Ssam { MSG_TYPE_DISCONNECT, "Disconnect" }, 641146778Ssam { MSG_TYPE_RELEASE, "Release" }, 642146778Ssam { MSG_TYPE_RELEASE_COMPLETE, "Release Complete" }, 643146778Ssam { MSG_TYPE_RESTART, "Restart" }, 644146778Ssam { MSG_TYPE_RESTART_ACK, "Restart ACK" }, 645146778Ssam { MSG_TYPE_STATUS, "Status Reply" }, 646146778Ssam { MSG_TYPE_STATUS_ENQ, "Status Enquiry" }, 647146778Ssam { 0, NULL } 648146778Ssam}; 64932145Spst 650146778Ssam#define MSG_ANSI_LOCKING_SHIFT 0x95 651146778Ssam 652146778Ssam#define FR_LMI_ANSI_REPORT_TYPE_IE 0x01 653146778Ssam#define FR_LMI_ANSI_LINK_VERIFY_IE_91 0x19 /* details? */ 654146778Ssam#define FR_LMI_ANSI_LINK_VERIFY_IE 0x03 655146778Ssam#define FR_LMI_ANSI_PVC_STATUS_IE 0x07 656146778Ssam 657146778Ssam#define FR_LMI_CCITT_REPORT_TYPE_IE 0x51 658146778Ssam#define FR_LMI_CCITT_LINK_VERIFY_IE 0x53 659146778Ssam#define FR_LMI_CCITT_PVC_STATUS_IE 0x57 660146778Ssam 661146778Ssamstruct tok fr_q933_ie_values_codeset5[] = { 662146778Ssam { FR_LMI_ANSI_REPORT_TYPE_IE, "ANSI Report Type" }, 663146778Ssam { FR_LMI_ANSI_LINK_VERIFY_IE_91, "ANSI Link Verify" }, 664146778Ssam { FR_LMI_ANSI_LINK_VERIFY_IE, "ANSI Link Verify" }, 665146778Ssam { FR_LMI_ANSI_PVC_STATUS_IE, "ANSI PVC Status" }, 666146778Ssam { FR_LMI_CCITT_REPORT_TYPE_IE, "CCITT Report Type" }, 667146778Ssam { FR_LMI_CCITT_LINK_VERIFY_IE, "CCITT Link Verify" }, 668146778Ssam { FR_LMI_CCITT_PVC_STATUS_IE, "CCITT PVC Status" }, 669146778Ssam { 0, NULL } 67032145Spst}; 67132145Spst 672146778Ssam#define FR_LMI_REPORT_TYPE_IE_FULL_STATUS 0 673146778Ssam#define FR_LMI_REPORT_TYPE_IE_LINK_VERIFY 1 674146778Ssam#define FR_LMI_REPORT_TYPE_IE_ASYNC_PVC 2 67532145Spst 676146778Ssamstruct tok fr_lmi_report_type_ie_values[] = { 677146778Ssam { FR_LMI_REPORT_TYPE_IE_FULL_STATUS, "Full Status" }, 678146778Ssam { FR_LMI_REPORT_TYPE_IE_LINK_VERIFY, "Link verify" }, 679146778Ssam { FR_LMI_REPORT_TYPE_IE_ASYNC_PVC, "Async PVC Status" }, 680146778Ssam { 0, NULL } 681146778Ssam}; 68232145Spst 683162021Ssam/* array of 16 codepages - currently we only support codepage 1,5 */ 684146778Ssamstatic struct tok *fr_q933_ie_codesets[] = { 685146778Ssam NULL, 686162021Ssam fr_q933_ie_values_codeset5, 687146778Ssam NULL, 688146778Ssam NULL, 689146778Ssam NULL, 690146778Ssam fr_q933_ie_values_codeset5, 691146778Ssam NULL, 692146778Ssam NULL, 693146778Ssam NULL, 694146778Ssam NULL, 695146778Ssam NULL, 696146778Ssam NULL, 697146778Ssam NULL, 698146778Ssam NULL, 699146778Ssam NULL, 700146778Ssam NULL 70132145Spst}; 70232145Spst 703162021Ssamstatic int fr_q933_print_ie_codeset5(const struct ie_tlv_header_t *ie_p, 704147904Ssam const u_char *p); 705147904Ssam 706162021Ssamtypedef int (*codeset_pr_func_t)(const struct ie_tlv_header_t *ie_p, 707147904Ssam const u_char *p); 708147904Ssam 709162021Ssam/* array of 16 codepages - currently we only support codepage 1,5 */ 710147904Ssamstatic codeset_pr_func_t fr_q933_print_ie_codeset[] = { 711147904Ssam NULL, 712162021Ssam fr_q933_print_ie_codeset5, 713147904Ssam NULL, 714147904Ssam NULL, 715147904Ssam NULL, 716147904Ssam fr_q933_print_ie_codeset5, 717147904Ssam NULL, 718147904Ssam NULL, 719147904Ssam NULL, 720147904Ssam NULL, 721147904Ssam NULL, 722147904Ssam NULL, 723147904Ssam NULL, 724147904Ssam NULL, 725147904Ssam NULL, 726147904Ssam NULL 727147904Ssam}; 728147904Ssam 72932145Spstvoid 730146778Ssamq933_print(const u_char *p, u_int length) 73132145Spst{ 73232145Spst const u_char *ptemp = p; 733162021Ssam struct ie_tlv_header_t *ie_p; 734146778Ssam int olen; 735146778Ssam int is_ansi = 0; 736147904Ssam u_int codeset; 737162021Ssam u_int ie_is_known = 0; 738146778Ssam 739146778Ssam if (length < 9) { /* shortest: Q.933a LINK VERIFY */ 740146778Ssam printf("[|q.933]"); 741146778Ssam return; 742146778Ssam } 743146778Ssam 744146778Ssam codeset = p[2]&0x0f; /* extract the codeset */ 745146778Ssam 746190207Srpaulo if (p[2] == MSG_ANSI_LOCKING_SHIFT) { 747190207Srpaulo is_ansi = 1; 748190207Srpaulo } 74932145Spst 750146778Ssam printf("%s", eflag ? "" : "Q.933, "); 75132145Spst 75232145Spst /* printing out header part */ 753162021Ssam printf("%s, codeset %u", is_ansi ? "ANSI" : "CCITT", codeset); 754146778Ssam 755190207Srpaulo if (p[0]) { 756190207Srpaulo printf(", Call Ref: 0x%02x", p[0]); 757190207Srpaulo } 758190207Srpaulo if (vflag) { 759190207Srpaulo printf(", %s (0x%02x), length %u", 760190207Srpaulo tok2str(fr_q933_msg_values, 761190207Srpaulo "unknown message", p[1]), 762190207Srpaulo p[1], 763190207Srpaulo length); 764190207Srpaulo } else { 765190207Srpaulo printf(", %s", 766190207Srpaulo tok2str(fr_q933_msg_values, 767190207Srpaulo "unknown message 0x%02x", p[1])); 768190207Srpaulo } 769146778Ssam 770146778Ssam olen = length; /* preserve the original length for non verbose mode */ 771146778Ssam 772146778Ssam if (length < (u_int)(2 - is_ansi)) { 773146778Ssam printf("[|q.933]"); 774146778Ssam return; 77532145Spst } 776190207Srpaulo length -= 2 + is_ansi; 777146778Ssam ptemp += 2 + is_ansi; 77832145Spst 77932145Spst /* Loop through the rest of IE */ 780190207Srpaulo while (length > sizeof(struct ie_tlv_header_t)) { 781162021Ssam ie_p = (struct ie_tlv_header_t *)ptemp; 782190207Srpaulo if (length < sizeof(struct ie_tlv_header_t) || 783190207Srpaulo length < sizeof(struct ie_tlv_header_t) + ie_p->ie_len) { 784190207Srpaulo if (vflag) { /* not bark if there is just a trailer */ 785146778Ssam printf("\n[|q.933]"); 786190207Srpaulo } else { 787146778Ssam printf(", length %u",olen); 788190207Srpaulo } 789146778Ssam return; 79032145Spst } 79132145Spst 792146778Ssam /* lets do the full IE parsing only in verbose mode 793146778Ssam * however some IEs (DLCI Status, Link Verify) 794190207Srpaulo * are also interestting in non-verbose mode */ 795190207Srpaulo if (vflag) { 796162021Ssam printf("\n\t%s IE (0x%02x), length %u: ", 797190207Srpaulo tok2str(fr_q933_ie_codesets[codeset], 798190207Srpaulo "unknown", ie_p->ie_type), 799162021Ssam ie_p->ie_type, 800146778Ssam ie_p->ie_len); 801190207Srpaulo } 802190207Srpaulo 803162021Ssam /* sanity check */ 804190207Srpaulo if (ie_p->ie_type == 0 || ie_p->ie_len == 0) { 805162021Ssam return; 806190207Srpaulo } 80732145Spst 808190207Srpaulo if (fr_q933_print_ie_codeset[codeset] != NULL) { 809162021Ssam ie_is_known = fr_q933_print_ie_codeset[codeset](ie_p, ptemp); 810190207Srpaulo } 811190207Srpaulo 812190207Srpaulo if (vflag >= 1 && !ie_is_known) { 813162021Ssam print_unknown_data(ptemp+2,"\n\t",ie_p->ie_len); 814190207Srpaulo } 815162021Ssam 816146778Ssam /* do we want to see a hexdump of the IE ? */ 817190207Srpaulo if (vflag> 1 && ie_is_known) { 818146778Ssam print_unknown_data(ptemp+2,"\n\t ",ie_p->ie_len); 819190207Srpaulo } 82032145Spst 821146778Ssam length = length - ie_p->ie_len - 2; 822146778Ssam ptemp = ptemp + ie_p->ie_len + 2; 823146778Ssam } 824190207Srpaulo if (!vflag) { 825146778Ssam printf(", length %u",olen); 826190207Srpaulo } 827146778Ssam} 828147904Ssam 829147904Ssamstatic int 830162021Ssamfr_q933_print_ie_codeset5(const struct ie_tlv_header_t *ie_p, const u_char *p) 831147904Ssam{ 832147904Ssam u_int dlci; 833147904Ssam 834162021Ssam switch (ie_p->ie_type) { 835147904Ssam 836147904Ssam case FR_LMI_ANSI_REPORT_TYPE_IE: /* fall through */ 837147904Ssam case FR_LMI_CCITT_REPORT_TYPE_IE: 838190207Srpaulo if (vflag) { 839147904Ssam printf("%s (%u)", 840147904Ssam tok2str(fr_lmi_report_type_ie_values,"unknown",p[2]), 841147904Ssam p[2]); 842190207Srpaulo } 843147904Ssam return 1; 844147904Ssam 845147904Ssam case FR_LMI_ANSI_LINK_VERIFY_IE: /* fall through */ 846147904Ssam case FR_LMI_CCITT_LINK_VERIFY_IE: 847147904Ssam case FR_LMI_ANSI_LINK_VERIFY_IE_91: 848190207Srpaulo if (!vflag) { 849147904Ssam printf(", "); 850190207Srpaulo } 851147904Ssam printf("TX Seq: %3d, RX Seq: %3d", p[2], p[3]); 852147904Ssam return 1; 853147904Ssam 854147904Ssam case FR_LMI_ANSI_PVC_STATUS_IE: /* fall through */ 855147904Ssam case FR_LMI_CCITT_PVC_STATUS_IE: 856190207Srpaulo if (!vflag) { 857147904Ssam printf(", "); 858190207Srpaulo } 859147904Ssam /* now parse the DLCI information element. */ 860147904Ssam if ((ie_p->ie_len < 3) || 861147904Ssam (p[2] & 0x80) || 862147904Ssam ((ie_p->ie_len == 3) && !(p[3] & 0x80)) || 863147904Ssam ((ie_p->ie_len == 4) && ((p[3] & 0x80) || !(p[4] & 0x80))) || 864147904Ssam ((ie_p->ie_len == 5) && ((p[3] & 0x80) || (p[4] & 0x80) || 865147904Ssam !(p[5] & 0x80))) || 866147904Ssam (ie_p->ie_len > 5) || 867190207Srpaulo !(p[ie_p->ie_len + 1] & 0x80)) { 868147904Ssam printf("Invalid DLCI IE"); 869190207Srpaulo } 870147904Ssam 871147904Ssam dlci = ((p[2] & 0x3F) << 4) | ((p[3] & 0x78) >> 3); 872190207Srpaulo if (ie_p->ie_len == 4) { 873147904Ssam dlci = (dlci << 6) | ((p[4] & 0x7E) >> 1); 874190207Srpaulo } 875190207Srpaulo else if (ie_p->ie_len == 5) { 876147904Ssam dlci = (dlci << 13) | (p[4] & 0x7F) | ((p[5] & 0x7E) >> 1); 877190207Srpaulo } 878147904Ssam 879147904Ssam printf("DLCI %u: status %s%s", dlci, 880147904Ssam p[ie_p->ie_len + 1] & 0x8 ? "New, " : "", 881147904Ssam p[ie_p->ie_len + 1] & 0x2 ? "Active" : "Inactive"); 882147904Ssam return 1; 883147904Ssam } 884147904Ssam 885147904Ssam return 0; 886147904Ssam} 887