Chinaunix首页 | 论坛 | 博客
  • 博客访问: 702204
  • 博文数量: 152
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1793
  • 用 户 组: 普通用户
  • 注册时间: 2013-09-12 12:26
个人简介

相信自己,只有不想做的,没有做不到的。

文章分类

全部博文(152)

文章存档

2021年(1)

2015年(2)

2014年(74)

2013年(75)

分类: Android平台

2014-09-15 23:26:07

                              第4章 深入理解wpa_supplicant

 

本章主要内容

  • 介绍wpa_supplicant的初始化
  • 介绍EAPEAPOL
  • 介绍wpa_supplicant如何加入无线网络

4.1 概述

wpa_supplicant是一个开源软件项目,它实现了Station[1]对无线网络进行管理和控制的功能。根据官方[2]描述,wpa_supplicant所支持的功能非常多,此处列举其中几个重要的功能点。

支持WPAIEEE 802.11i所定义的大部分功能:这部分功能集中在安全方面,包括:

  • 支持WPA-PSK(即WPA-Personal)和WPA-Enterprise(即利用RAIDUS认证服务器来完成身份认证的情况)。
  • 数据加密方面支持CCMPTKIPWEP104WEP40。注意,WEP104WEP40中的数字代表密钥的长度。104表示密钥长度为104个二进制位(如以ASCII字符个数来计算的话,WEP104支持的密钥长度为13ASCII字符)。
  • 完全支持WPAWPA2,包括PMKSA缓存,预认证(pre-authentication)等功能。
  • 支持IEEE 802.11r802.11w,其中802.11r规范定义了快速基础服务转移(Fast Transition)功能,而802.11w则新增了对管理帧的安全保护机制。
  • 支持WFA制定的Wi-Fi Proctected Setup功能、P2PTDLS等。

支持多种EAP Method:主要和802.1XSupplicant的功能有关,wpa_supplicant支持多达25EAP Method,包括:

  • EAP-TLSTLSTransport Layer Security)本身是一种传输层安全协议,它利用密钥算法提供端点身份认证与通讯保密,其基础是公钥基础设施(public key infrastructure,简称PKI)。EAP-TLS定义于RFC 5216
  • EAP-PEAPPEAPProtected Extensible Authentication Protocol,可扩展EAP)由微软、思科以及RSA Security三个公司共同开发,是一种利用证书加用户名和密码来进行身份验证的方法。
  • EAP-TTLS:它是TLS的拓展,全名为Tunneled Transport Layer Security(隧道传输层安全协议),相比TLS,它简化了认证过程中客户端的工作。
  • EAP-SIMEAP-PSKEAP-GPSK等其他认证方法。

读者可阅读参考资料[1]以了解更多EAP方法的知识。

对各种无线网卡和驱动的支持:

  • 支持nl80211/cfg80211驱动和Linux Wireless Extension驱动[3]
  • 支持Windows平台中的NDIS驱动。

提示:wpa_supplicant虽然支持Windows平台,但笔者相信绝大多数读者使用的都是Windows自带的无线网络管理程序(或者Intel芯片相关软件提供的无线网络管理程序)。从功能角度来说,读者可认为wpa_supplicant是这些私有程序的一种开源实现。

Android做为开源世界的集大成者,它在无线网络管理和控制方面直接使用了wpa_supplicantAndroid 4.1中,external目录下有两个和wpa_supplicant相关的目录,分别是wpa_supplicant_6wpa_supplicant_868分别代表对应wpa_supplicant的版本号为0.6.102.0-devel

提示:关于wpa_supplicant的发布历史,请读者参考

本书的分析目标是wpa_supplicant_8,它包含三个主要子目录,分别是:

  • hostapd:当手机进入SoftAP模式时,手机将扮演AP的角色,故需要hostapd来提供AP的功能。
  • wpa_supplicantStation模式,也叫Managed模式。它是本书分析的重点。
  • srchostapdwpa_supplicant中都包含了一些通用的数据结构和处理方法,这些内容都放在此src目录中。注意,hostapd/srcwpa_supplicant/src子目录均链接到此src目录。

