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