wpa supplicant与kernel的接口

分享一下我老师大神的人工智能教程。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

               

1. 接口定义实现wpa_drivers

    wpa_drivers的定义如下:

struct wpa_driver_ops *wpa_drivers[] ={#ifdef CONFIG_DRIVER_WEXT &wpa_driver_wext_ops,  // 我的系统使用的这个老的接口#endif /* CONFIG_DRIVER_WEXT */#ifdef CONFIG_DRIVER_NL80211   // 现在流行的NL80211接口 &wpa_driver_nl80211_ops,#endif /* CONFIG_DRIVER_NL80211 */#ifdef CONFIG_DRIVER_HOSTAP &wpa_driver_hostap_ops,#endif /* CONFIG_DRIVER_HOSTAP */#ifdef CONFIG_DRIVER_MADWIFI &wpa_driver_madwifi_ops,#endif /* CONFIG_DRIVER_MADWIFI */#ifdef CONFIG_DRIVER_BROADCOM &wpa_driver_broadcom_ops,#endif /* CONFIG_DRIVER_BROADCOM */#ifdef CONFIG_DRIVER_BSD &wpa_driver_bsd_ops,#endif /* CONFIG_DRIVER_BSD */#ifdef CONFIG_DRIVER_NDIS &wpa_driver_ndis_ops,#endif /* CONFIG_DRIVER_NDIS */#ifdef CONFIG_DRIVER_WIRED &wpa_driver_wired_ops,#endif /* CONFIG_DRIVER_WIRED */#ifdef CONFIG_DRIVER_TEST &wpa_driver_test_ops,#endif /* CONFIG_DRIVER_TEST */#ifdef CONFIG_DRIVER_RALINK &wpa_driver_ralink_ops,#endif /* CONFIG_DRIVER_RALINK */#ifdef CONFIG_DRIVER_OSX &wpa_driver_osx_ops,#endif /* CONFIG_DRIVER_OSX */#ifdef CONFIG_DRIVER_IPHONE &wpa_driver_iphone_ops,#endif /* CONFIG_DRIVER_IPHONE */#ifdef CONFIG_DRIVER_ROBOSWITCH &wpa_driver_roboswitch_ops,#endif /* CONFIG_DRIVER_ROBOSWITCH */#ifdef CONFIG_DRIVER_ATHEROS &wpa_driver_atheros_ops,#endif /* CONFIG_DRIVER_ATHEROS */#ifdef CONFIG_DRIVER_NONE &wpa_driver_none_ops,#endif /* CONFIG_DRIVER_NONE */ NULL};


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

service wpa_supplicant /system/bin/wpa_supplicant \    -Dwext -iwlan0 -c/data/misc/wifi/wpa_supplicant.conf    #-Dnl80211 -iwlan0 -puse_p2p_group_interface=1 -e/data/misc/wifi/entropy.bin    #   we will start as root and wpa_supplicant will switch to user wifi    #   after setting up the capabilities required for WEXT    #   user wifi    #   group wifi inet keystore    class main    socket wpa_wlan0 dgram 660 wifi wifi    disabled    oneshot


