internal void copy_from(tcp_seg seg) { this.next = seg.next; this.p = seg.p; this.len = seg.len; #if TCP_OVERSIZE_DBGCHECK this.oversize_left = seg.oversize_left; #endif // TCP_OVERSIZE_DBGCHECK #if TCP_CHECKSUM_ON_COPY this.chksum = seg.chksum; this.chksum_swapped = seg.chksum_swapped; #endif // TCP_CHECKSUM_ON_COPY this.flags = seg.flags; this.tcphdr = seg.tcphdr; }
public static void TCPH_UNSET_FLAG(tcp_hdr phdr, ushort flags) { phdr._hdrlen_rsvd_flags = (ushort)lwip.lwip_htons((ushort)(lwip.lwip_ntohs((phdr)._hdrlen_rsvd_flags) | (tcp_hdr.TCPH_FLAGS(phdr) & ~(flags)))); }
public static void TCPH_SET_FLAG(tcp_hdr phdr, ushort flags) { phdr._hdrlen_rsvd_flags = (ushort)((phdr)._hdrlen_rsvd_flags | lwip.lwip_htons(flags)); }
public static void TCPH_HDRLEN_SET(tcp_hdr phdr, int len) { phdr._hdrlen_rsvd_flags = (ushort)(lwip.lwip_htons((ushort)(((len) << 12) | tcp_hdr.TCPH_FLAGS(phdr)))); }
public static void TCPH_HDRLEN_FLAGS_SET(tcp_hdr phdr, int len, ushort flags) { phdr._hdrlen_rsvd_flags = lwip.lwip_htons((ushort)(((len) << 12) | (flags))); }
public static byte TCPH_FLAGS(tcp_hdr phdr) { return((byte)(lwip.lwip_ntohs((phdr)._hdrlen_rsvd_flags) & tcp.TCP_FLAGS)); }
/** * Send a TCP RESET packet (empty segment with RST flag set) either to * abort a connection or to show that there is no matching local connection * for a received segment. * * Called by tcp.tcp_abort() (to abort a local connection), tcp_input() (if no * matching local pcb was found), tcp_listen_input() (if incoming segment * has ACK flag set) and tcp_process() (received segment in the wrong state) * * Since a RST segment is in most cases not sent for an active connection, * tcp_rst() has a number of arguments that are taken from a tcp_pcb for * most other segment output functions. * * @param seqno the sequence number to use for the outgoing segment * @param ackno the acknowledge number to use for the outgoing segment * @param local_ip the local IP address to send the segment from * @param remote_ip the remote IP address to send the segment to * @param local_port the local TCP port to send the segment from * @param remote_port the remote TCP port to send the segment to */ public void tcp_rst(uint seqno, uint ackno, ip_addr local_ip, ip_addr remote_ip, ushort local_port, ushort remote_port) { pbuf p; tcp_hdr tcphdr; p = lwip.pbuf_alloc(pbuf_layer.PBUF_IP, tcp.TCP_HLEN, pbuf_type.PBUF_RAM); if (p == null) { lwip.LWIP_DEBUGF(opt.TCP_DEBUG, "tcp_rst: could not allocate memory for pbuf\n"); return; } lwip.LWIP_ASSERT("check that first pbuf can hold tcp_hdr", (p.len >= tcp_hdr.length)); tcphdr = new tcp_hdr(p.payload); tcphdr.src = lwip.lwip_htons(local_port); tcphdr.dest = lwip.lwip_htons(remote_port); tcphdr.seqno = lwip.lwip_htonl(seqno); tcphdr.ackno = lwip.lwip_htonl(ackno); tcp_hdr.TCPH_HDRLEN_FLAGS_SET(tcphdr, tcp.TCP_HLEN / 4, tcp.TCP_RST | tcp.TCP_ACK); tcphdr.wnd = lwip.PP_HTONS(opt.TCP_WND); tcphdr.chksum = 0; tcphdr.urgp = 0; #if CHECKSUM_GEN_TCP tcphdr.chksum = lwip.inet_chksum_pseudo(p, local_ip, remote_ip, lwip.IP_PROTO_TCP, p.tot_len); #endif ++lwip.lwip_stats.tcp.xmit; //snmp.snmp_inc_tcpoutrsts(); /* Send output with hardcoded TTL since we have no access to the pcb */ lwip.ip_output(p, local_ip, remote_ip, opt.TCP_TTL, 0, lwip.IP_PROTO_TCP); lwip.pbuf_free(p); lwip.LWIP_DEBUGF(opt.TCP_RST_DEBUG, "tcp_rst: seqno {0} ackno {1}.\n", seqno, ackno); }
/** * Send keepalive packets to keep a connection active although * no data is sent over it. * * Called by tcp_slowtmr() * * @param pcb the tcp_pcb for which to send a keepalive packet */ public void tcp_keepalive(tcp_pcb pcb) { pbuf p; tcp_hdr tcphdr; lwip.LWIP_DEBUGF(opt.TCP_DEBUG, "tcp_keepalive: sending KEEPALIVE probe to {0}.{1}.{2}.{3}\n", ip_addr.ip4_addr1_16(pcb.remote_ip), ip_addr.ip4_addr2_16(pcb.remote_ip), ip_addr.ip4_addr3_16(pcb.remote_ip), ip_addr.ip4_addr4_16(pcb.remote_ip)); lwip.LWIP_DEBUGF(opt.TCP_DEBUG, "tcp_keepalive: tcp_ticks {0} pcb.tmr {1} pcb.keep_cnt_sent {2}\n", tcp_ticks, pcb.tmr, pcb.keep_cnt_sent); p = tcp_output_alloc_header(pcb, 0, 0, lwip.lwip_htonl(pcb.snd_nxt - 1)); if (p == null) { lwip.LWIP_DEBUGF(opt.TCP_DEBUG, ("tcp_keepalive: could not allocate memory for pbuf\n")); return; } tcphdr = new tcp_hdr(p.payload); #if CHECKSUM_GEN_TCP tcphdr.chksum = lwip.inet_chksum_pseudo(p, pcb.local_ip, pcb.remote_ip, lwip.IP_PROTO_TCP, p.tot_len); #endif ++lwip.lwip_stats.tcp.xmit; /* Send output to IP */ #if LWIP_NETIF_HWADDRHINT lwip.ip_output_hinted(p, pcb.local_ip, pcb.remote_ip, pcb.ttl, 0, lwip.IP_PROTO_TCP, pcb.addr_hint); #else // LWIP_NETIF_HWADDRHINT lwip.ip_output(p, pcb.local_ip, pcb.remote_ip, pcb.ttl, 0, lwip.IP_PROTO_TCP); #endif // LWIP_NETIF_HWADDRHINT lwip.pbuf_free(p); lwip.LWIP_DEBUGF(opt.TCP_DEBUG, "tcp_keepalive: seqno {0} ackno {1}.\n", pcb.snd_nxt - 1, pcb.rcv_nxt); }
/** * The initial input processing of TCP. It verifies the TCP header, demultiplexes * the segment between the PCBs and passes it on to tcp_process(), which implements * the TCP finite state machine. This function is called by the IP layer (in * ip_input()). * * @param p received TCP segment to process (p.payload pointing to the IP header) * @param inp network interface on which this segment was received */ public void tcp_input(pbuf p, lwip inp) { tcp_pcb pcb, prev; tcp_pcb_listen lpcb; #if SO_REUSE tcp_pcb_listen lpcb_prev = null; tcp_pcb_listen lpcb_any = null; #endif // SO_REUSE byte hdrlen; err_t err; //PERF_START; ++lwip.lwip_stats.tcp.recv; ////snmp.snmp_inc_tcpinsegs(); tcphdr = new tcp_hdr(p.payload); #if TCP_INPUT_DEBUG tcp_debug_print(tcphdr); #endif /* Don't even process incoming broadcasts/multicasts. */ if (ip_addr.ip_addr_isbroadcast(lwip.current_iphdr_dest, inp) || ip_addr.ip_addr_ismulticast(lwip.current_iphdr_dest)) { ++lwip.lwip_stats.tcp.proterr; goto dropped; } #if CHECKSUM_CHECK_TCP /* Verify TCP checksum. */ if (lwip.inet_chksum_pseudo(p, lwip.ip_current_src_addr(), lwip.ip_current_dest_addr(), lwip.IP_PROTO_TCP, p.tot_len) != 0) { lwip.LWIP_DEBUGF(opt.TCP_INPUT_DEBUG, "tcp_input: packet discarded due to failing checksum 0x{0:X4}\n", lwip.inet_chksum_pseudo(p, lwip.ip_current_src_addr(), lwip.ip_current_dest_addr(), lwip.IP_PROTO_TCP, p.tot_len)); #if TCP_DEBUG tcp_debug_print(tcphdr); #endif // TCP_DEBUG ++lwip.lwip_stats.tcp.chkerr; goto dropped; } #endif /* Move the payload pointer in the pbuf so that it points to the TCP data instead of the TCP header. */ hdrlen = (byte)tcp_hdr.TCPH_HDRLEN(tcphdr); if (lwip.pbuf_header(p, (short)-(hdrlen * 4)) != 0) { /* drop short packets */ lwip.LWIP_DEBUGF(opt.TCP_INPUT_DEBUG, "tcp_input: short packet\n"); ++lwip.lwip_stats.tcp.lenerr; goto dropped; } /* Convert fields in TCP header to host byte order. */ tcphdr.src = lwip.lwip_ntohs(tcphdr.src); tcphdr.dest = lwip.lwip_ntohs(tcphdr.dest); seqno = tcphdr.seqno = lwip.lwip_ntohl(tcphdr.seqno); ackno = tcphdr.ackno = lwip.lwip_ntohl(tcphdr.ackno); tcphdr.wnd = lwip.lwip_ntohs(tcphdr.wnd); flags = tcp_hdr.TCPH_FLAGS(tcphdr); tcplen = (ushort)(p.tot_len + (((flags & (tcp.TCP_FIN | tcp.TCP_SYN)) != 0) ? 1 : 0)); /* Demultiplex an incoming segment. First, we check if it is destined for an active connection. */ prev = null; for (pcb = tcp_active_pcbs; pcb != null; pcb = (tcp_pcb)pcb.next) { lwip.LWIP_ASSERT("tcp_input: active pcb.state != tcp_state.CLOSED", pcb.state != tcp_state.CLOSED); lwip.LWIP_ASSERT("tcp_input: active pcb.state != TIME-WAIT", pcb.state != tcp_state.TIME_WAIT); lwip.LWIP_ASSERT("tcp_input: active pcb.state != tcp_state.LISTEN", pcb.state != tcp_state.LISTEN); if (pcb.remote_port == tcphdr.src && pcb.local_port == tcphdr.dest && ip_addr.ip_addr_cmp(pcb.remote_ip, lwip.current_iphdr_src) && ip_addr.ip_addr_cmp(pcb.local_ip, lwip.current_iphdr_dest)) { /* Move this PCB to the front of the list so that subsequent lookups will be faster (we exploit locality in TCP segment arrivals). */ lwip.LWIP_ASSERT("tcp_input: pcb.next != pcb (before cache)", pcb.next != pcb); if (prev != null) { prev.next = pcb.next; pcb.next = tcp_active_pcbs; tcp_active_pcbs = pcb; } lwip.LWIP_ASSERT("tcp_input: pcb.next != pcb (after cache)", pcb.next != pcb); break; } prev = pcb; } if (pcb == null) { /* If it did not go to an active connection, we check the connections in the TIME-WAIT state. */ for (pcb = tcp_tw_pcbs; pcb != null; pcb = (tcp_pcb)pcb.next) { lwip.LWIP_ASSERT("tcp_input: TIME-WAIT pcb.state == TIME-WAIT", pcb.state == tcp_state.TIME_WAIT); if (pcb.remote_port == tcphdr.src && pcb.local_port == tcphdr.dest && ip_addr.ip_addr_cmp(pcb.remote_ip, lwip.current_iphdr_src) && ip_addr.ip_addr_cmp(pcb.local_ip, lwip.current_iphdr_dest)) { /* We don't really care enough to move this PCB to the front of the list since we are not very likely to receive that many segments for connections in TIME-WAIT. */ lwip.LWIP_DEBUGF(opt.TCP_INPUT_DEBUG, "tcp_input: packed for tcp_state.TIME_WAITing connection.\n"); tcp_timewait_input(pcb); lwip.pbuf_free(p); return; } } /* Finally, if we still did not get a match, we check all PCBs that are tcp_state.LISTENing for incoming connections. */ tcp_pcb_listen lprev = null; for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != null; lpcb = (tcp_pcb_listen)lpcb.next) { if (lpcb.local_port == tcphdr.dest) { #if SO_REUSE if (ip_addr.ip_addr_cmp(lpcb.local_ip, lwip.current_iphdr_dest)) { /* found an exact match */ break; } else if (ip_addr.ip_addr_isany(lpcb.local_ip)) { /* found an ANY-match */ lpcb_any = lpcb; lpcb_prev = lprev; } #else // SO_REUSE if (ip_addr.ip_addr_cmp(lpcb.local_ip, lwip.current_iphdr_dest) || ip_addr.ip_addr_isany(lpcb.local_ip)) { /* found a match */ break; } #endif // SO_REUSE } lprev = lpcb; } #if SO_REUSE /* first try specific local IP */ if (lpcb == null) { /* only pass to ANY if no specific local IP has been found */ lpcb = lpcb_any; lprev = lpcb_prev; } #endif // SO_REUSE if (lpcb != null) { /* Move this PCB to the front of the list so that subsequent lookups will be faster (we exploit locality in TCP segment arrivals). */ if (lprev != null) { ((tcp_pcb_listen)lprev).next = lpcb.next; /* our successor is the remainder of the listening list */ lpcb.next = tcp_listen_pcbs.listen_pcbs; /* put this listening pcb at the head of the listening list */ tcp_listen_pcbs.listen_pcbs = lpcb; } lwip.LWIP_DEBUGF(opt.TCP_INPUT_DEBUG, "tcp_input: packed for tcp_state.LISTENing connection.\n"); tcp_listen_input(lpcb); lwip.pbuf_free(p); return; } } #if TCP_INPUT_DEBUG lwip.LWIP_DEBUGF(opt.TCP_INPUT_DEBUG, "+-+-+-+-+-+-+-+-+-+-+-+-+-+- tcp_input: flags "); tcp_debug_print_flags(tcp_hdr.TCPH_FLAGS(tcphdr)); lwip.LWIP_DEBUGF(opt.TCP_INPUT_DEBUG, "-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n"); #endif // TCP_INPUT_DEBUG if (pcb != null) { /* The incoming segment belongs to a connection. */ #if TCP_INPUT_DEBUG #if TCP_DEBUG tcp_debug_print_state(pcb.state); #endif // TCP_DEBUG #endif // TCP_INPUT_DEBUG /* Set up a tcp_seg structure. */ inseg.next = null; inseg.len = p.tot_len; inseg.p = p; inseg.tcphdr = tcphdr; recv_data = null; recv_flags = 0; if ((flags & tcp.TCP_PSH) != 0) { p.flags |= pbuf.PBUF_FLAG_PUSH; } /* If there is data which was previously "refused" by upper layer */ if (pcb.refused_data != null) { if ((tcp_process_refused_data(pcb) == err_t.ERR_ABRT) || ((pcb.refused_data != null) && (tcplen > 0))) { /* pcb has been aborted or refused data is still refused and the new segment contains data */ ++lwip.lwip_stats.tcp.drop; //snmp.snmp_inc_tcpinerrs(); goto aborted; } } tcp_input_pcb = pcb; err = tcp_process(pcb); /* A return value of err_t.ERR_ABRT means that tcp.tcp_abort() was called and that the pcb has been freed. If so, we don't do anything. */ if (err != err_t.ERR_ABRT) { if ((recv_flags & tcp.TF_RESET) != 0) { /* TF_RESET means that the connection was reset by the other end. We then call the error callback to inform the application that the connection is dead before we deallocate the PCB. */ TCP_EVENT_ERR(pcb.errf, pcb.callback_arg, err_t.ERR_RST); tcp_pcb_remove(tcp_active_pcbs, pcb); lwip.memp_free(memp_t.MEMP_TCP_PCB, pcb); } else if ((recv_flags & tcp.TF_CLOSED) != 0) { /* The connection has been closed and we will deallocate the PCB. */ if ((pcb.flags & tcp_pcb.TF_RXCLOSED) == 0) { /* Connection closed although the application has only shut down the tx side: call the PCB's err callback and indicate the closure to ensure the application doesn't continue using the PCB. */ TCP_EVENT_ERR(pcb.errf, pcb.callback_arg, err_t.ERR_CLSD); } tcp_pcb_remove(tcp_active_pcbs, pcb); lwip.memp_free(memp_t.MEMP_TCP_PCB, pcb); } else { err = err_t.ERR_OK; /* If the application has registered a "sent" function to be called when new send buffer space is available, we call it now. */ if (pcb.acked > 0) { TCP_EVENT_SENT(pcb, pcb.acked, out err); if (err == err_t.ERR_ABRT) { goto aborted; } } if (recv_data != null) { lwip.LWIP_ASSERT("pcb.refused_data == null", pcb.refused_data == null); if ((pcb.flags & tcp_pcb.TF_RXCLOSED) != 0) { /* received data although already closed . abort (send RST) to notify the remote host that not all data has been processed */ lwip.pbuf_free(recv_data); tcp_abort(pcb); goto aborted; } /* Notify application that data has been received. */ TCP_EVENT_RECV(pcb, recv_data, err_t.ERR_OK, out err); if (err == err_t.ERR_ABRT) { goto aborted; } /* If the upper layer can't receive this data, store it */ if (err != err_t.ERR_OK) { pcb.refused_data = recv_data; lwip.LWIP_DEBUGF(opt.TCP_INPUT_DEBUG, "tcp_input: keep incoming packet, because pcb is \"full\"\n"); } } /* If a FIN segment was received, we call the callback function with a null buffer to indicate EOF. */ if ((recv_flags & TF_GOT_FIN) != 0) { if (pcb.refused_data != null) { /* Delay this if we have refused data. */ pcb.refused_data.flags |= pbuf.PBUF_FLAG_TCP_FIN; } else { /* correct rcv_wnd as the application won't call tcp_recved() for the FIN's seqno */ if (pcb.rcv_wnd != opt.TCP_WND) { pcb.rcv_wnd++; } TCP_EVENT_CLOSED(pcb, out err); if (err == err_t.ERR_ABRT) { goto aborted; } } } tcp_input_pcb = null; /* Try to send something out. */ tcp_output(pcb); #if TCP_INPUT_DEBUG #if TCP_DEBUG tcp_debug_print_state(pcb.state); #endif // TCP_DEBUG #endif // TCP_INPUT_DEBUG } } /* Jump target if pcb has been aborted in a callback (by calling tcp.tcp_abort()). Below this line, 'pcb' may not be dereferenced! */ aborted: tcp_input_pcb = null; recv_data = null; /* give up our reference to inseg.p */ if (inseg.p != null) { lwip.pbuf_free(inseg.p); inseg.p = null; } } else { /* If no matching PCB was found, send a TCP RST (reset) to the sender. */ lwip.LWIP_DEBUGF(opt.TCP_RST_DEBUG, "tcp_input: no PCB match found, resetting.\n"); if ((tcp_hdr.TCPH_FLAGS(tcphdr) & tcp.TCP_RST) == 0) { ++lwip.lwip_stats.tcp.proterr; ++lwip.lwip_stats.tcp.drop; tcp_rst(ackno, seqno + tcplen, lwip.ip_current_dest_addr(), lwip.ip_current_src_addr(), tcphdr.dest, tcphdr.src); } lwip.pbuf_free(p); } lwip.LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane() != 0); //PERF_STOP("tcp_input"); return; dropped: ++lwip.lwip_stats.tcp.drop; //snmp.snmp_inc_tcpinerrs(); lwip.pbuf_free(p); }
public static void TCPH_FLAGS_SET(tcp_hdr phdr, ushort flags) { phdr._hdrlen_rsvd_flags = (ushort)(((phdr)._hdrlen_rsvd_flags & lwip.PP_HTONS(unchecked ((ushort)((~(ushort)(tcp.TCP_FLAGS))))) | lwip.lwip_htons(flags))); }
public static byte TCPH_FLAGS(tcp_hdr phdr) { return (byte)(lwip.lwip_ntohs((phdr)._hdrlen_rsvd_flags) & tcp.TCP_FLAGS); }
/** * Send persist timer zero-window probes to keep a connection active * when a window update is lost. * * Called by tcp_slowtmr() * * @param pcb the tcp_pcb for which to send a zero-window probe packet */ public void tcp_zero_window_probe(tcp_pcb pcb) { pbuf p; tcp_hdr tcphdr; tcp_seg seg; ushort len; byte is_fin; lwip.LWIP_DEBUGF(opt.TCP_DEBUG, "tcp_zero_window_probe: sending ZERO WINDOW probe to " + "{0}.{1}.{2}.{3}\n", ip_addr.ip4_addr1_16(pcb.remote_ip), ip_addr.ip4_addr2_16(pcb.remote_ip), ip_addr.ip4_addr3_16(pcb.remote_ip), ip_addr.ip4_addr4_16(pcb.remote_ip)); lwip.LWIP_DEBUGF(opt.TCP_DEBUG, "tcp_zero_window_probe: tcp_ticks " + "{0} pcb.tmr {1} pcb.keep_cnt_sent {2}\n", tcp_ticks, pcb.tmr, pcb.keep_cnt_sent); seg = pcb.unacked; if (seg == null) { seg = pcb.unsent; } if (seg == null) { return; } is_fin = (((tcp_hdr.TCPH_FLAGS(seg.tcphdr) & tcp.TCP_FIN) != 0) && (seg.len == 0)) ? (byte)1 : (byte)0; /* we want to send one seqno: either FIN or data (no options) */ len = is_fin != 0 ? (ushort)0 : (ushort)1; p = tcp_output_alloc_header(pcb, 0, len, seg.tcphdr.seqno); if (p == null) { lwip.LWIP_DEBUGF(opt.TCP_DEBUG, "tcp_zero_window_probe: no memory for pbuf\n"); return; } tcphdr = new tcp_hdr(p.payload); if (is_fin != 0) { /* FIN segment, no data */ tcp_hdr.TCPH_FLAGS_SET(tcphdr, tcp.TCP_ACK | tcp.TCP_FIN); } else { /* Data segment, copy in one byte from the head of the unacked queue */ pointer d = p.payload + tcp.TCP_HLEN; /* Depending on whether the segment has already been sent (unacked) or not (unsent), seg.p.payload points to the IP header or TCP header. Ensure we copy the first TCP data byte: */ lwip.pbuf_copy_partial(seg.p, d, 1, (ushort)(seg.p.tot_len - seg.len)); } #if CHECKSUM_GEN_TCP tcphdr.chksum = lwip.inet_chksum_pseudo(p, pcb.local_ip, pcb.remote_ip, lwip.IP_PROTO_TCP, p.tot_len); #endif ++lwip.lwip_stats.tcp.xmit; /* Send output to IP */ #if LWIP_NETIF_HWADDRHINT lwip.ip_output_hinted(p, pcb.local_ip, pcb.remote_ip, pcb.ttl, 0, lwip.IP_PROTO_TCP, pcb.addr_hint); #else // LWIP_NETIF_HWADDRHINT lwip.ip_output(p, pcb.local_ip, pcb.remote_ip, pcb.ttl, 0, lwip.IP_PROTO_TCP); #endif // LWIP_NETIF_HWADDRHINT lwip.pbuf_free(p); lwip.LWIP_DEBUGF(opt.TCP_DEBUG, "tcp_zero_window_probe: seqno {0}" + " ackno {1}.\n", pcb.snd_nxt - 1, pcb.rcv_nxt); }
public static void TCPH_FLAGS_SET(tcp_hdr phdr, ushort flags) { phdr._hdrlen_rsvd_flags = (ushort)(((phdr)._hdrlen_rsvd_flags & lwip.PP_HTONS(unchecked((ushort)((~(ushort)(tcp.TCP_FLAGS))))) | lwip.lwip_htons(flags))); }
/** Allocate a pbuf and create a tcphdr at p.payload, used for output * functions other than the default tcp.tcp_output . tcp_output_segment * (e.g. tcp_send_empty_ack, etc.) * * @param pcb tcp pcb for which to send a packet (used to initialize tcp_hdr) * @param optlen length of header-options * @param datalen length of tcp data to reserve in pbuf * @param seqno_be seqno in network byte order (big-endian) * @return pbuf with p.payload being the tcp_hdr */ private pbuf tcp_output_alloc_header(tcp_pcb pcb, ushort optlen, ushort datalen, uint seqno_be /* already in network byte order */) { tcp_hdr tcphdr; pbuf p = lwip.pbuf_alloc(pbuf_layer.PBUF_IP, (ushort)(tcp.TCP_HLEN + optlen + datalen), pbuf_type.PBUF_RAM); if (p != null) { lwip.LWIP_ASSERT("check that first pbuf can hold tcp_hdr", (p.len >= tcp.TCP_HLEN + optlen)); tcphdr = new tcp_hdr(p.payload); tcphdr.src = lwip.lwip_htons(pcb.local_port); tcphdr.dest = lwip.lwip_htons(pcb.remote_port); tcphdr.seqno = seqno_be; tcphdr.ackno = lwip.lwip_htonl(pcb.rcv_nxt); tcp_hdr.TCPH_HDRLEN_FLAGS_SET(tcphdr, (5 + optlen / 4), tcp.TCP_ACK); tcphdr.wnd = lwip.lwip_htons(pcb.rcv_ann_wnd); tcphdr.chksum = 0; tcphdr.urgp = 0; /* If we're sending a packet, update the announced right window edge */ pcb.rcv_ann_right_edge = pcb.rcv_nxt + pcb.rcv_ann_wnd; } return p; }
public static byte TCPH_HDRLEN(tcp_hdr phdr) { return (byte)(lwip.lwip_ntohs(phdr._hdrlen_rsvd_flags) >> 12); }
/** Send an ACK without data. * * @param pcb Protocol control block for the TCP connection to send the ACK */ public err_t tcp_send_empty_ack(tcp_pcb pcb) { pbuf p; tcp_hdr tcphdr; byte optlen = 0; #if LWIP_TCP_TIMESTAMPS if ((pcb.flags & tcp_pcb.TF_TIMESTAMP) != 0) { optlen = (byte)tcp_seg.LWIP_TCP_OPT_LENGTH(tcp_seg.TF_SEG_OPTS_TS); } #endif p = tcp_output_alloc_header(pcb, optlen, 0, lwip.lwip_htonl(pcb.snd_nxt)); if (p == null) { lwip.LWIP_DEBUGF(opt.TCP_OUTPUT_DEBUG, "tcp_output: (ACK) could not allocate pbuf\n"); return err_t.ERR_BUF; } tcphdr = new tcp_hdr(p.payload); lwip.LWIP_DEBUGF(opt.TCP_OUTPUT_DEBUG, "tcp_output: sending ACK for {0}\n", pcb.rcv_nxt); /* remove ACK flags from the PCB, as we send an empty ACK now */ pcb.flags &= unchecked((byte)~(tcp_pcb.TF_ACK_DELAY | tcp_pcb.TF_ACK_NOW)); /* NB. MSS option is only sent on SYNs, so ignore it here */ #if LWIP_TCP_TIMESTAMPS pcb.ts_lastacksent = pcb.rcv_nxt; if ((pcb.flags & tcp_pcb.TF_TIMESTAMP) != 0) { tcp_build_timestamp_option(pcb, new pointer(tcphdr.data, tcphdr.offset + tcp_hdr.length)); } #endif #if CHECKSUM_GEN_TCP tcphdr.chksum = lwip.inet_chksum_pseudo(p, pcb.local_ip, pcb.remote_ip, lwip.IP_PROTO_TCP, p.tot_len); #endif #if LWIP_NETIF_HWADDRHINT lwip.ip_output_hinted(p, pcb.local_ip, pcb.remote_ip, pcb.ttl, pcb.tos, lwip.IP_PROTO_TCP, pcb.addr_hint); #else // LWIP_NETIF_HWADDRHINT lwip.ip_output(p, pcb.local_ip, pcb.remote_ip, pcb.ttl, pcb.tos, lwip.IP_PROTO_TCP); #endif // LWIP_NETIF_HWADDRHINT lwip.pbuf_free(p); return err_t.ERR_OK; }
public static byte TCPH_HDRLEN(tcp_hdr phdr) { return((byte)(lwip.lwip_ntohs(phdr._hdrlen_rsvd_flags) >> 12)); }