// Copyright 2021 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

package netstack

import (
	"context"
	"errors"
	"fmt"
	"syscall/zx"
	"syscall/zx/fidl"
	"time"

	"go.fuchsia.dev/fuchsia/src/connectivity/network/netstack/fidlconv"
	"go.fuchsia.dev/fuchsia/src/connectivity/network/netstack/link/netdevice"
	"go.fuchsia.dev/fuchsia/src/connectivity/network/netstack/routetypes"
	"go.fuchsia.dev/fuchsia/src/connectivity/network/netstack/sync"
	"go.fuchsia.dev/fuchsia/src/lib/component"
	syslog "go.fuchsia.dev/fuchsia/src/lib/syslog/go"

	"fidl/fuchsia/hardware/network"
	"fidl/fuchsia/net"
	"fidl/fuchsia/net/interfaces"
	"fidl/fuchsia/net/interfaces/admin"

	"gvisor.dev/gvisor/pkg/tcpip"
	"gvisor.dev/gvisor/pkg/tcpip/link/ethernet"
	"gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
	"gvisor.dev/gvisor/pkg/tcpip/network/ipv6"
	"gvisor.dev/gvisor/pkg/tcpip/stack"
)

const (
	addressStateProviderName = "fuchsia.net.interfaces.admin/AddressStateProvider"
	controlName              = "fuchsia.net.interfaces.admin/Control"
	deviceControlName        = "fuchsia.net.interfaces.admin/DeviceControl"
)

var _ stack.AddressDispatcher = (*addressDispatcher)(nil)

type addressDispatcher struct {
	watcherDisp watcherAddressDispatcher
	mu          struct {
		sync.Mutex
		aspImpl *adminAddressStateProviderImpl
	}
}

func (ad *addressDispatcher) OnChanged(lifetimes stack.AddressLifetimes, state stack.AddressAssignmentState) {
	ad.watcherDisp.OnChanged(lifetimes, state)

	ad.mu.Lock()
	if ad.mu.aspImpl != nil {
		ad.mu.aspImpl.OnChanged(lifetimes, state)
	}
	ad.mu.Unlock()
}

func (ad *addressDispatcher) OnRemoved(reason stack.AddressRemovalReason) {
	ad.mu.Lock()
	if ad.mu.aspImpl != nil {
		ad.mu.aspImpl.OnRemoved(reason)
	}
	ad.mu.Unlock()

	ad.watcherDisp.OnRemoved(reason)
}

var _ admin.AddressStateProviderWithCtx = (*adminAddressStateProviderImpl)(nil)
var _ stack.AddressDispatcher = (*adminAddressStateProviderImpl)(nil)

type adminAddressStateProviderImpl struct {
	ns           *Netstack
	nicid        tcpip.NICID
	cancelServe  context.CancelFunc
	ready        chan struct{}
	protocolAddr tcpip.ProtocolAddress
	mu           struct {
		sync.Mutex
		eventProxy admin.AddressStateProviderEventProxy
		isHanging  bool
		// NB: state is the zero value while the address has been added but the
		// initial assignment state is unknown.
		state interfaces.AddressAssignmentState
		// NB: lastObserved is the zero value iff the client has yet to observe the
		// state for the first time.
		lastObserved interfaces.AddressAssignmentState
		// detached is set to true if Detach has been called on the channel, and will
		// result in the address not being removed when the client closes its end of
		// the channel.
		detached bool
		// removedReason is set to the reason why the address was removed. When this
		// is set, the address does not need to be removed when this protocol
		// terminates.
		removedReason stack.AddressRemovalReason
		// Indicates if the OnAddressAdded event was sent.
		sentAddedEvent bool
	}
	// The RouteSetId used to associate this address to any subnet route added
	// as a result of the add_subnet_route AddressParameters field.
	subnetRouteSetId routetypes.RouteSetId
	// The add_subnet_route AddressParameters field from when this address was
	// added to the stack.
	addSubnetRoute bool
}

func (pi *adminAddressStateProviderImpl) UpdateAddressProperties(_ fidl.Context, properties admin.AddressProperties) error {
	lifetimes := propertiesToLifetimes(properties)
	switch err := pi.ns.stack.SetAddressLifetimes(
		pi.nicid,
		pi.protocolAddr.AddressWithPrefix.Address,
		lifetimes,
	); err.(type) {
	case nil:
	case *tcpip.ErrUnknownNICID, *tcpip.ErrBadLocalAddress:
		// TODO(https://fxbug.dev/42176338): Upgrade to panic once we're guaranteed that we get here iff the address still exists.
		_ = syslog.WarnTf(addressStateProviderName, "SetAddressLifetimes(%d, %s, %#v) failed: %s",
			pi.nicid, pi.protocolAddr.AddressWithPrefix.Address, lifetimes, err)
	default:
		panic(fmt.Sprintf("SetAddressLifetimes(%d, %s, %#v) failed with unexpected error: %s",
			pi.nicid, pi.protocolAddr.AddressWithPrefix.Address, lifetimes, err))
	}
	return nil
}

func (pi *adminAddressStateProviderImpl) Detach(fidl.Context) error {
	pi.mu.Lock()
	defer pi.mu.Unlock()

	pi.mu.detached = true
	return nil
}

func (pi *adminAddressStateProviderImpl) WatchAddressAssignmentState(ctx fidl.Context) (interfaces.AddressAssignmentState, error) {
	pi.mu.Lock()
	defer pi.mu.Unlock()

	if pi.mu.isHanging {
		pi.cancelServe()
		return 0, errors.New("not allowed to call WatchAddressAssignmentState when a call is already in progress")
	}

	for {
		if pi.mu.lastObserved != pi.mu.state {
			state := pi.mu.state
			pi.mu.lastObserved = state
			syslog.DebugTf(addressStateProviderName, "NIC=%d address %+v observed state: %s", pi.nicid, pi.protocolAddr, state)
			return state, nil
		}

		pi.mu.isHanging = true
		pi.mu.Unlock()

		var err error
		select {
		case <-pi.ready:
		case <-ctx.Done():
			err = fmt.Errorf("cancelled: %w", ctx.Err())
		}

		pi.mu.Lock()
		pi.mu.isHanging = false
		if err != nil {
			return 0, err
		}
	}
}

var _ admin.ControlWithCtx = (*adminControlImpl)(nil)

type adminControlImpl struct {
	ns          *Netstack
	nicid       tcpip.NICID
	cancelServe context.CancelFunc
	syncRemoval bool
	doneChannel chan zx.Channel
	// TODO(https://fxbug.dev/42169142): encode owned, strong, and weak refs once
	// cloning Control is allowed.
	isStrongRef bool
}

