TCP: Implement AccECN

This work is based on
https://www.ietf.org/archive/id/draft-ietf-tcpm-accurate-ecn-20.html
In particular, add support for the AccECN option, the experimental
AccECN option, the AE flag and the ACE field.
This commit is contained in:
Michael Tuexen 2022-08-13 11:39:51 +02:00 committed by A Wireshark GitLab Utility
parent 308d9d1856
commit ecefcf8801
2 changed files with 261 additions and 51 deletions

View File

@ -147,6 +147,7 @@ static int proto_tcp_option_scpscor = -1;
static int proto_tcp_option_qs = -1;
static int proto_tcp_option_user_to = -1;
static int proto_tcp_option_tfo = -1;
static int proto_tcp_option_acc_ecn = -1;
static int proto_tcp_option_rvbd_probe = -1;
static int proto_tcp_option_rvbd_trpy = -1;
static int proto_tcp_option_exp = -1;
@ -166,9 +167,10 @@ static int hf_tcp_ack_abs = -1;
static int hf_tcp_hdr_len = -1;
static int hf_tcp_flags = -1;
static int hf_tcp_flags_res = -1;
static int hf_tcp_flags_ns = -1;
static int hf_tcp_flags_ae = -1;
static int hf_tcp_flags_cwr = -1;
static int hf_tcp_flags_ece = -1;
static int hf_tcp_flags_ace = -1;
static int hf_tcp_flags_urg = -1;
static int hf_tcp_flags_ack = -1;
static int hf_tcp_flags_push = -1;
@ -234,6 +236,9 @@ static int hf_tcp_option_qs_rate = -1;
static int hf_tcp_option_qs_ttl_diff = -1;
static int hf_tcp_option_tarr_rate = -1;
static int hf_tcp_option_tarr_reserved = -1;
static int hf_tcp_option_acc_ecn_ee0b = -1;
static int hf_tcp_option_acc_ecn_eceb = -1;
static int hf_tcp_option_acc_ecn_ee1b = -1;
static int hf_tcp_option_exp_data = -1;
static int hf_tcp_option_exp_exid = -1;
static int hf_tcp_option_unknown_payload = -1;
@ -381,6 +386,7 @@ static gint ett_tcp_scpsoption_flags = -1;
static gint ett_tcp_option_scps_extended = -1;
static gint ett_tcp_option_user_to = -1;
static gint ett_tcp_option_exp = -1;
static gint ett_tcp_option_acc_ecn = -1;
static gint ett_tcp_option_sack_perm = -1;
static gint ett_tcp_analysis = -1;
static gint ett_tcp_analysis_faults = -1;
@ -520,6 +526,8 @@ static gboolean read_seq_as_syn_cookie = FALSE;
#define TCPOPT_AO 29 /* RFC5925 The TCP Authentication Option */
#define TCPOPT_MPTCP 30 /* RFC6824 Multipath TCP */
#define TCPOPT_TFO 34 /* RFC7413 TCP Fast Open Cookie */
#define TCPOPT_ACC_ECN_0 0xac /* draft-ietf-tcpm-accurate-ecn */
#define TCPOPT_ACC_ECN_1 0xae /* draft-ietf-tcpm-accurate-ecn */
#define TCPOPT_EXP_FD 0xfd /* Experimental, reserved */
#define TCPOPT_EXP_FE 0xfe /* Experimental, reserved */
/* Non IANA registered option numbers */
@ -635,6 +643,8 @@ static const value_string tcp_option_kind_vs[] = {
{ TCPOPT_TFO, "TCP Fast Open Cookie" },
{ TCPOPT_RVBD_PROBE, "Riverbed Probe" },
{ TCPOPT_RVBD_TRPY, "Riverbed Transparency" },
{ TCPOPT_ACC_ECN_0, "Accurate ECN Order 0" },
{ TCPOPT_ACC_ECN_1, "Accurate ECN Order 1" },
{ TCPOPT_EXP_FD, "RFC3692-style Experiment 1" },
{ TCPOPT_EXP_FE, "RFC3692-style Experiment 2" },
{ 0, NULL }
@ -752,28 +762,51 @@ static int * const tcp_option_mptcp_tcprst_flags[] = {
static const unit_name_string units_64bit_version = { " (64bits version)", NULL };
static guint8
tcp_get_ace(const struct tcpheader *tcph)
{
guint8 ace;
ace = 0;
if (tcph->th_flags & TH_AE) {
ace += 4;
}
if (tcph->th_flags & TH_CWR) {
ace += 2;
}
if (tcph->th_flags & TH_ECE) {
ace += 1;
}
return ace;
}
static char *
tcp_flags_to_str(wmem_allocator_t *scope, const struct tcpheader *tcph)
{
static const char flags[][4] = { "FIN", "SYN", "RST", "PSH", "ACK", "URG", "ECE", "CWR", "NS" };
static const char flags[][4] = { "FIN", "SYN", "RST", "PSH", "ACK", "URG", "ECE", "CWR", "AE" };
static const char digit[][2] = { "0", "1", "2", "3", "4", "5", "6", "7" };
const int maxlength = 64; /* upper bounds, max 53B: 8 * 3 + 2 + strlen("Reserved") + 9 * 2 + 1 */
char *pbuf;
char *buf;
guint8 ace;
int i;
buf = pbuf = (char *) wmem_alloc(scope, maxlength);
*pbuf = '\0';
for (i = 0; i < 9; i++) {
for (i = 0; i < (tcph->th_use_ace ? 6 : 9); i++) {
if (tcph->th_flags & (1 << i)) {
if (buf[0])
pbuf = g_stpcpy(pbuf, ", ");
pbuf = g_stpcpy(pbuf, flags[i]);
}
}
if (tcph->th_use_ace) {
ace = tcp_get_ace(tcph);
pbuf = g_stpcpy(pbuf, ", ACE=");
pbuf = g_stpcpy(pbuf, digit[ace]);
}
if (tcph->th_flags & TH_RES) {
if (buf[0])
@ -792,14 +825,23 @@ tcp_flags_to_str_first_letter(wmem_allocator_t *scope, const struct tcpheader *t
wmem_strbuf_t *buf = wmem_strbuf_new(scope, "");
unsigned i;
const unsigned flags_count = 12;
const char first_letters[] = "RRRNCEUAPRSF";
const char first_letters[] = "RRRACEUAPRSF";
const char digits[] = "01234567";
/* upper three bytes are marked as reserved ('R'). */
for (i = 0; i < flags_count; i++) {
if (((tcph->th_flags >> (flags_count - 1 - i)) & 1)) {
wmem_strbuf_append_c(buf, first_letters[i]);
if (tcph->th_use_ace && 3 <= i && i <= 5) {
if (i == 4) {
wmem_strbuf_append_c(buf, digits[tcp_get_ace(tcph)]);
} else {
wmem_strbuf_append_c(buf, '-');
}
} else {
wmem_strbuf_append(buf, UTF8_MIDDLE_DOT);
if (((tcph->th_flags >> (flags_count - 1 - i)) & 1)) {
wmem_strbuf_append_c(buf, first_letters[i]);
} else {
wmem_strbuf_append(buf, UTF8_MIDDLE_DOT);
}
}
}
@ -4913,13 +4955,114 @@ dissect_tcpopt_tarr_data(tvbuff_t *tvb, int data_offset, guint data_len,
tcp_info_append_uint(pinfo, "TARR", rate);
proto_item_append_text(item, " %u", rate);
break;
}
}
}
static void
dissect_tcpopt_acc_ecn_data(tvbuff_t *tvb, int data_offset, guint data_len,
gboolean is_order_0, packet_info *pinfo, proto_tree *tree, proto_item *item, void *data _U_)
{
struct tcp_analysis *tcpd;
gint32 ee0b, eceb, ee1b;
switch (data_len) {
case 0:
col_append_str(pinfo->cinfo, COL_INFO, " AccECN");
break;
case 3:
if (is_order_0) {
ee0b = tvb_get_gint24(tvb, data_offset, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_tcp_option_acc_ecn_ee0b, tvb, data_offset, 3, ENC_BIG_ENDIAN);
proto_item_append_text(item, " (Order 0): EE0B %u", ee0b);
tcp_info_append_uint(pinfo, "EE0B", ee0b);
} else {
ee1b = tvb_get_gint24(tvb, data_offset, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_tcp_option_acc_ecn_ee1b, tvb, data_offset, 3, ENC_BIG_ENDIAN);
proto_item_append_text(item, " (Order 1): EE1B %u", ee1b);
tcp_info_append_uint(pinfo, "EE1B", ee1b);
}
break;
case 6:
if (is_order_0) {
ee0b = tvb_get_gint24(tvb, data_offset, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_tcp_option_acc_ecn_ee0b, tvb, data_offset, 3, ENC_BIG_ENDIAN);
tcp_info_append_uint(pinfo, "EE0B", ee0b);
} else {
ee1b = tvb_get_gint24(tvb, data_offset, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_tcp_option_acc_ecn_ee1b, tvb, data_offset, 3, ENC_BIG_ENDIAN);
tcp_info_append_uint(pinfo, "EE1B", ee1b);
}
eceb = tvb_get_gint24(tvb, data_offset + 3, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_tcp_option_acc_ecn_eceb, tvb, data_offset + 3, 3, ENC_BIG_ENDIAN);
tcp_info_append_uint(pinfo, "ECEB", eceb);
if (is_order_0) {
proto_item_append_text(item, " (Order 0): EE0B %u, ECEB %u", ee0b, eceb);
} else {
proto_item_append_text(item, " (Order 1): EE1B %u, ECEB %u", ee1b, eceb);
}
break;
case 9:
if (is_order_0) {
ee0b = tvb_get_gint24(tvb, data_offset, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_tcp_option_acc_ecn_ee0b, tvb, data_offset, 3, ENC_BIG_ENDIAN);
tcp_info_append_uint(pinfo, "EE0B", ee0b);
} else {
ee1b = tvb_get_gint24(tvb, data_offset, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_tcp_option_acc_ecn_ee1b, tvb, data_offset, 3, ENC_BIG_ENDIAN);
tcp_info_append_uint(pinfo, "EE1B", ee1b);
}
eceb = tvb_get_gint24(tvb, data_offset + 3, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_tcp_option_acc_ecn_eceb, tvb, data_offset + 3, 3, ENC_BIG_ENDIAN);
tcp_info_append_uint(pinfo, "ECEB", eceb);
if (is_order_0) {
ee1b = tvb_get_gint24(tvb, data_offset + 6, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_tcp_option_acc_ecn_ee1b, tvb, data_offset + 6, 3, ENC_BIG_ENDIAN);
tcp_info_append_uint(pinfo, "EE1B", ee1b);
proto_item_append_text(item, " (Order 0): EE0B %u, ECEB %u, EE1B %u", ee0b, eceb, ee1b);
} else {
ee0b = tvb_get_gint24(tvb, data_offset + 6, ENC_BIG_ENDIAN);
proto_tree_add_item(tree, hf_tcp_option_acc_ecn_ee0b, tvb, data_offset + 6, 3, ENC_BIG_ENDIAN);
tcp_info_append_uint(pinfo, "EE0B", ee0b);
proto_item_append_text(item, " (Order 1): EE1B %u, ECEB %u, EE0B %u", ee1b, eceb, ee0b);
}
break;
}
tcpd = get_tcp_conversation_data(NULL, pinfo);
if (tcpd != NULL) {
tcpd->had_acc_ecn_option = TRUE;
}
}
static int
dissect_tcpopt_acc_ecn(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
{
proto_item *length_item, *item;
proto_tree *acc_ecn_tree;
int offset;
guint8 kind, length;
offset = 0;
item = proto_tree_add_item(tree, proto_tcp_option_acc_ecn, tvb, offset, -1, ENC_NA);
acc_ecn_tree = proto_item_add_subtree(item, ett_tcp_option_acc_ecn);
kind = tvb_get_guint8(tvb, offset);
proto_tree_add_item(acc_ecn_tree, hf_tcp_option_kind, tvb, offset, 1, ENC_BIG_ENDIAN);
offset += 1;
length = tvb_get_guint8(tvb, offset);
length_item = proto_tree_add_item(acc_ecn_tree, hf_tcp_option_len, tvb, offset, 1, ENC_BIG_ENDIAN);
offset += 1;
if (length != 2 && length != 5 && length != 8 && length != 11) {
expert_add_info_format(pinfo, length_item, &ei_tcp_opt_len_invalid,
"option length should be 2, 5, 8, or 11 instead of %u", length);
} else {
dissect_tcpopt_acc_ecn_data(tvb, offset, length - 2, kind == TCPOPT_ACC_ECN_0, pinfo, acc_ecn_tree, item, data);
}
return tvb_captured_length(tvb);
}
static int
dissect_tcpopt_exp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
{
proto_item *length_item, *item;
proto_item *item, *length_item;
proto_tree *exp_tree;
guint16 exid;
guint8 kind;
@ -4947,6 +5090,19 @@ dissect_tcpopt_exp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* da
pinfo, exp_tree, item, data);
}
break;
case 0xACC0: /* draft-ietf-tcpm-accurate-ecn-20 */
case 0xACC1:
if (optlen != 4 && optlen != 7 && optlen != 10 && optlen != 13) {
expert_add_info_format(pinfo, length_item, &ei_tcp_opt_len_invalid,
"option length should be 4, 7, 10, or 13 instead of %d",
optlen);
} else {
proto_item_append_text(item, ": Accurate ECN");
dissect_tcpopt_acc_ecn_data(tvb, offset + 4, optlen - 4,
exid == 0xACC0, pinfo, exp_tree,
item, data);
}
break;
case TCPEXID_FO:
dissect_tcpopt_tfo_payload(tvb, offset + 2, optlen - 2, pinfo, exp_tree, data);
break;
@ -7190,6 +7346,7 @@ dissect_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
gboolean icmp_ip = FALSE;
guint8 conversation_completeness = 0;
gboolean conversation_is_new = FALSE;
guint8 ace;
tcph = wmem_new0(pinfo->pool, struct tcpheader);
tcph->th_sport = tvb_get_ntohs(tvb, offset);
@ -7284,37 +7441,38 @@ dissect_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
* retransmission later.
* XXX - Is this affected by MPTCP which can use multiple SYNs?
*/
if(tcpd && ((tcph->th_flags&(TH_SYN|TH_ACK))==TH_SYN) &&
(tcpd->fwd->static_flags & TCP_S_BASE_SEQ_SET)) {
if(tcph->th_seq!=tcpd->fwd->base_seq) {
if (!(pinfo->fd->visited)) {
if (tcpd != NULL && (tcph->th_flags & (TH_SYN|TH_ACK)) == TH_SYN) {
if (tcpd->fwd->static_flags & TCP_S_BASE_SEQ_SET) {
if(tcph->th_seq!=tcpd->fwd->base_seq) {
if (!(pinfo->fd->visited)) {
conv=conversation_new(pinfo->num, &pinfo->src, &pinfo->dst, ENDPOINT_TCP, pinfo->srcport, pinfo->destport, 0);
tcpd=get_tcp_conversation_data(conv,pinfo);
conv=conversation_new(pinfo->num, &pinfo->src, &pinfo->dst, ENDPOINT_TCP, pinfo->srcport, pinfo->destport, 0);
tcpd=get_tcp_conversation_data(conv,pinfo);
if(!tcpd->ta)
tcp_analyze_get_acked_struct(pinfo->num, tcph->th_seq, tcph->th_ack, TRUE, tcpd);
tcpd->ta->flags|=TCP_A_REUSED_PORTS;
if(!tcpd->ta)
tcp_analyze_get_acked_struct(pinfo->num, tcph->th_seq, tcph->th_ack, TRUE, tcpd);
tcpd->ta->flags|=TCP_A_REUSED_PORTS;
/* As above, a new conversation starting with a SYN implies conversation completeness value 1 */
tcpd->conversation_completeness = 1;
}
}
else {
if (!(pinfo->fd->visited)) {
/*
* Sometimes we need to restore the nextseq value.
* As stated in RFC 793 3.4 a RST packet might be
* sent with SEQ being equal to the ACK received,
* thus breaking our flow monitoring. (issue 17616)
*/
tcpd->fwd->tcp_analyze_seq_info->nextseq = tcpd->fwd->tcp_analyze_seq_info->maxseqtobeacked;
if(!tcpd->ta)
tcp_analyze_get_acked_struct(pinfo->num, tcph->th_seq, tcph->th_ack, TRUE, tcpd);
tcpd->ta->flags|=TCP_A_REUSED_PORTS;
/* As above, a new conversation starting with a SYN implies conversation completeness value 1 */
tcpd->conversation_completeness = 1;
}
} else {
if (!(pinfo->fd->visited)) {
/*
* Sometimes we need to restore the nextseq value.
* As stated in RFC 793 3.4 a RST packet might be
* sent with SEQ being equal to the ACK received,
* thus breaking our flow monitoring. (issue 17616)
*/
tcpd->fwd->tcp_analyze_seq_info->nextseq = tcpd->fwd->tcp_analyze_seq_info->maxseqtobeacked;
if(!tcpd->ta)
tcp_analyze_get_acked_struct(pinfo->num, tcph->th_seq, tcph->th_ack, TRUE, tcpd);
tcpd->ta->flags|=TCP_A_REUSED_PORTS;
}
}
}
tcpd->had_acc_ecn_setup_syn = (tcph->th_flags & (TH_AE|TH_CWR|TH_ECE)) == (TH_AE|TH_CWR|TH_ECE);
}
/* If this is a SYN/ACK packet, then check if its seq-nr is different
@ -7325,16 +7483,19 @@ dissect_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
* mission later.
* XXX - Is this affected by MPTCP which can use multiple SYNs?
*/
if(tcpd && ((tcph->th_flags&(TH_SYN|TH_ACK))==(TH_SYN|TH_ACK)) &&
(tcpd->fwd->static_flags & TCP_S_BASE_SEQ_SET) &&
(tcph->th_seq!=tcpd->fwd->base_seq) ) {
if (tcpd != NULL && (tcph->th_flags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) {
if ((tcpd->fwd->static_flags & TCP_S_BASE_SEQ_SET) &&
(tcph->th_seq != tcpd->fwd->base_seq)) {
/* the retrieved conversation might have a different base_seq (issue 16944) */
tcpd->fwd->base_seq = tcph->th_seq;
/* the retrieved conversation might have a different base_seq (issue 16944) */
tcpd->fwd->base_seq = tcph->th_seq;
if(!tcpd->ta)
tcp_analyze_get_acked_struct(pinfo->num, tcph->th_seq, tcph->th_ack, TRUE, tcpd);
tcpd->ta->flags|=TCP_A_REUSED_PORTS;
if(!tcpd->ta)
tcp_analyze_get_acked_struct(pinfo->num, tcph->th_seq, tcph->th_ack, TRUE, tcpd);
tcpd->ta->flags|=TCP_A_REUSED_PORTS;
}
tcpd->had_acc_ecn_setup_syn_ack = ((tcph->th_flags & (TH_AE|TH_CWR)) == TH_CWR) ||
((tcph->th_flags & (TH_AE|TH_ECE)) == TH_AE);
}
if (tcpd) {
@ -7433,6 +7594,16 @@ dissect_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
} else
tcph->th_have_seglen = FALSE;
/*
* Decode the ECN related flags as ACE if it is not a SYN segment,
* and an AccECN-setup SYN and SYN ACK have been observed, or an
* AccECN option was observed (this covers the case where Wireshark
* did not observe the initial handshake).
*/
tcph->th_use_ace = (tcph->th_flags & TH_SYN) == 0 &&
tcpd != NULL &&
((tcpd->had_acc_ecn_setup_syn && tcpd->had_acc_ecn_setup_syn_ack) ||
tcpd->had_acc_ecn_option);
flags_str = tcp_flags_to_str(pinfo->pool, tcph);
flags_str_first_letter = tcp_flags_to_str_first_letter(pinfo->pool, tcph);
@ -7592,9 +7763,19 @@ dissect_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
tcph->th_flags, "Flags: 0x%03x (%s)", tcph->th_flags, flags_str);
field_tree = proto_item_add_subtree(tf, ett_tcp_flags);
proto_tree_add_boolean(field_tree, hf_tcp_flags_res, tvb, offset + 12, 1, tcph->th_flags);
proto_tree_add_boolean(field_tree, hf_tcp_flags_ns, tvb, offset + 12, 1, tcph->th_flags);
proto_tree_add_boolean(field_tree, hf_tcp_flags_cwr, tvb, offset + 13, 1, tcph->th_flags);
proto_tree_add_boolean(field_tree, hf_tcp_flags_ece, tvb, offset + 13, 1, tcph->th_flags);
if (tcph->th_use_ace) {
ace = tcp_get_ace(tcph);
proto_tree_add_uint_format(field_tree, hf_tcp_flags_ace, tvb, 12, 2, ace,
"...%c %c%c.. .... = ACE: %u",
ace & 0x04 ? '1' : '0',
ace & 0x02 ? '1' : '0',
ace & 0x01 ? '1' : '0',
ace);
} else {
proto_tree_add_boolean(field_tree, hf_tcp_flags_ae, tvb, offset + 12, 1, tcph->th_flags);
proto_tree_add_boolean(field_tree, hf_tcp_flags_cwr, tvb, offset + 13, 1, tcph->th_flags);
proto_tree_add_boolean(field_tree, hf_tcp_flags_ece, tvb, offset + 13, 1, tcph->th_flags);
}
proto_tree_add_boolean(field_tree, hf_tcp_flags_urg, tvb, offset + 13, 1, tcph->th_flags);
proto_tree_add_boolean(field_tree, hf_tcp_flags_ack, tvb, offset + 13, 1, tcph->th_flags);
proto_tree_add_boolean(field_tree, hf_tcp_flags_push, tvb, offset + 13, 1, tcph->th_flags);
@ -8158,9 +8339,9 @@ proto_register_tcp(void)
{ "Reserved", "tcp.flags.res", FT_BOOLEAN, 12, TFS(&tfs_set_notset), TH_RES,
"Three reserved bits (must be zero)", HFILL }},
{ &hf_tcp_flags_ns,
{ "Nonce", "tcp.flags.ns", FT_BOOLEAN, 12, TFS(&tfs_set_notset), TH_NS,
"ECN concealment protection (RFC 3540)", HFILL }},
{ &hf_tcp_flags_ae,
{ "Accurate ECN", "tcp.flags.ae", FT_BOOLEAN, 12, TFS(&tfs_set_notset), TH_AE,
NULL, HFILL }},
{ &hf_tcp_flags_cwr,
{ "Congestion Window Reduced", "tcp.flags.cwr", FT_BOOLEAN, 12, TFS(&tfs_set_notset), TH_CWR,
@ -8170,6 +8351,10 @@ proto_register_tcp(void)
{ "ECN-Echo", "tcp.flags.ece", FT_BOOLEAN, 12, TFS(&tfs_set_notset), TH_ECE,
NULL, HFILL }},
{ &hf_tcp_flags_ace,
{ "ACE", "tcp.flags.ace", FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL }},
{ &hf_tcp_flags_urg,
{ "Urgent", "tcp.flags.urg", FT_BOOLEAN, 12, TFS(&tfs_set_notset), TH_URG,
NULL, HFILL }},
@ -8591,6 +8776,21 @@ proto_register_tcp(void)
{ "TARR Reserved", "tcp.options.tar.reserved", FT_UINT16, BASE_DEC,
NULL, TCPOPT_TARR_RESERVED_MASK, NULL, HFILL}},
{ &hf_tcp_option_acc_ecn_ee0b,
{ "Accurate ECN Echo ECT(0) Byte Counter", "tcp.options.acc_ecn.ee0b",
FT_UINT24, BASE_DEC, NULL, 0x0,
NULL, HFILL}},
{ &hf_tcp_option_acc_ecn_eceb,
{ "Accurate ECN Echo CE Byte Counter", "tcp.options.acc_ecn.eceb",
FT_UINT24, BASE_DEC, NULL, 0x0,
NULL, HFILL}},
{ &hf_tcp_option_acc_ecn_ee1b,
{ "Accurate ECN Echo ECT(1) Byte Counter", "tcp.options.acc_ecn.ee1b",
FT_UINT24, BASE_DEC, NULL, 0x0,
NULL, HFILL}},
{ &hf_tcp_option_scps_vector,
{ "TCP SCPS Capabilities Vector", "tcp.options.scps.vector",
FT_UINT8, BASE_HEX, NULL, 0x0,
@ -8929,6 +9129,7 @@ proto_register_tcp(void)
&ett_tcp_option_scps_extended,
&ett_tcp_option_user_to,
&ett_tcp_option_exp,
&ett_tcp_option_acc_ecn,
&ett_tcp_option_sack_perm,
&ett_tcp_option_mss,
&ett_tcp_opt_rvbd_probe,
@ -9147,6 +9348,7 @@ proto_register_tcp(void)
proto_tcp_option_qs = proto_register_protocol_in_name_only("TCP Option - Quick-Start", "Quick-Start", "tcp.options.qs", proto_tcp, FT_BYTES);
proto_tcp_option_user_to = proto_register_protocol_in_name_only("TCP Option - User Timeout", "User Timeout", "tcp.options.user_to", proto_tcp, FT_BYTES);
proto_tcp_option_tfo = proto_register_protocol_in_name_only("TCP Option - TCP Fast Open", "TCP Fast Open", "tcp.options.tfo", proto_tcp, FT_BYTES);
proto_tcp_option_acc_ecn = proto_register_protocol_in_name_only("TCP Option - Accurate ECN", "Accurate ECN", "tcp.options.acc_ecn", proto_tcp, FT_BYTES);
proto_tcp_option_rvbd_probe = proto_register_protocol_in_name_only("TCP Option - Riverbed Probe", "Riverbed Probe", "tcp.options.rvbd.probe", proto_tcp, FT_BYTES);
proto_tcp_option_rvbd_trpy = proto_register_protocol_in_name_only("TCP Option - Riverbed Transparency", "Riverbed Transparency", "tcp.options.rvbd.trpy", proto_tcp, FT_BYTES);
proto_tcp_option_exp = proto_register_protocol_in_name_only("TCP Option - Experimental", "Experimental", "tcp.options.experimental", proto_tcp, FT_BYTES);
@ -9328,6 +9530,8 @@ proto_reg_handoff_tcp(void)
dissector_add_uint("tcp.option", TCPOPT_TFO, create_dissector_handle( dissect_tcpopt_tfo, proto_tcp_option_tfo ));
dissector_add_uint("tcp.option", TCPOPT_RVBD_PROBE, create_dissector_handle( dissect_tcpopt_rvbd_probe, proto_tcp_option_rvbd_probe ));
dissector_add_uint("tcp.option", TCPOPT_RVBD_TRPY, create_dissector_handle( dissect_tcpopt_rvbd_trpy, proto_tcp_option_rvbd_trpy ));
dissector_add_uint("tcp.option", TCPOPT_ACC_ECN_0, create_dissector_handle( dissect_tcpopt_acc_ecn, proto_tcp_option_acc_ecn ));
dissector_add_uint("tcp.option", TCPOPT_ACC_ECN_1, create_dissector_handle( dissect_tcpopt_acc_ecn, proto_tcp_option_acc_ecn ));
dissector_add_uint("tcp.option", TCPOPT_EXP_FD, create_dissector_handle( dissect_tcpopt_exp, proto_tcp_option_exp ));
dissector_add_uint("tcp.option", TCPOPT_EXP_FE, create_dissector_handle( dissect_tcpopt_exp, proto_tcp_option_exp ));
dissector_add_uint("tcp.option", TCPOPT_MPTCP, create_dissector_handle( dissect_tcpopt_mptcp, proto_mptcp ));

View File

@ -29,7 +29,7 @@ extern "C" {
#define TH_URG 0x0020
#define TH_ECE 0x0040
#define TH_CWR 0x0080
#define TH_NS 0x0100
#define TH_AE 0x0100
#define TH_RES 0x0E00 /* 3 reserved bits */
#define TH_MASK 0x0FFF
@ -89,6 +89,7 @@ typedef struct tcpheader {
guint16 th_sport;
guint16 th_dport;
guint8 th_hlen;
gboolean th_use_ace;
guint16 th_flags;
guint32 th_stream; /* this stream index field is included to help differentiate when address/port pairs are reused */
address ip_src;
@ -487,6 +488,11 @@ struct tcp_analysis {
* connection or left before it was terminated explicitly
*/
guint8 conversation_completeness;
/* Track AccECN support */
gboolean had_acc_ecn_setup_syn;
gboolean had_acc_ecn_setup_syn_ack;
gboolean had_acc_ecn_option;
};
/* Structure that keeps per packet data. First used to be able