⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 c3eth.c

📁 这是交换机或路由器的交换软件部分
💻 C
📖 第 1 页 / 共 5 页
字号:
    U32 anotherport;
    
    if( NULL == pMBuf )
    {
        AOS_ASSERT(0);
        return AOS_FAIL;
    }

    if ( dstport > CPU_ETH_PORT_NUM )
    {
          AOS_ASSERT(0);
          mbuf_destroy(pMBuf);
          return AOS_FAIL;
    }

    pBuf  = MBUF_MTOD(pMBuf,U8*);
    ulLen = MBUF_GET_TOTAL_DATA_LENGTH(pMBuf);

    /***********
    pBuf2 =eth_get_aligned_buff();
    if( pBuf2 )
    {
        pBuf2 += ETH_HEADER_RESERV_LEN;
        aos_memcpy(pBuf2,pBuf,ulLen);
        aos_dmem_free(pBuf);
        pBuf = pBuf2;
    }
    **************/
        
    if( g_bEthBridgeFlag )
    {
        if( g_bSoftBirdgeFlag )
        {
           // 只有WAN口和LAN口同时UP的时候才激活 g_bSoftBirdgeFlag
           // 软件桥模式下,需要模拟以太交换网的功能,发出的报文需要确定出口
           //根据报文目的MAC地址在L2 HASH表查找,确定报文的最终出口(0 or 1?)
           if( AOS_FAIL == eth_get_l2_dstport(pBuf,&dstport) )
           {   
              //如果查找结果为空,需要Flooding报文,将报文向两个出口发送
              //这个报文需要发送两次,增加内存块引用索引,避免内存释放两次
              #if 0
              mem_buf_inc_ref(mem_obj_head(pBuf));
              anotherport = ((dstport==0)?1:0);
              ///eth_send_packet(anotherport,pBuf,ulLen); 
              pktDesc.pBase = pBufCopy;
              pktDesc.pData = pBufCopy+ETH_HEADER_RESERV_LEN;
              pktDesc.len   = ulLen;
              iad_eth_pktSend(ethCfgBlk[anotherport].iadEthHnd,
                              &pktDesc);          
              #else
              // 另一种方法虽然开销大一点,拷贝一份,但更安全          
              pBufCopy = (U8*)eth_get_aligned_buff();
              if( pBufCopy )
              {                  
                  aos_memcpy(pBufCopy+ETH_HEADER_RESERV_LEN,pBuf,ulLen);          
                  anotherport = ((dstport==0)?1:0);
                  eth_send_packet( anotherport,
                                   pBufCopy+ETH_HEADER_RESERV_LEN,
                                   ulLen,
                                   ETH_COPY_SEND );
              }
              else
              {
                  AOS_ASSERT(0);  
              }
              #endif 
           }
        }
        else
        {
            //对双口网关,桥接模式下缺省网口为WAN口,当WAN口LinkDown的时候从LAN口发送
            if( !g_ulWanLinkStatus )
            {
                dstport = SERVICE_LAN_PORT;
            }        
        }
    }
    
    //释放mbuf控制头
    aos_dmem_free(pMBuf);                        
    eth_send_packet(dstport,pBuf,ulLen,ETH_NORMAL_SEND);
    
    return AOS_SUCC;
}


U32  eth_send(U32  if_ulPhyLink,  MBUF_S *pMBuf)
{
    U32   ulRet = 0;
    U32   ulBlockNum;
    U32   EthNum;
    
    EthNum=((ETH_DRV_IF *)if_ulPhyLink)->chan_usPort;
    if ( EthNum >= CPU_ETH_PORT_NUM )
    {
          AOS_ASSERT(0);
          return  AOS_FAIL;
    }
    
    if( NULL == pMBuf )
    {
        AOS_ASSERT(0);
        return AOS_FAIL;
    }

    // 网口未启动时,丢弃发送报文
    if(  !ethCfgBlk[EthNum].initCfgDone )  
    {
          mbuf_destroy(pMBuf);
          return AOS_FAIL;
    }

    if( (g_ulWanLinkStatus == FALSE) &&
        (g_ulLanLinkStatus == FALSE) )  
    {
          mbuf_destroy(pMBuf);
          return AOS_FAIL;
    }
    
    ulBlockNum = MBUF_GET_DATA_BLOCK_NUMBER(pMBuf);
    if( ulBlockNum  > 1 )
    {
        MBUF_COMPRESS(pMBuf, 1, MPE_ETH, ulRet );
        if( AOS_SUCC != ulRet )
        {
            AOS_ASSERT(0);
            mbuf_destroy( pMBuf);
            return AOS_FAIL;
        }
    }

    eth_send_mbuf_packet(EthNum,pMBuf);

    return AOS_SUCC;    
}    

