move kmod to top level directory
This commit is contained in:
@ -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
|
||||
|
||||
|
@ -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>
|
@ -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;
|
||||
}
|
@ -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__ */
|
@ -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);
|
||||
}
|
@ -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__ */
|
||||
|
@ -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__ */
|
@ -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__ */
|
||||
|
@ -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
@ -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__ */
|
@ -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__ */
|
Reference in New Issue
Block a user