概述
应用层调用:
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 %dn",
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模块进行调用。
最后
以上就是纯情大树为你收集整理的netlink 与 socket的全部内容,希望文章能够帮你解决netlink 与 socket所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复