+static void
+ospf_decode_lls(netdissect_options *ndo,
+ const struct ospfhdr *op, u_int length)
+{
+ const u_char *dptr;
+ const u_char *dataend;
+ u_int length2;
+ uint16_t lls_type, lls_len;
+ uint32_t lls_flags;
+
+ switch (GET_U_1(op->ospf_type)) {
+
+ case OSPF_TYPE_HELLO:
+ if (!(GET_U_1(op->ospf_hello.hello_options) & OSPF_OPTION_L))
+ return;
+ break;
+
+ case OSPF_TYPE_DD:
+ if (!(GET_U_1(op->ospf_db.db_options) & OSPF_OPTION_L))
+ return;
+ break;
+
+ default:
+ return;
+ }
+
+ /* dig deeper if LLS data is available; see RFC4813 */
+ length2 = GET_BE_U_2(op->ospf_len);
+ dptr = (const u_char *)op + length2;
+ dataend = (const u_char *)op + length;
+
+ if (GET_BE_U_2(op->ospf_authtype) == OSPF_AUTH_MD5) {
+ dptr = dptr + GET_U_1(op->ospf_authdata + 3);
+ length2 += GET_U_1(op->ospf_authdata + 3);
+ }
+ if (length2 >= length) {
+ ND_PRINT("\n\t[LLS truncated]");
+ return;
+ }
+ ND_PRINT("\n\t LLS: checksum: 0x%04x", (u_int) GET_BE_U_2(dptr));
+
+ dptr += 2;
+ length2 = GET_BE_U_2(dptr);
+ ND_PRINT(", length: %u", length2);
+
+ dptr += 2;
+ while (dptr < dataend) {
+ lls_type = GET_BE_U_2(dptr);
+ ND_PRINT("\n\t %s (%u)",
+ tok2str(ospf_lls_tlv_values,"Unknown TLV",lls_type),
+ lls_type);
+ dptr += 2;
+ lls_len = GET_BE_U_2(dptr);
+ ND_PRINT(", length: %u", lls_len);
+ dptr += 2;
+ switch (lls_type) {
+
+ case OSPF_LLS_EO:
+ if (lls_len != 4) {
+ ND_PRINT(" [should be 4]");
+ lls_len = 4;
+ }
+ lls_flags = GET_BE_U_4(dptr);
+ ND_PRINT("\n\t Options: 0x%08x [%s]", lls_flags,
+ bittok2str(ospf_lls_eo_options, "?", lls_flags));
+
+ break;
+
+ case OSPF_LLS_MD5:
+ if (lls_len != 20) {
+ ND_PRINT(" [should be 20]");
+ lls_len = 20;
+ }
+ ND_PRINT("\n\t Sequence number: 0x%08x", GET_BE_U_4(dptr));
+ break;
+ }
+
+ dptr += lls_len;
+ }
+}
+