#define MPTCP_SUB_PRIO 0x5
#define MPTCP_SUB_FAIL 0x6
#define MPTCP_SUB_FCLOSE 0x7
+#define MPTCP_SUB_TCPRST 0x8
struct mptcp_option {
nd_uint8_t kind;
nd_uint8_t sub_etc; /* subtype upper 4 bits, other stuff lower 4 bits */
};
-#define MPTCP_OPT_SUBTYPE(sub_etc) ((GET_U_1(sub_etc) >> 4) & 0xF)
+#define MPTCP_OPT_SUBTYPE(sub_etc) (((sub_etc) >> 4) & 0xF)
+
+#define MP_CAPABLE_A 0x80
+
+static const struct tok mp_capable_flags[] = {
+ { MP_CAPABLE_A, "A" },
+ { 0x40, "B" },
+ { 0x20, "C" },
+ { 0x10, "D" },
+ { 0x08, "E" },
+ { 0x04, "F" },
+ { 0x02, "G" },
+ { 0x01, "H" },
+ { 0, NULL }
+};
struct mp_capable {
nd_uint8_t kind;
nd_uint8_t flags;
nd_uint64_t sender_key;
nd_uint64_t receiver_key;
+ nd_uint16_t data_len;
};
-#define MP_CAPABLE_OPT_VERSION(sub_ver) ((GET_U_1(sub_ver) >> 0) & 0xF)
-#define MP_CAPABLE_C 0x80
-#define MP_CAPABLE_S 0x01
+#define MP_CAPABLE_OPT_VERSION(sub_ver) (((sub_ver) >> 0) & 0xF)
struct mp_join {
nd_uint8_t kind;
{ 0x6, "v0-ip6" },
{ 0x4, "v0-ip4" },
{ 0x1, "v1-echo" },
- { 0x0, "v1" }
+ { 0x0, "v1" },
+ { 0, NULL }
};
struct mp_add_addr {
#define MP_PRIO_B 0x01
+static const struct tok mp_tcprst_flags[] = {
+ { 0x08, "U" },
+ { 0x04, "V" },
+ { 0x02, "W" },
+ { 0x01, "T" },
+ { 0, NULL }
+};
+
+static const struct tok mp_tcprst_reasons[] = {
+ { 0x06, "Middlebox interference" },
+ { 0x05, "Unacceptable performance" },
+ { 0x04, "Too much outstanding data" },
+ { 0x03, "Administratively prohibited" },
+ { 0x02, "Lack of resources" },
+ { 0x01, "MPTCP-specific error" },
+ { 0x00, "Unspecified error" },
+ { 0, NULL }
+};
+
+struct mp_tcprst {
+ nd_uint8_t kind;
+ nd_uint8_t len;
+ nd_uint8_t sub_b;
+ nd_uint8_t reason;
+};
+
static int
dummy_print(netdissect_options *ndo _U_,
const u_char *opt _U_, u_int opt_len _U_, u_char flags _U_)
const u_char *opt, u_int opt_len, u_char flags)
{
const struct mp_capable *mpc = (const struct mp_capable *) opt;
+ uint8_t version, csum_enabled;
if (!((opt_len == 12 || opt_len == 4) && flags & TH_SYN) &&
- !((opt_len == 20 || opt_len == 22) && (flags & (TH_SYN | TH_ACK)) ==
+ !((opt_len == 20 || opt_len == 22 || opt_len == 24) && (flags & (TH_SYN | TH_ACK)) ==
TH_ACK))
return 0;
- switch (MP_CAPABLE_OPT_VERSION(mpc->sub_ver)) {
+ version = MP_CAPABLE_OPT_VERSION(GET_U_1(mpc->sub_ver));
+ switch (version) {
case 0: /* fall through */
case 1:
- ND_PRINT(" v%d", MP_CAPABLE_OPT_VERSION(mpc->sub_ver));
+ ND_PRINT(" v%u", version);
break;
default:
- ND_PRINT(" Unknown Version (%d)",
- MP_CAPABLE_OPT_VERSION(mpc->sub_ver));
+ ND_PRINT(" Unknown Version (%u)", version);
return 1;
}
- if (GET_U_1(mpc->flags) & MP_CAPABLE_C)
+ ND_PRINT(" flags [%s]", bittok2str_nosep(mp_capable_flags, "none",
+ GET_U_1(mpc->flags)));
+
+ csum_enabled = GET_U_1(mpc->flags) & MP_CAPABLE_A;
+ if (csum_enabled)
ND_PRINT(" csum");
if (opt_len == 12 || opt_len >= 20) {
ND_PRINT(" {0x%" PRIx64, GET_BE_U_8(mpc->sender_key));
if (opt_len >= 20)
ND_PRINT(",0x%" PRIx64, GET_BE_U_8(mpc->receiver_key));
+
+ /* RFC 8684 Section 3.1 */
+ if ((opt_len == 22 && !csum_enabled) || opt_len == 24)
+ ND_PRINT(",data_len=%u", GET_BE_U_2(mpc->data_len));
ND_PRINT("}");
}
return 1;
* Data-Level Length present, and Checksum possibly present.
*/
ND_PRINT(" seq ");
- /*
+ /*
* If the m flag is set, we have an 8-byte NDS; if it's clear,
* we have a 4-byte DSN.
*/
const u_char *opt, u_int opt_len, u_char flags _U_)
{
const struct mp_remove_addr *remove_addr = (const struct mp_remove_addr *) opt;
- u_int i;
+ u_int i;
if (opt_len < 4)
return 0;
return 1;
}
+static int
+mp_tcprst_print(netdissect_options *ndo,
+ const u_char *opt, u_int opt_len, u_char flags _U_)
+{
+ const struct mp_tcprst *mpr = (const struct mp_tcprst *)opt;
+
+ if (opt_len != 4)
+ return 0;
+
+ ND_PRINT(" flags [%s]", bittok2str_nosep(mp_tcprst_flags, "none",
+ GET_U_1(mpr->sub_b)));
+
+ ND_PRINT(" reason %s", tok2str(mp_tcprst_reasons, "unknown (0x%02x)",
+ GET_U_1(mpr->reason)));
+ return 1;
+}
+
static const struct {
const char *name;
int (*print)(netdissect_options *, const u_char *, u_int, u_char);
} mptcp_options[] = {
- { "capable", mp_capable_print},
+ { "capable", mp_capable_print },
{ "join", mp_join_print },
{ "dss", mp_dss_print },
{ "add-addr", add_addr_print },
{ "prio", mp_prio_print },
{ "fail", mp_fail_print },
{ "fast-close", mp_fast_close_print },
+ { "tcprst", mp_tcprst_print },
{ "unknown", dummy_print },
};
const struct mptcp_option *opt;
u_int subtype;
- ndo->ndo_protocol = "mptcp";
+ ndo->ndo_protocol = "mptcp";
if (len < 3)
return 0;
opt = (const struct mptcp_option *) cp;
- ND_TCHECK_SIZE(opt);
- subtype = ND_MIN(MPTCP_OPT_SUBTYPE(opt->sub_etc), MPTCP_SUB_FCLOSE + 1);
+ subtype = MPTCP_OPT_SUBTYPE(GET_U_1(opt->sub_etc));
+ subtype = ND_MIN(subtype, MPTCP_SUB_TCPRST + 1);
+
+ ND_PRINT(" %u", len);
ND_PRINT(" %s", mptcp_options[subtype].name);
return mptcp_options[subtype].print(ndo, cp, len, flags);
-
-trunc:
- nd_print_trunc(ndo);
- return 0;
}