1 /*
2  * ipmi_serial_bmc_emu.c
3  *
4  * An emulator for various IPMI BMCs that sit on a serial port
5  *
6  * Author: MontaVista Software, Inc.
7  *         Corey Minyard <minyard@mvista.com>
8  *         source@mvista.com
9  *
10  * Copyright 2006 MontaVista Software Inc.
11  *
12  *  This program is free software; you can redistribute it and/or modify it
13  *  under the terms of the GNU General Public License as published by the
14  *  Free Software Foundation; either version 2 of the License, or (at your
15  *  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 General Public License along
30  *  with this program; if not, write to the Free Software Foundation, Inc.,
31  *  675 Mass Ave, Cambridge, MA 02139, USA.  */
32 
33 #include <stdio.h>
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <netinet/in.h>
37 #include <netinet/tcp.h>
38 #include <netdb.h>
39 #include <errno.h>
40 #include <string.h>
41 #include <ctype.h>
42 #include <unistd.h>
43 #include <stdlib.h>
44 #include <sys/select.h>
45 #include <readline/readline.h>
46 #include <readline/history.h>
47 
48 #define _GNU_SOURCE
49 #include <getopt.h>
50 
51 #define IPMB_MAX_MSG_LENGTH 32
52 #define IPMI_MAX_MSG_LENGTH 36
53 
54 struct msg {
55     unsigned char data[IPMB_MAX_MSG_LENGTH];
56     unsigned int data_len;
57     struct msg *next;
58 };
59 
60 struct msg_info;
61 
62 struct codec {
63     char *name;
64     void (*handle_char)(unsigned char ch, struct msg_info *mi);
65     void (*send)(unsigned char *msg, unsigned int msg_len,
66 		 struct msg_info *mi);
67     void *(*setup)(void);
68     void (*handle_event)(struct msg *emsg, struct msg_info *mi);
69     void (*handle_ipmb)(struct msg *emsg, struct msg_info *mi);
70 };
71 
72 struct oem_handler {
73     char *name;
74     int (*handler)(const unsigned char *msg, unsigned int len,
75 		   struct msg_info *mi,
76 		   unsigned char *rsp, unsigned int *rsp_len);
77     void (*init)(struct msg_info *mi);
78 };
79 
80 #define EVENT_BUFFER_GLOBAL_ENABLE	(1 << 2)
81 #define EVENT_LOG_GLOBAL_ENABLE		(1 << 3)
82 #define SUPPORTED_GLOBAL_ENABLES	(EVENT_BUFFER_GLOBAL_ENABLE | \
83 					 EVENT_LOG_GLOBAL_ENABLE)
84 
85 struct msg_info {
86     /* General info, set by main code, not formatters. */
87     void          *info;
88     int           sock;
89     struct codec  *codec;
90     struct oem_handler *oem;
91 
92     /* Queues for events and IPMB messages. */
93     struct msg *ipmb_q, *ipmb_q_tail;
94     struct msg *event_q, *event_q_tail;
95 
96     void *oem_info;
97 
98     /* Settings */
99     int           echo;
100     unsigned char my_ipmb;
101     int           debug;
102     int           do_attn;
103     unsigned char attn_chars[8];
104     unsigned int  attn_chars_len;
105     char          global_enables;
106 
107     /* Info from the recv message. */
108     unsigned char netfn;
109     unsigned char dest;
110     unsigned char seq;
111     unsigned char rsAddr;
112     unsigned char rqAddr;
113     unsigned char rqLUN;
114     unsigned char rsLUN;
115     unsigned char cmd;
116 };
117 
118 static void socket_send(const unsigned char *data, unsigned int len,
119 			struct msg_info *mi);
120 static void handle_msg(const unsigned char *msg, unsigned int len,
121 		       struct msg_info *mi);
122 static void handle_ipmb_msg(const unsigned char *msg, unsigned int len,
123 			    struct msg_info *mi, struct msg_info *top_mi);
124 
125 static unsigned char hex2char[16] = {
126     '0', '1', '2', '3', '4', '5', '6', '7',
127     '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
128 };
129 
fromhex(unsigned char c)130 static int fromhex(unsigned char c)
131 {
132     if (isdigit(c))
133 	return c - '0';
134     else if (isxdigit(c))
135 	return tolower(c) - 'a' + 10;
136     else
137 	return -EINVAL;
138 }
139 
140 static unsigned char
ipmb_checksum(const unsigned char * data,int size)141 ipmb_checksum(const unsigned char *data, int size)
142 {
143 	unsigned char csum = 0;
144 
145 	for (; size > 0; size--, data++)
146 		csum += *data;
147 
148 	return -csum;
149 }
150 
151 static int
unformat_ipmb_msg(const unsigned char * msg,unsigned int * pos,unsigned int * len,struct msg_info * mi)152 unformat_ipmb_msg(const unsigned char *msg, unsigned int *pos,
153 		  unsigned int *len, struct msg_info *mi)
154 {
155     msg += *pos;
156 
157     if (*len < 7) {
158 	fprintf(stderr, "Message too short\n");
159 	return -EINVAL;
160     }
161 
162     if (ipmb_checksum(msg, *len) != 0) {
163 	fprintf(stderr, "Message checksum failure\n");
164 	return -EINVAL;
165     }
166     (*len)--;
167 
168     mi->rsAddr = msg[0];
169     mi->netfn = msg[1] >> 2;
170     mi->rsLUN = msg[1] & 3;
171     mi->rqAddr = msg[3];
172     mi->seq = msg[4] >> 2;
173     mi->rqLUN = msg[4] & 3;
174     mi->cmd = msg[5];
175     *pos += 6;
176     *len -= 6;
177 
178     return 0;
179 }
180 
181 static unsigned int
format_ipmb_rsp(unsigned char * msg,const unsigned char * omsg,unsigned int omsg_len,struct msg_info * mi)182 format_ipmb_rsp(unsigned char *msg, const unsigned char *omsg,
183 		unsigned int omsg_len, struct msg_info *mi)
184 {
185     unsigned int msg_len;
186 
187     msg[0] = mi->rqAddr;
188     msg[1] = (mi->netfn << 2) | mi->rqLUN;
189     msg[2] = ipmb_checksum(msg, 2);
190     msg[3] = mi->rsAddr;
191     msg[4] = (mi->seq << 2) | mi->rsLUN;
192     msg[5] = mi->cmd;
193     memcpy(msg+6, omsg, omsg_len);
194     msg_len = omsg_len + 6;
195     msg[msg_len] = ipmb_checksum(msg + 3, msg_len - 3);
196     msg_len++;
197 
198     return msg_len;
199 }
200 
201 static void
queue_ipmb(struct msg * imsg,struct msg_info * mi)202 queue_ipmb(struct msg *imsg, struct msg_info *mi)
203 {
204     imsg->next = NULL;
205     if (mi->ipmb_q_tail)
206 	mi->ipmb_q_tail->next = imsg;
207     else
208 	mi->ipmb_q = imsg;
209     mi->ipmb_q_tail = imsg;
210     if (mi->do_attn)
211 	socket_send(mi->attn_chars, mi->attn_chars_len, mi);
212 }
213 
214 static void
queue_event(struct msg * emsg,struct msg_info * mi)215 queue_event(struct msg *emsg, struct msg_info *mi)
216 {
217     emsg->next = NULL;
218     if (mi->event_q_tail)
219 	mi->event_q_tail->next = emsg;
220     else
221 	mi->event_q = emsg;
222     mi->event_q_tail = emsg;
223     if (mi->do_attn)
224 	socket_send(mi->attn_chars, mi->attn_chars_len, mi);
225 }
226 
227 /***********************************************************************
228  *
229  * Radisys ASCII codec.
230  *
231  ***********************************************************************/
232 
233 #define RA_MAX_CHARS_SIZE (((IPMI_MAX_MSG_LENGTH + 1) * 3) + 4)
234 
235 struct ra_data {
236     unsigned char recv_chars[RA_MAX_CHARS_SIZE];
237     unsigned int  recv_chars_len;
238     int           recv_chars_too_many;
239 };
240 
ra_format_msg(const unsigned char * msg,unsigned int msg_len,struct msg_info * mi)241 static void ra_format_msg(const unsigned char *msg, unsigned int msg_len,
242 			  struct msg_info *mi)
243 {
244     unsigned int i;
245     unsigned int len;
246     unsigned char c[RA_MAX_CHARS_SIZE];
247 
248     len = 0;
249     for (i = 0; i < msg_len; i++) {
250 	c[len] = hex2char[msg[i] >> 4];
251 	len++;
252 	c[len] = hex2char[msg[i] & 0xf];
253 	len++;
254     }
255     c[len] = 0x0d;
256     len++;
257 
258     socket_send(c, len, mi);
259 }
260 
261 static void
ra_ipmb_handler(struct msg * imsg,struct msg_info * mi)262 ra_ipmb_handler(struct msg *imsg, struct msg_info *mi)
263 {
264     ra_format_msg(imsg->data, imsg->data_len, mi);
265     free(imsg);
266 }
267 
268 /*
269  * Called when the '0x0d' is seen.
270  */
ra_unformat_msg(unsigned char * r,unsigned int len,struct msg_info * mi)271 static int ra_unformat_msg(unsigned char *r, unsigned int len,
272 			   struct msg_info *mi)
273 {
274     unsigned char o[IPMI_MAX_MSG_LENGTH];
275     unsigned int p = 0;
276     unsigned int i = 0;
277     int          rv;
278 
279     while (p < len) {
280 	rv = fromhex(r[p]);
281 	if (rv < 0)
282 	    return rv;
283 	o[i] = rv << 4;
284 	p++;
285 	if (p >= len)
286 	    return -EINVAL;
287 	rv = fromhex(r[p]);
288 	if (rv < 0)
289 	    return rv;
290 	o[i] |= rv;
291 	p++;
292 	i++;
293     }
294 
295     p = 0;
296     rv = unformat_ipmb_msg(o, &p, &i, mi);
297     if (rv)
298 	return rv;
299     if ((mi->rsAddr == mi->my_ipmb) || (mi->rsAddr == 1))
300 	handle_msg(o + p, i, mi);
301     else
302 	handle_ipmb_msg(o + p, i, mi, mi);
303     return 0;
304 }
305 
306 static void
ra_handle_char(unsigned char ch,struct msg_info * mi)307 ra_handle_char(unsigned char ch, struct msg_info *mi)
308 {
309     struct ra_data *info = mi->info;
310     unsigned int len = info->recv_chars_len;
311     unsigned char *r;
312     int           rv;
313 
314     if (ch == 0x0d) {
315 	/* End of command, handle it. */
316 	if (info->recv_chars_too_many) {
317 	    /* Input data overrun. */
318 	    fprintf(stderr, "Data overrun\n");
319 	    info->recv_chars_too_many = 0;
320 	    info->recv_chars_len = 0;
321 	    return;
322 	}
323 	rv = ra_unformat_msg(info->recv_chars, info->recv_chars_len, mi);
324 	info->recv_chars_too_many = 0;
325 	info->recv_chars_len = 0;
326 	if (rv) {
327 	    /* Bad input data. */
328 	    fprintf(stderr, "Bad input data\n");
329 	    return;
330 	}
331 	return;
332     }
333 
334     if (info->recv_chars_too_many)
335 	return;
336 
337     r = info->recv_chars;
338 
339     if (len >= sizeof(info->recv_chars)) {
340 	info->recv_chars_too_many = 1;
341     } else if ((len > 0) && isspace(r[len-1]) && isspace(ch)) {
342 	/* Ignore multiple spaces together. */
343     } else {
344 	r[len] = ch;
345 	info->recv_chars_len++;
346     }
347 }
348 
349 static void
ra_send(unsigned char * omsg,unsigned int omsg_len,struct msg_info * mi)350 ra_send(unsigned char *omsg, unsigned int omsg_len, struct msg_info *mi)
351 {
352     unsigned char msg[IPMI_MAX_MSG_LENGTH + 7];
353     unsigned int msg_len;
354 
355     msg_len = format_ipmb_rsp(msg, omsg, omsg_len, mi);
356 
357     ra_format_msg(msg, msg_len, mi);
358 }
359 
360 static void *
ra_setup(void)361 ra_setup(void)
362 {
363     struct ra_data *info;
364 
365     info = malloc(sizeof(*info));
366     if (!info)
367 	return NULL;
368 
369     info->recv_chars_len = 0;
370     info->recv_chars_too_many = 0;
371     return info;
372 }
373 
374 /***********************************************************************
375  *
376  * Direct Mode codec.
377  *
378  ***********************************************************************/
379 
380 #define DM_START_CHAR		0xA0
381 #define DM_STOP_CHAR		0xA5
382 #define DM_PACKET_HANDSHAKE	0xA6
383 #define DM_DATA_ESCAPE_CHAR	0xAA
384 
385 struct dm_data {
386     unsigned char recv_msg[IPMI_MAX_MSG_LENGTH + 4];
387     unsigned int  recv_msg_len;
388     int           recv_msg_too_many;
389     int           in_recv_msg;
390     int           in_escape;
391 };
392 
393 static void
dm_handle_msg(unsigned char * msg,unsigned int len,struct msg_info * mi)394 dm_handle_msg(unsigned char *msg, unsigned int len, struct msg_info *mi)
395 {
396     int rv;
397     unsigned int pos;
398 
399     pos = 0;
400     rv = unformat_ipmb_msg(msg, &pos, &len, mi);
401     if (rv)
402 	return;
403     handle_msg(msg + pos, len, mi);
404 }
405 
406 static void
dm_handle_char(unsigned char ch,struct msg_info * mi)407 dm_handle_char(unsigned char ch, struct msg_info *mi)
408 {
409     struct dm_data *info = mi->info;
410     unsigned int len = info->recv_msg_len;
411     unsigned char c;
412 
413     switch (ch) {
414     case DM_START_CHAR:
415 	if (info->in_recv_msg)
416 	    fprintf(stderr, "Msg started in the middle of another\n");
417 	info->in_recv_msg = 1;
418 	info->recv_msg_len = 0;
419 	info->recv_msg_too_many = 0;
420 	info->in_escape = 0;
421 	break;
422 
423     case DM_STOP_CHAR:
424 	if (!info->in_recv_msg)
425 	    fprintf(stderr, "Empty message\n");
426 	else if (info->in_escape) {
427 	    info->in_recv_msg = 0;
428 	    fprintf(stderr, "Message ended in escape\n");
429 	} else if (info->recv_msg_too_many) {
430 	    fprintf(stderr, "Message too long\n");
431 	    info->in_recv_msg = 0;
432 	} else {
433 	    dm_handle_msg(info->recv_msg, info->recv_msg_len, mi);
434 	    info->in_recv_msg = 0;
435 	}
436 	info->in_escape = 0;
437 
438 	c = DM_PACKET_HANDSHAKE;
439 	socket_send(&c, 1, mi);
440 	break;
441 
442     case DM_PACKET_HANDSHAKE:
443 	info->in_escape = 0;
444 	break;
445 
446     case DM_DATA_ESCAPE_CHAR:
447 	if (!info->recv_msg_too_many)
448 	    info->in_escape = 1;
449 	break;
450 
451     default:
452 	if (!info->in_recv_msg)
453 	    /* Ignore characters outside of messages. */
454 	    break;
455 
456 	if (info->in_escape) {
457 	    info->in_escape = 0;
458 	    switch (ch) {
459 	    case 0xB0: ch = DM_START_CHAR; break;
460 	    case 0xB5: ch = DM_STOP_CHAR; break;
461 	    case 0xB6: ch = DM_PACKET_HANDSHAKE; break;
462 	    case 0xBA: ch = DM_DATA_ESCAPE_CHAR; break;
463 	    case 0x3B: ch = 0x1b; break;
464 	    default:
465 		fprintf(stderr, "Invalid escape char: 0x%x\n", ch);
466 		info->recv_msg_too_many = 1;
467 		return;
468 	    }
469 	}
470 
471 	if (!info->recv_msg_too_many) {
472 	    if (len >= sizeof(info->recv_msg)) {
473 		info->recv_msg_too_many = 1;
474 		break;
475 	    }
476 
477 	    info->recv_msg[len] = ch;
478 	    info->recv_msg_len++;
479 	}
480 	break;
481     }
482 }
483 
484 static void
dm_send(unsigned char * omsg,unsigned int omsg_len,struct msg_info * mi)485 dm_send(unsigned char *omsg, unsigned int omsg_len, struct msg_info *mi)
486 {
487     unsigned int i;
488     unsigned int len = 0;
489     unsigned char c[(IPMI_MAX_MSG_LENGTH + 7) * 2];
490     unsigned char msg[IPMI_MAX_MSG_LENGTH + 7];
491     unsigned int msg_len;
492 
493     msg_len = format_ipmb_rsp(msg, omsg, omsg_len, mi);
494 
495     c[len++] = 0xA0;
496     for (i = 0; i < msg_len; i++) {
497 	switch (msg[i]) {
498 	case 0xA0:
499 	    c[len++] = 0xAA;
500 	    c[len++] = 0xB0;
501 	    break;
502 
503 	case 0xA5:
504 	    c[len++] = 0xAA;
505 	    c[len++] = 0xB5;
506 	    break;
507 
508 	case 0xA6:
509 	    c[len++] = 0xAA;
510 	    c[len++] = 0xB6;
511 	    break;
512 
513 	case 0xAA:
514 	    c[len++] = 0xAA;
515 	    c[len++] = 0xBA;
516 	    break;
517 
518 	case 0x1B:
519 	    c[len++] = 0xAA;
520 	    c[len++] = 0x3B;
521 	    break;
522 
523 	default:
524 	    c[len++] = msg[i];
525 	}
526 
527     }
528     c[len++] = 0xA5;
529 
530     socket_send(c, len, mi);
531 }
532 
533 static void *
dm_setup(void)534 dm_setup(void)
535 {
536     struct dm_data *info;
537 
538     info = malloc(sizeof(*info));
539     if (!info)
540 	return NULL;
541     memset(info, 0, sizeof(*info));
542     return info;
543 }
544 
545 
546 /***********************************************************************
547  *
548  * Terminal Mode codec.
549  *
550  ***********************************************************************/
551 
552 #define TM_MAX_CHARS_SIZE (((IPMI_MAX_MSG_LENGTH + 1) * 3) + 4)
553 
554 struct tm_data {
555     unsigned char recv_chars[TM_MAX_CHARS_SIZE];
556     unsigned int  recv_chars_len;
557     int           recv_chars_too_many;
558 };
559 
tm_format_msg(const unsigned char * msg,unsigned int msg_len,struct msg_info * mi)560 static void tm_format_msg(const unsigned char *msg, unsigned int msg_len,
561 			  struct msg_info *mi)
562 {
563     unsigned int i;
564     unsigned int len;
565     unsigned char c[TM_MAX_CHARS_SIZE];
566     unsigned char t;
567 
568     len = 0;
569     c[len] = '[';
570     len++;
571 
572     t = mi->netfn << 2 | mi->rqLUN;
573     c[len] = hex2char[t >> 4];
574     len++;
575     c[len] = hex2char[t & 0xf];
576     len++;
577 
578     /*
579      * Insert the sequence number and bridge bits.  Bridge bits
580      * are always zero.
581      */
582     t = mi->seq << 2;
583     c[len] = hex2char[t >> 4];
584     len++;
585     c[len] = hex2char[t & 0xf];
586     len++;
587 
588     c[len] = hex2char[mi->cmd >> 4];
589     len++;
590     c[len] = hex2char[mi->cmd & 0xf];
591     len++;
592 
593     /* Now the rest of the message. */
594     for (i = 0; ; ) {
595 	c[len] = hex2char[msg[i] >> 4];
596 	len++;
597 	c[len] = hex2char[msg[i] & 0xf];
598 	len++;
599 	i++;
600 	if (i == msg_len)
601 	    break;
602 	c[len] = ' ';
603 	len++;
604     }
605     c[len] = ']';
606     len++;
607     c[len] = 0x0a;
608     len++;
609 
610     socket_send(c, len, mi);
611 }
612 
613 /*
614  * Called when the ']' is seen, the leading '[' is removed, too.  We
615  * get this with a leading space and no more than one space between
616  * items.
617  */
tm_unformat_msg(unsigned char * r,unsigned int len,struct msg_info * mi)618 static int tm_unformat_msg(unsigned char *r, unsigned int len,
619 			   struct msg_info *mi)
620 {
621     unsigned char o[IPMI_MAX_MSG_LENGTH];
622     unsigned int p = 0;
623     unsigned int i = 0;
624     int          rv;
625 
626 #define SKIP_SPACE if (isspace(r[p])) p++
627 #define ENSURE_MORE if (p >= len) return -EINVAL
628 
629 	SKIP_SPACE;
630 	while (p < len) {
631 		if (i >= sizeof(o))
632 			return -EFBIG;
633 		ENSURE_MORE;
634 		rv = fromhex(r[p]);
635 		if (rv < 0)
636 			return rv;
637 		o[i] = rv << 4;
638 		p++;
639 		ENSURE_MORE;
640 		rv = fromhex(r[p]);
641 		if (rv < 0)
642 			return rv;
643 		o[i] |= rv;
644 		p++;
645 		i++;
646 		SKIP_SPACE;
647 	}
648 
649 	if (i < 3)
650 	    return -EINVAL;
651 
652 	mi->netfn = o[0] >> 2;
653 	mi->rqLUN = o[0] & 3;
654 	mi->seq = o[1] >> 2;
655 	mi->cmd = o[2];
656 	handle_msg(o+3, i-3, mi);
657 	return 0;
658 #undef SKIP_SPACE
659 #undef ENSURE_MORE
660 }
661 
662 static void
tm_handle_char(unsigned char ch,struct msg_info * mi)663 tm_handle_char(unsigned char ch, struct msg_info *mi)
664 {
665     struct tm_data *info = mi->info;
666     unsigned int len = info->recv_chars_len;
667     unsigned char *r;
668     int           rv;
669 
670     if (ch == '[') {
671 	/*
672 	 * Start of a command.  Note that if a command is
673 	 * already in progress (len != 0) we abort it.
674 	 */
675 	if (len != 0)
676 	    fprintf(stderr, "Msg started in the middle of another\n");
677 
678 	/* Convert the leading '[' to a space, that's innocuous. */
679 	info->recv_chars[0] = ' ';
680 	info->recv_chars_len = 1;
681 	info->recv_chars_too_many = 0;
682 	return;
683     }
684 
685     if (len == 0)
686 	/* Ignore everything outside [ ]. */
687 	return;
688 
689     if (ch == ']') {
690 	/* End of command, handle it. */
691 	if (info->recv_chars_too_many) {
692 	    /* Input data overrun. */
693 	    fprintf(stderr, "Data overrun\n");
694 	    info->recv_chars_too_many = 0;
695 	    info->recv_chars_len = 0;
696 	    return;
697 	}
698 	rv = tm_unformat_msg(info->recv_chars, info->recv_chars_len, mi);
699 	info->recv_chars_too_many = 0;
700 	info->recv_chars_len = 0;
701 	if (rv) {
702 	    /* Bad input data. */
703 	    fprintf(stderr, "Bad input data\n");
704 	    return;
705 	}
706 	return;
707     }
708 
709     if (info->recv_chars_too_many)
710 	return;
711 
712     r = info->recv_chars;
713 
714     if (len >= sizeof(info->recv_chars)) {
715 	info->recv_chars_too_many = 1;
716     } else if ((len > 0) && isspace(r[len-1]) && isspace(ch)) {
717 	/* Ignore multiple spaces together. */
718     } else {
719 	r[len] = ch;
720 	info->recv_chars_len++;
721     }
722 }
723 
724 static void
tm_send(unsigned char * msg,unsigned int msg_len,struct msg_info * mi)725 tm_send(unsigned char *msg, unsigned int msg_len, struct msg_info *mi)
726 {
727     tm_format_msg(msg, msg_len, mi);
728 }
729 
730 static void *
tm_setup(void)731 tm_setup(void)
732 {
733     struct tm_data *info;
734 
735     info = malloc(sizeof(*info));
736     if (!info)
737 	return NULL;
738 
739     info->recv_chars_len = 0;
740     info->recv_chars_too_many = 0;
741     return info;
742 }
743 
744 
745 /***********************************************************************
746  *
747  * codec structure
748  *
749  ***********************************************************************/
750 struct codec codecs[] = {
751     { "TerminalMode",
752       tm_handle_char, tm_send, tm_setup, queue_event, queue_ipmb },
753     { "Direct",
754       dm_handle_char, dm_send, dm_setup, queue_event, queue_ipmb },
755     { "RadisysAscii",
756       ra_handle_char, ra_send, ra_setup, NULL, ra_ipmb_handler },
757     { NULL }
758 };
759 
760 
761 static void
socket_send(const unsigned char * data,unsigned int len,struct msg_info * mi)762 socket_send(const unsigned char *data, unsigned int len, struct msg_info *mi)
763 {
764     int rv;
765     unsigned int i;
766 
767     if (mi->debug > 0) {
768 	printf("Sock send:");
769 	for (i=0; i<len; i++) {
770 	    if ((i % 16) == 0)
771 		printf("\n  ");
772 	    printf(" %2.2x(%c)", data[i], isprint(data[i]) ? data[i] : ' ');
773 	}
774 	printf("\n");
775     }
776 
777  restart:
778     rv = write(mi->sock, data, len);
779     if (rv < 0) {
780 	perror("write");
781 	return;
782     } else if (((unsigned int) rv) < len) {
783 	len -= rv;
784 	data += rv;
785 	goto restart;
786     }
787 }
788 
789 #define IPMI_APP_NETFN	6
790 #define IPMI_GET_DEV_ID_CMD	0x01
791 #define IPMI_GET_DEVICE_GUID_CMD 0x08
792 #define IPMI_SET_BMC_GLOBAL_ENABLES_CMD	0x2e
793 #define IPMI_GET_BMC_GLOBAL_ENABLES_CMD	0x2f
794 #define IPMI_GET_MSG_FLAGS_CMD	0x31
795 #define IPMI_GET_MSG_CMD	0x33
796 #define IPMI_SEND_MSG_CMD	0x34
797 #define IPMI_READ_EVENT_MSG_CMD	0x35
798 #define IPMI_OEM_NETFN	0x2e
799 
800 static unsigned char ipmb_devid_data[] = {
801     0x00, 0x01, 0x00, 0x48, 0x02, 0x9f, 0xaa, 0x01, 0x00, 0x23, 0x00,
802     0x00, 0x11, 0x00, 0x04
803 };
804 
805 static void
handle_ipmb_msg(const unsigned char * msg,unsigned int len,struct msg_info * mi,struct msg_info * top_mi)806 handle_ipmb_msg(const unsigned char *msg, unsigned int len,
807 		struct msg_info *mi, struct msg_info *top_mi)
808 {
809     struct msg *imsg;
810     unsigned char rsp[IPMI_MAX_MSG_LENGTH];
811     unsigned int rsp_len;
812     unsigned int i;
813 
814     imsg = malloc(sizeof(*imsg));
815     if (!imsg)
816 	return;
817 
818     if (top_mi->debug > 0) {
819 	printf("Recv IPMB Msg (%x:%x):", mi->netfn, mi->cmd);
820 	for (i=0; i<len; i++) {
821 	    if ((i % 16) == 0)
822 		printf("\n  ");
823 	    printf(" %2.2x(%c)", msg[i], isprint(msg[i]) ? msg[i] : ' ');
824 	}
825 	printf("\n");
826     }
827 
828     if (mi->netfn == IPMI_APP_NETFN) {
829 	switch (mi->cmd) {
830 	case IPMI_GET_DEV_ID_CMD:
831 	    rsp[0] = 0;
832 	    memcpy(rsp+1, ipmb_devid_data, sizeof(ipmb_devid_data));
833 	    rsp_len = sizeof(ipmb_devid_data) + 1;
834 	    break;
835 	default:
836 	    goto invalid_msg;
837 	}
838     } else
839 	goto invalid_msg;
840 
841  send_rsp:
842     /* Convert to response. */
843     mi->netfn |= 1;
844     imsg->data_len = format_ipmb_rsp(imsg->data, rsp, rsp_len, mi);
845     top_mi->codec->handle_ipmb(imsg, top_mi);
846     return;
847 
848  invalid_msg:
849     rsp[0] = 0xc1;
850     rsp_len = 1;
851     goto send_rsp;
852 }
853 
854 static unsigned char devid_data[] = {
855     0x20, 0x01, 0x00, 0x48, 0x02, 0x9f, 0x22, 0x03, 0x00, 0x11, 0x43,
856     0x00, 0x11, 0x00, 0x04
857 };
858 
859 static unsigned char guid_data[] = {
860     0x00, 0x01, 0x00, 0x48, 0x02, 0x9f, 0xaa, 0x01,
861     0x00, 0x23, 0x00, 0x00, 0x11, 0x00, 0x04, 0x99
862 };
863 
864 static void
handle_msg(const unsigned char * msg,unsigned int len,struct msg_info * mi)865 handle_msg(const unsigned char *msg, unsigned int len, struct msg_info *mi)
866 {
867     unsigned int i;
868     unsigned char rsp[IPMI_MAX_MSG_LENGTH];
869     unsigned int rsp_len;
870     struct msg *m;
871     int rv;
872     struct msg_info nmi;
873     unsigned int p;
874 
875     if (mi->debug > 0) {
876 	printf("Recv Msg (%x:%x):", mi->netfn, mi->cmd);
877 	for (i=0; i<len; i++) {
878 	    if ((i % 16) == 0)
879 		printf("\n  ");
880 	    printf(" %2.2x(%c)", msg[i], isprint(msg[i]) ? msg[i] : ' ');
881 	}
882 	printf("\n");
883     }
884 
885     if (mi->oem) {
886 	rv = mi->oem->handler(msg, len, mi, rsp, &rsp_len);
887 	if (!rv)
888 	    goto send_rsp;
889     }
890 
891     if (mi->netfn == IPMI_APP_NETFN) {
892 	switch (mi->cmd) {
893 	case IPMI_GET_DEV_ID_CMD:
894 	    rsp[0] = 0;
895 	    memcpy(rsp+1, devid_data, sizeof(devid_data));
896 	    rsp_len = sizeof(devid_data) + 1;
897 	    break;
898 
899 	case IPMI_GET_DEVICE_GUID_CMD:
900 	    rsp[0] = 0;
901 	    memcpy(rsp+1, guid_data, sizeof(guid_data));
902 	    rsp_len = sizeof(guid_data) + 1;
903 	    break;
904 
905 	case IPMI_GET_MSG_FLAGS_CMD:
906 	    rsp[0] = 0;
907 	    rsp[1] = 0;
908 	    if (mi->event_q)
909 		rsp[1] |= 2;
910 	    if (mi->ipmb_q)
911 		rsp[1] |= 1;
912 	    rsp_len = 2;
913 	    break;
914 
915 	case IPMI_GET_MSG_CMD:
916 	    if (!mi->ipmb_q) {
917 		rsp[0] = 0x80;
918 		rsp_len = 1;
919 		break;
920 	    }
921 	    m = mi->ipmb_q;
922 	    mi->ipmb_q = m->next;
923 	    if (!mi->ipmb_q)
924 		mi->ipmb_q_tail = NULL;
925 
926 	    rsp[0] = 0;
927 	    rsp[1] = 0; /* Channel # */
928 	    /* Note we don't put our slave address in the response, as
929 	       that is what get smg expects. */
930 	    memcpy(rsp + 2, m->data + 1, m->data_len - 1);
931 	    rsp_len = 2 + m->data_len - 1;
932 	    free(m);
933 	    break;
934 
935 	case IPMI_SEND_MSG_CMD:
936 	    if (msg[0] != 0) {
937 		rsp[0] = 0xcc;
938 		rsp_len = 1;
939 		break;
940 	    }
941 	    p = 1;
942 	    len -= 1;
943 	    rv = unformat_ipmb_msg(msg, &p, &len, &nmi);
944 	    if (rv) {
945 		rsp[0] = 0xcc;
946 		rsp_len = 1;
947 		break;
948 	    }
949 	    if (nmi.netfn & 1) {
950 		/* Ignore responses */
951 		rsp[0] = 0;
952 		rsp_len = 1;
953 		break;
954 	    }
955 	    handle_ipmb_msg(msg+p, len, &nmi, mi);
956 	    rsp[0] = 0;
957 	    rsp_len = 1;
958 	    break;
959 
960 	case IPMI_SET_BMC_GLOBAL_ENABLES_CMD:
961 	    if (len < 1) {
962 		rsp[0] = 0xcc;
963 		rsp_len = 1;
964 		break;
965 	    }
966 
967 	    if ((msg[0] & ~SUPPORTED_GLOBAL_ENABLES) != 0) {
968 		rsp[0] = 0xcc;
969 		rsp_len = 1;
970 		break;
971 	    }
972 
973 	    mi->global_enables = msg[0];
974 
975 	    rsp[0] = 0;
976 	    rsp_len = 1;
977 	    break;
978 
979 	case IPMI_GET_BMC_GLOBAL_ENABLES_CMD:
980 	    rsp[0] = 0;
981 	    rsp[1] = mi->global_enables;
982 	    rsp_len = 2;
983 	    break;
984 
985 	case IPMI_READ_EVENT_MSG_CMD:
986 	    if (!mi->event_q) {
987 		rsp[0] = 0x80;
988 		rsp_len = 1;
989 		break;
990 	    }
991 	    m = mi->event_q;
992 	    mi->event_q = m->next;
993 	    if (!mi->event_q)
994 		mi->event_q_tail = NULL;
995 
996 	    rsp[0] = 0;
997 	    memcpy(rsp + 1, m->data, m->data_len);
998 	    rsp_len = 1 + m->data_len;
999 	    free(m);
1000 	    break;
1001 
1002 	default:
1003 	    goto invalid_msg;
1004 	}
1005     } else
1006 	goto invalid_msg;
1007 
1008  send_rsp:
1009     /* Convert to response. */
1010     mi->netfn |= 1;
1011     mi->codec->send(rsp, rsp_len, mi);
1012     return;
1013 
1014  invalid_msg:
1015     rsp[0] = 0xc1;
1016     rsp_len = 1;
1017     goto send_rsp;
1018 }
1019 
1020 #define PP_GET_SERIAL_INTF_CMD	0x01
1021 #define PP_SET_SERIAL_INTF_CMD	0x02
1022 static unsigned char pp_oem_chars[] = { 0x00, 0x40, 0x0a };
1023 static int
pp_oem_handler(const unsigned char * msg,unsigned int len,struct msg_info * mi,unsigned char * rsp,unsigned int * rsp_len)1024 pp_oem_handler(const unsigned char *msg, unsigned int len,
1025 	       struct msg_info *mi,
1026 	       unsigned char *rsp, unsigned int *rsp_len)
1027 {
1028     if ((len < 3) || (memcmp(msg, pp_oem_chars, 3) != 0))
1029 	return -ENOSYS;
1030     msg += 3;
1031     len -= 3;
1032 
1033     if (mi->netfn == IPMI_OEM_NETFN) {
1034 	switch (mi->cmd) {
1035 	case PP_GET_SERIAL_INTF_CMD:
1036 	    rsp[0] = 0;
1037 	    memcpy(rsp+1, pp_oem_chars, 3);
1038 	    rsp[4] = 0;
1039 	    if (msg[0] == 1)
1040 		rsp[4] |= mi->echo;
1041 	    *rsp_len = 5;
1042 	    break;
1043 
1044 	case PP_SET_SERIAL_INTF_CMD:
1045 	    if (len < 2)
1046 		rsp[0] = 0xcc;
1047 	    else if (msg[0] == 1) {
1048 		mi->echo = msg[1] & 1;
1049 		rsp[0] = 0;
1050 	    }
1051 	    memcpy(rsp+1, pp_oem_chars, 3);
1052 	    *rsp_len = 4;
1053 	    break;
1054 
1055 	default:
1056 	    return -ENOSYS;
1057 	}
1058     } else
1059 	return -ENOSYS;
1060 
1061     return 0;
1062 }
1063 
1064 static void
pp_oem_init(struct msg_info * mi)1065 pp_oem_init(struct msg_info *mi)
1066 {
1067     mi->echo = 1;
1068 }
1069 
1070 #define RA_CONTROLLER_OEM_NETFN	0x3e
1071 #define RA_GET_IPMB_ADDR_CMD	0x12
1072 static int
ra_oem_handler(const unsigned char * msg,unsigned int len,struct msg_info * mi,unsigned char * rsp,unsigned int * rsp_len)1073 ra_oem_handler(const unsigned char *msg, unsigned int len,
1074 	       struct msg_info *mi,
1075 	       unsigned char *rsp, unsigned int *rsp_len)
1076 {
1077     if (mi->netfn == RA_CONTROLLER_OEM_NETFN) {
1078 	switch (mi->cmd) {
1079 	case RA_GET_IPMB_ADDR_CMD:
1080 	    rsp[0] = 0;
1081 	    rsp[1] = mi->my_ipmb;
1082 	    *rsp_len = 2;
1083 	    break;
1084 
1085 	default:
1086 	    return -ENOSYS;
1087 	}
1088     } else if (mi->netfn == IPMI_APP_NETFN) {
1089 	switch (mi->cmd) {
1090 	case IPMI_GET_MSG_FLAGS_CMD:
1091 	    /* No message flag support. */
1092 	    rsp[0] = 0xc1;
1093 	    *rsp_len = 1;
1094 	    break;
1095 
1096 	default:
1097 	    return -ENOSYS;
1098 	}
1099     } else
1100 	return -ENOSYS;
1101 
1102     return 0;
1103 }
1104 
1105 static void
ra_oem_init(struct msg_info * mi)1106 ra_oem_init(struct msg_info *mi)
1107 {
1108 }
1109 
1110 static struct oem_handler oem_handlers[] = {
1111     { "PigeonPoint",		pp_oem_handler,		pp_oem_init },
1112     { "Radisys",		ra_oem_handler,		ra_oem_init },
1113     { NULL }
1114 };
1115 
1116 static char *
next_tok(char ** str)1117 next_tok(char **str)
1118 {
1119     char *rv;
1120     char *s = *str;
1121 
1122     while (isspace(*s))
1123 	s++;
1124     rv = s;
1125     while (*s && (!isspace(*s)))
1126 	s++;
1127     if (*s) {
1128 	*s = '\0';
1129 	s++;
1130     }
1131     *str = s;
1132     if (*rv)
1133 	return rv;
1134     else
1135 	return NULL;
1136 }
1137 
1138 static void
exit_handler(char * line,struct msg_info * mi)1139 exit_handler(char *line, struct msg_info *mi)
1140 {
1141     close(mi->sock);
1142     exit(0);
1143 }
1144 
1145 static void
inc_debug_handler(char * line,struct msg_info * mi)1146 inc_debug_handler(char *line, struct msg_info *mi)
1147 {
1148     mi->debug++;
1149 }
1150 
1151 static void
dec_debug_handler(char * line,struct msg_info * mi)1152 dec_debug_handler(char *line, struct msg_info *mi)
1153 {
1154     if (mi->debug > 0)
1155 	mi->debug--;
1156 }
1157 
1158 static void
event_handler(char * line,struct msg_info * mi)1159 event_handler(char *line, struct msg_info *mi)
1160 {
1161     struct msg *emsg;
1162     int i, p;
1163     unsigned char *m;
1164 
1165     if (!mi->codec->handle_event) {
1166 	printf("This codec does not support event messages\n");
1167 	return;
1168     }
1169 
1170     emsg = malloc(sizeof(*emsg));
1171     if (!emsg) {
1172 	printf("Could not allocate event message\n");
1173 	return;
1174     }
1175 
1176     p = 0;
1177     m = emsg->data;
1178     for (i=0; i<16; i++) {
1179 	char *s, *e;
1180 	s = next_tok(&line);
1181 	if (!s) {
1182 	    printf("Events need 16 bytes of data\n");
1183 	    free(emsg);
1184 	    return;
1185 	}
1186 	m[p++] = strtoul(s, &e, 16);
1187 	if (*e != '\0') {
1188 	    printf("Byte %d was invalid\n", i+1);
1189 	    free(emsg);
1190 	    return;
1191 	}
1192     }
1193     emsg->data_len = 16;
1194 
1195     mi->codec->handle_event(emsg, mi);
1196 }
1197 
1198 static void help_handler(char *line, struct msg_info *mi);
1199 
1200 static const char help_help[] = "This command.";
1201 static const char exit_help[] = "Quit the program.";
1202 static const char quit_help[] = "Quit the program.";
1203 static const char event_help[] =
1204 "Put an event into the event queue. Takes 16 bytes of data like:\n"
1205 "      event 10 20 30 40 50 60 70 80 90 a0 b0 c0 d0 e0 f0 f1";
1206 static const char inc_debug_help[] = "Increment the debugging flag.";
1207 static const char dec_debug_help[] = "Decrement the debugging flag.";
1208 
1209 static struct {
1210     const char *cmd;
1211     void (*handler)(char *line, struct msg_info *mi);
1212     const char *help;
1213 } cmds[] = {
1214     { "help",			help_handler,		help_help },
1215     { "exit",			exit_handler,		exit_help },
1216     { "quit",			exit_handler,		quit_help },
1217     { "event",			event_handler,		event_help },
1218     { "debug+",			inc_debug_handler,	inc_debug_help },
1219     { "debug-",			dec_debug_handler,	dec_debug_help },
1220     { NULL }
1221 };
1222 
1223 static void
help_handler(char * line,struct msg_info * mi)1224 help_handler(char *line, struct msg_info *mi)
1225 {
1226     int i;
1227     printf("Valid commands:");
1228     for (i=0; cmds[i].cmd; i++)
1229 	printf("  %s - %s\n", cmds[i].cmd, cmds[i].help);
1230 }
1231 
1232 static struct msg_info main_mi;
1233 
1234 static void
command_string_handler(char * cmdline)1235 command_string_handler(char *cmdline)
1236 {
1237     char *expansion = NULL;
1238     int result;
1239     int i;
1240     char *s, *cmd;
1241 
1242     if (cmdline == NULL) {
1243 	printf("\n");
1244 	exit_handler(NULL, &main_mi);
1245     }
1246 
1247     result = history_expand(cmdline, &expansion);
1248     if (result < 0 || result == 2) {
1249 	fprintf(stderr, "%s\n", expansion);
1250     } else if (expansion && strlen(expansion)){
1251 	add_history(expansion);
1252 
1253 	s = expansion;
1254 	cmd = next_tok(&s);
1255 	if (cmd) {
1256 	    /* Extract the command. */
1257 	    for (i=0; cmds[i].cmd != NULL; i++) {
1258 		if (strcmp(cmd, cmds[i].cmd) == 0)
1259 		    break;
1260 	    }
1261 	    if (cmds[i].cmd) {
1262 		cmds[i].handler(s, &main_mi);
1263 	    } else {
1264 		printf("Unknown command: '%s'\n", cmd);
1265 	    }
1266 	}
1267     }
1268     if (expansion)
1269 	free(expansion);
1270 }
1271 
1272 struct option options[] = {
1273     { "codec",		 1, NULL, 'c' },
1274     { "ipmb_addr",	 1, NULL, 'a' },
1275     { "oem_setup",	 1, NULL, 'o' },
1276     { "debug",		 0, NULL, 'd' },
1277     { "attn",		 2, NULL, 't' },
1278     { 0 }
1279 };
1280 
1281 static char *usage_str =
1282 "%s [options] <server> <port>\n"
1283 "  Emulate various IPMI serial port BMCs, primarily for testing the\n"
1284 "  IPMI driver.\n"
1285 "  Options are:\n"
1286 "   -c <codec>, --codec <codec> - Set the codec to use.  Valid codecs\n"
1287 "     are:\n"
1288 "        TerminalMode - Standard terminal mode\n"
1289 "        Direct - standard serial direct mode\n"
1290 "        RadisysAscii - Radisys defined ASCII\n"
1291 "   -a <addr>, --ipmb_addr <addr> - Set the IPMB address for the emulated\n"
1292 "     BMC.\n"
1293 "   -o <oem>, --oem_setup <oem> - Emulate certain OEM commands:\n"
1294 "     PigeonPoint - Emulate echo handling per the PigeonPoint IPMCs,\n"
1295 "         primarily for terminal mode.\n"
1296 "     Radisys - Emulate the Radisys method for fetching the IPMB address.\n"
1297 "   --attn[=<char>[,<char>[,...]]] - Set the attention characters to\n"
1298 "     the given value.  This is sent whenever something is added to the\n"
1299 "     event or receive message queue.  It defaults to one BELL character,\n"
1300 "     which is 0x07.  The specified values are numbers, like 0x07.\n"
1301 "     For direct mode using the ASCII escape, this would be 0x1b.  For\n"
1302 "     direct mode on the Sun CPxxxx, this would be 0xAA,0x47.\n"
1303 "   -d, --debug - Increment the debug setting\n"
1304 "  This program connects to a remote TCP port, so you need to have a\n"
1305 "  terminal server (in raw mode, not telnet mode) to use this program.\n"
1306 "  I use ser2net, get that if you need it.\n";
1307 char *cmdname;
1308 static void
usage(void)1309 usage(void)
1310 {
1311     printf(usage_str, cmdname);
1312     exit(1);
1313 }
1314 
1315 int
main(int argc,char * argv[])1316 main(int argc, char *argv[])
1317 {
1318     unsigned int i;
1319     struct addrinfo hints, *res0;
1320     struct sockaddr_storage saddr;
1321     struct sockaddr *addr = (struct sockaddr *) &saddr;
1322     size_t addrlen;
1323     struct msg_info *mi = &main_mi;
1324     int rv;
1325     char *s, *e;
1326 
1327     cmdname = argv[0];
1328 
1329     memset(mi, 0, sizeof(*mi));
1330     mi->my_ipmb = 0x20;
1331     mi->codec = &(codecs[0]);
1332 
1333     for (;;) {
1334 	int f;
1335 	f = getopt_long(argc, argv, "c:o:a:d", options, NULL);
1336 	if (f == -1)
1337 	    break;
1338 
1339 	switch (f) {
1340 	case 'c':
1341 	    for (i=0; codecs[i].name; i++) {
1342 		if (strcmp(codecs[i].name, optarg) == 0)
1343 		    break;
1344 	    }
1345 	    if (codecs[i].name)
1346 		mi->codec = &(codecs[i]);
1347 	    else {
1348 		fprintf(stderr, "Invalid codec: %s\n", optarg);
1349 		usage();
1350 	    }
1351 	    break;
1352 
1353 	case 'd':
1354 	    mi->debug++;
1355 	    break;
1356 
1357 	case 'a':
1358 	    mi->my_ipmb = strtoul(optarg, NULL, 0);
1359 	    break;
1360 
1361 	case 't':
1362 	    mi->do_attn = 1;
1363 	    if (optarg) {
1364 		s = optarg;
1365 		for (i=0; ; i++) {
1366 		    if (i >= sizeof(mi->attn_chars)) {
1367 			fprintf(stderr, "Too many attention characters\n");
1368 			usage();
1369 		    }
1370 		    mi->attn_chars[i] = strtoul(s, &e, 0);
1371 		    mi->attn_chars_len++;
1372 		    if (*e == '\0')
1373 			break;
1374 		    else if (*e == ',')
1375 			s = e + 1;
1376 		    else {
1377 			fprintf(stderr, "Invalid attention characters\n");
1378 			usage();
1379 		    }
1380 		}
1381 	    } else {
1382 		mi->attn_chars[0] = 0x07;
1383 		mi->attn_chars_len = 1;
1384 	    }
1385 	    break;
1386 
1387 	case 'o':
1388 	    for (i=0; oem_handlers[i].name != NULL; i++) {
1389 		if (strcmp(optarg, oem_handlers[i].name) == 0)
1390 		    break;
1391 	    }
1392 	    if (oem_handlers[i].name) {
1393 		mi->oem = &(oem_handlers[i]);
1394 		mi->oem->init(mi);
1395 	    } else {
1396 		fprintf(stderr, "Invalid OEM handler '%s'\n", optarg);
1397 		usage();
1398 	    }
1399 	    break;
1400 
1401 	default:
1402 	    fprintf(stderr, "Invalid flag: '%c'\n", optopt);
1403 	    usage();
1404 	}
1405     }
1406 
1407     i = optind;
1408     if (i+2 < ((unsigned int) argc)) {
1409 	fprintf(stderr, "Host and/or port not supplied\n");
1410 	usage();
1411     }
1412 
1413     memset(&hints, 0, sizeof(hints));
1414     hints.ai_socktype = SOCK_STREAM;
1415     hints.ai_family = AF_UNSPEC;
1416     rv = getaddrinfo(argv[i], argv[i+1], &hints, &res0);
1417     if (rv) {
1418 	perror("getaddrinfo");
1419 	usage();
1420     }
1421     /* Only get the first choices */
1422     memcpy(addr, res0->ai_addr, res0->ai_addrlen);
1423     addrlen = res0->ai_addrlen;
1424     freeaddrinfo(res0);
1425 
1426     mi->sock = socket(addr->sa_family, SOCK_STREAM, 0);
1427     if (mi->sock < 0) {
1428 	perror("socket");
1429 	usage();
1430     }
1431 
1432     rv = connect(mi->sock, (struct sockaddr *) addr, addrlen);
1433     if (rv < 0) {
1434 	perror("connect");
1435 	usage();
1436     }
1437 
1438     i = 1;
1439     if (setsockopt(mi->sock, IPPROTO_TCP, TCP_NODELAY,
1440 		   (char *) &i, sizeof(i)) == -1) {
1441 	perror("setsockopt TCP_NODELAY");
1442 	usage();
1443     }
1444 
1445     mi->info = mi->codec->setup();
1446     if (!mi->info) {
1447 	fprintf(stderr, "Out of memory\n");
1448 	usage();
1449     }
1450 
1451     printf("Starting IPMI serial BMC emulator with:\n  %s codec"
1452 	   "\n  %s OEM emulation\n",
1453 	   mi->codec->name, mi->oem ? mi->oem->name : "no");
1454     if (mi->do_attn) {
1455 	printf("  attention chars:");
1456 	for (i=0; i<mi->attn_chars_len; i++)
1457 	    printf(" %2.2x", mi->attn_chars[i]);
1458 	printf("\n");
1459     }
1460     stifle_history(500);
1461     rl_callback_handler_install("> ", command_string_handler);
1462 
1463     for (;;) {
1464 	unsigned char buf[128];
1465 	int i;
1466 	fd_set readfds;
1467 	int rv2;
1468 
1469 	FD_ZERO(&readfds);
1470 	FD_SET(0, &readfds);
1471 	FD_SET(mi->sock, &readfds);
1472 	rv = select(mi->sock+1, &readfds, NULL, NULL, NULL);
1473 	if (rv < 0) {
1474 	    if (errno != EINTR) {
1475 		perror("select");
1476 		usage();
1477 	    }
1478 	    continue;
1479 	}
1480 
1481 	if (FD_ISSET(mi->sock, &readfds)) {
1482 	    rv = read(mi->sock, buf, sizeof(buf));
1483 	    if (rv < 0) {
1484 		perror("read");
1485 		usage();
1486 	    }
1487 
1488 	    if (mi->debug > 1) {
1489 		printf("recv:");
1490 		for (i=0; i<rv; i++) {
1491 		    if ((i % 16) == 0)
1492 			printf("\n  ");
1493 		    printf(" %2.2x(%c)", buf[i],
1494 			   isprint(buf[i]) ? buf[i] : ' ');
1495 		}
1496 		printf("\n");
1497 	    }
1498 
1499 	    for (i=0; i<rv; i++) {
1500 		/*
1501 		 * Echo one at a time in case the echo gets turned off
1502 		 * in the middle of this data.
1503 		 */
1504 		if (mi->echo) {
1505 		    rv2 = write(mi->sock, buf+i, 1);
1506 		    if (rv2 < 0) {
1507 			perror("write");
1508 			usage();
1509 		    }
1510 		}
1511 		mi->codec->handle_char(buf[i], mi);
1512 	    }
1513 	}
1514 
1515 	if (FD_ISSET(0, &readfds))
1516 	    rl_callback_read_char();
1517     }
1518 }
1519