def test_steer_to_band(self): """Verify the parsing of the steer to band message.""" # Test 1: Valid steer to band messages (Version 1) test_cases = itertools.product( [BAND_TYPE.BAND_24G, BAND_TYPE.BAND_5G, BAND_TYPE.BAND_INVALID], [BAND_TYPE.BAND_24G, BAND_TYPE.BAND_5G]) for test_case in test_cases: # Steer to band with the given associated band (the first # element of test_case) and target band (the second element # of test_case). mac = '\x94\x45\x8d\x13\xb7\x86' msg = '\x00' + mac + chr(test_case[0].value) + chr( test_case[1].value) payload = steerexec.unpack_payload_from_bytes( common.Version.VERSION1, False, msg) self.assertEquals( steerexec.SteerToBand._make( (common.ether_ntoa(mac), test_case[0], test_case[1])), payload) # Same as above but in big-endian (which makes no difference) payload = steerexec.unpack_payload_from_bytes( common.Version.VERSION1, True, msg) self.assertEquals( steerexec.SteerToBand._make( (common.ether_ntoa(mac), test_case[0], test_case[1])), payload) # Test 2: Invalid target band (Version 1) mac = '\x49\xcd\x30\xda\x0c\x4c' msg = '\x00' + mac + '\x01\x02' self.assertRaises(MessageMalformedError, steerexec.unpack_payload_from_bytes, common.Version.VERSION1, False, msg)
def test_dual_band_update(self): """Verify the parsing of the dual band update message.""" # Test 1: Device becomes dual band mac = '\x91\x89\x0e\x16\xfb\x4e' msg = '\x03' + mac + '\x01' payload = stadb.unpack_payload_from_bytes( common.Version.VERSION1, False, msg) self.assertEquals(stadb.DualBandUpdate._make( (common.ether_ntoa(mac), True)), payload) # Same as above but in big-endian (which makes no difference) payload = stadb.unpack_payload_from_bytes( common.Version.VERSION1, True, msg) self.assertEquals(stadb.DualBandUpdate._make( (common.ether_ntoa(mac), True)), payload) # Test 2: Device is no longer considered dual band mac = '\x3b\x16\xf7\x1c\xbc\xd7' msg = '\x03' + mac + '\x00' payload = stadb.unpack_payload_from_bytes( common.Version.VERSION1, False, msg) self.assertEquals(stadb.DualBandUpdate._make( (common.ether_ntoa(mac), False)), payload) # Same as above but in big-endian (which makes no difference) payload = stadb.unpack_payload_from_bytes( common.Version.VERSION1, True, msg) self.assertEquals(stadb.DualBandUpdate._make( (common.ether_ntoa(mac), False)), payload)
def test_beacon_report(self): mac = '\x42\x62\x89\x67\x4d\xb4' # Test 1: Measurement on APID = 0xFF, channel = 100, essId = 0, # RCPI = -10 msg = '\x03' + mac + '\xFF\x64\x00\xF6' payload = wlanif.unpack_payload_from_bytes(common.Version.VERSION2, False, msg) self.assertEquals( wlanif.BeaconReport._make( (common.ether_ntoa(mac), common.BSSInfo(0xFF, 100, 0), -10)), payload) # Test 2: Similar but in big endian format (which makes no difference) msg = '\x03' + mac + '\xFF\x64\x00\xF6' payload = wlanif.unpack_payload_from_bytes(common.Version.VERSION2, True, msg) self.assertEquals( wlanif.BeaconReport._make( (common.ether_ntoa(mac), common.BSSInfo(0xFF, 100, 0), -10)), payload) # Test 3: Not supported in version 1 msg = '\x03' + mac + '\xFF\x64\x00\xF6' self.assertRaises(MessageMalformedError, wlanif.unpack_payload_from_bytes, common.Version.VERSION1, False, msg) self.assertRaises(MessageMalformedError, wlanif.unpack_payload_from_bytes, common.Version.VERSION1, True, msg)
def test_abort_steer_to_band(self): """Verify the parsing of the abort steer to band message.""" # Test 1: Valid steer to band messages for disabled_band in [BAND_TYPE.BAND_24G, BAND_TYPE.BAND_5G]: # Abort steer to band with the given disabled band. mac = '\x94\x45\x8d\x13\xb7\x86' msg = '\x01' + mac + chr(disabled_band.value) payload = steerexec.unpack_payload_from_bytes( common.Version.VERSION1, False, msg) self.assertEquals( steerexec.AbortSteerToBand._make( (common.ether_ntoa(mac), disabled_band)), payload) # Same as above but in big-endian (which makes no difference) payload = steerexec.unpack_payload_from_bytes( common.Version.VERSION1, True, msg) self.assertEquals( steerexec.AbortSteerToBand._make( (common.ether_ntoa(mac), disabled_band)), payload) # Test 2: Invalid disabled band mac = '\x49\xcd\x30\xda\x0c\x4c' msg = '\x01' + mac + '\x02' self.assertRaises(MessageMalformedError, steerexec.unpack_payload_from_bytes, common.Version.VERSION1, False, msg)
def test_interface(self): """Verify the parsing of the interface message v2.""" mac = '\xec\x40\xe4\xe7\xf5\xa5' # SSID length + string (null terminated) ssid = '\x09' + '\x74\x65\x73\x74\x73\x73\x69\x64\x00' # iface name length + string iface = '\x04' + '\x61\x74\x68\x30' # Fixed length portion: mac, channel, essid msg = '\x02' + mac + '\x06\x01' + ssid + iface # Test 1: Valid message payload = wlanif.unpack_payload_from_bytes(common.Version.VERSION2, False, msg) self.assertEquals( wlanif.Interface._make( (common.ether_ntoa(mac), 6, 1, 9, "testssid\x00", 4, "ath0")), payload) # Test 2: Same, but in big endian payload = wlanif.unpack_payload_from_bytes(common.Version.VERSION2, True, msg) self.assertEquals( wlanif.Interface._make( (common.ether_ntoa(mac), 6, 1, 9, "testssid\x00", 4, "ath0")), payload) # Test 3: Invalid SSID length ssid = '\xff' + '\x74\x65\x73\x74\x73\x73\x69\x64' msg = '\x02' + mac + '\x06\x01' + ssid + iface self.assertRaises(MessageMalformedError, wlanif.unpack_payload_from_bytes, common.Version.VERSION2, False, msg) self.assertRaises(MessageMalformedError, wlanif.unpack_payload_from_bytes, common.Version.VERSION2, True, msg) # Test 4: Invalid interface length ssid = '\x08' + '\x74\x65\x73\x74\x73\x73\x69\x64' iface = '\xff' + '\x61\x74\x68\x30\x00' msg = '\x02' + mac + '\x06\x01' + ssid + iface self.assertRaises(MessageMalformedError, wlanif.unpack_payload_from_bytes, common.Version.VERSION2, False, msg) self.assertRaises(MessageMalformedError, wlanif.unpack_payload_from_bytes, common.Version.VERSION2, True, msg) # Test 5: Not supported in version 1 iface = '\x05' + '\x61\x74\x68\x30\x00' msg = '\x02' + mac + '\x06\x01' + ssid + iface self.assertRaises(MessageMalformedError, wlanif.unpack_payload_from_bytes, common.Version.VERSION1, False, msg) self.assertRaises(MessageMalformedError, wlanif.unpack_payload_from_bytes, common.Version.VERSION1, True, msg)
def test_sta_pollution_changed_msg(self): """Verify the parsing of the STA pollution changed message.""" # Test 1: Pollution changed on a BSS on channel 149 test_cases = itertools.product([False, True], [ STAPollutionChangeReason.POLLUTION_CHANGE_DETECTION, STAPollutionChangeReason.POLLUTION_CHANGE_AGING, STAPollutionChangeReason.POLLUTION_CHANGE_REMOTE, STAPollutionChangeReason.POLLUTION_CHANGE_INVALID ]) for big_endian in (False, True): mac = '\x42\x62\x89\x67\x4d\xb4' for test_case in test_cases: msg = '\x03' + mac + '\xff\x95\x01' + \ chr(test_case[0]) + chr(test_case[1].value) payload = estimator.unpack_payload_from_bytes( common.Version.VERSION2, big_endian, msg) self.assertEquals( estimator.STAPollutionChanged._make( (common.ether_ntoa(mac), common.BSSInfo(255, 149, 1), test_case[0], test_case[1])), payload) # Test 2: Invalid pollution change reason for big_endian in (False, True): mac = '\x42\x62\x89\x67\x4d\xb4' for changed in (False, True): msg = '\x03' + mac + '\xff\x95\x01' + chr(changed) + \ chr(STAPollutionChangeReason.POLLUTION_CHANGE_INVALID.value + 1) self.assertRaises(MessageMalformedError, estimator.unpack_payload_from_bytes, common.Version.VERSION2, big_endian, msg)
def test_btm_compliance(self): """Verify the parsing of the BTM compliance message.""" # Test 1: Valid BTM compliance messages for compliance in BTMComplianceType: for is_unfriendly in [False, True]: # Changing to all the valid compliance states. mac = '\x6e\xee\xb2\x94\x33\x6f' countFailure = '\x0a\x00\x00\x00' countFailureActive = '\x01\x00\x00\x00' msg = '\x04' + mac + chr(is_unfriendly) + chr(compliance.value) + \ countFailure + countFailureActive payload = steerexec.unpack_payload_from_bytes( common.Version.VERSION2, False, msg) self.assertEquals( steerexec.BTMCompliance._make( (common.ether_ntoa(mac), is_unfriendly, compliance, 10, 1)), payload) # Same as above but in big-endian countFailure = '\x00\x00\x00\x0a' countFailureActive = '\x00\x00\x00\x01' msg = '\x04' + mac + chr(is_unfriendly) + chr(compliance.value) + \ countFailure + countFailureActive payload = steerexec.unpack_payload_from_bytes( common.Version.VERSION2, True, msg) self.assertEquals( steerexec.BTMCompliance._make( (common.ether_ntoa(mac), is_unfriendly, compliance, 10, 1)), payload) # Test 2: Invalid BTM compliance type mac = '\x6e\xee\xb2\x94\x33\x6f' countFailure = '\x0a\x00\x00\x00' countFailureActive = '\x01\x00\x00\x00' msg = '\x04' + mac + '\x01' + '\x04' + countFailure + countFailureActive self.assertRaises(MessageMalformedError, steerexec.unpack_payload_from_bytes, common.Version.VERSION2, False, msg) # Test 3: Not supported in version 1 mac = '\x6e\xee\xb2\x94\x33\x6f' msg = '\x04' + mac + '\x03' + '\x01' + countFailure + countFailureActive self.assertRaises(MessageMalformedError, steerexec.unpack_payload_from_bytes, common.Version.VERSION1, False, msg)
def test_ether_ntoa(self): """Test the function that formats an ethernet address as a string.""" self.assertRaises(ValueError, common.ether_ntoa, '\x11\x22\x33\x44\x55') # too short self.assertRaises(ValueError, common.ether_ntoa, '\x11\x22\x33\x44\x55\x66\x77') # too long self.assertEquals('ff:c1:c4:62:22:53', common.ether_ntoa('\xff\xc1\xc4\x62\x22\x53'))
def test_steering_prohibited(self): """Verify the parsing of the steering prohibited message.""" # Test 1: Valid steering prohibited messages Version 2 for prohibit_type in SteeringProhibitType: # Abort steer to band with the given disabled band. mac = '\x6e\xee\xb2\x94\x33\x6f' msg = '\x03' + mac + chr(prohibit_type.value) payload = steerexec.unpack_payload_from_bytes( common.Version.VERSION2, False, msg) self.assertEquals( steerexec.SteeringProhibited._make( (common.ether_ntoa(mac), prohibit_type)), payload) # Same as above but in big-endian (which makes no difference) payload = steerexec.unpack_payload_from_bytes( common.Version.VERSION2, True, msg) self.assertEquals( steerexec.SteeringProhibited._make( (common.ether_ntoa(mac), prohibit_type)), payload) # Test 2: Invalid steering prohibited type Version 2 mac = '\x6e\xee\xb2\x94\x33\x6f' msg = '\x03' + mac + '\x05' self.assertRaises(MessageMalformedError, steerexec.unpack_payload_from_bytes, common.Version.VERSION2, False, msg) # Test 3: Valid steering prohibited messages Version 1 for is_prohibited in [False, True]: # Abort steer to band with the given disabled band. mac = '\x6e\xee\xb2\x94\x33\x6f' msg = '\x03' + mac + chr(is_prohibited) payload = steerexec.unpack_payload_from_bytes( common.Version.VERSION1, False, msg) self.assertEquals( steerexec.SteeringProhibited._make( (common.ether_ntoa(mac), is_prohibited)), payload) # Same as above but in big-endian (which makes no difference) payload = steerexec.unpack_payload_from_bytes( common.Version.VERSION1, True, msg) self.assertEquals( steerexec.SteeringProhibited._make( (common.ether_ntoa(mac), is_prohibited)), payload)
def test_pre_assoc_steer(self): """Verify the parsing of the pre-association steer message.""" mac = '\x94\x45\x8d\x13\xb7\x86' transaction = '\x30' channel_count = '\x01' channel1 = '\x0a' channel2 = '\xfe' # Test 1: Single channel msg = '\x00' + mac + transaction + channel_count + channel1 payload = steerexec.unpack_payload_from_bytes(common.Version.VERSION2, False, msg) self.assertEquals( steerexec.PreAssocSteer._make( (common.ether_ntoa(mac), 0x30, 1, [0x0a])), payload) # Same as above but in big-endian (which makes no difference) payload = steerexec.unpack_payload_from_bytes(common.Version.VERSION2, True, msg) self.assertEquals( steerexec.PreAssocSteer._make( (common.ether_ntoa(mac), 0x30, 1, [0x0a])), payload) # Test 2: Two channels channel_count = '\x02' msg = '\x00' + mac + transaction + channel_count + channel1 + channel2 payload = steerexec.unpack_payload_from_bytes(common.Version.VERSION2, False, msg) self.assertEquals( steerexec.PreAssocSteer._make( (common.ether_ntoa(mac), 0x30, 2, [0x0a, 0xfe])), payload) # Test 3: Incorrect channel count raises an error msg = '\x00' + mac + transaction + 'x00' + channel1 + channel2 self.assertRaises(MessageMalformedError, steerexec.unpack_payload_from_bytes, common.Version.VERSION2, False, msg) msg = '\x00' + mac + transaction + 'x03' + channel1 + channel2 self.assertRaises(MessageMalformedError, steerexec.unpack_payload_from_bytes, common.Version.VERSION2, False, msg)
def test_interference_stats_msg(self): """Verify the parsing of the interference stats message""" # Test 1: Stats on a BSS on channel 36 mac = '\x42\x62\x89\x67\x4d\xb4' msg = '\x04' + mac + '\xff\x24\x00\x20\x01\x02' + \ '\x01\x02\x03\x04\x05\x06\x07\x08' + \ '\x0a\x0b\x0c\x0d' payload = estimator.unpack_payload_from_bytes(common.Version.VERSION2, False, msg) self.assertEquals( estimator.InterferenceStats._make( (common.ether_ntoa(mac), common.BSSInfo(255, 36, 0), 32, 513, 578437695752307201, 218893066)), payload) # Test 2: Similar but in big endian format (Tx rate changes) payload = estimator.unpack_payload_from_bytes(common.Version.VERSION2, True, msg) self.assertEquals( estimator.InterferenceStats._make( (common.ether_ntoa(mac), common.BSSInfo(255, 36, 0), 32, 258, 72623859790382856, 168496141)), payload)
def test_non_serving_data_metrics_msg(self): """Verify the parsing of the non-serving data metrics message.""" # Test 1: Measurement on a BSS on channel 6 mac = '\x42\x62\x89\x67\x4d\xb4' msg = '\x01' + mac + '\xff\x06\x01' + \ '\x50\x00\x00\x00\x42' payload = estimator.unpack_payload_from_bytes(common.Version.VERSION2, False, msg) self.assertEquals( estimator.NonServingDataMetrics._make( (common.ether_ntoa(mac), common.BSSInfo(255, 6, 1), 80, 66)), payload) # Test 2: Similar but in big endian format msg = '\x01' + mac + '\x02\x24\x00' + \ '\x00\x00\x00\x50\x42' payload = estimator.unpack_payload_from_bytes(common.Version.VERSION2, True, msg) self.assertEquals( estimator.NonServingDataMetrics._make( (common.ether_ntoa(mac), common.BSSInfo(2, 36, 0), 80, 66)), payload)
def test_sta_interference_detected_msg(self): """Verify the parsing of the STA interference detected message.""" # Test 1: Interference detected or not on a BSS on channel 11 for big_endian in (False, True): for detected in (False, True): mac = '\x42\x62\x89\x67\x4d\xb4' msg = '\x02' + mac + '\xff\x0b\x01' + chr(detected) payload = estimator.unpack_payload_from_bytes( common.Version.VERSION2, big_endian, msg) self.assertEquals( estimator.STAInterferenceDetected._make( (common.ether_ntoa(mac), common.BSSInfo(255, 11, 1), detected)), payload)
def test_steering_unfriendly(self): """Verify the parsing of the steering unfriendly message.""" # Test 1: Valid steering unfriendly messages for is_unfriendly in [False, True]: mac = '\x6e\xee\xb2\x94\x33\x6f' msg = '\x02' + mac + chr(is_unfriendly) payload = steerexec.unpack_payload_from_bytes( common.Version.VERSION1, False, msg) self.assertEquals( steerexec.SteeringUnfriendly._make( (common.ether_ntoa(mac), is_unfriendly)), payload) # Same as above but in big-endian (which makes no difference) payload = steerexec.unpack_payload_from_bytes( common.Version.VERSION1, True, msg) self.assertEquals( steerexec.SteeringUnfriendly._make( (common.ether_ntoa(mac), is_unfriendly)), payload) # Test 2: Valid steering unfriendly messages (v2) for is_unfriendly in [False, True]: mac = '\x6e\xee\xb2\x94\x33\x6f' msg = '\x02' + mac + chr(is_unfriendly) + '\x07\x00\x00\x00' payload = steerexec.unpack_payload_from_bytes( common.Version.VERSION2, False, msg) self.assertEquals( steerexec.SteeringUnfriendly_v2._make( (common.ether_ntoa(mac), is_unfriendly, 7)), payload) # Same as above but in big-endian msg = '\x02' + mac + chr(is_unfriendly) + '\x00\x00\x00\x07' payload = steerexec.unpack_payload_from_bytes( common.Version.VERSION2, True, msg) self.assertEquals( steerexec.SteeringUnfriendly_v2._make( (common.ether_ntoa(mac), is_unfriendly, 7)), payload)
def test_ether_aton(self): """Test the function that packs an ethernet address.""" self.assertRaises(ValueError, common.ether_aton, 'ff:c1:c4:62:22') # too short self.assertRaises(ValueError, common.ether_aton, 'ff:c1:c4:62:22:53:53') # too long self.assertRaises(ValueError, common.ether_aton, 'ff.c1.c4.62.22.53') # wrong separator self.assertEquals('\xff\xc1\xc4\x62\x22\x53', common.ether_aton('ff:c1:c4:62:22:53')) # Inverse of ether_ntoa self.assertEquals( '\xff\xc1\xc4\x62\x22\x53', common.ether_aton(common.ether_ntoa('\xff\xc1\xc4\x62\x22\x53')))
def replace_mac_address_with_string(payload, attr_name='mac'): """Replace the MAC address in the tuple with a formatted string. Args: payload (tuple): tuple containing a message attr_name (str): string containing the name of the MAC address field Returns: tuple updated with the MAC address in attr_name (if present) replaced with a string representation """ if hasattr(payload, attr_name): mac_addr = getattr(payload, attr_name) mac_addr = ether_ntoa(mac_addr) vals = {attr_name: mac_addr} payload = payload._replace(**vals) return payload
def test_unpack_msg(self): """Validate the top-level unpacking of messsages.""" # Test 1: A wlanif message msg = '\x10\x18\x29\xc6\x09\x00\xd6\x73\x06\x00\x01\x00\x00\x16' header, payload = parser.unpack_msg(msg) self.assertEquals( common.Header._make((common.Version.VERSION1, False, 24, 0x9c629, 0x673d6, common.ModuleID.WLANIF)), header) self.assertEquals( wlanif.RawChannelUtilization._make( (common.BAND_TYPE.BAND_24G, 22)), payload) # Test 2: A bandmon message msg = '\x11\xa2\x51\x77\x52\x0e\x00\x05\x03\xd9\x02\x01\x00\x37' header, payload = parser.unpack_msg(msg) self.assertEquals( common.Header._make( (common.Version.VERSION1, True, 162, 0x5177520e, 0x503d9, common.ModuleID.BANDMON)), header) self.assertEquals( bandmon.Utilization_v1._make((common.BAND_TYPE.BAND_24G, 55)), payload) # Test 3: A stadb message mac = '\xb2\xdd\x69\xa1\xb3\xe3' msg = '\x10\xa2\x0e\x52\x77\x51\xd9\x03\x05\x00\x05\x00' + mac + \ '\x00\x01\x01' header, payload = parser.unpack_msg(msg) self.assertEquals( common.Header._make((common.Version.VERSION1, False, 162, 0x5177520e, 0x503d9, common.ModuleID.STADB)), header) self.assertEquals( stadb.AssociationUpdate._make( (common.ether_ntoa(mac), common.BAND_TYPE.BAND_24G, True, True)), payload) # Test 4: A steerexec message mac = '\x6e\xee\xb2\x94\x33\x6f' msg = '\x11\x18\x00\x09\xc6\x29\x00\x06\x73\xd6\x06\x02' + mac + '\x01' header, payload = parser.unpack_msg(msg) self.assertEquals( common.Header._make((common.Version.VERSION1, True, 24, 0x9c629, 0x673d6, common.ModuleID.STEEREXEC)), header) self.assertEquals( steerexec.SteeringUnfriendly._make((common.ether_ntoa(mac), True)), payload) # Test 5: A diaglog message msg = '\x11\xa2\x51\x77\x52\x0e\x00\x05\x03\xd9\x08\x00abc' header, payload = parser.unpack_msg(msg) self.assertEquals( common.Header._make( (common.Version.VERSION1, True, 162, 0x5177520e, 0x503d9, common.ModuleID.DIAGLOG)), header) self.assertEquals(diaglog.StringMessage._make(('abc', )), payload) # Test 6: An estmiator message mac = '\x42\x62\x89\x67\x4d\xb4' msg = '\x20\x12\x60\x24\x87\x75\x15\x37\x00\x00\x09' + \ '\x00' + mac + '\xff\x06\x01\x2d\x00\x00\x00\x08\x00\x00\x00' + \ '\x50\x00\x00\x00\x42' header, payload = parser.unpack_msg(msg) self.assertEquals( common.Header._make( (common.Version.VERSION2, False, 18, 0x75872460, 0x3715, common.ModuleID.ESTIMATOR)), header) self.assertEquals( estimator.ServingDataMetrics._make( (common.ether_ntoa(mac), common.BSSInfo(255, 6, 1), 45, 8, 80, 66)), payload) # Test 7: An unhandled module msg = '\x11\xa2\x51\x77\x52\x0e\x00\x05\x03\xd9\x70\x12\x11\x22' self.assertRaises(ValueError, parser.unpack_msg, msg)
def test_msg_handler_multi_ap(self): """Test process_msgs when there are multiple AP registered. Make sure it will update model with the correct AP properly. Note that we only test valid messages here, since invalid messages will be handled by diagparser and not affect the logic here. """ self._create_device_db() model = self._create_mock_model() handler = MsgHandler(model, diagparser, None) handler.add_ap(self._ap1, self._ap1_addr[0]) # Each AP must have unique IP address self.assertRaises(ValueError, handler.add_ap, self._ap2, self._ap1_addr[0]) mac = '\x20\x02\xaf\xb7\x37\xa2' # Case 0: PostAssocSteer event, including 2 targets, should ignore remote BSS msg = '\x21\x18\x00\x09\xc6\x29\x00\x06\x73\xd6\x06\x05' + mac + \ '\x51\x01\x01\xFF\x64\x00\x02\xFF\x06\x00\x00\x64\x00' handler.process_msg(self._ap1_addr, msg) model.update_station_steering_status.assert_called_once_with( common.ether_ntoa(mac), start=True, assoc_vap=self._vap2, target_vaps=[self._vap1]) model.update_station_steering_status.reset_mock() # Add second AP handler.add_ap(self._ap2, self._ap2_addr[0]) # Case 1.1: Utilization on 2.4 GHz event for AP1 should update model msg = '\x21\xa2\x51\x77\x52\x0e\x00\x05\x03\xd9\x02\x01\x06\x37' handler.process_msg(self._ap1_addr, msg) model.update_utilizations.assert_called_once_with( { 'data': { self._vap1.vap_id: 55 }, 'type': 'average' }, self._ap1.ap_id) model.update_utilizations.reset_mock() # Case 1.2: RawChannelUtilization on 5 GHz event for AP2 should update model msg = '\x20\x18\x29\xc6\x09\x00\xd6\x73\x06\x00\x01\x00\x64\x16' handler.process_msg(self._ap2_addr, msg) model.update_utilizations.assert_called_once_with( { 'data': { self._vap4.vap_id: 22 }, 'type': 'raw' }, self._ap2.ap_id) model.update_utilizations.reset_mock() # Case 2.1: RSSIUpdate on 5 GHz event on AP1 should update model msg = '\x20\x0b\x29\x1f\x10\x01\x96\x0f\x07\x00\x05\x01' + mac + '\xFF\x64\x00\x10' handler.process_msg(self._ap1_addr, msg) model.update_associated_station_rssi.assert_called_once_with( self._vap2.vap_id, common.ether_ntoa(mac), 16, self._ap1.ap_id) model.update_associated_station_rssi.reset_mock() # Case 2.2: RawRSSI on 2.4 GHz event on AP2 should udpate model msg = '\x20\x0b\x29\x1f\x10\x01\x96\x0f\x07\x00\x01\x01' + mac + '\xFF\x06\x00\x20' handler.process_msg(self._ap2_addr, msg) model.update_associated_station_rssi.assert_called_once_with( self._vap3.vap_id, common.ether_ntoa(mac), 32, self._ap2.ap_id) model.update_associated_station_rssi.reset_mock() # Case 3.1: PostAssocSteer event, including 2 targets, one from local, # one from the other AP msg = '\x21\x18\x00\x09\xc6\x29\x00\x06\x73\xd6\x06\x05' + mac + \ '\x51\x01\x01\xFF\x64\x00\x02\xFF\x06\x00\x00\x64\x00' handler.process_msg(self._ap1_addr, msg) model.update_station_steering_status.assert_called_once_with( common.ether_ntoa(mac), start=True, assoc_vap=self._vap2, target_vaps=[self._vap1, self._vap4]) model.update_station_steering_status.reset_mock() # Case 3.2: PostAssocSteer event, including 2 targets, one from the # other AP, one from unknown AP, will ignore the unknown AP for now msg = '\x21\x18\x00\x09\xc6\x29\x00\x06\x73\xd6\x06\x05' + mac + \ '\x51\x01\x01\xFF\x64\x00\x02\x00\x64\x00\x01\x64\x00' handler.process_msg(self._ap1_addr, msg) model.update_station_steering_status.assert_called_once_with( common.ether_ntoa(mac), start=True, assoc_vap=self._vap2, target_vaps=[self._vap4]) model.update_station_steering_status.reset_mock() # Case 4.1: Association on 5 GHz event should update model msg = '\x20\x0b\x29\x1f\x10\x01\x96\x0f\x07\x00\x05\x00' + mac + \ '\xFF\x64\x00\x01\x01\x01\x00\x00' handler.process_msg(self._ap1_addr, msg) # Will disassociate on both APs calls = model.del_associated_station.call_args_list self.assertEquals(2, len(calls)) self.assertEquals(((common.ether_ntoa(mac), self._ap1.ap_id), ), calls[0]) self.assertEquals(((common.ether_ntoa(mac), self._ap2.ap_id), ), calls[1]) model.add_associated_station.assert_called_once_with( self._vap2.vap_id, common.ether_ntoa(mac), self._ap1.ap_id) model.update_station_steering_status.assert_called_once_with( common.ether_ntoa(mac), assoc_vap=self._vap2) model.update_associated_station_activity.assert_called_once_with( self._vap2.vap_id, common.ether_ntoa(mac), self._ap1.ap_id, is_active=True) # starts as active on association model.update_station_flags.assert_called_once_with( common.ether_ntoa(mac), self._ap1.ap_id, is_dual_band=True) # mark as dual band model.del_associated_station.reset_mock() model.add_associated_station.reset_mock() model.update_station_steering_status.reset_mock() model.update_associated_station_activity.reset_mock() model.update_station_flags.reset_mock() # Case 4.2: Disassociation event should update model msg = '\x20\x0b\x29\x1f\x10\x01\x96\x0f\x07\x00\x05\x00' + mac + \ '\xFF\x64\x00\x00\x01\x01\x00\x00' handler.process_msg(self._ap1_addr, msg) model.del_associated_station.assert_called_once_with( common.ether_ntoa(mac), self._ap1.ap_id) model.update_station_steering_status.assert_called_once_with( common.ether_ntoa(mac), assoc_vap=None, ap_id=self._ap1.ap_id) handler.process_msg(self._ap1_addr, msg) model.del_associated_station.reset_mock() self.assert_(not model.add_associated_station.called) self.assert_(not model.update_associated_station_activity.called) self.assert_(not model.update_station_flags.called) model.update_station_steering_status.reset_mock() # Case 5.1: Pollution state change on remote BSS msg = "\x20\x66\x14\x9e\x33\x57\x07\x4a\x05\x00\x09\x03" + mac + \ "\x00\x06\x00\x01\x02" handler.process_msg(self._ap2_addr, msg) model.update_station_pollution_state.assert_called_once_with( common.ether_ntoa(mac), self._ap2.ap_id, self._vap1, True) model.update_station_pollution_state.reset_mock() # Case 5.2 Pollution state change on unknown remote BSS is ignored msg = "\x20\x66\x14\x9e\x33\x57\x07\x4a\x05\x00\x09\x03" + mac + \ "\x01\x06\x00\x01\x02" handler.process_msg(self._ap2_addr, msg) self.assert_(not model.update_station_pollution_state.called) # Case 0: Message with unknown IP address should do nothing msg = '\x21\xa2\x51\x77\x52\x0e\x00\x05\x03\xd9\x02\x01\x06\x37' handler.process_msg(self._unknown_addr, msg) msg = '\x20\x0b\x29\x1f\x10\x01\x96\x0f\x07\x00\x01\x01' + mac + '\xFF\x06\x00\x20' handler.process_msg(self._unknown_addr, msg) self.assert_(not model.update_utilizations.called) self.assert_(not model.update_associated_station_rssi.called) self.assert_(not model.add_associated_station.called) self.assert_(not model.del_associated_station.called)
def unpack_payload_from_bytes(version, big_endian, buf): """Unpack the payload portion of the message provided. Args: version (int): the version number of the message big_endian (bool): whether the payload is encoded in big endian format or not buf (str): the entire payload to be unpacked Returns: the unpacked message as a namedtuple of the right type Raises: :class:`MessageMalformedError`: Unsupported message ID or band """ if len(buf) == 0: raise MessageMalformedError("Message ID is missing") msg_id = ord(buf[0]) band_attrs = None check_steer = False check_status = False if version == common.Version.VERSION1: if msg_id == MessageID.STEER_TO_BAND.value: unpacker = _SteerToBand constructor = SteerToBand band_attrs = [('assoc_band', True), ('target_band', False)] elif msg_id == MessageID.ABORT_STEER_TO_BAND.value: unpacker = _AbortSteerToBand constructor = AbortSteerToBand band_attrs = [('disabled_band', False)] elif msg_id == MessageID.STEERING_UNFRIENDLY.value: unpacker = _SteeringUnfriendly constructor = SteeringUnfriendly elif msg_id == MessageID.STEERING_PROHIBITED.value: unpacker = _SteeringProhibited constructor = SteeringProhibited else: raise MessageMalformedError("Unsupported message ID: %d" % msg_id) elif version == common.Version.VERSION2: if msg_id == MessageID.PRE_ASSOC_STEER.value: unpacker = _PreAssocSteer constructor = PreAssocSteer elif msg_id == MessageID.STEER_END.value: unpacker = _SteerEnd constructor = SteerEnd check_steer = True check_status = True elif msg_id == MessageID.STEERING_UNFRIENDLY.value: unpacker = _SteeringUnfriendlyBE_v2 if big_endian else _SteeringUnfriendlyLE_v2 constructor = SteeringUnfriendly_v2 elif msg_id == MessageID.STEERING_PROHIBITED.value: unpacker = _SteeringProhibited_v2 constructor = SteeringProhibited_v2 elif msg_id == MessageID.BTM_COMPLIANCE.value: unpacker = _BTMComplianceBE if big_endian else _BTMComplianceLE constructor = BTMCompliance elif msg_id == MessageID.POST_ASSOC_STEER.value: unpacker = _PostAssocSteer constructor = PostAssocSteer check_steer = True else: raise MessageMalformedError("Unsupported message ID: %d" % msg_id) else: raise MessageMalformedError("Invalid version number: %d" % version) if len(buf) < unpacker.size + 1: raise MessageMalformedError("Message too short: %d (need %d)" % (len(buf), unpacker.size + 1)) if msg_id == MessageID.PRE_ASSOC_STEER.value and version == common.Version.VERSION2: fields = unpacker.unpack(buf[1:unpacker.size + 1]) payload = constructor._make([common.ether_ntoa(fields[0])] + list(fields)[1:]) elif msg_id == MessageID.POST_ASSOC_STEER.value and version == common.Version.VERSION2: # Variable length messages # First unpack the fixed size portion fields = unpacker.unpack(buf[1:unpacker.size + 1]) fields = fields + (0, 0, 0) payload = constructor._make([common.ether_ntoa(fields[0])] + list(fields)[1:]) else: fields = unpacker.unpack(buf[1:]) payload = constructor._make([common.ether_ntoa(fields[0])] + list(fields)[1:]) if (msg_id == MessageID.PRE_ASSOC_STEER.value and version == common.Version.VERSION2): payload = get_pre_assoc_channel_list(payload, buf, unpacker) elif (msg_id == MessageID.POST_ASSOC_STEER.value and version == common.Version.VERSION2): payload = get_post_assoc_candidates(payload, buf, unpacker) payload = check_reason_type(payload) if band_attrs is not None: for attr in band_attrs: payload = common.check_band(payload, allow_invalid=attr[1], attr_name=attr[0]) if msg_id == MessageID.STEERING_PROHIBITED.value and version == common.Version.VERSION2: payload = check_steering_prohibit_type(payload) if msg_id == MessageID.BTM_COMPLIANCE.value: payload = check_btm_compliance_type(payload) if check_steer: payload = check_steer_type(payload) if check_status: payload = check_status_type(payload) return payload
def test_msg_handler_process_msgs_v2(self): """Test process_msgs function, make sure it will update model properly Note that we only test valid messages here, since invalid messages will be handled by diagparser and not affect the logic here. """ self._create_device_db() model = self._create_mock_model() handler = MsgHandler(model, diagparser, None) handler.add_ap(self._ap1, self._ap1_addr[0]) # Case 1.1: Utilization on 2.4 GHz event should update model msg = '\x21\xa2\x51\x77\x52\x0e\x00\x05\x03\xd9\x02\x01\x06\x37' handler.process_msg(self._ap1_addr, msg) model.update_utilizations.assert_called_once_with( { 'data': { self._vap1.vap_id: 55 }, 'type': 'average' }, self._ap1.ap_id) model.update_utilizations.reset_mock() # Case 1.2: RawChannelUtilization on 5 GHz event should update model msg = '\x20\x18\x29\xc6\x09\x00\xd6\x73\x06\x00\x01\x00\x64\x16' handler.process_msg(self._ap1_addr, msg) model.update_utilizations.assert_called_once_with( { 'data': { self._vap2.vap_id: 22 }, 'type': 'raw' }, self._ap1.ap_id) model.update_utilizations.reset_mock() mac = '\x20\x02\xaf\xb7\x37\xa2' # Case 2.1: RSSIUpdate on 5 GHz event should update model msg = '\x20\x0b\x29\x1f\x10\x01\x96\x0f\x07\x00\x05\x01' + mac + '\xFF\x64\x00\x10' handler.process_msg(self._ap1_addr, msg) model.update_associated_station_rssi.assert_called_once_with( self._vap2.vap_id, common.ether_ntoa(mac), 16, self._ap1.ap_id) model.update_associated_station_rssi.reset_mock() # Case 2.2: RawRSSI on 2.4 GHz event should udpate model msg = '\x20\x0b\x29\x1f\x10\x01\x96\x0f\x07\x00\x01\x01' + mac + '\xFF\x06\x00\x20' handler.process_msg(self._ap1_addr, msg) model.update_associated_station_rssi.assert_called_once_with( self._vap1.vap_id, common.ether_ntoa(mac), 32, self._ap1.ap_id) model.update_associated_station_rssi.reset_mock() # Case 3.1: Association on 5 GHz event should update model msg = '\x20\x0b\x29\x1f\x10\x01\x96\x0f\x07\x00\x05\x00' + mac + \ '\xFF\x64\x00\x01\x01\x01\x00\x00' handler.process_msg(self._ap1_addr, msg) model.del_associated_station.assert_called_once_with( common.ether_ntoa(mac), self._ap1.ap_id) model.add_associated_station.assert_called_once_with( self._vap2.vap_id, common.ether_ntoa(mac), self._ap1.ap_id) model.update_station_steering_status.assert_called_once_with( common.ether_ntoa(mac), assoc_vap=self._vap2) model.update_associated_station_activity.assert_called_once_with( self._vap2.vap_id, common.ether_ntoa(mac), self._ap1.ap_id, is_active=True) # starts as active on association model.update_station_flags.assert_called_once_with( common.ether_ntoa(mac), self._ap1.ap_id, is_dual_band=True) # mark as dual band model.del_associated_station.reset_mock() model.add_associated_station.reset_mock() model.update_station_steering_status.reset_mock() model.update_associated_station_activity.reset_mock() model.update_station_flags.reset_mock() # Case 3.2: Disassociation event should update model msg = '\x20\x0b\x29\x1f\x10\x01\x96\x0f\x07\x00\x05\x00' + mac + \ '\xFF\x64\x00\x00\x01\x01\x00\x00' handler.process_msg(self._ap1_addr, msg) model.del_associated_station.assert_called_once_with( common.ether_ntoa(mac), self._ap1.ap_id) model.update_station_steering_status.assert_called_once_with( common.ether_ntoa(mac), assoc_vap=None, ap_id=self._ap1.ap_id) handler.process_msg(self._ap1_addr, msg) model.del_associated_station.reset_mock() self.assert_(not model.add_associated_station.called) self.assert_(not model.update_associated_station_activity.called) self.assert_(not model.update_station_flags.called) model.update_station_steering_status.reset_mock() # Case 4: OverloadChange event should update model msg = '\x21\xa2\x51\x77\x52\x0e\x00\x05\x03\xd9\x02\x00\x01\x64' handler.process_msg(self._ap1_addr, msg) model.update_overload_status.assert_called_once_with( { self._vap1.vap_id: False, self._vap2.vap_id: True }, self._ap1._ap_id) model.update_overload_status.reset_mock() msg = '\x21\xa2\x51\x77\x52\x0e\x00\x05\x03\xd9\x02\x00\x02\x06\x64' handler.process_msg(self._ap1_addr, msg) model.update_overload_status.assert_called_once_with( { self._vap1.vap_id: True, self._vap2.vap_id: True }, self._ap1._ap_id) model.update_overload_status.reset_mock() # Case 5: PostAssocSteer event msg = '\x21\x18\x00\x09\xc6\x29\x00\x06\x73\xd6\x06\x05' + mac + \ '\x51\x01\x01\xFF\x64\x00\x01\xFF\x06\x00' handler.process_msg(self._ap1_addr, msg) model.update_station_steering_status.assert_called_once_with( common.ether_ntoa(mac), start=True, assoc_vap=self._vap2, target_vaps=[self._vap1]) model.update_station_steering_status.reset_mock() # Case 6a: SteerEnd event with a non-success msg = '\x21\x18\x00\x09\xc6\x29\x00\x06\x73\xd6\x06\x01' + mac + '\x51\x01\x01' handler.process_msg(self._ap1_addr, msg) model.update_station_steering_status.assert_called_once_with( common.ether_ntoa(mac), abort=True) model.update_station_steering_status.reset_mock() # Case 6b: SteerEnd event with a success; should be ignored msg = '\x21\x18\x00\x09\xc6\x29\x00\x06\x73\xd6\x06\x01' + mac + '\x51\x01\x00' handler.process_msg(self._ap1_addr, msg) self.assert_(not model.update_station_steering_status.called) # Case 7: Serving data metrics event msg = '\x20\x18\x00\x09\xc6\x29\x00\x06\x73\xd6\x09\x00' + mac + \ '\xff\x06\x01\x2d\x00\x00\x00\x08\x00\x00\x00\x50\x00\x00\x00\x42' handler.process_msg(self._ap1_addr, msg) model.update_associated_station_data_metrics.assert_called_once_with( self._vap1.vap_id, common.ether_ntoa(mac), 45 + 8, 80, 66, self._ap1.ap_id) model.update_associated_station_data_metrics.reset_mock() # Case 8a: Activity update - active msg = '\x20\x0b\x29\x1f\x10\x01\x96\x0f\x07\x00\x05\x02' + mac + '\xFF\x64\x00\x01' handler.process_msg(self._ap1_addr, msg) model.update_associated_station_activity.assert_called_once_with( self._vap2.vap_id, common.ether_ntoa(mac), self._ap1.ap_id, is_active=True) model.update_associated_station_activity.reset_mock() # Case 8b: Activity update - idle msg = '\x20\x0b\x29\x1f\x10\x01\x96\x0f\x07\x00\x05\x02' + mac + '\xFF\x64\x00\x00' handler.process_msg(self._ap1_addr, msg) model.update_associated_station_activity.assert_called_once_with( self._vap2.vap_id, common.ether_ntoa(mac), self._ap1.ap_id, is_active=False) model.update_associated_station_activity.reset_mock() # Case 9a: SteeringUnfriendly event - unfriendly msg = '\x21\x18\x00\x09\xc6\x29\x00\x06\x73\xd6\x06\x02' + mac + \ '\x01\x00\x00\x00\x05' handler.process_msg(self._ap1_addr, msg) model.update_station_flags.assert_called_once_with( common.ether_ntoa(mac), self._ap1.ap_id, is_unfriendly=True) model.update_station_flags.reset_mock() # Case 9b: SteeringUnfriendly event - friendly msg = '\x21\x18\x00\x09\xc6\x29\x00\x06\x73\xd6\x06\x02' + mac + \ '\x00\x00\x00\x00\x00' handler.process_msg(self._ap1_addr, msg) model.update_station_flags.assert_called_once_with( common.ether_ntoa(mac), self._ap1.ap_id, is_unfriendly=False) model.update_station_flags.reset_mock() # Case 10a: Dual band update - is dual band msg = '\x20\x0b\x29\x1f\x10\x01\x96\x0f\x07\x00\x05\x03' + mac + '\x01' handler.process_msg(self._ap1_addr, msg) model.update_station_flags.assert_called_once_with( common.ether_ntoa(mac), self._ap1.ap_id, is_dual_band=True) model.update_station_flags.reset_mock() # Case 10b: Dual band update - is not dual band msg = '\x20\x0b\x29\x1f\x10\x01\x96\x0f\x07\x00\x05\x03' + mac + '\x00' handler.process_msg(self._ap1_addr, msg) model.update_station_flags.assert_called_once_with( common.ether_ntoa(mac), self._ap1.ap_id, is_dual_band=False) model.update_station_flags.reset_mock() # Case 11a: Steering prohibited - long prohibit msg = '\x21\x18\x00\x09\xc6\x29\x00\x06\x73\xd6\x06\x03' + mac + '\x02' handler.process_msg(self._ap1_addr, msg) model.update_station_flags.assert_called_once_with( common.ether_ntoa(mac), self._ap1.ap_id, prohibit_type=SteeringProhibitType.PROHIBIT_LONG) model.update_station_flags.reset_mock() # Case 11b: Steering prohibited - short prohibit msg = '\x21\x18\x00\x09\xc6\x29\x00\x06\x73\xd6\x06\x03' + mac + '\x01' handler.process_msg(self._ap1_addr, msg) model.update_station_flags.assert_called_once_with( common.ether_ntoa(mac), self._ap1.ap_id, prohibit_type=SteeringProhibitType.PROHIBIT_SHORT) model.update_station_flags.reset_mock() # Case 11c: Steering prohibited - no prohibit msg = '\x21\x18\x00\x09\xc6\x29\x00\x06\x73\xd6\x06\x03' + mac + '\x00' handler.process_msg(self._ap1_addr, msg) model.update_station_flags.assert_called_once_with( common.ether_ntoa(mac), self._ap1.ap_id, prohibit_type=SteeringProhibitType.PROHIBIT_NONE) model.update_station_flags.reset_mock() # Case 12a: BTMCompliance - idle friendly msg = '\x21\x18\x00\x09\xc6\x29\x00\x06\x73\xd6\x06\x04' + mac + \ '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' handler.process_msg(self._ap1_addr, msg) model.update_station_flags.assert_called_once_with( common.ether_ntoa(mac), self._ap1.ap_id, btm_compliance=BTMComplianceType.BTM_COMPLIANCE_IDLE, is_btm_unfriendly=False) model.update_station_flags.reset_mock() # Case 12b: BTMCompliance - active unfriendly but still BTM friendly msg = '\x21\x18\x00\x09\xc6\x29\x00\x06\x73\xd6\x06\x04' + mac + \ '\x00\x01\x00\x00\x00\x00\x00\x00\x00\x02' handler.process_msg(self._ap1_addr, msg) model.update_station_flags.assert_called_once_with( common.ether_ntoa(mac), self._ap1.ap_id, btm_compliance=BTMComplianceType.BTM_COMPLIANCE_ACTIVE_UNFRIENDLY, is_btm_unfriendly=False) model.update_station_flags.reset_mock() # Case 12c: BTMCompliance - active unfriendly and not BTM friendly msg = '\x21\x18\x00\x09\xc6\x29\x00\x06\x73\xd6\x06\x04' + mac + \ '\x01\x01\x00\x00\x00\x00\x00\x00\x00\x02' handler.process_msg(self._ap1_addr, msg) model.update_station_flags.assert_called_once_with( common.ether_ntoa(mac), self._ap1.ap_id, btm_compliance=BTMComplianceType.BTM_COMPLIANCE_ACTIVE_UNFRIENDLY, is_btm_unfriendly=True) model.update_station_flags.reset_mock() # Case 12d: BTMCompliance - active and BTM friendly msg = '\x21\x18\x00\x09\xc6\x29\x00\x06\x73\xd6\x06\x04' + mac + \ '\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00' handler.process_msg(self._ap1_addr, msg) model.update_station_flags.assert_called_once_with( common.ether_ntoa(mac), self._ap1.ap_id, btm_compliance=BTMComplianceType.BTM_COMPLIANCE_ACTIVE, is_btm_unfriendly=False) model.update_station_flags.reset_mock() # Case 13a: BlackoutChange - blackout true msg = '\x21\xa2\x51\x77\x52\x0e\x00\x05\x03\xd9\x02\x02\x01' handler.process_msg(self._ap1_addr, msg) model.update_steering_blackout_status.assert_called_once_with( True, self._ap1._ap_id) model.update_steering_blackout_status.reset_mock() # Case 13b: BlackoutChange - blackout false msg = '\x21\xa2\x51\x77\x52\x0e\x00\x05\x03\xd9\x02\x02\x00' handler.process_msg(self._ap1_addr, msg) model.update_steering_blackout_status.assert_called_once_with( False, self._ap1._ap_id) model.update_steering_blackout_status.reset_mock() # Case 14a: Pollution state change - polluted msg = "\x20\x66\x14\x9e\x33\x57\x07\x4a\x05\x00\x09\x03" + mac + \ "\xff\x06\x00\x01\x02" handler.process_msg(self._ap1_addr, msg) model.update_station_pollution_state.assert_called_once_with( common.ether_ntoa(mac), self._ap1.ap_id, self._vap1, True) model.update_station_pollution_state.reset_mock() # Case 14b: Pollution state change - not polluted msg = "\x21\x66\x14\x9e\x33\x57\x07\x4a\x05\x00\x09\x03" + mac + \ "\xff\x64\x00\x00\x02" handler.process_msg(self._ap1_addr, msg) model.update_station_pollution_state.assert_called_once_with( common.ether_ntoa(mac), self._ap1.ap_id, self._vap2, False) model.update_station_pollution_state.reset_mock() # Case 14c: Pollution state change from unknown BSS, ignore msg = "\x20\x66\x14\x9e\x33\x57\x07\x4a\x05\x00\x09\x03" + mac + \ "\xff\x01\x00\x00\x02" handler.process_msg(self._ap1_addr, msg) self.assert_(not model.update_station_pollution_state.called) # Case 15: Other events should be ignored # Diaglog message msg = '\x21\xa2\x51\x77\x52\x0e\x00\x05\x03\xd9\x08\x00abc' handler.process_msg(self._ap1_addr, msg) self.assert_(not model.update_utilizations.called) self.assert_(not model.update_associated_station_rssi.called) self.assert_(not model.add_associated_station.called) self.assert_(not model.del_associated_station.called) self.assert_(not model.update_overload_status.called)
def test_msg_handler_process_msgs_v2_not_found(self): """Test process_msgs function, make sure it will update model properly Note that we only test valid messages here, since invalid messages will be handled by diagparser and not affect the logic here. """ self._create_device_db() model = self._create_mock_model() handler = MsgHandler(model, diagparser, None) handler.add_ap(self._ap3, self._ap3_addr[0]) # Case 1.1: Utilization on 2.4 GHz msg = '\x21\xa2\x51\x77\x52\x0e\x00\x05\x03\xd9\x02\x01\x06\x37' handler.process_msg(self._ap3_addr, msg) self.assert_(not model.update_utilizations.called) model.update_utilizations.reset_mock() # Case 1.2: RawChannelUtilization on 2.4 GHz msg = '\x20\x18\x29\xc6\x09\x00\xd6\x73\x06\x00\x01\x00\x06\x16' handler.process_msg(self._ap3_addr, msg) self.assert_(not model.update_utilizations.called) model.update_utilizations.reset_mock() mac = '\x20\x02\xaf\xb7\x37\xa2' # Case 2.1: RSSIUpdate on 2.4 GHz msg = '\x20\x0b\x29\x1f\x10\x01\x96\x0f\x07\x00\x05\x01' + mac + '\xFF\x06\x00\x10' handler.process_msg(self._ap3_addr, msg) self.assert_(not model.update_associated_station_rssi.called) model.update_associated_station_rssi.reset_mock() # Case 2.2: RawRSSI on 2.4 GHz msg = '\x20\x0b\x29\x1f\x10\x01\x96\x0f\x07\x00\x01\x01' + mac + '\xFF\x06\x00\x20' handler.process_msg(self._ap3_addr, msg) self.assert_(not model.update_associated_station_rssi.called) model.update_associated_station_rssi.reset_mock() # Case 3.1: Association on 5 GHz msg = '\x20\x0b\x29\x1f\x10\x01\x96\x0f\x07\x00\x05\x00' + mac + \ '\xFF\x06\x00\x01\x01\x01\x00\x00' handler.process_msg(self._ap3_addr, msg) self.assert_(not model.del_associated_station.called) self.assert_(not model.add_associated_station.called) self.assert_(not model.update_station_steering_status.called) self.assert_(not model.update_associated_station_activity.called) self.assert_(not model.update_station_flags.called) model.del_associated_station.reset_mock() model.add_associated_station.reset_mock() model.update_station_steering_status.reset_mock() model.update_associated_station_activity.reset_mock() model.update_station_flags.reset_mock() # Case 3.2: Disassociation msg = '\x20\x0b\x29\x1f\x10\x01\x96\x0f\x07\x00\x05\x00' + mac + \ '\xFF\x06\x00\x00\x01\x01\x00\x00' handler.process_msg(self._ap3_addr, msg) self.assert_(not model.del_associated_station.called) self.assert_(not model.update_station_steering_status.called) self.assert_(not model.add_associated_station.called) self.assert_(not model.update_associated_station_activity.called) self.assert_(not model.update_station_flags.called) model.del_associated_station.reset_mock() model.add_associated_station.reset_mock() model.update_station_steering_status.reset_mock() model.update_associated_station_activity.reset_mock() model.update_station_flags.reset_mock() # Case 4: OverloadChange event should update model msg = '\x21\xa2\x51\x77\x52\x0e\x00\x05\x03\xd9\x02\x00\x01\x06' handler.process_msg(self._ap3_addr, msg) model.update_overload_status.assert_called_once_with( {self._vap5.vap_id: False}, self._ap3._ap_id) model.update_overload_status.reset_mock() msg = '\x21\xa2\x51\x77\x52\x0e\x00\x05\x03\xd9\x02\x00\x02\x06\x64' handler.process_msg(self._ap3_addr, msg) model.update_overload_status.assert_called_once_with( {self._vap5.vap_id: True}, self._ap3._ap_id) model.update_overload_status.reset_mock() # Case 5a: PostAssocSteer event with assoc invalid msg = '\x21\x18\x00\x09\xc6\x29\x00\x06\x73\xd6\x06\x05' + mac + \ '\x51\x01\x01\xFF\x06\x00\x01\xFF\x64\x00' handler.process_msg(self._ap3_addr, msg) self.assert_(not model.update_station_steering_status.called) model.update_station_steering_status.reset_mock() # Case 5b: PostAssocSteer event with all targets invalid msg = '\x21\x18\x00\x09\xc6\x29\x00\x06\x73\xd6\x06\x05' + mac + \ '\x51\x01\x01\xFF\x06\x00\x01\xFF\x0b\x00' handler.process_msg(self._ap3_addr, msg) self.assert_(not model.update_station_steering_status.called) model.update_station_steering_status.reset_mock() # Case 5c: PostAssocSteer event with one target invalid msg = '\x21\x18\x00\x09\xc6\x29\x00\x06\x73\xd6\x06\x05' + mac + \ '\x51\x01\x01\xFF\x64\x00\x02\xFF\x0b\x00\xFF\x64\x00' handler.process_msg(self._ap3_addr, msg) model.update_station_steering_status.assert_called_once_with( common.ether_ntoa(mac), start=True, assoc_vap=self._vap5, target_vaps=[self._vap5]) model.update_station_steering_status.reset_mock() # Case 6: Serving data metrics event msg = '\x20\x18\x00\x09\xc6\x29\x00\x06\x73\xd6\x09\x00' + mac + \ '\xff\x06\x01\x2d\x00\x00\x00\x08\x00\x00\x00\x50\x00\x00\x00\x42' handler.process_msg(self._ap3_addr, msg) self.assert_(not model.update_associated_station_data_metrics.called) model.update_associated_station_data_metrics.reset_mock() # Case 7a: Activity update - active msg = '\x20\x0b\x29\x1f\x10\x01\x96\x0f\x07\x00\x05\x02' + mac + '\xFF\x06\x00\x01' handler.process_msg(self._ap3_addr, msg) self.assert_(not model.update_associated_station_activity.called) model.update_associated_station_activity.reset_mock() # Case 7b: Activity update - idle msg = '\x20\x0b\x29\x1f\x10\x01\x96\x0f\x07\x00\x05\x02' + mac + '\xFF\x06\x00\x00' handler.process_msg(self._ap3_addr, msg) self.assert_(not model.update_associated_station_activity.called) model.update_associated_station_activity.reset_mock()
def test_msg_handler_process_msgs(self): """Test process_msgs function, make sure it will update model properly Note that we only test valid messages here, since invalid messages will be handled by diagparser and not affect the logic here. """ self._create_device_db() model = self._create_mock_model() handler = MsgHandler(model, diagparser, None) mac = '\x20\x02\xaf\xb7\x37\xa2' # Case 0: Message from unknown IP address will be ignored msg = '\x11\xa2\x51\x77\x52\x0e\x00\x05\x03\xd9\x02\x01\x00\x37' handler.process_msg(self._ap1_addr, msg) msg = '\x10\x0b\x29\x1f\x10\x01\x96\x0f\x07\x00\x05\x01' + mac + '\x01\x10' handler.process_msg(self._ap1_addr, msg) msg = '\x10\x0b\x29\x1f\x10\x01\x96\x0f\x07\x00\x05\x00' + mac + '\x01\x01\x01' handler.process_msg(self._ap1_addr, msg) self.assert_(not model.update_utilizations.called) self.assert_(not model.update_associated_station_rssi.called) self.assert_(not model.add_associated_station.called) self.assert_(not model.del_associated_station.called) # Register AP1 with diaglog handler handler.add_ap(self._ap1, self._ap1_addr[0]) # Case 1.1: Utilization on 2.4 GHz event should update model msg = '\x11\xa2\x51\x77\x52\x0e\x00\x05\x03\xd9\x02\x01\x00\x37' handler.process_msg(self._ap1_addr, msg) model.update_utilizations.assert_called_once_with( { 'data': { self._vap1.vap_id: 55 }, 'type': 'average' }, self._ap1.ap_id) model.update_utilizations.reset_mock() # Case 1.2: RawChannelUtilization on 5 GHz event should update model msg = '\x10\x18\x29\xc6\x09\x00\xd6\x73\x06\x00\x01\x00\x01\x16' handler.process_msg(self._ap1_addr, msg) model.update_utilizations.assert_called_once_with( { 'data': { self._vap2.vap_id: 22 }, 'type': 'raw' }, self._ap1.ap_id) model.update_utilizations.reset_mock() # Case 2.1: RSSIUpdate on 5 GHz event should update model msg = '\x10\x0b\x29\x1f\x10\x01\x96\x0f\x07\x00\x05\x01' + mac + '\x01\x10' handler.process_msg(self._ap1_addr, msg) model.update_associated_station_rssi.assert_called_once_with( self._vap2.vap_id, common.ether_ntoa(mac), 16, self._ap1.ap_id) model.update_associated_station_rssi.reset_mock() # Case 2.2: RawRSSI on 2.4 GHz event should udpate model msg = '\x10\x0b\x29\x1f\x10\x01\x96\x0f\x07\x00\x01\x01' + mac + '\x00\x20' handler.process_msg(self._ap1_addr, msg) model.update_associated_station_rssi.assert_called_once_with( self._vap1.vap_id, common.ether_ntoa(mac), 32, self._ap1.ap_id) model.update_associated_station_rssi.reset_mock() # Case 3.1: Association on 5 GHz event should update model msg = '\x10\x0b\x29\x1f\x10\x01\x96\x0f\x07\x00\x05\x00' + mac + '\x01\x01\x01' handler.process_msg(self._ap1_addr, msg) model.del_associated_station.assert_called_once_with( common.ether_ntoa(mac), self._ap1.ap_id) model.add_associated_station.assert_called_once_with( self._vap2.vap_id, common.ether_ntoa(mac), self._ap1.ap_id) model.update_station_steering_status.assert_called_once_with( common.ether_ntoa(mac), assoc_band=self._vap2.band) model.update_associated_station_activity.assert_called_once_with( self._vap2.vap_id, common.ether_ntoa(mac), self._ap1.ap_id, is_active=True) # starts as active on association model.update_station_flags.assert_called_once_with( common.ether_ntoa(mac), self._ap1.ap_id, is_dual_band=True) # mark as dual band model.del_associated_station.reset_mock() model.add_associated_station.reset_mock() model.update_associated_station_activity.reset_mock() model.update_station_steering_status.reset_mock() model.update_station_flags.reset_mock() # Case 3.2: Disassociation event should update model msg = '\x10\x0b\x29\x1f\x10\x01\x96\x0f\x07\x00\x05\x00' + mac + '\x02\x00\x00' handler.process_msg(self._ap1_addr, msg) model.del_associated_station.assert_called_once_with( common.ether_ntoa(mac), self._ap1.ap_id) model.update_station_steering_status.assert_called_once_with( common.ether_ntoa(mac), assoc_band=BAND_TYPE.BAND_INVALID) model.del_associated_station.reset_mock() self.assert_(not model.add_associated_station.called) self.assert_(not model.update_associated_station_activity.called) self.assert_(not model.update_station_flags.called) model.update_station_steering_status.reset_mock() # Case 4: OverloadChange event should update model msg = '\x11\xa2\x51\x77\x52\x0e\x00\x05\x03\xd9\x02\x00\x03\x02' handler.process_msg(self._ap1_addr, msg) model.update_overload_status.assert_called_once_with( { self._vap1.vap_id: False, self._vap2.vap_id: True }, self._ap1._ap_id) model.update_overload_status.reset_mock() msg = '\x11\xa2\x51\x77\x52\x0e\x00\x05\x03\xd9\x02\x00\x00\x03' handler.process_msg(self._ap1_addr, msg) model.update_overload_status.assert_called_once_with( { self._vap1.vap_id: True, self._vap2.vap_id: True }, self._ap1._ap_id) model.update_overload_status.reset_mock() # Case 5: SteerToBand event msg = '\x11\x18\x00\x09\xc6\x29\x00\x06\x73\xd6\x06\x00' + mac + '\x01\x00' handler.process_msg(self._ap1_addr, msg) model.update_station_steering_status.assert_called_once_with( common.ether_ntoa(mac), start=True, assoc_band=BAND_TYPE.BAND_5G, target_band=BAND_TYPE.BAND_24G) model.update_station_steering_status.reset_mock() # Case 6: AbortSteerToBand event msg = '\x11\x18\x00\x09\xc6\x29\x00\x06\x73\xd6\x06\x01' + mac + '\x00' handler.process_msg(self._ap1_addr, msg) model.update_station_steering_status.assert_called_once_with( common.ether_ntoa(mac), abort=True) model.update_station_steering_status.reset_mock() # Case 7a: ActivityUpdate with active # Activity update msg = '\x10\x0b\x29\x1f\x10\x01\x96\x0f\x07\x00\x05\x02' + mac + '\x01\x01' handler.process_msg(self._ap1_addr, msg) model.update_associated_station_activity.assert_called_once_with( self._vap2.vap_id, common.ether_ntoa(mac), self._ap1.ap_id, is_active=True) model.update_associated_station_activity.reset_mock() # Case 7b: ActivityUpdate with idle msg = '\x10\x0b\x29\x1f\x10\x01\x96\x0f\x07\x00\x05\x02' + mac + '\x01\x00' handler.process_msg(self._ap1_addr, msg) model.update_associated_station_activity.assert_called_once_with( self._vap2.vap_id, common.ether_ntoa(mac), self._ap1.ap_id, is_active=False) model.update_associated_station_activity.reset_mock() # Case 8a: SteeringUnfriendly with marked as unfriendly msg = '\x11\x18\x00\x09\xc6\x29\x00\x06\x73\xd6\x06\x02' + mac + '\x01' handler.process_msg(self._ap1_addr, msg) model.update_station_flags.assert_called_once_with( common.ether_ntoa(mac), self._ap1.ap_id, is_unfriendly=True) model.update_station_flags.reset_mock() # Case 8b: SteeringUnfriendly with marked as friendly msg = '\x11\x18\x00\x09\xc6\x29\x00\x06\x73\xd6\x06\x02' + mac + '\x00' handler.process_msg(self._ap1_addr, msg) model.update_station_flags.assert_called_once_with( common.ether_ntoa(mac), self._ap1.ap_id, is_unfriendly=False) model.update_station_flags.reset_mock() # Case 9a: Dual band update - is dual band msg = '\x10\x0b\x29\x1f\x10\x01\x96\x0f\x07\x00\x05\x03' + mac + '\x01' handler.process_msg(self._ap1_addr, msg) model.update_station_flags.assert_called_once_with( common.ether_ntoa(mac), self._ap1.ap_id, is_dual_band=True) model.update_station_flags.reset_mock() # Case 9b: Dual band update - is not dual band msg = '\x10\x0b\x29\x1f\x10\x01\x96\x0f\x07\x00\x05\x03' + mac + '\x00' handler.process_msg(self._ap1_addr, msg) model.update_station_flags.assert_called_once_with( common.ether_ntoa(mac), self._ap1.ap_id, is_dual_band=False) model.update_station_flags.reset_mock() # Case 10a: Steering prohibited - is prohibited msg = '\x11\x18\x00\x09\xc6\x29\x00\x06\x73\xd6\x06\x03' + mac + '\x01' handler.process_msg(self._ap1_addr, msg) model.update_station_flags.assert_called_once_with( common.ether_ntoa(mac), self._ap1.ap_id, prohibit_type=SteeringProhibitType.PROHIBIT_LONG) model.update_station_flags.reset_mock() # Case 10b: Steering prohibited - is not prohibited msg = '\x11\x18\x00\x09\xc6\x29\x00\x06\x73\xd6\x06\x03' + mac + '\x00' handler.process_msg(self._ap1_addr, msg) model.update_station_flags.assert_called_once_with( common.ether_ntoa(mac), self._ap1.ap_id, prohibit_type=SteeringProhibitType.PROHIBIT_NONE) model.update_station_flags.reset_mock() # Case 11: Other messages are ignored # Diaglog message msg = '\x11\xa2\x51\x77\x52\x0e\x00\x05\x03\xd9\x08\x00abc' handler.process_msg(self._ap1_addr, msg) self.assert_(not model.update_utilizations.called) self.assert_(not model.update_associated_station_rssi.called) self.assert_(not model.add_associated_station.called) self.assert_(not model.del_associated_station.called) self.assert_(not model.update_overload_status.called)
def test_post_assoc_steer(self): """Verify the parsing of the post-association steer message.""" test_cases = itertools.product([ SteerType.STEER_TYPE_NONE, SteerType.STEER_TYPE_LEGACY, SteerType.STEER_TYPE_BTM_AND_BLACKLIST, SteerType.STEER_TYPE_BTM, SteerType.STEER_TYPE_BTM_AND_BLACKLIST_ACTIVE, SteerType.STEER_TYPE_BTM_ACTIVE, SteerType.STEER_TYPE_PREASSOCIATION, SteerType.STEER_TYPE_BTM_BE, SteerType.STEER_TYPE_BTM_BE_ACTIVE, SteerType.STEER_TYPE_BTM_BLACKLIST_BE, SteerType.STEER_TYPE_BTM_BLACKLIST_BE_ACTIVE, SteerType.STEER_TYPE_LEGACY_BE ], [ SteerReasonType.REASON_USER, SteerReasonType.REASON_ACTIVE_UPGRADE, SteerReasonType.REASON_ACTIVE_DOWNGRADE_RATE, SteerReasonType.REASON_ACTIVE_DOWNGRADE_RSSI, SteerReasonType.REASON_IDLE_UPGRADE, SteerReasonType.REASON_IDLE_DOWNGRADE, SteerReasonType.REASON_ACTIVE_OFFLOAD, SteerReasonType.REASON_IDLE_OFFLOAD, SteerReasonType.REASON_AP_REQUEST, SteerReasonType.REASON_INTERFERENCE_AVOIDANCE, SteerReasonType.REASON_INVALID ]) for test_case in test_cases: # Type of steering. mac = '\x94\x45\x8d\x13\xb7\x86' transaction = '\x10' assoc_ap = '\xff' assoc_channel = '\x0b' assoc_ess = '\x00' ap1 = '\xff' channel1 = '\x0a' ess1 = '\x00' msg = '\x05' + mac + transaction + chr(test_case[0].value) + \ chr(test_case[1].value) + \ assoc_ap + assoc_channel + assoc_ess + '\x01' + ap1 + channel1 + ess1 payload = steerexec.unpack_payload_from_bytes( common.Version.VERSION2, False, msg) self.assertEquals( steerexec.PostAssocSteer._make( (common.ether_ntoa(mac), 0x10, test_case[0], test_case[1], common.BSSInfo(0xFF, 0x0B, 0), 1, [common.BSSInfo(0xFF, 0x0A, 0)])), payload) # Same as above but in big-endian (which makes no difference) payload = steerexec.unpack_payload_from_bytes( common.Version.VERSION2, True, msg) self.assertEquals( steerexec.PostAssocSteer._make( (common.ether_ntoa(mac), 0x10, test_case[0], test_case[1], common.BSSInfo(0xFF, 0x0B, 0), 1, [common.BSSInfo(0xFF, 0x0A, 0)])), payload) # Test 2: Invalid steer type (Version 2) mac = '\x49\xcd\x30\xda\x0c\x4c' msg = '\x05' + mac + transaction + '\x0d' + '\x01' + \ assoc_ap + assoc_channel + assoc_ess + '\x01' + ap1 + channel1 + ess1 self.assertRaises(MessageMalformedError, steerexec.unpack_payload_from_bytes, common.Version.VERSION2, False, msg) # Test 3: Invalid steer reason (Version 2) mac = '\x49\xcd\x30\xda\x0c\x4c' msg = '\x05' + mac + transaction + '\x01' + '\x0d' + \ assoc_ap + assoc_channel + assoc_ess + '\x01' + ap1 + channel1 + ess1 self.assertRaises(MessageMalformedError, steerexec.unpack_payload_from_bytes, common.Version.VERSION2, False, msg) # Test 4: Two candidate BSSes ap2 = '\xff' channel2 = '\x0c' ess2 = '\x00' msg = '\x05' + mac + transaction + chr(test_case[0].value) + \ chr(test_case[1].value) + \ assoc_ap + assoc_channel + assoc_ess + '\x02' + ap1 + channel1 + ess1 + \ ap2 + channel2 + ess2 payload = steerexec.unpack_payload_from_bytes(common.Version.VERSION2, False, msg) self.assertEquals( steerexec.PostAssocSteer._make( (common.ether_ntoa(mac), 0x10, test_case[0], test_case[1], common.BSSInfo(0xFF, 0x0B, 0), 2, [ common.BSSInfo(0xFF, 0x0A, 0), common.BSSInfo(0xFF, 0x0C, 0) ])), payload) # Test 5: Can't be parsed with version 1 self.assertRaises(MessageMalformedError, steerexec.unpack_payload_from_bytes, common.Version.VERSION1, False, msg) # Test 6: Incorrect candidate count raises an error msg = '\x05' + mac + transaction + '\x01' + '\x01' + \ assoc_ap + assoc_channel + assoc_ess + '\x00' + ap1 + channel1 + ess1 + \ ap2 + channel2 + ess2 self.assertRaises(MessageMalformedError, steerexec.unpack_payload_from_bytes, common.Version.VERSION2, False, msg) msg = '\x05' + mac + transaction + '\x01' + '\x01' + \ assoc_ap + assoc_channel + assoc_ess + '\x03' + ap1 + channel1 + ess1 + \ ap2 + channel2 + ess2 self.assertRaises(MessageMalformedError, steerexec.unpack_payload_from_bytes, common.Version.VERSION2, False, msg)
def test_rssi_update(self): """Verify the parsing of the RSSI update message v1.""" # Test 1: RSSI update on 2.4 GHz mac = '\x8a\x25\xf2\x83\x93\x85' msg = '\x01' + mac + '\x00\x17' payload = stadb.unpack_payload_from_bytes( common.Version.VERSION1, False, msg) self.assertEquals(stadb.RSSIUpdate._make( (common.ether_ntoa(mac), BAND_TYPE.BAND_24G, 23)), payload) # Same in big endian payload = stadb.unpack_payload_from_bytes( common.Version.VERSION1, True, msg) self.assertEquals(stadb.RSSIUpdate._make( (common.ether_ntoa(mac), BAND_TYPE.BAND_24G, 23)), payload) # Test 2: RSSI update on 5 GHz mac = '\x32\x10\xbb\xf6\xa5\x35' msg = '\x01' + mac + '\x01\x12' payload = stadb.unpack_payload_from_bytes( common.Version.VERSION1, False, msg) self.assertEquals(stadb.RSSIUpdate._make( (common.ether_ntoa(mac), BAND_TYPE.BAND_5G, 18)), payload) # Same in big endian payload = stadb.unpack_payload_from_bytes( common.Version.VERSION1, True, msg) self.assertEquals(stadb.RSSIUpdate._make( (common.ether_ntoa(mac), BAND_TYPE.BAND_5G, 18)), payload) # Test 3: RSSI update on invalid band is malformed mac = '\xff\x7e\x74\x17\x52\xa9' msg = '\x01' + mac + '\x02\x06' self.assertRaises( MessageMalformedError, stadb.unpack_payload_from_bytes, common.Version.VERSION1, False, msg) # Same in big endian self.assertRaises( MessageMalformedError, stadb.unpack_payload_from_bytes, common.Version.VERSION1, True, msg) # Test 4: RSSI update on invalid band is malformed mac = '\xab\xd6\xd1\xd0\xfd\x25' msg = '\x01' + mac + '\x03\x06' self.assertRaises( MessageMalformedError, stadb.unpack_payload_from_bytes, common.Version.VERSION1, False, msg) # Same in big endian self.assertRaises( MessageMalformedError, stadb.unpack_payload_from_bytes, common.Version.VERSION1, True, msg) """Verify the parsing of the RSSI update message v2.""" # Test 1: RSSI update on channel 1 mac = '\x8a\x25\xf2\x83\x93\x85' msg = '\x02' + mac + '\xff\x01\x00\x17' payload = stadb.unpack_payload_from_bytes( common.Version.VERSION2, False, msg) self.assertEquals(stadb.RSSIUpdate_v2._make( (common.ether_ntoa(mac), common.BSSInfo(0xFF, 1, 0), 23)), payload) # Same in big endian payload = stadb.unpack_payload_from_bytes( common.Version.VERSION2, True, msg) self.assertEquals(stadb.RSSIUpdate_v2._make( (common.ether_ntoa(mac), common.BSSInfo(0xFF, 1, 0), 23)), payload) # Test 2: RSSI update on channel 100 mac = '\x32\x10\xbb\xf6\xa5\x35' msg = '\x02' + mac + '\x00\x24\x01\x12' payload = stadb.unpack_payload_from_bytes( common.Version.VERSION2, False, msg) self.assertEquals(stadb.RSSIUpdate_v2._make( (common.ether_ntoa(mac), common.BSSInfo(0, 36, 1), 18)), payload) # Same in big endian payload = stadb.unpack_payload_from_bytes( common.Version.VERSION2, True, msg) self.assertEquals(stadb.RSSIUpdate_v2._make( (common.ether_ntoa(mac), common.BSSInfo(0, 36, 1), 18)), payload) # Test 3: RSSI update with V2 header and V1 payload is malformed mac = '\x32\x10\xbb\xf6\xa5\x35' msg = '\x02' + mac + '\x01\x12' self.assertRaises( MessageMalformedError, stadb.unpack_payload_from_bytes, common.Version.VERSION2, False, msg) # Same in big endian self.assertRaises( MessageMalformedError, stadb.unpack_payload_from_bytes, common.Version.VERSION2, True, msg)
def test_activity_update(self): """Verify the parsing of the activity update message v1.""" test_cases = itertools.product([BAND_TYPE.BAND_24G, BAND_TYPE.BAND_5G], [True, False]) for test_case in test_cases: # Test with all combinations of band and activity change mac = '\xcd\x92\x1f\xe3\x84\x11' msg = '\x02' + mac + chr(test_case[0].value) + chr(test_case[1]) payload = stadb.unpack_payload_from_bytes( common.Version.VERSION1, False, msg) self.assertEquals(stadb.ActivityUpdate._make( (common.ether_ntoa(mac), test_case[0], test_case[1])), payload) # Same as above but in big-endian (which makes no difference) payload = stadb.unpack_payload_from_bytes( common.Version.VERSION1, True, msg) self.assertEquals(stadb.ActivityUpdate._make( (common.ether_ntoa(mac), test_case[0], test_case[1])), payload) # Test 2: Activity update on a invalid band is malformed mac = '\x00\x66\x9a\x85\x7b\xd9' msg = '\x02' + mac + '\x02\x00' self.assertRaises( MessageMalformedError, stadb.unpack_payload_from_bytes, common.Version.VERSION1, False, msg) # Same in big endian self.assertRaises( MessageMalformedError, stadb.unpack_payload_from_bytes, common.Version.VERSION1, False, msg) # Test 3: Activity update on a bogus band is malformed mac = '\xbb\xb9\x21\xd4\xab\xd4' msg = '\x02' + mac + '\x03\x00' self.assertRaises( MessageMalformedError, stadb.unpack_payload_from_bytes, common.Version.VERSION1, False, msg) # Same in big endian self.assertRaises( MessageMalformedError, stadb.unpack_payload_from_bytes, common.Version.VERSION1, False, msg) """Verify the parsing of the activity update message v2.""" for activity in [True, False]: # Test with all combinations of activity change mac = '\xcd\x92\x1f\xe3\x84\x11' msg = '\x02' + mac + '\xFF\x64\x00' + chr(activity) payload = stadb.unpack_payload_from_bytes( common.Version.VERSION2, False, msg) self.assertEquals(stadb.ActivityUpdate_v2._make( (common.ether_ntoa(mac), common.BSSInfo(0xFF, 100, 0), activity)), payload) # Same as above but in big-endian (which makes no difference) payload = stadb.unpack_payload_from_bytes( common.Version.VERSION2, True, msg) self.assertEquals(stadb.ActivityUpdate_v2._make( (common.ether_ntoa(mac), common.BSSInfo(0xFF, 100, 0), activity)), payload)
def test_association_update(self): """Verify the parsing of the association update message.""" # Test 1: Associated on 2.4 GHz mac = '\xb2\xdd\x69\xa1\xb3\xe3' msg = '\x00' + mac + '\x00\x01\x00' payload = stadb.unpack_payload_from_bytes( common.Version.VERSION1, False, msg) self.assertEquals(stadb.AssociationUpdate._make( (common.ether_ntoa(mac), BAND_TYPE.BAND_24G, True, False)), payload) # Same as above but in big-endian (which makes no difference) payload = stadb.unpack_payload_from_bytes( common.Version.VERSION1, True, msg) self.assertEquals(stadb.AssociationUpdate._make( (common.ether_ntoa(mac), BAND_TYPE.BAND_24G, True, False)), payload) # Test 2: Associated on 5 GHz mac = '\x67\xae\x3b\x86\xc3\x8e' msg = '\x00' + mac + '\x01\x01\x01' payload = stadb.unpack_payload_from_bytes( common.Version.VERSION1, False, msg) self.assertEquals(stadb.AssociationUpdate._make( (common.ether_ntoa(mac), BAND_TYPE.BAND_5G, True, True)), payload) # Same as above but in big endian payload = stadb.unpack_payload_from_bytes( common.Version.VERSION1, True, msg) self.assertEquals(stadb.AssociationUpdate._make( (common.ether_ntoa(mac), BAND_TYPE.BAND_5G, True, True)), payload) # Test 3: Disassociated mac = '\x29\xed\x66\x8b\x16\x77' msg = '\x00' + mac + '\x02\x00\x00' payload = stadb.unpack_payload_from_bytes( common.Version.VERSION1, False, msg) self.assertEquals(stadb.AssociationUpdate._make( (common.ether_ntoa(mac), BAND_TYPE.BAND_INVALID, False, False)), payload) # Same as above but in big endian payload = stadb.unpack_payload_from_bytes( common.Version.VERSION1, True, msg) self.assertEquals(stadb.AssociationUpdate._make( (common.ether_ntoa(mac), BAND_TYPE.BAND_INVALID, False, False)), payload) # Test 3.1: A valid version 1 payload with a version 2 header is malformed self.assertRaises( MessageMalformedError, stadb.unpack_payload_from_bytes, common.Version.VERSION2, False, msg) # Same in big endian self.assertRaises( MessageMalformedError, stadb.unpack_payload_from_bytes, common.Version.VERSION2, True, msg) # Test 4: Association update on a bogus band is malformed mac = '\xfc\x91\x14\xc5\x3c\x7f' msg = '\x00' + mac + '\x03\x00\x01' self.assertRaises( MessageMalformedError, stadb.unpack_payload_from_bytes, common.Version.VERSION1, False, msg) # Same in big endian self.assertRaises( MessageMalformedError, stadb.unpack_payload_from_bytes, common.Version.VERSION1, True, msg) # Repeat above test with a version 2 message # Test 5: Associated on 2.4 GHz mac = '\xb2\xdd\x69\xa1\xb3\xe3' msg = '\x00' + mac + '\xFF\x0b\x00\x01\x01\x00\x01\x00' payload = stadb.unpack_payload_from_bytes( common.Version.VERSION2, False, msg) self.assertEquals(stadb.AssociationUpdate_v2._make( (common.ether_ntoa(mac), common.BSSInfo(0xFF, 11, 0), True, True, False, True, False)), payload) # Same as above but in big-endian (which makes no difference) payload = stadb.unpack_payload_from_bytes( common.Version.VERSION2, True, msg) self.assertEquals(stadb.AssociationUpdate_v2._make( (common.ether_ntoa(mac), common.BSSInfo(0xFF, 11, 0), True, True, False, True, False)), payload) # Test 6: Associated on 5 GHz mac = '\x67\xae\x3b\x86\xc3\x8e' msg = '\x00' + mac + '\xFF\x64\x00\x01\x01\x01\x00\x01' payload = stadb.unpack_payload_from_bytes( common.Version.VERSION2, False, msg) self.assertEquals(stadb.AssociationUpdate_v2._make( (common.ether_ntoa(mac), common.BSSInfo(0xFF, 100, 0), True, True, True, False, True)), payload) # Same as above but in big endian payload = stadb.unpack_payload_from_bytes( common.Version.VERSION2, True, msg) self.assertEquals(stadb.AssociationUpdate_v2._make( (common.ether_ntoa(mac), common.BSSInfo(0xFF, 100, 0), True, True, True, False, True)), payload) # Test 7: Disassociated mac = '\x29\xed\x66\x8b\x16\x77' msg = '\x00' + mac + '\xFF\x64\x00\x00\x00\x00\x00\x00' payload = stadb.unpack_payload_from_bytes( common.Version.VERSION2, False, msg) self.assertEquals(stadb.AssociationUpdate_v2._make( (common.ether_ntoa(mac), common.BSSInfo(0xFF, 100, 0), False, False, False, False, False)), payload) # Same as above but in big endian payload = stadb.unpack_payload_from_bytes( common.Version.VERSION2, True, msg) self.assertEquals(stadb.AssociationUpdate_v2._make( (common.ether_ntoa(mac), common.BSSInfo(0xFF, 100, 0), False, False, False, False, False)), payload)
def test_steer_end(self): """Verify the parsing of the steer end message.""" test_cases = itertools.product([ SteerType.STEER_TYPE_NONE, SteerType.STEER_TYPE_LEGACY, SteerType.STEER_TYPE_BTM_AND_BLACKLIST, SteerType.STEER_TYPE_BTM, SteerType.STEER_TYPE_BTM_AND_BLACKLIST_ACTIVE, SteerType.STEER_TYPE_BTM_ACTIVE, SteerType.STEER_TYPE_PREASSOCIATION, SteerType.STEER_TYPE_BTM_BE, SteerType.STEER_TYPE_BTM_BE_ACTIVE, SteerType.STEER_TYPE_BTM_BLACKLIST_BE, SteerType.STEER_TYPE_BTM_BLACKLIST_BE_ACTIVE, SteerType.STEER_TYPE_LEGACY_BE ], [ SteerEndStatusType.STATUS_SUCCESS, SteerEndStatusType.STATUS_ABORT_AUTH_REJECT, SteerEndStatusType.STATUS_ABORT_LOW_RSSI, SteerEndStatusType.STATUS_ABORT_CHANGE_TARGET, SteerEndStatusType.STATUS_ABORT_USER, SteerEndStatusType.STATUS_BTM_REJECT, SteerEndStatusType.STATUS_BTM_RESPONSE_TIMEOUT, SteerEndStatusType.STATUS_ASSOC_TIMEOUT, SteerEndStatusType.STATUS_CHANNEL_CHANGE, SteerEndStatusType.STATUS_PREPARE_FAIL, SteerEndStatusType.STATUS_UNEXPECTED_BSS ]) # Test 1: Valid steer end messages for test_case in test_cases: # Test all combinations for steer type and status. mac = '\x94\x45\x8d\x13\xb7\x86' transaction = '\x33' msg = '\x01' + mac + transaction + chr(test_case[0].value) + chr( test_case[1].value) payload = steerexec.unpack_payload_from_bytes( common.Version.VERSION2, False, msg) self.assertEquals( steerexec.SteerEnd._make((common.ether_ntoa(mac), 0x33, test_case[0], test_case[1])), payload) # Same as above but in big-endian (which makes no difference) payload = steerexec.unpack_payload_from_bytes( common.Version.VERSION2, True, msg) self.assertEquals( steerexec.SteerEnd._make((common.ether_ntoa(mac), 0x33, test_case[0], test_case[1])), payload) # Test 2: Invalid steer type mac = '\x49\xcd\x30\xda\x0c\x4c' msg = '\x01' + mac + transaction + '\x0d\x00' self.assertRaises(MessageMalformedError, steerexec.unpack_payload_from_bytes, common.Version.VERSION2, False, msg) # Test 3: Invalid status mac = '\x49\xcd\x30\xda\x0c\x4c' msg = '\x01' + mac + transaction + '\x01\x0c' self.assertRaises(MessageMalformedError, steerexec.unpack_payload_from_bytes, common.Version.VERSION2, False, msg)
def test_raw_rssi(self): """Verify the parsing of the RSSI message v1.""" # Test 1: Measurement on 2.4 GHz mac = '\x42\x62\x89\x67\x4d\xb4' msg = '\x01' + mac + '\x00\x16' payload = wlanif.unpack_payload_from_bytes(common.Version.VERSION1, False, msg) self.assertEquals( wlanif.RawRSSI._make( (common.ether_ntoa(mac), BAND_TYPE.BAND_24G, 22)), payload) # Test 2: Similar but in big endian format (which makes no difference) msg = '\x01' + mac + '\x00\x25' payload = wlanif.unpack_payload_from_bytes(common.Version.VERSION1, True, msg) self.assertEquals( wlanif.RawRSSI._make( (common.ether_ntoa(mac), BAND_TYPE.BAND_24G, 37)), payload) # Test 3: RSSI measurement on 5 GHz now mac = '\xec\x40\xe4\xe7\xf5\xa5' msg = '\x01' + mac + '\x01\x50' payload = wlanif.unpack_payload_from_bytes(common.Version.VERSION1, False, msg) self.assertEquals( wlanif.RawRSSI._make( (common.ether_ntoa(mac), BAND_TYPE.BAND_5G, 80)), payload) # Test 4: Same in big endian msg = '\x01' + mac + '\x01\x47' payload = wlanif.unpack_payload_from_bytes(common.Version.VERSION1, True, msg) self.assertEquals( wlanif.RawRSSI._make( (common.ether_ntoa(mac), BAND_TYPE.BAND_5G, 71)), payload) # Test 5: The invalid enumerated band is rejected msg = '\x01' + mac + '\x02\x37' self.assertRaises(MessageMalformedError, wlanif.unpack_payload_from_bytes, common.Version.VERSION1, False, msg) self.assertRaises(MessageMalformedError, wlanif.unpack_payload_from_bytes, common.Version.VERSION1, True, msg) # Test 6: Band that is not even contained within the enum msg = '\x01' + mac + '\x03\x37' self.assertRaises(MessageMalformedError, wlanif.unpack_payload_from_bytes, common.Version.VERSION1, False, msg) self.assertRaises(MessageMalformedError, wlanif.unpack_payload_from_bytes, common.Version.VERSION1, True, msg) """Verify the parsing of the RSSI message v2.""" # Test 1: Measurement on APID = 0xFF, channel = 100, essId = 0 msg = '\x01' + mac + '\xFF\x64\x00\x16' payload = wlanif.unpack_payload_from_bytes(common.Version.VERSION2, False, msg) self.assertEquals( wlanif.RawRSSI_v2._make( (common.ether_ntoa(mac), common.BSSInfo(0xFF, 100, 0), 22)), payload) # Test 2: Similar but in big endian format (which makes no difference) msg = '\x01' + mac + '\xFF\x64\x00\x16' payload = wlanif.unpack_payload_from_bytes(common.Version.VERSION2, True, msg) self.assertEquals( wlanif.RawRSSI_v2._make( (common.ether_ntoa(mac), common.BSSInfo(0xFF, 100, 0), 22)), payload)