<menu id="w8yyk"><menu id="w8yyk"></menu></menu>
  • <dd id="w8yyk"><nav id="w8yyk"></nav></dd>
    <menu id="w8yyk"></menu>
    <menu id="w8yyk"><code id="w8yyk"></code></menu>
    <menu id="w8yyk"></menu>
    <xmp id="w8yyk">
    <xmp id="w8yyk"><nav id="w8yyk"></nav>
  • 網站首頁 > 物聯資訊 > 技術分享

    WEXT driver的執行過程實現(iwpriv部分/softapcontroller)

    2016-09-28 00:00:00 廣州睿豐德信息科技有限公司 閱讀
    睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接

    之前在看wifi driver源代碼時一直有一個疑惑就是net dev的wireless_handlers中(WEXT類型的接口)提供兩個iw_handler接口,怎么知道上層是調用的是private中的函數還是standard中的SIOCSIWPRIV接口和SIOCGIWPRIV接口。

    問Wifi的FAE,人家也不清楚,后來沒辦法只好在源代碼中找,現在終于有點頭緒與大家分享一下。

    android 中有個system/netd/目錄,在netd下有個softapController.cpp文件實際上該文件實現了程序iwpriv的功能,那么這個程序是干嘛的呢?嘿嘿從名字就可看出啦是給softap下control 命令的。至于這些命令從哪里來,待后續有機會再與大家分享netd部分時再討論。

     

    分析代碼的從入口函數開始,構造函數

    SoftapController::SoftapController()

    mSock = socket(AF_INET,SOCK_DGRAM, 0); //socket調用,這個我們之前有分析過,這個mSock很重要,這就是socket關聯的文件描述符接口,上層通過該接口與內核溝通。

    其它函數除了getPrivFuncNum外基本都是開給上層的函數接口,用于和底層溝通。我們就分析打開softap執行的第一個函數startDriver

    fnum = getPrivFuncNum(iface,"START");//函數用START作為參數,并返回該函數在driver中private中的第幾個

    ret = ioctl(mSock, fnum, &wrq);//執行指定的(”START”所對應的)程序

     

    getPrivFuncNum函數

    strncpy(wrq.ifr_name, iface, sizeof(wrq.ifr_name));//指定net device 比如wlan0/eth0

        wrq.u.data.pointer = mBuf;

        wrq.u.data.length = sizeof(mBuf) /sizeof(struct iw_priv_args);

        wrq.u.data.flags = 0;

        if ((ret = ioctl(mSock,SIOCGIWPRIV, &wrq)) < 0) {//獲得driver private handler的iw_priv_args

            LOGE("SIOCGIPRIV failed: %d",ret);

            return ret;

        }

        priv_ptr = (struct iw_priv_args*)wrq.u.data.pointer;

        for(i=0;(i < wrq.u.data.length);i++) {

            if (strcmp(priv_ptr[i].name, fname) ==0)//找出指定CMD

                return priv_ptr[i].cmd;

    }

    之前看這段代碼時真是困惑死了,SIOCGIWPRIV明明是standard提供的一個標準接口且在我要調用的wifi driver中并沒有實現怎么會調用結果是獲得private 的iw_priv_args,目前我先將該疑問留著到后面自然會明白。

     

    如下我只分析ioctl(mSock, SIOCGIWPRIV,&wrq)的流程,其它的ioctl流程基本一致只是過程中調用不同的函數。

     

     

    如上調用實際上該函數最終通過系統調用調用到kernel space.如下所示

    kernel/fs/Ioctl.c

    SYSCALL_DEFINE3(ioctl, unsigned int, fd,unsigned int, cmd, unsigned long, arg)

    {

    ……………………………………………………………………..

             error= do_vfs_ioctl(filp, fd, cmd, arg);//調用虛擬文件系統的ioctl

    ……………………………………………………………..

    }

    如上系統調用ioctl

    int do_vfs_ioctl(struct file *filp,unsigned int fd, unsigned int cmd,

                  unsigned long arg)

    switch (cmd) {

    …………………………………………..

    default:

                       if(S_ISREG(filp->f_path.dentry->d_inode->i_mode))

                                error= file_ioctl(filp, cmd, arg);

                       else

                                error= vfs_ioctl(filp, cmd, arg);

                       break;

     

    staticlong vfs_ioctl(struct file *filp, unsigned int cmd,

                             unsigned long arg)

    {

             int error = -ENOTTY;

     

             if (!filp->f_op)

                       goto out;

     

             if (filp->f_op->unlocked_ioctl) {

                       error = filp->f_op->unlocked_ioctl(filp, cmd, arg);//此處調用的文件描述符接口在創建socket時init_file中賦值file->f_op = fop;

                       if (error == -ENOIOCTLCMD)

                                error = -EINVAL;

                       goto out;

    在本例中如上實際上調用了socket的文件描述符,該描述符在創建socket時就提供如“android基于Socket的系統調用實現”中描述。

    socket_file_ops. unlocked_ioctl = sock_ioctl

     

    如下列出部分commond的宏定義,具體在kernel/include/linux/Wireless.h中定義。

    #define SIOCGIWPRIV 0x8B0D

    #define SIOCIWFIRSTPRIV 0x8BE0//第一個privatecommand對應位址

    #define SIOCIWLASTPRIV 0x8BFF

    #define SIOCIWFIRST 0x8B00

    #define SIOCIWLAST SIOCIWLASTPRIV 

     

    static longsock_ioctl(struct file *file, unsigned cmd, unsigned long arg)

    #ifdef CONFIG_WIRELESS_EXT

             if(cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {// 很明顯SIOCGIWPRIV是在條件之內的。

                       err= dev_ioctl(net, cmd, argp);

             }else

    #endif

     

    kernel/net/core/Dev.c

    int dev_ioctl(struct net*net, unsigned int cmd, void __user *arg)

    /* Take care of Wireless Extensions */

                       if(cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST)

                                return wext_handle_ioctl(net, &ifr, cmd, arg);

     

    kernel/net/wireless/Wext.c

    intwext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,

                             void __user *arg)

             ret= wext_ioctl_dispatch(net, ifr, cmd, &info,

                                          ioctl_standard_call,//調用執行driver提供的standard handler

                                           ioctl_private_call);// 調用執行driver提供的private handler

             if(ret >= 0 &&

                 IW_IS_GET(cmd) &&

                 copy_to_user(arg, ifr, sizeof(structiwreq)))

     

    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)

    dev_load(net, ifr->ifr_name);//根據名字得到net

    rtnl_lock();

             ret= wireless_process_ioctl(net, ifr, cmd, info, standard, private);

             rtnl_unlock();

     

    void dev_load(struct net *net, const char*name)

    {

             structnet_device *dev;

     

             read_lock(&dev_base_lock);

             dev= __dev_get_by_name(net, name);

             read_unlock(&dev_base_lock);

     

             if(!dev && capable(CAP_NET_ADMIN))

                       request_module("%s",name);

    }

    //dev_load通過name獲取net的dev,name就是softapcontroller.cpp中getPrivFuncNum的第一個參數iface

     

    static int wireless_process_ioctl(structnet *net, struct ifreq *ifr,

                                           unsigned int cmd,

                                           struct iw_request_info *info,

                                           wext_ioctl_func standard,

                                           wext_ioctl_func private)

    if(cmd == SIOCGIWSTATS)

                       return standard(dev, iwr,cmd, info,

                                         &iw_handler_get_iwstats);//get status,和SIOCGIWPRIV一樣是個特殊的command,從代碼跟下去看,wifidriver提供了指定接口。

     

             if (cmd == SIOCGIWPRIV &&dev->wireless_handlers)

                       return standard(dev, iwr, cmd,info,

                                         &iw_handler_get_private); //get private handle的信息(句柄,參數等)

     

    static int ioctl_standard_call(structnet_device *  dev,

                                       struct iwreq                 *iwr,

                                       unsigned int                 cmd,

                                       struct iw_request_info      *info,

                                       iw_handler                   handler)

    descr = &(standard_ioctl[cmd- SIOCIWFIRST]);//獲得指定cmd的一些信息如下有描述該結構體數組

     

             /*Check if we have a pointer to user space data or not */

             if(descr->header_type != IW_HEADER_TYPE_POINT){

     

                       /*No extra arguments. Trivial to handle */

                       ret= handler(dev, info, &(iwr->u), NULL);

     

                       /*Generate an event to notify listeners of the change */

                       if((descr->flags & IW_DESCR_FLAG_EVENT) &&

                          ((ret== 0) || (ret == -EIWCOMMIT)))

                                wireless_send_event(dev,cmd, &(iwr->u), NULL);

             }else {// SIOCGIWPRIV調用下面的函數,其中handler為iw_handler_get_private

                       ret= ioctl_standard_iw_point(&iwr->u.data, cmd, descr,

                                                         handler,dev, info);

             }

     

    static const struct iw_ioctl_description standard_ioctl[] = {

             [SIOCSIWCOMMIT  - SIOCIWFIRST] = {

                       .header_type   = IW_HEADER_TYPE_NULL,

             },

    -----------------------------------省略號-----------------------------------------------------

    [SIOCGIWPRIV          -SIOCIWFIRST] = { /* (handled directly by us) *///看見原注釋沒,實際作用是獲得driver中提供的private handle的個數及對應cmd的位置,以便調用到指定private handle。

                       .header_type   = IW_HEADER_TYPE_POINT,

                       .token_size      = sizeof(struct iw_priv_args),

                       .max_tokens    = 16,

                       .flags                  = IW_DESCR_FLAG_NOMAX,

             },

             [SIOCSIWSTATS         - SIOCIWFIRST] = {

                       .header_type   = IW_HEADER_TYPE_NULL,

             },

             [SIOCGIWSTATS        -SIOCIWFIRST] = { /* (handled directly by us) */ //get status command

                       .header_type   = IW_HEADER_TYPE_POINT,

                       .token_size      = 1,

                       .max_tokens    = sizeof(struct iw_statistics),

                       .flags                  = IW_DESCR_FLAG_DUMP,

             },

    -----------------------------------省略號-----------------------------------------------------

     

     

    static int ioctl_standard_iw_point(structiw_point *iwp, unsigned int cmd,

                                            const struct iw_ioctl_description *descr,

                                            iw_handler handler, struct net_device *dev,

                                            struct iw_request_info *info)

    err = handler(dev,info, (union iwreq_data *) iwp, extra);

     

     

    /*---------------------------------------------------------------- */

    /*

     * Standard Wireless Handler : get iwpriv definitions

     * Export the driver private handler definition

     * They will be picked up by tools like iwpriv...

     */

    static int iw_handler_get_private(structnet_device *           dev,

                                           struct iw_request_info *     info,

                                           union iwreq_data *               wrqu,

                                           char *                     extra)

    {

             /*Check if the driver has something to export */

             if((dev->wireless_handlers->num_private_args == 0) ||

                (dev->wireless_handlers->private_args== NULL))

                       return-EOPNOTSUPP;

     

             /*Check if there is enough buffer up there */

             if(wrqu->data.length < dev->wireless_handlers->num_private_args) {

                       /*User space can't know in advance how large the buffer

                        * needs to be. Give it a hint, so that we cansupport

                        * any size buffer we want somewhatefficiently... */

                       wrqu->data.length= dev->wireless_handlers->num_private_args;

                       return-E2BIG;

             }

     

             /* Set the number of available ioctls. */

             wrqu->data.length =dev->wireless_handlers->num_private_args;

     

             /* Copy structure to the user buffer. */

             memcpy(extra, dev->wireless_handlers->private_args,

                    sizeof(structiw_priv_args) * wrqu->data.length);

     

             return0;

    }

     

    如下為某wifi driver中定義的wext接口

    const struct iw_handler_defwl_iw_handler_def =

    {

             .num_standard= ARRAYSIZE(wl_iw_handler),

             .standard= (iw_handler *) wl_iw_handler,

             .num_private= ARRAYSIZE(wl_iw_priv_handler),

             .num_private_args = ARRAY_SIZE(wl_iw_priv_args),

             .private= (iw_handler *)wl_iw_priv_handler,

             .private_args = (void *) wl_iw_priv_args,

     

    #if WIRELESS_EXT >= 19

             get_wireless_stats:dhd_get_wireless_stats,// SIOCGIWSTATS執行的接口

    #endif

             };

    #endif

     

    至此可知道SIOCGIWPRIV實際上是將iface作為net設備名所對應的driver num_private_args及private_args傳給上層。接下來再調用對應的privatehandler中的函數.

    如start ioctl_private_call

    #if WIRELESS_EXT > 12

    static const iw_handlerwl_iw_priv_handler[] = {

             NULL,//SIOCIWFIRSTPRIV+0

             (iw_handler)wl_iw_set_active_scan,//SIOCIWFIRSTPRIV+1

             NULL,

             (iw_handler)wl_iw_get_rssi,//SIOCIWFIRSTPRIV+3

             NULL,

             (iw_handler)wl_iw_set_passive_scan,//SIOCIWFIRSTPRIV+5

             NULL,

             (iw_handler)wl_iw_get_link_speed,//SIOCIWFIRSTPRIV+7

             NULL,

             (iw_handler)wl_iw_get_macaddr,//SIOCIWFIRSTPRIV+9

             NULL,

             (iw_handler)wl_iw_control_wl_off,//SIOCIWFIRSTPRIV+11

             NULL,

             (iw_handler)wl_iw_control_wl_on,//SIOCIWFIRSTPRIV+13 所以調用start就是調用driver中該函數。

    #ifdef SOFTAP      

     

            

             NULL,

             (iw_handler)iwpriv_set_ap_config,

     

            

            

             NULL,

             (iw_handler)iwpriv_get_assoc_list,

     

            

             NULL,

             (iw_handler)iwpriv_set_mac_filters,

     

            

             NULL,

             (iw_handler)iwpriv_en_ap_bss,

     

            

             NULL,

             (iw_handler)iwpriv_wpasupp_loop_tst,

            

             NULL,

             (iw_handler)iwpriv_softap_stop,

            

             NULL,

             (iw_handler)iwpriv_fw_reload,

    #endif

    #if defined(CSCAN)

            

             NULL,

             (iw_handler)iwpriv_set_cscan

    #endif     

    };

     

    //start command在如下中定義。

    static const struct iw_priv_argswl_iw_priv_args[] =

    {

    …………………………………………………………………………………………….

             {

                       WL_IW_SET_START,//start 對應command,該command在wifi driver中有定義位址,可根據SIOCIWFIRSTPRIV(第一個privatecmd位址)來計算偏移。該driver中定義:#define WL_IW_SET_START                            (SIOCIWFIRSTPRIV+13)

                       0,

                       IW_PRIV_TYPE_CHAR| IW_PRIV_SIZE_FIXED | MAX_WX_STRING,

                       "START"

             },

     

     

    from:http://blog.csdn.net/zjjdyb/article/details/20993117

    RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成
    最近免费观看高清韩国日本大全