wpa_supplicantAndroid用户空间中无线网络部分的核心模块,所有Framework层中和Wi-Fi相关的操作最终都将借由wpa_supplicant来完成。另外,wpa_supplicant本身对802.11802.1XWi-Fi Alliance定义的一些规范都有极好的支持。所以,分析它将是加深理解802.11及相关理论知识的一个非常重要的途径。

本章拟打算带领读者从两条分析路线来掌握wpa_supplicant和相关的功能模块。

  • 路线一:首先将介绍wpa_supplicant的初始化过程。这条路线将帮助读者了解wpa_supplicant中常见的数据结构及之间的关系。这条路非常难走,请读者做好心理准备。
  • 路线二:我们将通过命令行发送命令的方式触发wpa_supplicant进行相关工作,使得手机加入一个利用WPA-PSK进行认证的无线网络。这条路线将帮助读者了解wpa_supplicant中的命令处理、scanassociation4-way handshake等相关处理流程。

提示:后续章节还将围绕Android中无线网络技术开展更多的讨论:

1)第5章将介绍Android Framework中的WifiService及其相关模块。

2)第67章节将继续wpa_supplicant之旅,其内容和WPSWi-Fi P2P以及WifiP2pService有关。

为了行文方便,本书将用WPAS来表示wpa_supplicant。另外,后文代码分析中还能见到一种重要的数据结构,它也叫wpa_supplicant。请读者根据上下文信息来理解wpa_supplicant的含义。

正式开始分析之旅前,我们先来简单了解下wpa_supplicant

4.2 初识wpa_supplicant

本节介绍WPAS一些外围知识,包括软件结构、编译配置、控制命令和对应控制API的用法。其中,控制命令的格式和API的用法将在后续介绍WifiService相关模块时会见到。另外,在研究WPAS时,能熟练掌握用git查询历史版本信息也非常关键。WPAS的故事首先从其软件架构开始。

4.2.1 wpa_supplicant架构介绍

wpa_supplicant是一个比较庞大的开源软件项目,包含500多个文件,20万行代码,其内部模块构成如图4-1所示[2]

4-1  wpa_supplicant软件架构

4-1所示的WPAS软件架构包括如下重要模块:

  • WPAS所有工作都围绕事件(对应图4-1中的event loop模块)展开。即,它是基于事件驱动的。事件驱动和消息驱动类似,主线程等待事件的发生并处理它们。WPAS没有使用多线程编程,所有事件处理都在主线程中完成。从这一点看,WPAS的运行机制倒是很简单。
  • 位于event loop模块下方的driver i/fi/f代表interface)接口模块用于隔离和底层驱动直接交互的那些driver控制模块(如wextndiswrapper等,WPAS中称之为driver wrapper)。这些driver wrapper和平台以及芯片所使用的驱动相关。不过,由于driver i/f的隔离作用,WPAS中其他模块将能最大程度保持平台以及驱动无关性。
  • driver wrapper经常要返回一些信息给上层。WPAS中,这些信息将通过driver events的方式反馈给WPAS其他模块进行处理。
  • 上一章曾介绍过EAP以及EAPOL协议。除了定义消息格式外,RFC4137文档定义了EAP状态机,而802.1X文档中还定义了EAPOL状态机。WPAS根据这两个协议分别实现了EAPEAPOL状态机。本章后续将详细分析这两个状态机以及背后的协议。除此之外,WPAS还定义了自己的状态机(即WPA/WPA2 State Machine)。
  • WPAS实现了多种EAP方法,如图4-1EAP method模块所示。另外它还包含了TLS模块和crypto模块用于支持对应的EAP方法。
  • EAPOL以及EAP消息都属于LLC层数据,所以WPASl2_packet模块用于收发EAPOLEAP消息。
  • WPAS支持较多的配置参数,这些参数的处理由configuration模块完成。
  • WPASC/S结构中的Server端,它通过ctrl i/f模块向客户端提供通信接口。Linux/Unix平台中,Client端利用Unixsocket与其通信。目前常用的Clientwpa_cli(无界面的命令行程序)和wpa_guiUIQt实现)。

WPAS支持众多功能,使用前往往需根据平台或驱动的特性进行编译配置,下面通过一个实例来介绍如何在Android中编译wpa_supplicant

4.2.2 wpa_supplicant编译配置介绍

本实例的背景情况如下:

笔者有一台三星Galaxy Note2手机,其OSAndroid 4.1.2。现在,笔者打算编译一个AOSPAndroid Open Source Project)的wpa_supplicant程序以替换Note2中原有的wpa_supplicant

提示:AOSPGoogle公版Android源码。几乎所有手机厂商都会根据芯片、硬件以及厂商自定义的特性去修改它。由于Note 2源码不公开,所以笔者只能编译AOSP版的wpa_supplicant

假设读者已经按第1章要求部署完毕Android 4.1源码和开发环境,那么接下来要做的是:

cd  4.1source #首先进入4.1源码根目录

source build/envsetup #建立Android源码编译环境

lunch  #选择要编译的设备和版本,笔者选择了1,代表full-eng。eng代表工程版,该选项对应的目标设备类型

        #(TARGET_PRODUCT)为generic,其编译出来的镜像文件可由模拟器加载并运行

由上述配置可知,笔者将使用generic的版本来编译一个wpa_supplicant以运行在真实的机器上。

提醒:通过执行lunch命令可知,不同的设备应有对应的编译配置项。由于笔者没有Note 2的源码,所以只能尝试编译generic版本。

接下来要为generic平台定制所使用的wpa_supplicant版本,这是通过修改BoardConfig.mk来完成的。

[-->BoardConfig.mk]

#在此文件最后添加如下内容:

WPA_SUPPLICANT_VERSION := VER_0_8_X  #表明使用wpa_supplicant_8

BOARD_WPA_SUPPLICANT_DRIVER := NL80211  #表明驱动使用Nl80211

BOARD_WLAN_DEVICE := bcmdhd  #表明kernel中的wifi设备为博通公司的bcmdhd

#编译博通公司驱动相关的静态库,该库对应的代码也在AOSP源码中,位置是,

#hardware/broadcom/wlan/bcmdhd/wpa_supplicant_8_lib/

BOARD_WPA_SUPPLICANT_PRIVATE_LIB := lib_driver_cmd_bcmdhd 

巧合的是,Note 2使用的wlan芯片刚好为bcmdhd

除了修改BoardConfig.mk外,WPAS也定义了自己的编译配置文件android.config,其内容如下:

......#该文件主要定义了编译时生成的宏,各平台根据自己的硬件情况去设置需要编译的内容

# Driver interface for generic Linux wireless extensions

CONFIG_DRIVER_WEXT=y  #可注释这一条以取消编译WEXT相关代码

# Driver interface for Linux drivers using the nl80211 kernel interface

CONFIG_DRIVER_NL80211=y  #可去掉此行的注释符号以增加对Nl80211的支持

CONFIG_LIBNL20=y

......#其他很多编译配置项都可在此文件中修改

#注意,此文件中对CONFIG_DRIVER_NL80211的修改和BoardConfig.mk中的BOARD_WPA_SUPPLICANT_DRIVER

#相重合。BoardConfig.mk的优先级较高,所以请读者先修改它。

配置完毕后,开始编译:

#首先要编译wpa_supplicant依赖的静态库lib_driver_cmd_bcmdhd

mmm hardware/broadcom/wlan/bcmdhd/wpa_supplicant_8_lib/

mmm external/wpa_supplicant_8 #生成wpa_supplicant,同时也会生成wpa_cli

然后将编译后wpa_supplicant替换Note 2/system/bin/wpa_supplicant并设置其为可运行(通过chmod命令设置其权限位0755)。同时,笔者也把wpa_cli push/system/bin下为后续测试做准备。

经过测试,笔者发现AOSPwpa_supplicant以及wpa_cli均能正常工作在Note 2上。这也间接表明Note 2并未对wpa_supplicant以及博通芯片相关的代码做较大改动。

注意:严格来说,android.cfg应该是唯一的编译控制文件。但由于底层wlan芯片不同,WPAS可能还依赖其他模块。所以,在具体实施时,BoardConfig.mk(或其他文件,视具体情况而定)也需要做修改。

4.2.3 命令和控制API介绍

1.  命令介绍

