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