netlink 与 socket


  
  

    
    
netlink对socket函数的实现(v2.6.18)
应用层调用:
skfd = socket(PF_NETLINK, SOCK_RAW, NL_IMP2);
/net/socket.c:
中有一个全局变量,它存储协议族:
static struct net_proto_family *net_families[NPROTO];
 struct net_proto_family {
         int             family;
         int             (*create)(struct socket *sock, int protocol);  (注1)         
         short           authentication;
         short           encryption;
         short           encrypt_net;
         struct module   *owner;
 };




系统调用:
asmlinkage long sys_socket(int family, int type, int protocol)
继续调用:
int sock_create(int family, int type, int protocol, struct socket **res)
继续调用:
static int __sock_create(int family, int type, int protocol, struct socket **res, int kern)
其中有一句:
if ((err = net_families[family]->create(sock, protocol)) < 0) {
               sock->ops = NULL;
               goto out_module_put;
}
说明它是调用协议族规定的create回调函数(见注1)
那么,我们需要知道netlink协议的协议族( net_proto_family)是什么时候进入全局变量net_families里的,继续向下看,发现有一个函数
int sock_register(struct net_proto_family *ops)
{
int err;
if (ops->family >= NPROTO) {
printk(KERN_CRIT "protocol %d >= NPROTO(%d)\n", ops->family, NPROTO);
return -ENOBUFS;
}
net_family_write_lock();
err = -EEXIST;
if (net_families[ops->family] == NULL) {        (注2)
net_families[ops->family]=ops;
err = 0;
}
net_family_write_unlock();
printk(KERN_INFO "NET: Registered protocol family %d\n",
ops->family);
return err;
}
系统是在这个函数中给全局变量net_families赋值的(见注2)。那netlink一定有调用 sock_register函数,搜源代码。。。。
发现在/net/netlink/af_netlink.c中有一个函数static int __init netlink_proto_init(void)。
此函数中调用了注册协议族的函数:
 sock_register(&netlink_family_ops);
而netlink_family_ops是netlink的一个全局变量:
static struct net_proto_family netlink_family_ops = {
       .family = PF_NETLINK,
       .create = netlink_create,(注3)
       .owner  = THIS_MODULE,  /* for consistency 8) */
};
由此可见,socket最终是调用netlink模块的netlink_create回调来创建netlink的“特殊”socket的(见注3)


struct socket {
       socket_state            state;
       unsigned long           flags;
       const struct proto_ops  *ops;
       struct fasync_struct    *fasync_list;
       struct file             *file;
       struct sock             *sk;
       wait_queue_head_t       wait;
       short                   type;
};


struct netlink_sock {
       /* struct sock has to be the first member of netlink_sock */
   struct sock             sk;
       u32                     pid;
       u32                     dst_pid;
       u32                     dst_group;
       u32                     flags;
       u32                     subscriptions;
       u32                     ngroups;
       unsigned long           *groups;
       unsigned long           state;
       wait_queue_head_t       wait;
       struct netlink_callback *cb;
       spinlock_t              cb_lock;
       void                    (*data_ready)(struct sock *sk, int bytes);
       struct module           *module;
};




由以上两个结构可见 netlink_socket的第一个元素就是系统标准的socket,它是对系统标准socket的一个封装,这样也方便由netlink_sock强转成标准socket,保持的兼容性








再往后,netlink _create函数会调用内部函数 __netlink_create;
static int __netlink_create(struct socket *sock, int protocol)
 {
         struct sock *sk;
         struct netlink_sock *nlk;
 
         sock->ops = &netlink_ops;
 
         sk = sk_alloc(PF_NETLINK, GFP_KERNEL, &netlink_proto, 1);
         if (!sk)
                 return -ENOMEM;
 
         sock_init_data(sock, sk);
 
         nlk = nlk_sk(sk);
         spin_lock_init(&nlk->cb_lock);
         init_waitqueue_head(&nlk->wait);
 
         sk->sk_destruct = netlink_sock_destruct;
         sk->sk_protocol = protocol;
         return 0;
 }
 此函数有一句 sock->ops = &netlink_ops; 实际上netlink_ops是netlink模块的一个全局常量,它表示着socket所关联的一系列操作
 
static const struct proto_ops netlink_ops = {
        .family =       PF_NETLINK,
        .owner =        THIS_MODULE,
        .release =      netlink_release,
        .bind =         netlink_bind,
        .connect =      netlink_connect,
        .socketpair =   sock_no_socketpair,
        .accept =       sock_no_accept,
        .getname =      netlink_getname,
        .poll =         datagram_poll,
        .ioctl =        sock_no_ioctl,
        .listen =       sock_no_listen,
        .shutdown =     sock_no_shutdown,
        .setsockopt =   netlink_setsockopt,
        .getsockopt =   netlink_getsockopt,
        .sendmsg =      netlink_sendmsg,
        .recvmsg =      netlink_recvmsg,
        .mmap =         sock_no_mmap,
        .sendpage =     sock_no_sendpage,
};




二、关于bind
 
应用层调用 bind(skfd, (struct sockaddr*)&local, sizeof(local));
系统调用:/net/socket.c
asmlinkage long sys_bind(int fd, struct sockaddr __user *umyaddr, int addrlen)
{
        struct socket *sock;
        char address[MAX_SOCK_ADDR];
        int err, fput_needed;




        if((sock = sockfd_lookup_light(fd, &err, &fput_needed))!=NULL)     //找到fd对应的的socket
        {
                if((err=move_addr_to_kernel(umyaddr,addrlen,address))>=0) {
                        err = security_socket_bind(sock, (struct sockaddr *)address, addrlen);
                        if (!err)
                                err = sock->ops->bind(sock,(struct sockaddr *)address, addrlen);  //将address 和socket绑定
                }
                fput_light(sock->file, fput_needed);
        }                       
        return err;
}




所以  err = sock->ops->bind(sock,(struct sockaddr *)address, addrlen); 实质上是调用netlink的bind函数。此时标准的addr被转成netlink的地址格式
并通过 netlink_update_subscriptions(sk, nlk->subscriptions + hweight32(nladdr->nl_groups) - hweight32(nlk->groups[0]));来将相关信息组织起来(详情以后分析)




总结
其它函数的实现与此类似也是最终转到了netlink模块进行调用。






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值