Linux内核工程导论——硬件:无线子系统

时间:2022-08-28 21:49:12

WiMax

    内核中有一个rfkill子系统,使用这个可以关闭任何一个射频收发器。Linux中倾向于通用架构子系统,各个设备其实都是实现这个子系统规定的函数。这些子系统向上就提供操作同类函数的完整接口。这就是类似于面向对象编程的Interface概念。


Wifi

PHY层

版本概要:

         802.11-2007是目前的基础版本,之前的过时版本不考虑。

         2009是较新的版本,就是目前最普及的802.11n。(100Mb/s)

         2012就是传说中的802.11ac,工作在5G,速度牛逼哄哄的,但穿透力不咋的。


各种PHY总览:

        2007里给出了5种PHY,也就是5种编码与调制方法,每种PHY对应的PHY帧格式都是不同的。也就是说,虽然这个wifi标准对外的接口(MAC)是一样的,但是根据底层采用的不同PHY,底层的从帧格式到编码、调制都是不一样的。5种PHY分别是:直序扩频(DSSS)、跳频扩频(FHSS)、正交频分复用(OFDM)、高速率直序扩频(HR/DSSS)、红外(TR)。另外,还给出一个叫ERP的增强版本的PHY,改变了调制方法,增强了DSSS和OFDM的速率。

       2009里又多了一种:高吞吐(HT OFDM),就是在原来的OFDM基础上改进得来。

       最新的802.11ac里又多了一种:超高吞吐(VHT OFDM),还是改进OFDM得来。

       两个改进的OFDM都支持MIMO,就是多天线。这玩意能提高不少速率,原理略过。

各PHY分别介绍:

        FHSS和DSSS属于扩频通信,就是把原来在较小带宽传送的信号用较大的带宽来传送。为什么要这样浪费带宽呢?窄带容易被干扰,把窄带信号分布到大带宽上就不易被干扰了。真的浪费带宽吗?同样的带宽能传输的数据速度还不一定谁快呢。

       FHSS就是在一系列窄频上同步跳跃;DSSS就是将相对大功率的窄频信号扩展到相对低功率的宽带信号。 两种扩频方式各有优劣,FHSS在移动性上更好,DSSS在静止速度上更快。所以,速度为主要考虑因素,会选择DSSS,移动性为主要考虑因素,会选用FHSS。目前,wifi上用户需求最大的是速度,所以DSSS发展较好。

       HR/DSSS是增强版的DSSS,原理很简单,只是改变了编码方式,和缩减了帧头部长度。从而增加了速度。

       ERP也是那么回事,通过对DSSS、OFDM编码的改进提高速度。

       OFDM是一种很神奇的技术。能提高频谱利用率,简单的说就是调制和复用的结合,提高信道吞吐。        

       而2009里说的HT OFDM就是增加一些MIMO(多天线)相关技术。用多根天线来增加速率。

       而802.11ac里说的VHT OFDM就是更高的带宽,更多OFDM子载波。技术上没有本质的变化,都是OFDM+MIMO的不断增强。


PHY整体对外接口:

       PHY的上层是MAC,各个版本的PHY需要向MAC提供统一的调用接口,就是原语。原语包括以下几类:

    1、基本特性。包括:MIB管理(PLME-GET、PLME-SET)、复位(PLME-RESET)、特性参数查询(PLME-CHARACTERISTICS)、DSSS进入测试模式(PLME-DSSSTESTMODE)、发送时间估计(PLME-TXTIME)

     2、数据首发。包括:数据传输(PHY-DATA)、发送控制(PHY-TXSTART、PHY-TXEND)、信道空闲检测(PHY-CCARESET、PHY-CCA)、接收控制(PHY-RXSTART、PHY-RXEND)


PHY内部结构:

        最下层叫PMD(物理介质依赖),与实际的物理介质打交道

        中间层叫PLCP(物理层聚合),把MAC层传下来要发送的数据变成对应的实际物理层PHY要发送的数据(经过调制和编码,肯定和MAC层原来的不同了),送给PMD

        最上层叫PHY SAP,就是上段定义的对MAC的服务接口。是MAC可以直接调用的稳定接口,不论具体的PHY是什么,这些接口都是可用的,而且只可以调用这些接口。

        说白了,SAP就是通过PLCP将各个不同的物理介质PMD以统一的接口对外展现。

        当然,结构中还包括一个信息库MIB,存储属性参数。

MAC层

