]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - keystone-rtos/netapi.git/blobdiff - ti/runtime/netapi/src/netapi_sec.c
Additional fix for SDOCM00107974: Add support for hmac-sha256 in netapi ipsecmgr...
[keystone-rtos/netapi.git] / ti / runtime / netapi / src / netapi_sec.c
old mode 100644 (file)
new mode 100755 (executable)
index 9ec00c0..09ffe7e
@@ -4,12 +4,12 @@
  **************************************************************
  * @file netapi_sec.c
  * 
- * @brief DESCRIPTION:  netapi security  cfg file for user space transport
+ * @brief DESCRIPTION:  netapi security cfg file for user space transport
  *               library
  * 
- * REVISION HISTORY:  rev 0.0.1 
+ * REVISION HISTORY:
  *
- *  Copyright (c) Texas Instruments Incorporated 2010-2011
+ *  Copyright (c) Texas Instruments Incorporated 2013
  * 
  *  Redistribution and use in source and binary forms, with or without 
  *  modification, are permitted provided that the following conditions 
  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
  *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *****************************************************************************/
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
+
 #include "netapi.h"
-#include "netapi_loc.h"
-
-
-//add a RX Security Association 
-NETCP_CFG_SA_T netapi_secAddSA(NETAPI_T h, //the  netapi handle
-                                int iface_no, //inteface to attach to
-                                NETAPI_SEC_SA_INFO_T *sa_info   ,//info on the SA
-                                nwalSecKeyParams_t * key_params, //keys,etc
-                                int inflow_mode, //SA implementation mode: inflow or sideband or both
-                                NETCP_CFG_ROUTE_HANDLE_T  route,  //Optional route
-                                void **p_data_mode_handle,
-                                void **p_inflow_mode_handle,
-                                int * perr)
-{
-NETAPI_HANDLE_T * n = (NETAPI_HANDLE_T *) h;
-nwal_RetValue       retValue;
-NetapiNwalTransInfo_t *pTransInfo;
-nwal_TransID_t     trans_id;
-unsigned int appId = NETAPI_NETCP_MATCH_IPSEC | iface_no;
-int tunnelId;
-nwalSaIpSecId_t  saInfo;
-int have_to_wait=1;
-nwalCreateSAParams_t    createParam =
+
+/********************************************************************
+ * FUNCTION PURPOSE:  API to add an IPSEC SA
+ ********************************************************************
+ * DESCRIPTION:  API to add an IPSEC SA
+ ********************************************************************/
+NETCP_CFG_SA_T netapi_secAddSA(NETAPI_T h,
+                               int iface_no,
+                               NETAPI_SEC_SA_INFO_T *sa_info,
+                               nwalSecKeyParams_t * key_params,
+                               int inflow_mode,
+                               NETCP_CFG_ROUTE_HANDLE_T  route,
+                               void **p_data_mode_handle,
+                               void **p_inflow_mode_handle,
+                               void * p_user_data,
+                               int * perr)
 {
-/* mac handle */
-       NULL,  //to be filled in
+    NETAPI_HANDLE_T * n = (NETAPI_HANDLE_T *) h;
+    nwal_RetValue       retValue;
+    NetapiNwalTransInfo_t *pTransInfo;
+    nwal_TransID_t     trans_id;
+    unsigned int appId = NETAPI_NETCP_MATCH_IPSEC | iface_no;
+    int tunnelId;
+    nwalSaIpSecId_t  saInfo;
+    int have_to_wait=1;
+    nwalTxDmPSCmdInfo_t     dmPSCmdInfo;
+    nwalSaIpSecId_t nwalSaIpSecId;
+    uint32_t    swInfo0 = 0;
+    uint32_t    swInfo1 = 0;
+
+    nwalCreateSAParams_t    createParam =
+    {
+        /* mac handle */
+        NULL,  //to be filled in
         4,
+        /*nwalSaIpSecParam_t */
+            {
+                0,/* validParams */
+                nwal_SA_MODE_TUNNEL,  //update from input
+                64,/* replayWindow */\
+                NWAL_SA_DIR_INBOUND,
+                0,
+                0,
+                NWAL_SA_AALG_HMAC_SHA1,/* update from input */
+                NWAL_SA_EALG_AES_CTR,  /* update from input */
+                { 0x00},      /* remMacAddr:  NA */
+                12,             /* update from input, mac size */
+                NWAL_MATCH_ACTION_CONTINUE_NEXT_ROUTE,/* Continue parsing to next route for match */
+                NWAL_NEXT_ROUTE_FAIL_ACTION_HOST,/* For next route fail action by default is route to host */
+                CPPI_PARAM_NOT_SPECIFIED,         /* Use default flow configured to NWAL  if packet is routed to host */
+                QMSS_PARAM_NOT_SPECIFIED,         /* Use default queue configured to NWAL if packet is routed to host */
+                0                                 /* route type */
+           },
+           /* nwalSaIpSecKeyParams_t */
+           {0}
+    };
+
+
+    void * mac_handle = netapip_netcpCfgGetMacHandle(&netapi_get_global()->nwal_context,iface_no);
+    *perr =NETAPI_ERR_OK;
+    if ((!n) || (!sa_info)  ||  (!p_data_mode_handle))
+    {
+        *perr = NETAPI_ERR_BAD_INPUT;
+        return -1;
+    }
 
-/*nwalSaIpSecParam_t */  
-    {   
-        0,/* validParams */
-        nwal_SA_MODE_TUNNEL,  //update from input
-        64,/* replayWindow */
-        NWAL_SA_DIR_INBOUND,
-        0,
-        0,
-        NWAL_SA_AALG_HMAC_SHA1,  //update
-        NWAL_SA_EALG_AES_CTR, //update
-        { 0x00},      /* remMacAddr:  NA */
-        12, /* macSize */
-        NWAL_MATCH_ACTION_CONTINUE_NEXT_ROUTE,       /* Continue parsing to next route for match */
-        NWAL_NEXT_ROUTE_FAIL_ACTION_HOST,            /* For next route fail action by default is route to host */
-        CPPI_PARAM_NOT_SPECIFIED,                    /* Use default flow configured to NWAL  if packet is routed to host */
-        QMSS_PARAM_NOT_SPECIFIED                     /* Use default queue configured to NWAL if packet is routed to host */
-    },
-    /* nwalSaIpSecKeyParams_t */
-    {0}
-};
-   void * mac_handle = netcp_cfgp_get_mac_handle(&netapi_get_global()->nwal_context,iface_no);
-
-    *perr =0;
-    if ((!n) || (!sa_info)  || (!mac_handle)|| (!p_data_mode_handle) ) {*perr = NETAPI_ERR_BAD_INPUT; return -1;}
+    /* reserve a slot */
+    tunnelId = netapip_netcpCfgFindSaSlot(n,
+                                          &netapi_get_global()->nwal_context,
+                                          iface_no);
 
-    //reserve a slot
-    tunnelId = netcp_cfgp_find_sa_slot(&netapi_get_global()->nwal_context,
-                           iface_no);
-    if (tunnelId <0) {*perr= NETAPI_ERR_NOMEM;  return -1; }
-    appId |=  (tunnelId<<8);
+    if (tunnelId <0)
+    {
+        *perr= NETAPI_ERR_NOMEM;
+        return -1;
+    }
+    appId |=  (tunnelId << NETAPI_NETCP_MATCH_ID_SHIFT);
+    netapi_Log("netapi_secAddSA: app id: 0x%x\n", appId);
 
     *p_data_mode_handle= NULL;  
-    *p_inflow_mode_handle= NULL;  
+    *p_inflow_mode_handle= NULL;
 
-    if (inflow_mode & NETAPI_SEC_SA_INFLOW)    
-    {
 
-    pTransInfo = netapip_GetFreeTransInfo((NETAPI_GLOBAL_T *) n->global, &trans_id);
-    if (!pTransInfo) { *perr =  NETAPI_ERR_BUSY;netcp_cfgp_delete_sa(&netapi_get_global()->nwal_context,tunnelId); return -1;}
-    pTransInfo->transType = NETAPI_NWAL_HANDLE_TRANS_SA;
-    pTransInfo->netapi_handle = h;
-
-    /* build SA parameters */
-    saInfo.spi = sa_info->spi;
-    memcpy(&saInfo.dst, &sa_info->dst, sizeof( nwalIpAddr_t));
-    memcpy(&saInfo.src, &sa_info->src, sizeof( nwalIpAddr_t));
-    saInfo.proto = sa_info->proto;
-    createParam.macHandle = mac_handle;
-    createParam.ipType = sa_info->ipType;
-    //memcpy(&createParam.saIpSecParam.src,&sa_info->src, sizeof(nwalIpAddr_t));
-    createParam.saIpSecParam.dir = sa_info->dir;
-    createParam.saIpSecParam.saMode = sa_info->saMode;
-    createParam.saIpSecParam.replayWindow = sa_info->replayWindow;
-    createParam.saIpSecParam.authMode = sa_info->authMode;
-    createParam.saIpSecParam.cipherMode = sa_info->cipherMode;
-    createParam.saIpSecParam.esnLo = sa_info->esnLo;
-    createParam.saIpSecParam.esnHi = sa_info->esnHi;
-    memcpy(&createParam.keyParam,key_params,sizeof(nwalSecKeyParams_t));
 
-    if (route != NULL)
-    {
-        netcp_cfgp_build_route(route,&createParam.saIpSecParam.appRxPktFlowId, 
-                                     &createParam.saIpSecParam.appRxPktQueue);
-    }
-    
-    //fire off config message
-    pTransInfo->state == NETAPI_NWAL_HANDLE_STATE_OPEN_PENDING;
-    retValue = nwal_setSecAssoc (((NETAPI_GLOBAL_T*) (n->global))->nwal_context.nwalInstHandle,
-                                  trans_id,
-                                 (nwal_AppId) appId,
-                                  &saInfo,
-                                  &createParam,
-                                  &pTransInfo->handle);
-    if(retValue == nwal_TRANS_COMPLETE)
-    {
-       have_to_wait=0;
-    }
-    else if(retValue !=  nwal_OK)
+    if (inflow_mode & NETAPI_SEC_SA_INFLOW)
     {
-        *perr = NETAPI_ERR_NWAL_ERR0;
-        printf (">netapi_sec - ERROR: nwal_setSecAssoc returned Error Code %d\n",
-                    retValue);
-        pTransInfo->inUse = nwal_FALSE;
-        netcp_cfgp_delete_sa(&netapi_get_global()->nwal_context,tunnelId);
-        return -1;
-    }
-    //pTransInfo->inUse = nwal_FALSE;
+        pTransInfo = netapip_getFreeTransInfo(n,
+                                              (NETAPI_PROC_GLOBAL_T *) n->proc_global,
+                                               &trans_id);
+        if (!pTransInfo)
+        {
+            *perr =  NETAPI_ERR_BUSY;
+            netapip_netcpCfgDeleteSa(&netapi_get_global()->nwal_context,tunnelId);
+            return -1;
+        }
+        pTransInfo->transType = NETAPI_NWAL_HANDLE_TRANS_SA;
+        pTransInfo->state = NETAPI_NWAL_HANDLE_STATE_OPEN_PENDING;
+        pTransInfo->inUse = nwal_TRUE;
+        pTransInfo->netapi_handle = h;
+
+        /* build SA parameters */
+        saInfo.spi = sa_info->spi;
+        memcpy(&saInfo.dst, &sa_info->dst, sizeof( nwalIpAddr_t));
+        memcpy(&saInfo.src, &sa_info->src, sizeof( nwalIpAddr_t));
+        saInfo.proto = sa_info->proto;
+        createParam.macHandle = mac_handle;
+        createParam.ipType = sa_info->ipType;
+        createParam.saIpSecParam.dir = sa_info->dir;
+        createParam.saIpSecParam.saMode = sa_info->saMode;
+        createParam.saIpSecParam.replayWindow = sa_info->replayWindow;
+        createParam.saIpSecParam.authMode = sa_info->authMode;
+        createParam.saIpSecParam.cipherMode = sa_info->cipherMode;
+        createParam.saIpSecParam.esnLo = sa_info->esnLo;
+        createParam.saIpSecParam.esnHi = sa_info->esnHi;
+        if ((sa_info->cipherMode == NWAL_SA_EALG_AES_GCM) ||
+            (sa_info->cipherMode == NWAL_SA_EALG_AES_CCM) ||
+            (sa_info->authMode == NWAL_SA_AALG_GMAC)      ||
+            (sa_info->authMode == NWAL_SA_AALG_HMAC_SHA2_256)      ||
+            (sa_info->authMode == NWAL_SA_AALG_HMAC_SHA2_256_RFC4868))
+        {
+            createParam.saIpSecParam.macSize = 16;
+        }
+        if  ((sa_info->authMode == NWAL_SA_AALG_NULL) && 
+            (!((sa_info->cipherMode == NWAL_SA_EALG_AES_GCM) || 
+               (sa_info->cipherMode == NWAL_SA_EALG_AES_CCM))))
+        {
+            createParam.saIpSecParam.replayWindow = 0;
+            createParam.saIpSecParam.macSize = 0;
+        }
+        memcpy(&createParam.keyParam,key_params,sizeof(nwalSecKeyParams_t));
 
-    //wait here until its done since scheduler isn't running yet most likely..
-    // todo:  make this handled by scheduler poll later ??
-    if((trans_id != NWAL_TRANSID_SPIN_WAIT)&&(have_to_wait))
-    {
-        n->nwal_local.numPendingCfg++;
-        while ((volatile) n->nwal_local.numPendingCfg)
+        if (route != NULL)
         {
-            // if response is there, then this poll squirts out in the CTl poll callback, 
-            // which handles the rest (including decrmenting #pending!!
-            nwal_pollCtl(((NETAPI_GLOBAL_T*) (n->global))->nwal_context.nwalInstHandle,NULL,NULL);
+            if((route->valid_params & NETCP_CFG_VALID_PARAM_ROUTE_TYPE) ==
+                NETCP_CFG_VALID_PARAM_ROUTE_TYPE)
+            {
+               createParam.saIpSecParam.validParams |= 
+                        NWAL_SA_INFO_VALID_PARAM_ROUTE_TYPE;
+            }
+            netapip_netcpCfgBuildRoute(route,
+                                       &createParam.saIpSecParam.appRxPktFlowId,
+                                       &createParam.saIpSecParam.appRxPktQueue,
+                                       &createParam.saIpSecParam.routeType);
         }
-    }
-    printf (">netapi sec: SA %d added to mac %d\n", tunnelId, iface_no);
 
-    pTransInfo->state =  NETAPI_NWAL_HANDLE_STATE_IDLE;
-    *p_inflow_mode_handle=pTransInfo->handle;  
-    pTransInfo->inUse = nwal_FALSE;
+        /* fire off config message */
+        retValue = nwal_setSecAssoc (((NETAPI_GLOBAL_T*) (n->global))->nwal_context.nwalInstHandle,
+                                        trans_id,
+                                        (nwal_AppId) appId,
+                                        &saInfo,
+                                        &createParam,
+                                        &pTransInfo->handle);
+        if(retValue == nwal_TRANS_COMPLETE)
+        {
+            have_to_wait=0;
+        }
+        else if(retValue !=  nwal_OK)
+        {
+            *perr = NETAPI_ERR_NWAL_ERR0;
+            netapip_freeTransInfo(pTransInfo);
+            netapip_netcpCfgDeleteSa(&netapi_get_global()->nwal_context,tunnelId);
+            return -1;
+        }
+
+        if((trans_id != NWAL_TRANSID_SPIN_WAIT)&&(have_to_wait))
+        {
+            n->nwal_local.numPendingCfg++;
+            while ((pTransInfo->state  !=NETAPI_NWAL_HANDLE_STATE_ERR) &&
+                    (pTransInfo->state !=NETAPI_NWAL_HANDLE_STATE_OPEN))
+            {
+                nwal_pollCtl(((NETAPI_GLOBAL_T*) (n->global))->nwal_context.nwalInstHandle,NULL,NULL);
+            }
+            if (pTransInfo->state == NETAPI_NWAL_HANDLE_STATE_ERR)
+            {
+                pTransInfo->state = NETAPI_NWAL_HANDLE_STATE_IDLE;
+                pTransInfo->inUse = nwal_FALSE;
+                *perr = NETAPI_ERR_PA_FW;
+                netapi_Log ("netapi_sec - ERROR returned by NETCP PA firmware %d\n",
+                        *perr);
+                netapip_netcpCfgDeleteSa(&netapi_get_global()->nwal_context,tunnelId);
+                return -1;
+            }
+        }
+
+        *p_inflow_mode_handle=pTransInfo->handle;
+        netapip_freeTransInfo(pTransInfo);
+
+        if (sa_info->dir == NWAL_SA_DIR_OUTBOUND)
+        {
+            memset(&nwalSaIpSecId, 0, sizeof(nwalSaIpSecId_t));
+            nwalSaIpSecId.spi = sa_info->spi;
+            memcpy(&(nwalSaIpSecId.src), &sa_info->src,sizeof( nwalIpAddr_t));
+            memcpy(&(nwalSaIpSecId.dst), &sa_info->dst,sizeof( nwalIpAddr_t));
+            nwalSaIpSecId.proto = sa_info->proto;
+            if (nwal_getSecAssoc(((NETAPI_GLOBAL_T*) (n->global))->nwal_context.nwalInstHandle,
+                                     &nwalSaIpSecId, 
+                                     NWAL_SA_DIR_OUTBOUND,
+                                     p_inflow_mode_handle,
+                                     &swInfo0,
+                                     &swInfo1) == nwal_TRUE)
+            {
+                //netapi_Log("netapisecAddSA swInfo0: 0x%x, swInfo1: 0x%x\n", swInfo0, swInfo1);
+            }
+            else
+                netapi_Log("netapisecAddSA: call to nwal_getSecAssoc() returned error\n");
+        }
     }
 
-    //sideband mode
+    /* sideband mode */
     if (inflow_mode &NETAPI_SEC_SA_SIDEBAND)
     {
-       nwalCreateDmSAParams_t  dmSaParam;
+        nwalCreateDmSAParams_t  dmSaParam;
         void * dm_handle;
         memset(&dmSaParam,0,sizeof(nwalCreateDmSAParams_t));
         dmSaParam.dmSaParam.dmChnType= (sa_info->dir==NWAL_SA_DIR_INBOUND)?  NWAL_DM_CHAN_DECRYPT: NWAL_DM_CHAN_ENCRYPT; /**direction*/ 
-        dmSaParam.dmSaParam.replayWindow=sa_info->replayWindow;   /**< Replay Window Size */
-        dmSaParam.dmSaParam.authMode=sa_info->authMode;            /**< Authentication Algorithm */
-        dmSaParam.dmSaParam.cipherMode=sa_info->cipherMode    ;     /**< Encryption Algorithm */
-        dmSaParam.dmSaParam.macSize=12;        /**todo: pass in or deduce */
-        dmSaParam.dmSaParam.aadSize=0;        /**todo: pass in or deduce */
+        dmSaParam.dmSaParam.replayWindow=sa_info->replayWindow;
+        dmSaParam.dmSaParam.authMode=sa_info->authMode;
+        dmSaParam.dmSaParam.cipherMode=sa_info->cipherMode;
+        dmSaParam.dmSaParam.macSize=12;
+        dmSaParam.dmSaParam.aadSize=0;
         dmSaParam.dmSaParam.enc1st =  (sa_info->dir ==NWAL_SA_DIR_OUTBOUND) ? nwal_TRUE : nwal_FALSE;  //encypt 1st for outbound
-        //todo; allow app q for Sideband return
-        dmSaParam.dmSaParam.appRxPktFlowId= CPPI_PARAM_NOT_SPECIFIED; 
-        dmSaParam.dmSaParam.appRxPktQueue= CPPI_PARAM_NOT_SPECIFIED; 
+        if ((sa_info->cipherMode == NWAL_SA_EALG_AES_GCM) ||
+            (sa_info->cipherMode == NWAL_SA_EALG_AES_CCM) ||
+            (sa_info->authMode == NWAL_SA_AALG_GMAC))
+        {
+            dmSaParam.dmSaParam.macSize = 16;
+            dmSaParam.dmSaParam.aadSize=8;
+            /* Enc1st needs to always be true for combined mode algorithms */
+            dmSaParam.dmSaParam.enc1st = nwal_TRUE;
+        }
+       else
+        {
+            dmSaParam.dmSaParam.macSize=12;
+            dmSaParam.dmSaParam.aadSize=0;
+        }
+
+       if  (sa_info->authMode == NWAL_SA_AALG_NULL)
+       {
+            dmSaParam.dmSaParam.enc1st = nwal_TRUE;
+       }
+        /* todo; allow app q for Sideband return */
         memcpy(&dmSaParam.keyParam,key_params,sizeof(nwalSecKeyParams_t));
         retValue = nwal_setDMSecAssoc(((NETAPI_GLOBAL_T*) (n->global))->nwal_context.nwalInstHandle,
                                   (nwal_AppId)appId,
@@ -202,140 +289,193 @@ nwalCreateSAParams_t    createParam =
                                   &dm_handle);
         if(retValue != nwal_OK)
         {
-               *perr = NETAPI_ERR_NWAL_ERR0;
-               printf (">netapi_sec - ERROR: nwal_setDMSecAssoc returned Error Code %d\n",
-                    retValue);
-                netcp_cfgp_delete_sa(&netapi_get_global()->nwal_context,tunnelId);
-                return -1;
+            *perr = NETAPI_ERR_NWAL_ERR0;
+            netapi_Log ("netapi_secAddSA: nwal_setDMSecAssoc() returned Error Code %d\n",
+            retValue);
+            netapip_netcpCfgDeleteSa(&netapi_get_global()->nwal_context,tunnelId);
+            return -1;
         }
-        printf(">netapisec %d Creating sideband mode SA for %d ( mac %d)\n", tunnelId, iface_no); 
+
+        //netapi_Log("netapi_secAddSA: Creating sideband mode SA for %d ( mac %d)\n", tunnelId, iface_no); 
         *p_data_mode_handle = dm_handle;
+        memset(&dmPSCmdInfo, 0, sizeof(nwalTxDmPSCmdInfo_t));
+        retValue =  nwal_initDMPSCmdInfo(netapip_returnNwalInstanceHandle(h),
+                                         *p_data_mode_handle,
+                                         &dmPSCmdInfo); 
     }
-    //save stuff
-    netcp_cfgp_insert_sa(&netapi_get_global()->nwal_context,
-                           tunnelId,
-                         (sa_info->dir ==   NWAL_SA_DIR_INBOUND) ? TRUE: FALSE,
+
+    netapip_netcpCfgInsertSa(&netapi_get_global()->nwal_context,
+                          tunnelId,
+                          (sa_info->dir ==   NWAL_SA_DIR_INBOUND) ? NETAPI_TRUE: NETAPI_FALSE,
                           inflow_mode,
-                          &saInfo, &createParam,
+                          &saInfo,
+                         &createParam,
                           *p_inflow_mode_handle,
-                          *p_data_mode_handle);
+                          *p_data_mode_handle,
+                          &dmPSCmdInfo,
+                          swInfo0,
+                          swInfo1,
+                          p_user_data);
     return  (appId);
 }
 
