关于以太网(Ethernet II)这个网络的个人理解以及应用(2)
阅读原文时间:2021年04月21日阅读:1

惩戒上篇文章,这里说下实际的开发应用,
在stm32f107环境下实现如下功能:
- 以太网接口用作串口使用(区别于C/S模型);
- 以太网接口接收全部的网内数据;
- 对网内数据包过滤,仅接收本机相关数据包及广播包;

工具:

anysend.exe:Anysend是基于Winpcap驱动开发的,实现以太网接口发送任意自组数据包的工具,各位请自行查找下载;
wireshark.exe:网络抓包工具
如果你是一个嵌入式开发人员,
MDK:嵌入式集成开发环境;
开发板:板载stm32f107处理器+PHY的开发板;

简要说下以太网外设:

以太网外设框图:

使用SMI接口(MDC、MDIO)读写PHY寄存器,参见下图的指引:

DMA发送描述符(接收描述符–略):

相关寄存器的配置,主要关注MAC寄存器和DMA寄存器:

可能用到的MAC、DMA相关寄存器如下:

源码流程图如下:

部分源码:

接收数据处理程序:

/**
  * @brief  Called when a frame is received
  * @param  None
  * @retval None
  */
void ETH_RxPkt_Handle(void)
{
    u8 *buffer;
    u16 len;
  FrameTypeDef frame;
    frame = ETH_RxPkt_ChainMode();
    /* Obtain the size of the packet and put it into the "len"
     variable. */
  len = frame.length;
    buffer= (u8*)frame.buffer;
    memcpy(buff_rx,(u8*)&buffer[0], len);
    /* Set Own bit of the Rx descriptor Status: gives the buffer back to ETHERNET DMA
    设置Rx描述符Status的 OWN位*/
  frame.descriptor->Status = ETH_DMARxDesc_OWN;
    /* When Rx Buffer unavailable flag is set: clear it and resume reception 
    Rx缓冲区不可用时,清除ETH_DMASR_RBUS并且恢复接收*/
  if ((ETH->DMASR & ETH_DMASR_RBUS) != (u32)RESET)  
  {
    /* Clear RBUS ETHERNET DMA flag */
    ETH->DMASR = ETH_DMASR_RBUS;
    /* Resume DMA reception */
    ETH->DMARPDR = 0;
  }
    //ETH_DMA_test();
}

获取接收到的数据信息(DMA描述符)

/*******************************************************************************
* Function Name  : ETH_RxPkt_ChainMode
* Description    : 获取接收到的数据信息(DMA描述符)
* Input          : None
* Output         : None
* Return         : frame: farme size and location
*******************************************************************************/
FrameTypeDef ETH_RxPkt_ChainMode(void)
{
  u32 framelength = 0;
  FrameTypeDef frame = {0,0}; 

  /* Check if the descriptor is owned by the ETHERNET DMA (when set) or CPU (when reset)
    检查这个描述符在被谁占用,DMA? CPU?*/
  if((DMARxDescToGet->Status & ETH_DMARxDesc_OWN) != (u32)RESET)
  { //不等于0,表示DMA正在使用描述符对应的缓冲区, 0==CPU占有,1==DMA占有,
      frame.length = ETH_ERROR;

    if ((ETH->DMASR & ETH_DMASR_RBUS) != (u32)RESET)  
    {
      /* Clear RBUS ETHERNET DMA flag */
      ETH->DMASR = ETH_DMASR_RBUS;
      /* Resume DMA reception */
      ETH->DMARPDR = 0;
    }

    /* Return error: OWN bit set */
    return frame; 
  }

  if(((DMARxDescToGet->Status & ETH_DMARxDesc_ES) == (u32)RESET) && //无相关错误
     ((DMARxDescToGet->Status & ETH_DMARxDesc_LS) != (u32)RESET) &&  //这个描述符指向的缓冲区是帧的最后一个缓冲区
     ((DMARxDescToGet->Status & ETH_DMARxDesc_FS) != (u32)RESET))  //这个描述符包含帧的第一个缓冲区
  {      
    /* Get the Frame Length of the received packet: substruct 4 bytes of the CRC 
        获取接收数据包的长度,需要减掉4字节的CRC*/
    framelength = ((DMARxDescToGet->Status & ETH_DMARxDesc_FL) >> ETH_DMARxDesc_FrameLengthShift) - 4;

    /* Get the addrees of the actual buffer */
    frame.buffer = DMARxDescToGet->Buffer1Addr; 
  }
  else
  {
    /* Return ERROR */
    framelength = ETH_ERROR;
  }

  frame.length = framelength;


  frame.descriptor = DMARxDescToGet;

  /* Update the ETHERNET DMA global Rx descriptor with next Rx decriptor 
    更新DMA全局Rx描述符成为下一个Rx描述符*/      
  /* Chained Mode ==链表模式*/    
  /* Selects the next DMA Rx descriptor list for next buffer to read 
    选择下一个DMA Rx描述符链表为下一个缓冲区去读*/ 
  DMARxDescToGet = (ETH_DMADESCTypeDef*) (DMARxDescToGet->Buffer2NextDescAddr);    

  /* Return Frame */
  return (frame);  
}