func (ci *adminControlImpl) getNICContext() *ifState {
	nicInfo, ok := ci.ns.stack.NICInfo()[ci.nicid]
	if !ok {
		// All serving control channels must be canceled before removing NICs from
		// the stack, this is a violation of that invariant.
		panic(fmt.Sprintf("NIC %d not found", ci.nicid))
	}
	return nicInfo.Context.(*ifState)
}

func (ci *adminControlImpl) Enable(fidl.Context) (admin.ControlEnableResult, error) {
	wasEnabled, err := ci.getNICContext().setState(true /* enabled */)
	if err != nil {
		// The only known error path that causes this failure is failure from the
		// device layers, which all mean we're possible racing with shutdown.
		_ = syslog.Errorf("ifs.Up() failed (NIC %d): %s", ci.nicid, err)
		return admin.ControlEnableResult{}, err
	}

	return admin.ControlEnableResultWithResponse(
		admin.ControlEnableResponse{
			DidEnable: !wasEnabled,
		}), nil
}

func (ci *adminControlImpl) Disable(fidl.Context) (admin.ControlDisableResult, error) {
	wasEnabled, err := ci.getNICContext().setState(false /* enabled */)
	if err != nil {
		// The only known error path that causes this failure is failure from the
		// device layers, which all mean we're possible racing with shutdown.
		_ = syslog.Errorf("ifs.Down() failed (NIC %d): %s", ci.nicid, err)
		return admin.ControlDisableResult{}, err
	}

	return admin.ControlDisableResultWithResponse(
		admin.ControlDisableResponse{
			DidDisable: wasEnabled,
		}), nil
}

func (ci *adminControlImpl) Detach(fidl.Context) error {
	// Make it a weak ref but don't decrease the reference count. If this was a
	// strong ref, the interface will leak.
	//
	// TODO(https://fxbug.dev/42169142): Detach should only be allowed on OWNED refs
	// once we allow cloning Control.
	ci.isStrongRef = false
	return nil
}

func (ci *adminControlImpl) isLoopback() bool {
	nicInfo, ok := ci.ns.stack.NICInfo()[ci.nicid]
	if !ok {
		panic(fmt.Sprintf("Remove on NIC %d not present", ci.nicid))
	}
	return nicInfo.Flags.Loopback
}

func (ci *adminControlImpl) Remove(fidl.Context) (admin.ControlRemoveResult, error) {
	if ci.isLoopback() {
		return admin.ControlRemoveResultWithErr(admin.ControlRemoveErrorNotAllowed), nil
	}

	ci.syncRemoval = true
	ci.cancelServe()

	return admin.ControlRemoveResultWithResponse(admin.ControlRemoveResponse{}), nil
}

func (ci *adminControlImpl) GetAuthorizationForInterface(fidl.Context) (admin.GrantForInterfaceAuthorization, error) {
	nicInfo := ci.getNICContext()

	token, err := nicInfo.authorizationToken.Duplicate(zx.RightTransfer | zx.RightDuplicate)
	if err != nil {
		return admin.GrantForInterfaceAuthorization{}, err
	}

	return admin.GrantForInterfaceAuthorization{InterfaceId: uint64(nicInfo.nicid), Token: token}, nil
}

func propertiesToLifetimes(properties admin.AddressProperties) stack.AddressLifetimes {
	lifetimes := stack.AddressLifetimes{
		ValidUntil: tcpip.MonotonicTimeInfinite(),
	}
	if properties.HasValidLifetimeEnd() {
		lifetimes.ValidUntil = fidlconv.ToTCPIPMonotonicTime(zx.Time(properties.GetValidLifetimeEnd()))
	}
	if properties.HasPreferredLifetimeInfo() {
		switch preferred := properties.GetPreferredLifetimeInfo(); preferred.Which() {
		case interfaces.PreferredLifetimeInfoDeprecated:
			lifetimes.Deprecated = true
		case interfaces.PreferredLifetimeInfoPreferredUntil:
			lifetimes.PreferredUntil = fidlconv.ToTCPIPMonotonicTime(zx.Time(preferred.PreferredUntil))
		default:
			panic(fmt.Sprintf("unknown preferred lifetime info tag: %+v", preferred))
		}
	} else {
		lifetimes.PreferredUntil = tcpip.MonotonicTimeInfinite()
	}
	return lifetimes
}

func (pi *adminAddressStateProviderImpl) OnChanged(lifetimes stack.AddressLifetimes, state stack.AddressAssignmentState) {
	_ = syslog.DebugTf(addressStateProviderName, "NIC=%d addr=%s changed lifetimes=%#v state=%s",
		pi.nicid, pi.protocolAddr.AddressWithPrefix, lifetimes, state)

	pi.mu.Lock()
	defer pi.mu.Unlock()

	pi.mu.state = fidlconv.ToAddressAssignmentState(state)
	if pi.mu.lastObserved != pi.mu.state {
		syslog.DebugTf(addressStateProviderName, "NIC=%d address %+v state changed from %s to %s", pi.nicid, pi.protocolAddr.AddressWithPrefix, pi.mu.lastObserved, pi.mu.state)
		select {
		case pi.ready <- struct{}{}:
		default:
		}
	}
}

func (pi *adminAddressStateProviderImpl) Remove(fidl.Context) error {
	_ = syslog.DebugTf(addressStateProviderName, "NICID=%d removing address %s from NIC %d due to explicit removal request", pi.nicid, pi.protocolAddr.AddressWithPrefix, pi.nicid)

	pi.mu.Lock()
	prevRemovedReason := pi.mu.removedReason
	// If not already set, removedReason will be set when the address is removed
	// below by the synchronous callback to pi.OnRemoved.
	pi.mu.Unlock()

	if prevRemovedReason != 0 {
		return nil
	}

	nicInfo, ok := pi.ns.stack.NICInfo()[pi.nicid]
	if !ok {
		panic(fmt.Sprintf("NIC %d not found when removing %s", pi.nicid, pi.protocolAddr.AddressWithPrefix))
	}
	ifs := nicInfo.Context.(*ifState)
	switch status := ifs.removeAddress(pi.protocolAddr); status {
	case zx.ErrOk:
	case zx.ErrNotFound:
		// Normally, we'd expect that it's impossible to get NotFound while holding
		// an AddressStateProvider, as the existence of the ASP itself should
		// indicate that the address is present.
		// However, we could be racing with fuchsia.net.interfaces.admin.Control/RemoveAddress
		// (see adminControlImpl.RemoveAddress in this file).
		_ = syslog.ErrorTf(addressStateProviderName, "tried to remove address %s that was not found on NIC %d", pi.protocolAddr.AddressWithPrefix, pi.nicid)
	case zx.ErrBadState:
		_ = syslog.WarnTf(addressStateProviderName, "NIC %d removed when trying to remove address %s due to explicit removal request: %s", pi.nicid, pi.protocolAddr.AddressWithPrefix, status)
	default:
		panic(fmt.Sprintf("NICID=%d unknown error trying to remove address %s upon explicit removal request: %s", pi.nicid, pi.protocolAddr.AddressWithPrefix, status))
	}
	return nil
}

func (pi *adminAddressStateProviderImpl) sendOnAddressRemovedEventAndCancelServeLocked() {
	if err := pi.mu.eventProxy.OnAddressRemoved(fidlconv.ToAddressRemovalReason(pi.mu.removedReason)); err != nil {
		var zxError *zx.Error
		if !errors.As(err, &zxError) || (zxError.Status != zx.ErrPeerClosed && zxError.Status != zx.ErrBadHandle) {
			_ = syslog.ErrorTf(addressStateProviderName, "NICID=%d failed to send OnAddressRemoved(%s) for %s: %s", pi.nicid, pi.mu.removedReason, pi.protocolAddr.AddressWithPrefix.Address, err)
		}
	}
	pi.cancelServe()
}

func (pi *adminAddressStateProviderImpl) OnRemoved(reason stack.AddressRemovalReason) {
	_ = syslog.DebugTf(addressStateProviderName, "NIC=%d addr=%s removed reason=%s", pi.nicid, pi.protocolAddr.AddressWithPrefix, reason)

	pi.mu.Lock()
	defer pi.mu.Unlock()

	pi.mu.removedReason = reason

	// If the OnAddressAdded event has not been sent yet, then that means the
	// address was removed while fuchsia.net.interfaces.admin/Control.AddAddress
	// operation is in-progress. This can happen when immediately after adding the
	// address to the core (gVisor) netstack but before the OnAddressAdded event
	// was sent (when no locks are held), DAD fails which triggers address
	// removal.
	if pi.mu.sentAddedEvent {
		pi.sendOnAddressRemovedEventAndCancelServeLocked()
	}
}

func (pi *adminAddressStateProviderImpl) cleanUpSubnetRoute() {
	if pi.addSubnetRoute {
		pi.ns.DelRouteSet(&pi.subnetRouteSetId)
	}
}

func (ci *adminControlImpl) AddAddress(_ fidl.Context, subnet net.Subnet, parameters admin.AddressParameters, request admin.AddressStateProviderWithCtxInterfaceRequest) error {
	protocolAddr := fidlconv.ToTCPIPProtocolAddress(subnet)
	addr := protocolAddr.AddressWithPrefix.Address

	ifs := ci.getNICContext()

	ctx, cancel := context.WithCancel(context.Background())
	impl := &adminAddressStateProviderImpl{
		ns:           ci.ns,
		nicid:        ci.nicid,
		ready:        make(chan struct{}, 1),
		cancelServe:  cancel,
		protocolAddr: protocolAddr,
	}
	impl.mu.Lock()
	impl.mu.eventProxy.Channel = request.Channel
	impl.mu.Unlock()

	addrDisp := &addressDispatcher{
		watcherDisp: watcherAddressDispatcher{
			nicid:        ifs.nicid,
			protocolAddr: protocolAddr,
			ch:           ifs.ns.interfaceEventChan,
		},
	}
	addrDisp.mu.Lock()
	addrDisp.mu.aspImpl = impl
	addrDisp.mu.Unlock()
	properties := stack.AddressProperties{
		Temporary: parameters.GetTemporaryWithDefault(false),
		Disp:      addrDisp,
	}
	if parameters.HasInitialProperties() {
		properties.Lifetimes = propertiesToLifetimes(parameters.GetInitialProperties())
	}

	var reason admin.AddressRemovalReason
	if protocolAddr.AddressWithPrefix.PrefixLen > protocolAddr.AddressWithPrefix.Address.BitLen() {
		reason = admin.AddressRemovalReasonInvalid
	} else if ok, status := ifs.addAddress(protocolAddr, properties); !ok {
		reason = status
	}
	if reason != 0 {
		defer cancel()
		impl.mu.Lock()
		defer impl.mu.Unlock()
		if err := impl.mu.eventProxy.OnAddressRemoved(reason); err != nil {
			var zxError *zx.Error
			if !errors.As(err, &zxError) || (zxError.Status != zx.ErrPeerClosed && zxError.Status != zx.ErrBadHandle) {
				_ = syslog.WarnTf(controlName, "NICID=%d failed to send OnAddressRemoved(%s) for %s: %s", impl.nicid, reason, protocolAddr.AddressWithPrefix.Address, err)
			}
		}
		if err := impl.mu.eventProxy.Close(); err != nil {
			_ = syslog.WarnTf(controlName, "NICID=%d failed to close %s channel", impl.nicid, addressStateProviderName)
		}
		return nil
	}

	addSubnetRoute := parameters.GetAddSubnetRouteWithDefault(false)
	impl.addSubnetRoute = addSubnetRoute
	if addSubnetRoute {
		// We treat every address as being associated with its own route set.
		// This allows us to close the address's route set when the address is
		// removed, guaranteeing we clean up the associated subnet route.
		impl.ns.AddRoute(
			addressWithPrefixRoute(ifs.nicid, protocolAddr.AddressWithPrefix),
			nil,   /* metric*/
			false, /* dynamic */
			false, /* replaceMatchingGvisorRoutes */
			&impl.subnetRouteSetId,
		)
	}

	impl.mu.Lock()
	defer impl.mu.Unlock()
	impl.mu.sentAddedEvent = true
	if err := impl.mu.eventProxy.OnAddressAdded(); err != nil {
		_ = syslog.ErrorTf(controlName, "NICID=%d failed to send OnAddressAdded() for %s - THIS MAY RESULT IN DROPPED ASP REQUESTS (https://fxbug.dev/42081560): %s", impl.nicid, protocolAddr.AddressWithPrefix.Address, err)
	}

	// If the address was removed before we sent the OnAddressAdded event, then
	// that means we need to send the (pending) OnAddressRemoved event. See
	// pi.OnRemoved for details.
	if impl.mu.removedReason != 0 {
		impl.sendOnAddressRemovedEventAndCancelServeLocked()
	}

	go func() {
		defer cancel()
		component.Serve(ctx, &admin.AddressStateProviderWithCtxStub{Impl: impl}, request.Channel, component.ServeOptions{
			Concurrent: true,
			OnError: func(err error) {
				_ = syslog.WarnTf(addressStateProviderName, "NICID=%d address state provider for %s: %s", impl.nicid, addr, err)
			},
		})

		impl.mu.Lock()
		detached, removedReason := impl.mu.detached, impl.mu.removedReason
		impl.mu.Unlock()

		addrDisp.mu.Lock()
		if detached {
			addrDisp.mu.aspImpl = nil
		}
		addrDisp.mu.Unlock()

		if !detached && removedReason == 0 {
			_ = syslog.DebugTf(addressStateProviderName, "NICID=%d removing address %s from NIC %d due to protocol closure", impl.nicid, addr, ci.nicid)
			switch status := ifs.removeAddress(impl.protocolAddr); status {
			case zx.ErrOk, zx.ErrNotFound:
			case zx.ErrBadState:
				_ = syslog.WarnTf(addressStateProviderName, "NIC %d removed when trying to remove address %s upon channel closure: %s", ci.nicid, addr, status)
			default:
				panic(fmt.Sprintf("NICID=%d unknown error trying to remove address %s upon channel closure: %s", impl.nicid, addr, status))
			}
		}

		if !detached {
			impl.cleanUpSubnetRoute()
		}
	}()
	return nil
}

