rework kernel socket handling to use udp tunnel infrastructure

Reimplmenting what is already there doesn't make sense. Switch
to the existing and UDP tunnel support code and handle the data
channel as a connected UDP socket
This commit is contained in:
Andreas Schultz 2016-02-22 16:54:54 +01:00
parent cc5b38f322
commit f3119eec8d
9 changed files with 92 additions and 151 deletions

View File

@ -402,52 +402,52 @@ int sc_capwap_80211_to_8023(struct sk_buff* skb) {
return 0;
}
int sc_capwap_bind(struct sc_capwap_session *session, int protocol, struct sockaddr_storage *sockaddr)
int sc_capwap_create(struct sc_capwap_session *session)
{
int ret;
int err;
struct udp_tunnel_sock_cfg cfg = {
.sk_user_data = session,
.encap_type = 1,
.encap_rcv = sc_capwap_recvpacket
};
TRACEKMOD("### sc_capwap_bind\n");
if (session->socket)
return -EBUSY;
ret = sock_create_kern(session->net, sockaddr->ss_family, SOCK_DGRAM, protocol, &session->socket);
if (ret < 0)
return ret;
/* Open UDP socket */
err = udp_sock_create(session->net, &session->udp_config, &session->socket);
if (err < 0)
goto error;
ret = kernel_bind(session->socket, (struct sockaddr *)sockaddr, sizeof(struct sockaddr_storage));
if (ret < 0)
goto err_close;
setup_udp_tunnel_sock(session->net, session->socket, &cfg);
rcu_assign_sk_user_data(session->socket->sk, session);
/* 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)
if (session->udp_config.family == AF_INET6)
udpv6_encap_enable();
return 0;
err = sc_capwap_sendkeepalive(session);
if (err < 0)
goto error;
err_close:
kernel_sock_shutdown(session->socket, SHUT_RDWR);
sock_release(session->socket);
return err;
error:
if (session->socket)
udp_tunnel_sock_release(session->socket);
session->socket = NULL;
return ret;
return err;
}
void sc_capwap_close(struct sc_capwap_session *session)
{
TRACEKMOD("### sc_capwap_close\n");
if (session->socket) {
kernel_sock_shutdown(session->socket, SHUT_RDWR);
sock_release(session->socket);
}
if (session->socket)
udp_tunnel_sock_release(session->socket);
session->socket = NULL;
sc_capwap_freesession(session);
}

View File

@ -6,6 +6,11 @@
#include <linux/in6.h>
#include <linux/skbuff.h>
#include <net/protocol.h>
#include <net/ip.h>
#include <net/udp.h>
#include <net/udp_tunnel.h>
#include "capwap_rfc.h"
/* */
@ -105,6 +110,7 @@ struct sc_capwap_session {
struct net *net;
struct socket *socket;
struct udp_port_cfg udp_config;
uint16_t mtu;
struct sc_capwap_sessionid_element sessionid;
@ -123,8 +129,7 @@ void sc_capwap_parsingdatapacket(struct sc_capwap_session* session, struct sk_bu
void sc_capwap_parsingmgmtpacket(struct sc_capwap_session* session, struct sk_buff* skb);
/* Indipendent implementation function */
int sc_capwap_bind(struct sc_capwap_session *session, int protocol,
struct sockaddr_storage *sockaddr);
int sc_capwap_create(struct sc_capwap_session *session);
int sc_capwap_send(struct sc_capwap_session *session, uint8_t* buffer, int length);
void sc_capwap_close(struct sc_capwap_session *session);

View File

@ -38,26 +38,6 @@ int sc_capwap_init(struct sc_capwap_session *session, struct net *net)
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_resetsession(struct sc_capwap_session *session)
{

View File

@ -16,9 +16,6 @@ struct sc_station *sc_find_station(struct hlist_head *sta_head, uint8_t radioid,
int sc_capwap_init(struct sc_capwap_session *sc_acsession, struct net *net);
/* */
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(struct sc_capwap_session *sc_acsession);
/* */

View File

@ -331,71 +331,65 @@ static int sc_netlink_notify(struct notifier_block* nb,
return NOTIFY_DONE;
}
static void cfg_assign_ip(void *ip, __be16 *port, struct sockaddr_storage *addr)
{
if (addr->ss_family == AF_INET) {
memcpy(ip, &((struct sockaddr_in *)addr)->sin_addr, sizeof(struct in_addr));
*port = ((struct sockaddr_in *)addr)->sin_port;
}
#if IS_ENABLED(CONFIG_IPV6)
if (addr->ss_family == AF_INET6) {
memcpy(ip, &((struct sockaddr_in6 *)addr)->sin6_addr, sizeof(struct in6_addr));
*port = ((struct sockaddr_in6 *)addr)->sin6_port;
}
#endif
}
/* */
static int sc_netlink_bind(struct sk_buff* skb, struct genl_info* info)
static int sc_netlink_create(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);
struct sc_capwap_session *session = &sn->sc_acsession;
struct udp_port_cfg *cfg = &session->udp_config;
struct sockaddr_storage *local, *peer;
uint16_t mtu = DEFAULT_MTU;
TRACEKMOD("### sc_netlink_bind\n");
TRACEKMOD("### sc_netlink_create\n");
/* Check Link */
if (!sn->sc_netlink_usermodeid)
return -ENOLINK;
/* Get bind address */
if (!info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS] ||
(nla_len(info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]) != sizeof(struct sockaddr_storage))) {
if (!info->attrs[NLSMARTCAPWAP_ATTR_LOCAL_ADDRESS] ||
!info->attrs[NLSMARTCAPWAP_ATTR_PEER_ADDRESS] ||
!info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID])
return -EINVAL;
}
/* Bind socket */
return sc_capwap_bind(&sn->sc_acsession, IPPROTO_UDP,
(struct sockaddr_storage *)nla_data(info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]));
}
/* */
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;
uint16_t mtu = DEFAULT_MTU;
TRACEKMOD("### sc_netlink_connect\n");
/* Check Link */
if (!sn->sc_netlink_usermodeid)
return -ENOLINK;
/* Get AC address */
if (!info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS] ||
(nla_len(info->attrs[NLSMARTCAPWAP_ATTR_ADDRESS]) != sizeof(struct sockaddr_storage))) {
return -EINVAL;
}
/* Get MTU */
if (info->attrs[NLSMARTCAPWAP_ATTR_MTU]) {
mtu = nla_get_u16(info->attrs[NLSMARTCAPWAP_ATTR_MTU]);
if ((mtu < MIN_MTU) || (mtu > MAX_MTU)) {
if ((mtu < MIN_MTU) || (mtu > MAX_MTU))
return -EINVAL;
}
}
if (!info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID] ||
nla_len(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID]) != sizeof(struct sc_capwap_sessionid_element)) {
return -EINVAL;
}
memcpy(&session->sessionid, nla_data(info->attrs[NLSMARTCAPWAP_ATTR_SESSION_ID]),
sizeof(struct sc_capwap_sessionid_element));
session->mtu = mtu;
/* Send packet */
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;
local = (struct sockaddr_storage *)nla_data(info->attrs[NLSMARTCAPWAP_ATTR_LOCAL_ADDRESS]);
peer = (struct sockaddr_storage *)nla_data(info->attrs[NLSMARTCAPWAP_ATTR_PEER_ADDRESS]);
return 0;
cfg->family = peer->ss_family;
cfg_assign_ip(&cfg->local_ip, &cfg->local_udp_port, local);
cfg_assign_ip(&cfg->peer_ip, &cfg->peer_udp_port, peer);
cfg->use_udp_checksums = 1;
cfg->use_udp6_tx_checksums = 1;
cfg->use_udp6_rx_checksums = 1;
return sc_capwap_create(session);
}
/* */
@ -728,9 +722,10 @@ static const struct nla_policy sc_netlink_policy[NLSMARTCAPWAP_ATTR_MAX + 1] = {
[NLSMARTCAPWAP_ATTR_MGMT_SUBTYPE_MASK] = { .type = NLA_U16 },
[NLSMARTCAPWAP_ATTR_CTRL_SUBTYPE_MASK] = { .type = NLA_U16 },
[NLSMARTCAPWAP_ATTR_DATA_SUBTYPE_MASK] = { .type = NLA_U16 },
[NLSMARTCAPWAP_ATTR_ADDRESS] = { .type = NLA_BINARY, .len = sizeof(struct sockaddr_storage) },
[NLSMARTCAPWAP_ATTR_LOCAL_ADDRESS] = { .len = sizeof(struct sockaddr_storage) },
[NLSMARTCAPWAP_ATTR_PEER_ADDRESS] = { .len = sizeof(struct sockaddr_storage) },
[NLSMARTCAPWAP_ATTR_MTU] = { .type = NLA_U16 },
[NLSMARTCAPWAP_ATTR_SESSION_ID] = { .type = NLA_BINARY, .len = sizeof(struct sc_capwap_sessionid_element) },
[NLSMARTCAPWAP_ATTR_SESSION_ID] = { .len = sizeof(struct sc_capwap_sessionid_element) },
[NLSMARTCAPWAP_ATTR_DTLS] = { .type = NLA_U16 },
[NLSMARTCAPWAP_ATTR_DATA_FRAME] = { .type = NLA_BINARY, .len = IEEE80211_MTU },
[NLSMARTCAPWAP_ATTR_RSSI] = { .type = NLA_U8 },
@ -748,14 +743,8 @@ static const struct genl_ops sc_netlink_ops[] = {
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NLSMARTCAPWAP_CMD_BIND,
.doit = sc_netlink_bind,
.policy = sc_netlink_policy,
.flags = GENL_ADMIN_PERM,
},
{
.cmd = NLSMARTCAPWAP_CMD_CONNECT,
.doit = sc_netlink_connect,
.cmd = NLSMARTCAPWAP_CMD_CREATE,
.doit = sc_netlink_create,
.policy = sc_netlink_policy,
.flags = GENL_ADMIN_PERM,
},

View File

@ -22,7 +22,8 @@ enum nlsmartcapwap_attrs {
NLSMARTCAPWAP_ATTR_CTRL_SUBTYPE_MASK,
NLSMARTCAPWAP_ATTR_DATA_SUBTYPE_MASK,
NLSMARTCAPWAP_ATTR_ADDRESS,
NLSMARTCAPWAP_ATTR_LOCAL_ADDRESS,
NLSMARTCAPWAP_ATTR_PEER_ADDRESS,
NLSMARTCAPWAP_ATTR_MTU,
NLSMARTCAPWAP_ATTR_SESSION_ID,
@ -47,8 +48,7 @@ enum nlsmartcapwap_commands {
NLSMARTCAPWAP_CMD_LINK,
NLSMARTCAPWAP_CMD_BIND,
NLSMARTCAPWAP_CMD_CONNECT,
NLSMARTCAPWAP_CMD_CREATE,
NLSMARTCAPWAP_CMD_RESET,
NLSMARTCAPWAP_CMD_SEND_KEEPALIVE,

View File

@ -40,8 +40,8 @@ void wtp_start_datachannel(void) {
#endif
/* 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)) {
if (wtp_kmod_create(g_wtp.net.localaddr.ss.ss_family, &dataaddr.ss, &g_wtp.sessionid, g_wtp.mtu) == 0) {
capwap_logging_error("Data channel connected");
/* Reset AC Prefered List Position */
g_wtp.acpreferedselected = 0;

View File

@ -198,63 +198,33 @@ static void wtp_kmod_event_receive(int fd, void** params, int paramscount) {
}
/* */
int wtp_kmod_bind(uint16_t family) {
int wtp_kmod_create(uint16_t family, struct sockaddr_storage* peeraddr,
struct capwap_sessionid_element* sessionid, uint16_t mtu) {
int result;
struct nl_msg* msg;
struct sockaddr_storage sockaddr;
ASSERT((family == AF_INET) || (family == AF_INET6));
ASSERT(peeraddr != NULL);
ASSERT((peeraddr->ss_family == AF_INET) || (peeraddr->ss_family == AF_INET6));
ASSERT(sessionid != NULL);
/* */
if (!wtp_kmod_isconnected()) {
if (!wtp_kmod_isconnected())
return -1;
}
/* */
msg = nlmsg_alloc();
if (!msg) {
if (!msg)
return -1;
}
/* */
memset(&sockaddr, 0, sizeof(struct sockaddr_storage));
sockaddr.ss_family = family;
/* */
genlmsg_put(msg, 0, 0, g_wtp.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_BIND, 0);
nla_put(msg, NLSMARTCAPWAP_ATTR_ADDRESS, sizeof(struct sockaddr_storage), &sockaddr);
/* */
result = wtp_kmod_send_and_recv_msg(msg, NULL, NULL);
/* */
nlmsg_free(msg);
return result;
}
/* */
int wtp_kmod_connect(struct sockaddr_storage* sockaddr, struct capwap_sessionid_element* sessionid, uint16_t mtu) {
int result;
struct nl_msg* msg;
ASSERT(sockaddr != NULL);
ASSERT((sockaddr->ss_family == AF_INET) || (sockaddr->ss_family == AF_INET6));
ASSERT(sessionid != NULL);
/* */
if (!wtp_kmod_isconnected()) {
return -1;
}
/* */
msg = nlmsg_alloc();
if (!msg) {
return -1;
}
/* */
genlmsg_put(msg, 0, 0, g_wtp.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_CONNECT, 0);
nla_put(msg, NLSMARTCAPWAP_ATTR_ADDRESS, sizeof(struct sockaddr_storage), sockaddr);
genlmsg_put(msg, 0, 0, g_wtp.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_CREATE, 0);
nla_put(msg, NLSMARTCAPWAP_ATTR_LOCAL_ADDRESS, sizeof(struct sockaddr_storage), &sockaddr);
nla_put(msg, NLSMARTCAPWAP_ATTR_PEER_ADDRESS, sizeof(struct sockaddr_storage), peeraddr);
nla_put(msg, NLSMARTCAPWAP_ATTR_SESSION_ID, sizeof(struct capwap_sessionid_element), sessionid);
nla_put_u16(msg, NLSMARTCAPWAP_ATTR_MTU, mtu);

View File

@ -50,8 +50,8 @@ int wtp_kmod_isconnected(void);
int wtp_kmod_getfd(struct pollfd* fds, struct wtp_kmod_event* events, int count);
/* */
int wtp_kmod_bind(uint16_t family);
int wtp_kmod_connect(struct sockaddr_storage* sockaddr, struct capwap_sessionid_element* sessionid, uint16_t mtu);
int wtp_kmod_create(uint16_t family, struct sockaddr_storage* peeraddr,
struct capwap_sessionid_element* sessionid, uint16_t mtu);
int wtp_kmod_resetsession(void);
/* */