move kmod to top level directory

This commit is contained in:
Andreas Schultz
2016-08-23 08:57:55 +02:00
parent 7bb46f9927
commit f4a2bae666
14 changed files with 12 additions and 3 deletions

View File

@ -31,7 +31,7 @@ endif
AM_CFLAGS += \
-I$(top_srcdir)/lib \
-I$(top_srcdir)/src \
-I$(top_srcdir)/src/kmod \
-I$(top_srcdir)/kmod \
-I$(top_srcdir)/lib/binding/ieee80211 \
-I$(top_srcdir)/src/binding/ieee80211

View File

@ -1,486 +0,0 @@
#if !defined(__CAPWAP_DRIVER_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
#define __CAPWAP_DRIVER_TRACE_H
#include <linux/tracepoint.h>
#include <net/mac80211.h>
#include "capwap.h"
#undef TRACE_SYSTEM
#define TRACE_SYSTEM capwap
#define SESSION_ENTRY __array(char, sessionid, 16)
#define SESSION_ASSIGN ((session) ? memcpy(__entry->sessionid, &session->sessionid, 16) : memset(__entry->sessionid, 0, 16))
#define SESSION_PR_FMT " session:%16phN"
#define SESSION_PR_ARG __entry->sessionid
#define SESSIONID_ENTRY __array(char, sessionid, 16)
#define SESSIONID_ASSIGN ((sessionid) ? memcpy(__entry->sessionid, sessionid, 16) : memset(__entry->sessionid, 0, 16))
#define SESSIONID_PR_FMT " session:%16phN"
#define SESSIONID_PR_ARG __entry->sessionid
#define SKB_ENTRY __field(struct sk_buff *, skb)
#define SKB_ASSIGN __entry->skb = skb
#define SKB_PR_FMT " skb:%p"
#define SKB_PR_ARG __entry->skb
#define FRAGMENT_ENTRY __field(struct sc_capwap_fragment *, fragment)
#define FRAGMENT_ASSIGN __entry->fragment = fragment
#define FRAGMENT_PR_FMT " frag:%p"
#define FRAGMENT_PR_ARG __entry->fragment
#define BSSID_ENTRY __array(char, bssid, ETH_ALEN)
#define BSSID_ASSIGN (bssid ? memcpy(__entry->bssid, bssid, ETH_ALEN) : memset(__entry->bssid, 0, ETH_ALEN))
#define BSSID_PR_FMT " BSS:%pM"
#define BSSID_PR_ARG __entry->bssid
/* capwap.c */
TRACE_EVENT(sc_capwap_fragment_free,
TP_PROTO(struct sc_capwap_fragment *fragment),
TP_ARGS(fragment),
TP_STRUCT__entry(
FRAGMENT_ENTRY
),
TP_fast_assign(
FRAGMENT_ASSIGN;
),
TP_printk(FRAGMENT_PR_FMT, FRAGMENT_PR_ARG)
);
TRACE_EVENT(sc_capwap_freesession,
TP_PROTO(struct sc_capwap_session *session),
TP_ARGS(session),
TP_STRUCT__entry(
SESSION_ENTRY
),
TP_fast_assign(
SESSION_ASSIGN;
),
TP_printk(SESSION_PR_FMT, SESSION_PR_ARG)
);
TRACE_EVENT(sc_capwap_defrag_evictor,
TP_PROTO(struct sc_capwap_session *session),
TP_ARGS(session),
TP_STRUCT__entry(
SESSION_ENTRY
),
TP_fast_assign(
SESSION_ASSIGN;
),
TP_printk(SESSION_PR_FMT, SESSION_PR_ARG)
);
TRACE_EVENT(sc_capwap_defrag_evictor_fragment_expired,
TP_PROTO(struct sc_capwap_session *session,
struct sc_capwap_fragment *fragment,
ktime_t now),
TP_ARGS(session,
fragment,
now),
TP_STRUCT__entry(
SESSION_ENTRY
FRAGMENT_ENTRY
__field(u64, now)
__field(u64, tstamp)
),
TP_fast_assign(
SESSION_ASSIGN;
FRAGMENT_ASSIGN;
__entry->now = now.tv64;
__entry->tstamp = fragment->tstamp.tv64;
),
TP_printk(SESSION_PR_FMT FRAGMENT_PR_FMT " (%llu %llu)",
SESSION_PR_ARG, FRAGMENT_PR_ARG,
__entry->now,
__entry->tstamp
)
);
TRACE_EVENT(sc_capwap_reasm,
TP_PROTO(struct sc_capwap_fragment *fragment),
TP_ARGS(fragment),
TP_STRUCT__entry(
FRAGMENT_ENTRY
),
TP_fast_assign(
FRAGMENT_ASSIGN;
),
TP_printk(FRAGMENT_PR_FMT, FRAGMENT_PR_ARG)
);
TRACE_EVENT(sc_capwap_defrag,
TP_PROTO(struct sc_capwap_session *session,
uint16_t id,
uint16_t offset,
uint16_t length),
TP_ARGS(session, id, offset, length),
TP_STRUCT__entry(
SESSION_ENTRY
__field(u16, id)
__field(u16, offset)
__field(u16, length)
),
TP_fast_assign(
SESSION_ASSIGN;
__entry->id = id;
__entry->offset = offset;
__entry->length = length;
),
TP_printk(
SESSION_PR_FMT " fragment id:%hu offset:%hu length:%hu",
SESSION_PR_ARG, __entry->id, __entry->offset, __entry->length
)
);
// TRACEKMOD("** *Fragment info: id %hu offset %hu length %hu\n", frag_id, cb->frag_offset, cb->frag_length);
TRACE_EVENT(sc_capwap_8023_to_80211,
TP_PROTO(struct sk_buff *skb, const uint8_t *bssid),
TP_ARGS(skb, bssid),
TP_STRUCT__entry(
SKB_ENTRY
BSSID_ENTRY
),
TP_fast_assign(
SKB_ASSIGN;
BSSID_ASSIGN;
),
TP_printk(
SKB_PR_FMT BSSID_PR_FMT,
SKB_PR_ARG, BSSID_PR_ARG
)
);
TRACE_EVENT(sc_capwap_80211_to_8023,
TP_PROTO(struct sk_buff *skb),
TP_ARGS(skb),
TP_STRUCT__entry(
SKB_ENTRY
),
TP_fast_assign(
SKB_ASSIGN;
),
TP_printk(SKB_PR_FMT, SKB_PR_ARG)
);
TRACE_EVENT(sc_capwap_create,
TP_PROTO(struct sc_capwap_session *session),
TP_ARGS(session),
TP_STRUCT__entry(
SESSION_ENTRY
),
TP_fast_assign(
SESSION_ASSIGN;
),
TP_printk(SESSION_PR_FMT, SESSION_PR_ARG)
);
TRACE_EVENT(sc_capwap_close,
TP_PROTO(struct sc_capwap_session *session),
TP_ARGS(session),
TP_STRUCT__entry(
SESSION_ENTRY
),
TP_fast_assign(
SESSION_ASSIGN;
),
TP_printk(SESSION_PR_FMT, SESSION_PR_ARG)
);
TRACE_EVENT(sc_capwap_newfragmentid,
TP_PROTO(struct sc_capwap_session *session),
TP_ARGS(session),
TP_STRUCT__entry(
SESSION_ENTRY
),
TP_fast_assign(
SESSION_ASSIGN;
),
TP_printk(SESSION_PR_FMT, SESSION_PR_ARG)
);
TRACE_EVENT(sc_capwap_createkeepalive,
TP_PROTO(struct sc_capwap_sessionid_element *sessionid),
TP_ARGS(sessionid),
TP_STRUCT__entry(
SESSIONID_ENTRY
),
TP_fast_assign(
SESSIONID_ASSIGN;
),
TP_printk(SESSIONID_PR_FMT, SESSIONID_PR_ARG)
);
TRACE_EVENT(sc_capwap_parsingpacket,
TP_PROTO(struct sc_capwap_session *session,
struct sk_buff *skb),
TP_ARGS(session, skb),
TP_STRUCT__entry(
SESSION_ENTRY
SKB_ENTRY
),
TP_fast_assign(
SESSION_ASSIGN;
SKB_ASSIGN;
),
TP_printk(
SESSION_PR_FMT SKB_PR_FMT,
SESSION_PR_ARG, SKB_PR_ARG
)
);
TRACE_EVENT(sc_capwap_forwarddata,
TP_PROTO(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),
TP_ARGS(session, radioid, binding, skb, flags, radioaddr, radioaddrlength, winfo),
TP_STRUCT__entry(
SESSION_ENTRY
__field(u8, radioid)
__field(u8, binding)
SKB_ENTRY
__field(u32, flags)
__field(int, radioaddrlength)
__array(char, radioaddr, 8)
__field(u8, rssi)
__field(u8, snr)
__field(u16, rate)
),
TP_fast_assign(
SESSION_ASSIGN;
__entry->radioid = radioid;
__entry->binding = binding;
SKB_ASSIGN;
__entry->binding = flags;
__entry->radioaddrlength = radioaddrlength;
((radioaddrlength != 0 && radioaddr) ? memcpy(__entry->radioaddr, radioaddr, min(radioaddrlength, 8)) : memset(__entry->radioaddr, 0, 8));
__entry->rssi = (winfo) ? ((struct sc_capwap_ieee80211_frame_info *)(winfo))->rssi : 0;
__entry->snr = (winfo) ? ((struct sc_capwap_ieee80211_frame_info *)(winfo))->snr : 0;
__entry->rate = (winfo) ? ((struct sc_capwap_ieee80211_frame_info *)(winfo))->rate : 0;
),
TP_printk(
SESSION_PR_FMT " radio:%d binding:%d" SKB_PR_FMT
"radioaddr:%*phC rssid:%d snr:%d rate:%d",
SESSION_PR_ARG, __entry->radioid, __entry->binding, SKB_PR_ARG,
min(__entry->radioaddrlength, 8), __entry->radioaddr,
__entry->rssi, __entry->snr, __entry->rate
)
);
TRACE_EVENT(sc_capwap_setradiomacaddress,
TP_PROTO(uint8_t *bssid),
TP_ARGS(bssid),
TP_STRUCT__entry(
BSSID_ENTRY
),
TP_fast_assign(
BSSID_ASSIGN;
),
TP_printk(BSSID_PR_FMT, BSSID_PR_ARG)
);
TRACE_EVENT(sc_capwap_setwinfo_frameinfo,
TP_PROTO(uint8_t rssi,
uint8_t snr,
uint16_t rate),
TP_ARGS(rssi, snr, rate),
TP_STRUCT__entry(
__field(u8, rssi)
__field(u8, snr)
__field(u16, rate)
),
TP_fast_assign(
__entry->rssi = rssi;
__entry->snr = snr;
__entry->rate = rate;
),
TP_printk(
" rssid:%d snr:%d rate:%d",
__entry->rssi, __entry->snr, __entry->rate
)
);
TRACE_EVENT(sc_capwap_setwinfo_destwlans,
TP_PROTO(uint16_t wlanidbitmap),
TP_ARGS(wlanidbitmap),
TP_STRUCT__entry(
__field(u16, wlanidbitmap)
),
TP_fast_assign(
__entry->wlanidbitmap = wlanidbitmap;
),
TP_printk(" id:%04x", __entry->wlanidbitmap)
);
/* capwap_private.c */
TRACE_EVENT(sc_capwap_resetsession,
TP_PROTO(struct sc_capwap_session *session),
TP_ARGS(session),
TP_STRUCT__entry(
SESSION_ENTRY
),
TP_fast_assign(
SESSION_ASSIGN;
),
TP_printk(SESSION_PR_FMT, SESSION_PR_ARG)
);
TRACE_EVENT(sc_capwap_sendkeepalive,
TP_PROTO(struct sc_capwap_session *session),
TP_ARGS(session),
TP_STRUCT__entry(
SESSION_ENTRY
),
TP_fast_assign(
SESSION_ASSIGN;
),
TP_printk(SESSION_PR_FMT, SESSION_PR_ARG)
);
TRACE_EVENT(sc_capwap_send,
TP_PROTO(struct sc_capwap_session *session),
TP_ARGS(session),
TP_STRUCT__entry(
SESSION_ENTRY
),
TP_fast_assign(
SESSION_ASSIGN;
),
TP_printk(SESSION_PR_FMT, SESSION_PR_ARG)
);
TRACE_EVENT(sc_send_80211,
TP_PROTO(struct sk_buff *skb, struct net_device *dev),
TP_ARGS(skb, dev),
TP_STRUCT__entry(
SKB_ENTRY
__array(char, dev_name, 32)
),
TP_fast_assign(
SKB_ASSIGN;
strlcpy(__entry->dev_name, dev->name, 32);
),
TP_printk(" %s" SKB_PR_FMT, __entry->dev_name, SKB_PR_ARG)
);
TRACE_EVENT(sc_capwap_parsingdatapacket,
TP_PROTO(struct sc_capwap_session *session,
struct sk_buff *skb),
TP_ARGS(session, skb),
TP_STRUCT__entry(
SESSION_ENTRY
SKB_ENTRY
),
TP_fast_assign(
SESSION_ASSIGN;
SKB_ASSIGN;
),
TP_printk(
SESSION_PR_FMT SKB_PR_FMT,
SESSION_PR_ARG, SKB_PR_ARG
)
);
#endif /* !__CAPWAP_DRIVER_TRACE_H || TRACE_HEADER_MULTI_READ */
#undef TRACE_INCLUDE_PATH
#define TRACE_INCLUDE_PATH .
#undef TRACE_INCLUDE_FILE
#define TRACE_INCLUDE_FILE capwap-trace
#include <trace/define_trace.h>