由图4-1的介绍可知,WPAS对外通过控制接口模块与客户端通信。在Android平台中,WPAS的客户端是位于Framework中的WifiService。用户在Settings界面进行Wi-Fi相关的操作最终都会经由WifiService通过发送命令的方式转交给wpa_supplicant去执行。WPAS定义了许多命令,常见的:

  • PING:心跳检测命令。客户端用它判断WPAS是否工作正常。WPAS收到”PING”命令后需要回复“PONG”。
  • MIB:客户端用该命令获取设备的MIB信息。
  • STATUS:客户端用该命令来获取WPAS的工作状态。
  • ADD_NETWORK:为WPAS添加一个新的无线网络。它将返回此新无线网络的id(从0开始)。注意:此network id非常重要,客户端后续将通过它来指明自己想操作的无线网络。
  • SET_NETWORK network id是无线网络的id。此命令用于设置指定无线网络的信息。其中variable为参数名,value为参数的值。
  • ENABLE_NETWORK :使能某个无线网络。此命令最终将促使WPAS发起一系列操作以加入该无线网络。

除了接收来自Client的命令外,WPAS也会主动给Client发送命令。例如,WPAS需用户为某个无线网络输入密码。这类命令称之为Interactive Request,其格式如下。

  • WPAS向客户端发送的命令遵循CTRL-REQ---格式。如CTRL-REQ-PASSWORD-0-Passwork needed for SSID test-network。这条命令表示需要用户为0号网络输入密码。
  • 客户端处理完后,需回复CTRL-RSP---。目前支持的field包括PASSWORDIDENTITYEAP中的identity或者用户名)、PIN等。
  • 最后,WPAS还可通过形如“CTRL-EVENT--”的命令向客户端通知一些事情。

提示:除了“CTRL-EVENT-XXX”之外,WPAS还支持形如“WPA:XXX”和“WPS-XXX”的通知事件。这些事件和WPAWPS有关。下一章分析WifiService时我们还能见到它们。

4-2所示为笔者利用wpa_cli测试status命令得到的结果。

4-2  wpa_cli命令测试示意

4-2所示为status命令的结果。图中最后几行显示WPASwpa_cli返回了两个CTRL-EVENT信息。

2.  控制API介绍

Android平台中WifiServiceWPAS的客户端,它和WPAS交互时必须使用wpa_supplicant提供的API。这些API声明于wpa_ctrl.h中,其用法如下:

//必须包含此头文件,链接时需包含libwpa_client.so动态库

#include “wpa_ctrl.h”

客户端使用wpa_ctrl时首先要分配控制对象。下面两个API用于创建和销毁控制对象wpa_ctrl

//创建一个wpa控制端对象wpa_ctrlAndroid平台中,参数ctrl_path代表unix域socket的位置

struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path);

void wpa_ctrl_close(struct wpa_ctrl *ctrl);//注销wpa_ctrl控制对象

下面这个函数用于发送命令给WPAS

//客户端发送命令给wpa_supplicant,回复的消息保存在reply中

int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,

             char *reply, size_t *reply_len,void (*msg_cb)(char *msg, size_t len));

msg_cb是一个回调函数,该参数的设置和WPASC/S通信机制的设计有关:

Client角度来看,它发送给WPAS的命令所对应的回复属于solicited event(意为有请求的事件),而前面所提到的CTRL-EVENT事件(用于通知事件)对应为unsolicited event(意为未请求的事件)。当Client在等待某个命令的回复时,WPAS同时可能有些通知事件要发送给客户端,这些通知事件不是该命令的回复,所以不能通过wpa_ctrl_requestreply参数返回。

为了防止丢失这些通知事件,wpa_cli设计了一个msg_cb回调用于客户端在等待命令回复的时候处理那些unsolicited event

这种一个函数完成两样完全不同的功能的设计实在有些特别,所以wpa_supplicant规定只有打开通知事件监听功能的wpa_ctrl对象才能在wpa_ctrl_request中通过msg_cb获取通知事件。而打开通知事件监听功能相关的API如下所示。

//打开通知事件监听功能

int wpa_ctrl_attach(struct wpa_ctrl *ctrl);

//打开通知事件监听功能的wpa_ctrl对象能直接调用下面的函数来接收unsolicited event

int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len);

如果客户端并不发送命令,而只是想接收Unsolicited event的话,可通过wpa_ctrl_recv函数来达到此目的。

