blob: 00202c553bc447972136272ebb977a0356842abe [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
William A. Kennington IIIc514d872019-04-06 18:19:38 -070060std::optional<ChannelParams> maybeGetChannelParams(sdbusplus::bus::bus& bus,
61 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);
128 return std::move(params);
129}
130
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700131ChannelParams getChannelParams(sdbusplus::bus::bus& bus, uint8_t channel)
132{
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
Johnathan Mantey65265362019-11-14 11:24:19 -0800165EthernetInterface::DHCPConf getDHCPProperty(sdbusplus::bus::bus& bus,
166 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 */
Johnathan Mantey65265362019-11-14 11:24:19 -0800183void setDHCPv4Property(sdbusplus::bus::bus& bus, const ChannelParams& params,
184 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
189 if ((currentDhcp == EthernetInterface::DHCPConf::v6) &&
190 (requestedDhcp == EthernetInterface::DHCPConf::v4))
191 {
192 nextDhcp = EthernetInterface::DHCPConf::both;
193 }
194 else if ((currentDhcp == EthernetInterface::DHCPConf::none) &&
195 (requestedDhcp == EthernetInterface::DHCPConf::v4))
196
197 {
198 nextDhcp = requestedDhcp;
199 }
200 else if (requestedDhcp == EthernetInterface::DHCPConf::none)
201 {
202 if (currentDhcp == EthernetInterface::DHCPConf::both)
203 {
204 nextDhcp = EthernetInterface::DHCPConf::v6;
205 }
206 else if (currentDhcp == EthernetInterface::DHCPConf::v4)
207 {
208 nextDhcp = EthernetInterface::DHCPConf::none;
209 }
210 }
211 else
212 {
213 nextDhcp = currentDhcp;
214 }
215 std::string newDhcp =
216 sdbusplus::xyz::openbmc_project::Network::server::convertForMessage(
217 nextDhcp);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700218 setDbusProperty(bus, params.service, params.logicalPath, INTF_ETHERNET,
Johnathan Mantey65265362019-11-14 11:24:19 -0800219 "DHCPEnabled", newDhcp);
220}
221
Johnathan Mantey65265362019-11-14 11:24:19 -0800222void setDHCPv6Property(sdbusplus::bus::bus& bus, const ChannelParams& params,
223 const EthernetInterface::DHCPConf requestedDhcp,
224 const bool defaultMode = true)
225{
226 EthernetInterface::DHCPConf currentDhcp = getDHCPProperty(bus, params);
227 EthernetInterface::DHCPConf nextDhcp = EthernetInterface::DHCPConf::none;
228
229 if (defaultMode)
230 {
231 if ((currentDhcp == EthernetInterface::DHCPConf::v4) &&
232 (requestedDhcp == EthernetInterface::DHCPConf::v6))
233 {
234 nextDhcp = EthernetInterface::DHCPConf::both;
235 }
236 else if ((currentDhcp == EthernetInterface::DHCPConf::none) &&
237 (requestedDhcp == EthernetInterface::DHCPConf::v6))
238
239 {
240 nextDhcp = requestedDhcp;
241 }
242 else if (requestedDhcp == EthernetInterface::DHCPConf::none)
243 {
244 if (currentDhcp == EthernetInterface::DHCPConf::both)
245 {
246 nextDhcp = EthernetInterface::DHCPConf::v4;
247 }
248 else if (currentDhcp == EthernetInterface::DHCPConf::v6)
249 {
250 nextDhcp = EthernetInterface::DHCPConf::none;
251 }
252 }
253 else
254 {
255 nextDhcp = currentDhcp;
256 }
257 }
258 else
259 {
260 // allow the v6 call to set any value
261 nextDhcp = requestedDhcp;
262 }
263
264 std::string newDhcp =
265 sdbusplus::xyz::openbmc_project::Network::server::convertForMessage(
266 nextDhcp);
267 setDbusProperty(bus, params.service, params.logicalPath, INTF_ETHERNET,
268 "DHCPEnabled", newDhcp);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700269}
270
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700271ether_addr stringToMAC(const char* mac)
272{
273 const ether_addr* ret = ether_aton(mac);
274 if (ret == nullptr)
275 {
276 log<level::ERR>("Invalid MAC Address", entry("MAC=%s", mac));
277 elog<InternalFailure>();
278 }
279 return *ret;
280}
281
282/** @brief Determines the MAC of the ethernet interface
283 *
284 * @param[in] bus - The bus object used for lookups
285 * @param[in] params - The parameters for the channel
286 * @return The configured mac address
287 */
288ether_addr getMACProperty(sdbusplus::bus::bus& bus, const ChannelParams& params)
289{
290 auto macStr = std::get<std::string>(getDbusProperty(
291 bus, params.service, params.ifPath, INTF_MAC, "MACAddress"));
292 return stringToMAC(macStr.c_str());
293}
294
295/** @brief Sets the system value for MAC address on the given interface
296 *
297 * @param[in] bus - The bus object used for lookups
298 * @param[in] params - The parameters for the channel
299 * @param[in] mac - MAC address to apply
300 */
301void setMACProperty(sdbusplus::bus::bus& bus, const ChannelParams& params,
302 const ether_addr& mac)
303{
304 std::string macStr = ether_ntoa(&mac);
305 setDbusProperty(bus, params.service, params.ifPath, INTF_MAC, "MACAddress",
306 macStr);
307}
308
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700309void deleteObjectIfExists(sdbusplus::bus::bus& bus, const std::string& service,
310 const std::string& path)
311{
312 if (path.empty())
313 {
314 return;
315 }
Ratan Guptab8e99552017-07-27 07:07:48 +0530316 try
tomjose26e17732016-03-03 08:52:51 -0600317 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700318 auto req = bus.new_method_call(service.c_str(), path.c_str(),
319 ipmi::DELETE_INTERFACE, "Delete");
320 bus.call_noreply(req);
321 }
322 catch (const sdbusplus::exception::SdBusError& e)
323 {
jayaprakash Mutyala84c49dc2020-05-18 23:12:13 +0000324 if (strcmp(e.name(),
325 "xyz.openbmc_project.Common.Error.InternalFailure") != 0 &&
326 strcmp(e.name(), "org.freedesktop.DBus.Error.UnknownObject") != 0)
tomjose26e17732016-03-03 08:52:51 -0600327 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700328 // We want to rethrow real errors
329 throw;
tomjose26e17732016-03-03 08:52:51 -0600330 }
331 }
tomjose26e17732016-03-03 08:52:51 -0600332}
333
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700334/** @brief Sets the address info configured for the interface
335 * If a previous address path exists then it will be removed
336 * before the new address is added.
337 *
338 * @param[in] bus - The bus object used for lookups
339 * @param[in] params - The parameters for the channel
340 * @param[in] address - The address of the new IP
341 * @param[in] prefix - The prefix of the new IP
342 */
343template <int family>
344void createIfAddr(sdbusplus::bus::bus& bus, const ChannelParams& params,
345 const typename AddrFamily<family>::addr& address,
346 uint8_t prefix)
Tom Josepha30c8d32018-03-22 02:15:03 +0530347{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700348 auto newreq =
349 bus.new_method_call(params.service.c_str(), params.logicalPath.c_str(),
350 INTF_IP_CREATE, "IP");
351 std::string protocol =
352 sdbusplus::xyz::openbmc_project::Network::server::convertForMessage(
353 AddrFamily<family>::protocol);
354 newreq.append(protocol, addrToString<family>(address), prefix, "");
355 bus.call_noreply(newreq);
356}
Tom Josepha30c8d32018-03-22 02:15:03 +0530357
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700358/** @brief Trivial helper for getting the IPv4 address from getIfAddrs()
359 *
360 * @param[in] bus - The bus object used for lookups
361 * @param[in] params - The parameters for the channel
362 * @return The address and prefix if found
363 */
364auto getIfAddr4(sdbusplus::bus::bus& bus, const ChannelParams& params)
Tom Josepha30c8d32018-03-22 02:15:03 +0530365{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700366 return getIfAddr<AF_INET>(bus, params, 0, originsV4);
367}
Tom Josepha30c8d32018-03-22 02:15:03 +0530368
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700369/** @brief Reconfigures the IPv4 address info configured for the interface
370 *
371 * @param[in] bus - The bus object used for lookups
372 * @param[in] params - The parameters for the channel
373 * @param[in] address - The new address if specified
374 * @param[in] prefix - The new address prefix if specified
375 */
376void reconfigureIfAddr4(sdbusplus::bus::bus& bus, const ChannelParams& params,
377 const std::optional<in_addr>& address,
378 std::optional<uint8_t> prefix)
379{
380 auto ifaddr = getIfAddr4(bus, params);
381 if (!ifaddr && !address)
Tom Josepha30c8d32018-03-22 02:15:03 +0530382 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700383 log<level::ERR>("Missing address for IPv4 assignment");
Tom Josepha30c8d32018-03-22 02:15:03 +0530384 elog<InternalFailure>();
385 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700386 uint8_t fallbackPrefix = AddrFamily<AF_INET>::defaultPrefix;
387 if (ifaddr)
Tom Josepha30c8d32018-03-22 02:15:03 +0530388 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700389 fallbackPrefix = ifaddr->prefix;
390 deleteObjectIfExists(bus, params.service, ifaddr->path);
391 }
392 createIfAddr<AF_INET>(bus, params, address.value_or(ifaddr->address),
393 prefix.value_or(fallbackPrefix));
394}
395
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700396template <int family>
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700397std::optional<IfNeigh<family>> findGatewayNeighbor(sdbusplus::bus::bus& bus,
398 const ChannelParams& params,
399 ObjectLookupCache& neighbors)
400{
401 auto gateway = getGatewayProperty<family>(bus, params);
402 if (!gateway)
403 {
404 return std::nullopt;
405 }
406
407 return findStaticNeighbor<family>(bus, params, *gateway, neighbors);
408}
409
410template <int family>
411std::optional<IfNeigh<family>> getGatewayNeighbor(sdbusplus::bus::bus& bus,
412 const ChannelParams& params)
413{
414 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
415 return findGatewayNeighbor<family>(bus, params, neighbors);
416}
417
418template <int family>
419void reconfigureGatewayMAC(sdbusplus::bus::bus& bus,
420 const ChannelParams& params, const ether_addr& mac)
421{
422 auto gateway = getGatewayProperty<family>(bus, params);
423 if (!gateway)
424 {
425 log<level::ERR>("Tried to set Gateway MAC without Gateway");
426 elog<InternalFailure>();
427 }
428
429 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
430 auto neighbor =
431 findStaticNeighbor<family>(bus, params, *gateway, neighbors);
432 if (neighbor)
433 {
434 deleteObjectIfExists(bus, params.service, neighbor->path);
435 }
436
437 createNeighbor<family>(bus, params, *gateway, mac);
438}
439
William A. Kennington III16064aa2019-04-13 17:44:53 -0700440/** @brief Deconfigures the IPv6 address info configured for the interface
441 *
442 * @param[in] bus - The bus object used for lookups
443 * @param[in] params - The parameters for the channel
444 * @param[in] idx - The address index to operate on
445 */
446void deconfigureIfAddr6(sdbusplus::bus::bus& bus, const ChannelParams& params,
447 uint8_t idx)
448{
449 auto ifaddr = getIfAddr<AF_INET6>(bus, params, idx, originsV6Static);
450 if (ifaddr)
451 {
452 deleteObjectIfExists(bus, params.service, ifaddr->path);
453 }
454}
455
456/** @brief Reconfigures the IPv6 address info configured for the interface
457 *
458 * @param[in] bus - The bus object used for lookups
459 * @param[in] params - The parameters for the channel
460 * @param[in] idx - The address index to operate on
461 * @param[in] address - The new address
462 * @param[in] prefix - The new address prefix
463 */
464void reconfigureIfAddr6(sdbusplus::bus::bus& bus, const ChannelParams& params,
465 uint8_t idx, const in6_addr& address, uint8_t prefix)
466{
467 deconfigureIfAddr6(bus, params, idx);
468 createIfAddr<AF_INET6>(bus, params, address, prefix);
469}
470
471/** @brief Converts the AddressOrigin into an IPv6Source
472 *
473 * @param[in] origin - The DBus Address Origin to convert
474 * @return The IPv6Source version of the origin
475 */
476IPv6Source originToSourceType(IP::AddressOrigin origin)
477{
478 switch (origin)
479 {
480 case IP::AddressOrigin::Static:
481 return IPv6Source::Static;
482 case IP::AddressOrigin::DHCP:
483 return IPv6Source::DHCP;
484 case IP::AddressOrigin::SLAAC:
485 return IPv6Source::SLAAC;
486 default:
487 {
488 auto originStr = sdbusplus::xyz::openbmc_project::Network::server::
489 convertForMessage(origin);
490 log<level::ERR>(
491 "Invalid IP::AddressOrigin conversion to IPv6Source",
492 entry("ORIGIN=%s", originStr.c_str()));
493 elog<InternalFailure>();
494 }
495 }
496}
497
498/** @brief Packs the IPMI message response with IPv6 address data
499 *
500 * @param[out] ret - The IPMI response payload to be packed
501 * @param[in] channel - The channel id corresponding to an ethernet interface
502 * @param[in] set - The set selector for determining address index
503 * @param[in] origins - Set of valid origins for address filtering
504 */
505void getLanIPv6Address(message::Payload& ret, uint8_t channel, uint8_t set,
506 const std::unordered_set<IP::AddressOrigin>& origins)
507{
508 auto source = IPv6Source::Static;
509 bool enabled = false;
510 in6_addr addr{};
511 uint8_t prefix = AddrFamily<AF_INET6>::defaultPrefix;
512 auto status = IPv6AddressStatus::Disabled;
513
514 auto ifaddr = channelCall<getIfAddr<AF_INET6>>(channel, set, origins);
515 if (ifaddr)
516 {
517 source = originToSourceType(ifaddr->origin);
518 enabled = true;
519 addr = ifaddr->address;
520 prefix = ifaddr->prefix;
521 status = IPv6AddressStatus::Active;
522 }
523
524 ret.pack(set);
525 ret.pack(static_cast<uint4_t>(source), uint3_t{}, enabled);
526 ret.pack(std::string_view(reinterpret_cast<char*>(&addr), sizeof(addr)));
527 ret.pack(prefix);
528 ret.pack(static_cast<uint8_t>(status));
529}
530
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700531/** @brief Gets the vlan ID configured on the interface
532 *
533 * @param[in] bus - The bus object used for lookups
534 * @param[in] params - The parameters for the channel
535 * @return VLAN id or the standard 0 for no VLAN
536 */
537uint16_t getVLANProperty(sdbusplus::bus::bus& bus, const ChannelParams& params)
538{
539 // VLAN devices will always have a separate logical object
540 if (params.ifPath == params.logicalPath)
541 {
542 return 0;
543 }
544
545 auto vlan = std::get<uint32_t>(getDbusProperty(
546 bus, params.service, params.logicalPath, INTF_VLAN, "Id"));
547 if ((vlan & VLAN_VALUE_MASK) != vlan)
548 {
549 logWithChannel<level::ERR>(params, "networkd returned an invalid vlan",
550 entry("VLAN=%" PRIu32, vlan));
Tom Josepha30c8d32018-03-22 02:15:03 +0530551 elog<InternalFailure>();
552 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700553 return vlan;
Tom Josepha30c8d32018-03-22 02:15:03 +0530554}
555
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700556/** @brief Deletes all of the possible configuration parameters for a channel
557 *
558 * @param[in] bus - The bus object used for lookups
559 * @param[in] params - The parameters for the channel
560 */
561void deconfigureChannel(sdbusplus::bus::bus& bus, ChannelParams& params)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500562{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700563 // Delete all objects associated with the interface
564 auto objreq = bus.new_method_call(MAPPER_BUS_NAME, MAPPER_OBJ, MAPPER_INTF,
565 "GetSubTree");
566 objreq.append(PATH_ROOT, 0, std::vector<std::string>{DELETE_INTERFACE});
567 auto objreply = bus.call(objreq);
568 ObjectTree objs;
569 objreply.read(objs);
570 for (const auto& [path, impls] : objs)
571 {
572 if (path.find(params.ifname) == path.npos)
573 {
574 continue;
575 }
576 for (const auto& [service, intfs] : impls)
577 {
578 deleteObjectIfExists(bus, service, path);
579 }
580 // Update params to reflect the deletion of vlan
581 if (path == params.logicalPath)
582 {
583 params.logicalPath = params.ifPath;
584 }
585 }
586
587 // Clear out any settings on the lower physical interface
Johnathan Mantey65265362019-11-14 11:24:19 -0800588 setDHCPv6Property(bus, params, EthernetInterface::DHCPConf::none, false);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500589}
590
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700591/** @brief Creates a new VLAN on the specified interface
592 *
593 * @param[in] bus - The bus object used for lookups
594 * @param[in] params - The parameters for the channel
595 * @param[in] vlan - The id of the new vlan
596 */
597void createVLAN(sdbusplus::bus::bus& bus, ChannelParams& params, uint16_t vlan)
Ratan Guptab8e99552017-07-27 07:07:48 +0530598{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700599 if (vlan == 0)
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +0530600 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700601 return;
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +0530602 }
603
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700604 auto req = bus.new_method_call(params.service.c_str(), PATH_ROOT,
605 INTF_VLAN_CREATE, "VLAN");
606 req.append(params.ifname, static_cast<uint32_t>(vlan));
607 auto reply = bus.call(req);
608 sdbusplus::message::object_path newPath;
609 reply.read(newPath);
610 params.logicalPath = std::move(newPath);
Richard Marian Thomaiyar75b480b2019-01-22 00:20:15 +0530611}
612
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700613/** @brief Performs the necessary reconfiguration to change the VLAN
614 *
615 * @param[in] bus - The bus object used for lookups
616 * @param[in] params - The parameters for the channel
617 * @param[in] vlan - The new vlan id to use
618 */
619void reconfigureVLAN(sdbusplus::bus::bus& bus, ChannelParams& params,
620 uint16_t vlan)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500621{
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700622 // Unfortunatetly we don't have built-in functions to migrate our interface
623 // customizations to new VLAN interfaces, or have some kind of decoupling.
624 // We therefore must retain all of our old information, setup the new VLAN
625 // configuration, then restore the old info.
Nan Li3d0df912016-10-18 19:51:41 +0800626
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700627 // Save info from the old logical interface
628 ObjectLookupCache ips(bus, params, INTF_IP);
629 auto ifaddr4 = findIfAddr<AF_INET>(bus, params, 0, originsV4, ips);
William A. Kennington III16064aa2019-04-13 17:44:53 -0700630 std::vector<IfAddr<AF_INET6>> ifaddrs6;
631 for (uint8_t i = 0; i < MAX_IPV6_STATIC_ADDRESSES; ++i)
632 {
633 auto ifaddr6 =
634 findIfAddr<AF_INET6>(bus, params, i, originsV6Static, ips);
635 if (!ifaddr6)
636 {
637 break;
638 }
639 ifaddrs6.push_back(std::move(*ifaddr6));
640 }
Johnathan Mantey65265362019-11-14 11:24:19 -0800641 EthernetInterface::DHCPConf dhcp = getDHCPProperty(bus, params);
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700642 ObjectLookupCache neighbors(bus, params, INTF_NEIGHBOR);
643 auto neighbor4 = findGatewayNeighbor<AF_INET>(bus, params, neighbors);
William A. Kennington III16064aa2019-04-13 17:44:53 -0700644 auto neighbor6 = findGatewayNeighbor<AF_INET6>(bus, params, neighbors);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500645
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700646 deconfigureChannel(bus, params);
647 createVLAN(bus, params, vlan);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500648
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700649 // Re-establish the saved settings
Johnathan Mantey65265362019-11-14 11:24:19 -0800650 setDHCPv6Property(bus, params, dhcp, false);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700651 if (ifaddr4)
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800652 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700653 createIfAddr<AF_INET>(bus, params, ifaddr4->address, ifaddr4->prefix);
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800654 }
William A. Kennington III16064aa2019-04-13 17:44:53 -0700655 for (const auto& ifaddr6 : ifaddrs6)
656 {
657 createIfAddr<AF_INET6>(bus, params, ifaddr6.address, ifaddr6.prefix);
658 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -0700659 if (neighbor4)
660 {
661 createNeighbor<AF_INET>(bus, params, neighbor4->ip, neighbor4->mac);
662 }
William A. Kennington III16064aa2019-04-13 17:44:53 -0700663 if (neighbor6)
664 {
665 createNeighbor<AF_INET6>(bus, params, neighbor6->ip, neighbor6->mac);
666 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700667}
Patrick Venturec7c1c3c2017-11-15 14:29:18 -0800668
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700669/** @brief Turns a prefix into a netmask
670 *
671 * @param[in] prefix - The prefix length
672 * @return The netmask
673 */
674in_addr prefixToNetmask(uint8_t prefix)
675{
676 if (prefix > 32)
Adriana Kobylak5d6481f2015-10-29 21:44:55 -0500677 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700678 log<level::ERR>("Invalid prefix", entry("PREFIX=%" PRIu8, prefix));
679 elog<InternalFailure>();
680 }
681 if (prefix == 0)
682 {
683 // Avoids 32-bit lshift by 32 UB
684 return {};
685 }
686 return {htobe32(~UINT32_C(0) << (32 - prefix))};
687}
688
689/** @brief Turns a a netmask into a prefix length
690 *
691 * @param[in] netmask - The netmask in byte form
692 * @return The prefix length
693 */
694uint8_t netmaskToPrefix(in_addr netmask)
695{
696 uint32_t x = be32toh(netmask.s_addr);
697 if ((~x & (~x + 1)) != 0)
698 {
699 char maskStr[INET_ADDRSTRLEN];
700 inet_ntop(AF_INET, &netmask, maskStr, sizeof(maskStr));
701 log<level::ERR>("Invalid netmask", entry("NETMASK=%s", maskStr));
702 elog<InternalFailure>();
703 }
Johnathan Mantey62c05dd2019-11-20 14:07:44 -0800704 return static_cast<bool>(x)
705 ? AddrFamily<AF_INET>::defaultPrefix - __builtin_ctz(x)
706 : 0;
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700707}
708
709// We need to store this value so it can be returned to the client
710// It is volatile so safe to store in daemon memory.
711static std::unordered_map<uint8_t, SetStatus> setStatus;
712
713// Until we have good support for fixed versions of IPMI tool
714// we need to return the VLAN id for disabled VLANs. The value is only
715// used for verification that a disable operation succeeded and will only
716// be sent if our system indicates that vlans are disabled.
717static std::unordered_map<uint8_t, uint16_t> lastDisabledVlan;
718
719/** @brief Gets the set status for the channel if it exists
720 * Otherise populates and returns the default value.
721 *
722 * @param[in] channel - The channel id corresponding to an ethernet interface
723 * @return A reference to the SetStatus for the channel
724 */
725SetStatus& getSetStatus(uint8_t channel)
726{
727 auto it = setStatus.find(channel);
728 if (it != setStatus.end())
729 {
730 return it->second;
731 }
732 return setStatus[channel] = SetStatus::Complete;
733}
734
Johnathan Mantey3b7a4072021-01-26 14:24:53 -0800735/** @brief Gets the IPv6 Router Advertisement value
736 *
737 * @param[in] bus - The bus object used for lookups
738 * @param[in] params - The parameters for the channel
739 * @return networkd IPV6AcceptRA value
740 */
741static bool getIPv6AcceptRA(sdbusplus::bus::bus& bus,
742 const ChannelParams& params)
743{
744 auto raEnabled =
745 std::get<bool>(getDbusProperty(bus, params.service, params.logicalPath,
746 INTF_ETHERNET, "IPv6AcceptRA"));
747 return raEnabled;
748}
749
750/** @brief Sets the IPv6AcceptRA flag
751 *
752 * @param[in] bus - The bus object used for lookups
753 * @param[in] params - The parameters for the channel
754 * @param[in] ipv6AcceptRA - boolean to enable/disable IPv6 Routing
755 * Advertisement
756 */
757void setIPv6AcceptRA(sdbusplus::bus::bus& bus, const ChannelParams& params,
758 const bool ipv6AcceptRA)
759{
760 setDbusProperty(bus, params.service, params.logicalPath, INTF_ETHERNET,
761 "IPv6AcceptRA", ipv6AcceptRA);
762}
763
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700764/**
765 * Define placeholder command handlers for the OEM Extension bytes for the Set
766 * LAN Configuration Parameters and Get LAN Configuration Parameters
767 * commands. Using "weak" linking allows the placeholder setLanOem/getLanOem
768 * functions below to be overridden.
769 * To create handlers for your own proprietary command set:
770 * Create/modify a phosphor-ipmi-host Bitbake append file within your Yocto
771 * recipe
772 * Create C++ file(s) that define IPMI handler functions matching the
773 * function names below (i.e. setLanOem). The default name for the
774 * transport IPMI commands is transporthandler_oem.cpp.
775 * Add:
776 * EXTRA_OECONF_append = " --enable-transport-oem=yes"
777 * Create a do_compile_prepend()/do_install_append method in your
778 * bbappend file to copy the file to the build directory.
779 * Add:
780 * PROJECT_SRC_DIR := "${THISDIR}/${PN}"
781 * # Copy the "strong" functions into the working directory, overriding the
782 * # placeholder functions.
783 * do_compile_prepend(){
784 * cp -f ${PROJECT_SRC_DIR}/transporthandler_oem.cpp ${S}
785 * }
786 *
787 * # Clean up after complilation has completed
788 * do_install_append(){
789 * rm -f ${S}/transporthandler_oem.cpp
790 * }
791 *
792 */
793
794/**
795 * Define the placeholder OEM commands as having weak linkage. Create
796 * setLanOem, and getLanOem functions in the transporthandler_oem.cpp
797 * file. The functions defined there must not have the "weak" attribute
798 * applied to them.
799 */
800RspType<> setLanOem(uint8_t channel, uint8_t parameter, message::Payload& req)
801 __attribute__((weak));
802RspType<message::Payload> getLanOem(uint8_t channel, uint8_t parameter,
803 uint8_t set, uint8_t block)
804 __attribute__((weak));
805
806RspType<> setLanOem(uint8_t channel, uint8_t parameter, message::Payload& req)
807{
808 req.trailingOk = true;
809 return response(ccParamNotSupported);
810}
811
812RspType<message::Payload> getLanOem(uint8_t channel, uint8_t parameter,
813 uint8_t set, uint8_t block)
814{
815 return response(ccParamNotSupported);
816}
Rajashekar Gade Reddy0b993fd2019-12-24 16:37:15 +0530817/**
818 * @brief is MAC address valid.
819 *
820 * This function checks whether the MAC address is valid or not.
821 *
822 * @param[in] mac - MAC address.
823 * @return true if MAC address is valid else retun false.
824 **/
825bool isValidMACAddress(const ether_addr& mac)
826{
827 // check if mac address is empty
828 if (equal(mac, ether_addr{}))
829 {
830 return false;
831 }
832 // we accept only unicast MAC addresses and same thing has been checked in
833 // phosphor-network layer. If the least significant bit of the first octet
834 // is set to 1, it is multicast MAC else it is unicast MAC address.
835 if (mac.ether_addr_octet[0] & 1)
836 {
837 return false;
838 }
839 return true;
840}
Johnathan Manteyb87034e2019-09-16 10:50:50 -0700841
vijayabharathix shettycc769252020-02-27 17:52:20 +0000842RspType<> setLan(Context::ptr ctx, uint4_t channelBits, uint4_t reserved1,
843 uint8_t parameter, message::Payload& req)
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700844{
vijayabharathix shettycc769252020-02-27 17:52:20 +0000845 const uint8_t channel = convertCurrentChannelNum(
846 static_cast<uint8_t>(channelBits), ctx->channel);
847 if (reserved1 || !isValidChannel(channel))
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700848 {
vijayabharathix shettycc769252020-02-27 17:52:20 +0000849 log<level::ERR>("Set Lan - Invalid field in request");
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700850 req.trailingOk = true;
851 return responseInvalidFieldRequest();
852 }
853
854 switch (static_cast<LanParam>(parameter))
855 {
856 case LanParam::SetStatus:
857 {
858 uint2_t flag;
859 uint6_t rsvd;
860 if (req.unpack(flag, rsvd) != 0 || !req.fullyUnpacked())
861 {
862 return responseReqDataLenInvalid();
863 }
Johnathan Mantey4a156852019-12-11 13:47:43 -0800864 if (rsvd)
865 {
866 return responseInvalidFieldRequest();
867 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700868 auto status = static_cast<SetStatus>(static_cast<uint8_t>(flag));
869 switch (status)
870 {
871 case SetStatus::Complete:
872 {
873 getSetStatus(channel) = status;
874 return responseSuccess();
875 }
876 case SetStatus::InProgress:
877 {
878 auto& storedStatus = getSetStatus(channel);
879 if (storedStatus == SetStatus::InProgress)
880 {
881 return response(ccParamSetLocked);
882 }
883 storedStatus = status;
884 return responseSuccess();
885 }
886 case SetStatus::Commit:
887 if (getSetStatus(channel) != SetStatus::InProgress)
888 {
889 return responseInvalidFieldRequest();
890 }
891 return responseSuccess();
892 }
893 return response(ccParamNotSupported);
894 }
895 case LanParam::AuthSupport:
896 {
897 req.trailingOk = true;
898 return response(ccParamReadOnly);
899 }
900 case LanParam::AuthEnables:
901 {
902 req.trailingOk = true;
Johnathan Mantey76ce9c72019-11-14 14:41:46 -0800903 return response(ccParamReadOnly);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700904 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -0800905 case LanParam::IP:
Hariharasubramanian R83951912016-01-20 07:06:36 -0600906 {
Johnathan Mantey65265362019-11-14 11:24:19 -0800907 EthernetInterface::DHCPConf dhcp =
908 channelCall<getDHCPProperty>(channel);
909 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
910 (dhcp == EthernetInterface::DHCPConf::both))
Johnathan Mantey930104a2019-12-17 09:18:34 -0800911 {
912 return responseCommandNotAvailable();
913 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700914 in_addr ip;
915 std::array<uint8_t, sizeof(ip)> bytes;
916 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
917 {
918 return responseReqDataLenInvalid();
919 }
920 copyInto(ip, bytes);
921 channelCall<reconfigureIfAddr4>(channel, ip, std::nullopt);
922 return responseSuccess();
Ratan Guptab8e99552017-07-27 07:07:48 +0530923 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700924 case LanParam::IPSrc:
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530925 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700926 uint4_t flag;
927 uint4_t rsvd;
928 if (req.unpack(flag, rsvd) != 0 || !req.fullyUnpacked())
929 {
930 return responseReqDataLenInvalid();
931 }
Johnathan Mantey4a156852019-12-11 13:47:43 -0800932 if (rsvd)
933 {
934 return responseInvalidFieldRequest();
935 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700936 switch (static_cast<IPSrc>(static_cast<uint8_t>(flag)))
937 {
938 case IPSrc::DHCP:
939 {
Johnathan Mantey65265362019-11-14 11:24:19 -0800940 // The IPSrc IPMI command is only for IPv4
941 // management. Modifying IPv6 state is done using
942 // a completely different Set LAN Configuration
943 // subcommand.
944 channelCall<setDHCPv4Property>(
945 channel, EthernetInterface::DHCPConf::v4);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700946 return responseSuccess();
947 }
948 case IPSrc::Unspecified:
949 case IPSrc::Static:
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700950 {
Johnathan Mantey65265362019-11-14 11:24:19 -0800951 channelCall<setDHCPv4Property>(
952 channel, EthernetInterface::DHCPConf::none);
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700953 return responseSuccess();
954 }
Rajashekar Gade Reddy8a860ea2019-12-24 11:31:19 +0530955 case IPSrc::BIOS:
956 case IPSrc::BMC:
957 {
958 return responseInvalidFieldRequest();
959 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700960 }
961 return response(ccParamNotSupported);
Ratan Guptacc6cdbf2017-09-01 23:06:25 +0530962 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -0800963 case LanParam::MAC:
Ratan Guptab8e99552017-07-27 07:07:48 +0530964 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700965 ether_addr mac;
966 std::array<uint8_t, sizeof(mac)> bytes;
967 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
Suryakanth Sekar0a327e12019-08-08 14:30:19 +0530968 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700969 return responseReqDataLenInvalid();
Suryakanth Sekar0a327e12019-08-08 14:30:19 +0530970 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700971 copyInto(mac, bytes);
Rajashekar Gade Reddy0b993fd2019-12-24 16:37:15 +0530972
973 if (!isValidMACAddress(mac))
974 {
975 return responseInvalidFieldRequest();
976 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700977 channelCall<setMACProperty>(channel, mac);
978 return responseSuccess();
Ratan Gupta533d03b2017-07-30 10:39:22 +0530979 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700980 case LanParam::SubnetMask:
Ratan Guptab8e99552017-07-27 07:07:48 +0530981 {
Johnathan Mantey65265362019-11-14 11:24:19 -0800982 EthernetInterface::DHCPConf dhcp =
983 channelCall<getDHCPProperty>(channel);
984 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
985 (dhcp == EthernetInterface::DHCPConf::both))
Johnathan Mantey930104a2019-12-17 09:18:34 -0800986 {
987 return responseCommandNotAvailable();
988 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700989 in_addr netmask;
990 std::array<uint8_t, sizeof(netmask)> bytes;
991 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
Ratan Guptab8e99552017-07-27 07:07:48 +0530992 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700993 return responseReqDataLenInvalid();
Ratan Guptab8e99552017-07-27 07:07:48 +0530994 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -0700995 copyInto(netmask, bytes);
996 channelCall<reconfigureIfAddr4>(channel, std::nullopt,
997 netmaskToPrefix(netmask));
998 return responseSuccess();
Ratan Guptab8e99552017-07-27 07:07:48 +0530999 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001000 case LanParam::Gateway1:
Ratan Guptab8e99552017-07-27 07:07:48 +05301001 {
Johnathan Mantey65265362019-11-14 11:24:19 -08001002 EthernetInterface::DHCPConf dhcp =
1003 channelCall<getDHCPProperty>(channel);
1004 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
1005 (dhcp == EthernetInterface::DHCPConf::both))
Johnathan Mantey930104a2019-12-17 09:18:34 -08001006 {
1007 return responseCommandNotAvailable();
1008 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001009 in_addr gateway;
1010 std::array<uint8_t, sizeof(gateway)> bytes;
1011 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1012 {
1013 return responseReqDataLenInvalid();
1014 }
1015 copyInto(gateway, bytes);
1016 channelCall<setGatewayProperty<AF_INET>>(channel, gateway);
1017 return responseSuccess();
1018 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001019 case LanParam::Gateway1MAC:
1020 {
1021 ether_addr gatewayMAC;
1022 std::array<uint8_t, sizeof(gatewayMAC)> bytes;
1023 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1024 {
1025 return responseReqDataLenInvalid();
1026 }
1027 copyInto(gatewayMAC, bytes);
1028 channelCall<reconfigureGatewayMAC<AF_INET>>(channel, gatewayMAC);
1029 return responseSuccess();
1030 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001031 case LanParam::VLANId:
1032 {
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301033 uint12_t vlanData = 0;
1034 uint3_t reserved = 0;
1035 bool vlanEnable = 0;
1036
1037 if (req.unpack(vlanData) || req.unpack(reserved) ||
1038 req.unpack(vlanEnable) || !req.fullyUnpacked())
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001039 {
1040 return responseReqDataLenInvalid();
1041 }
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301042
1043 if (reserved)
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001044 {
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301045 return responseInvalidFieldRequest();
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001046 }
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301047
1048 uint16_t vlan = static_cast<uint16_t>(vlanData);
1049
1050 if (!vlanEnable)
1051 {
1052 lastDisabledVlan[channel] = vlan;
1053 vlan = 0;
1054 }
jayaprakash Mutyala84c49dc2020-05-18 23:12:13 +00001055 else if (vlan == 0 || vlan == VLAN_VALUE_MASK)
1056 {
1057 return responseInvalidFieldRequest();
1058 }
Suryakanth Sekar8e8c8e22019-08-30 11:54:20 +05301059
jayaprakash Mutyala84c49dc2020-05-18 23:12:13 +00001060 channelCall<reconfigureVLAN>(channel, vlan);
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001061 return responseSuccess();
1062 }
1063 case LanParam::CiphersuiteSupport:
1064 case LanParam::CiphersuiteEntries:
William A. Kennington III16064aa2019-04-13 17:44:53 -07001065 case LanParam::IPFamilySupport:
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001066 {
1067 req.trailingOk = true;
1068 return response(ccParamReadOnly);
Ratan Guptab8e99552017-07-27 07:07:48 +05301069 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001070 case LanParam::IPFamilyEnables:
1071 {
1072 uint8_t enables;
1073 if (req.unpack(enables) != 0 || !req.fullyUnpacked())
1074 {
1075 return responseReqDataLenInvalid();
1076 }
1077 switch (static_cast<IPFamilyEnables>(enables))
1078 {
1079 case IPFamilyEnables::DualStack:
1080 return responseSuccess();
1081 case IPFamilyEnables::IPv4Only:
1082 case IPFamilyEnables::IPv6Only:
1083 return response(ccParamNotSupported);
1084 }
1085 return response(ccParamNotSupported);
1086 }
1087 case LanParam::IPv6Status:
1088 {
1089 req.trailingOk = true;
1090 return response(ccParamReadOnly);
1091 }
1092 case LanParam::IPv6StaticAddresses:
1093 {
1094 uint8_t set;
1095 uint7_t rsvd;
1096 bool enabled;
1097 in6_addr ip;
1098 std::array<uint8_t, sizeof(ip)> ipbytes;
1099 uint8_t prefix;
1100 uint8_t status;
1101 if (req.unpack(set, rsvd, enabled, ipbytes, prefix, status) != 0 ||
1102 !req.fullyUnpacked())
1103 {
1104 return responseReqDataLenInvalid();
1105 }
Johnathan Mantey4a156852019-12-11 13:47:43 -08001106 if (rsvd)
1107 {
1108 return responseInvalidFieldRequest();
1109 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001110 copyInto(ip, ipbytes);
1111 if (enabled)
1112 {
1113 channelCall<reconfigureIfAddr6>(channel, set, ip, prefix);
1114 }
1115 else
1116 {
1117 channelCall<deconfigureIfAddr6>(channel, set);
1118 }
1119 return responseSuccess();
1120 }
1121 case LanParam::IPv6DynamicAddresses:
1122 {
1123 req.trailingOk = true;
1124 return response(ccParamReadOnly);
1125 }
1126 case LanParam::IPv6RouterControl:
1127 {
1128 std::bitset<8> control;
Johnathan Mantey3b7a4072021-01-26 14:24:53 -08001129 constexpr uint8_t reservedRACCBits = 0xfc;
William A. Kennington III16064aa2019-04-13 17:44:53 -07001130 if (req.unpack(control) != 0 || !req.fullyUnpacked())
1131 {
1132 return responseReqDataLenInvalid();
1133 }
Johnathan Mantey3b7a4072021-01-26 14:24:53 -08001134 if (std::bitset<8> expected(control &
1135 std::bitset<8>(reservedRACCBits));
1136 expected.any())
William A. Kennington III16064aa2019-04-13 17:44:53 -07001137 {
Johnathan Mantey3b7a4072021-01-26 14:24:53 -08001138 return response(ccParamNotSupported);
William A. Kennington III16064aa2019-04-13 17:44:53 -07001139 }
Johnathan Mantey3b7a4072021-01-26 14:24:53 -08001140
1141 bool enableRA = control[IPv6RouterControlFlag::Dynamic];
1142 channelCall<setIPv6AcceptRA>(channel, enableRA);
William A. Kennington III16064aa2019-04-13 17:44:53 -07001143 return responseSuccess();
1144 }
1145 case LanParam::IPv6StaticRouter1IP:
1146 {
1147 in6_addr gateway;
1148 std::array<uint8_t, sizeof(gateway)> bytes;
1149 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1150 {
1151 return responseReqDataLenInvalid();
1152 }
1153 copyInto(gateway, bytes);
1154 channelCall<setGatewayProperty<AF_INET6>>(channel, gateway);
1155 return responseSuccess();
1156 }
1157 case LanParam::IPv6StaticRouter1MAC:
1158 {
1159 ether_addr mac;
1160 std::array<uint8_t, sizeof(mac)> bytes;
1161 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1162 {
1163 return responseReqDataLenInvalid();
1164 }
1165 copyInto(mac, bytes);
1166 channelCall<reconfigureGatewayMAC<AF_INET6>>(channel, mac);
1167 return responseSuccess();
1168 }
1169 case LanParam::IPv6StaticRouter1PrefixLength:
1170 {
1171 uint8_t prefix;
1172 if (req.unpack(prefix) != 0 || !req.fullyUnpacked())
1173 {
1174 return responseReqDataLenInvalid();
1175 }
1176 if (prefix != 0)
1177 {
1178 return responseInvalidFieldRequest();
1179 }
1180 return responseSuccess();
1181 }
1182 case LanParam::IPv6StaticRouter1PrefixValue:
1183 {
1184 std::array<uint8_t, sizeof(in6_addr)> bytes;
1185 if (req.unpack(bytes) != 0 || !req.fullyUnpacked())
1186 {
1187 return responseReqDataLenInvalid();
1188 }
1189 // Accept any prefix value since our prefix length has to be 0
1190 return responseSuccess();
1191 }
jayaprakash Mutyalab741b992019-12-02 17:29:09 +00001192 case LanParam::cipherSuitePrivilegeLevels:
1193 {
1194 uint8_t reserved;
1195 std::array<uint4_t, ipmi::maxCSRecords> cipherSuitePrivs;
1196
1197 if (req.unpack(reserved, cipherSuitePrivs) || !req.fullyUnpacked())
1198 {
1199 return responseReqDataLenInvalid();
1200 }
1201
1202 if (reserved)
1203 {
1204 return responseInvalidFieldRequest();
1205 }
1206
1207 uint8_t resp =
1208 getCipherConfigObject(csPrivFileName, csPrivDefaultFileName)
1209 .setCSPrivilegeLevels(channel, cipherSuitePrivs);
1210 if (!resp)
1211 {
1212 return responseSuccess();
1213 }
1214 else
1215 {
1216 req.trailingOk = true;
1217 return response(resp);
1218 }
1219 }
Ratan Guptab8e99552017-07-27 07:07:48 +05301220 }
vishwa1eaea4f2016-02-26 11:57:40 -06001221
Johnathan Manteyb87034e2019-09-16 10:50:50 -07001222 if ((parameter >= oemCmdStart) && (parameter <= oemCmdEnd))
1223 {
1224 return setLanOem(channel, parameter, req);
1225 }
1226
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001227 req.trailingOk = true;
1228 return response(ccParamNotSupported);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001229}
1230
vijayabharathix shettycc769252020-02-27 17:52:20 +00001231RspType<message::Payload> getLan(Context::ptr ctx, uint4_t channelBits,
1232 uint3_t reserved, bool revOnly,
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001233 uint8_t parameter, uint8_t set, uint8_t block)
Ratan Guptab8e99552017-07-27 07:07:48 +05301234{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001235 message::Payload ret;
1236 constexpr uint8_t current_revision = 0x11;
1237 ret.pack(current_revision);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001238
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001239 if (revOnly)
Suryakanth Sekare4054402019-08-08 15:16:52 +05301240 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001241 return responseSuccess(std::move(ret));
Suryakanth Sekare4054402019-08-08 15:16:52 +05301242 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001243
vijayabharathix shettycc769252020-02-27 17:52:20 +00001244 const uint8_t channel = convertCurrentChannelNum(
1245 static_cast<uint8_t>(channelBits), ctx->channel);
1246 if (reserved || !isValidChannel(channel))
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001247 {
vijayabharathix shettycc769252020-02-27 17:52:20 +00001248 log<level::ERR>("Get Lan - Invalid field in request");
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001249 return responseInvalidFieldRequest();
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001250 }
1251
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001252 static std::vector<uint8_t> cipherList;
1253 static bool listInit = false;
1254 if (!listInit)
1255 {
1256 try
1257 {
1258 cipherList = cipher::getCipherList();
1259 listInit = true;
1260 }
1261 catch (const std::exception& e)
1262 {
1263 }
1264 }
1265
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001266 switch (static_cast<LanParam>(parameter))
Tom Josepha30c8d32018-03-22 02:15:03 +05301267 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001268 case LanParam::SetStatus:
Tom Josepha30c8d32018-03-22 02:15:03 +05301269 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001270 SetStatus status;
1271 try
1272 {
1273 status = setStatus.at(channel);
1274 }
1275 catch (const std::out_of_range&)
1276 {
1277 status = SetStatus::Complete;
1278 }
1279 ret.pack(static_cast<uint2_t>(status), uint6_t{});
1280 return responseSuccess(std::move(ret));
Tom Josepha30c8d32018-03-22 02:15:03 +05301281 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001282 case LanParam::AuthSupport:
Tom Josepha30c8d32018-03-22 02:15:03 +05301283 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001284 std::bitset<6> support;
1285 ret.pack(support, uint2_t{});
1286 return responseSuccess(std::move(ret));
Tom Josepha30c8d32018-03-22 02:15:03 +05301287 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001288 case LanParam::AuthEnables:
vishwa1eaea4f2016-02-26 11:57:40 -06001289 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001290 std::bitset<6> enables;
1291 ret.pack(enables, uint2_t{}); // Callback
1292 ret.pack(enables, uint2_t{}); // User
1293 ret.pack(enables, uint2_t{}); // Operator
1294 ret.pack(enables, uint2_t{}); // Admin
1295 ret.pack(enables, uint2_t{}); // OEM
1296 return responseSuccess(std::move(ret));
William A. Kennington III39f94ef2018-11-19 22:36:16 -08001297 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001298 case LanParam::IP:
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001299 {
1300 auto ifaddr = channelCall<getIfAddr4>(channel);
1301 in_addr addr{};
1302 if (ifaddr)
1303 {
1304 addr = ifaddr->address;
1305 }
1306 ret.pack(dataRef(addr));
1307 return responseSuccess(std::move(ret));
1308 }
1309 case LanParam::IPSrc:
1310 {
1311 auto src = IPSrc::Static;
Johnathan Mantey65265362019-11-14 11:24:19 -08001312 EthernetInterface::DHCPConf dhcp =
1313 channelCall<getDHCPProperty>(channel);
1314 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
1315 (dhcp == EthernetInterface::DHCPConf::both))
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001316 {
1317 src = IPSrc::DHCP;
1318 }
1319 ret.pack(static_cast<uint4_t>(src), uint4_t{});
1320 return responseSuccess(std::move(ret));
1321 }
William A. Kennington IIIaab20232018-11-19 18:20:39 -08001322 case LanParam::MAC:
William A. Kennington III39f94ef2018-11-19 22:36:16 -08001323 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001324 ether_addr mac = channelCall<getMACProperty>(channel);
1325 ret.pack(dataRef(mac));
1326 return responseSuccess(std::move(ret));
1327 }
1328 case LanParam::SubnetMask:
1329 {
1330 auto ifaddr = channelCall<getIfAddr4>(channel);
1331 uint8_t prefix = AddrFamily<AF_INET>::defaultPrefix;
1332 if (ifaddr)
Ratan Guptab8e99552017-07-27 07:07:48 +05301333 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001334 prefix = ifaddr->prefix;
1335 }
1336 in_addr netmask = prefixToNetmask(prefix);
1337 ret.pack(dataRef(netmask));
1338 return responseSuccess(std::move(ret));
1339 }
1340 case LanParam::Gateway1:
1341 {
1342 auto gateway =
1343 channelCall<getGatewayProperty<AF_INET>>(channel).value_or(
1344 in_addr{});
1345 ret.pack(dataRef(gateway));
1346 return responseSuccess(std::move(ret));
1347 }
William A. Kennington III4bbc3db2019-04-15 00:02:10 -07001348 case LanParam::Gateway1MAC:
1349 {
1350 ether_addr mac{};
1351 auto neighbor = channelCall<getGatewayNeighbor<AF_INET>>(channel);
1352 if (neighbor)
1353 {
1354 mac = neighbor->mac;
1355 }
1356 ret.pack(dataRef(mac));
1357 return responseSuccess(std::move(ret));
1358 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001359 case LanParam::VLANId:
1360 {
1361 uint16_t vlan = channelCall<getVLANProperty>(channel);
1362 if (vlan != 0)
1363 {
1364 vlan |= VLAN_ENABLE_FLAG;
Ratan Guptab8e99552017-07-27 07:07:48 +05301365 }
1366 else
1367 {
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001368 vlan = lastDisabledVlan[channel];
Ratan Guptab8e99552017-07-27 07:07:48 +05301369 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001370 ret.pack(vlan);
1371 return responseSuccess(std::move(ret));
Adriana Kobylak342df102016-02-10 13:48:16 -06001372 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001373 case LanParam::CiphersuiteSupport:
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001374 {
srikanta mondal1d8579c2020-04-15 17:13:25 +00001375 if (getChannelSessionSupport(channel) ==
1376 EChannelSessSupported::none)
1377 {
1378 return responseInvalidFieldRequest();
1379 }
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001380 if (!listInit)
1381 {
1382 return responseUnspecifiedError();
1383 }
1384 ret.pack(static_cast<uint8_t>(cipherList.size() - 1));
1385 return responseSuccess(std::move(ret));
1386 }
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001387 case LanParam::CiphersuiteEntries:
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001388 {
srikanta mondal1d8579c2020-04-15 17:13:25 +00001389 if (getChannelSessionSupport(channel) ==
1390 EChannelSessSupported::none)
1391 {
1392 return responseInvalidFieldRequest();
1393 }
Johnathan Manteyaffadb52019-10-07 10:13:53 -07001394 if (!listInit)
1395 {
1396 return responseUnspecifiedError();
1397 }
1398 ret.pack(cipherList);
1399 return responseSuccess(std::move(ret));
1400 }
William A. Kennington III16064aa2019-04-13 17:44:53 -07001401 case LanParam::IPFamilySupport:
1402 {
1403 std::bitset<8> support;
1404 support[IPFamilySupportFlag::IPv6Only] = 0;
1405 support[IPFamilySupportFlag::DualStack] = 1;
1406 support[IPFamilySupportFlag::IPv6Alerts] = 1;
1407 ret.pack(support);
1408 return responseSuccess(std::move(ret));
1409 }
1410 case LanParam::IPFamilyEnables:
1411 {
1412 ret.pack(static_cast<uint8_t>(IPFamilyEnables::DualStack));
1413 return responseSuccess(std::move(ret));
1414 }
1415 case LanParam::IPv6Status:
1416 {
1417 ret.pack(MAX_IPV6_STATIC_ADDRESSES);
1418 ret.pack(MAX_IPV6_DYNAMIC_ADDRESSES);
1419 std::bitset<8> support;
1420 support[IPv6StatusFlag::DHCP] = 1;
1421 support[IPv6StatusFlag::SLAAC] = 1;
1422 ret.pack(support);
1423 return responseSuccess(std::move(ret));
1424 }
1425 case LanParam::IPv6StaticAddresses:
1426 {
1427 if (set >= MAX_IPV6_STATIC_ADDRESSES)
1428 {
1429 return responseParmOutOfRange();
1430 }
1431 getLanIPv6Address(ret, channel, set, originsV6Static);
1432 return responseSuccess(std::move(ret));
1433 }
1434 case LanParam::IPv6DynamicAddresses:
1435 {
1436 if (set >= MAX_IPV6_DYNAMIC_ADDRESSES)
1437 {
1438 return responseParmOutOfRange();
1439 }
1440 getLanIPv6Address(ret, channel, set, originsV6Dynamic);
1441 return responseSuccess(std::move(ret));
1442 }
1443 case LanParam::IPv6RouterControl:
1444 {
1445 std::bitset<8> control;
Johnathan Mantey3b7a4072021-01-26 14:24:53 -08001446 control[IPv6RouterControlFlag::Dynamic] =
1447 channelCall<getIPv6AcceptRA>(channel);
1448 control[IPv6RouterControlFlag::Static] = 1;
William A. Kennington III16064aa2019-04-13 17:44:53 -07001449 ret.pack(control);
1450 return responseSuccess(std::move(ret));
1451 }
1452 case LanParam::IPv6StaticRouter1IP:
1453 {
1454 in6_addr gateway{};
Johnathan Mantey65265362019-11-14 11:24:19 -08001455 EthernetInterface::DHCPConf dhcp =
1456 channelCall<getDHCPProperty>(channel);
1457 if ((dhcp == EthernetInterface::DHCPConf::v4) ||
1458 (dhcp == EthernetInterface::DHCPConf::none))
William A. Kennington III16064aa2019-04-13 17:44:53 -07001459 {
1460 gateway =
1461 channelCall<getGatewayProperty<AF_INET6>>(channel).value_or(
1462 in6_addr{});
1463 }
1464 ret.pack(dataRef(gateway));
1465 return responseSuccess(std::move(ret));
1466 }
1467 case LanParam::IPv6StaticRouter1MAC:
1468 {
1469 ether_addr mac{};
1470 auto neighbor = channelCall<getGatewayNeighbor<AF_INET6>>(channel);
1471 if (neighbor)
1472 {
1473 mac = neighbor->mac;
1474 }
1475 ret.pack(dataRef(mac));
1476 return responseSuccess(std::move(ret));
1477 }
1478 case LanParam::IPv6StaticRouter1PrefixLength:
1479 {
1480 ret.pack(UINT8_C(0));
1481 return responseSuccess(std::move(ret));
1482 }
1483 case LanParam::IPv6StaticRouter1PrefixValue:
1484 {
1485 in6_addr prefix{};
1486 ret.pack(dataRef(prefix));
1487 return responseSuccess(std::move(ret));
1488 }
jayaprakash Mutyalab741b992019-12-02 17:29:09 +00001489 case LanParam::cipherSuitePrivilegeLevels:
1490 {
1491 std::array<uint4_t, ipmi::maxCSRecords> csPrivilegeLevels;
1492
1493 uint8_t resp =
1494 getCipherConfigObject(csPrivFileName, csPrivDefaultFileName)
1495 .getCSPrivilegeLevels(channel, csPrivilegeLevels);
1496 if (!resp)
1497 {
1498 constexpr uint8_t reserved1 = 0x00;
1499 ret.pack(reserved1, csPrivilegeLevels);
1500 return responseSuccess(std::move(ret));
1501 }
1502 else
1503 {
1504 return response(resp);
1505 }
1506 }
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001507 }
1508
Johnathan Manteyb87034e2019-09-16 10:50:50 -07001509 if ((parameter >= oemCmdStart) && (parameter <= oemCmdEnd))
1510 {
1511 return getLanOem(channel, parameter, set, block);
1512 }
1513
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001514 return response(ccParamNotSupported);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001515}
1516
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001517} // namespace transport
1518} // namespace ipmi
Ratan Gupta1247e0b2018-03-07 10:47:25 +05301519
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001520void register_netfn_transport_functions() __attribute__((constructor));
Ratan Gupta1247e0b2018-03-07 10:47:25 +05301521
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001522void register_netfn_transport_functions()
1523{
William A. Kennington IIIc514d872019-04-06 18:19:38 -07001524 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1525 ipmi::transport::cmdSetLanConfigParameters,
1526 ipmi::Privilege::Admin, ipmi::transport::setLan);
1527 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport,
1528 ipmi::transport::cmdGetLanConfigParameters,
Johnathan Mantey34698d52019-11-19 14:47:30 -08001529 ipmi::Privilege::Operator, ipmi::transport::getLan);
Adriana Kobylak5d6481f2015-10-29 21:44:55 -05001530}