     由上可见,我的选择是wext, 即选择了:wpa_driver_wext_ops。具体选择在以下函数中实现,并最后保存在wpa_supplicant->driver中,以供在wpa_drv_scan中使用。
static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s,         const char *name)int i; size_t len; const char *pos, *driver = name; if (wpa_s == NULL)  return -1;       wpa_msg(wpa_s,MSG_ERROR,"***MY_WIFI:%s,name=%s\n",__FUNCTION__,name);     if (wpa_drivers[0] == NULL) {  wpa_msg(wpa_s, MSG_ERROR, "No driver interfaces build into "   "wpa_supplicant");  return -1; } if (name == NULL) {  /* default to first driver in the list */  wpa_s->driver = wpa_drivers[0];  wpa_s->global_drv_priv = wpa_s->global->drv_priv[0];  return 0; } do {  pos = os_strchr(driver, ',');  if (pos)   len = pos - driver;  else   len = os_strlen(driver);  for (i = 0; wpa_drivers[i]; i++) {   if (os_strlen(wpa_drivers[i]->name) == len &&       os_strncmp(driver, wpa_drivers[i]->name, len) ==       0) {    wpa_s->driver = wpa_drivers[i];  // 根据name进行匹配,并最后保存到wpa_supplicant->dirver中    wpa_s->global_drv_priv =     wpa_s->global->drv_priv[i];    return 0;   }  }  driver = pos + 1; } while (pos); wpa_msg(wpa_s, MSG_ERROR, "Unsupported driver '%s'", name); return -1;}


2. 接口操作函数实现

2.1 用户态实现

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

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

const struct wpa_driver_ops wpa_driver_wext_ops = { .name = "wext", .desc = "Linux wireless extensions (generic)", .get_bssid = wpa_driver_wext_get_bssid, .get_ssid = wpa_driver_wext_get_ssid,#ifdef WAPI .set_wapi = wpa_driver_wext_set_wapi,#endif .set_key = wpa_driver_wext_set_key, .set_countermeasures = wpa_driver_wext_set_countermeasures, .scan2 = wpa_driver_wext_scan, .get_scan_results2 = wpa_driver_wext_get_scan_results, .deauthenticate = wpa_driver_wext_deauthenticate, .disassociate = wpa_driver_wext_disassociate, .associate = wpa_driver_wext_associate, .init = wpa_driver_wext_init, // 初始ioctl socket, netlink socket .deinit = wpa_driver_wext_deinit, .add_pmkid = wpa_driver_wext_add_pmkid, .remove_pmkid = wpa_driver_wext_remove_pmkid, .flush_pmkid = wpa_driver_wext_flush_pmkid, .get_capa = wpa_driver_wext_get_capa, .set_operstate = wpa_driver_wext_set_operstate, .get_radio_name = wext_get_radio_name,#ifdef ANDROID .signal_poll = wpa_driver_signal_poll, .driver_cmd = wpa_driver_wext_driver_cmd, // 对应驱动中的 cfg80211_wext_setpriv#endif};


.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

static const iw_handler cfg80211_handlers[] = { [IW_IOCTL_IDX(SIOCGIWNAME)] = (iw_handler) cfg80211_wext_giwname, [IW_IOCTL_IDX(SIOCSIWFREQ)] = (iw_handler) cfg80211_wext_siwfreq, [IW_IOCTL_IDX(SIOCGIWFREQ)] = (iw_handler) cfg80211_wext_giwfreq, [IW_IOCTL_IDX(SIOCSIWMODE)] = (iw_handler) cfg80211_wext_siwmode, [IW_IOCTL_IDX(SIOCGIWMODE)] = (iw_handler) cfg80211_wext_giwmode, [IW_IOCTL_IDX(SIOCGIWRANGE)] = (iw_handler) cfg80211_wext_giwrange, [IW_IOCTL_IDX(SIOCSIWAP)] = (iw_handler) cfg80211_wext_siwap, [IW_IOCTL_IDX(SIOCGIWAP)] = (iw_handler) cfg80211_wext_giwap, [IW_IOCTL_IDX(SIOCSIWMLME)] = (iw_handler) cfg80211_wext_siwmlme, [IW_IOCTL_IDX(SIOCSIWSCAN)] = (iw_handler) cfg80211_wext_siwscan, [IW_IOCTL_IDX(SIOCGIWSCAN)] = (iw_handler) cfg80211_wext_giwscan, [IW_IOCTL_IDX(SIOCSIWESSID)] = (iw_handler) cfg80211_wext_siwessid, [IW_IOCTL_IDX(SIOCGIWESSID)] = (iw_handler) cfg80211_wext_giwessid, [IW_IOCTL_IDX(SIOCSIWRATE)] = (iw_handler) cfg80211_wext_siwrate, [IW_IOCTL_IDX(SIOCGIWRATE)] = (iw_handler) cfg80211_wext_giwrate, [IW_IOCTL_IDX(SIOCSIWRTS)] = (iw_handler) cfg80211_wext_siwrts, [IW_IOCTL_IDX(SIOCGIWRTS)] = (iw_handler) cfg80211_wext_giwrts, [IW_IOCTL_IDX(SIOCSIWFRAG)] = (iw_handler) cfg80211_wext_siwfrag, [IW_IOCTL_IDX(SIOCGIWFRAG)] = (iw_handler) cfg80211_wext_giwfrag, [IW_IOCTL_IDX(SIOCSIWTXPOW)] = (iw_handler) cfg80211_wext_siwtxpower, [IW_IOCTL_IDX(SIOCGIWTXPOW)] = (iw_handler) cfg80211_wext_giwtxpower, [IW_IOCTL_IDX(SIOCSIWRETRY)] = (iw_handler) cfg80211_wext_siwretry, [IW_IOCTL_IDX(SIOCGIWRETRY)] = (iw_handler) cfg80211_wext_giwretry, [IW_IOCTL_IDX(SIOCSIWENCODE)] = (iw_handler) cfg80211_wext_siwencode, [IW_IOCTL_IDX(SIOCGIWENCODE)] = (iw_handler) cfg80211_wext_giwencode, [IW_IOCTL_IDX(SIOCSIWPOWER)] = (iw_handler) cfg80211_wext_siwpower, [IW_IOCTL_IDX(SIOCGIWPOWER)] = (iw_handler) cfg80211_wext_giwpower, [IW_IOCTL_IDX(SIOCSIWGENIE)] = (iw_handler) cfg80211_wext_siwgenie, [IW_IOCTL_IDX(SIOCSIWAUTH)] = (iw_handler) cfg80211_wext_siwauth, [IW_IOCTL_IDX(SIOCGIWAUTH)] = (iw_handler) cfg80211_wext_giwauth, [IW_IOCTL_IDX(SIOCSIWENCODEEXT)]= (iw_handler) cfg80211_wext_siwencodeext, [IW_IOCTL_IDX(SIOCSIWPMKSA)] = (iw_handler) cfg80211_wext_siwpmksa,        [IW_IOCTL_IDX(SIOCSIWPRIV)] = (iw_handler)cfg80211_wext_setpriv};const struct iw_handler_def cfg80211_wext_handler = { .num_standard  = ARRAY_SIZE(cfg80211_handlers), .standard  = cfg80211_handlers, .get_wireless_stats = cfg80211_wireless_stats,};


2.3 用户态与Kernel态的交互

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

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

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

/** * wpa_driver_wext_init - Initialize WE driver interface * @ctx: context to be used when calling wpa_supplicant functions, * e.g., wpa_supplicant_event() * @ifname: interface name, e.g., wlan0 * Returns: Pointer to private data, %NULL on failure */void * wpa_driver_wext_init(void *ctx, const char *ifname) // 我的ifname为wlan0struct wpa_driver_wext_data *drv; struct netlink_config *cfg; struct rfkill_config *rcfg; char path[128]; struct stat buf;        wpa_printf(MSG_ERROR,"***MY_WIFI:%s,ifname=%s\n",__FUNCTION__,ifname);     drv = os_zalloc(sizeof(*drv)); if (drv == NULL)  return NULL; drv->ctx = ctx; os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); os_snprintf(path, sizeof(path), "/sys/class/net/%s/phy80211", ifname); if (stat(path, &buf) == 0) {  wpa_printf(MSG_DEBUG, "WEXT: cfg80211-based driver detected");  drv->cfg80211 = 1;  wext_get_phy_name(drv); } drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);  // 此drv->ioctl_sock用作为ioctl命令的fd if (drv->ioctl_sock < 0) {  perror("socket(PF_INET,SOCK_DGRAM)");  goto err1; } cfg = os_zalloc(sizeof(*cfg)); if (cfg == NULL)  goto err1; cfg->ctx = drv; cfg->newlink_cb = wpa_driver_wext_event_rtm_newlink; cfg->dellink_cb = wpa_driver_wext_event_rtm_dellink; drv->netlink = netlink_init(cfg);  // 初始化netlink,并注册事件接收函数 if (drv->netlink == NULL) {  os_free(cfg);  goto err2; } rcfg = os_zalloc(sizeof(*rcfg)); if (rcfg == NULL)  goto err3; rcfg->ctx = drv; os_strlcpy(rcfg->ifname, ifname, sizeof(rcfg->ifname)); rcfg->blocked_cb = wpa_driver_wext_rfkill_blocked; rcfg->unblocked_cb = wpa_driver_wext_rfkill_unblocked; drv->rfkill = rfkill_init(rcfg); if (drv->rfkill == NULL) {  wpa_printf(MSG_DEBUG, "WEXT: RFKILL status not available");  os_free(rcfg); } drv->mlme_sock = -1;#ifdef ANDROID drv->errors = 0; drv->driver_is_started = TRUE; drv->skip_disconnect = 0; drv->bgscan_enabled = 0;#endif if (wpa_driver_wext_finish_drv_init(drv) < 0)  goto err3; wpa_driver_wext_set_auth_param(drv, IW_AUTH_WPA_ENABLED, 1); return drv;err3: rfkill_deinit(drv->rfkill); netlink_deinit(drv->netlink);err2: close(drv->ioctl_sock);err1: os_free(drv); return NULL;}

其中参数ifname在/data/misc/wifi/wpa_supplicant.conf中被定义,如我的如下:
update_config=1ctrl_interface=wlan0eapol_version=1ap_scan=1fast_reauth=1


2.3.1 ioctl实现方案

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

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

      socket文件操作如下:

/* * Socket files have a set of 'special' operations as well as the generic file ones. These don't appear * in the operation structures but are done directly via the socketcall() multiplexor. */static const struct file_operations socket_file_ops = { .owner = THIS_MODULE, .llseek = no_llseek, .aio_read = sock_aio_read, .aio_write = sock_aio_write, .poll =  sock_poll, .unlocked_ioctl = sock_ioctl, // 这个就是被执行的ioctl#ifdef CONFIG_COMPAT .compat_ioctl = compat_sock_ioctl,#endif .mmap =  sock_mmap, .open =  sock_no_open, /* special open code to disallow open via /proc */ .release = sock_close, .fasync = sock_fasync, .sendpage = sock_sendpage, .splice_write = generic_splice_sendpage, .splice_read = sock_splice_read,};

从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<cfg80211_handlers中定义的>,并返回结果) 


static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg)struct socket *sock; struct sock *sk; void __user *argp = (void __user *)arg; int pid, err; struct net *net; sock = file->private_data; sk = sock->sk; net = sock_net(sk); if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) {  err = dev_ioctl(net, cmd, argp); } else#ifdef CONFIG_WEXT_CORE if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {    err = dev_ioctl(net, cmd, argp); //执行dev_ioctl } else#endif        ... } return err;}

int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg)struct ifreq ifr; int ret; char *colon; /*  * See which interface the caller is talking about.  */ switch (cmd) { /*  * Unknown or private ioctl.  */ default:  /* Take care of Wireless Extensions */  if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST)   return wext_handle_ioctl(net, &ifr, cmd, arg); // 执行wext_handle_ioctl  return -ENOTTY; }}

int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,        void __user *arg)struct iw_request_info info = { .cmd = cmd, .flags = 0 }; int ret; ret = wext_ioctl_dispatch(net, ifr, cmd, &info,  // 执行wext_ioctl_dispatch      ioctl_standard_call,      ioctl_private_call); if (ret >= 0 &&     IW_IS_GET(cmd) &&     copy_to_user(arg, ifr, sizeof(struct iwreq))) // 把执行结果copy到用户空间  return -EFAULT; return ret;}

/* entry point from dev ioctl */static int wext_ioctl_dispatch(struct net *net, struct ifreq *ifr,          unsigned int cmd, struct iw_request_info *info,          wext_ioctl_func standard,          wext_ioctl_func private)int ret = wext_permission_check(cmd); if (ret)  return ret; dev_load(net, ifr->ifr_name); rtnl_lock(); ret = wireless_process_ioctl(net, ifr, cmd, info, standard, private); //执行wireless_process_ioctl rtnl_unlock(); return ret;}

static iw_handler get_handler(struct net_device *dev, unsigned int cmd)/* Don't "optimise" the following variable, it will crash */ unsigned int index;  /* *MUST* be unsigned */ const struct iw_handler_def *handlers = NULL;    //printk("***IDONG_WIFI:%s,cmd=0x%x\n",__FUNCTION__,cmd);#ifdef CONFIG_CFG80211_WEXT if (dev->ieee80211_ptr && dev->ieee80211_ptr->wiphy)  handlers = dev->ieee80211_ptr->wiphy->wext;#endif#ifdef CONFIG_WIRELESS_EXT if (dev->wireless_handlers)  handlers = dev->wireless_handlers;#endif if (!handlers)  return NULL/* Try as a standard command */ index = IW_IOCTL_IDX(cmd); if (index < handlers->num_standard)  return handlers->standard[index];#ifdef CONFIG_WEXT_PRIV /* Try as a private command */ index = cmd - SIOCIWFIRSTPRIV; if (index < handlers->num_private)  return handlers->private[index];#endif /* Not found */ return NULL;}

static int wireless_process_ioctl(struct net *net, struct ifreq *ifr,      unsigned int cmd,      struct iw_request_info *info,      wext_ioctl_func standard,      wext_ioctl_func private)struct iwreq *iwr = (struct iwreq *) ifr; struct net_device *dev; iw_handler handler; /* Permissions are already checked in dev_ioctl() before calling us.  * The copy_to/from_user() of ifr is also dealt with in there */ /* Make sure the device exist */ if ((dev = __dev_get_by_name(net, ifr->ifr_name)) == NULL)  return -ENODEV; /* A bunch of special cases, then the generic case...  * Note that 'cmd' is already filtered in dev_ioctl() with  * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */ if (cmd == SIOCGIWSTATS)  return standard(dev, iwr, cmd, info,    &iw_handler_get_iwstats);#ifdef CONFIG_WEXT_PRIV if (cmd == SIOCGIWPRIV && dev->wireless_handlers)  return standard(dev, iwr, cmd, info,    iw_handler_get_private);#endif /* Basic check */ if (!netif_device_present(dev))  return -ENODEV; /* New driver API : try to find the handler */ handler = get_handler(dev, cmd); if (handler) {  /* Standard and private are not the same */  if (cmd < SIOCIWFIRSTPRIV)   return standard(dev, iwr, cmd, info, handler); // 去执行对应的iw_handler  else if (private)   return private(dev, iwr, cmd, info, handler); } /* Old driver API : call driver ioctl handler */ if (dev->netdev_ops->ndo_do_ioctl)  return dev->netdev_ops->ndo_do_ioctl(dev, ifr, cmd); return -EOPNOTSUPP;}


2.3.2 用户态初始化netlink


struct netlink_data * netlink_init(struct netlink_config *cfg)struct netlink_data *netlink; struct sockaddr_nl local; netlink = os_zalloc(sizeof(*netlink)); if (netlink == NULL)  return NULL; netlink->cfg = cfg; netlink->sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (netlink->sock < 0) {  wpa_printf(MSG_ERROR, "netlink: Failed to open netlink "      "socket: %s", strerror(errno));  netlink_deinit(netlink);  return NULL; } os_memset(&local, 0, sizeof(local)); local.nl_family = AF_NETLINK; local.nl_groups = RTMGRP_LINK; if (bind(netlink->sock, (struct sockaddr *) &local, sizeof(local)) < 0) {  wpa_printf(MSG_ERROR, "netlink: Failed to bind netlink "      "socket: %s", strerror(errno));  netlink_deinit(netlink);  return NULL; } eloop_register_read_sock(netlink->sock, netlink_receive, netlink,     NULL); return netlink;}

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


