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

1.首先需要明确指定的驱动接口。因为有较多的驱动接口可以使用,如wextnl80211等。指定了之后,才能调用相应接口的方法。

2.保存驱动接口

3.接口函数的实现(分为用户态和kernel)。系统已经定义了,我们只需找到定义的地方,了解有哪些函数。

4.交互

(a)用户态向kernel态发送请求(通过ioctl)

(b)kernel态向用户态发送事件通知(通过netlink)


1.首先需要明确指定的驱动接口

(1)查看init.XX.rc中指定的driver的命令参数;

(2)根据命令参数,在wpa_driver_ops *wpa_drivers[] 中查找对应接口。

wpa_drivers[]的定义是在[-->external/wpa_supplicant_8/src/drivers/drivers.c]


2.保存驱动接口

wpa_supplicant初始化过程中,在wpa_supplicant_init_iface方法中会调用wpa_supplicant_set_driver方法。该方法中又会调用select_driver方法。

static int select_driver(struct wpa_supplicant *wpa_s, int i)
{
    struct wpa_global *global = wpa_s->global;

if (wpa_drivers[i]->global_init && global->drv_priv[i] == NULL) { 
    //调用global_init方法,这与driver选择wext调用的流程不同了
        global->drv_priv[i] = wpa_drivers[i]->global_init();
        if (global->drv_priv[i] == NULL) {
            wpa_printf(MSG_ERROR, "Failed to initialize driver " 
                   "'%s'", wpa_drivers[i]->name); 
            return -1;
        }
    }  
// 根据name进行匹配,并最后保存到wpa_supplicant->dirver中
    wpa_s->driver = wpa_drivers[i];
    wpa_s->global_drv_priv = global->drv_priv[i];

    return 0;
}

 

 

3.接口操作函数实现

3.1用户态

代码:/external/wpa_supplicant_8/wpa_supplicant/src/drivers/driver_nl80211.c

const struct wpa_driver_ops wpa_driver_nl80211_ops = {
    .name = "nl80211",
    .desc = "Linux nl80211/cfg80211",
    .get_bssid = wpa_driver_nl80211_get_bssid,
    .get_ssid = wpa_driver_nl80211_get_ssid,
    .set_key = wpa_driver_nl80211_set_key,
    .scan2 = wpa_driver_nl80211_scan,
    .sched_scan = wpa_driver_nl80211_sched_scan,
    .stop_sched_scan = wpa_driver_nl80211_stop_sched_scan,
    .get_scan_results2 = wpa_driver_nl80211_get_scan_results,
    .deauthenticate = wpa_driver_nl80211_deauthenticate,
    .disassociate = wpa_driver_nl80211_disassociate,
    .authenticate = wpa_driver_nl80211_authenticate,
    .associate = wpa_driver_nl80211_associate,
    .global_init = nl80211_global_init,
    .global_deinit = nl80211_global_deinit,
    .init2 = wpa_driver_nl80211_init,
    .deinit = wpa_driver_nl80211_deinit,
    .get_capa = wpa_driver_nl80211_get_capa,
    .set_operstate = wpa_driver_nl80211_set_operstate,
    .set_supp_port = wpa_driver_nl80211_set_supp_port,
    .set_country = wpa_driver_nl80211_set_country,
    .set_ap = wpa_driver_nl80211_set_ap,
    .if_add = wpa_driver_nl80211_if_add,
    .if_remove = wpa_driver_nl80211_if_remove,
    .send_mlme = wpa_driver_nl80211_send_mlme,
    .get_hw_feature_data = wpa_driver_nl80211_get_hw_feature_data,
    .sta_add = wpa_driver_nl80211_sta_add,
    .sta_remove = wpa_driver_nl80211_sta_remove,
    .hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol,
#ifdef ANDROID_QCOM_PATCH
    .hapd_set_countermeasures = wpa_driver_nl80211_set_countermeasures,
#endif
    .sta_set_flags = wpa_driver_nl80211_sta_set_flags,
#ifdef HOSTAPD
    .hapd_init = i802_init,
    .hapd_deinit = i802_deinit,
    .set_wds_sta = i802_set_wds_sta,
#endif /* HOSTAPD */
#if defined(HOSTAPD) || defined(CONFIG_AP)
    .get_seqnum = i802_get_seqnum,
    .flush = i802_flush,
    .read_sta_data = i802_read_sta_data,
    .get_inact_sec = i802_get_inact_sec,
    .sta_clear_stats = i802_sta_clear_stats,
    .set_rts = i802_set_rts,
    .set_frag = i802_set_frag,
    .set_tx_queue_params = i802_set_tx_queue_params,
    .set_sta_vlan = i802_set_sta_vlan,
    .sta_deauth = i802_sta_deauth,
    .sta_disassoc = i802_sta_disassoc,
#endif /* HOSTAPD || CONFIG_AP */
    .set_freq = i802_set_freq,
    .send_action = wpa_driver_nl80211_send_action,
    .send_action_cancel_wait = wpa_driver_nl80211_send_action_cancel_wait,
    .remain_on_channel = wpa_driver_nl80211_remain_on_channel,
    .cancel_remain_on_channel =
    wpa_driver_nl80211_cancel_remain_on_channel,
    .probe_req_report = wpa_driver_nl80211_probe_req_report,
    .deinit_ap = wpa_driver_nl80211_deinit_ap,
    .resume = wpa_driver_nl80211_resume,
    .send_ft_action = nl80211_send_ft_action,
    .signal_monitor = nl80211_signal_monitor,
    .signal_poll = nl80211_signal_poll,
    .send_frame = nl80211_send_frame,
    .shared_freq = wpa_driver_nl80211_shared_freq,
    .set_param = nl80211_set_param,
    .get_radio_name = nl80211_get_radio_name,
    .add_pmkid = nl80211_add_pmkid,
    .remove_pmkid = nl80211_remove_pmkid,
    .flush_pmkid = nl80211_flush_pmkid,
    .set_rekey_info = nl80211_set_rekey_info,
    .poll_client = nl80211_poll_client,
    .set_p2p_powersave = nl80211_set_p2p_powersave,
#ifdef CONFIG_TDLS
    .send_tdls_mgmt = nl80211_send_tdls_mgmt,
    .tdls_oper = nl80211_tdls_oper,
#endif /* CONFIG_TDLS */
#ifdef ANDROID_P2P
    .set_noa = wpa_driver_set_p2p_noa,
#endif
#ifdef ANDROID
    .driver_cmd = wpa_driver_nl80211_driver_cmd, //处理DRIVER开头的命令
#endif
};

