+/* Prints an NTPv4 extension field */
+static void
+p_ntp_ef(netdissect_options *ndo, u_int type, u_int length, const u_char *ef_body)
+{
+ ND_PRINT("\n\t %s", tok2str(ntp_ef_types, "Unknown type", type));
+ ND_PRINT(" (0x%04x), length %u", type, length);
+
+ if (ndo->ndo_vflag > 2)
+ hex_print(ndo, "\n\t ", ef_body, length - 4);
+ else {
+ /*
+ * If we're not going to print it, at least make sure
+ * it's present in the packet, so if ef_len is too long,
+ * we stop.
+ */
+ ND_TCHECK_LEN(ef_body, length - 4);
+ }
+}
+
+/* Prints list of extension fields per RFC 7822 */
+static u_int
+p_ext_fields(netdissect_options *ndo, const u_char *cp, u_int length)
+{
+ const struct ntp_extension_field *ef;
+ u_int ef_type, ef_len, efs_len;
+ int first_ef;
+
+ first_ef = 1;
+ efs_len = 0;
+
+ /* RFC 7822 requires the last EF in the packet to have at least
+ 28 octets to avoid ambiguity with MACs */
+ while (length - efs_len >= 28) {
+ ef = (const struct ntp_extension_field *)(cp + efs_len);
+ ef_type = GET_BE_U_2(ef->type);
+ ef_len = GET_BE_U_2(ef->length);
+
+ if (efs_len + ef_len > length || ef_len < 4 || ef_len % 4 != 0) {
+ nd_print_invalid(ndo);
+ break;
+ }
+
+ if (first_ef) {
+ ND_PRINT("\n\tExtension fields:");
+ first_ef = 0;
+ }
+
+ p_ntp_ef(ndo, ef_type, ef_len, (const u_char *)(ef + 1));
+
+ /*
+ * The entire extension field is guaranteed to be in the
+ * captured data, as p_ntp_ef() will longjmp out if it
+ * isn't.
+ *
+ * As the total length of the captured data fits in a
+ * u_int, this means that the total length of all the
+ * extension fields will fit in a u_int, so this will
+ * never overflow.
+ */
+ efs_len += ef_len;
+ }
+
+ return efs_len;
+}