How do I receive raw, layer 2 packets in C/C++?
Asked Answered
B

5

11

How do I receive layer 2 packets in POSIXy C++? The packets only have src and dst MAC address, type/length, and custom formatted data. They're not TCP or UDP or IP or IGMP or ARP or whatever - they're a home-brewed format given unto me by the Hardware guys.

My socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW) never returns from its recvfrom().

I can send fine, I just can't receive no matter what options I fling at the network stack.

(Platform is VxWorks, but I can translate POSIX or Linux or whatever...)

receive code (current incarnation):

 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
Biddie answered 19/8, 2010 at 22:32 Comment(3)
I'm glad you tagged this POSIX, good luck trying to do this on Windoze ;)Codfish
https://mcmap.net/q/1158344/-udp-sockets-in-c #1796374Lasonyalasorella
Just a nitpick: POSIX does not define C++ bindings, only C.Tannie
P
4

I think the way to do this is to write your own Network Service that binds to the MUX layer in the VxWorks network stack. This is reasonably well documented in the VxWorks Network Programmer's Guide and something I have done a number of times.

A custom Network Service can be configured to see all layer 2 packets received on a network interface using the MUX_PROTO_SNARF service type, which is how Wind River's own WDB protocol works, or packets with a specific protocol type.

It is also possible to add a socket interface to your custom Network Service by writing a custom socket back-end that sits between the Network Service and the socket API. This is not required if you are happy to do the application processing in the Network Service.

You haven't said which version of VxWorks you are using but I think the above holds for VxWorks 5.5.x and 6.x

Phillisphilly answered 20/8, 2010 at 9:14 Comment(1)
Thanks. I went the lazy route and just copied the packet from the Xilinx code before it got into the network stack. Your way would be the... not lazy, not behind schedule way... :)Biddie
Z
3

Have you tried setting the socket protocol to htons(ETH_P_ALL) as prescribed in packet(7)? What you're doing doesn't have much to do with IP (although IPPROTO_RAW may be some wildcard value, dunno)

Zworykin answered 19/8, 2010 at 22:46 Comment(2)
Correct answer - the protocol passed to socket() shouldn't be IPPROTO_RAW, it should be the ethernet (802.3) protocol ID for your custom protocol, in network-byte-order.Ectomere
maybe start reading man pages and check any arguments you have guessed in there.Zworykin
V
1

I think this is going to be a bit tougher problem to solve than you expect. Given that it's not IP at all (or apparently any other protocol anything will recognize), I don't think you'll be able to solve your problem(s) entirely with user-level code. On Linux, I think you'd need to write your own device agnostic interface driver (probably using NAPI). Getting it to work under VxWorks will almost certainly be non-trivial (more like a complete rewrite from the ground-up than what most people would think of as a port).

Vikkivikky answered 19/8, 2010 at 23:5 Comment(0)
S
0

Have you tried confirming via Wireshark that a packet has actually been sent from the other end?

Also, for debugging, ask your hardware guys if they have a debug pin (you can attach to a logic analyzer) that they can assert when it receives a packet. Just to make sure that the hardware is getting the packets fine.

Spires answered 19/8, 2010 at 23:47 Comment(1)
It's all inside an FPGA, so it can't be sharked. HW says it works, so I have to go with that for now.Biddie
P
0

First you need to specify the protocol as ETH_P_ALL so that your interface gets all the packet. Set your socket to be on promiscuous mode. Then bind your RAW socket to an interface before you perform a receive.

Pieter answered 30/3, 2016 at 15:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.