summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2007-10-12 04:56:26 +0000
committermav <mav@FreeBSD.org>2007-10-12 04:56:26 +0000
commit58809b0788815a16cbc3fbef8276ecca2f0bf19e (patch)
tree264a22b2a879d196b870fbabecaa238b2b542671 /sys
parent2d88988487cba518641852dc4a4b069612021a1a (diff)
downloadFreeBSD-src-58809b0788815a16cbc3fbef8276ecca2f0bf19e.zip
FreeBSD-src-58809b0788815a16cbc3fbef8276ecca2f0bf19e.tar.gz
Protect struct seq with mutex.
Approved by: glebius (mentor)
Diffstat (limited to 'sys')
-rw-r--r--sys/netgraph/ng_l2tp.c89
1 files changed, 72 insertions, 17 deletions
diff --git a/sys/netgraph/ng_l2tp.c b/sys/netgraph/ng_l2tp.c
index 265dbf2..88adde2 100644
--- a/sys/netgraph/ng_l2tp.c
+++ b/sys/netgraph/ng_l2tp.c
@@ -128,6 +128,7 @@ struct l2tp_seq {
struct callout rack_timer; /* retransmit timer */
struct callout xack_timer; /* delayed ack timer */
struct mbuf *xwin[L2TP_MAX_XWIN]; /* transmit window */
+ struct mtx mtx; /* seq mutex */
};
/* Node private data */
@@ -675,6 +676,8 @@ ng_l2tp_shutdown(node_p node)
ng_uncallout(&seq->rack_timer, node);
ng_uncallout(&seq->xack_timer, node);
+ mtx_destroy(&seq->mtx);
+
FREE(priv, M_NETGRAPH_L2TP);
/* Unref node */
@@ -993,6 +996,7 @@ ng_l2tp_rcvdata_ctrl(hook_p hook, item_p item)
struct mbuf *m;
int error;
int i;
+ u_int16_t ns;
/* Sanity check */
L2TP_SEQ_CHECK(&priv->seq);
@@ -1021,9 +1025,12 @@ ng_l2tp_rcvdata_ctrl(hook_p hook, item_p item)
ERROUT(EOVERFLOW);
}
+ mtx_lock(&seq->mtx);
+
/* Find next empty slot in transmit queue */
for (i = 0; i < L2TP_MAX_XWIN && seq->xwin[i] != NULL; i++);
if (i == L2TP_MAX_XWIN) {
+ mtx_unlock(&seq->mtx);
priv->stats.xmitDrops++;
m_freem(m);
ERROUT(ENOBUFS);
@@ -1031,22 +1038,28 @@ ng_l2tp_rcvdata_ctrl(hook_p hook, item_p item)
seq->xwin[i] = m;
/* If peer's receive window is already full, nothing else to do */
- if (i >= seq->cwnd)
+ if (i >= seq->cwnd) {
+ mtx_unlock(&seq->mtx);
ERROUT(0);
+ }
/* Start retransmit timer if not already running */
if (!callout_active(&seq->rack_timer))
ng_callout(&seq->rack_timer, node, NULL,
hz, ng_l2tp_seq_rack_timeout, NULL, 0);
+
+ ns = seq->ns++;
+
+ mtx_unlock(&seq->mtx);
/* Copy packet */
- if ((m = L2TP_COPY_MBUF(seq->xwin[i], M_DONTWAIT)) == NULL) {
+ if ((m = L2TP_COPY_MBUF(m, M_DONTWAIT)) == NULL) {
priv->stats.memoryFailures++;
ERROUT(ENOBUFS);
}
/* Send packet and increment xmit sequence number */
- error = ng_l2tp_xmit_ctrl(priv, m, seq->ns++);
+ error = ng_l2tp_xmit_ctrl(priv, m, ns);
done:
/* Done */
L2TP_SEQ_CHECK(&priv->seq);
@@ -1164,6 +1177,7 @@ ng_l2tp_seq_init(priv_p priv)
seq->ssth = seq->wmax;
ng_callout_init(&seq->rack_timer);
ng_callout_init(&seq->xack_timer);
+ mtx_init(&seq->mtx, "ng_l2tp", NULL, MTX_DEF);
L2TP_SEQ_CHECK(seq);
}
@@ -1249,10 +1263,16 @@ ng_l2tp_seq_reset(priv_p priv)
NG_NODE_FOREACH_HOOK(priv->node, ng_l2tp_reset_session, NULL, hook);
/* Reset node's sequence number state */
- memset(seq, 0, sizeof(*seq));
- seq->cwnd = 1;
+ seq->ns = 0;
+ seq->nr = 0;
+ seq->rack = 0;
+ seq->xack = 0;
seq->wmax = L2TP_MAX_XWIN;
+ seq->cwnd = 1;
seq->ssth = seq->wmax;
+ seq->acks = 0;
+ seq->rexmits = 0;
+ bzero(seq->xwin, sizeof(seq->xwin));
/* Done */
L2TP_SEQ_CHECK(seq);
@@ -1265,14 +1285,20 @@ static void
ng_l2tp_seq_recv_nr(priv_p priv, u_int16_t nr)
{
struct l2tp_seq *const seq = &priv->seq;
- struct mbuf *m;
- int nack;
- int i;
+ struct mbuf *xwin[L2TP_MAX_XWIN]; /* partial local copy */
+ int nack;
+ int i, j;
+ uint16_t ns;
+
+ mtx_lock(&seq->mtx);
/* Verify peer's ACK is in range */
- if ((nack = L2TP_SEQ_DIFF(nr, seq->rack)) <= 0)
+ if ((nack = L2TP_SEQ_DIFF(nr, seq->rack)) <= 0) {
+ mtx_unlock(&seq->mtx);
return; /* duplicate ack */
+ }
if (L2TP_SEQ_DIFF(nr, seq->ns) > 0) {
+ mtx_unlock(&seq->mtx);
priv->stats.recvBadAcks++; /* ack for packet not sent */
return;
}
@@ -1324,8 +1350,10 @@ ng_l2tp_seq_recv_nr(priv_p priv, u_int16_t nr)
ng_uncallout(&seq->rack_timer, priv->node);
/* If transmit queue is empty, we're done for now */
- if (seq->xwin[0] == NULL)
+ if (seq->xwin[0] == NULL) {
+ mtx_unlock(&seq->mtx);
return;
+ }
/* Start restransmit timer again */
ng_callout(&seq->rack_timer, priv->node, NULL,
@@ -1333,16 +1361,30 @@ ng_l2tp_seq_recv_nr(priv_p priv, u_int16_t nr)
/*
* Send more packets, trying to keep peer's receive window full.
- * If there is a memory error, pretend packet was sent, as it
- * will get retransmitted later anyway.
+ * Make copy of everything we need before lock release.
*/
+ ns = seq->ns;
+ j = 0;
while ((i = L2TP_SEQ_DIFF(seq->ns, seq->rack)) < seq->cwnd
&& seq->xwin[i] != NULL) {
- if ((m = L2TP_COPY_MBUF(seq->xwin[i], M_DONTWAIT)) == NULL)
+ xwin[j++] = seq->xwin[i];
+ seq->ns++;
+ }
+
+ mtx_unlock(&seq->mtx);
+
+ /*
+ * Send prepared.
+ * If there is a memory error, pretend packet was sent, as it
+ * will get retransmitted later anyway.
+ */
+ for (i = 0; i < j; i++) {
+ struct mbuf *m;
+ if ((m = L2TP_COPY_MBUF(xwin[i], M_DONTWAIT)) == NULL)
priv->stats.memoryFailures++;
else
- ng_l2tp_xmit_ctrl(priv, m, seq->ns);
- seq->ns++;
+ ng_l2tp_xmit_ctrl(priv, m, ns);
+ ns++;
}
}
@@ -1371,6 +1413,8 @@ ng_l2tp_seq_recv_ns(priv_p priv, u_int16_t ns)
return (-1);
}
+ mtx_lock(&seq->mtx);
+
/* Update recv sequence number */
seq->nr++;
@@ -1379,6 +1423,8 @@ ng_l2tp_seq_recv_ns(priv_p priv, u_int16_t ns)
ng_callout(&seq->xack_timer, priv->node, NULL,
L2TP_DELAYED_ACK, ng_l2tp_seq_xack_timeout, NULL, 0);
+ mtx_unlock(&seq->mtx);
+
/* Accept packet */
return (0);
}
@@ -1473,6 +1519,8 @@ ng_l2tp_xmit_ctrl(priv_p priv, struct mbuf *m, u_int16_t ns)
u_int16_t session_id = 0;
int error;
+ mtx_lock(&seq->mtx);
+
/* Stop ack timer: we're sending an ack with this packet.
Doing this before to keep state predictable after error. */
if (callout_active(&seq->xack_timer))
@@ -1480,6 +1528,8 @@ ng_l2tp_xmit_ctrl(priv_p priv, struct mbuf *m, u_int16_t ns)
seq->xack = seq->nr;
+ mtx_unlock(&seq->mtx);
+
/* If no mbuf passed, send an empty packet (ZLB) */
if (m == NULL) {
@@ -1534,12 +1584,15 @@ ng_l2tp_xmit_ctrl(priv_p priv, struct mbuf *m, u_int16_t ns)
static void
ng_l2tp_seq_check(struct l2tp_seq *seq)
{
- const int self_unack = L2TP_SEQ_DIFF(seq->nr, seq->xack);
- const int peer_unack = L2TP_SEQ_DIFF(seq->ns, seq->rack);
+ int self_unack, peer_unack;
int i;
#define CHECK(p) KASSERT((p), ("%s: not: %s", __func__, #p))
+ mtx_lock(&seq->mtx);
+
+ self_unack = L2TP_SEQ_DIFF(seq->nr, seq->xack);
+ peer_unack = L2TP_SEQ_DIFF(seq->ns, seq->rack);
CHECK(seq->wmax <= L2TP_MAX_XWIN);
CHECK(seq->cwnd >= 1);
CHECK(seq->cwnd <= seq->wmax);
@@ -1559,6 +1612,8 @@ ng_l2tp_seq_check(struct l2tp_seq *seq)
for ( ; i < seq->cwnd; i++) /* verify peer's recv window full */
CHECK(seq->xwin[i] == NULL);
+ mtx_unlock(&seq->mtx);
+
#undef CHECK
}
#endif /* INVARIANTS */
OpenPOWER on IntegriCloud