Skip to content

Commit

Permalink
add max_copies to skf filter (#969)
Browse files Browse the repository at this point in the history
  • Loading branch information
michaeldjeffrey authored Jun 13, 2023
1 parent 19611d1 commit bba7f73
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 56 deletions.
2 changes: 1 addition & 1 deletion rebar.lock
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@
{<<"hackney">>,{pkg,<<"hackney">>,<<"1.18.1">>},0},
{<<"helium_proto">>,
{git,"https://github.com/helium/proto.git",
{ref,"3061e06dff4f4a643dd9e2bf98bc24b462071de3"}},
{ref,"91cd0c3953e8e233a86e6c67120a6df9b9b1cb40"}},
0},
{<<"hpack">>,
{git,"https://github.com/novalabsxyz/hpack.git",
Expand Down
7 changes: 5 additions & 2 deletions src/apis/router_console_ws_worker.erl
Original file line number Diff line number Diff line change
Expand Up @@ -404,13 +404,16 @@ update_device_record(DB, CF, DeviceID) ->
DevAddr
),
NwkSKey = router_device:nwk_s_key(Device),
MultiBuy = maps:get(multi_buy, router_device:metadata(Device), 0),
case IsActive of
true ->
ok = router_ics_skf_worker:update([{add, DevAddrInt, NwkSKey}]),
ok = router_ics_skf_worker:update([{add, DevAddrInt, NwkSKey, MultiBuy}]),
catch router_ics_eui_worker:add([DeviceID]),
lager:debug("device un-paused, sent SKF and EUI add", []);
false ->
ok = router_ics_skf_worker:update([{remove, DevAddrInt, NwkSKey}]),
ok = router_ics_skf_worker:update([
{remove, DevAddrInt, NwkSKey, MultiBuy}
]),
catch router_ics_eui_worker:remove([DeviceID]),
lager:debug("device paused, sent SKF and EUI remove", [])
end
Expand Down
65 changes: 26 additions & 39 deletions src/device/router_device_worker.erl
Original file line number Diff line number Diff line change
Expand Up @@ -422,11 +422,15 @@ handle_cast(
NwkSKey = router_device:nwk_s_key(Device1),
case IsActive of
true ->
ok = router_ics_skf_worker:update([{add, DevAddrInt, NwkSKey}]),
ok = router_ics_skf_worker:update([
{add, DevAddrInt, NwkSKey, MultiBuyValue}
]),
catch router_ics_eui_worker:add([DeviceID]),
lager:debug("device un-paused, sent SKF and EUI add", []);
false ->
ok = router_ics_skf_worker:update([{remove, DevAddrInt, NwkSKey}]),
ok = router_ics_skf_worker:update([
{remove, DevAddrInt, NwkSKey, MultiBuyValue}
]),
catch router_ics_eui_worker:remove([DeviceID]),
lager:debug("device paused, sent SKF and EUI remove", [])
end
Expand Down Expand Up @@ -760,7 +764,8 @@ handle_cast(
false ->
ok;
true ->
ToAdd = [{add, DevAddr0, UsedNwkSKey}],
MultiBuy = maps:get(multi_buy, router_device:metadata(D1), 0),
ToAdd = [{add, DevAddr0, UsedNwkSKey, MultiBuy}],

DevAddrToInt = fun(D) ->
<<Int:32/integer-unsigned-big>> = lorawan_utils:reverse(D),
Expand All @@ -769,12 +774,12 @@ handle_cast(

%% We have to usort just in case DevAddr assigned is the same
ToRemove0 = lists:usort([
{remove, DevAddrToInt(DevAddr), NwkSKey}
{remove, DevAddrToInt(DevAddr), NwkSKey, MultiBuy}
|| {NwkSKey, _} <- Keys, DevAddr <- router_device:devaddrs(Device0)
]),

%% Making sure that the pair that was added is not getting removed (just in case DevAddr assigned is the same)
ToRemove1 = ToRemove0 -- [{remove, DevAddr0, UsedNwkSKey}],
ToRemove1 = ToRemove0 -- [{remove, DevAddr0, UsedNwkSKey, MultiBuy}],
ok = router_ics_skf_worker:update(ToAdd ++ ToRemove1),
lager:debug("sending update skf ~p", [ToAdd ++ ToRemove1])
end,
Expand Down Expand Up @@ -1363,8 +1368,9 @@ handle_join(
{region, Region}
],
Device1 = router_device:update(DeviceUpdates, Device0),
MultiBuy = maps:get(multi_buy, router_device:metadata(Device1), 0),

ok = handle_join_skf(NewKeys, NewDevaddrs),
ok = handle_join_skf(NewKeys, NewDevaddrs, MultiBuy),

lager:debug(
"Join DevEUI ~s with AppEUI ~s tried to join with nonce ~p region ~p via ~s",
Expand All @@ -1388,25 +1394,32 @@ handle_join(
%% attempts, we won't have the information to remove all the unused keys.
-spec handle_join_skf(
NewKeys :: list({NwkSKey :: binary(), AppSKey :: binary()}),
NewDevAddrs :: list(DevAddr :: binary())
NewDevAddrs :: list(DevAddr :: binary()),
MaxCopies :: non_neg_integer()
) -> ok.
handle_join_skf([{NwkSKey, _} | _] = NewKeys, [NewDevAddr | _] = NewDevAddrs) ->
handle_join_skf([{NwkSKey, _} | _] = NewKeys, [NewDevAddr | _] = NewDevAddrs, MaxCopies) ->
DevAddrToInt = fun(D) ->
<<Int:32/integer-unsigned-big>> = lorawan_utils:reverse(D),
Int
end,

%% remove evicted keys from the config service for every devaddr.
EvictedKeys = router_device:credentials_to_evict(NewKeys),
ToRemoveKeys = [{remove, DevAddrToInt(D), NSK} || {NSK, _} <- EvictedKeys, D <- NewDevAddrs],
ToRemoveKeys = [
{remove, DevAddrToInt(D), NSK, MaxCopies}
|| {NSK, _} <- EvictedKeys, D <- NewDevAddrs
],

%% remove evicted devaddrs from the config service for every nwkskey.
EvictedAddrs = router_device:credentials_to_evict(NewDevAddrs),
ToRemoveAddrs = [{remove, DevAddrToInt(D), NSK} || {NSK, _} <- NewKeys, D <- EvictedAddrs],
ToRemoveAddrs = [
{remove, DevAddrToInt(D), NSK, MaxCopies}
|| {NSK, _} <- NewKeys, D <- EvictedAddrs
],

%% add the new devaddr, nskwkey.
<<DevAddrInt:32/integer-unsigned-big>> = lorawan_utils:reverse(NewDevAddr),
Updates = lists:usort([{add, DevAddrInt, NwkSKey}] ++ ToRemoveKeys ++ ToRemoveAddrs),
Updates = lists:usort([{add, DevAddrInt, NwkSKey, MaxCopies}] ++ ToRemoveKeys ++ ToRemoveAddrs),
ok = router_ics_skf_worker:update(Updates),

lager:debug("sending update skf for join ~p ~p", [Updates]),
Expand Down Expand Up @@ -1760,34 +1773,8 @@ validate_frame_(PacketFCnt, Packet, PubKeyBin, HotspotRegion, Device0, OfferCach
PHash :: binary(),
OfferCache :: map()
) -> {ok, non_neg_integer(), non_neg_integer()} | {error, any()}.
maybe_charge(Device, PayloadSize, PubKeyBin, PHash, OfferCache) ->
case maps:get({PubKeyBin, PHash}, OfferCache, undefined) of
undefined ->
case charge_when_no_offer() of
false ->
Metadata = router_device:metadata(Device),
{Balance, Nonce} =
case maps:get(organization_id, Metadata, undefined) of
undefined ->
{0, 0};
OrgID ->
router_console_dc_tracker:current_balance(OrgID)
end,
{ok, Balance, Nonce};
true ->
router_console_dc_tracker:charge(Device, PayloadSize)
end;
_ ->
router_console_dc_tracker:charge(Device, PayloadSize)
end.

-spec charge_when_no_offer() -> boolean().
charge_when_no_offer() ->
case application:get_env(router, charge_when_no_offer, true) of
"true" -> true;
true -> true;
_ -> false
end.
maybe_charge(Device, PayloadSize, _PubKeyBin, _PHash, _OfferCache) ->
router_console_dc_tracker:charge(Device, PayloadSize).

%%%-------------------------------------------------------------------
%% @doc
Expand Down
36 changes: 28 additions & 8 deletions src/grpc/router_ics_skf_worker.erl
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,14 @@ startup_reconcile() ->
%% Worker API
%% ------------------------------------------------------------------

-spec update(Updates :: list({add | remove, non_neg_integer(), binary()})) ->
-spec update(
Updates :: list({
add | remove,
DevaddrInt :: non_neg_integer(),
NwkSKey :: binary(),
MultiBuy :: non_neg_integer()
})
) ->
ok.
update([]) ->
ok;
Expand Down Expand Up @@ -202,23 +209,33 @@ diff_skf_to_updates(#{remote := _, local := _} = Diff) ->
(skfs()) -> skf_updates().
skf_to_add_update(SKFs) when erlang:is_list(SKFs) ->
lists:map(fun skf_to_add_update/1, SKFs);
skf_to_add_update(#iot_config_skf_v1_pb{devaddr = Devaddr, session_key = SessionKey}) ->
skf_to_add_update(#iot_config_skf_v1_pb{
devaddr = Devaddr,
session_key = SessionKey,
max_copies = MaxCopies
}) ->
#iot_config_route_skf_update_v1_pb{
action = add,
devaddr = Devaddr,
session_key = SessionKey
session_key = SessionKey,
max_copies = MaxCopies
}.

-spec skf_to_remove_update
(skf()) -> skf_update();
(skfs()) -> skf_updates().
skf_to_remove_update(SKFs) when erlang:is_list(SKFs) ->
lists:map(fun skf_to_remove_update/1, SKFs);
skf_to_remove_update(#iot_config_skf_v1_pb{devaddr = Devaddr, session_key = SessionKey}) ->
skf_to_remove_update(#iot_config_skf_v1_pb{
devaddr = Devaddr,
session_key = SessionKey,
max_copies = MaxCopies
}) ->
#iot_config_route_skf_update_v1_pb{
action = remove,
devaddr = Devaddr,
session_key = SessionKey
session_key = SessionKey,
max_copies = MaxCopies
}.

%% ------------------------------------------------------------------
Expand Down Expand Up @@ -271,11 +288,12 @@ handle_cast(
fun
(#iot_config_route_skf_update_v1_pb{} = Update) ->
Update;
({Action, Devaddr, Key}) ->
({Action, Devaddr, Key, MaxCopies}) ->
#iot_config_route_skf_update_v1_pb{
action = Action,
devaddr = Devaddr,
session_key = binary:encode_hex(Key)
session_key = binary:encode_hex(Key),
max_copies = MaxCopies
}
end,
Updates0
Expand Down Expand Up @@ -384,6 +402,7 @@ get_local_skfs(RouteID) ->
lists:usort(
lists:filtermap(
fun(Device) ->
MultiBuy = maps:get(multi_buy, router_device:metadata(Device), 0),
case
{
router_device:is_active(Device),
Expand All @@ -403,7 +422,8 @@ get_local_skfs(RouteID) ->
{true, #iot_config_skf_v1_pb{
route_id = RouteID,
devaddr = DevAddr,
session_key = erlang:binary_to_list(binary:encode_hex(SessionKey))
session_key = erlang:binary_to_list(binary:encode_hex(SessionKey)),
max_copies = MultiBuy
}}
end
end,
Expand Down
11 changes: 7 additions & 4 deletions test/router_ics_skf_worker_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,8 @@ main_test(Config) ->
ok = router_test_ics_route_service:add_skf(#iot_config_skf_v1_pb{
route_id = ?ROUTE_ID,
devaddr = 0,
session_key = []
session_key = [],
max_copies = 42
}),

%% Trigger a reconcile
Expand Down Expand Up @@ -243,18 +244,20 @@ device_to_skf(RouteID, Device) ->
#iot_config_skf_v1_pb{
route_id = RouteID,
devaddr = binary:decode_unsigned(router_device:devaddr(Device), little),
session_key = erlang:binary_to_list(binary:encode_hex(router_device:nwk_s_key(Device)))
session_key = erlang:binary_to_list(binary:encode_hex(router_device:nwk_s_key(Device))),
max_copies = maps:get(multi_buy, router_device:metadata(Device), 999)
}.

create_n_devices(N) ->
lists:map(
fun(_X) ->
fun(Idx) ->
ID = router_utils:uuid_v4(),
{ok, Devaddr} = router_device_devaddr:allocate(no_device, undefined),
router_device:update(
[
{devaddrs, [Devaddr]},
{keys, [{crypto:strong_rand_bytes(16), crypto:strong_rand_bytes(16)}]}
{keys, [{crypto:strong_rand_bytes(16), crypto:strong_rand_bytes(16)}]},
{metadata, #{multi_buy => Idx}}
],
router_device:new(ID)
)
Expand Down
6 changes: 4 additions & 2 deletions test/router_test_ics_route_service.erl
Original file line number Diff line number Diff line change
Expand Up @@ -211,13 +211,15 @@ update_skfs(Ctx, Req) ->
#iot_config_route_skf_update_v1_pb{
action = Action,
devaddr = Devaddr,
session_key = SessionKey
session_key = SessionKey,
max_copies = MaxCopies
}
) ->
SKF = #iot_config_skf_v1_pb{
devaddr = Devaddr,
session_key = SessionKey,
route_id = RouteID
route_id = RouteID,
max_copies = MaxCopies
},
case Action of
add -> add_skf(SKF);
Expand Down

0 comments on commit bba7f73

Please sign in to comment.