blob: 6031f32a3c95038c1dd25ae324145358271d6c1c [file] [log] [blame]
// Copyright 2021 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 wifi
import (
"context"
"fmt"
"strings"
"time"
"chromiumos/tast/common/network/ping"
"chromiumos/tast/common/wifi/security"
"chromiumos/tast/common/wifi/security/base"
"chromiumos/tast/common/wifi/security/wpa"
"chromiumos/tast/dut"
"chromiumos/tast/remote/wificell"
"chromiumos/tast/remote/wificell/dutcfg"
"chromiumos/tast/remote/wificell/router/ax"
"chromiumos/tast/remote/wificell/router/common/support"
"chromiumos/tast/testing"
"chromiumos/tast/testing/hwdep"
)
func init() {
testing.AddTest(&testing.Test{
Func: AxSimpleConnect,
Desc: "Verifies that DUT can connect to an AX host via AP in different WiFi configuration",
Contacts: []string{
"billyzhao@google.com",
"chromeos-wifi-champs@google.com", // WiFi oncall rotation; or http://b/new?component=893827
},
Attr: []string{"group:wificell", "wificell_func_ax", "wificell_unstable"},
ServiceDeps: []string{wificell.TFServiceName},
Vars: []string{"router", "pcap", "routertype"},
Params: []testing.Param{
{
// Verifies that DUT can connect to a broadcasted open 802.11ax on channels 100,104
Name: "80211ax",
Val: []axSimpleConnectTestcase{{
band: ax.Ghz5,
apOpts: []ax.Option{ax.Mode(ax.Mode80211ax), ax.SSID("googleTest0"), ax.Hidden(false), ax.ChanBandwidth(100, ax.Bw80)},
routerSecConfFac: ax.NewSecOpenConfigParamFac(),
secConfFac: base.NewConfigFactory(),
}, {
band: ax.Ghz5,
apOpts: []ax.Option{ax.Mode(ax.Mode80211ax), ax.SSID("googleTest1"), ax.Hidden(false), ax.ChanBandwidth(104, ax.Bw80)},
routerSecConfFac: ax.NewSecOpenConfigParamFac(),
secConfFac: base.NewConfigFactory(),
}},
}, {
// Verifies that DUT can connect to a hidden open 802.11ax network on channel 100, 104
Name: "80211axhidden",
Val: []axSimpleConnectTestcase{{
band: ax.Ghz5,
apOpts: []ax.Option{ax.Mode(ax.Mode80211ax), ax.SSID("googleTest0"), ax.Hidden(true), ax.ChanBandwidth(100, ax.Bw80)},
routerSecConfFac: ax.NewSecOpenConfigParamFac(),
secConfFac: base.NewConfigFactory(),
}, {
band: ax.Ghz5,
apOpts: []ax.Option{ax.Mode(ax.Mode80211ax), ax.SSID("googleTest1"), ax.Hidden(true), ax.ChanBandwidth(104, ax.Bw80)},
routerSecConfFac: ax.NewSecOpenConfigParamFac(),
secConfFac: base.NewConfigFactory(),
}},
},
{
// Verifies that DUT can connect to a broadcasted wpa (AES) 802.11ax network on channel 100, 104
Name: "80211axwpaaes",
Val: []axSimpleConnectTestcase{{
band: ax.Ghz5,
apOpts: []ax.Option{ax.Mode(ax.Mode80211ax), ax.SSID("googleTest0"), ax.Hidden(false), ax.ChanBandwidth(100, ax.Bw80)},
routerSecConfFac: ax.NewSecWPAConfigParamFac("helloworld", ax.AES),
secConfFac: wpa.NewConfigFactory("helloworld", wpa.Mode(wpa.ModePureWPA), wpa.Ciphers(wpa.CipherCCMP)),
}, {
band: ax.Ghz5,
apOpts: []ax.Option{ax.Mode(ax.Mode80211ax), ax.SSID("googleTest1"), ax.Hidden(false), ax.ChanBandwidth(104, ax.Bw80)},
routerSecConfFac: ax.NewSecWPAConfigParamFac("helloworld", ax.AES),
secConfFac: wpa.NewConfigFactory("helloworld", wpa.Mode(wpa.ModePureWPA), wpa.Ciphers(wpa.CipherCCMP)),
}},
},
{
// Verifies that DUT can connect to a hidden wpa (AES) 802.11ax network on channel 100, 104
Name: "80211axwpaaeshidden",
Val: []axSimpleConnectTestcase{{
band: ax.Ghz5,
apOpts: []ax.Option{ax.Mode(ax.Mode80211ax), ax.SSID("googleTest0"), ax.Hidden(true), ax.ChanBandwidth(100, ax.Bw40)},
routerSecConfFac: ax.NewSecWPAConfigParamFac("helloworld", ax.AES),
secConfFac: wpa.NewConfigFactory("helloworld", wpa.Mode(wpa.ModePureWPA), wpa.Ciphers(wpa.CipherCCMP)),
}, {
band: ax.Ghz5,
apOpts: []ax.Option{ax.Mode(ax.Mode80211ax), ax.SSID("googleTest1"), ax.Hidden(true), ax.ChanBandwidth(104, ax.Bw40)},
routerSecConfFac: ax.NewSecWPAConfigParamFac("helloworld", ax.AES),
secConfFac: wpa.NewConfigFactory("helloworld", wpa.Mode(wpa.ModePureWPA), wpa.Ciphers(wpa.CipherCCMP)),
}},
},
{
// Verifies that DUT can connect to a broadcasted open 802.11ax on channels 100 with 40Mhz channel width on the 5ghz band
Name: "80211ax40mhz5ghz",
Val: []axSimpleConnectTestcase{{
band: ax.Ghz5,
apOpts: []ax.Option{ax.Mode(ax.Mode80211ax), ax.SSID("googleTest0"), ax.Hidden(false), ax.ChanBandwidth(100, ax.Bw40)},
routerSecConfFac: ax.NewSecOpenConfigParamFac(),
secConfFac: base.NewConfigFactory(),
}},
},
{
// Verifies that DUT can connect to a broadcasted open 802.11ax on channels 100 with 80Mhz channel width on the 5ghz band
Name: "80211ax80mhz5ghz",
Val: []axSimpleConnectTestcase{{
band: ax.Ghz5,
apOpts: []ax.Option{ax.Mode(ax.Mode80211ax), ax.SSID("googleTest0"), ax.Hidden(false), ax.ChanBandwidth(100, ax.Bw80)},
routerSecConfFac: ax.NewSecOpenConfigParamFac(),
secConfFac: base.NewConfigFactory(),
}},
},
{
// Verifies that DUT can connect to a broadcasted open 802.11ax on channels 100 with 160Mhz channel width on the 5ghz band
Name: "80211ax160mhz5ghz",
Val: []axSimpleConnectTestcase{{
band: ax.Ghz5,
apOpts: []ax.Option{ax.Mode(ax.Mode80211ax), ax.SSID("googleTest0"), ax.Hidden(false), ax.ChanBandwidth(100, ax.Bw160)},
routerSecConfFac: ax.NewSecOpenConfigParamFac(),
secConfFac: base.NewConfigFactory(),
}},
},
{
// Verifies that DUT can connect to a broadcasted wpa (AES) 802.11ay network on channel 85, 41
Name: "80211axwpa6ghz",
Val: []axSimpleConnectTestcase{{
band: ax.Ghz6,
apOpts: []ax.Option{ax.Mode(ax.Mode80211ax), ax.SSID("googleTest0"), ax.Hidden(false), ax.ChanBandwidth(85, ax.Bw20)},
routerSecConfFac: ax.NewSecSAEConfigParamFac("helloworld", ax.AES),
secConfFac: wpa.NewConfigFactory("helloworld", wpa.Mode(wpa.ModePureWPA), wpa.Ciphers(wpa.CipherCCMP)),
}, {
band: ax.Ghz6,
apOpts: []ax.Option{ax.Mode(ax.Mode80211ax), ax.SSID("googleTest1"), ax.Hidden(false), ax.ChanBandwidth(41, ax.Bw20)},
routerSecConfFac: ax.NewSecSAEConfigParamFac("helloworld", ax.AES),
secConfFac: wpa.NewConfigFactory("helloworld", wpa.Mode(wpa.ModePureWPA), wpa.Ciphers(wpa.CipherCCMP)),
}},
ExtraHardwareDeps: hwdep.D(hwdep.Wifi80211ax6E()),
},
{
// Verifies that DUT can connect to a hidden wpa (AES) 802.11ay network on channel 85, 41
Name: "80211axwpahidden6ghz",
Val: []axSimpleConnectTestcase{{
band: ax.Ghz6,
apOpts: []ax.Option{ax.Mode(ax.Mode80211ax), ax.SSID("googleTest0"), ax.Hidden(true), ax.ChanBandwidth(85, ax.Bw20)},
routerSecConfFac: ax.NewSecSAEConfigParamFac("helloworld", ax.AES),
secConfFac: wpa.NewConfigFactory("helloworld", wpa.Mode(wpa.ModePureWPA), wpa.Ciphers(wpa.CipherCCMP)),
}, {
band: ax.Ghz6,
apOpts: []ax.Option{ax.Mode(ax.Mode80211ax), ax.SSID("googleTest1"), ax.Hidden(true), ax.ChanBandwidth(41, ax.Bw20)},
routerSecConfFac: ax.NewSecSAEConfigParamFac("helloworld", ax.AES),
secConfFac: wpa.NewConfigFactory("helloworld", wpa.Mode(wpa.ModePureWPA), wpa.Ciphers(wpa.CipherCCMP)),
}},
ExtraHardwareDeps: hwdep.D(hwdep.Wifi80211ax6E()),
},
{
// Verifies that DUT can connect to a broadcasted wpa (AES) 802.11ay with 40Mhz channel width on the 6ghz band
Name: "80211wpa40mhz6ghz",
Val: []axSimpleConnectTestcase{{
band: ax.Ghz6,
apOpts: []ax.Option{ax.Mode(ax.Mode80211ax), ax.SSID("googleTest0"), ax.Hidden(false), ax.ChanBandwidth(85, ax.Bw40)},
routerSecConfFac: ax.NewSecSAEConfigParamFac("helloworld", ax.AES),
secConfFac: wpa.NewConfigFactory("helloworld", wpa.Mode(wpa.ModePureWPA), wpa.Ciphers(wpa.CipherCCMP)),
}},
ExtraHardwareDeps: hwdep.D(hwdep.Wifi80211ax6E()),
},
{
// Verifies that DUT can connect to a broadcasted wpa (AES) 802.11ay with 80Mhz channel width on the 6ghz band
Name: "80211wpa80mhz6ghz",
Val: []axSimpleConnectTestcase{{
band: ax.Ghz6,
apOpts: []ax.Option{ax.Mode(ax.Mode80211ax), ax.SSID("googleTest0"), ax.Hidden(false), ax.ChanBandwidth(85, ax.Bw80)},
routerSecConfFac: ax.NewSecSAEConfigParamFac("helloworld", ax.AES),
secConfFac: wpa.NewConfigFactory("helloworld", wpa.Mode(wpa.ModePureWPA), wpa.Ciphers(wpa.CipherCCMP)),
}},
ExtraHardwareDeps: hwdep.D(hwdep.Wifi80211ax6E()),
},
{
// Verifies that DUT can connect to a broadcasted wpa (AES) 802.11ay with 40Mhz channel width on the 6ghz band
Name: "80211wpa160mhz6ghz",
Val: []axSimpleConnectTestcase{{
band: ax.Ghz6,
apOpts: []ax.Option{ax.Mode(ax.Mode80211ax), ax.SSID("googleTest0"), ax.Hidden(false), ax.ChanBandwidth(85, ax.Bw160)},
routerSecConfFac: ax.NewSecSAEConfigParamFac("helloworld", ax.AES),
secConfFac: wpa.NewConfigFactory("helloworld", wpa.Mode(wpa.ModePureWPA), wpa.Ciphers(wpa.CipherCCMP)),
}},
ExtraHardwareDeps: hwdep.D(hwdep.Wifi80211ax6E()),
},
},
})
}
type axSimpleConnectTestcase struct {
apOpts []ax.Option
band ax.BandEnum
routerSecConfFac ax.SecConfigParamFac
secConfFac security.ConfigFactory
pingOps []ping.Option
expectedFailure bool
}
func AxSimpleConnect(ctx context.Context, s *testing.State) {
var tfOps []wificell.TFOption
router, ok := s.Var("router")
if !ok || router == "" {
var err error
testing.ContextLogf(ctx, "Router name not specified, building default router hostname based on DUT hostname %q", s.DUT().HostName())
router, err = s.DUT().CompanionDeviceHostname(dut.CompanionSuffixRouter)
if err != nil {
s.Fatalf("Failed to synthesize default router name from DUT hostname %q: %v", s.DUT().HostName(), err)
}
testing.ContextLogf(ctx, "Using default router name %q for %s router", router, support.AxT.String())
}
tfOps = append(tfOps, wificell.TFRouter(router))
tfOps = append(tfOps, wificell.TFHostUsers(map[string]string{
router: "admin",
}))
// Parse the router's model.
var axType ax.DeviceType
routerTypeVar, ok := s.Var("routertype")
if !ok || len(routerTypeVar) == 0 || strings.EqualFold(routerTypeVar, support.AxT.String()) {
axType = ax.Unknown
} else {
var err error
axType, err = ax.DeviceTypeFromString(routerTypeVar)
if err != nil {
s.Fatalf("Invalid routertype %q: %v", routerTypeVar, err)
}
}
var tfRouterType support.RouterType
if axType != ax.Unknown {
tfRouterType = support.AxT
} else {
tfRouterType = support.UnknownT
}
tfOps = append(tfOps, wificell.TFRouterType(tfRouterType))
// Assert WiFi is up.
tf, err := wificell.NewTestFixture(ctx, ctx, s.DUT(), s.RPCHint(), tfOps...)
if err != nil {
s.Fatal("Failed to set up test fixture: ", err)
}
defer func(ctx context.Context) {
if err := tf.Close(ctx); err != nil {
s.Error("Failed to properly take down test fixture: ", err)
}
}(ctx)
ctx, cancel := tf.ReserveForClose(ctx)
defer cancel()
if tf.Router().RouterType() != support.AxT {
s.Fatal("Test fixture router is not an AX router")
}
rt, err := tf.AxRouter()
if err != nil {
s.Fatal("Failed to get ax router: ", err)
}
if axType == ax.Unknown {
axType, err = rt.ResolveAXDeviceType(ctx)
if err != nil {
s.Fatalf("Failed to resolve AX DeviceType from router, err: %v ", err)
}
}
testing.ContextLogf(ctx, "Resolved AX DeviceType to be %q", axType.String())
// Back up current router configuration.
backupString, err := rt.RetrieveConfiguration(ctx)
if err != nil {
s.Fatal("Could not retrieve current router configuration: ", err)
}
backupMap := make(map[string]ax.ConfigParam)
defer rt.UpdateConfig(ctx, backupMap)
ctx, cancel = tf.ReserveForClose(ctx)
defer cancel()
// subroutine to be run by each subtest.
testOnce := func(ctx context.Context, s *testing.State, band ax.BandEnum, options []ax.Option, rFac ax.SecConfigParamFac, secFac security.ConfigFactory, pingOps []ping.Option, expectedFailure bool) {
cfg := ax.Config{
Band: ax.BandToRadio(axType, band),
Type: axType,
NVRAMOut: &backupString,
RouterRecoveryMap: backupMap}
// Apply router options
for _, opt := range options {
opt(&cfg)
}
// Generate security config and update necessary router options
if rFac != nil {
cfgParamList, err := rFac.Gen(cfg.Type, band)
if err != nil {
s.Fatal("Could not generate security ConfigParam list: ", err)
}
cfg.RouterConfigParams = append(cfg.RouterConfigParams, cfgParamList...)
}
// Update DUT's connection options.
if secFac != nil {
secCfg, err := secFac.Gen()
if err != nil {
s.Fatal("Could not generate security factory: ", err)
}
cfg.DUTConnOptions = append(cfg.DUTConnOptions, dutcfg.ConnSecurity(secCfg))
}
// Update the router
if err = rt.ApplyRouterSettings(ctx, &cfg); err != nil {
s.Errorf("Could not apply the desired ax settings %s to the router: %v", cfg.RouterConfigParams, err)
}
// Get the router's IP to be used for ping test.
ip, err := rt.RouterIP(ctx)
if err != nil {
s.Error("Could not get the router's IP address: ", err)
}
s.Logf("The router's IP is %s", ip)
// Attempt to discovery and connect to AP.
if err := testing.Poll(ctx, func(ctx context.Context) error {
_, err = tf.ConnectWifi(ctx, cfg.SSID, cfg.DUTConnOptions...)
if err != nil {
if expectedFailure {
s.Log("Failed to connect to WiFi as expected")
// If we expect to fail, then this test is already done.
return nil
}
return err
}
return nil
}, &testing.PollOptions{Timeout: 120 * time.Second}); err != nil {
s.Fatal("Failed to connect to WiFi, err: ", err)
return
}
// Attempt to ping the router.
if err := testing.Poll(ctx, func(ctx context.Context) error {
if err := tf.PingFromDUT(ctx, ip); err != nil {
return err
}
return nil
}, &testing.PollOptions{Timeout: 60 * time.Second}); err != nil {
s.Error("Failed to ping from the DUT: ", err)
return
}
defer func(ctx context.Context) {
if err := tf.CleanDisconnectWifi(ctx); err != nil {
s.Error("Failed to disconnect WiFi, err: ", err)
}
}(ctx)
ctx, cancel = tf.ReserveForDisconnect(ctx)
defer cancel()
if expectedFailure {
s.Fatal("Expected to fail to connect to WiFi, but it was successful")
}
s.Log("Deconfiguring")
}
testcases := s.Param().([]axSimpleConnectTestcase)
// Default AP options run on every test,
defaultOpts := []ax.Option{ax.Radio(true)}
for i, tc := range testcases {
subtest := func(ctx context.Context, s *testing.State) {
testOnce(ctx, s, tc.band, append(tc.apOpts, defaultOpts...), tc.routerSecConfFac, tc.secConfFac, tc.pingOps, tc.expectedFailure)
}
if !s.Run(ctx, fmt.Sprintf("Testcase #%d", i), subtest) {
// Stop if any sub-test failed.
return
}
}
s.Log("Tearing down")
}