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模块进行调用。

标签