背景:

因项目需求,要在Uboot里面添加UDP通讯,广播功能,从主机获取一些参数配置(IP等)。Uboot没有TCP/IP协议栈,不支持TCP,只支持简单的网络协议,具体见/uboot_src/net/net.c

MAC问题

网络通讯的前提是有区别的MAC地址

  1. 烧写自己的MAC地址到Uboot
  2. 使用唯一的SN或UUID生成(节约MAC地址资源, 适用于局域网内)
    使用加密芯片全球唯一的SN,然后转化为MAC地址,检查MAC是否非法(is_valid_ether_addr(&sn[2])),非法则使用随机MAC(eth_random_addr(ethaddr);)
    setenv("ethaddr", ethaddr);保存MAC地址到uboot环境变量

Uboot增加UDP广播收发功能:

参考:https://segmentfault.com/a/1190000005273491

添加自定义的xx_udp.c和xx_udp.h

根据需要实现以下几部分(/uboot_src/net/):

实现开始和发送函数

void UdpStart(void)
{
    debug("%s\n", __func__);

    NetSetTimeout(UDP_TIMEOUT, UdpTimeout);/*超时处理回调*/
    net_set_udp_handler(UdpHandler); /*接受包处理回调*/
  memset(NetServerEther, 0, sizeof(NetServerEther));/*接受包*/

    UdpSend(); /*发送自己的包*/
}

主要是调用API函数:

NetSendUDPPacket(uchar   *ether,
              IPaddr_t dest,
              int      dport,
              int      sport,
              int      len);

说明:

  • ether:目标的以太网地址。如果是广播,则使用全局变量NetBroadcastAddr;如果未知,则指定全零的char[6]={0,0,0,0,0,0}
  • dest:目标的IP地址。如果是广播,则指定0;如果是单播,则指定一个ulong值,可使用string_to_ip()
  • dport:远端端口
  • sport:源端口
  • len:UDP包正文的长度

发送之前需要事先设置好正文,即

memcpy((char *)NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE, (char *)udp_pkt_data, udp_data_len);  
//udp_pkt_data为用户数据, udp_data_len为用户数据长度

实现超时回调函数

/*超时处理回调*/
static void UdpTimeout(void)
{
  puts("UdpTimeout\n");
  //如果未获取则重试
  if(getinfo_ok!=1)
    UdpStart();
  else
    net_set_state(NETLOOP_FAIL);// 结束NetLoop()
  return;
}
//    

实现接收回调函数

/*接受包处理回调*/
static void UdpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
      unsigned len) 
{
  debug("%s\n", __func__);
  printf("Receive udp packet: %s len:%d\n", pkt, len);

  //IP_t *ipPky = pkt - (IP_HDR_SIZE);//IP报头
  //IPAddr_t ipFrom = ipPkg->ip_src; //可以用于UDP response
  //...
}

/uboot_src/net/Makefile添加obj-$(CONFIG_CMD_UDP) += xx_udp.o

修改net.c和net.h

net.c (/uboot_src/include/net.c)

添加头文件

#if defined(CONFIG_CMD_UDP)
#include "spon_udp.h"
#endif

NetLoop()中添加自定义的执行分支

#if defined(CONFIG_CMD_UDP)
  case XXXUDP:
    UdpStart();
    break;
#endif

net.h (/uboot_src/include/net.h)

添加自定义的协议
enum proto_t {xxx, XXXUDP}
添加自定义的数据

#if defined(CONFIG_CMD_UDP)
extern IPaddr_t	UdpServerIP;
#endif

添加自定义命令(cmd_udp_xxx)

(具体可见Uboot添加自定义命令),来操作UDP通信

注: uboot里芯片厂商的MAC驱动过滤了广播包(MAC_PACKET_FILTER),修改相关驱动,原厂datasheet里缺少相关寄存器说明