blob: 40ef88fe909e150e10d02ff5b81101fe7be04f7e [file] [log] [blame]
Patrick Venture690a2342020-05-17 11:51:31 -07001#include "transporthandler.hpp"
2
William A. Kennington IIIc514d872019-04-06 18:19:38 -07003using phosphor::logging::commit;
4using phosphor::logging::elog;
5using phosphor::logging::entry;
6using phosphor::logging::level;
7using phosphor::logging::log;
8using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Johnathan Mantey65265362019-11-14 11:24:19 -08009using sdbusplus::xyz::openbmc_project::Network::server::EthernetInterface;
William A. Kennington IIIc514d872019-04-06 18:19:38 -070010using sdbusplus::xyz::openbmc_project::Network::server::IP;
William A. Kennington III4bbc3db2019-04-15 00:02:10 -070011using sdbusplus::xyz::openbmc_project::Network::server::Neighbor;
William A. Kennington IIIc514d872019-04-06 18:19:38 -070012
Johnathan Manteyaffadb52019-10-07 10:13:53 -070013namespace cipher
14{
15
16std::vector<uint8_t> getCipherList()
17{
18 std::vector<uint8_t> cipherList;
19
20 std::ifstream jsonFile(cipher::configFile);
21 if (!jsonFile.is_open())
22 {
23 log<level::ERR>("Channel Cipher suites file not found");
24 elog<InternalFailure>();
25 }
26
27 auto data = Json::parse(jsonFile, nullptr, false);
28 if (data.is_discarded())
29 {
30 log<level::ERR>("Parsing channel cipher suites JSON failed");
31 elog<InternalFailure>();
32 }
33
34 // Byte 1 is reserved
35 cipherList.push_back(0x00);
36
37 for (const auto& record : data)
38 {
39 cipherList.push_back(record.value(cipher, 0));
40 }
41
42 return cipherList;
43}
44} // namespace cipher
45
46namespace ipmi
47{
48namespace transport
49{
50
William A. Kennington IIIc514d872019-04-06 18:19:38 -070051/** @brief Valid address origins for IPv4 */
52const std::unordered_set<IP::AddressOrigin> originsV4 = {
53 IP::AddressOrigin::Static,
54 IP::AddressOrigin::DHCP,
55};
56
Johnathan Manteyb87034e2019-09-16 10:50:50 -070057static constexpr uint8_t oemCmdStart = 192;
58static constexpr uint8_t oemCmdEnd = 255;
59
Patrick Williams5d82f472022-07-22 19:26:53 -050060std::optional<ChannelParams> maybeGetChannelParams(sdbusplus::bus_t& bus,
William A. Kennington IIIc514d872019-04-06 18:19:38 -070061 uint8_t channel)
62{
63 auto ifname = getChannelName(channel);
64 if (ifname.empty())
Patrick Venturec7c1c3c2017-11-15 14:29:18 -080065 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -070066 return std::nullopt;
Patrick Venturec7c1c3c2017-11-15 14:29:18 -080067 }
Patrick Venturec7c1c3c2017-11-15 14:29:18 -080068
William A. Kennington IIIc514d872019-04-06 18:19:38 -070069 // Enumerate all VLAN + ETHERNET interfaces
70 auto req = bus.new_method_call(MAPPER_BUS_NAME, MAPPER_OBJ, MAPPER_INTF,
71 "GetSubTree");
72 req.append(PATH_ROOT, 0,
73 std::vector<std::string>{INTF_VLAN, INTF_ETHERNET});
74 auto reply = bus.call(req);
75 ObjectTree objs;
76 reply.read(objs);
77
78 ChannelParams params;
79 for (const auto& [path, impls] : objs)
80 {
81 if (path.find(ifname) == path.npos)
82 {
83 continue;
84 }
85 for (const auto& [service, intfs] : impls)
86 {
87 bool vlan = false;
88 bool ethernet = false;
89 for (const auto& intf : intfs)
90 {
91 if (intf == INTF_VLAN)
92 {
93 vlan = true;
94 }
95 else if (intf == INTF_ETHERNET)
96 {
97 ethernet = true;
98 }
99 }
100 if (params.service.empty() && (vlan || ethernet))
101 {
102 params.service = service;
103 }
104 if (params.ifPath.empty() && !vlan && ethernet)
105 {
106 params.ifPath = path;
107 }
108 if (params.logicalPath.empty() && vlan)
109 {
110 params.logicalPath = path;
111 }
112 }
113 }
114
115 // We must have a path for the underlying interface
116 if (params.ifPath.empty())
117 {
118 return std::nullopt;
119 }
120 // We don't have a VLAN so the logical path is the same
121 if (params.logicalPath.empty())
122 {
123 params.logicalPath = params.ifPath;
124 }
125
126 params.id = channel;
127 params.ifname = std::move(ifname);
Willy Tu11d68892022-01-20 10:37:34 -0800128 return params;
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700129}
130
Patrick Williams5d82f472022-07-22 19:26:53 -0500131ChannelParams getChannelParams(sdbusplus::bus_t& bus, uint8_t channel)
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700132{
133 auto params = maybeGetChannelParams(bus, channel);
134 if (!params)
135 {
136 log<level::ERR>("Failed to get channel params",
137 entry("CHANNEL=%" PRIu8, channel));
138 elog<InternalFailure>();
139 }
140 return std::move(*params);
141}
142
143/** @brief Wraps the phosphor logging method to insert some additional metadata
144 *
145 * @param[in] params - The parameters for the channel
146 * ...
147 */
148template <auto level, typename... Args>
149auto logWithChannel(const ChannelParams& params, Args&&... args)
150{
151 return log<level>(std::forward<Args>(args)...,
152 entry("CHANNEL=%d", params.id),
153 entry("IFNAME=%s", params.ifname.c_str()));
154}
155template <auto level, typename... Args>
156auto logWithChannel(const std::optional<ChannelParams>& params, Args&&... args)
157{
158 if (params)
159 {
160 return logWithChannel<level>(*params, std::forward<Args>(args)...);
161 }
162 return log<level>(std::forward<Args>(args)...);
163}
164
Patrick Williams5d82f472022-07-22 19:26:53 -0500165EthernetInterface::DHCPConf getDHCPProperty(sdbusplus::bus_t& bus,
Johnathan Mantey65265362019-11-14 11:24:19 -0800166 const ChannelParams& params)
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700167{
Johnathan Mantey65265362019-11-14 11:24:19 -0800168 std::string dhcpstr = std::get<std::string>(getDbusProperty(
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700169 bus, params.service, params.logicalPath, INTF_ETHERNET, "DHCPEnabled"));
Johnathan Mantey65265362019-11-14 11:24:19 -0800170 return EthernetInterface::convertDHCPConfFromString(dhcpstr);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700171}
172
Johnathan Mantey65265362019-11-14 11:24:19 -0800173/** @brief Sets the DHCP v4 state on the given interface
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700174 *
Johnathan Mantey65265362019-11-14 11:24:19 -0800175 * @param[in] bus - The bus object used for lookups
176 * @param[in] params - The parameters for the channel
177 * @param[in] requestedDhcp - DHCP state to assign
178 * (EthernetInterface::DHCPConf::none,
179 * EthernetInterface::DHCPConf::v4,
180 * EthernetInterface::DHCPConf::v6,
181 * EthernetInterface::DHCPConf::both)
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700182 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500183void setDHCPv4Property(sdbusplus::bus_t& bus, const ChannelParams& params,
Johnathan Mantey65265362019-11-14 11:24:19 -0800184 const EthernetInterface::DHCPConf requestedDhcp)
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700185{
Johnathan Mantey65265362019-11-14 11:24:19 -0800186 EthernetInterface::DHCPConf currentDhcp = getDHCPProperty(bus, params);
187 EthernetInterface::DHCPConf nextDhcp = EthernetInterface::DHCPConf::none;
188
Tony Leed5967af2021-07-06 15:49:11 +0800189 // When calling setDHCPv4Property, requestedDhcp only has "v4" and "none".
190 // setDHCPv4Property is only for IPv4 management. It should not modify
191 // IPv6 state.
192 if (requestedDhcp == EthernetInterface::DHCPConf::v4)
Johnathan Mantey65265362019-11-14 11:24:19 -0800193 {
Tony Leed5967af2021-07-06 15:49:11 +0800194 if ((currentDhcp == EthernetInterface::DHCPConf::v6) ||
195 (currentDhcp == EthernetInterface::DHCPConf::both))
196 nextDhcp = EthernetInterface::DHCPConf::both;
197 else if ((currentDhcp == EthernetInterface::DHCPConf::v4) ||
198 (currentDhcp == EthernetInterface::DHCPConf::none))
199 nextDhcp = EthernetInterface::DHCPConf::v4;
Johnathan Mantey65265362019-11-14 11:24:19 -0800200 }
201 else if (requestedDhcp == EthernetInterface::DHCPConf::none)
202 {
Tony Leed5967af2021-07-06 15:49:11 +0800203 if ((currentDhcp == EthernetInterface::DHCPConf::v6) ||
204 (currentDhcp == EthernetInterface::DHCPConf::both))
Johnathan Mantey65265362019-11-14 11:24:19 -0800205 nextDhcp = EthernetInterface::DHCPConf::v6;
Tony Leed5967af2021-07-06 15:49:11 +0800206 else if ((currentDhcp == EthernetInterface::DHCPConf::v4) ||
207 (currentDhcp == EthernetInterface::DHCPConf::none))
Johnathan Mantey65265362019-11-14 11:24:19 -0800208 nextDhcp = EthernetInterface::DHCPConf::none;
Johnathan Mantey65265362019-11-14 11:24:19 -0800209 }
Tony Leed5967af2021-07-06 15:49:11 +0800210 else // Stay the same.
Johnathan Mantey65265362019-11-14 11:24:19 -0800211 {
212 nextDhcp = currentDhcp;
213 }
214 std::string newDhcp =
215 sdbusplus::xyz::openbmc_project::Network::server::convertForMessage(
216 nextDhcp);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700217 setDbusProperty(bus, params.service, params.logicalPath, INTF_ETHERNET,
Johnathan Mantey65265362019-11-14 11:24:19 -0800218 "DHCPEnabled", newDhcp);
219}
220
Patrick Williams5d82f472022-07-22 19:26:53 -0500221void setDHCPv6Property(sdbusplus::bus_t& bus, const ChannelParams& params,
Johnathan Mantey65265362019-11-14 11:24:19 -0800222 const EthernetInterface::DHCPConf requestedDhcp,
223 const bool defaultMode = true)
224{
225 EthernetInterface::DHCPConf currentDhcp = getDHCPProperty(bus, params);
226 EthernetInterface::DHCPConf nextDhcp = EthernetInterface::DHCPConf::none;
227
228 if (defaultMode)
229 {
Jiaqing Zhaod385b5a2021-12-29 18:31:49 +0800230 // When calling setDHCPv6Property, requestedDhcp only has "v6" and
231 // "none".
232 // setDHCPv6Property is only for IPv6 management. It should not modify
233 // IPv4 state.
234 if (requestedDhcp == EthernetInterface::DHCPConf::v6)
Johnathan Mantey65265362019-11-14 11:24:19 -0800235 {
Jiaqing Zhaod385b5a2021-12-29 18:31:49 +0800236 if ((currentDhcp == EthernetInterface::DHCPConf::v4) ||
237 (currentDhcp == EthernetInterface::DHCPConf::both))
238 nextDhcp = EthernetInterface::DHCPConf::both;
239 else if ((currentDhcp == EthernetInterface::DHCPConf::v6) ||
240 (currentDhcp == EthernetInterface::DHCPConf::none))
241 nextDhcp = EthernetInterface::DHCPConf::v6;
Johnathan Mantey65265362019-11-14 11:24:19 -0800242 }
243 else if (requestedDhcp == EthernetInterface::DHCPConf::none)
244 {
Jiaqing Zhaod385b5a2021-12-29 18:31:49 +0800245 if ((currentDhcp == EthernetInterface::DHCPConf::v4) ||
246 (currentDhcp == EthernetInterface::DHCPConf::both))
Johnathan Mantey65265362019-11-14 11:24:19 -0800247 nextDhcp = EthernetInterface::DHCPConf::v4;
Jiaqing Zhaod385b5a2021-12-29 18:31:49 +0800248 else if ((currentDhcp == EthernetInterface::DHCPConf::v6) ||
249 (currentDhcp == EthernetInterface::DHCPConf::none))
Johnathan Mantey65265362019-11-14 11:24:19 -0800250 nextDhcp = EthernetInterface::DHCPConf::none;
Johnathan Mantey65265362019-11-14 11:24:19 -0800251 }
Jiaqing Zhaod385b5a2021-12-29 18:31:49 +0800252 else // Stay the same.
Johnathan Mantey65265362019-11-14 11:24:19 -0800253 {
254 nextDhcp = currentDhcp;
255 }
256 }
257 else
258 {
259 // allow the v6 call to set any value
260 nextDhcp = requestedDhcp;
261 }
262
263 std::string newDhcp =
264 sdbusplus::xyz::openbmc_project::Network::server::convertForMessage(
265 nextDhcp);
266 setDbusProperty(bus, params.service, params.logicalPath, INTF_ETHERNET,
267 "DHCPEnabled", newDhcp);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700268}
269
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700270ether_addr stringToMAC(const char* mac)
271{
272 const ether_addr* ret = ether_aton(mac);
273 if (ret == nullptr)
274 {
275 log<level::ERR>("Invalid MAC Address", entry("MAC=%s", mac));
276 elog<InternalFailure>();
277 }
278 return *ret;
279}
280
281/** @brief Determines the MAC of the ethernet interface
282 *
283 * @param[in] bus - The bus object used for lookups
284 * @param[in] params - The parameters for the channel
285 * @return The configured mac address
286 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500287ether_addr getMACProperty(sdbusplus::bus_t& bus, const ChannelParams& params)
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700288{
289 auto macStr = std::get<std::string>(getDbusProperty(
290 bus, params.service, params.ifPath, INTF_MAC, "MACAddress"));
291 return stringToMAC(macStr.c_str());
292}
293
294/** @brief Sets the system value for MAC address on the given interface
295 *
296 * @param[in] bus - The bus object used for lookups
297 * @param[in] params - The parameters for the channel
298 * @param[in] mac - MAC address to apply
299 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500300void setMACProperty(sdbusplus::bus_t& bus, const ChannelParams& params,
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700301 const ether_addr& mac)
302{
303 std::string macStr = ether_ntoa(&mac);
304 setDbusProperty(bus, params.service, params.ifPath, INTF_MAC, "MACAddress",
305 macStr);
306}
307
Patrick Williams5d82f472022-07-22 19:26:53 -0500308void deleteObjectIfExists(sdbusplus::bus_t& bus, const std::string& service,
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700309 const std::string& path)
310{
311 if (path.empty())
312 {
313 return;
314 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530315 try
tomjose26e17732016-03-03 08:52:51 -0600316 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700317 auto req = bus.new_method_call(service.c_str(), path.c_str(),
318 ipmi::DELETE_INTERFACE, "Delete");
319 bus.call_noreply(req);
320 }
Patrick Williams5d82f472022-07-22 19:26:53 -0500321 catch (const sdbusplus::exception_t& e)
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700322 {
jayaprakash Mutyala84c49dc2020-05-18 23:12:13 +0000323 if (strcmp(e.name(),
324 "xyz.openbmc_project.Common.Error.InternalFailure") != 0 &&
325 strcmp(e.name(), "org.freedesktop.DBus.Error.UnknownObject") != 0)
tomjose26e17732016-03-03 08:52:51 -0600326 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700327 // We want to rethrow real errors
328 throw;
tomjose26e17732016-03-03 08:52:51 -0600329 }
330 }
tomjose26e17732016-03-03 08:52:51 -0600331}
332
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700333/** @brief Sets the address info configured for the interface
334 * If a previous address path exists then it will be removed
335 * before the new address is added.
336 *
337 * @param[in] bus - The bus object used for lookups
338 * @param[in] params - The parameters for the channel
339 * @param[in] address - The address of the new IP
340 * @param[in] prefix - The prefix of the new IP
341 */
342template <int family>
Patrick Williams5d82f472022-07-22 19:26:53 -0500343void createIfAddr(sdbusplus::bus_t& bus, const ChannelParams& params,
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700344 const typename AddrFamily<family>::addr& address,
345 uint8_t prefix)
Tom Josepha30c8d32018-03-22 02:15:03 +0530346{
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500347 auto newreq = bus.new_method_call(params.service.c_str(),
348 params.logicalPath.c_str(),
349 INTF_IP_CREATE, "IP");
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700350 std::string protocol =
351 sdbusplus::xyz::openbmc_project::Network::server::convertForMessage(
352 AddrFamily<family>::protocol);
353 newreq.append(protocol, addrToString<family>(address), prefix, "");
354 bus.call_noreply(newreq);
355}
Tom Josepha30c8d32018-03-22 02:15:03 +0530356
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700357/** @brief Trivial helper for getting the IPv4 address from getIfAddrs()
358 *
359 * @param[in] bus - The bus object used for lookups
360 * @param[in] params - The parameters for the channel
361 * @return The address and prefix if found
362 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500363auto getIfAddr4(sdbusplus::bus_t& bus, const ChannelParams& params)
Tom Josepha30c8d32018-03-22 02:15:03 +0530364{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700365 return getIfAddr<AF_INET>(bus, params, 0, originsV4);
366}
Tom Josepha30c8d32018-03-22 02:15:03 +0530367
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700368/** @brief Reconfigures the IPv4 address info configured for the interface
369 *
370 * @param[in] bus - The bus object used for lookups
371 * @param[in] params - The parameters for the channel
372 * @param[in] address - The new address if specified
373 * @param[in] prefix - The new address prefix if specified
374 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500375void reconfigureIfAddr4(sdbusplus::bus_t& bus, const ChannelParams& params,
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700376 const std::optional<in_addr>& address,
377 std::optional<uint8_t> prefix)
378{
379 auto ifaddr = getIfAddr4(bus, params);
380 if (!ifaddr && !address)
Tom Josepha30c8d32018-03-22 02:15:03 +0530381 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700382 log<level::ERR>("Missing address for IPv4 assignment");
Tom Josepha30c8d32018-03-22 02:15:03 +0530383 elog<InternalFailure>();
384 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700385 uint8_t fallbackPrefix = AddrFamily<AF_INET>::defaultPrefix;
386 if (ifaddr)
Tom Josepha30c8d32018-03-22 02:15:03 +0530387 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700388 fallbackPrefix = ifaddr->prefix;
389 deleteObjectIfExists(bus, params.service, ifaddr->path);
390 }
391 createIfAddr<AF_INET>(bus, params, address.value_or(ifaddr->address),
392 prefix.value_or(fallbackPrefix));
393}
394
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700395template <int family>
Patrick Williams5d82f472022-07-22 19:26:53 -0500396std::optional<IfNeigh<family>> findGatewayNeighbor(sdbusplus::bus_t& bus,
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700397 const ChannelParams& params,
398 ObjectLookupCache& neighbors)
399{
400 auto gateway = getGatewayProperty<family>(bus, params);
401 if (!gateway)
402 {
403 return std::nullopt;
404 }
405
406 return findStaticNeighbor<family>(bus, params, *gateway, neighbors);
407}
408
409template <int family>
Patrick Williams5d82f472022-07-22 19:26:53 -0500410std::optional<IfNeigh<family>> getGatewayNeighbor(sdbusplus::bus_t& bus,
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700411 const ChannelParams& params)
412{
413 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
414 return findGatewayNeighbor<family>(bus, params, neighbors);
415}
416
417template <int family>
Patrick Williams5d82f472022-07-22 19:26:53 -0500418void reconfigureGatewayMAC(sdbusplus::bus_t& bus, const ChannelParams& params,
419 const ether_addr& mac)
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700420{
421 auto gateway = getGatewayProperty<family>(bus, params);
422 if (!gateway)
423 {
424 log<level::ERR>("Tried to set Gateway MAC without Gateway");
425 elog<InternalFailure>();
426 }
427
428 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500429 auto neighbor = findStaticNeighbor<family>(bus, params, *gateway,
430 neighbors);
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700431 if (neighbor)
432 {
433 deleteObjectIfExists(bus, params.service, neighbor->path);
434 }
435
436 createNeighbor<family>(bus, params, *gateway, mac);
437}
438
William A. Kennington III16064aa2019-04-13 17:44:53 -0700439/** @brief Deconfigures the IPv6 address info configured for the interface
440 *
441 * @param[in] bus - The bus object used for lookups
442 * @param[in] params - The parameters for the channel
443 * @param[in] idx - The address index to operate on
444 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500445void deconfigureIfAddr6(sdbusplus::bus_t& bus, const ChannelParams& params,
William A. Kennington III16064aa2019-04-13 17:44:53 -0700446 uint8_t idx)
447{
448 auto ifaddr = getIfAddr<AF_INET6>(bus, params, idx, originsV6Static);
449 if (ifaddr)
450 {
451 deleteObjectIfExists(bus, params.service, ifaddr->path);
452 }
453}
454
455/** @brief Reconfigures the IPv6 address info configured for the interface
456 *
457 * @param[in] bus - The bus object used for lookups
458 * @param[in] params - The parameters for the channel
459 * @param[in] idx - The address index to operate on
460 * @param[in] address - The new address
461 * @param[in] prefix - The new address prefix
462 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500463void reconfigureIfAddr6(sdbusplus::bus_t& bus, const ChannelParams& params,
William A. Kennington III16064aa2019-04-13 17:44:53 -0700464 uint8_t idx, const in6_addr& address, uint8_t prefix)
465{
466 deconfigureIfAddr6(bus, params, idx);
467 createIfAddr<AF_INET6>(bus, params, address, prefix);
468}
469
470/** @brief Converts the AddressOrigin into an IPv6Source
471 *
472 * @param[in] origin - The DBus Address Origin to convert
473 * @return The IPv6Source version of the origin
474 */
475IPv6Source originToSourceType(IP::AddressOrigin origin)
476{
477 switch (origin)
478 {
479 case IP::AddressOrigin::Static:
480 return IPv6Source::Static;
481 case IP::AddressOrigin::DHCP:
482 return IPv6Source::DHCP;
483 case IP::AddressOrigin::SLAAC:
484 return IPv6Source::SLAAC;
485 default:
486 {
487 auto originStr = sdbusplus::xyz::openbmc_project::Network::server::
488 convertForMessage(origin);
489 log<level::ERR>(
490 "Invalid IP::AddressOrigin conversion to IPv6Source",
491 entry("ORIGIN=%s", originStr.c_str()));
492 elog<InternalFailure>();
493 }
494 }
495}
496
497/** @brief Packs the IPMI message response with IPv6 address data
498 *
499 * @param[out] ret - The IPMI response payload to be packed
500 * @param[in] channel - The channel id corresponding to an ethernet interface
501 * @param[in] set - The set selector for determining address index
502 * @param[in] origins - Set of valid origins for address filtering
503 */
504void getLanIPv6Address(message::Payload& ret, uint8_t channel, uint8_t set,
505 const std::unordered_set<IP::AddressOrigin>& origins)
506{
507 auto source = IPv6Source::Static;
508 bool enabled = false;
509 in6_addr addr{};
Johnathan Mantey5aae0922021-10-21 13:05:36 -0700510 uint8_t prefix{};
William A. Kennington III16064aa2019-04-13 17:44:53 -0700511 auto status = IPv6AddressStatus::Disabled;
512
513 auto ifaddr = channelCall<getIfAddr<AF_INET6>>(channel, set, origins);
514 if (ifaddr)
515 {
516 source = originToSourceType(ifaddr->origin);
Johnathan Mantey846af862021-10-21 12:48:54 -0700517 enabled = (origins == originsV6Static);
William A. Kennington III16064aa2019-04-13 17:44:53 -0700518 addr = ifaddr->address;
519 prefix = ifaddr->prefix;
520 status = IPv6AddressStatus::Active;
521 }
522
523 ret.pack(set);
William A. Kennington III7a0e5df2021-05-19 13:31:29 -0700524 ret.pack(types::enum_cast<uint4_t>(source), uint3_t{}, enabled);
William A. Kennington III16064aa2019-04-13 17:44:53 -0700525 ret.pack(std::string_view(reinterpret_cast<char*>(&addr), sizeof(addr)));
526 ret.pack(prefix);
William A. Kennington III7a0e5df2021-05-19 13:31:29 -0700527 ret.pack(types::enum_cast<uint8_t>(status));
William A. Kennington III16064aa2019-04-13 17:44:53 -0700528}
529
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700530/** @brief Gets the vlan ID configured on the interface
531 *
532 * @param[in] bus - The bus object used for lookups
533 * @param[in] params - The parameters for the channel
534 * @return VLAN id or the standard 0 for no VLAN
535 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500536uint16_t getVLANProperty(sdbusplus::bus_t& bus, const ChannelParams& params)
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700537{
538 // VLAN devices will always have a separate logical object
539 if (params.ifPath == params.logicalPath)
540 {
541 return 0;
542 }
543
544 auto vlan = std::get<uint32_t>(getDbusProperty(
545 bus, params.service, params.logicalPath, INTF_VLAN, "Id"));
546 if ((vlan & VLAN_VALUE_MASK) != vlan)
547 {
548 logWithChannel<level::ERR>(params, "networkd returned an invalid vlan",
549 entry("VLAN=%" PRIu32, vlan));
Tom Josepha30c8d32018-03-22 02:15:03 +0530550 elog<InternalFailure>();
551 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700552 return vlan;
Tom Josepha30c8d32018-03-22 02:15:03 +0530553}
554
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700555/** @brief Deletes all of the possible configuration parameters for a channel
556 *
557 * @param[in] bus - The bus object used for lookups
558 * @param[in] params - The parameters for the channel
559 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500560void deconfigureChannel(sdbusplus::bus_t& bus, ChannelParams& params)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500561{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700562 // Delete all objects associated with the interface
563 auto objreq = bus.new_method_call(MAPPER_BUS_NAME, MAPPER_OBJ, MAPPER_INTF,
564 "GetSubTree");
565 objreq.append(PATH_ROOT, 0, std::vector<std::string>{DELETE_INTERFACE});
566 auto objreply = bus.call(objreq);
567 ObjectTree objs;
568 objreply.read(objs);
569 for (const auto& [path, impls] : objs)
570 {
571 if (path.find(params.ifname) == path.npos)
572 {
573 continue;
574 }
575 for (const auto& [service, intfs] : impls)
576 {
577 deleteObjectIfExists(bus, service, path);
578 }
579 // Update params to reflect the deletion of vlan
580 if (path == params.logicalPath)
581 {
582 params.logicalPath = params.ifPath;
583 }
584 }
585
586 // Clear out any settings on the lower physical interface
Johnathan Mantey65265362019-11-14 11:24:19 -0800587 setDHCPv6Property(bus, params, EthernetInterface::DHCPConf::none, false);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500588}
589
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700590/** @brief Creates a new VLAN on the specified interface
591 *
592 * @param[in] bus - The bus object used for lookups
593 * @param[in] params - The parameters for the channel
594 * @param[in] vlan - The id of the new vlan
595 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500596void createVLAN(sdbusplus::bus_t& bus, ChannelParams& params, uint16_t vlan)
Ratan Guptab8e99552017-07-27 07:07:48 +0530597{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700598 if (vlan == 0)
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +0530599 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700600 return;
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +0530601 }
602
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700603 auto req = bus.new_method_call(params.service.c_str(), PATH_ROOT,
604 INTF_VLAN_CREATE, "VLAN");
605 req.append(params.ifname, static_cast<uint32_t>(vlan));
606 auto reply = bus.call(req);
607 sdbusplus::message::object_path newPath;
608 reply.read(newPath);
609 params.logicalPath = std::move(newPath);
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +0530610}
611
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700612/** @brief Performs the necessary reconfiguration to change the VLAN
613 *
614 * @param[in] bus - The bus object used for lookups
615 * @param[in] params - The parameters for the channel
616 * @param[in] vlan - The new vlan id to use
617 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500618void reconfigureVLAN(sdbusplus::bus_t& bus, ChannelParams& params,
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700619 uint16_t vlan)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500620{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700621 // Unfortunatetly we don't have built-in functions to migrate our interface
622 // customizations to new VLAN interfaces, or have some kind of decoupling.
623 // We therefore must retain all of our old information, setup the new VLAN
624 // configuration, then restore the old info.
Nan Li3d0df912016-10-18 19:51:41 +0800625
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700626 // Save info from the old logical interface
627 ObjectLookupCache ips(bus, params, INTF_IP);
628 auto ifaddr4 = findIfAddr<AF_INET>(bus, params, 0, originsV4, ips);
William A. Kennington III16064aa2019-04-13 17:44:53 -0700629 std::vector<IfAddr<AF_INET6>> ifaddrs6;
630 for (uint8_t i = 0; i < MAX_IPV6_STATIC_ADDRESSES; ++i)
631 {
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500632 auto ifaddr6 = findIfAddr<AF_INET6>(bus, params, i, originsV6Static,
633 ips);
William A. Kennington III16064aa2019-04-13 17:44:53 -0700634 if (!ifaddr6)
635 {
636 break;
637 }
638 ifaddrs6.push_back(std::move(*ifaddr6));
639 }
Johnathan Mantey65265362019-11-14 11:24:19 -0800640 EthernetInterface::DHCPConf dhcp = getDHCPProperty(bus, params);
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700641 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
642 auto neighbor4 = findGatewayNeighbor<AF_INET>(bus, params, neighbors);
William A. Kennington III16064aa2019-04-13 17:44:53 -0700643 auto neighbor6 = findGatewayNeighbor<AF_INET6>(bus, params, neighbors);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500644
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700645 deconfigureChannel(bus, params);
646 createVLAN(bus, params, vlan);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500647
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700648 // Re-establish the saved settings
Johnathan Mantey65265362019-11-14 11:24:19 -0800649 setDHCPv6Property(bus, params, dhcp, false);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700650 if (ifaddr4)
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800651 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700652 createIfAddr<AF_INET>(bus, params, ifaddr4->address, ifaddr4->prefix);
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800653 }
William A. Kennington III16064aa2019-04-13 17:44:53 -0700654 for (const auto& ifaddr6 : ifaddrs6)
655 {
656 createIfAddr<AF_INET6>(bus, params, ifaddr6.address, ifaddr6.prefix);
657 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700658 if (neighbor4)
659 {
660 createNeighbor<AF_INET>(bus, params, neighbor4->ip, neighbor4->mac);
661 }
William A. Kennington III16064aa2019-04-13 17:44:53 -0700662 if (neighbor6)
663 {
664 createNeighbor<AF_INET6>(bus, params, neighbor6->ip, neighbor6->mac);
665 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700666}
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800667
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700668/** @brief Turns a prefix into a netmask
669 *
670 * @param[in] prefix - The prefix length
671 * @return The netmask
672 */
673in_addr prefixToNetmask(uint8_t prefix)
674{
675 if (prefix > 32)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500676 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700677 log<level::ERR>("Invalid prefix", entry("PREFIX=%" PRIu8, prefix));
678 elog<InternalFailure>();
679 }
680 if (prefix == 0)
681 {
682 // Avoids 32-bit lshift by 32 UB
683 return {};
684 }
685 return {htobe32(~UINT32_C(0) << (32 - prefix))};
686}
687
688/** @brief Turns a a netmask into a prefix length
689 *
690 * @param[in] netmask - The netmask in byte form
691 * @return The prefix length
692 */
693uint8_t netmaskToPrefix(in_addr netmask)
694{
695 uint32_t x = be32toh(netmask.s_addr);
696 if ((~x & (~x + 1)) != 0)
697 {
698 char maskStr[INET_ADDRSTRLEN];
699 inet_ntop(AF_INET, &netmask, maskStr, sizeof(maskStr));
700 log<level::ERR>("Invalid netmask", entry("NETMASK=%s", maskStr));
701 elog<InternalFailure>();
702 }
Johnathan Mantey62c05dd2019-11-20 14:07:44 -0800703 return static_cast<bool>(x)
704 ? AddrFamily<AF_INET>::defaultPrefix - __builtin_ctz(x)
705 : 0;
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700706}
707
708// We need to store this value so it can be returned to the client
709// It is volatile so safe to store in daemon memory.
710static std::unordered_map<uint8_t, SetStatus> setStatus;
711
712// Until we have good support for fixed versions of IPMI tool
713// we need to return the VLAN id for disabled VLANs. The value is only
714// used for verification that a disable operation succeeded and will only
715// be sent if our system indicates that vlans are disabled.
716static std::unordered_map<uint8_t, uint16_t> lastDisabledVlan;
717
718/** @brief Gets the set status for the channel if it exists
719 * Otherise populates and returns the default value.
720 *
721 * @param[in] channel - The channel id corresponding to an ethernet interface
722 * @return A reference to the SetStatus for the channel
723 */
724SetStatus& getSetStatus(uint8_t channel)
725{
726 auto it = setStatus.find(channel);
727 if (it != setStatus.end())
728 {
729 return it->second;
730 }
731 return setStatus[channel] = SetStatus::Complete;
732}
733
Johnathan Mantey3b7a4072021-01-26 14:24:53 -0800734/** @brief Gets the IPv6 Router Advertisement value
735 *
736 * @param[in] bus - The bus object used for lookups
737 * @param[in] params - The parameters for the channel
738 * @return networkd IPV6AcceptRA value
739 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500740static bool getIPv6AcceptRA(sdbusplus::bus_t& bus, const ChannelParams& params)
Johnathan Mantey3b7a4072021-01-26 14:24:53 -0800741{
742 auto raEnabled =
743 std::get<bool>(getDbusProperty(bus, params.service, params.logicalPath,
744 INTF_ETHERNET, "IPv6AcceptRA"));
745 return raEnabled;
746}
747
748/** @brief Sets the IPv6AcceptRA flag
749 *
750 * @param[in] bus - The bus object used for lookups
751 * @param[in] params - The parameters for the channel
752 * @param[in] ipv6AcceptRA - boolean to enable/disable IPv6 Routing
753 * Advertisement
754 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500755void setIPv6AcceptRA(sdbusplus::bus_t& bus, const ChannelParams& params,
Johnathan Mantey3b7a4072021-01-26 14:24:53 -0800756 const bool ipv6AcceptRA)
757{
758 setDbusProperty(bus, params.service, params.logicalPath, INTF_ETHERNET,
759 "IPv6AcceptRA", ipv6AcceptRA);
760}
761
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700762/**
763 * Define placeholder command handlers for the OEM Extension bytes for the Set
764 * LAN Configuration Parameters and Get LAN Configuration Parameters
765 * commands. Using "weak" linking allows the placeholder setLanOem/getLanOem
766 * functions below to be overridden.
767 * To create handlers for your own proprietary command set:
768 * Create/modify a phosphor-ipmi-host Bitbake append file within your Yocto
769 * recipe
770 * Create C++ file(s) that define IPMI handler functions matching the
771 * function names below (i.e. setLanOem). The default name for the
772 * transport IPMI commands is transporthandler_oem.cpp.
773 * Add:
Johnathan Manteyefe26682022-08-11 14:30:45 -0700774 * EXTRA_OEMESON:append = "-Dtransport-oem=enabled"
775 * Create a do_configure:prepend()/do_install:append() method in your
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700776 * bbappend file to copy the file to the build directory.
777 * Add:
778 * PROJECT_SRC_DIR := "${THISDIR}/${PN}"
779 * # Copy the "strong" functions into the working directory, overriding the
780 * # placeholder functions.
Johnathan Manteyefe26682022-08-11 14:30:45 -0700781 * do_configure:prepend(){
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700782 * cp -f ${PROJECT_SRC_DIR}/transporthandler_oem.cpp ${S}
783 * }
784 *
785 * # Clean up after complilation has completed
Johnathan Manteyefe26682022-08-11 14:30:45 -0700786 * do_install:append(){
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700787 * rm -f ${S}/transporthandler_oem.cpp
788 * }
789 *
790 */
791
792/**
793 * Define the placeholder OEM commands as having weak linkage. Create
794 * setLanOem, and getLanOem functions in the transporthandler_oem.cpp
795 * file. The functions defined there must not have the "weak" attribute
796 * applied to them.
797 */
798RspType<> setLanOem(uint8_t channel, uint8_t parameter, message::Payload& req)
799 __attribute__((weak));
800RspType<message::Payload> getLanOem(uint8_t channel, uint8_t parameter,
801 uint8_t set, uint8_t block)
802 __attribute__((weak));
803
Willy Tu11d68892022-01-20 10:37:34 -0800804RspType<> setLanOem(uint8_t, uint8_t, message::Payload& req)
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700805{
806 req.trailingOk = true;
807 return response(ccParamNotSupported);
808}
809
Willy Tu11d68892022-01-20 10:37:34 -0800810RspType<message::Payload> getLanOem(uint8_t, uint8_t, uint8_t, uint8_t)
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700811{
812 return response(ccParamNotSupported);
813}
Rajashekar Gade Reddy0b993fd2019-12-24 16:37:15 +0530814/**
815 * @brief is MAC address valid.
816 *
817 * This function checks whether the MAC address is valid or not.
818 *
819 * @param[in] mac - MAC address.
820 * @return true if MAC address is valid else retun false.
821 **/
822bool isValidMACAddress(const ether_addr& mac)
823{
824 // check if mac address is empty
825 if (equal(mac, ether_addr{}))
826 {
827 return false;
828 }
829 // we accept only unicast MAC addresses and same thing has been checked in
830 // phosphor-network layer. If the least significant bit of the first octet
831 // is set to 1, it is multicast MAC else it is unicast MAC address.
832 if (mac.ether_addr_octet[0] & 1)
833 {
834 return false;
835 }
836 return true;
837}
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700838
vijayabharathix shettycc769252020-02-27 17:52:20 +0000839RspType<> setLan(Context::ptr ctx, uint4_t channelBits, uint4_t reserved1,
840 uint8_t parameter, message::Payload& req)
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700841{
vijayabharathix shettycc769252020-02-27 17:52:20 +0000842 const uint8_t channel = convertCurrentChannelNum(
843 static_cast<uint8_t>(channelBits), ctx->channel);
844 if (reserved1 || !isValidChannel(channel))
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700845 {
vijayabharathix shettycc769252020-02-27 17:52:20 +0000846 log<level::ERR>("Set Lan - Invalid field in request");
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700847 req.trailingOk = true;
848 return responseInvalidFieldRequest();
849 }
850
851 switch (static_cast<LanParam>(parameter))
852 {
853 case LanParam::SetStatus:
854 {
855 uint2_t flag;
856 uint6_t rsvd;
857 if (req.unpack(flag, rsvd) != 0 || !req.fullyUnpacked())
858 {
859 return responseReqDataLenInvalid();
860 }
Johnathan Mantey4a156852019-12-11 13:47:43 -0800861 if (rsvd)
862 {
863 return responseInvalidFieldRequest();
864 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700865 auto status = static_cast<SetStatus>(static_cast<uint8_t>(flag));
866 switch (status)
867 {
868 case SetStatus::Complete:
869 {
870 getSetStatus(channel) = status;
871 return responseSuccess();
872 }
873 case SetStatus::InProgress:
874 {
875 auto& storedStatus = getSetStatus(channel);
876 if (storedStatus == SetStatus::InProgress)
877 {
878 return response(ccParamSetLocked);
879 }
880 storedStatus = status;
881 return responseSuccess();
882 }
883 case SetStatus::Commit:
884 if (getSetStatus(channel) != SetStatus::InProgress)
885 {
886 return responseInvalidFieldRequest();
887 }
888 return responseSuccess();
889 }
890 return response(ccParamNotSupported);
891 }
892 case LanParam::AuthSupport:
893 {
894 req.trailingOk = true;
895 return response(ccParamReadOnly);
896 }
897 case LanParam::AuthEnables:
898 {
899 req.trailingOk = true;
Johnathan Mantey76ce9c72019-11-14 14:41:46 -0800900 return response(ccParamReadOnly);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700901 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -0800902 case LanParam::IP:
Hariharasubramanian R83951912016-01-20 07:06:36 -0600903 {
Johnathan Mantey65265362019-11-14 11:24:19 -0800904 EthernetInterface::DHCPConf dhcp =
905 channelCall<getDHCPProperty>(channel);
906 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
907 (dhcp == EthernetInterface::DHCPConf::both))
Johnathan Mantey930104a2019-12-17 09:18:34 -0800908 {
909 return responseCommandNotAvailable();
910 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700911 in_addr ip;
912 std::array<uint8_t, sizeof(ip)> bytes;
913 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
914 {
915 return responseReqDataLenInvalid();
916 }
917 copyInto(ip, bytes);
918 channelCall<reconfigureIfAddr4>(channel, ip, std::nullopt);
919 return responseSuccess();
Ratan Guptab8e99552017-07-27 07:07:48 +0530920 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700921 case LanParam::IPSrc:
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530922 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700923 uint4_t flag;
924 uint4_t rsvd;
925 if (req.unpack(flag, rsvd) != 0 || !req.fullyUnpacked())
926 {
927 return responseReqDataLenInvalid();
928 }
Johnathan Mantey4a156852019-12-11 13:47:43 -0800929 if (rsvd)
930 {
931 return responseInvalidFieldRequest();
932 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700933 switch (static_cast<IPSrc>(static_cast<uint8_t>(flag)))
934 {
935 case IPSrc::DHCP:
936 {
Johnathan Mantey65265362019-11-14 11:24:19 -0800937 // The IPSrc IPMI command is only for IPv4
938 // management. Modifying IPv6 state is done using
939 // a completely different Set LAN Configuration
940 // subcommand.
941 channelCall<setDHCPv4Property>(
942 channel, EthernetInterface::DHCPConf::v4);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700943 return responseSuccess();
944 }
945 case IPSrc::Unspecified:
946 case IPSrc::Static:
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700947 {
Johnathan Mantey65265362019-11-14 11:24:19 -0800948 channelCall<setDHCPv4Property>(
949 channel, EthernetInterface::DHCPConf::none);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700950 return responseSuccess();
951 }
Rajashekar Gade Reddy8a860ea2019-12-24 11:31:19 +0530952 case IPSrc::BIOS:
953 case IPSrc::BMC:
954 {
955 return responseInvalidFieldRequest();
956 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700957 }
958 return response(ccParamNotSupported);
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530959 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -0800960 case LanParam::MAC:
Ratan Guptab8e99552017-07-27 07:07:48 +0530961 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700962 ether_addr mac;
963 std::array<uint8_t, sizeof(mac)> bytes;
964 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
Suryakanth Sekar0a327e12019-08-08 14:30:19 +0530965 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700966 return responseReqDataLenInvalid();
Suryakanth Sekar0a327e12019-08-08 14:30:19 +0530967 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700968 copyInto(mac, bytes);
Rajashekar Gade Reddy0b993fd2019-12-24 16:37:15 +0530969
970 if (!isValidMACAddress(mac))
971 {
972 return responseInvalidFieldRequest();
973 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700974 channelCall<setMACProperty>(channel, mac);
975 return responseSuccess();
Ratan Gupta533d03b2017-07-30 10:39:22 +0530976 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700977 case LanParam::SubnetMask:
Ratan Guptab8e99552017-07-27 07:07:48 +0530978 {
Johnathan Mantey65265362019-11-14 11:24:19 -0800979 EthernetInterface::DHCPConf dhcp =
980 channelCall<getDHCPProperty>(channel);
981 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
982 (dhcp == EthernetInterface::DHCPConf::both))
Johnathan Mantey930104a2019-12-17 09:18:34 -0800983 {
984 return responseCommandNotAvailable();
985 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700986 in_addr netmask;
987 std::array<uint8_t, sizeof(netmask)> bytes;
988 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
Ratan Guptab8e99552017-07-27 07:07:48 +0530989 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700990 return responseReqDataLenInvalid();
Ratan Guptab8e99552017-07-27 07:07:48 +0530991 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700992 copyInto(netmask, bytes);
Jiaqing Zhao6d4a44e2022-01-24 15:04:00 +0800993 uint8_t prefix = netmaskToPrefix(netmask);
994 if (prefix < MIN_IPV4_PREFIX_LENGTH)
995 {
996 return responseInvalidFieldRequest();
997 }
998 channelCall<reconfigureIfAddr4>(channel, std::nullopt, prefix);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700999 return responseSuccess();
Ratan Guptab8e99552017-07-27 07:07:48 +05301000 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001001 case LanParam::Gateway1:
Ratan Guptab8e99552017-07-27 07:07:48 +05301002 {
Johnathan Mantey65265362019-11-14 11:24:19 -08001003 EthernetInterface::DHCPConf dhcp =
1004 channelCall<getDHCPProperty>(channel);
1005 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
1006 (dhcp == EthernetInterface::DHCPConf::both))
Johnathan Mantey930104a2019-12-17 09:18:34 -08001007 {
1008 return responseCommandNotAvailable();
1009 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001010 in_addr gateway;
1011 std::array<uint8_t, sizeof(gateway)> bytes;
1012 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1013 {
1014 return responseReqDataLenInvalid();
1015 }
1016 copyInto(gateway, bytes);
1017 channelCall<setGatewayProperty<AF_INET>>(channel, gateway);
1018 return responseSuccess();
1019 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001020 case LanParam::Gateway1MAC:
1021 {
1022 ether_addr gatewayMAC;
1023 std::array<uint8_t, sizeof(gatewayMAC)> bytes;
1024 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1025 {
1026 return responseReqDataLenInvalid();
1027 }
1028 copyInto(gatewayMAC, bytes);
1029 channelCall<reconfigureGatewayMAC<AF_INET>>(channel, gatewayMAC);
1030 return responseSuccess();
1031 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001032 case LanParam::VLANId:
1033 {
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301034 uint12_t vlanData = 0;
1035 uint3_t reserved = 0;
1036 bool vlanEnable = 0;
1037
1038 if (req.unpack(vlanData) || req.unpack(reserved) ||
1039 req.unpack(vlanEnable) || !req.fullyUnpacked())
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001040 {
1041 return responseReqDataLenInvalid();
1042 }
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301043
1044 if (reserved)
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001045 {
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301046 return responseInvalidFieldRequest();
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001047 }
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301048
1049 uint16_t vlan = static_cast<uint16_t>(vlanData);
1050
1051 if (!vlanEnable)
1052 {
1053 lastDisabledVlan[channel] = vlan;
1054 vlan = 0;
1055 }
jayaprakash Mutyala84c49dc2020-05-18 23:12:13 +00001056 else if (vlan == 0 || vlan == VLAN_VALUE_MASK)
1057 {
1058 return responseInvalidFieldRequest();
1059 }
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301060
jayaprakash Mutyala84c49dc2020-05-18 23:12:13 +00001061 channelCall<reconfigureVLAN>(channel, vlan);
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001062 return responseSuccess();
1063 }
1064 case LanParam::CiphersuiteSupport:
1065 case LanParam::CiphersuiteEntries:
William A. Kennington III16064aa2019-04-13 17:44:53 -07001066 case LanParam::IPFamilySupport:
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001067 {
1068 req.trailingOk = true;
1069 return response(ccParamReadOnly);
Ratan Guptab8e99552017-07-27 07:07:48 +05301070 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001071 case LanParam::IPFamilyEnables:
1072 {
1073 uint8_t enables;
1074 if (req.unpack(enables) != 0 || !req.fullyUnpacked())
1075 {
1076 return responseReqDataLenInvalid();
1077 }
1078 switch (static_cast<IPFamilyEnables>(enables))
1079 {
1080 case IPFamilyEnables::DualStack:
1081 return responseSuccess();
1082 case IPFamilyEnables::IPv4Only:
1083 case IPFamilyEnables::IPv6Only:
1084 return response(ccParamNotSupported);
1085 }
1086 return response(ccParamNotSupported);
1087 }
1088 case LanParam::IPv6Status:
1089 {
1090 req.trailingOk = true;
1091 return response(ccParamReadOnly);
1092 }
1093 case LanParam::IPv6StaticAddresses:
1094 {
1095 uint8_t set;
1096 uint7_t rsvd;
1097 bool enabled;
1098 in6_addr ip;
1099 std::array<uint8_t, sizeof(ip)> ipbytes;
1100 uint8_t prefix;
1101 uint8_t status;
1102 if (req.unpack(set, rsvd, enabled, ipbytes, prefix, status) != 0 ||
1103 !req.fullyUnpacked())
1104 {
1105 return responseReqDataLenInvalid();
1106 }
Johnathan Mantey4a156852019-12-11 13:47:43 -08001107 if (rsvd)
1108 {
1109 return responseInvalidFieldRequest();
1110 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001111 copyInto(ip, ipbytes);
1112 if (enabled)
1113 {
Jiaqing Zhao6d4a44e2022-01-24 15:04:00 +08001114 if (prefix < MIN_IPV6_PREFIX_LENGTH ||
1115 prefix > MAX_IPV6_PREFIX_LENGTH)
1116 {
1117 return responseParmOutOfRange();
1118 }
Johnathan Manteya291f492021-10-15 13:45:27 -07001119 try
1120 {
1121 channelCall<reconfigureIfAddr6>(channel, set, ip, prefix);
1122 }
Patrick Williams5d82f472022-07-22 19:26:53 -05001123 catch (const sdbusplus::exception_t& e)
Johnathan Manteya291f492021-10-15 13:45:27 -07001124 {
1125 if (std::string_view err{
1126 "xyz.openbmc_project.Common.Error.InvalidArgument"};
1127 err == e.name())
1128 {
1129 return responseInvalidFieldRequest();
1130 }
1131 else
1132 {
1133 throw;
1134 }
1135 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001136 }
1137 else
1138 {
1139 channelCall<deconfigureIfAddr6>(channel, set);
1140 }
1141 return responseSuccess();
1142 }
1143 case LanParam::IPv6DynamicAddresses:
1144 {
1145 req.trailingOk = true;
1146 return response(ccParamReadOnly);
1147 }
1148 case LanParam::IPv6RouterControl:
1149 {
1150 std::bitset<8> control;
Johnathan Mantey3b7a4072021-01-26 14:24:53 -08001151 constexpr uint8_t reservedRACCBits = 0xfc;
William A. Kennington III16064aa2019-04-13 17:44:53 -07001152 if (req.unpack(control) != 0 || !req.fullyUnpacked())
1153 {
1154 return responseReqDataLenInvalid();
1155 }
Johnathan Mantey3b7a4072021-01-26 14:24:53 -08001156 if (std::bitset<8> expected(control &
1157 std::bitset<8>(reservedRACCBits));
1158 expected.any())
William A. Kennington III16064aa2019-04-13 17:44:53 -07001159 {
Johnathan Mantey3b7a4072021-01-26 14:24:53 -08001160 return response(ccParamNotSupported);
William A. Kennington III16064aa2019-04-13 17:44:53 -07001161 }
Johnathan Mantey3b7a4072021-01-26 14:24:53 -08001162
1163 bool enableRA = control[IPv6RouterControlFlag::Dynamic];
1164 channelCall<setIPv6AcceptRA>(channel, enableRA);
William A. Kennington III16064aa2019-04-13 17:44:53 -07001165 return responseSuccess();
1166 }
1167 case LanParam::IPv6StaticRouter1IP:
1168 {
1169 in6_addr gateway;
1170 std::array<uint8_t, sizeof(gateway)> bytes;
1171 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1172 {
1173 return responseReqDataLenInvalid();
1174 }
1175 copyInto(gateway, bytes);
1176 channelCall<setGatewayProperty<AF_INET6>>(channel, gateway);
1177 return responseSuccess();
1178 }
1179 case LanParam::IPv6StaticRouter1MAC:
1180 {
1181 ether_addr mac;
1182 std::array<uint8_t, sizeof(mac)> bytes;
1183 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1184 {
1185 return responseReqDataLenInvalid();
1186 }
1187 copyInto(mac, bytes);
1188 channelCall<reconfigureGatewayMAC<AF_INET6>>(channel, mac);
1189 return responseSuccess();
1190 }
1191 case LanParam::IPv6StaticRouter1PrefixLength:
1192 {
1193 uint8_t prefix;
1194 if (req.unpack(prefix) != 0 || !req.fullyUnpacked())
1195 {
1196 return responseReqDataLenInvalid();
1197 }
1198 if (prefix != 0)
1199 {
1200 return responseInvalidFieldRequest();
1201 }
1202 return responseSuccess();
1203 }
1204 case LanParam::IPv6StaticRouter1PrefixValue:
1205 {
1206 std::array<uint8_t, sizeof(in6_addr)> bytes;
1207 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1208 {
1209 return responseReqDataLenInvalid();
1210 }
1211 // Accept any prefix value since our prefix length has to be 0
1212 return responseSuccess();
1213 }
jayaprakash Mutyalab741b992019-12-02 17:29:09 +00001214 case LanParam::cipherSuitePrivilegeLevels:
1215 {
1216 uint8_t reserved;
1217 std::array<uint4_t, ipmi::maxCSRecords> cipherSuitePrivs;
1218
1219 if (req.unpack(reserved, cipherSuitePrivs) || !req.fullyUnpacked())
1220 {
1221 return responseReqDataLenInvalid();
1222 }
1223
1224 if (reserved)
1225 {
1226 return responseInvalidFieldRequest();
1227 }
1228
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -05001229 uint8_t resp = getCipherConfigObject(csPrivFileName,
1230 csPrivDefaultFileName)
1231 .setCSPrivilegeLevels(channel, cipherSuitePrivs);
jayaprakash Mutyalab741b992019-12-02 17:29:09 +00001232 if (!resp)
1233 {
1234 return responseSuccess();
1235 }
1236 else
1237 {
1238 req.trailingOk = true;
1239 return response(resp);
1240 }
1241 }
Ratan Guptab8e99552017-07-27 07:07:48 +05301242 }
vishwa1eaea4f2016-02-26 11:57:40 -06001243
Johnathan Manteyb87034e2019-09-16 10:50:50 -07001244 if ((parameter >= oemCmdStart) && (parameter <= oemCmdEnd))
1245 {
1246 return setLanOem(channel, parameter, req);
1247 }
1248
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001249 req.trailingOk = true;
1250 return response(ccParamNotSupported);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001251}
1252
vijayabharathix shettycc769252020-02-27 17:52:20 +00001253RspType<message::Payload> getLan(Context::ptr ctx, uint4_t channelBits,
1254 uint3_t reserved, bool revOnly,
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001255 uint8_t parameter, uint8_t set, uint8_t block)
Ratan Guptab8e99552017-07-27 07:07:48 +05301256{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001257 message::Payload ret;
1258 constexpr uint8_t current_revision = 0x11;
1259 ret.pack(current_revision);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001260
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001261 if (revOnly)
Suryakanth Sekare4054402019-08-08 15:16:52 +05301262 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001263 return responseSuccess(std::move(ret));
Suryakanth Sekare4054402019-08-08 15:16:52 +05301264 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001265
vijayabharathix shettycc769252020-02-27 17:52:20 +00001266 const uint8_t channel = convertCurrentChannelNum(
1267 static_cast<uint8_t>(channelBits), ctx->channel);
1268 if (reserved || !isValidChannel(channel))
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001269 {
vijayabharathix shettycc769252020-02-27 17:52:20 +00001270 log<level::ERR>("Get Lan - Invalid field in request");
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001271 return responseInvalidFieldRequest();
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001272 }
1273
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001274 static std::vector<uint8_t> cipherList;
1275 static bool listInit = false;
1276 if (!listInit)
1277 {
1278 try
1279 {
1280 cipherList = cipher::getCipherList();
1281 listInit = true;
1282 }
1283 catch (const std::exception& e)
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -05001284 {}
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001285 }
1286
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001287 switch (static_cast<LanParam>(parameter))
Tom Josepha30c8d32018-03-22 02:15:03 +05301288 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001289 case LanParam::SetStatus:
Tom Josepha30c8d32018-03-22 02:15:03 +05301290 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001291 SetStatus status;
1292 try
1293 {
1294 status = setStatus.at(channel);
1295 }
1296 catch (const std::out_of_range&)
1297 {
1298 status = SetStatus::Complete;
1299 }
William A. Kennington III7a0e5df2021-05-19 13:31:29 -07001300 ret.pack(types::enum_cast<uint2_t>(status), uint6_t{});
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001301 return responseSuccess(std::move(ret));
Tom Josepha30c8d32018-03-22 02:15:03 +05301302 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001303 case LanParam::AuthSupport:
Tom Josepha30c8d32018-03-22 02:15:03 +05301304 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001305 std::bitset<6> support;
1306 ret.pack(support, uint2_t{});
1307 return responseSuccess(std::move(ret));
Tom Josepha30c8d32018-03-22 02:15:03 +05301308 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001309 case LanParam::AuthEnables:
vishwa1eaea4f2016-02-26 11:57:40 -06001310 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001311 std::bitset<6> enables;
1312 ret.pack(enables, uint2_t{}); // Callback
1313 ret.pack(enables, uint2_t{}); // User
1314 ret.pack(enables, uint2_t{}); // Operator
1315 ret.pack(enables, uint2_t{}); // Admin
1316 ret.pack(enables, uint2_t{}); // OEM
1317 return responseSuccess(std::move(ret));
William A. Kennington III39f94ef2018-11-19 22:36:16 -08001318 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001319 case LanParam::IP:
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001320 {
1321 auto ifaddr = channelCall<getIfAddr4>(channel);
1322 in_addr addr{};
1323 if (ifaddr)
1324 {
1325 addr = ifaddr->address;
1326 }
1327 ret.pack(dataRef(addr));
1328 return responseSuccess(std::move(ret));
1329 }
1330 case LanParam::IPSrc:
1331 {
1332 auto src = IPSrc::Static;
Johnathan Mantey65265362019-11-14 11:24:19 -08001333 EthernetInterface::DHCPConf dhcp =
1334 channelCall<getDHCPProperty>(channel);
1335 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
1336 (dhcp == EthernetInterface::DHCPConf::both))
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001337 {
1338 src = IPSrc::DHCP;
1339 }
William A. Kennington III7a0e5df2021-05-19 13:31:29 -07001340 ret.pack(types::enum_cast<uint4_t>(src), uint4_t{});
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001341 return responseSuccess(std::move(ret));
1342 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001343 case LanParam::MAC:
William A. Kennington III39f94ef2018-11-19 22:36:16 -08001344 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001345 ether_addr mac = channelCall<getMACProperty>(channel);
1346 ret.pack(dataRef(mac));
1347 return responseSuccess(std::move(ret));
1348 }
1349 case LanParam::SubnetMask:
1350 {
1351 auto ifaddr = channelCall<getIfAddr4>(channel);
1352 uint8_t prefix = AddrFamily<AF_INET>::defaultPrefix;
1353 if (ifaddr)
Ratan Guptab8e99552017-07-27 07:07:48 +05301354 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001355 prefix = ifaddr->prefix;
1356 }
1357 in_addr netmask = prefixToNetmask(prefix);
1358 ret.pack(dataRef(netmask));
1359 return responseSuccess(std::move(ret));
1360 }
1361 case LanParam::Gateway1:
1362 {
1363 auto gateway =
1364 channelCall<getGatewayProperty<AF_INET>>(channel).value_or(
1365 in_addr{});
1366 ret.pack(dataRef(gateway));
1367 return responseSuccess(std::move(ret));
1368 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001369 case LanParam::Gateway1MAC:
1370 {
1371 ether_addr mac{};
1372 auto neighbor = channelCall<getGatewayNeighbor<AF_INET>>(channel);
1373 if (neighbor)
1374 {
1375 mac = neighbor->mac;
1376 }
1377 ret.pack(dataRef(mac));
1378 return responseSuccess(std::move(ret));
1379 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001380 case LanParam::VLANId:
1381 {
1382 uint16_t vlan = channelCall<getVLANProperty>(channel);
1383 if (vlan != 0)
1384 {
1385 vlan |= VLAN_ENABLE_FLAG;
Ratan Guptab8e99552017-07-27 07:07:48 +05301386 }
1387 else
1388 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001389 vlan = lastDisabledVlan[channel];
Ratan Guptab8e99552017-07-27 07:07:48 +05301390 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001391 ret.pack(vlan);
1392 return responseSuccess(std::move(ret));
Adriana Kobylak342df102016-02-10 13:48:16 -06001393 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001394 case LanParam::CiphersuiteSupport:
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001395 {
srikanta mondal1d8579c2020-04-15 17:13:25 +00001396 if (getChannelSessionSupport(channel) ==
1397 EChannelSessSupported::none)
1398 {
1399 return responseInvalidFieldRequest();
1400 }
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001401 if (!listInit)
1402 {
1403 return responseUnspecifiedError();
1404 }
1405 ret.pack(static_cast<uint8_t>(cipherList.size() - 1));
1406 return responseSuccess(std::move(ret));
1407 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001408 case LanParam::CiphersuiteEntries:
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001409 {
srikanta mondal1d8579c2020-04-15 17:13:25 +00001410 if (getChannelSessionSupport(channel) ==
1411 EChannelSessSupported::none)
1412 {
1413 return responseInvalidFieldRequest();
1414 }
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001415 if (!listInit)
1416 {
1417 return responseUnspecifiedError();
1418 }
1419 ret.pack(cipherList);
1420 return responseSuccess(std::move(ret));
1421 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001422 case LanParam::IPFamilySupport:
1423 {
1424 std::bitset<8> support;
1425 support[IPFamilySupportFlag::IPv6Only] = 0;
1426 support[IPFamilySupportFlag::DualStack] = 1;
1427 support[IPFamilySupportFlag::IPv6Alerts] = 1;
1428 ret.pack(support);
1429 return responseSuccess(std::move(ret));
1430 }
1431 case LanParam::IPFamilyEnables:
1432 {
1433 ret.pack(static_cast<uint8_t>(IPFamilyEnables::DualStack));
1434 return responseSuccess(std::move(ret));
1435 }
1436 case LanParam::IPv6Status:
1437 {
1438 ret.pack(MAX_IPV6_STATIC_ADDRESSES);
1439 ret.pack(MAX_IPV6_DYNAMIC_ADDRESSES);
1440 std::bitset<8> support;
1441 support[IPv6StatusFlag::DHCP] = 1;
1442 support[IPv6StatusFlag::SLAAC] = 1;
1443 ret.pack(support);
1444 return responseSuccess(std::move(ret));
1445 }
1446 case LanParam::IPv6StaticAddresses:
1447 {
1448 if (set >= MAX_IPV6_STATIC_ADDRESSES)
1449 {
1450 return responseParmOutOfRange();
1451 }
1452 getLanIPv6Address(ret, channel, set, originsV6Static);
1453 return responseSuccess(std::move(ret));
1454 }
1455 case LanParam::IPv6DynamicAddresses:
1456 {
1457 if (set >= MAX_IPV6_DYNAMIC_ADDRESSES)
1458 {
1459 return responseParmOutOfRange();
1460 }
1461 getLanIPv6Address(ret, channel, set, originsV6Dynamic);
1462 return responseSuccess(std::move(ret));
1463 }
1464 case LanParam::IPv6RouterControl:
1465 {
1466 std::bitset<8> control;
Johnathan Mantey3b7a4072021-01-26 14:24:53 -08001467 control[IPv6RouterControlFlag::Dynamic] =
1468 channelCall<getIPv6AcceptRA>(channel);
1469 control[IPv6RouterControlFlag::Static] = 1;
William A. Kennington III16064aa2019-04-13 17:44:53 -07001470 ret.pack(control);
1471 return responseSuccess(std::move(ret));
1472 }
1473 case LanParam::IPv6StaticRouter1IP:
1474 {
1475 in6_addr gateway{};
Johnathan Mantey65265362019-11-14 11:24:19 -08001476 EthernetInterface::DHCPConf dhcp =
1477 channelCall<getDHCPProperty>(channel);
1478 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
1479 (dhcp == EthernetInterface::DHCPConf::none))
William A. Kennington III16064aa2019-04-13 17:44:53 -07001480 {
1481 gateway =
1482 channelCall<getGatewayProperty<AF_INET6>>(channel).value_or(
1483 in6_addr{});
1484 }
1485 ret.pack(dataRef(gateway));
1486 return responseSuccess(std::move(ret));
1487 }
1488 case LanParam::IPv6StaticRouter1MAC:
1489 {
1490 ether_addr mac{};
1491 auto neighbor = channelCall<getGatewayNeighbor<AF_INET6>>(channel);
1492 if (neighbor)
1493 {
1494 mac = neighbor->mac;
1495 }
1496 ret.pack(dataRef(mac));
1497 return responseSuccess(std::move(ret));
1498 }
1499 case LanParam::IPv6StaticRouter1PrefixLength:
1500 {
1501 ret.pack(UINT8_C(0));
1502 return responseSuccess(std::move(ret));
1503 }
1504 case LanParam::IPv6StaticRouter1PrefixValue:
1505 {
1506 in6_addr prefix{};
1507 ret.pack(dataRef(prefix));
1508 return responseSuccess(std::move(ret));
1509 }
jayaprakash Mutyalab741b992019-12-02 17:29:09 +00001510 case LanParam::cipherSuitePrivilegeLevels:
1511 {
1512 std::array<uint4_t, ipmi::maxCSRecords> csPrivilegeLevels;
1513
1514 uint8_t resp =
1515 getCipherConfigObject(csPrivFileName, csPrivDefaultFileName)
1516 .getCSPrivilegeLevels(channel, csPrivilegeLevels);
1517 if (!resp)
1518 {
1519 constexpr uint8_t reserved1 = 0x00;
1520 ret.pack(reserved1, csPrivilegeLevels);
1521 return responseSuccess(std::move(ret));
1522 }
1523 else
1524 {
1525 return response(resp);
1526 }
1527 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001528 }
1529
Johnathan Manteyb87034e2019-09-16 10:50:50 -07001530 if ((parameter >= oemCmdStart) && (parameter <= oemCmdEnd))
1531 {
1532 return getLanOem(channel, parameter, set, block);
1533 }
1534
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001535 return response(ccParamNotSupported);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001536}
1537
Jian Zhang23f44652022-03-17 17:13:10 +08001538constexpr const char* solInterface = "xyz.openbmc_project.Ipmi.SOL";
1539constexpr const char* solPath = "/xyz/openbmc_project/ipmi/sol/";
1540constexpr const uint16_t solDefaultPort = 623;
1541
1542RspType<> setSolConfParams(Context::ptr ctx, uint4_t channelBits,
Willy Tu11d68892022-01-20 10:37:34 -08001543 uint4_t /*reserved*/, uint8_t parameter,
Jian Zhang23f44652022-03-17 17:13:10 +08001544 message::Payload& req)
1545{
1546 const uint8_t channel = convertCurrentChannelNum(
1547 static_cast<uint8_t>(channelBits), ctx->channel);
1548
1549 if (!isValidChannel(channel))
1550 {
1551 log<level::ERR>("Set Sol Config - Invalid channel in request");
1552 return responseInvalidFieldRequest();
1553 }
1554
1555 std::string solService{};
1556 std::string solPathWitheEthName = solPath + ipmi::getChannelName(channel);
1557
1558 if (ipmi::getService(ctx, solInterface, solPathWitheEthName, solService))
1559 {
1560 log<level::ERR>("Set Sol Config - Invalid solInterface",
1561 entry("SERVICE=%s", solService.c_str()),
1562 entry("OBJPATH=%s", solPathWitheEthName.c_str()),
1563 entry("INTERFACE=%s", solInterface));
1564 return responseInvalidFieldRequest();
1565 }
1566
1567 switch (static_cast<SolConfParam>(parameter))
1568 {
1569 case SolConfParam::Progress:
1570 {
1571 uint8_t progress;
1572 if (req.unpack(progress) != 0 || !req.fullyUnpacked())
1573 {
1574 return responseReqDataLenInvalid();
1575 }
1576
1577 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1578 solInterface, "Progress", progress))
1579 {
1580 return responseUnspecifiedError();
1581 }
1582 break;
1583 }
1584 case SolConfParam::Enable:
1585 {
1586 bool enable;
1587 uint7_t reserved2;
1588
1589 if (req.unpack(enable, reserved2) != 0 || !req.fullyUnpacked())
1590 {
1591 return responseReqDataLenInvalid();
1592 }
1593
1594 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1595 solInterface, "Enable", enable))
1596 {
1597 return responseUnspecifiedError();
1598 }
1599 break;
1600 }
1601 case SolConfParam::Authentication:
1602 {
1603 uint4_t privilegeBits{};
1604 uint2_t reserved2{};
1605 bool forceAuth = false;
1606 bool forceEncrypt = false;
1607
1608 if (req.unpack(privilegeBits, reserved2, forceAuth, forceEncrypt) !=
1609 0 ||
1610 !req.fullyUnpacked())
1611 {
1612 return responseReqDataLenInvalid();
1613 }
1614
1615 uint8_t privilege = static_cast<uint8_t>(privilegeBits);
Jonathan Domana48bf772023-05-26 17:54:57 -07001616 if (privilege < static_cast<uint8_t>(Privilege::User) ||
Jian Zhang23f44652022-03-17 17:13:10 +08001617 privilege > static_cast<uint8_t>(Privilege::Oem))
1618 {
1619 return ipmi::responseInvalidFieldRequest();
1620 }
1621
1622 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1623 solInterface, "Privilege", privilege))
1624 {
1625 return responseUnspecifiedError();
1626 }
1627
1628 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1629 solInterface, "ForceEncryption",
1630 forceEncrypt))
1631 {
1632 return responseUnspecifiedError();
1633 }
1634
1635 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1636 solInterface, "ForceAuthentication",
1637 forceAuth))
1638 {
1639 return responseUnspecifiedError();
1640 }
1641 break;
1642 }
1643 case SolConfParam::Accumulate:
1644 {
1645 uint8_t interval;
1646 uint8_t threshold;
1647 if (req.unpack(interval, threshold) != 0 || !req.fullyUnpacked())
1648 {
1649 return responseReqDataLenInvalid();
1650 }
1651
1652 if (threshold == 0)
1653 {
1654 return responseInvalidFieldRequest();
1655 }
1656
1657 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1658 solInterface, "AccumulateIntervalMS",
1659 interval))
1660 {
1661 return responseUnspecifiedError();
1662 }
1663
1664 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1665 solInterface, "Threshold", threshold))
1666 {
1667 return responseUnspecifiedError();
1668 }
1669 break;
1670 }
1671 case SolConfParam::Retry:
1672 {
1673 uint3_t countBits;
1674 uint5_t reserved2;
1675 uint8_t interval;
1676
1677 if (req.unpack(countBits, reserved2, interval) != 0 ||
1678 !req.fullyUnpacked())
1679 {
1680 return responseReqDataLenInvalid();
1681 }
1682
1683 uint8_t count = static_cast<uint8_t>(countBits);
1684 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1685 solInterface, "RetryCount", count))
1686 {
1687 return responseUnspecifiedError();
1688 }
1689
1690 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1691 solInterface, "RetryIntervalMS",
1692 interval))
1693 {
1694 return responseUnspecifiedError();
1695 }
1696 break;
1697 }
1698 case SolConfParam::Port:
1699 {
1700 return response(ipmiCCWriteReadParameter);
1701 }
1702 case SolConfParam::NonVbitrate:
1703 case SolConfParam::Vbitrate:
1704 case SolConfParam::Channel:
1705 default:
1706 return response(ipmiCCParamNotSupported);
1707 }
1708 return responseSuccess();
1709}
1710
1711RspType<message::Payload> getSolConfParams(Context::ptr ctx,
1712 uint4_t channelBits,
Willy Tu11d68892022-01-20 10:37:34 -08001713 uint3_t /*reserved*/, bool revOnly,
1714 uint8_t parameter, uint8_t /*set*/,
1715 uint8_t /*block*/)
Jian Zhang23f44652022-03-17 17:13:10 +08001716{
1717 message::Payload ret;
1718 constexpr uint8_t current_revision = 0x11;
1719 ret.pack(current_revision);
1720 if (revOnly)
1721 {
1722 return responseSuccess(std::move(ret));
1723 }
1724
1725 const uint8_t channel = convertCurrentChannelNum(
1726 static_cast<uint8_t>(channelBits), ctx->channel);
1727
1728 if (!isValidChannel(channel))
1729 {
1730 log<level::ERR>("Get Sol Config - Invalid channel in request");
1731 return responseInvalidFieldRequest();
1732 }
1733
1734 std::string solService{};
1735 std::string solPathWitheEthName = solPath + ipmi::getChannelName(channel);
1736
1737 if (ipmi::getService(ctx, solInterface, solPathWitheEthName, solService))
1738 {
1739 log<level::ERR>("Set Sol Config - Invalid solInterface",
1740 entry("SERVICE=%s", solService.c_str()),
1741 entry("OBJPATH=%s", solPathWitheEthName.c_str()),
1742 entry("INTERFACE=%s", solInterface));
1743 return responseInvalidFieldRequest();
1744 }
1745
1746 switch (static_cast<SolConfParam>(parameter))
1747 {
1748 case SolConfParam::Progress:
1749 {
1750 uint8_t progress;
1751 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1752 solInterface, "Progress", progress))
1753 {
1754 return responseUnspecifiedError();
1755 }
1756 ret.pack(progress);
1757 return responseSuccess(std::move(ret));
1758 }
1759 case SolConfParam::Enable:
1760 {
1761 bool enable{};
1762 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1763 solInterface, "Enable", enable))
1764 {
1765 return responseUnspecifiedError();
1766 }
1767 ret.pack(enable, uint7_t{});
1768 return responseSuccess(std::move(ret));
1769 }
1770 case SolConfParam::Authentication:
1771 {
1772 // 4bits, cast when pack
1773 uint8_t privilege;
1774 bool forceAuth = false;
1775 bool forceEncrypt = false;
1776
1777 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1778 solInterface, "Privilege", privilege))
1779 {
1780 return responseUnspecifiedError();
1781 }
1782
1783 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1784 solInterface, "ForceAuthentication",
1785 forceAuth))
1786 {
1787 return responseUnspecifiedError();
1788 }
1789
1790 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1791 solInterface, "ForceEncryption",
1792 forceEncrypt))
1793 {
1794 return responseUnspecifiedError();
1795 }
1796 ret.pack(uint4_t{privilege}, uint2_t{}, forceAuth, forceEncrypt);
1797 return responseSuccess(std::move(ret));
1798 }
1799 case SolConfParam::Accumulate:
1800 {
1801 uint8_t interval{}, threshold{};
1802
1803 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1804 solInterface, "AccumulateIntervalMS",
1805 interval))
1806 {
1807 return responseUnspecifiedError();
1808 }
1809
1810 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1811 solInterface, "Threshold", threshold))
1812 {
1813 return responseUnspecifiedError();
1814 }
1815 ret.pack(interval, threshold);
1816 return responseSuccess(std::move(ret));
1817 }
1818 case SolConfParam::Retry:
1819 {
1820 // 3bits, cast when cast
1821 uint8_t count{};
1822 uint8_t interval{};
1823
1824 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1825 solInterface, "RetryCount", count))
1826 {
1827 return responseUnspecifiedError();
1828 }
1829
1830 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1831 solInterface, "RetryIntervalMS",
1832 interval))
1833 {
1834 return responseUnspecifiedError();
1835 }
1836 ret.pack(uint3_t{count}, uint5_t{}, interval);
1837 return responseSuccess(std::move(ret));
1838 }
1839 case SolConfParam::Port:
1840 {
1841 auto port = solDefaultPort;
1842 ret.pack(static_cast<uint16_t>(port));
1843 return responseSuccess(std::move(ret));
1844 }
1845 case SolConfParam::Channel:
1846 {
1847 ret.pack(channel);
1848 return responseSuccess(std::move(ret));
1849 }
1850 case SolConfParam::NonVbitrate:
Jonathan Domana48bf772023-05-26 17:54:57 -07001851 {
1852 uint64_t baudRate;
1853 uint8_t encodedBitRate = 0;
1854 if (ipmi::getDbusProperty(
1855 ctx, "xyz.openbmc_project.Console.default",
1856 "/xyz/openbmc_project/console/default",
1857 "xyz.openbmc_project.Console.UART", "Baud", baudRate))
1858 {
1859 return ipmi::responseUnspecifiedError();
1860 }
1861 switch (baudRate)
1862 {
1863 case 9600:
1864 encodedBitRate = 0x06;
1865 break;
1866 case 19200:
1867 encodedBitRate = 0x07;
1868 break;
1869 case 38400:
1870 encodedBitRate = 0x08;
1871 break;
1872 case 57600:
1873 encodedBitRate = 0x09;
1874 break;
1875 case 115200:
1876 encodedBitRate = 0x0a;
1877 break;
1878 default:
1879 break;
1880 }
1881 ret.pack(encodedBitRate);
1882 return responseSuccess(std::move(ret));
1883 }
Jian Zhang23f44652022-03-17 17:13:10 +08001884 case SolConfParam::Vbitrate:
1885 default:
1886 return response(ipmiCCParamNotSupported);
1887 }
1888
1889 return response(ccParamNotSupported);
1890}
1891
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001892} // namespace transport
1893} // namespace ipmi
Ratan Gupta1247e0b2018-03-07 10:47:25 +05301894
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001895void register_netfn_transport_functions() __attribute__((constructor));
Ratan Gupta1247e0b2018-03-07 10:47:25 +05301896
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001897void register_netfn_transport_functions()
1898{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001899 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1900 ipmi::transport::cmdSetLanConfigParameters,
1901 ipmi::Privilege::Admin, ipmi::transport::setLan);
1902 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1903 ipmi::transport::cmdGetLanConfigParameters,
Johnathan Mantey34698d52019-11-19 14:47:30 -08001904 ipmi::Privilege::Operator, ipmi::transport::getLan);
Jian Zhang23f44652022-03-17 17:13:10 +08001905 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1906 ipmi::transport::cmdSetSolConfigParameters,
1907 ipmi::Privilege::Admin,
1908 ipmi::transport::setSolConfParams);
1909 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1910 ipmi::transport::cmdGetSolConfigParameters,
1911 ipmi::Privilege::User,
1912 ipmi::transport::getSolConfParams);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001913}