blob: 4a48c266534b8daa274c96047811204f1ef66596 [file] [log] [blame]
// Copyright 2022 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package common
import (
"context"
"fmt"
"chromiumos/tast/common/network/iw"
"chromiumos/tast/errors"
"chromiumos/tast/remote/wificell/router/common/support"
"chromiumos/tast/testing"
)
// IfaceManager manages WiFi ifaces on a controller router and tracks their availability.
type IfaceManager struct {
r support.Router
iwr *iw.Runner
nextIfaceID int
// Available is a map from the interface name to iw.NetDev for available interfaces.
Available map[string]*iw.NetDev
// Busy is a map from the interface name to iw.NetDev for busy interfaces.
Busy map[string]*iw.NetDev
}
// NewRouterIfaceManager creates a new IfaceManager
func NewRouterIfaceManager(r support.Router, iwr *iw.Runner) *IfaceManager {
return &IfaceManager{
r: r,
iwr: iwr,
Available: make(map[string]*iw.NetDev),
Busy: make(map[string]*iw.NetDev),
}
}
// RemoveAll removes all WiFi interfaces.
func (im *IfaceManager) RemoveAll(ctx context.Context) error {
netDevs, err := im.iwr.ListInterfaces(ctx)
if err != nil {
return errors.Wrap(err, "failed to list interfaces")
}
for _, w := range netDevs {
if err := im.Remove(ctx, w.IfName); err != nil {
return err
}
}
return nil
}
// Remove removes the given iface with the iw command.
func (im *IfaceManager) Remove(ctx context.Context, iface string) error {
testing.ContextLogf(ctx, "Deleting wdev %s on %s", iface, im.r.RouterName())
if err := im.iwr.RemoveInterface(ctx, iface); err != nil {
return err
}
if _, ok := im.Available[iface]; ok {
delete(im.Available, iface)
}
if _, ok := im.Busy[iface]; ok {
delete(im.Busy, iface)
}
return nil
}
// uniqueIfaceName returns an unique name for interface with type t.
func (im *IfaceManager) uniqueIfaceName(t iw.IfType) string {
name := fmt.Sprintf("%s%d", string(t), im.nextIfaceID)
im.nextIfaceID++
return name
}
// Create creates an interface on phy of type t and returns the name of created interface.
func (im *IfaceManager) Create(ctx context.Context, phyName string, phyID int, t iw.IfType) (*iw.NetDev, error) {
ifaceName := im.uniqueIfaceName(t)
testing.ContextLogf(ctx, "Creating wdev %s on wiphy %s", ifaceName, phyName)
if err := im.iwr.AddInterface(ctx, phyName, ifaceName, t); err != nil {
return nil, err
}
nd := &iw.NetDev{
PhyNum: phyID,
IfName: ifaceName,
IfType: t,
}
im.Available[ifaceName] = nd
return nd, nil
}
// SetBusy marks iface as busy.
func (im *IfaceManager) SetBusy(iface string) {
nd, ok := im.Available[iface]
if !ok {
return
}
im.Busy[iface] = nd
delete(im.Available, iface)
}
// SetAvailable marks iface as available.
func (im *IfaceManager) SetAvailable(iface string) {
nd, ok := im.Busy[iface]
if !ok {
return
}
im.Available[iface] = nd
delete(im.Busy, iface)
}
// IsPhyBusyAny returns true if the phyID is occupied by a busy interface of any type.
func (im *IfaceManager) IsPhyBusyAny(phyID int) bool {
for _, nd := range im.Busy {
if nd.PhyNum == phyID {
return true
}
}
return false
}
// IsPhyBusy returns true if the phyID is occupied by a busy interface of type t.
func (im *IfaceManager) IsPhyBusy(phyID int, t iw.IfType) bool {
for _, nd := range im.Busy {
if nd.PhyNum == phyID && nd.IfType == t {
return true
}
}
return false
}