View File

@ -1,811 +0,0 @@
#include "config.h"
#include <linux/module.h>
#include <linux/if_ether.h>
#include <linux/etherdevice.h>
#include <linux/ieee80211.h>
#include <linux/udp.h>
#include <net/udp.h>
#include "capwap.h"
#include "nlsmartcapwap.h"
#include "netlinkapp.h"
#define CREATE_TRACE_POINTS
#include "capwap-trace.h"
/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
static const unsigned char sc_rfc1042_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
static const unsigned char sc_bridge_tunnel_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
/* */
static void sc_capwap_fragment_free(struct sc_capwap_fragment* fragment)
{
trace_sc_capwap_fragment_free(fragment);
/* */
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_freesession(struct sc_capwap_session* session)
{
int i;
struct sc_capwap_fragment* temp;
struct sc_capwap_fragment* fragment;
struct sc_station *sta;
trace_sc_capwap_freesession(session);
/* Free socket buffers */
list_for_each_entry_safe(fragment, temp, &session->fragments.lru_list, lru_list) {
sc_capwap_fragment_free(fragment);
}
for (i = 0; i < STA_HASH_SIZE; i++) {
hlist_for_each_entry_rcu(sta, &session->station_list[i], station_list) {
hlist_del_rcu(&sta->station_list);
kfree_rcu(sta, rcu_head);
}
}
}
/* */
static void sc_capwap_defrag_evictor(struct sc_capwap_session* session, ktime_t now) {
ktime_t delta;
struct sc_capwap_fragment* fragment;
struct list_head* list = &session->fragments.lru_list;
trace_sc_capwap_defrag_evictor(session);
/* Light check without lock */
if (!list_empty(list)) {
spin_lock(&session->fragments.lock);
/* Remove last old fragment */
if (!list_empty(list)) {
fragment = list_first_entry(list, struct sc_capwap_fragment, lru_list);
delta = ktime_sub(now, fragment->tstamp);
if ((delta.tv64 < -NSEC_PER_SEC) || (delta.tv64 > NSEC_PER_SEC)) {
trace_sc_capwap_defrag_evictor_fragment_expired(session, fragment, now);
sc_capwap_fragment_free(fragment);
}
}
spin_unlock(&session->fragments.lock);
}
}
/* */
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;
trace_sc_capwap_reasm(fragment);
/* */
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, skbfrag->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 = skbfrag->len - offset;
TRACEKMOD("*** Append fragment size %d\n", len);
/* */
memcpy(skb_put(skb, len), skbfrag->data + offset, len);
skbfrag = skbfrag->next;
}
TRACEKMOD("*** Assemblate capwap data packet with total size %d\n", skb->len);
return skb;
}
/* */
static struct sk_buff* sc_capwap_defrag(struct sc_capwap_session* session, struct sk_buff* skb) {
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;
/* */
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;
trace_sc_capwap_defrag(session, frag_id, cb->frag_offset, cb->frag_length);
/* */
spin_lock(&session->fragments.lock);
/* Get fragment */
fragment = &session->fragments.queues[frag_id % CAPWAP_FRAGMENT_QUEUE];
if ((fragment->flags & CAPWAP_FRAGMENT_ENABLE) && (fragment->fragmentid != frag_id)) {
TRACEKMOD("*** Unable defrag, queue fragment busy\n");
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);
TRACEKMOD("*** Unable defrag, overlap error\n");
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) {
TRACEKMOD("*** Unable defrag, duplicate packet\n");
goto error2; /* Duplicate packet */
} else if (next_cb->frag_offset > cb->frag_offset) {
if ((cb->frag_offset + cb->frag_length) <= next_cb->frag_offset) {
break;
} else {
sc_capwap_fragment_free(fragment);
TRACEKMOD("*** Unable defrag, overlap error\n");
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;
TRACEKMOD("*** Fragment id %hu expire at %llu\n", frag_id, fragment->tstamp.tv64);
/* 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(&session->fragments.lock);
return skb_defrag;
error2:
spin_unlock(&session->fragments.lock);
error:
kfree_skb(skb);
return NULL;
}
/* */
static unsigned int sc_capwap_80211_hdrlen(__le16 fc) {
unsigned int hdrlen = 24;
if (ieee80211_is_data(fc)) {
if (ieee80211_has_a4(fc)) {
hdrlen = 30;
}
if (ieee80211_is_data_qos(fc)) {
hdrlen += IEEE80211_QOS_CTL_LEN;
if (ieee80211_has_order(fc)) {
hdrlen += IEEE80211_HT_CTL_LEN;
}
}
} else if (ieee80211_is_ctl(fc)) {
if ((fc & cpu_to_le16(0x00E0)) == cpu_to_le16(0x00C0)) {
hdrlen = 10;
} else {
hdrlen = 16;
}
}
return hdrlen;
}
/* */
int sc_capwap_8023_to_80211(struct sk_buff* skb, const uint8_t* bssid) {
uint16_t hdrlen;
int head_need;
struct ieee80211_hdr hdr;
int skip_header_bytes;
const uint8_t* encaps_data;
int encaps_len;
struct ethhdr* eh = (struct ethhdr*)skb->data;
uint16_t ethertype = ntohs(eh->h_proto);
trace_sc_capwap_8023_to_80211(skb, bssid);
/* IEEE 802.11 header */
hdrlen = 24;
hdr.frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA | IEEE80211_FCTL_FROMDS);
memcpy(hdr.addr1, eh->h_dest, ETH_ALEN);
memcpy(hdr.addr2, bssid, ETH_ALEN);
memcpy(hdr.addr3, eh->h_source, ETH_ALEN);
hdr.duration_id = 0;
hdr.seq_ctrl = 0;
/* */
skip_header_bytes = ETH_HLEN;
if ((ethertype == ETH_P_AARP) || (ethertype == ETH_P_IPX)) {
encaps_data = sc_bridge_tunnel_header;
encaps_len = sizeof(sc_bridge_tunnel_header);
skip_header_bytes -= 2;
} else if (ethertype >= ETH_P_802_3_MIN) {
encaps_data = sc_rfc1042_header;
encaps_len = sizeof(sc_rfc1042_header);
skip_header_bytes -= 2;
} else {
encaps_data = NULL;
encaps_len = 0;
}
/* Remove IEEE 802.3 header */
skb_pull(skb, skip_header_bytes);
/* Check headroom */
head_need = hdrlen + encaps_len - skb_headroom(skb);
if ((head_need > 0) || skb_cloned(skb)) {
head_need = max(head_need, 0);
if (head_need) {
skb_orphan(skb);
}
TRACEKMOD("*** Expand headroom skb of: %d\n", head_need);
if (pskb_expand_head(skb, head_need, 0, GFP_ATOMIC)) {
return -ENOMEM;
}
skb->truesize += head_need;
}
/* Add LLC header */
if (encaps_data) {
memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len);
}
/* Add IEEE 802.11 header */
memcpy(skb_push(skb, hdrlen), &hdr, hdrlen);
skb_reset_mac_header(skb);
return 0;
}
/* */
int sc_capwap_80211_to_8023(struct sk_buff* skb) {
struct ieee80211_hdr* hdr = (struct ieee80211_hdr*)skb->data;
uint16_t hdrlen;
uint16_t ethertype;
uint8_t* payload;
uint8_t dst[ETH_ALEN];
uint8_t src[ETH_ALEN] __aligned(2);
trace_sc_capwap_80211_to_8023(skb);
/* */
hdrlen = sc_capwap_80211_hdrlen(hdr->frame_control);
memcpy(dst, ieee80211_get_DA(hdr), ETH_ALEN);
memcpy(src, ieee80211_get_SA(hdr), ETH_ALEN);
/* */
if (!pskb_may_pull(skb, hdrlen + 8)) {
return -1;
}
/* */
payload = skb->data + hdrlen;
ethertype = (payload[6] << 8) | payload[7];
if (likely((ether_addr_equal(payload, sc_rfc1042_header) && (ethertype != ETH_P_AARP) && (ethertype != ETH_P_IPX)) || ether_addr_equal(payload, sc_bridge_tunnel_header))) {
skb_pull(skb, hdrlen + 6);
memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
} else {
struct ethhdr *ehdr;
__be16 len;
skb_pull(skb, hdrlen);
len = htons(skb->len);
ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr));
memcpy(ehdr->h_dest, dst, ETH_ALEN);
memcpy(ehdr->h_source, src, ETH_ALEN);
ehdr->h_proto = len;
}
return 0;
}
int sc_capwap_create(struct sc_capwap_session *session)
{
int err;
struct udp_tunnel_sock_cfg cfg = {
.sk_user_data = session,
.encap_type = 1,
.encap_rcv = sc_capwap_recvpacket
};
trace_sc_capwap_create(session);
if (session->socket)
return -EBUSY;
/* Open UDP socket */
err = udp_sock_create(session->net, &session->udp_config, &session->socket);
if (err < 0)
goto error;
setup_udp_tunnel_sock(session->net, session->socket, &cfg);
if (session->udp_config.family == AF_INET6)
udpv6_encap_enable();
err = sc_capwap_sendkeepalive(session);
if (err < 0)
goto error;
return err;
error:
if (session->socket)
udp_tunnel_sock_release(session->socket);
session->socket = NULL;
return err;
}
void sc_capwap_close(struct sc_capwap_session *session)
{
trace_sc_capwap_close(session);
if (session->socket)
udp_tunnel_sock_release(session->socket);
session->socket = NULL;
sc_capwap_freesession(session);
}
/* */
static uint16_t sc_capwap_newfragmentid(struct sc_capwap_session* session)
{
trace_sc_capwap_newfragmentid(session);
return atomic_inc_return(&session->fragmentid) & 0xFFFF;
}
/* */
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;
trace_sc_capwap_createkeepalive(sessionid);
/* */
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,
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;
trace_sc_capwap_parsingpacket(session, skb);
/* 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 */
}
/* */
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(session, 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(session->net, 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 (!skb->tstamp.tv64) {
skb->tstamp = ktime_get();
}
/* Cleaning old fragments */
sc_capwap_defrag_evictor(session, skb->tstamp);
/* */
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);
}
}
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 err;
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;
trace_sc_capwap_forwarddata(session, radioid, binding, skb, flags, radioaddr, radioaddrlength, winfo);
/* Check headroom */
headroom = skb_headroom(skb);
reserve = sizeof(struct sc_capwap_header) + radioaddrlength + winfolength;
if (skb_is_nonlinear(skb) || (headroom < reserve)) {
TRACEKMOD("*** Copy socket buffer and expand headroom of: %d\n", (reserve - headroom));
clone = skb_copy_expand(skb, max(headroom, reserve), skb_tailroom(skb), GFP_KERNEL);
if (!clone) {
TRACEKMOD("*** Unable to copy 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 */
err = sc_capwap_send(session, (uint8_t*)header, (size + length));
TRACEKMOD("*** Send packet result: %d\n", err);
if (err < 0) {
break;
}
/* */
header = (struct sc_capwap_header*)(((uint8_t*)header + size + length) - sizeof(struct sc_capwap_header));
fragmentoffset += length;
packetlength -= length;
}
if (clone) {
kfree_skb(clone);
}
return (!packetlength ? 0 : -EIO);
}
/* */
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;
trace_sc_capwap_setradiomacaddress(bssid);
memset(buffer, 0, size);
radioaddr = (struct sc_capwap_radio_addr*)buffer;
radioaddr->length = MACADDRESS_EUI48_LENGTH;
addr = (struct sc_capwap_macaddress_eui48*)radioaddr->addr;
memcpy(addr->addr, bssid, MACADDRESS_EUI48_LENGTH);
return radioaddr;
}
/* */
struct sc_capwap_wireless_information* sc_capwap_setwinfo_frameinfo(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;
trace_sc_capwap_setwinfo_frameinfo(rssi, snr, rate);
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;
}
/* */
struct sc_capwap_wireless_information* sc_capwap_setwinfo_destwlans(uint8_t* buffer, int size, uint16_t wlanidbitmap) {
struct sc_capwap_wireless_information* winfo;
struct sc_capwap_destination_wlans* destwlans;
trace_sc_capwap_setwinfo_destwlans(wlanidbitmap);
memset(buffer, 0, size);
winfo = (struct sc_capwap_wireless_information*)buffer;
winfo->length = sizeof(struct sc_capwap_destination_wlans);
destwlans = (struct sc_capwap_destination_wlans*)(buffer + sizeof(struct sc_capwap_wireless_information));
destwlans->wlanidbitmap = cpu_to_be16(wlanidbitmap);
return winfo;
}

