diff --git a/pkg/networkserver/grpc_deviceregistry.go b/pkg/networkserver/grpc_deviceregistry.go index c0e84fcfc9c..188e83b2431 100644 --- a/pkg/networkserver/grpc_deviceregistry.go +++ b/pkg/networkserver/grpc_deviceregistry.go @@ -2682,102 +2682,110 @@ func (ns *NetworkServer) Set(ctx context.Context, req *ttnpb.SetEndDeviceRequest } var evt events.Event - dev, ctx, err := ns.devices.SetByID(ctx, st.Device.Ids.ApplicationIds, st.Device.Ids.DeviceId, st.GetFields(), st.SetFunc(func(ctx context.Context, stored *ttnpb.EndDevice) error { - if hasSession { - macVersion := stored.GetMacState().GetLorawanVersion() - if stored.GetMacState() == nil && !st.HasSetField("mac_state") { - fps, err := ns.FrequencyPlansStore(ctx) - if err != nil { + dev, ctx, err := ns.devices.SetByID( + ctx, st.Device.Ids.ApplicationIds, st.Device.Ids.DeviceId, ttnpb.EndDeviceFieldPathsTopLevel, st.SetFunc(func(ctx context.Context, stored *ttnpb.EndDevice) error { + if nonZeroFields := ttnpb.NonZeroFields(stored, st.GetFields()...); len(nonZeroFields) > 0 { + newStored := &ttnpb.EndDevice{} + if err := newStored.SetFields(stored, nonZeroFields...); err != nil { return err } - macState, err := mac.NewState(st.Device, fps, ns.defaultMACSettings) - if err != nil { - return err - } - if macSets := ttnpb.FieldsWithoutPrefix("mac_state", st.SetFields()...); len(macSets) != 0 { - if err := macState.SetFields(st.Device.MacState, macSets...); err != nil { + stored = newStored + } + if hasSession { + macVersion := stored.GetMacState().GetLorawanVersion() + if stored.GetMacState() == nil && !st.HasSetField("mac_state") { + fps, err := ns.FrequencyPlansStore(ctx) + if err != nil { + return err + } + macState, err := mac.NewState(st.Device, fps, ns.defaultMACSettings) + if err != nil { return err } + if macSets := ttnpb.FieldsWithoutPrefix("mac_state", st.SetFields()...); len(macSets) != 0 { + if err := macState.SetFields(st.Device.MacState, macSets...); err != nil { + return err + } + } + st.Device.MacState = macState + st.AddSetFields( + "mac_state", + ) + macVersion = macState.LorawanVersion + } else if st.HasSetField("mac_state.lorawan_version") { + macVersion = st.Device.MacState.LorawanVersion + } + + if st.HasSetField("session.keys.f_nwk_s_int_key.key") && !macspec.UseNwkKey(macVersion) { + st.Device.Session.Keys.NwkSEncKey = st.Device.Session.Keys.FNwkSIntKey + st.Device.Session.Keys.SNwkSIntKey = st.Device.Session.Keys.FNwkSIntKey + st.AddSetFields( + "session.keys.nwk_s_enc_key.encrypted_key", + "session.keys.nwk_s_enc_key.kek_label", + "session.keys.nwk_s_enc_key.key", + "session.keys.s_nwk_s_int_key.encrypted_key", + "session.keys.s_nwk_s_int_key.kek_label", + "session.keys.s_nwk_s_int_key.key", + ) + } + if st.HasSetField("session.started_at") && st.Device.GetSession().GetStartedAt() == nil || + st.HasSetField("session.session_key_id") && !bytes.Equal(st.Device.GetSession().GetKeys().GetSessionKeyId(), stored.GetSession().GetKeys().GetSessionKeyId()) || + stored.GetSession().GetStartedAt() == nil { + st.Device.Session.StartedAt = timestamppb.New(time.Now()) // NOTE: This is not equivalent to timestamppb.Now(). + st.AddSetFields( + "session.started_at", + ) } - st.Device.MacState = macState - st.AddSetFields( - "mac_state", - ) - macVersion = macState.LorawanVersion - } else if st.HasSetField("mac_state.lorawan_version") { - macVersion = st.Device.MacState.LorawanVersion - } - - if st.HasSetField("session.keys.f_nwk_s_int_key.key") && !macspec.UseNwkKey(macVersion) { - st.Device.Session.Keys.NwkSEncKey = st.Device.Session.Keys.FNwkSIntKey - st.Device.Session.Keys.SNwkSIntKey = st.Device.Session.Keys.FNwkSIntKey - st.AddSetFields( - "session.keys.nwk_s_enc_key.encrypted_key", - "session.keys.nwk_s_enc_key.kek_label", - "session.keys.nwk_s_enc_key.key", - "session.keys.s_nwk_s_int_key.encrypted_key", - "session.keys.s_nwk_s_int_key.kek_label", - "session.keys.s_nwk_s_int_key.key", - ) - } - if st.HasSetField("session.started_at") && st.Device.GetSession().GetStartedAt() == nil || - st.HasSetField("session.session_key_id") && !bytes.Equal(st.Device.GetSession().GetKeys().GetSessionKeyId(), stored.GetSession().GetKeys().GetSessionKeyId()) || - stored.GetSession().GetStartedAt() == nil { - st.Device.Session.StartedAt = timestamppb.New(time.Now()) // NOTE: This is not equivalent to timestamppb.Now(). - st.AddSetFields( - "session.started_at", - ) } - } - if hasPendingSession { - var macVersion ttnpb.MACVersion - if st.HasSetField("pending_mac_state.lorawan_version") { - macVersion = st.Device.GetPendingMacState().GetLorawanVersion() - } else { - macVersion = stored.GetPendingMacState().GetLorawanVersion() - } - - useNwkKey := macspec.UseNwkKey(macVersion) - if st.HasSetField("pending_session.keys.f_nwk_s_int_key.key") && !useNwkKey { - st.Device.PendingSession.Keys.NwkSEncKey = st.Device.PendingSession.Keys.FNwkSIntKey - st.Device.PendingSession.Keys.SNwkSIntKey = st.Device.PendingSession.Keys.FNwkSIntKey - st.AddSetFields( - "pending_session.keys.nwk_s_enc_key.encrypted_key", - "pending_session.keys.nwk_s_enc_key.kek_label", - "pending_session.keys.nwk_s_enc_key.key", - "pending_session.keys.s_nwk_s_int_key.encrypted_key", - "pending_session.keys.s_nwk_s_int_key.kek_label", - "pending_session.keys.s_nwk_s_int_key.key", - ) - } - if st.HasSetField("pending_mac_state.queued_join_accept.keys.f_nwk_s_int_key.key") && hasQueuedJoinAccept && !useNwkKey { - st.Device.PendingMacState.QueuedJoinAccept.Keys.NwkSEncKey = st.Device.PendingMacState.QueuedJoinAccept.Keys.FNwkSIntKey - st.Device.PendingMacState.QueuedJoinAccept.Keys.SNwkSIntKey = st.Device.PendingMacState.QueuedJoinAccept.Keys.FNwkSIntKey - st.AddSetFields( - "pending_mac_state.queued_join_accept.keys.nwk_s_enc_key.encrypted_key", - "pending_mac_state.queued_join_accept.keys.nwk_s_enc_key.kek_label", - "pending_mac_state.queued_join_accept.keys.nwk_s_enc_key.key", - "pending_mac_state.queued_join_accept.keys.s_nwk_s_int_key.encrypted_key", - "pending_mac_state.queued_join_accept.keys.s_nwk_s_int_key.kek_label", - "pending_mac_state.queued_join_accept.keys.s_nwk_s_int_key.key", - ) + if hasPendingSession { + var macVersion ttnpb.MACVersion + if st.HasSetField("pending_mac_state.lorawan_version") { + macVersion = st.Device.GetPendingMacState().GetLorawanVersion() + } else { + macVersion = stored.GetPendingMacState().GetLorawanVersion() + } + + useNwkKey := macspec.UseNwkKey(macVersion) + if st.HasSetField("pending_session.keys.f_nwk_s_int_key.key") && !useNwkKey { + st.Device.PendingSession.Keys.NwkSEncKey = st.Device.PendingSession.Keys.FNwkSIntKey + st.Device.PendingSession.Keys.SNwkSIntKey = st.Device.PendingSession.Keys.FNwkSIntKey + st.AddSetFields( + "pending_session.keys.nwk_s_enc_key.encrypted_key", + "pending_session.keys.nwk_s_enc_key.kek_label", + "pending_session.keys.nwk_s_enc_key.key", + "pending_session.keys.s_nwk_s_int_key.encrypted_key", + "pending_session.keys.s_nwk_s_int_key.kek_label", + "pending_session.keys.s_nwk_s_int_key.key", + ) + } + if st.HasSetField("pending_mac_state.queued_join_accept.keys.f_nwk_s_int_key.key") && hasQueuedJoinAccept && !useNwkKey { + st.Device.PendingMacState.QueuedJoinAccept.Keys.NwkSEncKey = st.Device.PendingMacState.QueuedJoinAccept.Keys.FNwkSIntKey + st.Device.PendingMacState.QueuedJoinAccept.Keys.SNwkSIntKey = st.Device.PendingMacState.QueuedJoinAccept.Keys.FNwkSIntKey + st.AddSetFields( + "pending_mac_state.queued_join_accept.keys.nwk_s_enc_key.encrypted_key", + "pending_mac_state.queued_join_accept.keys.nwk_s_enc_key.kek_label", + "pending_mac_state.queued_join_accept.keys.nwk_s_enc_key.key", + "pending_mac_state.queued_join_accept.keys.s_nwk_s_int_key.encrypted_key", + "pending_mac_state.queued_join_accept.keys.s_nwk_s_int_key.kek_label", + "pending_mac_state.queued_join_accept.keys.s_nwk_s_int_key.key", + ) + } } - } - if stored == nil { - evt = evtCreateEndDevice.NewWithIdentifiersAndData(ctx, st.Device.Ids, nil) - return nil - } + if stored == nil { + evt = evtCreateEndDevice.NewWithIdentifiersAndData(ctx, st.Device.Ids, nil) + return nil + } - evt = evtUpdateEndDevice.NewWithIdentifiersAndData(ctx, st.Device.Ids, req.FieldMask.GetPaths()) - if st.HasSetField("multicast") && st.Device.Multicast != stored.Multicast { - return newInvalidFieldValueError("multicast") - } - if st.HasSetField("supports_join") && st.Device.SupportsJoin != stored.SupportsJoin { - return newInvalidFieldValueError("supports_join") - } - return nil - })) + evt = evtUpdateEndDevice.NewWithIdentifiersAndData(ctx, st.Device.Ids, req.FieldMask.GetPaths()) + if st.HasSetField("multicast") && st.Device.Multicast != stored.Multicast { + return newInvalidFieldValueError("multicast") + } + if st.HasSetField("supports_join") && st.Device.SupportsJoin != stored.SupportsJoin { + return newInvalidFieldValueError("supports_join") + } + return nil + })) if err != nil { logRegistryRPCError(ctx, err, "Failed to set device in registry") return nil, err