| /* |
| * 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 */ |