MAC层是802.11的主要功能部分。上层应用通过调用MAC层提供的接口原语调用MAC层的功能。

     MAC一共向上提供了2大类接口原语,共30种。数据(1)和管理(29)。数据部分就是提供普通数据包的收发接口,管理部分是主要功能部分,例如发起认证、连接、信道扫描等其它所有管理功能,如下表所示:(并非所有的原语都是可调用的,一部分是indication形式的向上通知。有request的是可以调用的())

     

数据部分  
数据 MA-UNITDATA
管理部分  
电源管理 MLME-POWERMGT
信道扫描 MLME-SCAN
时间同步 MLME-JOIN
认证 MLME-AUTHENTICATE
断开认证 MLME-DEAUTHENTICATE
建立连接 MLME-ASSOCIATE
重新连接 MLME-REASSOCIATE
断开连接 MLME-DISASSOCIATE
复位 MLME-RESET
网络开始 MLME-START
测量 MLME-MREQUEST
信道测量 MLME-MEASURE
测量报告 MLME-MREPORT
信道切换 MLME-CHANNELSWITCH
发送功率通知 MLME-TPCADAPT
设置密钥 MLME-SETKEYS
删除密钥 MLME-DELETEKEYS
迈克尔失败事件 MLME-MICHAELMICFAILURE
可扩展局域网认证协议帧 MLME-EAPOL
点对点连接请求 MLME-PeerKeySTART
设置发送或接收的安全保护 MLME-SETPROTECTION
帧密钥错误丢弃通知 MLME-PROTECTEDFRAMEDROPPED
交通流(TS)管理接口 MLME-ADDTS
MLME-DELTS
直接连接管理 MLME-DLS
MLME-DLSTearDown
高层同步支持 MLME-HL-SYNC
合并ACK帧管理 MLME-ADDBA
MLME-DELBA
Qos调度变更通知 MLME-SCHEDULE
发行商特有 MLME-VSPECIFIC
MIB管理 MLME-SET
MLME-GET

以上的所有的原语构成了MAC对外提供的可操作接口。

           在内部,MAC由除了函数还有数据,叫MIB,存储MAC的各种参数。还有个专业术语叫SME的,其实是一个单独的模块,用来跟接口函数功能互动,完成各函数之间的关联操作和配合响应。属于配合接口正常运作的角色,对外不提供接口。

           以上的接口原语,按照功能模块,可以归纳出MAC主要包括如下功能:

1、信道管理。包括:信道扫描(MLME-SCAN)、信道测量(MLME-MREQUEST、MLME-MEASURE、MLME-MREPORT)、信道切换(MLME-CHANNELSWITCH)

2、连接管理。包括:认证(MLME-AUTHENTICATE)、断开认证(MLME-DEAUTHENTICATE)、建立连接(MLME-ASSOCIATE)、重新连接(MLME-REASSOCIATE)、断开连接(MLME-DEASSOCIATE)、开始网络(MLME-START)、点对点连接请求(MLME-PeerKeySTART)、直接连接管理(MLME-DLS、MLME-DLSTearDown)、

3、服务质量(Qos):交通流(TS)管理接口(MLME-ADDTS、MLME-DELTS)、Qos调度变更通知(MLME-SCHEDULE)、

4、功率控制。包括:电源管理(MLME-POWERMGT)、发送功率通知(MLME-TPCADAPT)

5、安全。包括:密钥管理(MLME-SETKEYS、MLME-DELETEKEYS)、迈克尔失败事件(MLME-MICHAELMICFAILURE)、EAPOL(MLME-EAPOL)、帧密钥错误丢弃通知(MLME-PROTECTEDFRAMEDROPPED)

6、时间同步。包括:时间同步(MLME-JOIN)、高层同步支持(MLME-HL-SYNC)、

7、特性。包括:合并ACK帧管理(MLME-ADDBA、MLME-DELBA)、发行商特有(MLME-VSPECIFIC)、MIB管理(MLME-SET、MLME-GET)

信道接入方式

      信道接入看起来是PHY的活,但是这是一个算法,不是一个操作,所以是MAC的活,信道接入的几种方式就属于MAC层的功能了。

       wi-fi的信道接入模式包括两种:CSMA/CA、节点协调模式。在无Qos的情况下,两种原生态的就可以了。在有Qos下,在两种的基础上分别定义了优先级来实现Qos传输。

       CSMA/CA就是传说中的载波监听冲突检测,最基本的无线接入方式。IEEE 的无线标准大都以这种接入为基本方法,就是监听信道,没有正在传输的就传,有就随机退避一段时间再监听信道。标准给了它一个很蛋疼的名字:DCF(Distributed Coordination Function),意思是协调是分布的,大家平等来商量谁接入网络。

      节点协调模式:无线路由器安排特定的节点在特定的时间通信,从而造成无阻塞的信道。这种方式采用的帧发送间隔比DCF小,从而保证在DCF和本模式同时存在的网络,本模式具有较高的接入优先级。标准给了它另外一个蛋疼的名字:PCF(Poing Coordination Function),意思是由某一个节点来“协调”谁接入网络,这个节点就是AP啦。

       在有Qos的情况下,DCF变成了EDCA,PCF变成了HCCA。别管这些破名字,起这名字的目的我估么着就是让大家迷糊的,就是代号就是了。意思就是为了实现Qos的的帧差别对待,给定义了优先级。

