]> The Tcpdump Group git mirrors - tcpdump/blobdiff - print-babel.c
More UNALIGNED_MEM{CPY,CMP} on IP addresses.
[tcpdump] / print-babel.c
index c15f958670fd341e70ebf4d8aafe5f995f391807..4f128b32457679d0fb1e5bd4ed59b217e83c7a3f 100644 (file)
@@ -39,6 +39,8 @@
 #include "interface.h"
 #include "extract.h"
 
+static const char tstr[] = "[|babel]";
+
 static void babel_print_v2(const u_char *cp, u_int length);
 
 void
@@ -66,10 +68,11 @@ babel_print(const u_char *cp, u_int length) {
     return;
 
  trunc:
-    printf(" [|babel]");
+    printf(" %s", tstr);
     return;
 }
 
+/* TLVs */
 #define MESSAGE_PAD1 0
 #define MESSAGE_PADN 1
 #define MESSAGE_ACK_REQ 2
@@ -84,6 +87,18 @@ babel_print(const u_char *cp, u_int length) {
 #define MESSAGE_TSPC 11
 #define MESSAGE_HMAC 12
 
+/* sub-TLVs */
+#define MESSAGE_SUB_PAD1 0
+#define MESSAGE_SUB_PADN 1
+#define MESSAGE_SUB_DIVERSITY 2
+
+/* Diversity sub-TLV channel codes */
+static const struct tok diversity_str[] = {
+    { 0,   "reserved" },
+    { 255, "all"      },
+    { 0, NULL }
+};
+
 static const char *
 format_id(const u_char *id)
 {
@@ -126,6 +141,25 @@ format_address(const u_char *prefix)
 #endif
 }
 
+static const char *
+format_interval(const u_int16_t i)
+{
+    static char buf[sizeof("0000.0s")];
+
+    if (i == 0)
+        return "0.0s (bogus)";
+    snprintf(buf, sizeof(buf), "%u.%us", i / 10, i % 10);
+    return buf;
+}
+
+static const char *
+format_interval_update(const u_int16_t i)
+{
+    return i == 0xFFFF ? "infinity" : format_interval(i);
+}
+
+/* Return number of octets consumed from the input buffer (not the prefix length
+ * in bytes), or -1 for encoding error. */
 static int
 network_prefix(int ae, int plen, unsigned int omitted,
                const unsigned char *p, const unsigned char *dp,
@@ -133,6 +167,7 @@ network_prefix(int ae, int plen, unsigned int omitted,
 {
     unsigned pb;
     unsigned char prefix[16];
+    int consumed = 0;
 
     if(plen >= 0)
         pb = (plen + 7) / 8;
@@ -156,7 +191,10 @@ network_prefix(int ae, int plen, unsigned int omitted,
             if (dp == NULL) return -1;
             memcpy(prefix, dp, 12 + omitted);
         }
-        if(pb > omitted) memcpy(prefix + 12 + omitted, p, pb - omitted);
+        if(pb > omitted) {
+            memcpy(prefix + 12 + omitted, p, pb - omitted);
+            consumed = pb - omitted;
+        }
         break;
     case 2:
         if(omitted > 16 || (pb > omitted && len < pb - omitted))
@@ -165,20 +203,26 @@ network_prefix(int ae, int plen, unsigned int omitted,
             if (dp == NULL) return -1;
             memcpy(prefix, dp, omitted);
         }
-        if(pb > omitted) memcpy(prefix + omitted, p, pb - omitted);
+        if(pb > omitted) {
+            memcpy(prefix + omitted, p, pb - omitted);
+            consumed = pb - omitted;
+        }
         break;
     case 3:
         if(pb > 8 && len < pb - 8) return -1;
         prefix[0] = 0xfe;
         prefix[1] = 0x80;
-        if(pb > 8) memcpy(prefix + 8, p, pb - 8);
+        if(pb > 8) {
+            memcpy(prefix + 8, p, pb - 8);
+            consumed = pb - 8;
+        }
         break;
     default:
         return -1;
     }
 
     memcpy(p_r, prefix, 16);
-    return 1;
+    return consumed;
 }
 
 static int
@@ -188,6 +232,71 @@ network_address(int ae, const unsigned char *a, unsigned int len,
     return network_prefix(ae, -1, 0, a, NULL, len, a_r);
 }
 
+/*
+ * Sub-TLVs consume the "extra data" of Babel TLVs (see Section 4.3 of RFC6126),
+ * their encoding is similar to the encoding of TLVs, but the type namespace is
+ * different:
+ *
+ * o Type 0 stands for Pad1 sub-TLV with the same encoding as the Pad1 TLV.
+ * o Type 1 stands for PadN sub-TLV with the same encoding as the PadN TLV.
+ * o Type 2 stands for Diversity sub-TLV, which propagates diversity routing
+ *   data. Its body is a variable-length sequence of 8-bit unsigned integers,
+ *   each representing per-hop number of interferring radio channel for the
+ *   prefix. Channel 0 is invalid and must not be used in the sub-TLV, channel
+ *   255 interferes with any other channel.
+ *
+ * Sub-TLV types 0 and 1 are valid for any TLV type, whether sub-TLV type 2 is
+ * only valid for TLV type 8 (Update). Note that within an Update TLV a missing
+ * Diversity sub-TLV is not the same as a Diversity sub-TLV with an empty body.
+ * The former would mean a lack of any claims about the interference, and the
+ * latter would state that interference is definitely absent. */
+static void
+subtlvs_print(const u_char *cp, const u_char *ep, const uint8_t tlv_type) {
+    uint8_t subtype, sublen;
+    const char *sep;
+
+    while (cp < ep) {
+        subtype = *cp++;
+        if(subtype == MESSAGE_SUB_PAD1) {
+            printf(" sub-pad1");
+            continue;
+        }
+        if(cp == ep)
+            goto corrupt;
+        sublen = *cp++;
+        if(cp + sublen > ep)
+            goto corrupt;
+
+        switch(subtype) {
+        case MESSAGE_SUB_PADN:
+            printf(" sub-padn");
+            cp += sublen;
+            break;
+        case MESSAGE_SUB_DIVERSITY:
+            printf(" sub-diversity");
+            if (sublen == 0) {
+                printf(" empty");
+                break;
+            }
+            sep = " ";
+            while(sublen--) {
+                printf("%s%s", sep, tok2str(diversity_str, "%u", *cp++));
+                sep = "-";
+            }
+            if(tlv_type != MESSAGE_UPDATE)
+                printf(" (bogus)");
+            break;
+        default:
+            printf(" sub-unknown-0x%02x", subtype);
+            cp += sublen;
+        } /* switch */
+    } /* while */
+    return;
+
+ corrupt:
+    printf(" (corrupt)");
+}
+
 #define ICHECK(i, l) \
        if ((i) + (l) > bodylen || (i) + (l) > length) goto corrupt;
 
@@ -212,23 +321,22 @@ babel_print_v2(const u_char *cp, u_int length) {
         u_int type, len;
 
         message = cp + 4 + i;
+
+        TCHECK2(*message, 1);
+        if((type = message[0]) == MESSAGE_PAD1) {
+            printf(vflag ? "\n\tPad 1" : " pad1");
+            i += 1;
+            continue;
+        }
+
         TCHECK2(*message, 2);
         ICHECK(i, 2);
-        type = message[0];
         len = message[1];
 
         TCHECK2(*message, 2 + len);
         ICHECK(i, 2 + len);
 
         switch(type) {
-        case MESSAGE_PAD1: {
-            if(!vflag)
-                printf(" pad1");
-            else
-                printf("\n\tPad 1");
-        }
-            break;
-
         case MESSAGE_PADN: {
             if(!vflag)
                 printf(" padN");
@@ -246,7 +354,7 @@ babel_print_v2(const u_char *cp, u_int length) {
                 if(len < 6) goto corrupt;
                 nonce = EXTRACT_16BITS(message + 4);
                 interval = EXTRACT_16BITS(message + 6);
-                printf("%04x %d", nonce, interval);
+                printf("%04x %s", nonce, format_interval(interval));
             }
         }
             break;
@@ -273,7 +381,7 @@ babel_print_v2(const u_char *cp, u_int length) {
                 if(len < 6) goto corrupt;
                 seqno = EXTRACT_16BITS(message + 4);
                 interval = EXTRACT_16BITS(message + 6);
-                printf("seqno %u interval %u", seqno, interval);
+                printf("seqno %u interval %s", seqno, format_interval(interval));
             }
         }
             break;
@@ -290,9 +398,9 @@ babel_print_v2(const u_char *cp, u_int length) {
                 txcost = EXTRACT_16BITS(message + 4);
                 interval = EXTRACT_16BITS(message + 6);
                 rc = network_address(message[2], message + 8, len - 6, address);
-                if(rc < 0) { printf("[|babel]"); break; }
-                printf("%s txcost %u interval %d",
-                       format_address(address), txcost, interval);
+                if(rc < 0) { printf("%s", tstr); break; }
+                printf("%s txcost %u interval %s",
+                       format_address(address), txcost, format_interval(interval));
             }
         }
             break;
@@ -349,18 +457,21 @@ babel_print_v2(const u_char *cp, u_int length) {
                 interval = EXTRACT_16BITS(message + 6);
                 seqno = EXTRACT_16BITS(message + 8);
                 metric = EXTRACT_16BITS(message + 10);
-                printf("%s%s%s %s metric %u seqno %u interval %u",
+                printf("%s%s%s %s metric %u seqno %u interval %s",
                        (message[3] & 0x80) ? "/prefix": "",
                        (message[3] & 0x40) ? "/id" : "",
                        (message[3] & 0x3f) ? "/unknown" : "",
                        format_prefix(prefix, plen),
-                       metric, seqno, interval);
+                       metric, seqno, format_interval_update(interval));
                 if(message[3] & 0x80) {
                     if(message[2] == 1)
                         memcpy(v4_prefix, prefix, 16);
                     else
                         memcpy(v6_prefix, prefix, 16);
                 }
+                /* extra data? */
+                if((u_int)rc < len - 10)
+                    subtlvs_print(message + 12 + rc, message + 2 + len, type);
             }
         }
             break;
@@ -438,7 +549,7 @@ babel_print_v2(const u_char *cp, u_int length) {
     return;
 
  trunc:
-    printf(" [|babel]");
+    printf(" %s", tstr);
     return;
 
  corrupt: