title: Capturing PTP packets with Linux raw socket
body: <p>I want to implement a C program that captures all the Precision-Time-Protocol (PTP) frames on the Ethernet, so I created a raw socket and attached a filter for PTP, I use recvmsg() to read data from the socket.
  The first issue is that I wasn't receiving any PTP frames so I commented out the filter but now I am not getting any Ethernet frames either.</p>
  <pre class="lang-c prettyprint-override"><code>#include &lt;stdio.h&gt;
  #include &lt;stdbool.h&gt;
  #include &lt;unistd.h&gt;
  #include &lt;errno.h&gt;
  #include &lt;string.h&gt;
  
  #include &lt;sys/ioctl.h&gt;
  #include &lt;sys/socket.h&gt;
  #include &lt;linux/if_packet.h&gt;
  #include &lt;linux/filter.h&gt;
  #include &lt;net/if.h&gt;
  #include &lt;net/ethernet.h&gt;
  #include &lt;arpa/inet.h&gt;
  
  #define PTP_IF_NAME               &quot;enx503eaa33fc9d&quot;
  #define PACKET_SIZE               300
  #define NUM_OF_BLOCKS_PER_LINE    30
  #define SIZE_OF_BYYE_PRINT_BLOCK  3
  #define SIZE_OF_PRINT_BUFFER      \
      ( ( NUM_OF_BLOCKS_PER_LINE * SIZE_OF_BYYE_PRINT_BLOCK ) + 1 )
  
  #define PERROR(x, ...)  printf( x &quot;stderr:%m\n&quot;, ##__VA_ARGS__) 
  #define INFO(x, ...)    printf( x &quot;\n&quot;, ##__VA_ARGS__)
  #define ERROR(x, ...)   printf( x &quot;\n&quot;, ##__VA_ARGS__)
  
  int eventSock = -1;
  
  void printBuffer(unsigned char* buffer, size_t len) {
      unsigned char outBuffer[SIZE_OF_PRINT_BUFFER];
      unsigned char* pOutBuffer = outBuffer;
      int usedBytes = 0;
  
      for (int i = 0; i &lt; len; i++) {
          if ((usedBytes + SIZE_OF_BYYE_PRINT_BLOCK) &gt; SIZE_OF_PRINT_BUFFER) {
              INFO(&quot;%s&quot;, outBuffer);
              memset(outBuffer, 0, sizeof(outBuffer));
              usedBytes = 0;
              pOutBuffer = outBuffer;
          }
          sprintf(pOutBuffer, &quot;%02x &quot;, buffer[i]);
          usedBytes += SIZE_OF_BYYE_PRINT_BLOCK;
          pOutBuffer += SIZE_OF_BYYE_PRINT_BLOCK;
      }
      INFO(&quot;%s&quot;, outBuffer);
  }
  
  int getInterfaceIndex(char *ifaceName) {
  
      int sockfd;
      struct ifreq ifr;
  
      sockfd = socket(AF_INET, SOCK_DGRAM, 0);
      if (sockfd &lt; 0) {
          ERROR(&quot;Could not retrieve interface index for %s&quot;, ifaceName);
          return -1;
      }
  
      memset(&amp;ifr, 0, sizeof(ifr));
      strncpy(ifr.ifr_name, ifaceName, IFNAMSIZ);
      if (ioctl(sockfd, SIOCGIFINDEX, &amp;ifr) &lt; 0) {
          PERROR(&quot;failed to request hardware address for %s&quot;, ifaceName);
          close(sockfd);
          return -1;
      }
  
      close(sockfd);
      return ifr.ifr_ifindex;
  }
  
  bool InitSocket(char *ifaceName) {
      int IfIndex;
      struct sockaddr_ll sll;
  
      IfIndex = getInterfaceIndex(ifaceName);
      if (IfIndex &lt; 0) {
          return false;
      }
  
      /* create the socket */
      if ((eventSock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) &lt; 0) {
          PERROR(&quot;failed to initialize raw socket&quot;);
          return false;
      }
  
      /* binding to the interface */
      memset(&amp;sll, 0, sizeof(sll));
      sll.sll_family = AF_PACKET;
      sll.sll_ifindex = IfIndex;
      sll.sll_protocol = htons(ETH_P_ALL);
  
      /* Bind the socket to the interface */
      if (bind(eventSock, (struct sockaddr *) &amp;sll, sizeof(sll)) &lt; 0) {
          PERROR(&quot;failed to bind raw event socket&quot;);
          return false;
      }
      
      /* bpf bytecode to filter only PTP packets (ethertype 0x88f7)
       * obtained via &quot;tcpdump -dd ether proto 0x88f7&quot; */
  //  struct sock_filter filter_ptp[] = {
  //          { 0x28, 0, 0, 0x0000000c }, // ldh [12]
  //          { 0x15, 0, 1, 0x000088f7 }, // jeq #0x88f7 jt 2 jf 3
  //          { 0x06, 0, 0, 0x00040000 }, // ret #262144
  //          { 0x06, 0, 0, 0x00000000 }, // ret #0
  //  };
  //
  //  struct sock_fprog bpf_ptp = { .len = 4, .filter = filter_ptp, };
  //
  //  if (setsockopt(eventSock, SOL_SOCKET, SO_ATTACH_FILTER, &amp;bpf_ptp,
  //                 sizeof(bpf_ptp))) {
  //      PERROR(&quot;failed attaching filter to raw event socket&quot;);
  //      return false;
  //  }
  }
  
  int waitForData(struct timeval * timeout, fd_set *readfds) {
      int ret, nfds;
      struct timeval tv, *tv_ptr;
  
      if (timeout) {
          tv.tv_sec = timeout-&gt;tv_sec;
          tv.tv_usec = timeout-&gt;tv_usec;
          tv_ptr = &amp;tv;
      } else {
          tv_ptr = NULL;
      }
  
      FD_ZERO(readfds);
      nfds = 0;
  
      FD_SET(eventSock, readfds);
      nfds = eventSock;
      nfds++;
  
      ret = select(nfds, readfds, 0, 0, tv_ptr);
      return ret;
  }
  
  void netr(void) {
      ssize_t ret = 0;
      char buf[1024];
      struct msghdr msg;
      struct iovec vec[1];
      struct sockaddr_in from_addr;
  
      union {
          struct cmsghdr cm;
          char control[256];
      } cmsg_un;
  
      struct cmsghdr *cmsg;
  
      vec[0].iov_base = buf;
      vec[0].iov_len = PACKET_SIZE;
  
      memset(&amp;msg, 0, sizeof(msg));
      memset(&amp;from_addr, 0, sizeof(from_addr));
      memset(buf, 0, PACKET_SIZE);
      memset(&amp;cmsg_un, 0, sizeof(cmsg_un));
  
      msg.msg_name = (caddr_t) &amp; from_addr;
      msg.msg_namelen = sizeof(from_addr);
      msg.msg_iov = vec;
      msg.msg_iovlen = 1;
      msg.msg_control = cmsg_un.control;
      msg.msg_controllen = sizeof(cmsg_un.control);
      msg.msg_flags = 0;
  
      ret = recvmsg(eventSock, &amp;msg, MSG_DONTWAIT);
      if (ret &lt; 0) {
          PERROR(&quot;failed to receive message!&quot;);
      }
  
      INFO(&quot;received Bytes: %ld&quot;, ret);
      printBuffer(msg.msg_iov-&gt;iov_base, PACKET_SIZE);
  }
  
  int main(void) {
      int ret;
      fd_set readfds;
      struct timeval timeout = { .tv_sec = 1, .tv_usec = 0 };
  
      INFO(&quot;main started!!&quot;);
  
      InitSocket(PTP_IF_NAME);
  
      while (1) {
          INFO(&quot;waiting for event!!&quot;);
          ret = waitForData(&amp;timeout, &amp;readfds);
          INFO(&quot;select return = %d&quot;, ret);
          if (ret &gt; 0) {
              if (FD_ISSET(eventSock, &amp;readfds)) {
                  netr();
              }
          }
      }
  }
  </code></pre>