#ifdef ETH_PHP_ENABLE
U32 eth_php_init(void)
{
    iad_phpInitPar InitPar;
    iad_queueReqPar qParam;
    U8             *pBuf;
    iad_Error errCode = IAD_SUCCESS;
    U32 i;

    // PHP使用了4个硬件队列,分别为PhpFreeQue,OverflowQue,TaskQue,ResultQue
    pBuf  = aos_dmem_alloc( MPE_ETH, SID_ETH_PHP, ALIGN_SIZE*5); 
    if( pBuf == NULL )
    {
        AOS_ASSERT(0);
        return AOS_FAIL;
    }
    
    if( (U32)pBuf%ALIGN_SIZE )
    {   
        // not alligned 补齐
        (U32)pBuf &=(~(ALIGN_SIZE-1));
    }
    
    //为php申请FreeQue硬件队列空间
    qParam.qType = IAD_QUEUE_HW;
    qParam.qBase = pBuf;
    qParam.qLen  = ALIGN_SIZE;
    qParam.elmLen= sizeof(unsigned int);
    if( (errCode = iad_queue_request( &qParam, &g_hPhpFreeHnd)) != IAD_SUCCESS )
    {
        aos_printf(MPE_SYS,"c3eth php free hardware queue error=0x%x",errCode);
        return AOS_FAIL;
    }

    //为php申请OverFlowQue硬件队列空间
    pBuf += ALIGN_SIZE;
    qParam.qType = IAD_QUEUE_HW;
    qParam.qBase = pBuf;
    qParam.qLen  = ALIGN_SIZE;
    qParam.elmLen= sizeof(unsigned int);
    if( (errCode = iad_queue_request( &qParam, &g_hPhpOverHnd)) != IAD_SUCCESS )
    {
        aos_printf(MPE_SYS,"c3eth php overflow queue error=0x%x",errCode);
        AOS_ASSERT(0);
        return AOS_FAIL;
    }

    pBuf += ALIGN_SIZE;
    qParam.qBase = pBuf;
    qParam.qLen  = ALIGN_SIZE;
    qParam.elmLen= sizeof(unsigned int);
    if( (errCode = iad_queue_request( &qParam, &g_hPhpTaskHnd)) != IAD_SUCCESS )
    {
        aos_printf(MPE_SYS,"c3eth php Task queue error=0x%x",errCode);
        return AOS_FAIL;
    }

    pBuf += ALIGN_SIZE;
    qParam.qBase = pBuf;
    qParam.qLen  = ALIGN_SIZE;
    qParam.elmLen= sizeof(unsigned int);
    if( (errCode = iad_queue_request( &qParam, &g_hResultHnd)) != IAD_SUCCESS )
    {
        aos_printf(MPE_SYS,"c3eth php result queue error=0x%x",errCode);
        return AOS_FAIL;
    }

    //The PHP freeQ is a pointer
    //queue where the pointer is pointing to a 64-byte PHP TD (task descriptor) 
    InitPar.phpMode     = IAD_PHP_AUTO_INGRESS_ONLY;
    InitPar.phpFreeQHnd = g_hPhpFreeHnd;
    InitPar.phpFreeQMin = 1;
    InitPar.phpFreeQMax = N_PHP_TD_NUM;
    InitPar.phpOverflowQHnd = g_hPhpOverHnd;
    InitPar.phpTaskQHnd     = g_hPhpTaskHnd;
    InitPar.systemFreeQHnd  = g_hPhpFreeHnd;
    errCode = iad_php_init(&InitPar);
    if( errCode != IAD_SUCCESS )
    {
        aos_printf( MPE_SYS, "c3eth php init error=0x%x",errCode);
        return AOS_FAIL;        
    }


    pBuf  = aos_dmem_alloc( MPE_ETH, SID_ETH_PHPTD, IAD_PHP_TASK_DESC_LEN*N_PHP_TD_NUM );     
    if( pBuf == NULL )
    {
        AOS_ASSERT(0);
        return AOS_FAIL;
    }

    for( i=0; i< N_PHP_TD_NUM; i++)
    {
        if( IAD_SUCCESS != iad_queue_put(g_hPhpFreeHnd,
                                         &pBuf,sizeof(void*)) )
        {
            AOS_ASSERT(0);
            return AOS_FAIL;
        }  
        pBuf += IAD_PHP_TASK_DESC_LEN;      
    }

    return AOS_SUCC;        
}

