remove dos style newlines
This commit is contained in:
@ -1,18 +1,18 @@
|
||||
KVERSION = $(shell uname -r)
|
||||
|
||||
obj-m += smartcapwap.o
|
||||
|
||||
smartcapwap-y := \
|
||||
main.o \
|
||||
netlinkapp.o \
|
||||
capwap.o \
|
||||
capwap_private.o \
|
||||
station.o \
|
||||
socket.o \
|
||||
iface.o
|
||||
|
||||
all:
|
||||
make -C /lib/modules/$(KVERSION)/build M="$(PWD)" modules
|
||||
|
||||
clean:
|
||||
make -C /lib/modules/$(KVERSION)/build M="$(PWD)" clean
|
||||
KVERSION = $(shell uname -r)
|
||||
|
||||
obj-m += smartcapwap.o
|
||||
|
||||
smartcapwap-y := \
|
||||
main.o \
|
||||
netlinkapp.o \
|
||||
capwap.o \
|
||||
capwap_private.o \
|
||||
station.o \
|
||||
socket.o \
|
||||
iface.o
|
||||
|
||||
all:
|
||||
make -C /lib/modules/$(KVERSION)/build M="$(PWD)" modules
|
||||
|
||||
clean:
|
||||
make -C /lib/modules/$(KVERSION)/build M="$(PWD)" clean
|
||||
|
1578
src/ac/kmod/capwap.c
1578
src/ac/kmod/capwap.c
File diff suppressed because it is too large
Load Diff
@ -1,124 +1,124 @@
|
||||
#ifndef __KMOD_CAPWAP_HEADER__
|
||||
#define __KMOD_CAPWAP_HEADER__
|
||||
|
||||
#include "capwap_rfc.h"
|
||||
#include "socket.h"
|
||||
|
||||
/* */
|
||||
#define MAX_MTU 9000
|
||||
#define DEFAULT_MTU 1450
|
||||
#define MIN_MTU 500
|
||||
#define IEEE80211_MTU 7981
|
||||
|
||||
/* */
|
||||
#define CAPWAP_FRAGMENT_QUEUE 16
|
||||
|
||||
/* */
|
||||
#define CAPWAP_FRAGMENT_ENABLE 0x0001
|
||||
#define CAPWAP_FRAGMENT_LRUQUEUE 0x0002
|
||||
#define CAPWAP_FRAGMENT_LAST 0x0004
|
||||
|
||||
/* */
|
||||
#define SKB_CAPWAP_FLAG_FROM_DATA_CHANNEL 0x0001
|
||||
#define SKB_CAPWAP_FLAG_FROM_USER_SPACE 0x0002
|
||||
#define SKB_CAPWAP_FLAG_FROM_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
|
||||
|
||||
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 {
|
||||
uint16_t mtu;
|
||||
union capwap_addr peeraddr;
|
||||
struct sc_capwap_sessionid_element sessionid;
|
||||
|
||||
uint16_t fragmentid;
|
||||
spinlock_t fragmentid_lock;
|
||||
|
||||
struct sc_capwap_fragment_queue fragments;
|
||||
};
|
||||
|
||||
/* */
|
||||
extern union capwap_addr sc_localaddr;
|
||||
|
||||
/* Dipendent implementation function */
|
||||
void sc_capwap_recvpacket(struct sk_buff* skb);
|
||||
struct sc_capwap_session* sc_capwap_recvunknownkeepalive(const union capwap_addr* sockaddr, 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_bind(union capwap_addr* sockaddr);
|
||||
|
||||
void sc_capwap_initsession(struct sc_capwap_session* session);
|
||||
void sc_capwap_freesession(struct sc_capwap_session* session);
|
||||
uint16_t sc_capwap_newfragmentid(struct sc_capwap_session* session);
|
||||
|
||||
int sc_capwap_8023_to_80211(struct sk_buff* skb, const uint8_t* bssid);
|
||||
int sc_capwap_80211_to_8023(struct sk_buff* skb);
|
||||
|
||||
void sc_capwap_sessionid_printf(const struct sc_capwap_sessionid_element* sessionid, char* string);
|
||||
|
||||
int sc_capwap_createkeepalive(struct sc_capwap_sessionid_element* sessionid, uint8_t* buffer, int size);
|
||||
int sc_capwap_parsingpacket(struct sc_capwap_session* session, const union capwap_addr* sockaddr, struct sk_buff* skb);
|
||||
|
||||
struct sc_capwap_radio_addr* sc_capwap_setradiomacaddress(uint8_t* buffer, int size, uint8_t* bssid);
|
||||
struct sc_capwap_wireless_information* sc_capwap_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__ */
|
||||
#ifndef __KMOD_CAPWAP_HEADER__
|
||||
#define __KMOD_CAPWAP_HEADER__
|
||||
|
||||
#include "capwap_rfc.h"
|
||||
#include "socket.h"
|
||||
|
||||
/* */
|
||||
#define MAX_MTU 9000
|
||||
#define DEFAULT_MTU 1450
|
||||
#define MIN_MTU 500
|
||||
#define IEEE80211_MTU 7981
|
||||
|
||||
/* */
|
||||
#define CAPWAP_FRAGMENT_QUEUE 16
|
||||
|
||||
/* */
|
||||
#define CAPWAP_FRAGMENT_ENABLE 0x0001
|
||||
#define CAPWAP_FRAGMENT_LRUQUEUE 0x0002
|
||||
#define CAPWAP_FRAGMENT_LAST 0x0004
|
||||
|
||||
/* */
|
||||
#define SKB_CAPWAP_FLAG_FROM_DATA_CHANNEL 0x0001
|
||||
#define SKB_CAPWAP_FLAG_FROM_USER_SPACE 0x0002
|
||||
#define SKB_CAPWAP_FLAG_FROM_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
|
||||
|
||||
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 {
|
||||
uint16_t mtu;
|
||||
union capwap_addr peeraddr;
|
||||
struct sc_capwap_sessionid_element sessionid;
|
||||
|
||||
uint16_t fragmentid;
|
||||
spinlock_t fragmentid_lock;
|
||||
|
||||
struct sc_capwap_fragment_queue fragments;
|
||||
};
|
||||
|
||||
/* */
|
||||
extern union capwap_addr sc_localaddr;
|
||||
|
||||
/* Dipendent implementation function */
|
||||
void sc_capwap_recvpacket(struct sk_buff* skb);
|
||||
struct sc_capwap_session* sc_capwap_recvunknownkeepalive(const union capwap_addr* sockaddr, 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_bind(union capwap_addr* sockaddr);
|
||||
|
||||
void sc_capwap_initsession(struct sc_capwap_session* session);
|
||||
void sc_capwap_freesession(struct sc_capwap_session* session);
|
||||
uint16_t sc_capwap_newfragmentid(struct sc_capwap_session* session);
|
||||
|
||||
int sc_capwap_8023_to_80211(struct sk_buff* skb, const uint8_t* bssid);
|
||||
int sc_capwap_80211_to_8023(struct sk_buff* skb);
|
||||
|
||||
void sc_capwap_sessionid_printf(const struct sc_capwap_sessionid_element* sessionid, char* string);
|
||||
|
||||
int sc_capwap_createkeepalive(struct sc_capwap_sessionid_element* sessionid, uint8_t* buffer, int size);
|
||||
int sc_capwap_parsingpacket(struct sc_capwap_session* session, const union capwap_addr* sockaddr, struct sk_buff* skb);
|
||||
|
||||
struct sc_capwap_radio_addr* sc_capwap_setradiomacaddress(uint8_t* buffer, int size, uint8_t* bssid);
|
||||
struct sc_capwap_wireless_information* sc_capwap_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__ */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,67 +1,67 @@
|
||||
#ifndef __KMOD_CAPWAP_PRIVATE_HEADER__
|
||||
#define __KMOD_CAPWAP_PRIVATE_HEADER__
|
||||
|
||||
/* */
|
||||
struct sc_capwap_wlan {
|
||||
int used;
|
||||
|
||||
uint8_t bssid[MACADDRESS_EUI48_LENGTH];
|
||||
uint8_t macmode;
|
||||
uint8_t tunnelmode;
|
||||
};
|
||||
|
||||
/* */
|
||||
struct sc_capwap_session_priv {
|
||||
struct sc_capwap_session session;
|
||||
|
||||
struct list_head list;
|
||||
struct sc_capwap_session_priv* __rcu next_ipaddr;
|
||||
struct sc_capwap_session_priv* __rcu next_sessionid;
|
||||
|
||||
struct list_head list_stations;
|
||||
struct list_head list_connections;
|
||||
|
||||
/* */
|
||||
int isolation;
|
||||
uint8_t binding;
|
||||
struct sc_capwap_wlan wlans[CAPWAP_RADIOID_MAX_COUNT][CAPWAP_WLANID_MAX_COUNT];
|
||||
};
|
||||
|
||||
/* */
|
||||
struct sc_capwap_workthread {
|
||||
struct task_struct* thread;
|
||||
|
||||
struct sk_buff_head queue;
|
||||
wait_queue_head_t waitevent;
|
||||
};
|
||||
|
||||
/* */
|
||||
int sc_capwap_init(void);
|
||||
void sc_capwap_close(void);
|
||||
|
||||
/* */
|
||||
void sc_capwap_update_lock(void);
|
||||
void sc_capwap_update_unlock(void);
|
||||
|
||||
#ifdef CONFIG_PROVE_LOCKING
|
||||
int sc_capwap_update_lock_is_locked(void);
|
||||
#else
|
||||
static inline int sc_capwap_update_lock_is_locked(void) { return 1; }
|
||||
#endif
|
||||
|
||||
/* */
|
||||
int sc_capwap_sendkeepalive(const struct sc_capwap_sessionid_element* sessionid);
|
||||
|
||||
/* */
|
||||
int sc_capwap_newsession(const struct sc_capwap_sessionid_element* sessionid, uint8_t binding, uint16_t mtu);
|
||||
int sc_capwap_deletesession(const struct sc_capwap_sessionid_element* sessionid);
|
||||
|
||||
/* */
|
||||
int sc_capwap_addwlan(const struct sc_capwap_sessionid_element* sessionid, uint8_t radioid, uint8_t wlanid, const uint8_t* bssid, uint8_t macmode, uint8_t tunnelmode);
|
||||
int sc_capwap_removewlan(const struct sc_capwap_sessionid_element* sessionid, uint8_t radioid, uint8_t wlanid);
|
||||
|
||||
/* */
|
||||
int sc_capwap_authstation(const struct sc_capwap_sessionid_element* sessionid, const uint8_t* address, uint32_t ifindex, uint8_t radioid, uint8_t wlanid, uint16_t vlan);
|
||||
int sc_capwap_deauthstation(const struct sc_capwap_sessionid_element* sessionid, const uint8_t* address);
|
||||
|
||||
#endif /* __KMOD_CAPWAP_PRIVATE_HEADER__ */
|
||||
#ifndef __KMOD_CAPWAP_PRIVATE_HEADER__
|
||||
#define __KMOD_CAPWAP_PRIVATE_HEADER__
|
||||
|
||||
/* */
|
||||
struct sc_capwap_wlan {
|
||||
int used;
|
||||
|
||||
uint8_t bssid[MACADDRESS_EUI48_LENGTH];
|
||||
uint8_t macmode;
|
||||
uint8_t tunnelmode;
|
||||
};
|
||||
|
||||
/* */
|
||||
struct sc_capwap_session_priv {
|
||||
struct sc_capwap_session session;
|
||||
|
||||
struct list_head list;
|
||||
struct sc_capwap_session_priv* __rcu next_ipaddr;
|
||||
struct sc_capwap_session_priv* __rcu next_sessionid;
|
||||
|
||||
struct list_head list_stations;
|
||||
struct list_head list_connections;
|
||||
|
||||
/* */
|
||||
int isolation;
|
||||
uint8_t binding;
|
||||
struct sc_capwap_wlan wlans[CAPWAP_RADIOID_MAX_COUNT][CAPWAP_WLANID_MAX_COUNT];
|
||||
};
|
||||
|
||||
/* */
|
||||
struct sc_capwap_workthread {
|
||||
struct task_struct* thread;
|
||||
|
||||
struct sk_buff_head queue;
|
||||
wait_queue_head_t waitevent;
|
||||
};
|
||||
|
||||
/* */
|
||||
int sc_capwap_init(void);
|
||||
void sc_capwap_close(void);
|
||||
|
||||
/* */
|
||||
void sc_capwap_update_lock(void);
|
||||
void sc_capwap_update_unlock(void);
|
||||
|
||||
#ifdef CONFIG_PROVE_LOCKING
|
||||
int sc_capwap_update_lock_is_locked(void);
|
||||
#else
|
||||
static inline int sc_capwap_update_lock_is_locked(void) { return 1; }
|
||||
#endif
|
||||
|
||||
/* */
|
||||
int sc_capwap_sendkeepalive(const struct sc_capwap_sessionid_element* sessionid);
|
||||
|
||||
/* */
|
||||
int sc_capwap_newsession(const struct sc_capwap_sessionid_element* sessionid, uint8_t binding, uint16_t mtu);
|
||||
int sc_capwap_deletesession(const struct sc_capwap_sessionid_element* sessionid);
|
||||
|
||||
/* */
|
||||
int sc_capwap_addwlan(const struct sc_capwap_sessionid_element* sessionid, uint8_t radioid, uint8_t wlanid, const uint8_t* bssid, uint8_t macmode, uint8_t tunnelmode);
|
||||
int sc_capwap_removewlan(const struct sc_capwap_sessionid_element* sessionid, uint8_t radioid, uint8_t wlanid);
|
||||
|
||||
/* */
|
||||
int sc_capwap_authstation(const struct sc_capwap_sessionid_element* sessionid, const uint8_t* address, uint32_t ifindex, uint8_t radioid, uint8_t wlanid, uint16_t vlan);
|
||||
int sc_capwap_deauthstation(const struct sc_capwap_sessionid_element* sessionid, const uint8_t* address);
|
||||
|
||||
#endif /* __KMOD_CAPWAP_PRIVATE_HEADER__ */
|
||||
|
@ -1,187 +1,187 @@
|
||||
#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__ */
|
||||
#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 +1,13 @@
|
||||
#ifndef __KMOD_CONFIG_HEADER__
|
||||
#define __KMOD_CONFIG_HEADER__
|
||||
|
||||
#define DEBUGKMOD 1
|
||||
|
||||
#ifdef DEBUGKMOD
|
||||
#define TRACEKMOD(s, args...) printk("(%d) " s, smp_processor_id(), ##args)
|
||||
#else
|
||||
#define TRACEKMOD(s, args...)
|
||||
#endif
|
||||
|
||||
#endif /* __KMOD_CONFIG_HEADER__ */
|
||||
|
||||
#ifndef __KMOD_CONFIG_HEADER__
|
||||
#define __KMOD_CONFIG_HEADER__
|
||||
|
||||
#define DEBUGKMOD 1
|
||||
|
||||
#ifdef DEBUGKMOD
|
||||
#define TRACEKMOD(s, args...) printk("(%d) " s, smp_processor_id(), ##args)
|
||||
#else
|
||||
#define TRACEKMOD(s, args...)
|
||||
#endif
|
||||
|
||||
#endif /* __KMOD_CONFIG_HEADER__ */
|
||||
|
||||
|
@ -1,300 +1,300 @@
|
||||
#include "config.h"
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/smp.h>
|
||||
#include "iface.h"
|
||||
#include "station.h"
|
||||
#include "capwap.h"
|
||||
|
||||
/* */
|
||||
#define CAPWAP_IFACE_COUNT 8
|
||||
#define CAPWAP_IFACE_HASH(x) ((x) % CAPWAP_IFACE_COUNT)
|
||||
|
||||
static LIST_HEAD(sc_iface_list);
|
||||
static struct sc_netdev_priv* __rcu sc_iface_hash[CAPWAP_IFACE_COUNT];
|
||||
|
||||
/* */
|
||||
static void sc_iface_netdev_uninit(struct net_device* dev) {
|
||||
struct sc_netdev_priv* search;
|
||||
struct sc_capwap_station* temp;
|
||||
struct sc_capwap_station* station;
|
||||
int hash = CAPWAP_IFACE_HASH(dev->ifindex);
|
||||
struct sc_netdev_priv* priv = (struct sc_netdev_priv*)netdev_priv(dev);
|
||||
|
||||
TRACEKMOD("### sc_iface_netdev_uninit\n");
|
||||
|
||||
sc_capwap_update_lock();
|
||||
|
||||
/* Close stations */
|
||||
list_for_each_entry_safe(station, temp, &priv->list_stations, list_dev) {
|
||||
sc_stations_releaseconnection(station);
|
||||
sc_stations_free(station);
|
||||
}
|
||||
|
||||
/* */
|
||||
if (!list_empty(&priv->list_stations)) {
|
||||
TRACEKMOD("*** Bug: the list stations of interface is not empty\n");
|
||||
}
|
||||
|
||||
if (!list_empty(&priv->list_connections)) {
|
||||
TRACEKMOD("*** Bug: the list connections of interface is not empty\n");
|
||||
}
|
||||
|
||||
/* Remove interface from hash */
|
||||
search = rcu_dereference_protected(sc_iface_hash[hash], sc_capwap_update_lock_is_locked());
|
||||
if (search) {
|
||||
if (priv == search) {
|
||||
netif_tx_lock_bh(dev);
|
||||
netif_carrier_off(dev);
|
||||
netif_tx_unlock_bh(dev);
|
||||
|
||||
rcu_assign_pointer(sc_iface_hash[hash], priv->next);
|
||||
|
||||
list_del_rcu(&priv->list);
|
||||
synchronize_net();
|
||||
|
||||
dev_put(dev);
|
||||
} else {
|
||||
while (rcu_access_pointer(search->next) && (rcu_access_pointer(search->next) != priv)) {
|
||||
search = rcu_dereference_protected(search->next, sc_capwap_update_lock_is_locked());
|
||||
}
|
||||
|
||||
if (rcu_access_pointer(search->next)) {
|
||||
netif_tx_lock_bh(dev);
|
||||
netif_carrier_off(dev);
|
||||
netif_tx_unlock_bh(dev);
|
||||
|
||||
rcu_assign_pointer(search->next, priv->next);
|
||||
|
||||
list_del_rcu(&priv->list);
|
||||
synchronize_net();
|
||||
|
||||
dev_put(dev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sc_capwap_update_unlock();
|
||||
}
|
||||
|
||||
/* */
|
||||
static int sc_iface_netdev_open(struct net_device* dev) {
|
||||
TRACEKMOD("### sc_iface_netdev_open\n");
|
||||
|
||||
netif_start_queue(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
static int sc_iface_netdev_stop(struct net_device* dev) {
|
||||
TRACEKMOD("### sc_iface_netdev_stop\n");
|
||||
|
||||
netif_stop_queue(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
static int sc_iface_netdev_tx(struct sk_buff* skb, struct net_device* dev) {
|
||||
struct sc_netdev_priv* priv = (struct sc_netdev_priv*)netdev_priv(dev);
|
||||
|
||||
TRACEKMOD("### sc_iface_netdev_tx %d\n", smp_processor_id());
|
||||
|
||||
if (dev->flags & IFF_UP) {
|
||||
/* Ignore 802.1ad */
|
||||
if (skb->vlan_proto == htons(ETH_P_8021AD) || (eth_hdr(skb)->h_proto == htons(ETH_P_8021AD))) {
|
||||
goto drop;
|
||||
}
|
||||
|
||||
/* */
|
||||
spin_lock(&priv->lock);
|
||||
dev->stats.tx_packets++;
|
||||
dev->stats.tx_bytes += skb->len;
|
||||
spin_unlock(&priv->lock);
|
||||
|
||||
/* */
|
||||
CAPWAP_SKB_CB(skb)->flags = SKB_CAPWAP_FLAG_FROM_AC_TAP;
|
||||
sc_capwap_recvpacket(skb);
|
||||
} else {
|
||||
goto drop;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
drop:
|
||||
/* Drop packet */
|
||||
kfree_skb(skb);
|
||||
|
||||
/* */
|
||||
spin_lock(&priv->lock);
|
||||
dev->stats.rx_dropped++;
|
||||
spin_unlock(&priv->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
static int sc_iface_netdev_change_mtu(struct net_device* dev, int new_mtu) {
|
||||
TRACEKMOD("### sc_iface_netdev_change_mtu\n");
|
||||
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
static void sc_iface_netdev_setup(struct net_device* dev) {
|
||||
struct sc_netdev_priv* devpriv = (struct sc_netdev_priv*)netdev_priv(dev);
|
||||
|
||||
TRACEKMOD("### sc_iface_netdev_setup\n");
|
||||
|
||||
/* */
|
||||
memset(devpriv, 0, sizeof(struct sc_netdev_priv));
|
||||
devpriv->dev = dev;
|
||||
spin_lock_init(&devpriv->lock);
|
||||
INIT_LIST_HEAD(&devpriv->list_stations);
|
||||
INIT_LIST_HEAD(&devpriv->list_connections);
|
||||
}
|
||||
|
||||
/* */
|
||||
static const struct net_device_ops capwap_netdev_ops = {
|
||||
.ndo_uninit = sc_iface_netdev_uninit,
|
||||
.ndo_open = sc_iface_netdev_open,
|
||||
.ndo_stop = sc_iface_netdev_stop,
|
||||
.ndo_start_xmit = sc_iface_netdev_tx,
|
||||
.ndo_change_mtu = sc_iface_netdev_change_mtu,
|
||||
};
|
||||
|
||||
/* */
|
||||
int sc_iface_create(const char* ifname, uint16_t mtu) {
|
||||
int err;
|
||||
int hash;
|
||||
struct net_device* dev;
|
||||
struct sc_netdev_priv* priv;
|
||||
|
||||
TRACEKMOD("### sc_iface_create\n");
|
||||
|
||||
/* Create interface */
|
||||
dev = alloc_netdev(sizeof(struct sc_netdev_priv), ifname, sc_iface_netdev_setup);
|
||||
if (!dev) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* */
|
||||
priv = (struct sc_netdev_priv*)netdev_priv(dev);
|
||||
dev->netdev_ops = &capwap_netdev_ops;
|
||||
ether_setup(dev);
|
||||
|
||||
eth_hw_addr_random(dev);
|
||||
|
||||
dev->mtu = mtu;
|
||||
|
||||
dev->hw_features = NETIF_F_HW_CSUM;
|
||||
dev->features = dev->hw_features;
|
||||
|
||||
/* */
|
||||
err = register_netdev(dev);
|
||||
if (err) {
|
||||
free_netdev(dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* */
|
||||
hash = CAPWAP_IFACE_HASH(dev->ifindex);
|
||||
|
||||
/* */
|
||||
sc_capwap_update_lock();
|
||||
|
||||
list_add_rcu(&priv->list, &sc_iface_list);
|
||||
|
||||
priv->next = rcu_dereference_protected(sc_iface_hash[hash], sc_capwap_update_lock_is_locked());
|
||||
rcu_assign_pointer(sc_iface_hash[hash], priv);
|
||||
dev_hold(dev);
|
||||
|
||||
sc_capwap_update_unlock();
|
||||
|
||||
/* Enable carrier */
|
||||
netif_tx_lock_bh(dev);
|
||||
netif_carrier_on(dev);
|
||||
netif_tx_unlock_bh(dev);
|
||||
|
||||
return dev->ifindex;
|
||||
}
|
||||
|
||||
/* */
|
||||
int sc_iface_delete(uint32_t ifindex) {
|
||||
struct sc_netdev_priv* priv;
|
||||
struct net_device* dev = NULL;
|
||||
|
||||
TRACEKMOD("### sc_iface_delete\n");
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
/* Search device */
|
||||
priv = sc_iface_search(ifindex);
|
||||
if (priv) {
|
||||
dev = priv->dev;
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
/* */
|
||||
if (!dev) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/* Unregister device */
|
||||
unregister_netdev(dev);
|
||||
free_netdev(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
struct sc_netdev_priv* sc_iface_search(uint32_t ifindex) {
|
||||
struct sc_netdev_priv* priv;
|
||||
|
||||
TRACEKMOD("### sc_iface_search\n");
|
||||
|
||||
priv = rcu_dereference_check(sc_iface_hash[CAPWAP_IFACE_HASH(ifindex)], lockdep_is_held(&sc_iface_mutex));
|
||||
while (priv) {
|
||||
if (priv->dev->ifindex == ifindex) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* */
|
||||
priv = rcu_dereference_check(priv->next, lockdep_is_held(&sc_iface_mutex));
|
||||
}
|
||||
|
||||
return priv;
|
||||
}
|
||||
|
||||
/* */
|
||||
void sc_iface_closeall(void) {
|
||||
struct sc_netdev_priv* priv;
|
||||
|
||||
TRACEKMOD("### sc_iface_closeall\n");
|
||||
|
||||
for (;;) {
|
||||
struct net_device* dev = NULL;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
/* Get device */
|
||||
priv = list_first_or_null_rcu(&sc_iface_list, struct sc_netdev_priv, list);
|
||||
if (priv) {
|
||||
dev = priv->dev;
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
/* */
|
||||
if (!dev) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Unregister device */
|
||||
unregister_netdev(dev);
|
||||
free_netdev(dev);
|
||||
}
|
||||
}
|
||||
#include "config.h"
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/smp.h>
|
||||
#include "iface.h"
|
||||
#include "station.h"
|
||||
#include "capwap.h"
|
||||
|
||||
/* */
|
||||
#define CAPWAP_IFACE_COUNT 8
|
||||
#define CAPWAP_IFACE_HASH(x) ((x) % CAPWAP_IFACE_COUNT)
|
||||
|
||||
static LIST_HEAD(sc_iface_list);
|
||||
static struct sc_netdev_priv* __rcu sc_iface_hash[CAPWAP_IFACE_COUNT];
|
||||
|
||||
/* */
|
||||
static void sc_iface_netdev_uninit(struct net_device* dev) {
|
||||
struct sc_netdev_priv* search;
|
||||
struct sc_capwap_station* temp;
|
||||
struct sc_capwap_station* station;
|
||||
int hash = CAPWAP_IFACE_HASH(dev->ifindex);
|
||||
struct sc_netdev_priv* priv = (struct sc_netdev_priv*)netdev_priv(dev);
|
||||
|
||||
TRACEKMOD("### sc_iface_netdev_uninit\n");
|
||||
|
||||
sc_capwap_update_lock();
|
||||
|
||||
/* Close stations */
|
||||
list_for_each_entry_safe(station, temp, &priv->list_stations, list_dev) {
|
||||
sc_stations_releaseconnection(station);
|
||||
sc_stations_free(station);
|
||||
}
|
||||
|
||||
/* */
|
||||
if (!list_empty(&priv->list_stations)) {
|
||||
TRACEKMOD("*** Bug: the list stations of interface is not empty\n");
|
||||
}
|
||||
|
||||
if (!list_empty(&priv->list_connections)) {
|
||||
TRACEKMOD("*** Bug: the list connections of interface is not empty\n");
|
||||
}
|
||||
|
||||
/* Remove interface from hash */
|
||||
search = rcu_dereference_protected(sc_iface_hash[hash], sc_capwap_update_lock_is_locked());
|
||||
if (search) {
|
||||
if (priv == search) {
|
||||
netif_tx_lock_bh(dev);
|
||||
netif_carrier_off(dev);
|
||||
netif_tx_unlock_bh(dev);
|
||||
|
||||
rcu_assign_pointer(sc_iface_hash[hash], priv->next);
|
||||
|
||||
list_del_rcu(&priv->list);
|
||||
synchronize_net();
|
||||
|
||||
dev_put(dev);
|
||||
} else {
|
||||
while (rcu_access_pointer(search->next) && (rcu_access_pointer(search->next) != priv)) {
|
||||
search = rcu_dereference_protected(search->next, sc_capwap_update_lock_is_locked());
|
||||
}
|
||||
|
||||
if (rcu_access_pointer(search->next)) {
|
||||
netif_tx_lock_bh(dev);
|
||||
netif_carrier_off(dev);
|
||||
netif_tx_unlock_bh(dev);
|
||||
|
||||
rcu_assign_pointer(search->next, priv->next);
|
||||
|
||||
list_del_rcu(&priv->list);
|
||||
synchronize_net();
|
||||
|
||||
dev_put(dev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sc_capwap_update_unlock();
|
||||
}
|
||||
|
||||
/* */
|
||||
static int sc_iface_netdev_open(struct net_device* dev) {
|
||||
TRACEKMOD("### sc_iface_netdev_open\n");
|
||||
|
||||
netif_start_queue(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
static int sc_iface_netdev_stop(struct net_device* dev) {
|
||||
TRACEKMOD("### sc_iface_netdev_stop\n");
|
||||
|
||||
netif_stop_queue(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
static int sc_iface_netdev_tx(struct sk_buff* skb, struct net_device* dev) {
|
||||
struct sc_netdev_priv* priv = (struct sc_netdev_priv*)netdev_priv(dev);
|
||||
|
||||
TRACEKMOD("### sc_iface_netdev_tx %d\n", smp_processor_id());
|
||||
|
||||
if (dev->flags & IFF_UP) {
|
||||
/* Ignore 802.1ad */
|
||||
if (skb->vlan_proto == htons(ETH_P_8021AD) || (eth_hdr(skb)->h_proto == htons(ETH_P_8021AD))) {
|
||||
goto drop;
|
||||
}
|
||||
|
||||
/* */
|
||||
spin_lock(&priv->lock);
|
||||
dev->stats.tx_packets++;
|
||||
dev->stats.tx_bytes += skb->len;
|
||||
spin_unlock(&priv->lock);
|
||||
|
||||
/* */
|
||||
CAPWAP_SKB_CB(skb)->flags = SKB_CAPWAP_FLAG_FROM_AC_TAP;
|
||||
sc_capwap_recvpacket(skb);
|
||||
} else {
|
||||
goto drop;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
drop:
|
||||
/* Drop packet */
|
||||
kfree_skb(skb);
|
||||
|
||||
/* */
|
||||
spin_lock(&priv->lock);
|
||||
dev->stats.rx_dropped++;
|
||||
spin_unlock(&priv->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
static int sc_iface_netdev_change_mtu(struct net_device* dev, int new_mtu) {
|
||||
TRACEKMOD("### sc_iface_netdev_change_mtu\n");
|
||||
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
static void sc_iface_netdev_setup(struct net_device* dev) {
|
||||
struct sc_netdev_priv* devpriv = (struct sc_netdev_priv*)netdev_priv(dev);
|
||||
|
||||
TRACEKMOD("### sc_iface_netdev_setup\n");
|
||||
|
||||
/* */
|
||||
memset(devpriv, 0, sizeof(struct sc_netdev_priv));
|
||||
devpriv->dev = dev;
|
||||
spin_lock_init(&devpriv->lock);
|
||||
INIT_LIST_HEAD(&devpriv->list_stations);
|
||||
INIT_LIST_HEAD(&devpriv->list_connections);
|
||||
}
|
||||
|
||||
/* */
|
||||
static const struct net_device_ops capwap_netdev_ops = {
|
||||
.ndo_uninit = sc_iface_netdev_uninit,
|
||||
.ndo_open = sc_iface_netdev_open,
|
||||
.ndo_stop = sc_iface_netdev_stop,
|
||||
.ndo_start_xmit = sc_iface_netdev_tx,
|
||||
.ndo_change_mtu = sc_iface_netdev_change_mtu,
|
||||
};
|
||||
|
||||
/* */
|
||||
int sc_iface_create(const char* ifname, uint16_t mtu) {
|
||||
int err;
|
||||
int hash;
|
||||
struct net_device* dev;
|
||||
struct sc_netdev_priv* priv;
|
||||
|
||||
TRACEKMOD("### sc_iface_create\n");
|
||||
|
||||
/* Create interface */
|
||||
dev = alloc_netdev(sizeof(struct sc_netdev_priv), ifname, sc_iface_netdev_setup);
|
||||
if (!dev) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* */
|
||||
priv = (struct sc_netdev_priv*)netdev_priv(dev);
|
||||
dev->netdev_ops = &capwap_netdev_ops;
|
||||
ether_setup(dev);
|
||||
|
||||
eth_hw_addr_random(dev);
|
||||
|
||||
dev->mtu = mtu;
|
||||
|
||||
dev->hw_features = NETIF_F_HW_CSUM;
|
||||
dev->features = dev->hw_features;
|
||||
|
||||
/* */
|
||||
err = register_netdev(dev);
|
||||
if (err) {
|
||||
free_netdev(dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* */
|
||||
hash = CAPWAP_IFACE_HASH(dev->ifindex);
|
||||
|
||||
/* */
|
||||
sc_capwap_update_lock();
|
||||
|
||||
list_add_rcu(&priv->list, &sc_iface_list);
|
||||
|
||||
priv->next = rcu_dereference_protected(sc_iface_hash[hash], sc_capwap_update_lock_is_locked());
|
||||
rcu_assign_pointer(sc_iface_hash[hash], priv);
|
||||
dev_hold(dev);
|
||||
|
||||
sc_capwap_update_unlock();
|
||||
|
||||
/* Enable carrier */
|
||||
netif_tx_lock_bh(dev);
|
||||
netif_carrier_on(dev);
|
||||
netif_tx_unlock_bh(dev);
|
||||
|
||||
return dev->ifindex;
|
||||
}
|
||||
|
||||
/* */
|
||||
int sc_iface_delete(uint32_t ifindex) {
|
||||
struct sc_netdev_priv* priv;
|
||||
struct net_device* dev = NULL;
|
||||
|
||||
TRACEKMOD("### sc_iface_delete\n");
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
/* Search device */
|
||||
priv = sc_iface_search(ifindex);
|
||||
if (priv) {
|
||||
dev = priv->dev;
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
/* */
|
||||
if (!dev) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/* Unregister device */
|
||||
unregister_netdev(dev);
|
||||
free_netdev(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
struct sc_netdev_priv* sc_iface_search(uint32_t ifindex) {
|
||||
struct sc_netdev_priv* priv;
|
||||
|
||||
TRACEKMOD("### sc_iface_search\n");
|
||||
|
||||
priv = rcu_dereference_check(sc_iface_hash[CAPWAP_IFACE_HASH(ifindex)], lockdep_is_held(&sc_iface_mutex));
|
||||
while (priv) {
|
||||
if (priv->dev->ifindex == ifindex) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* */
|
||||
priv = rcu_dereference_check(priv->next, lockdep_is_held(&sc_iface_mutex));
|
||||
}
|
||||
|
||||
return priv;
|
||||
}
|
||||
|
||||
/* */
|
||||
void sc_iface_closeall(void) {
|
||||
struct sc_netdev_priv* priv;
|
||||
|
||||
TRACEKMOD("### sc_iface_closeall\n");
|
||||
|
||||
for (;;) {
|
||||
struct net_device* dev = NULL;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
/* Get device */
|
||||
priv = list_first_or_null_rcu(&sc_iface_list, struct sc_netdev_priv, list);
|
||||
if (priv) {
|
||||
dev = priv->dev;
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
/* */
|
||||
if (!dev) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Unregister device */
|
||||
unregister_netdev(dev);
|
||||
free_netdev(dev);
|
||||
}
|
||||
}
|
||||
|
@ -1,27 +1,27 @@
|
||||
#ifndef __KMOD_AC_IFACE_HEADER__
|
||||
#define __KMOD_AC_IFACE_HEADER__
|
||||
|
||||
/* */
|
||||
struct sc_netdev_priv {
|
||||
struct list_head list;
|
||||
struct net_device* dev;
|
||||
|
||||
spinlock_t lock;
|
||||
|
||||
struct list_head list_stations;
|
||||
struct list_head list_connections;
|
||||
|
||||
struct sc_netdev_priv* __rcu next;
|
||||
};
|
||||
|
||||
/* */
|
||||
int sc_iface_create(const char* ifname, uint16_t mtu);
|
||||
int sc_iface_delete(uint32_t ifindex);
|
||||
|
||||
/* */
|
||||
struct sc_netdev_priv* sc_iface_search(uint32_t ifindex);
|
||||
|
||||
/* */
|
||||
void sc_iface_closeall(void);
|
||||
|
||||
#endif /* __KMOD_AC_IFACE_HEADER__ */
|
||||
#ifndef __KMOD_AC_IFACE_HEADER__
|
||||
#define __KMOD_AC_IFACE_HEADER__
|
||||
|
||||
/* */
|
||||
struct sc_netdev_priv {
|
||||
struct list_head list;
|
||||
struct net_device* dev;
|
||||
|
||||
spinlock_t lock;
|
||||
|
||||
struct list_head list_stations;
|
||||
struct list_head list_connections;
|
||||
|
||||
struct sc_netdev_priv* __rcu next;
|
||||
};
|
||||
|
||||
/* */
|
||||
int sc_iface_create(const char* ifname, uint16_t mtu);
|
||||
int sc_iface_delete(uint32_t ifindex);
|
||||
|
||||
/* */
|
||||
struct sc_netdev_priv* sc_iface_search(uint32_t ifindex);
|
||||
|
||||
/* */
|
||||
void sc_iface_closeall(void);
|
||||
|
||||
#endif /* __KMOD_AC_IFACE_HEADER__ */
|
||||
|
@ -1,32 +1,32 @@
|
||||
#include "config.h"
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include "netlinkapp.h"
|
||||
|
||||
/* */
|
||||
static int __init smartcapwap_ac_init(void) {
|
||||
int ret;
|
||||
|
||||
TRACEKMOD("### smartcapwap_ac_init\n");
|
||||
|
||||
/* Initialize netlink */
|
||||
ret = sc_netlink_init();
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
module_init(smartcapwap_ac_init);
|
||||
|
||||
/* */
|
||||
static void __exit smartcapwap_ac_exit(void) {
|
||||
TRACEKMOD("### smartcapwap_ac_exit\n");
|
||||
|
||||
sc_netlink_exit();
|
||||
}
|
||||
module_exit(smartcapwap_ac_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Massimo Vellucci <vemax78@gmail.com>");
|
||||
MODULE_DESCRIPTION("SmartCAPWAP AC Data Channel Module");
|
||||
#include "config.h"
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include "netlinkapp.h"
|
||||
|
||||
/* */
|
||||
static int __init smartcapwap_ac_init(void) {
|
||||
int ret;
|
||||
|
||||
TRACEKMOD("### smartcapwap_ac_init\n");
|
||||
|
||||
/* Initialize netlink */
|
||||
ret = sc_netlink_init();
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
module_init(smartcapwap_ac_init);
|
||||
|
||||
/* */
|
||||
static void __exit smartcapwap_ac_exit(void) {
|
||||
TRACEKMOD("### smartcapwap_ac_exit\n");
|
||||
|
||||
sc_netlink_exit();
|
||||
}
|
||||
module_exit(smartcapwap_ac_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Massimo Vellucci <vemax78@gmail.com>");
|
||||
MODULE_DESCRIPTION("SmartCAPWAP AC Data Channel Module");
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,15 +1,15 @@
|
||||
#ifndef __KMOD_AC_NETLINKAPP_HEADER__
|
||||
#define __KMOD_AC_NETLINKAPP_HEADER__
|
||||
|
||||
#include "capwap_rfc.h"
|
||||
#include "socket.h"
|
||||
|
||||
/* */
|
||||
int sc_netlink_init(void);
|
||||
void sc_netlink_exit(void);
|
||||
|
||||
/* */
|
||||
int sc_netlink_notify_recv_keepalive(const union capwap_addr* sockaddr, struct sc_capwap_sessionid_element* sessionid);
|
||||
int sc_netlink_notify_recv_data(struct sc_capwap_sessionid_element* sessionid, uint8_t* packet, int length);
|
||||
|
||||
#endif /* __KMOD_AC_NETLINKAPP_HEADER__ */
|
||||
#ifndef __KMOD_AC_NETLINKAPP_HEADER__
|
||||
#define __KMOD_AC_NETLINKAPP_HEADER__
|
||||
|
||||
#include "capwap_rfc.h"
|
||||
#include "socket.h"
|
||||
|
||||
/* */
|
||||
int sc_netlink_init(void);
|
||||
void sc_netlink_exit(void);
|
||||
|
||||
/* */
|
||||
int sc_netlink_notify_recv_keepalive(const union capwap_addr* sockaddr, struct sc_capwap_sessionid_element* sessionid);
|
||||
int sc_netlink_notify_recv_data(struct sc_capwap_sessionid_element* sessionid, uint8_t* packet, int length);
|
||||
|
||||
#endif /* __KMOD_AC_NETLINKAPP_HEADER__ */
|
||||
|
@ -1,73 +1,73 @@
|
||||
#ifndef __AC_NLSMARTCAPWAP_HEADER__
|
||||
#define __AC_NLSMARTCAPWAP_HEADER__
|
||||
|
||||
/* */
|
||||
#define NLSMARTCAPWAP_GENL_NAME "smartcapwap_ac"
|
||||
|
||||
/* */
|
||||
#define NLSMARTCAPWAP_FLAGS_TUNNEL_8023 0x00000001
|
||||
|
||||
/* */
|
||||
enum sc_netlink_attrs {
|
||||
NLSMARTCAPWAP_ATTR_UNSPEC,
|
||||
|
||||
NLSMARTCAPWAP_ATTR_FLAGS,
|
||||
|
||||
NLSMARTCAPWAP_ATTR_SESSION_ID,
|
||||
|
||||
NLSMARTCAPWAP_ATTR_RADIOID,
|
||||
NLSMARTCAPWAP_ATTR_WLANID,
|
||||
NLSMARTCAPWAP_ATTR_BINDING,
|
||||
NLSMARTCAPWAP_ATTR_MACMODE,
|
||||
NLSMARTCAPWAP_ATTR_TUNNELMODE,
|
||||
|
||||
NLSMARTCAPWAP_ATTR_ADDRESS,
|
||||
NLSMARTCAPWAP_ATTR_MTU,
|
||||
|
||||
NLSMARTCAPWAP_ATTR_DATA_FRAME,
|
||||
|
||||
NLSMARTCAPWAP_ATTR_IFPHY_NAME,
|
||||
NLSMARTCAPWAP_ATTR_IFPHY_INDEX,
|
||||
|
||||
NLSMARTCAPWAP_ATTR_MACADDRESS,
|
||||
NLSMARTCAPWAP_ATTR_BSSID,
|
||||
|
||||
NLSMARTCAPWAP_ATTR_VLAN,
|
||||
|
||||
/* Last attribute */
|
||||
__NLSMARTCAPWAP_ATTR_AFTER_LAST,
|
||||
NLSMARTCAPWAP_ATTR_MAX = __NLSMARTCAPWAP_ATTR_AFTER_LAST - 1
|
||||
};
|
||||
|
||||
/* */
|
||||
enum sc_netlink_commands {
|
||||
NLSMARTCAPWAP_CMD_UNSPEC,
|
||||
|
||||
NLSMARTCAPWAP_CMD_LINK,
|
||||
|
||||
NLSMARTCAPWAP_CMD_ADD_IFACE,
|
||||
NLSMARTCAPWAP_CMD_DELETE_IFACE,
|
||||
|
||||
NLSMARTCAPWAP_CMD_BIND,
|
||||
|
||||
NLSMARTCAPWAP_CMD_SEND_KEEPALIVE,
|
||||
NLSMARTCAPWAP_CMD_RECV_KEEPALIVE,
|
||||
|
||||
NLSMARTCAPWAP_CMD_NEW_SESSION,
|
||||
NLSMARTCAPWAP_CMD_DELETE_SESSION,
|
||||
|
||||
NLSMARTCAPWAP_CMD_ADD_WLAN,
|
||||
NLSMARTCAPWAP_CMD_REMOVE_WLAN,
|
||||
|
||||
NLSMARTCAPWAP_CMD_SEND_DATA,
|
||||
NLSMARTCAPWAP_CMD_RECV_DATA,
|
||||
|
||||
NLSMARTCAPWAP_CMD_AUTH_STATION,
|
||||
NLSMARTCAPWAP_CMD_DEAUTH_STATION,
|
||||
|
||||
/* Last command */
|
||||
__NLSMARTCAPWAP_CMD_AFTER_LAST,
|
||||
NLSMARTCAPWAP_CMD_MAX = __NLSMARTCAPWAP_CMD_AFTER_LAST - 1
|
||||
};
|
||||
|
||||
#endif /* __AC_NLSMARTCAPWAP_HEADER__ */
|
||||
#ifndef __AC_NLSMARTCAPWAP_HEADER__
|
||||
#define __AC_NLSMARTCAPWAP_HEADER__
|
||||
|
||||
/* */
|
||||
#define NLSMARTCAPWAP_GENL_NAME "smartcapwap_ac"
|
||||
|
||||
/* */
|
||||
#define NLSMARTCAPWAP_FLAGS_TUNNEL_8023 0x00000001
|
||||
|
||||
/* */
|
||||
enum sc_netlink_attrs {
|
||||
NLSMARTCAPWAP_ATTR_UNSPEC,
|
||||
|
||||
NLSMARTCAPWAP_ATTR_FLAGS,
|
||||
|
||||
NLSMARTCAPWAP_ATTR_SESSION_ID,
|
||||
|
||||
NLSMARTCAPWAP_ATTR_RADIOID,
|
||||
NLSMARTCAPWAP_ATTR_WLANID,
|
||||
NLSMARTCAPWAP_ATTR_BINDING,
|
||||
NLSMARTCAPWAP_ATTR_MACMODE,
|
||||
NLSMARTCAPWAP_ATTR_TUNNELMODE,
|
||||
|
||||
NLSMARTCAPWAP_ATTR_ADDRESS,
|
||||
NLSMARTCAPWAP_ATTR_MTU,
|
||||
|
||||
NLSMARTCAPWAP_ATTR_DATA_FRAME,
|
||||
|
||||
NLSMARTCAPWAP_ATTR_IFPHY_NAME,
|
||||
NLSMARTCAPWAP_ATTR_IFPHY_INDEX,
|
||||
|
||||
NLSMARTCAPWAP_ATTR_MACADDRESS,
|
||||
NLSMARTCAPWAP_ATTR_BSSID,
|
||||
|
||||
NLSMARTCAPWAP_ATTR_VLAN,
|
||||
|
||||
/* Last attribute */
|
||||
__NLSMARTCAPWAP_ATTR_AFTER_LAST,
|
||||
NLSMARTCAPWAP_ATTR_MAX = __NLSMARTCAPWAP_ATTR_AFTER_LAST - 1
|
||||
};
|
||||
|
||||
/* */
|
||||
enum sc_netlink_commands {
|
||||
NLSMARTCAPWAP_CMD_UNSPEC,
|
||||
|
||||
NLSMARTCAPWAP_CMD_LINK,
|
||||
|
||||
NLSMARTCAPWAP_CMD_ADD_IFACE,
|
||||
NLSMARTCAPWAP_CMD_DELETE_IFACE,
|
||||
|
||||
NLSMARTCAPWAP_CMD_BIND,
|
||||
|
||||
NLSMARTCAPWAP_CMD_SEND_KEEPALIVE,
|
||||
NLSMARTCAPWAP_CMD_RECV_KEEPALIVE,
|
||||
|
||||
NLSMARTCAPWAP_CMD_NEW_SESSION,
|
||||
NLSMARTCAPWAP_CMD_DELETE_SESSION,
|
||||
|
||||
NLSMARTCAPWAP_CMD_ADD_WLAN,
|
||||
NLSMARTCAPWAP_CMD_REMOVE_WLAN,
|
||||
|
||||
NLSMARTCAPWAP_CMD_SEND_DATA,
|
||||
NLSMARTCAPWAP_CMD_RECV_DATA,
|
||||
|
||||
NLSMARTCAPWAP_CMD_AUTH_STATION,
|
||||
NLSMARTCAPWAP_CMD_DEAUTH_STATION,
|
||||
|
||||
/* Last command */
|
||||
__NLSMARTCAPWAP_CMD_AFTER_LAST,
|
||||
NLSMARTCAPWAP_CMD_MAX = __NLSMARTCAPWAP_CMD_AFTER_LAST - 1
|
||||
};
|
||||
|
||||
#endif /* __AC_NLSMARTCAPWAP_HEADER__ */
|
||||
|
@ -1,227 +1,227 @@
|
||||
#include "config.h"
|
||||
#include <linux/module.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/udp.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/udp.h>
|
||||
#include "socket.h"
|
||||
#include "capwap.h"
|
||||
|
||||
/* Socket */
|
||||
#define SOCKET_COUNT 2
|
||||
static struct socket* sc_sockets[SOCKET_COUNT];
|
||||
|
||||
/* */
|
||||
int sc_socket_recvpacket(struct sock* sk, struct sk_buff* skb) {
|
||||
TRACEKMOD("### sc_socket_recvpacket\n");
|
||||
|
||||
/* */
|
||||
CAPWAP_SKB_CB(skb)->flags = SKB_CAPWAP_FLAG_FROM_DATA_CHANNEL;
|
||||
|
||||
/* */
|
||||
sc_capwap_recvpacket(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
static int sc_socket_create(int type, union capwap_addr* sockaddr, uint16_t protocol) {
|
||||
int ret;
|
||||
|
||||
TRACEKMOD("### sc_socket_create\n");
|
||||
|
||||
/* Create socket */
|
||||
ret = sock_create_kern(sockaddr->ss.ss_family, SOCK_DGRAM, protocol, &sc_sockets[type]);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Bind to interface */
|
||||
ret = kernel_bind(sc_sockets[type], &sockaddr->sa, sizeof(union capwap_addr));
|
||||
if (ret) {
|
||||
goto failure;
|
||||
}
|
||||
|
||||
/* Set callback */
|
||||
udp_sk(sc_sockets[type]->sk)->encap_type = 1;
|
||||
udp_sk(sc_sockets[type]->sk)->encap_rcv = sc_socket_recvpacket;
|
||||
|
||||
/* */
|
||||
if (!((sockaddr->ss.ss_family == AF_INET) ? sockaddr->sin.sin_port : sockaddr->sin6.sin6_port)) {
|
||||
union capwap_addr localaddr;
|
||||
int localaddrsize = sizeof(union capwap_addr);
|
||||
|
||||
/* Retrieve port */
|
||||
ret = kernel_getsockname(sc_sockets[type], &localaddr.sa, &localaddrsize);
|
||||
if (ret) {
|
||||
goto failure;
|
||||
}
|
||||
|
||||
/* */
|
||||
if ((sockaddr->ss.ss_family == AF_INET) && (localaddr.ss.ss_family == AF_INET)) {
|
||||
sockaddr->sin.sin_port = localaddr.sin.sin_port;
|
||||
} else if ((sockaddr->ss.ss_family == AF_INET6) && (localaddr.ss.ss_family == AF_INET6)) {
|
||||
sockaddr->sin6.sin6_port = localaddr.sin6.sin6_port;
|
||||
} else {
|
||||
ret = -EFAULT;
|
||||
goto failure;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
failure:
|
||||
sock_release(sc_sockets[type]);
|
||||
sc_sockets[type] = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* */
|
||||
int sc_socket_getpeeraddr(struct sk_buff* skb, union capwap_addr* peeraddr) {
|
||||
unsigned char* nethdr;
|
||||
|
||||
TRACEKMOD("### sc_socket_getpeeraddr\n");
|
||||
|
||||
/* */
|
||||
nethdr = skb_network_header(skb);
|
||||
if (!nethdr) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* */
|
||||
switch (ntohs(skb->protocol)) {
|
||||
case ETH_P_IP: {
|
||||
/* Validate IPv4 header */
|
||||
if ((nethdr[0] & 0xf0) != 0x40) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Retrieve address */
|
||||
peeraddr->sin.sin_family = AF_INET;
|
||||
peeraddr->sin.sin_addr.s_addr = ((struct iphdr*)nethdr)->saddr;
|
||||
peeraddr->sin.sin_port = udp_hdr(skb)->source;
|
||||
break;
|
||||
}
|
||||
|
||||
case ETH_P_IPV6: {
|
||||
/* Validate IPv6 header */
|
||||
if ((nethdr[0] & 0xf0) != 0x60) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Retrieve address */
|
||||
peeraddr->sin6.sin6_family = AF_INET6;
|
||||
memcpy(&peeraddr->sin6.sin6_addr, &((struct ipv6hdr*)nethdr)->saddr, sizeof(struct in6_addr));
|
||||
peeraddr->sin6.sin6_port = udp_hdr(skb)->source;
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
int sc_socket_send(int type, uint8_t* buffer, int length, union capwap_addr* sockaddr) {
|
||||
struct kvec vec;
|
||||
struct msghdr msg;
|
||||
|
||||
TRACEKMOD("### sc_socket_send\n");
|
||||
|
||||
/* */
|
||||
vec.iov_base = buffer;
|
||||
vec.iov_len = length;
|
||||
|
||||
/* */
|
||||
memset(&msg, 0, sizeof(struct msghdr));
|
||||
msg.msg_name = sockaddr;
|
||||
msg.msg_namelen = sizeof(union capwap_addr);
|
||||
msg.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT;
|
||||
|
||||
/* */
|
||||
return kernel_sendmsg(sc_sockets[type], &msg, &vec, 1, length);
|
||||
}
|
||||
|
||||
/* */
|
||||
int sc_socket_init(void) {
|
||||
TRACEKMOD("### sc_socket_init\n");
|
||||
|
||||
memset(sc_sockets, 0, sizeof(sc_sockets));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
int sc_socket_bind(union capwap_addr* sockaddr) {
|
||||
int ret;
|
||||
|
||||
TRACEKMOD("### sc_socket_bind\n");
|
||||
|
||||
/* */
|
||||
if (sc_sockets[SOCKET_UDP] || sc_sockets[SOCKET_UDPLITE]) {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* UDP socket */
|
||||
ret = sc_socket_create(SOCKET_UDP, sockaddr, IPPROTO_UDP);
|
||||
if (ret) {
|
||||
goto failure;
|
||||
}
|
||||
|
||||
/* UDPLite socket */
|
||||
ret = sc_socket_create(SOCKET_UDPLITE, sockaddr, IPPROTO_UDPLITE);
|
||||
if (ret) {
|
||||
goto failure;
|
||||
}
|
||||
|
||||
/* */
|
||||
udp_encap_enable();
|
||||
if (sockaddr->ss.ss_family == AF_INET6) {
|
||||
udpv6_encap_enable();
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
failure:
|
||||
sc_socket_close();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* */
|
||||
void sc_socket_close(void) {
|
||||
TRACEKMOD("### sc_socket_close\n");
|
||||
|
||||
/* Close sockets */
|
||||
if (sc_sockets[SOCKET_UDP]) {
|
||||
kernel_sock_shutdown(sc_sockets[SOCKET_UDP], SHUT_RDWR);
|
||||
sock_release(sc_sockets[SOCKET_UDP]);
|
||||
}
|
||||
|
||||
if (sc_sockets[SOCKET_UDPLITE]) {
|
||||
kernel_sock_shutdown(sc_sockets[SOCKET_UDPLITE], SHUT_RDWR);
|
||||
sock_release(sc_sockets[SOCKET_UDPLITE]);
|
||||
}
|
||||
|
||||
memset(sc_sockets, 0, sizeof(sc_sockets));
|
||||
}
|
||||
|
||||
/* */
|
||||
int sc_addr_compare(const union capwap_addr* addr1, const union capwap_addr* addr2) {
|
||||
TRACEKMOD("### sc_addr_compare\n");
|
||||
|
||||
if (addr1->ss.ss_family == addr2->ss.ss_family) {
|
||||
if (addr1->ss.ss_family == AF_INET) {
|
||||
return (((addr1->sin.sin_addr.s_addr == addr2->sin.sin_addr.s_addr) && (addr1->sin.sin_port == addr2->sin.sin_port)) ? 0 : -1);
|
||||
} else if (addr1->ss.ss_family == AF_INET6) {
|
||||
return ((!memcmp(&addr1->sin6.sin6_addr, &addr2->sin6.sin6_addr, sizeof(struct in6_addr)) && (addr1->sin6.sin6_port == addr2->sin6.sin6_port)) ? 0 : -1);
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
#include "config.h"
|
||||
#include <linux/module.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/udp.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/udp.h>
|
||||
#include "socket.h"
|
||||
#include "capwap.h"
|
||||
|
||||
/* Socket */
|
||||
#define SOCKET_COUNT 2
|
||||
static struct socket* sc_sockets[SOCKET_COUNT];
|
||||
|
||||
/* */
|
||||
int sc_socket_recvpacket(struct sock* sk, struct sk_buff* skb) {
|
||||
TRACEKMOD("### sc_socket_recvpacket\n");
|
||||
|
||||
/* */
|
||||
CAPWAP_SKB_CB(skb)->flags = SKB_CAPWAP_FLAG_FROM_DATA_CHANNEL;
|
||||
|
||||
/* */
|
||||
sc_capwap_recvpacket(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
static int sc_socket_create(int type, union capwap_addr* sockaddr, uint16_t protocol) {
|
||||
int ret;
|
||||
|
||||
TRACEKMOD("### sc_socket_create\n");
|
||||
|
||||
/* Create socket */
|
||||
ret = sock_create_kern(sockaddr->ss.ss_family, SOCK_DGRAM, protocol, &sc_sockets[type]);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Bind to interface */
|
||||
ret = kernel_bind(sc_sockets[type], &sockaddr->sa, sizeof(union capwap_addr));
|
||||
if (ret) {
|
||||
goto failure;
|
||||
}
|
||||
|
||||
/* Set callback */
|
||||
udp_sk(sc_sockets[type]->sk)->encap_type = 1;
|
||||
udp_sk(sc_sockets[type]->sk)->encap_rcv = sc_socket_recvpacket;
|
||||
|
||||
/* */
|
||||
if (!((sockaddr->ss.ss_family == AF_INET) ? sockaddr->sin.sin_port : sockaddr->sin6.sin6_port)) {
|
||||
union capwap_addr localaddr;
|
||||
int localaddrsize = sizeof(union capwap_addr);
|
||||
|
||||
/* Retrieve port */
|
||||
ret = kernel_getsockname(sc_sockets[type], &localaddr.sa, &localaddrsize);
|
||||
if (ret) {
|
||||
goto failure;
|
||||
}
|
||||
|
||||
/* */
|
||||
if ((sockaddr->ss.ss_family == AF_INET) && (localaddr.ss.ss_family == AF_INET)) {
|
||||
sockaddr->sin.sin_port = localaddr.sin.sin_port;
|
||||
} else if ((sockaddr->ss.ss_family == AF_INET6) && (localaddr.ss.ss_family == AF_INET6)) {
|
||||
sockaddr->sin6.sin6_port = localaddr.sin6.sin6_port;
|
||||
} else {
|
||||
ret = -EFAULT;
|
||||
goto failure;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
failure:
|
||||
sock_release(sc_sockets[type]);
|
||||
sc_sockets[type] = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* */
|
||||
int sc_socket_getpeeraddr(struct sk_buff* skb, union capwap_addr* peeraddr) {
|
||||
unsigned char* nethdr;
|
||||
|
||||
TRACEKMOD("### sc_socket_getpeeraddr\n");
|
||||
|
||||
/* */
|
||||
nethdr = skb_network_header(skb);
|
||||
if (!nethdr) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* */
|
||||
switch (ntohs(skb->protocol)) {
|
||||
case ETH_P_IP: {
|
||||
/* Validate IPv4 header */
|
||||
if ((nethdr[0] & 0xf0) != 0x40) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Retrieve address */
|
||||
peeraddr->sin.sin_family = AF_INET;
|
||||
peeraddr->sin.sin_addr.s_addr = ((struct iphdr*)nethdr)->saddr;
|
||||
peeraddr->sin.sin_port = udp_hdr(skb)->source;
|
||||
break;
|
||||
}
|
||||
|
||||
case ETH_P_IPV6: {
|
||||
/* Validate IPv6 header */
|
||||
if ((nethdr[0] & 0xf0) != 0x60) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Retrieve address */
|
||||
peeraddr->sin6.sin6_family = AF_INET6;
|
||||
memcpy(&peeraddr->sin6.sin6_addr, &((struct ipv6hdr*)nethdr)->saddr, sizeof(struct in6_addr));
|
||||
peeraddr->sin6.sin6_port = udp_hdr(skb)->source;
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
int sc_socket_send(int type, uint8_t* buffer, int length, union capwap_addr* sockaddr) {
|
||||
struct kvec vec;
|
||||
struct msghdr msg;
|
||||
|
||||
TRACEKMOD("### sc_socket_send\n");
|
||||
|
||||
/* */
|
||||
vec.iov_base = buffer;
|
||||
vec.iov_len = length;
|
||||
|
||||
/* */
|
||||
memset(&msg, 0, sizeof(struct msghdr));
|
||||
msg.msg_name = sockaddr;
|
||||
msg.msg_namelen = sizeof(union capwap_addr);
|
||||
msg.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT;
|
||||
|
||||
/* */
|
||||
return kernel_sendmsg(sc_sockets[type], &msg, &vec, 1, length);
|
||||
}
|
||||
|
||||
/* */
|
||||
int sc_socket_init(void) {
|
||||
TRACEKMOD("### sc_socket_init\n");
|
||||
|
||||
memset(sc_sockets, 0, sizeof(sc_sockets));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
int sc_socket_bind(union capwap_addr* sockaddr) {
|
||||
int ret;
|
||||
|
||||
TRACEKMOD("### sc_socket_bind\n");
|
||||
|
||||
/* */
|
||||
if (sc_sockets[SOCKET_UDP] || sc_sockets[SOCKET_UDPLITE]) {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* UDP socket */
|
||||
ret = sc_socket_create(SOCKET_UDP, sockaddr, IPPROTO_UDP);
|
||||
if (ret) {
|
||||
goto failure;
|
||||
}
|
||||
|
||||
/* UDPLite socket */
|
||||
ret = sc_socket_create(SOCKET_UDPLITE, sockaddr, IPPROTO_UDPLITE);
|
||||
if (ret) {
|
||||
goto failure;
|
||||
}
|
||||
|
||||
/* */
|
||||
udp_encap_enable();
|
||||
if (sockaddr->ss.ss_family == AF_INET6) {
|
||||
udpv6_encap_enable();
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
failure:
|
||||
sc_socket_close();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* */
|
||||
void sc_socket_close(void) {
|
||||
TRACEKMOD("### sc_socket_close\n");
|
||||
|
||||
/* Close sockets */
|
||||
if (sc_sockets[SOCKET_UDP]) {
|
||||
kernel_sock_shutdown(sc_sockets[SOCKET_UDP], SHUT_RDWR);
|
||||
sock_release(sc_sockets[SOCKET_UDP]);
|
||||
}
|
||||
|
||||
if (sc_sockets[SOCKET_UDPLITE]) {
|
||||
kernel_sock_shutdown(sc_sockets[SOCKET_UDPLITE], SHUT_RDWR);
|
||||
sock_release(sc_sockets[SOCKET_UDPLITE]);
|
||||
}
|
||||
|
||||
memset(sc_sockets, 0, sizeof(sc_sockets));
|
||||
}
|
||||
|
||||
/* */
|
||||
int sc_addr_compare(const union capwap_addr* addr1, const union capwap_addr* addr2) {
|
||||
TRACEKMOD("### sc_addr_compare\n");
|
||||
|
||||
if (addr1->ss.ss_family == addr2->ss.ss_family) {
|
||||
if (addr1->ss.ss_family == AF_INET) {
|
||||
return (((addr1->sin.sin_addr.s_addr == addr2->sin.sin_addr.s_addr) && (addr1->sin.sin_port == addr2->sin.sin_port)) ? 0 : -1);
|
||||
} else if (addr1->ss.ss_family == AF_INET6) {
|
||||
return ((!memcmp(&addr1->sin6.sin6_addr, &addr2->sin6.sin6_addr, sizeof(struct in6_addr)) && (addr1->sin6.sin6_port == addr2->sin6.sin6_port)) ? 0 : -1);
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
@ -1,35 +1,35 @@
|
||||
#ifndef __KMOD_SOCKET_HEADER__
|
||||
#define __KMOD_SOCKET_HEADER__
|
||||
|
||||
#include <linux/socket.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/in6.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
/* */
|
||||
#define SOCKET_UDP 0
|
||||
#define SOCKET_UDPLITE 1
|
||||
|
||||
/* Universal socket address */
|
||||
union capwap_addr {
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_in sin;
|
||||
struct sockaddr_in6 sin6;
|
||||
struct sockaddr_storage ss;
|
||||
};
|
||||
|
||||
/* */
|
||||
int sc_socket_init(void);
|
||||
void sc_socket_close(void);
|
||||
|
||||
/* */
|
||||
int sc_socket_bind(union capwap_addr* sockaddr);
|
||||
int sc_socket_send(int type, uint8_t* buffer, int length, union capwap_addr* sockaddr);
|
||||
|
||||
/* */
|
||||
int sc_socket_getpeeraddr(struct sk_buff* skb, union capwap_addr* peeraddr);
|
||||
|
||||
/* */
|
||||
int sc_addr_compare(const union capwap_addr* addr1, const union capwap_addr* addr2);
|
||||
|
||||
#endif /* __KMOD_SOCKET_HEADER__ */
|
||||
#ifndef __KMOD_SOCKET_HEADER__
|
||||
#define __KMOD_SOCKET_HEADER__
|
||||
|
||||
#include <linux/socket.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/in6.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
/* */
|
||||
#define SOCKET_UDP 0
|
||||
#define SOCKET_UDPLITE 1
|
||||
|
||||
/* Universal socket address */
|
||||
union capwap_addr {
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_in sin;
|
||||
struct sockaddr_in6 sin6;
|
||||
struct sockaddr_storage ss;
|
||||
};
|
||||
|
||||
/* */
|
||||
int sc_socket_init(void);
|
||||
void sc_socket_close(void);
|
||||
|
||||
/* */
|
||||
int sc_socket_bind(union capwap_addr* sockaddr);
|
||||
int sc_socket_send(int type, uint8_t* buffer, int length, union capwap_addr* sockaddr);
|
||||
|
||||
/* */
|
||||
int sc_socket_getpeeraddr(struct sk_buff* skb, union capwap_addr* peeraddr);
|
||||
|
||||
/* */
|
||||
int sc_addr_compare(const union capwap_addr* addr1, const union capwap_addr* addr2);
|
||||
|
||||
#endif /* __KMOD_SOCKET_HEADER__ */
|
||||
|
@ -1,157 +1,157 @@
|
||||
#include "config.h"
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include "station.h"
|
||||
#include "capwap.h"
|
||||
#include "iface.h"
|
||||
|
||||
/* */
|
||||
#define STATION_HASH_SIZE 65536
|
||||
|
||||
/* */
|
||||
static LIST_HEAD(sc_station_list);
|
||||
static struct sc_capwap_station* __rcu sc_station_hash_addr[STATION_HASH_SIZE];
|
||||
|
||||
/* */
|
||||
static uint32_t sc_stations_hash_addr(const uint8_t* macaddress) {
|
||||
TRACEKMOD("### sc_stations_hash_addr\n");
|
||||
|
||||
return (((((uint32_t)macaddress[4] << 8) | (uint32_t)macaddress[5]) ^ ((uint32_t)macaddress[3] << 4)) % STATION_HASH_SIZE);
|
||||
}
|
||||
|
||||
/* */
|
||||
static struct sc_capwap_connection* sc_stations_searchconnection(struct sc_capwap_station* station) {
|
||||
struct sc_capwap_connection* connection;
|
||||
struct sc_capwap_session_priv* sessionpriv = rcu_access_pointer(station->sessionpriv);
|
||||
struct sc_netdev_priv* devpriv = rcu_access_pointer(station->devpriv);
|
||||
|
||||
TRACEKMOD("### sc_stations_searchconnection\n");
|
||||
|
||||
list_for_each_entry(connection, &sessionpriv->list_connections, list_session) {
|
||||
if ((connection->devpriv == devpriv) && (connection->radioid == station->radioid) && (connection->vlan == station->vlan)) {
|
||||
return connection;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* */
|
||||
void sc_stations_add(struct sc_capwap_station* station) {
|
||||
uint32_t hash;
|
||||
|
||||
TRACEKMOD("### sc_stations_add\n");
|
||||
|
||||
/* */
|
||||
list_add_rcu(&station->list, &sc_station_list);
|
||||
|
||||
hash = sc_stations_hash_addr(station->address);
|
||||
station->next_addr = rcu_dereference_protected(sc_station_hash_addr[hash], sc_capwap_update_lock_is_locked());
|
||||
rcu_assign_pointer(sc_station_hash_addr[hash], station);
|
||||
}
|
||||
|
||||
/* */
|
||||
struct sc_capwap_station* sc_stations_search(const uint8_t* macaddress) {
|
||||
struct sc_capwap_station* station;
|
||||
|
||||
TRACEKMOD("### sc_stations_search\n");
|
||||
|
||||
/* */
|
||||
station = rcu_dereference_check(sc_station_hash_addr[sc_stations_hash_addr(macaddress)], sc_capwap_update_lock_is_locked());
|
||||
while (station) {
|
||||
if (!memcmp(&station->address, macaddress, MACADDRESS_EUI48_LENGTH)) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* */
|
||||
station = rcu_dereference_check(station->next_addr, sc_capwap_update_lock_is_locked());
|
||||
}
|
||||
|
||||
return station;
|
||||
}
|
||||
|
||||
/* */
|
||||
void sc_stations_free(struct sc_capwap_station* station) {
|
||||
uint32_t hash;
|
||||
struct sc_capwap_station* search;
|
||||
|
||||
TRACEKMOD("### sc_stations_free\n");
|
||||
|
||||
/* */
|
||||
hash = sc_stations_hash_addr(station->address);
|
||||
search = rcu_dereference_protected(sc_station_hash_addr[hash], sc_capwap_update_lock_is_locked());
|
||||
|
||||
if (search) {
|
||||
if (search == station) {
|
||||
rcu_assign_pointer(sc_station_hash_addr[hash], station->next_addr);
|
||||
} else {
|
||||
while (rcu_access_pointer(search->next_addr) && (rcu_access_pointer(search->next_addr) != station)) {
|
||||
search = rcu_dereference_protected(search->next_addr, sc_capwap_update_lock_is_locked());
|
||||
}
|
||||
|
||||
if (rcu_access_pointer(search->next_addr)) {
|
||||
rcu_assign_pointer(search->next_addr, station->next_addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
list_del_rcu(&station->list_dev);
|
||||
list_del_rcu(&station->list_session);
|
||||
synchronize_net();
|
||||
|
||||
kfree(station);
|
||||
}
|
||||
|
||||
/* */
|
||||
int sc_stations_setconnection(struct sc_capwap_station* station) {
|
||||
struct sc_capwap_connection* connection;
|
||||
|
||||
TRACEKMOD("### sc_stations_setconnection\n");
|
||||
|
||||
/* */
|
||||
connection = sc_stations_searchconnection(station);
|
||||
if (!connection) {
|
||||
connection = (struct sc_capwap_connection*)kzalloc(sizeof(struct sc_capwap_connection), GFP_KERNEL);
|
||||
if (!connection) {
|
||||
TRACEKMOD("*** Unable to create connection\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* */
|
||||
connection->sessionpriv = rcu_access_pointer(station->sessionpriv);
|
||||
list_add_rcu(&connection->list_session, &connection->sessionpriv->list_connections);
|
||||
connection->devpriv = rcu_access_pointer(station->devpriv);
|
||||
list_add_rcu(&connection->list_dev, &connection->devpriv->list_connections);
|
||||
connection->radioid = station->radioid;
|
||||
connection->vlan = station->vlan;
|
||||
}
|
||||
|
||||
/* */
|
||||
connection->count++;
|
||||
connection->wlanidmask |= 1 << (station->wlanid - 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
void sc_stations_releaseconnection(struct sc_capwap_station* station) {
|
||||
struct sc_capwap_connection* connection;
|
||||
|
||||
TRACEKMOD("### sc_stations_releaseconnection\n");
|
||||
|
||||
connection = sc_stations_searchconnection(station);
|
||||
if (connection) {
|
||||
TRACEKMOD("*** Release connection reference %d\n", connection->count);
|
||||
|
||||
connection->count--;
|
||||
if (!connection->count) {
|
||||
list_del_rcu(&connection->list_session);
|
||||
list_del_rcu(&connection->list_dev);
|
||||
synchronize_net();
|
||||
|
||||
kfree(connection);
|
||||
}
|
||||
}
|
||||
}
|
||||
#include "config.h"
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include "station.h"
|
||||
#include "capwap.h"
|
||||
#include "iface.h"
|
||||
|
||||
/* */
|
||||
#define STATION_HASH_SIZE 65536
|
||||
|
||||
/* */
|
||||
static LIST_HEAD(sc_station_list);
|
||||
static struct sc_capwap_station* __rcu sc_station_hash_addr[STATION_HASH_SIZE];
|
||||
|
||||
/* */
|
||||
static uint32_t sc_stations_hash_addr(const uint8_t* macaddress) {
|
||||
TRACEKMOD("### sc_stations_hash_addr\n");
|
||||
|
||||
return (((((uint32_t)macaddress[4] << 8) | (uint32_t)macaddress[5]) ^ ((uint32_t)macaddress[3] << 4)) % STATION_HASH_SIZE);
|
||||
}
|
||||
|
||||
/* */
|
||||
static struct sc_capwap_connection* sc_stations_searchconnection(struct sc_capwap_station* station) {
|
||||
struct sc_capwap_connection* connection;
|
||||
struct sc_capwap_session_priv* sessionpriv = rcu_access_pointer(station->sessionpriv);
|
||||
struct sc_netdev_priv* devpriv = rcu_access_pointer(station->devpriv);
|
||||
|
||||
TRACEKMOD("### sc_stations_searchconnection\n");
|
||||
|
||||
list_for_each_entry(connection, &sessionpriv->list_connections, list_session) {
|
||||
if ((connection->devpriv == devpriv) && (connection->radioid == station->radioid) && (connection->vlan == station->vlan)) {
|
||||
return connection;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* */
|
||||
void sc_stations_add(struct sc_capwap_station* station) {
|
||||
uint32_t hash;
|
||||
|
||||
TRACEKMOD("### sc_stations_add\n");
|
||||
|
||||
/* */
|
||||
list_add_rcu(&station->list, &sc_station_list);
|
||||
|
||||
hash = sc_stations_hash_addr(station->address);
|
||||
station->next_addr = rcu_dereference_protected(sc_station_hash_addr[hash], sc_capwap_update_lock_is_locked());
|
||||
rcu_assign_pointer(sc_station_hash_addr[hash], station);
|
||||
}
|
||||
|
||||
/* */
|
||||
struct sc_capwap_station* sc_stations_search(const uint8_t* macaddress) {
|
||||
struct sc_capwap_station* station;
|
||||
|
||||
TRACEKMOD("### sc_stations_search\n");
|
||||
|
||||
/* */
|
||||
station = rcu_dereference_check(sc_station_hash_addr[sc_stations_hash_addr(macaddress)], sc_capwap_update_lock_is_locked());
|
||||
while (station) {
|
||||
if (!memcmp(&station->address, macaddress, MACADDRESS_EUI48_LENGTH)) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* */
|
||||
station = rcu_dereference_check(station->next_addr, sc_capwap_update_lock_is_locked());
|
||||
}
|
||||
|
||||
return station;
|
||||
}
|
||||
|
||||
/* */
|
||||
void sc_stations_free(struct sc_capwap_station* station) {
|
||||
uint32_t hash;
|
||||
struct sc_capwap_station* search;
|
||||
|
||||
TRACEKMOD("### sc_stations_free\n");
|
||||
|
||||
/* */
|
||||
hash = sc_stations_hash_addr(station->address);
|
||||
search = rcu_dereference_protected(sc_station_hash_addr[hash], sc_capwap_update_lock_is_locked());
|
||||
|
||||
if (search) {
|
||||
if (search == station) {
|
||||
rcu_assign_pointer(sc_station_hash_addr[hash], station->next_addr);
|
||||
} else {
|
||||
while (rcu_access_pointer(search->next_addr) && (rcu_access_pointer(search->next_addr) != station)) {
|
||||
search = rcu_dereference_protected(search->next_addr, sc_capwap_update_lock_is_locked());
|
||||
}
|
||||
|
||||
if (rcu_access_pointer(search->next_addr)) {
|
||||
rcu_assign_pointer(search->next_addr, station->next_addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
list_del_rcu(&station->list_dev);
|
||||
list_del_rcu(&station->list_session);
|
||||
synchronize_net();
|
||||
|
||||
kfree(station);
|
||||
}
|
||||
|
||||
/* */
|
||||
int sc_stations_setconnection(struct sc_capwap_station* station) {
|
||||
struct sc_capwap_connection* connection;
|
||||
|
||||
TRACEKMOD("### sc_stations_setconnection\n");
|
||||
|
||||
/* */
|
||||
connection = sc_stations_searchconnection(station);
|
||||
if (!connection) {
|
||||
connection = (struct sc_capwap_connection*)kzalloc(sizeof(struct sc_capwap_connection), GFP_KERNEL);
|
||||
if (!connection) {
|
||||
TRACEKMOD("*** Unable to create connection\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* */
|
||||
connection->sessionpriv = rcu_access_pointer(station->sessionpriv);
|
||||
list_add_rcu(&connection->list_session, &connection->sessionpriv->list_connections);
|
||||
connection->devpriv = rcu_access_pointer(station->devpriv);
|
||||
list_add_rcu(&connection->list_dev, &connection->devpriv->list_connections);
|
||||
connection->radioid = station->radioid;
|
||||
connection->vlan = station->vlan;
|
||||
}
|
||||
|
||||
/* */
|
||||
connection->count++;
|
||||
connection->wlanidmask |= 1 << (station->wlanid - 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* */
|
||||
void sc_stations_releaseconnection(struct sc_capwap_station* station) {
|
||||
struct sc_capwap_connection* connection;
|
||||
|
||||
TRACEKMOD("### sc_stations_releaseconnection\n");
|
||||
|
||||
connection = sc_stations_searchconnection(station);
|
||||
if (connection) {
|
||||
TRACEKMOD("*** Release connection reference %d\n", connection->count);
|
||||
|
||||
connection->count--;
|
||||
if (!connection->count) {
|
||||
list_del_rcu(&connection->list_session);
|
||||
list_del_rcu(&connection->list_dev);
|
||||
synchronize_net();
|
||||
|
||||
kfree(connection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,58 +1,58 @@
|
||||
#ifndef __KMOD_AC_STATION_HEADER__
|
||||
#define __KMOD_AC_STATION_HEADER__
|
||||
|
||||
#include "capwap_rfc.h"
|
||||
|
||||
/* */
|
||||
struct sc_capwap_connection {
|
||||
int count;
|
||||
|
||||
/* Session */
|
||||
struct sc_capwap_session_priv* sessionpriv;
|
||||
struct list_head list_session;
|
||||
|
||||
/* Interface */
|
||||
struct sc_netdev_priv* devpriv;
|
||||
struct list_head list_dev;
|
||||
|
||||
/* */
|
||||
uint16_t vlan;
|
||||
uint8_t radioid;
|
||||
uint8_t wlanidmask;
|
||||
};
|
||||
|
||||
/* */
|
||||
struct sc_capwap_station {
|
||||
struct list_head list;
|
||||
|
||||
/* */
|
||||
uint8_t address[MACADDRESS_EUI48_LENGTH];
|
||||
struct sc_capwap_station* __rcu next_addr;
|
||||
|
||||
/* Session */
|
||||
struct sc_capwap_session_priv* __rcu sessionpriv;
|
||||
struct list_head list_session;
|
||||
|
||||
/* Interface */
|
||||
struct sc_netdev_priv* __rcu devpriv;
|
||||
struct list_head list_dev;
|
||||
|
||||
/* */
|
||||
uint8_t bssid[MACADDRESS_EUI48_LENGTH];
|
||||
uint16_t vlan;
|
||||
uint8_t radioid;
|
||||
uint8_t wlanid;
|
||||
};
|
||||
|
||||
/* */
|
||||
void sc_stations_add(struct sc_capwap_station* station);
|
||||
void sc_stations_free(struct sc_capwap_station* station);
|
||||
|
||||
/* */
|
||||
struct sc_capwap_station* sc_stations_search(const uint8_t* macaddress);
|
||||
|
||||
/* */
|
||||
int sc_stations_setconnection(struct sc_capwap_station* station);
|
||||
void sc_stations_releaseconnection(struct sc_capwap_station* station);
|
||||
|
||||
#endif /* __KMOD_AC_STATION_HEADER__ */
|
||||
#ifndef __KMOD_AC_STATION_HEADER__
|
||||
#define __KMOD_AC_STATION_HEADER__
|
||||
|
||||
#include "capwap_rfc.h"
|
||||
|
||||
/* */
|
||||
struct sc_capwap_connection {
|
||||
int count;
|
||||
|
||||
/* Session */
|
||||
struct sc_capwap_session_priv* sessionpriv;
|
||||
struct list_head list_session;
|
||||
|
||||
/* Interface */
|
||||
struct sc_netdev_priv* devpriv;
|
||||
struct list_head list_dev;
|
||||
|
||||
/* */
|
||||
uint16_t vlan;
|
||||
uint8_t radioid;
|
||||
uint8_t wlanidmask;
|
||||
};
|
||||
|
||||
/* */
|
||||
struct sc_capwap_station {
|
||||
struct list_head list;
|
||||
|
||||
/* */
|
||||
uint8_t address[MACADDRESS_EUI48_LENGTH];
|
||||
struct sc_capwap_station* __rcu next_addr;
|
||||
|
||||
/* Session */
|
||||
struct sc_capwap_session_priv* __rcu sessionpriv;
|
||||
struct list_head list_session;
|
||||
|
||||
/* Interface */
|
||||
struct sc_netdev_priv* __rcu devpriv;
|
||||
struct list_head list_dev;
|
||||
|
||||
/* */
|
||||
uint8_t bssid[MACADDRESS_EUI48_LENGTH];
|
||||
uint16_t vlan;
|
||||
uint8_t radioid;
|
||||
uint8_t wlanid;
|
||||
};
|
||||
|
||||
/* */
|
||||
void sc_stations_add(struct sc_capwap_station* station);
|
||||
void sc_stations_free(struct sc_capwap_station* station);
|
||||
|
||||
/* */
|
||||
struct sc_capwap_station* sc_stations_search(const uint8_t* macaddress);
|
||||
|
||||
/* */
|
||||
int sc_stations_setconnection(struct sc_capwap_station* station);
|
||||
void sc_stations_releaseconnection(struct sc_capwap_station* station);
|
||||
|
||||
#endif /* __KMOD_AC_STATION_HEADER__ */
|
||||
|
Reference in New Issue
Block a user