Linux下Wifi编程

写用户空间程序时,现在官方推荐的唯一编程方式就是基于netlink的nl80211.h编程。

       netlink是一种linux下的用户空间和内核空间通信的方式,传输的都是一个个的帧。用户空间程序通过生成预定义好的结构帧,与内核达到传递消息的目的。

       nl80211.h是一个头文件,也是用户空间调用内核wifi相关功能的接口。其中定义了所有暴露给用户空间的API函数索引(不是函数本身),以及这些函数采用的参数的格式和定义。用户程序通过netlink机制,将这些API函数索引和对应的参数封装到netlink的帧中,发送给内核,内核解析netlink帧后,读取帧中的内容,就知道用户需要调用哪个函数,以及该函数的参数,完成内核功能调用。

       说实话,这么折腾还不如直接调用API。。。。鬼让人家定义了这个唯一框架,就这么样吧。。。。。

先主要说一下netlink:

       有人已经写的很详细了:http://www.carisma.slowglass.com/~tgr/libnl/doc/core.html#core_cb 

       这里面没有提到调用nl80211.h用到的libnl-genl。这是libnl的一个高层扩展,就是说libnl也可以直接完成这个库的功能。由于libnl的帧种类越来越多,所以就有必要给这些帧种类分类,所以出现了好多个protocol family。。。为了能统一不同的协议族,定义了libnl-genl这么个通用接口。其实代码量很小,只是小小封装了一下。由于iw(linux下的wifi配置程序)用的这个库,所以有必要提一下。

        libgl的使用流程方法见源文件:http://harmattan-dev.nokia.com/docs/platform-api-reference/xml/daily-docs/libnl-doc/genl_8c_source.html

        netlink各个模块的函数和结构体参考见:http://harmattan-dev.nokia.com/docs/platform-api-reference/xml/daily-docs/libnl-doc/modules.html

再说一下nl80211.h的使用:

        不得不说,此部分的文档烂的出奇,或者说是根本没有文档。作为给出的唯一接口,你的文档仅限于代码注释,你好意思嚒。。。。

        http://lwn.net/Articles/211209/ 这里有个2006年的文档,已经过时,但是可以略知一二。看看没坏处。

        想要两节nl80211.h的调用方法,推荐看一下iw的源代码。

大体流程如下:(只是逻辑关系,从iw源代码中抽取)

        nl_socket_alloc();                                                                                    //生成netlink的socket(netlink相关内容参考上文给出的介绍)

       nl_socket_set_buffer_size(state->nl_sock, 8192, 8192);                //调整缓存大小

       genl_connect(state->nl_sock)                                                               //socket和内核连接(注意,这里用的genl的函数封装,具体可查参考(上文给出的地址))

       genl_ctrl_resolve(state->nl_sock, "nl80211");                                    //genl的概念,向内核查询一下协议族的标志

        msg = nlmsg_alloc();                                                                              //生成要发送往内核的帧(还没有填充内容)

       cb = nl_cb_alloc(iw_debug ? NL_CB_DEBUG : NL_CB_DEFAULT);      //生成回调函数,回调函数相关,见第一篇netlink的文档

       genlmsg_put(msg, 0, 0, state->nl80211_id, 0,                                   //往刚生成的帧中填充头部信息
   cmd->nl_msg_flags, cmd->cmd, 0);

       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);                //向刚生成的帧内部添加一个属性值

       nl_socket_set_cb(state->nl_sock, s_cb);                                            //设置回调函数

       nl_send_auto_complete(state->nl_sock, msg);                                 //发送刚生成的帧给内核。自此,内核当收到该请求时就会执行在帧中填充的命令索引和参数。比如搜索无线网,帧中就会填充scan命令对应的索引和要扫描的信道作为参数。

while (err > 0)
nl_recvmsgs(state->nl_sock, cb);                                                 //等待接收内核的反馈