浅析ethx网卡控制函数ioctl实现具体流程

浅析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】

来源:http://blog.csdn.net/lcw_202/article/details/5993899

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值