summaryrefslogtreecommitdiff
path: root/sbin/ipsec/photurisd/kernel.c
diff options
context:
space:
mode:
authorNiels Provos <provos@cvs.openbsd.org>1998-03-04 11:43:56 +0000
committerNiels Provos <provos@cvs.openbsd.org>1998-03-04 11:43:56 +0000
commit4be2eb12506cf065e68c51750f45f81ba3d63717 (patch)
treeb4cb6a032a89a159e425ace730b3bda6a7b1c25f /sbin/ipsec/photurisd/kernel.c
parent8b1bb75ad56e072dc58c33715385fa7e439b2503 (diff)
compliance with draft-simpson-photuris-18.txt, better packet structure
checking, better support for new esp and ah, documentation ...
Diffstat (limited to 'sbin/ipsec/photurisd/kernel.c')
-rw-r--r--sbin/ipsec/photurisd/kernel.c432
1 files changed, 320 insertions, 112 deletions
diff --git a/sbin/ipsec/photurisd/kernel.c b/sbin/ipsec/photurisd/kernel.c
index 09d33c7116b..d36d287b580 100644
--- a/sbin/ipsec/photurisd/kernel.c
+++ b/sbin/ipsec/photurisd/kernel.c
@@ -29,7 +29,7 @@
*/
#ifndef lint
-static char rcsid[] = "$Id: kernel.c,v 1.4 1997/09/14 10:37:51 deraadt Exp $";
+static char rcsid[] = "$Id: kernel.c,v 1.5 1998/03/04 11:43:32 provos Exp $";
#endif
#include <sys/param.h>
@@ -73,13 +73,80 @@ static char rcsid[] = "$Id: kernel.c,v 1.4 1997/09/14 10:37:51 deraadt Exp $";
#include "config.h"
#endif
+#ifdef DEBUG
+time_t now;
+
+#define kernel_debug(x) {time(&now); printf("%.24s", ctime(&now)); printf x;}
+#else
+#define kernel_debug(x)
+#endif
+
static int sd;
+typedef struct {
+ int photuris_id;
+ int kernel_id, flags;
+} transform;
+
+/*
+ * Translation from Photuris Attributes to Kernel Transforms.
+ * For the actual ids see: draft-simpson-photuris-*.txt and
+ * draft-simpson-photuris-schemes-*.txt
+ */
+
+transform xf[] = {
+ { 5, ALG_AUTH_MD5, XF_AUTH|AH_OLD},
+ { 6, ALG_AUTH_SHA1, XF_AUTH|AH_OLD},
+ { 8, ALG_ENC_DES, XF_ENC|ESP_OLD},
+ {100, ALG_ENC_3DES, XF_ENC|ESP_NEW},
+ {101, ALG_ENC_BLF, XF_ENC|ESP_NEW},
+ {102, ALG_ENC_CAST, XF_ENC|ESP_NEW},
+ {105, ALG_AUTH_MD5, XF_AUTH|AH_NEW|ESP_NEW},
+ {106, ALG_AUTH_SHA1, XF_AUTH|AH_NEW|ESP_NEW},
+ {107, ALG_AUTH_RMD160, XF_AUTH|AH_NEW|ESP_NEW},
+};
+
+/*
+ * Translate a Photuris ID to an offset into a data structure for the
+ * corresponding Kernel transform.
+ * This makes is easier to write kernel modules for different IPSec
+ * implementations.
+ */
+
+int
+kernel_get_offset(int id)
+{
+ int i;
+
+ for (i=sizeof(xf)/sizeof(transform)-1; i >= 0; i--)
+ if (xf[i].photuris_id == id)
+ return i;
+
+ return -1;
+}
+
+/*
+ * For ESP, we can specify an additional AH transform.
+ * Not all combinations are possible.
+ * Returns AT_ENC, when the ESP transform does not allow this AH.
+ * Returns AT_AUTH, when the AH transform does not work with ESP.
+ */
+
+int
+kernel_valid(int encoff, int authoff)
+{
+ if (xf[encoff].flags & ESP_OLD)
+ return AT_ENC;
+ if (!(xf[authoff].flags & ESP_NEW))
+ return AT_AUTH;
+ return 0;
+}
+
int
init_kernel(void)
{
if ((sd = socket(AF_ENCAP, SOCK_RAW, AF_UNSPEC)) < 0)
- crit_error(1, "socket() in init_kernel()");
+ crit_error(1, "socket() for IPSec in init_kernel()");
return 1;
}
@@ -92,10 +159,8 @@ kernel_get_socket(void)
int
kernel_xf_set(struct encap_msghdr *em)
{
- if (write(sd, (char *)em, em->em_msglen) != em->em_msglen) {
- log_error(1, "write() in kernel_xf_set()");
+ if (write(sd, (char *)em, em->em_msglen) != em->em_msglen)
return 0;
- }
return 1;
}
@@ -115,6 +180,8 @@ kernel_reserve_spi(char *srcaddress, int options)
u_int32_t spi;
int proto;
+ kernel_debug(("kernel_reserve_spi: %s\n", srcaddress));
+
if ((options & (IPSEC_OPT_ENC|IPSEC_OPT_AUTH)) !=
(IPSEC_OPT_ENC|IPSEC_OPT_AUTH)) {
switch(options & (IPSEC_OPT_ENC|IPSEC_OPT_AUTH)) {
@@ -144,6 +211,8 @@ kernel_reserve_single_spi(char *srcaddress, u_int32_t spi, int proto)
{
struct encap_msghdr *em;
+ kernel_debug(("kernel_reserve_single_spi: %s, %08x\n", srcaddress, spi));
+
bzero(buffer, EMT_ENABLESPI_FLEN);
em = (struct encap_msghdr *)buffer;
@@ -156,8 +225,10 @@ kernel_reserve_single_spi(char *srcaddress, u_int32_t spi, int proto)
em->em_gen_dst.s_addr = inet_addr(srcaddress);
em->em_gen_sproto = proto;
- if (!kernel_xf_set(em))
+ if (!kernel_xf_set(em)) {
+ log_error(1, "kernel_xf_set() in kernel_reserve_single_spi()");
return 0;
+ }
if (!kernel_xf_read(em, EMT_RESERVESPI_FLEN))
return 0;
@@ -166,88 +237,173 @@ kernel_reserve_single_spi(char *srcaddress, u_int32_t spi, int proto)
}
int
-kernel_md5(char *srcaddress, char *dstaddress, u_int8_t *spi, u_int8_t *secret,
- int tunnel)
+kernel_ah(attrib_t *ob, struct spiob *SPI, u_int8_t *secrets)
{
struct encap_msghdr *em;
- struct ah_old_xencap *xd;
- int klen;
+ struct ah_old_xencap *xdo;
+ struct ah_new_xencap *xdn;
- klen = MD5_KEYLEN/8;
-
- bzero(buffer, EMT_SETSPI_FLEN + 4 + klen);
+ if (!(xf[ob->koff].flags & XF_AUTH)) {
+ log_error(0, "%d is not an auth transform in kernel_ah()", ob->id);
+ return -1;
+ }
em = (struct encap_msghdr *)buffer;
+
+ if (xf[ob->koff].flags & AH_OLD) {
+ bzero(buffer, EMT_SETSPI_FLEN + 4 + ob->klen);
+
+ em->em_msglen = EMT_SETSPI_FLEN + AH_OLD_XENCAP_LEN + ob->klen;
+
+ em->em_alg = XF_OLD_AH;
+
+ xdo = (struct ah_old_xencap *)(em->em_dat);
+
+ xdo->amx_hash_algorithm = xf[ob->koff].kernel_id;
+ xdo->amx_keylen = ob->klen;
- em->em_msglen = EMT_SETSPI_FLEN + AH_OLD_XENCAP_LEN + klen;
+ bcopy(secrets, xdo->amx_key, ob->klen);
+
+ } else {
+ bzero(buffer, EMT_SETSPI_FLEN + AH_NEW_XENCAP_LEN + ob->klen);
+
+ em->em_msglen = EMT_SETSPI_FLEN + AH_NEW_XENCAP_LEN + ob->klen;
+
+ em->em_alg = XF_NEW_AH;
+
+ xdn = (struct ah_new_xencap *)(em->em_dat);
+
+ xdn->amx_hash_algorithm = xf[ob->koff].kernel_id;
+ xdn->amx_wnd = 16;
+ xdn->amx_keylen = ob->klen;
+
+ bcopy(secrets, xdn->amx_key, ob->klen);
+ }
+
em->em_version = PFENCAP_VERSION_1;
em->em_type = EMT_SETSPI;
- em->em_spi = htonl((spi[0]<<24) + (spi[1]<<16) +
- (spi[2]<<8) + spi[3]);
- em->em_src.s_addr = inet_addr(srcaddress);
- em->em_dst.s_addr = inet_addr(dstaddress);
-
- if (tunnel) {
- em->em_osrc.s_addr = inet_addr(srcaddress);
- em->em_odst.s_addr = inet_addr(dstaddress);
+ em->em_spi = htonl((SPI->SPI[0]<<24) + (SPI->SPI[1]<<16) +
+ (SPI->SPI[2]<<8) + SPI->SPI[3]);
+ em->em_src.s_addr = inet_addr(SPI->local_address);
+ em->em_dst.s_addr = inet_addr(SPI->flags & SPI_OWNER ?
+ SPI->local_address : SPI->address);
+
+ if (SPI->flags & SPI_TUNNEL) {
+ em->em_osrc.s_addr = inet_addr(SPI->local_address);
+ em->em_odst.s_addr = inet_addr(SPI->flags & SPI_OWNER ?
+ SPI->local_address : SPI->address);
}
-
- em->em_alg = XF_OLD_AH;
em->em_sproto = IPPROTO_AH;
- xd = (struct ah_old_xencap *)(em->em_dat);
+ kernel_debug(("kernel_ah: %08x.\n", em->em_spi));
- xd->amx_hash_algorithm = ALG_AUTH_MD5;
- xd->amx_keylen = klen;
-
- bcopy(secret, xd->amx_key, klen);
-
- if (!kernel_xf_set(em))
+ if (!kernel_xf_set(em)) {
+ log_error(1, "kernel_xf_set() in kernel_ah()");
return -1;
-
- return MD5_KEYLEN/8;
+ }
+ return ob->klen;
}
int
-kernel_des(char *srcaddress, char *dstaddress, u_int8_t *spi, u_int8_t *secret,
- int tunnel)
+kernel_esp(attrib_t *ob, attrib_t *ob2, struct spiob *SPI, u_int8_t *secrets)
{
struct encap_msghdr *em;
- struct esp_old_xencap *xd;
+ struct esp_old_xencap *xdo;
+ struct esp_new_xencap *xdn;
+ attrib_t *attenc, *attauth = NULL;
+ u_int8_t *sec1, *sec2 = NULL;
+
+ if (ob->type & AT_AUTH) {
+ if (ob2 == NULL || ob2->type != AT_ENC) {
+ log_error(0, "No encryption after auth given in kernel_esp()");
+ return -1;
+ }
+ attenc = ob2;
+ attauth = ob;
+ sec2 = secrets;
+ sec1 = secrets + ob->klen;
+ } else if (ob->type == AT_ENC) {
+ attenc = ob;
+ sec1 = secrets;
+ if (ob2 != NULL && (ob2->type & AT_AUTH)) {
+ attauth = ob2;
+ sec2 = secrets + ob->klen;
+ }
+ } else {
+ log_error(0, "No encryption transform given in kernel_esp()");
+ return -1;
+ }
- bzero(buffer, EMT_SETSPI_FLEN + ESP_OLD_XENCAP_LEN + 4 + 8);
+ if ((xf[attenc->koff].flags & ESP_OLD) && attauth != NULL) {
+ log_error(0, "Old ESP does not support AH in kernel_esp()");
+ return -1;
+ }
em = (struct encap_msghdr *)buffer;
-
- em->em_msglen = EMT_SETSPI_FLEN + ESP_OLD_XENCAP_LEN + 4 + 8;
+
+ if (xf[attenc->koff].flags & ESP_OLD) {
+ bzero(buffer, EMT_SETSPI_FLEN + ESP_OLD_XENCAP_LEN +4+attenc->klen);
+
+ em->em_msglen = EMT_SETSPI_FLEN + ESP_OLD_XENCAP_LEN +4+attenc->klen;
+
+ em->em_alg = XF_OLD_ESP;
+
+ xdo = (struct esp_old_xencap *)(em->em_dat);
+
+ xdo->edx_enc_algorithm = ALG_ENC_DES;
+ xdo->edx_ivlen = 4;
+ xdo->edx_keylen = attenc->klen;
+
+ bcopy(SPI->SPI, xdo->edx_data, 4);
+ bcopy(sec1, xdo->edx_data+4, attenc->klen);
+ } else {
+ bzero(buffer, EMT_SETSPI_FLEN + ESP_NEW_XENCAP_LEN + attenc->klen +
+ (attauth ? attauth->klen : 0));
+
+ em->em_msglen = EMT_SETSPI_FLEN + ESP_NEW_XENCAP_LEN +
+ attenc->klen + (attauth ? attauth->klen : 0);
+
+ em->em_alg = XF_NEW_ESP;
+
+ xdn = (struct esp_new_xencap *)(em->em_dat);
+
+ xdn->edx_enc_algorithm = xf[attenc->koff].kernel_id;
+ xdn->edx_hash_algorithm = attauth ? xf[attauth->koff].kernel_id : 0;
+ xdn->edx_ivlen = 0;
+ xdn->edx_confkeylen = attenc->klen;
+ xdn->edx_authkeylen = attauth ? attauth->klen : 0;
+ xdn->edx_wnd = 16;
+ xdn->edx_flags = attauth ? ESP_NEW_FLAG_AUTH : 0;
+
+ bcopy(sec1, xdn->edx_data, attenc->klen);
+ if (attauth != NULL)
+ bcopy(sec2, xdn->edx_data + attenc->klen, attauth->klen);
+ }
+ /* Common settings shared by ESP_OLD and ESP_NEW */
+
em->em_version = PFENCAP_VERSION_1;
em->em_type = EMT_SETSPI;
- em->em_spi = htonl((spi[0]<<24) + (spi[1]<<16) +
- (spi[2]<<8) + spi[3]);
- em->em_src.s_addr = inet_addr(srcaddress);
- em->em_dst.s_addr = inet_addr(dstaddress);
+ em->em_spi = htonl((SPI->SPI[0]<<24) + (SPI->SPI[1]<<16) +
+ (SPI->SPI[2]<<8) + SPI->SPI[3]);
+ em->em_src.s_addr = inet_addr(SPI->local_address);
+ em->em_dst.s_addr = inet_addr(SPI->flags & SPI_OWNER ?
+ SPI->local_address : SPI->address);
+ em->em_sproto = IPPROTO_ESP;
- if (tunnel) {
- em->em_osrc.s_addr = inet_addr(srcaddress);
- em->em_odst.s_addr = inet_addr(dstaddress);
+ if (SPI->flags & SPI_TUNNEL) {
+ em->em_osrc.s_addr = inet_addr(SPI->local_address);
+ em->em_odst.s_addr = inet_addr(SPI->flags & SPI_OWNER ?
+ SPI->local_address : SPI->address);
}
- em->em_alg = XF_OLD_ESP;
- em->em_sproto = IPPROTO_ESP;
-
- xd = (struct esp_old_xencap *)(em->em_dat);
-
- xd->edx_enc_algorithm = ALG_ENC_DES;
- xd->edx_ivlen = 4;
- xd->edx_keylen = 8;
-
- bcopy(spi, xd->edx_data, 4);
- bcopy(secret, xd->edx_data + 8, 8);
+ kernel_debug(("kernel_esp: %08x\n", em->em_spi));
- if (!kernel_xf_set(em))
+ if (!kernel_xf_set(em)) {
+ log_error(1, "kernel_xf_set() in kernel_esp()");
return -1;
+ }
- return 8;
+ return attenc->klen + (attauth ? attauth->klen : 0);
}
/* Group an ESP SPI with an AH SPI */
@@ -260,6 +416,9 @@ kernel_group_spi(char *address, u_int8_t *spi)
u_int32_t SPI;
SPI = (spi[0]<<24) + (spi[1]<<16) + (spi[2]<<8) + spi[3];
+
+ kernel_debug(("kernel_group_spi: %s, %08x\n", address, SPI));
+
addr = inet_addr(address);
bzero(buffer, EMT_GRPSPIS_FLEN);
@@ -277,8 +436,10 @@ kernel_group_spi(char *address, u_int8_t *spi)
em->em_rel_dst2.s_addr = addr;
em->em_rel_sproto2 = IPPROTO_AH;
- if (!kernel_xf_set(em))
+ if (!kernel_xf_set(em)) {
+ log_error(1, "kernel_xf_set() in kernel_group_spi()");
return -1;
+ }
return 1;
}
@@ -293,6 +454,8 @@ kernel_enable_spi(in_addr_t isrc, in_addr_t ismask,
SPI = (spi[0]<<24) + (spi[1]<<16) + (spi[2]<<8) + spi[3];
+ kernel_debug(("kernel_enable_spi: %08x\n", SPI));
+
bzero(buffer, EMT_ENABLESPI_FLEN);
em = (struct encap_msghdr *)buffer;
@@ -311,8 +474,10 @@ kernel_enable_spi(in_addr_t isrc, in_addr_t ismask,
em->em_ena_sproto = proto;
em->em_ena_flags = flags;
- if (!kernel_xf_set(em))
+ if (!kernel_xf_set(em)) {
+ log_error(1, "kernel_xf_set() in kernel_enable_spi()");
return -1;
+ }
return 1;
}
@@ -327,6 +492,8 @@ kernel_disable_spi(in_addr_t isrc, in_addr_t ismask,
SPI = (spi[0]<<24) + (spi[1]<<16) + (spi[2]<<8) + spi[3];
+ kernel_debug(("kernel_disable_spi: %08x\n", SPI));
+
bzero(buffer, EMT_DISABLESPI_FLEN);
em = (struct encap_msghdr *)buffer;
@@ -345,8 +512,10 @@ kernel_disable_spi(in_addr_t isrc, in_addr_t ismask,
em->em_ena_sproto = proto;
em->em_ena_flags = flags;
- if (!kernel_xf_set(em))
+/* if (!kernel_xf_set(em) && errno != ENOENT) {
+ log_error(1, "kernel_xf_set() in kernel_disable_spi()");
return -1;
+ }*/
return 1;
}
@@ -368,8 +537,12 @@ kernel_delete_spi(char *address, u_int8_t *spi, int proto)
em->em_gen_dst.s_addr = inet_addr(address);
em->em_gen_sproto = proto;
- if (!kernel_xf_set(em))
+ kernel_debug(("kernel_delete_spi: %08x\n", em->em_gen_spi));
+
+ if (!kernel_xf_set(em)) {
+ log_error(1, "kernel_xf_set() in kernel_delete_spi()");
return -1;
+ }
return 1;
}
@@ -381,7 +554,9 @@ kernel_insert_spi(struct spiob *SPI)
u_int8_t *attributes;
u_int16_t attribsize;
u_int8_t *secrets;
+ attrib_t *attprop, *attprop2;
int i, n, offset, proto = 0;
+ int phase = 0;
spi = SPI->SPI;
attributes = SPI->attributes;
@@ -391,35 +566,51 @@ kernel_insert_spi(struct spiob *SPI)
for(n=0, i=0; n<attribsize; n += attributes[n+1] + 2) {
switch(attributes[n]) {
case AT_AH_ATTRIB:
+ phase = AT_AH_ATTRIB;
+ break;
case AT_ESP_ATTRIB:
+ phase = AT_ESP_ATTRIB;
break;
- case AT_MD5_KDP:
- offset = kernel_md5(SPI->local_address, SPI->flags & SPI_OWNER ?
- SPI->local_address : SPI->address,
- spi, secrets, SPI->flags & SPI_TUNNEL);
- if (offset == -1)
+ default:
+ if (phase == 0) {
+ log_error(0, "Unaligned attribute %d in kernel_insert_spi()", attributes[n]);
return -1;
- secrets += offset;
- i++;
- if (!proto)
- proto = IPPROTO_AH;
- break;
- case AT_DES_CBC:
- offset = kernel_des(SPI->local_address, SPI->flags & SPI_OWNER ?
- SPI->local_address : SPI->address,
- spi, secrets, SPI->flags & SPI_TUNNEL);
- if (offset == -1)
+ }
+ if ((attprop = getattrib(attributes[n])) == NULL) {
+ log_error(0, "Unknown attribute %d in kernel_insert_spi()",
+ attributes[n]);
return -1;
- secrets += offset;
- i++;
- if (!proto)
- proto = IPPROTO_ESP;
- break;
- default:
- log_error(0, "Unknown attribute %d in kernel_insert_spi()",
- attributes[n]);
- return -1;
+ }
+ switch (phase) {
+ case AT_AH_ATTRIB:
+ offset = kernel_ah(attprop, SPI, secrets);
+ if (offset == -1)
+ return -1;
+ phase = 0;
+ secrets += offset;
+ i++;
+ if (!proto)
+ proto = IPPROTO_AH;
+ break;
+ case AT_ESP_ATTRIB:
+ offset = attributes[n+1] + 2;
+ attprop2 = NULL;
+ if (n+offset < attribsize)
+ attprop2 = getattrib(attributes[n+offset]);
+ if (attprop2 != NULL)
+ n += offset;
+ offset = kernel_esp(attprop, attprop2, SPI, secrets);
+ if (offset == -1)
+ return -1;
+ phase = 0;
+ secrets += offset;
+ i++;
+ if (!proto)
+ proto = IPPROTO_ESP;
+ break;
+ }
}
+
}
/* Group the SPIs for User */
@@ -448,6 +639,8 @@ int
kernel_unlink_spi(struct spiob *ospi)
{
int n, proto = 0;
+ int phase = 0, offset;
+ attrib_t *attprop;
u_int32_t spi;
u_int8_t SPI[SPI_SIZE], *p;
@@ -467,39 +660,54 @@ kernel_unlink_spi(struct spiob *ospi)
SPI[3] = spi & 0xFF;
switch(ospi->attributes[n]) {
case AT_AH_ATTRIB:
+ phase = AT_AH_ATTRIB;
+ break;
case AT_ESP_ATTRIB:
+ phase = AT_ESP_ATTRIB;
break;
- case AT_MD5_KDP:
- if (!proto) {
- proto = IPPROTO_AH;
- if (!(ospi->flags & SPI_OWNER) &&
- kernel_disable_spi(ospi->isrc, ospi->ismask,
- ospi->idst, ospi->idmask,
- ospi->address, ospi->SPI, proto,
- ENABLE_FLAG_LOCAL) == -1)
- log_error(0, "kernel_disable_spi() in kernel_unlink_spi()");
+ default:
+ if (phase == 0) {
+ log_error(0, "Unaligned attribute %d in kernel_unlink_spi()", ospi->attributes[n]);
+ return -1;
+ }
+ if ((attprop = getattrib(ospi->attributes[n])) == NULL) {
+ log_error(0, "Unknown attribute %d in kernel_unlink_spi()",
+ ospi->attributes[n]);
+ return -1;
+ }
+ switch (phase) {
+ case AT_AH_ATTRIB:
+ if (!proto) {
+ proto = IPPROTO_AH;
+ if (!(ospi->flags & SPI_OWNER) &&
+ kernel_disable_spi(ospi->isrc, ospi->ismask,
+ ospi->idst, ospi->idmask,
+ ospi->address, ospi->SPI, proto,
+ ENABLE_FLAG_LOCAL) == -1)
+ log_error(0, "kernel_disable_spi() in kernel_unlink_spi()");
}
if (kernel_delete_spi(p, SPI, IPPROTO_AH) == -1)
log_error(0, "kernel_delete_spi() in kernel_unlink_spi()");
break;
- case AT_DES_CBC:
- if (!proto) {
- proto = IPPROTO_ESP;
- if (!(ospi->flags & SPI_OWNER) &&
- kernel_disable_spi(ospi->isrc, ospi->ismask,
- ospi->idst, ospi->idmask,
- ospi->address, ospi->SPI, proto,
- ENABLE_FLAG_LOCAL) == -1)
- log_error(0, "kernel_disable_spi() in kernel_unlink_spi()");
+ case AT_ESP_ATTRIB:
+ if (!proto) {
+ proto = IPPROTO_ESP;
+ if (!(ospi->flags & SPI_OWNER) &&
+ kernel_disable_spi(ospi->isrc, ospi->ismask,
+ ospi->idst, ospi->idmask,
+ ospi->address, ospi->SPI, proto,
+ ENABLE_FLAG_LOCAL) == -1)
+ log_error(0, "kernel_disable_spi() in kernel_unlink_spi()");
+ }
+ if (kernel_delete_spi(p, SPI, IPPROTO_ESP) == -1)
+ log_error(0, "kernel_delete_spi() in kernel_unlink_spi()");
+ offset = ospi->attributes[n+1] + 2;
+ if ((n + offset < ospi->attribsize) &&
+ getattrib(ospi->attributes[n+offset]) != NULL)
+ n += offset;
+ break;
}
- if (kernel_delete_spi(p, SPI, IPPROTO_ESP) == -1)
- log_error(0, "kernel_delete_spi() in kernel_unlink_spi()");
- break;
- default:
- log_error(0, "Unknown attribute %d in kernel_unlink_spi()",
- ospi->attributes[n]);
- return -1;
}
}