和菜鸟一起学linux之wifi学习记录

2024-06-19 18:38

本文主要是介绍和菜鸟一起学linux之wifi学习记录,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

也差不多一个月没有更新博客了,元旦也过去了,8天的班也上完了,小病也好了,时间又回到了每个周的周末了,不知道干嘛,突然发现好像失去了什么,好像做了很多很多没有意义的事,一直都是在原点打转,不知道接下去会是什么,不知道为了什么。也许总会有一段日子觉得很迷茫,不知所措。这么一来,原本要做的很多事都耽搁了,2012,离梦还有那么远,没有丝毫的前进。很累,但是不知道是身体的。还是心里的,还是…………

       不说这些了,还是把上次总结的wifi驱动给分析分析吧。

       Sdio wifi,首先,他是一个sdio的卡的设备,然后具备了wifi的功能,所以,注册的时候还是先以sdio的卡的设备去注册的。然后检测到卡之后就要驱动他的wifi功能了,显然,他是用sdio的协议,通过发命令和数据来控制的。虽然wifi数据的传输流程,但是也得知道他是怎么工作的,要不然连函数指针在哪都找不到,那就更别说其他的了。好了,还是先从初始化开始吧。

----------------------------------------------------华丽的分割线------------------------------------------------

 

关于sdio初始化

----------------------------------------------------------------------------------------------------------------------

 

首先是模块初始化os_dep/linux/sdio_intfs.c函数中调用下面这个函数。

static int __init rtw_drv_entry(void)

这里做了一些初始化工作,主要是:

ret = sdio_register_driver(&sdio_drvpriv.r871xs_drv);//注册了sdio的驱动。

sdio_drvpriv = {

       .r871xs_drv.probe = rtw_drv_init,

       .r871xs_drv.remove = rtw_dev_remove,

       .r871xs_drv.name = (char*)DRV_NAME,

       .r871xs_drv.id_table = sdio_ids,

       .r871xs_drv.drv = {

              .pm = &rtw_sdio_pm_ops,

       }

};

所以当检测到sdio卡插入了之后就会调用rtw_drv_int,而当卡被移除后就会调用rtw_dev_remove。还有电源管理啊什么的,就不细看了。下面主要还是看下rtw_drv_int函数吧。

if ((dvobj =sdio_dvobj_init(func)) == NULL)

if ((if1 =rtw_sdio_if1_init(dvobj, id)) == NULL)

if ((if2 =rtw_drv_if2_init(if1, NULL, sdio_set_intf_ops)) == NULL)

这里主要是sdio的host和wifi的绑定,可以让wifi用这个host来传输数据用的。看下这个函数就知道了sdio_set_intf_ops。这个函数里,主要是sdio的数据传输接口的一些函数指针的赋值。

pops->_read8= &sdio_read8;

       pops->_read16= &sdio_read16;

       pops->_read32= &sdio_read32;

       pops->_read_mem= &sdio_read_mem;

       pops->_read_port= &sdio_read_port;

 

       pops->_write8= &sdio_write8;

       pops->_write16= &sdio_write16;

       pops->_write32= &sdio_write32;

       pops->_writeN= &sdio_writeN;

       pops->_write_mem= &sdio_write_mem;

       pops->_write_port= &sdio_write_port;

最后wifi上面传输的数据,会调用这里的接口来通信的。

 

这里还分配了irq在接收数据的时候要用到

alloc_irq(dvobj) != _SUCCESS)

其调用了err = sdio_claim_irq(func,&sd_sync_int_hdl);

最后就是那个sd_sync_int_hdl函数的功能了

----------------------------------------------------华丽的分割线------------------------------------------------


关于Wifi初始化

----------------------------------------------------------------------------------------------------------------------

这个函数在os_dep/linux/os_intfs.c中的rtw_drv_if2_init进行初始化工作。

1、初始化netdev

       pnetdev = rtw_init_netdev(NULL);

       这个函数主要是:

a、pnetdev->netdev_ops = &rtw_netdev_ops;//函数指针的结构体的赋值

rtw_netdev_ops = {

       .ndo_open = netdev_open,

       .ndo_stop = netdev_close,

       .ndo_start_xmit = rtw_xmit_entry,

       .ndo_select_queue  = rtw_select_queue,

};

b、pnetdev->wireless_handlers = (struct iw_handler_def*)&rtw_handlers_def;//无线的handler

       c、loadparam(padapter, pnetdev);//一些参数的配置,wlan0这个接口名字也是这定义的。

 

