1 /*
2 * emu.c
3 *
4 * MontaVista IPMI code for emulating a MC.
5 *
6 * Author: MontaVista Software, Inc.
7 * Corey Minyard <minyard@mvista.com>
8 * source@mvista.com
9 *
10 * Copyright 2003,2012 MontaVista Software Inc.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 2 of
15 * the License, or (at your option) any later version.
16 *
17 *
18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
19 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
24 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
26 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
27 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * You should have received a copy of the GNU Lesser General Public
30 * License along with this program; if not, write to the Free
31 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
32 *
33 * Modified BSD Licence
34 *
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
37 * are met:
38 *
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above
42 * copyright notice, this list of conditions and the following
43 * disclaimer in the documentation and/or other materials provided
44 * with the distribution.
45 * 3. The name of the author may not be used to endorse or promote
46 * products derived from this software without specific prior
47 * written permission.
48 */
49
50 #include "bmc.h"
51
52 #include <string.h>
53 #include <stdlib.h>
54 #include <sys/time.h>
55 #include <stdio.h>
56
57 #include <OpenIPMI/ipmi_err.h>
58 #include <OpenIPMI/ipmi_msgbits.h>
59 #include <OpenIPMI/ipmi_picmg.h>
60 #include <OpenIPMI/ipmi_bits.h>
61 #include <OpenIPMI/ipmi_mc.h>
62 #include <OpenIPMI/ipmi_lan.h>
63 #include <OpenIPMI/extcmd.h>
64
65 static void ipmi_mc_start_cmd(lmc_data_t *mc);
66
67
68 const char *
get_lanserv_version(void)69 get_lanserv_version(void)
70 {
71 return PVERSION;
72 }
73
74 struct {
75 cmd_handler_f handler;
76 void *cb_data;
77 } group_extension_handlers[256];
78
79 void
ipmi_emu_register_group_extension_handler(uint8_t group_extension,cmd_handler_f handler,void * cb_data)80 ipmi_emu_register_group_extension_handler(uint8_t group_extension,
81 cmd_handler_f handler, void *cb_data)
82 {
83 group_extension_handlers[group_extension].handler = handler;
84 group_extension_handlers[group_extension].cb_data = cb_data;
85 }
86
87 static void
handle_group_extension_netfn(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)88 handle_group_extension_netfn(lmc_data_t *mc,
89 msg_t *msg,
90 unsigned char *rdata,
91 unsigned int *rdata_len,
92 void *cb_data)
93 {
94 uint8_t ge;
95
96 if (check_msg_length(msg, 1, rdata, rdata_len))
97 return;
98
99 ge = msg->data[0];
100 if (group_extension_handlers[ge].handler)
101 group_extension_handlers[ge].handler(mc, msg, rdata, rdata_len,
102 group_extension_handlers[ge].cb_data);
103 else
104 handle_invalid_cmd(mc, rdata, rdata_len);
105 }
106
107 static struct iana_handler_elem {
108 uint32_t iana;
109 cmd_handler_f handler;
110 void *cb_data;
111 struct iana_handler_elem *next;
112 } *iana_handlers;
113
find_iana(uint32_t iana)114 static struct iana_handler_elem *find_iana(uint32_t iana)
115 {
116 struct iana_handler_elem *p = iana_handlers;
117
118 while (p) {
119 if (p->iana == iana)
120 return p;
121 p = p->next;
122 }
123 return NULL;
124 }
125
126 int
ipmi_emu_register_iana_handler(uint32_t iana,cmd_handler_f handler,void * cb_data)127 ipmi_emu_register_iana_handler(uint32_t iana, cmd_handler_f handler,
128 void *cb_data)
129 {
130 struct iana_handler_elem *p;
131
132 if (iana > 0xffffff)
133 return EINVAL;
134 if (find_iana(iana))
135 return EAGAIN;
136 p = malloc(sizeof(*p));
137 if (!p)
138 return ENOMEM;
139 p->iana = iana;
140 p->handler = handler;
141 p->cb_data = cb_data;
142 p->next = iana_handlers;
143 iana_handlers = p;
144 return 0;
145 }
146
147 static void
handle_iana_netfn(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)148 handle_iana_netfn(lmc_data_t *mc,
149 msg_t *msg,
150 unsigned char *rdata,
151 unsigned int *rdata_len,
152 void *cb_data)
153 {
154 struct iana_handler_elem *p;
155
156 if (check_msg_length(msg, 3, rdata, rdata_len))
157 return;
158
159 msg->iana = msg->data[0] | (msg->data[1] << 8) | (msg->data[2] << 16);
160 p = find_iana(msg->iana);
161 if (!p) {
162 handle_invalid_cmd(mc, rdata, rdata_len);
163 goto out;
164 }
165
166 /* Remove the IANA */
167 memcpy(msg->data, msg->data + 3, msg->len - 3);
168 msg->len -= 3;
169
170 p->handler(mc, msg, rdata, rdata_len, p->cb_data);
171
172 out:
173 /* Insert the IANA back in. */
174 memcpy(rdata + 4, rdata + 1, *rdata_len);
175 rdata[1] = msg->iana & 0xff;
176 rdata[2] = (msg->iana >> 8) & 0xff;
177 rdata[3] = (msg->iana >> 16) & 0xff;
178 *rdata_len += 3;
179 }
180
181 static struct oi_iana_cmd_elem {
182 uint8_t cmd;
183 cmd_handler_f handler;
184 void *cb_data;
185 struct oi_iana_cmd_elem *next;
186 } *oi_iana_cmds;
187
find_oi_iana(uint8_t cmd)188 static struct oi_iana_cmd_elem *find_oi_iana(uint8_t cmd)
189 {
190 struct oi_iana_cmd_elem *p = oi_iana_cmds;
191
192 while (p) {
193 if (p->cmd == cmd)
194 return p;
195 p = p->next;
196 }
197 return NULL;
198 }
199
handle_oi_iana_cmd(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)200 static void handle_oi_iana_cmd(lmc_data_t *mc,
201 msg_t *msg,
202 unsigned char *rdata,
203 unsigned int *rdata_len,
204 void *cb_data)
205 {
206 struct oi_iana_cmd_elem *p;
207
208 p = find_oi_iana(msg->cmd);
209 if (!p) {
210 handle_invalid_cmd(mc, rdata, rdata_len);
211 return;
212 }
213
214 p->handler(mc, msg, rdata, rdata_len, p->cb_data);
215 }
216
217 int
ipmi_emu_register_oi_iana_handler(uint8_t cmd,cmd_handler_f handler,void * cb_data)218 ipmi_emu_register_oi_iana_handler(uint8_t cmd, cmd_handler_f handler,
219 void *cb_data)
220 {
221 struct oi_iana_cmd_elem *p;
222 int rv;
223
224 if (find_oi_iana(cmd))
225 return EAGAIN;
226 rv = ipmi_emu_register_iana_handler(OPENIPMI_IANA, handle_oi_iana_cmd,
227 NULL);
228 if (rv != 0 && rv != EAGAIN)
229 return rv;
230 p = malloc(sizeof(*p));
231 if (!p)
232 return ENOMEM;
233 p->cmd = cmd;
234 p->handler = handler;
235 p->cb_data = cb_data;
236 p->next = oi_iana_cmds;
237 oi_iana_cmds = p;
238 return 0;
239 }
240
241 static int
check_chassis_capable(lmc_data_t * mc)242 check_chassis_capable(lmc_data_t *mc)
243 {
244 return (mc->device_support & IPMI_DEVID_CHASSIS_DEVICE);
245 }
246
247 typedef struct netfn_handler_s {
248 cmd_handler_f *handlers;
249 void **cb_data;
250 cmd_handler_f main_handler;
251 void *main_handler_cb_data;
252 int (*check_capable)(lmc_data_t *mc);
253 } netfn_handler_t;
254
255 static netfn_handler_t netfn_handlers[32] = {
256 [IPMI_APP_NETFN >> 1] = { .handlers = app_netfn_handlers },
257 [IPMI_STORAGE_NETFN >> 1] = { .handlers = storage_netfn_handlers },
258 [IPMI_CHASSIS_NETFN >> 1] = { .handlers = chassis_netfn_handlers,
259 .check_capable = check_chassis_capable },
260 [IPMI_TRANSPORT_NETFN >> 1] = { .handlers = transport_netfn_handlers },
261 [IPMI_SENSOR_EVENT_NETFN >> 1] = { .handlers = sensor_event_netfn_handlers },
262 [IPMI_GROUP_EXTENSION_NETFN >> 1] = { .main_handler = handle_group_extension_netfn },
263 [IPMI_OEM_GROUP_NETFN >> 1] = { .main_handler = handle_iana_netfn },
264 [0x30 >> 1] = { .handlers = oem0_netfn_handlers }
265 };
266
267 int
ipmi_emu_register_cmd_handler(unsigned char netfn,unsigned char cmd,cmd_handler_f handler,void * cb_data)268 ipmi_emu_register_cmd_handler(unsigned char netfn, unsigned char cmd,
269 cmd_handler_f handler, void *cb_data)
270 {
271 unsigned int ni = netfn >> 1;
272
273 if (ni >= 32)
274 return EINVAL;
275
276 if (!netfn_handlers[ni].handlers) {
277 netfn_handlers[ni].handlers = malloc(256 * sizeof(cmd_handler_f));
278 if (!netfn_handlers[ni].handlers)
279 return ENOMEM;
280 memset(netfn_handlers[ni].handlers, 0, 256 * sizeof(cmd_handler_f));
281 }
282 if (!netfn_handlers[ni].cb_data) {
283 netfn_handlers[ni].cb_data = malloc(256 * sizeof(void *));
284 if (!netfn_handlers[ni].cb_data)
285 return ENOMEM;
286 memset(netfn_handlers[ni].cb_data, 0, 256 * sizeof(void *));
287 }
288
289 netfn_handlers[ni].cb_data[cmd] = cb_data;
290 netfn_handlers[ni].handlers[cmd] = handler;
291 return 0;
292 }
293
294 void
ipmi_emu_tick(emu_data_t * emu,unsigned int seconds)295 ipmi_emu_tick(emu_data_t *emu, unsigned int seconds)
296 {
297 if (emu->atca_fru_inv_locked) {
298 emu->atca_fru_inv_lock_timeout -= seconds;
299 if (emu->atca_fru_inv_lock_timeout < 0) {
300 emu->atca_fru_inv_locked = 0;
301 free(emu->temp_fru_inv_data);
302 emu->temp_fru_inv_data = NULL;
303 }
304 }
305
306 if (emu->users_changed) {
307 emu->users_changed = 0;
308 write_persist_users(emu->sysinfo);
309 }
310 }
311
312 #define IPMI_SEND_MSG_NO_TRACK 0x0
313 #define IPMI_SEND_MSG_TRACK_REQUEST 0x01
314 #define IPMI_SEND_MSG_SEND_RAW 0x2
315 #define IPMI_SEND_MSG_GET_TRACKING(v) ((v >> 6) & 0x3)
316
317 void
ipmi_emu_handle_msg(emu_data_t * emu,lmc_data_t * srcmc,msg_t * omsg,unsigned char * ordata,unsigned int * ordata_len)318 ipmi_emu_handle_msg(emu_data_t *emu,
319 lmc_data_t *srcmc,
320 msg_t *omsg,
321 unsigned char *ordata,
322 unsigned int *ordata_len)
323 {
324 lmc_data_t *mc;
325 msg_t smsg, *rmsg = NULL;
326 msg_t *msg;
327 unsigned char *data = NULL;
328 unsigned char *rdata;
329 unsigned int *rdata_len;
330 channel_t *rchan = omsg->orig_channel;
331
332 if (emu->sysinfo->debug & DEBUG_MSG)
333 emu->sysinfo->log(emu->sysinfo, DEBUG, omsg, "Receive message:");
334 if (omsg->netfn == IPMI_APP_NETFN && omsg->cmd == IPMI_SEND_MSG_CMD) {
335 /* Encapsulated IPMB, do special handling. */
336 unsigned char slave;
337 unsigned int data_len;
338
339 if (check_msg_length(omsg, 8, ordata, ordata_len))
340 return;
341 if ((omsg->data[0] & 0x3f) != 0) {
342 ordata[0] = IPMI_INVALID_DATA_FIELD_CC;
343 *ordata_len = 1;
344 return;
345 }
346
347 switch (IPMI_SEND_MSG_GET_TRACKING(omsg->data[0])) {
348 case IPMI_SEND_MSG_NO_TRACK:
349 rchan = srcmc->channels[15];
350 break;
351 case IPMI_SEND_MSG_TRACK_REQUEST:
352 break;
353 default:
354 ordata[0] = IPMI_INVALID_DATA_FIELD_CC;
355 *ordata_len = 1;
356 return;
357 }
358
359 data = omsg->data + 1;
360 data_len = omsg->len - 1;
361 if (data[0] == 0) {
362 /* Broadcast, just skip the first byte, but check len. */
363 data++;
364 data_len--;
365 if (data_len < 7) {
366 ordata[0] = IPMI_REQUEST_DATA_LENGTH_INVALID_CC;
367 *ordata_len = 1;
368 return;
369 }
370 }
371 slave = data[0];
372 mc = emu->sysinfo->ipmb_addrs[slave];
373 if (!mc || !mc->enabled) {
374 ordata[0] = 0x83; /* NAK on Write */
375 *ordata_len = 1;
376 return;
377 }
378
379 rmsg = malloc(sizeof(*rmsg) + IPMI_SIM_MAX_MSG_LENGTH);
380 if (!rmsg) {
381 ordata[0] = IPMI_OUT_OF_SPACE_CC;
382 *ordata_len = 1;
383 return;
384 }
385
386 *rmsg = *omsg;
387
388 rmsg->data = ((unsigned char *) rmsg) + sizeof(*rmsg);
389 rmsg->len = IPMI_SIM_MAX_MSG_LENGTH - 7; /* header and checksum */
390 rmsg->netfn = (data[1] & 0xfc) >> 2;
391 rmsg->cmd = data[5];
392 rdata = rmsg->data + 6;
393 rdata_len = &rmsg->len;
394 rmsg->data[0] = emu->sysinfo->bmc_ipmb;
395 rmsg->data[1] = ((data[1] & 0xfc) | 0x4) | (data[4] & 0x3);
396 rmsg->data[2] = -ipmb_checksum(rdata+1, 2, 0);
397 rmsg->data[3] = data[0];
398 rmsg->data[4] = (data[4] & 0xfc) | (data[1] & 0x03);
399 rmsg->data[5] = data[5];
400
401 smsg.src_addr = omsg->src_addr;
402 smsg.src_len = omsg->src_len;
403 smsg.netfn = data[1] >> 2;
404 smsg.rs_lun = data[1] & 0x3;
405 smsg.cmd = data[5];
406 smsg.data = data + 6;
407 smsg.len = data_len - 7; /* Subtract off the header and
408 the end checksum */
409 smsg.channel = 0; /* IPMB channel is 0 */
410 smsg.orig_channel = omsg->orig_channel;
411 smsg.sid = omsg->sid;
412 msg = &smsg;
413 } else {
414 mc = srcmc;
415 if (!mc || !mc->enabled) {
416 ordata[0] = 0xff;
417 *ordata_len = 1;
418 return;
419 }
420 rdata = ordata;
421 rdata_len = ordata_len;
422 msg = omsg;
423 }
424
425 if (netfn_handlers[msg->netfn >> 1].check_capable &&
426 !netfn_handlers[msg->netfn >> 1].check_capable(mc))
427 handle_invalid_cmd(mc, rdata, rdata_len);
428 else if (netfn_handlers[msg->netfn >> 1].main_handler)
429 netfn_handlers[msg->netfn >> 1].main_handler(mc, msg, rdata, rdata_len,
430 netfn_handlers[msg->netfn >> 1].main_handler_cb_data);
431 else if (netfn_handlers[msg->netfn >> 1].handlers &&
432 netfn_handlers[msg->netfn >> 1].handlers[msg->cmd]) {
433 void *cb_data = NULL;
434 if (netfn_handlers[msg->netfn >> 1].cb_data)
435 cb_data = netfn_handlers[msg->netfn >> 1].cb_data[msg->cmd];
436 netfn_handlers[msg->netfn >> 1].handlers[msg->cmd](mc, msg, rdata,
437 rdata_len, cb_data);
438 } else
439 handle_invalid_cmd(mc, rdata, rdata_len);
440
441 if (omsg->netfn == IPMI_APP_NETFN && omsg->cmd == IPMI_SEND_MSG_CMD) {
442 /* An encapsulated command, put the response into the receive q. */
443
444 if (rchan->recv_in_q) {
445 if (rchan->recv_in_q(srcmc->channels[15], rmsg))
446 return;
447 }
448
449 ordata[0] = 0;
450 *ordata_len = 1;
451
452 if (emu->sysinfo->debug & DEBUG_MSG)
453 debug_log_raw_msg(emu->sysinfo, rdata, *rdata_len,
454 "Response message:");
455
456 if (!rchan->has_recv_q) {
457 free(rmsg);
458 return;
459 }
460
461 rmsg->len += 6;
462 rmsg->data[rmsg->len] = -ipmb_checksum(rmsg->data, rmsg->len, 0);
463 rmsg->len += 1;
464 if (rchan->recv_q_tail) {
465 rmsg->next = rchan->recv_q_tail;
466 rchan->recv_q_tail = rmsg;
467 } else {
468 rmsg->next = NULL;
469 rchan->recv_q_head = rmsg;
470 rchan->recv_q_tail = rmsg;
471 if (rchan->channel_num == 15) {
472 srcmc->msg_flags |= IPMI_MC_MSG_FLAG_RCV_MSG_QUEUE;
473 if (rchan->set_atn)
474 rchan->set_atn(rchan, 1, IPMI_MC_MSG_INTS_ON(mc));
475 }
476 }
477 } else if (emu->sysinfo->debug & DEBUG_MSG)
478 debug_log_raw_msg(emu->sysinfo, ordata, *ordata_len,
479 "Response message:");
480 }
481
482 void
ipmi_resend_atn(channel_t * chan)483 ipmi_resend_atn(channel_t *chan)
484 {
485 lmc_data_t *mc = chan->mc;
486
487 if (chan->set_atn)
488 chan->set_atn(chan, !!mc->msg_flags, IPMI_MC_MSG_INTS_ON(mc));
489 }
490
491 msg_t *
ipmi_mc_get_next_recv_q(channel_t * chan)492 ipmi_mc_get_next_recv_q(channel_t *chan)
493 {
494 msg_t *rv;
495
496 if (!chan->recv_q_head)
497 return NULL;
498 rv = chan->recv_q_head;
499 chan->recv_q_head = rv->next;
500 if (!chan->recv_q_head) {
501 chan->recv_q_tail = NULL;
502 }
503 return rv;
504 }
505
506 emu_data_t *
ipmi_emu_alloc(void * user_data,ipmi_emu_sleep_cb sleeper,sys_data_t * sysinfo)507 ipmi_emu_alloc(void *user_data, ipmi_emu_sleep_cb sleeper, sys_data_t *sysinfo)
508 {
509 emu_data_t *data = malloc(sizeof(*data));
510
511 if (data) {
512 memset(data, 0, sizeof(*data));
513 data->user_data = user_data;
514 data->sleeper = sleeper;
515 data->sysinfo = sysinfo;
516 }
517
518 return data;
519 }
520
521 int
ipmi_emu_set_addr(emu_data_t * emu,unsigned int addr_num,unsigned char addr_type,void * addr_data,unsigned int addr_len)522 ipmi_emu_set_addr(emu_data_t *emu, unsigned int addr_num,
523 unsigned char addr_type,
524 void *addr_data, unsigned int addr_len)
525 {
526 emu_addr_t *addr;
527
528 if (addr_num >= MAX_EMU_ADDR)
529 return EINVAL;
530
531 addr = &(emu->addr[addr_num]);
532 if (addr_len > sizeof(addr->addr_data))
533 return EINVAL;
534
535 emu->sysinfo->get_monotonic_time(emu->sysinfo, &emu->last_addr_change_time);
536 addr->addr_type = addr_type;
537 memcpy(addr->addr_data, addr_data, addr_len);
538 addr->addr_len = addr_len;
539 addr->valid = 1;
540 return 0;
541 }
542
543 int
ipmi_emu_clear_addr(emu_data_t * emu,unsigned int addr_num)544 ipmi_emu_clear_addr(emu_data_t *emu, unsigned int addr_num)
545 {
546 emu_addr_t *addr;
547
548 if (addr_num >= MAX_EMU_ADDR)
549 return EINVAL;
550
551 addr = &(emu->addr[addr_num]);
552 addr->valid = 0;
553 return 0;
554 }
555
556 void
ipmi_emu_sleep(emu_data_t * emu,struct timeval * time)557 ipmi_emu_sleep(emu_data_t *emu, struct timeval *time)
558 {
559 emu->sleeper(emu, time);
560 }
561
562 void *
ipmi_emu_get_user_data(emu_data_t * emu)563 ipmi_emu_get_user_data(emu_data_t *emu)
564 {
565 return emu->user_data;
566 }
567
568 void
ipmi_mc_destroy(lmc_data_t * mc)569 ipmi_mc_destroy(lmc_data_t *mc)
570 {
571 sel_entry_t *entry, *n_entry;
572
573 entry = mc->sel.entries;
574 while (entry) {
575 n_entry = entry->next;
576 free(entry);
577 entry = n_entry;
578 }
579 free(mc);
580 }
581
582 int
ipmi_emu_set_mc_guid(lmc_data_t * mc,unsigned char guid[16],int force)583 ipmi_emu_set_mc_guid(lmc_data_t *mc,
584 unsigned char guid[16],
585 int force)
586 {
587 if (force || !mc->guid_set)
588 memcpy(mc->guid, guid, 16);
589 mc->guid_set = 1;
590 return 0;
591 }
592
593 void
ipmi_mc_disable(lmc_data_t * mc)594 ipmi_mc_disable(lmc_data_t *mc)
595 {
596 mc->enabled = 0;
597 }
598
599 void
ipmi_mc_enable(lmc_data_t * mc)600 ipmi_mc_enable(lmc_data_t *mc)
601 {
602 unsigned int i;
603 sys_data_t *sys = mc->sysinfo;
604
605 mc->enabled = 1;
606
607 for (i = 0; i < IPMI_MAX_CHANNELS; i++) {
608 channel_t *chan = mc->channels[i];
609 int err = 0;
610
611 if (!chan)
612 continue;
613
614 chan->smi_send = sys->csmi_send;
615 chan->oem.user_data = sys->info;
616 chan->alloc = sys->calloc;
617 chan->free = sys->cfree;
618 chan->log = sys->clog;
619 chan->mc = mc;
620
621 if (chan->medium_type == IPMI_CHANNEL_MEDIUM_8023_LAN)
622 err = sys->lan_channel_init(sys->info, chan);
623 else if (chan->medium_type == IPMI_CHANNEL_MEDIUM_RS232)
624 err = sys->ser_channel_init(sys->info, chan);
625 else if ((chan->medium_type == IPMI_CHANNEL_MEDIUM_IPMB) &&
626 ((chan->channel_num != 0) || (chan->prim_ipmb_in_cfg_file)))
627 err = sys->ipmb_channel_init(sys->info, chan);
628 else
629 chan_init(chan);
630 if (err) {
631 chan->log(chan, SETUP_ERROR, NULL,
632 "Unable to initialize channel for "
633 "IPMB 0x%2.2x, channel %d: %d",
634 mc->ipmb, chan->channel_num, err);
635 }
636 }
637
638 if (mc->startcmd.startnow && mc->startcmd.startcmd)
639 ipmi_mc_start_cmd(mc);
640 }
641
642 int
ipmi_mc_set_num_leds(lmc_data_t * mc,unsigned int count)643 ipmi_mc_set_num_leds(lmc_data_t *mc,
644 unsigned int count)
645 {
646 if (count > MAX_LEDS)
647 return EINVAL;
648 if (mc->emu->atca_mode && (count < MIN_ATCA_LEDS))
649 return EINVAL;
650
651 mc->num_leds = count;
652 return 0;
653 }
654
655 static int
init_mc(emu_data_t * emu,lmc_data_t * mc,unsigned int persist_sdr)656 init_mc(emu_data_t *emu, lmc_data_t *mc, unsigned int persist_sdr)
657 {
658 int err;
659
660 err = mc->sysinfo->alloc_timer(mc->sysinfo, watchdog_timeout,
661 mc, &mc->watchdog_timer);
662 if (err)
663 return err;
664
665 if (persist_sdr && mc->has_device_sdrs) {
666 read_mc_sdrs(mc, &mc->device_sdrs[0], "device0");
667 read_mc_sdrs(mc, &mc->device_sdrs[1], "device1");
668 read_mc_sdrs(mc, &mc->device_sdrs[2], "device2");
669 read_mc_sdrs(mc, &mc->device_sdrs[3], "device3");
670 }
671
672 if (persist_sdr && (mc->device_support & IPMI_DEVID_SDR_REPOSITORY_DEV))
673 read_mc_sdrs(mc, &mc->main_sdrs, "main");
674
675 return err;
676 }
677
678 static void
ipmi_mc_start_cmd(lmc_data_t * mc)679 ipmi_mc_start_cmd(lmc_data_t *mc)
680 {
681 if (!mc->startcmd.startcmd) {
682 mc->sysinfo->log(mc->sysinfo, OS_ERROR, NULL,
683 "Power on issued, no start command set");
684 return;
685 }
686
687 if (mc->startcmd.vmpid) {
688 /* Already running */
689
690 /* If we are waiting for a poweroff, disable that. */
691 if (mc->startcmd.wait_poweroff)
692 mc->startcmd.wait_poweroff = 0;
693 return;
694 }
695
696 ipmi_do_start_cmd(&mc->startcmd);
697 }
698
699 static void
chan_start_cmd(channel_t * chan)700 chan_start_cmd(channel_t *chan)
701 {
702 ipmi_mc_start_cmd(chan->mc);
703 }
704
705 static void
ipmi_mc_stop_cmd(lmc_data_t * mc,int do_it_now)706 ipmi_mc_stop_cmd(lmc_data_t *mc, int do_it_now)
707 {
708 if (mc->startcmd.wait_poweroff || !mc->startcmd.vmpid)
709 /* Already powering/powered off. */
710 return;
711 if (!do_it_now)
712 mc->startcmd.wait_poweroff = mc->startcmd.poweroff_wait_time;
713 else
714 mc->startcmd.wait_poweroff = 1; /* Just power off now. */
715 }
716
717 static void
chan_stop_cmd(channel_t * chan,int do_it_now)718 chan_stop_cmd(channel_t *chan, int do_it_now)
719 {
720 ipmi_mc_stop_cmd(chan->mc, do_it_now);
721 }
722
723 channel_t **
ipmi_mc_get_channelset(lmc_data_t * mc)724 ipmi_mc_get_channelset(lmc_data_t *mc)
725 {
726 return mc->channels;
727 }
728
729 ipmi_sol_t *
ipmi_mc_get_sol(lmc_data_t * mc)730 ipmi_mc_get_sol(lmc_data_t *mc)
731 {
732 return &mc->sol;
733 }
734
735 unsigned char
ipmi_mc_get_ipmb(lmc_data_t * mc)736 ipmi_mc_get_ipmb(lmc_data_t *mc)
737 {
738 return mc->ipmb;
739 }
740
741 int
ipmi_mc_users_changed(lmc_data_t * mc)742 ipmi_mc_users_changed(lmc_data_t *mc)
743 {
744 int rv = mc->users_changed;
745 mc->users_changed = 0;
746 return rv;
747 }
748
749 user_t *
ipmi_mc_get_users(lmc_data_t * mc)750 ipmi_mc_get_users(lmc_data_t *mc)
751 {
752 return mc->users;
753 }
754
755 pef_data_t *
ipmi_mc_get_pef(lmc_data_t * mc)756 ipmi_mc_get_pef(lmc_data_t *mc)
757 {
758 return &mc->pef;
759 }
760
761 startcmd_t *
ipmi_mc_get_startcmdinfo(lmc_data_t * mc)762 ipmi_mc_get_startcmdinfo(lmc_data_t *mc)
763 {
764 return &mc->startcmd;
765 }
766
767 int
ipmi_mc_alloc_unconfigured(sys_data_t * sys,unsigned char ipmb,lmc_data_t ** rmc)768 ipmi_mc_alloc_unconfigured(sys_data_t *sys, unsigned char ipmb,
769 lmc_data_t **rmc)
770 {
771 lmc_data_t *mc;
772 unsigned int i;
773
774 mc = sys->ipmb_addrs[ipmb];
775 if (mc) {
776 if (mc->configured) {
777 sys->log(sys, SETUP_ERROR, NULL,
778 "MC IPMB specified twice: 0x%x.", ipmb);
779 return EBUSY;
780 }
781 goto out;
782 }
783
784 mc = malloc(sizeof(*mc));
785 if (!mc)
786 return ENOMEM;
787 memset(mc, 0, sizeof(*mc));
788 mc->ipmb = ipmb;
789 sys->ipmb_addrs[ipmb] = mc;
790
791 mc->startcmd.poweroff_wait_time = 60;
792 mc->startcmd.kill_wait_time = 20;
793 mc->startcmd.startnow = 0;
794
795 for (i=0; i<=MAX_USERS; i++) {
796 mc->users[i].idx = i;
797 }
798
799 mc->pef.num_event_filters = MAX_EVENT_FILTERS;
800 for (i=0; i<MAX_EVENT_FILTERS; i++) {
801 mc->pef.event_filter_table[i][0] = i;
802 mc->pef.event_filter_data1[i][0] = i;
803 }
804 mc->pef.num_alert_policies = MAX_ALERT_POLICIES;
805 for (i=0; i<MAX_ALERT_POLICIES; i++)
806 mc->pef.alert_policy_table[i][0] = i;
807 mc->pef.num_alert_strings = MAX_ALERT_STRINGS;
808 for (i=0; i<MAX_ALERT_STRINGS; i++) {
809 mc->pef.alert_string_keys[i][0] = i;
810 }
811
812 mc->ipmb_channel.medium_type = IPMI_CHANNEL_MEDIUM_IPMB;
813 mc->ipmb_channel.channel_num = 0;
814 mc->ipmb_channel.protocol_type = IPMI_CHANNEL_PROTOCOL_IPMB;
815 mc->ipmb_channel.session_support = IPMI_CHANNEL_SESSION_LESS;
816 mc->ipmb_channel.active_sessions = 0;
817 mc->ipmb_channel.prim_ipmb_in_cfg_file = 0;
818 mc->channels[0] = &mc->ipmb_channel;
819 mc->channels[0]->log = sys->clog;
820
821 out:
822 *rmc = mc;
823 return 0;
824 }
825
826 void
handle_invalid_cmd(lmc_data_t * mc,unsigned char * rdata,unsigned int * rdata_len)827 handle_invalid_cmd(lmc_data_t *mc,
828 unsigned char *rdata,
829 unsigned int *rdata_len)
830 {
831 rdata[0] = IPMI_INVALID_CMD_CC;
832 *rdata_len = 1;
833 }
834
835 int
check_msg_length(msg_t * msg,unsigned int len,unsigned char * rdata,unsigned int * rdata_len)836 check_msg_length(msg_t *msg,
837 unsigned int len,
838 unsigned char *rdata,
839 unsigned int *rdata_len)
840 {
841 if (msg->len < len) {
842 rdata[0] = IPMI_REQUEST_DATA_LENGTH_INVALID_CC;
843 *rdata_len = 1;
844 return 1;
845 }
846
847 return 0;
848 }
849
850 static void
handle_tick(void * info,unsigned int seconds)851 handle_tick(void *info, unsigned int seconds)
852 {
853 lmc_data_t *mc = info;
854
855 if (mc->startcmd.wait_poweroff) {
856 if (mc->startcmd.wait_poweroff > 0) {
857 /* Waiting for the first kill */
858 mc->startcmd.wait_poweroff--;
859 if (mc->startcmd.wait_poweroff == 0) {
860 if (mc->startcmd.vmpid)
861 ipmi_do_kill(&mc->startcmd, 0);
862 mc->startcmd.wait_poweroff = -mc->startcmd.kill_wait_time;
863 }
864 } else {
865 mc->startcmd.wait_poweroff++;
866 if (mc->startcmd.wait_poweroff == 0 && mc->startcmd.vmpid)
867 ipmi_do_kill(&mc->startcmd, 1);
868 }
869 }
870 }
871
872 static void
handle_child_quit(void * info,pid_t pid)873 handle_child_quit(void *info, pid_t pid)
874 {
875 lmc_data_t *mc = info;
876
877 if (mc->startcmd.vmpid == pid) {
878 mc->startcmd.vmpid = 0;
879 mc->startcmd.wait_poweroff = 0;
880 }
881 }
882
883 int
ipmi_emu_add_mc(emu_data_t * emu,unsigned char ipmb,unsigned char device_id,unsigned char has_device_sdrs,unsigned char device_revision,unsigned char major_fw_rev,unsigned char minor_fw_rev,unsigned char device_support,unsigned char mfg_id[3],unsigned char product_id[2],unsigned int flags)884 ipmi_emu_add_mc(emu_data_t *emu,
885 unsigned char ipmb,
886 unsigned char device_id,
887 unsigned char has_device_sdrs,
888 unsigned char device_revision,
889 unsigned char major_fw_rev,
890 unsigned char minor_fw_rev,
891 unsigned char device_support,
892 unsigned char mfg_id[3],
893 unsigned char product_id[2],
894 unsigned int flags)
895 {
896 lmc_data_t *mc;
897 struct timeval t;
898 int i;
899 sys_data_t *sys = emu->sysinfo;
900
901 i = ipmi_mc_alloc_unconfigured(sys, ipmb, &mc);
902 if (i)
903 return i;
904
905 mc->sysinfo = sys;
906 mc->emu = emu;
907 mc->ipmb = ipmb;
908
909 mc->device_id = device_id;
910 mc->has_device_sdrs = has_device_sdrs;
911 mc->device_revision = device_revision;
912 mc->major_fw_rev = major_fw_rev;
913 mc->minor_fw_rev = minor_fw_rev;
914 mc->device_support = device_support;
915 mc->dynamic_sensor_population = flags & IPMI_MC_DYNAMIC_SENSOR_POPULATION;
916 memcpy(mc->mfg_id, mfg_id, 3);
917 memcpy(mc->product_id, product_id, 2);
918
919 /* Enable the event log by default. */
920 mc->global_enables = 1 << IPMI_MC_EVENT_LOG_BIT;
921
922 /* Start the time at zero. */
923 emu->sysinfo->get_monotonic_time(emu->sysinfo, &t);
924 mc->sel.time_offset = 0;
925 mc->main_sdrs.time_offset = 0;
926 mc->main_sdrs.next_entry = 1;
927 mc->main_sdrs.flags |= IPMI_SDR_RESERVE_SDR_SUPPORTED;
928 for (i=0; i<4; i++) {
929 mc->device_sdrs[i].time_offset = 0;
930 mc->device_sdrs[i].next_entry = 1;
931 }
932
933 mc->event_receiver = sys->bmc_ipmb;
934 mc->event_receiver_lun = 0;
935
936 mc->hs_sensor = NULL;
937
938 if (emu->atca_mode) {
939 mc->num_leds = 2;
940
941 /* By default only blue LED has local control. */
942 mc->leds[0].loc_cnt = 1;
943 mc->leds[0].loc_cnt_sup = 1;
944
945 mc->leds[0].def_loc_cnt_color = 1; /* Blue LED */
946 mc->leds[0].def_override_color = 1;
947 mc->leds[0].color_sup = 0x2;
948 mc->leds[0].color = 0x1;
949
950 for (i=1; i<MAX_LEDS; i++) {
951 /* Others default to red */
952 mc->leds[i].def_loc_cnt_color = 2;
953 mc->leds[i].def_override_color = 2;
954 mc->leds[i].color_sup = 0x2;
955 mc->leds[i].color = 0x2;
956 }
957 }
958
959 if (ipmb == emu->sysinfo->bmc_ipmb) {
960 int rv;
961
962 if (!mc->channels[15]) {
963 /* No one specified a system channel, make one up */
964 mc->sys_channel.medium_type = IPMI_CHANNEL_MEDIUM_SYS_INTF;
965 mc->sys_channel.channel_num = 15;
966 mc->sys_channel.protocol_type = IPMI_CHANNEL_PROTOCOL_KCS;
967 mc->sys_channel.session_support = IPMI_CHANNEL_SESSION_LESS;
968 mc->sys_channel.active_sessions = 0;
969 mc->channels[15] = &mc->sys_channel;
970 }
971
972 mc->channels[15]->has_recv_q = 1;
973 mc->sysinfo = emu->sysinfo;
974 rv = init_mc(emu, mc, flags & IPMI_MC_PERSIST_SDR);
975 if (rv) {
976 free(mc);
977 return rv;
978 }
979 }
980
981 if (mc->startcmd.startcmd) {
982 mc->child_quit_handler.info = mc;
983 mc->child_quit_handler.handler = handle_child_quit;
984 ipmi_register_child_quit_handler(&mc->child_quit_handler);
985 mc->tick_handler.info = mc;
986 mc->tick_handler.handler = handle_tick;
987 ipmi_register_tick_handler(&mc->tick_handler);
988 mc->channels[15]->start_cmd = chan_start_cmd;
989 mc->channels[15]->stop_cmd = chan_stop_cmd;
990 }
991
992 mc->configured = 1;
993
994 return 0;
995 }
996
997 void
ipmi_mc_set_device_id(lmc_data_t * mc,unsigned char device_id)998 ipmi_mc_set_device_id(lmc_data_t *mc, unsigned char device_id)
999 {
1000 mc->device_id = device_id;
1001 }
1002
1003 unsigned char
ipmi_mc_get_device_id(lmc_data_t * mc)1004 ipmi_mc_get_device_id(lmc_data_t *mc)
1005 {
1006 return mc->device_id;
1007 }
1008
1009 void
ipmi_set_has_device_sdrs(lmc_data_t * mc,unsigned char has_device_sdrs)1010 ipmi_set_has_device_sdrs(lmc_data_t *mc, unsigned char has_device_sdrs)
1011 {
1012 mc->has_device_sdrs = has_device_sdrs;
1013 }
1014
1015 unsigned char
ipmi_get_has_device_sdrs(lmc_data_t * mc)1016 ipmi_get_has_device_sdrs(lmc_data_t *mc)
1017 {
1018 return mc->has_device_sdrs;
1019 }
1020
1021 void
ipmi_set_device_revision(lmc_data_t * mc,unsigned char device_revision)1022 ipmi_set_device_revision(lmc_data_t *mc, unsigned char device_revision)
1023 {
1024 mc->device_revision = device_revision;
1025 }
1026
1027 unsigned char
ipmi_get_device_revision(lmc_data_t * mc)1028 ipmi_get_device_revision(lmc_data_t *mc)
1029 {
1030 return mc->device_revision;
1031 }
1032
1033 void
ipmi_set_major_fw_rev(lmc_data_t * mc,unsigned char major_fw_rev)1034 ipmi_set_major_fw_rev(lmc_data_t *mc, unsigned char major_fw_rev)
1035 {
1036 mc->major_fw_rev = major_fw_rev;
1037 }
1038
1039 unsigned char
ipmi_get_major_fw_rev(lmc_data_t * mc)1040 ipmi_get_major_fw_rev(lmc_data_t *mc)
1041 {
1042 return mc->major_fw_rev;
1043 }
1044
1045 void
ipmi_set_minor_fw_rev(lmc_data_t * mc,unsigned char minor_fw_rev)1046 ipmi_set_minor_fw_rev(lmc_data_t *mc, unsigned char minor_fw_rev)
1047 {
1048 mc->minor_fw_rev = minor_fw_rev;
1049 }
1050
1051 unsigned char
ipmi_get_minor_fw_rev(lmc_data_t * mc)1052 ipmi_get_minor_fw_rev(lmc_data_t *mc)
1053 {
1054 return mc->minor_fw_rev;
1055 }
1056
1057 void
ipmi_set_device_support(lmc_data_t * mc,unsigned char device_support)1058 ipmi_set_device_support(lmc_data_t *mc, unsigned char device_support)
1059 {
1060 mc->device_support = device_support;
1061 }
1062
1063 unsigned char
ipmi_get_device_support(lmc_data_t * mc)1064 ipmi_get_device_support(lmc_data_t *mc)
1065 {
1066 return mc->device_support;
1067 }
1068
1069 void
ipmi_set_mfg_id(lmc_data_t * mc,unsigned char mfg_id[3])1070 ipmi_set_mfg_id(lmc_data_t *mc, unsigned char mfg_id[3])
1071 {
1072 memcpy(mc->mfg_id, mfg_id, 3);
1073 }
1074
1075 void
ipmi_get_mfg_id(lmc_data_t * mc,unsigned char mfg_id[3])1076 ipmi_get_mfg_id(lmc_data_t *mc, unsigned char mfg_id[3])
1077 {
1078 memcpy(mfg_id, mc->mfg_id, 3);
1079 }
1080
1081 void
ipmi_set_product_id(lmc_data_t * mc,unsigned char product_id[2])1082 ipmi_set_product_id(lmc_data_t *mc, unsigned char product_id[2])
1083 {
1084 memcpy(mc->product_id, product_id, 2);
1085 }
1086
1087 void
ipmi_set_chassis_control_prog(lmc_data_t * mc,const char * prog)1088 ipmi_set_chassis_control_prog(lmc_data_t *mc, const char *prog)
1089 {
1090 mc->chassis_control_prog = prog;
1091 }
1092
1093 void
ipmi_mc_set_chassis_control_func(lmc_data_t * mc,int (* set)(lmc_data_t * mc,int op,unsigned char * val,void * cb_data),int (* get)(lmc_data_t * mc,int op,unsigned char * val,void * cb_data),void * cb_data)1094 ipmi_mc_set_chassis_control_func(lmc_data_t *mc,
1095 int (*set)(lmc_data_t *mc, int op,
1096 unsigned char *val,
1097 void *cb_data),
1098 int (*get)(lmc_data_t *mc, int op,
1099 unsigned char *val,
1100 void *cb_data),
1101 void *cb_data)
1102 {
1103 mc->chassis_control_set_func = set;
1104 mc->chassis_control_get_func = get;
1105 mc->chassis_control_cb_data = cb_data;
1106 }
1107
1108 void
ipmi_get_product_id(lmc_data_t * mc,unsigned char product_id[2])1109 ipmi_get_product_id(lmc_data_t *mc, unsigned char product_id[2])
1110 {
1111 memcpy(product_id, mc->product_id, 2);
1112 }
1113
1114 int
ipmi_emu_get_mc_by_addr(emu_data_t * emu,unsigned char ipmb,lmc_data_t ** mc)1115 ipmi_emu_get_mc_by_addr(emu_data_t *emu, unsigned char ipmb, lmc_data_t **mc)
1116 {
1117 if (!emu->sysinfo->ipmb_addrs[ipmb])
1118 return ENOSYS;
1119 *mc = emu->sysinfo->ipmb_addrs[ipmb];
1120 return 0;
1121 }
1122
1123 int
ipmi_emu_set_bmc_mc(emu_data_t * emu,unsigned char ipmb)1124 ipmi_emu_set_bmc_mc(emu_data_t *emu, unsigned char ipmb)
1125 {
1126 lmc_data_t *mc;
1127
1128 if (ipmb & 1)
1129 return EINVAL;
1130 emu->sysinfo->bmc_ipmb = ipmb;
1131 if (!ipmi_emu_get_mc_by_addr(emu, ipmb, &mc))
1132 mc->sysinfo = emu->sysinfo;
1133 return 0;
1134 }
1135
1136 lmc_data_t *
ipmi_emu_get_bmc_mc(emu_data_t * emu)1137 ipmi_emu_get_bmc_mc(emu_data_t *emu)
1138 {
1139 lmc_data_t *mc;
1140
1141 if (!ipmi_emu_get_mc_by_addr(emu, emu->sysinfo->bmc_ipmb, &mc))
1142 return mc;
1143 return NULL;
1144 }
1145
1146 void
emu_set_debug_level(emu_data_t * emu,unsigned int debug_level)1147 emu_set_debug_level(emu_data_t *emu, unsigned int debug_level)
1148 {
1149 emu->sysinfo->debug = debug_level;
1150 }
1151