blob: da4231a72764d4023f77337a3bbf45bb90452c3c [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};
Jayaprakash Mutyala4e02b432023-07-13 13:50:40 +0000393 (address == std::nullopt && prefix != std::nullopt) ||
394 (address != std::nullopt &&
395 (address.value().s_addr != nullIPv4.s_addr)))
Johnathan Manteycbfa6e12023-06-01 06:57:25 -0700396 {
397 createIfAddr<AF_INET>(bus, params, address.value_or(ifaddr->address),
398 prefix.value_or(fallbackPrefix));
399 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700400}
401
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700402template <int family>
Patrick Williams5d82f472022-07-22 19:26:53 -0500403std::optional<IfNeigh<family>> findGatewayNeighbor(sdbusplus::bus_t& bus,
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700404 const ChannelParams& params,
405 ObjectLookupCache& neighbors)
406{
407 auto gateway = getGatewayProperty<family>(bus, params);
408 if (!gateway)
409 {
410 return std::nullopt;
411 }
412
413 return findStaticNeighbor<family>(bus, params, *gateway, neighbors);
414}
415
416template <int family>
Patrick Williams5d82f472022-07-22 19:26:53 -0500417std::optional<IfNeigh<family>> getGatewayNeighbor(sdbusplus::bus_t& bus,
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700418 const ChannelParams& params)
419{
420 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
421 return findGatewayNeighbor<family>(bus, params, neighbors);
422}
423
424template <int family>
Patrick Williams5d82f472022-07-22 19:26:53 -0500425void reconfigureGatewayMAC(sdbusplus::bus_t& bus, const ChannelParams& params,
426 const ether_addr& mac)
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700427{
428 auto gateway = getGatewayProperty<family>(bus, params);
429 if (!gateway)
430 {
431 log<level::ERR>("Tried to set Gateway MAC without Gateway");
432 elog<InternalFailure>();
433 }
434
435 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500436 auto neighbor = findStaticNeighbor<family>(bus, params, *gateway,
437 neighbors);
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700438 if (neighbor)
439 {
440 deleteObjectIfExists(bus, params.service, neighbor->path);
441 }
442
443 createNeighbor<family>(bus, params, *gateway, mac);
444}
445
William A. Kennington III16064aa2019-04-13 17:44:53 -0700446/** @brief Deconfigures the IPv6 address info configured for the interface
447 *
448 * @param[in] bus - The bus object used for lookups
449 * @param[in] params - The parameters for the channel
450 * @param[in] idx - The address index to operate on
451 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500452void deconfigureIfAddr6(sdbusplus::bus_t& bus, const ChannelParams& params,
William A. Kennington III16064aa2019-04-13 17:44:53 -0700453 uint8_t idx)
454{
455 auto ifaddr = getIfAddr<AF_INET6>(bus, params, idx, originsV6Static);
456 if (ifaddr)
457 {
458 deleteObjectIfExists(bus, params.service, ifaddr->path);
459 }
460}
461
462/** @brief Reconfigures the IPv6 address info configured for the interface
463 *
464 * @param[in] bus - The bus object used for lookups
465 * @param[in] params - The parameters for the channel
466 * @param[in] idx - The address index to operate on
467 * @param[in] address - The new address
468 * @param[in] prefix - The new address prefix
469 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500470void reconfigureIfAddr6(sdbusplus::bus_t& bus, const ChannelParams& params,
William A. Kennington III16064aa2019-04-13 17:44:53 -0700471 uint8_t idx, const in6_addr& address, uint8_t prefix)
472{
473 deconfigureIfAddr6(bus, params, idx);
474 createIfAddr<AF_INET6>(bus, params, address, prefix);
475}
476
477/** @brief Converts the AddressOrigin into an IPv6Source
478 *
479 * @param[in] origin - The DBus Address Origin to convert
480 * @return The IPv6Source version of the origin
481 */
482IPv6Source originToSourceType(IP::AddressOrigin origin)
483{
484 switch (origin)
485 {
486 case IP::AddressOrigin::Static:
487 return IPv6Source::Static;
488 case IP::AddressOrigin::DHCP:
489 return IPv6Source::DHCP;
490 case IP::AddressOrigin::SLAAC:
491 return IPv6Source::SLAAC;
492 default:
493 {
494 auto originStr = sdbusplus::xyz::openbmc_project::Network::server::
495 convertForMessage(origin);
496 log<level::ERR>(
497 "Invalid IP::AddressOrigin conversion to IPv6Source",
498 entry("ORIGIN=%s", originStr.c_str()));
499 elog<InternalFailure>();
500 }
501 }
502}
503
504/** @brief Packs the IPMI message response with IPv6 address data
505 *
506 * @param[out] ret - The IPMI response payload to be packed
507 * @param[in] channel - The channel id corresponding to an ethernet interface
508 * @param[in] set - The set selector for determining address index
509 * @param[in] origins - Set of valid origins for address filtering
510 */
511void getLanIPv6Address(message::Payload& ret, uint8_t channel, uint8_t set,
512 const std::unordered_set<IP::AddressOrigin>& origins)
513{
514 auto source = IPv6Source::Static;
515 bool enabled = false;
516 in6_addr addr{};
Johnathan Mantey5aae0922021-10-21 13:05:36 -0700517 uint8_t prefix{};
William A. Kennington III16064aa2019-04-13 17:44:53 -0700518 auto status = IPv6AddressStatus::Disabled;
519
520 auto ifaddr = channelCall<getIfAddr<AF_INET6>>(channel, set, origins);
521 if (ifaddr)
522 {
523 source = originToSourceType(ifaddr->origin);
Johnathan Mantey846af862021-10-21 12:48:54 -0700524 enabled = (origins == originsV6Static);
William A. Kennington III16064aa2019-04-13 17:44:53 -0700525 addr = ifaddr->address;
526 prefix = ifaddr->prefix;
527 status = IPv6AddressStatus::Active;
528 }
529
530 ret.pack(set);
William A. Kennington III7a0e5df2021-05-19 13:31:29 -0700531 ret.pack(types::enum_cast<uint4_t>(source), uint3_t{}, enabled);
William A. Kennington III16064aa2019-04-13 17:44:53 -0700532 ret.pack(std::string_view(reinterpret_cast<char*>(&addr), sizeof(addr)));
533 ret.pack(prefix);
William A. Kennington III7a0e5df2021-05-19 13:31:29 -0700534 ret.pack(types::enum_cast<uint8_t>(status));
William A. Kennington III16064aa2019-04-13 17:44:53 -0700535}
536
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700537/** @brief Gets the vlan ID configured on the interface
538 *
539 * @param[in] bus - The bus object used for lookups
540 * @param[in] params - The parameters for the channel
541 * @return VLAN id or the standard 0 for no VLAN
542 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500543uint16_t getVLANProperty(sdbusplus::bus_t& bus, const ChannelParams& params)
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700544{
545 // VLAN devices will always have a separate logical object
546 if (params.ifPath == params.logicalPath)
547 {
548 return 0;
549 }
550
551 auto vlan = std::get<uint32_t>(getDbusProperty(
552 bus, params.service, params.logicalPath, INTF_VLAN, "Id"));
553 if ((vlan & VLAN_VALUE_MASK) != vlan)
554 {
555 logWithChannel<level::ERR>(params, "networkd returned an invalid vlan",
556 entry("VLAN=%" PRIu32, vlan));
Tom Josepha30c8d32018-03-22 02:15:03 +0530557 elog<InternalFailure>();
558 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700559 return vlan;
Tom Josepha30c8d32018-03-22 02:15:03 +0530560}
561
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700562/** @brief Deletes all of the possible configuration parameters for a channel
563 *
564 * @param[in] bus - The bus object used for lookups
565 * @param[in] params - The parameters for the channel
566 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500567void deconfigureChannel(sdbusplus::bus_t& bus, ChannelParams& params)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500568{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700569 // Delete all objects associated with the interface
570 auto objreq = bus.new_method_call(MAPPER_BUS_NAME, MAPPER_OBJ, MAPPER_INTF,
571 "GetSubTree");
572 objreq.append(PATH_ROOT, 0, std::vector<std::string>{DELETE_INTERFACE});
573 auto objreply = bus.call(objreq);
574 ObjectTree objs;
575 objreply.read(objs);
576 for (const auto& [path, impls] : objs)
577 {
578 if (path.find(params.ifname) == path.npos)
579 {
580 continue;
581 }
582 for (const auto& [service, intfs] : impls)
583 {
584 deleteObjectIfExists(bus, service, path);
585 }
586 // Update params to reflect the deletion of vlan
587 if (path == params.logicalPath)
588 {
589 params.logicalPath = params.ifPath;
590 }
591 }
592
593 // Clear out any settings on the lower physical interface
Johnathan Mantey65265362019-11-14 11:24:19 -0800594 setDHCPv6Property(bus, params, EthernetInterface::DHCPConf::none, false);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500595}
596
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700597/** @brief Creates a new VLAN on the specified interface
598 *
599 * @param[in] bus - The bus object used for lookups
600 * @param[in] params - The parameters for the channel
601 * @param[in] vlan - The id of the new vlan
602 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500603void createVLAN(sdbusplus::bus_t& bus, ChannelParams& params, uint16_t vlan)
Ratan Guptab8e99552017-07-27 07:07:48 +0530604{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700605 if (vlan == 0)
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +0530606 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700607 return;
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +0530608 }
609
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700610 auto req = bus.new_method_call(params.service.c_str(), PATH_ROOT,
611 INTF_VLAN_CREATE, "VLAN");
612 req.append(params.ifname, static_cast<uint32_t>(vlan));
613 auto reply = bus.call(req);
614 sdbusplus::message::object_path newPath;
615 reply.read(newPath);
616 params.logicalPath = std::move(newPath);
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +0530617}
618
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700619/** @brief Performs the necessary reconfiguration to change the VLAN
620 *
621 * @param[in] bus - The bus object used for lookups
622 * @param[in] params - The parameters for the channel
623 * @param[in] vlan - The new vlan id to use
624 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500625void reconfigureVLAN(sdbusplus::bus_t& bus, ChannelParams& params,
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700626 uint16_t vlan)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500627{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700628 // Unfortunatetly we don't have built-in functions to migrate our interface
629 // customizations to new VLAN interfaces, or have some kind of decoupling.
630 // We therefore must retain all of our old information, setup the new VLAN
631 // configuration, then restore the old info.
Nan Li3d0df912016-10-18 19:51:41 +0800632
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700633 // Save info from the old logical interface
634 ObjectLookupCache ips(bus, params, INTF_IP);
635 auto ifaddr4 = findIfAddr<AF_INET>(bus, params, 0, originsV4, ips);
William A. Kennington III16064aa2019-04-13 17:44:53 -0700636 std::vector<IfAddr<AF_INET6>> ifaddrs6;
637 for (uint8_t i = 0; i < MAX_IPV6_STATIC_ADDRESSES; ++i)
638 {
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500639 auto ifaddr6 = findIfAddr<AF_INET6>(bus, params, i, originsV6Static,
640 ips);
William A. Kennington III16064aa2019-04-13 17:44:53 -0700641 if (!ifaddr6)
642 {
643 break;
644 }
645 ifaddrs6.push_back(std::move(*ifaddr6));
646 }
Johnathan Mantey65265362019-11-14 11:24:19 -0800647 EthernetInterface::DHCPConf dhcp = getDHCPProperty(bus, params);
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700648 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
649 auto neighbor4 = findGatewayNeighbor<AF_INET>(bus, params, neighbors);
William A. Kennington III16064aa2019-04-13 17:44:53 -0700650 auto neighbor6 = findGatewayNeighbor<AF_INET6>(bus, params, neighbors);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500651
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700652 deconfigureChannel(bus, params);
653 createVLAN(bus, params, vlan);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500654
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700655 // Re-establish the saved settings
Johnathan Mantey65265362019-11-14 11:24:19 -0800656 setDHCPv6Property(bus, params, dhcp, false);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700657 if (ifaddr4)
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800658 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700659 createIfAddr<AF_INET>(bus, params, ifaddr4->address, ifaddr4->prefix);
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800660 }
William A. Kennington III16064aa2019-04-13 17:44:53 -0700661 for (const auto& ifaddr6 : ifaddrs6)
662 {
663 createIfAddr<AF_INET6>(bus, params, ifaddr6.address, ifaddr6.prefix);
664 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700665 if (neighbor4)
666 {
667 createNeighbor<AF_INET>(bus, params, neighbor4->ip, neighbor4->mac);
668 }
William A. Kennington III16064aa2019-04-13 17:44:53 -0700669 if (neighbor6)
670 {
671 createNeighbor<AF_INET6>(bus, params, neighbor6->ip, neighbor6->mac);
672 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700673}
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800674
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700675/** @brief Turns a prefix into a netmask
676 *
677 * @param[in] prefix - The prefix length
678 * @return The netmask
679 */
680in_addr prefixToNetmask(uint8_t prefix)
681{
682 if (prefix > 32)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500683 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700684 log<level::ERR>("Invalid prefix", entry("PREFIX=%" PRIu8, prefix));
685 elog<InternalFailure>();
686 }
687 if (prefix == 0)
688 {
689 // Avoids 32-bit lshift by 32 UB
690 return {};
691 }
692 return {htobe32(~UINT32_C(0) << (32 - prefix))};
693}
694
695/** @brief Turns a a netmask into a prefix length
696 *
697 * @param[in] netmask - The netmask in byte form
698 * @return The prefix length
699 */
700uint8_t netmaskToPrefix(in_addr netmask)
701{
702 uint32_t x = be32toh(netmask.s_addr);
703 if ((~x & (~x + 1)) != 0)
704 {
705 char maskStr[INET_ADDRSTRLEN];
706 inet_ntop(AF_INET, &netmask, maskStr, sizeof(maskStr));
707 log<level::ERR>("Invalid netmask", entry("NETMASK=%s", maskStr));
708 elog<InternalFailure>();
709 }
Johnathan Mantey62c05dd2019-11-20 14:07:44 -0800710 return static_cast<bool>(x)
711 ? AddrFamily<AF_INET>::defaultPrefix - __builtin_ctz(x)
712 : 0;
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700713}
714
715// We need to store this value so it can be returned to the client
716// It is volatile so safe to store in daemon memory.
717static std::unordered_map<uint8_t, SetStatus> setStatus;
718
719// Until we have good support for fixed versions of IPMI tool
720// we need to return the VLAN id for disabled VLANs. The value is only
721// used for verification that a disable operation succeeded and will only
722// be sent if our system indicates that vlans are disabled.
723static std::unordered_map<uint8_t, uint16_t> lastDisabledVlan;
724
725/** @brief Gets the set status for the channel if it exists
726 * Otherise populates and returns the default value.
727 *
728 * @param[in] channel - The channel id corresponding to an ethernet interface
729 * @return A reference to the SetStatus for the channel
730 */
731SetStatus& getSetStatus(uint8_t channel)
732{
733 auto it = setStatus.find(channel);
734 if (it != setStatus.end())
735 {
736 return it->second;
737 }
738 return setStatus[channel] = SetStatus::Complete;
739}
740
Johnathan Mantey3b7a4072021-01-26 14:24:53 -0800741/** @brief Gets the IPv6 Router Advertisement value
742 *
743 * @param[in] bus - The bus object used for lookups
744 * @param[in] params - The parameters for the channel
745 * @return networkd IPV6AcceptRA value
746 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500747static bool getIPv6AcceptRA(sdbusplus::bus_t& bus, const ChannelParams& params)
Johnathan Mantey3b7a4072021-01-26 14:24:53 -0800748{
749 auto raEnabled =
750 std::get<bool>(getDbusProperty(bus, params.service, params.logicalPath,
751 INTF_ETHERNET, "IPv6AcceptRA"));
752 return raEnabled;
753}
754
755/** @brief Sets the IPv6AcceptRA flag
756 *
757 * @param[in] bus - The bus object used for lookups
758 * @param[in] params - The parameters for the channel
759 * @param[in] ipv6AcceptRA - boolean to enable/disable IPv6 Routing
760 * Advertisement
761 */
Patrick Williams5d82f472022-07-22 19:26:53 -0500762void setIPv6AcceptRA(sdbusplus::bus_t& bus, const ChannelParams& params,
Johnathan Mantey3b7a4072021-01-26 14:24:53 -0800763 const bool ipv6AcceptRA)
764{
765 setDbusProperty(bus, params.service, params.logicalPath, INTF_ETHERNET,
766 "IPv6AcceptRA", ipv6AcceptRA);
767}
768
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700769/**
770 * Define placeholder command handlers for the OEM Extension bytes for the Set
771 * LAN Configuration Parameters and Get LAN Configuration Parameters
772 * commands. Using "weak" linking allows the placeholder setLanOem/getLanOem
773 * functions below to be overridden.
774 * To create handlers for your own proprietary command set:
775 * Create/modify a phosphor-ipmi-host Bitbake append file within your Yocto
776 * recipe
777 * Create C++ file(s) that define IPMI handler functions matching the
778 * function names below (i.e. setLanOem). The default name for the
779 * transport IPMI commands is transporthandler_oem.cpp.
780 * Add:
Johnathan Manteyefe26682022-08-11 14:30:45 -0700781 * EXTRA_OEMESON:append = "-Dtransport-oem=enabled"
782 * Create a do_configure:prepend()/do_install:append() method in your
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700783 * bbappend file to copy the file to the build directory.
784 * Add:
785 * PROJECT_SRC_DIR := "${THISDIR}/${PN}"
786 * # Copy the "strong" functions into the working directory, overriding the
787 * # placeholder functions.
Johnathan Manteyefe26682022-08-11 14:30:45 -0700788 * do_configure:prepend(){
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700789 * cp -f ${PROJECT_SRC_DIR}/transporthandler_oem.cpp ${S}
790 * }
791 *
792 * # Clean up after complilation has completed
Johnathan Manteyefe26682022-08-11 14:30:45 -0700793 * do_install:append(){
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700794 * rm -f ${S}/transporthandler_oem.cpp
795 * }
796 *
797 */
798
799/**
800 * Define the placeholder OEM commands as having weak linkage. Create
801 * setLanOem, and getLanOem functions in the transporthandler_oem.cpp
802 * file. The functions defined there must not have the "weak" attribute
803 * applied to them.
804 */
805RspType<> setLanOem(uint8_t channel, uint8_t parameter, message::Payload& req)
806 __attribute__((weak));
807RspType<message::Payload> getLanOem(uint8_t channel, uint8_t parameter,
808 uint8_t set, uint8_t block)
809 __attribute__((weak));
810
Willy Tu11d68892022-01-20 10:37:34 -0800811RspType<> setLanOem(uint8_t, uint8_t, message::Payload& req)
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700812{
813 req.trailingOk = true;
814 return response(ccParamNotSupported);
815}
816
Willy Tu11d68892022-01-20 10:37:34 -0800817RspType<message::Payload> getLanOem(uint8_t, uint8_t, uint8_t, uint8_t)
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700818{
819 return response(ccParamNotSupported);
820}
Rajashekar Gade Reddy0b993fd2019-12-24 16:37:15 +0530821/**
822 * @brief is MAC address valid.
823 *
824 * This function checks whether the MAC address is valid or not.
825 *
826 * @param[in] mac - MAC address.
827 * @return true if MAC address is valid else retun false.
828 **/
829bool isValidMACAddress(const ether_addr& mac)
830{
831 // check if mac address is empty
832 if (equal(mac, ether_addr{}))
833 {
834 return false;
835 }
836 // we accept only unicast MAC addresses and same thing has been checked in
837 // phosphor-network layer. If the least significant bit of the first octet
838 // is set to 1, it is multicast MAC else it is unicast MAC address.
839 if (mac.ether_addr_octet[0] & 1)
840 {
841 return false;
842 }
843 return true;
844}
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700845
vijayabharathix shettycc769252020-02-27 17:52:20 +0000846RspType<> setLan(Context::ptr ctx, uint4_t channelBits, uint4_t reserved1,
847 uint8_t parameter, message::Payload& req)
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700848{
vijayabharathix shettycc769252020-02-27 17:52:20 +0000849 const uint8_t channel = convertCurrentChannelNum(
850 static_cast<uint8_t>(channelBits), ctx->channel);
851 if (reserved1 || !isValidChannel(channel))
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700852 {
vijayabharathix shettycc769252020-02-27 17:52:20 +0000853 log<level::ERR>("Set Lan - Invalid field in request");
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700854 req.trailingOk = true;
855 return responseInvalidFieldRequest();
856 }
857
858 switch (static_cast<LanParam>(parameter))
859 {
860 case LanParam::SetStatus:
861 {
862 uint2_t flag;
863 uint6_t rsvd;
864 if (req.unpack(flag, rsvd) != 0 || !req.fullyUnpacked())
865 {
866 return responseReqDataLenInvalid();
867 }
Johnathan Mantey4a156852019-12-11 13:47:43 -0800868 if (rsvd)
869 {
870 return responseInvalidFieldRequest();
871 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700872 auto status = static_cast<SetStatus>(static_cast<uint8_t>(flag));
873 switch (status)
874 {
875 case SetStatus::Complete:
876 {
877 getSetStatus(channel) = status;
878 return responseSuccess();
879 }
880 case SetStatus::InProgress:
881 {
882 auto& storedStatus = getSetStatus(channel);
883 if (storedStatus == SetStatus::InProgress)
884 {
885 return response(ccParamSetLocked);
886 }
887 storedStatus = status;
888 return responseSuccess();
889 }
890 case SetStatus::Commit:
891 if (getSetStatus(channel) != SetStatus::InProgress)
892 {
893 return responseInvalidFieldRequest();
894 }
895 return responseSuccess();
896 }
897 return response(ccParamNotSupported);
898 }
899 case LanParam::AuthSupport:
900 {
901 req.trailingOk = true;
902 return response(ccParamReadOnly);
903 }
904 case LanParam::AuthEnables:
905 {
906 req.trailingOk = true;
Johnathan Mantey76ce9c72019-11-14 14:41:46 -0800907 return response(ccParamReadOnly);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700908 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -0800909 case LanParam::IP:
Hariharasubramanian R83951912016-01-20 07:06:36 -0600910 {
Johnathan Mantey65265362019-11-14 11:24:19 -0800911 EthernetInterface::DHCPConf dhcp =
912 channelCall<getDHCPProperty>(channel);
913 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
914 (dhcp == EthernetInterface::DHCPConf::both))
Johnathan Mantey930104a2019-12-17 09:18:34 -0800915 {
916 return responseCommandNotAvailable();
917 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700918 in_addr ip;
919 std::array<uint8_t, sizeof(ip)> bytes;
920 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
921 {
922 return responseReqDataLenInvalid();
923 }
924 copyInto(ip, bytes);
925 channelCall<reconfigureIfAddr4>(channel, ip, std::nullopt);
926 return responseSuccess();
Ratan Guptab8e99552017-07-27 07:07:48 +0530927 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700928 case LanParam::IPSrc:
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530929 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700930 uint4_t flag;
931 uint4_t rsvd;
932 if (req.unpack(flag, rsvd) != 0 || !req.fullyUnpacked())
933 {
934 return responseReqDataLenInvalid();
935 }
Johnathan Mantey4a156852019-12-11 13:47:43 -0800936 if (rsvd)
937 {
938 return responseInvalidFieldRequest();
939 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700940 switch (static_cast<IPSrc>(static_cast<uint8_t>(flag)))
941 {
942 case IPSrc::DHCP:
943 {
Johnathan Mantey65265362019-11-14 11:24:19 -0800944 // The IPSrc IPMI command is only for IPv4
945 // management. Modifying IPv6 state is done using
946 // a completely different Set LAN Configuration
947 // subcommand.
948 channelCall<setDHCPv4Property>(
949 channel, EthernetInterface::DHCPConf::v4);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700950 return responseSuccess();
951 }
952 case IPSrc::Unspecified:
953 case IPSrc::Static:
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700954 {
Johnathan Mantey65265362019-11-14 11:24:19 -0800955 channelCall<setDHCPv4Property>(
956 channel, EthernetInterface::DHCPConf::none);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700957 return responseSuccess();
958 }
Rajashekar Gade Reddy8a860ea2019-12-24 11:31:19 +0530959 case IPSrc::BIOS:
960 case IPSrc::BMC:
961 {
962 return responseInvalidFieldRequest();
963 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700964 }
965 return response(ccParamNotSupported);
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530966 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -0800967 case LanParam::MAC:
Ratan Guptab8e99552017-07-27 07:07:48 +0530968 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700969 ether_addr mac;
970 std::array<uint8_t, sizeof(mac)> bytes;
971 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
Suryakanth Sekar0a327e12019-08-08 14:30:19 +0530972 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700973 return responseReqDataLenInvalid();
Suryakanth Sekar0a327e12019-08-08 14:30:19 +0530974 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700975 copyInto(mac, bytes);
Rajashekar Gade Reddy0b993fd2019-12-24 16:37:15 +0530976
977 if (!isValidMACAddress(mac))
978 {
979 return responseInvalidFieldRequest();
980 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700981 channelCall<setMACProperty>(channel, mac);
982 return responseSuccess();
Ratan Gupta533d03b2017-07-30 10:39:22 +0530983 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700984 case LanParam::SubnetMask:
Ratan Guptab8e99552017-07-27 07:07:48 +0530985 {
Johnathan Mantey65265362019-11-14 11:24:19 -0800986 EthernetInterface::DHCPConf dhcp =
987 channelCall<getDHCPProperty>(channel);
988 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
989 (dhcp == EthernetInterface::DHCPConf::both))
Johnathan Mantey930104a2019-12-17 09:18:34 -0800990 {
991 return responseCommandNotAvailable();
992 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700993 in_addr netmask;
994 std::array<uint8_t, sizeof(netmask)> bytes;
995 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
Ratan Guptab8e99552017-07-27 07:07:48 +0530996 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700997 return responseReqDataLenInvalid();
Ratan Guptab8e99552017-07-27 07:07:48 +0530998 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700999 copyInto(netmask, bytes);
Jiaqing Zhao6d4a44e2022-01-24 15:04:00 +08001000 uint8_t prefix = netmaskToPrefix(netmask);
1001 if (prefix < MIN_IPV4_PREFIX_LENGTH)
1002 {
1003 return responseInvalidFieldRequest();
1004 }
1005 channelCall<reconfigureIfAddr4>(channel, std::nullopt, prefix);
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001006 return responseSuccess();
Ratan Guptab8e99552017-07-27 07:07:48 +05301007 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001008 case LanParam::Gateway1:
Ratan Guptab8e99552017-07-27 07:07:48 +05301009 {
Johnathan Mantey65265362019-11-14 11:24:19 -08001010 EthernetInterface::DHCPConf dhcp =
1011 channelCall<getDHCPProperty>(channel);
1012 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
1013 (dhcp == EthernetInterface::DHCPConf::both))
Johnathan Mantey930104a2019-12-17 09:18:34 -08001014 {
1015 return responseCommandNotAvailable();
1016 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001017 in_addr gateway;
1018 std::array<uint8_t, sizeof(gateway)> bytes;
1019 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1020 {
1021 return responseReqDataLenInvalid();
1022 }
1023 copyInto(gateway, bytes);
1024 channelCall<setGatewayProperty<AF_INET>>(channel, gateway);
1025 return responseSuccess();
1026 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001027 case LanParam::Gateway1MAC:
1028 {
1029 ether_addr gatewayMAC;
1030 std::array<uint8_t, sizeof(gatewayMAC)> bytes;
1031 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1032 {
1033 return responseReqDataLenInvalid();
1034 }
1035 copyInto(gatewayMAC, bytes);
1036 channelCall<reconfigureGatewayMAC<AF_INET>>(channel, gatewayMAC);
1037 return responseSuccess();
1038 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001039 case LanParam::VLANId:
1040 {
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301041 uint12_t vlanData = 0;
1042 uint3_t reserved = 0;
1043 bool vlanEnable = 0;
1044
1045 if (req.unpack(vlanData) || req.unpack(reserved) ||
1046 req.unpack(vlanEnable) || !req.fullyUnpacked())
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001047 {
1048 return responseReqDataLenInvalid();
1049 }
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301050
1051 if (reserved)
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001052 {
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301053 return responseInvalidFieldRequest();
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001054 }
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301055
1056 uint16_t vlan = static_cast<uint16_t>(vlanData);
1057
1058 if (!vlanEnable)
1059 {
1060 lastDisabledVlan[channel] = vlan;
1061 vlan = 0;
1062 }
jayaprakash Mutyala84c49dc2020-05-18 23:12:13 +00001063 else if (vlan == 0 || vlan == VLAN_VALUE_MASK)
1064 {
1065 return responseInvalidFieldRequest();
1066 }
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301067
jayaprakash Mutyala84c49dc2020-05-18 23:12:13 +00001068 channelCall<reconfigureVLAN>(channel, vlan);
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001069 return responseSuccess();
1070 }
1071 case LanParam::CiphersuiteSupport:
1072 case LanParam::CiphersuiteEntries:
William A. Kennington III16064aa2019-04-13 17:44:53 -07001073 case LanParam::IPFamilySupport:
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001074 {
1075 req.trailingOk = true;
1076 return response(ccParamReadOnly);
Ratan Guptab8e99552017-07-27 07:07:48 +05301077 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001078 case LanParam::IPFamilyEnables:
1079 {
1080 uint8_t enables;
1081 if (req.unpack(enables) != 0 || !req.fullyUnpacked())
1082 {
1083 return responseReqDataLenInvalid();
1084 }
1085 switch (static_cast<IPFamilyEnables>(enables))
1086 {
1087 case IPFamilyEnables::DualStack:
1088 return responseSuccess();
1089 case IPFamilyEnables::IPv4Only:
1090 case IPFamilyEnables::IPv6Only:
1091 return response(ccParamNotSupported);
1092 }
1093 return response(ccParamNotSupported);
1094 }
1095 case LanParam::IPv6Status:
1096 {
1097 req.trailingOk = true;
1098 return response(ccParamReadOnly);
1099 }
1100 case LanParam::IPv6StaticAddresses:
1101 {
1102 uint8_t set;
1103 uint7_t rsvd;
1104 bool enabled;
1105 in6_addr ip;
1106 std::array<uint8_t, sizeof(ip)> ipbytes;
1107 uint8_t prefix;
1108 uint8_t status;
1109 if (req.unpack(set, rsvd, enabled, ipbytes, prefix, status) != 0 ||
1110 !req.fullyUnpacked())
1111 {
1112 return responseReqDataLenInvalid();
1113 }
Johnathan Mantey4a156852019-12-11 13:47:43 -08001114 if (rsvd)
1115 {
1116 return responseInvalidFieldRequest();
1117 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001118 copyInto(ip, ipbytes);
1119 if (enabled)
1120 {
Jiaqing Zhao6d4a44e2022-01-24 15:04:00 +08001121 if (prefix < MIN_IPV6_PREFIX_LENGTH ||
1122 prefix > MAX_IPV6_PREFIX_LENGTH)
1123 {
1124 return responseParmOutOfRange();
1125 }
Johnathan Manteya291f492021-10-15 13:45:27 -07001126 try
1127 {
1128 channelCall<reconfigureIfAddr6>(channel, set, ip, prefix);
1129 }
Patrick Williams5d82f472022-07-22 19:26:53 -05001130 catch (const sdbusplus::exception_t& e)
Johnathan Manteya291f492021-10-15 13:45:27 -07001131 {
1132 if (std::string_view err{
1133 "xyz.openbmc_project.Common.Error.InvalidArgument"};
1134 err == e.name())
1135 {
1136 return responseInvalidFieldRequest();
1137 }
1138 else
1139 {
1140 throw;
1141 }
1142 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001143 }
1144 else
1145 {
1146 channelCall<deconfigureIfAddr6>(channel, set);
1147 }
1148 return responseSuccess();
1149 }
1150 case LanParam::IPv6DynamicAddresses:
1151 {
1152 req.trailingOk = true;
1153 return response(ccParamReadOnly);
1154 }
1155 case LanParam::IPv6RouterControl:
1156 {
1157 std::bitset<8> control;
Johnathan Mantey3b7a4072021-01-26 14:24:53 -08001158 constexpr uint8_t reservedRACCBits = 0xfc;
William A. Kennington III16064aa2019-04-13 17:44:53 -07001159 if (req.unpack(control) != 0 || !req.fullyUnpacked())
1160 {
1161 return responseReqDataLenInvalid();
1162 }
Johnathan Mantey3b7a4072021-01-26 14:24:53 -08001163 if (std::bitset<8> expected(control &
1164 std::bitset<8>(reservedRACCBits));
1165 expected.any())
William A. Kennington III16064aa2019-04-13 17:44:53 -07001166 {
Johnathan Mantey3b7a4072021-01-26 14:24:53 -08001167 return response(ccParamNotSupported);
William A. Kennington III16064aa2019-04-13 17:44:53 -07001168 }
Johnathan Mantey3b7a4072021-01-26 14:24:53 -08001169
1170 bool enableRA = control[IPv6RouterControlFlag::Dynamic];
1171 channelCall<setIPv6AcceptRA>(channel, enableRA);
William A. Kennington III16064aa2019-04-13 17:44:53 -07001172 return responseSuccess();
1173 }
1174 case LanParam::IPv6StaticRouter1IP:
1175 {
1176 in6_addr gateway;
1177 std::array<uint8_t, sizeof(gateway)> bytes;
1178 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1179 {
1180 return responseReqDataLenInvalid();
1181 }
1182 copyInto(gateway, bytes);
1183 channelCall<setGatewayProperty<AF_INET6>>(channel, gateway);
1184 return responseSuccess();
1185 }
1186 case LanParam::IPv6StaticRouter1MAC:
1187 {
1188 ether_addr mac;
1189 std::array<uint8_t, sizeof(mac)> bytes;
1190 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1191 {
1192 return responseReqDataLenInvalid();
1193 }
1194 copyInto(mac, bytes);
1195 channelCall<reconfigureGatewayMAC<AF_INET6>>(channel, mac);
1196 return responseSuccess();
1197 }
1198 case LanParam::IPv6StaticRouter1PrefixLength:
1199 {
1200 uint8_t prefix;
1201 if (req.unpack(prefix) != 0 || !req.fullyUnpacked())
1202 {
1203 return responseReqDataLenInvalid();
1204 }
1205 if (prefix != 0)
1206 {
1207 return responseInvalidFieldRequest();
1208 }
1209 return responseSuccess();
1210 }
1211 case LanParam::IPv6StaticRouter1PrefixValue:
1212 {
1213 std::array<uint8_t, sizeof(in6_addr)> bytes;
1214 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1215 {
1216 return responseReqDataLenInvalid();
1217 }
1218 // Accept any prefix value since our prefix length has to be 0
1219 return responseSuccess();
1220 }
jayaprakash Mutyalab741b992019-12-02 17:29:09 +00001221 case LanParam::cipherSuitePrivilegeLevels:
1222 {
1223 uint8_t reserved;
1224 std::array<uint4_t, ipmi::maxCSRecords> cipherSuitePrivs;
1225
1226 if (req.unpack(reserved, cipherSuitePrivs) || !req.fullyUnpacked())
1227 {
1228 return responseReqDataLenInvalid();
1229 }
1230
1231 if (reserved)
1232 {
1233 return responseInvalidFieldRequest();
1234 }
1235
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -05001236 uint8_t resp = getCipherConfigObject(csPrivFileName,
1237 csPrivDefaultFileName)
1238 .setCSPrivilegeLevels(channel, cipherSuitePrivs);
jayaprakash Mutyalab741b992019-12-02 17:29:09 +00001239 if (!resp)
1240 {
1241 return responseSuccess();
1242 }
1243 else
1244 {
1245 req.trailingOk = true;
1246 return response(resp);
1247 }
1248 }
Ratan Guptab8e99552017-07-27 07:07:48 +05301249 }
vishwa1eaea4f2016-02-26 11:57:40 -06001250
Johnathan Manteyb87034e2019-09-16 10:50:50 -07001251 if ((parameter >= oemCmdStart) && (parameter <= oemCmdEnd))
1252 {
1253 return setLanOem(channel, parameter, req);
1254 }
1255
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001256 req.trailingOk = true;
1257 return response(ccParamNotSupported);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001258}
1259
vijayabharathix shettycc769252020-02-27 17:52:20 +00001260RspType<message::Payload> getLan(Context::ptr ctx, uint4_t channelBits,
1261 uint3_t reserved, bool revOnly,
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001262 uint8_t parameter, uint8_t set, uint8_t block)
Ratan Guptab8e99552017-07-27 07:07:48 +05301263{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001264 message::Payload ret;
1265 constexpr uint8_t current_revision = 0x11;
1266 ret.pack(current_revision);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001267
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001268 if (revOnly)
Suryakanth Sekare4054402019-08-08 15:16:52 +05301269 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001270 return responseSuccess(std::move(ret));
Suryakanth Sekare4054402019-08-08 15:16:52 +05301271 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001272
vijayabharathix shettycc769252020-02-27 17:52:20 +00001273 const uint8_t channel = convertCurrentChannelNum(
1274 static_cast<uint8_t>(channelBits), ctx->channel);
1275 if (reserved || !isValidChannel(channel))
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001276 {
vijayabharathix shettycc769252020-02-27 17:52:20 +00001277 log<level::ERR>("Get Lan - Invalid field in request");
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001278 return responseInvalidFieldRequest();
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001279 }
1280
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001281 static std::vector<uint8_t> cipherList;
1282 static bool listInit = false;
1283 if (!listInit)
1284 {
1285 try
1286 {
1287 cipherList = cipher::getCipherList();
1288 listInit = true;
1289 }
1290 catch (const std::exception& e)
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -05001291 {}
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001292 }
1293
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001294 switch (static_cast<LanParam>(parameter))
Tom Josepha30c8d32018-03-22 02:15:03 +05301295 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001296 case LanParam::SetStatus:
Tom Josepha30c8d32018-03-22 02:15:03 +05301297 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001298 SetStatus status;
1299 try
1300 {
1301 status = setStatus.at(channel);
1302 }
1303 catch (const std::out_of_range&)
1304 {
1305 status = SetStatus::Complete;
1306 }
William A. Kennington III7a0e5df2021-05-19 13:31:29 -07001307 ret.pack(types::enum_cast<uint2_t>(status), uint6_t{});
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001308 return responseSuccess(std::move(ret));
Tom Josepha30c8d32018-03-22 02:15:03 +05301309 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001310 case LanParam::AuthSupport:
Tom Josepha30c8d32018-03-22 02:15:03 +05301311 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001312 std::bitset<6> support;
1313 ret.pack(support, uint2_t{});
1314 return responseSuccess(std::move(ret));
Tom Josepha30c8d32018-03-22 02:15:03 +05301315 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001316 case LanParam::AuthEnables:
vishwa1eaea4f2016-02-26 11:57:40 -06001317 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001318 std::bitset<6> enables;
1319 ret.pack(enables, uint2_t{}); // Callback
1320 ret.pack(enables, uint2_t{}); // User
1321 ret.pack(enables, uint2_t{}); // Operator
1322 ret.pack(enables, uint2_t{}); // Admin
1323 ret.pack(enables, uint2_t{}); // OEM
1324 return responseSuccess(std::move(ret));
William A. Kennington III39f94ef2018-11-19 22:36:16 -08001325 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001326 case LanParam::IP:
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001327 {
1328 auto ifaddr = channelCall<getIfAddr4>(channel);
1329 in_addr addr{};
1330 if (ifaddr)
1331 {
1332 addr = ifaddr->address;
1333 }
1334 ret.pack(dataRef(addr));
1335 return responseSuccess(std::move(ret));
1336 }
1337 case LanParam::IPSrc:
1338 {
1339 auto src = IPSrc::Static;
Johnathan Mantey65265362019-11-14 11:24:19 -08001340 EthernetInterface::DHCPConf dhcp =
1341 channelCall<getDHCPProperty>(channel);
1342 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
1343 (dhcp == EthernetInterface::DHCPConf::both))
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001344 {
1345 src = IPSrc::DHCP;
1346 }
William A. Kennington III7a0e5df2021-05-19 13:31:29 -07001347 ret.pack(types::enum_cast<uint4_t>(src), uint4_t{});
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001348 return responseSuccess(std::move(ret));
1349 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001350 case LanParam::MAC:
William A. Kennington III39f94ef2018-11-19 22:36:16 -08001351 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001352 ether_addr mac = channelCall<getMACProperty>(channel);
1353 ret.pack(dataRef(mac));
1354 return responseSuccess(std::move(ret));
1355 }
1356 case LanParam::SubnetMask:
1357 {
1358 auto ifaddr = channelCall<getIfAddr4>(channel);
1359 uint8_t prefix = AddrFamily<AF_INET>::defaultPrefix;
1360 if (ifaddr)
Ratan Guptab8e99552017-07-27 07:07:48 +05301361 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001362 prefix = ifaddr->prefix;
1363 }
1364 in_addr netmask = prefixToNetmask(prefix);
1365 ret.pack(dataRef(netmask));
1366 return responseSuccess(std::move(ret));
1367 }
1368 case LanParam::Gateway1:
1369 {
1370 auto gateway =
1371 channelCall<getGatewayProperty<AF_INET>>(channel).value_or(
1372 in_addr{});
1373 ret.pack(dataRef(gateway));
1374 return responseSuccess(std::move(ret));
1375 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001376 case LanParam::Gateway1MAC:
1377 {
1378 ether_addr mac{};
1379 auto neighbor = channelCall<getGatewayNeighbor<AF_INET>>(channel);
1380 if (neighbor)
1381 {
1382 mac = neighbor->mac;
1383 }
1384 ret.pack(dataRef(mac));
1385 return responseSuccess(std::move(ret));
1386 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001387 case LanParam::VLANId:
1388 {
1389 uint16_t vlan = channelCall<getVLANProperty>(channel);
1390 if (vlan != 0)
1391 {
1392 vlan |= VLAN_ENABLE_FLAG;
Ratan Guptab8e99552017-07-27 07:07:48 +05301393 }
1394 else
1395 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001396 vlan = lastDisabledVlan[channel];
Ratan Guptab8e99552017-07-27 07:07:48 +05301397 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001398 ret.pack(vlan);
1399 return responseSuccess(std::move(ret));
Adriana Kobylak342df102016-02-10 13:48:16 -06001400 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001401 case LanParam::CiphersuiteSupport:
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001402 {
srikanta mondal1d8579c2020-04-15 17:13:25 +00001403 if (getChannelSessionSupport(channel) ==
1404 EChannelSessSupported::none)
1405 {
1406 return responseInvalidFieldRequest();
1407 }
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001408 if (!listInit)
1409 {
1410 return responseUnspecifiedError();
1411 }
1412 ret.pack(static_cast<uint8_t>(cipherList.size() - 1));
1413 return responseSuccess(std::move(ret));
1414 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001415 case LanParam::CiphersuiteEntries:
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001416 {
srikanta mondal1d8579c2020-04-15 17:13:25 +00001417 if (getChannelSessionSupport(channel) ==
1418 EChannelSessSupported::none)
1419 {
1420 return responseInvalidFieldRequest();
1421 }
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001422 if (!listInit)
1423 {
1424 return responseUnspecifiedError();
1425 }
1426 ret.pack(cipherList);
1427 return responseSuccess(std::move(ret));
1428 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001429 case LanParam::IPFamilySupport:
1430 {
1431 std::bitset<8> support;
1432 support[IPFamilySupportFlag::IPv6Only] = 0;
1433 support[IPFamilySupportFlag::DualStack] = 1;
1434 support[IPFamilySupportFlag::IPv6Alerts] = 1;
1435 ret.pack(support);
1436 return responseSuccess(std::move(ret));
1437 }
1438 case LanParam::IPFamilyEnables:
1439 {
1440 ret.pack(static_cast<uint8_t>(IPFamilyEnables::DualStack));
1441 return responseSuccess(std::move(ret));
1442 }
1443 case LanParam::IPv6Status:
1444 {
1445 ret.pack(MAX_IPV6_STATIC_ADDRESSES);
1446 ret.pack(MAX_IPV6_DYNAMIC_ADDRESSES);
1447 std::bitset<8> support;
1448 support[IPv6StatusFlag::DHCP] = 1;
1449 support[IPv6StatusFlag::SLAAC] = 1;
1450 ret.pack(support);
1451 return responseSuccess(std::move(ret));
1452 }
1453 case LanParam::IPv6StaticAddresses:
1454 {
1455 if (set >= MAX_IPV6_STATIC_ADDRESSES)
1456 {
1457 return responseParmOutOfRange();
1458 }
1459 getLanIPv6Address(ret, channel, set, originsV6Static);
1460 return responseSuccess(std::move(ret));
1461 }
1462 case LanParam::IPv6DynamicAddresses:
1463 {
1464 if (set >= MAX_IPV6_DYNAMIC_ADDRESSES)
1465 {
1466 return responseParmOutOfRange();
1467 }
1468 getLanIPv6Address(ret, channel, set, originsV6Dynamic);
1469 return responseSuccess(std::move(ret));
1470 }
1471 case LanParam::IPv6RouterControl:
1472 {
1473 std::bitset<8> control;
Johnathan Mantey3b7a4072021-01-26 14:24:53 -08001474 control[IPv6RouterControlFlag::Dynamic] =
1475 channelCall<getIPv6AcceptRA>(channel);
1476 control[IPv6RouterControlFlag::Static] = 1;
William A. Kennington III16064aa2019-04-13 17:44:53 -07001477 ret.pack(control);
1478 return responseSuccess(std::move(ret));
1479 }
1480 case LanParam::IPv6StaticRouter1IP:
1481 {
1482 in6_addr gateway{};
Johnathan Mantey65265362019-11-14 11:24:19 -08001483 EthernetInterface::DHCPConf dhcp =
1484 channelCall<getDHCPProperty>(channel);
1485 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
1486 (dhcp == EthernetInterface::DHCPConf::none))
William A. Kennington III16064aa2019-04-13 17:44:53 -07001487 {
1488 gateway =
1489 channelCall<getGatewayProperty<AF_INET6>>(channel).value_or(
1490 in6_addr{});
1491 }
1492 ret.pack(dataRef(gateway));
1493 return responseSuccess(std::move(ret));
1494 }
1495 case LanParam::IPv6StaticRouter1MAC:
1496 {
1497 ether_addr mac{};
1498 auto neighbor = channelCall<getGatewayNeighbor<AF_INET6>>(channel);
1499 if (neighbor)
1500 {
1501 mac = neighbor->mac;
1502 }
1503 ret.pack(dataRef(mac));
1504 return responseSuccess(std::move(ret));
1505 }
1506 case LanParam::IPv6StaticRouter1PrefixLength:
1507 {
1508 ret.pack(UINT8_C(0));
1509 return responseSuccess(std::move(ret));
1510 }
1511 case LanParam::IPv6StaticRouter1PrefixValue:
1512 {
1513 in6_addr prefix{};
1514 ret.pack(dataRef(prefix));
1515 return responseSuccess(std::move(ret));
1516 }
jayaprakash Mutyalab741b992019-12-02 17:29:09 +00001517 case LanParam::cipherSuitePrivilegeLevels:
1518 {
1519 std::array<uint4_t, ipmi::maxCSRecords> csPrivilegeLevels;
1520
1521 uint8_t resp =
1522 getCipherConfigObject(csPrivFileName, csPrivDefaultFileName)
1523 .getCSPrivilegeLevels(channel, csPrivilegeLevels);
1524 if (!resp)
1525 {
1526 constexpr uint8_t reserved1 = 0x00;
1527 ret.pack(reserved1, csPrivilegeLevels);
1528 return responseSuccess(std::move(ret));
1529 }
1530 else
1531 {
1532 return response(resp);
1533 }
1534 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001535 }
1536
Johnathan Manteyb87034e2019-09-16 10:50:50 -07001537 if ((parameter >= oemCmdStart) && (parameter <= oemCmdEnd))
1538 {
1539 return getLanOem(channel, parameter, set, block);
1540 }
1541
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001542 return response(ccParamNotSupported);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001543}
1544
Jian Zhang23f44652022-03-17 17:13:10 +08001545constexpr const char* solInterface = "xyz.openbmc_project.Ipmi.SOL";
1546constexpr const char* solPath = "/xyz/openbmc_project/ipmi/sol/";
1547constexpr const uint16_t solDefaultPort = 623;
1548
1549RspType<> setSolConfParams(Context::ptr ctx, uint4_t channelBits,
Willy Tu11d68892022-01-20 10:37:34 -08001550 uint4_t /*reserved*/, uint8_t parameter,
Jian Zhang23f44652022-03-17 17:13:10 +08001551 message::Payload& req)
1552{
1553 const uint8_t channel = convertCurrentChannelNum(
1554 static_cast<uint8_t>(channelBits), ctx->channel);
1555
1556 if (!isValidChannel(channel))
1557 {
1558 log<level::ERR>("Set Sol Config - Invalid channel in request");
1559 return responseInvalidFieldRequest();
1560 }
1561
1562 std::string solService{};
1563 std::string solPathWitheEthName = solPath + ipmi::getChannelName(channel);
1564
1565 if (ipmi::getService(ctx, solInterface, solPathWitheEthName, solService))
1566 {
1567 log<level::ERR>("Set Sol Config - Invalid solInterface",
1568 entry("SERVICE=%s", solService.c_str()),
1569 entry("OBJPATH=%s", solPathWitheEthName.c_str()),
1570 entry("INTERFACE=%s", solInterface));
1571 return responseInvalidFieldRequest();
1572 }
1573
1574 switch (static_cast<SolConfParam>(parameter))
1575 {
1576 case SolConfParam::Progress:
1577 {
1578 uint8_t progress;
1579 if (req.unpack(progress) != 0 || !req.fullyUnpacked())
1580 {
1581 return responseReqDataLenInvalid();
1582 }
1583
1584 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1585 solInterface, "Progress", progress))
1586 {
1587 return responseUnspecifiedError();
1588 }
1589 break;
1590 }
1591 case SolConfParam::Enable:
1592 {
1593 bool enable;
1594 uint7_t reserved2;
1595
1596 if (req.unpack(enable, reserved2) != 0 || !req.fullyUnpacked())
1597 {
1598 return responseReqDataLenInvalid();
1599 }
1600
1601 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1602 solInterface, "Enable", enable))
1603 {
1604 return responseUnspecifiedError();
1605 }
1606 break;
1607 }
1608 case SolConfParam::Authentication:
1609 {
1610 uint4_t privilegeBits{};
1611 uint2_t reserved2{};
1612 bool forceAuth = false;
1613 bool forceEncrypt = false;
1614
1615 if (req.unpack(privilegeBits, reserved2, forceAuth, forceEncrypt) !=
1616 0 ||
1617 !req.fullyUnpacked())
1618 {
1619 return responseReqDataLenInvalid();
1620 }
1621
1622 uint8_t privilege = static_cast<uint8_t>(privilegeBits);
Jonathan Domana48bf772023-05-26 17:54:57 -07001623 if (privilege < static_cast<uint8_t>(Privilege::User) ||
Jian Zhang23f44652022-03-17 17:13:10 +08001624 privilege > static_cast<uint8_t>(Privilege::Oem))
1625 {
1626 return ipmi::responseInvalidFieldRequest();
1627 }
1628
1629 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1630 solInterface, "Privilege", privilege))
1631 {
1632 return responseUnspecifiedError();
1633 }
1634
1635 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1636 solInterface, "ForceEncryption",
1637 forceEncrypt))
1638 {
1639 return responseUnspecifiedError();
1640 }
1641
1642 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1643 solInterface, "ForceAuthentication",
1644 forceAuth))
1645 {
1646 return responseUnspecifiedError();
1647 }
1648 break;
1649 }
1650 case SolConfParam::Accumulate:
1651 {
1652 uint8_t interval;
1653 uint8_t threshold;
1654 if (req.unpack(interval, threshold) != 0 || !req.fullyUnpacked())
1655 {
1656 return responseReqDataLenInvalid();
1657 }
1658
1659 if (threshold == 0)
1660 {
1661 return responseInvalidFieldRequest();
1662 }
1663
1664 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1665 solInterface, "AccumulateIntervalMS",
1666 interval))
1667 {
1668 return responseUnspecifiedError();
1669 }
1670
1671 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1672 solInterface, "Threshold", threshold))
1673 {
1674 return responseUnspecifiedError();
1675 }
1676 break;
1677 }
1678 case SolConfParam::Retry:
1679 {
1680 uint3_t countBits;
1681 uint5_t reserved2;
1682 uint8_t interval;
1683
1684 if (req.unpack(countBits, reserved2, interval) != 0 ||
1685 !req.fullyUnpacked())
1686 {
1687 return responseReqDataLenInvalid();
1688 }
1689
1690 uint8_t count = static_cast<uint8_t>(countBits);
1691 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1692 solInterface, "RetryCount", count))
1693 {
1694 return responseUnspecifiedError();
1695 }
1696
1697 if (ipmi::setDbusProperty(ctx, solService, solPathWitheEthName,
1698 solInterface, "RetryIntervalMS",
1699 interval))
1700 {
1701 return responseUnspecifiedError();
1702 }
1703 break;
1704 }
1705 case SolConfParam::Port:
1706 {
1707 return response(ipmiCCWriteReadParameter);
1708 }
1709 case SolConfParam::NonVbitrate:
1710 case SolConfParam::Vbitrate:
1711 case SolConfParam::Channel:
1712 default:
1713 return response(ipmiCCParamNotSupported);
1714 }
1715 return responseSuccess();
1716}
1717
1718RspType<message::Payload> getSolConfParams(Context::ptr ctx,
1719 uint4_t channelBits,
Willy Tu11d68892022-01-20 10:37:34 -08001720 uint3_t /*reserved*/, bool revOnly,
1721 uint8_t parameter, uint8_t /*set*/,
1722 uint8_t /*block*/)
Jian Zhang23f44652022-03-17 17:13:10 +08001723{
1724 message::Payload ret;
1725 constexpr uint8_t current_revision = 0x11;
1726 ret.pack(current_revision);
1727 if (revOnly)
1728 {
1729 return responseSuccess(std::move(ret));
1730 }
1731
1732 const uint8_t channel = convertCurrentChannelNum(
1733 static_cast<uint8_t>(channelBits), ctx->channel);
1734
1735 if (!isValidChannel(channel))
1736 {
1737 log<level::ERR>("Get Sol Config - Invalid channel in request");
1738 return responseInvalidFieldRequest();
1739 }
1740
1741 std::string solService{};
1742 std::string solPathWitheEthName = solPath + ipmi::getChannelName(channel);
1743
1744 if (ipmi::getService(ctx, solInterface, solPathWitheEthName, solService))
1745 {
1746 log<level::ERR>("Set Sol Config - Invalid solInterface",
1747 entry("SERVICE=%s", solService.c_str()),
1748 entry("OBJPATH=%s", solPathWitheEthName.c_str()),
1749 entry("INTERFACE=%s", solInterface));
1750 return responseInvalidFieldRequest();
1751 }
1752
1753 switch (static_cast<SolConfParam>(parameter))
1754 {
1755 case SolConfParam::Progress:
1756 {
1757 uint8_t progress;
1758 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1759 solInterface, "Progress", progress))
1760 {
1761 return responseUnspecifiedError();
1762 }
1763 ret.pack(progress);
1764 return responseSuccess(std::move(ret));
1765 }
1766 case SolConfParam::Enable:
1767 {
1768 bool enable{};
1769 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1770 solInterface, "Enable", enable))
1771 {
1772 return responseUnspecifiedError();
1773 }
1774 ret.pack(enable, uint7_t{});
1775 return responseSuccess(std::move(ret));
1776 }
1777 case SolConfParam::Authentication:
1778 {
1779 // 4bits, cast when pack
1780 uint8_t privilege;
1781 bool forceAuth = false;
1782 bool forceEncrypt = false;
1783
1784 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1785 solInterface, "Privilege", privilege))
1786 {
1787 return responseUnspecifiedError();
1788 }
1789
1790 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1791 solInterface, "ForceAuthentication",
1792 forceAuth))
1793 {
1794 return responseUnspecifiedError();
1795 }
1796
1797 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1798 solInterface, "ForceEncryption",
1799 forceEncrypt))
1800 {
1801 return responseUnspecifiedError();
1802 }
1803 ret.pack(uint4_t{privilege}, uint2_t{}, forceAuth, forceEncrypt);
1804 return responseSuccess(std::move(ret));
1805 }
1806 case SolConfParam::Accumulate:
1807 {
1808 uint8_t interval{}, threshold{};
1809
1810 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1811 solInterface, "AccumulateIntervalMS",
1812 interval))
1813 {
1814 return responseUnspecifiedError();
1815 }
1816
1817 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1818 solInterface, "Threshold", threshold))
1819 {
1820 return responseUnspecifiedError();
1821 }
1822 ret.pack(interval, threshold);
1823 return responseSuccess(std::move(ret));
1824 }
1825 case SolConfParam::Retry:
1826 {
1827 // 3bits, cast when cast
1828 uint8_t count{};
1829 uint8_t interval{};
1830
1831 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1832 solInterface, "RetryCount", count))
1833 {
1834 return responseUnspecifiedError();
1835 }
1836
1837 if (ipmi::getDbusProperty(ctx, solService, solPathWitheEthName,
1838 solInterface, "RetryIntervalMS",
1839 interval))
1840 {
1841 return responseUnspecifiedError();
1842 }
1843 ret.pack(uint3_t{count}, uint5_t{}, interval);
1844 return responseSuccess(std::move(ret));
1845 }
1846 case SolConfParam::Port:
1847 {
1848 auto port = solDefaultPort;
1849 ret.pack(static_cast<uint16_t>(port));
1850 return responseSuccess(std::move(ret));
1851 }
1852 case SolConfParam::Channel:
1853 {
1854 ret.pack(channel);
1855 return responseSuccess(std::move(ret));
1856 }
1857 case SolConfParam::NonVbitrate:
Jonathan Domana48bf772023-05-26 17:54:57 -07001858 {
1859 uint64_t baudRate;
1860 uint8_t encodedBitRate = 0;
1861 if (ipmi::getDbusProperty(
1862 ctx, "xyz.openbmc_project.Console.default",
1863 "/xyz/openbmc_project/console/default",
1864 "xyz.openbmc_project.Console.UART", "Baud", baudRate))
1865 {
1866 return ipmi::responseUnspecifiedError();
1867 }
1868 switch (baudRate)
1869 {
1870 case 9600:
1871 encodedBitRate = 0x06;
1872 break;
1873 case 19200:
1874 encodedBitRate = 0x07;
1875 break;
1876 case 38400:
1877 encodedBitRate = 0x08;
1878 break;
1879 case 57600:
1880 encodedBitRate = 0x09;
1881 break;
1882 case 115200:
1883 encodedBitRate = 0x0a;
1884 break;
1885 default:
1886 break;
1887 }
1888 ret.pack(encodedBitRate);
1889 return responseSuccess(std::move(ret));
1890 }
Jian Zhang23f44652022-03-17 17:13:10 +08001891 case SolConfParam::Vbitrate:
1892 default:
1893 return response(ipmiCCParamNotSupported);
1894 }
1895
1896 return response(ccParamNotSupported);
1897}
1898
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001899} // namespace transport
1900} // namespace ipmi
Ratan Gupta1247e0b2018-03-07 10:47:25 +05301901
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001902void register_netfn_transport_functions() __attribute__((constructor));
Ratan Gupta1247e0b2018-03-07 10:47:25 +05301903
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001904void register_netfn_transport_functions()
1905{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001906 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1907 ipmi::transport::cmdSetLanConfigParameters,
1908 ipmi::Privilege::Admin, ipmi::transport::setLan);
1909 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1910 ipmi::transport::cmdGetLanConfigParameters,
Johnathan Mantey34698d52019-11-19 14:47:30 -08001911 ipmi::Privilege::Operator, ipmi::transport::getLan);
Jian Zhang23f44652022-03-17 17:13:10 +08001912 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1913 ipmi::transport::cmdSetSolConfigParameters,
1914 ipmi::Privilege::Admin,
1915 ipmi::transport::setSolConfParams);
1916 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1917 ipmi::transport::cmdGetSolConfigParameters,
1918 ipmi::Privilege::User,
1919 ipmi::transport::getSolConfParams);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001920}