发送数据包的处理程序:

err_t ETH_TxPkt_Handle(u8* buff,u16 len)
{
  int l = 0;
  u8 *buffer =  (u8 *)ETH_GetCurrentTxBuffer();//获取当前的发送缓冲区地址
  memcpy((u8*)&buffer[l], buff, len);
  while(ETH_ERROR== ETH_TxPkt_ChainMode(len));
  return 0;
}

更新DMA发送描述符:

/*******************************************************************************
* Function Name  : ETH_TxPkt_ChainMode
* Description    : Transmits a packet, from application buffer, pointed by ppkt.
* Input          : - FrameLength: Tx Packet size.
* Output         : None
* Return         : ETH_ERROR: in case of Tx desc owned by DMA
*                  ETH_SUCCESS: for correct transmission
*******************************************************************************/
u32 ETH_TxPkt_ChainMode(u16 FrameLength)
{
  /* Check if the descriptor is owned by the ETHERNET DMA (when set) or CPU (when reset) */
  if((DMATxDescToSet->Status & ETH_DMATxDesc_OWN) != (u32)RESET)
  {  //被DMA占用
    /* Return ERROR: OWN bit set */
    return ETH_ERROR;
  }

  /* Setting the Frame Length: bits[12:0] 
    设置帧长*/
  DMATxDescToSet->ControlBufferSize = (FrameLength & ETH_DMATxDesc_TBS1);

  /* Setting the last segment and first segment bits (in this case a frame is transmitted in one descriptor) */    
  DMATxDescToSet->Status |= ETH_DMATxDesc_LS | ETH_DMATxDesc_FS;

  /* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */
  DMATxDescToSet->Status |= ETH_DMATxDesc_OWN;

  /* When Tx Buffer unavailable flag is set: clear it and resume transmission */
  if ((ETH->DMASR & ETH_DMASR_TBUS) != (u32)RESET)
  {
    /* Clear TBUS ETHERNET DMA flag */
    ETH->DMASR = ETH_DMASR_TBUS;
    /* Resume DMA transmission*/
    ETH->DMATPDR = 0;
  }

  /* Update the ETHERNET DMA global Tx descriptor with next Tx decriptor */  
  /* Chained Mode */
  /* Selects the next DMA Tx descriptor list for next buffer to send */ 
  DMATxDescToSet = (ETH_DMADESCTypeDef*) (DMATxDescToSet->Buffer2NextDescAddr);    


  /* Return SUCCESS */
  return ETH_SUCCESS;   
}

应用:

以太网接口用作串口使用(区别于C/S模型):

在MAC帧过滤寄存器上做文章:

ETH_InitStructure.ETH_ReceiveAll = ETH_ReceiveAll_Enable;//

关于发送数据环节,只能发送Ethernet II协议侦,不能发送IEEE802.3帧,问题查找中;

以太网接口接收全部的网内数据:

同上…

对网内数据包过滤,仅接收本机相关数据包及广播包;

ETH_InitStructure.ETH_ReceiveAll = ETH_ReceiveAll_Disable;//关闭接收所有的帧,来实现过滤掉 非本机为目的地址的数据
  ETH_InitStructure.ETH_BroadcastFramesReception = ETH_BroadcastFramesReception_Enable;//允许接收所有广播帧
  ETH_InitStructure.ETH_PromiscuousMode = ETH_PromiscuousMode_Disable;  //关闭混合模式的地址过滤  
  ETH_InitStructure.ETH_MulticastFramesFilter = ETH_MulticastFramesFilter_Perfect;//对于组播地址使用完美地址过滤   
  ETH_InitStructure.ETH_UnicastFramesFilter = ETH_UnicastFramesFilter_Perfect;//对单播地址使用完美地址过滤 

源码参考:

对网内数据包过滤,仅接收本机相关数据包及广播包”应用源码见网盘:
链接: http://pan.baidu.com/s/1qXFVzze 密码: gkka

这块说的比较笼统,毕竟以太网很庞大,本人理解有限,想说出来更加费劲,,,,大伙有情况再一块儿分析,,,,

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章