blob: 91d998701920a807562e0ba78802e7c70ef8d16e [file] [log] [blame]
Patrick Venture5794fcf2017-10-26 11:11:14 -07001#include "channel.hpp"
2#include "types.hpp"
3#include "transporthandler.hpp"
4#include "utils.hpp"
5
6#include <string>
7#include <arpa/inet.h>
8
9#include <phosphor-logging/log.hpp>
10#include <phosphor-logging/elog-errors.hpp>
11#include "xyz/openbmc_project/Common/error.hpp"
12
13extern struct ChannelConfig_t channelConfig;
14
15constexpr auto ipv4Protocol = "xyz.openbmc_project.Network.IP.Protocol.IPv4";
16
17using namespace phosphor::logging;
18using namespace sdbusplus::xyz::openbmc_project::Common::Error;
19
20/** @struct GetChannelAccessRequest
21 *
22 * IPMI payload for Get Channel access command request.
23 */
24struct GetChannelAccessRequest
25{
26 uint8_t channelNumber; //!< Channel number.
27 uint8_t volatileSetting; //!< Get non-volatile or the volatile setting.
28} __attribute__((packed));
29
30/** @struct GetChannelAccessResponse
31 *
32 * IPMI payload for Get Channel access command response.
33 */
34struct GetChannelAccessResponse
35{
36 uint8_t settings; //!< Channel settings.
37 uint8_t privilegeLimit; //!< Channel privilege level limit.
38} __attribute__((packed));
39
40ipmi_ret_t ipmi_set_channel_access(ipmi_netfn_t netfn,
41 ipmi_cmd_t cmd,
42 ipmi_request_t request,
43 ipmi_response_t response,
44 ipmi_data_len_t data_len,
45 ipmi_context_t context)
46{
47 ipmi_ret_t rc = IPMI_CC_OK;
48
49 std::string ipaddress;
50 std::string gateway;
51 uint8_t prefix {};
52 uint32_t vlanID {};
53 std::string networkInterfacePath;
54 ipmi::DbusObjectInfo ipObject;
55 ipmi::DbusObjectInfo systemObject;
56
57 // Todo: parse the request data if needed.
58 // Using Set Channel cmd to apply changes of Set Lan Cmd.
59 try
60 {
61 sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
62
63 log<level::INFO>("Network data from Cache",
64 entry("PREFIX=%s", channelConfig.netmask.c_str()),
65 entry("ADDRESS=%s", channelConfig.ipaddr.c_str()),
66 entry("GATEWAY=%s", channelConfig.gateway.c_str()),
67 entry("VLAN=%d", channelConfig.vlanID),
68 entry("IPSRC=%d", channelConfig.ipsrc));
69
70 if (channelConfig.vlanID != ipmi::network::VLAN_ID_MASK)
71 {
72 //get the first twelve bits which is vlan id
73 //not interested in rest of the bits.
74 channelConfig.vlanID = le32toh(channelConfig.vlanID);
75 vlanID = channelConfig.vlanID & ipmi::network::VLAN_ID_MASK;
76 }
77
78 // if the asked ip src is DHCP then not interested in
79 // any given data except vlan.
80 if (channelConfig.ipsrc != ipmi::network::IPOrigin::DHCP)
81 {
82 // always get the system object
83 systemObject = ipmi::getDbusObject(
84 bus,
85 ipmi::network::SYSTEMCONFIG_INTERFACE,
86 ipmi::network::ROOT);
87
88 // the below code is to determine the mode of the interface
89 // as the handling is same, if the system is configured with
90 // DHCP or user has given all the data.
91 try
92 {
93 ipmi::ObjectTree ancestorMap;
94
95 ipmi::InterfaceList interfaces {
96 ipmi::network::ETHERNET_INTERFACE };
97
98 // if the system is having ip object,then
99 // get the IP object.
Ratan Guptadd646202017-11-21 17:46:59 +0530100 ipObject = ipmi::getIPObject(
101 bus,
102 ipmi::network::IP_INTERFACE,
103 ipmi::network::ROOT,
104 ipmi::network::IP_TYPE);
Patrick Venture5794fcf2017-10-26 11:11:14 -0700105
106 // Get the parent interface of the IP object.
107 try
108 {
109 ancestorMap = ipmi::getAllAncestors(bus,
110 ipObject.first,
111 std::move(interfaces));
112 }
113 catch (InternalFailure& e)
114 {
115 // if unable to get the parent interface
116 // then commit the error and return.
117 log<level::ERR>("Unable to get the parent interface",
118 entry("PATH=%s", ipObject.first.c_str()),
119 entry("INTERFACE=%s",
120 ipmi::network::ETHERNET_INTERFACE));
121 commit<InternalFailure>();
122 rc = IPMI_CC_UNSPECIFIED_ERROR;
123 channelConfig.clear();
124 return rc;
125 }
126
127 networkInterfacePath = ancestorMap.begin()->first;
128 }
129 catch (InternalFailure& e)
130 {
131 // TODO Currently IPMI supports single interface,need to handle
132 // Multiple interface through
133 // https://github.com/openbmc/openbmc/issues/2138
134
135 // if there is no ip configured on the system,then
136 // get the network interface object.
137 auto networkInterfaceObject = ipmi::getDbusObject(
138 bus,
139 ipmi::network::ETHERNET_INTERFACE,
140 ipmi::network::ROOT,
141 ipmi::network::INTERFACE);
142
143 networkInterfacePath = std::move(networkInterfaceObject.first);
144 }
145
146 // get the configured mode on the system.
147 auto enableDHCP = ipmi::getDbusProperty(
148 bus,
149 ipmi::network::SERVICE,
150 networkInterfacePath,
151 ipmi::network::ETHERNET_INTERFACE,
152 "DHCPEnabled").get<bool>();
153
154 // check whether user has given all the data
155 // or the configured system interface is dhcp enabled,
156 // in both of the cases get the values from the cache.
157 if ((!channelConfig.ipaddr.empty() &&
158 !channelConfig.netmask.empty() &&
159 !channelConfig.gateway.empty()) ||
160 (enableDHCP)) // configured system interface mode = DHCP
161 {
162 //convert mask into prefix
163 ipaddress = channelConfig.ipaddr;
164 prefix = ipmi::network::toPrefix(AF_INET, channelConfig.netmask);
165 gateway = channelConfig.gateway;
166 if (channelConfig.vlanID != ipmi::network::VLAN_ID_MASK)
167 {
168 //get the first twelve bits which is vlan id
169 //not interested in rest of the bits.
170 channelConfig.vlanID = le32toh(channelConfig.vlanID);
171 vlanID = channelConfig.vlanID & ipmi::network::VLAN_ID_MASK;
172 }
173 else
174 {
175 vlanID = ipmi::network::getVLAN(networkInterfacePath);
176 }
177
178 }
179 else // asked ip src = static and configured system src = static
180 // or partially given data.
181 {
182 // We have partial filled cache so get the remaining
183 // info from the system.
184
185 // Get the network data from the system as user has
186 // not given all the data then use the data fetched from the
187 // system but it is implementation dependent,IPMI spec doesn't
188 // force it.
189
190 // if system is not having any ip object don't throw error,
191 try
192 {
193 auto properties = ipmi::getAllDbusProperties(
194 bus,
195 ipObject.second,
196 ipObject.first,
197 ipmi::network::IP_INTERFACE);
198
199 ipaddress = channelConfig.ipaddr.empty() ?
Ratan Guptadd646202017-11-21 17:46:59 +0530200 properties["Address"].get<std::string>() :
201 channelConfig.ipaddr;
Patrick Venture5794fcf2017-10-26 11:11:14 -0700202
203 prefix = channelConfig.netmask.empty() ?
204 properties["PrefixLength"].get<uint8_t>() :
205 ipmi::network::toPrefix(AF_INET,
206 channelConfig.netmask);
207
208 }
209 catch (InternalFailure& e)
210 {
211 log<level::INFO>("Failed to get IP object which matches",
212 entry("INTERFACE=%s", ipmi::network::IP_INTERFACE),
213 entry("MATCH=%s", ipmi::network::IP_TYPE));
214 }
215
216 auto systemProperties = ipmi::getAllDbusProperties(
217 bus,
218 systemObject.second,
219 systemObject.first,
220 ipmi::network::SYSTEMCONFIG_INTERFACE);
221
222 gateway = channelConfig.gateway.empty() ?
223 systemProperties["DefaultGateway"].get<std::string>() :
224 channelConfig.gateway;
225
226 }
227 }
228
229 // Currently network manager doesn't support purging of all the
230 // ip addresses and the vlan interfaces from the parent interface,
231 // TODO once the support is there, will make the change here.
232 // https://github.com/openbmc/openbmc/issues/2141.
233
234 // TODO Currently IPMI supports single interface,need to handle
235 // Multiple interface through
236 // https://github.com/openbmc/openbmc/issues/2138
237
238 // instead of deleting all the vlan interfaces and
239 // all the ipv4 address,we will call reset method.
240 //delete all the vlan interfaces
241
242 ipmi::deleteAllDbusObjects(bus,
243 ipmi::network::ROOT,
244 ipmi::network::VLAN_INTERFACE);
245
246 // set the interface mode to static
247 auto networkInterfaceObject = ipmi::getDbusObject(
248 bus,
249 ipmi::network::ETHERNET_INTERFACE,
250 ipmi::network::ROOT,
251 ipmi::network::INTERFACE);
252
253 // setting the physical interface mode to static.
254 ipmi::setDbusProperty(bus,
255 ipmi::network::SERVICE,
256 networkInterfaceObject.first,
257 ipmi::network::ETHERNET_INTERFACE,
258 "DHCPEnabled",
259 false);
260
261 networkInterfacePath = networkInterfaceObject.first;
262
263 //delete all the ipv4 addresses
264 ipmi::deleteAllDbusObjects(bus,
265 ipmi::network::ROOT,
266 ipmi::network::IP_INTERFACE,
267 ipmi::network::IP_TYPE);
268
269 if (vlanID)
270 {
271 ipmi::network::createVLAN(bus,
272 ipmi::network::SERVICE,
273 ipmi::network::ROOT,
274 ipmi::network::INTERFACE,
275 vlanID);
276
277 auto networkInterfaceObject = ipmi::getDbusObject(
278 bus,
279 ipmi::network::VLAN_INTERFACE,
280 ipmi::network::ROOT);
281
282 networkInterfacePath = networkInterfaceObject.first;
283 }
284
285 if (channelConfig.ipsrc == ipmi::network::IPOrigin::DHCP)
286 {
287 ipmi::setDbusProperty(bus,
288 ipmi::network::SERVICE,
289 networkInterfacePath,
290 ipmi::network::ETHERNET_INTERFACE,
291 "DHCPEnabled",
292 true);
293 }
294 else
295 {
296 //change the mode to static
297 ipmi::setDbusProperty(bus,
298 ipmi::network::SERVICE,
299 networkInterfacePath,
300 ipmi::network::ETHERNET_INTERFACE,
301 "DHCPEnabled",
302 false);
303
304 if (!ipaddress.empty())
305 {
306 ipmi::network::createIP(bus,
307 ipmi::network::SERVICE,
308 networkInterfacePath,
309 ipv4Protocol,
310 ipaddress,
311 prefix);
312 }
313
314 if (!gateway.empty())
315 {
316 ipmi::setDbusProperty(bus,
317 systemObject.second,
318 systemObject.first,
319 ipmi::network::SYSTEMCONFIG_INTERFACE,
320 "DefaultGateway",
321 std::string(gateway));
322 }
323 }
324
325 }
326 catch (InternalFailure& e)
327 {
328 log<level::ERR>("Failed to set network data",
329 entry("PREFIX=%d", prefix),
330 entry("ADDRESS=%s", ipaddress.c_str()),
331 entry("GATEWAY=%s", gateway.c_str()),
332 entry("VLANID=%d", vlanID),
333 entry("IPSRC=%d", channelConfig.ipsrc));
334
335 commit<InternalFailure>();
336 rc = IPMI_CC_UNSPECIFIED_ERROR;
337 }
338
339 channelConfig.clear();
340 return rc;
341}
342
343ipmi_ret_t ipmi_get_channel_access(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
344 ipmi_request_t request, ipmi_response_t response,
345 ipmi_data_len_t data_len, ipmi_context_t context)
346{
347 auto requestData = reinterpret_cast<const GetChannelAccessRequest*>
348 (request);
349 std::vector<uint8_t> outPayload(sizeof(GetChannelAccessResponse));
350 auto responseData = reinterpret_cast<GetChannelAccessResponse*>
351 (outPayload.data());
352
353 // Channel 1 is arbitrarily assigned to ETH0 channel
354 constexpr auto channelOne = 0x01;
355
356 /*
357 * The value Eh is used as a way to identify the current channel that
358 * the command is being received from.
359 */
360 constexpr auto channelE = 0x0E;
361
362 if (requestData->channelNumber != channelOne &&
363 requestData->channelNumber != channelE)
364 {
365 *data_len = 0;
366 return IPMI_CC_INVALID_FIELD_REQUEST;
367 }
368
369 /*
370 * [7:6] - reserved
371 * [5] - 1b = Alerting disabled
372 * [4] - 1b = per message authentication disabled
373 * [3] - 0b = User level authentication enabled
374 * [2:0] - 2h = always available
375 */
376 constexpr auto channelSetting = 0x32;
377
378 responseData->settings = channelSetting;
379 //Defaulting the channel privilege to administrator level.
380 responseData->privilegeLimit = PRIVILEGE_ADMIN;
381
382 *data_len = outPayload.size();
383 memcpy(response, outPayload.data(), *data_len);
384
385 return IPMI_CC_OK;
386}
387
388// ATTENTION: This ipmi function is very hardcoded on purpose
389// OpenBMC does not fully support IPMI. This command is useful
390// to have around because it enables testing of interfaces with
391// the IPMI tool.
392#define GET_CHANNEL_INFO_CHANNEL_OFFSET 0
393// IPMI Table 6-2
394#define IPMI_CHANNEL_TYPE_IPMB 1
395// IPMI Table 6-3
396#define IPMI_CHANNEL_MEDIUM_TYPE_OTHER 6
397
398ipmi_ret_t ipmi_app_channel_info(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
399 ipmi_request_t request, ipmi_response_t response,
400 ipmi_data_len_t data_len, ipmi_context_t context)
401{
402 ipmi_ret_t rc = IPMI_CC_OK;
403 uint8_t resp[] = {
404 1,
405 IPMI_CHANNEL_MEDIUM_TYPE_OTHER,
406 IPMI_CHANNEL_TYPE_IPMB,
407 1,0x41,0xA7,0x00,0,0};
408 uint8_t *p = (uint8_t*) request;
409
410 printf("IPMI APP GET CHANNEL INFO\n");
411
412 // The supported channels numbers are 1 and 8.
413 // Channel Number E is used as way to identify the current channel
414 // that the command is being is received from.
415 if (*p == 0xe || *p == 1 || *p == 8) {
416
417 *data_len = sizeof(resp);
418 memcpy(response, resp, *data_len);
419
420 } else {
421 rc = IPMI_CC_PARM_OUT_OF_RANGE;
422 *data_len = 0;
423 }
424
425 return rc;
426}