summaryrefslogtreecommitdiffstats
path: root/sys/netinet/tcp_reass.c
diff options
context:
space:
mode:
authorandre <andre@FreeBSD.org>2007-03-23 20:16:50 +0000
committerandre <andre@FreeBSD.org>2007-03-23 20:16:50 +0000
commitacede79cbae3ad5ac9c813b98547f46f97d26877 (patch)
treea022c1c16b7dea8ff848da8084545ea9c6203fe4 /sys/netinet/tcp_reass.c
parent2d2929c912249f5cded546ea402051479a4a9b1a (diff)
downloadFreeBSD-src-acede79cbae3ad5ac9c813b98547f46f97d26877.zip
FreeBSD-src-acede79cbae3ad5ac9c813b98547f46f97d26877.tar.gz
Split tcp_input() into its two functional parts:
o tcp_input() now handles TCP segment sanity checks and preparations including the INPCB lookup and syncache. o tcp_do_segment() handles all data and ACK processing and is IPv4/v6 agnostic. Change all KASSERT() messages to ("%s: ", __func__). The changes in this commit are primarily of mechanical nature and no functional changes besides the function split are made. Discussed with: rwatson
Diffstat (limited to 'sys/netinet/tcp_reass.c')
-rw-r--r--sys/netinet/tcp_reass.c340
1 files changed, 208 insertions, 132 deletions
diff --git a/sys/netinet/tcp_reass.c b/sys/netinet/tcp_reass.c
index 519803b..6fdf186 100644
--- a/sys/netinet/tcp_reass.c
+++ b/sys/netinet/tcp_reass.c
@@ -177,7 +177,10 @@ struct inpcbinfo tcbinfo;
struct mtx *tcbinfo_mtx;
static void tcp_dooptions(struct tcpopt *, u_char *, int, int);
-
+static int tcp_do_segment(struct mbuf *, struct tcphdr *,
+ struct socket *, struct tcpcb *, int, int);
+static void tcp_dropwithreset(struct mbuf *, struct tcphdr *,
+ struct tcpcb *, int, int);
static void tcp_pulloutofband(struct socket *,
struct tcphdr *, struct mbuf *, int);
static int tcp_reass(struct tcpcb *, struct tcphdr *, int *,
@@ -437,29 +440,25 @@ tcp_input(struct mbuf *m, int off0)
struct ip *ip = NULL;
struct ipovly *ipov;
struct inpcb *inp = NULL;
+ struct tcpcb *tp = NULL;
+ struct socket *so = NULL;
u_char *optp = NULL;
int optlen = 0;
int len, tlen, off;
int drop_hdrlen;
- struct tcpcb *tp = NULL;
int thflags;
- struct socket *so = NULL;
- int todrop, acked, ourfinisacked, needoutput = 0;
- u_long tiwin;
- struct tcpopt to; /* options in this segment */
- int headlocked = 0;
+ int rstreason = 0; /* For badport_bandlim accounting purposes */
#ifdef IPFIREWALL_FORWARD
struct m_tag *fwd_tag;
#endif
- int rstreason; /* For badport_bandlim accounting purposes */
-
- struct ip6_hdr *ip6 = NULL;
#ifdef INET6
+ struct ip6_hdr *ip6 = NULL;
int isipv6;
char ip6buf[INET6_ADDRSTRLEN];
#else
const int isipv6 = 0;
#endif
+ struct tcpopt to; /* options in this segment */
#ifdef TCPDEBUG
/*
@@ -474,8 +473,8 @@ tcp_input(struct mbuf *m, int off0)
#ifdef INET6
isipv6 = (mtod(m, struct ip *)->ip_v == 6) ? 1 : 0;
#endif
- bzero((char *)&to, sizeof(to));
+ to.to_flags = 0;
tcpstat.tcps_rcvtotal++;
if (isipv6) {
@@ -618,9 +617,8 @@ tcp_input(struct mbuf *m, int off0)
* Locate pcb for segment.
*/
INP_INFO_WLOCK(&tcbinfo);
- headlocked = 1;
findpcb:
- KASSERT(headlocked, ("tcp_input: findpcb: head not locked"));
+ INP_INFO_WLOCK_ASSERT(&tcbinfo);
#ifdef IPFIREWALL_FORWARD
/* Grab info from PACKET_TAG_IPFORWARD tag prepended to the chain. */
fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL);
@@ -675,14 +673,14 @@ findpcb:
#ifdef IPSEC
ipsec6stat.in_polvio++;
#endif
- goto drop;
+ goto dropunlock;
} else
#endif /* INET6 */
if (inp != NULL && ipsec4_in_reject(m, inp)) {
#ifdef IPSEC
ipsecstat.in_polvio++;
#endif
- goto drop;
+ goto dropunlock;
}
#endif /*IPSEC || FAST_IPSEC*/
@@ -739,11 +737,11 @@ findpcb:
if (inp->inp_ip_minttl != 0) {
#ifdef INET6
if (isipv6 && inp->inp_ip_minttl > ip6->ip6_hlim)
- goto drop;
+ goto dropunlock;
else
#endif
if (inp->inp_ip_minttl > ip->ip_ttl)
- goto drop;
+ goto dropunlock;
}
/*
@@ -773,15 +771,15 @@ findpcb:
goto dropwithreset;
}
if (tp->t_state == TCPS_CLOSED)
- goto drop;
+ goto dropunlock; /* XXX: dropwithreset??? */
#ifdef MAC
INP_LOCK_ASSERT(inp);
if (mac_check_inpcb_deliver(inp, m))
- goto drop;
+ goto dropunlock;
#endif
so = inp->inp_socket;
- KASSERT(so != NULL, ("tcp_input: so == NULL"));
+ KASSERT(so != NULL, ("%s: so == NULL", __func__));
#ifdef TCPDEBUG
if (so->so_options & SO_DEBUG) {
ostate = tp->t_state;
@@ -802,10 +800,13 @@ findpcb:
bzero(&inc, sizeof(inc));
inc.inc_isipv6 = isipv6;
+#ifdef INET6
if (isipv6) {
inc.inc6_faddr = ip6->ip6_src;
inc.inc6_laddr = ip6->ip6_dst;
- } else {
+ } else
+#endif
+ {
inc.inc_faddr = ip->ip_src;
inc.inc_laddr = ip->ip_dst;
}
@@ -865,11 +866,23 @@ findpcb:
tp->snd_up = tp->snd_una;
tp->snd_max = tp->snd_nxt = tp->iss + 1;
tp->last_ack_sent = tp->rcv_nxt;
- goto after_listen;
+
+ /*
+ * Process the segment and the data it
+ * contains. tcp_do_segment() consumes
+ * the mbuf chain and unlocks the inpcb.
+ * XXX: The potential return value of
+ * TIME_WAIT nuked is supposed to be
+ * handled above.
+ */
+ if (tcp_do_segment(m, th, so, tp,
+ drop_hdrlen, tlen))
+ goto findpcb; /* TIME_WAIT nuked */
+ return;
}
if (thflags & TH_RST) {
syncache_chkrst(&inc, th);
- goto drop;
+ goto dropunlock;
}
if (thflags & TH_ACK) {
syncache_badack(&inc);
@@ -877,7 +890,7 @@ findpcb:
rstreason = BANDLIM_RST_OPENPORT;
goto dropwithreset;
}
- goto drop;
+ goto dropunlock;
}
/*
@@ -939,25 +952,25 @@ findpcb:
* in_broadcast() to find them.
*/
if (m->m_flags & (M_BCAST|M_MCAST))
- goto drop;
+ goto dropunlock;
if (isipv6) {
#ifdef INET6
if (th->th_dport == th->th_sport &&
IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &ip6->ip6_src))
- goto drop;
+ goto dropunlock;
if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
IN6_IS_ADDR_MULTICAST(&ip6->ip6_src))
- goto drop;
+ goto dropunlock;
#endif
} else {
if (th->th_dport == th->th_sport &&
ip->ip_dst.s_addr == ip->ip_src.s_addr)
- goto drop;
+ goto dropunlock;
if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) ||
IN_MULTICAST(ntohl(ip->ip_src.s_addr)) ||
ip->ip_src.s_addr == htonl(INADDR_BROADCAST) ||
in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif))
- goto drop;
+ goto dropunlock;
}
/*
* SYN appears to be valid. Create compressed TCP state
@@ -971,7 +984,7 @@ findpcb:
#endif
tcp_dooptions(&to, optp, optlen, TO_SYN);
if (!syncache_add(&inc, &to, th, inp, &so, m))
- goto drop;
+ goto dropunlock;
/*
* Entry added to syncache, mbuf used to
* send SYN-ACK packet. Everything unlocked
@@ -980,15 +993,46 @@ findpcb:
return;
}
/* Catch all. Everthing that makes it down here is junk. */
- goto drop;
+ goto dropunlock;
}
-after_listen:
- KASSERT(headlocked, ("tcp_input: after_listen: head not locked"));
- INP_LOCK_ASSERT(inp);
+ /*
+ * Segment belongs to a connection in SYN_SENT, ESTABLISHED or
+ * later state. tcp_do_segment() always consumes the mbuf chain
+ * and unlocks the inpcb.
+ */
+ if (tcp_do_segment(m, th, so, tp, drop_hdrlen, tlen))
+ goto findpcb; /* XXX: TIME_WAIT was nuked. */
+ return;
+
+dropwithreset:
+ tcp_dropwithreset(m, th, tp, tlen, rstreason);
+ m = NULL; /* mbuf chain got consumed. */
+dropunlock:
+ if (tp != NULL)
+ INP_UNLOCK(inp);
+ INP_INFO_WUNLOCK(&tcbinfo);
+drop:
+ if (m != NULL)
+ m_freem(m);
+ return;
+}
+
+static int
+tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
+ struct tcpcb *tp, int drop_hdrlen, int tlen)
+{
+ int thflags, acked, ourfinisacked, needoutput = 0;
+ int headlocked = 1;
+ int rstreason, todrop, win;
+ u_long tiwin;
+ struct tcpopt to;
+
+ thflags = th->th_flags;
- /* Syncache takes care of sockets in the listen state. */
- KASSERT(tp->t_state != TCPS_LISTEN, ("tcp_input: TCPS_LISTEN"));
+ INP_INFO_WLOCK_ASSERT(&tcbinfo);
+ INP_LOCK_ASSERT(tp->t_inpcb);
+ KASSERT(tp->t_state > TCPS_LISTEN, ("%s: TCPS_LISTEN", __func__));
/*
* Segment received on connection.
@@ -1008,7 +1052,9 @@ after_listen:
/*
* Parse options on any incoming segment.
*/
- tcp_dooptions(&to, optp, optlen, (thflags & TH_SYN) ? TO_SYN : 0);
+ tcp_dooptions(&to, (u_char *)(th + 1),
+ (th->th_off << 2) - sizeof(struct tcphdr),
+ (thflags & TH_SYN) ? TO_SYN : 0);
/*
* If echoed timestamp is later than the current time,
@@ -1100,7 +1146,8 @@ after_listen:
!IN_FASTRECOVERY(tp) &&
(to.to_flags & TOF_SACK) == 0 &&
TAILQ_EMPTY(&tp->snd_holes)))) {
- KASSERT(headlocked, ("headlocked"));
+ KASSERT(headlocked,
+ ("%s: headlocked", __func__));
INP_INFO_WUNLOCK(&tcbinfo);
headlocked = 0;
/*
@@ -1197,7 +1244,7 @@ after_listen:
tlen <= sbspace(&so->so_rcv)) {
int newsize = 0; /* automatic sockbuf scaling */
- KASSERT(headlocked, ("headlocked"));
+ KASSERT(headlocked, ("%s: headlocked", __func__));
INP_INFO_WUNLOCK(&tcbinfo);
headlocked = 0;
/*
@@ -1315,13 +1362,10 @@ after_listen:
* Receive window is amount of space in rcv queue,
* but not less than advertised window.
*/
- { int win;
-
win = sbspace(&so->so_rcv);
if (win < 0)
win = 0;
tp->rcv_wnd = imax(win, (int)(tp->rcv_adv - tp->rcv_nxt));
- }
/* Reset receive buffer auto scaling when not in bulk receive mode. */
tp->rfbuf_ts = 0;
@@ -1363,8 +1407,8 @@ after_listen:
}
if (thflags & TH_RST) {
if (thflags & TH_ACK) {
- KASSERT(headlocked, ("tcp_input: after_listen"
- ": tcp_drop.2: head not locked"));
+ KASSERT(headlocked, ("%s: after_listen: "
+ "tcp_drop.2: head not locked", __func__));
tp = tcp_drop(tp, ECONNREFUSED);
}
goto drop;
@@ -1430,9 +1474,9 @@ after_listen:
tp->t_state = TCPS_SYN_RECEIVED;
}
- KASSERT(headlocked, ("tcp_input: trimthenstep6: head not "
- "locked"));
- INP_LOCK_ASSERT(inp);
+ KASSERT(headlocked, ("%s: trimthenstep6: head not locked",
+ __func__));
+ INP_LOCK_ASSERT(tp->t_inpcb);
/*
* Advance th->th_seq to correspond to first data byte.
@@ -1471,7 +1515,8 @@ after_listen:
case TCPS_LAST_ACK:
case TCPS_CLOSING:
case TCPS_TIME_WAIT:
- KASSERT(tp->t_state != TCPS_TIME_WAIT, ("timewait"));
+ KASSERT(tp->t_state != TCPS_TIME_WAIT, ("%s: timewait",
+ __func__));
break; /* continue normal processing */
}
@@ -1562,22 +1607,21 @@ after_listen:
close:
tp->t_state = TCPS_CLOSED;
tcpstat.tcps_drops++;
- KASSERT(headlocked, ("tcp_input: "
- "trimthenstep6: tcp_close: head not "
- "locked"));
+ KASSERT(headlocked, ("%s: trimthenstep6: "
+ "tcp_close: head not locked", __func__));
tp = tcp_close(tp);
break;
case TCPS_CLOSING:
case TCPS_LAST_ACK:
- KASSERT(headlocked, ("trimthenstep6: "
- "tcp_close.2: head not locked"));
+ KASSERT(headlocked, ("%s: trimthenstep6: "
+ "tcp_close.2: head not locked", __func__));
tp = tcp_close(tp);
break;
case TCPS_TIME_WAIT:
KASSERT(tp->t_state != TCPS_TIME_WAIT,
- ("timewait"));
+ ("%s: timewait", __func__));
break;
}
}
@@ -1679,8 +1723,8 @@ after_listen:
*/
if ((so->so_state & SS_NOFDREF) &&
tp->t_state > TCPS_CLOSE_WAIT && tlen) {
- KASSERT(headlocked, ("trimthenstep6: tcp_close.3: head not "
- "locked"));
+ KASSERT(headlocked, ("%s: trimthenstep6: tcp_close.3: head "
+ "not locked", __func__));
tp = tcp_close(tp);
tcpstat.tcps_rcvafterclose++;
rstreason = BANDLIM_UNLIMITED;
@@ -1702,14 +1746,16 @@ after_listen:
* and start over if the sequence numbers
* are above the previous ones.
*/
- KASSERT(tp->t_state != TCPS_TIME_WAIT, ("timewait"));
+ KASSERT(tp->t_state != TCPS_TIME_WAIT, ("%s: timewait",
+ __func__));
if (thflags & TH_SYN &&
tp->t_state == TCPS_TIME_WAIT &&
SEQ_GT(th->th_seq, tp->rcv_nxt)) {
- KASSERT(headlocked, ("trimthenstep6: "
- "tcp_close.4: head not locked"));
+ KASSERT(headlocked, ("%s: trimthenstep6: "
+ "tcp_close.4: head not locked", __func__));
tp = tcp_close(tp);
- goto findpcb;
+ /* XXX: Shouldn't be possible. */
+ return (1);
}
/*
* If window is closed can only take segments at
@@ -1761,8 +1807,8 @@ after_listen:
* error and we send an RST and drop the connection.
*/
if (thflags & TH_SYN) {
- KASSERT(headlocked, ("tcp_input: tcp_drop: trimthenstep6: "
- "head not locked"));
+ KASSERT(headlocked, ("%s: tcp_drop: trimthenstep6: "
+ "head not locked", __func__));
tp = tcp_drop(tp, ECONNRESET);
rstreason = BANDLIM_UNLIMITED;
goto drop;
@@ -1842,7 +1888,8 @@ after_listen:
case TCPS_CLOSING:
case TCPS_LAST_ACK:
case TCPS_TIME_WAIT:
- KASSERT(tp->t_state != TCPS_TIME_WAIT, ("timewait"));
+ KASSERT(tp->t_state != TCPS_TIME_WAIT, ("%s: timewait",
+ __func__));
if (SEQ_GT(th->th_ack, tp->snd_max)) {
tcpstat.tcps_rcvacktoomuch++;
goto dropafterack;
@@ -1947,7 +1994,8 @@ after_listen:
tp->snd_cwnd = tp->t_maxseg;
(void) tcp_output(tp);
KASSERT(tp->snd_limited <= 2,
- ("tp->snd_limited too big"));
+ ("%s: tp->snd_limited too big",
+ __func__));
tp->snd_cwnd = tp->snd_ssthresh +
tp->t_maxseg *
(tp->t_dupacks - tp->snd_limited);
@@ -1961,7 +2009,8 @@ after_listen:
KASSERT(tp->t_dupacks == 1 ||
tp->t_dupacks == 2,
- ("dupacks not 1 or 2"));
+ ("%s: dupacks not 1 or 2",
+ __func__));
if (tp->t_dupacks == 1)
tp->snd_limited = 0;
tp->snd_cwnd =
@@ -1975,7 +2024,8 @@ after_listen:
tp->snd_limited == 0) ||
(sent == tp->t_maxseg + 1 &&
tp->t_flags & TF_SENTFIN),
- ("sent too much"));
+ ("%s: sent too much",
+ __func__));
tp->snd_limited = 2;
} else if (sent > 0)
++tp->snd_limited;
@@ -1987,7 +2037,8 @@ after_listen:
break;
}
- KASSERT(SEQ_GT(th->th_ack, tp->snd_una), ("th_ack <= snd_una"));
+ KASSERT(SEQ_GT(th->th_ack, tp->snd_una),
+ ("%s: th_ack <= snd_una", __func__));
/*
* If the congestion window was inflated to account
@@ -2049,9 +2100,9 @@ after_listen:
}
process_ACK:
- KASSERT(headlocked, ("tcp_input: process_ACK: head not "
- "locked"));
- INP_LOCK_ASSERT(inp);
+ KASSERT(headlocked, ("%s: process_ACK: head not locked",
+ __func__));
+ INP_LOCK_ASSERT(tp->t_inpcb);
acked = th->th_ack - tp->snd_una;
tcpstat.tcps_rcvackpack++;
@@ -2206,12 +2257,13 @@ process_ACK:
*/
case TCPS_CLOSING:
if (ourfinisacked) {
- KASSERT(headlocked, ("tcp_input: process_ACK: "
- "head not locked"));
+ KASSERT(headlocked, ("%s: process_ACK: "
+ "head not locked", __func__));
tcp_twstart(tp);
INP_INFO_WUNLOCK(&tcbinfo);
+ headlocked = 0;
m_freem(m);
- return;
+ return (0);
}
break;
@@ -2223,8 +2275,8 @@ process_ACK:
*/
case TCPS_LAST_ACK:
if (ourfinisacked) {
- KASSERT(headlocked, ("tcp_input: process_ACK:"
- " tcp_close: head not locked"));
+ KASSERT(headlocked, ("%s: process_ACK: "
+ "tcp_close: head not locked", __func__));
tp = tcp_close(tp);
goto drop;
}
@@ -2236,7 +2288,8 @@ process_ACK:
* it and restart the finack timer.
*/
case TCPS_TIME_WAIT:
- KASSERT(tp->t_state != TCPS_TIME_WAIT, ("timewait"));
+ KASSERT(tp->t_state != TCPS_TIME_WAIT,
+ ("%s: timewait", __func__));
callout_reset(tp->tt_2msl, 2 * tcp_msl,
tcp_timer_2msl, tp);
goto dropafterack;
@@ -2244,8 +2297,8 @@ process_ACK:
}
step6:
- KASSERT(headlocked, ("tcp_input: step6: head not locked"));
- INP_LOCK_ASSERT(inp);
+ KASSERT(headlocked, ("%s: step6: head not locked", __func__));
+ INP_LOCK_ASSERT(tp->t_inpcb);
/*
* Update window information.
@@ -2330,8 +2383,8 @@ step6:
tp->rcv_up = tp->rcv_nxt;
}
dodata: /* XXX */
- KASSERT(headlocked, ("tcp_input: dodata: head not locked"));
- INP_LOCK_ASSERT(inp);
+ KASSERT(headlocked, ("%s: dodata: head not locked", __func__));
+ INP_LOCK_ASSERT(tp->t_inpcb);
/*
* Process the segment text, merging it into the TCP sequencing queue,
@@ -2382,12 +2435,15 @@ dodata: /* XXX */
}
if (tlen > 0 && tp->sack_enable)
tcp_update_sack_list(tp, save_start, save_end);
+#if 0
/*
* Note the amount of data that peer has sent into
* our window, in order to estimate the sender's
* buffer size.
+ * XXX: Unused.
*/
len = so->so_rcv.sb_hiwat - (tp->rcv_adv - tp->rcv_nxt);
+#endif
} else {
m_freem(m);
thflags &= ~TH_FIN;
@@ -2440,17 +2496,18 @@ dodata: /* XXX */
* standard timers.
*/
case TCPS_FIN_WAIT_2:
- KASSERT(headlocked == 1, ("tcp_input: dodata: "
- "TCP_FIN_WAIT_2: head not locked"));
+ KASSERT(headlocked == 1, ("%s: dodata: "
+ "TCP_FIN_WAIT_2: head not locked", __func__));
tcp_twstart(tp);
INP_INFO_WUNLOCK(&tcbinfo);
- return;
+ return (0);
/*
* In TIME_WAIT state restart the 2 MSL time_wait timer.
*/
case TCPS_TIME_WAIT:
- KASSERT(tp->t_state != TCPS_TIME_WAIT, ("timewait"));
+ KASSERT(tp->t_state != TCPS_TIME_WAIT,
+ ("%s: timewait", __func__));
callout_reset(tp->tt_2msl, 2 * tcp_msl,
tcp_timer_2msl, tp);
break;
@@ -2471,18 +2528,19 @@ dodata: /* XXX */
(void) tcp_output(tp);
check_delack:
- KASSERT(headlocked == 0, ("tcp_input: check_delack: head locked"));
- INP_LOCK_ASSERT(inp);
+ KASSERT(headlocked == 0, ("%s: check_delack: head locked",
+ __func__));
+ INP_LOCK_ASSERT(tp->t_inpcb);
if (tp->t_flags & TF_DELACK) {
tp->t_flags &= ~TF_DELACK;
callout_reset(tp->tt_delack, tcp_delacktime,
tcp_timer_delack, tp);
}
- INP_UNLOCK(inp);
- return;
+ INP_UNLOCK(tp->t_inpcb);
+ return (0);
dropafterack:
- KASSERT(headlocked, ("tcp_input: dropafterack: head not locked"));
+ KASSERT(headlocked, ("%s: dropafterack: head not locked", __func__));
/*
* Generate an ACK dropping incoming segment if it occupies
* sequence space, where the ACK reflects our state.
@@ -2509,79 +2567,97 @@ dropafterack:
tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen,
&tcp_savetcp, 0);
#endif
- KASSERT(headlocked, ("headlocked should be 1"));
+ KASSERT(headlocked, ("%s: headlocked should be 1", __func__));
INP_INFO_WUNLOCK(&tcbinfo);
tp->t_flags |= TF_ACKNOW;
(void) tcp_output(tp);
- INP_UNLOCK(inp);
+ INP_UNLOCK(tp->t_inpcb);
m_freem(m);
- return;
+ return (0);
dropwithreset:
- KASSERT(headlocked, ("tcp_input: dropwithreset: head not locked"));
+ KASSERT(headlocked, ("%s: dropwithreset: head not locked", __func__));
+
+ tcp_dropwithreset(m, th, tp, tlen, rstreason);
+
+ if (tp != NULL)
+ INP_UNLOCK(tp->t_inpcb);
+ if (headlocked)
+ INP_INFO_WUNLOCK(&tcbinfo);
+ return (0);
+
+drop:
+ /*
+ * Drop space held by incoming segment and return.
+ */
+#ifdef TCPDEBUG
+ if (tp == NULL || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG))
+ tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen,
+ &tcp_savetcp, 0);
+#endif
+ if (tp != NULL)
+ INP_UNLOCK(tp->t_inpcb);
+ if (headlocked)
+ INP_INFO_WUNLOCK(&tcbinfo);
+ m_freem(m);
+ return (0);
+}
+
+
+/*
+ * Issue RST on TCP segment. The mbuf must still include the original
+ * packet header.
+ */
+static void
+tcp_dropwithreset(struct mbuf *m, struct tcphdr *th, struct tcpcb *tp,
+ int tlen, int rstreason)
+{
+ struct ip *ip;
+#ifdef INET6
+ struct ip6_hdr *ip6;
+#endif
+
/*
* Generate a RST, dropping incoming segment.
* Make ACK acceptable to originator of segment.
* Don't bother to respond if destination was broadcast/multicast.
*/
- if ((thflags & TH_RST) || m->m_flags & (M_BCAST|M_MCAST))
+ if ((th->th_flags & TH_RST) || m->m_flags & (M_BCAST|M_MCAST))
goto drop;
- if (isipv6) {
+#ifdef INET6
+ if (mtod(m, struct ip *)->ip_v == 6) {
+ ip6 = mtod(m, struct ip6_hdr *);
if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
IN6_IS_ADDR_MULTICAST(&ip6->ip6_src))
goto drop;
- } else {
+ /* IPv6 anycast check is done at tcp6_input() */
+ } else
+#endif
+ {
+ ip = mtod(m, struct ip *);
if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) ||
IN_MULTICAST(ntohl(ip->ip_src.s_addr)) ||
ip->ip_src.s_addr == htonl(INADDR_BROADCAST) ||
in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif))
goto drop;
}
- /* IPv6 anycast check is done at tcp6_input() */
- /*
- * Perform bandwidth limiting.
- */
+ /* Perform bandwidth limiting. */
if (badport_bandlim(rstreason) < 0)
goto drop;
-#ifdef TCPDEBUG
- if (tp == 0 || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG))
- tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen,
- &tcp_savetcp, 0);
-#endif
-
- if (thflags & TH_ACK)
- /* mtod() below is safe as long as hdr dropping is delayed */
- tcp_respond(tp, mtod(m, void *), th, m, (tcp_seq)0, th->th_ack,
- TH_RST);
- else {
- if (thflags & TH_SYN)
+ /* tcp_respond consumes the mbuf chain. */
+ if (th->th_flags & TH_ACK) {
+ tcp_respond(tp, mtod(m, void *), th, m, (tcp_seq)0,
+ th->th_ack, TH_RST);
+ } else {
+ if (th->th_flags & TH_SYN)
tlen++;
- /* mtod() below is safe as long as hdr dropping is delayed */
tcp_respond(tp, mtod(m, void *), th, m, th->th_seq+tlen,
- (tcp_seq)0, TH_RST|TH_ACK);
+ (tcp_seq)0, TH_RST|TH_ACK);
}
-
- if (tp != NULL)
- INP_UNLOCK(inp);
- if (headlocked)
- INP_INFO_WUNLOCK(&tcbinfo);
return;
-
drop:
- /*
- * Drop space held by incoming segment and return.
- */
-#ifdef TCPDEBUG
- if (tp == NULL || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG))
- tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen,
- &tcp_savetcp, 0);
-#endif
- if (tp != NULL)
- INP_UNLOCK(inp);
- if (headlocked)
- INP_INFO_WUNLOCK(&tcbinfo);
m_freem(m);
return;
}
OpenPOWER on IntegriCloud