psdriver_cmd用于处理DRIVER的命令,调用流程如下: 

wpa_supplicant_ctrl_iface_process-> (根据命令字符串调用对应的函数)
wpa_supplicant_driver_cmd->
wpa_drv_driver_cmd->
wpa_s->driver->driver_cmd->
wpa_driver_nl80211_driver_cmd -> (User)
...
cfg80211...

 

 

3.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,
};

const struct iw_handler_def cfg80211_wext_handler = {
    .num_standard       = ARRAY_SIZE(cfg80211_handlers), 
    .standard       = cfg80211_handlers,
    .get_wireless_stats = cfg80211_wireless_stats,
};

 

4.用户态和kernel态交互

4.1初始化

首先说明下用户态和kernel态交互的方式,如下所述:

a.用户态向kernel态发送请求时,通过ioctl来实现

b.kernel态向用户态发送事件通知,通过netlink实现

 

交互的初始化有两部分组成:nl80211_global_initwpa_driver_nl80211_init方法。以上a/b两点中ioctlnetlink是在nl80211_global_init方法中创建。

(1) nl80211_global_init方法

因为在”2.保存驱动接口”,select_driver方法中调用了global_init方法(会根据用户态的结构体wpa_driver_nl80211_ops中查找对应方法,即nl80211_global_init)

static void * nl80211_global_init(void)
{
    struct nl80211_global *global;
    struct netlink_config *cfg;

    global = os_zalloc(sizeof(*global));
    if (global == NULL)
        return NULL;
    global->ioctl_sock = -1;
    dl_list_init(&global->interfaces);
    global->if_add_ifindex = -1;

    cfg = os_zalloc(sizeof(*cfg)); 
    if (cfg == NULL)
        goto err;

    cfg->ctx = global;
    cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink;
    cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink;
    global->netlink = netlink_init(cfg); //初始化netlink,并注册事件接收函数 
    if (global->netlink == NULL) {     
        os_free(cfg);
        goto err;
    }  

    if (wpa_driver_nl80211_init_nl_global(global) < 0)                                                                                                                   
        goto err;
// 此global->ioctl_sock用作为ioctl命令的fd
    global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
    if (global->ioctl_sock < 0) {      
        perror("socket(PF_INET,SOCK_DGRAM)");
        goto err;
    }  

    return global;

err:
    nl80211_global_deinit(global);
    return NULL;
}

nl80211_global_init方法中,有两条关键语句:

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

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

 

分析以上两句:

(a)netlink_init方法中创建了一个socket,并添加到eloop_run方法中的rfds中。用于从kernel态发送事件给用户态

netlink->sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
......
eloop_register_read_sock(netlink->sock, netlink_receive, netlink,NULL); 

(b)socket用于从用户态发送请求给kernel

 

(2)wpa_driver_nl80211_init方法

wpa_supplicant_init_iface方法中有语句:

if (wpa_supplicant_set_driver(wpa_s, driver) < 0)
    return -1;
wpa_s->drv_priv = wpa_drv_init(wpa_s, wpa_s->ifname);

在设置完驱动后,会调用wpa_drv_init方法,其方法体中会调用init2方法,即wpa_driver_nl80211_init。该方法用来Initialize nl80211 driver interface.

 

4.2 用户态和kernel态交互之ioctl实现

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


先看下socket.c文件

/*
 *  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_ioctlkernel态调用iw_handler的执行流程如下:

sock_ioctl-> (kernel/net/socket.c)
  dev_ioctl-> (kernel/net/core/dev.c)
    下面的方法都在/net/wireless/wext-core.c中
    wext_handle_ioctl-> (把执行结果从kernel态copy到用户态)
      wext_ioctl_dispatch->(参数包括cmd/ioctl_standard_call/ioctl_private_call)
        wireless_process_ioctl->
          get_handler->  (根据cmd来判断调用standard或是private,即ioctl_standard_call或是ioctl_private_call方法)
      ioctl_standard_call (执行cmd指定的iw_handler<cfg80211_handlers中定义的>,并返回结果)

 

这样就完成了”通过ioctl,用户态向kernel态发送请求”。

这个流程的代码稍后贴出。

 1 /*
 2  *    With an ioctl, arg may well be a user mode pointer, but we don't know
 3  *    what to do with it - that's up to the protocol still.
 4  */
 5 
 6 static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg)
 7 {
 8     struct socket *sock;
 9     struct sock *sk;
10     void __user *argp = (void __user *)arg;
11     int pid, err;
12     struct net *net;
13 
14     sock = file->private_data;
15     sk = sock->sk;
16     net = sock_net(sk);
17     if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) {
18         err = dev_ioctl(net, cmd, argp);
19     } else
20 #ifdef CONFIG_WEXT_CORE
21     if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {
22         err = dev_ioctl(net, cmd, argp);
23     } else
24 #endif
25         switch (cmd) {
26         case FIOSETOWN:
27         case SIOCSPGRP:
28             err = -EFAULT;
29             if (get_user(pid, (int __user *)argp))
30                 break;
31             err = f_setown(sock->file, pid, 1);
32             break;
33         case FIOGETOWN:
34         case SIOCGPGRP:
35             err = put_user(f_getown(sock->file),
36                        (int __user *)argp);
37             break;
38         case SIOCGIFBR:
39         case SIOCSIFBR:
40         case SIOCBRADDBR:
41         case SIOCBRDELBR:
42             err = -ENOPKG;
43             if (!br_ioctl_hook)
44                 request_module("bridge");
45 
46             mutex_lock(&br_ioctl_mutex);
47             if (br_ioctl_hook)
48                 err = br_ioctl_hook(net, cmd, argp);
49             mutex_unlock(&br_ioctl_mutex);
50             break;
51         case SIOCGIFVLAN:
52         case SIOCSIFVLAN:
53             err = -ENOPKG;
54             if (!vlan_ioctl_hook)
55                 request_module("8021q");
56 
57             mutex_lock(&vlan_ioctl_mutex);
58             if (vlan_ioctl_hook)
59                 err = vlan_ioctl_hook(net, argp);
60             mutex_unlock(&vlan_ioctl_mutex);
61             break;
62         case SIOCADDDLCI:
63         case SIOCDELDLCI:
64             err = -ENOPKG;
65             if (!dlci_ioctl_hook)
66                 request_module("dlci");
67 
68             mutex_lock(&dlci_ioctl_mutex);
69             if (dlci_ioctl_hook)
70                 err = dlci_ioctl_hook(cmd, argp);
71             mutex_unlock(&dlci_ioctl_mutex);
72             break;
73         default:
74             err = sock_do_ioctl(net, sock, cmd, arg);
75             break;
76         }
77     return err;
78 }
sock_ioctl

相关文章:

  • 2022-12-23
  • 2021-05-03
  • 2021-08-14
  • 2022-12-23
  • 2022-02-05
  • 2022-12-23
猜你喜欢
  • 2021-11-21
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-05-15
  • 2022-12-23
相关资源
相似解决方案