blob: 61960d2d3df4fa89ca5f77b15330c51671df3968 [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 }
Johnathan Manteycbfa6e12023-06-01 06:57:25 -0700391
392 if (struct in_addr nullIPv4{0}; address.value().s_addr != nullIPv4.s_addr)
393 {
394 createIfAddr<AF_INET>(bus, params, address.value_or(ifaddr->address),
395 prefix.value_or(fallbackPrefix));
396 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700397}
398
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700399template <int family>
Patrick Williams5d82f472022-07-22 19:26:53 -0500400std::optional<IfNeigh<family>> findGatewayNeighbor(sdbusplus::bus_t& bus,
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700401 const ChannelParams& params,
402 ObjectLookupCache& neighbors)
403{
404 auto gateway = getGatewayProperty<family>(bus, params);
405 if (!gateway)
406 {
407 return std::nullopt;
408 }
409
410 return findStaticNeighbor<family>(bus, params, *gateway, neighbors);
411}
412
413template <int family>
Patrick Williams5d82f472022-07-22 19:26:53 -0500414std::optional<IfNeigh<family>> getGatewayNeighbor(sdbusplus::bus_t& bus,
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700415 const ChannelParams& params)
416{
417 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
418 return findGatewayNeighbor<family>(bus, params, neighbors);
419}
420
421template <int family>
Patrick Williams5d82f472022-07-22 19:26:53 -0500422void reconfigureGatewayMAC(sdbusplus::bus_t& bus, const ChannelParams& params,
423 const ether_addr& mac)
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700424{
425 auto gateway = getGatewayProperty<family>(bus, params);
426 if (!gateway)
427 {
428 log<level::ERR>("Tried to set Gateway MAC without Gateway");
429 elog<InternalFailure>();
430 }
431
432 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500433 auto neighbor = findStaticNeighbor<family>(bus, params, *gateway,
434 neighbors);
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700435 if (neighbor)
436 {
437 deleteObjectIfExists(bus, params.service, neighbor->path);
438 }
439
440 createNeighbor<family>(bus, params, *gateway, mac);
441}
442
William A. Kennington III16064aa2019-04-13 17:44:53 -0700443/** @brief Deconfigures the IPv6 address info configured for the interface
444 *
445 * @param[in] bus - The bus object used for lookups
446 * @param[in] params - The parameters for the channel
447 * @param[in] idx - The address index to operate on
448 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500449void deconfigureIfAddr6(sdbusplus::bus_t& bus, const ChannelParams& params,
William A. Kennington III16064aa2019-04-13 17:44:53 -0700450 uint8_t idx)
451{
452 auto ifaddr = getIfAddr<AF_INET6>(bus, params, idx, originsV6Static);
453 if (ifaddr)
454 {
455 deleteObjectIfExists(bus, params.service, ifaddr->path);
456 }
457}
458
459/** @brief Reconfigures the IPv6 address info configured for the interface
460 *
461 * @param[in] bus - The bus object used for lookups
462 * @param[in] params - The parameters for the channel
463 * @param[in] idx - The address index to operate on
464 * @param[in] address - The new address
465 * @param[in] prefix - The new address prefix
466 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500467void reconfigureIfAddr6(sdbusplus::bus_t& bus, const ChannelParams& params,
William A. Kennington III16064aa2019-04-13 17:44:53 -0700468 uint8_t idx, const in6_addr& address, uint8_t prefix)
469{
470 deconfigureIfAddr6(bus, params, idx);
471 createIfAddr<AF_INET6>(bus, params, address, prefix);
472}
473
474/** @brief Converts the AddressOrigin into an IPv6Source
475 *
476 * @param[in] origin - The DBus Address Origin to convert
477 * @return The IPv6Source version of the origin
478 */
479IPv6Source originToSourceType(IP::AddressOrigin origin)
480{
481 switch (origin)
482 {
483 case IP::AddressOrigin::Static:
484 return IPv6Source::Static;
485 case IP::AddressOrigin::DHCP:
486 return IPv6Source::DHCP;
487 case IP::AddressOrigin::SLAAC:
488 return IPv6Source::SLAAC;
489 default:
490 {
491 auto originStr = sdbusplus::xyz::openbmc_project::Network::server::
492 convertForMessage(origin);
493 log<level::ERR>(
494 "Invalid IP::AddressOrigin conversion to IPv6Source",
495 entry("ORIGIN=%s", originStr.c_str()));
496 elog<InternalFailure>();
497 }
498 }
499}
500
501/** @brief Packs the IPMI message response with IPv6 address data
502 *
503 * @param[out] ret - The IPMI response payload to be packed
504 * @param[in] channel - The channel id corresponding to an ethernet interface
505 * @param[in] set - The set selector for determining address index
506 * @param[in] origins - Set of valid origins for address filtering
507 */
508void getLanIPv6Address(message::Payload& ret, uint8_t channel, uint8_t set,
509 const std::unordered_set<IP::AddressOrigin>& origins)
510{
511 auto source = IPv6Source::Static;
512 bool enabled = false;
513 in6_addr addr{};
Johnathan Mantey5aae0922021-10-21 13:05:36 -0700514 uint8_t prefix{};
William A. Kennington III16064aa2019-04-13 17:44:53 -0700515 auto status = IPv6AddressStatus::Disabled;
516
517 auto ifaddr = channelCall<getIfAddr<AF_INET6>>(channel, set, origins);
518 if (ifaddr)
519 {
520 source = originToSourceType(ifaddr->origin);
Johnathan Mantey846af862021-10-21 12:48:54 -0700521 enabled = (origins == originsV6Static);
William A. Kennington III16064aa2019-04-13 17:44:53 -0700522 addr = ifaddr->address;
523 prefix = ifaddr->prefix;
524 status = IPv6AddressStatus::Active;
525 }
526
527 ret.pack(set);
William A. Kennington III7a0e5df2021-05-19 13:31:29 -0700528 ret.pack(types::enum_cast<uint4_t>(source), uint3_t{}, enabled);
William A. Kennington III16064aa2019-04-13 17:44:53 -0700529 ret.pack(std::string_view(reinterpret_cast<char*>(&addr), sizeof(addr)));
530 ret.pack(prefix);
William A. Kennington III7a0e5df2021-05-19 13:31:29 -0700531 ret.pack(types::enum_cast<uint8_t>(status));
William A. Kennington III16064aa2019-04-13 17:44:53 -0700532}
533
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700534/** @brief Gets the vlan ID configured on the interface
535 *
536 * @param[in] bus - The bus object used for lookups
537 * @param[in] params - The parameters for the channel
538 * @return VLAN id or the standard 0 for no VLAN
539 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500540uint16_t getVLANProperty(sdbusplus::bus_t& bus, const ChannelParams& params)
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700541{
542 // VLAN devices will always have a separate logical object
543 if (params.ifPath == params.logicalPath)
544 {
545 return 0;
546 }
547
548 auto vlan = std::get<uint32_t>(getDbusProperty(
549 bus, params.service, params.logicalPath, INTF_VLAN, "Id"));
550 if ((vlan & VLAN_VALUE_MASK) != vlan)
551 {
552 logWithChannel<level::ERR>(params, "networkd returned an invalid vlan",
553 entry("VLAN=%" PRIu32, vlan));
Tom Josepha30c8d32018-03-22 02:15:03 +0530554 elog<InternalFailure>();
555 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700556 return vlan;
Tom Josepha30c8d32018-03-22 02:15:03 +0530557}
558
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700559/** @brief Deletes all of the possible configuration parameters for a channel
560 *
561 * @param[in] bus - The bus object used for lookups
562 * @param[in] params - The parameters for the channel
563 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500564void deconfigureChannel(sdbusplus::bus_t& bus, ChannelParams& params)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500565{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700566 // Delete all objects associated with the interface
567 auto objreq = bus.new_method_call(MAPPER_BUS_NAME, MAPPER_OBJ, MAPPER_INTF,
568 "GetSubTree");
569 objreq.append(PATH_ROOT, 0, std::vector<std::string>{DELETE_INTERFACE});
570 auto objreply = bus.call(objreq);
571 ObjectTree objs;
572 objreply.read(objs);
573 for (const auto& [path, impls] : objs)
574 {
575 if (path.find(params.ifname) == path.npos)
576 {
577 continue;
578 }
579 for (const auto& [service, intfs] : impls)
580 {
581 deleteObjectIfExists(bus, service, path);
582 }
583 // Update params to reflect the deletion of vlan
584 if (path == params.logicalPath)
585 {
586 params.logicalPath = params.ifPath;
587 }
588 }
589
590 // Clear out any settings on the lower physical interface
Johnathan Mantey65265362019-11-14 11:24:19 -0800591 setDHCPv6Property(bus, params, EthernetInterface::DHCPConf::none, false);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500592}
593
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700594/** @brief Creates a new VLAN on the specified interface
595 *
596 * @param[in] bus - The bus object used for lookups
597 * @param[in] params - The parameters for the channel
598 * @param[in] vlan - The id of the new vlan
599 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500600void createVLAN(sdbusplus::bus_t& bus, ChannelParams& params, uint16_t vlan)
Ratan Guptab8e99552017-07-27 07:07:48 +0530601{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700602 if (vlan == 0)
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +0530603 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700604 return;
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +0530605 }
606
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700607 auto req = bus.new_method_call(params.service.c_str(), PATH_ROOT,
608 INTF_VLAN_CREATE, "VLAN");
609 req.append(params.ifname, static_cast<uint32_t>(vlan));
610 auto reply = bus.call(req);
611 sdbusplus::message::object_path newPath;
612 reply.read(newPath);
613 params.logicalPath = std::move(newPath);
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +0530614}
615
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700616/** @brief Performs the necessary reconfiguration to change the VLAN
617 *
618 * @param[in] bus - The bus object used for lookups
619 * @param[in] params - The parameters for the channel
620 * @param[in] vlan - The new vlan id to use
621 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500622void reconfigureVLAN(sdbusplus::bus_t& bus, ChannelParams& params,
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700623 uint16_t vlan)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500624{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700625 // Unfortunatetly we don't have built-in functions to migrate our interface
626 // customizations to new VLAN interfaces, or have some kind of decoupling.
627 // We therefore must retain all of our old information, setup the new VLAN
628 // configuration, then restore the old info.
Nan Li3d0df912016-10-18 19:51:41 +0800629
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700630 // Save info from the old logical interface
631 ObjectLookupCache ips(bus, params, INTF_IP);
632 auto ifaddr4 = findIfAddr<AF_INET>(bus, params, 0, originsV4, ips);
William A. Kennington III16064aa2019-04-13 17:44:53 -0700633 std::vector<IfAddr<AF_INET6>> ifaddrs6;
634 for (uint8_t i = 0; i < MAX_IPV6_STATIC_ADDRESSES; ++i)
635 {
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500636 auto ifaddr6 = findIfAddr<AF_INET6>(bus, params, i, originsV6Static,
637 ips);
William A. Kennington III16064aa2019-04-13 17:44:53 -0700638 if (!ifaddr6)
639 {
640 break;
641 }
642 ifaddrs6.push_back(std::move(*ifaddr6));
643 }
Johnathan Mantey65265362019-11-14 11:24:19 -0800644 EthernetInterface::DHCPConf dhcp = getDHCPProperty(bus, params);
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700645 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
646 auto neighbor4 = findGatewayNeighbor<AF_INET>(bus, params, neighbors);
William A. Kennington III16064aa2019-04-13 17:44:53 -0700647 auto neighbor6 = findGatewayNeighbor<AF_INET6>(bus, params, neighbors);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500648
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700649 deconfigureChannel(bus, params);
650 createVLAN(bus, params, vlan);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500651
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700652 // Re-establish the saved settings
Johnathan Mantey65265362019-11-14 11:24:19 -0800653 setDHCPv6Property(bus, params, dhcp, false);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700654 if (ifaddr4)
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800655 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700656 createIfAddr<AF_INET>(bus, params, ifaddr4->address, ifaddr4->prefix);
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800657 }
William A. Kennington III16064aa2019-04-13 17:44:53 -0700658 for (const auto& ifaddr6 : ifaddrs6)
659 {
660 createIfAddr<AF_INET6>(bus, params, ifaddr6.address, ifaddr6.prefix);
661 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700662 if (neighbor4)
663 {
664 createNeighbor<AF_INET>(bus, params, neighbor4->ip, neighbor4->mac);
665 }
William A. Kennington III16064aa2019-04-13 17:44:53 -0700666 if (neighbor6)
667 {
668 createNeighbor<AF_INET6>(bus, params, neighbor6->ip, neighbor6->mac);
669 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700670}
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800671
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700672/** @brief Turns a prefix into a netmask
673 *
674 * @param[in] prefix - The prefix length
675 * @return The netmask
676 */
677in_addr prefixToNetmask(uint8_t prefix)
678{
679 if (prefix > 32)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500680 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700681 log<level::ERR>("Invalid prefix", entry("PREFIX=%" PRIu8, prefix));
682 elog<InternalFailure>();
683 }
684 if (prefix == 0)
685 {
686 // Avoids 32-bit lshift by 32 UB
687 return {};
688 }
689 return {htobe32(~UINT32_C(0) << (32 - prefix))};
690}
691
692/** @brief Turns a a netmask into a prefix length
693 *
694 * @param[in] netmask - The netmask in byte form
695 * @return The prefix length
696 */
697uint8_t netmaskToPrefix(in_addr netmask)
698{
699 uint32_t x = be32toh(netmask.s_addr);
700 if ((~x & (~x + 1)) != 0)
701 {
702 char maskStr[INET_ADDRSTRLEN];
703 inet_ntop(AF_INET, &netmask, maskStr, sizeof(maskStr));
704 log<level::ERR>("Invalid netmask", entry("NETMASK=%s", maskStr));
705 elog<InternalFailure>();
706 }
Johnathan Mantey62c05dd2019-11-20 14:07:44 -0800707 return static_cast<bool>(x)
708 ? AddrFamily<AF_INET>::defaultPrefix - __builtin_ctz(x)
709 : 0;
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700710}
711
712// We need to store this value so it can be returned to the client
713// It is volatile so safe to store in daemon memory.
714static std::unordered_map<uint8_t, SetStatus> setStatus;
715
716// Until we have good support for fixed versions of IPMI tool
717// we need to return the VLAN id for disabled VLANs. The value is only
718// used for verification that a disable operation succeeded and will only
719// be sent if our system indicates that vlans are disabled.
720static std::unordered_map<uint8_t, uint16_t> lastDisabledVlan;
721
722/** @brief Gets the set status for the channel if it exists
723 * Otherise populates and returns the default value.
724 *
725 * @param[in] channel - The channel id corresponding to an ethernet interface
726 * @return A reference to the SetStatus for the channel
727 */
728SetStatus& getSetStatus(uint8_t channel)
729{
730 auto it = setStatus.find(channel);
731 if (it != setStatus.end())
732 {
733 return it->second;
734 }
735 return setStatus[channel] = SetStatus::Complete;
736}
737
Johnathan Mantey3b7a4072021-01-26 14:24:53 -0800738/** @brief Gets the IPv6 Router Advertisement value
739 *
740 * @param[in] bus - The bus object used for lookups
741 * @param[in] params - The parameters for the channel
742 * @return networkd IPV6AcceptRA value
743 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500744static bool getIPv6AcceptRA(sdbusplus::bus_t& bus, const ChannelParams& params)
Johnathan Mantey3b7a4072021-01-26 14:24:53 -0800745{
746 auto raEnabled =
747 std::get<bool>(getDbusProperty(bus, params.service, params.logicalPath,
748 INTF_ETHERNET, "IPv6AcceptRA"));
749 return raEnabled;
750}
751
752/** @brief Sets the IPv6AcceptRA flag
753 *
754 * @param[in] bus - The bus object used for lookups
755 * @param[in] params - The parameters for the channel
756 * @param[in] ipv6AcceptRA - boolean to enable/disable IPv6 Routing
757 * Advertisement
758 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500759void setIPv6AcceptRA(sdbusplus::bus_t& bus, const ChannelParams& params,
Johnathan Mantey3b7a4072021-01-26 14:24:53 -0800760 const bool ipv6AcceptRA)
761{
762 setDbusProperty(bus, params.service, params.logicalPath, INTF_ETHERNET,
763 "IPv6AcceptRA", ipv6AcceptRA);
764}
765
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700766/**
767 * Define placeholder command handlers for the OEM Extension bytes for the Set
768 * LAN Configuration Parameters and Get LAN Configuration Parameters
769 * commands. Using "weak" linking allows the placeholder setLanOem/getLanOem
770 * functions below to be overridden.
771 * To create handlers for your own proprietary command set:
772 * Create/modify a phosphor-ipmi-host Bitbake append file within your Yocto
773 * recipe
774 * Create C++ file(s) that define IPMI handler functions matching the
775 * function names below (i.e. setLanOem). The default name for the
776 * transport IPMI commands is transporthandler_oem.cpp.
777 * Add:
Johnathan Manteyefe26682022-08-11 14:30:45 -0700778 * EXTRA_OEMESON:append = "-Dtransport-oem=enabled"
779 * Create a do_configure:prepend()/do_install:append() method in your
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700780 * bbappend file to copy the file to the build directory.
781 * Add:
782 * PROJECT_SRC_DIR := "${THISDIR}/${PN}"
783 * # Copy the "strong" functions into the working directory, overriding the
784 * # placeholder functions.
Johnathan Manteyefe26682022-08-11 14:30:45 -0700785 * do_configure:prepend(){
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700786 * cp -f ${PROJECT_SRC_DIR}/transporthandler_oem.cpp ${S}
787 * }
788 *
789 * # Clean up after complilation has completed
Johnathan Manteyefe26682022-08-11 14:30:45 -0700790 * do_install:append(){
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700791 * rm -f ${S}/transporthandler_oem.cpp
792 * }
793 *
794 */
795
796/**
797 * Define the placeholder OEM commands as having weak linkage. Create
798 * setLanOem, and getLanOem functions in the transporthandler_oem.cpp
799 * file. The functions defined there must not have the "weak" attribute
800 * applied to them.
801 */
802RspType<> setLanOem(uint8_t channel, uint8_t parameter, message::Payload& req)
803 __attribute__((weak));
804RspType<message::Payload> getLanOem(uint8_t channel, uint8_t parameter,
805 uint8_t set, uint8_t block)
806 __attribute__((weak));
807
Willy Tu11d68892022-01-20 10:37:34 -0800808RspType<> setLanOem(uint8_t, uint8_t, message::Payload& req)
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700809{
810 req.trailingOk = true;
811 return response(ccParamNotSupported);
812}
813
Willy Tu11d68892022-01-20 10:37:34 -0800814RspType<message::Payload> getLanOem(uint8_t, uint8_t, uint8_t, uint8_t)
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700815{
816 return response(ccParamNotSupported);
817}
Rajashekar Gade Reddy0b993fd2019-12-24 16:37:15 +0530818/**
819 * @brief is MAC address valid.
820 *
821 * This function checks whether the MAC address is valid or not.
822 *
823 * @param[in] mac - MAC address.
824 * @return true if MAC address is valid else retun false.
825 **/
826bool isValidMACAddress(const ether_addr& mac)
827{
828 // check if mac address is empty
829 if (equal(mac, ether_addr{}))
830 {
831 return false;
832 }
833 // we accept only unicast MAC addresses and same thing has been checked in
834 // phosphor-network layer. If the least significant bit of the first octet
835 // is set to 1, it is multicast MAC else it is unicast MAC address.
836 if (mac.ether_addr_octet[0] & 1)
837 {
838 return false;
839 }
840 return true;
841}
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700842
vijayabharathix shettycc769252020-02-27 17:52:20 +0000843RspType<> setLan(Context::ptr ctx, uint4_t channelBits, uint4_t reserved1,
844 uint8_t parameter, message::Payload& req)
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700845{
vijayabharathix shettycc769252020-02-27 17:52:20 +0000846 const uint8_t channel = convertCurrentChannelNum(
847 static_cast<uint8_t>(channelBits), ctx->channel);
848 if (reserved1 || !isValidChannel(channel))
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700849 {
vijayabharathix shettycc769252020-02-27 17:52:20 +0000850 log<level::ERR>("Set Lan - Invalid field in request");
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700851 req.trailingOk = true;
852 return responseInvalidFieldRequest();
853 }
854
855 switch (static_cast<LanParam>(parameter))
856 {
857 case LanParam::SetStatus:
858 {
859 uint2_t flag;
860 uint6_t rsvd;
861 if (req.unpack(flag, rsvd) != 0 || !req.fullyUnpacked())
862 {
863 return responseReqDataLenInvalid();
864 }
Johnathan Mantey4a156852019-12-11 13:47:43 -0800865 if (rsvd)
866 {
867 return responseInvalidFieldRequest();
868 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700869 auto status = static_cast<SetStatus>(static_cast<uint8_t>(flag));
870 switch (status)
871 {
872 case SetStatus::Complete:
873 {
874 getSetStatus(channel) = status;
875 return responseSuccess();
876 }
877 case SetStatus::InProgress:
878 {
879 auto& storedStatus = getSetStatus(channel);
880 if (storedStatus == SetStatus::InProgress)
881 {
882 return response(ccParamSetLocked);
883 }
884 storedStatus = status;
885 return responseSuccess();
886 }
887 case SetStatus::Commit:
888 if (getSetStatus(channel) != SetStatus::InProgress)
889 {
890 return responseInvalidFieldRequest();
891 }
892 return responseSuccess();
893 }
894 return response(ccParamNotSupported);
895 }
896 case LanParam::AuthSupport:
897 {
898 req.trailingOk = true;
899 return response(ccParamReadOnly);
900 }
901 case LanParam::AuthEnables:
902 {
903 req.trailingOk = true;
Johnathan Mantey76ce9c72019-11-14 14:41:46 -0800904 return response(ccParamReadOnly);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700905 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -0800906 case LanParam::IP:
Hariharasubramanian R83951912016-01-20 07:06:36 -0600907 {
Johnathan Mantey65265362019-11-14 11:24:19 -0800908 EthernetInterface::DHCPConf dhcp =
909 channelCall<getDHCPProperty>(channel);
910 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
911 (dhcp == EthernetInterface::DHCPConf::both))
Johnathan Mantey930104a2019-12-17 09:18:34 -0800912 {
913 return responseCommandNotAvailable();
914 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700915 in_addr ip;
916 std::array<uint8_t, sizeof(ip)> bytes;
917 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
918 {
919 return responseReqDataLenInvalid();
920 }
921 copyInto(ip, bytes);
922 channelCall<reconfigureIfAddr4>(channel, ip, std::nullopt);
923 return responseSuccess();
Ratan Guptab8e99552017-07-27 07:07:48 +0530924 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700925 case LanParam::IPSrc:
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530926 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700927 uint4_t flag;
928 uint4_t rsvd;
929 if (req.unpack(flag, rsvd) != 0 || !req.fullyUnpacked())
930 {
931 return responseReqDataLenInvalid();
932 }
Johnathan Mantey4a156852019-12-11 13:47:43 -0800933 if (rsvd)
934 {
935 return responseInvalidFieldRequest();
936 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700937 switch (static_cast<IPSrc>(static_cast<uint8_t>(flag)))
938 {
939 case IPSrc::DHCP:
940 {
Johnathan Mantey65265362019-11-14 11:24:19 -0800941 // The IPSrc IPMI command is only for IPv4
942 // management. Modifying IPv6 state is done using
943 // a completely different Set LAN Configuration
944 // subcommand.
945 channelCall<setDHCPv4Property>(
946 channel, EthernetInterface::DHCPConf::v4);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700947 return responseSuccess();
948 }
949 case IPSrc::Unspecified:
950 case IPSrc::Static:
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700951 {
Johnathan Mantey65265362019-11-14 11:24:19 -0800952 channelCall<setDHCPv4Property>(
953 channel, EthernetInterface::DHCPConf::none);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700954 return responseSuccess();
955 }
Rajashekar Gade Reddy8a860ea2019-12-24 11:31:19 +0530956 case IPSrc::BIOS:
957 case IPSrc::BMC:
958 {
959 return responseInvalidFieldRequest();
960 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700961 }
962 return response(ccParamNotSupported);
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530963 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -0800964 case LanParam::MAC:
Ratan Guptab8e99552017-07-27 07:07:48 +0530965 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700966 ether_addr mac;
967 std::array<uint8_t, sizeof(mac)> bytes;
968 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
Suryakanth Sekar0a327e12019-08-08 14:30:19 +0530969 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700970 return responseReqDataLenInvalid();
Suryakanth Sekar0a327e12019-08-08 14:30:19 +0530971 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700972 copyInto(mac, bytes);
Rajashekar Gade Reddy0b993fd2019-12-24 16:37:15 +0530973
974 if (!isValidMACAddress(mac))
975 {
976 return responseInvalidFieldRequest();
977 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700978 channelCall<setMACProperty>(channel, mac);
979 return responseSuccess();
Ratan Gupta533d03b2017-07-30 10:39:22 +0530980 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700981 case LanParam::SubnetMask:
Ratan Guptab8e99552017-07-27 07:07:48 +0530982 {
Johnathan Mantey65265362019-11-14 11:24:19 -0800983 EthernetInterface::DHCPConf dhcp =
984 channelCall<getDHCPProperty>(channel);
985 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
986 (dhcp == EthernetInterface::DHCPConf::both))
Johnathan Mantey930104a2019-12-17 09:18:34 -0800987 {
988 return responseCommandNotAvailable();
989 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700990 in_addr netmask;
991 std::array<uint8_t, sizeof(netmask)> bytes;
992 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
Ratan Guptab8e99552017-07-27 07:07:48 +0530993 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700994 return responseReqDataLenInvalid();
Ratan Guptab8e99552017-07-27 07:07:48 +0530995 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700996 copyInto(netmask, bytes);
Jiaqing Zhao6d4a44e2022-01-24 15:04:00 +0800997 uint8_t prefix = netmaskToPrefix(netmask);
998 if (prefix < MIN_IPV4_PREFIX_LENGTH)
999 {
1000 return responseInvalidFieldRequest();
1001 }
1002 channelCall<reconfigureIfAddr4>(channel, std::nullopt, prefix);
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001003 return responseSuccess();
Ratan Guptab8e99552017-07-27 07:07:48 +05301004 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001005 case LanParam::Gateway1:
Ratan Guptab8e99552017-07-27 07:07:48 +05301006 {
Johnathan Mantey65265362019-11-14 11:24:19 -08001007 EthernetInterface::DHCPConf dhcp =
1008 channelCall<getDHCPProperty>(channel);
1009 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
1010 (dhcp == EthernetInterface::DHCPConf::both))
Johnathan Mantey930104a2019-12-17 09:18:34 -08001011 {
1012 return responseCommandNotAvailable();
1013 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001014 in_addr gateway;
1015 std::array<uint8_t, sizeof(gateway)> bytes;
1016 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1017 {
1018 return responseReqDataLenInvalid();
1019 }
1020 copyInto(gateway, bytes);
1021 channelCall<setGatewayProperty<AF_INET>>(channel, gateway);
1022 return responseSuccess();
1023 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001024 case LanParam::Gateway1MAC:
1025 {
1026 ether_addr gatewayMAC;
1027 std::array<uint8_t, sizeof(gatewayMAC)> bytes;
1028 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1029 {
1030 return responseReqDataLenInvalid();
1031 }
1032 copyInto(gatewayMAC, bytes);
1033 channelCall<reconfigureGatewayMAC<AF_INET>>(channel, gatewayMAC);
1034 return responseSuccess();
1035 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001036 case LanParam::VLANId:
1037 {
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301038 uint12_t vlanData = 0;
1039 uint3_t reserved = 0;
1040 bool vlanEnable = 0;
1041
1042 if (req.unpack(vlanData) || req.unpack(reserved) ||
1043 req.unpack(vlanEnable) || !req.fullyUnpacked())
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001044 {
1045 return responseReqDataLenInvalid();
1046 }
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301047
1048 if (reserved)
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001049 {
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301050 return responseInvalidFieldRequest();
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001051 }
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301052
1053 uint16_t vlan = static_cast<uint16_t>(vlanData);
1054
1055 if (!vlanEnable)
1056 {
1057 lastDisabledVlan[channel] = vlan;
1058 vlan = 0;
1059 }
jayaprakash Mutyala84c49dc2020-05-18 23:12:13 +00001060 else if (vlan == 0 || vlan == VLAN_VALUE_MASK)
1061 {
1062 return responseInvalidFieldRequest();
1063 }
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301064
jayaprakash Mutyala84c49dc2020-05-18 23:12:13 +00001065 channelCall<reconfigureVLAN>(channel, vlan);
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001066 return responseSuccess();
1067 }
1068 case LanParam::CiphersuiteSupport:
1069 case LanParam::CiphersuiteEntries:
William A. Kennington III16064aa2019-04-13 17:44:53 -07001070 case LanParam::IPFamilySupport:
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001071 {
1072 req.trailingOk = true;
1073 return response(ccParamReadOnly);
Ratan Guptab8e99552017-07-27 07:07:48 +05301074 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001075 case LanParam::IPFamilyEnables:
1076 {
1077 uint8_t enables;
1078 if (req.unpack(enables) != 0 || !req.fullyUnpacked())
1079 {
1080 return responseReqDataLenInvalid();
1081 }
1082 switch (static_cast<IPFamilyEnables>(enables))
1083 {
1084 case IPFamilyEnables::DualStack:
1085 return responseSuccess();
1086 case IPFamilyEnables::IPv4Only:
1087 case IPFamilyEnables::IPv6Only:
1088 return response(ccParamNotSupported);
1089 }
1090 return response(ccParamNotSupported);
1091 }
1092 case LanParam::IPv6Status:
1093 {
1094 req.trailingOk = true;
1095 return response(ccParamReadOnly);
1096 }
1097 case LanParam::IPv6StaticAddresses:
1098 {
1099 uint8_t set;
1100 uint7_t rsvd;
1101 bool enabled;
1102 in6_addr ip;
1103 std::array<uint8_t, sizeof(ip)> ipbytes;
1104 uint8_t prefix;
1105 uint8_t status;
1106 if (req.unpack(set, rsvd, enabled, ipbytes, prefix, status) != 0 ||
1107 !req.fullyUnpacked())
1108 {
1109 return responseReqDataLenInvalid();
1110 }
Johnathan Mantey4a156852019-12-11 13:47:43 -08001111 if (rsvd)
1112 {
1113 return responseInvalidFieldRequest();
1114 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001115 copyInto(ip, ipbytes);
1116 if (enabled)
1117 {
Jiaqing Zhao6d4a44e2022-01-24 15:04:00 +08001118 if (prefix < MIN_IPV6_PREFIX_LENGTH ||
1119 prefix > MAX_IPV6_PREFIX_LENGTH)
1120 {
1121 return responseParmOutOfRange();
1122 }
Johnathan Manteya291f492021-10-15 13:45:27 -07001123 try
1124 {
1125 channelCall<reconfigureIfAddr6>(channel, set, ip, prefix);
1126 }
Patrick Williams5d82f472022-07-22 19:26:53 -05001127 catch (const sdbusplus::exception_t& e)
Johnathan Manteya291f492021-10-15 13:45:27 -07001128 {
1129 if (std::string_view err{
1130 "xyz.openbmc_project.Common.Error.InvalidArgument"};
1131 err == e.name())
1132 {
1133 return responseInvalidFieldRequest();
1134 }
1135 else
1136 {
1137 throw;
1138 }
1139 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001140 }
1141 else
1142 {
1143 channelCall<deconfigureIfAddr6>(channel, set);
1144 }
1145 return responseSuccess();
1146 }
1147 case LanParam::IPv6DynamicAddresses:
1148 {
1149 req.trailingOk = true;
1150 return response(ccParamReadOnly);
1151 }
1152 case LanParam::IPv6RouterControl:
1153 {
1154 std::bitset<8> control;
Johnathan Mantey3b7a4072021-01-26 14:24:53 -08001155 constexpr uint8_t reservedRACCBits = 0xfc;
William A. Kennington III16064aa2019-04-13 17:44:53 -07001156 if (req.unpack(control) != 0 || !req.fullyUnpacked())
1157 {
1158 return responseReqDataLenInvalid();
1159 }
Johnathan Mantey3b7a4072021-01-26 14:24:53 -08001160 if (std::bitset<8> expected(control &
1161 std::bitset<8>(reservedRACCBits));
1162 expected.any())
William A. Kennington III16064aa2019-04-13 17:44:53 -07001163 {
Johnathan Mantey3b7a4072021-01-26 14:24:53 -08001164 return response(ccParamNotSupported);
William A. Kennington III16064aa2019-04-13 17:44:53 -07001165 }
Johnathan Mantey3b7a4072021-01-26 14:24:53 -08001166
1167 bool enableRA = control[IPv6RouterControlFlag::Dynamic];
1168 channelCall<setIPv6AcceptRA>(channel, enableRA);
William A. Kennington III16064aa2019-04-13 17:44:53 -07001169 return responseSuccess();
1170 }
1171 case LanParam::IPv6StaticRouter1IP:
1172 {
1173 in6_addr gateway;
1174 std::array<uint8_t, sizeof(gateway)> bytes;
1175 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1176 {
1177 return responseReqDataLenInvalid();
1178 }
1179 copyInto(gateway, bytes);
1180 channelCall<setGatewayProperty<AF_INET6>>(channel, gateway);
1181 return responseSuccess();
1182 }
1183 case LanParam::IPv6StaticRouter1MAC:
1184 {
1185 ether_addr mac;
1186 std::array<uint8_t, sizeof(mac)> bytes;
1187 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1188 {
1189 return responseReqDataLenInvalid();
1190 }
1191 copyInto(mac, bytes);
1192 channelCall<reconfigureGatewayMAC<AF_INET6>>(channel, mac);
1193 return responseSuccess();
1194 }
1195 case LanParam::IPv6StaticRouter1PrefixLength:
1196 {
1197 uint8_t prefix;
1198 if (req.unpack(prefix) != 0 || !req.fullyUnpacked())
1199 {
1200 return responseReqDataLenInvalid();
1201 }
1202 if (prefix != 0)
1203 {
1204 return responseInvalidFieldRequest();
1205 }
1206 return responseSuccess();
1207 }
1208 case LanParam::IPv6StaticRouter1PrefixValue:
1209 {
1210 std::array<uint8_t, sizeof(in6_addr)> bytes;
1211 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1212 {
1213 return responseReqDataLenInvalid();
1214 }
1215 // Accept any prefix value since our prefix length has to be 0
1216 return responseSuccess();
1217 }
jayaprakash Mutyalab741b992019-12-02 17:29:09 +00001218 case LanParam::cipherSuitePrivilegeLevels:
1219 {
1220 uint8_t reserved;
1221 std::array<uint4_t, ipmi::maxCSRecords> cipherSuitePrivs;
1222
1223 if (req.unpack(reserved, cipherSuitePrivs) || !req.fullyUnpacked())
1224 {
1225 return responseReqDataLenInvalid();
1226 }
1227
1228 if (reserved)
1229 {
1230 return responseInvalidFieldRequest();
1231 }
1232
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -05001233 uint8_t resp = getCipherConfigObject(csPrivFileName,
1234 csPrivDefaultFileName)
1235 .setCSPrivilegeLevels(channel, cipherSuitePrivs);
jayaprakash Mutyalab741b992019-12-02 17:29:09 +00001236 if (!resp)
1237 {
1238 return responseSuccess();
1239 }
1240 else
1241 {
1242 req.trailingOk = true;
1243 return response(resp);
1244 }
1245 }
Ratan Guptab8e99552017-07-27 07:07:48 +05301246 }
vishwa1eaea4f2016-02-26 11:57:40 -06001247
Johnathan Manteyb87034e2019-09-16 10:50:50 -07001248 if ((parameter >= oemCmdStart) && (parameter <= oemCmdEnd))
1249 {
1250 return setLanOem(channel, parameter, req);
1251 }
1252
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001253 req.trailingOk = true;
1254 return response(ccParamNotSupported);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001255}
1256
vijayabharathix shettycc769252020-02-27 17:52:20 +00001257RspType<message::Payload> getLan(Context::ptr ctx, uint4_t channelBits,
1258 uint3_t reserved, bool revOnly,
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001259 uint8_t parameter, uint8_t set, uint8_t block)
Ratan Guptab8e99552017-07-27 07:07:48 +05301260{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001261 message::Payload ret;
1262 constexpr uint8_t current_revision = 0x11;
1263 ret.pack(current_revision);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001264
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001265 if (revOnly)
Suryakanth Sekare4054402019-08-08 15:16:52 +05301266 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001267 return responseSuccess(std::move(ret));
Suryakanth Sekare4054402019-08-08 15:16:52 +05301268 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001269
vijayabharathix shettycc769252020-02-27 17:52:20 +00001270 const uint8_t channel = convertCurrentChannelNum(
1271 static_cast<uint8_t>(channelBits), ctx->channel);
1272 if (reserved || !isValidChannel(channel))
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001273 {
vijayabharathix shettycc769252020-02-27 17:52:20 +00001274 log<level::ERR>("Get Lan - Invalid field in request");
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001275 return responseInvalidFieldRequest();
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001276 }
1277
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001278 static std::vector<uint8_t> cipherList;
1279 static bool listInit = false;
1280 if (!listInit)
1281 {
1282 try
1283 {
1284 cipherList = cipher::getCipherList();
1285 listInit = true;
1286 }
1287 catch (const std::exception& e)
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -05001288 {}
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001289 }
1290
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001291 switch (static_cast<LanParam>(parameter))
Tom Josepha30c8d32018-03-22 02:15:03 +05301292 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001293 case LanParam::SetStatus:
Tom Josepha30c8d32018-03-22 02:15:03 +05301294 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001295 SetStatus status;
1296 try
1297 {
1298 status = setStatus.at(channel);
1299 }
1300 catch (const std::out_of_range&)
1301 {
1302 status = SetStatus::Complete;
1303 }
William A. Kennington III7a0e5df2021-05-19 13:31:29 -07001304 ret.pack(types::enum_cast<uint2_t>(status), uint6_t{});
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001305 return responseSuccess(std::move(ret));
Tom Josepha30c8d32018-03-22 02:15:03 +05301306 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001307 case LanParam::AuthSupport:
Tom Josepha30c8d32018-03-22 02:15:03 +05301308 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001309 std::bitset<6> support;
1310 ret.pack(support, uint2_t{});
1311 return responseSuccess(std::move(ret));
Tom Josepha30c8d32018-03-22 02:15:03 +05301312 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001313 case LanParam::AuthEnables:
vishwa1eaea4f2016-02-26 11:57:40 -06001314 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001315 std::bitset<6> enables;
1316 ret.pack(enables, uint2_t{}); // Callback
1317 ret.pack(enables, uint2_t{}); // User
1318 ret.pack(enables, uint2_t{}); // Operator
1319 ret.pack(enables, uint2_t{}); // Admin
1320 ret.pack(enables, uint2_t{}); // OEM
1321 return responseSuccess(std::move(ret));
William A. Kennington III39f94ef2018-11-19 22:36:16 -08001322 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001323 case LanParam::IP:
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001324 {
1325 auto ifaddr = channelCall<getIfAddr4>(channel);
1326 in_addr addr{};
1327 if (ifaddr)
1328 {
1329 addr = ifaddr->address;
1330 }
1331 ret.pack(dataRef(addr));
1332 return responseSuccess(std::move(ret));
1333 }
1334 case LanParam::IPSrc:
1335 {
1336 auto src = IPSrc::Static;
Johnathan Mantey65265362019-11-14 11:24:19 -08001337 EthernetInterface::DHCPConf dhcp =
1338 channelCall<getDHCPProperty>(channel);
1339 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
1340 (dhcp == EthernetInterface::DHCPConf::both))
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001341 {
1342 src = IPSrc::DHCP;
1343 }
William A. Kennington III7a0e5df2021-05-19 13:31:29 -07001344 ret.pack(types::enum_cast<uint4_t>(src), uint4_t{});
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001345 return responseSuccess(std::move(ret));
1346 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001347 case LanParam::MAC:
William A. Kennington III39f94ef2018-11-19 22:36:16 -08001348 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001349 ether_addr mac = channelCall<getMACProperty>(channel);
1350 ret.pack(dataRef(mac));
1351 return responseSuccess(std::move(ret));
1352 }
1353 case LanParam::SubnetMask:
1354 {
1355 auto ifaddr = channelCall<getIfAddr4>(channel);
1356 uint8_t prefix = AddrFamily<AF_INET>::defaultPrefix;
1357 if (ifaddr)
Ratan Guptab8e99552017-07-27 07:07:48 +05301358 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001359 prefix = ifaddr->prefix;
1360 }
1361 in_addr netmask = prefixToNetmask(prefix);
1362 ret.pack(dataRef(netmask));
1363 return responseSuccess(std::move(ret));
1364 }
1365 case LanParam::Gateway1:
1366 {
1367 auto gateway =
1368 channelCall<getGatewayProperty<AF_INET>>(channel).value_or(
1369 in_addr{});
1370 ret.pack(dataRef(gateway));
1371 return responseSuccess(std::move(ret));
1372 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001373 case LanParam::Gateway1MAC:
1374 {
1375 ether_addr mac{};
1376 auto neighbor = channelCall<getGatewayNeighbor<AF_INET>>(channel);
1377 if (neighbor)
1378 {
1379 mac = neighbor->mac;
1380 }
1381 ret.pack(dataRef(mac));
1382 return responseSuccess(std::move(ret));
1383 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001384 case LanParam::VLANId:
1385 {
1386 uint16_t vlan = channelCall<getVLANProperty>(channel);
1387 if (vlan != 0)
1388 {
1389 vlan |= VLAN_ENABLE_FLAG;
Ratan Guptab8e99552017-07-27 07:07:48 +05301390 }
1391 else
1392 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001393 vlan = lastDisabledVlan[channel];
Ratan Guptab8e99552017-07-27 07:07:48 +05301394 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001395 ret.pack(vlan);
1396 return responseSuccess(std::move(ret));
Adriana Kobylak342df102016-02-10 13:48:16 -06001397 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001398 case LanParam::CiphersuiteSupport:
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001399 {
srikanta mondal1d8579c2020-04-15 17:13:25 +00001400 if (getChannelSessionSupport(channel) ==
1401 EChannelSessSupported::none)
1402 {
1403 return responseInvalidFieldRequest();
1404 }
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001405 if (!listInit)
1406 {
1407 return responseUnspecifiedError();
1408 }
1409 ret.pack(static_cast<uint8_t>(cipherList.size() - 1));
1410 return responseSuccess(std::move(ret));
1411 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001412 case LanParam::CiphersuiteEntries:
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001413 {
srikanta mondal1d8579c2020-04-15 17:13:25 +00001414 if (getChannelSessionSupport(channel) ==
1415 EChannelSessSupported::none)
1416 {
1417 return responseInvalidFieldRequest();
1418 }
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001419 if (!listInit)
1420 {
1421 return responseUnspecifiedError();
1422 }
1423 ret.pack(cipherList);
1424 return responseSuccess(std::move(ret));
1425 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001426 case LanParam::IPFamilySupport:
1427 {
1428 std::bitset<8> support;
1429 support[IPFamilySupportFlag::IPv6Only] = 0;
1430 support[IPFamilySupportFlag::DualStack] = 1;
1431 support[IPFamilySupportFlag::IPv6Alerts] = 1;
1432 ret.pack(support);
1433 return responseSuccess(std::move(ret));
1434 }
1435 case LanParam::IPFamilyEnables:
1436 {
1437 ret.pack(static_cast<uint8_t>(IPFamilyEnables::DualStack));
1438 return responseSuccess(std::move(ret));
1439 }
1440 case LanParam::IPv6Status:
1441 {
1442 ret.pack(MAX_IPV6_STATIC_ADDRESSES);
1443 ret.pack(MAX_IPV6_DYNAMIC_ADDRESSES);
1444 std::bitset<8> support;
1445 support[IPv6StatusFlag::DHCP] = 1;
1446 support[IPv6StatusFlag::SLAAC] = 1;
1447 ret.pack(support);
1448 return responseSuccess(std::move(ret));
1449 }
1450 case LanParam::IPv6StaticAddresses:
1451 {
1452 if (set >= MAX_IPV6_STATIC_ADDRESSES)
1453 {
1454 return responseParmOutOfRange();
1455 }
1456 getLanIPv6Address(ret, channel, set, originsV6Static);
1457 return responseSuccess(std::move(ret));
1458 }
1459 case LanParam::IPv6DynamicAddresses:
1460 {
1461 if (set >= MAX_IPV6_DYNAMIC_ADDRESSES)
1462 {
1463 return responseParmOutOfRange();
1464 }
1465 getLanIPv6Address(ret, channel, set, originsV6Dynamic);
1466 return responseSuccess(std::move(ret));
1467 }
1468 case LanParam::IPv6RouterControl:
1469 {
1470 std::bitset<8> control;
Johnathan Mantey3b7a4072021-01-26 14:24:53 -08001471 control[IPv6RouterControlFlag::Dynamic] =
1472 channelCall<getIPv6AcceptRA>(channel);
1473 control[IPv6RouterControlFlag::Static] = 1;
William A. Kennington III16064aa2019-04-13 17:44:53 -07001474 ret.pack(control);
1475 return responseSuccess(std::move(ret));
1476 }
1477 case LanParam::IPv6StaticRouter1IP:
1478 {
1479 in6_addr gateway{};
Johnathan Mantey65265362019-11-14 11:24:19 -08001480 EthernetInterface::DHCPConf dhcp =
1481 channelCall<getDHCPProperty>(channel);
1482 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
1483 (dhcp == EthernetInterface::DHCPConf::none))
William A. Kennington III16064aa2019-04-13 17:44:53 -07001484 {
1485 gateway =
1486 channelCall<getGatewayProperty<AF_INET6>>(channel).value_or(
1487 in6_addr{});
1488 }
1489 ret.pack(dataRef(gateway));
1490 return responseSuccess(std::move(ret));
1491 }
1492 case LanParam::IPv6StaticRouter1MAC:
1493 {
1494 ether_addr mac{};
1495 auto neighbor = channelCall<getGatewayNeighbor<AF_INET6>>(channel);
1496 if (neighbor)
1497 {
1498 mac = neighbor->mac;
1499 }
1500 ret.pack(dataRef(mac));
1501 return responseSuccess(std::move(ret));
1502 }
1503 case LanParam::IPv6StaticRouter1PrefixLength:
1504 {
1505 ret.pack(UINT8_C(0));
1506 return responseSuccess(std::move(ret));
1507 }
1508 case LanParam::IPv6StaticRouter1PrefixValue:
1509 {
1510 in6_addr prefix{};
1511 ret.pack(dataRef(prefix));
1512 return responseSuccess(std::move(ret));
1513 }
jayaprakash Mutyalab741b992019-12-02 17:29:09 +00001514 case LanParam::cipherSuitePrivilegeLevels:
1515 {
1516 std::array<uint4_t, ipmi::maxCSRecords> csPrivilegeLevels;
1517
1518 uint8_t resp =
1519 getCipherConfigObject(csPrivFileName, csPrivDefaultFileName)
1520 .getCSPrivilegeLevels(channel, csPrivilegeLevels);
1521 if (!resp)
1522 {
1523 constexpr uint8_t reserved1 = 0x00;
1524 ret.pack(reserved1, csPrivilegeLevels);
1525 return responseSuccess(std::move(ret));
1526 }
1527 else
1528 {
1529 return response(resp);
1530 }
1531 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001532 }
1533
Johnathan Manteyb87034e2019-09-16 10:50:50 -07001534 if ((parameter >= oemCmdStart) && (parameter <= oemCmdEnd))
1535 {
1536 return getLanOem(channel, parameter, set, block);
1537 }
1538
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001539 return response(ccParamNotSupported);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001540}
1541
Jian Zhang23f44652022-03-17 17:13:10 +08001542constexpr const char* solInterface = "xyz.openbmc_project.Ipmi.SOL";
1543constexpr const char* solPath = "/xyz/openbmc_project/ipmi/sol/";
1544constexpr const uint16_t solDefaultPort = 623;
1545
1546RspType<> setSolConfParams(Context::ptr ctx, uint4_t channelBits,
Willy Tu11d68892022-01-20 10:37:34 -08001547 uint4_t /*reserved*/, uint8_t parameter,
Jian Zhang23f44652022-03-17 17:13:10 +08001548 message::Payload& req)
1549{
1550 const uint8_t channel = convertCurrentChannelNum(
1551 static_cast<uint8_t>(channelBits), ctx->channel);
1552
1553 if (!isValidChannel(channel))
1554 {
1555 log<level::ERR>("Set Sol Config - Invalid channel in request");
1556 return responseInvalidFieldRequest();
1557 }
1558
1559 std::string solService{};
1560 std::string solPathWitheEthName = solPath + ipmi::getChannelName(channel);
1561
1562 if (ipmi::getService(ctx, solInterface, solPathWitheEthName, solService))
1563 {
1564 log<level::ERR>("Set Sol Config - Invalid solInterface",
1565 entry("SERVICE=%s", solService.c_str()),
1566 entry("OBJPATH=%s", solPathWitheEthName.c_str()),
1567 entry("INTERFACE=%s", solInterface));
1568 return responseInvalidFieldRequest();
1569 }
1570
1571 switch (static_cast<SolConfParam>(parameter))
1572 {
1573 case SolConfParam::Progress:
1574 {
1575 uint8_t progress;
1576 if (req.unpack(progress) != 0 || !req.fullyUnpacked())
1577 {
1578 return responseReqDataLenInvalid();
1579 }
1580
1581 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1582 solInterface, "Progress", progress))
1583 {
1584 return responseUnspecifiedError();
1585 }
1586 break;
1587 }
1588 case SolConfParam::Enable:
1589 {
1590 bool enable;
1591 uint7_t reserved2;
1592
1593 if (req.unpack(enable, reserved2) != 0 || !req.fullyUnpacked())
1594 {
1595 return responseReqDataLenInvalid();
1596 }
1597
1598 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1599 solInterface, "Enable", enable))
1600 {
1601 return responseUnspecifiedError();
1602 }
1603 break;
1604 }
1605 case SolConfParam::Authentication:
1606 {
1607 uint4_t privilegeBits{};
1608 uint2_t reserved2{};
1609 bool forceAuth = false;
1610 bool forceEncrypt = false;
1611
1612 if (req.unpack(privilegeBits, reserved2, forceAuth, forceEncrypt) !=
1613 0 ||
1614 !req.fullyUnpacked())
1615 {
1616 return responseReqDataLenInvalid();
1617 }
1618
1619 uint8_t privilege = static_cast<uint8_t>(privilegeBits);
Jonathan Domana48bf772023-05-26 17:54:57 -07001620 if (privilege < static_cast<uint8_t>(Privilege::User) ||
Jian Zhang23f44652022-03-17 17:13:10 +08001621 privilege > static_cast<uint8_t>(Privilege::Oem))
1622 {
1623 return ipmi::responseInvalidFieldRequest();
1624 }
1625
1626 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1627 solInterface, "Privilege", privilege))
1628 {
1629 return responseUnspecifiedError();
1630 }
1631
1632 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1633 solInterface, "ForceEncryption",
1634 forceEncrypt))
1635 {
1636 return responseUnspecifiedError();
1637 }
1638
1639 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1640 solInterface, "ForceAuthentication",
1641 forceAuth))
1642 {
1643 return responseUnspecifiedError();
1644 }
1645 break;
1646 }
1647 case SolConfParam::Accumulate:
1648 {
1649 uint8_t interval;
1650 uint8_t threshold;
1651 if (req.unpack(interval, threshold) != 0 || !req.fullyUnpacked())
1652 {
1653 return responseReqDataLenInvalid();
1654 }
1655
1656 if (threshold == 0)
1657 {
1658 return responseInvalidFieldRequest();
1659 }
1660
1661 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1662 solInterface, "AccumulateIntervalMS",
1663 interval))
1664 {
1665 return responseUnspecifiedError();
1666 }
1667
1668 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1669 solInterface, "Threshold", threshold))
1670 {
1671 return responseUnspecifiedError();
1672 }
1673 break;
1674 }
1675 case SolConfParam::Retry:
1676 {
1677 uint3_t countBits;
1678 uint5_t reserved2;
1679 uint8_t interval;
1680
1681 if (req.unpack(countBits, reserved2, interval) != 0 ||
1682 !req.fullyUnpacked())
1683 {
1684 return responseReqDataLenInvalid();
1685 }
1686
1687 uint8_t count = static_cast<uint8_t>(countBits);
1688 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1689 solInterface, "RetryCount", count))
1690 {
1691 return responseUnspecifiedError();
1692 }
1693
1694 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1695 solInterface, "RetryIntervalMS",
1696 interval))
1697 {
1698 return responseUnspecifiedError();
1699 }
1700 break;
1701 }
1702 case SolConfParam::Port:
1703 {
1704 return response(ipmiCCWriteReadParameter);
1705 }
1706 case SolConfParam::NonVbitrate:
1707 case SolConfParam::Vbitrate:
1708 case SolConfParam::Channel:
1709 default:
1710 return response(ipmiCCParamNotSupported);
1711 }
1712 return responseSuccess();
1713}
1714
1715RspType<message::Payload> getSolConfParams(Context::ptr ctx,
1716 uint4_t channelBits,
Willy Tu11d68892022-01-20 10:37:34 -08001717 uint3_t /*reserved*/, bool revOnly,
1718 uint8_t parameter, uint8_t /*set*/,
1719 uint8_t /*block*/)
Jian Zhang23f44652022-03-17 17:13:10 +08001720{
1721 message::Payload ret;
1722 constexpr uint8_t current_revision = 0x11;
1723 ret.pack(current_revision);
1724 if (revOnly)
1725 {
1726 return responseSuccess(std::move(ret));
1727 }
1728
1729 const uint8_t channel = convertCurrentChannelNum(
1730 static_cast<uint8_t>(channelBits), ctx->channel);
1731
1732 if (!isValidChannel(channel))
1733 {
1734 log<level::ERR>("Get Sol Config - Invalid channel in request");
1735 return responseInvalidFieldRequest();
1736 }
1737
1738 std::string solService{};
1739 std::string solPathWitheEthName = solPath + ipmi::getChannelName(channel);
1740
1741 if (ipmi::getService(ctx, solInterface, solPathWitheEthName, solService))
1742 {
1743 log<level::ERR>("Set Sol Config - Invalid solInterface",
1744 entry("SERVICE=%s", solService.c_str()),
1745 entry("OBJPATH=%s", solPathWitheEthName.c_str()),
1746 entry("INTERFACE=%s", solInterface));
1747 return responseInvalidFieldRequest();
1748 }
1749
1750 switch (static_cast<SolConfParam>(parameter))
1751 {
1752 case SolConfParam::Progress:
1753 {
1754 uint8_t progress;
1755 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1756 solInterface, "Progress", progress))
1757 {
1758 return responseUnspecifiedError();
1759 }
1760 ret.pack(progress);
1761 return responseSuccess(std::move(ret));
1762 }
1763 case SolConfParam::Enable:
1764 {
1765 bool enable{};
1766 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1767 solInterface, "Enable", enable))
1768 {
1769 return responseUnspecifiedError();
1770 }
1771 ret.pack(enable, uint7_t{});
1772 return responseSuccess(std::move(ret));
1773 }
1774 case SolConfParam::Authentication:
1775 {
1776 // 4bits, cast when pack
1777 uint8_t privilege;
1778 bool forceAuth = false;
1779 bool forceEncrypt = false;
1780
1781 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1782 solInterface, "Privilege", privilege))
1783 {
1784 return responseUnspecifiedError();
1785 }
1786
1787 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1788 solInterface, "ForceAuthentication",
1789 forceAuth))
1790 {
1791 return responseUnspecifiedError();
1792 }
1793
1794 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1795 solInterface, "ForceEncryption",
1796 forceEncrypt))
1797 {
1798 return responseUnspecifiedError();
1799 }
1800 ret.pack(uint4_t{privilege}, uint2_t{}, forceAuth, forceEncrypt);
1801 return responseSuccess(std::move(ret));
1802 }
1803 case SolConfParam::Accumulate:
1804 {
1805 uint8_t interval{}, threshold{};
1806
1807 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1808 solInterface, "AccumulateIntervalMS",
1809 interval))
1810 {
1811 return responseUnspecifiedError();
1812 }
1813
1814 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1815 solInterface, "Threshold", threshold))
1816 {
1817 return responseUnspecifiedError();
1818 }
1819 ret.pack(interval, threshold);
1820 return responseSuccess(std::move(ret));
1821 }
1822 case SolConfParam::Retry:
1823 {
1824 // 3bits, cast when cast
1825 uint8_t count{};
1826 uint8_t interval{};
1827
1828 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1829 solInterface, "RetryCount", count))
1830 {
1831 return responseUnspecifiedError();
1832 }
1833
1834 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1835 solInterface, "RetryIntervalMS",
1836 interval))
1837 {
1838 return responseUnspecifiedError();
1839 }
1840 ret.pack(uint3_t{count}, uint5_t{}, interval);
1841 return responseSuccess(std::move(ret));
1842 }
1843 case SolConfParam::Port:
1844 {
1845 auto port = solDefaultPort;
1846 ret.pack(static_cast<uint16_t>(port));
1847 return responseSuccess(std::move(ret));
1848 }
1849 case SolConfParam::Channel:
1850 {
1851 ret.pack(channel);
1852 return responseSuccess(std::move(ret));
1853 }
1854 case SolConfParam::NonVbitrate:
Jonathan Domana48bf772023-05-26 17:54:57 -07001855 {
1856 uint64_t baudRate;
1857 uint8_t encodedBitRate = 0;
1858 if (ipmi::getDbusProperty(
1859 ctx, "xyz.openbmc_project.Console.default",
1860 "/xyz/openbmc_project/console/default",
1861 "xyz.openbmc_project.Console.UART", "Baud", baudRate))
1862 {
1863 return ipmi::responseUnspecifiedError();
1864 }
1865 switch (baudRate)
1866 {
1867 case 9600:
1868 encodedBitRate = 0x06;
1869 break;
1870 case 19200:
1871 encodedBitRate = 0x07;
1872 break;
1873 case 38400:
1874 encodedBitRate = 0x08;
1875 break;
1876 case 57600:
1877 encodedBitRate = 0x09;
1878 break;
1879 case 115200:
1880 encodedBitRate = 0x0a;
1881 break;
1882 default:
1883 break;
1884 }
1885 ret.pack(encodedBitRate);
1886 return responseSuccess(std::move(ret));
1887 }
Jian Zhang23f44652022-03-17 17:13:10 +08001888 case SolConfParam::Vbitrate:
1889 default:
1890 return response(ipmiCCParamNotSupported);
1891 }
1892
1893 return response(ccParamNotSupported);
1894}
1895
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001896} // namespace transport
1897} // namespace ipmi
Ratan Gupta1247e0b2018-03-07 10:47:25 +05301898
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001899void register_netfn_transport_functions() __attribute__((constructor));
Ratan Gupta1247e0b2018-03-07 10:47:25 +05301900
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001901void register_netfn_transport_functions()
1902{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001903 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1904 ipmi::transport::cmdSetLanConfigParameters,
1905 ipmi::Privilege::Admin, ipmi::transport::setLan);
1906 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1907 ipmi::transport::cmdGetLanConfigParameters,
Johnathan Mantey34698d52019-11-19 14:47:30 -08001908 ipmi::Privilege::Operator, ipmi::transport::getLan);
Jian Zhang23f44652022-03-17 17:13:10 +08001909 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1910 ipmi::transport::cmdSetSolConfigParameters,
1911 ipmi::Privilege::Admin,
1912 ipmi::transport::setSolConfParams);
1913 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1914 ipmi::transport::cmdGetSolConfigParameters,
1915 ipmi::Privilege::User,
1916 ipmi::transport::getSolConfParams);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001917}