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 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 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 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 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 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 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 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