blob: a533e8cdaf5f66e203d696b1af8ec5e17ee56cfa [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
Jian Zhangd05b9dd2023-07-04 14:48:40 +0800392 if (struct in_addr nullIPv4{0};
393 (address == std::nullopt || address.value().s_addr != nullIPv4.s_addr))
Johnathan Manteycbfa6e12023-06-01 06:57:25 -0700394 {
395 createIfAddr<AF_INET>(bus, params, address.value_or(ifaddr->address),
396 prefix.value_or(fallbackPrefix));
397 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700398}
399
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700400template <int family>
Patrick Williams5d82f472022-07-22 19:26:53 -0500401std::optional<IfNeigh<family>> findGatewayNeighbor(sdbusplus::bus_t& bus,
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700402 const ChannelParams& params,
403 ObjectLookupCache& neighbors)
404{
405 auto gateway = getGatewayProperty<family>(bus, params);
406 if (!gateway)
407 {
408 return std::nullopt;
409 }
410
411 return findStaticNeighbor<family>(bus, params, *gateway, neighbors);
412}
413
414template <int family>
Patrick Williams5d82f472022-07-22 19:26:53 -0500415std::optional<IfNeigh<family>> getGatewayNeighbor(sdbusplus::bus_t& bus,
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700416 const ChannelParams& params)
417{
418 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
419 return findGatewayNeighbor<family>(bus, params, neighbors);
420}
421
422template <int family>
Patrick Williams5d82f472022-07-22 19:26:53 -0500423void reconfigureGatewayMAC(sdbusplus::bus_t& bus, const ChannelParams& params,
424 const ether_addr& mac)
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700425{
426 auto gateway = getGatewayProperty<family>(bus, params);
427 if (!gateway)
428 {
429 log<level::ERR>("Tried to set Gateway MAC without Gateway");
430 elog<InternalFailure>();
431 }
432
433 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500434 auto neighbor = findStaticNeighbor<family>(bus, params, *gateway,
435 neighbors);
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700436 if (neighbor)
437 {
438 deleteObjectIfExists(bus, params.service, neighbor->path);
439 }
440
441 createNeighbor<family>(bus, params, *gateway, mac);
442}
443
William A. Kennington III16064aa2019-04-13 17:44:53 -0700444/** @brief Deconfigures the IPv6 address info configured for the interface
445 *
446 * @param[in] bus - The bus object used for lookups
447 * @param[in] params - The parameters for the channel
448 * @param[in] idx - The address index to operate on
449 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500450void deconfigureIfAddr6(sdbusplus::bus_t& bus, const ChannelParams& params,
William A. Kennington III16064aa2019-04-13 17:44:53 -0700451 uint8_t idx)
452{
453 auto ifaddr = getIfAddr<AF_INET6>(bus, params, idx, originsV6Static);
454 if (ifaddr)
455 {
456 deleteObjectIfExists(bus, params.service, ifaddr->path);
457 }
458}
459
460/** @brief Reconfigures the IPv6 address info configured for the interface
461 *
462 * @param[in] bus - The bus object used for lookups
463 * @param[in] params - The parameters for the channel
464 * @param[in] idx - The address index to operate on
465 * @param[in] address - The new address
466 * @param[in] prefix - The new address prefix
467 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500468void reconfigureIfAddr6(sdbusplus::bus_t& bus, const ChannelParams& params,
William A. Kennington III16064aa2019-04-13 17:44:53 -0700469 uint8_t idx, const in6_addr& address, uint8_t prefix)
470{
471 deconfigureIfAddr6(bus, params, idx);
472 createIfAddr<AF_INET6>(bus, params, address, prefix);
473}
474
475/** @brief Converts the AddressOrigin into an IPv6Source
476 *
477 * @param[in] origin - The DBus Address Origin to convert
478 * @return The IPv6Source version of the origin
479 */
480IPv6Source originToSourceType(IP::AddressOrigin origin)
481{
482 switch (origin)
483 {
484 case IP::AddressOrigin::Static:
485 return IPv6Source::Static;
486 case IP::AddressOrigin::DHCP:
487 return IPv6Source::DHCP;
488 case IP::AddressOrigin::SLAAC:
489 return IPv6Source::SLAAC;
490 default:
491 {
492 auto originStr = sdbusplus::xyz::openbmc_project::Network::server::
493 convertForMessage(origin);
494 log<level::ERR>(
495 "Invalid IP::AddressOrigin conversion to IPv6Source",
496 entry("ORIGIN=%s", originStr.c_str()));
497 elog<InternalFailure>();
498 }
499 }
500}
501
502/** @brief Packs the IPMI message response with IPv6 address data
503 *
504 * @param[out] ret - The IPMI response payload to be packed
505 * @param[in] channel - The channel id corresponding to an ethernet interface
506 * @param[in] set - The set selector for determining address index
507 * @param[in] origins - Set of valid origins for address filtering
508 */
509void getLanIPv6Address(message::Payload& ret, uint8_t channel, uint8_t set,
510 const std::unordered_set<IP::AddressOrigin>& origins)
511{
512 auto source = IPv6Source::Static;
513 bool enabled = false;
514 in6_addr addr{};
Johnathan Mantey5aae0922021-10-21 13:05:36 -0700515 uint8_t prefix{};
William A. Kennington III16064aa2019-04-13 17:44:53 -0700516 auto status = IPv6AddressStatus::Disabled;
517
518 auto ifaddr = channelCall<getIfAddr<AF_INET6>>(channel, set, origins);
519 if (ifaddr)
520 {
521 source = originToSourceType(ifaddr->origin);
Johnathan Mantey846af862021-10-21 12:48:54 -0700522 enabled = (origins == originsV6Static);
William A. Kennington III16064aa2019-04-13 17:44:53 -0700523 addr = ifaddr->address;
524 prefix = ifaddr->prefix;
525 status = IPv6AddressStatus::Active;
526 }
527
528 ret.pack(set);
William A. Kennington III7a0e5df2021-05-19 13:31:29 -0700529 ret.pack(types::enum_cast<uint4_t>(source), uint3_t{}, enabled);
William A. Kennington III16064aa2019-04-13 17:44:53 -0700530 ret.pack(std::string_view(reinterpret_cast<char*>(&addr), sizeof(addr)));
531 ret.pack(prefix);
William A. Kennington III7a0e5df2021-05-19 13:31:29 -0700532 ret.pack(types::enum_cast<uint8_t>(status));
William A. Kennington III16064aa2019-04-13 17:44:53 -0700533}
534
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700535/** @brief Gets the vlan ID configured on the interface
536 *
537 * @param[in] bus - The bus object used for lookups
538 * @param[in] params - The parameters for the channel
539 * @return VLAN id or the standard 0 for no VLAN
540 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500541uint16_t getVLANProperty(sdbusplus::bus_t& bus, const ChannelParams& params)
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700542{
543 // VLAN devices will always have a separate logical object
544 if (params.ifPath == params.logicalPath)
545 {
546 return 0;
547 }
548
549 auto vlan = std::get<uint32_t>(getDbusProperty(
550 bus, params.service, params.logicalPath, INTF_VLAN, "Id"));
551 if ((vlan & VLAN_VALUE_MASK) != vlan)
552 {
553 logWithChannel<level::ERR>(params, "networkd returned an invalid vlan",
554 entry("VLAN=%" PRIu32, vlan));
Tom Josepha30c8d32018-03-22 02:15:03 +0530555 elog<InternalFailure>();
556 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700557 return vlan;
Tom Josepha30c8d32018-03-22 02:15:03 +0530558}
559
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700560/** @brief Deletes all of the possible configuration parameters for a channel
561 *
562 * @param[in] bus - The bus object used for lookups
563 * @param[in] params - The parameters for the channel
564 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500565void deconfigureChannel(sdbusplus::bus_t& bus, ChannelParams& params)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500566{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700567 // Delete all objects associated with the interface
568 auto objreq = bus.new_method_call(MAPPER_BUS_NAME, MAPPER_OBJ, MAPPER_INTF,
569 "GetSubTree");
570 objreq.append(PATH_ROOT, 0, std::vector<std::string>{DELETE_INTERFACE});
571 auto objreply = bus.call(objreq);
572 ObjectTree objs;
573 objreply.read(objs);
574 for (const auto& [path, impls] : objs)
575 {
576 if (path.find(params.ifname) == path.npos)
577 {
578 continue;
579 }
580 for (const auto& [service, intfs] : impls)
581 {
582 deleteObjectIfExists(bus, service, path);
583 }
584 // Update params to reflect the deletion of vlan
585 if (path == params.logicalPath)
586 {
587 params.logicalPath = params.ifPath;
588 }
589 }
590
591 // Clear out any settings on the lower physical interface
Johnathan Mantey65265362019-11-14 11:24:19 -0800592 setDHCPv6Property(bus, params, EthernetInterface::DHCPConf::none, false);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500593}
594
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700595/** @brief Creates a new VLAN on the specified interface
596 *
597 * @param[in] bus - The bus object used for lookups
598 * @param[in] params - The parameters for the channel
599 * @param[in] vlan - The id of the new vlan
600 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500601void createVLAN(sdbusplus::bus_t& bus, ChannelParams& params, uint16_t vlan)
Ratan Guptab8e99552017-07-27 07:07:48 +0530602{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700603 if (vlan == 0)
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +0530604 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700605 return;
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +0530606 }
607
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700608 auto req = bus.new_method_call(params.service.c_str(), PATH_ROOT,
609 INTF_VLAN_CREATE, "VLAN");
610 req.append(params.ifname, static_cast<uint32_t>(vlan));
611 auto reply = bus.call(req);
612 sdbusplus::message::object_path newPath;
613 reply.read(newPath);
614 params.logicalPath = std::move(newPath);
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +0530615}
616
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700617/** @brief Performs the necessary reconfiguration to change the VLAN
618 *
619 * @param[in] bus - The bus object used for lookups
620 * @param[in] params - The parameters for the channel
621 * @param[in] vlan - The new vlan id to use
622 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500623void reconfigureVLAN(sdbusplus::bus_t& bus, ChannelParams& params,
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700624 uint16_t vlan)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500625{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700626 // Unfortunatetly we don't have built-in functions to migrate our interface
627 // customizations to new VLAN interfaces, or have some kind of decoupling.
628 // We therefore must retain all of our old information, setup the new VLAN
629 // configuration, then restore the old info.
Nan Li3d0df912016-10-18 19:51:41 +0800630
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700631 // Save info from the old logical interface
632 ObjectLookupCache ips(bus, params, INTF_IP);
633 auto ifaddr4 = findIfAddr<AF_INET>(bus, params, 0, originsV4, ips);
William A. Kennington III16064aa2019-04-13 17:44:53 -0700634 std::vector<IfAddr<AF_INET6>> ifaddrs6;
635 for (uint8_t i = 0; i < MAX_IPV6_STATIC_ADDRESSES; ++i)
636 {
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500637 auto ifaddr6 = findIfAddr<AF_INET6>(bus, params, i, originsV6Static,
638 ips);
William A. Kennington III16064aa2019-04-13 17:44:53 -0700639 if (!ifaddr6)
640 {
641 break;
642 }
643 ifaddrs6.push_back(std::move(*ifaddr6));
644 }
Johnathan Mantey65265362019-11-14 11:24:19 -0800645 EthernetInterface::DHCPConf dhcp = getDHCPProperty(bus, params);
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700646 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
647 auto neighbor4 = findGatewayNeighbor<AF_INET>(bus, params, neighbors);
William A. Kennington III16064aa2019-04-13 17:44:53 -0700648 auto neighbor6 = findGatewayNeighbor<AF_INET6>(bus, params, neighbors);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500649
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700650 deconfigureChannel(bus, params);
651 createVLAN(bus, params, vlan);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500652
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700653 // Re-establish the saved settings
Johnathan Mantey65265362019-11-14 11:24:19 -0800654 setDHCPv6Property(bus, params, dhcp, false);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700655 if (ifaddr4)
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800656 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700657 createIfAddr<AF_INET>(bus, params, ifaddr4->address, ifaddr4->prefix);
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800658 }
William A. Kennington III16064aa2019-04-13 17:44:53 -0700659 for (const auto& ifaddr6 : ifaddrs6)
660 {
661 createIfAddr<AF_INET6>(bus, params, ifaddr6.address, ifaddr6.prefix);
662 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700663 if (neighbor4)
664 {
665 createNeighbor<AF_INET>(bus, params, neighbor4->ip, neighbor4->mac);
666 }
William A. Kennington III16064aa2019-04-13 17:44:53 -0700667 if (neighbor6)
668 {
669 createNeighbor<AF_INET6>(bus, params, neighbor6->ip, neighbor6->mac);
670 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700671}
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800672
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700673/** @brief Turns a prefix into a netmask
674 *
675 * @param[in] prefix - The prefix length
676 * @return The netmask
677 */
678in_addr prefixToNetmask(uint8_t prefix)
679{
680 if (prefix > 32)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500681 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700682 log<level::ERR>("Invalid prefix", entry("PREFIX=%" PRIu8, prefix));
683 elog<InternalFailure>();
684 }
685 if (prefix == 0)
686 {
687 // Avoids 32-bit lshift by 32 UB
688 return {};
689 }
690 return {htobe32(~UINT32_C(0) << (32 - prefix))};
691}
692
693/** @brief Turns a a netmask into a prefix length
694 *
695 * @param[in] netmask - The netmask in byte form
696 * @return The prefix length
697 */
698uint8_t netmaskToPrefix(in_addr netmask)
699{
700 uint32_t x = be32toh(netmask.s_addr);
701 if ((~x & (~x + 1)) != 0)
702 {
703 char maskStr[INET_ADDRSTRLEN];
704 inet_ntop(AF_INET, &netmask, maskStr, sizeof(maskStr));
705 log<level::ERR>("Invalid netmask", entry("NETMASK=%s", maskStr));
706 elog<InternalFailure>();
707 }
Johnathan Mantey62c05dd2019-11-20 14:07:44 -0800708 return static_cast<bool>(x)
709 ? AddrFamily<AF_INET>::defaultPrefix - __builtin_ctz(x)
710 : 0;
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700711}
712
713// We need to store this value so it can be returned to the client
714// It is volatile so safe to store in daemon memory.
715static std::unordered_map<uint8_t, SetStatus> setStatus;
716
717// Until we have good support for fixed versions of IPMI tool
718// we need to return the VLAN id for disabled VLANs. The value is only
719// used for verification that a disable operation succeeded and will only
720// be sent if our system indicates that vlans are disabled.
721static std::unordered_map<uint8_t, uint16_t> lastDisabledVlan;
722
723/** @brief Gets the set status for the channel if it exists
724 * Otherise populates and returns the default value.
725 *
726 * @param[in] channel - The channel id corresponding to an ethernet interface
727 * @return A reference to the SetStatus for the channel
728 */
729SetStatus& getSetStatus(uint8_t channel)
730{
731 auto it = setStatus.find(channel);
732 if (it != setStatus.end())
733 {
734 return it->second;
735 }
736 return setStatus[channel] = SetStatus::Complete;
737}
738
Johnathan Mantey3b7a4072021-01-26 14:24:53 -0800739/** @brief Gets the IPv6 Router Advertisement value
740 *
741 * @param[in] bus - The bus object used for lookups
742 * @param[in] params - The parameters for the channel
743 * @return networkd IPV6AcceptRA value
744 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500745static bool getIPv6AcceptRA(sdbusplus::bus_t& bus, const ChannelParams& params)
Johnathan Mantey3b7a4072021-01-26 14:24:53 -0800746{
747 auto raEnabled =
748 std::get<bool>(getDbusProperty(bus, params.service, params.logicalPath,
749 INTF_ETHERNET, "IPv6AcceptRA"));
750 return raEnabled;
751}
752
753/** @brief Sets the IPv6AcceptRA flag
754 *
755 * @param[in] bus - The bus object used for lookups
756 * @param[in] params - The parameters for the channel
757 * @param[in] ipv6AcceptRA - boolean to enable/disable IPv6 Routing
758 * Advertisement
759 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500760void setIPv6AcceptRA(sdbusplus::bus_t& bus, const ChannelParams& params,
Johnathan Mantey3b7a4072021-01-26 14:24:53 -0800761 const bool ipv6AcceptRA)
762{
763 setDbusProperty(bus, params.service, params.logicalPath, INTF_ETHERNET,
764 "IPv6AcceptRA", ipv6AcceptRA);
765}
766
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700767/**
768 * Define placeholder command handlers for the OEM Extension bytes for the Set
769 * LAN Configuration Parameters and Get LAN Configuration Parameters
770 * commands. Using "weak" linking allows the placeholder setLanOem/getLanOem
771 * functions below to be overridden.
772 * To create handlers for your own proprietary command set:
773 * Create/modify a phosphor-ipmi-host Bitbake append file within your Yocto
774 * recipe
775 * Create C++ file(s) that define IPMI handler functions matching the
776 * function names below (i.e. setLanOem). The default name for the
777 * transport IPMI commands is transporthandler_oem.cpp.
778 * Add:
Johnathan Manteyefe26682022-08-11 14:30:45 -0700779 * EXTRA_OEMESON:append = "-Dtransport-oem=enabled"
780 * Create a do_configure:prepend()/do_install:append() method in your
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700781 * bbappend file to copy the file to the build directory.
782 * Add:
783 * PROJECT_SRC_DIR := "${THISDIR}/${PN}"
784 * # Copy the "strong" functions into the working directory, overriding the
785 * # placeholder functions.
Johnathan Manteyefe26682022-08-11 14:30:45 -0700786 * do_configure:prepend(){
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700787 * cp -f ${PROJECT_SRC_DIR}/transporthandler_oem.cpp ${S}
788 * }
789 *
790 * # Clean up after complilation has completed
Johnathan Manteyefe26682022-08-11 14:30:45 -0700791 * do_install:append(){
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700792 * rm -f ${S}/transporthandler_oem.cpp
793 * }
794 *
795 */
796
797/**
798 * Define the placeholder OEM commands as having weak linkage. Create
799 * setLanOem, and getLanOem functions in the transporthandler_oem.cpp
800 * file. The functions defined there must not have the "weak" attribute
801 * applied to them.
802 */
803RspType<> setLanOem(uint8_t channel, uint8_t parameter, message::Payload& req)
804 __attribute__((weak));
805RspType<message::Payload> getLanOem(uint8_t channel, uint8_t parameter,
806 uint8_t set, uint8_t block)
807 __attribute__((weak));
808
Willy Tu11d68892022-01-20 10:37:34 -0800809RspType<> setLanOem(uint8_t, uint8_t, message::Payload& req)
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700810{
811 req.trailingOk = true;
812 return response(ccParamNotSupported);
813}
814
Willy Tu11d68892022-01-20 10:37:34 -0800815RspType<message::Payload> getLanOem(uint8_t, uint8_t, uint8_t, uint8_t)
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700816{
817 return response(ccParamNotSupported);
818}
Rajashekar Gade Reddy0b993fd2019-12-24 16:37:15 +0530819/**
820 * @brief is MAC address valid.
821 *
822 * This function checks whether the MAC address is valid or not.
823 *
824 * @param[in] mac - MAC address.
825 * @return true if MAC address is valid else retun false.
826 **/
827bool isValidMACAddress(const ether_addr& mac)
828{
829 // check if mac address is empty
830 if (equal(mac, ether_addr{}))
831 {
832 return false;
833 }
834 // we accept only unicast MAC addresses and same thing has been checked in
835 // phosphor-network layer. If the least significant bit of the first octet
836 // is set to 1, it is multicast MAC else it is unicast MAC address.
837 if (mac.ether_addr_octet[0] & 1)
838 {
839 return false;
840 }
841 return true;
842}
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700843
vijayabharathix shettycc769252020-02-27 17:52:20 +0000844RspType<> setLan(Context::ptr ctx, uint4_t channelBits, uint4_t reserved1,
845 uint8_t parameter, message::Payload& req)
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700846{
vijayabharathix shettycc769252020-02-27 17:52:20 +0000847 const uint8_t channel = convertCurrentChannelNum(
848 static_cast<uint8_t>(channelBits), ctx->channel);
849 if (reserved1 || !isValidChannel(channel))
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700850 {
vijayabharathix shettycc769252020-02-27 17:52:20 +0000851 log<level::ERR>("Set Lan - Invalid field in request");
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700852 req.trailingOk = true;
853 return responseInvalidFieldRequest();
854 }
855
856 switch (static_cast<LanParam>(parameter))
857 {
858 case LanParam::SetStatus:
859 {
860 uint2_t flag;
861 uint6_t rsvd;
862 if (req.unpack(flag, rsvd) != 0 || !req.fullyUnpacked())
863 {
864 return responseReqDataLenInvalid();
865 }
Johnathan Mantey4a156852019-12-11 13:47:43 -0800866 if (rsvd)
867 {
868 return responseInvalidFieldRequest();
869 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700870 auto status = static_cast<SetStatus>(static_cast<uint8_t>(flag));
871 switch (status)
872 {
873 case SetStatus::Complete:
874 {
875 getSetStatus(channel) = status;
876 return responseSuccess();
877 }
878 case SetStatus::InProgress:
879 {
880 auto& storedStatus = getSetStatus(channel);
881 if (storedStatus == SetStatus::InProgress)
882 {
883 return response(ccParamSetLocked);
884 }
885 storedStatus = status;
886 return responseSuccess();
887 }
888 case SetStatus::Commit:
889 if (getSetStatus(channel) != SetStatus::InProgress)
890 {
891 return responseInvalidFieldRequest();
892 }
893 return responseSuccess();
894 }
895 return response(ccParamNotSupported);
896 }
897 case LanParam::AuthSupport:
898 {
899 req.trailingOk = true;
900 return response(ccParamReadOnly);
901 }
902 case LanParam::AuthEnables:
903 {
904 req.trailingOk = true;
Johnathan Mantey76ce9c72019-11-14 14:41:46 -0800905 return response(ccParamReadOnly);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700906 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -0800907 case LanParam::IP:
Hariharasubramanian R83951912016-01-20 07:06:36 -0600908 {
Johnathan Mantey65265362019-11-14 11:24:19 -0800909 EthernetInterface::DHCPConf dhcp =
910 channelCall<getDHCPProperty>(channel);
911 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
912 (dhcp == EthernetInterface::DHCPConf::both))
Johnathan Mantey930104a2019-12-17 09:18:34 -0800913 {
914 return responseCommandNotAvailable();
915 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700916 in_addr ip;
917 std::array<uint8_t, sizeof(ip)> bytes;
918 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
919 {
920 return responseReqDataLenInvalid();
921 }
922 copyInto(ip, bytes);
923 channelCall<reconfigureIfAddr4>(channel, ip, std::nullopt);
924 return responseSuccess();
Ratan Guptab8e99552017-07-27 07:07:48 +0530925 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700926 case LanParam::IPSrc:
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530927 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700928 uint4_t flag;
929 uint4_t rsvd;
930 if (req.unpack(flag, rsvd) != 0 || !req.fullyUnpacked())
931 {
932 return responseReqDataLenInvalid();
933 }
Johnathan Mantey4a156852019-12-11 13:47:43 -0800934 if (rsvd)
935 {
936 return responseInvalidFieldRequest();
937 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700938 switch (static_cast<IPSrc>(static_cast<uint8_t>(flag)))
939 {
940 case IPSrc::DHCP:
941 {
Johnathan Mantey65265362019-11-14 11:24:19 -0800942 // The IPSrc IPMI command is only for IPv4
943 // management. Modifying IPv6 state is done using
944 // a completely different Set LAN Configuration
945 // subcommand.
946 channelCall<setDHCPv4Property>(
947 channel, EthernetInterface::DHCPConf::v4);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700948 return responseSuccess();
949 }
950 case IPSrc::Unspecified:
951 case IPSrc::Static:
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700952 {
Johnathan Mantey65265362019-11-14 11:24:19 -0800953 channelCall<setDHCPv4Property>(
954 channel, EthernetInterface::DHCPConf::none);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700955 return responseSuccess();
956 }
Rajashekar Gade Reddy8a860ea2019-12-24 11:31:19 +0530957 case IPSrc::BIOS:
958 case IPSrc::BMC:
959 {
960 return responseInvalidFieldRequest();
961 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700962 }
963 return response(ccParamNotSupported);
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530964 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -0800965 case LanParam::MAC:
Ratan Guptab8e99552017-07-27 07:07:48 +0530966 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700967 ether_addr mac;
968 std::array<uint8_t, sizeof(mac)> bytes;
969 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
Suryakanth Sekar0a327e12019-08-08 14:30:19 +0530970 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700971 return responseReqDataLenInvalid();
Suryakanth Sekar0a327e12019-08-08 14:30:19 +0530972 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700973 copyInto(mac, bytes);
Rajashekar Gade Reddy0b993fd2019-12-24 16:37:15 +0530974
975 if (!isValidMACAddress(mac))
976 {
977 return responseInvalidFieldRequest();
978 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700979 channelCall<setMACProperty>(channel, mac);
980 return responseSuccess();
Ratan Gupta533d03b2017-07-30 10:39:22 +0530981 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700982 case LanParam::SubnetMask:
Ratan Guptab8e99552017-07-27 07:07:48 +0530983 {
Johnathan Mantey65265362019-11-14 11:24:19 -0800984 EthernetInterface::DHCPConf dhcp =
985 channelCall<getDHCPProperty>(channel);
986 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
987 (dhcp == EthernetInterface::DHCPConf::both))
Johnathan Mantey930104a2019-12-17 09:18:34 -0800988 {
989 return responseCommandNotAvailable();
990 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700991 in_addr netmask;
992 std::array<uint8_t, sizeof(netmask)> bytes;
993 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
Ratan Guptab8e99552017-07-27 07:07:48 +0530994 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700995 return responseReqDataLenInvalid();
Ratan Guptab8e99552017-07-27 07:07:48 +0530996 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700997 copyInto(netmask, bytes);
Jiaqing Zhao6d4a44e2022-01-24 15:04:00 +0800998 uint8_t prefix = netmaskToPrefix(netmask);
999 if (prefix < MIN_IPV4_PREFIX_LENGTH)
1000 {
1001 return responseInvalidFieldRequest();
1002 }
1003 channelCall<reconfigureIfAddr4>(channel, std::nullopt, prefix);
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001004 return responseSuccess();
Ratan Guptab8e99552017-07-27 07:07:48 +05301005 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001006 case LanParam::Gateway1:
Ratan Guptab8e99552017-07-27 07:07:48 +05301007 {
Johnathan Mantey65265362019-11-14 11:24:19 -08001008 EthernetInterface::DHCPConf dhcp =
1009 channelCall<getDHCPProperty>(channel);
1010 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
1011 (dhcp == EthernetInterface::DHCPConf::both))
Johnathan Mantey930104a2019-12-17 09:18:34 -08001012 {
1013 return responseCommandNotAvailable();
1014 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001015 in_addr gateway;
1016 std::array<uint8_t, sizeof(gateway)> bytes;
1017 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1018 {
1019 return responseReqDataLenInvalid();
1020 }
1021 copyInto(gateway, bytes);
1022 channelCall<setGatewayProperty<AF_INET>>(channel, gateway);
1023 return responseSuccess();
1024 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001025 case LanParam::Gateway1MAC:
1026 {
1027 ether_addr gatewayMAC;
1028 std::array<uint8_t, sizeof(gatewayMAC)> bytes;
1029 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1030 {
1031 return responseReqDataLenInvalid();
1032 }
1033 copyInto(gatewayMAC, bytes);
1034 channelCall<reconfigureGatewayMAC<AF_INET>>(channel, gatewayMAC);
1035 return responseSuccess();
1036 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001037 case LanParam::VLANId:
1038 {
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301039 uint12_t vlanData = 0;
1040 uint3_t reserved = 0;
1041 bool vlanEnable = 0;
1042
1043 if (req.unpack(vlanData) || req.unpack(reserved) ||
1044 req.unpack(vlanEnable) || !req.fullyUnpacked())
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001045 {
1046 return responseReqDataLenInvalid();
1047 }
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301048
1049 if (reserved)
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001050 {
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301051 return responseInvalidFieldRequest();
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001052 }
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301053
1054 uint16_t vlan = static_cast<uint16_t>(vlanData);
1055
1056 if (!vlanEnable)
1057 {
1058 lastDisabledVlan[channel] = vlan;
1059 vlan = 0;
1060 }
jayaprakash Mutyala84c49dc2020-05-18 23:12:13 +00001061 else if (vlan == 0 || vlan == VLAN_VALUE_MASK)
1062 {
1063 return responseInvalidFieldRequest();
1064 }
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301065
jayaprakash Mutyala84c49dc2020-05-18 23:12:13 +00001066 channelCall<reconfigureVLAN>(channel, vlan);
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001067 return responseSuccess();
1068 }
1069 case LanParam::CiphersuiteSupport:
1070 case LanParam::CiphersuiteEntries:
William A. Kennington III16064aa2019-04-13 17:44:53 -07001071 case LanParam::IPFamilySupport:
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001072 {
1073 req.trailingOk = true;
1074 return response(ccParamReadOnly);
Ratan Guptab8e99552017-07-27 07:07:48 +05301075 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001076 case LanParam::IPFamilyEnables:
1077 {
1078 uint8_t enables;
1079 if (req.unpack(enables) != 0 || !req.fullyUnpacked())
1080 {
1081 return responseReqDataLenInvalid();
1082 }
1083 switch (static_cast<IPFamilyEnables>(enables))
1084 {
1085 case IPFamilyEnables::DualStack:
1086 return responseSuccess();
1087 case IPFamilyEnables::IPv4Only:
1088 case IPFamilyEnables::IPv6Only:
1089 return response(ccParamNotSupported);
1090 }
1091 return response(ccParamNotSupported);
1092 }
1093 case LanParam::IPv6Status:
1094 {
1095 req.trailingOk = true;
1096 return response(ccParamReadOnly);
1097 }
1098 case LanParam::IPv6StaticAddresses:
1099 {
1100 uint8_t set;
1101 uint7_t rsvd;
1102 bool enabled;
1103 in6_addr ip;
1104 std::array<uint8_t, sizeof(ip)> ipbytes;
1105 uint8_t prefix;
1106 uint8_t status;
1107 if (req.unpack(set, rsvd, enabled, ipbytes, prefix, status) != 0 ||
1108 !req.fullyUnpacked())
1109 {
1110 return responseReqDataLenInvalid();
1111 }
Johnathan Mantey4a156852019-12-11 13:47:43 -08001112 if (rsvd)
1113 {
1114 return responseInvalidFieldRequest();
1115 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001116 copyInto(ip, ipbytes);
1117 if (enabled)
1118 {
Jiaqing Zhao6d4a44e2022-01-24 15:04:00 +08001119 if (prefix < MIN_IPV6_PREFIX_LENGTH ||
1120 prefix > MAX_IPV6_PREFIX_LENGTH)
1121 {
1122 return responseParmOutOfRange();
1123 }
Johnathan Manteya291f492021-10-15 13:45:27 -07001124 try
1125 {
1126 channelCall<reconfigureIfAddr6>(channel, set, ip, prefix);
1127 }
Patrick Williams5d82f472022-07-22 19:26:53 -05001128 catch (const sdbusplus::exception_t& e)
Johnathan Manteya291f492021-10-15 13:45:27 -07001129 {
1130 if (std::string_view err{
1131 "xyz.openbmc_project.Common.Error.InvalidArgument"};
1132 err == e.name())
1133 {
1134 return responseInvalidFieldRequest();
1135 }
1136 else
1137 {
1138 throw;
1139 }
1140 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001141 }
1142 else
1143 {
1144 channelCall<deconfigureIfAddr6>(channel, set);
1145 }
1146 return responseSuccess();
1147 }
1148 case LanParam::IPv6DynamicAddresses:
1149 {
1150 req.trailingOk = true;
1151 return response(ccParamReadOnly);
1152 }
1153 case LanParam::IPv6RouterControl:
1154 {
1155 std::bitset<8> control;
Johnathan Mantey3b7a4072021-01-26 14:24:53 -08001156 constexpr uint8_t reservedRACCBits = 0xfc;
William A. Kennington III16064aa2019-04-13 17:44:53 -07001157 if (req.unpack(control) != 0 || !req.fullyUnpacked())
1158 {
1159 return responseReqDataLenInvalid();
1160 }
Johnathan Mantey3b7a4072021-01-26 14:24:53 -08001161 if (std::bitset<8> expected(control &
1162 std::bitset<8>(reservedRACCBits));
1163 expected.any())
William A. Kennington III16064aa2019-04-13 17:44:53 -07001164 {
Johnathan Mantey3b7a4072021-01-26 14:24:53 -08001165 return response(ccParamNotSupported);
William A. Kennington III16064aa2019-04-13 17:44:53 -07001166 }
Johnathan Mantey3b7a4072021-01-26 14:24:53 -08001167
1168 bool enableRA = control[IPv6RouterControlFlag::Dynamic];
1169 channelCall<setIPv6AcceptRA>(channel, enableRA);
William A. Kennington III16064aa2019-04-13 17:44:53 -07001170 return responseSuccess();
1171 }
1172 case LanParam::IPv6StaticRouter1IP:
1173 {
1174 in6_addr gateway;
1175 std::array<uint8_t, sizeof(gateway)> bytes;
1176 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1177 {
1178 return responseReqDataLenInvalid();
1179 }
1180 copyInto(gateway, bytes);
1181 channelCall<setGatewayProperty<AF_INET6>>(channel, gateway);
1182 return responseSuccess();
1183 }
1184 case LanParam::IPv6StaticRouter1MAC:
1185 {
1186 ether_addr mac;
1187 std::array<uint8_t, sizeof(mac)> bytes;
1188 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1189 {
1190 return responseReqDataLenInvalid();
1191 }
1192 copyInto(mac, bytes);
1193 channelCall<reconfigureGatewayMAC<AF_INET6>>(channel, mac);
1194 return responseSuccess();
1195 }
1196 case LanParam::IPv6StaticRouter1PrefixLength:
1197 {
1198 uint8_t prefix;
1199 if (req.unpack(prefix) != 0 || !req.fullyUnpacked())
1200 {
1201 return responseReqDataLenInvalid();
1202 }
1203 if (prefix != 0)
1204 {
1205 return responseInvalidFieldRequest();
1206 }
1207 return responseSuccess();
1208 }
1209 case LanParam::IPv6StaticRouter1PrefixValue:
1210 {
1211 std::array<uint8_t, sizeof(in6_addr)> bytes;
1212 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1213 {
1214 return responseReqDataLenInvalid();
1215 }
1216 // Accept any prefix value since our prefix length has to be 0
1217 return responseSuccess();
1218 }
jayaprakash Mutyalab741b992019-12-02 17:29:09 +00001219 case LanParam::cipherSuitePrivilegeLevels:
1220 {
1221 uint8_t reserved;
1222 std::array<uint4_t, ipmi::maxCSRecords> cipherSuitePrivs;
1223
1224 if (req.unpack(reserved, cipherSuitePrivs) || !req.fullyUnpacked())
1225 {
1226 return responseReqDataLenInvalid();
1227 }
1228
1229 if (reserved)
1230 {
1231 return responseInvalidFieldRequest();
1232 }
1233
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -05001234 uint8_t resp = getCipherConfigObject(csPrivFileName,
1235 csPrivDefaultFileName)
1236 .setCSPrivilegeLevels(channel, cipherSuitePrivs);
jayaprakash Mutyalab741b992019-12-02 17:29:09 +00001237 if (!resp)
1238 {
1239 return responseSuccess();
1240 }
1241 else
1242 {
1243 req.trailingOk = true;
1244 return response(resp);
1245 }
1246 }
Ratan Guptab8e99552017-07-27 07:07:48 +05301247 }
vishwa1eaea4f2016-02-26 11:57:40 -06001248
Johnathan Manteyb87034e2019-09-16 10:50:50 -07001249 if ((parameter >= oemCmdStart) && (parameter <= oemCmdEnd))
1250 {
1251 return setLanOem(channel, parameter, req);
1252 }
1253
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001254 req.trailingOk = true;
1255 return response(ccParamNotSupported);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001256}
1257
vijayabharathix shettycc769252020-02-27 17:52:20 +00001258RspType<message::Payload> getLan(Context::ptr ctx, uint4_t channelBits,
1259 uint3_t reserved, bool revOnly,
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001260 uint8_t parameter, uint8_t set, uint8_t block)
Ratan Guptab8e99552017-07-27 07:07:48 +05301261{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001262 message::Payload ret;
1263 constexpr uint8_t current_revision = 0x11;
1264 ret.pack(current_revision);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001265
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001266 if (revOnly)
Suryakanth Sekare4054402019-08-08 15:16:52 +05301267 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001268 return responseSuccess(std::move(ret));
Suryakanth Sekare4054402019-08-08 15:16:52 +05301269 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001270
vijayabharathix shettycc769252020-02-27 17:52:20 +00001271 const uint8_t channel = convertCurrentChannelNum(
1272 static_cast<uint8_t>(channelBits), ctx->channel);
1273 if (reserved || !isValidChannel(channel))
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001274 {
vijayabharathix shettycc769252020-02-27 17:52:20 +00001275 log<level::ERR>("Get Lan - Invalid field in request");
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001276 return responseInvalidFieldRequest();
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001277 }
1278
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001279 static std::vector<uint8_t> cipherList;
1280 static bool listInit = false;
1281 if (!listInit)
1282 {
1283 try
1284 {
1285 cipherList = cipher::getCipherList();
1286 listInit = true;
1287 }
1288 catch (const std::exception& e)
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -05001289 {}
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001290 }
1291
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001292 switch (static_cast<LanParam>(parameter))
Tom Josepha30c8d32018-03-22 02:15:03 +05301293 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001294 case LanParam::SetStatus:
Tom Josepha30c8d32018-03-22 02:15:03 +05301295 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001296 SetStatus status;
1297 try
1298 {
1299 status = setStatus.at(channel);
1300 }
1301 catch (const std::out_of_range&)
1302 {
1303 status = SetStatus::Complete;
1304 }
William A. Kennington III7a0e5df2021-05-19 13:31:29 -07001305 ret.pack(types::enum_cast<uint2_t>(status), uint6_t{});
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001306 return responseSuccess(std::move(ret));
Tom Josepha30c8d32018-03-22 02:15:03 +05301307 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001308 case LanParam::AuthSupport:
Tom Josepha30c8d32018-03-22 02:15:03 +05301309 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001310 std::bitset<6> support;
1311 ret.pack(support, uint2_t{});
1312 return responseSuccess(std::move(ret));
Tom Josepha30c8d32018-03-22 02:15:03 +05301313 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001314 case LanParam::AuthEnables:
vishwa1eaea4f2016-02-26 11:57:40 -06001315 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001316 std::bitset<6> enables;
1317 ret.pack(enables, uint2_t{}); // Callback
1318 ret.pack(enables, uint2_t{}); // User
1319 ret.pack(enables, uint2_t{}); // Operator
1320 ret.pack(enables, uint2_t{}); // Admin
1321 ret.pack(enables, uint2_t{}); // OEM
1322 return responseSuccess(std::move(ret));
William A. Kennington III39f94ef2018-11-19 22:36:16 -08001323 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001324 case LanParam::IP:
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001325 {
1326 auto ifaddr = channelCall<getIfAddr4>(channel);
1327 in_addr addr{};
1328 if (ifaddr)
1329 {
1330 addr = ifaddr->address;
1331 }
1332 ret.pack(dataRef(addr));
1333 return responseSuccess(std::move(ret));
1334 }
1335 case LanParam::IPSrc:
1336 {
1337 auto src = IPSrc::Static;
Johnathan Mantey65265362019-11-14 11:24:19 -08001338 EthernetInterface::DHCPConf dhcp =
1339 channelCall<getDHCPProperty>(channel);
1340 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
1341 (dhcp == EthernetInterface::DHCPConf::both))
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001342 {
1343 src = IPSrc::DHCP;
1344 }
William A. Kennington III7a0e5df2021-05-19 13:31:29 -07001345 ret.pack(types::enum_cast<uint4_t>(src), uint4_t{});
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001346 return responseSuccess(std::move(ret));
1347 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001348 case LanParam::MAC:
William A. Kennington III39f94ef2018-11-19 22:36:16 -08001349 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001350 ether_addr mac = channelCall<getMACProperty>(channel);
1351 ret.pack(dataRef(mac));
1352 return responseSuccess(std::move(ret));
1353 }
1354 case LanParam::SubnetMask:
1355 {
1356 auto ifaddr = channelCall<getIfAddr4>(channel);
1357 uint8_t prefix = AddrFamily<AF_INET>::defaultPrefix;
1358 if (ifaddr)
Ratan Guptab8e99552017-07-27 07:07:48 +05301359 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001360 prefix = ifaddr->prefix;
1361 }
1362 in_addr netmask = prefixToNetmask(prefix);
1363 ret.pack(dataRef(netmask));
1364 return responseSuccess(std::move(ret));
1365 }
1366 case LanParam::Gateway1:
1367 {
1368 auto gateway =
1369 channelCall<getGatewayProperty<AF_INET>>(channel).value_or(
1370 in_addr{});
1371 ret.pack(dataRef(gateway));
1372 return responseSuccess(std::move(ret));
1373 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001374 case LanParam::Gateway1MAC:
1375 {
1376 ether_addr mac{};
1377 auto neighbor = channelCall<getGatewayNeighbor<AF_INET>>(channel);
1378 if (neighbor)
1379 {
1380 mac = neighbor->mac;
1381 }
1382 ret.pack(dataRef(mac));
1383 return responseSuccess(std::move(ret));
1384 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001385 case LanParam::VLANId:
1386 {
1387 uint16_t vlan = channelCall<getVLANProperty>(channel);
1388 if (vlan != 0)
1389 {
1390 vlan |= VLAN_ENABLE_FLAG;
Ratan Guptab8e99552017-07-27 07:07:48 +05301391 }
1392 else
1393 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001394 vlan = lastDisabledVlan[channel];
Ratan Guptab8e99552017-07-27 07:07:48 +05301395 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001396 ret.pack(vlan);
1397 return responseSuccess(std::move(ret));
Adriana Kobylak342df102016-02-10 13:48:16 -06001398 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001399 case LanParam::CiphersuiteSupport:
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001400 {
srikanta mondal1d8579c2020-04-15 17:13:25 +00001401 if (getChannelSessionSupport(channel) ==
1402 EChannelSessSupported::none)
1403 {
1404 return responseInvalidFieldRequest();
1405 }
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001406 if (!listInit)
1407 {
1408 return responseUnspecifiedError();
1409 }
1410 ret.pack(static_cast<uint8_t>(cipherList.size() - 1));
1411 return responseSuccess(std::move(ret));
1412 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001413 case LanParam::CiphersuiteEntries:
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001414 {
srikanta mondal1d8579c2020-04-15 17:13:25 +00001415 if (getChannelSessionSupport(channel) ==
1416 EChannelSessSupported::none)
1417 {
1418 return responseInvalidFieldRequest();
1419 }
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001420 if (!listInit)
1421 {
1422 return responseUnspecifiedError();
1423 }
1424 ret.pack(cipherList);
1425 return responseSuccess(std::move(ret));
1426 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001427 case LanParam::IPFamilySupport:
1428 {
1429 std::bitset<8> support;
1430 support[IPFamilySupportFlag::IPv6Only] = 0;
1431 support[IPFamilySupportFlag::DualStack] = 1;
1432 support[IPFamilySupportFlag::IPv6Alerts] = 1;
1433 ret.pack(support);
1434 return responseSuccess(std::move(ret));
1435 }
1436 case LanParam::IPFamilyEnables:
1437 {
1438 ret.pack(static_cast<uint8_t>(IPFamilyEnables::DualStack));
1439 return responseSuccess(std::move(ret));
1440 }
1441 case LanParam::IPv6Status:
1442 {
1443 ret.pack(MAX_IPV6_STATIC_ADDRESSES);
1444 ret.pack(MAX_IPV6_DYNAMIC_ADDRESSES);
1445 std::bitset<8> support;
1446 support[IPv6StatusFlag::DHCP] = 1;
1447 support[IPv6StatusFlag::SLAAC] = 1;
1448 ret.pack(support);
1449 return responseSuccess(std::move(ret));
1450 }
1451 case LanParam::IPv6StaticAddresses:
1452 {
1453 if (set >= MAX_IPV6_STATIC_ADDRESSES)
1454 {
1455 return responseParmOutOfRange();
1456 }
1457 getLanIPv6Address(ret, channel, set, originsV6Static);
1458 return responseSuccess(std::move(ret));
1459 }
1460 case LanParam::IPv6DynamicAddresses:
1461 {
1462 if (set >= MAX_IPV6_DYNAMIC_ADDRESSES)
1463 {
1464 return responseParmOutOfRange();
1465 }
1466 getLanIPv6Address(ret, channel, set, originsV6Dynamic);
1467 return responseSuccess(std::move(ret));
1468 }
1469 case LanParam::IPv6RouterControl:
1470 {
1471 std::bitset<8> control;
Johnathan Mantey3b7a4072021-01-26 14:24:53 -08001472 control[IPv6RouterControlFlag::Dynamic] =
1473 channelCall<getIPv6AcceptRA>(channel);
1474 control[IPv6RouterControlFlag::Static] = 1;
William A. Kennington III16064aa2019-04-13 17:44:53 -07001475 ret.pack(control);
1476 return responseSuccess(std::move(ret));
1477 }
1478 case LanParam::IPv6StaticRouter1IP:
1479 {
1480 in6_addr gateway{};
Johnathan Mantey65265362019-11-14 11:24:19 -08001481 EthernetInterface::DHCPConf dhcp =
1482 channelCall<getDHCPProperty>(channel);
1483 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
1484 (dhcp == EthernetInterface::DHCPConf::none))
William A. Kennington III16064aa2019-04-13 17:44:53 -07001485 {
1486 gateway =
1487 channelCall<getGatewayProperty<AF_INET6>>(channel).value_or(
1488 in6_addr{});
1489 }
1490 ret.pack(dataRef(gateway));
1491 return responseSuccess(std::move(ret));
1492 }
1493 case LanParam::IPv6StaticRouter1MAC:
1494 {
1495 ether_addr mac{};
1496 auto neighbor = channelCall<getGatewayNeighbor<AF_INET6>>(channel);
1497 if (neighbor)
1498 {
1499 mac = neighbor->mac;
1500 }
1501 ret.pack(dataRef(mac));
1502 return responseSuccess(std::move(ret));
1503 }
1504 case LanParam::IPv6StaticRouter1PrefixLength:
1505 {
1506 ret.pack(UINT8_C(0));
1507 return responseSuccess(std::move(ret));
1508 }
1509 case LanParam::IPv6StaticRouter1PrefixValue:
1510 {
1511 in6_addr prefix{};
1512 ret.pack(dataRef(prefix));
1513 return responseSuccess(std::move(ret));
1514 }
jayaprakash Mutyalab741b992019-12-02 17:29:09 +00001515 case LanParam::cipherSuitePrivilegeLevels:
1516 {
1517 std::array<uint4_t, ipmi::maxCSRecords> csPrivilegeLevels;
1518
1519 uint8_t resp =
1520 getCipherConfigObject(csPrivFileName, csPrivDefaultFileName)
1521 .getCSPrivilegeLevels(channel, csPrivilegeLevels);
1522 if (!resp)
1523 {
1524 constexpr uint8_t reserved1 = 0x00;
1525 ret.pack(reserved1, csPrivilegeLevels);
1526 return responseSuccess(std::move(ret));
1527 }
1528 else
1529 {
1530 return response(resp);
1531 }
1532 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001533 }
1534
Johnathan Manteyb87034e2019-09-16 10:50:50 -07001535 if ((parameter >= oemCmdStart) && (parameter <= oemCmdEnd))
1536 {
1537 return getLanOem(channel, parameter, set, block);
1538 }
1539
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001540 return response(ccParamNotSupported);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001541}
1542
Jian Zhang23f44652022-03-17 17:13:10 +08001543constexpr const char* solInterface = "xyz.openbmc_project.Ipmi.SOL";
1544constexpr const char* solPath = "/xyz/openbmc_project/ipmi/sol/";
1545constexpr const uint16_t solDefaultPort = 623;
1546
1547RspType<> setSolConfParams(Context::ptr ctx, uint4_t channelBits,
Willy Tu11d68892022-01-20 10:37:34 -08001548 uint4_t /*reserved*/, uint8_t parameter,
Jian Zhang23f44652022-03-17 17:13:10 +08001549 message::Payload& req)
1550{
1551 const uint8_t channel = convertCurrentChannelNum(
1552 static_cast<uint8_t>(channelBits), ctx->channel);
1553
1554 if (!isValidChannel(channel))
1555 {
1556 log<level::ERR>("Set Sol Config - Invalid channel in request");
1557 return responseInvalidFieldRequest();
1558 }
1559
1560 std::string solService{};
1561 std::string solPathWitheEthName = solPath + ipmi::getChannelName(channel);
1562
1563 if (ipmi::getService(ctx, solInterface, solPathWitheEthName, solService))
1564 {
1565 log<level::ERR>("Set Sol Config - Invalid solInterface",
1566 entry("SERVICE=%s", solService.c_str()),
1567 entry("OBJPATH=%s", solPathWitheEthName.c_str()),
1568 entry("INTERFACE=%s", solInterface));
1569 return responseInvalidFieldRequest();
1570 }
1571
1572 switch (static_cast<SolConfParam>(parameter))
1573 {
1574 case SolConfParam::Progress:
1575 {
1576 uint8_t progress;
1577 if (req.unpack(progress) != 0 || !req.fullyUnpacked())
1578 {
1579 return responseReqDataLenInvalid();
1580 }
1581
1582 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1583 solInterface, "Progress", progress))
1584 {
1585 return responseUnspecifiedError();
1586 }
1587 break;
1588 }
1589 case SolConfParam::Enable:
1590 {
1591 bool enable;
1592 uint7_t reserved2;
1593
1594 if (req.unpack(enable, reserved2) != 0 || !req.fullyUnpacked())
1595 {
1596 return responseReqDataLenInvalid();
1597 }
1598
1599 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1600 solInterface, "Enable", enable))
1601 {
1602 return responseUnspecifiedError();
1603 }
1604 break;
1605 }
1606 case SolConfParam::Authentication:
1607 {
1608 uint4_t privilegeBits{};
1609 uint2_t reserved2{};
1610 bool forceAuth = false;
1611 bool forceEncrypt = false;
1612
1613 if (req.unpack(privilegeBits, reserved2, forceAuth, forceEncrypt) !=
1614 0 ||
1615 !req.fullyUnpacked())
1616 {
1617 return responseReqDataLenInvalid();
1618 }
1619
1620 uint8_t privilege = static_cast<uint8_t>(privilegeBits);
Jonathan Domana48bf772023-05-26 17:54:57 -07001621 if (privilege < static_cast<uint8_t>(Privilege::User) ||
Jian Zhang23f44652022-03-17 17:13:10 +08001622 privilege > static_cast<uint8_t>(Privilege::Oem))
1623 {
1624 return ipmi::responseInvalidFieldRequest();
1625 }
1626
1627 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1628 solInterface, "Privilege", privilege))
1629 {
1630 return responseUnspecifiedError();
1631 }
1632
1633 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1634 solInterface, "ForceEncryption",
1635 forceEncrypt))
1636 {
1637 return responseUnspecifiedError();
1638 }
1639
1640 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1641 solInterface, "ForceAuthentication",
1642 forceAuth))
1643 {
1644 return responseUnspecifiedError();
1645 }
1646 break;
1647 }
1648 case SolConfParam::Accumulate:
1649 {
1650 uint8_t interval;
1651 uint8_t threshold;
1652 if (req.unpack(interval, threshold) != 0 || !req.fullyUnpacked())
1653 {
1654 return responseReqDataLenInvalid();
1655 }
1656
1657 if (threshold == 0)
1658 {
1659 return responseInvalidFieldRequest();
1660 }
1661
1662 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1663 solInterface, "AccumulateIntervalMS",
1664 interval))
1665 {
1666 return responseUnspecifiedError();
1667 }
1668
1669 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1670 solInterface, "Threshold", threshold))
1671 {
1672 return responseUnspecifiedError();
1673 }
1674 break;
1675 }
1676 case SolConfParam::Retry:
1677 {
1678 uint3_t countBits;
1679 uint5_t reserved2;
1680 uint8_t interval;
1681
1682 if (req.unpack(countBits, reserved2, interval) != 0 ||
1683 !req.fullyUnpacked())
1684 {
1685 return responseReqDataLenInvalid();
1686 }
1687
1688 uint8_t count = static_cast<uint8_t>(countBits);
1689 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1690 solInterface, "RetryCount", count))
1691 {
1692 return responseUnspecifiedError();
1693 }
1694
1695 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1696 solInterface, "RetryIntervalMS",
1697 interval))
1698 {
1699 return responseUnspecifiedError();
1700 }
1701 break;
1702 }
1703 case SolConfParam::Port:
1704 {
1705 return response(ipmiCCWriteReadParameter);
1706 }
1707 case SolConfParam::NonVbitrate:
1708 case SolConfParam::Vbitrate:
1709 case SolConfParam::Channel:
1710 default:
1711 return response(ipmiCCParamNotSupported);
1712 }
1713 return responseSuccess();
1714}
1715
1716RspType<message::Payload> getSolConfParams(Context::ptr ctx,
1717 uint4_t channelBits,
Willy Tu11d68892022-01-20 10:37:34 -08001718 uint3_t /*reserved*/, bool revOnly,
1719 uint8_t parameter, uint8_t /*set*/,
1720 uint8_t /*block*/)
Jian Zhang23f44652022-03-17 17:13:10 +08001721{
1722 message::Payload ret;
1723 constexpr uint8_t current_revision = 0x11;
1724 ret.pack(current_revision);
1725 if (revOnly)
1726 {
1727 return responseSuccess(std::move(ret));
1728 }
1729
1730 const uint8_t channel = convertCurrentChannelNum(
1731 static_cast<uint8_t>(channelBits), ctx->channel);
1732
1733 if (!isValidChannel(channel))
1734 {
1735 log<level::ERR>("Get Sol Config - Invalid channel in request");
1736 return responseInvalidFieldRequest();
1737 }
1738
1739 std::string solService{};
1740 std::string solPathWitheEthName = solPath + ipmi::getChannelName(channel);
1741
1742 if (ipmi::getService(ctx, solInterface, solPathWitheEthName, solService))
1743 {
1744 log<level::ERR>("Set Sol Config - Invalid solInterface",
1745 entry("SERVICE=%s", solService.c_str()),
1746 entry("OBJPATH=%s", solPathWitheEthName.c_str()),
1747 entry("INTERFACE=%s", solInterface));
1748 return responseInvalidFieldRequest();
1749 }
1750
1751 switch (static_cast<SolConfParam>(parameter))
1752 {
1753 case SolConfParam::Progress:
1754 {
1755 uint8_t progress;
1756 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1757 solInterface, "Progress", progress))
1758 {
1759 return responseUnspecifiedError();
1760 }
1761 ret.pack(progress);
1762 return responseSuccess(std::move(ret));
1763 }
1764 case SolConfParam::Enable:
1765 {
1766 bool enable{};
1767 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1768 solInterface, "Enable", enable))
1769 {
1770 return responseUnspecifiedError();
1771 }
1772 ret.pack(enable, uint7_t{});
1773 return responseSuccess(std::move(ret));
1774 }
1775 case SolConfParam::Authentication:
1776 {
1777 // 4bits, cast when pack
1778 uint8_t privilege;
1779 bool forceAuth = false;
1780 bool forceEncrypt = false;
1781
1782 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1783 solInterface, "Privilege", privilege))
1784 {
1785 return responseUnspecifiedError();
1786 }
1787
1788 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1789 solInterface, "ForceAuthentication",
1790 forceAuth))
1791 {
1792 return responseUnspecifiedError();
1793 }
1794
1795 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1796 solInterface, "ForceEncryption",
1797 forceEncrypt))
1798 {
1799 return responseUnspecifiedError();
1800 }
1801 ret.pack(uint4_t{privilege}, uint2_t{}, forceAuth, forceEncrypt);
1802 return responseSuccess(std::move(ret));
1803 }
1804 case SolConfParam::Accumulate:
1805 {
1806 uint8_t interval{}, threshold{};
1807
1808 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1809 solInterface, "AccumulateIntervalMS",
1810 interval))
1811 {
1812 return responseUnspecifiedError();
1813 }
1814
1815 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1816 solInterface, "Threshold", threshold))
1817 {
1818 return responseUnspecifiedError();
1819 }
1820 ret.pack(interval, threshold);
1821 return responseSuccess(std::move(ret));
1822 }
1823 case SolConfParam::Retry:
1824 {
1825 // 3bits, cast when cast
1826 uint8_t count{};
1827 uint8_t interval{};
1828
1829 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1830 solInterface, "RetryCount", count))
1831 {
1832 return responseUnspecifiedError();
1833 }
1834
1835 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1836 solInterface, "RetryIntervalMS",
1837 interval))
1838 {
1839 return responseUnspecifiedError();
1840 }
1841 ret.pack(uint3_t{count}, uint5_t{}, interval);
1842 return responseSuccess(std::move(ret));
1843 }
1844 case SolConfParam::Port:
1845 {
1846 auto port = solDefaultPort;
1847 ret.pack(static_cast<uint16_t>(port));
1848 return responseSuccess(std::move(ret));
1849 }
1850 case SolConfParam::Channel:
1851 {
1852 ret.pack(channel);
1853 return responseSuccess(std::move(ret));
1854 }
1855 case SolConfParam::NonVbitrate:
Jonathan Domana48bf772023-05-26 17:54:57 -07001856 {
1857 uint64_t baudRate;
1858 uint8_t encodedBitRate = 0;
1859 if (ipmi::getDbusProperty(
1860 ctx, "xyz.openbmc_project.Console.default",
1861 "/xyz/openbmc_project/console/default",
1862 "xyz.openbmc_project.Console.UART", "Baud", baudRate))
1863 {
1864 return ipmi::responseUnspecifiedError();
1865 }
1866 switch (baudRate)
1867 {
1868 case 9600:
1869 encodedBitRate = 0x06;
1870 break;
1871 case 19200:
1872 encodedBitRate = 0x07;
1873 break;
1874 case 38400:
1875 encodedBitRate = 0x08;
1876 break;
1877 case 57600:
1878 encodedBitRate = 0x09;
1879 break;
1880 case 115200:
1881 encodedBitRate = 0x0a;
1882 break;
1883 default:
1884 break;
1885 }
1886 ret.pack(encodedBitRate);
1887 return responseSuccess(std::move(ret));
1888 }
Jian Zhang23f44652022-03-17 17:13:10 +08001889 case SolConfParam::Vbitrate:
1890 default:
1891 return response(ipmiCCParamNotSupported);
1892 }
1893
1894 return response(ccParamNotSupported);
1895}
1896
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001897} // namespace transport
1898} // namespace ipmi
Ratan Gupta1247e0b2018-03-07 10:47:25 +05301899
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001900void register_netfn_transport_functions() __attribute__((constructor));
Ratan Gupta1247e0b2018-03-07 10:47:25 +05301901
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001902void register_netfn_transport_functions()
1903{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001904 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1905 ipmi::transport::cmdSetLanConfigParameters,
1906 ipmi::Privilege::Admin, ipmi::transport::setLan);
1907 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1908 ipmi::transport::cmdGetLanConfigParameters,
Johnathan Mantey34698d52019-11-19 14:47:30 -08001909 ipmi::Privilege::Operator, ipmi::transport::getLan);
Jian Zhang23f44652022-03-17 17:13:10 +08001910 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1911 ipmi::transport::cmdSetSolConfigParameters,
1912 ipmi::Privilege::Admin,
1913 ipmi::transport::setSolConfParams);
1914 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1915 ipmi::transport::cmdGetSolConfigParameters,
1916 ipmi::Privilege::User,
1917 ipmi::transport::getSolConfParams);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001918}