文档章节

wpa_supplicant与kernel的接口

s
 sflfqx
发布于 2014/09/29 17:07
字数 1669
阅读 433
收藏 0

1. 接口定义实现wpa_drivers

 

  wpa_drivers的定义如下:

[cpp] view plaincopy

  1. struct wpa_driver_ops *wpa_drivers[] =  

  2. {  

  3. #ifdef CONFIG_DRIVER_WEXT  

  4.     &wpa_driver_wext_ops,  // 我的系统使用的这个老的接口  

  5. #endif   

  6. #ifdef CONFIG_DRIVER_NL80211   // 现在流行的NL80211接口  

  7.     &wpa_driver_nl80211_ops,  

  8. #endif   

  9. #ifdef CONFIG_DRIVER_HOSTAP  

  10.     &wpa_driver_hostap_ops,  

  11. #endif   

  12. #ifdef CONFIG_DRIVER_MADWIFI  

  13.     &wpa_driver_madwifi_ops,  

  14. #endif   

  15. #ifdef CONFIG_DRIVER_BROADCOM  

  16.     &wpa_driver_broadcom_ops,  

  17. #endif   

  18. #ifdef CONFIG_DRIVER_BSD  

  19.     &wpa_driver_bsd_ops,  

  20. #endif   

  21. #ifdef CONFIG_DRIVER_NDIS  

  22.     &wpa_driver_ndis_ops,  

  23. #endif   

  24. #ifdef CONFIG_DRIVER_WIRED  

  25.     &wpa_driver_wired_ops,  

  26. #endif   

  27. #ifdef CONFIG_DRIVER_TEST  

  28.     &wpa_driver_test_ops,  

  29. #endif   

  30. #ifdef CONFIG_DRIVER_RALINK  

  31.     &wpa_driver_ralink_ops,  

  32. #endif   

  33. #ifdef CONFIG_DRIVER_OSX  

  34.     &wpa_driver_osx_ops,  

  35. #endif   

  36. #ifdef CONFIG_DRIVER_IPHONE  

  37.     &wpa_driver_iphone_ops,  

  38. #endif   

  39. #ifdef CONFIG_DRIVER_ROBOSWITCH  

  40.     &wpa_driver_roboswitch_ops,  

  41. #endif   

  42. #ifdef CONFIG_DRIVER_ATHEROS  

  43.     &wpa_driver_atheros_ops,  

  44. #endif   

  45. #ifdef CONFIG_DRIVER_NONE  

  46.     &wpa_driver_none_ops,  

  47. #endif   

  48.     NULL  

  49. };  

   具体选择哪一个driver,由wpa_supplicant的命令参数决定,如我的如下:
   在init.myboard.rc中定义:

 

[cpp] view plaincopy

  1. service wpa_supplicant /system/bin/wpa_supplicant \  

  2.     -Dwext -iwlan0 -c/data/misc/wifi/wpa_supplicant.conf  

  3.     #-Dnl80211 -iwlan0 -puse_p2p_group_interface=1 -e/data/misc/wifi/entropy.bin  

  4.     #   we will start as root and wpa_supplicant will switch to user wifi  

  5.     #   after setting up the capabilities required for WEXT  

  6.     #   user wifi  

  7.     #   group wifi inet keystore  

  8.     class main  

  9.     socket wpa_wlan0 dgram 660 wifi wifi  

  10.     disabled  

  11.     oneshot  

   由上可见,我的选择是wext, 即选择了:wpa_driver_wext_ops。具体选择在以下函数中实现,并最后保存在wpa_supplicant->driver中,以供在wpa_drv_scan中使用。

  首先需要讲解一下,在android4.0之后,wifi的工作方式基本都采用的是比较标准的nl80211方式,以前的wext方式现在使用的已经很少了,关于nl80211和wext的区别,小弟由于接触的少,所以简单的说两句(有错误的请各位大大指正啊,万谢!)

   wext:supplicant通过wext直接给wifi driver下命令,即不通过kernel,所以一般以wext工作的driver是不需要load cfg80211.ko的,这个cfg80211.ko就是kernel里面的wireless部分,主要对接supplicant和driver的。

   nl80211:supplicant的命令以nl80211的方式下给kernel,经过kernel再发送给driver,这样子做的好处是 supplicant和driver之间的通讯方式更加标准话,是以后的主流方式,我后面讲的driver都是以这种方式工作的。

