#include <arpa/inet.h>
#ifdef ENABLE_NATT
-# ifdef __linux__
-# include <linux/udp.h>
-# endif
-# if defined(__NetBSD__) || defined(__FreeBSD__)
-# include <netinet/udp.h>
-# endif
+#include <netinet/udp.h>
#endif
#include <sys/types.h>
#include <sys/sysctl.h>
#include <net/route.h>
-#ifdef __APPLE__
#include <System/net/pfkeyv2.h>
-#else
-#include <net/pfkeyv2.h>
-#endif
#include <netinet/in.h>
#ifndef HAVE_NETINET6_IPSEC
#include "grabmyaddr.h"
#include "vpn_control.h"
#include "vpn_control_var.h"
+#include "ike_session.h"
+#include "ipsecSessionTracer.h"
+#include "ipsecMessageTracer.h"
+#include "power_mgmt.h"
#if defined(SADB_X_EALG_RIJNDAELCBC) && !defined(SADB_X_EALG_AESCBC)
#define SADB_X_EALG_AESCBC SADB_X_EALG_RIJNDAELCBC
static int pk_recvspdget __P((caddr_t *));
static int pk_recvspddump __P((caddr_t *));
static int pk_recvspdflush __P((caddr_t *));
+static int pk_recvgetsastat __P((caddr_t *));
static struct sadb_msg *pk_recv __P((int, int *));
static int (*pkrecvf[]) __P((caddr_t *)) = {
NULL, /* SADB_X_SPDSETIDX */
pk_recvspdexpire,
NULL, /* SADB_X_SPDDELETE2 */
+pk_recvgetsastat, /* SADB_GETSASTAT */
NULL, /* SADB_X_NAT_T_NEW_MAPPING */
NULL, /* SADB_X_MIGRATE */
-#if (SADB_MAX > 24)
+#if (SADB_MAX > 25)
#error "SADB extra message?"
#endif
};
#endif
#endif
-
int
pfkey_process(msg)
struct sadb_msg *msg;
struct sadb_msg *msg;
int len;
+ if (slept_at || woke_at) {
+ plog(LLV_DEBUG, LOCATION, NULL,
+ "ignoring pfkey port until power-mgmt event is handled.\n");
+ return 0;
+ }
+
/* receive pfkey message. */
len = 0;
msg = (struct sadb_msg *)pk_recv(lcconf->sock_pfkey, &len);
{
struct saved_msg_elem *elem;
struct saved_msg_elem *elem_tmp = NULL;
-
+
+ if (slept_at || woke_at) {
+ plog(LLV_DEBUG, LOCATION, NULL,
+ "ignoring (saved) pfkey messages until power-mgmt event is handled.\n");
+ return 0;
+ }
+
TAILQ_FOREACH_SAFE(elem, &lcconf->saved_msg_queue, chain, elem_tmp) {
pfkey_process((struct sadb_msg *)elem->msg);
TAILQ_REMOVE(&lcconf->saved_msg_queue, elem, chain);
continue;
}
- if (msg->sadb_msg_pid != pid)
- continue;
-
/*
* for multi-processor system this had to be added because the messages can
* be interleaved - they won't all be dump messages
continue;
}
+ // ignore dump messages that aren't racoon's
+ if (msg->sadb_msg_pid != pid)
+ continue;
+
ml = msg->sadb_msg_len << 3;
bl = buf ? buf->l : 0;
buf = vrealloc(buf, bl + ml);
return -1;
}
+ if (iph2->is_dying) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "status mismatch phase2 dying (db:%d msg:%d)\n",
+ iph2->status, PHASE2ST_GETSPISENT);
+ return -1;
+ }
+
if (iph2->status != PHASE2ST_GETSPISENT) {
plog(LLV_ERROR, LOCATION, NULL,
"status mismatch (db:%d msg:%d)\n",
return -1;
}
+ // check the underlying iph2->ph1
+ if (!iph2->ph1) {
+ if (!ike_session_update_ph2_ph1bind(iph2)) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "can't proceed with getspi for %s. no suitable ISAKMP-SA found \n",
+ saddrwop2str(iph2->dst));
+ unbindph12(iph2);
+ remph2(iph2);
+ delph2(iph2);
+ return -1;
+ }
+ }
+
/* set SPI, and check to get all spi whether or not */
allspiok = 1;
notfound = 1;
plog(LLV_ERROR, LOCATION, NULL,
"get spi for unknown address %s\n",
saddrwop2str(iph2->dst));
+ unbindph12(iph2);
+ remph2(iph2);
+ delph2(iph2);
return -1;
}
lifebyte = 0;
#endif
-#ifdef __APPLE__
#ifdef ENABLE_NATT
plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_update\n");
if (pr->udp_encap) {
memset (&natt, 0, sizeof (natt));
natt.sport = extract_port (iph2->ph1->remote);
flags |= SADB_X_EXT_NATT;
- if (iph2->ph1->natt_flags & NAT_DETECTED_ME)
- flags |= SADB_X_EXT_NATT_KEEPALIVE;
- else if (iph2->ph1->rmconf->natt_multiple_user == TRUE &&
- mode == IPSEC_MODE_TRANSPORT &&
- src->sa_family == AF_INET)
+ if (iph2->ph1->natt_flags & NAT_DETECTED_ME) {
+ if (iph2->ph1->rmconf->natt_keepalive == TRUE)
+ flags |= SADB_X_EXT_NATT_KEEPALIVE;
+ } else {
+ if (iph2->ph1->rmconf->natt_multiple_user == TRUE &&
+ mode == IPSEC_MODE_TRANSPORT &&
+ src->sa_family == AF_INET) {
flags |= SADB_X_EXT_NATT_MULTIPLEUSERS;
+ }
+ if (iph2->ph1->natt_flags & NAT_DETECTED_PEER) {
+ // is mutually exclusive with SADB_X_EXT_NATT_KEEPALIVE
+ flags |= SADB_X_EXT_NATT_DETECTED_PEER;
+ }
+ }
} else {
memset (&natt, 0, sizeof (natt));
}
return -1;
}
#endif /* ENABLE_NATT */
-#else
-#ifdef ENABLE_NATT
- plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_update_nat\n");
- if (pr->udp_encap) {
- memset (&natt, 0, sizeof (natt));
- natt.type = iph2->ph1->natt_options->encaps_type;
- natt.sport = extract_port (iph2->ph1->remote);
- natt.dport = extract_port (iph2->ph1->local);
- natt.oa = NULL; // FIXME: Here comes OA!!!
- natt.frag = iph2->ph1->rmconf->esp_frag;
- } else {
- memset (&natt, 0, sizeof (natt));
- }
-
- if (pfkey_send_update_nat(
- lcconf->sock_pfkey,
- satype,
- mode,
- dst,
- src,
- pr->spi,
- pr->reqid_in,
- wsize,
- pr->keymat->v,
- e_type, e_keylen, a_type, a_keylen, flags,
- 0, lifebyte, iph2->approval->lifetime, 0,
- iph2->seq,
- natt.type, natt.sport, natt.dport, natt.oa,
- natt.frag) < 0) {
- plog(LLV_ERROR, LOCATION, NULL,
- "libipsec failed send update_nat (%s)\n",
- ipsec_strerror());
- return -1;
- }
-#else
- plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_update\n");
- if (pfkey_send_update(
- lcconf->sock_pfkey,
- satype,
- mode,
- dst,
- src,
- pr->spi,
- pr->reqid_in,
- wsize,
- pr->keymat->v,
- e_type, e_keylen, a_type, a_keylen, flags,
- 0, lifebyte, iph2->approval->lifetime, 0,
- iph2->seq) < 0) {
- plog(LLV_ERROR, LOCATION, NULL,
- "libipsec failed send update (%s)\n",
- ipsec_strerror());
- return -1;
- }
-#endif /* ENABLE_NATT */
-#endif /* __APPLE__ */
if (!lcconf->pathinfo[LC_PATHTYPE_BACKUPSA])
continue;
return -1;
}
+ if (iph2->is_dying) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "status mismatch phase2 dying (db:%d msg:%d)\n",
+ iph2->status, PHASE2ST_ADDSA);
+ return -1;
+ }
+
if (iph2->status != PHASE2ST_ADDSA) {
plog(LLV_ERROR, LOCATION, NULL,
"status mismatch (db:%d msg:%d)\n",
/* update status */
iph2->status = PHASE2ST_ESTABLISHED;
+ if (iph2->side == INITIATOR) {
+ IPSECSESSIONTRACEREVENT(iph2->parent_session,
+ IPSECSESSIONEVENTCODE_IKEV1_PH2_INIT_SUCC,
+ CONSTSTR("Initiator, Quick-Mode"),
+ CONSTSTR(NULL));
+ } else {
+ IPSECSESSIONTRACEREVENT(iph2->parent_session,
+ IPSECSESSIONEVENTCODE_IKEV1_PH2_RESP_SUCC,
+ CONSTSTR("Responder, Quick-Mode"),
+ CONSTSTR(NULL));
+ }
+
+ ike_session_ph2_established(iph2);
+
+ IPSECLOGASLMSG("IPSec Phase2 established (Initiated by %s).\n",
+ (iph2->side == INITIATOR)? "me" : "peer");
+
#ifdef ENABLE_STATS
gettimeofday(&iph2->end, NULL);
syslog(LOG_NOTICE, "%s(%s): %8.6f",
#endif
/* count up */
- iph2->ph1->ph2cnt++;
+ if (iph2->ph1)
+ iph2->ph1->ph2cnt++;
/* turn off schedule */
if (iph2->scr)
lifebyte = 0;
#endif
-#ifdef __APPLE__
#ifdef ENABLE_NATT
plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_add\n");
memset (&natt, 0, sizeof (natt));
natt.dport = extract_port (iph2->ph1->remote);
flags |= SADB_X_EXT_NATT;
- if (iph2->ph1->natt_flags & NAT_DETECTED_ME)
- flags |= SADB_X_EXT_NATT_KEEPALIVE;
- else if (iph2->ph1->rmconf->natt_multiple_user == TRUE &&
- mode == IPSEC_MODE_TRANSPORT &&
- dst->sa_family == AF_INET)
+ if (iph2->ph1->natt_flags & NAT_DETECTED_ME) {
+ if (iph2->ph1->rmconf->natt_keepalive == TRUE)
+ flags |= SADB_X_EXT_NATT_KEEPALIVE;
+ } else {
+ if (iph2->ph1->rmconf->natt_multiple_user == TRUE &&
+ mode == IPSEC_MODE_TRANSPORT &&
+ dst->sa_family == AF_INET) {
flags |= SADB_X_EXT_NATT_MULTIPLEUSERS;
+ }
+ if (iph2->ph1->natt_flags & NAT_DETECTED_PEER) {
+ // is mutually exclusive with SADB_X_EXT_NATT_KEEPALIVE
+ flags |= SADB_X_EXT_NATT_DETECTED_PEER;
+ }
+ }
} else {
memset (&natt, 0, sizeof (natt));
return -1;
}
#endif /* ENABLE_NATT */
-#else /* __APPLE__ */
-#ifdef ENABLE_NATT
- plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_add_nat\n");
-
- if (pr->udp_encap) {
- memset (&natt, 0, sizeof (natt));
- natt.type = UDP_ENCAP_ESPINUDP;
- natt.sport = extract_port (iph2->ph1->local);
- natt.dport = extract_port (iph2->ph1->remote);
- natt.oa = NULL; // FIXME: Here comes OA!!!
- natt.frag = iph2->ph1->rmconf->esp_frag;
- } else {
- memset (&natt, 0, sizeof (natt));
-
- /* Remove port information, that SA doesn't use it */
- set_port(src, 0);
- set_port(dst, 0);
- }
-
- if (pfkey_send_add_nat(
- lcconf->sock_pfkey,
- satype,
- mode,
- src,
- dst,
- pr->spi_p,
- pr->reqid_out,
- wsize,
- pr->keymat_p->v,
- e_type, e_keylen, a_type, a_keylen, flags,
- 0, lifebyte, iph2->approval->lifetime, 0,
- iph2->seq,
- natt.type, natt.sport, natt.dport, natt.oa,
- natt.frag) < 0) {
- plog(LLV_ERROR, LOCATION, NULL,
- "libipsec failed send add_nat (%s)\n",
- ipsec_strerror());
- return -1;
- }
-#else
- plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_add\n");
-
- /* Remove port information, it is not used without NAT-T */
- set_port(src, 0);
- set_port(dst, 0);
-
- if (pfkey_send_add(
- lcconf->sock_pfkey,
- satype,
- mode,
- src,
- dst,
- pr->spi_p,
- pr->reqid_out,
- wsize,
- pr->keymat_p->v,
- e_type, e_keylen, a_type, a_keylen, flags,
- 0, lifebyte, iph2->approval->lifetime, 0,
- iph2->seq) < 0) {
- plog(LLV_ERROR, LOCATION, NULL,
- "libipsec failed send add (%s)\n",
- ipsec_strerror());
- return -1;
- }
-#endif /* ENABLE_NATT */
-#endif /* __APPLE__ */
-
if (!lcconf->pathinfo[LC_PATHTYPE_BACKUPSA])
continue;
sadbsecas2str(iph2->src, iph2->dst,
msg->sadb_msg_satype, sa->sadb_sa_spi, sa_mode));
+ ike_session_cleanup_other_established_ph2s(iph2->parent_session, iph2);
+
#ifdef ENABLE_VPNCONTROL_PORT
{
u_int32_t address;
sa_mode));
return 0;
}
- if (iph2->status != PHASE2ST_ESTABLISHED) {
+ if (iph2->is_dying || iph2->status != PHASE2ST_ESTABLISHED) {
/*
* If the status is not equal to PHASE2ST_ESTABLISHED,
* racoon ignores this expire message. There are two reason.
*/
plog(LLV_WARNING, LOCATION, NULL,
"the expire message is received "
- "but the handler has not been established.\n");
+ "but the handler is dying or has not been established.\n");
return 0;
}
iph2->status = PHASE2ST_EXPIRED;
- /* INITIATOR, begin phase 2 exchange. */
+ /* INITIATOR, begin phase 2 exchange only if there's no other established ph2. */
/* allocate buffer for status management of pfkey message */
- if (iph2->side == INITIATOR) {
+ if (iph2->side == INITIATOR &&
+ !ike_session_has_other_established_ph2(iph2->parent_session, iph2) &&
+ !ike_session_drop_rekey(iph2->parent_session, IKE_SESSION_REKEY_TYPE_PH2)) {
initph2(iph2);
if (isakmp_post_acquire(iph2) < 0) {
plog(LLV_ERROR, LOCATION, iph2->dst,
"failed to begin ipsec sa "
- "re-negotication.\n");
+ "re-negotiation.\n");
unbindph12(iph2);
remph2(iph2);
delph2(iph2);
* should ignore such a acquire message because the phase 2
* is just negotiating.
* 2. its state is equal to PHASE2ST_ESTABLISHED, then racoon
- * has to prcesss such a acquire message because racoon may
- * lost the expire message.
+ * has to process such a acquire message because racoon may
+ * have lost the expire message.
*/
iph2[0] = getph2byid(src, dst, xpl->sadb_x_policy_id);
if (iph2[0] != NULL) {
return -1;
/* XXX should use the algorithm list from register message */
}
+ if (link_sainfo_to_ph2(iph2[n]->sainfo) != 0) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "failed to link sainfo\n");
+ iph2[n]->sainfo = NULL;
+ delph2(iph2[n]);
+ return -1;
+ }
}
if (set_proposal_from_policy(iph2[n], sp_out, sp_in) < 0) {
/* XXX should be looped if there are multiple phase 2 handler. */
if (isakmp_post_acquire(iph2[n]) < 0) {
plog(LLV_ERROR, LOCATION, NULL,
- "failed to begin ipsec sa negotication.\n");
+ "failed to begin ipsec sa negotiation.\n");
goto err;
}
+
+#if !TARGET_OS_EMBEDDED
+ if ( lcconf->vt == NULL){
+ if (!(lcconf->vt = vproc_transaction_begin(NULL)))
+ plog(LLV_ERROR, LOCATION, NULL,
+ "vproc_transaction_begin returns NULL.\n");
+ }
+#endif
+
return 0;
err:
/* sanity check */
if (mhp[0] == NULL
- || mhp[SADB_EXT_SA] == NULL
|| mhp[SADB_EXT_ADDRESS_SRC] == NULL
|| mhp[SADB_EXT_ADDRESS_DST] == NULL) {
plog(LLV_ERROR, LOCATION, NULL,
return -1;
}
+ plog(LLV_DEBUG2, LOCATION, NULL, "SADB delete message: proto-id %d\n", proto_id);
+ plog(LLV_DEBUG2, LOCATION, NULL, "src: %s\n", saddr2str(src));
+ plog(LLV_DEBUG2, LOCATION, NULL, "dst: %s\n", saddr2str(dst));
+
+ if (!sa) {
+ deleteallph2(src, dst, proto_id);
+ deleteallph1(src, dst);
+ return 0;
+ }
+
iph2 = getph2bysaidx(src, dst, proto_id, sa->sadb_sa_spi);
if (iph2 == NULL) {
/* ignore */
if (iph2->status == PHASE2ST_ESTABLISHED)
isakmp_info_send_d2(iph2);
+ ike_session_cleanup_ph1s_by_ph2(iph2);
unbindph12(iph2);
remph2(iph2);
delph2(iph2);
return -1;
}
- flushph2();
+ flushph2(false);
+ flushph1(false);
return 0;
}
return -1;
}
+ purgephXbyspid(xpl->sadb_x_policy_id, true);
+
remsp(sp);
delsp(sp);
return -1;
}
+ purgephXbyspid(xpl->sadb_x_policy_id, false);
+
remsp(sp);
delsp(sp);
return -1;
}
+ flushph2(false);
+ flushph1(false);
flushsp();
return 0;
return 0;
}
+int
+pk_sendget_inbound_sastats(ike_session_t *session)
+{
+ u_int32_t max_stats;
+ u_int32_t seq;
+
+ if (!session) {
+ plog(LLV_DEBUG, LOCATION, NULL, "invalid args in %s \n", __FUNCTION__);
+ return -1;
+ }
+
+ session->traffic_monitor.num_in_curr_req = 0;
+ bzero(session->traffic_monitor.in_curr_req, sizeof(session->traffic_monitor.in_curr_req));
+ max_stats = (sizeof(session->traffic_monitor.in_curr_req) / sizeof(session->traffic_monitor.in_curr_req[0]));
+
+ // get list of SAs
+ if ((session->traffic_monitor.num_in_curr_req = ike_session_get_sas_for_stats(session,
+ IPSEC_DIR_INBOUND,
+ &seq,
+ session->traffic_monitor.in_curr_req,
+ max_stats))) {
+ u_int64_t session_ids[] = {(u_int64_t)session, 0};
+
+ plog(LLV_DEBUG, LOCATION, NULL, "about to call %s\n", __FUNCTION__);
+
+ if (pfkey_send_getsastats(lcconf->sock_pfkey,
+ seq,
+ session_ids,
+ 1,
+ IPSEC_DIR_INBOUND,
+ session->traffic_monitor.in_curr_req,
+ session->traffic_monitor.num_in_curr_req) < 0) {
+ return -1;
+ }
+ plog(LLV_DEBUG, LOCATION, NULL, "%s successful\n", __FUNCTION__);
+
+ return session->traffic_monitor.num_in_curr_req;
+ }
+ return 0;
+}
+
+int
+pk_sendget_outbound_sastats(ike_session_t *session)
+{
+ u_int32_t max_stats;
+ u_int32_t seq;
+
+ if (!session) {
+ plog(LLV_DEBUG, LOCATION, NULL, "invalid args in %s \n", __FUNCTION__);
+ return -1;
+ }
+
+ session->traffic_monitor.num_out_curr_req = 0;
+ bzero(session->traffic_monitor.out_curr_req, sizeof(session->traffic_monitor.out_curr_req));
+ max_stats = (sizeof(session->traffic_monitor.out_curr_req) / sizeof(session->traffic_monitor.out_curr_req[0]));
+
+ // get list of SAs
+ if ((session->traffic_monitor.num_out_curr_req = ike_session_get_sas_for_stats(session,
+ IPSEC_DIR_OUTBOUND,
+ &seq,
+ session->traffic_monitor.out_curr_req,
+ max_stats))) {
+ u_int64_t session_ids[] = {(u_int64_t)session, 0};
+
+ plog(LLV_DEBUG, LOCATION, NULL, "about to call %s\n", __FUNCTION__);
+
+ if (pfkey_send_getsastats(lcconf->sock_pfkey,
+ seq,
+ session_ids,
+ 1,
+ IPSEC_DIR_OUTBOUND,
+ session->traffic_monitor.out_curr_req,
+ session->traffic_monitor.num_out_curr_req) < 0) {
+ return -1;
+ }
+ plog(LLV_DEBUG, LOCATION, NULL, "%s successful\n", __FUNCTION__);
+
+ return session->traffic_monitor.num_out_curr_req;
+ }
+ return 0;
+}
+
+/*
+ * receive GETSPDSTAT from kernel.
+ */
+static int
+pk_recvgetsastat(mhp)
+caddr_t *mhp;
+{
+ struct sadb_msg *msg;
+ struct sadb_session_id *session_id;
+ struct sadb_sastat *stat_resp;
+ ike_session_t *session;
+
+ /* validity check */
+ if (mhp[0] == NULL ||
+ mhp[SADB_EXT_SESSION_ID] == NULL ||
+ mhp[SADB_EXT_SASTAT] == NULL) {
+ plog(LLV_ERROR, LOCATION, NULL,
+ "inappropriate sadb getsastat response.\n");
+ return -1;
+ }
+ msg = (struct sadb_msg *)mhp[0];
+ session_id = (ike_session_t *)mhp[SADB_EXT_SESSION_ID];
+ stat_resp = (struct sadb_sastat *)mhp[SADB_EXT_SASTAT];
+
+ /* the message has to be processed or not ? */
+ if (msg->sadb_msg_pid != getpid()) {
+ plog(LLV_DEBUG, LOCATION, NULL,
+ "%s message is not interesting "
+ "because pid %d is not mine.\n",
+ s_pfkey_type(msg->sadb_msg_type),
+ msg->sadb_msg_pid);
+ return -1;
+ }
+ if (!session_id->sadb_session_id_v[0]) {
+ plog(LLV_DEBUG, LOCATION, NULL,
+ "%s message is bad "
+ "because session-id[0] is invalid.\n",
+ s_pfkey_type(msg->sadb_msg_type));
+ return -1;
+ }
+ session = (__typeof__(session))session_id->sadb_session_id_v[0];
+
+ if (!stat_resp->sadb_sastat_list_len) {
+ plog(LLV_DEBUG, LOCATION, NULL,
+ "%s message is bad "
+ "because it has no sastats.\n",
+ s_pfkey_type(msg->sadb_msg_type));
+ return -1;
+ }
+
+ ike_session_update_traffic_idle_status(session,
+ stat_resp->sadb_sastat_dir,
+ (struct sastat *)(stat_resp + 1),
+ stat_resp->sadb_sastat_list_len);
+ return 0;
+}
+
/*
* check if the algorithm is supported or not.
* OUT 0: ok
*/
static struct sadb_msg *
pk_recv(so, lenp)
-int so;
-int *lenp;
+ int so;
+ int *lenp;
{
struct sadb_msg *newmsg;
int reallen = 0;
if (reallen == 0)
return NULL;
-
+
if ((newmsg = racoon_calloc(1, reallen)) == NULL)
return NULL;
-
+
*lenp = recv(so, (caddr_t)newmsg, reallen, 0);
if (*lenp < 0) {
racoon_free(newmsg);
racoon_free(newmsg);
return NULL;
}
-
+
return newmsg;
}
-
-
/* see handler.h */
u_int32_t
pk_getseq()
daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST];
xpl = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY];
-#ifdef __linux__
- /* bsd skips over per-socket policies because there will be no
- * src and dst extensions in spddump messages. On Linux the only
- * way to achieve the same is check for policy id.
- */
- if (xpl->sadb_x_policy_id % 8 >= 3) return 0;
-#endif
-
new = newsp();
if (new == NULL) {
plog(LLV_ERROR, LOCATION, NULL,