func (ci *adminControlImpl) RemoveAddress(_ fidl.Context, address net.Subnet) (admin.ControlRemoveAddressResult, error) {
	protocolAddr := fidlconv.ToTCPIPProtocolAddress(address)
	nicInfo, ok := ci.ns.stack.NICInfo()[ci.nicid]
	if !ok {
		panic(fmt.Sprintf("NIC %d not found when removing %s", ci.nicid, protocolAddr.AddressWithPrefix))
	}
	ifs := nicInfo.Context.(*ifState)

	// If the address the caller requested to remove was assigned through DHCP,
	// just stop DHCP since that will result in the removal of the address.
	ifs.dhcpLock <- struct{}{}
	ifs.mu.Lock()
	defer func() {
		ifs.mu.Unlock()
		<-ifs.dhcpLock
	}()

	// DHCP client is only available for Ethernet interfaces.
	if ifs.mu.dhcp.Client != nil {
		if info := ifs.mu.dhcp.Client.Info(); info.Assigned.Address == protocolAddr.AddressWithPrefix.Address {
			ifs.setDHCPStatusLocked(nicInfo.Name, false)
			return admin.ControlRemoveAddressResultWithResponse(admin.ControlRemoveAddressResponse{DidRemove: true}), nil
		}
	}

	switch zxErr := ifs.removeAddress(protocolAddr); zxErr {
	case zx.ErrOk:
		return admin.ControlRemoveAddressResultWithResponse(admin.ControlRemoveAddressResponse{DidRemove: true}), nil
	case zx.ErrNotFound:
		return admin.ControlRemoveAddressResultWithResponse(admin.ControlRemoveAddressResponse{DidRemove: false}), nil
	default:
		panic(fmt.Sprintf("removeInterfaceAddress(%d, %v, false) = %s", ci.nicid, protocolAddr, zxErr))
	}
}

func (ci *adminControlImpl) GetId(fidl.Context) (uint64, error) {
	return uint64(ci.nicid), nil
}

// handleIPForwardingConfigurationResult handles the result of getting or
// setting IP forwarding or IP multicast forwarding configuration.
//
// Returns the result if the invoked function was successful. Otherwise, panics
// if an unexpected error occurred.
func handleIPForwardingConfigurationResult(result bool, err tcpip.Error, invokedFunction string) bool {
	switch err.(type) {
	case nil:
		return result
	case *tcpip.ErrUnknownNICID:
		// Impossible as this Control would be invalid if the interface is not
		// recognized.
		panic(fmt.Sprintf("got UnknownNICID error when Control is still valid from %s = %s", invokedFunction, err))
	default:
		panic(fmt.Sprintf("%s: %s", invokedFunction, err))
	}
}

// setIPForwardingLocked sets the IP forwarding configuration for the interface.
//
// The caller must hold the interface's write lock.
func (ci *adminControlImpl) setIPForwardingLocked(netProto tcpip.NetworkProtocolNumber, enabled bool) bool {
	prevEnabled, err := ci.ns.stack.SetNICForwarding(tcpip.NICID(ci.nicid), netProto, enabled)
	return handleIPForwardingConfigurationResult(prevEnabled, err, fmt.Sprintf("ci.ns.stack.SetNICForwarding(tcpip.NICID(%d), %d, %t)", ci.nicid, netProto, enabled))
}

// setMulticastIPForwardingLocked sets the IP multicast forwarding configuration
// for the interface.
//
// The caller must hold the interface's write lock.
func (ci *adminControlImpl) setMulticastIPForwardingLocked(netProto tcpip.NetworkProtocolNumber, enabled bool) bool {
	prevEnabled, err := ci.ns.stack.SetNICMulticastForwarding(tcpip.NICID(ci.nicid), netProto, enabled)
	return handleIPForwardingConfigurationResult(prevEnabled, err, fmt.Sprintf("ci.ns.stack.SetNICMulticastForwarding(tcpip.NICID(%d), %d, %t)", ci.nicid, netProto, enabled))
}

func (ci *adminControlImpl) getNetworkEndpoint(netProto tcpip.NetworkProtocolNumber) stack.NetworkEndpoint {
	ep, err := ci.ns.stack.GetNetworkEndpoint(tcpip.NICID(ci.nicid), netProto)
	if err != nil {
		panic(fmt.Sprintf("ci.ns.stack.GetNetworkEndpoint(tcpip.NICID(%d), %d): %s", ci.nicid, netProto, err))
	}

	return ep
}

func toAdminNudConfiguration(stackNud stack.NUDConfigurations) admin.NudConfiguration {
	var adminNud admin.NudConfiguration
	adminNud.SetMaxMulticastSolicitations(uint16(stackNud.MaxMulticastProbes))
	adminNud.SetMaxUnicastSolicitations(uint16(stackNud.MaxUnicastProbes))
	adminNud.SetBaseReachableTime(stackNud.BaseReachableTime.Nanoseconds())
	return adminNud
}

func (ci *adminControlImpl) getNUDConfig(netProto tcpip.NetworkProtocolNumber) stack.NUDConfigurations {
	config, err := ci.ns.stack.NUDConfigurations(tcpip.NICID(ci.nicid), netProto)
	if err != nil {
		panic(fmt.Sprintf("ci.ns.stack.NUDConfigurations(tcpip.NICID(%d), %d): %s", ci.nicid, netProto, err))
	}
	return config
}

