我们知道,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