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

📄 xfrm_user.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 2 页
字号:
	memcpy(&xp->selector, &p->sel, sizeof(xp->selector));	memcpy(&xp->lft, &p->lft, sizeof(xp->lft));	xp->action = p->action;	xp->flags = p->flags;	xp->family = p->sel.family;	/* XXX xp->share = p->share; */}static void copy_to_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy_info *p, int dir){	memcpy(&p->sel, &xp->selector, sizeof(p->sel));	memcpy(&p->lft, &xp->lft, sizeof(p->lft));	memcpy(&p->curlft, &xp->curlft, sizeof(p->curlft));	p->priority = xp->priority;	p->index = xp->index;	p->sel.family = xp->family;	p->dir = dir;	p->action = xp->action;	p->flags = xp->flags;	p->share = XFRM_SHARE_ANY; /* XXX xp->share */}static struct xfrm_policy *xfrm_policy_construct(struct xfrm_userpolicy_info *p, struct rtattr **xfrma, int *errp){	struct xfrm_policy *xp = xfrm_policy_alloc(GFP_KERNEL);	int err;	if (!xp) {		*errp = -ENOMEM;		return NULL;	}	copy_from_user_policy(xp, p);	err = copy_from_user_tmpl(xp, xfrma);	if (err) {		*errp = err;		kfree(xp);		xp = NULL;	}	return xp;}static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma){	struct xfrm_userpolicy_info *p = NLMSG_DATA(nlh);	struct xfrm_policy *xp;	int err;	int excl;	err = verify_newpolicy_info(p);	if (err)		return err;	xp = xfrm_policy_construct(p, (struct rtattr **) xfrma, &err);	if (!xp)		return err;	excl = nlh->nlmsg_type == XFRM_MSG_NEWPOLICY;	err = xfrm_policy_insert(p->dir, xp, excl);	if (err) {		kfree(xp);		return err;	}	xfrm_pol_put(xp);	return 0;}static int copy_to_user_tmpl(struct xfrm_policy *xp, struct sk_buff *skb){	struct xfrm_user_tmpl vec[XFRM_MAX_DEPTH];	int i;	if (xp->xfrm_nr == 0)		return 0;	for (i = 0; i < xp->xfrm_nr; i++) {		struct xfrm_user_tmpl *up = &vec[i];		struct xfrm_tmpl *kp = &xp->xfrm_vec[i];		memcpy(&up->id, &kp->id, sizeof(up->id));		up->family = xp->family;		memcpy(&up->saddr, &kp->saddr, sizeof(up->saddr));		up->reqid = kp->reqid;		up->mode = kp->mode;		up->share = kp->share;		up->optional = kp->optional;		up->aalgos = kp->aalgos;		up->ealgos = kp->ealgos;		up->calgos = kp->calgos;	}	RTA_PUT(skb, XFRMA_TMPL,		(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr),		vec);	return 0;rtattr_failure:	return -1;}static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr){	struct xfrm_dump_info *sp = ptr;	struct xfrm_userpolicy_info *p;	struct sk_buff *in_skb = sp->in_skb;	struct sk_buff *skb = sp->out_skb;	struct nlmsghdr *nlh;	unsigned char *b = skb->tail;	if (sp->this_idx < sp->start_idx)		goto out;	nlh = NLMSG_PUT(skb, NETLINK_CB(in_skb).pid,			sp->nlmsg_seq,			XFRM_MSG_NEWPOLICY, sizeof(*p));	p = NLMSG_DATA(nlh);	nlh->nlmsg_flags = 0;	copy_to_user_policy(xp, p, dir);	if (copy_to_user_tmpl(xp, skb) < 0)		goto nlmsg_failure;	nlh->nlmsg_len = skb->tail - b;out:	sp->this_idx++;	return 0;nlmsg_failure:	skb_trim(skb, b - skb->data);	return -1;}static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb){	struct xfrm_dump_info info;	info.in_skb = cb->skb;	info.out_skb = skb;	info.nlmsg_seq = cb->nlh->nlmsg_seq;	info.this_idx = 0;	info.start_idx = cb->args[0];	(void) xfrm_policy_walk(dump_one_policy, &info);	cb->args[0] = info.this_idx;	return skb->len;}static struct sk_buff *xfrm_policy_netlink(struct sk_buff *in_skb,					  struct xfrm_policy *xp,					  int dir, u32 seq){	struct xfrm_dump_info info;	struct sk_buff *skb;	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);	if (!skb)		return ERR_PTR(-ENOMEM);	NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid;	info.in_skb = in_skb;	info.out_skb = skb;	info.nlmsg_seq = seq;	info.this_idx = info.start_idx = 0;	if (dump_one_policy(xp, dir, 0, &info) < 0) {		kfree_skb(skb);		return NULL;	}	return skb;}static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma){	struct xfrm_policy *xp;	struct xfrm_userpolicy_id *p;	int err;	int delete;	p = NLMSG_DATA(nlh);	delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY;	err = verify_policy_dir(p->dir);	if (err)		return err;	if (p->index)		xp = xfrm_policy_byid(p->dir, p->index, delete);	else		xp = xfrm_policy_bysel(p->dir, &p->sel, delete);	if (xp == NULL)		return -ENOENT;	if (!delete) {		struct sk_buff *resp_skb;		resp_skb = xfrm_policy_netlink(skb, xp, p->dir, nlh->nlmsg_seq);		if (IS_ERR(resp_skb)) {			err = PTR_ERR(resp_skb);		} else {			err = netlink_unicast(xfrm_nl, resp_skb,					      NETLINK_CB(skb).pid,					      MSG_DONTWAIT);		}	}	xfrm_pol_put(xp);	return err;}static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma){	struct xfrm_usersa_flush *p = NLMSG_DATA(nlh);	xfrm_state_flush(p->proto);	return 0;}static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma){	xfrm_policy_flush();	return 0;}static const int xfrm_msg_min[(XFRM_MSG_MAX + 1 - XFRM_MSG_BASE)] = {	NLMSG_LENGTH(sizeof(struct xfrm_usersa_info)),	/* NEW SA */	NLMSG_LENGTH(sizeof(struct xfrm_usersa_id)),	/* DEL SA */	NLMSG_LENGTH(sizeof(struct xfrm_usersa_id)),	/* GET SA */	NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_info)),/* NEW POLICY */	NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_id)),  /* DEL POLICY */	NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_id)),  /* GET POLICY */	NLMSG_LENGTH(sizeof(struct xfrm_userspi_info)),	/* ALLOC SPI */	NLMSG_LENGTH(sizeof(struct xfrm_user_acquire)),	/* ACQUIRE */	NLMSG_LENGTH(sizeof(struct xfrm_user_expire)),	/* EXPIRE */	NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_info)),/* UPD POLICY */	NLMSG_LENGTH(sizeof(struct xfrm_usersa_info)),	/* UPD SA */	NLMSG_LENGTH(sizeof(struct xfrm_user_polexpire)), /* POLEXPIRE */	NLMSG_LENGTH(sizeof(struct xfrm_usersa_flush)),	/* FLUSH SA */	NLMSG_LENGTH(0),				/* FLUSH POLICY */};static struct xfrm_link {	int (*doit)(struct sk_buff *, struct nlmsghdr *, void **);	int (*dump)(struct sk_buff *, struct netlink_callback *);} xfrm_dispatch[] = {	{	.doit	=	xfrm_add_sa, 		},	{	.doit	=	xfrm_del_sa, 		},	{		.doit	=	xfrm_get_sa,		.dump	=	xfrm_dump_sa,	},	{	.doit	=	xfrm_add_policy 	},	{	.doit	=	xfrm_get_policy 	},	{		.doit	=	xfrm_get_policy,		.dump	=	xfrm_dump_policy,	},	{	.doit	=	xfrm_alloc_userspi	},	{},	{},	{	.doit	=	xfrm_add_policy 	},	{	.doit	=	xfrm_add_sa, 		},	{},	{	.doit	=	xfrm_flush_sa		},	{	.doit	=	xfrm_flush_policy	},};static int xfrm_done(struct netlink_callback *cb){	return 0;}static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp){	struct rtattr *xfrma[XFRMA_MAX];	struct xfrm_link *link;	int type, min_len;	if (!(nlh->nlmsg_flags & NLM_F_REQUEST))		return 0;	type = nlh->nlmsg_type;	/* A control message: ignore them */	if (type < XFRM_MSG_BASE)		return 0;	/* Unknown message: reply with EINVAL */	if (type > XFRM_MSG_MAX)		goto err_einval;	type -= XFRM_MSG_BASE;	link = &xfrm_dispatch[type];	/* All operations require privileges, even GET */	if (security_netlink_recv(skb)) {		*errp = -EPERM;		return -1;	}	if ((type == 2 || type == 5) && (nlh->nlmsg_flags & NLM_F_DUMP)) {		u32 rlen;		if (link->dump == NULL)			goto err_einval;		if ((*errp = netlink_dump_start(xfrm_nl, skb, nlh,						link->dump,						xfrm_done)) != 0) {			return -1;		}		rlen = NLMSG_ALIGN(nlh->nlmsg_len);		if (rlen > skb->len)			rlen = skb->len;		skb_pull(skb, rlen);		return -1;	}	memset(xfrma, 0, sizeof(xfrma));	if (nlh->nlmsg_len < (min_len = xfrm_msg_min[type]))		goto err_einval;	if (nlh->nlmsg_len > min_len) {		int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len);		struct rtattr *attr = (void *) nlh + NLMSG_ALIGN(min_len);		while (RTA_OK(attr, attrlen)) {			unsigned short flavor = attr->rta_type;			if (flavor) {				if (flavor > XFRMA_MAX)					goto err_einval;				xfrma[flavor - 1] = attr;			}			attr = RTA_NEXT(attr, attrlen);		}	}	if (link->doit == NULL)		goto err_einval;	*errp = link->doit(skb, nlh, (void **) &xfrma);	return *errp;err_einval:	*errp = -EINVAL;	return -1;}static int xfrm_user_rcv_skb(struct sk_buff *skb){	int err;	struct nlmsghdr *nlh;	while (skb->len >= NLMSG_SPACE(0)) {		u32 rlen;		nlh = (struct nlmsghdr *) skb->data;		if (nlh->nlmsg_len < sizeof(*nlh) ||		    skb->len < nlh->nlmsg_len)			return 0;		rlen = NLMSG_ALIGN(nlh->nlmsg_len);		if (rlen > skb->len)			rlen = skb->len;		if (xfrm_user_rcv_msg(skb, nlh, &err) < 0) {			if (err == 0)				return -1;			netlink_ack(skb, nlh, err);		} else if (nlh->nlmsg_flags & NLM_F_ACK)			netlink_ack(skb, nlh, 0);		skb_pull(skb, rlen);	}	return 0;}static void xfrm_netlink_rcv(struct sock *sk, int len){	do {		struct sk_buff *skb;		down(&xfrm_cfg_sem);		while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {			if (xfrm_user_rcv_skb(skb)) {				if (skb->len)					skb_queue_head(&sk->sk_receive_queue,						       skb);				else					kfree_skb(skb);				break;			}			kfree_skb(skb);		}		up(&xfrm_cfg_sem);	} while (xfrm_nl && xfrm_nl->sk_receive_queue.qlen);}static int build_expire(struct sk_buff *skb, struct xfrm_state *x, int hard){	struct xfrm_user_expire *ue;	struct nlmsghdr *nlh;	unsigned char *b = skb->tail;	nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_EXPIRE,			sizeof(*ue));	ue = NLMSG_DATA(nlh);	nlh->nlmsg_flags = 0;	copy_to_user_state(x, &ue->state);	ue->hard = (hard != 0) ? 1 : 0;	nlh->nlmsg_len = skb->tail - b;	return skb->len;nlmsg_failure:	skb_trim(skb, b - skb->data);	return -1;}static int xfrm_send_state_notify(struct xfrm_state *x, int hard){	struct sk_buff *skb;	skb = alloc_skb(sizeof(struct xfrm_user_expire) + 16, GFP_ATOMIC);	if (skb == NULL)		return -ENOMEM;	if (build_expire(skb, x, hard) < 0)		BUG();	NETLINK_CB(skb).dst_groups = XFRMGRP_EXPIRE;	return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_EXPIRE, GFP_ATOMIC);}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;	unsigned char *b = skb->tail;	__u32 seq = xfrm_get_acqseq();	nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_ACQUIRE,			sizeof(*ua));	ua = NLMSG_DATA(nlh);	nlh->nlmsg_flags = 0;	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;	nlh->nlmsg_len = skb->tail - b;	return skb->len;nlmsg_failure:	skb_trim(skb, b - skb->data);	return -1;}static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt,			     struct xfrm_policy *xp, int dir){	struct sk_buff *skb;	size_t len;	len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr);	len += NLMSG_SPACE(sizeof(struct xfrm_user_acquire));	skb = alloc_skb(len, GFP_ATOMIC);	if (skb == NULL)		return -ENOMEM;	if (build_acquire(skb, x, xt, xp, dir) < 0)		BUG();	NETLINK_CB(skb).dst_groups = XFRMGRP_ACQUIRE;	return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_ACQUIRE, GFP_ATOMIC);}/* User gives us xfrm_user_policy_info followed by an array of 0 * or more templates. */struct xfrm_policy *xfrm_compile_policy(u16 family, 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 (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 (nr > XFRM_MAX_DEPTH)		return NULL;	xp = xfrm_policy_alloc(GFP_KERNEL);	if (xp == NULL) {		*dir = -ENOBUFS;		return NULL;	}	copy_from_user_policy(xp, p);	copy_templates(xp, ut, nr);	*dir = p->dir;	return xp;}static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp,			   int dir, int hard){	struct xfrm_user_polexpire *upe;	struct nlmsghdr *nlh;	unsigned char *b = skb->tail;	nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_POLEXPIRE, sizeof(*upe));	upe = NLMSG_DATA(nlh);	nlh->nlmsg_flags = 0;	copy_to_user_policy(xp, &upe->pol, dir);	if (copy_to_user_tmpl(xp, skb) < 0)		goto nlmsg_failure;	upe->hard = !!hard;	nlh->nlmsg_len = skb->tail - b;	return skb->len;nlmsg_failure:	skb_trim(skb, b - skb->data);	return -1;}static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, int hard){	struct sk_buff *skb;	size_t len;	len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr);	len += NLMSG_SPACE(sizeof(struct xfrm_user_polexpire));	skb = alloc_skb(len, GFP_ATOMIC);	if (skb == NULL)		return -ENOMEM;	if (build_polexpire(skb, xp, dir, hard) < 0)		BUG();	NETLINK_CB(skb).dst_groups = XFRMGRP_EXPIRE;	return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_EXPIRE, 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,};static int __init xfrm_user_init(void){	printk(KERN_INFO "Initializing IPsec netlink socket\n");	xfrm_nl = netlink_kernel_create(NETLINK_XFRM, xfrm_netlink_rcv);	if (xfrm_nl == NULL)		panic("xfrm_user_init: cannot initialize xfrm_nl\n");	xfrm_register_km(&netlink_mgr);	return 0;}static void __exit xfrm_user_exit(void){	xfrm_unregister_km(&netlink_mgr);	sock_release(xfrm_nl->sk_socket);}module_init(xfrm_user_init);module_exit(xfrm_user_exit);MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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