func (ci *adminControlImpl) applyNUDConfig(netProto tcpip.NetworkProtocolNumber, nudConfig *admin.NudConfiguration) admin.NudConfiguration {
	var previousNudConfig admin.NudConfiguration

	// NB: We're reading and updating in place here without acquiring
	// locks, this is fine because we don't serve
	// fuchsia.net.interfaces.admin.Control concurrently.
	stackNudConfig := ci.getNUDConfig(netProto)
	needsNudUpdate := false
	if nudConfig.HasMaxMulticastSolicitations() {
		prev := stackNudConfig.MaxMulticastProbes
		stackNudConfig.MaxMulticastProbes = uint32(nudConfig.MaxMulticastSolicitations)
		previousNudConfig.SetMaxMulticastSolicitations(uint16(prev))
		needsNudUpdate = true
	}
	if nudConfig.HasMaxUnicastSolicitations() {
		prev := stackNudConfig.MaxUnicastProbes
		stackNudConfig.MaxUnicastProbes = uint32(nudConfig.MaxUnicastSolicitations)
		previousNudConfig.SetMaxUnicastSolicitations(uint16(prev))
		needsNudUpdate = true
	}
	if nudConfig.HasBaseReachableTime() {
		prev := stackNudConfig.BaseReachableTime
		stackNudConfig.BaseReachableTime = time.Duration(nudConfig.BaseReachableTime)
		previousNudConfig.SetBaseReachableTime(prev.Nanoseconds())
		needsNudUpdate = true
	}

	if needsNudUpdate {
		if err := ci.ns.stack.SetNUDConfigurations(tcpip.NICID(ci.nicid), netProto, stackNudConfig); err != nil {
			panic(fmt.Sprintf("ci.ns.stack.SetNUDConfigurations(tcpip.NICID(%d), %d, %v): %s", ci.nicid, netProto, stackNudConfig, err))
		}
	}
	return previousNudConfig
}

func (ci *adminControlImpl) getIGMPEndpoint() ipv4.IGMPEndpoint {
	// We want this to panic if EP does not implement ipv4.IGMPEndpoint.
	return ci.getNetworkEndpoint(ipv4.ProtocolNumber).(ipv4.IGMPEndpoint)
}

func (ci *adminControlImpl) getMLDEndpoint() ipv6.MLDEndpoint {
	// We want this to panic if EP does not implement ipv6.MLDEndpoint.
	return ci.getNetworkEndpoint(ipv6.ProtocolNumber).(ipv6.MLDEndpoint)
}

func toAdminIgmpVersion(v ipv4.IGMPVersion) admin.IgmpVersion {
	switch v {
	case ipv4.IGMPVersion1:
		return admin.IgmpVersionV1
	case ipv4.IGMPVersion2:
		return admin.IgmpVersionV2
	case ipv4.IGMPVersion3:
		return admin.IgmpVersionV3
	default:
		panic(fmt.Sprintf("unrecognized version = %d", v))
	}
}

func toAdminMldVersion(v ipv6.MLDVersion) admin.MldVersion {
	switch v {
	case ipv6.MLDVersion1:
		return admin.MldVersionV1
	case ipv6.MLDVersion2:
		return admin.MldVersionV2
	default:
		panic(fmt.Sprintf("unrecognized version = %d", v))
	}
}

