⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 af_netlink.c

📁 《嵌入式系统设计与实例开发实验教材二源码》Linux内核移植与编译实验
💻 C
📖 第 1 页 / 共 2 页
字号:
			continue;		}		sock_hold(sk);		if (skb2 == NULL) {			if (atomic_read(&skb->users) != 1) {				skb2 = skb_clone(skb, allocation);			} else {				skb2 = skb;				atomic_inc(&skb->users);			}		}		if (skb2 == NULL) {			netlink_overrun(sk);			/* Clone failed. Notify ALL listeners. */			failure = 1;		} else if (netlink_broadcast_deliver(sk, skb2)) {			netlink_overrun(sk);		} else			skb2 = NULL;		sock_put(sk);	}	netlink_unlock_table();	if (skb2)		kfree_skb(skb2);	kfree_skb(skb);}void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code){	struct sock *sk;	int protocol = ssk->protocol;	read_lock(&nl_table_lock);	for (sk = nl_table[protocol]; sk; sk = sk->next) {		if (ssk == sk)			continue;		if (sk->protinfo.af_netlink->pid == pid ||		    !(sk->protinfo.af_netlink->groups&group))			continue;		sk->err = code;		sk->error_report(sk);	}	read_unlock(&nl_table_lock);}static int netlink_sendmsg(struct socket *sock, struct msghdr *msg, int len,			   struct scm_cookie *scm){	struct sock *sk = sock->sk;	struct sockaddr_nl *addr=msg->msg_name;	u32 dst_pid;	u32 dst_groups;	struct sk_buff *skb;	int err;	if (msg->msg_flags&MSG_OOB)		return -EOPNOTSUPP;	if (msg->msg_namelen) {		if (addr->nl_family != AF_NETLINK)			return -EINVAL;		dst_pid = addr->nl_pid;		dst_groups = addr->nl_groups;		if (dst_groups && !capable(CAP_NET_ADMIN))			return -EPERM;	} else {		dst_pid = sk->protinfo.af_netlink->dst_pid;		dst_groups = sk->protinfo.af_netlink->dst_groups;	}	if (!sk->protinfo.af_netlink->pid) {		err = netlink_autobind(sock);		if (err)			goto out;	}	err = -EMSGSIZE;	if ((unsigned)len > sk->sndbuf-32)		goto out;	err = -ENOBUFS;	skb = alloc_skb(len, GFP_KERNEL);	if (skb==NULL)		goto out;	NETLINK_CB(skb).pid = sk->protinfo.af_netlink->pid;	NETLINK_CB(skb).groups = sk->protinfo.af_netlink->groups;	NETLINK_CB(skb).dst_pid = dst_pid;	NETLINK_CB(skb).dst_groups = dst_groups;	memcpy(NETLINK_CREDS(skb), &scm->creds, sizeof(struct ucred));	/* What can I do? Netlink is asynchronous, so that	   we will have to save current capabilities to	   check them, when this message will be delivered	   to corresponding kernel module.   --ANK (980802)	 */	NETLINK_CB(skb).eff_cap = current->cap_effective;	err = -EFAULT;	if (memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len)) {		kfree_skb(skb);		goto out;	}	if (dst_groups) {		atomic_inc(&skb->users);		netlink_broadcast(sk, skb, dst_pid, dst_groups, GFP_KERNEL);	}	err = netlink_unicast(sk, skb, dst_pid, msg->msg_flags&MSG_DONTWAIT);out:	return err;}static int netlink_recvmsg(struct socket *sock, struct msghdr *msg, int len,			   int flags, struct scm_cookie *scm){	struct sock *sk = sock->sk;	int noblock = flags&MSG_DONTWAIT;	int copied;	struct sk_buff *skb;	int err;	if (flags&MSG_OOB)		return -EOPNOTSUPP;	copied = 0;	skb = skb_recv_datagram(sk,flags,noblock,&err);	if (skb==NULL)		goto out;	msg->msg_namelen = 0;	copied = skb->len;	if (len < copied) {		msg->msg_flags |= MSG_TRUNC;		copied = len;	}	skb->h.raw = skb->data;	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);	if (msg->msg_name) {		struct sockaddr_nl *addr = (struct sockaddr_nl*)msg->msg_name;		addr->nl_family = AF_NETLINK;		addr->nl_pid	= NETLINK_CB(skb).pid;		addr->nl_groups	= NETLINK_CB(skb).dst_groups;		msg->msg_namelen = sizeof(*addr);	}	scm->creds = *NETLINK_CREDS(skb);	skb_free_datagram(sk, skb);	if (sk->protinfo.af_netlink->cb	    && atomic_read(&sk->rmem_alloc) <= sk->rcvbuf/2)		netlink_dump(sk);out:	if (skb_queue_len(&sk->receive_queue) <= sk->rcvbuf/2) {		if (skb_queue_len(&sk->receive_queue) == 0)			clear_bit(0, &sk->protinfo.af_netlink->state);		if (!test_bit(0, &sk->protinfo.af_netlink->state))			wake_up_interruptible(&sk->protinfo.af_netlink->wait);	}	return err ? : copied;}void netlink_data_ready(struct sock *sk, int len){	if (sk->protinfo.af_netlink->data_ready)		sk->protinfo.af_netlink->data_ready(sk, len);	if (skb_queue_len(&sk->receive_queue) <= sk->rcvbuf/2) {		if (skb_queue_len(&sk->receive_queue) == 0)			clear_bit(0, &sk->protinfo.af_netlink->state);		if (!test_bit(0, &sk->protinfo.af_netlink->state))			wake_up_interruptible(&sk->protinfo.af_netlink->wait);	}}/* *	We export these functions to other modules. They provide a  *	complete set of kernel non-blocking support for message *	queueing. */struct sock *netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len)){	struct socket *sock;	struct sock *sk;	if (unit<0 || unit>=MAX_LINKS)		return NULL;	if (!(sock = sock_alloc())) 		return NULL;	sock->type = SOCK_RAW;	if (netlink_create(sock, unit) < 0) {		sock_release(sock);		return NULL;	}	sk = sock->sk;	sk->data_ready = netlink_data_ready;	if (input)		sk->protinfo.af_netlink->data_ready = input;	netlink_insert(sk, 0);	return sk;}static void netlink_destroy_callback(struct netlink_callback *cb){	if (cb->skb)		kfree_skb(cb->skb);	kfree(cb);}/* * It looks a bit ugly. * It would be better to create kernel thread. */static int netlink_dump(struct sock *sk){	struct netlink_callback *cb;	struct sk_buff *skb;	struct nlmsghdr *nlh;	int len;		skb = sock_rmalloc(sk, NLMSG_GOODSIZE, 0, GFP_KERNEL);	if (!skb)		return -ENOBUFS;	spin_lock(&sk->protinfo.af_netlink->cb_lock);	cb = sk->protinfo.af_netlink->cb;	if (cb == NULL) {		spin_unlock(&sk->protinfo.af_netlink->cb_lock);		kfree_skb(skb);		return -EINVAL;	}	len = cb->dump(skb, cb);	if (len > 0) {		spin_unlock(&sk->protinfo.af_netlink->cb_lock);		skb_queue_tail(&sk->receive_queue, skb);		sk->data_ready(sk, len);		return 0;	}	nlh = __nlmsg_put(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, NLMSG_DONE, sizeof(int));	nlh->nlmsg_flags |= NLM_F_MULTI;	memcpy(NLMSG_DATA(nlh), &len, sizeof(len));	skb_queue_tail(&sk->receive_queue, skb);	sk->data_ready(sk, skb->len);	cb->done(cb);	sk->protinfo.af_netlink->cb = NULL;	spin_unlock(&sk->protinfo.af_netlink->cb_lock);	netlink_destroy_callback(cb);	sock_put(sk);	return 0;}int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,		       struct nlmsghdr *nlh,		       int (*dump)(struct sk_buff *skb, struct netlink_callback*),		       int (*done)(struct netlink_callback*)){	struct netlink_callback *cb;	struct sock *sk;	cb = kmalloc(sizeof(*cb), GFP_KERNEL);	if (cb == NULL)		return -ENOBUFS;	memset(cb, 0, sizeof(*cb));	cb->dump = dump;	cb->done = done;	cb->nlh = nlh;	atomic_inc(&skb->users);	cb->skb = skb;	sk = netlink_lookup(ssk->protocol, NETLINK_CB(skb).pid);	if (sk == NULL) {		netlink_destroy_callback(cb);		return -ECONNREFUSED;	}	/* A dump is in progress... */	spin_lock(&sk->protinfo.af_netlink->cb_lock);	if (sk->protinfo.af_netlink->cb) {		spin_unlock(&sk->protinfo.af_netlink->cb_lock);		netlink_destroy_callback(cb);		sock_put(sk);		return -EBUSY;	}	sk->protinfo.af_netlink->cb = cb;	spin_unlock(&sk->protinfo.af_netlink->cb_lock);	netlink_dump(sk);	return 0;}void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err){	struct sk_buff *skb;	struct nlmsghdr *rep;	struct nlmsgerr *errmsg;	int size;	if (err == 0)		size = NLMSG_SPACE(sizeof(struct nlmsgerr));	else		size = NLMSG_SPACE(4 + NLMSG_ALIGN(nlh->nlmsg_len));	skb = alloc_skb(size, GFP_KERNEL);	if (!skb)		return;	rep = __nlmsg_put(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq,			  NLMSG_ERROR, sizeof(struct nlmsgerr));	errmsg = NLMSG_DATA(rep);	errmsg->error = err;	memcpy(&errmsg->msg, nlh, err ? nlh->nlmsg_len : sizeof(struct nlmsghdr));	netlink_unicast(in_skb->sk, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);}#ifdef NL_EMULATE_DEVstatic rwlock_t nl_emu_lock = RW_LOCK_UNLOCKED;/* *	Backward compatibility. */	 int netlink_attach(int unit, int (*function)(int, struct sk_buff *skb)){	struct sock *sk = netlink_kernel_create(unit, NULL);	if (sk == NULL)		return -ENOBUFS;	sk->protinfo.af_netlink->handler = function;	write_lock_bh(&nl_emu_lock);	netlink_kernel[unit] = sk->socket;	write_unlock_bh(&nl_emu_lock);	return 0;}void netlink_detach(int unit){	struct socket *sock;	write_lock_bh(&nl_emu_lock);	sock = netlink_kernel[unit];	netlink_kernel[unit] = NULL;	write_unlock_bh(&nl_emu_lock);	sock_release(sock);}int netlink_post(int unit, struct sk_buff *skb){	struct socket *sock;	read_lock(&nl_emu_lock);	sock = netlink_kernel[unit];	if (sock) {		struct sock *sk = sock->sk;		memset(skb->cb, 0, sizeof(skb->cb));		sock_hold(sk);		read_unlock(&nl_emu_lock);		netlink_broadcast(sk, skb, 0, ~0, GFP_ATOMIC);		sock_put(sk);		return 0;	}	read_unlock(&nl_emu_lock);	return -EUNATCH;}#endif#ifdef CONFIG_PROC_FSstatic int netlink_read_proc(char *buffer, char **start, off_t offset,			     int length, int *eof, void *data){	off_t pos=0;	off_t begin=0;	int len=0;	int i;	struct sock *s;		len+= sprintf(buffer,"sk       Eth Pid    Groups   "		      "Rmem     Wmem     Dump     Locks\n");		for (i=0; i<MAX_LINKS; i++) {		read_lock(&nl_table_lock);		for (s = nl_table[i]; s; s = s->next) {			len+=sprintf(buffer+len,"%p %-3d %-6d %08x %-8d %-8d %p %d",				     s,				     s->protocol,				     s->protinfo.af_netlink->pid,				     s->protinfo.af_netlink->groups,				     atomic_read(&s->rmem_alloc),				     atomic_read(&s->wmem_alloc),				     s->protinfo.af_netlink->cb,				     atomic_read(&s->refcnt)				     );			buffer[len++]='\n';					pos=begin+len;			if(pos<offset) {				len=0;				begin=pos;			}			if(pos>offset+length) {				read_unlock(&nl_table_lock);				goto done;			}		}		read_unlock(&nl_table_lock);	}	*eof = 1;done:	*start=buffer+(offset-begin);	len-=(offset-begin);	if(len>length)		len=length;	if(len<0)		len=0;	return len;}#endifstruct proto_ops netlink_ops = {	family:		PF_NETLINK,	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:	sock_no_setsockopt,	getsockopt:	sock_no_getsockopt,	sendmsg:	netlink_sendmsg,	recvmsg:	netlink_recvmsg,	mmap:		sock_no_mmap,	sendpage:	sock_no_sendpage,};struct net_proto_family netlink_family_ops = {	PF_NETLINK,	netlink_create};static int __init netlink_proto_init(void){	struct sk_buff *dummy_skb;	if (sizeof(struct netlink_skb_parms) > sizeof(dummy_skb->cb)) {		printk(KERN_CRIT "netlink_init: panic\n");		return -1;	}	sock_register(&netlink_family_ops);#ifdef CONFIG_PROC_FS	create_proc_read_entry("net/netlink", 0, 0, netlink_read_proc, NULL);#endif	return 0;}static void __exit netlink_proto_exit(void){       sock_unregister(PF_NETLINK);       remove_proc_entry("net/netlink", NULL);}module_init(netlink_proto_init);module_exit(netlink_proto_exit);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -