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 "http_request.hpp"
9 #include "http_response.hpp"
10 #include "logging.hpp"
11 #include "utils/dbus_utils.hpp"
12 
13 #include <boost/system/error_code.hpp>
14 #include <boost/url/format.hpp>
15 #include <sdbusplus/unpack_properties.hpp>
16 
17 #include <memory>
18 #include <string>
19 #include <string_view>
20 
21 namespace redfish
22 {
23 
24 inline void afterGetSnmpTrapClientdata(
25     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
26     const boost::system::error_code& ec,
27     const dbus::utility::DBusPropertiesMap& propertiesList)
28 {
29     if (ec)
30     {
31         BMCWEB_LOG_ERROR("D-Bus response error on GetSubTree {}", ec);
32         messages::internalError(asyncResp->res);
33         return;
34     }
35 
36     std::string address;
37     uint16_t port = 0;
38 
39     bool success = sdbusplus::unpackPropertiesNoThrow(
40         dbus_utils::UnpackErrorPrinter(), propertiesList, "Address", address,
41         "Port", port);
42 
43     if (!success)
44     {
45         messages::internalError(asyncResp->res);
46         return;
47     }
48 
49     asyncResp->res.jsonValue["Destination"] =
50         boost::urls::format("snmp://{}:{}", address, port);
51 }
52 
53 inline void
54     getSnmpTrapClientdata(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
55                           const std::string& id, const std::string& objectPath)
56 {
57     asyncResp->res.jsonValue["@odata.type"] =
58         "#EventDestination.v1_8_0.EventDestination";
59     asyncResp->res.jsonValue["Protocol"] = "SNMPv2c";
60     asyncResp->res.jsonValue["@odata.id"] =
61         boost::urls::format("/redfish/v1/EventService/Subscriptions/{}", id);
62 
63     asyncResp->res.jsonValue["Id"] = id;
64     asyncResp->res.jsonValue["Name"] = "Event Destination";
65 
66     asyncResp->res.jsonValue["SubscriptionType"] = "SNMPTrap";
67     asyncResp->res.jsonValue["EventFormatType"] = "Event";
68 
69     std::shared_ptr<Subscription> subValue =
70         EventServiceManager::getInstance().getSubscription(id);
71     if (subValue != nullptr)
72     {
73         asyncResp->res.jsonValue["Context"] = subValue->customText;
74     }
75     else
76     {
77         asyncResp->res.jsonValue["Context"] = "";
78     }
79 
80     sdbusplus::asio::getAllProperties(
81         *crow::connections::systemBus, "xyz.openbmc_project.Network.SNMP",
82         objectPath, "xyz.openbmc_project.Network.Client",
83         [asyncResp](const boost::system::error_code& ec,
84                     const dbus::utility::DBusPropertiesMap& properties) {
85         afterGetSnmpTrapClientdata(asyncResp, ec, properties);
86     });
87 }
88 
89 inline void
90     getSnmpTrapClient(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
91                       const std::string& id)
92 {
93     crow::connections::systemBus->async_method_call(
94         [asyncResp, id](const boost::system::error_code& ec,
95                         dbus::utility::ManagedObjectType& resp) {
96         if (ec)
97         {
98             BMCWEB_LOG_ERROR("D-Bus response error on GetManagedObjects {}",
99                              ec);
100             messages::internalError(asyncResp->res);
101             return;
102         }
103 
104         for (const auto& objpath : resp)
105         {
106             sdbusplus::message::object_path path(objpath.first);
107             const std::string snmpId = path.filename();
108             if (snmpId.empty())
109             {
110                 BMCWEB_LOG_ERROR("The SNMP client ID is wrong");
111                 messages::internalError(asyncResp->res);
112                 return;
113             }
114             const std::string subscriptionId = "snmp" + snmpId;
115             if (id != subscriptionId)
116             {
117                 continue;
118             }
119 
120             getSnmpTrapClientdata(asyncResp, id, objpath.first);
121             return;
122         }
123 
124         messages::resourceNotFound(asyncResp->res, "Subscriptions", id);
125         EventServiceManager::getInstance().deleteSubscription(id);
126     },
127         "xyz.openbmc_project.Network.SNMP",
128         "/xyz/openbmc_project/network/snmp/manager",
129         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
130 }
131 
132 inline void afterSnmpClientCreate(
133     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
134     const boost::system::error_code& ec, const sdbusplus::message_t& msg,
135     const std::string& host, const std::string& dbusSNMPid)
136 {
137     if (ec)
138     {
139         const sd_bus_error* dbusError = msg.get_error();
140         if (dbusError != nullptr)
141         {
142             if (std::string_view(
143                     "xyz.openbmc_project.Common.Error.InvalidArgument") ==
144                 dbusError->name)
145             {
146                 messages::propertyValueIncorrect(asyncResp->res, "Destination",
147                                                  host);
148                 return;
149             }
150             if (ec.value() != EBADR)
151             {
152                 // SNMP not installed
153                 messages::propertyValueOutOfRange(asyncResp->res, "SNMPv2c",
154                                                   "Protocol");
155                 return;
156             }
157         }
158         messages::internalError(asyncResp->res);
159         return;
160     }
161     sdbusplus::message::object_path path(dbusSNMPid);
162     const std::string snmpId = path.filename();
163     if (snmpId.empty())
164     {
165         messages::internalError(asyncResp->res);
166         return;
167     }
168 
169     std::string subscriptionId = "snmp" + snmpId;
170 
171     boost::urls::url uri = boost::urls::format(
172         "/redfish/v1/EventService/Subscriptions/{}", subscriptionId);
173     asyncResp->res.addHeader("Location", uri.buffer());
174     messages::created(asyncResp->res);
175 }
176 
177 inline void
178     addSnmpTrapClient(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
179                       const std::string& host, uint16_t snmpTrapPort)
180 {
181     crow::connections::systemBus->async_method_call(
182         [asyncResp, host](const boost::system::error_code& ec,
183                           const sdbusplus::message_t& msg,
184                           const std::string& dbusSNMPid) {
185         afterSnmpClientCreate(asyncResp, ec, msg, host, dbusSNMPid);
186     },
187         "xyz.openbmc_project.Network.SNMP",
188         "/xyz/openbmc_project/network/snmp/manager",
189         "xyz.openbmc_project.Network.Client.Create", "Client", host,
190         snmpTrapPort);
191 }
192 
193 inline void
194     getSnmpSubscriptionList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
195                             const std::string& snmpId,
196                             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 
208 inline void
209     deleteSnmpTrapClient(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