Fix minor bug.
Add draft of ac kernel module.
This commit is contained in:
parent
2d6c4c4dd8
commit
71006a9121
@ -25,15 +25,16 @@ bin_PROGRAMS = ac
|
|||||||
AM_CFLAGS = \
|
AM_CFLAGS = \
|
||||||
-DCAPWAP_MULTITHREADING_ENABLE \
|
-DCAPWAP_MULTITHREADING_ENABLE \
|
||||||
-D_REENTRANT \
|
-D_REENTRANT \
|
||||||
-D_GNU_SOURCE
|
-D_GNU_SOURCE \
|
||||||
|
${LIBNL_CFLAGS} \
|
||||||
AM_CFLAGS += $(LIBXML2_CFLAGS) \
|
$(LIBXML2_CFLAGS) \
|
||||||
$(CYASSL_CFLAGS)
|
$(CYASSL_CFLAGS)
|
||||||
|
|
||||||
INCLUDES = \
|
INCLUDES = \
|
||||||
-I$(top_srcdir)/build \
|
-I$(top_srcdir)/build \
|
||||||
-I$(top_srcdir)/src/common \
|
-I$(top_srcdir)/src/common \
|
||||||
-I$(top_srcdir)/src/ac \
|
-I$(top_srcdir)/src/ac \
|
||||||
|
-I$(top_srcdir)/src/ac/kmod \
|
||||||
-I$(top_srcdir)/src/common/binding/ieee80211
|
-I$(top_srcdir)/src/common/binding/ieee80211
|
||||||
|
|
||||||
include $(top_srcdir)/build/Makefile_common.am
|
include $(top_srcdir)/build/Makefile_common.am
|
||||||
@ -50,6 +51,7 @@ ac_SOURCES = \
|
|||||||
$(top_srcdir)/src/ac/ac_session.c \
|
$(top_srcdir)/src/ac/ac_session.c \
|
||||||
$(top_srcdir)/src/ac/ac_session_data.c \
|
$(top_srcdir)/src/ac/ac_session_data.c \
|
||||||
$(top_srcdir)/src/ac/ac_wlans.c \
|
$(top_srcdir)/src/ac/ac_wlans.c \
|
||||||
|
$(top_srcdir)/src/ac/ac_kmod.c \
|
||||||
$(top_srcdir)/src/ac/ac_ieee80211_data.c \
|
$(top_srcdir)/src/ac/ac_ieee80211_data.c \
|
||||||
$(top_srcdir)/src/ac/ac_discovery.c \
|
$(top_srcdir)/src/ac/ac_discovery.c \
|
||||||
$(top_srcdir)/src/ac/ac_80211_json.c \
|
$(top_srcdir)/src/ac/ac_80211_json.c \
|
||||||
@ -90,4 +92,5 @@ ac_LDADD = \
|
|||||||
$(PTHREAD_LIBS) \
|
$(PTHREAD_LIBS) \
|
||||||
$(LIBXML2_LIBS) \
|
$(LIBXML2_LIBS) \
|
||||||
$(LIBJSON_LIBS) \
|
$(LIBJSON_LIBS) \
|
||||||
$(CYASSL_LIBS)
|
$(CYASSL_LIBS) \
|
||||||
|
$(LIBNL_LIBS)
|
||||||
|
@ -24,7 +24,8 @@ bin_PROGRAMS = wtp
|
|||||||
|
|
||||||
AM_CFLAGS = \
|
AM_CFLAGS = \
|
||||||
-D_REENTRANT \
|
-D_REENTRANT \
|
||||||
-D_GNU_SOURCE
|
-D_GNU_SOURCE \
|
||||||
|
${LIBNL_CFLAGS}
|
||||||
|
|
||||||
if DTLS_ENABLED
|
if DTLS_ENABLED
|
||||||
AM_CFLAGS += $(CYASSL_CFLAGS)
|
AM_CFLAGS += $(CYASSL_CFLAGS)
|
||||||
@ -62,7 +63,8 @@ wtp_SOURCES = \
|
|||||||
$(top_srcdir)/src/wtp/binding/ieee80211/wifi_drivers.c
|
$(top_srcdir)/src/wtp/binding/ieee80211/wifi_drivers.c
|
||||||
|
|
||||||
wtp_LDADD = \
|
wtp_LDADD = \
|
||||||
$(CONFIG_LIBS)
|
$(CONFIG_LIBS) \
|
||||||
|
$(LIBNL_LIBS)
|
||||||
|
|
||||||
if DTLS_ENABLED
|
if DTLS_ENABLED
|
||||||
wtp_LDADD += $(CYASSL_LIBS)
|
wtp_LDADD += $(CYASSL_LIBS)
|
||||||
@ -70,7 +72,4 @@ endif
|
|||||||
|
|
||||||
if BUILD_WTP_WIFI_DRIVERS_NL80211
|
if BUILD_WTP_WIFI_DRIVERS_NL80211
|
||||||
wtp_SOURCES += $(top_srcdir)/src/wtp/binding/ieee80211/wifi_nl80211.c
|
wtp_SOURCES += $(top_srcdir)/src/wtp/binding/ieee80211/wifi_nl80211.c
|
||||||
AM_CFLAGS += ${LIBNL_CFLAGS}
|
|
||||||
wtp_LDADD += $(LIBNL_LIBS)
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
30
configure.ac
30
configure.ac
@ -208,22 +208,24 @@ if test "${enable_ac}" = "yes"; then
|
|||||||
)
|
)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Check Netlink library
|
||||||
|
PKG_CHECK_MODULES(
|
||||||
|
[LIBNL],
|
||||||
|
[libnl-1],
|
||||||
|
[AC_DEFINE([HAVE_LIBNL_10], [1], [Use libnl-1.0 library])],
|
||||||
|
[PKG_CHECK_MODULES(
|
||||||
|
[LIBNL],
|
||||||
|
[libnl-tiny],
|
||||||
|
[AC_DEFINE([HAVE_LIBNL_TINY], [1], [Use libnl-tiny library])],
|
||||||
|
[AC_MSG_ERROR(You need the libnl or libnl-tiny)]
|
||||||
|
)]
|
||||||
|
)
|
||||||
|
|
||||||
|
AC_CHECK_HEADERS([netlink/genl/genl.h netlink/genl/family.h netlink/genl/ctrl.h], [], [AC_MSG_ERROR(You need the netlink header)])
|
||||||
|
AC_CHECK_HEADER([linux/nl80211.h], [], [AC_MSG_ERROR(You need the nl80211 header)])
|
||||||
|
|
||||||
# Check nl80211
|
# Check nl80211
|
||||||
if test "${enable_wifi_drivers_nl80211}" = "yes"; then
|
if test "${enable_wifi_drivers_nl80211}" = "yes"; then
|
||||||
PKG_CHECK_MODULES(
|
|
||||||
[LIBNL],
|
|
||||||
[libnl-1],
|
|
||||||
[AC_DEFINE([HAVE_LIBNL_10], [1], [Use libnl-1.0 library])],
|
|
||||||
[PKG_CHECK_MODULES(
|
|
||||||
[LIBNL],
|
|
||||||
[libnl-tiny],
|
|
||||||
[AC_DEFINE([HAVE_LIBNL_TINY], [1], [Use libnl-tiny library])],
|
|
||||||
[AC_MSG_ERROR(You need the libnl or libnl-tiny)]
|
|
||||||
)]
|
|
||||||
)
|
|
||||||
|
|
||||||
AC_CHECK_HEADERS([netlink/genl/genl.h netlink/genl/family.h netlink/genl/ctrl.h], [], [AC_MSG_ERROR(You need the netlink header)])
|
|
||||||
AC_CHECK_HEADER([linux/nl80211.h], [], [AC_MSG_ERROR(You need the nl80211 header)])
|
|
||||||
AC_DEFINE([ENABLE_WIFI_DRIVERS_NL80211], [1], [Enable WTP support for nl80211 wifi binding])
|
AC_DEFINE([ENABLE_WIFI_DRIVERS_NL80211], [1], [Enable WTP support for nl80211 wifi binding])
|
||||||
fi
|
fi
|
||||||
AM_CONDITIONAL([BUILD_WTP_WIFI_DRIVERS_NL80211], [test "${enable_wifi_drivers_nl80211}" = "yes"])
|
AM_CONDITIONAL([BUILD_WTP_WIFI_DRIVERS_NL80211], [test "${enable_wifi_drivers_nl80211}" = "yes"])
|
||||||
|
21
src/ac/ac.c
21
src/ac/ac.c
@ -833,11 +833,24 @@ int main(int argc, char** argv) {
|
|||||||
/* Complete configuration AC */
|
/* Complete configuration AC */
|
||||||
result = ac_configure();
|
result = ac_configure();
|
||||||
if (result == CAPWAP_SUCCESSFUL) {
|
if (result == CAPWAP_SUCCESSFUL) {
|
||||||
/* Running AC */
|
/* Connect AC to kernel module */
|
||||||
result = ac_execute();
|
value = ac_kmod_init();
|
||||||
|
if (!value || !g_ac.kmodrequest) {
|
||||||
|
if (ac_kmod_isconnected()) {
|
||||||
|
capwap_logging_info("SmartCAPWAP kernel module connected");
|
||||||
|
}
|
||||||
|
|
||||||
/* Close connection */
|
/* Running AC */
|
||||||
ac_close();
|
result = ac_execute();
|
||||||
|
|
||||||
|
/* Close connection */
|
||||||
|
ac_close();
|
||||||
|
|
||||||
|
/* Disconnect kernel module */
|
||||||
|
ac_kmod_free();
|
||||||
|
} else {
|
||||||
|
capwap_logging_fatal("Unable to connect to kernel module");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
24
src/ac/ac.h
24
src/ac/ac.h
@ -15,6 +15,8 @@
|
|||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <linux/if_ether.h>
|
#include <linux/if_ether.h>
|
||||||
|
|
||||||
|
#include <ac_kmod.h>
|
||||||
|
|
||||||
/* AC Configuration */
|
/* AC Configuration */
|
||||||
#define AC_DEFAULT_CONFIGURATION_FILE "/etc/capwap/ac.conf"
|
#define AC_DEFAULT_CONFIGURATION_FILE "/etc/capwap/ac.conf"
|
||||||
|
|
||||||
@ -73,6 +75,21 @@ struct ac_state {
|
|||||||
struct capwap_acipv6list_element acipv6list;
|
struct capwap_acipv6list_element acipv6list;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* */
|
||||||
|
struct ac_fds {
|
||||||
|
int fdstotalcount;
|
||||||
|
struct pollfd* fdspoll;
|
||||||
|
|
||||||
|
int fdsnetworkcount;
|
||||||
|
|
||||||
|
int msgqueuecount;
|
||||||
|
int msgqueuestartpos;
|
||||||
|
|
||||||
|
struct ac_kmod_event* kmodevents;
|
||||||
|
int kmodeventscount;
|
||||||
|
int kmodeventsstartpos;
|
||||||
|
};
|
||||||
|
|
||||||
/* AC */
|
/* AC */
|
||||||
struct ac_t {
|
struct ac_t {
|
||||||
int standalone;
|
int standalone;
|
||||||
@ -83,6 +100,8 @@ struct ac_t {
|
|||||||
struct capwap_network net;
|
struct capwap_network net;
|
||||||
unsigned short mtu;
|
unsigned short mtu;
|
||||||
|
|
||||||
|
struct ac_fds fds;
|
||||||
|
|
||||||
struct capwap_array* binding;
|
struct capwap_array* binding;
|
||||||
|
|
||||||
struct capwap_acname_element acname;
|
struct capwap_acname_element acname;
|
||||||
@ -91,6 +110,10 @@ struct ac_t {
|
|||||||
/* Sessions message queue */
|
/* Sessions message queue */
|
||||||
int fdmsgsessions[2];
|
int fdmsgsessions[2];
|
||||||
|
|
||||||
|
/* */
|
||||||
|
int kmodrequest;
|
||||||
|
struct ac_kmod_handle kmodhandle;
|
||||||
|
|
||||||
/* Sessions */
|
/* Sessions */
|
||||||
struct capwap_list* sessions;
|
struct capwap_list* sessions;
|
||||||
struct capwap_list* sessionsdata;
|
struct capwap_list* sessionsdata;
|
||||||
@ -133,6 +156,7 @@ extern struct ac_t g_ac;
|
|||||||
|
|
||||||
/* Primary thread */
|
/* Primary thread */
|
||||||
int ac_execute(void);
|
int ac_execute(void);
|
||||||
|
int ac_execute_update_fdspool(struct ac_fds* fds);
|
||||||
|
|
||||||
int ac_valid_binding(unsigned short binding);
|
int ac_valid_binding(unsigned short binding);
|
||||||
void ac_update_statistics(void);
|
void ac_update_statistics(void);
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
#define AC_RECV_NOERROR_MSGQUEUE -1001
|
#define AC_RECV_NOERROR_MSGQUEUE -1001
|
||||||
|
#define AC_RECV_NOERROR_KMODEVENT -1002
|
||||||
|
|
||||||
/* */
|
/* */
|
||||||
static int ac_recvmsgqueue(int fd, struct ac_session_msgqueue_item_t* item) {
|
static int ac_recvmsgqueue(int fd, struct ac_session_msgqueue_item_t* item) {
|
||||||
@ -103,11 +104,12 @@ void ac_msgqueue_notify_closethread(pthread_t threadid) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* */
|
/* */
|
||||||
static int ac_recvfrom(struct pollfd* fds, int fdscount, void* buffer, int* size, struct sockaddr_storage* recvfromaddr, struct sockaddr_storage* recvtoaddr) {
|
static int ac_recvfrom(struct ac_fds* fds, void* buffer, int* size, struct sockaddr_storage* recvfromaddr, struct sockaddr_storage* recvtoaddr) {
|
||||||
int index;
|
int index;
|
||||||
|
|
||||||
ASSERT(fds);
|
ASSERT(fds);
|
||||||
ASSERT(fdscount > 0);
|
ASSERT(fds->fdspoll != NULL);
|
||||||
|
ASSERT(fds->fdstotalcount > 0);
|
||||||
ASSERT(buffer != NULL);
|
ASSERT(buffer != NULL);
|
||||||
ASSERT(size != NULL);
|
ASSERT(size != NULL);
|
||||||
ASSERT(*size > 0);
|
ASSERT(*size > 0);
|
||||||
@ -115,25 +117,36 @@ static int ac_recvfrom(struct pollfd* fds, int fdscount, void* buffer, int* size
|
|||||||
ASSERT(recvtoaddr != NULL);
|
ASSERT(recvtoaddr != NULL);
|
||||||
|
|
||||||
/* Wait packet */
|
/* Wait packet */
|
||||||
index = capwap_wait_recvready(fds, fdscount, NULL);
|
index = capwap_wait_recvready(fds->fdspoll, fds->fdstotalcount, NULL);
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
return index;
|
return index;
|
||||||
} else if (index == (fdscount - 1)) {
|
} else if ((fds->kmodeventsstartpos >= 0) && (index >= fds->kmodeventsstartpos)) {
|
||||||
|
int pos = index - fds->kmodeventsstartpos;
|
||||||
|
|
||||||
|
if (pos < fds->kmodeventscount) {
|
||||||
|
if (!fds->kmodevents[pos].event_handler) {
|
||||||
|
return CAPWAP_RECV_ERROR_SOCKET;
|
||||||
|
}
|
||||||
|
|
||||||
|
fds->kmodevents[pos].event_handler(fds->fdspoll[index].fd, fds->kmodevents[pos].params, fds->kmodevents[pos].paramscount);
|
||||||
|
}
|
||||||
|
|
||||||
|
return AC_RECV_NOERROR_KMODEVENT;
|
||||||
|
} else if ((fds->msgqueuestartpos >= 0) && (index >= fds->msgqueuestartpos)) {
|
||||||
struct ac_session_msgqueue_item_t item;
|
struct ac_session_msgqueue_item_t item;
|
||||||
|
|
||||||
/* Receive message queue packet */
|
/* Receive message queue packet */
|
||||||
if (!ac_recvmsgqueue(fds[index].fd, &item)) {
|
if (!ac_recvmsgqueue(fds->fdspoll[index].fd, &item)) {
|
||||||
return CAPWAP_RECV_ERROR_SOCKET;
|
return CAPWAP_RECV_ERROR_SOCKET;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parsing message queue packet */
|
/* Parsing message queue packet */
|
||||||
ac_session_msgqueue_parsing_item(&item);
|
ac_session_msgqueue_parsing_item(&item);
|
||||||
|
|
||||||
return AC_RECV_NOERROR_MSGQUEUE;
|
return AC_RECV_NOERROR_MSGQUEUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Receive packet */
|
/* Receive packet */
|
||||||
if (!capwap_recvfrom_fd(fds[index].fd, buffer, size, recvfromaddr, recvtoaddr)) {
|
if (!capwap_recvfrom_fd(fds->fdspoll[index].fd, buffer, size, recvfromaddr, recvtoaddr)) {
|
||||||
return CAPWAP_RECV_ERROR_SOCKET;
|
return CAPWAP_RECV_ERROR_SOCKET;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -703,32 +716,118 @@ static void ac_signal_handler(int signum) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
static int ac_execute_init_fdspool(struct ac_fds* fds, struct capwap_network* net, int fdmsgqueue) {
|
||||||
|
ASSERT(fds != NULL);
|
||||||
|
ASSERT(net != NULL);
|
||||||
|
ASSERT(fdmsgqueue > 0);
|
||||||
|
|
||||||
|
/* */
|
||||||
|
memset(fds, 0, sizeof(struct ac_fds));
|
||||||
|
fds->fdsnetworkcount = capwap_network_set_pollfd(net, NULL, 0);
|
||||||
|
fds->msgqueuecount = 1;
|
||||||
|
fds->fdspoll = (struct pollfd*)capwap_alloc(sizeof(struct pollfd) * (fds->fdsnetworkcount + fds->msgqueuecount));
|
||||||
|
|
||||||
|
/* Retrive all socket for polling */
|
||||||
|
fds->fdstotalcount = capwap_network_set_pollfd(net, fds->fdspoll, fds->fdsnetworkcount);
|
||||||
|
if (fds->fdsnetworkcount != fds->fdstotalcount) {
|
||||||
|
capwap_free(fds->fdspoll);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unix socket message queue */
|
||||||
|
fds->msgqueuestartpos = fds->fdsnetworkcount;
|
||||||
|
fds->fdspoll[fds->msgqueuestartpos].events = POLLIN | POLLERR | POLLHUP | POLLNVAL;
|
||||||
|
fds->fdspoll[fds->msgqueuestartpos].fd = fdmsgqueue;
|
||||||
|
fds->fdstotalcount += fds->msgqueuecount;
|
||||||
|
|
||||||
|
return ac_execute_update_fdspool(fds);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
static void ac_execute_free_fdspool(struct ac_fds* fds) {
|
||||||
|
ASSERT(fds != NULL);
|
||||||
|
|
||||||
|
if (fds->fdspoll) {
|
||||||
|
capwap_free(fds->fdspoll);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fds->kmodevents) {
|
||||||
|
capwap_free(fds->kmodevents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
int ac_execute_update_fdspool(struct ac_fds* fds) {
|
||||||
|
int totalcount;
|
||||||
|
int kmodcount;
|
||||||
|
struct pollfd* fdsbuffer;
|
||||||
|
|
||||||
|
ASSERT(fds != NULL);
|
||||||
|
|
||||||
|
/* Retrieve number of Dynamic File Descriptor Event */
|
||||||
|
kmodcount = ac_kmod_getfd(NULL, NULL, 0);
|
||||||
|
if (kmodcount < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Kernel Module Events Callback */
|
||||||
|
fds->kmodeventsstartpos = -1;
|
||||||
|
if (kmodcount != fds->kmodeventscount) {
|
||||||
|
if (fds->kmodevents) {
|
||||||
|
capwap_free(fds->kmodevents);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
fds->kmodeventscount = kmodcount;
|
||||||
|
fds->kmodevents = (struct ac_kmod_event*)((kmodcount > 0) ? capwap_alloc(sizeof(struct ac_kmod_event) * kmodcount) : NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Resize poll */
|
||||||
|
totalcount = fds->fdsnetworkcount + fds->msgqueuecount + fds->kmodeventscount;
|
||||||
|
if (fds->fdstotalcount != totalcount) {
|
||||||
|
fdsbuffer = (struct pollfd*)capwap_alloc(sizeof(struct pollfd) * totalcount);
|
||||||
|
if (fds->fdspoll) {
|
||||||
|
int count = fds->fdsnetworkcount + fds->msgqueuecount;
|
||||||
|
if (count > 0) {
|
||||||
|
memcpy(fdsbuffer, fds->fdspoll, sizeof(struct pollfd) * count);
|
||||||
|
}
|
||||||
|
|
||||||
|
capwap_free(fds->fdspoll);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
fds->fdspoll = fdsbuffer;
|
||||||
|
fds->fdstotalcount = totalcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Retrieve File Descriptor Kernel Module Event */
|
||||||
|
if (fds->kmodeventscount > 0) {
|
||||||
|
fds->kmodeventsstartpos = fds->fdsnetworkcount + fds->msgqueuecount;
|
||||||
|
ac_kmod_getfd(&fds->fdspoll[fds->kmodeventsstartpos], fds->kmodevents, fds->kmodeventscount);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fds->fdstotalcount;
|
||||||
|
}
|
||||||
|
|
||||||
/* AC running */
|
/* AC running */
|
||||||
int ac_execute(void) {
|
int ac_execute(void) {
|
||||||
struct pollfd* fds;
|
|
||||||
int result = CAPWAP_SUCCESSFUL;
|
int result = CAPWAP_SUCCESSFUL;
|
||||||
int fdscount = CAPWAP_MAX_SOCKETS * 2 + 1;
|
|
||||||
|
|
||||||
int index;
|
int index;
|
||||||
int check;
|
int check;
|
||||||
int isctrlsocket = 0;
|
struct capwap_socket socket;
|
||||||
struct sockaddr_storage recvfromaddr;
|
struct sockaddr_storage recvfromaddr;
|
||||||
struct sockaddr_storage recvtoaddr;
|
struct sockaddr_storage recvtoaddr;
|
||||||
|
|
||||||
char buffer[CAPWAP_MAX_PACKET_SIZE];
|
char buffer[CAPWAP_MAX_PACKET_SIZE];
|
||||||
int buffersize;
|
int buffersize;
|
||||||
|
|
||||||
/* Configure poll struct */
|
/* Set file descriptor pool */
|
||||||
fds = (struct pollfd*)capwap_alloc(sizeof(struct pollfd) * fdscount);
|
if (ac_execute_init_fdspool(&g_ac.fds, &g_ac.net, g_ac.fdmsgsessions[1]) <= 0) {
|
||||||
|
capwap_logging_debug("Unable to initialize file descriptor pool");
|
||||||
/* Retrive all socket for polling */
|
return AC_ERROR_SYSTEM_FAILER;
|
||||||
fdscount = capwap_network_set_pollfd(&g_ac.net, fds, fdscount);
|
}
|
||||||
ASSERT(fdscount > 0);
|
|
||||||
|
|
||||||
/* Unix socket message queue */
|
|
||||||
fds[fdscount].events = POLLIN | POLLERR | POLLHUP | POLLNVAL;
|
|
||||||
fds[fdscount].fd = g_ac.fdmsgsessions[1];
|
|
||||||
fdscount++;
|
|
||||||
|
|
||||||
/* Handler signal */
|
/* Handler signal */
|
||||||
g_ac.running = 1;
|
g_ac.running = 1;
|
||||||
@ -738,14 +837,14 @@ int ac_execute(void) {
|
|||||||
|
|
||||||
/* Start discovery thread */
|
/* Start discovery thread */
|
||||||
if (!ac_discovery_start()) {
|
if (!ac_discovery_start()) {
|
||||||
capwap_free(fds);
|
ac_execute_free_fdspool(&g_ac.fds);
|
||||||
capwap_logging_debug("Unable to start discovery thread");
|
capwap_logging_debug("Unable to start discovery thread");
|
||||||
return AC_ERROR_SYSTEM_FAILER;
|
return AC_ERROR_SYSTEM_FAILER;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Enable Backend Management */
|
/* Enable Backend Management */
|
||||||
if (!ac_backend_start()) {
|
if (!ac_backend_start()) {
|
||||||
capwap_free(fds);
|
ac_execute_free_fdspool(&g_ac.fds);
|
||||||
ac_discovery_stop();
|
ac_discovery_stop();
|
||||||
capwap_logging_error("Unable start backend management");
|
capwap_logging_error("Unable start backend management");
|
||||||
return AC_ERROR_SYSTEM_FAILER;
|
return AC_ERROR_SYSTEM_FAILER;
|
||||||
@ -755,7 +854,7 @@ int ac_execute(void) {
|
|||||||
while (g_ac.running) {
|
while (g_ac.running) {
|
||||||
/* Receive packet */
|
/* Receive packet */
|
||||||
buffersize = sizeof(buffer);
|
buffersize = sizeof(buffer);
|
||||||
index = ac_recvfrom(fds, fdscount, buffer, &buffersize, &recvfromaddr, &recvtoaddr);
|
index = ac_recvfrom(&g_ac.fds, buffer, &buffersize, &recvfromaddr, &recvtoaddr);
|
||||||
if (!g_ac.running) {
|
if (!g_ac.running) {
|
||||||
capwap_logging_debug("Closing AC");
|
capwap_logging_debug("Closing AC");
|
||||||
break;
|
break;
|
||||||
@ -770,7 +869,7 @@ int ac_execute(void) {
|
|||||||
socklen_t sockinfolen = sizeof(struct sockaddr_storage);
|
socklen_t sockinfolen = sizeof(struct sockaddr_storage);
|
||||||
|
|
||||||
memset(&sockinfo, 0, sizeof(struct sockaddr_storage));
|
memset(&sockinfo, 0, sizeof(struct sockaddr_storage));
|
||||||
if (getsockname(fds[index].fd, (struct sockaddr*)&sockinfo, &sockinfolen) < 0) {
|
if (getsockname(g_ac.fds.fdspoll[index].fd, (struct sockaddr*)&sockinfo, &sockinfolen) < 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -778,9 +877,11 @@ int ac_execute(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Retrieve network information */
|
||||||
|
capwap_get_network_socket(&g_ac.net, &socket, g_ac.fds.fdspoll[index].fd);
|
||||||
|
|
||||||
/* Search the AC session / session data */
|
/* Search the AC session / session data */
|
||||||
isctrlsocket = ((index < (fdscount / 2)) ? 1 : 0);
|
if (socket.isctrlsocket) {
|
||||||
if (isctrlsocket) {
|
|
||||||
struct ac_session_t* session = ac_search_session_from_wtpaddress(&recvfromaddr);
|
struct ac_session_t* session = ac_search_session_from_wtpaddress(&recvfromaddr);
|
||||||
|
|
||||||
if (session) {
|
if (session) {
|
||||||
@ -813,15 +914,10 @@ int ac_execute(void) {
|
|||||||
unsigned long type = ntohl(control->type);
|
unsigned long type = ntohl(control->type);
|
||||||
|
|
||||||
if (type == CAPWAP_DISCOVERY_REQUEST) {
|
if (type == CAPWAP_DISCOVERY_REQUEST) {
|
||||||
ac_discovery_add_packet(buffer, buffersize, fds[index].fd, &recvfromaddr);
|
ac_discovery_add_packet(buffer, buffersize, g_ac.fds.fdspoll[index].fd, &recvfromaddr);
|
||||||
} else if (!g_ac.enabledtls && (type == CAPWAP_JOIN_REQUEST)) {
|
} else if (!g_ac.enabledtls && (type == CAPWAP_JOIN_REQUEST)) {
|
||||||
struct capwap_socket ctrlsock;
|
|
||||||
|
|
||||||
/* Retrive socket info */
|
|
||||||
capwap_get_network_socket(&g_ac.net, &ctrlsock, fds[index].fd);
|
|
||||||
|
|
||||||
/* Create a new session */
|
/* Create a new session */
|
||||||
session = ac_create_session(&recvfromaddr, &recvtoaddr, &ctrlsock);
|
session = ac_create_session(&recvfromaddr, &recvtoaddr, &socket);
|
||||||
ac_session_add_packet(session, buffer, buffersize, 1);
|
ac_session_add_packet(session, buffer, buffersize, 1);
|
||||||
|
|
||||||
/* Release reference */
|
/* Release reference */
|
||||||
@ -832,13 +928,8 @@ int ac_execute(void) {
|
|||||||
} else if (check == CAPWAP_DTLS_PACKET) {
|
} else if (check == CAPWAP_DTLS_PACKET) {
|
||||||
/* Before create new session check if receive DTLS Client Hello */
|
/* Before create new session check if receive DTLS Client Hello */
|
||||||
if (capwap_crypt_has_dtls_clienthello(&((char*)buffer)[sizeof(struct capwap_dtls_header)], buffersize - sizeof(struct capwap_dtls_header))) {
|
if (capwap_crypt_has_dtls_clienthello(&((char*)buffer)[sizeof(struct capwap_dtls_header)], buffersize - sizeof(struct capwap_dtls_header))) {
|
||||||
struct capwap_socket ctrlsock;
|
|
||||||
|
|
||||||
/* Retrive socket info */
|
|
||||||
capwap_get_network_socket(&g_ac.net, &ctrlsock, fds[index].fd);
|
|
||||||
|
|
||||||
/* Create a new session */
|
/* Create a new session */
|
||||||
session = ac_create_session(&recvfromaddr, &recvtoaddr, &ctrlsock);
|
session = ac_create_session(&recvfromaddr, &recvtoaddr, &socket);
|
||||||
ac_session_add_packet(session, buffer, buffersize, 0);
|
ac_session_add_packet(session, buffer, buffersize, 0);
|
||||||
|
|
||||||
/* Release reference */
|
/* Release reference */
|
||||||
@ -875,13 +966,8 @@ int ac_execute(void) {
|
|||||||
|
|
||||||
/* */
|
/* */
|
||||||
if (plain >= 0) {
|
if (plain >= 0) {
|
||||||
struct capwap_socket datasock;
|
|
||||||
|
|
||||||
/* Retrive socket info */
|
|
||||||
capwap_get_network_socket(&g_ac.net, &datasock, fds[index].fd);
|
|
||||||
|
|
||||||
/* Create a new session */
|
/* Create a new session */
|
||||||
sessiondata = ac_create_session_data(&recvfromaddr, &recvtoaddr, &datasock, plain);
|
sessiondata = ac_create_session_data(&recvfromaddr, &recvtoaddr, &socket, plain);
|
||||||
ac_session_data_add_packet(sessiondata, buffer, buffersize, 0);
|
ac_session_data_add_packet(sessiondata, buffer, buffersize, 0);
|
||||||
|
|
||||||
/* Release reference */
|
/* Release reference */
|
||||||
@ -889,7 +975,7 @@ int ac_execute(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if ((index == CAPWAP_RECV_ERROR_INTR) || (index == AC_RECV_NOERROR_MSGQUEUE)) {
|
} else if ((index == CAPWAP_RECV_ERROR_INTR) || (index == AC_RECV_NOERROR_MSGQUEUE) || (index == AC_RECV_NOERROR_KMODEVENT)) {
|
||||||
/* Ignore recv */
|
/* Ignore recv */
|
||||||
continue;
|
continue;
|
||||||
} else if (index == CAPWAP_RECV_ERROR_SOCKET) {
|
} else if (index == CAPWAP_RECV_ERROR_SOCKET) {
|
||||||
@ -913,7 +999,7 @@ int ac_execute(void) {
|
|||||||
/* Free Backend Management */
|
/* Free Backend Management */
|
||||||
ac_backend_free();
|
ac_backend_free();
|
||||||
|
|
||||||
/* Free memory */
|
/* Free file description pool */
|
||||||
capwap_free(fds);
|
ac_execute_free_fdspool(&g_ac.fds);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
278
src/ac/ac_kmod.c
Normal file
278
src/ac/ac_kmod.c
Normal file
@ -0,0 +1,278 @@
|
|||||||
|
#include "ac.h"
|
||||||
|
#include <netlink/genl/genl.h>
|
||||||
|
#include <netlink/genl/family.h>
|
||||||
|
#include <netlink/genl/ctrl.h>
|
||||||
|
#include "nlsmartcapwap.h"
|
||||||
|
|
||||||
|
/* Compatibility functions */
|
||||||
|
#ifdef HAVE_LIBNL_10
|
||||||
|
static uint32_t g_portbitmap[32] = { 0 };
|
||||||
|
|
||||||
|
static struct nl_sock* nl_socket_alloc_cb(void* cb) {
|
||||||
|
int i;
|
||||||
|
struct nl_sock* handle;
|
||||||
|
uint32_t pid = getpid() & 0x3FFFFF;
|
||||||
|
|
||||||
|
handle = nl_handle_alloc_cb(cb);
|
||||||
|
for (i = 0; i < 1024; i++) {
|
||||||
|
if (g_portbitmap[i / 32] & (1 << (i % 32))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_portbitmap[i / 32] |= 1 << (i % 32);
|
||||||
|
pid += i << 22;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
nl_socket_set_local_port(handle, pid);
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nl_socket_free(struct nl_sock* handle) {
|
||||||
|
uint32_t port = nl_socket_get_local_port(handle);
|
||||||
|
|
||||||
|
port >>= 22;
|
||||||
|
g_portbitmap[port / 32] &= ~(1 << (port % 32));
|
||||||
|
|
||||||
|
nl_handle_destroy(handle);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* */
|
||||||
|
typedef int (*ac_kmod_valid_cb)(struct nl_msg* msg, void* data);
|
||||||
|
|
||||||
|
/* */
|
||||||
|
static struct nl_sock* nl_create_handle(struct nl_cb* cb) {
|
||||||
|
struct nl_sock* handle;
|
||||||
|
|
||||||
|
handle = nl_socket_alloc_cb(cb);
|
||||||
|
if (!handle) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (genl_connect(handle)) {
|
||||||
|
nl_socket_free(handle);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
static int ac_kmod_no_seq_check(struct nl_msg* msg, void* arg) {
|
||||||
|
return NL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
static int ac_kmod_error_handler(struct sockaddr_nl* nla, struct nlmsgerr* err, void* arg) {
|
||||||
|
*((int*)arg) = err->error;
|
||||||
|
return NL_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
static int ac_kmod_finish_handler(struct nl_msg* msg, void* arg) {
|
||||||
|
*((int*)arg) = 0;
|
||||||
|
return NL_SKIP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
static int ac_kmod_ack_handler(struct nl_msg* msg, void* arg) {
|
||||||
|
*((int*)arg) = 0;
|
||||||
|
return NL_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
static int ac_kmod_event_handler(struct genlmsghdr* gnlh, struct nlattr** tb_msg, void* data) {
|
||||||
|
switch (gnlh->cmd) {
|
||||||
|
default: {
|
||||||
|
capwap_logging_debug("*** ac_kmod_event_handler: %d", (int)gnlh->cmd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NL_SKIP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
static int ac_kmod_valid_handler(struct nl_msg* msg, void* data) {
|
||||||
|
struct nlattr* tb_msg[NLSMARTCAPWAP_AC_ATTR_MAX + 1];
|
||||||
|
struct genlmsghdr* gnlh = nlmsg_data(nlmsg_hdr(msg));
|
||||||
|
|
||||||
|
nla_parse(tb_msg, NLSMARTCAPWAP_AC_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
|
||||||
|
|
||||||
|
return ac_kmod_event_handler(gnlh, tb_msg, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
static int ac_kmod_send_and_recv(struct nl_sock* nl, struct nl_cb* nl_cb, struct nl_msg* msg, ac_kmod_valid_cb valid_cb, void* data) {
|
||||||
|
int result;
|
||||||
|
struct nl_cb* cb;
|
||||||
|
|
||||||
|
/* Clone netlink callback */
|
||||||
|
cb = nl_cb_clone(nl_cb);
|
||||||
|
if (!cb) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Complete send message */
|
||||||
|
result = nl_send_auto_complete(nl, msg);
|
||||||
|
if (result < 0) {
|
||||||
|
nl_cb_put(cb);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Customize message callback */
|
||||||
|
nl_cb_err(cb, NL_CB_CUSTOM, ac_kmod_error_handler, &result);
|
||||||
|
nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, ac_kmod_finish_handler, &result);
|
||||||
|
nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ac_kmod_ack_handler, &result);
|
||||||
|
|
||||||
|
if (valid_cb) {
|
||||||
|
nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, valid_cb, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = 1;
|
||||||
|
while (result > 0) {
|
||||||
|
nl_recvmsgs(nl, cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
nl_cb_put(cb);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
static int ac_kmod_send_and_recv_msg(struct nl_msg* msg, ac_kmod_valid_cb valid_cb, void* data) {
|
||||||
|
return ac_kmod_send_and_recv(g_ac.kmodhandle.nl, g_ac.kmodhandle.nl_cb, msg, valid_cb, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
static int ac_kmod_link(void) {
|
||||||
|
int result;
|
||||||
|
struct nl_msg* msg;
|
||||||
|
|
||||||
|
/* */
|
||||||
|
msg = nlmsg_alloc();
|
||||||
|
if (!msg) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
genlmsg_put(msg, 0, 0, g_ac.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_AC_CMD_LINK, 0);
|
||||||
|
|
||||||
|
/* */
|
||||||
|
result = ac_kmod_send_and_recv_msg(msg, NULL, NULL);
|
||||||
|
if (result) {
|
||||||
|
if (result == -EALREADY) {
|
||||||
|
result = 0;
|
||||||
|
} else {
|
||||||
|
capwap_logging_warning("Unable to connect kernel module, error code: %d", result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
nlmsg_free(msg);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
static void ac_kmod_event_receive(int fd, void** params, int paramscount) {
|
||||||
|
int res;
|
||||||
|
|
||||||
|
ASSERT(fd >= 0);
|
||||||
|
ASSERT(params != NULL);
|
||||||
|
ASSERT(paramscount == 2);
|
||||||
|
|
||||||
|
/* */
|
||||||
|
res = nl_recvmsgs((struct nl_sock*)params[0], (struct nl_cb*)params[1]);
|
||||||
|
if (res) {
|
||||||
|
capwap_logging_warning("Receive kernel module message failed: %d", res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
int ac_kmod_isconnected(void) {
|
||||||
|
return (g_ac.kmodhandle.nlsmartcapwap_id ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
int ac_kmod_getfd(struct pollfd* fds, struct ac_kmod_event* events, int count) {
|
||||||
|
int kmodcount = (ac_kmod_isconnected() ? 1 : 0);
|
||||||
|
|
||||||
|
/* */
|
||||||
|
if (!kmodcount) {
|
||||||
|
return 0;
|
||||||
|
} else if (!fds && !events && !count) {
|
||||||
|
return kmodcount;
|
||||||
|
} else if ((count > 0) && (!fds || !events)) {
|
||||||
|
return -1;
|
||||||
|
} else if (count < kmodcount) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
fds[0].fd = g_ac.kmodhandle.nl_fd;
|
||||||
|
fds[0].events = POLLIN | POLLERR | POLLHUP;
|
||||||
|
|
||||||
|
/* */
|
||||||
|
events[0].event_handler = ac_kmod_event_receive;
|
||||||
|
events[0].params[0] = (void*)g_ac.kmodhandle.nl;
|
||||||
|
events[0].params[1] = (void*)g_ac.kmodhandle.nl_cb;
|
||||||
|
events[0].paramscount = 2;
|
||||||
|
|
||||||
|
return kmodcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
int ac_kmod_init(void) {
|
||||||
|
int result;
|
||||||
|
|
||||||
|
/* Configure netlink callback */
|
||||||
|
g_ac.kmodhandle.nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
|
||||||
|
if (!g_ac.kmodhandle.nl_cb) {
|
||||||
|
ac_kmod_free();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create netlink socket */
|
||||||
|
g_ac.kmodhandle.nl = nl_create_handle(g_ac.kmodhandle.nl_cb);
|
||||||
|
if (!g_ac.kmodhandle.nl) {
|
||||||
|
ac_kmod_free();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_ac.kmodhandle.nl_fd = nl_socket_get_fd(g_ac.kmodhandle.nl);
|
||||||
|
|
||||||
|
/* Get nlsmartcapwap netlink family */
|
||||||
|
g_ac.kmodhandle.nlsmartcapwap_id = genl_ctrl_resolve(g_ac.kmodhandle.nl, SMARTCAPWAP_AC_GENL_NAME);
|
||||||
|
if (g_ac.kmodhandle.nlsmartcapwap_id < 0) {
|
||||||
|
capwap_logging_warning("Unable to found kernel module");
|
||||||
|
ac_kmod_free();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Configure callback function */
|
||||||
|
nl_cb_set(g_ac.kmodhandle.nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, ac_kmod_no_seq_check, NULL);
|
||||||
|
nl_cb_set(g_ac.kmodhandle.nl_cb, NL_CB_VALID, NL_CB_CUSTOM, ac_kmod_valid_handler, NULL);
|
||||||
|
|
||||||
|
/* Link to kernel module */
|
||||||
|
result = ac_kmod_link();
|
||||||
|
if (result) {
|
||||||
|
ac_kmod_free();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
void ac_kmod_free(void) {
|
||||||
|
if (g_ac.kmodhandle.nl) {
|
||||||
|
nl_socket_free(g_ac.kmodhandle.nl);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_ac.kmodhandle.nl_cb) {
|
||||||
|
nl_cb_put(g_ac.kmodhandle.nl_cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
memset(&g_ac.kmodhandle, 0, sizeof(struct ac_kmod_handle));
|
||||||
|
}
|
42
src/ac/ac_kmod.h
Normal file
42
src/ac/ac_kmod.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#ifndef __AC_KMOD_HEADER__
|
||||||
|
#define __AC_KMOD_HEADER__
|
||||||
|
|
||||||
|
/* */
|
||||||
|
#ifdef HAVE_LIBNL_10
|
||||||
|
#define nl_sock nl_handle
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* */
|
||||||
|
#define AC_KMOD_MODE_LOCAL 0x00000001
|
||||||
|
#define AC_KMOD_MODE_TUNNEL_USERMODE 0x00000002
|
||||||
|
#define AC_KMOD_MODE_TUNNEL_KERNELMODE 0x00000003
|
||||||
|
|
||||||
|
/* */
|
||||||
|
#define AC_KMOD_FLAGS_TUNNEL_NATIVE 0x00000000
|
||||||
|
#define AC_KMOD_FLAGS_TUNNEL_8023 0x00000001
|
||||||
|
|
||||||
|
/* */
|
||||||
|
struct ac_kmod_handle {
|
||||||
|
struct nl_sock* nl;
|
||||||
|
int nl_fd;
|
||||||
|
struct nl_cb* nl_cb;
|
||||||
|
int nlsmartcapwap_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* */
|
||||||
|
#define AC_KMOD_EVENT_MAX_ITEMS 2
|
||||||
|
struct ac_kmod_event {
|
||||||
|
void (*event_handler)(int fd, void** params, int paramscount);
|
||||||
|
int paramscount;
|
||||||
|
void* params[AC_KMOD_EVENT_MAX_ITEMS];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* */
|
||||||
|
int ac_kmod_init(void);
|
||||||
|
void ac_kmod_free(void);
|
||||||
|
|
||||||
|
/* */
|
||||||
|
int ac_kmod_isconnected(void);
|
||||||
|
int ac_kmod_getfd(struct pollfd* fds, struct ac_kmod_event* events, int count);
|
||||||
|
|
||||||
|
#endif /* __AC_KMOD_HEADER__ */
|
13
src/ac/kmod/Makefile
Normal file
13
src/ac/kmod/Makefile
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
KVERSION = $(shell uname -r)
|
||||||
|
|
||||||
|
obj-m += smartcapwap.o
|
||||||
|
|
||||||
|
smartcapwap-y := \
|
||||||
|
main.o \
|
||||||
|
netlinkapp.o
|
||||||
|
|
||||||
|
all:
|
||||||
|
make -C /lib/modules/$(KVERSION)/build M="$(PWD)" modules
|
||||||
|
|
||||||
|
clean:
|
||||||
|
make -C /lib/modules/$(KVERSION)/build M="$(PWD)" clean
|
24
src/ac/kmod/main.c
Normal file
24
src/ac/kmod/main.c
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include "netlinkapp.h"
|
||||||
|
|
||||||
|
/* */
|
||||||
|
static int __init smartcapwap_ac_init(void) {
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
/* */
|
||||||
|
result = nlsmartcapwap_ac_init();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
module_init(smartcapwap_ac_init);
|
||||||
|
|
||||||
|
/* */
|
||||||
|
static void __exit smartcapwap_ac_exit(void) {
|
||||||
|
nlsmartcapwap_ac_exit();
|
||||||
|
}
|
||||||
|
module_exit(smartcapwap_ac_exit);
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_AUTHOR("Massimo Vellucci <vemax78@gmail.com>");
|
||||||
|
MODULE_DESCRIPTION("SmartCAPWAP AC Data Channel Module");
|
158
src/ac/kmod/netlinkapp.c
Normal file
158
src/ac/kmod/netlinkapp.c
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/version.h>
|
||||||
|
#include <linux/rtnetlink.h>
|
||||||
|
#include <linux/netlink.h>
|
||||||
|
#include <net/genetlink.h>
|
||||||
|
#include <linux/rcupdate.h>
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <net/mac80211.h>
|
||||||
|
#include <linux/ieee80211.h>
|
||||||
|
#include "nlsmartcapwap.h"
|
||||||
|
#include "netlinkapp.h"
|
||||||
|
|
||||||
|
/* */
|
||||||
|
struct nlsmartcapwap_ac_device {
|
||||||
|
struct list_head list;
|
||||||
|
|
||||||
|
u32 usermodeid;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* */
|
||||||
|
static u32 nlsmartcapwap_ac_usermodeid = 0;
|
||||||
|
static LIST_HEAD(nlsmartcapwap_ac_dev_list);
|
||||||
|
|
||||||
|
/* Netlink Family */
|
||||||
|
static struct genl_family nlsmartcapwap_ac_family = {
|
||||||
|
.id = GENL_ID_GENERATE,
|
||||||
|
.name = SMARTCAPWAP_AC_GENL_NAME,
|
||||||
|
.hdrsize = 0,
|
||||||
|
.version = 1,
|
||||||
|
.maxattr = NLSMARTCAPWAP_AC_ATTR_MAX,
|
||||||
|
.netnsok = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* */
|
||||||
|
static void nlsmartcapwap_ac_free_device(struct nlsmartcapwap_ac_device* nldev) {
|
||||||
|
/* Free memory */
|
||||||
|
kfree(nldev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
static void nlsmartcapwap_ac_close(void) {
|
||||||
|
struct nlsmartcapwap_ac_device* nldev;
|
||||||
|
struct nlsmartcapwap_ac_device* tmp;
|
||||||
|
|
||||||
|
list_for_each_entry_safe(nldev, tmp, &nlsmartcapwap_ac_dev_list, list) {
|
||||||
|
list_del(&nldev->list);
|
||||||
|
|
||||||
|
/* Free device */
|
||||||
|
nlsmartcapwap_ac_free_device(nldev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* */
|
||||||
|
static int nlsmartcapwap_ac_link(struct sk_buff* skb, struct genl_info* info) {
|
||||||
|
int ret = 0;
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)
|
||||||
|
u32 portid = info->snd_pid;
|
||||||
|
#else
|
||||||
|
u32 portid = info->snd_portid;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
rtnl_lock();
|
||||||
|
|
||||||
|
if (!nlsmartcapwap_ac_usermodeid) {
|
||||||
|
nlsmartcapwap_ac_usermodeid = portid;
|
||||||
|
} else if (nlsmartcapwap_ac_usermodeid == portid) {
|
||||||
|
ret = -EALREADY;
|
||||||
|
} else {
|
||||||
|
ret = -EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
rtnl_unlock();
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
static int nlsmartcapwap_ac_netlink_notify(struct notifier_block* nb, unsigned long state, void* _notify) {
|
||||||
|
struct netlink_notify* notify = (struct netlink_notify*)_notify;
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)
|
||||||
|
u32 portid = notify->pid;
|
||||||
|
#else
|
||||||
|
u32 portid = notify->portid;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* */
|
||||||
|
if (state == NETLINK_URELEASE) {
|
||||||
|
rtnl_lock();
|
||||||
|
|
||||||
|
if (nlsmartcapwap_ac_usermodeid == portid) {
|
||||||
|
nlsmartcapwap_ac_usermodeid = 0;
|
||||||
|
|
||||||
|
/* Close all devices */
|
||||||
|
nlsmartcapwap_ac_close();
|
||||||
|
}
|
||||||
|
|
||||||
|
rtnl_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
return NOTIFY_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
static const struct nla_policy nlsmartcapwap_ac_policy[NLSMARTCAPWAP_AC_ATTR_MAX + 1] = {
|
||||||
|
[NLSMARTCAPWAP_AC_ATTR_FLAGS] = { .type = NLA_U32 },
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Netlink Ops */
|
||||||
|
static struct genl_ops nlsmartcapwap_ac_ops[] = {
|
||||||
|
{
|
||||||
|
.cmd = NLSMARTCAPWAP_AC_CMD_LINK,
|
||||||
|
.doit = nlsmartcapwap_ac_link,
|
||||||
|
.policy = nlsmartcapwap_ac_policy,
|
||||||
|
.flags = GENL_ADMIN_PERM,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Netlink notify */
|
||||||
|
static struct notifier_block nlsmartcapwap_ac_netlink_notifier = {
|
||||||
|
.notifier_call = nlsmartcapwap_ac_netlink_notify,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* */
|
||||||
|
int nlsmartcapwap_ac_init(void) {
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Register netlink family */
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,12,0)
|
||||||
|
ret = genl_register_family_with_ops(&nlsmartcapwap_ac_family, nlsmartcapwap_ac_ops, sizeof(nlsmartcapwap_ac_ops) / sizeof(nlsmartcapwap_ac_ops[0]));
|
||||||
|
#else
|
||||||
|
ret = genl_register_family_with_ops(&nlsmartcapwap_ac_family, nlsmartcapwap_ac_ops);
|
||||||
|
#endif
|
||||||
|
if (ret) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Register netlink notifier */
|
||||||
|
ret = netlink_register_notifier(&nlsmartcapwap_ac_netlink_notifier);
|
||||||
|
if (ret) {
|
||||||
|
genl_unregister_family(&nlsmartcapwap_ac_family);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* */
|
||||||
|
void nlsmartcapwap_ac_exit(void) {
|
||||||
|
/* */
|
||||||
|
rtnl_lock();
|
||||||
|
nlsmartcapwap_ac_close();
|
||||||
|
rtnl_unlock();
|
||||||
|
|
||||||
|
/* */
|
||||||
|
netlink_unregister_notifier(&nlsmartcapwap_ac_netlink_notifier);
|
||||||
|
genl_unregister_family(&nlsmartcapwap_ac_family);
|
||||||
|
}
|
8
src/ac/kmod/netlinkapp.h
Normal file
8
src/ac/kmod/netlinkapp.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#ifndef __KMOD_AC_NETLINKAPP_HEADER__
|
||||||
|
#define __KMOD_AC_NETLINKAPP_HEADER__
|
||||||
|
|
||||||
|
/* */
|
||||||
|
int nlsmartcapwap_ac_init(void);
|
||||||
|
void nlsmartcapwap_ac_exit(void);
|
||||||
|
|
||||||
|
#endif /* __KMOD_AC_NETLINKAPP_HEADER__ */
|
29
src/ac/kmod/nlsmartcapwap.h
Normal file
29
src/ac/kmod/nlsmartcapwap.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#ifndef __AC_NLSMARTCAPWAP_HEADER__
|
||||||
|
#define __AC_NLSMARTCAPWAP_HEADER__
|
||||||
|
|
||||||
|
/* */
|
||||||
|
#define SMARTCAPWAP_AC_GENL_NAME "smartcapwap_ac"
|
||||||
|
|
||||||
|
/* */
|
||||||
|
enum nlsmartcapwap_ac_attrs {
|
||||||
|
NLSMARTCAPWAP_AC_ATTR_UNSPEC,
|
||||||
|
|
||||||
|
NLSMARTCAPWAP_AC_ATTR_FLAGS,
|
||||||
|
|
||||||
|
/* Last attribute */
|
||||||
|
__NLSMARTCAPWAP_AC_ATTR_AFTER_LAST,
|
||||||
|
NLSMARTCAPWAP_AC_ATTR_MAX = __NLSMARTCAPWAP_AC_ATTR_AFTER_LAST - 1
|
||||||
|
};
|
||||||
|
|
||||||
|
/* */
|
||||||
|
enum nlsmartcapwap_ac_commands {
|
||||||
|
NLSMARTCAPWAP_AC_CMD_UNSPEC,
|
||||||
|
|
||||||
|
NLSMARTCAPWAP_AC_CMD_LINK,
|
||||||
|
|
||||||
|
/* Last command */
|
||||||
|
__NLSMARTCAPWAP_AC_CMD_AFTER_LAST,
|
||||||
|
NLSMARTCAPWAP_AC_CMD_MAX = __NLSMARTCAPWAP_AC_CMD_AFTER_LAST - 1
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* __AC_NLSMARTCAPWAP_HEADER__ */
|
@ -239,7 +239,7 @@ int wtp_dfa_update_fdspool(struct wtp_fds* fds) {
|
|||||||
|
|
||||||
/* */
|
/* */
|
||||||
fds->kmodeventscount = kmodcount;
|
fds->kmodeventscount = kmodcount;
|
||||||
fds->kmodevents = (struct wtp_kmod_event*)((wificount > 0) ? capwap_alloc(sizeof(struct wtp_kmod_event) * kmodcount) : NULL);
|
fds->kmodevents = (struct wtp_kmod_event*)((kmodcount > 0) ? capwap_alloc(sizeof(struct wtp_kmod_event) * kmodcount) : NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wifi Events Callback */
|
/* Wifi Events Callback */
|
||||||
@ -271,7 +271,6 @@ int wtp_dfa_update_fdspool(struct wtp_fds* fds) {
|
|||||||
fds->fdstotalcount = totalcount;
|
fds->fdstotalcount = totalcount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Retrieve File Descriptor Kernel Module Event */
|
/* Retrieve File Descriptor Kernel Module Event */
|
||||||
if (fds->kmodeventscount > 0) {
|
if (fds->kmodeventscount > 0) {
|
||||||
fds->kmodeventsstartpos = fds->fdsnetworkcount;
|
fds->kmodeventsstartpos = fds->fdsnetworkcount;
|
||||||
|
@ -299,10 +299,15 @@ int wtp_kmod_join_mac80211_device(struct wifi_wlan* wlan, uint32_t mode, uint32_
|
|||||||
/* */
|
/* */
|
||||||
result = wtp_kmod_send_and_recv(interface->nl, interface->nl_cb, msg, NULL, NULL);
|
result = wtp_kmod_send_and_recv(interface->nl, interface->nl_cb, msg, NULL, NULL);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
|
interface->mode = mode;
|
||||||
|
interface->flags = flags;
|
||||||
interface->wlan = wlan;
|
interface->wlan = wlan;
|
||||||
|
|
||||||
/* */
|
/* */
|
||||||
capwap_itemlist_insert_after(g_wtp.kmodhandle.interfaces, NULL, itemlist);
|
capwap_itemlist_insert_after(g_wtp.kmodhandle.interfaces, NULL, itemlist);
|
||||||
|
if (mode == WTP_KMOD_MODE_TUNNEL_USERMODE) {
|
||||||
|
g_wtp.kmodhandle.interfaceconnectioncount++;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
nl_socket_free(interface->nl);
|
nl_socket_free(interface->nl);
|
||||||
nl_cb_put(interface->nl_cb);
|
nl_cb_put(interface->nl_cb);
|
||||||
@ -349,6 +354,10 @@ int wtp_kmod_leave_mac80211_device(struct wifi_wlan* wlan) {
|
|||||||
nl_cb_put(interface->nl_cb);
|
nl_cb_put(interface->nl_cb);
|
||||||
|
|
||||||
/* Free item */
|
/* Free item */
|
||||||
|
if (interface->mode == WTP_KMOD_MODE_TUNNEL_USERMODE) {
|
||||||
|
g_wtp.kmodhandle.interfaceconnectioncount--;
|
||||||
|
}
|
||||||
|
|
||||||
capwap_itemlist_free(capwap_itemlist_remove(g_wtp.kmodhandle.interfaces, itemlist));
|
capwap_itemlist_free(capwap_itemlist_remove(g_wtp.kmodhandle.interfaces, itemlist));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -369,19 +378,7 @@ int wtp_kmod_isconnected(void) {
|
|||||||
int wtp_kmod_getfd(struct pollfd* fds, struct wtp_kmod_event* events, int count) {
|
int wtp_kmod_getfd(struct pollfd* fds, struct wtp_kmod_event* events, int count) {
|
||||||
int i;
|
int i;
|
||||||
struct capwap_list_item* itemlist;
|
struct capwap_list_item* itemlist;
|
||||||
int kmodcount = 0;
|
int kmodcount = (wtp_kmod_isconnected() ? 1 + g_wtp.kmodhandle.interfaceconnectioncount : 0);
|
||||||
|
|
||||||
/* */
|
|
||||||
if (wtp_kmod_isconnected()) {
|
|
||||||
kmodcount = 1;
|
|
||||||
for (itemlist = g_wtp.kmodhandle.interfaces->first; itemlist; itemlist = itemlist->next) {
|
|
||||||
struct wtp_kmod_iface_handle* interface = (struct wtp_kmod_iface_handle*)itemlist->item;
|
|
||||||
|
|
||||||
if (interface->nl_fd) {
|
|
||||||
kmodcount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* */
|
/* */
|
||||||
if (!kmodcount) {
|
if (!kmodcount) {
|
||||||
|
@ -23,6 +23,8 @@ struct wtp_kmod_iface_handle {
|
|||||||
int nl_fd;
|
int nl_fd;
|
||||||
struct nl_cb* nl_cb;
|
struct nl_cb* nl_cb;
|
||||||
|
|
||||||
|
uint32_t mode;
|
||||||
|
uint32_t flags;
|
||||||
struct wifi_wlan* wlan;
|
struct wifi_wlan* wlan;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -35,6 +37,7 @@ struct wtp_kmod_handle {
|
|||||||
|
|
||||||
/* */
|
/* */
|
||||||
struct capwap_list* interfaces;
|
struct capwap_list* interfaces;
|
||||||
|
int interfaceconnectioncount;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* */
|
/* */
|
||||||
|
Loading…
Reference in New Issue
Block a user