wtp: rework kernel socket handling

Switch to a connected UDP kernel socket. Comparing the
local and remote IPs is no longer required and handling
different IP versions and UDP types is automatic.

The WTP logic needs to reopen the socket on demand now.
This commit is contained in:
Andreas Schultz 2016-02-18 15:06:39 +01:00
parent cae859e42f
commit a6d0efe91a
10 changed files with 196 additions and 479 deletions

View File

@ -3,22 +3,22 @@
#include <linux/if_ether.h>
#include <linux/etherdevice.h>
#include <linux/ieee80211.h>
#include "socket.h"
#include <linux/udp.h>
#include <net/udp.h>
#include "capwap.h"
#include "nlsmartcapwap.h"
#include "netlinkapp.h"
/* */
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 };
static const unsigned char sc_rfc1042_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
static unsigned char sc_bridge_tunnel_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
static const unsigned char sc_bridge_tunnel_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
/* */
static void sc_capwap_fragment_free(struct sc_capwap_fragment* fragment) {
static void sc_capwap_fragment_free(struct sc_capwap_fragment* fragment)
{
TRACEKMOD("### sc_capwap_fragment_free\n");
/* */
@ -34,6 +34,20 @@ static void sc_capwap_fragment_free(struct sc_capwap_fragment* fragment) {
}
}
/* */
static void sc_capwap_freesession(struct sc_capwap_session* session)
{
struct sc_capwap_fragment* temp;
struct sc_capwap_fragment* fragment;
TRACEKMOD("### sc_capwap_freesession\n");
/* Free socket buffers */
list_for_each_entry_safe(fragment, temp, &session->fragments.lru_list, lru_list) {
sc_capwap_fragment_free(fragment);
}
}
/* */
static void sc_capwap_defrag_evictor(struct sc_capwap_session* session, ktime_t now) {
ktime_t delta;
@ -273,7 +287,7 @@ int sc_capwap_8023_to_80211(struct sk_buff* skb, const uint8_t* bssid) {
int head_need;
struct ieee80211_hdr hdr;
int skip_header_bytes;
uint8_t* encaps_data;
const uint8_t* encaps_data;
int encaps_len;
struct ethhdr* eh = (struct ethhdr*)skb->data;
uint16_t ethertype = ntohs(eh->h_proto);
@ -379,58 +393,59 @@ int sc_capwap_80211_to_8023(struct sk_buff* skb) {
return 0;
}
/* */
int sc_capwap_bind(struct net *net, union capwap_addr* sockaddr) {
int sc_capwap_bind(struct sc_capwap_session *session, int protocol, struct sockaddr_storage *sockaddr)
{
int ret;
TRACEKMOD("### sc_capwap_bind\n");
/* */
ret = sc_socket_bind(net, sockaddr);
if (ret) {
if (session->socket)
return -EBUSY;
ret = sock_create_kern(session->net, sockaddr->ss_family, SOCK_DGRAM, protocol, &session->socket);
if (ret < 0)
return ret;
}
memcpy(&sc_localaddr, sockaddr, sizeof(union capwap_addr));
ret = kernel_bind(session->socket, (struct sockaddr *)sockaddr, sizeof(struct sockaddr_storage));
if (ret < 0)
goto err_close;
/* Set callback */
udp_sk(session->socket->sk)->encap_type = 1;
udp_sk(session->socket->sk)->encap_rcv = sc_capwap_recvpacket;
udp_encap_enable();
if (sockaddr->ss_family == AF_INET6)
udpv6_encap_enable();
return 0;
err_close:
kernel_sock_shutdown(session->socket, SHUT_RDWR);
sock_release(session->socket);
session->socket = NULL;
return ret;
}
/* */
void sc_capwap_initsession(struct sc_capwap_session* session) {
TRACEKMOD("### sc_capwap_initsession\n");
void sc_capwap_close(struct sc_capwap_session *session)
{
TRACEKMOD("### sc_capwap_close\n");
spin_lock_init(&session->fragmentid_lock);
/* Defragment packets */
memset(&session->fragments, 0, sizeof(struct sc_capwap_fragment_queue));
INIT_LIST_HEAD(&session->fragments.lru_list);
spin_lock_init(&session->fragments.lock);
}
/* */
void sc_capwap_freesession(struct sc_capwap_session* session) {
struct sc_capwap_fragment* temp;
struct sc_capwap_fragment* fragment;
TRACEKMOD("### sc_capwap_freesession\n");
/* Free socket buffers */
list_for_each_entry_safe(fragment, temp, &session->fragments.lru_list, lru_list) {
sc_capwap_fragment_free(fragment);
if (session->socket) {
kernel_sock_shutdown(session->socket, SHUT_RDWR);
sock_release(session->socket);
}
session->socket = NULL;
sc_capwap_freesession(session);
}
/* */
uint16_t sc_capwap_newfragmentid(struct sc_capwap_session* session) {
uint16_t fragmentid;
static uint16_t sc_capwap_newfragmentid(struct sc_capwap_session* session)
{
TRACEKMOD("### sc_capwap_newfragmentid\n");
spin_lock(&session->fragmentid_lock);
fragmentid = session->fragmentid++;
spin_unlock(&session->fragmentid_lock);
return fragmentid;
return atomic_inc_return(&session->fragmentid) & 0xFFFF;
}
/* */
@ -483,7 +498,6 @@ int sc_capwap_createkeepalive(struct sc_capwap_sessionid_element* sessionid, uin
/* */
int sc_capwap_parsingpacket(struct sc_capwap_session* session,
const union capwap_addr* sockaddr,
struct sk_buff* skb) {
int length;
uint16_t headersize;
@ -551,7 +565,7 @@ int sc_capwap_parsingpacket(struct sc_capwap_session* session,
struct sc_capwap_sessionid_element* sessionid = (struct sc_capwap_sessionid_element*)(((uint8_t*)message) + sizeof(struct sc_capwap_message_element));
if (!session) {
session = sc_capwap_recvunknownkeepalive(sockaddr, sessionid);
session = sc_capwap_recvunknownkeepalive(session, sessionid);
if (!session) {
TRACEKMOD("*** Receive unknown keep alive without valid session\n");
return -EINVAL;
@ -562,7 +576,7 @@ int sc_capwap_parsingpacket(struct sc_capwap_session* session,
}
/* Session found */
sc_netlink_notify_recv_keepalive(session->net, sockaddr, sessionid);
sc_netlink_notify_recv_keepalive(session->net, sessionid);
/* Parsing complete */
kfree_skb(skb);
@ -702,7 +716,7 @@ int sc_capwap_forwarddata(struct sc_capwap_session* session, uint8_t radioid, ui
}
/* Send packet */
err = sc_socket_send(SOCKET_UDP, (uint8_t*)header, (size + length), &session->peeraddr);
err = sc_capwap_send(session, (uint8_t*)header, (size + length));
TRACEKMOD("*** Send packet result: %d\n", err);
if (err < 0) {
break;

View File

@ -1,8 +1,12 @@
#ifndef __KMOD_CAPWAP_HEADER__
#define __KMOD_CAPWAP_HEADER__
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/in6.h>
#include <linux/skbuff.h>
#include "capwap_rfc.h"
#include "socket.h"
/* */
#define MAX_MTU 9000
@ -30,6 +34,14 @@
#define SKB_CAPWAP_FLAG_WIRELESSINFORMATION 0x0800
#define SKB_CAPWAP_FLAG_FRAGMENT 0x1000
/* Universal socket address */
union capwap_addr {
struct sockaddr sa;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
struct sockaddr_storage ss;
};
struct sc_skb_capwap_cb {
uint16_t flags;
@ -79,32 +91,28 @@ struct sc_capwap_fragment_queue {
struct sc_capwap_session {
struct net *net;
struct socket *socket;
uint16_t mtu;
union capwap_addr peeraddr;
struct sc_capwap_sessionid_element sessionid;
uint16_t fragmentid;
spinlock_t fragmentid_lock;
atomic_t fragmentid;
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);
int sc_capwap_recvpacket(struct sock *sk, struct sk_buff* skb);
struct sc_capwap_session* sc_capwap_recvunknownkeepalive(struct sc_capwap_session* session,
const struct sc_capwap_sessionid_element* sessionid);
void sc_capwap_parsingdatapacket(struct sc_capwap_session* session, struct sk_buff* skb);
void sc_capwap_parsingmgmtpacket(struct sc_capwap_session* session, struct sk_buff* skb);
/* Indipendent implementation function */
int sc_capwap_bind(struct net *net, 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_bind(struct sc_capwap_session *session, int protocol,
struct sockaddr_storage *sockaddr);
int sc_capwap_send(struct sc_capwap_session *session, uint8_t* buffer, int length);
void sc_capwap_close(struct sc_capwap_session *session);
int sc_capwap_8023_to_80211(struct sk_buff* skb, const uint8_t* bssid);
int sc_capwap_80211_to_8023(struct sk_buff* skb);
@ -112,7 +120,7 @@ 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);
int sc_capwap_parsingpacket(struct sc_capwap_session* session, struct sk_buff* skb);
struct sc_capwap_radio_addr* sc_capwap_setradiomacaddress(uint8_t* buffer, int size, uint8_t* bssid);
struct sc_capwap_wireless_information* sc_capwap_setwinfo_frameinfo(uint8_t* buffer, int size, uint8_t rssi, uint8_t snr, uint16_t rate);

View File

@ -14,71 +14,55 @@
#include "netlinkapp.h"
/* */
static struct sc_capwap_session sc_acsession;
/* */
int sc_capwap_init(struct net *net) {
int sc_capwap_init(struct sc_capwap_session *session, struct net *net)
{
TRACEKMOD("### sc_capwap_init\n");
/* Init session */
memset(&sc_acsession, 0, sizeof(struct sc_capwap_session));
sc_capwap_initsession(&sc_acsession);
memset(session, 0, sizeof(struct sc_capwap_session));
sc_acsession.net = net;
session->net = net;
/* Init sockect */
memset(&sc_localaddr, 0, sizeof(union capwap_addr));
return sc_socket_init();
/* Defragment packets */
memset(&session->fragments, 0, sizeof(struct sc_capwap_fragment_queue));
INIT_LIST_HEAD(&session->fragments.lru_list);
spin_lock_init(&session->fragments.lock);
return 0;
}
int sc_capwap_connect(struct sc_capwap_session *session,
struct sockaddr_storage *peeraddr,
struct sc_capwap_sessionid_element* sessionid, uint16_t mtu)
{
int err;
TRACEKMOD("### sc_capwap_connect(%p, %p, %p, %d)\n", session, peeraddr, sessionid, mtu);
memcpy(&session->sessionid, sessionid, sizeof(struct sc_capwap_sessionid_element));
session->mtu = mtu;
err = kernel_connect(session->socket,
(struct sockaddr *)peeraddr,
sizeof(*peeraddr), 0);
if (err < 0)
return err;
return sc_capwap_sendkeepalive(session);
}
/* */
void sc_capwap_close(void) {
TRACEKMOD("### sc_capwap_close\n");
/* */
sc_socket_close();
memset(&sc_localaddr, 0, sizeof(union capwap_addr));
sc_capwap_freesession(&sc_acsession);
}
/* */
int sc_capwap_connect(struct net *net, const union capwap_addr* sockaddr,
struct sc_capwap_sessionid_element* sessionid, uint16_t mtu) {
TRACEKMOD("### sc_capwap_connect\n");
if ((sc_localaddr.ss.ss_family != AF_INET) && (sc_localaddr.ss.ss_family != AF_INET6)) {
return -ENONET;
}
/* AC address */
if ((sockaddr->ss.ss_family == AF_INET6) && ipv6_addr_v4mapped(&sockaddr->sin6.sin6_addr)) {
return -EINVAL;
} else if ((sc_localaddr.ss.ss_family == AF_INET) && (sockaddr->ss.ss_family == AF_INET6)) {
return -EINVAL;
}
/* */
memcpy(&sc_acsession.peeraddr, sockaddr, sizeof(union capwap_addr));
memcpy(&sc_acsession.sessionid, sessionid, sizeof(struct sc_capwap_sessionid_element));
sc_acsession.mtu = mtu;
return sc_capwap_sendkeepalive();
}
/* */
void sc_capwap_resetsession(void) {
void sc_capwap_resetsession(struct sc_capwap_session *session)
{
TRACEKMOD("### sc_capwap_resetsession\n");
/* */
sc_capwap_freesession(&sc_acsession);
/* Reinit session */
memset(&sc_acsession, 0, sizeof(struct sc_capwap_session));
sc_capwap_initsession(&sc_acsession);
sc_capwap_close(session);
sc_capwap_init(session, session->net);
}
/* */
int sc_capwap_sendkeepalive(void) {
int sc_capwap_sendkeepalive(struct sc_capwap_session *session)
{
int ret;
int length;
uint8_t buffer[CAPWAP_KEEP_ALIVE_MAX_SIZE];
@ -86,10 +70,10 @@ int sc_capwap_sendkeepalive(void) {
TRACEKMOD("### sc_capwap_sendkeepalive\n");
/* Build keepalive */
length = sc_capwap_createkeepalive(&sc_acsession.sessionid, buffer, CAPWAP_KEEP_ALIVE_MAX_SIZE);
length = sc_capwap_createkeepalive(&session->sessionid, buffer, CAPWAP_KEEP_ALIVE_MAX_SIZE);
/* Send packet */
ret = sc_socket_send(SOCKET_UDP, buffer, length, &sc_acsession.peeraddr);
ret = sc_capwap_send(session, buffer, length);
TRACEKMOD("*** Send keep-alive result: %d\n", ret);
if (ret > 0) {
ret = 0;
@ -98,44 +82,37 @@ int sc_capwap_sendkeepalive(void) {
return ret;
}
/* */
struct sc_capwap_session* sc_capwap_getsession(const union capwap_addr* sockaddr) {
TRACEKMOD("### sc_capwap_getsession\n");
int sc_capwap_send(struct sc_capwap_session *session, uint8_t* buffer, int length)
{
struct kvec vec = {
.iov_base = buffer,
.iov_len = length,
};
struct msghdr msg = {
.msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL,
};
if (!sockaddr) {
return &sc_acsession;
} else if (sc_acsession.peeraddr.ss.ss_family == sockaddr->ss.ss_family) {
if (sc_acsession.peeraddr.ss.ss_family == AF_INET) {
if ((sc_acsession.peeraddr.sin.sin_port == sockaddr->sin.sin_port) && (sc_acsession.peeraddr.sin.sin_addr.s_addr == sockaddr->sin.sin_addr.s_addr)) {
return &sc_acsession;
}
} else if (sc_acsession.peeraddr.ss.ss_family == AF_INET6) {
if ((sc_acsession.peeraddr.sin6.sin6_port == sockaddr->sin6.sin6_port) && !ipv6_addr_cmp(&sc_acsession.peeraddr.sin6.sin6_addr, &sockaddr->sin6.sin6_addr)) {
return &sc_acsession;
}
}
}
TRACEKMOD("### sc_capwap_send\n");
return NULL;
return kernel_sendmsg(session->socket, &msg, &vec, 1, vec.iov_len);
}
/* */
void sc_capwap_recvpacket(struct sk_buff* skb) {
union capwap_addr peeraddr;
int sc_capwap_recvpacket(struct sock *sk, struct sk_buff* skb)
{
struct sc_capwap_session* session;
TRACEKMOD("### sc_capwap_recvpacket\n");
/* Get peer address */
if (sc_socket_getpeeraddr(skb, &peeraddr)) {
goto drop;
}
CAPWAP_SKB_CB(skb)->flags = SKB_CAPWAP_FLAG_FROM_DATA_CHANNEL;
sock_hold(sk);
/* Get session */
session = sc_capwap_getsession(&peeraddr);
session = (struct sc_capwap_session *)sk->sk_user_data;
if (!session) {
TRACEKMOD("*** Session not found\n");
goto drop;
}
/* Remove UDP header */
@ -145,26 +122,33 @@ void sc_capwap_recvpacket(struct sk_buff* skb) {
}
/* Parsing packet */
if (sc_capwap_parsingpacket(session, &peeraddr, skb)) {
if (sc_capwap_parsingpacket(session, skb)) {
TRACEKMOD("*** Parsing error\n");
goto drop;
}
return;
sock_put(sk);
return 0;
drop:
sock_put(sk);
kfree_skb(skb);
return 0;
}
/* */
struct sc_capwap_session* sc_capwap_recvunknownkeepalive(const union capwap_addr* sockaddr, const struct sc_capwap_sessionid_element* sessionid) {
struct sc_capwap_session* sc_capwap_recvunknownkeepalive(struct sc_capwap_session* session,
const struct sc_capwap_sessionid_element* sessionid)
{
TRACEKMOD("### sc_capwap_recvunknownkeepalive\n");
return NULL;
}
/* */
void sc_capwap_parsingdatapacket(struct sc_capwap_session* session, struct sk_buff* skb) {
void sc_capwap_parsingdatapacket(struct sc_capwap_session* session, struct sk_buff* skb)
{
uint8_t* pos;
uint8_t* dstaddress;
struct net_device* dev;

View File

@ -10,19 +10,16 @@ struct sc_capwap_workthread {
};
/* */
int sc_capwap_init(struct net *net);
void sc_capwap_close(void);
int sc_capwap_init(struct sc_capwap_session *sc_acsession, struct net *net);
/* */
int sc_capwap_connect(struct net *net, const union capwap_addr* sockaddr,
int sc_capwap_connect(struct sc_capwap_session *session,
struct sockaddr_storage *peeraddr,
struct sc_capwap_sessionid_element* sessionid, uint16_t mtu);
void sc_capwap_resetsession(void);
void sc_capwap_resetsession(struct sc_capwap_session *sc_acsession);
/* */
struct sc_capwap_session* sc_capwap_getsession(const union capwap_addr* sockaddr);
/* */
int sc_capwap_sendkeepalive(void);
int sc_capwap_sendkeepalive(struct sc_capwap_session *sc_acsession);
#endif /* __KMOD_CAPWAP_PRIVATE_HEADER__ */

View File

@ -27,6 +27,7 @@ struct sc_netlink_device {
uint8_t wlanid;
uint8_t binding;
struct net_device* dev;
struct net *net;
uint32_t flags;
};
@ -35,6 +36,8 @@ static int sc_net_id __read_mostly;
struct sc_net {
uint32_t sc_netlink_usermodeid;
struct sc_capwap_session sc_acsession;
struct list_head sc_netlink_dev_list;
};
@ -66,9 +69,12 @@ static struct genl_family sc_netlink_family = {
};
/* */
static int sc_netlink_handler(uint32_t ifindex, struct sk_buff* skb, int sig_dbm, unsigned char rate, void* data) {
static int sc_netlink_handler(uint32_t ifindex, struct sk_buff* skb,
int sig_dbm, unsigned char rate, void* data)
{
int ret = 0;
struct sc_netlink_device* nldev = (struct sc_netlink_device*)data;
struct sc_net *sn = net_generic(nldev->net, sc_net_id);
struct ieee80211_hdr* hdr = (struct ieee80211_hdr*)skb->data;
TRACEKMOD("### sc_netlink_handler\n");
@ -76,7 +82,6 @@ static int sc_netlink_handler(uint32_t ifindex, struct sk_buff* skb, int sig_dbm
/* IEEE802.11 Data Packet */
if (ieee80211_is_data(hdr->frame_control)) {
int err;
struct sc_capwap_session* session;
uint8_t radioaddrbuffer[CAPWAP_RADIO_EUI48_LENGTH_PADDED];
uint8_t winfobuffer[CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED];
struct sc_capwap_radio_addr* radioaddr = NULL;
@ -85,12 +90,6 @@ static int sc_netlink_handler(uint32_t ifindex, struct sk_buff* skb, int sig_dbm
/* Drop packet */
ret = -1;
/* */
session = sc_capwap_getsession(NULL);
if (!session) {
goto error;
}
/* IEEE 802.11 into IEEE 802.3 */
if (nldev->flags & NLSMARTCAPWAP_FLAGS_TUNNEL_8023) {
if (ieee80211_data_to_8023(skb, nldev->dev->dev_addr, NL80211_IFTYPE_AP)) {
@ -110,7 +109,7 @@ static int sc_netlink_handler(uint32_t ifindex, struct sk_buff* skb, int sig_dbm
CAPWAP_SKB_CB(skb)->flags = SKB_CAPWAP_FLAG_FROM_IEEE80211;
/* Forward to AC */
err = sc_capwap_forwarddata(session, nldev->radioid, nldev->binding, skb, nldev->flags, radioaddr, (radioaddr ? CAPWAP_RADIO_EUI48_LENGTH_PADDED : 0), winfo, (winfo ? CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED : 0));
err = sc_capwap_forwarddata(&sn->sc_acsession, nldev->radioid, nldev->binding, skb, nldev->flags, radioaddr, (radioaddr ? CAPWAP_RADIO_EUI48_LENGTH_PADDED : 0), winfo, (winfo ? CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED : 0));
}
error:
@ -153,6 +152,7 @@ static struct sc_netlink_device* sc_netlink_new_device(struct net *net, uint32_t
nldev->wlanid = wlanid;
nldev->binding = binding;
nldev->dev = dev;
nldev->net = net;
return nldev;
}
@ -268,7 +268,7 @@ static int sc_netlink_link(struct sk_buff* skb, struct genl_info* info)
}
/* Initialize library */
ret = sc_capwap_init(net);
ret = sc_capwap_init(&sn->sc_acsession, net);
if (ret) {
return ret;
}
@ -297,7 +297,7 @@ static int sc_netlink_reset(struct sk_buff* skb, struct genl_info* info)
sc_netlink_unregister_alldevice(sn);
/* Reset session */
sc_capwap_resetsession();
sc_capwap_resetsession(&sn->sc_acsession);
return 0;
}
@ -319,7 +319,7 @@ static int sc_netlink_notify(struct notifier_block* nb,
sc_netlink_unregister_alldevice(sn);
/* Close capwap engine */
sc_capwap_close();
sc_capwap_close(&sn->sc_acsession);
/* Allow unload module */
module_put(THIS_MODULE);
@ -335,14 +335,12 @@ static int sc_netlink_bind(struct sk_buff* skb, struct genl_info* info)
{
struct net *net = genl_info_net(info);
struct sc_net *sn = net_generic(net, sc_net_id);
union capwap_addr sockaddr;
TRACEKMOD("### sc_netlink_bind\n");
/* Check Link */
if (!sn->sc_netlink_usermodeid) {
if (!sn->sc_netlink_usermodeid)
return -ENOLINK;
}
/* Get bind address */
if (!info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS] ||
@ -350,13 +348,9 @@ static int sc_netlink_bind(struct sk_buff* skb, struct genl_info* info)
return -EINVAL;
}
memcpy(&sockaddr.ss, nla_data(info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]), sizeof(struct sockaddr_storage));
if ((sockaddr.ss.ss_family != AF_INET) && (sockaddr.ss.ss_family != AF_INET6)) {
return -EINVAL;
}
/* Bind socket */
return sc_capwap_bind(net, &sockaddr);
return sc_capwap_bind(&sn->sc_acsession, IPPROTO_UDP,
(struct sockaddr_storage *)nla_data(info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]));
}
/* */
@ -365,16 +359,13 @@ static int sc_netlink_connect(struct sk_buff* skb, struct genl_info* info)
struct net *net = genl_info_net(info);
struct sc_net *sn = net_generic(net, sc_net_id);
int ret;
union capwap_addr sockaddr;
struct sc_capwap_sessionid_element sessionid;
uint16_t mtu = DEFAULT_MTU;
TRACEKMOD("### sc_netlink_connect\n");
/* Check Link */
if (!sn->sc_netlink_usermodeid) {
if (!sn->sc_netlink_usermodeid)
return -ENOLINK;
}
/* Get AC address */
if (!info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS] ||
@ -382,11 +373,6 @@ static int sc_netlink_connect(struct sk_buff* skb, struct genl_info* info)
return -EINVAL;
}
memcpy(&sockaddr.ss, nla_data(info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]), sizeof(struct sockaddr_storage));
if ((sockaddr.ss.ss_family != AF_INET) && (sockaddr.ss.ss_family != AF_INET6)) {
return -EINVAL;
}
/* Get MTU */
if (info->attrs[NLSMARTCAPWAP_ATTR_MTU]) {
mtu = nla_get_u16(info->attrs[NLSMARTCAPWAP_ATTR_MTU]);
@ -395,19 +381,18 @@ static int sc_netlink_connect(struct sk_buff* skb, struct genl_info* info)
}
}
/* Get Session ID */
if (info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID] &&
(nla_len(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID]) == sizeof(struct sc_capwap_sessionid_element))) {
memcpy(sessionid.id, nla_data(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID]), sizeof(struct sc_capwap_sessionid_element));
} else {
if (!info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID] ||
nla_len(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID]) != sizeof(struct sc_capwap_sessionid_element)) {
return -EINVAL;
}
/* Send packet */
ret = sc_capwap_connect(net, &sockaddr, &sessionid, mtu);
if (ret < 0) {
ret = sc_capwap_connect(&sn->sc_acsession,
(struct sockaddr_storage *)nla_data(info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]),
(struct sc_capwap_sessionid_element *)nla_data(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID]),
mtu);
if (ret < 0)
return ret;
}
return 0;
}
@ -422,12 +407,11 @@ static int sc_netlink_send_keepalive(struct sk_buff* skb, struct genl_info* info
TRACEKMOD("### sc_netlink_send_keepalive\n");
/* Check Link */
if (!sn->sc_netlink_usermodeid) {
if (!sn->sc_netlink_usermodeid)
return -ENOLINK;
}
/* Send packet */
ret = sc_capwap_sendkeepalive();
ret = sc_capwap_sendkeepalive(&sn->sc_acsession);
if (ret < 0) {
return ret;
}
@ -448,7 +432,6 @@ static int sc_netlink_send_data(struct sk_buff* skb, struct genl_info* info)
uint16_t rate = 0;
int length;
struct sk_buff* skbdata;
struct sc_capwap_session* session;
unsigned char winfobuffer[CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED];
struct sc_capwap_wireless_information* winfo = NULL;
@ -462,12 +445,6 @@ static int sc_netlink_send_data(struct sk_buff* skb, struct genl_info* info)
return -EINVAL;
}
/* */
session = sc_capwap_getsession(NULL);
if (!session) {
return -ENOLINK;
}
/* Get radioid */
radioid = nla_get_u8(info->attrs[NLSMARTCAPWAP_ATTR_RADIOID]);
if (!IS_VALID_RADIOID(radioid) || !info->attrs[NLSMARTCAPWAP_ATTR_BINDING]) {
@ -514,7 +491,7 @@ static int sc_netlink_send_data(struct sk_buff* skb, struct genl_info* info)
CAPWAP_SKB_CB(skb)->flags = SKB_CAPWAP_FLAG_FROM_USER_SPACE;
/* Send packet */
ret = sc_capwap_forwarddata(session, radioid, binding, skbdata, 0, NULL, 0, winfo, (winfo ? CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED : 0));
ret = sc_capwap_forwarddata(&sn->sc_acsession, radioid, binding, skbdata, 0, NULL, 0, winfo, (winfo ? CAPWAP_WINFO_FRAMEINFO_LENGTH_PADDED : 0));
if (ret) {
TRACEKMOD("*** Unable send packet from sc_netlink_send_data function\n");
}
@ -727,7 +704,6 @@ struct notifier_block sc_device_notifier = {
/* */
int sc_netlink_notify_recv_keepalive(struct net *net,
const union capwap_addr* sockaddr,
struct sc_capwap_sessionid_element* sessionid)
{
struct sc_net *sn = net_generic(net, sc_net_id);
@ -803,11 +779,14 @@ struct net_device* sc_netlink_getdev_from_wlanid(struct net *net,
TRACEKMOD("### sc_netlink_getdev_from_wlanid\n");
/* Search */
list_for_each_entry(nldev, &sn->sc_netlink_dev_list, list) {
rcu_read_lock();
list_for_each_entry_rcu(nldev, &sn->sc_netlink_dev_list, list) {
if ((nldev->radioid == radioid) && (nldev->wlanid == wlanid)) {
rcu_read_unlock();
return nldev->dev;
}
}
rcu_read_unlock();
return NULL;
}
@ -823,11 +802,14 @@ struct net_device* sc_netlink_getdev_from_bssid(struct net *net,
TRACEKMOD("### sc_netlink_getdev_from_bssid\n");
/* Search */
list_for_each_entry(nldev, &sn->sc_netlink_dev_list, list) {
rcu_read_lock();
list_for_each_entry_rcu(nldev, &sn->sc_netlink_dev_list, list) {
if ((nldev->radioid == radioid) && !memcmp(nldev->dev->dev_addr, addr, MACADDRESS_EUI48_LENGTH)) {
rcu_read_unlock();
return nldev->dev;
}
}
rcu_read_unlock();
return NULL;
}
@ -837,7 +819,7 @@ static int __net_init sc_net_init(struct net *net)
struct sc_net *sn = net_generic(net, sc_net_id);
sn->sc_netlink_usermodeid = 0;
INIT_LIST_HEAD(&sn->sc_netlink_dev_list);
INIT_LIST_HEAD_RCU(&sn->sc_netlink_dev_list);
return 0;
}

View File

@ -2,7 +2,7 @@
#define __KMOD_WTP_NETLINKAPP_HEADER__
#include "capwap_rfc.h"
#include "socket.h"
#include "capwap.h"
/* */
int sc_netlink_init(void);
@ -14,7 +14,6 @@ struct net_device* sc_netlink_getdev_from_bssid(struct net *net, uint8_t radioid
/* */
int sc_netlink_notify_recv_keepalive(struct net *net,
const union capwap_addr* sockaddr,
struct sc_capwap_sessionid_element* sessionid);
int sc_netlink_notify_recv_data(struct net *net, uint8_t* packet, int length);

View File

@ -1,227 +0,0 @@
#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(struct net *net, int type, union capwap_addr* sockaddr, uint16_t protocol) {
int ret;
TRACEKMOD("### sc_socket_create\n");
/* Create socket */
ret = sock_create_kern(net, 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(struct net *net, 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(net, SOCKET_UDP, sockaddr, IPPROTO_UDP);
if (ret) {
goto failure;
}
/* UDPLite socket */
ret = sc_socket_create(net, 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;
}

View File

@ -1,35 +0,0 @@
#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(struct net *net, 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__ */

View File

@ -1229,12 +1229,6 @@ static int wtp_configure(void) {
return WTP_ERROR_NETWORK;
}
/* Bind data address */
if (wtp_kmod_bind(g_wtp.net.localaddr.ss.ss_family)) {
capwap_logging_fatal("Cannot bind data address");
return WTP_ERROR_NETWORK;
}
return CAPWAP_SUCCESSFUL;
}

View File

@ -39,8 +39,9 @@ void wtp_start_datachannel(void) {
}
#endif
/* Connect to AC data channel */
if (!wtp_kmod_connect(&dataaddr.ss, &g_wtp.sessionid, g_wtp.mtu)) {
/* Bind data address and Connect to AC data channel */
if (wtp_kmod_bind(g_wtp.net.localaddr.ss.ss_family) ||
!wtp_kmod_connect(&dataaddr.ss, &g_wtp.sessionid, g_wtp.mtu)) {
/* Reset AC Prefered List Position */
g_wtp.acpreferedselected = 0;