Revert "Revert "Revert "Revert "Share radio settings across interfaces.""""
A new unit test from another SWE's parallel change did not contain the
necessary new argument to WlanConfiguration(). Fixed.
This reverts commit 263e9ebc38405da6f4a0f1e20db679234d0e1dd9.
Change-Id: Ie122f0ade1727c298dffe45815d97802282c62c7
diff --git a/dm/binwifi.py b/dm/binwifi.py
index 5d3d7d0..bbcbdf6 100644
--- a/dm/binwifi.py
+++ b/dm/binwifi.py
@@ -349,7 +349,7 @@
encryption_modes, init='AESEncryption')
SignalsStr = tr.cwmptypes.ReadOnlyString()
- def __init__(self, ifname, if_suffix, bridge, band=None, standard='n',
+ def __init__(self, ifname, if_suffix, bridge, radio, band=None, standard='n',
width_2_4g=0, width_5g=0, autochan=None):
super(WlanConfiguration, self).__init__()
self._initialized = False
@@ -358,6 +358,8 @@
type(self).Name.Set(self, self._ifname)
self._band = band if band else '5'
self._bridge = bridge
+ self._radio = radio
+ self._radio.InterfaceList.add(self)
self._fixed_band = band
if standard == 'ac':
type(self).SupportedStandards.Set(self, 'a,b,g,n,ac')
@@ -460,7 +462,7 @@
atype = self.X_CATAWAMPUS_ORG_AutoChanType
self.new_config.AutoChannelType = self._autochan or atype
self.new_config.AutoChannelEnable = self.AutoChannelEnable
- self.new_config.Channel = self.Channel
+ self.new_config.Channel = self._radio.Channel
self.new_config.SSID = self.SSID
@property
@@ -562,7 +564,7 @@
ivalue = int(value)
if not self.ValidateChannel(ivalue):
raise ValueError('Invalid Channel: %d' % ivalue)
- self.new_config.Channel = ivalue
+ self._radio.Channel = ivalue
self.AutoChannelEnable = 'False'
self.Triggered()
@@ -869,7 +871,7 @@
else: # LEGACY
ch = 'auto'
else:
- ch = self.new_config.Channel
+ ch = self._radio.Channel
if ch:
cmd += ['-c', str(ch)]
ssid = self.new_config.SSID
diff --git a/dm/binwifi_test.py b/dm/binwifi_test.py
index e684862..a73c2a4 100644
--- a/dm/binwifi_test.py
+++ b/dm/binwifi_test.py
@@ -28,6 +28,7 @@
import google3
import binwifi
import netdev
+import platform.gfmedia.device as device
import tr.handle
import tr.session
from tr.wvtest import unittest
@@ -101,17 +102,17 @@
return bw
def testValidateExports(self):
- bw = self.WlanConfiguration('wifi0', '', 'br0')
+ bw = self.WlanConfiguration('wifi0', '', 'br0', device.Radio())
tr.handle.ValidateExports(bw)
def testCorrectParentModel(self):
# We want the catawampus extension, not the base tr-98 model.
- bw = self.WlanConfiguration('wifi0', '', 'br0')
+ bw = self.WlanConfiguration('wifi0', '', 'br0', device.Radio())
self.assertTrue(tr.handle.Handle.IsValidExport(
bw, 'OperatingFrequencyBand'))
def testWEPKeyIndex(self):
- bw = self.WlanConfiguration('wifi0', '', 'br0')
+ bw = self.WlanConfiguration('wifi0', '', 'br0', device.Radio())
bw.StartTransaction()
bw.WEPKeyIndex = 1 # should succeed
bw.WEPKeyIndex = 2
@@ -121,7 +122,7 @@
self.assertRaises(ValueError, setattr, bw, 'WEPKeyIndex', 5)
def testWifiStats(self):
- bw = self.WlanConfiguration('wifi0', '', 'br0')
+ bw = self.WlanConfiguration('wifi0', '', 'br0', device.Radio())
self.assertEqual(bw.TotalBytesReceived, 1)
self.assertEqual(bw.TotalBytesSent, 9)
self.assertEqual(bw.TotalPacketsReceived, 100)
@@ -131,7 +132,8 @@
def testConfigCommit(self):
for (if_suffix, s_param) in SUFFIX_PARAMS:
for (bridge, b_param) in BRIDGE_PARAMS:
- bw = self.WlanConfiguration('wifi0', if_suffix, bridge, band='2.4')
+ bw = self.WlanConfiguration('wifi0', if_suffix, bridge, device.Radio(),
+ band='2.4')
bw.StartTransaction()
bw.RadioEnabled = True
bw.Enable = True
@@ -155,7 +157,8 @@
def testAnotherConfigCommit(self):
for (if_suffix, s_param) in SUFFIX_PARAMS:
for (bridge, b_param) in BRIDGE_PARAMS:
- bw = self.WlanConfiguration('wlan2', if_suffix, bridge, band='2.4')
+ bw = self.WlanConfiguration('wlan2', if_suffix, bridge, device.Radio(),
+ band='2.4')
bw.StartTransaction()
bw.RadioEnabled = True
bw.Enable = True
@@ -181,7 +184,7 @@
for (if_suffix, s_param) in SUFFIX_PARAMS:
for (bridge, b_param) in BRIDGE_PARAMS:
bw = self.WlanConfiguration(
- 'wifi0', if_suffix, bridge, band='5', width_5g=80)
+ 'wifi0', if_suffix, bridge, device.Radio(), band='5', width_5g=80)
bw.StartTransaction()
bw.RadioEnabled = True
bw.Enable = True
@@ -205,7 +208,8 @@
def testRadioDisabled(self):
for if_suffix, s_param in SUFFIX_PARAMS:
- bw = self.WlanConfiguration('wifi0', if_suffix, 'br1', band='2.4')
+ bw = self.WlanConfiguration('wifi0', if_suffix, 'br1', device.Radio(),
+ band='2.4')
# The radio will only be disabled by command if it is first enabled.
bw.StartTransaction()
bw.Enable = True
@@ -225,12 +229,67 @@
self.assertFalse(ap)
self.assertEqual(buf.strip().splitlines(), [l for l in exp if l])
+ def testChannelShared(self):
+ radio = device.Radio()
+ bw = self.WlanConfiguration('wifi0', '', 'br0', radio, band='2.4')
+ bw_portal = self.WlanConfiguration('wifi0', '_portal', 'br0', radio,
+ band='2.4')
+
+ # Set up the captive portal with no specified channel.
+ bw_portal.StartTransaction()
+ bw_portal.RadioEnabled = True
+ bw_portal.Enable = True
+ bw_portal.AutoChannelEnable = False
+ bw_portal.SSID = 'Portal SSID 1'
+ bw_portal.BeaconType = 'WPA'
+ bw_portal.IEEE11iEncryptionModes = 'AESEncryption'
+ bw_portal.KeyPassphrase = 'testpassword'
+ ap, buf = self.GatherOutput(bw_portal)
+ exp = [
+ 'env', 'WIFI_PSK=testpassword', binwifi.BINWIFI[0],
+ 'set', '-P', '-b', '2.4', '-e', 'WPA_PSK_AES',
+ '--interface-suffix=_portal', '--bridge=br0',
+ '-s', 'Portal SSID 1', '-p', 'a/b/g/n', '-M',
+ ]
+ self.assertTrue(ap)
+ self.assertEqual(buf.strip().splitlines(), [l for l in exp if l])
+
+ # Now set up the WLAN with a specified channel. Make sure the specified
+ # channel is applied to the captive portal on the same radio as well.
+ bw.StartTransaction()
+ bw.RadioEnabled = True
+ bw.Enable = True
+ bw.AutoChannelEnable = False
+ bw.Channel = '44'
+ bw.SSID = 'Test SSID 1'
+ bw.BeaconType = 'WPA'
+ bw.IEEE11iEncryptionModes = 'AESEncryption'
+ bw.KeyPassphrase = 'testpassword'
+ ap, buf = self.GatherOutput(bw)
+ exp = [
+ 'env', 'WIFI_PSK=testpassword', binwifi.BINWIFI[0],
+ 'set', '-P', '-b', '2.4', '-e', 'WPA_PSK_AES', '', '--bridge=br0',
+ '-c', '44', '-s', 'Test SSID 1', '-p', 'a/b/g/n', '-M',
+ ]
+ self.assertTrue(ap)
+ self.assertEqual(buf.strip().splitlines(), [l for l in exp if l])
+
+ ap, buf = self.GatherOutput(bw_portal)
+ exp = [
+ 'env', 'WIFI_PSK=testpassword', binwifi.BINWIFI[0],
+ 'set', '-P', '-b', '2.4', '-e', 'WPA_PSK_AES',
+ '--interface-suffix=_portal', '--bridge=br0',
+ '-c', '44', '-s', 'Portal SSID 1', '-p', 'a/b/g/n', '-M',
+ ]
+ self.assertTrue(ap)
+ self.assertEqual(buf.strip().splitlines(), [l for l in exp if l])
+
def testPSK(self):
for i in range(1, 11):
for (if_suffix, s_param) in SUFFIX_PARAMS:
for (bridge, b_param) in BRIDGE_PARAMS:
bw = self.WlanConfiguration(
- 'wifi0', if_suffix, bridge, band='2.4')
+ 'wifi0', if_suffix, bridge, device.Radio(), band='2.4')
bw.StartTransaction()
bw.RadioEnabled = True
bw.Enable = True
@@ -250,7 +309,7 @@
self.assertEqual(buf.strip().splitlines(), [l for l in exp if l])
def testPasswordTriggers(self):
- bw = self.WlanConfiguration('wifi0', '', 'br0', band='2.4')
+ bw = self.WlanConfiguration('wifi0', '', 'br0', device.Radio(), band='2.4')
bw.StartTransaction()
bw.RadioEnabled = True
bw.Enable = True
@@ -273,7 +332,7 @@
for (if_suffix, s_param) in SUFFIX_PARAMS:
for (bridge, b_param) in BRIDGE_PARAMS:
bw = self.WlanConfiguration(
- 'wifi0', if_suffix, bridge, band='2.4')
+ 'wifi0', if_suffix, bridge, device.Radio(), band='2.4')
bw.StartTransaction()
bw.RadioEnabled = True
bw.Enable = True
@@ -291,7 +350,7 @@
self.assertEqual(buf.strip().splitlines(), [l for l in exp if l])
def testSSID(self):
- bw = self.WlanConfiguration('wifi0', '', 'br0', band='5')
+ bw = self.WlanConfiguration('wifi0', '', 'br0', device.Radio(), band='5')
bw.StartTransaction()
bw.SSID = 'this is ok'
self.loop.RunOnce(timeout=1)
@@ -303,7 +362,7 @@
# pylint: disable=protected-access
def testMakeBinWifiCommandSecurity(self):
- bw = self.WlanConfiguration('wifi0', '', 'br0', band='5')
+ bw = self.WlanConfiguration('wifi0', '', 'br0', device.Radio(), band='5')
bw.StartTransaction()
bw.SSID = 'this is ok'
bw.PreSharedKeyList['1'].KeyPassphrase = 'test password'
@@ -327,7 +386,7 @@
self.loop.RunOnce(timeout=1)
def testConmanFilenames(self):
- bw = self.WlanConfiguration('wifi0', '', 'br0', band='5')
+ bw = self.WlanConfiguration('wifi0', '', 'br0', device.Radio(), band='5')
self.assertEqual(bw.WifiCommandFileName(),
os.path.join(binwifi.CONMAN_DIR[0], 'command.5'))
self.assertEqual(bw.APEnabledFileName(),
@@ -339,7 +398,7 @@
def testAssociatedDevices(self):
binwifi.STATIONS_DIR[0] = 'testdata/binwifi/stations'
- bw = self.WlanConfiguration('wifi0', '', 'br0')
+ bw = self.WlanConfiguration('wifi0', '', 'br0', device.Radio())
self.assertEqual(bw.TotalAssociations, 3)
found = 0
for c in bw.AssociatedDeviceList.values():
@@ -370,7 +429,7 @@
self.assertEqual(found, 0x7)
def testVariousOperatingFrequencyBand(self):
- bw = self.WlanConfiguration('wifi0', '', 'br0')
+ bw = self.WlanConfiguration('wifi0', '', 'br0', device.Radio())
self.assertEqual(bw.OperatingFrequencyBand, '5GHz')
bw.OperatingFrequencyBand = '2.4GHz'
self.assertEqual(bw.OperatingFrequencyBand, '2.4GHz')
@@ -381,7 +440,7 @@
self.loop.RunOnce(timeout=1)
def testOperatingFrequencyBand(self):
- bw = self.WlanConfiguration('wifi0', '', 'br0')
+ bw = self.WlanConfiguration('wifi0', '', 'br0', device.Radio())
bw.StartTransaction()
bw.RadioEnabled = True
bw.Enable = True
@@ -398,7 +457,7 @@
self.assertTrue('-b 2.4' in ' '.join(buf.splitlines()))
def testBeaconType(self):
- bw = self.WlanConfiguration('wifi0', '', 'br0', band='5')
+ bw = self.WlanConfiguration('wifi0', '', 'br0', device.Radio(), band='5')
bw.StartTransaction()
bw.RadioEnabled = True
bw.Enable = True
@@ -420,7 +479,7 @@
def testStandard(self):
bw = self.WlanConfiguration(
- 'wifi0', '', 'br0', band='5', width_5g=80)
+ 'wifi0', '', 'br0', device.Radio(), band='5', width_5g=80)
bw.StartTransaction()
bw.RadioEnabled = True
bw.Enable = True
@@ -501,7 +560,7 @@
def testClientIsolation(self):
bw = self.WlanConfiguration(
- 'wifi0', '_portal', 'br1', band='5', width_5g=80)
+ 'wifi0', '_portal', 'br1', device.Radio(), band='5', width_5g=80)
bw.StartTransaction()
bw.RadioEnabled = True
bw.Enable = True
@@ -515,7 +574,7 @@
def testWidth(self):
bw = self.WlanConfiguration(
- 'wifi0', '', 'br0', band='5', width_5g=80)
+ 'wifi0', '', 'br0', device.Radio(), band='5', width_5g=80)
bw.StartTransaction()
bw.RadioEnabled = True
bw.Enable = True
@@ -525,7 +584,7 @@
self.assertTrue('-w 80' in ' '.join(buf.splitlines()))
bw = self.WlanConfiguration(
- 'wifi0', '', 'br0', band='5', width_2_4g=40)
+ 'wifi0', '', 'br0', device.Radio(), band='5', width_2_4g=40)
bw.StartTransaction()
bw.RadioEnabled = True
bw.Enable = True
@@ -535,7 +594,7 @@
self.assertFalse('-w 40' in ' '.join(buf.splitlines()))
bw = self.WlanConfiguration(
- 'wifi0', '', 'br0', band='2.4', width_2_4g=40)
+ 'wifi0', '', 'br0', device.Radio(), band='2.4', width_2_4g=40)
bw.StartTransaction()
bw.RadioEnabled = True
bw.Enable = True
@@ -545,7 +604,7 @@
self.assertTrue('-w 40' in ' '.join(buf.splitlines()))
bw = self.WlanConfiguration(
- 'wifi0', '', 'br0', band='2.4', width_5g=80)
+ 'wifi0', '', 'br0', device.Radio(), band='2.4', width_5g=80)
bw.StartTransaction()
bw.RadioEnabled = True
bw.Enable = True
@@ -555,7 +614,7 @@
self.assertFalse('-w 80' in ' '.join(buf.splitlines()))
def testAutoDisableRecommended(self):
- bw = self.WlanConfiguration('wifi0', '', 'br0', band='5')
+ bw = self.WlanConfiguration('wifi0', '', 'br0', device.Radio(), band='5')
self.assertFalse(bw.X_CATAWAMPUS_ORG_AutoDisableRecommended)
open(self.tmpdir + '/wifi0.disabled', 'w').write('')
self.assertTrue(bw.X_CATAWAMPUS_ORG_AutoDisableRecommended)
diff --git a/platform/gfmedia/device.py b/platform/gfmedia/device.py
index d818f59..bb77836 100755
--- a/platform/gfmedia/device.py
+++ b/platform/gfmedia/device.py
@@ -607,6 +607,20 @@
iflookup=iflookup, bridgename='br0', dmroot=tr.handle.Handle(dmroot))
+class Radio(object):
+ """Holds radio-level properties shared by interfaces on that radio."""
+
+ Channel = tr.cwmptypes.TriggerInt()
+
+ def __init__(self):
+ self.InterfaceList = set()
+
+ def Triggered(self):
+ print self.InterfaceList
+ for interface in self.InterfaceList:
+ interface.Triggered()
+
+
class LANDevice(tr.basemodel.InternetGatewayDevice.LANDevice):
"""tr-98 InternetGatewayDevice for Google Fiber media platforms."""
@@ -617,7 +631,7 @@
LANUSBInterfaceNumberOfEntries = tr.cwmptypes.NumberOf(
'LANUSBInterfaceConfigList')
- def __init__(self, if_suffix, bridge):
+ def __init__(self, if_suffix, bridge, radio_list):
super(LANDevice, self).__init__()
self.Unexport(['Alias'])
self.Unexport(objects=['Hosts', 'LANHostConfigManagement'])
@@ -631,9 +645,11 @@
if (_DoesInterfaceExist('wlan0' + if_suffix)
and _DoesInterfaceExist('wlan1' + if_suffix)):
# Two radios, instantiate both with fixed bands
- wifi = dm.binwifi.WlanConfiguration('wlan0', if_suffix, bridge, '2.4')
+ wifi = dm.binwifi.WlanConfiguration('wlan0', if_suffix, bridge,
+ radio_list['radio0'], '2.4')
self.WLANConfigurationList['1'] = wifi
- wifi = dm.binwifi.WlanConfiguration('wlan1', if_suffix, bridge, '5',
+ wifi = dm.binwifi.WlanConfiguration('wlan1', if_suffix, bridge,
+ radio_list['radio1'], '5',
standard='ac', width_5g=80,
autochan='HIGH')
self.WLANConfigurationList['2'] = wifi
@@ -646,7 +662,8 @@
kwargs['standard'] = 'ac'
kwargs['width_5g'] = 80
- wifi = dm.binwifi.WlanConfiguration('wlan0', if_suffix, bridge, **kwargs)
+ wifi = dm.binwifi.WlanConfiguration('wlan0', if_suffix, bridge,
+ radio_list['radio0'], **kwargs)
self.WLANConfigurationList['1'] = wifi
def _get_quantenna_interfaces(self):
@@ -681,8 +698,9 @@
'UPnP', 'USBHosts',
'UserInterface'],
lists=['WANDevice', 'SmartCardReader', 'User'])
- self.LANDeviceList = {'1': LANDevice('', 'br0'),
- '2': LANDevice('_portal', 'br1')}
+ self.RadioList = {'radio0': Radio(), 'radio1': Radio()}
+ self.LANDeviceList = {'1': LANDevice('', 'br0', self.RadioList),
+ '2': LANDevice('_portal', 'br1', self.RadioList)}
self.ManagementServer = tr.core.TODO() # higher level code splices this in
self.DeviceInfo = dm.device_info.DeviceInfo98Linux26(device_id)
diff --git a/platform/gfmedia/device_test.py b/platform/gfmedia/device_test.py
index f2a531f..727adcf 100755
--- a/platform/gfmedia/device_test.py
+++ b/platform/gfmedia/device_test.py
@@ -23,6 +23,7 @@
import google3
import device
+import dm.netdev
import tornado.ioloop
import tornado.testing
import tr.handle
@@ -60,6 +61,8 @@
self.old_VERSIONFILE = device.VERSIONFILE
device.ACTIVEWAN = 'testdata/device/activewan'
device.PYNETIFCONF = MockPynetInterface
+ self.old_PROC_NET_DEV = dm.netdev.PROC_NET_DEV
+ dm.netdev.PROC_NET_DEV = 'testdata/device/proc_net_dev'
self.install_cb_called = False
self.install_cb_faultcode = None
self.install_cb_faultstring = None
@@ -79,6 +82,7 @@
device.REBOOT = self.old_REBOOT
device.REPOMANIFEST = self.old_REPOMANIFEST
device.VERSIONFILE = self.old_VERSIONFILE
+ dm.netdev.PROC_NET_DEV = self.old_PROC_NET_DEV
def testGetSerialNumber(self):
device.HNVRAM = 'testdata/device/hnvram'
@@ -189,11 +193,16 @@
self.assertTrue(self.install_cb_faultstring)
def testValidateExports(self):
- tr.handle.ValidateExports(device.LANDevice('', 'br0'))
- tr.handle.ValidateExports(device.LANDevice('portal', ''))
- tr.handle.ValidateExports(device.Ethernet())
- # TODO(apenwarr): instantiate the entire schema here for proper testing.
- # It's a pain because many subsections may need fake data.
+ radio_list = {'radio0': device.Radio(), 'radio1': device.Radio()}
+ for interfaces in (['wlan0', 'wlan0_portal'],
+ ['wlan0', 'wlan0_portal', 'wlan1', 'wlan1_portal'],
+ []):
+ MockPynetInterface.INTERFACES = interfaces
+ tr.handle.ValidateExports(device.LANDevice('', 'br0', radio_list))
+ tr.handle.ValidateExports(device.LANDevice('portal', '', radio_list))
+ tr.handle.ValidateExports(device.Ethernet())
+ # TODO(apenwarr): instantiate the entire schema here for proper testing.
+ # It's a pain because many subsections may need fake data.
def testActiveWan(self):
device.ACTIVEWAN = 'testdata/device/activewan'
@@ -209,11 +218,16 @@
class MockPynetInterface(object):
+ INTERFACES = []
+
def __init__(self, ifname):
self.ifname = ifname
def get_index(self):
- raise IOError('No such interface in test')
+ try:
+ return self.INTERFACES.index(self.ifname)
+ except ValueError:
+ raise IOError('No such interface in test')
if __name__ == '__main__':
diff --git a/platform/gfmedia/testdata/device/proc_net_dev b/platform/gfmedia/testdata/device/proc_net_dev
new file mode 100644
index 0000000..5429901
--- /dev/null
+++ b/platform/gfmedia/testdata/device/proc_net_dev
@@ -0,0 +1,6 @@
+Inter-| Receive | Transmit
+ face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
+ wlan0: 1 100 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+ wlan0_portal: 1 100 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+ wlan1: 1 100 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+ wlan1_portal: 1 100 3 4 5 6 7 8 9 10 11 12 13 14 15 16