AP模式中多重基础服务集(Multi-BSS)下帧的接收

来源:互联网 发布:上古卷轴美女捏脸数据 编辑:程序博客网 时间:2024/05/29 02:08

   我们知道,AP模式下的无线网卡可以创建多个基础服务集(Base Service Set, BSS),我们可以为每一个BSS赋予一个SSID,也可以为每一个BSS设置不同的加密方式和密码。通过多个创建多个BSS的方式,就可以让同一个无线路由器提供不同的无线上网服务。那么问题来了,当AP接收到一个帧的时候,如何判断这个帧是否属于这个AP呢?我一开始认为,当AP接收到一个帧的时候,驱动程序便会循环检查每一个BSS的BSSID,看看是否有和接收到的帧的BSSID字段一致的BSS——如果有就ACK,否则就drop掉。后来当在我阅读ath9k驱动程序源代码的时候,才发现我的想法太天真了——一个AP会不停的收到许多帧,如果每收到一个帧,就去轮询每个BSS来确定这个帧是否属于这个AP,那效率实在是太低了。原来AR5212或者以上的无线网卡驱动采用了一种叫做“BSSID掩码(BSSID masking)”的方式,来决定是否ACK接收到的帧。

        假如我们的无线网卡的MAC地址是0001,并且创建了两个BSS(假设为BSS_1和BSS_2),其BSSID分别为0100和1001,那么BSSID掩码就是这样计算的:


mac = 0001   //无线网卡的MAC为0001

bssid_mask = 1111;   //掩码的初始值为1111                        

bssid_1 = 0100  //BSS_1的BSSID为0100

bssid_2 = 1001  //BSS_2的BSSID为1001

bssid_mask = bssid_mask & ~(mac ^ bssid_1)        //BSS_1被创建后的掩码

                      = 1111 & ~(0001 ^ 0100)

                      = 1111 & 1010

                      = 1010

bssid_mask = bssid_mask & ~(mac ^ bssid_2)      //然后BSS_2被创建后的掩码

                       = 1010 & ~(0001 ^ 1001)

                       = 1010 & 0111

                       = 0010


即,最后的掩码为0010。意思就是,当接收到一个帧的时候,只需要注意它BSSID字段的倒数第二位。假如这个AP接收到一个帧,它的BSSID字段为0110,因为它的倒数第二位是1,那么这个帧就不属于这个AP,就可以直接drop了。算法如下:

iframe = 0110 //接收到的帧的BSSID字段是0100

allow = (ifame & bssid_mask) == (bssid_mask & mac) ? true : false

          = (0110 & 0010) == (0010 & 0001) ? true : false

          = 0010 == 0000 ? true : false

          = false    //这个帧不属于这个AP,直接drop!

再看另一个例子,假如接收到一个帧的BSSID字段为0001,用眼观察,它的倒数第二位是0,那就是属于这个AP的——实际是否如此呢?我们来计算一下:

ifame = 0001 //接收到的帧的BSSID字段是0001

allow = (ifame & bssid_mask) == (bssid_mask & mac) ? true : false

          = (0001 & 0010) == (0010 & 0001) ? true : false

          = 0000 == 0000 ? true : false

          = true //这个帧属于这个AP,ACK它!

的确是这样的——通过BSSID掩码,驱动程序的作者用O(1)的算法秒杀了我之前幼稚又天真的O(n)算法!!


        综上所述,每当AP建立一个BSS,便要更新一下BSSID掩码。当只有一个BSS的时候,掩码就是初始掩码1111。(通常MAC地址是48位,那么初始掩码就是ff:ff:ff:ff:ff:ff)掩码的计算方法为

bssid_mask = bssid_mask & ~(mac ^ bssid)

每当接收到一个帧的时候,通过如下的方法来确定这个帧是否属于此AP:

allow = (ifame & bssid_mask == bssid_mask & mac) ? true : false


那么,代码是如何实现的呢?在drivers/net/wireless/ath/ath9k/virtual.c中,有如下代码:

[cpp] view plaincopy
  1. void ath9k_set_bssid_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif)  
  2. {  
  3.     struct ath_wiphy *aphy = hw->priv;  
  4.     struct ath_softc *sc = aphy->sc;  
  5.     struct ath_common *common = ath9k_hw_common(sc->sc_ah);  
  6.     struct ath9k_vif_iter_data iter_data;  
  7.     int i;  
  8.   
  9.     /* 
  10.      * Use the hardware MAC address as reference, the hardware uses it 
  11.      * together with the BSSID mask when matching addresses. 
  12.      */  
  13.     iter_data.hw_macaddr = common->macaddr;  
  14.     memset(&iter_data.mask, 0xff, ETH_ALEN);  
  15.   
  16.     if (vif)  
  17.         ath9k_vif_iter(&iter_data, vif->addr, vif);  //这个函数来计算掩码  
  18.       
  19.     /* Get list of all active MAC addresses */  
  20.     spin_lock_bh(&sc->wiphy_lock);  
  21.     ieee80211_iterate_active_interfaces_atomic(sc->hw, ath9k_vif_iter,  
  22.                            &iter_data);  
  23.     for (i = 0; i < sc->num_sec_wiphy; i++) {  
  24.         if (sc->sec_wiphy[i] == NULL)  
  25.             continue;  
  26.         ieee80211_iterate_active_interfaces_atomic(  
  27.             sc->sec_wiphy[i]->hw, ath9k_vif_iter, &iter_data);  
  28.     }  
  29.     spin_unlock_bh(&sc->wiphy_lock);  
  30.       
  31.     memcpy(common->bssidmask, iter_data.mask, ETH_ALEN);  
  32.     ath_hw_setbssidmask(common);  
  33. }  
