uint32_t get_next_seqnum(struct tcp_buf *tcp_buffer, int seq, struct ofpbuf *packet, bool loss_recovery){ unsigned int size; uint8_t tcp_flags; struct tcp_header *tcp; tcp = ofpbuf_l4(packet); tcp_flags = TCP_FLAGS(tcp->tcp_ctl); size = get_tcp_payload_size(packet); // Sliding the expected seq forward to recover from the probable burst // of losts packets if(loss_recovery){ return (seq + (get_tcp_payload_size(packet)*LOSS_RECOVERY_SLIDING)) % 0xFFFFFFFF; } else { if(tcp_flags & TCP_FIN){ VLOG_INFO("Last packet above was FIN"); tcp_buffer->fin_state = true; return (seq + size + 1) % 0xFFFFFFFF; } else{ return (seq + size) % 0xFFFFFFFF; } } }
/* If 'packet' is a TCP packet, returns the TCP flags. Otherwise, returns 0. * * 'flow' must be the flow corresponding to 'packet' and 'packet''s header * pointers must be properly initialized (e.g. with flow_extract()). */ uint8_t packet_get_tcp_flags(const struct ofpbuf *packet, const struct flow *flow) { if ((flow->dl_type == htons(ETH_TYPE_IP) || flow->dl_type == htons(ETH_TYPE_IPV6)) && flow->nw_proto == IPPROTO_TCP && packet->l7) { const struct tcp_header *tcp = packet->l4; return TCP_FLAGS(tcp->tcp_ctl); } else { return 0; } }
/* Extracts the flow stats for a packet. The 'flow' and 'packet' * arguments must have been initialized through a call to flow_extract(). */ void flow_extract_stats(const flow_t *flow, struct ofpbuf *packet, struct odp_flow_stats *stats) { memset(stats, '\0', sizeof(*stats)); if ((flow->dl_type == htons(ETH_TYPE_IP)) && packet->l4) { if ((flow->nw_proto == IP_TYPE_TCP) && packet->l7) { struct tcp_header *tcp = packet->l4; stats->tcp_flags = TCP_FLAGS(tcp->tcp_ctl); } } stats->n_bytes = packet->size; stats->n_packets = 1; }
/* Appends a string representation of 'match' to 's'. If 'priority' is * different from OFP_DEFAULT_PRIORITY, includes it in 's'. */ void match_format(const struct match *match, struct ds *s, unsigned int priority) { const struct flow_wildcards *wc = &match->wc; size_t start_len = s->length; const struct flow *f = &match->flow; bool skip_type = false; bool skip_proto = false; int i; BUILD_ASSERT_DECL(FLOW_WC_SEQ == 26); if (priority != OFP_DEFAULT_PRIORITY) { ds_put_format(s, "priority=%u,", priority); } format_uint32_masked(s, "pkt_mark", f->pkt_mark, wc->masks.pkt_mark); if (wc->masks.recirc_id) { format_uint32_masked(s, "recirc_id", f->recirc_id, wc->masks.recirc_id); } if (f->dp_hash && wc->masks.dp_hash) { format_uint32_masked(s, "dp_hash", f->dp_hash, wc->masks.dp_hash); } if (wc->masks.skb_priority) { ds_put_format(s, "skb_priority=%#"PRIx32",", f->skb_priority); } if (wc->masks.dl_type) { skip_type = true; if (f->dl_type == htons(ETH_TYPE_IP)) { if (wc->masks.nw_proto) { skip_proto = true; if (f->nw_proto == IPPROTO_ICMP) { ds_put_cstr(s, "icmp,"); } else if (f->nw_proto == IPPROTO_TCP) { ds_put_cstr(s, "tcp,"); } else if (f->nw_proto == IPPROTO_UDP) { ds_put_cstr(s, "udp,"); } else if (f->nw_proto == IPPROTO_SCTP) { ds_put_cstr(s, "sctp,"); } else { ds_put_cstr(s, "ip,"); skip_proto = false; } } else { ds_put_cstr(s, "ip,"); } } else if (f->dl_type == htons(ETH_TYPE_IPV6)) { if (wc->masks.nw_proto) { skip_proto = true; if (f->nw_proto == IPPROTO_ICMPV6) { ds_put_cstr(s, "icmp6,"); } else if (f->nw_proto == IPPROTO_TCP) { ds_put_cstr(s, "tcp6,"); } else if (f->nw_proto == IPPROTO_UDP) { ds_put_cstr(s, "udp6,"); } else if (f->nw_proto == IPPROTO_SCTP) { ds_put_cstr(s, "sctp6,"); } else { ds_put_cstr(s, "ipv6,"); skip_proto = false; } } else { ds_put_cstr(s, "ipv6,"); } } else if (f->dl_type == htons(ETH_TYPE_ARP)) { ds_put_cstr(s, "arp,"); } else if (f->dl_type == htons(ETH_TYPE_RARP)) { ds_put_cstr(s, "rarp,"); } else if (f->dl_type == htons(ETH_TYPE_MPLS)) { ds_put_cstr(s, "mpls,"); } else if (f->dl_type == htons(ETH_TYPE_MPLS_MCAST)) { ds_put_cstr(s, "mplsm,"); } else { skip_type = false; } } for (i = 0; i < FLOW_N_REGS; i++) { #define REGNAME_LEN 20 char regname[REGNAME_LEN]; if (snprintf(regname, REGNAME_LEN, "reg%d", i) >= REGNAME_LEN) { strcpy(regname, "reg?"); } format_uint32_masked(s, regname, f->regs[i], wc->masks.regs[i]); } format_flow_tunnel(s, match); format_be64_masked(s, "metadata", f->metadata, wc->masks.metadata); if (wc->masks.in_port.ofp_port) { ds_put_cstr(s, "in_port="); ofputil_format_port(f->in_port.ofp_port, s); ds_put_char(s, ','); } if (wc->masks.vlan_tci) { ovs_be16 vid_mask = wc->masks.vlan_tci & htons(VLAN_VID_MASK); ovs_be16 pcp_mask = wc->masks.vlan_tci & htons(VLAN_PCP_MASK); ovs_be16 cfi = wc->masks.vlan_tci & htons(VLAN_CFI); if (cfi && f->vlan_tci & htons(VLAN_CFI) && (!vid_mask || vid_mask == htons(VLAN_VID_MASK)) && (!pcp_mask || pcp_mask == htons(VLAN_PCP_MASK)) && (vid_mask || pcp_mask)) { if (vid_mask) { ds_put_format(s, "dl_vlan=%"PRIu16",", vlan_tci_to_vid(f->vlan_tci)); } if (pcp_mask) { ds_put_format(s, "dl_vlan_pcp=%d,", vlan_tci_to_pcp(f->vlan_tci)); } } else if (wc->masks.vlan_tci == htons(0xffff)) { ds_put_format(s, "vlan_tci=0x%04"PRIx16",", ntohs(f->vlan_tci)); } else { ds_put_format(s, "vlan_tci=0x%04"PRIx16"/0x%04"PRIx16",", ntohs(f->vlan_tci), ntohs(wc->masks.vlan_tci)); } } format_eth_masked(s, "dl_src", f->dl_src, wc->masks.dl_src); format_eth_masked(s, "dl_dst", f->dl_dst, wc->masks.dl_dst); if (!skip_type && wc->masks.dl_type) { ds_put_format(s, "dl_type=0x%04"PRIx16",", ntohs(f->dl_type)); } if (f->dl_type == htons(ETH_TYPE_IPV6)) { format_ipv6_netmask(s, "ipv6_src", &f->ipv6_src, &wc->masks.ipv6_src); format_ipv6_netmask(s, "ipv6_dst", &f->ipv6_dst, &wc->masks.ipv6_dst); if (wc->masks.ipv6_label) { if (wc->masks.ipv6_label == OVS_BE32_MAX) { ds_put_format(s, "ipv6_label=0x%05"PRIx32",", ntohl(f->ipv6_label)); } else { ds_put_format(s, "ipv6_label=0x%05"PRIx32"/0x%05"PRIx32",", ntohl(f->ipv6_label), ntohl(wc->masks.ipv6_label)); } } } else if (f->dl_type == htons(ETH_TYPE_ARP) || f->dl_type == htons(ETH_TYPE_RARP)) { format_ip_netmask(s, "arp_spa", f->nw_src, wc->masks.nw_src); format_ip_netmask(s, "arp_tpa", f->nw_dst, wc->masks.nw_dst); } else { format_ip_netmask(s, "nw_src", f->nw_src, wc->masks.nw_src); format_ip_netmask(s, "nw_dst", f->nw_dst, wc->masks.nw_dst); } if (!skip_proto && wc->masks.nw_proto) { if (f->dl_type == htons(ETH_TYPE_ARP) || f->dl_type == htons(ETH_TYPE_RARP)) { ds_put_format(s, "arp_op=%"PRIu8",", f->nw_proto); } else { ds_put_format(s, "nw_proto=%"PRIu8",", f->nw_proto); } } if (f->dl_type == htons(ETH_TYPE_ARP) || f->dl_type == htons(ETH_TYPE_RARP)) { format_eth_masked(s, "arp_sha", f->arp_sha, wc->masks.arp_sha); format_eth_masked(s, "arp_tha", f->arp_tha, wc->masks.arp_tha); } if (wc->masks.nw_tos & IP_DSCP_MASK) { ds_put_format(s, "nw_tos=%"PRIu8",", f->nw_tos & IP_DSCP_MASK); } if (wc->masks.nw_tos & IP_ECN_MASK) { ds_put_format(s, "nw_ecn=%"PRIu8",", f->nw_tos & IP_ECN_MASK); } if (wc->masks.nw_ttl) { ds_put_format(s, "nw_ttl=%"PRIu8",", f->nw_ttl); } if (wc->masks.mpls_lse[0] & htonl(MPLS_LABEL_MASK)) { ds_put_format(s, "mpls_label=%"PRIu32",", mpls_lse_to_label(f->mpls_lse[0])); } if (wc->masks.mpls_lse[0] & htonl(MPLS_TC_MASK)) { ds_put_format(s, "mpls_tc=%"PRIu8",", mpls_lse_to_tc(f->mpls_lse[0])); } if (wc->masks.mpls_lse[0] & htonl(MPLS_TTL_MASK)) { ds_put_format(s, "mpls_ttl=%"PRIu8",", mpls_lse_to_ttl(f->mpls_lse[0])); } if (wc->masks.mpls_lse[0] & htonl(MPLS_BOS_MASK)) { ds_put_format(s, "mpls_bos=%"PRIu8",", mpls_lse_to_bos(f->mpls_lse[0])); } format_be32_masked(s, "mpls_lse1", f->mpls_lse[1], wc->masks.mpls_lse[1]); format_be32_masked(s, "mpls_lse2", f->mpls_lse[2], wc->masks.mpls_lse[2]); switch (wc->masks.nw_frag) { case FLOW_NW_FRAG_ANY | FLOW_NW_FRAG_LATER: ds_put_format(s, "nw_frag=%s,", f->nw_frag & FLOW_NW_FRAG_ANY ? (f->nw_frag & FLOW_NW_FRAG_LATER ? "later" : "first") : (f->nw_frag & FLOW_NW_FRAG_LATER ? "<error>" : "no")); break; case FLOW_NW_FRAG_ANY: ds_put_format(s, "nw_frag=%s,", f->nw_frag & FLOW_NW_FRAG_ANY ? "yes" : "no"); break; case FLOW_NW_FRAG_LATER: ds_put_format(s, "nw_frag=%s,", f->nw_frag & FLOW_NW_FRAG_LATER ? "later" : "not_later"); break; } if (f->dl_type == htons(ETH_TYPE_IP) && f->nw_proto == IPPROTO_ICMP) { format_be16_masked(s, "icmp_type", f->tp_src, wc->masks.tp_src); format_be16_masked(s, "icmp_code", f->tp_dst, wc->masks.tp_dst); //add by ljx // format_be16_masked(s, "icmp_identify", *(ovs_be16*)(&f->ipv6_label), // *(ovs_be16*)&wc->masks.ipv6_label); format_be16_masked(s, "icmp_identify", f->ipv6_label, wc->masks.ipv6_label); } else if (f->dl_type == htons(ETH_TYPE_IPV6) && f->nw_proto == IPPROTO_ICMPV6) { format_be16_masked(s, "icmp_type", f->tp_src, wc->masks.tp_src); format_be16_masked(s, "icmp_code", f->tp_dst, wc->masks.tp_dst); format_ipv6_netmask(s, "nd_target", &f->nd_target, &wc->masks.nd_target); format_eth_masked(s, "nd_sll", f->arp_sha, wc->masks.arp_sha); format_eth_masked(s, "nd_tll", f->arp_tha, wc->masks.arp_tha); } else { format_be16_masked(s, "tp_src", f->tp_src, wc->masks.tp_src); format_be16_masked(s, "tp_dst", f->tp_dst, wc->masks.tp_dst); } if (is_ip_any(f) && f->nw_proto == IPPROTO_TCP && wc->masks.tcp_flags) { uint16_t mask = TCP_FLAGS(wc->masks.tcp_flags); if (mask == TCP_FLAGS(OVS_BE16_MAX)) { ds_put_format(s, "tcp_flags=0x%03"PRIx16",", ntohs(f->tcp_flags)); } else { format_flags_masked(s, "tcp_flags", packet_tcp_flag_to_string, ntohs(f->tcp_flags), mask); } } if (s->length > start_len && ds_last(s) == ',') { s->length--; } }
int get_packet_list(struct ofpbuf *out_packets[], struct ofpbuf * packet, uint32_t flow_id, uint32_t in_port){ struct tcp_buf * tcp_buf; uint8_t tcp_flags; struct tcp_header *tcp; uint32_t seq; int i, out_packets_count; uint32_t seq_work; struct ofpbuf * buf_pkt; int removed_items; // Getting the buffer for the flow, or creating a new one if // not existing tcp_buf = get_tcp_buf(flow_id); tcp = ofpbuf_l4(packet); tcp_flags = TCP_FLAGS(tcp->tcp_ctl); seq = get_tcp_seq(packet); out_packets_count = 0; if (tcp_flags & TCP_SYN){ tcp_buf->expected_seqnum = seq+1; VLOG_INFO("[SYN packet] sequence: %" PRIu32 " expected: %" PRIu32 " in_port: %"PRIu32 " size: %d", seq, tcp_buf->expected_seqnum, in_port, tcp_buf->inserted_items); out_packets[out_packets_count] = packet; out_packets_count++; } else if(tcp_buf->fin_state){ delete_tcp_buf(tcp_buf); out_packets[out_packets_count] = packet; out_packets_count++; } // Retransmission or packets which come without a SYN or after a FIN // Just send out else if(tcp_buf->expected_seqnum == -1){ out_packets[out_packets_count] = packet; out_packets_count++; } // Sending out and checking if the the gap in the reordering buffer has been filled else if(seq <= tcp_buf->expected_seqnum){ VLOG_INFO("[sending in order packet] seq: %"PRIu32 " expected: %" PRIu32 " in_port: %"PRIu32 " size: %d", seq, tcp_buf->expected_seqnum, in_port, tcp_buf->inserted_items); out_packets[out_packets_count] = packet; out_packets_count++; tcp_buf->consecutive_buffering_events = 0; // Increasing sequence only if it matches if(seq == tcp_buf->expected_seqnum){ tcp_buf->expected_seqnum = get_next_seqnum(tcp_buf, tcp_buf->expected_seqnum, packet, false); } // Check if there are packets waiting to be sent removed_items = 0; for(i=tcp_buf->inserted_items-1;i>= 0;i--){ seq_work = get_tcp_seq(tcp_buf->buffer[i]); if(seq_work <= tcp_buf->expected_seqnum){ VLOG_INFO("[sending out from buffer] sequence: %" PRIu32 " expected: %" PRIu32 " size: %d", seq_work, tcp_buf->expected_seqnum, tcp_buf->inserted_items - removed_items); removed_items++; out_packets[out_packets_count] = tcp_buf->buffer[i]; out_packets_count++; if(seq_work == tcp_buf->expected_seqnum){ tcp_buf->expected_seqnum = get_next_seqnum(tcp_buf, tcp_buf->expected_seqnum, tcp_buf->buffer[i], false); } } } tcp_buf->inserted_items = tcp_buf->inserted_items - removed_items; } // Buffer not full yet, buffering the packet else if(tcp_buf->inserted_items<TCP_BUF_SIZE && tcp_buf->consecutive_buffering_events < CONSECUTIVE_BUFFERING_TREESHOLD){ VLOG_INFO("[buffering] sequence: %"PRIu32 " expected: %" PRIu32 " in_port: %"PRIu32 " size: %d", seq, tcp_buf->expected_seqnum, in_port, tcp_buf->inserted_items); buf_pkt = ofpbuf_clone(packet); insert_descending_order(tcp_buf, buf_pkt); } // Buffer full or loss event detecte else{ VLOG_WARN("!! -- Empty Buffer Event -- !!"); if(tcp_buf->consecutive_buffering_events >= CONSECUTIVE_BUFFERING_TREESHOLD) syslog(LOG_INFO, "!! -- Because of an apparent loss -- !!"); seq_work = get_tcp_seq(tcp_buf->buffer[tcp_buf->inserted_items-1]); // If incoming packet has the smallest sequence if(seq<seq_work){ VLOG_INFO("[resetting buffer] sequence: %" PRIu32, seq); out_packets[out_packets_count] = packet; out_packets_count++; } // If a packet in the buffer has the smallest sequence else{ VLOG_INFO("[resetting] sequence: %" PRIu32, get_tcp_seq(tcp_buf->buffer[tcp_buf->inserted_items-1])); out_packets[out_packets_count] = tcp_buf->buffer[tcp_buf->inserted_items-1]; out_packets_count++; tcp_buf->inserted_items--; buf_pkt = ofpbuf_clone(packet); insert_descending_order(tcp_buf, buf_pkt); } // Completely empty the buffer for(i=tcp_buf->inserted_items-1;i>= 0;i--){ seq_work = get_tcp_seq(tcp_buf->buffer[i]); VLOG_INFO("resetting %" PRIu32, seq_work); get_next_seqnum(tcp_buf, seq_work, tcp_buf->buffer[i], false); out_packets[out_packets_count] = tcp_buf->buffer[i]; out_packets_count++; // Adjusting seqnum if(i==0){ tcp_buf->expected_seqnum = get_next_seqnum(tcp_buf, seq_work, tcp_buf->buffer[i], false); } } tcp_buf->inserted_items=0; if(tcp_buf->consecutive_buffering_events >= CONSECUTIVE_BUFFERING_TREESHOLD){ tcp_buf->expected_seqnum = get_next_seqnum(tcp_buf, tcp_buf->expected_seqnum, packet, true); } } return out_packets_count; }
/*************************************************************************** * * Asynchronous receive thread * * The transmit and receive threads run independently of each other. There * is no record what was transmitted. Instead, the transmit thread sets a * "SYN-cookie" in transmitted packets, which the receive thread will then * use to match up requests with responses. ***************************************************************************/ static void receive_thread(void *v) { struct ThreadPair *parms = (struct ThreadPair *)v; const struct Masscan *masscan = parms->masscan; struct Output *out; struct DedupTable *dedup; struct PcapFile *pcapfile = NULL; struct TCP_ConnectionTable *tcpcon = 0; LOG(1, "recv: start receive thread #%u\n", parms->nic_index); /* Lock this thread to a CPU. Transmit threads are on even CPUs, * receive threads on odd CPUs */ if (pixie_cpu_get_count() > 1) { unsigned cpu_count = pixie_cpu_get_count(); unsigned cpu = parms->nic_index * 2 + 1; while (cpu >= cpu_count) { cpu -= cpu_count; cpu++; } pixie_cpu_set_affinity(cpu); } /* * If configured, open a --pcap file for saving raw packets. This is * so that we can debug scans, but also so that we can look at the * strange things people send us. Note that we don't record transmitted * packets, just the packets we've received. */ /*if (masscan->pcap_filename[0]) pcapfile = pcapfile_openwrite(masscan->pcap_filename, 1);*/ /* * Open output. This is where results are reported when saving * the --output-format to the --output-filename */ out = output_create(masscan); /* * Create deduplication table. This is so when somebody sends us * multiple responses, we only record the first one. */ dedup = dedup_create(); /* * Create a TCP connection table for interacting with live * connections when doing --banners */ if (masscan->is_banners) { tcpcon = tcpcon_create_table( (size_t)((masscan->max_rate/5) / masscan->nic_count), parms->transmit_queue, parms->packet_buffers, &parms->tmplset->pkts[Proto_TCP], output_report_banner, out, masscan->tcb.timeout ); } if (masscan->is_offline) { while (!control_c_pressed_again) pixie_usleep(10000); parms->done_receiving = 1; return; } /* * Receive packets. This is where we catch any responses and print * them to the terminal. */ LOG(1, "begin receive thread\n"); while (!control_c_pressed_again) { int status; unsigned length; unsigned secs; unsigned usecs; const unsigned char *px; int err; unsigned x; struct PreprocessedInfo parsed; unsigned ip_me; unsigned ip_them; unsigned seqno_them; unsigned seqno_me; /* * RECIEVE * * This is the boring part of actually receiving a packet */ err = rawsock_recv_packet( parms->adapter, &length, &secs, &usecs, &px); if (err != 0) continue; /* * Do any TCP event timeouts based on the current timestamp from * the packet. For example, if the connection has been open for * around 10 seconds, we'll close the connection. (--banners) */ if (tcpcon) { tcpcon_timeouts(tcpcon, secs, usecs); } if (length > 1514) continue; /* * "Preprocess" the response packet. This means to go through and * figure out where the TCP/IP headers are and the locations of * some fields, like IP address and port numbers. */ x = preprocess_frame(px, length, 1, &parsed); if (!x) continue; /* corrupt packet */ ip_me = parsed.ip_dst[0]<<24 | parsed.ip_dst[1]<<16 | parsed.ip_dst[2]<< 8 | parsed.ip_dst[3]<<0; ip_them = parsed.ip_src[0]<<24 | parsed.ip_src[1]<<16 | parsed.ip_src[2]<< 8 | parsed.ip_src[3]<<0; seqno_them = TCP_SEQNO(px, parsed.transport_offset); seqno_me = TCP_ACKNO(px, parsed.transport_offset); /* verify: my IP address */ if (parms->adapter_ip != ip_me) continue; /* * Handle non-TCP protocols */ switch (parsed.found) { case FOUND_ARP: /* OOPS: handle arp instead. Since we may completely bypass the TCP/IP * stack, we may have to handle ARPs ourself, or the router will * lose track of us. */ LOGip(2, ip_them, 0, "-> ARP [%u] \n", px[parsed.found_offset]); arp_response( parms->adapter_ip, parms->adapter_mac, px, length, parms->packet_buffers, parms->transmit_queue); continue; case FOUND_UDP: case FOUND_DNS: if (!is_my_port(masscan, parsed.port_dst)) continue; handle_udp(out, px, length, &parsed); continue; case FOUND_ICMP: handle_icmp(out, px, length, &parsed); continue; case FOUND_TCP: /* fall down to below */ break; default: continue; } /* verify: my port number */ if (parms->adapter_port != parsed.port_dst) continue; /* Save raw packet in --pcap file */ if (pcapfile) { pcapfile_writeframe( pcapfile, px, length, length, secs, usecs); } { char buf[64]; LOGip(5, ip_them, parsed.port_src, "-> TCP ackno=0x%08x flags=0x%02x(%s)\n", seqno_me, TCP_FLAGS(px, parsed.transport_offset), reason_string(TCP_FLAGS(px, parsed.transport_offset), buf, sizeof(buf))); } /* If recording --banners, create a new "TCP Control Block (TCB)" */ if (tcpcon) { struct TCP_Control_Block *tcb; /* does a TCB already exist for this connection? */ tcb = tcpcon_lookup_tcb(tcpcon, ip_me, ip_them, parsed.port_dst, parsed.port_src); if (TCP_IS_SYNACK(px, parsed.transport_offset)) { if (syn_hash(ip_them, parsed.port_src) != seqno_me - 1) { LOG(2, "%u.%u.%u.%u - bad cookie: ackno=0x%08x expected=0x%08x\n", (ip_them>>24)&0xff, (ip_them>>16)&0xff, (ip_them>>8)&0xff, (ip_them>>0)&0xff, seqno_me-1, syn_hash(ip_them, parsed.port_src)); continue; } if (tcb == NULL) { tcb = tcpcon_create_tcb(tcpcon, ip_me, ip_them, parsed.port_dst, parsed.port_src, seqno_me, seqno_them+1); } tcpcon_handle(tcpcon, tcb, TCP_WHAT_SYNACK, 0, 0, secs, usecs, seqno_them+1); } else if (tcb) { /* If this is an ACK, then handle that first */ if (TCP_IS_ACK(px, parsed.transport_offset)) { tcpcon_handle(tcpcon, tcb, TCP_WHAT_ACK, 0, seqno_me, secs, usecs, seqno_them); } /* If this contains payload, handle that */ if (parsed.app_length) { tcpcon_handle(tcpcon, tcb, TCP_WHAT_DATA, px + parsed.app_offset, parsed.app_length, secs, usecs, seqno_them); } /* If this is a FIN, handle that. Note that ACK + * payload + FIN can come together */ if (TCP_IS_FIN(px, parsed.transport_offset) && !TCP_IS_RST(px, parsed.transport_offset)) { tcpcon_handle(tcpcon, tcb, TCP_WHAT_FIN, 0, 0, secs, usecs, seqno_them); } /* If this is a RST, then we'll be closing the connection */ if (TCP_IS_RST(px, parsed.transport_offset)) { tcpcon_handle(tcpcon, tcb, TCP_WHAT_RST, 0, 0, secs, usecs, seqno_them); } } else if (TCP_IS_FIN(px, parsed.transport_offset)) { /* * NO TCB! * This happens when we've sent a FIN, deleted our connection, * but the other side didn't get the packet. */ if (!TCP_IS_RST(px, parsed.transport_offset)) tcpcon_send_FIN( tcpcon, ip_me, ip_them, parsed.port_dst, parsed.port_src, seqno_them, seqno_me); } }