Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 21 Nov 2016 13:07:57 +0000 (UTC)
From:      "Andrey V. Elsukov" <ae@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r308924 - in projects/ipsec/sys: netinet netipsec
Message-ID:  <201611211307.uALD7vOA059452@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ae
Date: Mon Nov 21 13:07:57 2016
New Revision: 308924
URL: https://svnweb.freebsd.org/changeset/base/308924

Log:
  Modify PCB-related functions and unify its names.
  
  Some background.
  When IPsec compiled in the kernel, each inpcb allocates inpcbpolicy
  structure. This structure keeps two security policies (for INBOUND and
  OUTBOUND directions). By default these policies have IPSEC_POLICY_ENTRUST
  type. This means that application has not any preference for used security
  policies and kernel will use system-wide security policies.
  Some application could want to bypass IPsec processing (e.g. IKE daemons).
  Such applications use IP_IPSEC_POLICY/IPV6_IPSEC_POLICY socket option
  to configure IPsec bypass. In this case policies stored in the inpcbpolicy
  structure will have type IPSEC_POLICY_BYPASS. Only privileged socket
  can use this policy type. The last allowed for use by application policy
  type is IPSEC_POLICY_IPSEC. It also allowed only for privileged sockets.
  In theory application could configure security policy, that requires
  IPsec processing (ESP/AH transforms).
  In reality there are a bunch of problems:
  1) ENTRUST policies for each inpcb just waste the memory, even if system
     doesn't have any security policies;
  2) setsockopt/getsockopt interface was broken, only setsockopt worked
     partially;
  3) even if application has configured IPSEC policy, there is no way
     to set corresponding SA. It looks like all IKEd always require
     security policy that acquired SA should be visible via PF_KEY.
  *) I failed to find some application that uses IPSEC type of policies.
  
  What I did and plan to do to resolve issues:
  1) Now secpolicy pointers in the inpcbpolicy structure will not be
     initialized with ENTRUST policies. NULL pointer will mean ENTRUST
     policy. Also, if application didn't set BYPASS/IPSEC policies,
     the kernel will use these pointers to cache used security policies.
  2) Rework IP_IPSEC_POLICY/IPV6_IPSEC_POLICY socket options handling.
     To get needed policy we need a hint from application, user
     should correctly fill sadb_x_policy->sadb_x_policy_dir before
     doing getsockopt(). If passed buffer size is not enough, needed
     size will be returned in the sadb_x_policy_len field and ENOBUFS
     will be returned as return code.
  3) To resolve this issue we probably need to make PCB policies
     visible through PF_KEY interface. We can create additional list
     and link all such policies into it. This also will help when
     ipsec.ko module will unloaded. We can correctly free all created
     security policies. TBD.
  
  What changed:
  ipsec_init_pcbpolicy() allocates inpcbpolicy that stored in given inpcb.
  Now it requires only one inpcb argument.
  
  ipsec_control_pcbpolicy() used by IPv4/IPv6 control code to set or get
  security policies stored in PCB. Make ipsec_set_pcbpolicy() and
  ipsec_get_pcbpolicy() static.
  
  ipsec_delete_pcbpolicy() releases security polices if they are
  configured, then releases memory from inpcbpolicy structure.
  
  Update ipsec_newisr() and ipsec_delisr() to reflect changes in
  struct ipsecrequest.

Modified:
  projects/ipsec/sys/netinet/in_pcb.c
  projects/ipsec/sys/netinet/sctp_pcb.c
  projects/ipsec/sys/netinet/tcp_syncache.c
  projects/ipsec/sys/netipsec/ipsec.c
  projects/ipsec/sys/netipsec/ipsec.h

