summaryrefslogtreecommitdiff
path: root/accel-pppd/ctrl
diff options
context:
space:
mode:
authorKozlov Dmitry <xeb@mail.ru>2012-07-15 02:21:07 +0400
committerKozlov Dmitry <xeb@mail.ru>2012-07-15 02:21:07 +0400
commite687bb04784040fb26c231540e3c7b3ad9fd73d9 (patch)
treef0fce402e40b2043add9d59c8b9b811aa212b112 /accel-pppd/ctrl
parent177d7a666c96c66cadc44917654a7892dbad9150 (diff)
downloadaccel-ppp-xebd-e687bb04784040fb26c231540e3c7b3ad9fd73d9.tar.gz
accel-ppp-xebd-e687bb04784040fb26c231540e3c7b3ad9fd73d9.zip
ipoe: better support for ip unnumbered
Diffstat (limited to 'accel-pppd/ctrl')
-rw-r--r--accel-pppd/ctrl/ipoe/ipoe.c122
-rw-r--r--accel-pppd/ctrl/ipoe/ipoe.h4
2 files changed, 118 insertions, 8 deletions
diff --git a/accel-pppd/ctrl/ipoe/ipoe.c b/accel-pppd/ctrl/ipoe/ipoe.c
index ae4dca2..69ffe36 100644
--- a/accel-pppd/ctrl/ipoe/ipoe.c
+++ b/accel-pppd/ctrl/ipoe/ipoe.c
@@ -13,6 +13,7 @@
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/if.h>
+#include <linux/route.h>
#include <pcre.h>
@@ -44,6 +45,7 @@ static int conf_dhcpv4 = 1;
static int conf_up = 0;
static int conf_mode = 0;
static int conf_shared = 1;
+static int conf_ifcfg = 1;
//static int conf_dhcpv6;
static int conf_username;
static int conf_unit_cache;
@@ -66,6 +68,13 @@ static mempool_t ses_pool;
static LIST_HEAD(serv_list);
+struct ifaddr
+{
+ struct list_head entry;
+ in_addr_t addr;
+ int refs;
+};
+
struct iplink_arg
{
pcre *re;
@@ -180,9 +189,10 @@ static void ipoe_session_start(struct ipoe_session *ses)
struct ifreq ifr;
struct unit_cache *uc;
- if (ses->serv->opt_shared == 0)
+ if (ses->serv->opt_shared == 0 && (!ses->ses.ipv4 || ses->ses.ipv4->peer_addr == ses->yiaddr)) {
strncpy(ses->ses.ifname, ses->serv->ifname, AP_IFNAME_LEN);
- else if (ses->ifindex == -1) {
+ ses->ses.ifindex = ses->serv->ifindex;
+ } else if (ses->ifindex == -1) {
pthread_mutex_lock(&uc_lock);
if (!list_empty(&uc_list)) {
uc = list_entry(uc_list.next, typeof(*uc), entry);
@@ -246,6 +256,10 @@ static void ipoe_session_start(struct ipoe_session *ses)
return;
}
+ dhcpv4_get_ip(ses->serv->dhcpv4, &ses->yiaddr, &ses->siaddr, &ses->mask);
+ if (ses->yiaddr)
+ ses->dhcp_addr = 1;
+
ses->ses.ipv4 = ipdb_get_ipv4(&ses->ses);
/*if (!ses->ses.ipv4) {
log_ppp_warn("no free IPv4 address\n");
@@ -289,14 +303,93 @@ static void ipoe_session_start(struct ipoe_session *ses)
}
}
+static void ipoe_ifcfg_add(struct ipoe_session *ses)
+{
+ struct ifaddr *a;
+ struct ipoe_serv *serv = ses->serv;
+ int f = 0;
+
+ pthread_mutex_lock(&serv->lock);
+
+ if (ses->serv->opt_shared) {
+ list_for_each_entry(a, &serv->addr_list, entry) {
+ if (a->addr == ses->siaddr) {
+ f = 1;
+ break;
+ }
+ }
+ if (!f) {
+ a = _malloc(sizeof(*a));
+ a->addr = ses->siaddr;
+ a->refs = 1;
+ list_add_tail(&a->entry, &serv->addr_list);
+
+ if (ipaddr_add(serv->ifindex, a->addr, 32))
+ log_ppp_warn("ipoe: failed to add addess to interface '%s'\n", serv->ifname);
+ } else
+ a->refs++;
+ } else {
+ if (ipaddr_add(serv->ifindex, ses->siaddr, 32))
+ log_ppp_warn("ipoe: failed to add addess to interface '%s'\n", serv->ifname);
+ }
+
+ pthread_mutex_unlock(&serv->lock);
+
+ if (iproute_add(serv->ifindex, ses->siaddr, ses->yiaddr))
+ log_ppp_warn("ipoe: failed to add route to interface '%s'\n", serv->ifname);
+
+ ses->ifcfg = 1;
+}
+
+static void ipoe_ifcfg_del(struct ipoe_session *ses)
+{
+ struct ifaddr *a;
+ struct ipoe_serv *serv = ses->serv;
+
+ if (iproute_del(serv->ifindex, ses->yiaddr))
+ log_ppp_warn("ipoe: failed to delete route from interface '%s'\n", serv->ifname);
+
+ pthread_mutex_lock(&serv->lock);
+
+ if (ses->serv->opt_shared) {
+ list_for_each_entry(a, &serv->addr_list, entry) {
+ if (a->addr == ses->siaddr)
+ break;
+ }
+ if (--a->refs == 0) {
+ if (ipaddr_del(serv->ifindex, a->addr))
+ log_ppp_warn("ipoe: failed to delete addess from interface '%s'\n", serv->ifname);
+ list_del(&a->entry);
+ _free(a);
+ }
+ } else {
+ if (ipaddr_del(serv->ifindex, ses->siaddr))
+ log_ppp_warn("ipoe: failed to add addess to interface '%s'\n", serv->ifname);
+ }
+
+ pthread_mutex_unlock(&serv->lock);
+}
+
static void ipoe_session_activate(struct ipoe_session *ses)
{
+ uint32_t addr;
+
if (ses->ifindex != -1) {
- if (ipoe_nl_modify(ses->ifindex, ses->yiaddr, ses->ses.ipv4->peer_addr, NULL, NULL)) {
+ if (!ses->ses.ipv4)
+ addr = 1;
+ else if (ses->ses.ipv4->peer_addr != ses->yiaddr)
+ addr = ses->ses.ipv4->peer_addr;
+ else
+ addr = 0;
+ if (ipoe_nl_modify(ses->ifindex, ses->yiaddr, addr, NULL, NULL)) {
ap_session_terminate(&ses->ses, TERM_NAS_ERROR, 0);
return;
}
- }
+ } else
+ ses->ctrl.dont_ifcfg = 1;
+
+ if (ses->serv->opt_ifcfg)
+ ipoe_ifcfg_add(ses);
ap_session_activate(&ses->ses);
@@ -387,9 +480,12 @@ static void ipoe_session_finished(struct ap_session *s)
serv_close = ses->serv->need_close && list_empty(&ses->serv->sessions);
pthread_mutex_unlock(&ses->serv->lock);
- if (ses->yiaddr && ses->serv->dhcpv4 && ses->serv->dhcpv4->range)
+ if (ses->dhcp_addr)
dhcpv4_put_ip(ses->serv->dhcpv4, ses->yiaddr);
+ if (ses->ifcfg)
+ ipoe_ifcfg_del(ses);
+
if (serv_close)
ipoe_serv_close(&ses->serv->ctx);
@@ -436,8 +532,6 @@ static struct ipoe_session *ipoe_session_create_dhcpv4(struct ipoe_serv *serv, s
memcpy(ses->hwaddr, pack->hdr->chaddr, 6);
ses->giaddr = pack->hdr->giaddr;
- dhcpv4_get_ip(serv->dhcpv4, &ses->yiaddr, &ses->siaddr, &ses->mask);
-
if (pack->agent_circuit_id)
dlen += sizeof(struct dhcp_opt) + pack->agent_circuit_id->len;
@@ -797,6 +891,7 @@ static void add_interface(const char *ifname, int ifindex, const char *opt)
int opt_dhcpv4 = 0;
int opt_up = 0;
int opt_mode = conf_mode;
+ int opt_ifcfg = conf_ifcfg;
str0 = strchr(opt, ',');
if (str0) {
@@ -837,6 +932,8 @@ static void add_interface(const char *ifname, int ifindex, const char *opt)
opt_mode = MODE_L3;
else
goto parse_err;
+ } else if (strcmp(str, "ifcfg") == 0) {
+ opt_ifcfg = atoi(ptr1);
}
if (end)
@@ -875,7 +972,8 @@ static void add_interface(const char *ifname, int ifindex, const char *opt)
}
serv->opt_up = opt_up;
- serv->opt_mode = conf_mode;
+ serv->opt_mode = opt_mode;
+ serv->opt_ifcfg = opt_ifcfg;
return;
}
@@ -889,8 +987,10 @@ static void add_interface(const char *ifname, int ifindex, const char *opt)
serv->opt_dhcpv4 = opt_dhcpv4;
serv->opt_up = opt_up;
serv->opt_mode = opt_mode;
+ serv->opt_ifcfg = opt_ifcfg;
serv->active = 1;
INIT_LIST_HEAD(&serv->sessions);
+ INIT_LIST_HEAD(&serv->addr_list);
pthread_mutex_init(&serv->lock, NULL);
triton_context_register(&serv->ctx, NULL);
@@ -1116,6 +1216,12 @@ static void load_config(void)
else
conf_shared = 1;
+ opt = conf_get_opt("ipoe", "ifcfg");
+ if (opt)
+ conf_ifcfg = atoi(opt);
+ else
+ conf_ifcfg = 1;
+
opt = conf_get_opt("ipoe", "mode");
if (opt) {
if (!strcmp(opt, "L2"))
diff --git a/accel-pppd/ctrl/ipoe/ipoe.h b/accel-pppd/ctrl/ipoe/ipoe.h
index d18db69..edf9754 100644
--- a/accel-pppd/ctrl/ipoe/ipoe.h
+++ b/accel-pppd/ctrl/ipoe/ipoe.h
@@ -16,12 +16,14 @@ struct ipoe_serv
int ifindex;
int active;
struct list_head sessions;
+ struct list_head addr_list;
struct dhcpv4_serv *dhcpv4;
pthread_mutex_t lock;
int opt_mode;
int opt_shared:1;
int opt_dhcpv4:1;
int opt_up:1;
+ int opt_ifcfg:1;
int need_close:1;
};
@@ -51,6 +53,8 @@ struct ipoe_session
uint8_t *data;
struct dhcpv4_packet *dhcpv4_request;
int ifindex;
+ int ifcfg:1;
+ int dhcp_addr:1;
};
struct ipoe_session_info