"Fossies" - the Fresh Open Source Software Archive

Member "tcpdump-4.99.1/./print-fr.c" (7 Jun 2021, 33087 Bytes) of package /linux/misc/tcpdump-4.99.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "print-fr.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 4.99.0_vs_4.99.1.

    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 }