func (ci *adminControlImpl) SetConfiguration(_ fidl.Context, config admin.Configuration) (admin.ControlSetConfigurationResult, error) {
	if config.HasIpv4() {
		// Loopback does not support forwarding.
		if ci.isLoopback() {
			if config.Ipv4.HasForwarding() && config.Ipv4.Forwarding {
				return admin.ControlSetConfigurationResultWithErr(admin.ControlSetConfigurationErrorIpv4ForwardingUnsupported), nil
			}

			if config.Ipv4.HasMulticastForwarding() && config.Ipv4.MulticastForwarding {
				return admin.ControlSetConfigurationResultWithErr(admin.ControlSetConfigurationErrorIpv4MulticastForwardingUnsupported), nil
			}

			if config.Ipv4.HasArp() {
				return admin.ControlSetConfigurationResultWithErr(admin.ControlSetConfigurationErrorArpNotSupported), nil
			}
		}

		// Make sure the IGMP version (if specified) is supported.
		if config.Ipv4.HasIgmp() && config.Ipv4.Igmp.HasVersion() {
			switch config.Ipv4.Igmp.Version {
			case admin.IgmpVersionV1, admin.IgmpVersionV2, admin.IgmpVersionV3:
			default:
				return admin.ControlSetConfigurationResultWithErr(admin.ControlSetConfigurationErrorIpv4IgmpVersionUnsupported), nil
			}
		}

		if config.Ipv4.HasArp() {
			if config.Ipv4.Arp.HasNud() {
				if config.Ipv4.Arp.Nud.HasMaxMulticastSolicitations() && config.Ipv4.Arp.Nud.MaxMulticastSolicitations == 0 {
					return admin.ControlSetConfigurationResultWithErr(admin.ControlSetConfigurationErrorIllegalZeroValue), nil
				}
				if config.Ipv4.Arp.Nud.HasMaxUnicastSolicitations() && config.Ipv4.Arp.Nud.MaxUnicastSolicitations == 0 {
					return admin.ControlSetConfigurationResultWithErr(admin.ControlSetConfigurationErrorIllegalZeroValue), nil
				}
				if config.Ipv4.Arp.Nud.HasBaseReachableTime() {
					if config.Ipv4.Arp.Nud.BaseReachableTime < 0 {
						return admin.ControlSetConfigurationResultWithErr(admin.ControlSetConfigurationErrorIllegalNegativeValue), nil
					} else if config.Ipv4.Arp.Nud.BaseReachableTime == 0 {
						return admin.ControlSetConfigurationResultWithErr(admin.ControlSetConfigurationErrorIllegalZeroValue), nil
					}

				}
			}
		}
	}

	if config.HasIpv6() {
		// Loopback does not support forwarding.
		if ci.isLoopback() {
			if config.Ipv6.HasForwarding() && config.Ipv6.Forwarding {
				return admin.ControlSetConfigurationResultWithErr(admin.ControlSetConfigurationErrorIpv6ForwardingUnsupported), nil
			}

			if config.Ipv6.HasMulticastForwarding() && config.Ipv6.MulticastForwarding {
				return admin.ControlSetConfigurationResultWithErr(admin.ControlSetConfigurationErrorIpv6MulticastForwardingUnsupported), nil
			}

			if config.Ipv6.HasNdp() {
				return admin.ControlSetConfigurationResultWithErr(admin.ControlSetConfigurationErrorNdpNotSupported), nil
			}
		}

		// Make sure the MLD version (if specified) is supported.
		if config.Ipv6.HasMld() && config.Ipv6.Mld.HasVersion() {
			switch config.Ipv6.Mld.Version {
			case admin.MldVersionV1, admin.MldVersionV2:
			default:
				return admin.ControlSetConfigurationResultWithErr(admin.ControlSetConfigurationErrorIpv6MldVersionUnsupported), nil
			}
		}

		if config.Ipv6.HasNdp() {
			if config.Ipv6.Ndp.HasNud() {
				if config.Ipv6.Ndp.Nud.HasMaxMulticastSolicitations() && config.Ipv6.Ndp.Nud.MaxMulticastSolicitations == 0 {
					return admin.ControlSetConfigurationResultWithErr(admin.ControlSetConfigurationErrorIllegalZeroValue), nil
				}
				if config.Ipv6.Ndp.Nud.HasMaxUnicastSolicitations() && config.Ipv6.Ndp.Nud.MaxUnicastSolicitations == 0 {
					return admin.ControlSetConfigurationResultWithErr(admin.ControlSetConfigurationErrorIllegalZeroValue), nil
				}
				if config.Ipv6.Ndp.Nud.HasBaseReachableTime() {
					if config.Ipv6.Ndp.Nud.BaseReachableTime < 0 {
						return admin.ControlSetConfigurationResultWithErr(admin.ControlSetConfigurationErrorIllegalNegativeValue), nil
					} else if config.Ipv6.Ndp.Nud.BaseReachableTime == 0 {
						return admin.ControlSetConfigurationResultWithErr(admin.ControlSetConfigurationErrorIllegalZeroValue), nil
					}

				}
			}
		}
	}

	ifs := ci.getNICContext()
	ifs.mu.Lock()
	defer ifs.mu.Unlock()

	var previousConfig admin.Configuration

	if config.HasIpv4() {
		var previousIpv4Config admin.Ipv4Configuration
		ipv4Config := config.Ipv4

		if ipv4Config.HasForwarding() {
			previousIpv4Config.SetForwarding(ci.setIPForwardingLocked(ipv4.ProtocolNumber, ipv4Config.Forwarding))
		}

		if ipv4Config.HasMulticastForwarding() {
			previousIpv4Config.SetMulticastForwarding(ci.setMulticastIPForwardingLocked(ipv4.ProtocolNumber, ipv4Config.MulticastForwarding))
		}

		if ipv4Config.HasIgmp() {
			var previousIgmpConfig admin.IgmpConfiguration
			igmpConfig := ipv4Config.Igmp

			if igmpConfig.HasVersion() {
				var newVersion ipv4.IGMPVersion
				switch igmpConfig.Version {
				case admin.IgmpVersionV1:
					newVersion = ipv4.IGMPVersion1
				case admin.IgmpVersionV2:
					newVersion = ipv4.IGMPVersion2
				case admin.IgmpVersionV3:
					newVersion = ipv4.IGMPVersion3
				default:
					// We validated IGMP version above.
					panic(fmt.Sprintf("unexpected IGMP version = %d", igmpConfig.Version))
				}

				previousIgmpConfig.SetVersion(toAdminIgmpVersion(ci.getIGMPEndpoint().SetIGMPVersion(newVersion)))
			}

			previousIpv4Config.SetIgmp(previousIgmpConfig)
		}

		if ipv4Config.HasArp() {
			var previousArpConfig admin.ArpConfiguration
			if ipv4Config.Arp.HasNud() {
				previousArpConfig.SetNud(ci.applyNUDConfig(ipv4.ProtocolNumber, &ipv4Config.Arp.Nud))
			}

			previousIpv4Config.SetArp(previousArpConfig)
		}

		previousConfig.SetIpv4(previousIpv4Config)
	}

	if config.HasIpv6() {
		var previousIpv6Config admin.Ipv6Configuration
		ipv6Config := config.Ipv6

		if ipv6Config.HasForwarding() {
			previousIpv6Config.SetForwarding(ci.setIPForwardingLocked(ipv6.ProtocolNumber, ipv6Config.Forwarding))
		}

		if ipv6Config.HasMulticastForwarding() {
			previousIpv6Config.SetMulticastForwarding(ci.setMulticastIPForwardingLocked(ipv6.ProtocolNumber, ipv6Config.MulticastForwarding))
		}

		if ipv6Config.HasMld() {
			var previousMldConfig admin.MldConfiguration
			mldConfig := ipv6Config.Mld

			if mldConfig.HasVersion() {
				var newVersion ipv6.MLDVersion
				switch mldConfig.Version {
				case admin.MldVersionV1:
					newVersion = ipv6.MLDVersion1
				case admin.MldVersionV2:
					newVersion = ipv6.MLDVersion2
				default:
					// We validated MLD version above.
					panic(fmt.Sprintf("unexpected MLD version = %d", mldConfig.Version))
				}

				previousMldConfig.SetVersion(toAdminMldVersion(ci.getMLDEndpoint().SetMLDVersion(newVersion)))
			}

			previousIpv6Config.SetMld(previousMldConfig)
		}

		if ipv6Config.HasNdp() {
			var previousNdpConfig admin.NdpConfiguration
			if ipv6Config.Ndp.HasNud() {
				previousNdpConfig.SetNud(ci.applyNUDConfig(ipv6.ProtocolNumber, &ipv6Config.Ndp.Nud))
			}

			if ipv6Config.Ndp.HasDad() {
				_ = syslog.WarnTf(controlName, "ignoring unsupported DAD configuration")
			}

			previousIpv6Config.SetNdp(previousNdpConfig)
		}

		previousConfig.SetIpv6(previousIpv6Config)
	}

	// Invalidate all clients' destination caches, as disabling forwarding may
	// cause an existing cached route to become invalid.
	ifs.ns.resetDestinationCache()

	return admin.ControlSetConfigurationResultWithResponse(admin.ControlSetConfigurationResponse{
		PreviousConfig: previousConfig,
	}), nil
}

// ipForwardingRLocked gets the IP forwarding configuration for the interface.
//
// The caller must hold the interface's read lock.
func (ci adminControlImpl) ipForwardingRLocked(netProto tcpip.NetworkProtocolNumber) bool {
	enabled, err := ci.ns.stack.NICForwarding(tcpip.NICID(ci.nicid), netProto)
	return handleIPForwardingConfigurationResult(enabled, err, fmt.Sprintf("ci.ns.stack.NICForwarding(tcpip.NICID(%d), %d)", ci.nicid, netProto))
}