static void netlink_receive(int sock, void *eloop_ctx, void *sock_ctx)struct netlink_data *netlink = eloop_ctx; char buf[8192]; int left; struct sockaddr_nl from; socklen_t fromlen; struct nlmsghdr *h; int max_events = 10;try_again: fromlen = sizeof(from); left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT, //从netlink读取事件   (struct sockaddr *) &from, &fromlen); if (left < 0) {  if (errno != EINTR && errno != EAGAIN)   wpa_printf(MSG_INFO, "netlink: recvfrom failed: %s",       strerror(errno));  return; } h = (struct nlmsghdr *) buf; while (NLMSG_OK(h, left)) {  switch (h->nlmsg_type) {  case RTM_NEWLINK:   netlink_receive_link(netlink, netlink->cfg->newlink_cb,          h);   break;  case RTM_DELLINK:   netlink_receive_link(netlink, netlink->cfg->dellink_cb,          h);   break;  }  h = NLMSG_NEXT(h, left); } if (left > 0) {  wpa_printf(MSG_DEBUG, "netlink: %d extra bytes in the end of "      "netlink message", left); } if (--max_events > 0) {  /*   * Try to receive all events in one eloop call in order to   * limit race condition on cases where AssocInfo event, Assoc   * event, and EAPOL frames are received more or less at the   * same time. We want to process the event messages first   * before starting EAPOL processing.   */  goto try_again; }}



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

                                           

