]> git.saurik.com Git - apple/ipsec.git/blobdiff - ipsec-tools/racoon/pfkey_racoon.c
ipsec-146.3.tar.gz
[apple/ipsec.git] / ipsec-tools / racoon / pfkey_racoon.c
index 03e70b4394f9f634a8b4d79b469525c337b63b14..aa10d6da2882807af0cba204d821cda3d79cfab5 100644 (file)
 #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
@@ -133,6 +128,7 @@ static int pk_recvspdexpire __P((caddr_t *));
 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 *)) = {
@@ -159,9 +155,10 @@ pk_recvspdflush,
 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
 };
@@ -191,7 +188,6 @@ static int addnewsp __P((caddr_t *));
 #endif
 #endif
 
-       
 int
 pfkey_process(msg)
        struct sadb_msg *msg;
@@ -273,6 +269,12 @@ pfkey_handler()
        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);
@@ -295,7 +297,13 @@ pfkey_post_handler()
 {
        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);
@@ -357,9 +365,6 @@ pfkey_dump_sadb(satype)
                                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
@@ -370,6 +375,10 @@ pfkey_dump_sadb(satype)
                        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);
@@ -994,6 +1003,13 @@ pk_recvgetspi(mhp)
                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",
@@ -1001,6 +1017,19 @@ pk_recvgetspi(mhp)
                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;
@@ -1026,6 +1055,9 @@ pk_recvgetspi(mhp)
                plog(LLV_ERROR, LOCATION, NULL,
                        "get spi for unknown address %s\n",
                        saddrwop2str(iph2->dst));
+        unbindph12(iph2);
+        remph2(iph2);
+        delph2(iph2);
                return -1;
        }
 
@@ -1122,19 +1154,26 @@ pk_sendupdate(iph2)
                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));
                }
@@ -1178,62 +1217,6 @@ pk_sendupdate(iph2)
                        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;
@@ -1318,6 +1301,13 @@ pk_recvupdate(mhp)
                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",
@@ -1370,6 +1360,23 @@ pk_recvupdate(mhp)
        /* 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",
@@ -1377,7 +1384,8 @@ pk_recvupdate(mhp)
 #endif
 
        /* count up */
-       iph2->ph1->ph2cnt++;
+       if (iph2->ph1)
+               iph2->ph1->ph2cnt++;
 
        /* turn off schedule */
        if (iph2->scr)
@@ -1472,7 +1480,6 @@ pk_sendadd(iph2)
                lifebyte = 0;
 #endif
 
-#ifdef __APPLE__
 #ifdef ENABLE_NATT
                plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_add\n");
 
@@ -1480,12 +1487,20 @@ pk_sendadd(iph2)
                        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));
 
@@ -1538,73 +1553,6 @@ pk_sendadd(iph2)
                        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;
 
@@ -1696,6 +1644,8 @@ pk_recvadd(mhp)
                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;
@@ -1768,7 +1718,7 @@ pk_recvexpire(mhp)
                            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.
@@ -1779,7 +1729,7 @@ pk_recvexpire(mhp)
                 */
                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;
        }
 
@@ -1788,9 +1738,11 @@ pk_recvexpire(mhp)
 
        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);
 
@@ -1801,7 +1753,7 @@ pk_recvexpire(mhp)
                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);
@@ -1912,8 +1864,8 @@ pk_recvacquire(mhp)
         *       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) {
@@ -2025,6 +1977,13 @@ pk_recvacquire(mhp)
                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) {
@@ -2039,10 +1998,19 @@ pk_recvacquire(mhp)
        /* 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:
@@ -2072,7 +2040,6 @@ pk_recvdelete(mhp)
 
        /* 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,
@@ -2100,6 +2067,16 @@ pk_recvdelete(mhp)
                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 */
@@ -2119,6 +2096,7 @@ pk_recvdelete(mhp)
        if (iph2->status == PHASE2ST_ESTABLISHED)
                isakmp_info_send_d2(iph2);
 
+       ike_session_cleanup_ph1s_by_ph2(iph2);
        unbindph12(iph2);
        remph2(iph2);
        delph2(iph2);
@@ -2141,7 +2119,8 @@ pk_recvflush(mhp)
                return -1;
        }
 
-       flushph2();
+       flushph2(false);
+       flushph1(false);
 
        return 0;
 }
@@ -2543,6 +2522,8 @@ pk_recvspddelete(mhp)
                return -1;
        }
 
+    purgephXbyspid(xpl->sadb_x_policy_id, true);
+
        remsp(sp);
        delsp(sp);
 
@@ -2598,6 +2579,8 @@ pk_recvspdexpire(mhp)
                return -1;
        }
 
+    purgephXbyspid(xpl->sadb_x_policy_id, false);
+
        remsp(sp);
        delsp(sp);
 
@@ -2692,6 +2675,8 @@ pk_recvspdflush(mhp)
                return -1;
        }
 
+    flushph2(false);
+    flushph1(false);
        flushsp();
 
        return 0;
@@ -2733,6 +2718,145 @@ pk_sendeacquire(iph2)
        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
@@ -2793,8 +2917,8 @@ pk_checkalg(class, calg, keylen)
  */
 static struct sadb_msg *
 pk_recv(so, lenp)
-int so;
-int *lenp;
+       int so;
+       int *lenp;
 {
        struct sadb_msg *newmsg;
        int reallen = 0; 
@@ -2805,10 +2929,10 @@ int *lenp;
        
        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);
@@ -2817,12 +2941,10 @@ int *lenp;
                racoon_free(newmsg);
                return NULL;
        }
-       
+
        return newmsg;
 }
 
-
-
 /* see handler.h */
 u_int32_t
 pk_getseq()
@@ -2851,14 +2973,6 @@ addnewsp(mhp)
        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,