diff --git a/src/wtp/kmod/capwap.c b/src/wtp/kmod/capwap.c index e0ae91b..19ff817 100644 --- a/src/wtp/kmod/capwap.c +++ b/src/wtp/kmod/capwap.c @@ -3,22 +3,22 @@ #include #include #include -#include "socket.h" +#include +#include + #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; diff --git a/src/wtp/kmod/capwap.h b/src/wtp/kmod/capwap.h index 4cd5750..a2ebbb1 100644 --- a/src/wtp/kmod/capwap.h +++ b/src/wtp/kmod/capwap.h @@ -1,8 +1,12 @@ #ifndef __KMOD_CAPWAP_HEADER__ #define __KMOD_CAPWAP_HEADER__ +#include +#include +#include +#include + #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); diff --git a/src/wtp/kmod/capwap_private.c b/src/wtp/kmod/capwap_private.c index da5c7b6..b1a567a 100644 --- a/src/wtp/kmod/capwap_private.c +++ b/src/wtp/kmod/capwap_private.c @@ -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; diff --git a/src/wtp/kmod/capwap_private.h b/src/wtp/kmod/capwap_private.h index 630c005..a42d64c 100644 --- a/src/wtp/kmod/capwap_private.h +++ b/src/wtp/kmod/capwap_private.h @@ -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__ */ diff --git a/src/wtp/kmod/netlinkapp.c b/src/wtp/kmod/netlinkapp.c index 0b31d02..1d4637e 100644 --- a/src/wtp/kmod/netlinkapp.c +++ b/src/wtp/kmod/netlinkapp.c @@ -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; } diff --git a/src/wtp/kmod/netlinkapp.h b/src/wtp/kmod/netlinkapp.h index 895e615..8de341f 100644 --- a/src/wtp/kmod/netlinkapp.h +++ b/src/wtp/kmod/netlinkapp.h @@ -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); diff --git a/src/wtp/kmod/socket.c b/src/wtp/kmod/socket.c deleted file mode 100644 index 151e7de..0000000 --- a/src/wtp/kmod/socket.c +++ /dev/null @@ -1,227 +0,0 @@ -#include "config.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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; -} diff --git a/src/wtp/kmod/socket.h b/src/wtp/kmod/socket.h deleted file mode 100644 index ab6d84d..0000000 --- a/src/wtp/kmod/socket.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef __KMOD_SOCKET_HEADER__ -#define __KMOD_SOCKET_HEADER__ - -#include -#include -#include -#include - -/* */ -#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__ */ diff --git a/src/wtp/wtp.c b/src/wtp/wtp.c index d26b244..014a602 100644 --- a/src/wtp/wtp.c +++ b/src/wtp/wtp.c @@ -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; } diff --git a/src/wtp/wtp_dfa_dtls.c b/src/wtp/wtp_dfa_dtls.c index b604646..1dd5bde 100644 --- a/src/wtp/wtp_dfa_dtls.c +++ b/src/wtp/wtp_dfa_dtls.c @@ -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;