-//enable or disable inflow mode
-void netapi_secInflowMode(int iface, NETCP_CFG_SA_T sa,  int on)
+/********************************************************************
+ * FUNCTION PURPOSE:  Internal function  to dynamically switch between inflow
+ *                                  and sideband mode
+ ********************************************************************
+ * DESCRIPTION:  Internal function  to dynamically switch between inflow
+ *                                  and sideband mode
+ ********************************************************************/
+void netapi_secInflowMode(int iface,
+                          NETCP_CFG_SA_T sa,
+                          int on)
 {
-  /*todo */   /* FUTURE */
-  printf(">netapi_sec:  dynamic switch between inflow and sideband is not functional yet\n");
+    /* NOT_IMPLEMENTED */
+    netapi_Log("netapi_secInflowMode:  dynamic switch between inflow and sideband is NOT_IMPLEMENTED\n");
 }
 
-//delete the SA
-//(internal version)
-static void netapi_secDelSA_internal(NETAPI_T h,int iface_no, NETCP_CFG_SA_T  sa_app_id, int flags, int *perr)
+/********************************************************************
+ * FUNCTION PURPOSE:  Internal function  to delete an IPSEC SA
+ ********************************************************************
+ * DESCRIPTION:  Internal function to delete an IPSEC SA
+ ********************************************************************/
+static void netapi_secDelSA_internal(NETAPI_T h,
+                                     int iface_no,
+                                     NETCP_CFG_SA_T sa_app_id,
+                                     int flags,
+                                     int *perr)
 {
-NETAPI_HANDLE_T * n = (NETAPI_HANDLE_T *) h;
-nwal_RetValue       retValue;
-NetapiNwalTransInfo_t *pTransInfo;
-nwal_TransID_t     trans_id;
-int tunnelId = (sa_app_id >>8) &0xffff;
-void * handle_inflow;
-void * handle_sideband;
-int have_to_wait = 1;
-
-    handle_inflow = netcp_cfgp_get_sa_handles(&netapi_get_global()->nwal_context,
+    NETAPI_HANDLE_T * n = (NETAPI_HANDLE_T *) h;
+    nwal_RetValue       retValue;
+    NetapiNwalTransInfo_t *pTransInfo;
+    nwal_TransID_t     trans_id;
+    int tunnelId = (sa_app_id >> NETAPI_NETCP_MATCH_ID_SHIFT) &NETAPI_NETCP_MATCH_ID_MASK;
+    void * handle_inflow;
+    void * handle_sideband;
+    int have_to_wait = 1;
+
+    handle_inflow = netapip_netcpCfgGetSaHandles(&netapi_get_global()->nwal_context,
                                           tunnelId, &handle_sideband);
     *perr =0;
 
     if(handle_inflow)
     {
-    //get a transaction id
-    pTransInfo = netapip_GetFreeTransInfo((NETAPI_GLOBAL_T *) n->global, &trans_id);
-    if (!pTransInfo) { *perr =  NETAPI_ERR_BUSY; return ;}
-    pTransInfo->transType = NETAPI_NWAL_HANDLE_TRANS_SA;
-    pTransInfo->netapi_handle = h;
+    /* get a transaction id */
+        pTransInfo = netapip_getFreeTransInfo(n,
+                                              (NETAPI_PROC_GLOBAL_T *) n->proc_global,
+                                              &trans_id);
+        if (!pTransInfo)
+        {
+            *perr =  NETAPI_ERR_BUSY;
+            return;
+        }
+        pTransInfo->transType = NETAPI_NWAL_HANDLE_TRANS_SA;
+        pTransInfo->state = NETAPI_NWAL_HANDLE_STATE_CLOSE_PENDING;
+        pTransInfo->inUse = nwal_TRUE;
+        pTransInfo->netapi_handle = h;
 
-    //issue request
-    retValue = nwal_delSecAssoc(
+        retValue = nwal_delSecAssoc(
                 ((NETAPI_GLOBAL_T*) (n->global))->nwal_context.nwalInstHandle,
                 trans_id,
                 handle_inflow);
-    if(retValue == nwal_TRANS_COMPLETE)
-    {
-       have_to_wait=0;
-    }
-    else
-    if(retValue !=  nwal_OK)
-    {
-        *perr = NETAPI_ERR_NWAL_ERR0;
-        printf (">netapi_sec  - ERROR: nwal_delSA returned Error Code %d\n",
-                    retValue);
-        pTransInfo->inUse = nwal_FALSE;
-        return ;
-    }
-    //wait here until its done since scheduler isn't running yet most likely..
-    // todo:  make this handled by scheduler poll later ??
-    if((trans_id != NWAL_TRANSID_SPIN_WAIT)&&(have_to_wait))
-    {   
-        n->nwal_local.numPendingCfg++;
-        while ((volatile) n->nwal_local.numPendingCfg)
+        if(retValue == nwal_TRANS_COMPLETE)
         {
-            // if response is there, then this poll squirts out in the CTl poll callback, 
-            // which handles the rest (including decrmenting #pending!!
-            nwal_pollCtl(((NETAPI_GLOBAL_T*) (n->global))->nwal_context.nwalInstHandle,NULL,NULL);
+           have_to_wait=0;
+        }
+        else if(retValue !=  nwal_OK)
+        {
+                *perr = NETAPI_ERR_NWAL_ERR0;
+                netapi_Log ("netcp_cfg - ERROR: netapi_secDelSA_internal returned Error Code %d\n",
+                            retValue);
+                netapip_freeTransInfo(pTransInfo);
+                netapip_netcpCfgDeleteSa(&netapi_get_global()->nwal_context,tunnelId);
         }
-    }   
-    printf (">netapi sec: inflow tunnel %d (iface %d) deleted\n",tunnelId,iface_no);
-    pTransInfo->state =  NETAPI_NWAL_HANDLE_STATE_IDLE;
-    pTransInfo->inUse = nwal_FALSE;
+        if((trans_id != NWAL_TRANSID_SPIN_WAIT)&&(have_to_wait))
+        {
+            n->nwal_local.numPendingCfg++;
+
+            while ((pTransInfo->state  !=NETAPI_NWAL_HANDLE_STATE_ERR) &&
+                    (pTransInfo->state !=NETAPI_NWAL_HANDLE_STATE_IDLE))
+            {
+                nwal_pollCtl(((NETAPI_GLOBAL_T*) (n->global))->nwal_context.nwalInstHandle,NULL,NULL);
+            }
+            if (pTransInfo->state == NETAPI_NWAL_HANDLE_STATE_ERR)
+            {
+                netapip_freeTransInfo(pTransInfo);
+                *perr = NETAPI_ERR_PA_FW;
+                 if (!flags) 
+                    netapip_netcpCfgDeleteSa(&netapi_get_global()->nwal_context, tunnelId);
+                netapi_Log ("netapi_sec - ERROR returned by NETCP PA firmware %d\n",
+                        *perr);
+                return;
+           }
+        }
+        netapi_Log ("netapi sec: inflow tunnel %d (iface %d) deleted\n",tunnelId,iface_no);
+        netapip_freeTransInfo(pTransInfo);
     }
     if (handle_sideband)
     {
-       retValue=nwal_delDMSecAssoc( ((NETAPI_GLOBAL_T*) (n->global))->nwal_context.nwalInstHandle,
+        retValue=nwal_delDMSecAssoc( ((NETAPI_GLOBAL_T*) (n->global))->nwal_context.nwalInstHandle,
                                     handle_sideband);
         if(retValue !=  nwal_OK)
         {
             *perr = NETAPI_ERR_NWAL_ERR0;
-             printf (">netapi_sec  - ERROR: nwal_delDMSA returned Error Code %d\n",
+             netapi_Log ("netapi_sec  - ERROR: nwal_delDMSA returned Error Code %d\n",
                     retValue);
 
         }
-        else printf(">netapi_sec: Sideband SA deleted\n");
-     }
+        else 
+            netapi_Log("netapi_sec: Sideband SA deleted\n");
+    }
    
-    //zap the entry
-    if (!flags) netcp_cfgp_delete_sa(&netapi_get_global()->nwal_context, tunnelId);
+    /* zap the entry */
+    if (!flags)
+        netapip_netcpCfgDeleteSa(&netapi_get_global()->nwal_context, tunnelId);
 }
-//external version
-void netapi_secDelSA(NETAPI_T h,int iface_no, NETCP_CFG_SA_T  sa_app_id,  int *perr)
+
+/********************************************************************
+ * FUNCTION PURPOSE:  API to delete an IPSEC SA
+ ********************************************************************
+ * DESCRIPTION:  API to delete an IPSEC SA
+ ********************************************************************/
+void netapi_secDelSA(NETAPI_T h,
+                     int iface_no,
+                     NETCP_CFG_SA_T sa_app_id,
+                     int *perr)
 {
-netapi_secDelSA_internal( h, iface_no,  sa_app_id, 0x00, perr);
+    netapi_secDelSA_internal( h, iface_no,  sa_app_id, 0x00, perr);
 }
 
 
-//******************************************
-// Add Policy
-//******************************************
-NETCP_CFG_IPSEC_POLICY_T netapi_secAddRxPolicy(NETAPI_T h, //the  netapi handle
-                                NETCP_CFG_SA_T sa,  //tunnel to attach to
-                               nwal_IpType ipType,     //V4 or V6
-                               nwalIpAddr_t  * src_ip_addr,  //src (from where)
-                               nwalIpAddr_t  * dst_ip_addr,  //dst (us)
-                               nwalIpOpt_t * ip_qualifiers,  //other qualifiers
-                                NETCP_CFG_ROUTE_HANDLE_T  route,  //Optional route
-                                int * perr)
-{
-NETAPI_HANDLE_T * n = (NETAPI_HANDLE_T *) h;
-nwal_RetValue       retValue;
-NetapiNwalTransInfo_t *pTransInfo;
-nwal_TransID_t     trans_id;
-unsigned int appId = NETAPI_NETCP_MATCH_IPSEC_POLICY | (sa&0xff);
-int policyId;
-int tunnelId= (sa>>8)&0xff;
-void * blah;
-int iface_no = sa&0xff;
-nwalSecPolParams_t createParam =
+/********************************************************************
+ * FUNCTION PURPOSE:  API to add a receive security policy
+ ********************************************************************
+ * DESCRIPTION:  API to add a receive security policy
+ ********************************************************************/
+NETCP_CFG_IPSEC_POLICY_T netapi_secAddRxPolicy(NETAPI_T h, 
+                                               NETCP_CFG_SA_T sa,
+                                               nwal_IpType ipType,
+                                               nwalIpAddr_t * src_ip_addr,
+                                               nwalIpAddr_t * dst_ip_addr,
+                                               nwalIpOpt_t * ip_qualifiers,
+                                               NETCP_CFG_ROUTE_HANDLE_T  route,
+                                               void * user_data,
+                                               int * perr)
 {
+    NETAPI_HANDLE_T * n = (NETAPI_HANDLE_T *) h;
+    nwal_RetValue       retValue;
+    NetapiNwalTransInfo_t *pTransInfo;
+    nwal_TransID_t     trans_id;
+    unsigned int appId = NETAPI_NETCP_MATCH_IPSEC_POLICY;
+    int policyId;
+    int tunnelId= netapi_cfgGetMatchId(sa);
+    void * blah;
+    int iface_no = netapi_cfgGetMatchLogicalMacIface(sa);
+
+    nwalSecPolParams_t createParam =
+    {
         0,  /* handle */
+        0,  /* valid params */
         NWAL_SA_DIR_INBOUND,
         4,      /* IP Type */
         {0},  /* dst */
@@ -344,19 +484,38 @@ nwalSecPolParams_t createParam =
         NWAL_MATCH_ACTION_CONTINUE_NEXT_ROUTE,       /* Continue parsing to next route for match */
         NWAL_NEXT_ROUTE_FAIL_ACTION_HOST,            /* For next route fail action by default is route to host */
         CPPI_PARAM_NOT_SPECIFIED,                    /* Use default flow configured to NWAL  if packet is routed to host */
-        QMSS_PARAM_NOT_SPECIFIED                     /* Use default queue configured to NWAL if packet is routed to host */
-};
-void * sa_handle = NULL;
+        QMSS_PARAM_NOT_SPECIFIED,                    /* Use default queue configured to NWAL if packet is routed to host */
+        0                                            /* Optional: route type */
+    };
 
+    void * sa_handle = NULL;
     *perr =0;
-    if ((!n) ) {*perr = NETAPI_ERR_BAD_INPUT; return -1;}
+    
+    if ((!n) )
+    {
+        *perr = NETAPI_ERR_BAD_INPUT;
+        return -1;
+    }
 
-    sa_handle = netcp_cfgp_get_sa_handles(&netapi_get_global()->nwal_context,tunnelId,&blah);
-    if (!sa_handle) {*perr = NETAPI_ERR_BAD_INPUT; return -1;}
+    sa_handle = netapip_netcpCfgGetSaHandles(&netapi_get_global()->nwal_context,tunnelId,&blah);
+    if (!sa_handle)
+    {
+        *perr = NETAPI_ERR_BAD_INPUT;
+        return -1;
+    }
 
-    pTransInfo = netapip_GetFreeTransInfo((NETAPI_GLOBAL_T *) n->global, &trans_id);
-    if (!pTransInfo) { *perr =  NETAPI_ERR_BUSY; return -1;}
+    /* get a transaction id */
+    pTransInfo = netapip_getFreeTransInfo(n,
+                                          (NETAPI_PROC_GLOBAL_T *) n->proc_global,
+                                          &trans_id);
+    if (!pTransInfo)
+    {
+        *perr =  NETAPI_ERR_BUSY;
+        return -1;
+    }
     pTransInfo->transType = NETAPI_NWAL_HANDLE_TRANS_SA_POLICY;
+    pTransInfo->state = NETAPI_NWAL_HANDLE_STATE_OPEN_PENDING;
+    pTransInfo->inUse = nwal_TRUE;
     pTransInfo->netapi_handle = h;
     createParam.handle = sa_handle;
     createParam.ipType = ipType;
@@ -365,18 +524,30 @@ void * sa_handle = NULL;
     if (ip_qualifiers) memcpy(&createParam.ipOpt,ip_qualifiers ,sizeof(nwalIpOpt_t));
     if (route != NULL)
     {
-        netcp_cfgp_build_route(route,&createParam.appRxPktFlowId,
-                                     &createParam.appRxPktQueue);
+        if((route->valid_params & NETCP_CFG_VALID_PARAM_ROUTE_TYPE) ==
+            NETCP_CFG_VALID_PARAM_ROUTE_TYPE)
+        {
+           createParam.validParams |= 
+                    NWAL_SET_SEC_POLICY_VALID_PARAM_ROUTE_TYPE;
+        }
+        netapip_netcpCfgBuildRoute(route,
+                                   &createParam.appRxPktFlowId,
+                                   &createParam.appRxPktQueue,
+                                   &createParam.routeType);
     }
-    //reserve a slot
-    policyId = netcp_cfgp_find_policy_slot(&netapi_get_global()->nwal_context,
-                           tunnelId);
-    if (policyId <0) {*perr= NETAPI_ERR_NOMEM;  return -1; }
-    appId |=  (policyId<<8);
-
-    //fire off config message
-    pTransInfo->state == NETAPI_NWAL_HANDLE_STATE_OPEN_PENDING;
+    /* reserve a slot */
+    policyId = netapip_netcpCfgFindPolicySlot(n,
+                                              &netapi_get_global()->nwal_context,
+                                              tunnelId);
+    if (policyId <0) 
+    {
+        *perr= NETAPI_ERR_NOMEM;
+        netapip_freeTransInfo(pTransInfo);
+        return -1;
+    }
+    appId |=  (policyId <<8);
 
+    /* fire off config message */
     retValue = nwal_setSecPolicy (((NETAPI_GLOBAL_T*) (n->global))->nwal_context.nwalInstHandle,
                                   trans_id,
                                   (nwal_AppId) appId,
@@ -385,63 +556,85 @@ void * sa_handle = NULL;
     if(retValue !=  nwal_OK)
     {
         *perr = NETAPI_ERR_NWAL_ERR0;
-        printf (">netapi sec - ERROR: nwal_setPolicy returned Error Code %d\n",
+        printf("netapi_secAddPolicy: error returned: %d\n", retValue);
+        netapi_Log ("netapi sec - ERROR: nwal_setPolicy returned Error Code %d\n",
                     retValue);
-        pTransInfo->inUse = nwal_FALSE;
-        netcp_cfgp_delete_policy(&netapi_get_global()->nwal_context,policyId);
+        netapip_freeTransInfo(pTransInfo);
+        
+        netapip_netcpCfgDeletePolicy(&netapi_get_global()->nwal_context,policyId);
         return -1;
     }
-    //pTransInfo->inUse = nwal_FALSE;
 
-    //wait here until its done since scheduler isn't running yet most likely..
-    // todo:  make this handled by scheduler poll later ??
     if(trans_id != NWAL_TRANSID_SPIN_WAIT)
     {
         n->nwal_local.numPendingCfg++;
-        while ((volatile) n->nwal_local.numPendingCfg)
+        while ((pTransInfo->state  !=NETAPI_NWAL_HANDLE_STATE_ERR) &&
+                (pTransInfo->state !=NETAPI_NWAL_HANDLE_STATE_OPEN))
         {
-            // if response is there, then this poll squirts out in the CTl poll callback, 
-            // which handles the rest (including decrmenting #pending!!
             nwal_pollCtl(((NETAPI_GLOBAL_T*) (n->global))->nwal_context.nwalInstHandle,NULL,NULL);
         }
+        if (pTransInfo->state == NETAPI_NWAL_HANDLE_STATE_ERR)
+        {
+            netapip_freeTransInfo(pTransInfo);
+            *perr = NETAPI_ERR_PA_FW;
+            netapi_Log ("netapi_sec - ERROR2: netapi_secAddRxPolicy returned Error Code %d\n",
+                    *perr);
+            netapip_netcpCfgDeletePolicy(&netapi_get_global()->nwal_context,policyId);
+            return -1;
+        }
     }
-    printf (">netapi sec: SA %d added to tunnel %d  mac %d\n", policyId, tunnelId, iface_no);
-
-    //todo: the sideband i/f
+    netapi_Log ("netapi sec: SA %d added to tunnel %d  mac %d\n", policyId, tunnelId, iface_no);
 
-    //save stuff
-    netcp_cfgp_insert_policy(&netapi_get_global()->nwal_context,
+    /* save stuff */
+    netapip_netcpCfgInsertPolicy(&netapi_get_global()->nwal_context,
                            policyId,
-                          (void *) pTransInfo->handle);
-    pTransInfo->state =  NETAPI_NWAL_HANDLE_STATE_IDLE;
-    pTransInfo->inUse = nwal_FALSE;
+                          (void *) pTransInfo->handle,
+                          user_data);
+    netapip_freeTransInfo(pTransInfo);
     return  (appId);
 }
 
-//************************
-//Delete Policy  (internal)
-//***********************
-static void netapi_secDelRxPolicy_internal(NETAPI_T h, NETCP_CFG_IPSEC_POLICY_T policy_app_id, int flags, int *perr)
+/********************************************************************
+ * FUNCTION PURPOSE:  Internal function to delete a receive security policy
+ ********************************************************************
+ * DESCRIPTION:  Internal function to delete a receive security policy
+ ********************************************************************/
+static void netapi_secDelRxPolicy_internal(NETAPI_T h,
+                                           NETCP_CFG_IPSEC_POLICY_T policy_app_id,
+                                           int flags,
+                                           int *perr)
 {
-NETAPI_HANDLE_T * n = (NETAPI_HANDLE_T *) h;
-nwal_RetValue       retValue;
-NetapiNwalTransInfo_t *pTransInfo;
-nwal_TransID_t     trans_id;
-int policyId = (policy_app_id >>8) &0xffff;
-void * handle_policy=NULL;
-
-    handle_policy = netcp_cfgp_get_policy(&netapi_get_global()->nwal_context,policyId);
+    NETAPI_HANDLE_T * n = (NETAPI_HANDLE_T *) h;
+    nwal_RetValue       retValue;
+    NetapiNwalTransInfo_t *pTransInfo;
+    nwal_TransID_t     trans_id;
+    int policyId = netapi_cfgGetMatchId(policy_app_id);
+    void * handle_policy=NULL;
+
+    handle_policy = netapip_netcpCfgGetPolicy(&netapi_get_global()->nwal_context,policyId);
                                           ;
-    if (!handle_policy) {*perr = NETAPI_ERR_BAD_INPUT; return ;}
+    if (!handle_policy)
+    {
+        *perr = NETAPI_ERR_BAD_INPUT;
+        goto ERR_netapi_secDelRxPolicy_internal;
+     }
     *perr =0;
 
-    //get a transaction id
-    pTransInfo = netapip_GetFreeTransInfo((NETAPI_GLOBAL_T *) n->global, &trans_id);
-    if (!pTransInfo) { *perr =  NETAPI_ERR_BUSY; return ;}
+    /* get a transaction id */
+    pTransInfo = netapip_getFreeTransInfo(n,
+                                         (NETAPI_PROC_GLOBAL_T *) n->proc_global,
+                                         &trans_id);
+    if (!pTransInfo)
+    {
+        *perr =  NETAPI_ERR_BUSY;
+        goto ERR_netapi_secDelRxPolicy_internal;
+    }
     pTransInfo->transType = NETAPI_NWAL_HANDLE_TRANS_SA_POLICY;
+    pTransInfo->state = NETAPI_NWAL_HANDLE_STATE_CLOSE_PENDING;
+    pTransInfo->inUse = nwal_TRUE;
     pTransInfo->netapi_handle = h;
 
-    //issue request
+    /* issue request */
     retValue = nwal_delSecPolicy(
                 ((NETAPI_GLOBAL_T*) (n->global))->nwal_context.nwalInstHandle,
                 trans_id,
@@ -449,38 +642,147 @@ void * handle_policy=NULL;
     if(retValue !=  nwal_OK)
     {
         *perr = NETAPI_ERR_NWAL_ERR0;
-        printf (">netsec  - ERROR: nwal_delSAPolicy returned Error Code %d\n",
+        netapi_Log ("netapi sec - ERROR: netapi_secDelRxPolicy_internal returned Error Code %d\n",
                     retValue);
-        pTransInfo->inUse = nwal_FALSE;
-        return ;
+        netapip_freeTransInfo(pTransInfo);
+        goto ERR_netapi_secDelRxPolicy_internal;
     }
-    //wait here until its done since scheduler isn't running yet most likely..
-    // todo:  make this handled by scheduler poll later ??
+
     if(trans_id != NWAL_TRANSID_SPIN_WAIT)
     {
         n->nwal_local.numPendingCfg++;
-        while ((volatile) n->nwal_local.numPendingCfg)
+        while ((pTransInfo->state  !=NETAPI_NWAL_HANDLE_STATE_ERR) &&
+                    (pTransInfo->state !=NETAPI_NWAL_HANDLE_STATE_IDLE))
         {
-        // if response is there, then this poll squirts out in the CTl poll callback, 
-            // which handles the rest (including decrmenting #pending!!
             nwal_pollCtl(((NETAPI_GLOBAL_T*) (n->global))->nwal_context.nwalInstHandle,NULL,NULL);
         }
+        if (pTransInfo->state == NETAPI_NWAL_HANDLE_STATE_ERR)
+        {
+            netapip_freeTransInfo(pTransInfo);
+            *perr = NETAPI_ERR_PA_FW;
+            netapi_Log ("netapi_sec - ERROR2: netapi_secDelRxPolicy_internal returned Error Code %d\n",
+                    *perr);
+            //zap the entry
+            if (!flags)
+                netapip_netcpCfgDeletePolicy(&netapi_get_global()->nwal_context, policyId);
+            goto ERR_netapi_secDelRxPolicy_internal;
+            
+        }
+    }
+    netapi_Log ("netapi sec: policy %d (iface %d) deleted\n",policyId,(policy_app_id&0xff));
+    netapip_freeTransInfo(pTransInfo);
+    /* zap the entry */
+    if (!flags)
+    {
+        netapip_netcpCfgDeletePolicy(&netapi_get_global()->nwal_context, policyId);
     }
-    printf (">netapi sec: policy %d (iface %d) deleted\n",policyId,(policy_app_id&0xff));
-    pTransInfo->state =  NETAPI_NWAL_HANDLE_STATE_IDLE;
-    pTransInfo->inUse = nwal_FALSE;
-    //zap the entry
-    if (!flags) netcp_cfgp_delete_policy(&netapi_get_global()->nwal_context, policyId);
+ERR_netapi_secDelRxPolicy_internal:
+    return;
+}
+
+/********************************************************************
+ * FUNCTION PURPOSE:  API to delete a receive security policy
+ ********************************************************************
+ * DESCRIPTION:  API to delete a receive security policy
+ ********************************************************************/
+void netapi_secDelRxPolicy(NETAPI_T h,
+                           NETCP_CFG_IPSEC_POLICY_T policy_app_id,
+                           int *perr)
+{
+    netapi_secDelRxPolicy_internal(h,  policy_app_id, 0, perr);
 }
 
-//************************
-//Delete Policy  
-//***********************
-void netapi_secDelRxPolicy(NETAPI_T h, NETCP_CFG_IPSEC_POLICY_T policy_app_id, int *perr)
+/********************************************************************
+ * FUNCTION PURPOSE:  API to retrieve SA statistics via NWAL
+ ********************************************************************
+ * DESCRIPTION:  API to retrieve SA statistics via NWAL
+ ********************************************************************/
+void  netapi_getSaStats (NETAPI_T               h, 
+                         NETCP_CFG_SA_T         handle,
+                         NETAPI_SA_STATS_T*     pSaStats)
 {
-netapi_secDelRxPolicy_internal(h,  policy_app_id, 0, perr);
+    NETAPI_HANDLE_T * n = (NETAPI_HANDLE_T *) h;
+    void * handle_inflow;
+    void * handle_sideband;
+    int tunnelId = (handle >> NETAPI_NETCP_MATCH_ID_SHIFT) &0xffff;
+    int have_to_wait = 1;
+    handle_inflow = netapip_netcpCfgGetSaHandles(&netapi_get_global()->nwal_context,
+                                          tunnelId, &handle_sideband);
+    if(handle_inflow)
+    {
+        nwal_getSecAssocStats(((NETAPI_GLOBAL_T*) (n->global))->nwal_context.nwalInstHandle, 
+                                                handle_inflow, &(pSaStats->saIpsecStats));
+        pSaStats->validParams |= NETAPI_IPSEC_STAT_VALID;
+    }
+    if(handle_sideband)
+    {
+        nwal_getDataModeStats(((NETAPI_GLOBAL_T*) (n->global))->nwal_context.nwalInstHandle, 
+                                                handle_sideband, &(pSaStats->dataModeStats));
+        pSaStats->validParams |= NETAPI_SIDEBAND_DATA_MODE_STAT_VALID;
+    }
 }
 
 
+/**********************************************************************************
+ * FUNCTION PURPOSE:  API to  API to retrieve local channel context information
+ **********************************************************************************
+ * DESCRIPTION:  API to retrieve API to retrieve local channel context information
+ *********************************************************************************/
+void netapi_secGetChanCtxInfo(NETAPI_T h,
+                           NETCP_CFG_APP_ID_T appId,
+                           nwalChanCxtInfo_t* pInfo)
+{
+
+    NETAPI_HANDLE_T * n = (NETAPI_HANDLE_T *) h;
+    void * handle_inflow;
+    void * handle_sideband = NULL;
+    void * handle_policy=NULL;
+    nwalChanCxtInfo_t info;
+    uint32_t stage = 0;
+    int policyId;
+    int tunnelId;
+
+    if(!pInfo)
+        return;
+    memset(pInfo, 0, sizeof(nwalChanCxtInfo_t));
+
+    stage = netapi_cfgGetMatchStage(appId);
+    netapi_Log("netapi_secGetChanCtxInfo: app id: 0x%x, stage: 0x%x\n", appId, stage);
 
 
+    switch (stage)
+    {
+        case 1:
+            /* this is for SA, need SA and OUTER IP handle */
+            tunnelId = netapi_cfgGetMatchId(appId);
+            handle_inflow = netapip_netcpCfgGetSaHandles(&netapi_get_global()->nwal_context,
+                                          tunnelId, &handle_sideband);
+            if(handle_inflow)
+            {
+                nwal_getChanCxtInfo(&netapi_get_global()->nwal_context,
+                            handle_inflow,
+                            pInfo);
+                netapi_Log("netapi_secGetChanCtxInfo: outerIP: 0x%x, SA chan handle: 0x%x, bitmap: 0x%x\n",
+                    pInfo->paOuterIpHandle, pInfo->saChanHandle, pInfo->validBitMap);
+            }
+            break;
+        case 2:
+            /* this is for policy, need SA inner IP */
+            policyId = netapi_cfgGetMatchId(appId);
+            handle_policy = netapip_netcpCfgGetPolicy(&netapi_get_global()->nwal_context,
+                                                          policyId);
+            if (handle_policy)
+            {
+                nwal_getChanCxtInfo(&netapi_get_global()->nwal_context,
+                            handle_policy,
+                            pInfo);
+                netapi_Log("netapi_secGetChanCtxInfo: innerIP: 0x%x, bitmap: 0x%x\n",
+                    pInfo->paInnerIpHandle, pInfo->validBitMap);
+            }
+            break;
+        default:
+            netapi_Log("netapi_secGetChanCtxInfo:Invalid APPID provided\n");
+            break;
+    }
+    return;
+}