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

📄 key.c

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	LIST_FOREACH(sah, &sahtree, chain) {
		/* search valid state */
		for (stateidx = 0;
		     stateidx < _ARRAYLEN(saorder_state_valid);
		     stateidx++) {
			state = saorder_state_valid[stateidx];
			LIST_FOREACH(sav, &sah->savtree[state], chain) {
				/* sanity check */
				KEY_CHKSASTATE(sav->state, state, "key_allocsav");
				if (proto != sav->sah->saidx.proto)
					continue;
				if (spi != sav->spi)
					continue;
				if (family != sav->sah->saidx.src.ss_family ||
				    family != sav->sah->saidx.dst.ss_family)
					continue;

#if 0	/* don't check src */
				/* check src address */
				switch (family) {
				case AF_INET:
					bzero(&sin, sizeof(sin));
					sin.sin_family = AF_INET;
					sin.sin_len = sizeof(sin);
					bcopy(src, &sin.sin_addr,
					    sizeof(sin.sin_addr));
					if (key_sockaddrcmp((struct sockaddr*)&sin,
					    (struct sockaddr *)&sav->sah->saidx.src, 0) != 0)
						continue;

					break;
				case AF_INET6:
					bzero(&sin6, sizeof(sin6));
					sin6.sin6_family = AF_INET6;
					sin6.sin6_len = sizeof(sin6);
					bcopy(src, &sin6.sin6_addr,
					    sizeof(sin6.sin6_addr));
					if (IN6_IS_SCOPE_LINKLOCAL(&sin6.sin6_addr)) {
						/* kame fake scopeid */
						sin6.sin6_scope_id =
						    ntohs(sin6.sin6_addr.s6_addr16[1]);
						sin6.sin6_addr.s6_addr16[1] = 0;
					}
					if (key_sockaddrcmp((struct sockaddr*)&sin6,
					    (struct sockaddr *)&sav->sah->saidx.src, 0) != 0)
						continue;
					break;
				default:
					ipseclog((LOG_DEBUG, "key_allocsa: "
					    "unknown address family=%d.\n",
					    family));
					continue;
				}

#endif
				/* check dst address */
				switch (family) {
				case AF_INET:
					bzero(&sin, sizeof(sin));
					sin.sin_family = AF_INET;
					sin.sin_len = sizeof(sin);
					bcopy(dst, &sin.sin_addr,
					    sizeof(sin.sin_addr));
					if (key_sockaddrcmp((struct sockaddr*)&sin,
					    (struct sockaddr *)&sav->sah->saidx.dst, 0) != 0)
						continue;

					break;
				case AF_INET6:
					bzero(&sin6, sizeof(sin6));
					sin6.sin6_family = AF_INET6;
					sin6.sin6_len = sizeof(sin6);
					bcopy(dst, &sin6.sin6_addr,
					    sizeof(sin6.sin6_addr));
					if (IN6_IS_SCOPE_LINKLOCAL(&sin6.sin6_addr)) {
						/* kame fake scopeid */
						sin6.sin6_scope_id =
						    ntohs(sin6.sin6_addr.s6_addr16[1]);
						sin6.sin6_addr.s6_addr16[1] = 0;
					}
					if (key_sockaddrcmp((struct sockaddr*)&sin6,
					    (struct sockaddr *)&sav->sah->saidx.dst, 0) != 0)
						continue;
					break;
				default:
					ipseclog((LOG_DEBUG, "key_allocsa: "
					    "unknown address family=%d.\n",
					    family));
					continue;
				}

				goto found;
			}
		}
	}

	/* not found */
	splx(s);
	return NULL;

found:
	sav->refcnt++;
	splx(s);
	KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
		printf("DP allocsa cause refcnt++:%d SA:%p\n",
			sav->refcnt, sav));
	return sav;
}

/*
 * Must be called after calling key_allocsp().
 * For both the packet without socket and key_freeso().
 */
void
key_freesp(sp)
	struct secpolicy *sp;
{
	/* sanity check */
	if (sp == NULL)
		panic("key_freesp: NULL pointer is passed.\n");

	sp->refcnt--;
	KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
		printf("DP freesp cause refcnt--:%d SP:%p\n",
			sp->refcnt, sp));

	if (sp->refcnt == 0)
		key_delsp(sp);

	return;
}

/*
 * Must be called after calling key_allocsp().
 * For the packet with socket.
 */
void
key_freeso(so)
	struct socket *so;
{
	/* sanity check */
	if (so == NULL)
		panic("key_freeso: NULL pointer is passed.\n");