[cpp] view plaincopy

  1. static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s,  

  2.                      const char *name)  

  3. {  

  4.     int i;  

  5.     size_t len;  

  6.     const char *pos, *driver = name;  

  7.   

  8.     if (wpa_s == NULL)  

  9.         return -1;  

  10.   

  11.        wpa_msg(wpa_s,MSG_ERROR,"***MY_WIFI:%s,name=%s\n",__FUNCTION__,name);  

  12.       

  13.     if (wpa_drivers[0] == NULL) {  

  14.         wpa_msg(wpa_s, MSG_ERROR, "No driver interfaces build into "  

  15.             "wpa_supplicant");  

  16.         return -1;  

  17.     }  

  18.   

  19.     if (name == NULL) {  

  20.           

  21.         wpa_s->driver = wpa_drivers[0];  

  22.         wpa_s->global_drv_priv = wpa_s->global->drv_priv[0];  

  23.         return 0;  

  24.     }  

  25.   

  26.     do {  

  27.         pos = os_strchr(driver, ',');  

  28.         if (pos)  

  29.             len = pos - driver;  

  30.         else  

  31.             len = os_strlen(driver);  

  32.   

  33.         for (i = 0; wpa_drivers[i]; i++) {  

  34.             if (os_strlen(wpa_drivers[i]->name) == len &&  

  35.                 os_strncmp(driver, wpa_drivers[i]->name, len) ==  

  36.                 0) {  

  37.                 wpa_s->driver = wpa_drivers[i];  // 根据name进行匹配,并最后保存到wpa_supplicant->dirver中  

  38.                 wpa_s->global_drv_priv =  

  39.                     wpa_s->global->drv_priv[i];  

  40.                 return 0;  

  41.             }  

  42.         }  

  43.   

  44.         driver = pos + 1;  

  45.     } while (pos);  

  46.   

  47.     wpa_msg(wpa_s, MSG_ERROR, "Unsupported driver '%s'", name);  

  48.     return -1;  

  49. }  

2. 接口操作函数实现

2.1 用户态实现

  用户态实现的操作函数如下:

  实现代码见:/external/wpa_supplicant_8/wpa_supplicant/src/drivers/driver_wext.c

 

[cpp] view plaincopy

  1. const struct wpa_driver_ops wpa_driver_wext_ops = {  

  2.     .name = "wext",  

  3.     .desc = "Linux wireless extensions (generic)",  

  4.     .get_bssid = wpa_driver_wext_get_bssid,  

  5.     .get_ssid = wpa_driver_wext_get_ssid,  

  6. #ifdef WAPI  

  7.     .set_wapi = wpa_driver_wext_set_wapi,  

  8. #endif  

  9.     .set_key = wpa_driver_wext_set_key,  

  10.     .set_countermeasures = wpa_driver_wext_set_countermeasures,  

  11.     .scan2 = wpa_driver_wext_scan,  

  12.     .get_scan_results2 = wpa_driver_wext_get_scan_results,  

  13.     .deauthenticate = wpa_driver_wext_deauthenticate,  

  14.     .disassociate = wpa_driver_wext_disassociate,  

  15.     .associate = wpa_driver_wext_associate,  

  16.     .init = wpa_driver_wext_init, // 初始ioctl socket, netlink socket  

  17.     .deinit = wpa_driver_wext_deinit,  

  18.     .add_pmkid = wpa_driver_wext_add_pmkid,  

  19.     .remove_pmkid = wpa_driver_wext_remove_pmkid,  

  20.     .flush_pmkid = wpa_driver_wext_flush_pmkid,  

  21.     .get_capa = wpa_driver_wext_get_capa,  

  22.     .set_operstate = wpa_driver_wext_set_operstate,  

  23.     .get_radio_name = wext_get_radio_name,  

  24. #ifdef ANDROID  

  25.     .signal_poll = wpa_driver_signal_poll,  

  26.     .driver_cmd = wpa_driver_wext_driver_cmd, // 对应驱动中的 cfg80211_wext_setpriv  

  27. #endif  

  28. };  