2、netdev函数指针的结构体的赋值

pnetdev->netdev_ops = &rtw_netdev_if2_ops;

rtw_netdev_if2_ops = {

       .ndo_open = netdev_if2_open,

    .ndo_stop = netdev_if2_close,

    .ndo_start_xmit = rtw_xmit_entry,

    .ndo_set_mac_address =rtw_net_set_mac_address,

    .ndo_get_stats = rtw_net_get_stats,

    .ndo_do_ioctl =rtw_ioctl,

       .ndo_select_queue  = rtw_select_queue,

};

在上面已经初始化了,这里难道是添加了rtw_net_set_mac_address,rtw_ioctl吗?好吧,就当作上面无效,只用下面的就OK了。

 

3、初始化adapter

 

4、设置Hal的function, 分配Hal的数据

hal_set_hal_ops(padapter);

#define hal_set_hal_ops rtl8723as_set_hal_ops

所以调用的是hal/rtl8723a/sdio/sdio_halinit.c中的rtl8723as_set_hal_ops

这里又调用了hal/rtl8723a/rtl8723a_hal_init.中的rtl8723a_set_hal_ops(pHalFunc);而这个函数又设置了函数指针,其中有下面的函数指针的赋值:

pHalFunc->run_thread= &rtl8723a_start_thread;

 

回到主函数,该函数主要是设置一些函数指针,其中有下面几个函数指针的赋值:

pHalFunc->init_xmit_priv =&rtl8723as_init_xmit_priv;

pHalFunc->init_recv_priv =&rtl8723as_init_recv_priv;

pHalFunc->hal_init = &rtl8723as_hal_init;

       pHalFunc->hal_xmit= &rtl8723as_hal_xmit;

pHalFunc->mgnt_xmit = &rtl8723as_mgnt_xmit;

 

5、rtw_hal_read_chip_version(padapter);//读取芯片版本

if(rtw_init_drv_sw(padapter)!=_SUCCESS) //这里可是做了不少东西啊,初始化了很多的driver的数据。主要做了以下这些事情:

if ((rtw_init_cmd_priv(&padapter->cmdpriv)) == _FAIL)

if ((rtw_init_evt_priv(&padapter->evtpriv)) == _FAIL)

if (rtw_init_mlme_priv(padapter) == _FAIL)//

if(init_mlme_ext_priv(padapter) == _FAIL)

if(rtw_init_tdls_info(padapter) == _FAIL)

if(_rtw_init_xmit_priv(&padapter->xmitpriv,padapter) == _FAIL)//发送数据的队列,frame

的buf大小等的设置

if(_rtw_init_recv_priv(&padapter->recvpriv,padapter) == _FAIL)//接收数据的队列。Frame

的buf大小等的设置

rtw_init_netdev_name(pnetdev,name);//初始化网络接口名

 

6、_rtw_memcpy(mac,primary_padapter->eeprompriv.mac_addr, ETH_ALEN);

//从eeprom中读取mac地址

 

7、if(register_netdev(pnetdev) != 0)   //这里去注册netdev

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------华丽的分割线------------------------------------------------

 

 

关于Wifi工作总流程

----------------------------------------------------------------------------------------------------------------------

 

----------------------------------------------------华丽的分割线------------------------------------------------

关于Wifi接口激活

----------------------------------------------------------------------------------------------------------------------

       相信都知道网络调用到底层就是通过ioctl的接口,而应用层是socket这个网络套接字来调用的。底层主要实现的接口就如下结构体所示了。

rtw_netdev_ops = {

       .ndo_open = netdev_open,

       .ndo_stop = netdev_close,

       .ndo_start_xmit =rtw_xmit_entry,

       .ndo_select_queue  = rtw_select_queue,

};

       是不是一目了然?对的,和那个char设备很类似额。

       首先,我们一般都会在linux下用一条命令,那便是:ifconfig wlan0 up。这里的wlan0是初始化的时候弄好的,而对于我们本地的网卡,一般也是有一个eth0的接口的。所以,这个时候就调用了我们的netdev_open接口了。没错。那就先看看这里干了什么事情了。

os_dep/linux/os_intfs.c中的   ret = _netdev_open(pnetdev);

调用了这个函数,还用锁给锁住的。这里才是主要的处理了。

1、硬件抽象层的初始化

status =rtw_hal_init(padapter);

       status=        padapter->HalFunc.hal_init(padapter->pbuddy_adapter);

