#include #include #include #include #include #include #include #include "gianfar.h" #include "debug_info.h" #include "log.h" #include "hook.h" #define USED_MALLOC_CHDETIAL (0) #define PROC_NAME ("gfar") #define SEND_SEQ_POS (0x2C) #define RECV_SEQ_POS (SEND_SEQ_POS - 0x0E) static int irq_flags; static struct ipstack_hook_t ipstack_hook_p1010[UMB_MAX_GETH]; static struct gfar_private* g_geths[UMB_MAX_GETH]; static int g_geths_ref[UMB_MAX_GETH]; struct irq_hook { void* (*hook)(int, void*) ; void* data; int per_of_ms; }; static struct irq_hook irq_hooks[32]; static volatile uint32_t poll_hook_bitmap = 0xffffffff; static int g_irq_cnt = 0; static int g_1ms_timer = -1; #ifdef EN_SIP_SWITCH #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; #if !USED_MALLOC_CHDETIAL static SIP_CH_DETIAL g_SIPDetial[MAX_SIP_CH]; #endif const char g_DTMFTable[17] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '#', 'A', 'B', 'C', 'D', 'F' // Flash }; static int ipstack_hook_udp_recv_sip(struct sk_buff* skb); 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); #endif static struct sk_buff* dev_new_skb(struct gfar_private* priv); static int DbgFS_GianfarARPShow(struct seq_file* seq, void* token); static int DbgFS_GianfarChRTPShow(struct seq_file* seq, void* token); static int DbgFS_GianfarChPortShow(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 DBGFS_PRIV g_DbgFSConfig[] = { { "arp_mac", 0, NULL, NULL, DbgFS_GianfarARPShow, NULL, NULL }, { "ch_rtp", 0, NULL, NULL, DbgFS_GianfarChRTPShow, NULL, NULL }, { "ch_port", 0, NULL, NULL, DbgFS_GianfarChPortShow, NULL, NULL }, #ifdef EN_SIP_SWITCH { "sip_ch", 0, NULL, NULL, DbgFS_GianfarSipPortShow, NULL, NULL }, { "sip_arp", 0, NULL, NULL, DbgFS_SipArpShow, NULL, NULL }, #endif }; static int make_arp_request(unsigned int ethId, __be32 dest_ip) { struct sk_buff* skb = NULL; if(ethId > ETH_INTERFACE_2) { return 0; } skb = arp_create(ARPOP_REQUEST, ETH_P_ARP, dest_ip, g_geths[ethId]->ndev, g_geths[ethId]->chIpAddr, NULL, g_geths[ethId]->ndev->dev_addr, NULL); if(skb) { arp_xmit(skb); } else { printk("..."); } return 0; } static int get_mac_form_ip(unsigned char* haddr, ETH_INTERFACE ethId, __be32 ipaddr, int id) { struct neighbour* n; struct gfar_private* ugeth = g_geths[ethId]; __be32 oldip = ipaddr; //memset(haddr, 0xFF, ETH_ALEN); if(ugeth->chGWIpAddr != 0) { if((ipaddr & ugeth->chGWMask) != (ugeth->chIpAddr & ugeth->chGWMask)) { if(id == 4 || id == 3) { printk("ipaddr = 0x%08X, ugeth->chGWMask = 0x%08X, ugeth->chIpAddr = 0x%08X\n", ipaddr, ugeth->chGWMask, ugeth->chIpAddr); } ipaddr = ugeth->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, ugeth->ndev, 1); if(n != NULL) { n->used = jiffies; if(n->nud_state & NUD_VALID) { read_lock_bh(&n->lock); memcpy(haddr, n->ha, ugeth->ndev->addr_len); read_unlock_bh(&n->lock); neigh_release(n); return 0; } } 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); } make_arp_request(ethId, ipaddr); return -1; } struct ipstack_hook_t* ipstack_hook_get(int ucc_num) { return &ipstack_hook_p1010[ucc_num]; } EXPORT_SYMBOL(ipstack_hook_get); static PRTP_CH_DETAILS ipstack_hook_get_grtp(struct gfar_private* ugeth) { if(ipstack_hook_p1010[ugeth->ucc_num].pRtpChDetails == NULL) { printk("%d RTP Detailse is NULL\n", ugeth->ucc_num); } return ipstack_hook_p1010[ugeth->ucc_num].pRtpChDetails; } static int is_rtp_kbuf(void* p, int ucc_num) { struct ipstack_hook_t* gfar_hook = ipstack_hook_get(ucc_num); //under 1G is phys addr if(p < (void*)gfar_hook->kmap_addr || p > (void*)gfar_hook->kmap_end) { return 0; } return 1; } static int walk_rtp_list(struct gfar_private* ugeth) { int ch = ugeth->current_tx; unsigned short seq_index; struct ipstack_hook_t* pGfarHook = &ipstack_hook_p1010[ugeth->ucc_num]; PRTP_CH_DETAILS pBase = pGfarHook->pRtpChDetails; PRTP_CH_DETAILS rtp_ch = pBase + 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; } if(pGfarHook->rtpChDbgs[ch].uSendBytes % 1000 == 0 || pGfarHook->rtpChDbgs[ch].uSendBytes % 1001 == 0) { get_mac_form_ip(ktx->data, ugeth->ucc_num, pGfarHook->linkIPAddr[ch], 1); } //this will be clean by reclaim the tx skb ktx->status |= IP_SENDING_FLAGS; if(pGfarHook->hook_xmit(ktx, RTP_BUFF_TYPE, rtp_ch->netdev) == NETDEV_TX_OK) { seq_index = *(unsigned short*)(ktx->data + SEND_SEQ_POS); if(pGfarHook->sendIndex[ch] != 0xFFFFFFFF) { if(seq_index != pGfarHook->sendIndex[ch] + 1) { pGfarHook->rtpChDbgs[ch].uSendSeqLost++; } } pGfarHook->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; pGfarHook->rtpChDbgs[ch].uSendBytes++; return NETDEV_TX_OK; } ktx->status &= (~IP_SENDING_FLAGS); return NETDEV_TX_BUSY; } void geth_timer_hook(uint32_t irq_cnt) { int i = 0, k = 0; uint32_t bits, qlen; struct ipstack_hook_t* priv = NULL; for(i = 0; i < UMB_MAX_GETH; i++) { struct gfar_private* ugeth = g_geths[i]; if(ugeth && ugeth->opened_ref && !xchg(&g_geths_ref[i], 1)) { struct ipstack_hook_t* pGarHook = &ipstack_hook_p1010[ugeth->ucc_num]; int procCh = pGarHook->rtpCfgCh; int weight = procCh / 10; for(k = 0; k < weight; k++) { if(walk_rtp_list(ugeth) == NETDEV_TX_BUSY) { break; } ugeth->current_tx++; ugeth->current_tx %= procCh; } priv = ipstack_hook_get(i); qlen = skb_queue_len(&priv->qtx); if(qlen > 0) { pGarHook->backlog_xmit(ugeth, qlen); } gfar_netpoll(ugeth); g_geths_ref[i] = 0; } } bits = ~poll_hook_bitmap; while((i = fls(bits) - 1) >= 0) { if(irq_hooks[i].per_of_ms > 1) { if((irq_cnt % irq_hooks[i].per_of_ms) == 0) { irq_hooks[i].hook(irq_cnt, irq_hooks[i].data); } } else { irq_hooks[i].hook(irq_cnt, irq_hooks[i].data); } bits &= ~(1 << i); } return ; } int register_irq_poll(void * (*hooks)(int, void* obj), void* data, unsigned int per_of_ms) { int ret = -ENOSPC; int idx = 0; if((idx = fls(poll_hook_bitmap) - 1) >= 0) { poll_hook_bitmap &= ~(1 << idx); irq_hooks[idx].hook = hooks; irq_hooks[idx].data = data; irq_hooks[idx].per_of_ms = per_of_ms; ret = idx; } return ret; } EXPORT_SYMBOL(register_irq_poll); int unregister_irq_poll(int idx, void * (*hooks)(int, void* obj)) { int ret = -EINVAL; if(!(poll_hook_bitmap & (1 << idx))) { irq_hooks[idx].hook = NULL; poll_hook_bitmap |= (1 << idx); } return ret; } EXPORT_SYMBOL(unregister_irq_poll); int config_rtp_port(int ethId, unsigned short index, unsigned short port, unsigned short port_base, unsigned short port_step, unsigned int bReConfig) { int portIndex = 0; struct ipstack_hook_t* pGfarHook = ipstack_hook_get(ethId); //printk(" port %d, base %d, index %d\n", port, port_base, index); if(bReConfig) { pGfarHook->rtpBasePort = port_base; pGfarHook->rtpCfgCh = 0; pGfarHook->rtpPortStep = port_step; } #if 0 if(pGfarHook->rtpBasePort == 0xFFFF) { pGfarHook->rtpBasePort = port_base; } else if(pGfarHook->rtpBasePort != port_base && port_base != 0xFFFF) { printk("%s(%d): port_base pre init to %d, now is %d\n", __FUNCTION__, __LINE__, port_base, pGfarHook->rtpBasePort); return -1; } #endif if(index < pGfarHook->rtpMaxCh) { if(pGfarHook->rtpCfgCh < pGfarHook->rtpMaxCh) { pGfarHook->rtpCfgCh++; portIndex = (port - pGfarHook->rtpBasePort) / pGfarHook->rtpPortStep; pGfarHook->rtpPortIndex[portIndex] = index; } // printk("pGfarHook->rtpPortIndex[%d] = %d\n", portIndex, index); return 0; } return -1; } EXPORT_SYMBOL(config_rtp_port); static struct sk_buff* dev_new_skb(struct gfar_private* priv) { unsigned int alignamount; struct sk_buff* skb = NULL; skb = netdev_alloc_skb(priv->ndev, priv->rx_buffer_size + RXBUF_ALIGNMENT); if(!skb) { return NULL; } alignamount = RXBUF_ALIGNMENT - (((unsigned long) skb->data) & (RXBUF_ALIGNMENT - 1)); /* We need the data buffer to be aligned properly. We will reserve * as many bytes as needed to align the data properly * Do only if not already aligned */ if(alignamount != RXBUF_ALIGNMENT) { skb_reserve(skb, alignamount); } GFAR_CB(skb)->alignamount = alignamount; /* Keep incoming device pointer for recycling */ skb->skb_owner = priv->ndev; return skb; } static int ipstack_hook_backlog_xmit(struct gfar_private* ugeth, int len) { struct ipstack_hook_t* priv = ipstack_hook_get(ugeth->ucc_num); int i; for(i = 0; i < len; i++) { struct sk_buff* skb = skb_dequeue(&priv->qtx); if(skb) { if(priv->hook_xmit((void*)skb, SKB_BUFF_TYPE, skb->dev) == NETDEV_TX_OK) { continue; } } break; } return i; } static int ipstack_hook_udp_recv(struct sk_buff* skb) { 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 int src_ip = *(unsigned int*)&skb->data[12]; unsigned short seq_index = *(unsigned short*)&skb->data[RECV_SEQ_POS]; int dif = ((struct gfar_private*)netdev_priv(skb->dev))->ucc_num; struct ipstack_hook_t* pGfarHook = ipstack_hook_get(dif); int ch = -1; struct sk_buff* pOutSKB = NULL; PRTP_CH_DETAILS rtp_ch; struct rtp_rx_buf_t* krx; struct sk_buff* skbSIP; int udp_len = udphdr->len; int port = (udphdr->dest - pGfarHook->rtpBasePort); #ifdef EN_SIP_SWITCH // stun package if((pUdpData[0] & 0xC0) == 0 && pUdpData[4] == 0x21 && pUdpData[5] == 0x12 && pUdpData[6] == 0xA4 && pUdpData[7] == 0x42) { return 0; } // 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) { 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(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; if(CheckMacAddress(&pCh->portRTP, pCh->sipETHId) == -1) { pCh->sipDebug.mask_eth0_2_ethx |= CHK_CH_DROP_WAITARP; dev_kfree_skb_any(skb); return udphdr->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 udphdr->len; } pCh->sipDebug.mask_eth0_2_ethx |= CHK_CH_SWITCH_ERR; } } } return 0; } #endif if(port >= 0 && port < (pGfarHook->rtpCfgCh * pGfarHook->rtpPortStep)) { ch = pGfarHook->rtpPortIndex[port / 3]; if(ch < 0 || ch >= pGfarHook->rtpCfgCh) { return 0; } if(src_ip != pGfarHook->linkIPAddr[ch]) { return 0; } } if(ch >= 0 && ch < pGfarHook->rtpCfgCh) { rtp_ch = pGfarHook->pRtpChDetails + ch; pGfarHook->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; krx->len = udphdr->len; pOutSKB = krx->skb; krx->skb = skb; krx->status = 1; dev_kfree_skb_any(pOutSKB); if(pGfarHook->recvIndex[ch] != 0xFFFFFFFF) { if(seq_index != pGfarHook->recvIndex[ch] + 1) { pGfarHook->rtpChDbgs[ch].uRecvSeqLost++; } } pGfarHook->recvIndex[ch] = seq_index; pGfarHook->rtpChDbgs[ch].uRecBytes++; if(&rtp_ch->rx[2] == krx) { krx = &rtp_ch->rx[0]; } else { krx++; } rtp_ch->current_krx = krx; ret = udphdr->len; } else { pGfarHook->rtpChDbgs[ch].uLostPackages++; pGfarHook->rtpChDbgs[ch].uBufStatus = (rtp_ch->rx[2].status << 2) | (rtp_ch->rx[1].status << 1) | (rtp_ch->rx[0].status); ret = 0; } } } return ret; } static int ipstack_hook_backlog(struct sk_buff* skb) { struct gfar_private* ugeth = netdev_priv(skb->dev); uint32_t qlen = 0; uint32_t ucc_num = ugeth->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)) { netif_stop_queue(ugeth->ndev); } } 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 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, rtplen, tp; struct gfar_private* ugeth = netdev_priv(skb->dev); struct ipstack_hook_t* pGfarHook = &ipstack_hook_p1010[ugeth->ucc_num]; //uint32_t ucc_num = ugeth->ucc_num; ip_prot = *(uint16_t*)&skb->data[0xc]; rtplen = skb->len - 54; tp = (rtplen % 80 == 0) ? rtplen / 80 : -1; if(tp > 0 && tp < 5) { 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)) { // PRTP_CH_DETAILS g_rtp = ipstack_hook_get_grtp(ugeth); ch = *(uint16_t*)&skb->data[0x2e]; rtp_port = *(uint16_t*)&skb->data[0x30]; if(ch >= 0 && ch < pGfarHook->rtpCfgCh) { PRTP_CH_DETAILS rtp_ch = ipstack_hook_get_grtp(ugeth) + 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; } rtp_ch->sk = skb->sk; skb->sk->sk_user_data = (void*)rtp_ch; pGfarHook->linkIPAddr[ch] = *(unsigned int*)&skb->data[0x1E]; pGfarHook->rtpChDbgs[ch].uRecBytes = 0; pGfarHook->rtpChDbgs[ch].uSendBytes = 0; pGfarHook->rtpChDbgs[ch].uUDPRecPackages = 0; pGfarHook->rtpChDbgs[ch].uLostPackages = 0; pGfarHook->rtpChDbgs[ch].uRecvSeqLost = 0; pGfarHook->rtpChDbgs[ch].uSendSeqLost = 0; pGfarHook->sendIndex[ch] = 0xFFFFFFFF; pGfarHook->recvIndex[ch] = 0xFFFFFFFF; // printk("ch %d dest ip = 0x%08X\n", ch, g_DestIpAddr[ch]); } dev_kfree_skb(skb); return NETDEV_TX_OK; } } } pGfarHook->backlog(skb); return NETDEV_TX_OK; } static int g_rtp_init(struct gfar_private* ugeth) { PRTP_CH_DETAILS rtp_tmp; struct txfcb* fcb = NULL; struct ipstack_hook_t* pGfarHook = ipstack_hook_get(ugeth->ucc_num); int j, k, i; i = ugeth->ucc_num; rtp_tmp = ipstack_hook_get_grtp(ugeth); if(!rtp_tmp) { return -ENOMEM; } memset(rtp_tmp, 0, sizeof(RTP_CH_DETAILS) * MAX_RTP_CH); memset(pGfarHook->rtpPortIndex, 0xFF, sizeof(pGfarHook->rtpPortIndex)); for(j = 0; j < pGfarHook->rtpMaxCh; j++) { PRTP_CH_DETAILS rtp_ch = rtp_tmp + 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++) { fcb = (struct txfcb*)rtp_ch->tx[k].fcb; fcb->flags = TXFCB_DEFAULT | TXFCB_UDP | TXFCB_TUP | TXFCB_CTU; fcb->l3os = 14; fcb->l4os = 20; 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].data = (char*)dev_new_skb(ugeth); rtp_ch->rx[k].skb = rtp_ch->rx[k].data; } pGfarHook->rtpChDbgs[j].uRecBytes = 0; pGfarHook->rtpChDbgs[j].uSendBytes = 0; pGfarHook->rtpChDbgs[j].uUDPRecPackages = 0; pGfarHook->rtpChDbgs[j].uLostPackages = 0; pGfarHook->rtpPortIndex[j] = 0xFFFF; } return 0; } static int ipstack_hook_init(struct gfar_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(&g_geths_ref[i], 1)) { msleep(2); } ret = g_rtp_init(ugeth); g_geths[i] = ugeth; g_geths_ref[i] = 0; printk("ucc %d hook = %p\n", i, ipstack_hook_p1010[i].do_sock_recv); #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; #endif return ret; } static int ipstack_hook_exit(struct gfar_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(&g_geths_ref[i], 1)) { msleep(2); } g_geths[i] = NULL; /* driver auto free device's all skb, so.... */ //g_rtp_exit(ugeth); g_geths_ref[i] = 0; return 0; } #if 0 static int gfar_proc_show(struct seq_file* m, void* v) { unsigned int i = 0; PRTP_CH_DETAILS pRtp = NULL; seq_printf(m, "--------GFAR ETH DRIVER INFO--------\n"); seq_puts(m, "\n"); seq_printf(m, "irq cnt: %u\n", g_irq_cnt); seq_printf(m, "RTP PORT BASE = %d(0x%08X)\n", g_RtpPortBase, g_RtpPortBase); for(i = 0; i < UMB_MAX_RTP_CFG; i++) { if(g_RtpPortIndex[i] != 0xFFFF) { seq_printf(m, "Ch %u Port %d\n", g_RtpPortIndex[i], i); } } #if 1 for(i = 0; i < UMB_MAX_RTP_CH; i++) { pRtp = ipstack_hook_get_grtp(g_geths[0]) + i; if(pRtp->sk != NULL) { seq_printf(m, "Ch %d Send MAC: %02X:%02X:%02X:%02X:%02X:%02X/%02X:%02X:%02X:%02X:%02X:%02X\n\n", i, pRtp->tx[0].data[0], pRtp->tx[0].data[1], pRtp->tx[0].data[2], pRtp->tx[0].data[3], pRtp->tx[0].data[4], pRtp->tx[0].data[5], pRtp->tx[1].data[0], pRtp->tx[1].data[1], pRtp->tx[1].data[2], pRtp->tx[1].data[3], pRtp->tx[1].data[4], pRtp->tx[1].data[5]); } } for(i = 0; i < UMB_MAX_RTP_CH; i++) { pRtp = ipstack_hook_get_grtp(g_geths[0]) + i; if(pRtp->sk != NULL) { seq_printf(m, "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, pRtp->current_krx, pRtp->current_krx->status, pRtp->current_krx->len, pRtp->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++ ); } } #endif return 0; } static int gfar_proc_open(struct inode* inode, struct file* file) { return single_open(file, gfar_proc_show, NULL); } static ssize_t gfar_proc_write(struct file* file, const char __user* userbuf, size_t count, loff_t* data) { char buf[20]; if(count >= sizeof(buf)) { printk("Input Params Error:count = %d, max size = %d\n", count, sizeof(buf)); return -1; } if(copy_from_user(buf, userbuf, count)) { printk("Copy Data To Kernel Error\n"); return -2; } buf[count] = '\0'; if(strict_strtoul(buf, 0, (long unsigned int*)&g_GfarOption)) { return -3; } printk("Set Options To [%u]\n", g_GfarOption); return count; } static const struct file_operations gfar_proc_fops = { .open = gfar_proc_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, .write = gfar_proc_write, }; #endif static int rtp_kbuf_init(void) { int i; InitDebugInfoProc("gfar"); 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); } } for(i = 0; i < UMB_MAX_GETH; i++) { struct ipstack_hook_t* pGfarHook = &ipstack_hook_p1010[i]; pGfarHook->kmap_len = sizeof(RTP_CH_DETAILS) * MAX_RTP_CH; pGfarHook->kmap_addr = (uint8_t*)__get_free_pages(GFP_DMA32 | GFP_ATOMIC, get_order(pGfarHook->kmap_len)); if(pGfarHook->kmap_addr) { pGfarHook->kmap_phy = virt_to_phys(pGfarHook->kmap_addr); } pGfarHook->kmap_end = (pGfarHook->kmap_addr + pGfarHook->kmap_len); memset(pGfarHook->kmap_addr, 0, pGfarHook->kmap_len); pGfarHook->pRtpChDetails = (PRTP_CH_DETAILS)pGfarHook->kmap_addr; } return 0; } static int rtp_kbuf_exit(void) { int i; for(i = 0; i < UMB_MAX_GETH; i++) { struct ipstack_hook_t* pGfarHook = &ipstack_hook_p1010[i]; if(pGfarHook->kmap_addr) { free_pages((unsigned long)pGfarHook->kmap_addr, get_order(pGfarHook->kmap_len)); pGfarHook->pRtpChDetails = NULL; } } for(i = 0; i < sizeof(g_DbgFSConfig) / sizeof(g_DbgFSConfig[0]); i++) { DebugFsUnRegister(&g_DbgFSConfig[i]); } DeInitDebugInfoProc(); return 0; } static int timer_1ms_handle(void* pData) { /* if(g_irq_cnt % 1000 == 0) { struct timeval ts; //printk("%d.%d - %d.%d\n", ts.tv_sec, ts.tv_usec, g_Clock.tv_sec, g_Clock.tv_usec); //printk("need = %d, rlt = %d, newTimerCnt = %d\n", need, rlt, newTimerCnt); do_gettimeofday(&ts); printk("Cnt = %d, Time:%d.%d\n", g_irq_cnt, ts.tv_sec, ts.tv_usec / 1000); } */ if(irq_flags & IRQ_STOP) { #ifdef USED_FSL_TIMER unregister_mpic_timer_irq(g_1ms_timer); #else unregister_ext_timer_irq(g_1ms_timer); #endif return 0; } g_irq_cnt++; geth_timer_hook(g_irq_cnt); if(irq_flags & IRQ_STOP) { #ifdef USED_FSL_TIMER unregister_mpic_timer_irq(g_1ms_timer); #else unregister_ext_timer_irq(g_1ms_timer); #endif return 0; } return 0; } int geth_timer_init(int ms) { LOG_EX(LOG_Info, "USED MPIC TIMER......\n"); mrs_irq_init(); #ifdef USED_FSL_TIMER g_1ms_timer = register_mpic_timer_irq(timer_1ms_handle, NULL); #else g_1ms_timer = register_ext_timer_irq(timer_1ms_handle, NULL); #endif rtp_kbuf_init(); return 0; } int geth_timer_exit(void) { irq_flags |= IRQ_STOP; #ifdef USED_FSL_TIMER unregister_mpic_timer_irq(g_1ms_timer); #else unregister_ext_timer_irq(g_1ms_timer); #endif msleep(10); rtp_kbuf_exit(); mrs_irq_exit(); return 0; } static struct ipstack_hook_t ipstack_hook_p1010[UMB_MAX_GETH] = { { .hook_init = ipstack_hook_init, .hook_exit = ipstack_hook_exit, .xmit_filter = ipstack_hook_xmit_filter, .backlog = ipstack_hook_backlog, .hook_xmit = 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, .rtpMaxCh = MAX_RTP_CH, .rtpBasePort = 0xFFFF, .rtpPortStep = 0, .rtpCfgCh = 0, }, { .hook_init = ipstack_hook_init, .hook_exit = ipstack_hook_exit, .xmit_filter = ipstack_hook_xmit_filter_eth2, .backlog = ipstack_hook_backlog, .hook_xmit = 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, .rtpMaxCh = MAX_SIP_CH, .rtpBasePort = 0xFFFF, .rtpPortStep = 0, .rtpCfgCh = 0, }, { .hook_init = ipstack_hook_init, .hook_exit = ipstack_hook_exit, .backlog = ipstack_hook_backlog, .xmit_filter = ipstack_hook_xmit_filter_eth2, .hook_xmit = 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, .rtpMaxCh = MAX_SIP_CH, .rtpBasePort = 0xFFFF, .rtpPortStep = 0, .rtpCfgCh = 0, }, }; static int DbgFS_GianfarARPShow(struct seq_file* seq, void* token) { unsigned int opt = g_DbgFSConfig[0].params; int i = 0; int ucc = opt > 2 ? 0 : opt; PRTP_CH_DETAILS pRtpBase = ipstack_hook_get_grtp(g_geths[ucc]); struct ipstack_hook_t* pGfarHook = ipstack_hook_get(ucc); if(token == SEQ_START_TOKEN) { seq_printf(seq, "Gainfar ETH%d RTP Ch ARP Mac Info:\n", ucc); seq_printf(seq, "---------------------------------------------------\n"); for(i = 0; i < pGfarHook->rtpCfgCh; i++) { PRTP_CH_DETAILS pRtp = pRtpBase + i; if(pRtp->sk != NULL) { seq_printf(seq, "Ch %d Send MAC: %02X:%02X:%02X:%02X:%02X:%02X/%02X:%02X:%02X:%02X:%02X:%02X\n\n", i, pRtp->tx[0].data[0], pRtp->tx[0].data[1], pRtp->tx[0].data[2], pRtp->tx[0].data[3], pRtp->tx[0].data[4], pRtp->tx[0].data[5], pRtp->tx[1].data[0], pRtp->tx[1].data[1], pRtp->tx[1].data[2], pRtp->tx[1].data[3], pRtp->tx[1].data[4], pRtp->tx[1].data[5]); } } } return 0; } static int DbgFS_GianfarChRTPShow(struct seq_file* seq, void* token) { unsigned int opt = g_DbgFSConfig[1].params; int i = 0; int ucc = opt > 2 ? 0 : opt; struct ipstack_hook_t* pGfarHook = ipstack_hook_get(ucc); PRTP_CH_DETAILS pRtpBase = ipstack_hook_get_grtp(g_geths[ucc]); if(token == SEQ_START_TOKEN) { seq_printf(seq, "irq cnt: %u\n", g_irq_cnt); seq_printf(seq, "Gainfar ETH%d Ch RTP Info:\n", ucc); seq_printf(seq, "---------------------------------------------------\n"); for(i = 0; i < pGfarHook->rtpMaxCh; i++) { PRTP_CH_DETAILS pRtp = pRtpBase + i; if(pRtp->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, pRtp->current_krx, pRtp->current_krx->status, pRtp->current_krx->len, pRtp->sk, pGfarHook->rtpChDbgs[i].uSendBytes, pGfarHook->rtpChDbgs[i].uRecBytes, pGfarHook->rtpChDbgs[i].uSendSeqLost, pGfarHook->rtpChDbgs[i].uRecvSeqLost, pGfarHook->rtpChDbgs[i].uLostPackages, pGfarHook->rtpChDbgs[i].uBufStatus, pGfarHook->rtpChDbgs[i].uUDPRecPackages ); } } } return 0; } static int DbgFS_GianfarChPortShow(struct seq_file* seq, void* token) { unsigned int opt = g_DbgFSConfig[2].params; int i = 0; int ucc = opt > 2 ? 0 : opt; struct ipstack_hook_t* pGfarHook = ipstack_hook_get(ucc); if(token == SEQ_START_TOKEN) { seq_printf(seq, "Gainfar ETH%d Ch Port Info:\n", ucc); seq_printf(seq, "---------------------------------------------------\n"); seq_printf(seq, "RTP PORT BASE = %u, Max Ch = %u, Configured Ch = %u\n", pGfarHook->rtpBasePort, pGfarHook->rtpMaxCh, pGfarHook->rtpCfgCh); for(i = 0; i < pGfarHook->rtpMaxCh; i++) { if(pGfarHook->rtpPortIndex[i] != 0xFFFF) { seq_printf(seq, "Ch %u Port %d\n", pGfarHook->rtpPortIndex[i], pGfarHook->rtpBasePort + (i * pGfarHook->rtpPortStep)); } } } return 0; } #ifdef EN_SIP_SWITCH static int DbgFS_SipArpShow(struct seq_file* seq, void* token) { unsigned int opt = g_DbgFSConfig[4].params; unsigned char mac[12]; int ret, i = 0; if(token == SEQ_START_TOKEN) { for(i = 0; i < 3; i++) { if(g_geths[i] != NULL) { ret = get_mac_form_ip(mac, i, g_geths[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_geths[i]->ucc_num, (g_geths[i]->chGWIpAddr >> 24) & 0xFF, (g_geths[i]->chGWIpAddr >> 16) & 0xFF, (g_geths[i]->chGWIpAddr >> 8) & 0xFF, g_geths[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, 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, 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); } } } static int DbgFS_GianfarSipPortShow(struct seq_file* seq, void* token) { unsigned int opt = g_DbgFSConfig[3].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_geths[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_geths[i], g_geths[i]->ucc_num, (g_geths[i]->chIpAddr >> 24) & 0xFF, (g_geths[i]->chIpAddr >> 16) & 0xFF, (g_geths[i]->chIpAddr >> 8) & 0xFF, g_geths[i]->chIpAddr & 0xFF, (g_geths[i]->chGWIpAddr >> 24) & 0xFF, (g_geths[i]->chGWIpAddr >> 16) & 0xFF, (g_geths[i]->chGWIpAddr >> 8) & 0xFF, g_geths[i]->chGWIpAddr & 0xFF, (g_geths[i]->chGWMask >> 24) & 0xFF, (g_geths[i]->chGWMask >> 16) & 0xFF, (g_geths[i]->chGWMask >> 8) & 0xFF, g_geths[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 In IP: %d.%d.%d.%d\n", (pCh->portRTP.chLinkInfo.inTarget.ipAddr >> 24) & 0xFF, (pCh->portRTP.chLinkInfo.inTarget.ipAddr >> 16) & 0xFF, (pCh->portRTP.chLinkInfo.inTarget.ipAddr >> 8) & 0xFF, pCh->portRTP.chLinkInfo.inTarget.ipAddr & 0xFF); seq_printf(seq, "RTP In Port: %d\n", pCh->portRTP.chLinkInfo.inTarget.ipPort); seq_printf(seq, "RTP In Mac: %02X:%02X:%02X:%02X:%02X:%02X\n", pCh->portRTP.chLinkInfo.inTarget.ethAddr[0], pCh->portRTP.chLinkInfo.inTarget.ethAddr[1], pCh->portRTP.chLinkInfo.inTarget.ethAddr[2], pCh->portRTP.chLinkInfo.inTarget.ethAddr[3], pCh->portRTP.chLinkInfo.inTarget.ethAddr[4], pCh->portRTP.chLinkInfo.inTarget.ethAddr[5]); seq_printf(seq, "RTP Used Target: 0x%08X\n\n", pCh->portRTP.chLinkInfo.usdTarget); seq_printf(seq, "RTP Stun Tag: %d\n", pCh->portRTP.chLinkInfo.stunTags); 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", pCh->sipDebug.eth0_seq_error); seq_printf(seq, "ETH0 drop: %d\n\n", pCh->sipDebug.eth0_drop_src); 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); seq_printf(seq, "ETHx drop: %d\n\n", pCh->sipDebug.ethx_drop_src); if(g_CheckRFC2833) { seq_printf(seq, "ETHx Error Dtmf: %d\n", pCh->sipDebug.ethx_rfc2833_error); seq_printf(seq, "ETHx Drv Err Dtmf: %d\n", pCh->sipDebug.drv_rcv_rfc2833_error); } seq_printf(seq, "ETHx Rcv Dtmf: %d\n", pCh->sipDebug.ethx_rfc2833_recv); seq_printf(seq, "ETHx Rcv lost Dtmf: %d\n", pCh->sipDebug.ethx_rfc2833_rcv_lost); seq_printf(seq, "ETHx Snd lost Dtmf: %d\n", pCh->sipDebug.ethx_rfc2833_snd_lost); seq_printf(seq, "ETHx 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); 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 * 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) { #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.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 != 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; 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(pCh->portRTP.chStatus == CH_STATUS_UNKONWN) { return -1; } get_mac_form_ip(macAddr, pCh->sipETHId, 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; memset(pCh->portRTP.chLinkInfo.inTarget.ethAddr, 0xFF, ETH_ALEN); pCh->portRTP.chLinkInfo.inTarget.ipAddr = 0; pCh->portRTP.chLinkInfo.inTarget.ipPort = 0; pCh->portRTP.chLinkInfo.usdTarget = 0; 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]; get_mac_form_ip(macAddr, ETH_INTERFACE_0, 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); memset(pPort->chLinkInfo.inTarget.ethAddr, 0xFF, 6); pPort->chLinkInfo.inTarget.ipAddr = 0; pPort->chLinkInfo.inTarget.ipPort = 0; } } 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, __be32 gwaddr, __be32 gwmask) { struct gfar_private* pGfar = NULL; if(ethId <= ETH_INTERFACE_2) { pGfar = g_geths[ethId]; if(pGfar != NULL) { pGfar->chIpAddr = ipaddr; pGfar->chGWIpAddr = gwaddr; pGfar->chGWMask = gwmask; } if(gwaddr != 0) { make_arp_request(ethId, gwaddr); } } 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, 4); if(rlt == 4) { 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]; } 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) { pCh->sipDebug.ethx_rfc2833_snd_lost++; return -1; } } return i; } EXPORT_SYMBOL(sip_send_dtmf); static 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); } 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 = *(unsigned short*)(skb->data + 30 + 4); timeStamp = *(unsigned int*)(skb->data + 32 + 4); syncId = *(unsigned int*)(skb->data + 36 + 4); } else { dtmfIndex = *(unsigned char*)(skb->data + 40); endFlag = *(unsigned char*)(skb->data + 41); seqNumber = *(unsigned short*)(skb->data + 30); timeStamp = *(unsigned int*)(skb->data + 32); syncId = *(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); } } // 收到结束标记的清理 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++) { // 同一个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)) { if(kfifo_in(&pCh->dtmfRecvFifo, &dtmfIndex, 4) != 4) { 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) { PIP_ADDR_INFO pIpAddr = NULL; if(pPort->chLinkInfo.dstTarget.ipAddr == 0xFFFFFFFF || ethId == ETH_INTERFACE_0) { pIpAddr = &pPort->chLinkInfo.inTarget; pPort->chLinkInfo.usdTarget |= 1 << 3; } else { pIpAddr = &pPort->chLinkInfo.dstTarget; pPort->chLinkInfo.usdTarget |= 1 << 4; } if(pIpAddr->ethAddr[0] == 0xFF && pIpAddr->ethAddr[1] == 0xFF && pIpAddr->ethAddr[2] == 0xFF && pIpAddr->ethAddr[3] == 0xFF && pIpAddr->ethAddr[4] == 0xFF && pIpAddr->ethAddr[5] == 0xFF ) { return get_mac_form_ip(pIpAddr->ethAddr, ethId, pIpAddr->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; PIP_ADDR_INFO pIpAddr = NULL; PSIP_CH_DETIAL pCh = &g_SIPChInfo.pSipChDetial[sipCh]; struct sk_buff* skbSIP = skb_clone(skb, GFP_ATOMIC); struct gfar_private* ucc_drv = g_geths[ethId]; 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, skbSIP->len); pHead = (PPACKAGE_HEAD)skbSIP->data; if(pPort->chLinkInfo.dstTarget.ipAddr == 0xFFFFFFFF) { pIpAddr = &pPort->chLinkInfo.inTarget; pPort->chLinkInfo.usdTarget = 1 << 1; if(pIpAddr->ipAddr == 0 || pIpAddr->ipPort == 0) { dev_kfree_skb_any(skbSIP); return NULL; } } else { pIpAddr = &pPort->chLinkInfo.dstTarget; pPort->chLinkInfo.usdTarget = 1 << 2; } if(pPort->chLinkInfo.toRTPCh.isUpdate == 0) { if(pIpAddr->ethAddr[0] == 0xFF && pIpAddr->ethAddr[1] == 0xFF && pIpAddr->ethAddr[2] == 0xFF && pIpAddr->ethAddr[3] == 0xFF && pIpAddr->ethAddr[4] == 0xFF && pIpAddr->ethAddr[5] == 0xFF ) { get_mac_form_ip(pIpAddr->ethAddr, ETH_INTERFACE_0, pIpAddr->ipAddr, 5); } memcpy(pHead->ethHead.h_dest, pIpAddr->ethAddr, ETH_ALEN); pHead->ipHead.saddr = ucc_drv->chIpAddr; pHead->ipHead.daddr = pIpAddr->ipAddr; pHead->udpHead.source = g_SIPChInfo.iRTPPortBase + sipCh; pHead->udpHead.dest = pIpAddr->ipPort; memcpy(&pPort->chLinkInfo.toRTPCh.headValue, pHead, sizeof(PACKAGE_HEAD)); pPort->chLinkInfo.toRTPCh.isUpdate = 1; } else { PACKAGE_HEAD ipHead = *pHead; if((pIpAddr->ethAddr[0] == 0xFF && pIpAddr->ethAddr[1] == 0xFF && pIpAddr->ethAddr[2] == 0xFF && pIpAddr->ethAddr[3] == 0xFF && pIpAddr->ethAddr[4] == 0xFF && pIpAddr->ethAddr[5] == 0xFF) || pCh->sipDebug.cnt_eth0_2_ethx % 1000 == 0 ) { if(get_mac_form_ip(pIpAddr->ethAddr, ethId, pIpAddr->ipAddr, 6) == 0) { memcpy(&pPort->chLinkInfo.toRTPCh.headValue, pIpAddr->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) { 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*)(skbSIP->data + 42); 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(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 = pCh->portRTP.chLinkInfo.stunTags; pTags++; *pTags = pHead->udpHead.len - 8; 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(ipstack_hook_backlog(skbSIP) == 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); struct gfar_private* ucc_drv = g_geths[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 ) { get_mac_form_ip(pPort->chLinkInfo.dstTarget.ethAddr, ETH_INTERFACE_0, pPort->chLinkInfo.dstTarget.ipAddr, 7); } 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, ETH_INTERFACE_0, 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(ipstack_hook_backlog(skbSIP) == NETDEV_TX_OK) { pCh->sipDebug.cnt_ethx_2_eth0++; } return skbSIP; } static int ipstack_hook_udp_recv_sip(struct sk_buff* skb) { 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; struct gfar_private* ucc_drv = g_geths[ETH_INTERFACE_0]; int ucc = ((struct gfar_private*)netdev_priv(skb->dev))->ucc_num; struct sk_buff* skbSIP; unsigned short seq_index = *(unsigned short*)&skb->data[RECV_SEQ_POS]; unsigned char* pUdpData = (unsigned char*)(skb->data + 28); int udp_len = udphdr->len; // 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(iphdr->daddr != g_geths[ucc]->chIpAddr) { return 0; } // 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) { dev_kfree_skb_any(skb); return udp_len; } if(pCh->portRTP.chLinkInfo.dstTarget.ipAddr != 0xFFFFFFFF) { if(pCh->portRTP.chLinkInfo.dstTarget.ipAddr != iphdr->saddr || pCh->portRTP.chLinkInfo.dstTarget.ipPort != udphdr->source) { pCh->sipDebug.ethx_drop_src++; dev_kfree_skb_any(skb); return udp_len; } } pCh->portRTP.chLinkInfo.inTarget.ipAddr = iphdr->saddr; pCh->portRTP.chLinkInfo.inTarget.ipPort = udphdr->source; 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 { int iStatus = 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, ETH_INTERFACE_0) == -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 == 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) { 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, ETH_INTERFACE_0) == -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, ETH_INTERFACE_0) == -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; } #endif