blob: 023951f9d7a0c8f8973828ebaed5f7963aff12b1 [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.
*
*
*/
#ifndef _MODULE_MC6_H_
#define _MODULE_MC6_H_
#include "types.h"
#include "modules.h"
#include "channels.h"
#include "multicast.h"
#include "fe.h"
#include "module_ipv6.h"
#define MC6_MAX_LISTENERS_PER_GROUP MCx_MAX_LISTENERS_PER_GROUP
#define MC6_NUM_HASH_ENTRIES 16
typedef struct tMC6_context {
unsigned char hoplimit_check_rule;
}MC6_context;
#if defined (COMCERTO_2000)
#if defined (COMCERTO_2000_CONTROL)
/** Control path MC6 HW entry */
typedef struct _thw_MC6Entry {
U32 flags;
U32 dma_addr;
U32 next;
U32 src_addr[4];
U32 dst_addr[4];
/* common portion */
MCxEntry mcdest;
U16 status;
U8 rtpqos_slot;
U8 padding; // structure size must be a multiple of 8 bytes for EFET transfers
/* These fields are only used by host software, so keep them at the end of the structure */
struct dlist_head list;
struct _tMC6Entry *sw_entry; /**< pointer to the software flow entry */
unsigned long removal_time;
}hw_MC6Entry, *Phw_MC6Entry;
/** Control path MC6 SW entry */
typedef struct _tMC6Entry {
struct slist_entry list;
U32 src_addr[4];
U32 dst_addr[4];
/* common portion */
MCxEntry mcdest;
U16 status;
U8 padding[2]; //structure size must be a multiple of 8 bytes for EFET transfers
hw_MC6Entry *hw_entry;
}MC6Entry, *PMC6Entry;
#else
/** Data path MC6 entry */
typedef struct _tMC6Entry {
U32 flags;
U32 dma_addr;
U32 next;
U32 src_addr[4];
U32 dst_addr[4];
/* common portion */
MCxEntry mcdest;
U16 status;
U8 rtpqos_slot;
U8 padding; //structure size must be a multiple of 8 bytes for EFET transfers
}MC6Entry, *PMC6Entry;
#endif
#else /* COMCERTO 1000 */
typedef struct _tMC6Entry {
struct slist_entry list;
U32 src_addr[4];
U32 dst_addr[4];
/* common portion */
MCxEntry mcdest;
U16 status;
U8 rtpqos_slot;
U8 padding; //structure size must be a multiple of 8 bytes for EFET transfers
}MC6Entry, *PMC6Entry;
#endif
/***********************************
* MC4 API Command and Entry structures
*
***********************************/
typedef struct _tMC6Output {
U32 timer;
U8 output_device_str[11];
U8 shaper_mask;
U8 uc_bit:1,
q_bit:1,
rsvd:6;
U8 uc_mac[6];
U8 queue;
U8 new_output_device_str[11];
U8 if_bit:1,
unused:7;
}MC6Output, *PMC6Output;
typedef struct _tMC6Command {
U16 action;
U8 mode : 1,
queue : 5,
rsvd : 2;
U8 src_mask_len;
U32 src_addr[4];
U32 dst_addr[4];
U32 num_output;
MC6Output output_list[MCx_MAX_LISTENERS_IN_QUERY];
}MC6Command, *PMC6Command;
#define MC6_MIN_COMMAND_SIZE 64 /* with one listener entry using 1 interface name */
extern struct tMC6_context gMC6Ctx;
#if !defined(COMCERTO_2000) || defined(COMCERTO_2000_CONTROL)
extern struct slist_head mc6_table_memory[MC6_NUM_HASH_ENTRIES];
#else
extern PVOID mc6_table_memory[MC6_NUM_HASH_ENTRIES];
#endif
BOOL mc6_init(void);
void mc6_exit(void);
void M_MC6_process_packet(PMetadata mtd) __attribute__((section ("fast_path")));
#if !defined(COMCERTO_2000)
void M_mc6_entry(void) __attribute__((section ("fast_path")));
#endif
void MC6_interface_purge(U32 if_index);
static inline u32 HASH_MC6(void *pdestaddr) // pass in ptr to IPv6 dest addr
{
u16 *p = (u16 *)pdestaddr;
u32 hash;
hash = ntohs(p[4]) + ntohs(p[5]) + ntohs(p[6]) + ntohs(p[7]);
hash = hash ^ (hash >> 4) ^ (hash >> 8) ^ (hash >> 12);
return hash & (MC6_NUM_HASH_ENTRIES - 1);
}
#if defined(COMCERTO_2000_CLASS)
/** Searches multicast forwarding table for a match based on a given IPv6 header.
* @param[in] ipv6_hdr pointer to IPv6 header to be used for the search.
* @return pointer to matching entry, or NULL if no entry found.
*/
static __inline MC6Entry *MC6_rule_search_class(ipv6_hdr_t *ipv6_hdr)
{
PMC6Entry dmem_entry;
volatile PMC6Entry ddr_entry;
U32 *srca = ipv6_hdr->SourceAddress;
U32 *dsta = ipv6_hdr->DestinationAddress;
U32 hash_key;
hash_key = HASH_MC6(dsta);
ddr_entry = mc6_table_memory[hash_key];
dmem_entry = (PVOID)(CLASS_ROUTE0_BASE_ADDR);
while (ddr_entry) {
efet_memcpy(dmem_entry, ddr_entry, sizeof(MC6Entry));
while (dmem_entry->flags & HASH_ENTRY_UPDATING)
{
while (ddr_entry->flags & HASH_ENTRY_UPDATING) ;
efet_memcpy(dmem_entry, ddr_entry, sizeof(MC6Entry));
}
if (!IPV6_CMP(dsta, dmem_entry->dst_addr))
{
if (ipv6_cmp_mask(srca, (U32*)dmem_entry->src_addr, dmem_entry->mcdest.src_mask_len)) {
return dmem_entry;
}
}
ddr_entry = (PMC6Entry) dmem_entry->next;
}
return NULL;
}
#else
/** Searches multicast forwarding table for match based on source and destination IPv6 addresses.
* @param[in] srca IPv6 source address
* @param[in] dsta IPv6 destination address
* @return pointer to matching entry, or NULL if no entry found.
*/
static __inline MC6Entry *MC6_rule_search(U32 *srca, U32 *dsta)
{
PMC6Entry this_entry;
struct slist_entry *entry;
U32 hash_key;
#define _l_src ((PACKED_U32 *)(srca))
#define _l_dst ((PACKED_U32 *)(dsta))
hash_key = HASH_MC6(_l_dst);
slist_for_each(this_entry, entry, &mc6_table_memory[hash_key], list)
{
if (!IPV6_CMP(_l_dst,this_entry->dst_addr))
{
if (ipv6_cmp_mask((U32*) _l_src, (U32*)this_entry->src_addr, this_entry->mcdest.src_mask_len)) {
return this_entry;
}
}
}
#undef _l_src
#undef _l_dst
return NULL;
}
#endif
#endif /* _MODULE_MC6_H_ */