而HalFunc.hal_init这个函数指针在初始化的时候已经赋值给了

hal/rtl8723a/sdio/sdio_halinit.c文件中的rtl8723as_hal_init这个函数,这个函数的调用了很多东东了。

       ret= _InitPowerOn(padapter);    //开电源

       ret= InitLLTTable(padapter, boundary);

       ret= rtl8723a_FirmwareDownload(padapter);//下载firmware

rtl8723a_InitializeFirmwareVars(padapter);

HalDetectPwrDownMode(padapter);//低功耗模式

_InitRFType(padapter);   // Set RF type for BB/RF configuration

ret =PHY_MACConfig8723A(padapter); //物理层的一些操作

ret =PHY_BBConfig8723A(padapter);

…………这里做了很多的物理层的操作就不细看了。

 

2、开两个线程,用来发送命令和数据。

status=rtw_start_drv_threads(padapter);

a、这里先开一个cmd线程

padapter->cmdThread=kernel_thread(rtw_cmd_thread,padapter,CLONE_FS|CLONE_FILES);

cmd线程处理函数rtw_cmd_thread在core/rtw_cmd.c中,他调用了

这里主要是:

cmd_hdl = wlancmds[pcmd->cmdcode].h2cfuns;

pcmd_callback =rtw_cmd_callback[pcmd->cmdcode].callback;


上层通过ioctl调用下来后,会根据具体的handle和callback函数调用对应的函数做相应的处理的。

b、再开一个数据线程

rtw_hal_start_thread(padapter);然后调用这个函数指针。

padapter->HalFunc.run_thread(padapter);

其在初始化的时候被赋值为rtl8723a_start_thread

pHalData->SdioXmitThread = kernel_thread(rtl8723as_xmit_thread, padapter, CLONE_FS|CLONE_FILES);//又开了一个rtl8723as_xmit_thread线程了。传输数据的。

具体在hal/rtl8723a/sdio/rtl_8723as_xmit.c

调用了ret =rtl8723as_xmit_handler(padapter);

接着是err = rtw_hal_xmit_thread_handler(padapter);

padapter->HalFunc.xmit_thread_handler(padapter);函数指针调用过程,

              会调用rtl8723as_xmit_buf_handler

然后是queue_empty =rtl8723_dequeue_writeport(padapter, freePage);

最后调用rtw_write_port(padapter,deviceId, pxmitbuf->len, (u8 *)pxmitbuf);和sdio控制器交互。


       3、初始化wifi的mac子系统管理实体

if (init_hw_mlme_ext(padapter) == _FAIL)

 

4、初始化cfg80211wifi的phy

rtw_cfg80211_init_wiphy(padapter);

      

       5、开启或者唤醒队列。

              if(!rtw_netif_queue_stopped(pnetdev))

                     rtw_netif_start_queue(pnetdev);

              else

                     rtw_netif_wake_queue(pnetdev);

      

       ok了,基本open了之后,就做了这些工作。

------------------------------------------------华丽的分割线------------------------------------------------

 

 关于wifi的数据传输

----------------------------------------------------------------------------------------------------------------------

1、接收数据

os_dep/linux/sdio_intfs.c中的中断函数sd_sync_int_hdl这个可以知道,每次数据接收就是通过这个中断函数来的。

其调用了hal/rtl8723a/sdio/sdio_ops.c的sd_int_hdl(psdpriv->if1); 接着sd_int_dpc(padapter);

若fifo不空,那么就调用

precvbuf = sd_recv_rxfifo(padapter,phal->SdioRxFIFOSize);其主要做了

a、首先是分配recvbuf

      b、再分配的是skb

c、然后从rxfifo中读数据

d、最后是初始化recvbuf

如果上面成功了,那么就调用下面的函数了

sd_rxhandler(padapter, precvbuf);

首先那便是enqueue recvbuf

rtw_enqueue_recvbuf(precvbuf, ppending_queue);

接着会调度tasklet去做处理的

tasklet_schedule(&precvpriv->recv_tasklet);

又因为pHalFunc->init_recv_priv= &rtl8723as_init_recv_priv;其中init就有tasklet函数的初始化等工作。所以即调用了hal/rtl8723as/sdio/rtl8723as_recv.c 中的

rtl8723as_recv_tasklet函数了

precvbuf =rtw_dequeue_recvbuf(&precvpriv->recv_buf_pending_queue);//先出队列

