spbx/roms/srcs/images/ethernet/common/hook.c

2428 lines
70 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/phy.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/spinlock_types.h>
#include <linux/net.h>
#include <net/udp.h>
#include <net/arp.h>
#include <net/inet_common.h>
#include "debug_info.h"
#include "log.h"
#if defined(PLATFORM_MV78460)
#include "mv_netdev.h"
#elif defined(PLATFORM_P1010)
#include "gianfar.h"
#endif
#include "hook.h"
#define P1010_CPU_COUNT_PER_MS (50000)
#define SEND_SEQ_POS (0x2C)
#define RECV_SEQ_POS (SEND_SEQ_POS - 0x0E)
static int DbgFS_RtpPortShow(struct seq_file* seq, void* token);
static int DbgFS_GianfarSipPortShow(struct seq_file* seq, void* token);
static int DbgFS_SipArpShow(struct seq_file* seq, void* token);
static int DbgFS_NICCfgShow(struct seq_file* seq, void* token);
static int DbgFS_EthIrqShow(struct seq_file* seq, void* token);
static int DbgFS_EthIrqHelp(struct seq_file* seq, void* token);
static int DbgFS_EthIrqIoctl(struct seq_file* seq, char* cmd, char* params);
#ifdef PLATFORM_MV78460
static unsigned char g_spbxNetId = ETH_INTERFACE_2;
#else
static unsigned char g_spbxNetId = ETH_INTERFACE_0;
#endif
static PNIC_RCV_RTP_DATA g_pRcvRtpHook = NULL;
static spinlock_t g_RegHookLock;
PNIC_PRIVATE g_NICInfo[MAX_ETH_PORT];
typedef enum __DBGFS_ID
{
DBG_SIP_CH,
DBG_SIP_ARP,
DBG_RTP_PORT,
DBG_NIC_CFG,
DBG_ETH_IRQ,
} DBGFS_ID;
static DBGFS_PRIV g_DbgFSConfig[] =
{
{
"sip_ch", 0, NULL, NULL,
DbgFS_GianfarSipPortShow, NULL, NULL
},
{
"sip_arp", 0, NULL, NULL,
DbgFS_SipArpShow, NULL, NULL
},
{
"rtp_port", 0, NULL, NULL,
DbgFS_RtpPortShow, NULL, NULL
},
{
"nic_config", 0, NULL, NULL,
DbgFS_NICCfgShow, NULL, NULL
},
{
"eth_irq", 0, NULL, NULL,
DbgFS_EthIrqShow, DbgFS_EthIrqIoctl, DbgFS_EthIrqHelp
},
};
int NIC_GetInfo(const char* pNIC, PNIC_INFO pInfo)
{
int iRet = 0;
struct socket* sock;
struct ifreq ifr;
mm_segment_t oldCfg;
struct net_device* dev;
if(!pNIC || !pInfo)
{
LOG_EX(LOG_Error, "Input Params Error:%p, %p", pNIC, pInfo);
return -1;
}
memset(pInfo, 0, sizeof(NIC_INFO));
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, pNIC);
iRet = sock_create_kern(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock);
if(iRet < 0 || NULL == sock)
{
LOG_EX(LOG_Error, "sock_create_kern Error:%d\n", iRet);
return -1;
}
dev = dev_get_by_name(sock_net(sock->sk), pNIC);
if(dev == NULL)
{
LOG_EX(LOG_Error, "dev_get_by_name Error\n");
return -1;
}
pInfo->devIfIndex = dev->ifindex;
memcpy(pInfo->macAddr, dev->dev_addr, 6);
oldCfg = get_fs();
set_fs(KERNEL_DS);
if((iRet = inet_ioctl(sock, SIOCGIFADDR, (unsigned long)&ifr)) != 0)
{
LOG_EX(LOG_Error, "Get Ip Addr Error: %d\n", iRet);
}
pInfo->ipAddr = ((struct sockaddr_in*)&ifr.ifr_addr)->sin_addr.s_addr;
if((iRet = inet_ioctl(sock, SIOCGIFBRDADDR, (unsigned long)&ifr)) != 0)
{
LOG_EX(LOG_Error, "Get Board Addr Error: %d\n", iRet);
}
pInfo->boardAddr = ((struct sockaddr_in*)&ifr.ifr_broadaddr)->sin_addr.s_addr;
if((iRet = inet_ioctl(sock, SIOCGIFNETMASK, (unsigned long)&ifr)) != 0)
{
LOG_EX(LOG_Error, "Get Netmask Addr Error: %d\n", iRet);
}
pInfo->netMask = ((struct sockaddr_in*)&ifr.ifr_netmask)->sin_addr.s_addr;
set_fs(oldCfg);
sock_release(sock);
return 0;
}
EXPORT_SYMBOL(NIC_GetInfo);
int make_arp_request_ex(unsigned int ethId, __be32 dest_ip)
{
struct sk_buff* skb = NULL;
NIC_INFO nicInfo;
if(!IS_VALUABLED_ETH(ethId))
{
return -1;
}
if(g_NICInfo[ethId] == NULL)
{
return -2;
}
if(g_NICInfo[ethId]->opened_ref == 0)
{
return -3;
}
memset(&nicInfo, 0, sizeof(NIC_INFO));
NIC_GetInfo(g_NICInfo[ethId]->ndev->name, &nicInfo);
skb = arp_create(ARPOP_REQUEST,
ETH_P_ARP,
dest_ip,
g_NICInfo[ethId]->ndev,
nicInfo.ipAddr,
NULL,
nicInfo.macAddr,
NULL);
if(skb)
{
arp_xmit(skb);
}
else
{
return -3;
}
return 0;
}
EXPORT_SYMBOL(make_arp_request_ex);
int make_arp_request(unsigned int ethId, __be32 dest_ip)
{
struct sk_buff* skb = NULL;
if(!IS_VALUABLED_ETH(ethId))
{
return -1;
}
if(g_NICInfo[ethId] == NULL)
{
return -2;
}
if(g_NICInfo[ethId]->opened_ref == 0)
{
return -3;
}
skb = arp_create(ARPOP_REQUEST,
ETH_P_ARP,
dest_ip,
g_NICInfo[ethId]->ndev,
g_NICInfo[ethId]->chIpAddr,
NULL,
g_NICInfo[ethId]->ndev->dev_addr,
NULL);
if(skb)
{
arp_xmit(skb);
}
return 0;
}
EXPORT_SYMBOL(make_arp_request);
int get_eth_mac(unsigned char* haddr, ETH_INTERFACE ethId)
{
struct net_device* pDev = NULL;
if(!IS_VALUABLED_ETH(ethId))
{
return -1;
}
if(g_NICInfo[ethId] == NULL)
{
return -2;
}
if(g_NICInfo[ethId]->opened_ref == 0)
{
return -3;
}
if(haddr)
{
pDev = g_NICInfo[ethId]->ndev;
memcpy(haddr, pDev->dev_addr, pDev->addr_len);
return pDev->addr_len;
}
return 0;
}
EXPORT_SYMBOL(get_eth_mac);
int get_mac_form_ip(unsigned char* haddr, ETH_INTERFACE ethId, __be32 ipaddr, int id)
{
struct neighbour* n;
PNIC_PRIVATE pEthInfo = NULL;
__be32 oldip = ipaddr;
if(!IS_VALUABLED_ETH(ethId))
{
return -1;
}
pEthInfo = g_NICInfo[ethId];
if(pEthInfo == NULL)
{
return -2;
}
if(id == 4 || id == 3)
{
printk("ethId = %d, ipaddr = 0x%08X\n", ethId, ipaddr);
}
//memset(haddr, 0xFF, ETH_ALEN);
if(pEthInfo->chGWIpAddr != 0)
{
if((ntohl(ipaddr) & pEthInfo->chGWMask) != (pEthInfo->chIpAddr & pEthInfo->chGWMask))
{
if(id == 4 || id == 3)
{
printk("ipaddr = 0x%08X, pEthInfo->chGWMask = 0x%08X, pEthInfo->chIpAddr = 0x%08X\n",
ipaddr, pEthInfo->chGWMask, pEthInfo->chIpAddr);
}
ipaddr = pEthInfo->chGWIpAddr;
}
}
if(id == 4 || id == 3)
{
printk("eth %d ipaddr 0x%08X get ip 0x%08X arp call by %d\n",
ethId, oldip, ipaddr, id);
}
if(haddr != NULL)
{
n = __neigh_lookup(&arp_tbl, &ipaddr, pEthInfo->ndev, 1);
if(n != NULL)
{
n->used = jiffies;
if(n->nud_state & NUD_VALID)
{
memcpy(haddr, n->ha, pEthInfo->ndev->addr_len);
neigh_release(n);
return 0;
}
else
{
neigh_release(n);
}
}
else if(id == 4 || id == 3)
{
printk("__neigh_lookup is null\n");
}
}
if(id == 4 || id == 3)
{
printk("eth %d ipaddr 0x%08X get ip 0x%08X arp call by %d Error\n",
ethId, oldip, ipaddr, id);
}
return -1;
}
EXPORT_SYMBOL(get_mac_form_ip);
unsigned short get_ip_checksum(unsigned short* buffer, int size)
{
unsigned long cksum = 0;
while(size > 1)
{
cksum += *buffer++;
size -= sizeof(unsigned short);
}
if(size)
{
cksum += *(unsigned short*)buffer;
}
cksum = (cksum >> 16) + (cksum & 0xffff);
cksum += (cksum >> 16);
return (unsigned short)(~cksum);
}
EXPORT_SYMBOL(get_ip_checksum);
#define RECV_RFC2833_RECV_NEW (0)
#define RECV_RFC2833_RECV_REP (1)
#define RECV_RFC2833_RECV_DROP (2)
#define RECV_RFC2833_RECV_UNRECV (4)
#define CHK_CH_STATUS (1 << 0)
#define CHK_CH_DSTTARGET (1 << 1)
#define CHK_CH_NEEDSWITCH (1 << 2)
#define CHK_CH_SWITCH_OK (1 << 3)
#define CHK_CH_SWITCH_ERR (1 << 4)
#define CHK_CH_RFC2833 (1 << 5)
#define CHK_CH_NEEDSWITCH_SAMEBOARD (1 << 6)
#define CHK_CH_RECVUDP (1 << 7)
#define CHK_CH_DROP_WAITARP (1 << 8)
static SIP_CH_INFO g_SIPChInfo;
static int g_DebugRFC2833 = 0;
static int g_CheckRFC2833 = 0;
static SIP_CH_DETIAL g_SIPDetial[MAX_SIP_CH];
const char g_DTMFTable[17] =
{
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'*', '#',
'A', 'B', 'C', 'D',
'F' // Flash
};
static struct sk_buff* switch_to_sip(int sipCh,
struct sk_buff* skb,
ETH_INTERFACE ethId,
PCH_PORT_INFO pPort);
static int CheckMacAddress(PCH_PORT_INFO pPort, ETH_INTERFACE ethId);
static int DbgFS_SipArpShow(struct seq_file* seq, void* token)
{
unsigned int opt = g_DbgFSConfig[DBG_SIP_ARP].params;
unsigned char mac[12];
int ret, i = 0;
if(token == SEQ_START_TOKEN)
{
for(i = 0; i < 3; i++)
{
if(g_NICInfo[i] != NULL)
{
ret = get_mac_form_ip(mac, i,
htonl(g_NICInfo[i]->chGWIpAddr), 2);
seq_printf(seq, "eth %d request arp %d.%d.%d.%d is %02X:%02X:%02X:%02X:%02X:%02X ret %d\n",
g_NICInfo[i]->port,
(g_NICInfo[i]->chGWIpAddr >> 24) & 0xFF,
(g_NICInfo[i]->chGWIpAddr >> 16) & 0xFF,
(g_NICInfo[i]->chGWIpAddr >> 8) & 0xFF,
g_NICInfo[i]->chGWIpAddr & 0xFF,
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], ret);
}
}
if(opt >= 0 && opt < g_SIPChInfo.iTotalCh)
{
PSIP_CH_DETIAL pCh = g_SIPChInfo.pSipChDetial + opt;
seq_printf(seq, "pCh->portB2B.chStatus = %d, pCh->portB2B.chStatus = %d\n",
pCh->portB2B.chStatus, pCh->portRTP.chStatus);
if(pCh->portB2B.chStatus == 2)
{
ret = get_mac_form_ip(mac, 0,
htonl(pCh->portB2B.chLinkInfo.dstTarget.ipAddr), 3);
seq_printf(seq, "eth %d request arp %d.%d.%d.%d is %02X:%02X:%02X:%02X:%02X:%02X ret %d\n",
0,
(pCh->portB2B.chLinkInfo.dstTarget.ipAddr >> 24) & 0xFF,
(pCh->portB2B.chLinkInfo.dstTarget.ipAddr >> 16) & 0xFF,
(pCh->portB2B.chLinkInfo.dstTarget.ipAddr >> 8) & 0xFF,
pCh->portB2B.chLinkInfo.dstTarget.ipAddr & 0xFF,
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], ret);
}
if(pCh->portRTP.chStatus == 2)
{
ret = get_mac_form_ip(mac, pCh->sipETHId,
htonl(pCh->portRTP.chLinkInfo.dstTarget.ipAddr), 4);
seq_printf(seq, "eth %d request arp %d.%d.%d.%d is %02X:%02X:%02X:%02X:%02X:%02X ret %d\n",
pCh->sipETHId,
(pCh->portRTP.chLinkInfo.dstTarget.ipAddr >> 24) & 0xFF,
(pCh->portRTP.chLinkInfo.dstTarget.ipAddr >> 16) & 0xFF,
(pCh->portRTP.chLinkInfo.dstTarget.ipAddr >> 8) & 0xFF,
pCh->portRTP.chLinkInfo.dstTarget.ipAddr & 0xFF,
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], ret);
}
}
else
{
seq_printf(seq, "opt = %d\n", opt);
}
}
return 0;
}
static int DbgFS_GianfarSipPortShow(struct seq_file* seq, void* token)
{
unsigned int opt = g_DbgFSConfig[DBG_SIP_CH].params;
int i = 0;
if(token == SEQ_START_TOKEN)
{
if(opt == 1)
{
seq_printf(seq, "g_DebugRFC2833 Off\n");
g_DebugRFC2833 = 0;
}
else if(opt == 2)
{
seq_printf(seq, "g_DebugRFC2833 On\n");
g_DebugRFC2833 = 1;
}
else if(opt == 3)
{
seq_printf(seq, "g_CheckRFC2833 Off\n");
g_CheckRFC2833 = 0;
}
else if(opt == 4)
{
seq_printf(seq, "g_CheckRFC2833 On\n");
g_CheckRFC2833 = 1;
}
else if(opt == 5)
{
seq_printf(seq, "g_CheckRFC2833 Clean\n");
for(i = 0; i < g_SIPChInfo.iTotalCh; i++)
{
g_SIPChInfo.pSipChDetial[i].sipDebug.ethx_rfc2833_error = 0;
}
}
else
{
seq_printf(seq, "g_CheckRFC2833 = %d, g_DebugRFC2833 = %d\n",
g_CheckRFC2833, g_DebugRFC2833);
}
seq_printf(seq, "SPI Info:\n");
for(i = 0; i < 3; i++)
{
if(g_NICInfo[i] != NULL)
{
seq_printf(seq,
"ucc=%p, index=%d ipaddr=%d.%d.%d.%d gw=%d.%d.%d.%d gw mask=%d.%d.%d.%d\n",
g_NICInfo[i], g_NICInfo[i]->port,
(g_NICInfo[i]->chIpAddr >> 24) & 0xFF,
(g_NICInfo[i]->chIpAddr >> 16) & 0xFF,
(g_NICInfo[i]->chIpAddr >> 8) & 0xFF,
g_NICInfo[i]->chIpAddr & 0xFF,
(g_NICInfo[i]->chGWIpAddr >> 24) & 0xFF,
(g_NICInfo[i]->chGWIpAddr >> 16) & 0xFF,
(g_NICInfo[i]->chGWIpAddr >> 8) & 0xFF,
g_NICInfo[i]->chGWIpAddr & 0xFF,
(g_NICInfo[i]->chGWMask >> 24) & 0xFF,
(g_NICInfo[i]->chGWMask >> 16) & 0xFF,
(g_NICInfo[i]->chGWMask >> 8) & 0xFF,
g_NICInfo[i]->chGWMask & 0xFF);
}
}
seq_printf(seq, "Total Ch: %d\n", g_SIPChInfo.iTotalCh);
seq_printf(seq, "Port Base: %d\n", g_SIPChInfo.iPortBase);
seq_printf(seq, "Port Step: %d\n", g_SIPChInfo.iPortStep);
seq_printf(seq, "RTP Port Base: %d\n", g_SIPChInfo.iRTPPortBase);
for(i = 0; i < g_SIPChInfo.iTotalCh; i++)
{
PSIP_CH_DETIAL pCh = g_SIPChInfo.pSipChDetial + i;
if(pCh->portB2B.chStatus != 2 &&
pCh->portRTP.chStatus != 2)
{
continue;
}
seq_printf(seq, "++++++++++++++++Ch %d Info+++++++++++++\n", i);
seq_printf(seq, "B2B Status: %d\n", pCh->portB2B.chStatus);
seq_printf(seq, "B2B IP Port: %d\n", pCh->portB2B.ipPort);
seq_printf(seq, "B2B Link IP: %d.%d.%d.%d\n",
(pCh->portB2B.chLinkInfo.dstTarget.ipAddr >> 24) & 0xFF,
(pCh->portB2B.chLinkInfo.dstTarget.ipAddr >> 16) & 0xFF,
(pCh->portB2B.chLinkInfo.dstTarget.ipAddr >> 8) & 0xFF,
pCh->portB2B.chLinkInfo.dstTarget.ipAddr & 0xFF);
seq_printf(seq, "B2B Link Port: %d\n", pCh->portB2B.chLinkInfo.dstTarget.ipPort);
seq_printf(seq, "B2B Link Mac: %02X:%02X:%02X:%02X:%02X:%02X\n\n",
pCh->portB2B.chLinkInfo.dstTarget.ethAddr[0],
pCh->portB2B.chLinkInfo.dstTarget.ethAddr[1],
pCh->portB2B.chLinkInfo.dstTarget.ethAddr[2],
pCh->portB2B.chLinkInfo.dstTarget.ethAddr[3],
pCh->portB2B.chLinkInfo.dstTarget.ethAddr[4],
pCh->portB2B.chLinkInfo.dstTarget.ethAddr[5]);
seq_printf(seq, "RTP Status: %d\n", pCh->portRTP.chStatus);
seq_printf(seq, "RTP ETH: %d\n", pCh->sipETHId);
seq_printf(seq, "RTP IP Port: %d\n", pCh->portRTP.ipPort);
seq_printf(seq, "RTP Link IP: %d.%d.%d.%d\n",
(pCh->portRTP.chLinkInfo.dstTarget.ipAddr >> 24) & 0xFF,
(pCh->portRTP.chLinkInfo.dstTarget.ipAddr >> 16) & 0xFF,
(pCh->portRTP.chLinkInfo.dstTarget.ipAddr >> 8) & 0xFF,
pCh->portRTP.chLinkInfo.dstTarget.ipAddr & 0xFF);
seq_printf(seq, "RTP Link Port: %d\n", pCh->portRTP.chLinkInfo.dstTarget.ipPort);
seq_printf(seq, "RTP Link Mac: %02X:%02X:%02X:%02X:%02X:%02X\n\n",
pCh->portRTP.chLinkInfo.dstTarget.ethAddr[0],
pCh->portRTP.chLinkInfo.dstTarget.ethAddr[1],
pCh->portRTP.chLinkInfo.dstTarget.ethAddr[2],
pCh->portRTP.chLinkInfo.dstTarget.ethAddr[3],
pCh->portRTP.chLinkInfo.dstTarget.ethAddr[4],
pCh->portRTP.chLinkInfo.dstTarget.ethAddr[5]);
seq_printf(seq, "RTP Stun Tag: %d\n", pCh->portRTP.chLinkInfo.stunTags);
seq_printf(seq, "ETH(spbx) Recv: %d\n", pCh->sipDebug.cnt_eth0_recv);
seq_printf(seq, "ETH(spbx) Switch: %d\n", pCh->sipDebug.cnt_eth0_2_ethx);
seq_printf(seq, "ETH(spbx) Mask: 0x%08X\n", pCh->sipDebug.mask_eth0_2_ethx);
seq_printf(seq, "ETH(spbx) lost: %d\n", pCh->sipDebug.eth0_seq_error);
seq_printf(seq, "ETH(spbx) drop: %d\n\n", pCh->sipDebug.eth0_drop_src);
seq_printf(seq, "ETH(sip) Recv: %d\n", pCh->sipDebug.cnt_ethx_recv);
seq_printf(seq, "ETH(sip) Switch: %d\n", pCh->sipDebug.cnt_ethx_2_eth0);
seq_printf(seq, "ETH(sip) Mask: 0x%08X\n", pCh->sipDebug.mask_ethx_2_eth0);
seq_printf(seq, "ETH(sip) lost: %d\n", pCh->sipDebug.ethx_seq_error);
seq_printf(seq, "ETH(sip) drop: %d\n\n", pCh->sipDebug.ethx_drop_src);
if(g_CheckRFC2833)
{
seq_printf(seq, "ETH(sip) Error Dtmf: %d\n", pCh->sipDebug.ethx_rfc2833_error);
seq_printf(seq, "ETH(sip) Drv Err Dtmf: %d\n", pCh->sipDebug.drv_rcv_rfc2833_error);
}
seq_printf(seq, "ETH(sip) Rcv Dtmf: %d\n", pCh->sipDebug.ethx_rfc2833_recv);
seq_printf(seq, "ETH(sip) Rcv lost Dtmf: %d\n", pCh->sipDebug.ethx_rfc2833_rcv_lost);
seq_printf(seq, "ETH(sip) Snd lost Dtmf: %d\n", pCh->sipDebug.ethx_rfc2833_snd_lost);
seq_printf(seq, "ETH(sip) Drv Rcv Dtmf: %d\n\n", pCh->sipDebug.drv_rcv_rfc2833_recv);
}
}
return 0;
}
static char GetDTMFValue(char dtmf)
{
switch(dtmf)
{
case '0':
return 0;
case '1':
return 1;
case '2':
return 2;
case '3':
return 3;
case '4':
return 4;
case '5':
return 5;
case '6':
return 6;
case '7':
return 7;
case '8':
return 8;
case '9':
return 9;
case '*':
return 10;
case '#':
return 11;
case 'A':
case 'a':
return 12;
case 'B':
case 'b':
return 13;
case 'C':
case 'c':
return 14;
case 'D':
case 'd':
return 15;
case 'F':
case 'f':
return 16;
}
return -1;
}
static void InitIPAddrInfo(PIP_ADDR_INFO pAddrInfo)
{
if(pAddrInfo)
{
memset(pAddrInfo->ethAddr, 0xFF, ETH_ALEN);
pAddrInfo->ipAddr = 0;
pAddrInfo->ipPort = -1;
}
}
static void InitChDTMFRecvInfoBuf(PCH_DTMF_INFO pChDtmf, int i)
{
pChDtmf->dtmfRecvBuf[i].refStatus = RFC2833_RECV_IDLE;
pChDtmf->dtmfRecvBuf[i].dtmfValue = 0xFF;
pChDtmf->dtmfRecvBuf[i].refCount = 0;
pChDtmf->dtmfRecvBuf[i].synIdentifier = 0;
pChDtmf->dtmfRecvBuf[i].timeStamps = 0;
pChDtmf->dtmfRecvBuf[i].seqNumber = 0;
pChDtmf->dtmfRecvBuf[i].payloadType = 0xFF;
}
static void InitChDTMFRecvInfo(PCH_DTMF_INFO pChDtmf)
{
int i = 0;
for(i = 0; i < MAX_DTMF_RECV_BUF; i++)
{
// pChDtmf->dtmfRecvValue[i] = 0xFF;
pChDtmf->dtmfRecvBuf[i].refStatus = RFC2833_RECV_IDLE;
pChDtmf->dtmfRecvBuf[i].dtmfValue = 0xFF;
pChDtmf->dtmfRecvBuf[i].refCount = 0;
pChDtmf->dtmfRecvBuf[i].synIdentifier = 0;
pChDtmf->dtmfRecvBuf[i].timeStamps = 0;
pChDtmf->dtmfRecvBuf[i].seqNumber = 0;
pChDtmf->dtmfRecvBuf[i].payloadType = 0xFF;
}
}
static void InitChDTMFInfo(PCH_DTMF_INFO pChDtmf)
{
if(pChDtmf)
{
pChDtmf->refSendMask = 0;
pChDtmf->drvRfc2833ChkVal = 0;
pChDtmf->nicRfc2833ChkVal = 0;
pChDtmf->dtmfSendBuf.dtmfValue = 0xFF;
pChDtmf->dtmfSendBuf.refCount = 7;
pChDtmf->dtmfSendBuf.refStatus = RFC2833_SEND_IDLE;
pChDtmf->dtmfSendBuf.synIdentifier = 0;
pChDtmf->dtmfSendBuf.timeStamps = 0;
pChDtmf->dtmfSendBuf.payloadType = 101;
pChDtmf->curSendIndex = -1;
pChDtmf->srcIp = 0;
pChDtmf->srcPort = 0;
InitChDTMFRecvInfo(pChDtmf);
}
}
static void InitChPortInfo(PCH_PORT_INFO pPort, PORT_TYPE portType)
{
if(pPort)
{
pPort->portType = portType;
pPort->ipPort = -1;
pPort->chStatus = CH_STATUS_UNKONWN;
pPort->chLinkInfo.linkCh = -1;
}
}
static void InitSIPChDetial(PSIP_CH_DETIAL pCh)
{
int rlt = 0;
if(pCh)
{
memset(pCh, 0, sizeof(SIP_CH_DETIAL));
pCh->chId = -1;
pCh->sipETHId = -1;
InitChPortInfo(&pCh->portB2B, PORT_TYPE_B2B);
InitChPortInfo(&pCh->portIPR, PORT_TYPE_IPR);
InitChPortInfo(&pCh->portT38, PORT_TYPE_T38);
InitChPortInfo(&pCh->portRTP, PORT_TYPE_SIPRTP);
InitChDTMFInfo(&pCh->rfc2833DTMF);
kfifo_free(&pCh->dtmfSendFifo);
rlt = kfifo_alloc(&pCh->dtmfSendFifo, MAX_DTMF_SEND_BUF, GFP_KERNEL);
kfifo_free(&pCh->dtmfRecvFifo);
rlt = kfifo_alloc(&pCh->dtmfRecvFifo, MAX_DTMF_RECV_BUF * 4, GFP_KERNEL);
}
}
int config_sip_ch(unsigned int maxSIPCh,
unsigned int portBase,
unsigned int portStep,
unsigned int rtpPortBase)
{
int i = 0;
if(maxSIPCh > MAX_SIP_CH)
{
maxSIPCh = MAX_SIP_CH;
}
if(maxSIPCh > 0)
{
for(i = 0; i < maxSIPCh; i++)
{
InitSIPChDetial(&g_SIPChInfo.pSipChDetial[i]);
g_SIPChInfo.pSipChDetial[i].sipDebug.ethx_rfc2833_error = 0;
}
g_SIPChInfo.iTotalCh = maxSIPCh;
g_SIPChInfo.iPortBase = portBase;
g_SIPChInfo.iPortStep = portStep;
g_SIPChInfo.iRTPPortBase = rtpPortBase;
return 0;
}
return -1;
}
EXPORT_SYMBOL(config_sip_ch);
int config_sip_port(unsigned int chId,
unsigned int ethId,
unsigned short chPort,
unsigned short sipChPort)
{
if(ethId == g_spbxNetId)
{
return -1;
}
if(g_NICInfo[ethId] == NULL)
{
return -2;
}
if(g_SIPChInfo.pSipChDetial != NULL
&& chId < g_SIPChInfo.iTotalCh)
{
PSIP_CH_DETIAL pChDetail = g_SIPChInfo.pSipChDetial + chId;
pChDetail->chId = chId;
pChDetail->sipETHId = ethId;
pChDetail->portIPR.ipPort = chPort + 0;
pChDetail->portB2B.ipPort = chPort + 1;
pChDetail->portT38.ipPort = chPort + 2;
pChDetail->portRTP.ipPort = sipChPort;
pChDetail->portIPR.chStatus = CH_STATUS_CONFIGUREED;
pChDetail->portB2B.chStatus = CH_STATUS_CONFIGUREED;
pChDetail->portT38.chStatus = CH_STATUS_CONFIGUREED;
pChDetail->portRTP.chStatus = CH_STATUS_CONFIGUREED;
return 0;
}
return -1;
}
EXPORT_SYMBOL(config_sip_port);
int eth_sip_link(unsigned int sipCh,
__be32 dst_ipAddr,
__be16 dst_ipPort,
__be16 stun_tags)
{
PSIP_CH_DETIAL pCh = NULL;
unsigned char macAddr[24];
if(g_SIPChInfo.pSipChDetial == NULL || sipCh >= g_SIPChInfo.iTotalCh)
{
return -1;
}
pCh = &g_SIPChInfo.pSipChDetial[sipCh];
if(g_NICInfo[pCh->sipETHId] == NULL)
{
return -2;
}
if(g_NICInfo[pCh->sipETHId]->opened_ref == 0)
{
return -3;
}
if(pCh->portRTP.chStatus == CH_STATUS_UNKONWN)
{
return -1;
}
make_arp_request(pCh->sipETHId, htonl(dst_ipAddr));
get_mac_form_ip(macAddr, pCh->sipETHId, htonl(dst_ipAddr), 21);
memset(pCh->portRTP.chLinkInfo.dstTarget.ethAddr, 0xFF, ETH_ALEN);
pCh->portRTP.chLinkInfo.dstTarget.ipAddr = dst_ipAddr;
pCh->portRTP.chLinkInfo.dstTarget.ipPort = dst_ipPort;
pCh->portRTP.chLinkInfo.toRTPCh.isUpdate = 0;
pCh->portRTP.chLinkInfo.fromRTPCh.isUpdate = 0;
pCh->portRTP.chLinkInfo.stunTags = stun_tags;
pCh->portRTP.chStatus = CH_STATUS_LINKED;
pCh->sipDebug.cnt_ethx_recv = 0;
pCh->sipDebug.cnt_ethx_2_eth0 = 0;
pCh->sipDebug.mask_ethx_2_eth0 = 0;
pCh->sipDebug.ethx_seq_index = 0;
pCh->sipDebug.ethx_seq_error = 0;
return 0;
}
EXPORT_SYMBOL(eth_sip_link);
int eth_link(unsigned int chId, PORT_TYPE portType,
__be32 dst_ipAddr,
__be16 dst_ipPort)
{
PSIP_CH_DETIAL pCh = NULL;
unsigned char macAddr[24];
if(g_SIPChInfo.pSipChDetial == NULL || chId >= g_SIPChInfo.iTotalCh)
{
return -1;
}
pCh = &g_SIPChInfo.pSipChDetial[chId];
if(g_NICInfo[pCh->sipETHId] == NULL)
{
return -2;
}
if(g_NICInfo[pCh->sipETHId]->opened_ref == 0)
{
return -3;
}
make_arp_request(g_spbxNetId, htonl(dst_ipAddr));
get_mac_form_ip(macAddr, g_spbxNetId, htonl(dst_ipAddr), 20);
if(portType == PORT_TYPE_B2B)
{
memset(pCh->portB2B.chLinkInfo.dstTarget.ethAddr, 0xFF, ETH_ALEN);
pCh->portB2B.chLinkInfo.dstTarget.ipAddr = dst_ipAddr;
pCh->portB2B.chLinkInfo.dstTarget.ipPort = dst_ipPort;
pCh->portB2B.chLinkInfo.toRTPCh.isUpdate = 0;
pCh->portB2B.chLinkInfo.fromRTPCh.isUpdate = 0;
pCh->portB2B.chStatus = CH_STATUS_LINKED;
}
else if(portType == PORT_TYPE_IPR)
{
memset(pCh->portIPR.chLinkInfo.dstTarget.ethAddr, 0xFF, ETH_ALEN);
pCh->portIPR.chLinkInfo.dstTarget.ipAddr = dst_ipAddr;
pCh->portIPR.chLinkInfo.dstTarget.ipPort = dst_ipPort;
pCh->portIPR.chLinkInfo.toRTPCh.isUpdate = 0;
pCh->portIPR.chLinkInfo.fromRTPCh.isUpdate = 0;
pCh->portIPR.chStatus = CH_STATUS_LINKED;
}
else if(portType == PORT_TYPE_T38)
{
memset(pCh->portT38.chLinkInfo.dstTarget.ethAddr, 0xFF, ETH_ALEN);
pCh->portT38.chLinkInfo.dstTarget.ipAddr = dst_ipAddr;
pCh->portT38.chLinkInfo.dstTarget.ipPort = dst_ipPort;
pCh->portT38.chLinkInfo.toRTPCh.isUpdate = 0;
pCh->portT38.chLinkInfo.fromRTPCh.isUpdate = 0;
pCh->portT38.chStatus = CH_STATUS_LINKED;
}
kfifo_reset(&pCh->dtmfSendFifo);
kfifo_reset(&pCh->dtmfRecvFifo);
InitChDTMFInfo(&pCh->rfc2833DTMF);
pCh->sipDebug.cnt_eth0_2_ethx = 0;
pCh->sipDebug.cnt_eth0_recv = 0;
pCh->sipDebug.mask_eth0_2_ethx = 0;
pCh->sipDebug.eth0_seq_index = 0;
pCh->sipDebug.eth0_seq_error = 0;
return 0;
}
EXPORT_SYMBOL(eth_link);
static void InitSIPLinkReset(PCH_PORT_INFO pPort)
{
if(pPort)
{
pPort->chStatus = CH_STATUS_IDLE;
pPort->chLinkInfo.linkCh = -1;
InitIPAddrInfo(&pPort->chLinkInfo.dstTarget);
pPort->chLinkInfo.fromRTPCh.isUpdate = 0;
pPort->chLinkInfo.toRTPCh.isUpdate = 0;
pPort->chLinkInfo.stunTags = 0;
memset(&pPort->chLinkInfo.fromRTPCh.headValue, 0, sizeof(PACKAGE_HEAD));
memset(&pPort->chLinkInfo.toRTPCh.headValue, 0, sizeof(PACKAGE_HEAD));
memset(pPort->chLinkInfo.dstTarget.ethAddr, 0xFF, 6);
}
}
int eth_unlink(unsigned int chId, int portType)
{
PSIP_CH_DETIAL pCh = NULL;
if(g_SIPChInfo.pSipChDetial == NULL || chId >= g_SIPChInfo.iTotalCh)
{
return -1;
}
pCh = &g_SIPChInfo.pSipChDetial[chId];
switch(portType)
{
case PORT_TYPE_IPR:
if(pCh->portIPR.chStatus == CH_STATUS_LINKED)
{
InitSIPLinkReset(&pCh->portIPR);
}
break;
case PORT_TYPE_B2B:
if(pCh->portB2B.chStatus == CH_STATUS_LINKED)
{
InitSIPLinkReset(&pCh->portB2B);
}
break;
case PORT_TYPE_T38:
if(pCh->portT38.chStatus == CH_STATUS_LINKED)
{
InitSIPLinkReset(&pCh->portT38);
}
break;
case PORT_TYPE_SIPRTP:
if(pCh->portRTP.chStatus == CH_STATUS_LINKED)
{
InitSIPLinkReset(&pCh->portRTP);
}
break;
}
kfifo_reset(&pCh->dtmfSendFifo);
kfifo_reset(&pCh->dtmfRecvFifo);
InitChDTMFInfo(&pCh->rfc2833DTMF);
return 0;
}
EXPORT_SYMBOL(eth_unlink);
int sip_recv_dtmf(unsigned int sipCh)
{
char value = -1, rlt = 0;
PSIP_CH_DETIAL pCh = NULL;
if(g_SIPChInfo.pSipChDetial == NULL || sipCh >= g_SIPChInfo.iTotalCh)
{
return -1;
}
pCh = &g_SIPChInfo.pSipChDetial[sipCh];
if(pCh->portRTP.chStatus != CH_STATUS_LINKED)
{
return -1;
}
#ifdef PLATFORM_MV78460
rlt = kfifo_get(&pCh->dtmfRecvFifo, &value);
if(rlt != 0)
#else
rlt = kfifo_out(&pCh->dtmfRecvFifo, &value, 4);
if(rlt == 4)
#endif
{
if(g_CheckRFC2833)
{
if(pCh->rfc2833DTMF.drvRfc2833ChkVal != value)
{
pCh->sipDebug.drv_rcv_rfc2833_error++;
if(sipCh == 0 && g_DebugRFC2833 != 0)
{
printk("ch %d rcv 2833 Error: rcv %d need %d\n",
sipCh,
value, pCh->rfc2833DTMF.drvRfc2833ChkVal);
}
}
if(value == 11)
{
pCh->rfc2833DTMF.drvRfc2833ChkVal = 0;
}
else
{
pCh->rfc2833DTMF.drvRfc2833ChkVal++;
}
}
pCh->sipDebug.drv_rcv_rfc2833_recv++;
return (int)g_DTMFTable[value & 0x0F];
}
else
{
return -1;
}
}
EXPORT_SYMBOL(sip_recv_dtmf);
int sip_send_dtmf(unsigned int sipCh, char* pDtmfChar, int numChars)
{
int i = 0;
PSIP_CH_DETIAL pCh = NULL;
if(g_SIPChInfo.pSipChDetial == NULL || sipCh >= g_SIPChInfo.iTotalCh
|| numChars > MAX_DTMF_SEND_BUF)
{
return -1;
}
if(pDtmfChar == NULL)
{
if(kfifo_is_empty(&pCh->dtmfSendFifo))
{
return 0;
}
else
{
return kfifo_len(&pCh->dtmfSendFifo);
}
}
pCh = &g_SIPChInfo.pSipChDetial[sipCh];
pCh->rfc2833DTMF.dtmfSendBuf.refStatus = RFC2833_SEND_IDLE;
//kfifo_reset(&pCh->dtmfSendFifo);
// GetDTMFValue
for(i = 0; i < numChars; i++)
{
char dtmf = GetDTMFValue(pDtmfChar[i]);
#ifdef PLATFORM_MV78460
if(kfifo_put(&pCh->dtmfSendFifo, &dtmf) == 0)
#else
if(kfifo_in(&pCh->dtmfSendFifo, &dtmf, 1) != 1)
#endif
{
pCh->sipDebug.ethx_rfc2833_snd_lost++;
return -1;
}
}
return i;
}
EXPORT_SYMBOL(sip_send_dtmf);
static int recv_dtmf_from_sip(int sipCh, struct sk_buff* skb)
{
unsigned short seqNumber;
unsigned int timeStamp, syncId;
unsigned char dtmfIndex;
unsigned char endFlag;
int i = 0;
int bRecved = RECV_RFC2833_RECV_UNRECV;
struct iphdr* iphdr = (struct iphdr*)skb->data;
struct udphdr* udphdr = (struct udphdr*)(skb->data + iphdr->ihl * 4);
PSIP_CH_DETIAL pCh = g_SIPChInfo.pSipChDetial + sipCh;
if(pCh->portRTP.chLinkInfo.stunTags != 0)
{
dtmfIndex = *(unsigned char*)(skb->data + 40 + 4);
endFlag = *(unsigned char*)(skb->data + 41 + 4);
seqNumber = ntohs(*(unsigned short*)(skb->data + 30 + 4));
timeStamp = ntohl(*(unsigned int*)(skb->data + 32 + 4));
syncId = ntohl(*(unsigned int*)(skb->data + 36 + 4));
}
else
{
dtmfIndex = *(unsigned char*)(skb->data + 40);
endFlag = *(unsigned char*)(skb->data + 41);
seqNumber = ntohs(*(unsigned short*)(skb->data + 30));
timeStamp = ntohl(*(unsigned int*)(skb->data + 32));
syncId = ntohl(*(unsigned int*)(skb->data + 36));
}
// ?????RFC2833
for(i = 0; i < MAX_DTMF_RECV_BUF; i++)
{
if(pCh->rfc2833DTMF.dtmfRecvBuf[i].refStatus != RFC2833_RECV_IDLE
&& pCh->rfc2833DTMF.dtmfRecvBuf[i].seqNumber != 0)
{
if(pCh->rfc2833DTMF.dtmfRecvBuf[i].seqNumber + 1000 < seqNumber
|| (endFlag & 0x80))
{
InitChDTMFRecvInfoBuf(&pCh->rfc2833DTMF, i);
}
}
// <20>յ<EFBFBD><D5B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǵ<EFBFBD><C7B5><EFBFBD><EFBFBD><EFBFBD>
if(pCh->rfc2833DTMF.dtmfRecvBuf[i].synIdentifier == syncId
&& (endFlag & 0x80))
{
InitChDTMFRecvInfoBuf(&pCh->rfc2833DTMF, i);
return RECV_RFC2833_RECV_DROP;
}
}
for(i = 0; i < MAX_DTMF_RECV_BUF; i++)
{
// ͬһ<CDAC><D2BB>DTMF
if(pCh->rfc2833DTMF.dtmfRecvBuf[i].synIdentifier == syncId
&& pCh->rfc2833DTMF.dtmfRecvBuf[i].timeStamps == timeStamp
&& abs(seqNumber - pCh->rfc2833DTMF.dtmfRecvBuf[i].seqNumber) < 100
)
{
if(pCh->rfc2833DTMF.dtmfRecvBuf[i].refStatus == RFC2833_RECVING)
{
if(pCh->rfc2833DTMF.dtmfRecvBuf[i].dtmfValue == dtmfIndex)
{
pCh->rfc2833DTMF.dtmfRecvBuf[i].seqNumber = seqNumber;
pCh->rfc2833DTMF.dtmfRecvBuf[i].refCount++;
bRecved = RECV_RFC2833_RECV_REP;
if((pCh->rfc2833DTMF.dtmfRecvBuf[i].refCount >= 2)
&& (pCh->rfc2833DTMF.dtmfRecvBuf[i].refStatus != RFC2833_RECV_LOCK))
{
#ifdef PLATFORM_MV78460
if(kfifo_put(&pCh->dtmfRecvFifo, &dtmfIndex) == 0)
#else
if(kfifo_in(&pCh->dtmfRecvFifo, &dtmfIndex, 4) != 4)
#endif
{
printk("ch %d RFC2833 FIFO Full, lost dtmf %c(%d)\n",
sipCh, g_DTMFTable[dtmfIndex], dtmfIndex);
pCh->sipDebug.ethx_rfc2833_rcv_lost++;
}
pCh->rfc2833DTMF.dtmfRecvBuf[i].refStatus = RFC2833_RECV_LOCK;
pCh->sipDebug.ethx_rfc2833_recv++;
if(sipCh == 0 && g_DebugRFC2833 != 0)
{
printk("ch %d recv rfc2833 %c(%d) ssrc = 0x%08X time = 0x%08X seq = %d \
ip = 0x%08X, Port = %d, dstip = 0x%08X, dstPort = %d, len = %d \
link_ip = 0x%08X, link_port = %d\n",
sipCh, g_DTMFTable[dtmfIndex], dtmfIndex,
syncId, timeStamp, seqNumber,
iphdr->saddr, udphdr->source,
iphdr->daddr, udphdr->dest, iphdr->tot_len,
pCh->portRTP.chLinkInfo.dstTarget.ipAddr,
pCh->portRTP.chLinkInfo.dstTarget.ipPort);
}
if(g_CheckRFC2833)
{
if(pCh->rfc2833DTMF.nicRfc2833ChkVal != dtmfIndex)
{
pCh->sipDebug.ethx_rfc2833_error++;
if(sipCh == 0 && g_DebugRFC2833 != 0)
{
printk("ch %d array %d rcv 2833 Error: rcv %d need %d, \
ip = 0x%08X, Port = %d, srcip = 0x%08X, srcPort = %d, \
link_ip = 0x%08X, link_port = %d\
ssrc = 0x%08X time = 0x%08X seq = %d\n",
sipCh,
i,
dtmfIndex,
pCh->rfc2833DTMF.nicRfc2833ChkVal,
iphdr->saddr, udphdr->source,
pCh->rfc2833DTMF.srcIp,
pCh->rfc2833DTMF.srcPort,
pCh->portRTP.chLinkInfo.dstTarget.ipAddr,
pCh->portRTP.chLinkInfo.dstTarget.ipPort,
syncId, timeStamp, seqNumber);
}
}
if(pCh->rfc2833DTMF.nicRfc2833ChkVal == 11)
{
pCh->rfc2833DTMF.nicRfc2833ChkVal = 0;
}
else
{
pCh->rfc2833DTMF.nicRfc2833ChkVal++;
}
}
}
}
else
{
bRecved = RECV_RFC2833_RECV_DROP;
}
}
else
{
bRecved = RECV_RFC2833_RECV_DROP;
}
break;
}
}
if(bRecved == RECV_RFC2833_RECV_UNRECV)
{
for(i = 0; i < MAX_DTMF_RECV_BUF; i++)
{
if(pCh->rfc2833DTMF.dtmfRecvBuf[i].refStatus == RFC2833_RECV_IDLE
&& (endFlag & 0x80) == 0)
{
InitChDTMFRecvInfoBuf(&pCh->rfc2833DTMF, i);
pCh->rfc2833DTMF.dtmfRecvBuf[i].seqNumber = seqNumber;
pCh->rfc2833DTMF.dtmfRecvBuf[i].synIdentifier = syncId;
pCh->rfc2833DTMF.dtmfRecvBuf[i].timeStamps = timeStamp;
pCh->rfc2833DTMF.srcIp = iphdr->saddr;
pCh->rfc2833DTMF.srcPort = udphdr->source;
pCh->rfc2833DTMF.dtmfRecvBuf[i].dtmfValue = dtmfIndex;
pCh->rfc2833DTMF.dtmfRecvBuf[i].refCount = 1;
pCh->rfc2833DTMF.dtmfRecvBuf[i].refStatus = RFC2833_RECVING;
bRecved = RECV_RFC2833_RECV_NEW;
break;
}
}
}
return bRecved;
}
static int CheckMacAddress(PCH_PORT_INFO pPort, ETH_INTERFACE ethId)
{
if(pPort->chLinkInfo.dstTarget.ethAddr[0] == 0xFF
&& pPort->chLinkInfo.dstTarget.ethAddr[1] == 0xFF
&& pPort->chLinkInfo.dstTarget.ethAddr[2] == 0xFF
&& pPort->chLinkInfo.dstTarget.ethAddr[3] == 0xFF
&& pPort->chLinkInfo.dstTarget.ethAddr[4] == 0xFF
&& pPort->chLinkInfo.dstTarget.ethAddr[5] == 0xFF
)
{
return get_mac_form_ip(pPort->chLinkInfo.dstTarget.ethAddr,
ethId,
htonl(pPort->chLinkInfo.dstTarget.ipAddr), 30);
}
return 0;
}
static struct sk_buff* switch_to_sip(int sipCh,
struct sk_buff* skb,
ETH_INTERFACE ethId,
PCH_PORT_INFO pPort)
{
PPACKAGE_HEAD pHead = NULL;
PRFC2833_INFO pDTMF = NULL;
unsigned char* pPayload = NULL;
PSIP_CH_DETIAL pCh = &g_SIPChInfo.pSipChDetial[sipCh];
struct sk_buff* skbSIP = skb_clone(skb, GFP_ATOMIC);
PNIC_PRIVATE pEthInfo = g_NICInfo[ethId];
if(skbSIP == NULL)
{
return NULL;
}
dev_kfree_skb_any(skb);
skbSIP->dev = pEthInfo->ndev;
eth_header(skbSIP, pEthInfo->ndev, ETH_P_IP, NULL, NULL, skbSIP->len);
pHead = (PPACKAGE_HEAD)skbSIP->data;
if(pPort->chLinkInfo.toRTPCh.isUpdate == 0)
{
if(pPort->chLinkInfo.dstTarget.ethAddr[0] == 0xFF
&& pPort->chLinkInfo.dstTarget.ethAddr[1] == 0xFF
&& pPort->chLinkInfo.dstTarget.ethAddr[2] == 0xFF
&& pPort->chLinkInfo.dstTarget.ethAddr[3] == 0xFF
&& pPort->chLinkInfo.dstTarget.ethAddr[4] == 0xFF
&& pPort->chLinkInfo.dstTarget.ethAddr[5] == 0xFF
)
{
get_mac_form_ip(pPort->chLinkInfo.dstTarget.ethAddr,
ethId,
htonl(pPort->chLinkInfo.dstTarget.ipAddr), 5);
}
memcpy(pHead->ethHead.h_dest,
pPort->chLinkInfo.dstTarget.ethAddr, ETH_ALEN);
pHead->ipHead.saddr = htonl(pEthInfo->chIpAddr);
pHead->ipHead.daddr = htonl(pPort->chLinkInfo.dstTarget.ipAddr);
pHead->udpHead.source = htons(g_SIPChInfo.iRTPPortBase + sipCh);
pHead->udpHead.dest = htons(pPort->chLinkInfo.dstTarget.ipPort);
memcpy(&pPort->chLinkInfo.toRTPCh.headValue,
pHead,
sizeof(PACKAGE_HEAD));
pPort->chLinkInfo.toRTPCh.isUpdate = 1;
}
else
{
PACKAGE_HEAD ipHead = *pHead;
if((pPort->chLinkInfo.dstTarget.ethAddr[0] == 0xFF
&& pPort->chLinkInfo.dstTarget.ethAddr[1] == 0xFF
&& pPort->chLinkInfo.dstTarget.ethAddr[2] == 0xFF
&& pPort->chLinkInfo.dstTarget.ethAddr[3] == 0xFF
&& pPort->chLinkInfo.dstTarget.ethAddr[4] == 0xFF
&& pPort->chLinkInfo.dstTarget.ethAddr[5] == 0xFF)
|| pCh->sipDebug.cnt_eth0_2_ethx % 1000 == 0
)
{
if(get_mac_form_ip(pPort->chLinkInfo.dstTarget.ethAddr,
ethId,
htonl(pPort->chLinkInfo.dstTarget.ipAddr), 6) == 0)
{
memcpy(&pPort->chLinkInfo.toRTPCh.headValue,
pPort->chLinkInfo.dstTarget.ethAddr,
ETH_ALEN);
}
}
memcpy(pHead,
&pPort->chLinkInfo.toRTPCh.headValue,
sizeof(PACKAGE_HEAD));
pHead->ipHead.id = ipHead.ipHead.id;
pHead->ipHead.frag_off = ipHead.ipHead.frag_off;
pHead->ipHead.tot_len = ipHead.ipHead.tot_len;
pHead->udpHead.len = ipHead.udpHead.len;
}
if(!kfifo_is_empty(&pCh->dtmfSendFifo))
{
if(pCh->rfc2833DTMF.dtmfSendBuf.refStatus == RFC2833_SEND_IDLE)
{
#ifdef PLATFORM_MV78460
int rlt = kfifo_get(&pCh->dtmfSendFifo,
&pCh->rfc2833DTMF.dtmfSendBuf.dtmfValue);
if(rlt != 0)
#else
int rlt = kfifo_out(&pCh->dtmfSendFifo,
&pCh->rfc2833DTMF.dtmfSendBuf.dtmfValue, 1);
if(rlt == 1)
#endif
{
pCh->rfc2833DTMF.dtmfSendBuf.synIdentifier = 0;
pCh->rfc2833DTMF.dtmfSendBuf.timeStamps = 0;
pCh->rfc2833DTMF.dtmfSendBuf.refCount = 7;
pCh->rfc2833DTMF.dtmfSendBuf.payloadType = 101;
pCh->rfc2833DTMF.dtmfSendBuf.refStatus = RFC2833_SEND_BEGING;
}
}
}
if(pCh->rfc2833DTMF.dtmfSendBuf.refStatus != RFC2833_SEND_IDLE)
{
pDTMF = &pCh->rfc2833DTMF.dtmfSendBuf;
pPayload = (unsigned char*)(skbSIP->data + 42);
pHead->udpHead.len = htons(24);
pHead->udpHead.check = 0;
pHead->ipHead.tot_len = htons(44);
pPayload[1] = 101;
if(pDTMF->refCount == 7)
{
pPayload[1] |= 1 << 7;
pDTMF->timeStamps = *(int*)(&pPayload[4]);
}
memcpy(&pPayload[4], &pDTMF->timeStamps, 4);
pPayload[12] = pDTMF->dtmfValue;
pPayload[13] = 0x0a;
if(pDTMF->refCount <= 3)
{
pPayload[13] |= 1 << 7;
pPayload[2] = (pCh->rfc2833DTMF.dtmfSendBuf.seqNumber + 1) >> 8;
pPayload[3] = (pCh->rfc2833DTMF.dtmfSendBuf.seqNumber + 1) & 0xFF;
pPayload[14] = ((8 - 3) * 80) >> 8;
pPayload[15] = ((8 - 3) * 80) & 0xFF;
}
else
{
pCh->rfc2833DTMF.dtmfSendBuf.seqNumber = ntohs(*(unsigned short*)(&pPayload[2]));
pPayload[14] = ((8 - pDTMF->refCount) * 80) >> 8;
pPayload[15] = ((8 - pDTMF->refCount) * 80) & 0xFF;
}
// pskb_trim(skbSIP, skbSIP->len - 76);
pskb_trim(skbSIP, 58);
pDTMF->refCount--;
if(pDTMF->refCount > 0)
{
pDTMF->refStatus = RFC2833_SENDING;
}
else
{
pDTMF->refStatus = RFC2833_SEND_IDLE;
if(pCh->rfc2833DTMF.refSendMask > 0)
{
pCh->rfc2833DTMF.refSendMask &= ~(pCh->rfc2833DTMF.curSendIndex << 1);
}
pCh->rfc2833DTMF.refSendMask = 0;
}
}
if(pCh->portRTP.chLinkInfo.stunTags != 0)
{
unsigned short* pTags = NULL;
skb_push(skbSIP, 4);
memmove(skbSIP->data, pHead, 42);
pHead = (PPACKAGE_HEAD)skbSIP->data;
pTags = (unsigned short*)(skbSIP->data + 42);
*pTags = htons(pCh->portRTP.chLinkInfo.stunTags);
pTags++;
*pTags = htons(pHead->udpHead.len - 8);
pHead->udpHead.len += htons(4);
pHead->ipHead.tot_len += htons(4);
}
pHead->udpHead.check = 0;
pHead->ipHead.check = 0;
pHead->ipHead.check =
get_ip_checksum((unsigned short*)&pHead->ipHead, 20);
if(eth_tx_skb(skbSIP, pEthInfo->ndev) == NETDEV_TX_OK)
{
pCh->sipDebug.cnt_eth0_2_ethx++;
}
return skbSIP;
}
static struct sk_buff* switch_from_sip(int sipCh,
struct sk_buff* skb,
PCH_PORT_INFO pPort)
{
PPACKAGE_HEAD pHead = NULL;
struct sk_buff* skbSIP = skb_clone(skb, GFP_ATOMIC);
PNIC_PRIVATE pEthInfo = g_NICInfo[g_spbxNetId];
PSIP_CH_DETIAL pCh = &g_SIPChInfo.pSipChDetial[sipCh];
if(skbSIP == NULL)
{
return NULL;
}
dev_kfree_skb_any(skb);
skbSIP->dev = pEthInfo->ndev;
eth_header(skbSIP, pEthInfo->ndev, ETH_P_IP, NULL, NULL, skb->len);
pHead = (PPACKAGE_HEAD)skbSIP->data;
if(pPort->chLinkInfo.fromRTPCh.isUpdate == 0)
{
if(pPort->chLinkInfo.dstTarget.ethAddr[0] == 0xFF
&& pPort->chLinkInfo.dstTarget.ethAddr[1] == 0xFF
&& pPort->chLinkInfo.dstTarget.ethAddr[2] == 0xFF
&& pPort->chLinkInfo.dstTarget.ethAddr[3] == 0xFF
&& pPort->chLinkInfo.dstTarget.ethAddr[4] == 0xFF
&& pPort->chLinkInfo.dstTarget.ethAddr[5] == 0xFF
)
{
get_mac_form_ip(pPort->chLinkInfo.dstTarget.ethAddr,
g_spbxNetId,
htonl(pPort->chLinkInfo.dstTarget.ipAddr), 7);
}
memcpy(pHead->ethHead.h_dest,
pPort->chLinkInfo.dstTarget.ethAddr, ETH_ALEN);
pHead->ipHead.saddr = htonl(pEthInfo->chIpAddr);
pHead->ipHead.daddr = htonl(pPort->chLinkInfo.dstTarget.ipAddr);
pHead->udpHead.source = htons(pPort->ipPort);
pHead->udpHead.dest = htons(pPort->chLinkInfo.dstTarget.ipPort);
memcpy(&pPort->chLinkInfo.fromRTPCh.headValue,
pHead,
sizeof(PACKAGE_HEAD));
pPort->chLinkInfo.fromRTPCh.isUpdate = 1;
}
else
{
PACKAGE_HEAD ipHead = *pHead;
if((pPort->chLinkInfo.dstTarget.ethAddr[0] == 0xFF
&& pPort->chLinkInfo.dstTarget.ethAddr[1] == 0xFF
&& pPort->chLinkInfo.dstTarget.ethAddr[2] == 0xFF
&& pPort->chLinkInfo.dstTarget.ethAddr[3] == 0xFF
&& pPort->chLinkInfo.dstTarget.ethAddr[4] == 0xFF
&& pPort->chLinkInfo.dstTarget.ethAddr[5] == 0xFF)
|| pCh->sipDebug.cnt_ethx_2_eth0 % 1000 == 0
)
{
if(get_mac_form_ip(pPort->chLinkInfo.dstTarget.ethAddr,
g_spbxNetId,
htonl(pPort->chLinkInfo.dstTarget.ipAddr), 8) == 0)
{
memcpy(&pPort->chLinkInfo.fromRTPCh.headValue,
pPort->chLinkInfo.dstTarget.ethAddr,
ETH_ALEN);
}
}
memcpy(pHead,
&pPort->chLinkInfo.fromRTPCh.headValue,
sizeof(PACKAGE_HEAD));
pHead->ipHead.id = ipHead.ipHead.id;
pHead->ipHead.frag_off = ipHead.ipHead.frag_off;
pHead->ipHead.tot_len = ipHead.ipHead.tot_len;
pHead->udpHead.len = ipHead.udpHead.len;
}
if(pCh->portRTP.chLinkInfo.stunTags != 0)
{
unsigned short* pTags = (unsigned short*)(skbSIP->data + 42);
unsigned short* pLen = (unsigned short*)(skbSIP->data + 44);
if(*pTags == pCh->portRTP.chLinkInfo.stunTags
&& *pLen == pHead->udpHead.len - 12)
{
memcpy(&skbSIP->data[42], &skbSIP->data[46], *pLen);
pskb_trim(skbSIP, skbSIP->len - 4);
pHead->udpHead.len -= 4;
pHead->ipHead.tot_len -= 4;
}
}
pHead->udpHead.check = 0;
pHead->ipHead.check = 0;
pHead->ipHead.check =
get_ip_checksum((unsigned short*)&pHead->ipHead, 20);
if(eth_tx_skb(skbSIP, pEthInfo->ndev) == NETDEV_TX_OK)
{
pCh->sipDebug.cnt_ethx_2_eth0++;
}
return skbSIP;
}
//static int ipstack_hook_udp_recv_sip(struct sk_buff* skb, int* rlt)
static int ipstack_hook_udp_recv_sip(struct sk_buff* skb, PNIC_PRIVATE pp)
{
unsigned char dtmfIndex;
struct iphdr* iphdr = (struct iphdr*)skb->data;
struct udphdr* udphdr = (struct udphdr*)(skb->data + iphdr->ihl * 4);
char payloadType = 0;// *(char*)(skb->data + 29) & 0x7F;
PNIC_PRIVATE pEthInfo = g_NICInfo[g_spbxNetId];
int ucc = pp->port;
struct sk_buff* skbSIP;
unsigned short seq_index = ntohs(*(unsigned short*)&skb->data[RECV_SEQ_POS]);
unsigned char* pUdpData = (unsigned char*)(skb->data + 28);
int udp_len = ntohs(udphdr->len);
int sipCh;
// stun package
if((pUdpData[0] & 0xC0) == 0
&& pUdpData[4] == 0x21
&& pUdpData[5] == 0x12
&& pUdpData[6] == 0xA4
&& pUdpData[7] == 0x42)
{
return 0;
}
// not this nic package
if(ntohl(iphdr->daddr) != g_NICInfo[ucc]->chIpAddr)
{
return 0;
}
sipCh = (ntohs(udphdr->dest) - g_SIPChInfo.iRTPPortBase);
// SPI Ch Package
if(sipCh >= 0 && sipCh < g_SIPChInfo.iTotalCh)
{
PSIP_CH_DETIAL pCh = g_SIPChInfo.pSipChDetial + sipCh;
pCh->sipDebug.cnt_ethx_recv++;
if(pCh->sipDebug.ethx_seq_index == 0
|| pCh->sipDebug.ethx_seq_index == 0xFFFF)
{
pCh->sipDebug.ethx_seq_index = seq_index;
}
else
{
if(pCh->sipDebug.ethx_seq_index != seq_index - 1)
{
pCh->sipDebug.ethx_seq_error++;
}
pCh->sipDebug.ethx_seq_index = seq_index;
}
pCh->sipDebug.mask_ethx_2_eth0 = CHK_CH_RECVUDP;
if(pCh->portRTP.chStatus != CH_STATUS_LINKED)
{
dev_kfree_skb_any(skb);
return udp_len;
}
if(pCh->portRTP.chLinkInfo.dstTarget.ipAddr != ntohl(iphdr->saddr)
|| pCh->portRTP.chLinkInfo.dstTarget.ipPort != ntohs(udphdr->source))
{
pCh->sipDebug.ethx_drop_src++;
dev_kfree_skb_any(skb);
return udp_len;
}
if(pCh->portRTP.chLinkInfo.stunTags != 0)
{
payloadType = *(char*)(skb->data + 29 + 4) & 0x7F;
dtmfIndex = *(unsigned char*)(skb->data + 40 + 4);
}
else
{
payloadType = *(char*)(skb->data + 29) & 0x7F;
dtmfIndex = *(unsigned char*)(skb->data + 40);
}
if(payloadType >= 96 && dtmfIndex < 17) // RFC2833 DTMF
{
recv_dtmf_from_sip(sipCh, skb);
pCh->sipDebug.mask_ethx_2_eth0 |= CHK_CH_RFC2833;
dev_kfree_skb_any(skb);
return udp_len;
}
else
{
if(pCh->portT38.chStatus == CH_STATUS_LINKED)
{
pCh->sipDebug.mask_ethx_2_eth0 |= CHK_CH_STATUS | CHK_CH_NEEDSWITCH;
if(CheckMacAddress(&pCh->portT38, g_spbxNetId) == -1)
{
pCh->sipDebug.mask_ethx_2_eth0 |= CHK_CH_DROP_WAITARP;
dev_kfree_skb_any(skb);
return udp_len;
}
skbSIP = switch_from_sip(sipCh, skb, &pCh->portT38);
if(skbSIP != NULL)
{
pCh->sipDebug.mask_ethx_2_eth0 |= CHK_CH_SWITCH_OK;
//*rlt = 1;
}
else
{
pCh->sipDebug.mask_ethx_2_eth0 |= CHK_CH_SWITCH_ERR;
}
return udp_len;
}
else
{
if(pCh->portB2B.chStatus == CH_STATUS_LINKED)
{
pCh->sipDebug.mask_ethx_2_eth0 |= CHK_CH_STATUS;
if(pCh->portB2B.chLinkInfo.dstTarget.ipAddr == pEthInfo->chIpAddr)
{
int b2bCh = (pCh->portB2B.chLinkInfo.dstTarget.ipPort
- g_SIPChInfo.iPortBase) / g_SIPChInfo.iPortStep;
pCh->sipDebug.mask_eth0_2_ethx |= CHK_CH_NEEDSWITCH_SAMEBOARD;
if(b2bCh >= 0 && b2bCh <= g_SIPChInfo.iTotalCh)
{
PSIP_CH_DETIAL pB2BCh = g_SIPChInfo.pSipChDetial + b2bCh;
if(pB2BCh->portB2B.chStatus == CH_STATUS_LINKED)
{
if(CheckMacAddress(&pB2BCh->portRTP, pB2BCh->sipETHId) == -1)
{
pCh->sipDebug.mask_ethx_2_eth0 |= CHK_CH_DROP_WAITARP;
dev_kfree_skb_any(skb);
return udphdr->len;
}
skbSIP = switch_to_sip(b2bCh, skb, pB2BCh->sipETHId,
&pB2BCh->portRTP);
if(skbSIP != NULL)
{
pCh->sipDebug.mask_ethx_2_eth0 |= CHK_CH_SWITCH_OK;
//*rlt = 1;
}
else
{
pCh->sipDebug.mask_ethx_2_eth0 |= CHK_CH_SWITCH_ERR;
}
return udp_len;
}
}
}
else
{
pCh->sipDebug.mask_ethx_2_eth0 |= CHK_CH_STATUS | CHK_CH_NEEDSWITCH;
if(CheckMacAddress(&pCh->portB2B, g_spbxNetId) == -1)
{
pCh->sipDebug.mask_ethx_2_eth0 |= CHK_CH_DROP_WAITARP;
dev_kfree_skb_any(skb);
return udp_len;
}
//
skbSIP = switch_from_sip(sipCh, skb, &pCh->portB2B);
if(skbSIP != NULL)
{
pCh->sipDebug.mask_ethx_2_eth0 |= CHK_CH_SWITCH_OK;
//*rlt = 1;
}
else
{
pCh->sipDebug.mask_ethx_2_eth0 |= CHK_CH_SWITCH_ERR;
}
return udp_len;
}
}
if(pCh->portIPR.chStatus == CH_STATUS_LINKED)
{
pCh->sipDebug.mask_ethx_2_eth0 |= CHK_CH_STATUS | CHK_CH_NEEDSWITCH;
if(CheckMacAddress(&pCh->portIPR, g_spbxNetId) == -1)
{
pCh->sipDebug.mask_ethx_2_eth0 |= CHK_CH_DROP_WAITARP;
dev_kfree_skb_any(skb);
return udp_len;
}
skbSIP = switch_from_sip(sipCh, skb, &pCh->portIPR);
if(skbSIP != NULL)
{
pCh->sipDebug.mask_ethx_2_eth0 |= CHK_CH_SWITCH_OK;
//*rlt = 1;
}
else
{
pCh->sipDebug.mask_ethx_2_eth0 |= CHK_CH_SWITCH_ERR;
}
return udp_len;
}
}
}
}
return 0;
}
static int ipstack_hook_udp_recv_spbx(struct sk_buff* skb, PNIC_PRIVATE pp)
{
int ret = 0;
struct iphdr* iphdr = (struct iphdr*)skb->data;
struct udphdr* udphdr = (struct udphdr*)(skb->data + iphdr->ihl * 4);
unsigned char* pUdpData = (unsigned char*)(skb->data + 28);
unsigned short seq_index = ntohs(*(unsigned short*)&skb->data[RECV_SEQ_POS]);
struct sk_buff* skbSIP;
int udp_len = ntohs(udphdr->len);
int sipCh;
// stun package
if((pUdpData[0] & 0xC0) == 0
&& pUdpData[4] == 0x21
&& pUdpData[5] == 0x12
&& pUdpData[6] == 0xA4
&& pUdpData[7] == 0x42)
{
return 0;
}
// not this nic package
if(ntohl(iphdr->daddr) != g_NICInfo[pp->port]->chIpAddr)
{
return 0;
}
sipCh = (ntohs(udphdr->dest) - g_SIPChInfo.iPortBase) / g_SIPChInfo.iPortStep;
// SPI Ch Package
if(sipCh >= 0 && sipCh < g_SIPChInfo.iTotalCh)
{
PSIP_CH_DETIAL pCh = g_SIPChInfo.pSipChDetial + sipCh;
pCh->sipDebug.mask_eth0_2_ethx = CHK_CH_RECVUDP;
pCh->sipDebug.cnt_eth0_recv++;
if(pCh->sipDebug.eth0_seq_index == 0
|| pCh->sipDebug.ethx_seq_index == 0xFFFF)
{
pCh->sipDebug.eth0_seq_index = seq_index;
}
else
{
if(pCh->sipDebug.eth0_seq_index != seq_index - 1)
{
pCh->sipDebug.eth0_seq_error++;
}
pCh->sipDebug.eth0_seq_index = seq_index;
}
if(pCh->sipETHId == g_spbxNetId)
{
dev_kfree_skb_any(skb);
return udp_len;
}
if(pCh->portRTP.chStatus == CH_STATUS_LINKED)
{
pCh->sipDebug.mask_eth0_2_ethx |= CHK_CH_STATUS;
if(ntohl(iphdr->saddr) == pCh->portB2B.chLinkInfo.dstTarget.ipAddr
|| ntohl(iphdr->saddr) == pCh->portIPR.chLinkInfo.dstTarget.ipAddr
|| ntohl(iphdr->saddr) == pCh->portT38.chLinkInfo.dstTarget.ipAddr)
{
pCh->sipDebug.mask_eth0_2_ethx |= CHK_CH_NEEDSWITCH;
if(CheckMacAddress(&pCh->portRTP, pCh->sipETHId) == -1)
{
pCh->sipDebug.mask_eth0_2_ethx |= CHK_CH_DROP_WAITARP;
dev_kfree_skb_any(skb);
return udp_len;
}
skbSIP = switch_to_sip(sipCh, skb, pCh->sipETHId, &pCh->portRTP);
if(skbSIP != NULL)
{
pCh->sipDebug.mask_eth0_2_ethx |= CHK_CH_SWITCH_OK;
return udp_len;
}
pCh->sipDebug.mask_eth0_2_ethx |= CHK_CH_SWITCH_ERR;
}
}
}
return ret;
}
int ipstack_hook_udp_recv(struct sk_buff* skb, PNIC_PRIVATE pp)
{
struct iphdr* iphdr = (struct iphdr*)skb->data;
struct udphdr* udphdr = (struct udphdr*)(skb->data + iphdr->ihl * 4);
unsigned long flags;
int port = ntohs(udphdr->dest);
int rcvBytes = 0;
if(pp->port == g_spbxNetId)
{
if(port >= g_SIPChInfo.iPortBase &&
port < g_SIPChInfo.iPortBase +
(g_SIPChInfo.iTotalCh * g_SIPChInfo.iPortStep))
{
return ipstack_hook_udp_recv_spbx(skb, pp);
}
else if(port >= pp->rtpCfg.rtpBasePort &&
port < pp->rtpCfg.rtpBasePort +
(pp->rtpCfg.rtpCfgCh * pp->rtpCfg.rtpPortStep))
{
if(g_pRcvRtpHook != NULL)
{
int ch = (port - pp->rtpCfg.rtpBasePort) / pp->rtpCfg.rtpPortStep;
if(ch < 0 || ch >= pp->rtpCfg.rtpCfgCh)
{
return 0;
}
spin_lock_irqsave(&g_RegHookLock, flags);
rcvBytes = g_pRcvRtpHook(pp->port, ch, (unsigned char*)iphdr, iphdr->tot_len);
spin_unlock_irqrestore(&g_RegHookLock, flags);
if(rcvBytes > 0)
{
dev_kfree_skb_any(skb);
}
return rcvBytes;
}
}
}
else
{
if(ntohs(udphdr->dest) >= g_SIPChInfo.iRTPPortBase &&
ntohs(udphdr->dest) < (g_SIPChInfo.iRTPPortBase + g_SIPChInfo.iTotalCh))
{
return ipstack_hook_udp_recv_sip(skb, pp);
}
}
return 0;
}
void ipstack_hook_init(void)
{
int i;
g_SIPChInfo.iTotalCh = 0;
g_SIPChInfo.pSipChDetial = g_SIPDetial;
g_SIPChInfo.iPortBase = -1;
g_SIPChInfo.iPortStep = -1;
InitDebugInfoProc("hook_netdrv");
for(i = 0; i < sizeof(g_DbgFSConfig) / sizeof(g_DbgFSConfig[0]); i++)
{
if(DebugFsRegister(&g_DbgFSConfig[i]) != ERR_DBGFS_NO_ERROR)
{
LOG_EX(LOG_Error, "%d Regisetr %s Error\n",
i, g_DbgFSConfig[i].name);
}
}
spin_lock_init(&g_RegHookLock) ;
}
void ipstack_hook_exit(void)
{
int i;
g_SIPChInfo.iTotalCh = 0;
g_SIPChInfo.iPortBase = -1;
g_SIPChInfo.iPortStep = -1;
for(i = 0; i < sizeof(g_DbgFSConfig) / sizeof(g_DbgFSConfig[0]); i++)
{
DebugFsUnRegister(&g_DbgFSConfig[i]);
}
DeInitDebugInfoProc();
}
ETH_IRQ_MODE eth_get_irq_mode(int ethId)
{
#if defined(PLATFORM_MV78460)
struct eth_port* pp = NULL;
#elif defined(PLATFORM_P1010)
struct gfar_private* pp = NULL;
#endif
if(ethId < 0 || ethId >= MAX_ETH_PORT)
{
return IRQ_MODE_ERROR;
}
pp = GET_ETH_PRIVATE(ethId);
if(pp == NULL)
{
return IRQ_MODE_ERROR;
}
return pp->devPrivate.irqMode;
}
EXPORT_SYMBOL(eth_get_irq_mode);
const char* eth_get_irq_aliase(ETH_IRQ_MODE irqMode)
{
switch(irqMode)
{
case IRQ_MODE_1MS:
return "IRQ_MODE_1MS";
case IRQ_MODE_MAC:
return "IRQ_MODE_MAC";
default:
return "IRQ_MODE_ERROR";
}
return "IRQ_MODE_UNKNOWN";
}
EXPORT_SYMBOL(eth_get_irq_aliase);
int config_eth_rtp(int ethId,
unsigned short maxCh,
unsigned short port_base,
unsigned short port_step)
{
g_NICInfo[ethId]->rtpCfg.rtpBasePort = port_base;
g_NICInfo[ethId]->rtpCfg.rtpCfgCh = maxCh;
g_NICInfo[ethId]->rtpCfg.rtpPortStep = port_step;
}
EXPORT_SYMBOL(config_eth_rtp);
PNIC_PRIVATE eth_get_hook_info(int ethId)
{
if(ethId >= 0 && ethId <= MAX_ETH_PORT)
{
return g_NICInfo[ethId];
}
return NULL;
}
EXPORT_SYMBOL(eth_get_hook_info);
void register_rcv_rtp_hook(PNIC_RCV_RTP_DATA phook)
{
unsigned long flags;
spin_lock_irqsave(&g_RegHookLock, flags);
g_pRcvRtpHook = phook;
spin_unlock_irqrestore(&g_RegHookLock, flags);
}
EXPORT_SYMBOL(register_rcv_rtp_hook);
void unregister_rcv_rtp_hook(void)
{
unsigned long flags;
spin_lock_irqsave(&g_RegHookLock, flags);
g_pRcvRtpHook = NULL;
spin_unlock_irqrestore(&g_RegHookLock, flags);
}
EXPORT_SYMBOL(unregister_rcv_rtp_hook);
int config_eth_ipaddr(unsigned int ethId, __be32 ipaddr, __be32 gwaddr, __be32 gwmask)
{
PNIC_PRIVATE pGfar = NULL;
if(ethId < MAX_ETH_PORT)
{
pGfar = g_NICInfo[ethId];
if(pGfar == NULL)
{
return -1;
}
else
{
pGfar->chIpAddr = ipaddr;
pGfar->chGWIpAddr = gwaddr;
pGfar->chGWMask = gwmask;
if(gwaddr != 0)
{
make_arp_request(ethId, gwaddr);
}
}
}
return 0;
}
EXPORT_SYMBOL(config_eth_ipaddr);
void eth_set_hook_info(int ethId, PNIC_PRIVATE pp)
{
if(ethId >= 0 && ethId <= MAX_ETH_PORT)
{
g_NICInfo[ethId] = pp;
}
}
void eth_init_hook_info(void)
{
int i;
for(i = 0; i < MAX_ETH_PORT; i++)
{
g_NICInfo[i] = NULL;
}
}
static int DbgFS_RtpPortShow(struct seq_file* seq, void* token)
{
int i = 0;
if(token == SEQ_START_TOKEN)
{
for(i = 0; i < MAX_ETH_PORT; i++)
{
if(g_NICInfo[i])
{
seq_printf(seq, "Eth%d: Port Base = %d, Port Step = %d, CfgCh = %d\n",
i,
g_NICInfo[i]->rtpCfg.rtpBasePort,
g_NICInfo[i]->rtpCfg.rtpPortStep,
g_NICInfo[i]->rtpCfg.rtpCfgCh);
}
else
{
seq_printf(seq, "ETH%d: unused\n", i);
}
}
}
return 0;
}
static int DbgFS_NICCfgShow(struct seq_file* seq, void* token)
{
int i = 0;
if(token == SEQ_START_TOKEN)
{
for(i = 0; i < MAX_ETH_PORT; i++)
{
if(g_NICInfo[i] != NULL)
{
seq_printf(seq, "ETH%d: \n", i);
seq_printf(seq, "IP Addr : %d.%d.%d.%d\n",
(g_NICInfo[i]->chIpAddr >> 24) & 0xFF,
(g_NICInfo[i]->chIpAddr >> 16) & 0xFF,
(g_NICInfo[i]->chIpAddr >> 8) & 0xFF,
g_NICInfo[i]->chIpAddr & 0xFF);
seq_printf(seq, "GW Addr : %d.%d.%d.%d\n",
(g_NICInfo[i]->chGWIpAddr >> 24) & 0xFF,
(g_NICInfo[i]->chGWIpAddr >> 16) & 0xFF,
(g_NICInfo[i]->chGWIpAddr >> 8) & 0xFF,
g_NICInfo[i]->chGWIpAddr & 0xFF);
seq_printf(seq, "Netmask Addr : %d.%d.%d.%d\n",
(g_NICInfo[i]->chGWMask >> 24) & 0xFF,
(g_NICInfo[i]->chGWMask >> 16) & 0xFF,
(g_NICInfo[i]->chGWMask >> 8) & 0xFF,
g_NICInfo[i]->chGWMask & 0xFF);
seq_printf(seq, "Mac Addr : %02X:%02X:%02X:%02X:%02X:%02X\n",
g_NICInfo[i]->ndev->dev_addr[0],
g_NICInfo[i]->ndev->dev_addr[1],
g_NICInfo[i]->ndev->dev_addr[2],
g_NICInfo[i]->ndev->dev_addr[3],
g_NICInfo[i]->ndev->dev_addr[4],
g_NICInfo[i]->ndev->dev_addr[5]);
}
else
{
seq_printf(seq, "ETH%d: unused\n", i);
}
}
}
return 0;
}
static int DbgFS_EthIrqShow(struct seq_file* seq, void* token)
{
unsigned int eth_id = g_DbgFSConfig[DBG_ETH_IRQ].params;
if(token == SEQ_START_TOKEN)
{
if(IS_VALUABLED_ETH(eth_id))
{
ETH_IRQ_MODE irqMode = eth_get_irq_mode(eth_id);
seq_printf(seq, "ETH%d current work on %s(%d) irq mode.\n",
eth_id, (char*)eth_get_irq_aliase(irqMode), (int)irqMode);
}
else
{
seq_printf(seq, "Error eth id: %d\n", eth_id);
}
}
return 0;
}
static int DbgFS_EthIrqHelp(struct seq_file* seq, void* token)
{
printk("==============Options Helps=============\n");
printk("usage: echo \"<eth_id>\" > /proc/hook_netdrv/eth_irq\n");
printk("eth_id:\n");
printk("\t[0..%d]: Show eth0..eth:%d Current IrqMode.\n", MAX_ETH_PORT, MAX_ETH_PORT);
printk("\nusage: echo \"set <irq_mode>\" > /proc/hook_netdrv/eth_irq\n");
printk("irq_mode:\n");
printk("\t[1ms]: Set ethx receive and send used 1ms irq.\n");
printk("\t[mac]: Set ethx receive and send used chipset irq.\n");
return 0;
}
static int DbgFS_EthIrqIoctl(struct seq_file* seq, char* cmd, char* params)
{
unsigned int eth_id = g_DbgFSConfig[DBG_ETH_IRQ].params;
int ret = 0;
char tmpBuf[64];
if(!IS_VALUABLED_ETH(eth_id))
{
LOG_EX(LOG_Error, "Error: Current ETH is %d\n", eth_id);
return -ERR_PARA_OUTOFRANGE;
}
if(strcmp(cmd, "set") == 0)
{
ETH_IRQ_MODE irqMode;
ret = GetStringParamValue(params, 0, tmpBuf, 64);
if(ret != ERR_DBGFS_NO_ERROR)
{
LOG_EX(LOG_Error, "get %d params(%s) error\n", 0, params);
return -ERR_PARA_OUTOFRANGE;
}
if(strcmp(tmpBuf, "1ms") == 0)
{
ret = eth_switch_irq_to_1ms(eth_id);
irqMode = IRQ_MODE_1MS;
}
else if(strcmp(tmpBuf, "mac") == 0)
{
ret = eth_switch_irq_to_mac(eth_id);
irqMode = IRQ_MODE_MAC;
}
else
{
LOG_EX(LOG_Error, "Error IRQ_MODE(1ms/mac) (%s)\n", tmpBuf);
return 0;
}
LOG_EX((ret == 0) ? LOG_Info : LOG_Error,
"ETH%d Switch IRQ Mode To %s %s\n", eth_id,
(char*)eth_get_irq_aliase(irqMode),
(ret == 0) ? "OK" : "Error");
}
else
{
LOG_EX(LOG_Error, "Unknown command (%s)\n", cmd);
}
return 0;
}
int SetLocalNICId(int id)
{
if(id >= 0 && id < MAX_ETH_PORT)
{
g_spbxNetId = id;
return 0;
}
return -1;
}
EXPORT_SYMBOL(SetLocalNICId);
unsigned long long get_cpu_tick(void)
{
uint32_t h = 0;
uint32_t l = 0;
uint32_t h1 = 0;
asm volatile("1: \n"
"mftbu %0 \n"
"mftb %1 \n"
"mftbu %2 \n"
"cmpw %0,%2 \n"
"bne 1b \n"
:"=r"(h), "=r"(l), "=r"(h1):);
return (((unsigned long long)h) << 32) | l;
}
EXPORT_SYMBOL(get_cpu_tick);
unsigned long long cpu_tick_to_ms(unsigned long long tick)
{
return div64_u64(tick, P1010_CPU_COUNT_PER_MS);
}
EXPORT_SYMBOL(get_cpu_tick_of_ms);