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 <netinet/in.h>
22 #include <poll.h>
23 #include <sys/socket.h>
24 #include <sys/types.h>
25 
26 #include <cstdio>
27 #include <cstring>
28 
29 namespace ncsi
30 {
31 
32 int SockIO::init()
33 {
34     RETURN_IF_ERROR(sockfd_ = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)),
35                     "ncsi::SockIO::init() failed");
36     return 0;
37 }
38 
39 int SockIO::bind_to_iface(const net::IFaceBase& iface)
40 {
41     iface.set_sock_flags(sockfd_, IFF_PROMISC);
42 
43     std::memset(&sock_addr_, 0, sizeof(sock_addr_));
44 
45     sock_addr_.sll_family = AF_PACKET;
46     sock_addr_.sll_protocol = htons(ETH_P_ALL);
47 
48     RETURN_IF_ERROR(iface.bind_sock(sockfd_, &sock_addr_),
49                     "ncsi::SockIO::bind_to_iface failed");
50 
51     return 0;
52 }
53 
54 /**
55  * Drops VLAN tagged packets from a socket
56  *
57  * ld vlant
58  * jneq #0, drop
59  * ld proto
60  * jneq #0x88f8, drop
61  * ret #-1
62  * drop: ret #0
63  */
64 struct sock_filter vlan_remove_code[] = {
65     {0x20, 0, 0, 0xfffff02c}, {0x15, 0, 3, 0x00000000},
66     {0x20, 0, 0, 0xfffff000}, {0x15, 0, 1, 0x000088f8},
67     {0x6, 0, 0, 0xffffffff},  {0x6, 0, 0, 0x00000000}};
68 
69 struct sock_fprog vlan_remove_bpf = {
70     std::size(vlan_remove_code),
71     vlan_remove_code,
72 };
73 
74 int SockIO::filter_vlans()
75 {
76     return setsockopt(sockfd_, SOL_SOCKET, SO_ATTACH_FILTER, &vlan_remove_bpf,
77                       sizeof(vlan_remove_bpf));
78 }
79 
80 int SockIO::recv(void* buf, size_t maxlen)
81 {
82     struct pollfd sock_pollfd
83     {
84         sockfd_, POLLIN | POLLPRI, 0
85     };
86 
87     int ret = poll(&sock_pollfd, 1, kpoll_timeout_);
88     if (ret > 0)
89     {
90         return ::recv(sockfd_, buf, maxlen, 0);
91     }
92 
93     return ret;
94 }
95 
96 } // namespace ncsi
97