1.wpa_supplicant软件架构分析
https://www.cnblogs.com/oracleloyal/p/5564786.html
2.wpa_supplicant-2.6移植
2.1libnl-1.1.4
(1)source code:
https://pan.baidu.com/s/1mwni0CtOFA7tcPJFGg3F7Q
(2)解压
$sudo tar -xvf *.gz
(3)$sudo mkdir build.sh
##################################################
export PATH=$PATH:/opt/Embedsky/gcc-4.6.2-glibc-2.13-linaro-multilib-2011.12/tq-linaro-toolchain/bin
export AR=arm-none-gnueabi-ar LD=arm-none-linux-gnueabi-ld
./configure --host=arm-none-linux-gnueabi- CC=arm-none-linux-gnueabi-gcc --prefix=/home/jason/E9/wpa/package/out //这条命令自动生成Makefile 文件,需要重新配置,直接删除Makefile 再./configure即可
#make CC=arm-none-linux-gnueabi-gcc AR=arm-none-linux-gnueabi-ar LD=arm-none-linux-gnueabi-ld
make
make install
##################################################
(4)out
/wpa/package/out/lib$ ls
libnl.a libnl.so libnl.so.1 libnl.so.1.1.4 pkgconfig
2.2openssl-1.0.1s
(1)source code
https://pan.baidu.com/s/1h1vsm9y4-EbtVyMV8Gfw1Q
(2)解压
$sudo tar -xvf *.gz
(3)$sudo mkdir build.sh
================================
export PATH=$PATH:/opt/Embedsky/gcc-4.6.2-glibc-2.13-linaro-multilib-2011.12/tq-linaro-toolchain/bin
./config no-asm --cross-compile-prefix=arm-none-linux-gnueabi- --prefix=/home/jason/E9/wpa/package/out
#./Configure no-asm --cross-compile-prefix=arm-none-linux-gnueabi- --prefix=/home/jason/E9/wpa/package/out
make
make install
================================
Problem:
Solution:
step1:Remove the all "-m64" of Makefile
step2: remove line ./config in build.sh
step3: sudo ./build.sh
//make again,don't run ./config no-asm --cross-compile-prefix=arm-none-linux-gnueabi- --prefix=/home/jason/E9/wpa/package/out anymore
Note: after remove "-m64" of Makefile,don't run ./config anymore,otherwise "-m64" issue can't be solved
(4)out
2.3wpa_supplicant-2.6
(1)source code
https://w1.fi/releases/
(2)解压
$sudo tar -xvf *.gz
(3)编译
step1: $sudo cp defconfig .config
step2: 修改.config文件
# Additional directories for cross-compilation on Linux host for mingw target
CFLAGS += -I/home/jason/E9/wpa/package/out/include
LIBS += -L/home/jason/E9/wpa/package/out/lib
CC=arm-none-linux-gnueabi-gcc
AR=arm-none-gnueabi-ar
LD=arm-none-linux-gnueabi-ld
step3:
export ARCH=arm
export PATH=$PATH:/opt/Embedsky/gcc-4.6.2-glibc-2.13-linaro-multilib-2011.12/tq-linaro-toolchain/bin/
make
Problem:
/wpa/package/out/lib/libnl.a: could not read symbols: File in wrong format
Solve:
add -ldl to Makefile
3.部署文件到目标板
3.1 cp wpa_cli/wpa_supplicant/wpa_passphrase 到目标板 usr/sbin
3.2 cp libnl.so.1 到目标板 lib/
3.3 cp libgcc_s.so.1到目标板 lib/
4.应用
问题1:
# wpa_supplicant -D nl80211 -i mlan0 -c /etc/wpa_supplicant.conf
Successfully initialized wpa_supplicant
nl80211: deinit ifname=mlan0 disabled_11b_rates=0
mlan0: Failed to initialize driver interface
# wpa_supplicant -D wext -i mlan0 -c /etc/wpa_supplicant.conf
Successfully initialized wpa_supplicant
rfkill: Cannot get wiphy information
wlan: SCAN COMPLETED: scanned AP count=0
ioctl[SIOCSIWESSID]: Bad address
mkdir[ctrl_interface=/var/run/wpa_supplicant]: No such file or directory
Failed to initialize control interface '/var/run/wpa_supplicant'.
解决1:
(1)要建立文件/var/run/wpa_supplicant 在etc/wpa_supplicant.conf有指定wpa_cli的文件夹
(2)驱动不对, nl80211找不到,要用wext驱动
===========================代码架构==============================
1.主线
wpa_supplicant是一个单线程的运行方式,靠事件event驱动,eloop_run()主循环通过select的方式不断监控不同事件event的变化相应调用处函数.
2.重要结构体
2.1 wpa_interface: Parameters for wpa_supplicant_add_iface() 与网口有关
2.2 wpa_params: Parameters for wpa_supplicant_init() 与wpa_supplicant -imlan0 -Dnl80211 ....命令的传入参数有关
2.3 wpa_global: Internal, global data for all %wpa_supplicant interfaces
2.4 wpa_supplicant:
2.5 l2_packet_data
3.初始化
3.1wpa_supplicant_init
3.1.1 eap_register_methods
3.1.2 eloop_init
初始化主线程eloop_data结构体,主要是通过各种事件event驱动,各类事件如下
(1)socket 事件
不同的socket事件通过放到fd_table里进行select监控.
如:priv->sock,netlink->sock,global->nl_event,l2->fd
(2)signal 事件
(3)timeout 事件
struct eloop_data {
int max_sock;
int count; /* sum of all table counts */
#if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE)
int max_fd;
struct eloop_sock *fd_table;
#endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */
struct eloop_sock_table readers; //socket event
struct eloop_sock_table writers;
struct eloop_sock_table exceptions;
struct dl_list timeout; //time event
int signal_count; //signal event
struct eloop_signal *signals;
};
3.1.3 wpa_supplicant_global_ctrl_iface_init()
(1)wpas_global_ctrl_iface_open_sock()
eloop_register_read_sock(priv->sock,wpa_supplicant_global_ctrl_iface_receive,global, priv);
创建wpa server并将此socket放到fd_table里进行select监控同时注册接收函数wpa_supplicant_global_ctrl_iface_receive
即wpa_cli发的命令都是通过此接受函数处理.
(2)wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
注册wpa_server的发送函数wpa_supplicant_ctrl_iface_msg_cb最终调用wpa_supplicant_ctrl_iface_send函数
即wpa_server发送数据给wpa_cli
3.2 wpa_supplicant_add_iface
3.2.1wpa_supplicant_init_iface //very important
(1)wpa_config_read(wpa_s->confname, NULL); //read file /etc/wpa_supplicant.conf
wpas_init_driver(wpa_s, iface)
wpa_supplicant_set_driver
global->drv_priv[i] = wpa_drivers[i]->global_init(global); // wpa_driver_nl80211_ops={}
.global_init = nl80211_global_init,
nl80211_global_init 创建3种不同类型的socket, 1.rtnetlinks socket 2. generic netlink socket 3. ictrl socket,用于与kernel交互.
1. rknetlink类型,用来处理网卡的路由,如新建,删除。
>netlink_init->netlink->sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); //NETLINK_ROUTE
>eloop_register_read_sock(netlink->sock, netlink_receive, netlink,NULL); -->wpa_driver_nl80211_event_rtm_newlink()
建立了netlink->sock并注册了来自kernel事件的接收函数同是将此socket放到eloop fd_table里select监控
2. generic netlink类型: 创建了连个socket,一个收,一个发。收的socket对应的回调函数过程是wpa_driver_nl80211_event_receive() -> process_global_event(),而发的handler根据命令的不同而不同。
>global->nl = nl_create_handle(global->nl_cb, "nl");
>global->nl_event = nl_create_handle(global->nl_cb, "event");
>nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,process_global_event, global);
>nl80211_register_eloop_read(&global->nl_event,wpa_driver_nl80211_event_receive,global->nl_cb);
将socket "global->nl_event" 放到eloop fd_table里select监控,并注册接收函数
wpa_driver_nl80211_event_receive()->process_global_event()
nl80211主要是通过发不同的命令cmd给到kernel的nl80211_cmd_msg,process_global_event()会接受cmd并调用不同处理函数
3. ioctl socket: 用来控制网口的up/down, 获取和设置hwaddr。
>global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
int linux_set_iface_flags(int sock, const char *ifname, int dev_up);
int linux_iface_up(int sock, const char *ifname);
int linux_get_ifhwaddr(int sock, const char *ifname, u8 *addr);
int linux_set_ifhwaddr(int sock, const char *ifname, const u8 *addr);
int linux_br_add(int sock, const char *brname);
int linux_br_del(int sock, const char *brname);
int linux_br_add_if(int sock, const char *brname, const char *ifname);
int linux_br_del_if(int sock, const char *brname, const char *ifname);
int linux_br_get(char *brname, const char *ifname);
(2)wpa_supplicant_init_wpa
l2_packet_init() //L2 packet
l2->fd = socket(PF_PACKET, l2_hdr ? SOCK_RAW : SOCK_DGRAM,htons(protocol));
ioctl(l2->fd, SIOCGIFINDEX, &ifr)
ioctl(l2->fd, SIOCGIFHWADDR, &ifr)
eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL);
L2 packet主要通过ioctrl控制,注册了回调函数l2_packet_receive并放到eloop fd_table去select监控
l2_packet_receive->wpa_supplicant_rx_eapol
3.3wpa_supplicant_run
eloop_run
主线程,程序不断循环监控以上所说的几种类型的事件的变化来相应处理.