blob: 84bbf69bc5abd49e6e20165309d627a15239c06f [file] [log] [blame]
Andrew Jeffery4fe996c2018-02-27 12:16:48 +10301// SPDX-License-Identifier: Apache-2.0
2// Copyright (C) 2018 IBM Corp.
Cyril Burc85e34d2016-11-15 11:50:41 +11003
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +11004#define _GNU_SOURCE
Cyril Burc85e34d2016-11-15 11:50:41 +11005#include <assert.h>
6#include <errno.h>
7#include <fcntl.h>
8#include <getopt.h>
9#include <limits.h>
10#include <poll.h>
11#include <stdbool.h>
12#include <stdint.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <syslog.h>
Michael Neuling899ebac2017-01-14 11:20:26 -060017#include <signal.h>
Cyril Burc85e34d2016-11-15 11:50:41 +110018#include <sys/ioctl.h>
19#include <sys/mman.h>
20#include <sys/stat.h>
21#include <sys/timerfd.h>
22#include <sys/types.h>
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110023#include <sys/signalfd.h>
Cyril Burc85e34d2016-11-15 11:50:41 +110024#include <time.h>
25#include <unistd.h>
Andrew Jeffery78210b92017-01-13 13:06:09 +103026#include <inttypes.h>
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110027#include <systemd/sd-bus.h>
Cyril Burc85e34d2016-11-15 11:50:41 +110028
Suraj Jitindar Singh8d65bb42017-05-01 16:05:17 +100029#include "config.h"
Andrew Jeffery26558db2018-08-10 00:22:38 +093030#include "mboxd.h"
Cyril Burc85e34d2016-11-15 11:50:41 +110031#include "common.h"
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110032#include "dbus.h"
Andrew Jeffery55f4d6f2018-08-06 12:26:44 +093033#include "control_dbus.h"
Andrew Jefferyeebc6bd2018-08-08 10:38:19 +093034#include "flash.h"
Andrew Jefferycd186112018-08-08 10:47:55 +093035#include "lpc.h"
Andrew Jeffery457a6e52018-08-08 11:21:08 +093036#include "transport_mbox.h"
Andrew Jeffery23140be2018-09-05 14:15:07 +093037#include "transport_dbus.h"
Andrew Jefferyf593b1b2018-08-08 11:01:04 +093038#include "windows.h"
Andrew Jeffery53c21aa2018-03-26 11:56:16 +103039#include "vpnor/mboxd_pnor_partition_table.h"
Cyril Burc85e34d2016-11-15 11:50:41 +110040
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110041#define USAGE \
42"\nUsage: %s [-V | --version] [-h | --help] [-v[v] | --verbose] [-s | --syslog]\n" \
Suraj Jitindar Singhc29172e2017-04-12 14:26:47 +100043"\t\t[-n | --window-num <num>]\n" \
44"\t\t[-w | --window-size <size>M]\n" \
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110045"\t\t-f | --flash <size>[K|M]\n\n" \
46"\t-v | --verbose\t\tBe [more] verbose\n" \
47"\t-s | --syslog\t\tLog output to syslog (pointless without -v)\n" \
48"\t-n | --window-num\tThe number of windows\n" \
Suraj Jitindar Singhc29172e2017-04-12 14:26:47 +100049"\t\t\t\t(default: fill the reserved memory region)\n" \
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110050"\t-w | --window-size\tThe window size (power of 2) in MB\n" \
Suraj Jitindar Singhc29172e2017-04-12 14:26:47 +100051"\t\t\t\t(default: 1MB)\n" \
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110052"\t-f | --flash\t\tSize of flash in [K|M] bytes\n\n"
Cyril Burc85e34d2016-11-15 11:50:41 +110053
Andrew Jefferyfe0c9e82018-11-01 14:02:17 +103054static int dbus_init(struct mbox_context *context,
55 const struct transport_ops **ops)
Andrew Jefferyef9e62d2018-08-08 15:48:27 +093056{
57 int rc;
58
59 rc = sd_bus_default_system(&context->bus);
60 if (rc < 0) {
61 MSG_ERR("Failed to connect to the system bus: %s\n",
62 strerror(-rc));
63 return rc;
64 }
65
66 rc = control_legacy_init(context);
67 if (rc < 0) {
68 MSG_ERR("Failed to initialise legacy DBus interface: %s\n",
69 strerror(-rc));
70 return rc;
71 }
72
73 rc = control_dbus_init(context);
74 if (rc < 0) {
75 MSG_ERR("Failed to initialise DBus control interface: %s\n",
76 strerror(-rc));
77 return rc;
78 }
79
Andrew Jefferyfe0c9e82018-11-01 14:02:17 +103080 rc = transport_dbus_init(context, ops);
Andrew Jeffery23140be2018-09-05 14:15:07 +093081 if (rc < 0) {
82 MSG_ERR("Failed to initialise DBus protocol interface: %s\n",
83 strerror(-rc));
84 return rc;
85 }
86
Andrew Jefferyef9e62d2018-08-08 15:48:27 +093087 rc = sd_bus_request_name(context->bus, MBOX_DBUS_NAME,
88 SD_BUS_NAME_ALLOW_REPLACEMENT |
89 SD_BUS_NAME_REPLACE_EXISTING);
90 if (rc < 0) {
Andrew Jeffery23140be2018-09-05 14:15:07 +093091 MSG_ERR("Failed to request DBus name: %s\n", strerror(-rc));
Andrew Jefferyef9e62d2018-08-08 15:48:27 +093092 return rc;
93 }
94
95 rc = sd_bus_get_fd(context->bus);
96 if (rc < 0) {
97 MSG_ERR("Failed to get bus fd: %s\n", strerror(-rc));
98 return rc;
99 }
100
101 context->fds[DBUS_FD].fd = rc;
102
103 return 0;
104}
105
106static void dbus_free(struct mbox_context *context)
107{
Andrew Jeffery23140be2018-09-05 14:15:07 +0930108 transport_dbus_free(context);
Andrew Jefferyef9e62d2018-08-08 15:48:27 +0930109 control_dbus_free(context);
110 control_legacy_free(context);
111 sd_bus_unref(context->bus);
112}
Andrew Jeffery55f4d6f2018-08-06 12:26:44 +0930113
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100114static int poll_loop(struct mbox_context *context)
Cyril Burc85e34d2016-11-15 11:50:41 +1100115{
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100116 int rc = 0, i;
Cyril Bur46233672017-01-16 13:33:26 +1100117
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100118 /* Set POLLIN on polling file descriptors */
119 for (i = 0; i < POLL_FDS; i++) {
120 context->fds[i].events = POLLIN;
Cyril Bur46233672017-01-16 13:33:26 +1100121 }
122
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100123 while (1) {
124 rc = poll(context->fds, POLL_FDS, -1);
125
126 if (rc < 0) { /* Error */
127 MSG_ERR("Error from poll(): %s\n", strerror(errno));
128 break; /* This should mean we clean up nicely */
129 }
130
131 /* Event on Polled File Descriptor - Handle It */
132 if (context->fds[SIG_FD].revents & POLLIN) { /* Signal */
133 struct signalfd_siginfo info = { 0 };
134
135 rc = read(context->fds[SIG_FD].fd, (void *) &info,
136 sizeof(info));
137 if (rc != sizeof(info)) {
138 MSG_ERR("Error reading signal event: %s\n",
139 strerror(errno));
140 }
141
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000142 MSG_DBG("Received signal: %d\n", info.ssi_signo);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100143 switch (info.ssi_signo) {
144 case SIGINT:
145 case SIGTERM:
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000146 MSG_INFO("Caught Signal - Exiting...\n");
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100147 context->terminate = true;
148 break;
149 case SIGHUP:
150 /* Host didn't request reset -> Notify it */
Andrew Jeffery2ebfd202018-08-20 11:46:28 +0930151 if (windows_reset_all(context)) {
152 rc = protocol_events_set(context,
153 BMC_EVENT_WINDOW_RESET);
154 if (rc < 0) {
155 MSG_ERR("Failed to notify host of reset, expect host-side corruption\n");
156 break;
157 }
158 }
Andrew Jeffery17971e42018-08-08 16:36:10 +0930159 rc = lpc_reset(context);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100160 if (rc < 0) {
161 MSG_ERR("WARNING: Failed to point the "
162 "LPC bus back to flash on "
163 "SIGHUP\nIf the host requires "
164 "this expect problems...\n");
165 }
166 break;
167 default:
168 MSG_ERR("Unhandled Signal: %d\n",
169 info.ssi_signo);
170 break;
171 }
172 }
173 if (context->fds[DBUS_FD].revents & POLLIN) { /* DBUS */
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000174 while ((rc = sd_bus_process(context->bus, NULL)) > 0) {
175 MSG_DBG("DBUS Event\n");
176 }
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100177 if (rc < 0) {
178 MSG_ERR("Error handling DBUS event: %s\n",
179 strerror(-rc));
180 }
181 }
182 if (context->terminate) {
183 break; /* This should mean we clean up nicely */
184 }
185 if (context->fds[MBOX_FD].revents & POLLIN) { /* MBOX */
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000186 MSG_DBG("MBOX Event\n");
Andrew Jefferyd86141b2018-08-09 14:58:53 +0930187 rc = transport_mbox_dispatch(context);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100188 if (rc < 0) {
189 MSG_ERR("Error handling MBOX event\n");
190 }
191 }
192 }
193
Deepak Kodihalli017e45c2017-07-12 01:06:30 -0500194 /* Best to reset windows and the lpc mapping for safety */
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100195 /* Host didn't request reset -> Notify it */
Andrew Jefferyfd4fa342018-11-23 08:33:37 +1100196 windows_reset_all(context);
197
Andrew Jeffery17971e42018-08-08 16:36:10 +0930198 rc = lpc_reset(context);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100199 /* Not much we can do if this fails */
200 if (rc < 0) {
201 MSG_ERR("WARNING: Failed to point the LPC bus back to flash\n"
202 "If the host requires this expect problems...\n");
203 }
204
205 return rc;
Cyril Burc85e34d2016-11-15 11:50:41 +1100206}
207
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100208static int init_signals(struct mbox_context *context, sigset_t *set)
Cyril Burc85e34d2016-11-15 11:50:41 +1100209{
210 int rc;
Cyril Burc85e34d2016-11-15 11:50:41 +1100211
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100212 /* Block SIGHUPs, SIGTERMs and SIGINTs */
213 sigemptyset(set);
214 sigaddset(set, SIGHUP);
215 sigaddset(set, SIGINT);
216 sigaddset(set, SIGTERM);
217 rc = sigprocmask(SIG_BLOCK, set, NULL);
218 if (rc < 0) {
219 MSG_ERR("Failed to set SIG_BLOCK mask %s\n", strerror(errno));
220 return rc;
Cyril Burc85e34d2016-11-15 11:50:41 +1100221 }
222
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100223 /* Get Signal File Descriptor */
224 rc = signalfd(-1, set, SFD_NONBLOCK);
225 if (rc < 0) {
226 MSG_ERR("Failed to get signalfd %s\n", strerror(errno));
227 return rc;
Cyril Burc85e34d2016-11-15 11:50:41 +1100228 }
229
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100230 context->fds[SIG_FD].fd = rc;
Cyril Burc85e34d2016-11-15 11:50:41 +1100231 return 0;
232}
233
Cyril Burc85e34d2016-11-15 11:50:41 +1100234static void usage(const char *name)
235{
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100236 printf(USAGE, name);
Cyril Burc85e34d2016-11-15 11:50:41 +1100237}
238
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100239static bool parse_cmdline(int argc, char **argv,
240 struct mbox_context *context)
Cyril Burc85e34d2016-11-15 11:50:41 +1100241{
Cyril Bure8f2de12017-01-17 16:56:02 +1100242 char *endptr;
Suraj Jitindar Singhc29172e2017-04-12 14:26:47 +1000243 int opt;
Cyril Burc85e34d2016-11-15 11:50:41 +1100244
245 static const struct option long_options[] = {
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100246 { "flash", required_argument, 0, 'f' },
247 { "window-size", optional_argument, 0, 'w' },
248 { "window-num", optional_argument, 0, 'n' },
249 { "verbose", no_argument, 0, 'v' },
250 { "syslog", no_argument, 0, 's' },
251 { "version", no_argument, 0, 'V' },
252 { "help", no_argument, 0, 'h' },
253 { 0, 0, 0, 0 }
Cyril Burc85e34d2016-11-15 11:50:41 +1100254 };
255
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100256 verbosity = MBOX_LOG_NONE;
Cyril Burc85e34d2016-11-15 11:50:41 +1100257 mbox_vlog = &mbox_log_console;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100258
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100259 context->current = NULL; /* No current window */
260
261 while ((opt = getopt_long(argc, argv, "f:w::n::vsVh", long_options, NULL))
262 != -1) {
Cyril Burc85e34d2016-11-15 11:50:41 +1100263 switch (opt) {
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100264 case 0:
265 break;
266 case 'f':
267 context->flash_size = strtol(optarg, &endptr, 10);
268 if (optarg == endptr) {
269 fprintf(stderr, "Unparseable flash size\n");
270 return false;
271 }
272 switch (*endptr) {
273 case '\0':
Cyril Burc85e34d2016-11-15 11:50:41 +1100274 break;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100275 case 'M':
276 context->flash_size <<= 10;
277 case 'K':
278 context->flash_size <<= 10;
Cyril Burc85e34d2016-11-15 11:50:41 +1100279 break;
280 default:
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100281 fprintf(stderr, "Unknown units '%c'\n",
282 *endptr);
283 return false;
284 }
285 break;
286 case 'n':
287 context->windows.num = strtol(argv[optind], &endptr,
288 10);
289 if (optarg == endptr || *endptr != '\0') {
290 fprintf(stderr, "Unparseable window num\n");
291 return false;
292 }
293 break;
294 case 'w':
295 context->windows.default_size = strtol(argv[optind],
296 &endptr, 10);
297 context->windows.default_size <<= 20; /* Given in MB */
298 if (optarg == endptr || (*endptr != '\0' &&
299 *endptr != 'M')) {
300 fprintf(stderr, "Unparseable window size\n");
301 return false;
302 }
Suraj Jitindar Singh0aff80c2017-04-12 14:37:24 +1000303 if (!is_power_of_2(context->windows.default_size)) {
304 fprintf(stderr, "Window size not power of 2\n");
305 return false;
306 }
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100307 break;
308 case 'v':
309 verbosity++;
310 break;
311 case 's':
312 /* Avoid a double openlog() */
313 if (mbox_vlog != &vsyslog) {
314 openlog(PREFIX, LOG_ODELAY, LOG_DAEMON);
315 mbox_vlog = &vsyslog;
316 }
317 break;
318 case 'V':
Suraj Jitindar Singh8d65bb42017-05-01 16:05:17 +1000319 printf("%s V%s\n", THIS_NAME, PACKAGE_VERSION);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100320 exit(0);
321 case 'h':
322 return false; /* This will print the usage message */
323 default:
324 return false;
Cyril Burc85e34d2016-11-15 11:50:41 +1100325 }
326 }
327
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100328 if (!context->flash_size) {
Cyril Bure8f2de12017-01-17 16:56:02 +1100329 fprintf(stderr, "Must specify a non-zero flash size\n");
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100330 return false;
Cyril Bure8f2de12017-01-17 16:56:02 +1100331 }
332
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000333 MSG_INFO("Flash size: 0x%.8x\n", context->flash_size);
Cyril Burc85e34d2016-11-15 11:50:41 +1100334
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100335 if (verbosity) {
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000336 MSG_INFO("%s logging\n", verbosity == MBOX_LOG_DEBUG ? "Debug" :
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100337 "Verbose");
Cyril Burc85e34d2016-11-15 11:50:41 +1100338 }
339
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100340 return true;
Cyril Burc85e34d2016-11-15 11:50:41 +1100341}
342
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100343int main(int argc, char **argv)
344{
Andrew Jefferyfe0c9e82018-11-01 14:02:17 +1030345 const struct transport_ops *mbox_ops, *dbus_ops;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100346 struct mbox_context *context;
347 char *name = argv[0];
348 sigset_t set;
349 int rc, i;
350
351 context = calloc(1, sizeof(*context));
352 if (!context) {
353 fprintf(stderr, "Memory allocation failed\n");
354 exit(1);
355 }
356
357 if (!parse_cmdline(argc, argv, context)) {
358 usage(name);
359 free(context);
360 exit(0);
361 }
362
363 for (i = 0; i < TOTAL_FDS; i++) {
364 context->fds[i].fd = -1;
365 }
366
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000367 MSG_INFO("Starting Daemon\n");
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100368
369 rc = init_signals(context, &set);
370 if (rc) {
371 goto finish;
372 }
373
Andrew Jeffery1e531af2018-08-07 13:32:57 +0930374 rc = protocol_init(context);
375 if (rc) {
376 goto finish;
377 }
378
Andrew Jefferyfe0c9e82018-11-01 14:02:17 +1030379 rc = transport_mbox_init(context, &mbox_ops);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100380 if (rc) {
381 goto finish;
382 }
383
Andrew Jefferycb9b2102018-08-08 16:31:07 +0930384 rc = lpc_dev_init(context);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100385 if (rc) {
386 goto finish;
387 }
388
389 /* We've found the reserved memory region -> we can assign to windows */
Andrew Jefferyc1a67fa2018-08-08 17:07:38 +0930390 rc = windows_init(context);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100391 if (rc) {
392 goto finish;
393 }
394
Andrew Jefferyd6b09bc2018-08-08 16:47:54 +0930395 rc = flash_dev_init(context);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100396 if (rc) {
397 goto finish;
398 }
399
Andrew Jefferyfe0c9e82018-11-01 14:02:17 +1030400 rc = dbus_init(context, &dbus_ops);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100401 if (rc) {
402 goto finish;
403 }
404
Deepak Kodihalli017e45c2017-07-12 01:06:30 -0500405#ifdef VIRTUAL_PNOR_ENABLED
Deepak Kodihalli64ec3e42017-07-17 06:15:16 -0500406 init_vpnor(context);
Deepak Kodihalli017e45c2017-07-12 01:06:30 -0500407#endif
408
409 /* Set the LPC bus mapping */
Andrew Jeffery17971e42018-08-08 16:36:10 +0930410 rc = lpc_reset(context);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100411 if (rc) {
Andrew Jeffery8fe809e2018-05-17 09:54:32 +0930412 MSG_ERR("LPC configuration failed, RESET required: %d\n", rc);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100413 }
414
Andrew Jefferyfe0c9e82018-11-01 14:02:17 +1030415 /* We're ready to go, alert the host */
416 context->bmc_events |= BMC_EVENT_DAEMON_READY;
Andrew Jeffery4c15bb12018-12-05 14:15:28 +1030417 context->bmc_events |= BMC_EVENT_PROTOCOL_RESET;
Andrew Jefferyfe0c9e82018-11-01 14:02:17 +1030418
419 /* Alert on all supported transports */
420 rc = protocol_events_put(context, mbox_ops);
421 if (rc) {
422 goto finish;
423 }
424
425 rc = protocol_events_put(context, dbus_ops);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100426 if (rc) {
427 goto finish;
428 }
429
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000430 MSG_INFO("Entering Polling Loop\n");
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100431 rc = poll_loop(context);
432
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000433 MSG_INFO("Exiting Poll Loop: %d\n", rc);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100434
435finish:
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000436 MSG_INFO("Daemon Exiting...\n");
Andrew Jefferyfe0c9e82018-11-01 14:02:17 +1030437 context->bmc_events &= ~BMC_EVENT_DAEMON_READY;
Andrew Jefferyfab672b2018-11-01 17:12:09 +1030438 context->bmc_events |= BMC_EVENT_PROTOCOL_RESET;
Andrew Jefferyfe0c9e82018-11-01 14:02:17 +1030439
440 /* Alert on all supported transports */
441 protocol_events_put(context, mbox_ops);
442 protocol_events_put(context, dbus_ops);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100443
Andrew Jeffery1e531af2018-08-07 13:32:57 +0930444#ifdef VIRTUAL_PNOR_ENABLED
445 destroy_vpnor(context);
446#endif
Andrew Jefferyef9e62d2018-08-08 15:48:27 +0930447 dbus_free(context);
Andrew Jefferydec6ca62018-08-08 16:49:43 +0930448 flash_dev_free(context);
Andrew Jeffery2e2df282018-08-08 16:32:22 +0930449 lpc_dev_free(context);
Andrew Jeffery55260ce2018-08-09 15:05:59 +0930450 transport_mbox_free(context);
Andrew Jefferyf5f51422018-08-08 17:08:33 +0930451 windows_free(context);
Andrew Jeffery1e531af2018-08-07 13:32:57 +0930452 protocol_free(context);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100453 free(context);
454
455 return rc;
456}