Added functionality into capwap data channel kernel module
This commit is contained in:
@ -1,5 +1,7 @@
|
||||
#include "config.h"
|
||||
#include <linux/module.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/ieee80211.h>
|
||||
#include "socket.h"
|
||||
#include "capwap.h"
|
||||
@ -12,6 +14,12 @@
|
||||
/* */
|
||||
union capwap_addr sc_localaddr;
|
||||
|
||||
/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
|
||||
static unsigned char sc_rfc1042_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
|
||||
|
||||
/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
|
||||
static unsigned char sc_bridge_tunnel_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
|
||||
|
||||
/* */
|
||||
static void sc_capwap_fragment_free(struct sc_capwap_fragment* fragment) {
|
||||
TRACEKMOD("### sc_capwap_fragment_free\n");
|
||||
@ -32,7 +40,6 @@ static void sc_capwap_fragment_free(struct sc_capwap_fragment* fragment) {
|
||||
/* */
|
||||
static void sc_capwap_defrag_evictor(struct sc_capwap_session* session, ktime_t now) {
|
||||
ktime_t delta;
|
||||
unsigned long flags;
|
||||
struct sc_capwap_fragment* fragment;
|
||||
|
||||
TRACEKMOD("### sc_capwap_defrag_evictor\n");
|
||||
@ -45,7 +52,7 @@ static void sc_capwap_defrag_evictor(struct sc_capwap_session* session, ktime_t
|
||||
|
||||
/* Remove last old fragment */
|
||||
if (!list_empty(&session->fragments.lru_list)) {
|
||||
spin_lock_irqsave(&session->fragments.lock, flags);
|
||||
spin_lock(&session->fragments.lock);
|
||||
|
||||
fragment = list_first_entry(&session->fragments.lru_list, struct sc_capwap_fragment, lru_list);
|
||||
if (fragment) {
|
||||
@ -58,7 +65,7 @@ static void sc_capwap_defrag_evictor(struct sc_capwap_session* session, ktime_t
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&session->fragments.lock, flags);
|
||||
spin_unlock(&session->fragments.lock);
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,7 +111,6 @@ static struct sk_buff* sc_capwap_reasm(struct sc_capwap_fragment* fragment) {
|
||||
|
||||
/* */
|
||||
static struct sk_buff* sc_capwap_defrag(struct sc_capwap_session* session, struct sk_buff* skb) {
|
||||
unsigned long flags;
|
||||
uint16_t headersize;
|
||||
uint16_t frag_id;
|
||||
struct sk_buff* prev;
|
||||
@ -132,7 +138,7 @@ static struct sk_buff* sc_capwap_defrag(struct sc_capwap_session* session, struc
|
||||
cb->frag_length = skb->len - headersize;
|
||||
|
||||
/* */
|
||||
spin_lock_irqsave(&session->fragments.lock, flags);
|
||||
spin_lock(&session->fragments.lock);
|
||||
|
||||
/* Get fragment */
|
||||
fragment = &session->fragments.queues[frag_id % CAPWAP_FRAGMENT_QUEUE];
|
||||
@ -219,18 +225,158 @@ static struct sk_buff* sc_capwap_defrag(struct sc_capwap_session* session, struc
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&session->fragments.lock, flags);
|
||||
spin_unlock(&session->fragments.lock);
|
||||
|
||||
return skb_defrag;
|
||||
|
||||
error2:
|
||||
spin_unlock_irqrestore(&session->fragments.lock, flags);
|
||||
spin_unlock(&session->fragments.lock);
|
||||
|
||||
error:
|
||||
kfree_skb(skb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* */
|
||||
static unsigned int sc_capwap_80211_hdrlen(__le16 fc) {
|
||||
unsigned int hdrlen = 24;
|
||||
|
||||
TRACEKMOD("### sc_capwap_80211_hdrlen\n");
|
||||
|
||||
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;
|
||||
uint8_t* encaps_data;
|
||||
int encaps_len;
|
||||
struct ethhdr* eh = (struct ethhdr*)skb->data;
|
||||
uint16_t ethertype = ntohs(eh->h_proto);
|
||||
|
||||
TRACEKMOD("### sc_capwap_8023_to_80211\n");
|
||||
|
||||
/* 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);
|
||||
|
||||
TRACEKMOD("### sc_capwap_80211_to_8023\n");
|
||||
|
||||
/* */
|
||||
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_bind(union capwap_addr* sockaddr) {
|
||||
int ret;
|
||||
@ -275,13 +421,12 @@ void sc_capwap_freesession(struct sc_capwap_session* session) {
|
||||
/* */
|
||||
uint16_t sc_capwap_newfragmentid(struct sc_capwap_session* session) {
|
||||
uint16_t fragmentid;
|
||||
unsigned long flags;
|
||||
|
||||
TRACEKMOD("### sc_capwap_newfragmentid\n");
|
||||
|
||||
spin_lock_irqsave(&session->fragmentid_lock, flags);
|
||||
spin_lock(&session->fragmentid_lock);
|
||||
fragmentid = session->fragmentid++;
|
||||
spin_unlock_irqrestore(&session->fragmentid_lock, flags);
|
||||
spin_unlock(&session->fragmentid_lock);
|
||||
|
||||
return fragmentid;
|
||||
}
|
||||
@ -454,8 +599,6 @@ int sc_capwap_parsingpacket(struct sc_capwap_session* session, const union capwa
|
||||
}
|
||||
}
|
||||
|
||||
/* Parsing complete */
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -464,6 +607,7 @@ int sc_capwap_parsingpacket(struct sc_capwap_session* session, const union capwa
|
||||
|
||||
/* */
|
||||
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;
|
||||
@ -482,7 +626,7 @@ int sc_capwap_forwarddata(struct sc_capwap_session* session, uint8_t radioid, ui
|
||||
reserve = sizeof(struct sc_capwap_header) + radioaddrlength + winfolength;
|
||||
if (skb_is_nonlinear(skb) || (headroom < reserve)) {
|
||||
printk("*** Expand socket buffer\n");
|
||||
clone = skb_copy_expand(skb, max_t(int, headroom, reserve), skb_tailroom(skb), GFP_KERNEL);
|
||||
clone = skb_copy_expand(skb, max(headroom, reserve), skb_tailroom(skb), GFP_KERNEL);
|
||||
if (!clone) {
|
||||
printk("*** Unable to expand socket buffer\n");
|
||||
return -ENOMEM;
|
||||
@ -551,7 +695,9 @@ int sc_capwap_forwarddata(struct sc_capwap_session* session, uint8_t radioid, ui
|
||||
}
|
||||
|
||||
/* Send packet */
|
||||
if (sc_socket_send(SOCKET_UDP, (uint8_t*)header, (size + length), &session->peeraddr) < 0) {
|
||||
err = sc_socket_send(SOCKET_UDP, (uint8_t*)header, (size + length), &session->peeraddr);
|
||||
TRACEKMOD("*** Send packet result: %d\n", err);
|
||||
if (err < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
@ -593,18 +739,18 @@ struct sc_capwap_radio_addr* sc_capwap_setradiomacaddress(uint8_t* buffer, int s
|
||||
radioaddr = (struct sc_capwap_radio_addr*)buffer;
|
||||
radioaddr->length = MACADDRESS_EUI48_LENGTH;
|
||||
|
||||
addr = (struct sc_capwap_macaddress_eui48*)(buffer + sizeof(struct sc_capwap_radio_addr));
|
||||
addr = (struct sc_capwap_macaddress_eui48*)radioaddr->addr;
|
||||
memcpy(addr->addr, bssid, MACADDRESS_EUI48_LENGTH);
|
||||
|
||||
return radioaddr;
|
||||
}
|
||||
|
||||
/* */
|
||||
struct sc_capwap_wireless_information* sc_capwap_setwirelessinformation(uint8_t* buffer, int size, uint8_t rssi, uint8_t snr, uint16_t rate) {
|
||||
struct sc_capwap_wireless_information* 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;
|
||||
|
||||
TRACEKMOD("### sc_capwap_setwirelessinformation\n");
|
||||
TRACEKMOD("### sc_capwap_setwinfo_frameinfo\n");
|
||||
|
||||
memset(buffer, 0, size);
|
||||
|
||||
@ -618,3 +764,21 @@ struct sc_capwap_wireless_information* sc_capwap_setwirelessinformation(uint8_t*
|
||||
|
||||
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;
|
||||
|
||||
TRACEKMOD("### sc_capwap_setwinfo_destwlans\n");
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -21,27 +21,25 @@
|
||||
/* */
|
||||
#define SKB_CAPWAP_FLAG_FROM_DATA_CHANNEL 0x0001
|
||||
#define SKB_CAPWAP_FLAG_FROM_USER_SPACE 0x0002
|
||||
#define SKB_CAPWAP_FLAG_FROM_IEEE80211 0x0004
|
||||
|
||||
#define SKB_CAPWAP_FLAG_PEERADDRESS 0x0010
|
||||
#define SKB_CAPWAP_FLAG_RADIOID 0x0020
|
||||
#define SKB_CAPWAP_FLAG_BINDING 0x0040
|
||||
#define SKB_CAPWAP_FLAG_RADIOADDRESS 0x0080
|
||||
#define SKB_CAPWAP_FLAG_WIRELESSINFORMATION 0x0100
|
||||
#define SKB_CAPWAP_FLAG_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;
|
||||
struct capwap_addr_little peeraddr;
|
||||
|
||||
/* Session ID */
|
||||
struct sc_capwap_sessionid_element sessionid;
|
||||
|
||||
/* Capwap information */
|
||||
uint8_t radioid;
|
||||
uint8_t binding;
|
||||
|
||||
/* Radio Address */
|
||||
uint8_t radioaddr_addr[MACADDRESS_EUI48_LENGTH];
|
||||
|
||||
/* Wireless Information */
|
||||
uint8_t winfo_rssi;
|
||||
uint8_t winfo_snr;
|
||||
@ -106,16 +104,17 @@ void sc_capwap_initsession(struct sc_capwap_session* session);
|
||||
void sc_capwap_freesession(struct sc_capwap_session* session);
|
||||
uint16_t sc_capwap_newfragmentid(struct sc_capwap_session* session);
|
||||
|
||||
void sc_capwap_sessionid_printf(const struct sc_capwap_sessionid_element* sessionid, char* string);
|
||||
int sc_capwap_8023_to_80211(struct sk_buff* skb, const uint8_t* bssid);
|
||||
int sc_capwap_80211_to_8023(struct sk_buff* skb);
|
||||
|
||||
struct sc_capwap_packet* sc_capwap_poppacketqueue(struct sc_capwap_session* session);
|
||||
void sc_capwap_pushpacketqueue(struct sc_capwap_session* session, struct sc_capwap_packet* packet);
|
||||
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_setwirelessinformation(uint8_t* buffer, int size, uint8_t rssi, uint8_t snr, uint16_t rate);
|
||||
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);
|
||||
|
||||
|
@ -1,6 +1,9 @@
|
||||
#include "config.h"
|
||||
#include <linux/module.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/ieee80211.h>
|
||||
#include <net/mac80211.h>
|
||||
#include <net/ipv6.h>
|
||||
#include "capwap.h"
|
||||
#include "nlsmartcapwap.h"
|
||||
@ -77,6 +80,7 @@ int sc_capwap_sendkeepalive(void) {
|
||||
|
||||
/* Send packet */
|
||||
ret = sc_socket_send(SOCKET_UDP, buffer, length, &sc_acsession.peeraddr);
|
||||
TRACEKMOD("*** Send keep-alive result: %d\n", ret);
|
||||
if (ret > 0) {
|
||||
ret = 0;
|
||||
}
|
||||
@ -151,8 +155,119 @@ struct sc_capwap_session* sc_capwap_recvunknownkeepalive(const union capwap_addr
|
||||
|
||||
/* */
|
||||
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;
|
||||
|
||||
TRACEKMOD("### sc_capwap_parsingdatapacket\n");
|
||||
|
||||
/* 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)) {
|
||||
/* Accept only broadcast packet with wireless information */
|
||||
if (winfo) {
|
||||
uint8_t wlanid = 1;
|
||||
uint16_t bitmask = be16_to_cpu(destwlan->wlanidbitmap);
|
||||
while (bitmask) {
|
||||
if (bitmask & 0x01) {
|
||||
dev = sc_netlink_getdev_from_wlanid(GET_RID_HEADER(header), wlanid);
|
||||
if (dev) {
|
||||
struct sk_buff* clone = skb_copy_expand(skb, skb_headroom(skb), skb_tailroom(skb), GFP_KERNEL);
|
||||
if (!clone) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
TRACEKMOD("****************\n");
|
||||
print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 16, 1, clone->data, sizeof(struct ethhdr), 1);
|
||||
TRACEKMOD("++++++++++++++++\n");
|
||||
|
||||
/* */
|
||||
if (!is80211) {
|
||||
if (sc_capwap_8023_to_80211(clone, dev->dev_addr)) {
|
||||
kfree_skb(clone);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 16, 1, clone->data, sizeof(struct ieee80211_hdr), 1);
|
||||
TRACEKMOD("****************\n");
|
||||
|
||||
TRACEKMOD("** Send broadcast packet to interface: %d\n", dev->ifindex);
|
||||
|
||||
/* Send packet */
|
||||
local_bh_disable();
|
||||
ieee80211_inject_xmit(clone, dev);
|
||||
local_bh_enable();
|
||||
} else {
|
||||
TRACEKMOD("*** Unknown wlanid: %d\n", (int)wlanid);
|
||||
}
|
||||
}
|
||||
|
||||
/* Next */
|
||||
wlanid++;
|
||||
bitmask >>= 1;
|
||||
}
|
||||
} else {
|
||||
TRACEKMOD("*** Invalid broadcast packet\n");
|
||||
}
|
||||
|
||||
/* Free broadcast packet */
|
||||
kfree_skb(skb);
|
||||
} else {
|
||||
/* Accept only 802.11 frame or 802.3 frame with radio address */
|
||||
if (is80211 || (radioaddr && (radioaddr->length == MACADDRESS_EUI48_LENGTH))){
|
||||
if (!is80211) {
|
||||
if (sc_capwap_8023_to_80211(skb, radioaddr->addr)) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
dev = sc_netlink_getdev_from_bssid(GET_RID_HEADER(header), ((struct ieee80211_hdr*)skb->data)->addr2);
|
||||
if (!dev) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
TRACEKMOD("** Send packet to interface: %d\n", dev->ifindex);
|
||||
|
||||
/* Send packet */
|
||||
local_bh_disable();
|
||||
ieee80211_inject_xmit(skb, dev);
|
||||
local_bh_enable();
|
||||
} else {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
TRACEKMOD("*** Invalid packet\n");
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
/* */
|
||||
|
@ -79,6 +79,7 @@ struct sc_capwap_header {
|
||||
#define CAPWAP_RADIO_MAX_LENGTH_PADDED 12
|
||||
struct sc_capwap_radio_addr {
|
||||
uint8_t length;
|
||||
uint8_t addr[0];
|
||||
} __packed;
|
||||
|
||||
/* Wireless Information */
|
||||
@ -96,6 +97,12 @@ struct sc_capwap_ieee80211_frame_info {
|
||||
__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)
|
||||
|
||||
@ -112,7 +119,10 @@ struct sc_capwap_message_element {
|
||||
|
||||
/* Session id message element */
|
||||
struct sc_capwap_sessionid_element {
|
||||
uint8_t id[16];
|
||||
union {
|
||||
uint8_t id[16];
|
||||
uint32_t id32[4];
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/* */
|
||||
@ -169,4 +179,9 @@ struct sc_capwap_macaddress_eui64 {
|
||||
#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__ */
|
||||
|
@ -68,8 +68,8 @@ static int sc_netlink_handler(uint32_t ifindex, struct sk_buff* skb, int sig_dbm
|
||||
if (ieee80211_is_data(hdr->frame_control)) {
|
||||
int err;
|
||||
struct sc_capwap_session* session;
|
||||
unsigned char radioaddrbuffer[CAPWAP_RADIO_EUI48_LENGTH_PADDED];
|
||||
unsigned char winfobuffer[CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED];
|
||||
uint8_t radioaddrbuffer[CAPWAP_RADIO_EUI48_LENGTH_PADDED];
|
||||
uint8_t winfobuffer[CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED];
|
||||
struct sc_capwap_radio_addr* radioaddr = NULL;
|
||||
struct sc_capwap_wireless_information* winfo = NULL;
|
||||
|
||||
@ -97,7 +97,7 @@ static int sc_netlink_handler(uint32_t ifindex, struct sk_buff* skb, int sig_dbm
|
||||
|
||||
/* Create Wireless Information */
|
||||
if (sig_dbm || rate) {
|
||||
winfo = sc_capwap_setwirelessinformation(winfobuffer, CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED, (uint8_t)sig_dbm, 0, ((uint16_t)rate) * 5);
|
||||
winfo = sc_capwap_setwinfo_frameinfo(winfobuffer, CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED, (uint8_t)sig_dbm, 0, ((uint16_t)rate) * 5);
|
||||
}
|
||||
|
||||
/* */
|
||||
@ -455,7 +455,7 @@ static int sc_netlink_send_data(struct sk_buff* skb, struct genl_info* info) {
|
||||
|
||||
/* Create Wireless Information */
|
||||
if (rssi || snr || rate) {
|
||||
winfo = sc_capwap_setwirelessinformation(winfobuffer, CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED, rssi, snr, rate);
|
||||
winfo = sc_capwap_setwinfo_frameinfo(winfobuffer, CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED, rssi, snr, rate);
|
||||
}
|
||||
|
||||
/* Create socket buffer */
|
||||
@ -728,6 +728,38 @@ error:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* */
|
||||
struct net_device* sc_netlink_getdev_from_wlanid(uint8_t radioid, uint8_t wlanid) {
|
||||
struct sc_netlink_device* nldev;
|
||||
|
||||
TRACEKMOD("### sc_netlink_getdev_from_wlanid\n");
|
||||
|
||||
/* Search */
|
||||
list_for_each_entry(nldev, &sc_netlink_dev_list, list) {
|
||||
if ((nldev->radioid == radioid) && (nldev->wlanid == wlanid)) {
|
||||
return nldev->dev;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* */
|
||||
struct net_device* sc_netlink_getdev_from_bssid(uint8_t radioid, const uint8_t* addr) {
|
||||
struct sc_netlink_device* nldev;
|
||||
|
||||
TRACEKMOD("### sc_netlink_getdev_from_bssid\n");
|
||||
|
||||
/* Search */
|
||||
list_for_each_entry(nldev, &sc_netlink_dev_list, list) {
|
||||
if ((nldev->radioid == radioid) && !memcmp(nldev->dev->dev_addr, addr, MACADDRESS_EUI48_LENGTH)) {
|
||||
return nldev->dev;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* */
|
||||
int sc_netlink_init(void) {
|
||||
int ret;
|
||||
|
@ -8,6 +8,10 @@
|
||||
int sc_netlink_init(void);
|
||||
void sc_netlink_exit(void);
|
||||
|
||||
/* */
|
||||
struct net_device* sc_netlink_getdev_from_wlanid(uint8_t radioid, uint8_t wlanid);
|
||||
struct net_device* sc_netlink_getdev_from_bssid(uint8_t radioid, const uint8_t* addr);
|
||||
|
||||
/* */
|
||||
int sc_netlink_notify_recv_keepalive(const union capwap_addr* sockaddr, struct sc_capwap_sessionid_element* sessionid);
|
||||
int sc_netlink_notify_recv_data(uint8_t* packet, int length);
|
||||
|
@ -225,29 +225,3 @@ int sc_addr_compare(const union capwap_addr* addr1, const union capwap_addr* add
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* */
|
||||
void sc_addr_tolittle(const union capwap_addr* addr, struct capwap_addr_little* little) {
|
||||
little->family = (uint8_t)addr->ss.ss_family;
|
||||
if (addr->ss.ss_family == AF_INET) {
|
||||
memcpy(&little->addr4, &addr->sin.sin_addr, sizeof(struct in_addr));
|
||||
little->port = addr->sin.sin_port;
|
||||
} else if (addr->ss.ss_family == AF_INET6) {
|
||||
memcpy(&little->addr6, &addr->sin6.sin6_addr, sizeof(struct in6_addr));
|
||||
little->port = addr->sin6.sin6_port;
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
void sc_addr_fromlittle(const struct capwap_addr_little* little, union capwap_addr* addr) {
|
||||
memset(addr, 0, sizeof(union capwap_addr));
|
||||
|
||||
addr->ss.ss_family = little->family;
|
||||
if (little->family == AF_INET) {
|
||||
memcpy(&addr->sin.sin_addr, &little->addr4, sizeof(struct in_addr));
|
||||
addr->sin.sin_port = little->port;
|
||||
} else if (little->family == AF_INET6) {
|
||||
memcpy(&addr->sin6.sin6_addr, &little->addr6, sizeof(struct in6_addr));
|
||||
addr->sin6.sin6_port = little->port;
|
||||
}
|
||||
}
|
||||
|
@ -10,16 +10,6 @@
|
||||
#define SOCKET_UDP 0
|
||||
#define SOCKET_UDPLITE 1
|
||||
|
||||
/* Little socket address */
|
||||
struct capwap_addr_little {
|
||||
uint8_t family;
|
||||
union {
|
||||
struct in_addr addr4;
|
||||
struct in6_addr addr6;
|
||||
};
|
||||
uint16_t port;
|
||||
};
|
||||
|
||||
/* Universal socket address */
|
||||
union capwap_addr {
|
||||
struct sockaddr sa;
|
||||
@ -35,11 +25,11 @@ void sc_socket_close(void);
|
||||
/* */
|
||||
int sc_socket_bind(union capwap_addr* sockaddr);
|
||||
int sc_socket_send(int type, uint8_t* buffer, int length, union capwap_addr* sockaddr);
|
||||
|
||||
/* */
|
||||
int sc_socket_getpeeraddr(struct sk_buff* skb, union capwap_addr* peeraddr);
|
||||
|
||||
/* */
|
||||
int sc_addr_compare(const union capwap_addr* addr1, const union capwap_addr* addr2);
|
||||
void sc_addr_tolittle(const union capwap_addr* addr, struct capwap_addr_little* little);
|
||||
void sc_addr_fromlittle(const struct capwap_addr_little* little, union capwap_addr* addr);
|
||||
|
||||
#endif /* __KMOD_SOCKET_HEADER__ */
|
||||
|
Reference in New Issue
Block a user