综上所述,单独使用wpa_ctrl_recvwpa_ctrl_request都不方便。所以,一种常见的用法是:客户端创建两个wpa_ctrl对象来简化自己的逻辑处理:

  • 一个打开了通知事件监听功能的wpa_ctrl对象将只通过wpa_ctrl_recv来接收通知事件。
  • 另外一个wpa_ctrl专职用于发送命令和接收回复。由于没有调用wpa_ctrl_attach,故它不会收到通知事件。

提示:下一章分析WifiService时将见到这种创建两个wpa_ctrl对象的做法。

4.2.4  git的使用

WPAS难度较大的一个重要原因是其注释较少,很多变量的含义没有任何解释。笔者也为此大伤脑筋。不得以,只能通过查看WPAS代码的历史版本来寻根溯源。经过实践,笔者总结了利用git来查询WPAS历史版本信息的一些步骤,分别如下。

git clone命令下载WPAS官方代码。

git clone git://w1.fi/srv/git/hostap.git  

以下命令的含义是查询use_monitordriver_nl80211.c中的变化情况。

git blame src/drivers/driver_nl80211.c | grep use_monitor 

因为use_monitor定义于该文件中,所以用git blame去查看它。得到的结果如图4-3所示。

4-3  git blame结果

4-3中的第一行显示了use_monitor最早出现的那个patch的情况,其对应的commit ida11241fa。接着,再通过命令git log a11241fa查看当时的commit信息,结果如图4-4所示。

4-4  git log结果

4-4展示了a11241fa对应的commit消息。由于提交者一般会在该消息中添加注释性内容。所以可通过研究这些内容来了解代码中某些变量的含义。

下面正式开始WPAS的代码分析之旅。首先是WPAS的初始化流程分析。



[1]注意,wpa_supplicant项目中还包含一个名为hostapd程序的代码,它实现了AP的功能。本书不拟讨论hostpad的代码。

[2] wpa_supplicant项目的官方地址为

[3]根据审稿专家的反馈,wpa_supplicant仅支持Linux Wireless Extension V19以后的版本。

 

==========略略略略略略略略略略略略略略略===============

4.5  wpa_supplicant连接无线网络分析

本节将介绍本章第二条分析路线,即通过命令行发送命令的方式触发wpa_supplicant进行相关工作,使手机加入一个利用WPA-PSK进行认证的无线网络。

以笔者的Note 2为例,整个过程用到的命令如下所示。

[命令示例]

adb root #获取手机root用户权限。只有root被破解的手机才能成功

adb shell #登录手机shell

#笔者事先已编译wpa_cli并将其放到/system/bin目录中。这个命令用于启动wpa_cli,-i参数指明unix域控制

#socket文件名,它应该和wpa_supplicant启动时设置的控制接口文件名一致

wpa_cli -iwlan0 #该命令执行后,将进入wpa_cli进程,后续操作都在此进程中开展

#发送ADD_NETWORK命令给wpa_supplicant,它将返回一个新网络配置项的编号。请参考4.3.3.1"wpas_ssid结构

#体介绍"一节

ADD_NETWORK #假设wpa_supplicant返回的新网络配置项编号为0

SET_NETWORK 0 ssid "Test" #设置0号网络的ssid为“Test”

SET_NETWORK 0 key_mgmt WPA-PSK #设置0号网络的key_mgmt为“WPA-PSK”

SET_NETWORK 0 psk "12345Test" #设置0号网络的psk为“12345Test”

ENABLE_NETWORK 0 #使能0号网络,它将触发wpa_supplicant扫描、关联等一系列操作直到加入无线网络“Test”

CTRL+C #退出wpa_cli

dhcpcd wlan0 #启动dhcpd,wlan0为无线接口设备名。dhcpcd可为手机从AP那获取一个IP地址

dhcpcd成功执行后,手机将从AP那分配到一个IP地址。至此,手机就可以使用“Test”无线网络了。

注意:上述命令执行前有几个注意事项:

1)先要在Settings中开启无线网络。这个操作完成了wlan驱动及相应固件加载的工作。该工作实际上由netd来完成,而wpa_cli无法完成它。

2)开启无线网络后,WifiServicewpa_supplicant都开始工作了。为了避免WifiService的干扰,可以把Settings中的那些已知的无线网络信息都清除。

3)由于wpa_supplicant支持多个客户端,所以wpa_cli可以和WifiService共同工作。只要不操作Settings中无线网络相关的选项,WifiService就不会干扰wpa_cli

