The capwap data channel migrated from userspace to kernalspace

This commit is contained in:
vemax78
2014-09-10 21:58:23 +02:00
parent 71006a9121
commit 8d9985fdea
104 changed files with 6967 additions and 4840 deletions

View File

@ -3,6 +3,7 @@
#include "capwap_element.h"
#include "wifi_drivers.h"
#include "wtp_radio.h"
#include "wtp_kmod.h"
/* Declare enable wifi driver */
#ifdef ENABLE_WIFI_DRIVERS_NL80211
@ -314,7 +315,7 @@ static void wifi_wlan_send_mgmt_deauthentication(struct wifi_wlan* wlan, const u
capwap_logging_info("Sent IEEE802.11 Deuthentication to %s station", stationaddress);
/* Forwards the station deauthentication also to AC */
wifi_wlan_send_frame(wlan, (uint8_t*)g_bufferIEEE80211, responselength, 1, 0, 0, 0);
wifi_wlan_send_frame(wlan, (uint8_t*)g_bufferIEEE80211, responselength, 0, 0, 0);
} else {
capwap_logging_warning("Unable to send IEEE802.11 Deuthentication to %s station", stationaddress);
}
@ -419,7 +420,7 @@ static void wifi_wlan_receive_station_mgmt_probe_request(struct wifi_wlan* wlan,
if (!wlan->device->instance->ops->wlan_sendframe(wlan, g_bufferIEEE80211, responselength, wlan->device->currentfrequency.frequency, 0, 0, 0, nowaitack)) {
/* If enable Split Mac send the probe request message to AC */
if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) {
wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, 1, rssi, snr, rate);
wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, rssi, snr, rate);
}
} else {
capwap_logging_warning("Unable to send IEEE802.11 Probe Response");
@ -583,10 +584,10 @@ static void wifi_wlan_receive_station_mgmt_authentication(struct wifi_wlan* wlan
capwap_logging_info("Sent IEEE802.11 Authentication Response to %s station with %d status code", stationaddress, (int)responsestatuscode);
/* Notify authentication request message also to AC */
wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, 1, rssi, snr, rate);
wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, rssi, snr, rate);
/* Forwards the authentication response message also to AC */
wifi_wlan_send_frame(wlan, (uint8_t*)g_bufferIEEE80211, responselength, 1, 0, 0, 0);
wifi_wlan_send_frame(wlan, (uint8_t*)g_bufferIEEE80211, responselength, 0, 0, 0);
} else if (station) {
capwap_logging_warning("Unable to send IEEE802.11 Authentication Response to %s station", stationaddress);
wifi_station_delete(station);
@ -596,7 +597,7 @@ static void wifi_wlan_receive_station_mgmt_authentication(struct wifi_wlan* wlan
wifi_station_delete(station);
}
} else if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) {
wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, 1, rssi, snr, rate);
wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, rssi, snr, rate);
}
}
@ -682,10 +683,10 @@ static void wifi_wlan_receive_station_mgmt_association_request(struct wifi_wlan*
capwap_logging_info("Sent IEEE802.11 Association Response to %s station with %d status code", station->addrtext, (int)resultstatuscode);
/* Notify association request message also to AC */
wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, 1, rssi, snr, rate);
wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, rssi, snr, rate);
/* Forwards the association response message also to AC */
wifi_wlan_send_frame(wlan, (uint8_t*)g_bufferIEEE80211, responselength, 1, 0, 0, 0);
wifi_wlan_send_frame(wlan, (uint8_t*)g_bufferIEEE80211, responselength, 0, 0, 0);
} else {
capwap_logging_warning("Unable to send IEEE802.11 Association Response to %s station", station->addrtext);
wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0);
@ -695,7 +696,7 @@ static void wifi_wlan_receive_station_mgmt_association_request(struct wifi_wlan*
wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0);
}
} else if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) {
wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, 1, rssi, snr, rate);
wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, rssi, snr, rate);
/* Station information */
station->capability = __le16_to_cpu(frame->associationresponse.capability);
@ -729,7 +730,7 @@ static void wifi_wlan_receive_station_mgmt_disassociation(struct wifi_wlan* wlan
/* TODO */
/* Notify disassociation message also to AC */
wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, 1, rssi, snr, rate);
wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, rssi, snr, rate);
}
/* */
@ -750,7 +751,7 @@ static void wifi_wlan_receive_station_mgmt_deauthentication(struct wifi_wlan* wl
}
/* Notify deauthentication message also to AC */
wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, 1, rssi, snr, rate);
wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, rssi, snr, rate);
}
/* */
@ -1479,8 +1480,8 @@ int wifi_wlan_startap(struct wifi_wlan* wlan, struct wlan_startap_params* params
wlan->authmode = params->authmode;
wlan->macmode = params->macmode;
wlan->tunnelmode = params->tunnelmode;
wlan->send_frame = params->send_frame;
wlan->send_frame_to_ac_cbparam = params->send_frame_to_ac_cbparam;
wlan->radioid = params->radioid;
wlan->wlanid = params->wlanid;
/* Start AP */
result = wlan->device->instance->ops->wlan_startap(wlan);
@ -1655,16 +1656,23 @@ void wifi_wlan_receive_ac_frame(struct wifi_wlan* wlan, struct ieee80211_header*
}
/* */
int wifi_wlan_send_frame(struct wifi_wlan* wlan, const uint8_t* data, int length, int nativeframe, uint8_t rssi, uint8_t snr, uint16_t rate) {
int wifi_wlan_send_frame(struct wifi_wlan* wlan, const uint8_t* data, int length, uint8_t rssi, uint8_t snr, uint16_t rate) {
int result;
ASSERT(wlan != NULL);
ASSERT(wlan->handle != NULL);
if (!data || (length <= 0) || !wlan->send_frame) {
if (!data || (length <= 0)) {
return -1;
}
/* */
return wlan->send_frame(wlan->send_frame_to_ac_cbparam, data, length, nativeframe, rssi, snr, rate, wlan->address, MACADDRESS_EUI48_LENGTH);
/* Send packet to AC */
result = wtp_kmod_send_data(wlan->radioid, data, length, rssi, snr, rate);
if (result) {
capwap_logging_warning("Unable to sent packet to AC: %d error code", result);
}
return result;
}
/* */
@ -1704,23 +1712,17 @@ int wifi_station_authorize(struct wifi_wlan* wlan, struct station_add_params* pa
}
/* */
int wifi_station_deauthorize(struct wifi_device* device, const uint8_t* address) {
void wifi_station_deauthorize(struct wifi_device* device, const uint8_t* address) {
struct wifi_station* station;
ASSERT(device != NULL);
ASSERT(address != NULL);
/* Get station */
/* */
station = wifi_station_get(NULL, address);
if (!station || !station->wlan) {
return -1;
if (station && station->wlan) {
wifi_wlan_deauthentication_station(station->wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0);
}
/* Station deauthorized */
capwap_logging_info("Deauthorize station: %s", station->addrtext);
wifi_wlan_deauthentication_station(station->wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0);
return 1;
}
/* */

View File

@ -87,11 +87,11 @@ struct device_setconfiguration_params {
};
/* */
typedef int (*send_frame_to_ac)(void* param, const uint8_t* frame, int length, int nativeframe, uint8_t rssi, uint8_t snr, uint16_t rate, uint8_t* bssaddress, int bssaddresstype);
typedef int (*send_frame_to_ac)(void* param, const uint8_t* frame, int length, uint8_t rssi, uint8_t snr, uint16_t rate);
struct wlan_startap_params {
send_frame_to_ac send_frame;
void* send_frame_to_ac_cbparam;
uint8_t radioid;
uint8_t wlanid;
const char* ssid;
uint8_t ssid_hidden;
@ -289,8 +289,8 @@ struct wifi_wlan {
uint8_t address[MACADDRESS_EUI48_LENGTH];
/* */
send_frame_to_ac send_frame;
void* send_frame_to_ac_cbparam;
uint8_t radioid;
uint8_t wlanid;
/* WLAN information */
char ssid[IEEE80211_SSID_MAX_LENGTH + 1];
@ -409,7 +409,7 @@ int wifi_wlan_startap(struct wifi_wlan* wlan, struct wlan_startap_params* params
void wifi_wlan_stopap(struct wifi_wlan* wlan);
int wifi_wlan_getbssid(struct wifi_wlan* wlan, uint8_t* bssid);
uint16_t wifi_wlan_check_capability(struct wifi_wlan* wlan, uint16_t capability);
int wifi_wlan_send_frame(struct wifi_wlan* wlan, const uint8_t* data, int length, int nativeframe, uint8_t rssi, uint8_t snr, uint16_t rate);
int wifi_wlan_send_frame(struct wifi_wlan* wlan, const uint8_t* data, int length, uint8_t rssi, uint8_t snr, uint16_t rate);
void wifi_wlan_destroy(struct wifi_wlan* wlan);
/* WLAN packet management */
@ -419,7 +419,7 @@ void wifi_wlan_receive_ac_frame(struct wifi_wlan* wlan, struct ieee80211_header*
/* Station management */
int wifi_station_authorize(struct wifi_wlan* wlan, struct station_add_params* params);
int wifi_station_deauthorize(struct wifi_device* device, const uint8_t* address);
void wifi_station_deauthorize(struct wifi_device* device, const uint8_t* address);
/* Util functions */
uint32_t wifi_iface_index(const char* ifname);

View File

@ -759,6 +759,7 @@ static int nl80211_wlan_startap(struct wifi_wlan* wlan) {
return -1;
}
/* */
nl_cb_set(wlanhandle->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, nl80211_no_seq_check, NULL);
nl_cb_set(wlanhandle->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, nl80211_wlan_valid_handler, (void*)wlan);
@ -798,16 +799,13 @@ static int nl80211_wlan_startap(struct wifi_wlan* wlan) {
/* */
if (wlan->tunnelmode != CAPWAP_ADD_WLAN_TUNNELMODE_LOCAL) {
/* Join interface to kernel module */
if ((g_wtp.tunneldataframe == WTP_TUNNEL_DATA_FRAME_KERNELMODE) || (g_wtp.tunneldataframe == WTP_TUNNEL_DATA_FRAME_USERMODE)) {
uint32_t mode = ((g_wtp.tunneldataframe == WTP_TUNNEL_DATA_FRAME_KERNELMODE) ? WTP_KMOD_MODE_TUNNEL_KERNELMODE : WTP_KMOD_MODE_TUNNEL_USERMODE);
uint32_t flags = ((wlan->tunnelmode == CAPWAP_ADD_WLAN_TUNNELMODE_80211) ? WTP_KMOD_FLAGS_TUNNEL_NATIVE : WTP_KMOD_FLAGS_TUNNEL_8023);
/* Join interface in kernel module */
uint32_t flags = ((wlan->tunnelmode == CAPWAP_ADD_WLAN_TUNNELMODE_80211) ? WTP_KMOD_FLAGS_TUNNEL_NATIVE : WTP_KMOD_FLAGS_TUNNEL_8023);
if (!wtp_kmod_join_mac80211_device(wlan, mode, flags)) {
capwap_logging_info("Joined in kernel mode the interface %d", wlan->virtindex);
}
if (!wtp_kmod_join_mac80211_device(wlan, flags)) {
capwap_logging_info("Joined the interface %d in kernel mode ", wlan->virtindex);
} else {
capwap_logging_warning("Tunneling is not supported for interface %d", wlan->virtindex);
capwap_logging_error("Unable to join the interface %d in kernel mode ", wlan->virtindex);
return -1;
}
}
@ -833,9 +831,7 @@ static void nl80211_wlan_stopap(struct wifi_wlan* wlan) {
/* */
if (wlan->tunnelmode != CAPWAP_ADD_WLAN_TUNNELMODE_LOCAL) {
/* Leave interface from kernel module */
if ((g_wtp.tunneldataframe == WTP_TUNNEL_DATA_FRAME_KERNELMODE) || (g_wtp.tunneldataframe == WTP_TUNNEL_DATA_FRAME_USERMODE)) {
wtp_kmod_leave_mac80211_device(wlan);
}
wtp_kmod_leave_mac80211_device(wlan);
}
/* */
@ -1068,6 +1064,12 @@ int nl80211_station_deauthorize(struct wifi_wlan* wlan, const uint8_t* address)
}
}
/* */
if (!result) {
char addrtext[CAPWAP_MACADDRESS_EUI48_BUFFER];
capwap_logging_info("Deauthorize station: %s", capwap_printf_macaddress(addrtext, address, MACADDRESS_EUI48_LENGTH));
}
/* */
nlmsg_free(msg);
return result;

View File

@ -2,4 +2,7 @@ obj-m += smartcapwap.o
smartcapwap-y := \
main.o \
netlinkapp.o
netlinkapp.o \
socket.o \
capwap.o \
capwap_private.o

621
src/wtp/kmod/capwap.c Normal file
View File

@ -0,0 +1,621 @@
#include "config.h"
#include <linux/module.h>
#include <linux/ieee80211.h>
#include "socket.h"
#include "capwap.h"
#include "nlsmartcapwap.h"
#include "netlinkapp.h"
/* */
#define TIMEOUT_PACKET 10
/* */
union capwap_addr sc_localaddr;
/* */
static void sc_capwap_fragment_free(struct sc_capwap_fragment* fragment) {
TRACEKMOD("### sc_capwap_fragment_free\n");
/* */
list_del(&fragment->lru_list);
fragment->flags = 0;
/* Free socket buffer */
while (fragment->fragments) {
struct sk_buff* next = fragment->fragments->next;
kfree_skb(fragment->fragments);
fragment->fragments = next;
}
}
/* */
static void sc_capwap_defrag_evictor(struct sc_capwap_session* session, ktime_t now) {
ktime_t delta;
unsigned long flags;
struct sc_capwap_fragment* fragment;
TRACEKMOD("### sc_capwap_defrag_evictor\n");
/* */
if (now.tv64 == 0) {
TRACEKMOD("*** Get time\n");
now = ktime_get();
}
/* Remove last old fragment */
if (!list_empty(&session->fragments.lru_list)) {
spin_lock_irqsave(&session->fragments.lock, flags);
fragment = list_first_entry(&session->fragments.lru_list, struct sc_capwap_fragment, lru_list);
if (fragment) {
delta = ktime_sub(now, fragment->tstamp);
if ((delta.tv64 < 0) || (delta.tv64 > NSEC_PER_SEC)) {
TRACEKMOD("*** Expired fragment %hu\n", fragment->fragmentid);
/* Reset fragment */
sc_capwap_fragment_free(fragment);
}
}
spin_unlock_irqrestore(&session->fragments.lock, flags);
}
}
/* */
static struct sk_buff* sc_capwap_reasm(struct sc_capwap_fragment* fragment) {
int len;
int offset;
struct sk_buff* skb;
struct sk_buff* skbfrag;
struct sc_capwap_header* header;
/* */
skbfrag = fragment->fragments;
len = GET_HLEN_HEADER((struct sc_capwap_header*)skbfrag->data) * 4;
/* Create new packet */
skb = alloc_skb(len + fragment->totallength, GFP_KERNEL);
if (!skb) {
return NULL;
}
/* The first capwap header is header of reassembled packet without fragment field */
header = (struct sc_capwap_header*)skb_put(skb, len);
memcpy(header, skb->data, len);
SET_FLAG_F_HEADER(header, 0);
SET_FLAG_L_HEADER(header, 0);
header->frag_id = (__be16)0;
header->frag_off = (__be16)0;
/* Copy body */
while (skbfrag) {
offset = GET_HLEN_HEADER((struct sc_capwap_header*)skbfrag->data) * 4;
len = skb->len - offset;
/* */
memcpy(skb_put(skb, len), skb->data + offset, len);
skbfrag = skbfrag->next;
}
return skb;
}
/* */
static struct sk_buff* sc_capwap_defrag(struct sc_capwap_session* session, struct sk_buff* skb) {
unsigned long flags;
uint16_t headersize;
uint16_t frag_id;
struct sk_buff* prev;
struct sk_buff* next;
struct sc_capwap_fragment* fragment;
struct sc_skb_capwap_cb* cb;
struct sk_buff* skb_defrag = NULL;
struct sc_capwap_header* header = (struct sc_capwap_header*)skb->data;
TRACEKMOD("### sc_capwap_defrag\n");
/* */
headersize = GET_HLEN_HEADER(header) * 4;
if (skb->len < headersize) {
goto error;
}
/* */
frag_id = be16_to_cpu(header->frag_id);
/* */
cb = CAPWAP_SKB_CB(skb);
cb->flags |= SKB_CAPWAP_FLAG_FRAGMENT;
cb->frag_offset = be16_to_cpu(header->frag_off);
cb->frag_length = skb->len - headersize;
/* */
spin_lock_irqsave(&session->fragments.lock, flags);
/* Get fragment */
fragment = &session->fragments.queues[frag_id % CAPWAP_FRAGMENT_QUEUE];
if ((fragment->flags & CAPWAP_FRAGMENT_ENABLE) && (fragment->fragmentid != frag_id)) {
goto error2; /* Queue fragment busy*/
}
/* Init fragment */
if (!(fragment->flags & CAPWAP_FRAGMENT_ENABLE)) {
fragment->flags = CAPWAP_FRAGMENT_ENABLE;
fragment->fragmentid = frag_id;
fragment->fragments = NULL;
fragment->lastfragment = NULL;
fragment->recvlength = 0;
fragment->totallength = 0;
list_add_tail(&fragment->lru_list, &session->fragments.lru_list);
}
/* Search fragment position */
prev = fragment->lastfragment;
if (!prev) {
next = NULL;
} else if (CAPWAP_SKB_CB(prev)->frag_offset < cb->frag_offset) {
if ((CAPWAP_SKB_CB(prev)->frag_offset + CAPWAP_SKB_CB(prev)->frag_length) < cb->frag_offset) {
next = NULL;
} else {
sc_capwap_fragment_free(fragment);
goto error2; /* Overlap error */
}
} else {
prev = NULL;
for (next = fragment->fragments; next != NULL; next = next->next) {
struct sc_skb_capwap_cb* next_cb = CAPWAP_SKB_CB(next);
if (next_cb->frag_offset < cb->frag_offset) {
if ((next_cb->frag_offset + next_cb->frag_length) < cb->frag_offset) {
break;
} else {
sc_capwap_fragment_free(fragment);
goto error2; /* Overlap error */
}
}
prev = next;
}
}
/* Insert fragment */
skb->prev = NULL;
skb->next = next;
if (!next) {
fragment->lastfragment = skb;
}
if (prev) {
prev->next = skb;
} else {
fragment->fragments = skb;
}
/* Update size */
fragment->recvlength += cb->frag_length;
if (IS_FLAG_L_HEADER(header)) {
fragment->totallength = cb->frag_offset + cb->frag_length;
fragment->flags |= CAPWAP_FRAGMENT_LAST;
}
/* Check if receive all fragment */
if ((fragment->flags & CAPWAP_FRAGMENT_LAST) && (fragment->recvlength == fragment->totallength)) {
skb_defrag = sc_capwap_reasm(fragment);
/* Free fragment complete */
sc_capwap_fragment_free(fragment);
} else {
/* Update timeout */
fragment->tstamp = skb->tstamp;
if (fragment->tstamp.tv64 == 0) {
fragment->tstamp = ktime_get();
}
/* Set LRU timeout */
if (!list_is_last(&fragment->lru_list, &session->fragments.lru_list)) {
list_move_tail(&fragment->lru_list, &session->fragments.lru_list);
}
}
spin_unlock_irqrestore(&session->fragments.lock, flags);
return skb_defrag;
error2:
spin_unlock_irqrestore(&session->fragments.lock, flags);
error:
kfree_skb(skb);
return NULL;
}
/* */
int sc_capwap_bind(union capwap_addr* sockaddr) {
int ret;
TRACEKMOD("### sc_capwap_bind\n");
/* */
ret = sc_socket_bind(sockaddr);
if (ret) {
return ret;
}
memcpy(&sc_localaddr, sockaddr, sizeof(union capwap_addr));
return 0;
}
/* */
void sc_capwap_initsession(struct sc_capwap_session* session) {
TRACEKMOD("### sc_capwap_initsession\n");
INIT_LIST_HEAD(&session->list);
spin_lock_init(&session->fragmentid_lock);
/* Defragment packets */
memset(&session->fragments, 0, sizeof(struct sc_capwap_fragment_queue));
INIT_LIST_HEAD(&session->fragments.lru_list);
spin_lock_init(&session->fragments.lock);
}
/* */
void sc_capwap_freesession(struct sc_capwap_session* session) {
struct sc_capwap_fragment* temp;
struct sc_capwap_fragment* fragment;
TRACEKMOD("### sc_capwap_freesession\n");
/* Free socket buffers */
list_for_each_entry_safe(fragment, temp, &session->fragments.lru_list, lru_list) {
sc_capwap_fragment_free(fragment);
}
}
/* */
uint16_t sc_capwap_newfragmentid(struct sc_capwap_session* session) {
uint16_t fragmentid;
unsigned long flags;
TRACEKMOD("### sc_capwap_newfragmentid\n");
spin_lock_irqsave(&session->fragmentid_lock, flags);
fragmentid = session->fragmentid++;
spin_unlock_irqrestore(&session->fragmentid_lock, flags);
return fragmentid;
}
/* */
int sc_capwap_createkeepalive(struct sc_capwap_sessionid_element* sessionid, uint8_t* buffer, int size) {
int length;
struct sc_capwap_header* header;
struct sc_capwap_data_message* dataheader;
struct sc_capwap_message_element* msgelement;
TRACEKMOD("### sc_capwap_createkeepalive\n");
/* */
if (size < CAPWAP_KEEP_ALIVE_MAX_SIZE) {
return -ENOMEM;
}
/* Preamble CAPWAP header */
header = (struct sc_capwap_header*)buffer;
length = sizeof(struct sc_capwap_header);
buffer += sizeof(struct sc_capwap_header);
memset(header, 0, sizeof(struct sc_capwap_header));
SET_VERSION_HEADER(header, CAPWAP_PROTOCOL_VERSION);
SET_TYPE_HEADER(header, CAPWAP_PREAMBLE_HEADER);
SET_HLEN_HEADER(header, sizeof(struct sc_capwap_header) / 4);
SET_WBID_HEADER(header, CAPWAP_WIRELESS_BINDING_IEEE80211);
SET_FLAG_K_HEADER(header, 1);
/* CAPWAP Data header */
dataheader = (struct sc_capwap_data_message*)buffer;
length += sizeof(struct sc_capwap_data_message);
buffer += sizeof(struct sc_capwap_data_message);
dataheader->length = cpu_to_be16(sizeof(struct sc_capwap_data_message) + sizeof(struct sc_capwap_message_element) + sizeof(struct sc_capwap_sessionid_element));
/* CAPWAP Keep-Alive Message Element */
msgelement = (struct sc_capwap_message_element*)buffer;
length += sizeof(struct sc_capwap_message_element);
buffer += sizeof(struct sc_capwap_message_element);
msgelement->type = cpu_to_be16(CAPWAP_ELEMENT_SESSIONID);
msgelement->length = cpu_to_be16(sizeof(struct sc_capwap_sessionid_element));
/* Session ID */
memcpy(buffer, sessionid, sizeof(struct sc_capwap_sessionid_element));
length += sizeof(struct sc_capwap_sessionid_element);
return length;
}
/* */
int sc_capwap_parsingpacket(struct sc_capwap_session* session, const union capwap_addr* sockaddr, struct sk_buff* skb) {
int length;
uint16_t headersize;
struct sc_capwap_data_message* dataheader;
struct sc_capwap_message_element* message;
struct sc_capwap_header* header = (struct sc_capwap_header*)skb->data;
TRACEKMOD("### sc_capwap_parsingpacket\n");
/* Linearize socket buffer */
if (skb_linearize(skb)) {
TRACEKMOD("*** Unable to linearize packet\n");
return -EINVAL;
}
/* Check header */
if (skb->len < sizeof(struct sc_capwap_header)) {
TRACEKMOD("*** Invalid capwap header length\n");
return -EINVAL;
} else if (GET_VERSION_HEADER(header) != CAPWAP_PROTOCOL_VERSION) {
TRACEKMOD("*** Invalid capwap header version\n");
return -EINVAL;
} else if (GET_TYPE_HEADER(header) != CAPWAP_PREAMBLE_HEADER) {
TRACEKMOD("*** Packet is encrypted\n");
return -EINVAL; /* Accept only plain packet */
}
/* Cleaning old fragments */
if (session) {
sc_capwap_defrag_evictor(session, skb->tstamp);
}
/* */
if (IS_FLAG_K_HEADER(header)) {
/* Keep alive can not fragment */
if (IS_FLAG_F_HEADER(header)) {
TRACEKMOD("*** Keep alive can not fragment\n");
return -EINVAL;
}
/* */
length = skb->len;
headersize = GET_HLEN_HEADER(header) * 4;
if (length < (headersize + sizeof(struct sc_capwap_data_message))) {
TRACEKMOD("*** Invalid capwap data header length\n");
return -EINVAL;
}
/* Data message */
length -= headersize;
dataheader = (struct sc_capwap_data_message*)(((uint8_t*)header) + headersize);
headersize = ntohs(dataheader->length);
if (length < headersize) {
TRACEKMOD("*** Capwap data header length mismatch\n");
return -EINVAL;
}
/* Message elements */
headersize -= sizeof(struct sc_capwap_data_message);
message = (struct sc_capwap_message_element*)(((uint8_t*)dataheader) + sizeof(struct sc_capwap_data_message));
while (headersize > 0) {
uint16_t msglength = ntohs(message->length);
if (headersize < (msglength + sizeof(struct sc_capwap_message_element))) {
TRACEKMOD("*** Invalid capwap message element length\n");
return -EINVAL;
}
/* */
if ((ntohs(message->type) == CAPWAP_ELEMENT_SESSIONID) && (msglength == sizeof(struct sc_capwap_sessionid_element))) {
struct sc_capwap_sessionid_element* sessionid = (struct sc_capwap_sessionid_element*)(((uint8_t*)message) + sizeof(struct sc_capwap_message_element));
if (!session) {
session = sc_capwap_recvunknownkeepalive(sockaddr, sessionid);
if (!session) {
TRACEKMOD("*** Receive unknown keep alive without valid session\n");
return -EINVAL;
}
} else if (memcmp(&session->sessionid, sessionid, sizeof(struct sc_capwap_sessionid_element))) {
TRACEKMOD("*** Session id mismatch\n");
return -EINVAL;
}
/* Session found */
sc_netlink_notify_recv_keepalive(sockaddr, sessionid);
/* Parsing complete */
kfree_skb(skb);
return 0;
}
/* Next message element */
msglength += sizeof(struct sc_capwap_message_element);
message = (struct sc_capwap_message_element*)(((uint8_t*)message) + msglength);
headersize -= msglength;
}
} else if (session) {
if (IS_FLAG_F_HEADER(header)) {
skb = sc_capwap_defrag(session, skb);
if (!skb) {
return 0;
}
/* Get new header info */
header = (struct sc_capwap_header*)skb->data;
}
/* Parsing data/management packet */
if (!IS_FLAG_T_HEADER(header)) {
sc_capwap_parsingdatapacket(session, skb);
} else if (GET_WBID_HEADER(header) == CAPWAP_WIRELESS_BINDING_IEEE80211) {
struct ieee80211_hdr* hdr = (struct ieee80211_hdr*)(skb->data + GET_HLEN_HEADER(header) * 4);
if (ieee80211_is_data_present(hdr->frame_control)) {
sc_capwap_parsingdatapacket(session, skb);
} else if (ieee80211_is_mgmt(hdr->frame_control) || ieee80211_is_ctl(hdr->frame_control)) {
sc_capwap_parsingmgmtpacket(session, skb);
}
}
/* Parsing complete */
kfree_skb(skb);
return 0;
}
return -EINVAL;
}
/* */
int sc_capwap_forwarddata(struct sc_capwap_session* session, uint8_t radioid, uint8_t binding, struct sk_buff* skb, uint32_t flags, struct sc_capwap_radio_addr* radioaddr, int radioaddrlength, struct sc_capwap_wireless_information* winfo, int winfolength) {
int size;
int length;
int reserve;
int headroom;
int requestfragment;
__be16 fragmentid = 0;
int fragmentoffset = 0;
struct sc_capwap_header* header;
struct sk_buff* clone = NULL;
int packetlength = skb->len;
TRACEKMOD("### sc_capwap_forwarddata\n");
/* Check headroom */
headroom = skb_headroom(skb);
reserve = sizeof(struct sc_capwap_header) + radioaddrlength + winfolength;
if (skb_is_nonlinear(skb) || (headroom < reserve)) {
printk("*** Expand socket buffer\n");
clone = skb_copy_expand(skb, max_t(int, headroom, reserve), skb_tailroom(skb), GFP_KERNEL);
if (!clone) {
printk("*** Unable to expand socket buffer\n");
return -ENOMEM;
}
skb = clone;
}
/* Check MTU */
requestfragment = (((packetlength + reserve) > session->mtu) ? 1 : 0);
if (requestfragment) {
fragmentid = cpu_to_be16(sc_capwap_newfragmentid(session));
}
/* */
header = (struct sc_capwap_header*)skb_push(skb, sizeof(struct sc_capwap_header) + radioaddrlength + winfolength);
while (packetlength > 0) {
memset(header, 0, sizeof(struct sc_capwap_header));
SET_VERSION_HEADER(header, CAPWAP_PROTOCOL_VERSION);
SET_TYPE_HEADER(header, CAPWAP_PREAMBLE_HEADER);
SET_WBID_HEADER(header, binding);
SET_RID_HEADER(header, radioid);
SET_FLAG_T_HEADER(header, ((flags & NLSMARTCAPWAP_FLAGS_TUNNEL_8023) ? 0 : 1));
if (!fragmentoffset) {
uint8_t* headeroption = (uint8_t*)header + sizeof(struct sc_capwap_header);
if (radioaddr) {
SET_FLAG_M_HEADER(header, 1);
memcpy(headeroption, radioaddr, radioaddrlength);
headeroption += radioaddrlength;
}
if (winfo) {
SET_FLAG_W_HEADER(header, 1);
memcpy(headeroption, winfo, winfolength);
headeroption += winfolength;
}
size = sizeof(struct sc_capwap_header) + radioaddrlength + winfolength;
SET_HLEN_HEADER(header, size / 4);
} else {
size = sizeof(struct sc_capwap_header);
SET_HLEN_HEADER(header, size / 4);
}
/* Calculate body size */
length = session->mtu - size;
if (packetlength <= length) {
length = packetlength;
} else if (requestfragment) {
length -= length % 8; /* Capwap fragment size is module 8 */
} else {
break;
}
/* Fragment options */
if (requestfragment) {
SET_FLAG_F_HEADER(header, 1);
if (packetlength == length) {
SET_FLAG_L_HEADER(header, 1);
}
header->frag_id = fragmentid;
header->frag_off = cpu_to_be16(fragmentoffset);
}
/* Send packet */
if (sc_socket_send(SOCKET_UDP, (uint8_t*)header, (size + length), &session->peeraddr) < 0) {
break;
}
/* */
header = (struct sc_capwap_header*)((uint8_t*)header + (size + length));
fragmentoffset += length;
packetlength -= length;
}
if (clone) {
kfree_skb(clone);
}
return (!packetlength ? 0 : -EIO);
}
/* */
void sc_capwap_sessionid_printf(const struct sc_capwap_sessionid_element* sessionid, char* string) {
int i;
char* pos = string;
for (i = 0; i < 16; i++) {
snprintf(pos, 3, "%02x", sessionid->id[i]);
pos += 2;
}
*pos = 0;
}
/* */
struct sc_capwap_radio_addr* sc_capwap_setradiomacaddress(uint8_t* buffer, int size, uint8_t* bssid) {
struct sc_capwap_radio_addr* radioaddr;
struct sc_capwap_macaddress_eui48* addr;
TRACEKMOD("### sc_capwap_setwirelessinformation\n");
memset(buffer, 0, size);
radioaddr = (struct sc_capwap_radio_addr*)buffer;
radioaddr->length = MACADDRESS_EUI48_LENGTH;
addr = (struct sc_capwap_macaddress_eui48*)(buffer + sizeof(struct sc_capwap_radio_addr));
memcpy(addr->addr, bssid, MACADDRESS_EUI48_LENGTH);
return radioaddr;
}
/* */
struct sc_capwap_wireless_information* sc_capwap_setwirelessinformation(uint8_t* buffer, int size, uint8_t rssi, uint8_t snr, uint16_t rate) {
struct sc_capwap_wireless_information* winfo;
struct sc_capwap_ieee80211_frame_info* frameinfo;
TRACEKMOD("### sc_capwap_setwirelessinformation\n");
memset(buffer, 0, size);
winfo = (struct sc_capwap_wireless_information*)buffer;
winfo->length = sizeof(struct sc_capwap_ieee80211_frame_info);
frameinfo = (struct sc_capwap_ieee80211_frame_info*)(buffer + sizeof(struct sc_capwap_wireless_information));
frameinfo->rssi = rssi;
frameinfo->snr = snr;
frameinfo->rate = cpu_to_be16(rate);
return winfo;
}

128
src/wtp/kmod/capwap.h Normal file
View File

@ -0,0 +1,128 @@
#ifndef __KMOD_CAPWAP_HEADER__
#define __KMOD_CAPWAP_HEADER__
#include "capwap_rfc.h"
#include "socket.h"
/* */
#define MAX_MTU 9000
#define DEFAULT_MTU 1450
#define MIN_MTU 500
#define IEEE80211_MTU 7981
/* */
#define CAPWAP_FRAGMENT_QUEUE 16
/* */
#define CAPWAP_FRAGMENT_ENABLE 0x0001
#define CAPWAP_FRAGMENT_LRUQUEUE 0x0002
#define CAPWAP_FRAGMENT_LAST 0x0004
/* */
#define SKB_CAPWAP_FLAG_FROM_DATA_CHANNEL 0x0001
#define SKB_CAPWAP_FLAG_FROM_USER_SPACE 0x0002
#define SKB_CAPWAP_FLAG_FROM_IEEE80211 0x0004
#define SKB_CAPWAP_FLAG_PEERADDRESS 0x0010
#define SKB_CAPWAP_FLAG_RADIOID 0x0020
#define SKB_CAPWAP_FLAG_BINDING 0x0040
#define SKB_CAPWAP_FLAG_RADIOADDRESS 0x0080
#define SKB_CAPWAP_FLAG_WIRELESSINFORMATION 0x0100
#define SKB_CAPWAP_FLAG_FRAGMENT 0x1000
struct sc_skb_capwap_cb {
uint16_t flags;
struct capwap_addr_little peeraddr;
/* Capwap information */
uint8_t radioid;
uint8_t binding;
/* Radio Address */
uint8_t radioaddr_addr[MACADDRESS_EUI48_LENGTH];
/* Wireless Information */
uint8_t winfo_rssi;
uint8_t winfo_snr;
uint16_t winfo_rate;
/* Fragment */
uint16_t frag_offset;
uint16_t frag_length;
};
#define CAPWAP_SKB_CB(skb) ((struct sc_skb_capwap_cb*)((skb)->cb))
/* */
struct sc_capwap_fragment {
struct list_head lru_list;
uint8_t flags;
ktime_t tstamp;
uint16_t fragmentid;
struct sk_buff* fragments;
struct sk_buff* lastfragment;
int recvlength;
int totallength;
};
/* */
struct sc_capwap_fragment_queue {
spinlock_t lock;
struct list_head lru_list;
struct sc_capwap_fragment queues[CAPWAP_FRAGMENT_QUEUE];
};
/* */
struct sc_capwap_session {
struct list_head list;
struct sc_capwap_session* __rcu next;
uint16_t mtu;
union capwap_addr peeraddr;
struct sc_capwap_sessionid_element sessionid;
uint16_t fragmentid;
spinlock_t fragmentid_lock;
struct sc_capwap_fragment_queue fragments;
};
/* */
extern union capwap_addr sc_localaddr;
/* Dipendent implementation function */
void sc_capwap_recvpacket(struct sk_buff* skb);
struct sc_capwap_session* sc_capwap_recvunknownkeepalive(const union capwap_addr* sockaddr, struct sc_capwap_sessionid_element* sessionid);
void sc_capwap_parsingdatapacket(struct sc_capwap_session* session, struct sk_buff* skb);
void sc_capwap_parsingmgmtpacket(struct sc_capwap_session* session, struct sk_buff* skb);
/* Indipendent implementation function */
int sc_capwap_bind(union capwap_addr* sockaddr);
void sc_capwap_initsession(struct sc_capwap_session* session);
void sc_capwap_freesession(struct sc_capwap_session* session);
uint16_t sc_capwap_newfragmentid(struct sc_capwap_session* session);
void sc_capwap_sessionid_printf(const struct sc_capwap_sessionid_element* sessionid, char* string);
struct sc_capwap_packet* sc_capwap_poppacketqueue(struct sc_capwap_session* session);
void sc_capwap_pushpacketqueue(struct sc_capwap_session* session, struct sc_capwap_packet* packet);
int sc_capwap_createkeepalive(struct sc_capwap_sessionid_element* sessionid, uint8_t* buffer, int size);
int sc_capwap_parsingpacket(struct sc_capwap_session* session, const union capwap_addr* sockaddr, struct sk_buff* skb);
struct sc_capwap_radio_addr* sc_capwap_setradiomacaddress(uint8_t* buffer, int size, uint8_t* bssid);
struct sc_capwap_wireless_information* sc_capwap_setwirelessinformation(uint8_t* buffer, int size, uint8_t rssi, uint8_t snr, uint16_t rate);
int sc_capwap_forwarddata(struct sc_capwap_session* session, uint8_t radioid, uint8_t binding, struct sk_buff* skb, uint32_t flags, struct sc_capwap_radio_addr* radioaddr, int radioaddrlength, struct sc_capwap_wireless_information* winfo, int winfolength);
/* Private funciotn */
#include "capwap_private.h"
#endif /* __KMOD_CAPWAP_HEADER__ */

View File

@ -0,0 +1,164 @@
#include "config.h"
#include <linux/module.h>
#include <linux/kthread.h>
#include <net/ipv6.h>
#include "capwap.h"
#include "nlsmartcapwap.h"
#include "netlinkapp.h"
/* */
static struct sc_capwap_session sc_acsession;
/* */
int sc_capwap_init(uint32_t threads) {
TRACEKMOD("### sc_capwap_init\n");
/* Init session */
memset(&sc_localaddr, 0, sizeof(union capwap_addr));
memset(&sc_acsession, 0, sizeof(struct sc_capwap_session));
sc_capwap_initsession(&sc_acsession);
/* Init sockect */
return sc_socket_init();
}
/* */
void sc_capwap_close(void) {
TRACEKMOD("### sc_capwap_close\n");
/* */
sc_socket_close();
sc_capwap_freesession(&sc_acsession);
}
/* */
int sc_capwap_connect(const union capwap_addr* sockaddr, struct sc_capwap_sessionid_element* sessionid, uint16_t mtu) {
TRACEKMOD("### sc_capwap_connect\n");
if ((sc_localaddr.ss.ss_family != AF_INET) && (sc_localaddr.ss.ss_family != AF_INET6)) {
return -ENONET;
}
/* AC address */
if ((sockaddr->ss.ss_family == AF_INET6) && ipv6_addr_v4mapped(&sockaddr->sin6.sin6_addr)) {
return -EINVAL;
} else if ((sc_localaddr.ss.ss_family == AF_INET) && (sockaddr->ss.ss_family == AF_INET6)) {
return -EINVAL;
}
/* */
memcpy(&sc_acsession.peeraddr, sockaddr, sizeof(union capwap_addr));
memcpy(&sc_acsession.sessionid, sessionid, sizeof(struct sc_capwap_sessionid_element));
sc_acsession.mtu = mtu;
return sc_capwap_sendkeepalive();
}
/* */
void sc_capwap_resetsession(void) {
sc_capwap_freesession(&sc_acsession);
/* Reinit session */
memset(&sc_localaddr, 0, sizeof(union capwap_addr));
memset(&sc_acsession, 0, sizeof(struct sc_capwap_session));
sc_capwap_initsession(&sc_acsession);
}
/* */
int sc_capwap_sendkeepalive(void) {
int ret;
int length;
uint8_t buffer[CAPWAP_KEEP_ALIVE_MAX_SIZE];
TRACEKMOD("### sc_capwap_sendkeepalive\n");
/* Build keepalive */
length = sc_capwap_createkeepalive(&sc_acsession.sessionid, buffer, CAPWAP_KEEP_ALIVE_MAX_SIZE);
/* Send packet */
ret = sc_socket_send(SOCKET_UDP, buffer, length, &sc_acsession.peeraddr);
if (ret > 0) {
ret = 0;
}
return ret;
}
/* */
struct sc_capwap_session* sc_capwap_getsession(const union capwap_addr* sockaddr) {
TRACEKMOD("### sc_capwap_getsession\n");
if (!sockaddr) {
return &sc_acsession;
} else if (sc_acsession.peeraddr.ss.ss_family == sockaddr->ss.ss_family) {
if (sc_acsession.peeraddr.ss.ss_family == AF_INET) {
if ((sc_acsession.peeraddr.sin.sin_port == sockaddr->sin.sin_port) && (sc_acsession.peeraddr.sin.sin_addr.s_addr == sockaddr->sin.sin_addr.s_addr)) {
return &sc_acsession;
}
} else if (sc_acsession.peeraddr.ss.ss_family == AF_INET6) {
if ((sc_acsession.peeraddr.sin6.sin6_port == sockaddr->sin6.sin6_port) && !ipv6_addr_cmp(&sc_acsession.peeraddr.sin6.sin6_addr, &sockaddr->sin6.sin6_addr)) {
return &sc_acsession;
}
}
}
return NULL;
}
/* */
void sc_capwap_recvpacket(struct sk_buff* skb) {
union capwap_addr peeraddr;
struct sc_capwap_session* session;
TRACEKMOD("### sc_capwap_recvpacket\n");
/* Get peer address */
if (sc_socket_getpeeraddr(skb, &peeraddr)) {
goto drop;
}
/* Get session */
session = sc_capwap_getsession(&peeraddr);
if (!session) {
TRACEKMOD("*** Session not found\n");
goto drop;
}
/* Remove UDP header */
if (!skb_pull(skb, sizeof(struct udphdr))) {
TRACEKMOD("*** Invalid packet\n");
goto drop;
}
/* Parsing packet */
if (sc_capwap_parsingpacket(session, &peeraddr, skb)) {
TRACEKMOD("*** Parsing error\n");
goto drop;
}
return;
drop:
kfree_skb(skb);
}
/* */
struct sc_capwap_session* sc_capwap_recvunknownkeepalive(const union capwap_addr* sockaddr, struct sc_capwap_sessionid_element* sessionid) {
TRACEKMOD("### sc_capwap_recvunknownkeepalive\n");
return NULL;
}
/* */
void sc_capwap_parsingdatapacket(struct sc_capwap_session* session, struct sk_buff* skb) {
TRACEKMOD("### sc_capwap_parsingdatapacket\n");
}
/* */
void sc_capwap_parsingmgmtpacket(struct sc_capwap_session* session, struct sk_buff* skb) {
TRACEKMOD("### sc_capwap_parsingmgmtpacket\n");
/* Send packet with capwap header into userspace */
sc_netlink_notify_recv_data(skb->data, skb->len);
}

View File

@ -0,0 +1,27 @@
#ifndef __KMOD_CAPWAP_PRIVATE_HEADER__
#define __KMOD_CAPWAP_PRIVATE_HEADER__
/* */
struct sc_capwap_workthread {
struct task_struct* thread;
struct sk_buff_head queue;
wait_queue_head_t waitevent;
};
/* */
int sc_capwap_init(uint32_t threads);
void sc_capwap_close(void);
/* */
int sc_capwap_connect(const union capwap_addr* sockaddr, struct sc_capwap_sessionid_element* sessionid, uint16_t mtu);
void sc_capwap_resetsession(void);
/* */
struct sc_capwap_session* sc_capwap_getsession(const union capwap_addr* sockaddr);
/* */
int sc_capwap_sendkeepalive(void);
#endif /* __KMOD_CAPWAP_PRIVATE_HEADER__ */

172
src/wtp/kmod/capwap_rfc.h Normal file
View File

@ -0,0 +1,172 @@
#ifndef __KMOD_CAPWAP_RFC_HEADER__
#define __KMOD_CAPWAP_RFC_HEADER__
#include <linux/types.h>
#include <asm/byteorder.h>
/* */
#define CAPWAP_RADIOID_MAX_COUNT 31
#define IS_VALID_RADIOID(x) ((x >= 1) && (x <= CAPWAP_RADIOID_MAX_COUNT))
#define CAPWAP_WLANID_MAX_COUNT 16
#define IS_VALID_WLANID(x) ((x >= 1) && (x <= CAPWAP_WLANID_MAX_COUNT))
/* */
#define CAPWAP_WIRELESS_BINDING_NONE 0
#define CAPWAP_WIRELESS_BINDING_IEEE80211 1
/* */
#define CAPWAP_ELEMENT_SESSIONID 35
/* */
#define CAPWAP_KEEPALIVE_SIZE (sizeof(struct sc_capwap_dtls_header) + \
sizeof(struct sc_capwap_header) + \
sizeof(struct sc_capwap_data_message) + \
sizeof(struct sc_capwap_message_element) + \
sizeof(struct sc_capwap_sessionid_element))
/* Preamble */
struct sc_capwap_preamble {
#if defined(__BIG_ENDIAN_BITFIELD)
uint8_t version: 4,
type: 4;
#elif defined(__LITTLE_ENDIAN_BITFIELD)
uint8_t type: 4,
version: 4;
#endif
} __packed;
/* DTLS header */
struct sc_capwap_dtls_header {
struct sc_capwap_preamble preamble;
uint8_t reserved[3];
} __packed;
/* Plain header */
struct sc_capwap_header {
struct sc_capwap_preamble preamble;
#if defined(__BIG_ENDIAN_BITFIELD)
uint16_t hlen: 5,
rid: 5,
wbid: 5,
flag_t: 1;
uint8_t flag_f: 1,
flag_l: 1,
flag_w: 1,
flag_m: 1,
flag_k: 1,
flag_res: 3;
#elif defined(__LITTLE_ENDIAN_BITFIELD)
uint16_t _rid_hi: 3,
hlen: 5,
flag_t: 1,
wbid: 5,
_rid_lo: 2;
uint8_t flag_res: 3,
flag_k: 1,
flag_m: 1,
flag_w: 1,
flag_l: 1,
flag_f: 1;
#endif
__be16 frag_id;
__be16 frag_off;
} __packed;
/* Mac Address */
#define CAPWAP_RADIO_EUI48_LENGTH_PADDED 8
#define CAPWAP_RADIO_EUI64_LENGTH_PADDED 12
#define CAPWAP_RADIO_MAX_LENGTH_PADDED 12
struct sc_capwap_radio_addr {
uint8_t length;
} __packed;
/* Wireless Information */
#define CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED 8
#define CAPWAP_WINFO_DESTWLAN_LENGTH_PADDED 8
#define CAPWAP_WINFO_MAX_LENGTH_PADDED 8
struct sc_capwap_wireless_information {
uint8_t length;
} __packed;
/* IEEE802.11 Wireless Information */
struct sc_capwap_ieee80211_frame_info {
uint8_t rssi;
uint8_t snr;
__be16 rate;
} __packed;
/* */
#define CAPWAP_HEADER_MAX_LENGTH (sizeof(struct sc_capwap_header) + CAPWAP_RADIO_MAX_LENGTH_PADDED + CAPWAP_WINFO_MAX_LENGTH_PADDED)
/* Data channel message */
struct sc_capwap_data_message {
__be16 length;
} __packed;
/* Message element */
struct sc_capwap_message_element {
__be16 type;
__be16 length;
} __packed;
/* Session id message element */
struct sc_capwap_sessionid_element {
uint8_t id[16];
} __packed;
/* */
#define MACADDRESS_EUI48_LENGTH 6
struct sc_capwap_macaddress_eui48 {
uint8_t addr[MACADDRESS_EUI48_LENGTH];
} __packed;
/* */
#define MACADDRESS_EUI64_LENGTH 8
struct sc_capwap_macaddress_eui64 {
uint8_t addr[MACADDRESS_EUI64_LENGTH];
} __packed;
/* Capwap preamble */
#define CAPWAP_PROTOCOL_VERSION 0
#define CAPWAP_PREAMBLE_HEADER 0
#define CAPWAP_PREAMBLE_DTLS_HEADER 1
#define CAPWAP_WIRELESS_BINDING_NONE 0
#define CAPWAP_WIRELESS_BINDING_IEEE80211 1
/* */
#define CAPWAP_KEEP_ALIVE_MAX_SIZE (sizeof(struct sc_capwap_header) + sizeof(struct sc_capwap_data_message) + sizeof(struct sc_capwap_message_element) + sizeof(struct sc_capwap_sessionid_element))
/* */
#define GET_VERSION_HEADER(x) ((x)->preamble.version)
#define SET_VERSION_HEADER(x, y) ((x)->preamble.version = (uint8_t)(y))
#define GET_TYPE_HEADER(x) ((x)->preamble.type)
#define SET_TYPE_HEADER(x, y) ((x)->preamble.type = (uint8_t)(y))
#define GET_HLEN_HEADER(x) ((x)->hlen)
#define SET_HLEN_HEADER(x, y) ((x)->hlen = (uint16_t)(y))
#if defined(__BIG_ENDIAN_BITFIELD)
#define GET_RID_HEADER(x) ((uint8_t)((x)->rid))
#define SET_RID_HEADER(x, y) ((x)->rid = (uint16_t)(y))
#elif defined(__LITTLE_ENDIAN_BITFIELD)
#define GET_RID_HEADER(x) ((uint8_t)((uint16_t)((x)->_rid_hi << 2 | (x)->_rid_lo)))
#define SET_RID_HEADER(x, y) ({ (x)->_rid_hi = (uint16_t)((y) >> 2); (x)->_rid_lo = (uint16_t)((y) & 0x0003); })
#endif
#define GET_WBID_HEADER(x) ((uint8_t)((x)->wbid))
#define SET_WBID_HEADER(x, y) ((x)->wbid = (uint16_t)(y))
#define IS_FLAG_T_HEADER(x) ((x)->flag_t)
#define SET_FLAG_T_HEADER(x, y) ((x)->flag_t = ((y) ? 1 : 0))
#define IS_FLAG_F_HEADER(x) ((x)->flag_f)
#define SET_FLAG_F_HEADER(x, y) ((x)->flag_f = ((y) ? 1 : 0))
#define IS_FLAG_L_HEADER(x) ((x)->flag_l)
#define SET_FLAG_L_HEADER(x, y) ((x)->flag_l = ((y) ? 1 : 0))
#define IS_FLAG_W_HEADER(x) ((x)->flag_w)
#define SET_FLAG_W_HEADER(x, y) ((x)->flag_w = ((y) ? 1 : 0))
#define IS_FLAG_M_HEADER(x) ((x)->flag_m)
#define SET_FLAG_M_HEADER(x, y) ((x)->flag_m = ((y) ? 1 : 0))
#define IS_FLAG_K_HEADER(x) ((x)->flag_k)
#define SET_FLAG_K_HEADER(x, y) ((x)->flag_k = ((y) ? 1 : 0))
#endif /* __KMOD_CAPWAP_RFC_HEADER__ */

13
src/wtp/kmod/config.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef __KMOD_CONFIG_HEADER__
#define __KMOD_CONFIG_HEADER__
#define DEBUGKMOD 1
#ifdef DEBUGKMOD
#define TRACEKMOD(s, args...) printk(s, ##args)
#else
#define TRACEKMOD(s, args...)
#endif
#endif /* __KMOD_CONFIG_HEADER__ */

View File

@ -1,23 +1,31 @@
#include "config.h"
#include <linux/module.h>
#include <linux/kernel.h>
#include "netlinkapp.h"
/* */
static int __init smartcapwap_init(void) {
int result = 0;
static int __init smartcapwap_wtp_init(void) {
int ret;
/* */
result = nlsmartcapwap_init();
TRACEKMOD("### smartcapwap_wtp_init\n");
return result;
/* Initialize netlink */
ret = sc_netlink_init();
if (ret) {
return ret;
}
return ret;
}
module_init(smartcapwap_init);
module_init(smartcapwap_wtp_init);
/* */
static void __exit smartcapwap_exit(void) {
nlsmartcapwap_exit();
static void __exit smartcapwap_wtp_exit(void) {
TRACEKMOD("### smartcapwap_wtp_exit\n");
sc_netlink_exit();
}
module_exit(smartcapwap_exit);
module_exit(smartcapwap_wtp_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Massimo Vellucci <vemax78@gmail.com>");

View File

@ -1,5 +1,7 @@
#include "config.h"
#include <linux/module.h>
#include <linux/rtnetlink.h>
#include <linux/netdevice.h>
#include <linux/netlink.h>
#include <net/genetlink.h>
#include <linux/rcupdate.h>
@ -8,154 +10,200 @@
#include <linux/ieee80211.h>
#include "nlsmartcapwap.h"
#include "netlinkapp.h"
#include "capwap.h"
/* */
struct nlsmartcapwap_device {
struct sc_netlink_device {
struct list_head list;
struct ieee80211_pcktunnel pcktunnel_handler;
u32 usermodeid;
u32 ifindex;
u32 flags;
uint32_t ifindex;
uint8_t radioid;
uint8_t wlanid;
uint8_t binding;
struct net_device* dev;
uint32_t flags;
};
/* */
static u32 nlsmartcapwap_usermodeid = 0;
static LIST_HEAD(nlsmartcapwap_dev_list);
static uint32_t sc_netlink_usermodeid;
static LIST_HEAD(sc_netlink_dev_list);
/* */
static int nlsmartcapwap_pre_doit(__genl_const struct genl_ops* ops, struct sk_buff* skb, struct genl_info* info) {
static int sc_netlink_pre_doit(__genl_const struct genl_ops* ops, struct sk_buff* skb, struct genl_info* info) {
TRACEKMOD("### sc_netlink_pre_doit\n");
rtnl_lock();
return 0;
}
/* */
static void nlsmartcapwap_post_doit(__genl_const struct genl_ops* ops, struct sk_buff* skb, struct genl_info* info) {
static void sc_netlink_post_doit(__genl_const struct genl_ops* ops, struct sk_buff* skb, struct genl_info* info) {
TRACEKMOD("### sc_netlink_post_doit\n");
rtnl_unlock();
}
/* Netlink Family */
static struct genl_family nlsmartcapwap_family = {
static struct genl_family sc_netlink_family = {
.id = GENL_ID_GENERATE,
.name = SMARTCAPWAP_GENL_NAME,
.name = NLSMARTCAPWAP_GENL_NAME,
.hdrsize = 0,
.version = 1,
.maxattr = NLSMARTCAPWAP_ATTR_MAX,
.netnsok = true,
.pre_doit = nlsmartcapwap_pre_doit,
.post_doit = nlsmartcapwap_post_doit,
.pre_doit = sc_netlink_pre_doit,
.post_doit = sc_netlink_post_doit,
};
/* */
static int nlsmartcapwap_handler(u32 ifindex, struct sk_buff* skb, int sig_dbm, unsigned char rate, void* data) {
int result = 0;
int frame8023 = 0;
struct nlsmartcapwap_device* nldev = (struct nlsmartcapwap_device*)data;
static int sc_netlink_handler(uint32_t ifindex, struct sk_buff* skb, int sig_dbm, unsigned char rate, void* data) {
int ret = 0;
struct sc_netlink_device* nldev = (struct sc_netlink_device*)data;
struct ieee80211_hdr* hdr = (struct ieee80211_hdr*)skb->data;
TRACEKMOD("### sc_netlink_handler\n");
/* IEEE802.11 Data Packet */
if (ieee80211_is_data(hdr->frame_control)) {
if ((nldev->flags & SMARTCAPWAP_FLAGS_BLOCK_DATA_FRAME) && ieee80211_is_data_present(hdr->frame_control)) {
result = -1;
int err;
struct sc_capwap_session* session;
unsigned char radioaddrbuffer[CAPWAP_RADIO_EUI48_LENGTH_PADDED];
unsigned char winfobuffer[CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED];
struct sc_capwap_radio_addr* radioaddr = NULL;
struct sc_capwap_wireless_information* winfo = NULL;
printk("*** receive packet\n");
/* Drop packet */
ret = -1;
/* */
session = sc_capwap_getsession(NULL);
if (!session) {
goto error;
}
/* Convert IEEE802.11 to IEEE802.3 */
if (nldev->flags & SMARTCAPWAP_FLAGS_TUNNEL_8023) {
frame8023 = 1;
}
}
/* */
if (nldev->flags & SMARTCAPWAP_FLAGS_SEND_USERSPACE) {
void* msg;
struct sk_buff* sk_msg;
/* Alloc message */
sk_msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
if (sk_msg) {
/* Set command */
msg = genlmsg_put(sk_msg, 0, 0, &nlsmartcapwap_family, 0, NLSMARTCAPWAP_CMD_FRAME);
if (msg) {
/* Set params */
if (nla_put_u32(sk_msg, NLSMARTCAPWAP_ATTR_IFINDEX, nldev->ifindex) ||
nla_put(sk_msg, NLSMARTCAPWAP_ATTR_FRAME, skb->len, skb->data) ||
(frame8023 && nla_put_flag(sk_msg, NLSMARTCAPWAP_ATTR_8023_FRAME)) ||
(sig_dbm && nla_put_u32(sk_msg, NLSMARTCAPWAP_ATTR_RX_SIGNAL_DBM, (u32)sig_dbm)) ||
(rate && nla_put_u8(sk_msg, NLSMARTCAPWAP_ATTR_RX_RATE, (u8)rate))) {
/* Abort message */
genlmsg_cancel(sk_msg, msg);
nlmsg_free(sk_msg);
} else {
/* Send message */
genlmsg_end(sk_msg, msg);
genlmsg_unicast(&init_net, sk_msg, nldev->usermodeid);
}
} else {
nlmsg_free(sk_msg);
/* IEEE 802.11 into IEEE 802.3 */
if (nldev->flags & NLSMARTCAPWAP_FLAGS_TUNNEL_8023) {
if (ieee80211_data_to_8023(skb, nldev->dev->dev_addr, NL80211_IFTYPE_AP)) {
printk("*** convertion error\n");
goto error;
}
/* Create Radio Mac Address */
radioaddr = sc_capwap_setradiomacaddress(radioaddrbuffer, CAPWAP_RADIO_EUI48_LENGTH_PADDED, nldev->dev->dev_addr);
}
/* Create Wireless Information */
if (sig_dbm || rate) {
winfo = sc_capwap_setwirelessinformation(winfobuffer, CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED, (uint8_t)sig_dbm, 0, ((uint16_t)rate) * 5);
}
/* */
CAPWAP_SKB_CB(skb)->flags = SKB_CAPWAP_FLAG_FROM_IEEE80211;
/* Forward to AC */
err = sc_capwap_forwarddata(session, nldev->radioid, nldev->binding, skb, nldev->flags, radioaddr, (radioaddr ? CAPWAP_RADIO_EUI48_LENGTH_PADDED : 0), winfo, (winfo ? CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED : 0));
printk("*** send: %d\n", err);
}
return result;
error:
return ret;
}
/* */
static struct nlsmartcapwap_device* nlsmartcapwap_new_device(u32 ifindex) {
struct nlsmartcapwap_device* nldev;
static struct sc_netlink_device* sc_netlink_new_device(uint32_t ifindex, uint8_t radioid, u8 wlanid, uint8_t binding) {
struct net_device* dev;
struct sc_netlink_device* nldev;
TRACEKMOD("### sc_netlink_new_device\n");
/* Retrieve device from ifindex */
dev = dev_get_by_index(&init_net, ifindex);
if (!dev) {
return NULL;
}
/* Check if wireless device */
if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy) {
dev_put(dev);
return NULL;
}
/* Create device */
nldev = (struct nlsmartcapwap_device*)kzalloc(sizeof(struct nlsmartcapwap_device), GFP_KERNEL);
if (nldev) {
/* Initialize device */
nldev->pcktunnel_handler.handler = nlsmartcapwap_handler;
nldev->pcktunnel_handler.data = (void*)nldev;
nldev->ifindex = ifindex;
nldev = (struct sc_netlink_device*)kzalloc(sizeof(struct sc_netlink_device), GFP_KERNEL);
if (!nldev) {
dev_put(dev);
return NULL;
}
/* Initialize device */
nldev->pcktunnel_handler.handler = sc_netlink_handler;
nldev->pcktunnel_handler.data = (void*)nldev;
nldev->ifindex = ifindex;
nldev->radioid = radioid;
nldev->wlanid = wlanid;
nldev->binding = binding;
nldev->dev = dev;
return nldev;
}
/* */
static void nlsmartcapwap_free_device(struct nlsmartcapwap_device* nldev) {
static void sc_netlink_free_device(struct sc_netlink_device* nldev) {
TRACEKMOD("### sc_netlink_free_device\n");
/* Disconnect device from mac80211 */
ieee80211_pcktunnel_deregister(nldev->ifindex, &nldev->pcktunnel_handler);
ieee80211_pcktunnel_deregister(nldev->dev, &nldev->pcktunnel_handler);
/* */
dev_put(nldev->dev);
/* Free memory */
kfree(nldev);
}
/* */
static struct nlsmartcapwap_device* nlsmartcapwap_register_device(u32 ifindex) {
struct nlsmartcapwap_device* nldev;
static struct sc_netlink_device* sc_netlink_register_device(uint32_t ifindex, uint8_t radioid, uint16_t wlanid, uint8_t binding) {
struct sc_netlink_device* nldev;
TRACEKMOD("### sc_netlink_register_device\n");
ASSERT_RTNL();
/* */
if (!IS_VALID_RADIOID(radioid) || !IS_VALID_WLANID(wlanid)) {
return NULL;
}
/* Search device */
list_for_each_entry(nldev, &nlsmartcapwap_dev_list, list) {
list_for_each_entry(nldev, &sc_netlink_dev_list, list) {
if (nldev->ifindex == ifindex) {
return nldev;
return NULL;
}
}
/* Create device */
nldev = nlsmartcapwap_new_device(ifindex);
nldev = sc_netlink_new_device(ifindex, radioid, wlanid, binding);
if (nldev) {
list_add_rcu(&nldev->list, &nlsmartcapwap_dev_list);
list_add_rcu(&nldev->list, &sc_netlink_dev_list);
}
return nldev;
}
/* */
static int nlsmartcapwap_unregister_device(u32 ifindex) {
static int sc_netlink_unregister_device(uint32_t ifindex) {
int ret = -ENODEV;
struct nlsmartcapwap_device* nldev;
struct sc_netlink_device* nldev;
TRACEKMOD("### sc_netlink_unregister_device\n");
ASSERT_RTNL();
/* Search device */
list_for_each_entry(nldev, &nlsmartcapwap_dev_list, list) {
list_for_each_entry(nldev, &sc_netlink_dev_list, list) {
if (nldev->ifindex == ifindex) {
/* Remove from list */
list_del_rcu(&nldev->list);
@ -163,7 +211,7 @@ static int nlsmartcapwap_unregister_device(u32 ifindex) {
/* Free device */
ret = 0;
nlsmartcapwap_free_device(nldev);
sc_netlink_free_device(nldev);
break;
}
}
@ -172,27 +220,43 @@ static int nlsmartcapwap_unregister_device(u32 ifindex) {
}
/* */
static void nlsmartcapwap_close(void) {
struct nlsmartcapwap_device* nldev;
struct nlsmartcapwap_device* tmp;
static void sc_netlink_unregister_alldevice(void) {
struct sc_netlink_device* tmp;
struct sc_netlink_device* nldev;
list_for_each_entry_safe(nldev, tmp, &nlsmartcapwap_dev_list, list) {
list_del(&nldev->list);
TRACEKMOD("### sc_netlink_unregister_alldevice\n");
ASSERT_RTNL();
/* Close all devices */
list_for_each_entry_safe(nldev, tmp, &sc_netlink_dev_list, list) {
/* Remove from list */
list_del_rcu(&nldev->list);
synchronize_net();
/* Free device */
nlsmartcapwap_free_device(nldev);
sc_netlink_free_device(nldev);
}
}
/* */
static int nlsmartcapwap_link(struct sk_buff* skb, struct genl_info* info) {
int ret = 0;
u32 portid = genl_info_snd_portid(info);
static int sc_netlink_link(struct sk_buff* skb, struct genl_info* info) {
int ret;
uint32_t portid = genl_info_snd_portid(info);
if (!nlsmartcapwap_usermodeid) {
nlsmartcapwap_usermodeid = portid;
} else if (nlsmartcapwap_usermodeid == portid) {
TRACEKMOD("### sc_netlink_link\n");
if (!sc_netlink_usermodeid) {
/* Initialize library */
ret = sc_capwap_init(1);
if (!ret) {
sc_netlink_usermodeid = portid;
/* Deny unload module */
try_module_get(THIS_MODULE);
}
} else if (sc_netlink_usermodeid == portid) {
ret = -EALREADY;
} else {
ret = -EBUSY;
@ -202,19 +266,39 @@ static int nlsmartcapwap_link(struct sk_buff* skb, struct genl_info* info) {
}
/* */
static int nlsmartcapwap_netlink_notify(struct notifier_block* nb, unsigned long state, void* _notify) {
struct netlink_notify* notify = (struct netlink_notify*)_notify;
u32 portid = netlink_notify_portid(notify);
static int sc_netlink_reset(struct sk_buff* skb, struct genl_info* info) {
/* Check Link */
if (sc_netlink_usermodeid != genl_info_snd_portid(info)) {
return -ENOLINK;
}
/* Close all devices */
sc_netlink_unregister_alldevice();
/* Reset session */
sc_capwap_resetsession();
return 0;
}
/* */
static int sc_netlink_notify(struct notifier_block* nb, unsigned long state, void* _notify) {
struct netlink_notify* notify = (struct netlink_notify*)_notify;
/* */
if (state == NETLINK_URELEASE) {
rtnl_lock();
if (nlsmartcapwap_usermodeid == portid) {
nlsmartcapwap_usermodeid = 0;
if (sc_netlink_usermodeid == netlink_notify_portid(notify)) {
sc_netlink_usermodeid = 0;
/* Close all devices */
nlsmartcapwap_close();
sc_netlink_unregister_alldevice();
/* Close capwap engine */
sc_capwap_close();
/* Allow unload module */
module_put(THIS_MODULE);
}
rtnl_unlock();
@ -224,10 +308,194 @@ static int nlsmartcapwap_netlink_notify(struct notifier_block* nb, unsigned long
}
/* */
static int nlsmartcapwap_join_mac80211_device(struct sk_buff* skb, struct genl_info* info) {
u32 ifindex;
struct nlsmartcapwap_device* nldev;
int ret = -EINVAL;
static int sc_netlink_bind(struct sk_buff* skb, struct genl_info* info) {
union capwap_addr sockaddr;
TRACEKMOD("### sc_netlink_bind\n");
/* Check Link */
if (sc_netlink_usermodeid != genl_info_snd_portid(info)) {
return -ENOLINK;
}
/* Get bind address */
if (!info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS] || (nla_len(info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]) != sizeof(struct sockaddr_storage))) {
return -EINVAL;
}
memcpy(&sockaddr.ss, nla_data(info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]), sizeof(struct sockaddr_storage));
if ((sockaddr.ss.ss_family != AF_INET) && (sockaddr.ss.ss_family != AF_INET6)) {
return -EINVAL;
}
/* Bind socket */
return sc_capwap_bind(&sockaddr);
}
/* */
static int sc_netlink_connect(struct sk_buff* skb, struct genl_info* info) {
int ret;
union capwap_addr sockaddr;
struct sc_capwap_sessionid_element sessionid;
uint16_t mtu = DEFAULT_MTU;
TRACEKMOD("### sc_netlink_connect\n");
/* Check Link */
if (sc_netlink_usermodeid != genl_info_snd_portid(info)) {
return -ENOLINK;
}
/* Get AC address */
if (!info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS] || (nla_len(info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]) != sizeof(struct sockaddr_storage))) {
return -EINVAL;
}
memcpy(&sockaddr.ss, nla_data(info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]), sizeof(struct sockaddr_storage));
if ((sockaddr.ss.ss_family != AF_INET) && (sockaddr.ss.ss_family != AF_INET6)) {
return -EINVAL;
}
/* Get MTU */
if (info->attrs[NLSMARTCAPWAP_ATTR_MTU]) {
mtu = nla_get_u16(info->attrs[NLSMARTCAPWAP_ATTR_MTU]);
if ((mtu < MIN_MTU) || (mtu > MAX_MTU)) {
return -EINVAL;
}
}
/* Get Session ID */
if (info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID] && (nla_len(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID]) == sizeof(struct sc_capwap_sessionid_element))) {
memcpy(sessionid.id, nla_data(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID]), sizeof(struct sc_capwap_sessionid_element));
} else {
return -EINVAL;
}
/* Send packet */
ret = sc_capwap_connect(&sockaddr, &sessionid, mtu);
if (ret < 0) {
return ret;
}
return 0;
}
/* */
static int sc_netlink_send_keepalive(struct sk_buff* skb, struct genl_info* info) {
int ret;
TRACEKMOD("### sc_netlink_send_keepalive\n");
/* Check Link */
if (sc_netlink_usermodeid != genl_info_snd_portid(info)) {
return -ENOLINK;
}
/* Send packet */
ret = sc_capwap_sendkeepalive();
if (ret < 0) {
return ret;
}
return 0;
}
/* */
static int sc_netlink_send_data(struct sk_buff* skb, struct genl_info* info) {
int ret;
uint8_t radioid;
uint8_t binding;
uint8_t rssi = 0;
uint8_t snr = 0;
uint16_t rate = 0;
int length;
struct sk_buff* skbdata;
struct sc_capwap_session* session;
unsigned char winfobuffer[CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED];
struct sc_capwap_wireless_information* winfo = NULL;
TRACEKMOD("### sc_netlink_send_data\n");
/* Check Link */
if (sc_netlink_usermodeid != genl_info_snd_portid(info)) {
return -ENOLINK;
} else if (!info->attrs[NLSMARTCAPWAP_ATTR_RADIOID] || !info->attrs[NLSMARTCAPWAP_ATTR_DATA_FRAME]) {
return -EINVAL;
}
/* */
session = sc_capwap_getsession(NULL);
if (!session) {
return -ENOLINK;
}
/* Get radioid */
radioid = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_RADIOID]);
if (!IS_VALID_RADIOID(radioid) || !info->attrs[NLSMARTCAPWAP_ATTR_BINDING]) {
return -EINVAL;
}
/* Get binding */
binding = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_BINDING]);
/* Get RSSI */
if (info->attrs[NLSMARTCAPWAP_ATTR_RSSI]) {
rssi = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_RSSI]);
}
/* Get SNR */
if (info->attrs[NLSMARTCAPWAP_ATTR_SNR]) {
snr = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_SNR]);
}
/* Get RATE */
if (info->attrs[NLSMARTCAPWAP_ATTR_RATE]) {
rate = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_RATE]);
}
/* Create Wireless Information */
if (rssi || snr || rate) {
winfo = sc_capwap_setwirelessinformation(winfobuffer, CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED, rssi, snr, rate);
}
/* Create socket buffer */
length = nla_len(info->attrs[NLSMARTCAPWAP_ATTR_DATA_FRAME]);
skbdata = alloc_skb(length + CAPWAP_HEADER_MAX_LENGTH, GFP_KERNEL);
if (!skbdata) {
return -ENOMEM;
}
/* Reserve space for Capwap Header */
skb_reserve(skbdata, CAPWAP_HEADER_MAX_LENGTH);
/* Copy data into socket buffer */
memcpy(skb_put(skbdata, length), nla_data(info->attrs[NLSMARTCAPWAP_ATTR_DATA_FRAME]), length);
/* */
CAPWAP_SKB_CB(skb)->flags = SKB_CAPWAP_FLAG_FROM_USER_SPACE;
/* Send packet */
ret = sc_capwap_forwarddata(session, radioid, binding, skbdata, 0, NULL, 0, winfo, (winfo ? CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED : 0));
if (ret) {
TRACEKMOD("*** Unable send packet from sc_netlink_send_data function\n");
}
kfree_skb(skbdata);
return ret;
}
/* */
static int sc_netlink_join_mac80211_device(struct sk_buff* skb, struct genl_info* info) {
int ret;
uint32_t ifindex;
struct sc_netlink_device* nldev;
TRACEKMOD("### sc_netlink_join_mac80211_device\n");
/* Check Link */
if (sc_netlink_usermodeid != genl_info_snd_portid(info)) {
return -ENOLINK;
}
/* Get interface index */
if (!info->attrs[NLSMARTCAPWAP_ATTR_IFINDEX]) {
@ -239,8 +507,13 @@ static int nlsmartcapwap_join_mac80211_device(struct sk_buff* skb, struct genl_i
return -EINVAL;
}
/* Check */
if (!info->attrs[NLSMARTCAPWAP_ATTR_RADIOID] || !info->attrs[NLSMARTCAPWAP_ATTR_WLANID] || !info->attrs[NLSMARTCAPWAP_ATTR_BINDING]) {
return -EINVAL;
}
/* Register device */
nldev = nlsmartcapwap_register_device(ifindex);
nldev = sc_netlink_register_device(ifindex, nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_RADIOID]), nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_WLANID]), nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_BINDING]));
if (!nldev) {
return -EINVAL;
}
@ -263,106 +536,240 @@ static int nlsmartcapwap_join_mac80211_device(struct sk_buff* skb, struct genl_i
nldev->pcktunnel_handler.subtype_mask[2] = nla_get_u16(info->attrs[NLSMARTCAPWAP_ATTR_DATA_SUBTYPE_MASK]);
}
/* */
if (nldev->flags & SMARTCAPWAP_FLAGS_SEND_USERSPACE) {
nldev->usermodeid = genl_info_snd_portid(info);
}
/* Connect device to mac80211 */
ret = ieee80211_pcktunnel_register(ifindex, &nldev->pcktunnel_handler);
ret = ieee80211_pcktunnel_register(nldev->dev, &nldev->pcktunnel_handler);
if (ret) {
nlsmartcapwap_unregister_device(ifindex);
sc_netlink_unregister_device(ifindex);
}
return ret;
}
/* */
static int nlsmartcapwap_leave_mac80211_device(struct sk_buff* skb, struct genl_info* info) {
u32 ifindex;
static int sc_netlink_leave_mac80211_device(struct sk_buff* skb, struct genl_info* info) {
TRACEKMOD("### sc_netlink_leave_mac80211_device\n");
/* Check Link */
if (sc_netlink_usermodeid != genl_info_snd_portid(info)) {
return -ENOLINK;
}
/* Get interface index */
if (!info->attrs[NLSMARTCAPWAP_ATTR_IFINDEX]) {
return -EINVAL;
}
ifindex = nla_get_u32(info->attrs[NLSMARTCAPWAP_ATTR_IFINDEX]);
if (!ifindex) {
return -EINVAL;
}
/* Unregister device */
return nlsmartcapwap_unregister_device(ifindex);
return sc_netlink_unregister_device(nla_get_u32(info->attrs[NLSMARTCAPWAP_ATTR_IFINDEX]));
}
/* */
static const struct nla_policy nlsmartcapwap_policy[NLSMARTCAPWAP_ATTR_MAX + 1] = {
static int sc_device_event(struct notifier_block* unused, unsigned long event, void* ptr) {
struct net_device* dev = netdev_notifier_info_to_dev(ptr);
/* Check event only if connect with WTP userspace */
if (!sc_netlink_usermodeid) {
return NOTIFY_DONE;
}
/* */
switch (event) {
case NETDEV_UNREGISTER: {
/* Try to unregister device */
sc_netlink_unregister_device(dev->ifindex);
break;
}
}
return NOTIFY_DONE;
}
/* */
static const struct nla_policy sc_netlink_policy[NLSMARTCAPWAP_ATTR_MAX + 1] = {
[NLSMARTCAPWAP_ATTR_IFINDEX] = { .type = NLA_U32 },
[NLSMARTCAPWAP_ATTR_RADIOID] = { .type = NLA_U8 },
[NLSMARTCAPWAP_ATTR_WLANID] = { .type = NLA_U8 },
[NLSMARTCAPWAP_ATTR_BINDING] = { .type = NLA_U8 },
[NLSMARTCAPWAP_ATTR_FLAGS] = { .type = NLA_U32 },
[NLSMARTCAPWAP_ATTR_MGMT_SUBTYPE_MASK] = { .type = NLA_U16 },
[NLSMARTCAPWAP_ATTR_CTRL_SUBTYPE_MASK] = { .type = NLA_U16 },
[NLSMARTCAPWAP_ATTR_DATA_SUBTYPE_MASK] = { .type = NLA_U16 },
[NLSMARTCAPWAP_ATTR_FRAME] = { .type = NLA_BINARY, .len = IEEE80211_MAX_DATA_LEN },
[NLSMARTCAPWAP_ATTR_8023_FRAME] = { .type = NLA_FLAG },
[NLSMARTCAPWAP_ATTR_RX_SIGNAL_DBM] = { .type = NLA_U32 },
[NLSMARTCAPWAP_ATTR_RX_RATE] = { .type = NLA_U8 },
[NLSMARTCAPWAP_ATTR_ADDRESS] = { .type = NLA_BINARY, .len = sizeof(struct sockaddr_storage) },
[NLSMARTCAPWAP_ATTR_MTU] = { .type = NLA_U16 },
[NLSMARTCAPWAP_ATTR_SESSION_ID] = { .type = NLA_BINARY, .len = sizeof(struct sc_capwap_sessionid_element) },
[NLSMARTCAPWAP_ATTR_DTLS] = { .type = NLA_U16 },
[NLSMARTCAPWAP_ATTR_DATA_FRAME] = { .type = NLA_BINARY, .len = IEEE80211_MTU },
[NLSMARTCAPWAP_ATTR_RSSI] = { .type = NLA_U8 },
[NLSMARTCAPWAP_ATTR_SNR] = { .type = NLA_U8 },
[NLSMARTCAPWAP_ATTR_RATE] = { .type = NLA_U16 },
};
/* Netlink Ops */
static __genl_const struct genl_ops nlsmartcapwap_ops[] = {
static __genl_const struct genl_ops sc_netlink_ops[] = {
{
.cmd = NLSMARTCAPWAP_CMD_LINK,
.doit = nlsmartcapwap_link,
.policy = nlsmartcapwap_policy,
.doit = sc_netlink_link,
.policy = sc_netlink_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NLSMARTCAPWAP_CMD_BIND,
.doit = sc_netlink_bind,
.policy = sc_netlink_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NLSMARTCAPWAP_CMD_CONNECT,
.doit = sc_netlink_connect,
.policy = sc_netlink_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NLSMARTCAPWAP_CMD_RESET,
.doit = sc_netlink_reset,
.policy = sc_netlink_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NLSMARTCAPWAP_CMD_SEND_KEEPALIVE,
.doit = sc_netlink_send_keepalive,
.policy = sc_netlink_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NLSMARTCAPWAP_CMD_SEND_DATA,
.doit = sc_netlink_send_data,
.policy = sc_netlink_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NLSMARTCAPWAP_CMD_JOIN_MAC80211_DEVICE,
.doit = nlsmartcapwap_join_mac80211_device,
.policy = nlsmartcapwap_policy,
.doit = sc_netlink_join_mac80211_device,
.policy = sc_netlink_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NLSMARTCAPWAP_CMD_LEAVE_MAC80211_DEVICE,
.doit = nlsmartcapwap_leave_mac80211_device,
.policy = nlsmartcapwap_policy,
.doit = sc_netlink_leave_mac80211_device,
.policy = sc_netlink_policy,
.flags = GENL_ADMIN_PERM,
},
};
/* Netlink notify */
static struct notifier_block nlsmartcapwap_netlink_notifier = {
.notifier_call = nlsmartcapwap_netlink_notify,
static struct notifier_block sc_netlink_notifier = {
.notifier_call = sc_netlink_notify,
};
/* Interface notify */
struct notifier_block sc_device_notifier = {
.notifier_call = sc_device_event
};
/* */
int nlsmartcapwap_init(void) {
int sc_netlink_notify_recv_keepalive(const union capwap_addr* sockaddr, struct sc_capwap_sessionid_element* sessionid) {
void* msg;
struct sk_buff* sk_msg;
TRACEKMOD("### sc_netlink_notify_recv_keepalive\n");
/* Alloc message */
sk_msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
if (!sk_msg) {
return -ENOMEM;
}
/* Set command */
msg = genlmsg_put(sk_msg, 0, 0, &sc_netlink_family, 0, NLSMARTCAPWAP_CMD_RECV_KEEPALIVE);
if (!msg) {
nlmsg_free(sk_msg);
return -ENOMEM;
}
/* Send message */
genlmsg_end(sk_msg, msg);
return genlmsg_unicast(&init_net, sk_msg, sc_netlink_usermodeid);
}
/* */
int sc_netlink_notify_recv_data(uint8_t* packet, int length) {
void* msg;
struct sk_buff* sk_msg;
TRACEKMOD("### sc_netlink_notify_recv_data\n");
/* Alloc message */
sk_msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
if (!sk_msg) {
return -ENOMEM;
}
/* Set command */
msg = genlmsg_put(sk_msg, 0, 0, &sc_netlink_family, 0, NLSMARTCAPWAP_CMD_RECV_DATA);
if (!msg) {
goto error;
}
/* */
if (nla_put(sk_msg, NLSMARTCAPWAP_ATTR_DATA_FRAME, length, packet)) {
goto error2;
}
/* Send message */
genlmsg_end(sk_msg, msg);
return genlmsg_unicast(&init_net, sk_msg, sc_netlink_usermodeid);
error2:
genlmsg_cancel(sk_msg, msg);
error:
nlmsg_free(sk_msg);
return -ENOMEM;
}
/* */
int sc_netlink_init(void) {
int ret;
/* Register netlink family */
ret = genl_register_family_with_ops(&nlsmartcapwap_family, nlsmartcapwap_ops);
TRACEKMOD("### sc_netlink_init\n");
/* */
sc_netlink_usermodeid = 0;
/* Register interface event */
ret = register_netdevice_notifier(&sc_device_notifier);
if (ret) {
return ret;
goto error;
}
/* Register netlink family */
ret = genl_register_family_with_ops(&sc_netlink_family, sc_netlink_ops);
if (ret) {
goto error2;
}
/* Register netlink notifier */
ret = netlink_register_notifier(&nlsmartcapwap_netlink_notifier);
ret = netlink_register_notifier(&sc_netlink_notifier);
if (ret) {
genl_unregister_family(&nlsmartcapwap_family);
return ret;
goto error3;
}
return 0;
error3:
genl_unregister_family(&sc_netlink_family);
error2:
unregister_netdevice_notifier(&sc_device_notifier);
error:
return ret;
}
/* */
void nlsmartcapwap_exit(void) {
/* */
rtnl_lock();
nlsmartcapwap_close();
rtnl_unlock();
void sc_netlink_exit(void) {
TRACEKMOD("### sc_netlink_exit\n");
/* */
netlink_unregister_notifier(&nlsmartcapwap_netlink_notifier);
genl_unregister_family(&nlsmartcapwap_family);
netlink_unregister_notifier(&sc_netlink_notifier);
genl_unregister_family(&sc_netlink_family);
unregister_netdevice_notifier(&sc_device_notifier);
}

View File

@ -1,8 +1,15 @@
#ifndef __KMOD_CAPWAP_NETLINKAPP_HEADER__
#define __KMOD_CAPWAP_NETLINKAPP_HEADER__
#ifndef __KMOD_WTP_NETLINKAPP_HEADER__
#define __KMOD_WTP_NETLINKAPP_HEADER__
#include "capwap_rfc.h"
#include "socket.h"
/* */
int nlsmartcapwap_init(void);
void nlsmartcapwap_exit(void);
int sc_netlink_init(void);
void sc_netlink_exit(void);
#endif /* __KMOD_CAPWAP_NETLINKAPP_HEADER__ */
/* */
int sc_netlink_notify_recv_keepalive(const union capwap_addr* sockaddr, struct sc_capwap_sessionid_element* sessionid);
int sc_netlink_notify_recv_data(uint8_t* packet, int length);
#endif /* __KMOD_WTP_NETLINKAPP_HEADER__ */

View File

@ -1,19 +1,20 @@
#ifndef __CAPWAP_NLSMARTCAPWAP_HEADER__
#define __CAPWAP_NLSMARTCAPWAP_HEADER__
#ifndef __WTP_NLSMARTCAPWAP_HEADER__
#define __WTP_NLSMARTCAPWAP_HEADER__
/* */
#define SMARTCAPWAP_GENL_NAME "smartcapwap"
#define NLSMARTCAPWAP_GENL_NAME "smartcapwap_wtp"
/* */
#define SMARTCAPWAP_FLAGS_SEND_USERSPACE 0x00000001
#define SMARTCAPWAP_FLAGS_BLOCK_DATA_FRAME 0x00000002
#define SMARTCAPWAP_FLAGS_TUNNEL_8023 0x00000004
#define NLSMARTCAPWAP_FLAGS_TUNNEL_8023 0x00000001
/* */
enum nlsmartcapwap_attrs {
NLSMARTCAPWAP_ATTR_UNSPEC,
NLSMARTCAPWAP_ATTR_IFINDEX,
NLSMARTCAPWAP_ATTR_RADIOID,
NLSMARTCAPWAP_ATTR_WLANID,
NLSMARTCAPWAP_ATTR_BINDING,
NLSMARTCAPWAP_ATTR_FLAGS,
@ -21,10 +22,17 @@ enum nlsmartcapwap_attrs {
NLSMARTCAPWAP_ATTR_CTRL_SUBTYPE_MASK,
NLSMARTCAPWAP_ATTR_DATA_SUBTYPE_MASK,
NLSMARTCAPWAP_ATTR_FRAME,
NLSMARTCAPWAP_ATTR_8023_FRAME,
NLSMARTCAPWAP_ATTR_RX_SIGNAL_DBM,
NLSMARTCAPWAP_ATTR_RX_RATE,
NLSMARTCAPWAP_ATTR_ADDRESS,
NLSMARTCAPWAP_ATTR_MTU,
NLSMARTCAPWAP_ATTR_SESSION_ID,
NLSMARTCAPWAP_ATTR_DTLS,
NLSMARTCAPWAP_ATTR_DATA_FRAME,
NLSMARTCAPWAP_ATTR_RSSI,
NLSMARTCAPWAP_ATTR_SNR,
NLSMARTCAPWAP_ATTR_RATE,
/* Last attribute */
__NLSMARTCAPWAP_ATTR_AFTER_LAST,
@ -37,14 +45,15 @@ enum nlsmartcapwap_commands {
NLSMARTCAPWAP_CMD_LINK,
NLSMARTCAPWAP_CMD_SET_AC_ADDRESS,
NLSMARTCAPWAP_CMD_BIND,
NLSMARTCAPWAP_CMD_CONNECT,
NLSMARTCAPWAP_CMD_TEARDOWN,
NLSMARTCAPWAP_CMD_RESET,
NLSMARTCAPWAP_CMD_SEND_KEEPALIVE,
NLSMARTCAPWAP_CMD_RECV_KEEPALIVE,
NLSMARTCAPWAP_CMD_FRAME,
NLSMARTCAPWAP_CMD_SEND_DATA,
NLSMARTCAPWAP_CMD_RECV_DATA,
NLSMARTCAPWAP_CMD_JOIN_MAC80211_DEVICE,
NLSMARTCAPWAP_CMD_LEAVE_MAC80211_DEVICE,
@ -54,4 +63,4 @@ enum nlsmartcapwap_commands {
NLSMARTCAPWAP_CMD_MAX = __NLSMARTCAPWAP_CMD_AFTER_LAST - 1
};
#endif /* __CAPWAP_NLSMARTCAPWAP_HEADER__ */
#endif /* __WTP_NLSMARTCAPWAP_HEADER__ */

257
src/wtp/kmod/socket.c Normal file
View File

@ -0,0 +1,257 @@
#include "config.h"
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/socket.h>
#include <linux/kthread.h>
#include <linux/net.h>
#include <linux/if_ether.h>
#include <linux/udp.h>
#include <net/ipv6.h>
#include <net/sock.h>
#include <net/udp.h>
#include "socket.h"
#include "capwap.h"
/* Socket */
#define SOCKET_COUNT 2
static struct socket* sc_sockets[SOCKET_COUNT];
/* */
int sc_socket_recvpacket(struct sock* sk, struct sk_buff* skb) {
struct sc_skb_capwap_cb* cb = CAPWAP_SKB_CB(skb);
TRACEKMOD("### sc_socket_recvpacket\n");
/* */
cb->flags = SKB_CAPWAP_FLAG_FROM_DATA_CHANNEL;
/* */
sc_capwap_recvpacket(skb);
return 0;
}
/* */
static int sc_socket_create(int type, union capwap_addr* sockaddr, uint16_t protocol) {
int ret;
TRACEKMOD("### sc_socket_create\n");
/* Create socket */
ret = sock_create_kern(sockaddr->ss.ss_family, SOCK_DGRAM, protocol, &sc_sockets[type]);
if (ret) {
goto failure;
}
/* Bind to interface */
ret = kernel_bind(sc_sockets[type], &sockaddr->sa, sizeof(union capwap_addr));
if (ret) {
goto failure2;
}
/* Set callback */
udp_sk(sc_sockets[type]->sk)->encap_type = 1;
udp_sk(sc_sockets[type]->sk)->encap_rcv = sc_socket_recvpacket;
/* */
if (!((sockaddr->ss.ss_family == AF_INET) ? sockaddr->sin.sin_port : sockaddr->sin6.sin6_port)) {
union capwap_addr localaddr;
int localaddrsize = sizeof(union capwap_addr);
/* Retrieve port */
ret = kernel_getsockname(sc_sockets[type], &localaddr.sa, &localaddrsize);
if (ret) {
goto failure2;
}
/* */
if ((sockaddr->ss.ss_family == AF_INET) && (localaddr.ss.ss_family == AF_INET)) {
sockaddr->sin.sin_port = localaddr.sin.sin_port;
} else if ((sockaddr->ss.ss_family == AF_INET6) && (localaddr.ss.ss_family == AF_INET6)) {
sockaddr->sin6.sin6_port = localaddr.sin6.sin6_port;
} else {
ret = -EFAULT;
goto failure2;
}
}
return ret;
failure2:
sock_release(sc_sockets[type]);
sc_sockets[type] = 0;
failure:
return ret;
}
/* */
int sc_socket_getpeeraddr(struct sk_buff* skb, union capwap_addr* peeraddr) {
unsigned char* nethdr;
TRACEKMOD("### sc_socket_getpeeraddr\n");
/* */
nethdr = skb_network_header(skb);
if (!nethdr) {
return -EINVAL;
}
/* */
switch (ntohs(skb->protocol)) {
case ETH_P_IP: {
/* Validate IPv4 header */
if ((nethdr[0] & 0xf0) != 0x40) {
return -EINVAL;
}
/* Retrieve address */
peeraddr->sin.sin_family = AF_INET;
peeraddr->sin.sin_addr.s_addr = ((struct iphdr*)nethdr)->saddr;
peeraddr->sin.sin_port = udp_hdr(skb)->source;
break;
}
case ETH_P_IPV6: {
/* Validate IPv6 header */
if ((nethdr[0] & 0xf0) != 0x60) {
return -EINVAL;
}
/* Retrieve address */
peeraddr->sin6.sin6_family = AF_INET6;
memcpy(&peeraddr->sin6.sin6_addr, &((struct ipv6hdr*)nethdr)->saddr, sizeof(struct in6_addr));
peeraddr->sin6.sin6_port = udp_hdr(skb)->source;
break;
}
default: {
return -EINVAL;
}
}
return 0;
}
/* */
int sc_socket_send(int type, uint8_t* buffer, int length, union capwap_addr* sockaddr) {
struct kvec vec;
struct msghdr msg;
TRACEKMOD("### sc_socket_send\n");
/* */
vec.iov_base = buffer;
vec.iov_len = length;
/* */
memset(&msg, 0, sizeof(struct msghdr));
msg.msg_name = sockaddr;
msg.msg_namelen = sizeof(union capwap_addr);
msg.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT;
/* */
return kernel_sendmsg(sc_sockets[type], &msg, &vec, 1, length);
}
/* */
int sc_socket_init(void) {
TRACEKMOD("### sc_socket_init\n");
memset(sc_sockets, 0, sizeof(sc_sockets));
return 0;
}
/* */
int sc_socket_bind(union capwap_addr* sockaddr) {
int ret;
TRACEKMOD("### sc_socket_bind\n");
/* */
if (sc_sockets[SOCKET_UDP] || sc_sockets[SOCKET_UDPLITE]) {
return -EBUSY;
}
/* UDP socket */
ret = sc_socket_create(SOCKET_UDP, sockaddr, IPPROTO_UDP);
if (ret) {
goto failure;
}
/* UDPLite socket */
ret = sc_socket_create(SOCKET_UDPLITE, sockaddr, IPPROTO_UDPLITE);
if (ret) {
goto failure;
}
/* */
udp_encap_enable();
if (sockaddr->ss.ss_family == AF_INET6) {
udpv6_encap_enable();
}
return 0;
failure:
sc_socket_close();
return ret;
}
/* */
void sc_socket_close(void) {
TRACEKMOD("### sc_socket_close\n");
/* Close sockets */
if (sc_sockets[SOCKET_UDP]) {
kernel_sock_shutdown(sc_sockets[SOCKET_UDP], SHUT_RDWR);
sock_release(sc_sockets[SOCKET_UDP]);
}
if (sc_sockets[SOCKET_UDPLITE]) {
kernel_sock_shutdown(sc_sockets[SOCKET_UDPLITE], SHUT_RDWR);
sock_release(sc_sockets[SOCKET_UDPLITE]);
}
memset(sc_sockets, 0, sizeof(sc_sockets));
}
/* */
int sc_addr_compare(const union capwap_addr* addr1, const union capwap_addr* addr2) {
TRACEKMOD("### sc_addr_compare\n");
if (addr1->ss.ss_family == addr2->ss.ss_family) {
if (addr1->ss.ss_family == AF_INET) {
return (((addr1->sin.sin_addr.s_addr == addr2->sin.sin_addr.s_addr) && (addr1->sin.sin_port == addr2->sin.sin_port)) ? 0 : -1);
} else if (addr1->ss.ss_family == AF_INET6) {
return ((!memcmp(&addr1->sin6.sin6_addr, &addr2->sin6.sin6_addr, sizeof(struct in6_addr)) && (addr1->sin6.sin6_port == addr2->sin6.sin6_port)) ? 0 : -1);
}
}
return -1;
}
/* */
void sc_addr_tolittle(const union capwap_addr* addr, struct capwap_addr_little* little) {
little->family = (uint8_t)addr->ss.ss_family;
if (little->family == AF_INET) {
memcpy(&little->addr4, &addr->sin.sin_addr, sizeof(struct in_addr));
little->port = addr->sin.sin_port;
} else if (little->family == AF_INET6) {
memcpy(&little->addr6, &addr->sin6.sin6_addr, sizeof(struct in6_addr));
little->port = addr->sin6.sin6_port;
}
}
/* */
void sc_addr_fromlittle(const struct capwap_addr_little* little, union capwap_addr* addr) {
memset(addr, 0, sizeof(union capwap_addr));
addr->ss.ss_family = little->family;
if (little->family == AF_INET) {
memcpy(&addr->sin.sin_addr, &little->addr4, sizeof(struct in_addr));
addr->sin.sin_port = little->port;
} else if (little->family == AF_INET6) {
memcpy(&addr->sin6.sin6_addr, &little->addr6, sizeof(struct in6_addr));
addr->sin6.sin6_port = little->port;
}
}

45
src/wtp/kmod/socket.h Normal file
View File

@ -0,0 +1,45 @@
#ifndef __KMOD_SOCKET_HEADER__
#define __KMOD_SOCKET_HEADER__
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/in6.h>
#include <linux/skbuff.h>
/* */
#define SOCKET_UDP 0
#define SOCKET_UDPLITE 1
/* Little socket address */
struct capwap_addr_little {
uint8_t family;
union {
struct in_addr addr4;
struct in6_addr addr6;
};
uint16_t port;
};
/* Universal socket address */
union capwap_addr {
struct sockaddr sa;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
struct sockaddr_storage ss;
};
/* */
int sc_socket_init(void);
void sc_socket_close(void);
/* */
int sc_socket_bind(union capwap_addr* sockaddr);
int sc_socket_send(int type, uint8_t* buffer, int length, union capwap_addr* sockaddr);
int sc_socket_getpeeraddr(struct sk_buff* skb, union capwap_addr* peeraddr);
/* */
int sc_addr_compare(const union capwap_addr* addr1, const union capwap_addr* addr2);
void sc_addr_tolittle(const union capwap_addr* addr, struct capwap_addr_little* little);
void sc_addr_fromlittle(const struct capwap_addr_little* little, union capwap_addr* addr);
#endif /* __KMOD_SOCKET_HEADER__ */

View File

@ -62,7 +62,6 @@ static int wtp_init(void) {
g_wtp.mactype.type = CAPWAP_LOCALMAC;
g_wtp.mactunnel.mode = CAPWAP_WTP_LOCAL_BRIDGING;
g_wtp.tunneldataframe = WTP_TUNNEL_DATA_FRAME_KERNELMODE;
/* DTLS */
g_wtp.validdtlsdatapolicy = CAPWAP_ACDESC_CLEAR_DATA_CHANNEL_ENABLED;
@ -76,8 +75,8 @@ static int wtp_init(void) {
/* AC information */
g_wtp.discoverytype.type = CAPWAP_DISCOVERYTYPE_TYPE_UNKNOWN;
g_wtp.acdiscoveryrequest = 1;
g_wtp.acdiscoveryarray = capwap_array_create(sizeof(struct sockaddr_storage), 0, 0);
g_wtp.acpreferedarray = capwap_array_create(sizeof(struct sockaddr_storage), 0, 0);
g_wtp.acdiscoveryarray = capwap_array_create(sizeof(union sockaddr_capwap), 0, 0);
g_wtp.acpreferedarray = capwap_array_create(sizeof(union sockaddr_capwap), 0, 0);
g_wtp.acdiscoveryresponse = capwap_array_create(sizeof(struct wtp_discovery_response), 0, 1);
/* Radios */
@ -135,48 +134,22 @@ static void wtp_destroy(void) {
wtp_radio_free();
}
/* Save AC address */
static int wtp_add_acaddress(struct sockaddr_storage* source, struct capwap_array* array) {
ASSERT(source != NULL);
ASSERT(array != NULL);
if ((g_wtp.net.sock_family == AF_UNSPEC) || (g_wtp.net.sock_family == source->ss_family)) {
struct sockaddr_storage* destaddr = (struct sockaddr_storage*)capwap_array_get_item_pointer(array, array->count);
/* Save address, if request, mapping IPv4 to IPv6 */
if ((g_wtp.net.sock_family == AF_UNSPEC) && (source->ss_family == AF_INET) && !(g_wtp.net.bind_ctrl_flags & CAPWAP_IPV6ONLY_FLAG)) {
if (!capwap_ipv4_mapped_ipv6(source, destaddr)) {
memcpy(destaddr, source, sizeof(struct sockaddr_storage));
}
} else {
memcpy(destaddr, source, sizeof(struct sockaddr_storage));
}
return 1;
}
return 0;
}
/* */
static int wtp_add_default_acaddress() {
struct sockaddr_storage address;
struct sockaddr_in* addressv4 = (struct sockaddr_in*)&address;
/*struct sockaddr_in6* addressv6 = (struct sockaddr_in6*)&address;*/
static void wtp_add_default_acaddress() {
union sockaddr_capwap address;
/* Broadcast IPv4 */
addressv4->sin_family = AF_INET;
addressv4->sin_addr.s_addr = INADDR_BROADCAST;
addressv4->sin_port = htons(CAPWAP_CONTROL_PORT);
wtp_add_acaddress(&address, g_wtp.acdiscoveryarray);
memset(&address, 0, sizeof(union sockaddr_capwap));
address.sin.sin_family = AF_INET;
address.sin.sin_addr.s_addr = INADDR_BROADCAST;
address.sin.sin_port = htons(CAPWAP_CONTROL_PORT);
memcpy(capwap_array_get_item_pointer(g_wtp.acdiscoveryarray, g_wtp.acdiscoveryarray->count), &address, sizeof(union sockaddr_capwap));
/* Multicast IPv4 */
/* TODO */
/* Multicast IPv6 */
/* TODO */
return ((g_wtp.acdiscoveryarray->count > 0) ? 1 : 0);
}
/* Help */
@ -514,8 +487,6 @@ static int wtp_parsing_radio_configuration(config_setting_t* configElement, stru
static int wtp_parsing_configuration_1_0(config_t* config) {
int i;
int configBool;
int configIPv4;
int configIPv6;
LIBCONFIG_LOOKUP_INT_ARG configInt;
const char* configString;
config_setting_t* configSetting;
@ -651,19 +622,6 @@ static int wtp_parsing_configuration_1_0(config_t* config) {
g_wtp.mactunnel.mode |= CAPWAP_WTP_LOCAL_BRIDGING;
}
}
if (config_lookup_string(config, "application.tunnelmode.dataframe", &configString) == CONFIG_TRUE) {
if (!strcmp(configString, "none")) {
g_wtp.tunneldataframe = WTP_TUNNEL_DATA_FRAME_NONE;
} else if (!strcmp(configString, "kernelmode")) {
g_wtp.tunneldataframe = WTP_TUNNEL_DATA_FRAME_KERNELMODE;
} else if (!strcmp(configString, "usermode")) {
g_wtp.tunneldataframe = WTP_TUNNEL_DATA_FRAME_USERMODE;
} else {
capwap_logging_error("Invalid configuration file, unknown application.tunnelmode.dataframe value");
return 0;
}
}
}
/* Set mactype of WTP */
@ -1094,7 +1052,7 @@ static int wtp_parsing_configuration_1_0(config_t* config) {
return 0;
}
strcpy(g_wtp.net.bind_interface, configString);
strcpy(g_wtp.net.bindiface, configString);
}
/* Set mtu of WTP */
@ -1107,16 +1065,6 @@ static int wtp_parsing_configuration_1_0(config_t* config) {
}
}
/* Set network port of WTP */
if (config_lookup_int(config, "application.network.port", &configInt) == CONFIG_TRUE) {
if ((configInt > 0) && (configInt < 65535)) {
g_wtp.net.bind_sock_ctrl_port = (unsigned short)configInt;
} else {
capwap_logging_error("Invalid configuration file, invalid application.network.port value");
return 0;
}
}
/* Set transport of WTP */
if (config_lookup_string(config, "application.network.transport", &configString) == CONFIG_TRUE) {
if (!strcmp(configString, "udp")) {
@ -1129,35 +1077,6 @@ static int wtp_parsing_configuration_1_0(config_t* config) {
}
}
/* Set ipv4 & ipv6 of WTP */
if (config_lookup_bool(config, "application.network.ipv4", &configIPv4) != CONFIG_TRUE) {
configIPv4 = 1;
}
if (config_lookup_bool(config, "application.network.ipv6", &configIPv6) != CONFIG_TRUE) {
configIPv6 = 1;
}
if (configIPv4 && configIPv6) {
g_wtp.net.sock_family = AF_UNSPEC;
} else if (!configIPv4 && !configIPv6) {
capwap_logging_error("Invalid configuration file, request enable application.network.ipv4 or application.network.ipv6");
return 0;
} else {
g_wtp.net.sock_family = (configIPv4 ? AF_INET : AF_INET6);
}
/* Set ip dual stack of WTP */
if (config_lookup_bool(config, "application.network.ipdualstack", &configBool) == CONFIG_TRUE) {
if (!configBool) {
g_wtp.net.bind_ctrl_flags |= CAPWAP_IPV6ONLY_FLAG;
g_wtp.net.bind_data_flags |= CAPWAP_IPV6ONLY_FLAG;
} else {
g_wtp.net.bind_ctrl_flags &= ~CAPWAP_IPV6ONLY_FLAG;
g_wtp.net.bind_data_flags &= ~CAPWAP_IPV6ONLY_FLAG;
}
}
/* Set search discovery of WTP */
if (config_lookup_bool(config, "application.acdiscovery.search", &configBool) == CONFIG_TRUE) {
g_wtp.acdiscoveryrequest = (configBool ? 1 : 0);
@ -1167,19 +1086,19 @@ static int wtp_parsing_configuration_1_0(config_t* config) {
configSetting = config_lookup(config, "application.acdiscovery.host");
if (configSetting != NULL) {
int count = config_setting_length(configSetting);
for (i = 0; i < count; i++) {
const char* address = config_setting_get_string_elem(configSetting, i);
if (address != NULL) {
struct sockaddr_storage acaddr;
union sockaddr_capwap acaddr;
/* Parsing address */
if (capwap_address_from_string(address, &acaddr)) {
if (!CAPWAP_GET_NETWORK_PORT(&acaddr)) {
CAPWAP_SET_NETWORK_PORT(&acaddr, CAPWAP_CONTROL_PORT);
}
wtp_add_acaddress(&acaddr, g_wtp.acdiscoveryarray);
memcpy(capwap_array_get_item_pointer(g_wtp.acdiscoveryarray, g_wtp.acdiscoveryarray->count), &acaddr, sizeof(union sockaddr_capwap));
g_wtp.discoverytype.type = CAPWAP_DISCOVERYTYPE_TYPE_STATIC;
} else {
capwap_logging_error("Invalid configuration file, invalid application.acdiscovery.host value");
@ -1193,19 +1112,19 @@ static int wtp_parsing_configuration_1_0(config_t* config) {
configSetting = config_lookup(config, "application.acprefered.host");
if (configSetting != NULL) {
int count = config_setting_length(configSetting);
for (i = 0; i < count; i++) {
const char* address = config_setting_get_string_elem(configSetting, i);
if (address != NULL) {
struct sockaddr_storage acaddr;
union sockaddr_capwap acaddr;
/* Parsing address */
if (capwap_address_from_string(address, &acaddr)) {
if (!CAPWAP_GET_NETWORK_PORT(&acaddr)) {
CAPWAP_SET_NETWORK_PORT(&acaddr, CAPWAP_CONTROL_PORT);
}
wtp_add_acaddress(&acaddr, g_wtp.acpreferedarray);
memcpy(capwap_array_get_item_pointer(g_wtp.acpreferedarray, g_wtp.acpreferedarray->count), &acaddr, sizeof(union sockaddr_capwap));
} else {
capwap_logging_error("Invalid configuration file, invalid application.acprefered.host value");
return 0;
@ -1294,17 +1213,25 @@ static int wtp_load_configuration(int argc, char **argv) {
/* Init WTP */
static int wtp_configure(void) {
/* If not set try IPv6 */
if (g_wtp.net.localaddr.ss.ss_family == AF_UNSPEC) {
g_wtp.net.localaddr.ss.ss_family = AF_INET6;
}
/* If request add default acdiscovery */
if (!g_wtp.acdiscoveryarray->count) {
if (!wtp_add_default_acaddress()) {
capwap_logging_debug("Unable add default AC discovery");
return WTP_ERROR_NETWORK;
}
wtp_add_default_acaddress();
}
/* Bind to any address */
if (!capwap_bind_sockets(&g_wtp.net)) {
capwap_logging_fatal("Cannot bind address");
/* Bind control address */
if (capwap_bind_sockets(&g_wtp.net)) {
capwap_logging_fatal("Cannot bind control address");
return WTP_ERROR_NETWORK;
}
/* Bind data address */
if (wtp_kmod_bind(g_wtp.net.localaddr.ss.ss_family)) {
capwap_logging_fatal("Cannot bind data address");
return WTP_ERROR_NETWORK;
}
@ -1396,11 +1323,8 @@ int main(int argc, char** argv) {
wtp_wait_radio_ready();
/* Connect WTP with kernel module */
value = wtp_kmod_init();
if (!value || !g_wtp.kmodrequest) {
if (wtp_kmod_isconnected()) {
capwap_logging_info("SmartCAPWAP kernel module connected");
}
if (!wtp_kmod_init()) {
capwap_logging_info("SmartCAPWAP kernel module connected");
/* */
capwap_logging_info("Startup WTP");
@ -1411,7 +1335,7 @@ int main(int argc, char** argv) {
/* Running WTP */
result = wtp_dfa_running();
/* Close socket */
/* Close sockets */
capwap_close_sockets(&g_wtp.net);
}

View File

@ -68,13 +68,13 @@ struct wtp_t {
int running;
/* */
int kmodrequest;
struct wtp_kmod_handle kmodhandle;
/* */
char wlanprefix[IFNAMSIZ];
/* */
unsigned short mtu;
struct capwap_network net;
struct wtp_fds fds;
@ -113,21 +113,20 @@ struct wtp_t {
struct capwap_statisticstimer_element statisticstimer;
struct capwap_wtprebootstat_element rebootstat;
int tunneldataframe;
struct capwap_packet_rxmng* rxmngctrlpacket;
struct capwap_packet_rxmng* rxmngdatapacket;
/* */
unsigned short fragmentid;
struct capwap_packet_rxmng* rxmngpacket;
/* */
unsigned char localseqnumber;
unsigned char remoteseqnumber;
unsigned short mtu;
unsigned short fragmentid;
uint8_t localseqnumber;
struct capwap_list* requestfragmentpacket;
struct capwap_list* responsefragmentpacket;
unsigned char lastrecvpackethash[16];
int retransmitcount;
/* */
uint32_t remotetype;
uint8_t remoteseqnumber;
struct capwap_list* responsefragmentpacket;
/* */
int acdiscoveryrequest;
unsigned long acpreferedselected;
@ -135,13 +134,6 @@ struct wtp_t {
struct capwap_array* acpreferedarray;
struct capwap_array* acdiscoveryresponse;
struct sockaddr_storage wtpctrladdress;
struct sockaddr_storage wtpdataaddress;
struct sockaddr_storage acctrladdress;
struct sockaddr_storage acdataaddress;
struct capwap_socket acctrlsock;
struct capwap_socket acdatasock;
/* */
struct capwap_array* radios;
@ -154,8 +146,7 @@ struct wtp_t {
unsigned char dtlsdatapolicy;
unsigned char validdtlsdatapolicy;
struct capwap_dtls_context dtlscontext;
struct capwap_dtls ctrldtls;
struct capwap_dtls datadtls;
struct capwap_dtls dtls;
int faileddtlssessioncount;
int faileddtlsauthfailcount;
};

View File

@ -17,39 +17,24 @@ static void wtp_signal_handler(int signum) {
}
/* */
static struct capwap_packet_rxmng* wtp_get_packet_rxmng(int isctrlmsg) {
struct capwap_packet_rxmng* rxmngpacket = NULL;
if (isctrlmsg) {
if (!g_wtp.rxmngctrlpacket) {
g_wtp.rxmngctrlpacket = capwap_packet_rxmng_create_message(CAPWAP_CONTROL_PACKET);
}
rxmngpacket = g_wtp.rxmngctrlpacket;
} else {
if (!g_wtp.rxmngdatapacket) {
g_wtp.rxmngdatapacket = capwap_packet_rxmng_create_message(CAPWAP_DATA_PACKET);
}
rxmngpacket = g_wtp.rxmngdatapacket;
static struct capwap_packet_rxmng* wtp_get_packet_rxmng(void) {
if (!g_wtp.rxmngpacket) {
g_wtp.rxmngpacket = capwap_packet_rxmng_create_message();
}
return rxmngpacket;
return g_wtp.rxmngpacket;
}
/* */
void wtp_free_packet_rxmng(int isctrlmsg) {
if (isctrlmsg && g_wtp.rxmngctrlpacket) {
capwap_packet_rxmng_free(g_wtp.rxmngctrlpacket);
g_wtp.rxmngctrlpacket = NULL;
} else if (!isctrlmsg && g_wtp.rxmngdatapacket) {
capwap_packet_rxmng_free(g_wtp.rxmngdatapacket);
g_wtp.rxmngdatapacket = NULL;
void wtp_free_packet_rxmng(void) {
if (g_wtp.rxmngpacket) {
capwap_packet_rxmng_free(g_wtp.rxmngpacket);
g_wtp.rxmngpacket = NULL;
}
}
/* */
static void wtp_send_invalid_request(struct capwap_packet_rxmng* rxmngpacket, struct capwap_connection* connection, uint32_t errorcode) {
static void wtp_send_invalid_request(struct capwap_packet_rxmng* rxmngpacket, uint32_t errorcode) {
struct capwap_header_data capwapheader;
struct capwap_packet_txmng* txmngpacket;
struct capwap_list* responsefragmentpacket;
@ -59,7 +44,6 @@ static void wtp_send_invalid_request(struct capwap_packet_rxmng* rxmngpacket, st
ASSERT(rxmngpacket != NULL);
ASSERT(rxmngpacket->fragmentlist->first != NULL);
ASSERT(connection != NULL);
/* */
packet = (struct capwap_fragment_packet_item*)rxmngpacket->fragmentlist->first->item;
@ -83,7 +67,7 @@ static void wtp_send_invalid_request(struct capwap_packet_rxmng* rxmngpacket, st
capwap_packet_txmng_free(txmngpacket);
/* Send unknown response */
capwap_crypt_sendto_fragmentpacket(&g_wtp.ctrldtls, connection->socket.socket[connection->socket.type], responsefragmentpacket, &connection->localaddr, &connection->remoteaddr);
capwap_crypt_sendto_fragmentpacket(&g_wtp.dtls, responsefragmentpacket);
/* Don't buffering a packets sent */
capwap_list_free(responsefragmentpacket);
@ -142,7 +126,7 @@ static void wtp_dfa_execute(struct capwap_parsed_packet* packet) {
}
/* */
static int wtp_recvfrom(struct wtp_fds* fds, void* buffer, int* size, struct sockaddr_storage* recvfromaddr, struct sockaddr_storage* recvtoaddr) {
static int wtp_recvfrom(struct wtp_fds* fds, void* buffer, int* size, union sockaddr_capwap* recvfromaddr, union sockaddr_capwap* recvtoaddr) {
int index;
ASSERT(fds != NULL);
@ -185,7 +169,7 @@ static int wtp_recvfrom(struct wtp_fds* fds, void* buffer, int* size, struct soc
}
/* Receive packet */
if (!capwap_recvfrom_fd(fds->fdspoll[index].fd, buffer, size, recvfromaddr, recvtoaddr)) {
if (capwap_recvfrom(fds->fdspoll[index].fd, buffer, size, recvfromaddr, recvtoaddr)) {
return CAPWAP_RECV_ERROR_SOCKET;
}
@ -335,13 +319,11 @@ int wtp_dfa_running(void) {
char* buffer;
int buffersize;
struct capwap_socket socket;
struct capwap_connection connection;
struct capwap_parsed_packet packet;
int index;
struct sockaddr_storage recvfromaddr;
struct sockaddr_storage recvtoaddr;
union sockaddr_capwap fromaddr;
union sockaddr_capwap toaddr;
/* Init */
memset(&packet, 0, sizeof(struct capwap_parsed_packet));
@ -366,79 +348,51 @@ int wtp_dfa_running(void) {
/* If request wait packet from AC */
buffer = bufferencrypt;
buffersize = CAPWAP_MAX_PACKET_SIZE;
index = wtp_recvfrom(&g_wtp.fds, buffer, &buffersize, &recvfromaddr, &recvtoaddr);
index = wtp_recvfrom(&g_wtp.fds, buffer, &buffersize, &fromaddr, &toaddr);
if (!g_wtp.running) {
capwap_logging_debug("Closing WTP, Teardown connection");
wtp_dfa_closeapp();
break;
} else if (index >= 0) {
if (g_wtp.teardown) {
/* Drop packet */
continue;
continue; /* Drop packet */
} else {
int check;
/* Retrieve network information */
capwap_get_network_socket(&g_wtp.net, &socket, g_wtp.fds.fdspoll[index].fd);
/* Check source */
if (socket.isctrlsocket && (g_wtp.acctrladdress.ss_family != AF_UNSPEC)) {
if (capwap_compare_ip(&g_wtp.acctrladdress, &recvfromaddr)) {
/* Unknown source */
continue;
}
} else if (!socket.isctrlsocket && (g_wtp.acdataaddress.ss_family != AF_UNSPEC)) {
if (capwap_compare_ip(&g_wtp.acdataaddress, &recvfromaddr)) {
/* Unknown source */
continue;
}
if (capwap_compare_ip(&g_wtp.dtls.peeraddr, &fromaddr)) {
continue; /* Unknown source */
}
/* Check of packet */
check = capwap_sanity_check(socket.isctrlsocket, g_wtp.state, buffer, buffersize, g_wtp.ctrldtls.enable, g_wtp.datadtls.enable);
check = capwap_sanity_check(g_wtp.state, buffer, buffersize, g_wtp.dtls.enable);
if (check == CAPWAP_DTLS_PACKET) {
struct capwap_dtls* dtls = (socket.isctrlsocket ? &g_wtp.ctrldtls : &g_wtp.datadtls);
int oldaction = g_wtp.dtls.action;
if (dtls->enable) {
int oldaction = dtls->action;
/* Decrypt packet */
buffersize = capwap_decrypt_packet(dtls, buffer, buffersize, bufferplain, CAPWAP_MAX_PACKET_SIZE);
if (buffersize > 0) {
buffer = bufferplain;
check = CAPWAP_PLAIN_PACKET;
} else if (buffersize == CAPWAP_ERROR_AGAIN) {
/* Check is handshake complete */
if ((oldaction == CAPWAP_DTLS_ACTION_HANDSHAKE) && (dtls->action == CAPWAP_DTLS_ACTION_DATA)) {
if (socket.isctrlsocket) {
if (g_wtp.state == CAPWAP_DTLS_CONNECT_STATE) {
check = CAPWAP_NONE_PACKET;
wtp_send_join();
} else {
check = CAPWAP_WRONG_PACKET;
wtp_teardown_connection();
}
} else {
if (g_wtp.state == CAPWAP_DATA_CHECK_STATE) {
check = CAPWAP_NONE_PACKET;
wtp_start_datachannel();
} else {
check = CAPWAP_WRONG_PACKET;
wtp_teardown_connection();
}
}
}
continue; /* Next packet */
} else {
if ((oldaction == CAPWAP_DTLS_ACTION_DATA) && (dtls->action == CAPWAP_DTLS_ACTION_SHUTDOWN)) {
/* Decrypt packet */
buffersize = capwap_decrypt_packet(&g_wtp.dtls, buffer, buffersize, bufferplain, CAPWAP_MAX_PACKET_SIZE);
if (buffersize > 0) {
buffer = bufferplain;
check = CAPWAP_PLAIN_PACKET;
} else if (buffersize == CAPWAP_ERROR_AGAIN) {
/* Check is handshake complete */
if ((oldaction == CAPWAP_DTLS_ACTION_HANDSHAKE) && (g_wtp.dtls.action == CAPWAP_DTLS_ACTION_DATA)) {
if (g_wtp.state == CAPWAP_DTLS_CONNECT_STATE) {
check = CAPWAP_NONE_PACKET;
wtp_send_join();
} else {
check = CAPWAP_WRONG_PACKET;
wtp_teardown_connection();
}
continue; /* Next packet */
}
continue; /* Next packet */
} else {
continue; /* Drop packet */
if ((oldaction == CAPWAP_DTLS_ACTION_DATA) && (g_wtp.dtls.action == CAPWAP_DTLS_ACTION_SHUTDOWN)) {
wtp_teardown_connection();
}
continue; /* Next packet */
}
} else if (check == CAPWAP_WRONG_PACKET) {
capwap_logging_debug("Warning: sanity check failure");
@ -450,30 +404,8 @@ int wtp_dfa_running(void) {
if (check == CAPWAP_PLAIN_PACKET) {
struct capwap_packet_rxmng* rxmngpacket;
/* Detect local address */
if (recvtoaddr.ss_family == AF_UNSPEC) {
if (capwap_get_localaddress_by_remoteaddress(&recvtoaddr, &recvfromaddr, g_wtp.net.bind_interface, (!(g_wtp.net.bind_ctrl_flags & CAPWAP_IPV6ONLY_FLAG) ? 1 : 0))) {
struct sockaddr_storage sockinfo;
socklen_t sockinfolen = sizeof(struct sockaddr_storage);
memset(&sockinfo, 0, sizeof(struct sockaddr_storage));
if (getsockname(g_wtp.fds.fdspoll[index].fd, (struct sockaddr*)&sockinfo, &sockinfolen) < 0) {
break;
}
CAPWAP_SET_NETWORK_PORT(&recvtoaddr, CAPWAP_GET_NETWORK_PORT(&sockinfo));
}
}
/* */
if (socket.isctrlsocket) {
capwap_logging_debug("Receive control packet");
} else {
capwap_logging_debug("Receive data packet");
}
/* Defragment management */
rxmngpacket = wtp_get_packet_rxmng(socket.isctrlsocket);
rxmngpacket = wtp_get_packet_rxmng();
/* If request, defragmentation packet */
check = capwap_packet_rxmng_add_recv_packet(rxmngpacket, buffer, buffersize);
@ -481,63 +413,61 @@ int wtp_dfa_running(void) {
continue;
} else if (check != CAPWAP_RECEIVE_COMPLETE_PACKET) {
/* Discard fragments */
wtp_free_packet_rxmng(socket.isctrlsocket);
wtp_free_packet_rxmng();
continue;
}
/* Receive all fragment */
memcpy(&connection.socket, &socket, sizeof(struct capwap_socket));
memcpy(&connection.localaddr, &recvtoaddr, sizeof(struct sockaddr_storage));
memcpy(&connection.remoteaddr, &recvfromaddr, sizeof(struct sockaddr_storage));
/* Check for already response to packet */
if (socket.isctrlsocket) {
if (capwap_recv_retrasmitted_request(&g_wtp.ctrldtls, rxmngpacket, &connection, g_wtp.lastrecvpackethash, g_wtp.responsefragmentpacket)) {
wtp_free_packet_rxmng(socket.isctrlsocket);
capwap_logging_debug("Retrasmitted packet");
continue;
if (capwap_is_request_type(rxmngpacket->ctrlmsg.type) && (g_wtp.remotetype == rxmngpacket->ctrlmsg.type) && (g_wtp.remoteseqnumber == rxmngpacket->ctrlmsg.seq)) {
/* Retransmit response */
if (!capwap_crypt_sendto_fragmentpacket(&g_wtp.dtls, g_wtp.responsefragmentpacket)) {
capwap_logging_error("Error to resend response packet");
} else {
capwap_logging_debug("Retrasmitted control packet");
}
/* Check message type */
res = capwap_check_message_type(rxmngpacket);
if (res != VALID_MESSAGE_TYPE) {
if (res == INVALID_REQUEST_MESSAGE_TYPE) {
capwap_logging_warning("Unexpected Unrecognized Request, send Response Packet with error");
wtp_send_invalid_request(rxmngpacket, &connection, CAPWAP_RESULTCODE_MSG_UNEXPECTED_UNRECOGNIZED_REQUEST);
}
continue;
}
capwap_logging_debug("Invalid message type");
wtp_free_packet_rxmng(socket.isctrlsocket);
continue;
/* Check message type */
res = capwap_check_message_type(rxmngpacket);
if (res != VALID_MESSAGE_TYPE) {
if (res == INVALID_REQUEST_MESSAGE_TYPE) {
capwap_logging_warning("Unexpected Unrecognized Request, send Response Packet with error");
wtp_send_invalid_request(rxmngpacket, CAPWAP_RESULTCODE_MSG_UNEXPECTED_UNRECOGNIZED_REQUEST);
}
capwap_logging_debug("Invalid message type");
wtp_free_packet_rxmng();
continue;
}
/* Parsing packet */
res = capwap_parsing_packet(rxmngpacket, &connection, &packet);
res = capwap_parsing_packet(rxmngpacket, &packet);
if (res != PARSING_COMPLETE) {
if (socket.isctrlsocket && (res == UNRECOGNIZED_MESSAGE_ELEMENT) && capwap_is_request_type(rxmngpacket->ctrlmsg.type)) {
if ((res == UNRECOGNIZED_MESSAGE_ELEMENT) && capwap_is_request_type(rxmngpacket->ctrlmsg.type)) {
capwap_logging_warning("Unrecognized Message Element, send Response Packet with error");
wtp_send_invalid_request(rxmngpacket, &connection, CAPWAP_RESULTCODE_FAILURE_UNRECOGNIZED_MESSAGE_ELEMENT);
wtp_send_invalid_request(rxmngpacket, CAPWAP_RESULTCODE_FAILURE_UNRECOGNIZED_MESSAGE_ELEMENT);
/* TODO: add the unrecognized message element */
}
/* */
capwap_free_parsed_packet(&packet);
wtp_free_packet_rxmng(socket.isctrlsocket);
wtp_free_packet_rxmng();
capwap_logging_debug("Failed parsing packet");
continue;
}
/* Validate packet */
if (capwap_validate_parsed_packet(&packet, NULL)) {
if (socket.isctrlsocket && capwap_is_request_type(rxmngpacket->ctrlmsg.type)) {
if (capwap_is_request_type(rxmngpacket->ctrlmsg.type)) {
capwap_logging_warning("Missing Mandatory Message Element, send Response Packet with error");
wtp_send_invalid_request(rxmngpacket, &connection, CAPWAP_RESULTCODE_FAILURE_MISSING_MANDATORY_MSG_ELEMENT);
wtp_send_invalid_request(rxmngpacket, CAPWAP_RESULTCODE_FAILURE_MISSING_MANDATORY_MSG_ELEMENT);
}
/* */
capwap_free_parsed_packet(&packet);
wtp_free_packet_rxmng(socket.isctrlsocket);
wtp_free_packet_rxmng();
capwap_logging_debug("Failed validation parsed packet");
continue;
}
@ -547,7 +477,7 @@ int wtp_dfa_running(void) {
/* Free packet */
capwap_free_parsed_packet(&packet);
wtp_free_packet_rxmng(socket.isctrlsocket);
wtp_free_packet_rxmng();
}
}
} else if ((index == CAPWAP_RECV_ERROR_INTR) || (index == WTP_RECV_NOERROR_RADIO)) {
@ -580,24 +510,32 @@ void wtp_free_reference_last_request(void) {
/* */
void wtp_free_reference_last_response(void) {
capwap_list_flush(g_wtp.responsefragmentpacket);
memset(&g_wtp.lastrecvpackethash[0], 0, sizeof(g_wtp.lastrecvpackethash));
g_wtp.remotetype = 0;
g_wtp.remoteseqnumber = 0;
}
/* */
void wtp_dfa_retransmition_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param) {
g_wtp.retransmitcount++;
if (g_wtp.retransmitcount >= WTP_MAX_RETRANSMIT) {
/* Timeout state */
wtp_free_reference_last_request();
if (!g_wtp.requestfragmentpacket->count) {
capwap_logging_warning("Invalid retransmition request packet");
wtp_teardown_connection();
} else {
/* Retransmit request */
capwap_logging_debug("Retransmition request packet");
if (!capwap_crypt_sendto_fragmentpacket(&g_wtp.ctrldtls, g_wtp.acctrlsock.socket[g_wtp.acctrlsock.type], g_wtp.requestfragmentpacket, &g_wtp.wtpctrladdress, &g_wtp.acctrladdress)) {
capwap_logging_error("Error to send request packet");
}
g_wtp.retransmitcount++;
if (g_wtp.retransmitcount >= WTP_MAX_RETRANSMIT) {
capwap_logging_info("Retransmition request packet timeout");
/* Update timeout */
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_RETRANSMIT_INTERVAL, wtp_dfa_retransmition_timeout, NULL, NULL);
/* Timeout state */
wtp_free_reference_last_request();
wtp_teardown_connection();
} else {
/* Retransmit request */
capwap_logging_debug("Retransmition request packet");
if (!capwap_crypt_sendto_fragmentpacket(&g_wtp.dtls, g_wtp.requestfragmentpacket)) {
capwap_logging_error("Error to send request packet");
}
/* Update timeout */
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_RETRANSMIT_INTERVAL, wtp_dfa_retransmition_timeout, NULL, NULL);
}
}
}

View File

@ -13,14 +13,11 @@ struct wtp_discovery_response {
void wtp_free_discovery_response_array(void);
/* */
int wtp_bio_send(struct capwap_dtls* dtls, char* buffer, int length, void* param);
/* */
void wtp_teardown_connection(void);
/* */
void wtp_free_packet_rxmng(int isctrlmsg);
void wtp_free_packet_rxmng(void);
void wtp_free_reference_last_request(void);
void wtp_free_reference_last_response(void);
@ -69,6 +66,8 @@ void wtp_dfa_state_reset(void);
/* */
void wtp_ieee80211_packet(uint8_t radioid, const struct ieee80211_header* header, int length);
int wtp_send_data_packet(uint8_t radioid, uint8_t wlanid, const uint8_t* frame, int length, int nativeframe, uint8_t rssi, uint8_t snr, uint16_t rate, uint8_t* bssaddress, int bssaddresstype);
void wtp_recv_data_keepalive(void);
void wtp_recv_data(uint8_t* buffer, int length);
#endif /* __WTP_DFA_HEADER__ */

View File

@ -10,6 +10,7 @@
void wtp_send_configure(void) {
int i;
struct capwap_header_data capwapheader;
struct capwap_acnamepriority_element acnamepriority;
struct capwap_packet_txmng* txmngpacket;
/* Build packet */
@ -21,8 +22,12 @@ void wtp_send_configure(void) {
wtp_create_radioadmstate_element(txmngpacket);
capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_STATISTICSTIMER, &g_wtp.statisticstimer);
capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_WTPREBOOTSTAT, &g_wtp.rebootstat);
/* CAPWAP_ELEMENT_ACNAMEPRIORITY */ /* TODO */
capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_TRANSPORT, &g_wtp.transport);
acnamepriority.priority = 1;
acnamepriority.name = g_wtp.acname.name;
capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_ACNAMEPRIORITY, &acnamepriority);
/* CAPWAP_ELEMENT_WTPSTATICIPADDRESS */ /* TODO */
if (g_wtp.binding == CAPWAP_WIRELESS_BINDING_IEEE80211) {
@ -86,7 +91,7 @@ void wtp_send_configure(void) {
capwap_packet_txmng_free(txmngpacket);
/* Send Configuration Status request to AC */
if (capwap_crypt_sendto_fragmentpacket(&g_wtp.ctrldtls, g_wtp.acctrlsock.socket[g_wtp.acctrlsock.type], g_wtp.requestfragmentpacket, &g_wtp.wtpctrladdress, &g_wtp.acctrladdress)) {
if (capwap_crypt_sendto_fragmentpacket(&g_wtp.dtls, g_wtp.requestfragmentpacket)) {
g_wtp.retransmitcount = 0;
wtp_dfa_change_state(CAPWAP_CONFIGURE_STATE);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_RETRANSMIT_INTERVAL, wtp_dfa_retransmition_timeout, NULL, NULL);
@ -106,7 +111,7 @@ void wtp_dfa_state_configure(struct capwap_parsed_packet* packet) {
/* */
binding = GET_WBID_HEADER(packet->rxmngpacket->header);
if (packet->rxmngpacket->isctrlpacket && (binding == g_wtp.binding) && (packet->rxmngpacket->ctrlmsg.type == CAPWAP_CONFIGURATION_STATUS_RESPONSE) && ((g_wtp.localseqnumber - 1) == packet->rxmngpacket->ctrlmsg.seq)) {
if ((binding == g_wtp.binding) && (packet->rxmngpacket->ctrlmsg.type == CAPWAP_CONFIGURATION_STATUS_RESPONSE) && ((g_wtp.localseqnumber - 1) == packet->rxmngpacket->ctrlmsg.seq)) {
/* Valid packet, free request packet */
wtp_free_reference_last_request();

View File

@ -32,7 +32,7 @@ void wtp_send_datacheck(void) {
capwap_packet_txmng_free(txmngpacket);
/* Send Change State Event request to AC */
if (capwap_crypt_sendto_fragmentpacket(&g_wtp.ctrldtls, g_wtp.acctrlsock.socket[g_wtp.acctrlsock.type], g_wtp.requestfragmentpacket, &g_wtp.wtpctrladdress, &g_wtp.acctrladdress)) {
if (capwap_crypt_sendto_fragmentpacket(&g_wtp.dtls, g_wtp.requestfragmentpacket)) {
g_wtp.retransmitcount = 0;
wtp_dfa_change_state(CAPWAP_DATA_CHECK_STATE);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_RETRANSMIT_INTERVAL, wtp_dfa_retransmition_timeout, NULL, NULL);
@ -51,7 +51,7 @@ void wtp_dfa_state_datacheck(struct capwap_parsed_packet* packet) {
/* */
binding = GET_WBID_HEADER(packet->rxmngpacket->header);
if (packet->rxmngpacket->isctrlpacket && (binding == g_wtp.binding) && (packet->rxmngpacket->ctrlmsg.type == CAPWAP_CHANGE_STATE_EVENT_RESPONSE) && ((g_wtp.localseqnumber - 1) == packet->rxmngpacket->ctrlmsg.seq)) {
if ((binding == g_wtp.binding) && (packet->rxmngpacket->ctrlmsg.type == CAPWAP_CHANGE_STATE_EVENT_RESPONSE) && ((g_wtp.localseqnumber - 1) == packet->rxmngpacket->ctrlmsg.seq)) {
/* Valid packet, free request packet */
wtp_free_reference_last_request();

View File

@ -28,76 +28,62 @@ void wtp_dfa_state_discovery_timeout(struct capwap_timeout* timeout, unsigned lo
int i, j, w;
int countwtp = -1;
int indexpreferred = -1;
struct sockaddr_storage checkaddr;
struct sockaddr_in* checkaddripv4;
struct sockaddr_in6* checkaddripv6;
union sockaddr_capwap checkaddr;
union sockaddr_capwap peeraddr;
/* */
g_wtp.acctrladdress.ss_family = AF_UNSPEC;
peeraddr.ss.ss_family = AF_UNSPEC;
/* Selected by preferred or less WTP by AC */
for (i = 0; i < g_wtp.acdiscoveryresponse->count; i++) {
struct wtp_discovery_response* response = (struct wtp_discovery_response*)capwap_array_get_item_pointer(g_wtp.acdiscoveryresponse, i);
/* AC with IPv4 */
if ((g_wtp.net.sock_family == AF_UNSPEC) || (g_wtp.net.sock_family == AF_INET)) {
for (w = 0; w < response->controlipv4->count; w++) {
struct capwap_controlipv4_element* controlipv4 = (struct capwap_controlipv4_element*)capwap_array_get_item_pointer(response->controlipv4, w);
for (w = 0; w < response->controlipv4->count; w++) {
struct capwap_controlipv4_element* controlipv4 = (struct capwap_controlipv4_element*)capwap_array_get_item_pointer(response->controlipv4, w);
/* Create IPv4 address */
memset(&checkaddr, 0, sizeof(struct sockaddr_storage));
checkaddripv4 = (struct sockaddr_in*)&checkaddr;
checkaddripv4->sin_family = AF_INET;
checkaddripv4->sin_port = htons(CAPWAP_CONTROL_PORT);
memcpy(&checkaddripv4->sin_addr, &controlipv4->address, sizeof(struct in_addr));
/* Create IPv4 address */
checkaddr.sin.sin_family = AF_INET;
memcpy(&checkaddr.sin.sin_addr, &controlipv4->address, sizeof(struct in_addr));
checkaddr.sin.sin_port = htons(CAPWAP_CONTROL_PORT);
/* Check for preferred AC */
for (j = 0; j < ((indexpreferred != -1) ? indexpreferred : g_wtp.acpreferedarray->count); j++) {
struct sockaddr_storage* acpreferredaddr = (struct sockaddr_storage*)capwap_array_get_item_pointer(g_wtp.acpreferedarray, j);
/* Check for preferred AC */
for (j = 0; j < ((indexpreferred != -1) ? indexpreferred : g_wtp.acpreferedarray->count); j++) {
union sockaddr_capwap* acpreferredaddr = (union sockaddr_capwap*)capwap_array_get_item_pointer(g_wtp.acpreferedarray, j);
if (!capwap_compare_ip(acpreferredaddr, &checkaddr)) {
indexpreferred = j;
memcpy(&g_wtp.acctrladdress, &checkaddr, sizeof(struct sockaddr_storage));
capwap_get_network_socket(&g_wtp.net, &g_wtp.acctrlsock, capwap_get_socket(&g_wtp.net, g_wtp.acctrladdress.ss_family, IPPROTO_UDP, 1));
capwap_get_network_socket(&g_wtp.net, &g_wtp.acdatasock, capwap_get_socket(&g_wtp.net, g_wtp.acctrladdress.ss_family, (g_wtp.transport.type == CAPWAP_UDP_TRANSPORT ? IPPROTO_UDP : IPPROTO_UDPLITE), CAPWAP_DATA_SOCKET));
break;
}
if (!capwap_compare_ip(acpreferredaddr, &checkaddr)) {
indexpreferred = j;
memcpy(&peeraddr, &checkaddr, sizeof(union sockaddr_capwap));
break;
}
}
/* Check by number of WTP */
if (indexpreferred == -1) {
if ((countwtp == -1) || (countwtp > controlipv4->wtpcount)) {
countwtp = controlipv4->wtpcount;
memcpy(&g_wtp.acctrladdress, &checkaddr, sizeof(struct sockaddr_storage));
capwap_get_network_socket(&g_wtp.net, &g_wtp.acctrlsock, capwap_get_socket(&g_wtp.net, g_wtp.acctrladdress.ss_family, IPPROTO_UDP, 1));
capwap_get_network_socket(&g_wtp.net, &g_wtp.acdatasock, capwap_get_socket(&g_wtp.net, g_wtp.acctrladdress.ss_family, (g_wtp.transport.type == CAPWAP_UDP_TRANSPORT ? IPPROTO_UDP : IPPROTO_UDPLITE), CAPWAP_DATA_SOCKET));
}
/* Check by number of WTP */
if (indexpreferred == -1) {
if ((countwtp == -1) || (countwtp > controlipv4->wtpcount)) {
countwtp = controlipv4->wtpcount;
memcpy(&peeraddr, &checkaddr, sizeof(union sockaddr_capwap));
}
}
}
/* AC with IPv6 */
if ((g_wtp.net.sock_family == AF_UNSPEC) || (g_wtp.net.sock_family == AF_INET6)) {
if ((g_wtp.net.localaddr.ss.ss_family == AF_INET6)) {
for (w = 0; w < response->controlipv6->count; w++) {
struct capwap_controlipv6_element* controlipv6 = (struct capwap_controlipv6_element*)capwap_array_get_item_pointer(response->controlipv6, w);
/* Create IPv6 address */
memset(&checkaddr, 0, sizeof(struct sockaddr_storage));
checkaddripv6 = (struct sockaddr_in6*)&checkaddr;
checkaddripv6->sin6_family = AF_INET6;
checkaddripv6->sin6_port = htons(CAPWAP_CONTROL_PORT);
memcpy(&checkaddripv6->sin6_addr, &controlipv6->address, sizeof(struct in6_addr));
checkaddr.sin6.sin6_family = AF_INET6;
memcpy(&checkaddr.sin6.sin6_addr, &controlipv6->address, sizeof(struct in6_addr));
checkaddr.sin6.sin6_port = htons(CAPWAP_CONTROL_PORT);
/* Check for preferred AC */
for (j = 0; j < ((indexpreferred != -1) ? indexpreferred : g_wtp.acpreferedarray->count); j++) {
struct sockaddr_storage* acpreferredaddr = (struct sockaddr_storage*)capwap_array_get_item_pointer(g_wtp.acpreferedarray, j);
union sockaddr_capwap* acpreferredaddr = (union sockaddr_capwap*)capwap_array_get_item_pointer(g_wtp.acpreferedarray, j);
if (!capwap_compare_ip(acpreferredaddr, &checkaddr)) {
indexpreferred = j;
memcpy(&g_wtp.acctrladdress, &checkaddr, sizeof(struct sockaddr_storage));
capwap_get_network_socket(&g_wtp.net, &g_wtp.acctrlsock, capwap_get_socket(&g_wtp.net, g_wtp.acctrladdress.ss_family, IPPROTO_UDP, 1));
capwap_get_network_socket(&g_wtp.net, &g_wtp.acdatasock, capwap_get_socket(&g_wtp.net, g_wtp.acctrladdress.ss_family, (g_wtp.transport.type == CAPWAP_UDP_TRANSPORT ? IPPROTO_UDP : IPPROTO_UDPLITE), CAPWAP_DATA_SOCKET));
memcpy(&peeraddr, &checkaddr, sizeof(union sockaddr_capwap));
break;
}
}
@ -106,9 +92,7 @@ void wtp_dfa_state_discovery_timeout(struct capwap_timeout* timeout, unsigned lo
if (indexpreferred == -1) {
if ((countwtp == -1) || (countwtp > controlipv6->wtpcount)) {
countwtp = controlipv6->wtpcount;
memcpy(&g_wtp.acctrladdress, &checkaddr, sizeof(struct sockaddr_storage));
capwap_get_network_socket(&g_wtp.net, &g_wtp.acctrlsock, capwap_get_socket(&g_wtp.net, g_wtp.acctrladdress.ss_family, IPPROTO_UDP, 1));
capwap_get_network_socket(&g_wtp.net, &g_wtp.acdatasock, capwap_get_socket(&g_wtp.net, g_wtp.acctrladdress.ss_family, (g_wtp.transport.type == CAPWAP_UDP_TRANSPORT ? IPPROTO_UDP : IPPROTO_UDPLITE), CAPWAP_DATA_SOCKET));
memcpy(&peeraddr, &checkaddr, sizeof(union sockaddr_capwap));
}
}
}
@ -119,32 +103,24 @@ void wtp_dfa_state_discovery_timeout(struct capwap_timeout* timeout, unsigned lo
wtp_free_discovery_response_array();
/* Change state if found AC */
if (g_wtp.acctrladdress.ss_family != AF_UNSPEC) {
memcpy(&g_wtp.acdataaddress, &g_wtp.acctrladdress, sizeof(struct sockaddr_storage));
CAPWAP_SET_NETWORK_PORT(&g_wtp.acdataaddress, CAPWAP_GET_NETWORK_PORT(&g_wtp.acdataaddress) + 1);
if (peeraddr.ss.ss_family != AF_UNSPEC) {
union sockaddr_capwap localaddr;
/* Retrieve local address */
if (capwap_get_localaddress_by_remoteaddress(&g_wtp.wtpctrladdress, &g_wtp.acctrladdress, g_wtp.net.bind_interface, (!(g_wtp.net.bind_ctrl_flags & CAPWAP_IPV6ONLY_FLAG) ? 1 : 0))) {
struct sockaddr_storage sockinfo;
socklen_t sockinfolen = sizeof(struct sockaddr_storage);
if (!capwap_network_get_localaddress(&localaddr, &peeraddr, g_wtp.net.bindiface)) {
CAPWAP_SET_NETWORK_PORT(&localaddr, CAPWAP_GET_NETWORK_PORT(&g_wtp.net.localaddr));
memset(&sockinfo, 0, sizeof(struct sockaddr_storage));
if (!getsockname(g_wtp.acctrlsock.socket[g_wtp.acctrlsock.type], (struct sockaddr*)&sockinfo, &sockinfolen)) {
CAPWAP_SET_NETWORK_PORT(&g_wtp.wtpctrladdress, CAPWAP_GET_NETWORK_PORT(&sockinfo));
/* */
capwap_crypt_setconnection(&g_wtp.dtls, g_wtp.net.socket, &localaddr, &peeraddr);
/* */
memcpy(&g_wtp.wtpdataaddress, &g_wtp.wtpctrladdress, sizeof(struct sockaddr_storage));
CAPWAP_SET_NETWORK_PORT(&g_wtp.wtpdataaddress, CAPWAP_GET_NETWORK_PORT(&g_wtp.wtpdataaddress) + 1);
/* */
if (!g_wtp.enabledtls) {
wtp_send_join(); /* Bypass DTLS connection */
} else {
wtp_start_dtlssetup(); /* Create DTLS connection */
}
return;
/* */
if (!g_wtp.enabledtls) {
wtp_send_join(); /* Bypass DTLS connection */
} else {
wtp_start_dtlssetup(); /* Create DTLS connection */
}
return;
}
}
}
@ -193,15 +169,8 @@ void wtp_dfa_state_discovery_timeout(struct capwap_timeout* timeout, unsigned lo
/* Send discovery request to AC */
for (i = 0; i < g_wtp.acdiscoveryarray->count; i++) {
int sock;
struct sockaddr_storage* sendtoaddr = (struct sockaddr_storage*)capwap_array_get_item_pointer(g_wtp.acdiscoveryarray, i);
sock = capwap_get_socket(&g_wtp.net, sendtoaddr->ss_family, IPPROTO_UDP, 1);
if (sock >= 0) {
if (!capwap_sendto_fragmentpacket(sock, g_wtp.requestfragmentpacket, NULL, sendtoaddr)) {
capwap_logging_debug("Warning: error to send discovery request packet");
break;
}
if (!capwap_sendto_fragmentpacket(g_wtp.net.socket, g_wtp.requestfragmentpacket, (union sockaddr_capwap*)capwap_array_get_item_pointer(g_wtp.acdiscoveryarray, i))) {
capwap_logging_debug("Warning: error to send discovery request packet");
}
}
@ -223,7 +192,7 @@ void wtp_dfa_state_discovery(struct capwap_parsed_packet* packet) {
/* */
binding = GET_WBID_HEADER(packet->rxmngpacket->header);
if (packet->rxmngpacket->isctrlpacket && (binding == g_wtp.binding) && (packet->rxmngpacket->ctrlmsg.type == CAPWAP_DISCOVERY_RESPONSE) && ((g_wtp.localseqnumber - 1) == packet->rxmngpacket->ctrlmsg.seq)) {
if ((binding == g_wtp.binding) && (packet->rxmngpacket->ctrlmsg.type == CAPWAP_DISCOVERY_RESPONSE) && ((g_wtp.localseqnumber - 1) == packet->rxmngpacket->ctrlmsg.seq)) {
struct capwap_resultcode_element* resultcode;
/* Check the success of the Request */

View File

@ -7,23 +7,14 @@ static void wtp_dfa_state_dtlsconnect_timeout(struct capwap_timeout* timeout, un
wtp_teardown_connection();
}
/* DTLS BIO send */
int wtp_bio_send(struct capwap_dtls* dtls, char* buffer, int length, void* param) {
struct capwap_socket* socket = ((dtls->session == CAPWAP_DTLS_CONTROL_SESSION) ? &g_wtp.acctrlsock : &g_wtp.acdatasock);
struct sockaddr_storage* wtpaddress = ((dtls->session == CAPWAP_DTLS_CONTROL_SESSION) ? &g_wtp.wtpctrladdress : &g_wtp.wtpdataaddress);
struct sockaddr_storage* acaddress = ((dtls->session == CAPWAP_DTLS_CONTROL_SESSION) ? &g_wtp.acctrladdress : &g_wtp.acdataaddress);
return capwap_sendto(socket->socket[socket->type], buffer, length, wtpaddress, acaddress);
}
/* */
void wtp_start_dtlssetup(void) {
/* Create DTLS session */
if (!capwap_crypt_createsession(&g_wtp.ctrldtls, CAPWAP_DTLS_CONTROL_SESSION, &g_wtp.dtlscontext, wtp_bio_send, NULL)) {
if (!capwap_crypt_createsession(&g_wtp.dtls, &g_wtp.dtlscontext)) {
wtp_dfa_change_state(CAPWAP_SULKING_STATE);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_SILENT_INTERVAL, wtp_dfa_state_sulking_timeout, NULL, NULL);
} else {
if (capwap_crypt_open(&g_wtp.ctrldtls, &g_wtp.acctrladdress) == CAPWAP_HANDSHAKE_ERROR) {
if (capwap_crypt_open(&g_wtp.dtls) == CAPWAP_HANDSHAKE_ERROR) {
wtp_dfa_change_state(CAPWAP_SULKING_STATE);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_SILENT_INTERVAL, wtp_dfa_state_sulking_timeout, NULL, NULL);
} else {
@ -35,77 +26,34 @@ void wtp_start_dtlssetup(void) {
/* */
void wtp_start_datachannel(void) {
struct capwap_list* txfragpacket;
struct capwap_header_data capwapheader;
struct capwap_packet_txmng* txmngpacket;
union sockaddr_capwap dataaddr;
/* If need, create DTLS Data channel crypted */
if (g_wtp.dtlsdatapolicy & CAPWAP_ACDESC_DTLS_DATA_CHANNEL_ENABLED) {
if (!g_wtp.datadtls.enable) {
/* Create DTLS data session before send data keepalive */
if (capwap_crypt_createsession(&g_wtp.datadtls, CAPWAP_DTLS_DATA_SESSION, &g_wtp.dtlscontext, wtp_bio_send, NULL)) {
if (capwap_crypt_open(&g_wtp.datadtls, &g_wtp.acdataaddress) == CAPWAP_HANDSHAKE_CONTINUE) {
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_DTLS_INTERVAL, wtp_dfa_state_dtlsconnect_timeout, NULL, NULL); /* Wait complete dtls handshake */
} else {
wtp_teardown_connection();
}
} else {
wtp_teardown_connection();
}
/* Set AC data address */
memcpy(&dataaddr, &g_wtp.dtls.peeraddr, sizeof(union sockaddr_capwap));
CAPWAP_SET_NETWORK_PORT(&dataaddr, (CAPWAP_GET_NETWORK_PORT(&g_wtp.dtls.peeraddr) + 1));
return;
} else if (g_wtp.datadtls.action != CAPWAP_DTLS_ACTION_DATA) {
wtp_teardown_connection();
return;
}
}
/* Connect to AC data channel */
if (!wtp_kmod_connect(&dataaddr.ss, &g_wtp.sessionid, g_wtp.mtu)) {
/* Reset AC Prefered List Position */
g_wtp.acpreferedselected = 0;
/* Build packet */
capwap_header_init(&capwapheader, CAPWAP_RADIOID_NONE, g_wtp.binding);
capwap_header_set_keepalive_flag(&capwapheader, 1);
txmngpacket = capwap_packet_txmng_create_data_message(&capwapheader, g_wtp.mtu); /* CAPWAP_DONT_FRAGMENT */
/* Add message element */
capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_SESSIONID, &g_wtp.sessionid);
/* Data keepalive complete, get fragment packets into local list */
txfragpacket = capwap_list_create();
capwap_packet_txmng_get_fragment_packets(txmngpacket, txfragpacket, 0);
if (txfragpacket->count == 1) {
/* Send Data keepalive to AC */
if (capwap_crypt_sendto_fragmentpacket(&g_wtp.datadtls, g_wtp.acdatasock.socket[g_wtp.acdatasock.type], txfragpacket, &g_wtp.wtpdataaddress, &g_wtp.acdataaddress)) {
/* Reset AC Prefered List Position */
g_wtp.acpreferedselected = 0;
/* Set timer */
wtp_dfa_change_state(CAPWAP_RUN_STATE);
capwap_timeout_unset(g_wtp.timeout, g_wtp.idtimercontrol);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimerecho, g_wtp.echointerval, wtp_dfa_state_run_echo_timeout, NULL, NULL);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimerkeepalivedead, WTP_DATACHANNEL_KEEPALIVEDEAD, wtp_dfa_state_run_keepalivedead_timeout, NULL, NULL);
} else {
/* Error to send packets */
capwap_logging_debug("Warning: error to send data channel keepalive packet");
wtp_teardown_connection();
}
/* Set timer */
wtp_dfa_change_state(CAPWAP_RUN_STATE);
capwap_timeout_unset(g_wtp.timeout, g_wtp.idtimercontrol);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimerecho, g_wtp.echointerval, wtp_dfa_state_run_echo_timeout, NULL, NULL);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimerkeepalivedead, WTP_DATACHANNEL_KEEPALIVEDEAD, wtp_dfa_state_run_keepalivedead_timeout, NULL, NULL);
} else {
capwap_logging_debug("Warning: error to send data channel keepalive packet, fragment packet");
/* Error to send packets */
capwap_logging_error("Error to send data channel keepalive packet");
wtp_teardown_connection();
}
/* Free packets manager */
capwap_list_free(txfragpacket);
capwap_packet_txmng_free(txmngpacket);
}
/* */
static void wtp_dfa_state_dtlsteardown_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param) {
/* Free and reset resource */
if (g_wtp.ctrldtls.enable) {
capwap_crypt_freesession(&g_wtp.ctrldtls);
}
if (g_wtp.datadtls.enable) {
capwap_crypt_freesession(&g_wtp.datadtls);
if (g_wtp.dtls.enable) {
capwap_crypt_freesession(&g_wtp.dtls);
}
/* */
@ -117,8 +65,7 @@ static void wtp_dfa_state_dtlsteardown_timeout(struct capwap_timeout* timeout, u
/* */
wtp_free_reference_last_request();
wtp_free_reference_last_response();
wtp_free_packet_rxmng(0);
wtp_free_packet_rxmng(1);
wtp_free_packet_rxmng();
/* */
if (!g_wtp.running) {
@ -140,15 +87,15 @@ void wtp_dfa_state_dtlsteardown(struct capwap_parsed_packet* packet) {
void wtp_teardown_connection(void) {
g_wtp.teardown = 1;
/* TODO: close SSID ? */
/* DTSL Control */
if (g_wtp.ctrldtls.enable) {
capwap_crypt_close(&g_wtp.ctrldtls);
if (g_wtp.dtls.enable) {
capwap_crypt_close(&g_wtp.dtls);
}
/* DTLS Data */
if (g_wtp.datadtls.enable) {
capwap_crypt_close(&g_wtp.datadtls);
}
/* Close data channel session */
wtp_kmod_resetsession();
/* */
wtp_dfa_change_state(CAPWAP_DTLS_TEARDOWN_STATE);

View File

@ -13,40 +13,30 @@ void wtp_dfa_state_idle(void) {
/* */
if (!g_wtp.acdiscoveryrequest && (g_wtp.acpreferedarray->count > 0)) {
while (g_wtp.acpreferedselected < g_wtp.acpreferedarray->count) {
union sockaddr_capwap localaddr;
union sockaddr_capwap peeraddr;
/* Found in configuration file the AC address */
memcpy(&g_wtp.acctrladdress, capwap_array_get_item_pointer(g_wtp.acpreferedarray, g_wtp.acpreferedselected), sizeof(struct sockaddr_storage));
memcpy(&g_wtp.acdataaddress, &g_wtp.acctrladdress, sizeof(struct sockaddr_storage));
CAPWAP_SET_NETWORK_PORT(&g_wtp.acdataaddress, CAPWAP_GET_NETWORK_PORT(&g_wtp.acdataaddress) + 1);
memcpy(&peeraddr, capwap_array_get_item_pointer(g_wtp.acpreferedarray, g_wtp.acpreferedselected), sizeof(union sockaddr_capwap));
/* Next AC */
g_wtp.acpreferedselected++;
/* Configure socket */
capwap_get_network_socket(&g_wtp.net, &g_wtp.acctrlsock, capwap_get_socket(&g_wtp.net, g_wtp.acctrladdress.ss_family, IPPROTO_UDP, CAPWAP_CTRL_SOCKET));
capwap_get_network_socket(&g_wtp.net, &g_wtp.acdatasock, capwap_get_socket(&g_wtp.net, g_wtp.acdataaddress.ss_family, (g_wtp.transport.type == CAPWAP_UDP_TRANSPORT ? IPPROTO_UDP : IPPROTO_UDPLITE), CAPWAP_DATA_SOCKET));
/* Retrieve local address */
if (capwap_get_localaddress_by_remoteaddress(&g_wtp.wtpctrladdress, &g_wtp.acctrladdress, g_wtp.net.bind_interface, (!(g_wtp.net.bind_ctrl_flags & CAPWAP_IPV6ONLY_FLAG) ? 1 : 0))) {
struct sockaddr_storage sockinfo;
socklen_t sockinfolen = sizeof(struct sockaddr_storage);
if (!capwap_network_get_localaddress(&localaddr, &peeraddr, g_wtp.net.bindiface)) {
CAPWAP_SET_NETWORK_PORT(&localaddr, CAPWAP_GET_NETWORK_PORT(&g_wtp.net.localaddr));
memset(&sockinfo, 0, sizeof(struct sockaddr_storage));
if (!getsockname(g_wtp.acctrlsock.socket[g_wtp.acctrlsock.type], (struct sockaddr*)&sockinfo, &sockinfolen)) {
CAPWAP_SET_NETWORK_PORT(&g_wtp.wtpctrladdress, CAPWAP_GET_NETWORK_PORT(&sockinfo));
/* */
capwap_crypt_setconnection(&g_wtp.dtls, g_wtp.net.socket, &localaddr, &peeraddr);
/* */
memcpy(&g_wtp.wtpdataaddress, &g_wtp.wtpctrladdress, sizeof(struct sockaddr_storage));
CAPWAP_SET_NETWORK_PORT(&g_wtp.wtpdataaddress, CAPWAP_GET_NETWORK_PORT(&g_wtp.wtpdataaddress) + 1);
/* */
if (!g_wtp.enabledtls) {
wtp_send_join(); /* Bypass DTLS connection */
} else {
wtp_start_dtlssetup(); /* Create DTLS connection */
}
return;
/* */
if (!g_wtp.enabledtls) {
wtp_send_join(); /* Bypass DTLS connection */
} else {
wtp_start_dtlssetup(); /* Create DTLS connection */
}
return;
}
}
}

View File

@ -48,15 +48,15 @@ void wtp_send_join(void) {
capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_ECNSUPPORT, &g_wtp.ecn);
if (g_wtp.wtpctrladdress.ss_family == AF_INET) {
if (g_wtp.dtls.localaddr.ss.ss_family == AF_INET) {
struct capwap_localipv4_element addr;
memcpy(&addr.address, &((struct sockaddr_in*)&g_wtp.wtpctrladdress)->sin_addr, sizeof(struct in_addr));
memcpy(&addr.address, &g_wtp.dtls.localaddr.sin.sin_addr, sizeof(struct in_addr));
capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_LOCALIPV4, &addr);
} else if (g_wtp.wtpctrladdress.ss_family == AF_INET6) {
} else if (g_wtp.dtls.localaddr.ss.ss_family == AF_INET6) {
struct capwap_localipv6_element addr;
memcpy(&addr.address, &((struct sockaddr_in6*)&g_wtp.wtpctrladdress)->sin6_addr, sizeof(struct in6_addr));
memcpy(&addr.address, &g_wtp.dtls.localaddr.sin6.sin6_addr, sizeof(struct in6_addr));
capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_LOCALIPV6, &addr);
}
@ -76,7 +76,7 @@ void wtp_send_join(void) {
capwap_packet_txmng_free(txmngpacket);
/* Send join request to AC */
if (capwap_crypt_sendto_fragmentpacket(&g_wtp.ctrldtls, g_wtp.acctrlsock.socket[g_wtp.acctrlsock.type], g_wtp.requestfragmentpacket, &g_wtp.wtpctrladdress, &g_wtp.acctrladdress)) {
if (capwap_crypt_sendto_fragmentpacket(&g_wtp.dtls, g_wtp.requestfragmentpacket)) {
g_wtp.retransmitcount = 0;
wtp_dfa_change_state(CAPWAP_JOIN_STATE);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_RETRANSMIT_INTERVAL, wtp_dfa_retransmition_timeout, NULL, NULL);
@ -97,7 +97,7 @@ void wtp_dfa_state_join(struct capwap_parsed_packet* packet) {
/* */
binding = GET_WBID_HEADER(packet->rxmngpacket->header);
if (packet->rxmngpacket->isctrlpacket && (binding == g_wtp.binding) && (packet->rxmngpacket->ctrlmsg.type == CAPWAP_JOIN_RESPONSE) && ((g_wtp.localseqnumber - 1) == packet->rxmngpacket->ctrlmsg.seq)) {
if ((binding == g_wtp.binding) && (packet->rxmngpacket->ctrlmsg.type == CAPWAP_JOIN_RESPONSE) && ((g_wtp.localseqnumber - 1) == packet->rxmngpacket->ctrlmsg.seq)) {
/* Valid packet, free request packet */
wtp_free_reference_last_request();

View File

@ -5,10 +5,6 @@
#include "wtp_radio.h"
#include "ieee80211.h"
/* */
#define WTP_BODY_PACKET_MAX_SIZE 8192
static uint8_t g_bodypacket[WTP_BODY_PACKET_MAX_SIZE];
/* */
static int send_echo_request(void) {
int result = -1;
@ -33,7 +29,7 @@ static int send_echo_request(void) {
capwap_packet_txmng_free(txmngpacket);
/* Send echo request to AC */
if (capwap_crypt_sendto_fragmentpacket(&g_wtp.ctrldtls, g_wtp.acctrlsock.socket[g_wtp.acctrlsock.type], g_wtp.requestfragmentpacket, &g_wtp.wtpctrladdress, &g_wtp.acctrladdress)) {
if (capwap_crypt_sendto_fragmentpacket(&g_wtp.dtls, g_wtp.requestfragmentpacket)) {
result = 0;
} else {
/* Error to send packets */
@ -94,11 +90,11 @@ static void receive_reset_request(struct capwap_parsed_packet* packet) {
capwap_packet_txmng_free(txmngpacket);
/* Save remote sequence number */
g_wtp.remotetype = packet->rxmngpacket->ctrlmsg.type;
g_wtp.remoteseqnumber = packet->rxmngpacket->ctrlmsg.seq;
capwap_get_packet_digest(packet->rxmngpacket, packet->connection, g_wtp.lastrecvpackethash);
/* Send Reset response to AC */
if (!capwap_crypt_sendto_fragmentpacket(&g_wtp.ctrldtls, g_wtp.acctrlsock.socket[g_wtp.acctrlsock.type], g_wtp.responsefragmentpacket, &g_wtp.wtpctrladdress, &g_wtp.acctrladdress)) {
if (!capwap_crypt_sendto_fragmentpacket(&g_wtp.dtls, g_wtp.responsefragmentpacket)) {
capwap_logging_debug("Warning: error to send reset response packet");
}
}
@ -143,11 +139,11 @@ static void receive_station_configuration_request(struct capwap_parsed_packet* p
capwap_packet_txmng_free(txmngpacket);
/* Save remote sequence number */
g_wtp.remotetype = packet->rxmngpacket->ctrlmsg.type;
g_wtp.remoteseqnumber = packet->rxmngpacket->ctrlmsg.seq;
capwap_get_packet_digest(packet->rxmngpacket, packet->connection, g_wtp.lastrecvpackethash);
/* Send Station Configuration response to AC */
if (!capwap_crypt_sendto_fragmentpacket(&g_wtp.ctrldtls, g_wtp.acctrlsock.socket[g_wtp.acctrlsock.type], g_wtp.responsefragmentpacket, &g_wtp.wtpctrladdress, &g_wtp.acctrladdress)) {
if (!capwap_crypt_sendto_fragmentpacket(&g_wtp.dtls, g_wtp.responsefragmentpacket)) {
capwap_logging_debug("Warning: error to send Station Configuration response packet");
}
}
@ -203,213 +199,133 @@ static void receive_ieee80211_wlan_configuration_request(struct capwap_parsed_pa
capwap_packet_txmng_free(txmngpacket);
/* Save remote sequence number */
g_wtp.remotetype = packet->rxmngpacket->ctrlmsg.type;
g_wtp.remoteseqnumber = packet->rxmngpacket->ctrlmsg.seq;
capwap_get_packet_digest(packet->rxmngpacket, packet->connection, g_wtp.lastrecvpackethash);
/* Send IEEE802.11 WLAN Configuration response to AC */
if (!capwap_crypt_sendto_fragmentpacket(&g_wtp.ctrldtls, g_wtp.acctrlsock.socket[g_wtp.acctrlsock.type], g_wtp.responsefragmentpacket, &g_wtp.wtpctrladdress, &g_wtp.acctrladdress)) {
if (!capwap_crypt_sendto_fragmentpacket(&g_wtp.dtls, g_wtp.responsefragmentpacket)) {
capwap_logging_debug("Warning: error to send IEEE802.11 WLAN Configuration response packet");
}
}
}
/* */
static void send_data_keepalive_request() {
struct capwap_list* txfragpacket;
struct capwap_header_data capwapheader;
struct capwap_packet_txmng* txmngpacket;
/* Build packet */
capwap_header_init(&capwapheader, CAPWAP_RADIOID_NONE, g_wtp.binding);
capwap_header_set_keepalive_flag(&capwapheader, 1);
txmngpacket = capwap_packet_txmng_create_data_message(&capwapheader, g_wtp.mtu); /* CAPWAP_DONT_FRAGMENT */
/* Add message element */
capwap_packet_txmng_add_message_element(txmngpacket, CAPWAP_ELEMENT_SESSIONID, &g_wtp.sessionid);
/* Data keepalive complete, get fragment packets into local list */
txfragpacket = capwap_list_create();
capwap_packet_txmng_get_fragment_packets(txmngpacket, txfragpacket, 0);
if (txfragpacket->count == 1) {
/* Send Data keepalive to AC */
if (capwap_crypt_sendto_fragmentpacket(&g_wtp.datadtls, g_wtp.acdatasock.socket[g_wtp.acdatasock.type], txfragpacket, &g_wtp.wtpdataaddress, &g_wtp.acdataaddress)) {
capwap_timeout_unset(g_wtp.timeout, g_wtp.idtimerkeepalive);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimerkeepalivedead, WTP_DATACHANNEL_KEEPALIVEDEAD, wtp_dfa_state_run_keepalivedead_timeout, NULL, NULL);
} else {
/* Error to send packets */
capwap_logging_debug("Warning: error to send data channel keepalive packet");
wtp_teardown_connection();
}
} else {
capwap_logging_debug("Warning: error to send data channel keepalive packet, fragment packet");
wtp_teardown_connection();
}
/* Free packets manager */
capwap_list_free(txfragpacket);
capwap_packet_txmng_free(txmngpacket);
}
/* */
int wtp_send_data_packet(uint8_t radioid, uint8_t wlanid, const uint8_t* frame, int length, int nativeframe, uint8_t rssi, uint8_t snr, uint16_t rate, uint8_t* bssaddress, int bssaddresstype) {
int result;
struct capwap_list* txfragpacket;
struct capwap_header_data capwapheader;
struct capwap_packet_txmng* txmngpacket;
ASSERT(IS_VALID_RADIOID(radioid));
ASSERT(IS_VALID_WLANID(wlanid));
ASSERT(frame != NULL);
ASSERT(length > 0);
/* Check for IEEE 802.3 frame */
if (!nativeframe && (!bssaddress || (bssaddresstype == MACADDRESS_NONE_LENGTH))) {
return 0;
}
/* Build packet */
capwap_header_init(&capwapheader, radioid, g_wtp.binding);
capwap_header_set_nativeframe_flag(&capwapheader, (nativeframe ? 1: 0));
/* Set radio macaddress */
if (!nativeframe) {
capwap_header_set_radio_macaddress(&capwapheader, bssaddresstype, bssaddress);
}
/* Set wireless information */
if (rssi || snr || rate) {
struct capwap_ieee80211_frame_info frameinfo;
frameinfo.rssi = rssi;
frameinfo.snr = snr;
frameinfo.rate = htons(rate);
capwap_header_set_wireless_information(&capwapheader, &frameinfo, sizeof(struct capwap_ieee80211_frame_info));
}
txmngpacket = capwap_packet_txmng_create_data_message(&capwapheader, g_wtp.mtu);
/* */
capwap_packet_txmng_add_data(txmngpacket, frame, (unsigned short)length);
/* Data message complete, get fragment packets into local list */
txfragpacket = capwap_list_create();
capwap_packet_txmng_get_fragment_packets(txmngpacket, txfragpacket, g_wtp.fragmentid);
if (txfragpacket->count > 1) {
g_wtp.fragmentid++;
}
/* */
result = capwap_crypt_sendto_fragmentpacket(&g_wtp.datadtls, g_wtp.acdatasock.socket[g_wtp.acdatasock.type], txfragpacket, &g_wtp.wtpdataaddress, &g_wtp.acdataaddress);
if (!result) {
capwap_logging_debug("Warning: error to send data packet");
}
/* Free packets manager */
capwap_list_free(txfragpacket);
capwap_packet_txmng_free(txmngpacket);
return result;
}
/* */
void wtp_dfa_state_run_echo_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param) {
capwap_logging_debug("Send Echo Request");
if (!send_echo_request()) {
g_wtp.retransmitcount = 0;
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimercontrol, WTP_RETRANSMIT_INTERVAL, wtp_dfa_retransmition_timeout, NULL, NULL);
} else {
capwap_logging_error("Unable to send Echo Request");
wtp_teardown_connection();
}
}
/* */
void wtp_dfa_state_run_keepalive_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param) {
send_data_keepalive_request();
capwap_logging_debug("Send Keep-Alive");
capwap_timeout_unset(g_wtp.timeout, g_wtp.idtimerkeepalive);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimerkeepalivedead, WTP_DATACHANNEL_KEEPALIVEDEAD, wtp_dfa_state_run_keepalivedead_timeout, NULL, NULL);
if (wtp_kmod_send_keepalive()) {
capwap_logging_error("Unable to send Keep-Alive");
wtp_teardown_connection();
}
}
/* */
void wtp_dfa_state_run_keepalivedead_timeout(struct capwap_timeout* timeout, unsigned long index, void* context, void* param) {
capwap_logging_info("Keep-Alive timeout, teardown");
wtp_teardown_connection();
}
/* */
void wtp_recv_data_keepalive(void) {
capwap_logging_debug("Receive Keep-Alive");
/* Receive Data Keep-Alive, wait for next packet */
capwap_timeout_unset(g_wtp.timeout, g_wtp.idtimerkeepalivedead);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimerkeepalive, WTP_DATACHANNEL_KEEPALIVE_INTERVAL, wtp_dfa_state_run_keepalive_timeout, NULL, NULL);
}
/* */
void wtp_recv_data(uint8_t* buffer, int length) {
int headersize;
struct capwap_header* header = (struct capwap_header*)buffer;
/* */
if (length < sizeof(struct capwap_header)) {
return;
}
/* */
headersize = GET_HLEN_HEADER(header) * 4;
if ((length - headersize) > 0) {
wtp_radio_receive_data_packet(GET_RID_HEADER(header), GET_WBID_HEADER(header), (buffer + headersize), (length - headersize));
}
}
/* */
void wtp_dfa_state_run(struct capwap_parsed_packet* packet) {
ASSERT(packet != NULL);
if (packet->rxmngpacket->isctrlpacket) {
if (capwap_is_request_type(packet->rxmngpacket->ctrlmsg.type) || ((g_wtp.localseqnumber - 1) == packet->rxmngpacket->ctrlmsg.seq)) {
switch (packet->rxmngpacket->ctrlmsg.type) {
case CAPWAP_CONFIGURATION_UPDATE_REQUEST: {
/* TODO */
break;
}
case CAPWAP_CHANGE_STATE_EVENT_RESPONSE: {
/* TODO */
break;
}
case CAPWAP_ECHO_RESPONSE: {
if (!receive_echo_response(packet)) {
capwap_timeout_unset(g_wtp.timeout, g_wtp.idtimercontrol);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimerecho, g_wtp.echointerval, wtp_dfa_state_run_echo_timeout, NULL, NULL);
}
break;
}
case CAPWAP_CLEAR_CONFIGURATION_REQUEST: {
/* TODO */
break;
}
case CAPWAP_WTP_EVENT_RESPONSE: {
/* TODO */
break;
}
case CAPWAP_DATA_TRANSFER_REQUEST: {
/* TODO */
break;
}
case CAPWAP_DATA_TRANSFER_RESPONSE: {
/* TODO */
break;
}
case CAPWAP_STATION_CONFIGURATION_REQUEST: {
receive_station_configuration_request(packet);
break;
}
case CAPWAP_RESET_REQUEST: {
receive_reset_request(packet);
wtp_dfa_change_state(CAPWAP_RESET_STATE);
wtp_dfa_state_reset();
break;
}
case CAPWAP_IEEE80211_WLAN_CONFIGURATION_REQUEST: {
receive_ieee80211_wlan_configuration_request(packet);
break;
}
if (capwap_is_request_type(packet->rxmngpacket->ctrlmsg.type) || ((g_wtp.localseqnumber - 1) == packet->rxmngpacket->ctrlmsg.seq)) {
switch (packet->rxmngpacket->ctrlmsg.type) {
case CAPWAP_CONFIGURATION_UPDATE_REQUEST: {
/* TODO */
break;
}
}
} else {
if (IS_FLAG_K_HEADER(packet->rxmngpacket->header)) {
if (!memcmp(capwap_get_message_element_data(packet, CAPWAP_ELEMENT_SESSIONID), &g_wtp.sessionid, sizeof(struct capwap_sessionid_element))) {
/* Receive Data Keep-Alive, wait for next packet */
capwap_timeout_unset(g_wtp.timeout, g_wtp.idtimerkeepalivedead);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimerkeepalive, WTP_DATACHANNEL_KEEPALIVE_INTERVAL, wtp_dfa_state_run_keepalive_timeout, NULL, NULL);
}
} else {
/* Get body packet */
int bodypacketlength = capwap_packet_getdata(packet->rxmngpacket, g_bodypacket, WTP_BODY_PACKET_MAX_SIZE);
if (bodypacketlength > 0) {
uint8_t radioid = GET_RID_HEADER(packet->rxmngpacket->header);
unsigned short binding = GET_WBID_HEADER(packet->rxmngpacket->header);
wtp_radio_receive_data_packet(radioid, binding, g_bodypacket, bodypacketlength);
case CAPWAP_CHANGE_STATE_EVENT_RESPONSE: {
/* TODO */
break;
}
case CAPWAP_ECHO_RESPONSE: {
if (!receive_echo_response(packet)) {
capwap_logging_debug("Receive Echo Response");
capwap_timeout_unset(g_wtp.timeout, g_wtp.idtimercontrol);
capwap_timeout_set(g_wtp.timeout, g_wtp.idtimerecho, g_wtp.echointerval, wtp_dfa_state_run_echo_timeout, NULL, NULL);
}
break;
}
case CAPWAP_CLEAR_CONFIGURATION_REQUEST: {
/* TODO */
break;
}
case CAPWAP_WTP_EVENT_RESPONSE: {
/* TODO */
break;
}
case CAPWAP_DATA_TRANSFER_REQUEST: {
/* TODO */
break;
}
case CAPWAP_DATA_TRANSFER_RESPONSE: {
/* TODO */
break;
}
case CAPWAP_STATION_CONFIGURATION_REQUEST: {
receive_station_configuration_request(packet);
break;
}
case CAPWAP_RESET_REQUEST: {
receive_reset_request(packet);
wtp_dfa_change_state(CAPWAP_RESET_STATE);
wtp_dfa_state_reset();
break;
}
case CAPWAP_IEEE80211_WLAN_CONFIGURATION_REQUEST: {
receive_ieee80211_wlan_configuration_request(packet);
break;
}
}
}

View File

@ -1,4 +1,5 @@
#include "wtp.h"
#include "wtp_dfa.h"
#include <netlink/genl/genl.h>
#include <netlink/genl/family.h>
#include <netlink/genl/ctrl.h>
@ -84,23 +85,16 @@ static int wtp_kmod_ack_handler(struct nl_msg* msg, void* arg) {
/* */
static int wtp_kmod_event_handler(struct genlmsghdr* gnlh, struct nlattr** tb_msg, void* data) {
switch (gnlh->cmd) {
case NLSMARTCAPWAP_CMD_FRAME: {
struct wtp_kmod_iface_handle* interface = (struct wtp_kmod_iface_handle*)data;
if (tb_msg[NLSMARTCAPWAP_ATTR_FRAME]) {
uint32_t sig_dbm = (tb_msg[NLSMARTCAPWAP_ATTR_RX_SIGNAL_DBM] ? nla_get_u32(tb_msg[NLSMARTCAPWAP_ATTR_RX_SIGNAL_DBM]) : 0);
uint16_t rate = (tb_msg[NLSMARTCAPWAP_ATTR_RX_RATE] ? ((uint16_t)nla_get_u8(tb_msg[NLSMARTCAPWAP_ATTR_RX_RATE])) * 5 : 0); /* Convert rate 500Kbps to 100Kbps */
int nativeframe = (tb_msg[SMARTCAPWAP_FLAGS_TUNNEL_8023] ? 0 : 1);
/* Forwards the frame to AC */
wifi_wlan_send_frame(interface->wlan, (uint8_t*)nla_data(tb_msg[NLSMARTCAPWAP_ATTR_FRAME]), nla_len(tb_msg[NLSMARTCAPWAP_ATTR_FRAME]), nativeframe, (uint8_t)sig_dbm, 0, rate);
}
case NLSMARTCAPWAP_CMD_RECV_KEEPALIVE: {
wtp_recv_data_keepalive();
break;
}
default: {
capwap_logging_debug("*** wtp_kmod_event_handler: %d", (int)gnlh->cmd);
case NLSMARTCAPWAP_CMD_RECV_DATA: {
if (tb_msg[NLSMARTCAPWAP_ATTR_DATA_FRAME]) {
wtp_recv_data(nla_data(tb_msg[NLSMARTCAPWAP_ATTR_DATA_FRAME]), nla_len(tb_msg[NLSMARTCAPWAP_ATTR_DATA_FRAME]));
}
break;
}
}
@ -204,15 +198,177 @@ static void wtp_kmod_event_receive(int fd, void** params, int paramscount) {
}
/* */
int wtp_kmod_join_mac80211_device(struct wifi_wlan* wlan, uint32_t mode, uint32_t flags) {
int wtp_kmod_bind(uint16_t family) {
int result;
struct nl_msg* msg;
struct sockaddr_storage sockaddr;
ASSERT((family == AF_INET) || (family == AF_INET6));
/* */
if (!wtp_kmod_isconnected()) {
return -1;
}
/* */
msg = nlmsg_alloc();
if (!msg) {
return -1;
}
/* */
memset(&sockaddr, 0, sizeof(struct sockaddr_storage));
sockaddr.ss_family = family;
/* */
genlmsg_put(msg, 0, 0, g_wtp.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_BIND, 0);
nla_put(msg, NLSMARTCAPWAP_ATTR_ADDRESS, sizeof(struct sockaddr_storage), &sockaddr);
/* */
result = wtp_kmod_send_and_recv_msg(msg, NULL, NULL);
/* */
nlmsg_free(msg);
return result;
}
/* */
int wtp_kmod_connect(struct sockaddr_storage* sockaddr, struct capwap_sessionid_element* sessionid, uint16_t mtu) {
int result;
struct nl_msg* msg;
ASSERT(sockaddr != NULL);
ASSERT((sockaddr->ss_family == AF_INET) || (sockaddr->ss_family == AF_INET6));
ASSERT(sessionid != NULL);
/* */
if (!wtp_kmod_isconnected()) {
return -1;
}
/* */
msg = nlmsg_alloc();
if (!msg) {
return -1;
}
/* */
genlmsg_put(msg, 0, 0, g_wtp.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_CONNECT, 0);
nla_put(msg, NLSMARTCAPWAP_ATTR_ADDRESS, sizeof(struct sockaddr_storage), sockaddr);
nla_put(msg, NLSMARTCAPWAP_ATTR_SESSION_ID, sizeof(struct capwap_sessionid_element), sessionid);
nla_put_u16(msg, NLSMARTCAPWAP_ATTR_MTU, mtu);
/* */
result = wtp_kmod_send_and_recv_msg(msg, NULL, NULL);
/* */
nlmsg_free(msg);
return result;
}
/* */
int wtp_kmod_send_keepalive(void) {
int result;
struct nl_msg* msg;
/* */
if (!wtp_kmod_isconnected()) {
return -1;
}
/* */
msg = nlmsg_alloc();
if (!msg) {
return -1;
}
/* */
genlmsg_put(msg, 0, 0, g_wtp.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_SEND_KEEPALIVE, 0);
/* */
result = wtp_kmod_send_and_recv_msg(msg, NULL, NULL);
/* */
nlmsg_free(msg);
return result;
}
/* */
int wtp_kmod_resetsession(void) {
int result;
struct nl_msg* msg;
/* */
if (!wtp_kmod_isconnected()) {
return -1;
}
/* */
msg = nlmsg_alloc();
if (!msg) {
return -1;
}
/* */
genlmsg_put(msg, 0, 0, g_wtp.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_RESET, 0);
/* */
result = wtp_kmod_send_and_recv_msg(msg, NULL, NULL);
/* */
nlmsg_free(msg);
return result;
}
/* */
int wtp_kmod_send_data(uint8_t radioid, const uint8_t* frame, int length, uint8_t rssi, uint8_t snr, uint16_t rate) {
int result;
struct nl_msg* msg;
/* */
if (!wtp_kmod_isconnected()) {
return -1;
}
/* */
msg = nlmsg_alloc();
if (!msg) {
return -1;
}
/* */
genlmsg_put(msg, 0, 0, g_wtp.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_SEND_DATA, 0);
nla_put_u8(msg, NLSMARTCAPWAP_ATTR_RADIOID, radioid);
nla_put(msg, NLSMARTCAPWAP_ATTR_DATA_FRAME, length, frame);
nla_put_u8(msg, NLSMARTCAPWAP_ATTR_BINDING, g_wtp.binding);
if (rssi) {
nla_put_u8(msg, NLSMARTCAPWAP_ATTR_RSSI, rssi);
}
if (snr) {
nla_put_u8(msg, NLSMARTCAPWAP_ATTR_SNR, snr);
}
if (rate) {
nla_put_u16(msg, NLSMARTCAPWAP_ATTR_RATE, rate);
}
/* */
result = wtp_kmod_send_and_recv_msg(msg, NULL, NULL);
/* */
nlmsg_free(msg);
return result;
}
/* */
int wtp_kmod_join_mac80211_device(struct wifi_wlan* wlan, uint32_t flags) {
int result;
struct nl_msg* msg;
struct capwap_list_item* itemlist;
struct wtp_kmod_iface_handle* interface;
uint32_t kmodflags = 0;
uint16_t subtype_mgmt = 0;
uint16_t subtype_ctrl = 0;
uint16_t subtype_data = 0;
ASSERT(wlan != NULL);
@ -226,91 +382,38 @@ int wtp_kmod_join_mac80211_device(struct wifi_wlan* wlan, uint32_t mode, uint32_
interface = (struct wtp_kmod_iface_handle*)itemlist->item;
memset(interface, 0, sizeof(struct wtp_kmod_iface_handle));
/* Socket management */
if (mode == WTP_KMOD_MODE_TUNNEL_USERMODE) {
interface->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
if (!interface->nl_cb) {
capwap_itemlist_free(itemlist);
return -1;
}
nl_cb_set(interface->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, wtp_kmod_no_seq_check, NULL);
nl_cb_set(interface->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, wtp_kmod_valid_handler, (void*)interface);
interface->nl = nl_create_handle(interface->nl_cb);
if (interface->nl) {
interface->nl_fd = nl_socket_get_fd(interface->nl);
} else {
nl_cb_put(interface->nl_cb);
capwap_itemlist_free(itemlist);
return -1;
}
}
/* */
msg = nlmsg_alloc();
if (!msg) {
if (mode == WTP_KMOD_MODE_TUNNEL_USERMODE) {
nl_socket_free(interface->nl);
nl_cb_put(interface->nl_cb);
}
capwap_itemlist_free(itemlist);
return -1;
}
/* Set flags */
switch (mode) {
case WTP_KMOD_MODE_LOCAL: {
break;
}
case WTP_KMOD_MODE_TUNNEL_USERMODE: {
kmodflags |= SMARTCAPWAP_FLAGS_SEND_USERSPACE | SMARTCAPWAP_FLAGS_BLOCK_DATA_FRAME;
subtype_data = 0xffff;
if (flags & WTP_KMOD_FLAGS_TUNNEL_8023) {
kmodflags |= SMARTCAPWAP_FLAGS_TUNNEL_8023;
}
break;
}
case WTP_KMOD_MODE_TUNNEL_KERNELMODE: {
kmodflags |= SMARTCAPWAP_FLAGS_BLOCK_DATA_FRAME;
subtype_data = 0xffff;
if (flags & WTP_KMOD_FLAGS_TUNNEL_8023) {
kmodflags |= SMARTCAPWAP_FLAGS_TUNNEL_8023;
}
break;
}
if (flags & WTP_KMOD_FLAGS_TUNNEL_8023) {
kmodflags |= NLSMARTCAPWAP_FLAGS_TUNNEL_8023;
}
/* */
genlmsg_put(msg, 0, 0, g_wtp.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_JOIN_MAC80211_DEVICE, 0);
nla_put_u32(msg, NLSMARTCAPWAP_ATTR_IFINDEX, wlan->virtindex);
nla_put_u8(msg, NLSMARTCAPWAP_ATTR_RADIOID, wlan->radioid);
nla_put_u8(msg, NLSMARTCAPWAP_ATTR_WLANID, wlan->wlanid);
nla_put_u8(msg, NLSMARTCAPWAP_ATTR_BINDING, g_wtp.binding);
nla_put_u32(msg, NLSMARTCAPWAP_ATTR_FLAGS, kmodflags);
nla_put_u16(msg, NLSMARTCAPWAP_ATTR_MGMT_SUBTYPE_MASK, subtype_mgmt);
nla_put_u16(msg, NLSMARTCAPWAP_ATTR_CTRL_SUBTYPE_MASK, subtype_ctrl);
nla_put_u16(msg, NLSMARTCAPWAP_ATTR_DATA_SUBTYPE_MASK, subtype_data);
nla_put_u16(msg, NLSMARTCAPWAP_ATTR_MGMT_SUBTYPE_MASK, 0x0000);
nla_put_u16(msg, NLSMARTCAPWAP_ATTR_CTRL_SUBTYPE_MASK, 0x0000);
nla_put_u16(msg, NLSMARTCAPWAP_ATTR_DATA_SUBTYPE_MASK, 0xffff);
/* */
result = wtp_kmod_send_and_recv(interface->nl, interface->nl_cb, msg, NULL, NULL);
result = wtp_kmod_send_and_recv_msg(msg, NULL, NULL);
if (!result) {
interface->mode = mode;
interface->flags = flags;
interface->wlan = wlan;
/* */
capwap_itemlist_insert_after(g_wtp.kmodhandle.interfaces, NULL, itemlist);
if (mode == WTP_KMOD_MODE_TUNNEL_USERMODE) {
g_wtp.kmodhandle.interfaceconnectioncount++;
}
} else {
nl_socket_free(interface->nl);
nl_cb_put(interface->nl_cb);
capwap_itemlist_free(itemlist);
}
@ -350,14 +453,6 @@ int wtp_kmod_leave_mac80211_device(struct wifi_wlan* wlan) {
struct wtp_kmod_iface_handle* interface = (struct wtp_kmod_iface_handle*)itemlist->item;
if (interface->wlan == wlan) {
nl_socket_free(interface->nl);
nl_cb_put(interface->nl_cb);
/* 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));
break;
}
@ -376,9 +471,7 @@ int wtp_kmod_isconnected(void) {
/* */
int wtp_kmod_getfd(struct pollfd* fds, struct wtp_kmod_event* events, int count) {
int i;
struct capwap_list_item* itemlist;
int kmodcount = (wtp_kmod_isconnected() ? 1 + g_wtp.kmodhandle.interfaceconnectioncount : 0);
int kmodcount = (wtp_kmod_isconnected() ? 1 : 0);
/* */
if (!kmodcount) {
@ -401,27 +494,6 @@ int wtp_kmod_getfd(struct pollfd* fds, struct wtp_kmod_event* events, int count)
events[0].params[1] = (void*)g_wtp.kmodhandle.nl_cb;
events[0].paramscount = 2;
/* */
for (i = 1, 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) {
fds[i].fd = interface->nl_fd;
fds[i].events = POLLIN | POLLERR | POLLHUP;
/* */
events[i].event_handler = wtp_kmod_event_receive;
events[i].params[0] = (void*)interface->nl;
events[i].params[1] = (void*)interface->nl_cb;
events[i].paramscount = 2;
/* */
i++;
}
}
ASSERT(kmodcount == i);
return kmodcount;
}
@ -446,7 +518,7 @@ int wtp_kmod_init(void) {
g_wtp.kmodhandle.nl_fd = nl_socket_get_fd(g_wtp.kmodhandle.nl);
/* Get nlsmartcapwap netlink family */
g_wtp.kmodhandle.nlsmartcapwap_id = genl_ctrl_resolve(g_wtp.kmodhandle.nl, SMARTCAPWAP_GENL_NAME);
g_wtp.kmodhandle.nlsmartcapwap_id = genl_ctrl_resolve(g_wtp.kmodhandle.nl, NLSMARTCAPWAP_GENL_NAME);
if (g_wtp.kmodhandle.nlsmartcapwap_id < 0) {
capwap_logging_warning("Unable to found kernel module");
wtp_kmod_free();

View File

@ -8,22 +8,12 @@
#define nl_sock nl_handle
#endif
/* */
#define WTP_KMOD_MODE_LOCAL 0x00000001
#define WTP_KMOD_MODE_TUNNEL_USERMODE 0x00000002
#define WTP_KMOD_MODE_TUNNEL_KERNELMODE 0x00000003
/* */
#define WTP_KMOD_FLAGS_TUNNEL_NATIVE 0x00000000
#define WTP_KMOD_FLAGS_TUNNEL_8023 0x00000001
/* */
struct wtp_kmod_iface_handle {
struct nl_sock* nl;
int nl_fd;
struct nl_cb* nl_cb;
uint32_t mode;
uint32_t flags;
struct wifi_wlan* wlan;
};
@ -37,7 +27,6 @@ struct wtp_kmod_handle {
/* */
struct capwap_list* interfaces;
int interfaceconnectioncount;
};
/* */
@ -57,7 +46,16 @@ int wtp_kmod_isconnected(void);
int wtp_kmod_getfd(struct pollfd* fds, struct wtp_kmod_event* events, int count);
/* */
int wtp_kmod_join_mac80211_device(struct wifi_wlan* wlan, uint32_t mode, uint32_t flags);
int wtp_kmod_bind(uint16_t family);
int wtp_kmod_connect(struct sockaddr_storage* sockaddr, struct capwap_sessionid_element* sessionid, uint16_t mtu);
int wtp_kmod_resetsession(void);
/* */
int wtp_kmod_send_keepalive(void);
int wtp_kmod_send_data(uint8_t radioid, const uint8_t* frame, int length, uint8_t rssi, uint8_t snr, uint16_t rate);
/* */
int wtp_kmod_join_mac80211_device(struct wifi_wlan* wlan, uint32_t flags);
int wtp_kmod_leave_mac80211_device(struct wifi_wlan* wlan);
#endif /* __WTP_KMOD_HEADER__ */

View File

@ -3,6 +3,7 @@
#include "capwap_list.h"
#include "wtp_radio.h"
#include "wtp_dfa.h"
#include "wtp_kmod.h"
/* */
#define WTP_UPDATE_FREQUENCY_DSSS 1
@ -50,18 +51,6 @@ static int wtp_radio_configure_phy(struct wtp_radio* radio) {
return 0;
}
/* */
static int wtp_radio_send_frame_to_ac(void* param, const uint8_t* frame, int length, int nativeframe, uint8_t rssi, uint8_t snr, uint16_t rate, uint8_t* bssaddress, int bssaddresstype) {
struct wtp_radio_wlan* wlan = (struct wtp_radio_wlan*)param;
ASSERT(param != NULL);
ASSERT(frame != NULL);
ASSERT(length > 0);
/* Send packet */
return wtp_send_data_packet(wlan->radio->radioid, wlan->wlanid, frame, length, nativeframe, rssi, snr, rate, bssaddress, bssaddresstype);
}
/* */
static unsigned long wtp_radio_acl_item_gethash(const void* key, unsigned long keysize, unsigned long hashsize) {
uint8_t* macaddress = (uint8_t*)key;
@ -538,11 +527,10 @@ struct wtp_radio_wlan* wtp_radio_get_wlan(struct wtp_radio* radio, uint8_t wlani
}
/* */
struct wtp_radio_wlan* wtp_radio_search_wlan(struct wtp_radio* radio, const uint8_t* bssid) {
static struct wtp_radio_wlan* __wtp_radio_search_wlan(struct wtp_radio* radio, const uint8_t* bssid) {
struct capwap_list_item* itemwlan;
ASSERT(radio != NULL);
ASSERT(bssid != NULL);
/* Retrieve BSS */
for (itemwlan = radio->wlan->first; itemwlan != NULL; itemwlan = itemwlan->next) {
@ -555,6 +543,27 @@ struct wtp_radio_wlan* wtp_radio_search_wlan(struct wtp_radio* radio, const uint
return NULL;
}
/* */
struct wtp_radio_wlan* wtp_radio_search_wlan(struct wtp_radio* radio, const uint8_t* bssid) {
int i;
ASSERT(bssid != NULL);
if (radio) {
return __wtp_radio_search_wlan(radio, bssid);
}
/* Search from any radio */
for (i = 0; i < g_wtp.radios->count; i++) {
struct wtp_radio_wlan* wlansearch = __wtp_radio_search_wlan((struct wtp_radio*)capwap_array_get_item_pointer(g_wtp.radios, i), bssid);
if (wlansearch) {
return wlansearch;
}
}
return NULL;
}
/* */
void wtp_radio_receive_data_packet(uint8_t radioid, unsigned short binding, const uint8_t* frame, int length) {
struct wtp_radio* radio;
@ -580,7 +589,6 @@ void wtp_radio_receive_data_packet(uint8_t radioid, unsigned short binding, cons
}
}
}
}
/* */
@ -638,8 +646,8 @@ uint32_t wtp_radio_create_wlan(struct capwap_parsed_packet* packet, struct capwa
/* Wlan configuration */
memset(&params, 0, sizeof(struct wlan_startap_params));
params.send_frame = wtp_radio_send_frame_to_ac;
params.send_frame_to_ac_cbparam = (void*)wlan;
params.radioid = addwlan->radioid;
params.wlanid = addwlan->wlanid;
params.ssid = (const char*)addwlan->ssid;
params.ssid_hidden = addwlan->suppressssid;
params.capability = addwlan->capability;
@ -736,9 +744,8 @@ uint32_t wtp_radio_delete_station(struct capwap_parsed_packet* packet) {
return CAPWAP_RESULTCODE_FAILURE;
}
if (wifi_station_deauthorize(radio->devicehandle, deletestation->address)) {
return CAPWAP_RESULTCODE_FAILURE;
}
/* */
wifi_station_deauthorize(radio->devicehandle, deletestation->address);
return CAPWAP_RESULTCODE_SUCCESS;
}