天天看點

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

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,

        .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,

        .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,

    .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 */

在wlan_add_card函數中

dev->wireless_handlers = (struct iw_handler_def *) &wlan_handler_def;

===============在kernel的net中使用wireless extention擴充接口

    index = cmd - SIOCIWFIRSTPRIV;

        return dev->wireless_handlers->private[index];

=>sock_ioctl

=>dev_ioctl

+++/* Take care of Wireless Extensions */

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

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

=>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_auto_deep_sleep=>

wlan_set_deep_sleep=>

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.html

繼續閱讀