#endif

U32  eth_end( void )
{
    iad_eth_setEnableTx(ethCfgBlk[0].iadEthHnd, TRUE);
    iad_eth_setEnableRx(ethCfgBlk[1].iadEthHnd, TRUE);
    return AOS_SUCC;
}

/*******************************************************************************
*
* EthStart - start the device
*
* This function connect interrupts and start the
* device running in interrupt mode.
*
* RETURNS: OK or AOS_FAIL
*
*/
U32  eth_start( U32 ethnum)
{
    iad_eth_CfgBlk *p_ethCfgBlk;
    static BOOL_T   bInit = FALSE;
    U32             ulRet;
    
    p_ethCfgBlk = &ethCfgBlk[ethnum];

    if( bInit == FALSE )
    {
        bInit = TRUE; 

        // Poll任务只创建一次    
        ulRet = aos_task_create("ethpoll", 
                    10240,
                    TASK_PRIO_HIGHEST,
                    AOS_TASK_NOPREEMPT,
                    eth_recv_poll,
                    NULL,
                    &g_ulEthPollTaskId );   
                    
        if( AOS_SUCC != ulRet)
        {
            AOS_ASSERT(0);
            return AOS_FAIL;
        }                                
        
        // DMA Burst size 32bytes        
        //IAD_REG_WR(IAD_ETH1_REG_BASE_ADDR,IAD_ETH_REG_DMA_BURST_SZ,0);
        //IAD_REG_WR(IAD_ETH2_REG_BASE_ADDR,IAD_ETH_REG_DMA_BURST_SZ,0);

        // 中断模式启动可以减少延时,但是流量很大的时候开销急剧增加
        IAD_REG_WR(IAD_ETH1_REG_BASE_ADDR,IAD_ETH_REG_INTR_ENABLE,
                   IAD_RX_PACKET_DONE);
        IAD_REG_WR(IAD_ETH2_REG_BASE_ADDR,IAD_ETH_REG_INTR_ENABLE,
                   IAD_RX_PACKET_DONE);
        iad_interrupt_hook(IAD_IV_ETH0, (VOIDFUNCTIONPTR)eth_intr_proc, SERVICE_LAN_PORT); 
        iad_interrupt_hook(IAD_IV_ETH1, (VOIDFUNCTIONPTR)eth_intr_proc, SERVICE_WAN_PORT);

        if( FALSE == g_bEthPollMode )
        {            
            iad_enable_interrupt(IAD_IV_ETH0);
            iad_enable_interrupt(IAD_IV_ETH1);
        }
        
        if( g_bEthBridgeFlag )
        {
            g_pstL2MacHashTbl = hash_create_table(L2MAC_HASH_MAX_NUM , NULL);
            if(AOS_ADDR_INVALID(g_pstL2MacHashTbl))
            {
                AOS_ASSERT(0);
                return AOS_FAIL;
            } 
            // 启动周期定时器老化
           aos_callbacktimer_start(&g_L2AgeTmr, MPE_ETH, L2_AGING_PERIOD*1000,
                                   0,(U32)NULL, eth_l2mac_aging, AOS_TIMER_LOOP);

        }
        
        #ifdef ETH_PHP_ENABLE
        if( eth_php_init()!= AOS_SUCC )
        {
            AOS_ASSERT(0);
            return AOS_FAIL;        
        }
        #endif
        
    }    

    {
        U32 ethmode;

        if( ethnum == SERVICE_WAN_PORT )
            cfm_get_parameter(CMD_WAN_ETH_MODE, (VOID*)&ethmode, sizeof(U32));
        else
            cfm_get_parameter(CMD_LAN_ETH_MODE, (VOID*)&ethmode, sizeof(U32));        
                  
        //设置以太网工作模式
        eth_set_workmode( ethnum, ethmode);
    }     

    #ifdef ETH_PHP_ENABLE
    {
    iad_phpConnPar  ConnPar;
    iad_phpConnHnd  ConnHnd;

    // eth PHP AutoIngress Connection 
    // ConnHnd用于轮询任务里面的iad_php_pktRcv() AutoIngress Mode
    //                          iad_php_get()  Manual Mode
    ConnPar.connMode = IAD_PHP_AUTO_INGRESS_ONLY;
    ConnPar.ingress.autoI.inPortType = IAD_PHP_ETH;
    ConnPar.ingress.autoI.port.ethHnd = p_ethCfgBlk->iadEthHnd;
    ConnPar.ingress.autoI.uCodeSel = IAD_PHP_ETH_TCPIPCHKSUM_N_TCPHASH;
    ConnPar.resultQHnd = g_hResultHnd;
    ulRet = iad_php_connSetup( &ConnPar, &ConnHnd ); 
    if( IAD_SUCCESS != ulRet )
    {
        aos_printf(MPE_SYS,"c3eth php autoingress conn error=0x%x",ulRet);
        return AOS_FAIL;
    }   
    p_ethCfgBlk->hAutoConnHnd = ConnHnd;
    //aos_printf(MPE_SYS,"c3eth php autoingress conn id=%d",ConnHnd);
    }
    #endif

    /* Now, enable Tx and RX */
    iad_eth_setEnableTx(p_ethCfgBlk->iadEthHnd, TRUE);
    iad_eth_setEnableRx(p_ethCfgBlk->iadEthHnd, TRUE);

    p_ethCfgBlk->initCfgDone = TRUE;  
        
    return AOS_SUCC;
}

