/* * Copyright (C) 2003-2015 FreeIPMI Core Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifdef HAVE_CONFIG_H #include #endif /* HAVE_CONFIG_H */ #include #include #ifdef STDC_HEADERS #include #include #endif /* STDC_HEADERS */ #if HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ #include #include #include "freeipmi/debug/ipmi-debug.h" #include "freeipmi/fiid/fiid.h" #include "freeipmi/interface/ipmi-ipmb-interface.h" #include "ipmi-debug-common.h" #include "libcommon/ipmi-trace.h" #include "freeipmi-portability.h" #define IPMI_DEBUG_MAX_BUF_LEN 65536 #define IPMI_DEBUG_MAX_PKT_LEN 65536 #define IPMI_DEBUG_CHAR_PER_LINE 8 #define IPMI_DEBUG_DEFAULT_FD STDERR_FILENO static int _write (int fd, const void *buf, size_t n) { /* chu: by Chris Dunlap */ size_t nleft; ssize_t nwritten; unsigned char *p; p = (unsigned char *)buf; nleft = n; while (nleft > 0) { if ((nwritten = write (fd, p, nleft)) < 0) { if (errno == EINTR) continue; else return (-1); } nleft -= nwritten; p += nwritten; } return (n); } int debug_dprintf (int fd, const char *fmt, ...) { va_list ap; int len, rv; char buf[IPMI_DEBUG_MAX_BUF_LEN]; va_start (ap, fmt); len = vsnprintf (buf, IPMI_DEBUG_MAX_BUF_LEN, fmt, ap); rv = _write (fd, buf, len); va_end (ap); return (rv); } int debug_set_prefix (char *buf, unsigned int buflen, const char *prefix) { assert (buf && buflen > 3); /* clear buffer, empty prefix allowed */ memset (buf, '\0', buflen); if (prefix) { strncpy (buf, prefix, buflen); buf[buflen - 1] = '\0'; /* strncpy may not null terminate */ buf[buflen - 2] = '\0'; /* guaranteed space for ' ' */ buf[buflen - 3] = '\0'; /* guaranteed space for ':' */ strcat (buf, ": "); } return (0); } int debug_output_str (int fd, const char *prefix, const char *str) { /* achu: Yeah, I know this is slow. Figure out something better * later. */ if (str) { char *ptr = (char *)str; if (prefix) { if (debug_dprintf (fd, "%s", prefix) < 0) { ERRNO_TRACE (errno); return (-1); } } while (*ptr != '\0') { if (*ptr == '\n') { if (debug_dprintf (fd, "%c", *ptr++) < 0) { ERRNO_TRACE (errno); return (-1); } if (prefix) { if (debug_dprintf (fd, "%s", prefix) < 0) { ERRNO_TRACE (errno); return (-1); } } } else { if (debug_dprintf (fd, "%c", *ptr++) < 0) { ERRNO_TRACE (errno); return (-1); } } } if (debug_dprintf (fd, "\n") < 0) { ERRNO_TRACE (errno); return (-1); } } return (0); } int debug_output_byte_array (int fd, const char *prefix, const uint8_t *buf, unsigned int buf_len) { unsigned int count = 0; assert (buf); while (count < buf_len) { int i = 0; if (prefix) { if (debug_dprintf (fd, "%s", prefix) < 0) { ERRNO_TRACE (errno); return (-1); } } if (debug_dprintf (fd, "[ ") < 0) { ERRNO_TRACE (errno); return (-1); } while (count < buf_len && i < IPMI_DEBUG_CHAR_PER_LINE) { if (debug_dprintf (fd, "%02Xh ", buf[count++]) < 0) { ERRNO_TRACE (errno); return (-1); } i++; } if (debug_dprintf (fd, "]\n") < 0) { ERRNO_TRACE (errno); return (-1); } } return (0); } int debug_dump_ipmb (int fd, const char *prefix, const uint8_t *ipmb_buf, unsigned int ipmb_buf_len, fiid_template_t tmpl_ipmb_msg_hdr, fiid_template_t tmpl_ipmb_cmd) { char *ipmb_msg_hdr = "IPMB Message Header:\n" "--------------------"; char *ipmb_cmd_hdr = "IPMB Message Data:\n" "------------------"; char *ipmb_msg_trlr_hdr = "IPMB Message Trailer:\n" "---------------------"; char *ipmb_unexpected_hdr = "IPMB Unexpected Data:\n" "---------------------"; fiid_obj_t obj_ipmb_msg_hdr = NULL; fiid_obj_t obj_ipmb_cmd = NULL; fiid_obj_t obj_ipmb_msg_trlr = NULL; fiid_obj_t obj_ipmb_unexpected_data = NULL; int obj_ipmb_msg_trlr_len = 0; unsigned int obj_ipmb_cmd_len = 0; int ipmb_hdr_len = 0; int ipmb_cmd_len = 0; int ipmb_trlr_len = 0; int len; unsigned int ipmb_indx = 0; int rv = -1; assert (ipmb_buf); assert (ipmb_buf_len); assert (tmpl_ipmb_msg_hdr); assert (tmpl_ipmb_cmd); if (!(obj_ipmb_msg_hdr = fiid_obj_create (tmpl_ipmb_msg_hdr))) { ERRNO_TRACE (errno); goto cleanup; } if (!(obj_ipmb_cmd = fiid_obj_create (tmpl_ipmb_cmd))) { ERRNO_TRACE (errno); goto cleanup; } if (!(obj_ipmb_msg_trlr = fiid_obj_create (tmpl_ipmb_msg_trlr))) { ERRNO_TRACE (errno); goto cleanup; } if ((obj_ipmb_msg_trlr_len = fiid_template_len_bytes (tmpl_ipmb_msg_trlr)) < 0) { ERRNO_TRACE (errno); goto cleanup; } if ((ipmb_hdr_len = fiid_obj_set_all (obj_ipmb_msg_hdr, ipmb_buf, ipmb_buf_len)) < 0) { FIID_OBJECT_ERROR_TO_ERRNO (obj_ipmb_msg_hdr); goto cleanup; } ipmb_indx += ipmb_hdr_len; if (ipmi_obj_dump (fd, prefix, ipmb_msg_hdr, NULL, obj_ipmb_msg_hdr) < 0) { ERRNO_TRACE (errno); goto cleanup; } if (ipmb_buf_len <= ipmb_indx) { rv = 0; goto cleanup; } if ((ipmb_buf_len - ipmb_hdr_len) <= obj_ipmb_msg_trlr_len) goto dump_ipmb_extra; obj_ipmb_cmd_len = (ipmb_buf_len - ipmb_hdr_len) - obj_ipmb_msg_trlr_len; if ((ipmb_cmd_len = fiid_obj_set_all (obj_ipmb_cmd, ipmb_buf + ipmb_hdr_len, obj_ipmb_cmd_len)) < 0) { FIID_OBJECT_ERROR_TO_ERRNO (obj_ipmb_cmd); goto cleanup; } ipmb_indx += ipmb_cmd_len; if (ipmi_obj_dump (fd, prefix, ipmb_cmd_hdr, NULL, obj_ipmb_cmd) < 0) { ERRNO_TRACE (errno); goto cleanup; } if (ipmb_buf_len <= ipmb_indx) { rv = 0; goto cleanup; } if ((ipmb_trlr_len = fiid_obj_set_all (obj_ipmb_msg_trlr, ipmb_buf + ipmb_hdr_len + ipmb_cmd_len, (ipmb_buf_len - ipmb_hdr_len - ipmb_cmd_len))) < 0) { FIID_OBJECT_ERROR_TO_ERRNO (obj_ipmb_msg_trlr); goto cleanup; } ipmb_indx += ipmb_trlr_len; if (ipmi_obj_dump (fd, prefix, ipmb_msg_trlr_hdr, NULL, obj_ipmb_msg_trlr) < 0) { ERRNO_TRACE (errno); goto cleanup; } /* Dump IPMB unexpected stuff */ dump_ipmb_extra: if ((ipmb_buf_len - ipmb_indx) > 0) { if (!(obj_ipmb_unexpected_data = fiid_obj_create (tmpl_unexpected_data))) { ERRNO_TRACE (errno); goto cleanup; } if ((len = fiid_obj_set_all (obj_ipmb_unexpected_data, ipmb_buf + ipmb_indx, ipmb_buf_len - ipmb_indx)) < 0) { FIID_OBJECT_ERROR_TO_ERRNO (obj_ipmb_unexpected_data); goto cleanup; } ipmb_indx += len; if (ipmi_obj_dump (fd, prefix, ipmb_unexpected_hdr, NULL, obj_ipmb_unexpected_data) < 0) { ERRNO_TRACE (errno); goto cleanup; } } rv = 0; cleanup: fiid_obj_destroy (obj_ipmb_msg_hdr); fiid_obj_destroy (obj_ipmb_cmd); fiid_obj_destroy (obj_ipmb_msg_trlr); fiid_obj_destroy (obj_ipmb_unexpected_data); return (rv); }