// multicastIPForwardingRLocked gets the IP multicast forwarding configuration
// for the interface.
//
// The caller must hold the interface's read lock.
func (ci adminControlImpl) multicastIPForwardingRLocked(netProto tcpip.NetworkProtocolNumber) bool {
	enabled, err := ci.ns.stack.NICMulticastForwarding(tcpip.NICID(ci.nicid), netProto)
	return handleIPForwardingConfigurationResult(enabled, err, fmt.Sprintf("ci.ns.stack.NICMulticastForwarding(tcpip.NICID(%d), %d)", ci.nicid, netProto))
}

func (ci *adminControlImpl) GetConfiguration(fidl.Context) (admin.ControlGetConfigurationResult, error) {
	ifs := ci.getNICContext()
	ifs.mu.RLock()
	defer ifs.mu.RUnlock()

	var config admin.Configuration

	{
		var ipv4Config admin.Ipv4Configuration
		ipv4Config.SetForwarding(ci.ipForwardingRLocked(ipv4.ProtocolNumber))
		ipv4Config.SetMulticastForwarding(ci.multicastIPForwardingRLocked(ipv4.ProtocolNumber))

		var igmpConfig admin.IgmpConfiguration
		igmpConfig.SetVersion(toAdminIgmpVersion(ci.getIGMPEndpoint().GetIGMPVersion()))
		ipv4Config.SetIgmp(igmpConfig)
		if !ci.isLoopback() {
			var arpConfig admin.ArpConfiguration
			arpConfig.SetNud(toAdminNudConfiguration(ci.getNUDConfig(ipv4.ProtocolNumber)))
			ipv4Config.SetArp(arpConfig)
		}

		config.SetIpv4(ipv4Config)
	}

	{
		var ipv6Config admin.Ipv6Configuration
		ipv6Config.SetForwarding(ci.ipForwardingRLocked(ipv6.ProtocolNumber))
		ipv6Config.SetMulticastForwarding(ci.multicastIPForwardingRLocked(ipv6.ProtocolNumber))

		var mldConfig admin.MldConfiguration
		mldConfig.SetVersion(toAdminMldVersion(ci.getMLDEndpoint().GetMLDVersion()))
		ipv6Config.SetMld(mldConfig)
		if !ci.isLoopback() {
			var ndpConfig admin.NdpConfiguration
			ndpConfig.SetNud(toAdminNudConfiguration(ci.getNUDConfig(ipv6.ProtocolNumber)))
			ipv6Config.SetNdp(ndpConfig)
		}

		config.SetIpv6(ipv6Config)
	}

	return admin.ControlGetConfigurationResultWithResponse(admin.ControlGetConfigurationResponse{
		Config: config,
	}), nil
}

type adminControlCollection struct {
	mu struct {
		sync.Mutex
		tearingDown    bool
		controls       map[*adminControlImpl]struct{}
		strongRefCount uint
	}
}

func (c *adminControlCollection) stopServing() []zx.Channel {
	c.mu.Lock()
	controls := c.mu.controls
	c.mu.controls = nil
	c.mu.tearingDown = true
	c.mu.Unlock()

	for control := range controls {
		control.cancelServe()
	}

	var pendingTerminal []zx.Channel
	for control := range controls {
		pending := <-control.doneChannel
		if pending.Handle().IsValid() {
			pendingTerminal = append(pendingTerminal, pending)
		}
	}

	return pendingTerminal
}

func sendControlTerminationReason(pending []zx.Channel, reason admin.InterfaceRemovedReason) {
	for _, c := range pending {
		eventProxy := admin.ControlEventProxy{Channel: c}
		if err := eventProxy.OnInterfaceRemoved(reason); err != nil {
			_ = syslog.WarnTf(controlName, "failed to send interface close reason %s: %s", reason, err)
		}
		// Close the channel iff the event proxy hasn't done it already.
		if channel := eventProxy.Channel; channel.Handle().IsValid() {
			if err := channel.Close(); err != nil {
				_ = syslog.ErrorTf(controlName, "channel.Close() = %s", err)
			}
		}
	}
}

func (ifs *ifState) addAdminConnection(request admin.ControlWithCtxInterfaceRequest, strong bool) {

	impl, ctx, cancel := func() (*adminControlImpl, context.Context, context.CancelFunc) {
		ifs.adminControls.mu.Lock()
		defer ifs.adminControls.mu.Unlock()

		// Do not add more connections to an interface that is tearing down.
		if ifs.adminControls.mu.tearingDown {
			if err := request.Channel.Close(); err != nil {
				_ = syslog.ErrorTf(controlName, "request.channel.Close() = %s", err)
			}
			return nil, nil, nil
		}

		ctx, cancel := context.WithCancel(context.Background())
		impl := &adminControlImpl{
			ns:          ifs.ns,
			nicid:       ifs.nicid,
			cancelServe: cancel,
			// We need a buffer in this channel to accommodate for the Remove
			// call, which buffers the request channel here before removing the
			// interface.
			doneChannel: make(chan zx.Channel, 1),
			isStrongRef: strong,
		}

		ifs.adminControls.mu.controls[impl] = struct{}{}
		if impl.isStrongRef {
			ifs.adminControls.mu.strongRefCount++
		}

		return impl, ctx, cancel
	}()
	if impl == nil {
		return
	}

	go func() {
		defer cancel()
		defer close(impl.doneChannel)
		requestChannel := request.Channel

		component.Serve(ctx, &admin.ControlWithCtxStub{Impl: impl}, requestChannel, component.ServeOptions{
			Concurrent:       false,
			KeepChannelAlive: true,
			OnError: func(err error) {
				_ = syslog.WarnTf(controlName, "%s", err)
			},
		})

		// NB: anonymous function is used to restrict section where the lock is
		// held.
		ifStateToRemove := func() *ifState {
			ifs.adminControls.mu.Lock()
			defer ifs.adminControls.mu.Unlock()
			wasCanceled := errors.Is(ctx.Err(), context.Canceled)

			if keepInterface := func() bool {
				// Always proceed with removal if this was a synchronous remove
				// request.
				if impl.syncRemoval {
					return false
				}

				// Don't consider destroying if not a strong ref.
				//
				// Note that the implementation can change from a strong to a
				// weak ref if Detach is called, which is how we allow
				// interfaces to leak.
				//
				// This is also how we prevent destruction from interfaces
				// created with the legacy API, since they never have strong
				// refs.
				if !impl.isStrongRef {
					return true
				}

				ifs.adminControls.mu.strongRefCount--
				// If serving was canceled, that means that removal happened due
				// to outside cancelation already.
				if wasCanceled {
					return true
				}

				// Don't destroy if there are any strong refs left.
				if ifs.adminControls.mu.strongRefCount != 0 {
					return true
				}

				return false
			}(); keepInterface {
				if wasCanceled {
					// If we were canceled, pass the request channel along so
					// it'll receive the epitaph later.
					impl.doneChannel <- requestChannel
				} else {
					delete(ifs.adminControls.mu.controls, impl)
					if err := requestChannel.Close(); err != nil {
						_ = syslog.ErrorTf(controlName, "requestChannel.Close() = %s", err)
					}
				}
				return nil
			}

			// We're good to remove this interface.
			// Prevent new connections while we're holding the collection lock,
			// avoiding races between here and removing the interface below.
			ifs.adminControls.mu.tearingDown = true

			// Stash the requestChannel in our finalization channel so the
			// terminal event is sent later.
			impl.doneChannel <- requestChannel

			nicInfo, ok := impl.ns.stack.NICInfo()[impl.nicid]
			if !ok {
				panic(fmt.Sprintf("failed to find interface %d", impl.nicid))
			}
			// We can safely remove the interface now because we're certain that
			// this control impl is not in the collection anymore, so it can't
			// deadlock waiting for control interfaces to finish.
			return nicInfo.Context.(*ifState)
		}()

		if ifStateToRemove != nil {
			ifStateToRemove.RemoveByUser()
		}

	}()
}

