2018-10-19 23:34:09 +00:00
// Copyright 2018 Google LLC
2018-04-27 17:37:02 +00:00
//
// 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.
// Package epsocket provides an implementation of the socket.Socket interface
// that is backed by a tcpip.Endpoint.
//
// It does not depend on any particular endpoint implementation, and thus can
// be used to expose certain endpoints to the sentry while leaving others out,
// for example, TCP endpoints and Unix-domain endpoints.
//
// Lock ordering: netstack => mm: ioSequencePayload copies user memory inside
// tcpip.Endpoint.Write(). Netstack is allowed to (and does) hold locks during
// this operation.
package epsocket
import (
"bytes"
"math"
"strings"
"sync"
"syscall"
"gvisor.googlesource.com/gvisor/pkg/abi/linux"
"gvisor.googlesource.com/gvisor/pkg/binary"
2018-10-09 22:11:46 +00:00
"gvisor.googlesource.com/gvisor/pkg/metric"
2018-04-27 17:37:02 +00:00
"gvisor.googlesource.com/gvisor/pkg/sentry/arch"
"gvisor.googlesource.com/gvisor/pkg/sentry/context"
"gvisor.googlesource.com/gvisor/pkg/sentry/fs"
"gvisor.googlesource.com/gvisor/pkg/sentry/fs/fsutil"
"gvisor.googlesource.com/gvisor/pkg/sentry/inet"
"gvisor.googlesource.com/gvisor/pkg/sentry/kernel"
"gvisor.googlesource.com/gvisor/pkg/sentry/kernel/kdefs"
ktime "gvisor.googlesource.com/gvisor/pkg/sentry/kernel/time"
"gvisor.googlesource.com/gvisor/pkg/sentry/safemem"
"gvisor.googlesource.com/gvisor/pkg/sentry/socket"
2018-10-17 18:36:32 +00:00
"gvisor.googlesource.com/gvisor/pkg/sentry/socket/unix/transport"
2018-10-20 18:12:26 +00:00
"gvisor.googlesource.com/gvisor/pkg/sentry/unimpl"
2018-04-27 17:37:02 +00:00
"gvisor.googlesource.com/gvisor/pkg/sentry/usermem"
"gvisor.googlesource.com/gvisor/pkg/syserr"
"gvisor.googlesource.com/gvisor/pkg/syserror"
"gvisor.googlesource.com/gvisor/pkg/tcpip"
"gvisor.googlesource.com/gvisor/pkg/tcpip/buffer"
2018-08-09 05:38:41 +00:00
"gvisor.googlesource.com/gvisor/pkg/tcpip/stack"
2018-04-27 17:37:02 +00:00
"gvisor.googlesource.com/gvisor/pkg/waiter"
)
2018-10-09 22:11:46 +00:00
func mustCreateMetric ( name , description string ) * tcpip . StatCounter {
var cm tcpip . StatCounter
metric . MustRegisterCustomUint64Metric ( name , false /* sync */ , description , cm . Value )
return & cm
}
// Metrics contains metrics exported by netstack.
var Metrics = tcpip . Stats {
UnknownProtocolRcvdPackets : mustCreateMetric ( "/netstack/unknown_protocol_received_packets" , "Number of packets received by netstack that were for an unknown or unsupported protocol." ) ,
MalformedRcvdPackets : mustCreateMetric ( "/netstack/malformed_received_packets" , "Number of packets received by netstack that were deemed malformed." ) ,
DroppedPackets : mustCreateMetric ( "/netstack/dropped_packets" , "Number of packets dropped by netstack due to full queues." ) ,
IP : tcpip . IPStats {
PacketsReceived : mustCreateMetric ( "/netstack/ip/packets_received" , "Total number of IP packets received from the link layer in nic.DeliverNetworkPacket." ) ,
InvalidAddressesReceived : mustCreateMetric ( "/netstack/ip/invalid_addresses_received" , "Total number of IP packets received with an unknown or invalid destination address." ) ,
PacketsDelivered : mustCreateMetric ( "/netstack/ip/packets_delivered" , "Total number of incoming IP packets that are successfully delivered to the transport layer via HandlePacket." ) ,
PacketsSent : mustCreateMetric ( "/netstack/ip/packets_sent" , "Total number of IP packets sent via WritePacket." ) ,
OutgoingPacketErrors : mustCreateMetric ( "/netstack/ip/outgoing_packet_errors" , "Total number of IP packets which failed to write to a link-layer endpoint." ) ,
} ,
TCP : tcpip . TCPStats {
ActiveConnectionOpenings : mustCreateMetric ( "/netstack/tcp/active_connection_openings" , "Number of connections opened successfully via Connect." ) ,
PassiveConnectionOpenings : mustCreateMetric ( "/netstack/tcp/passive_connection_openings" , "Number of connections opened successfully via Listen." ) ,
FailedConnectionAttempts : mustCreateMetric ( "/netstack/tcp/failed_connection_attempts" , "Number of calls to Connect or Listen (active and passive openings, respectively) that end in an error." ) ,
ValidSegmentsReceived : mustCreateMetric ( "/netstack/tcp/valid_segments_received" , "Number of TCP segments received that the transport layer successfully parsed." ) ,
InvalidSegmentsReceived : mustCreateMetric ( "/netstack/tcp/invalid_segments_received" , "Number of TCP segments received that the transport layer could not parse." ) ,
SegmentsSent : mustCreateMetric ( "/netstack/tcp/segments_sent" , "Number of TCP segments sent." ) ,
ResetsSent : mustCreateMetric ( "/netstack/tcp/resets_sent" , "Number of TCP resets sent." ) ,
ResetsReceived : mustCreateMetric ( "/netstack/tcp/resets_received" , "Number of TCP resets received." ) ,
} ,
UDP : tcpip . UDPStats {
PacketsReceived : mustCreateMetric ( "/netstack/udp/packets_received" , "Number of UDP datagrams received via HandlePacket." ) ,
UnknownPortErrors : mustCreateMetric ( "/netstack/udp/unknown_port_errors" , "Number of incoming UDP datagrams dropped because they did not have a known destination port." ) ,
ReceiveBufferErrors : mustCreateMetric ( "/netstack/udp/receive_buffer_errors" , "Number of incoming UDP datagrams dropped due to the receiving buffer being in an invalid state." ) ,
MalformedPacketsReceived : mustCreateMetric ( "/netstack/udp/malformed_packets_received" , "Number of incoming UDP datagrams dropped due to the UDP header being in a malformed state." ) ,
PacketsSent : mustCreateMetric ( "/netstack/udp/packets_sent" , "Number of UDP datagrams sent via sendUDP." ) ,
} ,
}
2018-04-27 17:37:02 +00:00
const sizeOfInt32 int = 4
2018-05-22 20:46:37 +00:00
var errStackType = syserr . New ( "expected but did not receive an epsocket.Stack" , linux . EINVAL )
2018-04-27 17:37:02 +00:00
// ntohs converts a 16-bit number from network byte order to host byte order. It
// assumes that the host is little endian.
func ntohs ( v uint16 ) uint16 {
return v << 8 | v >> 8
}
// htons converts a 16-bit number from host byte order to network byte order. It
// assumes that the host is little endian.
func htons ( v uint16 ) uint16 {
return ntohs ( v )
}
// commonEndpoint represents the intersection of a tcpip.Endpoint and a
2018-10-17 18:36:32 +00:00
// transport.Endpoint.
2018-04-27 17:37:02 +00:00
type commonEndpoint interface {
// GetLocalAddress implements tcpip.Endpoint.GetLocalAddress and
2018-10-17 18:36:32 +00:00
// transport.Endpoint.GetLocalAddress.
2018-04-27 17:37:02 +00:00
GetLocalAddress ( ) ( tcpip . FullAddress , * tcpip . Error )
// GetRemoteAddress implements tcpip.Endpoint.GetRemoteAddress and
2018-10-17 18:36:32 +00:00
// transport.Endpoint.GetRemoteAddress.
2018-04-27 17:37:02 +00:00
GetRemoteAddress ( ) ( tcpip . FullAddress , * tcpip . Error )
// Readiness implements tcpip.Endpoint.Readiness and
2018-10-17 18:36:32 +00:00
// transport.Endpoint.Readiness.
2018-04-27 17:37:02 +00:00
Readiness ( mask waiter . EventMask ) waiter . EventMask
// SetSockOpt implements tcpip.Endpoint.SetSockOpt and
2018-10-17 18:36:32 +00:00
// transport.Endpoint.SetSockOpt.
2018-04-27 17:37:02 +00:00
SetSockOpt ( interface { } ) * tcpip . Error
// GetSockOpt implements tcpip.Endpoint.GetSockOpt and
2018-10-17 18:36:32 +00:00
// transport.Endpoint.GetSockOpt.
2018-04-27 17:37:02 +00:00
GetSockOpt ( interface { } ) * tcpip . Error
}
// SocketOperations encapsulates all the state needed to represent a network stack
// endpoint in the kernel context.
2018-08-02 17:41:44 +00:00
//
// +stateify savable
2018-04-27 17:37:02 +00:00
type SocketOperations struct {
socket . ReceiveTimeout
fsutil . PipeSeek ` state:"nosave" `
fsutil . NotDirReaddir ` state:"nosave" `
fsutil . NoFsync ` state:"nosave" `
fsutil . NoopFlush ` state:"nosave" `
fsutil . NoMMap ` state:"nosave" `
* waiter . Queue
family int
Endpoint tcpip . Endpoint
2018-10-17 18:36:32 +00:00
skType transport . SockType
2018-04-27 17:37:02 +00:00
// readMu protects access to readView, control, and sender.
readMu sync . Mutex ` state:"nosave" `
readView buffer . View
2018-05-02 05:11:07 +00:00
readCM tcpip . ControlMessages
2018-04-27 17:37:02 +00:00
sender tcpip . FullAddress
}
// New creates a new endpoint socket.
2018-11-14 02:01:26 +00:00
func New ( t * kernel . Task , family int , skType transport . SockType , queue * waiter . Queue , endpoint tcpip . Endpoint ) ( * fs . File , * syserr . Error ) {
if skType == transport . SockStream {
if err := endpoint . SetSockOpt ( tcpip . DelayOption ( 1 ) ) ; err != nil {
return nil , syserr . TranslateNetstackError ( err )
}
}
2018-04-27 17:37:02 +00:00
dirent := socket . NewDirent ( t , epsocketDevice )
2018-05-16 20:28:29 +00:00
defer dirent . DecRef ( )
2018-04-27 17:37:02 +00:00
return fs . NewFile ( t , dirent , fs . FileFlags { Read : true , Write : true } , & SocketOperations {
Queue : queue ,
family : family ,
Endpoint : endpoint ,
skType : skType ,
2018-11-14 02:01:26 +00:00
} ) , nil
2018-04-27 17:37:02 +00:00
}
var sockAddrInetSize = int ( binary . Size ( linux . SockAddrInet { } ) )
var sockAddrInet6Size = int ( binary . Size ( linux . SockAddrInet6 { } ) )
// GetAddress reads an sockaddr struct from the given address and converts it
// to the FullAddress format. It supports AF_UNIX, AF_INET and AF_INET6
// addresses.
func GetAddress ( sfamily int , addr [ ] byte ) ( tcpip . FullAddress , * syserr . Error ) {
// Make sure we have at least 2 bytes for the address family.
if len ( addr ) < 2 {
return tcpip . FullAddress { } , syserr . ErrInvalidArgument
}
family := usermem . ByteOrder . Uint16 ( addr )
if family != uint16 ( sfamily ) {
return tcpip . FullAddress { } , syserr . ErrAddressFamilyNotSupported
}
// Get the rest of the fields based on the address family.
switch family {
case linux . AF_UNIX :
path := addr [ 2 : ]
2018-08-14 22:05:44 +00:00
if len ( path ) > linux . UnixPathMax {
return tcpip . FullAddress { } , syserr . ErrInvalidArgument
}
2018-08-20 23:08:32 +00:00
// Drop the terminating NUL (if one exists) and everything after
// it for filesystem (non-abstract) addresses.
if len ( path ) > 0 && path [ 0 ] != 0 {
2018-04-27 17:37:02 +00:00
if n := bytes . IndexByte ( path [ 1 : ] , 0 ) ; n >= 0 {
path = path [ : n + 1 ]
}
}
return tcpip . FullAddress {
Addr : tcpip . Address ( path ) ,
} , nil
case linux . AF_INET :
var a linux . SockAddrInet
if len ( addr ) < sockAddrInetSize {
return tcpip . FullAddress { } , syserr . ErrBadAddress
}
binary . Unmarshal ( addr [ : sockAddrInetSize ] , usermem . ByteOrder , & a )
out := tcpip . FullAddress {
Addr : tcpip . Address ( a . Addr [ : ] ) ,
Port : ntohs ( a . Port ) ,
}
if out . Addr == "\x00\x00\x00\x00" {
out . Addr = ""
}
return out , nil
case linux . AF_INET6 :
var a linux . SockAddrInet6
if len ( addr ) < sockAddrInet6Size {
return tcpip . FullAddress { } , syserr . ErrBadAddress
}
binary . Unmarshal ( addr [ : sockAddrInet6Size ] , usermem . ByteOrder , & a )
out := tcpip . FullAddress {
Addr : tcpip . Address ( a . Addr [ : ] ) ,
Port : ntohs ( a . Port ) ,
}
if isLinkLocal ( out . Addr ) {
out . NIC = tcpip . NICID ( a . Scope_id )
}
if out . Addr == tcpip . Address ( strings . Repeat ( "\x00" , 16 ) ) {
out . Addr = ""
}
return out , nil
default :
return tcpip . FullAddress { } , syserr . ErrAddressFamilyNotSupported
}
}
func ( s * SocketOperations ) isPacketBased ( ) bool {
return s . skType == linux . SOCK_DGRAM || s . skType == linux . SOCK_SEQPACKET || s . skType == linux . SOCK_RDM
}
// fetchReadView updates the readView field of the socket if it's currently
// empty. It assumes that the socket is locked.
func ( s * SocketOperations ) fetchReadView ( ) * syserr . Error {
if len ( s . readView ) > 0 {
return nil
}
s . readView = nil
s . sender = tcpip . FullAddress { }
2018-05-02 05:11:07 +00:00
v , cms , err := s . Endpoint . Read ( & s . sender )
2018-04-27 17:37:02 +00:00
if err != nil {
return syserr . TranslateNetstackError ( err )
}
s . readView = v
2018-05-02 05:11:07 +00:00
s . readCM = cms
2018-04-27 17:37:02 +00:00
return nil
}
// Release implements fs.FileOperations.Release.
func ( s * SocketOperations ) Release ( ) {
s . Endpoint . Close ( )
}
// Read implements fs.FileOperations.Read.
func ( s * SocketOperations ) Read ( ctx context . Context , _ * fs . File , dst usermem . IOSequence , _ int64 ) ( int64 , error ) {
if dst . NumBytes ( ) == 0 {
return 0 , nil
}
2018-05-02 05:11:07 +00:00
n , _ , _ , _ , err := s . nonBlockingRead ( ctx , dst , false , false , false )
2018-04-27 17:37:02 +00:00
if err == syserr . ErrWouldBlock {
return int64 ( n ) , syserror . ErrWouldBlock
}
if err != nil {
return 0 , err . ToError ( )
}
return int64 ( n ) , nil
}
// ioSequencePayload implements tcpip.Payload. It copies user memory bytes on demand
// based on the requested size.
type ioSequencePayload struct {
ctx context . Context
src usermem . IOSequence
}
// Get implements tcpip.Payload.
func ( i * ioSequencePayload ) Get ( size int ) ( [ ] byte , * tcpip . Error ) {
if size > i . Size ( ) {
size = i . Size ( )
}
v := buffer . NewView ( size )
if _ , err := i . src . CopyIn ( i . ctx , v ) ; err != nil {
return nil , tcpip . ErrBadAddress
}
return v , nil
}
// Size implements tcpip.Payload.
func ( i * ioSequencePayload ) Size ( ) int {
return int ( i . src . NumBytes ( ) )
}
// Write implements fs.FileOperations.Write.
func ( s * SocketOperations ) Write ( ctx context . Context , _ * fs . File , src usermem . IOSequence , _ int64 ) ( int64 , error ) {
f := & ioSequencePayload { ctx : ctx , src : src }
2018-09-28 17:59:21 +00:00
n , resCh , err := s . Endpoint . Write ( f , tcpip . WriteOptions { } )
2018-04-27 17:37:02 +00:00
if err == tcpip . ErrWouldBlock {
2018-12-06 19:40:39 +00:00
return 0 , syserror . ErrWouldBlock
2018-04-27 17:37:02 +00:00
}
2018-09-28 17:59:21 +00:00
if resCh != nil {
t := ctx . ( * kernel . Task )
if err := t . Block ( resCh ) ; err != nil {
2018-12-06 19:40:39 +00:00
return 0 , syserr . FromError ( err ) . ToError ( )
2018-09-28 17:59:21 +00:00
}
n , _ , err = s . Endpoint . Write ( f , tcpip . WriteOptions { } )
}
2018-12-06 19:40:39 +00:00
if err != nil {
return 0 , syserr . TranslateNetstackError ( err ) . ToError ( )
}
if int64 ( n ) < src . NumBytes ( ) {
return int64 ( n ) , syserror . ErrWouldBlock
}
return int64 ( n ) , nil
2018-04-27 17:37:02 +00:00
}
// Readiness returns a mask of ready events for socket s.
func ( s * SocketOperations ) Readiness ( mask waiter . EventMask ) waiter . EventMask {
r := s . Endpoint . Readiness ( mask )
// Check our cached value iff the caller asked for readability and the
// endpoint itself is currently not readable.
if ( mask & ^ r & waiter . EventIn ) != 0 {
s . readMu . Lock ( )
if len ( s . readView ) > 0 {
r |= waiter . EventIn
}
s . readMu . Unlock ( )
}
return r
}
// Connect implements the linux syscall connect(2) for sockets backed by
// tpcip.Endpoint.
func ( s * SocketOperations ) Connect ( t * kernel . Task , sockaddr [ ] byte , blocking bool ) * syserr . Error {
addr , err := GetAddress ( s . family , sockaddr )
if err != nil {
return err
}
// Always return right away in the non-blocking case.
if ! blocking {
return syserr . TranslateNetstackError ( s . Endpoint . Connect ( addr ) )
}
// Register for notification when the endpoint becomes writable, then
// initiate the connection.
e , ch := waiter . NewChannelEntry ( nil )
s . EventRegister ( & e , waiter . EventOut )
defer s . EventUnregister ( & e )
if err := s . Endpoint . Connect ( addr ) ; err != tcpip . ErrConnectStarted && err != tcpip . ErrAlreadyConnecting {
return syserr . TranslateNetstackError ( err )
}
// It's pending, so we have to wait for a notification, and fetch the
// result once the wait completes.
if err := t . Block ( ch ) ; err != nil {
return syserr . FromError ( err )
}
// Call Connect() again after blocking to find connect's result.
return syserr . TranslateNetstackError ( s . Endpoint . Connect ( addr ) )
}
// Bind implements the linux syscall bind(2) for sockets backed by
// tcpip.Endpoint.
func ( s * SocketOperations ) Bind ( t * kernel . Task , sockaddr [ ] byte ) * syserr . Error {
addr , err := GetAddress ( s . family , sockaddr )
if err != nil {
return err
}
// Issue the bind request to the endpoint.
return syserr . TranslateNetstackError ( s . Endpoint . Bind ( addr , nil ) )
}
// Listen implements the linux syscall listen(2) for sockets backed by
// tcpip.Endpoint.
func ( s * SocketOperations ) Listen ( t * kernel . Task , backlog int ) * syserr . Error {
return syserr . TranslateNetstackError ( s . Endpoint . Listen ( backlog ) )
}
// blockingAccept implements a blocking version of accept(2), that is, if no
// connections are ready to be accept, it will block until one becomes ready.
func ( s * SocketOperations ) blockingAccept ( t * kernel . Task ) ( tcpip . Endpoint , * waiter . Queue , * syserr . Error ) {
// Register for notifications.
e , ch := waiter . NewChannelEntry ( nil )
s . EventRegister ( & e , waiter . EventIn )
defer s . EventUnregister ( & e )
// Try to accept the connection again; if it fails, then wait until we
// get a notification.
for {
if ep , wq , err := s . Endpoint . Accept ( ) ; err != tcpip . ErrWouldBlock {
return ep , wq , syserr . TranslateNetstackError ( err )
}
if err := t . Block ( ch ) ; err != nil {
return nil , nil , syserr . FromError ( err )
}
}
}
// Accept implements the linux syscall accept(2) for sockets backed by
// tcpip.Endpoint.
func ( s * SocketOperations ) Accept ( t * kernel . Task , peerRequested bool , flags int , blocking bool ) ( kdefs . FD , interface { } , uint32 , * syserr . Error ) {
// Issue the accept request to get the new endpoint.
2018-11-14 02:01:26 +00:00
ep , wq , terr := s . Endpoint . Accept ( )
if terr != nil {
if terr != tcpip . ErrWouldBlock || ! blocking {
return 0 , nil , 0 , syserr . TranslateNetstackError ( terr )
2018-04-27 17:37:02 +00:00
}
var err * syserr . Error
ep , wq , err = s . blockingAccept ( t )
if err != nil {
return 0 , nil , 0 , err
}
}
2018-11-14 02:01:26 +00:00
ns , err := New ( t , s . family , s . skType , wq , ep )
if err != nil {
return 0 , nil , 0 , err
}
2018-04-27 17:37:02 +00:00
defer ns . DecRef ( )
if flags & linux . SOCK_NONBLOCK != 0 {
flags := ns . Flags ( )
flags . NonBlocking = true
ns . SetFlags ( flags . Settable ( ) )
}
var addr interface { }
var addrLen uint32
if peerRequested {
// Get address of the peer and write it to peer slice.
var err * syserr . Error
addr , addrLen , err = ns . FileOperations . ( * SocketOperations ) . GetPeerName ( t )
if err != nil {
return 0 , nil , 0 , err
}
}
fdFlags := kernel . FDFlags {
CloseOnExec : flags & linux . SOCK_CLOEXEC != 0 ,
}
fd , e := t . FDMap ( ) . NewFDFrom ( 0 , ns , fdFlags , t . ThreadGroup ( ) . Limits ( ) )
return fd , addr , addrLen , syserr . FromError ( e )
}
// ConvertShutdown converts Linux shutdown flags into tcpip shutdown flags.
func ConvertShutdown ( how int ) ( tcpip . ShutdownFlags , * syserr . Error ) {
var f tcpip . ShutdownFlags
switch how {
case linux . SHUT_RD :
f = tcpip . ShutdownRead
case linux . SHUT_WR :
f = tcpip . ShutdownWrite
case linux . SHUT_RDWR :
f = tcpip . ShutdownRead | tcpip . ShutdownWrite
default :
return 0 , syserr . ErrInvalidArgument
}
return f , nil
}
// Shutdown implements the linux syscall shutdown(2) for sockets backed by
// tcpip.Endpoint.
func ( s * SocketOperations ) Shutdown ( t * kernel . Task , how int ) * syserr . Error {
f , err := ConvertShutdown ( how )
if err != nil {
return err
}
// Issue shutdown request.
return syserr . TranslateNetstackError ( s . Endpoint . Shutdown ( f ) )
}
// GetSockOpt implements the linux syscall getsockopt(2) for sockets backed by
// tcpip.Endpoint.
func ( s * SocketOperations ) GetSockOpt ( t * kernel . Task , level , name , outLen int ) ( interface { } , * syserr . Error ) {
return GetSockOpt ( t , s , s . Endpoint , s . family , s . skType , level , name , outLen )
}
// GetSockOpt can be used to implement the linux syscall getsockopt(2) for
// sockets backed by a commonEndpoint.
2018-10-17 18:36:32 +00:00
func GetSockOpt ( t * kernel . Task , s socket . Socket , ep commonEndpoint , family int , skType transport . SockType , level , name , outLen int ) ( interface { } , * syserr . Error ) {
2018-04-27 17:37:02 +00:00
switch level {
2018-08-09 05:38:41 +00:00
case linux . SOL_SOCKET :
2018-11-19 23:25:00 +00:00
return getSockOptSocket ( t , s , ep , family , skType , name , outLen )
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
case linux . SOL_TCP :
return getSockOptTCP ( t , ep , name , outLen )
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
case linux . SOL_IPV6 :
return getSockOptIPv6 ( t , ep , name , outLen )
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
case linux . SOL_IP ,
linux . SOL_UDP ,
linux . SOL_ICMPV6 ,
linux . SOL_RAW ,
linux . SOL_PACKET :
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
t . Kernel ( ) . EmitUnimplementedEvent ( t )
}
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
return nil , syserr . ErrProtocolNotAvailable
}
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
// getSockOptSocket implements GetSockOpt when level is SOL_SOCKET.
func getSockOptSocket ( t * kernel . Task , s socket . Socket , ep commonEndpoint , family int , skType transport . SockType , name , outLen int ) ( interface { } , * syserr . Error ) {
switch name {
case linux . SO_TYPE :
if outLen < sizeOfInt32 {
return nil , syserr . ErrInvalidArgument
}
return int32 ( skType ) , nil
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
case linux . SO_ERROR :
if outLen < sizeOfInt32 {
return nil , syserr . ErrInvalidArgument
}
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
// Get the last error and convert it.
err := ep . GetSockOpt ( tcpip . ErrorOption { } )
if err == nil {
return int32 ( 0 ) , nil
}
return int32 ( syserr . TranslateNetstackError ( err ) . ToLinux ( ) . Number ( ) ) , nil
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
case linux . SO_PEERCRED :
if family != linux . AF_UNIX || outLen < syscall . SizeofUcred {
return nil , syserr . ErrInvalidArgument
}
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
tcred := t . Credentials ( )
return syscall . Ucred {
Pid : int32 ( t . ThreadGroup ( ) . ID ( ) ) ,
Uid : uint32 ( tcred . EffectiveKUID . In ( tcred . UserNamespace ) . OrOverflow ( ) ) ,
Gid : uint32 ( tcred . EffectiveKGID . In ( tcred . UserNamespace ) . OrOverflow ( ) ) ,
} , nil
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
case linux . SO_PASSCRED :
if outLen < sizeOfInt32 {
return nil , syserr . ErrInvalidArgument
}
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
var v tcpip . PasscredOption
if err := ep . GetSockOpt ( & v ) ; err != nil {
return nil , syserr . TranslateNetstackError ( err )
}
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
return int32 ( v ) , nil
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
case linux . SO_SNDBUF :
if outLen < sizeOfInt32 {
return nil , syserr . ErrInvalidArgument
}
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
var size tcpip . SendBufferSizeOption
if err := ep . GetSockOpt ( & size ) ; err != nil {
return nil , syserr . TranslateNetstackError ( err )
}
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
if size > math . MaxInt32 {
size = math . MaxInt32
}
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
return int32 ( size ) , nil
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
case linux . SO_RCVBUF :
if outLen < sizeOfInt32 {
return nil , syserr . ErrInvalidArgument
}
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
var size tcpip . ReceiveBufferSizeOption
if err := ep . GetSockOpt ( & size ) ; err != nil {
return nil , syserr . TranslateNetstackError ( err )
}
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
if size > math . MaxInt32 {
size = math . MaxInt32
}
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
return int32 ( size ) , nil
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
case linux . SO_REUSEADDR :
if outLen < sizeOfInt32 {
return nil , syserr . ErrInvalidArgument
}
2018-05-02 05:11:07 +00:00
2018-11-19 23:25:00 +00:00
var v tcpip . ReuseAddressOption
if err := ep . GetSockOpt ( & v ) ; err != nil {
return nil , syserr . TranslateNetstackError ( err )
}
2018-05-02 05:11:07 +00:00
2018-11-19 23:25:00 +00:00
return int32 ( v ) , nil
2018-05-02 05:11:07 +00:00
2018-11-19 23:25:00 +00:00
case linux . SO_KEEPALIVE :
if outLen < sizeOfInt32 {
return nil , syserr . ErrInvalidArgument
2018-04-27 17:37:02 +00:00
}
2018-11-19 23:25:00 +00:00
return int32 ( 0 ) , nil
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
case linux . SO_LINGER :
if outLen < syscall . SizeofLinger {
return nil , syserr . ErrInvalidArgument
}
return syscall . Linger { } , nil
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
case linux . SO_RCVTIMEO :
if outLen < linux . SizeOfTimeval {
return nil , syserr . ErrInvalidArgument
}
2018-11-14 02:01:26 +00:00
2018-11-19 23:25:00 +00:00
return linux . NsecToTimeval ( s . RecvTimeout ( ) ) , nil
2018-11-14 02:01:26 +00:00
2018-11-19 23:25:00 +00:00
case linux . SO_TIMESTAMP :
if outLen < sizeOfInt32 {
return nil , syserr . ErrInvalidArgument
}
2018-11-14 02:01:26 +00:00
2018-11-19 23:25:00 +00:00
var v tcpip . TimestampOption
if err := ep . GetSockOpt ( & v ) ; err != nil {
return nil , syserr . TranslateNetstackError ( err )
}
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
return int32 ( v ) , nil
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
default :
socket . GetSockOptEmitUnimplementedEvent ( t , name )
}
return nil , syserr . ErrProtocolNotAvailable
}
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
// getSockOptTCP implements GetSockOpt when level is SOL_TCP.
func getSockOptTCP ( t * kernel . Task , ep commonEndpoint , name , outLen int ) ( interface { } , * syserr . Error ) {
switch name {
case linux . TCP_NODELAY :
if outLen < sizeOfInt32 {
return nil , syserr . ErrInvalidArgument
}
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
var v tcpip . DelayOption
if err := ep . GetSockOpt ( & v ) ; err != nil {
return nil , syserr . TranslateNetstackError ( err )
}
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
if v == 0 {
return int32 ( 1 ) , nil
2018-04-27 17:37:02 +00:00
}
2018-11-19 23:25:00 +00:00
return int32 ( 0 ) , nil
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
case linux . TCP_CORK :
if outLen < sizeOfInt32 {
return nil , syserr . ErrInvalidArgument
}
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
var v tcpip . CorkOption
if err := ep . GetSockOpt ( & v ) ; err != nil {
return nil , syserr . TranslateNetstackError ( err )
}
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
return int32 ( v ) , nil
2018-12-09 08:49:37 +00:00
case linux . TCP_QUICKACK :
if outLen < sizeOfInt32 {
return nil , syserr . ErrInvalidArgument
}
var v tcpip . QuickAckOption
if err := ep . GetSockOpt ( & v ) ; err != nil {
return nil , syserr . TranslateNetstackError ( err )
}
return int32 ( v ) , nil
2018-11-19 23:25:00 +00:00
case linux . TCP_INFO :
var v tcpip . TCPInfoOption
if err := ep . GetSockOpt ( & v ) ; err != nil {
return nil , syserr . TranslateNetstackError ( err )
2018-04-27 17:37:02 +00:00
}
2018-11-19 23:25:00 +00:00
// TODO: Translate fields once they are added to
// tcpip.TCPInfoOption.
info := linux . TCPInfo { }
// Linux truncates the output binary to outLen.
ib := binary . Marshal ( nil , usermem . ByteOrder , & info )
if len ( ib ) > outLen {
ib = ib [ : outLen ]
}
return ib , nil
case linux . TCP_CC_INFO ,
linux . TCP_NOTSENT_LOWAT ,
linux . TCP_ZEROCOPY_RECEIVE :
t . Kernel ( ) . EmitUnimplementedEvent ( t )
default :
emitUmplementedEventTCP ( t , name )
2018-04-27 17:37:02 +00:00
}
2018-11-19 23:25:00 +00:00
return nil , syserr . ErrProtocolNotAvailable
}
// getSockOptIPv6 implements GetSockOpt when level is SOL_IPV6.
func getSockOptIPv6 ( t * kernel . Task , ep commonEndpoint , name , outLen int ) ( interface { } , * syserr . Error ) {
switch name {
case linux . IPV6_V6ONLY :
if outLen < sizeOfInt32 {
return nil , syserr . ErrInvalidArgument
}
var v tcpip . V6OnlyOption
if err := ep . GetSockOpt ( & v ) ; err != nil {
return nil , syserr . TranslateNetstackError ( err )
}
return int32 ( v ) , nil
case linux . IPV6_PATHMTU :
t . Kernel ( ) . EmitUnimplementedEvent ( t )
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
default :
emitUmplementedEventIPv6 ( t , name )
}
2018-04-27 17:37:02 +00:00
return nil , syserr . ErrProtocolNotAvailable
}
// SetSockOpt implements the linux syscall setsockopt(2) for sockets backed by
// tcpip.Endpoint.
func ( s * SocketOperations ) SetSockOpt ( t * kernel . Task , level int , name int , optVal [ ] byte ) * syserr . Error {
return SetSockOpt ( t , s , s . Endpoint , level , name , optVal )
}
// SetSockOpt can be used to implement the linux syscall setsockopt(2) for
// sockets backed by a commonEndpoint.
func SetSockOpt ( t * kernel . Task , s socket . Socket , ep commonEndpoint , level int , name int , optVal [ ] byte ) * syserr . Error {
switch level {
2018-08-09 05:38:41 +00:00
case linux . SOL_SOCKET :
2018-11-19 23:25:00 +00:00
return setSockOptSocket ( t , s , ep , name , optVal )
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
case linux . SOL_TCP :
return setSockOptTCP ( t , ep , name , optVal )
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
case linux . SOL_IPV6 :
return setSockOptIPv6 ( t , ep , name , optVal )
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
case linux . SOL_IP :
return setSockOptIP ( t , ep , name , optVal )
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
case linux . SOL_UDP ,
linux . SOL_ICMPV6 ,
linux . SOL_RAW ,
linux . SOL_PACKET :
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
t . Kernel ( ) . EmitUnimplementedEvent ( t )
}
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
// Default to the old behavior; hand off to network stack.
return syserr . TranslateNetstackError ( ep . SetSockOpt ( struct { } { } ) )
}
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
// setSockOptSocket implements SetSockOpt when level is SOL_SOCKET.
func setSockOptSocket ( t * kernel . Task , s socket . Socket , ep commonEndpoint , name int , optVal [ ] byte ) * syserr . Error {
switch name {
case linux . SO_SNDBUF :
if len ( optVal ) < sizeOfInt32 {
return syserr . ErrInvalidArgument
}
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
v := usermem . ByteOrder . Uint32 ( optVal )
return syserr . TranslateNetstackError ( ep . SetSockOpt ( tcpip . SendBufferSizeOption ( v ) ) )
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
case linux . SO_RCVBUF :
if len ( optVal ) < sizeOfInt32 {
return syserr . ErrInvalidArgument
}
2018-05-02 05:11:07 +00:00
2018-11-19 23:25:00 +00:00
v := usermem . ByteOrder . Uint32 ( optVal )
return syserr . TranslateNetstackError ( ep . SetSockOpt ( tcpip . ReceiveBufferSizeOption ( v ) ) )
2018-05-02 05:11:07 +00:00
2018-11-19 23:25:00 +00:00
case linux . SO_REUSEADDR :
if len ( optVal ) < sizeOfInt32 {
return syserr . ErrInvalidArgument
2018-04-27 17:37:02 +00:00
}
2018-11-19 23:25:00 +00:00
v := usermem . ByteOrder . Uint32 ( optVal )
return syserr . TranslateNetstackError ( ep . SetSockOpt ( tcpip . ReuseAddressOption ( v ) ) )
2018-04-27 17:37:02 +00:00
2018-11-19 23:25:00 +00:00
case linux . SO_PASSCRED :
if len ( optVal ) < sizeOfInt32 {
return syserr . ErrInvalidArgument
}
2018-11-14 02:01:26 +00:00
2018-11-19 23:25:00 +00:00
v := usermem . ByteOrder . Uint32 ( optVal )
return syserr . TranslateNetstackError ( ep . SetSockOpt ( tcpip . PasscredOption ( v ) ) )
case linux . SO_RCVTIMEO :
if len ( optVal ) < linux . SizeOfTimeval {
return syserr . ErrInvalidArgument
2018-04-27 17:37:02 +00:00
}
2018-11-19 23:25:00 +00:00
var v linux . Timeval
binary . Unmarshal ( optVal [ : linux . SizeOfTimeval ] , usermem . ByteOrder , & v )
s . SetRecvTimeout ( v . ToNsecCapped ( ) )
return nil
case linux . SO_TIMESTAMP :
if len ( optVal ) < sizeOfInt32 {
return syserr . ErrInvalidArgument
}
v := usermem . ByteOrder . Uint32 ( optVal )
return syserr . TranslateNetstackError ( ep . SetSockOpt ( tcpip . TimestampOption ( v ) ) )
default :
socket . SetSockOptEmitUnimplementedEvent ( t , name )
}
// Default to the old behavior; hand off to network stack.
return syserr . TranslateNetstackError ( ep . SetSockOpt ( struct { } { } ) )
}
// setSockOptTCP implements SetSockOpt when level is SOL_TCP.
func setSockOptTCP ( t * kernel . Task , ep commonEndpoint , name int , optVal [ ] byte ) * syserr . Error {
switch name {
case linux . TCP_NODELAY :
if len ( optVal ) < sizeOfInt32 {
return syserr . ErrInvalidArgument
}
v := usermem . ByteOrder . Uint32 ( optVal )
var o tcpip . DelayOption
if v == 0 {
o = 1
}
return syserr . TranslateNetstackError ( ep . SetSockOpt ( o ) )
case linux . TCP_CORK :
if len ( optVal ) < sizeOfInt32 {
2018-04-27 17:37:02 +00:00
return syserr . ErrInvalidArgument
}
2018-11-19 23:25:00 +00:00
v := usermem . ByteOrder . Uint32 ( optVal )
return syserr . TranslateNetstackError ( ep . SetSockOpt ( tcpip . CorkOption ( v ) ) )
2018-12-09 08:49:37 +00:00
case linux . TCP_QUICKACK :
if len ( optVal ) < sizeOfInt32 {
return syserr . ErrInvalidArgument
}
v := usermem . ByteOrder . Uint32 ( optVal )
return syserr . TranslateNetstackError ( ep . SetSockOpt ( tcpip . QuickAckOption ( v ) ) )
2018-11-19 23:25:00 +00:00
case linux . TCP_REPAIR_OPTIONS :
t . Kernel ( ) . EmitUnimplementedEvent ( t )
default :
emitUmplementedEventTCP ( t , name )
2018-04-27 17:37:02 +00:00
}
// Default to the old behavior; hand off to network stack.
return syserr . TranslateNetstackError ( ep . SetSockOpt ( struct { } { } ) )
}
2018-11-19 23:25:00 +00:00
// setSockOptIPv6 implements SetSockOpt when level is SOL_IPV6.
func setSockOptIPv6 ( t * kernel . Task , ep commonEndpoint , name int , optVal [ ] byte ) * syserr . Error {
switch name {
case linux . IPV6_V6ONLY :
if len ( optVal ) < sizeOfInt32 {
return syserr . ErrInvalidArgument
}
v := usermem . ByteOrder . Uint32 ( optVal )
return syserr . TranslateNetstackError ( ep . SetSockOpt ( tcpip . V6OnlyOption ( v ) ) )
case linux . IPV6_ADD_MEMBERSHIP ,
linux . IPV6_DROP_MEMBERSHIP ,
linux . IPV6_IPSEC_POLICY ,
linux . IPV6_JOIN_ANYCAST ,
linux . IPV6_LEAVE_ANYCAST ,
linux . IPV6_PKTINFO ,
linux . IPV6_ROUTER_ALERT ,
linux . IPV6_XFRM_POLICY ,
linux . MCAST_BLOCK_SOURCE ,
linux . MCAST_JOIN_GROUP ,
linux . MCAST_JOIN_SOURCE_GROUP ,
linux . MCAST_LEAVE_GROUP ,
linux . MCAST_LEAVE_SOURCE_GROUP ,
linux . MCAST_UNBLOCK_SOURCE :
t . Kernel ( ) . EmitUnimplementedEvent ( t )
default :
emitUmplementedEventIPv6 ( t , name )
}
// Default to the old behavior; hand off to network stack.
return syserr . TranslateNetstackError ( ep . SetSockOpt ( struct { } { } ) )
}
// setSockOptIP implements SetSockOpt when level is SOL_IP.
func setSockOptIP ( t * kernel . Task , ep commonEndpoint , name int , optVal [ ] byte ) * syserr . Error {
switch name {
case linux . IP_ADD_MEMBERSHIP , linux . MCAST_JOIN_GROUP , linux . IP_MULTICAST_IF :
// FIXME: Disallow IP-level multicast group options by
// default. These will need to be supported by appropriately plumbing
// the level through to the network stack (if at all). However, we
// still allow setting TTL, and multicast-enable/disable type options.
t . Kernel ( ) . EmitUnimplementedEvent ( t )
return syserr . ErrInvalidArgument
case linux . IP_ADD_SOURCE_MEMBERSHIP ,
linux . IP_BIND_ADDRESS_NO_PORT ,
linux . IP_BLOCK_SOURCE ,
linux . IP_CHECKSUM ,
linux . IP_DROP_MEMBERSHIP ,
linux . IP_DROP_SOURCE_MEMBERSHIP ,
linux . IP_FREEBIND ,
linux . IP_HDRINCL ,
linux . IP_IPSEC_POLICY ,
linux . IP_MINTTL ,
linux . IP_MSFILTER ,
linux . IP_MTU_DISCOVER ,
linux . IP_MULTICAST_ALL ,
linux . IP_MULTICAST_LOOP ,
linux . IP_MULTICAST_TTL ,
linux . IP_NODEFRAG ,
linux . IP_OPTIONS ,
linux . IP_PASSSEC ,
linux . IP_PKTINFO ,
linux . IP_RECVERR ,
linux . IP_RECVFRAGSIZE ,
linux . IP_RECVOPTS ,
linux . IP_RECVORIGDSTADDR ,
linux . IP_RECVTOS ,
linux . IP_RECVTTL ,
linux . IP_RETOPTS ,
linux . IP_TOS ,
linux . IP_TRANSPARENT ,
linux . IP_TTL ,
linux . IP_UNBLOCK_SOURCE ,
linux . IP_UNICAST_IF ,
linux . IP_XFRM_POLICY ,
linux . MCAST_BLOCK_SOURCE ,
linux . MCAST_JOIN_SOURCE_GROUP ,
linux . MCAST_LEAVE_GROUP ,
linux . MCAST_LEAVE_SOURCE_GROUP ,
linux . MCAST_MSFILTER ,
linux . MCAST_UNBLOCK_SOURCE :
t . Kernel ( ) . EmitUnimplementedEvent ( t )
}
// Default to the old behavior; hand off to network stack.
return syserr . TranslateNetstackError ( ep . SetSockOpt ( struct { } { } ) )
}
// emitUmplementedEventTCP emits unimplemented event if name is valid. This
// function contains names that are common between Get and SetSockOpt when
// level is SOL_TCP.
func emitUmplementedEventTCP ( t * kernel . Task , name int ) {
switch name {
case linux . TCP_CONGESTION ,
linux . TCP_CORK ,
linux . TCP_DEFER_ACCEPT ,
linux . TCP_FASTOPEN ,
linux . TCP_FASTOPEN_CONNECT ,
linux . TCP_FASTOPEN_KEY ,
linux . TCP_FASTOPEN_NO_COOKIE ,
linux . TCP_INQ ,
linux . TCP_KEEPCNT ,
linux . TCP_KEEPIDLE ,
linux . TCP_KEEPINTVL ,
linux . TCP_LINGER2 ,
linux . TCP_MAXSEG ,
linux . TCP_QUEUE_SEQ ,
linux . TCP_QUICKACK ,
linux . TCP_REPAIR ,
linux . TCP_REPAIR_QUEUE ,
linux . TCP_REPAIR_WINDOW ,
linux . TCP_SAVED_SYN ,
linux . TCP_SAVE_SYN ,
linux . TCP_SYNCNT ,
linux . TCP_THIN_DUPACK ,
linux . TCP_THIN_LINEAR_TIMEOUTS ,
linux . TCP_TIMESTAMP ,
linux . TCP_ULP ,
linux . TCP_USER_TIMEOUT ,
linux . TCP_WINDOW_CLAMP :
t . Kernel ( ) . EmitUnimplementedEvent ( t )
}
}
// emitUmplementedEventIPv6 emits unimplemented event if name is valid. It
// contains names that are common between Get and SetSockOpt when level is
// SOL_IPV6.
func emitUmplementedEventIPv6 ( t * kernel . Task , name int ) {
switch name {
case linux . IPV6_2292DSTOPTS ,
linux . IPV6_2292HOPLIMIT ,
linux . IPV6_2292HOPOPTS ,
linux . IPV6_2292PKTINFO ,
linux . IPV6_2292PKTOPTIONS ,
linux . IPV6_2292RTHDR ,
linux . IPV6_ADDR_PREFERENCES ,
linux . IPV6_AUTOFLOWLABEL ,
linux . IPV6_DONTFRAG ,
linux . IPV6_DSTOPTS ,
linux . IPV6_FLOWINFO ,
linux . IPV6_FLOWINFO_SEND ,
linux . IPV6_FLOWLABEL_MGR ,
linux . IPV6_FREEBIND ,
linux . IPV6_HOPOPTS ,
linux . IPV6_MINHOPCOUNT ,
linux . IPV6_MTU ,
linux . IPV6_MTU_DISCOVER ,
linux . IPV6_MULTICAST_ALL ,
linux . IPV6_MULTICAST_HOPS ,
linux . IPV6_MULTICAST_IF ,
linux . IPV6_MULTICAST_LOOP ,
linux . IPV6_RECVDSTOPTS ,
linux . IPV6_RECVERR ,
linux . IPV6_RECVFRAGSIZE ,
linux . IPV6_RECVHOPLIMIT ,
linux . IPV6_RECVHOPOPTS ,
linux . IPV6_RECVORIGDSTADDR ,
linux . IPV6_RECVPATHMTU ,
linux . IPV6_RECVPKTINFO ,
linux . IPV6_RECVRTHDR ,
linux . IPV6_RECVTCLASS ,
linux . IPV6_RTHDR ,
linux . IPV6_RTHDRDSTOPTS ,
linux . IPV6_TCLASS ,
linux . IPV6_TRANSPARENT ,
linux . IPV6_UNICAST_HOPS ,
linux . IPV6_UNICAST_IF ,
linux . MCAST_MSFILTER ,
linux . IPV6_ADDRFORM :
t . Kernel ( ) . EmitUnimplementedEvent ( t )
}
}
2018-04-27 17:37:02 +00:00
// isLinkLocal determines if the given IPv6 address is link-local. This is the
// case when it has the fe80::/10 prefix. This check is used to determine when
// the NICID is relevant for a given IPv6 address.
func isLinkLocal ( addr tcpip . Address ) bool {
return len ( addr ) >= 2 && addr [ 0 ] == 0xfe && addr [ 1 ] & 0xc0 == 0x80
}
// ConvertAddress converts the given address to a native format.
func ConvertAddress ( family int , addr tcpip . FullAddress ) ( interface { } , uint32 ) {
switch family {
case linux . AF_UNIX :
var out linux . SockAddrUnix
out . Family = linux . AF_UNIX
2018-08-20 23:08:32 +00:00
l := len ( [ ] byte ( addr . Addr ) )
for i := 0 ; i < l ; i ++ {
2018-04-27 17:37:02 +00:00
out . Path [ i ] = int8 ( addr . Addr [ i ] )
}
2018-08-20 23:08:32 +00:00
2018-04-27 17:37:02 +00:00
// Linux returns the used length of the address struct (including the
// null terminator) for filesystem paths. The Family field is 2 bytes.
// It is sometimes allowed to exclude the null terminator if the
2018-08-20 23:08:32 +00:00
// address length is the max. Abstract and empty paths always return
// the full exact length.
if l == 0 || out . Path [ 0 ] == 0 || l == len ( out . Path ) {
return out , uint32 ( 2 + l )
2018-04-27 17:37:02 +00:00
}
2018-08-20 23:08:32 +00:00
return out , uint32 ( 3 + l )
2018-04-27 17:37:02 +00:00
case linux . AF_INET :
var out linux . SockAddrInet
copy ( out . Addr [ : ] , addr . Addr )
out . Family = linux . AF_INET
out . Port = htons ( addr . Port )
return out , uint32 ( binary . Size ( out ) )
case linux . AF_INET6 :
var out linux . SockAddrInet6
if len ( addr . Addr ) == 4 {
// Copy address is v4-mapped format.
copy ( out . Addr [ 12 : ] , addr . Addr )
out . Addr [ 10 ] = 0xff
out . Addr [ 11 ] = 0xff
} else {
copy ( out . Addr [ : ] , addr . Addr )
}
out . Family = linux . AF_INET6
out . Port = htons ( addr . Port )
if isLinkLocal ( addr . Addr ) {
out . Scope_id = uint32 ( addr . NIC )
}
return out , uint32 ( binary . Size ( out ) )
default :
return nil , 0
}
}
// GetSockName implements the linux syscall getsockname(2) for sockets backed by
// tcpip.Endpoint.
func ( s * SocketOperations ) GetSockName ( t * kernel . Task ) ( interface { } , uint32 , * syserr . Error ) {
addr , err := s . Endpoint . GetLocalAddress ( )
if err != nil {
return nil , 0 , syserr . TranslateNetstackError ( err )
}
a , l := ConvertAddress ( s . family , addr )
return a , l , nil
}
// GetPeerName implements the linux syscall getpeername(2) for sockets backed by
// tcpip.Endpoint.
func ( s * SocketOperations ) GetPeerName ( t * kernel . Task ) ( interface { } , uint32 , * syserr . Error ) {
addr , err := s . Endpoint . GetRemoteAddress ( )
if err != nil {
return nil , 0 , syserr . TranslateNetstackError ( err )
}
a , l := ConvertAddress ( s . family , addr )
return a , l , nil
}
// coalescingRead is the fast path for non-blocking, non-peek, stream-based
// case. It coalesces as many packets as possible before returning to the
// caller.
func ( s * SocketOperations ) coalescingRead ( ctx context . Context , dst usermem . IOSequence , discard bool ) ( int , * syserr . Error ) {
var err * syserr . Error
var copied int
// Copy as many views as possible into the user-provided buffer.
for dst . NumBytes ( ) != 0 {
err = s . fetchReadView ( )
if err != nil {
break
}
var n int
var e error
if discard {
n = len ( s . readView )
if int64 ( n ) > dst . NumBytes ( ) {
n = int ( dst . NumBytes ( ) )
}
} else {
n , e = dst . CopyOut ( ctx , s . readView )
}
copied += n
s . readView . TrimFront ( n )
dst = dst . DropFirst ( n )
if e != nil {
err = syserr . FromError ( e )
break
}
}
// If we managed to copy something, we must deliver it.
if copied > 0 {
return copied , nil
}
return 0 , err
}
// nonBlockingRead issues a non-blocking read.
2018-05-02 05:11:07 +00:00
//
// TODO: Support timestamps for stream sockets.
func ( s * SocketOperations ) nonBlockingRead ( ctx context . Context , dst usermem . IOSequence , peek , trunc , senderRequested bool ) ( int , interface { } , uint32 , socket . ControlMessages , * syserr . Error ) {
2018-04-27 17:37:02 +00:00
isPacket := s . isPacketBased ( )
// Fast path for regular reads from stream (e.g., TCP) endpoints. Note
// that senderRequested is ignored for stream sockets.
if ! peek && ! isPacket {
// TCP sockets discard the data if MSG_TRUNC is set.
//
// This behavior is documented in man 7 tcp:
// Since version 2.4, Linux supports the use of MSG_TRUNC in the flags
// argument of recv(2) (and recvmsg(2)). This flag causes the received
// bytes of data to be discarded, rather than passed back in a
// caller-supplied buffer.
s . readMu . Lock ( )
n , err := s . coalescingRead ( ctx , dst , trunc )
s . readMu . Unlock ( )
2018-05-02 05:11:07 +00:00
return n , nil , 0 , socket . ControlMessages { } , err
2018-04-27 17:37:02 +00:00
}
s . readMu . Lock ( )
defer s . readMu . Unlock ( )
if err := s . fetchReadView ( ) ; err != nil {
2018-05-02 05:11:07 +00:00
return 0 , nil , 0 , socket . ControlMessages { } , err
2018-04-27 17:37:02 +00:00
}
if ! isPacket && peek && trunc {
// MSG_TRUNC with MSG_PEEK on a TCP socket returns the
// amount that could be read.
var rql tcpip . ReceiveQueueSizeOption
if err := s . Endpoint . GetSockOpt ( & rql ) ; err != nil {
2018-05-02 05:11:07 +00:00
return 0 , nil , 0 , socket . ControlMessages { } , syserr . TranslateNetstackError ( err )
2018-04-27 17:37:02 +00:00
}
available := len ( s . readView ) + int ( rql )
bufLen := int ( dst . NumBytes ( ) )
if available < bufLen {
2018-05-02 05:11:07 +00:00
return available , nil , 0 , socket . ControlMessages { } , nil
2018-04-27 17:37:02 +00:00
}
2018-05-02 05:11:07 +00:00
return bufLen , nil , 0 , socket . ControlMessages { } , nil
2018-04-27 17:37:02 +00:00
}
n , err := dst . CopyOut ( ctx , s . readView )
var addr interface { }
var addrLen uint32
if isPacket && senderRequested {
addr , addrLen = ConvertAddress ( s . family , s . sender )
}
if peek {
if l := len ( s . readView ) ; trunc && l > n {
// isPacket must be true.
2018-05-02 05:11:07 +00:00
return l , addr , addrLen , socket . ControlMessages { IP : s . readCM } , syserr . FromError ( err )
2018-04-27 17:37:02 +00:00
}
if isPacket || err != nil {
2018-05-02 05:11:07 +00:00
return int ( n ) , addr , addrLen , socket . ControlMessages { IP : s . readCM } , syserr . FromError ( err )
2018-04-27 17:37:02 +00:00
}
// We need to peek beyond the first message.
dst = dst . DropFirst ( n )
num , err := dst . CopyOutFrom ( ctx , safemem . FromVecReaderFunc { func ( dsts [ ] [ ] byte ) ( int64 , error ) {
2018-05-02 05:11:07 +00:00
n , _ , err := s . Endpoint . Peek ( dsts )
// TODO: Handle peek timestamp.
2018-04-27 17:37:02 +00:00
if err != nil {
return int64 ( n ) , syserr . TranslateNetstackError ( err ) . ToError ( )
}
return int64 ( n ) , nil
} } )
n += int ( num )
if err == syserror . ErrWouldBlock && n > 0 {
// We got some data, so no need to return an error.
err = nil
}
2018-05-02 05:11:07 +00:00
return int ( n ) , nil , 0 , socket . ControlMessages { IP : s . readCM } , syserr . FromError ( err )
2018-04-27 17:37:02 +00:00
}
var msgLen int
if isPacket {
msgLen = len ( s . readView )
s . readView = nil
} else {
msgLen = int ( n )
s . readView . TrimFront ( int ( n ) )
}
if trunc {
2018-05-02 05:11:07 +00:00
return msgLen , addr , addrLen , socket . ControlMessages { IP : s . readCM } , syserr . FromError ( err )
2018-04-27 17:37:02 +00:00
}
2018-05-02 05:11:07 +00:00
return int ( n ) , addr , addrLen , socket . ControlMessages { IP : s . readCM } , syserr . FromError ( err )
2018-04-27 17:37:02 +00:00
}
// RecvMsg implements the linux syscall recvmsg(2) for sockets backed by
// tcpip.Endpoint.
2018-05-02 05:11:07 +00:00
func ( s * SocketOperations ) RecvMsg ( t * kernel . Task , dst usermem . IOSequence , flags int , haveDeadline bool , deadline ktime . Time , senderRequested bool , controlDataLen uint64 ) ( n int , senderAddr interface { } , senderAddrLen uint32 , controlMessages socket . ControlMessages , err * syserr . Error ) {
2018-04-27 17:37:02 +00:00
trunc := flags & linux . MSG_TRUNC != 0
peek := flags & linux . MSG_PEEK != 0
2018-12-11 01:55:45 +00:00
dontWait := flags & linux . MSG_DONTWAIT != 0
waitAll := flags & linux . MSG_WAITALL != 0
2018-04-27 17:37:02 +00:00
if senderRequested && ! s . isPacketBased ( ) {
// Stream sockets ignore the sender address.
senderRequested = false
}
2018-05-02 05:11:07 +00:00
n , senderAddr , senderAddrLen , controlMessages , err = s . nonBlockingRead ( t , dst , peek , trunc , senderRequested )
2018-06-20 00:28:19 +00:00
2018-06-22 17:18:19 +00:00
if s . isPacketBased ( ) && err == syserr . ErrClosedForReceive && flags & linux . MSG_DONTWAIT != 0 {
2018-06-20 00:28:19 +00:00
// In this situation we should return EAGAIN.
return 0 , nil , 0 , socket . ControlMessages { } , syserr . ErrTryAgain
}
2018-12-11 01:55:45 +00:00
if err != nil && ( err != syserr . ErrWouldBlock || dontWait ) {
// Read failed and we should not retry.
return 0 , nil , 0 , socket . ControlMessages { } , err
}
if err == nil && ( dontWait || ! waitAll || s . isPacketBased ( ) || int64 ( n ) >= dst . NumBytes ( ) ) {
// We got all the data we need.
2018-04-27 17:37:02 +00:00
return
}
2018-12-11 01:55:45 +00:00
// Don't overwrite any data we received.
dst = dst . DropFirst ( n )
2018-04-27 17:37:02 +00:00
// We'll have to block. Register for notifications and keep trying to
// send all the data.
e , ch := waiter . NewChannelEntry ( nil )
s . EventRegister ( & e , waiter . EventIn )
defer s . EventUnregister ( & e )
for {
2018-12-11 01:55:45 +00:00
var rn int
rn , senderAddr , senderAddrLen , controlMessages , err = s . nonBlockingRead ( t , dst , peek , trunc , senderRequested )
n += rn
if err != nil && err != syserr . ErrWouldBlock {
// Always stop on errors other than would block as we generally
// won't be able to get any more data. Eat the error if we got
// any data.
if n > 0 {
err = nil
}
return
}
if err == nil && ( s . isPacketBased ( ) || ! waitAll || int64 ( rn ) >= dst . NumBytes ( ) ) {
// We got all the data we need.
2018-04-27 17:37:02 +00:00
return
}
2018-12-11 01:55:45 +00:00
dst = dst . DropFirst ( rn )
2018-04-27 17:37:02 +00:00
if err := t . BlockWithDeadline ( ch , haveDeadline , deadline ) ; err != nil {
2018-12-13 21:19:39 +00:00
if n > 0 {
return n , senderAddr , senderAddrLen , controlMessages , nil
}
2018-04-27 17:37:02 +00:00
if err == syserror . ETIMEDOUT {
2018-05-02 05:11:07 +00:00
return 0 , nil , 0 , socket . ControlMessages { } , syserr . ErrTryAgain
2018-04-27 17:37:02 +00:00
}
2018-05-02 05:11:07 +00:00
return 0 , nil , 0 , socket . ControlMessages { } , syserr . FromError ( err )
2018-04-27 17:37:02 +00:00
}
}
}
// SendMsg implements the linux syscall sendmsg(2) for sockets backed by
// tcpip.Endpoint.
2018-05-02 05:11:07 +00:00
func ( s * SocketOperations ) SendMsg ( t * kernel . Task , src usermem . IOSequence , to [ ] byte , flags int , controlMessages socket . ControlMessages ) ( int , * syserr . Error ) {
// Reject Unix control messages.
if ! controlMessages . Unix . Empty ( ) {
2018-04-27 17:37:02 +00:00
return 0 , syserr . ErrInvalidArgument
}
var addr * tcpip . FullAddress
if len ( to ) > 0 {
addrBuf , err := GetAddress ( s . family , to )
if err != nil {
return 0 , err
}
addr = & addrBuf
}
v := buffer . NewView ( int ( src . NumBytes ( ) ) )
// Copy all the data into the buffer.
if _ , err := src . CopyIn ( t , v ) ; err != nil {
return 0 , syserr . FromError ( err )
}
opts := tcpip . WriteOptions {
To : addr ,
More : flags & linux . MSG_MORE != 0 ,
EndOfRecord : flags & linux . MSG_EOR != 0 ,
}
2018-09-28 17:59:21 +00:00
n , resCh , err := s . Endpoint . Write ( tcpip . SlicePayload ( v ) , opts )
if resCh != nil {
if err := t . Block ( resCh ) ; err != nil {
2018-12-06 19:40:39 +00:00
return 0 , syserr . FromError ( err )
2018-09-28 17:59:21 +00:00
}
n , _ , err = s . Endpoint . Write ( tcpip . SlicePayload ( v ) , opts )
}
2018-12-06 19:40:39 +00:00
dontWait := flags & linux . MSG_DONTWAIT != 0
if err == nil && ( n >= uintptr ( len ( v ) ) || dontWait ) {
// Complete write.
return int ( n ) , nil
}
if err != nil && ( err != tcpip . ErrWouldBlock || dontWait ) {
2018-04-27 17:37:02 +00:00
return int ( n ) , syserr . TranslateNetstackError ( err )
}
// We'll have to block. Register for notification and keep trying to
// send all the data.
e , ch := waiter . NewChannelEntry ( nil )
s . EventRegister ( & e , waiter . EventOut )
defer s . EventUnregister ( & e )
v . TrimFront ( int ( n ) )
total := n
for {
2018-09-28 17:59:21 +00:00
n , _ , err = s . Endpoint . Write ( tcpip . SlicePayload ( v ) , opts )
2018-04-27 17:37:02 +00:00
v . TrimFront ( int ( n ) )
total += n
2018-12-06 19:40:39 +00:00
if err != nil && err != tcpip . ErrWouldBlock && total == 0 {
return 0 , syserr . TranslateNetstackError ( err )
}
if err == nil && len ( v ) == 0 || err != nil && err != tcpip . ErrWouldBlock {
return int ( total ) , nil
2018-04-27 17:37:02 +00:00
}
if err := t . Block ( ch ) ; err != nil {
2018-12-06 19:40:39 +00:00
// handleIOError will consume errors from t.Block if needed.
2018-04-27 17:37:02 +00:00
return int ( total ) , syserr . FromError ( err )
}
}
}
2018-05-18 17:42:52 +00:00
// Ioctl implements fs.FileOperations.Ioctl.
func ( s * SocketOperations ) Ioctl ( ctx context . Context , io usermem . IO , args arch . SyscallArguments ) ( uintptr , error ) {
return Ioctl ( ctx , s . Endpoint , io , args )
}
// Ioctl performs a socket ioctl.
func Ioctl ( ctx context . Context , ep commonEndpoint , io usermem . IO , args arch . SyscallArguments ) ( uintptr , error ) {
switch arg := int ( args [ 1 ] . Int ( ) ) ; arg {
case syscall . SIOCGIFFLAGS ,
syscall . SIOCGIFADDR ,
syscall . SIOCGIFBRDADDR ,
syscall . SIOCGIFDSTADDR ,
syscall . SIOCGIFHWADDR ,
syscall . SIOCGIFINDEX ,
syscall . SIOCGIFMAP ,
syscall . SIOCGIFMETRIC ,
syscall . SIOCGIFMTU ,
syscall . SIOCGIFNAME ,
syscall . SIOCGIFNETMASK ,
syscall . SIOCGIFTXQLEN :
var ifr linux . IFReq
if _ , err := usermem . CopyObjectIn ( ctx , io , args [ 2 ] . Pointer ( ) , & ifr , usermem . IOOpts {
AddressSpaceActive : true ,
} ) ; err != nil {
return 0 , err
}
if err := interfaceIoctl ( ctx , io , arg , & ifr ) ; err != nil {
return 0 , err . ToError ( )
}
_ , err := usermem . CopyObjectOut ( ctx , io , args [ 2 ] . Pointer ( ) , & ifr , usermem . IOOpts {
AddressSpaceActive : true ,
} )
return 0 , err
case syscall . SIOCGIFCONF :
// Return a list of interface addresses or the buffer size
// necessary to hold the list.
var ifc linux . IFConf
if _ , err := usermem . CopyObjectIn ( ctx , io , args [ 2 ] . Pointer ( ) , & ifc , usermem . IOOpts {
AddressSpaceActive : true ,
} ) ; err != nil {
return 0 , err
}
if err := ifconfIoctl ( ctx , io , & ifc ) ; err != nil {
return 0 , err
}
_ , err := usermem . CopyObjectOut ( ctx , io , args [ 2 ] . Pointer ( ) , ifc , usermem . IOOpts {
AddressSpaceActive : true ,
} )
return 0 , err
case linux . TIOCINQ :
var v tcpip . ReceiveQueueSizeOption
if err := ep . GetSockOpt ( & v ) ; err != nil {
return 0 , syserr . TranslateNetstackError ( err ) . ToError ( )
}
if v > math . MaxInt32 {
v = math . MaxInt32
}
// Copy result to user-space.
_ , err := usermem . CopyObjectOut ( ctx , io , args [ 2 ] . Pointer ( ) , int32 ( v ) , usermem . IOOpts {
AddressSpaceActive : true ,
} )
return 0 , err
case linux . TIOCOUTQ :
var v tcpip . SendQueueSizeOption
if err := ep . GetSockOpt ( & v ) ; err != nil {
return 0 , syserr . TranslateNetstackError ( err ) . ToError ( )
}
if v > math . MaxInt32 {
v = math . MaxInt32
}
// Copy result to user-space.
_ , err := usermem . CopyObjectOut ( ctx , io , args [ 2 ] . Pointer ( ) , int32 ( v ) , usermem . IOOpts {
AddressSpaceActive : true ,
} )
return 0 , err
2018-10-20 18:12:26 +00:00
case linux . SIOCGIFMEM , linux . SIOCGIFPFLAGS , linux . SIOCGMIIPHY , linux . SIOCGMIIREG :
unimpl . EmitUnimplementedEvent ( ctx )
2018-05-18 17:42:52 +00:00
}
return 0 , syserror . ENOTTY
}
2018-04-27 17:37:02 +00:00
// interfaceIoctl implements interface requests.
2018-05-18 17:42:52 +00:00
func interfaceIoctl ( ctx context . Context , io usermem . IO , arg int , ifr * linux . IFReq ) * syserr . Error {
2018-04-27 17:37:02 +00:00
var (
iface inet . Interface
index int32
found bool
)
// Find the relevant device.
2018-05-15 21:55:29 +00:00
stack := inet . StackFromContext ( ctx )
if stack == nil {
2018-05-18 17:42:52 +00:00
return syserr . ErrNoDevice
2018-05-15 21:55:29 +00:00
}
2018-05-18 17:42:52 +00:00
// SIOCGIFNAME uses ifr.ifr_ifindex rather than ifr.ifr_name to
// identify a device.
if arg == syscall . SIOCGIFNAME {
// Gets the name of the interface given the interface index
// stored in ifr_ifindex.
index = int32 ( usermem . ByteOrder . Uint32 ( ifr . Data [ : 4 ] ) )
if iface , ok := stack . Interfaces ( ) [ index ] ; ok {
ifr . SetName ( iface . Name )
return nil
}
return syserr . ErrNoDevice
}
// Find the relevant device.
2018-05-15 21:55:29 +00:00
for index , iface = range stack . Interfaces ( ) {
2018-04-27 17:37:02 +00:00
if iface . Name == ifr . Name ( ) {
found = true
break
}
}
if ! found {
return syserr . ErrNoDevice
}
switch arg {
case syscall . SIOCGIFINDEX :
// Copy out the index to the data.
usermem . ByteOrder . PutUint32 ( ifr . Data [ : ] , uint32 ( index ) )
case syscall . SIOCGIFHWADDR :
// Copy the hardware address out.
ifr . Data [ 0 ] = 6 // IEEE802.2 arp type.
ifr . Data [ 1 ] = 0
n := copy ( ifr . Data [ 2 : ] , iface . Addr )
for i := 2 + n ; i < len ( ifr . Data ) ; i ++ {
ifr . Data [ i ] = 0 // Clear padding.
}
usermem . ByteOrder . PutUint16 ( ifr . Data [ : 2 ] , uint16 ( n ) )
case syscall . SIOCGIFFLAGS :
2018-05-22 20:46:37 +00:00
f , err := interfaceStatusFlags ( stack , iface . Name )
if err != nil {
return err
}
2018-08-09 05:38:41 +00:00
// Drop the flags that don't fit in the size that we need to return. This
// matches Linux behavior.
usermem . ByteOrder . PutUint16 ( ifr . Data [ : 2 ] , uint16 ( f ) )
2018-04-27 17:37:02 +00:00
case syscall . SIOCGIFADDR :
// Copy the IPv4 address out.
2018-05-15 21:55:29 +00:00
for _ , addr := range stack . InterfaceAddrs ( ) [ index ] {
2018-04-27 17:37:02 +00:00
// This ioctl is only compatible with AF_INET addresses.
if addr . Family != linux . AF_INET {
continue
}
copy ( ifr . Data [ 4 : 8 ] , addr . Addr )
break
}
case syscall . SIOCGIFMETRIC :
// Gets the metric of the device. As per netdevice(7), this
// always just sets ifr_metric to 0.
usermem . ByteOrder . PutUint32 ( ifr . Data [ : 4 ] , 0 )
2018-10-12 20:57:10 +00:00
2018-04-27 17:37:02 +00:00
case syscall . SIOCGIFMTU :
// Gets the MTU of the device.
2018-10-12 20:57:10 +00:00
usermem . ByteOrder . PutUint32 ( ifr . Data [ : 4 ] , iface . MTU )
2018-04-27 17:37:02 +00:00
case syscall . SIOCGIFMAP :
// Gets the hardware parameters of the device.
// TODO: Implement.
case syscall . SIOCGIFTXQLEN :
// Gets the transmit queue length of the device.
// TODO: Implement.
case syscall . SIOCGIFDSTADDR :
// Gets the destination address of a point-to-point device.
// TODO: Implement.
case syscall . SIOCGIFBRDADDR :
// Gets the broadcast address of a device.
// TODO: Implement.
case syscall . SIOCGIFNETMASK :
// Gets the network mask of a device.
2018-05-15 21:55:29 +00:00
for _ , addr := range stack . InterfaceAddrs ( ) [ index ] {
2018-05-04 23:21:38 +00:00
// This ioctl is only compatible with AF_INET addresses.
if addr . Family != linux . AF_INET {
continue
}
// Populate ifr.ifr_netmask (type sockaddr).
usermem . ByteOrder . PutUint16 ( ifr . Data [ 0 : 2 ] , uint16 ( linux . AF_INET ) )
usermem . ByteOrder . PutUint16 ( ifr . Data [ 2 : 4 ] , 0 )
var mask uint32 = 0xffffffff << ( 32 - addr . PrefixLen )
// Netmask is expected to be returned as a big endian
// value.
binary . BigEndian . PutUint32 ( ifr . Data [ 4 : 8 ] , mask )
break
}
2018-04-27 17:37:02 +00:00
default :
// Not a valid call.
return syserr . ErrInvalidArgument
}
return nil
}
// ifconfIoctl populates a struct ifconf for the SIOCGIFCONF ioctl.
2018-05-18 17:42:52 +00:00
func ifconfIoctl ( ctx context . Context , io usermem . IO , ifc * linux . IFConf ) error {
2018-04-27 17:37:02 +00:00
// If Ptr is NULL, return the necessary buffer size via Len.
// Otherwise, write up to Len bytes starting at Ptr containing ifreq
// structs.
2018-05-15 21:55:29 +00:00
stack := inet . StackFromContext ( ctx )
if stack == nil {
2018-05-18 17:42:52 +00:00
return syserr . ErrNoDevice . ToError ( )
2018-05-15 21:55:29 +00:00
}
2018-05-18 17:42:52 +00:00
2018-04-27 17:37:02 +00:00
if ifc . Ptr == 0 {
2018-05-15 21:55:29 +00:00
ifc . Len = int32 ( len ( stack . Interfaces ( ) ) ) * int32 ( linux . SizeOfIFReq )
2018-04-27 17:37:02 +00:00
return nil
}
max := ifc . Len
ifc . Len = 0
2018-05-15 21:55:29 +00:00
for key , ifaceAddrs := range stack . InterfaceAddrs ( ) {
iface := stack . Interfaces ( ) [ key ]
2018-04-27 17:37:02 +00:00
for _ , ifaceAddr := range ifaceAddrs {
// Don't write past the end of the buffer.
if ifc . Len + int32 ( linux . SizeOfIFReq ) > max {
break
}
if ifaceAddr . Family != linux . AF_INET {
continue
}
// Populate ifr.ifr_addr.
ifr := linux . IFReq { }
ifr . SetName ( iface . Name )
usermem . ByteOrder . PutUint16 ( ifr . Data [ 0 : 2 ] , uint16 ( ifaceAddr . Family ) )
usermem . ByteOrder . PutUint16 ( ifr . Data [ 2 : 4 ] , 0 )
copy ( ifr . Data [ 4 : 8 ] , ifaceAddr . Addr [ : 4 ] )
// Copy the ifr to userspace.
dst := uintptr ( ifc . Ptr ) + uintptr ( ifc . Len )
ifc . Len += int32 ( linux . SizeOfIFReq )
if _ , err := usermem . CopyObjectOut ( ctx , io , usermem . Addr ( dst ) , ifr , usermem . IOOpts {
AddressSpaceActive : true ,
} ) ; err != nil {
return err
}
}
}
return nil
}
2018-05-22 20:46:37 +00:00
// interfaceStatusFlags returns status flags for an interface in the stack.
// Flag values and meanings are described in greater detail in netdevice(7) in
// the SIOCGIFFLAGS section.
2018-08-09 05:38:41 +00:00
func interfaceStatusFlags ( stack inet . Stack , name string ) ( uint32 , * syserr . Error ) {
2018-05-22 20:46:37 +00:00
// epsocket should only ever be passed an epsocket.Stack.
epstack , ok := stack . ( * Stack )
if ! ok {
return 0 , errStackType
}
// Find the NIC corresponding to this interface.
2018-08-09 05:38:41 +00:00
for _ , info := range epstack . Stack . NICInfo ( ) {
2018-05-22 20:46:37 +00:00
if info . Name == name {
2018-08-09 05:38:41 +00:00
return nicStateFlagsToLinux ( info . Flags ) , nil
2018-05-22 20:46:37 +00:00
}
}
2018-08-09 05:38:41 +00:00
return 0 , syserr . ErrNoDevice
}
2018-05-22 20:46:37 +00:00
2018-08-09 05:38:41 +00:00
func nicStateFlagsToLinux ( f stack . NICStateFlags ) uint32 {
var rv uint32
if f . Up {
rv |= linux . IFF_UP | linux . IFF_LOWER_UP
2018-05-22 20:46:37 +00:00
}
2018-08-09 05:38:41 +00:00
if f . Running {
rv |= linux . IFF_RUNNING
2018-05-22 20:46:37 +00:00
}
2018-08-09 05:38:41 +00:00
if f . Promiscuous {
rv |= linux . IFF_PROMISC
2018-05-22 20:46:37 +00:00
}
2018-08-09 05:38:41 +00:00
if f . Loopback {
rv |= linux . IFF_LOOPBACK
2018-05-22 20:46:37 +00:00
}
2018-08-09 05:38:41 +00:00
return rv
2018-05-22 20:46:37 +00:00
}