1 #include "watchdog.hpp"
2 #include "utils.hpp"
3 
4 #include <systemd/sd-bus.h>
5 
6 #include <mapper.h>
7 #include <sdbusplus/bus.hpp>
8 
9 extern sd_bus *bus;
10 
11 struct set_wd_data_t {
12     uint8_t timer_use;
13     uint8_t timer_action;
14     uint8_t preset;
15     uint8_t flags;
16     uint8_t ls;
17     uint8_t ms;
18 }  __attribute__ ((packed));
19 
20 static constexpr auto objname = "/xyz/openbmc_project/watchdog/host0";
21 static constexpr auto iface = "xyz.openbmc_project.State.Watchdog";
22 static constexpr auto property_iface = "org.freedesktop.DBus.Properties";
23 
24 ipmi_ret_t ipmi_app_set_watchdog(
25         ipmi_netfn_t netfn,
26         ipmi_cmd_t cmd,
27         ipmi_request_t request,
28         ipmi_response_t response,
29         ipmi_data_len_t data_len,
30         ipmi_context_t context)
31 {
32     sd_bus_message *reply = NULL;
33     sd_bus_error error = SD_BUS_ERROR_NULL;
34     int r = 0;
35 
36     set_wd_data_t *reqptr = (set_wd_data_t*) request;
37 
38     uint16_t timer = 0;
39 
40     // Making this uint64_t to match with provider
41     uint64_t timer_ms = 0;
42     char *busname = NULL;
43     *data_len = 0;
44 
45     // Get number of 100ms intervals
46     timer = (((uint16_t)reqptr->ms) << 8) + reqptr->ls;
47     // Get timer value in ms
48     timer_ms = timer * 100;
49 
50     printf("WATCHDOG SET Timer:[0x%X] 100ms intervals\n",timer);
51 
52     // Get bus name
53     r = mapper_get_service(bus, objname, &busname);
54     if (r < 0) {
55         fprintf(stderr, "Failed to get %s bus name: %s\n",
56                 objname, strerror(-r));
57         goto finish;
58     }
59 
60     // Disable watchdog if running
61     r = sd_bus_call_method(bus, busname, objname, property_iface,
62                            "Set", &error, &reply, "ssv",
63                            iface, "Enabled", "b", false);
64     if(r < 0) {
65         fprintf(stderr, "Failed to disable Watchdog: %s\n",
66                     strerror(-r));
67         goto finish;
68     }
69 
70     /*
71      * If the action is 0, it means, do nothing.  Multiple actions on timer
72      * expiration aren't supported by phosphor-watchdog yet, so when the
73      * action set is "none", we should just leave the timer disabled.
74      */
75     if (0 == reqptr->timer_action)
76     {
77         goto finish;
78     }
79 
80     if (reqptr->timer_use & 0x40)
81     {
82         sd_bus_error_free(&error);
83         reply = sd_bus_message_unref(reply);
84 
85         // Set the Interval for the Watchdog
86         r = sd_bus_call_method(bus, busname, objname, property_iface,
87                                "Set", &error, &reply, "ssv",
88                                iface, "Interval", "t", timer_ms);
89         if(r < 0) {
90             fprintf(stderr, "Failed to set new expiration time: %s\n",
91                     strerror(-r));
92             goto finish;
93         }
94 
95         // Now Enable Watchdog
96         r = sd_bus_call_method(bus, busname, objname, property_iface,
97                                "Set", &error, &reply, "ssv",
98                                iface, "Enabled", "b", true);
99         if(r < 0) {
100             fprintf(stderr, "Failed to Enable Watchdog: %s\n",
101                     strerror(-r));
102             goto finish;
103         }
104     }
105 
106 finish:
107     sd_bus_error_free(&error);
108     reply = sd_bus_message_unref(reply);
109     free(busname);
110 
111     return (r < 0) ? -1 : IPMI_CC_OK;
112 }
113 
114 ipmi_ret_t ipmi_app_reset_watchdog(
115         ipmi_netfn_t netfn,
116         ipmi_cmd_t cmd,
117         ipmi_request_t request,
118         ipmi_response_t response,
119         ipmi_data_len_t data_len,
120         ipmi_context_t context)
121 {
122     sd_bus_message *reply = NULL;
123     sd_bus_error error = SD_BUS_ERROR_NULL;
124     int r = 0;
125     char *busname = NULL;
126 
127     // Current time interval that is set in watchdog.
128     uint64_t interval = 0;
129 
130     // Status code.
131     ipmi_ret_t rc = IPMI_CC_OK;
132     *data_len = 0;
133 
134     printf("WATCHDOG RESET\n");
135     // Get bus name
136     r = mapper_get_service(bus, objname, &busname);
137     if (r < 0) {
138         fprintf(stderr, "Failed to get %s bus name: %s\n",
139                 objname, strerror(-r));
140         goto finish;
141     }
142 
143     // Get the current interval and set it back.
144     r = sd_bus_call_method(bus, busname, objname, property_iface,
145                            "Get", &error, &reply, "ss",
146                            iface, "Interval");
147 
148     if(r < 0) {
149         fprintf(stderr, "Failed to get current Interval msg: %s\n",
150                 strerror(-r));
151         goto finish;
152     }
153 
154     // Now extract the value
155     r = sd_bus_message_read(reply, "v", "t", &interval);
156     if (r < 0) {
157         fprintf(stderr, "Failed to read current interval: %s\n",
158                 strerror(-r));
159         goto finish;
160     }
161 
162     sd_bus_error_free(&error);
163     reply = sd_bus_message_unref(reply);
164 
165     // Set watchdog timer
166     r = sd_bus_call_method(bus, busname, objname, property_iface,
167                            "Set", &error, &reply, "ssv",
168                            iface, "TimeRemaining", "t", interval);
169     if(r < 0) {
170         fprintf(stderr, "Failed to refresh the timer: %s\n",
171                 strerror(-r));
172         goto finish;
173     }
174 
175 finish:
176     sd_bus_error_free(&error);
177     reply = sd_bus_message_unref(reply);
178     free(busname);
179 
180     return rc;
181 }
182