108a70aa5SVernon Mauery /**
208a70aa5SVernon Mauery  * Copyright © 2018 Intel Corporation
308a70aa5SVernon Mauery  *
408a70aa5SVernon Mauery  * Licensed under the Apache License, Version 2.0 (the "License");
508a70aa5SVernon Mauery  * you may not use this file except in compliance with the License.
608a70aa5SVernon Mauery  * You may obtain a copy of the License at
708a70aa5SVernon Mauery  *
808a70aa5SVernon Mauery  *     http://www.apache.org/licenses/LICENSE-2.0
908a70aa5SVernon Mauery  *
1008a70aa5SVernon Mauery  * Unless required by applicable law or agreed to in writing, software
1108a70aa5SVernon Mauery  * distributed under the License is distributed on an "AS IS" BASIS,
1208a70aa5SVernon Mauery  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1308a70aa5SVernon Mauery  * See the License for the specific language governing permissions and
1408a70aa5SVernon Mauery  * limitations under the License.
1508a70aa5SVernon Mauery  */
1608a70aa5SVernon Mauery #pragma once
1708a70aa5SVernon Mauery #include <algorithm>
1808a70aa5SVernon Mauery #include <boost/callable_traits.hpp>
1908a70aa5SVernon Mauery #include <cstdint>
20e08fbffcSVernon Mauery #include <ipmid/api-types.hpp>
2108a70aa5SVernon Mauery #include <ipmid/message.hpp>
2208a70aa5SVernon Mauery #include <memory>
2308a70aa5SVernon Mauery #include <tuple>
2408a70aa5SVernon Mauery #include <utility>
2508a70aa5SVernon Mauery 
2608a70aa5SVernon Mauery namespace ipmi
2708a70aa5SVernon Mauery {
2808a70aa5SVernon Mauery 
2908a70aa5SVernon Mauery using FilterFunction = ipmi::Cc(ipmi::message::Request::ptr);
3008a70aa5SVernon Mauery 
3108a70aa5SVernon Mauery /**
3208a70aa5SVernon Mauery  * @brief Filter base class for dealing with IPMI request/response
3308a70aa5SVernon Mauery  *
3408a70aa5SVernon Mauery  * The subclasses are all templated so they can provide access to any type of
3508a70aa5SVernon Mauery  * command callback functions.
3608a70aa5SVernon Mauery  */
3708a70aa5SVernon Mauery class FilterBase
3808a70aa5SVernon Mauery {
3908a70aa5SVernon Mauery   public:
4008a70aa5SVernon Mauery     using ptr = std::shared_ptr<FilterBase>;
4108a70aa5SVernon Mauery 
42*7d7a6858SPatrick Williams     virtual ~FilterBase() = default;
43*7d7a6858SPatrick Williams 
4408a70aa5SVernon Mauery     virtual ipmi::Cc call(message::Request::ptr request) = 0;
4508a70aa5SVernon Mauery };
4608a70aa5SVernon Mauery 
4708a70aa5SVernon Mauery /**
4808a70aa5SVernon Mauery  * @brief filter concrete class
4908a70aa5SVernon Mauery  *
5008a70aa5SVernon Mauery  * This is the base template that ipmi filters will resolve into. This is
5108a70aa5SVernon Mauery  * essentially just a wrapper to hold the filter callback so it can be stored in
5208a70aa5SVernon Mauery  * the filter list.
5308a70aa5SVernon Mauery  *
5408a70aa5SVernon Mauery  * Filters are called with a ipmi::message::Request shared_ptr on all IPMI
5508a70aa5SVernon Mauery  * commands in priority order and each filter has the opportunity to reject the
5608a70aa5SVernon Mauery  * command (by returning an IPMI error competion code.) If all the filters
5708a70aa5SVernon Mauery  * return success, the actual IPMI command will be executed. Filters can reject
5808a70aa5SVernon Mauery  * the command for any reason, based on system state, the context, the command
5908a70aa5SVernon Mauery  * payload, etc.
6008a70aa5SVernon Mauery  */
6108a70aa5SVernon Mauery template <typename Filter>
6208a70aa5SVernon Mauery class IpmiFilter : public FilterBase
6308a70aa5SVernon Mauery {
6408a70aa5SVernon Mauery   public:
6508a70aa5SVernon Mauery     IpmiFilter(Filter&& filter) : filter_(std::move(filter))
6608a70aa5SVernon Mauery     {
6708a70aa5SVernon Mauery     }
6808a70aa5SVernon Mauery 
6908a70aa5SVernon Mauery     ipmi::Cc call(message::Request::ptr request) override
7008a70aa5SVernon Mauery     {
7108a70aa5SVernon Mauery         return filter_(request);
7208a70aa5SVernon Mauery     }
7308a70aa5SVernon Mauery 
7408a70aa5SVernon Mauery   private:
7508a70aa5SVernon Mauery     Filter filter_;
7608a70aa5SVernon Mauery };
7708a70aa5SVernon Mauery 
7808a70aa5SVernon Mauery /**
7908a70aa5SVernon Mauery  * @brief helper function to construct a filter object
8008a70aa5SVernon Mauery  *
8108a70aa5SVernon Mauery  * This is called internally by the ipmi::registerFilter function.
8208a70aa5SVernon Mauery  */
8308a70aa5SVernon Mauery template <typename Filter>
8408a70aa5SVernon Mauery static inline auto makeFilter(Filter&& filter)
8508a70aa5SVernon Mauery {
8608a70aa5SVernon Mauery     FilterBase::ptr ptr(new IpmiFilter<Filter>(std::forward<Filter>(filter)));
8708a70aa5SVernon Mauery     return ptr;
8808a70aa5SVernon Mauery }
8908a70aa5SVernon Mauery template <typename Filter>
9008a70aa5SVernon Mauery static inline auto makeFilter(const Filter& filter)
9108a70aa5SVernon Mauery {
9208a70aa5SVernon Mauery     Filter lFilter = filter;
9308a70aa5SVernon Mauery     return makeFilter(std::forward<Filter>(lFilter));
9408a70aa5SVernon Mauery }
9508a70aa5SVernon Mauery 
96e08fbffcSVernon Mauery namespace impl
97e08fbffcSVernon Mauery {
98e08fbffcSVernon Mauery 
99e08fbffcSVernon Mauery // IPMI command filter registration implementation
100e08fbffcSVernon Mauery void registerFilter(int prio, ::ipmi::FilterBase::ptr filter);
101e08fbffcSVernon Mauery 
102e08fbffcSVernon Mauery } // namespace impl
103e08fbffcSVernon Mauery 
104e08fbffcSVernon Mauery /**
105e08fbffcSVernon Mauery  * @brief IPMI command filter registration function
106e08fbffcSVernon Mauery  *
107e08fbffcSVernon Mauery  * This function should be used to register IPMI command filter functions.
108e08fbffcSVernon Mauery  * This function just passes the callback to makeFilter, which creates a
109e08fbffcSVernon Mauery  * wrapper functor object that ultimately calls the callback.
110e08fbffcSVernon Mauery  *
111e08fbffcSVernon Mauery  * Filters are called with a ipmi::message::Request shared_ptr on all IPMI
112e08fbffcSVernon Mauery  * commands in priority order and each filter has the opportunity to reject the
113e08fbffcSVernon Mauery  * command (by returning an IPMI error competion code.) If all the filters
114e08fbffcSVernon Mauery  * return success, the actual IPMI command will be executed. Filters can reject
115e08fbffcSVernon Mauery  * the command for any reason, based on system state, the context, the command
116e08fbffcSVernon Mauery  * payload, etc.
117e08fbffcSVernon Mauery  *
118e08fbffcSVernon Mauery  * @param prio - priority at which to register; see api.hpp
119e08fbffcSVernon Mauery  * @param filter - the callback function that will handle this request
120e08fbffcSVernon Mauery  *
121e08fbffcSVernon Mauery  * @return bool - success of registering the handler
122e08fbffcSVernon Mauery  */
123e08fbffcSVernon Mauery template <typename Filter>
124e08fbffcSVernon Mauery void registerFilter(int prio, Filter&& filter)
125e08fbffcSVernon Mauery {
126e08fbffcSVernon Mauery     auto f = ipmi::makeFilter(std::forward<Filter>(filter));
127e08fbffcSVernon Mauery     impl::registerFilter(prio, f);
128e08fbffcSVernon Mauery }
129e08fbffcSVernon Mauery 
130e08fbffcSVernon Mauery template <typename Filter>
131e08fbffcSVernon Mauery void registerFilter(int prio, const Filter& filter)
132e08fbffcSVernon Mauery {
133e08fbffcSVernon Mauery     auto f = ipmi::makeFilter(filter);
134e08fbffcSVernon Mauery     impl::registerFilter(prio, f);
135e08fbffcSVernon Mauery }
136e08fbffcSVernon Mauery 
13708a70aa5SVernon Mauery } // namespace ipmi
138