SYSCTL_INT(_net_inet_ip, OID_AUTO, check_interface, CTLFLAG_RW,
&ip_checkinterface, 0, "Verify packet arrives on correct interface");
+static struct lwkt_token ipq_token = LWKT_TOKEN_MP_INITIALIZER(ipq_token);
+
#ifdef DIAGNOSTIC
static int ipprintfs = 0;
#endif
/*
* Look for queue of fragments of this datagram.
*/
- for (fp = ipq[sum].next; fp != &ipq[sum]; fp = fp->next)
+ lwkt_gettoken(&ipq_token);
+ for (fp = ipq[sum].next; fp != &ipq[sum]; fp = fp->next) {
if (ip->ip_id == fp->ipq_id &&
ip->ip_src.s_addr == fp->ipq_src.s_addr &&
ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
ip->ip_p == fp->ipq_p)
goto found;
+ }
fp = NULL;
if (ip->ip_len == 0 || (ip->ip_len & 0x7) != 0) {
ipstat.ips_toosmall++; /* XXX */
m_freem(m);
- return NULL;
+ goto done;
}
m->m_flags |= M_FRAG;
- } else
+ } else {
m->m_flags &= ~M_FRAG;
+ }
ip->ip_off <<= 3;
ipstat.ips_fragments++;
/*
* Find a segment which begins after this one does.
*/
- for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt)
+ for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt) {
if (GETIP(q)->ip_off > ip->ip_off)
break;
+ }
/*
* If there is a preceding segment, it may provide some of
ipstat.ips_fragdropped += fp->ipq_nfrags;
ip_freef(fp);
}
- return (NULL);
+ goto done;
}
next += GETIP(q)->ip_len;
}
ipstat.ips_fragdropped += fp->ipq_nfrags;
ip_freef(fp);
}
- return (NULL);
+ goto done;
}
/*
ipstat.ips_toolong++;
ipstat.ips_fragdropped += fp->ipq_nfrags;
ip_freef(fp);
- return (NULL);
+ goto done;
}
/*
}
ipstat.ips_reassembled++;
+ lwkt_reltoken(&ipq_token);
return (m);
dropfrag:
if (fp != NULL)
fp->ipq_nfrags--;
m_freem(m);
+done:
+ lwkt_reltoken(&ipq_token);
return (NULL);
#undef GETIP
/*
* Free a fragment reassembly header and all
* associated datagrams.
+ *
+ * Called with ipq_token held.
*/
static void
ip_freef(struct ipq *fp)
{
struct mbuf *q;
+ /*
+ * Remove first to protect against blocking
+ */
+ remque(fp);
+
+ /*
+ * Clean out at our leisure
+ */
while (fp->ipq_frags) {
q = fp->ipq_frags;
fp->ipq_frags = q->m_nextpkt;
q->m_nextpkt = NULL;
m_freem(q);
}
- remque(fp);
mpipe_free(&ipq_mpipe, fp);
nipq--;
}
struct ipq *fp;
int i;
- crit_enter();
+ lwkt_gettoken(&ipq_token);
for (i = 0; i < IPREASS_NHASH; i++) {
fp = ipq[i].next;
if (fp == NULL)
}
}
}
+ lwkt_reltoken(&ipq_token);
ipflow_slowtimo();
- crit_exit();
}
/*
{
int i;
+ lwkt_gettoken(&ipq_token);
for (i = 0; i < IPREASS_NHASH; i++) {
while (ipq[i].next != &ipq[i]) {
ipstat.ips_fragdropped += ipq[i].next->ipq_nfrags;
ip_freef(ipq[i].next);
}
}
+ lwkt_reltoken(&ipq_token);
in_rtqdrain();
}
tp->reportblk.rblk_start = tp->reportblk.rblk_end;
return (0);
}
- tcp_reass_qsize++;
+ atomic_add_int(&tcp_reass_qsize, 1);
/*
* Find a segment which begins after this one does.
tcpstat.tcps_rcvdupbyte += *tlenp;
m_freem(m);
kfree(te, M_TSEGQ);
- tcp_reass_qsize--;
+ atomic_add_int(&tcp_reass_qsize, -1);
/*
* Try to present any queued data
* at the left window edge to the user.
LIST_REMOVE(q, tqe_q);
m_freem(q->tqe_m);
kfree(q, M_TSEGQ);
- tcp_reass_qsize--;
+ atomic_add_int(&tcp_reass_qsize, -1);
q = nq;
}
tp->reportblk.rblk_end = tend;
LIST_REMOVE(q, tqe_q);
kfree(q, M_TSEGQ);
- tcp_reass_qsize--;
+ atomic_add_int(&tcp_reass_qsize, -1);
}
if (p == NULL) {
if (!(tp->t_flags & TF_DUPSEG))
tp->reportblk.rblk_start = p->tqe_th->th_seq;
kfree(te, M_TSEGQ);
- tcp_reass_qsize--;
- } else
+ atomic_add_int(&tcp_reass_qsize, -1);
+ } else {
LIST_INSERT_AFTER(p, te, tqe_q);
+ }
}
present:
else
ssb_appendstream(&so->so_rcv, q->tqe_m);
kfree(q, M_TSEGQ);
- tcp_reass_qsize--;
+ atomic_add_int(&tcp_reass_qsize, -1);
ND6_HINT(tp);
sorwakeup(so);
return (flags);
rstreason = BANDLIM_RST_OPENPORT;
goto dropwithreset;
}
+
+ /*
+ * Could not complete 3-way handshake,
+ * connection is being closed down, and
+ * syncache will free mbuf.
+ */
if (so == NULL)
- /*
- * Could not complete 3-way handshake,
- * connection is being closed down, and
- * syncache will free mbuf.
- */
return;
+
+ /*
+ * We must be in the correct protocol thread
+ * for this connection.
+ */
+ KKASSERT(so->so_port == &curthread->td_msgport);
+
/*
* Socket is created in state SYN_RECEIVED.
* Continue processing segment.
tcp_dooptions(&to, optp, optlen, TRUE);
if (!syncache_add(&inc, &to, th, &so, m))
goto drop;
+
+ /*
+ * Entry added to syncache, mbuf used to
+ * send SYN,ACK packet.
+ */
if (so == NULL)
- /*
- * Entry added to syncache, mbuf used to
- * send SYN,ACK packet.
- */
return;
+
+ /*
+ * We must be in the correct protocol thread for
+ * this connection.
+ */
+ KKASSERT(so->so_port == &curthread->td_msgport);
+
inp = so->so_pcb;
tp = intotcpcb(inp);
tp->snd_wnd = tiwin;
}
goto drop;
}
-after_listen:
- /* should not happen - syncache should pick up these connections */
+after_listen:
+ /*
+ * Should not happen - syncache should pick up these connections.
+ *
+ * Once we are past handling listen sockets we must be in the
+ * correct protocol processing thread.
+ */
KASSERT(tp->t_state != TCPS_LISTEN, ("tcp_input: TCPS_LISTEN state"));
+ KKASSERT(so->so_port == &curthread->td_msgport);
/*
* This is the second part of the MSS DoS prevention code (after
const boolean_t isipv6 = FALSE;
#endif
+ KKASSERT(so->so_port == &curthread->td_msgport);
+
/*
* Determine length of data that should be transmitted,
* and flags that will be used.
LIST_REMOVE(q, tqe_q);
m_freem(q->tqe_m);
FREE(q, M_TSEGQ);
- tcp_reass_qsize--;
+ atomic_add_int(&tcp_reass_qsize, -1);
}
/* throw away SACK blocks in scoreboard*/
if (TCP_DO_SACK(tp))
static __inline void
tcp_drain_oncpu(struct inpcbhead *head)
{
+ struct inpcb *marker;
struct inpcb *inpb;
struct tcpcb *tcpb;
struct tseg_qent *te;
- LIST_FOREACH(inpb, head, inp_list) {
- if (inpb->inp_flags & INP_PLACEMARKER)
- continue;
- if ((tcpb = intotcpcb(inpb))) {
- while ((te = LIST_FIRST(&tcpb->t_segq)) != NULL) {
- LIST_REMOVE(te, tqe_q);
- m_freem(te->tqe_m);
- FREE(te, M_TSEGQ);
- tcp_reass_qsize--;
- }
+ /*
+ * Allows us to block while running the list
+ */
+ marker = kmalloc(sizeof(struct inpcb), M_TEMP, M_WAITOK|M_ZERO);
+ marker->inp_flags |= INP_PLACEMARKER;
+ LIST_INSERT_HEAD(head, marker, inp_list);
+
+ while ((inpb = LIST_NEXT(marker, inp_list)) != NULL) {
+ if ((inpb->inp_flags & INP_PLACEMARKER) == 0 &&
+ (tcpb = intotcpcb(inpb)) != NULL &&
+ (te = LIST_FIRST(&tcpb->t_segq)) != NULL) {
+ LIST_REMOVE(te, tqe_q);
+ m_freem(te->tqe_m);
+ FREE(te, M_TSEGQ);
+ atomic_add_int(&tcp_reass_qsize, -1);
+ /* retry */
+ } else {
+ LIST_REMOVE(marker, inp_list);
+ LIST_INSERT_AFTER(inpb, marker, inp_list);
}
}
+ LIST_REMOVE(marker, inp_list);
+ kfree(marker, M_TEMP);
}
#ifdef SMP
_mm->m_len += _mplen; \
} else \
_mm = m_prepend(_mm, _mplen, __mhow); \
- if (_mm != NULL && _mm->m_flags & M_PKTHDR) \
+ if (_mm != NULL && (_mm->m_flags & M_PKTHDR)) \
_mm->m_pkthdr.len += _mplen; \
*_mmp = _mm; \
} while (0)