.driver_cmd处理以DRIVER开始的命令,如:

   DRIVER MACADDR

   DRIVER BTCOEXSCAN-STOP

   DRIVER RXFILTER-ADD 3

   DRIVER RXFILTER-START

   DRIVER RXFILTER-STOP

   DRIVER RXFILTER-REMOVE 2

   DRIVER RXFILTER-START

  DRIVER SETBAND 0

   DRIVER SCAN-ACTIVE

   DRIVER SCAN-PASSIVE

  执行流程如下所示:

   wpa_supplicant_ctrl_iface_process-> (根据命令字符串调用对应的函数)

    wpa_supplicant_driver_cmd->

     wpa_drv_driver_cmd->

      wpa_s->driver->driver_cmd->

       wpa_driver_wext_driver_cmd-> (User)

      ...

       cfg80211_wext_setpriv(Kernel)

2.2 Kernel态实现    

   Kernel态实现的操作函数如下:

   实现代码见:net/wireless/wext_compat.c

 

[cpp] view plaincopy

  1. static const iw_handler cfg80211_handlers[] = {  

  2.     [IW_IOCTL_IDX(SIOCGIWNAME)] = (iw_handler) cfg80211_wext_giwname,  

  3.     [IW_IOCTL_IDX(SIOCSIWFREQ)] = (iw_handler) cfg80211_wext_siwfreq,  

  4.     [IW_IOCTL_IDX(SIOCGIWFREQ)] = (iw_handler) cfg80211_wext_giwfreq,  

  5.     [IW_IOCTL_IDX(SIOCSIWMODE)] = (iw_handler) cfg80211_wext_siwmode,  

  6.     [IW_IOCTL_IDX(SIOCGIWMODE)] = (iw_handler) cfg80211_wext_giwmode,  

  7.     [IW_IOCTL_IDX(SIOCGIWRANGE)]    = (iw_handler) cfg80211_wext_giwrange,  

  8.     [IW_IOCTL_IDX(SIOCSIWAP)]   = (iw_handler) cfg80211_wext_siwap,  

  9.     [IW_IOCTL_IDX(SIOCGIWAP)]   = (iw_handler) cfg80211_wext_giwap,  

  10.     [IW_IOCTL_IDX(SIOCSIWMLME)] = (iw_handler) cfg80211_wext_siwmlme,  

  11.     [IW_IOCTL_IDX(SIOCSIWSCAN)] = (iw_handler) cfg80211_wext_siwscan,  

  12.     [IW_IOCTL_IDX(SIOCGIWSCAN)] = (iw_handler) cfg80211_wext_giwscan,  

  13.     [IW_IOCTL_IDX(SIOCSIWESSID)]    = (iw_handler) cfg80211_wext_siwessid,  

  14.     [IW_IOCTL_IDX(SIOCGIWESSID)]    = (iw_handler) cfg80211_wext_giwessid,  

  15.     [IW_IOCTL_IDX(SIOCSIWRATE)] = (iw_handler) cfg80211_wext_siwrate,  

  16.     [IW_IOCTL_IDX(SIOCGIWRATE)] = (iw_handler) cfg80211_wext_giwrate,  

  17.     [IW_IOCTL_IDX(SIOCSIWRTS)]  = (iw_handler) cfg80211_wext_siwrts,  

  18.     [IW_IOCTL_IDX(SIOCGIWRTS)]  = (iw_handler) cfg80211_wext_giwrts,  

  19.     [IW_IOCTL_IDX(SIOCSIWFRAG)] = (iw_handler) cfg80211_wext_siwfrag,  

  20.     [IW_IOCTL_IDX(SIOCGIWFRAG)] = (iw_handler) cfg80211_wext_giwfrag,  

  21.     [IW_IOCTL_IDX(SIOCSIWTXPOW)]    = (iw_handler) cfg80211_wext_siwtxpower,  

  22.     [IW_IOCTL_IDX(SIOCGIWTXPOW)]    = (iw_handler) cfg80211_wext_giwtxpower,  

  23.     [IW_IOCTL_IDX(SIOCSIWRETRY)]    = (iw_handler) cfg80211_wext_siwretry,  

  24.  ..........................

  25.   

  26. const struct iw_handler_def cfg80211_wext_handler = {  

  27.     .num_standard       = ARRAY_SIZE(cfg80211_handlers),  

  28.     .standard       = cfg80211_handlers,  

  29.     .get_wireless_stats = cfg80211_wireless_stats,  

  30. };  


2.3 用户态与Kernel态的交互

    用户态向Kernel态发送请求时,通过ioctl来实现。

   Kernel态向用户态发送事件通知,通过netlink来实现。

   其交互的初始化在wpa_driver_wext_init中实现,其代码如下:

 

[cpp] view plaincopy

  1.   

  2. void * wpa_driver_wext_init(void *ctx, const char *ifname) // 我的ifname为wlan0  

  3. {  

  4.     struct wpa_driver_wext_data *drv;  

  5.     struct netlink_config *cfg;  

  6.     struct rfkill_config *rcfg;  

  7.     char path[128];  

  8.     struct stat buf;  

  9.   

  10.         wpa_printf(MSG_ERROR,"***MY_WIFI:%s,ifname=%s\n",__FUNCTION__,ifname);  

  11.       

  12.     drv = os_zalloc(sizeof(*drv));  

  13.     if (drv == NULL)  

  14.         return NULL;  

  15.     drv->ctx = ctx;  

  16.     os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));  

  17.   

  18.     os_snprintf(path, sizeof(path), "/sys/class/net/%s/phy80211", ifname);  

  19.     if (stat(path, &buf) == 0) {  

  20.         wpa_printf(MSG_DEBUG, "WEXT: cfg80211-based driver detected");  

  21.         drv->cfg80211 = 1;  

  22.         wext_get_phy_name(drv);  

  23.     }  

  24.   

  25.     drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);  // 此drv->ioctl_sock用作为ioctl命令的fd  

  26.     if (drv->ioctl_sock < 0) {  

  27.         perror("socket(PF_INET,SOCK_DGRAM)");  

  28.         goto err1;  

  29.     }  

  30.   

  31.     cfg = os_zalloc(sizeof(*cfg));  

  32.     if (cfg == NULL)  

  33.         goto err1;  

  34.     cfg->ctx = drv;  

  35.     cfg->newlink_cb = wpa_driver_wext_event_rtm_newlink;  

  36.     cfg->dellink_cb = wpa_driver_wext_event_rtm_dellink;  

  37.     drv->netlink = netlink_init(cfg);  // 初始化netlink,并注册事件接收函数  

  38.     if (drv->netlink == NULL) {  

  39.         os_free(cfg);  

  40.         goto err2;  

  41.     }  

  42.   

  43.     rcfg = os_zalloc(sizeof(*rcfg));  

  44.   

