summaryrefslogtreecommitdiff
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
parent64b5b693764c4f36870fd988ccbb53bcb188e74d (diff)
downloadaccel-ppp-xebd-80c32d237e01b1c05663ccfa34003d2f49aa7eee.tar.gz
accel-ppp-xebd-80c32d237e01b1c05663ccfa34003d2f49aa7eee.zip
initial session backup implementation
-rw-r--r--CMakeLists.txt2
-rw-r--r--accel-pppd/CMakeLists.txt8
-rw-r--r--accel-pppd/backup/CMakeLists.txt4
-rw-r--r--accel-pppd/backup/backup.c245
-rw-r--r--accel-pppd/backup/backup.h94
-rw-r--r--accel-pppd/backup/backup_file.c351
-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
-rw-r--r--accel-pppd/extra/ippool.c102
-rw-r--r--accel-pppd/ifcfg.c159
-rw-r--r--accel-pppd/include/ap_session.h6
-rw-r--r--accel-pppd/include/ap_session_backup.h23
l---------accel-pppd/include/backup.h1
-rw-r--r--accel-pppd/main.c177
-rw-r--r--accel-pppd/radius/CMakeLists.txt4
-rw-r--r--accel-pppd/radius/acct.c112
-rw-r--r--accel-pppd/radius/backup.c163
-rw-r--r--accel-pppd/radius/radius.c17
-rw-r--r--accel-pppd/radius/radius_p.h5
-rw-r--r--accel-pppd/radius/req.c29
-rw-r--r--accel-pppd/radius/serv.c26
-rw-r--r--accel-pppd/session.c33
-rw-r--r--accel-pppd/session_backup.c136
-rw-r--r--ipoe-util/CMakeLists.txt22
l---------ipoe-util/ipoe.h1
-rw-r--r--ipoe-util/ipses-add-net.c64
-rw-r--r--ipoe-util/ipses-create.c71
-rw-r--r--ipoe-util/ipses-delete.c58
31 files changed, 1770 insertions, 379 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f358ce3..8bcaf1a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -38,6 +38,4 @@ endif (BUILD_DRIVER OR BUILD_DRIVER_ONLY)
if (BUILD_IPOE_DRIVER)
add_subdirectory(drivers/ipoe)
- add_subdirectory(ipoe-util)
-
endif (BUILD_IPOE_DRIVER)
diff --git a/accel-pppd/CMakeLists.txt b/accel-pppd/CMakeLists.txt
index c50dc58..777d7e5 100644
--- a/accel-pppd/CMakeLists.txt
+++ b/accel-pppd/CMakeLists.txt
@@ -24,6 +24,11 @@ IF (MEMDEBUG)
ENDIF (VALGRIND)
ENDIF (MEMDEBUG)
+IF (BACKUP)
+ ADD_DEFINITIONS(-DUSE_BACKUP)
+ ADD_SUBDIRECTORY(backup)
+ENDIF (BACKUP)
+
IF (NOT DEFINED RADIUS)
SET(RADIUS TRUE)
ENDIF (NOT DEFINED RADIUS)
@@ -43,8 +48,11 @@ ADD_SUBDIRECTORY(shaper)
ADD_EXECUTABLE(accel-pppd
session.c
+ session_backup.c
ifcfg.c
+ backup/backup.c
+
ppp/ppp.c
ppp/ppp_fsm.c
ppp/ppp_lcp.c
diff --git a/accel-pppd/backup/CMakeLists.txt b/accel-pppd/backup/CMakeLists.txt
new file mode 100644
index 0000000..77fefab
--- /dev/null
+++ b/accel-pppd/backup/CMakeLists.txt
@@ -0,0 +1,4 @@
+ADD_LIBRARY(backup_file SHARED backup_file.c)
+
+INSTALL(TARGETS backup_file LIBRARY DESTINATION lib/accel-ppp)
+
diff --git a/accel-pppd/backup/backup.c b/accel-pppd/backup/backup.c
new file mode 100644
index 0000000..d045f0c
--- /dev/null
+++ b/accel-pppd/backup/backup.c
@@ -0,0 +1,245 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "triton.h"
+#include "events.h"
+#include "ap_session.h"
+#include "backup.h"
+
+#ifdef USE_BACKUP
+
+static LIST_HEAD(storage_list);
+static LIST_HEAD(module_list);
+
+struct backup_tag __export *backup_add_tag(struct backup_mod *m, uint8_t id, int internal, const void *data, size_t size)
+{
+ struct backup_tag *t;
+
+ t = m->data->storage->alloc_tag(m->data, size);
+ if (!t)
+ return NULL;
+
+ t->id = id;
+ t->internal = internal;
+ t->size = size;
+ memcpy(t->data, data, size);
+
+ list_add_tail(&t->entry, &m->tag_list);
+
+ return t;
+}
+
+void backup_add_fd(struct backup_mod *m, int fd)
+{
+ if (m->data->storage->add_fd)
+ m->data->storage->add_fd(m->data, fd);
+}
+
+struct backup_mod __export *backup_find_mod(struct backup_data *d, uint8_t mod_id)
+{
+ struct backup_mod *m;
+
+ list_for_each_entry(m, &d->mod_list, entry) {
+ if (m->id == mod_id)
+ return m;
+ }
+
+ return NULL;
+}
+
+struct backup_tag __export *backup_find_tag(struct backup_data *d, uint8_t mod_id, uint8_t tag_id, int internal)
+{
+ struct backup_mod *m = backup_find_mod(d, mod_id);
+ struct backup_tag *t;
+
+ if (!m)
+ return NULL;
+
+ list_for_each_entry(t, &m->tag_list, entry) {
+ if (t->id == tag_id && t->internal == internal)
+ return t;
+ }
+
+ return NULL;
+}
+
+void __export backup_free(struct backup_data *data)
+{
+ struct backup_mod *m;
+ struct backup_tag *t;
+
+ while (!list_empty(&data->mod_list)) {
+ m = list_entry(data->mod_list.next, typeof(*m), entry);
+ while (!list_empty(&m->tag_list)) {
+ t = list_entry(m->tag_list.next, typeof(*t), entry);
+ list_del(&t->entry);
+ data->storage->free_tag(data, t);
+ }
+ list_del(&m->entry);
+ data->storage->free_mod(m);
+ }
+ data->storage->free(data);
+}
+
+int __export backup_save_session(struct ap_session *ses)
+{
+ struct backup_storage *storage;
+ struct backup_module *module;
+ struct backup_data *d;
+ struct backup_mod *m;
+ int r, f1 = 0, f2;
+
+ list_for_each_entry(storage, &storage_list, entry) {
+ d = storage->create(ses);
+ if (!d)
+ continue;
+
+ //d->ses = ses;
+
+ f2 = 0;
+
+ list_for_each_entry(module, &module_list, entry) {
+ if (!module->save)
+ continue;
+
+ m = storage->alloc_mod(d);
+ if (!m) {
+ f2 = 1;
+ break;
+ }
+
+ m->data = d;
+ m->id = module->id;
+ r = module->save(ses, m);
+ if (r == -2) {
+ storage->free_mod(m);
+ continue;
+ }
+
+ list_add_tail(&m->entry, &d->mod_list);
+
+ if (r == -1) {
+ f2 = 1;
+ break;
+ }
+ }
+
+ if (f2)
+ backup_free(d);
+ else {
+ f1 = 1;
+ if (storage->commit)
+ storage->commit(d);
+ ses->backup = d;
+ }
+ }
+
+ return !f1;
+}
+
+/*int backup_restore_internal(void)
+{
+ struct backup_storage *storage;
+
+ list_for_each_entry(storage, &storage_list, entry) {
+ if (storage->restore_internal) {
+ if (storage->check_integrity())
+ continue;
+ storage->restore_internal();
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+void backup_restore_external(void)
+{
+ struct backup_storage *storage;
+
+ list_for_each_entry(storage, &storage_list, entry) {
+ if (storage->restore_external) {
+ if (storage->check_integrity())
+ continue;
+ storage->restore_external();
+ return;
+ }
+ }
+}*/
+
+static void __restore_session(struct ap_session *ses)
+{
+ struct backup_module *module;
+ struct backup_mod *m;
+ struct backup_module *ctrl = NULL;
+
+ list_for_each_entry(module, &module_list, entry) {
+ if (module->ctrl_start)
+ ctrl = module;
+ if (module->restore) {
+ m = backup_find_mod(ses->backup, module->id);
+ if (!m)
+ continue;
+ module->restore(ses, m);
+ }
+ }
+
+ if (ctrl)
+ ctrl->ctrl_start(ses);
+ else {
+ triton_event_fire(EV_CTRL_STARTING, ses);
+ triton_event_fire(EV_CTRL_STARTED, ses);
+
+ ap_session_starting(ses);
+ ap_session_activate(ses);
+ }
+}
+
+void __export backup_restore_session(struct backup_data *d)
+{
+ struct backup_module *module;
+ struct backup_mod *m;
+ struct ap_session *ses;
+
+ list_for_each_entry(module, &module_list, entry) {
+ if (module->ctrl_restore) {
+ m = backup_find_mod(d, module->id);
+ if (!m)
+ continue;
+ ses = module->ctrl_restore(m);
+ ses->backup = d;
+ d->ses = ses;
+ ses->state = AP_STATE_RESTORE;
+ triton_context_call(ses->ctrl->ctx, (triton_event_func)__restore_session, ses);
+ break;
+ }
+ }
+}
+
+
+void __export backup_register_module(struct backup_module *m)
+{
+ list_add_tail(&m->entry, &module_list);
+}
+
+void __export backup_register_storage(struct backup_storage *s)
+{
+ list_add_tail(&s->entry, &storage_list);
+}
+
+void backup_restore_fd()
+{
+
+}
+
+void backup_restore(int internal)
+{
+ struct backup_storage *storage;
+
+ list_for_each_entry(storage, &storage_list, entry) {
+ if (storage->restore)
+ storage->restore(internal);
+ }
+}
+
+#endif
diff --git a/accel-pppd/backup/backup.h b/accel-pppd/backup/backup.h
new file mode 100644
index 0000000..39c4ed7
--- /dev/null
+++ b/accel-pppd/backup/backup.h
@@ -0,0 +1,94 @@
+#ifndef __BACKUP_H
+#define __BACKUP_H
+
+#include <stdint.h>
+#include "list.h"
+
+#define MODID_COMMON 1
+#define MODID_RADIUS 2
+#define MODID_PPPOE 3
+#define MODID_IPOE 4
+#define MODID_PPTP 5
+#define MODID_L2TP 6
+#define MODID_IPPOOL 7
+
+
+struct ap_session;
+struct backup_storage;
+struct backup_data;
+
+struct backup_tag
+{
+ struct list_head entry;
+ uint16_t internal:1;
+ uint8_t id;
+ uint16_t size;
+ uint8_t *data;
+};
+
+struct backup_mod
+{
+ struct backup_data *data;
+ struct list_head entry;
+ int id;
+ struct list_head tag_list;
+};
+
+struct backup_data
+{
+ struct ap_session *ses;
+ struct backup_storage *storage;
+ struct list_head mod_list;
+ int internal:1;
+};
+
+struct backup_module
+{
+ struct list_head entry;
+ int id;
+
+ int (*save)(struct ap_session *, struct backup_mod *);
+ int (*restore)(struct ap_session *, struct backup_mod *);
+
+ struct ap_session *(*ctrl_restore)(struct backup_mod *);
+ void (*ctrl_start)(struct ap_session *ses);
+};
+
+struct backup_storage
+{
+ struct list_head entry;
+
+ /*int (*check_integrity)(void);
+ int (*restore)(int internal);*/
+
+ void (*restore)(int internal);
+
+ struct backup_data *(*create)(struct ap_session *);
+ int (*commit)(struct backup_data *);
+ void (*free)(struct backup_data *);
+
+ struct backup_mod *(*alloc_mod)(struct backup_data *);
+ void (*free_mod)(struct backup_mod *);
+
+ void (*add_fd)(struct backup_data *, int fd);
+
+ struct backup_tag *(*alloc_tag)(struct backup_data *, int size);
+ void (*free_tag)(struct backup_data *, struct backup_tag *);
+};
+
+void backup_register_module(struct backup_module *);
+void backup_register_storage(struct backup_storage *);
+
+int backup_save_session(struct ap_session *ses);
+void backup_restore_session(struct backup_data *d);
+
+struct backup_mod *backup_find_mod(struct backup_data *d, uint8_t mod_id);
+struct backup_tag *backup_find_tag(struct backup_data *d, uint8_t mod_id, uint8_t tag_id, int internal);
+struct backup_tag *backup_add_tag(struct backup_mod *m, uint8_t id, int internal, const void *data, size_t size);
+void backup_add_fd(struct backup_mod *m, int fd);
+
+void backup_restore(int internal);
+void backup_restore_fd();
+
+#endif
+
diff --git a/accel-pppd/backup/backup_file.c b/accel-pppd/backup/backup_file.c
new file mode 100644
index 0000000..b9d2646
--- /dev/null
+++ b/accel-pppd/backup/backup_file.c
@@ -0,0 +1,351 @@
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+#include <sys/mman.h>
+
+#include "triton.h"
+#include "log.h"
+#include "ap_session.h"
+#include "backup.h"
+#include "crypto.h"
+#include "memdebug.h"
+
+#define VERSION 1
+
+struct fs_backup_data
+{
+ struct list_head fd_list;
+ int fd;
+ void *map_addr;
+ int map_len;
+ char sessionid[AP_SESSIONID_LEN];
+ struct backup_data data;
+};
+
+static char *conf_path;
+
+static struct backup_storage file_storage;
+
+static struct backup_data *fs_create(struct ap_session *ses)
+{
+ struct fs_backup_data *d = _malloc(sizeof(*d));
+
+ if (!d)
+ return NULL;
+
+ memset(d, 0, sizeof(*d));
+ d->fd = -1;
+ INIT_LIST_HEAD(&d->fd_list);
+ INIT_LIST_HEAD(&d->data.mod_list);
+ d->data.ses = ses;
+ d->data.storage = &file_storage;
+
+ return &d->data;
+}
+
+static int fs_commit(struct backup_data *d)
+{
+ char fname[PATH_MAX];
+ int fd;
+ struct backup_mod *mod;
+ struct backup_tag *tag;
+ struct iovec iov[IOV_MAX];
+ int i, len, n;
+ MD5_CTX md5;
+ unsigned char md5_buf[16];
+ uint8_t end[4] = {0, 0, 0, 0};
+ uint8_t version = VERSION;
+ uint8_t *ptr;
+
+ if (!conf_path)
+ return -1;
+
+ sprintf(fname, "%s/%s", conf_path, d->ses->sessionid);
+
+ fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE);
+
+ if (fd < 0) {
+ log_error("backup: can not create file '%s': %s\n", fname, strerror(errno));
+ return -1;
+ }
+
+ MD5_Init(&md5);
+ MD5_Update(&md5, &version, 1);
+
+ iov[0].iov_base = &version;
+ iov[0].iov_len = 1;
+ i = 1;
+ len = 1;
+
+ list_for_each_entry(mod, &d->mod_list, entry) {
+ MD5_Update(&md5, &mod->id, 1);
+ iov[i].iov_base = &mod->id;
+ iov[i].iov_len = 1;
+ i++;
+ len++;
+
+ list_for_each_entry(tag, &mod->tag_list, entry) {
+ ptr = (uint8_t *)(tag + 1);
+ *ptr = tag->id; ptr++;
+ *ptr = tag->internal ? 1 : 0; ptr++;
+ *(uint16_t *)ptr = tag->size;
+ MD5_Update(&md5, tag + 1, 4 + tag->size);
+ iov[i].iov_base = tag + 1;
+ iov[i].iov_len = 4 + tag->size;
+ i++;
+ len += 4 + tag->size;
+ if (i == IOV_MAX - 2) {
+ n = writev(fd, iov, i);
+ if (n < len) {
+ log_error("backup: short write %i/%i\n", n, len);
+ goto out_err;
+ }
+ i = 0;
+ len = 0;
+ }
+ }
+
+ MD5_Update(&md5, end, 4);
+ iov[i].iov_base = end;
+ iov[i].iov_len = 4;
+ i++;
+ len += 4;
+ }
+
+ MD5_Final(md5_buf, &md5);
+
+ iov[i].iov_base = md5_buf;
+ iov[i].iov_len = 16;
+ len += 16;
+
+ n = writev(fd, iov, i + 1);
+ if (n < len) {
+ log_error("backup: short write %i/%i\n", n, len);
+ goto out_err;
+ }
+
+ close(fd);
+
+ while (!list_empty(&d->mod_list)) {
+ mod = list_entry(d->mod_list.next, typeof(*mod), entry);
+ list_del(&mod->entry);
+ while (!list_empty(&mod->tag_list)) {
+ tag = list_entry(mod->tag_list.next, typeof(*tag), entry);
+ list_del(&tag->entry);
+ _free(tag);
+ }
+ _free(mod);
+ }
+
+ return 0;
+
+out_err:
+ close(fd);
+ unlink(fname);
+ return -1;
+}
+
+static void fs_free(struct backup_data *d)
+{
+ struct fs_backup_data *fsd = container_of(d, typeof(*fsd), data);
+ char fname[PATH_MAX];
+
+ if (fsd->map_addr)
+ munmap(fsd->map_addr, fsd->map_len);
+
+ if (fsd->fd != -1)
+ close(fsd->fd);
+
+ sprintf(fname, "%s/%s", conf_path, d->ses->sessionid);
+ unlink(fname);
+
+ _free(fsd);
+}
+
+static struct backup_mod *fs_alloc_mod(struct backup_data *d)
+{
+ struct backup_mod *m = _malloc(sizeof(struct backup_mod));
+
+ if (!m)
+ return NULL;
+
+ memset(m, 0, sizeof(*m));
+ INIT_LIST_HEAD(&m->tag_list);
+
+ return m;
+}
+
+static void fs_free_mod(struct backup_mod *mod)
+{
+ _free(mod);
+}
+
+static struct backup_tag *fs_alloc_tag(struct backup_data *d, int size)
+{
+ struct backup_tag *t = _malloc(sizeof(struct backup_tag) + 4 + size);
+
+ if (!t)
+ return NULL;
+
+ memset(t, 0, sizeof(*t));
+
+ t->data = (uint8_t *)(t + 1) + 4;
+
+ return t;
+}
+
+static void fs_free_tag(struct backup_data *d, struct backup_tag *tag)
+{
+ _free(tag);
+}
+
+static void fs_add_fd(struct backup_data *d, int fd)
+{
+
+}
+
+static void restore_session(const char *fn, int internal)
+{
+ char fname[PATH_MAX];
+ int fd;
+ struct stat st;
+ uint8_t *ptr, *endptr;
+ MD5_CTX md5;
+ unsigned char md5_buf[16];
+ struct backup_data *d;
+ struct fs_backup_data *fsd;
+ struct backup_mod *mod;
+ struct backup_tag *tag;
+
+ sprintf(fname, "%s/%s", conf_path, fn);
+
+ fd = open(fname, O_RDONLY);
+ if (fd < 0) {
+ log_emerg("backup_file: open '%s': %s\n", fname, strerror(errno));
+ return;
+ }
+
+ fstat(fd, &st);
+
+ ptr = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
+ if (ptr == MAP_FAILED) {
+ log_emerg("backup_file: mmap '%s': %s\n", fname, strerror(errno));
+ close(fd);
+ return;
+ }
+
+ if (*ptr != VERSION)
+ goto out;
+
+ MD5_Init(&md5);
+ MD5_Update(&md5, ptr, st.st_size - 16);
+ MD5_Final(md5_buf, &md5);
+
+ if (memcmp(md5_buf, ptr + st.st_size - 16, 16))
+ goto out;
+
+ d = fs_create(NULL);
+ if (!d)
+ goto out;
+
+ d->internal = internal;
+
+ fsd = container_of(d, typeof(*fsd), data);
+ fsd->fd = fd;
+ fsd->map_addr = ptr;
+ fsd->map_len = st.st_size;
+
+ endptr = ptr + st.st_size - 16;
+ ptr++;
+
+ while (ptr < endptr) {
+ mod = fs_alloc_mod(d);
+ list_add_tail(&mod->entry, &d->mod_list);
+ mod->data = d;
+ mod->id = *ptr; ptr++;
+ while (ptr < endptr) {
+ if (*(uint8_t *)ptr == 0) {
+ ptr += 4;
+ break;
+ }
+
+ if (!internal && ptr[1]) {
+ ptr += 4 + *(uint16_t *)(ptr + 2);
+ continue;
+ }
+
+ tag = fs_alloc_tag(d, 0);
+ tag->id = *ptr; ptr++;
+ tag->internal = (*ptr & 0x01) ? 1 : 0; ptr ++;
+ tag->size = *(uint16_t *)ptr; ptr += 2;
+ tag->data = ptr; ptr += tag->size;
+
+ list_add_tail(&tag->entry, &mod->tag_list);
+ }
+ }
+
+ backup_restore_session(d);
+
+ return;
+
+out:
+ munmap(ptr, st.st_size);
+ close(fd);
+}
+
+static void fs_restore(int internal)
+{
+ DIR *dirp;
+ struct dirent ent, *res;
+
+ if (!conf_path)
+ return;
+
+ dirp = opendir(conf_path);
+ if (!dirp) {
+ log_emerg("backup_file: opendir: %s\n", strerror(errno));
+ return;
+ }
+
+ while (1) {
+ if (readdir_r(dirp, &ent, &res)) {
+ log_emerg("backup_file: readdir: %s\n", strerror(errno));
+ break;
+ }
+ if (!res)
+ break;
+ if (strcmp(ent.d_name, ".") == 0 || strcmp(ent.d_name, "..") == 0)
+ continue;
+ restore_session(ent.d_name, internal);
+ }
+
+ closedir(dirp);
+}
+
+static struct backup_storage file_storage = {
+ .create = fs_create,
+ .commit = fs_commit,
+ .free = fs_free,
+ .alloc_mod = fs_alloc_mod,
+ .free_mod = fs_free_mod,
+ .add_fd = fs_add_fd,
+ .alloc_tag = fs_alloc_tag,
+ .free_tag = fs_free_tag,
+ .restore = fs_restore,
+};
+
+static void init(void)
+{
+ conf_path = conf_get_opt("backup", "path");
+
+ backup_register_storage(&file_storage);
+}
+
+DEFINE_INIT(1000, init);
diff --git a/accel-pppd/ctrl/ipoe/CMakeLists.txt b/accel-pppd/ctrl/ipoe/CMakeLists.txt
index 297d81b..7be18cc 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 0000000..b2d0c0c
--- /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 5878b0c..fea61a8 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 97b13e6..a2efd37 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 ec603d5..525dc0b 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);
}
diff --git a/accel-pppd/extra/ippool.c b/accel-pppd/extra/ippool.c
index ab2dfb2..ccb3b2a 100644
--- a/accel-pppd/extra/ippool.c
+++ b/accel-pppd/extra/ippool.c
@@ -9,6 +9,8 @@
#include "ipdb.h"
#include "list.h"
#include "spinlock.h"
+#include "backup.h"
+#include "ap_session_backup.h"
#ifdef RADIUS
#include "radius.h"
@@ -23,6 +25,8 @@ struct ippool_t
struct list_head gw_list;
struct list_head tunnel_list;
struct list_head items;
+ uint32_t startip;
+ uint32_t endip;
spinlock_t lock;
};
@@ -143,7 +147,7 @@ static int parse2(const char *str, uint32_t *begin, uint32_t *end)
return 0;
}
-static void add_range(struct list_head *list, const char *name)
+static void add_range(struct ippool_t *p, struct list_head *list, const char *name)
{
uint32_t i,startip, endip;
struct ipaddr_t *ip;
@@ -161,6 +165,9 @@ static void add_range(struct list_head *list, const char *name)
list_add_tail(&ip->entry, list);
cnt++;
}
+
+ p->startip = startip;
+ p->endip = endip;
}
static void generate_pool(struct ippool_t *p)
@@ -243,6 +250,89 @@ static struct ipdb_t ipdb = {
.put_ipv4 = put_ip,
};
+#ifdef USE_BACKUP
+static void put_ip_b(struct ap_session *ses, struct ipv4db_item_t *it)
+{
+ _free(it);
+}
+
+static struct ipdb_t ipdb_b = {
+ .put_ipv4 = put_ip_b,
+};
+
+static int session_save(struct ap_session *ses, struct backup_mod *m)
+{
+ if (!ses->ipv4 || ses->ipv4->owner != &ipdb)
+ return -2;
+
+ return 0;
+}
+
+static int session_restore(struct ap_session *ses, struct backup_mod *m)
+{
+ struct backup_tag *tag;
+ in_addr_t addr = 0, peer_addr;
+ struct ippool_t *p;
+ struct ippool_item_t *it, *it0 = NULL;
+
+ m = backup_find_mod(m->data, MODID_COMMON);
+
+ list_for_each_entry(tag, &m->tag_list, entry) {
+ switch (tag->id) {
+ case SES_TAG_IPV4_ADDR:
+ addr = *(in_addr_t *)tag->data;
+ break;
+ case SES_TAG_IPV4_PEER_ADDR:
+ peer_addr = *(in_addr_t *)tag->data;
+ break;
+ }
+ }
+
+ spin_lock(&def_pool->lock);
+ list_for_each_entry(it, &def_pool->items, entry) {
+ if (peer_addr == it->it.peer_addr && addr == it->it.addr) {
+ list_del(&it->entry);
+ it0 = it;
+ break;
+ }
+ }
+ spin_unlock(&def_pool->lock);
+
+ if (!it0) {
+ list_for_each_entry(p, &pool_list, entry) {
+ spin_lock(&p->lock);
+ list_for_each_entry(it, &p->items, entry) {
+ if (peer_addr == it->it.peer_addr && addr == it->it.addr) {
+ list_del(&it->entry);
+ it0 = it;
+ break;
+ }
+ }
+ spin_unlock(&p->lock);
+ if (it0)
+ break;
+ }
+ }
+
+ if (it0)
+ ses->ipv4 = &it0->it;
+ else {
+ ses->ipv4 = _malloc(sizeof(*ses->ipv4));
+ ses->ipv4->addr = addr;
+ ses->ipv4->peer_addr = peer_addr;
+ ses->ipv4->owner = &ipdb_b;
+ }
+
+ return 0;
+}
+
+static struct backup_module backup_mod = {
+ .id = MODID_IPPOOL,
+ .save = session_save,
+ .restore = session_restore,
+};
+#endif
+
#ifdef RADIUS
static int parse_attr(struct ap_session *ses, struct rad_attr_t *attr)
{
@@ -348,11 +438,11 @@ static void ippool_init(void)
p = pool_name ? find_pool(pool_name + 1, 1) : def_pool;
if (!strcmp(opt->name, "gw"))
- add_range(&p->gw_list, opt->val);
+ add_range(p, &p->gw_list, opt->val);
else if (!strcmp(opt->name, "tunnel"))
- add_range(&p->tunnel_list, opt->val);
+ add_range(p, &p->tunnel_list, opt->val);
else if (!opt->val)
- add_range(&p->tunnel_list, opt->name);
+ add_range(p, &p->tunnel_list, opt->name);
}
}
@@ -363,6 +453,10 @@ static void ippool_init(void)
ipdb_register(&ipdb);
+#ifdef USE_BACKUP
+ backup_register_module(&backup_mod);
+#endif
+
#ifdef RADIUS
if (triton_module_loaded("radius"))
triton_event_register_handler(EV_RADIUS_ACCESS_ACCEPT, (triton_event_func)ev_radius_access_accept);
diff --git a/accel-pppd/ifcfg.c b/accel-pppd/ifcfg.c
index 134edfb..7399a60 100644
--- a/accel-pppd/ifcfg.c
+++ b/accel-pppd/ifcfg.c
@@ -17,6 +17,7 @@
#include "ppp.h"
#include "ipdb.h"
#include "log.h"
+#include "backup.h"
// from /usr/include/linux/ipv6.h
struct in6_ifreq {
@@ -56,7 +57,7 @@ void ap_session_ifup(struct ap_session *ses)
{
struct ipv6db_addr_t *a;
struct ifreq ifr;
- struct rtentry rt;
+ //struct rtentry rt;
struct in6_ifreq ifr6;
struct npioctl np;
struct sockaddr_in addr;
@@ -72,96 +73,102 @@ void ap_session_ifup(struct ap_session *ses)
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, ses->ifname);
-
- if (ses->ipv4) {
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = ses->ipv4->addr;
- memcpy(&ifr.ifr_addr, &addr, sizeof(addr));
-
- if (ioctl(sock_fd, SIOCSIFADDR, &ifr))
- log_ppp_error("failed to set IPv4 address: %s\n", strerror(errno));
-
- /*if (ses->ctrl->type == CTRL_TYPE_IPOE) {
- addr.sin_addr.s_addr = 0xffffffff;
- memcpy(&ifr.ifr_netmask, &addr, sizeof(addr));
- if (ioctl(sock_fd, SIOCSIFNETMASK, &ifr))
- log_ppp_error("failed to set IPv4 nask: %s\n", strerror(errno));
- }*/
+
+#ifdef USE_BACKUP
+ if (!ses->backup || !ses->backup->internal) {
+#endif
+ if (ses->ipv4) {
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = ses->ipv4->addr;
+ memcpy(&ifr.ifr_addr, &addr, sizeof(addr));
+
+ if (ioctl(sock_fd, SIOCSIFADDR, &ifr))
+ log_ppp_error("failed to set IPv4 address: %s\n", strerror(errno));
- addr.sin_addr.s_addr = ses->ipv4->peer_addr;
-
- /*if (ses->ctrl->type == CTRL_TYPE_IPOE) {
- memset(&rt, 0, sizeof(rt));
- memcpy(&rt.rt_dst, &addr, sizeof(addr));
- rt.rt_flags = RTF_HOST | RTF_UP;
- rt.rt_metric = 1;
- rt.rt_dev = ifr.ifr_name;
- if (ioctl(sock_fd, SIOCADDRT, &rt, sizeof(rt)))
- log_ppp_error("failed to add route: %s\n", strerror(errno));
- } else*/ {
- memcpy(&ifr.ifr_dstaddr, &addr, sizeof(addr));
+ /*if (ses->ctrl->type == CTRL_TYPE_IPOE) {
+ addr.sin_addr.s_addr = 0xffffffff;
+ memcpy(&ifr.ifr_netmask, &addr, sizeof(addr));
+ if (ioctl(sock_fd, SIOCSIFNETMASK, &ifr))
+ log_ppp_error("failed to set IPv4 nask: %s\n", strerror(errno));
+ }*/
- if (ioctl(sock_fd, SIOCSIFDSTADDR, &ifr))
- log_ppp_error("failed to set peer IPv4 address: %s\n", strerror(errno));
+ addr.sin_addr.s_addr = ses->ipv4->peer_addr;
+
+ /*if (ses->ctrl->type == CTRL_TYPE_IPOE) {
+ memset(&rt, 0, sizeof(rt));
+ memcpy(&rt.rt_dst, &addr, sizeof(addr));
+ rt.rt_flags = RTF_HOST | RTF_UP;
+ rt.rt_metric = 1;
+ rt.rt_dev = ifr.ifr_name;
+ if (ioctl(sock_fd, SIOCADDRT, &rt, sizeof(rt)))
+ log_ppp_error("failed to add route: %s\n", strerror(errno));
+ } else*/ {
+ memcpy(&ifr.ifr_dstaddr, &addr, sizeof(addr));
+
+ if (ioctl(sock_fd, SIOCSIFDSTADDR, &ifr))
+ log_ppp_error("failed to set peer IPv4 address: %s\n", strerror(errno));
+ }
}
- }
-
- if (ses->ipv6) {
- devconf(ses, "accept_ra", "0");
- devconf(ses, "autoconf", "0");
- devconf(ses, "forwarding", "1");
- memset(&ifr6, 0, sizeof(ifr6));
-
- if (ses->ctrl->type != CTRL_TYPE_IPOE) {
- ifr6.ifr6_addr.s6_addr32[0] = htons(0xfe80);
- *(uint64_t *)(ifr6.ifr6_addr.s6_addr + 8) = ses->ipv6->intf_id;
- ifr6.ifr6_prefixlen = 64;
- ifr6.ifr6_ifindex = ses->ifindex;
+ if (ses->ipv6) {
+ devconf(ses, "accept_ra", "0");
+ devconf(ses, "autoconf", "0");
+ devconf(ses, "forwarding", "1");
- if (ioctl(sock6_fd, SIOCSIFADDR, &ifr6))
- log_ppp_error("faild to set LL IPv6 address: %s\n", strerror(errno));
- }
-
- list_for_each_entry(a, &ses->ipv6->addr_list, entry) {
- if (a->prefix_len == 128)
- continue;
+ memset(&ifr6, 0, sizeof(ifr6));
+
+ if (ses->ctrl->type != CTRL_TYPE_IPOE) {
+ ifr6.ifr6_addr.s6_addr32[0] = htons(0xfe80);
+ *(uint64_t *)(ifr6.ifr6_addr.s6_addr + 8) = ses->ipv6->intf_id;
+ ifr6.ifr6_prefixlen = 64;
+ ifr6.ifr6_ifindex = ses->ifindex;
+
+ if (ioctl(sock6_fd, SIOCSIFADDR, &ifr6))
+ log_ppp_error("faild to set LL IPv6 address: %s\n", strerror(errno));
+ }
+
+ list_for_each_entry(a, &ses->ipv6->addr_list, entry) {
+ if (a->prefix_len == 128)
+ continue;
- build_addr(a, ses->ipv6->intf_id, &ifr6.ifr6_addr);
- ifr6.ifr6_prefixlen = a->prefix_len;
+ build_addr(a, ses->ipv6->intf_id, &ifr6.ifr6_addr);
+ ifr6.ifr6_prefixlen = a->prefix_len;
- if (ioctl(sock6_fd, SIOCSIFADDR, &ifr6))
- log_ppp_error("failed to add IPv6 address: %s\n", strerror(errno));
+ if (ioctl(sock6_fd, SIOCSIFADDR, &ifr6))
+ log_ppp_error("failed to add IPv6 address: %s\n", strerror(errno));
+ }
}
- }
-
- if (ioctl(sock_fd, SIOCGIFFLAGS, &ifr))
- log_ppp_error("failed to get interface flags: %s\n", strerror(errno));
- ifr.ifr_flags |= IFF_UP;
+ if (ioctl(sock_fd, SIOCGIFFLAGS, &ifr))
+ log_ppp_error("failed to get interface flags: %s\n", strerror(errno));
- if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr))
- log_ppp_error("failed to set interface flags: %s\n", strerror(errno));
+ ifr.ifr_flags |= IFF_UP;
- if (ses->ctrl->type != CTRL_TYPE_IPOE) {
- ppp = container_of(ses, typeof(*ppp), ses);
- if (ses->ipv4) {
- np.protocol = PPP_IP;
- np.mode = NPMODE_PASS;
+ if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr))
+ log_ppp_error("failed to set interface flags: %s\n", strerror(errno));
- if (ioctl(ppp->unit_fd, PPPIOCSNPMODE, &np))
- log_ppp_error("failed to set NP (IPv4) mode: %s\n", strerror(errno));
- }
-
- if (ses->ipv6) {
- np.protocol = PPP_IPV6;
- np.mode = NPMODE_PASS;
+ if (ses->ctrl->type != CTRL_TYPE_IPOE) {
+ ppp = container_of(ses, typeof(*ppp), ses);
+ if (ses->ipv4) {
+ np.protocol = PPP_IP;
+ np.mode = NPMODE_PASS;
+
+ if (ioctl(ppp->unit_fd, PPPIOCSNPMODE, &np))
+ log_ppp_error("failed to set NP (IPv4) mode: %s\n", strerror(errno));
+ }
+
+ if (ses->ipv6) {
+ np.protocol = PPP_IPV6;
+ np.mode = NPMODE_PASS;
- if (ioctl(ppp->unit_fd, PPPIOCSNPMODE, &np))
- log_ppp_error("failed to set NP (IPv6) mode: %s\n", strerror(errno));
+ if (ioctl(ppp->unit_fd, PPPIOCSNPMODE, &np))
+ log_ppp_error("failed to set NP (IPv6) mode: %s\n", strerror(errno));
+ }
}
+#ifdef USE_BACKUP
}
+#endif
ses->ctrl->started(ses);
diff --git a/accel-pppd/include/ap_session.h b/accel-pppd/include/ap_session.h
index b964c80..075058c 100644
--- a/accel-pppd/include/ap_session.h
+++ b/accel-pppd/include/ap_session.h
@@ -7,6 +7,7 @@
#define AP_STATE_STARTING 1
#define AP_STATE_ACTIVE 2
#define AP_STATE_FINISHING 3
+#define AP_STATE_RESTORE 4
#define TERM_USER_REQUEST 1
#define TERM_SESSION_TIMEOUT 2
@@ -30,6 +31,7 @@
#define MPPE_REQUIRE 2
struct ap_session;
+struct backup_data;
struct ap_ctrl
{
@@ -71,6 +73,10 @@ struct ap_session
struct ap_ctrl *ctrl;
+#ifdef USE_BACKUP
+ struct backup_data *backup;
+#endif
+
int terminating:1;
int terminated:1;
int terminate_cause;
diff --git a/accel-pppd/include/ap_session_backup.h b/accel-pppd/include/ap_session_backup.h
new file mode 100644
index 0000000..e6382ff
--- /dev/null
+++ b/accel-pppd/include/ap_session_backup.h
@@ -0,0 +1,23 @@
+#ifndef __AP_SESSION_BACKUP_H
+#define __AP_SESSION_BACKUP_H
+
+#define SES_TAG_USERNAME 1
+#define SES_TAG_SESSIONID 2
+#define SES_TAG_START_TIME 3
+#define SES_TAG_IPV4_ADDR 4
+#define SES_TAG_IPV4_PEER_ADDR 5
+#define SES_TAG_IPV6_INTFID 6
+#define SES_TAG_IPV6_PEER_INTFID 7
+#define SES_TAG_IPV6_ADDR 8
+#define SES_TAG_IFINDEX 9
+#define SES_TAG_IFNAME 10
+
+
+struct ses_tag_ipv6
+{
+ struct in6_addr addr;
+ uint8_t prefix_len;
+} __attribute__((packed));
+
+#endif
+
diff --git a/accel-pppd/include/backup.h b/accel-pppd/include/backup.h
new file mode 120000
index 0000000..0271d05
--- /dev/null
+++ b/accel-pppd/include/backup.h
@@ -0,0 +1 @@
+../backup/backup.h \ No newline at end of file
diff --git a/accel-pppd/main.c b/accel-pppd/main.c
index e153caf..9e51556 100644
--- a/accel-pppd/main.c
+++ b/accel-pppd/main.c
@@ -4,6 +4,11 @@
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
+#include <fcntl.h>
+#include <time.h>
+#include <limits.h>
+#include <malloc.h>
+#include <dirent.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/resource.h>
@@ -13,9 +18,16 @@
#include "memdebug.h"
#include "log.h"
#include "events.h"
+#include "backup.h"
+
+#ifndef ARG_MAX
+#define ARG_MAX 128*1024
+#endif
static char *pid_file;
static char *conf_file;
+static char *conf_dump;
+static char *exec_file;
static void change_limits(void)
{
@@ -50,19 +62,138 @@ static void config_reload_notify(int r)
if (!r)
triton_event_fire(EV_CONFIG_RELOAD, NULL);
}
+
static void config_reload(int num)
{
triton_conf_reload(config_reload_notify);
}
+static void close_all_fd(void)
+{
+ DIR *dirp;
+ struct dirent ent, *res;
+ char path[128];
+
+ sprintf(path, "/proc/%u/fd", getpid());
+
+ dirp = opendir(path);
+ if (!dirp)
+ return;
+
+ while (1) {
+ if (readdir_r(dirp, &ent, &res))
+ return;
+ if (!res)
+ break;
+ close((unsigned long)atol(ent.d_name));
+ }
+
+ closedir(dirp);
+}
+
+void core_restart(int soft)
+{
+ char fname[128];
+ int fd, n;
+ char cmdline[ARG_MAX];
+ char *args[16];
+ char *ptr = cmdline, *endptr;
+ sigset_t set;
+
+ if (fork()) {
+ close_all_fd();
+ return;
+ }
+
+ sigfillset(&set);
+ pthread_sigmask(SIG_SETMASK, &set, NULL);
+
+ sprintf(fname, "/proc/%i/cmdline", getpid());
+
+ fd = open(fname, O_RDONLY);
+ n = read(fd, cmdline, ARG_MAX);
+
+ endptr = ptr + n;
+
+ n = 0;
+ while (ptr < endptr) {
+ args[n++] = ptr;
+ while (ptr < endptr && *ptr++);
+ }
+
+ args[n++] = NULL;
+
+#ifdef USE_BACKUP
+ if (soft)
+ backup_restore_fd();
+ else
+#endif
+ if (fork()) {
+ close_all_fd();
+ _exit(0);
+ }
+
+
+ while (1) {
+ sleep(3);
+ execv(args[0], args);
+ }
+}
+
+static void sigsegv(int num)
+{
+ char cmd[PATH_MAX];
+ char fname[PATH_MAX];
+ struct rlimit lim;
+
+#ifdef USE_BACKUP
+ core_restart(1);
+#else
+ core_restart(0);
+#endif
+
+ if (conf_dump) {
+ FILE *f;
+ unsigned int t = time(NULL);
+ sprintf(fname, "%s/cmd-%u", conf_dump, t);
+ f = fopen(fname, "w");
+ if (!f)
+ goto out;
+ fprintf(f, "thread apply all bt full\ndetach\nquit\n");
+ fclose(f);
+
+ sprintf(cmd, "gdb -x %s %s %d > %s/dump-%u", fname, exec_file, getpid(), conf_dump, t);
+ system(cmd);
+ unlink(fname);
+
+ lim.rlim_cur = RLIM_INFINITY;
+ lim.rlim_max = RLIM_INFINITY;
+
+ setrlimit(RLIMIT_CORE, &lim);
+
+ chdir(conf_dump);
+ }
+
+out:
+ abort();
+}
+
int main(int argc, char **argv)
{
sigset_t set;
- int i, sig, goto_daemon = 0;
+ int i, sig, goto_daemon = 0, len;
+ pid_t pid = 0;
+ struct sigaction sa;
+ int pagesize = sysconf(_SC_PAGE_SIZE);
+#ifdef USE_BACKUP
+ int internal = 0;
+#endif
if (argc < 2)
goto usage;
+ exec_file = argv[0];
+
for(i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-d"))
goto_daemon = 1;
@@ -74,16 +205,38 @@ int main(int argc, char **argv)
if (i == argc - 1)
goto usage;
conf_file = argv[++i];
+ } else if (!strcmp(argv[i], "--dump")) {
+ if (i == argc - 1)
+ goto usage;
+ len = (strlen(argv[i + 1]) / pagesize + 1) * pagesize;
+ conf_dump = memalign(pagesize, len);
+ strcpy(conf_dump, argv[++i]);
+ mprotect(conf_dump, len, PROT_READ);
}
}
if (!conf_file)
goto usage;
+
+ if (pid_file) {
+ FILE *f = fopen(pid_file, "r");
+ if (f) {
+ fscanf(f, "%u", &pid);
+ fclose(f);
+ }
+#ifdef USE_BACKUP
+ internal = pid == getppid();
+#endif
+ /*if (pid) {
+ printf("%i %i %i\n", pid, getppid(), getpid());
+ return 0;
+ }*/
+ }
if (triton_init(conf_file))
_exit(EXIT_FAILURE);
- if (goto_daemon) {
+ if (goto_daemon && pid != getpid()) {
/*pid_t pid = fork();
if (pid > 0)
_exit(EXIT_SUCCESS);
@@ -121,15 +274,19 @@ int main(int argc, char **argv)
triton_run();
- sigfillset(&set);
- struct sigaction sa = {
- .sa_handler = config_reload,
- .sa_mask = set,
- };
+ sigfillset(&set);
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = config_reload;
+ sa.sa_mask = set;
sigaction(SIGUSR1, &sa, NULL);
+
+ sa.sa_handler = sigsegv;
+ sa.sa_mask = set;
+ sigaction(SIGSEGV, &sa, NULL);
+
sigdelset(&set, SIGKILL);
sigdelset(&set, SIGSTOP);
sigdelset(&set, SIGSEGV);
@@ -151,7 +308,11 @@ int main(int argc, char **argv)
sigaddset(&set, SIGILL);
sigaddset(&set, SIGFPE);
sigaddset(&set, SIGBUS);
-
+
+#ifdef USE_BACKUP
+ backup_restore(internal);
+#endif
+
sigwait(&set, &sig);
log_info1("terminate, sig = %i\n", sig);
diff --git a/accel-pppd/radius/CMakeLists.txt b/accel-pppd/radius/CMakeLists.txt
index 0c1789e..d139fe1 100644
--- a/accel-pppd/radius/CMakeLists.txt
+++ b/accel-pppd/radius/CMakeLists.txt
@@ -10,6 +10,10 @@ SET(sources
radius.c
)
+IF (BACKUP)
+ SET(sources ${sources} backup.c)
+ENDIF (BACKUP)
+
ADD_DEFINITIONS(-DDICTIONARY="${CMAKE_INSTALL_PREFIX}/share/accel-ppp/radius/dictionary")
ADD_LIBRARY(radius SHARED ${sources})
diff --git a/accel-pppd/radius/acct.c b/accel-pppd/radius/acct.c
index dfc982d..b5f7ff7 100644
--- a/accel-pppd/radius/acct.c
+++ b/accel-pppd/radius/acct.c
@@ -10,6 +10,8 @@
#include "crypto.h"
#include "log.h"
+#include "backup.h"
+#include "ap_session_backup.h"
#include "radius_p.h"
#include "memdebug.h"
@@ -235,7 +237,9 @@ int rad_acct_start(struct radius_pd_t *rpd)
if (!conf_accounting)
return 0;
- rpd->acct_req = rad_req_alloc(rpd, CODE_ACCOUNTING_REQUEST, rpd->ses->username);
+ if (!rpd->acct_req)
+ rpd->acct_req = rad_req_alloc(rpd, CODE_ACCOUNTING_REQUEST, rpd->ses->username);
+
if (!rpd->acct_req)
return -1;
@@ -259,71 +263,77 @@ int rad_acct_start(struct radius_pd_t *rpd)
if (req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret))
goto out_err;
- while (1) {
-
- if (rad_server_req_enter(rpd->acct_req)) {
- if (rad_server_realloc(rpd->acct_req)) {
- log_ppp_warn("radius:acct_start: no servers available\n");
- goto out_err;
- }
- if (req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret))
- goto out_err;
- continue;
- }
+#ifdef USE_BACKUP
+ if (rpd->ses->state != AP_STATE_RESTORE || !rpd->ses->backup->internal) {
+#endif
+ while (1) {
- for (i = 0; i < conf_max_try; i++) {
- if (conf_acct_delay_time) {
- time(&ts);
- rad_packet_change_int(rpd->acct_req->pack, NULL, "Acct-Delay-Time", ts - rpd->acct_timestamp);
+ if (rad_server_req_enter(rpd->acct_req)) {
+ if (rad_server_realloc(rpd->acct_req)) {
+ log_ppp_warn("radius:acct_start: no servers available\n");
+ goto out_err;
+ }
if (req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret))
goto out_err;
+ continue;
}
- if (rad_req_send(rpd->acct_req, conf_verbose))
- goto out_err;
+ for (i = 0; i < conf_max_try; i++) {
+ if (conf_acct_delay_time) {
+ time(&ts);
+ rad_packet_change_int(rpd->acct_req->pack, NULL, "Acct-Delay-Time", ts - rpd->acct_timestamp);
+ if (req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret))
+ goto out_err;
+ }
- __sync_add_and_fetch(&rpd->acct_req->serv->stat_acct_sent, 1);
+ if (rad_req_send(rpd->acct_req, conf_verbose))
+ goto out_err;
+
+ __sync_add_and_fetch(&rpd->acct_req->serv->stat_acct_sent, 1);
+
+ rad_req_wait(rpd->acct_req, conf_timeout);
+
+ if (!rpd->acct_req->reply) {
+ if (conf_acct_delay_time)
+ rpd->acct_req->pack->id++;
+ __sync_add_and_fetch(&rpd->acct_req->serv->stat_acct_lost, 1);
+ stat_accm_add(rpd->acct_req->serv->stat_acct_lost_1m, 1);
+ stat_accm_add(rpd->acct_req->serv->stat_acct_lost_5m, 1);
+ continue;
+ }
- rad_req_wait(rpd->acct_req, conf_timeout);
+ dt = (rpd->acct_req->reply->tv.tv_sec - rpd->acct_req->pack->tv.tv_sec) * 1000 +
+ (rpd->acct_req->reply->tv.tv_nsec - rpd->acct_req->pack->tv.tv_nsec) / 1000000;
+ stat_accm_add(rpd->acct_req->serv->stat_acct_query_1m, dt);
+ stat_accm_add(rpd->acct_req->serv->stat_acct_query_5m, dt);
- if (!rpd->acct_req->reply) {
- if (conf_acct_delay_time)
+ if (rpd->acct_req->reply->id != rpd->acct_req->pack->id || rpd->acct_req->reply->code != CODE_ACCOUNTING_RESPONSE) {
+ rad_packet_free(rpd->acct_req->reply);
+ rpd->acct_req->reply = NULL;
rpd->acct_req->pack->id++;
- __sync_add_and_fetch(&rpd->acct_req->serv->stat_acct_lost, 1);
- stat_accm_add(rpd->acct_req->serv->stat_acct_lost_1m, 1);
- stat_accm_add(rpd->acct_req->serv->stat_acct_lost_5m, 1);
- continue;
+ __sync_add_and_fetch(&rpd->acct_req->serv->stat_acct_lost, 1);
+ stat_accm_add(rpd->acct_req->serv->stat_acct_lost_1m, 1);
+ stat_accm_add(rpd->acct_req->serv->stat_acct_lost_5m, 1);
+ } else
+ break;
}
- dt = (rpd->acct_req->reply->tv.tv_sec - rpd->acct_req->pack->tv.tv_sec) * 1000 +
- (rpd->acct_req->reply->tv.tv_nsec - rpd->acct_req->pack->tv.tv_nsec) / 1000000;
- stat_accm_add(rpd->acct_req->serv->stat_acct_query_1m, dt);
- stat_accm_add(rpd->acct_req->serv->stat_acct_query_5m, dt);
-
- if (rpd->acct_req->reply->id != rpd->acct_req->pack->id || rpd->acct_req->reply->code != CODE_ACCOUNTING_RESPONSE) {
- rad_packet_free(rpd->acct_req->reply);
- rpd->acct_req->reply = NULL;
- rpd->acct_req->pack->id++;
- __sync_add_and_fetch(&rpd->acct_req->serv->stat_acct_lost, 1);
- stat_accm_add(rpd->acct_req->serv->stat_acct_lost_1m, 1);
- stat_accm_add(rpd->acct_req->serv->stat_acct_lost_5m, 1);
- } else
- break;
- }
-
- rad_server_req_exit(rpd->acct_req);
+ rad_server_req_exit(rpd->acct_req);
- if (rpd->acct_req->reply)
- break;
+ if (rpd->acct_req->reply)
+ break;
- rad_server_fail(rpd->acct_req->serv);
- if (rad_server_realloc(rpd->acct_req)) {
- log_ppp_warn("radius:acct_start: no servers available\n");
- goto out_err;
+ rad_server_fail(rpd->acct_req->serv);
+ if (rad_server_realloc(rpd->acct_req)) {
+ log_ppp_warn("radius:acct_start: no servers available\n");
+ goto out_err;
+ }
+ if (req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret))
+ goto out_err;
}
- if (req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret))
- goto out_err;
+#ifdef USE_BACKUP
}
+#endif
rpd->acct_req->hnd.read = rad_acct_read;
diff --git a/accel-pppd/radius/backup.c b/accel-pppd/radius/backup.c
new file mode 100644
index 0000000..4c40ec6
--- /dev/null
+++ b/accel-pppd/radius/backup.c
@@ -0,0 +1,163 @@
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <net/ethernet.h>
+
+#include "log.h"
+#include "memdebug.h"
+
+#include "backup.h"
+#include "ap_session_backup.h"
+#include "radius_p.h"
+
+#define RAD_TAG_INTERIM_INTERVAL 1
+#define RAD_TAG_SESSION_TIMEOUT 2
+#define RAD_TAG_IPV4_ADDR 3
+#define RAD_TAG_IPV6_ADDR 4
+#define RAD_TAG_IPV6_DP 5
+#define RAD_TAG_ATTR_CLASS 6
+#define RAD_TAG_ATTR_STATE 7
+#define RAD_TAG_TERMINATION_ACTION 8
+#define RAD_TAG_ACCT_SERVER_ADDR 9
+#define RAD_TAG_ACCT_SERVER_PORT 10
+
+
+#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 radius_pd_t *rpd = find_pd(ses);
+ uint64_t session_timeout = ses->start_time + rpd->session_timeout.expire_tv.tv_sec;
+
+ if (!rpd)
+ return 0;
+
+ if (!rpd->authenticated)
+ return -2;
+
+ add_tag(RAD_TAG_INTERIM_INTERVAL, &rpd->acct_interim_interval, 4);
+
+ if (rpd->session_timeout.tpd)
+ add_tag(RAD_TAG_SESSION_TIMEOUT, &session_timeout, 8);
+
+ if (ses->ipv4 == &rpd->ipv4_addr)
+ add_tag(RAD_TAG_IPV4_ADDR, NULL, 0);
+
+ if (ses->ipv6 == &rpd->ipv6_addr)
+ add_tag(RAD_TAG_IPV6_ADDR, NULL, 0);
+
+ /*if (rpd->ipv6_pd_assigned) {
+
+ }*/
+
+ if (rpd->attr_class)
+ add_tag(RAD_TAG_ATTR_CLASS, rpd->attr_class, rpd->attr_class_len);
+
+ if (rpd->attr_state)
+ add_tag(RAD_TAG_ATTR_CLASS, rpd->attr_state, rpd->attr_state_len);
+
+ add_tag(RAD_TAG_TERMINATION_ACTION, &rpd->termination_action, 4);
+
+ if (rpd->acct_req) {
+ add_tag(RAD_TAG_ACCT_SERVER_ADDR, &rpd->acct_req->server_addr, 4);
+ add_tag(RAD_TAG_ACCT_SERVER_PORT, &rpd->acct_req->server_port, 2);
+ }
+
+ return 0;
+}
+
+static int session_restore(struct ap_session *ses, struct backup_mod *m)
+{
+ return 0;
+}
+
+static void restore_ipv4_addr(struct ap_session *ses)
+{
+ struct backup_mod *m = backup_find_mod(ses->backup, MODID_COMMON);
+ struct backup_tag *tag;
+
+ list_for_each_entry(tag, &m->tag_list, entry) {
+ switch (tag->id) {
+ case SES_TAG_IPV4_ADDR:
+ ses->ipv4->addr = *(in_addr_t *)tag->data;
+ break;
+ case SES_TAG_IPV4_PEER_ADDR:
+ ses->ipv4->peer_addr = *(in_addr_t *)tag->data;
+ break;
+ }
+ }
+}
+
+static void restore_ipv6_addr(struct ap_session *ses)
+{
+
+}
+
+void radius_restore_session(struct ap_session *ses, struct radius_pd_t *rpd)
+{
+ struct backup_mod *m = backup_find_mod(ses->backup, MODID_RADIUS);
+ struct backup_tag *tag;
+ in_addr_t acct_addr = 0;
+ int acct_port;
+
+ if (!m)
+ return;
+
+ list_for_each_entry(tag, &m->tag_list, entry) {
+ switch (tag->id) {
+ case RAD_TAG_INTERIM_INTERVAL:
+ rpd->acct_interim_interval = *(uint32_t *)tag->data;
+ break;
+ case RAD_TAG_SESSION_TIMEOUT:
+ rpd->session_timeout.expire_tv.tv_sec = *(uint64_t *)tag->data - ses->start_time;
+ break;
+ case RAD_TAG_IPV4_ADDR:
+ ses->ipv4 = &rpd->ipv4_addr;
+ restore_ipv4_addr(ses);
+ break;
+ case RAD_TAG_IPV6_ADDR:
+ restore_ipv6_addr(ses);
+ break;
+ case RAD_TAG_ATTR_CLASS:
+ rpd->attr_class = _malloc(tag->size);
+ memcpy(rpd->attr_class, tag->data, tag->size);
+ rpd->attr_class_len = tag->size;
+ break;
+ case RAD_TAG_ATTR_STATE:
+ rpd->attr_state = _malloc(tag->size);
+ memcpy(rpd->attr_state, tag->data, tag->size);
+ rpd->attr_state_len = tag->size;
+ break;
+ case RAD_TAG_TERMINATION_ACTION:
+ rpd->termination_action = *(uint32_t *)tag->data;
+ break;
+ case RAD_TAG_ACCT_SERVER_ADDR:
+ acct_addr = *(in_addr_t *)tag->data;
+ break;
+ case RAD_TAG_ACCT_SERVER_PORT:
+ acct_port = *(uint16_t *)tag->data;
+ break;
+ }
+ }
+
+ if (acct_addr)
+ rpd->acct_req = rad_req_alloc2(rpd, CODE_ACCOUNTING_REQUEST, rpd->ses->username, acct_addr, acct_port);
+
+ rpd->authenticated = 1;
+}
+
+static struct backup_module mod = {
+ .id = MODID_RADIUS,
+ .save = session_save,
+ .restore = session_restore,
+};
+
+static void init(void)
+{
+ backup_register_module(&mod);
+}
+
+DEFINE_INIT(100, init);
+
diff --git a/accel-pppd/radius/radius.c b/accel-pppd/radius/radius.c
index d880ad0..82ac979 100644
--- a/accel-pppd/radius/radius.c
+++ b/accel-pppd/radius/radius.c
@@ -84,7 +84,6 @@ int rad_proc_attrs(struct rad_req_t *req)
if (!conf_gw_ip_address)
log_ppp_warn("radius: gw-ip-address not specified, cann't assign IP address...\n");
else {
- req->rpd->ipv4_addr.owner = &ipdb;
req->rpd->ipv4_addr.peer_addr = attr->val.ipaddr;
req->rpd->ipv4_addr.addr = conf_gw_ip_address;
}
@@ -190,7 +189,6 @@ static struct ipv6db_item_t *get_ipv6(struct ap_session *ses)
{
struct radius_pd_t *rpd = find_pd(ses);
- rpd->ipv6_addr.owner = &ipdb;
rpd->ipv6_addr.intf_id = 0;
if (!list_empty(&rpd->ipv6_addr.addr_list))
@@ -203,10 +201,10 @@ static struct ipv6db_prefix_t *get_ipv6_prefix(struct ap_session *ses)
{
struct radius_pd_t *rpd = find_pd(ses);
- rpd->ipv6_dp.owner = &ipdb;
-
- if (!list_empty(&rpd->ipv6_dp.prefix_list))
+ if (!list_empty(&rpd->ipv6_dp.prefix_list)) {
+ rpd->ipv6_dp_assigned = 1;
return &rpd->ipv6_dp;
+ }
return NULL;
}
@@ -240,12 +238,21 @@ static void ses_starting(struct ap_session *ses)
INIT_LIST_HEAD(&rpd->plugin_list);
INIT_LIST_HEAD(&rpd->ipv6_addr.addr_list);
INIT_LIST_HEAD(&rpd->ipv6_dp.prefix_list);
+
+ rpd->ipv4_addr.owner = &ipdb;
+ rpd->ipv6_addr.owner = &ipdb;
+ rpd->ipv6_dp.owner = &ipdb;
list_add_tail(&rpd->pd.entry, &ses->pd_list);
pthread_rwlock_wrlock(&sessions_lock);
list_add_tail(&rpd->entry, &sessions);
pthread_rwlock_unlock(&sessions_lock);
+
+#ifdef USE_BACKUP
+ if (ses->state == AP_STATE_RESTORE && ses->backup)
+ radius_restore_session(ses, rpd);
+#endif
}
static void ses_acct_start(struct ap_session *ses)
diff --git a/accel-pppd/radius/radius_p.h b/accel-pppd/radius/radius_p.h
index f8adb46..0709351 100644
--- a/accel-pppd/radius/radius_p.h
+++ b/accel-pppd/radius/radius_p.h
@@ -19,6 +19,7 @@ struct radius_pd_t
struct ap_session *ses;
pthread_mutex_t lock;
int authenticated:1;
+ int ipv6_dp_assigned:1;
struct rad_req_t *auth_req;
struct rad_req_t *acct_req;
@@ -142,6 +143,7 @@ int rad_dict_load(const char *fname);
void rad_dict_free(struct rad_dict_t *dict);
struct rad_req_t *rad_req_alloc(struct radius_pd_t *rpd, int code, const char *username);
+struct rad_req_t *rad_req_alloc2(struct radius_pd_t *rpd, int code, const char *username, in_addr_t addr, int port);
int rad_req_acct_fill(struct rad_req_t *);
void rad_req_free(struct rad_req_t *);
int rad_req_send(struct rad_req_t *, int verbose);
@@ -169,6 +171,7 @@ int rad_packet_send(struct rad_packet_t *pck, int fd, struct sockaddr_in *addr);
void dm_coa_cancel(struct radius_pd_t *pd);
struct rad_server_t *rad_server_get(int);
+struct rad_server_t *rad_server_get2(int, in_addr_t, int);
void rad_server_put(struct rad_server_t *, int);
int rad_server_req_enter(struct rad_req_t *);
void rad_server_req_exit(struct rad_req_t *);
@@ -176,6 +179,8 @@ int rad_server_realloc(struct rad_req_t *);
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 radius_restore_session(struct ap_session *ses, struct radius_pd_t *rpd);
struct stat_accm_t;
struct stat_accm_t *stat_accm_create(unsigned int time);
diff --git a/accel-pppd/radius/req.c b/accel-pppd/radius/req.c
index f452c42..cd9a170 100644
--- a/accel-pppd/radius/req.c
+++ b/accel-pppd/radius/req.c
@@ -16,8 +16,9 @@
static int rad_req_read(struct triton_md_handler_t *h);
static void rad_req_timeout(struct triton_timer_t *t);
+static int make_socket(struct rad_req_t *req);
-struct rad_req_t *rad_req_alloc(struct radius_pd_t *rpd, int code, const char *username)
+static struct rad_req_t *__rad_req_alloc(struct radius_pd_t *rpd, int code, const char *username, in_addr_t addr, int port)
{
struct rad_plugin_t *plugin;
struct ppp_t *ppp = NULL;
@@ -38,7 +39,11 @@ struct rad_req_t *rad_req_alloc(struct radius_pd_t *rpd, int code, const char *u
req->type = code == CODE_ACCESS_REQUEST ? RAD_SERV_AUTH : RAD_SERV_ACCT;
- req->serv = rad_server_get(req->type);
+ if (addr)
+ req->serv = rad_server_get2(req->type, addr, port);
+ else
+ req->serv = rad_server_get(req->type);
+
if (!req->serv)
goto out_err;
@@ -120,6 +125,26 @@ out_err:
return NULL;
}
+struct rad_req_t *rad_req_alloc(struct radius_pd_t *rpd, int code, const char *username)
+{
+ return __rad_req_alloc(rpd, code, username, 0, 0);
+}
+
+struct rad_req_t *rad_req_alloc2(struct radius_pd_t *rpd, int code, const char *username, in_addr_t addr, int port)
+{
+ struct rad_req_t *req = __rad_req_alloc(rpd, code, username, addr, port);
+
+ if (!req)
+ return NULL;
+
+ if (code == CODE_ACCOUNTING_REQUEST)
+ req->server_port = req->serv->acct_port;
+
+ make_socket(req);
+
+ return req;
+}
+
int rad_req_acct_fill(struct rad_req_t *req)
{
struct ipv6db_addr_t *a;
diff --git a/accel-pppd/radius/serv.c b/accel-pppd/radius/serv.c
index 4de6ad1..aae3719 100644
--- a/accel-pppd/radius/serv.c
+++ b/accel-pppd/radius/serv.c
@@ -24,9 +24,9 @@ static LIST_HEAD(serv_list);
static void __free_server(struct rad_server_t *);
-static struct rad_server_t *__rad_server_get(int type, struct rad_server_t *exclude)
+static struct rad_server_t *__rad_server_get(int type, struct rad_server_t *exclude, in_addr_t addr, int port)
{
- struct rad_server_t *s, *s0 = NULL;
+ struct rad_server_t *s, *s0 = NULL, *s1 = NULL;
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
@@ -43,6 +43,15 @@ static struct rad_server_t *__rad_server_get(int type, struct rad_server_t *excl
else if (type == RAD_SERV_ACCT && !s->acct_port)
continue;
+ if (s->addr == addr) {
+ if (type == RAD_SERV_AUTH && port == s->auth_port)
+ s1 = s;
+ else if (type == RAD_SERV_ACCT && port == s->acct_port)
+ s1 = s;
+ else if (!s1)
+ s1 = s;
+ }
+
if (!s0) {
s0 = s;
continue;
@@ -52,7 +61,9 @@ static struct rad_server_t *__rad_server_get(int type, struct rad_server_t *excl
s0 = s;
}
- if (!s0)
+ if (s1)
+ s0 = s1;
+ else if (!s0)
return NULL;
__sync_add_and_fetch(&s0->client_cnt[type], 1);
@@ -62,7 +73,12 @@ static struct rad_server_t *__rad_server_get(int type, struct rad_server_t *excl
struct rad_server_t *rad_server_get(int type)
{
- return __rad_server_get(type, NULL);
+ return __rad_server_get(type, NULL, 0, 0);
+}
+
+struct rad_server_t *rad_server_get2(int type, in_addr_t addr, int port)
+{
+ return __rad_server_get(type, NULL, addr, port);
}
void rad_server_put(struct rad_server_t *s, int type)
@@ -137,7 +153,7 @@ void rad_server_req_exit(struct rad_req_t *req)
int rad_server_realloc(struct rad_req_t *req)
{
- struct rad_server_t *s = __rad_server_get(req->type, req->serv);
+ struct rad_server_t *s = __rad_server_get(req->type, req->serv, 0, 0);
if (!s)
return -1;
diff --git a/accel-pppd/session.c b/accel-pppd/session.c
index 886aa40..d24dcd7 100644
--- a/accel-pppd/session.c
+++ b/accel-pppd/session.c
@@ -17,6 +17,7 @@
#include "log.h"
#include "events.h"
#include "ap_session.h"
+#include "backup.h"
#include "spinlock.h"
#include "mempool.h"
#include "memdebug.h"
@@ -51,8 +52,6 @@ int __export ap_session_starting(struct ap_session *ses)
{
struct ifreq ifr;
- ses->start_time = time(NULL);
-
if (ses->ifindex == -1) {
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, ses->ifname);
@@ -63,10 +62,14 @@ int __export ap_session_starting(struct ap_session *ses)
}
ses->ifindex = ifr.ifr_ifindex;
}
-
- generate_sessionid(ses);
- ses->state = AP_STATE_STARTING;
+ if (ses->state != AP_STATE_RESTORE) {
+ ses->start_time = time(NULL);
+ generate_sessionid(ses);
+
+ ses->state = AP_STATE_STARTING;
+ }
+
__sync_add_and_fetch(&ap_session_stat.starting, 1);
pthread_rwlock_wrlock(&ses_lock);
@@ -80,10 +83,16 @@ int __export ap_session_starting(struct ap_session *ses)
void __export ap_session_activate(struct ap_session *ses)
{
+ ap_session_ifup(ses);
+
ses->state = AP_STATE_ACTIVE;
__sync_sub_and_fetch(&ap_session_stat.starting, 1);
__sync_add_and_fetch(&ap_session_stat.active, 1);
- ap_session_ifup(ses);
+
+#ifdef USE_BACKUP
+ if (!ses->backup)
+ backup_save_session(ses);
+#endif
}
void __export ap_session_finished(struct ap_session *ses)
@@ -98,6 +107,7 @@ void __export ap_session_finished(struct ap_session *ses)
case AP_STATE_ACTIVE:
__sync_sub_and_fetch(&ap_session_stat.active, 1);
break;
+ case AP_STATE_RESTORE:
case AP_STATE_STARTING:
__sync_sub_and_fetch(&ap_session_stat.starting, 1);
break;
@@ -123,6 +133,11 @@ void __export ap_session_finished(struct ap_session *ses)
_free(ses->ipv6_pool_name);
ses->ipv6_pool_name = NULL;
}
+
+#ifdef USE_BACKUP
+ if (ses->backup)
+ ses->backup->storage->free(ses->backup);
+#endif
if (ap_shutdown && !ap_session_stat.starting && !ap_session_stat.active && !ap_session_stat.finishing)
kill(getpid(), SIGTERM);
@@ -145,14 +160,14 @@ void __export ap_session_terminate(struct ap_session *ses, int cause, int hard)
return;
}
- ses->terminating = 1;
- ses->state = AP_STATE_FINISHING;
-
if (ses->state == AP_STATE_ACTIVE)
__sync_sub_and_fetch(&ap_session_stat.active, 1);
else
__sync_sub_and_fetch(&ap_session_stat.starting, 1);
+
__sync_add_and_fetch(&ap_session_stat.finishing, 1);
+ ses->terminating = 1;
+ ses->state = AP_STATE_FINISHING;
log_ppp_debug("terminate\n");
diff --git a/accel-pppd/session_backup.c b/accel-pppd/session_backup.c
new file mode 100644
index 0000000..8607362
--- /dev/null
+++ b/accel-pppd/session_backup.c
@@ -0,0 +1,136 @@
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <netinet/in.h>
+
+#include "events.h"
+#include "triton.h"
+#include "log.h"
+#include "ap_session.h"
+#include "backup.h"
+#include "ap_session_backup.h"
+#include "ipdb.h"
+
+#include "memdebug.h"
+
+#ifdef USE_BACKUP
+
+#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 ipv6db_addr_t *a;
+ struct ses_tag_ipv6 ipv6;
+
+ add_tag(SES_TAG_USERNAME, ses->username, strlen(ses->username));
+ add_tag(SES_TAG_SESSIONID, ses->sessionid, AP_SESSIONID_LEN);
+ add_tag(SES_TAG_START_TIME, &ses->start_time, sizeof(time_t));
+ add_tag(SES_TAG_IFNAME, ses->ifname, strlen(ses->ifname));
+ add_tag_int(SES_TAG_IFINDEX, &ses->ifindex, 4);
+
+ if (ses->ipv4) {
+ add_tag(SES_TAG_IPV4_ADDR, &ses->ipv4->addr, 4);
+ add_tag(SES_TAG_IPV4_PEER_ADDR, &ses->ipv4->peer_addr, 4);
+ }
+
+ if (ses->ipv6) {
+ add_tag(SES_TAG_IPV6_INTFID, &ses->ipv6->intf_id, 8);
+ add_tag(SES_TAG_IPV6_PEER_INTFID, &ses->ipv6->peer_intf_id, 8);
+ list_for_each_entry(a, &ses->ipv6->addr_list, entry) {
+ ipv6.addr = a->addr;
+ ipv6.prefix_len = a->prefix_len;
+ add_tag(SES_TAG_IPV6_ADDR, &ipv6, sizeof(ipv6));
+ }
+ }
+
+ //add_tag_int(PPP_TAG_FD, &ses->fd, sizeof(ses->fd));
+ //add_tag_int(PPP_TAG_CHAN_FD, &ses->chan_fd, sizeof(ses->chan_fd));
+ //add_tag_int(PPP_TAG_UNIT_FD, &ses->unit_fd, sizeof(ses->unit_fd));
+ //add_tag_int(PPP_TAG_UNIT, &ses->unit_idx, sizeof(ses->unit_idx));
+
+ //triton_event_fire(EV_PPP_SESSION_SAVE, &ev);
+
+ return 0;
+}
+
+static int session_restore(struct ap_session *ses, struct backup_mod *m)
+{
+ struct backup_tag *t;
+
+ list_for_each_entry(t, &m->tag_list, entry) {
+ switch(t->id) {
+ case SES_TAG_USERNAME:
+ ses->username = _malloc(t->size + 1);
+ if (!ses->username) {
+ log_emerg("out of memory");
+ return -1;
+ }
+ memcpy(ses->username, t->data, t->size);
+ ses->username[t->size] = 0;
+ break;
+ case SES_TAG_SESSIONID:
+ memcpy(ses->sessionid, t->data, AP_SESSIONID_LEN);
+ break;
+ case SES_TAG_IFNAME:
+ memcpy(ses->ifname, t->data, t->size);
+ ses->ifname[t->size] = 0;
+ break;
+ case SES_TAG_START_TIME:
+ ses->start_time = *(time_t *)t->data;
+ break;
+ case SES_TAG_IFINDEX:
+ if (ses->backup->internal)
+ ses->ifindex = *(uint32_t *)t->data;
+ break;
+ /*case PPP_TAG_FD:
+ ses->fd = *(int *)t->data;
+ break;
+ case PPP_TAG_CHAN_FD:
+ ses->chan_fd = *(int *)t->data;
+ break;
+ case PPP_TAG_UNIT_FD:
+ ses->chan_fd = *(int *)t->data;
+ break;
+ case PPP_TAG_UNIT:
+ ses->unit_idx = *(int *)t->data;
+ break;
+ case PPP_TAG_IPV4_ADDR:
+ if (!ses->ipv4) {
+ ses->ipv4 = _malloc(sizeof(*ses->ipv4));
+ memset(ses->ipv4, 0, sizeof(*ses->ipv4));
+ ses->ipv4->owner = &ipdb;
+ }
+ ses->ipv4->addr = *(in_addr_t *)t->data;
+ break;
+ case PPP_TAG_IPV4_PEER_ADDR:
+ if (!ses->ipv4) {
+ ses->ipv4 = _malloc(sizeof(*ses->ipv4));
+ memset(ses->ipv4, 0, sizeof(*ses->ipv4));
+ ses->ipv4->owner = &ipdb;
+ }
+ ses->ipv4->peer_addr = *(in_addr_t *)t->data;
+ break;*/
+ }
+ }
+
+ return 0;
+ //return establish_ses(ses);
+}
+
+static struct backup_module mod = {
+ .id = MODID_COMMON,
+ .save = session_save,
+ .restore = session_restore,
+};
+
+static void init(void)
+{
+ backup_register_module(&mod);
+}
+
+DEFINE_INIT(101, init);
+
+#endif
diff --git a/ipoe-util/CMakeLists.txt b/ipoe-util/CMakeLists.txt
deleted file mode 100644
index 51a59d3..0000000
--- a/ipoe-util/CMakeLists.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
-INCLUDE_DIRECTORIES(${CMAKE_HOME_DIRECTORY}/ipses)
-
-if (LIBNL2)
- ADD_DEFINITIONS("-DLIBNL2")
-endif (LIBNL2)
-
-ADD_EXECUTABLE(ipses-create ipses-create.c)
-ADD_EXECUTABLE(ipses-delete ipses-delete.c)
-ADD_EXECUTABLE(ipses-add-net ipses-add-net.c)
-
-if (LIBNL2)
- TARGET_LINK_LIBRARIES(ipses-create nl nl-genl m)
- TARGET_LINK_LIBRARIES(ipses-delete nl nl-genl m)
- TARGET_LINK_LIBRARIES(ipses-add-net nl nl-genl m)
-else (LIBNL2)
- TARGET_LINK_LIBRARIES(ipses-create nl)
- TARGET_LINK_LIBRARIES(ipses-delete nl)
- TARGET_LINK_LIBRARIES(ipses-add-net nl)
-endif (LIBNL2)
-
-
diff --git a/ipoe-util/ipoe.h b/ipoe-util/ipoe.h
deleted file mode 120000
index 7117b41..0000000
--- a/ipoe-util/ipoe.h
+++ /dev/null
@@ -1 +0,0 @@
-../drivers/ipoe/ipoe.h \ No newline at end of file
diff --git a/ipoe-util/ipses-add-net.c b/ipoe-util/ipses-add-net.c
deleted file mode 100644
index 3e9df23..0000000
--- a/ipoe-util/ipses-add-net.c
+++ /dev/null
@@ -1,64 +0,0 @@
-#include <net/ethernet.h>
-#include <netinet/in.h>
-#include <netinet/ether.h>
-#include <arpa/inet.h>
-#include <string.h>
-#include <errno.h>
-#include <stdio.h>
-
-#include <netlink/netlink.h>
-#include <netlink/genl/genl.h>
-#include <netlink/genl/ctrl.h>
-
-
-#include "ipoe.h"
-
-int main(int argc, char **argv)
-{
-#if LIBNL2
- struct nl_sock *h;
-#else
- struct nl_handle *h;
-#endif
- struct nl_msg *msg;
- int family;
- in_addr_t local, remote;
- int err;
- uint32_t addr;
- int m;
-
- if (argc != 3) {
- printf("usage: ipses-add-net <addr> <mask>\n");
- return 1;
- }
-
- addr = inet_addr(argv[1]);
- m = atoi(argv[2]);
-
-#if LIBNL2
- h = nl_socket_alloc();
-#else
- h = nl_handle_alloc();
-#endif
- genl_connect(h);
- family = genl_ctrl_resolve(h, IPOE_GENL_NAME);
-
- msg = nlmsg_alloc();
- genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, NLM_F_REQUEST, IPOE_CMD_ADD_NET, IPOE_GENL_VERSION);
- nla_put_u32(msg, IPOE_ATTR_ADDR, addr);
- nla_put_u64(msg, IPOE_ATTR_MASK, (1 << m) - 1);
-
- nl_send_auto_complete(h, msg);
- err = nl_recvmsgs_default(h);
-#if LIBNL2
- printf("recv: %s\n", nl_geterror(err));
-#else
- nl_perror("recv");
-#endif
-
- nlmsg_free(msg);
- nl_close(h);
-
- return 0;
-}
-
diff --git a/ipoe-util/ipses-create.c b/ipoe-util/ipses-create.c
deleted file mode 100644
index 4c02cc6..0000000
--- a/ipoe-util/ipses-create.c
+++ /dev/null
@@ -1,71 +0,0 @@
-#include <net/ethernet.h>
-#include <netinet/in.h>
-#include <netinet/ether.h>
-#include <arpa/inet.h>
-#include <string.h>
-#include <errno.h>
-#include <stdio.h>
-
-#include <netlink/netlink.h>
-#include <netlink/genl/genl.h>
-#include <netlink/genl/ctrl.h>
-
-
-#include "ipoe.h"
-
-int main(int argc, char **argv)
-{
-#if LIBNL2
- struct nl_sock *h;
-#else
- struct nl_handle *h;
-#endif
- struct nl_msg *msg;
- int family;
- in_addr_t local, remote;
- int err;
- union {
- struct ether_addr a;
- uint64_t u64;
- } hwaddr;
-
- if (argc != 4 && argc != 5) {
- printf("usage: ipses-create <ifname> <hwaddr> <peer_addr> <addr>\n");
- return 1;
- }
-
- ether_aton_r(argv[2], &hwaddr.a);
- local = inet_addr(argv[3]);
- if (argc == 5)
- remote = inet_addr(argv[4]);
-
-#if LIBNL2
- h = nl_socket_alloc();
-#else
- h = nl_handle_alloc();
-#endif
- genl_connect(h);
- family = genl_ctrl_resolve(h, IPOE_GENL_NAME);
-
- msg = nlmsg_alloc();
- genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, NLM_F_REQUEST, IPOE_CMD_CREATE, IPOE_GENL_VERSION);
- nla_put_u32(msg, IPOE_ATTR_PEER_ADDR, local);
- nla_put_string(msg, IPOE_ATTR_IFNAME, argv[1]);
- nla_put_u64(msg, IPOE_ATTR_HWADDR, hwaddr.u64);
- if (argc == 5)
- nla_put_u32(msg, IPOE_ATTR_ADDR, remote);
-
- nl_send_auto_complete(h, msg);
- err = nl_recvmsgs_default(h);
-#if LIBNL2
- printf("recv: %s\n", nl_geterror(err));
-#else
- nl_perror("recv");
-#endif
-
- nlmsg_free(msg);
- nl_close(h);
-
- return 0;
-}
-
diff --git a/ipoe-util/ipses-delete.c b/ipoe-util/ipses-delete.c
deleted file mode 100644
index 4e6a184..0000000
--- a/ipoe-util/ipses-delete.c
+++ /dev/null
@@ -1,58 +0,0 @@
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <string.h>
-#include <errno.h>
-#include <stdio.h>
-
-#include <netlink/netlink.h>
-#include <netlink/genl/genl.h>
-#include <netlink/genl/ctrl.h>
-
-
-#include "ipoe.h"
-
-int main(int argc, char **argv)
-{
-#if LIBNL2
- struct nl_sock *h;
-#else
- struct nl_handle *h;
-#endif
- struct nl_msg *msg;
- int family;
- in_addr_t local;
- int err;
-
- if (argc != 2) {
- printf("usage: ipses-delete <addr>\n");
- return 1;
- }
-
- local = inet_addr(argv[1]);
-
-#if LIBNL2
- h = nl_socket_alloc();
-#else
- h = nl_handle_alloc();
-#endif
- genl_connect(h);
- family = genl_ctrl_resolve(h, IPOE_GENL_NAME);
-
- msg = nlmsg_alloc();
- genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, NLM_F_REQUEST, IPOE_CMD_DELETE, IPOE_GENL_VERSION);
- nla_put_u32(msg, IPOE_ATTR_PEER_ADDR, local);
-
- nl_send_auto_complete(h, msg);
- err = nl_recvmsgs_default(h);
-#if LIBNL2
- printf("recv: %s\n", nl_geterror(err));
-#else
- nl_perror("recv");
-#endif
-
- nlmsg_free(msg);
- nl_close(h);
-
- return 0;
-}
-