blob: 2f21001e710872f82f53353ba66a17f848457949 [file] [log] [blame]
/*
* Copyright (c) 2009 Mindspeed Technologies, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "module_ipsec.h"
#include "module_tunnel.h"
#include "fe.h"
/* This function returns total SA entries configured with a given handle */
static int IPsec_Get_Hash_SAEntries(int sa_handle_index)
{
int tot_sa_entries = 0;
PSAEntry pSAEntry;
struct slist_entry *entry;
slist_for_each(pSAEntry, entry, &sa_cache_by_h[sa_handle_index], list_h)
{
tot_sa_entries++;
}
return tot_sa_entries;
}
/* This function fills the snapshot of SA entries in a given handle hash index */
static int IPsec_SA_Get_Handle_Snapshot(int sa_handle_index, int sa_entries, PSAQueryCommand pSAHandleSnapshot)
{
int tot_sa_entries=0;
PSAEntry pSAEntry;
struct slist_entry *entry;
slist_for_each(pSAEntry, entry, &sa_cache_by_h[sa_handle_index], list_h)
{
pSAHandleSnapshot->src_ip[0] = pSAEntry->id.saddr[0];
pSAHandleSnapshot->src_ip[1] = pSAEntry->id.saddr[1];
pSAHandleSnapshot->src_ip[2] = pSAEntry->id.saddr[2];
pSAHandleSnapshot->src_ip[3] = pSAEntry->id.saddr[3];
pSAHandleSnapshot->dst_ip[0] = pSAEntry->id.daddr.a6[0];
pSAHandleSnapshot->dst_ip[1] = pSAEntry->id.daddr.a6[1];
pSAHandleSnapshot->dst_ip[2] = pSAEntry->id.daddr.a6[2];
pSAHandleSnapshot->dst_ip[3] = pSAEntry->id.daddr.a6[3];
pSAHandleSnapshot->spi = pSAEntry->id.spi;
pSAHandleSnapshot->sa_type = pSAEntry->id.proto;
pSAHandleSnapshot->family = pSAEntry->family;
pSAHandleSnapshot->handle = pSAEntry->handle;
pSAHandleSnapshot->mtu = pSAEntry->mtu;
pSAHandleSnapshot->state = pSAEntry->state;
if (pSAEntry->elp_sa)
{
pSAHandleSnapshot->flags = pSAEntry->elp_sa->flags;
if (pSAEntry->elp_sa->flags & ESPAH_ANTI_REPLAY_ENABLE)
pSAHandleSnapshot->replay_window = 0x1;
else
pSAHandleSnapshot->replay_window = 0x0;
pSAHandleSnapshot->key_alg = pSAEntry->elp_sa->algo;
if (pSAEntry->elp_sa->algo & 0x7)
{
#if defined(COMCERTO_1000) || defined(COMCERTO_2000)
*((U32*)&pSAHandleSnapshot->auth_key[0]) = htonl(*(U32*)&pSAEntry->elp_sa->auth_key0);
*((U32*)&pSAHandleSnapshot->auth_key[4]) = htonl(*(U32*)&pSAEntry->elp_sa->auth_key1);
*((U32*)&pSAHandleSnapshot->auth_key[8]) = htonl(*(U32*)&pSAEntry->elp_sa->auth_key2);
*((U32*)&pSAHandleSnapshot->auth_key[12]) = htonl(*(U32*)&pSAEntry->elp_sa->auth_key3);
*((U32*)&pSAHandleSnapshot->auth_key[16]) = htonl(*(U32*)&pSAEntry->elp_sa->auth_key4);
*((U32*)&pSAHandleSnapshot->ext_auth_key[0]) = htonl(*(U32*)&pSAEntry->elp_sa->ext_auth_key0);
*((U32*)&pSAHandleSnapshot->ext_auth_key[4]) = htonl(*(U32*)&pSAEntry->elp_sa->ext_auth_key1);
*((U32*)&pSAHandleSnapshot->ext_auth_key[8]) = htonl(*(U32*)&pSAEntry->elp_sa->ext_auth_key2);
#else
int i;
for (i =0; i < 5; i++)
*((U32*)&pSAHandleSnapshot->auth_key[i*4]) = htonl(*(U32*)&pSAEntry->elp_sa->auth_key[i*4]);
for (i =0; i < 3; i++)
*((U32*)&pSAHandleSnapshot->ext_auth_key[i*4]) = htonl(*(U32*)&pSAEntry->elp_sa->ext_auth_key[i*4]);
#endif
}
if ((pSAEntry->elp_sa->algo >> 3) & 0x1F)
{
#if defined(COMCERTO_1000) || defined(COMCERTO_2000)
*((U32*)&pSAHandleSnapshot->cipher_key[0]) = htonl(*(U32*)&pSAEntry->elp_sa->cipher0);
*((U32*)&pSAHandleSnapshot->cipher_key[4]) = htonl(*(U32*)&pSAEntry->elp_sa->cipher1);
*((U32*)&pSAHandleSnapshot->cipher_key[8]) = htonl(*(U32*)&pSAEntry->elp_sa->cipher2);
*((U32*)&pSAHandleSnapshot->cipher_key[12]) = htonl(*(U32*)&pSAEntry->elp_sa->cipher3);
*((U32*)&pSAHandleSnapshot->cipher_key[16]) = htonl(*(U32*)&pSAEntry->elp_sa->cipher4);
*((U32*)&pSAHandleSnapshot->cipher_key[20]) = htonl(*(U32*)&pSAEntry->elp_sa->cipher5);
*((U32*)&pSAHandleSnapshot->cipher_key[24]) = htonl(*(U32*)&pSAEntry->elp_sa->cipher6);
*((U32*)&pSAHandleSnapshot->cipher_key[28]) = htonl(*(U32*)&pSAEntry->elp_sa->cipher7);
#else
int i;
for (i =0; i < 7; i++)
*((U32*)&pSAHandleSnapshot->cipher_key[i*4]) = htonl(*(U32*)&pSAEntry->elp_sa->cipher_key[i*4]);
#endif
}
}
if (pSAEntry->mode == SA_MODE_TUNNEL)
{
pSAHandleSnapshot->mode = SA_MODE_TUNNEL;
if (pSAEntry->header_len == IPV4_HDR_SIZE)
{
pSAHandleSnapshot->tunnel_proto_family = PROTO_FAMILY_IPV4;
pSAHandleSnapshot->tnl.ipv4.DestinationAddress = pSAEntry->tunnel.ip4.DestinationAddress;
pSAHandleSnapshot->tnl.ipv4.SourceAddress = pSAEntry->tunnel.ip4.SourceAddress;
pSAHandleSnapshot->tnl.ipv4.TypeOfService = pSAEntry->tunnel.ip4.TypeOfService;
pSAHandleSnapshot->tnl.ipv4.Protocol = pSAEntry->tunnel.ip4.Protocol;
pSAHandleSnapshot->tnl.ipv4.TotalLength = pSAEntry->tunnel.ip4.TotalLength;
}
else
{
pSAHandleSnapshot->tunnel_proto_family = PROTO_FAMILY_IPV6;
pSAHandleSnapshot->tnl.ipv6.DestinationAddress[0] = pSAEntry->tunnel.ip6.DestinationAddress[0];
pSAHandleSnapshot->tnl.ipv6.DestinationAddress[1] = pSAEntry->tunnel.ip6.DestinationAddress[1];
pSAHandleSnapshot->tnl.ipv6.DestinationAddress[2] = pSAEntry->tunnel.ip6.DestinationAddress[2];
pSAHandleSnapshot->tnl.ipv6.DestinationAddress[3] = pSAEntry->tunnel.ip6.DestinationAddress[3];
pSAHandleSnapshot->tnl.ipv6.SourceAddress[0] = pSAEntry->tunnel.ip6.SourceAddress[0];
pSAHandleSnapshot->tnl.ipv6.SourceAddress[1] = pSAEntry->tunnel.ip6.SourceAddress[1];
pSAHandleSnapshot->tnl.ipv6.SourceAddress[2] = pSAEntry->tunnel.ip6.SourceAddress[2];
pSAHandleSnapshot->tnl.ipv6.SourceAddress[3] = pSAEntry->tunnel.ip6.SourceAddress[3];
IPV6_SET_TRAFFIC_CLASS(&pSAHandleSnapshot->tnl.ipv6, IPV6_GET_TRAFFIC_CLASS(&pSAEntry->tunnel.ip6));
IPV6_SET_VERSION(&pSAHandleSnapshot->tnl.ipv6, IPV6_GET_VERSION(&pSAEntry->tunnel.ip6));
IPV6_COPY_FLOW_LABEL(&pSAHandleSnapshot->tnl.ipv6, &pSAEntry->tunnel.ip6);
}
}
pSAHandleSnapshot->soft_byte_limit = pSAEntry->lft_conf.soft_byte_limit;
pSAHandleSnapshot->hard_byte_limit = pSAEntry->lft_conf.hard_byte_limit;
pSAHandleSnapshot->soft_packet_limit = pSAEntry->lft_conf.soft_packet_limit;
pSAHandleSnapshot->hard_packet_limit = pSAEntry->lft_conf.hard_packet_limit;
pSAHandleSnapshot++;
tot_sa_entries++;
if(--sa_entries <= 0)
break;
}
return tot_sa_entries;
}
/* This function creates the snapshot memory for SAs and returns the
next SA entry from the snapshot of the SA entries of a
single handle to the caller */
int IPsec_Get_Next_SAEntry(PSAQueryCommand pSAQueryCmd, int reset_action)
{
int ipsec_sa_hash_entries;
PSAQueryCommand pSACmd;
static PSAQueryCommand pSASnapshot = NULL;
static int sa_hash_index = 0, sa_snapshot_entries =0, sa_snapshot_index=0 , sa_snapshot_buf_entries = 0;
if(reset_action)
{
sa_hash_index = 0;
sa_snapshot_entries =0;
sa_snapshot_index=0;
if(pSASnapshot)
{
Heap_Free(pSASnapshot);
pSASnapshot = NULL;
}
sa_snapshot_buf_entries = 0;
}
if (sa_snapshot_index == 0)
{
while( sa_hash_index < NUM_SA_ENTRIES)
{
ipsec_sa_hash_entries = IPsec_Get_Hash_SAEntries(sa_hash_index);
if(ipsec_sa_hash_entries == 0)
{
sa_hash_index++;
continue;
}
if(ipsec_sa_hash_entries > sa_snapshot_buf_entries)
{
if(pSASnapshot)
Heap_Free(pSASnapshot);
pSASnapshot = Heap_Alloc(ipsec_sa_hash_entries * sizeof(SAQueryCommand));
if (!pSASnapshot)
{
sa_hash_index = 0;
sa_snapshot_buf_entries = 0;
return ERR_NOT_ENOUGH_MEMORY;
}
sa_snapshot_buf_entries = ipsec_sa_hash_entries;
}
sa_snapshot_entries = IPsec_SA_Get_Handle_Snapshot(sa_hash_index , ipsec_sa_hash_entries,pSASnapshot);
break;
}
if (sa_hash_index >= NUM_SA_ENTRIES)
{
sa_hash_index = 0;
if (pSASnapshot)
{
Heap_Free(pSASnapshot);
pSASnapshot = NULL;
}
sa_snapshot_buf_entries = 0;
return ERR_SA_ENTRY_NOT_FOUND;
}
}
pSACmd = &pSASnapshot[sa_snapshot_index++];
SFL_memcpy(pSAQueryCmd, pSACmd, sizeof(SAQueryCommand));
if (sa_snapshot_index == sa_snapshot_entries)
{
sa_snapshot_index = 0;
sa_hash_index ++;
}
return NO_ERR;
}
#ifdef CFG_STATS
/* This function fills the snapshot of SA entries
in a given hash index, statReset = 1 resets the stats of SA. */
static int stat_Get_SA_Hash_Snapshot(int sa_hash_index, int sa_entries,
PStatIpsecEntryResponse pStatSASnapshot)
{
int tot_sa_entries=0;
PSAEntry pSAEntry;
struct slist_entry *entry;
u32 last_bytes, last_bytes_up32;
slist_for_each(pSAEntry, entry, &sa_cache_by_h[sa_hash_index], list_h)
{
pStatSASnapshot->spi = ntohl(pSAEntry->id.spi);
pStatSASnapshot->proto = pSAEntry->id.proto;
pStatSASnapshot->family = pSAEntry->family;
pStatSASnapshot->dstIP[0] = pSAEntry->id.daddr.a6[0];
pStatSASnapshot->dstIP[1] = pSAEntry->id.daddr.a6[1];
pStatSASnapshot->dstIP[2] = pSAEntry->id.daddr.a6[2];
pStatSASnapshot->dstIP[3] = pSAEntry->id.daddr.a6[3];
#if defined(COMCERTO_2000)
pStatSASnapshot->total_pkts_processed =
be32_to_cpu(pSAEntry->hw_sa->stats.last_pkts_processed);
last_bytes = pSAEntry->hw_sa->stats.last_bytes_processed & 0xffffffff;
last_bytes_up32= (pSAEntry->hw_sa->stats.last_bytes_processed >> 32)& 0xffffffff;
pStatSASnapshot->total_bytes_processed[0] = be32_to_cpu(last_bytes_up32);
pStatSASnapshot->total_bytes_processed[1] = be32_to_cpu(last_bytes);
#else
pStatSASnapshot->total_pkts_processed =
pSAEntry->total_pkts_processed;
pStatSASnapshot->total_bytes_processed[0] =
pSAEntry->total_bytes_processed & 0xffffffff;
pStatSASnapshot->total_bytes_processed[1] =
(pSAEntry->total_bytes_processed >> 32) & 0xffffffff;
#endif
pStatSASnapshot->eof = 0;
#if !defined(COMCERTO_2000)
if(gStatIpsecQueryStatus & STAT_IPSEC_QUERY_RESET)
{
pSAEntry->total_pkts_processed = pSAEntry->total_bytes_processed = 0;
}
#endif
pStatSASnapshot->sagd = pSAEntry->handle;
pStatSASnapshot++;
tot_sa_entries++;
if(--sa_entries <= 0)
break;
}
printk (KERN_ERR "total_sa_entries:%x\n", tot_sa_entries);
return tot_sa_entries;
}
/* This function creates the snapshot memory and returns the
next SA entry from the snapshop of the SA entries of a
single hash to the caller (statReset = 1 resets the stats) */
int stat_Get_Next_SAEntry(PStatIpsecEntryResponse pSACmd, int reset_action)
{
int stat_sa_hash_entries;
PStatIpsecEntryResponse pSA;
static PStatIpsecEntryResponse pStatSASnapshot = NULL;
static int stat_sa_hash_index = 0, stat_sa_snapshot_entries =0, stat_sa_snapshot_index=0, stat_sa_snapshot_buf_entries = 0;
if(reset_action)
{
stat_sa_hash_index = 0;
stat_sa_snapshot_entries =0;
stat_sa_snapshot_index=0;
if(pStatSASnapshot)
{
Heap_Free(pStatSASnapshot);
pStatSASnapshot = NULL;
}
stat_sa_snapshot_buf_entries = 0;
return NO_ERR;
}
if (stat_sa_snapshot_index == 0)
{
while( stat_sa_hash_index < NUM_SA_ENTRIES)
{
stat_sa_hash_entries = IPsec_Get_Hash_SAEntries(stat_sa_hash_index);
if(stat_sa_hash_entries == 0)
{
stat_sa_hash_index++;
continue;
}
if (stat_sa_hash_entries > stat_sa_snapshot_buf_entries)
{
if(pStatSASnapshot)
Heap_Free(pStatSASnapshot);
pStatSASnapshot = Heap_Alloc(stat_sa_hash_entries * sizeof(StatIpsecEntryResponse));
if (!pStatSASnapshot)
{
stat_sa_hash_index = 0;
stat_sa_snapshot_buf_entries = 0;
return ERR_NOT_ENOUGH_MEMORY;
}
stat_sa_snapshot_buf_entries = stat_sa_hash_entries;
}
stat_sa_snapshot_entries = stat_Get_SA_Hash_Snapshot(stat_sa_hash_index , stat_sa_hash_entries, pStatSASnapshot);
break;
}
if (stat_sa_hash_index >= NUM_SA_ENTRIES)
{
stat_sa_hash_index = 0;
if(pStatSASnapshot)
{
Heap_Free(pStatSASnapshot);
pStatSASnapshot = NULL;
}
stat_sa_snapshot_buf_entries = 0;
return ERR_SA_ENTRY_NOT_FOUND;
}
}
pSA = &pStatSASnapshot[stat_sa_snapshot_index++];
SFL_memcpy(pSACmd, pSA, sizeof(StatIpsecEntryResponse));
if (stat_sa_snapshot_index == stat_sa_snapshot_entries)
{
stat_sa_snapshot_index = 0;
stat_sa_hash_index ++;
}
return NO_ERR;
}
#endif /* CFG_STATS */