]> The Tcpdump Group git mirrors - tcpdump/blobdiff - print-forces.c
Add changes in 4.2.1.
[tcpdump] / print-forces.c
index 2ad063bc852315c6afed60a7a146016523a8bf59..033580e51bc2ac8a6e0227d68d71d9743ab5c14b 100644 (file)
@@ -34,18 +34,24 @@ int
 prestlv_print(register const u_char * pptr, register u_int len,
              u_int16_t op_msk _U_, int indent)
 {
-       struct forces_tlv *tlv = (struct forces_tlv *)pptr;
+       const struct forces_tlv *tlv = (struct forces_tlv *)pptr;
        register const u_char *tdp = (u_char *) TLV_DATA(tlv);
        struct res_val *r = (struct res_val *)tdp;
-       u_int16_t dlen = len - TLV_HDRL;
+       u_int dlen;
 
+       /*
+        * pdatacnt_print() has ensured that len (the TLV length)
+        * >= TLV_HDRL.
+        */
+       dlen = len - TLV_HDRL;
        if (dlen != RESLEN) {
-               printf("illegal RESULT-TLV: %d bytes! \n", dlen);
+               printf("illegal RESULT-TLV: %d bytes!\n", dlen);
                return -1;
        }
 
+       TCHECK(*r);
        if (r->result >= 0x18 && r->result <= 0xFE) {
-               printf("illegal reserved result code: 0x%x! \n", r->result);
+               printf("illegal reserved result code: 0x%x!\n", r->result);
                return -1;
        }
 
@@ -55,16 +61,28 @@ prestlv_print(register const u_char * pptr, register u_int len,
                       tok2str(ForCES_errs, NULL, r->result), r->result);
        }
        return 0;
