blob: 6b194ada2ca9a15446707058f14580bfdec0e256 [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_IPV4_H_
#define _MODULE_IPV4_H_
#include "channels.h"
#include "modules.h"
#include "fe.h"
#include "common_hdrs.h"
#include "layer2.h"
#include "module_socket.h"
#define UDP_REPLY_TIMER_INIT 0xFFFFFFFF
#define MAX_L2_HEADER 18
//Conntrack entry
#if !defined(COMCERTO_2000)
typedef struct _tCtEntry{
// start of common header -- must match IPv6
struct slist_entry list;
U32 last_ct_timer;
union {
U16 fwmark;
struct {
U16 queue : 5;
U16 vlan_pbits : 3;
U16 dscp_mark_flag : 1;
U16 dscp_mark_value : 6;
U16 set_vlan_pbits : 1;
} __attribute__((packed));
};
U16 status;
union {
PRouteEntry pRtEntry;
U32 route_id;
};
// end of common header
U32 Saddr_v4;
U32 Daddr_v4;
U16 Sport;
U16 Dport;
U16 ip_chksm_corr;
U16 tcp_udp_chksm_corr;
// DC line boundary
U32 twin_Saddr;
U32 twin_Daddr;
U16 twin_Sport;
U16 twin_Dport;
U16 unused1;
U16 unused2;
//U32 unused2;
PRouteEntry tnl_route;
U16 hSAEntry[SA_MAX_OP];
U8 rtpqos_slot;
}CtEntry, *PCtEntry;
static inline PRouteEntry ct_tnl_route(PCtEntry pCtEntry)
{
return pCtEntry->tnl_route;
}
static inline PRouteEntry ct_route(PCtEntry pCtEntry)
{
return pCtEntry->pRtEntry;
}
static inline U8 GET_PROTOCOL(PCtEntry pCtEntry)
{
return ct_proto[pCtEntry->status & CONNTRACK_PROTO_MASK];
}
static inline void SET_PROTOCOL(PCtEntry pCtEntry_orig,PCtEntry pCtEntry_rep, U8 Proto)
{
switch(Proto)
{
case IPPROTOCOL_UDP:
pCtEntry_orig->status |= CONNTRACK_UDP;
pCtEntry_rep->status |= CONNTRACK_UDP;
break;
case IPPROTOCOL_IPIP:
pCtEntry_orig->status |= CONNTRACK_IPIP;
pCtEntry_rep->status |= CONNTRACK_IPIP;
break;
case IPPROTOCOL_TCP:
default:
break;
}
#elif defined(COMCERTO_2000_CONTROL)
struct hw_ct {
U32 next;
U32 flags;
/******* !!!!!!!!!!!!!!!!!! *********/
/* Be careful about adding/moving fields in this structure -- hw_ct_delayed_remove() does a
partial structure copy that depends on the exact layout of the structure */
/******* !!!!!!!!!!!!!!!!!! *********/
U16 Sport;
U16 Dport;
U8 proto;
U8 rtpqos_slot;
U16 hash;
union {
struct {
U32 Saddr_v4;
U32 Daddr_v4;
U32 twin_Saddr;
U32 twin_Daddr;
U16 twin_Sport;
U16 twin_Dport;
struct hw_route_4o6 tnl4o6_route;
};
struct {
U32 Saddr_v6[4];
U32 Daddr_v6[4];
struct hw_route tnl6o4_route;
};
};
/* End of fields used by hardware */
struct hw_route route;
union {
U16 fwmark;
struct {
U16 set_vlan_pbits : 1;
U16 dscp_mark_value : 6;
U16 dscp_mark_flag : 1;
U16 vlan_pbits : 3;
U16 queue : 5;
};
};
U16 status;
U32 active;
U16 ip_chksm_corr;
U16 tcp_udp_chksm_corr;
U16 hSAEntry[SA_MAX_OP];
U32 twin_dma_addr;
/******* !!!!!!!!!!!!!!!!!! *********/
/* Be careful about adding/moving fields in this structure -- hw_ct_delayed_remove() does a
partial structure copy that depends on the exact layout of the structure */
/******* !!!!!!!!!!!!!!!!!! *********/
U32 dma_addr; /** Physical address of the hardware conntrack, used for keepalive writeback and delayed removal*/
/* The bellow fields are only used by host software, so keep them at the end of the structure */
struct dlist_head list; /** if the entry is in the hash array, this is the list head for the hash bucket,
otherwise it's a list entry in the hash bucket list */
struct dlist_head rlist;
struct _tCtEntry *pCtEntry; /** pointer to the software conntrack */
unsigned long removal_time;
};
typedef struct _tCtEntry {
struct slist_entry list;
U16 Sport;
U16 Dport;
U8 proto;
U8 inPhyPortNum;
U16 hash;
union {
struct {
U32 Saddr_v4;
U32 Daddr_v4;
U32 unused1;
U32 unused2;
U32 twin_Saddr;
U32 twin_Daddr;
U16 twin_Sport;
U16 twin_Dport;
U32 unused3;
};
struct {
U32 Saddr_v6[4];
U32 Daddr_v6[4];
};
};
/* End of fields used by hardware */
U32 route_id;
PRouteEntry pRtEntry;
union {
U16 fwmark;
struct {
U16 set_vlan_pbits : 1;
U16 dscp_mark_value : 6;
U16 dscp_mark_flag : 1;
U16 vlan_pbits : 3;
U16 queue : 5;
};
};
U16 status;
U32 last_ct_timer;
U16 ip_chksm_corr;
U16 tcp_udp_chksm_corr;
PRouteEntry tnl_route;
U16 hSAEntry[SA_MAX_OP];
struct _tCtEntry *twin;
struct hw_ct *ct; /** pointer to the hardware conntrack */
}CtEntry, *PCtEntry;
static inline U8 GET_PROTOCOL(PCtEntry pCtEntry)
{
return pCtEntry->proto;
}
static inline void SET_PROTOCOL(PCtEntry pCtEntry_orig,PCtEntry pCtEntry_rep, U8 Proto)
{
pCtEntry_orig->proto = Proto;
pCtEntry_rep->proto = Proto;
}
#define IS_HASH_ARRAY(ctrl, ct_addr) (((unsigned long)(ct_addr) >= (unsigned long)(ctrl->hash_array_baseaddr)) \
&& ((unsigned long)(ct_addr) < ((unsigned long)(ctrl->hash_array_baseaddr) + (NUM_CT_ENTRIES * CLASS_ROUTE_SIZE))))
#else // defined(COMCERTO_2000)
void M_IPV4_rtp_process_from_util(PMetadata mtd, lmem_trailer_t *trailer);
void M_IPV4_process_from_util(PMetadata mtd, lmem_trailer_t *trailer);
typedef struct _tCtEntry{
struct slist_entry list;
U32 flags;
U16 Sport;
U16 Dport;
U8 proto;
U8 rtpqos_slot;
U16 hash;
union {
struct {
U32 Saddr_v4;
U32 Daddr_v4;
U32 twin_Saddr;
U32 twin_Daddr;
U16 twin_Sport;
U16 twin_Dport;
RouteEntry_4o6 tnl4o6_route;
};
struct {
U32 Saddr_v6[4];
U32 Daddr_v6[4];
RouteEntry tnl6o4_route;
};
};
/* End of fields used by hardware */
RouteEntry route;
union {
U16 fwmark;
struct {
U16 set_vlan_pbits : 1;
U16 dscp_mark_value : 6;
U16 dscp_mark_flag : 1;
U16 vlan_pbits : 3;
U16 queue : 5;
};
};
U16 status;
U32 active;
U16 ip_chksm_corr;
U16 tcp_udp_chksm_corr;
U16 hSAEntry[SA_MAX_OP];
U32 twin_dma_addr;
U32 dma_addr; /** Physical address of the hardware conntrack, used for keepalive writeback and delayed removal*/
}CtEntry, *PCtEntry;
#if !defined(COMCERTO_2000_CONTROL)
static inline PRouteEntry_4o6 ct_tnl_route(PCtEntry pCtEntry)
{
return &pCtEntry->tnl4o6_route;
}
#endif
static inline PRouteEntry ct_route(PCtEntry pCtEntry)
{
return &pCtEntry->route;
}
#if defined(CFG_STANDALONE)
static inline void temp_route_setup(PRouteEntry pRtEntry, PCtEntry pCtEntry, PMetadata mtd)
{
//#define TEST_PPPOE
#if !defined(TEST_PPPOE)
pRtEntry->itf = (mtd->input_port == 0 ? &phy_port[1].itf : &phy_port[0].itf);
if (pRtEntry->mtu == 0)
pRtEntry->mtu = 1500;
#else /* to test PPPoE */
pRtEntry->itf = (mtd->input_port == 0 ? &phy_port[1].itf : &pppoe_itf[0].itf);
if (pRtEntry->mtu == 0)
pRtEntry->mtu = 1492;
#endif
}
#endif
#endif /* !defined(COMCERTO_2000) */
#if defined(COMCERTO_2000_CONTROL)
#define CT_TWIN(pentry) (((PCtEntry)(pentry))->twin)
#define CT6_TWIN(pentry) CT_TWIN(pentry)
#define CT_ORIG(pentry) ((((PCtEntry)(pentry))->status & CONNTRACK_ORIG) ? (PCtEntry)(pentry) : ((PCtEntry)(pentry))->twin)
#define CT6_ORIG(pentry) CT_ORIG(pentry)
#define CT_REPLY_BIT(pentry) (!(((PCtEntry)(pentry))->status & CONNTRACK_ORIG))
#elif defined(COMCERTO_2000)
#define CT_TWIN(pentry) (((PCtEntry)(pentry))->twin_dma_addr)
#define CT6_TWIN(pentry) CT_TWIN(pentry)
#else
#define CT_TWIN(pentry) (PCtEntry)((U32)(pentry) ^ CTENTRY_UNIDIR_SIZE)
#define CT6_TWIN(pentry) (PCtEntryIPv6)((U32)(pentry) ^ CTENTRY_UNIDIR_SIZE)
#define CT_ORIG(pentry) (PCtEntry)((U32)(pentry) & ~CTENTRY_UNIDIR_SIZE)
#define CT6_ORIG(pentry) (PCtEntryIPv6)((U32)(pentry) & ~CTENTRY_UNIDIR_SIZE)
#define CT_REPLY_BIT(pentry) ((U32)(pentry) & CTENTRY_UNIDIR_SIZE)
#endif
extern struct slist_head rt_cache[];
PCtEntry ct_alloc(void);
void ct_free(PCtEntry pEntry_orig);
int ct_add(PCtEntry pEntry_orig, PCtEntry pEntry_rep, U32 hash_orig, U32 hash_rep);
void ct_update(PCtEntry pEntry_orig, PCtEntry pEntry_rep, U32 hash_orig, U32 hash_rep);
void ct_remove(PCtEntry pEntry_orig, PCtEntry pEntry_rep, U32 hash_orig, U32 hash_rep);
int ipv4_init(void);
void ipv4_exit(void);
#if defined(COMCERTO_2000_CONTROL) || !defined(COMCERTO_2000)
U32 Get_Ctentry_Hash(PVOID pblock) __attribute__ ((noinline));
int IPv4_delete_CTpair(PCtEntry ctEntry) __attribute__ ((noinline));
void IP_deleteCt_from_onif_index(U32 if_index) __attribute__ ((noinline));
void IP_MarkSwap(PCtEntry pCtEntry, PCtEntry pCtTwin) __attribute__ ((noinline));
PRouteEntry IP_Check_Route(PCtEntry pCtEntry);
void IP_delete_CT_route(PCtEntry pCtEntry) __attribute__ ((noinline));
void IP_expire(PCtEntry pCtEntry);
U32 IP_get_fwmark(PCtEntry pOrigEntry, PCtEntry pReplEntry);
#endif
#if !defined(COMCERTO_2000)
void M_ipv4_entry(void) __attribute__((section ("fast_path")));
#endif
PCtEntry IPv4_get_ctentry(U32 saddr, U32 daddr, U16 sport, U16 dport, U16 proto) __attribute__ ((noinline));
void M_IPV4_process_packet(PMetadata mtd) __attribute__((section ("fast_path")));
void M_RTP_RELAY_process_packet(PMetadata mtd);
PMetadata IPv4_fragment_packet(PMetadata mtd, ipv4_hdr_t *ipv4_hdr, U32 mtu, U32 preL2_len, U32 if_type);
#if defined(COMCERTO_2000)
PMetadata IPv4_fragment_packet_ipsec(PMetadata mtd, ipv4_hdr_t *ipv4_hdr, U32 mtu, U32 preL2_len, U32 if_type);
#endif
int IPv4_xmit_on_socket(PMetadata mtd, PSockEntry pSocket, BOOL ipv4_update, U32 payload_diff, U8* inner_ipv4hdr);
#if defined(COMCERTO_2000)
#define CT_VALID (1 << 0)
#define CT_USED (1 << 1)
#define CT_UPDATING (1 << 2)
extern U32 class_route_table_base;
extern U32 class_route_table_hash_mask;
#if defined(COMCERTO_2000_CONTROL)
extern struct slist_head ct_cache[];
#else
extern PCtEntry ct_cache[];
static inline void ct_keepalive(PCtEntry pCtEntry)
{
/* If host has marked connection inactive, update ddr structure */
if (!pCtEntry->active)
{
PCtEntry ddr_ct = (PCtEntry)pCtEntry->dma_addr;
ddr_ct->active = 1;
}
}
#endif
#define CRCPOLY_BE 0x04c11db7
static inline U32 crc32_be(U8 *data)
{
int i, j;
U32 crc = 0xffffffff;
for (i = 0; i < 4; i++) {
crc ^= *data++ << 24;
for (j = 0; j < 8; j++)
crc = (crc << 1) ^ ((crc & 0x80000000) ? CRCPOLY_BE : 0);
}
return crc;
}
static __inline U32 HASH_CT(U32 Saddr, U32 Daddr, U32 Sport, U32 Dport, U16 Proto)
{
U32 sum;
sum = Saddr ^ htonl(ntohs(Sport));
sum = crc32_be((u8 *)&sum);
sum += ntohl(Daddr);
sum += Proto;
sum += ntohs(Dport);
// sum += phy_no;
return sum & CT_TABLE_HASH_MASK;
}
PCtEntry M_ipv4_frag_ConntrackMatch(PMetadata mtd, ipv4_hdr_t * ipv4_hdr);
#else
extern struct slist_head ct_cache[];
static __inline U32 HASH_CT(U32 Saddr, U32 Daddr, U32 Sport, U32 Dport, U16 Proto)
{
U32 sum;
sum = Saddr + ((Daddr << 7) | (Daddr >> 25));
sum ^= Sport + ((Dport << 11) | (Dport >> 21));
sum ^= (sum >> 16);
sum ^= (sum >> 8);
return (sum ^ Proto) & CT_TABLE_HASH_MASK;
}
// Fast CTData
extern U8 Fast_CTData[];
extern U8 *pFast_CTData_freelist;
#define Is_FastCT_block(pblock) (((U32)(pblock) & 0xFF000000) == 0x0a000000)
void Fast_CTData_CopyBlock(PVOID newblock, PVOID origblock) __attribute__ ((noinline));
static INLINE U8 *Fast_CTData_Alloc(void)
{
U8 *pblock;
if (pFast_CTData_freelist != NULL)
{
pblock = pFast_CTData_freelist;
pFast_CTData_freelist = *(U8 **)pblock;
}
else
{
pblock = Heap_Alloc(CTENTRY_BIDIR_SIZE);
}
return pblock;
}
static INLINE void CTData_Free(PVOID pblock)
{
if (Is_FastCT_block(pblock))
{
*(U8 **)pblock = pFast_CTData_freelist;
pFast_CTData_freelist = (U8 *)pblock;
}
else
Heap_Free(pblock);
}
static inline void ct_keepalive(PCtEntry pCtEntry)
{
// we update the timeout since we saw a new packet
pCtEntry->last_ct_timer = ct_timer;
}
#endif /* COMCERTO_2000 */
#endif /* _MODULE_IPV4_H_ */