summaryrefslogtreecommitdiff
path: root/accel-pppd/ctrl/ipoe
diff options
context:
space:
mode:
authorKozlov Dmitry <xeb@mail.ru>2012-07-05 14:08:04 +0400
committerKozlov Dmitry <xeb@mail.ru>2012-07-05 14:08:04 +0400
commit64b5b693764c4f36870fd988ccbb53bcb188e74d (patch)
tree7af1897fdb9edd9cf40885c65f8567ae58bc0de6 /accel-pppd/ctrl/ipoe
parent046642d5729493b25e5fba4b11c507fe3d2e2687 (diff)
downloadaccel-ppp-64b5b693764c4f36870fd988ccbb53bcb188e74d.tar.gz
accel-ppp-64b5b693764c4f36870fd988ccbb53bcb188e74d.zip
ipoe: futher work
Diffstat (limited to 'accel-pppd/ctrl/ipoe')
-rw-r--r--accel-pppd/ctrl/ipoe/ipoe.c183
-rw-r--r--accel-pppd/ctrl/ipoe/ipoe.h7
-rw-r--r--accel-pppd/ctrl/ipoe/ipoe_netlink.c57
3 files changed, 209 insertions, 38 deletions
diff --git a/accel-pppd/ctrl/ipoe/ipoe.c b/accel-pppd/ctrl/ipoe/ipoe.c
index eedd8cf9..5878b0c4 100644
--- a/accel-pppd/ctrl/ipoe/ipoe.c
+++ b/accel-pppd/ctrl/ipoe/ipoe.c
@@ -37,7 +37,13 @@
#define USERNAME_IFNAME 0
#define USERNAME_LUA 1
+#define MODE_L2 0
+#define MODE_L3 1
+
static int conf_dhcpv4 = 1;
+static int conf_up = 0;
+static int conf_mode = 0;
+static int conf_shared = 1;
//static int conf_dhcpv6;
static int conf_username;
@@ -51,7 +57,6 @@ static int conf_netmask = 24;
static int conf_lease_time = 600;
static int conf_lease_timeout = 660;
static int conf_verbose;
-static int conf_opt_single = 0;
static unsigned int stat_starting;
static unsigned int stat_active;
@@ -158,10 +163,10 @@ static void ipoe_session_start(struct ipoe_session *ses)
char *passwd;
struct ifreq ifr;
- if (ses->serv->opt_single)
+ if (ses->serv->opt_shared == 0)
strncpy(ses->ses.ifname, ses->serv->ifname, AP_IFNAME_LEN);
else {
- ses->ifindex = ipoe_nl_create(0, 0, ses->serv->ifname, ses->hwaddr);
+ ses->ifindex = ipoe_nl_create(0, 0, ses->dhcpv4_request ? ses->serv->ifname : NULL, ses->hwaddr);
if (ses->ifindex == -1) {
log_ppp_error("ipoe: failed to create interface\n");
ipoe_session_finished(&ses->ses);
@@ -178,6 +183,7 @@ static void ipoe_session_start(struct ipoe_session *ses)
}
strncpy(ses->ses.ifname, ifr.ifr_name, AP_IFNAME_LEN);
+ ses->ses.ifindex = ses->ifindex;
}
if (!ses->ses.username) {
@@ -236,6 +242,11 @@ static void ipoe_session_start(struct ipoe_session *ses)
ses->timer.expire = ipoe_session_timeout;
ses->timer.expire_tv.tv_sec = conf_offer_timeout;
triton_timer_add(&ses->ctx, &ses->timer, 0);
+ } else {
+ if (ipoe_nl_modify(ses->ifindex, ses->giaddr, ses->ses.ipv4->peer_addr, NULL, NULL))
+ ap_session_terminate(&ses->ses, TERM_NAS_ERROR, 0);
+ else
+ ap_session_activate(&ses->ses);
}
}
@@ -493,7 +504,7 @@ static void ipoe_recv_dhcpv4(struct dhcpv4_serv *dhcpv4, struct dhcpv4_packet *p
dhcpv4_print_packet(pack, log_ppp_info2);
}
- if (serv->opt_single)
+ if (serv->opt_shared == 0)
ipoe_drop_sessions(serv, ses);
if (ses->ses.state == AP_STATE_STARTING && !ses->dhcpv4_request) {
@@ -552,7 +563,9 @@ static struct ipoe_session *ipoe_session_create_up(struct ipoe_serv *serv, struc
ses->ctrl.terminate = ipoe_session_terminate;
ses->ctrl.type = CTRL_TYPE_IPOE;
ses->ctrl.name = "ipoe";
-
+
+ ses->giaddr = iph->saddr;
+
ses->ctrl.calling_station_id = _malloc(17);
ses->ctrl.called_station_id = _malloc(17);
@@ -585,10 +598,13 @@ void ipoe_recv_up(int ifindex, struct ethhdr *eth, struct iphdr *iph)
list_for_each_entry(serv, &serv_list, entry) {
if (serv->ifindex != ifindex)
continue;
+
+ if (!serv->opt_up)
+ return;
pthread_mutex_lock(&serv->lock);
list_for_each_entry(ses, &serv->sessions, entry) {
- if (memcmp(ses->hwaddr, eth->h_source, 6) == 0) {
+ if (ses->giaddr == iph->saddr) {
pthread_mutex_unlock(&serv->lock);
return;
}
@@ -649,42 +665,105 @@ static void ipoe_drop_sessions(struct ipoe_serv *serv, struct ipoe_session *skip
static void add_interface(const char *ifname, int ifindex, const char *opt)
{
- int opt_single;
- const char *ptr;
+ char *str0, *str, *ptr1, *ptr2;
+ int end;
struct ipoe_serv *serv;
+ int opt_shared = conf_shared;
+ int opt_dhcpv4 = 0;
+ int opt_up = 0;
+ int opt_mode = conf_mode;
+
+ str0 = strchr(opt, ',');
+ if (str0) {
+ str0 = _strdup(str0 + 1);
+ str = str0;
+
+ while (1) {
+ for (ptr1 = str + 1; *ptr1 && *ptr1 != '='; ptr1++);
- ptr = strstr(opt, ",single");
- if (ptr) {
- if (ptr[7] && ptr[7] != ',')
- goto out_err_parse;
- opt_single = 1;
- } else {
- ptr = strstr(opt, ",shared");
- if (ptr) {
- if (ptr[7] && ptr[7] != ',')
- goto out_err_parse;
- opt_single = 0;
- } else
- opt_single = conf_opt_single;
+ if (!*ptr1)
+ goto parse_err;
+
+ *ptr1 = 0;
+
+ for (ptr2 = ++ptr1; *ptr2 && *ptr2 != ','; ptr2++);
+
+ end = *ptr2 == 0;
+
+ if (!end)
+ *ptr2 = 0;
+
+ if (ptr2 == ptr1)
+ goto parse_err;
+
+ if (strcmp(str, "start") == 0) {
+ if (!strcmp(ptr1, "up"))
+ opt_up = 1;
+ else if (!strcmp(ptr1, "dhcpv4"))
+ opt_dhcpv4 = 1;
+ else
+ goto parse_err;
+ } else if (strcmp(str, "shared") == 0) {
+ opt_shared = atoi(ptr1);
+ } else if (strcmp(str, "mode") == 0) {
+ if (!strcmp(ptr1, "L2"))
+ opt_mode = MODE_L2;
+ else if (!strcmp(ptr1, "L3"))
+ opt_mode = MODE_L3;
+ else
+ goto parse_err;
+ } else
+ goto parse_err;
+
+ if (end)
+ break;
+
+ str = ptr2 + 1;
+ }
+
+ _free(str0);
}
-
+
+ if (!opt_up && !opt_dhcpv4) {
+ opt_up = conf_up;
+ opt_dhcpv4 = conf_dhcpv4;
+ }
+
list_for_each_entry(serv, &serv_list, entry) {
- if (strcmp(ifname, serv->ifname) == 0) {
- serv->active = 1;
- serv->ifindex = ifindex;
- if (opt_single && !serv->opt_single)
- ipoe_drop_sessions(serv, NULL);
- serv->opt_single = opt_single;
- return;
+ if (!strcmp(ifname, serv->ifname))
+ continue;
+
+ serv->active = 1;
+ serv->ifindex = ifindex;
+
+ if ((opt_shared && !serv->opt_shared) || (!opt_shared && serv->opt_shared)) {
+ ipoe_drop_sessions(serv, NULL);
+ serv->opt_shared = opt_shared;
}
+
+ if (opt_dhcpv4 && !serv->dhcpv4) {
+ serv->dhcpv4 = dhcpv4_create(&serv->ctx, serv->ifname);
+ if (serv->dhcpv4)
+ serv->dhcpv4->recv = ipoe_recv_dhcpv4;
+ } else if (!opt_dhcpv4 && serv->dhcpv4) {
+ dhcpv4_free(serv->dhcpv4);
+ serv->dhcpv4 = NULL;
+ }
+
+ serv->opt_up = opt_up;
+ serv->opt_mode = conf_mode;
+
+ return;
}
serv = _malloc(sizeof(*serv));
memset(serv, 0, sizeof(*serv));
serv->ifname = _strdup(ifname);
serv->ifindex = ifindex;
- serv->opt_single = opt_single;
- serv->opt_dhcpv4 = conf_dhcpv4;
+ serv->opt_shared = opt_shared;
+ serv->opt_dhcpv4 = opt_dhcpv4;
+ serv->opt_up = opt_up;
+ serv->opt_mode = opt_mode;
serv->active = 1;
INIT_LIST_HEAD(&serv->sessions);
pthread_mutex_init(&serv->lock, NULL);
@@ -703,8 +782,9 @@ static void add_interface(const char *ifname, int ifindex, const char *opt)
return;
-out_err_parse:
+parse_err:
log_error("ipoe: failed to parse '%s'\n", opt);
+ _free(str0);
}
static void load_interface(const char *opt)
@@ -853,13 +933,11 @@ static void load_config(void)
{
const char *opt;
struct conf_sect_t *s = conf_get_section("ipoe");
+ struct conf_option_t *opt1;
if (!s)
return;
- load_interfaces(s);
- load_local_nets(s);
-
opt = conf_get_opt("ipoe", "username");
if (opt) {
if (strcmp(opt, "ifname") == 0)
@@ -901,6 +979,41 @@ static void load_config(void)
opt = conf_get_opt("ipoe", "lease-timeout");
if (opt)
conf_lease_timeout = atoi(opt);
+
+ opt = conf_get_opt("ipoe", "shared");
+ if (opt)
+ conf_shared = atoi(opt);
+ else
+ conf_shared = 1;
+
+ opt = conf_get_opt("ipoe", "mode");
+ if (opt) {
+ if (!strcmp(opt, "L2"))
+ conf_mode = MODE_L2;
+ else if (!strcmp(opt, "L3"))
+ conf_mode = MODE_L3;
+ else
+ log_emerg("ipoe: failed to parse 'mode=%s'\n", opt);
+ } else
+ conf_mode = MODE_L2;
+
+ conf_dhcpv4 = 0;
+ conf_up = 0;
+
+ list_for_each_entry(opt1, &s->items, entry) {
+ if (strcmp(opt1->name, "start"))
+ continue;
+ if (!strcmp(opt1->val, "dhcpv4"))
+ conf_dhcpv4 = 1;
+ else if (!strcmp(opt1->val, "up"))
+ conf_up = 1;
+ }
+
+ if (!conf_dhcpv4 && !conf_up)
+ conf_dhcpv4 = 1;
+
+ load_interfaces(s);
+ load_local_nets(s);
}
static void ipoe_init(void)
diff --git a/accel-pppd/ctrl/ipoe/ipoe.h b/accel-pppd/ctrl/ipoe/ipoe.h
index 30760906..97b13e63 100644
--- a/accel-pppd/ctrl/ipoe/ipoe.h
+++ b/accel-pppd/ctrl/ipoe/ipoe.h
@@ -15,11 +15,13 @@ struct ipoe_serv
char *ifname;
int ifindex;
int active;
- int opt_single;
- int opt_dhcpv4;
struct list_head sessions;
struct dhcpv4_serv *dhcpv4;
pthread_mutex_t lock;
+ int opt_mode;
+ int opt_shared:1;
+ int opt_dhcpv4:1;
+ int opt_up:1;
};
struct dhcp_opt
@@ -60,6 +62,7 @@ void ipoe_nl_add_net(uint32_t addr, int mask);
void ipoe_nl_delete_nets(void);
int ipoe_nl_create(uint32_t peer_addr, uint32_t addr, const char *ifname, uint8_t *hwaddr);
void ipoe_nl_delete(int ifindex);
+int ipoe_nl_modify(int ifindex, uint32_t peer_addr, uint32_t addr, const char *ifname, uint8_t *hwaddr);
#endif
diff --git a/accel-pppd/ctrl/ipoe/ipoe_netlink.c b/accel-pppd/ctrl/ipoe/ipoe_netlink.c
index 57da0def..ec603d5d 100644
--- a/accel-pppd/ctrl/ipoe/ipoe_netlink.c
+++ b/accel-pppd/ctrl/ipoe/ipoe_netlink.c
@@ -109,7 +109,7 @@ int ipoe_nl_create(uint32_t peer_addr, uint32_t addr, const char *ifname, uint8_
nlh->nlmsg_type = ipoe_genl_id;
ghdr = NLMSG_DATA(&req.n);
- ghdr->cmd = IPOE_CMD_DELETE;
+ ghdr->cmd = IPOE_CMD_CREATE;
if (peer_addr)
addattr32(nlh, 1024, IPOE_ATTR_PEER_ADDR, peer_addr);
@@ -163,6 +163,61 @@ out:
return ret;
}
+int ipoe_nl_modify(int ifindex, uint32_t peer_addr, uint32_t addr, const char *ifname, uint8_t *hwaddr)
+{
+ struct rtnl_handle rth;
+ struct nlmsghdr *nlh;
+ struct genlmsghdr *ghdr;
+ int ret = 0;
+ struct {
+ struct nlmsghdr n;
+ char buf[1024];
+ } req;
+ union {
+ uint8_t hwaddr[6];
+ uint64_t u64;
+ } u;
+
+ if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC)) {
+ log_ppp_error("ipoe: cannot open generic netlink socket\n");
+ return -1;
+ }
+
+ nlh = &req.n;
+ nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
+ nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ nlh->nlmsg_type = ipoe_genl_id;
+
+ ghdr = NLMSG_DATA(&req.n);
+ ghdr->cmd = IPOE_CMD_MODIFY;
+
+ addattr32(nlh, 1024, IPOE_ATTR_IFINDEX, ifindex);
+
+ if (peer_addr)
+ addattr32(nlh, 1024, IPOE_ATTR_PEER_ADDR, peer_addr);
+
+ if (addr)
+ addattr32(nlh, 1024, IPOE_ATTR_ADDR, addr);
+
+ if (hwaddr) {
+ memcpy(u.hwaddr, hwaddr, 6);
+ addattr_l(nlh, 1024, IPOE_ATTR_HWADDR, &u.u64, 8);
+ }
+
+ if (ifname)
+ addattr_l(nlh, 1024, IPOE_ATTR_IFNAME, ifname, strlen(ifname) + 1);
+
+ if (rtnl_talk(&rth, nlh, 0, 0, nlh, NULL, NULL, 0) < 0 ) {
+ log_ppp_error("ipoe: nl_create: error talking to kernel\n");
+ ret = -1;
+ }
+
+ rtnl_close(&rth);
+
+ return ret;
+}
+
+
void ipoe_nl_delete(int ifindex)
{
struct rtnl_handle rth;