1 /*
2 * Copyright (C) 2003-2015 FreeIPMI Core Team
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif /* HAVE_CONFIG_H */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #ifdef STDC_HEADERS
26 #include <string.h>
27 #include <stdarg.h>
28 #endif /* STDC_HEADERS */
29 #if HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif /* HAVE_UNISTD_H */
32 #include <assert.h>
33 #include <errno.h>
34
35 #include "freeipmi/debug/ipmi-debug.h"
36 #include "freeipmi/fiid/fiid.h"
37 #include "freeipmi/interface/ipmi-ipmb-interface.h"
38
39 #include "ipmi-debug-common.h"
40
41 #include "libcommon/ipmi-trace.h"
42
43 #include "freeipmi-portability.h"
44
45 #define IPMI_DEBUG_MAX_BUF_LEN 65536
46 #define IPMI_DEBUG_MAX_PKT_LEN 65536
47 #define IPMI_DEBUG_CHAR_PER_LINE 8
48 #define IPMI_DEBUG_DEFAULT_FD STDERR_FILENO
49
50 static int
_write(int fd,const void * buf,size_t n)51 _write (int fd, const void *buf, size_t n)
52 {
53 /* chu: by Chris Dunlap <dunlap6 at llnl dot gov> */
54 size_t nleft;
55 ssize_t nwritten;
56 unsigned char *p;
57
58 p = (unsigned char *)buf;
59 nleft = n;
60 while (nleft > 0)
61 {
62 if ((nwritten = write (fd, p, nleft)) < 0)
63 {
64 if (errno == EINTR)
65 continue;
66 else
67 return (-1);
68 }
69 nleft -= nwritten;
70 p += nwritten;
71 }
72 return (n);
73 }
74
75 int
debug_dprintf(int fd,const char * fmt,...)76 debug_dprintf (int fd, const char *fmt, ...)
77 {
78 va_list ap;
79 int len, rv;
80 char buf[IPMI_DEBUG_MAX_BUF_LEN];
81
82 va_start (ap, fmt);
83 len = vsnprintf (buf, IPMI_DEBUG_MAX_BUF_LEN, fmt, ap);
84 rv = _write (fd, buf, len);
85 va_end (ap);
86
87 return (rv);
88 }
89
90 int
debug_set_prefix(char * buf,unsigned int buflen,const char * prefix)91 debug_set_prefix (char *buf, unsigned int buflen, const char *prefix)
92 {
93 assert (buf && buflen > 3);
94
95 /* clear buffer, empty prefix allowed */
96 memset (buf, '\0', buflen);
97 if (prefix)
98 {
99 strncpy (buf, prefix, buflen);
100 buf[buflen - 1] = '\0'; /* strncpy may not null terminate */
101 buf[buflen - 2] = '\0'; /* guaranteed space for ' ' */
102 buf[buflen - 3] = '\0'; /* guaranteed space for ':' */
103 strcat (buf, ": ");
104 }
105
106 return (0);
107 }
108
109 int
debug_output_str(int fd,const char * prefix,const char * str)110 debug_output_str (int fd, const char *prefix, const char *str)
111 {
112 /* achu: Yeah, I know this is slow. Figure out something better
113 * later.
114 */
115 if (str)
116 {
117 char *ptr = (char *)str;
118
119 if (prefix)
120 {
121 if (debug_dprintf (fd, "%s", prefix) < 0)
122 {
123 ERRNO_TRACE (errno);
124 return (-1);
125 }
126 }
127
128 while (*ptr != '\0')
129 {
130 if (*ptr == '\n')
131 {
132 if (debug_dprintf (fd, "%c", *ptr++) < 0)
133 {
134 ERRNO_TRACE (errno);
135 return (-1);
136 }
137 if (prefix)
138 {
139 if (debug_dprintf (fd, "%s", prefix) < 0)
140 {
141 ERRNO_TRACE (errno);
142 return (-1);
143 }
144 }
145 }
146 else
147 {
148 if (debug_dprintf (fd, "%c", *ptr++) < 0)
149 {
150 ERRNO_TRACE (errno);
151 return (-1);
152 }
153 }
154 }
155
156 if (debug_dprintf (fd, "\n") < 0)
157 {
158 ERRNO_TRACE (errno);
159 return (-1);
160 }
161 }
162
163 return (0);
164 }
165
166 int
debug_output_byte_array(int fd,const char * prefix,const uint8_t * buf,unsigned int buf_len)167 debug_output_byte_array (int fd, const char *prefix, const uint8_t *buf, unsigned int buf_len)
168 {
169 unsigned int count = 0;
170
171 assert (buf);
172
173 while (count < buf_len)
174 {
175 int i = 0;
176 if (prefix)
177 {
178 if (debug_dprintf (fd, "%s", prefix) < 0)
179 {
180 ERRNO_TRACE (errno);
181 return (-1);
182 }
183 }
184
185 if (debug_dprintf (fd, "[ ") < 0)
186 {
187 ERRNO_TRACE (errno);
188 return (-1);
189 }
190
191 while (count < buf_len && i < IPMI_DEBUG_CHAR_PER_LINE)
192 {
193 if (debug_dprintf (fd, "%02Xh ", buf[count++]) < 0)
194 {
195 ERRNO_TRACE (errno);
196 return (-1);
197 }
198 i++;
199 }
200
201 if (debug_dprintf (fd, "]\n") < 0)
202 {
203 ERRNO_TRACE (errno);
204 return (-1);
205 }
206 }
207
208 return (0);
209 }
210
211 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)212 debug_dump_ipmb (int fd,
213 const char *prefix,
214 const uint8_t *ipmb_buf,
215 unsigned int ipmb_buf_len,
216 fiid_template_t tmpl_ipmb_msg_hdr,
217 fiid_template_t tmpl_ipmb_cmd)
218 {
219 char *ipmb_msg_hdr =
220 "IPMB Message Header:\n"
221 "--------------------";
222 char *ipmb_cmd_hdr =
223 "IPMB Message Data:\n"
224 "------------------";
225 char *ipmb_msg_trlr_hdr =
226 "IPMB Message Trailer:\n"
227 "---------------------";
228 char *ipmb_unexpected_hdr =
229 "IPMB Unexpected Data:\n"
230 "---------------------";
231 fiid_obj_t obj_ipmb_msg_hdr = NULL;
232 fiid_obj_t obj_ipmb_cmd = NULL;
233 fiid_obj_t obj_ipmb_msg_trlr = NULL;
234 fiid_obj_t obj_ipmb_unexpected_data = NULL;
235 int obj_ipmb_msg_trlr_len = 0;
236 unsigned int obj_ipmb_cmd_len = 0;
237 int ipmb_hdr_len = 0;
238 int ipmb_cmd_len = 0;
239 int ipmb_trlr_len = 0;
240 int len;
241 unsigned int ipmb_indx = 0;
242 int rv = -1;
243
244 assert (ipmb_buf);
245 assert (ipmb_buf_len);
246 assert (tmpl_ipmb_msg_hdr);
247 assert (tmpl_ipmb_cmd);
248
249 if (!(obj_ipmb_msg_hdr = fiid_obj_create (tmpl_ipmb_msg_hdr)))
250 {
251 ERRNO_TRACE (errno);
252 goto cleanup;
253 }
254 if (!(obj_ipmb_cmd = fiid_obj_create (tmpl_ipmb_cmd)))
255 {
256 ERRNO_TRACE (errno);
257 goto cleanup;
258 }
259 if (!(obj_ipmb_msg_trlr = fiid_obj_create (tmpl_ipmb_msg_trlr)))
260 {
261 ERRNO_TRACE (errno);
262 goto cleanup;
263 }
264
265 if ((obj_ipmb_msg_trlr_len = fiid_template_len_bytes (tmpl_ipmb_msg_trlr)) < 0)
266 {
267 ERRNO_TRACE (errno);
268 goto cleanup;
269 }
270
271 if ((ipmb_hdr_len = fiid_obj_set_all (obj_ipmb_msg_hdr,
272 ipmb_buf,
273 ipmb_buf_len)) < 0)
274 {
275 FIID_OBJECT_ERROR_TO_ERRNO (obj_ipmb_msg_hdr);
276 goto cleanup;
277 }
278 ipmb_indx += ipmb_hdr_len;
279
280 if (ipmi_obj_dump (fd,
281 prefix,
282 ipmb_msg_hdr,
283 NULL,
284 obj_ipmb_msg_hdr) < 0)
285 {
286 ERRNO_TRACE (errno);
287 goto cleanup;
288 }
289
290 if (ipmb_buf_len <= ipmb_indx)
291 {
292 rv = 0;
293 goto cleanup;
294 }
295
296 if ((ipmb_buf_len - ipmb_hdr_len) <= obj_ipmb_msg_trlr_len)
297 goto dump_ipmb_extra;
298
299 obj_ipmb_cmd_len = (ipmb_buf_len - ipmb_hdr_len) - obj_ipmb_msg_trlr_len;
300
301 if ((ipmb_cmd_len = fiid_obj_set_all (obj_ipmb_cmd,
302 ipmb_buf + ipmb_hdr_len,
303 obj_ipmb_cmd_len)) < 0)
304 {
305 FIID_OBJECT_ERROR_TO_ERRNO (obj_ipmb_cmd);
306 goto cleanup;
307 }
308 ipmb_indx += ipmb_cmd_len;
309
310 if (ipmi_obj_dump (fd,
311 prefix,
312 ipmb_cmd_hdr,
313 NULL,
314 obj_ipmb_cmd) < 0)
315 {
316 ERRNO_TRACE (errno);
317 goto cleanup;
318 }
319
320 if (ipmb_buf_len <= ipmb_indx)
321 {
322 rv = 0;
323 goto cleanup;
324 }
325
326 if ((ipmb_trlr_len = fiid_obj_set_all (obj_ipmb_msg_trlr,
327 ipmb_buf + ipmb_hdr_len + ipmb_cmd_len,
328 (ipmb_buf_len - ipmb_hdr_len - ipmb_cmd_len))) < 0)
329 {
330 FIID_OBJECT_ERROR_TO_ERRNO (obj_ipmb_msg_trlr);
331 goto cleanup;
332 }
333 ipmb_indx += ipmb_trlr_len;
334
335 if (ipmi_obj_dump (fd,
336 prefix,
337 ipmb_msg_trlr_hdr,
338 NULL,
339 obj_ipmb_msg_trlr) < 0)
340 {
341 ERRNO_TRACE (errno);
342 goto cleanup;
343 }
344
345 /* Dump IPMB unexpected stuff */
346
347 dump_ipmb_extra:
348
349 if ((ipmb_buf_len - ipmb_indx) > 0)
350 {
351 if (!(obj_ipmb_unexpected_data = fiid_obj_create (tmpl_unexpected_data)))
352 {
353 ERRNO_TRACE (errno);
354 goto cleanup;
355 }
356
357 if ((len = fiid_obj_set_all (obj_ipmb_unexpected_data,
358 ipmb_buf + ipmb_indx,
359 ipmb_buf_len - ipmb_indx)) < 0)
360 {
361 FIID_OBJECT_ERROR_TO_ERRNO (obj_ipmb_unexpected_data);
362 goto cleanup;
363 }
364 ipmb_indx += len;
365
366 if (ipmi_obj_dump (fd,
367 prefix,
368 ipmb_unexpected_hdr,
369 NULL,
370 obj_ipmb_unexpected_data) < 0)
371 {
372 ERRNO_TRACE (errno);
373 goto cleanup;
374 }
375 }
376
377 rv = 0;
378 cleanup:
379 fiid_obj_destroy (obj_ipmb_msg_hdr);
380 fiid_obj_destroy (obj_ipmb_cmd);
381 fiid_obj_destroy (obj_ipmb_msg_trlr);
382 fiid_obj_destroy (obj_ipmb_unexpected_data);
383 return (rv);
384
385 }
386