其中参数ifname在/data/misc/wifi/wpa_supplicant.conf中被定义,如我的如下:

[cpp] view plaincopy

  1. update_config=1  

  2. ctrl_interface=wlan0  

  3. eapol_version=1  

  4. ap_scan=1  

  5. fast_reauth=1  

2.3.1 ioctl实现方案

   在用户态可简单执行一个ioctl(fd,cmd,...)命令即可。

   在Kernel态则是通过唯一的cmd (SIOCIWFIRST--SIOCIWLAST) 来进行区分,从而执行cfg80211_handlers中对应的函数。

   socket文件操作如下:

 

[cpp] view plaincopy

  1.   

  2.   

  3. static const struct file_operations socket_file_ops = {  

  4.     .owner =    THIS_MODULE,  

  5.     .llseek =   no_llseek,  

  6.     .aio_read = sock_aio_read,  

  7.     .aio_write =    sock_aio_write,  

  8.     .poll =     sock_poll,  

  9.     .unlocked_ioctl = sock_ioctl, // 这个就是被执行的ioctl  

  10. #ifdef CONFIG_COMPAT  

  11.     .compat_ioctl = compat_sock_ioctl,  

  12. #endif  

  13.     .mmap =     sock_mmap,  

  14.     .open =     sock_no_open,     

  15.     .release =  sock_close,  

  16.     .fasync =   sock_fasync,  

  17.     .sendpage = sock_sendpage,  

  18.     .splice_write = generic_splice_sendpage,  

  19.     .splice_read =  sock_splice_read,  

  20. };  

