#include <slirp.h>
#include "ip_icmp.h"
-struct socket tcb;
-
#define TCPREXMTTHRESH 3
-struct socket *tcp_last_so = &tcb;
-
-tcp_seq tcp_iss; /* tcp initial send seq # */
#define TCP_PAWS_IDLE (24 * 24 * 60 * 60 * PR_SLOWHZ)
tp->t_flags |= TF_DELACK; \
(tp)->rcv_nxt += (ti)->ti_len; \
flags = (ti)->ti_flags & TH_FIN; \
- STAT(tcpstat.tcps_rcvpack++); \
- STAT(tcpstat.tcps_rcvbyte += (ti)->ti_len); \
if (so->so_emu) { \
if (tcp_emu((so),(m))) sbappend((so), (m)); \
} else \
tp->t_flags |= TF_DELACK; \
(tp)->rcv_nxt += (ti)->ti_len; \
flags = (ti)->ti_flags & TH_FIN; \
- STAT(tcpstat.tcps_rcvpack++); \
- STAT(tcpstat.tcps_rcvbyte += (ti)->ti_len); \
if (so->so_emu) { \
if (tcp_emu((so),(m))) sbappend(so, (m)); \
} else \
i = q->ti_seq + q->ti_len - ti->ti_seq;
if (i > 0) {
if (i >= ti->ti_len) {
- STAT(tcpstat.tcps_rcvduppack++);
- STAT(tcpstat.tcps_rcvdupbyte += ti->ti_len);
- m_freem(m);
+ m_free(m);
/*
* Try to present any queued data
* at the left window edge to the user.
}
q = tcpiphdr_next(q);
}
- STAT(tcpstat.tcps_rcvoopack++);
- STAT(tcpstat.tcps_rcvoobyte += ti->ti_len);
ti->ti_mbuf = m;
/*
q = tcpiphdr_next(q);
m = tcpiphdr_prev(q)->ti_mbuf;
remque(tcpiphdr2qlink(tcpiphdr_prev(q)));
- m_freem(m);
+ m_free(m);
}
/*
m = ti->ti_mbuf;
ti = tcpiphdr_next(ti);
if (so->so_state & SS_FCANTSENDMORE)
- m_freem(m);
+ m_free(m);
else {
if (so->so_emu) {
if (tcp_emu(so,m)) sbappend(so, m);
u_long tiwin;
int ret;
struct ex_list *ex_ptr;
+ Slirp *slirp;
DEBUG_CALL("tcp_input");
- DEBUG_ARGS((dfd," m = %8lx iphlen = %2d inso = %lx\n",
+ DEBUG_ARGS((dfd, " m = %8lx iphlen = %2d inso = %lx\n",
(long )m, iphlen, (long )inso ));
/*
*/
if (m == NULL) {
so = inso;
+ slirp = so->slirp;
/* Re-set a few variables */
tp = sototcpcb(so);
goto cont_conn;
}
+ slirp = m->slirp;
-
- STAT(tcpstat.tcps_rcvtotal++);
/*
* Get IP and TCP header together in first mbuf.
* Note: IP leaves IP header in first mbuf.
tcpiphdr2qlink(ti)->next = tcpiphdr2qlink(ti)->prev = NULL;
memset(&ti->ti_i.ih_mbuf, 0 , sizeof(struct mbuf_ptr));
ti->ti_x1 = 0;
- ti->ti_len = htons((u_int16_t)tlen);
+ ti->ti_len = htons((uint16_t)tlen);
len = sizeof(struct ip ) + tlen;
if(cksum(m, len)) {
- STAT(tcpstat.tcps_rcvbadsum++);
goto drop;
}
*/
off = ti->ti_off << 2;
if (off < sizeof (struct tcphdr) || off > tlen) {
- STAT(tcpstat.tcps_rcvbadoff++);
goto drop;
}
tlen -= off;
m->m_data += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
m->m_len -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
- if (slirp_restrict) {
- for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
- if (ex_ptr->ex_fport == ti->ti_dport &&
- ti->ti_dst.s_addr == ex_ptr->ex_addr.s_addr) {
- break;
- }
- }
- if (!ex_ptr)
- goto drop;
- }
/*
* Locate pcb for segment.
*/
findso:
- so = tcp_last_so;
+ so = slirp->tcp_last_so;
if (so->so_fport != ti->ti_dport ||
so->so_lport != ti->ti_sport ||
so->so_laddr.s_addr != ti->ti_src.s_addr ||
so->so_faddr.s_addr != ti->ti_dst.s_addr) {
- so = solookup(&tcb, ti->ti_src, ti->ti_sport,
+ so = solookup(&slirp->tcb, ti->ti_src, ti->ti_sport,
ti->ti_dst, ti->ti_dport);
if (so)
- tcp_last_so = so;
- STAT(tcpstat.tcps_socachemiss++);
+ slirp->tcp_last_so = so;
}
/*
* as if it was LISTENING, and continue...
*/
if (so == NULL) {
+ if (slirp->restricted) {
+ /* Any hostfwds will have an existing socket, so we only get here
+ * for non-hostfwd connections. These should be dropped, unless it
+ * happens to be a guestfwd.
+ */
+ for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
+ if (ex_ptr->ex_fport == ti->ti_dport &&
+ ti->ti_dst.s_addr == ex_ptr->ex_addr.s_addr) {
+ break;
+ }
+ }
+ if (!ex_ptr) {
+ goto dropwithreset;
+ }
+ }
+
if ((tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) != TH_SYN)
goto dropwithreset;
- if ((so = socreate()) == NULL)
+ if ((so = socreate(slirp)) == NULL)
goto dropwithreset;
if (tcp_attach(so) < 0) {
free(so); /* Not sofree (if it failed, it's not insqued) */
/*
* this is a pure ack for outstanding data.
*/
- STAT(tcpstat.tcps_predack++);
if (tp->t_rtt &&
SEQ_GT(ti->ti_ack, tp->t_rtseq))
tcp_xmit_timer(tp, tp->t_rtt);
acked = ti->ti_ack - tp->snd_una;
- STAT(tcpstat.tcps_rcvackpack++);
- STAT(tcpstat.tcps_rcvackbyte += acked);
sbdrop(&so->so_snd, acked);
tp->snd_una = ti->ti_ack;
- m_freem(m);
+ m_free(m);
/*
* If all outstanding data are acked, stop
* with nothing on the reassembly queue and
* we have enough buffer space to take it.
*/
- STAT(tcpstat.tcps_preddat++);
tp->rcv_nxt += ti->ti_len;
- STAT(tcpstat.tcps_rcvpack++);
- STAT(tcpstat.tcps_rcvbyte += ti->ti_len);
/*
* Add data to socket buffer.
*/
* If this is destined for the control address, then flag to
* tcp_ctl once connected, otherwise connect
*/
- if ((so->so_faddr.s_addr & vnetwork_mask.s_addr) ==
- vnetwork_addr.s_addr) {
- if (so->so_faddr.s_addr != vhost_addr.s_addr &&
- so->so_faddr.s_addr != vnameserver_addr.s_addr) {
+ if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
+ slirp->vnetwork_addr.s_addr) {
+ if (so->so_faddr.s_addr != slirp->vhost_addr.s_addr &&
+ so->so_faddr.s_addr != slirp->vnameserver_addr.s_addr) {
/* May be an add exec */
- for(ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
+ for (ex_ptr = slirp->exec_list; ex_ptr;
+ ex_ptr = ex_ptr->ex_next) {
if(ex_ptr->ex_fport == so->so_fport &&
so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr) {
so->so_state |= SS_CTL;
if((tcp_fconnect(so) == -1) && (errno != EINPROGRESS) && (errno != EWOULDBLOCK)) {
u_char code=ICMP_UNREACH_NET;
- DEBUG_MISC((dfd," tcp fconnect errno = %d-%s\n",
+ DEBUG_MISC((dfd, " tcp fconnect errno = %d-%s\n",
errno,strerror(errno)));
if(errno == ECONNREFUSED) {
/* ACK the SYN, send RST to refuse the connection */
*ip=save_ip;
icmp_error(m, ICMP_UNREACH,code, 0,strerror(errno));
}
- tp = tcp_close(tp);
+ tcp_close(tp);
m_free(m);
} else {
/*
so->so_ti = ti;
tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
tp->t_state = TCPS_SYN_RECEIVED;
+ tcp_template(tp);
}
return;
if (iss)
tp->iss = iss;
else
- tp->iss = tcp_iss;
- tcp_iss += TCP_ISSINCR/2;
+ tp->iss = slirp->tcp_iss;
+ slirp->tcp_iss += TCP_ISSINCR/2;
tp->irs = ti->ti_seq;
tcp_sendseqinit(tp);
tcp_rcvseqinit(tp);
tp->t_flags |= TF_ACKNOW;
tp->t_state = TCPS_SYN_RECEIVED;
tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
- STAT(tcpstat.tcps_accepts++);
goto trimthenstep6;
} /* case TCPS_LISTEN */
goto dropwithreset;
if (tiflags & TH_RST) {
- if (tiflags & TH_ACK)
- tp = tcp_drop(tp,0); /* XXX Check t_softerror! */
+ if (tiflags & TH_ACK) {
+ tcp_drop(tp, 0); /* XXX Check t_softerror! */
+ }
goto drop;
}
tcp_rcvseqinit(tp);
tp->t_flags |= TF_ACKNOW;
if (tiflags & TH_ACK && SEQ_GT(tp->snd_una, tp->iss)) {
- STAT(tcpstat.tcps_connects++);
soisfconnected(so);
tp->t_state = TCPS_ESTABLISHED;
m_adj(m, -todrop);
ti->ti_len = tp->rcv_wnd;
tiflags &= ~TH_FIN;
- STAT(tcpstat.tcps_rcvpackafterwin++);
- STAT(tcpstat.tcps_rcvbyteafterwin += todrop);
}
tp->snd_wl1 = ti->ti_seq - 1;
tp->rcv_up = ti->ti_seq;
*/
tp->t_flags |= TF_ACKNOW;
todrop = ti->ti_len;
- STAT(tcpstat.tcps_rcvduppack++);
- STAT(tcpstat.tcps_rcvdupbyte += todrop);
- } else {
- STAT(tcpstat.tcps_rcvpartduppack++);
- STAT(tcpstat.tcps_rcvpartdupbyte += todrop);
}
m_adj(m, todrop);
ti->ti_seq += todrop;
if ((so->so_state & SS_NOFDREF) &&
tp->t_state > TCPS_CLOSE_WAIT && ti->ti_len) {
tp = tcp_close(tp);
- STAT(tcpstat.tcps_rcvafterclose++);
goto dropwithreset;
}
*/
todrop = (ti->ti_seq+ti->ti_len) - (tp->rcv_nxt+tp->rcv_wnd);
if (todrop > 0) {
- STAT(tcpstat.tcps_rcvpackafterwin++);
if (todrop >= ti->ti_len) {
- STAT(tcpstat.tcps_rcvbyteafterwin += ti->ti_len);
/*
* If a new connection request is received
* while in TIME_WAIT, drop the old connection
*/
if (tp->rcv_wnd == 0 && ti->ti_seq == tp->rcv_nxt) {
tp->t_flags |= TF_ACKNOW;
- STAT(tcpstat.tcps_rcvwinprobe++);
- } else
+ } else {
goto dropafterack;
- } else
- STAT(tcpstat.tcps_rcvbyteafterwin += todrop);
+ }
+ }
m_adj(m, -todrop);
ti->ti_len -= todrop;
tiflags &= ~(TH_PUSH|TH_FIN);
case TCPS_FIN_WAIT_2:
case TCPS_CLOSE_WAIT:
tp->t_state = TCPS_CLOSED;
- STAT(tcpstat.tcps_drops++);
- tp = tcp_close(tp);
+ tcp_close(tp);
goto drop;
case TCPS_CLOSING:
case TCPS_LAST_ACK:
case TCPS_TIME_WAIT:
- tp = tcp_close(tp);
+ tcp_close(tp);
goto drop;
}
if (SEQ_GT(tp->snd_una, ti->ti_ack) ||
SEQ_GT(ti->ti_ack, tp->snd_max))
goto dropwithreset;
- STAT(tcpstat.tcps_connects++);
tp->t_state = TCPS_ESTABLISHED;
/*
* The sent SYN is ack'ed with our sequence number +1
if (SEQ_LEQ(ti->ti_ack, tp->snd_una)) {
if (ti->ti_len == 0 && tiwin == tp->snd_wnd) {
- STAT(tcpstat.tcps_rcvdupack++);
- DEBUG_MISC((dfd," dup ack m = %lx so = %lx \n",
+ DEBUG_MISC((dfd, " dup ack m = %lx so = %lx\n",
(long )m, (long )so));
/*
* If we have outstanding data (other than
tp->snd_cwnd = tp->snd_ssthresh;
tp->t_dupacks = 0;
if (SEQ_GT(ti->ti_ack, tp->snd_max)) {
- STAT(tcpstat.tcps_rcvacktoomuch++);
goto dropafterack;
}
acked = ti->ti_ack - tp->snd_una;
- STAT(tcpstat.tcps_rcvackpack++);
- STAT(tcpstat.tcps_rcvackbyte += acked);
/*
* If transmit timer is running and timed sequence
*/
case TCPS_LAST_ACK:
if (ourfinisacked) {
- tp = tcp_close(tp);
+ tcp_close(tp);
goto drop;
}
break;
(SEQ_LT(tp->snd_wl1, ti->ti_seq) ||
(tp->snd_wl1 == ti->ti_seq && (SEQ_LT(tp->snd_wl2, ti->ti_ack) ||
(tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd))))) {
- /* keep track of pure window updates */
- if (ti->ti_len == 0 &&
- tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd)
- STAT(tcpstat.tcps_rcvwinupd++);
tp->snd_wnd = tiwin;
tp->snd_wl1 = ti->ti_seq;
tp->snd_wl2 = ti->ti_ack;
tp->rcv_up = tp->rcv_nxt;
dodata:
+ /*
+ * If this is a small packet, then ACK now - with Nagel
+ * congestion avoidance sender won't send more until
+ * he gets an ACK.
+ */
+ if (ti->ti_len && (unsigned)ti->ti_len <= 5 &&
+ ((struct tcpiphdr_2 *)ti)->first_char == (char)27) {
+ tp->t_flags |= TF_ACKNOW;
+ }
+
/*
* Process the segment text, merging it into the TCP sequencing queue,
* and arranging for acknowledgment of receipt if necessary.
if ((ti->ti_len || (tiflags&TH_FIN)) &&
TCPS_HAVERCVDFIN(tp->t_state) == 0) {
TCP_REASS(tp, ti, m, so, tiflags);
- /*
- * Note the amount of data that peer has sent into
- * our window, in order to estimate the sender's
- * buffer size.
- */
- len = so->so_rcv.sb_datalen - (tp->rcv_adv - tp->rcv_nxt);
} else {
m_free(m);
tiflags &= ~TH_FIN;
}
}
- /*
- * If this is a small packet, then ACK now - with Nagel
- * congestion avoidance sender won't send more until
- * he gets an ACK.
- *
- * See above.
- */
- if (ti->ti_len && (unsigned)ti->ti_len <= 5 &&
- ((struct tcpiphdr_2 *)ti)->first_char == (char)27) {
- tp->t_flags |= TF_ACKNOW;
- }
-
/*
* Return any desired output.
*/
*/
if (tiflags & TH_RST)
goto drop;
- m_freem(m);
+ m_free(m);
tp->t_flags |= TF_ACKNOW;
(void) tcp_output(tp);
return;
* Drop space held by incoming segment and return.
*/
m_free(m);
-
- return;
}
static void
tcp_dooptions(struct tcpcb *tp, u_char *cp, int cnt, struct tcpiphdr *ti)
{
- u_int16_t mss;
+ uint16_t mss;
int opt, optlen;
DEBUG_CALL("tcp_dooptions");
- DEBUG_ARGS((dfd," tp = %lx cnt=%i \n", (long )tp, cnt));
+ DEBUG_ARGS((dfd, " tp = %lx cnt=%i\n", (long)tp, cnt));
for (; cnt > 0; cnt -= optlen, cp += optlen) {
opt = cp[0];
DEBUG_ARG("tp = %lx", (long)tp);
DEBUG_ARG("rtt = %d", rtt);
- STAT(tcpstat.tcps_rttupdated++);
if (tp->t_srtt != 0) {
/*
* srtt is stored as fixed point with 3 bits after the