blob: 17c8d58905d3c12488bba4bfd281b7010880ef90 [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_mc4.h"
#include "module_mc6.h"
#include "layer2.h"
#include "fe.h"
/* This function returns total multicast entries
configured in a given hash index */
static int MC4_Get_Hash_Entries(int mc4_hash_index)
{
int tot_mc4_entries = 0;
PMC4Entry pMC4Entry;
struct slist_entry *entry;
slist_for_each(pMC4Entry, entry, &mc4_table_memory[mc4_hash_index], list)
{
tot_mc4_entries++;
if((pMC4Entry->mcdest.num_listeners > MCx_MAX_LISTENERS_IN_QUERY) ||
((pMC4Entry->mcdest.num_listeners == MCx_MAX_LISTENERS_IN_QUERY) && (pMC4Entry->mcdest.flags & MC_ACP_LISTENER)))
tot_mc4_entries++;
}
return tot_mc4_entries;
}
/* This function fills the snapshot of MC4 entries in a given hash index */
static int MC4_Get_Hash_Snapshot(int mc4_hash_index, int mc4_tot_entries, PMC4Command pMC4Snapshot)
{
int tot_mc4_entries = 0, i;
PMC4Entry pMC4Entry;
struct slist_entry *entry;
int j = 0;
slist_for_each(pMC4Entry, entry, &mc4_table_memory[mc4_hash_index], list)
{
memset(pMC4Snapshot, 0, sizeof(MC4Command));
pMC4Snapshot->src_addr = pMC4Entry->src_addr;
pMC4Snapshot->src_addr_mask = pMC4Entry->mcdest.src_mask_len;
pMC4Snapshot->dst_addr = pMC4Entry->dst_addr;
pMC4Snapshot->queue = pMC4Entry->mcdest.queue_base;
pMC4Snapshot->num_output = pMC4Entry->mcdest.num_listeners;
for(i = 0,j = 0; j <pMC4Entry->mcdest.num_listeners; j++)
{
unsigned short output_index;
POnifDesc pOnif;
output_index = pMC4Entry->mcdest.listeners[j].output_index;
pOnif = get_onif_by_index(output_index);
strcpy((char *)pMC4Snapshot->output_list[i].output_device_str, (char *)pOnif->name);
pMC4Snapshot->output_list[i].timer = pMC4Entry->mcdest.listeners[j].timer;
pMC4Snapshot->output_list[i].shaper_mask= pMC4Entry->mcdest.listeners[j].shaper_mask;
pMC4Snapshot->output_list[i].uc_bit = (pMC4Entry->mcdest.listeners[j].uc_bit);
if(pMC4Snapshot->output_list[i].uc_bit)
COPY_MACADDR(pMC4Snapshot->output_list[i].uc_mac,pMC4Entry->mcdest.listeners[j].dstmac);
pMC4Snapshot->output_list[i].queue = pMC4Entry->mcdest.listeners[j].queue_base;
if((++i >= MCx_MAX_LISTENERS_IN_QUERY) &&
( (pMC4Entry->mcdest.num_listeners - (j+1)) || (pMC4Entry->mcdest.flags & MC_ACP_LISTENER)))
{
pMC4Snapshot->num_output = MCx_MAX_LISTENERS_IN_QUERY;
pMC4Snapshot++;
tot_mc4_entries++;
mc4_tot_entries--;
i = 0;
memset(pMC4Snapshot, 0, sizeof(MC4Command));
}
}
pMC4Snapshot->num_output = i;
if ((pMC4Entry->mcdest.flags & MC_ACP_LISTENER) && i < MCx_MAX_LISTENERS_IN_QUERY)
{
pMC4Snapshot->num_output++;
strcpy((char *)pMC4Snapshot->output_list[i].output_device_str, "ACP");
pMC4Snapshot->output_list[i].timer = pMC4Entry->mcdest.wifi_listener_timer;
}
pMC4Snapshot++;
tot_mc4_entries++;
mc4_tot_entries--;
if (mc4_tot_entries == 0)
break;
}
return tot_mc4_entries;
}
/* This function creates the snapshot memory and returns the
next MC4 entry from the snapshot of the MC4 entries of a
single hash to the caller */
int MC4_Get_Next_Hash_Entry(PMC4Command pMC4Cmd, int reset_action)
{
int mc4_hash_entries;
PMC4Command pMC4;
static PMC4Command pMC4Snapshot = NULL;
static int mc4_hash_index = 0, mc4_snapshot_entries =0, mc4_snapshot_index=0, mc4_snapshot_buf_entries = 0;
if(reset_action)
{
mc4_hash_index = 0;
mc4_snapshot_entries =0;
mc4_snapshot_index=0;
if(pMC4Snapshot)
{
Heap_Free(pMC4Snapshot);
pMC4Snapshot = NULL;
}
mc4_snapshot_buf_entries = 0;
}
if (mc4_snapshot_index == 0)
{
while( mc4_hash_index < MC4_NUM_HASH_ENTRIES)
{
mc4_hash_entries = MC4_Get_Hash_Entries(mc4_hash_index);
if(mc4_hash_entries == 0)
{
mc4_hash_index++;
continue;
}
if(mc4_hash_entries > mc4_snapshot_buf_entries)
{
if(pMC4Snapshot)
Heap_Free(pMC4Snapshot);
pMC4Snapshot = Heap_Alloc(mc4_hash_entries * sizeof(MC4Command));
if (!pMC4Snapshot)
{
mc4_hash_index = 0;
mc4_snapshot_buf_entries = 0;
return ERR_NOT_ENOUGH_MEMORY;
}
mc4_snapshot_buf_entries = mc4_hash_entries;
}
mc4_snapshot_entries = MC4_Get_Hash_Snapshot(mc4_hash_index ,mc4_hash_entries, pMC4Snapshot);
break;
}
if (mc4_hash_index >= MC4_NUM_HASH_ENTRIES)
{
mc4_hash_index = 0;
if(pMC4Snapshot)
{
Heap_Free(pMC4Snapshot);
pMC4Snapshot = NULL;
}
mc4_snapshot_buf_entries = 0;
return ERR_MC_ENTRY_NOT_FOUND;
}
}
pMC4 = &pMC4Snapshot[mc4_snapshot_index++];
SFL_memcpy(pMC4Cmd, pMC4, sizeof(MC4Command));
if (mc4_snapshot_index == mc4_snapshot_entries)
{
mc4_snapshot_index = 0;
mc4_hash_index ++;
}
return NO_ERR;
}
/* This function returns total multicastv6 entries
configured in a given hash index */
static int MC6_Get_Hash_Entries(int mc6_hash_index)
{
int tot_mc6_entries = 0;
PMC6Entry pMC6Entry;
struct slist_entry *entry;
slist_for_each(pMC6Entry, entry, &mc6_table_memory[mc6_hash_index], list)
{
tot_mc6_entries++;
if((pMC6Entry->mcdest.num_listeners > MCx_MAX_LISTENERS_IN_QUERY) ||
((pMC6Entry->mcdest.num_listeners == MCx_MAX_LISTENERS_IN_QUERY) && (pMC6Entry->mcdest.flags & MC_ACP_LISTENER)))
tot_mc6_entries++;
}
return tot_mc6_entries;
}
/* This function fills the snapshot of MC6 entries in a given hash index */
static int MC6_Get_Hash_Snapshot(int mc6_hash_index, int mc6_tot_entries, PMC6Command pMC6Snapshot)
{
int tot_mc6_entries = 0,i;
PMC6Entry pMC6Entry;
struct slist_entry *entry;
int j =0;
slist_for_each(pMC6Entry, entry, &mc6_table_memory[mc6_hash_index], list)
{
memset(pMC6Snapshot, 0, sizeof(MC6Command));
SFL_memcpy(pMC6Snapshot->src_addr, pMC6Entry->src_addr, IPV6_ADDRESS_LENGTH);
pMC6Snapshot->src_mask_len = pMC6Entry->mcdest.src_mask_len;
SFL_memcpy(pMC6Snapshot->dst_addr, pMC6Entry->dst_addr, IPV6_ADDRESS_LENGTH);
pMC6Snapshot->queue = pMC6Entry->mcdest.queue_base;
for(i = 0,j = 0; j <pMC6Entry->mcdest.num_listeners; j++)
{
unsigned short output_index;
POnifDesc pOnif;
output_index = pMC6Entry->mcdest.listeners[j].output_index;
pOnif = get_onif_by_index(output_index);
strcpy((char *)pMC6Snapshot->output_list[i].output_device_str, (char *)pOnif->name);
pMC6Snapshot->output_list[i].timer = pMC6Entry->mcdest.listeners[j].timer;
pMC6Snapshot->output_list[i].shaper_mask= pMC6Entry->mcdest.listeners[j].shaper_mask;
pMC6Snapshot->output_list[i].uc_bit = pMC6Entry->mcdest.listeners[j].uc_bit;
if(pMC6Snapshot->output_list[i].uc_bit)
COPY_MACADDR(pMC6Snapshot->output_list[i].uc_mac,pMC6Entry->mcdest.listeners[j].dstmac);
pMC6Snapshot->output_list[i].queue = pMC6Entry->mcdest.listeners[j].queue_base;
if((++i >= MCx_MAX_LISTENERS_IN_QUERY) &&
( (pMC6Entry->mcdest.num_listeners - (j+1)) || (pMC6Entry->mcdest.flags & MC_ACP_LISTENER)))
{
pMC6Snapshot->num_output = MCx_MAX_LISTENERS_IN_QUERY;
pMC6Snapshot++;
tot_mc6_entries++;
mc6_tot_entries--;
i = 0;
memset(pMC6Snapshot, 0, sizeof(MC6Command));
}
}
pMC6Snapshot->num_output = i;
if ((pMC6Entry->mcdest.flags & MC_ACP_LISTENER) && i < MCx_MAX_LISTENERS_IN_QUERY)
{
pMC6Snapshot->num_output++;
strcpy((char *)pMC6Snapshot->output_list[i].output_device_str, "ACP");
pMC6Snapshot->output_list[i].timer = pMC6Entry->mcdest.wifi_listener_timer;
}
pMC6Snapshot++;
tot_mc6_entries++;
mc6_tot_entries--;
if (mc6_tot_entries == 0)
break;
}
return tot_mc6_entries;
}
/* This function creates the snapshot memory and returns the
next MC6 entry from the snapshot of the MC4 entries of a
single hash to the caller */
int MC6_Get_Next_Hash_Entry(PMC6Command pMC6Cmd, int reset_action)
{
int mc6_hash_entries;
PMC6Command pMC6;
static PMC6Command pMC6Snapshot = NULL;
static int mc6_hash_index = 0, mc6_snapshot_entries =0, mc6_snapshot_index=0, mc6_snapshot_buf_entries = 0;
if(reset_action)
{
mc6_hash_index = 0;
mc6_snapshot_entries =0;
mc6_snapshot_index=0;
if(pMC6Snapshot)
{
Heap_Free(pMC6Snapshot);
pMC6Snapshot = NULL;
}
mc6_snapshot_buf_entries = 0;
}
if (mc6_snapshot_index == 0)
{
while( mc6_hash_index < MC6_NUM_HASH_ENTRIES)
{
mc6_hash_entries = MC6_Get_Hash_Entries(mc6_hash_index);
if(mc6_hash_entries == 0)
{
mc6_hash_index++;
continue;
}
if(mc6_hash_entries > mc6_snapshot_buf_entries)
{
if(pMC6Snapshot)
Heap_Free(pMC6Snapshot);
pMC6Snapshot = Heap_Alloc(mc6_hash_entries * sizeof(MC6Command));
if (!pMC6Snapshot)
{
mc6_hash_index = 0;
mc6_snapshot_buf_entries = 0;
return ERR_NOT_ENOUGH_MEMORY;
}
mc6_snapshot_buf_entries = mc6_hash_entries;
}
mc6_snapshot_entries = MC6_Get_Hash_Snapshot(mc6_hash_index , mc6_hash_entries, pMC6Snapshot);
break;
}
if (mc6_hash_index >= MC6_NUM_HASH_ENTRIES)
{
mc6_hash_index = 0;
if(pMC6Snapshot)
{
Heap_Free(pMC6Snapshot);
pMC6Snapshot = NULL;
}
mc6_snapshot_buf_entries = 0;
return ERR_MC_ENTRY_NOT_FOUND;
}
}
pMC6 = &pMC6Snapshot[mc6_snapshot_index++];
SFL_memcpy(pMC6Cmd, pMC6, sizeof(MC6Command));
if (mc6_snapshot_index == mc6_snapshot_entries)
{
mc6_snapshot_index = 0;
mc6_hash_index ++;
}
return NO_ERR;
}