1 /*
2 * Copyright (c) 2012 Pigeon Point Systems. All Rights Reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * Redistribution of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * Redistribution in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * Neither the name of Pigeon Point Systems nor the names of
16 * contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * This software is provided "AS IS," without a warranty of any kind.
20 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
21 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
22 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
23 * PIGEON POINT SYSTEMS ("PPS") AND ITS LICENSORS SHALL NOT BE LIABLE
24 * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
25 * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
26 * PPS OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
27 * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
28 * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
29 * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
30 * EVEN IF PPS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
31 */
32 #define _GNU_SOURCE 1
33
34 /* Serial Interface, Basic Mode plugin. */
35
36 #include <alloca.h>
37 #include <stdio.h>
38 #include <fcntl.h>
39 #include <time.h>
40 #include <unistd.h>
41 #include <sys/ioctl.h>
42 #include <errno.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <ctype.h>
46 #include <sys/types.h>
47 #include <sys/stat.h>
48 #include <sys/poll.h>
49 #include <termios.h>
50
51 #include <ipmitool/ipmi.h>
52 #include <ipmitool/ipmi_intf.h>
53 #include <ipmitool/helper.h>
54 #include <ipmitool/log.h>
55
56 #if defined(HAVE_CONFIG_H)
57 # include <config.h>
58 #endif
59
60 #define SERIAL_BM_MAX_MSG_SIZE 47
61 #define SERIAL_BM_MAX_RQ_SIZE 33 /* 40 - 7 */
62 #define SERIAL_BM_MAX_RS_SIZE 32 /* 40 - 8 */
63 #define SERIAL_BM_TIMEOUT 5
64 #define SERIAL_BM_RETRY_COUNT 5
65 #define SERIAL_BM_MAX_BUFFER_SIZE 250
66
67 #define BM_START 0xA0
68 #define BM_STOP 0xA5
69 #define BM_HANDSHAKE 0xA6
70 #define BM_ESCAPE 0xAA
71
72 /*
73 * IPMB message header
74 */
75 struct ipmb_msg_hdr {
76 unsigned char rsSA;
77 unsigned char netFn; /* NET FN | RS LUN */
78 unsigned char csum1;
79 unsigned char rqSA;
80 unsigned char rqSeq; /* RQ SEQ | RQ LUN */
81 unsigned char cmd;
82 unsigned char data[0];
83 };
84
85 /*
86 * Send Message command request for IPMB-format
87 */
88 struct ipmi_send_message_rq {
89 unsigned char channel;
90 struct ipmb_msg_hdr msg;
91 };
92
93 /*
94 * Get Message command response for IPMB-format
95 */
96 struct ipmi_get_message_rp {
97 unsigned char completion;
98 unsigned char channel;
99 unsigned char netFn;
100 unsigned char csum1;
101 unsigned char rsSA;
102 unsigned char rqSeq;
103 unsigned char cmd;
104 unsigned char data[0];
105 };
106
107 /*
108 * State for the received message
109 */
110 enum {
111 MSG_NONE,
112 MSG_IN_PROGRESS,
113 MSG_DONE
114 };
115
116 /*
117 * Message parsing context
118 */
119 struct serial_bm_parse_ctx{
120 int state;
121 uint8_t * msg;
122 size_t msg_len;
123 size_t max_len;
124 int escape;
125 };
126
127 /*
128 * Receiving context
129 */
130 struct serial_bm_recv_ctx {
131 char buffer[SERIAL_BM_MAX_BUFFER_SIZE];
132 size_t buffer_size;
133 size_t max_buffer_size;
134 };
135
136 /*
137 * Sending context
138 */
139 struct serial_bm_request_ctx {
140 uint8_t rsSA;
141 uint8_t netFn;
142 uint8_t rqSA;
143 uint8_t rqSeq;
144 uint8_t cmd;
145 };
146
147 /*
148 * Table of supported baud rates
149 */
150 static const struct {
151 int baudinit;
152 int baudrate;
153 } rates[] = {
154 { B2400, 2400 },
155 { B9600, 9600 },
156 { B19200, 19200 },
157 { B38400, 38400 },
158 { B57600, 57600 },
159 { B115200, 115200 },
160 { B230400, 230400 },
161 #ifdef B460800
162 { B460800, 460800 },
163 #endif
164 };
165
166 /*
167 * Table of special characters
168 */
169 static const struct {
170 uint8_t character;
171 uint8_t escape;
172 } characters[] = {
173 { BM_START, 0xB0 }, /* start */
174 { BM_STOP, 0xB5 }, /* stop */
175 { BM_HANDSHAKE, 0xB6 }, /* packet handshake */
176 { BM_ESCAPE, 0xBA }, /* data escape */
177 { 0x1B, 0x3B } /* escape */
178 };
179
180 static int is_system;
181
182 /*
183 * Setup serial interface
184 */
185 static int
serial_bm_setup(struct ipmi_intf * intf)186 serial_bm_setup(struct ipmi_intf * intf)
187 {
188 /* setup default LAN maximum request and response sizes */
189 intf->max_request_data_size = SERIAL_BM_MAX_RQ_SIZE;
190 intf->max_response_data_size = SERIAL_BM_MAX_RS_SIZE;
191
192 return 0;
193 }
194
195 /*
196 * Open serial interface
197 */
198 static int
serial_bm_open(struct ipmi_intf * intf)199 serial_bm_open(struct ipmi_intf * intf)
200 {
201 struct termios ti;
202 unsigned int rate = 9600;
203 char *p;
204 int i;
205
206 if (!intf->devfile) {
207 lprintf(LOG_ERR, "Serial device is not specified");
208 return -1;
209 }
210
211 is_system = 0;
212
213 /* check if baud rate is specified */
214 if ((p = strchr(intf->devfile, ':'))) {
215 char * pp;
216
217 /* separate device name from baud rate */
218 *p++ = '\0';
219
220 /* check for second colon */
221 if ((pp = strchr(p, ':'))) {
222 /* this is needed to normally acquire baud rate */
223 *pp++ = '\0';
224
225 /* check if it is a system interface */
226 if (pp[0] == 'S' || pp[0] == 's') {
227 is_system = 1;
228 }
229 }
230
231 if (str2uint(p, &rate)) {
232 lprintf(LOG_ERR, "Invalid baud rate specified\n");
233 return -1;
234 }
235 }
236
237 intf->fd = open(intf->devfile, O_RDWR | O_NONBLOCK, 0);
238 if (intf->fd < 0) {
239 lperror(LOG_ERR, "Could not open device at %s", intf->devfile);
240 return -1;
241 }
242
243 for (i = 0; i < sizeof(rates) / sizeof(rates[0]); i++) {
244 if (rates[i].baudrate == rate) {
245 break;
246 }
247 }
248 if (i >= sizeof(rates) / sizeof(rates[0])) {
249 lprintf(LOG_ERR, "Unsupported baud rate %i specified", rate);
250 return -1;
251 }
252
253 tcgetattr(intf->fd, &ti);
254
255 cfsetispeed(&ti, rates[i].baudinit);
256 cfsetospeed(&ti, rates[i].baudinit);
257
258 /* 8N1 */
259 ti.c_cflag &= ~PARENB;
260 ti.c_cflag &= ~CSTOPB;
261 ti.c_cflag &= ~CSIZE;
262 ti.c_cflag |= CS8;
263
264 /* enable the receiver and set local mode */
265 ti.c_cflag |= (CLOCAL | CREAD);
266
267 /* no flow control */
268 ti.c_cflag &= ~CRTSCTS;
269 ti.c_iflag &= ~(IGNBRK | IGNCR | INLCR | ICRNL | INPCK | ISTRIP
270 | IXON | IXOFF | IXANY);
271 #ifdef IUCLC
272 /* Only disable uppercase-to-lowercase mapping on input for
273 platforms supporting the flag. */
274 ti.c_iflag &= ~(IUCLC);
275 #endif
276
277
278 ti.c_oflag &= ~(OPOST);
279 ti.c_lflag &= ~(ICANON | ISIG | ECHO | ECHONL | NOFLSH);
280
281 /* set the new options for the port with flushing */
282 tcsetattr(intf->fd, TCSAFLUSH, &ti);
283
284 if (intf->ssn_params.timeout == 0)
285 intf->ssn_params.timeout = SERIAL_BM_TIMEOUT;
286 if (intf->ssn_params.retry == 0)
287 intf->ssn_params.retry = SERIAL_BM_RETRY_COUNT;
288
289 intf->opened = 1;
290
291 return 0;
292 }
293
294 /*
295 * Close serial interface
296 */
297 static void
serial_bm_close(struct ipmi_intf * intf)298 serial_bm_close(struct ipmi_intf * intf)
299 {
300 if (intf->opened) {
301 close(intf->fd);
302 intf->fd = -1;
303 }
304 ipmi_intf_session_cleanup(intf);
305 intf->opened = 0;
306 }
307
308 /*
309 * Allocate sequence number for tracking
310 */
311 static uint8_t
serial_bm_alloc_seq(void)312 serial_bm_alloc_seq(void)
313 {
314 static uint8_t seq = 0;
315 if (++seq == 64) {
316 seq = 0;
317 }
318 return seq;
319 }
320
321 /*
322 * Flush the buffers
323 */
324 static int
serial_bm_flush(struct ipmi_intf * intf)325 serial_bm_flush(struct ipmi_intf * intf)
326 {
327 #if defined(TCFLSH)
328 return ioctl(intf->fd, TCFLSH, TCIOFLUSH);
329 #elif defined(TIOCFLUSH)
330 return ioctl(intf->fd, TIOCFLUSH);
331 #else
332 # error "unsupported platform, missing flush support (TCFLSH/TIOCFLUSH)"
333 #endif
334 }
335
336 /*
337 * Return escaped character for the given one
338 */
339 static inline uint8_t
serial_bm_get_escaped_char(uint8_t c)340 serial_bm_get_escaped_char(uint8_t c)
341 {
342 int i;
343
344 for (i = 0; i < 5; i++) {
345 if (characters[i].character == c) {
346 return characters[i].escape;
347 }
348 }
349
350 return c;
351 }
352
353 /*
354 * Return unescaped character for the given one
355 */
356 static inline uint8_t
serial_bm_get_unescaped_char(uint8_t c)357 serial_bm_get_unescaped_char(uint8_t c)
358 {
359 int i;
360
361 for (i = 0; i < 5; i++) {
362 if (characters[i].escape == c) {
363 return characters[i].character;
364 }
365 }
366
367 return c;
368 }
369
370 /*
371 * Send message to serial port
372 */
373 static int
serial_bm_send_msg(struct ipmi_intf * intf,uint8_t * msg,int msg_len)374 serial_bm_send_msg(struct ipmi_intf * intf, uint8_t * msg, int msg_len)
375 {
376 int i, size, tmp = 0;
377 uint8_t * buf, * data;
378
379 if (verbose > 3) {
380 fprintf(stderr, "Sending request:\n");
381 fprintf(stderr, " rsSA = 0x%x\n", msg[0]);
382 fprintf(stderr, " NetFN/rsLUN = 0x%x\n", msg[1]);
383 fprintf(stderr, " rqSA = 0x%x\n", msg[3]);
384 fprintf(stderr, " rqSeq/rqLUN = 0x%x\n", msg[4]);
385 fprintf(stderr, " cmd = 0x%x\n", msg[5]);
386 if (msg_len > 7) {
387 fprintf(stderr, " data_len = %d\n", msg_len - 7);
388 fprintf(stderr, " data = %s\n",
389 buf2str(msg + 6, msg_len - 7));
390 }
391 }
392
393 if (verbose > 4) {
394 fprintf(stderr, "Message data:\n");
395 fprintf(stderr, " %s\n", buf2str(msg, msg_len));
396 }
397
398 /* calculate escaped characters number */
399 for (i = 0; i < msg_len; i++) {
400 if (serial_bm_get_escaped_char(msg[i]) != msg[i]) {
401 tmp++;
402 }
403 }
404
405 /* calculate required buffer size */
406 size = msg_len + tmp + 2;
407
408 /* allocate buffer for output data */
409 buf = data = (uint8_t *) alloca(size);
410
411 if (!buf) {
412 lperror(LOG_ERR, "ipmitool: alloca error");
413 return -1;
414 }
415
416 /* start character */
417 *buf++ = 0xA0;
418
419 for (i = 0; i < msg_len; i++) {
420 tmp = serial_bm_get_escaped_char(msg[i]);
421 if (tmp != msg[i]) {
422 *buf++ = 0xAA;
423 }
424
425 *buf++ = tmp;
426 }
427
428 /* stop character */
429 *buf++ = 0xA5;
430
431 if (verbose > 5) {
432 fprintf(stderr, "Sent serial data:\n %s\n", buf2str(data, size));
433 }
434
435 /* write data to serial port */
436 tmp = write(intf->fd, data, size);
437 if (tmp <= 0) {
438 lperror(LOG_ERR, "ipmitool: write error");
439 return -1;
440 }
441
442 return 0;
443 }
444
445 /*
446 * This function waits for incoming data
447 */
448 static int
serial_bm_wait_for_data(struct ipmi_intf * intf)449 serial_bm_wait_for_data(struct ipmi_intf * intf)
450 {
451 int n;
452 struct pollfd pfd;
453
454 pfd.fd = intf->fd;
455 pfd.events = POLLIN;
456 pfd.revents = 0;
457
458 n = poll(&pfd, 1, intf->ssn_params.timeout * 1000);
459 if (n < 0) {
460 lperror(LOG_ERR, "Poll for serial data failed");
461 return -1;
462 } else if (!n) {
463 return -1;
464 }
465 return 0;
466 }
467
468 /*
469 * This function parses incoming data in basic mode format to IPMB message
470 */
471 static int
serial_bm_parse_buffer(const uint8_t * data,int data_len,struct serial_bm_parse_ctx * ctx)472 serial_bm_parse_buffer(const uint8_t * data, int data_len,
473 struct serial_bm_parse_ctx * ctx)
474 {
475 int i, tmp;
476
477 for (i = 0; i < data_len; i++) {
478 /* check for start of new message */
479 if (data[i] == BM_START) {
480 ctx->state = MSG_IN_PROGRESS;
481 ctx->escape = 0;
482 ctx->msg_len = 0;
483 /* check if message is not started */
484 } else if (ctx->state != MSG_IN_PROGRESS) {
485 /* skip character */
486 continue;
487 /* continue escape sequence */
488 } else if (ctx->escape) {
489 /* get original character */
490 tmp = serial_bm_get_unescaped_char(data[i]);
491
492 /* check if not special character */
493 if (tmp == data[i]) {
494 lprintf(LOG_ERR, "ipmitool: bad response");
495 /* reset message state */
496 ctx->state = MSG_NONE;
497 continue;
498 }
499
500 /* check message length */
501 if (ctx->msg_len >= ctx->max_len) {
502 lprintf(LOG_ERR, "ipmitool: response is too long");
503 /* reset message state */
504 ctx->state = MSG_NONE;
505 continue;
506 }
507
508 /* add parsed character */
509 ctx->msg[ctx->msg_len++] = tmp;
510
511 /* clear escape flag */
512 ctx->escape = 0;
513 /* check for escape character */
514 } else if (data[i] == BM_ESCAPE) {
515 ctx->escape = 1;
516 continue;
517 /* check for stop character */
518 } else if (data[i] == BM_STOP) {
519 ctx->state = MSG_DONE;
520 return i + 1;
521 /* check for packet handshake character */
522 } else if (data[i] == BM_HANDSHAKE) {
523 /* just skip it */
524 continue;
525 } else {
526 /* check message length */
527 if (ctx->msg_len >= ctx->max_len) {
528 lprintf(LOG_ERR, "ipmitool: response is too long");
529 return -1;
530 }
531
532 /* add parsed character */
533 ctx->msg[ctx->msg_len++] = data[i];
534 }
535 }
536
537 /* return number of parsed characters */
538 return i;
539 }
540
541 /*
542 * Read and parse data from serial port
543 */
544 static int
serial_bm_recv_msg(struct ipmi_intf * intf,struct serial_bm_recv_ctx * recv_ctx,uint8_t * msg_data,size_t msg_len)545 serial_bm_recv_msg(struct ipmi_intf * intf,
546 struct serial_bm_recv_ctx * recv_ctx,
547 uint8_t * msg_data, size_t msg_len)
548 {
549 struct serial_bm_parse_ctx parse_ctx;
550 int rv;
551
552 parse_ctx.state = MSG_NONE;
553 parse_ctx.msg = msg_data;
554 parse_ctx.max_len = msg_len;
555
556 do {
557 /* wait for data in the port */
558 if (serial_bm_wait_for_data(intf)) {
559 return 0;
560 }
561
562 /* read data into buffer */
563 rv = read(intf->fd, recv_ctx->buffer + recv_ctx->buffer_size,
564 recv_ctx->max_buffer_size - recv_ctx->buffer_size);
565
566 if (rv < 0) {
567 lperror(LOG_ERR, "ipmitool: read error");
568 return -1;
569 }
570
571 if (verbose > 5) {
572 fprintf(stderr, "Received serial data:\n %s\n",
573 buf2str(recv_ctx->buffer + recv_ctx->buffer_size, rv));
574 }
575
576 /* increment buffer size */
577 recv_ctx->buffer_size += rv;
578
579 /* parse buffer */
580 rv = serial_bm_parse_buffer(recv_ctx->buffer,
581 recv_ctx->buffer_size, &parse_ctx);
582
583 if (rv < recv_ctx->buffer_size) {
584 /* move non-parsed part of the buffer to the beginning */
585 memmove(recv_ctx->buffer, recv_ctx->buffer + rv,
586 recv_ctx->buffer_size - rv);
587 }
588
589 /* decrement buffer size */
590 recv_ctx->buffer_size -= rv;
591 } while (parse_ctx.state != MSG_DONE);
592
593 if (verbose > 4) {
594 printf("Received message:\n %s\n",
595 buf2str(msg_data, parse_ctx.msg_len));
596 }
597
598 /* received a message */
599 return parse_ctx.msg_len;
600 }
601
602 /*
603 * Build IPMB message to be transmitted
604 */
605 static int
serial_bm_build_msg(const struct ipmi_intf * intf,const struct ipmi_rq * req,uint8_t * msg,size_t max_len,struct serial_bm_request_ctx * ctx,int * msg_len)606 serial_bm_build_msg(const struct ipmi_intf * intf,
607 const struct ipmi_rq * req, uint8_t * msg, size_t max_len,
608 struct serial_bm_request_ctx * ctx, int * msg_len
609 )
610 {
611 uint8_t * data = msg, seq;
612 struct ipmb_msg_hdr * hdr = (struct ipmb_msg_hdr *) msg;
613 struct ipmi_send_message_rq * inner_rq = NULL, * outer_rq = NULL;
614 int bridging_level;
615
616 /* acquire bridging level */
617 if (intf->target_addr && intf->target_addr != intf->my_addr) {
618 if (intf->transit_addr != 0) {
619 bridging_level = 2;
620 } else {
621 bridging_level = 1;
622 }
623 } else {
624 bridging_level = 0;
625 }
626
627 /* check overall packet length */
628 if(req->msg.data_len + 7 + bridging_level * 8 > max_len) {
629 lprintf(LOG_ERR, "ipmitool: Message data is too long");
630 return -1;
631 }
632
633 /* allocate new sequence number */
634 seq = serial_bm_alloc_seq() << 2;
635
636 if (bridging_level) {
637 /* compose send message request */
638 hdr->netFn = 0x18;
639 hdr->cmd = 0x34;
640
641 /* set pointer to send message request data */
642 outer_rq = (struct ipmi_send_message_rq *) (hdr + 1);
643
644 /* compose the outer send message request */
645 if (bridging_level == 2) {
646 outer_rq->channel = intf->transit_channel | 0x40;
647 outer_rq->msg.rsSA = intf->transit_addr;
648 outer_rq->msg.netFn = 0x18;
649 outer_rq->msg.csum1 = -(outer_rq->msg.rsSA + outer_rq->msg.netFn);
650 outer_rq->msg.rqSA = intf->my_addr;
651 outer_rq->msg.rqSeq = seq;
652 outer_rq->msg.cmd = 0x34;
653
654 /* inner send message request is further */
655 inner_rq = (outer_rq + 1);
656 } else {
657 /* there is only outer send message reuest */
658 inner_rq = outer_rq;
659 }
660
661 /* compose the inner send message request */
662 inner_rq->channel = intf->target_channel | 0x40;
663 inner_rq->msg.rsSA = intf->target_addr;
664 inner_rq->msg.netFn = (req->msg.netfn << 2) | req->msg.lun;
665 inner_rq->msg.csum1 = -(inner_rq->msg.rsSA + inner_rq->msg.netFn);
666 inner_rq->msg.rqSA = intf->my_addr;
667 inner_rq->msg.rqSeq = seq;
668 inner_rq->msg.cmd = req->msg.cmd;
669
670 /* check if interface is the system one */
671 if (is_system) {
672 /* need response to LUN 2 */
673 outer_rq->msg.rqSeq |= 2;
674
675 /* do not track response */
676 outer_rq->channel &= ~0x40;
677
678 /* restore BMC SA if bridging not to primary IPMB channel */
679 if (outer_rq->channel) {
680 outer_rq->msg.rqSA = IPMI_BMC_SLAVE_ADDR;
681 }
682 }
683
684 /* fill-in the second context */
685 ctx[1].rsSA = outer_rq->msg.rsSA;
686 ctx[1].netFn = outer_rq->msg.netFn;
687 ctx[1].rqSA = outer_rq->msg.rqSA;
688 ctx[1].rqSeq = outer_rq->msg.rqSeq;
689 ctx[1].cmd = outer_rq->msg.cmd;
690
691 /* move write pointer */
692 msg = (uint8_t *)(inner_rq + 1);
693 } else {
694 /* compose direct request */
695 hdr->netFn = (req->msg.netfn << 2) | req->msg.lun;
696 hdr->cmd = req->msg.cmd;
697
698 /* move write pointer */
699 msg = (uint8_t *)(hdr + 1);
700 }
701
702 /* fill-in the rest header fields */
703 hdr->rsSA = IPMI_BMC_SLAVE_ADDR;
704 hdr->csum1 = -(hdr->rsSA + hdr->netFn);
705 hdr->rqSA = IPMI_REMOTE_SWID;
706 hdr->rqSeq = seq;
707
708 /* fill-in the first context */
709 ctx[0].rsSA = hdr->rsSA;
710 ctx[0].netFn = hdr->netFn;
711 ctx[0].rqSA = hdr->rqSA;
712 ctx[0].rqSeq = hdr->rqSeq;
713 ctx[0].cmd = hdr->cmd;
714
715 /* write request data */
716 memcpy(msg, req->msg.data, req->msg.data_len);
717
718 /* move write pointer */
719 msg += req->msg.data_len;
720
721 if (bridging_level) {
722 /* write inner message checksum */
723 *msg++ = ipmi_csum(&inner_rq->msg.rqSA, req->msg.data_len + 3);
724
725 /* check for double bridging */
726 if (bridging_level == 2) {
727 /* write outer message checksum */
728 *msg++ = ipmi_csum(&outer_rq->msg.rqSA, 4);
729 }
730
731 /* write overall message checksum */
732 *msg++ = ipmi_csum(&hdr->rqSA, 4);
733 } else {
734 /* write overall message checksum */
735 *msg++ = ipmi_csum(&hdr->rqSA, req->msg.data_len + 3);
736 }
737
738 /* save message length */
739 *msg_len = msg - data;
740
741 /* return bridging level */
742 return bridging_level;
743 }
744
745 /*
746 * Wait for request response
747 */
748 static int
serial_bm_wait_response(struct ipmi_intf * intf,struct serial_bm_request_ctx * req_ctx,struct serial_bm_recv_ctx * read_ctx,uint8_t * msg,size_t max_len)749 serial_bm_wait_response(struct ipmi_intf * intf,
750 struct serial_bm_request_ctx * req_ctx, struct serial_bm_recv_ctx * read_ctx,
751 uint8_t * msg, size_t max_len)
752 {
753 struct ipmb_msg_hdr * hdr = (struct ipmb_msg_hdr *) msg;
754 int msg_len, netFn, rqSeq;
755
756 /* receive and match message */
757 while ((msg_len = serial_bm_recv_msg(intf, read_ctx, msg, max_len)) > 0) {
758 /* validate message size */
759 if (msg_len < 8) {
760 lprintf(LOG_ERR, "ipmitool: response is too short");
761 continue;
762 }
763
764 /* validate checksum 1 */
765 if (ipmi_csum(msg, 3)) {
766 lprintf(LOG_ERR, "ipmitool: bad checksum 1");
767 continue;
768 }
769
770 /* validate checksum 2 */
771 if (ipmi_csum(msg + 3, msg_len - 3)) {
772 lprintf(LOG_ERR, "ipmitool: bad checksum 2");
773 continue;
774 }
775
776 /* swap requester and responder LUNs */
777 netFn = ((req_ctx->netFn|4) & ~3) | (req_ctx->rqSeq & 3);
778 rqSeq = (req_ctx->rqSeq & ~3) | (req_ctx->netFn & 3);
779
780 /* check for the waited response */
781 if (hdr->rsSA == req_ctx->rqSA
782 && hdr->netFn == netFn
783 && hdr->rqSA == req_ctx->rsSA
784 && hdr->rqSeq == rqSeq
785 && hdr->cmd == req_ctx->cmd) {
786 /* check if something new has been parsed */
787 if (verbose > 3) {
788 fprintf(stderr, "Got response:\n");
789 fprintf(stderr, " rsSA = 0x%x\n", msg[0]);
790 fprintf(stderr, " NetFN/rsLUN = 0x%x\n", msg[1]);
791 fprintf(stderr, " rqSA = 0x%x\n", msg[3]);
792 fprintf(stderr, " rqSeq/rqLUN = 0x%x\n", msg[4]);
793 fprintf(stderr, " cmd = 0x%x\n", msg[5]);
794 fprintf(stderr, " completion code = 0x%x\n", msg[6]);
795 if (msg_len > 8) {
796 fprintf(stderr, " data_len = %d\n", msg_len - 8);
797 fprintf(stderr, " data = %s\n",
798 buf2str(msg + 7, msg_len - 8));
799 }
800 }
801
802 /* copy only completion and response data */
803 memmove(msg, hdr + 1, msg_len - sizeof (*hdr) - 1);
804
805 /* update message length */
806 msg_len -= sizeof (*hdr) + 1;
807
808 /* the waited one */
809 break;
810 }
811 }
812
813 return msg_len;
814 }
815
816 /*
817 * Get message from receive message queue
818 */
819 static int
serial_bm_get_message(struct ipmi_intf * intf,struct serial_bm_request_ctx * req_ctx,struct serial_bm_recv_ctx * read_ctx,uint8_t * msg,size_t max_len)820 serial_bm_get_message(struct ipmi_intf * intf,
821 struct serial_bm_request_ctx * req_ctx,
822 struct serial_bm_recv_ctx * read_ctx,
823 uint8_t * msg, size_t max_len)
824 {
825 uint8_t data[SERIAL_BM_MAX_MSG_SIZE];
826 struct serial_bm_request_ctx tmp_ctx;
827 struct ipmi_get_message_rp * rp = (struct ipmi_get_message_rp *) data;
828 struct ipmb_msg_hdr * hdr = (struct ipmb_msg_hdr *) data;
829 clock_t start, tm;
830 int rv, netFn, rqSeq;
831
832 start = clock();
833
834 do {
835 /* fill-in request context */
836 tmp_ctx.rsSA = IPMI_BMC_SLAVE_ADDR;
837 tmp_ctx.netFn = 0x18;
838 tmp_ctx.rqSA = IPMI_REMOTE_SWID;
839 tmp_ctx.rqSeq = serial_bm_alloc_seq() << 2;
840 tmp_ctx.cmd = 0x33;
841
842 /* fill-in request data */
843 hdr->rsSA = tmp_ctx.rsSA;
844 hdr->netFn = tmp_ctx.netFn;
845 hdr->csum1 = ipmi_csum(data, 2);
846 hdr->rqSA = tmp_ctx.rqSA;
847 hdr->rqSeq = tmp_ctx.rqSeq;
848 hdr->cmd = tmp_ctx.cmd;
849 hdr->data[0] = ipmi_csum(&hdr->rqSA, 3);
850
851 /* send request */
852 serial_bm_flush(intf);
853 serial_bm_send_msg(intf, data, 7);
854
855 /* wait for response */
856 rv = serial_bm_wait_response(intf, &tmp_ctx, read_ctx,
857 data, sizeof (data));
858
859 /* check for IO error or timeout */
860 if (rv <= 0) {
861 return rv;
862 }
863
864 /* check completion code */
865 if (rp->completion == 0) {
866 /* swap requester and responder LUNs */
867 netFn = ((req_ctx->netFn|4) & ~3) | (req_ctx->rqSeq & 3);
868 rqSeq = (req_ctx->rqSeq & ~3) | (req_ctx->netFn & 3);
869
870 /* check for the waited response */
871 if (rp->netFn == netFn
872 && rp->rsSA == req_ctx->rsSA
873 && rp->rqSeq == rqSeq
874 && rp->cmd == req_ctx->cmd) {
875 /* copy the rest of message */
876 memcpy(msg, rp->data, rv - sizeof (*rp) - 1);
877 return rv - sizeof (*rp) - 1;
878 }
879 } else if (rp->completion != 0x80) {
880 return 0;
881 }
882
883 tm = clock() - start;
884
885 tm /= CLOCKS_PER_SEC;
886 } while (tm < intf->ssn_params.timeout);
887
888 return 0;
889 }
890
891 static struct ipmi_rs *
serial_bm_send_request(struct ipmi_intf * intf,struct ipmi_rq * req)892 serial_bm_send_request(struct ipmi_intf * intf, struct ipmi_rq * req)
893 {
894 static struct ipmi_rs rsp;
895 uint8_t msg[SERIAL_BM_MAX_MSG_SIZE], * resp = msg;
896 struct serial_bm_request_ctx req_ctx[3];
897 struct serial_bm_recv_ctx read_ctx;
898 int retry, rv, msg_len, bridging_level;
899
900 if (!intf->opened && intf->open && intf->open(intf) < 0) {
901 return NULL;
902 }
903
904 /* reset receive context */
905 read_ctx.buffer_size = 0;
906 read_ctx.max_buffer_size = SERIAL_BM_MAX_BUFFER_SIZE;
907
908 /* Send the message and receive the answer */
909 for (retry = 0; retry < intf->ssn_params.retry; retry++) {
910 /* build output message */
911 bridging_level = serial_bm_build_msg(intf, req, msg,
912 sizeof (msg), req_ctx, &msg_len);
913 if (msg_len < 0) {
914 return NULL;
915 }
916
917 /* send request */
918 serial_bm_flush(intf);
919 serial_bm_send_msg(intf, msg, msg_len);
920
921 /* wait for response */
922 rv = serial_bm_wait_response(intf, &req_ctx[0],
923 &read_ctx, msg, sizeof (msg));
924
925 /* check for IO error */
926 if (rv < 0) {
927 return NULL;
928 }
929
930 /* check for timeout */
931 if (rv == 0) {
932 continue;
933 }
934
935 /* check for bridging */
936 if (bridging_level && msg[0] == 0) {
937 /* in the case of payload interface we check receive message queue */
938 if (is_system) {
939 /* check message flags */
940 rv = serial_bm_get_message(intf, &req_ctx[1],
941 &read_ctx, msg, sizeof (msg));
942
943 /* check for IO error */
944 if (rv < 0) {
945 return NULL;
946 }
947
948 /* check for timeout */
949 if (rv == 0) {
950 continue;
951 }
952 /* check if response for inner request is not encapsulated */
953 } else if (rv == 1) {
954 /* wait for response for inner request */
955 rv = serial_bm_wait_response(intf, &req_ctx[1],
956 &read_ctx, msg, sizeof (msg));
957
958 /* check for IO error */
959 if (rv < 0) {
960 return NULL;
961 }
962
963 /* check for timeout */
964 if (rv == 0) {
965 continue;
966 }
967 } else {
968 /* skip outer level header */
969 resp = msg + 7;
970 /* decrement response size */
971 rv -= 8;
972 }
973
974 /* check response size */
975 if (resp[0] == 0 && bridging_level == 2 && rv < 8) {
976 lprintf(LOG_ERR, "ipmitool: Message response is too short");
977 /* invalid message length */
978 return NULL;
979 }
980 }
981
982 /* check for double bridging */
983 if (bridging_level == 2 && resp[0] == 0) {
984 /* get completion code */
985 rsp.ccode = resp[7];
986 rsp.data_len = rv - 9;
987 memcpy(rsp.data, resp + 8, rsp.data_len);
988 } else {
989 rsp.ccode = resp[0];
990 rsp.data_len = rv - 1;
991 memcpy(rsp.data, resp + 1, rsp.data_len);
992 }
993
994 /* return response */
995 return &rsp;
996 }
997
998 /* no valid response */
999 return NULL;
1000 }
1001
1002 /*
1003 * Serial BM interface
1004 */
1005 struct ipmi_intf ipmi_serial_bm_intf = {
1006 .name = "serial-basic",
1007 .desc = "Serial Interface, Basic Mode",
1008 .setup = serial_bm_setup,
1009 .open = serial_bm_open,
1010 .close = serial_bm_close,
1011 .sendrecv = serial_bm_send_request,
1012 };
1013