blob: 5425dd8509ecb9334931ecf454daa2de6a2a36e5 [file] [log] [blame]
// Copyright 2020 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.
//go:build !build_with_native_toolchain
// +build !build_with_native_toolchain
package testutil
import (
"sync/atomic"
"syscall/zx"
"testing"
"unsafe"
ethernetext "go.fuchsia.dev/fuchsia/src/connectivity/network/netstack/fidlext/fuchsia/hardware/ethernet"
"fidl/fuchsia/hardware/ethernet"
"gen/netstack/link/eth"
)
// makeEntryFifo creates a pair of handles to a FIFO of "depth" FifoEntry
// elements for use in tests. The created handles are automatically closed on
// test cleanup.
func makeEntryFifo(t *testing.T, depth uint) (zx.Handle, zx.Handle) {
t.Helper()
var device, client zx.Handle
if status := zx.Sys_fifo_create(depth, uint(unsafe.Sizeof(eth.FifoEntry{})), 0, &device, &client); status != zx.ErrOk {
t.Fatalf("failed to create fake FIFO: %s", status)
}
t.Cleanup(func() {
_ = device.Close()
_ = client.Close()
})
return device, client
}
// Returns an ethernetext.Device struct that implements
// ethernet.Device and can be started and stopped.
//
// Reports the passed in ethernet.Info when Device#GetInfo is called.
func MakeEthernetDevice(t *testing.T, info ethernet.Info, depth uint32) (ethernetext.Device, ethernet.Fifos) {
t.Helper()
clientRxFifo, deviceRxFifo := makeEntryFifo(t, uint(depth))
clientTxFifo, deviceTxFifo := makeEntryFifo(t, uint(depth))
var started uint32
return ethernetext.Device{
TB: t,
GetInfoImpl: func() (ethernet.Info, error) { return info, nil },
SetClientNameImpl: func(string) (int32, error) { return 0, nil },
GetStatusImpl: func() (ethernet.DeviceStatus, error) {
var status ethernet.DeviceStatus
if atomic.LoadUint32(&started) == 1 {
status |= ethernet.DeviceStatusOnline
}
// Emulate the driver by clearing the signal. Note that without doing this the client would
// hot-loop, continually observing the signal.
err := deviceRxFifo.SignalPeer(zx.Signals(ethernet.SignalStatus), 0)
return status, err
},
GetFifosImpl: func() (int32, *ethernet.Fifos, error) {
return int32(zx.ErrOk), &ethernet.Fifos{
Rx: clientRxFifo,
Tx: clientTxFifo,
RxDepth: depth,
TxDepth: depth,
}, nil
},
SetIoBufferImpl: func(h zx.VMO) (int32, error) {
return int32(zx.ErrOk), h.Close()
},
StartImpl: func() (int32, error) {
if atomic.CompareAndSwapUint32(&started, 0, 1) {
switch err := deviceRxFifo.SignalPeer(0, zx.Signals(ethernet.SignalStatus)).(type) {
case *zx.Error:
return int32(err.Status), nil
default:
return int32(zx.ErrOk), err
}
}
return int32(zx.ErrOk), nil
},
ConfigMulticastSetPromiscuousModeImpl: func(bool) (int32, error) {
return int32(zx.ErrOk), nil
},
StopImpl: func() error {
atomic.StoreUint32(&started, 0)
return nil
},
}, ethernet.Fifos{
Rx: deviceRxFifo,
Tx: deviceTxFifo,
}
}