View File

@ -1,154 +0,0 @@
#ifndef __KMOD_CAPWAP_HEADER__
#define __KMOD_CAPWAP_HEADER__
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/in6.h>
#include <linux/skbuff.h>
#include <net/protocol.h>
#include <net/ip.h>
#include <net/udp.h>
#include <net/udp_tunnel.h>
#include "capwap_rfc.h"
/* */
#define STA_HASH_SIZE 16
/* */
#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_AC_TAP 0x0004
#define SKB_CAPWAP_FLAG_FROM_IEEE80211 0x0008
#define SKB_CAPWAP_FLAG_SESSIONID 0x0100
#define SKB_CAPWAP_FLAG_RADIOID 0x0200
#define SKB_CAPWAP_FLAG_BINDING 0x0400
#define SKB_CAPWAP_FLAG_WIRELESSINFORMATION 0x0800
#define SKB_CAPWAP_FLAG_FRAGMENT 0x1000
/* Universal socket address */
union capwap_addr {
struct sockaddr sa;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
struct sockaddr_storage ss;
};
#define STA_FLAG_AKM_ONLY 0x0001
struct sc_station {
struct hlist_node station_list;
uint8_t radioid;
uint8_t mac[ETH_ALEN];
uint8_t wlanid;
uint32_t flags;
struct rcu_head rcu_head;
};
struct sc_skb_capwap_cb {
uint16_t flags;
/* Session ID */
struct sc_capwap_sessionid_element sessionid;
/* Capwap information */
uint8_t radioid;
uint8_t binding;
/* 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 net *net;
struct socket *socket;
struct udp_port_cfg udp_config;
uint16_t mtu;
struct sc_capwap_sessionid_element sessionid;
atomic_t fragmentid;
struct sc_capwap_fragment_queue fragments;
struct hlist_head station_list[STA_HASH_SIZE];
};
/* Dipendent implementation function */
int sc_capwap_recvpacket(struct sock *sk, struct sk_buff* skb);
struct sc_capwap_session* sc_capwap_recvunknownkeepalive(struct sc_capwap_session* session,
const 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_create(struct sc_capwap_session *session);
int sc_capwap_send(struct sc_capwap_session *session, uint8_t* buffer, int length);
void sc_capwap_close(struct sc_capwap_session *session);
int sc_capwap_8023_to_80211(struct sk_buff* skb, const uint8_t* bssid);
int sc_capwap_80211_to_8023(struct sk_buff* skb);
int sc_capwap_createkeepalive(struct sc_capwap_sessionid_element* sessionid, uint8_t* buffer, int size);
int sc_capwap_parsingpacket(struct sc_capwap_session* session, 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_setwinfo_frameinfo(uint8_t* buffer, int size, uint8_t rssi, uint8_t snr, uint16_t rate);
struct sc_capwap_wireless_information* sc_capwap_setwinfo_destwlans(uint8_t* buffer, int size, uint16_t wlanidbitmap);
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

@ -1,339 +0,0 @@
#include "config.h"
#include <linux/module.h>
#include <linux/kthread.h>
#include <linux/etherdevice.h>
#include <linux/ieee80211.h>
#include <net/net_namespace.h>
#include <net/mac80211.h>
#include <net/ipv6.h>
#include <net/xfrm.h>
#include "capwap.h"
#include "nlsmartcapwap.h"
#include "netlinkapp.h"
#include "capwap-trace.h"
/* */
int sc_capwap_init(struct sc_capwap_session *session, struct net *net)
{
int i;
TRACEKMOD("### sc_capwap_init\n");
ASSERT_RTNL();
/* Init session */
memset(session, 0, sizeof(struct sc_capwap_session));
session->net = net;
/* 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);
for (i = 0; i < STA_HASH_SIZE; i++)
INIT_HLIST_HEAD(&session->station_list[i]);
return 0;
}
/* */
void sc_capwap_resetsession(struct sc_capwap_session *session)
{
trace_sc_capwap_resetsession(session);
sc_capwap_close(session);
sc_capwap_init(session, session->net);
}
/* */
int sc_capwap_sendkeepalive(struct sc_capwap_session *session)
{
int ret;
int length;
uint8_t buffer[CAPWAP_KEEP_ALIVE_MAX_SIZE];
trace_sc_capwap_sendkeepalive(session);
/* Build keepalive */
length = sc_capwap_createkeepalive(&session->sessionid, buffer, CAPWAP_KEEP_ALIVE_MAX_SIZE);
/* Send packet */
ret = sc_capwap_send(session, buffer, length);
TRACEKMOD("*** Send keep-alive result: %d\n", ret);
if (ret > 0) {
ret = 0;
}
return ret;
}
int sc_capwap_send(struct sc_capwap_session *session, uint8_t* buffer, int length)
{
struct kvec vec = {
.iov_base = buffer,
.iov_len = length,
};
struct msghdr msg = {
.msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL,
};
trace_sc_capwap_send(session);
return kernel_sendmsg(session->socket, &msg, &vec, 1, vec.iov_len);
}
int sc_capwap_recvpacket(struct sock *sk, struct sk_buff* skb)
{
struct sc_capwap_session* session;
TRACEKMOD("### sc_capwap_recvpacket\n");
CAPWAP_SKB_CB(skb)->flags = SKB_CAPWAP_FLAG_FROM_DATA_CHANNEL;
sock_hold(sk);
/* Get session */
session = (struct sc_capwap_session *)sk->sk_user_data;
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, skb)) {
TRACEKMOD("*** Parsing error\n");
goto drop;
}
sock_put(sk);
return 0;
drop:
sock_put(sk);
kfree_skb(skb);
return 0;
}
/* */
struct sc_capwap_session* sc_capwap_recvunknownkeepalive(struct sc_capwap_session* session,
const struct sc_capwap_sessionid_element* sessionid)
{
TRACEKMOD("### sc_capwap_recvunknownkeepalive\n");
return NULL;
}
static void sc_send_8023(struct sk_buff *skb, struct net_device *dev)
{
struct ethhdr *eh;
if (unlikely(!pskb_may_pull(skb, ETH_HLEN)))
return;
/* drop conntrack reference */
nf_reset(skb);
/* detach skb from CAPWAP */
skb_orphan(skb);
secpath_reset(skb);
/* drop any routing info */
skb_dst_drop(skb);
skb->dev = dev;
skb_reset_mac_header(skb);
eh = eth_hdr(skb);
if (likely(eth_proto_is_802_3(eh->h_proto)))
skb->protocol = eh->h_proto;
else
skb->protocol = htons(ETH_P_802_2);
skb_set_network_header(skb, ETH_HLEN);
/* Force the device to verify it. */
skb->ip_summed = CHECKSUM_NONE;
dev_queue_xmit(skb);
}
static void sc_send_80211(struct sk_buff *skb, struct net_device *dev)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
trace_sc_send_80211(skb, dev);
/* detach skb from CAPWAP */
skb_orphan(skb);
secpath_reset(skb);
/* drop any routing info */
skb_dst_drop(skb);
/* drop conntrack reference */
nf_reset(skb);
skb_reset_mac_header(skb);
skb_reset_network_header(skb);
skb_reset_transport_header(skb);
skb->dev = dev;
skb->protocol = htons(ETH_P_CONTROL);
memset(info, 0, sizeof(*info));
info->flags = IEEE80211_TX_CTL_INJECTED;
/* Force the device to verify it. */
skb->ip_summed = CHECKSUM_NONE;
dev_queue_xmit(skb);
}
/* */
void sc_capwap_parsingdatapacket(struct sc_capwap_session* session, struct sk_buff* skb)
{
uint8_t* pos;
uint8_t* dstaddress;
struct net_device* dev;
struct sc_capwap_header* header = (struct sc_capwap_header*)skb->data;
int is80211 = (IS_FLAG_T_HEADER(header) ? 1 : 0);
struct sc_capwap_radio_addr* radioaddr = NULL;
int radioaddrsize = 0;
struct sc_capwap_wireless_information* winfo = NULL;
struct sc_capwap_destination_wlans* destwlan = NULL;
int winfosize = 0;
trace_sc_capwap_parsingdatapacket(session, skb);
/* Retrieve optional attribute */
pos = skb->data + sizeof(struct sc_capwap_header);
if (IS_FLAG_M_HEADER(header)) {
radioaddr = (struct sc_capwap_radio_addr*)pos;
radioaddrsize = (sizeof(struct sc_capwap_radio_addr) + radioaddr->length + 3) & ~3;
pos += radioaddrsize;
}
if (IS_FLAG_W_HEADER(header)) {
winfo = (struct sc_capwap_wireless_information*)pos;
destwlan = (struct sc_capwap_destination_wlans*)(pos + sizeof(struct sc_capwap_wireless_information));
winfosize = (sizeof(struct sc_capwap_wireless_information) + winfo->length + 3) & ~3;
pos += winfosize;
}
/* Body packet */
skb_pull(skb, GET_HLEN_HEADER(header) * 4);
dstaddress = (is80211 ? ieee80211_get_DA((struct ieee80211_hdr*)skb->data) : (uint8_t*)((struct ethhdr*)skb->data)->h_dest);
if (is_multicast_ether_addr(dstaddress)) {
uint8_t wlanid;
uint16_t bitmask;
/* Accept only broadcast packet with wireless information */
if (!winfo) {
TRACEKMOD("*** Invalid broadcast packet\n");
/* Free broadcast packet */
kfree_skb(skb);
return;
}
for (wlanid = 1, bitmask = be16_to_cpu(destwlan->wlanidbitmap);
bitmask;
wlanid++, bitmask >>=1 )
{
struct sk_buff* clone;
if (!(bitmask & 0x01))
continue;
dev = sc_netlink_getdev_from_wlanid(session->net, GET_RID_HEADER(header), wlanid);
if (!dev) {
TRACEKMOD("*** Unknown wlanid: %d\n", (int)wlanid);
continue;
}
clone = skb_copy_expand(skb, skb_headroom(skb), skb_tailroom(skb), GFP_KERNEL);
if (!clone)
goto error;
/* */
if (!is80211) {
TRACEKMOD("*** Send 802.3 broadcast packet to interface: %d\n",
dev->ifindex);
sc_send_8023(clone, dev);
} else {
TRACEKMOD("*** Send broadcast packet to interface: %d\n", dev->ifindex);
/* Send packet */
local_bh_disable();
ieee80211_inject_xmit(clone, dev);
local_bh_enable();
}
}
} else {
uint32_t hash;
struct hlist_head *sta_head;
struct sc_station *sta;
hash = jhash(dstaddress, ETH_ALEN, GET_RID_HEADER(header)) % STA_HASH_SIZE;
sta_head = &session->station_list[hash];
rcu_read_lock();
sta = sc_find_station(sta_head, GET_RID_HEADER(header), dstaddress);
if (!sta) {
rcu_read_unlock();
TRACEKMOD("*** Radio Id for STA invalid: %d, %pM\n",
GET_RID_HEADER(header), dstaddress);
goto error;
}
dev = sc_netlink_getdev_from_wlanid(session->net, GET_RID_HEADER(header), sta->wlanid);
if (!dev) {
TRACEKMOD("*** no interface for Radio Id/WLAN Id: %d, %d\n",
GET_RID_HEADER(header), sta->wlanid);
rcu_read_unlock();
goto error;
}
rcu_read_unlock();
if (!is80211) {
sc_send_8023(skb, dev);
} else {
if (memcmp(dev->dev_addr, ((struct ieee80211_hdr*)skb->data)->addr2, ETH_ALEN) != 0) {
TRACEKMOD("*** Invalid BSSID in 802.11 packet\n");
goto error;
}
TRACEKMOD("** Send packet to interface: %d\n", dev->ifindex);
sc_send_80211(skb, dev);
}
}
return;
error:
TRACEKMOD("*** Invalid packet\n");
kfree_skb(skb);
}
/* */
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(session->net, skb->data, skb->len);
}

