1026d7285Schristos /** 2026d7285Schristos * Copyright (c) 2012 3026d7285Schristos * 4026d7285Schristos * Gregory Detal <gregory.detal@uclouvain.be> 5026d7285Schristos * Christoph Paasch <christoph.paasch@uclouvain.be> 6026d7285Schristos * 7026d7285Schristos * Redistribution and use in source and binary forms, with or without 8026d7285Schristos * modification, are permitted provided that the following conditions 9026d7285Schristos * are met: 10026d7285Schristos * 11026d7285Schristos * 1. Redistributions of source code must retain the above copyright 12026d7285Schristos * notice, this list of conditions and the following disclaimer. 13026d7285Schristos * 14026d7285Schristos * 2. Redistributions in binary form must reproduce the above copyright 15026d7285Schristos * notice, this list of conditions and the following disclaimer in the 16026d7285Schristos * documentation and/or other materials provided with the distribution. 17026d7285Schristos * 18026d7285Schristos * 3. Neither the name of the University nor of the Laboratory may be used 19026d7285Schristos * to endorse or promote products derived from this software without 20026d7285Schristos * specific prior written permission. 21026d7285Schristos * 22026d7285Schristos * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23026d7285Schristos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24026d7285Schristos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25026d7285Schristos * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26026d7285Schristos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27026d7285Schristos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28026d7285Schristos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29026d7285Schristos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30026d7285Schristos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31026d7285Schristos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32026d7285Schristos * SUCH DAMAGE. 33026d7285Schristos */ 34026d7285Schristos 35fdccd7e4Schristos #include <sys/cdefs.h> 36fdccd7e4Schristos #ifndef lint 37*26ba0b50Schristos __RCSID("$NetBSD: print-mptcp.c,v 1.6 2024/09/02 16:15:32 christos Exp $"); 38fdccd7e4Schristos #endif 39fdccd7e4Schristos 40dc860a36Sspz /* \summary: Multipath TCP (MPTCP) printer */ 41dc860a36Sspz 42dc860a36Sspz /* specification: RFC 6824 */ 43dc860a36Sspz 44c74ad251Schristos #include <config.h> 45026d7285Schristos 46c74ad251Schristos #include "netdissect-stdinc.h" 47026d7285Schristos 48784088dfSchristos #include "netdissect.h" 49026d7285Schristos #include "extract.h" 50026d7285Schristos #include "addrtoname.h" 51026d7285Schristos 52026d7285Schristos #include "tcp.h" 53026d7285Schristos 54c47fd378Schristos #define MPTCP_SUB_CAPABLE 0x0 55c47fd378Schristos #define MPTCP_SUB_JOIN 0x1 56c47fd378Schristos #define MPTCP_SUB_DSS 0x2 57c47fd378Schristos #define MPTCP_SUB_ADD_ADDR 0x3 58c47fd378Schristos #define MPTCP_SUB_REMOVE_ADDR 0x4 59c47fd378Schristos #define MPTCP_SUB_PRIO 0x5 60c47fd378Schristos #define MPTCP_SUB_FAIL 0x6 61c47fd378Schristos #define MPTCP_SUB_FCLOSE 0x7 62c47fd378Schristos 63c47fd378Schristos struct mptcp_option { 64c74ad251Schristos nd_uint8_t kind; 65c74ad251Schristos nd_uint8_t len; 66c74ad251Schristos nd_uint8_t sub_etc; /* subtype upper 4 bits, other stuff lower 4 bits */ 67c47fd378Schristos }; 68c47fd378Schristos 69c47fd378Schristos #define MPTCP_OPT_SUBTYPE(sub_etc) (((sub_etc) >> 4) & 0xF) 70c47fd378Schristos 71c47fd378Schristos struct mp_capable { 72c74ad251Schristos nd_uint8_t kind; 73c74ad251Schristos nd_uint8_t len; 74c74ad251Schristos nd_uint8_t sub_ver; 75c74ad251Schristos nd_uint8_t flags; 76c74ad251Schristos nd_uint64_t sender_key; 77c74ad251Schristos nd_uint64_t receiver_key; 78c47fd378Schristos }; 79c47fd378Schristos 80c47fd378Schristos #define MP_CAPABLE_OPT_VERSION(sub_ver) (((sub_ver) >> 0) & 0xF) 81c47fd378Schristos #define MP_CAPABLE_C 0x80 82c47fd378Schristos #define MP_CAPABLE_S 0x01 83c47fd378Schristos 84c47fd378Schristos struct mp_join { 85c74ad251Schristos nd_uint8_t kind; 86c74ad251Schristos nd_uint8_t len; 87c74ad251Schristos nd_uint8_t sub_b; 88c74ad251Schristos nd_uint8_t addr_id; 89c47fd378Schristos union { 90c47fd378Schristos struct { 91c74ad251Schristos nd_uint32_t token; 92c74ad251Schristos nd_uint32_t nonce; 93c47fd378Schristos } syn; 94c47fd378Schristos struct { 95c74ad251Schristos nd_uint64_t mac; 96c74ad251Schristos nd_uint32_t nonce; 97c47fd378Schristos } synack; 98c47fd378Schristos struct { 99c74ad251Schristos nd_byte mac[20]; 100c47fd378Schristos } ack; 101c47fd378Schristos } u; 102c47fd378Schristos }; 103c47fd378Schristos 104c47fd378Schristos #define MP_JOIN_B 0x01 105c47fd378Schristos 106c47fd378Schristos struct mp_dss { 107c74ad251Schristos nd_uint8_t kind; 108c74ad251Schristos nd_uint8_t len; 109c74ad251Schristos nd_uint8_t sub; 110c74ad251Schristos nd_uint8_t flags; 111c47fd378Schristos }; 112c47fd378Schristos 113c47fd378Schristos #define MP_DSS_F 0x10 114c47fd378Schristos #define MP_DSS_m 0x08 115c47fd378Schristos #define MP_DSS_M 0x04 116c47fd378Schristos #define MP_DSS_a 0x02 117c47fd378Schristos #define MP_DSS_A 0x01 118c47fd378Schristos 119c74ad251Schristos static const struct tok mptcp_addr_subecho_bits[] = { 120c74ad251Schristos { 0x6, "v0-ip6" }, 121c74ad251Schristos { 0x4, "v0-ip4" }, 122c74ad251Schristos { 0x1, "v1-echo" }, 123c74ad251Schristos { 0x0, "v1" }, 124c74ad251Schristos { 0, NULL } 125c74ad251Schristos }; 126c74ad251Schristos 127c47fd378Schristos struct mp_add_addr { 128c74ad251Schristos nd_uint8_t kind; 129c74ad251Schristos nd_uint8_t len; 130c74ad251Schristos nd_uint8_t sub_echo; 131c74ad251Schristos nd_uint8_t addr_id; 132c47fd378Schristos union { 133c47fd378Schristos struct { 134c74ad251Schristos nd_ipv4 addr; 135c74ad251Schristos nd_uint16_t port; 136c74ad251Schristos nd_uint64_t mac; 137c47fd378Schristos } v4; 138c47fd378Schristos struct { 139c74ad251Schristos nd_ipv4 addr; 140c74ad251Schristos nd_uint64_t mac; 141c74ad251Schristos } v4np; 142c74ad251Schristos struct { 143c74ad251Schristos nd_ipv6 addr; 144c74ad251Schristos nd_uint16_t port; 145c74ad251Schristos nd_uint64_t mac; 146c47fd378Schristos } v6; 147c74ad251Schristos struct { 148c74ad251Schristos nd_ipv6 addr; 149c74ad251Schristos nd_uint64_t mac; 150c74ad251Schristos } v6np; 151c47fd378Schristos } u; 152c47fd378Schristos }; 153c47fd378Schristos 154c47fd378Schristos struct mp_remove_addr { 155c74ad251Schristos nd_uint8_t kind; 156c74ad251Schristos nd_uint8_t len; 157c74ad251Schristos nd_uint8_t sub; 158c47fd378Schristos /* list of addr_id */ 159c74ad251Schristos nd_uint8_t addrs_id[1]; 160c47fd378Schristos }; 161c47fd378Schristos 162c47fd378Schristos struct mp_fail { 163c74ad251Schristos nd_uint8_t kind; 164c74ad251Schristos nd_uint8_t len; 165c74ad251Schristos nd_uint8_t sub; 166c74ad251Schristos nd_uint8_t resv; 167c74ad251Schristos nd_uint64_t data_seq; 168c47fd378Schristos }; 169c47fd378Schristos 170c47fd378Schristos struct mp_close { 171c74ad251Schristos nd_uint8_t kind; 172c74ad251Schristos nd_uint8_t len; 173c74ad251Schristos nd_uint8_t sub; 174c74ad251Schristos nd_uint8_t rsv; 175c74ad251Schristos nd_byte key[8]; 176c47fd378Schristos }; 177c47fd378Schristos 178c47fd378Schristos struct mp_prio { 179c74ad251Schristos nd_uint8_t kind; 180c74ad251Schristos nd_uint8_t len; 181c74ad251Schristos nd_uint8_t sub_b; 182c74ad251Schristos nd_uint8_t addr_id; 183c47fd378Schristos }; 184c47fd378Schristos 185c47fd378Schristos #define MP_PRIO_B 0x01 186c47fd378Schristos 187c47fd378Schristos static int 188c47fd378Schristos dummy_print(netdissect_options *ndo _U_, 189c47fd378Schristos const u_char *opt _U_, u_int opt_len _U_, u_char flags _U_) 190026d7285Schristos { 191026d7285Schristos return 1; 192026d7285Schristos } 193026d7285Schristos 194c47fd378Schristos static int 195c47fd378Schristos mp_capable_print(netdissect_options *ndo, 196c47fd378Schristos const u_char *opt, u_int opt_len, u_char flags) 197026d7285Schristos { 198784088dfSchristos const struct mp_capable *mpc = (const struct mp_capable *) opt; 199c74ad251Schristos uint8_t version; 200026d7285Schristos 201c74ad251Schristos if (!((opt_len == 12 || opt_len == 4) && flags & TH_SYN) && 202c74ad251Schristos !((opt_len == 20 || opt_len == 22) && (flags & (TH_SYN | TH_ACK)) == 203c74ad251Schristos TH_ACK)) 204026d7285Schristos return 0; 205026d7285Schristos 206c74ad251Schristos version = MP_CAPABLE_OPT_VERSION(GET_U_1(mpc->sub_ver)); 207c74ad251Schristos switch (version) { 208c74ad251Schristos case 0: /* fall through */ 209c74ad251Schristos case 1: 210c74ad251Schristos ND_PRINT(" v%u", version); 211c74ad251Schristos break; 212c74ad251Schristos default: 213c74ad251Schristos ND_PRINT(" Unknown Version (%u)", version); 214026d7285Schristos return 1; 215026d7285Schristos } 216026d7285Schristos 217c74ad251Schristos if (GET_U_1(mpc->flags) & MP_CAPABLE_C) 218c74ad251Schristos ND_PRINT(" csum"); 219c74ad251Schristos if (opt_len == 12 || opt_len >= 20) { 220c74ad251Schristos ND_PRINT(" {0x%" PRIx64, GET_BE_U_8(mpc->sender_key)); 221c74ad251Schristos if (opt_len >= 20) 222c74ad251Schristos ND_PRINT(",0x%" PRIx64, GET_BE_U_8(mpc->receiver_key)); 223c74ad251Schristos ND_PRINT("}"); 224c74ad251Schristos } 225026d7285Schristos return 1; 226026d7285Schristos } 227026d7285Schristos 228c47fd378Schristos static int 229c47fd378Schristos mp_join_print(netdissect_options *ndo, 230c47fd378Schristos const u_char *opt, u_int opt_len, u_char flags) 231026d7285Schristos { 232784088dfSchristos const struct mp_join *mpj = (const struct mp_join *) opt; 233026d7285Schristos 23472c96ff3Schristos if (!(opt_len == 12 && (flags & TH_SYN)) && 235026d7285Schristos !(opt_len == 16 && (flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) && 23672c96ff3Schristos !(opt_len == 24 && (flags & TH_ACK))) 237026d7285Schristos return 0; 238026d7285Schristos 239026d7285Schristos if (opt_len != 24) { 240c74ad251Schristos if (GET_U_1(mpj->sub_b) & MP_JOIN_B) 241c74ad251Schristos ND_PRINT(" backup"); 242c74ad251Schristos ND_PRINT(" id %u", GET_U_1(mpj->addr_id)); 243026d7285Schristos } 244026d7285Schristos 245026d7285Schristos switch (opt_len) { 246026d7285Schristos case 12: /* SYN */ 247c74ad251Schristos ND_PRINT(" token 0x%x" " nonce 0x%x", 248c74ad251Schristos GET_BE_U_4(mpj->u.syn.token), 249c74ad251Schristos GET_BE_U_4(mpj->u.syn.nonce)); 250026d7285Schristos break; 251026d7285Schristos case 16: /* SYN/ACK */ 252c74ad251Schristos ND_PRINT(" hmac 0x%" PRIx64 " nonce 0x%x", 253c74ad251Schristos GET_BE_U_8(mpj->u.synack.mac), 254c74ad251Schristos GET_BE_U_4(mpj->u.synack.nonce)); 255026d7285Schristos break; 256026d7285Schristos case 24: {/* ACK */ 257026d7285Schristos size_t i; 258c74ad251Schristos ND_PRINT(" hmac 0x"); 259026d7285Schristos for (i = 0; i < sizeof(mpj->u.ack.mac); ++i) 260c74ad251Schristos ND_PRINT("%02x", mpj->u.ack.mac[i]); 261026d7285Schristos } 262026d7285Schristos default: 263026d7285Schristos break; 264026d7285Schristos } 265026d7285Schristos return 1; 266026d7285Schristos } 267026d7285Schristos 268c47fd378Schristos static int 269c47fd378Schristos mp_dss_print(netdissect_options *ndo, 270c47fd378Schristos const u_char *opt, u_int opt_len, u_char flags) 271026d7285Schristos { 272784088dfSchristos const struct mp_dss *mdss = (const struct mp_dss *) opt; 273c74ad251Schristos uint8_t mdss_flags; 274026d7285Schristos 27572c96ff3Schristos /* We need the flags, at a minimum. */ 27672c96ff3Schristos if (opt_len < 4) 27772c96ff3Schristos return 0; 27872c96ff3Schristos 27972c96ff3Schristos if (flags & TH_SYN) 280026d7285Schristos return 0; 281026d7285Schristos 282c74ad251Schristos mdss_flags = GET_U_1(mdss->flags); 283c74ad251Schristos if (mdss_flags & MP_DSS_F) 284c74ad251Schristos ND_PRINT(" fin"); 285026d7285Schristos 286026d7285Schristos opt += 4; 28772c96ff3Schristos opt_len -= 4; 288c74ad251Schristos if (mdss_flags & MP_DSS_A) { 28972c96ff3Schristos /* Ack present */ 290c74ad251Schristos ND_PRINT(" ack "); 29172c96ff3Schristos /* 29272c96ff3Schristos * If the a flag is set, we have an 8-byte ack; if it's 29372c96ff3Schristos * clear, we have a 4-byte ack. 29472c96ff3Schristos */ 295c74ad251Schristos if (mdss_flags & MP_DSS_a) { 29672c96ff3Schristos if (opt_len < 8) 29772c96ff3Schristos return 0; 298c74ad251Schristos ND_PRINT("%" PRIu64, GET_BE_U_8(opt)); 299026d7285Schristos opt += 8; 30072c96ff3Schristos opt_len -= 8; 301026d7285Schristos } else { 30272c96ff3Schristos if (opt_len < 4) 30372c96ff3Schristos return 0; 304c74ad251Schristos ND_PRINT("%u", GET_BE_U_4(opt)); 305026d7285Schristos opt += 4; 30672c96ff3Schristos opt_len -= 4; 307026d7285Schristos } 308026d7285Schristos } 309026d7285Schristos 310c74ad251Schristos if (mdss_flags & MP_DSS_M) { 31172c96ff3Schristos /* 31272c96ff3Schristos * Data Sequence Number (DSN), Subflow Sequence Number (SSN), 31372c96ff3Schristos * Data-Level Length present, and Checksum possibly present. 31472c96ff3Schristos */ 315c74ad251Schristos ND_PRINT(" seq "); 31672c96ff3Schristos /* 31772c96ff3Schristos * If the m flag is set, we have an 8-byte NDS; if it's clear, 31872c96ff3Schristos * we have a 4-byte DSN. 31972c96ff3Schristos */ 320c74ad251Schristos if (mdss_flags & MP_DSS_m) { 32172c96ff3Schristos if (opt_len < 8) 32272c96ff3Schristos return 0; 323c74ad251Schristos ND_PRINT("%" PRIu64, GET_BE_U_8(opt)); 324026d7285Schristos opt += 8; 32572c96ff3Schristos opt_len -= 8; 326026d7285Schristos } else { 32772c96ff3Schristos if (opt_len < 4) 32872c96ff3Schristos return 0; 329c74ad251Schristos ND_PRINT("%u", GET_BE_U_4(opt)); 330026d7285Schristos opt += 4; 33172c96ff3Schristos opt_len -= 4; 332026d7285Schristos } 33372c96ff3Schristos if (opt_len < 4) 33472c96ff3Schristos return 0; 335c74ad251Schristos ND_PRINT(" subseq %u", GET_BE_U_4(opt)); 336026d7285Schristos opt += 4; 33772c96ff3Schristos opt_len -= 4; 33872c96ff3Schristos if (opt_len < 2) 33972c96ff3Schristos return 0; 340c74ad251Schristos ND_PRINT(" len %u", GET_BE_U_2(opt)); 341026d7285Schristos opt += 2; 34272c96ff3Schristos opt_len -= 2; 343026d7285Schristos 34472c96ff3Schristos /* 34572c96ff3Schristos * The Checksum is present only if negotiated. 34672c96ff3Schristos * If there are at least 2 bytes left, process the next 2 34772c96ff3Schristos * bytes as the Checksum. 34872c96ff3Schristos */ 34972c96ff3Schristos if (opt_len >= 2) { 350c74ad251Schristos ND_PRINT(" csum 0x%x", GET_BE_U_2(opt)); 35172c96ff3Schristos opt_len -= 2; 352026d7285Schristos } 35372c96ff3Schristos } 35472c96ff3Schristos if (opt_len != 0) 35572c96ff3Schristos return 0; 356026d7285Schristos return 1; 357026d7285Schristos } 358026d7285Schristos 359c47fd378Schristos static int 360c47fd378Schristos add_addr_print(netdissect_options *ndo, 361c47fd378Schristos const u_char *opt, u_int opt_len, u_char flags _U_) 362026d7285Schristos { 363784088dfSchristos const struct mp_add_addr *add_addr = (const struct mp_add_addr *) opt; 364026d7285Schristos 365c74ad251Schristos if (!(opt_len == 8 || opt_len == 10 || opt_len == 16 || opt_len == 18 || 366c74ad251Schristos opt_len == 20 || opt_len == 22 || opt_len == 28 || opt_len == 30)) 367026d7285Schristos return 0; 368026d7285Schristos 369c74ad251Schristos ND_PRINT(" %s", 370c74ad251Schristos tok2str(mptcp_addr_subecho_bits, "[bad version/echo]", 371c74ad251Schristos GET_U_1(add_addr->sub_echo) & 0xF)); 372c74ad251Schristos ND_PRINT(" id %u", GET_U_1(add_addr->addr_id)); 373c74ad251Schristos if (opt_len == 8 || opt_len == 10 || opt_len == 16 || opt_len == 18) { 374c74ad251Schristos ND_PRINT(" %s", GET_IPADDR_STRING(add_addr->u.v4.addr)); 375c74ad251Schristos if (opt_len == 10 || opt_len == 18) 376c74ad251Schristos ND_PRINT(":%u", GET_BE_U_2(add_addr->u.v4.port)); 377c74ad251Schristos if (opt_len == 16) 378c74ad251Schristos ND_PRINT(" hmac 0x%" PRIx64, GET_BE_U_8(add_addr->u.v4np.mac)); 379c74ad251Schristos if (opt_len == 18) 380c74ad251Schristos ND_PRINT(" hmac 0x%" PRIx64, GET_BE_U_8(add_addr->u.v4.mac)); 381c74ad251Schristos } 382c74ad251Schristos 383c74ad251Schristos if (opt_len == 20 || opt_len == 22 || opt_len == 28 || opt_len == 30) { 384c74ad251Schristos ND_PRINT(" %s", GET_IP6ADDR_STRING(add_addr->u.v6.addr)); 385c74ad251Schristos if (opt_len == 22 || opt_len == 30) 386c74ad251Schristos ND_PRINT(":%u", GET_BE_U_2(add_addr->u.v6.port)); 387c74ad251Schristos if (opt_len == 28) 388c74ad251Schristos ND_PRINT(" hmac 0x%" PRIx64, GET_BE_U_8(add_addr->u.v6np.mac)); 389c74ad251Schristos if (opt_len == 30) 390c74ad251Schristos ND_PRINT(" hmac 0x%" PRIx64, GET_BE_U_8(add_addr->u.v6.mac)); 391026d7285Schristos } 392026d7285Schristos 393026d7285Schristos return 1; 394026d7285Schristos } 395026d7285Schristos 396c47fd378Schristos static int 397c47fd378Schristos remove_addr_print(netdissect_options *ndo, 398c47fd378Schristos const u_char *opt, u_int opt_len, u_char flags _U_) 399026d7285Schristos { 400784088dfSchristos const struct mp_remove_addr *remove_addr = (const struct mp_remove_addr *) opt; 401c74ad251Schristos u_int i; 402026d7285Schristos 403026d7285Schristos if (opt_len < 4) 404026d7285Schristos return 0; 405026d7285Schristos 406026d7285Schristos opt_len -= 3; 407c74ad251Schristos ND_PRINT(" id"); 408c74ad251Schristos for (i = 0; i < opt_len; i++) 409c74ad251Schristos ND_PRINT(" %u", GET_U_1(remove_addr->addrs_id[i])); 410026d7285Schristos return 1; 411026d7285Schristos } 412026d7285Schristos 413c47fd378Schristos static int 414c47fd378Schristos mp_prio_print(netdissect_options *ndo, 415c47fd378Schristos const u_char *opt, u_int opt_len, u_char flags _U_) 416026d7285Schristos { 417784088dfSchristos const struct mp_prio *mpp = (const struct mp_prio *) opt; 418026d7285Schristos 419026d7285Schristos if (opt_len != 3 && opt_len != 4) 420026d7285Schristos return 0; 421026d7285Schristos 422c74ad251Schristos if (GET_U_1(mpp->sub_b) & MP_PRIO_B) 423c74ad251Schristos ND_PRINT(" backup"); 424026d7285Schristos else 425c74ad251Schristos ND_PRINT(" non-backup"); 426026d7285Schristos if (opt_len == 4) 427c74ad251Schristos ND_PRINT(" id %u", GET_U_1(mpp->addr_id)); 428026d7285Schristos 429026d7285Schristos return 1; 430026d7285Schristos } 431026d7285Schristos 432c47fd378Schristos static int 433c47fd378Schristos mp_fail_print(netdissect_options *ndo, 434c47fd378Schristos const u_char *opt, u_int opt_len, u_char flags _U_) 435026d7285Schristos { 436026d7285Schristos if (opt_len != 12) 437026d7285Schristos return 0; 438026d7285Schristos 439c74ad251Schristos ND_PRINT(" seq %" PRIu64, GET_BE_U_8(opt + 4)); 440026d7285Schristos return 1; 441026d7285Schristos } 442026d7285Schristos 443c47fd378Schristos static int 444c47fd378Schristos mp_fast_close_print(netdissect_options *ndo, 445c47fd378Schristos const u_char *opt, u_int opt_len, u_char flags _U_) 446026d7285Schristos { 447026d7285Schristos if (opt_len != 12) 448026d7285Schristos return 0; 449026d7285Schristos 450c74ad251Schristos ND_PRINT(" key 0x%" PRIx64, GET_BE_U_8(opt + 4)); 451026d7285Schristos return 1; 452026d7285Schristos } 453026d7285Schristos 454c47fd378Schristos static const struct { 455026d7285Schristos const char *name; 456c47fd378Schristos int (*print)(netdissect_options *, const u_char *, u_int, u_char); 457026d7285Schristos } mptcp_options[] = { 458026d7285Schristos { "capable", mp_capable_print }, 459026d7285Schristos { "join", mp_join_print }, 460026d7285Schristos { "dss", mp_dss_print }, 461026d7285Schristos { "add-addr", add_addr_print }, 462026d7285Schristos { "rem-addr", remove_addr_print }, 463026d7285Schristos { "prio", mp_prio_print }, 464026d7285Schristos { "fail", mp_fail_print }, 465026d7285Schristos { "fast-close", mp_fast_close_print }, 466026d7285Schristos { "unknown", dummy_print }, 467026d7285Schristos }; 468026d7285Schristos 469c47fd378Schristos int 470c47fd378Schristos mptcp_print(netdissect_options *ndo, 471c47fd378Schristos const u_char *cp, u_int len, u_char flags) 472026d7285Schristos { 473784088dfSchristos const struct mptcp_option *opt; 474026d7285Schristos u_int subtype; 475026d7285Schristos 476c74ad251Schristos ndo->ndo_protocol = "mptcp"; 477026d7285Schristos if (len < 3) 478026d7285Schristos return 0; 479026d7285Schristos 480784088dfSchristos opt = (const struct mptcp_option *) cp; 481c74ad251Schristos subtype = MPTCP_OPT_SUBTYPE(GET_U_1(opt->sub_etc)); 482c74ad251Schristos subtype = ND_MIN(subtype, MPTCP_SUB_FCLOSE + 1); 483026d7285Schristos 484c74ad251Schristos ND_PRINT(" %u", len); 485c74ad251Schristos 486c74ad251Schristos ND_PRINT(" %s", mptcp_options[subtype].name); 487c47fd378Schristos return mptcp_options[subtype].print(ndo, cp, len, flags); 488026d7285Schristos } 489