10f74e101Schristos /* 20f74e101Schristos * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996 30f74e101Schristos * The Regents of the University of California. All rights reserved. 40f74e101Schristos * 50f74e101Schristos * Redistribution and use in source and binary forms, with or without 60f74e101Schristos * modification, are permitted provided that: (1) source code distributions 70f74e101Schristos * retain the above copyright notice and this paragraph in its entirety, (2) 80f74e101Schristos * distributions including binary code include the above copyright notice and 90f74e101Schristos * this paragraph in its entirety in the documentation or other materials 100f74e101Schristos * provided with the distribution, and (3) all advertising materials mentioning 110f74e101Schristos * features or use of this software display the following acknowledgement: 120f74e101Schristos * ``This product includes software developed by the University of California, 130f74e101Schristos * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 140f74e101Schristos * the University nor the names of its contributors may be used to endorse 150f74e101Schristos * or promote products derived from this software without specific prior 160f74e101Schristos * written permission. 170f74e101Schristos * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 180f74e101Schristos * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 190f74e101Schristos * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 200f74e101Schristos */ 210f74e101Schristos 2211b3aaa1Schristos #include <sys/cdefs.h> 230f74e101Schristos #ifndef lint 24*26ba0b50Schristos __RCSID("$NetBSD: print-fr.c,v 1.12 2024/09/02 16:15:31 christos Exp $"); 250f74e101Schristos #endif 260f74e101Schristos 27dc860a36Sspz /* \summary: Frame Relay printer */ 28dc860a36Sspz 29c74ad251Schristos #include <config.h> 300f74e101Schristos 31c74ad251Schristos #include "netdissect-stdinc.h" 320f74e101Schristos 330f74e101Schristos #include <stdio.h> 340f74e101Schristos #include <string.h> 350f74e101Schristos 36fdccd7e4Schristos #include "netdissect.h" 37b3a00663Schristos #include "addrtoname.h" 380f74e101Schristos #include "ethertype.h" 39ba2ff121Schristos #include "llc.h" 400f74e101Schristos #include "nlpid.h" 410f74e101Schristos #include "extract.h" 420f74e101Schristos 43b3a00663Schristos static void frf15_print(netdissect_options *ndo, const u_char *, u_int); 440f74e101Schristos 450f74e101Schristos /* 460f74e101Schristos * the frame relay header has a variable length 470f74e101Schristos * 480f74e101Schristos * the EA bit determines if there is another byte 490f74e101Schristos * in the header 500f74e101Schristos * 510f74e101Schristos * minimum header length is 2 bytes 520f74e101Schristos * maximum header length is 4 bytes 530f74e101Schristos * 540f74e101Schristos * 7 6 5 4 3 2 1 0 550f74e101Schristos * +----+----+----+----+----+----+----+----+ 560f74e101Schristos * | DLCI (6 bits) | CR | EA | 570f74e101Schristos * +----+----+----+----+----+----+----+----+ 580f74e101Schristos * | DLCI (4 bits) |FECN|BECN| DE | EA | 590f74e101Schristos * +----+----+----+----+----+----+----+----+ 600f74e101Schristos * | DLCI (7 bits) | EA | 610f74e101Schristos * +----+----+----+----+----+----+----+----+ 620f74e101Schristos * | DLCI (6 bits) |SDLC| EA | 630f74e101Schristos * +----+----+----+----+----+----+----+----+ 640f74e101Schristos */ 650f74e101Schristos 660f74e101Schristos #define FR_EA_BIT 0x01 670f74e101Schristos 680f74e101Schristos #define FR_CR_BIT 0x02000000 690f74e101Schristos #define FR_DE_BIT 0x00020000 700f74e101Schristos #define FR_BECN_BIT 0x00040000 710f74e101Schristos #define FR_FECN_BIT 0x00080000 720f74e101Schristos #define FR_SDLC_BIT 0x00000002 730f74e101Schristos 740f74e101Schristos 75870189d2Schristos static const struct tok fr_header_flag_values[] = { 760f74e101Schristos { FR_CR_BIT, "C!" }, 770f74e101Schristos { FR_DE_BIT, "DE" }, 780f74e101Schristos { FR_BECN_BIT, "BECN" }, 790f74e101Schristos { FR_FECN_BIT, "FECN" }, 800f74e101Schristos { FR_SDLC_BIT, "sdlcore" }, 810f74e101Schristos { 0, NULL } 820f74e101Schristos }; 830f74e101Schristos 840f74e101Schristos /* FRF.15 / FRF.16 */ 850f74e101Schristos #define MFR_B_BIT 0x80 860f74e101Schristos #define MFR_E_BIT 0x40 870f74e101Schristos #define MFR_C_BIT 0x20 880f74e101Schristos #define MFR_BEC_MASK (MFR_B_BIT | MFR_E_BIT | MFR_C_BIT) 890f74e101Schristos #define MFR_CTRL_FRAME (MFR_B_BIT | MFR_E_BIT | MFR_C_BIT) 900f74e101Schristos #define MFR_FRAG_FRAME (MFR_B_BIT | MFR_E_BIT ) 910f74e101Schristos 92870189d2Schristos static const struct tok frf_flag_values[] = { 930f74e101Schristos { MFR_B_BIT, "Begin" }, 940f74e101Schristos { MFR_E_BIT, "End" }, 950f74e101Schristos { MFR_C_BIT, "Control" }, 960f74e101Schristos { 0, NULL } 970f74e101Schristos }; 980f74e101Schristos 99ba2ff121Schristos /* Finds out Q.922 address length, DLCI and flags. Returns 1 on success, 100ba2ff121Schristos * 0 on invalid address, -1 on truncated packet 1010f74e101Schristos * save the flags dep. on address length 1020f74e101Schristos */ 103c74ad251Schristos static int parse_q922_header(netdissect_options *ndo, 104ba2ff121Schristos const u_char *p, u_int *dlci, 105c74ad251Schristos u_int *addr_len, uint32_t *flags, u_int length) 1060f74e101Schristos { 107c74ad251Schristos if (!ND_TTEST_1(p) || length < 1) 1080f74e101Schristos return -1; 109c74ad251Schristos if ((GET_U_1(p) & FR_EA_BIT)) 110ba2ff121Schristos return 0; 1110f74e101Schristos 112c74ad251Schristos if (!ND_TTEST_1(p + 1) || length < 2) 113ba2ff121Schristos return -1; 1140f74e101Schristos *addr_len = 2; 115c74ad251Schristos *dlci = ((GET_U_1(p) & 0xFC) << 2) | ((GET_U_1(p + 1) & 0xF0) >> 4); 1160f74e101Schristos 117c74ad251Schristos *flags = ((GET_U_1(p) & 0x02) << 24) | /* CR flag */ 118c74ad251Schristos ((GET_U_1(p + 1) & 0x0e) << 16); /* FECN,BECN,DE flags */ 1190f74e101Schristos 120c74ad251Schristos if (GET_U_1(p + 1) & FR_EA_BIT) 121ba2ff121Schristos return 1; /* 2-byte Q.922 address */ 1220f74e101Schristos 1230f74e101Schristos p += 2; 124ba2ff121Schristos length -= 2; 125c74ad251Schristos if (!ND_TTEST_1(p) || length < 1) 126ba2ff121Schristos return -1; 1270f74e101Schristos (*addr_len)++; /* 3- or 4-byte Q.922 address */ 128c74ad251Schristos if ((GET_U_1(p) & FR_EA_BIT) == 0) { 129c74ad251Schristos *dlci = (*dlci << 7) | (GET_U_1(p) >> 1); 1300f74e101Schristos (*addr_len)++; /* 4-byte Q.922 address */ 1310f74e101Schristos p++; 132ba2ff121Schristos length--; 1330f74e101Schristos } 1340f74e101Schristos 135c74ad251Schristos if (!ND_TTEST_1(p) || length < 1) 136ba2ff121Schristos return -1; 137c74ad251Schristos if ((GET_U_1(p) & FR_EA_BIT) == 0) 138ba2ff121Schristos return 0; /* more than 4 bytes of Q.922 address? */ 1390f74e101Schristos 140c74ad251Schristos *flags = *flags | (GET_U_1(p) & 0x02); /* SDLC flag */ 1410f74e101Schristos 142c74ad251Schristos *dlci = (*dlci << 6) | (GET_U_1(p) >> 2); 1430f74e101Schristos 144ba2ff121Schristos return 1; 1450f74e101Schristos } 1460f74e101Schristos 147c74ad251Schristos const char * 148ba2ff121Schristos q922_string(netdissect_options *ndo, const u_char *p, u_int length) 149ba2ff121Schristos { 1500f74e101Schristos 1510f74e101Schristos static u_int dlci, addr_len; 152c74ad251Schristos static uint32_t flags; 153c74ad251Schristos static char buffer[sizeof("parse_q922_header() returned XXXXXXXXXXX")]; 154c74ad251Schristos int ret; 1550f74e101Schristos memset(buffer, 0, sizeof(buffer)); 1560f74e101Schristos 157c74ad251Schristos ret = parse_q922_header(ndo, p, &dlci, &addr_len, &flags, length); 158c74ad251Schristos if (ret == 1) { 1590f74e101Schristos snprintf(buffer, sizeof(buffer), "DLCI %u", dlci); 1600f74e101Schristos return buffer; 161c74ad251Schristos } else if (ret == 0) { 162c74ad251Schristos return "<Invalid DLCI>"; 163c74ad251Schristos } else if (ret == -1) { 164c74ad251Schristos return "<Truncated>"; 165c74ad251Schristos } else { 166c74ad251Schristos snprintf(buffer, sizeof(buffer), "parse_q922_header() returned %d", ret); 167c74ad251Schristos return buffer; 168c74ad251Schristos } 1690f74e101Schristos } 1700f74e101Schristos 1710f74e101Schristos 1720f74e101Schristos /* Frame Relay packet structure, with flags and CRC removed 1730f74e101Schristos 1740f74e101Schristos +---------------------------+ 1750f74e101Schristos | Q.922 Address* | 1760f74e101Schristos +-- --+ 1770f74e101Schristos | | 1780f74e101Schristos +---------------------------+ 1790f74e101Schristos | Control (UI = 0x03) | 1800f74e101Schristos +---------------------------+ 1810f74e101Schristos | Optional Pad (0x00) | 1820f74e101Schristos +---------------------------+ 1830f74e101Schristos | NLPID | 1840f74e101Schristos +---------------------------+ 1850f74e101Schristos | . | 1860f74e101Schristos | . | 1870f74e101Schristos | . | 1880f74e101Schristos | Data | 1890f74e101Schristos | . | 1900f74e101Schristos | . | 1910f74e101Schristos +---------------------------+ 1920f74e101Schristos 1930f74e101Schristos * Q.922 addresses, as presently defined, are two octets and 1940f74e101Schristos contain a 10-bit DLCI. In some networks Q.922 addresses 1950f74e101Schristos may optionally be increased to three or four octets. 1960f74e101Schristos */ 1970f74e101Schristos 1980f74e101Schristos static void 199c74ad251Schristos fr_hdr_print(netdissect_options *ndo, int length, u_int addr_len, 200c74ad251Schristos u_int dlci, uint32_t flags, uint16_t nlpid) 2010f74e101Schristos { 202b3a00663Schristos if (ndo->ndo_qflag) { 203c74ad251Schristos ND_PRINT("Q.922, DLCI %u, length %u: ", 2040f74e101Schristos dlci, 205c74ad251Schristos length); 2060f74e101Schristos } else { 2070f74e101Schristos if (nlpid <= 0xff) /* if its smaller than 256 then its a NLPID */ 208c74ad251Schristos ND_PRINT("Q.922, hdr-len %u, DLCI %u, Flags [%s], NLPID %s (0x%02x), length %u: ", 2090f74e101Schristos addr_len, 2100f74e101Schristos dlci, 211c74ad251Schristos bittok2str(fr_header_flag_values, "none", flags), 2120f74e101Schristos tok2str(nlpid_values,"unknown", nlpid), 2130f74e101Schristos nlpid, 214c74ad251Schristos length); 2150f74e101Schristos else /* must be an ethertype */ 216c74ad251Schristos ND_PRINT("Q.922, hdr-len %u, DLCI %u, Flags [%s], cisco-ethertype %s (0x%04x), length %u: ", 2170f74e101Schristos addr_len, 2180f74e101Schristos dlci, 219c74ad251Schristos bittok2str(fr_header_flag_values, "none", flags), 2200f74e101Schristos tok2str(ethertype_values, "unknown", nlpid), 2210f74e101Schristos nlpid, 222c74ad251Schristos length); 2230f74e101Schristos } 2240f74e101Schristos } 2250f74e101Schristos 226c74ad251Schristos /* Frame Relay */ 227c74ad251Schristos void 228b3a00663Schristos fr_if_print(netdissect_options *ndo, 229c74ad251Schristos const struct pcap_pkthdr *h, const u_char *p) 2300f74e101Schristos { 231c74ad251Schristos u_int length = h->len; 232c74ad251Schristos u_int caplen = h->caplen; 2330f74e101Schristos 234c74ad251Schristos ndo->ndo_protocol = "fr"; 235c74ad251Schristos if (caplen < 4) { /* minimum frame header length */ 236c74ad251Schristos nd_print_trunc(ndo); 237c74ad251Schristos ndo->ndo_ll_hdr_len += caplen; 238c74ad251Schristos return; 239c74ad251Schristos } 2400f74e101Schristos 241c74ad251Schristos ndo->ndo_ll_hdr_len += fr_print(ndo, p, length); 2420f74e101Schristos } 2430f74e101Schristos 2440f74e101Schristos u_int 245b3a00663Schristos fr_print(netdissect_options *ndo, 246c74ad251Schristos const u_char *p, u_int length) 2470f74e101Schristos { 248ba2ff121Schristos int ret; 249b3a00663Schristos uint16_t extracted_ethertype; 2500f74e101Schristos u_int dlci; 2510f74e101Schristos u_int addr_len; 252b3a00663Schristos uint16_t nlpid; 2530f74e101Schristos u_int hdr_len; 254c74ad251Schristos uint32_t flags; 2550f74e101Schristos 256c74ad251Schristos ndo->ndo_protocol = "fr"; 257c74ad251Schristos ret = parse_q922_header(ndo, p, &dlci, &addr_len, &flags, length); 258ba2ff121Schristos if (ret == -1) 259ba2ff121Schristos goto trunc; 260ba2ff121Schristos if (ret == 0) { 261c74ad251Schristos ND_PRINT("Q.922, invalid address"); 2620f74e101Schristos return 0; 2630f74e101Schristos } 2640f74e101Schristos 265c74ad251Schristos ND_TCHECK_1(p + addr_len); 266ba2ff121Schristos if (length < addr_len + 1) 267ba2ff121Schristos goto trunc; 2680f74e101Schristos 269c74ad251Schristos if (GET_U_1(p + addr_len) != LLC_UI && dlci != 0) { 270ba2ff121Schristos /* 271ba2ff121Schristos * Let's figure out if we have Cisco-style encapsulation, 272ba2ff121Schristos * with an Ethernet type (Cisco HDLC type?) following the 273ba2ff121Schristos * address. 274ba2ff121Schristos */ 275c74ad251Schristos if (!ND_TTEST_2(p + addr_len) || length < addr_len + 2) { 276ba2ff121Schristos /* no Ethertype */ 277c74ad251Schristos ND_PRINT("UI %02x! ", GET_U_1(p + addr_len)); 278ba2ff121Schristos } else { 279c74ad251Schristos extracted_ethertype = GET_BE_U_2(p + addr_len); 2800f74e101Schristos 281b3a00663Schristos if (ndo->ndo_eflag) 282ba2ff121Schristos fr_hdr_print(ndo, length, addr_len, dlci, 283ba2ff121Schristos flags, extracted_ethertype); 2840f74e101Schristos 285b3a00663Schristos if (ethertype_print(ndo, extracted_ethertype, 2860f74e101Schristos p+addr_len+ETHERTYPE_LEN, 2870f74e101Schristos length-addr_len-ETHERTYPE_LEN, 288c74ad251Schristos ND_BYTES_AVAILABLE_AFTER(p)-addr_len-ETHERTYPE_LEN, 289dc860a36Sspz NULL, NULL) == 0) 2900f74e101Schristos /* ether_type not known, probably it wasn't one */ 291c74ad251Schristos ND_PRINT("UI %02x! ", GET_U_1(p + addr_len)); 2920f74e101Schristos else 293ba2ff121Schristos return addr_len + 2; 294ba2ff121Schristos } 2950f74e101Schristos } 2960f74e101Schristos 297c74ad251Schristos ND_TCHECK_1(p + addr_len + 1); 298ba2ff121Schristos if (length < addr_len + 2) 299ba2ff121Schristos goto trunc; 300ba2ff121Schristos 301c74ad251Schristos if (GET_U_1(p + addr_len + 1) == 0) { 302ba2ff121Schristos /* 303ba2ff121Schristos * Assume a pad byte after the control (UI) byte. 304ba2ff121Schristos * A pad byte should only be used with 3-byte Q.922. 305ba2ff121Schristos */ 3060f74e101Schristos if (addr_len != 3) 307c74ad251Schristos ND_PRINT("Pad! "); 308ba2ff121Schristos hdr_len = addr_len + 1 /* UI */ + 1 /* pad */ + 1 /* NLPID */; 309ba2ff121Schristos } else { 310ba2ff121Schristos /* 311ba2ff121Schristos * Not a pad byte. 312ba2ff121Schristos * A pad byte should be used with 3-byte Q.922. 313ba2ff121Schristos */ 314ba2ff121Schristos if (addr_len == 3) 315c74ad251Schristos ND_PRINT("No pad! "); 316ba2ff121Schristos hdr_len = addr_len + 1 /* UI */ + 1 /* NLPID */; 317ba2ff121Schristos } 3180f74e101Schristos 319c74ad251Schristos ND_TCHECK_1(p + hdr_len - 1); 320ba2ff121Schristos if (length < hdr_len) 321ba2ff121Schristos goto trunc; 322c74ad251Schristos nlpid = GET_U_1(p + hdr_len - 1); 3230f74e101Schristos 324b3a00663Schristos if (ndo->ndo_eflag) 325b3a00663Schristos fr_hdr_print(ndo, length, addr_len, dlci, flags, nlpid); 3260f74e101Schristos p += hdr_len; 3270f74e101Schristos length -= hdr_len; 3280f74e101Schristos 3290f74e101Schristos switch (nlpid) { 3300f74e101Schristos case NLPID_IP: 331b3a00663Schristos ip_print(ndo, p, length); 3320f74e101Schristos break; 3330f74e101Schristos 3340f74e101Schristos case NLPID_IP6: 335b3a00663Schristos ip6_print(ndo, p, length); 3360f74e101Schristos break; 337ba2ff121Schristos 3380f74e101Schristos case NLPID_CLNP: 3390f74e101Schristos case NLPID_ESIS: 3400f74e101Schristos case NLPID_ISIS: 34172c96ff3Schristos isoclns_print(ndo, p - 1, length + 1); /* OSI printers need the NLPID field */ 3420f74e101Schristos break; 3430f74e101Schristos 3440f74e101Schristos case NLPID_SNAP: 345c74ad251Schristos if (snap_print(ndo, p, length, ND_BYTES_AVAILABLE_AFTER(p), NULL, NULL, 0) == 0) { 3460f74e101Schristos /* ether_type not known, print raw packet */ 347b3a00663Schristos if (!ndo->ndo_eflag) 348b3a00663Schristos fr_hdr_print(ndo, length + hdr_len, hdr_len, 3490f74e101Schristos dlci, flags, nlpid); 350b3a00663Schristos if (!ndo->ndo_suppress_default_print) 351b3a00663Schristos ND_DEFAULTPRINT(p - hdr_len, length + hdr_len); 3520f74e101Schristos } 3530f74e101Schristos break; 3540f74e101Schristos 3550f74e101Schristos case NLPID_Q933: 356b3a00663Schristos q933_print(ndo, p, length); 3570f74e101Schristos break; 3580f74e101Schristos 3590f74e101Schristos case NLPID_MFR: 360b3a00663Schristos frf15_print(ndo, p, length); 3610f74e101Schristos break; 3620f74e101Schristos 3630f74e101Schristos case NLPID_PPP: 364b3a00663Schristos ppp_print(ndo, p, length); 3650f74e101Schristos break; 3660f74e101Schristos 3670f74e101Schristos default: 368b3a00663Schristos if (!ndo->ndo_eflag) 369b3a00663Schristos fr_hdr_print(ndo, length + hdr_len, addr_len, 3700f74e101Schristos dlci, flags, nlpid); 371b3a00663Schristos if (!ndo->ndo_xflag) 372b3a00663Schristos ND_DEFAULTPRINT(p, length); 3730f74e101Schristos } 3740f74e101Schristos 3750f74e101Schristos return hdr_len; 3760f74e101Schristos 3770f74e101Schristos trunc: 378c74ad251Schristos nd_print_trunc(ndo); 3790f74e101Schristos return 0; 3800f74e101Schristos 3810f74e101Schristos } 3820f74e101Schristos 383c74ad251Schristos /* Multi Link Frame Relay (FRF.16) */ 384c74ad251Schristos void 385b3a00663Schristos mfr_if_print(netdissect_options *ndo, 386c74ad251Schristos const struct pcap_pkthdr *h, const u_char *p) 3870f74e101Schristos { 388c74ad251Schristos u_int length = h->len; 389c74ad251Schristos u_int caplen = h->caplen; 3900f74e101Schristos 391c74ad251Schristos ndo->ndo_protocol = "mfr"; 392c74ad251Schristos if (caplen < 2) { /* minimum frame header length */ 393c74ad251Schristos nd_print_trunc(ndo); 394c74ad251Schristos ndo->ndo_ll_hdr_len += caplen; 395c74ad251Schristos return; 396c74ad251Schristos } 3970f74e101Schristos 398c74ad251Schristos ndo->ndo_ll_hdr_len += mfr_print(ndo, p, length); 3990f74e101Schristos } 4000f74e101Schristos 4010f74e101Schristos 4020f74e101Schristos #define MFR_CTRL_MSG_ADD_LINK 1 4030f74e101Schristos #define MFR_CTRL_MSG_ADD_LINK_ACK 2 4040f74e101Schristos #define MFR_CTRL_MSG_ADD_LINK_REJ 3 4050f74e101Schristos #define MFR_CTRL_MSG_HELLO 4 4060f74e101Schristos #define MFR_CTRL_MSG_HELLO_ACK 5 4070f74e101Schristos #define MFR_CTRL_MSG_REMOVE_LINK 6 4080f74e101Schristos #define MFR_CTRL_MSG_REMOVE_LINK_ACK 7 4090f74e101Schristos 410870189d2Schristos static const struct tok mfr_ctrl_msg_values[] = { 4110f74e101Schristos { MFR_CTRL_MSG_ADD_LINK, "Add Link" }, 4120f74e101Schristos { MFR_CTRL_MSG_ADD_LINK_ACK, "Add Link ACK" }, 4130f74e101Schristos { MFR_CTRL_MSG_ADD_LINK_REJ, "Add Link Reject" }, 4140f74e101Schristos { MFR_CTRL_MSG_HELLO, "Hello" }, 4150f74e101Schristos { MFR_CTRL_MSG_HELLO_ACK, "Hello ACK" }, 4160f74e101Schristos { MFR_CTRL_MSG_REMOVE_LINK, "Remove Link" }, 4170f74e101Schristos { MFR_CTRL_MSG_REMOVE_LINK_ACK, "Remove Link ACK" }, 4180f74e101Schristos { 0, NULL } 4190f74e101Schristos }; 4200f74e101Schristos 4210f74e101Schristos #define MFR_CTRL_IE_BUNDLE_ID 1 4220f74e101Schristos #define MFR_CTRL_IE_LINK_ID 2 4230f74e101Schristos #define MFR_CTRL_IE_MAGIC_NUM 3 4240f74e101Schristos #define MFR_CTRL_IE_TIMESTAMP 5 4250f74e101Schristos #define MFR_CTRL_IE_VENDOR_EXT 6 4260f74e101Schristos #define MFR_CTRL_IE_CAUSE 7 4270f74e101Schristos 428870189d2Schristos static const struct tok mfr_ctrl_ie_values[] = { 4290f74e101Schristos { MFR_CTRL_IE_BUNDLE_ID, "Bundle ID"}, 4300f74e101Schristos { MFR_CTRL_IE_LINK_ID, "Link ID"}, 4310f74e101Schristos { MFR_CTRL_IE_MAGIC_NUM, "Magic Number"}, 4320f74e101Schristos { MFR_CTRL_IE_TIMESTAMP, "Timestamp"}, 4330f74e101Schristos { MFR_CTRL_IE_VENDOR_EXT, "Vendor Extension"}, 4340f74e101Schristos { MFR_CTRL_IE_CAUSE, "Cause"}, 4350f74e101Schristos { 0, NULL } 4360f74e101Schristos }; 4370f74e101Schristos 4380f74e101Schristos #define MFR_ID_STRING_MAXLEN 50 4390f74e101Schristos 4400f74e101Schristos struct ie_tlv_header_t { 441b3a00663Schristos uint8_t ie_type; 442b3a00663Schristos uint8_t ie_len; 4430f74e101Schristos }; 4440f74e101Schristos 4450f74e101Schristos u_int 446b3a00663Schristos mfr_print(netdissect_options *ndo, 447c74ad251Schristos const u_char *p, u_int length) 4480f74e101Schristos { 4490f74e101Schristos u_int tlen,idx,hdr_len = 0; 450b3a00663Schristos uint16_t sequence_num; 451b3a00663Schristos uint8_t ie_type,ie_len; 452b3a00663Schristos const uint8_t *tptr; 4530f74e101Schristos 4540f74e101Schristos 4550f74e101Schristos /* 4560f74e101Schristos * FRF.16 Link Integrity Control Frame 4570f74e101Schristos * 4580f74e101Schristos * 7 6 5 4 3 2 1 0 4590f74e101Schristos * +----+----+----+----+----+----+----+----+ 4600f74e101Schristos * | B | E | C=1| 0 0 0 0 | EA | 4610f74e101Schristos * +----+----+----+----+----+----+----+----+ 4620f74e101Schristos * | 0 0 0 0 0 0 0 0 | 4630f74e101Schristos * +----+----+----+----+----+----+----+----+ 4640f74e101Schristos * | message type | 4650f74e101Schristos * +----+----+----+----+----+----+----+----+ 4660f74e101Schristos */ 4670f74e101Schristos 468c74ad251Schristos ndo->ndo_protocol = "mfr"; 469c74ad251Schristos 470c74ad251Schristos if (length < 4) { /* minimum frame header length */ 471c74ad251Schristos ND_PRINT("[length %u < 4]", length); 472c74ad251Schristos nd_print_invalid(ndo); 473817e9a7eSchristos return length; 474817e9a7eSchristos } 475c74ad251Schristos ND_TCHECK_4(p); 4760f74e101Schristos 477c74ad251Schristos if ((GET_U_1(p) & MFR_BEC_MASK) == MFR_CTRL_FRAME && GET_U_1(p + 1) == 0) { 478c74ad251Schristos ND_PRINT("FRF.16 Control, Flags [%s], %s, length %u", 479c74ad251Schristos bittok2str(frf_flag_values,"none",(GET_U_1(p) & MFR_BEC_MASK)), 480c74ad251Schristos tok2str(mfr_ctrl_msg_values,"Unknown Message (0x%02x)",GET_U_1(p + 2)), 481c74ad251Schristos length); 4820f74e101Schristos tptr = p + 3; 4830f74e101Schristos tlen = length -3; 4840f74e101Schristos hdr_len = 3; 4850f74e101Schristos 486b3a00663Schristos if (!ndo->ndo_vflag) 4870f74e101Schristos return hdr_len; 4880f74e101Schristos 4890f74e101Schristos while (tlen>sizeof(struct ie_tlv_header_t)) { 490c74ad251Schristos ND_TCHECK_LEN(tptr, sizeof(struct ie_tlv_header_t)); 491c74ad251Schristos ie_type=GET_U_1(tptr); 492c74ad251Schristos ie_len=GET_U_1(tptr + 1); 4930f74e101Schristos 494c74ad251Schristos ND_PRINT("\n\tIE %s (%u), length %u: ", 4950f74e101Schristos tok2str(mfr_ctrl_ie_values,"Unknown",ie_type), 4960f74e101Schristos ie_type, 497c74ad251Schristos ie_len); 4980f74e101Schristos 4990f74e101Schristos /* infinite loop check */ 5000f74e101Schristos if (ie_type == 0 || ie_len <= sizeof(struct ie_tlv_header_t)) 5010f74e101Schristos return hdr_len; 5020f74e101Schristos 503c74ad251Schristos ND_TCHECK_LEN(tptr, ie_len); 5040f74e101Schristos tptr+=sizeof(struct ie_tlv_header_t); 5050f74e101Schristos /* tlv len includes header */ 5060f74e101Schristos ie_len-=sizeof(struct ie_tlv_header_t); 5070f74e101Schristos tlen-=sizeof(struct ie_tlv_header_t); 5080f74e101Schristos 5090f74e101Schristos switch (ie_type) { 5100f74e101Schristos 5110f74e101Schristos case MFR_CTRL_IE_MAGIC_NUM: 512817e9a7eSchristos /* FRF.16.1 Section 3.4.3 Magic Number Information Element */ 513817e9a7eSchristos if (ie_len != 4) { 514c74ad251Schristos ND_PRINT("[IE data length %d != 4]", ie_len); 515c74ad251Schristos nd_print_invalid(ndo); 516817e9a7eSchristos break; 517817e9a7eSchristos } 518c74ad251Schristos ND_PRINT("0x%08x", GET_BE_U_4(tptr)); 5190f74e101Schristos break; 5200f74e101Schristos 5210f74e101Schristos case MFR_CTRL_IE_BUNDLE_ID: /* same message format */ 5220f74e101Schristos case MFR_CTRL_IE_LINK_ID: 5230f74e101Schristos for (idx = 0; idx < ie_len && idx < MFR_ID_STRING_MAXLEN; idx++) { 524c74ad251Schristos if (GET_U_1(tptr + idx) != 0) /* don't print null termination */ 525c74ad251Schristos fn_print_char(ndo, GET_U_1(tptr + idx)); 5260f74e101Schristos else 5270f74e101Schristos break; 5280f74e101Schristos } 5290f74e101Schristos break; 5300f74e101Schristos 5310f74e101Schristos case MFR_CTRL_IE_TIMESTAMP: 532*26ba0b50Schristos /* 533*26ba0b50Schristos * FRF.16.1 Section 3.4.4 Timestamp Information Element 534*26ba0b50Schristos * 535*26ba0b50Schristos * The maximum length is 14 octets. Format is implementation 536*26ba0b50Schristos * specific. 537*26ba0b50Schristos */ 538*26ba0b50Schristos if (ie_len > 14) { 539*26ba0b50Schristos ND_PRINT("[Timestamp IE length %d > 14]", ie_len); 540*26ba0b50Schristos nd_print_invalid(ndo); 5410f74e101Schristos break; 5420f74e101Schristos } 543*26ba0b50Schristos /* fall through and hexdump */ 544c74ad251Schristos ND_FALL_THROUGH; 5450f74e101Schristos 5460f74e101Schristos /* 5470f74e101Schristos * FIXME those are the defined IEs that lack a decoder 5480f74e101Schristos * you are welcome to contribute code ;-) 5490f74e101Schristos */ 5500f74e101Schristos 5510f74e101Schristos case MFR_CTRL_IE_VENDOR_EXT: 5520f74e101Schristos case MFR_CTRL_IE_CAUSE: 5530f74e101Schristos 5540f74e101Schristos default: 555b3a00663Schristos if (ndo->ndo_vflag <= 1) 556b3a00663Schristos print_unknown_data(ndo, tptr, "\n\t ", ie_len); 5570f74e101Schristos break; 5580f74e101Schristos } 5590f74e101Schristos 5600f74e101Schristos /* do we want to see a hexdump of the IE ? */ 561b3a00663Schristos if (ndo->ndo_vflag > 1 ) 562b3a00663Schristos print_unknown_data(ndo, tptr, "\n\t ", ie_len); 5630f74e101Schristos 5640f74e101Schristos tlen-=ie_len; 5650f74e101Schristos tptr+=ie_len; 5660f74e101Schristos } 5670f74e101Schristos return hdr_len; 5680f74e101Schristos } 5690f74e101Schristos /* 5700f74e101Schristos * FRF.16 Fragmentation Frame 5710f74e101Schristos * 5720f74e101Schristos * 7 6 5 4 3 2 1 0 5730f74e101Schristos * +----+----+----+----+----+----+----+----+ 5740f74e101Schristos * | B | E | C=0|seq. (high 4 bits) | EA | 5750f74e101Schristos * +----+----+----+----+----+----+----+----+ 5760f74e101Schristos * | sequence (low 8 bits) | 5770f74e101Schristos * +----+----+----+----+----+----+----+----+ 5780f74e101Schristos * | DLCI (6 bits) | CR | EA | 5790f74e101Schristos * +----+----+----+----+----+----+----+----+ 5800f74e101Schristos * | DLCI (4 bits) |FECN|BECN| DE | EA | 5810f74e101Schristos * +----+----+----+----+----+----+----+----+ 5820f74e101Schristos */ 5830f74e101Schristos 584c74ad251Schristos sequence_num = (GET_U_1(p)&0x1e)<<7 | GET_U_1(p + 1); 5850f74e101Schristos /* whole packet or first fragment ? */ 586c74ad251Schristos if ((GET_U_1(p) & MFR_BEC_MASK) == MFR_FRAG_FRAME || 587c74ad251Schristos (GET_U_1(p) & MFR_BEC_MASK) == MFR_B_BIT) { 588c74ad251Schristos ND_PRINT("FRF.16 Frag, seq %u, Flags [%s], ", 5890f74e101Schristos sequence_num, 590c74ad251Schristos bittok2str(frf_flag_values,"none",(GET_U_1(p) & MFR_BEC_MASK))); 5910f74e101Schristos hdr_len = 2; 592b3a00663Schristos fr_print(ndo, p+hdr_len,length-hdr_len); 5930f74e101Schristos return hdr_len; 5940f74e101Schristos } 5950f74e101Schristos 5960f74e101Schristos /* must be a middle or the last fragment */ 597c74ad251Schristos ND_PRINT("FRF.16 Frag, seq %u, Flags [%s]", 5980f74e101Schristos sequence_num, 599c74ad251Schristos bittok2str(frf_flag_values,"none",(GET_U_1(p) & MFR_BEC_MASK))); 600b3a00663Schristos print_unknown_data(ndo, p, "\n\t", length); 6010f74e101Schristos 6020f74e101Schristos return hdr_len; 6030f74e101Schristos 6040f74e101Schristos trunc: 605c74ad251Schristos nd_print_trunc(ndo); 6060f74e101Schristos return length; 6070f74e101Schristos } 6080f74e101Schristos 6090f74e101Schristos /* an NLPID of 0xb1 indicates a 2-byte 6100f74e101Schristos * FRF.15 header 6110f74e101Schristos * 6120f74e101Schristos * 7 6 5 4 3 2 1 0 6130f74e101Schristos * +----+----+----+----+----+----+----+----+ 6140f74e101Schristos * ~ Q.922 header ~ 6150f74e101Schristos * +----+----+----+----+----+----+----+----+ 6160f74e101Schristos * | NLPID (8 bits) | NLPID=0xb1 6170f74e101Schristos * +----+----+----+----+----+----+----+----+ 6180f74e101Schristos * | B | E | C |seq. (high 4 bits) | R | 6190f74e101Schristos * +----+----+----+----+----+----+----+----+ 6200f74e101Schristos * | sequence (low 8 bits) | 6210f74e101Schristos * +----+----+----+----+----+----+----+----+ 6220f74e101Schristos */ 6230f74e101Schristos 6240f74e101Schristos #define FR_FRF15_FRAGTYPE 0x01 6250f74e101Schristos 6260f74e101Schristos static void 627b3a00663Schristos frf15_print(netdissect_options *ndo, 628ba2ff121Schristos const u_char *p, u_int length) 629ba2ff121Schristos { 630b3a00663Schristos uint16_t sequence_num, flags; 6310f74e101Schristos 632fdccd7e4Schristos if (length < 2) 633fdccd7e4Schristos goto trunc; 634fdccd7e4Schristos 635c74ad251Schristos flags = GET_U_1(p)&MFR_BEC_MASK; 636c74ad251Schristos sequence_num = (GET_U_1(p)&0x1e)<<7 | GET_U_1(p + 1); 6370f74e101Schristos 638c74ad251Schristos ND_PRINT("FRF.15, seq 0x%03x, Flags [%s],%s Fragmentation, length %u", 6390f74e101Schristos sequence_num, 6400f74e101Schristos bittok2str(frf_flag_values,"none",flags), 641c74ad251Schristos GET_U_1(p)&FR_FRF15_FRAGTYPE ? "Interface" : "End-to-End", 642c74ad251Schristos length); 6430f74e101Schristos 6440f74e101Schristos /* TODO: 6450f74e101Schristos * depending on all permutations of the B, E and C bit 6460f74e101Schristos * dig as deep as we can - e.g. on the first (B) fragment 6470f74e101Schristos * there is enough payload to print the IP header 6480f74e101Schristos * on non (B) fragments it depends if the fragmentation 649c74ad251Schristos * model is end-to-end or interface based whether we want to print 6500f74e101Schristos * another Q.922 header 6510f74e101Schristos */ 652fdccd7e4Schristos return; 6530f74e101Schristos 654fdccd7e4Schristos trunc: 655c74ad251Schristos nd_print_trunc(ndo); 6560f74e101Schristos } 6570f74e101Schristos 6580f74e101Schristos /* 6590f74e101Schristos * Q.933 decoding portion for framerelay specific. 6600f74e101Schristos */ 6610f74e101Schristos 6620f74e101Schristos /* Q.933 packet format 6630f74e101Schristos Format of Other Protocols 6640f74e101Schristos using Q.933 NLPID 6650f74e101Schristos +-------------------------------+ 6660f74e101Schristos | Q.922 Address | 6670f74e101Schristos +---------------+---------------+ 6680f74e101Schristos |Control 0x03 | NLPID 0x08 | 6690f74e101Schristos +---------------+---------------+ 6700f74e101Schristos | L2 Protocol ID | 6710f74e101Schristos | octet 1 | octet 2 | 6720f74e101Schristos +-------------------------------+ 6730f74e101Schristos | L3 Protocol ID | 6740f74e101Schristos | octet 2 | octet 2 | 6750f74e101Schristos +-------------------------------+ 6760f74e101Schristos | Protocol Data | 6770f74e101Schristos +-------------------------------+ 6780f74e101Schristos | FCS | 6790f74e101Schristos +-------------------------------+ 6800f74e101Schristos */ 6810f74e101Schristos 6820f74e101Schristos /* L2 (Octet 1)- Call Reference Usually is 0x0 */ 6830f74e101Schristos 6840f74e101Schristos /* 6850f74e101Schristos * L2 (Octet 2)- Message Types definition 1 byte long. 6860f74e101Schristos */ 6870f74e101Schristos /* Call Establish */ 6880f74e101Schristos #define MSG_TYPE_ESC_TO_NATIONAL 0x00 6890f74e101Schristos #define MSG_TYPE_ALERT 0x01 6900f74e101Schristos #define MSG_TYPE_CALL_PROCEEDING 0x02 6910f74e101Schristos #define MSG_TYPE_CONNECT 0x07 6920f74e101Schristos #define MSG_TYPE_CONNECT_ACK 0x0F 6930f74e101Schristos #define MSG_TYPE_PROGRESS 0x03 6940f74e101Schristos #define MSG_TYPE_SETUP 0x05 6950f74e101Schristos /* Call Clear */ 6960f74e101Schristos #define MSG_TYPE_DISCONNECT 0x45 6970f74e101Schristos #define MSG_TYPE_RELEASE 0x4D 6980f74e101Schristos #define MSG_TYPE_RELEASE_COMPLETE 0x5A 6990f74e101Schristos #define MSG_TYPE_RESTART 0x46 7000f74e101Schristos #define MSG_TYPE_RESTART_ACK 0x4E 7010f74e101Schristos /* Status */ 7020f74e101Schristos #define MSG_TYPE_STATUS 0x7D 7030f74e101Schristos #define MSG_TYPE_STATUS_ENQ 0x75 7040f74e101Schristos 705870189d2Schristos static const struct tok fr_q933_msg_values[] = { 7060f74e101Schristos { MSG_TYPE_ESC_TO_NATIONAL, "ESC to National" }, 7070f74e101Schristos { MSG_TYPE_ALERT, "Alert" }, 7080f74e101Schristos { MSG_TYPE_CALL_PROCEEDING, "Call proceeding" }, 7090f74e101Schristos { MSG_TYPE_CONNECT, "Connect" }, 7100f74e101Schristos { MSG_TYPE_CONNECT_ACK, "Connect ACK" }, 7110f74e101Schristos { MSG_TYPE_PROGRESS, "Progress" }, 7120f74e101Schristos { MSG_TYPE_SETUP, "Setup" }, 7130f74e101Schristos { MSG_TYPE_DISCONNECT, "Disconnect" }, 7140f74e101Schristos { MSG_TYPE_RELEASE, "Release" }, 7150f74e101Schristos { MSG_TYPE_RELEASE_COMPLETE, "Release Complete" }, 7160f74e101Schristos { MSG_TYPE_RESTART, "Restart" }, 7170f74e101Schristos { MSG_TYPE_RESTART_ACK, "Restart ACK" }, 7180f74e101Schristos { MSG_TYPE_STATUS, "Status Reply" }, 7190f74e101Schristos { MSG_TYPE_STATUS_ENQ, "Status Enquiry" }, 7200f74e101Schristos { 0, NULL } 7210f74e101Schristos }; 7220f74e101Schristos 723dc860a36Sspz #define IE_IS_SINGLE_OCTET(iecode) ((iecode) & 0x80) 724dc860a36Sspz #define IE_IS_SHIFT(iecode) (((iecode) & 0xF0) == 0x90) 725dc860a36Sspz #define IE_SHIFT_IS_NON_LOCKING(iecode) ((iecode) & 0x08) 726dc860a36Sspz #define IE_SHIFT_IS_LOCKING(iecode) (!(IE_SHIFT_IS_NON_LOCKING(iecode))) 727dc860a36Sspz #define IE_SHIFT_CODESET(iecode) ((iecode) & 0x07) 7280f74e101Schristos 7290f74e101Schristos #define FR_LMI_ANSI_REPORT_TYPE_IE 0x01 7300f74e101Schristos #define FR_LMI_ANSI_LINK_VERIFY_IE_91 0x19 /* details? */ 7310f74e101Schristos #define FR_LMI_ANSI_LINK_VERIFY_IE 0x03 7320f74e101Schristos #define FR_LMI_ANSI_PVC_STATUS_IE 0x07 7330f74e101Schristos 7340f74e101Schristos #define FR_LMI_CCITT_REPORT_TYPE_IE 0x51 7350f74e101Schristos #define FR_LMI_CCITT_LINK_VERIFY_IE 0x53 7360f74e101Schristos #define FR_LMI_CCITT_PVC_STATUS_IE 0x57 7370f74e101Schristos 738dc860a36Sspz static const struct tok fr_q933_ie_values_codeset_0_5[] = { 7390f74e101Schristos { FR_LMI_ANSI_REPORT_TYPE_IE, "ANSI Report Type" }, 7400f74e101Schristos { FR_LMI_ANSI_LINK_VERIFY_IE_91, "ANSI Link Verify" }, 7410f74e101Schristos { FR_LMI_ANSI_LINK_VERIFY_IE, "ANSI Link Verify" }, 7420f74e101Schristos { FR_LMI_ANSI_PVC_STATUS_IE, "ANSI PVC Status" }, 7430f74e101Schristos { FR_LMI_CCITT_REPORT_TYPE_IE, "CCITT Report Type" }, 7440f74e101Schristos { FR_LMI_CCITT_LINK_VERIFY_IE, "CCITT Link Verify" }, 7450f74e101Schristos { FR_LMI_CCITT_PVC_STATUS_IE, "CCITT PVC Status" }, 7460f74e101Schristos { 0, NULL } 7470f74e101Schristos }; 7480f74e101Schristos 7490f74e101Schristos #define FR_LMI_REPORT_TYPE_IE_FULL_STATUS 0 7500f74e101Schristos #define FR_LMI_REPORT_TYPE_IE_LINK_VERIFY 1 7510f74e101Schristos #define FR_LMI_REPORT_TYPE_IE_ASYNC_PVC 2 7520f74e101Schristos 753870189d2Schristos static const struct tok fr_lmi_report_type_ie_values[] = { 7540f74e101Schristos { FR_LMI_REPORT_TYPE_IE_FULL_STATUS, "Full Status" }, 7550f74e101Schristos { FR_LMI_REPORT_TYPE_IE_LINK_VERIFY, "Link verify" }, 7560f74e101Schristos { FR_LMI_REPORT_TYPE_IE_ASYNC_PVC, "Async PVC Status" }, 7570f74e101Schristos { 0, NULL } 7580f74e101Schristos }; 7590f74e101Schristos 760dc860a36Sspz /* array of 16 codesets - currently we only support codepage 0 and 5 */ 761870189d2Schristos static const struct tok *fr_q933_ie_codesets[] = { 762dc860a36Sspz fr_q933_ie_values_codeset_0_5, 7630f74e101Schristos NULL, 7640f74e101Schristos NULL, 7650f74e101Schristos NULL, 766dc860a36Sspz NULL, 767dc860a36Sspz fr_q933_ie_values_codeset_0_5, 7680f74e101Schristos NULL, 7690f74e101Schristos NULL, 7700f74e101Schristos NULL, 7710f74e101Schristos NULL, 7720f74e101Schristos NULL, 7730f74e101Schristos NULL, 7740f74e101Schristos NULL, 7750f74e101Schristos NULL, 7760f74e101Schristos NULL, 7770f74e101Schristos NULL 7780f74e101Schristos }; 7790f74e101Schristos 780dc860a36Sspz static int fr_q933_print_ie_codeset_0_5(netdissect_options *ndo, u_int iecode, 781dc860a36Sspz u_int ielength, const u_char *p); 7820f74e101Schristos 783dc860a36Sspz typedef int (*codeset_pr_func_t)(netdissect_options *, u_int iecode, 784dc860a36Sspz u_int ielength, const u_char *p); 7850f74e101Schristos 786dc860a36Sspz /* array of 16 codesets - currently we only support codepage 0 and 5 */ 787b3a00663Schristos static const codeset_pr_func_t fr_q933_print_ie_codeset[] = { 788dc860a36Sspz fr_q933_print_ie_codeset_0_5, 7890f74e101Schristos NULL, 7900f74e101Schristos NULL, 7910f74e101Schristos NULL, 792dc860a36Sspz NULL, 793dc860a36Sspz fr_q933_print_ie_codeset_0_5, 7940f74e101Schristos NULL, 7950f74e101Schristos NULL, 7960f74e101Schristos NULL, 7970f74e101Schristos NULL, 7980f74e101Schristos NULL, 7990f74e101Schristos NULL, 8000f74e101Schristos NULL, 8010f74e101Schristos NULL, 8020f74e101Schristos NULL, 8030f74e101Schristos NULL 8040f74e101Schristos }; 8050f74e101Schristos 806dc860a36Sspz /* 807dc860a36Sspz * ITU-T Q.933. 808dc860a36Sspz * 809dc860a36Sspz * p points to octet 2, the octet containing the length of the 810dc860a36Sspz * call reference value, so p[n] is octet n+2 ("octet X" is as 811dc860a36Sspz * used in Q.931/Q.933). 812dc860a36Sspz * 813dc860a36Sspz * XXX - actually used both for Q.931 and Q.933. 814dc860a36Sspz */ 8150f74e101Schristos void 816b3a00663Schristos q933_print(netdissect_options *ndo, 817b3a00663Schristos const u_char *p, u_int length) 8180f74e101Schristos { 819dc860a36Sspz u_int olen; 820dc860a36Sspz u_int call_ref_length, i; 821dc860a36Sspz uint8_t call_ref[15]; /* maximum length - length field is 4 bits */ 822dc860a36Sspz u_int msgtype; 823dc860a36Sspz u_int iecode; 824dc860a36Sspz u_int ielength; 825dc860a36Sspz u_int codeset = 0; 826dc860a36Sspz u_int is_ansi = 0; 827dc860a36Sspz u_int ie_is_known; 828dc860a36Sspz u_int non_locking_shift; 829dc860a36Sspz u_int unshift_codeset; 8300f74e101Schristos 831c74ad251Schristos ndo->ndo_protocol = "q.933"; 832c74ad251Schristos ND_PRINT("%s", ndo->ndo_eflag ? "" : "Q.933"); 833dc860a36Sspz 834c74ad251Schristos if (length == 0 || !ND_TTEST_1(p)) { 835dc860a36Sspz if (!ndo->ndo_eflag) 836c74ad251Schristos ND_PRINT(", "); 837c74ad251Schristos ND_PRINT("length %u", length); 838fdccd7e4Schristos goto trunc; 8390f74e101Schristos } 8400f74e101Schristos 841dc860a36Sspz /* 842dc860a36Sspz * Get the length of the call reference value. 843dc860a36Sspz */ 844dc860a36Sspz olen = length; /* preserve the original length for display */ 845c74ad251Schristos call_ref_length = GET_U_1(p) & 0x0f; 846dc860a36Sspz p++; 847dc860a36Sspz length--; 848dc860a36Sspz 849dc860a36Sspz /* 850dc860a36Sspz * Get the call reference value. 851dc860a36Sspz */ 852dc860a36Sspz for (i = 0; i < call_ref_length; i++) { 853c74ad251Schristos if (length == 0 || !ND_TTEST_1(p)) { 854dc860a36Sspz if (!ndo->ndo_eflag) 855c74ad251Schristos ND_PRINT(", "); 856c74ad251Schristos ND_PRINT("length %u", olen); 857dc860a36Sspz goto trunc; 858dc860a36Sspz } 859c74ad251Schristos call_ref[i] = GET_U_1(p); 860dc860a36Sspz p++; 861dc860a36Sspz length--; 862dc860a36Sspz } 863dc860a36Sspz 864dc860a36Sspz /* 865dc860a36Sspz * Get the message type. 866dc860a36Sspz */ 867c74ad251Schristos if (length == 0 || !ND_TTEST_1(p)) { 868dc860a36Sspz if (!ndo->ndo_eflag) 869c74ad251Schristos ND_PRINT(", "); 870c74ad251Schristos ND_PRINT("length %u", olen); 871dc860a36Sspz goto trunc; 872dc860a36Sspz } 873c74ad251Schristos msgtype = GET_U_1(p); 874dc860a36Sspz p++; 875dc860a36Sspz length--; 876dc860a36Sspz 877dc860a36Sspz /* 878dc860a36Sspz * Peek ahead to see if we start with a shift. 879dc860a36Sspz */ 880dc860a36Sspz non_locking_shift = 0; 881dc860a36Sspz unshift_codeset = codeset; 882dc860a36Sspz if (length != 0) { 883c74ad251Schristos if (!ND_TTEST_1(p)) { 884dc860a36Sspz if (!ndo->ndo_eflag) 885c74ad251Schristos ND_PRINT(", "); 886c74ad251Schristos ND_PRINT("length %u", olen); 887dc860a36Sspz goto trunc; 888dc860a36Sspz } 889c74ad251Schristos iecode = GET_U_1(p); 890dc860a36Sspz if (IE_IS_SHIFT(iecode)) { 891dc860a36Sspz /* 892dc860a36Sspz * It's a shift. Skip over it. 893dc860a36Sspz */ 894dc860a36Sspz p++; 895dc860a36Sspz length--; 896dc860a36Sspz 897dc860a36Sspz /* 898dc860a36Sspz * Get the codeset. 899dc860a36Sspz */ 900dc860a36Sspz codeset = IE_SHIFT_CODESET(iecode); 901dc860a36Sspz 902dc860a36Sspz /* 903dc860a36Sspz * If it's a locking shift to codeset 5, 904dc860a36Sspz * mark this as ANSI. (XXX - 5 is actually 905dc860a36Sspz * for national variants in general, not 906dc860a36Sspz * the US variant in particular, but maybe 907dc860a36Sspz * this is more American exceptionalism. :-)) 908dc860a36Sspz */ 909dc860a36Sspz if (IE_SHIFT_IS_LOCKING(iecode)) { 910dc860a36Sspz /* 911dc860a36Sspz * It's a locking shift. 912dc860a36Sspz */ 913dc860a36Sspz if (codeset == 5) { 914dc860a36Sspz /* 915dc860a36Sspz * It's a locking shift to 916dc860a36Sspz * codeset 5, so this is 917dc860a36Sspz * T1.617 Annex D. 918dc860a36Sspz */ 919dc860a36Sspz is_ansi = 1; 920dc860a36Sspz } 921dc860a36Sspz } else { 922dc860a36Sspz /* 923dc860a36Sspz * It's a non-locking shift. 924dc860a36Sspz * Remember the current codeset, so we 925dc860a36Sspz * can revert to it after the next IE. 926dc860a36Sspz */ 927dc860a36Sspz non_locking_shift = 1; 928dc860a36Sspz unshift_codeset = 0; 929dc860a36Sspz } 930dc860a36Sspz } 931dc860a36Sspz } 9320f74e101Schristos 9330f74e101Schristos /* printing out header part */ 934dc860a36Sspz if (!ndo->ndo_eflag) 935c74ad251Schristos ND_PRINT(", "); 936c74ad251Schristos ND_PRINT("%s, codeset %u", is_ansi ? "ANSI" : "CCITT", codeset); 9370f74e101Schristos 938dc860a36Sspz if (call_ref_length != 0) { 939c74ad251Schristos if (call_ref_length > 1 || GET_U_1(p) != 0) { 940dc860a36Sspz /* 941dc860a36Sspz * Not a dummy call reference. 942dc860a36Sspz */ 943c74ad251Schristos ND_PRINT(", Call Ref: 0x"); 944dc860a36Sspz for (i = 0; i < call_ref_length; i++) 945c74ad251Schristos ND_PRINT("%02x", call_ref[i]); 946dc860a36Sspz } 9470f74e101Schristos } 948b3a00663Schristos if (ndo->ndo_vflag) { 949c74ad251Schristos ND_PRINT(", %s (0x%02x), length %u", 9500f74e101Schristos tok2str(fr_q933_msg_values, 951dc860a36Sspz "unknown message", msgtype), 952dc860a36Sspz msgtype, 953c74ad251Schristos olen); 9540f74e101Schristos } else { 955c74ad251Schristos ND_PRINT(", %s", 9560f74e101Schristos tok2str(fr_q933_msg_values, 957c74ad251Schristos "unknown message 0x%02x", msgtype)); 9580f74e101Schristos } 9590f74e101Schristos 960dc860a36Sspz /* Loop through the rest of the IEs */ 961dc860a36Sspz while (length != 0) { 962dc860a36Sspz /* 963dc860a36Sspz * What's the state of any non-locking shifts? 964dc860a36Sspz */ 965dc860a36Sspz if (non_locking_shift == 1) { 966dc860a36Sspz /* 967dc860a36Sspz * There's a non-locking shift in effect for 968dc860a36Sspz * this IE. Count it, so we reset the codeset 969dc860a36Sspz * before the next IE. 970dc860a36Sspz */ 971dc860a36Sspz non_locking_shift = 2; 972dc860a36Sspz } else if (non_locking_shift == 2) { 973dc860a36Sspz /* 974dc860a36Sspz * Unshift. 975dc860a36Sspz */ 976dc860a36Sspz codeset = unshift_codeset; 977dc860a36Sspz non_locking_shift = 0; 9780f74e101Schristos } 9790f74e101Schristos 980dc860a36Sspz /* 981dc860a36Sspz * Get the first octet of the IE. 982dc860a36Sspz */ 983c74ad251Schristos if (!ND_TTEST_1(p)) { 984dc860a36Sspz if (!ndo->ndo_vflag) { 985c74ad251Schristos ND_PRINT(", length %u", olen); 9860f74e101Schristos } 987dc860a36Sspz goto trunc; 9880f74e101Schristos } 989c74ad251Schristos iecode = GET_U_1(p); 990dc860a36Sspz p++; 991dc860a36Sspz length--; 992dc860a36Sspz 993dc860a36Sspz /* Single-octet IE? */ 994dc860a36Sspz if (IE_IS_SINGLE_OCTET(iecode)) { 995dc860a36Sspz /* 996dc860a36Sspz * Yes. Is it a shift? 997dc860a36Sspz */ 998dc860a36Sspz if (IE_IS_SHIFT(iecode)) { 999dc860a36Sspz /* 1000dc860a36Sspz * Yes. Is it locking? 1001dc860a36Sspz */ 1002dc860a36Sspz if (IE_SHIFT_IS_LOCKING(iecode)) { 1003dc860a36Sspz /* 1004dc860a36Sspz * Yes. 1005dc860a36Sspz */ 1006dc860a36Sspz non_locking_shift = 0; 1007dc860a36Sspz } else { 1008dc860a36Sspz /* 1009dc860a36Sspz * No. Remember the current 1010dc860a36Sspz * codeset, so we can revert 1011dc860a36Sspz * to it after the next IE. 1012dc860a36Sspz */ 1013dc860a36Sspz non_locking_shift = 1; 1014dc860a36Sspz unshift_codeset = codeset; 1015fdccd7e4Schristos } 10160f74e101Schristos 1017dc860a36Sspz /* 1018dc860a36Sspz * Get the codeset. 1019dc860a36Sspz */ 1020dc860a36Sspz codeset = IE_SHIFT_CODESET(iecode); 1021dc860a36Sspz } 1022dc860a36Sspz } else { 1023dc860a36Sspz /* 1024dc860a36Sspz * No. Get the IE length. 1025dc860a36Sspz */ 1026c74ad251Schristos if (length == 0 || !ND_TTEST_1(p)) { 1027dc860a36Sspz if (!ndo->ndo_vflag) { 1028c74ad251Schristos ND_PRINT(", length %u", olen); 1029dc860a36Sspz } 1030dc860a36Sspz goto trunc; 1031dc860a36Sspz } 1032c74ad251Schristos ielength = GET_U_1(p); 1033dc860a36Sspz p++; 1034dc860a36Sspz length--; 1035dc860a36Sspz 10360f74e101Schristos /* lets do the full IE parsing only in verbose mode 10370f74e101Schristos * however some IEs (DLCI Status, Link Verify) 1038dc860a36Sspz * are also interesting in non-verbose mode */ 1039b3a00663Schristos if (ndo->ndo_vflag) { 1040c74ad251Schristos ND_PRINT("\n\t%s IE (0x%02x), length %u: ", 10410f74e101Schristos tok2str(fr_q933_ie_codesets[codeset], 1042dc860a36Sspz "unknown", iecode), 1043dc860a36Sspz iecode, 1044c74ad251Schristos ielength); 10450f74e101Schristos } 10460f74e101Schristos 1047fdccd7e4Schristos /* sanity checks */ 1048dc860a36Sspz if (iecode == 0 || ielength == 0) { 10490f74e101Schristos return; 10500f74e101Schristos } 1051c74ad251Schristos if (length < ielength || !ND_TTEST_LEN(p, ielength)) { 1052dc860a36Sspz if (!ndo->ndo_vflag) { 1053c74ad251Schristos ND_PRINT(", length %u", olen); 1054dc860a36Sspz } 1055fdccd7e4Schristos goto trunc; 1056fdccd7e4Schristos } 10570f74e101Schristos 1058dc860a36Sspz ie_is_known = 0; 10590f74e101Schristos if (fr_q933_print_ie_codeset[codeset] != NULL) { 1060dc860a36Sspz ie_is_known = fr_q933_print_ie_codeset[codeset](ndo, iecode, ielength, p); 10610f74e101Schristos } 10620f74e101Schristos 1063dc860a36Sspz if (ie_is_known) { 1064dc860a36Sspz /* 1065dc860a36Sspz * Known IE; do we want to see a hexdump 1066dc860a36Sspz * of it? 1067dc860a36Sspz */ 1068dc860a36Sspz if (ndo->ndo_vflag > 1) { 1069dc860a36Sspz /* Yes. */ 1070dc860a36Sspz print_unknown_data(ndo, p, "\n\t ", ielength); 1071dc860a36Sspz } 1072dc860a36Sspz } else { 1073dc860a36Sspz /* 1074dc860a36Sspz * Unknown IE; if we're printing verbosely, 1075dc860a36Sspz * print its content in hex. 1076dc860a36Sspz */ 1077dc860a36Sspz if (ndo->ndo_vflag >= 1) { 1078dc860a36Sspz print_unknown_data(ndo, p, "\n\t", ielength); 1079dc860a36Sspz } 10800f74e101Schristos } 10810f74e101Schristos 1082dc860a36Sspz length -= ielength; 1083dc860a36Sspz p += ielength; 10840f74e101Schristos } 10850f74e101Schristos } 1086b3a00663Schristos if (!ndo->ndo_vflag) { 1087c74ad251Schristos ND_PRINT(", length %u", olen); 10880f74e101Schristos } 1089fdccd7e4Schristos return; 1090fdccd7e4Schristos 1091fdccd7e4Schristos trunc: 1092c74ad251Schristos nd_print_trunc(ndo); 10930f74e101Schristos } 10940f74e101Schristos 10950f74e101Schristos static int 1096dc860a36Sspz fr_q933_print_ie_codeset_0_5(netdissect_options *ndo, u_int iecode, 1097dc860a36Sspz u_int ielength, const u_char *p) 10980f74e101Schristos { 10990f74e101Schristos u_int dlci; 11000f74e101Schristos 1101dc860a36Sspz switch (iecode) { 11020f74e101Schristos 11030f74e101Schristos case FR_LMI_ANSI_REPORT_TYPE_IE: /* fall through */ 11040f74e101Schristos case FR_LMI_CCITT_REPORT_TYPE_IE: 1105dc860a36Sspz if (ielength < 1) { 1106dc860a36Sspz if (!ndo->ndo_vflag) { 1107c74ad251Schristos ND_PRINT(", "); 1108dc860a36Sspz } 1109c74ad251Schristos ND_PRINT("Invalid REPORT TYPE IE"); 1110dc860a36Sspz return 1; 1111dc860a36Sspz } 1112b3a00663Schristos if (ndo->ndo_vflag) { 1113c74ad251Schristos ND_PRINT("%s (%u)", 1114c74ad251Schristos tok2str(fr_lmi_report_type_ie_values,"unknown",GET_U_1(p)), 1115c74ad251Schristos GET_U_1(p)); 11160f74e101Schristos } 11170f74e101Schristos return 1; 11180f74e101Schristos 11190f74e101Schristos case FR_LMI_ANSI_LINK_VERIFY_IE: /* fall through */ 11200f74e101Schristos case FR_LMI_CCITT_LINK_VERIFY_IE: 11210f74e101Schristos case FR_LMI_ANSI_LINK_VERIFY_IE_91: 1122b3a00663Schristos if (!ndo->ndo_vflag) { 1123c74ad251Schristos ND_PRINT(", "); 11240f74e101Schristos } 1125dc860a36Sspz if (ielength < 2) { 1126c74ad251Schristos ND_PRINT("Invalid LINK VERIFY IE"); 1127dc860a36Sspz return 1; 1128dc860a36Sspz } 1129c74ad251Schristos ND_PRINT("TX Seq: %3d, RX Seq: %3d", GET_U_1(p), GET_U_1(p + 1)); 11300f74e101Schristos return 1; 11310f74e101Schristos 11320f74e101Schristos case FR_LMI_ANSI_PVC_STATUS_IE: /* fall through */ 11330f74e101Schristos case FR_LMI_CCITT_PVC_STATUS_IE: 1134b3a00663Schristos if (!ndo->ndo_vflag) { 1135c74ad251Schristos ND_PRINT(", "); 11360f74e101Schristos } 11370f74e101Schristos /* now parse the DLCI information element. */ 1138dc860a36Sspz if ((ielength < 3) || 1139c74ad251Schristos (GET_U_1(p) & 0x80) || 1140c74ad251Schristos ((ielength == 3) && !(GET_U_1(p + 1) & 0x80)) || 1141c74ad251Schristos ((ielength == 4) && 1142c74ad251Schristos ((GET_U_1(p + 1) & 0x80) || !(GET_U_1(p + 2) & 0x80))) || 1143c74ad251Schristos ((ielength == 5) && 1144c74ad251Schristos ((GET_U_1(p + 1) & 0x80) || (GET_U_1(p + 2) & 0x80) || 1145c74ad251Schristos !(GET_U_1(p + 3) & 0x80))) || 1146dc860a36Sspz (ielength > 5) || 1147c74ad251Schristos !(GET_U_1(p + ielength - 1) & 0x80)) { 1148c74ad251Schristos ND_PRINT("Invalid DLCI in PVC STATUS IE"); 1149dc860a36Sspz return 1; 11500f74e101Schristos } 11510f74e101Schristos 1152c74ad251Schristos dlci = ((GET_U_1(p) & 0x3F) << 4) | ((GET_U_1(p + 1) & 0x78) >> 3); 1153dc860a36Sspz if (ielength == 4) { 1154c74ad251Schristos dlci = (dlci << 6) | ((GET_U_1(p + 2) & 0x7E) >> 1); 1155*26ba0b50Schristos } else if (ielength == 5) { 1156c74ad251Schristos dlci = (dlci << 13) | (GET_U_1(p + 2) & 0x7F) | ((GET_U_1(p + 3) & 0x7E) >> 1); 11570f74e101Schristos } 11580f74e101Schristos 1159c74ad251Schristos ND_PRINT("DLCI %u: status %s%s", dlci, 1160c74ad251Schristos GET_U_1(p + ielength - 1) & 0x8 ? "New, " : "", 1161c74ad251Schristos GET_U_1(p + ielength - 1) & 0x2 ? "Active" : "Inactive"); 11620f74e101Schristos return 1; 11630f74e101Schristos } 11640f74e101Schristos 11650f74e101Schristos return 0; 11660f74e101Schristos } 1167