Implement removing device from Relay filter list.

This commit is contained in:
Orne Brocaar 2023-07-31 16:00:08 +01:00
parent 050610de55
commit 4359e90613
2 changed files with 140 additions and 14 deletions

View File

@ -1652,12 +1652,12 @@ impl Data {
async fn _update_filter_list(&mut self) -> Result<()> {
trace!("Updating Relay filter list");
// Get the current relay state.
let mut relay = if let Some(r) = &self.device_session.relay {
r.clone()
} else {
internal::Relay::default()
};
if self.device_session.relay.is_none() {
self.device_session.relay = Some(internal::Relay::default());
}
// Get a copy of the current relay state.
let relay = self.device_session.relay.as_ref().unwrap().clone();
// Get devices that must be configured on the relay.
let relay_devices = relay::list_devices(
@ -1669,22 +1669,52 @@ impl Data {
)
.await?;
// We filter out the devices that are no longer configured on the relay.
// This way we can combine the delete + add by just overwriting an old slot.
// Note that index 0 has a special meaning.
// Get DevEUIs of Relay EDs.
let relay_devices_dev_euis: Vec<Vec<u8>> =
relay_devices.iter().map(|d| d.dev_eui.to_vec()).collect();
relay
// Calculate removed slots.
let removed_slots: Vec<u32> = relay
.filters
.retain(|f| f.index == 0 || relay_devices_dev_euis.contains(&f.dev_eui));
.iter()
.filter(|f| f.index != 0 && !relay_devices_dev_euis.contains(&f.dev_eui))
.map(|f| f.index)
.collect();
// Calculate free slots.
// Note that the first slot is used as "catch-all" filter.
let used_slots: Vec<u32> = relay.filters.iter().map(|f| f.index).collect();
let used_slots: Vec<u32> = relay
.filters
.iter()
.filter(|f| f.index == 0 || relay_devices_dev_euis.contains(&f.dev_eui))
.map(|f| f.index)
.collect();
let free_slots: Vec<u32> = (1..15).filter(|x| !used_slots.contains(x)).collect();
// Update device-session.
self.device_session.relay = Some(relay);
// Unset slots of devices that are no longer configured.
if !removed_slots.is_empty() {
let mut commands: Vec<lrwn::MACCommand> = Vec::new();
for slot in removed_slots {
commands.push(lrwn::MACCommand::FilterListReq(
lrwn::FilterListReqPayload {
filter_list_idx: slot as u8,
filter_list_action: lrwn::FilterListAction::NoRule,
filter_list_eui: vec![],
},
));
if commands.len() > 5 {
commands.drain(5..);
}
}
let set = lrwn::MACCommandSet::new(commands);
mac_command::set_pending(&self.device.dev_eui, lrwn::CID::FilterListReq, &set).await?;
self.mac_commands.push(set);
// The deletes needs to be processed before we can add new entries.
return Ok(());
}
// Make sure the first item contains the "catch-all" filter.
// This is needed to make sure that only the rest of the filter items are allowed to join
@ -3230,6 +3260,59 @@ mod test {
..Default::default()
},
},
Test {
name: "remove filter".into(),
device_session: internal::DeviceSession {
relay: Some(internal::Relay {
filters: vec![
internal::RelayFilter {
index: 0,
action: 2,
provisioned: true,
..Default::default()
},
internal::RelayFilter {
index: 1,
action: 1,
dev_eui: vec![2, 2, 2, 2, 2, 2, 2, 0],
join_eui: vec![2, 2, 2, 2, 2, 2, 2, 1],
provisioned: true,
},
],
..Default::default()
}),
..Default::default()
},
relay_devices: vec![],
expected_mac_commands: vec![lrwn::MACCommandSet::new(vec![
lrwn::MACCommand::FilterListReq(lrwn::FilterListReqPayload {
filter_list_idx: 1,
filter_list_action: lrwn::FilterListAction::NoRule,
filter_list_eui: vec![],
}),
])],
expected_device_session: internal::DeviceSession {
relay: Some(internal::Relay {
filters: vec![
internal::RelayFilter {
index: 0,
action: 2,
provisioned: true,
..Default::default()
},
internal::RelayFilter {
index: 1,
action: 1,
dev_eui: vec![2, 2, 2, 2, 2, 2, 2, 0],
join_eui: vec![2, 2, 2, 2, 2, 2, 2, 1],
provisioned: true,
},
],
..Default::default()
}),
..Default::default()
},
},
];
let _guard = test::prepare().await;

View File

@ -44,6 +44,13 @@ pub fn handle(
f.provisioned = true;
}
}
// If the action was NoRule, we remove the filter from the relay filters.
if req_pl.filter_list_action == lrwn::FilterListAction::NoRule {
relay
.filters
.retain(|f| f.index != req_pl.filter_list_idx as u32);
}
}
} else {
error!(
@ -168,6 +175,42 @@ mod test {
},
expected_error: None,
},
Test {
name: "acked removing filter".into(),
device_session: internal::DeviceSession {
relay: Some(internal::Relay {
filters: vec![internal::RelayFilter {
index: 1,
provisioned: true,
..Default::default()
}],
..Default::default()
}),
..Default::default()
},
filter_list_req: Some(lrwn::MACCommandSet::new(vec![
lrwn::MACCommand::FilterListReq(lrwn::FilterListReqPayload {
filter_list_idx: 1,
filter_list_action: lrwn::FilterListAction::NoRule,
filter_list_eui: vec![],
}),
])),
filter_list_ans: lrwn::MACCommandSet::new(vec![lrwn::MACCommand::FilterListAns(
lrwn::FilterListAnsPayload {
filter_list_action_ack: true,
filter_list_len_ack: true,
combined_rules_ack: true,
},
)]),
expected_device_session: internal::DeviceSession {
relay: Some(internal::Relay {
filters: vec![],
..Default::default()
}),
..Default::default()
},
expected_error: None,
},
];
for tst in &tests {