update_recvframe_attrib(precvframe, (structrecv_stat*)ptr);//帧解析

pkt_copy = netdev_alloc_skb(padapter->pnetdev,alloc_sz);//封装skb,使得上层可以处理它。然后就是写入数据,传给上层了。

OK,数据从sdio接口读取,然后交给上层就是这样了。


2、数据发送

已经在wifi初始化的时候.ndo_start_xmit= rtw_xmit_entry,了,所以发送函数就调用到了

rtw_xmit_entry函数会调用到res = rtw_xmit(padapter,&pkt);

do_queue_select(padapter, &pxmitframe->attrib)//他会选择一个队列,因为有4个队列啊。

之后就会通过if (rtw_hal_xmit(padapter, pxmitframe) == _FALSE)

然后padapter->HalFunc.hal_xmit(padapter,pxmitframe);这个调用到了抽象层的sdio去了。

由上面的初始化可以知道pHalFunc->hal_xmit =&rtl8723as_hal_xmit;

其在hal/rtl8723as/sdio/rtl8723as_xmit.c中。

他会调用err = rtw_xmitframe_enqueue(padapter, pxmitframe);,接着是

rtw_xmit_classifier(_adapter*padapter, struct xmit_frame *pxmitframe);

然后这里他会选择一个队列去放数据。

----------------------------------------------------华丽的分割线----------------------------------------------


关于wifi的应用调用接口

----------------------------------------------------------------------------------------------------------------------

最主要的就是rtw_handlers[]了。

rtw_wx_get_name,        /* SIOCGIWNAME */

rtw_wx_set_freq,          /* SIOCSIWFREQ */

rtw_wx_get_freq,         /* SIOCGIWFREQ */

rtw_wx_set_mode,        /* SIOCSIWMODE */

rtw_wx_get_mode,              /* SIOCGIWMODE */

rtw_wx_get_sens,         /* SIOCGIWSENS */

rtw_wx_get_range,              /* SIOCGIWRANGE */

rtw_wx_set_priv,          /* SIOCSIWPRIV */

rtw_wx_set_wap,         /* SIOCSIWAP */

rtw_wx_get_wap,         /* SIOCGIWAP */

rtw_wx_set_mlme,        /* request MLME operation; uses struct iw_mlme */

rtw_wx_set_scan,         /* SIOCSIWSCAN */

rtw_wx_get_scan,         /* SIOCGIWSCAN */

rtw_wx_set_essid,        /* SIOCSIWESSID */

rtw_wx_get_essid,        /* SIOCGIWESSID */

rtw_wx_get_nick,         /* SIOCGIWNICKN */

rtw_wx_set_rate,          /* SIOCSIWRATE */

rtw_wx_get_rate,          /* SIOCGIWRATE */

rtw_wx_set_rts,                   /* SIOCSIWRTS */

rtw_wx_get_rts,                  /* SIOCGIWRTS */

rtw_wx_set_frag,          /* SIOCSIWFRAG */

rtw_wx_get_frag,         /* SIOCGIWFRAG */

rtw_wx_get_retry,         /* SIOCGIWRETRY */

rtw_wx_set_enc,                 /* SIOCSIWENCODE */

rtw_wx_get_enc,                 /* SIOCGIWENCODE */

rtw_wx_get_power,             /* SIOCGIWPOWER */

rtw_wx_set_gen_ie,             /* SIOCSIWGENIE */

rtw_wx_set_auth,         /* SIOCSIWAUTH */

rtw_wx_set_enc_ext,           /* SIOCSIWENCODEEXT */

rtw_wx_set_pmkid,              /* SIOCSIWPMKSA */

 

下面根据简单的几个ioctl来分析下,主要流程看下图就可以了。

----------------------------------------------------华丽的分割线----------------------------------------------



关于wifi的连接过程

----------------------------------------------------------------------------------------------------------------------

Wifi连接过程主要是先由应用层调用SIOCSIWESSID这个命令,然后根据sdio wifi通过帧数据来交互认真,连接等。主要流程如下:

----------------------------------------------------华丽的分割线----------------------------------------------


原文:http://blog.csdn.net/eastmoon502136/article/details/8496258


这篇关于和菜鸟一起学linux之wifi学习记录的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1075831

相关文章

linux生产者,消费者问题

pthread_cond_wait() :用于阻塞当前线程,等待别的线程使用pthread_cond_signal()或pthread_cond_broadcast来唤醒它。 pthread_cond_wait() 必须与pthread_mutex 配套使用。pthread_cond_wait()函数一进入wait状态就会自动release mutex。当其他线程通过pthread

