资讯动态

【2016-02-23】Linux无线模块WEXT简单分析

发布时间:2026/9/16 9:43:35 来源:尧图企业网站定制
[历史归档]本文原发布于 cstriker1407.info 个人博客内容为历史存档仅供参考。发布时间2016-02-23 标题Linux无线模块WEXT简单分析分类操作系统 / linux / kernel 标签linux·kernel·wextLinux无线模块WEXT简单分析在新版本的linux中WIFI使用过nl80211来配置的但是wext也是保留的方便其他工具使用。作者最近就在工作中遇到了这个问题很多配置需要通过iw工具集来实现。那么这里就简单的笔记下wext吧。PS:作者对于linux网络架构理解的非常浅显可能有错误还请大家多多指正。而且有ioctl的数目繁多这里就简单的笔记下主干分发过程具体驱动在具体分析吧。当我们调用socket进行协议调用时会在文件操作中支持ioctl操作/net/socket.c/* * Socket files have a set of special operations as well as the generic file ones. These dont appear * in the operation structures but are done directly via the socketcall() multiplexor. */staticconststructfile_operationssocket_file_ops{。。。.unlocked_ioctlsock_ioctl,#ifdefCONFIG_COMPAT.compat_ioctlcompat_sock_ioctl,#endif};/* 由于socket是通用架构因此这里不会有具体的ioctl的实现而是基于每个注册到该协议里的dev的实现 */staticlongsock_ioctl(structfile*file,unsignedcmd,unsignedlongarg){structsocket*sock;structsock*sk;void__user*argp(void__user*)arg;intpid,err;structnet*net;sockfile-private_data;sksock-sk;netsock_net(sk);/* 可以看到只要是cmd符合一定的要求的全部路由到指定dev中实现 */if(cmdSIOCDEVPRIVATEcmd(SIOCDEVPRIVATE15)){errdev_ioctl(net,cmd,argp);}else#ifdefCONFIG_WIRELESS_EXTif(cmdSIOCIWFIRSTcmdSIOCIWLAST){errdev_ioctl(net,cmd,argp);}else#endif/* CONFIG_WIRELESS_EXT */switch(cmd){caseFIOSETOWN:caseSIOCSPGRP:err-EFAULT;if(get_user(pid,(int__user*)argp))break;errf_setown(sock-file,pid,1);break;caseFIOGETOWN:caseSIOCGPGRP:errput_user(f_getown(sock-file),(int__user*)argp);break;caseSIOCGIFBR:caseSIOCSIFBR:caseSIOCBRADDBR:caseSIOCBRDELBR:err-ENOPKG;if(!br_ioctl_hook)request_module(bridge);mutex_lock(br_ioctl_mutex);if(br_ioctl_hook)errbr_ioctl_hook(net,cmd,argp);mutex_unlock(br_ioctl_mutex);break;caseSIOCGIFVLAN:caseSIOCSIFVLAN:err-ENOPKG;if(!vlan_ioctl_hook)request_module(8021q);mutex_lock(vlan_ioctl_mutex);if(vlan_ioctl_hook)errvlan_ioctl_hook(net,argp);mutex_unlock(vlan_ioctl_mutex);break;caseSIOCADDDLCI:caseSIOCDELDLCI:err-ENOPKG;if(!dlci_ioctl_hook)request_module(dlci);mutex_lock(dlci_ioctl_mutex);if(dlci_ioctl_hook)errdlci_ioctl_hook(cmd,argp);mutex_unlock(dlci_ioctl_mutex);break;default:errsock-ops-ioctl(sock,cmd,arg);/* * If this ioctl is unknown try to hand it down * to the NIC driver. */if(err-ENOIOCTLCMD)errdev_ioctl(net,cmd,argp);break;}returnerr;}/net/core/dev.c/* 同样dev也是通用代码但是在代码的最后会有wext的配置 */intdev_ioctl(structnet*net,unsignedintcmd,void__user*arg){structifreqifr;intret;char*colon;/* One special case: SIOCGIFCONF takes ifconf argument and requires shared lock, because it sleeps writing to user space. */if(cmdSIOCGIFCONF){rtnl_lock();retdev_ifconf(net,(char__user*)arg);rtnl_unlock();returnret;}if(cmdSIOCGIFNAME)returndev_ifname(net,(structifreq__user*)arg);if(copy_from_user(ifr,arg,sizeof(structifreq)))return-EFAULT;ifr.ifr_name[IFNAMSIZ-1]0;colonstrchr(ifr.ifr_name,:);if(colon)*colon0;/* * See which interface the caller is talking about. */switch(cmd){/* * These ioctl calls: * - can be done by all. * - atomic and do not require locking. * - return a value */caseSIOCGIFFLAGS:caseSIOCGIFMETRIC:caseSIOCGIFMTU:caseSIOCGIFHWADDR:caseSIOCGIFSLAVE:caseSIOCGIFMAP:caseSIOCGIFINDEX:caseSIOCGIFTXQLEN:dev_load(net,ifr.ifr_name);read_lock(dev_base_lock);retdev_ifsioc_locked(net,ifr,cmd);read_unlock(dev_base_lock);if(!ret){if(colon)*colon:;if(copy_to_user(arg,ifr,sizeof(structifreq)))ret-EFAULT;}returnret;caseSIOCETHTOOL:dev_load(net,ifr.ifr_name);rtnl_lock();retdev_ethtool(net,ifr);rtnl_unlock();if(!ret){if(colon)*colon:;if(copy_to_user(arg,ifr,sizeof(structifreq)))ret-EFAULT;}returnret;/* * These ioctl calls: * - require superuser power. * - require strict serialization. * - return a value */caseSIOCGMIIPHY:caseSIOCGMIIREG:caseSIOCSIFNAME:if(!capable(CAP_NET_ADMIN))return-EPERM;dev_load(net,ifr.ifr_name);rtnl_lock();retdev_ifsioc(net,ifr,cmd);rtnl_unlock();if(!ret){if(colon)*colon:;if(copy_to_user(arg,ifr,sizeof(structifreq)))ret-EFAULT;}returnret;/* * These ioctl calls: * - require superuser power. * - require strict serialization. * - do not return a value */caseSIOCSIFFLAGS:caseSIOCSIFMETRIC:caseSIOCSIFMTU:caseSIOCSIFMAP:caseSIOCSIFHWADDR:caseSIOCSIFSLAVE:caseSIOCADDMULTI:caseSIOCDELMULTI:caseSIOCSIFHWBROADCAST:caseSIOCSIFTXQLEN:caseSIOCSMIIREG:caseSIOCBONDENSLAVE:caseSIOCBONDRELEASE:caseSIOCBONDSETHWADDR:caseSIOCBONDCHANGEACTIVE:caseSIOCBRADDIF:caseSIOCBRDELIF:caseSIOCSHWTSTAMP:if(!capable(CAP_NET_ADMIN))return-EPERM;/* fall through */caseSIOCBONDSLAVEINFOQUERY:caseSIOCBONDINFOQUERY:dev_load(net,ifr.ifr_name);rtnl_lock();retdev_ifsioc(net,ifr,cmd);rtnl_unlock();returnret;caseSIOCGIFMEM:/* Get the per device memory space. We can add this but * currently do not support it */caseSIOCSIFMEM:/* Set the per device memory buffer space. * Not applicable in our case */caseSIOCSIFLINK:return-EINVAL;/* * Unknown or private ioctl. */default:if(cmdSIOCWANDEV||(cmdSIOCDEVPRIVATEcmdSIOCDEVPRIVATE15)){dev_load(net,ifr.ifr_name);rtnl_lock();retdev_ifsioc(net,ifr,cmd);rtnl_unlock();if(!retcopy_to_user(arg,ifr,sizeof(structifreq)))ret-EFAULT;returnret;}/* 如果ioctl号码在wext中那么额外处理 *//* Take care of Wireless Extensions */if(cmdSIOCIWFIRSTcmdSIOCIWLAST)returnwext_handle_ioctl(net,ifr,cmd,arg);return-EINVAL;}}/net/wireless/wext.c/* wext针对ioctl的路由主函数 */intwext_handle_ioctl(structnet*net,structifreq*ifr,unsignedintcmd,void__user*arg){structiw_request_infoinfo{.cmdcmd,.flags0};intret;/* 继续分发 */retwext_ioctl_dispatch(net,ifr,cmd,info,ioctl_standard_call,ioctl_private_call);if(ret0IW_IS_GET(cmd)copy_to_user(arg,ifr,sizeof(structiwreq)))return-EFAULT;returnret;}/* entry point from dev ioctl */staticintwext_ioctl_dispatch(structnet*net,structifreq*ifr,unsignedintcmd,structiw_request_info*info,wext_ioctl_func standard,wext_ioctl_func private){intretwext_permission_check(cmd);if(ret)returnret;dev_load(net,ifr-ifr_name);rtnl_lock();/* 继续分发 */retwireless_process_ioctl(net,ifr,cmd,info,standard,private);rtnl_unlock();returnret;}在分析wireless_process_ioctl之前先看下standand和private两个函数/* standand函数实现 这里是wext的标准ioctl的实现 由于wext已经不再开发只是维护因此这里代码会尽可能的转到nl80211上去wireless_send_event 会通过构建nlmsg发到内核netlink队列里然后同nl80211进行实现不过也有可能WIFI驱动定义了自己的 标准的IOCTL的实现函数这里不再分析。 */staticintioctl_standard_call(structnet_device*dev,structiwreq*iwr,unsignedintcmd,structiw_request_info*info,iw_handler handler){conststructiw_ioctl_description*descr;intret-EINVAL;/* Get the description of the IOCTL */if((cmd-SIOCIWFIRST)standard_ioctl_num)return-EOPNOTSUPP;descr(standard_ioctl);/* 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 */rethandler(dev,info,(iwr-u),NULL);/* Generate an event to notify listeners of the change */if((descr-flagsIW_DESCR_FLAG_EVENT)((ret0)||(ret-EIWCOMMIT)))wireless_send_event(dev,cmd,(iwr-u),NULL);}else{retioctl_standard_iw_point(iwr-u.data,cmd,descr,handler,dev,info);}/* Call commit handler if needed and defined */if(ret-EIWCOMMIT)retcall_commit_handler(dev);/* Here, we will generate the appropriate event if needed */returnret;}/* private函数实现 由于这里的ioctl都不是标准的因此只能通过驱动中自定义的ioctl来实现 */staticintioctl_private_call(structnet_device*dev,structiwreq*iwr,unsignedintcmd,structiw_request_info*info,iw_handler handler){intextra_size0,ret-EINVAL;conststructiw_priv_args*descr;extra_sizeget_priv_descr_and_size(dev,cmd,descr);/* Check if we have a pointer to user space data or not. */if(extra_size0){/* No extra arguments. Trivial to handle */rethandler(dev,info,(iwr-u),(char*)(iwr-u));}else{retioctl_private_iw_point(iwr-u.data,cmd,descr,handler,dev,info,extra_size);}/* Call commit handler if needed and defined */if(ret-EIWCOMMIT)retcall_commit_handler(dev);returnret;}最后在来分析wireless_process_ioctl函数/* ioctl分发实现函数 */staticintwireless_process_ioctl(structnet*net,structifreq*ifr,unsignedintcmd,structiw_request_info*info,wext_ioctl_func standard,wext_ioctl_func private){structiwreq*iwr(structiwreq*)ifr;structnet_device*dev;iw_handler handler;/* Permissions are already checked in dev_ioctl() before calling us. * The copy_to/from_user() of ifr is also dealt with in there *//* Make sure the device exist */if((dev__dev_get_by_name(net,ifr-ifr_name))NULL)return-ENODEV;/* 调用标准实现 *//* A bunch of special cases, then the generic case... * Note that cmd is already filtered in dev_ioctl() with * (cmd SIOCIWFIRST cmd SIOCIWLAST) */if(cmdSIOCGIWSTATS)returnstandard(dev,iwr,cmd,info,iw_handler_get_iwstats);if(cmdSIOCGIWPRIVdev-wireless_handlers)returnstandard(dev,iwr,cmd,info,iw_handler_get_private);/* Basic check */if(!netif_device_present(dev))return-ENODEV;/* 如果WIFI驱动定义了自己的ioctl的实现函数那么这里就可以处理 *//* New driver API : try to find the handler */handlerget_handler(dev,cmd);if(handler){/* Standard and private are not the same */if(cmdSIOCIWFIRSTPRIV)returnstandard(dev,iwr,cmd,info,handler);elsereturnprivate(dev,iwr,cmd,info,handler);}/* 如果WIFI驱动没有定义自己的ioctl实现但是定义了ndo_do_ioctl函数也可以调用该函数进行实现 *//* Old driver API : call driver ioctl handler */if(dev-netdev_ops-ndo_do_ioctl)returndev-netdev_ops-ndo_do_ioctl(dev,ifr,cmd);return-EOPNOTSUPP;}

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价