vendor/golang.org/x/sys/unix/ifreq_linux.go
changeset 260 445e01aede7e
equal deleted inserted replaced
259:db4911b0c721 260:445e01aede7e
       
     1 // Copyright 2021 The Go Authors. All rights reserved.
       
     2 // Use of this source code is governed by a BSD-style
       
     3 // license that can be found in the LICENSE file.
       
     4 
       
     5 //go:build linux
       
     6 // +build linux
       
     7 
       
     8 package unix
       
     9 
       
    10 import (
       
    11 	"unsafe"
       
    12 )
       
    13 
       
    14 // Helpers for dealing with ifreq since it contains a union and thus requires a
       
    15 // lot of unsafe.Pointer casts to use properly.
       
    16 
       
    17 // An Ifreq is a type-safe wrapper around the raw ifreq struct. An Ifreq
       
    18 // contains an interface name and a union of arbitrary data which can be
       
    19 // accessed using the Ifreq's methods. To create an Ifreq, use the NewIfreq
       
    20 // function.
       
    21 //
       
    22 // Use the Name method to access the stored interface name. The union data
       
    23 // fields can be get and set using the following methods:
       
    24 //   - Uint16/SetUint16: flags
       
    25 //   - Uint32/SetUint32: ifindex, metric, mtu
       
    26 type Ifreq struct{ raw ifreq }
       
    27 
       
    28 // NewIfreq creates an Ifreq with the input network interface name after
       
    29 // validating the name does not exceed IFNAMSIZ-1 (trailing NULL required)
       
    30 // bytes.
       
    31 func NewIfreq(name string) (*Ifreq, error) {
       
    32 	// Leave room for terminating NULL byte.
       
    33 	if len(name) >= IFNAMSIZ {
       
    34 		return nil, EINVAL
       
    35 	}
       
    36 
       
    37 	var ifr ifreq
       
    38 	copy(ifr.Ifrn[:], name)
       
    39 
       
    40 	return &Ifreq{raw: ifr}, nil
       
    41 }
       
    42 
       
    43 // TODO(mdlayher): get/set methods for hardware address sockaddr, char array, etc.
       
    44 
       
    45 // Name returns the interface name associated with the Ifreq.
       
    46 func (ifr *Ifreq) Name() string {
       
    47 	return ByteSliceToString(ifr.raw.Ifrn[:])
       
    48 }
       
    49 
       
    50 // According to netdevice(7), only AF_INET addresses are returned for numerous
       
    51 // sockaddr ioctls. For convenience, we expose these as Inet4Addr since the Port
       
    52 // field and other data is always empty.
       
    53 
       
    54 // Inet4Addr returns the Ifreq union data from an embedded sockaddr as a C
       
    55 // in_addr/Go []byte (4-byte IPv4 address) value. If the sockaddr family is not
       
    56 // AF_INET, an error is returned.
       
    57 func (ifr *Ifreq) Inet4Addr() ([]byte, error) {
       
    58 	raw := *(*RawSockaddrInet4)(unsafe.Pointer(&ifr.raw.Ifru[:SizeofSockaddrInet4][0]))
       
    59 	if raw.Family != AF_INET {
       
    60 		// Cannot safely interpret raw.Addr bytes as an IPv4 address.
       
    61 		return nil, EINVAL
       
    62 	}
       
    63 
       
    64 	return raw.Addr[:], nil
       
    65 }
       
    66 
       
    67 // SetInet4Addr sets a C in_addr/Go []byte (4-byte IPv4 address) value in an
       
    68 // embedded sockaddr within the Ifreq's union data. v must be 4 bytes in length
       
    69 // or an error will be returned.
       
    70 func (ifr *Ifreq) SetInet4Addr(v []byte) error {
       
    71 	if len(v) != 4 {
       
    72 		return EINVAL
       
    73 	}
       
    74 
       
    75 	var addr [4]byte
       
    76 	copy(addr[:], v)
       
    77 
       
    78 	ifr.clear()
       
    79 	*(*RawSockaddrInet4)(
       
    80 		unsafe.Pointer(&ifr.raw.Ifru[:SizeofSockaddrInet4][0]),
       
    81 	) = RawSockaddrInet4{
       
    82 		// Always set IP family as ioctls would require it anyway.
       
    83 		Family: AF_INET,
       
    84 		Addr:   addr,
       
    85 	}
       
    86 
       
    87 	return nil
       
    88 }
       
    89 
       
    90 // Uint16 returns the Ifreq union data as a C short/Go uint16 value.
       
    91 func (ifr *Ifreq) Uint16() uint16 {
       
    92 	return *(*uint16)(unsafe.Pointer(&ifr.raw.Ifru[:2][0]))
       
    93 }
       
    94 
       
    95 // SetUint16 sets a C short/Go uint16 value as the Ifreq's union data.
       
    96 func (ifr *Ifreq) SetUint16(v uint16) {
       
    97 	ifr.clear()
       
    98 	*(*uint16)(unsafe.Pointer(&ifr.raw.Ifru[:2][0])) = v
       
    99 }
       
   100 
       
   101 // Uint32 returns the Ifreq union data as a C int/Go uint32 value.
       
   102 func (ifr *Ifreq) Uint32() uint32 {
       
   103 	return *(*uint32)(unsafe.Pointer(&ifr.raw.Ifru[:4][0]))
       
   104 }
       
   105 
       
   106 // SetUint32 sets a C int/Go uint32 value as the Ifreq's union data.
       
   107 func (ifr *Ifreq) SetUint32(v uint32) {
       
   108 	ifr.clear()
       
   109 	*(*uint32)(unsafe.Pointer(&ifr.raw.Ifru[:4][0])) = v
       
   110 }
       
   111 
       
   112 // clear zeroes the ifreq's union field to prevent trailing garbage data from
       
   113 // being sent to the kernel if an ifreq is reused.
       
   114 func (ifr *Ifreq) clear() {
       
   115 	for i := range ifr.raw.Ifru {
       
   116 		ifr.raw.Ifru[i] = 0
       
   117 	}
       
   118 }
       
   119 
       
   120 // TODO(mdlayher): export as IfreqData? For now we can provide helpers such as
       
   121 // IoctlGetEthtoolDrvinfo which use these APIs under the hood.
       
   122 
       
   123 // An ifreqData is an Ifreq which carries pointer data. To produce an ifreqData,
       
   124 // use the Ifreq.withData method.
       
   125 type ifreqData struct {
       
   126 	name [IFNAMSIZ]byte
       
   127 	// A type separate from ifreq is required in order to comply with the
       
   128 	// unsafe.Pointer rules since the "pointer-ness" of data would not be
       
   129 	// preserved if it were cast into the byte array of a raw ifreq.
       
   130 	data unsafe.Pointer
       
   131 	// Pad to the same size as ifreq.
       
   132 	_ [len(ifreq{}.Ifru) - SizeofPtr]byte
       
   133 }
       
   134 
       
   135 // withData produces an ifreqData with the pointer p set for ioctls which require
       
   136 // arbitrary pointer data.
       
   137 func (ifr Ifreq) withData(p unsafe.Pointer) ifreqData {
       
   138 	return ifreqData{
       
   139 		name: ifr.raw.Ifrn,
       
   140 		data: p,
       
   141 	}
       
   142 }