4)然后按上述步骤执行wpa_cli

根据前文所述,所有来自客户端的命令都由wpa_supplicant_ctrl_iface_receive函数处理(参考4.3.4中“wpa_supplicant_ctrl_iface_init介绍”一节)。该函数代码非常简单,就是根据客户端发送的命令进行对应处理。

[-->ctrl_iface_unix.c::wpa_supplicant_ctrl_iface_receive]

static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,

                          void *sock_ctx)

{

    struct wpa_supplicant *wpa_s = eloop_ctx;

    struct ctrl_iface_priv *priv = sock_ctx;

    char buf[4096]; int res; struct sockaddr_un from;

    socklen_t fromlen = sizeof(from);

    char *reply = NULL; size_t reply_len = 0; int new_attached = 0;

 

    res = recvfrom(sock, buf, sizeof(buf) - 1, 0,(struct sockaddr *) &from, &fromlen);

     .....

    buf[res] = '\0';

    //客户端第一次和WPAS连接时,需要发送"ATTACH"命令

    if (os_strcmp(buf, "ATTACH") == 0) {

        ......//略过相关处理

    } .....//"DETACH"和"LEVEL"命令处理

else {

#if defined(CONFIG_P2P) && defined(ANDROID_P2P)

     ......//P2P处理。虽然WPAS编译时打开了CONFIG_P2P和ANDROID_P2P,但本章不讨论P2P相关的内容

#endif

        //大部分的命令处理都在wpa_supplicant_ctrl_iface_process函数中

        reply = wpa_supplicant_ctrl_iface_process(wpa_s, buf,&reply_len);

    }

   

    if (reply) {//回复客户端

        sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,fromlen);

        os_free(reply);

    } ......

  /*

    Client成功ATTACH后,将通知EAPOL模块。因为有些认证流程需要用户的参与(例如输入密码之类的),

    所以当客户端连接上后,EAPOL模块将判断是否需要和客户端交互。读者可阅读

     eapol_sm_notify_ctrl_attached函数。

  */

   if (new_attached)

        eapol_sm_notify_ctrl_attached(wpa_s->eapol);

}

如上述代码所示,绝大部分命令都由wpa_supplicant_ctrl_iface_process函数处理。下面将按顺序来分析其处理ADD_NETWORKSET_NETWORK以及ENABLE_NETWORK的代码。

4.5.1  ADD_NETWORK命令处理

[-->ctrl_iface.c::wpa_supplicant_ctrl_iface_process]

char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,char *buf,

                   size_t *resp_len)

{

    char *reply;

    const int reply_size = 4096;

    int ctrl_rsp = 0;

    int reply_len;

    ......

    reply = os_malloc(reply_size);

   .....

    //开始命令处理

    ......

    else if (os_strcmp(buf, "ADD_NETWORK") == 0) {

        reply_len = wpa_supplicant_ctrl_iface_add_network( wpa_s, reply, reply_size);

    }else if

    ......//其他命令处理

   

    if (reply_len < 0) {//命令处理出错

        os_memcpy(reply, "FAIL\n", 5);

        reply_len = 5;

    }

    ......

    *resp_len = reply_len;

    return reply;

}

ADD_NETWORK的真正处理在wpa_supplicant_ctrl_iface_add_network函数中,其代码如下所示。

[-->ctrl_iface.c::wpa_supplicant_ctrl_iface_add_network]

static int wpa_supplicant_ctrl_iface_add_network(struct wpa_supplicant *wpa_s,

                  char *buf, size_t buflen)

{

    struct wpa_ssid *ssid;

    int ret;

    //wpa_config_add_network返回一个wpa_ssid对象,读者还记得它吗?wpa_ssid是无线网络配置项在

   //WPAS中的反映(请参考4.3.3中“wpa_ssid结构体介绍”一节)。wpa_config_add_network内部就是

   //分配一个wpa_ssid对象,然后将其保存到一个链表中。注意,wpa_config是wpa_supplicant.conf

   //在代码中的代表。所以,此处添加的无线网络信息将会保存到配置文件中,以备下次使用。

    ssid = wpa_config_add_network(wpa_s->conf);

   ......

    wpas_notify_network_added(wpa_s, ssid);

    ssid->disabled = 1; //disabled为1表示该无线网络未启用,需要通过ENABLE_NETWORK来启动它

    //设置该无线网络的默认配置项

    wpa_config_set_network_defaults(ssid);

   //返回该网络的编号(由wpa_ssid的id变量表示。它在wpa_config_add_network函数中被赋值)

    ret = os_snprintf(buf, buflen, "%d\n", ssid->id);

    ......

    return ret;

}

