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