summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Kozlov <xeb@mail.ru>2016-03-05 20:48:55 +0300
committerDmitry Kozlov <xeb@mail.ru>2016-03-05 20:48:55 +0300
commit80eab99d6dc0cedfc97be191349a6dde3f326a5a (patch)
tree0d3adc8ca275710bcdfe065b5ac406ae114d2f2b
parent5de6604bc0cd21714a23607ad2b35d567bbe029d (diff)
downloadaccel-ppp-80eab99d6dc0cedfc97be191349a6dde3f326a5a.tar.gz
accel-ppp-80eab99d6dc0cedfc97be191349a6dde3f326a5a.zip
pppoe: fixed race condition
-rw-r--r--accel-pppd/ctrl/pppoe/disc.c35
1 files changed, 24 insertions, 11 deletions
diff --git a/accel-pppd/ctrl/pppoe/disc.c b/accel-pppd/ctrl/pppoe/disc.c
index 5a8fc83a..db969d8f 100644
--- a/accel-pppd/ctrl/pppoe/disc.c
+++ b/accel-pppd/ctrl/pppoe/disc.c
@@ -20,16 +20,16 @@
#include "memdebug.h"
+#define MAX_NET 2
+#define HASH_BITS 0xff
+
struct tree {
pthread_mutex_t lock;
struct rb_root root;
};
-#define HASH_BITS 0xff
-
struct disc_net {
struct triton_context_t ctx;
- struct list_head entry;
struct triton_md_handler_t hnd;
const struct ap_net *net;
struct tree tree[0];
@@ -39,7 +39,9 @@ static uint8_t bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
static mempool_t pkt_pool;
-static LIST_HEAD(nets);
+static struct disc_net *nets[MAX_NET];
+static int net_cnt;
+static pthread_mutex_t nets_lock = PTHREAD_MUTEX_INITIALIZER;
static void disc_close(struct triton_context_t *ctx);
static int disc_read(struct triton_md_handler_t *h);
@@ -52,6 +54,9 @@ static struct disc_net *init_net(const struct ap_net *net)
struct tree *tree;
int sock;
+ if (net_cnt == MAX_NET - 1)
+ return NULL;
+
sock = net->socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PPP_DISC));
if (sock < 0)
return NULL;
@@ -87,20 +92,21 @@ static struct disc_net *init_net(const struct ap_net *net)
triton_context_register(&n->ctx, NULL);
triton_md_register_handler(&n->ctx, &n->hnd);
triton_md_enable_handler(&n->hnd, MD_MODE_READ);
- triton_context_wakeup(&n->ctx);
- list_add_tail(&n->entry, &nets);
+ nets[net_cnt++] = n;
+
+ triton_context_wakeup(&n->ctx);
return n;
}
static struct disc_net *find_net(const struct ap_net *net)
{
- struct disc_net *n;
+ int i;
- list_for_each_entry(n, &nets, entry) {
- if (n->net == net)
- return n;
+ for (i = 0; i < net_cnt; i++) {
+ if (nets[i]->net == net)
+ return nets[i];
}
return NULL;
@@ -115,7 +121,14 @@ int pppoe_disc_start(struct pppoe_serv_t *serv)
struct pppoe_serv_t *n;
if (!net) {
- net = init_net(serv->net);
+ pthread_mutex_lock(&nets_lock);
+
+ net = find_net(serv->net);
+ if (!net)
+ net = init_net(serv->net);
+
+ pthread_mutex_unlock(&nets_lock);
+
if (!net)
return -1;
}