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>
20*e08fbffcSVernon 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 
4208a70aa5SVernon Mauery     virtual ipmi::Cc call(message::Request::ptr request) = 0;
4308a70aa5SVernon Mauery };
4408a70aa5SVernon Mauery 
4508a70aa5SVernon Mauery /**
4608a70aa5SVernon Mauery  * @brief filter concrete class
4708a70aa5SVernon Mauery  *
4808a70aa5SVernon Mauery  * This is the base template that ipmi filters will resolve into. This is
4908a70aa5SVernon Mauery  * essentially just a wrapper to hold the filter callback so it can be stored in
5008a70aa5SVernon Mauery  * the filter list.
5108a70aa5SVernon Mauery  *
5208a70aa5SVernon Mauery  * Filters are called with a ipmi::message::Request shared_ptr on all IPMI
5308a70aa5SVernon Mauery  * commands in priority order and each filter has the opportunity to reject the
5408a70aa5SVernon Mauery  * command (by returning an IPMI error competion code.) If all the filters
5508a70aa5SVernon Mauery  * return success, the actual IPMI command will be executed. Filters can reject
5608a70aa5SVernon Mauery  * the command for any reason, based on system state, the context, the command
5708a70aa5SVernon Mauery  * payload, etc.
5808a70aa5SVernon Mauery  */
5908a70aa5SVernon Mauery template <typename Filter>
6008a70aa5SVernon Mauery class IpmiFilter : public FilterBase
6108a70aa5SVernon Mauery {
6208a70aa5SVernon Mauery   public:
6308a70aa5SVernon Mauery     IpmiFilter(Filter&& filter) : filter_(std::move(filter))
6408a70aa5SVernon Mauery     {
6508a70aa5SVernon Mauery     }
6608a70aa5SVernon Mauery 
6708a70aa5SVernon Mauery     ipmi::Cc call(message::Request::ptr request) override
6808a70aa5SVernon Mauery     {
6908a70aa5SVernon Mauery         return filter_(request);
7008a70aa5SVernon Mauery     }
7108a70aa5SVernon Mauery 
7208a70aa5SVernon Mauery   private:
7308a70aa5SVernon Mauery     Filter filter_;
7408a70aa5SVernon Mauery };
7508a70aa5SVernon Mauery 
7608a70aa5SVernon Mauery /**
7708a70aa5SVernon Mauery  * @brief helper function to construct a filter object
7808a70aa5SVernon Mauery  *
7908a70aa5SVernon Mauery  * This is called internally by the ipmi::registerFilter function.
8008a70aa5SVernon Mauery  */
8108a70aa5SVernon Mauery template <typename Filter>
8208a70aa5SVernon Mauery static inline auto makeFilter(Filter&& filter)
8308a70aa5SVernon Mauery {
8408a70aa5SVernon Mauery     FilterBase::ptr ptr(new IpmiFilter<Filter>(std::forward<Filter>(filter)));
8508a70aa5SVernon Mauery     return ptr;
8608a70aa5SVernon Mauery }
8708a70aa5SVernon Mauery template <typename Filter>
8808a70aa5SVernon Mauery static inline auto makeFilter(const Filter& filter)
8908a70aa5SVernon Mauery {
9008a70aa5SVernon Mauery     Filter lFilter = filter;
9108a70aa5SVernon Mauery     return makeFilter(std::forward<Filter>(lFilter));
9208a70aa5SVernon Mauery }
9308a70aa5SVernon Mauery 
94*e08fbffcSVernon Mauery namespace impl
95*e08fbffcSVernon Mauery {
96*e08fbffcSVernon Mauery 
97*e08fbffcSVernon Mauery // IPMI command filter registration implementation
98*e08fbffcSVernon Mauery void registerFilter(int prio, ::ipmi::FilterBase::ptr filter);
99*e08fbffcSVernon Mauery 
100*e08fbffcSVernon Mauery } // namespace impl
101*e08fbffcSVernon Mauery 
102*e08fbffcSVernon Mauery /**
103*e08fbffcSVernon Mauery  * @brief IPMI command filter registration function
104*e08fbffcSVernon Mauery  *
105*e08fbffcSVernon Mauery  * This function should be used to register IPMI command filter functions.
106*e08fbffcSVernon Mauery  * This function just passes the callback to makeFilter, which creates a
107*e08fbffcSVernon Mauery  * wrapper functor object that ultimately calls the callback.
108*e08fbffcSVernon Mauery  *
109*e08fbffcSVernon Mauery  * Filters are called with a ipmi::message::Request shared_ptr on all IPMI
110*e08fbffcSVernon Mauery  * commands in priority order and each filter has the opportunity to reject the
111*e08fbffcSVernon Mauery  * command (by returning an IPMI error competion code.) If all the filters
112*e08fbffcSVernon Mauery  * return success, the actual IPMI command will be executed. Filters can reject
113*e08fbffcSVernon Mauery  * the command for any reason, based on system state, the context, the command
114*e08fbffcSVernon Mauery  * payload, etc.
115*e08fbffcSVernon Mauery  *
116*e08fbffcSVernon Mauery  * @param prio - priority at which to register; see api.hpp
117*e08fbffcSVernon Mauery  * @param filter - the callback function that will handle this request
118*e08fbffcSVernon Mauery  *
119*e08fbffcSVernon Mauery  * @return bool - success of registering the handler
120*e08fbffcSVernon Mauery  */
121*e08fbffcSVernon Mauery template <typename Filter>
122*e08fbffcSVernon Mauery void registerFilter(int prio, Filter&& filter)
123*e08fbffcSVernon Mauery {
124*e08fbffcSVernon Mauery     auto f = ipmi::makeFilter(std::forward<Filter>(filter));
125*e08fbffcSVernon Mauery     impl::registerFilter(prio, f);
126*e08fbffcSVernon Mauery }
127*e08fbffcSVernon Mauery 
128*e08fbffcSVernon Mauery template <typename Filter>
129*e08fbffcSVernon Mauery void registerFilter(int prio, const Filter& filter)
130*e08fbffcSVernon Mauery {
131*e08fbffcSVernon Mauery     auto f = ipmi::makeFilter(filter);
132*e08fbffcSVernon Mauery     impl::registerFilter(prio, f);
133*e08fbffcSVernon Mauery }
134*e08fbffcSVernon Mauery 
13508a70aa5SVernon Mauery } // namespace ipmi
136