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