summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--accel-dp/if_dp.h10
-rw-r--r--accel-pppd/ctrl/pppoe/disc.c62
-rw-r--r--accel-pppd/ctrl/pppoe/pppoe.c2
-rw-r--r--accel-pppd/net/dp.c174
-rw-r--r--accel-pppd/ppp/ppp.c34
5 files changed, 242 insertions, 40 deletions
diff --git a/accel-dp/if_dp.h b/accel-dp/if_dp.h
index 5c209a79..72a9d724 100644
--- a/accel-dp/if_dp.h
+++ b/accel-dp/if_dp.h
@@ -4,6 +4,7 @@
#include <stdint.h>
enum {
+ MSG_PIPE,
MSG_SOCKET,
MSG_CONNECT,
MSG_BIND,
@@ -22,6 +23,11 @@ struct msg_hdr {
uint8_t id;
};
+struct msg_pipe {
+ uint8_t id;
+ uint8_t pid;
+};
+
struct msg_socket {
uint8_t id;
int domain;
@@ -55,6 +61,7 @@ struct msg_recv {
struct msg_send {
uint8_t id;
+ uint8_t pid;
size_t len;
int flags;
socklen_t addrlen;
@@ -62,7 +69,8 @@ struct msg_send {
struct msg_ioctl {
uint8_t id;
- unsigned long request;
+ uint8_t pid;
+ unsigned int request;
char arg[0];
};
diff --git a/accel-pppd/ctrl/pppoe/disc.c b/accel-pppd/ctrl/pppoe/disc.c
index 58efd1e2..a0a21751 100644
--- a/accel-pppd/ctrl/pppoe/disc.c
+++ b/accel-pppd/ctrl/pppoe/disc.c
@@ -32,6 +32,7 @@ struct disc_net {
struct triton_context_t ctx;
struct triton_md_handler_t hnd;
const struct ap_net *net;
+ int refs;
struct tree tree[0];
};
@@ -76,7 +77,7 @@ static struct disc_net *init_net(const struct ap_net *net)
fcntl(sock, F_SETFD, FD_CLOEXEC);
net->set_nonblocking(sock, 1);
- n = malloc(sizeof(*net) + (HASH_BITS + 1) * sizeof(struct tree));
+ n = _malloc(sizeof(*net) + (HASH_BITS + 1) * sizeof(struct tree));
tree = n->tree;
for (i = 0; i <= HASH_BITS; i++) {
@@ -89,6 +90,7 @@ static struct disc_net *init_net(const struct ap_net *net)
n->hnd.fd = sock;
n->hnd.read = disc_read;
n->net = net;
+ n->refs = 1;
triton_context_register(&n->ctx, NULL);
triton_md_register_handler(&n->ctx, &n->hnd);
@@ -101,6 +103,24 @@ static struct disc_net *init_net(const struct ap_net *net)
return n;
}
+static void free_net(struct disc_net *net)
+{
+ int i;
+
+ pthread_mutex_lock(&nets_lock);
+ for (i = 0; i < MAX_NET; i++) {
+ if (nets[i] == net) {
+ memcpy(nets + i, nets + i + 1, net_cnt - i - 1);
+ net_cnt--;
+ break;
+ }
+ }
+ pthread_mutex_unlock(&nets_lock);
+
+ _free(net);
+}
+
+
static struct disc_net *find_net(const struct ap_net *net)
{
int i;
@@ -134,6 +154,9 @@ int pppoe_disc_start(struct pppoe_serv_t *serv)
return -1;
}
+ if (net->hnd.fd == -1)
+ return -1;
+
t = &net->tree[ifindex & HASH_BITS];
pthread_mutex_lock(&t->lock);
@@ -159,6 +182,8 @@ int pppoe_disc_start(struct pppoe_serv_t *serv)
rb_link_node(&serv->node, parent, p);
rb_insert_color(&serv->node, &t->root);
+ __sync_add_and_fetch(&net->refs, 1);
+
pthread_mutex_unlock(&t->lock);
return net->hnd.fd;
@@ -172,6 +197,9 @@ void pppoe_disc_stop(struct pppoe_serv_t *serv)
pthread_mutex_lock(&t->lock);
rb_erase(&serv->node, &t->root);
pthread_mutex_unlock(&t->lock);
+
+ if (__sync_sub_and_fetch(&n->refs, 1) == 0)
+ free_net(n);
}
static int forward(struct disc_net *net, int ifindex, void *pkt, int len)
@@ -232,6 +260,31 @@ static void notify_down(struct disc_net *net, int ifindex)
pthread_mutex_unlock(&t->lock);
}
+static void disc_stop(struct disc_net *net)
+{
+ struct pppoe_serv_t *s;
+ struct rb_node *n;
+ int i;
+
+ triton_md_unregister_handler(&net->hnd, 1);
+ triton_context_unregister(&net->ctx);
+
+ for (i = 0; i <= HASH_BITS; i++) {
+ struct tree *t = &net->tree[i];
+
+ pthread_mutex_lock(&t->lock);
+ for (n = rb_first(&t->root); n; n = rb_next(n)) {
+ s = rb_entry(n, typeof(*s), node);
+ triton_context_call(&s->ctx, (triton_event_func)_server_stop, s);
+ }
+ pthread_mutex_unlock(&t->lock);
+ }
+
+ if (__sync_sub_and_fetch(&net->refs, 1) == 0)
+ free_net(net);
+}
+
+
static int disc_read(struct triton_md_handler_t *h)
{
struct disc_net *net = container_of(h, typeof(*net), hnd);
@@ -252,12 +305,17 @@ static int disc_read(struct triton_md_handler_t *h)
if (errno == EAGAIN)
break;
+ log_error("pppoe: disc: read: %s\n", strerror(errno));
+
if (errno == ENETDOWN) {
notify_down(net, src.sll_ifindex);
continue;
}
- log_error("pppoe: disc: read: %s\n", strerror(errno));
+ if (errno == EBADE) {
+ disc_stop(net);
+ return 1;
+ }
continue;
}
diff --git a/accel-pppd/ctrl/pppoe/pppoe.c b/accel-pppd/ctrl/pppoe/pppoe.c
index 8a216baa..242f7e07 100644
--- a/accel-pppd/ctrl/pppoe/pppoe.c
+++ b/accel-pppd/ctrl/pppoe/pppoe.c
@@ -427,7 +427,7 @@ static void connect_channel(struct pppoe_conn_t *conn)
triton_event_fire(EV_CTRL_STARTED, &conn->ppp.ses);
sock = net->socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OE);
- if (!sock) {
+ if (sock < 0) {
log_error("pppoe: socket(PPPOX): %s\n", strerror(errno));
goto out_err;
}
diff --git a/accel-pppd/net/dp.c b/accel-pppd/net/dp.c
index 018c7c75..be5ebc0f 100644
--- a/accel-pppd/net/dp.c
+++ b/accel-pppd/net/dp.c
@@ -1,5 +1,8 @@
#include <unistd.h>
+#include <stdlib.h>
#include <errno.h>
+#include <pthread.h>
+#include <sched.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/ioctl.h>
@@ -13,9 +16,102 @@
#include "if_dp.h"
+#define MAX_PIPE 16
+
+struct dp_pipe {
+ struct list_head entry;
+ int sock;
+ uint8_t pid;
+};
+
static struct sockaddr_un dp_addr;
static int dp_sock;
+static LIST_HEAD(pipes);
+static pthread_mutex_t pipe_lock;
+static int pipe_cnt;
+
+static int pipe_open(uint8_t pid)
+{
+ struct msg_pipe msg = {
+ .id = MSG_PIPE,
+ .pid = pid,
+ };
+ struct msg_result res;
+ int sock = socket(AF_UNIX, SOCK_SEQPACKET, 0);
+ if (sock < 0) {
+ log_error("dp: socket: %s\n", strerror(errno));
+ return -1;
+ }
+
+ if (connect(sock, (struct sockaddr *)&dp_addr, sizeof(dp_addr))) {
+ log_error("dp: connect: %s\n", strerror(errno));
+ close(sock);
+ return -1;
+ }
+
+ if (write(sock, &msg, sizeof(msg)) < 0) {
+ close(sock);
+ return -1;
+ }
+
+ if (read(sock, &res, sizeof(res)) != sizeof(res)) {
+ close(sock);
+ return -1;
+ }
+
+ if (res.err) {
+ log_error("dp: failed to connect pipe: %s\n", strerror(res.err));
+ close(sock);
+ return -1;
+ }
+
+ return sock;
+}
+
+static struct dp_pipe *pipe_get()
+{
+ struct dp_pipe *p;
+ uint8_t pid;
+ int sock;
+
+ while (1) {
+ pthread_mutex_lock(&pipe_lock);
+ if (list_empty(&pipes)) {
+ if (pipe_cnt == MAX_PIPE) {
+ pthread_mutex_unlock(&pipe_lock);
+ sched_yield();
+ }
+ pid = pipe_cnt;
+ pipe_cnt++;
+ pthread_mutex_unlock(&pipe_lock);
+
+ sock = pipe_open(pid);
+ if (sock < 0)
+ return NULL;
+
+ p = malloc(sizeof(*p));
+ p->pid = pid;
+ p->sock = sock;
+ break;
+ } else {
+ p = list_entry(pipes.next, typeof(*p), entry);
+ list_del(&p->entry);
+ pthread_mutex_unlock(&pipe_lock);
+ break;
+ }
+ }
+
+ return p;
+}
+
+static void pipe_put(struct dp_pipe *p)
+{
+ pthread_mutex_lock(&pipe_lock);
+ list_add(&p->entry, &pipes);
+ pthread_mutex_unlock(&pipe_lock);
+}
+
static int dp_socket(int domain, int type, int proto)
{
struct msg_socket msg = {
@@ -270,11 +366,24 @@ static ssize_t dp_write(int sock, const void *buf, size_t len)
.iov_len = len,
}
};
+ struct dp_pipe *p = pipe_get();
+ int r;
- if (writev(sock, iov, 2) < 0)
+ if (!p)
return -1;
- if (read(sock, &res, sizeof(res)) != sizeof(res)) {
+ msg.pid = p->pid;
+
+ if (writev(sock, iov, 2) < 0) {
+ pipe_put(p);
+ return -1;
+ }
+
+ r = read(p->sock, &res, sizeof(res));
+
+ pipe_put(p);
+
+ if (r != sizeof(res)) {
errno = EBADE;
return -1;
}
@@ -310,11 +419,24 @@ static ssize_t dp_sendto(int sock, const void *buf, size_t len, int flags, const
.iov_len = len,
}
};
+ struct dp_pipe *p = pipe_get();
+ int r;
- if (writev(sock, iov, 3) < 0)
+ if (!p)
return -1;
- if (read(sock, &res, sizeof(res)) != sizeof(res)) {
+ msg.pid = p->pid;
+
+ if (writev(sock, iov, 3) < 0) {
+ pipe_put(p);
+ return -1;
+ }
+
+ r = read(p->sock, &res, sizeof(res));
+
+ pipe_put(p);
+
+ if (r != sizeof(res)) {
errno = EBADE;
return -1;
}
@@ -340,9 +462,11 @@ static int dp_setsockopt(int sock, int level, int optname, const void *optval, s
static int dp_ppp_open()
{
- int id = MSG_PPP_OPEN;
+ struct msg_hdr msg = {
+ .id = MSG_PPP_OPEN,
+ };
struct msg_result res;
- int sock = socket(AF_UNIX, SOCK_STREAM, 0);
+ int sock = socket(AF_UNIX, SOCK_SEQPACKET, 0);
if (sock < 0)
return -1;
@@ -352,7 +476,7 @@ static int dp_ppp_open()
return -1;
}
- if (write(sock, &id, sizeof(id)) < 0) {
+ if (write(sock, &msg, sizeof(msg)) < 0) {
close(sock);
return -1;
}
@@ -388,6 +512,11 @@ static int dp_ppp_ioctl(int fd, unsigned long request, void *arg)
.iov_base = arg,
}
};
+ struct dp_pipe *p = pipe_get();
+ int r;
+
+ if (!p)
+ return -1;
switch (request) {
case PPPIOCSNPMODE:
@@ -398,9 +527,9 @@ static int dp_ppp_ioctl(int fd, unsigned long request, void *arg)
break;
case PPPIOCGFLAGS:
case PPPIOCGCHAN:
- case PPPIOCNEWUNIT:
iov[1].iov_len = 0;
break;
+ case PPPIOCNEWUNIT:
case PPPIOCSFLAGS:
case PPPIOCSMRU:
case PPPIOCATTCHAN:
@@ -410,15 +539,23 @@ static int dp_ppp_ioctl(int fd, unsigned long request, void *arg)
}
- if (writev(fd, iov, iov[1].iov_len ? 2 : 1) < 0)
+ msg.pid = p->pid;
+
+ if (writev(fd, iov, 2) < 0) {
+ pipe_put(p);
return -1;
+ }
iov[0].iov_base = &res;
iov[0].iov_len = sizeof(res);
iov[1].iov_base = arg;
iov[1].iov_len = 1024;
- if (readv(fd, iov, 2) < sizeof(res)) {
+ r = readv(p->sock, iov, 2);
+
+ pipe_put(p);
+
+ if (r < sizeof(res)) {
errno = EBADE;
return -1;
}
@@ -448,14 +585,27 @@ static int dp_sock_ioctl(unsigned long request, void *arg)
.iov_len = sizeof(struct ifreq),
}
};
+ struct dp_pipe *p = pipe_get();
+ int r;
+
+ if (!p)
+ return -1;
+
+ msg.pid = p->pid;
- if (writev(dp_sock, iov, 2) < 0)
+ if (writev(dp_sock, iov, 2) < 0) {
+ pipe_put(p);
return -1;
+ }
iov[0].iov_base = &res;
iov[0].iov_len = sizeof(res);
- if (readv(dp_sock, iov, 2) < sizeof(res)) {
+ r = readv(p->sock, iov, 2);
+
+ pipe_put(p);
+
+ if (r < sizeof(res)) {
errno = EBADE;
return -1;
}
diff --git a/accel-pppd/ppp/ppp.c b/accel-pppd/ppp/ppp.c
index ab67aa21..f05b47bb 100644
--- a/accel-pppd/ppp/ppp.c
+++ b/accel-pppd/ppp/ppp.c
@@ -93,11 +93,8 @@ int __export establish_ppp(struct ppp_t *ppp)
}
fcntl(ppp->chan_fd, F_SETFD, fcntl(ppp->chan_fd, F_GETFD) | FD_CLOEXEC);
- if (fcntl(ppp->chan_fd, F_SETFL, O_NONBLOCK)) {
- log_ppp_error("ppp: cannot set nonblocking mode: %s\n",
- strerror(errno));
- goto exit_close_chan;
- }
+
+ net->set_nonblocking(ppp->chan_fd, 1);
if (net->ppp_ioctl(ppp->chan_fd, PPPIOCATTCHAN, &ppp->chan_idx) < 0) {
log_ppp_error("ioctl(PPPIOCATTCHAN): %s\n", strerror(errno));
@@ -357,18 +354,14 @@ static int ppp_chan_read(struct triton_md_handler_t *h)
cont:
ppp->buf_size = net->read(h->fd, ppp->buf, PPP_BUF_SIZE);
if (ppp->buf_size < 0) {
- if (errno != EAGAIN)
+ if (errno != EAGAIN) {
log_ppp_error("ppp_chan_read: %s\n", strerror(errno));
+ ap_session_terminate(&ppp->ses, TERM_NAS_ERROR, 1);
+ return 1;
+ }
break;
}
- //printf("ppp_chan_read: ");
- //print_buf(ppp->buf,ppp->buf_size);
- if (ppp->buf_size == 0) {
- ap_session_terminate(&ppp->ses, TERM_NAS_ERROR, 1);
- return 1;
- }
-
if (ppp->buf_size < 2) {
log_ppp_error("ppp_chan_read: short read %i\n", ppp->buf_size);
continue;
@@ -409,21 +402,14 @@ static int ppp_unit_read(struct triton_md_handler_t *h)
cont:
ppp->buf_size = net->read(h->fd, ppp->buf, PPP_BUF_SIZE);
if (ppp->buf_size < 0) {
- if (errno != EAGAIN)
+ if (errno != EAGAIN) {
log_ppp_error("ppp_unit_read: %s\n",strerror(errno));
+ ap_session_terminate(&ppp->ses, TERM_NAS_ERROR, 1);
+ return 1;
+ }
break;
}
- //printf("ppp_unit_read: %i\n", ppp->buf_size);
- if (ppp->buf_size == 0)
- return 0;
- //print_buf(ppp->buf,ppp->buf_size);
-
- /*if (ppp->buf_size == 0) {
- ap_session_terminate(ppp, TERM_NAS_ERROR, 1);
- return 1;
- }*/
-
if (ppp->buf_size < 2) {
log_ppp_error("ppp_unit_read: short read %i\n", ppp->buf_size);
continue;