]> The Tcpdump Group git mirrors - tcpdump/blobdiff - print-cfm.c
Use more the EXTRACT_U_1() macro (40/n)
[tcpdump] / print-cfm.c
index 43ad438c6a4040d2f2d4e8a991dbbf5457ceeee6..2a2485e96d7d7f69fe1227a89ab31c0b583c2d0b 100644 (file)
@@ -12,7 +12,7 @@
  * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  * FOR A PARTICULAR PURPOSE.
  *
- * Original code by Hannes Gredler (hannes@juniper.net)
+ * Original code by Hannes Gredler (hannes@gredler.at)
  */
 
 /* \summary: IEEE 802.1ag Connectivity Fault Management (CFM) protocols printer */
@@ -50,7 +50,7 @@ struct cfm_common_header_t {
 #define        CFM_OPCODE_LTM 5
 
 static const struct tok cfm_opcode_values[] = {
-    { CFM_OPCODE_CCM, "Continouity Check Message"},
+    { CFM_OPCODE_CCM, "Continuity Check Message"},
     { CFM_OPCODE_LBR, "Loopback Reply"},
     { CFM_OPCODE_LBM, "Loopback Message"},
     { CFM_OPCODE_LTR, "Linktrace Reply"},
@@ -217,17 +217,22 @@ static const struct tok cfm_tlv_senderid_chassisid_values[] = {
 
 static int
 cfm_network_addr_print(netdissect_options *ndo,
-                       register const u_char *tptr)
+                       register const u_char *tptr, const u_int length)
 {
     u_int network_addr_type;
     u_int hexdump =  FALSE;
 
     /*
-     * Altough AFIs are tpically 2 octects wide,
+     * Although AFIs are typically 2 octects wide,
      * 802.1ab specifies that this field width
-     * is only once octet
+     * is only one octet.
      */
-    network_addr_type = *tptr;
+    if (length < 1) {
+        ND_PRINT((ndo, "\n\t  Network Address Type (invalid, no data"));
+        return hexdump;
+    }
+    /* The calling function must make any due ND_TCHECK calls. */
+    network_addr_type = EXTRACT_U_1(tptr);
     ND_PRINT((ndo, "\n\t  Network Address Type %s (%u)",
            tok2str(af_values, "Unknown", network_addr_type),
            network_addr_type));
@@ -237,10 +242,20 @@ cfm_network_addr_print(netdissect_options *ndo,
      */
     switch(network_addr_type) {
     case AFNUM_INET:
+        if (length != 1 + 4) {
+            ND_PRINT((ndo, "(invalid IPv4 address length %u)", length - 1));
+            hexdump = TRUE;
+            break;
+        }
         ND_PRINT((ndo, ", %s", ipaddr_string(ndo, tptr + 1)));
         break;
 
     case AFNUM_INET6:
+        if (length != 1 + 16) {
+            ND_PRINT((ndo, "(invalid IPv6 address length %u)", length - 1));
+            hexdump = TRUE;
+            break;
+        }
         ND_PRINT((ndo, ", %s", ip6addr_string(ndo, tptr + 1)));
         break;
 
@@ -305,7 +320,7 @@ cfm_print(netdissect_options *ndo,
 
     ND_PRINT((ndo, "\n\tFirst TLV offset %u", cfm_common_header->first_tlv_offset));
 
-    tptr += sizeof(const struct cfm_common_header_t);
+    tptr += sizeof(struct cfm_common_header_t);
     tlen = length - sizeof(struct cfm_common_header_t);
 
     /*
@@ -346,8 +361,8 @@ cfm_print(netdissect_options *ndo,
         }
 
         ND_PRINT((ndo, "\n\t  Sequence Number 0x%08x, MA-End-Point-ID 0x%04x",
-               EXTRACT_32BITS(msg_ptr.cfm_ccm->sequence),
-               EXTRACT_16BITS(msg_ptr.cfm_ccm->ma_epi)));
+               EXTRACT_BE_U_4(msg_ptr.cfm_ccm->sequence),
+               EXTRACT_BE_U_2(msg_ptr.cfm_ccm->ma_epi)));
 
         namesp = msg_ptr.cfm_ccm->names;
         names_data_remaining = sizeof(msg_ptr.cfm_ccm->names);
@@ -368,8 +383,11 @@ cfm_print(netdissect_options *ndo,
                    md_nameformat,
                    md_namelength));
 
-            /* -2 for the MA short name format and length */
-            if (md_namelength > names_data_remaining - 2) {
+            /*
+             * -3 for the MA short name format and length and one byte
+             * of MA short name.
+             */
+            if (md_namelength > names_data_remaining - 3) {
                 ND_PRINT((ndo, " (too large, must be <= %u)", names_data_remaining - 2));
                 return;
             }
@@ -459,7 +477,7 @@ cfm_print(netdissect_options *ndo,
                bittok2str(cfm_ltm_flag_values, "none", cfm_common_header->flags)));
 
         ND_PRINT((ndo, "\n\t  Transaction-ID 0x%08x, ttl %u",
-               EXTRACT_32BITS(msg_ptr.cfm_ltm->transaction_id),
+               EXTRACT_BE_U_4(msg_ptr.cfm_ltm->transaction_id),
                msg_ptr.cfm_ltm->ttl));
 
         ND_PRINT((ndo, "\n\t  Original-MAC %s, Target-MAC %s",
@@ -482,7 +500,7 @@ cfm_print(netdissect_options *ndo,
                bittok2str(cfm_ltr_flag_values, "none", cfm_common_header->flags)));
 
         ND_PRINT((ndo, "\n\t  Transaction-ID 0x%08x, ttl %u",
-               EXTRACT_32BITS(msg_ptr.cfm_ltr->transaction_id),
+               EXTRACT_BE_U_4(msg_ptr.cfm_ltr->transaction_id),
                msg_ptr.cfm_ltr->ttl));
 
         ND_PRINT((ndo, "\n\t  Replay-Action %s (%u)",
@@ -511,7 +529,7 @@ cfm_print(netdissect_options *ndo,
         cfm_tlv_header = (const struct cfm_tlv_header_t *)tptr;
 
         /* Enough to read the tlv type ? */
-        ND_TCHECK2(*tptr, 1);
+        ND_TCHECK_1(tptr);
         cfm_tlv_type=cfm_tlv_header->type;
 
         ND_PRINT((ndo, "\n\t%s TLV (0x%02x)",
@@ -527,7 +545,7 @@ cfm_print(netdissect_options *ndo,
         if (tlen < sizeof(struct cfm_tlv_header_t))
             goto tooshort;
         ND_TCHECK2(*tptr, sizeof(struct cfm_tlv_header_t));
-        cfm_tlv_len=EXTRACT_16BITS(&cfm_tlv_header->length);
+        cfm_tlv_len=EXTRACT_BE_U_2(&cfm_tlv_header->length);
 
         ND_PRINT((ndo, ", length %u", cfm_tlv_len));
 
@@ -548,8 +566,8 @@ cfm_print(netdissect_options *ndo,
                 return;
             }
             ND_PRINT((ndo, ", Status: %s (%u)",
-                   tok2str(cfm_tlv_port_status_values, "Unknown", *tptr),
-                   *tptr));
+                   tok2str(cfm_tlv_port_status_values, "Unknown", EXTRACT_U_1(tptr)),
+                   EXTRACT_U_1(tptr)));
             break;
 
         case CFM_TLV_INTERFACE_STATUS:
@@ -558,8 +576,8 @@ cfm_print(netdissect_options *ndo,
                 return;
             }
             ND_PRINT((ndo, ", Status: %s (%u)",
-                   tok2str(cfm_tlv_interface_status_values, "Unknown", *tptr),
-                   *tptr));
+                   tok2str(cfm_tlv_interface_status_values, "Unknown", EXTRACT_U_1(tptr)),
+                   EXTRACT_U_1(tptr)));
             break;
 
         case CFM_TLV_PRIVATE:
@@ -568,9 +586,9 @@ cfm_print(netdissect_options *ndo,
                 return;
             }
             ND_PRINT((ndo, ", Vendor: %s (%u), Sub-Type %u",
-                   tok2str(oui_values,"Unknown", EXTRACT_24BITS(tptr)),
-                   EXTRACT_24BITS(tptr),
-                   *(tptr + 3)));
+                   tok2str(oui_values,"Unknown", EXTRACT_BE_U_3(tptr)),
+                   EXTRACT_BE_U_3(tptr),
+                   EXTRACT_U_1(tptr + 3)));
             hexdump = TRUE;
             break;
 
@@ -581,23 +599,29 @@ cfm_print(netdissect_options *ndo,
 
             if (cfm_tlv_len < 1) {
                 ND_PRINT((ndo, " (too short, must be >= 1)"));
-                return;
+                goto next_tlv;
             }
 
             /*
              * Get the Chassis ID length and check it.
+             * IEEE 802.1Q-2014 Section 21.5.3.1
              */
-            chassis_id_length = *tptr;
+            chassis_id_length = EXTRACT_U_1(tptr);
             tptr++;
             tlen--;
             cfm_tlv_len--;
 
             if (chassis_id_length) {
+                /*
+                 * IEEE 802.1Q-2014 Section 21.5.3.2: Chassis ID Subtype, references
+                 * IEEE 802.1AB-2005 Section 9.5.2.2, subsequently
+                 * IEEE 802.1AB-2016 Section 8.5.2.2: chassis ID subtype
+                 */
                 if (cfm_tlv_len < 1) {
                     ND_PRINT((ndo, "\n\t  (TLV too short)"));
-                    return;
+                    goto next_tlv;
                 }
-                chassis_id_type = *tptr;
+                chassis_id_type = EXTRACT_U_1(tptr);
                 cfm_tlv_len--;
                 ND_PRINT((ndo, "\n\t  Chassis-ID Type %s (%u), Chassis-ID length %u",
                        tok2str(cfm_tlv_senderid_chassisid_values,
@@ -608,16 +632,22 @@ cfm_print(netdissect_options *ndo,
 
                 if (cfm_tlv_len < chassis_id_length) {
                     ND_PRINT((ndo, "\n\t  (TLV too short)"));
-                    return;
+                    goto next_tlv;
                 }
 
+                /* IEEE 802.1Q-2014 Section 21.5.3.3: Chassis ID */
                 switch (chassis_id_type) {
                 case CFM_CHASSIS_ID_MAC_ADDRESS:
+                    if (chassis_id_length != ETHER_ADDR_LEN) {
+                        ND_PRINT((ndo, " (invalid MAC address length)"));
+                        hexdump = TRUE;
+                        break;
+                    }
                     ND_PRINT((ndo, "\n\t  MAC %s", etheraddr_string(ndo, tptr + 1)));
                     break;
 
                 case CFM_CHASSIS_ID_NETWORK_ADDRESS:
-                    hexdump |= cfm_network_addr_print(ndo, tptr);
+                    hexdump |= cfm_network_addr_print(ndo, tptr + 1, chassis_id_length);
                     break;
 
                 case CFM_CHASSIS_ID_INTERFACE_NAME: /* fall through */
@@ -640,38 +670,53 @@ cfm_print(netdissect_options *ndo,
 
             /*
              * Check if there is a Management Address.
+             * IEEE 802.1Q-2014 Section 21.5.3.4: Management Address Domain Length
+             * This and all subsequent fields are not present if the TLV length
+             * allows only the above fields.
              */
             if (cfm_tlv_len == 0) {
                 /* No, there isn't; we're done. */
-                return;
+                break;
             }
 
-            mgmt_addr_length = *tptr;
+            /* Here mgmt_addr_length stands for the management domain length. */
+            mgmt_addr_length = EXTRACT_U_1(tptr);
             tptr++;
             tlen--;
             cfm_tlv_len--;
+            ND_PRINT((ndo, "\n\t  Management Address Domain Length %u", mgmt_addr_length));
             if (mgmt_addr_length) {
+                /* IEEE 802.1Q-2014 Section 21.5.3.5: Management Address Domain */
                 if (cfm_tlv_len < mgmt_addr_length) {
                     ND_PRINT((ndo, "\n\t  (TLV too short)"));
-                    return;
+                    goto next_tlv;
                 }
                 cfm_tlv_len -= mgmt_addr_length;
                 /*
                  * XXX - this is an OID; print it as such.
                  */
+                hex_print(ndo, "\n\t  Management Address Domain: ", tptr, mgmt_addr_length);
                 tptr += mgmt_addr_length;
                 tlen -= mgmt_addr_length;
 
+                /*
+                 * IEEE 802.1Q-2014 Section 21.5.3.6: Management Address Length
+                 * This field is present if Management Address Domain Length is not 0.
+                 */
                 if (cfm_tlv_len < 1) {
-                    ND_PRINT((ndo, "\n\t  (TLV too short)"));
-                    return;
+                    ND_PRINT((ndo, " (Management Address Length is missing)"));
+                    hexdump = TRUE;
+                    break;
                 }
-                
-                mgmt_addr_length = *tptr;
+
+                /* Here mgmt_addr_length stands for the management address length. */
+                mgmt_addr_length = EXTRACT_U_1(tptr);
                 tptr++;
                 tlen--;
                 cfm_tlv_len--;
+                ND_PRINT((ndo, "\n\t  Management Address Length %u", mgmt_addr_length));
                 if (mgmt_addr_length) {
+                    /* IEEE 802.1Q-2014 Section 21.5.3.7: Management Address */
                     if (cfm_tlv_len < mgmt_addr_length) {
                         ND_PRINT((ndo, "\n\t  (TLV too short)"));
                         return;
@@ -680,6 +725,7 @@ cfm_print(netdissect_options *ndo,
                     /*
                      * XXX - this is a TransportDomain; print it as such.
                      */
+                    hex_print(ndo, "\n\t  Management Address: ", tptr, mgmt_addr_length);
                     tptr += mgmt_addr_length;
                     tlen -= mgmt_addr_length;
                 }
@@ -703,6 +749,7 @@ cfm_print(netdissect_options *ndo,
         if (hexdump || ndo->ndo_vflag > 1)
             print_unknown_data(ndo, tlv_ptr, "\n\t  ", cfm_tlv_len);
 
+next_tlv:
         tptr+=cfm_tlv_len;
         tlen-=cfm_tlv_len;
     }