+
+trunc:
+       fputs("[|forces]", stdout);
+       return -1;
 }
 
 int
 fdatatlv_print(register const u_char * pptr, register u_int len,
               u_int16_t op_msk _U_, int indent)
 {
-       struct forces_tlv *tlv = (struct forces_tlv *)pptr;
-       u_int tll = len - TLV_HDRL;
+       const struct forces_tlv *tlv = (struct forces_tlv *)pptr;
+       u_int rlen;
        register const u_char *tdp = (u_char *) TLV_DATA(tlv);
-       u_int16_t type = ntohs(tlv->type);
+       u_int16_t type;
+
+       /*
+        * pdatacnt_print() or pkeyitlv_print() has ensured that len
+        * (the TLV length) >= TLV_HDRL.
+        */
+       rlen = len - TLV_HDRL;
+       TCHECK(*tlv);
+       type = EXTRACT_16BITS(&tlv->type);
        if (type != F_TLV_FULD) {
                printf("Error: expecting FULLDATA!\n");
                return -1;
@@ -73,23 +91,33 @@ fdatatlv_print(register const u_char * pptr, register u_int len,
        if (vflag >= 3) {
                char *ib = indent_pr(indent + 2, 1);
                printf("%s[", &ib[1]);
-               hex_print_with_offset(ib, tdp, tll, 0);
+               hex_print_with_offset(ib, tdp, rlen, 0);
                printf("\n%s]\n", &ib[1]);
        }
        return 0;
+
+trunc:
+       fputs("[|forces]", stdout);
+       return -1;
 }
 
 int
 sdatailv_print(register const u_char * pptr, register u_int len,
               u_int16_t op_msk _U_, int indent)
 {
-       u_int tll = len - ILV_HDRL;
-       struct forces_ilv *ilv = (struct forces_ilv *)pptr;
+       u_int rlen;
+       const struct forces_ilv *ilv = (struct forces_ilv *)pptr;
        int invilv;
 
+       if (len < ILV_HDRL) {
+               printf("Error: BAD SPARSEDATA-TLV!\n");
+               return -1;
+       }
+       rlen = len - ILV_HDRL;
        indent += 1;
-       while (1) {
-               invilv = ilv_valid(ilv, tll);
+       while (rlen != 0) {
+               TCHECK(*ilv);
+               invilv = ilv_valid(ilv, rlen);
                if (invilv) {
                        printf("Error: BAD ILV!\n");
                        return -1;
@@ -98,65 +126,94 @@ sdatailv_print(register const u_char * pptr, register u_int len,
                        register const u_char *tdp = (u_char *) ILV_DATA(ilv);
                        char *ib = indent_pr(indent, 1);
                        printf("\n%s SPARSEDATA: type %x length %d\n", &ib[1],
-                              ntohl(ilv->type), ntohl(ilv->length));
+                              EXTRACT_32BITS(&ilv->type),
+                              EXTRACT_32BITS(&ilv->length));
                        printf("%s[", &ib[1]);
-                       hex_print_with_offset(ib, tdp, tll, 0);
+                       hex_print_with_offset(ib, tdp, rlen, 0);
                        printf("\n%s]\n", &ib[1]);
                }
 
-               ilv = GO_NXT_ILV(ilv, tll);
+               ilv = GO_NXT_ILV(ilv, rlen);
        }
 
        return 0;
+
+trunc:
+       fputs("[|forces]", stdout);
+       return -1;
 }
 
 int
 sdatatlv_print(register const u_char * pptr, register u_int len,
               u_int16_t op_msk, int indent)
 {
-       struct forces_tlv *tlv = (struct forces_tlv *)pptr;
-       u_int tll = len - TLV_HDRL;
+       const struct forces_tlv *tlv = (struct forces_tlv *)pptr;
+       u_int rlen;
        register const u_char *tdp = (u_char *) TLV_DATA(tlv);
-       u_int16_t type = ntohs(tlv->type);
+       u_int16_t type;
+
+       /*
+        * pdatacnt_print() has ensured that len (the TLV length)
+        * >= TLV_HDRL.
+        */
+       rlen = len - TLV_HDRL;
+       TCHECK(*tlv);
+       type = EXTRACT_16BITS(&tlv->type);
        if (type != F_TLV_SPAD) {
                printf("Error: expecting SPARSEDATA!\n");
                return -1;
        }
 
-       return sdatailv_print(tdp, tll, op_msk, indent);
+       return sdatailv_print(tdp, rlen, op_msk, indent);
+
+trunc:
+       fputs("[|forces]", stdout);
+       return -1;
 }
 
 int
 pkeyitlv_print(register const u_char * pptr, register u_int len,
               u_int16_t op_msk, int indent)
 {
-       struct forces_tlv *tlv = (struct forces_tlv *)pptr;
+       const struct forces_tlv *tlv = (struct forces_tlv *)pptr;
        register const u_char *tdp = (u_char *) TLV_DATA(tlv);
        register const u_char *dp = tdp + 4;
-       struct forces_tlv *kdtlv = (struct forces_tlv *)dp;
-       u_int32_t id = EXTRACT_32BITS(tdp);
+       const struct forces_tlv *kdtlv = (struct forces_tlv *)dp;
+       u_int32_t id;
        char *ib = indent_pr(indent, 0);
        u_int16_t type, tll;
        int invtlv;
 
+       TCHECK(*tdp);
+       id = EXTRACT_32BITS(tdp);
        printf("%sKeyinfo: Key 0x%x\n", ib, id);
-       type = ntohs(kdtlv->type);
+       TCHECK(*kdtlv);
+       type = EXTRACT_16BITS(&kdtlv->type);
        invtlv = tlv_valid(kdtlv, len);
 
        if (invtlv) {
                printf("%s TLV type 0x%x len %d\n",
                       tok2str(ForCES_TLV_err, NULL, invtlv), type,
-                      ntohs(kdtlv->length));
+                      EXTRACT_16BITS(&kdtlv->length));
                return -1;
        }
-       tll = ntohs(kdtlv->length);
+       /*
+        * At this point, tlv_valid() has ensured that the TLV
+        * length is large enough but not too large (it doesn't
+        * go past the end of the containing TLV).
+        */
+       tll = EXTRACT_16BITS(&kdtlv->length);
        dp = (u_char *) TLV_DATA(kdtlv);
        return fdatatlv_print(dp, tll, op_msk, indent);
+
+trunc:
+       fputs("[|forces]", stdout);
+       return -1;
 }
 
 int
 pdatacnt_print(register const u_char * pptr, register u_int len,
-              u_int32_t IDcnt, u_int16_t op_msk, int indent)
+              u_int16_t IDcnt, u_int16_t op_msk, int indent)
 {
        u_int i;
        int rc;
@@ -164,6 +221,9 @@ pdatacnt_print(register const u_char * pptr, register u_int len,
        char *ib = indent_pr(indent, 0);
 
        for (i = 0; i < IDcnt; i++) {
+               TCHECK2(*pptr, 4);
+               if (len < 4)
+                       goto trunc;
                id = EXTRACT_32BITS(pptr);
                if (vflag >= 3)
                        printf("%s  ID#%02u: %d\n", ib, i + 1, id);
@@ -171,43 +231,52 @@ pdatacnt_print(register const u_char * pptr, register u_int len,
                pptr += 4;
        }
        if (len) {
-               struct forces_tlv *pdtlv = (struct forces_tlv *)pptr;
-               u_int16_t type = ntohs(pdtlv->type);
-               u_int16_t tll = ntohs(pdtlv->length) - TLV_HDRL;
+               const struct forces_tlv *pdtlv = (struct forces_tlv *)pptr;
+               u_int16_t type;
+               u_int16_t tll;
                int pad = 0;
-               u_int aln = F_ALN_LEN(ntohs(pdtlv->length));
-
-               int invtlv = tlv_valid(pdtlv, len);
+               u_int aln;
+               int invtlv;
 
+               TCHECK(*pdtlv);
+               type = EXTRACT_16BITS(&pdtlv->type);
+               invtlv = tlv_valid(pdtlv, len);
                if (invtlv) {
                        printf
                            ("%s Outstanding bytes %d for TLV type 0x%x TLV len %d\n",
                             tok2str(ForCES_TLV_err, NULL, invtlv), len, type,
-                            ntohs(pdtlv->length));
+                            EXTRACT_16BITS(&pdtlv->length));
                        goto pd_err;
                }
-               if (aln > ntohs(pdtlv->length)) {
+               /*
+                * At this point, tlv_valid() has ensured that the TLV
+                * length is large enough but not too large (it doesn't
+                * go past the end of the containing TLV).
+                */
+               tll = EXTRACT_16BITS(&pdtlv->length) - TLV_HDRL;
+               aln = F_ALN_LEN(EXTRACT_16BITS(&pdtlv->length));
+               if (aln > EXTRACT_16BITS(&pdtlv->length)) {
                        if (aln > len) {
                                printf
                                    ("Invalid padded pathdata TLV type 0x%x len %d missing %d pad bytes\n",
-                                    type, ntohs(pdtlv->length), aln - len);
+                                    type, EXTRACT_16BITS(&pdtlv->length), aln - len);
                        } else {
-                               pad = aln - ntohs(pdtlv->length);
+                               pad = aln - EXTRACT_16BITS(&pdtlv->length);
                        }
                }
                if (pd_valid(type)) {
-                       struct pdata_ops *ops = get_forces_pd(type);
+                       const struct pdata_ops *ops = get_forces_pd(type);
 
                        if (vflag >= 3 && ops->v != F_TLV_PDAT) {
                                if (pad)
                                        printf
-                                           ("%s %s (Length %d DataLen %d pad %d Bytes)\n",
-                                            ib, ops->s, ntohs(pdtlv->length),
+                                           ("%s  %s (Length %d DataLen %d pad %d Bytes)\n",
+                                            ib, ops->s, EXTRACT_16BITS(&pdtlv->length),
                                             tll, pad);
                                else
                                        printf
                                            ("%s  %s (Length %d DataLen %d Bytes)\n",
-                                            ib, ops->s, ntohs(pdtlv->length),
+                                            ib, ops->s, EXTRACT_16BITS(&pdtlv->length),
                                             tll);
                        }
 
@@ -216,11 +285,12 @@ pdatacnt_print(register const u_char * pptr, register u_int len,
                        rc = ops->print((const u_char *)pdtlv,
                                        tll + pad + TLV_HDRL, op_msk,
                                        indent + 2);
+                       len -= (TLV_HDRL + pad + tll);
                } else {
                        printf("Invalid path data content type 0x%x len %d\n",
-                              type, ntohs(pdtlv->length));
+                              type, EXTRACT_16BITS(&pdtlv->length));
 pd_err:
-                       if (ntohs(pdtlv->length)) {
+                       if (EXTRACT_16BITS(&pdtlv->length)) {
                                hex_print_with_offset("Bad Data val\n\t  [",
                                                      pptr, len, 0);
                                printf("]\n");
@@ -229,27 +299,38 @@ pd_err:
                        }
                }
        }
-       return 0;
+       return len;
+
+trunc:
+       fputs("[|forces]", stdout);
+       return -1;
 }
 
 int
 pdata_print(register const u_char * pptr, register u_int len,
            u_int16_t op_msk, int indent)
 {
-       struct pathdata_h *pdh = (struct pathdata_h *)pptr;
+       const struct pathdata_h *pdh = (struct pathdata_h *)pptr;
        char *ib = indent_pr(indent, 0);
        u_int minsize = 0;
+       int more_pd = 0;
+       u_int16_t idcnt = 0;
+
+       TCHECK(*pdh);
+       if (len < sizeof(struct pathdata_h))
+               goto trunc;
        if (vflag >= 3) {
                printf("\n%sPathdata: Flags 0x%x ID count %d\n",
-                      ib, ntohs(pdh->pflags), ntohs(pdh->pIDcnt));
+                      ib, EXTRACT_16BITS(&pdh->pflags), EXTRACT_16BITS(&pdh->pIDcnt));
        }
 
-       if (ntohs(pdh->pflags) & F_SELKEY) {
+       if (EXTRACT_16BITS(&pdh->pflags) & F_SELKEY) {
                op_msk |= B_KEYIN;
        }
        pptr += sizeof(struct pathdata_h);
        len -= sizeof(struct pathdata_h);
-       minsize = ntohs(pdh->pIDcnt) * 4;
+       idcnt = EXTRACT_16BITS(&pdh->pIDcnt);
+       minsize = idcnt * 4;
        if (len < minsize) {
                printf("\t\t\ttruncated IDs expected %uB got %uB\n", minsize,
                       len);
@@ -257,69 +338,101 @@ pdata_print(register const u_char * pptr, register u_int len,
                printf("]\n");
                return -1;
        }
-       return pdatacnt_print(pptr, len, ntohs(pdh->pIDcnt), op_msk, indent);
+       more_pd = pdatacnt_print(pptr, len, idcnt, op_msk, indent);
+       if (more_pd > 0) {
+               int consumed = len - more_pd;
+               pptr += consumed;
+               len = more_pd; 
+               /* XXX: Argh, recurse some more */
+               return recpdoptlv_print(pptr, len, op_msk, indent+1);
+       } else
+               return 0;
+
+trunc:
+       fputs("[|forces]", stdout);
+       return -1;
 }
 
 int
 genoptlv_print(register const u_char * pptr, register u_int len,
               u_int16_t op_msk, int indent)
 {
-       struct forces_tlv *pdtlv = (struct forces_tlv *)pptr;
-       u_int16_t type = ntohs(pdtlv->type);
-       int tll = ntohs(pdtlv->length) - TLV_HDRL;
-       int invtlv = tlv_valid(pdtlv, len);
+       const struct forces_tlv *pdtlv = (struct forces_tlv *)pptr;
+       u_int16_t type;
+       int tll;
+       int invtlv;
        char *ib = indent_pr(indent, 0);
 
+       TCHECK(*pdtlv);
+       type = EXTRACT_16BITS(&pdtlv->type);
+       tll = EXTRACT_16BITS(&pdtlv->length) - TLV_HDRL;
+       invtlv = tlv_valid(pdtlv, len);
        printf("genoptlvprint - %s TLV type 0x%x len %d\n",
-              tok2str(ForCES_TLV, NULL, type), type, ntohs(pdtlv->length));
+              tok2str(ForCES_TLV, NULL, type), type, EXTRACT_16BITS(&pdtlv->length));
        if (!invtlv) {
+               /*
+                * At this point, tlv_valid() has ensured that the TLV
+                * length is large enough but not too large (it doesn't
+                * go past the end of the containing TLV).
+                */
                register const u_char *dp = (u_char *) TLV_DATA(pdtlv);
                if (!ttlv_valid(type)) {
                        printf("%s TLV type 0x%x len %d\n",
                               tok2str(ForCES_TLV_err, NULL, invtlv), type,
-                              ntohs(pdtlv->length));
+                              EXTRACT_16BITS(&pdtlv->length));
                        return -1;
                }
                if (vflag >= 3)
                        printf("%s%s, length %d (data length %d Bytes)",
                               ib, tok2str(ForCES_TLV, NULL, type),
-                              ntohs(pdtlv->length), tll);
+                              EXTRACT_16BITS(&pdtlv->length), tll);
 
                return pdata_print(dp, tll, op_msk, indent + 1);
        } else {
                printf("\t\t\tInvalid ForCES TLV type=%x", type);
                return -1;
        }
+
+trunc:
+       fputs("[|forces]", stdout);
+       return -1;
 }
 
 int
 recpdoptlv_print(register const u_char * pptr, register u_int len,
                 u_int16_t op_msk, int indent)
 {
-       struct forces_tlv *pdtlv = (struct forces_tlv *)pptr;
-       int tll = len;
+       const struct forces_tlv *pdtlv = (struct forces_tlv *)pptr;
+       int tll;
        int rc = 0;
        int invtlv;
        u_int16_t type;
        register const u_char *dp;
        char *ib;
 
-       while (1) {
+       while (len != 0) {
+               TCHECK(*pdtlv);
                invtlv = tlv_valid(pdtlv, len);
                if (invtlv) {
                        break;
                }
+
+               /*
+                * At this point, tlv_valid() has ensured that the TLV
+                * length is large enough but not too large (it doesn't
+                * go past the end of the containing TLV).
+                */
                ib = indent_pr(indent, 0);
-               type = ntohs(pdtlv->type);
+               type = EXTRACT_16BITS(&pdtlv->type);
                dp = (u_char *) TLV_DATA(pdtlv);
-               tll = ntohs(pdtlv->length) - TLV_HDRL;
+               tll = EXTRACT_16BITS(&pdtlv->length) - TLV_HDRL;
 
                if (vflag >= 3)
                        printf
                            ("%s%s, length %d (data encapsulated %d Bytes)",
                             ib, tok2str(ForCES_TLV, NULL, type),
-                            ntohs(pdtlv->length),
-                            ntohs(pdtlv->length) - TLV_HDRL);
+                            EXTRACT_16BITS(&pdtlv->length),
+                            EXTRACT_16BITS(&pdtlv->length) - TLV_HDRL);
 
                rc = pdata_print(dp, tll, op_msk, indent + 1);
                pdtlv = GO_NXT_TLV(pdtlv, len);
@@ -327,12 +440,16 @@ recpdoptlv_print(register const u_char * pptr, register u_int len,
 
        if (len) {
                printf
-                   ("\n\t\tMessy PATHDATA TLV header, type (0x%x) \n\t\texcess of %d Bytes ",
-                    ntohs(pdtlv->type), tll - ntohs(pdtlv->length));
+                   ("\n\t\tMessy PATHDATA TLV header, type (0x%x)\n\t\texcess of %d Bytes ",
+                    EXTRACT_16BITS(&pdtlv->type), len - EXTRACT_16BITS(&pdtlv->length));
                return -1;
        }
 
        return 0;
+
+trunc:
+       fputs("[|forces]", stdout);
+       return -1;
 }
 
 int
@@ -340,6 +457,7 @@ invoptlv_print(register const u_char * pptr, register u_int len,
               u_int16_t op_msk _U_, int indent)
 {
        char *ib = indent_pr(indent, 1);
+
        if (vflag >= 3) {
                printf("%sData[", &ib[1]);
                hex_print_with_offset(ib, pptr, len, 0);
@@ -348,19 +466,26 @@ invoptlv_print(register const u_char * pptr, register u_int len,
        return -1;
 }
 
-int otlv_print(struct forces_tlv *otlv, u_int16_t op_msk _U_, int indent)
+int otlv_print(const struct forces_tlv *otlv, u_int16_t op_msk _U_, int indent)
 {
        int rc = 0;
        register const u_char *dp = (u_char *) TLV_DATA(otlv);
-       u_int16_t type = ntohs(otlv->type);
-       int tll = ntohs(otlv->length) - TLV_HDRL;
+       u_int16_t type;
+       int tll;
        char *ib = indent_pr(indent, 0);
-       struct optlv_h *ops;
-
+       const struct optlv_h *ops;
+
+       /*
+        * lfbselect_print() has ensured that EXTRACT_16BITS(&otlv->length)
+        * >= TLV_HDRL.
+        */
+       TCHECK(*otlv);
+       type = EXTRACT_16BITS(&otlv->type);
+       tll = EXTRACT_16BITS(&otlv->length) - TLV_HDRL;
        ops = get_forces_optlv_h(type);
        if (vflag >= 3) {
                printf("%sOper TLV %s(0x%x) length %d\n", ib, ops->s, type,
-                      ntohs(otlv->length));
+                      EXTRACT_16BITS(&otlv->length));
        }
        /* empty TLVs like COMMIT and TRCOMMIT are empty, we stop here .. */
        if (!ops->flags & ZERO_TTLV) {
@@ -371,7 +496,7 @@ int otlv_print(struct forces_tlv *otlv, u_int16_t op_msk _U_, int indent)
        /* rest of ops must at least have 12B {pathinfo} */
        if (tll < OP_MIN_SIZ) {
                printf("\t\tOper TLV %s(0x%x) length %d\n", ops->s, type,
-                      ntohs(otlv->length));
+                      EXTRACT_16BITS(&otlv->length));
                printf("\t\tTruncated data size %d minimum required %d\n", tll,
                       OP_MIN_SIZ);
                return invoptlv_print(dp, tll, ops->op_msk, indent);
@@ -380,6 +505,10 @@ int otlv_print(struct forces_tlv *otlv, u_int16_t op_msk _U_, int indent)
 
        rc = ops->print(dp, tll, ops->op_msk, indent + 1);
        return rc;
+
+trunc:
+       fputs("[|forces]", stdout);
+       return -1;
 }
 
 #define ASTDLN 4
@@ -388,22 +517,28 @@ int
 asttlv_print(register const u_char * pptr, register u_int len,
             u_int16_t op_msk _U_, int indent)
 {
-
        u_int32_t rescode;
-       u_int16_t dlen = len - TLV_HDRL;
+       u_int dlen;
        char *ib = indent_pr(indent, 0);
+
+       /*
+        * forces_type_print() has ensured that len (the TLV length)
+        * >= TLV_HDRL.
+        */
+       dlen = len - TLV_HDRL;
        if (dlen != ASTDLN) {
-               printf("illegal ASTresult-TLV: %d bytes! \n", dlen);
+               printf("illegal ASTresult-TLV: %d bytes!\n", dlen);
                return -1;
        }
+       TCHECK2(*pptr, 4);
        rescode = EXTRACT_32BITS(pptr);
        if (rescode > ASTMCD) {
-               printf("illegal ASTresult result code: %d! \n", rescode);
+               printf("illegal ASTresult result code: %d!\n", rescode);
                return -1;
        }
 
        if (vflag >= 3) {
-               printf("Teardown reason: \n%s", ib);
+               printf("Teardown reason:\n%s", ib);
                switch (rescode) {
                case 0:
                        printf("Normal Teardown");
@@ -424,9 +559,13 @@ asttlv_print(register const u_char * pptr, register u_int len,
                        printf("Unknown Teardown reason");
                        break;
                }
-               printf("(%x) \n%s", rescode, ib);
+               printf("(%x)\n%s", rescode, ib);
        }
        return 0;
+
+trunc:
+       fputs("[|forces]", stdout);
+       return -1;
 }
 
 #define ASRDLN 4
@@ -435,19 +574,24 @@ int
 asrtlv_print(register const u_char * pptr, register u_int len,
             u_int16_t op_msk _U_, int indent)
 {
-
        u_int32_t rescode;
-       u_int16_t dlen = len - TLV_HDRL;
+       u_int dlen;
        char *ib = indent_pr(indent, 0);
 
+       /*
+        * forces_type_print() has ensured that len (the TLV length)
+        * >= TLV_HDRL.
+        */
+       dlen = len - TLV_HDRL;
        if (dlen != ASRDLN) {   /* id, instance, oper tlv */
-               printf("illegal ASRresult-TLV: %d bytes! \n", dlen);
+               printf("illegal ASRresult-TLV: %d bytes!\n", dlen);
                return -1;
        }
+       TCHECK2(*pptr, 4);
        rescode = EXTRACT_32BITS(pptr);
 
        if (rescode > ASRMCD) {
-               printf("illegal ASRresult result code: %d! \n", rescode);
+               printf("illegal ASRresult result code: %d!\n", rescode);
                return -1;
        }
 
@@ -467,16 +611,24 @@ asrtlv_print(register const u_char * pptr, register u_int len,
                        printf("Unknown ");
                        break;
                }
-               printf("(%x) \n%s", rescode, ib);
+               printf("(%x)\n%s", rescode, ib);
        }
        return 0;
+
+trunc:
+       fputs("[|forces]", stdout);
+       return -1;
 }
 
+/*
+ * XXX - not used.
+ */
 int
 gentltlv_print(register const u_char * pptr _U_, register u_int len,
               u_int16_t op_msk _U_, int indent _U_)
 {
-       u_int16_t dlen = len - TLV_HDRL;
+       u_int dlen = len - TLV_HDRL;
+
        if (dlen < 4) {         /* at least 32 bits must exist */
                printf("truncated TLV: %d bytes missing! ", 4 - dlen);
                return -1;
@@ -489,38 +641,67 @@ int
 print_metailv(register const u_char * pptr, register u_int len,
              u_int16_t op_msk _U_, int indent)
 {
-       u_int16_t dlen = len - ILV_HDRL;
-       int tll = dlen;
+       u_int dlen;
+       u_int rlen;
        char *ib = indent_pr(indent, 0);
        /* XXX: check header length */
-       struct forces_ilv *ilv = (struct forces_ilv *)pptr;
-       printf("\n%sMetaID 0x%x length %d\n", ib, ntohl(ilv->type),
-              ntohl(ilv->length));
-       hex_print_with_offset("\n\t\t\t\t[", ILV_DATA(ilv), tll, 0);
+       const struct forces_ilv *ilv = (struct forces_ilv *)pptr;
+
+       /*
+        * print_metatlv() has ensured that len (what remains in the
+        * ILV) >= ILV_HDRL.
+        */
+       dlen = len - ILV_HDRL;
+       rlen = dlen;
+       TCHECK(*ilv);
+       printf("\n%sMetaID 0x%x length %d\n", ib, EXTRACT_32BITS(&ilv->type),
+              EXTRACT_32BITS(&ilv->length));
+       hex_print_with_offset("\n\t\t\t\t[", ILV_DATA(ilv), rlen, 0);
        return 0;
+
+trunc:
+       fputs("[|forces]", stdout);
+       return -1;
 }
 
 int
 print_metatlv(register const u_char * pptr, register u_int len,
              u_int16_t op_msk _U_, int indent)
 {
-       u_int16_t dlen = len - TLV_HDRL;
+       u_int dlen;
        char *ib = indent_pr(indent, 0);
-       u_int tll = dlen;
-       struct forces_ilv *ilv = (struct forces_ilv *)pptr;
+       u_int rlen;
+       const struct forces_ilv *ilv = (struct forces_ilv *)pptr;
        int invilv;
 
-       printf("\n%s METADATA \n", ib);
-       while (1) {
-               invilv = ilv_valid(ilv, tll);
+       /*
+        * redirect_print() has ensured that len (what remains in the
+        * TLV) >= TLV_HDRL.
+        */
+       dlen = len - TLV_HDRL;
+       rlen = dlen;
+       printf("\n%s METADATA\n", ib);
+       while (rlen != 0) {
+               TCHECK(*ilv);
+               invilv = ilv_valid(ilv, rlen);
                if (invilv)
                        break;
-               print_metailv((u_char *) ilv, tll, 0, indent + 1);
 
-               ilv = GO_NXT_ILV(ilv, tll);
+               /*
+                * At this point, ilv_valid() has ensured that the ILV
+                * length is large enough but not too large (it doesn't
+                * go past the end of the containing TLV).
+                */
+               print_metailv((u_char *) ilv, rlen, 0, indent + 1);
+
+               ilv = GO_NXT_ILV(ilv, rlen);
        }
 
        return 0;
+
+trunc:
+       fputs("[|forces]", stdout);
+       return -1;
 }
 
 /*
@@ -529,11 +710,16 @@ int
 print_reddata(register const u_char * pptr, register u_int len,
              u_int16_t op_msk _U_, int indent _U_)
 {
-       u_int16_t dlen = len - TLV_HDRL;
-       u_int tll = dlen;
+       u_int dlen;
+       u_int rlen;
        int invtlv;
-       struct forces_tlv *tlv = (struct forces_tlv *)pptr;
+       const struct forces_tlv *tlv = (struct forces_tlv *)pptr;
 
+       /*
+        * redirect_print() has ensured that len (what remains in the
+        * TLV) >= TLV_HDRL.
+        */
+       dlen = len - TLV_HDRL;
        printf("\n\t\t Redirect DATA\n");
        if (dlen <= RD_MIN) {
                printf("\n\t\ttruncated Redirect data: %d bytes missing! ",
@@ -541,59 +727,87 @@ print_reddata(register const u_char * pptr, register u_int len,
                return -1;
        }
 
-       invtlv = tlv_valid(tlv, tll);
+       rlen = dlen;
+       TCHECK(*tlv);
+       invtlv = tlv_valid(tlv, rlen);
 
        if (invtlv) {
-               printf("Redir data type 0x%x len %d\n", ntohs(tlv->type),
-                      ntohs(tlv->length));
+               printf("Redir data type 0x%x len %d\n", EXTRACT_16BITS(&tlv->type),
+                      EXTRACT_16BITS(&tlv->length));
                return -1;
        }
 
-       tll -= TLV_HDRL;
-       hex_print_with_offset("\n\t\t\t[", TLV_DATA(tlv), tll, 0);
+       /*
+        * At this point, tlv_valid() has ensured that the TLV
+        * length is large enough but not too large (it doesn't
+        * go past the end of the containing TLV).
+        */
+       rlen -= TLV_HDRL;
+       hex_print_with_offset("\n\t\t\t[", TLV_DATA(tlv), rlen, 0);
        return 0;
+
+trunc:
+       fputs("[|forces]", stdout);
+       return -1;
 }
 
 int
 redirect_print(register const u_char * pptr, register u_int len,
               u_int16_t op_msk _U_, int indent)
 {
-       struct forces_tlv *tlv = (struct forces_tlv *)pptr;
-       u_int16_t dlen = len - TLV_HDRL;
-       u_int tll = dlen;
+       const struct forces_tlv *tlv = (struct forces_tlv *)pptr;
+       u_int dlen;
+       u_int rlen;
        int invtlv;
 
+       /*
+        * forces_type_print() has ensured that len (the TLV length)
+        * >= TLV_HDRL.
+        */
+       dlen = len - TLV_HDRL;
        if (dlen <= RD_MIN) {
                printf("\n\t\ttruncated Redirect TLV: %d bytes missing! ",
                       RD_MIN - dlen);
                return -1;
        }
 
+       rlen = dlen;
        indent += 1;
-       while (1) {
-               invtlv = tlv_valid(tlv, tll);
+       while (rlen != 0) {
+               TCHECK(*tlv);
+               invtlv = tlv_valid(tlv, rlen);
                if (invtlv)
                        break;
-               if (ntohs(tlv->type) == F_TLV_METD) {
-                       print_metatlv((u_char *) TLV_DATA(tlv), tll, 0, indent);
-               } else if ((ntohs(tlv->type) == F_TLV_REDD)) {
-                       print_reddata((u_char *) TLV_DATA(tlv), tll, 0, indent);
+
+               /*
+                * At this point, tlv_valid() has ensured that the TLV
+                * length is large enough but not too large (it doesn't
+                * go past the end of the containing TLV).
+                */
+               if (EXTRACT_16BITS(&tlv->type) == F_TLV_METD) {
+                       print_metatlv((u_char *) TLV_DATA(tlv), rlen, 0, indent);
+               } else if ((EXTRACT_16BITS(&tlv->type) == F_TLV_REDD)) {
+                       print_reddata((u_char *) TLV_DATA(tlv), rlen, 0, indent);
                } else {
                        printf("Unknown REDIRECT TLV 0x%x len %d\n",
-                              ntohs(tlv->type), ntohs(tlv->length));
+                              EXTRACT_16BITS(&tlv->type), EXTRACT_16BITS(&tlv->length));
                }
 
-               tlv = GO_NXT_TLV(tlv, tll);
+               tlv = GO_NXT_TLV(tlv, rlen);
        }
 
-       if (tll) {
+       if (rlen) {
                printf
-                   ("\n\t\tMessy Redirect TLV header, type (0x%x) \n\t\texcess of %d Bytes ",
-                    ntohs(tlv->type), tll - ntohs(tlv->length));
+                   ("\n\t\tMessy Redirect TLV header, type (0x%x)\n\t\texcess of %d Bytes ",
+                    EXTRACT_16BITS(&tlv->type), rlen - EXTRACT_16BITS(&tlv->length));
                return -1;
        }
 
        return 0;
+
+trunc:
+       fputs("[|forces]", stdout);
+       return -1;
 }
 
 #define OP_OFF 8
@@ -604,68 +818,96 @@ lfbselect_print(register const u_char * pptr, register u_int len,
                u_int16_t op_msk, int indent)
 {
        const struct forces_lfbsh *lfbs;
-       struct forces_tlv *otlv;
+       const struct forces_tlv *otlv;
        char *ib = indent_pr(indent, 0);
-       u_int16_t dlen = len - TLV_HDRL;
-       u_int tll = dlen - OP_OFF;
+       u_int dlen;
+       u_int rlen;
        int invtlv;
 
+       /*
+        * forces_type_print() has ensured that len (the TLV length)
+        * >= TLV_HDRL.
+        */
+       dlen = len - TLV_HDRL;
        if (dlen <= OP_MIN) {   /* id, instance, oper tlv header .. */
                printf("\n\t\ttruncated lfb selector: %d bytes missing! ",
                       OP_MIN - dlen);
                return -1;
        }
 
+       /*
+        * At this point, we know that dlen > OP_MIN; OP_OFF < OP_MIN, so
+        * we also know that it's > OP_OFF.
+        */
+       rlen = dlen - OP_OFF;
+
        lfbs = (const struct forces_lfbsh *)pptr;
+       TCHECK(*lfbs);
        if (vflag >= 3) {
                printf("\n%s%s(Classid %x) instance %x\n",
-                      ib, tok2str(ForCES_LFBs, NULL, ntohl(lfbs->class)),
-                      ntohl(lfbs->class), ntohl(lfbs->instance));
+                      ib, tok2str(ForCES_LFBs, NULL, EXTRACT_32BITS(&lfbs->class)),
+                      EXTRACT_32BITS(&lfbs->class),
+                      EXTRACT_32BITS(&lfbs->instance));
        }
 
        otlv = (struct forces_tlv *)(lfbs + 1);
 
        indent += 1;
-       while (1) {
-               invtlv = tlv_valid(otlv, tll);
+       while (rlen != 0) {
+               TCHECK(*otlv);
+               invtlv = tlv_valid(otlv, rlen);
                if (invtlv)
                        break;
-               if (op_valid(ntohs(otlv->type), op_msk)) {
+
+               /*
+                * At this point, tlv_valid() has ensured that the TLV
+                * length is large enough but not too large (it doesn't
+                * go past the end of the containing TLV).
+                */
+               if (op_valid(EXTRACT_16BITS(&otlv->type), op_msk)) {
                        otlv_print(otlv, 0, indent);
                } else {
                        if (vflag < 3)
                                printf("\n");
                        printf
                            ("\t\tINValid oper-TLV type 0x%x length %d for this ForCES message\n",
-                            ntohs(otlv->type), ntohs(otlv->length));
-                       invoptlv_print((u_char *)otlv, tll, 0, indent);
+                            EXTRACT_16BITS(&otlv->type), EXTRACT_16BITS(&otlv->length));
+                       invoptlv_print((u_char *)otlv, rlen, 0, indent);
                }
-               otlv = GO_NXT_TLV(otlv, tll);
+               otlv = GO_NXT_TLV(otlv, rlen);
        }
 
-       if (tll) {
+       if (rlen) {
                printf
-                   ("\n\t\tMessy oper TLV header, type (0x%x) \n\t\texcess of %d Bytes ",
-                    ntohs(otlv->type), tll - ntohs(otlv->length));
+                   ("\n\t\tMessy oper TLV header, type (0x%x)\n\t\texcess of %d Bytes ",
+                    EXTRACT_16BITS(&otlv->type), rlen - EXTRACT_16BITS(&otlv->length));
                return -1;
        }
 
        return 0;
+
+trunc:
+       fputs("[|forces]", stdout);
+       return -1;
 }
 
 int
 forces_type_print(register const u_char * pptr, const struct forcesh *fhdr _U_,
-                 register u_int mlen, struct tom_h *tops)
+                 register u_int mlen, const struct tom_h *tops)
 {
-       struct forces_tlv *tltlv;
-       u_int tll;
+       const struct forces_tlv *tltlv;
+       u_int rlen;
        int invtlv;
        int rc = 0;
        int ttlv = 0;
 
-       tll = mlen - sizeof(struct forcesh);
+       /*
+        * forces_print() has already checked that mlen >= ForCES_HDRL
+        * by calling ForCES_HLN_VALID().
+        */
+       rlen = mlen - ForCES_HDRL;
 
-       if (tll > TLV_HLN) {
+       if (rlen > TLV_HLN) {
                if (tops->flags & ZERO_TTLV) {
                        printf("<0x%x>Illegal Top level TLV!\n", tops->flags);
                        return -1;
@@ -688,49 +930,66 @@ forces_type_print(register const u_char * pptr, const struct forcesh *fhdr _U_,
 
        /*XXX: 15 top level tlvs will probably be fine
           You are nuts if you send more ;-> */
-       while (1) {
-               invtlv = tlv_valid(tltlv, tll);
+       while (rlen != 0) {
+               TCHECK(*tltlv);
+               invtlv = tlv_valid(tltlv, rlen);
                if (invtlv)
                        break;
-               if (!ttlv_valid(ntohs(tltlv->type))) {
+
+               /*
+                * At this point, tlv_valid() has ensured that the TLV
+                * length is large enough but not too large (it doesn't
+                * go past the end of the packet).
+                */
+               if (!ttlv_valid(EXTRACT_16BITS(&tltlv->type))) {
                        printf("\n\tInvalid ForCES Top TLV type=0x%x",
-                              ntohs(tltlv->type));
+                              EXTRACT_16BITS(&tltlv->type));
                        return -1;
                }
 
                if (vflag >= 3)
                        printf("\t%s, length %d (data length %d Bytes)",
-                              tok2str(ForCES_TLV, NULL, ntohs(tltlv->type)),
-                              ntohs(tltlv->length), ntohs(tltlv->length) - 4);
+                              tok2str(ForCES_TLV, NULL, EXTRACT_16BITS(&tltlv->type)),
+                              EXTRACT_16BITS(&tltlv->length),
+                              EXTRACT_16BITS(&tltlv->length) - TLV_HDRL);
 
                rc = tops->print((u_char *) TLV_DATA(tltlv),
-                                ntohs(tltlv->length), tops->op_msk, 9);
+                                EXTRACT_16BITS(&tltlv->length), tops->op_msk, 9);
                if (rc < 0) {
                        return -1;
                }
-               tltlv = GO_NXT_TLV(tltlv, tll);
+               tltlv = GO_NXT_TLV(tltlv, rlen);
                ttlv--;
                if (ttlv <= 0)
                        break;
        }
-       if (tll) {
-               printf("\tMess TopTLV header: min %ld, total %d advertised %d ",
-                      sizeof(struct forces_tlv), tll, ntohs(tltlv->length));
+       /*
+        * XXX - if ttlv != 0, does that mean that the packet was too
+        * short, and didn't have *enough* TLVs in it?
+        */
+       if (rlen) {
+               printf("\tMess TopTLV header: min %u, total %d advertised %d ",
+                      TLV_HDRL, rlen, EXTRACT_16BITS(&tltlv->length));
                return -1;
        }
 
        return 0;
+
+trunc:
+       fputs("[|forces]", stdout);
+       return -1;
 }
 
 void forces_print(register const u_char * pptr, register u_int len)
 {
        const struct forcesh *fhdr;
-       u_int16_t mlen;
+       u_int mlen;
        u_int32_t flg_raw;
-       struct tom_h *tops;
+       const struct tom_h *tops;
        int rc = 0;
 
        fhdr = (const struct forcesh *)pptr;
+       TCHECK(*fhdr);
        if (!tom_valid(fhdr->fm_tom)) {
                printf("Invalid ForCES message type %d\n", fhdr->fm_tom);
                goto error;
@@ -747,17 +1006,18 @@ void forces_print(register const u_char * pptr, register u_int len)
        printf("\n\tForCES %s ", tops->s);
        if (!ForCES_HLN_VALID(mlen, len)) {
                printf
-                   ("Illegal ForCES pkt len - min %ld, total recvd %d, advertised %d ",
-                    sizeof(struct forcesh), len, ForCES_BLN(fhdr));
+                   ("Illegal ForCES pkt len - min %u, total recvd %d, advertised %d ",
+                    ForCES_HDRL, len, ForCES_BLN(fhdr));
                goto error;
        }
 
+       TCHECK2(*(pptr + 20), 4);
        flg_raw = EXTRACT_32BITS(pptr + 20);
        if (vflag >= 1) {
                printf("\n\tForCES Version %d len %uB flags 0x%08x ",
                       ForCES_V(fhdr), mlen, flg_raw);
-               printf("\n\tSrcID 0x%x(%s) DstID 0x%x(%s) Correlator 0x%"
-                      PRIu64, ForCES_SID(fhdr), ForCES_node(ForCES_SID(fhdr)),
+               printf("\n\tSrcID 0x%x(%s) DstID 0x%x(%s) Correlator 0x%" PRIu64,
+                      ForCES_SID(fhdr), ForCES_node(ForCES_SID(fhdr)),
                       ForCES_DID(fhdr), ForCES_node(ForCES_DID(fhdr)),
                       EXTRACT_64BITS(fhdr->fm_cor));
 
@@ -765,12 +1025,14 @@ void forces_print(register const u_char * pptr, register u_int len)
        if (vflag >= 2) {
                printf
                    ("\n\tForCES flags:\n\t  %s(0x%x), prio=%d, %s(0x%x),\n\t  %s(0x%x), %s(0x%x)\n",
-                    ForCES_ACKp(fhdr->f_ack), fhdr->f_ack, fhdr->f_pri,
-                    ForCES_EMp(fhdr->f_em), fhdr->f_em, ForCES_ATp(fhdr->f_at),
-                    fhdr->f_at, ForCES_TPp(fhdr->f_tp), fhdr->f_tp);
+                    ForCES_ACKp(ForCES_ACK(fhdr)), ForCES_ACK(fhdr),
+                    ForCES_PRI(fhdr),
+                    ForCES_EMp(ForCES_EM(fhdr)), ForCES_EM(fhdr),
+                    ForCES_ATp(ForCES_AT(fhdr)), ForCES_AT(fhdr),
+                    ForCES_TPp(ForCES_TP(fhdr)), ForCES_TP(fhdr));
                printf
-                   ("\t  Extra flags: rsv(b5-7) 0x%x rsv(b13-15) 0x%x rsv(b16-31) 0x%x\n",
-                    fhdr->f_rs1, fhdr->f_rs2, ntohs(fhdr->f_rs3));
+                   ("\t  Extra flags: rsv(b5-7) 0x%x rsv(b13-31) 0x%x\n",
+                    ForCES_RS1(fhdr), ForCES_RS2(fhdr));
        }
        rc = forces_type_print(pptr, fhdr, mlen, tops);
        if (rc < 0) {
@@ -781,9 +1043,13 @@ error:
        }
 
        if (vflag >= 4) {
-               printf("\n\t  Raw ForCES message \n\t [");
+               printf("\n\t  Raw ForCES message\n\t [");
                hex_print_with_offset("\n\t ", pptr, len, 0);
                printf("\n\t ]");
        }
        printf("\n");
+       return;
+
+trunc:
+       fputs("[|forces]", stdout);
 }