	switch (so->so_proto->pr_domain->dom_family) {
#ifdef INET
	case PF_INET:
	    {
		struct inpcb *pcb = sotoinpcb(so);

		/* Does it have a PCB ? */
		if (pcb == NULL)
			return;
		key_freesp_so(&pcb->inp_sp->sp_in);
		key_freesp_so(&pcb->inp_sp->sp_out);
	    }
		break;
#endif
#ifdef INET6
	case PF_INET6:
	    {
#ifdef HAVE_NRL_INPCB
		struct inpcb *pcb  = sotoinpcb(so);

		/* Does it have a PCB ? */
		if (pcb == NULL)
			return;
		key_freesp_so(&pcb->inp_sp->sp_in);
		key_freesp_so(&pcb->inp_sp->sp_out);
#else
		struct in6pcb *pcb  = sotoin6pcb(so);

		/* Does it have a PCB ? */
		if (pcb == NULL)
			return;
		key_freesp_so(&pcb->in6p_sp->sp_in);
		key_freesp_so(&pcb->in6p_sp->sp_out);
#endif
	    }
		break;
#endif /* INET6 */
	default:
		ipseclog((LOG_DEBUG, "key_freeso: unknown address family=%d.\n",
		    so->so_proto->pr_domain->dom_family));
		return;
	}

	return;
}

static void
key_freesp_so(sp)
	struct secpolicy **sp;
{
	/* sanity check */
	if (sp == NULL || *sp == NULL)
		panic("key_freesp_so: sp == NULL\n");

	switch ((*sp)->policy) {
	case IPSEC_POLICY_IPSEC:
		KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
			printf("DP freeso calls free SP:%p\n", *sp));
		key_freesp(*sp);
		*sp = NULL;
		break;
	case IPSEC_POLICY_ENTRUST:
	case IPSEC_POLICY_BYPASS:
		return;
	default:
		panic("key_freesp_so: Invalid policy found %d", (*sp)->policy);
	}

	return;
}

/*
 * Must be called after calling key_allocsa().
 * This function is called by key_freesp() to free some SA allocated
 * for a policy.
 */
void
key_freesav(sav)
	struct secasvar *sav;
{
	/* sanity check */
	if (sav == NULL)
		panic("key_freesav: NULL pointer is passed.\n");

	sav->refcnt--;
	KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
		printf("DP freesav cause refcnt--:%d SA:%p SPI %u\n",
			sav->refcnt, sav, (u_int32_t)ntohl(sav->spi)));

	if (sav->refcnt == 0)
		key_delsav(sav);

	return;
}

/* %%% SPD management */
/*
 * free security policy entry.
 */
static void
key_delsp(sp)
	struct secpolicy *sp;
{
	int s;

	/* sanity check */
	if (sp == NULL)
		panic("key_delsp: NULL pointer is passed.\n");

	sp->state = IPSEC_SPSTATE_DEAD;

	if (sp->refcnt > 0)
		return; /* can't free */

#ifdef __NetBSD__
	s = splsoftnet();	/*called from softclock()*/
#else
	s = splnet();	/*called from softclock()*/
#endif
	/* remove from SP index */
	if (__LIST_CHAINED(sp))
		LIST_REMOVE(sp, chain);

    {
	struct ipsecrequest *isr = sp->req, *nextisr;

	while (isr != NULL) {
		if (isr->sav != NULL) {
			KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
				printf("DP delsp calls free SA:%p\n",
					isr->sav));
			key_freesav(isr->sav);
			isr->sav = NULL;
		}

#if defined(NSEC) && NSEC > 0
		if (isr->tunifp) {
			int s;

			s = splimp();
			sec_demolish(isr->tunifp);
			splx(s);

			/* XXX more garbage-collection */
			isr->tunifp = NULL;
		}
#endif

		nextisr = isr->next;
		KFREE(isr);
		isr = nextisr;
	}
    }

	keydb_delsecpolicy(sp);

	splx(s);

	return;
}

/*
 * search SPD
 * OUT:	NULL	: not found
 *	others	: found, pointer to a SP.
 */
static struct secpolicy *
key_getsp(spidx)
	struct secpolicyindex *spidx;
{
	struct secpolicy *sp;

	/* sanity check */
	if (spidx == NULL)
		panic("key_getsp: NULL pointer is passed.\n");

	LIST_FOREACH(sp, &sptree[spidx->dir], chain) {
		if (sp->state == IPSEC_SPSTATE_DEAD)
			continue;
		if (key_cmpspidx_exactly(spidx, &sp->spidx)) {
			sp->refcnt++;
			return sp;
		}
	}

