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 iface.set_sock_flags(sockfd_, IFF_PROMISC);
43
44 RETURN_IF_ERROR(iface.bind_sock(sockfd_),
45 "ncsi::SockIO::bind_to_iface failed");
46
47 return 0;
48 }
49
50 /**
51 * Drops VLAN tagged packets from a socket
52 *
53 * ld vlant
54 * jneq #0, drop
55 * ld proto
56 * jneq #0x88f8, drop
57 * ret #-1
58 * drop: ret #0
59 */
60 struct sock_filter vlan_remove_code[] = {
61 {0x20, 0, 0, 0xfffff02c}, {0x15, 0, 3, 0x00000000},
62 {0x20, 0, 0, 0xfffff000}, {0x15, 0, 1, 0x000088f8},
63 {0x6, 0, 0, 0xffffffff}, {0x6, 0, 0, 0x00000000}};
64
65 struct sock_fprog vlan_remove_bpf = {
66 std::size(vlan_remove_code),
67 vlan_remove_code,
68 };
69
filter_vlans()70 int SockIO::filter_vlans()
71 {
72 return setsockopt(sockfd_, SOL_SOCKET, SO_ATTACH_FILTER, &vlan_remove_bpf,
73 sizeof(vlan_remove_bpf));
74 }
75
recv(void * buf,size_t maxlen)76 int SockIO::recv(void* buf, size_t maxlen)
77 {
78 struct pollfd sock_pollfd{sockfd_, POLLIN | POLLPRI, 0};
79
80 int ret = poll(&sock_pollfd, 1, kpoll_timeout_);
81 if (ret > 0)
82 {
83 return ::recv(sockfd_, buf, maxlen, 0);
84 }
85
86 return ret;
87 }
88
89 } // namespace ncsi
90