Allow creating packet socket bound to any protocol
...even protocols the stack is unaware of. While I am here, annotate checklocks on stack.packetEndpointList. PiperOrigin-RevId: 397226754
This commit is contained in:
parent
85bd3dd9b1
commit
b28bd31bb6
|
@ -97,6 +97,8 @@ type packetEndpointList struct {
|
|||
mu sync.RWMutex
|
||||
|
||||
// eps is protected by mu, but the contained PacketEndpoint values are not.
|
||||
//
|
||||
// +checklocks:mu
|
||||
eps []PacketEndpoint
|
||||
}
|
||||
|
||||
|
@ -117,6 +119,12 @@ func (p *packetEndpointList) remove(ep PacketEndpoint) {
|
|||
}
|
||||
}
|
||||
|
||||
func (p *packetEndpointList) len() int {
|
||||
p.mu.RLock()
|
||||
defer p.mu.RUnlock()
|
||||
return len(p.eps)
|
||||
}
|
||||
|
||||
// forEach calls fn with each endpoints in p while holding the read lock on p.
|
||||
func (p *packetEndpointList) forEach(fn func(PacketEndpoint)) {
|
||||
p.mu.RLock()
|
||||
|
@ -157,14 +165,8 @@ func newNIC(stack *Stack, id tcpip.NICID, name string, ep LinkEndpoint, ctx NICC
|
|||
|
||||
resolutionRequired := ep.Capabilities()&CapabilityResolutionRequired != 0
|
||||
|
||||
// Register supported packet and network endpoint protocols.
|
||||
for _, netProto := range header.Ethertypes {
|
||||
nic.packetEPs.eps[netProto] = new(packetEndpointList)
|
||||
}
|
||||
for _, netProto := range stack.networkProtocols {
|
||||
netNum := netProto.Number()
|
||||
nic.packetEPs.eps[netNum] = new(packetEndpointList)
|
||||
|
||||
netEP := netProto.NewEndpoint(nic, nic)
|
||||
nic.networkEndpoints[netNum] = netEP
|
||||
|
||||
|
@ -974,7 +976,8 @@ func (n *nic) registerPacketEndpoint(netProto tcpip.NetworkProtocolNumber, ep Pa
|
|||
|
||||
eps, ok := n.packetEPs.eps[netProto]
|
||||
if !ok {
|
||||
return &tcpip.ErrNotSupported{}
|
||||
eps = new(packetEndpointList)
|
||||
n.packetEPs.eps[netProto] = eps
|
||||
}
|
||||
eps.add(ep)
|
||||
|
||||
|
@ -990,6 +993,9 @@ func (n *nic) unregisterPacketEndpoint(netProto tcpip.NetworkProtocolNumber, ep
|
|||
return
|
||||
}
|
||||
eps.remove(ep)
|
||||
if eps.len() == 0 {
|
||||
delete(n.packetEPs.eps, netProto)
|
||||
}
|
||||
}
|
||||
|
||||
// isValidForOutgoing returns true if the endpoint can be used to send out a
|
||||
|
|
|
@ -366,6 +366,10 @@ syscall_test(
|
|||
test = "//test/syscalls/linux:packet_socket_raw_test",
|
||||
)
|
||||
|
||||
syscall_test(
|
||||
test = "//test/syscalls/linux:packet_socket_test",
|
||||
)
|
||||
|
||||
syscall_test(
|
||||
test = "//test/syscalls/linux:partial_bad_buffer_test",
|
||||
)
|
||||
|
|
|
@ -7,6 +7,7 @@ package(
|
|||
|
||||
exports_files(
|
||||
[
|
||||
"packet_socket.cc",
|
||||
"packet_socket_dgram.cc",
|
||||
"packet_socket_raw.cc",
|
||||
"raw_socket.cc",
|
||||
|
@ -1480,6 +1481,20 @@ cc_binary(
|
|||
],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "packet_socket_test",
|
||||
testonly = 1,
|
||||
srcs = ["packet_socket.cc"],
|
||||
linkstatic = 1,
|
||||
deps = [
|
||||
"//test/util:capability_util",
|
||||
"//test/util:file_descriptor",
|
||||
"//test/util:socket_util",
|
||||
gtest,
|
||||
"//test/util:test_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "pty_test",
|
||||
testonly = 1,
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
// Copyright 2021 The gVisor Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <net/if.h>
|
||||
#include <netinet/if_ether.h>
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "test/util/capability_util.h"
|
||||
#include "test/util/file_descriptor.h"
|
||||
#include "test/util/socket_util.h"
|
||||
|
||||
namespace gvisor {
|
||||
namespace testing {
|
||||
|
||||
namespace {
|
||||
|
||||
using ::testing::Combine;
|
||||
using ::testing::Values;
|
||||
|
||||
class PacketSocketTest : public ::testing::TestWithParam<std::tuple<int, int>> {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
if (!ASSERT_NO_ERRNO_AND_VALUE(HavePacketSocketCapability())) {
|
||||
const auto [type, protocol] = GetParam();
|
||||
ASSERT_THAT(socket(AF_PACKET, type, htons(protocol)),
|
||||
SyscallFailsWithErrno(EPERM));
|
||||
GTEST_SKIP() << "Missing packet socket capability";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TEST_P(PacketSocketTest, Create) {
|
||||
const auto [type, protocol] = GetParam();
|
||||
FileDescriptor fd =
|
||||
ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_PACKET, type, htons(protocol)));
|
||||
EXPECT_GE(fd.get(), 0);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(AllPacketSocketTests, PacketSocketTest,
|
||||
Combine(Values(SOCK_DGRAM, SOCK_RAW),
|
||||
Values(0, 1, 255, ETH_P_IP, ETH_P_IPV6,
|
||||
std::numeric_limits<uint16_t>::max())));
|
||||
|
||||
} // namespace
|
||||
|
||||
} // namespace testing
|
||||
} // namespace gvisor
|
|
@ -17,6 +17,8 @@
|
|||
#ifndef GVISOR_TEST_UTIL_CAPABILITY_UTIL_H_
|
||||
#define GVISOR_TEST_UTIL_CAPABILITY_UTIL_H_
|
||||
|
||||
#include "test/util/posix_error.h"
|
||||
|
||||
#if defined(__Fuchsia__)
|
||||
// Nothing to include.
|
||||
#elif defined(__linux__)
|
||||
|
|
Loading…
Reference in New Issue