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

本文转载自http://blog.chinaunix.net/u1/38994/showart_1107738.html

 

 

浅析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,
} ;
网卡控制因为涉及到的知识点比较多, 上面只是从宏观上对数据流程做了一个简单的介绍, 深入到其中的每个知识点, 都会牵扯出一系列文章, 读者需要自己去一个个的慢慢深入, 希望本文能够对刚刚接触网络驱动的读者有所帮助和启发

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值