summaryrefslogtreecommitdiff
path: root/accel-pppd
diff options
context:
space:
mode:
Diffstat (limited to 'accel-pppd')
-rw-r--r--accel-pppd/CMakeLists.txt5
-rw-r--r--accel-pppd/accel-ppp.conf10
-rw-r--r--accel-pppd/accel-ppp.conf.53
-rw-r--r--accel-pppd/cli/std_cmd.c2
-rw-r--r--accel-pppd/cli/tcp.c49
-rw-r--r--accel-pppd/cli/telnet.c55
-rw-r--r--accel-pppd/ctrl/ipoe/CMakeLists.txt4
-rw-r--r--accel-pppd/ctrl/ipoe/arp.c33
-rw-r--r--accel-pppd/ctrl/ipoe/dhcp_attr_defs.h311
-rw-r--r--accel-pppd/ctrl/ipoe/dhcpv4.c42
-rw-r--r--accel-pppd/ctrl/ipoe/dhcpv4.h2
-rw-r--r--accel-pppd/ctrl/ipoe/ipoe.c402
-rw-r--r--accel-pppd/ctrl/ipoe/ipoe.h5
-rw-r--r--accel-pppd/ctrl/ipoe/ipoe_netlink.c8
-rw-r--r--accel-pppd/ctrl/ipoe/lua.c16
-rw-r--r--accel-pppd/ctrl/ipoe/lua_bit.c189
-rw-r--r--accel-pppd/ctrl/l2tp/l2tp.c30
-rw-r--r--accel-pppd/ctrl/pppoe/CMakeLists.txt2
-rw-r--r--accel-pppd/ctrl/pppoe/disc.c62
-rw-r--r--accel-pppd/ctrl/pppoe/pppoe.c54
-rw-r--r--accel-pppd/ctrl/pppoe/pppoe.h2
-rw-r--r--accel-pppd/ctrl/pptp/pptp.c26
-rw-r--r--accel-pppd/extra/chap-secrets.c15
-rw-r--r--accel-pppd/extra/net-snmp/sessionTable_data_get.h4
-rw-r--r--accel-pppd/extra/pppd_compat.c119
-rw-r--r--accel-pppd/ifcfg.c82
-rw-r--r--accel-pppd/include/ap_net.h20
-rw-r--r--accel-pppd/include/ap_session.h9
-rw-r--r--accel-pppd/include/events.h1
l---------[-rw-r--r--]accel-pppd/include/ppp_auth.h38
-rw-r--r--accel-pppd/iprange.c287
-rw-r--r--accel-pppd/iprange.h10
-rw-r--r--accel-pppd/ipv6/dhcpv6.c34
-rw-r--r--accel-pppd/ipv6/nd.c21
-rw-r--r--accel-pppd/libnetlink/iputils.c282
-rw-r--r--accel-pppd/libnetlink/iputils.h2
-rw-r--r--accel-pppd/libnetlink/libnetlink.h2
-rw-r--r--accel-pppd/main.c62
-rw-r--r--accel-pppd/memdebug.c3
-rw-r--r--accel-pppd/net.c332
-rw-r--r--accel-pppd/net/CMakeLists.txt7
-rw-r--r--accel-pppd/net/dp.c493
l---------accel-pppd/net/if_dp.h1
-rw-r--r--accel-pppd/ppp/lcp_opt_pcomp.c4
-rw-r--r--accel-pppd/ppp/ppp.c70
-rw-r--r--accel-pppd/ppp/ppp_ifcfg.c182
-rw-r--r--accel-pppd/ppp/ppp_notify.c54
-rw-r--r--accel-pppd/ppp/ppp_pd.c14
-rw-r--r--accel-pppd/radius/acct.c22
-rw-r--r--accel-pppd/radius/dict.c133
-rw-r--r--accel-pppd/radius/dict/dictionary1
-rw-r--r--accel-pppd/radius/dict/dictionary.dhcp442
-rw-r--r--accel-pppd/radius/dm_coa.c5
-rw-r--r--accel-pppd/radius/packet.c164
-rw-r--r--accel-pppd/radius/radius.c33
-rw-r--r--accel-pppd/radius/radius.h13
-rw-r--r--accel-pppd/radius/radius_p.h4
-rw-r--r--accel-pppd/radius/req.c4
-rw-r--r--accel-pppd/radius/serv.c2
-rw-r--r--accel-pppd/session.c15
-rw-r--r--accel-pppd/shaper/limiter.c64
-rw-r--r--accel-pppd/shaper/shaper.c6
-rw-r--r--accel-pppd/triton/list.h23
-rw-r--r--accel-pppd/utils.c27
-rw-r--r--accel-pppd/utils.h2
-rw-r--r--accel-pppd/vlan-mon/vlan_mon.c8
66 files changed, 2969 insertions, 1459 deletions
diff --git a/accel-pppd/CMakeLists.txt b/accel-pppd/CMakeLists.txt
index 505beed3..8ffcbf4d 100644
--- a/accel-pppd/CMakeLists.txt
+++ b/accel-pppd/CMakeLists.txt
@@ -47,11 +47,12 @@ IF (SHAPER)
ADD_SUBDIRECTORY(shaper)
ENDIF (SHAPER)
-ADD_SUBDIRECTORY(net)
-
INCLUDE(CheckIncludeFile)
CHECK_INCLUDE_FILE("linux/netfilter/ipset/ip_set.h" HAVE_IPSET)
+INCLUDE(CheckFunctionExists)
+CHECK_FUNCTION_EXISTS(setns HAVE_SETNS)
+
ADD_EXECUTABLE(accel-pppd
memdebug.c
session.c
diff --git a/accel-pppd/accel-ppp.conf b/accel-pppd/accel-ppp.conf
index 2fcb85ad..474d1134 100644
--- a/accel-pppd/accel-ppp.conf
+++ b/accel-pppd/accel-ppp.conf
@@ -30,6 +30,8 @@ pppd_compat
#ipv6_dhcp
#ipv6pool
+#net-accel-dp
+
[core]
log-error=/var/log/accel-ppp/core.log
thread-count=4
@@ -38,6 +40,7 @@ thread-count=4
#single-session=replace
#sid-case=upper
#sid-source=seq
+#max-sessions=1000
[ppp]
verbose=1
@@ -58,6 +61,7 @@ lcp-echo-interval=20
#lcp-echo-failure=3
lcp-echo-timeout=120
unit-cache=1
+#unit-preallocate=1
[auth]
#any-login=0
@@ -81,7 +85,7 @@ called-sid=mac
#vlan-mon=eth0,10-200
#vlan-timeout=60
#vlan-name=%I.%N
-#interface=eth1,padi-limit=1000
+#interface=eth1,padi-limit=1000,net=accel-dp
interface=eth0
[l2tp]
@@ -122,6 +126,7 @@ start=dhcpv4
#nat=0
#proto=100
#relay=10.10.10.10
+#vendor=Custom
#attr-dhcp-client-ip=DHCP-Client-IP-Address
#attr-dhcp-router-ip=DHCP-Router-IP-Address
#attr-dhcp-mask=DHCP-Mask
@@ -267,3 +272,6 @@ verbose=1
pref-lifetime=604800
valid-lifetime=2592000
route-via-gw=1
+
+[accel-dp]
+socket=/var/run/accel-dp.sock
diff --git a/accel-pppd/accel-ppp.conf.5 b/accel-pppd/accel-ppp.conf.5
index 4c25a495..bfc5427f 100644
--- a/accel-pppd/accel-ppp.conf.5
+++ b/accel-pppd/accel-ppp.conf.5
@@ -195,6 +195,9 @@ Specifies timeout in seconds to wait for any peer activity. If this option speci
.BI "unit-cache=" n
Specifies number of interfaces to keep in cache. It means that don't destory interface after corresponding session is destoyed, instead place it to cache and use it later for new sessions repeatedly.
This should reduce kernel-level interface creation/deletion rate lack.
+.TP
+.BI "unit-preallocate=" 0|1
+If set to 1 then allocate ppp unit (interface) before authorization, so Nas-Port and Nas-Port-Id would be defined in Access-Request phase.
.SH [ipoe]
.TP
.BI "verbose=" n
diff --git a/accel-pppd/cli/std_cmd.c b/accel-pppd/cli/std_cmd.c
index 62327f92..500102b0 100644
--- a/accel-pppd/cli/std_cmd.c
+++ b/accel-pppd/cli/std_cmd.c
@@ -20,7 +20,7 @@ void core_restart(int);
static int show_stat_exec(const char *cmd, char * const *fields, int fields_cnt, void *client)
{
struct timespec ts;
- time_t dt;
+ unsigned long dt;
int day,hour;
char statm_fname[128];
FILE *f;
diff --git a/accel-pppd/cli/tcp.c b/accel-pppd/cli/tcp.c
index 2a6bfdee..051ff84c 100644
--- a/accel-pppd/cli/tcp.c
+++ b/accel-pppd/cli/tcp.c
@@ -95,7 +95,7 @@ static int cli_client_send(struct cli_client_t *tcln, const void *_buf, int size
if (cln->disconnect)
return -1;
- if (!list_empty(&cln->xmit_queue)) {
+ if (cln->xmit_buf) {
b = _malloc(sizeof(*b) + size);
b->size = size;
memcpy(b->buf, buf, size);
@@ -109,7 +109,7 @@ static int cli_client_send(struct cli_client_t *tcln, const void *_buf, int size
if (errno == EAGAIN) {
b = _malloc(sizeof(*b) + size - n);
b->size = size - n;
- memcpy(b->buf, buf, size - n);
+ memcpy(b->buf, buf + n, size - n);
queue_buffer(cln, b);
triton_md_enable_handler(&cln->hnd, MD_MODE_WRITE);
@@ -147,7 +147,7 @@ static int cln_read(struct triton_md_handler_t *h)
while (1) {
n = read(h->fd, cln->cmdline + cln->recv_pos, RECV_BUF_SIZE - 1 - cln->recv_pos);
if (n == 0)
- break;
+ goto disconn_soft;
if (n < 0) {
if (errno != EAGAIN)
log_error("cli: read: %s\n", strerror(errno));
@@ -162,7 +162,7 @@ static int cln_read(struct triton_md_handler_t *h)
if (!d) {
if (cln->recv_pos == RECV_BUF_SIZE - 1) {
log_warn("cli: tcp: recv buffer overflow\n");
- goto drop;
+ goto disconn_hard;
}
break;
}
@@ -171,7 +171,7 @@ static int cln_read(struct triton_md_handler_t *h)
if (!cln->auth) {
if (strcmp((char *)cln->cmdline, conf_cli_passwd))
- goto drop;
+ goto disconn_hard;
cln->auth = 1;
} else {
if (conf_verbose == 2)
@@ -181,15 +181,25 @@ static int cln_read(struct triton_md_handler_t *h)
}
if (cln->disconnect)
- goto drop;
+ goto disconn_soft;
cln->recv_pos -= (uint8_t *)d + 1 - cln->cmdline;
memmove(cln->cmdline, d + 1, cln->recv_pos);
}
}
-drop:
+disconn_soft:
+ /* Wait for pending data to be transmitted before disconnecting */
+ if (cln->xmit_buf) {
+ triton_md_disable_handler(&cln->hnd, MD_MODE_READ);
+ cln->disconnect = 1;
+
+ return 0;
+ }
+
+disconn_hard:
disconnect(cln);
+
return -1;
}
@@ -198,10 +208,7 @@ static int cln_write(struct triton_md_handler_t *h)
struct tcp_client_t *cln = container_of(h, typeof(*cln), hnd);
int k;
- if (!cln->xmit_buf)
- return 0;
-
- while (1) {
+ while (cln->xmit_buf) {
for (; cln->xmit_pos < cln->xmit_buf->size; cln->xmit_pos += k) {
k = write(cln->hnd.fd, cln->xmit_buf->buf + cln->xmit_pos, cln->xmit_buf->size - cln->xmit_pos);
if (k < 0) {
@@ -209,8 +216,7 @@ static int cln_write(struct triton_md_handler_t *h)
return 0;
if (errno != EPIPE)
log_error("cli: tcp: write: %s\n", strerror(errno));
- disconnect(cln);
- return -1;
+ goto disconn;
}
}
@@ -219,16 +225,25 @@ static int cln_write(struct triton_md_handler_t *h)
if (list_empty(&cln->xmit_queue)) {
cln->xmit_buf = NULL;
- break;
+ } else {
+ cln->xmit_buf = list_first_entry(&cln->xmit_queue,
+ typeof(*cln->xmit_buf),
+ entry);
+ list_del(&cln->xmit_buf->entry);
}
-
- cln->xmit_buf = list_entry(cln->xmit_queue.next, typeof(*cln->xmit_buf), entry);
- list_del(&cln->xmit_buf->entry);
}
+ if (cln->disconnect)
+ goto disconn;
+
triton_md_disable_handler(&cln->hnd, MD_MODE_WRITE);
return 0;
+
+disconn:
+ disconnect(cln);
+
+ return -1;
}
static int serv_read(struct triton_md_handler_t *h)
diff --git a/accel-pppd/cli/telnet.c b/accel-pppd/cli/telnet.c
index de2f39ff..9ef2ea84 100644
--- a/accel-pppd/cli/telnet.c
+++ b/accel-pppd/cli/telnet.c
@@ -143,7 +143,7 @@ static int telnet_send(struct telnet_client_t *cln, const void *_buf, int size)
if (cln->disconnect)
return -1;
- if (!list_empty(&cln->xmit_queue)) {
+ if (cln->xmit_buf) {
b = _malloc(sizeof(*b) + size);
b->size = size;
memcpy(b->buf, buf, size);
@@ -157,7 +157,7 @@ static int telnet_send(struct telnet_client_t *cln, const void *_buf, int size)
if (errno == EAGAIN) {
b = _malloc(sizeof(*b) + size - n);
b->size = size - n;
- memcpy(b->buf, buf, size - n);
+ memcpy(b->buf, buf + n, size - n);
queue_buffer(cln, b);
triton_md_enable_handler(&cln->hnd, MD_MODE_WRITE);
@@ -477,10 +477,8 @@ static int cln_read(struct triton_md_handler_t *h)
while (1) {
n = read(h->fd, recv_buf, RECV_BUF_SIZE);
- if (n == 0) {
- disconnect(cln);
- return -1;
- }
+ if (n == 0)
+ goto disconn_soft;
if (n < 0) {
if (errno != EAGAIN)
log_error("cli: telnet: read: %s\n", strerror(errno));
@@ -492,13 +490,25 @@ static int cln_read(struct triton_md_handler_t *h)
if (telnet_input_char(cln, recv_buf[i]))
break;
}
- if (cln->disconnect) {
- disconnect(cln);
- return -1;
- }
+
+ if (cln->disconnect)
+ goto disconn_soft;
}
return 0;
+
+disconn_soft:
+ /* Wait for pending data to be transmitted before disconnecting */
+ if (cln->xmit_buf) {
+ triton_md_disable_handler(&cln->hnd, MD_MODE_READ);
+ cln->disconnect = 1;
+
+ return 0;
+ }
+
+ disconnect(cln);
+
+ return -1;
}
static int cln_write(struct triton_md_handler_t *h)
@@ -506,10 +516,7 @@ static int cln_write(struct triton_md_handler_t *h)
struct telnet_client_t *cln = container_of(h, typeof(*cln), hnd);
int k;
- if (!cln->xmit_buf)
- return 0;
-
- while (1) {
+ while (cln->xmit_buf) {
for (; cln->xmit_pos < cln->xmit_buf->size; cln->xmit_pos += k) {
k = write(cln->hnd.fd, cln->xmit_buf->buf + cln->xmit_pos, cln->xmit_buf->size - cln->xmit_pos);
if (k < 0) {
@@ -517,8 +524,7 @@ static int cln_write(struct triton_md_handler_t *h)
return 0;
if (errno != EPIPE)
log_error("cli: telnet: write: %s\n", strerror(errno));
- disconnect(cln);
- return -1;
+ goto disconn;
}
}
@@ -527,16 +533,25 @@ static int cln_write(struct triton_md_handler_t *h)
if (list_empty(&cln->xmit_queue)) {
cln->xmit_buf = NULL;
- break;
+ } else {
+ cln->xmit_buf = list_first_entry(&cln->xmit_queue,
+ typeof(*cln->xmit_buf),
+ entry);
+ list_del(&cln->xmit_buf->entry);
}
-
- cln->xmit_buf = list_entry(cln->xmit_queue.next, typeof(*cln->xmit_buf), entry);
- list_del(&cln->xmit_buf->entry);
}
+ if (cln->disconnect)
+ goto disconn;
+
triton_md_disable_handler(&cln->hnd, MD_MODE_WRITE);
return 0;
+
+disconn:
+ disconnect(cln);
+
+ return -1;
}
static int serv_read(struct triton_md_handler_t *h)
diff --git a/accel-pppd/ctrl/ipoe/CMakeLists.txt b/accel-pppd/ctrl/ipoe/CMakeLists.txt
index f15365ab..bba74633 100644
--- a/accel-pppd/ctrl/ipoe/CMakeLists.txt
+++ b/accel-pppd/ctrl/ipoe/CMakeLists.txt
@@ -16,7 +16,7 @@ IF (LUA)
ENDIF (NOT LUA51_FOUND)
INCLUDE_DIRECTORIES(${LUA_INCLUDE_DIR})
ADD_DEFINITIONS(-DUSE_LUA)
- SET(sources ${sources} lua.c lua_lpack.c)
+ SET(sources ${sources} lua.c lua_lpack.c lua_bit.c)
ENDIF (LUA)
ADD_LIBRARY(ipoe SHARED ${sources})
@@ -24,5 +24,7 @@ IF (LUA)
TARGET_LINK_LIBRARIES(ipoe ${LUA_LIBRARIES})
ENDIF(LUA)
TARGET_LINK_LIBRARIES(ipoe vlan-mon)
+set_property(TARGET ipoe PROPERTY CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
+set_property(TARGET ipoe PROPERTY INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}/accel-ppp)
INSTALL(TARGETS ipoe LIBRARY DESTINATION lib${LIB_SUFFIX}/accel-ppp)
diff --git a/accel-pppd/ctrl/ipoe/arp.c b/accel-pppd/ctrl/ipoe/arp.c
index 58533582..36b03447 100644
--- a/accel-pppd/ctrl/ipoe/arp.c
+++ b/accel-pppd/ctrl/ipoe/arp.c
@@ -39,6 +39,8 @@ struct arp_tree {
static mempool_t arp_pool;
static mempool_t arp_hdr_pool;
+static uint8_t bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
#define HASH_BITS 0xff
static struct arp_tree *arp_tree;
@@ -63,6 +65,12 @@ static void arp_ctx_read(struct _arphdr *ah)
ah2.ar_op = htons(ARPOP_REPLY);
pthread_mutex_lock(&ipoe->lock);
+ if (ah->ar_op == htons(ARPOP_REPLY)) {
+ ipoe_serv_recv_arp(ipoe, ah);
+ pthread_mutex_unlock(&ipoe->lock);
+ goto out;
+ }
+
list_for_each_entry(ses, &ipoe->sessions, entry) {
if (ses->yiaddr == ah->ar_spa) {
ses1 = ses;
@@ -80,8 +88,14 @@ static void arp_ctx_read(struct _arphdr *ah)
break;
}
- if (!ses1 || (ses1->ses.state != AP_STATE_ACTIVE) ||
- (ses2 && ses2->ses.state != AP_STATE_ACTIVE)) {
+ if (!ses1 && ipoe->opt_up) {
+ ipoe_serv_recv_arp(ipoe, ah);
+ pthread_mutex_unlock(&ipoe->lock);
+ goto out;
+ }
+
+ if (!ipoe->opt_arp || !ses1 || ses1->arph ||
+ (ses2 && ses2->ses.state != AP_STATE_ACTIVE)) {
pthread_mutex_unlock(&ipoe->lock);
goto out;
}
@@ -112,7 +126,7 @@ out:
mempool_free(ah);
}
-void arp_send(int ifindex, struct _arphdr *arph)
+void arp_send(int ifindex, struct _arphdr *arph, int broadcast)
{
struct sockaddr_ll dst;
@@ -120,6 +134,10 @@ void arp_send(int ifindex, struct _arphdr *arph)
dst.sll_family = AF_PACKET;
dst.sll_ifindex = ifindex;
dst.sll_protocol = htons(ETH_P_ARP);
+ if (broadcast)
+ memcpy(dst.sll_addr, bc_addr, ETH_ALEN);
+ else
+ memcpy(dst.sll_addr, arph->ar_tha, ETH_ALEN);
arph->ar_op = htons(ARPOP_REPLY);
@@ -150,8 +168,13 @@ static int arp_read(struct triton_md_handler_t *h)
if (r < sizeof(*ah))
continue;
- if (ah->ar_op != htons(ARPOP_REQUEST))
- continue;
+ if (ah->ar_op != htons(ARPOP_REQUEST)) {
+ if (ah->ar_op != htons(ARPOP_REPLY))
+ continue;
+
+ if (memcmp(src.sll_addr, bc_addr, ETH_ALEN))
+ continue;
+ }
if (ah->ar_pln != 4)
continue;
diff --git a/accel-pppd/ctrl/ipoe/dhcp_attr_defs.h b/accel-pppd/ctrl/ipoe/dhcp_attr_defs.h
new file mode 100644
index 00000000..c68111c1
--- /dev/null
+++ b/accel-pppd/ctrl/ipoe/dhcp_attr_defs.h
@@ -0,0 +1,311 @@
+#define VENDOR_DHCP 54
+#define DHCP_Opcode 256
+#define DHCP_Hardware_Type 257
+#define DHCP_Hardware_Address_Length 258
+#define DHCP_Hop_Count 259
+#define DHCP_Transaction_Id 260
+#define DHCP_Number_of_Seconds 261
+#define DHCP_Flags 262
+#define DHCP_Client_IP_Address 263
+#define DHCP_Your_IP_Address 264
+#define DHCP_Server_IP_Address 265
+#define DHCP_Gateway_IP_Address 266
+#define DHCP_Client_Hardware_Address 267
+#define DHCP_Server_Host_Name 268
+#define DHCP_Boot_Filename 269
+#define DHCP_Relay_To_IP_Address 270
+#define DHCP_Relay_Max_Hop_Count 271
+#define DHCP_Relay_IP_Address 272
+#define DHCP_Flags_Broadcast 0x8000
+#define DHCP_Hardware_Type_Ethernet 1
+#define DHCP_Hardware_Type_Experiemental_Ethernet 2
+#define DHCP_Hardware_Type_AX_25 3
+#define DHCP_Hardware_Type_Proteon_Token_Ring 4
+#define DHCP_Hardware_Type_Chaos 5
+#define DHCP_Hardware_Type_IEEE_802 6
+#define DHCP_Hardware_Type_Arcnet 7
+#define DHCP_Hardware_Type_Hyperchannel 8
+#define DHCP_Hardware_Type_Lanstar 9
+#define DHCP_Hardware_Type_Autonet_Short_Address 10
+#define DHCP_Hardware_Type_LocalTalk 11
+#define DHCP_Hardware_Type_LocalNet 12
+#define DHCP_Hardware_Type_Ultra_Link 13
+#define DHCP_Hardware_Type_SMDS 14
+#define DHCP_Hardware_Type_Frame_Relay 15
+#define DHCP_Hardware_Type_ATM_16 16
+#define DHCP_Hardware_Type_HDLC 17
+#define DHCP_Hardware_Type_Fibre_Channel 18
+#define DHCP_Hardware_Type_ATM_19 19
+#define DHCP_Hardware_Type_Serial_Line 20
+#define DHCP_Hardware_Type_ATM_21 21
+#define DHCP_Hardware_Type_MIL_STD_188_220 22
+#define DHCP_Hardware_Type_Metricom 23
+#define DHCP_Hardware_Type_IEEE_1394 24
+#define DHCP_Hardware_Type_MAPOS 25
+#define DHCP_Hardware_Type_Twinaxial 26
+#define DHCP_Hardware_Type_EUI_64 27
+#define DHCP_Hardware_Type_HIPARP 28
+#define DHCP_Hardware_Type_IP_Over_ISO_7816_3 29
+#define DHCP_Hardware_Type_ARPSec 30
+#define DHCP_Hardware_Type_IPSec_Tunnel 31
+#define DHCP_Hardware_Type_Infiniband 32
+#define DHCP_Hardware_Type_CAI_TIA_102 33
+#define DHCP_Subnet_Mask 1
+#define DHCP_Time_Offset 2
+#define DHCP_Router_Address 3
+#define DHCP_Time_Server 4
+#define DHCP_IEN_116_Name_Server 5
+#define DHCP_Domain_Name_Server 6
+#define DHCP_Log_Server 7
+#define DHCP_Quotes_Server 8
+#define DHCP_LPR_Server 9
+#define DHCP_Impress_Server 10
+#define DHCP_RLP_Server 11
+#define DHCP_Hostname 12
+#define DHCP_Boot_File_Size 13
+#define DHCP_Merit_Dump_File 14
+#define DHCP_Domain_Name 15
+#define DHCP_Swap_Server 16
+#define DHCP_Root_Path 17
+#define DHCP_Bootp_Extensions_Path 18
+#define DHCP_IP_Forward_Enable 19
+#define DHCP_Source_Route_Enable 20
+#define DHCP_Policy_Filter 21
+#define DHCP_Max_Datagram_Reassembly_Sz 22
+#define DHCP_Default_IP_TTL 23
+#define DHCP_Path_MTU_Aging_Timeout 24
+#define DHCP_Path_MTU_Plateau_Table 25
+#define DHCP_Interface_MTU_Size 26
+#define DHCP_All_Subnets_Are_Local 27
+#define DHCP_Broadcast_Address 28
+#define DHCP_Perform_Mask_Discovery 29
+#define DHCP_Provide_Mask_To_Others 30
+#define DHCP_Perform_Router_Discovery 31
+#define DHCP_Router_Solicitation_Address 32
+#define DHCP_Static_Routes 33
+#define DHCP_Trailer_Encapsulation 34
+#define DHCP_ARP_Cache_Timeout 35
+#define DHCP_Ethernet_Encapsulation 36
+#define DHCP_Default_TCP_TTL 37
+#define DHCP_Keep_Alive_Interval 38
+#define DHCP_Keep_Alive_Garbage 39
+#define DHCP_NIS_Domain_Name 40
+#define DHCP_NIS_Servers 41
+#define DHCP_NTP_Servers 42
+#define DHCP_Vendor 43
+#define DHCP_NETBIOS_Name_Servers 44
+#define DHCP_NETBIOS_Dgm_Dist_Servers 45
+#define DHCP_NETBIOS_Node_Type 46
+#define DHCP_NETBIOS 47
+#define DHCP_X_Window_Font_Server 48
+#define DHCP_X_Window_Display_Mgr 49
+#define DHCP_Requested_IP_Address 50
+#define DHCP_IP_Address_Lease_Time 51
+#define DHCP_Overload 52
+#define DHCP_Message_Type 53
+#define DHCP_DHCP_Server_Identifier 54
+#define DHCP_Parameter_Request_List 55
+#define DHCP_DHCP_Error_Message 56
+#define DHCP_DHCP_Maximum_Msg_Size 57
+#define DHCP_Renewal_Time 58
+#define DHCP_Rebinding_Time 59
+#define DHCP_Vendor_Class_Identifier 60
+#define DHCP_Client_Identifier 61
+#define DHCP_Netware_Domain_Name 62
+#define DHCP_Netware_Sub_Options 63
+#define DHCP_NIS_Client_Domain_Name 64
+#define DHCP_NIS_Server_Address 65
+#define DHCP_TFTP_Server_Name 66
+#define DHCP_Boot_File_Name 67
+#define DHCP_Home_Agent_Address 68
+#define DHCP_SMTP_Server_Address 69
+#define DHCP_POP3_Server_Address 70
+#define DHCP_NNTP_Server_Address 71
+#define DHCP_WWW_Server_Address 72
+#define DHCP_Finger_Server_Address 73
+#define DHCP_IRC_Server_Address 74
+#define DHCP_StreetTalk_Server_Address 75
+#define DHCP_STDA_Server_Address 76
+#define DHCP_User_Class 77
+#define DHCP_Directory_Agent 78
+#define DHCP_Service_Scope 79
+#define DHCP_Rapid_Commit 80
+#define DHCP_Client_FQDN 81
+#define DHCP_Relay_Agent_Information 82
+#define DHCP_Agent_Circuit_Id 1
+#define DHCP_Agent_Remote_Id 2
+#define DHCP_Relay_Circuit_Id 1
+#define DHCP_Relay_Remote_Id 2
+#define DHCP_Docsis_Device_Class 4
+#define DHCP_Relay_Link_Selection 5
+#define DHCP_Subscriber_Id 6
+#define DHCP_RADIUS_Attributes 7
+#define DHCP_Authentication_Information 8
+#define DHCP_Vendor_Specific_Information 9
+#define DHCP_Relay_Agent_Flags 10
+#define DHCP_Server_Identifier_Override 11
+#define DHCP_iSNS 83
+#define DHCP_NDS_Servers 85
+#define DHCP_NDS_Tree_Name 86
+#define DHCP_NDS_Context 87
+#define DHCP_Authentication 90
+#define DHCP_Client_Last_Txn_Time 91
+#define DHCP_associated_ip 92
+#define DHCP_Client_System 93
+#define DHCP_Client_NDI 94
+#define DHCP_LDAP 95
+#define DHCP_UUID GUID
+#define DHCP_User_Auth 98
+#define DHCP_Netinfo_Address 112
+#define DHCP_Netinfo_Tag 113
+#define DHCP_URL 114
+#define DHCP_Auto_Config 116
+#define DHCP_Name_Service_Search 117
+#define DHCP_Subnet_Selection_Option 118
+#define DHCP_Domain_Search 119
+#define DHCP_SIP_Servers_DHCP_Option 120
+#define DHCP_Classless_Static_Route 121
+#define DHCP_CCC 122
+#define DHCP_GeoConf_Option 123
+#define DHCP_V_I_Vendor_Class 124
+#define DHCP_V_I_Vendor_Specific 125
+#define DHCP_Etherboot 128
+#define DHCP_TFTP_Server_IP_Address 128
+#define DHCP_Call_Server_IP_address 129
+#define DHCP_Ethernet_Interface 130
+#define DHCP_Vendor_Discrimination_Str 130
+#define DHCP_Remote_Stats_Svr_IP_Address 131
+#define DHCP_IEEE_802_1Q_L2_Priority 132
+#define DHCP_IEEE_802_1P_VLAN_ID 133
+#define DHCP_Diffserv_Code_Point 134
+#define DHCP_HTTP_Proxy 135
+#define DHCP_Cisco_TFTP_Server_IP_Addresses 150
+#define DHCP_End_Of_Options 255
+#define DHCP_Opcode_Client_Message 1
+#define DHCP_Opcode_Server_Message 2
+#define DHCP_Message_Type_DHCP_Discover 1
+#define DHCP_Message_Type_DHCP_Offer 2
+#define DHCP_Message_Type_DHCP_Request 3
+#define DHCP_Message_Type_DHCP_Decline 4
+#define DHCP_Message_Type_DHCP_Ack 5
+#define DHCP_Message_Type_DHCP_NAK 6
+#define DHCP_Message_Type_DHCP_Release 7
+#define DHCP_Message_Type_DHCP_Inform 8
+#define DHCP_Message_Type_DHCP_Force_Renew 9
+#define DHCP_Parameter_Request_List_DHCP_Subnet_Mask 1
+#define DHCP_Parameter_Request_List_DHCP_Time_Offset 2
+#define DHCP_Parameter_Request_List_DHCP_Router_Address 3
+#define DHCP_Parameter_Request_List_DHCP_Time_Server 4
+#define DHCP_Parameter_Request_List_DHCP_IEN_116_Name_Server 5
+#define DHCP_Parameter_Request_List_DHCP_Domain_Name_Server 6
+#define DHCP_Parameter_Request_List_DHCP_Log_Server 7
+#define DHCP_Parameter_Request_List_DHCP_Quotes_Server 8
+#define DHCP_Parameter_Request_List_DHCP_LPR_Server 9
+#define DHCP_Parameter_Request_List_DHCP_Impress_Server 10
+#define DHCP_Parameter_Request_List_DHCP_RLP_Server 11
+#define DHCP_Parameter_Request_List_DHCP_Hostname 12
+#define DHCP_Parameter_Request_List_DHCP_Boot_File_Size 13
+#define DHCP_Parameter_Request_List_DHCP_Merit_Dump_File 14
+#define DHCP_Parameter_Request_List_DHCP_Domain_Name 15
+#define DHCP_Parameter_Request_List_DHCP_Swap_Server 16
+#define DHCP_Parameter_Request_List_DHCP_Root_Path 17
+#define DHCP_Parameter_Request_List_DHCP_Bootp_Extensions_Path 18
+#define DHCP_Parameter_Request_List_DHCP_IP_Forward_Enable 19
+#define DHCP_Parameter_Request_List_DHCP_Source_Route_Enable 20
+#define DHCP_Parameter_Request_List_DHCP_Policy_Filter 21
+#define DHCP_Parameter_Request_List_DHCP_Max_Datagram_Reassembly_Sz 22
+#define DHCP_Parameter_Request_List_DHCP_Default_IP_TTL 23
+#define DHCP_Parameter_Request_List_DHCP_Path_MTU_Aging_Timeout 24
+#define DHCP_Parameter_Request_List_DHCP_Path_MTU_Plateau_Table 25
+#define DHCP_Parameter_Request_List_DHCP_Interface_MTU_Size 26
+#define DHCP_Parameter_Request_List_DHCP_All_Subnets_Are_Local 27
+#define DHCP_Parameter_Request_List_DHCP_Broadcast_Address 28
+#define DHCP_Parameter_Request_List_DHCP_Perform_Mask_Discovery 29
+#define DHCP_Parameter_Request_List_DHCP_Provide_Mask_To_Others 30
+#define DHCP_Parameter_Request_List_DHCP_Perform_Router_Discovery 31
+#define DHCP_Parameter_Request_List_DHCP_Router_Solicitation_Address 32
+#define DHCP_Parameter_Request_List_DHCP_Static_Routes 33
+#define DHCP_Parameter_Request_List_DHCP_Trailer_Encapsulation 34
+#define DHCP_Parameter_Request_List_DHCP_ARP_Cache_Timeout 35
+#define DHCP_Parameter_Request_List_DHCP_Ethernet_Encapsulation 36
+#define DHCP_Parameter_Request_List_DHCP_Default_TCP_TTL 37
+#define DHCP_Parameter_Request_List_DHCP_Keep_Alive_Interval 38
+#define DHCP_Parameter_Request_List_DHCP_Keep_Alive_Garbage 39
+#define DHCP_Parameter_Request_List_DHCP_NIS_Domain_Name 40
+#define DHCP_Parameter_Request_List_DHCP_NIS_Servers 41
+#define DHCP_Parameter_Request_List_DHCP_NTP_Servers 42
+#define DHCP_Parameter_Request_List_DHCP_Vendor 43
+#define DHCP_Parameter_Request_List_DHCP_NETBIOS_Name_Servers 44
+#define DHCP_Parameter_Request_List_DHCP_NETBIOS_Dgm_Dist_Servers 45
+#define DHCP_Parameter_Request_List_DHCP_NETBIOS_Node_Type 46
+#define DHCP_Parameter_Request_List_DHCP_NETBIOS 47
+#define DHCP_Parameter_Request_List_DHCP_X_Window_Font_Server 48
+#define DHCP_Parameter_Request_List_DHCP_X_Window_Display_Mgr 49
+#define DHCP_Parameter_Request_List_DHCP_Requested_IP_Address 50
+#define DHCP_Parameter_Request_List_DHCP_IP_Address_Lease_Time 51
+#define DHCP_Parameter_Request_List_DHCP_Overload 52
+#define DHCP_Parameter_Request_List_DHCP_Message_Type 53
+#define DHCP_Parameter_Request_List_DHCP_DHCP_Server_Identifier 54
+#define DHCP_Parameter_Request_List_DHCP_Parameter_Request_List 55
+#define DHCP_Parameter_Request_List_DHCP_DHCP_Error_Message 56
+#define DHCP_Parameter_Request_List_DHCP_DHCP_Maximum_Msg_Size 57
+#define DHCP_Parameter_Request_List_DHCP_Renewal_Time 58
+#define DHCP_Parameter_Request_List_DHCP_Rebinding_Time 59
+#define DHCP_Parameter_Request_List_DHCP_Class_Identifier 60
+#define DHCP_Parameter_Request_List_DHCP_Client_Identifier 61
+#define DHCP_Parameter_Request_List_DHCP_Netware_Domain_Name 62
+#define DHCP_Parameter_Request_List_DHCP_Netware_Sub_Options 63
+#define DHCP_Parameter_Request_List_DHCP_NIS_Client_Domain_Name 64
+#define DHCP_Parameter_Request_List_DHCP_NIS_Server_Address 65
+#define DHCP_Parameter_Request_List_DHCP_TFTP_Server_Name 66
+#define DHCP_Parameter_Request_List_DHCP_Boot_File_Name 67
+#define DHCP_Parameter_Request_List_DHCP_Home_Agent_Address 68
+#define DHCP_Parameter_Request_List_DHCP_SMTP_Server_Address 69
+#define DHCP_Parameter_Request_List_DHCP_POP3_Server_Address 70
+#define DHCP_Parameter_Request_List_DHCP_NNTP_Server_Address 71
+#define DHCP_Parameter_Request_List_DHCP_WWW_Server_Address 72
+#define DHCP_Parameter_Request_List_DHCP_Finger_Server_Address 73
+#define DHCP_Parameter_Request_List_DHCP_IRC_Server_Address 74
+#define DHCP_Parameter_Request_List_DHCP_StreetTalk_Server_Address 75
+#define DHCP_Parameter_Request_List_DHCP_STDA_Server_Address 76
+#define DHCP_Parameter_Request_List_DHCP_User_Class 77
+#define DHCP_Parameter_Request_List_DHCP_Directory_Agent 78
+#define DHCP_Parameter_Request_List_DHCP_Service_Scope 79
+#define DHCP_Parameter_Request_List_DHCP_Rapid_Commit 80
+#define DHCP_Parameter_Request_List_DHCP_Client_FQDN 81
+#define DHCP_Parameter_Request_List_DHCP_Relay_Agent_Information 82
+#define DHCP_Parameter_Request_List_DHCP_iSNS 83
+#define DHCP_Parameter_Request_List_DHCP_NDS_Servers 85
+#define DHCP_Parameter_Request_List_DHCP_NDS_Tree_Name 86
+#define DHCP_Parameter_Request_List_DHCP_NDS_Context 87
+#define DHCP_Parameter_Request_List_DHCP_Authentication 90
+#define DHCP_Parameter_Request_List_DHCP_Client_Last_Txn_Time 91
+#define DHCP_Parameter_Request_List_DHCP_associated_ip 92
+#define DHCP_Parameter_Request_List_DHCP_Client_System 93
+#define DHCP_Parameter_Request_List_DHCP_Client_NDI 94
+#define DHCP_Parameter_Request_List_DHCP_LDAP 95
+#define DHCP_Parameter_Request_List_DHCP_UUID GUID
+#define DHCP_Parameter_Request_List_DHCP_User_Auth 98
+#define DHCP_Parameter_Request_List_DHCP_Netinfo_Address 112
+#define DHCP_Parameter_Request_List_DHCP_Netinfo_Tag 113
+#define DHCP_Parameter_Request_List_DHCP_URL 114
+#define DHCP_Parameter_Request_List_DHCP_Auto_Config 116
+#define DHCP_Parameter_Request_List_DHCP_Name_Service_Search 117
+#define DHCP_Parameter_Request_List_DHCP_Subnet_Selection_Option 118
+#define DHCP_Parameter_Request_List_DHCP_Domain_Search 119
+#define DHCP_Parameter_Request_List_DHCP_SIP_Servers_DHCP_Option 120
+#define DHCP_Parameter_Request_List_DHCP_Classless_Static_Route 121
+#define DHCP_Parameter_Request_List_DHCP_CCC 122
+#define DHCP_Parameter_Request_List_DHCP_GeoConf_Option 123
+#define DHCP_Parameter_Request_List_DHCP_V_I_Vendor_Class 124
+#define DHCP_Parameter_Request_List_DHCP_V_I_Vendor_Specific 125
+#define DHCP_Parameter_Request_List_DHCP_Etherboot 128
+#define DHCP_Parameter_Request_List_DHCP_TFTP_Server_IP_Address 128
+#define DHCP_Parameter_Request_List_DHCP_Call_Server_IP_address 129
+#define DHCP_Parameter_Request_List_DHCP_Ethernet_Interface 130
+#define DHCP_Parameter_Request_List_DHCP_Vendor_Discrimination_Str 130
+#define DHCP_Parameter_Request_List_DHCP_Remote_Stats_Svr_IP_Address 131
+#define DHCP_Parameter_Request_List_DHCP_IEEE_802_1P_VLAN_ID 132
+#define DHCP_Parameter_Request_List_DHCP_IEEE_802_1Q_L2_Priority 133
+#define DHCP_Parameter_Request_List_DHCP_Diffserv_Code_Point 134
+#define DHCP_Parameter_Request_List_DHCP_HTTP_Proxy 135
diff --git a/accel-pppd/ctrl/ipoe/dhcpv4.c b/accel-pppd/ctrl/ipoe/dhcpv4.c
index 6d0d1c9c..ccad3182 100644
--- a/accel-pppd/ctrl/ipoe/dhcpv4.c
+++ b/accel-pppd/ctrl/ipoe/dhcpv4.c
@@ -22,6 +22,8 @@
#include "memdebug.h"
#include "ap_session.h"
#include "ipdb.h"
+#include "radius.h"
+#include "dhcp_attr_defs.h"
#include "dhcpv4.h"
@@ -1126,6 +1128,46 @@ void dhcpv4_reserve_ip(struct dhcpv4_serv *serv, uint32_t ip)
pthread_mutex_unlock(&serv->range->lock);
}
+struct dhcpv4_packet *dhcpv4_clone_radius(struct rad_packet_t *rad)
+{
+ struct dhcpv4_packet *pkt = dhcpv4_packet_alloc();
+ uint8_t *ptr = pkt->data, *endptr = ptr + BUF_SIZE;
+ struct dhcpv4_option *opt;
+ struct rad_attr_t *attr;
+
+ if (!pkt)
+ return NULL;
+
+ pkt->refs = 1;
+
+ list_for_each_entry(attr, &rad->attrs, entry) {
+ if (attr->vendor && attr->vendor->id == VENDOR_DHCP && attr->attr->id < 256) {
+ if (ptr + attr->len >= endptr)
+ goto out;
+
+ opt = mempool_alloc(opt_pool);
+ if (!opt) {
+ log_emerg("out of memory\n");
+ goto out;
+ }
+ memset(opt, 0, sizeof(*opt));
+ opt->type = attr->attr->id;
+ opt->len = attr->len;
+ opt->data = ptr;
+ memcpy(ptr, attr->raw, attr->len);
+ ptr += attr->len;
+
+ list_add_tail(&opt->entry, &pkt->options);
+ }
+ }
+
+ return pkt;
+
+out:
+ dhcpv4_packet_free(pkt);
+ return NULL;
+}
+
static void load_config()
{
const char *opt;
diff --git a/accel-pppd/ctrl/ipoe/dhcpv4.h b/accel-pppd/ctrl/ipoe/dhcpv4.h
index 58473036..a7fa5a90 100644
--- a/accel-pppd/ctrl/ipoe/dhcpv4.h
+++ b/accel-pppd/ctrl/ipoe/dhcpv4.h
@@ -101,6 +101,7 @@ struct dhcpv4_relay {
};
struct ap_session;
+struct rad_packet_t;
struct dhcpv4_serv *dhcpv4_create(struct triton_context_t *ctx, const char *ifname, const char *opt);
void dhcpv4_free(struct dhcpv4_serv *);
@@ -120,6 +121,7 @@ void dhcpv4_packet_ref(struct dhcpv4_packet *pack);
struct dhcpv4_option *dhcpv4_packet_find_opt(struct dhcpv4_packet *pack, int type);
int dhcpv4_packet_insert_opt82(struct dhcpv4_packet *pack, const char *agent_circuit_id, const char *agent_remote_id);
void dhcpv4_packet_free(struct dhcpv4_packet *pack);
+struct dhcpv4_packet *dhcpv4_clone_radius(struct rad_packet_t *);
int dhcpv4_check_options(struct dhcpv4_packet *);
void dhcpv4_print_options(struct dhcpv4_packet *, void (*)(const char *, ...));
diff --git a/accel-pppd/ctrl/ipoe/ipoe.c b/accel-pppd/ctrl/ipoe/ipoe.c
index e4c1fae8..8687d1f4 100644
--- a/accel-pppd/ctrl/ipoe/ipoe.c
+++ b/accel-pppd/ctrl/ipoe/ipoe.c
@@ -7,6 +7,7 @@
#include <fcntl.h>
#include <assert.h>
#include <time.h>
+#include <limits.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <net/ethernet.h>
@@ -14,6 +15,7 @@
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/if.h>
+#include <linux/if_arp.h>
#include <linux/route.h>
#include <pcre.h>
@@ -28,6 +30,7 @@
#include "ap_session.h"
#include "pwdb.h"
#include "ipdb.h"
+#include "dhcp_attr_defs.h"
#include "iputils.h"
#include "ipset.h"
@@ -76,6 +79,12 @@ struct disc_item {
struct timespec ts;
};
+struct arp_item {
+ struct list_head entry;
+ struct timespec ts;
+ struct _arphdr arph;
+};
+
struct delay {
struct list_head entry;
unsigned int conn_cnt;
@@ -116,6 +125,7 @@ static const char *conf_password;
static int conf_unit_cache;
static int conf_noauth;
#ifdef RADIUS
+static int conf_vendor;
static int conf_attr_dhcp_client_ip;
static int conf_attr_dhcp_router_ip;
static int conf_attr_dhcp_mask;
@@ -166,6 +176,7 @@ static unsigned int stat_delayed_offer;
static mempool_t ses_pool;
static mempool_t disc_item_pool;
+static mempool_t arp_item_pool;
static mempool_t req_item_pool;
static int connlimit_loaded;
@@ -200,10 +211,16 @@ static int ipoe_rad_send_auth_request(struct rad_plugin_t *rad, struct rad_packe
static int ipoe_rad_send_acct_request(struct rad_plugin_t *rad, struct rad_packet_t *pack);
static void ipoe_session_create_auto(struct ipoe_serv *serv);
static void ipoe_serv_timeout(struct triton_timer_t *t);
+static struct ipoe_session *ipoe_session_create_up(struct ipoe_serv *serv, struct ethhdr *eth, struct iphdr *iph, struct _arphdr *arph);
static void ipoe_ctx_switch(struct triton_context_t *ctx, void *arg)
{
- net = &def_net;
+ if (arg) {
+ struct ap_session *s = arg;
+ net = s->net;
+ } else
+ net = def_net;
+
log_switch(ctx, arg);
}
@@ -600,7 +617,6 @@ cont:
if (ses->serv->opt_shared == 0 && ses->ses.ipv4 && ses->ses.ipv4->peer_addr != ses->yiaddr) {
if (ipoe_create_interface(ses))
return;
-
}
ap_session_set_ifindex(&ses->ses);
@@ -622,9 +638,16 @@ static void ipoe_session_start(struct ipoe_session *ses)
char *username;
const char *pass;
- if (ses->dhcpv4_request && conf_verbose) {
- log_ppp_info2("recv ");
- dhcpv4_print_packet(ses->dhcpv4_request, 0, log_ppp_info2);
+ if (conf_verbose) {
+ if (ses->dhcpv4_request) {
+ log_ppp_info2("recv ");
+ dhcpv4_print_packet(ses->dhcpv4_request, 0, log_ppp_info2);
+ } else if (ses->arph) {
+ char addr1[64], addr2[64];
+ u_inet_ntoa(ses->arph->ar_tpa, addr1);
+ u_inet_ntoa(ses->arph->ar_spa, addr2);
+ log_ppp_info2("recv [ARP Request who-has %s tell %s]\n", addr1, addr2);
+ }
}
__sync_add_and_fetch(&stat_starting, 1);
@@ -700,6 +723,24 @@ static void find_gw_addr(struct ipoe_session *ses)
}
}
+static void send_arp_reply(struct ipoe_serv *serv, struct _arphdr *arph)
+{
+ __be32 tpa = arph->ar_tpa;
+
+ if (conf_verbose) {
+ char addr[64];
+ u_inet_ntoa(arph->ar_tpa, addr);
+ log_ppp_info2("send [ARP Reply %s is-at %02x:%02x:%02x:%02x:%02x:%02x]\n", addr,
+ serv->hwaddr[0], serv->hwaddr[1], serv->hwaddr[2], serv->hwaddr[3], serv->hwaddr[4], serv->hwaddr[5]);
+ }
+
+ memcpy(arph->ar_tha, arph->ar_sha, ETH_ALEN);
+ memcpy(arph->ar_sha, serv->hwaddr, ETH_ALEN);
+ arph->ar_tpa = arph->ar_spa;
+ arph->ar_spa = tpa;
+ arp_send(serv->ifindex, arph, 1);
+}
+
static void __ipoe_session_start(struct ipoe_session *ses)
{
if (!ses->yiaddr && ses->serv->dhcpv4) {
@@ -795,11 +836,6 @@ static void __ipoe_session_start(struct ipoe_session *ses)
dhcpv4_packet_free(ses->dhcpv4_request);
ses->dhcpv4_request = NULL;
-
- ses->timer.expire = ipoe_session_timeout;
- ses->timer.period = 0;
- ses->timer.expire_tv.tv_sec = conf_offer_timeout;
- triton_timer_add(&ses->ctx, &ses->timer, 0);
} else {
if (!ses->router)
find_gw_addr(ses);
@@ -808,7 +844,7 @@ static void __ipoe_session_start(struct ipoe_session *ses)
ses->router = ses->serv->opt_src;
if (!ses->router)
- ses->siaddr = iproute_get(ses->yiaddr, NULL);
+ ses->router = iproute_get(ses->yiaddr, NULL);
if (!ses->router) {
log_ppp_error("can't determine router address\n");
@@ -821,8 +857,21 @@ static void __ipoe_session_start(struct ipoe_session *ses)
ses->siaddr = ses->router;
- __ipoe_session_activate(ses);
+ if (ses->arph) {
+ ses->wait_start = 1;
+ send_arp_reply(ses->serv, ses->arph);
+ _free(ses->arph);
+ ses->arph = NULL;
+ } else {
+ __ipoe_session_activate(ses);
+ return;
+ }
}
+
+ ses->timer.expire = ipoe_session_timeout;
+ ses->timer.period = 0;
+ ses->timer.expire_tv.tv_sec = conf_offer_timeout;
+ triton_timer_add(&ses->ctx, &ses->timer, 0);
}
static void make_ipv6_intfid(uint64_t *intfid, const uint8_t *hwaddr)
@@ -841,9 +890,11 @@ static void __ipoe_session_activate(struct ipoe_session *ses)
uint32_t addr, gw = 0;
struct ipoe_serv *serv = ses->serv;
- if (ses->terminating)
+ if (ses->terminating || ses->started)
return;
+ log_ppp_debug("ipoe: activate session\n");
+
if (ses->ifindex != -1) {
addr = 0;
/*if (!ses->ses.ipv4) {
@@ -883,12 +934,7 @@ static void __ipoe_session_activate(struct ipoe_session *ses)
if (ses->ifindex == -1) {
if (serv->opt_ifcfg)
- ipaddr_add(serv->ifindex, ses->router, conf_ip_unnumbered ? 32 : ses->mask);
- else if (!conf_ip_unnumbered)
- iproute_add(serv->ifindex, ses->router, ses->yiaddr, 0, conf_proto, ses->mask);
-
- if (conf_ip_unnumbered)
- iproute_add(serv->ifindex, serv->opt_src ?: ses->router, ses->yiaddr, 0, conf_proto, 32);
+ ipaddr_add_peer(serv->ifindex, ses->router, ses->yiaddr);
} else
ses->ctrl.dont_ifcfg = 0;
@@ -908,6 +954,13 @@ static void __ipoe_session_activate(struct ipoe_session *ses)
ap_session_activate(&ses->ses);
+ if (ses->ifindex == -1) {
+ if (!conf_ip_unnumbered)
+ iproute_add(serv->ifindex, ses->router, ses->yiaddr, 0, conf_proto, ses->mask);
+ else if (!serv->opt_ifcfg)
+ iproute_add(serv->ifindex, serv->opt_src ?: ses->router, ses->yiaddr, 0, conf_proto, 32);
+ }
+
if (ses->l4_redirect)
ipoe_change_l4_redirect(ses, 0);
@@ -919,14 +972,6 @@ static void __ipoe_session_activate(struct ipoe_session *ses)
dhcpv4_packet_free(ses->dhcpv4_request);
ses->dhcpv4_request = NULL;
- } else if (ses->arph) {
- if (ses->arph->ar_tpa == ses->router) {
- memcpy(ses->arph->ar_tha, ses->serv->hwaddr, ETH_ALEN);
- arp_send(ses->serv->ifindex, ses->arph);
- }
-
- _free(ses->arph);
- ses->arph = NULL;
}
ses->timer.expire = ipoe_session_timeout;
@@ -1010,6 +1055,10 @@ static void ipoe_session_started(struct ap_session *s)
if (ses->timer.tpd)
triton_timer_mod(&ses->timer, 0);
+ if (ses->ses.ipv4->peer_addr != ses->yiaddr)
+ //ipaddr_add_peer(ses->ses.ifindex, ses->router, ses->yiaddr); // breaks quagga
+ iproute_add(ses->ses.ifindex, ses->router, ses->yiaddr, 0, conf_proto, 32);
+
if (ses->ifindex != -1 && ses->xid) {
ses->dhcpv4 = dhcpv4_create(ses->ctrl.ctx, ses->ses.ifname, "");
if (!ses->dhcpv4) {
@@ -1064,11 +1113,23 @@ static void ipoe_session_finished(struct ap_session *s)
struct ipoe_session *ses = container_of(s, typeof(*ses), ses);
struct ipoe_serv *serv = ses->serv;
struct unit_cache *uc;
+ struct ifreq ifr;
log_ppp_info1("ipoe: session finished\n");
if (ses->ifindex != -1) {
- if (uc_size < conf_unit_cache && !ipoe_nl_modify(ses->ifindex, 0, 0, 0, 0, NULL)) {
+ if (uc_size < conf_unit_cache) {
+ strcpy(ifr.ifr_name, s->ifname);
+ ioctl(sock_fd, SIOCGIFFLAGS, &ifr);
+ if (ifr.ifr_flags & IFF_UP) {
+ ifr.ifr_flags &= ~IFF_UP;
+ ioctl(sock_fd, SIOCSIFFLAGS, &ifr);
+ }
+
+ ipaddr_del_peer(s->ifindex, ses->router, ses->yiaddr);
+
+ ipoe_nl_modify(ses->ifindex, 0, 0, 0, 0, NULL);
+
uc = mempool_alloc(uc_pool);
uc->ifindex = ses->ifindex;
pthread_mutex_lock(&uc_lock);
@@ -1098,7 +1159,6 @@ static void ipoe_session_finished(struct ap_session *s)
triton_event_fire(EV_CTRL_FINISHED, s);
if (s->ifindex == ses->serv->ifindex && strcmp(s->ifname, ses->serv->ifname)) {
- struct ifreq ifr;
int flags;
log_info2("ipoe: rename %s to %s\n", s->ifname, ses->serv->ifname);
@@ -1134,7 +1194,8 @@ static void ipoe_session_terminated(struct ipoe_session *ses)
if (ses->l4_redirect_set)
ipoe_change_l4_redirect(ses, 1);
- ap_session_finished(&ses->ses);
+ if (!ses->ses.terminated)
+ ap_session_finished(&ses->ses);
}
static void ipoe_session_terminated_pkt(struct dhcpv4_packet *pack)
@@ -1182,6 +1243,12 @@ static struct ipoe_session *ipoe_session_create_dhcpv4(struct ipoe_serv *serv, s
int dlen = 0;
uint8_t *ptr = NULL;
+ if (ap_shutdown)
+ return NULL;
+
+ if (conf_max_sessions && ap_session_stat.active + ap_session_stat.starting >= conf_max_sessions)
+ return NULL;
+
ses = ipoe_session_alloc(serv->ifname);
if (!ses)
return NULL;
@@ -1415,36 +1482,79 @@ static void ipoe_ses_recv_dhcpv4_request(struct dhcpv4_packet *pack)
static void ipoe_serv_disc_timer(struct triton_timer_t *t)
{
struct ipoe_serv *serv = container_of(t, typeof(*serv), disc_timer);
- struct disc_item *d;
struct timespec ts;
- int delay, offer_delay;
+ int delay, delay1 = INT_MAX, delay2 = INT_MAX, offer_delay;
clock_gettime(CLOCK_MONOTONIC, &ts);
while (!list_empty(&serv->disc_list)) {
- d = list_entry(serv->disc_list.next, typeof(*d), entry);
+ struct disc_item *d = list_entry(serv->disc_list.next, typeof(*d), entry);
delay = (ts.tv_sec - d->ts.tv_sec) * 1000 + (ts.tv_nsec - d->ts.tv_nsec) / 1000000;
offer_delay = get_offer_delay();
if (delay < offer_delay - 1) {
- delay = offer_delay - delay;
- t->expire_tv.tv_sec = delay / 1000;
- t->expire_tv.tv_usec = (delay % 1000) * 1000;
- triton_timer_mod(t, 0);
- return;
+ delay1 = delay;
+ break;
}
__ipoe_recv_dhcpv4(serv->dhcpv4, d->pack, 1);
+ dhcpv4_packet_free(d->pack);
list_del(&d->entry);
- dhcpv4_packet_free(d->pack);
mempool_free(d);
__sync_sub_and_fetch(&stat_delayed_offer, 1);
}
- triton_timer_del(t);
+ while (!list_empty(&serv->arp_list)) {
+ struct arp_item *d = list_entry(serv->arp_list.next, typeof(*d), entry);
+
+ delay = (ts.tv_sec - d->ts.tv_sec) * 1000 + (ts.tv_nsec - d->ts.tv_nsec) / 1000000;
+ offer_delay = get_offer_delay();
+
+ if (delay < offer_delay - 1) {
+ delay2 = delay;
+ break;
+ }
+
+ ipoe_session_create_up(serv, NULL, NULL, &d->arph);
+
+ list_del(&d->entry);
+ mempool_free(d);
+
+ __sync_sub_and_fetch(&stat_delayed_offer, 1);
+ }
+
+ if (list_empty(&serv->disc_list) && list_empty(&serv->arp_list))
+ triton_timer_del(t);
+ else {
+ delay = delay1 < delay2 ? delay1 : delay2;
+ delay = offer_delay - delay;
+ t->expire_tv.tv_sec = delay / 1000;
+ t->expire_tv.tv_usec = (delay % 1000) * 1000;
+ triton_timer_mod(t, 0);
+ }
+}
+
+static void ipoe_serv_add_disc_arp(struct ipoe_serv *serv, struct _arphdr *arph, int offer_delay)
+{
+ struct arp_item *d = mempool_alloc(arp_item_pool);
+
+ if (!d)
+ return;
+
+ __sync_add_and_fetch(&stat_delayed_offer, 1);
+
+ memcpy(&d->arph, arph, sizeof(*arph));
+ clock_gettime(CLOCK_MONOTONIC, &d->ts);
+ list_add_tail(&d->entry, &serv->arp_list);
+
+ if (!serv->disc_timer.tpd) {
+ serv->disc_timer.expire_tv.tv_sec = offer_delay / 1000;
+ serv->disc_timer.expire_tv.tv_usec = (offer_delay % 1000) * 1000;
+ triton_timer_add(&serv->ctx, &serv->disc_timer, 0);
+ }
}
static void ipoe_serv_add_disc(struct ipoe_serv *serv, struct dhcpv4_packet *pack, int offer_delay)
@@ -1782,6 +1892,9 @@ static struct ipoe_session *ipoe_session_create_up(struct ipoe_serv *serv, struc
if (ap_shutdown)
return NULL;
+ if (conf_max_sessions && ap_session_stat.active + ap_session_stat.starting >= conf_max_sessions)
+ return NULL;
+
if (l4_redirect_list_check(saddr))
return NULL;
@@ -1931,13 +2044,13 @@ void ipoe_recv_up(int ifindex, struct ethhdr *eth, struct iphdr *iph, struct _ar
pthread_mutex_lock(&serv->lock);
- if (!serv->opt_shared && !list_empty(&serv->sessions)) {
- pthread_mutex_unlock(&serv->lock);
- break;
- }
-
list_for_each_entry(ses, &serv->sessions, entry) {
if (ses->yiaddr == saddr) {
+ if (ses->wait_start) {
+ ses->wait_start = 0;
+ triton_context_call(&ses->ctx, (triton_event_func)__ipoe_session_activate, ses);
+ }
+
pthread_mutex_unlock(&serv->lock);
pthread_mutex_unlock(&serv_lock);
return;
@@ -1953,7 +2066,53 @@ void ipoe_recv_up(int ifindex, struct ethhdr *eth, struct iphdr *iph, struct _ar
pthread_mutex_unlock(&serv_lock);
}
+void ipoe_serv_recv_arp(struct ipoe_serv *serv, struct _arphdr *arph)
+{
+ struct arp_item *d;
+
+ if (arph->ar_op == htons(ARPOP_REQUEST)) {
+ int offer_delay = get_offer_delay();
+
+ if (offer_delay == -1)
+ return;
+
+ list_for_each_entry(d, &serv->arp_list, entry) {
+ if (d->arph.ar_spa == arph->ar_spa)
+ return;
+ }
+
+ if (offer_delay)
+ ipoe_serv_add_disc_arp(serv, arph, offer_delay);
+ else
+ ipoe_session_create_up(serv, NULL, NULL, arph);
+ } else {
+ list_for_each_entry(d, &serv->arp_list, entry) {
+ if (d->arph.ar_spa == arph->ar_tpa) {
+ list_del(&d->entry);
+ mempool_free(d);
+
+ __sync_sub_and_fetch(&stat_delayed_offer, 1);
+
+ break;
+ }
+ }
+ }
+}
+
#ifdef RADIUS
+
+static int ipaddr_to_prefix(in_addr_t ipaddr)
+{
+ if (ipaddr == 0)
+ return 0;
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ return 33 - ffs(htonl(ipaddr));
+#else
+ return 33 - ffs(ipaddr);
+#endif
+}
+
static void ev_radius_access_accept(struct ev_radius_t *ev)
{
struct ipoe_session *ses = container_of(ev->ses, typeof(*ses), ses);
@@ -1964,24 +2123,21 @@ static void ev_radius_access_accept(struct ev_radius_t *ev)
return;
list_for_each_entry(attr, &ev->reply->attrs, entry) {
+ int vendor_id = attr->vendor ? attr->vendor->id : 0;
+
+ if (conf_vendor != vendor_id)
+ continue;
+
if (attr->attr->id == conf_attr_dhcp_client_ip)
ses->yiaddr = attr->val.ipaddr;
else if (attr->attr->id == conf_attr_dhcp_router_ip)
ses->router = attr->val.ipaddr;
else if (attr->attr->id == conf_attr_dhcp_mask) {
if (attr->attr->type == ATTR_TYPE_INTEGER) {
- if (attr->val.integer > 0 && attr->val.integer < 31)
+ if (attr->val.integer > 0 && attr->val.integer <= 32)
ses->mask = attr->val.integer;
- } else if (attr->attr->type == ATTR_TYPE_IPADDR) {
- if (attr->val.ipaddr == 0xffffffff)
- ses->mask = 32;
- else
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- ses->mask = 31 - ffs(htonl(attr->val.ipaddr));
-#else
- ses->mask = 31 - ffs(attr->val.ipaddr);
-#endif
- }
+ } else if (attr->attr->type == ATTR_TYPE_IPADDR)
+ ses->mask = ipaddr_to_prefix(attr->val.ipaddr);
} else if (attr->attr->id == conf_attr_l4_redirect) {
if (attr->attr->type == ATTR_TYPE_STRING) {
if (attr->len && attr->val.string[0] != '0')
@@ -1999,6 +2155,31 @@ static void ev_radius_access_accept(struct ev_radius_t *ev)
else if (attr->attr->id == conf_attr_l4_redirect_ipset) {
if (attr->attr->type == ATTR_TYPE_STRING)
ses->l4_redirect_ipset = _strdup(attr->val.string);
+ } else if (attr->vendor && attr->vendor->id == VENDOR_DHCP) {
+ ses->dhcpv4_relay_reply = dhcpv4_clone_radius(ev->reply);
+
+ switch (attr->attr->id) {
+ case DHCP_Your_IP_Address:
+ ses->yiaddr = attr->val.ipaddr;
+ break;
+ case DHCP_Server_IP_Address:
+ ses->yiaddr = attr->val.ipaddr;
+ break;
+ case DHCP_Router_Address:
+ ses->router = *(in_addr_t *)attr->raw;
+ break;
+ case DHCP_Subnet_Mask:
+ ses->mask = ipaddr_to_prefix(attr->val.ipaddr);
+ break;
+ case DHCP_IP_Address_Lease_Time:
+ ses->lease_time = attr->val.integer;
+ lease_time_set = 1;
+ break;
+ case DHCP_Renewal_Time:
+ ses->renew_time = attr->val.integer;
+ renew_time_set = 1;
+ break;
+ }
}
}
@@ -2014,8 +2195,9 @@ static void ev_radius_coa(struct ev_radius_t *ev)
{
struct ipoe_session *ses = container_of(ev->ses, typeof(*ses), ses);
struct rad_attr_t *attr;
- int l4_redirect;
+ int l4_redirect = -1;
int lease_time_set = 0, renew_time_set = 0;
+ char *ipset = NULL;
if (ev->ses->ctrl->type != CTRL_TYPE_IPOE)
return;
@@ -2023,11 +2205,16 @@ static void ev_radius_coa(struct ev_radius_t *ev)
l4_redirect = ses->l4_redirect;
list_for_each_entry(attr, &ev->request->attrs, entry) {
+ int vendor_id = attr->vendor ? attr->vendor->id : 0;
+
+ if (conf_vendor != vendor_id)
+ continue;
+
if (attr->attr->id == conf_attr_l4_redirect) {
if (attr->attr->type == ATTR_TYPE_STRING)
- ses->l4_redirect = attr->len && attr->val.string[0] != '0';
+ l4_redirect = attr->len && attr->val.string[0] != '0';
else
- ses->l4_redirect = ((unsigned int)attr->val.integer) > 0;
+ l4_redirect = ((unsigned int)attr->val.integer) > 0;
} else if (strcmp(attr->attr->name, "Framed-IP-Address") == 0) {
if (ses->ses.ipv4 && ses->ses.ipv4->peer_addr != attr->val.ipaddr)
ipoe_change_addr(ses, attr->val.ipaddr);
@@ -2041,10 +2228,8 @@ static void ev_radius_coa(struct ev_radius_t *ev)
ses->l4_redirect_table = attr->val.integer;
else if (attr->attr->id == conf_attr_l4_redirect_ipset) {
if (attr->attr->type == ATTR_TYPE_STRING) {
- if (ses->l4_redirect_ipset && strcmp(ses->l4_redirect_ipset, attr->val.string)) {
- _free(ses->l4_redirect_ipset);
- ses->l4_redirect_ipset = _strdup(attr->val.string);
- }
+ if (!ses->l4_redirect_ipset || strcmp(ses->l4_redirect_ipset, attr->val.string))
+ ipset = attr->val.string;
}
}
}
@@ -2056,9 +2241,23 @@ static void ev_radius_coa(struct ev_radius_t *ev)
ses->renew_time = ses->lease_time / 2;
}
- //if (l4_redirect && !ses->l4_redirect) || (!l4_redirect && ses->l4_redirect))
- if (l4_redirect != ses->l4_redirect && ev->ses->state == AP_STATE_ACTIVE)
- ipoe_change_l4_redirect(ses, l4_redirect);
+ if (l4_redirect >= 0 && ev->ses->state == AP_STATE_ACTIVE) {
+ if (ses->l4_redirect && l4_redirect && ipset) {
+ ipoe_change_l4_redirect(ses, 1);
+ ses->l4_redirect = 0;
+ }
+
+ if (ipset) {
+ if (ses->l4_redirect_ipset)
+ _free(ses->l4_redirect_ipset);
+ ses->l4_redirect_ipset = _strdup(ipset);
+ }
+
+ if (l4_redirect != ses->l4_redirect ) {
+ ipoe_change_l4_redirect(ses, l4_redirect == 0);
+ ses->l4_redirect = l4_redirect;
+ }
+ }
}
static int ipoe_rad_send_acct_request(struct rad_plugin_t *rad, struct rad_packet_t *pack)
@@ -2138,6 +2337,13 @@ static void ipoe_serv_release(struct ipoe_serv *serv)
__sync_sub_and_fetch(&stat_delayed_offer, 1);
}
+ while (!list_empty(&serv->arp_list)) {
+ struct arp_item *d = list_entry(serv->arp_list.next, typeof(*d), entry);
+ list_del(&d->entry);
+ mempool_free(d);
+ __sync_sub_and_fetch(&stat_delayed_offer, 1);
+ }
+
while (!list_empty(&serv->req_list)) {
struct request_item *r = list_first_entry(&serv->req_list, typeof(*r), entry);
list_del(&r->entry);
@@ -2462,6 +2668,7 @@ static void add_interface(const char *ifname, int ifindex, const char *opt, int
in_addr_t opt_src = conf_src;
int opt_arp = conf_arp;
struct ifreq ifr;
+ uint8_t hwaddr[ETH_ALEN];
str0 = strchr(opt, ',');
if (str0) {
@@ -2539,6 +2746,9 @@ static void add_interface(const char *ifname, int ifindex, const char *opt, int
}
}
+ if (!opt_arp && opt_up && opt_mode == MODE_L2)
+ opt_arp = 1;
+
if (!opt_up && !opt_dhcpv4 && !opt_auto) {
opt_up = conf_up;
opt_dhcpv4 = conf_dhcpv4;
@@ -2601,10 +2811,10 @@ static void add_interface(const char *ifname, int ifindex, const char *opt, int
if (!serv->dhcpv4_relay && serv->opt_dhcpv4 && opt_relay)
serv->dhcpv4_relay = dhcpv4_relay_create(opt_relay, opt_giaddr, &serv->ctx, (triton_event_func)ipoe_recv_dhcpv4_relay);
- if (serv->arp && !conf_arp) {
+ if (serv->arp && !opt_arp) {
arpd_stop(serv->arp);
serv->arp = NULL;
- } else if (!serv->arp && conf_arp)
+ } else if (!serv->arp && opt_arp)
serv->arp = arpd_start(serv);
serv->opt_up = opt_up;
@@ -2660,9 +2870,11 @@ static void add_interface(const char *ifname, int ifindex, const char *opt, int
return;
}
+ memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+
ioctl(sock_fd, SIOCGIFFLAGS, &ifr);
- if ((ifr.ifr_flags & IFF_UP) && opt_shared == 0) {
+ if ((ifr.ifr_flags & IFF_UP) && opt_shared == 0 && opt_ifcfg) {
int flags = ifr.ifr_flags;
ifr.ifr_flags &= ~IFF_UP;
@@ -2702,12 +2914,14 @@ static void add_interface(const char *ifname, int ifindex, const char *opt, int
serv->opt_lua_username_func = opt_lua_username_func;
#endif
serv->parent_ifindex = parent_ifindex;
+ serv->parent_vid = parent_ifindex ? iplink_vlan_get_vid(parent_ifindex, NULL) : 0;
serv->vid = vid;
serv->active = 1;
INIT_LIST_HEAD(&serv->sessions);
INIT_LIST_HEAD(&serv->disc_list);
+ INIT_LIST_HEAD(&serv->arp_list);
INIT_LIST_HEAD(&serv->req_list);
- memcpy(serv->hwaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+ memcpy(serv->hwaddr, hwaddr, ETH_ALEN);
serv->disc_timer.expire = ipoe_serv_disc_timer;
triton_context_register(&serv->ctx, NULL);
@@ -2912,25 +3126,43 @@ static void parse_conf_rad_attr(const char *opt, int *val)
{
struct rad_dict_attr_t *attr;
+ *val = 0;
+
opt = conf_get_opt("ipoe", opt);
+ if (!opt)
+ return;
- *val = 0;
+ if (conf_vendor) {
+ struct rad_dict_vendor_t *vendor = rad_dict_find_vendor_id(conf_vendor);
+ attr = rad_dict_find_vendor_attr(vendor, opt);
+ } else
+ attr = rad_dict_find_attr(opt);
- if (opt) {
- if (atoi(opt) > 0)
- *val = atoi(opt);
- else {
- attr = rad_dict_find_attr(opt);
- if (attr)
- *val = attr->id;
- else
- log_emerg("ipoe: couldn't find '%s' in dictionary\n", opt);
- }
- }
+ if (attr)
+ *val = attr->id;
+ else if (atoi(opt) > 0)
+ *val = atoi(opt);
+ else
+ log_emerg("ipoe: couldn't find '%s' in dictionary\n", opt);
}
static void load_radius_attrs(void)
{
+ const char *vendor = conf_get_opt("ipoe", "vendor");
+
+ if (vendor) {
+ struct rad_dict_vendor_t *v = rad_dict_find_vendor_name(vendor);
+ if (v)
+ conf_vendor = v->id;
+ else {
+ conf_vendor = atoi(vendor);
+ if (!rad_dict_find_vendor_id(conf_vendor)) {
+ conf_vendor = 0;
+ log_emerg("ipoe: vendor '%s' not found\n", vendor);
+ }
+ }
+ }
+
parse_conf_rad_attr("attr-dhcp-client-ip", &conf_attr_dhcp_client_ip);
parse_conf_rad_attr("attr-dhcp-router-ip", &conf_attr_dhcp_router_ip);
parse_conf_rad_attr("attr-dhcp-mask", &conf_attr_dhcp_mask);
@@ -3145,9 +3377,6 @@ static void load_vlan_mon(struct conf_sect_t *sect)
long mask[4096/8/sizeof(long)];
static int registered = 0;
- if (!triton_module_loaded("vlan-mon"))
- return;
-
if (!registered) {
vlan_mon_register_proto(ETH_P_IP, ipoe_vlan_mon_notify);
registered = 1;
@@ -3255,7 +3484,7 @@ static void load_config(void)
if (!s)
return;
- net = &def_net;
+ net = def_net;
opt = conf_get_opt("ipoe", "username");
if (opt) {
@@ -3525,6 +3754,7 @@ static void ipoe_init(void)
{
ses_pool = mempool_create(sizeof(struct ipoe_session));
disc_item_pool = mempool_create(sizeof(struct disc_item));
+ arp_item_pool = mempool_create(sizeof(struct arp_item));
req_item_pool = mempool_create(sizeof(struct request_item));
uc_pool = mempool_create(sizeof(struct unit_cache));
diff --git a/accel-pppd/ctrl/ipoe/ipoe.h b/accel-pppd/ctrl/ipoe/ipoe.h
index e398648e..f8bc82bf 100644
--- a/accel-pppd/ctrl/ipoe/ipoe.h
+++ b/accel-pppd/ctrl/ipoe/ipoe.h
@@ -41,6 +41,7 @@ struct ipoe_serv {
struct dhcpv4_relay *dhcpv4_relay;
void *arp;
struct list_head disc_list;
+ struct list_head arp_list;
struct list_head req_list;
struct triton_timer_t disc_timer;
struct triton_timer_t timer;
@@ -111,6 +112,7 @@ struct ipoe_session {
int l4_redirect_set:1;
int terminate:1;
int UP:1;
+ int wait_start:1;
};
struct ipoe_session_info {
@@ -133,6 +135,7 @@ void ipoe_recv_up(int ifindex, struct ethhdr *eth, struct iphdr *iph, struct _ar
struct ipoe_session *ipoe_session_alloc(const char *ifname);
struct ipoe_serv *ipoe_find_serv(const char *ifname);
+void ipoe_serv_recv_arp(struct ipoe_serv *s, struct _arphdr *arph);
void ipoe_nl_add_interface(int ifindex, uint8_t mode);
void ipoe_nl_del_interface(int ifindex);
@@ -148,7 +151,7 @@ void ipoe_nl_del_net(uint32_t addr);
void *arpd_start(struct ipoe_serv *ipoe);
void arpd_stop(void *arp);
-void arp_send(int ifindex, struct _arphdr *arph);
+void arp_send(int ifindex, struct _arphdr *arph, int bc);
#endif
diff --git a/accel-pppd/ctrl/ipoe/ipoe_netlink.c b/accel-pppd/ctrl/ipoe/ipoe_netlink.c
index df135458..54a5423a 100644
--- a/accel-pppd/ctrl/ipoe/ipoe_netlink.c
+++ b/accel-pppd/ctrl/ipoe/ipoe_netlink.c
@@ -606,8 +606,16 @@ static void ipoe_mc_close(struct triton_context_t *ctx)
triton_context_unregister(ctx);
}
+static void ipoe_mc_ctx_switch(struct triton_context_t *ctx, void *arg)
+{
+ net = def_net;
+ log_switch(NULL, NULL);
+}
+
+
static struct triton_context_t mc_ctx = {
.close = ipoe_mc_close,
+ .before_switch = ipoe_mc_ctx_switch,
};
static struct triton_md_handler_t mc_hnd = {
diff --git a/accel-pppd/ctrl/ipoe/lua.c b/accel-pppd/ctrl/ipoe/lua.c
index 0f5a1dc4..d5f9e95d 100644
--- a/accel-pppd/ctrl/ipoe/lua.c
+++ b/accel-pppd/ctrl/ipoe/lua.c
@@ -32,8 +32,10 @@ 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);
+static int packet4_vlan(lua_State *L);
int luaopen_lpack(lua_State *L);
+int luaopen_bit(lua_State *L);
static const struct luaL_reg packet4_lib [] = {
{"hdr", packet4_hdr},
@@ -42,6 +44,7 @@ static const struct luaL_reg packet4_lib [] = {
{"options", packet4_options},
{"agent_circuit_id", packet4_agent_circuit_id},
{"agent_remote_id", packet4_agent_remote_id},
+ {"vlan", packet4_vlan},
{NULL, NULL}
};
@@ -170,6 +173,18 @@ static int packet4_agent_remote_id(lua_State *L)
return 1;
}
+static int packet4_vlan(lua_State *L)
+{
+ struct ipoe_session *ses = luaL_checkudata(L, 1, IPOE_PACKET4);
+
+ if (!ses)
+ return 0;
+
+ lua_pushinteger(L, (ses->serv->parent_vid << 16) | ses->serv->vid);
+
+ return 1;
+}
+
static void init_lua()
{
__serial = serial;
@@ -179,6 +194,7 @@ static void init_lua()
luaL_openlibs(L);
luaopen_lpack(L);
+ luaopen_bit(L);
luaopen_packet4(L);
if (luaL_loadfile(L, conf_filename))
diff --git a/accel-pppd/ctrl/ipoe/lua_bit.c b/accel-pppd/ctrl/ipoe/lua_bit.c
new file mode 100644
index 00000000..690df7d3
--- /dev/null
+++ b/accel-pppd/ctrl/ipoe/lua_bit.c
@@ -0,0 +1,189 @@
+/*
+** Lua BitOp -- a bit operations library for Lua 5.1/5.2.
+** http://bitop.luajit.org/
+**
+** Copyright (C) 2008-2012 Mike Pall. All rights reserved.
+**
+** Permission is hereby granted, free of charge, to any person obtaining
+** a copy of this software and associated documentation files (the
+** "Software"), to deal in the Software without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Software, and to
+** permit persons to whom the Software is furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be
+** included in all copies or substantial portions of the Software.
+**
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+**
+** [ MIT license: http://www.opensource.org/licenses/mit-license.php ]
+*/
+
+#define LUA_BITOP_VERSION "1.0.2"
+
+#define LUA_LIB
+#include "lua.h"
+#include "lauxlib.h"
+
+#ifdef _MSC_VER
+/* MSVC is stuck in the last century and doesn't have C99's stdint.h. */
+typedef __int32 int32_t;
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int64 uint64_t;
+#else
+#include <stdint.h>
+#endif
+
+typedef int32_t SBits;
+typedef uint32_t UBits;
+
+typedef union {
+ lua_Number n;
+#ifdef LUA_NUMBER_DOUBLE
+ uint64_t b;
+#else
+ UBits b;
+#endif
+} BitNum;
+
+/* Convert argument to bit type. */
+static UBits barg(lua_State *L, int idx)
+{
+ BitNum bn;
+ UBits b;
+#if LUA_VERSION_NUM < 502
+ bn.n = lua_tonumber(L, idx);
+#else
+ bn.n = luaL_checknumber(L, idx);
+#endif
+#if defined(LUA_NUMBER_DOUBLE)
+ bn.n += 6755399441055744.0; /* 2^52+2^51 */
+#ifdef SWAPPED_DOUBLE
+ b = (UBits)(bn.b >> 32);
+#else
+ b = (UBits)bn.b;
+#endif
+#elif defined(LUA_NUMBER_INT) || defined(LUA_NUMBER_LONG) || \
+ defined(LUA_NUMBER_LONGLONG) || defined(LUA_NUMBER_LONG_LONG) || \
+ defined(LUA_NUMBER_LLONG)
+ if (sizeof(UBits) == sizeof(lua_Number))
+ b = bn.b;
+ else
+ b = (UBits)(SBits)bn.n;
+#elif defined(LUA_NUMBER_FLOAT)
+#error "A 'float' lua_Number type is incompatible with this library"
+#else
+#error "Unknown number type, check LUA_NUMBER_* in luaconf.h"
+#endif
+#if LUA_VERSION_NUM < 502
+ if (b == 0 && !lua_isnumber(L, idx)) {
+ luaL_typerror(L, idx, "number");
+ }
+#endif
+ return b;
+}
+
+/* Return bit type. */
+#define BRET(b) lua_pushnumber(L, (lua_Number)(SBits)(b)); return 1;
+
+static int bit_tobit(lua_State *L) { BRET(barg(L, 1)) }
+static int bit_bnot(lua_State *L) { BRET(~barg(L, 1)) }
+
+#define BIT_OP(func, opr) \
+ static int func(lua_State *L) { int i; UBits b = barg(L, 1); \
+ for (i = lua_gettop(L); i > 1; i--) b opr barg(L, i); BRET(b) }
+BIT_OP(bit_band, &=)
+BIT_OP(bit_bor, |=)
+BIT_OP(bit_bxor, ^=)
+
+#define bshl(b, n) (b << n)
+#define bshr(b, n) (b >> n)
+#define bsar(b, n) ((SBits)b >> n)
+#define brol(b, n) ((b << n) | (b >> (32-n)))
+#define bror(b, n) ((b << (32-n)) | (b >> n))
+#define BIT_SH(func, fn) \
+ static int func(lua_State *L) { \
+ UBits b = barg(L, 1); UBits n = barg(L, 2) & 31; BRET(fn(b, n)) }
+BIT_SH(bit_lshift, bshl)
+BIT_SH(bit_rshift, bshr)
+BIT_SH(bit_arshift, bsar)
+BIT_SH(bit_rol, brol)
+BIT_SH(bit_ror, bror)
+
+static int bit_bswap(lua_State *L)
+{
+ UBits b = barg(L, 1);
+ b = (b >> 24) | ((b >> 8) & 0xff00) | ((b & 0xff00) << 8) | (b << 24);
+ BRET(b)
+}
+
+static int bit_tohex(lua_State *L)
+{
+ UBits b = barg(L, 1);
+ SBits n = lua_isnone(L, 2) ? 8 : (SBits)barg(L, 2);
+ const char *hexdigits = "0123456789abcdef";
+ char buf[8];
+ int i;
+ if (n < 0) { n = -n; hexdigits = "0123456789ABCDEF"; }
+ if (n > 8) n = 8;
+ for (i = (int)n; --i >= 0; ) { buf[i] = hexdigits[b & 15]; b >>= 4; }
+ lua_pushlstring(L, buf, (size_t)n);
+ return 1;
+}
+
+static const struct luaL_Reg bit_funcs[] = {
+ { "tobit", bit_tobit },
+ { "bnot", bit_bnot },
+ { "band", bit_band },
+ { "bor", bit_bor },
+ { "bxor", bit_bxor },
+ { "lshift", bit_lshift },
+ { "rshift", bit_rshift },
+ { "arshift", bit_arshift },
+ { "rol", bit_rol },
+ { "ror", bit_ror },
+ { "bswap", bit_bswap },
+ { "tohex", bit_tohex },
+ { NULL, NULL }
+};
+
+/* Signed right-shifts are implementation-defined per C89/C99.
+** But the de facto standard are arithmetic right-shifts on two's
+** complement CPUs. This behaviour is required here, so test for it.
+*/
+#define BAD_SAR (bsar(-8, 2) != (SBits)-2)
+
+LUALIB_API int luaopen_bit(lua_State *L)
+{
+ UBits b;
+ lua_pushnumber(L, (lua_Number)1437217655L);
+ b = barg(L, -1);
+ if (b != (UBits)1437217655L || BAD_SAR) { /* Perform a simple self-test. */
+ const char *msg = "compiled with incompatible luaconf.h";
+#ifdef LUA_NUMBER_DOUBLE
+#ifdef _WIN32
+ if (b == (UBits)1610612736L)
+ msg = "use D3DCREATE_FPU_PRESERVE with DirectX";
+#endif
+ if (b == (UBits)1127743488L)
+ msg = "not compiled with SWAPPED_DOUBLE";
+#endif
+ if (BAD_SAR)
+ msg = "arithmetic right-shift broken";
+ luaL_error(L, "bit library self-test failed (%s)", msg);
+ }
+#if LUA_VERSION_NUM < 502
+ luaL_register(L, "bit", bit_funcs);
+#else
+ luaL_newlib(L, bit_funcs);
+#endif
+ return 1;
+}
+
diff --git a/accel-pppd/ctrl/l2tp/l2tp.c b/accel-pppd/ctrl/l2tp/l2tp.c
index 72264aa5..51f8e7dc 100644
--- a/accel-pppd/ctrl/l2tp/l2tp.c
+++ b/accel-pppd/ctrl/l2tp/l2tp.c
@@ -255,7 +255,13 @@ static inline int nsnr_cmp(uint16_t ns, uint16_t nr)
static void l2tp_ctx_switch(struct triton_context_t *ctx, void *arg)
{
- net = &def_net;
+ struct ap_session *apses = arg;
+
+ if (apses)
+ net = apses->net;
+ else
+ net = def_net;
+
log_switch(ctx, arg);
}
@@ -2731,6 +2737,9 @@ static int l2tp_recv_SCCRQ(const struct l2tp_serv_t *serv,
return 0;
}
+ if (conf_max_sessions && ap_session_stat.active + ap_session_stat.starting >= conf_max_sessions)
+ return 0;
+
if (triton_module_loaded("connlimit")
&& connlimit_check(cl_key_from_ipv4(pack->addr.sin_addr.s_addr))) {
log_warn("l2tp: connection limits reached,"
@@ -3257,6 +3266,9 @@ static int l2tp_recv_ICRQ(struct l2tp_conn_t *conn,
return 0;
}
+ if (conf_max_sessions && ap_session_stat.active + ap_session_stat.starting >= conf_max_sessions)
+ return 0;
+
if (triton_module_loaded("connlimit")
&& connlimit_check(cl_key_from_ipv4(conn->peer_addr.sin_addr.s_addr))) {
log_tunnel(log_warn, conn, "connection limits reached,"
@@ -3557,6 +3569,9 @@ static int l2tp_recv_OCRQ(struct l2tp_conn_t *conn,
return 0;
}
+ if (conf_max_sessions && ap_session_stat.active + ap_session_stat.starting >= conf_max_sessions)
+ return 0;
+
if (triton_module_loaded("connlimit")
&& connlimit_check(cl_key_from_ipv4(conn->peer_addr.sin_addr.s_addr))) {
log_tunnel(log_warn, conn, "connection limits reached,"
@@ -4910,6 +4925,19 @@ static void load_config(void)
}
conf_ip_pool = conf_get_opt("l2tp", "ip-pool");
+
+ switch (iprange_check_activation()) {
+ case IPRANGE_DISABLED:
+ log_warn("l2tp: iprange module disabled, improper IP configuration of PPP interfaces may cause kernel soft lockup\n");
+ break;
+ case IPRANGE_NO_RANGE:
+ log_warn("l2tp: no IP address range defined in section [%s], incoming L2TP connections will be rejected\n",
+ IPRANGE_CONF_SECTION);
+ break;
+ default:
+ /* Makes compiler happy */
+ break;
+ }
}
static void l2tp_init(void)
diff --git a/accel-pppd/ctrl/pppoe/CMakeLists.txt b/accel-pppd/ctrl/pppoe/CMakeLists.txt
index 5e1cbdc6..808cd513 100644
--- a/accel-pppd/ctrl/pppoe/CMakeLists.txt
+++ b/accel-pppd/ctrl/pppoe/CMakeLists.txt
@@ -14,5 +14,7 @@ ENDIF(RADIUS)
ADD_LIBRARY(pppoe SHARED ${sources})
TARGET_LINK_LIBRARIES(pppoe vlan-mon)
+set_property(TARGET pppoe PROPERTY CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
+set_property(TARGET pppoe PROPERTY INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}/accel-ppp)
INSTALL(TARGETS pppoe LIBRARY DESTINATION lib${LIB_SUFFIX}/accel-ppp)
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 1d836f54..c5721765 100644
--- a/accel-pppd/ctrl/pppoe/pppoe.c
+++ b/accel-pppd/ctrl/pppoe/pppoe.c
@@ -265,7 +265,7 @@ static int pppoe_rad_send_accounting_request(struct rad_plugin_t *rad, struct ra
static void pppoe_conn_ctx_switch(struct triton_context_t *ctx, void *arg)
{
struct pppoe_conn_t *conn = arg;
- net = conn->serv->net;
+ net = conn->ppp.ses.net;
log_switch(ctx, &conn->ppp.ses);
}
@@ -401,6 +401,7 @@ static struct pppoe_conn_t *allocate_channel(struct pppoe_serv_t *serv, const ui
ppp_init(&conn->ppp);
+ conn->ppp.ses.net = serv->net;
conn->ppp.ses.ctrl = &conn->ctrl;
conn->ppp.ses.chan_name = conn->ctrl.calling_station_id;
@@ -428,7 +429,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;
}
@@ -748,7 +749,7 @@ static void pppoe_send(struct pppoe_serv_t *serv, const uint8_t *pack)
struct pppoe_hdr *hdr = (struct pppoe_hdr *)(pack + ETH_HLEN);
int len = ETH_HLEN + sizeof(*hdr) + ntohs(hdr->length);
- sendto(serv->disc_sock, pack, len, MSG_DONTWAIT, (struct sockaddr *)&addr, sizeof(addr));
+ net->sendto(serv->disc_sock, pack, len, MSG_DONTWAIT, (struct sockaddr *)&addr, sizeof(addr));
}
static void pppoe_send_PADO(struct pppoe_serv_t *serv, const uint8_t *addr, const struct pppoe_tag *host_uniq, const struct pppoe_tag *relay_sid, const struct pppoe_tag *service_name, uint16_t ppp_max_payload)
@@ -955,6 +956,9 @@ static void pppoe_recv_PADI(struct pppoe_serv_t *serv, uint8_t *pack, int size)
if (ap_shutdown || pado_delay == -1)
return;
+ if (conf_max_sessions && ap_session_stat.active + ap_session_stat.starting >= conf_max_sessions)
+ return;
+
if (check_padi_limit(serv, ethhdr->h_source)) {
__sync_add_and_fetch(&stat_PADI_drop, 1);
if (conf_verbose) {
@@ -1078,6 +1082,9 @@ static void pppoe_recv_PADR(struct pppoe_serv_t *serv, uint8_t *pack, int size)
if (ap_shutdown)
return;
+ if (conf_max_sessions && ap_session_stat.active + ap_session_stat.starting >= conf_max_sessions)
+ return;
+
if (!memcmp(ethhdr->h_dest, bc_addr, ETH_ALEN)) {
if (conf_verbose)
log_warn("pppoe: discard PADR (destination address is broadcast)\n");
@@ -1280,14 +1287,32 @@ static void pppoe_serv_timeout(struct triton_timer_t *t)
pppoe_server_free(serv);
}
-static int parse_server(const char *opt, int *padi_limit)
+static int parse_server(const char *opt, int *padi_limit, struct ap_net **net)
{
char *ptr, *endptr;
+ char name[64];
- ptr = strstr(opt, ",padi-limit=");
- if (ptr) {
- *padi_limit = strtol(ptr + 12, &endptr, 10);
- if (*endptr != 0 && *endptr != ',')
+ while (*opt == ',') {
+ opt++;
+ ptr = strchr(opt, '=');
+ if (!ptr)
+ goto out_err;
+ if (!strncmp(opt, "padi-limit=", sizeof("padi-limit=") - 1)) {
+ *padi_limit = strtol(ptr + 1, &endptr, 10);
+ if (*endptr != 0 && *endptr != ',')
+ goto out_err;
+ opt = endptr;
+ } else if (!strncmp(opt, "net=", sizeof("net=") - 1)) {
+ ptr++;
+ for (endptr = ptr + 1; *endptr && *endptr != ','; endptr++);
+ if (endptr - ptr >= sizeof(name))
+ goto out_err;
+ memcpy(name, ptr, endptr - ptr);
+ name[endptr - ptr] = 0;
+ *net = ap_net_find(name);
+ if (!*net)
+ goto out_err;
+ } else
goto out_err;
}
@@ -1370,18 +1395,20 @@ static void __pppoe_server_start(const char *ifname, const char *opt, void *cli,
struct pppoe_serv_t *serv;
struct ifreq ifr;
int padi_limit = conf_padi_limit;
- const struct ap_net *net = &def_net;
+ struct ap_net *net = def_net;
- if (parse_server(opt, &padi_limit)) {
+ if (parse_server(opt, &padi_limit, &net)) {
if (cli)
cli_sendv(cli, "failed to parse '%s'\r\n", opt);
else
log_error("pppoe: failed to parse '%s'\r\n", opt);
+
+ return;
}
pthread_rwlock_rdlock(&serv_lock);
list_for_each_entry(serv, &serv_list, entry) {
- if (!strcmp(serv->ifname, ifname)) {
+ if (serv->net == net && !strcmp(serv->ifname, ifname)) {
if (cli)
cli_send(cli, "error: already exists\r\n");
pthread_rwlock_unlock(&serv_lock);
@@ -1456,7 +1483,7 @@ static void __pppoe_server_start(const char *ifname, const char *opt, void *cli,
goto out_err;
}
- if (parent_ifindex == -1)
+ if (parent_ifindex == -1 && net == def_net)
vid = iplink_vlan_get_vid(ifr.ifr_ifindex, &parent_ifindex);
serv->ctx.close = pppoe_serv_close;
@@ -1860,9 +1887,6 @@ static void load_vlan_mon(struct conf_sect_t *sect)
long mask[4096/8/sizeof(long)];
static int registered = 0;
- if (!triton_module_loaded("vlan-mon"))
- return;
-
if (!registered) {
vlan_mon_register_proto(ETH_P_PPP_DISC, pppoe_vlan_mon_notify);
registered = 1;
diff --git a/accel-pppd/ctrl/pppoe/pppoe.h b/accel-pppd/ctrl/pppoe/pppoe.h
index 059c9aed..1ea7b07d 100644
--- a/accel-pppd/ctrl/pppoe/pppoe.h
+++ b/accel-pppd/ctrl/pppoe/pppoe.h
@@ -70,7 +70,7 @@ struct pppoe_serv_t
struct triton_context_t ctx;
struct rb_node node;
- const struct ap_net *net;
+ struct ap_net *net;
int disc_sock;
uint8_t hwaddr[ETH_ALEN];
diff --git a/accel-pppd/ctrl/pptp/pptp.c b/accel-pppd/ctrl/pptp/pptp.c
index 0a0afa4d..99958cc8 100644
--- a/accel-pppd/ctrl/pptp/pptp.c
+++ b/accel-pppd/ctrl/pptp/pptp.c
@@ -75,7 +75,11 @@ static void ppp_finished(struct ap_session *);
static void pptp_ctx_switch(struct triton_context_t *ctx, void *arg)
{
- net = &def_net;
+ if (arg) {
+ struct ap_session *s = arg;
+ net = s->net;
+ } else
+ net = def_net;
log_switch(ctx, arg);
}
@@ -644,9 +648,14 @@ static int pptp_connect(struct triton_md_handler_t *h)
continue;
}
+ if (conf_max_sessions && ap_session_stat.active + ap_session_stat.starting >= conf_max_sessions) {
+ close(sock);
+ continue;
+ }
+
if (triton_module_loaded("connlimit") && connlimit_check(cl_key_from_ipv4(addr.sin_addr.s_addr))) {
close(sock);
- return 0;
+ continue;
}
log_info2("pptp: new connection from %s\n", inet_ntoa(addr.sin_addr));
@@ -773,6 +782,19 @@ static void load_config(void)
}
conf_ip_pool = conf_get_opt("pptp", "ip-pool");
+
+ switch (iprange_check_activation()) {
+ case IPRANGE_DISABLED:
+ log_warn("pptp: iprange module disabled, improper IP configuration of PPP interfaces may cause kernel soft lockup\n");
+ break;
+ case IPRANGE_NO_RANGE:
+ log_warn("pptp: no IP address range defined in section [%s], incoming PPTP connections will be rejected\n",
+ IPRANGE_CONF_SECTION);
+ break;
+ default:
+ /* Makes compiler happy */
+ break;
+ }
}
static void pptp_init(void)
diff --git a/accel-pppd/extra/chap-secrets.c b/accel-pppd/extra/chap-secrets.c
index b693a326..f99bd0b9 100644
--- a/accel-pppd/extra/chap-secrets.c
+++ b/accel-pppd/extra/chap-secrets.c
@@ -7,7 +7,6 @@
#include <arpa/inet.h>
#ifdef CRYPTO_OPENSSL
-#include "openssl/evp.h"
#include "crypto.h"
#endif
@@ -129,7 +128,7 @@ static struct cs_pd_t *create_pd(struct ap_session *ses, const char *username)
char username_hash[EVP_MAX_MD_SIZE * 2 + 1];
uint8_t hash[EVP_MAX_MD_SIZE];
struct hash_chain *hc;
- EVP_MD_CTX md_ctx;
+ EVP_MD_CTX *md_ctx = NULL;
char c;
#endif
@@ -140,11 +139,13 @@ static struct cs_pd_t *create_pd(struct ap_session *ses, const char *username)
if (conf_encrypted && !list_empty(&hash_chain)) {
unsigned int size = 0;
list_for_each_entry(hc, &hash_chain, entry) {
- EVP_MD_CTX_init(&md_ctx);
- EVP_DigestInit_ex(&md_ctx, hc->md, NULL);
- EVP_DigestUpdate(&md_ctx, size == 0 ? (void *)username : (void *)hash, size == 0 ? strlen(username) : size);
- EVP_DigestFinal_ex(&md_ctx, hash, &size);
- EVP_MD_CTX_cleanup(&md_ctx);
+ md_ctx = EVP_MD_CTX_new();
+ EVP_MD_CTX_init(md_ctx);
+ EVP_DigestInit_ex(md_ctx, hc->md, NULL);
+ EVP_DigestUpdate(md_ctx, size == 0 ? (void *)username : (void *)hash, size == 0 ? strlen(username) : size);
+ EVP_DigestFinal_ex(md_ctx, hash, &size);
+ EVP_MD_CTX_free(md_ctx);
+ md_ctx = NULL;
}
for (n = 0; n < size; n++)
diff --git a/accel-pppd/extra/net-snmp/sessionTable_data_get.h b/accel-pppd/extra/net-snmp/sessionTable_data_get.h
index 82107200..37a3accb 100644
--- a/accel-pppd/extra/net-snmp/sessionTable_data_get.h
+++ b/accel-pppd/extra/net-snmp/sessionTable_data_get.h
@@ -19,6 +19,10 @@
extern "C" {
#endif
+#ifndef U64
+ typedef struct counter64 U64;
+#endif
+
/* *********************************************************************
* GET function declarations
*/
diff --git a/accel-pppd/extra/pppd_compat.c b/accel-pppd/extra/pppd_compat.c
index 2956624d..d54743c8 100644
--- a/accel-pppd/extra/pppd_compat.c
+++ b/accel-pppd/extra/pppd_compat.c
@@ -468,7 +468,7 @@ static void write_radattr(struct pppd_compat_pd *pd, struct rad_packet_t *pack)
fprintf(f, "%i.%i.%i.%i\n", (addr >> 24) & 0xff, (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff);
break;
case ATTR_TYPE_DATE:
- fprintf(f, "%lu\n", attr->val.date);
+ fprintf(f, "%lu\n", (unsigned long) attr->val.date);
break;
}
}
@@ -525,49 +525,112 @@ static void build_addr(struct ipv6db_addr_t *a, uint64_t intf_id, struct in6_add
static void fill_env(char **env, char *mem, struct pppd_compat_pd *pd)
{
struct ap_session *ses = pd->ses;
- uint64_t tx_bytes, rx_bytes;
+ size_t mem_sz = ENV_MEM;
+ int write_sz;
int n = 0;
- tx_bytes = (uint64_t)ses->acct_tx_bytes + 4294967296llu*ses->acct_output_gigawords;
- rx_bytes = (uint64_t)ses->acct_rx_bytes + 4294967296llu*ses->acct_input_gigawords;
-
- env[n++] = mem;
- mem += sprintf(mem, "PEERNAME=%s", pd->ses->username) + 1;
- env[n++] = mem;
- mem += sprintf(mem, "CALLING_SID=%s", pd->ses->ctrl->calling_station_id) + 1;
- env[n++] = mem;
- mem += sprintf(mem, "CALLED_SID=%s", pd->ses->ctrl->called_station_id) + 1;
+ env[n] = mem;
+ write_sz = snprintf(mem, mem_sz, "PEERNAME=%s", pd->ses->username);
+ if (write_sz < 0 || write_sz >= mem_sz)
+ goto out;
+ mem_sz -= write_sz + 1;
+ mem += write_sz + 1;
+ ++n;
+
+ env[n] = mem;
+ write_sz = snprintf(mem, mem_sz, "CALLING_SID=%s",
+ pd->ses->ctrl->calling_station_id);
+ if (write_sz < 0 || write_sz >= mem_sz)
+ goto out;
+ mem_sz -= write_sz + 1;
+ mem += write_sz + 1;
+ ++n;
+
+ env[n] = mem;
+ write_sz = snprintf(mem, mem_sz, "CALLED_SID=%s",
+ pd->ses->ctrl->called_station_id);
+ if (write_sz < 0 || write_sz >= mem_sz)
+ goto out;
+ mem_sz -= write_sz + 1;
+ mem += write_sz + 1;
+ ++n;
if (ses->ipv6) {
///FIXME only first address is passed to env
- struct ipv6db_addr_t *a = list_first_entry(&ses->ipv6->addr_list, typeof(*a), entry);
+ struct ipv6db_addr_t *a = list_first_entry(&ses->ipv6->addr_list,
+ typeof(*a), entry);
+ char ip6_buf[INET6_ADDRSTRLEN];
struct in6_addr addr;
+
build_addr(a, ses->ipv6->peer_intf_id, &addr);
- env[n++] = mem;
- strcpy(mem, "IPV6_PREFIX="); mem += 12;
- inet_ntop(AF_INET6, &addr, mem, ENV_MEM); mem = strchr(mem, 0);
- mem += sprintf(mem, "/%i", a->prefix_len) + 1;
+
+ env[n] = mem;
+ write_sz = snprintf(mem, mem_sz, "IPV6_PREFIX=%s/%i",
+ inet_ntop(AF_INET6, &addr, ip6_buf,
+ sizeof(ip6_buf)),
+ a->prefix_len);
+ if (write_sz < 0 || write_sz >= mem_sz)
+ goto out;
+ mem_sz -= write_sz + 1;
+ mem += write_sz + 1;
+ ++n;
}
if (ses->ipv6_dp) {
///FIXME only first prefix is passed to env
- struct ipv6db_addr_t *a = list_first_entry(&ses->ipv6_dp->prefix_list, typeof(*a), entry);
- env[n++] = mem;
- strcpy(mem, "IPV6_DELEGATED_PREFIX="); mem += 22;
- inet_ntop(AF_INET6, &a->addr, mem, ENV_MEM); mem = strchr(mem, 0);
- mem += sprintf(mem, "/%i", a->prefix_len) + 1;
+ struct ipv6db_addr_t *a = list_first_entry(&ses->ipv6_dp->prefix_list,
+ typeof(*a), entry);
+ char ip6_buf[INET6_ADDRSTRLEN];
+
+ env[n] = mem;
+ write_sz = snprintf(mem, mem_sz, "IPV6_DELEGATED_PREFIX=%s/%i",
+ inet_ntop(AF_INET6, &a->addr, ip6_buf,
+ sizeof(ip6_buf)),
+ a->prefix_len);
+ if (write_sz < 0 || write_sz >= mem_sz)
+ goto out;
+ mem_sz -= write_sz + 1;
+ mem += write_sz + 1;
+ ++n;
}
if (pd->ses->stop_time) {
- env[n++] = mem;
- mem += sprintf(mem, "CONNECT_TIME=%lu", pd->ses->stop_time - pd->ses->start_time) + 1;
- env[n++] = mem;
- mem += sprintf(mem, "BYTES_SENT=%" PRIu64, tx_bytes) + 1;
- env[n++] = mem;
- mem += sprintf(mem, "BYTES_RCVD=%" PRIu64, rx_bytes) + 1;
+ uint64_t gword_sz = (uint64_t)UINT32_MAX + 1;
+ uint64_t tx_bytes;
+ uint64_t rx_bytes;
+
+ tx_bytes = ses->acct_tx_bytes + gword_sz * ses->acct_output_gigawords;
+ rx_bytes = ses->acct_rx_bytes + gword_sz * ses->acct_input_gigawords;
+
+ env[n] = mem;
+ write_sz = snprintf(mem, mem_sz, "CONNECT_TIME=%lu",
+ (unsigned long)(pd->ses->stop_time -
+ pd->ses->start_time));
+ if (write_sz < 0 || write_sz >= mem_sz)
+ goto out;
+ mem_sz -= write_sz + 1;
+ mem += write_sz + 1;
+ ++n;
+
+ env[n] = mem;
+ write_sz = snprintf(mem, mem_sz, "BYTES_SENT=%" PRIu64,
+ tx_bytes);
+ if (write_sz < 0 || write_sz >= mem_sz)
+ goto out;
+ mem_sz -= write_sz + 1;
+ mem += write_sz + 1;
+ ++n;
+
+ env[n] = mem;
+ write_sz = snprintf(mem, mem_sz, "BYTES_RCVD=%" PRIu64,
+ rx_bytes);
+ if (write_sz < 0 || write_sz >= mem_sz)
+ goto out;
+ ++n;
}
- env[n++] = NULL;
+out:
+ env[n] = NULL;
}
static void init(void)
diff --git a/accel-pppd/ifcfg.c b/accel-pppd/ifcfg.c
index 3a1fffd0..5e7c790a 100644
--- a/accel-pppd/ifcfg.c
+++ b/accel-pppd/ifcfg.c
@@ -149,9 +149,11 @@ void __export ap_session_accounting_started(struct ap_session *ses)
}
if (ses->ipv6) {
+ net->enter_ns();
devconf(ses, "accept_ra", "0");
devconf(ses, "autoconf", "0");
devconf(ses, "forwarding", "1");
+ net->exit_ns();
memset(&ifr6, 0, sizeof(ifr6));
@@ -161,7 +163,7 @@ void __export ap_session_accounting_started(struct ap_session *ses)
ifr6.ifr6_prefixlen = 64;
ifr6.ifr6_ifindex = ses->ifindex;
- if (ioctl(sock6_fd, SIOCSIFADDR, &ifr6))
+ if (net->sock6_ioctl(SIOCSIFADDR, &ifr6))
log_ppp_error("faild to set LL IPv6 address: %s\n", strerror(errno));
}
@@ -246,7 +248,7 @@ void __export ap_session_ifdown(struct ap_session *ses)
ifr6.ifr6_addr.s6_addr32[0] = htonl(0xfe800000);
*(uint64_t *)(ifr6.ifr6_addr.s6_addr + 8) = ses->ipv6->intf_id;
ifr6.ifr6_prefixlen = 64;
- ioctl(sock6_fd, SIOCDIFADDR, &ifr6);
+ net->sock6_ioctl(SIOCDIFADDR, &ifr6);
}
list_for_each_entry(a, &ses->ipv6->addr_list, entry) {
@@ -267,42 +269,72 @@ void __export ap_session_ifdown(struct ap_session *ses)
int __export ap_session_rename(struct ap_session *ses, const char *ifname, int len)
{
struct ifreq ifr;
- int r, up = 0;
+ int i, r, up = 0;
+ struct ap_net *ns = NULL;
+ char ns_name[256];
if (len == -1)
len = strlen(ifname);
+ for (i = 0; i < len; i++) {
+ if (ifname[i] == '/') {
+ memcpy(ns_name, ifname, i);
+ ns_name[i] = 0;
+
+ ns = ap_net_open_ns(ns_name);
+ if (!ns)
+ return -1;
+
+ ifname += i + 1;
+ len -= i + 1;
+ break;
+ }
+ }
+
if (len >= IFNAMSIZ) {
- log_ppp_warn("cannot rename interface (name is too long)\n");
+ log_ppp_error("cannot rename interface (name is too long)\n");
return -1;
}
- strcpy(ifr.ifr_name, ses->ifname);
- memcpy(ifr.ifr_newname, ifname, len);
- ifr.ifr_newname[len] = 0;
-
- r = net->sock_ioctl(SIOCSIFNAME, &ifr);
- if (r && errno == EBUSY) {
- net->sock_ioctl(SIOCGIFFLAGS, &ifr);
- ifr.ifr_flags &= ~IFF_UP;
- net->sock_ioctl(SIOCSIFFLAGS, &ifr);
-
+ if (len) {
+ strcpy(ifr.ifr_name, ses->ifname);
memcpy(ifr.ifr_newname, ifname, len);
ifr.ifr_newname[len] = 0;
+
r = net->sock_ioctl(SIOCSIFNAME, &ifr);
+ if (r && errno == EBUSY) {
+ net->sock_ioctl(SIOCGIFFLAGS, &ifr);
+ ifr.ifr_flags &= ~IFF_UP;
+ net->sock_ioctl(SIOCSIFFLAGS, &ifr);
+
+ memcpy(ifr.ifr_newname, ifname, len);
+ ifr.ifr_newname[len] = 0;
+ r = net->sock_ioctl(SIOCSIFNAME, &ifr);
+
+ up = 1;
+ }
- up = 1;
+ if (r) {
+ if (!ses->ifname_rename)
+ ses->ifname_rename = _strdup(ifr.ifr_newname);
+ else
+ log_ppp_warn("interface rename to %s failed: %s\n", ifr.ifr_newname, strerror(errno));
+ } else {
+ log_ppp_info2("rename interface to '%s'\n", ifr.ifr_newname);
+ memcpy(ses->ifname, ifname, len);
+ ses->ifname[len] = 0;
+ }
}
- if (r) {
- if (!ses->ifname_rename)
- ses->ifname_rename = _strdup(ifr.ifr_newname);
- else
- log_ppp_warn("interface rename failed: %s\n", strerror(errno));
- } else {
- log_ppp_info2("rename interface to '%s'\n", ifr.ifr_newname);
- memcpy(ses->ifname, ifname, len);
- ses->ifname[len] = 0;
+ if (ns) {
+ if (net->move_link(ns, ses->ifindex)) {
+ log_ppp_error("failed to attach namespace\n");
+ ns->release(ns);
+ return -1;
+ }
+ ses->net = ns;
+ net = ns;
+ log_ppp_info2("move to namespace %s\n", ns->name);
}
if (up) {
@@ -311,6 +343,6 @@ int __export ap_session_rename(struct ap_session *ses, const char *ifname, int l
net->sock_ioctl(SIOCSIFFLAGS, &ifr);
}
- return r;
+ return 0;
}
diff --git a/accel-pppd/include/ap_net.h b/accel-pppd/include/ap_net.h
index 0872e228..25121d94 100644
--- a/accel-pppd/include/ap_net.h
+++ b/accel-pppd/include/ap_net.h
@@ -1,7 +1,12 @@
#ifndef __AP_NET_H
#define __AP_NET_H
+struct rtnl_handle;
+
struct ap_net {
+ struct list_head entry;
+ int refs;
+ char *name;
int (*socket)(int domain, int type, int proto);
int (*connect)(int sock, const struct sockaddr *, socklen_t len);
int (*bind)(int sock, const struct sockaddr *, socklen_t len);
@@ -13,8 +18,23 @@ struct ap_net {
int (*set_nonblocking)(int sock, int f);
int (*setsockopt)(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
int (*sock_ioctl)(unsigned long request, void *arg);
+ int (*sock6_ioctl)(unsigned long request, void *arg);
int (*ppp_open)();
int (*ppp_ioctl)(int fd, unsigned long request, void *arg);
+ void (*enter_ns)();
+ void (*exit_ns)();
+ struct rtnl_handle *(*rtnl_get)();
+ void (*rtnl_put)(struct rtnl_handle *);
+ int (*rtnl_open)(struct rtnl_handle *h, int proto);
+ int (*move_link)(struct ap_net *net, int ifindex);
+ void (*release)(struct ap_net *net);
};
+extern __thread struct ap_net *net;
+extern struct ap_net *def_net;
+
+int ap_net_register(struct ap_net *net);
+struct ap_net *ap_net_find(const char *name);
+struct ap_net *ap_net_open_ns(const char *name);
+
#endif
diff --git a/accel-pppd/include/ap_session.h b/accel-pppd/include/ap_session.h
index 0baaab2c..421360db 100644
--- a/accel-pppd/include/ap_session.h
+++ b/accel-pppd/include/ap_session.h
@@ -81,6 +81,7 @@ struct ap_session
struct ipv6db_prefix_t *ipv6_dp;
char *ipv4_pool_name;
char *ipv6_pool_name;
+ struct ap_net *net;
const struct ap_ctrl *ctrl;
@@ -125,13 +126,11 @@ struct ap_session_stat
extern pthread_rwlock_t ses_lock;
extern struct list_head ses_list;
extern int ap_shutdown;
-extern int sock_fd; // internet socket for ioctls
-extern int sock6_fd; // internet socket for ioctls
+extern int sock_fd;
+extern int sock6_fd;
extern int urandom_fd;
extern struct ap_session_stat ap_session_stat;
-
-extern __thread const struct ap_net *net;
-extern const struct ap_net def_net;
+extern int conf_max_sessions;
void ap_session_init(struct ap_session *ses);
void ap_session_set_ifindex(struct ap_session *ses);
diff --git a/accel-pppd/include/events.h b/accel-pppd/include/events.h
index 37dfa82c..c388575d 100644
--- a/accel-pppd/include/events.h
+++ b/accel-pppd/include/events.h
@@ -22,6 +22,7 @@
#define EV_MPPE_KEYS 102
#define EV_DNS 103
#define EV_WINS 104
+#define EV_FORCE_INTERIM_UPDATE 105
#define EV_RADIUS_ACCESS_ACCEPT 200
#define EV_RADIUS_COA 201
diff --git a/accel-pppd/include/ppp_auth.h b/accel-pppd/include/ppp_auth.h
index 839a8817..527c8538 100644..120000
--- a/accel-pppd/include/ppp_auth.h
+++ b/accel-pppd/include/ppp_auth.h
@@ -1,37 +1 @@
-#ifndef PPP_AUTH_H
-#define PPP_AUTH_H
-
-#include "list.h"
-
-struct ppp_auth_handler_t;
-
-struct auth_data_t
-{
- struct list_head entry;
- int proto;
- int state;
- struct ppp_auth_handler_t *h;
-};
-
-struct ppp_auth_handler_t
-{
- struct list_head entry;
- const char *name;
- struct auth_data_t* (*init)(struct ppp_t*);
- int (*send_conf_req)(struct ppp_t*, struct auth_data_t*, uint8_t*);
- int (*recv_conf_req)(struct ppp_t*, struct auth_data_t*, uint8_t*);
- int (*start)(struct ppp_t*, struct auth_data_t*);
- int (*finish)(struct ppp_t*, struct auth_data_t*);
- void (*free)(struct ppp_t*,struct auth_data_t*);
- int (*check)(uint8_t *);
- int (*restart)(struct ppp_t*,struct auth_data_t*);
-};
-
-int ppp_auth_register_handler(struct ppp_auth_handler_t*);
-
-int ppp_auth_succeeded(struct ppp_t *ppp, char *username);
-void ppp_auth_failed(struct ppp_t *ppp, char *username);
-int ppp_auth_restart(struct ppp_t *ppp);
-
-#endif
-
+../ppp/ppp_auth.h \ No newline at end of file
diff --git a/accel-pppd/iprange.c b/accel-pppd/iprange.c
index 6ea2c2f9..f7b77a27 100644
--- a/accel-pppd/iprange.c
+++ b/accel-pppd/iprange.c
@@ -1,12 +1,18 @@
+#include <pthread.h>
+#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
#include "triton.h"
+#include "events.h"
#include "list.h"
#include "log.h"
+#include "utils.h"
#include "iprange.h"
@@ -19,99 +25,172 @@ struct iprange_t
uint32_t end;
};
-static int conf_disable = 0;
-
+static pthread_mutex_t iprange_lock = PTHREAD_MUTEX_INITIALIZER;
+static bool conf_disable = false;
static LIST_HEAD(client_ranges);
-//static LIST_HEAD(tunnel_ranges);
-//parses ranges like x.x.x.x/mask
-static struct iprange_t *parse1(const char *str)
+/* Maximum IPv4 address length with CIDR notation but no extra 0,
+ * e.g. "0xff.0xff.0xff.0xff/32".
+ */
+#define CIDR_MAXLEN 22
+
+
+static void free_ranges(struct list_head *head)
{
- int n,f1,f2,f3,f4,m;
- struct iprange_t *r;
- int mask;
-
- n = sscanf(str, "%u.%u.%u.%u/%u",&f1, &f2, &f3, &f4, &m);
- if (n != 5)
- return NULL;
- if (f1 > 255)
- return NULL;
- if (f2 > 255)
- return NULL;
- if (f3 > 255)
- return NULL;
- if (f4 > 255)
- return NULL;
- if (m > 32)
- return NULL;
-
- r = _malloc(sizeof(*r));
- r->begin = (f4 << 24) | (f3 << 16) | (f2 << 8) | f1;
-
- mask = htonl(~((1 << (32 - m)) - 1));
- r->end = ntohl(r->begin | ~mask);
- r->begin = ntohl(r->begin);
-
- return r;
+ struct iprange_t *range;
+
+ while (!list_empty(head)) {
+ range = list_first_entry(head, typeof(*range), entry);
+ list_del(&range->entry);
+ _free(range);
+ }
}
-//parses ranges like x.x.x.x-y
-static struct iprange_t *parse2(const char *str)
+static int parse_iprange(const char *str, struct iprange_t **range)
{
- int n,f1,f2,f3,f4,m;
- struct iprange_t *r;
+ char ipstr[CIDR_MAXLEN + 1] = { 0 };
+ struct iprange_t *_range;
+ struct in_addr addr;
+ const char *errmsg;
+ char *suffix_str;
+ uint32_t ipmin;
+ uint32_t ipmax;
+ bool is_cidr;
+
+ /* Extra spaces and comments must have already been removed */
+ if (strpbrk(str, " \t#")) {
+ log_error("iprange: impossible to parse range \"%s\":"
+ " invalid space or comment character found\n",
+ str);
+ return -1;
+ }
+
+ if (!strcmp(str, "disable"))
+ goto disable;
+
+ strncpy(ipstr, str, CIDR_MAXLEN + 1);
+ if (ipstr[CIDR_MAXLEN] != '\0') {
+ log_error("iprange: impossible to parse range \"%s\":"
+ " line too long\n",
+ str);
+ return -1;
+ }
- n = sscanf(str, "%u.%u.%u.%u-%u",&f1, &f2, &f3, &f4, &m);
- if (n != 5)
- return NULL;
- if (f1 > 255)
- return NULL;
- if (f2 > 255)
- return NULL;
- if (f3 > 255)
- return NULL;
- if (f4 > 255)
- return NULL;
- if (m < f4 || m > 255)
- return NULL;
-
- r = _malloc(sizeof(*r));
- r->begin = ntohl((f4 << 24) | (f3 << 16) | (f2 << 8) | f1);
- r->end = ntohl((m << 24) | (f3 << 16) | (f2 << 8) | f1);
-
- return r;
+ suffix_str = strpbrk(ipstr, "-/");
+ if (!suffix_str) {
+ log_error("iprange: impossible to parse range \"%s\":"
+ " unrecognised range format\n",
+ str);
+ return -1;
+ }
+
+ is_cidr = *suffix_str == '/';
+ *suffix_str = '\0';
+ ++suffix_str;
+
+ if (u_parse_ip4addr(ipstr, &addr, &errmsg)) {
+ log_error("iprange: impossible to parse range \"%s\":"
+ " invalid IPv4 address \"%s\"\n",
+ str, ipstr);
+ return -1;
+ }
+ ipmin = ntohl(addr.s_addr);
+
+
+ /* If is_cidr is set, range is given with CIDR notation,
+ * e.g. "192.0.2.0/24".
+ * If unset, range is an IP address where the last octet is replaced by
+ * an octet range, e.g. "192.0.2.0-255".
+ */
+ if (is_cidr) {
+ long int prefix_len;
+ uint32_t mask;
+
+ if (u_readlong(&prefix_len, suffix_str, 0, 32)) {
+ log_error("iprange: impossible to parse range \"%s\":"
+ " invalid CIDR prefix length \"/%s\"\n",
+ str, suffix_str);
+ return -1;
+ }
+
+ /* Interpret /0 as disable request */
+ if (prefix_len == 0) {
+ if (ipmin != INADDR_ANY)
+ log_warn("iprange: %s is equivalent to 0.0.0.0/0 and disables the iprange module\n",
+ str);
+ goto disable;
+ }
+
+ mask = INADDR_BROADCAST << (32 - prefix_len);
+ if (ipmin != (ipmin & mask)) {
+ char buf[INET_ADDRSTRLEN] = { 0 };
+
+ ipmin &= mask;
+ addr.s_addr = htonl(ipmin);
+ log_warn("iprange: first IP of range %s will be %s\n",
+ str, inet_ntop(AF_INET, &addr, buf,
+ sizeof(buf)));
+ }
+
+ ipmax = ipmin | ~mask;
+ } else {
+ long int max;
+
+ if (u_readlong(&max, suffix_str, ipmin & 0xff, 255)) {
+ log_error("iprange: impossible to parse range \"%s\":"
+ " invalid upper bound \"-%s\"\n",
+ str, suffix_str);
+ return -1;
+ }
+
+ ipmax = (ipmin & 0xffffff00) | max;
+ }
+
+ _range = _malloc(sizeof(*_range));
+ if (!_range) {
+ log_error("iprange: impossible to allocate range \"%s\":"
+ " memory allocation failed\n", str);
+ return -1;
+ }
+
+ _range->begin = ipmin;
+ _range->end = ipmax;
+ *range = _range;
+
+ return 0;
+
+disable:
+ *range = NULL;
+
+ return 0;
}
-static void load_ranges(struct list_head *list, const char *conf_sect)
+static bool load_ranges(struct list_head *list, const char *conf_sect)
{
struct conf_sect_t *s = conf_get_section(conf_sect);
struct conf_option_t *opt;
struct iprange_t *r;
- if (!s) {
- log_emerg("iprange: section '%s' not found in config file, pptp and l2tp probably will not work...\n", conf_sect);
- return;
- }
+ if (!s)
+ return false;
list_for_each_entry(opt, &s->items, entry) {
- if (!strcmp(opt->name, "disable"))
- goto disable;
- r = parse1(opt->name);
- if (!r)
- r = parse2(opt->name);
+ /* Ignore parsing errors, parse_iprange() already logs suitable
+ * error message.
+ */
+ if (parse_iprange(opt->name, &r) < 0)
+ continue;
+
if (!r) {
- log_emerg("iprange: cann't parse '%s' in '%s'\n", opt->name, conf_sect);
- _exit(EXIT_FAILURE);
+ free_ranges(list);
+
+ return true;
}
- if (r->begin == r->end)
- goto disable;
+
list_add_tail(&r->entry, list);
}
- return;
-disable:
- conf_disable = 1;
- log_emerg("iprange: iprange module disabled so improper ip address assigning may cause kernel soft lockup!\n");
+ return false;
}
static int check_range(struct list_head *list, in_addr_t ipaddr)
@@ -127,25 +206,77 @@ static int check_range(struct list_head *list, in_addr_t ipaddr)
return -1;
}
+enum iprange_status __export iprange_check_activation(void)
+{
+ bool disabled;
+ bool empty;
+
+ pthread_mutex_lock(&iprange_lock);
+ disabled = conf_disable;
+ empty = list_empty(&client_ranges);
+ pthread_mutex_unlock(&iprange_lock);
+
+ if (disabled)
+ return IPRANGE_DISABLED;
+
+ if (empty)
+ return IPRANGE_NO_RANGE;
+
+ return IPRANGE_ACTIVE;
+}
+
int __export iprange_client_check(in_addr_t ipaddr)
{
+ int res;
+
+ pthread_mutex_lock(&iprange_lock);
if (conf_disable)
- return 0;
+ res = 0;
+ else
+ res = check_range(&client_ranges, ipaddr);
+ pthread_mutex_unlock(&iprange_lock);
- return check_range(&client_ranges, ipaddr);
+ return res;
}
+
int __export iprange_tunnel_check(in_addr_t ipaddr)
{
+ int res;
+
+ pthread_mutex_lock(&iprange_lock);
if (conf_disable)
- return 0;
+ res = 0;
+ else
+ res = !check_range(&client_ranges, ipaddr);
+ pthread_mutex_unlock(&iprange_lock);
+
+ return res;
+}
+
+static void iprange_load_config(void *data)
+{
+ LIST_HEAD(new_ranges);
+ LIST_HEAD(old_ranges);
+ bool disable;
+
+ disable = load_ranges(&new_ranges, IPRANGE_CONF_SECTION);
+
+ pthread_mutex_lock(&iprange_lock);
+ list_replace(&client_ranges, &old_ranges);
+ list_replace(&new_ranges, &client_ranges);
+ conf_disable = disable;
+ pthread_mutex_unlock(&iprange_lock);
- return !check_range(&client_ranges, ipaddr);
+ free_ranges(&old_ranges);
}
static void iprange_init(void)
{
- load_ranges(&client_ranges, "client-ip-range");
- //load_ranges(&tunnel_ranges, "tunnel-ip-range");
+ iprange_load_config(NULL);
+ if (triton_event_register_handler(EV_CONFIG_RELOAD,
+ iprange_load_config) < 0)
+ log_error("iprange: registration of CONFIG_RELOAD event failed,"
+ " iprange will not be able to reload its configuration\n");
}
DEFINE_INIT(10, iprange_init);
diff --git a/accel-pppd/iprange.h b/accel-pppd/iprange.h
index 88a2486a..39bd8ba2 100644
--- a/accel-pppd/iprange.h
+++ b/accel-pppd/iprange.h
@@ -3,6 +3,16 @@
#include <netinet/in.h>
+
+#define IPRANGE_CONF_SECTION "client-ip-range"
+
+enum iprange_status {
+ IPRANGE_DISABLED,
+ IPRANGE_NO_RANGE,
+ IPRANGE_ACTIVE,
+};
+
+enum iprange_status iprange_check_activation(void);
int iprange_client_check(in_addr_t ipaddr);
int iprange_tunnel_check(in_addr_t ipaddr);
diff --git a/accel-pppd/ipv6/dhcpv6.c b/accel-pppd/ipv6/dhcpv6.c
index 595b5974..f147a8cd 100644
--- a/accel-pppd/ipv6/dhcpv6.c
+++ b/accel-pppd/ipv6/dhcpv6.c
@@ -66,15 +66,15 @@ static void ev_ses_started(struct ap_session *ses)
if (!ses->ipv6)
return;
- sock = socket(AF_INET6, SOCK_DGRAM, 0);
+ sock = net->socket(AF_INET6, SOCK_DGRAM, 0);
if (!sock) {
log_ppp_error("dhcpv6: socket: %s\n", strerror(errno));
return;
}
- setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &f, sizeof(f));
+ net->setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &f, sizeof(f));
- if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, ses->ifname, strlen(ses->ifname))) {
+ if (net->setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, ses->ifname, strlen(ses->ifname))) {
log_ppp_error("ipv6_nd: setsockopt(SO_BINDTODEVICE): %s\n", strerror(errno));
close(sock);
return;
@@ -84,7 +84,7 @@ static void ev_ses_started(struct ap_session *ses)
addr.sin6_family = AF_INET6;
addr.sin6_port = htons(DHCPV6_SERV_PORT);
- if (bind(sock, (struct sockaddr *)&addr, sizeof(addr))) {
+ if (net->bind(sock, (struct sockaddr *)&addr, sizeof(addr))) {
log_ppp_error("dhcpv6: bind: %s\n", strerror(errno));
close(sock);
return;
@@ -95,14 +95,14 @@ static void ev_ses_started(struct ap_session *ses)
mreq.ipv6mr_multiaddr.s6_addr32[0] = htonl(0xff020000);
mreq.ipv6mr_multiaddr.s6_addr32[3] = htonl(0x010002);
- if (setsockopt(sock, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq))) {
+ if (net->setsockopt(sock, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq))) {
log_ppp_error("dhcpv6: failed to join to All_DHCP_Relay_Agents_and_Servers\n");
close(sock);
return;
}
- fcntl(sock, F_SETFL, O_NONBLOCK);
fcntl(sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC);
+ net->set_nonblocking(sock, 1);
pd = _malloc(sizeof(*pd));
memset(pd, 0, sizeof(*pd));
@@ -189,7 +189,7 @@ static void insert_dp_routes(struct ap_session *ses, struct dhcpv6_pd *pd)
rt6.rtmsg_flags |= RTF_GATEWAY;
list_for_each_entry(a, &ses->ipv6->addr_list, entry) {
build_addr(a, ses->ipv6->peer_intf_id, &rt6.rtmsg_gateway);
- if (ioctl(sock6_fd, SIOCADDRT, &rt6)) {
+ if (net->sock6_ioctl(SIOCADDRT, &rt6)) {
err = errno;
inet_ntop(AF_INET6, &p->addr, str1, sizeof(str1));
inet_ntop(AF_INET6, &rt6.rtmsg_gateway, str2, sizeof(str2));
@@ -202,7 +202,7 @@ static void insert_dp_routes(struct ap_session *ses, struct dhcpv6_pd *pd)
rt6.rtmsg_metric++;
}
} else {
- if (ioctl(sock6_fd, SIOCADDRT, &rt6)) {
+ if (net->sock6_ioctl(SIOCADDRT, &rt6)) {
err = errno;
inet_ntop(AF_INET6, &p->addr, str1, sizeof(str1));
log_ppp_error("dhcpv6: route add %s/%i: %s\n",
@@ -363,8 +363,11 @@ static void dhcpv6_send_reply(struct dhcpv6_packet *req, struct dhcpv6_pd *pd, i
ia_na->T1 = conf_pref_lifetime == -1 ? -1 : htonl(conf_pref_lifetime / 2);
ia_na->T2 = conf_pref_lifetime == -1 ? -1 : htonl((conf_pref_lifetime * 4) / 5);
- if (!ses->ipv6_dp)
+ if (!ses->ipv6_dp) {
ses->ipv6_dp = ipdb_get_ipv6_prefix(ses);
+ if (ses->ipv6_dp)
+ triton_event_fire(EV_FORCE_INTERIM_UPDATE, ses);
+ }
if ((req->hdr->type == D6_RENEW) && pd->dp_iaid != ia_na->iaid) {
insert_status(reply, opt1, D6_STATUS_NoBinding);
@@ -454,7 +457,7 @@ static void dhcpv6_send_reply(struct dhcpv6_packet *req, struct dhcpv6_pd *pd, i
dhcpv6_packet_print(reply, log_ppp_info2);
}
- sendto(pd->hnd.fd, reply->hdr, reply->endptr - (void *)reply->hdr, 0, (struct sockaddr *)&req->addr, sizeof(req->addr));
+ net->sendto(pd->hnd.fd, reply->hdr, reply->endptr - (void *)reply->hdr, 0, (struct sockaddr *)&req->addr, sizeof(req->addr));
dhcpv6_packet_free(reply);
}
@@ -539,8 +542,11 @@ static void dhcpv6_send_reply2(struct dhcpv6_packet *req, struct dhcpv6_pd *pd,
ia_na->T1 = conf_pref_lifetime == -1 ? -1 : htonl(conf_pref_lifetime / 2);
ia_na->T2 = conf_pref_lifetime == -1 ? -1 : htonl((conf_pref_lifetime * 4) / 5);
- if (!ses->ipv6_dp)
- ses->ipv6_dp = ipdb_get_ipv6_prefix(req->ses);
+ if (!ses->ipv6_dp) {
+ ses->ipv6_dp = ipdb_get_ipv6_prefix(ses);
+ if (ses->ipv6_dp)
+ triton_event_fire(EV_FORCE_INTERIM_UPDATE, ses);
+ }
if (!ses->ipv6_dp)
goto out;
@@ -603,7 +609,7 @@ static void dhcpv6_send_reply2(struct dhcpv6_packet *req, struct dhcpv6_pd *pd,
dhcpv6_packet_print(reply, log_ppp_info2);
}
- sendto(pd->hnd.fd, reply->hdr, reply->endptr - (void *)reply->hdr, 0, (struct sockaddr *)&req->addr, sizeof(req->addr));
+ net->sendto(pd->hnd.fd, reply->hdr, reply->endptr - (void *)reply->hdr, 0, (struct sockaddr *)&req->addr, sizeof(req->addr));
out:
dhcpv6_packet_free(reply);
@@ -793,7 +799,7 @@ static int dhcpv6_read(struct triton_md_handler_t *h)
uint8_t *buf = _malloc(BUF_SIZE);
while (1) {
- n = recvfrom(h->fd, buf, BUF_SIZE, 0, &addr, &len);
+ n = net->recvfrom(h->fd, buf, BUF_SIZE, 0, (struct sockaddr *)&addr, &len);
if (n == -1) {
if (errno == EAGAIN)
break;
diff --git a/accel-pppd/ipv6/nd.c b/accel-pppd/ipv6/nd.c
index 19a3d7d3..1d70ae95 100644
--- a/accel-pppd/ipv6/nd.c
+++ b/accel-pppd/ipv6/nd.c
@@ -185,7 +185,7 @@ static void ipv6_nd_send_ra(struct ipv6_nd_handler_t *h, struct sockaddr_in6 *ad
} else
endptr = rdnss_addr;
- sendto(h->hnd.fd, buf, endptr - buf, 0, (struct sockaddr *)addr, sizeof(*addr));
+ net->sendto(h->hnd.fd, buf, endptr - buf, 0, (struct sockaddr *)addr, sizeof(*addr));
mempool_free(buf);
}
@@ -225,7 +225,7 @@ static int ipv6_nd_read(struct triton_md_handler_t *_h)
}
while (1) {
- n = recvfrom(h->hnd.fd, icmph, BUF_SIZE, 0, &addr, &addr_len);
+ n = net->recvfrom(h->hnd.fd, icmph, BUF_SIZE, 0, (struct sockaddr *)&addr, &addr_len);
if (n == -1) {
if (errno == EAGAIN)
break;
@@ -269,31 +269,31 @@ static int ipv6_nd_start(struct ap_session *ses)
int val;
struct ipv6_nd_handler_t *h;
- sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
+ sock = net->socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
if (sock < 0) {
log_ppp_error("socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6): %s\n", strerror(errno));
return -1;
}
- if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, ses->ifname, strlen(ses->ifname))) {
+ if (net->setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, ses->ifname, strlen(ses->ifname))) {
log_ppp_error("ipv6_nd: setsockopt(SO_BINDTODEVICE): %s\n", strerror(errno));
goto out_err;
}
val = 2;
- if (setsockopt(sock, IPPROTO_RAW, IPV6_CHECKSUM, &val, sizeof(val))) {
+ if (net->setsockopt(sock, IPPROTO_RAW, IPV6_CHECKSUM, &val, sizeof(val))) {
log_ppp_error("ipv6_nd: setsockopt(IPV6_CHECKSUM): %s\n", strerror(errno));
goto out_err;
}
val = 255;
- if (setsockopt(sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val, sizeof(val))) {
+ if (net->setsockopt(sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val, sizeof(val))) {
log_ppp_error("ipv6_nd: setsockopt(IPV6_UNICAST_HOPS): %s\n", strerror(errno));
goto out_err;
}
- if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, sizeof(val))) {
+ if (net->setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, sizeof(val))) {
log_ppp_error("ipv6_nd: setsockopt(IPV6_MULTICAST_HOPS): %s\n", strerror(errno));
goto out_err;
}
@@ -307,7 +307,7 @@ static int ipv6_nd_start(struct ap_session *ses)
ICMP6_FILTER_SETBLOCKALL(&filter);
ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter);
- if (setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(filter))) {
+ if (net->setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(filter))) {
log_ppp_error("ipv6_nd: setsockopt(ICMP6_FILTER): %s\n", strerror(errno));
goto out_err;
}
@@ -317,13 +317,14 @@ static int ipv6_nd_start(struct ap_session *ses)
mreq.ipv6mr_multiaddr.s6_addr32[0] = htonl(0xff020000);
mreq.ipv6mr_multiaddr.s6_addr32[3] = htonl(0x2);
- if (setsockopt(sock, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq))) {
+ if (net->setsockopt(sock, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq))) {
log_ppp_error("ipv6_nd: failed to join ipv6 allrouters\n");
goto out_err;
}
fcntl(sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC);
- fcntl(sock, F_SETFL, O_NONBLOCK);
+
+ net->set_nonblocking(sock, 1);
h = _malloc(sizeof(*h));
memset(h, 0, sizeof(*h));
diff --git a/accel-pppd/libnetlink/iputils.c b/accel-pppd/libnetlink/iputils.c
index 30a06d1f..1052b609 100644
--- a/accel-pppd/libnetlink/iputils.c
+++ b/accel-pppd/libnetlink/iputils.c
@@ -20,6 +20,7 @@
#include "libnetlink.h"
#include "iputils.h"
+#include "ap_net.h"
#ifdef ACCEL_DP
#define _malloc(x) malloc(x)
@@ -37,37 +38,6 @@ struct arg
void *arg;
};
-static pthread_key_t rth_key;
-static __thread struct rtnl_handle *rth;
-
-static void open_rth(void)
-{
- rth = _malloc(sizeof(*rth));
-
- if (!rth)
- return;
-
- memset(rth, 0, sizeof(*rth));
-
- if (rtnl_open(rth, 0)) {
- log_ppp_error("radius: cannot open rtnetlink\n");
- _free(rth);
- rth = NULL;
- return;
- }
-
- pthread_setspecific(rth_key, rth);
-}
-
-static void free_rth(void *arg)
-{
- struct rtnl_handle *rth = arg;
-
- rtnl_close(rth);
-
- _free(rth);
-}
-
static int store_nlmsg(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
{
struct ifinfomsg *ifi = NLMSG_DATA(n);
@@ -143,9 +113,8 @@ int __export iplink_get_stats(int ifindex, struct rtnl_link_stats *stats)
struct ifinfomsg *ifi;
int len;
struct rtattr *tb[IFLA_MAX + 1];
-
- if (!rth)
- open_rth();
+ struct rtnl_handle *rth = net->rtnl_get();
+ int r = -1;
if (!rth)
return -1;
@@ -159,10 +128,10 @@ int __export iplink_get_stats(int ifindex, struct rtnl_link_stats *stats)
req.i.ifi_index = ifindex;
if (rtnl_talk(rth, &req.n, 0, 0, &req.n, NULL, NULL, 0) < 0)
- return -1;
+ goto out;
if (req.n.nlmsg_type != RTM_NEWLINK)
- return -1;
+ goto out;
ifi = NLMSG_DATA(&req.n);
@@ -170,15 +139,18 @@ int __export iplink_get_stats(int ifindex, struct rtnl_link_stats *stats)
len -= NLMSG_LENGTH(sizeof(*ifi));
if (len < 0)
- return -1;
+ goto out;
parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
- if (tb[IFLA_STATS])
+ if (tb[IFLA_STATS]) {
memcpy(stats, RTA_DATA(tb[IFLA_STATS]), sizeof(*stats));
- else
- return -1;
+ r = 0;
+ }
- return 0;
+out:
+ net->rtnl_put(rth);
+
+ return r;
}
int __export iplink_vlan_add(const char *ifname, int ifindex, int vid)
@@ -189,9 +161,8 @@ int __export iplink_vlan_add(const char *ifname, int ifindex, int vid)
char buf[4096];
} req;
struct rtattr *linkinfo, *data;
-
- if (!rth)
- open_rth();
+ struct rtnl_handle *rth = net->rtnl_get();
+ int r = 0;
if (!rth)
return -1;
@@ -218,9 +189,11 @@ int __export iplink_vlan_add(const char *ifname, int ifindex, int vid)
linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo;
if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
- return -1;
+ r = -1;
- return 0;
+ net->rtnl_put(rth);
+
+ return r;
}
int __export iplink_vlan_del(int ifindex)
@@ -231,9 +204,8 @@ int __export iplink_vlan_del(int ifindex)
char buf[4096];
} req;
struct rtattr *linkinfo;
-
- if (!rth)
- open_rth();
+ struct rtnl_handle *rth = net->rtnl_get();
+ int r = 0;
if (!rth)
return -1;
@@ -257,9 +229,11 @@ int __export iplink_vlan_del(int ifindex)
linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo;
if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
- return -1;
+ r = -1;
- return 0;
+ net->rtnl_put(rth);
+
+ return r;
}
int __export iplink_vlan_get_vid(int ifindex, int *iflink)
@@ -272,9 +246,8 @@ int __export iplink_vlan_get_vid(int ifindex, int *iflink)
struct ifinfomsg *ifi;
int len;
struct rtattr *tb[IFLA_MAX + 1];
-
- if (!rth)
- open_rth();
+ struct rtnl_handle *rth = net->rtnl_get();
+ int r = 0;
if (!rth)
return -1;
@@ -288,10 +261,10 @@ int __export iplink_vlan_get_vid(int ifindex, int *iflink)
req.i.ifi_index = ifindex;
if (rtnl_talk(rth, &req.n, 0, 0, &req.n, NULL, NULL, 0) < 0)
- return -1;
+ goto out;
if (req.n.nlmsg_type != RTM_NEWLINK)
- return -1;
+ goto out;
ifi = NLMSG_DATA(&req.n);
@@ -299,12 +272,12 @@ int __export iplink_vlan_get_vid(int ifindex, int *iflink)
len -= NLMSG_LENGTH(sizeof(*ifi));
if (len < 0)
- return -1;
+ goto out;
parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
if (!tb[IFLA_LINKINFO])
- return 0;
+ goto out;
if (iflink && tb[IFLA_LINK])
*iflink = *(int *)RTA_DATA(tb[IFLA_LINK]);
@@ -312,10 +285,15 @@ int __export iplink_vlan_get_vid(int ifindex, int *iflink)
parse_rtattr_nested(tb, IFLA_MAX, tb[IFLA_LINKINFO]);
if (strcmp(RTA_DATA(tb[IFLA_INFO_KIND]), "vlan"))
- return 0;
+ goto out;
parse_rtattr_nested(tb, IFLA_MAX, tb[IFLA_INFO_DATA]);
- return *(uint16_t *)RTA_DATA(tb[IFLA_VLAN_ID]);
+ r = *(uint16_t *)RTA_DATA(tb[IFLA_VLAN_ID]);
+
+out:
+ net->rtnl_put(rth);
+
+ return r;
}
@@ -326,9 +304,8 @@ int __export ipaddr_add(int ifindex, in_addr_t addr, int mask)
struct ifaddrmsg i;
char buf[4096];
} req;
-
- if (!rth)
- open_rth();
+ struct rtnl_handle *rth = net->rtnl_get();
+ int r = 0;
if (!rth)
return -1;
@@ -345,21 +322,55 @@ int __export ipaddr_add(int ifindex, in_addr_t addr, int mask)
addattr32(&req.n, sizeof(req), IFA_LOCAL, addr);
if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
- return -1;
+ r = -1;
- return 0;
+ net->rtnl_put(rth);
+
+ return r;
}
-int __export ipaddr_del(int ifindex, in_addr_t addr, int mask)
+int __export ipaddr_add_peer(int ifindex, in_addr_t addr, in_addr_t peer_addr)
{
struct ipaddr_req {
struct nlmsghdr n;
struct ifaddrmsg i;
char buf[4096];
} req;
+ struct rtnl_handle *rth = net->rtnl_get();
+ int r = 0;
if (!rth)
- open_rth();
+ return -1;
+
+ memset(&req, 0, sizeof(req) - 4096);
+
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
+ req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
+ req.n.nlmsg_type = RTM_NEWADDR;
+ req.i.ifa_family = AF_INET;
+ req.i.ifa_index = ifindex;
+ req.i.ifa_prefixlen = 32;
+
+ addattr32(&req.n, sizeof(req), IFA_LOCAL, addr);
+ addattr32(&req.n, sizeof(req), IFA_ADDRESS, peer_addr);
+
+ if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
+ r = -1;
+
+ net->rtnl_put(rth);
+
+ return r;
+}
+
+int __export ipaddr_del(int ifindex, in_addr_t addr, int mask)
+{
+ struct ipaddr_req {
+ struct nlmsghdr n;
+ struct ifaddrmsg i;
+ char buf[4096];
+ } req;
+ struct rtnl_handle *rth = net->rtnl_get();
+ int r = 0;
if (!rth)
return -1;
@@ -376,9 +387,44 @@ int __export ipaddr_del(int ifindex, in_addr_t addr, int mask)
addattr32(&req.n, sizeof(req), IFA_LOCAL, addr);
if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
+ r = -1;
+
+ net->rtnl_put(rth);
+
+ return r;
+}
+
+int __export ipaddr_del_peer(int ifindex, in_addr_t addr, in_addr_t peer)
+{
+ struct ipaddr_req {
+ struct nlmsghdr n;
+ struct ifaddrmsg i;
+ char buf[4096];
+ } req;
+ struct rtnl_handle *rth = net->rtnl_get();
+ int r = 0;
+
+ if (!rth)
return -1;
- return 0;
+ memset(&req, 0, sizeof(req) - 4096);
+
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
+ req.n.nlmsg_flags = NLM_F_REQUEST;
+ req.n.nlmsg_type = RTM_DELADDR;
+ req.i.ifa_family = AF_INET;
+ req.i.ifa_index = ifindex;
+ req.i.ifa_prefixlen = 32;
+
+ addattr32(&req.n, sizeof(req), IFA_LOCAL, addr);
+ addattr32(&req.n, sizeof(req), IFA_ADDRESS, peer);
+
+ if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
+ r = -1;
+
+ net->rtnl_put(rth);
+
+ return r;
}
int __export iproute_add(int ifindex, in_addr_t src, in_addr_t dst, in_addr_t gw, int proto, int mask)
@@ -388,9 +434,8 @@ int __export iproute_add(int ifindex, in_addr_t src, in_addr_t dst, in_addr_t gw
struct rtmsg i;
char buf[4096];
} req;
-
- if (!rth)
- open_rth();
+ struct rtnl_handle *rth = net->rtnl_get();
+ int r = 0;
if (!rth)
return -1;
@@ -416,9 +461,11 @@ int __export iproute_add(int ifindex, in_addr_t src, in_addr_t dst, in_addr_t gw
addattr32(&req.n, sizeof(req), RTA_DST, dst);
if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
- return -1;
+ r = -1;
- return 0;
+ net->rtnl_put(rth);
+
+ return r;
}
int __export iproute_del(int ifindex, in_addr_t dst, int proto, int mask)
@@ -428,9 +475,8 @@ int __export iproute_del(int ifindex, in_addr_t dst, int proto, int mask)
struct rtmsg i;
char buf[4096];
} req;
-
- if (!rth)
- open_rth();
+ struct rtnl_handle *rth = net->rtnl_get();
+ int r = 0;
if (!rth)
return -1;
@@ -453,9 +499,11 @@ int __export iproute_del(int ifindex, in_addr_t dst, int proto, int mask)
addattr32(&req.n, sizeof(req), RTA_OIF, ifindex);
if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
- return -1;
+ r = -1;
- return 0;
+ net->rtnl_put(rth);
+
+ return r;
}
int __export ip6route_add(int ifindex, struct in6_addr *dst, int pref_len, int proto)
@@ -465,9 +513,8 @@ int __export ip6route_add(int ifindex, struct in6_addr *dst, int pref_len, int p
struct rtmsg i;
char buf[4096];
} req;
-
- if (!rth)
- open_rth();
+ struct rtnl_handle *rth = net->rtnl_get();
+ int r = 0;
if (!rth)
return -1;
@@ -488,9 +535,11 @@ int __export ip6route_add(int ifindex, struct in6_addr *dst, int pref_len, int p
addattr32(&req.n, sizeof(req), RTA_OIF, ifindex);
if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
- return -1;
+ r = -1;
- return 0;
+ net->rtnl_put(rth);
+
+ return r;
}
int __export ip6route_del(int ifindex, struct in6_addr *dst, int pref_len)
@@ -500,9 +549,8 @@ int __export ip6route_del(int ifindex, struct in6_addr *dst, int pref_len)
struct rtmsg i;
char buf[4096];
} req;
-
- if (!rth)
- open_rth();
+ struct rtnl_handle *rth = net->rtnl_get();
+ int r = 0;
if (!rth)
return -1;
@@ -521,9 +569,11 @@ int __export ip6route_del(int ifindex, struct in6_addr *dst, int pref_len)
addattr_l(&req.n, sizeof(req), RTA_DST, dst, sizeof(*dst));
if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
- return -1;
+ r = -1;
- return 0;
+ net->rtnl_put(rth);
+
+ return r;
}
int __export ip6addr_add(int ifindex, struct in6_addr *addr, int prefix_len)
@@ -533,9 +583,8 @@ int __export ip6addr_add(int ifindex, struct in6_addr *addr, int prefix_len)
struct ifaddrmsg i;
char buf[4096];
} req;
-
- if (!rth)
- open_rth();
+ struct rtnl_handle *rth = net->rtnl_get();
+ int r = 0;
if (!rth)
return -1;
@@ -553,9 +602,11 @@ int __export ip6addr_add(int ifindex, struct in6_addr *addr, int prefix_len)
addattr_l(&req.n, sizeof(req), IFA_ADDRESS, addr, 16);
if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
- return -1;
+ r = -1;
- return 0;
+ net->rtnl_put(rth);
+
+ return r;
}
int __export ip6addr_del(int ifindex, struct in6_addr *addr, int prefix_len)
@@ -565,9 +616,8 @@ int __export ip6addr_del(int ifindex, struct in6_addr *addr, int prefix_len)
struct ifaddrmsg i;
char buf[4096];
} req;
-
- if (!rth)
- open_rth();
+ struct rtnl_handle *rth = net->rtnl_get();
+ int r = 0;
if (!rth)
return -1;
@@ -584,9 +634,11 @@ int __export ip6addr_del(int ifindex, struct in6_addr *addr, int prefix_len)
addattr_l(&req.n, sizeof(req), IFA_ADDRESS, addr, 16);
if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
- return -1;
+ r = -1;
- return 0;
+ net->rtnl_put(rth);
+
+ return r;
}
in_addr_t __export iproute_get(in_addr_t dst, in_addr_t *gw)
@@ -600,14 +652,12 @@ in_addr_t __export iproute_get(in_addr_t dst, in_addr_t *gw)
struct rtattr *tb[RTA_MAX+1];
int len;
in_addr_t res = 0;
+ struct rtnl_handle *rth = net->rtnl_get();
if (gw)
*gw = 0;
if (!rth)
- open_rth();
-
- if (!rth)
return -1;
memset(&req, 0, sizeof(req) - 4096);
@@ -654,6 +704,8 @@ in_addr_t __export iproute_get(in_addr_t dst, in_addr_t *gw)
*gw = *(uint32_t *)RTA_DATA(tb[RTA_GATEWAY]);
out:
+ net->rtnl_put(rth);
+
return res;
}
@@ -664,9 +716,8 @@ int __export iprule_add(uint32_t addr, int table)
struct rtmsg i;
char buf[4096];
} req;
-
- if (!rth)
- open_rth();
+ struct rtnl_handle *rth = net->rtnl_get();
+ int r = 0;
if (!rth)
return -1;
@@ -688,9 +739,11 @@ int __export iprule_add(uint32_t addr, int table)
addattr32(&req.n, sizeof(req), FRA_TABLE, table);
if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
- return -1;
+ r = -1;
- return 0;
+ net->rtnl_put(rth);
+
+ return r;
}
int __export iprule_del(uint32_t addr, int table)
@@ -700,9 +753,8 @@ int __export iprule_del(uint32_t addr, int table)
struct rtmsg i;
char buf[4096];
} req;
-
- if (!rth)
- open_rth();
+ struct rtnl_handle *rth = net->rtnl_get();
+ int r = 0;
if (!rth)
return -1;
@@ -724,15 +776,9 @@ int __export iprule_del(uint32_t addr, int table)
addattr32(&req.n, sizeof(req), FRA_TABLE, table);
if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
- return -1;
-
- return 0;
-}
+ r = -1;
+ net->rtnl_put(rth);
-static void init(void)
-{
- pthread_key_create(&rth_key, free_rth);
+ return r;
}
-
-DEFINE_INIT(100, init);
diff --git a/accel-pppd/libnetlink/iputils.h b/accel-pppd/libnetlink/iputils.h
index dad06870..301cfed1 100644
--- a/accel-pppd/libnetlink/iputils.h
+++ b/accel-pppd/libnetlink/iputils.h
@@ -13,7 +13,9 @@ int iplink_vlan_del(int ifindex);
int iplink_vlan_get_vid(int ifindex, int *iflink);
int ipaddr_add(int ifindex, in_addr_t addr, int mask);
+int ipaddr_add_peer(int ifindex, in_addr_t addr, in_addr_t peer_addr);
int ipaddr_del(int ifindex, in_addr_t addr, int mask);
+int ipaddr_del_peer(int ifindex, in_addr_t addr, in_addr_t peer);
int iproute_add(int ifindex, in_addr_t src, in_addr_t dst, in_addr_t gw, int proto, int mask);
int iproute_del(int ifindex, in_addr_t dst, int proto, int mask);
diff --git a/accel-pppd/libnetlink/libnetlink.h b/accel-pppd/libnetlink/libnetlink.h
index f68bf8a1..5089c46f 100644
--- a/accel-pppd/libnetlink/libnetlink.h
+++ b/accel-pppd/libnetlink/libnetlink.h
@@ -76,8 +76,6 @@ extern int __parse_rtattr_nested_compat(struct rtattr *tb[], int max, struct rta
extern int rtnl_listen(struct rtnl_handle *, rtnl_filter_t handler,
void *jarg);
-extern int rtnl_from_file(FILE *, rtnl_filter_t handler,
- void *jarg);
#define NLMSG_TAIL(nmsg) \
((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
diff --git a/accel-pppd/main.c b/accel-pppd/main.c
index 02ada1d1..0f85c771 100644
--- a/accel-pppd/main.c
+++ b/accel-pppd/main.c
@@ -169,53 +169,55 @@ void core_restart(int soft)
static void sigsegv(int num)
{
- char cmd[PATH_MAX];
- char fname[128];
+ char cmd[128];
+ char dump[128];
char exec_file[PATH_MAX];
- struct rlimit lim;
pid_t pid;
- int status;
+ FILE *f;
+ int fd;
+ char pid_str[16];
+ unsigned int t;
pthread_sigmask(SIG_SETMASK, &orig_set, NULL);
if (conf_dump) {
- FILE *f;
- unsigned int t = time(NULL);
-
+ t = time(NULL);
+ sprintf(pid_str, "%u", getpid());
+ sprintf(cmd, "cmd-%u", t);
chdir(conf_dump);
- sprintf(fname, "cmd-%u", t);
- f = fopen(fname, "w");
+ pid = fork();
+ if (pid == 0) {
+ printf("starting gdb...\n");
+ sprintf(dump, "dump-%u", t);
+ fd = open(dump, O_CREAT|O_TRUNC|O_WRONLY,0600);
+ if (fd == -1)
+ _exit(0);
+
+ dup2(fd, STDOUT_FILENO);
+ dup2(fd, STDERR_FILENO);
+ close(fd);
+
+ f = fopen(cmd, "w");
if (!f)
- goto out;
- fprintf(f, "thread apply all bt full\ndetach\nquit\n");
+ _exit(0);
+ fprintf(f, "info shared\nthread apply all bt full\ngenerate-core-file core-%u\ndetach\nquit\n", t);
fclose(f);
- sprintf(exec_file, "/proc/%u/exe", getpid());
+ sprintf(exec_file, "/proc/%s/exe", pid_str);
readlink(exec_file, exec_file, PATH_MAX);
- sprintf(cmd, "gdb -x %s %s %d > dump-%u", fname, exec_file, getpid(), t);
-
- system(cmd);
-
- unlink(fname);
- }
-
-out:
- pid = fork();
- if (pid) {
- waitpid(pid, &status, 0);
- __core_restart(1);
- }
+ execlp("gdb", "gdb", "-x", cmd, exec_file, pid_str, NULL);
+ perror("exec");
+ _exit(0);
+ }
- if (conf_dump) {
- lim.rlim_cur = RLIM_INFINITY;
- lim.rlim_max = RLIM_INFINITY;
+ printf("waitpid: %i\n", waitpid(pid, NULL, 0));
- setrlimit(RLIMIT_CORE, &lim);
+ unlink(cmd);
}
- abort();
+ __core_restart(1);
}
static void shutdown_cb()
diff --git a/accel-pppd/memdebug.c b/accel-pppd/memdebug.c
index 08c6ad05..5353e572 100644
--- a/accel-pppd/memdebug.c
+++ b/accel-pppd/memdebug.c
@@ -49,9 +49,6 @@ static struct mem_t *_md_malloc(size_t size, const char *fname, int line)
if (mem == NULL)
return NULL;
- if (size > 4096)
- line = 0;
-
mem->fname = fname;
mem->line = line;
mem->size = size;
diff --git a/accel-pppd/net.c b/accel-pppd/net.c
index ddf2d2f8..e5cf2818 100644
--- a/accel-pppd/net.c
+++ b/accel-pppd/net.c
@@ -1,15 +1,48 @@
+#include <stdlib.h>
+#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
+#include <string.h>
+#include <pthread.h>
+#include <sched.h>
+#include <limits.h>
+#include <errno.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
+#include <sys/syscall.h>
+#include "config.h"
#include "triton.h"
-
+#include "log.h"
+#include "libnetlink.h"
#include "ap_net.h"
+#include "memdebug.h"
+
+#ifndef HAVE_SETNS
+#ifdef SYS_setns
+int setns(int fd, int nstype)
+{
+ return syscall(SYS_setns, fd, nstype);
+}
+#endif
+#endif
+
+struct kern_net {
+ struct ap_net net;
+ struct rtnl_handle *rth;
+ int ns_fd;
+ int sock;
+ int sock6;
+};
-extern int sock_fd;
+static const char *conf_netns_run_dir;
-__export __thread const struct ap_net *net;
+static LIST_HEAD(nets);
+static pthread_mutex_t nets_lock = PTHREAD_MUTEX_INITIALIZER;
+
+__export __thread struct ap_net *net;
+__export struct ap_net *def_net;
+static int def_ns_fd;
static int def_socket(int domain, int type, int proto)
{
@@ -73,21 +106,280 @@ static int def_ppp_ioctl(int fd, unsigned long request, void *arg)
static int def_sock_ioctl(unsigned long request, void *arg)
{
- return ioctl(sock_fd, request, arg);
-}
-
-__export const struct ap_net def_net = {
- .socket = def_socket,
- .connect = def_connect,
- .bind = def_bind,
- .listen = def_listen,
- .read = def_read,
- .recvfrom = def_recvfrom,
- .write = def_write,
- .sendto = def_sendto,
- .set_nonblocking = def_set_nonblocking,
- .setsockopt = def_setsockopt,
- .ppp_open = def_ppp_open,
- .ppp_ioctl = def_ppp_ioctl,
- .sock_ioctl = def_sock_ioctl,
+ struct kern_net *n = container_of(net, typeof(*n), net);
+
+ return ioctl(n->sock, request, arg);
+}
+
+static int def_sock6_ioctl(unsigned long request, void *arg)
+{
+ struct kern_net *n = container_of(net, typeof(*n), net);
+
+ return ioctl(n->sock6, request, arg);
+}
+
+static void enter_ns()
+{
+#ifdef SYS_setns
+ if (net != def_net) {
+ struct kern_net *n = container_of(net, typeof(*n), net);
+ setns(n->ns_fd, CLONE_NEWNET);
+ }
+#endif
+}
+
+static void exit_ns()
+{
+#ifdef SYS_setns
+ if (net != def_net)
+ setns(def_ns_fd, CLONE_NEWNET);
+#endif
+}
+
+static struct rtnl_handle *def_rtnl_get()
+{
+ struct kern_net *n = container_of(net, typeof(*n), net);
+ struct rtnl_handle *rth = __sync_lock_test_and_set(&n->rth, NULL);
+ int r;
+
+ if (!rth) {
+ rth = _malloc(sizeof(*rth));
+ enter_ns();
+ r = rtnl_open(rth, 0);
+ exit_ns();
+
+ if (r) {
+ _free(rth);
+ return NULL;
+ }
+ }
+
+ return rth;
+}
+
+static void def_rtnl_put(struct rtnl_handle *rth)
+{
+ struct kern_net *n = container_of(net, typeof(*n), net);
+
+ if (!__sync_bool_compare_and_swap(&n->rth, NULL, rth)) {
+ rtnl_close(rth);
+ _free(rth);
+ }
+}
+
+static int def_rtnl_open(struct rtnl_handle *rth, int proto)
+{
+ struct kern_net *n = container_of(net, typeof(*n), net);
+ int r;
+
+ enter_ns();
+ r = rtnl_open_byproto(rth, 0, proto);
+ exit_ns();
+
+ return r;
+}
+
+static int def_move_link(struct ap_net *new_net, int ifindex)
+{
+#ifdef SYS_setns
+ struct iplink_req {
+ struct nlmsghdr n;
+ struct ifinfomsg i;
+ char buf[1024];
+ } req;
+ struct rtnl_handle *rth = net->rtnl_get();
+ struct kern_net *n = container_of(new_net, typeof(*n), net);
+ int r = 0;
+
+ if (!rth)
+ return -1;
+
+ memset(&req, 0, sizeof(req) - 1024);
+
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+ req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ req.n.nlmsg_type = RTM_SETLINK;
+ req.i.ifi_family = AF_UNSPEC;
+ req.i.ifi_index = ifindex;
+
+ addattr_l(&req.n, 4096, IFLA_NET_NS_FD, &n->ns_fd, sizeof(n->ns_fd));
+
+ if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
+ r = -1;
+
+ net->rtnl_put(rth);
+
+ return r;
+#else
+ return -1;
+#endif
+}
+
+static void def_release(struct ap_net *d)
+{
+ struct kern_net *n = container_of(d, typeof(*n), net);
+
+ if (d == def_net)
+ return;
+
+ pthread_mutex_lock(&nets_lock);
+ if (--d->refs) {
+ pthread_mutex_unlock(&nets_lock);
+ return;
+ }
+
+ list_del(&d->entry);
+ pthread_mutex_unlock(&nets_lock);
+
+ net = def_net;
+
+ log_debug("close ns %s\n", n->net.name);
+
+ close(n->sock);
+ close(n->sock6);
+ close(n->ns_fd);
+
+ if (n->rth) {
+ rtnl_close(n->rth);
+ _free(n->rth);
+ }
+
+ _free(n);
+}
+
+static struct ap_net *alloc_net(const char *name)
+{
+ struct kern_net *n;
+ struct ap_net *net;
+#ifdef SYS_setns
+ int ns_fd;
+
+ if (name) {
+ char fname[PATH_MAX];
+ sprintf(fname, "%s/%s", conf_netns_run_dir, name);
+ ns_fd = open(fname, O_RDONLY);
+ if (ns_fd == -1) {
+ log_ppp_error("open %s: %s\n", fname, strerror(errno));
+ return NULL;
+ }
+
+ if (setns(ns_fd, CLONE_NEWNET)) {
+ log_ppp_error("setns %s: %s\n", fname, strerror(errno));
+ close(ns_fd);
+ return NULL;
+ }
+ } else
+ def_ns_fd = ns_fd = open("/proc/self/ns/net", O_RDONLY);
+
+ log_debug("open ns %s\n", name);
+#endif
+
+ n = _malloc(sizeof(*n));
+ net = &n->net;
+
+ net->refs = 1;
+ net->name = name ? _strdup(name) : "def";
+ net->socket = def_socket;
+ net->connect = def_connect;
+ net->bind = def_bind;
+ net->listen = def_listen;
+ net->read = def_read;
+ net->recvfrom = def_recvfrom;
+ net->write = def_write;
+ net->sendto = def_sendto;
+ net->set_nonblocking = def_set_nonblocking;
+ net->setsockopt = def_setsockopt;
+ net->ppp_open = def_ppp_open;
+ net->ppp_ioctl = def_ppp_ioctl;
+ net->sock_ioctl = def_sock_ioctl;
+ net->sock6_ioctl = def_sock6_ioctl;
+ net->enter_ns = enter_ns;
+ net->exit_ns = exit_ns;
+ net->rtnl_get = def_rtnl_get;
+ net->rtnl_put = def_rtnl_put;
+ net->rtnl_open = def_rtnl_open;
+ net->move_link = def_move_link;
+ net->release = def_release;
+
+ n->sock = socket(AF_INET, SOCK_DGRAM, 0);
+ n->sock6 = socket(AF_INET6, SOCK_DGRAM, 0);
+ n->rth = _malloc(sizeof(*n->rth));
+ rtnl_open(n->rth, 0);
+
+#ifdef SYS_setns
+ n->ns_fd = ns_fd;
+ if (ns_fd != def_ns_fd)
+ setns(def_ns_fd, CLONE_NEWNET);
+#endif
+
+ list_add_tail(&net->entry, &nets);
+
+ return net;
};
+
+int __export ap_net_register(struct ap_net *net)
+{
+ pthread_mutex_lock(&nets_lock);
+ list_add_tail(&net->entry, &nets);
+ pthread_mutex_unlock(&nets_lock);
+
+ return 0;
+}
+
+static struct ap_net *find_net(const char *name)
+{
+ struct ap_net *n;
+
+ list_for_each_entry(n, &nets, entry) {
+ if (!strcmp(name, n->name)) {
+ n->refs++;
+ return n;
+ }
+ }
+
+ return NULL;
+}
+
+__export struct ap_net *ap_net_find(const char *name)
+{
+ struct ap_net *n;
+
+ pthread_mutex_lock(&nets_lock);
+ n = find_net(name);
+ pthread_mutex_unlock(&nets_lock);
+
+ return n;
+}
+
+__export struct ap_net *ap_net_open_ns(const char *name)
+{
+#ifdef SYS_setns
+ struct ap_net *n;
+
+ pthread_mutex_lock(&nets_lock);
+ n = find_net(name);
+ if (!n)
+ n = alloc_net(name);
+ pthread_mutex_unlock(&nets_lock);
+
+ return n;
+#else
+ log_ppp_error("netns is not suppotred\n");
+ return NULL;
+#endif
+}
+
+static void __init init()
+{
+ const char *opt;
+
+ opt = conf_get_opt("common", "netns-run-dir");
+ if (opt)
+ conf_netns_run_dir = opt;
+ else
+ conf_netns_run_dir = "/var/run/netns";
+
+ def_net = net = alloc_net(NULL);
+}
+
+DEFINE_INIT(1, init);
diff --git a/accel-pppd/net/CMakeLists.txt b/accel-pppd/net/CMakeLists.txt
deleted file mode 100644
index 422ca06a..00000000
--- a/accel-pppd/net/CMakeLists.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-IF (DEFINED DPDK)
- ADD_LIBRARY(net-dp SHARED dp.c)
-
- INSTALL(TARGETS net-dp
- LIBRARY DESTINATION lib${LIB_SUFFIX}/accel-ppp
- )
-ENDIF()
diff --git a/accel-pppd/net/dp.c b/accel-pppd/net/dp.c
deleted file mode 100644
index e30d74b2..00000000
--- a/accel-pppd/net/dp.c
+++ /dev/null
@@ -1,493 +0,0 @@
-#include <unistd.h>
-#include <errno.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/ioctl.h>
-#include <sys/uio.h>
-#include <linux/ppp-ioctl.h>
-#include <linux/if.h>
-
-#include "triton.h"
-#include "ap_net.h"
-#include "log.h"
-
-#include "if_dp.h"
-
-static struct sockaddr_un dp_addr;
-static int dp_sock;
-
-static int dp_socket(int domain, int type, int proto)
-{
- struct msg_socket msg = {
- .id = MSG_SOCKET,
- .domain = domain,
- .type = type,
- .proto = proto,
- };
- struct msg_result res;
-
- int sock = socket(AF_UNIX, SOCK_DGRAM, 0);
- if (sock < 0)
- return -1;
-
- if (connect(sock, (struct sockaddr *)&dp_addr, sizeof(dp_addr))) {
- 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);
- errno = EBADE;
- return -1;
- }
-
- if (res.err) {
- close(sock);
- errno = res.err;
- return -1;
- }
-
- return sock;
-}
-
-static int dp_connect(int sock, const struct sockaddr *addr, socklen_t len)
-{
- struct msg_connect msg = {
- .id = MSG_CONNECT,
- .addrlen = len,
- };
- struct msg_result res;
- struct iovec iov[2] = {
- {
- .iov_base = &msg,
- .iov_len = sizeof(msg),
- },
- {
- .iov_base = (void *)addr,
- .iov_len = len,
- }
- };
-
- if (writev(sock, iov, 2) < 0)
- return -1;
-
- if (read(sock, &res, sizeof(res)) != sizeof(res)) {
- errno = EBADE;
- return -1;
- }
-
- if (res.err) {
- errno = res.err;
- return -1;
- }
-
- return 0;
-}
-
-static int dp_bind(int sock, const struct sockaddr *addr, socklen_t len)
-{
- struct msg_bind msg = {
- .id = MSG_BIND,
- .addrlen = len,
- };
- struct msg_result res;
- struct iovec iov[2] = {
- {
- .iov_base = &msg,
- .iov_len = sizeof(msg),
- },
- {
- .iov_base = (void *)addr,
- .iov_len = len,
- }
- };
-
- if (writev(sock, iov, 2) < 0)
- return -1;
-
- if (read(sock, &res, sizeof(res)) != sizeof(res)) {
- errno = EBADE;
- return -1;
- }
-
- if (res.err) {
- errno = res.err;
- return -1;
- }
-
- return 0;
-}
-
-static int dp_listen(int sock, int backlog)
-{
- struct msg_listen msg = {
- .id = MSG_LISTEN,
- .backlog = backlog,
- };
- struct msg_result res;
-
- if (write(sock, &msg, sizeof(msg)) < 0)
- return -1;
-
- if (read(sock, &res, sizeof(res)) != sizeof(res)) {
- errno = EBADE;
- return -1;
- }
-
- if (res.err) {
- errno = res.err;
- return -1;
- }
-
- return 0;
-}
-
-static ssize_t dp_read(int sock, void *buf, size_t len)
-{
- struct msg_recv msg = {
- .id = MSG_RECV,
- .len = len,
- .flags = 0,
- .addrlen = 0,
- };
- struct msg_result res;
- struct iovec iov[2] = {
- {
- .iov_base = &res,
- .iov_len = sizeof(res),
- },
- {
- .iov_base = buf,
- .iov_len = len,
- }
- };
-
- if (write(sock, &msg, sizeof(msg)))
- return -1;
-
-again:
- if (readv(sock, iov, 2) < sizeof(res)) {
- errno = EBADE;
- return -1;
- }
-
- if (res.err) {
- errno = res.err;
- return -1;
- }
-
- if (!res.len)
- goto again;
-
- return res.len;
-}
-
-static ssize_t dp_recvfrom(int sock, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen)
-{
- struct msg_recv msg = {
- .id = MSG_RECV,
- .len = len,
- .flags = flags,
- .addrlen = 0,
- };
- struct msg_result res;
- struct iovec iov[2] = {
- {
- .iov_base = &res,
- .iov_len = sizeof(res),
- },
- {
- .iov_base = buf,
- .iov_len = len,
- }
- };
-
- if (write(sock, &msg, sizeof(msg)))
- return -1;
-
-again:
- if (readv(sock, iov, 2) < sizeof(res)) {
- errno = EBADE;
- return -1;
- }
-
- if (res.err) {
- errno = res.err;
- return -1;
- }
-
- if (!res.len)
- goto again;
-
- memcpy(src_addr, &res.ss, res.addrlen);
- *addrlen = res.addrlen;
-
- return res.len;
-}
-
-static ssize_t dp_write(int sock, const void *buf, size_t len)
-{
- struct msg_send msg = {
- .id = MSG_SEND,
- .len = len,
- .flags = 0,
- .addrlen = 0,
- };
- struct msg_result res;
- struct iovec iov[2] = {
- {
- .iov_base = &msg,
- .iov_len = sizeof(msg),
- },
- {
- .iov_base = (void *)buf,
- .iov_len = len,
- }
- };
-
- if (writev(sock, iov, 2) < 0)
- return -1;
-
- if (read(sock, &res, sizeof(res)) != sizeof(res)) {
- errno = EBADE;
- return -1;
- }
-
- if (res.err) {
- errno = res.err;
- return -1;
- }
-
- return res.len;
-}
-
-static ssize_t dp_sendto(int sock, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen)
-{
- struct msg_send msg = {
- .id = MSG_SEND,
- .len = len,
- .flags = flags,
- .addrlen = addrlen,
- };
- struct msg_result res;
- struct iovec iov[3] = {
- {
- .iov_base = &msg,
- .iov_len = sizeof(msg),
- },
- {
- .iov_base = (void *)dest_addr,
- .iov_len = addrlen,
- },
- {
- .iov_base = (void *)buf,
- .iov_len = len,
- }
- };
-
- if (writev(sock, iov, 3) < 0)
- return -1;
-
- if (read(sock, &res, sizeof(res)) != sizeof(res)) {
- errno = EBADE;
- return -1;
- }
-
- if (res.err) {
- errno = res.err;
- return -1;
- }
-
- return res.len;
-}
-
-static int dp_set_nonblocking(int sock, int f)
-{
- return 0;
-}
-
-static int dp_setsockopt(int sock, int level, int optname, const void *optval, socklen_t optlen)
-{
- return 0;
-}
-
-
-static int dp_ppp_open()
-{
- int id = MSG_PPP_OPEN;
- struct msg_result res;
- int sock = socket(AF_UNIX, SOCK_STREAM, 0);
-
- if (sock < 0)
- return -1;
-
- if (connect(sock, (struct sockaddr *)&dp_addr, sizeof(dp_addr))) {
- close(sock);
- return -1;
- }
-
- if (write(sock, &id, sizeof(id)) < 0) {
- close(sock);
- return -1;
- }
-
- if (read(sock, &res, sizeof(res)) != sizeof(res)) {
- close(sock);
- errno = EBADE;
- return -1;
- }
-
- if (res.err) {
- close(sock);
- errno = res.err;
- return -1;
- }
-
- return sock;
-}
-
-static int dp_ppp_ioctl(int fd, unsigned long request, void *arg)
-{
- struct msg_ioctl msg = {
- .id = MSG_IOCTL,
- .request = request,
- };
- struct msg_result res;
- struct iovec iov[2] = {
- {
- .iov_base = &msg,
- .iov_len = sizeof(msg),
- },
- {
- .iov_base = arg,
- }
- };
-
- switch (request) {
- case PPPIOCSNPMODE:
- iov[1].iov_len = sizeof(struct npioctl);
- break;
- case PPPIOCSCOMPRESS:
- iov[1].iov_len = sizeof(struct ppp_option_data);
- break;
- case PPPIOCGFLAGS:
- case PPPIOCGCHAN:
- case PPPIOCNEWUNIT:
- iov[1].iov_len = 0;
- break;
- case PPPIOCSFLAGS:
- case PPPIOCSMRU:
- case PPPIOCATTCHAN:
- case PPPIOCCONNECT:
- iov[1].iov_len = sizeof(int);
- break;
-
- }
-
- if (writev(fd, iov, iov[1].iov_len ? 2 : 1) < 0)
- 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)) {
- errno = EBADE;
- return -1;
- }
-
- if (res.err) {
- errno = res.err;
- return -1;
- }
-
- return res.len;
-}
-
-static int dp_sock_ioctl(unsigned long request, void *arg)
-{
- struct msg_ioctl msg = {
- .id = MSG_SOCK_IOCTL,
- .request = request,
- };
- struct msg_result res;
- struct iovec iov[2] = {
- {
- .iov_base = &msg,
- .iov_len = sizeof(msg),
- },
- {
- .iov_base = arg,
- .iov_len = sizeof(struct ifreq),
- }
- };
-
- if (writev(dp_sock, iov, 2) < 0)
- return -1;
-
- iov[0].iov_base = &res;
- iov[0].iov_len = sizeof(res);
-
- if (readv(dp_sock, iov, 2) < sizeof(res)) {
- errno = EBADE;
- return -1;
- }
-
- if (res.err) {
- errno = res.err;
- return -1;
- }
-
- return res.len;
-}
-
-static const struct ap_net dp_net = {
- .socket = dp_socket,
- .connect = dp_connect,
- .bind = dp_bind,
- .listen = dp_listen,
- .read = dp_read,
- .recvfrom = dp_recvfrom,
- .write = dp_write,
- .sendto = dp_sendto,
- .set_nonblocking = dp_set_nonblocking,
- .setsockopt = dp_setsockopt,
- .ppp_open = dp_ppp_open,
- .ppp_ioctl = dp_ppp_ioctl,
- .sock_ioctl = dp_sock_ioctl,
-};
-
-static void init()
-{
- const char *opt = conf_get_opt("net-dpdk", "socket");
-
- if (!opt)
- return;
-
- if (strlen(opt) >= sizeof(dp_addr.sun_path)) {
- log_error("net-dpdk: socket path is too long\n");
- return;
- }
-
- strcpy(dp_addr.sun_path, opt);
-
- dp_addr.sun_family = AF_UNIX;
-
- dp_sock = socket(AF_UNIX, SOCK_DGRAM, 0);
- if (dp_sock < 0)
- return;
-
- if (connect(dp_sock, (struct sockaddr *)&dp_addr, sizeof(dp_addr))) {
- log_error("dpdk: connect: %s\n", strerror(errno));
- close(dp_sock);
- return;
- }
-}
-
-DEFINE_INIT(1, init)
diff --git a/accel-pppd/net/if_dp.h b/accel-pppd/net/if_dp.h
deleted file mode 120000
index 32df37ad..00000000
--- a/accel-pppd/net/if_dp.h
+++ /dev/null
@@ -1 +0,0 @@
-../../accel-dp/if_dp.h \ No newline at end of file
diff --git a/accel-pppd/ppp/lcp_opt_pcomp.c b/accel-pppd/ppp/lcp_opt_pcomp.c
index 97560ccf..6bc04d25 100644
--- a/accel-pppd/ppp/lcp_opt_pcomp.c
+++ b/accel-pppd/ppp/lcp_opt_pcomp.c
@@ -115,9 +115,9 @@ static int pcomp_recv_conf_ack(struct ppp_lcp_t *lcp, struct lcp_option_t *opt,
if (net->ppp_ioctl(lcp->ppp->chan_fd, PPPIOCGFLAGS, &flags))
goto err;
- flags &= ~SC_COMP_AC;
+ flags &= ~SC_COMP_PROT;
if (pcomp_opt->pcomp & 1)
- flags |= SC_COMP_AC;
+ flags |= SC_COMP_PROT;
if (net->ppp_ioctl(lcp->ppp->chan_fd, PPPIOCSFLAGS, &flags))
goto err;
diff --git a/accel-pppd/ppp/ppp.c b/accel-pppd/ppp/ppp.c
index ab67aa21..e511bf86 100644
--- a/accel-pppd/ppp/ppp.c
+++ b/accel-pppd/ppp/ppp.c
@@ -28,7 +28,8 @@
#include "memdebug.h"
int __export conf_ppp_verbose;
-int conf_unit_cache = 0;
+int conf_unit_cache;
+static int conf_unit_preallocate;
#define PPP_BUF_SIZE 8192
static mempool_t buf_pool;
@@ -93,11 +94,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));
@@ -113,7 +111,11 @@ int __export establish_ppp(struct ppp_t *ppp)
ppp->chan_hnd.fd = ppp->chan_fd;
ppp->chan_hnd.read = ppp_chan_read;
- log_ppp_debug("ppp establishing\n");
+ if (conf_unit_preallocate) {
+ if (connect_ppp_channel(ppp))
+ goto exit_close_chan;
+ } else
+ log_ppp_debug("ppp establishing\n");
if (ap_session_starting(&ppp->ses))
goto exit_close_chan;
@@ -136,6 +138,9 @@ int __export connect_ppp_channel(struct ppp_t *ppp)
struct pppunit_cache *uc = NULL;
struct ifreq ifr;
+ if (ppp->unit_fd != -1)
+ return 0;
+
if (uc_size) {
pthread_mutex_lock(&uc_lock);
if (!list_empty(&uc_list)) {
@@ -233,9 +238,8 @@ static void destablish_ppp(struct ppp_t *ppp)
{
struct pppunit_cache *uc = NULL;
- ap_session_finished(&ppp->ses);
-
if (ppp->unit_fd < 0) {
+ ap_session_finished(&ppp->ses);
destroy_ppp_channel(ppp);
return;
}
@@ -243,15 +247,28 @@ static void destablish_ppp(struct ppp_t *ppp)
if (conf_unit_cache) {
struct ifreq ifr;
+ if (ppp->ses.net != def_net) {
+ if (net->move_link(def_net, ppp->ses.ifindex)) {
+ log_ppp_warn("failed to attach to default namespace\n");
+ triton_md_unregister_handler(&ppp->unit_hnd, 1);
+ goto skip;
+ }
+ ppp->ses.net = def_net;
+ net = def_net;
+ }
+
sprintf(ifr.ifr_newname, "ppp%i", ppp->ses.unit_idx);
if (strcmp(ifr.ifr_newname, ppp->ses.ifname)) {
strncpy(ifr.ifr_name, ppp->ses.ifname, IFNAMSIZ);
if (net->sock_ioctl(SIOCSIFNAME, &ifr)) {
+ log_ppp_warn("failed to rename ppp to default name\n");
triton_md_unregister_handler(&ppp->unit_hnd, 1);
goto skip;
}
}
+ }
+ if (conf_unit_cache) {
triton_md_unregister_handler(&ppp->unit_hnd, 0);
uc = mempool_alloc(uc_pool);
@@ -261,6 +278,8 @@ static void destablish_ppp(struct ppp_t *ppp)
triton_md_unregister_handler(&ppp->unit_hnd, 1);
skip:
+ ap_session_finished(&ppp->ses);
+
ppp->unit_fd = -1;
destroy_ppp_channel(ppp);
@@ -357,17 +376,16 @@ 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 == 0)
+ break;
if (ppp->buf_size < 2) {
log_ppp_error("ppp_chan_read: short read %i\n", ppp->buf_size);
@@ -409,20 +427,16 @@ 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;
- }*/
+ break;
if (ppp->buf_size < 2) {
log_ppp_error("ppp_unit_read: short read %i\n", ppp->buf_size);
@@ -707,6 +721,12 @@ static void load_config(void)
conf_unit_cache = atoi(opt);
else
conf_unit_cache = 0;
+
+ opt = conf_get_opt("ppp", "unit-preallocate");
+ if (opt)
+ conf_unit_preallocate = atoi(opt);
+ else
+ conf_unit_preallocate = 0;
}
static void init(void)
diff --git a/accel-pppd/ppp/ppp_ifcfg.c b/accel-pppd/ppp/ppp_ifcfg.c
deleted file mode 100644
index 5f767219..00000000
--- a/accel-pppd/ppp/ppp_ifcfg.c
+++ /dev/null
@@ -1,182 +0,0 @@
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <errno.h>
-#include <limits.h>
-#include <arpa/inet.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include "linux_ppp.h"
-
-#include "triton.h"
-#include "events.h"
-#include "ppp.h"
-#include "ipdb.h"
-#include "log.h"
-
-// from /usr/include/linux/ipv6.h
-struct in6_ifreq {
- struct in6_addr ifr6_addr;
- __u32 ifr6_prefixlen;
- int ifr6_ifindex;
-};
-
-static void devconf(struct ppp_t *ppp, const char *attr, const char *val)
-{
- int fd;
- char fname[PATH_MAX];
-
- sprintf(fname, "/proc/sys/net/ipv6/conf/%s/%s", ppp->ifname, attr);
- fd = open(fname, O_WRONLY);
- if (!fd) {
- log_ppp_error("ppp: failed to open '%s': %s\n", fname, strerror(errno));
- return;
- }
-
- write(fd, val, strlen(val));
-
- close(fd);
-}
-
-static void build_addr(struct ipv6db_addr_t *a, uint64_t intf_id, struct in6_addr *addr)
-{
- memcpy(addr, &a->addr, sizeof(*addr));
-
- if (a->prefix_len <= 64)
- *(uint64_t *)(addr->s6_addr + 8) = intf_id;
- else
- *(uint64_t *)(addr->s6_addr + 8) |= intf_id & ((1 << (128 - a->prefix_len)) - 1);
-}
-
-void ppp_ifup(struct ppp_t *ppp)
-{
- struct ipv6db_addr_t *a;
- struct ifreq ifr;
- struct in6_ifreq ifr6;
- struct npioctl np;
- struct sockaddr_in addr;
-
- triton_event_fire(EV_SES_ACCT_START, ppp);
- if (ppp->stop_time)
- return;
-
- triton_event_fire(EV_SES_PRE_UP, ppp);
- if (ppp->stop_time)
- return;
-
- memset(&ifr, 0, sizeof(ifr));
- strcpy(ifr.ifr_name, ppp->ifname);
-
- if (ppp->ses.ipv4) {
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = ppp->ses.ipv4->addr;
- memcpy(&ifr.ifr_addr,&addr,sizeof(addr));
-
- if (net->sock_ioctl(SIOCSIFADDR, &ifr))
- log_ppp_error("ppp: failed to set IPv4 address: %s\n", strerror(errno));
-
- addr.sin_addr.s_addr = ppp->ses.ipv4->peer_addr;
- memcpy(&ifr.ifr_dstaddr,&addr,sizeof(addr));
-
- if (net->sock_ioctl(SIOCSIFDSTADDR, &ifr))
- log_ppp_error("ppp: failed to set peer IPv4 address: %s\n", strerror(errno));
- }
-
- if (ppp->ses.ipv6) {
- devconf(ppp, "accept_ra", "0");
- devconf(ppp, "autoconf", "0");
- devconf(ppp, "forwarding", "1");
-
- memset(&ifr6, 0, sizeof(ifr6));
- ifr6.ifr6_addr.s6_addr32[0] = htonl(0xfe800000);
- *(uint64_t *)(ifr6.ifr6_addr.s6_addr + 8) = ppp->ses.ipv6->intf_id;
- ifr6.ifr6_prefixlen = 64;
- ifr6.ifr6_ifindex = ppp->ifindex;
-
- if (ioctl(sock6_fd, SIOCSIFADDR, &ifr6))
- log_ppp_error("ppp: failed to set LL IPv6 address: %s\n", strerror(errno));
-
- list_for_each_entry(a, &ppp->ses.ipv6->addr_list, entry) {
- if (a->prefix_len == 128)
- continue;
-
- build_addr(a, ppp->ses.ipv6->intf_id, &ifr6.ifr6_addr);
- ifr6.ifr6_prefixlen = a->prefix_len;
-
- if (ioctl(sock6_fd, SIOCSIFADDR, &ifr6))
- log_ppp_error("ppp: failed to add IPv6 address: %s\n", strerror(errno));
- }
- }
-
- if (net->sock_ioctl(SIOCGIFFLAGS, &ifr))
- log_ppp_error("ppp: failed to get interface flags: %s\n", strerror(errno));
-
- ifr.ifr_flags |= IFF_UP | IFF_POINTOPOINT;
-
- if (net->sock_ioctl(SIOCSIFFLAGS, &ifr))
- log_ppp_error("ppp: failed to set interface flags: %s\n", strerror(errno));
-
- if (ppp->ses.ipv4) {
- np.protocol = PPP_IP;
- np.mode = NPMODE_PASS;
-
- if (net->ppp_ioctl(ppp->unit_fd, PPPIOCSNPMODE, &np))
- log_ppp_error("ppp: failed to set NP (IPv4) mode: %s\n", strerror(errno));
- }
-
- if (ppp->ses.ipv6) {
- np.protocol = PPP_IPV6;
- np.mode = NPMODE_PASS;
-
- if (net->ppp_ioctl(ppp->unit_fd, PPPIOCSNPMODE, &np))
- log_ppp_error("ppp: failed to set NP (IPv6) mode: %s\n", strerror(errno));
- }
-
- ppp->ses.ctrl->started(ppp);
-
- triton_event_fire(EV_SES_STARTED, ppp);
-}
-
-void __export ppp_ifdown(struct ppp_t *ppp)
-{
- struct ifreq ifr;
- struct sockaddr_in addr;
- struct in6_ifreq ifr6;
- struct ipv6db_addr_t *a;
-
- memset(&ifr, 0, sizeof(ifr));
- strcpy(ifr.ifr_name, ppp->ifname);
- net->sock_ioctl(SIOCSIFFLAGS, &ifr);
-
- if (ppp->ses.ipv4) {
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- memcpy(&ifr.ifr_addr,&addr,sizeof(addr));
- net->sock_ioctl(SIOCSIFADDR, &ifr);
- }
-
- if (ppp->ses.ipv6) {
- memset(&ifr6, 0, sizeof(ifr6));
- ifr6.ifr6_addr.s6_addr32[0] = htonl(0xfe800000);
- *(uint64_t *)(ifr6.ifr6_addr.s6_addr + 8) = ppp->ses.ipv6->intf_id;
- ifr6.ifr6_prefixlen = 64;
- ifr6.ifr6_ifindex = ppp->ifindex;
-
- ioctl(sock6_fd, SIOCDIFADDR, &ifr6);
-
- list_for_each_entry(a, &ppp->ses.ipv6->addr_list, entry) {
- if (a->prefix_len == 128)
- continue;
-
- build_addr(a, ppp->ses.ipv6->intf_id, &ifr6.ifr6_addr);
- ifr6.ifr6_prefixlen = a->prefix_len;
-
- ioctl(sock6_fd, SIOCDIFADDR, &ifr6);
- }
- }
-}
-
diff --git a/accel-pppd/ppp/ppp_notify.c b/accel-pppd/ppp/ppp_notify.c
deleted file mode 100644
index ad9fd1fc..00000000
--- a/accel-pppd/ppp/ppp_notify.c
+++ /dev/null
@@ -1,54 +0,0 @@
-#include "ppp.h"
-
-static LIST_HEAD(notified_list);
-
-void __export ppp_register_notified(struct ppp_notified_t *n)
-{
- list_add_tail(&n->entry, &notified_list);
-}
-
-void __export ppp_unregister_notified(struct ppp_notified_t *n)
-{
- list_del(&n->entry);
-}
-
-void ppp_notify_starting(struct ppp_t *ppp)
-{
- struct ppp_notified_t *n;
-
- list_for_each_entry(n, &notified_list, entry) {
- if (n->starting)
- n->starting(n, ppp);
- }
-}
-
-void ppp_notify_started(struct ppp_t *ppp)
-{
- struct ppp_notified_t *n;
-
- list_for_each_entry(n, &notified_list, entry) {
- if (n->started)
- n->started(n, ppp);
- }
-}
-
-void ppp_notify_finished(struct ppp_t *ppp)
-{
- struct ppp_notified_t *n;
-
- list_for_each_entry(n, &notified_list, entry) {
- if (n->finished)
- n->finished(n, ppp);
- }
-}
-
-void ppp_notify_finishing(struct ppp_t *ppp)
-{
- struct ppp_notified_t *n;
-
- list_for_each_entry(n, &notified_list, entry) {
- if (n->finishing)
- n->finishing(n, ppp);
- }
-}
-
diff --git a/accel-pppd/ppp/ppp_pd.c b/accel-pppd/ppp/ppp_pd.c
deleted file mode 100644
index c33ae968..00000000
--- a/accel-pppd/ppp/ppp_pd.c
+++ /dev/null
@@ -1,14 +0,0 @@
-#include "ppp.h"
-
-#include "memdebug.h"
-
-int ppp_store_pd(struct ppp_t *ppp, pd_key_t key, void *data)
-{
- struct ppp_pd_t *pd;
-
- list_for_each_entry(pd, &ppp->pd_list, entry)
- if (pd->key == key)
- return -1;
-
-
-}
diff --git a/accel-pppd/radius/acct.c b/accel-pppd/radius/acct.c
index 3d194474..9292fdaa 100644
--- a/accel-pppd/radius/acct.c
+++ b/accel-pppd/radius/acct.c
@@ -147,13 +147,15 @@ static void rad_acct_timeout(struct triton_timer_t *t)
static void rad_acct_interim_update(struct triton_timer_t *t)
{
struct radius_pd_t *rpd = container_of(t, typeof(*rpd), acct_interim_timer);
+ struct ap_session *ses = rpd->ses;
struct timespec ts;
+ int force = 0;
if (rpd->acct_req->entry.next || rpd->acct_req->timeout.tpd)
return;
if (rpd->session_timeout.expire_tv.tv_sec &&
- rpd->session_timeout.expire_tv.tv_sec - (_time() - rpd->ses->start_time) < INTERIM_SAFE_TIME)
+ rpd->session_timeout.expire_tv.tv_sec - (_time() - ses->start_time) < INTERIM_SAFE_TIME)
return;
if (req_set_stat(rpd->acct_req, rpd->ses)) {
@@ -161,7 +163,15 @@ static void rad_acct_interim_update(struct triton_timer_t *t)
return;
}
- if (!rpd->acct_interim_interval)
+ if (ses->ipv6_dp && !rpd->ipv6_dp_sent) {
+ struct ipv6db_addr_t *a;
+ list_for_each_entry(a, &ses->ipv6_dp->prefix_list, entry)
+ rad_packet_add_ipv6prefix(rpd->acct_req->pack, NULL, "Delegated-IPv6-Prefix", &a->addr, a->prefix_len);
+ rpd->ipv6_dp_sent = 1;
+ force = 1;
+ }
+
+ if (!rpd->acct_interim_interval && !force)
return;
clock_gettime(CLOCK_MONOTONIC, &ts);
@@ -180,6 +190,14 @@ static void rad_acct_interim_update(struct triton_timer_t *t)
}
}
+void rad_acct_force_interim_update(struct radius_pd_t *rpd)
+{
+ if (!rpd->acct_req)
+ return;
+
+ rad_acct_interim_update(&rpd->acct_interim_timer);
+}
+
static int rad_acct_before_send(struct rad_req_t *req)
{
struct timespec ts;
diff --git a/accel-pppd/radius/dict.c b/accel-pppd/radius/dict.c
index 7f4849cd..fa75dd9c 100644
--- a/accel-pppd/radius/dict.c
+++ b/accel-pppd/radius/dict.c
@@ -30,7 +30,7 @@ static int split(char *buf, char **ptr)
{
int i;
- for (i = 0; i < 3; i++) {
+ for (i = 0; i < 4; i++) {
buf = skip_word(buf);
if (!*buf)
return i;
@@ -70,12 +70,13 @@ static char *path, *fname1, *buf;
static int dict_load(const char *fname)
{
FILE *f;
- char *ptr[3], *endptr;
+ char *ptr[4], *endptr;
int r, n = 0;
- struct rad_dict_attr_t *attr;
+ struct rad_dict_attr_t *attr = NULL;
struct rad_dict_value_t *val;
struct rad_dict_vendor_t *vendor;
struct list_head *items;
+ struct list_head *parent_items;
f = fopen(fname, "r");
if (!f) {
@@ -90,48 +91,77 @@ static int dict_load(const char *fname)
if (buf[0] == '#' || buf[0] == '\n' || buf[0] == 0)
continue;
r = split(buf, ptr);
- if (r == 1) {
- if (!strcmp(buf, "BEGIN-VENDOR")) {
+
+ if (*ptr[r - 1] == '#')
+ r--;
+
+ if (!strcmp(buf, "VENDOR")) {
+ if (r < 2)
+ goto out_err_syntax;
+
+ vendor = malloc(sizeof(*vendor));
+ if (!vendor) {
+ log_emerg("radius: out of memory\n");
+ goto out_err;
+ }
+
+ vendor->id = strtol(ptr[1], &endptr, 10);
+ if (*endptr != 0)
+ goto out_err_syntax;
+
+ vendor->name = strdup(ptr[0]);
+ if (!vendor->name) {
+ log_emerg("radius: out of memory\n");
+ goto out_err;
+ }
+
+ if (r == 3) {
+ if (memcmp(ptr[2], "format=", 7))
+ goto out_err_syntax;
+
+ vendor->tag = strtoul(ptr[2] + 7, &endptr, 10);
+ if (*endptr != ',')
+ goto out_err_syntax;
+
+ vendor->len = strtoul(endptr + 1, &endptr, 10);
+ } else {
+ vendor->tag = 1;
+ vendor->len = 1;
+ }
+
+ INIT_LIST_HEAD(&vendor->items);
+ list_add_tail(&vendor->entry, &dict->vendors);
+ } else if (!strcmp(buf, "BEGIN-VENDOR")) {
+ if (r < 1)
+ goto out_err_syntax;
+
vendor = rad_dict_find_vendor_name(ptr[0]);
if (!vendor) {
log_emerg("radius:%s:%i: vendor not found\n", fname, n);
goto out_err;
}
items = &vendor->items;
- } else if (!strcmp(buf, "END-VENDOR"))
- items = &dict->items;
- else if (!strcmp(buf, "$INCLUDE")) {
- for (r = strlen(path) - 1; r; r--)
- if (path[r] == '/') {
- path[r + 1] = 0;
- break;
- }
- strcpy(fname1, path);
- strcat(fname1, ptr[0]);
- if (dict_load(fname1))
- goto out_err;
- } else
+ } else if (!strcmp(buf, "END-VENDOR"))
+ items = &dict->items;
+ else if (!strcmp(buf, "$INCLUDE")) {
+ if (r < 1)
goto out_err_syntax;
- } else if (r == 2) {
- if (!strcmp(buf, "VENDOR")) {
- vendor = malloc(sizeof(*vendor));
- if (!vendor) {
- log_emerg("radius: out of memory\n");
- goto out_err;
- }
- vendor->id = strtol(ptr[1], &endptr, 10);
- if (*endptr != 0)
- goto out_err_syntax;
- vendor->name = strdup(ptr[0]);
- if (!vendor->name) {
- log_emerg("radius: out of memory\n");
- goto out_err;
+
+ for (r = strlen(path) - 1; r; r--)
+ if (path[r] == '/') {
+ path[r + 1] = 0;
+ break;
}
- INIT_LIST_HEAD(&vendor->items);
- list_add_tail(&vendor->entry, &dict->vendors);
- } else
- goto out_err_syntax;
- } else if (r == 3) {
+ strcpy(fname1, path);
+ strcat(fname1, ptr[0]);
+ if (dict_load(fname1))
+ goto out_err;
+ } else if (!strcmp(buf, "BEGIN-TLV")) {
+ parent_items = items;
+ items = &attr->tlv;
+ } else if (!strcmp(buf, "END-TLV")) {
+ items = parent_items;
+ } else if (r > 2) {
if (!strcmp(buf, "ATTRIBUTE")) {
attr = malloc(sizeof(*attr));
if (!attr) {
@@ -140,14 +170,26 @@ static int dict_load(const char *fname)
}
memset(attr, 0, sizeof(*attr));
INIT_LIST_HEAD(&attr->values);
+ INIT_LIST_HEAD(&attr->tlv);
list_add_tail(&attr->entry, items);
attr->name = strdup(ptr[0]);
attr->id = strtol(ptr[1], &endptr, 10);
- if (*endptr != 0)
- goto out_err_syntax;
- if (!strcmp(ptr[2], "integer"))
+ attr->array = 0;
+ attr->size = 0;
+
+ if (r > 3 && !strcmp(ptr[3], "array"))
+ attr->array = 1;
+
+ if (!strcmp(ptr[2], "integer")) {
+ attr->type = ATTR_TYPE_INTEGER;
+ attr->size = 4;
+ } else if (!strcmp(ptr[2], "short")) {
+ attr->type = ATTR_TYPE_INTEGER;
+ attr->size = 2;
+ } else if (!strcmp(ptr[2], "byte")) {
attr->type = ATTR_TYPE_INTEGER;
- else if (!strcmp(ptr[2], "string"))
+ attr->size = 1;
+ } else if (!strcmp(ptr[2], "string"))
attr->type = ATTR_TYPE_STRING;
else if (!strcmp(ptr[2], "date"))
attr->type = ATTR_TYPE_DATE;
@@ -161,6 +203,10 @@ static int dict_load(const char *fname)
attr->type = ATTR_TYPE_IPV6ADDR;
else if (!strcmp(ptr[2], "ipv6prefix"))
attr->type = ATTR_TYPE_IPV6PREFIX;
+ else if (!strcmp(ptr[2], "ether"))
+ attr->type = ATTR_TYPE_ETHER;
+ else if (!strcmp(ptr[2], "tlv"))
+ attr->type = ATTR_TYPE_TLV;
else {
log_emerg("radius:%s:%i: unknown attribute type\n", fname, n);
goto out_err;
@@ -181,7 +227,10 @@ static int dict_load(const char *fname)
val->name = strdup(ptr[1]);
switch (attr->type) {
case ATTR_TYPE_INTEGER:
- val->val.integer = strtol(ptr[2], &endptr, 10);
+ if (ptr[2][0] == '0' && ptr[2][1] == 'x')
+ val->val.integer = strtol(ptr[2] + 2, &endptr, 16);
+ else
+ val->val.integer = strtol(ptr[2], &endptr, 10);
if (*endptr != 0)
goto out_err_syntax;
break;
diff --git a/accel-pppd/radius/dict/dictionary b/accel-pppd/radius/dict/dictionary
index e76b8ded..de056801 100644
--- a/accel-pppd/radius/dict/dictionary
+++ b/accel-pppd/radius/dict/dictionary
@@ -78,3 +78,4 @@ $INCLUDE dictionary.rfc5176
$INCLUDE dictionary.microsoft
$INCLUDE dictionary.cisco
$INCLUDE dictionary.alcatel
+$INCLUDE dictionary.dhcp
diff --git a/accel-pppd/radius/dict/dictionary.dhcp b/accel-pppd/radius/dict/dictionary.dhcp
new file mode 100644
index 00000000..de9aec75
--- /dev/null
+++ b/accel-pppd/radius/dict/dictionary.dhcp
@@ -0,0 +1,442 @@
+# -*- text -*-
+# Copyright (C) 2011 The FreeRADIUS Server project and contributors
+##############################################################################
+#
+# DHCP to RADUS gateway dictionary.
+#
+# http://www.iana.org/assignments/bootp-dhcp-parameters
+#
+# Also http://www.networksorcery.com/enp/protocol/bootp/options.htm
+#
+# http://www.bind9.net/rfc-dhcp
+#
+# $Id: 65ed832e2dfc9dc84e27795ed11492ceecceda84 $
+#
+##############################################################################
+
+#
+
+# This is really Apollo's number, but since they're out of business,
+# I don't think they'll be needing this.
+#
+# HP owns the Apollo assets, but let's not worry about that.
+#
+# The vendor codes are 2 octets, because we need 256 numbers
+# for the base DHCP options, PLUS a few for the DHCP headers,
+# which aren't in option format.
+#
+# On top of that, a number of options are really TLV's.
+# We need to be able to understand them, too.
+#
+VENDOR DHCP 54 format=2,1
+
+BEGIN-VENDOR DHCP
+
+ATTRIBUTE DHCP-Opcode 256 byte
+ATTRIBUTE DHCP-Hardware-Type 257 byte
+ATTRIBUTE DHCP-Hardware-Address-Length 258 byte
+ATTRIBUTE DHCP-Hop-Count 259 byte
+ATTRIBUTE DHCP-Transaction-Id 260 integer
+ATTRIBUTE DHCP-Number-of-Seconds 261 short
+ATTRIBUTE DHCP-Flags 262 short
+ATTRIBUTE DHCP-Client-IP-Address 263 ipaddr
+ATTRIBUTE DHCP-Your-IP-Address 264 ipaddr
+ATTRIBUTE DHCP-Server-IP-Address 265 ipaddr
+ATTRIBUTE DHCP-Gateway-IP-Address 266 ipaddr
+ATTRIBUTE DHCP-Client-Hardware-Address 267 ether # 16 octets
+ATTRIBUTE DHCP-Server-Host-Name 268 string # 64 octets
+ATTRIBUTE DHCP-Boot-Filename 269 string # 128 octets
+
+ATTRIBUTE DHCP-Relay-To-IP-Address 270 ipaddr
+ATTRIBUTE DHCP-Relay-Max-Hop-Count 271 integer
+
+# This is copied from the request packet, giaddr, and
+# added to the reply packet by the server core.
+ATTRIBUTE DHCP-Relay-IP-Address 272 ipaddr
+
+VALUE DHCP-Flags Broadcast 0x8000
+
+VALUE DHCP-Hardware-Type Ethernet 1
+VALUE DHCP-Hardware-Type Experiemental-Ethernet 2
+VALUE DHCP-Hardware-Type AX.25 3
+VALUE DHCP-Hardware-Type Proteon-Token-Ring 4
+VALUE DHCP-Hardware-Type Chaos 5
+VALUE DHCP-Hardware-Type IEEE-802 6
+VALUE DHCP-Hardware-Type Arcnet 7
+VALUE DHCP-Hardware-Type Hyperchannel 8
+VALUE DHCP-Hardware-Type Lanstar 9
+VALUE DHCP-Hardware-Type Autonet-Short-Address 10
+VALUE DHCP-Hardware-Type LocalTalk 11
+VALUE DHCP-Hardware-Type LocalNet 12
+VALUE DHCP-Hardware-Type Ultra-Link 13
+VALUE DHCP-Hardware-Type SMDS 14
+VALUE DHCP-Hardware-Type Frame-Relay 15
+VALUE DHCP-Hardware-Type ATM-16 16
+VALUE DHCP-Hardware-Type HDLC 17
+VALUE DHCP-Hardware-Type Fibre-Channel 18
+VALUE DHCP-Hardware-Type ATM-19 19
+VALUE DHCP-Hardware-Type Serial-Line 20
+VALUE DHCP-Hardware-Type ATM-21 21
+VALUE DHCP-Hardware-Type MIL-STD-188-220 22
+VALUE DHCP-Hardware-Type Metricom 23
+VALUE DHCP-Hardware-Type IEEE-1394 24
+VALUE DHCP-Hardware-Type MAPOS 25
+VALUE DHCP-Hardware-Type Twinaxial 26
+VALUE DHCP-Hardware-Type EUI-64 27
+VALUE DHCP-Hardware-Type HIPARP 28
+VALUE DHCP-Hardware-Type IP-Over-ISO-7816-3 29
+VALUE DHCP-Hardware-Type ARPSec 30
+VALUE DHCP-Hardware-Type IPSec-Tunnel 31
+VALUE DHCP-Hardware-Type Infiniband 32
+VALUE DHCP-Hardware-Type CAI-TIA-102 33
+
+##############################################################################
+#
+# DHCP Options, with comments. For now, many are "octets",
+# as FreeRADIUS doesn't handle complex data structures.
+#
+##############################################################################
+
+#ATTRIBUTE DHCP-Pad 0 octets
+ATTRIBUTE DHCP-Subnet-Mask 1 ipaddr
+# Time Offset in twos-complement notation.
+ATTRIBUTE DHCP-Time-Offset 2 integer
+ATTRIBUTE DHCP-Router-Address 3 ipaddr array
+ATTRIBUTE DHCP-Time-Server 4 ipaddr array
+ATTRIBUTE DHCP-IEN-116-Name-Server 5 ipaddr array
+ATTRIBUTE DHCP-Domain-Name-Server 6 ipaddr array
+# Logging-Server addresses
+ATTRIBUTE DHCP-Log-Server 7 ipaddr array
+ATTRIBUTE DHCP-Quotes-Server 8 ipaddr array
+ATTRIBUTE DHCP-LPR-Server 9 ipaddr array
+ATTRIBUTE DHCP-Impress-Server 10 ipaddr array
+ATTRIBUTE DHCP-RLP-Server 11 ipaddr array
+# Hostname string
+ATTRIBUTE DHCP-Hostname 12 string
+# Size of boot file in 512 byte
+ATTRIBUTE DHCP-Boot-File-Size 13 short
+# Client to dump and name
+ATTRIBUTE DHCP-Merit-Dump-File 14 octets
+ATTRIBUTE DHCP-Domain-Name 15 string
+ATTRIBUTE DHCP-Swap-Server 16 ipaddr
+# Path name for root disk
+ATTRIBUTE DHCP-Root-Path 17 string
+ATTRIBUTE DHCP-Bootp-Extensions-Path 18 string
+ATTRIBUTE DHCP-IP-Forward-Enable 19 byte
+ATTRIBUTE DHCP-Source-Route-Enable 20 byte
+# Routing Policy Filters
+ATTRIBUTE DHCP-Policy-Filter 21 octets
+ATTRIBUTE DHCP-Max-Datagram-Reassembly-Sz 22 short
+ATTRIBUTE DHCP-Default-IP-TTL 23 octets
+ATTRIBUTE DHCP-Path-MTU-Aging-Timeout 24 integer
+ATTRIBUTE DHCP-Path-MTU-Plateau-Table 25 short array
+ATTRIBUTE DHCP-Interface-MTU-Size 26 short
+ATTRIBUTE DHCP-All-Subnets-Are-Local 27 byte
+ATTRIBUTE DHCP-Broadcast-Address 28 ipaddr
+ATTRIBUTE DHCP-Perform-Mask-Discovery 29 byte
+ATTRIBUTE DHCP-Provide-Mask-To-Others 30 byte
+ATTRIBUTE DHCP-Perform-Router-Discovery 31 byte
+ATTRIBUTE DHCP-Router-Solicitation-Address 32 ipaddr
+# first is destination address, second is router.
+ATTRIBUTE DHCP-Static-Routes 33 ipaddr array
+ATTRIBUTE DHCP-Trailer-Encapsulation 34 byte
+ATTRIBUTE DHCP-ARP-Cache-Timeout 35 integer
+ATTRIBUTE DHCP-Ethernet-Encapsulation 36 byte
+ATTRIBUTE DHCP-Default-TCP-TTL 37 byte
+ATTRIBUTE DHCP-Keep-Alive-Interval 38 integer
+ATTRIBUTE DHCP-Keep-Alive-Garbage 39 byte
+ATTRIBUTE DHCP-NIS-Domain-Name 40 string
+ATTRIBUTE DHCP-NIS-Servers 41 ipaddr array
+ATTRIBUTE DHCP-NTP-Servers 42 ipaddr array
+# N Vendor Specific Information
+ATTRIBUTE DHCP-Vendor 43 octets # tlv
+ATTRIBUTE DHCP-NETBIOS-Name-Servers 44 ipaddr array
+ATTRIBUTE DHCP-NETBIOS-Dgm-Dist-Servers 45 ipaddr array
+ATTRIBUTE DHCP-NETBIOS-Node-Type 46 byte
+# N NETBIOS Scope
+ATTRIBUTE DHCP-NETBIOS 47 octets
+ATTRIBUTE DHCP-X-Window-Font-Server 48 ipaddr array
+ATTRIBUTE DHCP-X-Window-Display-Mgr 49 ipaddr array
+ATTRIBUTE DHCP-Requested-IP-Address 50 ipaddr
+ATTRIBUTE DHCP-IP-Address-Lease-Time 51 integer
+# Overload "sname" or "file"
+ATTRIBUTE DHCP-Overload 52 byte
+ATTRIBUTE DHCP-Message-Type 53 byte
+ATTRIBUTE DHCP-DHCP-Server-Identifier 54 ipaddr
+
+# Array of 1-byte numbers indicating which options the client
+# would like to see in the response.
+ATTRIBUTE DHCP-Parameter-Request-List 55 byte array
+ATTRIBUTE DHCP-DHCP-Error-Message 56 octets
+ATTRIBUTE DHCP-DHCP-Maximum-Msg-Size 57 short
+ATTRIBUTE DHCP-Renewal-Time 58 integer
+ATTRIBUTE DHCP-Rebinding-Time 59 integer
+ATTRIBUTE DHCP-Vendor-Class-Identifier 60 string
+
+# Client Identifier
+# First octets is DHCP-Hardware-Type, rest are type-specific data,
+# e.g. MAC address.
+ATTRIBUTE DHCP-Client-Identifier 61 octets
+ATTRIBUTE DHCP-Netware-Domain-Name 62 octets
+ATTRIBUTE DHCP-Netware-Sub-Options 63 octets
+ATTRIBUTE DHCP-NIS-Client-Domain-Name 64 octets
+ATTRIBUTE DHCP-NIS-Server-Address 65 ipaddr
+ATTRIBUTE DHCP-TFTP-Server-Name 66 string
+ATTRIBUTE DHCP-Boot-File-Name 67 string
+# Home Agent Addresses
+ATTRIBUTE DHCP-Home-Agent-Address 68 octets
+ATTRIBUTE DHCP-SMTP-Server-Address 69 ipaddr array
+ATTRIBUTE DHCP-POP3-Server-Address 70 ipaddr array
+ATTRIBUTE DHCP-NNTP-Server-Address 71 ipaddr array
+ATTRIBUTE DHCP-WWW-Server-Address 72 ipaddr array
+ATTRIBUTE DHCP-Finger-Server-Address 73 ipaddr array
+ATTRIBUTE DHCP-IRC-Server-Address 74 ipaddr array
+ATTRIBUTE DHCP-StreetTalk-Server-Address 75 ipaddr array
+ATTRIBUTE DHCP-STDA-Server-Address 76 ipaddr array
+# User Class Information
+ATTRIBUTE DHCP-User-Class 77 octets
+# directory agent information
+ATTRIBUTE DHCP-Directory-Agent 78 octets
+# service location agent scope
+ATTRIBUTE DHCP-Service-Scope 79 octets
+# Rapid Commit
+ATTRIBUTE DHCP-Rapid-Commit 80 octets
+# Fully Qualified Domain Name
+ATTRIBUTE DHCP-Client-FQDN 81 string
+# Relay Agent Information
+ATTRIBUTE DHCP-Relay-Agent-Information 82 tlv
+
+BEGIN-TLV DHCP-Relay-Agent-Information
+
+ATTRIBUTE DHCP-Agent-Circuit-Id 1 octets
+ATTRIBUTE DHCP-Agent-Remote-Id 2 octets
+
+ATTRIBUTE DHCP-Relay-Circuit-Id 1 octets
+ATTRIBUTE DHCP-Relay-Remote-Id 2 octets
+
+# 3 is reserved and shouldn't be used for anything
+ATTRIBUTE DHCP-Docsis-Device-Class 4 integer
+ATTRIBUTE DHCP-Relay-Link-Selection 5 ipaddr
+ATTRIBUTE DHCP-Subscriber-Id 6 string
+
+# AGH! RADIUS inside of DHCP!
+ATTRIBUTE DHCP-RADIUS-Attributes 7 octets
+
+# Horribly complicated
+ATTRIBUTE DHCP-Authentication-Information 8 octets
+ATTRIBUTE DHCP-Vendor-Specific-Information 9 octets
+ATTRIBUTE DHCP-Relay-Agent-Flags 10 byte
+ATTRIBUTE DHCP-Server-Identifier-Override 11 ipaddr
+END-TLV DHCP-Relay-Agent-Information
+
+# Internet Storage Name Service
+ATTRIBUTE DHCP-iSNS 83 octets
+# Novell Directory Services
+ATTRIBUTE DHCP-NDS-Servers 85 octets
+# Novell Directory Services
+ATTRIBUTE DHCP-NDS-Tree-Name 86 octets
+# Novell Directory Services
+ATTRIBUTE DHCP-NDS-Context 87 octets
+# Authentication
+ATTRIBUTE DHCP-Authentication 90 octets
+
+ATTRIBUTE DHCP-Client-Last-Txn-Time 91 octets
+
+ATTRIBUTE DHCP-associated-ip 92 octets
+# Client System Architecture
+ATTRIBUTE DHCP-Client-System 93 octets
+# Client Network Device Interface
+ATTRIBUTE DHCP-Client-NDI 94 octets
+# Lightweight Directory Access Protocol
+ATTRIBUTE DHCP-LDAP 95 octets
+# UUID/GUID-based Client Identifier
+ATTRIBUTE DHCP-UUID/GUID 97 octets
+# Open Group's User Authentication
+ATTRIBUTE DHCP-User-Auth 98 octets
+# NetInfo Parent-Server Address
+ATTRIBUTE DHCP-Netinfo-Address 112 octets
+# NetInfo Parent-Server Tag
+ATTRIBUTE DHCP-Netinfo-Tag 113 octets
+# URL
+ATTRIBUTE DHCP-URL 114 octets
+# DHCP Auto-Configuration
+ATTRIBUTE DHCP-Auto-Config 116 byte
+# Name Service Search
+ATTRIBUTE DHCP-Name-Service-Search 117 octets
+# Subnet Selection Option
+ATTRIBUTE DHCP-Subnet-Selection-Option 118 octets
+# DNS domain serach list
+ATTRIBUTE DHCP-Domain-Search 119 octets
+# SIP-Servers DHCP Option
+ATTRIBUTE DHCP-SIP-Servers-DHCP-Option 120 octets
+# Classless Static Route Option
+ATTRIBUTE DHCP-Classless-Static-Route 121 octets
+# CableLabs Client Configuration
+ATTRIBUTE DHCP-CCC 122 octets
+# 16 GeoConf Option
+ATTRIBUTE DHCP-GeoConf-Option 123 octets
+
+# Vendor Class
+#
+# String name that defines the vendor space used for the TLV's
+# in option 125.
+#
+ATTRIBUTE DHCP-V-I-Vendor-Class 124 octets
+# Vendor-Specific
+ATTRIBUTE DHCP-V-I-Vendor-Specific 125 octets # tlv
+ATTRIBUTE DHCP-Etherboot 128 ether
+# (for IP Phone software load)
+ATTRIBUTE DHCP-TFTP-Server-IP-Address 128 octets
+
+ATTRIBUTE DHCP-Call-Server-IP-address 129 octets
+
+ATTRIBUTE DHCP-Ethernet-Interface 130 octets
+
+ATTRIBUTE DHCP-Vendor-Discrimination-Str 130 octets
+
+ATTRIBUTE DHCP-Remote-Stats-Svr-IP-Address 131 octets
+
+ATTRIBUTE DHCP-IEEE-802.1Q-L2-Priority 132 octets
+
+ATTRIBUTE DHCP-IEEE-802.1P-VLAN-ID 133 octets
+
+ATTRIBUTE DHCP-Diffserv-Code-Point 134 octets
+
+ATTRIBUTE DHCP-HTTP-Proxy 135 octets
+
+ATTRIBUTE DHCP-Cisco-TFTP-Server-IP-Addresses 150 ipaddr array
+
+ATTRIBUTE DHCP-End-Of-Options 255 byte
+
+VALUE DHCP-Opcode Client-Message 1
+VALUE DHCP-Opcode Server-Message 2
+
+VALUE DHCP-Message-Type DHCP-Discover 1
+VALUE DHCP-Message-Type DHCP-Offer 2
+VALUE DHCP-Message-Type DHCP-Request 3
+VALUE DHCP-Message-Type DHCP-Decline 4
+VALUE DHCP-Message-Type DHCP-Ack 5
+VALUE DHCP-Message-Type DHCP-NAK 6
+VALUE DHCP-Message-Type DHCP-Release 7
+VALUE DHCP-Message-Type DHCP-Inform 8
+VALUE DHCP-Message-Type DHCP-Force-Renew 9
+
+VALUE DHCP-Parameter-Request-List DHCP-Subnet-Mask 1
+VALUE DHCP-Parameter-Request-List DHCP-Time-Offset 2
+VALUE DHCP-Parameter-Request-List DHCP-Router-Address 3
+VALUE DHCP-Parameter-Request-List DHCP-Time-Server 4
+VALUE DHCP-Parameter-Request-List DHCP-IEN-116-Name-Server 5
+VALUE DHCP-Parameter-Request-List DHCP-Domain-Name-Server 6
+VALUE DHCP-Parameter-Request-List DHCP-Log-Server 7
+VALUE DHCP-Parameter-Request-List DHCP-Quotes-Server 8
+VALUE DHCP-Parameter-Request-List DHCP-LPR-Server 9
+VALUE DHCP-Parameter-Request-List DHCP-Impress-Server 10
+VALUE DHCP-Parameter-Request-List DHCP-RLP-Server 11
+VALUE DHCP-Parameter-Request-List DHCP-Hostname 12
+VALUE DHCP-Parameter-Request-List DHCP-Boot-File-Size 13
+VALUE DHCP-Parameter-Request-List DHCP-Merit-Dump-File 14
+VALUE DHCP-Parameter-Request-List DHCP-Domain-Name 15
+VALUE DHCP-Parameter-Request-List DHCP-Swap-Server 16
+VALUE DHCP-Parameter-Request-List DHCP-Root-Path 17
+VALUE DHCP-Parameter-Request-List DHCP-Bootp-Extensions-Path 18
+VALUE DHCP-Parameter-Request-List DHCP-IP-Forward-Enable 19
+VALUE DHCP-Parameter-Request-List DHCP-Source-Route-Enable 20
+VALUE DHCP-Parameter-Request-List DHCP-Policy-Filter 21
+VALUE DHCP-Parameter-Request-List DHCP-Max-Datagram-Reassembly-Sz 22
+VALUE DHCP-Parameter-Request-List DHCP-Default-IP-TTL 23
+VALUE DHCP-Parameter-Request-List DHCP-Path-MTU-Aging-Timeout 24
+VALUE DHCP-Parameter-Request-List DHCP-Path-MTU-Plateau-Table 25
+VALUE DHCP-Parameter-Request-List DHCP-Interface-MTU-Size 26
+VALUE DHCP-Parameter-Request-List DHCP-All-Subnets-Are-Local 27
+VALUE DHCP-Parameter-Request-List DHCP-Broadcast-Address 28
+VALUE DHCP-Parameter-Request-List DHCP-Perform-Mask-Discovery 29
+VALUE DHCP-Parameter-Request-List DHCP-Provide-Mask-To-Others 30
+VALUE DHCP-Parameter-Request-List DHCP-Perform-Router-Discovery 31
+VALUE DHCP-Parameter-Request-List DHCP-Router-Solicitation-Address 32
+VALUE DHCP-Parameter-Request-List DHCP-Static-Routes 33
+VALUE DHCP-Parameter-Request-List DHCP-Trailer-Encapsulation 34
+VALUE DHCP-Parameter-Request-List DHCP-ARP-Cache-Timeout 35
+VALUE DHCP-Parameter-Request-List DHCP-Ethernet-Encapsulation 36
+VALUE DHCP-Parameter-Request-List DHCP-Default-TCP-TTL 37
+VALUE DHCP-Parameter-Request-List DHCP-Keep-Alive-Interval 38
+VALUE DHCP-Parameter-Request-List DHCP-Keep-Alive-Garbage 39
+VALUE DHCP-Parameter-Request-List DHCP-NIS-Domain-Name 40
+VALUE DHCP-Parameter-Request-List DHCP-NIS-Servers 41
+VALUE DHCP-Parameter-Request-List DHCP-NTP-Servers 42
+VALUE DHCP-Parameter-Request-List DHCP-Vendor 43
+VALUE DHCP-Parameter-Request-List DHCP-NETBIOS-Name-Servers 44
+VALUE DHCP-Parameter-Request-List DHCP-NETBIOS-Dgm-Dist-Servers 45
+VALUE DHCP-Parameter-Request-List DHCP-NETBIOS-Node-Type 46
+VALUE DHCP-Parameter-Request-List DHCP-NETBIOS 47
+VALUE DHCP-Parameter-Request-List DHCP-X-Window-Font-Server 48
+VALUE DHCP-Parameter-Request-List DHCP-X-Window-Display-Mgr 49
+VALUE DHCP-Parameter-Request-List DHCP-Requested-IP-Address 50
+VALUE DHCP-Parameter-Request-List DHCP-IP-Address-Lease-Time 51
+VALUE DHCP-Parameter-Request-List DHCP-Overload 52
+VALUE DHCP-Parameter-Request-List DHCP-Message-Type 53
+VALUE DHCP-Parameter-Request-List DHCP-DHCP-Server-Identifier 54
+VALUE DHCP-Parameter-Request-List DHCP-Parameter-Request-List 55
+VALUE DHCP-Parameter-Request-List DHCP-DHCP-Error-Message 56
+VALUE DHCP-Parameter-Request-List DHCP-DHCP-Maximum-Msg-Size 57
+VALUE DHCP-Parameter-Request-List DHCP-Renewal-Time 58
+VALUE DHCP-Parameter-Request-List DHCP-Rebinding-Time 59
+VALUE DHCP-Parameter-Request-List DHCP-Class-Identifier 60
+VALUE DHCP-Parameter-Request-List DHCP-Client-Identifier 61
+VALUE DHCP-Parameter-Request-List DHCP-Netware-Domain-Name 62
+VALUE DHCP-Parameter-Request-List DHCP-Netware-Sub-Options 63
+VALUE DHCP-Parameter-Request-List DHCP-NIS-Client-Domain-Name 64
+VALUE DHCP-Parameter-Request-List DHCP-NIS-Server-Address 65
+VALUE DHCP-Parameter-Request-List DHCP-TFTP-Server-Name 66
+VALUE DHCP-Parameter-Request-List DHCP-Boot-File-Name 67
+VALUE DHCP-Parameter-Request-List DHCP-Home-Agent-Address 68
+VALUE DHCP-Parameter-Request-List DHCP-SMTP-Server-Address 69
+VALUE DHCP-Parameter-Request-List DHCP-POP3-Server-Address 70
+VALUE DHCP-Parameter-Request-List DHCP-NNTP-Server-Address 71
+VALUE DHCP-Parameter-Request-List DHCP-WWW-Server-Address 72
+VALUE DHCP-Parameter-Request-List DHCP-Finger-Server-Address 73
+VALUE DHCP-Parameter-Request-List DHCP-IRC-Server-Address 74
+VALUE DHCP-Parameter-Request-List DHCP-StreetTalk-Server-Address 75
+VALUE DHCP-Parameter-Request-List DHCP-STDA-Server-Address 76
+VALUE DHCP-Parameter-Request-List DHCP-User-Class 77
+VALUE DHCP-Parameter-Request-List DHCP-Directory-Agent 78
+VALUE DHCP-Parameter-Request-List DHCP-Service-Scope 79
+VALUE DHCP-Parameter-Request-List DHCP-Rapid-Commit 80
+VALUE DHCP-Parameter-Request-List DHCP-Client-FQDN 81
+VALUE DHCP-Parameter-Request-List DHCP-Relay-Agent-Information 82
+VALUE DHCP-Parameter-Request-List DHCP-iSNS 83
+VALUE DHCP-Parameter-Request-List DHCP-NDS-Servers 85
+VALUE DHCP-Parameter-Request-List DHCP-NDS-Tree-Name 86
+VALUE DHCP-Parameter-Request-List DHCP-NDS-Context 87
+VALUE DHCP-Parameter-Request-List DHCP-Authentication 90
+VALUE DHCP-Parameter-Request-List DHCP-Client-Last-Txn-Time 91
+VALUE DHCP-Parameter-Request-List DHCP-associated-ip 92
+VALUE DHCP-Parameter-Request-List DHCP-Client-System 93
+VALUE DHCP-Parameter-Request-List DHCP-Client-NDI 94
+VALUE DHCP-Parameter-Request-List DHCP-LDAP 95
+VALUE DHCP-Parameter-Request-List DHCP-UUID/GUID 97
+VALUE DHCP-Parameter-Request-List DHCP-User-Auth 98
+VALUE DHCP-Parameter-Request-List DHCP-Netinfo-Address 112
+VALUE DHCP-Parameter-Request-List DHCP-Netinfo-Tag 113
+VALUE DHCP-Parameter-Request-List DHCP-URL 114
+VALUE DHCP-Parameter-Request-List DHCP-Auto-Config 116
+VALUE DHCP-Parameter-Request-List DHCP-Name-Service-Search 117
+VALUE DHCP-Parameter-Request-List DHCP-Subnet-Selection-Option 118
+VALUE DHCP-Parameter-Request-List DHCP-Domain-Search 119
+VALUE DHCP-Parameter-Request-List DHCP-SIP-Servers-DHCP-Option 120
+VALUE DHCP-Parameter-Request-List DHCP-Classless-Static-Route 121
+VALUE DHCP-Parameter-Request-List DHCP-CCC 122
+VALUE DHCP-Parameter-Request-List DHCP-GeoConf-Option 123
+VALUE DHCP-Parameter-Request-List DHCP-V-I-Vendor-Class 124
+VALUE DHCP-Parameter-Request-List DHCP-V-I-Vendor-Specific 125
+VALUE DHCP-Parameter-Request-List DHCP-Etherboot 128
+VALUE DHCP-Parameter-Request-List DHCP-TFTP-Server-IP-Address 128
+VALUE DHCP-Parameter-Request-List DHCP-Call-Server-IP-address 129
+VALUE DHCP-Parameter-Request-List DHCP-Ethernet-Interface 130
+VALUE DHCP-Parameter-Request-List DHCP-Vendor-Discrimination-Str 130
+VALUE DHCP-Parameter-Request-List DHCP-Remote-Stats-Svr-IP-Address 131
+VALUE DHCP-Parameter-Request-List DHCP-IEEE-802.1P-VLAN-ID 132
+VALUE DHCP-Parameter-Request-List DHCP-IEEE-802.1Q-L2-Priority 133
+VALUE DHCP-Parameter-Request-List DHCP-Diffserv-Code-Point 134
+VALUE DHCP-Parameter-Request-List DHCP-HTTP-Proxy 135
+
+END-VENDOR DHCP
diff --git a/accel-pppd/radius/dm_coa.c b/accel-pppd/radius/dm_coa.c
index fd59bf11..ea9743d9 100644
--- a/accel-pppd/radius/dm_coa.c
+++ b/accel-pppd/radius/dm_coa.c
@@ -146,6 +146,7 @@ static void disconnect_request(struct radius_pd_t *rpd)
static void coa_request(struct radius_pd_t *rpd)
{
struct rad_attr_t *class;
+ struct rad_attr_t *attr;
void *prev_class = rpd->attr_class;
struct ev_radius_t ev = {
.ses = rpd->ses,
@@ -181,6 +182,10 @@ static void coa_request(struct radius_pd_t *rpd)
rad_packet_add_octets(rpd->acct_req->pack, NULL, "Class", rpd->attr_class, rpd->attr_class_len);
}
+ attr = rad_packet_find_attr(rpd->dm_coa_req, NULL, "Session-Timeout");
+ if (attr)
+ rad_update_session_timeout(rpd, attr->val.integer);
+
dm_coa_send_ack(serv.hnd.fd, rpd->dm_coa_req, &rpd->dm_coa_addr);
}
diff --git a/accel-pppd/radius/packet.c b/accel-pppd/radius/packet.c
index e23b23cc..26284b5c 100644
--- a/accel-pppd/radius/packet.c
+++ b/accel-pppd/radius/packet.c
@@ -188,9 +188,24 @@ int rad_packet_recv(int fd, struct rad_packet_t **p, struct sockaddr_in *addr)
vendor = rad_dict_find_vendor_id(vendor_id);
if (vendor) {
ptr += 4;
- id = *ptr; ptr++;
- len = *ptr - 2; ptr++;
- n -= 2 + 4;
+
+ if (vendor->tag == 2)
+ id = (uint16_t)ntohs(*(uint16_t *)ptr);
+ else
+ id = *ptr;
+
+ ptr += vendor->tag;
+
+ if (vendor->len == 2)
+ len = (uint16_t)ntohs(*(uint16_t *)ptr);
+ else
+ len = *ptr;
+
+ ptr += vendor->len;
+
+ len -= vendor->tag + vendor->len;
+
+ n -= 4 + vendor->tag + vendor->len;
} else
log_ppp_warn("radius:packet: vendor %i not found\n", id);
} else
@@ -206,40 +221,47 @@ int rad_packet_recv(int fd, struct rad_packet_t **p, struct sockaddr_in *addr)
attr->vendor = vendor;
attr->attr = da;
attr->len = len;
- switch (da->type) {
- case ATTR_TYPE_STRING:
- attr->val.string = _malloc(len+1);
- if (!attr->val.string) {
- log_emerg("radius:packet: out of memory\n");
- _free(attr);
- goto out_err;
- }
- memcpy(attr->val.string, ptr, len);
- attr->val.string[len] = 0;
- break;
- case ATTR_TYPE_OCTETS:
- attr->val.octets = _malloc(len);
- if (!attr->val.octets) {
- log_emerg("radius:packet: out of memory\n");
- _free(attr);
- goto out_err;
- }
- memcpy(attr->val.octets, ptr, len);
- break;
- case ATTR_TYPE_DATE:
- case ATTR_TYPE_INTEGER:
- attr->val.integer = ntohl(*(uint32_t*)ptr);
- break;
- case ATTR_TYPE_IPADDR:
- case ATTR_TYPE_IFID:
- case ATTR_TYPE_IPV6ADDR:
- memcpy(&attr->val.integer, ptr, len);
- break;
- case ATTR_TYPE_IPV6PREFIX:
- attr->val.ipv6prefix.len = ptr[1];
- memset(&attr->val.ipv6prefix.prefix, 0, sizeof(attr->val.ipv6prefix.prefix));
- memcpy(&attr->val.ipv6prefix.prefix, ptr + 2, len - 2);
- break;
+ attr->raw = ptr;
+
+ if (!da->array) {
+ switch (da->type) {
+ case ATTR_TYPE_STRING:
+ attr->val.string = _malloc(len+1);
+ if (!attr->val.string) {
+ log_emerg("radius:packet: out of memory\n");
+ _free(attr);
+ goto out_err;
+ }
+ memcpy(attr->val.string, ptr, len);
+ attr->val.string[len] = 0;
+ break;
+ case ATTR_TYPE_OCTETS:
+ case ATTR_TYPE_ETHER:
+ case ATTR_TYPE_TLV:
+ attr->val.octets = ptr;
+ break;
+ case ATTR_TYPE_INTEGER:
+ if (len != da->size)
+ log_ppp_warn("radius:packet: attribute %s has invalid length %i (must be %i)\n", da->name, len, da->size);
+ case ATTR_TYPE_DATE:
+ if (len == 4)
+ attr->val.integer = ntohl(*(uint32_t*)ptr);
+ else if (len == 2)
+ attr->val.integer = ntohs(*(uint16_t*)ptr);
+ else if (len == 1)
+ attr->val.integer = *ptr;
+ break;
+ case ATTR_TYPE_IPADDR:
+ case ATTR_TYPE_IFID:
+ case ATTR_TYPE_IPV6ADDR:
+ memcpy(&attr->val.integer, ptr, len);
+ break;
+ case ATTR_TYPE_IPV6PREFIX:
+ attr->val.ipv6prefix.len = ptr[1];
+ memset(&attr->val.ipv6prefix.prefix, 0, sizeof(attr->val.ipv6prefix.prefix));
+ memcpy(&attr->val.ipv6prefix.prefix, ptr + 2, len - 2);
+ break;
+ }
}
list_add_tail(&attr->entry, &pack->attrs);
} else
@@ -268,7 +290,7 @@ void rad_packet_free(struct rad_packet_t *pack)
while(!list_empty(&pack->attrs)) {
attr = list_entry(pack->attrs.next, typeof(*attr), entry);
list_del(&attr->entry);
- if (attr->attr->type == ATTR_TYPE_STRING || attr->attr->type == ATTR_TYPE_OCTETS)
+ if (attr->attr->type == ATTR_TYPE_STRING)
_free(attr->val.string);
mempool_free(attr);
}
@@ -291,6 +313,7 @@ void rad_packet_print(struct rad_packet_t *pack, struct rad_server_t *s, void (*
print("[RADIUS(%i) ", s->id);
else
print("[RADIUS ");
+
switch(pack->code) {
case CODE_ACCESS_REQUEST:
print("Access-Request");
@@ -331,43 +354,46 @@ void rad_packet_print(struct rad_packet_t *pack, struct rad_server_t *s, void (*
default:
print("Unknown (%i)", pack->code);
}
+
print(" id=%x", pack->id);
list_for_each_entry(attr, &pack->attrs, entry) {
- if (attr->vendor)
- print("<%s %s ", attr->vendor->name, attr->attr->name);
- else
- print(" <%s ", attr->attr->name);
- switch (attr->attr->type) {
- case ATTR_TYPE_INTEGER:
- val = rad_dict_find_val(attr->attr, attr->val);
- if (val)
- print("%s", val->name);
- else
- print("%u", attr->val.integer);
- break;
- case ATTR_TYPE_STRING:
- print("\"%s\"", attr->val.string);
- break;
- case ATTR_TYPE_IPADDR:
- addr = ntohl(attr->val.ipaddr);
- print("%i.%i.%i.%i", (addr >> 24) & 0xff, (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff);
- break;
- case ATTR_TYPE_IFID:
- ifid_u.ifid = attr->val.ifid;
- print("%x:%x:%x:%x", ntohs(ifid_u.u16[0]), ntohs(ifid_u.u16[1]), ntohs(ifid_u.u16[2]), ntohs(ifid_u.u16[3]));
- break;
- case ATTR_TYPE_IPV6ADDR:
- inet_ntop(AF_INET6, &attr->val.ipv6addr, ip_str, sizeof(ip_str));
- print("%s", ip_str);
- break;
- case ATTR_TYPE_IPV6PREFIX:
- inet_ntop(AF_INET6, &attr->val.ipv6prefix.prefix, ip_str, sizeof(ip_str));
- print("%s/%i", ip_str, attr->val.ipv6prefix.len);
- break;
+ print(" <%s", attr->attr->name);
+
+ if (!attr->attr->array) {
+ switch (attr->attr->type) {
+ case ATTR_TYPE_INTEGER:
+ val = rad_dict_find_val(attr->attr, attr->val);
+ if (val)
+ print(" %s", val->name);
+ else
+ print(" %u", attr->val.integer);
+ break;
+ case ATTR_TYPE_STRING:
+ print(" \"%s\"", attr->val.string);
+ break;
+ case ATTR_TYPE_IPADDR:
+ addr = ntohl(attr->val.ipaddr);
+ print(" %i.%i.%i.%i", (addr >> 24) & 0xff, (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff);
+ break;
+ case ATTR_TYPE_IFID:
+ ifid_u.ifid = attr->val.ifid;
+ print(" %x:%x:%x:%x", ntohs(ifid_u.u16[0]), ntohs(ifid_u.u16[1]), ntohs(ifid_u.u16[2]), ntohs(ifid_u.u16[3]));
+ break;
+ case ATTR_TYPE_IPV6ADDR:
+ inet_ntop(AF_INET6, &attr->val.ipv6addr, ip_str, sizeof(ip_str));
+ print(" %s", ip_str);
+ break;
+ case ATTR_TYPE_IPV6PREFIX:
+ inet_ntop(AF_INET6, &attr->val.ipv6prefix.prefix, ip_str, sizeof(ip_str));
+ print(" %s/%i", ip_str, attr->val.ipv6prefix.len);
+ break;
+ }
}
+
print(">");
}
+
print("]\n");
}
diff --git a/accel-pppd/radius/radius.c b/accel-pppd/radius/radius.c
index 24ca20a3..eede9067 100644
--- a/accel-pppd/radius/radius.c
+++ b/accel-pppd/radius/radius.c
@@ -216,12 +216,14 @@ int rad_proc_attrs(struct rad_req_t *req)
break;
case Framed_IPv6_Prefix:
a = _malloc(sizeof(*a));
+ memset(a, 0, sizeof(*a));
a->prefix_len = attr->val.ipv6prefix.len;
a->addr = attr->val.ipv6prefix.prefix;
list_add_tail(&a->entry, &rpd->ipv6_addr.addr_list);
break;
case Delegated_IPv6_Prefix:
a = _malloc(sizeof(*a));
+ memset(a, 0, sizeof(*a));
a->prefix_len = attr->val.ipv6prefix.len;
a->addr = attr->val.ipv6prefix.prefix;
list_add_tail(&a->entry, &rpd->ipv6_dp.prefix_list);
@@ -230,7 +232,11 @@ int rad_proc_attrs(struct rad_req_t *req)
rpd->ses->unit_idx = attr->val.integer;
break;
case NAS_Port_Id:
- ap_session_rename(rpd->ses, attr->val.string, attr->len);
+ if (rpd->ses->ifname_rename)
+ _free(rpd->ses->ifname_rename);
+ rpd->ses->ifname_rename = _malloc(attr->len + 1);
+ memcpy(rpd->ses->ifname_rename, attr->val.string, attr->len);
+ rpd->ses->ifname_rename[attr->len] = 0;
break;
case Framed_Route:
parse_framed_route(rpd, attr->val.string);
@@ -369,6 +375,17 @@ static void session_timeout(struct triton_timer_t *t)
ap_session_terminate(rpd->ses, TERM_SESSION_TIMEOUT, 0);
}
+void rad_update_session_timeout(struct radius_pd_t *rpd, int timeout)
+{
+ rpd->session_timeout.expire_tv.tv_sec = timeout;
+ rpd->session_timeout.expire = session_timeout;
+
+ if (rpd->session_timeout.tpd)
+ triton_timer_mod(&rpd->session_timeout, 0);
+ else
+ triton_timer_add(rpd->ses->ctrl->ctx, &rpd->session_timeout, 0);
+}
+
static void ses_starting(struct ap_session *ses)
{
struct radius_pd_t *rpd = mempool_alloc(rpd_pool);
@@ -520,6 +537,19 @@ static void ses_finished(struct ap_session *ses)
release_pd(rpd);
}
+static void force_interim_update(struct ap_session *ses)
+{
+ struct radius_pd_t *rpd = find_pd(ses);
+
+ if (ses->terminating)
+ return;
+
+ if (!rpd)
+ return;
+
+ rad_acct_force_interim_update(rpd);
+}
+
struct radius_pd_t *find_pd(struct ap_session *ses)
{
struct ap_private *pd;
@@ -806,6 +836,7 @@ static void radius_init(void)
triton_event_register_handler(EV_SES_ACCT_START, (triton_event_func)ses_acct_start);
triton_event_register_handler(EV_SES_FINISHING, (triton_event_func)ses_finishing);
triton_event_register_handler(EV_SES_FINISHED, (triton_event_func)ses_finished);
+ triton_event_register_handler(EV_FORCE_INTERIM_UPDATE, (triton_event_func)force_interim_update);
triton_event_register_handler(EV_CONFIG_RELOAD, (triton_event_func)load_config);
}
diff --git a/accel-pppd/radius/radius.h b/accel-pppd/radius/radius.h
index ad27b898..3176f53b 100644
--- a/accel-pppd/radius/radius.h
+++ b/accel-pppd/radius/radius.h
@@ -14,6 +14,8 @@
#define ATTR_TYPE_IFID 5
#define ATTR_TYPE_IPV6ADDR 6
#define ATTR_TYPE_IPV6PREFIX 7
+#define ATTR_TYPE_ETHER 8
+#define ATTR_TYPE_TLV 9
#define CODE_ACCESS_REQUEST 1
#define CODE_ACCESS_ACCEPT 2
@@ -55,6 +57,8 @@ struct rad_dict_vendor_t
{
struct list_head entry;
int id;
+ int tag;
+ int len;
const char *name;
struct list_head items;
};
@@ -71,8 +75,11 @@ struct rad_dict_attr_t
struct list_head entry;
const char *name;
int id;
- int type;
+ int type:31;
+ int array:1;
+ int size;
struct list_head values;
+ struct list_head tlv;
};
struct rad_attr_t
@@ -81,8 +88,10 @@ struct rad_attr_t
struct rad_dict_attr_t *attr;
struct rad_dict_vendor_t *vendor;
//struct rad_dict_value_t *val;
- rad_value_t val;
int len;
+ int cnt;
+ void *raw;
+ rad_value_t val;
};
struct rad_packet_t
diff --git a/accel-pppd/radius/radius_p.h b/accel-pppd/radius/radius_p.h
index 0e1789fd..a01467d1 100644
--- a/accel-pppd/radius/radius_p.h
+++ b/accel-pppd/radius/radius_p.h
@@ -41,6 +41,7 @@ struct radius_pd_t {
int authenticated:1;
int acct_started:1;
int ipv6_dp_assigned:1;
+ int ipv6_dp_sent:1;
struct rad_req_t *acct_req;
struct triton_timer_t acct_interim_timer;
@@ -202,6 +203,7 @@ int rad_auth_null(struct radius_pd_t *rpd, const char *username, va_list args);
int rad_acct_start(struct radius_pd_t *rpd);
int rad_acct_stop(struct radius_pd_t *rpd);
void rad_acct_stop_defer(struct radius_pd_t *rpd);
+void rad_acct_force_interim_update(struct radius_pd_t *rpd);
struct rad_packet_t *rad_packet_alloc(int code);
int rad_packet_build(struct rad_packet_t *pack, uint8_t *RA);
@@ -223,6 +225,8 @@ void rad_server_fail(struct rad_server_t *);
void rad_server_timeout(struct rad_server_t *);
void rad_server_reply(struct rad_server_t *);
+void rad_update_session_timeout(struct radius_pd_t *rpd, int timeout);
+
void radius_restore_session(struct ap_session *ses, struct radius_pd_t *rpd);
struct rtnl_link_stats;
diff --git a/accel-pppd/radius/req.c b/accel-pppd/radius/req.c
index a2cf6a77..cc916795 100644
--- a/accel-pppd/radius/req.c
+++ b/accel-pppd/radius/req.c
@@ -82,10 +82,10 @@ static struct rad_req_t *__rad_req_alloc(struct radius_pd_t *rpd, int code, cons
if (rad_packet_add_ipaddr(req->pack, NULL, "NAS-IP-Address", conf_nas_ip_address))
goto out_err;
- if (rad_packet_add_int(req->pack, NULL, "NAS-Port", rpd->ses->unit_idx))
+ if (rpd->ses->unit_idx != -1 && rad_packet_add_int(req->pack, NULL, "NAS-Port", rpd->ses->unit_idx))
goto out_err;
- if (rad_packet_add_str(req->pack, NULL, "NAS-Port-Id", rpd->ses->ifname))
+ if (*rpd->ses->ifname && rad_packet_add_str(req->pack, NULL, "NAS-Port-Id", rpd->ses->ifname))
goto out_err;
if (req->rpd->ses->ctrl->type == CTRL_TYPE_IPOE) {
diff --git a/accel-pppd/radius/serv.c b/accel-pppd/radius/serv.c
index 9b59d04b..d40bff10 100644
--- a/accel-pppd/radius/serv.c
+++ b/accel-pppd/radius/serv.c
@@ -69,7 +69,7 @@ static struct rad_server_t *__rad_server_get(int type, struct rad_server_t *excl
if ((s->backup < s0->backup) ||
((s->backup == s0->backup) &&
- ((s->client_cnt[0] + s->client_cnt[1])/s->weight < (s0->client_cnt[0] + s0->client_cnt[1])/s0->weight)))
+ ((s->client_cnt[0] + s->client_cnt[1])*s0->weight < (s0->client_cnt[0] + s0->client_cnt[1])*s->weight)))
s0 = s;
}
diff --git a/accel-pppd/session.c b/accel-pppd/session.c
index ad164f3f..1d25c3a3 100644
--- a/accel-pppd/session.c
+++ b/accel-pppd/session.c
@@ -34,6 +34,7 @@ static int conf_single_session = -1;
static int conf_sid_source;
static int conf_seq_save_timeout = 10;
static const char *conf_seq_file;
+int __export conf_max_sessions;
pthread_rwlock_t __export ses_lock = PTHREAD_RWLOCK_INITIALIZER;
__export LIST_HEAD(ses_list);
@@ -62,6 +63,7 @@ void __export ap_session_init(struct ap_session *ses)
INIT_LIST_HEAD(&ses->pd_list);
ses->ifindex = -1;
ses->unit_idx = -1;
+ ses->net = net;
}
void __export ap_session_set_ifindex(struct ap_session *ses)
@@ -75,6 +77,10 @@ void __export ap_session_set_ifindex(struct ap_session *ses)
ses->acct_tx_packets_i = stats.tx_packets;
ses->acct_rx_bytes_i = stats.rx_bytes;
ses->acct_tx_bytes_i = stats.tx_bytes;
+ ses->acct_rx_bytes = 0;
+ ses->acct_tx_bytes = 0;
+ ses->acct_input_gigawords = 0;
+ ses->acct_output_gigawords = 0;
}
}
@@ -235,6 +241,9 @@ void __export ap_session_finished(struct ap_session *ses)
ses->ifname_rename = NULL;
}
+ if (ses->net)
+ ses->net->release(ses->net);
+
if (ses->timer.tpd)
triton_timer_del(&ses->timer);
@@ -507,6 +516,12 @@ static void load_config(void)
conf_seq_file = conf_get_opt("common", "seq-file");
if (!conf_seq_file)
conf_seq_file = "/var/lib/accel-ppp/seq";
+
+ opt = conf_get_opt("common", "max-sessions");
+ if (opt)
+ conf_max_sessions = atoi(opt);
+ else
+ conf_max_sessions = 0;
}
static void init(void)
diff --git a/accel-pppd/shaper/limiter.c b/accel-pppd/shaper/limiter.c
index 738f747e..0e754012 100644
--- a/accel-pppd/shaper/limiter.c
+++ b/accel-pppd/shaper/limiter.c
@@ -455,59 +455,64 @@ static int remove_htb_ifb(struct rtnl_handle *rth, int ifindex, int priority)
int install_limiter(struct ap_session *ses, int down_speed, int down_burst, int up_speed, int up_burst, int idx)
{
- struct rtnl_handle rth;
+ struct rtnl_handle *rth = net->rtnl_get();
int r;
- if (rtnl_open(&rth, 0)) {
+ if (!rth) {
log_ppp_error("shaper: cannot open rtnetlink\n");
return -1;
}
- down_speed = down_speed * 1000 / 8;
- down_burst = down_burst ? down_burst : conf_down_burst_factor * down_speed;
- up_speed = up_speed * 1000 / 8;
- up_burst = up_burst ? up_burst : conf_up_burst_factor * up_speed;
-
- if (conf_down_limiter == LIM_TBF)
- r = install_tbf(&rth, ses->ifindex, down_speed, down_burst);
- else {
- r = install_htb(&rth, ses->ifindex, down_speed, down_burst);
- if (r == 0)
- r = install_leaf_qdisc(&rth, ses->ifindex, 0x00010001, 0x00020000);
+ if (down_speed) {
+ down_speed = down_speed * 1000 / 8;
+ down_burst = down_burst ? down_burst : conf_down_burst_factor * down_speed;
+
+ if (conf_down_limiter == LIM_TBF)
+ r = install_tbf(rth, ses->ifindex, down_speed, down_burst);
+ else {
+ r = install_htb(rth, ses->ifindex, down_speed, down_burst);
+ if (r == 0)
+ r = install_leaf_qdisc(rth, ses->ifindex, 0x00010001, 0x00020000);
+ }
}
- if (conf_up_limiter == LIM_POLICE)
- r = install_police(&rth, ses->ifindex, up_speed, up_burst);
- else {
- r = install_htb_ifb(&rth, ses->ifindex, idx, up_speed, up_burst);
- if (r == 0)
- r = install_leaf_qdisc(&rth, conf_ifb_ifindex, 0x00010000 + idx, idx << 16);
+ if (up_speed) {
+ up_speed = up_speed * 1000 / 8;
+ up_burst = up_burst ? up_burst : conf_up_burst_factor * up_speed;
+
+ if (conf_up_limiter == LIM_POLICE)
+ r = install_police(rth, ses->ifindex, up_speed, up_burst);
+ else {
+ r = install_htb_ifb(rth, ses->ifindex, idx, up_speed, up_burst);
+ if (r == 0)
+ r = install_leaf_qdisc(rth, conf_ifb_ifindex, 0x00010000 + idx, idx << 16);
+ }
}
if (conf_fwmark)
- install_fwmark(&rth, ses->ifindex, 0x00010000);
+ install_fwmark(rth, ses->ifindex, 0x00010000);
- rtnl_close(&rth);
+ net->rtnl_put(rth);
return r;
}
int remove_limiter(struct ap_session *ses, int idx)
{
- struct rtnl_handle rth;
+ struct rtnl_handle *rth = net->rtnl_get();
- if (rtnl_open(&rth, 0)) {
+ if (!rth) {
log_ppp_error("shaper: cannot open rtnetlink\n");
return -1;
}
- remove_root(&rth, ses->ifindex);
- remove_ingress(&rth, ses->ifindex);
+ remove_root(rth, ses->ifindex);
+ remove_ingress(rth, ses->ifindex);
if (conf_up_limiter == LIM_HTB)
- remove_htb_ifb(&rth, ses->ifindex, idx);
+ remove_htb_ifb(rth, ses->ifindex, idx);
- rtnl_close(&rth);
+ net->rtnl_put(rth);
return 0;
}
@@ -518,6 +523,7 @@ int init_ifb(const char *name)
struct rtattr *tail;
struct ifreq ifr;
int r;
+ int sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
struct {
struct nlmsghdr n;
@@ -541,6 +547,7 @@ int init_ifb(const char *name)
if (ioctl(sock_fd, SIOCGIFINDEX, &ifr)) {
log_emerg("shaper: ioctl(SIOCGIFINDEX): %s\n", strerror(errno));
+ close(sock_fd);
return -1;
}
@@ -550,11 +557,13 @@ int init_ifb(const char *name)
if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr)) {
log_emerg("shaper: ioctl(SIOCSIFINDEX): %s\n", strerror(errno));
+ close(sock_fd);
return -1;
}
if (rtnl_open(&rth, 0)) {
log_emerg("shaper: cannot open rtnetlink\n");
+ close(sock_fd);
return -1;
}
@@ -587,6 +596,7 @@ int init_ifb(const char *name)
out:
rtnl_close(&rth);
+ close(sock_fd);
return r;
}
diff --git a/accel-pppd/shaper/shaper.c b/accel-pppd/shaper/shaper.c
index f13290df..e0d95690 100644
--- a/accel-pppd/shaper/shaper.c
+++ b/accel-pppd/shaper/shaper.c
@@ -121,7 +121,7 @@ static int alloc_idx(int init)
pthread_rwlock_wrlock(&shaper_lock);
if (idx_map[init / __BITS_PER_LONG] & (1 << (init % __BITS_PER_LONG))) {
i = init / __BITS_PER_LONG;
- p = init % __BITS_PER_LONG;
+ p = (init % __BITS_PER_LONG) + 1;
} else {
for (i = init / __BITS_PER_LONG; i < MAX_IDX / __BITS_PER_LONG; i++) {
p = ffs(idx_map[i]);
@@ -443,7 +443,7 @@ static void ev_shaper(struct ev_shaper_t *ev)
if (!pd->idx)
pd->idx = alloc_idx(pd->ses->ifindex);
- if (pd->down_speed > 0 && pd->up_speed > 0) {
+ if (pd->down_speed > 0 || pd->up_speed > 0) {
if (!install_limiter(ev->ses, down_speed, down_burst, up_speed, up_burst, pd->idx)) {
if (conf_verbose)
log_ppp_info2("shaper: installed shaper %i/%i (Kbit)\n", down_speed, up_speed);
@@ -483,7 +483,7 @@ static void ev_ppp_pre_up(struct ap_session *ses)
if (!pd->idx)
pd->idx = alloc_idx(ses->ifindex);
- if (down_speed > 0 && up_speed > 0) {
+ if (down_speed > 0 || up_speed > 0) {
if (!install_limiter(ses, down_speed, down_burst, up_speed, up_burst, pd->idx)) {
if (conf_verbose)
log_ppp_info2("shaper: installed shaper %i/%i (Kbit)\n", down_speed, up_speed);
diff --git a/accel-pppd/triton/list.h b/accel-pppd/triton/list.h
index a650037f..20b917d4 100644
--- a/accel-pppd/triton/list.h
+++ b/accel-pppd/triton/list.h
@@ -99,6 +99,29 @@ static inline void list_del(struct list_head *entry)
}
/**
+ * list_replace - replace old entry by new one
+ * @old : the element to be replaced
+ * @new : the new element to insert
+ *
+ * If @old was empty, it will be overwritten.
+ */
+static inline void list_replace(struct list_head *old,
+ struct list_head *new)
+{
+ new->next = old->next;
+ new->next->prev = new;
+ new->prev = old->prev;
+ new->prev->next = new;
+}
+
+static inline void list_replace_init(struct list_head *old,
+ struct list_head *new)
+{
+ list_replace(old, new);
+ INIT_LIST_HEAD(old);
+}
+
+/**
* list_del_init - deletes entry from list and reinitialize it.
* @entry: the element to delete from the list.
*/
diff --git a/accel-pppd/utils.c b/accel-pppd/utils.c
index 81b4c993..3b87ee16 100644
--- a/accel-pppd/utils.c
+++ b/accel-pppd/utils.c
@@ -1,7 +1,9 @@
#include <errno.h>
+#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
+#include <netinet/in.h>
#include "triton.h"
#include "utils.h"
@@ -35,6 +37,31 @@ int __export u_readlong(long int *dst, const char *src,
}
}
+int __export u_parse_ip4addr(const char *src, struct in_addr *addr,
+ const char **err_msg)
+{
+ struct addrinfo hint = {
+ .ai_flags = AI_NUMERICHOST,
+ .ai_family = AF_INET,
+ .ai_socktype = 0,
+ .ai_protocol = 0,
+ };
+ struct addrinfo *ainfo;
+ int err;
+
+ err = getaddrinfo(src, NULL, &hint, &ainfo);
+ if (err) {
+ *err_msg = gai_strerror(err);
+ return err;
+ }
+
+ *addr = ((struct sockaddr_in *)ainfo->ai_addr)->sin_addr;
+
+ freeaddrinfo(ainfo);
+
+ return 0;
+}
+
int __export u_randbuf(void *buf, size_t buf_len, int *err)
{
uint8_t *u8buf = buf;
diff --git a/accel-pppd/utils.h b/accel-pppd/utils.h
index be62f6a3..87582648 100644
--- a/accel-pppd/utils.h
+++ b/accel-pppd/utils.h
@@ -5,6 +5,8 @@
void u_inet_ntoa(in_addr_t, char *str);
int u_readlong(long int *dst, const char *src, long int min, long int max);
+int u_parse_ip4addr(const char *src, struct in_addr *addr,
+ const char **err_msg);
int u_randbuf(void *buf, size_t buf_len, int *err);
#endif
diff --git a/accel-pppd/vlan-mon/vlan_mon.c b/accel-pppd/vlan-mon/vlan_mon.c
index 102f6f41..10e6c210 100644
--- a/accel-pppd/vlan-mon/vlan_mon.c
+++ b/accel-pppd/vlan-mon/vlan_mon.c
@@ -18,6 +18,7 @@
#include "genl.h"
#include "libnetlink.h"
#include "iputils.h"
+#include "ap_net.h"
#include "vlan_mon.h"
#include "if_vlan_mon.h"
@@ -503,6 +504,12 @@ static void vlan_mon_mc_close(struct triton_context_t *ctx)
triton_context_unregister(ctx);
}
+static void mc_ctx_switch(struct triton_context_t *ctx, void *arg)
+{
+ net = def_net;
+ log_switch(NULL, NULL);
+}
+
static struct triton_context_t mc_ctx = {
.close = vlan_mon_mc_close,
};
@@ -531,6 +538,7 @@ static void init(void)
fcntl(rth.fd, F_SETFL, O_NONBLOCK);
fcntl(rth.fd, F_SETFD, fcntl(rth.fd, F_GETFD) | FD_CLOEXEC);
+ mc_ctx.before_switch = mc_ctx_switch;
triton_context_register(&mc_ctx, NULL);
mc_hnd.fd = rth.fd;
triton_md_register_handler(&mc_ctx, &mc_hnd);