1 /*
2  * serial_ipmi.c
3  *
4  * MontaVista IPMI LAN server serial port interface.
5  *
6  * Author: MontaVista Software, Inc.
7  *         Corey Minyard <minyard@mvista.com>
8  *         source@mvista.com
9  *
10  * Copyright 2012 MontaVista Software Inc.
11  *
12  * This software is available to you under a choice of one of two
13  * licenses.  You may choose to be licensed under the terms of the GNU
14  * Lesser General Public License (GPL) Version 2 or the modified BSD
15  * license below.  The following disclamer applies to both licenses:
16  *
17  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
18  *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
23  *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
25  *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
26  *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * GNU Lesser General Public Licence
29  *
30  *  This program is free software; you can redistribute it and/or
31  *  modify it under the terms of the GNU Lesser General Public License
32  *  as published by the Free Software Foundation; either version 2 of
33  *  the License, or (at your option) any later version.
34  *
35  *  You should have received a copy of the GNU Lesser General Public
36  *  License along with this program; if not, write to the Free
37  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
38  *
39  * Modified BSD Licence
40  *
41  * Redistribution and use in source and binary forms, with or without
42  * modification, are permitted provided that the following conditions
43  * are met:
44  *
45  *   1. Redistributions of source code must retain the above copyright
46  *      notice, this list of conditions and the following disclaimer.
47  *   2. Redistributions in binary form must reproduce the above
48  *      copyright notice, this list of conditions and the following
49  *      disclaimer in the documentation and/or other materials provided
50  *      with the distribution.
51  *   3. The name of the author may not be used to endorse or promote
52  *      products derived from this software without specific prior
53  *      written permission.
54  */
55 
56 #include <ctype.h>
57 #include <string.h>
58 #include <stdlib.h>
59 #include <unistd.h>
60 #include <errno.h>
61 #include <sys/types.h>
62 #include <sys/wait.h>
63 #include <OpenIPMI/ipmi_mc.h>
64 #include <OpenIPMI/ipmi_msgbits.h>
65 #include <OpenIPMI/serserv.h>
66 
67 #define EVENT_BUFFER_GLOBAL_ENABLE	(1 << 2)
68 #define EVENT_LOG_GLOBAL_ENABLE		(1 << 3)
69 #define SUPPORTED_GLOBAL_ENABLES	(EVENT_BUFFER_GLOBAL_ENABLE | \
70 					 EVENT_LOG_GLOBAL_ENABLE)
71 
72 static void
raw_send(serserv_data_t * si,unsigned char * data,unsigned int len)73 raw_send(serserv_data_t *si, unsigned char *data, unsigned int len)
74 {
75     if (si->sysinfo->debug & DEBUG_RAW_MSG)
76 	debug_log_raw_msg(si->sysinfo, data, len, "Raw serial send:");
77     si->send_out(si, data, len);
78 }
79 
80 static unsigned char hex2char[16] = {
81     '0', '1', '2', '3', '4', '5', '6', '7',
82     '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
83 };
84 
fromhex(unsigned char c)85 static int fromhex(unsigned char c)
86 {
87     if (isdigit(c))
88 	return c - '0';
89     else if (isxdigit(c))
90 	return tolower(c) - 'a' + 10;
91     else
92 	return -1;
93 }
94 
95 static int
unformat_ipmb_msg(msg_t * msg,unsigned char * msgd,unsigned int len,serserv_data_t * si)96 unformat_ipmb_msg(msg_t *msg, unsigned char *msgd, unsigned int len,
97 		  serserv_data_t *si)
98 {
99     if (len < 7) {
100 	fprintf(stderr, "Message too short\n");
101 	return -1;
102     }
103 
104     if (ipmb_checksum(msgd, len, 0) != 0) {
105 	fprintf(stderr, "Message checksum failure\n");
106 	return -1;
107     }
108     len--;
109 
110     msg->rs_addr = msgd[0];
111     msg->netfn = msgd[1] >> 2;
112     msg->rs_lun = msgd[1] & 3;
113     msg->rq_addr = msgd[3];
114     msg->rq_seq = msgd[4] >> 2;
115     msg->rq_lun = msgd[4] & 3;
116     msg->cmd = msgd[5];
117 
118     msg->len = len - 6;
119     msg->data = msgd + 6;
120 
121     msg->src_addr = NULL;
122     msg->src_len = 0;
123 
124     return 0;
125 }
126 
127 static void
format_ipmb_rsp(msg_t * msg,unsigned char * msgd,unsigned int * msgd_len,serserv_data_t * mi)128 format_ipmb_rsp(msg_t *msg, unsigned char *msgd,
129 		unsigned int *msgd_len, serserv_data_t *mi)
130 {
131     msgd[0] = msg->rs_addr;
132     msgd[1] = (msg->netfn << 2) | msg->rs_lun;
133     msgd[2] = -ipmb_checksum(msgd, 2, 0);
134     msgd[3] = msg->rq_addr;
135     msgd[4] = (msg->rq_seq << 2) | msg->rq_lun;
136     msgd[5] = msg->cmd;
137     memcpy(msgd + 6, msg->data, msg->len);
138     *msgd_len = msg->len + 6;
139     msgd[*msgd_len] = -ipmb_checksum(msgd + 3, (*msgd_len) - 3, 0);
140     (*msgd_len)++;
141 }
142 
handle_attn(channel_t * chan,int val,int irq)143 static void handle_attn(channel_t *chan, int val, int irq)
144 {
145     serserv_data_t *si = chan->chan_info;
146 
147     if (val && si->do_attn)
148 	raw_send(si, si->attn_chars, si->attn_chars_len);
149 }
150 
151 /***********************************************************************
152  *
153  * Radisys ASCII codec.
154  *
155  ***********************************************************************/
156 
157 #define RA_MAX_CHARS_SIZE (((IPMI_SIM_MAX_MSG_LENGTH + 1) * 3) + 4)
158 
159 struct ra_data {
160     unsigned char recv_chars[RA_MAX_CHARS_SIZE];
161     unsigned int  recv_chars_len;
162     int           recv_chars_too_many;
163 };
164 
ra_format_msg(const unsigned char * msg,unsigned int msg_len,serserv_data_t * si)165 static void ra_format_msg(const unsigned char *msg, unsigned int msg_len,
166 			  serserv_data_t *si)
167 {
168     unsigned int i;
169     unsigned int len;
170     unsigned char c[RA_MAX_CHARS_SIZE];
171 
172     len = 0;
173     for (i = 0; i < msg_len; i++) {
174 	c[len] = hex2char[msg[i] >> 4];
175 	len++;
176 	c[len] = hex2char[msg[i] & 0xf];
177 	len++;
178     }
179     c[len] = 0x0d;
180     len++;
181 
182     raw_send(si, c, len);
183 }
184 
185 static int
ra_ipmb_handler(channel_t * chan,msg_t * msg)186 ra_ipmb_handler(channel_t *chan, msg_t *msg)
187 {
188     serserv_data_t *si = chan->chan_info;
189 
190     ra_format_msg(msg->data, msg->len, si);
191     free(msg);
192     return 1;
193 }
194 
195 /*
196  * Called when the '0x0d' is seen.
197  */
ra_unformat_msg(unsigned char * r,unsigned int len,serserv_data_t * si)198 static int ra_unformat_msg(unsigned char *r, unsigned int len,
199 			   serserv_data_t *si)
200 {
201     unsigned char real_o[IPMI_SIM_MAX_MSG_LENGTH + 1];
202     unsigned char *o = real_o + 1;
203     msg_t msg;
204     unsigned int p = 0;
205     unsigned int i = 0;
206     int          rv;
207 
208     if (si->sysinfo->debug & DEBUG_RAW_MSG)
209 	debug_log_raw_msg(si->sysinfo, r, len, "Raw serial receive:");
210 
211     while (p < len) {
212 	rv = fromhex(r[p]);
213 	if (rv < 0)
214 	    return rv;
215 	o[i] = rv << 4;
216 	p++;
217 	if (p >= len)
218 	    return -1;
219 	rv = fromhex(r[p]);
220 	if (rv < 0)
221 	    return rv;
222 	o[i] |= rv;
223 	p++;
224 	i++;
225     }
226 
227     if (i < 1)
228 	return -1;
229 
230     memset(&msg, 0, sizeof(msg));
231     if ((o[0] == si->sysinfo->bmc_ipmb) || (o[0] == 1)) {
232 	rv = unformat_ipmb_msg(&msg, o, i, si);
233 	if (rv)
234 	    return rv;
235     } else {
236 	msg.rs_addr = 1;
237 	msg.netfn = IPMI_APP_NETFN;
238 	msg.rs_lun = 0;
239 	msg.rq_addr = 1;
240 	msg.rq_seq = 0;
241 	msg.rq_lun = 0;
242 	msg.cmd = IPMI_SEND_MSG_CMD;
243 
244 	msg.len = i + 1;
245 	msg.data = real_o;
246 	real_o[0] = 0;
247     }
248     channel_smi_send(&si->channel, &msg);
249     return 0;
250 }
251 
252 static void
ra_handle_char(unsigned char ch,serserv_data_t * si)253 ra_handle_char(unsigned char ch, serserv_data_t *si)
254 {
255     struct ra_data *info = si->codec_info;
256     unsigned int len = info->recv_chars_len;
257     unsigned char *r;
258     int           rv;
259 
260     if (ch == 0x0d) {
261 	/* End of command, handle it. */
262 	if (info->recv_chars_too_many) {
263 	    /* Input data overrun. */
264 	    fprintf(stderr, "Data overrun\n");
265 	    info->recv_chars_too_many = 0;
266 	    info->recv_chars_len = 0;
267 	    return;
268 	}
269 	rv = ra_unformat_msg(info->recv_chars, info->recv_chars_len, si);
270 	info->recv_chars_too_many = 0;
271 	info->recv_chars_len = 0;
272 	if (rv) {
273 	    /* Bad input data. */
274 	    fprintf(stderr, "Bad input data\n");
275 	    return;
276 	}
277 	return;
278     }
279 
280     if (info->recv_chars_too_many)
281 	return;
282 
283     r = info->recv_chars;
284 
285     if (len >= sizeof(info->recv_chars)) {
286 	info->recv_chars_too_many = 1;
287     } else if ((len > 0) && isspace(r[len-1]) && isspace(ch)) {
288 	/* Ignore multiple spaces together. */
289     } else {
290 	r[len] = ch;
291 	info->recv_chars_len++;
292     }
293 }
294 
295 static void
ra_send(msg_t * omsg,serserv_data_t * si)296 ra_send(msg_t *omsg, serserv_data_t *si)
297 {
298     unsigned char msg[IPMI_SIM_MAX_MSG_LENGTH + 7];
299     unsigned int msg_len;
300 
301     if (omsg->netfn == IPMI_APP_NETFN && omsg->cmd == IPMI_SEND_MSG_CMD)
302 	return; /* These are dummies, ignore them. */
303 
304     format_ipmb_rsp(omsg, msg, &msg_len, si);
305 
306     ra_format_msg(msg, msg_len, si);
307 }
308 
309 int
ra_setup(serserv_data_t * si)310 ra_setup(serserv_data_t *si)
311 {
312     struct ra_data *info;
313     info = malloc(sizeof(*info));
314     if (!info)
315 	return -1;
316 
317     info->recv_chars_len = 0;
318     info->recv_chars_too_many = 0;
319     si->codec_info = info;
320     si->channel.recv_in_q = ra_ipmb_handler;
321     return 0;
322 }
323 
324 /***********************************************************************
325  *
326  * Direct Mode codec.
327  *
328  ***********************************************************************/
329 
330 #define DM_START_CHAR		0xA0
331 #define DM_STOP_CHAR		0xA5
332 #define DM_PACKET_HANDSHAKE	0xA6
333 #define DM_DATA_ESCAPE_CHAR	0xAA
334 
335 struct dm_data {
336     unsigned char recv_msg[IPMI_SIM_MAX_MSG_LENGTH + 4];
337     unsigned int  recv_msg_len;
338     int           recv_msg_too_many;
339     int           in_recv_msg;
340     int           in_escape;
341 };
342 
343 static void
dm_handle_msg(unsigned char * imsg,unsigned int len,serserv_data_t * si)344 dm_handle_msg(unsigned char *imsg, unsigned int len, serserv_data_t *si)
345 {
346     int rv;
347     msg_t msg;
348 
349     if (si->sysinfo->debug & DEBUG_RAW_MSG)
350 	debug_log_raw_msg(si->sysinfo, imsg, len, "Raw serial receive:");
351 
352     memset(&msg, 0, sizeof(msg));
353     rv = unformat_ipmb_msg(&msg, imsg, len, si);
354     if (rv)
355 	return;
356     channel_smi_send(&si->channel, &msg);
357 }
358 
359 static void
dm_handle_char(unsigned char ch,serserv_data_t * si)360 dm_handle_char(unsigned char ch, serserv_data_t *si)
361 {
362     struct dm_data *info = si->codec_info;
363     unsigned int len = info->recv_msg_len;
364     unsigned char c;
365 
366     switch (ch) {
367     case DM_START_CHAR:
368 	if (info->in_recv_msg)
369 	    fprintf(stderr, "Msg started in the middle of another\n");
370 	info->in_recv_msg = 1;
371 	info->recv_msg_len = 0;
372 	info->recv_msg_too_many = 0;
373 	info->in_escape = 0;
374 	break;
375 
376     case DM_STOP_CHAR:
377 	if (!info->in_recv_msg)
378 	    fprintf(stderr, "Empty message\n");
379 	else if (info->in_escape) {
380 	    info->in_recv_msg = 0;
381 	    fprintf(stderr, "Message ended in escape\n");
382 	} else if (info->recv_msg_too_many) {
383 	    fprintf(stderr, "Message too long\n");
384 	    info->in_recv_msg = 0;
385 	} else {
386 	    dm_handle_msg(info->recv_msg, info->recv_msg_len, si);
387 	    info->in_recv_msg = 0;
388 	}
389 	info->in_escape = 0;
390 
391 	c = DM_PACKET_HANDSHAKE;
392 	raw_send(si, &c, 1);
393 	break;
394 
395     case DM_PACKET_HANDSHAKE:
396 	info->in_escape = 0;
397 	break;
398 
399     case DM_DATA_ESCAPE_CHAR:
400 	if (!info->recv_msg_too_many)
401 	    info->in_escape = 1;
402 	break;
403 
404     default:
405 	if (!info->in_recv_msg)
406 	    /* Ignore characters outside of messages. */
407 	    break;
408 
409 	if (info->in_escape) {
410 	    info->in_escape = 0;
411 	    switch (ch) {
412 	    case 0xB0: ch = DM_START_CHAR; break;
413 	    case 0xB5: ch = DM_STOP_CHAR; break;
414 	    case 0xB6: ch = DM_PACKET_HANDSHAKE; break;
415 	    case 0xBA: ch = DM_DATA_ESCAPE_CHAR; break;
416 	    case 0x3B: ch = 0x1b; break;
417 	    default:
418 		fprintf(stderr, "Invalid escape char: 0x%x\n", ch);
419 		info->recv_msg_too_many = 1;
420 		return;
421 	    }
422 	}
423 
424 	if (!info->recv_msg_too_many) {
425 	    if (len >= sizeof(info->recv_msg)) {
426 		info->recv_msg_too_many = 1;
427 		break;
428 	    }
429 
430 	    info->recv_msg[len] = ch;
431 	    info->recv_msg_len++;
432 	}
433 	break;
434     }
435 }
436 
437 static void
dm_send(msg_t * imsg,serserv_data_t * si)438 dm_send(msg_t *imsg, serserv_data_t *si)
439 {
440     unsigned int i;
441     unsigned int len = 0;
442     unsigned char c[(IPMI_SIM_MAX_MSG_LENGTH + 7) * 2];
443     unsigned char msg[IPMI_SIM_MAX_MSG_LENGTH + 7];
444     unsigned int msg_len;
445 
446     format_ipmb_rsp(imsg, msg, &msg_len, si);
447 
448     c[len++] = 0xA0;
449     for (i = 0; i < msg_len; i++) {
450 	switch (msg[i]) {
451 	case 0xA0:
452 	    c[len++] = 0xAA;
453 	    c[len++] = 0xB0;
454 	    break;
455 
456 	case 0xA5:
457 	    c[len++] = 0xAA;
458 	    c[len++] = 0xB5;
459 	    break;
460 
461 	case 0xA6:
462 	    c[len++] = 0xAA;
463 	    c[len++] = 0xB6;
464 	    break;
465 
466 	case 0xAA:
467 	    c[len++] = 0xAA;
468 	    c[len++] = 0xBA;
469 	    break;
470 
471 	case 0x1B:
472 	    c[len++] = 0xAA;
473 	    c[len++] = 0x3B;
474 	    break;
475 
476 	default:
477 	    c[len++] = msg[i];
478 	}
479 
480     }
481     c[len++] = 0xA5;
482 
483     raw_send(si, c, len);
484 }
485 
486 static int
dm_setup(serserv_data_t * si)487 dm_setup(serserv_data_t *si)
488 {
489     struct dm_data *info;
490 
491     info = malloc(sizeof(*info));
492     if (!info)
493 	return -1;
494     memset(info, 0, sizeof(*info));
495     si->channel.set_atn = handle_attn;
496     si->codec_info = info;
497     return 0;
498 }
499 
500 
501 /***********************************************************************
502  *
503  * Terminal Mode codec.
504  *
505  ***********************************************************************/
506 
507 #define TM_MAX_CHARS_SIZE (((IPMI_SIM_MAX_MSG_LENGTH + 1) * 3) + 4)
508 
509 struct tm_data {
510     unsigned char recv_chars[TM_MAX_CHARS_SIZE];
511     unsigned int  recv_chars_len;
512     int           recv_chars_too_many;
513 };
514 
515 static void
tm_send(msg_t * msg,serserv_data_t * si)516 tm_send(msg_t *msg, serserv_data_t *si)
517 {
518     unsigned int i;
519     unsigned int len;
520     unsigned char c[TM_MAX_CHARS_SIZE];
521     unsigned char t;
522 
523     len = 0;
524     c[len] = '[';
525     len++;
526 
527     t = msg->netfn << 2 | msg->rs_lun;
528     c[len] = hex2char[t >> 4];
529     len++;
530     c[len] = hex2char[t & 0xf];
531     len++;
532 
533     /*
534      * Insert the sequence number and bridge bits.  Bridge bits
535      * are always zero.
536      */
537     t = msg->rq_seq << 2;
538     c[len] = hex2char[t >> 4];
539     len++;
540     c[len] = hex2char[t & 0xf];
541     len++;
542 
543     c[len] = hex2char[msg->cmd >> 4];
544     len++;
545     c[len] = hex2char[msg->cmd & 0xf];
546     len++;
547 
548     /* Now the rest of the message. */
549     for (i = 0; ; ) {
550 	c[len] = hex2char[msg->data[i] >> 4];
551 	len++;
552 	c[len] = hex2char[msg->data[i] & 0xf];
553 	len++;
554 	i++;
555 	if (i == msg->len)
556 	    break;
557 	c[len] = ' ';
558 	len++;
559     }
560     c[len] = ']';
561     len++;
562     c[len] = 0x0a;
563     len++;
564 
565     raw_send(si, c, len);
566 }
567 
568 /*
569  * Called when the ']' is seen, the leading '[' is removed, too.  We
570  * get this with a leading space and no more than one space between
571  * items.
572  */
tm_unformat_msg(unsigned char * r,unsigned int len,serserv_data_t * si)573 static int tm_unformat_msg(unsigned char *r, unsigned int len,
574 			   serserv_data_t *si)
575 {
576     unsigned char o[IPMI_SIM_MAX_MSG_LENGTH];
577     msg_t         msg;
578     unsigned int  p = 0;
579     unsigned int  i = 0;
580     int           rv;
581 
582     if (si->sysinfo->debug & DEBUG_RAW_MSG)
583 	debug_log_raw_msg(si->sysinfo, r, len, "Raw serial receive:");
584 
585 #define SKIP_SPACE if (isspace(r[p])) p++
586 #define ENSURE_MORE if (p >= len) return -1
587 
588 	SKIP_SPACE;
589 	while (p < len) {
590 		if (i >= sizeof(o))
591 			return -1;
592 		ENSURE_MORE;
593 		rv = fromhex(r[p]);
594 		if (rv < 0)
595 			return rv;
596 		o[i] = rv << 4;
597 		p++;
598 		ENSURE_MORE;
599 		rv = fromhex(r[p]);
600 		if (rv < 0)
601 			return rv;
602 		o[i] |= rv;
603 		p++;
604 		i++;
605 		SKIP_SPACE;
606 	}
607 
608 	if (i < 3)
609 	    return -1;
610 
611 	memset(&msg, 0, sizeof(msg));
612 	msg.netfn = o[0] >> 2;
613 	msg.rq_lun = o[0] & 3;
614 	msg.rq_seq = o[1] >> 2;
615 	msg.cmd = o[2];
616 	msg.data = o + 3;
617 	msg.len = i - 3;
618 	msg.src_addr = NULL;
619 	msg.src_len = 0;
620 
621 	channel_smi_send(&si->channel, &msg);
622 	return 0;
623 #undef SKIP_SPACE
624 #undef ENSURE_MORE
625 }
626 
627 static void
tm_handle_char(unsigned char ch,serserv_data_t * si)628 tm_handle_char(unsigned char ch, serserv_data_t *si)
629 {
630     struct tm_data *info = si->codec_info;
631     unsigned int len = info->recv_chars_len;
632     unsigned char *r;
633     int           rv;
634 
635     if (ch == '[') {
636 	/*
637 	 * Start of a command.  Note that if a command is
638 	 * already in progress (len != 0) we abort it.
639 	 */
640 	if (len != 0)
641 	    fprintf(stderr, "Msg started in the middle of another\n");
642 
643 	/* Convert the leading '[' to a space, that's innocuous. */
644 	info->recv_chars[0] = ' ';
645 	info->recv_chars_len = 1;
646 	info->recv_chars_too_many = 0;
647 	return;
648     }
649 
650     if (len == 0)
651 	/* Ignore everything outside [ ]. */
652 	return;
653 
654     if (ch == ']') {
655 	/* End of command, handle it. */
656 	if (info->recv_chars_too_many) {
657 	    /* Input data overrun. */
658 	    fprintf(stderr, "Data overrun\n");
659 	    info->recv_chars_too_many = 0;
660 	    info->recv_chars_len = 0;
661 	    return;
662 	}
663 	rv = tm_unformat_msg(info->recv_chars, info->recv_chars_len, si);
664 	info->recv_chars_too_many = 0;
665 	info->recv_chars_len = 0;
666 	if (rv) {
667 	    /* Bad input data. */
668 	    fprintf(stderr, "Bad input data\n");
669 	    return;
670 	}
671 	return;
672     }
673 
674     if (info->recv_chars_too_many)
675 	return;
676 
677     r = info->recv_chars;
678 
679     if (len >= sizeof(info->recv_chars)) {
680 	info->recv_chars_too_many = 1;
681     } else if ((len > 0) && isspace(r[len-1]) && isspace(ch)) {
682 	/* Ignore multiple spaces together. */
683     } else {
684 	r[len] = ch;
685 	info->recv_chars_len++;
686     }
687 }
688 
689 static int
tm_setup(serserv_data_t * si)690 tm_setup(serserv_data_t *si)
691 {
692     struct tm_data *info;
693 
694     info = malloc(sizeof(*info));
695     if (!info)
696 	return -1;
697 
698     info->recv_chars_len = 0;
699     info->recv_chars_too_many = 0;
700     si->channel.set_atn = handle_attn;
701     si->codec_info = info;
702     return 0;
703 }
704 
705 
706 /***********************************************************************
707  *
708  * VM Mode codec.
709  *
710  ***********************************************************************/
711 
712 /*
713  * This protocol has an end-of-message marker, everything from the
714  * beginning or the last end of message is a new message (or command).
715  * Messages are normal IPMI messages with the following header:
716  *
717  *   seq
718  *   netfn << 2 | lun
719  *   cmd
720  *   data....
721  *   checksum
722  *
723  * The sequence is return in the response as-is.
724  * Commands are special things to alert the other end of things like
725  * attn, requests for reset/nmi/etc.
726  */
727 
728 #define VM_MSG_CHAR	0xA0 /* Marks end of message */
729 #define VM_CMD_CHAR	0xA1 /* Marks end of a command */
730 #define VM_ESCAPE_CHAR	0xAA /* Set bit 4 from the next byte to 0 */
731 
732 #define VM_PROTOCOL_VERSION	1
733 #define VM_CMD_VERSION		0xff /* A version number byte follows */
734 #define VM_CMD_NOATTN		0x00
735 #define VM_CMD_ATTN		0x01
736 #define VM_CMD_ATTN_IRQ		0x02
737 #define VM_CMD_POWEROFF		0x03
738 #define VM_CMD_RESET		0x04
739 #define VM_CMD_ENABLE_IRQ	0x05 /* Enable/disable the messaging irq */
740 #define VM_CMD_DISABLE_IRQ	0x06
741 #define VM_CMD_SEND_NMI		0x07
742 #define VM_CMD_CAPABILITIES	0x08
743 #define   VM_CAPABILITIES_POWER	0x01
744 #define   VM_CAPABILITIES_RESET	0x02
745 #define   VM_CAPABILITIES_IRQ	0x04
746 #define   VM_CAPABILITIES_NMI	0x08
747 #define   VM_CAPABILITIES_ATTN	0x10
748 #define   VM_CAPABILITIES_GRACEFUL_SHUTDOWN 0x20
749 #define VM_CMD_GRACEFUL_SHUTDOWN 0x09
750 
751 struct vm_data {
752     unsigned char recv_msg[IPMI_SIM_MAX_MSG_LENGTH + 4];
753     unsigned int  recv_msg_len;
754     int           recv_msg_too_many;
755     int           in_escape;
756     int		  attn_works;
757 };
758 
759 static void
vm_handle_msg(unsigned char * imsg,unsigned int len,serserv_data_t * si)760 vm_handle_msg(unsigned char *imsg, unsigned int len, serserv_data_t *si)
761 {
762     msg_t msg;
763 
764     if (si->sysinfo->debug & DEBUG_RAW_MSG)
765 	debug_log_raw_msg(si->sysinfo, imsg, len, "Raw serial receive:");
766 
767     if (len < 4) {
768 	fprintf(stderr, "Message too short\n");
769 	return;
770     }
771 
772     if (ipmb_checksum(imsg, len, 0) != 0) {
773 	fprintf(stderr, "Message checksum failure\n");
774 	return;
775     }
776     len--;
777 
778     memset(&msg, 0, sizeof(msg));
779     msg.rq_seq = imsg[0];
780     msg.netfn = imsg[1] >> 2;
781     msg.rs_lun = imsg[1] & 0x3;
782     msg.cmd = imsg[2];
783     msg.len = len - 3;
784     msg.data = imsg + 3;
785 
786     channel_smi_send(&si->channel, &msg);
787 }
788 
789 static void
vm_handle_cmd(unsigned char * imsg,unsigned int len,serserv_data_t * si)790 vm_handle_cmd(unsigned char *imsg, unsigned int len, serserv_data_t *si)
791 {
792     struct vm_data *info = si->codec_info;
793 
794     if (si->sysinfo->debug & DEBUG_RAW_MSG)
795 	debug_log_raw_msg(si->sysinfo, imsg, len, "Raw serial cmd:");
796 
797     if (len < 1)
798 	return;
799 
800     switch (imsg[0]) {
801     case VM_CMD_VERSION:
802 	/* We only support one version for now. */
803 	break;
804 
805     case VM_CMD_CAPABILITIES:
806 	if (len < 2)
807 	    return;
808 	if (imsg[1] & VM_CAPABILITIES_POWER)
809 	    si->channel.hw_capabilities |= (1 << HW_OP_POWERON);
810 	if (imsg[1] & VM_CAPABILITIES_GRACEFUL_SHUTDOWN)
811 	    si->channel.hw_capabilities |= (1 << HW_OP_GRACEFUL_SHUTDOWN);
812 	if (imsg[1] & VM_CAPABILITIES_RESET)
813 	    si->channel.hw_capabilities |= (1 << HW_OP_RESET);
814 	if (imsg[1] & VM_CAPABILITIES_IRQ)
815 	    si->channel.hw_capabilities |= (1 << HW_OP_IRQ_ENABLE);
816 	if (imsg[1] & VM_CAPABILITIES_NMI)
817 	    si->channel.hw_capabilities |= (1 << HW_OP_SEND_NMI);
818 	if (imsg[1] & VM_CAPABILITIES_ATTN)
819 	    info->attn_works = 1;
820 	break;
821 
822     case VM_CMD_RESET:
823 	/* The remote end reset, report it. */
824 	if (si->sysinfo->target_reset)
825 	    si->sysinfo->target_reset(si->sysinfo);
826 	break;
827     }
828 }
829 
830 static void
vm_handle_char(unsigned char ch,serserv_data_t * si)831 vm_handle_char(unsigned char ch, serserv_data_t *si)
832 {
833     struct vm_data *info = si->codec_info;
834     unsigned int len = info->recv_msg_len;
835 
836     switch (ch) {
837     case VM_MSG_CHAR:
838     case VM_CMD_CHAR:
839 	if (info->in_escape) {
840 	    fprintf(stderr, "Message ended in escape\n");
841 	} else if (info->recv_msg_too_many) {
842 	    fprintf(stderr, "Message too long\n");
843 	} else if (info->recv_msg_len == 0) {
844 	    /* Nothing to do */
845 	} else if (ch == VM_MSG_CHAR) {
846 	    vm_handle_msg(info->recv_msg, info->recv_msg_len, si);
847 	} else if (ch == VM_CMD_CHAR) {
848 	    vm_handle_cmd(info->recv_msg, info->recv_msg_len, si);
849 	}
850 	info->in_escape = 0;
851 	info->recv_msg_len = 0;
852 	info->recv_msg_too_many = 0;
853 	break;
854 
855     case VM_ESCAPE_CHAR:
856 	if (!info->recv_msg_too_many)
857 	    info->in_escape = 1;
858 	break;
859 
860     default:
861 	if (info->in_escape) {
862 	    info->in_escape = 0;
863 	    ch &= ~0x10;
864 	}
865 
866 	if (!info->recv_msg_too_many) {
867 	    if (len >= sizeof(info->recv_msg)) {
868 		info->recv_msg_too_many = 1;
869 		break;
870 	    }
871 
872 	    info->recv_msg[len] = ch;
873 	    info->recv_msg_len++;
874 	}
875 	break;
876     }
877 }
878 
879 static void
vm_add_char(unsigned char ch,unsigned char * c,unsigned int * pos)880 vm_add_char(unsigned char ch, unsigned char *c, unsigned int *pos)
881 {
882     switch (ch) {
883     case VM_MSG_CHAR:
884     case VM_CMD_CHAR:
885     case VM_ESCAPE_CHAR:
886 	c[(*pos)++] = VM_ESCAPE_CHAR;
887 	c[(*pos)++] = ch | 0x10;
888 	break;
889 
890     default:
891 	c[(*pos)++] = ch;
892     }
893 }
894 
895 static void
vm_send(msg_t * imsg,serserv_data_t * si)896 vm_send(msg_t *imsg, serserv_data_t *si)
897 {
898     unsigned int i;
899     unsigned int len = 0;
900     unsigned char c[(IPMI_SIM_MAX_MSG_LENGTH + 7) * 2];
901     unsigned char csum;
902     unsigned char ch;
903 
904     ch = imsg->rq_seq;
905     vm_add_char(ch, c, &len);
906     csum = ipmb_checksum(&ch, 1, 0);
907 
908     ch = (imsg->netfn << 2) | imsg->rs_lun;
909     vm_add_char(ch, c, &len);
910     csum = ipmb_checksum(&ch, 1, csum);
911 
912     vm_add_char(imsg->cmd, c, &len);
913     csum = ipmb_checksum(&imsg->cmd, 1, csum);
914 
915     for (i = 0; i < imsg->len; i++)
916 	vm_add_char(imsg->data[i], c, &len);
917 
918     vm_add_char(-ipmb_checksum(imsg->data, imsg->len, csum), c, &len);
919     c[len++] = VM_MSG_CHAR;
920 
921     raw_send(si, c, len);
922 }
923 
924 static void
vm_set_attn(channel_t * chan,int val,int irq)925 vm_set_attn(channel_t *chan, int val, int irq)
926 {
927     serserv_data_t *si = chan->chan_info;
928     unsigned int len = 0;
929     unsigned char c[3];
930 
931     if (!val)
932 	vm_add_char(VM_CMD_NOATTN, c, &len);
933     else if (irq)
934 	vm_add_char(VM_CMD_ATTN_IRQ, c, &len);
935     else
936 	vm_add_char(VM_CMD_ATTN, c, &len);
937 
938     c[len++] = VM_CMD_CHAR;
939 
940     raw_send(si, c, len);
941 }
942 
943 static int
vm_hw_op(channel_t * chan,unsigned int op)944 vm_hw_op(channel_t *chan, unsigned int op)
945 {
946     serserv_data_t *si = chan->chan_info;
947     unsigned int len = 0;
948     unsigned char c[3];
949 
950     switch(op) {
951     case HW_OP_RESET:
952 	vm_add_char(VM_CMD_RESET, c, &len);
953 	break;
954 
955     case HW_OP_POWERON:
956 	if (chan->start_cmd)
957 	    chan->start_cmd(chan);
958 	return 0;
959 
960     case HW_OP_POWEROFF:
961 	if (si->connected)
962 	    vm_add_char(VM_CMD_POWEROFF, c, &len);
963 	if (chan->stop_cmd)
964 	    chan->stop_cmd(chan, !si->connected);
965 	break;
966 
967     case HW_OP_GRACEFUL_SHUTDOWN:
968 	if (si->connected)
969 	    vm_add_char(VM_CMD_GRACEFUL_SHUTDOWN, c, &len);
970 	break;
971 
972     case HW_OP_SEND_NMI:
973 	vm_add_char(VM_CMD_SEND_NMI, c, &len);
974 	break;
975 
976     case HW_OP_IRQ_ENABLE:
977 	vm_add_char(VM_CMD_ENABLE_IRQ, c, &len);
978 	break;
979 
980     case HW_OP_IRQ_DISABLE:
981 	vm_add_char(VM_CMD_DISABLE_IRQ, c, &len);
982 	break;
983 
984     case HW_OP_CHECK_POWER:
985 	return si->connected;
986 	break;
987 
988     default:
989 	return 0;
990     }
991 
992     c[len++] = VM_CMD_CHAR;
993 
994     raw_send(si, c, len);
995     return 0;
996 }
997 
998 static void
vm_connected(serserv_data_t * si)999 vm_connected(serserv_data_t *si)
1000 {
1001     unsigned int len = 0;
1002     unsigned char c[5];
1003 
1004     vm_add_char(VM_CMD_VERSION, c, &len);
1005     vm_add_char(VM_PROTOCOL_VERSION, c, &len);
1006     c[len++] = VM_CMD_CHAR;
1007     raw_send(si, c, len);
1008     si->connected = 1;
1009     ipmi_resend_atn(&si->channel);
1010 }
1011 
1012 static void
vm_disconnected(serserv_data_t * si)1013 vm_disconnected(serserv_data_t *si)
1014 {
1015     si->connected = 0;
1016 }
1017 
1018 static int
vm_setup(serserv_data_t * si)1019 vm_setup(serserv_data_t *si)
1020 {
1021     struct vm_data *info;
1022 
1023     info = malloc(sizeof(*info));
1024     if (!info)
1025 	return -1;
1026     memset(info, 0, sizeof(*info));
1027     si->codec_info = info;
1028     si->channel.hw_op = vm_hw_op;
1029     si->channel.set_atn = vm_set_attn;
1030     si->channel.hw_capabilities = (1 << HW_OP_POWERON);
1031     return 0;
1032 }
1033 
1034 
1035 /***********************************************************************
1036  *
1037  * codec structure
1038  *
1039  ***********************************************************************/
1040 static ser_codec_t codecs[] = {
1041     { "TerminalMode",
1042       tm_handle_char, tm_send, tm_setup },
1043     { "Direct",
1044       dm_handle_char, dm_send, dm_setup },
1045     { "RadisysAscii",
1046       ra_handle_char, ra_send, ra_setup },
1047     { "VM",
1048       vm_handle_char, vm_send, vm_setup, vm_connected, vm_disconnected },
1049     { NULL }
1050 };
1051 
1052 static ser_codec_t *
ser_lookup_codec(const char * name)1053 ser_lookup_codec(const char *name)
1054 {
1055     unsigned int i;
1056 
1057     for (i = 0; codecs[i].name; i++) {
1058 	if (strcmp(codecs[i].name, name) == 0)
1059 	    return &codecs[i];
1060     }
1061     return NULL;
1062 }
1063 
1064 #define PP_GET_SERIAL_INTF_CMD	0x01
1065 #define PP_SET_SERIAL_INTF_CMD	0x02
1066 static unsigned char pp_oem_chars[] = { 0x00, 0x40, 0x0a };
1067 static int
pp_oem_handler(channel_t * chan,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len)1068 pp_oem_handler(channel_t *chan, msg_t *msg, unsigned char *rdata,
1069 	       unsigned int *rdata_len)
1070 {
1071     serserv_data_t *ser = chan->chan_info;
1072 
1073     if (msg->netfn != IPMI_OEM_GROUP_NETFN)
1074 	return 0;
1075 
1076     if ((msg->len < 3) || (memcmp(msg->data, pp_oem_chars, 3) != 0))
1077 	return 0;
1078 
1079     switch (msg->cmd) {
1080     case PP_GET_SERIAL_INTF_CMD:
1081 	rdata[0] = 0;
1082 	memcpy(rdata + 1, pp_oem_chars, 3);
1083 	rdata[4] = 0;
1084 	if (msg->data[3] == 1)
1085 	    rdata[4] |= ser->echo;
1086 	*rdata_len = 5;
1087 	return 1;
1088 
1089     case PP_SET_SERIAL_INTF_CMD:
1090 	if (msg->len < 5)
1091 	    rdata[0] = 0xcc;
1092 	else if (msg->data[3] == 1) {
1093 	    ser->echo = msg->data[4] & 1;
1094 	    rdata[0] = 0;
1095 	}
1096 	memcpy(rdata + 1, pp_oem_chars, 3);
1097 	*rdata_len = 4;
1098 	return 1;
1099     }
1100 
1101     return 0;
1102 }
1103 
1104 static void
pp_oem_init(serserv_data_t * ser)1105 pp_oem_init(serserv_data_t *ser)
1106 {
1107     ser->echo = 1;
1108     ser->channel.oem_intf_recv_handler = pp_oem_handler;
1109 }
1110 
1111 #define RA_CONTROLLER_OEM_NETFN	0x3e
1112 #define RA_GET_IPMB_ADDR_CMD	0x12
1113 static int
ra_oem_handler(channel_t * chan,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len)1114 ra_oem_handler(channel_t *chan, msg_t *msg, unsigned char *rdata,
1115 	       unsigned int *rdata_len)
1116 {
1117     serserv_data_t *ser = chan->chan_info;
1118 
1119     if (msg->netfn == RA_CONTROLLER_OEM_NETFN) {
1120 	switch (msg->cmd) {
1121 	case RA_GET_IPMB_ADDR_CMD:
1122 	    rdata[0] = 0;
1123 	    rdata[1] = ser->my_ipmb;
1124 	    *rdata_len = 2;
1125 	    return 1;
1126 	}
1127     } else if (msg->netfn == IPMI_APP_NETFN) {
1128 	switch (msg->cmd) {
1129 	case IPMI_GET_MSG_FLAGS_CMD:
1130 	    /* No message flag support. */
1131 	    rdata[0] = 0xc1;
1132 	    *rdata_len = 1;
1133 	    return 1;
1134 	}
1135     }
1136 
1137     return 0;
1138 }
1139 
1140 static void
ra_oem_init(serserv_data_t * ser)1141 ra_oem_init(serserv_data_t *ser)
1142 {
1143     ser->channel.oem_intf_recv_handler = ra_oem_handler;
1144 }
1145 
1146 static ser_oem_handler_t oem_handlers[] = {
1147     { "PigeonPoint",		pp_oem_handler,		pp_oem_init },
1148     { "Radisys",		ra_oem_handler,		ra_oem_init },
1149     { NULL }
1150 };
1151 
1152 static ser_oem_handler_t *
ser_lookup_oem(const char * name)1153 ser_lookup_oem(const char *name)
1154 {
1155     unsigned int i;
1156 
1157     for (i = 0; oem_handlers[i].name; i++) {
1158 	if (strcmp(oem_handlers[i].name, name) == 0)
1159 	    return &oem_handlers[i];
1160     }
1161     return NULL;
1162 }
1163 
1164 static void
ser_return_rsp(channel_t * chan,msg_t * imsg,rsp_msg_t * rsp)1165 ser_return_rsp(channel_t *chan, msg_t *imsg, rsp_msg_t *rsp)
1166 {
1167     serserv_data_t *ser = chan->chan_info;
1168     msg_t msg;
1169 
1170     if (!ser->connected)
1171 	return;
1172 
1173     msg.netfn = rsp->netfn;
1174     msg.cmd = rsp->cmd;
1175     msg.data = rsp->data;
1176     msg.len = rsp->data_len;
1177     msg.rq_lun = imsg->rs_lun;
1178     msg.rq_addr = imsg->rs_addr;
1179     msg.rs_lun = imsg->rq_lun;
1180     msg.rs_addr = imsg->rq_addr;
1181     msg.rq_seq = imsg->rq_seq;
1182     ser->codec->send(&msg, ser);
1183 }
1184 
1185 void
serserv_handle_data(serserv_data_t * ser,uint8_t * data,unsigned int len)1186 serserv_handle_data(serserv_data_t *ser, uint8_t *data, unsigned int len)
1187 {
1188     unsigned int i;
1189 
1190     for (i = 0; i < len; i++)
1191 	ser->codec->handle_char(data[i], ser);
1192 }
1193 
1194 int
serserv_init(serserv_data_t * ser)1195 serserv_init(serserv_data_t *ser)
1196 {
1197     ser->channel.return_rsp = ser_return_rsp;
1198 
1199     ser->codec->setup(ser);
1200     if (ser->oem)
1201 	ser->oem->init(ser);
1202 
1203     chan_init(&ser->channel);
1204     return 0;
1205 }
1206 
1207 int
serserv_read_config(char ** tokptr,sys_data_t * sys,const char ** errstr)1208 serserv_read_config(char **tokptr, sys_data_t *sys, const char **errstr)
1209 {
1210     serserv_data_t *ser;
1211     const char *tok, *tok2;
1212     char *endp;
1213     int err;
1214     unsigned int chan_num;
1215 
1216     ser = malloc(sizeof(*ser));
1217     if (!ser) {
1218 	*errstr = "Out of memory";
1219 	return -1;
1220     }
1221     memset(ser, 0, sizeof(*ser));
1222 
1223     tok = mystrtok(NULL, " \t\n", tokptr);
1224     if (!tok) {
1225 	*errstr = "No channel given";
1226 	goto out_err;
1227     }
1228     ser->channel.session_support = IPMI_CHANNEL_SESSION_LESS;
1229     ser->channel.medium_type = IPMI_CHANNEL_MEDIUM_RS232;
1230     if (strcmp(tok, "kcs") == 0) {
1231 	chan_num = 15;
1232 	ser->channel.protocol_type = IPMI_CHANNEL_PROTOCOL_KCS;
1233     } else if (strcmp(tok, "bt") == 0) {
1234 	chan_num = 15;
1235 	ser->channel.protocol_type = IPMI_CHANNEL_PROTOCOL_BT_v15;
1236     } else if (strcmp(tok, "smic") == 0) {
1237 	chan_num = 15;
1238 	ser->channel.protocol_type = IPMI_CHANNEL_PROTOCOL_SMIC;
1239     } else {
1240 	chan_num = strtoul(tok, &endp, 0);
1241 	if (*endp != '\0') {
1242 	    *errstr = "Channel not a valid number";
1243 	    goto out_err;
1244 	}
1245 	ser->channel.protocol_type = IPMI_CHANNEL_PROTOCOL_TMODE;
1246     }
1247     if (chan_num != 15) {
1248 	*errstr = "Only BMC channel (channel 15, or kcs/bt/smic) is"
1249 	    " supported for serial";
1250 	goto out_err;
1251     }
1252 
1253     if (sys->chan_set[chan_num]) {
1254 	*errstr = "System channel already defined";
1255 	goto out_err;
1256     }
1257     ser->channel.channel_num = chan_num;
1258 
1259     err = get_sock_addr(tokptr, &ser->addr.addr, &ser->addr.addr_len,
1260 			NULL, SOCK_STREAM, errstr);
1261     if (err)
1262 	goto out_err;
1263 
1264     for (tok = mystrtok(NULL, " \t\n", tokptr); tok;
1265 	 tok = mystrtok(NULL, " \t\n", tokptr)) {
1266 	if (strcmp(tok, "connect") == 0) {
1267 	    ser->do_connect = 1;
1268 	    continue;
1269 	}
1270 
1271 	tok2 = mystrtok(NULL, " \t\n", tokptr);
1272 	if (strcmp(tok, "codec") == 0) {
1273 	    if (!tok2) {
1274 		*errstr = "Missing parameter for codec";
1275 		return -1;
1276 	    }
1277 	    ser->codec = ser_lookup_codec(tok2);
1278 	    if (!ser->codec) {
1279 		*errstr = "Invalid codec";
1280 		return -1;
1281 	    }
1282 	} else if (strcmp(tok, "oem") == 0) {
1283 	    if (!tok2) {
1284 		*errstr = "Missing parameter for oem";
1285 		return -1;
1286 	    }
1287 	    ser->oem = ser_lookup_oem(tok2);
1288 	    if (!ser->oem) {
1289 		*errstr = "Invalid oem setting";
1290 		return -1;
1291 	    }
1292 	} else if (strcmp(tok, "attn") == 0) {
1293 	    unsigned int pos = 0;
1294 	    char *tokptr2 = NULL;
1295 
1296 	    if (!tok2) {
1297 		*errstr = "Missing parameter for attn";
1298 		return -1;
1299 	    }
1300 
1301 	    ser->do_attn = 1;
1302 	    tok2 = mystrtok((char *) tok2, ",", &tokptr2);
1303 	    while (tok2) {
1304 		if (pos >= sizeof(ser->attn_chars)) {
1305 		    *errstr = "Too many attn characters";
1306 		    return -1;
1307 		}
1308 		ser->attn_chars[pos] = strtoul(tok2, &endp, 0);
1309 		if (*endp != '\0') {
1310 		    *errstr = "Invalid attn value";
1311 		    return -1;
1312 		}
1313 		pos++;
1314 		tok2 = mystrtok(NULL, ",", &tokptr2);
1315 	    }
1316 	    ser->attn_chars_len = pos;
1317 	} else if (strcmp(tok, "ipmb") == 0) {
1318 	    char *endp;
1319 	    ser->my_ipmb = strtoul(tok2, &endp, 0);
1320 	    if (*endp != '\0') {
1321 		*errstr = "Invalid IPMB address";
1322 		return -1;
1323 	    }
1324 	} else {
1325 	    *errstr = "Invalid setting, not connect, codec, oem, attn, or ipmb";
1326 	    return -1;
1327 	}
1328     }
1329 
1330     if (!ser->codec) {
1331 	*errstr = "codec not specified";
1332 	goto out_err;
1333     }
1334 
1335     ser->sysinfo = sys;
1336     ser->channel.chan_info = ser;
1337 
1338     sys->chan_set[chan_num] = &ser->channel;
1339     return 0;
1340 
1341  out_err:
1342     free(ser);
1343     return -1;
1344 }
1345