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

📄 af_key.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 5 页
字号:
	/* default error is no buffer space */	err = -ENOBUFS;	/* RFC2367:   Only SADB_SASTATE_MATURE SAs may be submitted in an SADB_ADD message.   SADB_SASTATE_LARVAL SAs are created by SADB_GETSPI and it is not   sensible to add a new SA in the DYING or SADB_SASTATE_DEAD state.   Therefore, the sadb_sa_state field of all submitted SAs MUST be   SADB_SASTATE_MATURE and the kernel MUST return an error if this is   not true.           However, KAME setkey always uses SADB_SASTATE_LARVAL.	   Hence, we have to _ignore_ sadb_sa_state, which is also reasonable.	 */	if (sa->sadb_sa_auth > SADB_AALG_MAX ||	    (hdr->sadb_msg_satype == SADB_X_SATYPE_IPCOMP &&	     sa->sadb_sa_encrypt > SADB_X_CALG_MAX) ||	    sa->sadb_sa_encrypt > SADB_EALG_MAX)		return ERR_PTR(-EINVAL);	key = (struct sadb_key*) ext_hdrs[SADB_EXT_KEY_AUTH-1];	if (key != NULL &&	    sa->sadb_sa_auth != SADB_X_AALG_NULL &&	    ((key->sadb_key_bits+7) / 8 == 0 ||	     (key->sadb_key_bits+7) / 8 > key->sadb_key_len * sizeof(uint64_t)))		return ERR_PTR(-EINVAL);	key = ext_hdrs[SADB_EXT_KEY_ENCRYPT-1];	if (key != NULL &&	    sa->sadb_sa_encrypt != SADB_EALG_NULL &&	    ((key->sadb_key_bits+7) / 8 == 0 ||	     (key->sadb_key_bits+7) / 8 > key->sadb_key_len * sizeof(uint64_t)))		return ERR_PTR(-EINVAL);	x = xfrm_state_alloc();	if (x == NULL)		return ERR_PTR(-ENOBUFS);	x->id.proto = proto;	x->id.spi = sa->sadb_sa_spi;	x->props.replay_window = sa->sadb_sa_replay;	if (sa->sadb_sa_flags & SADB_SAFLAGS_NOECN)		x->props.flags |= XFRM_STATE_NOECN;	if (sa->sadb_sa_flags & SADB_SAFLAGS_DECAP_DSCP)		x->props.flags |= XFRM_STATE_DECAP_DSCP;	lifetime = (struct sadb_lifetime*) ext_hdrs[SADB_EXT_LIFETIME_HARD-1];	if (lifetime != NULL) {		x->lft.hard_packet_limit = _KEY2X(lifetime->sadb_lifetime_allocations);		x->lft.hard_byte_limit = _KEY2X(lifetime->sadb_lifetime_bytes);		x->lft.hard_add_expires_seconds = lifetime->sadb_lifetime_addtime;		x->lft.hard_use_expires_seconds = lifetime->sadb_lifetime_usetime;	}	lifetime = (struct sadb_lifetime*) ext_hdrs[SADB_EXT_LIFETIME_SOFT-1];	if (lifetime != NULL) {		x->lft.soft_packet_limit = _KEY2X(lifetime->sadb_lifetime_allocations);		x->lft.soft_byte_limit = _KEY2X(lifetime->sadb_lifetime_bytes);		x->lft.soft_add_expires_seconds = lifetime->sadb_lifetime_addtime;		x->lft.soft_use_expires_seconds = lifetime->sadb_lifetime_usetime;	}	key = (struct sadb_key*) ext_hdrs[SADB_EXT_KEY_AUTH-1];	if (sa->sadb_sa_auth) {		int keysize = 0;		struct xfrm_algo_desc *a = xfrm_aalg_get_byid(sa->sadb_sa_auth);		if (!a) {			err = -ENOSYS;			goto out;		}		if (key)			keysize = (key->sadb_key_bits + 7) / 8;		x->aalg = kmalloc(sizeof(*x->aalg) + keysize, GFP_KERNEL);		if (!x->aalg)			goto out;		strcpy(x->aalg->alg_name, a->name);		x->aalg->alg_key_len = 0;		if (key) {			x->aalg->alg_key_len = key->sadb_key_bits;			memcpy(x->aalg->alg_key, key+1, keysize);		}		x->props.aalgo = sa->sadb_sa_auth;		/* x->algo.flags = sa->sadb_sa_flags; */	}	if (sa->sadb_sa_encrypt) {		if (hdr->sadb_msg_satype == SADB_X_SATYPE_IPCOMP) {			struct xfrm_algo_desc *a = xfrm_calg_get_byid(sa->sadb_sa_encrypt);			if (!a) {				err = -ENOSYS;				goto out;			}			x->calg = kmalloc(sizeof(*x->calg), GFP_KERNEL);			if (!x->calg)				goto out;			strcpy(x->calg->alg_name, a->name);			x->props.calgo = sa->sadb_sa_encrypt;		} else {			int keysize = 0;			struct xfrm_algo_desc *a = xfrm_ealg_get_byid(sa->sadb_sa_encrypt);			if (!a) {				err = -ENOSYS;				goto out;			}			key = (struct sadb_key*) ext_hdrs[SADB_EXT_KEY_ENCRYPT-1];			if (key)				keysize = (key->sadb_key_bits + 7) / 8;			x->ealg = kmalloc(sizeof(*x->ealg) + keysize, GFP_KERNEL);			if (!x->ealg)				goto out;			strcpy(x->ealg->alg_name, a->name);			x->ealg->alg_key_len = 0;			if (key) {				x->ealg->alg_key_len = key->sadb_key_bits;				memcpy(x->ealg->alg_key, key+1, keysize);			}			x->props.ealgo = sa->sadb_sa_encrypt;		}	}	/* x->algo.flags = sa->sadb_sa_flags; */	x->props.family = pfkey_sadb_addr2xfrm_addr((struct sadb_address *) ext_hdrs[SADB_EXT_ADDRESS_SRC-1], 						    &x->props.saddr);	if (!x->props.family) {		err = -EAFNOSUPPORT;		goto out;	}	pfkey_sadb_addr2xfrm_addr((struct sadb_address *) ext_hdrs[SADB_EXT_ADDRESS_DST-1], 				  &x->id.daddr);	if (ext_hdrs[SADB_X_EXT_SA2-1]) {		struct sadb_x_sa2 *sa2 = (void*)ext_hdrs[SADB_X_EXT_SA2-1];		x->props.mode = sa2->sadb_x_sa2_mode;		if (x->props.mode)			x->props.mode--;		x->props.reqid = sa2->sadb_x_sa2_reqid;	}	if (ext_hdrs[SADB_EXT_ADDRESS_PROXY-1]) {		struct sadb_address *addr = ext_hdrs[SADB_EXT_ADDRESS_PROXY-1];		/* Nobody uses this, but we try. */		x->sel.family = pfkey_sadb_addr2xfrm_addr(addr, &x->sel.saddr);		x->sel.prefixlen_s = addr->sadb_address_prefixlen;	}	if (ext_hdrs[SADB_X_EXT_NAT_T_TYPE-1]) {		struct sadb_x_nat_t_type* n_type;		struct xfrm_encap_tmpl *natt;		x->encap = kmalloc(sizeof(*x->encap), GFP_KERNEL);		if (!x->encap)			goto out;		natt = x->encap;		n_type = ext_hdrs[SADB_X_EXT_NAT_T_TYPE-1];		natt->encap_type = n_type->sadb_x_nat_t_type_type;		if (ext_hdrs[SADB_X_EXT_NAT_T_SPORT-1]) {			struct sadb_x_nat_t_port* n_port =				ext_hdrs[SADB_X_EXT_NAT_T_SPORT-1];			natt->encap_sport = n_port->sadb_x_nat_t_port_port;		}		if (ext_hdrs[SADB_X_EXT_NAT_T_DPORT-1]) {			struct sadb_x_nat_t_port* n_port =				ext_hdrs[SADB_X_EXT_NAT_T_DPORT-1];			natt->encap_dport = n_port->sadb_x_nat_t_port_port;		}	}	x->type = xfrm_get_type(proto, x->props.family);	if (x->type == NULL) {		err = -ENOPROTOOPT;		goto out;	}	if (x->type->init_state(x, NULL)) {		err = -EINVAL;		goto out;	}	x->km.seq = hdr->sadb_msg_seq;	x->km.state = XFRM_STATE_VALID;	return x;out:	x->km.state = XFRM_STATE_DEAD;	xfrm_state_put(x);	return ERR_PTR(err);}static int pfkey_reserved(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs){	return -EOPNOTSUPP;}static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs){	struct sk_buff *resp_skb;	struct sadb_x_sa2 *sa2;	struct sadb_address *saddr, *daddr;	struct sadb_msg *out_hdr;	struct xfrm_state *x = NULL;	u8 mode;	u32 reqid;	u8 proto;	unsigned short family;	xfrm_address_t *xsaddr = NULL, *xdaddr = NULL;	if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1],				     ext_hdrs[SADB_EXT_ADDRESS_DST-1]))		return -EINVAL;	proto = pfkey_satype2proto(hdr->sadb_msg_satype);	if (proto == 0)		return -EINVAL;	if ((sa2 = ext_hdrs[SADB_X_EXT_SA2-1]) != NULL) {		mode = sa2->sadb_x_sa2_mode - 1;		reqid = sa2->sadb_x_sa2_reqid;	} else {		mode = 0;		reqid = 0;	}	saddr = ext_hdrs[SADB_EXT_ADDRESS_SRC-1];	daddr = ext_hdrs[SADB_EXT_ADDRESS_DST-1];	family = ((struct sockaddr *)(saddr + 1))->sa_family;	switch (family) {	case AF_INET:		xdaddr = (xfrm_address_t *)&((struct sockaddr_in *)(daddr + 1))->sin_addr.s_addr;		xsaddr = (xfrm_address_t *)&((struct sockaddr_in *)(saddr + 1))->sin_addr.s_addr;		break;#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)	case AF_INET6:		xdaddr = (xfrm_address_t *)&((struct sockaddr_in6 *)(daddr + 1))->sin6_addr;		xsaddr = (xfrm_address_t *)&((struct sockaddr_in6 *)(saddr + 1))->sin6_addr;		break;#endif	}	if (hdr->sadb_msg_seq) {		x = xfrm_find_acq_byseq(hdr->sadb_msg_seq);		if (x && xfrm_addr_cmp(&x->id.daddr, xdaddr, family)) {			xfrm_state_put(x);			x = NULL;		}	}	if (!x)		x = xfrm_find_acq(mode, reqid, proto, xdaddr, xsaddr, 1, family);	if (x == NULL)		return -ENOENT;	resp_skb = ERR_PTR(-ENOENT);	spin_lock_bh(&x->lock);	if (x->km.state != XFRM_STATE_DEAD) {		struct sadb_spirange *range = ext_hdrs[SADB_EXT_SPIRANGE-1];		u32 min_spi, max_spi;		if (range != NULL) {			min_spi = range->sadb_spirange_min;			max_spi = range->sadb_spirange_max;		} else {			min_spi = 0x100;			max_spi = 0x0fffffff;		}		xfrm_alloc_spi(x, htonl(min_spi), htonl(max_spi));		if (x->id.spi)			resp_skb = pfkey_xfrm_state2msg(x, 0, 3);	}	spin_unlock_bh(&x->lock);	if (IS_ERR(resp_skb)) {		xfrm_state_put(x);		return  PTR_ERR(resp_skb);	}	out_hdr = (struct sadb_msg *) resp_skb->data;	out_hdr->sadb_msg_version = hdr->sadb_msg_version;	out_hdr->sadb_msg_type = SADB_GETSPI;	out_hdr->sadb_msg_satype = pfkey_proto2satype(proto);	out_hdr->sadb_msg_errno = 0;	out_hdr->sadb_msg_reserved = 0;	out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;	out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;	xfrm_state_put(x);	pfkey_broadcast(resp_skb, GFP_KERNEL, BROADCAST_ONE, sk);	return 0;}static int pfkey_acquire(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs){	struct xfrm_state *x;	if (hdr->sadb_msg_len != sizeof(struct sadb_msg)/8)		return -EOPNOTSUPP;	if (hdr->sadb_msg_seq == 0 || hdr->sadb_msg_errno == 0)		return 0;	x = xfrm_find_acq_byseq(hdr->sadb_msg_seq);	if (x == NULL)		return 0;	spin_lock_bh(&x->lock);	if (x->km.state == XFRM_STATE_ACQ) {		x->km.state = XFRM_STATE_ERROR;		wake_up(&km_waitq);	}	spin_unlock_bh(&x->lock);	xfrm_state_put(x);	return 0;}static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs){	struct sk_buff *out_skb;	struct sadb_msg *out_hdr;	struct xfrm_state *x;	int err;	xfrm_probe_algs();		x = pfkey_msg2xfrm_state(hdr, ext_hdrs);	if (IS_ERR(x))		return PTR_ERR(x);	if (hdr->sadb_msg_type == SADB_ADD)		err = xfrm_state_add(x);	else		err = xfrm_state_update(x);	if (err < 0) {		x->km.state = XFRM_STATE_DEAD;		xfrm_state_put(x);		return err;	}	out_skb = pfkey_xfrm_state2msg(x, 0, 3);	if (IS_ERR(out_skb))		return  PTR_ERR(out_skb); /* XXX Should we return 0 here ? */	out_hdr = (struct sadb_msg *) out_skb->data;	out_hdr->sadb_msg_version = hdr->sadb_msg_version;	out_hdr->sadb_msg_type = hdr->sadb_msg_type;	out_hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto);	out_hdr->sadb_msg_errno = 0;	out_hdr->sadb_msg_reserved = 0;	out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;	out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;	pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, sk);	return 0;}static int pfkey_delete(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs){	struct xfrm_state *x;	if (!ext_hdrs[SADB_EXT_SA-1] ||	    !present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1],				     ext_hdrs[SADB_EXT_ADDRESS_DST-1]))		return -EINVAL;	x = pfkey_xfrm_state_lookup(hdr, ext_hdrs);	if (x == NULL)		return -ESRCH;	if (xfrm_state_kern(x)) {		xfrm_state_put(x);		return -EPERM;	}		xfrm_state_delete(x);	xfrm_state_put(x);	pfkey_broadcast(skb_clone(skb, GFP_KERNEL), GFP_KERNEL, 			BROADCAST_ALL, sk);	return 0;}static int pfkey_get(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs){	__u8 proto;	struct sk_buff *out_skb;	struct sadb_msg *out_hdr;	struct xfrm_state *x;	if (!ext_hdrs[SADB_EXT_SA-1] ||	    !present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1],				     ext_hdrs[SADB_EXT_ADDRESS_DST-1]))		return -EINVAL;	x = pfkey_xfrm_state_lookup(hdr, ext_hdrs);	if (x == NULL)		return -ESRCH;	out_skb = pfkey_xfrm_state2msg(x, 1, 3);	proto = x->id.proto;	xfrm_state_put(x);	if (IS_ERR(out_skb))		return  PTR_ERR(out_skb);	out_hdr = (struct sadb_msg *) out_skb->data;	out_hdr->sadb_msg_version = hdr->sadb_msg_version;	out_hdr->sadb_msg_type = SADB_DUMP;	out_hdr->sadb_msg_satype = pfkey_proto2satype(proto);	out_hdr->sadb_msg_errno = 0;	out_hdr->sadb_msg_reserved = 0;	out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;	out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;	pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, sk);	return 0;}static struct sk_buff *compose_sadb_supported(struct sadb_msg *orig, int allocation){	struct sk_buff *skb;	struct sadb_msg *hdr;	int len, auth_len, enc_len, i;	auth_len = xfrm_count_auth_supported();	if (auth_len) {		auth_len *= sizeof(struct sadb_alg);		auth_len += sizeof(struct sadb_supported);	}		enc_len = xfrm_count_enc_supported();	if (enc_len) {		enc_len *= sizeof(struct sadb_alg);		enc_len += sizeof(struct sadb_supported);	}		len = enc_len + auth_len + sizeof(struct sadb_msg);	skb = alloc_skb(len + 16, allocation);	if (!skb)		goto out_put_algs;	hdr = (struct sadb_msg *) skb_put(skb, sizeof(*hdr));	pfkey_hdr_dup(hdr, orig);	hdr->sadb_msg_errno = 0;	hdr->sadb_msg_len = len / sizeof(uint64_t);	if (auth_len) {		struct sadb_supported *sp;		struct sadb_alg *ap;		sp = (struct sadb_supported *) skb_put(skb, auth_len);		ap = (struct sadb_alg *) (sp + 1);		sp->sadb_supported_len = auth_len / sizeof(uint64_t);		sp->sadb_supported_exttype = SADB_EXT_SUPPORTED_AUTH;		for (i = 0; ; i++) {			struct xfrm_algo_desc *aalg = xfrm_aalg_get_byidx(i);			if (!aalg)

⌨️ 快捷键说明

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