• ieee80211_scan_work函数详细代码如下:                                      

void ieee80211_scan_work(struct work_struct *work)struct ieee80211_local *local =  container_of(work, struct ieee80211_local, scan_work.work); struct ieee80211_sub_if_data *sdata; unsigned long next_delay = 0bool aborted, hw_scan; mutex_lock(&local->mtx); sdata = local->scan_sdata; if (test_and_clear_bit(SCAN_COMPLETED, &local->scanning)) {  aborted = test_and_clear_bit(SCAN_ABORTED, &local->scanning);  goto out_complete; } if (!sdata || !local->scan_req)  goto out; if (local->scan_req && !local->scanning) {  struct cfg80211_scan_request *req = local->scan_req;  int rc;  local->scan_req = NULL;  local->scan_sdata = NULL;  rc = __ieee80211_start_scan(sdata, req);  if (rc) {   /* need to complete scan in cfg80211 */   local->scan_req = req;   aborted = true;   goto out_complete;  } else   goto out; } /*  * Avoid re-scheduling when the sdata is going away.  */ if (!ieee80211_sdata_running(sdata)) {  aborted = true;  goto out_complete; } /*  * as long as no delay is required advance immediately  * without scheduling a new work  */ do {  if (!ieee80211_sdata_running(sdata)) {   aborted = true;   goto out_complete;  }  switch (local->next_scan_state) {  case SCAN_DECISION:   /* if no more bands/channels left, complete scan */   if (local->scan_channel_idx >= local->scan_req->n_channels) {    aborted = false;    goto out_complete;   }   ieee80211_scan_state_decision(local, &next_delay);   break;  case SCAN_SET_CHANNEL:   ieee80211_scan_state_set_channel(local, &next_delay);   break;  case SCAN_SEND_PROBE:   ieee80211_scan_state_send_probe(local, &next_delay);   break;  case SCAN_LEAVE_OPER_CHANNEL:   ieee80211_scan_state_leave_oper_channel(local, &next_delay);   break;  case SCAN_ENTER_OPER_CHANNEL:   ieee80211_scan_state_enter_oper_channel(local, &next_delay);   break;  } } while (next_delay == 0); ieee80211_queue_delayed_work(&local->hw, &local->scan_work, next_delay); goto out;out_complete: hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning); __ieee80211_scan_completed(&local->hw, aborted, hw_scan);out: mutex_unlock(&local->mtx);}


                                         






           

分享一下我老师大神的人工智能教程。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

猜你喜欢

转载自blog.csdn.net/hddghhfd/article/details/87896279