views:

43

answers:

1

I have the following code to open a raw socket and send over it. In the send function I have a trace statement showing me that the length of my packet is 21. However, when I view the packets on the receiving end using a packet sniffer, I see:

  1. The actual packet length is 60.
  2. The length (as given in the 802.3 header) is 256.

Neither of those numbers is 21, and I'm communicating with an embedded device that does not like the discrepancy. I've Googled around but I can't figure out how to make sendto() report the correct length.

bool EthernetSocket::_open(const char *ifname) {
  _sd = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_802_2));
  _ifname = ifname;
  _ifidx = Ethernet::GetInterface(ifname);
  if(_sd < 0) {
    perror("Failed to open socket");
    _bOpened = false;
  }
  else {
    _bOpened = true;
  }
  return _bOpened;
}


bool EthernetSocket::_send(const Buffer& txbuff, Address& addr) {
  if(txbuff.Length() == 0)
    return false;

  if(_ifidx != -1)
    addr.SetInterface(_ifidx);

printf("SEND: Length: %d\n", txbuff.Length());
  if(sendto(_sd, txbuff.Data(), txbuff.Length(), 0, (struct sockaddr *) addr.Component(), (socklen_t) addr.Size()) == -1) {
    perror("Failed broadcast");
    return false;
  }
  return true;
}

Edit: I've discovered that that field is being set to the sll_protocol field in my sockaddr_ll structure. But why? Setting it to htons(ETH_P_802_2), as it should be, does not help.

A: 

I have a partial answer.

Setting sll_protocol to htons(ETH_P_802_3) fixes the problem. I'm not sure why this is, as ETH_P_802_2 and ETH_P_802_3 are supposed to behave pretty much the same - and all the relevant kernel source I could find backs me up on this.

I receive packets via recvfrom() with protocol ETH_P_802_2, and the returned address consequently has its sll_protocol field set to ETH_P_802_2. This means that to reply, I have to manually set the field to ETH_P_802_3 after receiving data. This is an awful kludge.

What's going on??

Andrew Poelstra