51单片机学习记录———定时器

文章目录 前言一、定时器介绍二、STC89C52定时器资源三、定时器框图四、定时器模式五、定时器相关寄存器六、定时器练习 前言 一个学习嵌入式的小白~ 有问题评论区或私信指出~ 提示:以下是本篇文章正文内容,下面案例可供参考 一、定时器介绍 定时器介绍:51单片机的定时器属于单片机的内部资源,其电路的连接和运转均在单片机内部完成。 定时器作用: 1.用于计数系统,可

问题:第一次世界大战的起止时间是 #其他#学习方法#微信

问题:第一次世界大战的起止时间是 A.1913 ~1918 年 B.1913 ~1918 年 C.1914 ~1918 年 D.1914 ~1919 年 参考答案如图所示

[word] word设置上标快捷键 #学习方法#其他#媒体

word设置上标快捷键 办公中,少不了使用word,这个是大家必备的软件,今天给大家分享word设置上标快捷键,希望在办公中能帮到您! 1、添加上标 在录入一些公式,或者是化学产品时,需要添加上标内容,按下快捷键Ctrl+shift++就能将需要的内容设置为上标符号。 word设置上标快捷键的方法就是以上内容了,需要的小伙伴都可以试一试呢!

Linux 安装、配置Tomcat 的HTTPS

Linux 安装 、配置Tomcat的HTTPS 安装Tomcat 这里选择的是 tomcat 10.X ,需要Java 11及更高版本 Binary Distributions ->Core->选择 tar.gz包 下载、上传到内网服务器 /opt 目录tar -xzf 解压将解压的根目录改名为 tomat-10 并移动到 /opt 下, 形成个人习惯的路径 /opt/tomcat-10

AssetBundle学习笔记

AssetBundle是unity自定义的资源格式,通过调用引擎的资源打包接口对资源进行打包成.assetbundle格式的资源包。本文介绍了AssetBundle的生成,使用,加载,卸载以及Unity资源更新的一个基本步骤。 目录 1.定义: 2.AssetBundle的生成: 1)设置AssetBundle包的属性——通过编辑器界面 补充:分组策略 2)调用引擎接口API

RedHat运维-Linux文本操作基础-AWK进阶

你不用整理,跟着敲一遍,有个印象,然后把它保存到本地,以后要用再去看,如果有了新东西,你自个再添加。这是我参考牛客上的shell编程专项题,只不过换成了问答的方式而已。不用背,就算是我自己亲自敲,我现在好多也记不住。 1. 输出nowcoder.txt文件第5行的内容 2. 输出nowcoder.txt文件第6行的内容 3. 输出nowcoder.txt文件第7行的内容 4. 输出nowcode

Javascript高级程序设计(第四版)--学习记录之变量、内存

原始值与引用值 原始值:简单的数据即基础数据类型,按值访问。 引用值:由多个值构成的对象即复杂数据类型,按引用访问。 动态属性 对于引用值而言,可以随时添加、修改和删除其属性和方法。 let person = new Object();person.name = 'Jason';person.age = 42;console.log(person.name,person.age);//'J

【Linux进阶】UNIX体系结构分解——操作系统,内核,shell

1.什么是操作系统? 从严格意义上说,可将操作系统定义为一种软件,它控制计算机硬件资源,提供程序运行环境。我们通常将这种软件称为内核(kerel),因为它相对较小,而且位于环境的核心。  从广义上说,操作系统包括了内核和一些其他软件,这些软件使得计算机能够发挥作用,并使计算机具有自己的特生。这里所说的其他软件包括系统实用程序(system utility)、应用程序、shell以及公用函数库等

大学湖北中医药大学法医学试题及答案,分享几个实用搜题和学习工具 #微信#学习方法#职场发展

今天分享拥有拍照搜题、文字搜题、语音搜题、多重搜题等搜题模式,可以快速查找问题解析,加深对题目答案的理解。 1.快练题 这是一个网站 找题的网站海量题库,在线搜题,快速刷题~为您提供百万优质题库,直接搜索题库名称,支持多种刷题模式:顺序练习、语音听题、本地搜题、顺序阅读、模拟考试、组卷考试、赶快下载吧! 2.彩虹搜题 这是个老公众号了 支持手写输入,截图搜题,详细步骤,解题必备