ath9k_vif_iter是这样的:
[cpp] view plaincopy
  1. static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)  
  2. {  
  3.     struct ath9k_vif_iter_data *iter_data = data;  
  4.     int i;  
  5.   
  6.     for (i = 0; i < ETH_ALEN; i++)  
  7.         iter_data->mask[i] &= ~(iter_data->hw_macaddr[i] ^ mac[i]);  //就是上面提到的算法  
  8. }  

在drivers/net/wireless/ath/ath9k/main.c中,有个ath9k_add_interface函数,这个函数在创建一个BSS的时候会被调用,代码如下:

[cpp] view plaincopy
  1. static int ath9k_add_interface(struct ieee80211_hw *hw,  
  2.                    struct ieee80211_vif *vif)  
  3. {  
  4.     struct ath_wiphy *aphy = hw->priv;  
  5.     struct ath_softc *sc = aphy->sc;  
  6.     struct ath_hw *ah = sc->sc_ah;  
  7.     struct ath_common *common = ath9k_hw_common(ah);  
  8.     struct ath_vif *avp = (void *)vif->drv_priv;  
  9.     enum nl80211_iftype ic_opmode = NL80211_IFTYPE_UNSPECIFIED;  
  10.     int ret = 0;  
  11.   
  12.     mutex_lock(&sc->mutex);  
  13.   
  14.     switch (vif->type) {  
  15.     case NL80211_IFTYPE_STATION:  
  16.         ic_opmode = NL80211_IFTYPE_STATION;  
  17.         break;  
  18.     case NL80211_IFTYPE_WDS:  
  19.         ic_opmode = NL80211_IFTYPE_WDS;  
  20.         break;  
  21.     case NL80211_IFTYPE_ADHOC:  
  22.     case NL80211_IFTYPE_AP:  
  23.     case NL80211_IFTYPE_MESH_POINT:  
  24.         if (sc->nbcnvifs >= ATH_BCBUF) {  
  25.             ret = -ENOBUFS;  
  26.             goto out;  
  27.         }  
  28.         ic_opmode = vif->type;  
  29.         break;  
  30.     default:  
  31.         ath_err(common, "Interface type %d not yet supported\n",  
  32.             vif->type);  
  33.         ret = -EOPNOTSUPP;  
  34.         goto out;  
  35.     }  
  36.   
  37.     ath_dbg(common, ATH_DBG_CONFIG,  
  38.         "Attach a VIF of type: %d\n", ic_opmode);  
  39.   
  40.     /* Set the VIF opmode */  
  41.     avp->av_opmode = ic_opmode;  
  42.     avp->av_bslot = -1;  
  43.   
  44.     sc->nvifs++;  
  45.   
  46.     ath9k_set_bssid_mask(hw, vif); //计算新的BSSID掩码  
  47.   
  48.     if (sc->nvifs > 1)  
  49.         goto out; /* skip global settings for secondary vif */  
  50.   
  51.     if (ic_opmode == NL80211_IFTYPE_AP) {  
  52.         ath9k_hw_set_tsfadjust(ah, 1);  
  53.         sc->sc_flags |= SC_OP_TSF_RESET;  
  54.     }  
  55.   
  56.     /* Set the device opmode */  
  57.     ah->opmode = ic_opmode;  
  58.   
  59.     /* 
  60.      * Enable MIB interrupts when there are hardware phy counters. 
  61.      * Note we only do this (at the moment) for station mode. 
  62.      */  
  63.     if ((vif->type == NL80211_IFTYPE_STATION) ||  
  64.         (vif->type == NL80211_IFTYPE_ADHOC) ||  
  65.         (vif->type == NL80211_IFTYPE_MESH_POINT)) {  
  66.         if (ah->config.enable_ani)  
  67.             ah->imask |= ATH9K_INT_MIB;  
  68.         ah->imask |= ATH9K_INT_TSFOOR;  
  69.     }  
  70.   
  71.     ath9k_hw_set_interrupts(ah, ah->imask);  
  72.   
  73.     if (vif->type == NL80211_IFTYPE_AP    ||  
  74.         vif->type == NL80211_IFTYPE_ADHOC) {  
  75.         sc->sc_flags |= SC_OP_ANI_RUN;  
  76.         ath_start_ani(common);  
  77.     }  
  78.   
  79. out:  
  80.     mutex_unlock(&sc->mutex);  
  81.     return ret;  
  82. }  

由此可见,驱动程序在每次创建一个BSS——驱动程序的层面上看就是一个网络接口(network interface)——便会更新一下BSSID掩码。


        其实,BSSID掩码也是有缺陷的。还拿刚才的例子来说,MAC地址为0001的无线网卡有两个BSS,其BSSID分别为
0100和1001,根据上面的算法,计算的掩码为0010。假如此时收到一个BSSID字段为1100的帧,根据如下算法计算:

allow = (ifame_bssid & bssid_mask) == (bssid_mask & mac) ? true : false

         = (1100 & 0010) == (0010 & 0001) ? true : false

         = 0000 == 0000 ? true : false

         = true

但是,此AP根本不存在BSSID为1100的BSS!假如此时在同一个信道里面,另一个AP恰好存在一个BSSID为1100的BSS的话,那么这两个AP将同时ACK这个帧,其后果就是哪个ACK帧也不可能被客户端接收到——客户端只好重新发送这个帧——从而形成恶性循环。但是除非是管理员故意这么设置,可能性不大——一般没有人会在同一个信道和覆盖范围里面设置多个AP吧。

0 0
原创粉丝点击