var _ admin.InstallerWithCtx = (*interfacesAdminInstallerImpl)(nil)

type interfacesAdminInstallerImpl struct {
	ns *Netstack
}

func (i *interfacesAdminInstallerImpl) InstallDevice(_ fidl.Context, device network.DeviceWithCtxInterface, deviceControl admin.DeviceControlWithCtxInterfaceRequest) error {
	client, err := netdevice.NewClient(context.Background(), &device, &netdevice.SimpleSessionConfigFactory{})
	if err != nil {
		_ = syslog.WarnTf(controlName, "InstallDevice: %s", err)
		_ = deviceControl.Close()
		return nil
	}

	ctx, cancel := context.WithCancel(context.Background())
	impl := &interfacesAdminDeviceControlImpl{
		ns:           i.ns,
		deviceClient: client,
	}

	// Running the device client and serving the FIDL are tied to the same
	// context because their lifecycles are linked.
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		defer wg.Done()
		impl.deviceClient.Run(ctx)
		cancel()
	}()

	go func() {
		component.Serve(ctx, &admin.DeviceControlWithCtxStub{Impl: impl}, deviceControl.Channel, component.ServeOptions{
			OnError: func(err error) {
				_ = syslog.WarnTf(deviceControlName, "%s", err)
			},
		})
		if !impl.detached {
			cancel()
		}
		// Wait for device goroutine to finish before closing the device.
		wg.Wait()
		if err := impl.deviceClient.Close(); err != nil {
			_ = syslog.ErrorTf(deviceControlName, "deviceClient.Close() = %s", err)
		}
	}()

	return nil
}

var _ admin.DeviceControlWithCtx = (*interfacesAdminDeviceControlImpl)(nil)

type interfacesAdminDeviceControlImpl struct {
	ns           *Netstack
	deviceClient *netdevice.Client
	detached     bool
}

func (d *interfacesAdminDeviceControlImpl) CreateInterface(_ fidl.Context, portId network.PortId, control admin.ControlWithCtxInterfaceRequest, options admin.Options) error {

	ifs, closeReason := func() (*ifState, admin.InterfaceRemovedReason) {
		port, err := d.deviceClient.NewPort(context.Background(), portId)
		if err != nil {
			_ = syslog.WarnTf(deviceControlName, "NewPort(_, %d) failed: %s", portId, err)
			{
				var unsupported *netdevice.InvalidPortOperatingModeError
				if errors.As(err, &unsupported) {
					return nil, admin.InterfaceRemovedReasonBadPort
				}
			}
			{
				var alreadyBound *netdevice.PortAlreadyBoundError
				if errors.As(err, &alreadyBound) {
					return nil, admin.InterfaceRemovedReasonPortAlreadyBound
				}
			}

			// Assume all other errors are due to problems communicating with the
			// port.
			return nil, admin.InterfaceRemovedReasonPortClosed
		}
		defer func() {
			if port != nil {
				_ = port.Close()
			}
		}()

		var namePrefix string
		var linkEndpoint stack.LinkEndpoint
		switch mode := port.Mode(); mode {
		case netdevice.PortModeEthernet:
			namePrefix = "eth"
			linkEndpoint = ethernet.New(port)
		case netdevice.PortModeIp:
			namePrefix = "ip"
			linkEndpoint = port
		default:
			panic(fmt.Sprintf("unknown port mode %d", mode))
		}

		metric := defaultInterfaceMetric
		if options.HasMetric() {
			metric = routetypes.Metric(options.GetMetric())
		}
		ifs, err := d.ns.addEndpoint(
			makeEndpointName(namePrefix, options.GetNameWithDefault("")),
			linkEndpoint,
			port,
			port,
			metric,
			qdiscConfig{numQueues: numQDiscFIFOQueues, queueLen: int(port.TxDepth()) * qdiscTxDepthMultiplier},
		)
		if err != nil {
			_ = syslog.WarnTf(deviceControlName, "addEndpoint failed: %s", err)
			var tcpipError *TcpIpError
			if errors.As(err, &tcpipError) {
				switch tcpipError.Err.(type) {
				case *tcpip.ErrDuplicateNICID:
					return nil, admin.InterfaceRemovedReasonDuplicateName
				}
			}
			panic(fmt.Sprintf("unexpected error ns.AddEndpoint(..) = %s", err))
		}

		// Prevent deferred cleanup from running.
		port = nil

		return ifs, 0
	}()

	if closeReason != 0 {
		proxy := admin.ControlEventProxy{
			Channel: control.Channel,
		}
		if err := proxy.OnInterfaceRemoved(closeReason); err != nil {
			_ = syslog.WarnTf(deviceControlName, "failed to write terminal event %s: %s", closeReason, err)
		}
		_ = control.Close()
		return nil
	}

	ifs.addAdminConnection(control, true /* strong */)

	return nil
}

func (d *interfacesAdminDeviceControlImpl) Detach(fidl.Context) error {
	d.detached = true
	return nil
}
