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

2713 lines
76 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 <net/udp.h>
#include <asm/fsl_gtm.h>
#include <net/arp.h>
#include "ucc_geth.h"
#include "debugfs.h"
#include "hook.h"
#include "irq.h"
#define USED_MALLOC_CHDETIAL (0)
#define SEND_SEQ_POS (0x2C)
#define RECV_SEQ_POS (SEND_SEQ_POS - 0x0E)
#define USED_FOR_TEST_ETH (0)
extern void ucc_netpoll(struct ucc_geth_private* dev);
extern uint64_t get_basetimer(void);
#ifdef EN_SIP_SWITCH
static struct sk_buff* switch_to_sip(int sipCh,
struct sk_buff* skb,
ETH_INTERFACE ethId,
PCH_PORT_INFO pPort);
#endif
static E_TIMER_1MS* hook_1ms;
static unsigned short g_RtpPortBase = 0xFFFF;
static int g_RtpPortIndex[UMB_MAX_RTP_CH];
static unsigned int g_SendIndex[UMB_MAX_RTP_CH];
static unsigned int g_RecvIndex[UMB_MAX_RTP_CH];
static struct ucc_geth_private* ugeths[UMB_MAX_GETH];
static struct g_rtp_t* g_rtp[UMB_MAX_GETH];
static int ugeths_ref[UMB_MAX_GETH];
static int ugeth_attached;
static RTP_CH_DBGS g_RtpChDbgs[UMB_MAX_RTP_CH];
static CPU_TIMER_DBG g_MaxTimeDbgs[UMB_MAX_GETH];
static CPU_TIMER_DBG g_AvgTimeDbgs[UMB_MAX_GETH];
static unsigned int g_DestIpAddr[UMB_MAX_RTP_CH];
static struct g_rtp_t* current_rtp;
//static int g_rtp_weight = UMB_MAX_RTP_CH;
static struct ipstack_hook_t ipstack_hook_8309[3];
static struct ipstack_hook_t* ipstack_hook = (struct ipstack_hook_t*)(&ipstack_hook_8309);
#define MAX_IRQ_LOOP_CNT 1024
static uint32_t irq_cnt;
static uint16_t irq_latency[1024];
static uint16_t max_latency[1024];
//static int irq_flags;
static unsigned int g_IRQCountHW = 0;
static unsigned int g_IRQCountLW = 0;
static uint64_t g_IRQCount = 0;
#ifdef EN_SIP_SWITCH
#define MAX_UMB_CH (128)
#define MAX_TC_CH (128)
#define MAX_SIP_CH (128)
static SIP_CH_INFO g_SIPChInfo;
#if !USED_MALLOC_CHDETIAL
static SIP_CH_DETIAL g_SIPDetial[MAX_SIP_CH];
#endif
static int g_DebugRFC2833 = 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;
}
#if USED_FOR_TEST_ETH
static void emual_config(void);
#endif
#endif
struct ipstack_hook_t* ipstack_hook_get(int ucc_num)
{
return &ipstack_hook_8309[ucc_num];
}
EXPORT_SYMBOL(ipstack_hook_get);
static struct g_rtp_t* ipstack_hook_get_grtp(struct ucc_geth_private* ugeth)
{
return g_rtp[ugeth->ucc_num];
}
static int is_rtp_kbuf(char* p)
{
if((uint8_t*)p < ipstack_hook->kmap_addr ||
(uint8_t*)p > ipstack_hook->kmap_end) //under 1G is phys addr
{
return 0;
}
return 1;
}
static int rtp_kbuf_init(int num)
{
int i;
for(i = 0; i < num; i++)
{
ipstack_hook = &ipstack_hook_8309[i];
ipstack_hook->kmap_len = sizeof(struct g_rtp_t);
ipstack_hook->kmap_addr = (uint8_t*)__get_free_pages(GFP_DMA32 | GFP_ATOMIC,
get_order(ipstack_hook->kmap_len));
if(ipstack_hook->kmap_addr)
{
ipstack_hook->kmap_phy = (uintptr_t)virt_to_phys(ipstack_hook->kmap_addr);
}
ipstack_hook->kmap_end = (ipstack_hook->kmap_addr + ipstack_hook->kmap_len);
memset(ipstack_hook->kmap_addr, 0, ipstack_hook->kmap_len);
g_rtp[i] = (struct g_rtp_t*)ipstack_hook->kmap_addr;
}
return 0;
}
static int rtp_kbuf_exit(void)
{
int i;
for(i = 0; i < 3; i++)
{
ipstack_hook = &ipstack_hook_8309[i];
if(ipstack_hook->kmap_addr)
{
free_pages((unsigned long)ipstack_hook->kmap_addr, get_order(ipstack_hook->kmap_len));
}
}
return 0;
}
struct sk_buff* dev_new_skb(struct ucc_geth_private* ugeth)
{
struct sk_buff* skb = NULL;
skb = dev_alloc_skb(ugeth->ug_info->uf_info.max_rx_buf_length +
UCC_GETH_RX_DATA_BUF_ALIGNMENT);
if(skb == NULL)
{
printk("dev_alloc_skb failed %s:%u\n", __FILE__, __LINE__);
return NULL;
}
skb_reserve(skb,
UCC_GETH_RX_DATA_BUF_ALIGNMENT -
(((unsigned)skb->data) & (UCC_GETH_RX_DATA_BUF_ALIGNMENT -
1)));
skb->dev = ugeth->ndev;
//virt_to_phys(skb->data);
return skb;
}
static int g_rtp_init(struct ucc_geth_private* ugeth)
{
struct g_rtp_t* g_rtp_tmp;
int j, k, i;
i = ugeth->ucc_num;
g_rtp_tmp = g_rtp[i];
if(!g_rtp_tmp)
{
return -ENOMEM;
}
memset(g_rtp_tmp, 0, sizeof(struct g_rtp_t));
for(j = 0; j < UMB_MAX_RTP_CH; j++)
{
struct rtp_ch_t* rtp_ch = &g_rtp_tmp->rtp_ch[j];
rtp_ch->current_ktx = &rtp_ch->tx[0];
rtp_ch->current_utx = &rtp_ch->tx[0];
rtp_ch->current_krx = &rtp_ch->rx[0];
rtp_ch->current_urx = &rtp_ch->rx[0];
rtp_ch->sk = NULL;
for(k = 0; k < sizeof(rtp_ch->tx) / sizeof(rtp_ch->tx[0]); k++)
{
rtp_ch->tx[k].status = 0;
rtp_ch->tx[k].len = 0;
}
for(k = 0; k < sizeof(rtp_ch->rx) / sizeof(rtp_ch->rx[0]); k++)
{
rtp_ch->rx[k].status = 0;
rtp_ch->rx[k].len = 0;
rtp_ch->rx[k].skb = dev_new_skb(ugeth);
rtp_ch->rx[k].data = rtp_ch->rx[k].skb;
}
if(i == 0)
{
g_RtpPortIndex[j] = -1;
}
}
return 0;
}
static int g_rtp_exit(struct ucc_geth_private* ugeth)
{
struct g_rtp_t* g_rtp_tmp;
int j, k, i;
i = ugeth->ucc_num;
g_rtp_tmp = g_rtp[i];
if(!g_rtp_tmp)
{
return -ENOMEM;
}
for(j = 0; j < UMB_MAX_RTP_CH; j++)
{
struct rtp_ch_t* rtp_ch = &g_rtp_tmp->rtp_ch[j];
for(k = 0; k < sizeof(rtp_ch->rx) / sizeof(rtp_ch->rx[0]); k++)
{
if(rtp_ch->rx[k].skb)
{
dev_kfree_skb(rtp_ch->rx[k].skb);
}
}
}
return 0;
}
static int ipstack_hook_init(struct ucc_geth_private* ugeth)
{
int i = ugeth->ucc_num;
int ret = 0;
struct ipstack_hook_t* priv = ipstack_hook_get(i);
if(i > UMB_MAX_GETH || i < 0)
{
return 1;
}
//skb_queue_head_init(&priv->qtx[i]);
skb_queue_head_init(&priv->qtx);
while(xchg(&ugeths_ref[i], 1))
{
msleep(2);
}
ret = g_rtp_init(ugeth);
ugeths[i] = ugeth;
ugeths_ref[i] = 0;
ugeth_attached++;
printk("ugeth_attached@%p %d(id=%d)\n", &ugeth_attached, ugeth_attached, i);
#ifdef EN_SIP_SWITCH
g_SIPChInfo.iTotalCh = 0;
#if USED_MALLOC_CHDETIAL
g_SIPChInfo.pSipChDetial = NULL;
#else
g_SIPChInfo.pSipChDetial = g_SIPDetial;
#endif
g_SIPChInfo.iPortBase = -1;
g_SIPChInfo.iPortStep = -1;
#if USED_FOR_TEST_ETH
if(i == 1)
{
emual_config();
}
#endif
#endif
return ret;
}
static int ipstack_hook_exit(struct ucc_geth_private* ugeth)
{
struct sk_buff* skb;
int i = ugeth->ucc_num;
struct ipstack_hook_t* priv = ipstack_hook_get(i);
#ifdef EN_SIP_SWITCH
g_SIPChInfo.iTotalCh = 0;
g_SIPChInfo.iPortBase = -1;
g_SIPChInfo.iPortStep = -1;
#if USED_MALLOC_CHDETIAL
if(g_SIPChInfo.pSipChDetial != NULL)
{
kfree(g_SIPChInfo.pSipChDetial);
}
#endif
#endif
if(i > UMB_MAX_GETH || i < 0)
{
return 1;
}
do
{
skb = skb_dequeue(&priv->qtx);
if(skb)
{
kfree_skb(skb);
}
}
while(skb);
while(xchg(&ugeths_ref[i], 1))
{
msleep(2);
}
ugeths[i] = NULL;
g_rtp_exit(ugeth);
ugeth_attached--;
ugeths_ref[i] = 0;
return 0;
}
static int stopped_cnt;
static unsigned long stopped_ts;
static int ipstack_hook_backlog(struct sk_buff* skb)
{
struct ucc_geth_private* ugeth = netdev_priv(skb->dev);
uint32_t qlen = 0;
uint32_t ucc_num = ugeth->ucc_num;
//skb_queue_tail(&ipstack_hook->qtx[ucc_num],skb);
//qlen = skb_queue_len(&ipstack_hook->qtx[ucc_num]);
struct ipstack_hook_t* priv = ipstack_hook_get(ucc_num);
skb_queue_tail(&priv->qtx, skb);
qlen = skb_queue_len(&priv->qtx);
if(qlen >= 240)
{
if(qlen > 240)
{
printk("ipstack_hook_backlog qlen:%u \n", qlen);
}
if(!netif_queue_stopped(ugeth->ndev))
{
stopped_cnt++;
netif_stop_queue(ugeth->ndev);
stopped_ts = jiffies;
}
}
return NETDEV_TX_OK;
}
static int ipstack_hook_xmit_filter(struct sk_buff* skb)
{
uint16_t ip_prot;
uint8_t udp_prot;
uint32_t first_magic;
uint32_t second_magic;
uint16_t ch;
uint16_t rtp_port;
int j;
struct ucc_geth_private* ugeth = netdev_priv(skb->dev);
// uint32_t ucc_num = ugeth->ucc_num;
ip_prot = *(uint16_t*)&skb->data[0xc];
if(skb->len == 118)
{
first_magic = *(uint32_t*)&skb->data[0x2a];
if(first_magic == 0x58694327)
{
second_magic = *(uint32_t*)&skb->data[0x32];
//ip_prot =*(uint16_t*)&skb->data[0xc];
udp_prot = *(uint8_t*)&skb->data[0x17];
if((udp_prot == IPPROTO_UDP) && (cpu_to_be16(ip_prot) == ETH_P_IP)
&& (second_magic == 0x58694327))
{
struct g_rtp_t* g_rtp = ipstack_hook_get_grtp(ugeth);
ch = *(uint16_t*)&skb->data[0x2e];
rtp_port = *(uint16_t*)&skb->data[0x30];
// printk("%s(%d) ch = %d, MAX = %d\n", __FUNCTION__, __LINE__,
// ch, UMB_MAX_RTP_CH);
if(ch < UMB_MAX_RTP_CH)
{
// printk("%s(%d)\n", __FUNCTION__, __LINE__);
struct rtp_ch_t* rtp_ch = &g_rtp->rtp_ch[ch];
rtp_ch->netdev = skb->dev;
rtp_ch->current_ktx->status = 0;
rtp_ch->current_ktx->len = skb->len;
rtp_ch->current_utx = rtp_ch->current_ktx;
for(j = 0; j < sizeof(rtp_ch->tx) / sizeof(rtp_ch->tx[0]); j++)
{
memcpy(rtp_ch->tx[j].data , &skb->data[0], skb->len);
}
rtp_ch->current_krx->len = 0;
rtp_ch->current_urx = rtp_ch->current_krx;
for(j = 0; j < sizeof(rtp_ch->rx) / sizeof(rtp_ch->rx[0]); j++)
{
rtp_ch->rx[j].len = 0;
rtp_ch->rx[j].status = 0;
}
// printk("%s(%d)\n", __FUNCTION__, __LINE__);
rtp_ch->sk = skb->sk;
skb->sk->sk_user_data = (void*)rtp_ch;
g_DestIpAddr[ch] = *(unsigned int*)&skb->data[0x1E];
g_RtpChDbgs[ch].uRecBytes = 0;
g_RtpChDbgs[ch].uSendBytes = 0;
g_RtpChDbgs[ch].uBufStatus = 0;
g_RtpChDbgs[ch].uLostPackages = 0;
g_RtpChDbgs[ch].uUDPRecPackages = 0;
g_RtpChDbgs[ch].uRecvSeqLost = 0;
g_RtpChDbgs[ch].uSendSeqLost = 0;
g_SendIndex[ch] = 0xFFFFFFFF;
g_RecvIndex[ch] = 0xFFFFFFFF;
memset(&g_MaxTimeDbgs[ugeth->ucc_num], 0, sizeof(CPU_TIMER_DBG));
memset(&g_AvgTimeDbgs[ugeth->ucc_num], 0, sizeof(CPU_TIMER_DBG));
}
//*(char *)0 = 'c';
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
}
}
ipstack_hook->backlog(skb);
return NETDEV_TX_OK;
}
static int ipstack_hook_xmit_filter_eth2(struct sk_buff* skb)
{
ipstack_hook_backlog(skb);
return NETDEV_TX_OK;
}
//static int hook_xmit_cnt;
//static int wake_up_cnt;
static int ipstack_hook_backlog_xmit(struct ucc_geth_private* ugeth)
{
int i;
//int ucc_num = ugeth->ucc_num;
for(i = 0; ugeth->tx_desc > 0; i++)
{
//struct sk_buff* skb = skb_dequeue(&ipstack_hook->qtx[ucc_num]);
struct sk_buff* skb = skb_dequeue(&ipstack_hook->qtx);
if(skb)
{
if(ipstack_hook->hook_xmit((void*)skb, SKB_BUFF_TYPE, skb->dev) == NETDEV_TX_OK)
{
continue;
}
}
break;
}
return i;
}
extern void register_sockopt_hook(void * (*hook)(int));
extern void unregister_sockopt_hook(void);
#if 0
static struct rtp_rx_buf_t* get_rtp_rx_ch(int dif, uint32_t ch)
{
struct rtp_ch_t* rtp_ch = NULL;
uint16_t status;
//rtp_ch = sockets[ch]->sk->sk_user_data;
rtp_ch = &(g_rtp[dif]->rtp_ch[ch]);
if(rtp_ch)
{
status = rtp_ch->current_krx->status;
if(!status)
{
return rtp_ch->current_krx;
}
}
return NULL;
}
#endif
#ifdef EN_SIP_SWITCH
static int make_arp_request(ETH_INTERFACE ethId, __be32 dest_ip)
{
struct sk_buff* skb = arp_create(ARPOP_REQUEST,
ETH_P_ARP,
dest_ip,
ugeths[ethId]->ndev,
ugeths[ethId]->chIpAddr,
NULL,
ugeths[ethId]->ndev->dev_addr,
NULL);
if(skb)
{
arp_xmit(skb);
}
else
{
printk("...");
}
return 0;
}
static int get_mac_form_ip(unsigned char* haddr, struct net_device* dev, __be32 ipaddr)
{
struct neighbour* n;
if(haddr != NULL && dev != NULL)
{
n = __neigh_lookup(&arp_tbl, &ipaddr, dev, 1);
if(n != NULL)
{
n->used = jiffies;
if(n->nud_state & NUD_VALID)
{
read_lock_bh(&n->lock);
memcpy(haddr, n->ha, dev->addr_len);
read_unlock_bh(&n->lock);
neigh_release(n);
return 0;
}
}
}
return -1;
}
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);
struct ucc_geth_private* ucc_drv = ugeths[ETH_INTERFACE_0];
PSIP_CH_DETIAL pCh = &g_SIPChInfo.pSipChDetial[sipCh];
if(skbSIP == NULL)
{
return NULL;
}
dev_kfree_skb_any(skb);
skbSIP->dev = ucc_drv->ndev;
eth_header(skbSIP, ucc_drv->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
)
{
if(get_mac_form_ip(pPort->chLinkInfo.dstTarget.ethAddr,
ucc_drv->ndev,
pPort->chLinkInfo.dstTarget.ipAddr) != 0)
{
make_arp_request(ETH_INTERFACE_0,
pPort->chLinkInfo.dstTarget.ipAddr);
}
}
memcpy(pHead->ethHead.h_dest,
pPort->chLinkInfo.dstTarget.ethAddr, ETH_ALEN);
pHead->ipHead.saddr = ucc_drv->chIpAddr;
pHead->ipHead.daddr = pPort->chLinkInfo.dstTarget.ipAddr;
pHead->udpHead.source = pPort->ipPort;
pHead->udpHead.dest = 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,
ucc_drv->ndev,
pPort->chLinkInfo.dstTarget.ipAddr) != 0)
{
make_arp_request(ETH_INTERFACE_0,
pPort->chLinkInfo.dstTarget.ipAddr);
}
else
{
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;
pHead->udpHead.check = 0;
}
#if 0
for(i = 0; i <= 0x85; i++)
{
if(i % 16 == 0 && i != 0)
{
printk("\n");
}
printk("%02X ", skbSIP->data[i]);
}
printk("\n");
#endif
if(ipstack_hook_backlog(skbSIP) == NETDEV_TX_OK)
{
pCh->sipDebug.cnt_ethx_2_eth0++;
}
return skbSIP;
}
const char g_DTMFTable[17] =
{
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'*', '#',
'A', 'B', 'C', 'D',
'F' // Flash
};
static void InitChDTMFRecvInfo(PCH_DTMF_INFO pChDtmf);
#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)
static int recv_dtmf_from_sip(int sipCh, struct sk_buff* skb)
{
int i = 0;
int bRecved = RECV_RFC2833_RECV_UNRECV;
// unsigned char* pPayload = (char*)(skb->data + 28);
// char payloadType = *(char*)(skb->data + 29) & 0x7F;
unsigned short seqNumber = *(unsigned short*)(skb->data + 30);
unsigned int timeStamp = *(unsigned int*)(skb->data + 32);
unsigned int syncId = *(unsigned int*)(skb->data + 36);
unsigned char dtmfIndex = *(unsigned char*)(skb->data + 40);
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;
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD>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)
{
InitChDTMFRecvInfo(&pCh->rfc2833DTMF);
}
}
}
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;
}
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)
{
InitChDTMFRecvInfo(&pCh->rfc2833DTMF);
pCh->rfc2833DTMF.dtmfRecvBuf[i].seqNumber = seqNumber;
pCh->rfc2833DTMF.dtmfRecvBuf[i].synIdentifier = syncId;
pCh->rfc2833DTMF.dtmfRecvBuf[i].timeStamps = timeStamp;
pCh->rfc2833DTMF.dtmfRecvBuf[i].dtmfValue = dtmfIndex;
pCh->rfc2833DTMF.dtmfRecvBuf[i].refCount = 1;
pCh->rfc2833DTMF.dtmfRecvBuf[i].refStatus = RFC2833_RECVING;
kfifo_in(&pCh->dtmfRecvFifo, &g_DTMFTable[dtmfIndex], 1);
if(g_DebugRFC2833 != 0)
{
printk("ch %d recv rfc2833 %c(%d), udp port:%d, rtp base:%d\n",
sipCh, g_DTMFTable[dtmfIndex], dtmfIndex,
udphdr->dest, g_SIPChInfo.iRTPPortBase);
}
bRecved = RECV_RFC2833_RECV_NEW;
break;
}
}
}
return bRecved;
}
static int ipstack_hook_udp_recv_sip(struct sk_buff* skb, int* rlt)
{
struct iphdr* iphdr = (struct iphdr*)skb->data;
struct udphdr* udphdr = (struct udphdr*)(skb->data + iphdr->ihl * 4);
char payloadType = *(char*)(skb->data + 29) & 0x7F;
struct ucc_geth_private* ucc_drv = ugeths[ETH_INTERFACE_0];
struct sk_buff* skbSIP;
unsigned short seq_index = *(unsigned short*)&skb->data[RECV_SEQ_POS];
// SPI Ch Package
if(udphdr->dest >= g_SIPChInfo.iRTPPortBase &&
udphdr->dest < (g_SIPChInfo.iRTPPortBase + g_SIPChInfo.iTotalCh))
{
int sipCh = (udphdr->dest - g_SIPChInfo.iRTPPortBase);
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 = 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)
{
return 0;
}
if(payloadType >= 96) // RFC2833 DTMF
{
int iStatus = recv_dtmf_from_sip(sipCh, skb);
pCh->sipDebug.mask_ethx_2_eth0 |= CHK_CH_RFC2833;
if(iStatus == RECV_RFC2833_RECV_UNRECV)
{
return 0;
}
else
{
*rlt = 1;
dev_kfree_skb_any(skb);
return (int)skb;
}
}
else
{
if(pCh->portT38.chStatus == CH_STATUS_LINKED)
{
pCh->sipDebug.mask_ethx_2_eth0 |= CHK_CH_STATUS | CHK_CH_NEEDSWITCH;
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 (int)skbSIP;
}
else
{
if(pCh->portB2B.chStatus == CH_STATUS_LINKED)
{
pCh->sipDebug.mask_ethx_2_eth0 |= CHK_CH_STATUS;
if(pCh->portB2B.chLinkInfo.dstTarget.ipAddr == ucc_drv->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)
{
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 (int)skbSIP;
}
}
}
else
{
pCh->sipDebug.mask_ethx_2_eth0 |= CHK_CH_STATUS | CHK_CH_NEEDSWITCH;
// ²»Í¬Íø¿¨¼äת·¢
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 (int)skbSIP;
}
}
if(pCh->portIPR.chStatus == CH_STATUS_LINKED)
{
pCh->sipDebug.mask_ethx_2_eth0 |= CHK_CH_STATUS | CHK_CH_NEEDSWITCH;
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 (int)skbSIP;
}
}
}
}
}
return 0;
}
#endif
static int dbg_dif, dbg_ch;
static uint32_t proxy_rtp_got_cnt, proxy_rtp_lost_cnt;
#ifdef EN_SIP_SWITCH
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);
struct ucc_geth_private* ucc_drv = ugeths[ethId];
// struct ipstack_hook_t* drv_hook = &ipstack_hook_8309[ucc_drv->ucc_num];
if(skbSIP == NULL)
{
return NULL;
}
dev_kfree_skb_any(skb);
skbSIP->dev = ucc_drv->ndev;
eth_header(skbSIP, ucc_drv->ndev, ETH_P_IP, NULL, NULL, skb->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
)
{
if(get_mac_form_ip(pPort->chLinkInfo.dstTarget.ethAddr,
ucc_drv->ndev,
pPort->chLinkInfo.dstTarget.ipAddr) != 0)
{
make_arp_request(ethId,
pPort->chLinkInfo.dstTarget.ipAddr);
}
}
memcpy(pHead->ethHead.h_dest,
pPort->chLinkInfo.dstTarget.ethAddr, ETH_ALEN);
pHead->ipHead.saddr = ucc_drv->chIpAddr;
pHead->ipHead.daddr = pPort->chLinkInfo.dstTarget.ipAddr;
pHead->udpHead.source = g_SIPChInfo.iRTPPortBase + sipCh;
pHead->udpHead.dest = 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,
ucc_drv->ndev,
pPort->chLinkInfo.dstTarget.ipAddr) == 0)
{
memcpy(&pPort->chLinkInfo.toRTPCh.headValue,
pPort->chLinkInfo.dstTarget.ethAddr,
ETH_ALEN);
}
else
{
make_arp_request(ethId,
pPort->chLinkInfo.dstTarget.ipAddr);
}
}
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;
pHead->udpHead.check = 0;
}
#if 0
printk("addr %p, %p, %p, %p\n",
pHead, &pHead->ethHead, &pHead->ipHead, &pHead->udpHead);
for(i = 0; i <= 0x85; i++)
{
if(i % 16 == 0 && i != 0)
{
printk("\n");
}
printk("%02X ", skbSIP->data[i]);
}
printk("\n");
#endif
if(!kfifo_is_empty(&pCh->dtmfSendFifo))
{
if(pCh->rfc2833DTMF.dtmfSendBuf.refStatus == RFC2833_SEND_IDLE)
{
int rlt = kfifo_out(&pCh->dtmfSendFifo,
&pCh->rfc2833DTMF.dtmfSendBuf.dtmfValue, 1);
if(rlt == 1)
{
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*)(skb->data + 28);
pHead->udpHead.len = 24;
pHead->udpHead.check = 0;
pHead->ipHead.tot_len = 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 = *(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(ipstack_hook_backlog(skbSIP) == NETDEV_TX_OK)
{
pCh->sipDebug.cnt_eth0_2_ethx++;
}
return skbSIP;
}
#endif
static int ipstack_hook_udp_recv(struct sk_buff* skb, int* rlt)
{
int ret = 0, port = 0;
struct iphdr* iphdr = (struct iphdr*)skb->data;
struct udphdr* udphdr = (struct udphdr*)(skb->data + iphdr->ihl * 4);
// struct ucc_geth_private* ugeth = netdev_priv(skb->dev);
unsigned int src_ip = *(unsigned int*)&skb->data[12];
unsigned short seq_index = *(unsigned short*)&skb->data[RECV_SEQ_POS];
struct sk_buff* out_skb = NULL;
struct sk_buff* skbSIP;
int ch = -1;
int dif;
struct rtp_ch_t* rtp_ch;
struct rtp_rx_buf_t* krx;
static int err_cnt = 0;
// g_RtpPortBase = 6000;
port = udphdr->dest - g_RtpPortBase;
#ifdef EN_SIP_SWITCH
// SPI Ch Package
if(udphdr->dest >= g_SIPChInfo.iPortBase &&
udphdr->dest < g_SIPChInfo.iPortBase +
(g_SIPChInfo.iTotalCh * g_SIPChInfo.iPortStep))
{
int sipCh = (udphdr->dest - g_SIPChInfo.iPortBase) / g_SIPChInfo.iPortStep;
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.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 < 0 || pCh->sipETHId > ETH_INTERFACE_2)
{
return 0;
}
if(pCh->portRTP.chStatus == CH_STATUS_LINKED)
{
pCh->sipDebug.mask_eth0_2_ethx |= CHK_CH_STATUS;
if(iphdr->saddr == pCh->portB2B.chLinkInfo.dstTarget.ipAddr
|| iphdr->saddr == pCh->portIPR.chLinkInfo.dstTarget.ipAddr
|| iphdr->saddr == pCh->portT38.chLinkInfo.dstTarget.ipAddr)
{
pCh->sipDebug.mask_eth0_2_ethx |= CHK_CH_NEEDSWITCH;
skbSIP = switch_to_sip(sipCh, skb, pCh->sipETHId, &pCh->portRTP);
if(skbSIP != NULL)
{
pCh->sipDebug.mask_eth0_2_ethx |= CHK_CH_SWITCH_OK;
*rlt = 1;
}
else
{
pCh->sipDebug.mask_eth0_2_ethx |= CHK_CH_SWITCH_ERR;
}
return (int)skbSIP;
}
}
}
return 0;
}
#endif
if(port >= 0 && port < UMB_MAX_RTP_CH)
{
ch = g_RtpPortIndex[port];
if(ch < 0 || ch >= UMB_MAX_RTP_CH)
{
if(err_cnt++ % 2000 == 0)
{
printk("udp port %d, port base %d, port %d, ch = %d\n",
udphdr->dest, g_RtpPortBase, port, ch);
}
return 0;
}
if(src_ip != g_DestIpAddr[ch])
{
// printk("ch %d this package is old need (0x%08X), current (0x%08X), skip it\n",
// ch, g_DestIpAddr[ch], src_ip);
return 0;
}
//printk("dest = %d, port = %d, g_portbase = %d, ch = %d\n",
// udphdr->dest, port, g_RtpPortBase, ch);
}
if(ch >= 0 && ch < UMB_MAX_RTP_CH)
{
//ch = udphdr->dest - 6000;
dif = ((struct ucc_geth_private*)netdev_priv(skb->dev))->ucc_num;
rtp_ch = &(g_rtp[dif]->rtp_ch[ch]);
dbg_dif = dif;
dbg_ch = ch;
g_RtpChDbgs[ch].uUDPRecPackages++;
if(rtp_ch->sk)
{
if(!rtp_ch->current_krx->status)
{
krx = rtp_ch->current_krx;
//memcpy(krx->data, (char *)udphdr, udphdr->len);
krx->data = (char*)udphdr;//iphdr;
out_skb = krx->skb;
krx->skb = skb;
krx->status = 1;
if(g_RecvIndex[ch] != 0xFFFFFFFF && seq_index != 0)
{
if(seq_index != g_RecvIndex[ch] + 1)
{
g_RtpChDbgs[ch].uRecvSeqLost++;
}
}
g_RecvIndex[ch] = seq_index;
//if (&rtp_ch->rx[3] == krx) {
if(&rtp_ch->rx[2] == krx)
{
krx = &rtp_ch->rx[0];
}
else
{
krx++;
}
g_RtpChDbgs[ch].uRecBytes++;
rtp_ch->current_krx = krx;
proxy_rtp_got_cnt++;
*rlt = 0;
}
else
{
proxy_rtp_lost_cnt++;
g_RtpChDbgs[ch].uLostPackages++;
g_RtpChDbgs[ch].uBufStatus =
(rtp_ch->current_krx->status << 3) |
(rtp_ch->rx[2].status << 2) |
(rtp_ch->rx[1].status << 1) |
(rtp_ch->rx[0].status << 0);
}
ret = udphdr->len; //iphdr->tot_len;
}
}
return (int)out_skb;
}
enum
{
IP_TX_OK_FLAGS = 0x0000,
IP_SEND_FLAGS = 0x0001,
IP_CSUM_FLAGS = 0x0010,
IP_SENDING_FLAGS = 0x0100
};
enum
{
IP_RX_FLAGS = 0x0001,
};
#define DEBUG_CODE_LINE() (printk("%s(%d)\n", __FUNCTION__, __LINE__))
//static uint32_t rtp_start = 0;
//static uint32_t rtp_loop = 0;
static int walk_rtp_list(struct ucc_geth_private* ugeth, int ch)
{
unsigned short seq_index;
//int ch = ugeth->current_tx;
struct rtp_ch_t* rtp_ch = &current_rtp->rtp_ch[ch];
register struct rtp_tx_buf_t* ktx = rtp_ch->current_ktx;
if(ktx->status & IP_SENDING_FLAGS || ktx->status == 0)
{
return NETDEV_TX_LOCKED;
}
//printk("%p-%p-%p-%p\n", ipstack_hook, (ipstack_hook->hook_xmit), rtp_ch, rtp_ch->netdev);
if(rtp_ch->netdev == NULL)
{
return NETDEV_TX_LOCKED;
}
if(g_RtpChDbgs[ch].uSendBytes % 1000 == 0
|| g_RtpChDbgs[ch].uSendBytes % 1001 == 0)
{
get_mac_form_ip(ktx->data, rtp_ch->netdev, g_DestIpAddr[ch]);
}
//this will be clean by reclaim the tx skb
ktx->status |= IP_SENDING_FLAGS;
if(ipstack_hook->hook_xmit(ktx, RTP_BUFF_TYPE, rtp_ch->netdev) == NETDEV_TX_OK)
{
seq_index = *(unsigned short*)(ktx->data + SEND_SEQ_POS);
if(g_SendIndex[ch] != 0xFFFFFFFF)
{
if(seq_index != g_SendIndex[ch] + 1)
{
g_RtpChDbgs[ch].uSendSeqLost++;
}
}
g_SendIndex[ch] = seq_index;
if(ktx == &rtp_ch->tx[1])
{
ktx = &rtp_ch->tx[0];
}
else
{
ktx = &rtp_ch->tx[1];
}
rtp_ch->current_ktx = ktx;
g_RtpChDbgs[ch].uSendBytes++;
return NETDEV_TX_OK;
}
ktx->status &= (~IP_SENDING_FLAGS);
return NETDEV_TX_BUSY;
}
int write_rtp_to_nic(int ucc_num, int ch)
{
int ret = NETDEV_TX_BUSY;
struct ucc_geth_private* ugeth = ugeths[ucc_num];
if(ugeth && ugeth->opened_ref && !xchg(&ugeths_ref[ucc_num], 1))
{
ipstack_hook = &ipstack_hook_8309[ucc_num];
current_rtp = g_rtp[ucc_num];
//ugeth->current_tx = ch;
ret = walk_rtp_list(ugeth,ch);
ugeths_ref[ucc_num] = 0;
}
return ret;
}
EXPORT_SYMBOL(write_rtp_to_nic);
struct irq_hook
{
void* (*hook)(uint32_t, void*) ;
void* data;
};
int config_rtp_port(unsigned short index, unsigned short port,
unsigned short port_base)
{
//unsigned int portIndex = (port - port_base) / step;
//printk(" port %d, base %d, index %d\n", port, port_base, index);
if(g_RtpPortBase == 0xFFFF)
{
g_RtpPortBase = port_base;
}
else if(g_RtpPortBase != port_base)
{
printk("%s(%d): port_base pre init to %d, now is %d\n", __FUNCTION__, __LINE__,
port_base, g_RtpPortBase);
return -1;
}
if(index < UMB_MAX_RTP_CH)
{
g_RtpPortIndex[port - port_base] = index;
//printk("g_RtpPortIndex[%d] = %d\n", port - port_base, index);
return 0;
}
return -1;
}
EXPORT_SYMBOL(config_rtp_port);
static struct irq_hook irq_hooks[32];;
static volatile uint32_t poll_hook_bitmap = 0xffffffff;
int register_irq_poll(void * (*hooks)(int, void* obj), void* data)
{
int ret = -ENOSPC;
int idx = 0;
if((idx = fls(poll_hook_bitmap) - 1) >= 0)
{
poll_hook_bitmap &= ~(1 << idx);
irq_hooks[idx].hook = (void*)hooks;
irq_hooks[idx].data = data;
ret = idx;
printk("irq_poll_register %x\n", ret);
}
return ret;
}
EXPORT_SYMBOL(register_irq_poll);
int unregister_irq_poll(int idx, void * (*hooks)(int, void* obj))
{
int ret = -EINVAL;
printk("irq_poll_unregister %x\n", idx);
if(!(poll_hook_bitmap & (1 << idx)))
{
poll_hook_bitmap |= (1 << idx);
}
return ret;
}
EXPORT_SYMBOL(unregister_irq_poll);
void geth_timer_hook(uint32_t irq_cnt)
{
int i;//, k;
//int hook_first = 0;
uint32_t bits;
uint64_t uTimeStart, uTimeUsed;
uint64_t uRTPSend, uNetOpt;
// uint64_t uHook;
// uint32_t k;
// struct rtp_ch_t *krtp;
//if(strcmp(GetBoardName(), "UMB") == 0)
{
//hook_first = 1;
bits = ~poll_hook_bitmap;
while((i = fls(bits) - 1) >= 0)
{
bits &= ~(1 << i);
irq_hooks[i].hook(irq_cnt, irq_hooks[i].data);
}
}
for(i = 0; i < 3; i++)
{
struct ucc_geth_private* ugeth = ugeths[i];
if(ugeth && ugeth->opened_ref && !xchg(&ugeths_ref[i], 1))
{
//int weight = g_rtp_weight;
uTimeStart = get_basetimer();
ipstack_hook = &ipstack_hook_8309[ugeth->ucc_num];
current_rtp = g_rtp[ugeth->ucc_num];
#if 0
if(i == 0)
{
//for(k = 0; k < UMB_MAX_RTP_CH; k++)
ugeth->current_tx = rtp_start;
krtp = &current_rtp->rtp_ch[rtp_start];
k = rtp_loop;
while(k--)
{
if(krtp->current_ktx->status == IP_SEND_FLAGS)
{
if(walk_rtp_list(ugeth,ugeth->current_tx) == NETDEV_TX_BUSY)
{
break;
}
}
ugeth->current_tx++;
krtp++;
//ugeth->current_tx %= UMB_MAX_RTP_CH;
}
}
#endif
uTimeUsed = get_basetimer() - uTimeStart;
uRTPSend = uTimeUsed;
// ͳ<>Ʒ<EFBFBD><C6B7><EFBFBD>RTP<54><50><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD>ƽ<EFBFBD><C6BD>ֵ
g_AvgTimeDbgs[i].uRTPSendTime += uTimeUsed;
g_AvgTimeDbgs[i].uRTPSendCnt++;
//ugeth->current_tx = 0;
uTimeStart = get_basetimer();
if(ugeth->tx_desc > 0)
{
ipstack_hook->backlog_xmit(ugeth);
}
ucc_netpoll((struct ucc_geth_private*)ugeth);
uTimeUsed = get_basetimer() - uTimeStart;
uNetOpt = uTimeUsed;
// ͳ<><CDB3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD>ƽ<EFBFBD><C6BD>ֵ
g_AvgTimeDbgs[i].uRTPNetTime += uTimeUsed;
g_AvgTimeDbgs[i].uRTPNetCnt++;
ugeths_ref[i] = 0;
if(uNetOpt + uRTPSend > g_MaxTimeDbgs[i].uRTPNetTime +
g_MaxTimeDbgs[i].uRTPSendTime)
{
g_MaxTimeDbgs[i].uRTPNetTime = uNetOpt;
g_MaxTimeDbgs[i].uRTPSendTime = uRTPSend;
}
}
}
#if 0
if(hook_first == 0)
{
uTimeStart = get_basetimer();
bits = ~poll_hook_bitmap;
while((i = fls(bits) - 1) >= 0)
{
bits &= ~(1 << i);
irq_hooks[i].hook(irq_cnt, irq_hooks[i].data);
}
uTimeUsed = get_basetimer() - uTimeStart;
uHook = uTimeUsed;
// ͳ<><CDB3>IRQ HOOK<4F><4B><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
if(g_MaxTimeDbgs[0].uIRQHookTime < uTimeUsed)
{
g_MaxTimeDbgs[0].uIRQHookTime = uTimeUsed;
}
// ͳ<><CDB3>IRQ HOOK<4F><4B><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD>ƽ<EFBFBD><C6BD>ֵ
g_AvgTimeDbgs[0].uIRQHookTime += uTimeUsed;
g_AvgTimeDbgs[0].uIRQHookCnt++;
}
#endif
return ;
}
static irqreturn_t umb_1ms_irq(int irq, void* dev_id)
{
uint64_t uTime, uTemp;
#ifdef GTM_TIMER
uint16_t gtcnt = 0;
uint16_t gtcnt1 = 0;
struct gtm* gtm = timer_1ms->gtm;
if(irq_flags & IRQ_STOP)
{
gtm_stop_timer16(timer_1ms);
return IRQ_HANDLED;
}
gtm_ack_timer16(timer_1ms, 0xffff);
gtcnt = in_be16(timer_1ms->gtcnr);
//gtcnt 单位us 16bit (65535 us)
irq_latency[irq_cnt % MAX_IRQ_LOOP_CNT] = gtcnt;
geth_timer_hook(irq_cnt);
gtcnt = in_be16(timer_1ms->gtcnr);
max_latency[irq_cnt % MAX_IRQ_LOOP_CNT] = gtcnt;
irq_cnt++;
#else
handler_irq();
geth_timer_hook(irq_cnt);
irq_cnt++;
#endif
uTemp = get_basetimer();
uTime = uTemp - g_IRQCount;
g_IRQCount = uTemp;
g_IRQCountHW = uTime >> 32;
g_IRQCountLW = uTime & 0xFFFFFFFF;
return IRQ_HANDLED;
}
#define DBG_MASK_UGETH (1 << 0)
#define DBG_MASK_PORTCFG (1 << 1)
#define DBG_RTP_HOOK (1 << 2)
#define DBG_SIP_INFO (1 << 3)
#define DBG_SIP_ONLY_CONNECT (1 << 4)
#define DBG_CPU_COUNT (1 << 5)
static int hook_show(struct seq_file* seq, void* token)
{
int i;
uint32_t max_load = 0;
uint32_t max_tv = 0;
uint32_t max_tv1 = 0;
if(token == SEQ_START_TOKEN)
{
struct debugfs_priv* pv = seq->private;
uint32_t dbgMask = ~(*(uint32_t *)(pv->options));
if(*(uint32_t *)(pv->options) == 0x17)
{
g_DebugRFC2833 = 1;
}
else
{
g_DebugRFC2833 = 0;
}
seq_puts(seq, "Mask DBG_MASK_UGETH (1 << 0)\n");
seq_puts(seq, "Mask DBG_MASK_PORTCFG (1 << 1)\n");
seq_puts(seq, "Mask DBG_RTP_HOOK (1 << 2)\n");
seq_puts(seq, "Mask DBG_SIP_INFO (1 << 3)\n");
seq_puts(seq, "Mask DBG_SIP_ONLY_CONNECT (1 << 4)\n");
seq_puts(seq, "Mask DBG_CPU_COUNT (1 << 5)\n");
seq_printf(seq, "umb driver ver0.1 debug mask = 0x%08X\n", dbgMask);
seq_printf(seq, "1ms Interrupt Used %s(%d)\n", hook_1ms->irqName,
hook_1ms->irq);
seq_printf(seq, "ucc=%p, index=%d ipaddr=0x%08X\n",
ugeths[0], ugeths[0]->ucc_num, ugeths[0]->chIpAddr);
seq_printf(seq, "ucc=%p, index=%d ipaddr=0x%08X\n",
ugeths[1], ugeths[1]->ucc_num, ugeths[1]->chIpAddr);
seq_printf(seq, "ucc=%p, index=%d ipaddr=0x%08X\n",
ugeths[2], ugeths[2]->ucc_num, ugeths[2]->chIpAddr);
if(dbgMask & DBG_MASK_UGETH)
{
seq_printf(seq,
"IRQ_SEPNR = 0x%08X, IRQ_SECNR = 0x%08X, IRQ_SEPCR = 0x%08X IRQ_SEMSR = 0x%08X IRQ_SEFCR = 0x%08X\n",
hook_1ms->pBase[IRQ_SEPNR],
hook_1ms->pBase[IRQ_SECNR],
hook_1ms->pBase[IRQ_SEPCR],
hook_1ms->pBase[IRQ_SEMSR],
hook_1ms->pBase[IRQ_SEFCR]);
seq_printf(seq, "ugeth_attached:%u, irq cnt: %u\n", ugeth_attached, irq_cnt);
for(i = 0; i < 3; i++)
{
if(ugeths[i])
{
seq_printf(seq, "ucc%d,tx_desc:%u ref:%u,opened_ref:%u,skblen:%u\n",
ugeths[i]->ucc_num,
ugeths[i]->tx_desc,
ugeths_ref[i],
((struct ucc_geth_private*)ugeths[i])->opened_ref,
//skb_queue_len(&ipstack_hook->qtx[i])
skb_queue_len(&(ipstack_hook_get(ugeths[i]->ucc_num)->qtx))
);
}
}
for(i = 0; i < MAX_IRQ_LOOP_CNT; i++)
{
max_load += (max_latency[i] - irq_latency[i]);
max_tv = (max_latency[i] > max_tv) ? max_latency[i] : max_tv;
max_tv1 = (irq_latency[i] > max_tv1) ? irq_latency[i] : max_tv1;
}
seq_printf(seq, "simple %u irq got max_load: %u,%u,%u\n",
MAX_IRQ_LOOP_CNT, max_load, max_tv, max_tv1);
seq_printf(seq, "dbg_dif:%x, dbg_ch:%x, rtp_lost:%u, rtp_got:%u\n",
dbg_dif, dbg_ch,
proxy_rtp_lost_cnt,
proxy_rtp_got_cnt
);
}
if(dbgMask & DBG_MASK_PORTCFG)
{
seq_printf(seq, "rtp port base = %u(0x%08X)\n", g_RtpPortBase, g_RtpPortBase);
for(i = 0; i < UMB_MAX_RTP_CH; i++)
{
if(g_RtpPortIndex[i] != -1)
{
seq_printf(seq, "Ch %d port = %d\n", g_RtpPortIndex[i], i);
}
}
seq_printf(seq, "Others Ch port = -1\n");
}
if(dbgMask & DBG_RTP_HOOK)
{
for(i = 0; i < UMB_MAX_RTP_CH; i++)
{
if(g_rtp[0]->rtp_ch[i].sk != NULL)
{
seq_printf(seq, "Ch %d Send MAC: %02X:%02X:%02X:%02X:%02X:%02X/%02X:%02X:%02X:%02X:%02X:%02X\n\n",
i,
g_rtp[0]->rtp_ch[i].tx[0].data[0],
g_rtp[0]->rtp_ch[i].tx[0].data[1],
g_rtp[0]->rtp_ch[i].tx[0].data[2],
g_rtp[0]->rtp_ch[i].tx[0].data[3],
g_rtp[0]->rtp_ch[i].tx[0].data[4],
g_rtp[0]->rtp_ch[i].tx[0].data[5],
g_rtp[0]->rtp_ch[i].tx[1].data[0],
g_rtp[0]->rtp_ch[i].tx[1].data[1],
g_rtp[0]->rtp_ch[i].tx[1].data[2],
g_rtp[0]->rtp_ch[i].tx[1].data[3],
g_rtp[0]->rtp_ch[i].tx[1].data[4],
g_rtp[0]->rtp_ch[i].tx[1].data[5]);
}
}
for(i = 0; i < UMB_MAX_RTP_CH; i++)
{
if(g_rtp[0]->rtp_ch[i].sk != NULL)
{
seq_printf(seq, "ch[%u] current_krx:%p,status:%x,len:%x,sk@%p, send:%u, recv:%u, seq_send:%u, seq_recv:%u, lost:%u, buf:0x%02X, udprecv:%u\n",
i,
g_rtp[0]->rtp_ch[i].current_krx,
g_rtp[0]->rtp_ch[i].current_krx->status,
g_rtp[0]->rtp_ch[i].current_krx->len,
g_rtp[0]->rtp_ch[i].sk,
g_RtpChDbgs[i].uSendBytes,
g_RtpChDbgs[i].uRecBytes,
g_RtpChDbgs[i].uSendSeqLost,
g_RtpChDbgs[i].uRecvSeqLost,
g_RtpChDbgs[i].uLostPackages,
g_RtpChDbgs[i].uBufStatus,
g_RtpChDbgs[i].uUDPRecPackages++
);
}
}
}
#ifdef EN_SIP_SWITCH
if(dbgMask & DBG_SIP_INFO || dbgMask & DBG_SIP_ONLY_CONNECT)
{
seq_printf(seq, "SPI Info:\n");
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(!(dbgMask & DBG_SIP_ONLY_CONNECT))
{
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, "ETH0 Recv: %d\n", pCh->sipDebug.cnt_eth0_recv);
seq_printf(seq, "ETH0 Switch: %d\n", pCh->sipDebug.cnt_eth0_2_ethx);
seq_printf(seq, "ETH0 Mask: 0x%08X\n", pCh->sipDebug.mask_eth0_2_ethx);
seq_printf(seq, "ETH0 lost: %d\n\n", pCh->sipDebug.eth0_seq_error);
seq_printf(seq, "ETHx Recv: %d\n", pCh->sipDebug.cnt_ethx_recv);
seq_printf(seq, "ETHx Switch: %d\n", pCh->sipDebug.cnt_ethx_2_eth0);
seq_printf(seq, "ETHx Mask: 0x%08X\n", pCh->sipDebug.mask_ethx_2_eth0);
seq_printf(seq, "ETHx lost: %d\n", pCh->sipDebug.ethx_seq_error);
}
#endif
}
if(dbgMask & DBG_CPU_COUNT)
{
seq_printf(seq, "1MS Count = %u-%u\n", g_IRQCountHW, g_IRQCountLW);
for(i = 0; i < 3; i++)
{
seq_printf(seq, "ETH[%d] Max: RtpSend = %u, Net = %u, Hook = %u\n",
i,
(unsigned int)g_MaxTimeDbgs[i].uRTPSendTime,
(unsigned int)g_MaxTimeDbgs[i].uRTPNetTime,
(unsigned int)g_MaxTimeDbgs[i].uIRQHookTime);
seq_printf(seq, "ETH[%d] Avage: RtpSend = %u, Net = %u, Hook = %u\n",
i,
g_AvgTimeDbgs[i].uRTPSendTime / g_AvgTimeDbgs[i].uRTPSendCnt,
g_AvgTimeDbgs[i].uRTPNetTime / g_AvgTimeDbgs[i].uRTPNetCnt,
g_AvgTimeDbgs[i].uIRQHookTime / g_AvgTimeDbgs[i].uIRQHookCnt);
}
}
}
return 0;
}
static struct debugfs_priv hook_priv[] =
{
{"hook", "", NULL, ugeths, hook_show},
};
static struct ucc_geth_private* ugeths[UMB_MAX_GETH];
int geth_timer_init(int ms)
{
#ifdef GTM_TIMER
int ret;
//timer_1ms = gtm_get_timer16();
timer_1ms = gtm_get_timer16_by_id(0);
if(IS_ERR(timer_1ms))
{
ret = PTR_ERR(timer_1ms);
printk(KERN_DEBUG "timer_1ms gtm_get_timer16 failed %i", timer_1ms);
return -EEXIST;
}
ugeth_attached = 0;
ret = request_irq(timer_1ms->irq, umb_1ms_irq, IRQF_DISABLED, "gptimer1",
timer_1ms);
if(ret)
{
printk(KERN_DEBUG "failed to request_irq for mygtm timer irq:%d ret:%d\n",
timer_1ms->irq, ret);
gtm_put_timer16(timer_1ms);
return -EEXIST;
}
IRQ_TC = 1000 * ms;
rtp_kbuf_init(3);
gtm_set_exact_timer16(timer_1ms, IRQ_TC, true);
umb_register_seqfs(hook_priv);
#else
int ret;
irq_init();
hook_1ms = irq_get_timer();
if(hook_1ms->pBase == NULL)
{
return -1;
}
ret = request_irq(hook_1ms->irq, umb_1ms_irq, 0, "irq", 0);
if(ret)
{
printk(KERN_DEBUG "failed to request_irq for mygtm timer irq:%d ret:%d\n",
hook_1ms->irq, ret);
return -EEXIST;
}
rtp_kbuf_init(3);
umb_register_seqfs(hook_priv);
#endif
memset(&g_MaxTimeDbgs, 0, sizeof(CPU_TIMER_DBG));
memset(&g_AvgTimeDbgs, 0, sizeof(CPU_TIMER_DBG));
return 0;
}
int geth_timer_exit(void)
{
#ifdef GTM_TIMER
irq_flags |= IRQ_STOP;
gtm_stop_timer16(timer_1ms);
msleep(10);
free_irq(timer_1ms->irq, timer_1ms);
gtm_put_timer16(timer_1ms);
rtp_kbuf_exit();
umb_unregister_seqfs(hook_priv);
#else
if(hook_1ms->pBase != NULL && hook_1ms->irq != 0)
{
free_irq(hook_1ms->irq, NULL);
irq_exit();
}
rtp_kbuf_exit();
umb_unregister_seqfs(hook_priv);
#endif
return 0;
}
#ifdef EN_SIP_SWITCH
static struct ipstack_hook_t ipstack_hook_8309[3] =
{
{
.hook_init = ipstack_hook_init,
.hook_exit = ipstack_hook_exit,
.xmit_filter = ipstack_hook_xmit_filter,
.backlog = ipstack_hook_backlog,
.hook_xmit = NULL,
.ucc_ndev = NULL,
.backlog_xmit = ipstack_hook_backlog_xmit,
.get_grtp = ipstack_hook_get_grtp,
.gptimer_init = geth_timer_init,
.gptimer_exit = geth_timer_exit,
.is_rtp_kbuf = is_rtp_kbuf,
.do_sock_send = NULL,
.do_sock_recv = ipstack_hook_udp_recv,
},
{
.hook_init = ipstack_hook_init,
.hook_exit = ipstack_hook_exit,
.xmit_filter = ipstack_hook_xmit_filter_eth2,
.backlog = ipstack_hook_backlog,
.hook_xmit = NULL,
.ucc_ndev = NULL,
.backlog_xmit = ipstack_hook_backlog_xmit,
.get_grtp = ipstack_hook_get_grtp,
.gptimer_init = geth_timer_init,
.gptimer_exit = geth_timer_exit,
.is_rtp_kbuf = is_rtp_kbuf,
.do_sock_send = NULL,
.do_sock_recv = ipstack_hook_udp_recv_sip,
},
{
.hook_init = ipstack_hook_init,
.hook_exit = ipstack_hook_exit,
.xmit_filter = ipstack_hook_xmit_filter_eth2,
.backlog = ipstack_hook_backlog,
.hook_xmit = NULL,
.ucc_ndev = NULL,
.backlog_xmit = ipstack_hook_backlog_xmit,
.get_grtp = ipstack_hook_get_grtp,
.gptimer_init = geth_timer_init,
.gptimer_exit = geth_timer_exit,
.is_rtp_kbuf = is_rtp_kbuf,
.do_sock_send = NULL,
.do_sock_recv = ipstack_hook_udp_recv_sip,
},
};
#else
static struct ipstack_hook_t ipstack_hook_8309[3] =
{
{
.hook_init = ipstack_hook_init,
.hook_exit = ipstack_hook_exit,
.xmit_filter = ipstack_hook_xmit_filter,
.backlog = ipstack_hook_backlog,
.hook_xmit = NULL,
.ucc_ndev = NULL,
.backlog_xmit = ipstack_hook_backlog_xmit,
.get_grtp = ipstack_hook_get_grtp,
.gptimer_init = geth_timer_init,
.gptimer_exit = geth_timer_exit,
.is_rtp_kbuf = is_rtp_kbuf,
.do_sock_send = NULL,
.do_sock_recv = ipstack_hook_udp_recv,
},
{
.hook_init = ipstack_hook_init,
.hook_exit = ipstack_hook_exit,
.xmit_filter = ipstack_hook_xmit_filter_eth2,
.backlog = ipstack_hook_backlog,
.hook_xmit = NULL,
.ucc_ndev = NULL,
.backlog_xmit = ipstack_hook_backlog_xmit,
.get_grtp = ipstack_hook_get_grtp,
.gptimer_init = geth_timer_init,
.gptimer_exit = geth_timer_exit,
.is_rtp_kbuf = is_rtp_kbuf,
.do_sock_send = NULL,
.do_sock_recv = ipstack_hook_udp_recv,
},
{
.hook_init = ipstack_hook_init,
.hook_exit = ipstack_hook_exit,
.xmit_filter = ipstack_hook_xmit_filter,
.backlog = ipstack_hook_backlog,
.hook_xmit = NULL,
.ucc_ndev = NULL,
.backlog_xmit = ipstack_hook_xmit_filter_eth2,
.get_grtp = ipstack_hook_get_grtp,
.gptimer_init = geth_timer_init,
.gptimer_exit = geth_timer_exit,
.is_rtp_kbuf = is_rtp_kbuf,
.do_sock_send = NULL,
.do_sock_recv = ipstack_hook_udp_recv,
},
};
#endif
#ifdef EN_SIP_SWITCH
#define MAX_UMB_CH (128)
#define MAX_TC_CH (128)
#define MAX_SIP_CH (128)
static void InitIPAddrInfo(PIP_ADDR_INFO pAddrInfo)
{
if(pAddrInfo)
{
memset(pAddrInfo->ethAddr, 0xFF, ETH_ALEN);
pAddrInfo->ipAddr = 0;
pAddrInfo->ipPort = -1;
}
}
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->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;
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);
if(pCh->dtmfSendFifo.buffer != NULL)
{
kfifo_free(&pCh->dtmfSendFifo);
}
rlt = kfifo_alloc(&pCh->dtmfSendFifo, MAX_DTMF_SEND_BUF, GFP_KERNEL);
if(pCh->dtmfRecvFifo.buffer != NULL)
{
kfifo_free(&pCh->dtmfRecvFifo);
}
rlt = kfifo_alloc(&pCh->dtmfRecvFifo, MAX_DTMF_RECV_BUF, 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)
{
#if USED_MALLOC_CHDETIAL
if(g_SIPChInfo.pSipChDetial != NULL)
{
kfree(g_SIPChInfo.pSipChDetial);
g_SIPChInfo.pSipChDetial = NULL;
}
g_SIPChInfo.pSipChDetial = kmalloc(sizeof(SIP_CH_DETIAL) * maxSIPCh,
GFP_ATOMIC);
if(g_SIPChInfo.pSipChDetial == NULL)
{
return -1;
}
#endif
for(i = 0; i < maxSIPCh; i++)
{
InitSIPChDetial(&g_SIPChInfo.pSipChDetial[i]);
}
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 != ETH_INTERFACE_2 && ethId != ETH_INTERFACE_1)
{
return -1;
}
if(g_SIPChInfo.pSipChDetial != NULL
&& chId < g_SIPChInfo.iTotalCh)
{
PSIP_CH_DETIAL pChDetail = g_SIPChInfo.pSipChDetial + chId;
pChDetail->chId = chId;
pChDetail->sipETHId = (ethId == 1) ? 2 : 1;
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)
{
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_UNKONWN)
{
return -1;
}
make_arp_request(pCh->sipETHId, dst_ipAddr);
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.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;
if(g_SIPChInfo.pSipChDetial == NULL || chId >= g_SIPChInfo.iTotalCh)
{
return -1;
}
pCh = &g_SIPChInfo.pSipChDetial[chId];
make_arp_request(ETH_INTERFACE_0, dst_ipAddr);
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;
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 config_eth_ipaddr(unsigned int ethId, __be32 ipaddr)
{
struct ucc_geth_private* ucc_drv = NULL;
if(ethId <= ETH_INTERFACE_2)
{
if(ethId == 1)
ucc_drv = ugeths[2];
else if(ethId == 2)
ucc_drv = ugeths[1];
else if(ethId == 0)
ucc_drv = ugeths[0];
if(ucc_drv != NULL)
{
ucc_drv->chIpAddr = ipaddr;
}
}
return -1;
}
EXPORT_SYMBOL(config_eth_ipaddr);
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;
}
rlt = kfifo_out(&pCh->dtmfRecvFifo, &value, 1);
if(rlt == 1)
{
return (char)value;
}
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]);
if(kfifo_in(&pCh->dtmfSendFifo, &dtmf, 1) != 1)
{
return -1;
}
}
return i;
}
EXPORT_SYMBOL(sip_send_dtmf);
#if USED_FOR_TEST_ETH
static void emual_config(void)
{
int i = 0;
__be32 spbx_ipaddr = 192 << 24 | 168 << 16 | 0 << 8 | 60;
__be16 spbx_port = 6001;
__be32 sip_ipaddr = 192 << 24 | 168 << 16 | 1 << 8 | 30;
__be16 sip_port = 10000;
#define PORT_BASE_SIP (6500)
#define PORT_BASE_RTP (9000)
#define PORT_STEP_SIP (3)
#define MAX_SIP_CH_NUM (1)
config_sip_ch(MAX_SIP_CH_NUM, PORT_BASE_SIP, PORT_STEP_SIP, PORT_BASE_RTP);
for(i = 0; i < MAX_SIP_CH_NUM; i++)
{
config_sip_port(i, ETH_INTERFACE_1, PORT_BASE_SIP + (i * 3), PORT_BASE_RTP + i);
}
for(i = 0; i < MAX_SIP_CH_NUM; i++)
{
eth_sip_link(i, sip_ipaddr, sip_port + i);
eth_link(i, PORT_TYPE_B2B, spbx_ipaddr, spbx_port + (i * 3) + 1);
}
// eth_link(0, PORT_TYPE_B2B, spbx_ipaddr, spbx_port + 4);
// eth_link(1, PORT_TYPE_B2B, spbx_ipaddr, spbx_port + 1);
config_eth_ipaddr(ETH_INTERFACE_0,
192 << 24 | 168 << 16 | 0 << 8 | 10);
config_eth_ipaddr(ETH_INTERFACE_1,
192 << 24 | 168 << 16 | 1 << 8 | 20);
config_eth_ipaddr(ETH_INTERFACE_2,
192 << 24 | 168 << 16 | 2 << 8 | 20);
}
#endif
#endif