View File

@ -1,25 +0,0 @@
#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;
};
/* */
struct sc_station *sc_find_station(struct hlist_head *sta_head, uint8_t radioid, uint8_t *mac);
/* */
int sc_capwap_init(struct sc_capwap_session *sc_acsession, struct net *net);
/* */
void sc_capwap_resetsession(struct sc_capwap_session *sc_acsession);
/* */
int sc_capwap_sendkeepalive(struct sc_capwap_session *sc_acsession);
#endif /* __KMOD_CAPWAP_PRIVATE_HEADER__ */

View File

@ -1,187 +0,0 @@
#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;
uint8_t addr[0];
} __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;
/* Destination WLANs */
struct sc_capwap_destination_wlans {
__be16 wlanidbitmap;
__be16 reserved;
} __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 {
union {
uint8_t id[16];
uint32_t id32[4];
};
} __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))
/* IEEE 802.11 Add WLAN */
#define CAPWAP_ADD_WLAN_TUNNELMODE_LOCAL 0
#define CAPWAP_ADD_WLAN_TUNNELMODE_8023 1
#define CAPWAP_ADD_WLAN_TUNNELMODE_80211 2
#endif /* __KMOD_CAPWAP_RFC_HEADER__ */

View File

@ -1,13 +0,0 @@
#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,32 +0,0 @@
#include "config.h"
#include <linux/module.h>
#include <linux/kernel.h>
#include "netlinkapp.h"
/* */
static int __init smartcapwap_wtp_init(void) {
int ret;
TRACEKMOD("### smartcapwap_wtp_init\n");
/* Initialize netlink */
ret = sc_netlink_init();
if (ret) {
return ret;
}
return ret;
}
module_init(smartcapwap_wtp_init);
/* */
static void __exit smartcapwap_wtp_exit(void) {
TRACEKMOD("### smartcapwap_wtp_exit\n");
sc_netlink_exit();
}
module_exit(smartcapwap_wtp_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Massimo Vellucci <vemax78@gmail.com>");
MODULE_DESCRIPTION("SmartCAPWAP WTP Data Channel Module");

File diff suppressed because it is too large Load Diff

View File

@ -1,19 +0,0 @@
#ifndef __KMOD_WTP_NETLINKAPP_HEADER__
#define __KMOD_WTP_NETLINKAPP_HEADER__
#include "capwap_rfc.h"
#include "capwap.h"
/* */
int sc_netlink_init(void);
void sc_netlink_exit(void);
/* */
struct net_device* sc_netlink_getdev_from_wlanid(struct net *net, uint8_t radioid, uint8_t wlanid);
/* */
int sc_netlink_notify_recv_keepalive(struct net *net,
struct sc_capwap_sessionid_element* sessionid);
int sc_netlink_notify_recv_data(struct net *net, uint8_t* packet, int length);
#endif /* __KMOD_WTP_NETLINKAPP_HEADER__ */

View File

@ -1,71 +0,0 @@
#ifndef __WTP_NLSMARTCAPWAP_HEADER__
#define __WTP_NLSMARTCAPWAP_HEADER__
/* */
#define NLSMARTCAPWAP_GENL_NAME "smartcapwap_wtp"
/* */
#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,
NLSMARTCAPWAP_ATTR_MGMT_SUBTYPE_MASK,
NLSMARTCAPWAP_ATTR_CTRL_SUBTYPE_MASK,
NLSMARTCAPWAP_ATTR_DATA_SUBTYPE_MASK,
NLSMARTCAPWAP_ATTR_LOCAL_ADDRESS,
NLSMARTCAPWAP_ATTR_PEER_ADDRESS,
NLSMARTCAPWAP_ATTR_MTU,
NLSMARTCAPWAP_ATTR_SESSION_ID,
NLSMARTCAPWAP_ATTR_DTLS,
NLSMARTCAPWAP_ATTR_DATA_FRAME,
NLSMARTCAPWAP_ATTR_RSSI,
NLSMARTCAPWAP_ATTR_SNR,
NLSMARTCAPWAP_ATTR_RATE,
NLSMARTCAPWAP_ATTR_MAC,
/* Last attribute */
__NLSMARTCAPWAP_ATTR_AFTER_LAST,
NLSMARTCAPWAP_ATTR_MAX = __NLSMARTCAPWAP_ATTR_AFTER_LAST - 1
};
/* */
enum nlsmartcapwap_commands {
NLSMARTCAPWAP_CMD_UNSPEC,
NLSMARTCAPWAP_CMD_LINK,
NLSMARTCAPWAP_CMD_CREATE,
NLSMARTCAPWAP_CMD_RESET,
NLSMARTCAPWAP_CMD_SEND_KEEPALIVE,
NLSMARTCAPWAP_CMD_RECV_KEEPALIVE,
NLSMARTCAPWAP_CMD_SEND_DATA,
NLSMARTCAPWAP_CMD_RECV_DATA,
NLSMARTCAPWAP_CMD_JOIN_MAC80211_DEVICE,
NLSMARTCAPWAP_CMD_LEAVE_MAC80211_DEVICE,
NLSMARTCAPWAP_CMD_ADD_STATION,
NLSMARTCAPWAP_CMD_DEL_STATION,
/* Last command */
__NLSMARTCAPWAP_CMD_AFTER_LAST,
NLSMARTCAPWAP_CMD_MAX = __NLSMARTCAPWAP_CMD_AFTER_LAST - 1
};
#endif /* __WTP_NLSMARTCAPWAP_HEADER__ */