从sock_ioctl到iw_handler的执行注程如下所示:

 sock_ioctl->

  dev_ioctl->

   wext_handle_ioctl-> (把执行结果从kernel态copy到用户态)

    wext_ioctl_dispatch->

     wireless_process_ioctl->

       1) get_handler

       2) ioctl_standard_call (执行cmd指定的iw_handler,并返回结果) 

 

2.3.2 用户态初始化netlink

 

[cpp] view plaincopy

  1. struct netlink_data * netlink_init(struct netlink_config *cfg)  

  2. {  

  3.     struct netlink_data *netlink;  

  4.     struct sockaddr_nl local;  

  5.   

  6.     netlink = os_zalloc(sizeof(*netlink));  

  7.     if (netlink == NULL)  

  8.         return NULL;  

  9.   

  10.     netlink->cfg = cfg;  

  11.   

  12.     netlink->sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);  

  13.     if (netlink->sock < 0) {  

  14.         wpa_printf(MSG_ERROR, "netlink: Failed to open netlink "  

  15.                "socket: %s", strerror(errno));  

  16.         netlink_deinit(netlink);  

  17.         return NULL;  

  18.     }  

  19.   

  20.     os_memset(&local, 0, sizeof(local));  

  21.     local.nl_family = AF_NETLINK;  

  22.     local.nl_groups = RTMGRP_LINK;  

  23.     if (bind(netlink->sock, (struct sockaddr *) &local, sizeof(local)) < 0)  

  24.     {  

  25.         wpa_printf(MSG_ERROR, "netlink: Failed to bind netlink "  

  26.                "socket: %s", strerror(errno));  

  27.         netlink_deinit(netlink);  

  28.         return NULL;  

  29.     }  

  30.   

  31.     eloop_register_read_sock(netlink->sock, netlink_receive, netlink,  

  32.                  NULL);  

  33.   

  34.     return netlink;  

  35. }  

2.3.3 用户态netlink事件接收函数netlink_receive

 

[cpp] view plaincopy

  1. static void netlink_receive(int sock, void *eloop_ctx, void *sock_ctx)  

  2. {  

  3.     struct netlink_data *netlink = eloop_ctx;  

  4.     char buf[8192];  

  5.     int left;  

  6.     struct sockaddr_nl from;  

  7.     socklen_t fromlen;  

  8.     struct nlmsghdr *h;  

  9.     int max_events = 10;  

  10.   

  11. try_again:  

  12.     fromlen = sizeof(from);  

  13.     left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT, //从netlink读取事件  

  14.             (struct sockaddr *) &from, &fromlen);  

  15.     if (left < 0) {  

  16.         if (errno != EINTR && errno != EAGAIN)  

  17.             wpa_printf(MSG_INFO, "netlink: recvfrom failed: %s",  

  18.                    strerror(errno));  

  19.         return;  

  20.     }  

  21.   

  22.     h =

  23. }  

3. SCAN流程

wpa_supplicant_ctrl_iface_process-> ( buf 内容为SCAN )

 wpa_supplicant_req_scan->wpa_supplicant_scan->wpa_supplicant_trigger_scan->wpa_drv_scan->wpa_s->driver->scan2->wpa_driver_wext_scan-> (Request the driver to initiate scan)wpa_driver_wext_combo_scan->ioctl(drv->ioctl_sock, SIOCSIWPRIV, &iwr)-> (User)...cfg80211_wext_setpriv (cmd=CSCAN S)->cfg80211_wext_siwscan->rdev->ops->scan (cfg80211_ops mac80211_config_ops->scan)->ieee80211_scan-> ieee80211_request_scan->__ieee80211_start_scan->ieee80211_start_sw_scan-><1> drv_sw_scan_start->local->ops->sw_scan_start(ieee80211_ops ath9k_htc_ops->sw_scan_start)->ath9k_htc_sw_scan_start-> <2> ieee80211_hw_config-> (set power level at maximum rate for scanning)drv_config->local->ops->config( ieee80211_ops ath9k_htc_ops->config)-> ath9k_htc_config->ath9k_htc_setpower(priv,ATH9K_PM_AWAKE<3>  ieee80211_queue_delayed_work(&local->scan_work)->(注:INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work)) ieee80211_scan_work-> (根据local当前状态进行下一步工作,直到工作完成)__ieee80211_scan_completed-> (所有扫描的工作完成之后,调用此函数)drv_sw_scan_complete->local->ops->sw_scan_complete( ieee80211_ops ath9k_htc_ops->sw_scan_complete)ath9k_htc_sw_scan_complete