上述代码比较简单,无非就是分配一个wpa_ssid对象,然后设置它的一些默认属性。整个函数返回该wpa_ssid对象的id,即它在链表中的顺序。

wpa_ssid的默认属性对后续流程有一些影响,那么默认属性都是什么呢?不妨来看看wpa_config_set_network_defaults函数,代码如下所示。

[-->config.c::wpa_config_set_network_defaults]

void wpa_config_set_network_defaults(struct wpa_ssid *ssid)

{

   //设置proto、pairwise_cipher、group_cipher以及key_mgmt的信息,读者还记得这些变量的含义吗?

   //请参考4.3.3中“安全相关成员变量及背景知识介绍”一节

    ssid->proto = DEFAULT_PROTO;

    ssid->pairwise_cipher = DEFAULT_PAIRWISE;

    ssid->group_cipher = DEFAULT_GROUP;

    ssid->key_mgmt = DEFAULT_KEY_MGMT;

#ifdef IEEE8021X_EAPOL

    ssid->eapol_flags = DEFAULT_EAPOL_FLAGS;//EAP相关变量,见下文解释

    ssid->eap_workaround = DEFAULT_EAP_WORKAROUND;

    ssid->eap.fragment_size = DEFAULT_FRAGMENT_SIZE;

#endif /* IEEE8021X_EAPOL */

#ifdef CONFIG_HT_OVERRIDES

    ......//和802.11n有关,本书不涉及

#endif /* CONFIG_HT_OVERRIDES */

}

