【问题标题】:How do I receive raw, layer 2 packets in C/C++?如何在 C/C++ 中接收原始的第 2 层数据包?
【发布时间】:2011-04-01 09:46:25
【问题描述】:

如何在 POSIXy C++ 中接收第 2 层数据包?数据包只有 src 和 dst MAC 地址、类型/长度和自定义格式的数据。它们不是 TCP 或 UDP 或 IP 或 IGMP 或 ARP 或其他任何东西 - 它们是硬件人员给我的自制格式。

我的socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW) 永远不会从它的recvfrom() 返回。

我可以发送很好,但无论我在网络堆栈中抛出什么选项,我都无法接收。

(平台是 VxWorks,但我可以翻译 POSIX 或 Linux 之类的……)

接收代码(当前化身):

 int s;

 if ((s = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW)) < 0) {
  printf("socket create error.");
      return -1;
 }

   struct ifreq          _ifr;   
   strncpy(_ifr.ifr_name, "lltemac0", strlen("lltemac0"));
   ioctl(s, IP_SIOCGIFINDEX, &_ifr);

   struct sockaddr_ll _sockAttrib;
   memset(&_sockAttrib, 0, sizeof(_sockAttrib));
   _sockAttrib.sll_len      = sizeof(_sockAttrib);
   _sockAttrib.sll_family   = AF_PACKET;
   _sockAttrib.sll_protocol = IFT_ETHER;
   _sockAttrib.sll_ifindex  = _ifr.ifr_ifindex;
   _sockAttrib.sll_hatype   = 0xFFFF;
   _sockAttrib.sll_pkttype  = PACKET_HOST;
   _sockAttrib.sll_halen    = 6;
   _sockAttrib.sll_addr[0]  = 0x00;
   _sockAttrib.sll_addr[1]  = 0x02;
   _sockAttrib.sll_addr[2]  = 0x03;
   _sockAttrib.sll_addr[3]  = 0x12;
   _sockAttrib.sll_addr[4]  = 0x34;
   _sockAttrib.sll_addr[5]  = 0x56;
   int _sockAttribLen = sizeof(_sockAttrib);


 char packet[64];
 memset(packet, 0, sizeof(packet));

   if (recvfrom(s, (char *)packet, sizeof(packet), 0,
                (struct sockaddr *)&_sockAttrib, &_sockAttribLen) < 0)
   {
      printf("packet receive error.");
   }

   // code never reaches here

【问题讨论】:

标签: c++ c sockets posix vxworks


【解决方案1】:

首先您需要将协议指定为 ETH_P_ALL 以便您的接口获取所有数据包。将您的套接字设置为混杂模式。然后在执行接收之前将您的 RAW 套接字绑定到接口。

【讨论】:

    【解决方案2】:

    我认为这样做的方法是编写自己的网络服务,该服务绑定到 VxWorks 网络堆栈中的 MUX 层。这在 VxWorks Network Programmer's Guide 中有很好的记录,我已经做过很多次了。

    自定义网络服务可以配置为查看使用 MUX_PROTO_SNARF 服务类型的网络接口上接收的所有第 2 层数据包,这是 Wind River 自己的 WDB 协议的工作方式,或具有特定协议类型的数据包。

    还可以通过编写位于网络服务和套接字 API 之间的自定义套接字后端来向自定义网络服务添加套接字接口。如果您愿意在网络服务中进行应用程序处理,则不需要这样做。

    您还没有说您使用的是哪个版本的 VxWorks,但我认为以上内容适用于 VxWorks 5.5.x 和 6.x

    【讨论】:

    • 谢谢。我走的是懒惰的路线,只是在数据包进入网络堆栈之前从赛灵思代码中复制了数据包。你的方式将是......不懒惰,不落后于计划的方式...... :)
    【解决方案3】:

    您是否尝试过通过 Wireshark 确认数据包实际上是从另一端发送的?

    此外,对于调试,请询问您的硬件人员是否有调试引脚(您可以连接到逻辑分析仪),以便在收到数据包时进行断言。只是为了确保硬件可以正常接收数据包。

    【讨论】:

    • 这一切都在一个 FPGA 中,所以它不能被鲨鱼。硬件说它有效,所以我现在必须这样做。
    【解决方案4】:

    我认为这将是一个比您预期的更难解决的问题。鉴于它根本不是 IP(或者显然任何其他协议都可以识别),我认为您无法完全使用用户级代码解决您的问题。在 Linux 上,我认为您需要编写自己的 device agnostic interface 驱动程序(可能使用 NAPI)。让它在 VxWorks 下运行几乎肯定不是一件容易的事(更像是从头开始完全重写,而不是大多数人认为的移植)。

    【讨论】:

      【解决方案5】:

      您是否尝试按照packet(7) 中的规定将套接字协议设置为htons(ETH_P_ALL)?您所做的与 IP 没有太大关系(尽管IPPROTO_RAW 可能是一些通配符值,不知道)

      【讨论】:

      • 正确答案 - 传递给 socket() 的协议不应该是 IPPROTO_RAW,它应该是您的自定义协议的以太网 (802.3) 协议 ID,按网络字节顺序排列。跨度>
      • 也许开始阅读手册页并检查您在那里猜到的任何参数。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-17
      • 1970-01-01
      • 2014-11-30
      • 2017-05-10
      • 1970-01-01
      相关资源
      最近更新 更多