diff options
-rw-r--r-- | accel-dp/if_dp.h | 10 | ||||
-rw-r--r-- | accel-pppd/ctrl/pppoe/disc.c | 62 | ||||
-rw-r--r-- | accel-pppd/ctrl/pppoe/pppoe.c | 2 | ||||
-rw-r--r-- | accel-pppd/net/dp.c | 174 | ||||
-rw-r--r-- | accel-pppd/ppp/ppp.c | 34 |
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; |