1 #pragma once
2 
3 #include "async_resp.hpp"
4 #include "dbus_singleton.hpp"
5 #include "dbus_utility.hpp"
6 #include "error_messages.hpp"
7 #include "event_service_manager.hpp"
8 #include "generated/enums/event_destination.hpp"
9 #include "http_request.hpp"
10 #include "http_response.hpp"
11 #include "logging.hpp"
12 #include "utils/dbus_utils.hpp"
13 
14 #include <boost/system/error_code.hpp>
15 #include <boost/url/format.hpp>
16 #include <sdbusplus/unpack_properties.hpp>
17 
18 #include <memory>
19 #include <string>
20 #include <string_view>
21 
22 namespace redfish
23 {
24 
25 inline void afterGetSnmpTrapClientdata(
26     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
27     const boost::system::error_code& ec,
28     const dbus::utility::DBusPropertiesMap& propertiesList)
29 {
30     if (ec)
31     {
32         BMCWEB_LOG_ERROR("D-Bus response error on GetSubTree {}", ec);
33         messages::internalError(asyncResp->res);
34         return;
35     }
36 
37     std::string address;
38     uint16_t port = 0;
39 
40     bool success = sdbusplus::unpackPropertiesNoThrow(
41         dbus_utils::UnpackErrorPrinter(), propertiesList, "Address", address,
42         "Port", port);
43 
44     if (!success)
45     {
46         messages::internalError(asyncResp->res);
47         return;
48     }
49 
50     asyncResp->res.jsonValue["Destination"] =
51         boost::urls::format("snmp://{}:{}", address, port);
52 }
53 
54 inline void
55     getSnmpTrapClientdata(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
56                           const std::string& id, const std::string& objectPath)
57 {
58     asyncResp->res.jsonValue["@odata.type"] =
59         "#EventDestination.v1_8_0.EventDestination";
60     asyncResp->res.jsonValue["Protocol"] =
61         event_destination::EventDestinationProtocol::SNMPv2c;
62     asyncResp->res.jsonValue["@odata.id"] =
63         boost::urls::format("/redfish/v1/EventService/Subscriptions/{}", id);
64 
65     asyncResp->res.jsonValue["Id"] = id;
66     asyncResp->res.jsonValue["Name"] = "Event Destination";
67 
68     asyncResp->res.jsonValue["SubscriptionType"] =
69         event_destination::SubscriptionType::SNMPTrap;
70     asyncResp->res.jsonValue["EventFormatType"] =
71         event_destination::EventFormatType::Event;
72 
73     std::shared_ptr<Subscription> subValue =
74         EventServiceManager::getInstance().getSubscription(id);
75     if (subValue != nullptr)
76     {
77         asyncResp->res.jsonValue["Context"] = subValue->customText;
78     }
79     else
80     {
81         asyncResp->res.jsonValue["Context"] = "";
82     }
83 
84     sdbusplus::asio::getAllProperties(
85         *crow::connections::systemBus, "xyz.openbmc_project.Network.SNMP",
86         objectPath, "xyz.openbmc_project.Network.Client",
87         [asyncResp](const boost::system::error_code& ec,
88                     const dbus::utility::DBusPropertiesMap& properties) {
89             afterGetSnmpTrapClientdata(asyncResp, ec, properties);
90         });
91 }
92 
93 inline void getSnmpTrapClient(
94     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
95 {
96     crow::connections::systemBus->async_method_call(
97         [asyncResp, id](const boost::system::error_code& ec,
98                         dbus::utility::ManagedObjectType& resp) {
99             if (ec)
100             {
101                 BMCWEB_LOG_ERROR("D-Bus response error on GetManagedObjects {}",
102                                  ec);
103                 messages::internalError(asyncResp->res);
104                 return;
105             }
106 
107             for (const auto& objpath : resp)
108             {
109                 sdbusplus::message::object_path path(objpath.first);
110                 const std::string snmpId = path.filename();
111                 if (snmpId.empty())
112                 {
113                     BMCWEB_LOG_ERROR("The SNMP client ID is wrong");
114                     messages::internalError(asyncResp->res);
115                     return;
116                 }
117                 const std::string subscriptionId = "snmp" + snmpId;
118                 if (id != subscriptionId)
119                 {
120                     continue;
121                 }
122 
123                 getSnmpTrapClientdata(asyncResp, id, objpath.first);
124                 return;
125             }
126 
127             messages::resourceNotFound(asyncResp->res, "Subscriptions", id);
128             EventServiceManager::getInstance().deleteSubscription(id);
129         },
130         "xyz.openbmc_project.Network.SNMP",
131         "/xyz/openbmc_project/network/snmp/manager",
132         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
133 }
134 
135 inline void afterSnmpClientCreate(
136     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
137     const boost::system::error_code& ec, const sdbusplus::message_t& msg,
138     const std::string& host, const std::string& dbusSNMPid)
139 {
140     if (ec)
141     {
142         const sd_bus_error* dbusError = msg.get_error();
143         if (dbusError != nullptr)
144         {
145             if (std::string_view(
146                     "xyz.openbmc_project.Common.Error.InvalidArgument") ==
147                 dbusError->name)
148             {
149                 messages::propertyValueIncorrect(asyncResp->res, "Destination",
150                                                  host);
151                 return;
152             }
153             if (ec.value() != EBADR)
154             {
155                 // SNMP not installed
156                 messages::propertyValueOutOfRange(asyncResp->res, "SNMPv2c",
157                                                   "Protocol");
158                 return;
159             }
160         }
161         messages::internalError(asyncResp->res);
162         return;
163     }
164     sdbusplus::message::object_path path(dbusSNMPid);
165     const std::string snmpId = path.filename();
166     if (snmpId.empty())
167     {
168         messages::internalError(asyncResp->res);
169         return;
170     }
171 
172     std::string subscriptionId = "snmp" + snmpId;
173 
174     boost::urls::url uri = boost::urls::format(
175         "/redfish/v1/EventService/Subscriptions/{}", subscriptionId);
176     asyncResp->res.addHeader("Location", uri.buffer());
177     messages::created(asyncResp->res);
178 }
179 
180 inline void
181     addSnmpTrapClient(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
182                       const std::string& host, uint16_t snmpTrapPort)
183 {
184     crow::connections::systemBus->async_method_call(
185         [asyncResp,
186          host](const boost::system::error_code& ec,
187                const sdbusplus::message_t& msg, const std::string& dbusSNMPid) {
188             afterSnmpClientCreate(asyncResp, ec, msg, host, dbusSNMPid);
189         },
190         "xyz.openbmc_project.Network.SNMP",
191         "/xyz/openbmc_project/network/snmp/manager",
192         "xyz.openbmc_project.Network.Client.Create", "Client", host,
193         snmpTrapPort);
194 }
195 
196 inline void getSnmpSubscriptionList(
197     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
198     const std::string& snmpId, nlohmann::json& memberArray)
199 {
200     const std::string subscriptionId = "snmp" + snmpId;
201 
202     nlohmann::json::object_t member;
203     member["@odata.id"] = boost::urls::format(
204         "/redfish/v1/EventService/Subscriptions/{}", subscriptionId);
205     memberArray.push_back(std::move(member));
206 
207     asyncResp->res.jsonValue["Members@odata.count"] = memberArray.size();
208 }
209 
210 inline void
211     deleteSnmpTrapClient(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
212                          const std::string& param)
213 {
214     std::string_view snmpTrapId = param;
215 
216     // Erase "snmp" in the request to find the corresponding
217     // dbus snmp client id. For example, the snmpid in the
218     // request is "snmp1", which will be "1" after being erased.
219     snmpTrapId.remove_prefix(4);
220 
221     sdbusplus::message::object_path snmpPath =
222         sdbusplus::message::object_path(
223             "/xyz/openbmc_project/network/snmp/manager") /
224         std::string(snmpTrapId);
225 
226     crow::connections::systemBus->async_method_call(
227         [asyncResp, param](const boost::system::error_code& ec) {
228             if (ec)
229             {
230                 // The snmp trap id is incorrect
231                 if (ec.value() == EBADR)
232                 {
233                     messages::resourceNotFound(asyncResp->res, "Subscription",
234                                                param);
235                     return;
236                 }
237                 messages::internalError(asyncResp->res);
238                 return;
239             }
240             messages::success(asyncResp->res);
241         },
242         "xyz.openbmc_project.Network.SNMP", static_cast<std::string>(snmpPath),
243         "xyz.openbmc_project.Object.Delete", "Delete");
244 }
245 
246 } // namespace redfish
247