xref: /openbmc/google-misc/subprojects/ncsid/src/ncsi_sockio.cpp (revision 7c15db6f4dcd1da68967ca2a463ef890d4521f56)
1  // Copyright 2021 Google LLC
2  //
3  // Licensed under the Apache License, Version 2.0 (the "License");
4  // you may not use this file except in compliance with the License.
5  // You may obtain a copy of the License at
6  //
7  //      http://www.apache.org/licenses/LICENSE-2.0
8  //
9  // Unless required by applicable law or agreed to in writing, software
10  // distributed under the License is distributed on an "AS IS" BASIS,
11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  // See the License for the specific language governing permissions and
13  // limitations under the License.
14  
15  #include "ncsi_sockio.h"
16  
17  #include "common_defs.h"
18  #include "net_iface.h"
19  
20  #include <linux/filter.h>
21  #include <linux/if.h>
22  #include <linux/if_ether.h>
23  #include <netinet/in.h>
24  #include <poll.h>
25  #include <sys/socket.h>
26  
27  #include <cstring>
28  #include <iterator>
29  
30  namespace ncsi
31  {
32  
init()33  int SockIO::init()
34  {
35      RETURN_IF_ERROR(sockfd_ = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)),
36                      "ncsi::SockIO::init() failed");
37      return 0;
38  }
39  
bind_to_iface(const net::IFaceBase & iface)40  int SockIO::bind_to_iface(const net::IFaceBase& iface)
41  {
42      struct packet_mreq mreq = {};
43      RETURN_IF_ERROR(mreq.mr_ifindex = iface.get_index(),
44                      "ncsi::SockIO::bind_to_iface get_index");
45      mreq.mr_type = PACKET_MR_PROMISC;
46      RETURN_IF_ERROR(setsockopt(sockfd_, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
47                                 &mreq, sizeof(mreq)),
48                      "ncsi::SockIO::bind_to_iface setsockopt failed");
49  
50      RETURN_IF_ERROR(iface.bind_sock(sockfd_),
51                      "ncsi::SockIO::bind_to_iface failed");
52  
53      return 0;
54  }
55  
56  /**
57   * Drops VLAN tagged packets from a socket
58   *
59   * ld vlant
60   * jneq #0, drop
61   * ld proto
62   * jneq #0x88f8, drop
63   * ret #-1
64   * drop: ret #0
65   */
66  struct sock_filter vlan_remove_code[] = {
67      {0x20, 0, 0, 0xfffff02c}, {0x15, 0, 3, 0x00000000},
68      {0x20, 0, 0, 0xfffff000}, {0x15, 0, 1, 0x000088f8},
69      {0x6, 0, 0, 0xffffffff},  {0x6, 0, 0, 0x00000000}};
70  
71  struct sock_fprog vlan_remove_bpf = {
72      std::size(vlan_remove_code),
73      vlan_remove_code,
74  };
75  
filter_vlans()76  int SockIO::filter_vlans()
77  {
78      return setsockopt(sockfd_, SOL_SOCKET, SO_ATTACH_FILTER, &vlan_remove_bpf,
79                        sizeof(vlan_remove_bpf));
80  }
81  
recv(void * buf,size_t maxlen)82  int SockIO::recv(void* buf, size_t maxlen)
83  {
84      struct pollfd sock_pollfd{sockfd_, POLLIN | POLLPRI, 0};
85  
86      int ret = poll(&sock_pollfd, 1, kpoll_timeout_);
87      if (ret > 0)
88      {
89          return ::recv(sockfd_, buf, maxlen, 0);
90      }
91  
92      return ret;
93  }
94  
95  } // namespace ncsi
96