//每秒计算一次网口流速
void eth_packet_rate_proc(void)
{
    static U32 ulOrgCnt=0;
    U32 delta;
    
    // 对网关一个网口不可能产生高流速,所以采用WAN口为基准计算网口的流速
    if( ethCfgBlk[SERVICE_WAN_PORT].ethStatSum.ulRxTotalFrames >= ulOrgCnt )
    {
        delta=ethCfgBlk[SERVICE_WAN_PORT].ethStatSum.ulRxTotalFrames-ulOrgCnt;        
    }
    else
    {
        // 32位翻转
        delta= 0xFFFFFFFF-ulOrgCnt+ethCfgBlk[SERVICE_WAN_PORT].ethStatSum.ulRxTotalFrames;
    }
    ulOrgCnt = ethCfgBlk[SERVICE_WAN_PORT].ethStatSum.ulRxTotalFrames;

    //aos_printf(0,"eth wan delta=%d",delta);
    
    if( delta > g_ulEthHiRate )
    {
        if( FALSE == g_bEthPollMode )
            eth_recv_mode_switch(TRUE);
    }
    else if( delta < g_ulEthLowRate )
    {
        if( TRUE == g_bEthPollMode )
            eth_recv_mode_switch(FALSE);
    }

    //此次计算以太网接收模式不变化
    return;
}

void eth_recv_mode_switch(U32 bPollMode)
{    
    if( bPollMode )
    {        

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -