diff --git a/conf/wtp.conf b/conf/wtp.conf index 10ce3e3..f7df662 100755 --- a/conf/wtp.conf +++ b/conf/wtp.conf @@ -12,6 +12,7 @@ application: { binding = "802.11"; tunnelmode: { + dataframe = "usermode"; nativeframe = false; ethframe = false; localbridging = true; diff --git a/src/common/capwap_protocol.c b/src/common/capwap_protocol.c index 092fb01..568c199 100644 --- a/src/common/capwap_protocol.c +++ b/src/common/capwap_protocol.c @@ -202,7 +202,7 @@ void capwap_header_init(struct capwap_header_data* data, unsigned short radioid, } /* */ -void capwap_header_set_radio_macaddress(struct capwap_header_data* data, int radiotype, char* macaddress) { +void capwap_header_set_radio_macaddress(struct capwap_header_data* data, int radiotype, const uint8_t* macaddress) { struct capwap_header* header; ASSERT(data != NULL); @@ -288,6 +288,7 @@ void capwap_header_set_wireless_information(struct capwap_header_data* data, voi /* Remove old wireless information */ if (IS_FLAG_W_HEADER(header)) { + SET_FLAG_W_HEADER(header, 0); SET_HLEN_HEADER(header, size); } @@ -308,6 +309,7 @@ void capwap_header_set_wireless_information(struct capwap_header_data* data, voi /* Update size */ size += lengthpadded; + SET_FLAG_W_HEADER(header, 1); SET_HLEN_HEADER(header, size); } } diff --git a/src/common/capwap_protocol.h b/src/common/capwap_protocol.h index 130b793..8118343 100644 --- a/src/common/capwap_protocol.h +++ b/src/common/capwap_protocol.h @@ -31,7 +31,7 @@ struct capwap_header_data { }; void capwap_header_init(struct capwap_header_data* data, unsigned short radioid, unsigned short binding); -void capwap_header_set_radio_macaddress(struct capwap_header_data* data, int radiotype, char* macaddress); +void capwap_header_set_radio_macaddress(struct capwap_header_data* data, int radiotype, const uint8_t* macaddress); void capwap_header_set_wireless_information(struct capwap_header_data* data, void* buffer, unsigned char length); void capwap_header_set_keepalive_flag(struct capwap_header_data* data, int enable); void capwap_header_set_nativeframe_flag(struct capwap_header_data* data, int enable); diff --git a/src/common/capwap_rfc.h b/src/common/capwap_rfc.h index ba27ce8..4dca1a2 100644 --- a/src/common/capwap_rfc.h +++ b/src/common/capwap_rfc.h @@ -71,20 +71,27 @@ struct capwap_header { /* Mac Address */ struct capwap_mac_address { uint8_t length; - int8_t address[0]; + uint8_t address[0]; } STRUCT_PACKED; /* Wireless Information */ struct capwap_wireless_information { uint8_t length; - int8_t data[0]; + uint8_t data[0]; +} STRUCT_PACKED; + +/* IEEE802.11 Wireless Information */ +struct capwap_ieee80211_frame_info { + uint8_t rssi; + uint8_t snr; + uint16_t rate; } STRUCT_PACKED; /* Message element */ struct capwap_message_element { uint16_t type; uint16_t length; - int8_t data[0]; + uint8_t data[0]; } STRUCT_PACKED; /* Control Message Type */ @@ -132,7 +139,7 @@ struct capwap_control_message { uint8_t seq; uint16_t length; uint8_t flags; - int8_t elements[0]; + uint8_t elements[0]; } STRUCT_PACKED; /* Data Message Keep-Alive*/ @@ -140,11 +147,11 @@ struct capwap_control_message { struct capwap_data_message { uint16_t length; - int8_t elements[0]; + uint8_t elements[0]; } STRUCT_PACKED; /* Capwap dtls header helper */ -#define GET_DTLS_BODY(x) (void*)(((int8_t*)(x)) + sizeof(struct capwap_dtls_header)) +#define GET_DTLS_BODY(x) (void*)(((uint8_t*)(x)) + sizeof(struct capwap_dtls_header)) /* Capwap header helper */ #define GET_VERSION_HEADER(x) ((x)->preamble.version) @@ -182,9 +189,9 @@ struct capwap_data_message { #define GET_FRAGMENT_OFFSET_HEADER(x) (ntohs((x)->frag_off) & FRAGMENT_OFFSET_MASK) #define SET_FRAGMENT_OFFSET_HEADER(x, y) ((x)->frag_off &= ~FRAGMENT_OFFSET_MASK, (x)->frag_off |= htons((uint16_t)(y) & FRAGMENT_OFFSET_MASK)) -#define GET_RADIO_MAC_ADDRESS_STRUCT(x) ((struct capwap_mac_address*)(((int8_t*)(x)) + sizeof(struct capwap_header))) -#define GET_WIRELESS_INFORMATION_STRUCT(x) ((struct capwap_wireless_information*)(((int8_t*)(x)) + sizeof(struct capwap_header) + (IS_FLAG_M_HEADER(x) ? (((GET_RADIO_MAC_ADDRESS_STRUCT(x)->length + sizeof(struct capwap_mac_address)) + 3) / 4) * 4 : 0))) -#define GET_PAYLOAD_HEADER(x) ((void*)(((int8_t*)(x)) + GET_HLEN_HEADER(x) * 4)) +#define GET_RADIO_MAC_ADDRESS_STRUCT(x) ((struct capwap_mac_address*)(((uint8_t*)(x)) + sizeof(struct capwap_header))) +#define GET_WIRELESS_INFORMATION_STRUCT(x) ((struct capwap_wireless_information*)(((uint8_t*)(x)) + sizeof(struct capwap_header) + (IS_FLAG_M_HEADER(x) ? (((GET_RADIO_MAC_ADDRESS_STRUCT(x)->length + sizeof(struct capwap_mac_address)) + 3) / 4) * 4 : 0))) +#define GET_PAYLOAD_HEADER(x) ((void*)(((uint8_t*)(x)) + GET_HLEN_HEADER(x) * 4)) #define IS_SEQUENCE_SMALLER(s1, s2) (((((s1) < (s2)) && (((s2) - (s1)) < 128)) || (((s1) > (s2)) && (((s1) - (s2)) > 128))) ? 1 : 0) diff --git a/src/kmod/netlinkapp.c b/src/kmod/netlinkapp.c index b34b248..e97a266 100644 --- a/src/kmod/netlinkapp.c +++ b/src/kmod/netlinkapp.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "nlsmartcapwap.h" #include "netlinkapp.h" @@ -13,6 +14,7 @@ struct nlsmartcapwap_device { struct list_head list; struct ieee80211_pcktunnel pcktunnel_handler; + u32 usermodeid; u32 ifindex; u32 flags; }; @@ -46,49 +48,56 @@ static struct genl_family nlsmartcapwap_family = { /* */ static int nlsmartcapwap_handler(u32 ifindex, struct sk_buff* skb, int sig_dbm, unsigned char rate, void* data) { + int result = 0; + int frame8023 = 0; struct nlsmartcapwap_device* nldev = (struct nlsmartcapwap_device*)data; struct ieee80211_hdr* hdr = (struct ieee80211_hdr*)skb->data; - /* Check source network */ - if (ifindex == nldev->ifindex) { - if (nldev->flags & SMARTCAPWAP_FLAGS_SEND_USERSPACE) { - void* msg; - struct sk_buff* sk_msg; + /* IEEE802.11 Data Packet */ + if (ieee80211_is_data(hdr->frame_control)) { + if ((nldev->flags & SMARTCAPWAP_FLAGS_BLOCK_DATA_FRAME) && ieee80211_is_data_present(hdr->frame_control)) { + result = -1; + } - /* Alloc message */ - sk_msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); - if (sk_msg) { - /* Set command */ - msg = genlmsg_put(sk_msg, 0, 0, &nlsmartcapwap_family, 0, NLSMARTCAPWAP_CMD_FRAME); - if (msg) { - /* Set params */ - if (nla_put_u32(sk_msg, NLSMARTCAPWAP_ATTR_IFINDEX, nldev->ifindex) || - nla_put(sk_msg, NLSMARTCAPWAP_ATTR_FRAME, skb->len, skb->data) || - (sig_dbm && nla_put_u32(sk_msg, NLSMARTCAPWAP_ATTR_RX_SIGNAL_DBM, (u32)sig_dbm)) || - (rate && nla_put_u8(sk_msg, NLSMARTCAPWAP_ATTR_RX_RATE, (u8)rate))) { + /* Convert IEEE802.11 to IEEE802.3 */ + if (nldev->flags & SMARTCAPWAP_FLAGS_TUNNEL_8023) { + frame8023 = 1; + } + } - /* Abort message */ - genlmsg_cancel(sk_msg, msg); - nlmsg_free(sk_msg); - } else { - /* Send message */ - genlmsg_end(sk_msg, msg); - genlmsg_unicast(&init_net, sk_msg, nlsmartcapwap_usermodeid); - } - } else { + /* */ + if (nldev->flags & SMARTCAPWAP_FLAGS_SEND_USERSPACE) { + void* msg; + struct sk_buff* sk_msg; + + /* Alloc message */ + sk_msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); + if (sk_msg) { + /* Set command */ + msg = genlmsg_put(sk_msg, 0, 0, &nlsmartcapwap_family, 0, NLSMARTCAPWAP_CMD_FRAME); + if (msg) { + /* Set params */ + if (nla_put_u32(sk_msg, NLSMARTCAPWAP_ATTR_IFINDEX, nldev->ifindex) || + nla_put(sk_msg, NLSMARTCAPWAP_ATTR_FRAME, skb->len, skb->data) || + (frame8023 && nla_put_flag(sk_msg, NLSMARTCAPWAP_ATTR_8023_FRAME)) || + (sig_dbm && nla_put_u32(sk_msg, NLSMARTCAPWAP_ATTR_RX_SIGNAL_DBM, (u32)sig_dbm)) || + (rate && nla_put_u8(sk_msg, NLSMARTCAPWAP_ATTR_RX_RATE, (u8)rate))) { + + /* Abort message */ + genlmsg_cancel(sk_msg, msg); nlmsg_free(sk_msg); + } else { + /* Send message */ + genlmsg_end(sk_msg, msg); + genlmsg_unicast(&init_net, sk_msg, nldev->usermodeid); } + } else { + nlmsg_free(sk_msg); } } } - /* Check if block all IEEE802.11 Data Packet */ - if ((nldev->flags & SMARTCAPWAP_FLAGS_BLOCK_DATA_FRAME) && - ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) { - return -1; - } - - return 0; + return result; } /* */ @@ -254,6 +263,9 @@ static int nlsmartcapwap_join_mac80211_device(struct sk_buff* skb, struct genl_i nldev->pcktunnel_handler.subtype_mask[2] = nla_get_u16(info->attrs[NLSMARTCAPWAP_ATTR_DATA_SUBTYPE_MASK]); } + /* */ + nldev->usermodeid = genl_info_snd_portid(info); + /* Connect device to mac80211 */ ret = ieee80211_pcktunnel_register(ifindex, &nldev->pcktunnel_handler); if (ret) { @@ -289,6 +301,7 @@ static const struct nla_policy nlsmartcapwap_policy[NLSMARTCAPWAP_ATTR_MAX + 1] [NLSMARTCAPWAP_ATTR_CTRL_SUBTYPE_MASK] = { .type = NLA_U16 }, [NLSMARTCAPWAP_ATTR_DATA_SUBTYPE_MASK] = { .type = NLA_U16 }, [NLSMARTCAPWAP_ATTR_FRAME] = { .type = NLA_BINARY, .len = IEEE80211_MAX_DATA_LEN }, + [NLSMARTCAPWAP_ATTR_8023_FRAME] = { .type = NLA_FLAG }, [NLSMARTCAPWAP_ATTR_RX_SIGNAL_DBM] = { .type = NLA_U32 }, [NLSMARTCAPWAP_ATTR_RX_RATE] = { .type = NLA_U8 }, }; diff --git a/src/kmod/nlsmartcapwap.h b/src/kmod/nlsmartcapwap.h index 701e804..3fe27f9 100644 --- a/src/kmod/nlsmartcapwap.h +++ b/src/kmod/nlsmartcapwap.h @@ -7,6 +7,7 @@ /* */ #define SMARTCAPWAP_FLAGS_SEND_USERSPACE 0x00000001 #define SMARTCAPWAP_FLAGS_BLOCK_DATA_FRAME 0x00000002 +#define SMARTCAPWAP_FLAGS_TUNNEL_8023 0x00000004 /* */ enum nlsmartcapwap_attrs { @@ -21,6 +22,7 @@ enum nlsmartcapwap_attrs { NLSMARTCAPWAP_ATTR_DATA_SUBTYPE_MASK, NLSMARTCAPWAP_ATTR_FRAME, + NLSMARTCAPWAP_ATTR_8023_FRAME, NLSMARTCAPWAP_ATTR_RX_SIGNAL_DBM, NLSMARTCAPWAP_ATTR_RX_RATE, diff --git a/src/wtp/binding/ieee80211/wifi_drivers.c b/src/wtp/binding/ieee80211/wifi_drivers.c index 1a693fd..471b10a 100644 --- a/src/wtp/binding/ieee80211/wifi_drivers.c +++ b/src/wtp/binding/ieee80211/wifi_drivers.c @@ -1,9 +1,7 @@ -#include "capwap.h" +#include "wtp.h" #include "capwap_list.h" #include "capwap_element.h" -#include "capwap_network.h" #include "wifi_drivers.h" -#include "wtp.h" #include "wtp_radio.h" /* Declare enable wifi driver */ @@ -316,7 +314,7 @@ static void wifi_wlan_send_mgmt_deauthentication(struct wifi_wlan* wlan, const u capwap_logging_info("Sent IEEE802.11 Deuthentication to %s station", stationaddress); /* Forwards the station deauthentication also to AC */ - wlan->send_frame(wlan->send_frame_to_ac_cbparam, (struct ieee80211_header_mgmt*)g_bufferIEEE80211, responselength); + wifi_wlan_send_frame(wlan, (uint8_t*)g_bufferIEEE80211, responselength, 1, 0, 0, 0); } else { capwap_logging_warning("Unable to send IEEE802.11 Deuthentication to %s station", stationaddress); } @@ -421,7 +419,7 @@ static void wifi_wlan_receive_station_mgmt_probe_request(struct wifi_wlan* wlan, if (!wlan->device->instance->ops->wlan_sendframe(wlan, g_bufferIEEE80211, responselength, wlan->device->currentfrequency.frequency, 0, 0, 0, nowaitack)) { /* If enable Split Mac send the probe request message to AC */ if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) { - wlan->send_frame(wlan->send_frame_to_ac_cbparam, frame, length); + wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, 1, rssi, snr, rate); } } else { capwap_logging_warning("Unable to send IEEE802.11 Probe Response"); @@ -585,10 +583,10 @@ static void wifi_wlan_receive_station_mgmt_authentication(struct wifi_wlan* wlan capwap_logging_info("Sent IEEE802.11 Authentication Response to %s station with %d status code", stationaddress, (int)responsestatuscode); /* Notify authentication request message also to AC */ - wlan->send_frame(wlan->send_frame_to_ac_cbparam, frame, length); + wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, 1, rssi, snr, rate); /* Forwards the authentication response message also to AC */ - wlan->send_frame(wlan->send_frame_to_ac_cbparam, (struct ieee80211_header_mgmt*)g_bufferIEEE80211, responselength); + wifi_wlan_send_frame(wlan, (uint8_t*)g_bufferIEEE80211, responselength, 1, 0, 0, 0); } else if (station) { capwap_logging_warning("Unable to send IEEE802.11 Authentication Response to %s station", stationaddress); wifi_station_delete(station); @@ -598,7 +596,7 @@ static void wifi_wlan_receive_station_mgmt_authentication(struct wifi_wlan* wlan wifi_station_delete(station); } } else if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) { - wlan->send_frame(wlan->send_frame_to_ac_cbparam, frame, length); + wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, 1, rssi, snr, rate); } } @@ -684,10 +682,10 @@ static void wifi_wlan_receive_station_mgmt_association_request(struct wifi_wlan* capwap_logging_info("Sent IEEE802.11 Association Response to %s station with %d status code", station->addrtext, (int)resultstatuscode); /* Notify association request message also to AC */ - wlan->send_frame(wlan->send_frame_to_ac_cbparam, frame, length); + wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, 1, rssi, snr, rate); /* Forwards the association response message also to AC */ - wlan->send_frame(wlan->send_frame_to_ac_cbparam, (struct ieee80211_header_mgmt*)g_bufferIEEE80211, responselength); + wifi_wlan_send_frame(wlan, (uint8_t*)g_bufferIEEE80211, responselength, 1, 0, 0, 0); } else { capwap_logging_warning("Unable to send IEEE802.11 Association Response to %s station", station->addrtext); wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0); @@ -697,7 +695,7 @@ static void wifi_wlan_receive_station_mgmt_association_request(struct wifi_wlan* wifi_wlan_deauthentication_station(wlan, station, IEEE80211_REASON_PREV_AUTH_NOT_VALID, 0); } } else if (wlan->macmode == CAPWAP_ADD_WLAN_MACMODE_SPLIT) { - wlan->send_frame(wlan->send_frame_to_ac_cbparam, frame, length); + wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, 1, rssi, snr, rate); /* Station information */ station->capability = __le16_to_cpu(frame->associationresponse.capability); @@ -731,7 +729,7 @@ static void wifi_wlan_receive_station_mgmt_disassociation(struct wifi_wlan* wlan /* TODO */ /* Notify disassociation message also to AC */ - wlan->send_frame(wlan->send_frame_to_ac_cbparam, frame, length); + wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, 1, rssi, snr, rate); } /* */ @@ -752,7 +750,7 @@ static void wifi_wlan_receive_station_mgmt_deauthentication(struct wifi_wlan* wl } /* Notify deauthentication message also to AC */ - wlan->send_frame(wlan->send_frame_to_ac_cbparam, frame, length); + wifi_wlan_send_frame(wlan, (uint8_t*)frame, length, 1, rssi, snr, rate); } /* */ @@ -1580,6 +1578,9 @@ void wifi_wlan_receive_station_frame(struct wifi_wlan* wlan, const struct ieee80 uint16_t framecontrol_type; uint16_t framecontrol_subtype; + ASSERT(wlan != NULL); + ASSERT(wlan->handle != NULL); + /* Check frame */ if (!frame || (length < sizeof(struct ieee80211_header))) { return; @@ -1602,6 +1603,9 @@ void wifi_wlan_receive_station_ackframe(struct wifi_wlan* wlan, const struct iee uint16_t framecontrol_type; uint16_t framecontrol_subtype; + ASSERT(wlan != NULL); + ASSERT(wlan->handle != NULL); + /* Check frame */ if (!frame || (length < sizeof(struct ieee80211_header))) { return; @@ -1625,6 +1629,9 @@ void wifi_wlan_receive_ac_frame(struct wifi_wlan* wlan, struct ieee80211_header* uint16_t framecontrol_type; uint16_t framecontrol_subtype; + ASSERT(wlan != NULL); + ASSERT(wlan->handle != NULL); + /* Check frame */ if (!frame || (length < sizeof(struct ieee80211_header))) { return; @@ -1647,6 +1654,19 @@ void wifi_wlan_receive_ac_frame(struct wifi_wlan* wlan, struct ieee80211_header* } } +/* */ +int wifi_wlan_send_frame(struct wifi_wlan* wlan, const uint8_t* data, int length, int nativeframe, uint8_t rssi, uint8_t snr, uint16_t rate) { + ASSERT(wlan != NULL); + ASSERT(wlan->handle != NULL); + + if (!data || (length <= 0) || !wlan->send_frame) { + return -1; + } + + /* */ + return wlan->send_frame(wlan->send_frame_to_ac_cbparam, data, length, nativeframe, rssi, snr, rate, wlan->address, MACADDRESS_EUI48_LENGTH); +} + /* */ int wifi_station_authorize(struct wifi_wlan* wlan, struct station_add_params* params) { int result; diff --git a/src/wtp/binding/ieee80211/wifi_drivers.h b/src/wtp/binding/ieee80211/wifi_drivers.h index 75c4064..d3b023f 100644 --- a/src/wtp/binding/ieee80211/wifi_drivers.h +++ b/src/wtp/binding/ieee80211/wifi_drivers.h @@ -87,7 +87,7 @@ struct device_setconfiguration_params { }; /* */ -typedef void (*send_frame_to_ac)(void* param, const struct ieee80211_header_mgmt* mgmt, int mgmtlength); +typedef int (*send_frame_to_ac)(void* param, const uint8_t* frame, int length, int nativeframe, uint8_t rssi, uint8_t snr, uint16_t rate, uint8_t* bssaddress, int bssaddresstype); struct wlan_startap_params { send_frame_to_ac send_frame; @@ -409,6 +409,7 @@ int wifi_wlan_startap(struct wifi_wlan* wlan, struct wlan_startap_params* params void wifi_wlan_stopap(struct wifi_wlan* wlan); int wifi_wlan_getbssid(struct wifi_wlan* wlan, uint8_t* bssid); uint16_t wifi_wlan_check_capability(struct wifi_wlan* wlan, uint16_t capability); +int wifi_wlan_send_frame(struct wifi_wlan* wlan, const uint8_t* data, int length, int nativeframe, uint8_t rssi, uint8_t snr, uint16_t rate); void wifi_wlan_destroy(struct wifi_wlan* wlan); /* WLAN packet management */ diff --git a/src/wtp/binding/ieee80211/wifi_nl80211.c b/src/wtp/binding/ieee80211/wifi_nl80211.c index 05b4b86..a9b41f3 100644 --- a/src/wtp/binding/ieee80211/wifi_nl80211.c +++ b/src/wtp/binding/ieee80211/wifi_nl80211.c @@ -1,8 +1,7 @@ -#include "capwap.h" +#include "wtp.h" #include "capwap_array.h" #include "capwap_list.h" #include "capwap_element.h" -#include "capwap_network.h" #include #include #include @@ -371,11 +370,9 @@ static int nl80211_wlan_event(struct wifi_wlan* wlan, struct genlmsghdr* gnlh, s if (tb_msg[NL80211_ATTR_FRAME]) { uint32_t frequency = (tb_msg[NL80211_ATTR_WIPHY_FREQ] ? nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_FREQ]) : 0); uint8_t rssi = (tb_msg[NL80211_ATTR_RX_SIGNAL_DBM] ? (uint8_t)nla_get_u32(tb_msg[NL80211_ATTR_RX_SIGNAL_DBM]) : 0); - uint8_t snr = 0; - uint16_t rate = 0; /* */ - wifi_wlan_receive_station_frame(wlan, (struct ieee80211_header*)nla_data(tb_msg[NL80211_ATTR_FRAME]), nla_len(tb_msg[NL80211_ATTR_FRAME]), frequency, rssi, snr, rate); + wifi_wlan_receive_station_frame(wlan, (struct ieee80211_header*)nla_data(tb_msg[NL80211_ATTR_FRAME]), nla_len(tb_msg[NL80211_ATTR_FRAME]), frequency, rssi, 0, 0); } break; @@ -799,15 +796,26 @@ static int nl80211_wlan_startap(struct wifi_wlan* wlan) { return -1; } + /* */ + if (wlan->tunnelmode != CAPWAP_ADD_WLAN_TUNNELMODE_LOCAL) { + /* Join interface to kernel module */ + if ((g_wtp.tunneldataframe == WTP_TUNNEL_DATA_FRAME_KERNELMODE) || (g_wtp.tunneldataframe == WTP_TUNNEL_DATA_FRAME_USERMODE)) { + uint32_t mode = ((g_wtp.tunneldataframe == WTP_TUNNEL_DATA_FRAME_KERNELMODE) ? WTP_KMOD_MODE_TUNNEL_KERNELMODE : WTP_KMOD_MODE_TUNNEL_USERMODE); + uint32_t flags = ((wlan->tunnelmode == CAPWAP_ADD_WLAN_TUNNELMODE_80211) ? WTP_KMOD_FLAGS_TUNNEL_NATIVE : WTP_KMOD_FLAGS_TUNNEL_8023); + + if (!wtp_kmod_join_mac80211_device(wlan, mode, flags)) { + capwap_logging_info("Joined in kernel mode the interface %d", wlan->virtindex); + } + } else { + capwap_logging_warning("Tunneling is not supported for interface %d", wlan->virtindex); + return -1; + } + } + /* Enable operation status */ wlan->flags |= WIFI_WLAN_OPERSTATE_RUNNING; netlink_set_link_status(wlanhandle->devicehandle->globalhandle->netlinkhandle, wlan->virtindex, -1, IF_OPER_UP); - /* */ - if (!wtp_kmod_join_mac80211_device(wlan->virtindex)) { - capwap_logging_info("Joined in kernel mode the interface %d", wlan->virtindex); - } - return 0; } @@ -822,6 +830,14 @@ static void nl80211_wlan_stopap(struct wifi_wlan* wlan) { /* */ wlanhandle = (struct nl80211_wlan_handle*)wlan->handle; + /* */ + if (wlan->tunnelmode != CAPWAP_ADD_WLAN_TUNNELMODE_LOCAL) { + /* Leave interface from kernel module */ + if ((g_wtp.tunneldataframe == WTP_TUNNEL_DATA_FRAME_KERNELMODE) || (g_wtp.tunneldataframe == WTP_TUNNEL_DATA_FRAME_USERMODE)) { + wtp_kmod_leave_mac80211_device(wlan); + } + } + /* */ if (wlan->flags & WIFI_WLAN_SET_BEACON) { msg = nlmsg_alloc(); diff --git a/src/wtp/wtp.c b/src/wtp/wtp.c index ae5b8a8..587d3c6 100644 --- a/src/wtp/wtp.c +++ b/src/wtp/wtp.c @@ -62,6 +62,7 @@ static int wtp_init(void) { g_wtp.mactype.type = CAPWAP_LOCALMAC; g_wtp.mactunnel.mode = CAPWAP_WTP_LOCAL_BRIDGING; + g_wtp.tunneldataframe = WTP_TUNNEL_DATA_FRAME_KERNELMODE; /* DTLS */ g_wtp.validdtlsdatapolicy = CAPWAP_ACDESC_CLEAR_DATA_CHANNEL_ENABLED; @@ -650,6 +651,19 @@ static int wtp_parsing_configuration_1_0(config_t* config) { g_wtp.mactunnel.mode |= CAPWAP_WTP_LOCAL_BRIDGING; } } + + if (config_lookup_string(config, "application.tunnelmode.dataframe", &configString) == CONFIG_TRUE) { + if (!strcmp(configString, "none")) { + g_wtp.tunneldataframe = WTP_TUNNEL_DATA_FRAME_NONE; + } else if (!strcmp(configString, "kernelmode")) { + g_wtp.tunneldataframe = WTP_TUNNEL_DATA_FRAME_KERNELMODE; + } else if (!strcmp(configString, "usermode")) { + g_wtp.tunneldataframe = WTP_TUNNEL_DATA_FRAME_USERMODE; + } else { + capwap_logging_error("Invalid configuration file, unknown application.tunnelmode.dataframe value"); + return 0; + } + } } /* Set mactype of WTP */ diff --git a/src/wtp/wtp.h b/src/wtp/wtp.h index 857a051..33c0479 100644 --- a/src/wtp/wtp.h +++ b/src/wtp/wtp.h @@ -42,6 +42,10 @@ #define WTP_INIT_REMOTE_SEQUENCE 0xff +#define WTP_TUNNEL_DATA_FRAME_NONE 0x00000000 +#define WTP_TUNNEL_DATA_FRAME_KERNELMODE 0x00000001 +#define WTP_TUNNEL_DATA_FRAME_USERMODE 0x00000002 + /* */ struct wtp_fds { int fdstotalcount; @@ -109,6 +113,8 @@ struct wtp_t { struct capwap_statisticstimer_element statisticstimer; struct capwap_wtprebootstat_element rebootstat; + int tunneldataframe; + struct capwap_packet_rxmng* rxmngctrlpacket; struct capwap_packet_rxmng* rxmngdatapacket; diff --git a/src/wtp/wtp_dfa.h b/src/wtp/wtp_dfa.h index f299098..2b80c5a 100644 --- a/src/wtp/wtp_dfa.h +++ b/src/wtp/wtp_dfa.h @@ -69,6 +69,6 @@ void wtp_dfa_state_reset(void); /* */ void wtp_ieee80211_packet(uint8_t radioid, const struct ieee80211_header* header, int length); -void wtp_send_data_packet(uint8_t radioid, uint8_t wlanid, const uint8_t* data, int length, int leavenativeframe); +int wtp_send_data_packet(uint8_t radioid, uint8_t wlanid, const uint8_t* frame, int length, int nativeframe, uint8_t rssi, uint8_t snr, uint16_t rate, uint8_t* bssaddress, int bssaddresstype); #endif /* __WTP_DFA_HEADER__ */ diff --git a/src/wtp/wtp_dfa_run.c b/src/wtp/wtp_dfa_run.c index cabefd1..e3bc95c 100644 --- a/src/wtp/wtp_dfa_run.c +++ b/src/wtp/wtp_dfa_run.c @@ -251,22 +251,45 @@ static void send_data_keepalive_request() { } /* */ -void wtp_send_data_packet(uint8_t radioid, uint8_t wlanid, const uint8_t* data, int length, int leavenativeframe) { +int wtp_send_data_packet(uint8_t radioid, uint8_t wlanid, const uint8_t* frame, int length, int nativeframe, uint8_t rssi, uint8_t snr, uint16_t rate, uint8_t* bssaddress, int bssaddresstype) { + int result; struct capwap_list* txfragpacket; struct capwap_header_data capwapheader; struct capwap_packet_txmng* txmngpacket; + ASSERT(IS_VALID_RADIOID(radioid)); + ASSERT(IS_VALID_WLANID(wlanid)); + ASSERT(frame != NULL); + ASSERT(length > 0); + + /* Check for IEEE 802.3 frame */ + if (!nativeframe && (!bssaddress || (bssaddresstype == MACADDRESS_NONE_LENGTH))) { + return 0; + } + /* Build packet */ capwap_header_init(&capwapheader, radioid, g_wtp.binding); - capwap_header_set_nativeframe_flag(&capwapheader, (leavenativeframe ? 1: 0)); + capwap_header_set_nativeframe_flag(&capwapheader, (nativeframe ? 1: 0)); + + /* Set radio macaddress */ + if (!nativeframe) { + capwap_header_set_radio_macaddress(&capwapheader, bssaddresstype, bssaddress); + } + + /* Set wireless information */ + if (rssi || snr || rate) { + struct capwap_ieee80211_frame_info frameinfo; + + frameinfo.rssi = rssi; + frameinfo.snr = snr; + frameinfo.rate = htons(rate); + capwap_header_set_wireless_information(&capwapheader, &frameinfo, sizeof(struct capwap_ieee80211_frame_info)); + } + txmngpacket = capwap_packet_txmng_create_data_message(&capwapheader, g_wtp.mtu); /* */ - if (leavenativeframe) { - capwap_packet_txmng_add_data(txmngpacket, data, (unsigned short)length); - } else { - /* TODO */ - } + capwap_packet_txmng_add_data(txmngpacket, frame, (unsigned short)length); /* Data message complete, get fragment packets into local list */ txfragpacket = capwap_list_create(); @@ -275,13 +298,17 @@ void wtp_send_data_packet(uint8_t radioid, uint8_t wlanid, const uint8_t* data, g_wtp.fragmentid++; } - if (!capwap_crypt_sendto_fragmentpacket(&g_wtp.datadtls, g_wtp.acdatasock.socket[g_wtp.acdatasock.type], txfragpacket, &g_wtp.wtpdataaddress, &g_wtp.acdataaddress)) { + /* */ + result = capwap_crypt_sendto_fragmentpacket(&g_wtp.datadtls, g_wtp.acdatasock.socket[g_wtp.acdatasock.type], txfragpacket, &g_wtp.wtpdataaddress, &g_wtp.acdataaddress); + if (!result) { capwap_logging_debug("Warning: error to send data packet"); } /* Free packets manager */ capwap_list_free(txfragpacket); capwap_packet_txmng_free(txmngpacket); + + return result; } /* */ diff --git a/src/wtp/wtp_kmod.c b/src/wtp/wtp_kmod.c index 5fc07d6..aa2b3a7 100644 --- a/src/wtp/wtp_kmod.c +++ b/src/wtp/wtp_kmod.c @@ -81,6 +81,33 @@ static int wtp_kmod_ack_handler(struct nl_msg* msg, void* arg) { return NL_STOP; } +/* */ +static int wtp_kmod_event_handler(struct genlmsghdr* gnlh, struct nlattr** tb_msg, void* data) { + switch (gnlh->cmd) { + case NLSMARTCAPWAP_CMD_FRAME: { + struct wtp_kmod_iface_handle* interface = (struct wtp_kmod_iface_handle*)data; + + if (tb_msg[NLSMARTCAPWAP_ATTR_FRAME]) { + uint32_t sig_dbm = (tb_msg[NLSMARTCAPWAP_ATTR_RX_SIGNAL_DBM] ? nla_get_u32(tb_msg[NLSMARTCAPWAP_ATTR_RX_SIGNAL_DBM]) : 0); + uint16_t rate = (tb_msg[NLSMARTCAPWAP_ATTR_RX_RATE] ? ((uint16_t)nla_get_u8(tb_msg[NLSMARTCAPWAP_ATTR_RX_RATE])) * 5 : 0); /* Convert rate 500Kbps to 100Kbps */ + int nativeframe = (tb_msg[SMARTCAPWAP_FLAGS_TUNNEL_8023] ? 0 : 1); + + /* Forwards the frame to AC */ + wifi_wlan_send_frame(interface->wlan, (uint8_t*)nla_data(tb_msg[NLSMARTCAPWAP_ATTR_FRAME]), nla_len(tb_msg[NLSMARTCAPWAP_ATTR_FRAME]), nativeframe, (uint8_t)sig_dbm, 0, rate); + } + + break; + } + + default: { + capwap_logging_debug("*** wtp_kmod_event_handler: %d", (int)gnlh->cmd); + break; + } + } + + return NL_SKIP; +} + /* */ static int wtp_kmod_valid_handler(struct nl_msg* msg, void* data) { struct nlattr* tb_msg[NLSMARTCAPWAP_ATTR_MAX + 1]; @@ -88,7 +115,7 @@ static int wtp_kmod_valid_handler(struct nl_msg* msg, void* data) { nla_parse(tb_msg, NLSMARTCAPWAP_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); - return NL_SKIP; + return wtp_kmod_event_handler(gnlh, tb_msg, data); } /* */ @@ -177,12 +204,122 @@ static void wtp_kmod_event_receive(int fd, void** params, int paramscount) { } /* */ -int wtp_kmod_join_mac80211_device(uint32_t ifindex) { +int wtp_kmod_join_mac80211_device(struct wifi_wlan* wlan, uint32_t mode, uint32_t flags) { + int result; + struct nl_sock* nl; + struct nl_cb* nl_cb; + struct nl_msg* msg; + struct capwap_list_item* itemlist; + struct wtp_kmod_iface_handle* interface; + uint32_t kmodflags = 0; + uint16_t subtype_mgmt = 0; + uint16_t subtype_ctrl = 0; + uint16_t subtype_data = 0; + + ASSERT(wlan != NULL); + + /* */ + if (!wtp_kmod_isconnected()) { + return -1; + } + + /* */ + itemlist = capwap_itemlist_create(sizeof(struct wtp_kmod_iface_handle)); + interface = (struct wtp_kmod_iface_handle*)itemlist->item; + + /* Socket management */ + nl_cb = nl_cb_alloc(NL_CB_DEFAULT); + if (!nl_cb) { + capwap_itemlist_free(itemlist); + return -1; + } + + nl_cb_set(nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, wtp_kmod_no_seq_check, NULL); + nl_cb_set(nl_cb, NL_CB_VALID, NL_CB_CUSTOM, wtp_kmod_valid_handler, (void*)interface); + + nl = nl_create_handle(nl_cb); + if (!nl) { + nl_cb_put(nl_cb); + capwap_itemlist_free(itemlist); + return -1; + } + + /* */ + msg = nlmsg_alloc(); + if (!msg) { + nl_socket_free(nl); + nl_cb_put(nl_cb); + capwap_itemlist_free(itemlist); + return -1; + } + + /* Set flags */ + switch (mode) { + case WTP_KMOD_MODE_LOCAL: { + break; + } + + case WTP_KMOD_MODE_TUNNEL_USERMODE: { + kmodflags |= SMARTCAPWAP_FLAGS_SEND_USERSPACE | SMARTCAPWAP_FLAGS_BLOCK_DATA_FRAME; + subtype_data = 0xffff; + + if (flags & WTP_KMOD_FLAGS_TUNNEL_8023) { + kmodflags |= SMARTCAPWAP_FLAGS_TUNNEL_8023; + } + + break; + } + + case WTP_KMOD_MODE_TUNNEL_KERNELMODE: { + kmodflags |= SMARTCAPWAP_FLAGS_BLOCK_DATA_FRAME; + subtype_data = 0xffff; + + if (flags & WTP_KMOD_FLAGS_TUNNEL_8023) { + kmodflags |= SMARTCAPWAP_FLAGS_TUNNEL_8023; + } + + break; + } + } + + /* */ + genlmsg_put(msg, 0, 0, g_wtp.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_JOIN_MAC80211_DEVICE, 0); + nla_put_u32(msg, NLSMARTCAPWAP_ATTR_IFINDEX, wlan->virtindex); + nla_put_u32(msg, NLSMARTCAPWAP_ATTR_FLAGS, kmodflags); + nla_put_u16(msg, NLSMARTCAPWAP_ATTR_MGMT_SUBTYPE_MASK, subtype_mgmt); + nla_put_u16(msg, NLSMARTCAPWAP_ATTR_CTRL_SUBTYPE_MASK, subtype_ctrl); + nla_put_u16(msg, NLSMARTCAPWAP_ATTR_DATA_SUBTYPE_MASK, subtype_data); + + /* */ + result = wtp_kmod_send_and_recv(nl, nl_cb, msg, NULL, NULL); + if (!result) { + interface->nl = nl; + interface->nl_fd = nl_socket_get_fd(nl); + interface->nl_cb = nl_cb; + interface->wlan = wlan; + + /* */ + capwap_itemlist_insert_after(g_wtp.kmodhandle.interfaces, NULL, itemlist); + } else { + nl_socket_free(nl); + nl_cb_put(nl_cb); + capwap_itemlist_free(itemlist); + } + + /* */ + nlmsg_free(msg); + return result; +} + +/* */ +int wtp_kmod_leave_mac80211_device(struct wifi_wlan* wlan) { int result; struct nl_msg* msg; + ASSERT(wlan != NULL); + /* */ - if (!g_wtp.kmodhandle.nlsmartcapwap_id) { + if (!wtp_kmod_isconnected()) { return -1; } @@ -193,15 +330,26 @@ int wtp_kmod_join_mac80211_device(uint32_t ifindex) { } /* */ - genlmsg_put(msg, 0, 0, g_wtp.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_JOIN_MAC80211_DEVICE, 0); - nla_put_u32(msg, NLSMARTCAPWAP_ATTR_IFINDEX, ifindex); - nla_put_u32(msg, NLSMARTCAPWAP_ATTR_FLAGS, SMARTCAPWAP_FLAGS_SEND_USERSPACE | SMARTCAPWAP_FLAGS_BLOCK_DATA_FRAME); - nla_put_u16(msg, NLSMARTCAPWAP_ATTR_DATA_SUBTYPE_MASK, 0xffff); + genlmsg_put(msg, 0, 0, g_wtp.kmodhandle.nlsmartcapwap_id, 0, 0, NLSMARTCAPWAP_CMD_LEAVE_MAC80211_DEVICE, 0); + nla_put_u32(msg, NLSMARTCAPWAP_ATTR_IFINDEX, wlan->virtindex); /* */ result = wtp_kmod_send_and_recv_msg(msg, NULL, NULL); - if (result) { - capwap_logging_warning("Unable to join with interface: %d", ifindex); + if (!result) { + struct capwap_list_item* itemlist; + + for (itemlist = g_wtp.kmodhandle.interfaces->first; itemlist != NULL; itemlist = itemlist->next) { + struct wtp_kmod_iface_handle* interface = (struct wtp_kmod_iface_handle*)itemlist->item; + + if (interface->wlan == wlan) { + nl_socket_free(interface->nl); + nl_cb_put(interface->nl_cb); + + /* Free item */ + capwap_itemlist_free(capwap_itemlist_remove(g_wtp.kmodhandle.interfaces, itemlist)); + break; + } + } } /* */ @@ -216,7 +364,9 @@ int wtp_kmod_isconnected(void) { /* */ int wtp_kmod_getfd(struct pollfd* fds, struct wtp_kmod_event* events, int count) { - int kmodcount = (wtp_kmod_isconnected() ? 1 : 0); + int i = 1; + struct capwap_list_item* itemlist; + int kmodcount = (wtp_kmod_isconnected() ? 1 + g_wtp.kmodhandle.interfaces->count : 0); /* */ if (!fds && !events && !count) { @@ -237,6 +387,22 @@ int wtp_kmod_getfd(struct pollfd* fds, struct wtp_kmod_event* events, int count) events[0].params[1] = (void*)g_wtp.kmodhandle.nl_cb; events[0].paramscount = 2; + /* */ + for (itemlist = g_wtp.kmodhandle.interfaces->first; itemlist; i++, itemlist = itemlist->next) { + struct wtp_kmod_iface_handle* interface = (struct wtp_kmod_iface_handle*)itemlist->item; + + /* */ + fds[i].fd = interface->nl_fd; + fds[i].events = POLLIN | POLLERR | POLLHUP; + + /* */ + events[i].event_handler = wtp_kmod_event_receive; + events[i].params[0] = (void*)interface->nl; + events[i].params[1] = (void*)interface->nl_cb; + events[i].paramscount = 2; + } + + ASSERT(kmodcount == i); return kmodcount; } @@ -279,11 +445,26 @@ int wtp_kmod_init(void) { return result; } + /* */ + g_wtp.kmodhandle.interfaces = capwap_list_create(); return 0; } /* */ void wtp_kmod_free(void) { + if (g_wtp.kmodhandle.interfaces) { + while (g_wtp.kmodhandle.interfaces->first) { + struct wtp_kmod_iface_handle* interface = (struct wtp_kmod_iface_handle*)g_wtp.kmodhandle.interfaces->first->item; + + if (wtp_kmod_leave_mac80211_device(interface->wlan)) { + break; + } + } + + /* */ + capwap_list_free(g_wtp.kmodhandle.interfaces); + } + if (g_wtp.kmodhandle.nl) { nl_socket_free(g_wtp.kmodhandle.nl); } diff --git a/src/wtp/wtp_kmod.h b/src/wtp/wtp_kmod.h index 20d1b6a..cf98f9c 100644 --- a/src/wtp/wtp_kmod.h +++ b/src/wtp/wtp_kmod.h @@ -1,17 +1,40 @@ #ifndef __WTP_KMOD_HEADER__ #define __WTP_KMOD_HEADER__ +#include "wifi_drivers.h" + /* */ #ifdef HAVE_LIBNL_10 #define nl_sock nl_handle #endif +/* */ +#define WTP_KMOD_MODE_LOCAL 0x00000001 +#define WTP_KMOD_MODE_TUNNEL_USERMODE 0x00000002 +#define WTP_KMOD_MODE_TUNNEL_KERNELMODE 0x00000003 + +/* */ +#define WTP_KMOD_FLAGS_TUNNEL_NATIVE 0x00000000 +#define WTP_KMOD_FLAGS_TUNNEL_8023 0x00000001 + +/* */ +struct wtp_kmod_iface_handle { + struct nl_sock* nl; + int nl_fd; + struct nl_cb* nl_cb; + + struct wifi_wlan* wlan; +}; + /* */ struct wtp_kmod_handle { struct nl_sock* nl; int nl_fd; struct nl_cb* nl_cb; int nlsmartcapwap_id; + + /* */ + struct capwap_list* interfaces; }; /* */ @@ -31,6 +54,7 @@ int wtp_kmod_isconnected(void); int wtp_kmod_getfd(struct pollfd* fds, struct wtp_kmod_event* events, int count); /* */ -int wtp_kmod_join_mac80211_device(uint32_t ifindex); +int wtp_kmod_join_mac80211_device(struct wifi_wlan* wlan, uint32_t mode, uint32_t flags); +int wtp_kmod_leave_mac80211_device(struct wifi_wlan* wlan); #endif /* __WTP_KMOD_HEADER__ */ diff --git a/src/wtp/wtp_radio.c b/src/wtp/wtp_radio.c index a7e83fd..8be1389 100644 --- a/src/wtp/wtp_radio.c +++ b/src/wtp/wtp_radio.c @@ -51,15 +51,15 @@ static int wtp_radio_configure_phy(struct wtp_radio* radio) { } /* */ -static void wtp_radio_send_frame_to_ac(void* param, const struct ieee80211_header_mgmt* mgmt, int mgmtlength) { +static int wtp_radio_send_frame_to_ac(void* param, const uint8_t* frame, int length, int nativeframe, uint8_t rssi, uint8_t snr, uint16_t rate, uint8_t* bssaddress, int bssaddresstype) { struct wtp_radio_wlan* wlan = (struct wtp_radio_wlan*)param; ASSERT(param != NULL); - ASSERT(mgmt != NULL); - ASSERT(mgmtlength >= sizeof(struct ieee80211_header)); + ASSERT(frame != NULL); + ASSERT(length > 0); /* Send packet */ - wtp_send_data_packet(wlan->radio->radioid, wlan->wlanid, (const uint8_t*)mgmt, mgmtlength, 1); + return wtp_send_data_packet(wlan->radio->radioid, wlan->wlanid, frame, length, nativeframe, rssi, snr, rate, bssaddress, bssaddresstype); } /* */