<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>
  • 網站首頁 > 物聯資訊 > 技術分享

    Iwpriv工作流程及常用命令使用之二

    2016-09-28 00:00:00 廣州睿豐德信息科技有限公司 閱讀
    睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接 iwpriv工具通過ioctl動態獲取相應無線網卡驅動的private_args所有擴展參數 iwpriv是處理下面的wlan_private_args的所有擴展命令,iwpriv的實現上,是這樣的,
    =>main
    =>set_private
    =>iw_get_priv_info獲取wireless網卡所能處理的所有wlan_private_args類型. dev_ioctl
    =>wext_handle_ioctl
    =>wireless_process_ioctl
        if (cmd == SIOCGIWPRIV && dev->wireless_handlers)
            return ioctl_standard_call(dev, ifr, cmd,
                         &iw_handler_get_private);
    static int ioctl_standard_call(struct net_device *    dev,
                 struct ifreq *        ifr,
                 unsigned int        cmd,
                 iw_handler        handler)
    {
        ...
            /* Call the handler */
            ret = handler(dev, &info, &(iwr->u), extra);
                if (user_length < iwr->u.data.length) {
                    kfree(extra);
                    return -E2BIG;
    //通知iwpriv,本wifi網卡對應的private命令還沒有完,還有,這樣iwpriv將會繼續
    //maxpriv默認為16,即將以16個為一組,一組一組的從wifi網卡驅動讀取該網卡所能支持的所有private_args參數
    //newpriv = realloc(priv, maxpriv * sizeof(priv[0]));繼續申請,繼續拷貝,知道將wifi網卡自定義的wlan_private_args參數全部
    //傳出到iwpriv為止.
                }
        ...
    }
        /* 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 ioctl_standard_call(dev, ifr, cmd, handler);
            else //如果有對應的handler,那么處理iwpriv的命令,可以我們的iwpriv都是由dev->do_ioctl完成的.
                return ioctl_private_call(dev, ifr, cmd, handler);
        }
        /* Old driver API : call driver ioctl handler */
        if (dev->do_ioctl)
    //如果dev->wireless_handlers->standard和dev->wireless_handlers->private[index都不對該cmd作處理,那么由
    //dev->do_ioctl = wlan_do_ioctl;我們驅動的最后處理函數wlan_do_ioctl處理.
            return dev->do_ioctl(dev, ifr, cmd); 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 */     /* Check if we have some wireless handlers defined */
        if (dev->wireless_handlers == NULL)
            return NULL;     /* Try as a standard command */
        index = cmd - SIOCIWFIRST;
        if (index < dev->wireless_handlers->num_standard)
            return dev->wireless_handlers->standard[index];     /* Try as a private command */
        index = cmd - SIOCIWFIRSTPRIV;//     if (index < dev->wireless_handlers->num_private)
            return dev->wireless_handlers->private[index];//該private命令的handler.
        /* Not found */
        return NULL;
    }
    下面wlan_private_args為本wifi網卡驅動的所能支持的所有命令,也就是iwpriv命令所能支持的所有命令 struct iw_handler_def wlan_handler_def = {
      num_standard:sizeof(wlan_handler) / sizeof(iw_handler),
      num_private:sizeof(wlan_private_handler) / sizeof(iw_handler),
      num_private_args:sizeof(wlan_private_args) / sizeof(struct iw_priv_args),
      standard:(iw_handler *) wlan_handler,
      private:(iw_handler *) wlan_private_handler,
      private_args:(struct iw_priv_args *) wlan_private_args,
    #if WIRELESS_EXT > 20
      get_wireless_stats:wlan_get_wireless_stats,
    #endif
    }; 以下為示意代碼,我們的wifi網卡驅動支持如下iwpriv命令.
    static const struct iw_priv_args wlan_private_args[] = {
         "extscan"/     "hostcmd"/     "arpfilter"/     "regrdwr"/     "sdcmd52rw"/
         "sdcmd53rw"/     "setgetconf"/     "getcis"/     "scantype"/     "deauth"
         "getNF"/     "getRSSI"/     "bgscan"/     "enable11d"/     "adhocgrate"
         "sdioclock"/     "wmm"/     "uapsdnullgen"/     "setcoalescing"/     "adhocgprot"
         "setpowercons"/     "wmm_qosinfo"/     "lolisteninter"/     "fwwakeupmethod"
         "psnullinterval"/     "bcnmisto"/     "adhocawakepd"/     "moduletype"
         "autodeepsleep"/     "enhanceps"/     "wakeupmt"/     "setrxant"/     "settxant"
         "authalgs"/     "encryptionmode"/     "setregioncode"/     "setlisteninter"
         "setmultipledtim"/     "setbcnavg"/     "setdataavg"/     "associate"/     "getregioncode"
         "getlisteninter"/     "getmultipledtim"/     "gettxrate"/     "getbcnavg"
         "getdataavg"/     "getrxant"/     "gettxant"/     "gettsf"/     "wpssession"
         "deepsleep"/     "adhocstop"/     "radioon"/     "radiooff"/     "rmaeskey"
         "crypto_test"/     "reasso-on"/     "reasso-off"/     "wlanidle-on"/     "wlanidle-off"
         "sleepparams"/     "requesttpc"/     "powercap"/     "measreq"/     "bca-ts"
         "scanmode"/     "getadhocstatus"/     "setgenie"/     "getgenie"/     "qstatus"
         "ts_status"/     "setaeskey"/     "getaeskey"/     "version"/     "verext"/     "setwpaie"
         "setband"/     "setadhocch"/     "chanswann"/     "getband"/     "getadhocch"
         "getlog"/     "tpccfg"/     "scanprobes"/     "ledgpio"/     "sleeppd"/     "rateadapt"
         "getSNR"/     "getrate"/     "getrxinfo"/     "atimwindow"/     "bcninterval"/     "sdiopullctrl"
         "scantime"/     "sysclock"/     "txcontrol"/     "hscfg"/     "hssetpara"/     "inactoext"
         "dbgscfg"/     "drvdbg"/     "drvdelaymax"/     "intfctrl"/     "setquietie"/     ""
         "setuserscan"/     "getscantable"/     "setmrvltlv"/     "getassocrsp"/     "addts"
         "delts"/    "qconfig"/     "qstats"/     "txpktstats"/     "getcfptable"/     "mefcfg"
         "getmem" };     淺析ethx網卡控制函數ioctl實現具體流程 ====================
    1.應用層程序iwpriv
    wireless tools網絡配置應用程序iwpriv命令格式:
    iwpriv ethX private-command [parameters] iwpriv部分實現源碼如下:
    int main(int argc, char *argv[])
    {
        ...
        sockfd = socket(AF_INET, SOCK_STREAM, 0);
        ...
        ioctl(sockfd, ioctl_val, &iwr);//將控制命令通過ioctl發送到無線網卡
        ...
    }
    ====================
    2.系統調用sys_ioctl
    應用層通過ioctl(sockfd, ioctl_val, &iwr);觸發sys_ioctl系統調用,實際流程:
    sys_ioctl=>vfs_ioctl=>do_ioctl=最后調用
    filp->f_op->unlocked_ioctl執行具體的ioctl操作,該操作就是sock_ioctl,至于為什么是sock_ioctl,后邊作了進一步分析
    sock_ioctl=>
    {
        ...
        #ifdef CONFIG_WIRELESS_EXT
            if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {
                err = dev_ioctl(net, cmd, argp);//         } else
        #endif
        ...
    }
    dev_ioctl=>wext_handle_ioctl
    {
        ...
    /* Take care of Wireless Extensions */
        if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST)
            return wext_handle_ioctl(net, &ifr, cmd, arg);
        ...
    }
    wext_handle_ioctl=>wireless_process_ioctl=>
    然后通過if ((dev = __dev_get_by_name(net, ifr->ifr_name)) == NULL)函數,
    從系統管理的net鏈表中,把ioctl指定的ethX對應的struct net_device摘出來,
    最后調用ioctl_private_call(handler)或者調用dev->do_ioctl(dev, ifr, cmd)來處理該ioctl,
    這兩個函數分別指向wlan_handler_def和wlan_do_ioctl
    ====================
    3.wifi網卡是怎么登記到kernel上的
    wlan_probe()=>wlan_add_card()=>alloc_etherdev()=>
    之后將操作方法添加到struct net_device *dev=alloc_etherdev()申請的dev上去,其中包括:
        ...
        /* Setup the OS Interface to our functions */
        dev->open = wlan_open;
        dev->hard_start_xmit = wlan_hard_start_xmit;
        dev->stop = wlan_close;
        dev->do_ioctl = wlan_do_ioctl;
        dev->set_mac_address = wlan_set_mac_address;     dev->tx_timeout = wlan_tx_timeout;
        dev->get_stats = wlan_get_stats;
        dev->watchdog_timeo = MRVDRV_DEFAULT_WATCHDOG_TIMEOUT;
        dev->wireless_handlers = (struct iw_handler_def *) &wlan_handler_def;
        dev->set_multicast_list = wlan_set_multicast_list;
        ...
    4.socket系統調用如何關聯上ioctl和ethX設備 asmlinkage long sys_socket(int family, int type, int protocol); sys_socket=>sock_create=>__sock_create=>sock = sock_alloc();通過sock_mnt->mnt_sb從socket文件系統的超級塊上申請一個inode節點,這樣也就同時獲得了由 該inode描述的一個sock結構體單元,所以sokcet和dentry目錄項等效,
    接下來從net_families全局管理結構體中找到當前family對應的ops操作集,
    net_proto_family *pf=net_families[family];
    pf->create(net, sock, protocol);//核心調用,對于ipv4,就是inet_create
    以ipv4為例
    static struct net_proto_family inet_family_ops = {
        .family = PF_INET,
        .create = inet_create,
        .owner    = THIS_MODULE,
    };
    還記得上面應用層創建sokcet的函數吧,
    sockfd = socket(AF_INET, SOCK_STREAM, 0);//AF_INET雖然等于PF_INET,但是因為種種原因我們提倡使用PF_INET
    可見family等于AF_INET,type等于SOCK_STREAM,協議protocol為0,也就是采用IP協議,
    inet_create=>inetsw[sock->type]也就是inetsw[SOCK_STREAM],
    從inetsw[sock->type]中找到已經登記的protocol網絡協議處理函數,
    inetsw[]是怎么填充的呢?inet_init()=>inet_register_protosw(inetsw_array)=>這樣inetsw_array中的所有protocol處理模塊都將登記到inetsw中了,
    static struct inet_protosw inetsw_array[] =
    {
        {
            .type = SOCK_STREAM,
            .protocol = IPPROTO_TCP,
            .prot = &tcp_prot,
            .ops = &inet_stream_ops,
            .capability = -1,
            .no_check = 0,
            .flags = INET_PROTOSW_PERMANENT | INET_PROTOSW_ICSK,
        },     {
            .type = SOCK_DGRAM,
            .protocol = IPPROTO_UDP,
            .prot = &udp_prot,
            .ops = &inet_dgram_ops,
            .capability = -1,
            .no_check = UDP_CSUM_DEFAULT,
            .flags = INET_PROTOSW_PERMANENT,
        },
        {
            .type = SOCK_RAW,
            .protocol = IPPROTO_IP,    /* wild card */
            .prot = &raw_prot,
            .ops = &inet_sockraw_ops,
            .capability = CAP_NET_RAW,
            .no_check = UDP_CSUM_DEFAULT,
            .flags = INET_PROTOSW_REUSE,
        }
    };
    至 于inet_init,則是以fs_initcall(inet_init)方式,以5號優先級被build in到了內核中,當kernel啟動時會在start_kernel=>rest_init=>kernel_init=> do_basic_setup=>do_initcalls中依據優先級號優先于其他module驅動被調用.
    這樣sock->ops = answer->ops;對于ipv4也就等于inet_stream_ops,
    接下來就是將ops填充到file操作指針中了,
    sys_socket=>sock_map_fd=>sock_attach_fd=>
    dentry->d_op = &sockfs_dentry_operations;
    init_file(file, sock_mnt, dentry, FMODE_READ | FMODE_WRITE, &socket_file_ops);
    file->private_data = sock;
    其中init_file=>file->f_op = fop;也就是file->f_op = socket_file_ops;
    所以read(),wirte(),poll()和ioctl()應用程序調用的file->f_op就是socket_file_ops了,
    比如:
    read()對應sock_aio_read網絡異步讀
    write()對應sock_aio_write網絡異步寫
    ioctl()對應sock_ioctl socket_file_ops結構體具體實現如下:
    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,
    #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,
    };
    網卡控制因為涉及到的知識點比較多,上面只是從宏觀上對數據流程做了一個簡單的介紹,深入到其中的每個知識點,都會牽扯出一系列文章,讀者需要自己去一個個的慢慢深入,希望本文能夠對剛剛接觸網絡驅動的讀者有所幫助和啟發【gliethttp.Leith】 wireless extention擴展接口Blog作者的回復:
    wlan_add_card=>
    wlan_create_thread(wlan_service_main_thread, &priv->MainThread, "wlan_main_service");
    =>wlan_service_main_thread=>wlan_exec_next_cmd=>
    將調用wlan_enter_ps和wlan_exit_ps
    sbi_interrupt=>從sdio口上傳來的中斷數據,sdio_irq_thread=>process_sdio_pending_irqs=>調用func->irq_handler(func);即本.
    在mmc_signal_sdio_irq=>將調用wake_up_process(host->sdio_irq_thread);來喚醒該irq處理線程,可能還有其他命令需要處理wlan_exec_next_cmd
    這個pxamci_irq就是mmc的物理irq中斷了,pxamci_irq=>mmc_signal_sdio_irq(host->mmc); wlan_exec_next_cmd=>只要cmd鏈表上CmdNode還存在,
    那么就會執行wlan_dnld_cmd_to_fw(wlan_private * priv, CmdCtrlNode * CmdNode)將CmdNode中的數據下發下去,
    然后重新觸發wlan_mod_timer(&Adapter->MrvDrvCommandTimer, MRVDRV_TIMER_5S);
    也就是wlan_cmd_timeout_func命令超時處理函數,
    在cmd已經有了恢復之后,在主線程中調用wlan_process_cmdresp,立即調用wlan_cancel_timer(&Adapter->MrvDrvCommandTimer);來刪除定時器 wlan_service_main_thread=>每次喚醒都會檢查
    ====
        /* Execute the next command */
        if (!priv->wlan_dev.cmd_sent && !Adapter->CurCmd)
            wlan_exec_next_cmd(priv);
    ====
    wlan_prepare_cmd=>
    wlan_hostcmd_ioctl=>
    獲取一個空閑的CmdNode節點wlan_get_cmd_node,當完成賦值之后,執行如下語句,將CmdNode節點添加到處理隊列中:
    wlan_insert_cmd_to_pending_q(Adapter, CmdNode, TRUE);
    wake_up_interruptible(&priv->MainThread.waitQ);
    另外在數組中
    /*
     * iwconfig settable callbacks 
     */
    static const iw_handler wlan_handler[]這個數組中全部是回調函數, /** wlan_handler_def */
    struct iw_handler_def wlan_handler_def = {
      num_standard:sizeof(wlan_handler) / sizeof(iw_handler),
      num_private:sizeof(wlan_private_handler) / sizeof(iw_handler),
      num_private_args:sizeof(wlan_private_args) / sizeof(struct iw_priv_args),
      standard:(iw_handler *) wlan_handler,
      private:(iw_handler *) wlan_private_handler,
      private_args:(struct iw_priv_args *) wlan_private_args,
    #if WIRELESS_EXT > 20
      get_wireless_stats:wlan_get_wireless_stats,
    #endif
    };
    在wlan_add_card函數中
    dev->wireless_handlers = (struct iw_handler_def *) &wlan_handler_def; ===============在kernel的net中使用wireless extention擴展接口 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 */     /* Check if we have some wireless handlers defined */
        if (dev->wireless_handlers == NULL)
            return NULL;     /* Try as a standard command */
        index = cmd - SIOCIWFIRST;
        if (index < dev->wireless_handlers->num_standard)
            return dev->wireless_handlers->standard[index];     /* Try as a private command */
        index = cmd - SIOCIWFIRSTPRIV;
        if (index < dev->wireless_handlers->num_private)
            return dev->wireless_handlers->private[index];     /* Not found */
        return NULL;
    }
    =>sock_ioctl
    =>dev_ioctl
    +++/* Take care of Wireless Extensions */
    +++if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST)
    +++return wext_handle_ioctl(net, &ifr, cmd, arg);
    =>wext_handle_ioctl
    =>wireless_process_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd)
    =>get_handler(dev, cmd);如果沒有實現該cmd,那么將調用dev->do_ioctl來處理,
    wlan_reassoc_timer_func=>
    wmm_start_queue=>
    wlan_tx_packet=>
    wlan_tx_timeout=>
    wlan_remove_card=>
    wlan_hostcmd_ioctl=>
    wlan_auto_deep_sleep=>
    wlan_set_deep_sleep=>
    wlan_prepare_cmd=>
    wlan_cmd_timeout_func=>
    將調用wake_up_interruptible(&priv->MainThread.waitQ);喚醒wlan_service_main_thread主處理線程. wlan_hard_start_xmit=>wlan_tx_packet發送數據包
    dev->tx_timeout = wlan_tx_timeout;
    wlan_initialize_timer(&Adapter->MrvDrvCommandTimer, wlan_cmd_timeout_func, priv); int wlan_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
    {
        ...
            case WLAN_WAKEUP_MT:
                if (wrq->u.data.length > 0)
                    Adapter->IntCounter++;
                wake_up_interruptible(&priv->MainThread.waitQ);
                break;
        ...
    }
    在wlan_process_cmdresp()處理完該cmd之后,調用
    wlan_insert_cmd_to_free_q=>wlan_clean_cmd_noder,從命令鏈表上刪除已經處理完成的cmd_node,
    wlan_clean_cmd_noder然后pTempNode->CmdWaitQWoken = TRUE;同時如果該cmd_node是一個被阻塞等待的,那么喚醒等待的程序.
    wake_up_interruptible(&pTempNode->cmdwait_q);   Available private ioctls :
              set              (8BE2) : set 1024 char  & get   0
              connStatus       (0004) : set 1024 char  & get 2047 char
              driverVer        (0005) : set 1024 char  & get 2047 char
              bainfo           (0006) : set 1024 char  & get 2047 char
              descinfo         (0007) : set 1024 char  & get 2047 char
              radio_off        (000A) : set 1024 char  & get 2047 char
              radio_on         (000B) : set 1024 char  & get 2047 char
              show             (0015) : set 1024 char  & get 2047 char
              adhocEntry       (0016) : set 1024 char  & get 2047 char
              bbp              (8BE3) : set 2047 char  & get 2047 char
              mac              (8BE5) : set 1024 char  & get 1024 char
              rf               (8BF3) : set 2047 char  & get 2047 char
              e2p              (8BE7) : set 1024 char  & get 1024 char
              stat             (8BE9) : set   0       & get 2047 char ‍          get_site_survey  (8BED) : set   0       & get 1024 char    查看網絡狀態            Connect to stongest open AP 設置命令          
    iwpriv ra0 set SSID="" 
    iwpriv ra0 set Channel=0 
    iwpriv ra0 set NetworkType=Infra 
    iwpriv ra0 set AuthMode=SHARED 
    iwpriv ra0 set EncrypType=WEP 
    iwpriv ra0 set DefaultKeyID=1 
    iwpriv ra0 set Key1="whatever" 
    iwpriv ra0 set SSID="some_ssed" 
    iwpriv ra0 set WPAPSK="wpa_key" ... ‍顯示命令 iwpriv ra0 show SSID iwpriv ra0 show Channel 
    iwpriv ra0 show NetworkType iwpriv ra0 show AuthMode iwpriv ra0 show EncrypType iwpriv ra0 show DefaultKeyID 
    iwpriv ra0 show Key1 
    iwpriv ra0 show WPAPSK ...   ./iwpriv ra0 show    無線網卡功能參數
    ra0       show:
    SSID
    WirelessMode
    TxBurst
    TxPreamble
    TxPower
    Channel
    BGProtection
    RTSThreshold
    FragThreshold
    HtBw
    HtMcs
    HtGi
    HtOpMode
    HtExtcha
    HtMpduDensity
    HtBaWinSize
    HtRdg
    HtAmsdu
    HtAutoBa
    CountryRegion
    CountryRegionABand
    CountryCode
    PktAggregate
    WmmCapable
    IEEE80211H
    NetworkType
    WPAPSK
    AutoReconnect
    AuthMode
    EncrypType
    DefaultKeyID
    Key1
    Key2
    Key3
    Key4
    PMK
    弈自:http://hi.baidu.com/fghzone/blog/item/4131382a6a57ff88033bf6f0.htmlRFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成
    最近免费观看高清韩国日本大全