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

📄 xfrm_user.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
};static struct xfrm_link {	int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **);	int (*dump)(struct sk_buff *, struct netlink_callback *);} xfrm_dispatch[XFRM_NR_MSGTYPES] = {	[XFRM_MSG_NEWSA       - XFRM_MSG_BASE] = { .doit = xfrm_add_sa        },	[XFRM_MSG_DELSA       - XFRM_MSG_BASE] = { .doit = xfrm_del_sa        },	[XFRM_MSG_GETSA       - XFRM_MSG_BASE] = { .doit = xfrm_get_sa,						   .dump = xfrm_dump_sa       },	[XFRM_MSG_NEWPOLICY   - XFRM_MSG_BASE] = { .doit = xfrm_add_policy    },	[XFRM_MSG_DELPOLICY   - XFRM_MSG_BASE] = { .doit = xfrm_get_policy    },	[XFRM_MSG_GETPOLICY   - XFRM_MSG_BASE] = { .doit = xfrm_get_policy,						   .dump = xfrm_dump_policy   },	[XFRM_MSG_ALLOCSPI    - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi },	[XFRM_MSG_ACQUIRE     - XFRM_MSG_BASE] = { .doit = xfrm_add_acquire   },	[XFRM_MSG_EXPIRE      - XFRM_MSG_BASE] = { .doit = xfrm_add_sa_expire },	[XFRM_MSG_UPDPOLICY   - XFRM_MSG_BASE] = { .doit = xfrm_add_policy    },	[XFRM_MSG_UPDSA       - XFRM_MSG_BASE] = { .doit = xfrm_add_sa        },	[XFRM_MSG_POLEXPIRE   - XFRM_MSG_BASE] = { .doit = xfrm_add_pol_expire},	[XFRM_MSG_FLUSHSA     - XFRM_MSG_BASE] = { .doit = xfrm_flush_sa      },	[XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_flush_policy  },	[XFRM_MSG_NEWAE       - XFRM_MSG_BASE] = { .doit = xfrm_new_ae  },	[XFRM_MSG_GETAE       - XFRM_MSG_BASE] = { .doit = xfrm_get_ae  },	[XFRM_MSG_MIGRATE     - XFRM_MSG_BASE] = { .doit = xfrm_do_migrate    },	[XFRM_MSG_GETSADINFO  - XFRM_MSG_BASE] = { .doit = xfrm_get_sadinfo   },	[XFRM_MSG_GETSPDINFO  - XFRM_MSG_BASE] = { .doit = xfrm_get_spdinfo   },};static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh){	struct nlattr *attrs[XFRMA_MAX+1];	struct xfrm_link *link;	int type, err;	type = nlh->nlmsg_type;	if (type > XFRM_MSG_MAX)		return -EINVAL;	type -= XFRM_MSG_BASE;	link = &xfrm_dispatch[type];	/* All operations require privileges, even GET */	if (security_netlink_recv(skb, CAP_NET_ADMIN))		return -EPERM;	if ((type == (XFRM_MSG_GETSA - XFRM_MSG_BASE) ||	     type == (XFRM_MSG_GETPOLICY - XFRM_MSG_BASE)) &&	    (nlh->nlmsg_flags & NLM_F_DUMP)) {		if (link->dump == NULL)			return -EINVAL;		return netlink_dump_start(xfrm_nl, skb, nlh, link->dump, NULL);	}	err = nlmsg_parse(nlh, xfrm_msg_min[type], attrs, XFRMA_MAX,			  xfrma_policy);	if (err < 0)		return err;	if (link->doit == NULL)		return -EINVAL;	return link->doit(skb, nlh, attrs);}static void xfrm_netlink_rcv(struct sk_buff *skb){	mutex_lock(&xfrm_cfg_mutex);	netlink_rcv_skb(skb, &xfrm_user_rcv_msg);	mutex_unlock(&xfrm_cfg_mutex);}static inline size_t xfrm_expire_msgsize(void){	return NLMSG_ALIGN(sizeof(struct xfrm_user_expire));}static int build_expire(struct sk_buff *skb, struct xfrm_state *x, struct km_event *c){	struct xfrm_user_expire *ue;	struct nlmsghdr *nlh;	nlh = nlmsg_put(skb, c->pid, 0, XFRM_MSG_EXPIRE, sizeof(*ue), 0);	if (nlh == NULL)		return -EMSGSIZE;	ue = nlmsg_data(nlh);	copy_to_user_state(x, &ue->state);	ue->hard = (c->data.hard != 0) ? 1 : 0;	return nlmsg_end(skb, nlh);}static int xfrm_exp_state_notify(struct xfrm_state *x, struct km_event *c){	struct sk_buff *skb;	skb = nlmsg_new(xfrm_expire_msgsize(), GFP_ATOMIC);	if (skb == NULL)		return -ENOMEM;	if (build_expire(skb, x, c) < 0)		BUG();	return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC);}static int xfrm_aevent_state_notify(struct xfrm_state *x, struct km_event *c){	struct sk_buff *skb;	skb = nlmsg_new(xfrm_aevent_msgsize(), GFP_ATOMIC);	if (skb == NULL)		return -ENOMEM;	if (build_aevent(skb, x, c) < 0)		BUG();	return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_AEVENTS, GFP_ATOMIC);}static int xfrm_notify_sa_flush(struct km_event *c){	struct xfrm_usersa_flush *p;	struct nlmsghdr *nlh;	struct sk_buff *skb;	int len = NLMSG_ALIGN(sizeof(struct xfrm_usersa_flush));	skb = nlmsg_new(len, GFP_ATOMIC);	if (skb == NULL)		return -ENOMEM;	nlh = nlmsg_put(skb, c->pid, c->seq, XFRM_MSG_FLUSHSA, sizeof(*p), 0);	if (nlh == NULL) {		kfree_skb(skb);		return -EMSGSIZE;	}	p = nlmsg_data(nlh);	p->proto = c->data.proto;	nlmsg_end(skb, nlh);	return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC);}static inline size_t xfrm_sa_len(struct xfrm_state *x){	size_t l = 0;	if (x->aalg)		l += nla_total_size(xfrm_alg_len(x->aalg));	if (x->ealg)		l += nla_total_size(xfrm_alg_len(x->ealg));	if (x->calg)		l += nla_total_size(sizeof(*x->calg));	if (x->encap)		l += nla_total_size(sizeof(*x->encap));	if (x->security)		l += nla_total_size(sizeof(struct xfrm_user_sec_ctx) +				    x->security->ctx_len);	if (x->coaddr)		l += nla_total_size(sizeof(*x->coaddr));	/* Must count this as this may become non-zero behind our back. */	l += nla_total_size(sizeof(x->lastused));	return l;}static int xfrm_notify_sa(struct xfrm_state *x, struct km_event *c){	struct xfrm_usersa_info *p;	struct xfrm_usersa_id *id;	struct nlmsghdr *nlh;	struct sk_buff *skb;	int len = xfrm_sa_len(x);	int headlen;	headlen = sizeof(*p);	if (c->event == XFRM_MSG_DELSA) {		len += nla_total_size(headlen);		headlen = sizeof(*id);	}	len += NLMSG_ALIGN(headlen);	skb = nlmsg_new(len, GFP_ATOMIC);	if (skb == NULL)		return -ENOMEM;	nlh = nlmsg_put(skb, c->pid, c->seq, c->event, headlen, 0);	if (nlh == NULL)		goto nla_put_failure;	p = nlmsg_data(nlh);	if (c->event == XFRM_MSG_DELSA) {		struct nlattr *attr;		id = nlmsg_data(nlh);		memcpy(&id->daddr, &x->id.daddr, sizeof(id->daddr));		id->spi = x->id.spi;		id->family = x->props.family;		id->proto = x->id.proto;		attr = nla_reserve(skb, XFRMA_SA, sizeof(*p));		if (attr == NULL)			goto nla_put_failure;		p = nla_data(attr);	}	if (copy_to_user_state_extra(x, p, skb))		goto nla_put_failure;	nlmsg_end(skb, nlh);	return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC);nla_put_failure:	/* Somebody screwed up with xfrm_sa_len! */	WARN_ON(1);	kfree_skb(skb);	return -1;}static int xfrm_send_state_notify(struct xfrm_state *x, struct km_event *c){	switch (c->event) {	case XFRM_MSG_EXPIRE:		return xfrm_exp_state_notify(x, c);	case XFRM_MSG_NEWAE:		return xfrm_aevent_state_notify(x, c);	case XFRM_MSG_DELSA:	case XFRM_MSG_UPDSA:	case XFRM_MSG_NEWSA:		return xfrm_notify_sa(x, c);	case XFRM_MSG_FLUSHSA:		return xfrm_notify_sa_flush(c);	default:		 printk("xfrm_user: Unknown SA event %d\n", c->event);		 break;	}	return 0;}static inline size_t xfrm_acquire_msgsize(struct xfrm_state *x,					  struct xfrm_policy *xp){	return NLMSG_ALIGN(sizeof(struct xfrm_user_acquire))	       + nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr)	       + nla_total_size(xfrm_user_sec_ctx_size(x->security))	       + userpolicy_type_attrsize();}static int build_acquire(struct sk_buff *skb, struct xfrm_state *x,			 struct xfrm_tmpl *xt, struct xfrm_policy *xp,			 int dir){	struct xfrm_user_acquire *ua;	struct nlmsghdr *nlh;	__u32 seq = xfrm_get_acqseq();	nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_ACQUIRE, sizeof(*ua), 0);	if (nlh == NULL)		return -EMSGSIZE;	ua = nlmsg_data(nlh);	memcpy(&ua->id, &x->id, sizeof(ua->id));	memcpy(&ua->saddr, &x->props.saddr, sizeof(ua->saddr));	memcpy(&ua->sel, &x->sel, sizeof(ua->sel));	copy_to_user_policy(xp, &ua->policy, dir);	ua->aalgos = xt->aalgos;	ua->ealgos = xt->ealgos;	ua->calgos = xt->calgos;	ua->seq = x->km.seq = seq;	if (copy_to_user_tmpl(xp, skb) < 0)		goto nlmsg_failure;	if (copy_to_user_state_sec_ctx(x, skb))		goto nlmsg_failure;	if (copy_to_user_policy_type(xp->type, skb) < 0)		goto nlmsg_failure;	return nlmsg_end(skb, nlh);nlmsg_failure:	nlmsg_cancel(skb, nlh);	return -EMSGSIZE;}static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt,			     struct xfrm_policy *xp, int dir){	struct sk_buff *skb;	skb = nlmsg_new(xfrm_acquire_msgsize(x, xp), GFP_ATOMIC);	if (skb == NULL)		return -ENOMEM;	if (build_acquire(skb, x, xt, xp, dir) < 0)		BUG();	return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_ACQUIRE, GFP_ATOMIC);}/* User gives us xfrm_user_policy_info followed by an array of 0 * or more templates. */static struct xfrm_policy *xfrm_compile_policy(struct sock *sk, int opt,					       u8 *data, int len, int *dir){	struct xfrm_userpolicy_info *p = (struct xfrm_userpolicy_info *)data;	struct xfrm_user_tmpl *ut = (struct xfrm_user_tmpl *) (p + 1);	struct xfrm_policy *xp;	int nr;	switch (sk->sk_family) {	case AF_INET:		if (opt != IP_XFRM_POLICY) {			*dir = -EOPNOTSUPP;			return NULL;		}		break;#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)	case AF_INET6:		if (opt != IPV6_XFRM_POLICY) {			*dir = -EOPNOTSUPP;			return NULL;		}		break;#endif	default:		*dir = -EINVAL;		return NULL;	}	*dir = -EINVAL;	if (len < sizeof(*p) ||	    verify_newpolicy_info(p))		return NULL;	nr = ((len - sizeof(*p)) / sizeof(*ut));	if (validate_tmpl(nr, ut, p->sel.family))		return NULL;	if (p->dir > XFRM_POLICY_OUT)		return NULL;	xp = xfrm_policy_alloc(GFP_KERNEL);	if (xp == NULL) {		*dir = -ENOBUFS;		return NULL;	}	copy_from_user_policy(xp, p);	xp->type = XFRM_POLICY_TYPE_MAIN;	copy_templates(xp, ut, nr);	*dir = p->dir;	return xp;}static inline size_t xfrm_polexpire_msgsize(struct xfrm_policy *xp){	return NLMSG_ALIGN(sizeof(struct xfrm_user_polexpire))	       + nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr)	       + nla_total_size(xfrm_user_sec_ctx_size(xp->security))	       + userpolicy_type_attrsize();}static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp,			   int dir, struct km_event *c){	struct xfrm_user_polexpire *upe;	struct nlmsghdr *nlh;	int hard = c->data.hard;	nlh = nlmsg_put(skb, c->pid, 0, XFRM_MSG_POLEXPIRE, sizeof(*upe), 0);	if (nlh == NULL)		return -EMSGSIZE;	upe = nlmsg_data(nlh);	copy_to_user_policy(xp, &upe->pol, dir);	if (copy_to_user_tmpl(xp, skb) < 0)		goto nlmsg_failure;	if (copy_to_user_sec_ctx(xp, skb))		goto nlmsg_failure;	if (copy_to_user_policy_type(xp->type, skb) < 0)		goto nlmsg_failure;	upe->hard = !!hard;	return nlmsg_end(skb, nlh);nlmsg_failure:	nlmsg_cancel(skb, nlh);	return -EMSGSIZE;}static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c){	struct sk_buff *skb;	skb = nlmsg_new(xfrm_polexpire_msgsize(xp), GFP_ATOMIC);	if (skb == NULL)		return -ENOMEM;	if (build_polexpire(skb, xp, dir, c) < 0)		BUG();	return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC);}static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event *c){	struct xfrm_userpolicy_info *p;	struct xfrm_userpolicy_id *id;	struct nlmsghdr *nlh;	struct sk_buff *skb;	int len = nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr);	int headlen;	headlen = sizeof(*p);	if (c->event == XFRM_MSG_DELPOLICY) {		len += nla_total_size(headlen);		headlen = sizeof(*id);	}	len += userpolicy_type_attrsize();	len += NLMSG_ALIGN(headlen);	skb = nlmsg_new(len, GFP_ATOMIC);	if (skb == NULL)		return -ENOMEM;	nlh = nlmsg_put(skb, c->pid, c->seq, c->event, headlen, 0);	if (nlh == NULL)		goto nlmsg_failure;	p = nlmsg_data(nlh);	if (c->event == XFRM_MSG_DELPOLICY) {		struct nlattr *attr;		id = nlmsg_data(nlh);		memset(id, 0, sizeof(*id));		id->dir = dir;		if (c->data.byid)			id->index = xp->index;		else			memcpy(&id->sel, &xp->selector, sizeof(id->sel));		attr = nla_reserve(skb, XFRMA_POLICY, sizeof(*p));		if (attr == NULL)			goto nlmsg_failure;		p = nla_data(attr);	}	copy_to_user_policy(xp, p, dir);	if (copy_to_user_tmpl(xp, skb) < 0)		goto nlmsg_failure;	if (copy_to_user_policy_type(xp->type, skb) < 0)		goto nlmsg_failure;	nlmsg_end(skb, nlh);	return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC);nlmsg_failure:	kfree_skb(skb);	return -1;}static int xfrm_notify_policy_flush(struct km_event *c){	struct nlmsghdr *nlh;	struct sk_buff *skb;	skb = nlmsg_new(userpolicy_type_attrsize(), GFP_ATOMIC);	if (skb == NULL)		return -ENOMEM;	nlh = nlmsg_put(skb, c->pid, c->seq, XFRM_MSG_FLUSHPOLICY, 0, 0);	if (nlh == NULL)		goto nlmsg_failure;	if (copy_to_user_policy_type(c->data.type, skb) < 0)		goto nlmsg_failure;	nlmsg_end(skb, nlh);	return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC);nlmsg_failure:	kfree_skb(skb);	return -1;}static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c){	switch (c->event) {	case XFRM_MSG_NEWPOLICY:	case XFRM_MSG_UPDPOLICY:	case XFRM_MSG_DELPOLICY:		return xfrm_notify_policy(xp, dir, c);	case XFRM_MSG_FLUSHPOLICY:		return xfrm_notify_policy_flush(c);	case XFRM_MSG_POLEXPIRE:		return xfrm_exp_policy_notify(xp, dir, c);	default:		printk("xfrm_user: Unknown Policy event %d\n", c->event);	}	return 0;}static inline size_t xfrm_report_msgsize(void){	return NLMSG_ALIGN(sizeof(struct xfrm_user_report));}static int build_report(struct sk_buff *skb, u8 proto,			struct xfrm_selector *sel, xfrm_address_t *addr){	struct xfrm_user_report *ur;	struct nlmsghdr *nlh;	nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_REPORT, sizeof(*ur), 0);	if (nlh == NULL)		return -EMSGSIZE;	ur = nlmsg_data(nlh);	ur->proto = proto;	memcpy(&ur->sel, sel, sizeof(ur->sel));	if (addr)		NLA_PUT(skb, XFRMA_COADDR, sizeof(*addr), addr);	return nlmsg_end(skb, nlh);nla_put_failure:	nlmsg_cancel(skb, nlh);	return -EMSGSIZE;}static int xfrm_send_report(u8 proto, struct xfrm_selector *sel,			    xfrm_address_t *addr){	struct sk_buff *skb;	skb = nlmsg_new(xfrm_report_msgsize(), GFP_ATOMIC);	if (skb == NULL)		return -ENOMEM;	if (build_report(skb, proto, sel, addr) < 0)		BUG();	return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_REPORT, GFP_ATOMIC);}static struct xfrm_mgr netlink_mgr = {	.id		= "netlink",	.notify		= xfrm_send_state_notify,	.acquire	= xfrm_send_acquire,	.compile_policy	= xfrm_compile_policy,	.notify_policy	= xfrm_send_policy_notify,	.report		= xfrm_send_report,	.migrate	= xfrm_send_migrate,};static int __init xfrm_user_init(void){	struct sock *nlsk;	printk(KERN_INFO "Initializing XFRM netlink socket\n");	nlsk = netlink_kernel_create(&init_net, NETLINK_XFRM, XFRMNLGRP_MAX,				     xfrm_netlink_rcv, NULL, THIS_MODULE);	if (nlsk == NULL)		return -ENOMEM;	rcu_assign_pointer(xfrm_nl, nlsk);	xfrm_register_km(&netlink_mgr);	return 0;}static void __exit xfrm_user_exit(void){	struct sock *nlsk = xfrm_nl;	xfrm_unregister_km(&netlink_mgr);	rcu_assign_pointer(xfrm_nl, NULL);	synchronize_rcu();	sock_release(nlsk->sk_socket);}module_init(xfrm_user_init);module_exit(xfrm_user_exit);MODULE_LICENSE("GPL");MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_XFRM);

⌨️ 快捷键说明

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