1 /* 2 * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that: (1) source code distributions 7 * retain the above copyright notice and this paragraph in its entirety, (2) 8 * distributions including binary code include the above copyright notice and 9 * this paragraph in its entirety in the documentation or other materials 10 * provided with the distribution, and (3) all advertising materials mentioning 11 * features or use of this software display the following acknowledgement: 12 * ``This product includes software developed by the University of California, 13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 14 * the University nor the names of its contributors may be used to endorse 15 * or promote products derived from this software without specific prior 16 * written permission. 17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 20 */ 21 22 /* \summary: Frame Relay printer */ 23 24 #ifdef HAVE_CONFIG_H 25 #include <config.h> 26 #endif 27 28 #include "netdissect-stdinc.h" 29 30 #include <stdio.h> 31 #include <string.h> 32 33 #include "netdissect.h" 34 #include "addrtoname.h" 35 #include "ethertype.h" 36 #include "llc.h" 37 #include "nlpid.h" 38 #include "extract.h" 39 40 static void frf15_print(netdissect_options *ndo, const u_char *, u_int); 41 42 /* 43 * the frame relay header has a variable length 44 * 45 * the EA bit determines if there is another byte 46 * in the header 47 * 48 * minimum header length is 2 bytes 49 * maximum header length is 4 bytes 50 * 51 * 7 6 5 4 3 2 1 0 52 * +----+----+----+----+----+----+----+----+ 53 * | DLCI (6 bits) | CR | EA | 54 * +----+----+----+----+----+----+----+----+ 55 * | DLCI (4 bits) |FECN|BECN| DE | EA | 56 * +----+----+----+----+----+----+----+----+ 57 * | DLCI (7 bits) | EA | 58 * +----+----+----+----+----+----+----+----+ 59 * | DLCI (6 bits) |SDLC| EA | 60 * +----+----+----+----+----+----+----+----+ 61 */ 62 63 #define FR_EA_BIT 0x01 64 65 #define FR_CR_BIT 0x02000000 66 #define FR_DE_BIT 0x00020000 67 #define FR_BECN_BIT 0x00040000 68 #define FR_FECN_BIT 0x00080000 69 #define FR_SDLC_BIT 0x00000002 70 71 72 static const struct tok fr_header_flag_values[] = { 73 { FR_CR_BIT, "C!" }, 74 { FR_DE_BIT, "DE" }, 75 { FR_BECN_BIT, "BECN" }, 76 { FR_FECN_BIT, "FECN" }, 77 { FR_SDLC_BIT, "sdlcore" }, 78 { 0, NULL } 79 }; 80 81 /* FRF.15 / FRF.16 */ 82 #define MFR_B_BIT 0x80 83 #define MFR_E_BIT 0x40 84 #define MFR_C_BIT 0x20 85 #define MFR_BEC_MASK (MFR_B_BIT | MFR_E_BIT | MFR_C_BIT) 86 #define MFR_CTRL_FRAME (MFR_B_BIT | MFR_E_BIT | MFR_C_BIT) 87 #define MFR_FRAG_FRAME (MFR_B_BIT | MFR_E_BIT ) 88 89 static const struct tok frf_flag_values[] = { 90 { MFR_B_BIT, "Begin" }, 91 { MFR_E_BIT, "End" }, 92 { MFR_C_BIT, "Control" }, 93 { 0, NULL } 94 }; 95 96 /* Finds out Q.922 address length, DLCI and flags. Returns 1 on success, 97 * 0 on invalid address, -1 on truncated packet 98 * save the flags dep. on address length 99 */ 100 static int parse_q922_header(netdissect_options *ndo, 101 const u_char *p, u_int *dlci, 102 u_int *addr_len, uint32_t *flags, u_int length) 103 { 104 if (!ND_TTEST_1(p) || length < 1) 105 return -1; 106 if ((GET_U_1(p) & FR_EA_BIT)) 107 return 0; 108 109 if (!ND_TTEST_1(p + 1) || length < 2) 110 return -1; 111 *addr_len = 2; 112 *dlci = ((GET_U_1(p) & 0xFC) << 2) | ((GET_U_1(p + 1) & 0xF0) >> 4); 113 114 *flags = ((GET_U_1(p) & 0x02) << 24) | /* CR flag */ 115 ((GET_U_1(p + 1) & 0x0e) << 16); /* FECN,BECN,DE flags */ 116 117 if (GET_U_1(p + 1) & FR_EA_BIT) 118 return 1; /* 2-byte Q.922 address */ 119 120 p += 2; 121 length -= 2; 122 if (!ND_TTEST_1(p) || length < 1) 123 return -1; 124 (*addr_len)++; /* 3- or 4-byte Q.922 address */ 125 if ((GET_U_1(p) & FR_EA_BIT) == 0) { 126 *dlci = (*dlci << 7) | (GET_U_1(p) >> 1); 127 (*addr_len)++; /* 4-byte Q.922 address */ 128 p++; 129 length--; 130 } 131 132 if (!ND_TTEST_1(p) || length < 1) 133 return -1; 134 if ((GET_U_1(p) & FR_EA_BIT) == 0) 135 return 0; /* more than 4 bytes of Q.922 address? */ 136 137 *flags = *flags | (GET_U_1(p) & 0x02); /* SDLC flag */ 138 139 *dlci = (*dlci << 6) | (GET_U_1(p) >> 2); 140 141 return 1; 142 } 143 144 const char * 145 q922_string(netdissect_options *ndo, const u_char *p, u_int length) 146 { 147 148 static u_int dlci, addr_len; 149 static uint32_t flags; 150 static char buffer[sizeof("parse_q922_header() returned XXXXXXXXXXX")]; 151 int ret; 152 memset(buffer, 0, sizeof(buffer)); 153 154 ret = parse_q922_header(ndo, p, &dlci, &addr_len, &flags, length); 155 if (ret == 1) { 156 snprintf(buffer, sizeof(buffer), "DLCI %u", dlci); 157 return buffer; 158 } else if (ret == 0) { 159 return "<Invalid DLCI>"; 160 } else if (ret == -1) { 161 return "<Truncated>"; 162 } else { 163 snprintf(buffer, sizeof(buffer), "parse_q922_header() returned %d", ret); 164 return buffer; 165 } 166 } 167 168 169 /* Frame Relay packet structure, with flags and CRC removed 170 171 +---------------------------+ 172 | Q.922 Address* | 173 +-- --+ 174 | | 175 +---------------------------+ 176 | Control (UI = 0x03) | 177 +---------------------------+ 178 | Optional Pad (0x00) | 179 +---------------------------+ 180 | NLPID | 181 +---------------------------+ 182 | . | 183 | . | 184 | . | 185 | Data | 186 | . | 187 | . | 188 +---------------------------+ 189 190 * Q.922 addresses, as presently defined, are two octets and 191 contain a 10-bit DLCI. In some networks Q.922 addresses 192 may optionally be increased to three or four octets. 193 */ 194 195 static void 196 fr_hdr_print(netdissect_options *ndo, int length, u_int addr_len, 197 u_int dlci, uint32_t flags, uint16_t nlpid) 198 { 199 if (ndo->ndo_qflag) { 200 ND_PRINT("Q.922, DLCI %u, length %u: ", 201 dlci, 202 length); 203 } else { 204 if (nlpid <= 0xff) /* if its smaller than 256 then its a NLPID */ 205 ND_PRINT("Q.922, hdr-len %u, DLCI %u, Flags [%s], NLPID %s (0x%02x), length %u: ", 206 addr_len, 207 dlci, 208 bittok2str(fr_header_flag_values, "none", flags), 209 tok2str(nlpid_values,"unknown", nlpid), 210 nlpid, 211 length); 212 else /* must be an ethertype */ 213 ND_PRINT("Q.922, hdr-len %u, DLCI %u, Flags [%s], cisco-ethertype %s (0x%04x), length %u: ", 214 addr_len, 215 dlci, 216 bittok2str(fr_header_flag_values, "none", flags), 217 tok2str(ethertype_values, "unknown", nlpid), 218 nlpid, 219 length); 220 } 221 } 222 223 /* Frame Relay */ 224 void 225 fr_if_print(netdissect_options *ndo, 226 const struct pcap_pkthdr *h, const u_char *p) 227 { 228 u_int length = h->len; 229 u_int caplen = h->caplen; 230 231 ndo->ndo_protocol = "fr"; 232 if (caplen < 4) { /* minimum frame header length */ 233 nd_print_trunc(ndo); 234 ndo->ndo_ll_hdr_len += caplen; 235 return; 236 } 237 238 ndo->ndo_ll_hdr_len += fr_print(ndo, p, length); 239 } 240 241 u_int 242 fr_print(netdissect_options *ndo, 243 const u_char *p, u_int length) 244 { 245 int ret; 246 uint16_t extracted_ethertype; 247 u_int dlci; 248 u_int addr_len; 249 uint16_t nlpid; 250 u_int hdr_len; 251 uint32_t flags; 252 253 ndo->ndo_protocol = "fr"; 254 ret = parse_q922_header(ndo, p, &dlci, &addr_len, &flags, length); 255 if (ret == -1) 256 goto trunc; 257 if (ret == 0) { 258 ND_PRINT("Q.922, invalid address"); 259 return 0; 260 } 261 262 ND_TCHECK_1(p + addr_len); 263 if (length < addr_len + 1) 264 goto trunc; 265 266 if (GET_U_1(p + addr_len) != LLC_UI && dlci != 0) { 267 /* 268 * Let's figure out if we have Cisco-style encapsulation, 269 * with an Ethernet type (Cisco HDLC type?) following the 270 * address. 271 */ 272 if (!ND_TTEST_2(p + addr_len) || length < addr_len + 2) { 273 /* no Ethertype */ 274 ND_PRINT("UI %02x! ", GET_U_1(p + addr_len)); 275 } else { 276 extracted_ethertype = GET_BE_U_2(p + addr_len); 277 278 if (ndo->ndo_eflag) 279 fr_hdr_print(ndo, length, addr_len, dlci, 280 flags, extracted_ethertype); 281 282 if (ethertype_print(ndo, extracted_ethertype, 283 p+addr_len+ETHERTYPE_LEN, 284 length-addr_len-ETHERTYPE_LEN, 285 ND_BYTES_AVAILABLE_AFTER(p)-addr_len-ETHERTYPE_LEN, 286 NULL, NULL) == 0) 287 /* ether_type not known, probably it wasn't one */ 288 ND_PRINT("UI %02x! ", GET_U_1(p + addr_len)); 289 else 290 return addr_len + 2; 291 } 292 } 293 294 ND_TCHECK_1(p + addr_len + 1); 295 if (length < addr_len + 2) 296 goto trunc; 297 298 if (GET_U_1(p + addr_len + 1) == 0) { 299 /* 300 * Assume a pad byte after the control (UI) byte. 301 * A pad byte should only be used with 3-byte Q.922. 302 */ 303 if (addr_len != 3) 304 ND_PRINT("Pad! "); 305 hdr_len = addr_len + 1 /* UI */ + 1 /* pad */ + 1 /* NLPID */; 306 } else { 307 /* 308 * Not a pad byte. 309 * A pad byte should be used with 3-byte Q.922. 310 */ 311 if (addr_len == 3) 312 ND_PRINT("No pad! "); 313 hdr_len = addr_len + 1 /* UI */ + 1 /* NLPID */; 314 } 315 316 ND_TCHECK_1(p + hdr_len - 1); 317 if (length < hdr_len) 318 goto trunc; 319 nlpid = GET_U_1(p + hdr_len - 1); 320 321 if (ndo->ndo_eflag) 322 fr_hdr_print(ndo, length, addr_len, dlci, flags, nlpid); 323 p += hdr_len; 324 length -= hdr_len; 325 326 switch (nlpid) { 327 case NLPID_IP: 328 ip_print(ndo, p, length); 329 break; 330 331 case NLPID_IP6: 332 ip6_print(ndo, p, length); 333 break; 334 335 case NLPID_CLNP: 336 case NLPID_ESIS: 337 case NLPID_ISIS: 338 isoclns_print(ndo, p - 1, length + 1); /* OSI printers need the NLPID field */ 339 break; 340 341 case NLPID_SNAP: 342 if (snap_print(ndo, p, length, ND_BYTES_AVAILABLE_AFTER(p), NULL, NULL, 0) == 0) { 343 /* ether_type not known, print raw packet */ 344 if (!ndo->ndo_eflag) 345 fr_hdr_print(ndo, length + hdr_len, hdr_len, 346 dlci, flags, nlpid); 347 if (!ndo->ndo_suppress_default_print) 348 ND_DEFAULTPRINT(p - hdr_len, length + hdr_len); 349 } 350 break; 351 352 case NLPID_Q933: 353 q933_print(ndo, p, length); 354 break; 355 356 case NLPID_MFR: 357 frf15_print(ndo, p, length); 358 break; 359 360 case NLPID_PPP: 361 ppp_print(ndo, p, length); 362 break; 363 364 default: 365 if (!ndo->ndo_eflag) 366 fr_hdr_print(ndo, length + hdr_len, addr_len, 367 dlci, flags, nlpid); 368 if (!ndo->ndo_xflag) 369 ND_DEFAULTPRINT(p, length); 370 } 371 372 return hdr_len; 373 374 trunc: 375 nd_print_trunc(ndo); 376 return 0; 377 378 } 379 380 /* Multi Link Frame Relay (FRF.16) */ 381 void 382 mfr_if_print(netdissect_options *ndo, 383 const struct pcap_pkthdr *h, const u_char *p) 384 { 385 u_int length = h->len; 386 u_int caplen = h->caplen; 387 388 ndo->ndo_protocol = "mfr"; 389 if (caplen < 2) { /* minimum frame header length */ 390 nd_print_trunc(ndo); 391 ndo->ndo_ll_hdr_len += caplen; 392 return; 393 } 394 395 ndo->ndo_ll_hdr_len += mfr_print(ndo, p, length); 396 } 397 398 399 #define MFR_CTRL_MSG_ADD_LINK 1 400 #define MFR_CTRL_MSG_ADD_LINK_ACK 2 401 #define MFR_CTRL_MSG_ADD_LINK_REJ 3 402 #define MFR_CTRL_MSG_HELLO 4 403 #define MFR_CTRL_MSG_HELLO_ACK 5 404 #define MFR_CTRL_MSG_REMOVE_LINK 6 405 #define MFR_CTRL_MSG_REMOVE_LINK_ACK 7 406 407 static const struct tok mfr_ctrl_msg_values[] = { 408 { MFR_CTRL_MSG_ADD_LINK, "Add Link" }, 409 { MFR_CTRL_MSG_ADD_LINK_ACK, "Add Link ACK" }, 410 { MFR_CTRL_MSG_ADD_LINK_REJ, "Add Link Reject" }, 411 { MFR_CTRL_MSG_HELLO, "Hello" }, 412 { MFR_CTRL_MSG_HELLO_ACK, "Hello ACK" }, 413 { MFR_CTRL_MSG_REMOVE_LINK, "Remove Link" }, 414 { MFR_CTRL_MSG_REMOVE_LINK_ACK, "Remove Link ACK" }, 415 { 0, NULL } 416 }; 417 418 #define MFR_CTRL_IE_BUNDLE_ID 1 419 #define MFR_CTRL_IE_LINK_ID 2 420 #define MFR_CTRL_IE_MAGIC_NUM 3 421 #define MFR_CTRL_IE_TIMESTAMP 5 422 #define MFR_CTRL_IE_VENDOR_EXT 6 423 #define MFR_CTRL_IE_CAUSE 7 424 425 static const struct tok mfr_ctrl_ie_values[] = { 426 { MFR_CTRL_IE_BUNDLE_ID, "Bundle ID"}, 427 { MFR_CTRL_IE_LINK_ID, "Link ID"}, 428 { MFR_CTRL_IE_MAGIC_NUM, "Magic Number"}, 429 { MFR_CTRL_IE_TIMESTAMP, "Timestamp"}, 430 { MFR_CTRL_IE_VENDOR_EXT, "Vendor Extension"}, 431 { MFR_CTRL_IE_CAUSE, "Cause"}, 432 { 0, NULL } 433 }; 434 435 #define MFR_ID_STRING_MAXLEN 50 436 437 struct ie_tlv_header_t { 438 uint8_t ie_type; 439 uint8_t ie_len; 440 }; 441 442 u_int 443 mfr_print(netdissect_options *ndo, 444 const u_char *p, u_int length) 445 { 446 u_int tlen,idx,hdr_len = 0; 447 uint16_t sequence_num; 448 uint8_t ie_type,ie_len; 449 const uint8_t *tptr; 450 451 452 /* 453 * FRF.16 Link Integrity Control Frame 454 * 455 * 7 6 5 4 3 2 1 0 456 * +----+----+----+----+----+----+----+----+ 457 * | B | E | C=1| 0 0 0 0 | EA | 458 * +----+----+----+----+----+----+----+----+ 459 * | 0 0 0 0 0 0 0 0 | 460 * +----+----+----+----+----+----+----+----+ 461 * | message type | 462 * +----+----+----+----+----+----+----+----+ 463 */ 464 465 ndo->ndo_protocol = "mfr"; 466 467 if (length < 4) { /* minimum frame header length */ 468 ND_PRINT("[length %u < 4]", length); 469 nd_print_invalid(ndo); 470 return length; 471 } 472 ND_TCHECK_4(p); 473 474 if ((GET_U_1(p) & MFR_BEC_MASK) == MFR_CTRL_FRAME && GET_U_1(p + 1) == 0) { 475 ND_PRINT("FRF.16 Control, Flags [%s], %s, length %u", 476 bittok2str(frf_flag_values,"none",(GET_U_1(p) & MFR_BEC_MASK)), 477 tok2str(mfr_ctrl_msg_values,"Unknown Message (0x%02x)",GET_U_1(p + 2)), 478 length); 479 tptr = p + 3; 480 tlen = length -3; 481 hdr_len = 3; 482 483 if (!ndo->ndo_vflag) 484 return hdr_len; 485 486 while (tlen>sizeof(struct ie_tlv_header_t)) { 487 ND_TCHECK_LEN(tptr, sizeof(struct ie_tlv_header_t)); 488 ie_type=GET_U_1(tptr); 489 ie_len=GET_U_1(tptr + 1); 490 491 ND_PRINT("\n\tIE %s (%u), length %u: ", 492 tok2str(mfr_ctrl_ie_values,"Unknown",ie_type), 493 ie_type, 494 ie_len); 495 496 /* infinite loop check */ 497 if (ie_type == 0 || ie_len <= sizeof(struct ie_tlv_header_t)) 498 return hdr_len; 499 500 ND_TCHECK_LEN(tptr, ie_len); 501 tptr+=sizeof(struct ie_tlv_header_t); 502 /* tlv len includes header */ 503 ie_len-=sizeof(struct ie_tlv_header_t); 504 tlen-=sizeof(struct ie_tlv_header_t); 505 506 switch (ie_type) { 507 508 case MFR_CTRL_IE_MAGIC_NUM: 509 /* FRF.16.1 Section 3.4.3 Magic Number Information Element */ 510 if (ie_len != 4) { 511 ND_PRINT("[IE data length %d != 4]", ie_len); 512 nd_print_invalid(ndo); 513 break; 514 } 515 ND_PRINT("0x%08x", GET_BE_U_4(tptr)); 516 break; 517 518 case MFR_CTRL_IE_BUNDLE_ID: /* same message format */ 519 case MFR_CTRL_IE_LINK_ID: 520 for (idx = 0; idx < ie_len && idx < MFR_ID_STRING_MAXLEN; idx++) { 521 if (GET_U_1(tptr + idx) != 0) /* don't print null termination */ 522 fn_print_char(ndo, GET_U_1(tptr + idx)); 523 else 524 break; 525 } 526 break; 527 528 case MFR_CTRL_IE_TIMESTAMP: 529 if (ie_len == sizeof(struct timeval)) { 530 ts_print(ndo, (const struct timeval *)tptr); 531 break; 532 } 533 /* fall through and hexdump if no unix timestamp */ 534 ND_FALL_THROUGH; 535 536 /* 537 * FIXME those are the defined IEs that lack a decoder 538 * you are welcome to contribute code ;-) 539 */ 540 541 case MFR_CTRL_IE_VENDOR_EXT: 542 case MFR_CTRL_IE_CAUSE: 543 544 default: 545 if (ndo->ndo_vflag <= 1) 546 print_unknown_data(ndo, tptr, "\n\t ", ie_len); 547 break; 548 } 549 550 /* do we want to see a hexdump of the IE ? */ 551 if (ndo->ndo_vflag > 1 ) 552 print_unknown_data(ndo, tptr, "\n\t ", ie_len); 553 554 tlen-=ie_len; 555 tptr+=ie_len; 556 } 557 return hdr_len; 558 } 559 /* 560 * FRF.16 Fragmentation Frame 561 * 562 * 7 6 5 4 3 2 1 0 563 * +----+----+----+----+----+----+----+----+ 564 * | B | E | C=0|seq. (high 4 bits) | EA | 565 * +----+----+----+----+----+----+----+----+ 566 * | sequence (low 8 bits) | 567 * +----+----+----+----+----+----+----+----+ 568 * | DLCI (6 bits) | CR | EA | 569 * +----+----+----+----+----+----+----+----+ 570 * | DLCI (4 bits) |FECN|BECN| DE | EA | 571 * +----+----+----+----+----+----+----+----+ 572 */ 573 574 sequence_num = (GET_U_1(p)&0x1e)<<7 | GET_U_1(p + 1); 575 /* whole packet or first fragment ? */ 576 if ((GET_U_1(p) & MFR_BEC_MASK) == MFR_FRAG_FRAME || 577 (GET_U_1(p) & MFR_BEC_MASK) == MFR_B_BIT) { 578 ND_PRINT("FRF.16 Frag, seq %u, Flags [%s], ", 579 sequence_num, 580 bittok2str(frf_flag_values,"none",(GET_U_1(p) & MFR_BEC_MASK))); 581 hdr_len = 2; 582 fr_print(ndo, p+hdr_len,length-hdr_len); 583 return hdr_len; 584 } 585 586 /* must be a middle or the last fragment */ 587 ND_PRINT("FRF.16 Frag, seq %u, Flags [%s]", 588 sequence_num, 589 bittok2str(frf_flag_values,"none",(GET_U_1(p) & MFR_BEC_MASK))); 590 print_unknown_data(ndo, p, "\n\t", length); 591 592 return hdr_len; 593 594 trunc: 595 nd_print_trunc(ndo); 596 return length; 597 } 598 599 /* an NLPID of 0xb1 indicates a 2-byte 600 * FRF.15 header 601 * 602 * 7 6 5 4 3 2 1 0 603 * +----+----+----+----+----+----+----+----+ 604 * ~ Q.922 header ~ 605 * +----+----+----+----+----+----+----+----+ 606 * | NLPID (8 bits) | NLPID=0xb1 607 * +----+----+----+----+----+----+----+----+ 608 * | B | E | C |seq. (high 4 bits) | R | 609 * +----+----+----+----+----+----+----+----+ 610 * | sequence (low 8 bits) | 611 * +----+----+----+----+----+----+----+----+ 612 */ 613 614 #define FR_FRF15_FRAGTYPE 0x01 615 616 static void 617 frf15_print(netdissect_options *ndo, 618 const u_char *p, u_int length) 619 { 620 uint16_t sequence_num, flags; 621 622 if (length < 2) 623 goto trunc; 624 625 flags = GET_U_1(p)&MFR_BEC_MASK; 626 sequence_num = (GET_U_1(p)&0x1e)<<7 | GET_U_1(p + 1); 627 628 ND_PRINT("FRF.15, seq 0x%03x, Flags [%s],%s Fragmentation, length %u", 629 sequence_num, 630 bittok2str(frf_flag_values,"none",flags), 631 GET_U_1(p)&FR_FRF15_FRAGTYPE ? "Interface" : "End-to-End", 632 length); 633 634 /* TODO: 635 * depending on all permutations of the B, E and C bit 636 * dig as deep as we can - e.g. on the first (B) fragment 637 * there is enough payload to print the IP header 638 * on non (B) fragments it depends if the fragmentation 639 * model is end-to-end or interface based whether we want to print 640 * another Q.922 header 641 */ 642 return; 643 644 trunc: 645 nd_print_trunc(ndo); 646 } 647 648 /* 649 * Q.933 decoding portion for framerelay specific. 650 */ 651 652 /* Q.933 packet format 653 Format of Other Protocols 654 using Q.933 NLPID 655 +-------------------------------+ 656 | Q.922 Address | 657 +---------------+---------------+ 658 |Control 0x03 | NLPID 0x08 | 659 +---------------+---------------+ 660 | L2 Protocol ID | 661 | octet 1 | octet 2 | 662 +-------------------------------+ 663 | L3 Protocol ID | 664 | octet 2 | octet 2 | 665 +-------------------------------+ 666 | Protocol Data | 667 +-------------------------------+ 668 | FCS | 669 +-------------------------------+ 670 */ 671 672 /* L2 (Octet 1)- Call Reference Usually is 0x0 */ 673 674 /* 675 * L2 (Octet 2)- Message Types definition 1 byte long. 676 */ 677 /* Call Establish */ 678 #define MSG_TYPE_ESC_TO_NATIONAL 0x00 679 #define MSG_TYPE_ALERT 0x01 680 #define MSG_TYPE_CALL_PROCEEDING 0x02 681 #define MSG_TYPE_CONNECT 0x07 682 #define MSG_TYPE_CONNECT_ACK 0x0F 683 #define MSG_TYPE_PROGRESS 0x03 684 #define MSG_TYPE_SETUP 0x05 685 /* Call Clear */ 686 #define MSG_TYPE_DISCONNECT 0x45 687 #define MSG_TYPE_RELEASE 0x4D 688 #define MSG_TYPE_RELEASE_COMPLETE 0x5A 689 #define MSG_TYPE_RESTART 0x46 690 #define MSG_TYPE_RESTART_ACK 0x4E 691 /* Status */ 692 #define MSG_TYPE_STATUS 0x7D 693 #define MSG_TYPE_STATUS_ENQ 0x75 694 695 static const struct tok fr_q933_msg_values[] = { 696 { MSG_TYPE_ESC_TO_NATIONAL, "ESC to National" }, 697 { MSG_TYPE_ALERT, "Alert" }, 698 { MSG_TYPE_CALL_PROCEEDING, "Call proceeding" }, 699 { MSG_TYPE_CONNECT, "Connect" }, 700 { MSG_TYPE_CONNECT_ACK, "Connect ACK" }, 701 { MSG_TYPE_PROGRESS, "Progress" }, 702 { MSG_TYPE_SETUP, "Setup" }, 703 { MSG_TYPE_DISCONNECT, "Disconnect" }, 704 { MSG_TYPE_RELEASE, "Release" }, 705 { MSG_TYPE_RELEASE_COMPLETE, "Release Complete" }, 706 { MSG_TYPE_RESTART, "Restart" }, 707 { MSG_TYPE_RESTART_ACK, "Restart ACK" }, 708 { MSG_TYPE_STATUS, "Status Reply" }, 709 { MSG_TYPE_STATUS_ENQ, "Status Enquiry" }, 710 { 0, NULL } 711 }; 712 713 #define IE_IS_SINGLE_OCTET(iecode) ((iecode) & 0x80) 714 #define IE_IS_SHIFT(iecode) (((iecode) & 0xF0) == 0x90) 715 #define IE_SHIFT_IS_NON_LOCKING(iecode) ((iecode) & 0x08) 716 #define IE_SHIFT_IS_LOCKING(iecode) (!(IE_SHIFT_IS_NON_LOCKING(iecode))) 717 #define IE_SHIFT_CODESET(iecode) ((iecode) & 0x07) 718 719 #define FR_LMI_ANSI_REPORT_TYPE_IE 0x01 720 #define FR_LMI_ANSI_LINK_VERIFY_IE_91 0x19 /* details? */ 721 #define FR_LMI_ANSI_LINK_VERIFY_IE 0x03 722 #define FR_LMI_ANSI_PVC_STATUS_IE 0x07 723 724 #define FR_LMI_CCITT_REPORT_TYPE_IE 0x51 725 #define FR_LMI_CCITT_LINK_VERIFY_IE 0x53 726 #define FR_LMI_CCITT_PVC_STATUS_IE 0x57 727 728 static const struct tok fr_q933_ie_values_codeset_0_5[] = { 729 { FR_LMI_ANSI_REPORT_TYPE_IE, "ANSI Report Type" }, 730 { FR_LMI_ANSI_LINK_VERIFY_IE_91, "ANSI Link Verify" }, 731 { FR_LMI_ANSI_LINK_VERIFY_IE, "ANSI Link Verify" }, 732 { FR_LMI_ANSI_PVC_STATUS_IE, "ANSI PVC Status" }, 733 { FR_LMI_CCITT_REPORT_TYPE_IE, "CCITT Report Type" }, 734 { FR_LMI_CCITT_LINK_VERIFY_IE, "CCITT Link Verify" }, 735 { FR_LMI_CCITT_PVC_STATUS_IE, "CCITT PVC Status" }, 736 { 0, NULL } 737 }; 738 739 #define FR_LMI_REPORT_TYPE_IE_FULL_STATUS 0 740 #define FR_LMI_REPORT_TYPE_IE_LINK_VERIFY 1 741 #define FR_LMI_REPORT_TYPE_IE_ASYNC_PVC 2 742 743 static const struct tok fr_lmi_report_type_ie_values[] = { 744 { FR_LMI_REPORT_TYPE_IE_FULL_STATUS, "Full Status" }, 745 { FR_LMI_REPORT_TYPE_IE_LINK_VERIFY, "Link verify" }, 746 { FR_LMI_REPORT_TYPE_IE_ASYNC_PVC, "Async PVC Status" }, 747 { 0, NULL } 748 }; 749 750 /* array of 16 codesets - currently we only support codepage 0 and 5 */ 751 static const struct tok *fr_q933_ie_codesets[] = { 752 fr_q933_ie_values_codeset_0_5, 753 NULL, 754 NULL, 755 NULL, 756 NULL, 757 fr_q933_ie_values_codeset_0_5, 758 NULL, 759 NULL, 760 NULL, 761 NULL, 762 NULL, 763 NULL, 764 NULL, 765 NULL, 766 NULL, 767 NULL 768 }; 769 770 static int fr_q933_print_ie_codeset_0_5(netdissect_options *ndo, u_int iecode, 771 u_int ielength, const u_char *p); 772 773 typedef int (*codeset_pr_func_t)(netdissect_options *, u_int iecode, 774 u_int ielength, const u_char *p); 775 776 /* array of 16 codesets - currently we only support codepage 0 and 5 */ 777 static const codeset_pr_func_t fr_q933_print_ie_codeset[] = { 778 fr_q933_print_ie_codeset_0_5, 779 NULL, 780 NULL, 781 NULL, 782 NULL, 783 fr_q933_print_ie_codeset_0_5, 784 NULL, 785 NULL, 786 NULL, 787 NULL, 788 NULL, 789 NULL, 790 NULL, 791 NULL, 792 NULL, 793 NULL 794 }; 795 796 /* 797 * ITU-T Q.933. 798 * 799 * p points to octet 2, the octet containing the length of the 800 * call reference value, so p[n] is octet n+2 ("octet X" is as 801 * used in Q.931/Q.933). 802 * 803 * XXX - actually used both for Q.931 and Q.933. 804 */ 805 void 806 q933_print(netdissect_options *ndo, 807 const u_char *p, u_int length) 808 { 809 u_int olen; 810 u_int call_ref_length, i; 811 uint8_t call_ref[15]; /* maximum length - length field is 4 bits */ 812 u_int msgtype; 813 u_int iecode; 814 u_int ielength; 815 u_int codeset = 0; 816 u_int is_ansi = 0; 817 u_int ie_is_known; 818 u_int non_locking_shift; 819 u_int unshift_codeset; 820 821 ndo->ndo_protocol = "q.933"; 822 ND_PRINT("%s", ndo->ndo_eflag ? "" : "Q.933"); 823 824 if (length == 0 || !ND_TTEST_1(p)) { 825 if (!ndo->ndo_eflag) 826 ND_PRINT(", "); 827 ND_PRINT("length %u", length); 828 goto trunc; 829 } 830 831 /* 832 * Get the length of the call reference value. 833 */ 834 olen = length; /* preserve the original length for display */ 835 call_ref_length = GET_U_1(p) & 0x0f; 836 p++; 837 length--; 838 839 /* 840 * Get the call reference value. 841 */ 842 for (i = 0; i < call_ref_length; i++) { 843 if (length == 0 || !ND_TTEST_1(p)) { 844 if (!ndo->ndo_eflag) 845 ND_PRINT(", "); 846 ND_PRINT("length %u", olen); 847 goto trunc; 848 } 849 call_ref[i] = GET_U_1(p); 850 p++; 851 length--; 852 } 853 854 /* 855 * Get the message type. 856 */ 857 if (length == 0 || !ND_TTEST_1(p)) { 858 if (!ndo->ndo_eflag) 859 ND_PRINT(", "); 860 ND_PRINT("length %u", olen); 861 goto trunc; 862 } 863 msgtype = GET_U_1(p); 864 p++; 865 length--; 866 867 /* 868 * Peek ahead to see if we start with a shift. 869 */ 870 non_locking_shift = 0; 871 unshift_codeset = codeset; 872 if (length != 0) { 873 if (!ND_TTEST_1(p)) { 874 if (!ndo->ndo_eflag) 875 ND_PRINT(", "); 876 ND_PRINT("length %u", olen); 877 goto trunc; 878 } 879 iecode = GET_U_1(p); 880 if (IE_IS_SHIFT(iecode)) { 881 /* 882 * It's a shift. Skip over it. 883 */ 884 p++; 885 length--; 886 887 /* 888 * Get the codeset. 889 */ 890 codeset = IE_SHIFT_CODESET(iecode); 891 892 /* 893 * If it's a locking shift to codeset 5, 894 * mark this as ANSI. (XXX - 5 is actually 895 * for national variants in general, not 896 * the US variant in particular, but maybe 897 * this is more American exceptionalism. :-)) 898 */ 899 if (IE_SHIFT_IS_LOCKING(iecode)) { 900 /* 901 * It's a locking shift. 902 */ 903 if (codeset == 5) { 904 /* 905 * It's a locking shift to 906 * codeset 5, so this is 907 * T1.617 Annex D. 908 */ 909 is_ansi = 1; 910 } 911 } else { 912 /* 913 * It's a non-locking shift. 914 * Remember the current codeset, so we 915 * can revert to it after the next IE. 916 */ 917 non_locking_shift = 1; 918 unshift_codeset = 0; 919 } 920 } 921 } 922 923 /* printing out header part */ 924 if (!ndo->ndo_eflag) 925 ND_PRINT(", "); 926 ND_PRINT("%s, codeset %u", is_ansi ? "ANSI" : "CCITT", codeset); 927 928 if (call_ref_length != 0) { 929 if (call_ref_length > 1 || GET_U_1(p) != 0) { 930 /* 931 * Not a dummy call reference. 932 */ 933 ND_PRINT(", Call Ref: 0x"); 934 for (i = 0; i < call_ref_length; i++) 935 ND_PRINT("%02x", call_ref[i]); 936 } 937 } 938 if (ndo->ndo_vflag) { 939 ND_PRINT(", %s (0x%02x), length %u", 940 tok2str(fr_q933_msg_values, 941 "unknown message", msgtype), 942 msgtype, 943 olen); 944 } else { 945 ND_PRINT(", %s", 946 tok2str(fr_q933_msg_values, 947 "unknown message 0x%02x", msgtype)); 948 } 949 950 /* Loop through the rest of the IEs */ 951 while (length != 0) { 952 /* 953 * What's the state of any non-locking shifts? 954 */ 955 if (non_locking_shift == 1) { 956 /* 957 * There's a non-locking shift in effect for 958 * this IE. Count it, so we reset the codeset 959 * before the next IE. 960 */ 961 non_locking_shift = 2; 962 } else if (non_locking_shift == 2) { 963 /* 964 * Unshift. 965 */ 966 codeset = unshift_codeset; 967 non_locking_shift = 0; 968 } 969 970 /* 971 * Get the first octet of the IE. 972 */ 973 if (!ND_TTEST_1(p)) { 974 if (!ndo->ndo_vflag) { 975 ND_PRINT(", length %u", olen); 976 } 977 goto trunc; 978 } 979 iecode = GET_U_1(p); 980 p++; 981 length--; 982 983 /* Single-octet IE? */ 984 if (IE_IS_SINGLE_OCTET(iecode)) { 985 /* 986 * Yes. Is it a shift? 987 */ 988 if (IE_IS_SHIFT(iecode)) { 989 /* 990 * Yes. Is it locking? 991 */ 992 if (IE_SHIFT_IS_LOCKING(iecode)) { 993 /* 994 * Yes. 995 */ 996 non_locking_shift = 0; 997 } else { 998 /* 999 * No. Remember the current 1000 * codeset, so we can revert 1001 * to it after the next IE. 1002 */ 1003 non_locking_shift = 1; 1004 unshift_codeset = codeset; 1005 } 1006 1007 /* 1008 * Get the codeset. 1009 */ 1010 codeset = IE_SHIFT_CODESET(iecode); 1011 } 1012 } else { 1013 /* 1014 * No. Get the IE length. 1015 */ 1016 if (length == 0 || !ND_TTEST_1(p)) { 1017 if (!ndo->ndo_vflag) { 1018 ND_PRINT(", length %u", olen); 1019 } 1020 goto trunc; 1021 } 1022 ielength = GET_U_1(p); 1023 p++; 1024 length--; 1025 1026 /* lets do the full IE parsing only in verbose mode 1027 * however some IEs (DLCI Status, Link Verify) 1028 * are also interesting in non-verbose mode */ 1029 if (ndo->ndo_vflag) { 1030 ND_PRINT("\n\t%s IE (0x%02x), length %u: ", 1031 tok2str(fr_q933_ie_codesets[codeset], 1032 "unknown", iecode), 1033 iecode, 1034 ielength); 1035 } 1036 1037 /* sanity checks */ 1038 if (iecode == 0 || ielength == 0) { 1039 return; 1040 } 1041 if (length < ielength || !ND_TTEST_LEN(p, ielength)) { 1042 if (!ndo->ndo_vflag) { 1043 ND_PRINT(", length %u", olen); 1044 } 1045 goto trunc; 1046 } 1047 1048 ie_is_known = 0; 1049 if (fr_q933_print_ie_codeset[codeset] != NULL) { 1050 ie_is_known = fr_q933_print_ie_codeset[codeset](ndo, iecode, ielength, p); 1051 } 1052 1053 if (ie_is_known) { 1054 /* 1055 * Known IE; do we want to see a hexdump 1056 * of it? 1057 */ 1058 if (ndo->ndo_vflag > 1) { 1059 /* Yes. */ 1060 print_unknown_data(ndo, p, "\n\t ", ielength); 1061 } 1062 } else { 1063 /* 1064 * Unknown IE; if we're printing verbosely, 1065 * print its content in hex. 1066 */ 1067 if (ndo->ndo_vflag >= 1) { 1068 print_unknown_data(ndo, p, "\n\t", ielength); 1069 } 1070 } 1071 1072 length -= ielength; 1073 p += ielength; 1074 } 1075 } 1076 if (!ndo->ndo_vflag) { 1077 ND_PRINT(", length %u", olen); 1078 } 1079 return; 1080 1081 trunc: 1082 nd_print_trunc(ndo); 1083 } 1084 1085 static int 1086 fr_q933_print_ie_codeset_0_5(netdissect_options *ndo, u_int iecode, 1087 u_int ielength, const u_char *p) 1088 { 1089 u_int dlci; 1090 1091 switch (iecode) { 1092 1093 case FR_LMI_ANSI_REPORT_TYPE_IE: /* fall through */ 1094 case FR_LMI_CCITT_REPORT_TYPE_IE: 1095 if (ielength < 1) { 1096 if (!ndo->ndo_vflag) { 1097 ND_PRINT(", "); 1098 } 1099 ND_PRINT("Invalid REPORT TYPE IE"); 1100 return 1; 1101 } 1102 if (ndo->ndo_vflag) { 1103 ND_PRINT("%s (%u)", 1104 tok2str(fr_lmi_report_type_ie_values,"unknown",GET_U_1(p)), 1105 GET_U_1(p)); 1106 } 1107 return 1; 1108 1109 case FR_LMI_ANSI_LINK_VERIFY_IE: /* fall through */ 1110 case FR_LMI_CCITT_LINK_VERIFY_IE: 1111 case FR_LMI_ANSI_LINK_VERIFY_IE_91: 1112 if (!ndo->ndo_vflag) { 1113 ND_PRINT(", "); 1114 } 1115 if (ielength < 2) { 1116 ND_PRINT("Invalid LINK VERIFY IE"); 1117 return 1; 1118 } 1119 ND_PRINT("TX Seq: %3d, RX Seq: %3d", GET_U_1(p), GET_U_1(p + 1)); 1120 return 1; 1121 1122 case FR_LMI_ANSI_PVC_STATUS_IE: /* fall through */ 1123 case FR_LMI_CCITT_PVC_STATUS_IE: 1124 if (!ndo->ndo_vflag) { 1125 ND_PRINT(", "); 1126 } 1127 /* now parse the DLCI information element. */ 1128 if ((ielength < 3) || 1129 (GET_U_1(p) & 0x80) || 1130 ((ielength == 3) && !(GET_U_1(p + 1) & 0x80)) || 1131 ((ielength == 4) && 1132 ((GET_U_1(p + 1) & 0x80) || !(GET_U_1(p + 2) & 0x80))) || 1133 ((ielength == 5) && 1134 ((GET_U_1(p + 1) & 0x80) || (GET_U_1(p + 2) & 0x80) || 1135 !(GET_U_1(p + 3) & 0x80))) || 1136 (ielength > 5) || 1137 !(GET_U_1(p + ielength - 1) & 0x80)) { 1138 ND_PRINT("Invalid DLCI in PVC STATUS IE"); 1139 return 1; 1140 } 1141 1142 dlci = ((GET_U_1(p) & 0x3F) << 4) | ((GET_U_1(p + 1) & 0x78) >> 3); 1143 if (ielength == 4) { 1144 dlci = (dlci << 6) | ((GET_U_1(p + 2) & 0x7E) >> 1); 1145 } 1146 else if (ielength == 5) { 1147 dlci = (dlci << 13) | (GET_U_1(p + 2) & 0x7F) | ((GET_U_1(p + 3) & 0x7E) >> 1); 1148 } 1149 1150 ND_PRINT("DLCI %u: status %s%s", dlci, 1151 GET_U_1(p + ielength - 1) & 0x8 ? "New, " : "", 1152 GET_U_1(p + ielength - 1) & 0x2 ? "Active" : "Inactive"); 1153 return 1; 1154 } 1155 1156 return 0; 1157 } 1158