blob: 297719eeabae35b0f3105f3aba96b42e269d6501 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Ad-hoc unsafe encoding/decoding of C data types used by the
// protocol libc talks to netstack.
package main
import (
"fmt"
"log"
"syscall/zx"
"syscall/zx/mxerror"
"syscall/zx/zxsocket"
"unsafe"
"github.com/google/netstack/tcpip"
)
const (
c_sockaddr_in_len = int(unsafe.Sizeof(c_sockaddr_in{}))
c_sockaddr_in6_len = int(unsafe.Sizeof(c_sockaddr_in6{}))
c_sockaddr_storage_len = int(unsafe.Sizeof(c_sockaddr_storage{}))
c_mxrio_sockaddr_reply_len = int(unsafe.Sizeof(c_mxrio_sockaddr_reply{}))
c_fdio_socket_msg_hdr_len = int(unsafe.Sizeof(c_fdio_socket_msg_hdr{}))
)
func init() {
if c_sockaddr_storage_len < c_sockaddr_in_len {
panic("c_sockaddr_storage cannot hold c_sockaddr_in")
}
if c_sockaddr_storage_len < c_sockaddr_in6_len {
panic("c_sockaddr_storage cannot hold c_sockaddr_in6")
}
}
func (v *c_mxrio_sockopt_req_reply) Decode(data []byte) error {
if uintptr(len(data)) < unsafe.Sizeof(c_mxrio_sockopt_req_reply{}) {
return fmt.Errorf("netstack: short c_mxrio_sockopt_req_reply: %d", len(data))
}
req := (*c_mxrio_sockopt_req_reply)(unsafe.Pointer(&data[0]))
*v = *req
return nil
}
func (v *c_mxrio_sockopt_req_reply) Encode(msg *zxsocket.Msg) {
r := (*c_mxrio_sockopt_req_reply)(unsafe.Pointer(&msg.Data[0]))
*r = *v
msg.Datalen = uint32(unsafe.Sizeof(*v))
}
func (v *c_mxrio_sockopt_tcp_info) Encode(out *c_mxrio_sockopt_req_reply) error {
r := (*c_mxrio_sockopt_tcp_info)(unsafe.Pointer(&out.optval[0]))
*r = *v
out.optlen = c_socklen(unsafe.Sizeof(*v))
return nil
}
func (v *c_mxrio_sockaddr_reply) Encode(msg *zxsocket.Msg) {
r := (*c_mxrio_sockaddr_reply)(unsafe.Pointer(&msg.Data[0]))
*r = *v
msg.Datalen = uint32(unsafe.Sizeof(*v))
}
func (v *c_ip_mreq) Decode(data []byte) error {
if uintptr(len(data)) < unsafe.Sizeof(c_ip_mreq{}) {
return fmt.Errorf("netstack: short c_ip_mreq: %d", len(data))
}
req := (*c_ip_mreq)(unsafe.Pointer(&data[0]))
*v = *req
return nil
}
func (v *c_ip_mreqn) Decode(data []byte) error {
if uintptr(len(data)) < unsafe.Sizeof(c_ip_mreqn{}) {
return fmt.Errorf("netstack: short c_ip_mreqn: %d", len(data))
}
req := (*c_ip_mreqn)(unsafe.Pointer(&data[0]))
*v = *req
return nil
}
func (v *c_netc_get_if_info) Encode(msg *zxsocket.Msg) {
r := (*c_netc_get_if_info)(unsafe.Pointer(&msg.Data[0]))
*r = *v
msg.Datalen = uint32(unsafe.Sizeof(*v))
}
func (v *c_netc_if_info) Encode(msg *zxsocket.Msg) {
r := (*c_netc_if_info)(unsafe.Pointer(&msg.Data[0]))
*r = *v
msg.Datalen = uint32(unsafe.Sizeof(*v))
}
// TODO: make these methods on c_sockaddr_storage
func writeSockaddrStorage4(dst *c_sockaddr_storage, src *c_sockaddr_in) c_socklen {
srcb := (*[unsafe.Sizeof(*src)]byte)(unsafe.Pointer(src))[:]
dstb := (*[unsafe.Sizeof(*dst)]byte)(unsafe.Pointer(dst))[:]
return c_socklen(copy(dstb, srcb))
}
func writeSockaddrStorage6(dst *c_sockaddr_storage, src *c_sockaddr_in6) c_socklen {
srcb := (*[unsafe.Sizeof(*src)]byte)(unsafe.Pointer(src))[:]
dstb := (*[unsafe.Sizeof(*dst)]byte)(unsafe.Pointer(dst))[:]
return c_socklen(copy(dstb, srcb))
}
func writeSockaddrStorage(dst *c_sockaddr_storage, a tcpip.FullAddress) (c_socklen, error) {
switch len(a.Addr) {
case 0, 4:
sockaddr := c_sockaddr_in{sin_family: AF_INET}
sockaddr.sin_port.setPort(a.Port)
copy(sockaddr.sin_addr[:], a.Addr)
return writeSockaddrStorage4(dst, &sockaddr), nil
case 16:
sockaddr := c_sockaddr_in6{sin6_family: AF_INET6}
sockaddr.sin6_port.setPort(a.Port)
copy(sockaddr.sin6_addr[:], a.Addr)
return writeSockaddrStorage6(dst, &sockaddr), nil
}
return 0, mxerror.Errorf(zx.ErrInvalidArgs, "write sockaddr: bad address len %d", len(a.Addr))
}
func (v c_in_port) port() uint16 {
return uint16(v[0])<<8 | uint16(v[1])
}
func (v *c_in_port) setPort(port uint16) {
v[0] = uint8(port >> 8)
v[1] = uint8(port)
}
func readSockaddrIn(data []byte) (*tcpip.FullAddress, error) {
// TODO: recast in terms of c_sockaddr_storage
// TODO: split out the not-unsafe parts into socket_conv.go.
family := uint16(data[0]) | uint16(data[1])<<8
if debug2 {
log.Printf("readSockaddrIn: family=%d", family)
}
switch family {
case AF_INET:
if len(data) < int(unsafe.Sizeof(c_sockaddr_in{})) {
return nil, mxerror.Errorf(zx.ErrInvalidArgs, "reading c_sockaddr_in: len(data)=%d too small", len(data))
}
v := (*c_sockaddr_in)(unsafe.Pointer(&data[0]))
addr := &tcpip.FullAddress{
Port: uint16(data[3]) | uint16(data[2])<<8,
}
// INADDR_ANY is represented as tcpip.Address("").
if !isZeros(v.sin_addr[:]) {
addr.Addr = tcpip.Address(v.sin_addr[:])
}
if debug2 {
log.Printf("readSockaddrIn: addr=%v", addr)
}
return addr, nil
case AF_INET6:
if len(data) < int(unsafe.Sizeof(c_sockaddr_in6{})) {
return nil, mxerror.Errorf(zx.ErrInvalidArgs, "reading c_sockaddr_in6: len(data)=%d too small", len(data))
}
v := (*c_sockaddr_in6)(unsafe.Pointer(&data[0]))
addr := &tcpip.FullAddress{
Port: uint16(data[3]) | uint16(data[2])<<8,
}
if !isZeros(v.sin6_addr[:]) {
addr.Addr = tcpip.Address(v.sin6_addr[:])
}
if debug2 {
log.Printf("readSockaddrIn: addr=%v", addr)
}
return addr, nil
default:
return nil, mxerror.Errorf(zx.ErrInvalidArgs, "reading c_sockaddr: unknown family: %d", family)
}
}
func readSocketMsgHdr(data []byte) (*tcpip.FullAddress, error) {
if len(data) < c_fdio_socket_msg_hdr_len {
return nil, mxerror.Errorf(zx.ErrInvalidArgs, "reading socket msg header: too short: %d", len(data))
}
hdr := (*c_fdio_socket_msg_hdr)(unsafe.Pointer(&data[0]))
if hdr.addrlen == 0 {
return nil, nil
}
return readSockaddrIn(data) // first field of c_fdio_socket_msg_hdr is c_sockaddr_storage
}
func writeSocketMsgHdr(data []byte, addr tcpip.FullAddress) error {
if len(data) < c_fdio_socket_msg_hdr_len {
return mxerror.Errorf(zx.ErrInvalidArgs, "writing socket msg header: too short: %d", len(data))
}
hdr := (*c_fdio_socket_msg_hdr)(unsafe.Pointer(&data[0]))
l, err := writeSockaddrStorage(&hdr.addr, addr)
hdr.addrlen = l
hdr.flags = 0
return err
}