mirror of
https://gitee.com/Vancouver2017/luban-lite.git
synced 2025-12-16 17:18:56 +00:00
2605 lines
72 KiB
C
2605 lines
72 KiB
C
/*
|
|
* Wireless utility functions
|
|
*/
|
|
#include "atbm_hal.h"
|
|
#include "wpa_main.h"
|
|
#if CONFIG_P2P
|
|
#include "p2p_common.h"
|
|
#endif
|
|
#if ATBM_SUPPORT_BRIDGE
|
|
#include "atbm_bridge.h"
|
|
#endif
|
|
|
|
unsigned int atbm_cfg80211_classify8021d(struct atbm_buff *skb);
|
|
/*
|
|
static const struct country_code_to_string country_strings[] = {
|
|
{CTRY_DEBUG, "DB" },
|
|
{CTRY_DEFAULT, "NA" },
|
|
{CTRY_ALBANIA, "AL" },
|
|
{CTRY_ALGERIA, "DZ" },
|
|
{CTRY_ARGENTINA, "AR" },
|
|
{CTRY_ARMENIA, "AM" },
|
|
{CTRY_AUSTRALIA, "AU" },
|
|
{CTRY_AUSTRIA, "AT" },
|
|
{CTRY_AZERBAIJAN, "AZ" },
|
|
{CTRY_BAHRAIN, "BH" },
|
|
{CTRY_BELARUS, "BY" },
|
|
{CTRY_BELGIUM, "BE" },
|
|
{CTRY_BELIZE, "BZ" },
|
|
{CTRY_BOLIVIA, "BO" },
|
|
{CTRY_BRAZIL, "BR" },
|
|
{CTRY_BRUNEI_DARUSSALAM, "BN" },
|
|
{CTRY_BULGARIA, "BG" },
|
|
{CTRY_CANADA, "CA" },
|
|
{CTRY_CHILE, "CL" },
|
|
{CTRY_CHINA, "CN" },
|
|
{CTRY_COLOMBIA, "CO" },
|
|
{CTRY_COSTA_RICA, "CR" },
|
|
{CTRY_CROATIA, "HR" },
|
|
{CTRY_CYPRUS, "CY" },
|
|
{CTRY_CZECH, "CZ" },
|
|
{CTRY_DENMARK, "DK" },
|
|
{CTRY_DOMINICAN_REPUBLIC, "DO" },
|
|
{CTRY_ECUADOR, "EC" },
|
|
{CTRY_EGYPT, "EG" },
|
|
{CTRY_EL_SALVADOR, "SV" },
|
|
{CTRY_ESTONIA, "EE" },
|
|
{CTRY_FINLAND, "FI" },
|
|
{CTRY_FRANCE, "FR" },
|
|
{CTRY_FRANCE2, "F2" },
|
|
{CTRY_GEORGIA, "GE" },
|
|
{CTRY_GERMANY, "DE" },
|
|
{CTRY_GREECE, "GR" },
|
|
{CTRY_GUATEMALA, "GT" },
|
|
{CTRY_HONDURAS, "HN" },
|
|
{CTRY_HONG_KONG, "HK" },
|
|
{CTRY_HUNGARY, "HU" },
|
|
{CTRY_ICELAND, "IS" },
|
|
{CTRY_INDIA, "IN" },
|
|
{CTRY_INDONESIA, "ID" },
|
|
{CTRY_IRAN, "IR" },
|
|
{CTRY_IRELAND, "IE" },
|
|
{CTRY_ISRAEL, "IL" },
|
|
{CTRY_ITALY, "IT" },
|
|
{CTRY_JAPAN, "JP" },
|
|
{CTRY_JAPAN1, "J1" },
|
|
{CTRY_JAPAN2, "J2" },
|
|
{CTRY_JAPAN3, "J3" },
|
|
{CTRY_JAPAN4, "J4" },
|
|
{CTRY_JAPAN5, "J5" },
|
|
{CTRY_JAPAN7, "JP" },
|
|
{CTRY_JAPAN6, "JP" },
|
|
{CTRY_JAPAN8, "JP" },
|
|
{CTRY_JAPAN9, "JP" },
|
|
{CTRY_JAPAN10, "JP" },
|
|
{CTRY_JAPAN11, "JP" },
|
|
{CTRY_JAPAN12, "JP" },
|
|
{CTRY_JAPAN13, "JP" },
|
|
{CTRY_JAPAN14, "JP" },
|
|
{CTRY_JAPAN15, "JP" },
|
|
{CTRY_JAPAN16, "JP" },
|
|
{CTRY_JAPAN17, "JP" },
|
|
{CTRY_JAPAN18, "JP" },
|
|
{CTRY_JAPAN19, "JP" },
|
|
{CTRY_JAPAN20, "JP" },
|
|
{CTRY_JAPAN21, "JP" },
|
|
{CTRY_JAPAN22, "JP" },
|
|
{CTRY_JAPAN23, "JP" },
|
|
{CTRY_JAPAN24, "JP" },
|
|
{CTRY_JAPAN25, "JP" },
|
|
{CTRY_JAPAN26, "JP" },
|
|
{CTRY_JAPAN27, "JP" },
|
|
{CTRY_JAPAN28, "JP" },
|
|
{CTRY_JAPAN29, "JP" },
|
|
{CTRY_JAPAN30, "JP" },
|
|
{CTRY_JAPAN31, "JP" },
|
|
{CTRY_JAPAN32, "JP" },
|
|
{CTRY_JAPAN33, "JP" },
|
|
{CTRY_JAPAN34, "JP" },
|
|
{CTRY_JAPAN35, "JP" },
|
|
{CTRY_JAPAN36, "JP" },
|
|
{CTRY_JAPAN37, "JP" },
|
|
{CTRY_JAPAN38, "JP" },
|
|
{CTRY_JAPAN39, "JP" },
|
|
{CTRY_JAPAN40, "JP" },
|
|
{CTRY_JAPAN41, "JP" },
|
|
{CTRY_JAPAN42, "JP" },
|
|
{CTRY_JAPAN43, "JP" },
|
|
{CTRY_JAPAN44, "JP" },
|
|
{CTRY_JAPAN45, "JP" },
|
|
{CTRY_JAPAN46, "JP" },
|
|
{CTRY_JAPAN47, "JP" },
|
|
{CTRY_JAPAN48, "JP" },
|
|
{CTRY_JORDAN, "JO" },
|
|
{CTRY_KAZAKHSTAN, "KZ" },
|
|
{CTRY_KOREA_NORTH, "KP" },
|
|
{CTRY_KOREA_ROC, "KR" },
|
|
{CTRY_KOREA_ROC2, "K2" },
|
|
{CTRY_KUWAIT, "KW" },
|
|
{CTRY_LATVIA, "LV" },
|
|
{CTRY_LEBANON, "LB" },
|
|
{CTRY_LIECHTENSTEIN, "LI" },
|
|
{CTRY_LITHUANIA, "LT" },
|
|
{CTRY_LUXEMBOURG, "LU" },
|
|
{CTRY_MACAU, "MO" },
|
|
{CTRY_MACEDONIA, "MK" },
|
|
{CTRY_MALAYSIA, "MY" },
|
|
{CTRY_MEXICO, "MX" },
|
|
{CTRY_MONACO, "MC" },
|
|
{CTRY_MOROCCO, "MA" },
|
|
{CTRY_NETHERLANDS, "NL" },
|
|
{CTRY_NEW_ZEALAND, "NZ" },
|
|
{CTRY_NORWAY, "NO" },
|
|
{CTRY_OMAN, "OM" },
|
|
{CTRY_PAKISTAN, "PK" },
|
|
{CTRY_PANAMA, "PA" },
|
|
{CTRY_PERU, "PE" },
|
|
{CTRY_PHILIPPINES, "PH" },
|
|
{CTRY_POLAND, "PL" },
|
|
{CTRY_PORTUGAL, "PT" },
|
|
{CTRY_PUERTO_RICO, "PR" },
|
|
{CTRY_QATAR, "QA" },
|
|
{CTRY_ROMANIA, "RO" },
|
|
{CTRY_RUSSIA, "RU" },
|
|
{CTRY_SAUDI_ARABIA, "SA" },
|
|
{CTRY_SINGAPORE, "SG" },
|
|
{CTRY_SLOVAKIA, "SK" },
|
|
{CTRY_SLOVENIA, "SI" },
|
|
{CTRY_SOUTH_AFRICA, "ZA" },
|
|
{CTRY_SPAIN, "ES" },
|
|
{CTRY_SWEDEN, "SE" },
|
|
{CTRY_SWITZERLAND, "CH" },
|
|
{CTRY_SYRIA, "SY" },
|
|
{CTRY_TAIWAN, "TW" },
|
|
{CTRY_THAILAND, "TH" },
|
|
{CTRY_TRINIDAD_Y_TOBAGO, "TT" },
|
|
{CTRY_TUNISIA, "TN" },
|
|
{CTRY_TURKEY, "TR" },
|
|
{CTRY_UKRAINE, "UA" },
|
|
{CTRY_UAE, "AE" },
|
|
{CTRY_UNITED_KINGDOM, "GB" },
|
|
{CTRY_UNITED_STATES, "US" },
|
|
{CTRY_UNITED_STATES_FCC49, "US" },
|
|
{CTRY_URUGUAY, "UY" },
|
|
{CTRY_UZBEKISTAN, "UZ" },
|
|
{CTRY_VENEZUELA, "VE" },
|
|
{CTRY_VIET_NAM, "VN" },
|
|
{CTRY_YEMEN, "YE" },
|
|
{CTRY_ZIMBABWE, "ZW" }
|
|
};
|
|
*/
|
|
|
|
|
|
|
|
|
|
atbm_void atbmwifi_ieee80211_channel_country(struct atbmwifi_common *hw_priv,int region_id){
|
|
|
|
struct atbmwifi_ieee80211_channel *chantable=atbmwifi_band_2ghz.channels;
|
|
|
|
int nchan = 0;
|
|
int chan_vl = 1;
|
|
switch(region_id){
|
|
case country_usa:
|
|
case country_canada:/*1~11*/
|
|
case region_taiwan:/*1~11*/
|
|
case country_SINGAPORE:/*1~11*/
|
|
for(chan_vl=1;chan_vl<=11;chan_vl++){
|
|
chantable[nchan].hw_value = chan_vl;
|
|
nchan++;
|
|
}
|
|
break;
|
|
case country_brazil:/*1~14*/
|
|
case country_japan:/*1~14*/
|
|
for(chan_vl=1;chan_vl<=14;chan_vl++){
|
|
chantable[nchan].hw_value = chan_vl;
|
|
nchan++;
|
|
}
|
|
break;
|
|
case country_Israel:/*3~9*/
|
|
for(chan_vl=3;chan_vl<=9;chan_vl++){
|
|
chantable[nchan].hw_value = chan_vl;
|
|
nchan++;
|
|
}
|
|
break;
|
|
case country_chinese:
|
|
case country_europe:
|
|
case country_australia:/*1~13*/
|
|
default:
|
|
for(chan_vl=1;chan_vl<=13;chan_vl++){
|
|
chantable[nchan].hw_value = chan_vl;
|
|
nchan++;
|
|
}
|
|
break;
|
|
|
|
}
|
|
atbmwifi_band_2ghz.n_channels = nchan;
|
|
hw_priv->region_id = region_id;
|
|
}
|
|
|
|
/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
|
|
/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
|
|
static const unsigned char atbm_rfc1042_header[] =
|
|
{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
|
|
|
|
/* Bridge-Tunnel header (for EtherTypes ATBM_ETH_P_AARP and ATBM_ETH_P_IPX) */
|
|
static const unsigned char atbm_bridge_tunnel_header[] =
|
|
{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
|
|
|
|
unsigned int atbmwifi_ieee80211_hdrlen(atbm_uint16 fc)
|
|
{
|
|
unsigned int hdrlen = 24;
|
|
|
|
if (atbmwifi_ieee80211_is_data(fc)) {
|
|
if (atbmwifi_ieee80211_has_a4(fc))
|
|
hdrlen = 30;
|
|
if (atbmwifi_ieee80211_is_data_qos(fc)) {
|
|
hdrlen += ATBM_IEEE80211_QOS_CTL_LEN;
|
|
if (atbmwifi_ieee80211_has_order(fc))
|
|
hdrlen += ATBM_IEEE80211_HT_CTL_LEN;
|
|
}
|
|
goto out;
|
|
}
|
|
|
|
if (atbmwifi_ieee80211_is_ctl(fc)) {
|
|
/*
|
|
* ACK and CTS are 10 bytes, all others 16. To see how
|
|
* to get this condition consider
|
|
* subtype mask: 0b0000000011110000 (0x00F0)
|
|
* ACK subtype: 0b0000000011010000 (0x00D0)
|
|
* CTS subtype: 0b0000000011000000 (0x00C0)
|
|
* bits that matter: ^^^ (0x00E0)
|
|
* value of those: 0b0000000011000000 (0x00C0)
|
|
*/
|
|
if ((fc & atbm_cpu_to_le16(0x00E0)) == atbm_cpu_to_le16(0x00C0))
|
|
hdrlen = 10;
|
|
else
|
|
hdrlen = 16;
|
|
}
|
|
out:
|
|
return hdrlen;
|
|
}
|
|
|
|
unsigned int atbmwifi_ieee80211_get_hdrlen_from_skb(const struct atbm_buff *skb)
|
|
{
|
|
const struct atbmwifi_ieee80211_hdr *hdr =
|
|
(const struct atbmwifi_ieee80211_hdr *)ATBM_OS_SKB_DATA(skb);
|
|
unsigned int hdrlen;
|
|
|
|
if (atbm_unlikely(ATBM_OS_SKB_LEN(skb) < 10))
|
|
return 0;
|
|
hdrlen = atbmwifi_ieee80211_hdrlen(hdr->frame_control);
|
|
if (atbm_unlikely(hdrlen > ATBM_OS_SKB_LEN(skb)))
|
|
return 0;
|
|
return hdrlen;
|
|
}
|
|
|
|
/*
|
|
* requires that rx->skb is a frame with ethernet header
|
|
*/
|
|
ATBM_BOOL atbmwifi_ieee80211_frame_allowed(struct atbm_buff *skb, atbm_uint16 fc)
|
|
{
|
|
// static const atbm_uint8 pae_group_addr[ATBM_ETH_ALEN] __aligned(2)
|
|
// = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x03 };
|
|
|
|
|
|
return ATBM_TRUE;
|
|
}
|
|
|
|
atbm_void atbmwifi_ieee80211_amsdu_to_8023s(struct atbm_buff *skb, struct atbm_buff_head *list,
|
|
const atbm_uint8 *addr, enum atbm_nl80211_iftype iftype,
|
|
ATBM_BOOL has_80211_header)
|
|
{
|
|
struct atbm_buff *frame = ATBM_NULL;
|
|
atbm_uint16 ethertype;
|
|
atbm_uint8 *payload;
|
|
const struct atbmwifi_ieee8023_hdr *eth;
|
|
int remaining, err;
|
|
atbm_uint8 dst[ATBM_ETH_ALEN], src[ATBM_ETH_ALEN];
|
|
|
|
if (has_80211_header) {
|
|
err = atbmwifi_ieee80211_data_to_8023(skb, addr, iftype);
|
|
if (err)
|
|
goto out;
|
|
|
|
/* skip the wrapping header */
|
|
eth = (struct atbmwifi_ieee8023_hdr *) atbm_skb_pull(skb, sizeof(struct atbmwifi_ieee8023_hdr));
|
|
if (!eth)
|
|
goto out;
|
|
} else {
|
|
eth = (struct atbmwifi_ieee8023_hdr *) ATBM_OS_SKB_DATA(skb);
|
|
}
|
|
|
|
while (skb != frame) {
|
|
atbm_uint8 padding;
|
|
atbm_uint16 len = eth->h_proto;
|
|
unsigned int subframe_len = sizeof(struct atbmwifi_ieee8023_hdr) + atbm_ntohs(len);
|
|
|
|
remaining = ATBM_OS_SKB_LEN(skb);
|
|
atbm_memcpy(dst, eth->h_dest, ATBM_ETH_ALEN);
|
|
atbm_memcpy(src, eth->h_source, ATBM_ETH_ALEN);
|
|
|
|
padding = (4 - subframe_len) & 0x3;
|
|
/* the last MSDU has no padding */
|
|
if (subframe_len > remaining)
|
|
goto purge;
|
|
|
|
/* mitigate A-MSDU aggregation injection attacks */
|
|
if (!atbm_compare_ether_addr(eth->h_dest, atbm_rfc1042_header))
|
|
goto purge;
|
|
|
|
atbm_skb_pull(skb, sizeof(struct atbmwifi_ieee8023_hdr));
|
|
/* reuse skb for the last subframe */
|
|
if (remaining <= subframe_len + padding)
|
|
frame = skb;
|
|
else {
|
|
unsigned int hlen = 32;
|
|
/*
|
|
* Allocate and reserve two bytes more for payload
|
|
* alignment since sizeof(struct ethhdr) is 14.
|
|
*/
|
|
frame = atbm_dev_alloc_skb(hlen + subframe_len + 2);
|
|
if (!frame)
|
|
goto purge;
|
|
|
|
atbm_skb_reserve(frame, hlen + sizeof(struct atbmwifi_ieee8023_hdr) + 2);
|
|
atbm_memcpy(atbm_skb_put(frame, atbm_ntohs(len)), ATBM_OS_SKB_DATA(skb),atbm_ntohs(len));
|
|
|
|
eth = (struct atbmwifi_ieee8023_hdr *)atbm_skb_pull(skb, atbm_ntohs(len) +
|
|
padding);
|
|
if (!eth) {
|
|
atbm_dev_kfree_skb(frame);
|
|
goto purge;
|
|
}
|
|
}
|
|
|
|
//skb_reset_network_header(frame);
|
|
//frame->dev = skb->dev;
|
|
//frame->priority = skb->priority;
|
|
|
|
payload = ATBM_OS_SKB_DATA(frame);
|
|
ethertype = (payload[6] << 8) | payload[7];
|
|
|
|
if (atbm_likely((atbm_compare_ether_addr(payload, atbm_rfc1042_header) == 0 &&
|
|
ethertype != ATBM_ETH_P_AARP && ethertype != ATBM_ETH_P_IPX) ||
|
|
atbm_compare_ether_addr(payload,atbm_bridge_tunnel_header) == 0)) {
|
|
/* remove RFC1042 or Bridge-Tunnel
|
|
* encapsulation and replace EtherType */
|
|
atbm_skb_pull(frame, 6);
|
|
atbm_memcpy(atbm_skb_push(frame, ATBM_ETH_ALEN), src, ATBM_ETH_ALEN);
|
|
atbm_memcpy(atbm_skb_push(frame, ATBM_ETH_ALEN), dst, ATBM_ETH_ALEN);
|
|
} else {
|
|
atbm_memcpy(atbm_skb_push(frame, sizeof(atbm_uint16)), &len,
|
|
sizeof(atbm_uint16));
|
|
atbm_memcpy(atbm_skb_push(frame, ATBM_ETH_ALEN), src, ATBM_ETH_ALEN);
|
|
atbm_memcpy(atbm_skb_push(frame, ATBM_ETH_ALEN), dst, ATBM_ETH_ALEN);
|
|
}
|
|
atbm_skb_queue_tail(list, frame);
|
|
}
|
|
|
|
return;
|
|
|
|
purge:
|
|
atbm_skb_queue_purge(list);
|
|
out:
|
|
atbm_dev_kfree_skb(skb);
|
|
}
|
|
/*
|
|
if ap mode ,we need forward mul-data or unicast data for other sta to the air
|
|
skb need upload to tcpip return 1, other return 0
|
|
*/
|
|
struct atbmwifi_vif *atbmwifi_ieee80211_forward_skb(struct atbmwifi_vif *priv,struct atbm_buff *skb)
|
|
{
|
|
struct atbmwifi_ieee8023_hdr *hdr = (struct atbmwifi_ieee8023_hdr *) ATBM_OS_SKB_DATA(skb);
|
|
struct atbm_buff *txskb = ATBM_NULL;
|
|
struct atbmwifi_sta_priv * sta_priv =ATBM_NULL;
|
|
struct atbmwifi_vif *peer_priv;
|
|
|
|
/*
|
|
wifi_printk(WIFI_ALWAYS, "rx iftype:%s proto:%s port:%d src:"MACSTR" dst:"MACSTR"\n",
|
|
(priv->iftype == ATBM_NL80211_IFTYPE_AP) ? "ap":"sta",
|
|
(ethtype == 0) ? "IP" :((ethtype == 1) ? "ARP" : "unknown"),
|
|
port, MAC2STR(hdr->h_source), MAC2STR(hdr->h_dest));
|
|
*/
|
|
|
|
peer_priv = _atbmwifi_hwpriv_to_vifpriv(priv->hw_priv, !(priv->if_id));
|
|
if((priv->iftype == ATBM_NL80211_IFTYPE_AP) || (priv->iftype == ATBM_NL80211_IFTYPE_P2P_GO)){
|
|
if (atbm_is_multicast_ether_addr(hdr->h_dest)) {
|
|
txskb = atbm_dev_alloc_skb(ATBM_OS_SKB_LEN(skb));
|
|
if (txskb) {
|
|
txskb->priority = 0;
|
|
atbm_memcpy(ATBM_OS_SKB_DATA(txskb), ATBM_OS_SKB_DATA(skb), ATBM_OS_SKB_LEN(skb));
|
|
atbm_skb_put(txskb,ATBM_OS_SKB_LEN(skb));
|
|
atbmwifi_tx_start(txskb,priv);
|
|
}
|
|
}else{
|
|
#if ATBM_SUPPORT_BRIDGE
|
|
if(atbm_memcmp(hdr->h_dest,peer_priv->mac_addr,6)
|
|
#else
|
|
if(atbm_memcmp(hdr->h_dest,priv->mac_addr,6)
|
|
#endif
|
|
){
|
|
sta_priv = atbmwifi_sta_find(priv,hdr->h_dest);
|
|
if (sta_priv) {
|
|
txskb = atbm_dev_alloc_skb(ATBM_OS_SKB_LEN(skb));
|
|
if (txskb) {
|
|
txskb->priority = 0;
|
|
atbm_memcpy(ATBM_OS_SKB_DATA(txskb), ATBM_OS_SKB_DATA(skb), ATBM_OS_SKB_LEN(skb));
|
|
atbm_skb_put(txskb,ATBM_OS_SKB_LEN(skb));
|
|
atbmwifi_tx_start(txskb,priv);
|
|
}
|
|
atbm_dev_kfree_skb(skb);
|
|
return ATBM_NULL;
|
|
}
|
|
}
|
|
}
|
|
#if ATBM_SUPPORT_BRIDGE
|
|
if(peer_priv && peer_priv->connect_ok
|
|
&& atbm_memcmp(peer_priv->mac_addr, ATBM_OS_SKB_DATA(skb), ATBM_ETH_ALEN)
|
|
){
|
|
struct atbmwifi_ieee8023_hdr *brhdr;
|
|
struct atbm_buff *brskb;
|
|
|
|
brskb = get_sta_deliver_skb(skb);
|
|
if(brskb){
|
|
atbmwifi_tx_start(brskb,peer_priv);
|
|
}
|
|
}
|
|
return peer_priv;
|
|
#endif
|
|
}
|
|
#if ATBM_SUPPORT_BRIDGE
|
|
else{
|
|
struct atbm_buff *brskb;
|
|
if(!atbm_memcmp(hdr->h_dest,peer_priv->mac_addr,6)){
|
|
wifi_printk(WIFI_DBG_ERROR, "error unexpected data!!\n");
|
|
atbm_dev_kfree_skb(skb);
|
|
return ATBM_FALSE;
|
|
}
|
|
//wifi_printk(WIFI_ALWAYS, "iftype:%d\n", peer_priv->iftype);
|
|
if(peer_priv && peer_priv->connect_ok){
|
|
brskb = get_ap_deliver_skb(skb);
|
|
if(brskb){
|
|
atbmwifi_tx_start(brskb,peer_priv);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
return priv;
|
|
}
|
|
|
|
atbm_void atbmwifi_ieee80211_deliver_skb(struct atbmwifi_vif *priv,struct atbm_buff *skb,atbm_uint16 *need_free)
|
|
{
|
|
struct atbmwifi_vif *tx_priv;
|
|
if(!eapol_input(priv,skb)){
|
|
if(priv->assoc_ok==1){
|
|
//if ap mode ,we need forward mul-data or unicast data for other sta
|
|
tx_priv = atbmwifi_ieee80211_forward_skb(priv,skb);
|
|
if(tx_priv){
|
|
tcp_opt->net_rx(tx_priv->ndev,skb);
|
|
}
|
|
*need_free=0;
|
|
}
|
|
}else{
|
|
*need_free=0;
|
|
}
|
|
}
|
|
|
|
#if ATBM_SUPPORT_BRIDGE
|
|
int atbmwifi_br_tx_skb(struct atbmwifi_vif *priv,struct atbm_buff *skb){
|
|
struct atbmwifi_vif *peer_priv;
|
|
struct atbm_buff *txskb;
|
|
struct atbmwifi_sta_priv * sta_priv =ATBM_NULL;
|
|
struct atbmwifi_ieee8023_hdr *hdr = (struct atbmwifi_ieee8023_hdr *) ATBM_OS_SKB_DATA(skb);
|
|
|
|
if(!atbmwifi_is_sta_mode(priv->iftype)){
|
|
return 0;
|
|
}
|
|
|
|
peer_priv = _atbmwifi_hwpriv_to_vifpriv(priv->hw_priv, !(priv->if_id));
|
|
if(peer_priv && peer_priv->connect_ok){
|
|
if (atbm_is_multicast_ether_addr(hdr->h_dest)) {
|
|
txskb = atbm_dev_alloc_skb(ATBM_OS_SKB_LEN(skb));
|
|
if (txskb) {
|
|
txskb->priority = 0;
|
|
atbm_memcpy(ATBM_OS_SKB_DATA(txskb), ATBM_OS_SKB_DATA(skb), ATBM_OS_SKB_LEN(skb));
|
|
atbm_skb_put(txskb,ATBM_OS_SKB_LEN(skb));
|
|
atbmwifi_tx_start(txskb, peer_priv);
|
|
}
|
|
}else{
|
|
sta_priv = atbmwifi_sta_find(peer_priv,hdr->h_dest);
|
|
if (sta_priv) {
|
|
txskb = atbm_dev_alloc_skb(ATBM_OS_SKB_LEN(skb));
|
|
if (txskb) {
|
|
txskb->priority = 0;
|
|
atbm_memcpy(ATBM_OS_SKB_DATA(txskb), ATBM_OS_SKB_DATA(skb), ATBM_OS_SKB_LEN(skb));
|
|
atbm_skb_put(txskb,ATBM_OS_SKB_LEN(skb));
|
|
atbmwifi_tx_start(txskb, peer_priv);
|
|
}
|
|
atbm_dev_kfree_skb(skb);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
#endif
|
|
/*
|
|
amsdu return ATBM_TRUE, else return 0;
|
|
need free skb return 0, else return 1;
|
|
*/
|
|
int atbmwifi_ieee80211_rx_h_amsdu(struct atbmwifi_vif *priv,struct atbm_buff *skb)
|
|
{
|
|
struct atbmwifi_ieee80211_hdr *hdr;
|
|
atbm_uint16 fc;
|
|
atbm_uint16 need_free = 1;
|
|
struct atbm_buff_head frame_list;
|
|
struct atbmwifi_ieee80211_rx_status *status = ATBM_IEEE80211_SKB_RXCB(skb);
|
|
|
|
|
|
if (!(status->flag & ATBM_RX_FLAG_AMSDU)){
|
|
return 0;
|
|
}
|
|
hdr = (struct atbmwifi_ieee80211_hdr *) ATBM_OS_SKB_DATA(skb);
|
|
|
|
if (atbm_is_multicast_ether_addr(hdr->addr1))
|
|
goto drop;
|
|
|
|
if(status->flag & ATBM_RX_FLAG_DECRYPTED){
|
|
switch(priv->connect.crypto_pairwise){
|
|
case ATBM_WLAN_CIPHER_SUITE_WEP40:
|
|
case ATBM_WLAN_CIPHER_SUITE_WEP104:
|
|
case ATBM_WLAN_CIPHER_SUITE_TKIP:
|
|
goto drop;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
fc = hdr->frame_control;
|
|
|
|
|
|
__atbm_skb_queue_head_init(&frame_list);
|
|
|
|
|
|
|
|
atbmwifi_ieee80211_amsdu_to_8023s(skb, &frame_list, priv->mac_addr,
|
|
priv->iftype, ATBM_TRUE);
|
|
|
|
while (!atbm_skb_queue_empty(&frame_list)) {
|
|
skb = atbm_skb_dequeue(&frame_list);
|
|
|
|
if (!atbmwifi_ieee80211_frame_allowed(skb, fc)) {
|
|
atbm_dev_kfree_skb(skb);
|
|
continue;
|
|
}
|
|
atbmwifi_ieee80211_deliver_skb(priv,skb,&need_free);
|
|
if(need_free){
|
|
atbm_dev_kfree_skb(skb);
|
|
need_free = 1;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
drop:
|
|
atbm_dev_kfree_skb(skb);
|
|
return 1;
|
|
}
|
|
|
|
|
|
|
|
int atbmwifi_ieee80211_data_to_8023(struct atbm_buff *skb, const atbm_uint8 *addr,
|
|
enum atbm_nl80211_iftype iftype)
|
|
{
|
|
struct atbmwifi_ieee80211_hdr *hdr = (struct atbmwifi_ieee80211_hdr *) ATBM_OS_SKB_DATA(skb);
|
|
atbm_uint16 hdrlen, ethertype;
|
|
atbm_uint8 *payload;
|
|
atbm_uint8 dst[ATBM_ETH_ALEN];
|
|
atbm_uint8 src[ATBM_ETH_ALEN];
|
|
|
|
if (atbm_unlikely(!atbmwifi_ieee80211_is_data_present(hdr->frame_control)))
|
|
return -1;
|
|
|
|
hdrlen = atbmwifi_ieee80211_hdrlen(hdr->frame_control);
|
|
|
|
/* convert IEEE 802.11 header + possible LLC headers into Ethernet
|
|
* header
|
|
* IEEE 802.11 address fields:
|
|
* ToDS FromDS Addr1 Addr2 Addr3 Addr4
|
|
* 0 0 DA SA BSSID n/a
|
|
* 0 1 DA BSSID SA n/a
|
|
* 1 0 BSSID SA DA n/a
|
|
* 1 1 RA TA DA SA
|
|
*/
|
|
atbm_memcpy(dst, atbmwifi_ieee80211_get_DA(hdr), ATBM_ETH_ALEN);
|
|
atbm_memcpy(src, atbmwifi_ieee80211_get_SA(hdr), ATBM_ETH_ALEN);
|
|
|
|
switch (hdr->frame_control &
|
|
atbm_cpu_to_le16(ATBM_IEEE80211_FCTL_TODS | ATBM_IEEE80211_FCTL_FROMDS)) {
|
|
case atbm_cpu_to_le16(ATBM_IEEE80211_FCTL_TODS):
|
|
if (atbm_unlikely(!atbmwifi_is_ap_mode(iftype)))
|
|
return -1;
|
|
break;
|
|
case atbm_cpu_to_le16(ATBM_IEEE80211_FCTL_TODS | ATBM_IEEE80211_FCTL_FROMDS):
|
|
//if (unlikely(iftype != NL80211_IFTYPE_WDS &&
|
|
// iftype != ATBM_NL80211_IFTYPE_STATION))
|
|
return -1;
|
|
break;
|
|
case atbm_cpu_to_le16(ATBM_IEEE80211_FCTL_FROMDS):
|
|
if (!atbmwifi_is_sta_mode(iftype) ||
|
|
(atbm_is_multicast_ether_addr(dst) &&
|
|
!atbm_compare_ether_addr(src, addr)))
|
|
return -1;
|
|
break;
|
|
case atbm_cpu_to_le16(0):
|
|
if (iftype != ATBM_NL80211_IFTYPE_ADHOC &&
|
|
iftype != ATBM_NL80211_IFTYPE_STATION)
|
|
return -1;
|
|
break;
|
|
}
|
|
|
|
payload = ATBM_OS_SKB_DATA(skb) + hdrlen;
|
|
ethertype = (payload[6] << 8) | payload[7];
|
|
if (atbm_likely((atbm_compare_ether_addr(payload, atbm_rfc1042_header) == 0 &&
|
|
ethertype != ATBM_ETH_P_AARP && ethertype != ATBM_ETH_P_IPX) ||
|
|
atbm_compare_ether_addr(payload, atbm_bridge_tunnel_header) == 0)) {
|
|
/* remove RFC1042 or Bridge-Tunnel encapsulation and
|
|
* replace EtherType */
|
|
atbm_skb_pull(skb, hdrlen + 6);
|
|
atbm_memcpy(atbm_skb_push(skb, ATBM_ETH_ALEN), src, ATBM_ETH_ALEN);
|
|
atbm_memcpy(atbm_skb_push(skb, ATBM_ETH_ALEN), dst, ATBM_ETH_ALEN);
|
|
} else {
|
|
struct atbmwifi_ieee8023_hdr *ehdr;
|
|
atbm_uint16 len;
|
|
|
|
atbm_skb_pull(skb, hdrlen);
|
|
len = atbm_htons(ATBM_OS_SKB_LEN(skb));
|
|
ehdr = (struct atbmwifi_ieee8023_hdr *) atbm_skb_push(skb, sizeof(struct atbmwifi_ieee8023_hdr));
|
|
atbm_memcpy(ehdr->h_dest, dst, ATBM_ETH_ALEN);
|
|
atbm_memcpy(ehdr->h_source, src, ATBM_ETH_ALEN);
|
|
ehdr->h_proto = ethertype;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int atbmwifi_ieee80211_data_from_8023(struct atbm_buff *skb, const atbm_uint8 *addr,
|
|
enum atbm_nl80211_iftype iftype, atbm_uint8 *bssid, ATBM_BOOL qos,atbm_uint8 encrype)
|
|
{
|
|
struct atbmwifi_ieee80211_qos_hdr * hdr;
|
|
struct atbmwifi_ieee8023_hdr *ethdr = (struct atbmwifi_ieee8023_hdr *)ATBM_OS_SKB_DATA(skb);
|
|
atbm_uint16 hdrlen, ethertype;
|
|
atbm_uint8 * llchdr=ATBM_NULL;
|
|
atbm_uint16 fc;
|
|
const atbm_uint8 *encaps_data;
|
|
int encaps_len, skip_header_bytes;
|
|
|
|
if (atbm_unlikely(ATBM_OS_SKB_LEN(skb) < ATBM_ETH_HLEN))
|
|
return -ATBM_EINVAL;
|
|
/* convert Ethernet header to proper 802.11 header (based on
|
|
* operation mode) */
|
|
ethertype = atbm_ntohs(ethdr->h_proto);
|
|
|
|
|
|
fc = atbm_cpu_to_le16(ATBM_IEEE80211_FTYPE_DATA | ATBM_IEEE80211_STYPE_DATA);
|
|
|
|
skip_header_bytes = ATBM_ETH_HLEN;
|
|
if (ethertype == ATBM_ETH_P_AARP || ethertype == ATBM_ETH_P_IPX) {
|
|
encaps_data = atbm_bridge_tunnel_header;
|
|
encaps_len = sizeof(atbm_bridge_tunnel_header);
|
|
skip_header_bytes -= 2;
|
|
} else if (ethertype > 0x600) {
|
|
encaps_data = atbm_rfc1042_header;
|
|
encaps_len = sizeof(atbm_rfc1042_header);
|
|
skip_header_bytes -= 2;
|
|
} else {
|
|
encaps_data = ATBM_NULL;
|
|
encaps_len = 0;
|
|
}
|
|
atbm_skb_pull(skb, skip_header_bytes);
|
|
|
|
if (encaps_data) {
|
|
llchdr = atbm_skb_push(skb, encaps_len);
|
|
}
|
|
|
|
hdrlen = 24;
|
|
if (qos)
|
|
hdrlen += 2;
|
|
hdr= (struct atbmwifi_ieee80211_qos_hdr *)atbm_skb_push(skb, hdrlen);
|
|
fc = atbm_cpu_to_le16(ATBM_IEEE80211_FTYPE_DATA | ATBM_IEEE80211_STYPE_DATA);
|
|
|
|
switch (iftype) {
|
|
case ATBM_NL80211_IFTYPE_AP:
|
|
case ATBM_NL80211_IFTYPE_P2P_GO:
|
|
fc |= atbm_cpu_to_le16(ATBM_IEEE80211_FCTL_FROMDS);
|
|
/* DA BSSID SA */
|
|
atbm_memcpy(hdr->addr1, ethdr->h_dest, ATBM_ETH_ALEN);
|
|
atbm_memcpy(hdr->addr2, addr, ATBM_ETH_ALEN);
|
|
atbm_memcpy(hdr->addr3, ethdr->h_source, ATBM_ETH_ALEN);
|
|
break;
|
|
case ATBM_NL80211_IFTYPE_STATION:
|
|
case ATBM_NL80211_IFTYPE_P2P_CLIENT:
|
|
fc |= atbm_cpu_to_le16(ATBM_IEEE80211_FCTL_TODS);
|
|
/* BSSID SA DA */
|
|
atbm_memcpy(hdr->addr1, bssid, ATBM_ETH_ALEN);
|
|
atbm_memcpy(hdr->addr2, ethdr->h_source, ATBM_ETH_ALEN);
|
|
atbm_memcpy(hdr->addr3, ethdr->h_dest, ATBM_ETH_ALEN);
|
|
break;
|
|
#ifdef CONFIG_WIFI_IBSS
|
|
case ATBM_NL80211_IFTYPE_ADHOC:
|
|
/* DA SA BSSID */
|
|
atbm_memcpy(hdr->addr1, ethdr->h_dest, ATBM_ETH_ALEN);
|
|
atbm_memcpy(hdr->addr2, ethdr->h_source, ATBM_ETH_ALEN);
|
|
atbm_memcpy(hdr->addr3, bssid, ATBM_ETH_ALEN);
|
|
break;
|
|
#endif /*CONFIG_WIFI_IBSS*/
|
|
default:
|
|
return -ATBM_EOPNOTSUPP;
|
|
}
|
|
|
|
if (qos) {
|
|
atbm_uint8 ack_policy=0, tid;
|
|
fc |= atbm_cpu_to_le16(ATBM_IEEE80211_STYPE_QOS_DATA);
|
|
/* use the data classifier to determine what 802.1d tag the
|
|
* data frame has */
|
|
tid = skb->priority & ATBM_IEEE80211_QOS_CTL_TAG1D_MASK;
|
|
|
|
/* qos header is 2 bytes */
|
|
hdr->qos_ctrl = ack_policy | tid;
|
|
}
|
|
|
|
hdr->frame_control = fc;
|
|
hdr->duration_id = 0;
|
|
hdr->seq_ctrl = 0;
|
|
if (encaps_data) {
|
|
atbm_memcpy(llchdr, encaps_data, encaps_len);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#if ATBM_DRIVER_PROCESS_BA
|
|
int ieee80211_tx_h_sequence(struct atbmwifi_sta_priv *sta_priv, struct atbm_buff *skb, int tid)
|
|
{
|
|
struct atbmwifi_ieee80211_tx_info *info = ATBM_IEEE80211_SKB_TXCB(skb);
|
|
struct atbmwifi_ieee80211_hdr *hdr = (struct atbmwifi_ieee80211_hdr *)ATBM_OS_SKB_DATA(skb);
|
|
atbm_uint16 *seq;
|
|
atbm_uint8 *qc;
|
|
|
|
/*
|
|
* Packet injection may want to control the sequence
|
|
* number, if we have no matching interface then we
|
|
* neither assign one ourselves nor ask the driver to.
|
|
*/
|
|
|
|
if (atbm_unlikely(atbmwifi_ieee80211_is_ctl(hdr->frame_control)))
|
|
return TX_CONTINUE;
|
|
|
|
if (atbmwifi_ieee80211_hdrlen(hdr->frame_control) < 24)
|
|
return TX_CONTINUE;
|
|
|
|
if (atbmwifi_ieee80211_is_qos_nullfunc(hdr->frame_control))
|
|
return TX_CONTINUE;
|
|
|
|
/*
|
|
* Anything but QoS data that has a sequence number field
|
|
* (is long enough) gets a sequence number from the global
|
|
* counter.
|
|
*/
|
|
if (!atbmwifi_ieee80211_is_data_qos(hdr->frame_control)) {
|
|
/* driver should assign sequence number */
|
|
info->flags |= ATBM_IEEE80211_TX_CTL_ASSIGN_SEQ;
|
|
return TX_CONTINUE;
|
|
}
|
|
|
|
/*
|
|
* This should be true for injected/management frames only, for
|
|
* management frames we have set the IEEE80211_TX_CTL_ASSIGN_SEQ
|
|
* above since they are not QoS-data frames.
|
|
*/
|
|
if (!sta_priv)
|
|
return TX_CONTINUE;
|
|
|
|
/* include per-STA, per-TID sequence counter */
|
|
|
|
//qc = ieee80211_get_qos_ctl(hdr);
|
|
//tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
|
|
seq = &sta_priv->tid_seq[tid];
|
|
|
|
hdr->seq_ctrl = atbm_cpu_to_le16(*seq);
|
|
|
|
/* Increase the sequence number. */
|
|
*seq = (*seq + 0x10) & ATBM_IEEE80211_SCTL_SEQ;
|
|
|
|
return TX_CONTINUE;
|
|
}
|
|
#endif
|
|
|
|
atbm_void atbmwifi_ieee80211_get_sta_rateinfo(struct atbmwifi_cfg80211_rate *sta,
|
|
struct atbmwifi_ieee80211_supported_band *band, atbm_uint8 *supp_rates,int supp_rates_len)
|
|
{
|
|
int i,j;
|
|
int rate =0;
|
|
ATBM_BOOL is_basic;
|
|
for (i = 0; i < supp_rates_len; i++) {
|
|
rate = (supp_rates[i] & 0x7f);
|
|
is_basic = !!(supp_rates[i] & 0x80);
|
|
|
|
for (j = 0; j < band->n_bitrates; j++) {
|
|
if (band->bitrates[j].bitrate == rate) {
|
|
sta->support_rates |= BIT(j);
|
|
if (is_basic)
|
|
sta->basic_rates |= BIT(j);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
add support rate ie
|
|
add exsupport rate ie
|
|
*/
|
|
atbm_uint8 * atbmwifi_ieee80211_add_rate_ie(atbm_uint8 * pos,ATBM_BOOL no_cck,atbm_uint32 mask)
|
|
{
|
|
|
|
int supp_rates_len;
|
|
struct atbmwifi_ieee80211_rate *rate;
|
|
int num_rates;
|
|
int ext_rates_len;
|
|
int i;
|
|
atbm_uint8 * prate_len =0;
|
|
|
|
#if CONFIG_5G_SUPPORT
|
|
if(no_cck){
|
|
rate = atbmwifi_a_rates;
|
|
num_rates = atbmwifi_a_rates_size;
|
|
}else
|
|
#endif
|
|
{
|
|
rate = atbmwifi_g_rates;
|
|
num_rates = atbmwifi_g_rates_size;
|
|
}
|
|
//
|
|
///build support rate
|
|
//
|
|
supp_rates_len = 0;
|
|
*pos++ = ATBM_WLAN_EID_SUPP_RATES;
|
|
//save rate len point
|
|
prate_len = pos;
|
|
*pos++ = supp_rates_len;
|
|
|
|
for(i=0;i<num_rates;i++){
|
|
*pos++ = (atbm_uint8) (rate[i].bitrate)|(ATBM_IEEE80211_RT_BASIC & rate[i].rate_flag);
|
|
if (++supp_rates_len == 8){
|
|
i++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
*prate_len = supp_rates_len;
|
|
|
|
if(i == num_rates || mask < BIT(i))
|
|
return pos;
|
|
|
|
//
|
|
///buildex support rate
|
|
//
|
|
|
|
ext_rates_len = 0;
|
|
*pos++ = ATBM_WLAN_EID_EXT_SUPP_RATES;
|
|
//save rate len point
|
|
prate_len = pos;
|
|
*pos++ = ext_rates_len;
|
|
for(;i<num_rates;i++){
|
|
if(mask&BIT(i)){
|
|
*pos++ = (atbm_uint8) (rate[i].bitrate)|(ATBM_IEEE80211_RT_BASIC & rate[i].rate_flag);
|
|
ext_rates_len++;
|
|
}
|
|
}
|
|
*prate_len = ext_rates_len;
|
|
|
|
return pos;
|
|
}
|
|
|
|
/*
|
|
only called when sending assoc req
|
|
add support rate ie
|
|
add exsupport rate ie
|
|
*/
|
|
atbm_uint8 * atbmwifi_ieee80211_add_rate_ie_from_ap(atbm_uint8 * pos,ATBM_BOOL no_cck,atbm_uint32 mask, atbm_uint32 basic_mask)
|
|
{
|
|
|
|
int supp_rates_len;
|
|
struct atbmwifi_ieee80211_rate *rate;
|
|
int num_rates;
|
|
int ext_rates_len;
|
|
int i;
|
|
atbm_uint8 * prate_len =0;
|
|
|
|
#if CONFIG_5G_SUPPORT
|
|
if(no_cck){
|
|
rate = atbmwifi_a_rates;
|
|
num_rates = atbmwifi_a_rates_size;
|
|
}else
|
|
#endif
|
|
{
|
|
rate = atbmwifi_g_rates;
|
|
num_rates = atbmwifi_g_rates_size;
|
|
}
|
|
|
|
///build support rate
|
|
//
|
|
supp_rates_len = 0;
|
|
*pos++ = ATBM_WLAN_EID_SUPP_RATES;
|
|
//save rate len point
|
|
prate_len = pos;
|
|
*pos++ = supp_rates_len;
|
|
|
|
for(i=0;i<num_rates;i++){
|
|
if(mask&BIT(i)){
|
|
if(basic_mask & BIT(i))
|
|
*pos++ = (atbm_uint8) (rate[i].bitrate)|ATBM_IEEE80211_RT_BASIC;
|
|
else
|
|
*pos++ = (atbm_uint8) (rate[i].bitrate);
|
|
if (++supp_rates_len == 8){
|
|
i++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
*prate_len = supp_rates_len;
|
|
if(i==num_rates || mask < BIT(i))
|
|
return pos;
|
|
|
|
//
|
|
///buildex support rate
|
|
//
|
|
ext_rates_len = 0;
|
|
*pos++ = ATBM_WLAN_EID_EXT_SUPP_RATES;
|
|
//save rate len point
|
|
prate_len = pos;
|
|
*pos++ = ext_rates_len;
|
|
for(;i<num_rates;i++){
|
|
if(mask&BIT(i)){
|
|
if(basic_mask & BIT(i))
|
|
*pos++ = (atbm_uint8) (rate[i].bitrate)|ATBM_IEEE80211_RT_BASIC;
|
|
else
|
|
*pos++ = (atbm_uint8) (rate[i].bitrate);
|
|
ext_rates_len++;
|
|
}
|
|
}
|
|
*prate_len = ext_rates_len;
|
|
|
|
return pos;
|
|
}
|
|
|
|
/* Given a data frame determine the 802.1p/1d tag to use. */
|
|
unsigned int atbm_cfg80211_classify8021d(struct atbm_buff *skb)
|
|
{
|
|
#ifdef CONFIG_OS_FREERTOS
|
|
unsigned int dscp;
|
|
struct atbm_ip_hdr *iphdr;
|
|
struct atbmwifi_ieee8023_hdr *ethhdr;
|
|
atbm_uint16 protocol = 0;
|
|
|
|
ethhdr = (struct atbmwifi_ieee8023_hdr *)ATBM_OS_SKB_DATA(skb);
|
|
protocol = atbm_htons(ethhdr->h_proto);
|
|
|
|
if (protocol==atbm_htons(ATBM_ETH_P_IP)){
|
|
//dscp = (unsigned int)(atbm_skb_pull(skb,ETH_HLEN+1)) & 0xfc;
|
|
iphdr = (struct atbm_ip_hdr *)(((atbm_uint8 *)ATBM_OS_SKB_DATA(skb))+ATBM_ETH_HLEN);
|
|
dscp = ATBM_IPH_TOS(iphdr) & 0xfc;
|
|
}
|
|
else{
|
|
return 0;
|
|
}
|
|
return dscp >> 5;
|
|
#else //#ifndef CONFIG_OS_FREERTOS
|
|
return skb->priority;
|
|
#endif //#ifndef CONFIG_OS_FREERTOS
|
|
}
|
|
|
|
atbm_uint8 *atbmwifi_find_ie(atbm_uint8 eid, const atbm_uint8 *ies, int len)
|
|
{
|
|
while (len > 2 && ies[0] != eid) {
|
|
len -= ies[1] + 2;
|
|
ies += ies[1] + 2;
|
|
}
|
|
if (len < 2)
|
|
return ATBM_NULL;
|
|
if (len < 2 + ies[1])
|
|
return ATBM_NULL;
|
|
return (atbm_uint8 *)ies;
|
|
}
|
|
|
|
/*
|
|
atbm_uint8 *atbm_cfg80211_find_vendor_ie(atbm_uint8 * oui,
|
|
const atbm_uint8 *ies, int len)
|
|
{
|
|
struct atbmwifi_ieee80211_vendor_ie *ie;
|
|
const atbm_uint8 *pos = ies, *end = ies + len;
|
|
atbm_uint32 ie_oui;
|
|
atbm_uint32 find_oui;
|
|
|
|
#define ATBM_WPA_GET_BE32(a) ((((atbm_uint32) (a)[0]) << 24) | (((atbm_uint32) (a)[1]) << 16) | \
|
|
(((atbm_uint32) (a)[2]) << 8) | ((atbm_uint32) (a)[3]))
|
|
|
|
while (pos < end) {
|
|
pos = atbmwifi_find_ie(ATBM_WLAN_EID_VENDOR_SPECIFIC, pos,
|
|
end - pos);
|
|
if (!pos)
|
|
return ATBM_NULL;
|
|
|
|
if (end - pos < sizeof(*ie))
|
|
return ATBM_NULL;
|
|
|
|
ie = (struct atbmwifi_ieee80211_vendor_ie *)pos;
|
|
ie_oui = ATBM_WPA_GET_BE32(&ie->oui[0]);
|
|
find_oui = ATBM_WPA_GET_BE32(oui);
|
|
if (ie_oui == find_oui)
|
|
return(atbm_uint8 *) pos;
|
|
|
|
pos += 2 + ie->len;
|
|
}
|
|
return ATBM_NULL;
|
|
}
|
|
*/
|
|
/*
|
|
* Set the direction field and address fields of an outgoing
|
|
* non-QoS frame. Note this should be called early on in
|
|
* constructing a frame as it sets i_fc[1]; other bits can
|
|
* then be or'd in.
|
|
*/
|
|
#if 0
|
|
atbm_void atbmwifi_ieee80211_buid_machdr(
|
|
struct atbmwifi_vif *priv,
|
|
struct atbmwifi_ieee80211_hdr *wh,
|
|
int type,
|
|
const atbm_uint8 sa[ATBM_IEEE80211_ADDR_LEN],
|
|
const atbm_uint8 da[ATBM_IEEE80211_ADDR_LEN],
|
|
const atbm_uint8 bssid[ATBM_IEEE80211_ADDR_LEN])
|
|
{
|
|
|
|
wh->i_fc[0] =/* IEEE80211_FC0_VERSION_0 |*/ type;
|
|
if ((type & ATBM_IEEE80211_FCTL_FTYPE ) == ATBM_IEEE80211_FTYPE_DATA) {
|
|
switch (priv->iftype) {
|
|
case ATBM_NL80211_IFTYPE_STATION:
|
|
wh->i_fc[1] = ATBM_IEEE80211_FCTL_TODS;
|
|
ATBM_IEEE80211_ADDR_COPY(wh->addr1, bssid);
|
|
ATBM_IEEE80211_ADDR_COPY(wh->addr2, sa);
|
|
ATBM_IEEE80211_ADDR_COPY(wh->addr3, da);
|
|
break;
|
|
case ATBM_NL80211_IFTYPE_ADHOC:
|
|
wh->i_fc[1] = 0;//IEEE80211_FC1_DIR_NODS;
|
|
ATBM_IEEE80211_ADDR_COPY(wh->addr1, da);
|
|
ATBM_IEEE80211_ADDR_COPY(wh->addr2, sa);
|
|
ATBM_IEEE80211_ADDR_COPY(wh->addr3, bssid);
|
|
break;
|
|
case ATBM_NL80211_IFTYPE_AP:
|
|
wh->i_fc[1] = ATBM_IEEE80211_FCTL_FROMDS;
|
|
ATBM_IEEE80211_ADDR_COPY(wh->addr1, da);
|
|
ATBM_IEEE80211_ADDR_COPY(wh->addr2, bssid);
|
|
ATBM_IEEE80211_ADDR_COPY(wh->addr3, sa);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
wh->i_fc[1] = 0;// IEEE80211_FC1_DIR_NODS;
|
|
ATBM_IEEE80211_ADDR_COPY(wh->addr1, da);
|
|
ATBM_IEEE80211_ADDR_COPY(wh->addr2, sa);
|
|
ATBM_IEEE80211_ADDR_COPY(wh->addr3, bssid);
|
|
}
|
|
wh->duration_id= 0;
|
|
/* NB: use non-QoS tid */
|
|
wh->seq_ctrl = 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/* TODO: maintain separate sequence and fragment numbers for each AC
|
|
* TODO: IGMP snooping to track which multicasts to forward - and use QOS-DATA
|
|
* if only WMM stations are receiving a certain group */
|
|
|
|
|
|
static atbm_uint8 wmm_aci_aifsn(int aifsn, int acm, int aci)
|
|
{
|
|
atbm_uint8 ret;
|
|
ret = (aifsn << ATBM_WMM_AC_AIFNS_SHIFT) & ATBM_WMM_AC_AIFSN_MASK;
|
|
if (acm)
|
|
ret |= ATBM_WMM_AC_ACM;
|
|
ret |= (aci << ATBM_WMM_AC_ACI_SHIFT) & ATBM_WMM_AC_ACI_MASK;
|
|
return ret;
|
|
}
|
|
|
|
|
|
static atbm_uint8 wmm_ecw(int ecwmin, int ecwmax)
|
|
{
|
|
return ((ecwmin << ATBM_WMM_AC_ECWMIN_SHIFT) & ATBM_WMM_AC_ECWMIN_MASK) |
|
|
((ecwmax << ATBM_WMM_AC_ECWMAX_SHIFT) & ATBM_WMM_AC_ECWMAX_MASK);
|
|
}
|
|
|
|
|
|
/*
|
|
* Add WMM Parameter Element to Beacon, Probe Response, and (Re)Association
|
|
* Response frames.
|
|
*/
|
|
atbm_uint8 * atbmwifi_ieee80211_add_wmm_param(struct atbmwifi_vif *priv, atbm_uint8 *eid)
|
|
{
|
|
atbm_uint8 *pos = eid;
|
|
struct wmm_parameter_element *wmm =
|
|
(struct wmm_parameter_element *) (pos + 2);
|
|
int e;
|
|
|
|
if (!priv->bss.sta_priv.wmm_used)
|
|
return eid;
|
|
eid[0] = ATBM_WLAN_EID_VENDOR_SPECIFIC;
|
|
wmm->oui[0] = 0x00;
|
|
wmm->oui[1] = 0x50;
|
|
wmm->oui[2] = 0xf2;
|
|
wmm->oui_type = ATBM_WMM_OUI_TYPE;
|
|
wmm->oui_subtype = ATBM_WMM_OUI_SUBTYPE_PARAMETER_ELEMENT;
|
|
wmm->version = WMM_VERSION;
|
|
wmm->qos_info = priv->bss.parameter_set_count & 0xf;
|
|
|
|
if (priv->bss.sta_priv.uapsd_supported)
|
|
wmm->qos_info |= ATBM_IEEE80211_WMM_IE_AP_QOSINFO_UAPSD;
|
|
|
|
wmm->reserved = 0;
|
|
|
|
/* fill in a parameter set record for each AC */
|
|
for (e = 0; e < 4; e++) {
|
|
struct wmm_ac_parameter *ac = &wmm->ac[e];
|
|
struct config_edca_params *wmm_param = &priv->wmm_params[e];
|
|
|
|
|
|
ac->aci_aifsn = wmm_aci_aifsn(wmm_param->aifns,
|
|
wmm_param->wmep_acm,
|
|
e);
|
|
ac->cw = wmm_ecw(wmm_param->cwMin, wmm_param->cwMax);
|
|
ac->txop_limit = atbm_host_to_le16( wmm_param->txOpLimit);
|
|
}
|
|
|
|
pos = (atbm_uint8 *) (wmm + 1);
|
|
eid[1] = pos - eid - 2; /* element length */
|
|
|
|
return pos;
|
|
}
|
|
|
|
#define WME_OUI_BYTES 0x00, 0x50, 0xf2
|
|
/*
|
|
* Add a WME Info element to a frame.
|
|
*/
|
|
atbm_uint8 *atbmwifi_ieee80211_add_wme(struct atbmwifi_vif *priv, atbm_uint8 *eid)
|
|
{
|
|
atbm_uint8 *pos = eid;
|
|
struct wmm_information_element *wmm =
|
|
(struct wmm_information_element *) (pos + 2);
|
|
//int e;
|
|
|
|
if (!priv->bss.sta_priv.wmm_used)
|
|
return eid;
|
|
|
|
eid[0] = ATBM_WLAN_EID_VENDOR_SPECIFIC;
|
|
wmm->oui[0] = 0x00;
|
|
wmm->oui[1] = 0x50;
|
|
wmm->oui[2] = 0xf2;
|
|
wmm->oui_type = ATBM_WMM_OUI_TYPE;
|
|
wmm->oui_subtype = ATBM_WMM_OUI_SUBTYPE_INFORMATION_ELEMENT;
|
|
wmm->version = WMM_VERSION;
|
|
|
|
/* QoS Info field depends on operating mode */
|
|
switch (priv->iftype) {
|
|
case ATBM_NL80211_IFTYPE_AP:
|
|
case ATBM_NL80211_IFTYPE_P2P_GO:
|
|
wmm->qos_info = priv->bss.parameter_set_count & 0xf;
|
|
if (priv->bss.sta_priv.uapsd_supported)
|
|
wmm->qos_info |= ATBM_IEEE80211_WMM_IE_AP_QOSINFO_UAPSD;
|
|
break;
|
|
case ATBM_NL80211_IFTYPE_STATION:
|
|
case ATBM_NL80211_IFTYPE_P2P_CLIENT:
|
|
if (priv->bss.sta_priv.uapsd_supported){
|
|
wmm->qos_info = priv->wmm_params[0].uapsdEnable
|
|
|( priv->wmm_params[1].uapsdEnable<<1)
|
|
|( priv->wmm_params[2].uapsdEnable<<2)
|
|
|( priv->wmm_params[3].uapsdEnable<<3);
|
|
wmm->qos_info |= (priv->bss.uapsd_max_sp_len <<
|
|
ATBM_IEEE80211_WMM_IE_STA_QOSINFO_SP_SHIFT);
|
|
}
|
|
else{
|
|
wmm->qos_info = 0;
|
|
}
|
|
break;
|
|
default:
|
|
wmm->qos_info = 0;
|
|
}
|
|
pos = (atbm_uint8 *) (wmm + 1);
|
|
eid[1] = pos - eid - 2; /* element length */
|
|
|
|
return pos;
|
|
}
|
|
|
|
atbm_uint8 * atbmwifi_ieee80211_add_wpa_ie(struct atbmwifi_vif *priv, atbm_uint8 *eid)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
atbm_uint8 * atbmwifi_ieee80211_add_ht_operation(struct atbmwifi_vif *priv, atbm_uint8 *eid)
|
|
{
|
|
#if BW_40M_SUPPORT
|
|
struct atbmwifi_cfg *config = atbmwifi_get_config(priv);
|
|
#endif
|
|
struct atbmwifi_ieee80211_ht_operation *oper;
|
|
atbm_uint8 *pos = eid;
|
|
|
|
*pos++ = ATBM_WLAN_EID_HT_OPERATION;
|
|
*pos++ = sizeof(*oper);
|
|
wifi_printk(WIFI_DBG_MSG,"atbm: atbmwifi_ieee80211_add_ht_operation() ===>\n");
|
|
|
|
oper = (struct atbmwifi_ieee80211_ht_operation *) pos;
|
|
atbm_memset(oper, 0, sizeof(*oper));
|
|
oper->control_chan = priv->config.channel_index;
|
|
oper->ht_param = ATBM_IEEE80211_HT_PARAM_CHA_SEC_NONE
|
|
/*|IEEE80211_HT_PARAM_SPSMP_SUPPORT*/;
|
|
oper->operation_mode = ATBM_IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED
|
|
|ATBM_IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT
|
|
|ATBM_IEEE80211_HT_OP_MODE_BURST_TX_LIMIT;
|
|
#if BW_40M_SUPPORT
|
|
if (config->secondary_channel == 1){
|
|
oper->ht_param |= ATBM_IEEE80211_HT_PARAM_CHA_SEC_ABOVE |
|
|
ATBM_IEEE80211_HT_PARAM_CHAN_WIDTH_ANY;
|
|
}
|
|
else if (config->secondary_channel == -1){
|
|
oper->ht_param |= ATBM_IEEE80211_HT_PARAM_CHA_SEC_BELOW |
|
|
ATBM_IEEE80211_HT_PARAM_CHAN_WIDTH_ANY;
|
|
}
|
|
//enable rifs mode
|
|
oper->ht_param |=ATBM_IEEE80211_HT_PARAM_RIFS_MODE;
|
|
#endif
|
|
atbm_memcpy(pos, oper, sizeof(*oper));
|
|
pos += sizeof(*oper);
|
|
wifi_printk(WIFI_DBG_MSG,"atbm: atbmwifi_ieee80211_add_ht_operation() <===\n");
|
|
return pos;
|
|
}
|
|
|
|
atbm_uint8 * atbmwifi_ieee80211_add_ht_ie(struct atbmwifi_vif *priv,
|
|
struct atbmwifi_ieee80211_supported_band *band, atbm_uint8 * pos)
|
|
{
|
|
//struct atbmwifi_ieee80211_ht_info *ht_info;
|
|
atbm_uint16 cap = 0;
|
|
atbm_uint16 tmp;
|
|
|
|
|
|
//case IEEE80211_SMPS_OFF:
|
|
cap = band->ht_cap.cap;
|
|
|
|
/* reserve and fill IE */
|
|
*pos++ = ATBM_WLAN_EID_HT_CAPABILITY;
|
|
*pos++ = sizeof(struct atbmwifi_ieee80211_ht_cap);
|
|
atbm_memset(pos, 0, sizeof(struct atbmwifi_ieee80211_ht_cap));
|
|
|
|
/* capability flags */
|
|
tmp = atbm_cpu_to_le16(cap);
|
|
atbm_memcpy(pos, &tmp, sizeof(atbm_uint16));
|
|
pos += sizeof(atbm_uint16);
|
|
|
|
/* AMPDU parameters */
|
|
*pos++ = band->ht_cap.ampdu_factor |
|
|
( band->ht_cap.ampdu_density<<
|
|
ATBM_IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
|
|
|
|
/* MCS set */
|
|
atbm_memcpy(pos, &band->ht_cap.mcs, sizeof(band->ht_cap.mcs));
|
|
pos += sizeof(band->ht_cap.mcs);
|
|
|
|
/* extended capabilities */
|
|
pos += sizeof(atbm_uint16);
|
|
|
|
/* BF capabilities */
|
|
pos += sizeof(atbm_uint32);
|
|
|
|
/* antenna selection */
|
|
pos += sizeof(atbm_uint8);
|
|
return pos;
|
|
}
|
|
|
|
/* frame sending functions */
|
|
atbm_void atbmwifi_ieee80211_send_deauth_disassoc(struct atbmwifi_vif *priv,
|
|
const atbm_uint8 *da,const atbm_uint8 *bssid, atbm_uint16 stype, atbm_uint16 reason,
|
|
atbm_void *cookie, ATBM_BOOL send_frame)
|
|
{
|
|
struct atbmwifi_common * hw_priv = priv->hw_priv;
|
|
struct atbm_buff *skb;
|
|
struct atbmwifi_ieee80211_mgmt *mgmt;
|
|
|
|
skb = atbm_dev_alloc_skb( sizeof(*mgmt));
|
|
if (!skb)
|
|
return;
|
|
|
|
//atbm_skb_reserve(skb, local->hw.extra_tx_headroom);
|
|
|
|
mgmt = (struct atbmwifi_ieee80211_mgmt *) atbm_skb_put(skb, 24);
|
|
atbm_memset(mgmt, 0, 24);
|
|
atbm_memcpy(mgmt->da, da,ATBM_ETH_ALEN);
|
|
atbm_memcpy(mgmt->sa, priv->mac_addr, ATBM_ETH_ALEN);
|
|
atbm_memcpy(mgmt->bssid, bssid, ATBM_ETH_ALEN);
|
|
mgmt->frame_control = atbm_cpu_to_le16(ATBM_IEEE80211_FTYPE_MGMT | stype);
|
|
atbm_skb_put(skb, 2);
|
|
/* u.deauth.reason_code == u.disassoc.reason_code */
|
|
mgmt->u.deauth.reason_code = atbm_cpu_to_le16(reason);
|
|
|
|
//__cfg80211_send_deauth(sdata->dev, (atbm_uint8 *)mgmt, skb->data_len);
|
|
|
|
ATBM_IEEE80211_SKB_TXCB(skb)->flags |= ATBM_IEEE80211_TX_INTFL_DONT_ENCRYPT;
|
|
ATBM_IEEE80211_SKB_TXCB(skb)->flags |= ATBM_IEEE80211_TX_CTL_USE_MINRATE;
|
|
|
|
atbmwifi_tx(hw_priv,skb,priv);
|
|
|
|
}
|
|
|
|
atbm_void atbmwifi_ieee80211_connection_loss(struct atbmwifi_vif *priv)
|
|
{
|
|
|
|
if (!priv->assoc_ok) {
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* must be outside lock due to cfg80211,
|
|
* but that's not a problem.
|
|
*/
|
|
atbmwifi_ieee80211_send_deauth_disassoc(priv, priv->daddr,priv->bssid,
|
|
ATBM_IEEE80211_STYPE_DEAUTH,
|
|
ATBM_WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
|
|
ATBM_NULL, ATBM_TRUE);
|
|
}
|
|
atbm_void atbmwifi_ieee80211_ht_cap_ie_to_sta_ht_cap(struct atbmwifi_ieee80211_supported_band *sband,
|
|
struct atbmwifi_ieee80211_ht_cap *ht_cap_ie,
|
|
struct atbmwifi_ieee80211_sta_ht_cap *ht_cap)
|
|
{
|
|
atbm_uint8 ampdu_info, tx_mcs_set_cap;
|
|
int i, max_tx_streams;
|
|
|
|
ATBM_BUG_ON(!ht_cap);
|
|
|
|
atbm_memset(ht_cap, 0, sizeof(*ht_cap));
|
|
|
|
if (!ht_cap_ie || !sband->ht_cap.ht_supported)
|
|
return;
|
|
|
|
ht_cap->ht_supported = ATBM_TRUE;
|
|
|
|
/*
|
|
* The bits listed in this expression should be
|
|
* the same for the peer and us, if the station
|
|
* advertises more then we can't use those thus
|
|
* we mask them out.
|
|
*/
|
|
ht_cap->cap = atbm_le16_to_cpu(ht_cap_ie->cap_info) & sband->ht_cap.cap;
|
|
/*
|
|
* The STBC bits are asymmetric -- if we don't have
|
|
* TX then mask out the peer's RX and vice versa.
|
|
*/
|
|
if (!(sband->ht_cap.cap & ATBM_IEEE80211_HT_CAP_TX_STBC))
|
|
ht_cap->cap &= ~ATBM_IEEE80211_HT_CAP_RX_STBC;
|
|
if (!(sband->ht_cap.cap & ATBM_IEEE80211_HT_CAP_RX_STBC))
|
|
ht_cap->cap &= ~ATBM_IEEE80211_HT_CAP_TX_STBC;
|
|
|
|
ampdu_info = ht_cap_ie->ampdu_params_info;
|
|
ht_cap->ampdu_factor =
|
|
ampdu_info & ATBM_IEEE80211_HT_AMPDU_PARM_FACTOR;
|
|
ht_cap->ampdu_density =
|
|
(ampdu_info & ATBM_IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2;
|
|
|
|
/* own MCS TX capabilities */
|
|
tx_mcs_set_cap = sband->ht_cap.mcs.tx_params;
|
|
|
|
/* Copy peer MCS TX capabilities, the driver might need them. */
|
|
ht_cap->mcs.tx_params = ht_cap_ie->mcs.tx_params;
|
|
|
|
/* can we TX with MCS rates? */
|
|
if (!(tx_mcs_set_cap & ATBM_IEEE80211_HT_MCS_TX_DEFINED))
|
|
return;
|
|
|
|
/* Counting from 0, therefore +1 */
|
|
if (tx_mcs_set_cap & ATBM_IEEE80211_HT_MCS_TX_RX_DIFF)
|
|
max_tx_streams =
|
|
((tx_mcs_set_cap & ATBM_IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK)
|
|
>> ATBM_IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT) + 1;
|
|
else
|
|
max_tx_streams = ATBM_IEEE80211_HT_MCS_TX_MAX_STREAMS;
|
|
|
|
/*
|
|
* 802.11n-2009 20.3.5 / 20.6 says:
|
|
* - indices 0 to 7 and 32 are single spatial stream
|
|
* - 8 to 31 are multiple spatial streams using equal modulation
|
|
* [8..15 for two streams, 16..23 for three and 24..31 for four]
|
|
* - remainder are multiple spatial streams using unequal modulation
|
|
*/
|
|
for (i = 0; i < max_tx_streams; i++)
|
|
ht_cap->mcs.rx_mask[i] =
|
|
sband->ht_cap.mcs.rx_mask[i] & ht_cap_ie->mcs.rx_mask[i];
|
|
|
|
if (tx_mcs_set_cap & ATBM_IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION)
|
|
for (i = ATBM_IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE;
|
|
i < ATBM_IEEE80211_HT_MCS_MASK_LEN; i++)
|
|
ht_cap->mcs.rx_mask[i] =
|
|
sband->ht_cap.mcs.rx_mask[i] &
|
|
ht_cap_ie->mcs.rx_mask[i];
|
|
|
|
/* handle MCS rate 32 too */
|
|
if (sband->ht_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1)
|
|
ht_cap->mcs.rx_mask[32/8] |= 1;
|
|
}
|
|
|
|
atbm_void atbmwifi_ieee80211_parse_qos(struct atbmwifi_vif *priv,struct atbm_buff *skb)
|
|
{
|
|
struct atbmwifi_ieee80211_hdr *hdr = (struct atbmwifi_ieee80211_hdr *)ATBM_OS_SKB_DATA(skb);
|
|
struct atbmwifi_ieee80211_rx_status *status = ATBM_IEEE80211_SKB_RXCB(skb);
|
|
atbm_uint8 tid, seqno_idx;
|
|
|
|
/* does the frame have a qos control field? */
|
|
if (atbmwifi_ieee80211_is_data_qos(hdr->frame_control)) {
|
|
atbm_uint8 *qc = atbmwifi_ieee80211_get_qos_ctl(hdr);
|
|
/* frame has qos control */
|
|
tid = *qc & ATBM_IEEE80211_QOS_CTL_TID_MASK;
|
|
if (*qc & ATBM_IEEE80211_QOS_CTL_A_MSDU_PRESENT)
|
|
status->flag |= ATBM_RX_FLAG_AMSDU;
|
|
|
|
seqno_idx = tid;
|
|
//security_idx = tid;
|
|
} else {
|
|
/*
|
|
* IEEE 802.11-2007, 7.1.3.4.1 ("Sequence Number field"):
|
|
*
|
|
* Sequence numbers for management frames, QoS data
|
|
* frames with a broadcast/multicast address in the
|
|
* Address 1 field, and all non-QoS data frames sent
|
|
* by QoS STAs are assigned using an additional single
|
|
* modulo-4096 counter, [...]
|
|
*
|
|
* We also use that counter for non-QoS STAs.
|
|
*/
|
|
seqno_idx = ATBM_NUM_RX_DATA_QUEUES;
|
|
//security_idx = 0;
|
|
//if (atbmwifi_ieee80211_is_mgmt(hdr->frame_control))
|
|
// security_idx = ATBM_NUM_RX_DATA_QUEUES;
|
|
tid = 0;
|
|
}
|
|
|
|
status->seqno_idx = seqno_idx;
|
|
//status->security_idx = security_idx;
|
|
/* Set skb->priority to 1d tag if highest order bit of TID is not set.
|
|
* For now, set skb->priority to 0 for other cases. */
|
|
//status->priority = (tid > 7) ? 0 : tid;
|
|
}
|
|
int atbm_ieee80211_handle_bss_capability(struct atbmwifi_vif *priv,
|
|
atbm_uint16 capab, int erp_valid, atbm_uint8 erp)
|
|
{
|
|
struct atbmwifi_cfg80211_bss * bss_conf = &priv->bss;
|
|
atbm_uint32 changed = 0;
|
|
int use_protection;
|
|
int short_preamble;
|
|
int use_short_slot;
|
|
|
|
if (erp_valid) {
|
|
use_protection = (erp & ATBM_WLAN_ERP_USE_PROTECTION) != 0;
|
|
short_preamble = (erp & ATBM_WLAN_ERP_BARKER_PREAMBLE) == 0;
|
|
} else {
|
|
use_protection = ATBM_FALSE;
|
|
short_preamble = !!(capab & ATBM_WLAN_CAPABILITY_SHORT_PREAMBLE);
|
|
}
|
|
use_short_slot = !!(capab & ATBM_WLAN_CAPABILITY_SHORT_SLOT_TIME);
|
|
|
|
if (use_protection != bss_conf->use_cts_prot) {
|
|
bss_conf->use_cts_prot = use_protection;
|
|
changed |= ATBM_BSS_CHANGED_ERP_CTS_PROT;
|
|
}
|
|
|
|
if (short_preamble != bss_conf->sta_priv.short_preamble) {
|
|
bss_conf->sta_priv.short_preamble = short_preamble;
|
|
changed |= ATBM_BSS_CHANGED_ERP_PREAMBLE;
|
|
}
|
|
|
|
if (use_short_slot != bss_conf->use_short_slot) {
|
|
bss_conf->use_short_slot = use_short_slot;
|
|
changed |= ATBM_BSS_CHANGED_ERP_SLOT;
|
|
}
|
|
|
|
return changed;
|
|
}
|
|
|
|
static int atbmwifi_set_channel_type(struct atbmwifi_vif *priv)
|
|
{
|
|
int ret;
|
|
struct atbmwifi_common *hw_priv = _atbmwifi_vifpriv_to_hwpriv(priv);
|
|
struct wsm_set_chantype set_channtype;
|
|
set_channtype.band=WSM_PHY_BAND_2_4G;
|
|
set_channtype.flag = 0;
|
|
set_channtype.channelNumber = priv->bss.channel_num;
|
|
set_channtype.channelType = priv->bss.channel_type;
|
|
ret=wsm_set_chantype_func(hw_priv,&set_channtype,priv->if_id);
|
|
if(ret){
|
|
wifi_printk(WIFI_CONNECT,"atbmwifi_set_channel_type error\n");
|
|
}
|
|
return ret;
|
|
}
|
|
int atbmwifi_set_channel_work(atbm_void *work)
|
|
{
|
|
struct atbmwifi_vif *priv=(struct atbmwifi_vif *)work;
|
|
atbmwifi_set_channel_type(priv);
|
|
return 0;
|
|
}
|
|
|
|
atbm_void atbmwifi_sw_chntimeout(atbm_void *data1,atbm_void *data2)
|
|
{
|
|
struct atbmwifi_vif *priv=(struct atbmwifi_vif*)data1;
|
|
atbmwifi_set_channel_type(priv);
|
|
}
|
|
static int atbmwifi_ieee80211_stop_tx_queues(struct atbmwifi_vif *priv)
|
|
{
|
|
/*Stop tx queue until set channtype success*/
|
|
tcp_opt->net_stop_queue(priv->ndev,1);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* ieee80211_enable_ht should be called only after the operating band
|
|
* has been determined as ht configuration depends on the hw's
|
|
* HT abilities for a specific band.
|
|
*/
|
|
int atbmwifi_ieee80211_enable_ht(struct atbmwifi_ieee80211_ht_info *hti,
|
|
struct atbmwifi_vif *priv, atbm_uint16 ap_ht_cap_flags,
|
|
int beacon_htcap_ie)
|
|
{
|
|
struct atbmwifi_common *hw_priv = _atbmwifi_vifpriv_to_hwpriv(priv);
|
|
struct atbmwifi_ieee80211_supported_band *sband;
|
|
atbm_uint8 ht_opmode;
|
|
int enable_ht = 1;
|
|
atbm_uint32 changed = 0;
|
|
enum atbm_nl80211_channel_type prev_chantype;
|
|
enum atbm_nl80211_channel_type channel_type = ATBM_NL80211_CHAN_NO_HT;
|
|
|
|
sband = &atbmwifi_band_2ghz;
|
|
|
|
prev_chantype=priv->bss.channel_type;
|
|
|
|
/* HT is not supported */
|
|
if (!sband->ht_cap.ht_supported)
|
|
enable_ht = ATBM_FALSE;
|
|
//wifi_printk(WIFI_CONNECT,"hti->ht_param=%x,enable_ht=%d\n",hti->ht_param,enable_ht);
|
|
if (enable_ht) {
|
|
channel_type = ATBM_NL80211_CHAN_HT20;
|
|
if (!(ap_ht_cap_flags & ATBM_IEEE80211_HT_CAP_40MHZ_INTOLERANT) &&
|
|
(sband->ht_cap.cap & ATBM_IEEE80211_HT_CAP_SUP_WIDTH_20_40) &&
|
|
(hti->ht_param & ATBM_IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) {
|
|
switch(hti->ht_param & ATBM_IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
|
|
case ATBM_IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
|
|
channel_type = ATBM_NL80211_CHAN_HT40PLUS;
|
|
break;
|
|
case ATBM_IEEE80211_HT_PARAM_CHA_SEC_BELOW:
|
|
channel_type = ATBM_NL80211_CHAN_HT40MINUS;
|
|
break;
|
|
}
|
|
}
|
|
/*TxRate with shortGI*/
|
|
if (ap_ht_cap_flags & (ATBM_IEEE80211_HT_CAP_SGI_20|ATBM_IEEE80211_HT_CAP_SGI_40)){
|
|
priv->bss.sta_priv.sgi = 1;
|
|
}
|
|
}
|
|
if(hw_priv->channel_type >=ATBM_NL80211_CHAN_HT40MINUS){
|
|
priv->bss.channel_type = channel_type;
|
|
}
|
|
else {
|
|
priv->bss.channel_type = hw_priv->channel_type;
|
|
}
|
|
|
|
if(priv->iftype == ATBM_NL80211_IFTYPE_STATION){
|
|
if (prev_chantype != channel_type) {
|
|
priv->bss.channel_type = channel_type;
|
|
ht_opmode = atbm_le16_to_cpu(hti->operation_mode);
|
|
priv->ht_operation_mode = ht_opmode;
|
|
changed |= ATBM_BSS_CHANGED_HT;
|
|
atbm_queue_work(hw_priv,priv->chantype_switch_work);
|
|
}
|
|
//wifi_printk(WIFI_CONNECT,"priv->bss.channel_type=%d\n",priv->bss.channel_type);
|
|
if (priv->bss.channel_type>=ATBM_NL80211_CHAN_HT40MINUS){
|
|
priv->bss.ht_40M = 1;
|
|
}else{
|
|
priv->bss.ht_40M = 0;
|
|
}
|
|
}
|
|
|
|
return changed;
|
|
}
|
|
atbm_void atbmwifi_ieee80211_bss_info_change_notify(struct atbmwifi_vif *priv,
|
|
atbm_uint32 changed)
|
|
{
|
|
//struct atbmwifi_common *hw_priv = _atbmwifi_vifpriv_to_hwpriv(priv);
|
|
//TODO
|
|
|
|
}
|
|
int atbmwifi_ieee80211_frequency_to_channel(int freq)
|
|
{
|
|
/* see 802.11 17.3.8.3.2 and Annex J */
|
|
if (freq == 2484){
|
|
return 14;
|
|
}else if (freq < 2484){
|
|
return (freq - 2407) / 5;
|
|
}else if (freq >= 4910 && freq <= 4980){
|
|
return (freq - 4000) / 5;
|
|
}else{
|
|
return (freq - 5000) / 5;
|
|
}
|
|
}
|
|
int atbmwifi_ieee80211_channel_to_frequency(int chan, enum atbmwifi_ieee80211_band band)
|
|
{
|
|
/* see 802.11 17.3.8.3.2 and Annex J
|
|
* there are overlapping channel numbers in 5GHz and 2GHz bands */
|
|
if (band == ATBM_IEEE80211_BAND_5GHZ) {
|
|
if (chan >= 182 && chan <= 196){
|
|
return 4000 + chan * 5;
|
|
}else{
|
|
return 5000 + chan * 5;
|
|
}
|
|
} else { /* ATBM_IEEE80211_BAND_2GHZ */
|
|
if (chan == 14){
|
|
return 2484;
|
|
}else if (chan < 14){
|
|
return 2407 + chan * 5;
|
|
}else{
|
|
return 0; /* not supported */
|
|
}
|
|
}
|
|
}
|
|
struct atbmwifi_ieee80211_channel * atbmwifi_ieee80211_get_channel(struct atbmwifi_vif *priv,
|
|
int new_freq){
|
|
struct atbmwifi_ieee80211_supported_band *sband;
|
|
|
|
enum atbmwifi_ieee80211_band band;
|
|
int i;
|
|
for (band = 0; band < ATBM_IEEE80211_NUM_BANDS; band++) {
|
|
sband = &atbmwifi_band_2ghz;
|
|
if (!sband){
|
|
continue;
|
|
}
|
|
for (i = 0; i < sband->n_channels; i++) {
|
|
if (sband->channels[i].center_freq == new_freq)
|
|
return &sband->channels[i];
|
|
}
|
|
}
|
|
return ATBM_NULL;
|
|
|
|
}
|
|
static int atbmwifi_ieee802_11_parse_vendor_specific(atbm_uint8 *pos, atbm_size_t elen,
|
|
struct atbmwifi_ieee802_11_elems *elems,
|
|
int show_errors)
|
|
{
|
|
atbm_uint32 oui;
|
|
|
|
/* first 3 bytes in vendor specific information element are the IEEE
|
|
* OUI of the vendor. The following byte is used a vendor specific
|
|
* sub-type. */
|
|
if (elen < 4) {
|
|
if (show_errors) {
|
|
wifi_printk(WIFI_DBG_MSG,"short vendor specific "
|
|
"information element ignored (len=%lu)",
|
|
(unsigned long) elen);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
oui = ATBM_WPA_GET_BE24(pos);
|
|
switch (oui) {
|
|
case ATBM_OUI_MICROSOFT:
|
|
/* Microsoft/Wi-Fi information elements are further typed and
|
|
* subtyped */
|
|
switch (pos[3]) {
|
|
case 1:
|
|
/* Microsoft OUI (00:50:F2) with OUI Type 1:
|
|
* real WPA information element */
|
|
elems->wpa = pos;
|
|
elems->wpa_len = elen;
|
|
break;
|
|
case ATBM_WMM_OUI_TYPE:
|
|
/* WMM information element */
|
|
if (elen < 5) {
|
|
wifi_printk(WIFI_DBG_MSG,"short WMM "
|
|
"information element ignored "
|
|
"(len=%lu)",
|
|
(unsigned long) elen);
|
|
return -1;
|
|
}
|
|
switch (pos[4]) {
|
|
case ATBM_WMM_OUI_SUBTYPE_INFORMATION_ELEMENT:
|
|
elems->wmm_info = pos;
|
|
elems->wmm_info_len = elen;
|
|
break;
|
|
case ATBM_WMM_OUI_SUBTYPE_PARAMETER_ELEMENT:
|
|
elems->wmm_param = pos;
|
|
elems->wmm_param_len = elen;
|
|
break;
|
|
default:
|
|
wifi_printk(WIFI_DBG_MSG,"unknown WMM "
|
|
"information element ignored "
|
|
"(subtype=%d len=%lu)",
|
|
pos[4], (unsigned long) elen);
|
|
return -1;
|
|
}
|
|
break;
|
|
#if CONFIG_WPS
|
|
case 4:
|
|
/* Wi-Fi Protected Setup (WPS) IE */
|
|
elems->wps_ie = pos;
|
|
elems->wps_ie_len = elen;
|
|
break;
|
|
#endif
|
|
default:
|
|
wifi_printk(WIFI_DBG_MSG,"Unknown Microsoft "
|
|
"information element ignored "
|
|
"(type=%d len=%lu)",
|
|
pos[3], (unsigned long) elen);
|
|
return -1;
|
|
}
|
|
break;
|
|
|
|
case ATBM_OUI_WFA:
|
|
switch (pos[3]) {
|
|
#if CONFIG_P2P
|
|
case ATBM_P2P_OUI_TYPE:
|
|
case ATBM_WFD_OUI_TYPE:
|
|
/* Wi-Fi Alliance - P2P IE */
|
|
if(!elems->p2p_ie){
|
|
elems->p2p_ie = pos;
|
|
elems->p2p_ie_len = elen;
|
|
}
|
|
break;
|
|
#endif
|
|
default:
|
|
wifi_printk(WIFI_DBG_MSG,"Unknown WFA "
|
|
"information element ignored "
|
|
"(type=%d len=%lu)\n",
|
|
pos[3], (unsigned long) elen);
|
|
return -1;
|
|
}
|
|
break;
|
|
#if CONFIG_P2P
|
|
case ATBM_OUI_QCA:
|
|
if(pos[3] == QCA_VENDOR_ELEM_P2P_PREF_CHAN_LIST){
|
|
elems->pref_freq_list = pos;
|
|
elems->pref_freq_list_len = elen;
|
|
}
|
|
break;
|
|
#endif
|
|
default:
|
|
/*
|
|
printk(KERN_DEBUG "unknown vendor specific "
|
|
"information element ignored (vendor OUI "
|
|
"%02x:%02x:%02x len=%lu)",
|
|
pos[0], pos[1], pos[2], (unsigned long) elen);*/
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
atbm_void atbm_ieee802_11_parse_elems(atbm_uint8 *start, int len,
|
|
struct atbmwifi_ieee802_11_elems *elems)
|
|
{
|
|
atbm_size_t left = len;
|
|
atbm_uint8 *pos = start;
|
|
|
|
atbm_memset(elems, 0, sizeof(struct atbmwifi_ieee802_11_elems ));
|
|
while (left >= 2) {
|
|
atbm_uint8 id, elen;
|
|
|
|
id = *pos++;
|
|
elen = *pos++;
|
|
left -= 2;
|
|
|
|
if (elen > left)
|
|
break;
|
|
|
|
switch (id) {
|
|
case ATBM_WLAN_EID_SSID:
|
|
elems->ssid = pos;
|
|
elems->ssid_len = elen;
|
|
if(elems->ssid_len > 32)
|
|
elems->ssid_len =32;
|
|
break;
|
|
case ATBM_WLAN_EID_SUPP_RATES:
|
|
elems->supp_rates = pos;
|
|
elems->supp_rates_len = elen;
|
|
break;
|
|
case ATBM_WLAN_EID_DS_PARAMS:
|
|
elems->ds_params = pos;
|
|
elems->ds_params_len = elen;
|
|
break;
|
|
case ATBM_WLAN_EID_TIM:
|
|
if (elen >= sizeof(struct atbmwifi_ieee80211_tim_ie)) {
|
|
elems->tim = (atbm_void *)pos;
|
|
elems->tim_len = elen;
|
|
}
|
|
break;
|
|
case ATBM_WLAN_EID_VENDOR_SPECIFIC:
|
|
atbmwifi_ieee802_11_parse_vendor_specific(pos,elen,elems,1);
|
|
break;
|
|
case ATBM_WLAN_EID_RSN:
|
|
elems->rsn = pos;
|
|
elems->rsn_len = elen;
|
|
break;
|
|
case ATBM_WLAN_EID_ERP_INFO:
|
|
elems->erp_info = pos;
|
|
elems->erp_info_len = elen;
|
|
break;
|
|
case ATBM_WLAN_EID_EXT_SUPP_RATES:
|
|
elems->ext_supp_rates = pos;
|
|
elems->ext_supp_rates_len = elen;
|
|
break;
|
|
case ATBM_WLAN_EID_HT_CAPABILITY:
|
|
if (elen >= sizeof(struct atbmwifi_ieee80211_ht_cap))
|
|
elems->ht_cap_elem = (atbm_void *)pos;
|
|
break;
|
|
case ATBM_WLAN_EID_HT_OPERATION:
|
|
if (elen >= sizeof(struct atbmwifi_ieee80211_ht_info))
|
|
elems->ht_info_elem = (atbm_void *)pos;
|
|
break;
|
|
case ATBM_WLAN_EID_EXT_CHANSWITCH_ANN:
|
|
elems->extended_ch_switch_elem = pos;
|
|
elems->extended_ch_switch_elem_len = elen;
|
|
break;
|
|
case ATBM_WLAN_EID_SECONDARY_CH_OFFSET:
|
|
elems->secondary_ch_elem=pos;
|
|
elems->secondary_ch_elem_len=elen;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
left -= elen;
|
|
pos += elen;
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
#if FAST_CONNECT_NO_SCAN
|
|
int atbm_wifi_reserve_key_ie(atbm_uint8 *buf, int buf_len, atbm_uint8 *ie, int ie_len){
|
|
atbm_size_t left = ie_len;
|
|
atbm_uint8 *pos = ie;
|
|
atbm_size_t len = 0;
|
|
|
|
while (left >= 2) {
|
|
atbm_uint8 id, elen;
|
|
id = *pos++;
|
|
elen = *pos++;
|
|
left -= 2;
|
|
|
|
if (elen > left)
|
|
break;
|
|
switch (id) {
|
|
case ATBM_WLAN_EID_SSID:
|
|
case ATBM_WLAN_EID_SUPP_RATES:
|
|
case ATBM_WLAN_EID_DS_PARAMS:
|
|
case ATBM_WLAN_EID_EXT_SUPP_RATES:
|
|
case ATBM_WLAN_EID_HT_CAPABILITY:
|
|
case ATBM_WLAN_EID_HT_OPERATION:
|
|
case ATBM_WLAN_EID_RSN:
|
|
if(len + 2 + elen <= buf_len){
|
|
atbm_memcpy(&buf[len], pos - 2, elen + 2);
|
|
len = len + 2 + elen;
|
|
}else{
|
|
return -1;
|
|
}
|
|
break;
|
|
case ATBM_WLAN_EID_VENDOR_SPECIFIC:
|
|
if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 &&
|
|
pos[2] == 0xf2){
|
|
if(pos[3] == 1 || (pos[3] == 2 && elen > 5)){
|
|
if(len + 2 + elen <= buf_len){
|
|
atbm_memcpy(&buf[len], pos - 2, elen + 2);
|
|
len = len + 2 + elen;
|
|
}else{
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
left -= elen;
|
|
pos += elen;
|
|
}
|
|
return len;
|
|
}
|
|
#endif
|
|
|
|
atbm_void atbm_ieee80211_sta_process_chanswitch(struct atbmwifi_vif *priv,struct atbmwifi_cfg80211_bss *bss,
|
|
struct atbmwifi_ieee80211_channel_sw_packed_ie *sw_packed_ie,
|
|
atbm_uint64 timestamp)
|
|
{
|
|
struct atbmwifi_common *hw_priv = _atbmwifi_vifpriv_to_hwpriv(priv);
|
|
struct atbmwifi_cfg *config = atbmwifi_get_config(priv);
|
|
|
|
struct atbmwifi_ieee80211_channel_sw_ie *sw_elem = sw_packed_ie->chan_sw_ie;
|
|
struct atbmwifi_ieee80211_ext_chansw_ie *ex_sw_elem = sw_packed_ie->ex_chan_sw_ie;
|
|
struct atbmwifi_ieee80211_sec_chan_offs_ie *sec_chan_ie = sw_packed_ie->sec_chan_offs_ie;
|
|
enum atbmwifi_ieee80211_band new_band = ATBM_IEEE80211_NUM_BANDS;
|
|
#define CHANGE_SW_CHANNEL_BIT (1<<0)
|
|
#define CHANGE_CHANNEL_TYPE_BIT (1<<1)
|
|
//atbm_uint8 change = 0;
|
|
int new_freq = 0;
|
|
atbm_uint8 mode = 0;
|
|
atbm_uint8 count = 0;
|
|
atbm_uint8 new_ch_num = 0;
|
|
struct atbmwifi_ieee80211_channel *new_ch = ATBM_NULL;
|
|
|
|
if (!priv->assoc_ok){
|
|
return;
|
|
}
|
|
if(ex_sw_elem)
|
|
{
|
|
if((ex_sw_elem->new_operaring_class>=81)&&
|
|
(ex_sw_elem->new_operaring_class<=84))
|
|
{
|
|
new_band = ATBM_IEEE80211_BAND_2GHZ;
|
|
}
|
|
new_ch_num= ex_sw_elem->new_ch_num;
|
|
mode = ex_sw_elem->mode;
|
|
count = ex_sw_elem->count;
|
|
}
|
|
else if(sw_elem)
|
|
{
|
|
new_band = priv->hw_priv->band;
|
|
new_ch_num = sw_elem->new_ch_num;
|
|
mode = sw_elem->mode;
|
|
count = sw_elem->count;
|
|
}
|
|
new_freq = atbmwifi_ieee80211_channel_to_frequency(new_ch_num,new_band);
|
|
|
|
new_ch = atbmwifi_ieee80211_get_channel(priv, new_freq);
|
|
if (!new_ch || new_ch->flags & ATBM_IEEE80211_CHAN_DISABLED){
|
|
return;
|
|
}
|
|
if(sec_chan_ie)
|
|
{
|
|
enum atbm_nl80211_channel_type prev_chantype = bss->channel_type;
|
|
enum atbm_nl80211_channel_type new_chantype = prev_chantype;
|
|
switch(sec_chan_ie->sec_chan_offs)
|
|
{
|
|
case ATBM_IEEE80211_HT_PARAM_CHA_SEC_NONE:
|
|
new_chantype = ATBM_NL80211_CHAN_NO_HT;
|
|
break;
|
|
case ATBM_IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
|
|
new_chantype = ATBM_NL80211_CHAN_HT40PLUS;
|
|
break;
|
|
case ATBM_IEEE80211_HT_PARAM_CHA_SEC_BELOW:
|
|
new_chantype = ATBM_NL80211_CHAN_HT40MINUS;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
bss->channel_type=new_chantype;
|
|
if(prev_chantype == new_chantype)
|
|
return;
|
|
atbm_queue_work(hw_priv,priv->chantype_switch_work);
|
|
return;
|
|
}
|
|
/* channel switch handled in software */
|
|
if (new_ch_num!=bss->channel_num){
|
|
bss->channel_num=new_ch_num;
|
|
if (count <= 1) {
|
|
atbm_queue_work(hw_priv,priv->chantype_switch_work);
|
|
} else {
|
|
if (mode)
|
|
{
|
|
atbmwifi_ieee80211_stop_tx_queues(priv);
|
|
}
|
|
config->flags |= ATBM_IEEE80211_STA_CSA_RECEIVED;
|
|
atbmwifi_eloop_register_timeout(0,(atbm_GetOsTimeMs() + (count *priv->bss.sta_priv.beacon_interval)),
|
|
atbmwifi_sw_chntimeout,(atbm_void *)priv,ATBM_NULL);
|
|
}
|
|
}
|
|
}
|
|
static int ecw2cw(int ecw)
|
|
{
|
|
return (1 << ecw) - 1;
|
|
}
|
|
int atbmwifi_config_tx_wmmparam(struct atbmwifi_vif *priv)
|
|
{
|
|
struct atbmwifi_common *hw_priv = _atbmwifi_vifpriv_to_hwpriv(priv);
|
|
struct config_edca_params *wmm_param;
|
|
struct wsm_edca_params edca;
|
|
ATBM_BOOL old_uapsdFlags;
|
|
int ret;
|
|
old_uapsdFlags=priv->uapsd_info.uapsdFlags;
|
|
//VO
|
|
wmm_param= &priv->wmm_params[ATBM_D11_ACI_AC_VO];
|
|
WSM_EDCA_SET(&edca, ATBM_IEEE80211_AC_VO /*0*/, wmm_param->aifns, wmm_param->cwMin, wmm_param->cwMax,
|
|
wmm_param->txOpLimit, 0xc8, wmm_param->uapsdEnable);
|
|
//VI
|
|
wmm_param= &priv->wmm_params[ATBM_D11_ACI_AC_VI];
|
|
WSM_EDCA_SET(&edca, ATBM_IEEE80211_AC_VI /*1*/, wmm_param->aifns, wmm_param->cwMin, wmm_param->cwMax,
|
|
wmm_param->txOpLimit, 0xc8, wmm_param->uapsdEnable);
|
|
//BE
|
|
wmm_param= &priv->wmm_params[ATBM_D11_ACI_AC_BE];
|
|
WSM_EDCA_SET(&edca, ATBM_IEEE80211_AC_BE /*2*/, wmm_param->aifns, wmm_param->cwMin, wmm_param->cwMax,
|
|
wmm_param->txOpLimit, 0xc8, wmm_param->uapsdEnable);
|
|
//BK
|
|
wmm_param= &priv->wmm_params[ATBM_D11_ACI_AC_BK];
|
|
WSM_EDCA_SET(&edca, ATBM_IEEE80211_AC_BK /*3*/, wmm_param->aifns, wmm_param->cwMin, wmm_param->cwMax,
|
|
wmm_param->txOpLimit, 0xc8, wmm_param->uapsdEnable);
|
|
|
|
ret = wsm_set_edca_params(hw_priv, &edca, priv->if_id);
|
|
if (ATBM_WARN_ON(ret)){
|
|
goto out;
|
|
}
|
|
//wifi_printk(WIFI_CONNECT,"old_uapsdFlags=%d,priv->uapsd_info.uapsdFlags=%d\n",old_uapsdFlags,priv->uapsd_info.uapsdFlags);
|
|
if (priv->iftype == ATBM_NL80211_IFTYPE_STATION) {
|
|
ret = atbmwifi_set_uapsd_param(priv, &edca);
|
|
if(!ret&&(old_uapsdFlags!=priv->uapsd_info.uapsdFlags)){
|
|
atbmwifi_set_pm(priv,ATBM_TRUE,0);
|
|
}
|
|
}
|
|
return ret;
|
|
out:
|
|
return -1;
|
|
|
|
}
|
|
atbm_void atbmwifi_ieee80211_set_wmm_default(struct atbmwifi_vif *priv)
|
|
{
|
|
struct atbmwifi_common *hw_priv = _atbmwifi_vifpriv_to_hwpriv(priv);
|
|
ATBM_BOOL use_11b;
|
|
int ac;
|
|
int queue;
|
|
int aCWmin, aCWmax;
|
|
struct config_edca_params *qparam;
|
|
if (hw_priv->hw_queues < ATBM_IEEE80211_NUM_ACS)
|
|
return;
|
|
qparam=&priv->wmm_params[0];
|
|
if (!priv->bss.sta_priv.rate_11g){
|
|
use_11b=ATBM_TRUE;
|
|
}
|
|
for (ac = 0; ac < ATBM_IEEE80211_NUM_ACS; ac++) {
|
|
/* Set defaults according to 802.11-2007 Table 7-37 */
|
|
aCWmax = 1023;
|
|
if (use_11b)
|
|
aCWmin = 31;
|
|
else
|
|
aCWmin = 15;
|
|
|
|
switch (ac) {
|
|
case 3: /* AC_BK */
|
|
queue = 0;
|
|
qparam[queue].cwMax = aCWmax;
|
|
qparam[queue].cwMin = aCWmin;
|
|
qparam[queue].txOpLimit= 0;
|
|
qparam[queue].aifns= 7;
|
|
break;
|
|
default: /* never happens but let's not leave undefined */
|
|
case 2: /* AC_BE */
|
|
queue = 1;
|
|
qparam[queue].cwMax = aCWmax;
|
|
qparam[queue].cwMin = aCWmin;
|
|
qparam[queue].txOpLimit = 0;
|
|
qparam[queue].aifns = 3;
|
|
break;
|
|
case 1: /* AC_VI */
|
|
queue = 2;
|
|
qparam[queue].cwMax = aCWmin;
|
|
qparam[queue].cwMin = (aCWmin + 1) / 2 - 1;
|
|
if (use_11b)
|
|
qparam[queue].txOpLimit = 6016/32;
|
|
else
|
|
qparam[queue].txOpLimit = 3008/32;
|
|
qparam[queue].aifns = 2;
|
|
break;
|
|
case 0: /* AC_VO */
|
|
queue = 3;
|
|
qparam[queue].cwMax = (aCWmin + 1) / 2 - 1;
|
|
qparam[queue].cwMin = (aCWmin + 1) / 4 - 1;
|
|
if (use_11b)
|
|
qparam[queue].txOpLimit = 3264/32;
|
|
else
|
|
qparam[queue].txOpLimit = 1504/32;
|
|
qparam[queue].aifns = 2;
|
|
break;
|
|
}
|
|
|
|
qparam[queue].uapsdEnable= ATBM_FALSE;
|
|
/* enable WMM or activate new settings */
|
|
atbmwifi_config_tx_wmmparam(priv);
|
|
|
|
}
|
|
|
|
}
|
|
static unsigned short atbm_get_unaligned_le16(const unsigned char * ptr)
|
|
{
|
|
return (((ptr[1]) << 8) | (ptr[0]));
|
|
}
|
|
atbm_void atbmwifi_ieee80211_sta_wmm_params(struct atbmwifi_vif *priv,
|
|
atbm_uint8 *wmm_param, int wmm_param_len)
|
|
{
|
|
//struct atbmwifi_common *hw_priv = _atbmwifi_vifpriv_to_hwpriv(priv);
|
|
//struct atbmwifi_cfg *config = atbmwifi_get_config(priv);
|
|
int left;
|
|
//int count;
|
|
atbm_uint8 *pos, uapsd_queues = 0;
|
|
int queue;
|
|
uapsd_queues = priv->uapsd_queues;
|
|
if (!wmm_param){
|
|
return;
|
|
}
|
|
if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1)
|
|
return;
|
|
pos = wmm_param + 8;
|
|
left = wmm_param_len - 8;
|
|
|
|
for (; left >= 4; left -= 4, pos += 4) {
|
|
int aci = (pos[0] >> 5) & 0x03;
|
|
int acm = (pos[0] >> 4) & 0x01;
|
|
int uapsd = ATBM_FALSE;
|
|
//int queue;
|
|
/*wifi_printk(WIFI_CONNECT,"aci=%d,acm=%d,aifns=%d,cwMax=%d,cwMin=%d,txOpLimit=%d,uapsdEnable=%d\n",aci,acm,(pos[0] & 0x0f),(ecw2cw((pos[1] & 0xf0) >> 4)),\
|
|
(ecw2cw(pos[1] & 0x0f)),atbm_get_unaligned_le16(pos + 2),uapsd);*/
|
|
switch (aci) {
|
|
case 1: /* AC_BK */
|
|
queue = 3;
|
|
if (acm)
|
|
priv->wmm_acm |= BIT(1) | BIT(2); /* BK/- */
|
|
if (uapsd_queues & ATBM_IEEE80211_WMM_IE_STA_QOSINFO_AC_BK)
|
|
uapsd = ATBM_TRUE;
|
|
break;
|
|
case 2: /* AC_VI */
|
|
queue = 1;
|
|
if (acm)
|
|
priv->wmm_acm |= BIT(4) | BIT(5); /* CL/VI */
|
|
if (uapsd_queues & ATBM_IEEE80211_WMM_IE_STA_QOSINFO_AC_VI)
|
|
uapsd = ATBM_TRUE;
|
|
break;
|
|
case 3: /* AC_VO */
|
|
queue = 0;
|
|
if (acm)
|
|
priv->wmm_acm |= BIT(6) | BIT(7); /* VO/NC */
|
|
if (uapsd_queues & ATBM_IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
|
|
uapsd = ATBM_TRUE;
|
|
break;
|
|
case 0: /* AC_BE */
|
|
default:
|
|
queue = 2;
|
|
if (acm)
|
|
priv->wmm_acm |= BIT(0) | BIT(3); /* BE/EE */
|
|
if (uapsd_queues & ATBM_IEEE80211_WMM_IE_STA_QOSINFO_AC_BE)
|
|
uapsd = ATBM_TRUE;
|
|
break;
|
|
}
|
|
/* enable WMM or activate new settings */
|
|
priv->wmm_params[aci].wmep_acm=priv->wmm_acm;
|
|
priv->wmm_params[aci].aifns= pos[0] & 0x0f;
|
|
priv->wmm_params[aci].cwMax= ecw2cw((pos[1] & 0xf0) >> 4);
|
|
priv->wmm_params[aci].cwMin= ecw2cw(pos[1] & 0x0f);
|
|
priv->wmm_params[aci].txOpLimit= atbm_get_unaligned_le16(pos + 2);
|
|
priv->wmm_params[aci].uapsdEnable= uapsd;
|
|
}
|
|
atbmwifi_config_tx_wmmparam(priv);
|
|
}
|
|
ATBM_BOOL atbmwifi_iee80211_check_combination(struct atbmwifi_vif *ignore_priv,atbm_uint8 combination_channel)
|
|
{
|
|
struct atbmwifi_common *hw_priv = ignore_priv->hw_priv;
|
|
struct atbmwifi_vif *priv = ATBM_NULL;
|
|
atbm_uint8 index = 0;
|
|
for(index = 0;index<ATBM_WIFI_MAX_VIFS;index++){
|
|
priv = hw_priv->vif_list[index];
|
|
if(priv == ATBM_NULL){
|
|
continue;
|
|
}
|
|
if(priv == ignore_priv){
|
|
continue;
|
|
}
|
|
if(priv->iftype == ATBM_NUM_NL80211_IFTYPES){
|
|
continue;
|
|
}
|
|
if((priv->join_status == ATBMWIFI__JOIN_STATUS_STA)||
|
|
(priv->join_status == ATBMWIFI__JOIN_STATUS_AP)){
|
|
if((atbm_uint8)priv->config.channel_index != combination_channel){
|
|
wifi_printk(WIFI_ALWAYS, "channel conflict[%d]:[%d] \n", priv->config.channel_index, combination_channel);
|
|
return ATBM_FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return ATBM_TRUE;
|
|
}
|
|
|
|
#if BW_40M_SUPPORT
|
|
atbm_void atbmwifi_iee80211_unify_channel_type(struct atbmwifi_vif *ignore_priv, atbm_uint32 channel_type)
|
|
{
|
|
struct atbmwifi_common *hw_priv = ignore_priv->hw_priv;
|
|
struct atbmwifi_vif *priv = ATBM_NULL;
|
|
struct wsm_set_chantype set_channtype;
|
|
atbm_uint8 index = 0;
|
|
hw_priv->channel_type = channel_type;
|
|
for(index = 0;index<ATBM_WIFI_MAX_VIFS;index++){
|
|
priv = hw_priv->vif_list[index];
|
|
if(priv == ATBM_NULL){
|
|
continue;
|
|
}
|
|
if(priv == ignore_priv){
|
|
continue;
|
|
}
|
|
if(priv->iftype == ATBM_NUM_NL80211_IFTYPES){
|
|
continue;
|
|
}
|
|
if((priv->join_status == ATBMWIFI__JOIN_STATUS_STA)||
|
|
(priv->join_status == ATBMWIFI__JOIN_STATUS_AP)){
|
|
if(priv->bss.channel_type != channel_type){
|
|
set_channtype.band = (hw_priv->band == ATBM_IEEE80211_BAND_5GHZ) ?
|
|
WSM_PHY_BAND_5G : WSM_PHY_BAND_2_4G;
|
|
set_channtype.flag = 0;
|
|
set_channtype.channelNumber = ignore_priv->config.channel_index;
|
|
set_channtype.channelType = channel_type;
|
|
priv->bss.channel_type = channel_type;
|
|
wsm_set_chantype_func(hw_priv,&set_channtype,priv->if_id);
|
|
}
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
int atbmwifi_iee80211_peerif_channel_type(struct atbmwifi_vif *ignore_priv)
|
|
{
|
|
struct atbmwifi_common *hw_priv = ignore_priv->hw_priv;
|
|
struct atbmwifi_vif *priv = ATBM_NULL;
|
|
atbm_uint8 index = 0;
|
|
for(index = 0;index<ATBM_WIFI_MAX_VIFS;index++){
|
|
priv = hw_priv->vif_list[index];
|
|
if(priv == ATBM_NULL){
|
|
continue;
|
|
}
|
|
if(priv == ignore_priv){
|
|
continue;
|
|
}
|
|
if(priv->iftype == ATBM_NUM_NL80211_IFTYPES){
|
|
continue;
|
|
}
|
|
if((priv->join_status == ATBMWIFI__JOIN_STATUS_STA)||
|
|
(priv->join_status == ATBMWIFI__JOIN_STATUS_AP)){
|
|
return priv->bss.channel_type;
|
|
}
|
|
}
|
|
return hw_priv->channel_type;
|
|
}
|
|
#endif
|
|
|
|
int atbmwifi_iee80211_peerif_channel(struct atbmwifi_vif *ignore_priv)
|
|
{
|
|
struct atbmwifi_common *hw_priv = ignore_priv->hw_priv;
|
|
struct atbmwifi_vif *priv = ATBM_NULL;
|
|
atbm_uint8 index = 0;
|
|
for(index = 0;index<ATBM_WIFI_MAX_VIFS;index++){
|
|
priv = hw_priv->vif_list[index];
|
|
if(priv == ATBM_NULL){
|
|
continue;
|
|
}
|
|
if(priv == ignore_priv){
|
|
continue;
|
|
}
|
|
if((priv->join_status == ATBMWIFI__JOIN_STATUS_STA)||
|
|
(priv->join_status == ATBMWIFI__JOIN_STATUS_AP)){
|
|
if((atbm_uint8)priv->config.channel_index > 0
|
|
#if (CONFIG_5G_SUPPORT == 0)
|
|
&& ((atbm_uint8)priv->config.channel_index < 14)
|
|
#endif
|
|
)
|
|
{
|
|
return (atbm_uint8)priv->config.channel_index;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
struct atbmwifi_vif * atbmwifi_iee80211_getvif_by_name
|
|
(struct atbmwifi_common *hw_priv,char *name)
|
|
{
|
|
atbm_uint8 name_size = strlen(name);
|
|
struct atbmwifi_vif *priv = ATBM_NULL;
|
|
atbm_uint8 index = 0;
|
|
wifi_printk(WIFI_ALWAYS,"name(%s),name_size(%d)\n",name,name_size);
|
|
if(name_size>ATBM_IFNAMSIZ)
|
|
return ATBM_NULL;
|
|
for(index = 0;index<ATBM_WIFI_MAX_VIFS;index++){
|
|
priv = hw_priv->vif_list[index];
|
|
if(priv == ATBM_NULL)
|
|
continue;
|
|
if(memcmp(priv->if_name,name,name_size) == 0){
|
|
wifi_printk(WIFI_ALWAYS,"name(%s),name_size(%d),if_id(%d)\n",name,name_size,priv->if_id);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return priv;
|
|
}
|
|
ATBM_BOOL atbmwifi_ieee80211_check_alive_if(struct atbmwifi_common *hw_priv,struct atbmwifi_vif *ignore_priv)
|
|
{
|
|
struct atbmwifi_vif *priv = ATBM_NULL;
|
|
atbm_uint8 index = 0;
|
|
|
|
for(index = 0;index<ATBM_WIFI_MAX_VIFS;index++){
|
|
priv = hw_priv->vif_list[index];
|
|
if(priv == ATBM_NULL){
|
|
continue;
|
|
}
|
|
if(priv == ignore_priv){
|
|
continue;
|
|
}
|
|
|
|
if(priv->iftype != ATBM_NUM_NL80211_IFTYPES){
|
|
return ATBM_TRUE;
|
|
}
|
|
}
|
|
|
|
return ATBM_FALSE;
|
|
}
|
|
|
|
atbm_void atbmwifi_start_iftype(struct atbmwifi_vif *start_priv,enum atbm_nl80211_iftype start_type)
|
|
{
|
|
if(start_priv->iftype != ATBM_NUM_NL80211_IFTYPES){
|
|
return;
|
|
}
|
|
start_priv->iftype = start_type;
|
|
|
|
if(atbmwifi_is_sta_mode(start_type)){
|
|
atbmwifi_start_sta(start_priv);
|
|
}
|
|
else if(atbmwifi_is_ap_mode(start_type)){
|
|
atbmwifi_start_ap(start_priv);
|
|
}
|
|
}
|
|
|
|
atbm_void atbmwifi_stop_iftype(struct atbmwifi_vif *stop_priv,enum atbm_nl80211_iftype stop_type)
|
|
{
|
|
if(stop_priv->iftype == ATBM_NUM_NL80211_IFTYPES){
|
|
return;
|
|
}
|
|
if(atbmwifi_is_sta_mode(stop_type)){
|
|
atbmwifi_stop_sta(stop_priv);
|
|
}
|
|
else if(atbmwifi_is_ap_mode(stop_type)){
|
|
atbmwifi_stop_ap(stop_priv);
|
|
}
|
|
|
|
stop_priv->iftype = ATBM_NUM_NL80211_IFTYPES;
|
|
}
|
|
|
|
static atbm_void __atbmwifi_start_wifimode(struct atbmwifi_vif *start_priv,enum atbm_nl80211_iftype start_type)
|
|
{
|
|
ATBM_BOOL other_alive_if = ATBM_FALSE;
|
|
ATBM_BOOL all_alive_if = ATBM_FALSE;
|
|
|
|
ATBM_BOOL priv_need_change = ((start_type != start_priv->iftype)&&(start_priv->iftype != ATBM_NUM_NL80211_IFTYPES))? ATBM_TRUE:ATBM_FALSE;
|
|
other_alive_if = atbmwifi_ieee80211_check_alive_if(start_priv->hw_priv,start_priv);
|
|
all_alive_if = atbmwifi_ieee80211_check_alive_if(start_priv->hw_priv,ATBM_NULL);
|
|
if(priv_need_change == ATBM_TRUE){
|
|
atbmwifi_stop_iftype(start_priv,start_priv->iftype);
|
|
}
|
|
/*Intial/stop the Station/Ap iftype is ATBM_NUM_NL80211_IFTYPES*/
|
|
if(start_priv->iftype == ATBM_NUM_NL80211_IFTYPES){
|
|
atbmwifi_start_iftype(start_priv,start_type);
|
|
}
|
|
wifi_printk(WIFI_ALWAYS,"atbmwifi_start_wifimode:other_alive_if(%d),all_alive_if(%d)\n ",other_alive_if,all_alive_if);
|
|
}
|
|
atbm_void atbmwifi_start_wifimode(struct atbmwifi_vif *start_priv,enum atbm_nl80211_iftype start_type)
|
|
{
|
|
atbmwifi_wpa_event_queue((atbm_void*)start_priv,(atbm_void*)start_type,ATBM_NULL,WPA_EVENT__INIT,ATBM_WPA_EVENT_ACK);
|
|
}
|
|
atbm_void atbmwifi_wpa_event_mode_init(struct atbmwifi_vif *start_priv,enum atbm_nl80211_iftype start_type)
|
|
{
|
|
__atbmwifi_start_wifimode(start_priv,start_type);
|
|
}
|
|
static atbm_void __atbmwifi_stop_wifimode(struct atbmwifi_vif *stop_priv,enum atbm_nl80211_iftype stop_type)
|
|
{
|
|
ATBM_BOOL other_alive_if = ATBM_FALSE;
|
|
ATBM_BOOL all_alive_if = ATBM_FALSE;
|
|
other_alive_if = atbmwifi_ieee80211_check_alive_if(stop_priv->hw_priv,stop_priv);
|
|
all_alive_if = atbmwifi_ieee80211_check_alive_if(stop_priv->hw_priv,ATBM_NULL);
|
|
atbmwifi_stop_iftype(stop_priv,stop_type);
|
|
|
|
if(all_alive_if != other_alive_if){
|
|
wifi_printk(WIFI_ALWAYS,"All Interface is down\n ");
|
|
}
|
|
}
|
|
atbm_void atbmwifi_wpa_event_mode_deinit(struct atbmwifi_vif *stop_priv,enum atbm_nl80211_iftype stop_type)
|
|
{
|
|
__atbmwifi_stop_wifimode(stop_priv,stop_type);
|
|
}
|
|
atbm_void atbmwifi_stop_wifimode(struct atbmwifi_vif *stop_priv,enum atbm_nl80211_iftype stop_type)
|
|
{
|
|
atbmwifi_wpa_event_queue((atbm_void*)stop_priv,(atbm_void*)stop_type,ATBM_NULL,WPA_EVENT__DEINIT,ATBM_WPA_EVENT_ACK);
|
|
}
|
|
struct atbmwifi_cfg *atbmwifi_get_config(struct atbmwifi_vif *priv)
|
|
{
|
|
return &priv->config;
|
|
}
|
|
struct atbmwifi_vif *atbmwifi_config_get_priv(struct atbmwifi_cfg *config)
|
|
{
|
|
return atbm_container_of(config,struct atbmwifi_vif,config);
|
|
}
|
|
struct hostapd_data *atbmiwifi_get_hostapd(struct atbmwifi_vif *priv)
|
|
{
|
|
return (struct hostapd_data *)(priv->appdata);
|
|
}
|
|
|
|
#if CONFIG_WIFI_BT_COMB
|
|
int atbm_ble_do_ble_xmit(struct atbmwifi_common *hw_priv,atbm_uint8* xmit,atbm_size_t len)
|
|
{
|
|
return wsm_ble_xmit(hw_priv,xmit,len);
|
|
}
|
|
#endif
|
|
|
|
#ifndef CONFIG_OS_FREERTOS
|
|
#if (BYTE_ORDER == LITTLE_ENDIAN)
|
|
|
|
/**
|
|
* Convert an uint16 from host- to network byte order.
|
|
*
|
|
* @param n uint16 in host byte order
|
|
* @return n in network byte order
|
|
*/
|
|
atbm_uint16 atbm_htons(atbm_uint16 n)
|
|
{
|
|
return ((n & 0xff) << 8) | ((n & 0xff00) >> 8);
|
|
}
|
|
|
|
/**
|
|
* Convert an uint16 from network- to host byte order.
|
|
*
|
|
* @param n uint16 in network byte order
|
|
* @return n in host byte order
|
|
*/
|
|
atbm_uint16 atbm_ntohs(atbm_uint16 n)
|
|
{
|
|
return atbm_htons(n);
|
|
}
|
|
|
|
/**
|
|
* Convert an uint32 from host- to network byte order.
|
|
*
|
|
* @param n uint32 in host byte order
|
|
* @return n in network byte order
|
|
*/
|
|
atbm_uint32 atbm_htonl(atbm_uint32 n)
|
|
{
|
|
return ((n & 0xff) << 24) |
|
|
((n & 0xff00) << 8) |
|
|
((n & 0xff0000UL) >> 8) |
|
|
((n & 0xff000000UL) >> 24);
|
|
}
|
|
|
|
/**
|
|
* Convert an uint32 from network- to host byte order.
|
|
*
|
|
* @param n uint32 in network byte order
|
|
* @return n in host byte order
|
|
*/
|
|
atbm_uint32 atbm_ntohl(atbm_uint32 n)
|
|
{
|
|
return atbm_htonl(n);
|
|
}
|
|
#endif /* (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN) */
|
|
|
|
|
|
atbm_void dump_mem(const atbm_void *mem, int count)
|
|
{
|
|
const unsigned char *p = mem;
|
|
int i = 0;
|
|
|
|
for(i = 0; i < count; i++){
|
|
|
|
if( i % 16 == 0)
|
|
ATBM_DEBUG(1, 0, "\n");
|
|
|
|
ATBM_DEBUG(1, 0, "%02x ", p[i]);
|
|
}
|
|
ATBM_DEBUG(1, 0, "\n");
|
|
}
|
|
|
|
char ConvertHexChar(char ch){
|
|
if(ch >= '0' && ch <= '9')
|
|
return ch - '0';
|
|
if(ch >= 'a' && ch <= 'f')
|
|
return ch - 'a' + 10;
|
|
if(ch >= 'A' && ch < 'F')
|
|
return ch - 'A' + 10;
|
|
return -1;
|
|
}
|
|
|
|
int hex2byte(const char *hex)
|
|
{
|
|
int a, b;
|
|
a = ConvertHexChar(*hex++);
|
|
if(a < 0)
|
|
return -1;
|
|
b = ConvertHexChar(*hex++);
|
|
if(b < 0)
|
|
return -1;
|
|
return (a << 4) | b;
|
|
}
|
|
int atbmwifi_hexstr2bin(atbm_uint8 *buf, const char *hex, atbm_size_t len)
|
|
{
|
|
atbm_size_t i;
|
|
int a;
|
|
const char *ipos = hex;
|
|
atbm_uint8 *opos = (atbm_uint8 *)buf;
|
|
|
|
for(i = 0; i < len; i += 2){
|
|
a = hex2byte(ipos);
|
|
if(a < 0)
|
|
return -1;
|
|
*opos++ = a;
|
|
ipos += 2;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
char *dup_binstr(const atbm_void *src, atbm_size_t len)
|
|
{
|
|
char *res;
|
|
|
|
if(src == ATBM_NULL)
|
|
return ATBM_NULL;
|
|
res = (char *)atbm_kmalloc(len + 1,GFP_KERNEL);
|
|
if(res == ATBM_NULL)
|
|
atbm_memcpy(res, src, len);
|
|
res[len] = '\0';
|
|
|
|
return res;
|
|
}
|
|
#endif //CONFIG_OS_FREERTOS
|
|
|
|
/* Try to prevent most compilers from optimizing out clearing of memory that
|
|
* becomes unaccessible after this function is called. This is mostly the case
|
|
* for clearing local stack variables at the end of a function. This is not
|
|
* exactly perfect, i.e., someone could come up with a compiler that figures out
|
|
* the pointer is pointing to memset and then end up optimizing the call out, so
|
|
* try go a bit further by storing the first octet (now zero) to make this even
|
|
* a bit more difficult to optimize out. Once memset_s() is available, that
|
|
* could be used here instead. */
|
|
static void * (* const volatile memset_func)(void *, int, atbm_size_t) = atbm_memset;
|
|
static atbm_uint8 forced_memzero_val;
|
|
|
|
void forced_memzero(void *ptr, atbm_size_t len)
|
|
{
|
|
memset_func(ptr, 0, len);
|
|
if (len)
|
|
forced_memzero_val = ((atbm_uint8 *) ptr)[0];
|
|
}
|
|
|
|
|
|
void bin_clear_free(void *bin, atbm_size_t len)
|
|
{
|
|
if (bin) {
|
|
forced_memzero(bin, len);
|
|
atbm_kfree(bin);
|
|
}
|
|
}
|
|
|
|
void buf_shift_right(atbm_uint8 *buf, atbm_size_t len, atbm_size_t bits)
|
|
{
|
|
atbm_size_t i;
|
|
|
|
for (i = len - 1; i > 0; i--)
|
|
buf[i] = (buf[i - 1] << (8 - bits)) | (buf[i] >> bits);
|
|
buf[0] >>= bits;
|
|
}
|
|
|
|
int random_get_bytes(atbm_uint8 *buf, atbm_size_t len)
|
|
{
|
|
return atbmwifi_os_get_random(buf, len);
|
|
}
|
|
|