本文转载自:http://blog.sina.com.cn/s/blog_a6559d920101kcpn.html

共有 人打赏支持
s
粉丝 42
博文 202
码字总数 0
作品 0
深圳
高级程序员
wpa_supplicant与kernel交互

wpa_supplicant与kernel交互的操作,一般需要先明确驱动接口,以及用户态和kernel态的接口函数,以此来进行调用操作。这里分为4个步骤讨论。 1.首先需要明确指定的驱动接口。因为有较多的驱动...

sflfqx
2014/07/29
0
0
wpa_supplicant 初始化流程分析

启动命令 wpa supplicant 在启动时,启动命令可以带有很多参数,目前我们的启动命令如下: wpasupplicant /system/bin/wpasupplicant -Dwext -ieth0 -c/data/wifi/wpasupplicant.conf -f/dat...

sflfqx
2013/09/26
0
0
wpa_supplicant软件架构分析

struct socket 数据结构 interface network callback 目录(?)[+] 启动命令 wpa_supplicant 初始化流程 main函数 wpasupplicantinit函数 wpasupplicantadd_iface函数 wpasupplicantrun函数 Wp......

sflfqx
2013/09/18
0
0
wpa_supplicant代码初探收藏

wpa_supplicant代码初探收藏 这几天在尝试把wpa_supplicant移植到windows ce上,替换微软的WZC。先把源代码down下来,了解了一下大致的结构。 wpasupplicant运行的整个核心就是elooprun函数。...

sflfqx
2013/09/26
0
0
Android WiFi--系统架构

系统架构 Android WiFi系统引入了wpasupplicant,它的整个WiFi系统以wpasupplicant为核心来定义上层用户接口和下层驱动接口。整个WiFi系统架构如下图所示: 一切尽在上图中,下面将对每部分进...

sflfqx
2014/04/10
0
0

没有更多内容

加载失败,请刷新页面

加载更多

day96-20180923-英语流利阅读-待学习

英国王子也不看好人工智能,理由却和霍金不同 Daniel 2018-09-23 1.今日导读 2016 年 3 月 9 日至 15 日,世界围棋冠军李世石与谷歌研发的计算机围棋程序 AlphaGo 进行人机大战并以 1 比 4 ...

飞鱼说编程
45分钟前
1
0
今天在码云遇到一个很有意思的人 for Per.js

今天在码云遇到一个很有意思的人,他在我的Per.js项目下面评论了一句,大意为“你试试这句代码,看看速度到底是你快还是Vue快”【当然,这个评论被我手残不小心删掉了...】。 然后我就试了,...

Skyogo
50分钟前
24
0
Java -------- 首字母相关排序总结

Java 字符串数组首字母排序 字符串数组按首字母排序:(区分大小写) String[] strings = new String[]{"ba","aa","CC","Ba","DD","ee","dd"}; Arrays.sort(strings); for (int i ...

切切歆语
52分钟前
2
0
还在用 Git 的 -f 参数强推仓库,你这是在作死!

最近,美国一个程序员因为同事不写注释,代码不规范,最严重的是天天使用 git push -f 参数强行覆盖仓库,该程序员忍无可忍向四名同事开抢,其中一人情况危急!!! 不写注释、代码不规范是一...

红薯
今天
466
0
NPM报错终极大法

所有的错误基本上都跟node的版本相关 直接删除系统中的node 重新安装 sudo rm -rf /usr/local/{bin/{node,npm},lib/node_modules/npm,lib/node,share/man/*/node.*} 重新安装 $ n lts$ npm...

lilugirl
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部