上述代码中出现了三个和EAPOL相关的变量,此处简单介绍一下:

  • eapol_flags:它和动态WEP key有关。只适用于非WPA安全环境中,可取值有三个,分别是1(代码中定义为BIT(0),表示需要为单播数据传输使用动态WEP Key,对应宏为EAPOL_FLAG_REQUIRE_KEY_UNICAST)、2(代码中定义为BIT(1),表示需要为组播数据传输使用动态WEP Key,对应宏为EAPOL_FLAG_REQUIRE_KEY_BROADCAST)以及3(单播和组播都使用动态WEP Key,对应宏为DEFAULT_EAPOL_FLAGS
  • eap_workaround:身份认证方法多种多样,而有些Authenticator服务器(缩写为AS)并不严格遵守规范。该变量表示碰到这种情况时,WPAS是否可以采取“绕”(workaround本意是“变通”)过去的方式来对待这些AS。由于这种不严格的情况非常普遍,所以该值默认是1
  • fragment_size:该变量和EAPOL消息分片大小有关。默认的DEFAULT_FRAGMENT_SIZE大小为1398,表示EAPOL消息只要不超过这个大小,就不用对其进行分片。

ADD_NETWORK”命令比较简单,它最终将返回给客户端对应的无线网络配置的编号。在本例中,它是0

下面来看客户端通过“SET_NETWORK”为该无线网络配置项设置参数的处理过程。

 

============================略略略略略===================

4.6  本章总结和参考资料一览

4.6.1  本章总结

本章对wpa_supplicant进行了一番剖析,涉及如下几个重点内容:

  • WPAS的启动:在这条分析路线中,读者能感受到WPAS中多种多样的数据结构以及之间较为复杂的关系。同时,我们对那些极具背景含义的成员变量也进行了深入介绍。
  • EAPOL/EAP模块:这一节中,我们先向读者介绍了理论知识,然后结合代码分析了WPAS如何将理论知识转化成代码。从笔者角度来看,状态机的代码比看状态切换图要复杂得多。读者不妨自己亲身体验一下。
  • 扫描、关联及4-Way Handshake分析:我们通过一个实例讲解了这一流程涉及的重要函数和相关知识点。该流程实际上包含的代码远比书中给出来的多,原因是WPAS支持的许多其他功能(如WPSP2P802.11R802.11W等)都在这一流程中有涉及。根据笔者自己的学习经验,只有先搞清楚一个最简单的流程,后面才能循序渐进地把其他功能的分析加进来。

提示:本章编撰时,市面上搭载Android 4.2的手机较少。所以此处的分析目标是Android 4.1中的wpa_supplicant。不过笔者比较了它和Android 4.2中的wpa_supplicant。虽然4.2中的WPAS变化较大,但主要体现在一些新增功能和Bug修改上。读者如果搞清楚了本章所介绍的内容,再转去研究4.2中的WPAS所需要的学习成本不会太大。

 

4.6.2  参考资料一览

概述

[1] 

维基百科关于EAP各种方法的一个简单介绍。

[2]  wpa_supplicant/devel/

wpa_supplicant官方开发文档。读者可以简单浏览一下。

wpa_ssid结构体介绍

[3]  802.11-2012 附录M.4 Suggested pass-phrase-to-PSK mapping

该节介绍了passphrase转换成PSK的方法,甚至还有伪代码实现。感兴趣的读者不妨结合WPAS中的代码来研究它。

[4]  802.11-2012 8.4.2.27.2节“Cipher suites

[5]  802.11-2012 8.4.2.27.3节“AKM suites

上述两小节分别介绍了CipherAKM suites的情况。注意,其中定义的取值定义是指在RSN IE中的取值,和代码中定义的宏不是一回事。

[6]  802.11-2012 12章“Fast BSS Transition

官方文档。不过难度较大,建议读者阅读“Secure Roaming in 802.11 Networks”一书后再去看它。提醒,此书是笔者目前阅读到的关于Wi-Fi Roaming相关知识介绍最完整的一本。

[7]  Real 802.11 SecurityWi-Fi Protected Access and 802.11i 6章“How IEEE 802.11 WEP Works and Why It Doesn't

关于WEP介绍的章节。另外,对安全感兴趣的读者请仔细阅读此书。

[8] 

关于Opportunistic PMK Caching的简单介绍。

[9]  Secure Roaming in 802.11 Networks8章“Opportunistic Key Caching”一节

相比[8]而言,这一节对OKC有更为详尽的介绍。

wpa_supplicant结构体介绍

[10]  802.11无线网络权威指南(第二版)第七章“802.11RSNTKIPCCMP”,P171-P172

[11]  802.11-2012 11.4.2.4节“TKIP countermeasures procedures

上述两个参考资料介绍了TKIP countermeasures的处理方式。请读者先阅读[10]

[12] 

[13]  Secure Roaming in 802.11 Networks5.2.5节“Background Scanning

Background Scan技术的介绍。

[14] 

[15] 

GAS以及802.11u相关的一些介绍。

wpa_supplicant_init_iface分析之三

[16]  http://www.mjmwired.net/kernel/Documentation/rfkill.txt

[17] 

这两篇资料介绍了rfkill相关的信息。感兴趣的读者不妨仔细阅读它们。

[18] 

RFC2863 3.1.13IfAdminStatus and IfOperStatus”一节描述了IfOperStatus的取值情况及相关说明。

[19]  http://wireless.kernel.org/en/developers/Documentation/nl80211/kerneldoc

linux wireless kernel官方网站中nl80211内核部分的一些解释。

EAP模块分析

[20] 

RFC4137文档的PDF版。相比TXT版而言,它用图来描述状态机的状态切换。

EAPOL模块分析

[21]  802.1X 2004

WPAS中的802.1X实现是基于802.1X 2004版。相比2010版而言,笔者觉得2004版的内容更具条理性。尤其是其关于EAPOL各状态机的描述非常清晰。

EAPOL-Key交换流程分析

[22]  Real 802.11 SecurityWi-Fi Protected Access and 802.11i 10章“WPA and RSN Key Hierarchy

[23]  802.11-2012 11.6Keys and key distribution

这两篇参考资料对Pairwise KeyGroup Key以及4-Way HandshakeGroup Key Handshake都有详细的介绍。

[24]  wireless.kernel.org/en/users/Documentation/WoWLAN

[25]  msdn.microsoft.com/en-us/library/windows/hardware/ff571052(v=vs.85).aspx

这两篇文章对WoWLAN有一番介绍。读者可简单阅读它们。

 

阅读(2342) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~