Modified: projects/ipsec/sys/netinet/in_pcb.c
==============================================================================
--- projects/ipsec/sys/netinet/in_pcb.c	Mon Nov 21 12:00:31 2016	(r308923)
+++ projects/ipsec/sys/netinet/in_pcb.c	Mon Nov 21 13:07:57 2016	(r308924)
@@ -304,7 +304,7 @@ in_pcballoc(struct socket *so, struct in
 	mac_inpcb_create(so, inp);
 #endif
 #ifdef IPSEC
-	error = ipsec_init_policy(so, &inp->inp_sp);
+	error = ipsec_init_pcbpolicy(inp);
 	if (error != 0) {
 #ifdef MAC
 		mac_inpcb_destroy(inp);

Modified: projects/ipsec/sys/netinet/sctp_pcb.c
==============================================================================
--- projects/ipsec/sys/netinet/sctp_pcb.c	Mon Nov 21 12:00:31 2016	(r308923)
+++ projects/ipsec/sys/netinet/sctp_pcb.c	Mon Nov 21 13:07:57 2016	(r308924)
@@ -2460,7 +2460,7 @@ sctp_inpcb_alloc(struct socket *so, uint
 		return (ENOBUFS);
 	}
 #ifdef IPSEC
-	error = ipsec_init_policy(so, &inp->ip_inp.inp.inp_sp);
+	error = ipsec_init_pcbpolicy(&inp->ip_inp.inp);
 	if (error != 0) {
 		crfree(inp->ip_inp.inp.inp_cred);
 		SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_ep), inp);

Modified: projects/ipsec/sys/netinet/tcp_syncache.c
==============================================================================
--- projects/ipsec/sys/netinet/tcp_syncache.c	Mon Nov 21 12:00:31 2016	(r308923)
+++ projects/ipsec/sys/netinet/tcp_syncache.c	Mon Nov 21 13:07:57 2016	(r308924)
@@ -738,7 +738,7 @@ syncache_socket(struct syncache *sc, str
 	}
 #ifdef IPSEC
 	/* Copy old policy into new socket's. */
-	if (ipsec_copy_policy(sotoinpcb(lso)->inp_sp, inp->inp_sp))
+	if (ipsec_copy_pcbpolicy(sotoinpcb(lso), inp) != 0)
 		printf("syncache_socket: could not copy policy\n");
 #endif
 #ifdef INET6

Modified: projects/ipsec/sys/netipsec/ipsec.c
==============================================================================
--- projects/ipsec/sys/netipsec/ipsec.c	Mon Nov 21 12:00:31 2016	(r308923)
+++ projects/ipsec/sys/netipsec/ipsec.c	Mon Nov 21 13:07:57 2016	(r308924)
@@ -255,8 +255,6 @@ static void ipsec6_get_ulp(const struct 
 static void ipsec6_setspidx_ipaddr(const struct mbuf *,
     struct secpolicyindex *);
 #endif
-static void ipsec_delpcbpolicy(struct inpcbpolicy *);
-static struct secpolicy *ipsec_deepcopy_policy(struct secpolicy *src);
 static void vshiftl(unsigned char *, int, int);
 
 MALLOC_DEFINE(M_IPSEC_INPCB, "inpcbpolicy", "inpcb-resident ipsec policy");
@@ -801,246 +799,213 @@ ipsec_run_hhooks(struct ipsec_ctx_data *
 	return (0);
 }
 
-static void
-ipsec_delpcbpolicy(struct inpcbpolicy *p)
-{
-
-	free(p, M_IPSEC_INPCB);
-}
-
-/* Initialize policy in PCB. */
+/* Initialize PCB policy. */
 int
-ipsec_init_policy(struct socket *so, struct inpcbpolicy **pcb_sp)
+ipsec_init_pcbpolicy(struct inpcb *inp)
 {
-	struct inpcbpolicy *new;
 
-	/* Sanity check. */
-	if (so == NULL || pcb_sp == NULL)
-		panic("%s: NULL pointer was passed.\n", __func__);
+	IPSEC_ASSERT(inp != NULL, ("null inp"));
+	IPSEC_ASSERT(inp->inp_sp == NULL, ("inp_sp already initialized"));
 
-	new = (struct inpcbpolicy *) malloc(sizeof(struct inpcbpolicy),
-					    M_IPSEC_INPCB, M_NOWAIT|M_ZERO);
-	if (new == NULL) {
+	inp->inp_sp = malloc(sizeof(struct inpcbpolicy), M_IPSEC_INPCB,
+	    M_NOWAIT | M_ZERO);
+	if (inp->inp_sp == NULL) {
 		ipseclog((LOG_DEBUG, "%s: No more memory.\n", __func__));
 		return (ENOBUFS);
 	}
-
-	new->priv = IPSEC_IS_PRIVILEGED_SO(so);
-
-	if ((new->sp_in = KEY_NEWSP()) == NULL) {
-		ipsec_delpcbpolicy(new);
-		return (ENOBUFS);
-	}
-	new->sp_in->policy = IPSEC_POLICY_ENTRUST;
-	if ((new->sp_out = KEY_NEWSP()) == NULL) {
-		KEY_FREESP(&new->sp_in);
-		ipsec_delpcbpolicy(new);
-		return (ENOBUFS);
-	}
-	new->sp_out->policy = IPSEC_POLICY_ENTRUST;
-	*pcb_sp = new;
-
 	return (0);
 }
 
-/* Copy old IPsec policy into new. */
+/* Delete PCB policy. */
 int
-ipsec_copy_policy(struct inpcbpolicy *old, struct inpcbpolicy *new)
+ipsec_delete_pcbpolicy(struct inpcb *inp)
 {
-	struct secpolicy *sp;
 
-	sp = ipsec_deepcopy_policy(old->sp_in);
-	if (sp) {
-		KEY_FREESP(&new->sp_in);
-		new->sp_in = sp;
-	} else
-		return (ENOBUFS);
+	if (inp->inp_sp == NULL)
+		return (0);
 
-	sp = ipsec_deepcopy_policy(old->sp_out);
-	if (sp) {
-		KEY_FREESP(&new->sp_out);
-		new->sp_out = sp;
-	} else
-		return (ENOBUFS);
+	if (inp->inp_sp->flags & INP_INBOUND_POLICY)
+		key_freesp(&inp->inp_sp->sp_in);
 
-	new->priv = old->priv;
+	if (inp->inp_sp->flags & INP_OUTBOUND_POLICY)
+		key_freesp(&inp->inp_sp->sp_out);
 
+	free(inp->inp_sp, M_IPSEC_INPCB);
+	inp->inp_sp = NULL;
 	return (0);
 }
 
-struct ipsecrequest *
-ipsec_newisr(void)
-{
-	struct ipsecrequest *p;
-
-	p = malloc(sizeof(struct ipsecrequest), M_IPSEC_SR, M_NOWAIT|M_ZERO);
-	if (p != NULL)
-		IPSECREQUEST_LOCK_INIT(p);
-	return (p);
-}
-
-void
-ipsec_delisr(struct ipsecrequest *p)
-{
-
-	IPSECREQUEST_LOCK_DESTROY(p);
-	free(p, M_IPSEC_SR);
-}
-
 /* Deep-copy a policy in PCB. */
 static struct secpolicy *
-ipsec_deepcopy_policy(struct secpolicy *src)
+ipsec_deepcopy_pcbpolicy(struct secpolicy *src)
 {
-	struct ipsecrequest *newchain = NULL;
-	struct ipsecrequest *p;
-	struct ipsecrequest **q;
-	struct ipsecrequest *r;
 	struct secpolicy *dst;
+	int i;
 
 	if (src == NULL)
 		return (NULL);
-	dst = KEY_NEWSP();
-	if (dst == NULL)
-		return (NULL);
-
-	/*
-	 * Deep-copy IPsec request chain.  This is required since struct
-	 * ipsecrequest is not reference counted.
-	 */
-	q = &newchain;
-	for (p = src->req; p; p = p->next) {
-		*q = ipsec_newisr();
-		if (*q == NULL)
-			goto fail;
-		(*q)->saidx.proto = p->saidx.proto;
-		(*q)->saidx.mode = p->saidx.mode;
-		(*q)->level = p->level;
-		(*q)->saidx.reqid = p->saidx.reqid;
 
-		bcopy(&p->saidx.src, &(*q)->saidx.src, sizeof((*q)->saidx.src));
-		bcopy(&p->saidx.dst, &(*q)->saidx.dst, sizeof((*q)->saidx.dst));
+	IPSEC_ASSERT(src->state == IPSEC_SPSTATE_PCB, ("SP isn't PCB"));
 
-		(*q)->sp = dst;
-
-		q = &((*q)->next);
-	}
+	dst = key_newsp();
+	if (dst == NULL)
+		return (NULL);
 
-	dst->req = newchain;
 	dst->policy = src->policy;
-	/* Do not touch the refcnt fields. */
-
-	return (dst);
-
-fail:
-	for (p = newchain; p; p = r) {
-		r = p->next;
-		ipsec_delisr(p);
-		p = NULL;
+	dst->state = src->state;
+	dst->priority = src->priority;
+	/* Do not touch the refcnt field. */
+
+	/* Copy IPsec request chain. */
+	for (i = 0; i < src->tcount; i++) {
+		dst->req[i] = ipsec_newisr();
+		if (dst->req[i] == NULL) {
+			key_freesp(&dst);
+			return (NULL);
+		}
+		bcopy(src->req[i], dst->req[i], sizeof(struct ipsecrequest));
+		dst->tcount++;
 	}
-	KEY_FREESP(&dst);
-	return (NULL);
+	KEYDBG(IPSEC_DUMP,
+	    printf("%s: copied SP(%p) -> SP(%p)\n", __func__, src, dst);
+	    kdebug_secpolicy(dst));
+	return (dst);
 }
 
-/* Set policy and IPsec request if present. */
-static int
-ipsec_set_policy_internal(struct secpolicy **pcb_sp, int optname,
-    caddr_t request, size_t len, struct ucred *cred)
+/* Copy old IPsec policy into new. */
+int
+ipsec_copy_pcbpolicy(struct inpcb *old, struct inpcb *new)
 {
-	struct sadb_x_policy *xpl;
-	struct secpolicy *newsp = NULL;
-	int error;
+	struct secpolicy *sp;
 
-	/* Sanity check. */
-	if (pcb_sp == NULL || *pcb_sp == NULL || request == NULL)
-		return (EINVAL);
-	if (len < sizeof(*xpl))
-		return (EINVAL);
-	xpl = (struct sadb_x_policy *)request;
+	/*
+	 * old->inp_sp can be NULL if PCB was created when an IPsec
+	 * support was unavailable. This is not an error, we don't have
+	 * policies in this PCB, so nothing to copy.
+	 */
+	if (old->inp_sp == NULL)
+		return (0);
 
-	KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
-		printf("%s: passed policy\n", __func__);
-		kdebug_sadb_x_policy((struct sadb_ext *)xpl));
-
-	/* Check policy type. */
-	/* ipsec_set_policy_internal() accepts IPSEC, ENTRUST and BYPASS. */
-	if (xpl->sadb_x_policy_type == IPSEC_POLICY_DISCARD
-	 || xpl->sadb_x_policy_type == IPSEC_POLICY_NONE)
-		return (EINVAL);
+	IPSEC_ASSERT(new->inp_sp != NULL, ("new inp_sp is NULL"));
+	INP_WLOCK_ASSERT(new);
 
-	/* Check privileged socket. */
-	if (cred != NULL && xpl->sadb_x_policy_type == IPSEC_POLICY_BYPASS) {
-		error = priv_check_cred(cred, PRIV_NETINET_IPSEC, 0);
-		if (error)
-			return (EACCES);
-	}
+	if (old->inp_sp->flags & INP_INBOUND_POLICY) {
+		sp = ipsec_deepcopy_pcbpolicy(old->inp_sp->sp_in);
+		if (sp == NULL)
+			return (ENOBUFS);
+	} else
+		sp = NULL;
 
-	/* Allocating new SP entry. */
-	if ((newsp = key_msg2sp(xpl, len, &error)) == NULL)
-		return (error);
+	if (new->inp_sp->flags & INP_INBOUND_POLICY)
+		key_freesp(&new->inp_sp->sp_in);
 
-	/* Clear old SP and set new SP. */
-	KEY_FREESP(pcb_sp);
-	*pcb_sp = newsp;
-	KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
-		printf("%s: new policy\n", __func__);
-		kdebug_secpolicy(newsp));
+	new->inp_sp->sp_in = sp;
+	if (sp != NULL)
+		new->inp_sp->flags |= INP_INBOUND_POLICY;
+	else
+		new->inp_sp->flags &= ~INP_INBOUND_POLICY;
+
+	if (old->inp_sp->flags & INP_OUTBOUND_POLICY) {
+		sp = ipsec_deepcopy_pcbpolicy(old->inp_sp->sp_out);
+		if (sp == NULL)
+			return (ENOBUFS);
+	} else
+		sp = NULL;
+
+	if (new->inp_sp->flags & INP_OUTBOUND_POLICY)
+		key_freesp(&new->inp_sp->sp_out);
 
+	new->inp_sp->sp_out = sp;
+	if (sp != NULL)
+		new->inp_sp->flags |= INP_OUTBOUND_POLICY;
+	else
+		new->inp_sp->flags &= ~INP_OUTBOUND_POLICY;
 	return (0);
 }
 
-int
-ipsec_set_policy(struct inpcb *inp, int optname, caddr_t request,
-    size_t len, struct ucred *cred)
+static int
+ipsec_set_pcbpolicy(struct inpcb *inp, struct ucred *cred,
+    void *request, size_t len)
 {
 	struct sadb_x_policy *xpl;
-	struct secpolicy **pcb_sp;
+	struct secpolicy **spp, *newsp;
+	int error, flags;
 
-	/* Sanity check. */
-	if (inp == NULL || request == NULL)
-		return (EINVAL);
-	if (len < sizeof(*xpl))
-		return (EINVAL);
 	xpl = (struct sadb_x_policy *)request;
-
 	/* Select direction. */
 	switch (xpl->sadb_x_policy_dir) {
 	case IPSEC_DIR_INBOUND:
-		pcb_sp = &inp->inp_sp->sp_in;
+		spp = &inp->inp_sp->sp_in;
+		flags = INP_INBOUND_POLICY;
 		break;
 	case IPSEC_DIR_OUTBOUND:
-		pcb_sp = &inp->inp_sp->sp_out;
+		spp = &inp->inp_sp->sp_out;
+		flags = INP_OUTBOUND_POLICY;
 		break;
 	default:
 		ipseclog((LOG_ERR, "%s: invalid direction=%u\n", __func__,
 			xpl->sadb_x_policy_dir));
 		return (EINVAL);
 	}
+	/*
+	 * Privileged sockets are allowed to set own security policy
+	 * and configure IPsec bypass. Unprivileged sockets only can
+	 * have ENTRUST policy.
+	 */
+	switch (xpl->sadb_x_policy_type) {
+	case IPSEC_POLICY_IPSEC:
+	case IPSEC_POLICY_BYPASS:
+		if (cred != NULL &&
+		    priv_check_cred(cred, PRIV_NETINET_IPSEC, 0) != 0)
+			return (EACCES);
+		/* Allocate new SP entry. */
+		newsp = key_msg2sp(xpl, len, &error);
+		if (newsp == NULL)
+			return (error);
+		newsp->state = IPSEC_SPSTATE_PCB;
+		break;
+	case IPSEC_POLICY_ENTRUST:
+		/* We just use NULL pointer for ENTRUST policy */
+		newsp = NULL;
+		break;
+	default:
+		/* Other security policy types aren't allowed for PCB */
+		return (EINVAL);
+	}
 
-	return (ipsec_set_policy_internal(pcb_sp, optname, request, len, cred));
+	/* Clear old SP and set new SP. */
+	if (*spp != NULL)
+		key_freesp(spp);
+	*spp = newsp;
+	KEYDBG(IPSEC_DUMP,
+	    printf("%s: new SP(%p)\n", __func__, newsp));
+	if (newsp == NULL)
+		inp->inp_sp->flags &= ~flags;
+	else {
+		inp->inp_sp->flags |= flags;
+		KEYDBG(IPSEC_DUMP, kdebug_secpolicy(newsp));
+	}
+	return (0);
 }
 
-int
-ipsec_get_policy(struct inpcb *inp, caddr_t request, size_t len,
-    struct mbuf **mp)
+static int
+ipsec_get_pcbpolicy(struct inpcb *inp, void *request, size_t *len)
 {
 	struct sadb_x_policy *xpl;
-	struct secpolicy *pcb_sp;
+	struct secpolicy *sp;
+	int error, flags;
 
-	/* Sanity check. */
-	if (inp == NULL || request == NULL || mp == NULL)
-		return (EINVAL);
-	IPSEC_ASSERT(inp->inp_sp != NULL, ("null inp_sp"));
-	if (len < sizeof(*xpl))
-		return (EINVAL);
 	xpl = (struct sadb_x_policy *)request;
-
+	flags = inp->inp_sp->flags;
 	/* Select direction. */
 	switch (xpl->sadb_x_policy_dir) {
 	case IPSEC_DIR_INBOUND:
-		pcb_sp = inp->inp_sp->sp_in;
+		sp = inp->inp_sp->sp_in;
+		flags &= INP_INBOUND_POLICY;
 		break;
 	case IPSEC_DIR_OUTBOUND:
-		pcb_sp = inp->inp_sp->sp_out;
+		sp = inp->inp_sp->sp_out;
+		flags &= INP_OUTBOUND_POLICY;
 		break;
 	default:
 		ipseclog((LOG_ERR, "%s: invalid direction=%u\n", __func__,
@@ -1048,42 +1013,86 @@ ipsec_get_policy(struct inpcb *inp, cadd
 		return (EINVAL);
 	}
 
-	/* Sanity check. Should be an IPSEC_ASSERT. */
-	if (pcb_sp == NULL)
-		return (EINVAL);
-
-	*mp = key_sp2msg(pcb_sp);
-	if (!*mp) {
-		ipseclog((LOG_DEBUG, "%s: No more memory.\n", __func__));
-		return (ENOBUFS);
+	if (flags == 0) {
+		/* Return ENTRUST policy */
+		xpl->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
+		xpl->sadb_x_policy_type = IPSEC_POLICY_ENTRUST;
+		xpl->sadb_x_policy_id = 0;
+		xpl->sadb_x_policy_priority = 0;
+		xpl->sadb_x_policy_len = PFKEY_UNIT64(sizeof(*xpl));
+		*len = sizeof(*xpl);
+		return (0);
 	}
 
-	(*mp)->m_type = MT_DATA;
-	KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
-		printf("%s:\n", __func__); kdebug_mbuf(*mp));
+	IPSEC_ASSERT(sp != NULL,
+	    ("sp is NULL, but flags is 0x%04x", inp->inp_sp->flags));
 
+	key_addref(sp);
+	error = key_sp2msg(sp, request, len);
+	key_freesp(&sp);
+	if (error == EINVAL)
+		return (error);
+	/*
+	 * We return "success", but user should check *len.
+	 * *len will be set to size of valid data and
+	 * sadb_x_policy_len will contain needed size.
+	 */
 	return (0);
 }
 
-/* Delete policy in PCB. */
+/* Handle socket option control request for PCB */
 int
-ipsec_delete_pcbpolicy(struct inpcb *inp)
+ipsec_control_pcbpolicy(struct inpcb *inp, struct sockopt *sopt)
 {
-	IPSEC_ASSERT(inp != NULL, ("null inp"));
+	void *optdata;
+	size_t optlen;
+	int error;
 
 	if (inp->inp_sp == NULL)
-		return (0);
+		return (ENOPROTOOPT);
 
-	if (inp->inp_sp->sp_in != NULL)
-		KEY_FREESP(&inp->inp_sp->sp_in);
+	/* Limit maximum request size to PAGE_SIZE */
+	optlen = sopt->sopt_valsize;
+	if (optlen < sizeof(struct sadb_x_policy) || optlen > PAGE_SIZE)
+		return (EINVAL);
 
-	if (inp->inp_sp->sp_out != NULL)
-		KEY_FREESP(&inp->inp_sp->sp_out);
+	optdata = malloc(optlen, M_TEMP, sopt->sopt_td ? M_WAITOK: M_NOWAIT);
+	if (optdata == NULL)
+		return (ENOBUFS);
+	/*
+	 * We need a hint from the user, what policy is requested - input
+	 * or output? User should specify it in the buffer, even for
+	 * setsockopt().
+	 */
+	error = sooptcopyin(sopt, optdata, optlen, optlen);
+	if (error == 0) {
+		if (sopt->sopt_dir == SOPT_SET)
+			error = ipsec_set_pcbpolicy(inp,
+			    sopt->sopt_td ? sopt->sopt_td->td_ucred: NULL,
+			    optdata, optlen);
+		else {
+			error = ipsec_get_pcbpolicy(inp, optdata, &optlen);
+			if (error == 0)
+				error = sooptcopyout(sopt, optdata, optlen);
+		}
+	}
+	free(optdata, M_TEMP);
+	return (error);
+}
 
-	ipsec_delpcbpolicy(inp->inp_sp);
-	inp->inp_sp = NULL;
+struct ipsecrequest *
+ipsec_newisr(void)
+{
 
-	return (0);
+	return (malloc(sizeof(struct ipsecrequest), M_IPSEC_SR,
+	    M_NOWAIT | M_ZERO));
+}
+
+void
+ipsec_delisr(struct ipsecrequest *p)
+{
+
+	free(p, M_IPSEC_SR);
 }
 
 /*

Modified: projects/ipsec/sys/netipsec/ipsec.h
==============================================================================
--- projects/ipsec/sys/netipsec/ipsec.h	Mon Nov 21 12:00:31 2016	(r308923)
+++ projects/ipsec/sys/netipsec/ipsec.h	Mon Nov 21 13:07:57 2016	(r308924)
@@ -298,29 +298,24 @@ VNET_DECLARE(int, crypto_support);
 /* for openbsd compatibility */
 #define	DPRINTF(x)	do { if (V_ipsec_debug) printf x; } while (0)
 
-extern	struct ipsecrequest *ipsec_newisr(void);
-extern	void ipsec_delisr(struct ipsecrequest *);
-
 struct inpcb;
+struct secasvar;
+struct sockopt;
+
+struct ipsecrequest *ipsec_newisr(void);
+void ipsec_delisr(struct ipsecrequest *);
 struct secpolicy *ipsec4_checkpolicy(const struct mbuf *, struct inpcb *,
     int *);
-extern struct secpolicy * ipsec_getpolicybyaddr(const struct mbuf *, u_int,
-    int *);
-
-extern int ipsec_init_policy(struct socket *so, struct inpcbpolicy **);
-extern int ipsec_copy_policy(struct inpcbpolicy *, struct inpcbpolicy *);
 
 u_int ipsec_get_reqlevel(struct secpolicy *, u_int);
 int ipsec4_in_reject(const struct mbuf *, struct inpcb *);
 size_t ipsec_hdrsiz_inpcb(struct inpcb *);
 
-extern int ipsec_set_policy(struct inpcb *inp, int optname,
-	caddr_t request, size_t len, struct ucred *cred);
-extern int ipsec_get_policy(struct inpcb *inpcb, caddr_t request,
-    size_t len, struct mbuf **mp);
-extern int ipsec_delete_pcbpolicy(struct inpcb *);
+int ipsec_init_pcbpolicy(struct inpcb *);
+int ipsec_delete_pcbpolicy(struct inpcb *);
+int ipsec_copy_pcbpolicy(struct inpcb *, struct inpcb *);
+int ipsec_control_pcbpolicy(struct inpcb *, struct sockopt *);
 
-struct secas;
 extern int ipsec_chkreplay(u_int32_t, struct secasvar *);
 extern int ipsec_updatereplay(u_int32_t, struct secasvar *);
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201611211307.uALD7vOA059452>