summaryrefslogtreecommitdiff
path: root/accel-pppd/net
diff options
context:
space:
mode:
Diffstat (limited to 'accel-pppd/net')
-rw-r--r--accel-pppd/net/dp.c174
1 files changed, 162 insertions, 12 deletions
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;
}