summaryrefslogtreecommitdiff
path: root/accel-pppd
diff options
context:
space:
mode:
authorKozlov Dmitry <xeb@mail.ru>2012-06-22 18:11:19 +0400
committerKozlov Dmitry <xeb@mail.ru>2012-06-22 18:11:19 +0400
commit4080b4e1ffdb1482ab26557eb46a8121d93ac584 (patch)
tree0732197c98f911a18c024f7b91ec1031de34e10b /accel-pppd
parentb57c6b9e838fa7fa39e81164912d518b43de3723 (diff)
downloadaccel-ppp-4080b4e1ffdb1482ab26557eb46a8121d93ac584.tar.gz
accel-ppp-4080b4e1ffdb1482ab26557eb46a8121d93ac584.zip
initial ipoe implementation
Diffstat (limited to 'accel-pppd')
-rw-r--r--accel-pppd/CMakeLists.txt3
-rw-r--r--accel-pppd/ctrl/CMakeLists.txt1
-rw-r--r--accel-pppd/ctrl/ipoe/CMakeLists.txt24
-rw-r--r--accel-pppd/ctrl/ipoe/dhcpv4.c538
-rw-r--r--accel-pppd/ctrl/ipoe/dhcpv4.h89
-rw-r--r--accel-pppd/ctrl/ipoe/dhcpv4_options.c290
-rw-r--r--accel-pppd/ctrl/ipoe/ipoe.c688
-rw-r--r--accel-pppd/ctrl/ipoe/ipoe.h54
-rw-r--r--accel-pppd/ctrl/ipoe/lua.c253
-rw-r--r--accel-pppd/ctrl/ipoe/lua_lpack.c271
-rw-r--r--accel-pppd/ctrl/l2tp/l2tp.c4
-rw-r--r--accel-pppd/ctrl/pppoe/pppoe.c6
-rw-r--r--accel-pppd/ctrl/pptp/pptp.c6
-rw-r--r--accel-pppd/extra/pppd_compat.c32
-rw-r--r--accel-pppd/ifcfg.c49
-rw-r--r--accel-pppd/include/ap_session.h2
l---------accel-pppd/include/iplink.h1
l---------accel-pppd/include/libnetlink.h1
-rw-r--r--accel-pppd/ipdb.h1
-rw-r--r--accel-pppd/libnetlink/iplink.c77
-rw-r--r--accel-pppd/libnetlink/iplink.h8
-rw-r--r--accel-pppd/libnetlink/libnetlink.c (renamed from accel-pppd/shaper/libnetlink.c)44
-rw-r--r--accel-pppd/libnetlink/libnetlink.h (renamed from accel-pppd/shaper/libnetlink.h)0
-rw-r--r--accel-pppd/radius/auth.c28
-rw-r--r--accel-pppd/radius/radius.c4
-rw-r--r--accel-pppd/radius/radius_p.h1
-rw-r--r--accel-pppd/radius/req.c21
-rw-r--r--accel-pppd/shaper/CMakeLists.txt2
28 files changed, 2436 insertions, 62 deletions
diff --git a/accel-pppd/CMakeLists.txt b/accel-pppd/CMakeLists.txt
index a65f7fef..787dbd8c 100644
--- a/accel-pppd/CMakeLists.txt
+++ b/accel-pppd/CMakeLists.txt
@@ -66,6 +66,9 @@ ADD_EXECUTABLE(accel-pppd
cli/telnet.c
cli/tcp.c
cli/cli.c
+
+ libnetlink/libnetlink.c
+ libnetlink/iplink.c
pwdb.c
ipdb.c
diff --git a/accel-pppd/ctrl/CMakeLists.txt b/accel-pppd/ctrl/CMakeLists.txt
index 6b37bc4a..9b6a11d6 100644
--- a/accel-pppd/ctrl/CMakeLists.txt
+++ b/accel-pppd/ctrl/CMakeLists.txt
@@ -1,3 +1,4 @@
ADD_SUBDIRECTORY(pptp)
ADD_SUBDIRECTORY(pppoe)
ADD_SUBDIRECTORY(l2tp)
+ADD_SUBDIRECTORY(ipoe)
diff --git a/accel-pppd/ctrl/ipoe/CMakeLists.txt b/accel-pppd/ctrl/ipoe/CMakeLists.txt
new file mode 100644
index 00000000..e2b71cbc
--- /dev/null
+++ b/accel-pppd/ctrl/ipoe/CMakeLists.txt
@@ -0,0 +1,24 @@
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
+
+SET(sources
+ ipoe.c
+ dhcpv4.c
+ dhcpv4_options.c
+)
+
+IF (LUA)
+ include(FindLua51)
+ IF (NOT LUA51_FOUND)
+ MESSAGE(FATAL_ERROR "lua not found")
+ ENDIF (NOT LUA51_FOUND)
+ INCLUDE_DIRECTORIES(${LUA_INCLUDE_DIR})
+ ADD_DEFINITIONS(-DUSE_LUA)
+ SET(sources ${sources} lua.c lua_lpack.c)
+ENDIF (LUA)
+
+ADD_LIBRARY(ipoe SHARED ${sources})
+IF (LUA)
+ TARGET_LINK_LIBRARIES(ipoe ${LUA_LIBRARIES})
+ENDIF(LUA)
+
+INSTALL(TARGETS ipoe LIBRARY DESTINATION lib/accel-ppp)
diff --git a/accel-pppd/ctrl/ipoe/dhcpv4.c b/accel-pppd/ctrl/ipoe/dhcpv4.c
new file mode 100644
index 00000000..2955d6cd
--- /dev/null
+++ b/accel-pppd/ctrl/ipoe/dhcpv4.c
@@ -0,0 +1,538 @@
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <net/ethernet.h>
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+#include <netpacket/packet.h>
+#include <arpa/inet.h>
+#include <linux/if.h>
+
+#include "events.h"
+#include "list.h"
+#include "triton.h"
+#include "log.h"
+#include "mempool.h"
+#include "memdebug.h"
+#include "ap_session.h"
+#include "ipdb.h"
+
+#include "dhcpv4.h"
+
+#define DHCP_SERV_PORT 67
+#define DHCP_CLIENT_PORT 68
+#define DHCP_MAGIC "\x63\x82\x53\x63"
+
+
+#define BUF_SIZE 4096
+
+
+static int conf_verbose;
+
+static mempool_t pack_pool;
+static mempool_t opt_pool;
+
+static int dhcpv4_read(struct triton_md_handler_t *h);
+
+struct dhcpv4_serv *dhcpv4_create(struct triton_context_t *ctx, const char *ifname)
+{
+ struct dhcpv4_serv *serv;
+ int sock, raw_sock;
+ struct sockaddr_in addr;
+ struct sockaddr_ll ll_addr;
+ struct ifreq ifr;
+ int f = 1;
+
+ memset(&ifr, 0, sizeof(ifr));
+
+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(sock_fd, SIOCGIFINDEX, &ifr)) {
+ log_error("dhcpv4(%s): ioctl(SIOCGIFINDEX): %s\n", ifname, strerror(errno));
+ return NULL;
+ }
+
+ raw_sock = socket(AF_PACKET, SOCK_RAW, ntohs(ETH_P_IP));
+ if (raw_sock < 0) {
+ log_error("dhcpv4: packet socket is not supported by kernel\n");
+ return NULL;
+ }
+
+ memset(&ll_addr, 0, sizeof(ll_addr));
+ ll_addr.sll_family = AF_PACKET;
+ ll_addr.sll_ifindex = ifr.ifr_ifindex;
+ ll_addr.sll_protocol = ntohs(ETH_P_IP);
+
+ if (bind(raw_sock, (struct sockaddr *)&ll_addr, sizeof(ll_addr))) {
+ log_error("dhcpv4(%s): bind: %s\n", ifname, strerror(errno));
+ close(raw_sock);
+ return NULL;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(DHCP_SERV_PORT);
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+
+ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &f, sizeof(f)))
+ log_error("setsockopt(SO_REUSEADDR): %s\n", strerror(errno));
+
+
+ if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &f, sizeof(f))) {
+ log_error("setsockopt(SO_BROADCAST): %s\n", strerror(errno));
+ goto out_err;
+ }
+
+ if (bind(sock, &addr, sizeof(addr))) {
+ log_error("bind: %s\n", strerror(errno));
+ goto out_err;
+ }
+
+ if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname))) {
+ log_error("setsockopt(SO_BINDTODEVICE): %s\n", strerror(errno));
+ goto out_err;
+ }
+
+ if (ioctl(sock, SIOCGIFHWADDR, &ifr)) {
+ log_error("dhcpv4(%s): ioctl(SIOCGIFHWADDR): %s\n", ifname, strerror(errno));
+ goto out_err;
+ }
+
+ memcpy(serv->hwaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+
+ fcntl(raw_sock, F_SETFL, O_NONBLOCK);
+ fcntl(raw_sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC);
+
+ fcntl(sock, F_SETFL, O_NONBLOCK);
+ fcntl(sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC);
+
+ serv = _malloc(sizeof(*serv));
+ memset(serv, 0, sizeof(*serv));
+
+ serv->ctx = ctx;
+ serv->hnd.fd = sock;
+ serv->hnd.read = dhcpv4_read;
+ serv->raw_sock = raw_sock;
+
+ triton_md_register_handler(ctx, &serv->hnd);
+ triton_md_enable_handler(&serv->hnd, MD_MODE_READ);
+
+ return serv;
+
+out_err:
+ close(raw_sock);
+ close(sock);
+ return NULL;
+}
+
+void dhcpv4_free(struct dhcpv4_serv *serv)
+{
+ triton_md_unregister_handler(&serv->hnd);
+ close(serv->hnd.fd);
+ _free(serv);
+}
+
+void dhcpv4_print_packet(struct dhcpv4_packet *pack, void (*print)(const char *fmt, ...))
+{
+ const char *msg_name[] = {"Discover", "Offer", "Request", "Decline", "Ack", "Nak", "Release", "Inform"};
+
+ print("[DHCPv4 %s xid=%x ", msg_name[pack->msg_type - 1], pack->hdr->xid);
+
+ if (pack->hdr->ciaddr)
+ print("ciaddr=%i.%i.%i.%i ",
+ pack->hdr->ciaddr & 0xff,
+ (pack->hdr->ciaddr >> 8) & 0xff,
+ (pack->hdr->ciaddr >> 16) & 0xff,
+ (pack->hdr->ciaddr >> 24) & 0xff);
+
+ if (pack->hdr->yiaddr)
+ print("yiaddr=%i.%i.%i.%i ",
+ pack->hdr->yiaddr & 0xff,
+ (pack->hdr->yiaddr >> 8) & 0xff,
+ (pack->hdr->yiaddr >> 16) & 0xff,
+ (pack->hdr->yiaddr >> 24) & 0xff);
+
+ if (pack->hdr->siaddr)
+ print("ciaddr=%i.%i.%i.%i ",
+ pack->hdr->siaddr & 0xff,
+ (pack->hdr->siaddr >> 8) & 0xff,
+ (pack->hdr->siaddr >> 16) & 0xff,
+ (pack->hdr->siaddr >> 24) & 0xff);
+
+ if (pack->hdr->giaddr)
+ print("giaddr=%i.%i.%i.%i ",
+ pack->hdr->giaddr & 0xff,
+ (pack->hdr->giaddr >> 8) & 0xff,
+ (pack->hdr->giaddr >> 16) & 0xff,
+ (pack->hdr->giaddr >> 24) & 0xff);
+
+ print("chaddr=%02x:%02x:%02x:%02x:%02x:%02x ",
+ pack->hdr->chaddr[0],
+ pack->hdr->chaddr[1],
+ pack->hdr->chaddr[2],
+ pack->hdr->chaddr[3],
+ pack->hdr->chaddr[4],
+ pack->hdr->chaddr[5],
+ pack->hdr->chaddr[6]);
+
+ dhcpv4_print_options(pack, print);
+
+ print("]\n");
+}
+
+static int parse_opt82(struct dhcpv4_packet *pack, struct dhcpv4_option *opt)
+{
+ uint8_t *ptr = opt->data;
+ uint8_t *endptr = ptr + opt->len;
+ int type, len;
+ struct dhcpv4_option *opt1;
+
+ while (ptr < endptr) {
+ type = *ptr++;
+ len = *ptr++;
+ if (ptr + len > endptr)
+ return -1;
+ if (type == 1 || type == 2) {
+ opt1 = mempool_alloc(opt_pool);
+ if (!opt1) {
+ log_emerg("out of memory\n");
+ return -1;
+ }
+
+ opt1->type = type;
+ opt1->len = len;
+ opt1->data = ptr;
+
+ if (type == 1)
+ pack->agent_circuit_id = opt1;
+ else
+ pack->agent_remote_id = opt1;
+ }
+
+ ptr += len;
+ }
+
+ return 0;
+}
+
+static int dhcpv4_parse_packet(struct dhcpv4_packet *pack, int len)
+{
+ struct dhcpv4_option *opt;
+ uint8_t *ptr, *endptr = pack->data + len;
+
+ if (len < sizeof(struct dhcpv4_hdr)) {
+ if (conf_verbose)
+ log_warn("dhcpv4: short packet received\n");
+ return -1;
+ }
+
+ if (pack->hdr->op != DHCP_OP_REQUEST)
+ return -1;
+
+ if (pack->hdr->htype != 1)
+ return -1;
+
+ if (pack->hdr->hlen != 6)
+ return -1;
+
+ if (memcmp(pack->hdr->magic, DHCP_MAGIC, 4))
+ return -1;
+
+ ptr = pack->data + sizeof(struct dhcpv4_hdr);
+
+ while (ptr < endptr) {
+ if (*ptr == 0) {
+ ptr++;
+ continue;
+ }
+
+ if (*ptr == 0xff)
+ break;
+
+ opt = mempool_alloc(opt_pool);
+ if (!opt) {
+ log_emerg("out of memory\n");
+ return -1;
+ }
+ memset(opt, 0, sizeof(*opt));
+ opt->type = *ptr++;
+ opt->len = *ptr++;
+ opt->data = ptr;
+ ptr += opt->len;
+
+ if (ptr > endptr)
+ return -1;
+
+ list_add_tail(&opt->entry, &pack->options);
+
+ if (opt->type == 53)
+ pack->msg_type = opt->data[0];
+ else if (opt->type == 82)
+ parse_opt82(pack, opt);
+ else if (opt->type == 50)
+ pack->request_ip = *(uint32_t *)opt->data;
+ else if (opt->type == 54)
+ pack->server_id = *(uint32_t *)opt->data;
+ }
+
+ if (pack->msg_type == 0 || pack->msg_type > 8)
+ return -1;
+
+ if (dhcpv4_check_options(pack))
+ return -1;
+
+ /*if (conf_verbose) {
+ log_info2("recv ");
+ print_packet(pack, log_info2);
+ }*/
+
+ return 0;
+}
+
+static struct dhcpv4_packet *dhcpv4_packet_alloc()
+{
+ struct dhcpv4_packet *pack = mempool_alloc(pack_pool);
+
+ if (!pack)
+ return NULL;
+
+ memset(pack, 0, sizeof(*pack));
+
+ INIT_LIST_HEAD(&pack->options);
+
+ pack->hdr = (struct dhcpv4_hdr *)pack->data;
+ pack->ptr = (uint8_t *)(pack->hdr + 1);
+
+ memcpy(pack->hdr->magic, DHCP_MAGIC, 4);
+
+ return pack;
+}
+
+static int dhcpv4_read(struct triton_md_handler_t *h)
+{
+ struct dhcpv4_packet *pack;
+ struct dhcpv4_serv *serv = container_of(h, typeof(*serv), hnd);
+ struct sockaddr_in addr;
+ socklen_t len;
+ int n;
+
+ while (1) {
+ pack = dhcpv4_packet_alloc();
+ if (!pack) {
+ log_emerg("out of memory\n");
+ return 1;
+ }
+
+ len = sizeof(addr);
+ n = recvfrom(h->fd, pack->data, BUF_SIZE, 0, &addr, &len);
+ if (n == -1) {
+ mempool_free(pack);
+ if (errno == EAGAIN)
+ return 0;
+ log_error("dhcpv4: recv: %s\n", strerror(errno));
+ continue;
+ }
+
+ if (dhcpv4_parse_packet(pack, n)) {
+ dhcpv4_packet_free(pack);
+ continue;
+ }
+
+ if (serv->recv)
+ serv->recv(serv, pack);
+ }
+}
+
+uint16_t ip_csum(uint16_t *buf, int len)
+{
+ uint32_t sum=0;
+ int i;
+
+ for (i=0; i < len; i += 2)
+ sum += *buf++;
+
+ // take only 16 bits out of the 32 bit sum and add up the carries
+ while (sum >> 16)
+ sum = (sum & 0xffff) + (sum >> 16);
+
+ // one's complement the result
+ sum = ~sum;
+
+ return sum & 0xffff;
+}
+
+
+static int dhcpv4_send(struct dhcpv4_serv *serv, struct dhcpv4_packet *pack, in_addr_t saddr, in_addr_t daddr)
+{
+ uint8_t hdr[sizeof(struct ether_header) + sizeof(struct iphdr) + sizeof(struct udphdr)];
+ struct ether_header *eth = (struct ether_header *)hdr;
+ struct iphdr *ip = (struct iphdr *)(eth + 1);
+ struct udphdr *udp = (struct udphdr *)(ip + 1);
+ int len = pack->ptr - pack->data;
+ struct iovec iov[2];
+
+ memcpy(eth->ether_dhost, pack->hdr->chaddr, ETH_ALEN);
+ memcpy(eth->ether_shost, serv->hwaddr, ETH_ALEN);
+ eth->ether_type = htons(ETH_P_IP);
+
+ ip->ihl = 5;
+ ip->version = 4;
+ ip->tos = 0x10;
+ ip->tot_len = ntohs(sizeof(*ip) + sizeof(*udp) + len);
+ ip->id = 0;
+ ip->frag_off = 0;
+ ip->ttl = 128;
+ ip->protocol = IPPROTO_UDP;
+ ip->check = 0;
+ ip->saddr = saddr;
+ ip->daddr = daddr;
+ ip->check = ip_csum((uint16_t *)ip, 20);
+
+ udp->source = ntohs(DHCP_SERV_PORT);
+ udp->dest = ntohs(DHCP_CLIENT_PORT);
+ udp->len = htons(sizeof(*udp) + len);
+ udp->check = 0;
+
+ iov[0].iov_base = hdr;
+ iov[0].iov_len = sizeof(hdr);
+ iov[1].iov_base = pack->data;
+ iov[1].iov_len = len;
+
+ len = writev(serv->raw_sock, iov, 2);
+
+ if (len < 0)
+ return -1;
+
+ return 0;
+}
+
+void dhcpv4_packet_free(struct dhcpv4_packet *pack)
+{
+ struct dhcpv4_option *opt;
+
+ while (!list_empty(&pack->options)) {
+ opt = list_entry(pack->options.next, typeof(*opt), entry);
+ list_del(&opt->entry);
+ mempool_free(opt);
+ }
+
+ if (pack->agent_circuit_id)
+ mempool_free(pack->agent_circuit_id);
+
+ if (pack->agent_remote_id)
+ mempool_free(pack->agent_remote_id);
+
+ mempool_free(pack);
+}
+
+int dhcpv4_packet_add_opt(struct dhcpv4_packet *pack, int type, const void *data, int len)
+{
+ struct dhcpv4_option *opt = mempool_alloc(opt_pool);
+
+ if (!opt) {
+ log_emerg("out of memory\n");
+ return -1;
+ }
+
+ *pack->ptr++ = type;
+ *pack->ptr++ = len;
+
+ opt->type = type;
+ opt->len = len;
+ opt->data = pack->ptr;
+ pack->ptr += len;
+
+ memcpy(opt->data, data, len);
+
+ list_add_tail(&opt->entry, &pack->options);
+
+ return 0;
+}
+
+int dhcpv4_send_reply(int msg_type, struct dhcpv4_serv *serv, struct dhcpv4_packet *req, struct ap_session *ses, int lease_time)
+{
+ struct dhcpv4_packet *pack;
+ int val, r;
+
+ pack = dhcpv4_packet_alloc();
+ if (!pack) {
+ log_emerg("out of memory\n");
+ return -1;
+ }
+
+ memcpy(pack->hdr, req->hdr, sizeof(*req->hdr));
+
+ pack->hdr->op = DHCP_OP_REPLY;
+ pack->hdr->yiaddr = ses->ipv4->peer_addr;
+ pack->hdr->siaddr = ses->ipv4->addr;
+
+ if (dhcpv4_packet_add_opt(pack, 53, &msg_type, 1))
+ goto out_err;
+
+ if (dhcpv4_packet_add_opt(pack, 54, &ses->ipv4->addr, 4))
+ goto out_err;
+
+ val = ntohl(lease_time);
+ if (dhcpv4_packet_add_opt(pack, 51, &val, 4))
+ goto out_err;
+
+ if (dhcpv4_packet_add_opt(pack, 3, &ses->ipv4->addr, 4))
+ goto out_err;
+
+ val = htonl(~((1 << (32 - ses->ipv4->mask)) - 1));
+ if (dhcpv4_packet_add_opt(pack, 1, &val, 4))
+ goto out_err;
+
+ *pack->ptr++ = 255;
+
+ if (conf_verbose) {
+ pack->msg_type = msg_type;
+ log_ppp_info2("send ");
+ dhcpv4_print_packet(pack, log_ppp_info2);
+ }
+
+ r = dhcpv4_send(serv, pack, ses->ipv4->addr, ses->ipv4->peer_addr);
+
+ dhcpv4_packet_free(pack);
+
+ return r;
+
+out_err:
+ dhcpv4_packet_free(pack);
+ return -1;
+}
+
+int dhcpv4_send_nak(struct dhcpv4_serv *serv, struct dhcpv4_packet *req)
+{
+
+ return 0;
+}
+
+static void load_config()
+{
+ const char *opt;
+
+ opt = conf_get_opt("ipoe", "verbose");
+ if (opt)
+ conf_verbose = atoi(opt);
+}
+
+static void init()
+{
+ pack_pool = mempool_create(BUF_SIZE + sizeof(struct dhcpv4_packet));
+ opt_pool = mempool_create(sizeof(struct dhcpv4_option));
+
+ load_config();
+
+ triton_event_register_handler(EV_CONFIG_RELOAD, (triton_event_func)load_config);
+}
+
+DEFINE_INIT(100, init);
diff --git a/accel-pppd/ctrl/ipoe/dhcpv4.h b/accel-pppd/ctrl/ipoe/dhcpv4.h
new file mode 100644
index 00000000..52e90a3e
--- /dev/null
+++ b/accel-pppd/ctrl/ipoe/dhcpv4.h
@@ -0,0 +1,89 @@
+#ifndef __DHCPV4_H
+#define __DHCPV4_H
+
+#include <stdint.h>
+#include "list.h"
+
+#include "triton.h"
+
+#define __packed __attribute__((packed))
+
+#define DHCP_OP_REQUEST 1
+#define DHCP_OP_REPLY 2
+
+#define DHCPDISCOVER 1
+#define DHCPOFFER 2
+#define DHCPREQUEST 3
+#define DHCPDECLINE 4
+#define DHCPACK 5
+#define DHCPNAK 6
+#define DHCPRELEASE 7
+#define DHCPINFORM 8
+
+struct dhcpv4_hdr
+{
+ uint8_t op;
+ uint8_t htype;
+ uint8_t hlen;
+ uint8_t hops;
+ uint32_t xid;
+ uint16_t sec;
+ uint16_t flags;
+ uint32_t ciaddr;
+ uint32_t yiaddr;
+ uint32_t siaddr;
+ uint32_t giaddr;
+ uint8_t chaddr[16];
+ char sname[64];
+ char file[128];
+ uint8_t magic[4];
+} __packed;
+
+struct dhcpv4_option
+{
+ struct list_head entry;
+ uint8_t type;
+ uint8_t len;
+ uint8_t *data;
+};
+
+struct dhcpv4_packet
+{
+ struct dhcpv4_hdr *hdr;
+ struct list_head options;
+ struct dhcpv4_option *client_id;
+ struct dhcpv4_option *agent_circuit_id;
+ struct dhcpv4_option *agent_remote_id;
+ uint32_t request_ip;
+ uint32_t server_id;
+ int msg_type;
+ uint8_t *ptr;
+ uint8_t data[0];
+};
+
+struct dhcpv4_serv
+{
+ struct triton_context_t *ctx;
+ struct triton_md_handler_t hnd;
+ int raw_sock;
+ uint8_t hwaddr[6];
+ void (*recv)(struct dhcpv4_serv *serv, struct dhcpv4_packet *pack);
+};
+
+struct ap_session;
+
+struct dhcpv4_serv *dhcpv4_create(struct triton_context_t *ctx, const char *ifname);
+void dhcpv4_free(struct dhcpv4_serv *);
+
+
+int dhcpv4_send_reply(int msg_type, struct dhcpv4_serv *serv, struct dhcpv4_packet *req, struct ap_session *ses, int lease_time);
+int dhcpv4_send_nak(struct dhcpv4_serv *serv, struct dhcpv4_packet *req);
+
+void dhcpv4_packet_free(struct dhcpv4_packet *pack);
+
+int dhcpv4_check_options(struct dhcpv4_packet *);
+void dhcpv4_print_options(struct dhcpv4_packet *, void (*)(const char *, ...));
+
+void dhcpv4_print_packet(struct dhcpv4_packet *pack, void (*print)(const char *fmt, ...));
+
+#endif
diff --git a/accel-pppd/ctrl/ipoe/dhcpv4_options.c b/accel-pppd/ctrl/ipoe/dhcpv4_options.c
new file mode 100644
index 00000000..82e64902
--- /dev/null
+++ b/accel-pppd/ctrl/ipoe/dhcpv4_options.c
@@ -0,0 +1,290 @@
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <arpa/inet.h>
+
+#include "dhcpv4.h"
+
+struct known_option
+{
+ int type;
+ int min_len;
+ int max_len;
+ int elem_size;
+ const char *name;
+ void (*print)(const struct dhcpv4_option *opt, int elem_size, void (*print)(const char *fmt, ...));
+};
+
+static void print_int(const struct dhcpv4_option *opt, int elem_size, void (*print)(const char *fmt, ...));
+static void print_uint(const struct dhcpv4_option *opt, int elem_size, void (*print)(const char *fmt, ...));
+static void print_ip(const struct dhcpv4_option *opt, int elem_size, void (*print)(const char *fmt, ...));
+static void print_str(const struct dhcpv4_option *opt, int elem_size, void (*print)(const char *fmt, ...));
+static void print_hex(const struct dhcpv4_option *opt, int elem_size, void (*print)(const char *fmt, ...));
+static void print_route(const struct dhcpv4_option *opt, int elem_size, void (*print)(const char *fmt, ...));
+static void print_classless_route(const struct dhcpv4_option *opt, int elem_size, void (*print)(const char *fmt, ...));
+static void print_message_type(const struct dhcpv4_option *opt, int elem_size, void (*print)(const char *fmt, ...));
+static void print_request_list(const struct dhcpv4_option *opt, int elem_size, void (*print)(const char *fmt, ...));
+static void print_relay_agent(const struct dhcpv4_option *opt, int elem_size, void (*print)(const char *fmt, ...));
+
+static struct known_option options[] = {
+ { 1, 4, 4, 4, "Subnet", print_ip },
+ { 2, 4, 4, 4, "Time-Offset", print_int },
+ { 3, 4, 255, 4, "Router", print_ip },
+ { 4, 4, 255, 4, "Time-Server", print_ip },
+ { 5, 4, 255, 4, "Name-Server", print_ip },
+ { 6, 4, 255, 4, "DNS", print_ip },
+ //{ 7, 4, 255, 4, "log-server", print_ip },
+ //{ 8, 4, 255, 4, "cookie-server", print_ip },
+ //{ 9, 4, 255, 4, "lpr-server", print_ip },
+ //{ 10, 4, 255, 4, "impress-server", print_ip },
+ //{ 11, 4, 255, 4, "resourse-location", print_ip },
+ { 12, 1, 255, 1, "Host-Name", print_str },
+ //{ 13, 4, 255, 4, "impress-server", print_ip },
+ { 15, 1, 255, 1, "Domain-Name", print_str },
+ { 26, 2, 2, 2, "MTU", print_int },
+ { 28, 4, 4, 4, "Broadcast", print_ip },
+ { 33, 8, 255, 8, "Route", print_route },
+ { 42, 4, 4, 4, "NTP", print_ip },
+ { 43, 1, 255, 1, "Vendor-Specific", print_hex },
+ { 50, 4, 4, 4, "Request-IP", print_ip },
+ { 51, 4, 4, 4, "Lease-Time", print_uint },
+ { 53, 1, 1, 1, "Message-Type", print_message_type },
+ { 54, 4, 4, 4, "Server-ID", print_ip },
+ { 55, 1, 255, 1, "Request-List", print_request_list },
+ { 56, 1, 255, 1, "Message", print_str },
+ { 57, 2, 2, 2, "Max-Message-Size", print_uint },
+ { 58, 4, 4, 4, "T1", print_uint },
+ { 59, 4, 4, 4, "T2", print_uint },
+ { 60, 1, 255, 1, "Vendor-Class", print_hex },
+ { 61, 2, 255, 1, "Client-ID", print_hex },
+ { 82, 3, 255, 1, "Relay-Agent", print_relay_agent },
+ { 121, 5, 255, 1, "Classless-Route", print_classless_route },
+ { 0 },
+};
+
+int dhcpv4_check_options(struct dhcpv4_packet *pack)
+{
+ struct dhcpv4_option *opt;
+ struct known_option *kopt;
+
+ list_for_each_entry(opt, &pack->options, entry) {
+ for (kopt = options; kopt->type; kopt++) {
+ if (kopt->type != opt->type)
+ continue;
+ if (opt->len < kopt->min_len)
+ return -1;
+ if (opt->len > kopt->max_len)
+ return -1;
+ if (opt->len % kopt->elem_size != 0)
+ return -1;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+void dhcpv4_print_options(struct dhcpv4_packet *pack, void (*print)(const char *fmt, ...))
+{
+ struct dhcpv4_option *opt;
+ struct known_option *kopt;
+ int n = 0;
+
+ list_for_each_entry(opt, &pack->options, entry) {
+ if (n)
+ print(" <");
+ else
+ print("<");
+ n++;
+ for (kopt = options; kopt->type && kopt->type != opt->type; kopt++);
+ if (kopt->type) {
+ print("%s ", kopt->name);
+ kopt->print(opt, kopt->elem_size, print);
+ } else {
+ print("Option-%i ");
+ print_hex(opt, 1, print);
+ }
+ print(">");
+ }
+}
+
+
+static void print_int(const struct dhcpv4_option *opt, int elem_size, void (*print)(const char *fmt, ...))
+{
+ if (opt->len == 2)
+ print("%i", ntohs(*(int16_t *)(opt->data)));
+ else
+ print("%i", ntohl(*(int32_t *)(opt->data)));
+}
+
+static void print_uint(const struct dhcpv4_option *opt, int elem_size, void (*print)(const char *fmt, ...))
+{
+ if (opt->len == 2)
+ print("%u", ntohs(*(uint16_t *)(opt->data)));
+ else
+ print("%u", ntohl(*(uint32_t *)(opt->data)));
+}
+
+static void print_ip(const struct dhcpv4_option *opt, int elem_size, void (*print)(const char *fmt, ...))
+{
+ int i, n = opt->len / elem_size;
+ uint32_t ip;
+
+ for (i = 0; i < n; i++) {
+ ip = ntohl(*(uint32_t *)(opt->data + i*elem_size));
+
+ if (i)
+ print(",");
+
+ print("%i.%i.%i.%i",
+ (ip >> 24) & 0xff,
+ (ip >> 16) & 0xff,
+ (ip >> 8) & 0xff,
+ ip & 0xff);
+ }
+}
+
+static void print_str(const struct dhcpv4_option *opt, int elem_size, void (*print)(const char *fmt, ...))
+{
+ const char *ptr = (const char *)opt->data;
+ const char *endptr = ptr + opt->len;
+
+ for(; ptr < endptr; ptr++)
+ print("%c", *ptr);
+}
+
+static void print_hex(const struct dhcpv4_option *opt, int elem_size, void (*print)(const char *fmt, ...))
+{
+ const uint8_t *ptr = opt->data;
+ const uint8_t *endptr = ptr + opt->len;
+
+ for(; ptr < endptr; ptr++)
+ print("%02x", *ptr);
+}
+
+static void print_route(const struct dhcpv4_option *opt, int elem_size, void (*print)(const char *fmt, ...))
+{
+ int i, n = opt->len / 8;
+ uint32_t ip, gw;
+
+ for (i = 0; i < n; i++) {
+ ip = ntohl(*(uint32_t *)(opt->data + i*8));
+ gw = ntohl(*(uint32_t *)(opt->data + i*8 + 4));
+
+ if (i)
+ print(",");
+
+ print("%i.%i.%i.%i via %i.%i.%i.%i",
+ (ip >> 24) & 0xff,
+ (ip >> 16) & 0xff,
+ (ip >> 8) & 0xff,
+ ip & 0xff,
+ (gw >> 24) & 0xff,
+ (gw >> 16) & 0xff,
+ (gw >> 8) & 0xff,
+ gw & 0xff);
+ }
+}
+
+static void print_message_type(const struct dhcpv4_option *opt, int elem_size, void (*print)(const char *fmt, ...))
+{
+ const char *msg_name[] = {"", "Discover", "Offer", "Request", "Decline", "Ack", "Nak", "Release", "Inform"};
+
+ print("%s", msg_name[opt->data[0]]);
+}
+
+static void print_request_list(const struct dhcpv4_option *opt, int elem_size, void (*print)(const char *fmt, ...))
+{
+ int i;
+ struct known_option *kopt;
+
+ for (i = 0; i < opt->len; i++) {
+ if (i)
+ print(",");
+ for (kopt = options; kopt->type && kopt->type != opt->data[i]; kopt++);
+ if (kopt->type)
+ print("%s", kopt->name);
+ else
+ print("%i", opt->data[i]);
+ }
+}
+
+static void print_relay_agent(const struct dhcpv4_option *opt, int elem_size, void (*print)(const char *fmt, ...))
+{
+ const uint8_t *ptr = opt->data;
+ const uint8_t *endptr = ptr + opt->len;
+ const uint8_t *endptr1;
+ int type, len;
+
+ while (ptr < endptr) {
+ if (ptr != opt->data)
+ print(" ");
+ type = *ptr++;
+ len = *ptr++;
+ /*if (ptr + len > endptr) {
+ print(" invalid");
+ return;
+ }*/
+ if (type == 1)
+ print("{Agent-Circuit-ID ");
+ else if (type == 2)
+ print("{Agent-Remote-ID ");
+ else
+ print("{Option-%i ", type);
+
+ endptr1 = ptr + len;
+ for (;ptr < endptr1; ptr++) {
+ if (!isprint(*ptr)) {
+ print("_");
+ break;
+ }
+ print("%c", *ptr);
+ }
+ for (;ptr < endptr1; ptr++)
+ print("%02x", *ptr);
+ print("}");
+ }
+}
+
+static void print_classless_route(const struct dhcpv4_option *opt, int elem_size, void (*print)(const char *fmt, ...))
+{
+ const uint8_t *ptr = opt->data;
+ const uint8_t *endptr = ptr + opt->len;
+ int mask, i, mask1 = 0;
+ uint32_t ip;
+ uint32_t gw;
+
+ while (ptr < endptr) {
+ if (ptr != opt->data)
+ print(",");
+
+ mask = *ptr++;
+ ip = ntohl(*(uint32_t *)ptr);
+ for (i = 0; i < mask; i++)
+ mask1 |= (1 << (32 - i));
+ ip &= mask1;
+ if (mask <= 8)
+ ptr++;
+ else if (mask <= 16)
+ ptr += 2;
+ else if (mask <= 24)
+ ptr += 3;
+ else
+ ptr += 4;
+ gw = ntohl(*(uint32_t *)ptr);
+ ptr += 4;
+
+ print("%i.%i.%i.%i/%i via %i.%i.%i.%i",
+ (ip >> 24) & 0xff,
+ (ip >> 16) & 0xff,
+ (ip >> 8) & 0xff,
+ ip & 0xff,
+ mask,
+ (gw >> 24) & 0xff,
+ (gw >> 16) & 0xff,
+ (gw >> 8) & 0xff,
+ gw & 0xff);
+ }
+}
diff --git a/accel-pppd/ctrl/ipoe/ipoe.c b/accel-pppd/ctrl/ipoe/ipoe.c
new file mode 100644
index 00000000..2258c622
--- /dev/null
+++ b/accel-pppd/ctrl/ipoe/ipoe.c
@@ -0,0 +1,688 @@
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <time.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <linux/if.h>
+
+#include <pcre.h>
+
+#include "events.h"
+#include "list.h"
+#include "triton.h"
+#include "log.h"
+#include "mempool.h"
+#include "utils.h"
+#include "cli.h"
+#include "ap_session.h"
+#include "pwdb.h"
+#include "ipdb.h"
+
+#include "iplink.h"
+#include "connlimit.h"
+
+#include "ipoe.h"
+
+#include "memdebug.h"
+
+#define USERNAME_IFNAME 0
+#define USERNAME_LUA 1
+
+static int conf_dhcpv4 = 1;
+//static int conf_dhcpv6;
+static int conf_username;
+
+#ifdef USE_LUA
+static const char *conf_lua_username_func;
+#endif
+
+static int conf_offer_timeout = 3;
+static in_addr_t conf_gw_address;
+static int conf_netmask = 24;
+static int conf_lease_time = 600;
+static int conf_lease_timeout = 660;
+static int conf_verbose;
+
+static unsigned int stat_starting;
+static unsigned int stat_active;
+
+static mempool_t ses_pool;
+
+static LIST_HEAD(serv_list);
+
+struct iplink_arg
+{
+ pcre *re;
+ const char *opt;
+};
+
+static void ipoe_session_finished(struct ap_session *s);
+
+static struct ipoe_session *ipoe_session_lookup(struct ipoe_serv *serv, struct dhcpv4_packet *pack)
+{
+ struct ipoe_session *ses;
+
+ list_for_each_entry(ses, &serv->sessions, entry) {
+ if (pack->hdr->xid != ses->xid)
+ continue;
+
+ if (pack->hdr->giaddr != ses->giaddr)
+ continue;
+
+ if (pack->agent_circuit_id && !ses->agent_circuit_id)
+ continue;
+
+ if (pack->agent_remote_id && !ses->agent_remote_id)
+ continue;
+
+ if (pack->client_id && !ses->client_id)
+ continue;
+
+ if (!pack->agent_circuit_id && ses->agent_circuit_id)
+ continue;
+
+ if (!pack->agent_remote_id && ses->agent_remote_id)
+ continue;
+
+ if (!pack->client_id && ses->client_id)
+ continue;
+
+ if (pack->agent_circuit_id) {
+ if (pack->agent_circuit_id->len != ses->agent_circuit_id->len)
+ continue;
+ if (memcmp(pack->agent_circuit_id->data, ses->agent_circuit_id->data, pack->agent_circuit_id->len))
+ continue;
+ }
+
+ if (pack->agent_remote_id) {
+ if (pack->agent_remote_id->len != ses->agent_remote_id->len)
+ continue;
+ if (memcmp(pack->agent_remote_id->data, ses->agent_remote_id->data, pack->agent_remote_id->len))
+ continue;
+ }
+
+ if (pack->client_id) {
+ if (pack->client_id->len != ses->client_id->len)
+ continue;
+ if (memcmp(pack->client_id->data, ses->client_id->data, pack->client_id->len))
+ continue;
+ }
+
+ if (memcmp(pack->hdr->chaddr, ses->hwaddr, 6))
+ continue;
+
+ return ses;
+ }
+
+ return NULL;
+}
+
+static void ipoe_session_timeout(struct triton_timer_t *t)
+{
+ struct ipoe_session *ses = container_of(t, typeof(*ses), timer);
+
+ triton_timer_del(t);
+
+ log_ppp_info2("session timed out\n");
+
+ ap_session_terminate(&ses->ses, TERM_LOST_CARRIER, 0);
+}
+
+static void ipoe_session_set_username(struct ipoe_session *ses)
+{
+#ifdef USE_LUA
+ if (conf_username == USERNAME_LUA) {
+ ipoe_lua_set_username(ses, conf_lua_username_func);
+ } else
+#endif
+ ses->ses.username = _strdup(ses->ses.ifname);
+}
+
+static void ipoe_session_start(struct ipoe_session *ses)
+{
+ int r;
+ char *passwd;
+
+ if (ses->serv->opt_single)
+ strncpy(ses->ses.ifname, ses->serv->ifname, AP_IFNAME_LEN);
+
+ ipoe_session_set_username(ses);
+ if (!ses->ses.username) {
+ ipoe_session_finished(&ses->ses);
+ return;
+ }
+
+ triton_event_fire(EV_CTRL_STARTING, &ses->ses);
+ triton_event_fire(EV_CTRL_STARTED, &ses->ses);
+
+ ap_session_starting(&ses->ses);
+
+ r = pwdb_check(&ses->ses, ses->ses.username, 0);
+ if (r == PWDB_NO_IMPL) {
+ passwd = pwdb_get_passwd(&ses->ses, ses->ses.username);
+ if (!passwd)
+ r = PWDB_DENIED;
+ else {
+ r = PWDB_SUCCESS;
+ _free(passwd);
+ }
+ }
+
+ if (r == PWDB_DENIED) {
+ if (conf_ppp_verbose)
+ log_ppp_warn("authentication failed\n");
+ ap_session_terminate(&ses->ses, TERM_AUTH_ERROR, 0);
+ return;
+ }
+
+ if (ses->dhcpv4_request) {
+ ses->ses.ipv4 = ipdb_get_ipv4(&ses->ses);
+ if (!ses->ses.ipv4) {
+ log_ppp_warn("no free IPv4 address\n");
+ ap_session_terminate(&ses->ses, TERM_AUTH_ERROR, 0);
+ return;
+ }
+
+ if (conf_gw_address)
+ ses->ses.ipv4->addr = conf_gw_address;
+
+ if (conf_netmask)
+ ses->ses.ipv4->mask = conf_netmask;
+ else if (!ses->ses.ipv4->mask)
+ ses->ses.ipv4->mask = 24;
+
+ dhcpv4_send_reply(DHCPOFFER, ses->serv->dhcpv4, ses->dhcpv4_request, &ses->ses, conf_lease_time);
+
+ dhcpv4_packet_free(ses->dhcpv4_request);
+ ses->dhcpv4_request = NULL;
+ }
+
+ ses->timer.expire = ipoe_session_timeout;
+ ses->timer.period = conf_offer_timeout * 1000;
+ triton_timer_add(&ses->ctx, &ses->timer, 0);
+}
+
+static void ipoe_session_activate(struct ipoe_session *ses)
+{
+ ap_session_activate(&ses->ses);
+
+ if (ses->ses.state == AP_STATE_ACTIVE)
+ dhcpv4_send_reply(DHCPACK, ses->serv->dhcpv4, ses->dhcpv4_request, &ses->ses, conf_lease_time);
+ else
+ dhcpv4_send_nak(ses->serv->dhcpv4, ses->dhcpv4_request);
+
+ dhcpv4_packet_free(ses->dhcpv4_request);
+ ses->dhcpv4_request = NULL;
+}
+
+static void ipoe_session_started(struct ap_session *s)
+{
+ struct ipoe_session *ses = container_of(s, typeof(*ses), ses);
+
+ log_ppp_debug("ipoe: session started\n");
+
+ triton_timer_del(&ses->timer);
+
+ ses->timer.expire = ipoe_session_timeout;
+ ses->timer.period = conf_lease_timeout * 1000;
+ triton_timer_add(&ses->ctx, &ses->timer, 0);
+}
+
+static void ipoe_session_free(struct ipoe_session *ses)
+{
+ if (ses->timer.tpd)
+ triton_timer_del(&ses->timer);
+
+ triton_context_unregister(&ses->ctx);
+
+ if (ses->data)
+ _free(ses->data);
+
+ mempool_free(ses);
+}
+
+static void ipoe_session_finished(struct ap_session *s)
+{
+ struct ipoe_session *ses = container_of(s, typeof(*ses), ses);
+
+ log_ppp_debug("ipoe: session finished\n");
+
+ pthread_mutex_lock(&ses->serv->lock);
+ list_del(&ses->entry);
+ pthread_mutex_unlock(&ses->serv->lock);
+
+ triton_context_call(&ses->ctx, (triton_event_func)ipoe_session_free, ses);
+}
+
+static void ipoe_session_terminate(struct ap_session *s, int hard)
+{
+ ap_session_finished(s);
+}
+
+
+static void ipoe_session_close(struct triton_context_t *ctx)
+{
+ struct ipoe_session *ses = container_of(ctx, typeof(*ses), ctx);
+
+ if (ses->ses.state)
+ ap_session_terminate(&ses->ses, TERM_ADMIN_RESET, 1);
+ else
+ ipoe_session_finished(&ses->ses);
+}
+
+static struct ipoe_session *ipoe_session_create(struct ipoe_serv *serv, struct dhcpv4_packet *pack)
+{
+ struct ipoe_session *ses;
+ int dlen = 0;
+ uint8_t *ptr;
+
+ ses = mempool_alloc(ses_pool);
+ if (!ses) {
+ log_emerg("out of memery\n");
+ return NULL;
+ }
+
+ memset(ses, 0, sizeof(*ses));
+
+ ap_session_init(&ses->ses);
+
+ ses->serv = serv;
+ ses->dhcpv4_request = pack;
+
+ ses->xid = pack->hdr->xid;
+ memcpy(ses->hwaddr, pack->hdr->chaddr, 6);
+ ses->giaddr = pack->hdr->giaddr;
+
+ if (pack->agent_circuit_id)
+ dlen += sizeof(struct dhcp_opt) + pack->agent_circuit_id->len;
+
+ if (pack->agent_remote_id)
+ dlen += sizeof(struct dhcp_opt) + pack->agent_remote_id->len;
+
+ if (pack->client_id)
+ dlen += sizeof(struct dhcp_opt) + pack->client_id->len;
+
+ if (dlen) {
+ ses->data = _malloc(dlen);
+ if (!ses->data) {
+ log_emerg("out of memery\n");
+ mempool_free(ses);
+ return NULL;
+ }
+ ptr = ses->data;
+ }
+
+ if (pack->agent_circuit_id) {
+ ses->agent_circuit_id = (struct dhcp_opt *)ptr;
+ ses->agent_circuit_id->len = pack->agent_circuit_id->len;
+ memcpy(ses->agent_circuit_id->data, pack->agent_circuit_id->data, pack->agent_circuit_id->len);
+ ptr += sizeof(struct dhcp_opt) + pack->agent_circuit_id->len;
+ }
+
+ if (pack->agent_remote_id) {
+ ses->agent_remote_id = (struct dhcp_opt *)ptr;
+ ses->agent_remote_id->len = pack->agent_remote_id->len;
+ memcpy(ses->agent_remote_id->data, pack->agent_remote_id->data, pack->agent_remote_id->len);
+ ptr += sizeof(struct dhcp_opt) + pack->agent_remote_id->len;
+ }
+
+ if (pack->client_id) {
+ ses->client_id = (struct dhcp_opt *)ptr;
+ ses->client_id->len = pack->client_id->len;
+ memcpy(ses->client_id->data, pack->client_id->data, pack->client_id->len);
+ ptr += sizeof(struct dhcp_opt) + pack->client_id->len;
+ }
+
+ ses->ctx.before_switch = log_switch;
+ ses->ctx.close = ipoe_session_close;
+ ses->ctrl.ctx = &ses->ctx;
+ ses->ctrl.started = ipoe_session_started;
+ ses->ctrl.finished = ipoe_session_finished;
+ ses->ctrl.terminate = ipoe_session_terminate;
+ ses->ctrl.type = CTRL_TYPE_IPOE;
+ ses->ctrl.name = "ipoe";
+
+ ses->ctrl.calling_station_id = _malloc(19);
+ ses->ctrl.called_station_id = serv->ifname;
+
+ ptr = ses->hwaddr;
+ sprintf(ses->ctrl.calling_station_id, "%02x:%02x:%02x:%02x:%02x:%02x",
+ ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5]);
+
+ ses->ses.ctrl = &ses->ctrl;
+ ses->ses.chan_name = ses->ctrl.calling_station_id;
+
+ triton_context_register(&ses->ctx, &ses->ses);
+
+ triton_context_wakeup(&ses->ctx);
+
+ //pthread_mutex_lock(&serv->lock);
+ list_add_tail(&ses->entry, &serv->sessions);
+ //pthread_mutex_unlock(&serv->lock);
+
+ triton_context_call(&ses->ctx, (triton_event_func)ipoe_session_start, ses);
+
+ return ses;
+}
+
+static void ipoe_dhcpv4_recv(struct dhcpv4_serv *dhcpv4, struct dhcpv4_packet *pack)
+{
+ struct ipoe_serv *serv = container_of(dhcpv4->ctx, typeof(*serv), ctx);
+ struct ipoe_session *ses;
+ //struct dhcpv4_packet *reply;
+
+ pthread_mutex_lock(&serv->lock);
+ if (pack->msg_type == DHCPDISCOVER) {
+ ses = ipoe_session_lookup(serv, pack);
+ if (!ses) {
+ ses = ipoe_session_create(serv, pack);
+
+ if (conf_verbose && ses) {
+ log_switch(dhcpv4->ctx, &ses->ses);
+ log_ppp_info2("recv ");
+ dhcpv4_print_packet(pack, log_ppp_info2);
+ }
+ } else {
+ log_switch(dhcpv4->ctx, &ses->ses);
+
+ if (conf_verbose) {
+ log_ppp_info2("recv ");
+ dhcpv4_print_packet(pack, log_ppp_info2);
+ }
+
+ if (ses->ses.state == AP_STATE_ACTIVE)
+ dhcpv4_send_reply(DHCPOFFER, dhcpv4, pack, &ses->ses, conf_lease_time);
+
+ dhcpv4_packet_free(pack);
+ }
+ } else if (pack->msg_type == DHCPREQUEST) {
+ ses = ipoe_session_lookup(serv, pack);
+
+ if (!ses) {
+ if (conf_verbose) {
+ log_info2("recv ");
+ dhcpv4_print_packet(pack, log_info2);
+ }
+
+ dhcpv4_send_nak(dhcpv4, pack);
+ } else {
+ if (!ses->ses.ipv4 || pack->server_id != ses->ses.ipv4->addr || pack->request_ip != ses->ses.ipv4->peer_addr) {
+ if (conf_verbose) {
+ log_info2("recv ");
+ dhcpv4_print_packet(pack, log_info2);
+ }
+
+ if (ses->ses.ipv4 && pack->request_ip != ses->ses.ipv4->peer_addr)
+ dhcpv4_send_nak(dhcpv4, pack);
+ ap_session_terminate(&ses->ses, TERM_USER_REQUEST, 0);
+ } else {
+ if (conf_verbose) {
+ log_switch(dhcpv4->ctx, &ses->ses);
+ log_ppp_info2("recv ");
+ dhcpv4_print_packet(pack, log_ppp_info2);
+ }
+
+ if (ses->ses.state == AP_STATE_STARTING && !ses->dhcpv4_request) {
+ ses->dhcpv4_request = pack;
+ pack = NULL;
+ triton_context_call(&ses->ctx, (triton_event_func)ipoe_session_activate, ses);
+ }
+ }
+ }
+ if (pack)
+ dhcpv4_packet_free(pack);
+ } else if (pack->msg_type == DHCPDECLINE || pack->msg_type == DHCPRELEASE) {
+ ses = ipoe_session_lookup(serv, pack);
+ if (ses) {
+ if (conf_verbose) {
+ log_switch(dhcpv4->ctx, &ses->ses);
+ log_ppp_info2("recv ");
+ dhcpv4_print_packet(pack, log_ppp_info2);
+ }
+
+ ap_session_terminate(&ses->ses, TERM_USER_REQUEST, 0);
+ }
+ dhcpv4_packet_free(pack);
+ }
+ pthread_mutex_unlock(&serv->lock);
+}
+
+static void ipoe_serv_close(struct triton_context_t *ctx)
+{
+ struct ipoe_serv *serv = container_of(ctx, typeof(*serv), ctx);
+
+ if (serv->dhcpv4)
+ dhcpv4_free(serv->dhcpv4);
+
+ triton_context_unregister(ctx);
+
+ _free(serv->ifname);
+ _free(serv);
+}
+
+static int show_stat_exec(const char *cmd, char * const *fields, int fields_cnt, void *client)
+{
+ cli_send(client, "ipoe:\r\n");
+ cli_sendv(client," starting: %u\r\n", stat_starting);
+ cli_sendv(client," active: %u\r\n", stat_active);
+
+ return CLI_CMD_OK;
+}
+
+void __export ipoe_get_stat(unsigned int **starting, unsigned int **active)
+{
+ *starting = &stat_starting;
+ *active = &stat_active;
+}
+
+static void ipoe_drop_sessions(struct ipoe_serv *serv)
+{
+
+}
+
+static void add_interface(const char *ifname, int ifindex, const char *opt)
+{
+ int opt_single;
+ const char *ptr;
+ struct ipoe_serv *serv;
+
+ ptr = strstr(opt, ",single");
+ if (ptr) {
+ if (ptr[7] && ptr[7] != ',')
+ goto out_err_parse;
+ opt_single = 1;
+ } else
+ opt_single = 0;
+
+
+ list_for_each_entry(serv, &serv_list, entry) {
+ if (strcmp(ifname, serv->ifname) == 0) {
+ serv->active = 1;
+ serv->ifindex = ifindex;
+ if (opt_single && !serv->opt_single)
+ ipoe_drop_sessions(serv);
+ serv->opt_single = opt_single;
+ return;
+ }
+ }
+
+ serv = _malloc(sizeof(*serv));
+ memset(serv, 0, sizeof(*serv));
+ serv->ifname = _strdup(ifname);
+ serv->ifindex = ifindex;
+ serv->opt_single = opt_single;
+ serv->opt_dhcpv4 = conf_dhcpv4;
+ INIT_LIST_HEAD(&serv->sessions);
+ pthread_mutex_init(&serv->lock, NULL);
+
+ triton_context_register(&serv->ctx, NULL);
+
+ if (serv->opt_dhcpv4) {
+ serv->dhcpv4 = dhcpv4_create(&serv->ctx, serv->ifname);
+ if (serv->dhcpv4)
+ serv->dhcpv4->recv = ipoe_dhcpv4_recv;
+ }
+
+ triton_context_wakeup(&serv->ctx);
+
+ return;
+
+out_err_parse:
+ log_error("ipoe: failed to parse '%s'\n", opt);
+}
+
+static void load_interface(const char *opt)
+{
+ const char *ptr;
+ struct ifreq ifr;
+
+ for (ptr = opt; *ptr && *ptr != ','; ptr++);
+
+ if (ptr - opt >= sizeof(ifr.ifr_name))
+ return;
+
+ memcpy(ifr.ifr_name, opt, ptr - opt);
+ ifr.ifr_name[ptr - opt] = 0;
+
+ if (ioctl(sock_fd, SIOCGIFINDEX, &ifr)) {
+ log_error("ipoe: '%s': ioctl(SIOCGIFINDEX): %s\n", ifr.ifr_name, strerror(errno));
+ return;
+ }
+
+ add_interface(ifr.ifr_name, ifr.ifr_ifindex, opt);
+}
+
+static int __load_interface_re(int index, int flags, const char *name, struct iplink_arg *arg)
+{
+ if (pcre_exec(arg->re, NULL, name, strlen(name), 0, 0, NULL, 0) < 0)
+ return 0;
+
+ add_interface(name, index, arg->opt);
+
+ return 0;
+}
+
+static void load_interface_re(const char *opt)
+{
+ pcre *re = NULL;
+ const char *pcre_err;
+ char *pattern;
+ const char *ptr;
+ int pcre_offset;
+ struct iplink_arg arg;
+
+ for (ptr = opt; *ptr && *ptr != ','; ptr++);
+
+ pattern = _malloc(ptr - (opt + 3) + 1);
+ memcpy(pattern, opt + 3, ptr - (opt + 3));
+ pattern[ptr - (opt + 3)] = 0;
+
+ re = pcre_compile2(pattern, 0, NULL, &pcre_err, &pcre_offset, NULL);
+
+ if (!re) {
+ log_error("ipoe: %s at %i\r\n", pcre_err, pcre_offset);
+ return;
+ }
+
+ arg.re = re;
+ arg.opt = opt;
+
+ iplink_list((iplink_list_func)__load_interface_re, &arg);
+
+ pcre_free(re);
+ _free(pattern);
+}
+
+static void load_interfaces(struct conf_sect_t *sect)
+{
+ struct ipoe_serv *serv;
+ struct conf_option_t *opt;
+ struct list_head *pos, *n;
+
+ list_for_each_entry(serv, &serv_list, entry)
+ serv->active = 0;
+
+ list_for_each_entry(opt, &sect->items, entry) {
+ if (strcmp(opt->name, "interface"))
+ continue;
+ if (!opt->val)
+ continue;
+
+ if (strlen(opt->val) > 3 && memcmp(opt->val, "re:", 3) == 0)
+ load_interface_re(opt->val);
+ else
+ load_interface(opt->val);
+ }
+
+ list_for_each_safe(pos, n, &serv_list) {
+ serv = list_entry(pos, typeof(*serv), entry);
+ if (!serv->active) {
+ list_del(&serv->entry);
+ triton_context_call(&serv->ctx, (triton_event_func)ipoe_serv_close, &serv->ctx);
+ }
+ }
+}
+
+static void load_config(void)
+{
+ const char *opt;
+ struct conf_sect_t *s = conf_get_section("ipoe");
+
+ if (!s)
+ return;
+
+ load_interfaces(s);
+
+ opt = conf_get_opt("ipoe", "username");
+ if (opt) {
+ if (strcmp(opt, "ifname") == 0)
+ conf_username = USERNAME_IFNAME;
+#ifdef USE_LUA
+ else if (strlen(opt) > 4 && memcmp(opt, "lua:", 4) == 0) {
+ conf_username = USERNAME_LUA;
+ conf_lua_username_func = opt + 4;
+#endif
+ } else
+ log_emerg("ipoe: unknown username value '%s'\n", opt);
+ }
+
+ opt = conf_get_opt("ipoe", "gw-ip-address");
+ if (opt)
+ conf_gw_address = inet_addr(opt);
+ else
+ conf_gw_address = 0;
+
+ opt = conf_get_opt("ipoe", "netmask");
+ if (opt) {
+ conf_netmask = atoi(opt);
+ if (conf_netmask <= 0 || conf_netmask > 32) {
+ log_error("ipoe: invalid netmask %s\n", opt);
+ conf_netmask = 0;
+ }
+ } else
+ conf_netmask = 0;
+
+ opt = conf_get_opt("ipoe", "verbose");
+ if (opt)
+ conf_verbose = atoi(opt);
+}
+
+static void ipoe_init(void)
+{
+ ses_pool = mempool_create(sizeof(struct ipoe_session));
+
+ load_config();
+
+ cli_register_simple_cmd2(show_stat_exec, NULL, 2, "show", "stat");
+
+ triton_event_register_handler(EV_CONFIG_RELOAD, (triton_event_func)load_config);
+}
+
+DEFINE_INIT(20, ipoe_init);
diff --git a/accel-pppd/ctrl/ipoe/ipoe.h b/accel-pppd/ctrl/ipoe/ipoe.h
new file mode 100644
index 00000000..adbc5cff
--- /dev/null
+++ b/accel-pppd/ctrl/ipoe/ipoe.h
@@ -0,0 +1,54 @@
+#ifndef __IPOE_H
+#define __IPOE_H
+
+#include <stdint.h>
+#include <pthread.h>
+
+#include "triton.h"
+#include "ap_session.h"
+#include "dhcpv4.h"
+
+struct ipoe_serv
+{
+ struct list_head entry;
+ struct triton_context_t ctx;
+ char *ifname;
+ int ifindex;
+ int active;
+ int opt_single;
+ int opt_dhcpv4;
+ struct list_head sessions;
+ struct dhcpv4_serv *dhcpv4;
+ pthread_mutex_t lock;
+};
+
+struct dhcp_opt
+{
+ uint8_t len;
+ uint8_t data[0];
+};
+
+struct ipoe_session
+{
+ struct list_head entry;
+ struct triton_context_t ctx;
+ struct triton_timer_t timer;
+ struct ipoe_serv *serv;
+ struct ap_ctrl ctrl;
+ struct ap_session ses;
+ uint8_t hwaddr[6];
+ struct dhcp_opt *client_id;
+ struct dhcp_opt *agent_circuit_id;
+ struct dhcp_opt *agent_remote_id;
+ uint32_t xid;
+ uint32_t giaddr;
+ uint8_t *data;
+ struct dhcpv4_packet *dhcpv4_request;
+};
+
+#ifdef USE_LUA
+int ipoe_lua_set_username(struct ipoe_session *, const char *func);
+#endif
+
+#endif
+
diff --git a/accel-pppd/ctrl/ipoe/lua.c b/accel-pppd/ctrl/ipoe/lua.c
new file mode 100644
index 00000000..77beca6e
--- /dev/null
+++ b/accel-pppd/ctrl/ipoe/lua.c
@@ -0,0 +1,253 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <pthread.h>
+
+/* Include the Lua API header files. */
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+
+#include "events.h"
+#include "log.h"
+#include "utils.h"
+
+#include "ipoe.h"
+
+#include "memdebug.h"
+
+#define IPOE_PACKET4 "ipoe.packet4"
+
+static const char *conf_filename;
+static int serial;
+static int file_error;
+
+static __thread lua_State *L;
+static __thread int __serial;
+static pthread_key_t __key;
+
+static int packet4_hdr(lua_State *L);
+static int packet4_ifname(lua_State *L);
+static int packet4_option(lua_State *L);
+static int packet4_options(lua_State *L);
+static int packet4_agent_circuit_id(lua_State *L);
+static int packet4_agent_remote_id(lua_State *L);
+
+int luaopen_lpack(lua_State *L);
+
+static const struct luaL_reg packet4_lib [] = {
+ {"hdr", packet4_hdr},
+ {"ifname", packet4_ifname},
+ {"option", packet4_option},
+ {"options", packet4_options},
+ {"agent_circuit_id", packet4_agent_circuit_id},
+ {"agent_remote_id", packet4_agent_remote_id},
+ {NULL, NULL}
+};
+
+static int luaopen_packet4(lua_State *L)
+{
+ luaL_newmetatable(L, IPOE_PACKET4);
+
+ lua_pushstring(L, "__index");
+ lua_pushvalue(L, -2); /* pushes the metatable */
+ lua_settable(L, -3); /* metatable.__index = metatable */
+
+
+ luaI_openlib(L, NULL, packet4_lib, 0);
+
+ luaI_openlib(L, "packet4", packet4_lib, 0);
+
+ return 1;
+}
+
+static int packet4_hdr(lua_State *L)
+{
+ struct ipoe_session *ses = luaL_checkudata(L, 1, IPOE_PACKET4);
+ const char *name = luaL_checkstring(L, 2);
+ char str[20];
+ uint8_t *ptr;
+
+ if (!ses)
+ return 0;
+
+ if (!strcmp(name, "xid"))
+ lua_pushinteger(L, ses->dhcpv4_request->hdr->xid);
+ else if (!strcmp(name, "ciaddr")) {
+ u_inet_ntoa(ses->dhcpv4_request->hdr->ciaddr, str);
+ lua_pushstring(L, str);
+ } else if (!strcmp(name, "giaddr")) {
+ u_inet_ntoa(ses->dhcpv4_request->hdr->giaddr, str);
+ lua_pushstring(L, str);
+ } else if (!strcmp(name, "chaddr")) {
+ ptr = ses->dhcpv4_request->hdr->chaddr;
+ sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
+ ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5]);
+ lua_pushstring(L, str);
+ }
+
+ return 1;
+}
+
+static int packet4_ifname(lua_State *L)
+{
+ struct ipoe_session *ses = luaL_checkudata(L, 1, IPOE_PACKET4);
+
+ if (!ses)
+ return 0;
+
+ lua_pushstring(L, ses->serv->ifname);
+
+ return 1;
+}
+
+static int packet4_option(lua_State *L)
+{
+ struct ipoe_session *ses = luaL_checkudata(L, 1, IPOE_PACKET4);
+ int type = luaL_checkinteger(L, 2);
+ struct dhcpv4_option *opt;
+
+ list_for_each_entry(opt, &ses->dhcpv4_request->options, entry) {
+ if (opt->type == type) {
+ lua_pushlstring(L, (char *)opt->data, opt->len);
+ return 1;
+ }
+ }
+
+ lua_pushnil(L);
+
+ return 1;
+}
+
+static int packet4_options(lua_State *L)
+{
+ struct ipoe_session *ses = luaL_checkudata(L, 1, IPOE_PACKET4);
+ struct dhcpv4_option *opt;
+ int i = 1;
+
+ if (!ses)
+ return 0;
+
+ lua_newtable(L);
+
+ list_for_each_entry(opt, &ses->dhcpv4_request->options, entry) {
+ lua_pushinteger(L, opt->type);
+ lua_rawseti(L, -2, i++);
+ }
+
+ return 1;
+}
+
+static int packet4_agent_circuit_id(lua_State *L)
+{
+ struct ipoe_session *ses = luaL_checkudata(L, 1, IPOE_PACKET4);
+
+ if (!ses)
+ return 0;
+
+ if (ses->agent_circuit_id)
+ lua_pushlstring(L, (char *)ses->agent_circuit_id->data, ses->agent_circuit_id->len);
+ else
+ lua_pushnil(L);
+
+ return 1;
+}
+
+static int packet4_agent_remote_id(lua_State *L)
+{
+ struct ipoe_session *ses = luaL_checkudata(L, 1, IPOE_PACKET4);
+
+ if (!ses)
+ return 0;
+
+ if (ses->agent_remote_id)
+ lua_pushlstring(L, (char *)ses->agent_remote_id->data, ses->agent_remote_id->len);
+ else
+ lua_pushnil(L);
+
+ return 1;
+}
+
+static void init_lua()
+{
+ __serial = serial;
+
+ L = lua_open();
+
+ luaL_openlibs(L);
+
+ luaopen_lpack(L);
+ luaopen_packet4(L);
+
+ if (luaL_loadfile(L, conf_filename))
+ goto out_err;
+
+ if (lua_pcall(L, 0, 0, 0))
+ goto out_err;
+
+ file_error = 0;
+
+ pthread_setspecific(__key, L);
+
+ return;
+
+out_err:
+ file_error = 1;
+ log_ppp_error("ipoe: lua: %s\n", lua_tostring(L, -1));
+ lua_close(L);
+ L = NULL;
+}
+
+int ipoe_lua_set_username(struct ipoe_session *ses, const char *func)
+{
+ if (file_error && serial == __serial)
+ return -1;
+
+ if (L && serial != __serial) {
+ lua_close(L);
+ init_lua();
+ } else if (!L)
+ init_lua();
+
+ if (!L)
+ return -1;
+
+ lua_getglobal(L, func);
+ lua_pushlightuserdata(L, ses);
+ luaL_getmetatable(L, IPOE_PACKET4);
+ lua_setmetatable(L, -2);
+
+ if (lua_pcall(L, 1, 1, 0)) {
+ log_ppp_error("ipoe: lua: %s\n", lua_tostring(L, -1));
+ return -1;
+ }
+
+ if (!lua_isstring(L, -1)) {
+ log_ppp_error("ipoe: lua: function '%s' must return a string\n", func);
+ return -1;
+ }
+
+ ses->ses.username = _strdup(lua_tostring(L, -1));
+
+ lua_pop(L, 1);
+
+ return 0;
+}
+
+static void load_config()
+{
+ conf_filename = conf_get_opt("ipoe", "lua-file");
+
+ serial++;
+}
+
+static void init()
+{
+ load_config();
+
+ pthread_key_create(&__key, (void (*)(void *))lua_close);
+
+ triton_event_register_handler(EV_CONFIG_RELOAD, (triton_event_func)load_config);
+}
+
+DEFINE_INIT(100, init);
diff --git a/accel-pppd/ctrl/ipoe/lua_lpack.c b/accel-pppd/ctrl/ipoe/lua_lpack.c
new file mode 100644
index 00000000..22d34774
--- /dev/null
+++ b/accel-pppd/ctrl/ipoe/lua_lpack.c
@@ -0,0 +1,271 @@
+/*
+* lpack.c
+* a Lua library for packing and unpacking binary data
+* Luiz Henrique de Figueiredo <lhf@tecgraf.puc-rio.br>
+* 29 Jun 2007 19:27:20
+* This code is hereby placed in the public domain.
+* with contributions from Ignacio Castaņo <castanyo@yahoo.es> and
+* Roberto Ierusalimschy <roberto@inf.puc-rio.br>.
+*/
+
+#define OP_ZSTRING 'z' /* zero-terminated string */
+#define OP_BSTRING 'p' /* string preceded by length byte */
+#define OP_WSTRING 'P' /* string preceded by length word */
+#define OP_SSTRING 'a' /* string preceded by length size_t */
+#define OP_STRING 'A' /* string */
+#define OP_FLOAT 'f' /* float */
+#define OP_DOUBLE 'd' /* double */
+#define OP_NUMBER 'n' /* Lua number */
+#define OP_CHAR 'c' /* char */
+#define OP_BYTE 'b' /* byte = unsigned char */
+#define OP_SHORT 'h' /* short */
+#define OP_USHORT 'H' /* unsigned short */
+#define OP_INT 'i' /* int */
+#define OP_UINT 'I' /* unsigned int */
+#define OP_LONG 'l' /* long */
+#define OP_ULONG 'L' /* unsigned long */
+#define OP_LITTLEENDIAN '<' /* little endian */
+#define OP_BIGENDIAN '>' /* big endian */
+#define OP_NATIVE '=' /* native endian */
+
+#include <ctype.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "lua.h"
+#include "lualib.h"
+#include "lauxlib.h"
+
+static void badcode(lua_State *L, int c)
+{
+ char s[]="bad code `?'";
+ s[sizeof(s)-3]=c;
+ luaL_argerror(L,1,s);
+}
+
+static int doendian(int c)
+{
+ int x=1;
+ int e=*(char*)&x;
+ if (c==OP_LITTLEENDIAN) return !e;
+ if (c==OP_BIGENDIAN) return e;
+ if (c==OP_NATIVE) return 0;
+ return 0;
+}
+
+static void doswap(int swap, void *p, size_t n)
+{
+ if (swap)
+ {
+ char *a=p;
+ int i,j;
+ for (i=0, j=n-1, n=n/2; n--; i++, j--)
+ {
+ char t=a[i]; a[i]=a[j]; a[j]=t;
+ }
+ }
+}
+
+#define UNPACKNUMBER(OP,T) \
+ case OP: \
+ { \
+ T a; \
+ int m=sizeof(a); \
+ if (i+m>len) goto done; \
+ memcpy(&a,s+i,m); \
+ i+=m; \
+ doswap(swap,&a,m); \
+ lua_pushnumber(L,(lua_Number)a); \
+ ++n; \
+ break; \
+ }
+
+#define UNPACKSTRING(OP,T) \
+ case OP: \
+ { \
+ T l; \
+ int m=sizeof(l); \
+ if (i+m>len) goto done; \
+ memcpy(&l,s+i,m); \
+ doswap(swap,&l,m); \
+ if (i+m+l>len) goto done; \
+ i+=m; \
+ lua_pushlstring(L,s+i,l); \
+ i+=l; \
+ ++n; \
+ break; \
+ }
+
+static int l_unpack(lua_State *L) /** unpack(s,f,[init]) */
+{
+ size_t len;
+ const char *s=luaL_checklstring(L,1,&len);
+ const char *f=luaL_checkstring(L,2);
+ int i=luaL_optnumber(L,3,1)-1;
+ int n=0;
+ int swap=0;
+ lua_pushnil(L);
+ while (*f)
+ {
+ int c=*f++;
+ int N=1;
+ if (isdigit(*f))
+ {
+ N=0;
+ while (isdigit(*f)) N=10*N+(*f++)-'0';
+ if (N==0 && c==OP_STRING) { lua_pushliteral(L,""); ++n; }
+ }
+ while (N--) switch (c)
+ {
+ case OP_LITTLEENDIAN:
+ case OP_BIGENDIAN:
+ case OP_NATIVE:
+ {
+ swap=doendian(c);
+ N=0;
+ break;
+ }
+ case OP_STRING:
+ {
+ ++N;
+ if (i+N>len) goto done;
+ lua_pushlstring(L,s+i,N);
+ i+=N;
+ ++n;
+ N=0;
+ break;
+ }
+ case OP_ZSTRING:
+ {
+ size_t l;
+ if (i>=len) goto done;
+ l=strlen(s+i);
+ lua_pushlstring(L,s+i,l);
+ i+=l+1;
+ ++n;
+ break;
+ }
+ UNPACKSTRING(OP_BSTRING, unsigned char)
+ UNPACKSTRING(OP_WSTRING, unsigned short)
+ UNPACKSTRING(OP_SSTRING, size_t)
+ UNPACKNUMBER(OP_NUMBER, lua_Number)
+ UNPACKNUMBER(OP_DOUBLE, double)
+ UNPACKNUMBER(OP_FLOAT, float)
+ UNPACKNUMBER(OP_CHAR, int8_t)
+ UNPACKNUMBER(OP_BYTE, uint8_t)
+ UNPACKNUMBER(OP_SHORT, int16_t)
+ UNPACKNUMBER(OP_USHORT, uint16_t)
+ UNPACKNUMBER(OP_INT, int32_t)
+ UNPACKNUMBER(OP_UINT, uint32_t)
+ UNPACKNUMBER(OP_LONG, int64_t)
+ UNPACKNUMBER(OP_ULONG, uint64_t)
+ case ' ': case ',':
+ break;
+ default:
+ badcode(L,c);
+ break;
+ }
+ }
+done:
+ lua_pushnumber(L,i+1);
+ lua_replace(L,-n-2);
+ return n+1;
+}
+
+#define PACKNUMBER(OP,T) \
+ case OP: \
+ { \
+ T a=(T)luaL_checknumber(L,i++); \
+ doswap(swap,&a,sizeof(a)); \
+ luaL_addlstring(&b,(void*)&a,sizeof(a)); \
+ break; \
+ }
+
+#define PACKSTRING(OP,T) \
+ case OP: \
+ { \
+ size_t l; \
+ const char *a=luaL_checklstring(L,i++,&l); \
+ T ll=(T)l; \
+ doswap(swap,&ll,sizeof(ll)); \
+ luaL_addlstring(&b,(void*)&ll,sizeof(ll)); \
+ luaL_addlstring(&b,a,l); \
+ break; \
+ }
+
+static int l_pack(lua_State *L) /** pack(f,...) */
+{
+ int i=2;
+ const char *f=luaL_checkstring(L,1);
+ int swap=0;
+ luaL_Buffer b;
+ luaL_buffinit(L,&b);
+ while (*f)
+ {
+ int c=*f++;
+ int N=1;
+ if (isdigit(*f))
+ {
+ N=0;
+ while (isdigit(*f)) N=10*N+(*f++)-'0';
+ }
+ while (N--) switch (c)
+ {
+ case OP_LITTLEENDIAN:
+ case OP_BIGENDIAN:
+ case OP_NATIVE:
+ {
+ swap=doendian(c);
+ N=0;
+ break;
+ }
+ case OP_STRING:
+ case OP_ZSTRING:
+ {
+ size_t l;
+ const char *a=luaL_checklstring(L,i++,&l);
+ luaL_addlstring(&b,a,l+(c==OP_ZSTRING));
+ break;
+ }
+ PACKSTRING(OP_BSTRING, unsigned char)
+ PACKSTRING(OP_WSTRING, unsigned short)
+ PACKSTRING(OP_SSTRING, size_t)
+ PACKNUMBER(OP_NUMBER, lua_Number)
+ PACKNUMBER(OP_DOUBLE, double)
+ PACKNUMBER(OP_FLOAT, float)
+ PACKNUMBER(OP_CHAR, int8_t)
+ PACKNUMBER(OP_BYTE, uint8_t)
+ PACKNUMBER(OP_SHORT, int16_t)
+ PACKNUMBER(OP_USHORT, uint16_t)
+ PACKNUMBER(OP_INT, int32_t)
+ PACKNUMBER(OP_UINT, uint32_t)
+ PACKNUMBER(OP_LONG, int64_t)
+ PACKNUMBER(OP_ULONG, uint64_t)
+ case ' ': case ',':
+ break;
+ default:
+ badcode(L,c);
+ break;
+ }
+ }
+ luaL_pushresult(&b);
+ return 1;
+}
+
+static const luaL_reg R[] =
+{
+ {"pack", l_pack},
+ {"unpack", l_unpack},
+ {NULL, NULL}
+};
+
+int luaopen_lpack(lua_State *L)
+{
+#ifdef USE_GLOBALS
+ lua_register(L,"bpack",l_pack);
+ lua_register(L,"bunpack",l_unpack);
+#else
+ luaI_openlib(L, LUA_STRLIBNAME, R, 0);
+#endif
+ return 0;
+}
diff --git a/accel-pppd/ctrl/l2tp/l2tp.c b/accel-pppd/ctrl/l2tp/l2tp.c
index e3db614a..0ad8649c 100644
--- a/accel-pppd/ctrl/l2tp/l2tp.c
+++ b/accel-pppd/ctrl/l2tp/l2tp.c
@@ -144,7 +144,7 @@ static void l2tp_disconnect(struct l2tp_conn_t *conn)
if (conn->tunnel_fd != -1)
close(conn->tunnel_fd);
- triton_event_fire(EV_CTRL_FINISHED, &conn->ppp);
+ triton_event_fire(EV_CTRL_FINISHED, &conn->ppp.ses);
log_ppp_info1("disconnected\n");
@@ -423,7 +423,7 @@ static int l2tp_connect(struct l2tp_conn_t *conn)
conn->ppp.ses.chan_name = _strdup(inet_ntoa(conn->addr.sin_addr));
- triton_event_fire(EV_CTRL_STARTED, &conn->ppp);
+ triton_event_fire(EV_CTRL_STARTED, &conn->ppp.ses);
if (establish_ppp(&conn->ppp))
return -1;
diff --git a/accel-pppd/ctrl/pppoe/pppoe.c b/accel-pppd/ctrl/pppoe/pppoe.c
index 7981eba1..2659a6f5 100644
--- a/accel-pppd/ctrl/pppoe/pppoe.c
+++ b/accel-pppd/ctrl/pppoe/pppoe.c
@@ -120,7 +120,7 @@ static void disconnect(struct pppoe_conn_t *conn)
close(conn->disc_sock);
- triton_event_fire(EV_CTRL_FINISHED, &conn->ppp);
+ triton_event_fire(EV_CTRL_FINISHED, &conn->ppp.ses);
log_ppp_info1("disconnected\n");
@@ -293,8 +293,8 @@ static struct pppoe_conn_t *allocate_channel(struct pppoe_serv_t *serv, const ui
triton_context_register(&conn->ctx, &conn->ppp.ses);
triton_context_wakeup(&conn->ctx);
- triton_event_fire(EV_CTRL_STARTING, &conn->ppp);
- triton_event_fire(EV_CTRL_STARTED, &conn->ppp);
+ triton_event_fire(EV_CTRL_STARTING, &conn->ppp.ses);
+ triton_event_fire(EV_CTRL_STARTED, &conn->ppp.ses);
conn->disc_sock = dup(serv->hnd.fd);
diff --git a/accel-pppd/ctrl/pptp/pptp.c b/accel-pppd/ctrl/pptp/pptp.c
index 59d50984..dddf5edc 100644
--- a/accel-pppd/ctrl/pptp/pptp.c
+++ b/accel-pppd/ctrl/pptp/pptp.c
@@ -91,7 +91,7 @@ static void disconnect(struct pptp_conn_t *conn)
} else if (conn->state != STATE_CLOSE)
__sync_sub_and_fetch(&stat_starting, 1);
- triton_event_fire(EV_CTRL_FINISHED, &conn->ppp);
+ triton_event_fire(EV_CTRL_FINISHED, &conn->ppp.ses);
log_ppp_info1("disconnected\n");
@@ -327,7 +327,7 @@ static int pptp_out_call_rqst(struct pptp_conn_t *conn)
conn->ppp.fd = pptp_sock;
conn->ppp.ses.chan_name = _strdup(inet_ntoa(dst_addr.sa_addr.pptp.sin_addr));
- triton_event_fire(EV_CTRL_STARTED, &conn->ppp);
+ triton_event_fire(EV_CTRL_STARTED, &conn->ppp.ses);
if (establish_ppp(&conn->ppp)) {
close(pptp_sock);
@@ -689,7 +689,7 @@ static int pptp_connect(struct triton_md_handler_t *h)
triton_timer_add(&conn->ctx, &conn->timeout_timer, 0);
triton_context_wakeup(&conn->ctx);
- triton_event_fire(EV_CTRL_STARTING, &conn->ppp);
+ triton_event_fire(EV_CTRL_STARTING, &conn->ppp.ses);
__sync_add_and_fetch(&stat_starting, 1);
}
diff --git a/accel-pppd/extra/pppd_compat.c b/accel-pppd/extra/pppd_compat.c
index 4ed7824e..fcb83c25 100644
--- a/accel-pppd/extra/pppd_compat.c
+++ b/accel-pppd/extra/pppd_compat.c
@@ -107,8 +107,9 @@ static void ip_change_handler(struct sigchld_handler_t *h, int status)
static void ev_ses_starting(struct ap_session *ses)
{
- struct pppd_compat_pd_t *pd = _malloc(sizeof(*pd));
-
+ struct pppd_compat_pd_t *pd;
+
+ pd = _malloc(sizeof(*pd));
if (!pd) {
log_emerg("pppd_compat: out of memory\n");
return;
@@ -232,17 +233,21 @@ static void ev_ses_finishing(struct ap_session *ses)
if (!pd)
return;
- memset(&ifreq, 0, sizeof(ifreq));
- ifreq.stats_ptr = (void *)&ifreq.stats;
- strcpy(ifreq.ifr__name, ses->ifname);
+ if (ses->ctrl->type == CTRL_TYPE_IPOE) {
- if (ioctl(sock_fd, SIOCGPPPSTATS, &ifreq)) {
- log_ppp_error("pppd_compat: failed to get ppp statistics: %s\n", strerror(errno));
- return;
- }
+ } else {
+ memset(&ifreq, 0, sizeof(ifreq));
+ ifreq.stats_ptr = (void *)&ifreq.stats;
+ strcpy(ifreq.ifr__name, ses->ifname);
- pd->bytes_sent = ifreq.stats.p.ppp_obytes;
- pd->bytes_rcvd = ifreq.stats.p.ppp_ibytes;
+ if (ioctl(sock_fd, SIOCGPPPSTATS, &ifreq)) {
+ log_ppp_error("pppd_compat: failed to get ppp statistics: %s\n", strerror(errno));
+ return;
+ }
+
+ pd->bytes_sent = ifreq.stats.p.ppp_obytes;
+ pd->bytes_rcvd = ifreq.stats.p.ppp_ibytes;
+ }
}
static void ev_ses_finished(struct ap_session *ses)
@@ -331,6 +336,9 @@ static void ev_radius_access_accept(struct ev_radius_t *ev)
{
struct pppd_compat_pd_t *pd = find_pd(ev->ses);
+ if (!pd)
+ return;
+
write_radattr(ev->ses, ev->reply, 0);
pd->radattr_saved = 1;
@@ -479,7 +487,7 @@ static struct pppd_compat_pd_t *find_pd(struct ap_session *ses)
}
}
- log_ppp_warn("pppd_compat: pd not found\n");
+ //log_ppp_warn("pppd_compat: pd not found\n");
return NULL;
}
diff --git a/accel-pppd/ifcfg.c b/accel-pppd/ifcfg.c
index a1bb2e34..11251e1a 100644
--- a/accel-pppd/ifcfg.c
+++ b/accel-pppd/ifcfg.c
@@ -9,6 +9,7 @@
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
+#include <linux/route.h>
#include "linux_ppp.h"
#include "triton.h"
@@ -55,6 +56,7 @@ void ap_session_ifup(struct ap_session *ses)
{
struct ipv6db_addr_t *a;
struct ifreq ifr;
+ struct rtentry rt;
struct in6_ifreq ifr6;
struct npioctl np;
struct sockaddr_in addr;
@@ -75,16 +77,34 @@ void ap_session_ifup(struct ap_session *ses)
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = ses->ipv4->addr;
- memcpy(&ifr.ifr_addr,&addr,sizeof(addr));
+ memcpy(&ifr.ifr_addr, &addr, sizeof(addr));
if (ioctl(sock_fd, SIOCSIFADDR, &ifr))
log_ppp_error("failed to set IPv4 address: %s\n", strerror(errno));
+
+ if (ses->ctrl->type == CTRL_TYPE_IPOE) {
+ addr.sin_addr.s_addr = 0xffffffff;
+ memcpy(&ifr.ifr_netmask, &addr, sizeof(addr));
+ if (ioctl(sock_fd, SIOCSIFNETMASK, &ifr))
+ log_ppp_error("failed to set IPv4 nask: %s\n", strerror(errno));
+ }
addr.sin_addr.s_addr = ses->ipv4->peer_addr;
- memcpy(&ifr.ifr_dstaddr,&addr,sizeof(addr));
-
- if (ioctl(sock_fd, SIOCSIFDSTADDR, &ifr))
- log_ppp_error("failed to set peer IPv4 address: %s\n", strerror(errno));
+
+ if (ses->ctrl->type == CTRL_TYPE_IPOE) {
+ memset(&rt, 0, sizeof(rt));
+ memcpy(&rt.rt_dst, &addr, sizeof(addr));
+ rt.rt_flags = RTF_HOST | RTF_UP;
+ rt.rt_metric = 1;
+ rt.rt_dev = ifr.ifr_name;
+ if (ioctl(sock_fd, SIOCADDRT, &rt, sizeof(rt)))
+ log_ppp_error("failed to add route: %s\n", strerror(errno));
+ } else {
+ memcpy(&ifr.ifr_dstaddr, &addr, sizeof(addr));
+
+ if (ioctl(sock_fd, SIOCSIFDSTADDR, &ifr))
+ log_ppp_error("failed to set peer IPv4 address: %s\n", strerror(errno));
+ }
}
if (ses->ipv6) {
@@ -93,13 +113,16 @@ void ap_session_ifup(struct ap_session *ses)
devconf(ses, "forwarding", "1");
memset(&ifr6, 0, sizeof(ifr6));
- ifr6.ifr6_addr.s6_addr32[0] = htons(0xfe80);
- *(uint64_t *)(ifr6.ifr6_addr.s6_addr + 8) = ses->ipv6->intf_id;
- ifr6.ifr6_prefixlen = 64;
- ifr6.ifr6_ifindex = ses->ifindex;
+
+ if (ses->ctrl->type != CTRL_TYPE_IPOE) {
+ ifr6.ifr6_addr.s6_addr32[0] = htons(0xfe80);
+ *(uint64_t *)(ifr6.ifr6_addr.s6_addr + 8) = ses->ipv6->intf_id;
+ ifr6.ifr6_prefixlen = 64;
+ ifr6.ifr6_ifindex = ses->ifindex;
- if (ioctl(sock6_fd, SIOCSIFADDR, &ifr6))
- log_ppp_error("faild to set LL IPv6 address: %s\n", strerror(errno));
+ if (ioctl(sock6_fd, SIOCSIFADDR, &ifr6))
+ log_ppp_error("faild to set LL IPv6 address: %s\n", strerror(errno));
+ }
list_for_each_entry(a, &ses->ipv6->addr_list, entry) {
if (a->prefix_len == 128)
@@ -154,7 +177,9 @@ void __export ap_session_ifdown(struct ap_session *ses)
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, ses->ifname);
- ioctl(sock_fd, SIOCSIFFLAGS, &ifr);
+
+ if (ses->ctrl->type != CTRL_TYPE_IPOE)
+ ioctl(sock_fd, SIOCSIFFLAGS, &ifr);
if (ses->ipv4) {
memset(&addr, 0, sizeof(addr));
diff --git a/accel-pppd/include/ap_session.h b/accel-pppd/include/ap_session.h
index 681d05fb..b964c80d 100644
--- a/accel-pppd/include/ap_session.h
+++ b/accel-pppd/include/ap_session.h
@@ -2,7 +2,7 @@
#define __AP_SESSION_H__
#define AP_SESSIONID_LEN 16
-#define AP_IFNAME_LEN 10
+#define AP_IFNAME_LEN 16
#define AP_STATE_STARTING 1
#define AP_STATE_ACTIVE 2
diff --git a/accel-pppd/include/iplink.h b/accel-pppd/include/iplink.h
new file mode 120000
index 00000000..7f0f09d4
--- /dev/null
+++ b/accel-pppd/include/iplink.h
@@ -0,0 +1 @@
+../libnetlink/iplink.h \ No newline at end of file
diff --git a/accel-pppd/include/libnetlink.h b/accel-pppd/include/libnetlink.h
new file mode 120000
index 00000000..d494ddb4
--- /dev/null
+++ b/accel-pppd/include/libnetlink.h
@@ -0,0 +1 @@
+../libnetlink/libnetlink.h \ No newline at end of file
diff --git a/accel-pppd/ipdb.h b/accel-pppd/ipdb.h
index 0d13b76e..69cb12f3 100644
--- a/accel-pppd/ipdb.h
+++ b/accel-pppd/ipdb.h
@@ -11,6 +11,7 @@ struct ipv4db_item_t
struct ipdb_t *owner;
in_addr_t addr;
in_addr_t peer_addr;
+ int mask;
};
struct ipv6db_addr_t
diff --git a/accel-pppd/libnetlink/iplink.c b/accel-pppd/libnetlink/iplink.c
new file mode 100644
index 00000000..ba3ada06
--- /dev/null
+++ b/accel-pppd/libnetlink/iplink.c
@@ -0,0 +1,77 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <net/if_arp.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/uio.h>
+
+#include "libnetlink.h"
+#include "iplink.h"
+#include "triton.h"
+#include "log.h"
+
+struct arg
+{
+ iplink_list_func func;
+ void *arg;
+};
+
+static int store_nlmsg(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
+{
+ struct ifinfomsg *ifi = NLMSG_DATA(n);
+ struct rtattr *tb[IFLA_MAX + 1];
+ struct arg *a = arg;
+
+ if (n->nlmsg_type != RTM_NEWLINK)
+ return 0;
+
+ if (n->nlmsg_len < NLMSG_LENGTH(sizeof(*ifi)))
+ return -1;
+
+ memset(tb, 0, sizeof(tb));
+ parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n));
+
+ if (tb[IFLA_IFNAME] == NULL)
+ return 0;
+
+ //printf("%i %s\n", ifi->ifi_index, RTA_DATA(tb[IFLA_IFNAME]));
+
+ return a->func(ifi->ifi_index, ifi->ifi_flags, RTA_DATA(tb[IFLA_IFNAME]), a->arg);
+}
+
+int __export iplink_list(iplink_list_func func, void *arg)
+{
+ struct rtnl_handle rth;
+ struct arg a = { .func = func, .arg = arg };
+
+ if (rtnl_open(&rth, 0)) {
+ log_emerg("iplink: cannot open rtnetlink\n");
+ return -1;
+ }
+
+ if (rtnl_wilddump_request(&rth, AF_PACKET, RTM_GETLINK) < 0) {
+ log_emerg("iplink: cannot send dump request\n");
+ goto out_err;
+ }
+
+ if (rtnl_dump_filter(&rth, store_nlmsg, &a, NULL, NULL) < 0) {
+ log_emerg("iplink: dump terminated\n");
+ goto out_err;
+ }
+
+ rtnl_close(&rth);
+
+ return 0;
+
+out_err:
+ rtnl_close(&rth);
+
+ return -1;
+}
+
diff --git a/accel-pppd/libnetlink/iplink.h b/accel-pppd/libnetlink/iplink.h
new file mode 100644
index 00000000..70c7c600
--- /dev/null
+++ b/accel-pppd/libnetlink/iplink.h
@@ -0,0 +1,8 @@
+#ifndef __IPLINK_H
+#define __IPLINK_H
+
+typedef int (*iplink_list_func)(int index, int flags, const char *name, void *arg);
+
+int iplink_list(iplink_list_func func, void *arg);
+
+#endif
diff --git a/accel-pppd/shaper/libnetlink.c b/accel-pppd/libnetlink/libnetlink.c
index 74cd5cb5..55a1a67a 100644
--- a/accel-pppd/shaper/libnetlink.c
+++ b/accel-pppd/libnetlink/libnetlink.c
@@ -26,9 +26,11 @@
#include "libnetlink.h"
#include "log.h"
+#define __export __attribute__((visibility("default")))
+
int rcvbuf = 1024 * 1024;
-void rtnl_close(struct rtnl_handle *rth)
+void __export rtnl_close(struct rtnl_handle *rth)
{
if (rth->fd >= 0) {
close(rth->fd);
@@ -36,7 +38,7 @@ void rtnl_close(struct rtnl_handle *rth)
}
}
-int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions,
+int __export rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions,
int protocol)
{
socklen_t addr_len;
@@ -85,12 +87,12 @@ int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions,
return 0;
}
-int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions)
+int __export rtnl_open(struct rtnl_handle *rth, unsigned subscriptions)
{
return rtnl_open_byproto(rth, subscriptions, NETLINK_ROUTE);
}
-int rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type)
+int __export rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type)
{
struct {
struct nlmsghdr nlh;
@@ -108,12 +110,12 @@ int rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type)
return send(rth->fd, (void*)&req, sizeof(req), 0);
}
-int rtnl_send(struct rtnl_handle *rth, const char *buf, int len)
+int __export rtnl_send(struct rtnl_handle *rth, const char *buf, int len)
{
return send(rth->fd, buf, len, 0);
}
-int rtnl_send_check(struct rtnl_handle *rth, const char *buf, int len)
+int __export rtnl_send_check(struct rtnl_handle *rth, const char *buf, int len)
{
struct nlmsghdr *h;
int status;
@@ -146,7 +148,7 @@ int rtnl_send_check(struct rtnl_handle *rth, const char *buf, int len)
return 0;
}
-int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)
+int __export rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)
{
struct nlmsghdr nlh;
struct sockaddr_nl nladdr;
@@ -173,7 +175,7 @@ int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)
return sendmsg(rth->fd, &msg, 0);
}
-int rtnl_dump_filter_l(struct rtnl_handle *rth,
+int __export rtnl_dump_filter_l(struct rtnl_handle *rth,
const struct rtnl_dump_filter_arg *arg)
{
struct sockaddr_nl nladdr;
@@ -266,7 +268,7 @@ skip_it:
}
}
-int rtnl_dump_filter(struct rtnl_handle *rth,
+int __export rtnl_dump_filter(struct rtnl_handle *rth,
rtnl_filter_t filter,
void *arg1,
rtnl_filter_t junk,
@@ -280,7 +282,7 @@ int rtnl_dump_filter(struct rtnl_handle *rth,
return rtnl_dump_filter_l(rth, a);
}
-int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
+int __export rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
unsigned groups, struct nlmsghdr *answer,
rtnl_filter_t junk,
void *jarg, int ignore_einval)
@@ -405,7 +407,7 @@ int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
}
}
-int rtnl_listen(struct rtnl_handle *rtnl,
+int __export rtnl_listen(struct rtnl_handle *rtnl,
rtnl_filter_t handler,
void *jarg)
{
@@ -480,7 +482,7 @@ int rtnl_listen(struct rtnl_handle *rtnl,
}
}
-int rtnl_from_file(FILE *rtnl, rtnl_filter_t handler,
+int __export rtnl_from_file(FILE *rtnl, rtnl_filter_t handler,
void *jarg)
{
int status;
@@ -535,7 +537,7 @@ int rtnl_from_file(FILE *rtnl, rtnl_filter_t handler,
}
}
-int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data)
+int __export addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data)
{
int len = RTA_LENGTH(4);
struct rtattr *rta;
@@ -551,7 +553,7 @@ int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data)
return 0;
}
-int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
+int __export addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
int alen)
{
int len = RTA_LENGTH(alen);
@@ -569,7 +571,7 @@ int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
return 0;
}
-int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len)
+int __export addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len)
{
if (NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len) > maxlen) {
log_error("libnetlink: ""addraw_l ERROR: message exceeded bound of %d\n",maxlen);
@@ -582,7 +584,7 @@ int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len)
return 0;
}
-struct rtattr *addattr_nest(struct nlmsghdr *n, int maxlen, int type)
+struct rtattr __export *addattr_nest(struct nlmsghdr *n, int maxlen, int type)
{
struct rtattr *nest = NLMSG_TAIL(n);
@@ -590,13 +592,13 @@ struct rtattr *addattr_nest(struct nlmsghdr *n, int maxlen, int type)
return nest;
}
-int addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest)
+int __export addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest)
{
nest->rta_len = (void *)NLMSG_TAIL(n) - (void *)nest;
return n->nlmsg_len;
}
-struct rtattr *addattr_nest_compat(struct nlmsghdr *n, int maxlen, int type,
+struct rtattr __export *addattr_nest_compat(struct nlmsghdr *n, int maxlen, int type,
const void *data, int len)
{
struct rtattr *start = NLMSG_TAIL(n);
@@ -606,7 +608,7 @@ struct rtattr *addattr_nest_compat(struct nlmsghdr *n, int maxlen, int type,
return start;
}
-int addattr_nest_compat_end(struct nlmsghdr *n, struct rtattr *start)
+int __export addattr_nest_compat_end(struct nlmsghdr *n, struct rtattr *start)
{
struct rtattr *nest = (void *)start + NLMSG_ALIGN(start->rta_len);
@@ -615,7 +617,7 @@ int addattr_nest_compat_end(struct nlmsghdr *n, struct rtattr *start)
return n->nlmsg_len;
}
-int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data)
+int __export rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data)
{
int len = RTA_LENGTH(4);
struct rtattr *subrta;
@@ -632,7 +634,7 @@ int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data)
return 0;
}
-int rta_addattr_l(struct rtattr *rta, int maxlen, int type,
+int __export rta_addattr_l(struct rtattr *rta, int maxlen, int type,
const void *data, int alen)
{
struct rtattr *subrta;
diff --git a/accel-pppd/shaper/libnetlink.h b/accel-pppd/libnetlink/libnetlink.h
index f68bf8a1..f68bf8a1 100644
--- a/accel-pppd/shaper/libnetlink.h
+++ b/accel-pppd/libnetlink/libnetlink.h
diff --git a/accel-pppd/radius/auth.c b/accel-pppd/radius/auth.c
index 6a0b3a96..6cb4e803 100644
--- a/accel-pppd/radius/auth.c
+++ b/accel-pppd/radius/auth.c
@@ -552,3 +552,31 @@ out:
}
+int rad_auth_null(struct radius_pd_t *rpd, const char *username, va_list args)
+{
+ struct rad_req_t *req;
+ int r = PWDB_DENIED;
+
+ req = rad_req_alloc(rpd, CODE_ACCESS_REQUEST, username);
+ if (!req)
+ return PWDB_DENIED;
+
+ if (conf_sid_in_auth)
+ if (rad_packet_add_str(req->pack, NULL, "Acct-Session-Id", rpd->ses->sessionid))
+ return -1;
+
+ r = rad_auth_send(req);
+ if (r == PWDB_SUCCESS) {
+ struct ev_radius_t ev = {
+ .ses = rpd->ses,
+ .request = req->pack,
+ .reply = req->reply,
+ };
+ triton_event_fire(EV_RADIUS_ACCESS_ACCEPT, &ev);
+ }
+
+ rad_req_free(req);
+
+ return r;
+}
+
diff --git a/accel-pppd/radius/radius.c b/accel-pppd/radius/radius.c
index b654f29c..d880ad01 100644
--- a/accel-pppd/radius/radius.c
+++ b/accel-pppd/radius/radius.c
@@ -164,7 +164,9 @@ static int check(struct pwdb_t *pwdb, struct ap_session *ses, const char *userna
r = rad_auth_mschap_v2(rpd, username, args);
break;
}
- break;
+ case 0:
+ r = rad_auth_null(rpd, username, args);
+ break;
}
va_end(args);
diff --git a/accel-pppd/radius/radius_p.h b/accel-pppd/radius/radius_p.h
index e2c48bf9..f8adb465 100644
--- a/accel-pppd/radius/radius_p.h
+++ b/accel-pppd/radius/radius_p.h
@@ -154,6 +154,7 @@ int rad_auth_pap(struct radius_pd_t *rpd, const char *username, va_list args);
int rad_auth_chap_md5(struct radius_pd_t *rpd, const char *username, va_list args);
int rad_auth_mschap_v1(struct radius_pd_t *rpd, const char *username, va_list args);
int rad_auth_mschap_v2(struct radius_pd_t *rpd, const char *username, va_list args);
+int rad_auth_null(struct radius_pd_t *rpd, const char *username, va_list args);
int rad_acct_start(struct radius_pd_t *rpd);
void rad_acct_stop(struct radius_pd_t *rpd);
diff --git a/accel-pppd/radius/req.c b/accel-pppd/radius/req.c
index 33273b43..f452c425 100644
--- a/accel-pppd/radius/req.c
+++ b/accel-pppd/radius/req.c
@@ -71,12 +71,21 @@ struct rad_req_t *rad_req_alloc(struct radius_pd_t *rpd, int code, const char *u
if (rad_packet_add_int(req->pack, NULL, "NAS-Port", ppp->ses.unit_idx))
goto out_err;
}
- if (rad_packet_add_val(req->pack, NULL, "NAS-Port-Type", "Virtual"))
- goto out_err;
- if (rad_packet_add_val(req->pack, NULL, "Service-Type", "Framed-User"))
- goto out_err;
- if (rad_packet_add_val(req->pack, NULL, "Framed-Protocol", "PPP"))
- goto out_err;
+
+ if (req->rpd->ses->ctrl->type == CTRL_TYPE_IPOE) {
+ if (rad_packet_add_val(req->pack, NULL, "NAS-Port-Type", "Ethernet"))
+ goto out_err;
+ } else {
+ if (rad_packet_add_val(req->pack, NULL, "NAS-Port-Type", "Virtual"))
+ goto out_err;
+
+ if (rad_packet_add_val(req->pack, NULL, "Service-Type", "Framed-User"))
+ goto out_err;
+
+ if (rad_packet_add_val(req->pack, NULL, "Framed-Protocol", "PPP"))
+ goto out_err;
+ }
+
if (rpd->ses->ctrl->calling_station_id)
if (rad_packet_add_str(req->pack, NULL, "Calling-Station-Id", rpd->ses->ctrl->calling_station_id))
goto out_err;
diff --git a/accel-pppd/shaper/CMakeLists.txt b/accel-pppd/shaper/CMakeLists.txt
index 515fd839..3c1ac951 100644
--- a/accel-pppd/shaper/CMakeLists.txt
+++ b/accel-pppd/shaper/CMakeLists.txt
@@ -1,4 +1,4 @@
-ADD_LIBRARY(shaper SHARED shaper.c limiter.c leaf_qdisc.c tc_core.c libnetlink.c)
+ADD_LIBRARY(shaper SHARED shaper.c limiter.c leaf_qdisc.c tc_core.c)
INSTALL(TARGETS shaper
LIBRARY DESTINATION lib/accel-ppp