blob: d54fac83c26ace8ac255110de0f074913cf00f67 [file] [log] [blame]
Patrick Venture690a2342020-05-17 11:51:31 -07001#include "transporthandler.hpp"
2
William A. Kennington III7a3831b2023-06-21 01:10:49 -07003#include <stdplus/raw.hpp>
4
5#include <array>
6
William A. Kennington IIIc514d872019-04-06 18:19:38 -07007using phosphor::logging::commit;
8using phosphor::logging::elog;
9using phosphor::logging::entry;
10using phosphor::logging::level;
11using phosphor::logging::log;
Willy Tu523e2d12023-09-05 11:36:48 -070012using sdbusplus::error::xyz::openbmc_project::common::InternalFailure;
William A. Kennington III7a3831b2023-06-21 01:10:49 -070013using sdbusplus::error::xyz::openbmc_project::common::InvalidArgument;
Willy Tu523e2d12023-09-05 11:36:48 -070014using sdbusplus::server::xyz::openbmc_project::network::EthernetInterface;
15using sdbusplus::server::xyz::openbmc_project::network::IP;
16using sdbusplus::server::xyz::openbmc_project::network::Neighbor;
William A. Kennington IIIc514d872019-04-06 18:19:38 -070017
Johnathan Manteyaffadb52019-10-07 10:13:53 -070018namespace cipher
19{
20
21std::vector<uint8_t> getCipherList()
22{
23 std::vector<uint8_t> cipherList;
24
25 std::ifstream jsonFile(cipher::configFile);
26 if (!jsonFile.is_open())
27 {
28 log<level::ERR>("Channel Cipher suites file not found");
29 elog<InternalFailure>();
30 }
31
32 auto data = Json::parse(jsonFile, nullptr, false);
33 if (data.is_discarded())
34 {
35 log<level::ERR>("Parsing channel cipher suites JSON failed");
36 elog<InternalFailure>();
37 }
38
39 // Byte 1 is reserved
40 cipherList.push_back(0x00);
41
42 for (const auto& record : data)
43 {
44 cipherList.push_back(record.value(cipher, 0));
45 }
46
47 return cipherList;
48}
49} // namespace cipher
50
51namespace ipmi
52{
53namespace transport
54{
55
William A. Kennington IIIc514d872019-04-06 18:19:38 -070056/** @brief Valid address origins for IPv4 */
57const std::unordered_set<IP::AddressOrigin> originsV4 = {
58 IP::AddressOrigin::Static,
59 IP::AddressOrigin::DHCP,
60};
61
Johnathan Manteyb87034e2019-09-16 10:50:50 -070062static constexpr uint8_t oemCmdStart = 192;
63static constexpr uint8_t oemCmdEnd = 255;
64
Patrick Williams5d82f472022-07-22 19:26:53 -050065std::optional<ChannelParams> maybeGetChannelParams(sdbusplus::bus_t& bus,
William A. Kennington IIIc514d872019-04-06 18:19:38 -070066 uint8_t channel)
67{
68 auto ifname = getChannelName(channel);
69 if (ifname.empty())
Patrick Venturec7c1c3c2017-11-15 14:29:18 -080070 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -070071 return std::nullopt;
Patrick Venturec7c1c3c2017-11-15 14:29:18 -080072 }
Patrick Venturec7c1c3c2017-11-15 14:29:18 -080073
William A. Kennington IIIc514d872019-04-06 18:19:38 -070074 // Enumerate all VLAN + ETHERNET interfaces
75 auto req = bus.new_method_call(MAPPER_BUS_NAME, MAPPER_OBJ, MAPPER_INTF,
76 "GetSubTree");
77 req.append(PATH_ROOT, 0,
78 std::vector<std::string>{INTF_VLAN, INTF_ETHERNET});
79 auto reply = bus.call(req);
80 ObjectTree objs;
81 reply.read(objs);
82
83 ChannelParams params;
84 for (const auto& [path, impls] : objs)
85 {
86 if (path.find(ifname) == path.npos)
87 {
88 continue;
89 }
90 for (const auto& [service, intfs] : impls)
91 {
92 bool vlan = false;
93 bool ethernet = false;
94 for (const auto& intf : intfs)
95 {
96 if (intf == INTF_VLAN)
97 {
98 vlan = true;
99 }
100 else if (intf == INTF_ETHERNET)
101 {
102 ethernet = true;
103 }
104 }
105 if (params.service.empty() && (vlan || ethernet))
106 {
107 params.service = service;
108 }
109 if (params.ifPath.empty() && !vlan && ethernet)
110 {
111 params.ifPath = path;
112 }
113 if (params.logicalPath.empty() && vlan)
114 {
115 params.logicalPath = path;
116 }
117 }
118 }
119
120 // We must have a path for the underlying interface
121 if (params.ifPath.empty())
122 {
123 return std::nullopt;
124 }
125 // We don't have a VLAN so the logical path is the same
126 if (params.logicalPath.empty())
127 {
128 params.logicalPath = params.ifPath;
129 }
130
131 params.id = channel;
132 params.ifname = std::move(ifname);
Willy Tu11d68892022-01-20 10:37:34 -0800133 return params;
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700134}
135
Patrick Williams5d82f472022-07-22 19:26:53 -0500136ChannelParams getChannelParams(sdbusplus::bus_t& bus, uint8_t channel)
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700137{
138 auto params = maybeGetChannelParams(bus, channel);
139 if (!params)
140 {
141 log<level::ERR>("Failed to get channel params",
142 entry("CHANNEL=%" PRIu8, channel));
143 elog<InternalFailure>();
144 }
145 return std::move(*params);
146}
147
148/** @brief Wraps the phosphor logging method to insert some additional metadata
149 *
150 * @param[in] params - The parameters for the channel
151 * ...
152 */
153template <auto level, typename... Args>
154auto logWithChannel(const ChannelParams& params, Args&&... args)
155{
156 return log<level>(std::forward<Args>(args)...,
157 entry("CHANNEL=%d", params.id),
158 entry("IFNAME=%s", params.ifname.c_str()));
159}
160template <auto level, typename... Args>
161auto logWithChannel(const std::optional<ChannelParams>& params, Args&&... args)
162{
163 if (params)
164 {
165 return logWithChannel<level>(*params, std::forward<Args>(args)...);
166 }
167 return log<level>(std::forward<Args>(args)...);
168}
169
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700170ether_addr stringToMAC(const char* mac)
171{
172 const ether_addr* ret = ether_aton(mac);
173 if (ret == nullptr)
174 {
175 log<level::ERR>("Invalid MAC Address", entry("MAC=%s", mac));
176 elog<InternalFailure>();
177 }
178 return *ret;
179}
180
William A. Kennington IIIa8a2e5f2023-06-21 17:50:01 -0700181/** @brief Get / Set the Property value from phosphor-networkd EthernetInterface
182 */
183template <typename T>
184static T getEthProp(sdbusplus::bus_t& bus, const ChannelParams& params,
185 const std::string& prop)
186{
187 return std::get<T>(getDbusProperty(bus, params.service, params.logicalPath,
188 INTF_ETHERNET, prop));
189}
190template <typename T>
191static void setEthProp(sdbusplus::bus_t& bus, const ChannelParams& params,
192 const std::string& prop, const T& t)
193{
194 return setDbusProperty(bus, params.service, params.logicalPath,
195 INTF_ETHERNET, prop, t);
196}
197
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700198/** @brief Determines the MAC of the ethernet interface
199 *
200 * @param[in] bus - The bus object used for lookups
201 * @param[in] params - The parameters for the channel
202 * @return The configured mac address
203 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500204ether_addr getMACProperty(sdbusplus::bus_t& bus, const ChannelParams& params)
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700205{
206 auto macStr = std::get<std::string>(getDbusProperty(
207 bus, params.service, params.ifPath, INTF_MAC, "MACAddress"));
208 return stringToMAC(macStr.c_str());
209}
210
211/** @brief Sets the system value for MAC address on the given interface
212 *
213 * @param[in] bus - The bus object used for lookups
214 * @param[in] params - The parameters for the channel
215 * @param[in] mac - MAC address to apply
216 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500217void setMACProperty(sdbusplus::bus_t& bus, const ChannelParams& params,
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700218 const ether_addr& mac)
219{
220 std::string macStr = ether_ntoa(&mac);
221 setDbusProperty(bus, params.service, params.ifPath, INTF_MAC, "MACAddress",
222 macStr);
223}
224
Patrick Williams5d82f472022-07-22 19:26:53 -0500225void deleteObjectIfExists(sdbusplus::bus_t& bus, const std::string& service,
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700226 const std::string& path)
227{
228 if (path.empty())
229 {
230 return;
231 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530232 try
tomjose26e17732016-03-03 08:52:51 -0600233 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700234 auto req = bus.new_method_call(service.c_str(), path.c_str(),
235 ipmi::DELETE_INTERFACE, "Delete");
236 bus.call_noreply(req);
237 }
Patrick Williams5d82f472022-07-22 19:26:53 -0500238 catch (const sdbusplus::exception_t& e)
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700239 {
jayaprakash Mutyala84c49dc2020-05-18 23:12:13 +0000240 if (strcmp(e.name(),
241 "xyz.openbmc_project.Common.Error.InternalFailure") != 0 &&
242 strcmp(e.name(), "org.freedesktop.DBus.Error.UnknownObject") != 0)
tomjose26e17732016-03-03 08:52:51 -0600243 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700244 // We want to rethrow real errors
245 throw;
tomjose26e17732016-03-03 08:52:51 -0600246 }
247 }
tomjose26e17732016-03-03 08:52:51 -0600248}
249
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700250/** @brief Sets the address info configured for the interface
251 * If a previous address path exists then it will be removed
252 * before the new address is added.
253 *
254 * @param[in] bus - The bus object used for lookups
255 * @param[in] params - The parameters for the channel
256 * @param[in] address - The address of the new IP
257 * @param[in] prefix - The prefix of the new IP
258 */
259template <int family>
Patrick Williams5d82f472022-07-22 19:26:53 -0500260void createIfAddr(sdbusplus::bus_t& bus, const ChannelParams& params,
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700261 const typename AddrFamily<family>::addr& address,
262 uint8_t prefix)
Tom Josepha30c8d32018-03-22 02:15:03 +0530263{
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500264 auto newreq = bus.new_method_call(params.service.c_str(),
265 params.logicalPath.c_str(),
266 INTF_IP_CREATE, "IP");
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700267 std::string protocol =
Willy Tu523e2d12023-09-05 11:36:48 -0700268 sdbusplus::common::xyz::openbmc_project::network::convertForMessage(
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700269 AddrFamily<family>::protocol);
270 newreq.append(protocol, addrToString<family>(address), prefix, "");
271 bus.call_noreply(newreq);
272}
Tom Josepha30c8d32018-03-22 02:15:03 +0530273
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700274/** @brief Trivial helper for getting the IPv4 address from getIfAddrs()
275 *
276 * @param[in] bus - The bus object used for lookups
277 * @param[in] params - The parameters for the channel
278 * @return The address and prefix if found
279 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500280auto getIfAddr4(sdbusplus::bus_t& bus, const ChannelParams& params)
Tom Josepha30c8d32018-03-22 02:15:03 +0530281{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700282 return getIfAddr<AF_INET>(bus, params, 0, originsV4);
283}
Tom Josepha30c8d32018-03-22 02:15:03 +0530284
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700285/** @brief Reconfigures the IPv4 address info configured for the interface
286 *
287 * @param[in] bus - The bus object used for lookups
288 * @param[in] params - The parameters for the channel
289 * @param[in] address - The new address if specified
290 * @param[in] prefix - The new address prefix if specified
291 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500292void reconfigureIfAddr4(sdbusplus::bus_t& bus, const ChannelParams& params,
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700293 const std::optional<in_addr>& address,
294 std::optional<uint8_t> prefix)
295{
296 auto ifaddr = getIfAddr4(bus, params);
297 if (!ifaddr && !address)
Tom Josepha30c8d32018-03-22 02:15:03 +0530298 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700299 log<level::ERR>("Missing address for IPv4 assignment");
Tom Josepha30c8d32018-03-22 02:15:03 +0530300 elog<InternalFailure>();
301 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700302 uint8_t fallbackPrefix = AddrFamily<AF_INET>::defaultPrefix;
303 if (ifaddr)
Tom Josepha30c8d32018-03-22 02:15:03 +0530304 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700305 fallbackPrefix = ifaddr->prefix;
306 deleteObjectIfExists(bus, params.service, ifaddr->path);
307 }
Johnathan Manteycbfa6e12023-06-01 06:57:25 -0700308
Jian Zhangd05b9dd2023-07-04 14:48:40 +0800309 if (struct in_addr nullIPv4{0};
Jayaprakash Mutyala4e02b432023-07-13 13:50:40 +0000310 (address == std::nullopt && prefix != std::nullopt) ||
311 (address != std::nullopt &&
312 (address.value().s_addr != nullIPv4.s_addr)))
Johnathan Manteycbfa6e12023-06-01 06:57:25 -0700313 {
314 createIfAddr<AF_INET>(bus, params, address.value_or(ifaddr->address),
315 prefix.value_or(fallbackPrefix));
316 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700317}
318
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700319template <int family>
Patrick Williams5d82f472022-07-22 19:26:53 -0500320std::optional<IfNeigh<family>> findGatewayNeighbor(sdbusplus::bus_t& bus,
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700321 const ChannelParams& params,
322 ObjectLookupCache& neighbors)
323{
324 auto gateway = getGatewayProperty<family>(bus, params);
325 if (!gateway)
326 {
327 return std::nullopt;
328 }
329
330 return findStaticNeighbor<family>(bus, params, *gateway, neighbors);
331}
332
333template <int family>
Patrick Williams5d82f472022-07-22 19:26:53 -0500334std::optional<IfNeigh<family>> getGatewayNeighbor(sdbusplus::bus_t& bus,
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700335 const ChannelParams& params)
336{
337 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
338 return findGatewayNeighbor<family>(bus, params, neighbors);
339}
340
341template <int family>
Patrick Williams5d82f472022-07-22 19:26:53 -0500342void reconfigureGatewayMAC(sdbusplus::bus_t& bus, const ChannelParams& params,
343 const ether_addr& mac)
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700344{
345 auto gateway = getGatewayProperty<family>(bus, params);
346 if (!gateway)
347 {
348 log<level::ERR>("Tried to set Gateway MAC without Gateway");
349 elog<InternalFailure>();
350 }
351
352 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500353 auto neighbor = findStaticNeighbor<family>(bus, params, *gateway,
354 neighbors);
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700355 if (neighbor)
356 {
357 deleteObjectIfExists(bus, params.service, neighbor->path);
358 }
359
360 createNeighbor<family>(bus, params, *gateway, mac);
361}
362
William A. Kennington III16064aa2019-04-13 17:44:53 -0700363/** @brief Deconfigures the IPv6 address info configured for the interface
364 *
365 * @param[in] bus - The bus object used for lookups
366 * @param[in] params - The parameters for the channel
367 * @param[in] idx - The address index to operate on
368 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500369void deconfigureIfAddr6(sdbusplus::bus_t& bus, const ChannelParams& params,
William A. Kennington III16064aa2019-04-13 17:44:53 -0700370 uint8_t idx)
371{
372 auto ifaddr = getIfAddr<AF_INET6>(bus, params, idx, originsV6Static);
373 if (ifaddr)
374 {
375 deleteObjectIfExists(bus, params.service, ifaddr->path);
376 }
377}
378
379/** @brief Reconfigures the IPv6 address info configured for the interface
380 *
381 * @param[in] bus - The bus object used for lookups
382 * @param[in] params - The parameters for the channel
383 * @param[in] idx - The address index to operate on
384 * @param[in] address - The new address
385 * @param[in] prefix - The new address prefix
386 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500387void reconfigureIfAddr6(sdbusplus::bus_t& bus, const ChannelParams& params,
William A. Kennington III16064aa2019-04-13 17:44:53 -0700388 uint8_t idx, const in6_addr& address, uint8_t prefix)
389{
390 deconfigureIfAddr6(bus, params, idx);
391 createIfAddr<AF_INET6>(bus, params, address, prefix);
392}
393
394/** @brief Converts the AddressOrigin into an IPv6Source
395 *
396 * @param[in] origin - The DBus Address Origin to convert
397 * @return The IPv6Source version of the origin
398 */
399IPv6Source originToSourceType(IP::AddressOrigin origin)
400{
401 switch (origin)
402 {
403 case IP::AddressOrigin::Static:
404 return IPv6Source::Static;
405 case IP::AddressOrigin::DHCP:
406 return IPv6Source::DHCP;
407 case IP::AddressOrigin::SLAAC:
408 return IPv6Source::SLAAC;
409 default:
410 {
Willy Tu523e2d12023-09-05 11:36:48 -0700411 auto originStr = sdbusplus::common::xyz::openbmc_project::network::
William A. Kennington III16064aa2019-04-13 17:44:53 -0700412 convertForMessage(origin);
413 log<level::ERR>(
414 "Invalid IP::AddressOrigin conversion to IPv6Source",
415 entry("ORIGIN=%s", originStr.c_str()));
416 elog<InternalFailure>();
417 }
418 }
419}
420
421/** @brief Packs the IPMI message response with IPv6 address data
422 *
423 * @param[out] ret - The IPMI response payload to be packed
424 * @param[in] channel - The channel id corresponding to an ethernet interface
425 * @param[in] set - The set selector for determining address index
426 * @param[in] origins - Set of valid origins for address filtering
427 */
428void getLanIPv6Address(message::Payload& ret, uint8_t channel, uint8_t set,
429 const std::unordered_set<IP::AddressOrigin>& origins)
430{
431 auto source = IPv6Source::Static;
432 bool enabled = false;
433 in6_addr addr{};
Johnathan Mantey5aae0922021-10-21 13:05:36 -0700434 uint8_t prefix{};
William A. Kennington III16064aa2019-04-13 17:44:53 -0700435 auto status = IPv6AddressStatus::Disabled;
436
437 auto ifaddr = channelCall<getIfAddr<AF_INET6>>(channel, set, origins);
438 if (ifaddr)
439 {
440 source = originToSourceType(ifaddr->origin);
Johnathan Mantey846af862021-10-21 12:48:54 -0700441 enabled = (origins == originsV6Static);
William A. Kennington III16064aa2019-04-13 17:44:53 -0700442 addr = ifaddr->address;
443 prefix = ifaddr->prefix;
444 status = IPv6AddressStatus::Active;
445 }
446
447 ret.pack(set);
William A. Kennington III7a0e5df2021-05-19 13:31:29 -0700448 ret.pack(types::enum_cast<uint4_t>(source), uint3_t{}, enabled);
William A. Kennington III16064aa2019-04-13 17:44:53 -0700449 ret.pack(std::string_view(reinterpret_cast<char*>(&addr), sizeof(addr)));
450 ret.pack(prefix);
William A. Kennington III7a0e5df2021-05-19 13:31:29 -0700451 ret.pack(types::enum_cast<uint8_t>(status));
William A. Kennington III16064aa2019-04-13 17:44:53 -0700452}
453
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700454/** @brief Gets the vlan ID configured on the interface
455 *
456 * @param[in] bus - The bus object used for lookups
457 * @param[in] params - The parameters for the channel
458 * @return VLAN id or the standard 0 for no VLAN
459 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500460uint16_t getVLANProperty(sdbusplus::bus_t& bus, const ChannelParams& params)
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700461{
462 // VLAN devices will always have a separate logical object
463 if (params.ifPath == params.logicalPath)
464 {
465 return 0;
466 }
467
468 auto vlan = std::get<uint32_t>(getDbusProperty(
469 bus, params.service, params.logicalPath, INTF_VLAN, "Id"));
470 if ((vlan & VLAN_VALUE_MASK) != vlan)
471 {
472 logWithChannel<level::ERR>(params, "networkd returned an invalid vlan",
473 entry("VLAN=%" PRIu32, vlan));
Tom Josepha30c8d32018-03-22 02:15:03 +0530474 elog<InternalFailure>();
475 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700476 return vlan;
Tom Josepha30c8d32018-03-22 02:15:03 +0530477}
478
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700479/** @brief Deletes all of the possible configuration parameters for a channel
480 *
481 * @param[in] bus - The bus object used for lookups
482 * @param[in] params - The parameters for the channel
483 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500484void deconfigureChannel(sdbusplus::bus_t& bus, ChannelParams& params)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500485{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700486 // Delete all objects associated with the interface
487 auto objreq = bus.new_method_call(MAPPER_BUS_NAME, MAPPER_OBJ, MAPPER_INTF,
488 "GetSubTree");
489 objreq.append(PATH_ROOT, 0, std::vector<std::string>{DELETE_INTERFACE});
490 auto objreply = bus.call(objreq);
491 ObjectTree objs;
492 objreply.read(objs);
493 for (const auto& [path, impls] : objs)
494 {
495 if (path.find(params.ifname) == path.npos)
496 {
497 continue;
498 }
499 for (const auto& [service, intfs] : impls)
500 {
501 deleteObjectIfExists(bus, service, path);
502 }
503 // Update params to reflect the deletion of vlan
504 if (path == params.logicalPath)
505 {
506 params.logicalPath = params.ifPath;
507 }
508 }
509
510 // Clear out any settings on the lower physical interface
William A. Kennington IIIa8a2e5f2023-06-21 17:50:01 -0700511 setEthProp(bus, params, "DHCP4", false);
512 setEthProp(bus, params, "DHCP6", false);
513 setEthProp(bus, params, "IPv6AcceptRA", false);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500514}
515
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700516/** @brief Creates a new VLAN on the specified interface
517 *
518 * @param[in] bus - The bus object used for lookups
519 * @param[in] params - The parameters for the channel
520 * @param[in] vlan - The id of the new vlan
521 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500522void createVLAN(sdbusplus::bus_t& bus, ChannelParams& params, uint16_t vlan)
Ratan Guptab8e99552017-07-27 07:07:48 +0530523{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700524 if (vlan == 0)
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +0530525 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700526 return;
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +0530527 }
528
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700529 auto req = bus.new_method_call(params.service.c_str(), PATH_ROOT,
530 INTF_VLAN_CREATE, "VLAN");
531 req.append(params.ifname, static_cast<uint32_t>(vlan));
532 auto reply = bus.call(req);
533 sdbusplus::message::object_path newPath;
534 reply.read(newPath);
535 params.logicalPath = std::move(newPath);
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +0530536}
537
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700538/** @brief Performs the necessary reconfiguration to change the VLAN
539 *
540 * @param[in] bus - The bus object used for lookups
541 * @param[in] params - The parameters for the channel
542 * @param[in] vlan - The new vlan id to use
543 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500544void reconfigureVLAN(sdbusplus::bus_t& bus, ChannelParams& params,
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700545 uint16_t vlan)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500546{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700547 // Unfortunatetly we don't have built-in functions to migrate our interface
548 // customizations to new VLAN interfaces, or have some kind of decoupling.
549 // We therefore must retain all of our old information, setup the new VLAN
550 // configuration, then restore the old info.
Nan Li3d0df912016-10-18 19:51:41 +0800551
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700552 // Save info from the old logical interface
William A. Kennington IIIa8a2e5f2023-06-21 17:50:01 -0700553 bool dhcp4 = getEthProp<bool>(bus, params, "DHCP4");
554 bool dhcp6 = getEthProp<bool>(bus, params, "DHCP6");
555 bool ra = getEthProp<bool>(bus, params, "IPv6AcceptRA");
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700556 ObjectLookupCache ips(bus, params, INTF_IP);
557 auto ifaddr4 = findIfAddr<AF_INET>(bus, params, 0, originsV4, ips);
William A. Kennington III16064aa2019-04-13 17:44:53 -0700558 std::vector<IfAddr<AF_INET6>> ifaddrs6;
559 for (uint8_t i = 0; i < MAX_IPV6_STATIC_ADDRESSES; ++i)
560 {
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500561 auto ifaddr6 = findIfAddr<AF_INET6>(bus, params, i, originsV6Static,
562 ips);
William A. Kennington III16064aa2019-04-13 17:44:53 -0700563 if (!ifaddr6)
564 {
565 break;
566 }
567 ifaddrs6.push_back(std::move(*ifaddr6));
568 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700569 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
570 auto neighbor4 = findGatewayNeighbor<AF_INET>(bus, params, neighbors);
William A. Kennington III16064aa2019-04-13 17:44:53 -0700571 auto neighbor6 = findGatewayNeighbor<AF_INET6>(bus, params, neighbors);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500572
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700573 deconfigureChannel(bus, params);
574 createVLAN(bus, params, vlan);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500575
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700576 // Re-establish the saved settings
William A. Kennington IIIa8a2e5f2023-06-21 17:50:01 -0700577 setEthProp(bus, params, "DHCP4", dhcp4);
578 setEthProp(bus, params, "DHCP6", dhcp6);
579 setEthProp(bus, params, "IPv6AcceptRA", ra);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700580 if (ifaddr4)
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800581 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700582 createIfAddr<AF_INET>(bus, params, ifaddr4->address, ifaddr4->prefix);
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800583 }
William A. Kennington III16064aa2019-04-13 17:44:53 -0700584 for (const auto& ifaddr6 : ifaddrs6)
585 {
586 createIfAddr<AF_INET6>(bus, params, ifaddr6.address, ifaddr6.prefix);
587 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700588 if (neighbor4)
589 {
590 createNeighbor<AF_INET>(bus, params, neighbor4->ip, neighbor4->mac);
591 }
William A. Kennington III16064aa2019-04-13 17:44:53 -0700592 if (neighbor6)
593 {
594 createNeighbor<AF_INET6>(bus, params, neighbor6->ip, neighbor6->mac);
595 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700596}
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800597
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700598/** @brief Turns a prefix into a netmask
599 *
600 * @param[in] prefix - The prefix length
601 * @return The netmask
602 */
603in_addr prefixToNetmask(uint8_t prefix)
604{
605 if (prefix > 32)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500606 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700607 log<level::ERR>("Invalid prefix", entry("PREFIX=%" PRIu8, prefix));
608 elog<InternalFailure>();
609 }
610 if (prefix == 0)
611 {
612 // Avoids 32-bit lshift by 32 UB
613 return {};
614 }
615 return {htobe32(~UINT32_C(0) << (32 - prefix))};
616}
617
618/** @brief Turns a a netmask into a prefix length
619 *
620 * @param[in] netmask - The netmask in byte form
621 * @return The prefix length
622 */
623uint8_t netmaskToPrefix(in_addr netmask)
624{
625 uint32_t x = be32toh(netmask.s_addr);
626 if ((~x & (~x + 1)) != 0)
627 {
628 char maskStr[INET_ADDRSTRLEN];
629 inet_ntop(AF_INET, &netmask, maskStr, sizeof(maskStr));
630 log<level::ERR>("Invalid netmask", entry("NETMASK=%s", maskStr));
631 elog<InternalFailure>();
632 }
Johnathan Mantey62c05dd2019-11-20 14:07:44 -0800633 return static_cast<bool>(x)
634 ? AddrFamily<AF_INET>::defaultPrefix - __builtin_ctz(x)
635 : 0;
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700636}
637
638// We need to store this value so it can be returned to the client
639// It is volatile so safe to store in daemon memory.
640static std::unordered_map<uint8_t, SetStatus> setStatus;
641
642// Until we have good support for fixed versions of IPMI tool
643// we need to return the VLAN id for disabled VLANs. The value is only
644// used for verification that a disable operation succeeded and will only
645// be sent if our system indicates that vlans are disabled.
646static std::unordered_map<uint8_t, uint16_t> lastDisabledVlan;
647
648/** @brief Gets the set status for the channel if it exists
649 * Otherise populates and returns the default value.
650 *
651 * @param[in] channel - The channel id corresponding to an ethernet interface
652 * @return A reference to the SetStatus for the channel
653 */
654SetStatus& getSetStatus(uint8_t channel)
655{
656 auto it = setStatus.find(channel);
657 if (it != setStatus.end())
658 {
659 return it->second;
660 }
661 return setStatus[channel] = SetStatus::Complete;
662}
663
William A. Kennington III7a3831b2023-06-21 01:10:49 -0700664/** @brief Unpacks the trivially copyable type from the message */
665template <typename T>
666static T unpackT(message::Payload& req)
667{
668 std::array<uint8_t, sizeof(T)> bytes;
669 if (req.unpack(bytes) != 0)
670 {
671 throw ccReqDataLenInvalid;
672 }
673 return stdplus::raw::copyFrom<T>(bytes);
674}
675
676/** @brief Ensure the message is fully unpacked */
677static void unpackFinal(message::Payload& req)
678{
679 if (!req.fullyUnpacked())
680 {
681 throw ccReqDataTruncated;
682 }
683}
684
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700685/**
686 * Define placeholder command handlers for the OEM Extension bytes for the Set
687 * LAN Configuration Parameters and Get LAN Configuration Parameters
688 * commands. Using "weak" linking allows the placeholder setLanOem/getLanOem
689 * functions below to be overridden.
690 * To create handlers for your own proprietary command set:
691 * Create/modify a phosphor-ipmi-host Bitbake append file within your Yocto
692 * recipe
693 * Create C++ file(s) that define IPMI handler functions matching the
694 * function names below (i.e. setLanOem). The default name for the
695 * transport IPMI commands is transporthandler_oem.cpp.
696 * Add:
Johnathan Manteyefe26682022-08-11 14:30:45 -0700697 * EXTRA_OEMESON:append = "-Dtransport-oem=enabled"
698 * Create a do_configure:prepend()/do_install:append() method in your
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700699 * bbappend file to copy the file to the build directory.
700 * Add:
701 * PROJECT_SRC_DIR := "${THISDIR}/${PN}"
702 * # Copy the "strong" functions into the working directory, overriding the
703 * # placeholder functions.
Johnathan Manteyefe26682022-08-11 14:30:45 -0700704 * do_configure:prepend(){
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700705 * cp -f ${PROJECT_SRC_DIR}/transporthandler_oem.cpp ${S}
706 * }
707 *
708 * # Clean up after complilation has completed
Johnathan Manteyefe26682022-08-11 14:30:45 -0700709 * do_install:append(){
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700710 * rm -f ${S}/transporthandler_oem.cpp
711 * }
712 *
713 */
714
715/**
716 * Define the placeholder OEM commands as having weak linkage. Create
717 * setLanOem, and getLanOem functions in the transporthandler_oem.cpp
718 * file. The functions defined there must not have the "weak" attribute
719 * applied to them.
720 */
721RspType<> setLanOem(uint8_t channel, uint8_t parameter, message::Payload& req)
722 __attribute__((weak));
723RspType<message::Payload> getLanOem(uint8_t channel, uint8_t parameter,
724 uint8_t set, uint8_t block)
725 __attribute__((weak));
726
Willy Tu11d68892022-01-20 10:37:34 -0800727RspType<> setLanOem(uint8_t, uint8_t, message::Payload& req)
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700728{
729 req.trailingOk = true;
730 return response(ccParamNotSupported);
731}
732
Willy Tu11d68892022-01-20 10:37:34 -0800733RspType<message::Payload> getLanOem(uint8_t, uint8_t, uint8_t, uint8_t)
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700734{
735 return response(ccParamNotSupported);
736}
737
Jian Zhangcf19d142023-07-31 10:22:53 +0800738/**
739 * @brief is a valid LAN channel.
740 *
741 * This function checks whether the input channel is a valid LAN channel or not.
742 *
743 * @param[in] channel: the channel number.
744 * @return nullopt if the channel is invalid, false if the channel is not a LAN
745 * channel, true if the channel is a LAN channel.
746 **/
747std::optional<bool> isLanChannel(uint8_t channel)
748{
749 ChannelInfo chInfo;
750 auto cc = getChannelInfo(channel, chInfo);
751 if (cc != ccSuccess)
752 {
753 return std::nullopt;
754 }
755
756 return chInfo.mediumType ==
757 static_cast<uint8_t>(EChannelMediumType::lan8032);
758}
759
William A. Kennington III7a3831b2023-06-21 01:10:49 -0700760RspType<> setLanInt(Context::ptr ctx, uint4_t channelBits, uint4_t reserved1,
761 uint8_t parameter, message::Payload& req)
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700762{
vijayabharathix shettycc769252020-02-27 17:52:20 +0000763 const uint8_t channel = convertCurrentChannelNum(
764 static_cast<uint8_t>(channelBits), ctx->channel);
765 if (reserved1 || !isValidChannel(channel))
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700766 {
vijayabharathix shettycc769252020-02-27 17:52:20 +0000767 log<level::ERR>("Set Lan - Invalid field in request");
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700768 req.trailingOk = true;
769 return responseInvalidFieldRequest();
770 }
771
Jian Zhangcf19d142023-07-31 10:22:53 +0800772 if (!isLanChannel(channel).value_or(false))
773 {
774 log<level::ERR>("Set Lan - Not a LAN channel");
775 return responseInvalidFieldRequest();
776 }
777
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700778 switch (static_cast<LanParam>(parameter))
779 {
780 case LanParam::SetStatus:
781 {
782 uint2_t flag;
783 uint6_t rsvd;
William A. Kennington III7a3831b2023-06-21 01:10:49 -0700784 if (req.unpack(flag, rsvd) != 0)
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700785 {
786 return responseReqDataLenInvalid();
787 }
William A. Kennington III7a3831b2023-06-21 01:10:49 -0700788 unpackFinal(req);
Johnathan Mantey4a156852019-12-11 13:47:43 -0800789 if (rsvd)
790 {
791 return responseInvalidFieldRequest();
792 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700793 auto status = static_cast<SetStatus>(static_cast<uint8_t>(flag));
794 switch (status)
795 {
796 case SetStatus::Complete:
797 {
798 getSetStatus(channel) = status;
799 return responseSuccess();
800 }
801 case SetStatus::InProgress:
802 {
803 auto& storedStatus = getSetStatus(channel);
804 if (storedStatus == SetStatus::InProgress)
805 {
806 return response(ccParamSetLocked);
807 }
808 storedStatus = status;
809 return responseSuccess();
810 }
811 case SetStatus::Commit:
812 if (getSetStatus(channel) != SetStatus::InProgress)
813 {
814 return responseInvalidFieldRequest();
815 }
816 return responseSuccess();
817 }
818 return response(ccParamNotSupported);
819 }
820 case LanParam::AuthSupport:
821 {
822 req.trailingOk = true;
823 return response(ccParamReadOnly);
824 }
825 case LanParam::AuthEnables:
826 {
827 req.trailingOk = true;
Johnathan Mantey76ce9c72019-11-14 14:41:46 -0800828 return response(ccParamReadOnly);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700829 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -0800830 case LanParam::IP:
Hariharasubramanian R83951912016-01-20 07:06:36 -0600831 {
William A. Kennington IIIa8a2e5f2023-06-21 17:50:01 -0700832 if (channelCall<getEthProp<bool>>(channel, "DHCP4"))
Johnathan Mantey930104a2019-12-17 09:18:34 -0800833 {
834 return responseCommandNotAvailable();
835 }
William A. Kennington III7a3831b2023-06-21 01:10:49 -0700836 auto ip = unpackT<in_addr>(req);
837 unpackFinal(req);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700838 channelCall<reconfigureIfAddr4>(channel, ip, std::nullopt);
839 return responseSuccess();
Ratan Guptab8e99552017-07-27 07:07:48 +0530840 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700841 case LanParam::IPSrc:
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530842 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700843 uint4_t flag;
844 uint4_t rsvd;
William A. Kennington III7a3831b2023-06-21 01:10:49 -0700845 if (req.unpack(flag, rsvd) != 0)
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700846 {
847 return responseReqDataLenInvalid();
848 }
William A. Kennington III7a3831b2023-06-21 01:10:49 -0700849 unpackFinal(req);
Johnathan Mantey4a156852019-12-11 13:47:43 -0800850 if (rsvd)
851 {
852 return responseInvalidFieldRequest();
853 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700854 switch (static_cast<IPSrc>(static_cast<uint8_t>(flag)))
855 {
856 case IPSrc::DHCP:
Johnathan Mantey65265362019-11-14 11:24:19 -0800857 // The IPSrc IPMI command is only for IPv4
858 // management. Modifying IPv6 state is done using
859 // a completely different Set LAN Configuration
860 // subcommand.
William A. Kennington IIIa8a2e5f2023-06-21 17:50:01 -0700861 channelCall<setEthProp<bool>>(channel, "DHCP4", true);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700862 return responseSuccess();
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700863 case IPSrc::Unspecified:
864 case IPSrc::Static:
William A. Kennington IIIa8a2e5f2023-06-21 17:50:01 -0700865 channelCall<setEthProp<bool>>(channel, "DHCP4", false);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700866 return responseSuccess();
Rajashekar Gade Reddy8a860ea2019-12-24 11:31:19 +0530867 case IPSrc::BIOS:
868 case IPSrc::BMC:
Rajashekar Gade Reddy8a860ea2019-12-24 11:31:19 +0530869 return responseInvalidFieldRequest();
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700870 }
871 return response(ccParamNotSupported);
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530872 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -0800873 case LanParam::MAC:
Ratan Guptab8e99552017-07-27 07:07:48 +0530874 {
William A. Kennington III7a3831b2023-06-21 01:10:49 -0700875 auto mac = unpackT<ether_addr>(req);
876 unpackFinal(req);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700877 channelCall<setMACProperty>(channel, mac);
878 return responseSuccess();
Ratan Gupta533d03b2017-07-30 10:39:22 +0530879 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700880 case LanParam::SubnetMask:
Ratan Guptab8e99552017-07-27 07:07:48 +0530881 {
William A. Kennington IIIa8a2e5f2023-06-21 17:50:01 -0700882 if (channelCall<getEthProp<bool>>(channel, "DHCP4"))
Johnathan Mantey930104a2019-12-17 09:18:34 -0800883 {
884 return responseCommandNotAvailable();
885 }
William A. Kennington III7a3831b2023-06-21 01:10:49 -0700886 auto netmask = unpackT<in_addr>(req);
887 unpackFinal(req);
William A. Kennington III6fdbb2d2023-06-21 15:27:02 -0700888 channelCall<reconfigureIfAddr4>(channel, std::nullopt,
889 netmaskToPrefix(netmask));
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700890 return responseSuccess();
Ratan Guptab8e99552017-07-27 07:07:48 +0530891 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700892 case LanParam::Gateway1:
Ratan Guptab8e99552017-07-27 07:07:48 +0530893 {
William A. Kennington IIIa8a2e5f2023-06-21 17:50:01 -0700894 if (channelCall<getEthProp<bool>>(channel, "DHCP4"))
Johnathan Mantey930104a2019-12-17 09:18:34 -0800895 {
896 return responseCommandNotAvailable();
897 }
William A. Kennington III7a3831b2023-06-21 01:10:49 -0700898 auto gateway = unpackT<in_addr>(req);
899 unpackFinal(req);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700900 channelCall<setGatewayProperty<AF_INET>>(channel, gateway);
901 return responseSuccess();
902 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700903 case LanParam::Gateway1MAC:
904 {
William A. Kennington III7a3831b2023-06-21 01:10:49 -0700905 auto gatewayMAC = unpackT<ether_addr>(req);
906 unpackFinal(req);
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700907 channelCall<reconfigureGatewayMAC<AF_INET>>(channel, gatewayMAC);
908 return responseSuccess();
909 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700910 case LanParam::VLANId:
911 {
William A. Kennington III7a3831b2023-06-21 01:10:49 -0700912 uint12_t vlanData;
913 uint3_t rsvd;
914 bool vlanEnable;
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +0530915
William A. Kennington III7a3831b2023-06-21 01:10:49 -0700916 if (req.unpack(vlanData, rsvd, vlanEnable) != 0)
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700917 {
918 return responseReqDataLenInvalid();
919 }
William A. Kennington III7a3831b2023-06-21 01:10:49 -0700920 unpackFinal(req);
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +0530921
William A. Kennington III7a3831b2023-06-21 01:10:49 -0700922 if (rsvd)
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700923 {
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +0530924 return responseInvalidFieldRequest();
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700925 }
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +0530926
927 uint16_t vlan = static_cast<uint16_t>(vlanData);
928
929 if (!vlanEnable)
930 {
931 lastDisabledVlan[channel] = vlan;
932 vlan = 0;
933 }
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +0530934
jayaprakash Mutyala84c49dc2020-05-18 23:12:13 +0000935 channelCall<reconfigureVLAN>(channel, vlan);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700936 return responseSuccess();
937 }
938 case LanParam::CiphersuiteSupport:
939 case LanParam::CiphersuiteEntries:
William A. Kennington III16064aa2019-04-13 17:44:53 -0700940 case LanParam::IPFamilySupport:
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700941 {
942 req.trailingOk = true;
943 return response(ccParamReadOnly);
Ratan Guptab8e99552017-07-27 07:07:48 +0530944 }
William A. Kennington III16064aa2019-04-13 17:44:53 -0700945 case LanParam::IPFamilyEnables:
946 {
947 uint8_t enables;
William A. Kennington III7a3831b2023-06-21 01:10:49 -0700948 if (req.unpack(enables) != 0)
William A. Kennington III16064aa2019-04-13 17:44:53 -0700949 {
950 return responseReqDataLenInvalid();
951 }
William A. Kennington III7a3831b2023-06-21 01:10:49 -0700952 unpackFinal(req);
William A. Kennington III16064aa2019-04-13 17:44:53 -0700953 switch (static_cast<IPFamilyEnables>(enables))
954 {
955 case IPFamilyEnables::DualStack:
956 return responseSuccess();
957 case IPFamilyEnables::IPv4Only:
958 case IPFamilyEnables::IPv6Only:
959 return response(ccParamNotSupported);
960 }
961 return response(ccParamNotSupported);
962 }
963 case LanParam::IPv6Status:
964 {
965 req.trailingOk = true;
966 return response(ccParamReadOnly);
967 }
968 case LanParam::IPv6StaticAddresses:
969 {
970 uint8_t set;
971 uint7_t rsvd;
972 bool enabled;
William A. Kennington III16064aa2019-04-13 17:44:53 -0700973 uint8_t prefix;
974 uint8_t status;
William A. Kennington III7a3831b2023-06-21 01:10:49 -0700975 if (req.unpack(set, rsvd, enabled) != 0)
William A. Kennington III16064aa2019-04-13 17:44:53 -0700976 {
977 return responseReqDataLenInvalid();
978 }
William A. Kennington III7a3831b2023-06-21 01:10:49 -0700979 auto ip = unpackT<in6_addr>(req);
980 if (req.unpack(prefix, status) != 0)
981 {
982 return responseReqDataLenInvalid();
983 }
984 unpackFinal(req);
Johnathan Mantey4a156852019-12-11 13:47:43 -0800985 if (rsvd)
986 {
987 return responseInvalidFieldRequest();
988 }
William A. Kennington III16064aa2019-04-13 17:44:53 -0700989 if (enabled)
990 {
Jiaqing Zhao6d4a44e2022-01-24 15:04:00 +0800991 if (prefix < MIN_IPV6_PREFIX_LENGTH ||
992 prefix > MAX_IPV6_PREFIX_LENGTH)
993 {
994 return responseParmOutOfRange();
995 }
William A. Kennington III7a3831b2023-06-21 01:10:49 -0700996 channelCall<reconfigureIfAddr6>(channel, set, ip, prefix);
William A. Kennington III16064aa2019-04-13 17:44:53 -0700997 }
998 else
999 {
1000 channelCall<deconfigureIfAddr6>(channel, set);
1001 }
1002 return responseSuccess();
1003 }
1004 case LanParam::IPv6DynamicAddresses:
1005 {
1006 req.trailingOk = true;
1007 return response(ccParamReadOnly);
1008 }
1009 case LanParam::IPv6RouterControl:
1010 {
1011 std::bitset<8> control;
Johnathan Mantey3b7a4072021-01-26 14:24:53 -08001012 constexpr uint8_t reservedRACCBits = 0xfc;
William A. Kennington III7a3831b2023-06-21 01:10:49 -07001013 if (req.unpack(control) != 0)
William A. Kennington III16064aa2019-04-13 17:44:53 -07001014 {
1015 return responseReqDataLenInvalid();
1016 }
William A. Kennington III7a3831b2023-06-21 01:10:49 -07001017 unpackFinal(req);
Johnathan Mantey3b7a4072021-01-26 14:24:53 -08001018 if (std::bitset<8> expected(control &
1019 std::bitset<8>(reservedRACCBits));
1020 expected.any())
William A. Kennington III16064aa2019-04-13 17:44:53 -07001021 {
Johnathan Mantey3b7a4072021-01-26 14:24:53 -08001022 return response(ccParamNotSupported);
William A. Kennington III16064aa2019-04-13 17:44:53 -07001023 }
Johnathan Mantey3b7a4072021-01-26 14:24:53 -08001024
1025 bool enableRA = control[IPv6RouterControlFlag::Dynamic];
William A. Kennington IIIa8a2e5f2023-06-21 17:50:01 -07001026 channelCall<setEthProp<bool>>(channel, "IPv6AcceptRA", enableRA);
1027 channelCall<setEthProp<bool>>(channel, "DHCP6", enableRA);
William A. Kennington III16064aa2019-04-13 17:44:53 -07001028 return responseSuccess();
1029 }
1030 case LanParam::IPv6StaticRouter1IP:
1031 {
William A. Kennington III7a3831b2023-06-21 01:10:49 -07001032 auto gateway = unpackT<in6_addr>(req);
1033 unpackFinal(req);
William A. Kennington III16064aa2019-04-13 17:44:53 -07001034 channelCall<setGatewayProperty<AF_INET6>>(channel, gateway);
1035 return responseSuccess();
1036 }
1037 case LanParam::IPv6StaticRouter1MAC:
1038 {
William A. Kennington III7a3831b2023-06-21 01:10:49 -07001039 auto mac = unpackT<ether_addr>(req);
1040 unpackFinal(req);
William A. Kennington III16064aa2019-04-13 17:44:53 -07001041 channelCall<reconfigureGatewayMAC<AF_INET6>>(channel, mac);
1042 return responseSuccess();
1043 }
1044 case LanParam::IPv6StaticRouter1PrefixLength:
1045 {
1046 uint8_t prefix;
William A. Kennington III7a3831b2023-06-21 01:10:49 -07001047 if (req.unpack(prefix) != 0)
William A. Kennington III16064aa2019-04-13 17:44:53 -07001048 {
1049 return responseReqDataLenInvalid();
1050 }
William A. Kennington III7a3831b2023-06-21 01:10:49 -07001051 unpackFinal(req);
William A. Kennington III16064aa2019-04-13 17:44:53 -07001052 if (prefix != 0)
1053 {
1054 return responseInvalidFieldRequest();
1055 }
1056 return responseSuccess();
1057 }
1058 case LanParam::IPv6StaticRouter1PrefixValue:
1059 {
William A. Kennington III7a3831b2023-06-21 01:10:49 -07001060 unpackT<in6_addr>(req);
1061 unpackFinal(req);
William A. Kennington III16064aa2019-04-13 17:44:53 -07001062 // Accept any prefix value since our prefix length has to be 0
1063 return responseSuccess();
1064 }
jayaprakash Mutyalab741b992019-12-02 17:29:09 +00001065 case LanParam::cipherSuitePrivilegeLevels:
1066 {
William A. Kennington III7a3831b2023-06-21 01:10:49 -07001067 uint8_t rsvd;
jayaprakash Mutyalab741b992019-12-02 17:29:09 +00001068 std::array<uint4_t, ipmi::maxCSRecords> cipherSuitePrivs;
1069
William A. Kennington III7a3831b2023-06-21 01:10:49 -07001070 if (req.unpack(rsvd, cipherSuitePrivs))
jayaprakash Mutyalab741b992019-12-02 17:29:09 +00001071 {
1072 return responseReqDataLenInvalid();
1073 }
William A. Kennington III7a3831b2023-06-21 01:10:49 -07001074 unpackFinal(req);
jayaprakash Mutyalab741b992019-12-02 17:29:09 +00001075
William A. Kennington III7a3831b2023-06-21 01:10:49 -07001076 if (rsvd)
jayaprakash Mutyalab741b992019-12-02 17:29:09 +00001077 {
1078 return responseInvalidFieldRequest();
1079 }
1080
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -05001081 uint8_t resp = getCipherConfigObject(csPrivFileName,
1082 csPrivDefaultFileName)
1083 .setCSPrivilegeLevels(channel, cipherSuitePrivs);
jayaprakash Mutyalab741b992019-12-02 17:29:09 +00001084 if (!resp)
1085 {
1086 return responseSuccess();
1087 }
1088 else
1089 {
1090 req.trailingOk = true;
1091 return response(resp);
1092 }
1093 }
Ratan Guptab8e99552017-07-27 07:07:48 +05301094 }
vishwa1eaea4f2016-02-26 11:57:40 -06001095
Johnathan Manteyb87034e2019-09-16 10:50:50 -07001096 if ((parameter >= oemCmdStart) && (parameter <= oemCmdEnd))
1097 {
1098 return setLanOem(channel, parameter, req);
1099 }
1100
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001101 req.trailingOk = true;
1102 return response(ccParamNotSupported);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001103}
1104
William A. Kennington III7a3831b2023-06-21 01:10:49 -07001105RspType<> setLan(Context::ptr ctx, uint4_t channelBits, uint4_t reserved1,
1106 uint8_t parameter, message::Payload& req)
1107{
1108 try
1109 {
1110 return setLanInt(ctx, channelBits, reserved1, parameter, req);
1111 }
1112 catch (ipmi::Cc cc)
1113 {
1114 return response(cc);
1115 }
1116 catch (const sdbusplus::exception_t& e)
1117 {
1118 if (std::string_view{InvalidArgument::errName} == e.name())
1119 {
1120 return responseInvalidFieldRequest();
1121 }
1122 throw;
1123 }
1124}
1125
vijayabharathix shettycc769252020-02-27 17:52:20 +00001126RspType<message::Payload> getLan(Context::ptr ctx, uint4_t channelBits,
1127 uint3_t reserved, bool revOnly,
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001128 uint8_t parameter, uint8_t set, uint8_t block)
Ratan Guptab8e99552017-07-27 07:07:48 +05301129{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001130 message::Payload ret;
1131 constexpr uint8_t current_revision = 0x11;
1132 ret.pack(current_revision);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001133
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001134 if (revOnly)
Suryakanth Sekare4054402019-08-08 15:16:52 +05301135 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001136 return responseSuccess(std::move(ret));
Suryakanth Sekare4054402019-08-08 15:16:52 +05301137 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001138
vijayabharathix shettycc769252020-02-27 17:52:20 +00001139 const uint8_t channel = convertCurrentChannelNum(
1140 static_cast<uint8_t>(channelBits), ctx->channel);
1141 if (reserved || !isValidChannel(channel))
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001142 {
vijayabharathix shettycc769252020-02-27 17:52:20 +00001143 log<level::ERR>("Get Lan - Invalid field in request");
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001144 return responseInvalidFieldRequest();
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001145 }
1146
Jian Zhangcf19d142023-07-31 10:22:53 +08001147 if (!isLanChannel(channel).value_or(false))
1148 {
1149 log<level::ERR>("Set Lan - Not a LAN channel");
1150 return responseInvalidFieldRequest();
1151 }
1152
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001153 static std::vector<uint8_t> cipherList;
1154 static bool listInit = false;
1155 if (!listInit)
1156 {
1157 try
1158 {
1159 cipherList = cipher::getCipherList();
1160 listInit = true;
1161 }
1162 catch (const std::exception& e)
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -05001163 {}
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001164 }
1165
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001166 switch (static_cast<LanParam>(parameter))
Tom Josepha30c8d32018-03-22 02:15:03 +05301167 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001168 case LanParam::SetStatus:
Tom Josepha30c8d32018-03-22 02:15:03 +05301169 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001170 SetStatus status;
1171 try
1172 {
1173 status = setStatus.at(channel);
1174 }
1175 catch (const std::out_of_range&)
1176 {
1177 status = SetStatus::Complete;
1178 }
William A. Kennington III7a0e5df2021-05-19 13:31:29 -07001179 ret.pack(types::enum_cast<uint2_t>(status), uint6_t{});
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001180 return responseSuccess(std::move(ret));
Tom Josepha30c8d32018-03-22 02:15:03 +05301181 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001182 case LanParam::AuthSupport:
Tom Josepha30c8d32018-03-22 02:15:03 +05301183 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001184 std::bitset<6> support;
1185 ret.pack(support, uint2_t{});
1186 return responseSuccess(std::move(ret));
Tom Josepha30c8d32018-03-22 02:15:03 +05301187 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001188 case LanParam::AuthEnables:
vishwa1eaea4f2016-02-26 11:57:40 -06001189 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001190 std::bitset<6> enables;
1191 ret.pack(enables, uint2_t{}); // Callback
1192 ret.pack(enables, uint2_t{}); // User
1193 ret.pack(enables, uint2_t{}); // Operator
1194 ret.pack(enables, uint2_t{}); // Admin
1195 ret.pack(enables, uint2_t{}); // OEM
1196 return responseSuccess(std::move(ret));
William A. Kennington III39f94ef2018-11-19 22:36:16 -08001197 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001198 case LanParam::IP:
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001199 {
1200 auto ifaddr = channelCall<getIfAddr4>(channel);
1201 in_addr addr{};
1202 if (ifaddr)
1203 {
1204 addr = ifaddr->address;
1205 }
William A. Kennington III7a3831b2023-06-21 01:10:49 -07001206 ret.pack(stdplus::raw::asView<char>(addr));
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001207 return responseSuccess(std::move(ret));
1208 }
1209 case LanParam::IPSrc:
1210 {
William A. Kennington IIIa8a2e5f2023-06-21 17:50:01 -07001211 auto src = channelCall<getEthProp<bool>>(channel, "DHCP4")
1212 ? IPSrc::DHCP
1213 : IPSrc::Static;
William A. Kennington III7a0e5df2021-05-19 13:31:29 -07001214 ret.pack(types::enum_cast<uint4_t>(src), uint4_t{});
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001215 return responseSuccess(std::move(ret));
1216 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001217 case LanParam::MAC:
William A. Kennington III39f94ef2018-11-19 22:36:16 -08001218 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001219 ether_addr mac = channelCall<getMACProperty>(channel);
William A. Kennington III7a3831b2023-06-21 01:10:49 -07001220 ret.pack(stdplus::raw::asView<char>(mac));
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001221 return responseSuccess(std::move(ret));
1222 }
1223 case LanParam::SubnetMask:
1224 {
1225 auto ifaddr = channelCall<getIfAddr4>(channel);
1226 uint8_t prefix = AddrFamily<AF_INET>::defaultPrefix;
1227 if (ifaddr)
Ratan Guptab8e99552017-07-27 07:07:48 +05301228 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001229 prefix = ifaddr->prefix;
1230 }
1231 in_addr netmask = prefixToNetmask(prefix);
William A. Kennington III7a3831b2023-06-21 01:10:49 -07001232 ret.pack(stdplus::raw::asView<char>(netmask));
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001233 return responseSuccess(std::move(ret));
1234 }
1235 case LanParam::Gateway1:
1236 {
1237 auto gateway =
1238 channelCall<getGatewayProperty<AF_INET>>(channel).value_or(
1239 in_addr{});
William A. Kennington III7a3831b2023-06-21 01:10:49 -07001240 ret.pack(stdplus::raw::asView<char>(gateway));
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001241 return responseSuccess(std::move(ret));
1242 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001243 case LanParam::Gateway1MAC:
1244 {
1245 ether_addr mac{};
1246 auto neighbor = channelCall<getGatewayNeighbor<AF_INET>>(channel);
1247 if (neighbor)
1248 {
1249 mac = neighbor->mac;
1250 }
William A. Kennington III7a3831b2023-06-21 01:10:49 -07001251 ret.pack(stdplus::raw::asView<char>(mac));
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001252 return responseSuccess(std::move(ret));
1253 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001254 case LanParam::VLANId:
1255 {
1256 uint16_t vlan = channelCall<getVLANProperty>(channel);
1257 if (vlan != 0)
1258 {
1259 vlan |= VLAN_ENABLE_FLAG;
Ratan Guptab8e99552017-07-27 07:07:48 +05301260 }
1261 else
1262 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001263 vlan = lastDisabledVlan[channel];
Ratan Guptab8e99552017-07-27 07:07:48 +05301264 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001265 ret.pack(vlan);
1266 return responseSuccess(std::move(ret));
Adriana Kobylak342df102016-02-10 13:48:16 -06001267 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001268 case LanParam::CiphersuiteSupport:
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001269 {
srikanta mondal1d8579c2020-04-15 17:13:25 +00001270 if (getChannelSessionSupport(channel) ==
1271 EChannelSessSupported::none)
1272 {
1273 return responseInvalidFieldRequest();
1274 }
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001275 if (!listInit)
1276 {
1277 return responseUnspecifiedError();
1278 }
1279 ret.pack(static_cast<uint8_t>(cipherList.size() - 1));
1280 return responseSuccess(std::move(ret));
1281 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001282 case LanParam::CiphersuiteEntries:
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001283 {
srikanta mondal1d8579c2020-04-15 17:13:25 +00001284 if (getChannelSessionSupport(channel) ==
1285 EChannelSessSupported::none)
1286 {
1287 return responseInvalidFieldRequest();
1288 }
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001289 if (!listInit)
1290 {
1291 return responseUnspecifiedError();
1292 }
1293 ret.pack(cipherList);
1294 return responseSuccess(std::move(ret));
1295 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001296 case LanParam::IPFamilySupport:
1297 {
1298 std::bitset<8> support;
1299 support[IPFamilySupportFlag::IPv6Only] = 0;
1300 support[IPFamilySupportFlag::DualStack] = 1;
1301 support[IPFamilySupportFlag::IPv6Alerts] = 1;
1302 ret.pack(support);
1303 return responseSuccess(std::move(ret));
1304 }
1305 case LanParam::IPFamilyEnables:
1306 {
1307 ret.pack(static_cast<uint8_t>(IPFamilyEnables::DualStack));
1308 return responseSuccess(std::move(ret));
1309 }
1310 case LanParam::IPv6Status:
1311 {
1312 ret.pack(MAX_IPV6_STATIC_ADDRESSES);
1313 ret.pack(MAX_IPV6_DYNAMIC_ADDRESSES);
1314 std::bitset<8> support;
1315 support[IPv6StatusFlag::DHCP] = 1;
1316 support[IPv6StatusFlag::SLAAC] = 1;
1317 ret.pack(support);
1318 return responseSuccess(std::move(ret));
1319 }
1320 case LanParam::IPv6StaticAddresses:
1321 {
1322 if (set >= MAX_IPV6_STATIC_ADDRESSES)
1323 {
1324 return responseParmOutOfRange();
1325 }
1326 getLanIPv6Address(ret, channel, set, originsV6Static);
1327 return responseSuccess(std::move(ret));
1328 }
1329 case LanParam::IPv6DynamicAddresses:
1330 {
1331 if (set >= MAX_IPV6_DYNAMIC_ADDRESSES)
1332 {
1333 return responseParmOutOfRange();
1334 }
1335 getLanIPv6Address(ret, channel, set, originsV6Dynamic);
1336 return responseSuccess(std::move(ret));
1337 }
1338 case LanParam::IPv6RouterControl:
1339 {
1340 std::bitset<8> control;
Johnathan Mantey3b7a4072021-01-26 14:24:53 -08001341 control[IPv6RouterControlFlag::Dynamic] =
William A. Kennington IIIa8a2e5f2023-06-21 17:50:01 -07001342 channelCall<getEthProp<bool>>(channel, "IPv6AcceptRA");
Johnathan Mantey3b7a4072021-01-26 14:24:53 -08001343 control[IPv6RouterControlFlag::Static] = 1;
William A. Kennington III16064aa2019-04-13 17:44:53 -07001344 ret.pack(control);
1345 return responseSuccess(std::move(ret));
1346 }
1347 case LanParam::IPv6StaticRouter1IP:
1348 {
1349 in6_addr gateway{};
William A. Kennington IIIa8a2e5f2023-06-21 17:50:01 -07001350 if (!channelCall<getEthProp<bool>>(channel, "IPv6AcceptRA"))
William A. Kennington III16064aa2019-04-13 17:44:53 -07001351 {
1352 gateway =
1353 channelCall<getGatewayProperty<AF_INET6>>(channel).value_or(
1354 in6_addr{});
1355 }
William A. Kennington III7a3831b2023-06-21 01:10:49 -07001356 ret.pack(stdplus::raw::asView<char>(gateway));
William A. Kennington III16064aa2019-04-13 17:44:53 -07001357 return responseSuccess(std::move(ret));
1358 }
1359 case LanParam::IPv6StaticRouter1MAC:
1360 {
1361 ether_addr mac{};
1362 auto neighbor = channelCall<getGatewayNeighbor<AF_INET6>>(channel);
1363 if (neighbor)
1364 {
1365 mac = neighbor->mac;
1366 }
William A. Kennington III7a3831b2023-06-21 01:10:49 -07001367 ret.pack(stdplus::raw::asView<char>(mac));
William A. Kennington III16064aa2019-04-13 17:44:53 -07001368 return responseSuccess(std::move(ret));
1369 }
1370 case LanParam::IPv6StaticRouter1PrefixLength:
1371 {
1372 ret.pack(UINT8_C(0));
1373 return responseSuccess(std::move(ret));
1374 }
1375 case LanParam::IPv6StaticRouter1PrefixValue:
1376 {
1377 in6_addr prefix{};
William A. Kennington III7a3831b2023-06-21 01:10:49 -07001378 ret.pack(stdplus::raw::asView<char>(prefix));
William A. Kennington III16064aa2019-04-13 17:44:53 -07001379 return responseSuccess(std::move(ret));
1380 }
jayaprakash Mutyalab741b992019-12-02 17:29:09 +00001381 case LanParam::cipherSuitePrivilegeLevels:
1382 {
1383 std::array<uint4_t, ipmi::maxCSRecords> csPrivilegeLevels;
1384
1385 uint8_t resp =
1386 getCipherConfigObject(csPrivFileName, csPrivDefaultFileName)
1387 .getCSPrivilegeLevels(channel, csPrivilegeLevels);
1388 if (!resp)
1389 {
1390 constexpr uint8_t reserved1 = 0x00;
1391 ret.pack(reserved1, csPrivilegeLevels);
1392 return responseSuccess(std::move(ret));
1393 }
1394 else
1395 {
1396 return response(resp);
1397 }
1398 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001399 }
1400
Johnathan Manteyb87034e2019-09-16 10:50:50 -07001401 if ((parameter >= oemCmdStart) && (parameter <= oemCmdEnd))
1402 {
1403 return getLanOem(channel, parameter, set, block);
1404 }
1405
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001406 return response(ccParamNotSupported);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001407}
1408
Jian Zhang23f44652022-03-17 17:13:10 +08001409constexpr const char* solInterface = "xyz.openbmc_project.Ipmi.SOL";
1410constexpr const char* solPath = "/xyz/openbmc_project/ipmi/sol/";
1411constexpr const uint16_t solDefaultPort = 623;
1412
1413RspType<> setSolConfParams(Context::ptr ctx, uint4_t channelBits,
Willy Tu11d68892022-01-20 10:37:34 -08001414 uint4_t /*reserved*/, uint8_t parameter,
Jian Zhang23f44652022-03-17 17:13:10 +08001415 message::Payload& req)
1416{
1417 const uint8_t channel = convertCurrentChannelNum(
1418 static_cast<uint8_t>(channelBits), ctx->channel);
1419
1420 if (!isValidChannel(channel))
1421 {
1422 log<level::ERR>("Set Sol Config - Invalid channel in request");
1423 return responseInvalidFieldRequest();
1424 }
1425
1426 std::string solService{};
1427 std::string solPathWitheEthName = solPath + ipmi::getChannelName(channel);
1428
1429 if (ipmi::getService(ctx, solInterface, solPathWitheEthName, solService))
1430 {
1431 log<level::ERR>("Set Sol Config - Invalid solInterface",
1432 entry("SERVICE=%s", solService.c_str()),
1433 entry("OBJPATH=%s", solPathWitheEthName.c_str()),
1434 entry("INTERFACE=%s", solInterface));
1435 return responseInvalidFieldRequest();
1436 }
1437
1438 switch (static_cast<SolConfParam>(parameter))
1439 {
1440 case SolConfParam::Progress:
1441 {
1442 uint8_t progress;
1443 if (req.unpack(progress) != 0 || !req.fullyUnpacked())
1444 {
1445 return responseReqDataLenInvalid();
1446 }
1447
1448 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1449 solInterface, "Progress", progress))
1450 {
1451 return responseUnspecifiedError();
1452 }
1453 break;
1454 }
1455 case SolConfParam::Enable:
1456 {
1457 bool enable;
1458 uint7_t reserved2;
1459
1460 if (req.unpack(enable, reserved2) != 0 || !req.fullyUnpacked())
1461 {
1462 return responseReqDataLenInvalid();
1463 }
1464
1465 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1466 solInterface, "Enable", enable))
1467 {
1468 return responseUnspecifiedError();
1469 }
1470 break;
1471 }
1472 case SolConfParam::Authentication:
1473 {
1474 uint4_t privilegeBits{};
1475 uint2_t reserved2{};
1476 bool forceAuth = false;
1477 bool forceEncrypt = false;
1478
1479 if (req.unpack(privilegeBits, reserved2, forceAuth, forceEncrypt) !=
1480 0 ||
1481 !req.fullyUnpacked())
1482 {
1483 return responseReqDataLenInvalid();
1484 }
1485
1486 uint8_t privilege = static_cast<uint8_t>(privilegeBits);
Jonathan Domana48bf772023-05-26 17:54:57 -07001487 if (privilege < static_cast<uint8_t>(Privilege::User) ||
Jian Zhang23f44652022-03-17 17:13:10 +08001488 privilege > static_cast<uint8_t>(Privilege::Oem))
1489 {
1490 return ipmi::responseInvalidFieldRequest();
1491 }
1492
1493 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1494 solInterface, "Privilege", privilege))
1495 {
1496 return responseUnspecifiedError();
1497 }
1498
1499 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1500 solInterface, "ForceEncryption",
1501 forceEncrypt))
1502 {
1503 return responseUnspecifiedError();
1504 }
1505
1506 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1507 solInterface, "ForceAuthentication",
1508 forceAuth))
1509 {
1510 return responseUnspecifiedError();
1511 }
1512 break;
1513 }
1514 case SolConfParam::Accumulate:
1515 {
1516 uint8_t interval;
1517 uint8_t threshold;
1518 if (req.unpack(interval, threshold) != 0 || !req.fullyUnpacked())
1519 {
1520 return responseReqDataLenInvalid();
1521 }
1522
1523 if (threshold == 0)
1524 {
1525 return responseInvalidFieldRequest();
1526 }
1527
1528 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1529 solInterface, "AccumulateIntervalMS",
1530 interval))
1531 {
1532 return responseUnspecifiedError();
1533 }
1534
1535 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1536 solInterface, "Threshold", threshold))
1537 {
1538 return responseUnspecifiedError();
1539 }
1540 break;
1541 }
1542 case SolConfParam::Retry:
1543 {
1544 uint3_t countBits;
1545 uint5_t reserved2;
1546 uint8_t interval;
1547
1548 if (req.unpack(countBits, reserved2, interval) != 0 ||
1549 !req.fullyUnpacked())
1550 {
1551 return responseReqDataLenInvalid();
1552 }
1553
1554 uint8_t count = static_cast<uint8_t>(countBits);
1555 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1556 solInterface, "RetryCount", count))
1557 {
1558 return responseUnspecifiedError();
1559 }
1560
1561 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1562 solInterface, "RetryIntervalMS",
1563 interval))
1564 {
1565 return responseUnspecifiedError();
1566 }
1567 break;
1568 }
1569 case SolConfParam::Port:
1570 {
1571 return response(ipmiCCWriteReadParameter);
1572 }
1573 case SolConfParam::NonVbitrate:
1574 case SolConfParam::Vbitrate:
1575 case SolConfParam::Channel:
1576 default:
1577 return response(ipmiCCParamNotSupported);
1578 }
1579 return responseSuccess();
1580}
1581
1582RspType<message::Payload> getSolConfParams(Context::ptr ctx,
1583 uint4_t channelBits,
Willy Tu11d68892022-01-20 10:37:34 -08001584 uint3_t /*reserved*/, bool revOnly,
1585 uint8_t parameter, uint8_t /*set*/,
1586 uint8_t /*block*/)
Jian Zhang23f44652022-03-17 17:13:10 +08001587{
1588 message::Payload ret;
1589 constexpr uint8_t current_revision = 0x11;
1590 ret.pack(current_revision);
1591 if (revOnly)
1592 {
1593 return responseSuccess(std::move(ret));
1594 }
1595
1596 const uint8_t channel = convertCurrentChannelNum(
1597 static_cast<uint8_t>(channelBits), ctx->channel);
1598
1599 if (!isValidChannel(channel))
1600 {
1601 log<level::ERR>("Get Sol Config - Invalid channel in request");
1602 return responseInvalidFieldRequest();
1603 }
1604
1605 std::string solService{};
1606 std::string solPathWitheEthName = solPath + ipmi::getChannelName(channel);
1607
1608 if (ipmi::getService(ctx, solInterface, solPathWitheEthName, solService))
1609 {
1610 log<level::ERR>("Set Sol Config - Invalid solInterface",
1611 entry("SERVICE=%s", solService.c_str()),
1612 entry("OBJPATH=%s", solPathWitheEthName.c_str()),
1613 entry("INTERFACE=%s", solInterface));
1614 return responseInvalidFieldRequest();
1615 }
1616
1617 switch (static_cast<SolConfParam>(parameter))
1618 {
1619 case SolConfParam::Progress:
1620 {
1621 uint8_t progress;
1622 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1623 solInterface, "Progress", progress))
1624 {
1625 return responseUnspecifiedError();
1626 }
1627 ret.pack(progress);
1628 return responseSuccess(std::move(ret));
1629 }
1630 case SolConfParam::Enable:
1631 {
1632 bool enable{};
1633 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1634 solInterface, "Enable", enable))
1635 {
1636 return responseUnspecifiedError();
1637 }
1638 ret.pack(enable, uint7_t{});
1639 return responseSuccess(std::move(ret));
1640 }
1641 case SolConfParam::Authentication:
1642 {
1643 // 4bits, cast when pack
1644 uint8_t privilege;
1645 bool forceAuth = false;
1646 bool forceEncrypt = false;
1647
1648 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1649 solInterface, "Privilege", privilege))
1650 {
1651 return responseUnspecifiedError();
1652 }
1653
1654 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1655 solInterface, "ForceAuthentication",
1656 forceAuth))
1657 {
1658 return responseUnspecifiedError();
1659 }
1660
1661 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1662 solInterface, "ForceEncryption",
1663 forceEncrypt))
1664 {
1665 return responseUnspecifiedError();
1666 }
1667 ret.pack(uint4_t{privilege}, uint2_t{}, forceAuth, forceEncrypt);
1668 return responseSuccess(std::move(ret));
1669 }
1670 case SolConfParam::Accumulate:
1671 {
1672 uint8_t interval{}, threshold{};
1673
1674 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1675 solInterface, "AccumulateIntervalMS",
1676 interval))
1677 {
1678 return responseUnspecifiedError();
1679 }
1680
1681 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1682 solInterface, "Threshold", threshold))
1683 {
1684 return responseUnspecifiedError();
1685 }
1686 ret.pack(interval, threshold);
1687 return responseSuccess(std::move(ret));
1688 }
1689 case SolConfParam::Retry:
1690 {
1691 // 3bits, cast when cast
1692 uint8_t count{};
1693 uint8_t interval{};
1694
1695 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1696 solInterface, "RetryCount", count))
1697 {
1698 return responseUnspecifiedError();
1699 }
1700
1701 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1702 solInterface, "RetryIntervalMS",
1703 interval))
1704 {
1705 return responseUnspecifiedError();
1706 }
1707 ret.pack(uint3_t{count}, uint5_t{}, interval);
1708 return responseSuccess(std::move(ret));
1709 }
1710 case SolConfParam::Port:
1711 {
1712 auto port = solDefaultPort;
1713 ret.pack(static_cast<uint16_t>(port));
1714 return responseSuccess(std::move(ret));
1715 }
1716 case SolConfParam::Channel:
1717 {
1718 ret.pack(channel);
1719 return responseSuccess(std::move(ret));
1720 }
1721 case SolConfParam::NonVbitrate:
Jonathan Domana48bf772023-05-26 17:54:57 -07001722 {
1723 uint64_t baudRate;
1724 uint8_t encodedBitRate = 0;
1725 if (ipmi::getDbusProperty(
1726 ctx, "xyz.openbmc_project.Console.default",
1727 "/xyz/openbmc_project/console/default",
1728 "xyz.openbmc_project.Console.UART", "Baud", baudRate))
1729 {
1730 return ipmi::responseUnspecifiedError();
1731 }
1732 switch (baudRate)
1733 {
1734 case 9600:
1735 encodedBitRate = 0x06;
1736 break;
1737 case 19200:
1738 encodedBitRate = 0x07;
1739 break;
1740 case 38400:
1741 encodedBitRate = 0x08;
1742 break;
1743 case 57600:
1744 encodedBitRate = 0x09;
1745 break;
1746 case 115200:
1747 encodedBitRate = 0x0a;
1748 break;
1749 default:
1750 break;
1751 }
1752 ret.pack(encodedBitRate);
1753 return responseSuccess(std::move(ret));
1754 }
Jian Zhang23f44652022-03-17 17:13:10 +08001755 case SolConfParam::Vbitrate:
1756 default:
1757 return response(ipmiCCParamNotSupported);
1758 }
1759
1760 return response(ccParamNotSupported);
1761}
1762
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001763} // namespace transport
1764} // namespace ipmi
Ratan Gupta1247e0b2018-03-07 10:47:25 +05301765
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001766void register_netfn_transport_functions() __attribute__((constructor));
Ratan Gupta1247e0b2018-03-07 10:47:25 +05301767
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001768void register_netfn_transport_functions()
1769{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001770 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1771 ipmi::transport::cmdSetLanConfigParameters,
1772 ipmi::Privilege::Admin, ipmi::transport::setLan);
1773 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1774 ipmi::transport::cmdGetLanConfigParameters,
Johnathan Mantey34698d52019-11-19 14:47:30 -08001775 ipmi::Privilege::Operator, ipmi::transport::getLan);
Jian Zhang23f44652022-03-17 17:13:10 +08001776 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1777 ipmi::transport::cmdSetSolConfigParameters,
1778 ipmi::Privilege::Admin,
1779 ipmi::transport::setSolConfParams);
1780 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1781 ipmi::transport::cmdGetSolConfigParameters,
1782 ipmi::Privilege::User,
1783 ipmi::transport::getSolConfParams);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001784}