summaryrefslogtreecommitdiff
path: root/accel-pppd/ctrl/ipoe
diff options
context:
space:
mode:
authorKozlov Dmitry <xeb@mail.ru>2012-07-10 18:58:53 +0400
committerKozlov Dmitry <xeb@mail.ru>2012-07-10 18:58:53 +0400
commit80c32d237e01b1c05663ccfa34003d2f49aa7eee (patch)
treea49da21b5219e4bc89d9794918f054f3620cb140 /accel-pppd/ctrl/ipoe
parent64b5b693764c4f36870fd988ccbb53bcb188e74d (diff)
downloadaccel-ppp-80c32d237e01b1c05663ccfa34003d2f49aa7eee.tar.gz
accel-ppp-80c32d237e01b1c05663ccfa34003d2f49aa7eee.zip
initial session backup implementation
Diffstat (limited to 'accel-pppd/ctrl/ipoe')
-rw-r--r--accel-pppd/ctrl/ipoe/CMakeLists.txt4
-rw-r--r--accel-pppd/ctrl/ipoe/backup.c168
-rw-r--r--accel-pppd/ctrl/ipoe/ipoe.c59
-rw-r--r--accel-pppd/ctrl/ipoe/ipoe.h4
-rw-r--r--accel-pppd/ctrl/ipoe/ipoe_netlink.c1
5 files changed, 235 insertions, 1 deletions
diff --git a/accel-pppd/ctrl/ipoe/CMakeLists.txt b/accel-pppd/ctrl/ipoe/CMakeLists.txt
index 297d81b1..7be18cc0 100644
--- a/accel-pppd/ctrl/ipoe/CMakeLists.txt
+++ b/accel-pppd/ctrl/ipoe/CMakeLists.txt
@@ -17,6 +17,10 @@ IF (LUA)
SET(sources ${sources} lua.c lua_lpack.c)
ENDIF (LUA)
+IF (BACKUP)
+ SET(sources ${sources} backup.c)
+ENDIF (BACKUP)
+
ADD_LIBRARY(ipoe SHARED ${sources})
IF (LUA)
TARGET_LINK_LIBRARIES(ipoe ${LUA_LIBRARIES})
diff --git a/accel-pppd/ctrl/ipoe/backup.c b/accel-pppd/ctrl/ipoe/backup.c
new file mode 100644
index 00000000..b2d0c0c4
--- /dev/null
+++ b/accel-pppd/ctrl/ipoe/backup.c
@@ -0,0 +1,168 @@
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <net/ethernet.h>
+
+#include "log.h"
+#include "memdebug.h"
+
+#include "ipoe.h"
+#include "backup.h"
+#include "ap_session_backup.h"
+
+#define IPOE_TAG_HWADDR 1
+#define IPOE_TAG_CLIENT_ID 2
+#define IPOE_TAG_AGENT_CIRCUIT_ID 3
+#define IPOE_TAG_AGENT_REMOTE_ID 4
+#define IPOE_TAG_XID 5
+#define IPOE_TAG_GIADDR 6
+#define IPOE_TAG_CALLING_SID 7
+#define IPOE_TAG_CALLED_SID 8
+#define IPOE_TAG_IFNAME 9
+
+#define IPOE_TAG_IFINDEX 100
+
+
+#define add_tag(id, data, size) if (!backup_add_tag(m, id, 0, data, size)) return -1;
+#define add_tag_int(id, data, size) if (!backup_add_tag(m, id, 1, data, size)) return -1;
+
+static int session_save(struct ap_session *ses, struct backup_mod *m)
+{
+ struct ipoe_session *conn = container_of(ses, typeof(*conn), ses);
+
+ add_tag(IPOE_TAG_HWADDR, conn->hwaddr, 6);
+ add_tag(IPOE_TAG_CALLING_SID, ses->ctrl->calling_station_id, strlen(ses->ctrl->calling_station_id));
+ add_tag(IPOE_TAG_CALLED_SID, ses->ctrl->called_station_id, strlen(ses->ctrl->called_station_id));
+ add_tag(IPOE_TAG_XID, &conn->xid, 4);
+ add_tag(IPOE_TAG_GIADDR, &conn->giaddr, 4);
+
+ if (conn->client_id)
+ add_tag(IPOE_TAG_CLIENT_ID, conn->client_id->data, conn->client_id->len);
+ if (conn->agent_circuit_id)
+ add_tag(IPOE_TAG_AGENT_CIRCUIT_ID, conn->agent_circuit_id->data, conn->agent_circuit_id->len);
+ if (conn->agent_circuit_id)
+ add_tag(IPOE_TAG_AGENT_REMOTE_ID, conn->agent_remote_id->data, conn->agent_remote_id->len);
+
+ //add_tag_int(IPOE_TAG_IFNAME, conn->serv->ifname, strlen(conn->serv->ifname) + 1);
+ add_tag(IPOE_TAG_IFNAME, conn->serv->ifname, strlen(conn->serv->ifname) + 1);
+
+ return 0;
+}
+
+static int session_restore(struct ap_session *ses, struct backup_mod *m)
+{
+ struct ipoe_session *conn = container_of(ses, typeof(*conn), ses);
+
+
+ return 0;
+}
+
+static void set_dhcpv4_opt(struct dhcp_opt **opt, struct backup_tag *t, uint8_t **ptr)
+{
+ *opt = (struct dhcp_opt *)(*ptr);
+ (*opt)->len = t->size;
+ memcpy((*opt)->data, t->data, t->size);
+ (*ptr) += sizeof(**opt) + t->size;
+}
+
+static struct ap_session *ctrl_restore(struct backup_mod *m)
+{
+ struct backup_tag *t;
+ struct ipoe_session *ses;
+ struct ipoe_serv *serv;
+ struct backup_tag *ifname = NULL;
+ int dlen = 0;
+ uint8_t *ptr;
+
+ //if (!m->data->internal)
+ // return NULL;
+
+ list_for_each_entry(t, &m->tag_list, entry) {
+ switch(t->id) {
+ case IPOE_TAG_CLIENT_ID:
+ case IPOE_TAG_AGENT_CIRCUIT_ID:
+ case IPOE_TAG_AGENT_REMOTE_ID:
+ dlen += sizeof(struct dhcp_opt) + t->size;
+ break;
+ case IPOE_TAG_IFNAME:
+ ifname = t;
+ break;
+ }
+ }
+
+ if (!ifname)
+ return NULL;
+
+ serv = ipoe_find_serv((char *)ifname->data);
+ if (!serv)
+ return NULL;
+
+ ses = ipoe_session_alloc();
+ if (!ses)
+ return NULL;
+
+ if (dlen)
+ ses->data = _malloc(dlen);
+
+ ptr = ses->data;
+
+ list_for_each_entry(t, &m->tag_list, entry) {
+ switch(t->id) {
+ case IPOE_TAG_HWADDR:
+ memcpy(ses->hwaddr, t->data, 6);
+ break;
+ case IPOE_TAG_CALLING_SID:
+ ses->ctrl.calling_station_id = _malloc(t->size + 1);
+ memcpy(ses->ctrl.calling_station_id, t->data, t->size);
+ ses->ctrl.calling_station_id[t->size] = 0;
+ break;
+ case IPOE_TAG_CALLED_SID:
+ ses->ctrl.called_station_id = _malloc(t->size + 1);
+ memcpy(ses->ctrl.called_station_id, t->data, t->size);
+ ses->ctrl.called_station_id[t->size] = 0;
+ break;
+ case IPOE_TAG_XID:
+ ses->xid = *(uint32_t *)t->data;
+ break;
+ case IPOE_TAG_GIADDR:
+ ses->giaddr = *(uint32_t *)t->data;
+ break;
+ case IPOE_TAG_CLIENT_ID:
+ set_dhcpv4_opt(&ses->client_id, t, &ptr);
+ break;
+ case IPOE_TAG_AGENT_CIRCUIT_ID:
+ set_dhcpv4_opt(&ses->agent_circuit_id, t, &ptr);
+ break;
+ case IPOE_TAG_AGENT_REMOTE_ID:
+ set_dhcpv4_opt(&ses->agent_remote_id, t, &ptr);
+ break;
+ }
+ }
+
+ ses->serv = serv;
+
+ triton_context_register(&ses->ctx, &ses->ses);
+ triton_context_wakeup(&ses->ctx);
+
+ pthread_mutex_lock(&serv->lock);
+ list_add_tail(&ses->entry, &serv->sessions);
+ pthread_mutex_unlock(&serv->lock);
+
+ return &ses->ses;
+}
+
+static struct backup_module mod = {
+ .id = MODID_IPOE,
+ .save = session_save,
+ .restore = session_restore,
+ .ctrl_restore = ctrl_restore,
+};
+
+static void init(void)
+{
+ backup_register_module(&mod);
+}
+
+DEFINE_INIT(100, init);
+
diff --git a/accel-pppd/ctrl/ipoe/ipoe.c b/accel-pppd/ctrl/ipoe/ipoe.c
index 5878b0c4..fea61a8b 100644
--- a/accel-pppd/ctrl/ipoe/ipoe.c
+++ b/accel-pppd/ctrl/ipoe/ipoe.c
@@ -73,6 +73,7 @@ struct iplink_arg
static void ipoe_session_finished(struct ap_session *s);
static void ipoe_drop_sessions(struct ipoe_serv *serv, struct ipoe_session *skip);
+static void ipoe_serv_close(struct triton_context_t *ctx);
static struct ipoe_session *ipoe_session_lookup(struct ipoe_serv *serv, struct dhcpv4_packet *pack)
{
@@ -321,13 +322,18 @@ static void ipoe_session_free(struct ipoe_session *ses)
static void ipoe_session_finished(struct ap_session *s)
{
struct ipoe_session *ses = container_of(s, typeof(*ses), ses);
+ int serv_close;
log_ppp_debug("ipoe: session finished\n");
pthread_mutex_lock(&ses->serv->lock);
list_del(&ses->entry);
+ serv_close = ses->serv->need_close && list_empty(&ses->serv->sessions);
pthread_mutex_unlock(&ses->serv->lock);
+ if (serv_close)
+ ipoe_serv_close(&ses->serv->ctx);
+
triton_context_call(&ses->ctx, (triton_event_func)ipoe_session_free, ses);
}
@@ -590,6 +596,37 @@ static struct ipoe_session *ipoe_session_create_up(struct ipoe_serv *serv, struc
return ses;
}
+struct ipoe_session *ipoe_session_alloc(void)
+{
+ struct ipoe_session *ses;
+
+ ses = mempool_alloc(ses_pool);
+ if (!ses) {
+ log_emerg("out of memery\n");
+ return NULL;
+ }
+
+ memset(ses, 0, sizeof(*ses));
+
+ ap_session_init(&ses->ses);
+
+ ses->ifindex = -1;
+
+ ses->ctx.before_switch = log_switch;
+ ses->ctx.close = ipoe_session_close;
+ ses->ctrl.ctx = &ses->ctx;
+ ses->ctrl.started = ipoe_session_started;
+ ses->ctrl.finished = ipoe_session_finished;
+ ses->ctrl.terminate = ipoe_session_terminate;
+ ses->ctrl.type = CTRL_TYPE_IPOE;
+ ses->ctrl.name = "ipoe";
+
+ ses->ses.ctrl = &ses->ctrl;
+ ses->ses.chan_name = ses->ctrl.calling_station_id;
+
+ return ses;
+}
+
void ipoe_recv_up(int ifindex, struct ethhdr *eth, struct iphdr *iph)
{
struct ipoe_serv *serv;
@@ -619,6 +656,14 @@ static void ipoe_serv_close(struct triton_context_t *ctx)
{
struct ipoe_serv *serv = container_of(ctx, typeof(*serv), ctx);
+ pthread_mutex_lock(&serv->lock);
+ if (!list_empty(&serv->sessions)) {
+ serv->need_close = 1;
+ pthread_mutex_unlock(&serv->lock);
+ return;
+ }
+ pthread_mutex_unlock(&serv->lock);
+
if (serv->dhcpv4)
dhcpv4_free(serv->dhcpv4);
@@ -663,6 +708,18 @@ static void ipoe_drop_sessions(struct ipoe_serv *serv, struct ipoe_session *skip
}
}
+struct ipoe_serv *ipoe_find_serv(const char *ifname)
+{
+ struct ipoe_serv *serv;
+
+ list_for_each_entry(serv, &serv_list, entry) {
+ if (strcmp(serv->ifname, ifname) == 0)
+ return serv;
+ }
+
+ return NULL;
+}
+
static void add_interface(const char *ifname, int ifindex, const char *opt)
{
char *str0, *str, *ptr1, *ptr2;
@@ -758,6 +815,7 @@ static void add_interface(const char *ifname, int ifindex, const char *opt)
serv = _malloc(sizeof(*serv));
memset(serv, 0, sizeof(*serv));
+ serv->ctx.close = ipoe_serv_close;
serv->ifname = _strdup(ifname);
serv->ifindex = ifindex;
serv->opt_shared = opt_shared;
@@ -873,6 +931,7 @@ static void load_interfaces(struct conf_sect_t *sect)
list_for_each_safe(pos, n, &serv_list) {
serv = list_entry(pos, typeof(*serv), entry);
if (!serv->active) {
+ ipoe_drop_sessions(serv, NULL);
list_del(&serv->entry);
triton_context_call(&serv->ctx, (triton_event_func)ipoe_serv_close, &serv->ctx);
}
diff --git a/accel-pppd/ctrl/ipoe/ipoe.h b/accel-pppd/ctrl/ipoe/ipoe.h
index 97b13e63..a2efd374 100644
--- a/accel-pppd/ctrl/ipoe/ipoe.h
+++ b/accel-pppd/ctrl/ipoe/ipoe.h
@@ -22,6 +22,7 @@ struct ipoe_serv
int opt_shared:1;
int opt_dhcpv4:1;
int opt_up:1;
+ int need_close:1;
};
struct dhcp_opt
@@ -57,6 +58,9 @@ struct iphdr;
struct ethhdr;
void ipoe_recv_up(int ifindex, struct ethhdr *eth, struct iphdr *iph);
+struct ipoe_session *ipoe_session_alloc(void);
+
+struct ipoe_serv *ipoe_find_serv(const char *ifname);
void ipoe_nl_add_net(uint32_t addr, int mask);
void ipoe_nl_delete_nets(void);
diff --git a/accel-pppd/ctrl/ipoe/ipoe_netlink.c b/accel-pppd/ctrl/ipoe/ipoe_netlink.c
index ec603d5d..525dc0b3 100644
--- a/accel-pppd/ctrl/ipoe/ipoe_netlink.c
+++ b/accel-pppd/ctrl/ipoe/ipoe_netlink.c
@@ -364,7 +364,6 @@ static int ipoe_up_read(struct triton_md_handler_t *h)
static void ipoe_up_close(struct triton_context_t *ctx)
{
- rtnl_close(&rth);
triton_md_unregister_handler(&up_hnd);
triton_context_unregister(ctx);
}