	return NULL;
}

/*
 * get SP by index.
 * OUT:	NULL	: not found
 *	others	: found, pointer to a SP.
 */
static struct secpolicy *
key_getspbyid(id)
	u_int32_t id;
{
	struct secpolicy *sp;

	LIST_FOREACH(sp, &sptree[IPSEC_DIR_INBOUND], chain) {
		if (sp->state == IPSEC_SPSTATE_DEAD)
			continue;
		if (sp->id == id) {
			sp->refcnt++;
			return sp;
		}
	}

	LIST_FOREACH(sp, &sptree[IPSEC_DIR_OUTBOUND], chain) {
		if (sp->state == IPSEC_SPSTATE_DEAD)
			continue;
		if (sp->id == id) {
			sp->refcnt++;
			return sp;
		}
	}

	return NULL;
}

struct secpolicy *
key_newsp()
{
	struct secpolicy *newsp = NULL;

	newsp = keydb_newsecpolicy();
	if (!newsp)
		return newsp;

	newsp->refcnt = 1;
	newsp->req = NULL;

	return newsp;
}

/*
 * create secpolicy structure from sadb_x_policy structure.
 * NOTE: `state', `secpolicyindex' in secpolicy structure are not set,
 * so must be set properly later.
 */
struct secpolicy *
key_msg2sp(xpl0, len, error)
	struct sadb_x_policy *xpl0;
	size_t len;
	int *error;
{
	struct secpolicy *newsp;

	/* sanity check */
	if (xpl0 == NULL)
		panic("key_msg2sp: NULL pointer was passed.\n");
	if (len < sizeof(*xpl0))
		panic("key_msg2sp: invalid length.\n");
	if (len != PFKEY_EXTLEN(xpl0)) {
		ipseclog((LOG_DEBUG, "key_msg2sp: Invalid msg length.\n"));
		*error = EINVAL;
		return NULL;
	}

	if ((newsp = key_newsp()) == NULL) {
		*error = ENOBUFS;
		return NULL;
	}

	newsp->spidx.dir = xpl0->sadb_x_policy_dir;
	newsp->policy = xpl0->sadb_x_policy_type;

	/* check policy */
	switch (xpl0->sadb_x_policy_type) {
	case IPSEC_POLICY_DISCARD:
	case IPSEC_POLICY_NONE:
	case IPSEC_POLICY_ENTRUST:
	case IPSEC_POLICY_BYPASS:
		newsp->req = NULL;
		break;

	case IPSEC_POLICY_IPSEC:
	    {
		int tlen;
		struct sadb_x_ipsecrequest *xisr;
		struct ipsecrequest **p_isr = &newsp->req;

		/* validity check */
		if (PFKEY_EXTLEN(xpl0) < sizeof(*xpl0)) {
			ipseclog((LOG_DEBUG,
			    "key_msg2sp: Invalid msg length.\n"));
			key_freesp(newsp);
			*error = EINVAL;
			return NULL;
		}

		tlen = PFKEY_EXTLEN(xpl0) - sizeof(*xpl0);
		xisr = (struct sadb_x_ipsecrequest *)(xpl0 + 1);

		while (tlen > 0) {

			/* length check */
			if (xisr->sadb_x_ipsecrequest_len < sizeof(*xisr)) {
				ipseclog((LOG_DEBUG, "key_msg2sp: "
					"invalid ipsecrequest length.\n"));
				key_freesp(newsp);
				*error = EINVAL;
				return NULL;
			}

			/* allocate request buffer */
			KMALLOC(*p_isr, struct ipsecrequest *, sizeof(**p_isr));
			if ((*p_isr) == NULL) {
				ipseclog((LOG_DEBUG,
				    "key_msg2sp: No more memory.\n"));
				key_freesp(newsp);
				*error = ENOBUFS;
				return NULL;
			}
			bzero(*p_isr, sizeof(**p_isr));

			/* set values */
			(*p_isr)->next = NULL;

			switch (xisr->sadb_x_ipsecrequest_proto) {
			case IPPROTO_ESP:
			case IPPROTO_AH:
			case IPPROTO_IPCOMP:
				break;
			default:
				ipseclog((LOG_DEBUG,
				    "key_msg2sp: invalid proto type=%u\n",
				    xisr->sadb_x_ipsecrequest_proto));
				key_freesp(newsp);
				*error = EPROTONOSUPPORT;

⌨️ 快捷键说明

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