1 /*
2 * Copyright (c) 2003 Sun Microsystems, Inc. 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 Sun Microsystems, Inc. or 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 * SUN MICROSYSTEMS, INC. ("SUN") 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 * SUN 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 SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
31 */
32
33 #include <stdlib.h>
34 #include <string.h>
35 #include <strings.h>
36 #include <stdio.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <sys/select.h>
40 #include <sys/time.h>
41 #include <time.h>
42 #include <signal.h>
43 #include <unistd.h>
44
45 #if defined(HAVE_CONFIG_H)
46 # include <config.h>
47 #endif
48
49 #if defined(HAVE_TERMIOS_H)
50 # include <termios.h>
51 #elif defined (HAVE_SYS_TERMIOS_H)
52 # include <sys/termios.h>
53 #endif
54
55 #include <ipmitool/helper.h>
56 #include <ipmitool/log.h>
57 #include <ipmitool/ipmi.h>
58 #include <ipmitool/ipmi_intf.h>
59 #include <ipmitool/ipmi_sol.h>
60 #include <ipmitool/ipmi_strings.h>
61 #include <ipmitool/bswap.h>
62
63
64 #define SOL_PARAMETER_SET_IN_PROGRESS 0x00
65 #define SOL_PARAMETER_SOL_ENABLE 0x01
66 #define SOL_PARAMETER_SOL_AUTHENTICATION 0x02
67 #define SOL_PARAMETER_CHARACTER_INTERVAL 0x03
68 #define SOL_PARAMETER_SOL_RETRY 0x04
69 #define SOL_PARAMETER_SOL_NON_VOLATILE_BIT_RATE 0x05
70 #define SOL_PARAMETER_SOL_VOLATILE_BIT_RATE 0x06
71 #define SOL_PARAMETER_SOL_PAYLOAD_CHANNEL 0x07
72 #define SOL_PARAMETER_SOL_PAYLOAD_PORT 0x08
73
74 #define MAX_SOL_RETRY 6
75
76 const struct valstr sol_parameter_vals[] = {
77 { SOL_PARAMETER_SET_IN_PROGRESS, "Set In Progress (0)" },
78 { SOL_PARAMETER_SOL_ENABLE, "Enable (1)" },
79 { SOL_PARAMETER_SOL_AUTHENTICATION, "Authentication (2)" },
80 { SOL_PARAMETER_CHARACTER_INTERVAL, "Character Interval (3)" },
81 { SOL_PARAMETER_SOL_RETRY, "Retry (4)" },
82 { SOL_PARAMETER_SOL_NON_VOLATILE_BIT_RATE, "Nonvolatile Bitrate (5)" },
83 { SOL_PARAMETER_SOL_VOLATILE_BIT_RATE, "Volatile Bitrate (6)" },
84 { SOL_PARAMETER_SOL_PAYLOAD_CHANNEL, "Payload Channel (7)" },
85 { SOL_PARAMETER_SOL_PAYLOAD_PORT, "Payload Port (8)" },
86 { 0x00, NULL },
87 };
88
89
90 static struct timeval _start_keepalive;
91 static struct termios _saved_tio;
92 static int _in_raw_mode = 0;
93 static int _disable_keepalive = 0;
94 static int _use_sol_for_keepalive = 0;
95 static int _keepalive_retries = 0;
96
97 extern int verbose;
98
99 /*
100 * ipmi_sol_payload_access
101 */
102 int
ipmi_sol_payload_access(struct ipmi_intf * intf,uint8_t channel,uint8_t userid,int enable)103 ipmi_sol_payload_access(struct ipmi_intf * intf, uint8_t channel,
104 uint8_t userid, int enable)
105 {
106 struct ipmi_rq req;
107 struct ipmi_rs *rsp;
108 int rc = (-1);
109 uint8_t data[6];
110
111 memset(&req, 0, sizeof(req));
112 req.msg.netfn = IPMI_NETFN_APP;
113 req.msg.cmd = IPMI_SET_USER_PAYLOAD_ACCESS;
114 req.msg.data = data;
115 req.msg.data_len = 6;
116
117 memset(data, 0, 6);
118 /* channel */
119 data[0] = channel & 0xf;
120 /* user id */
121 data[1] = userid & 0x3f;
122 if (!enable) {
123 /* disable */
124 data[1] |= 0x40;
125 }
126 /* payload 1 is SOL */
127 data[2] = 0x02;
128 rsp = intf->sendrecv(intf, &req);
129 if (rsp == NULL) {
130 lprintf(LOG_ERR, "Error %sabling SOL payload for user %d on channel %d",
131 enable ? "en" : "dis", userid, channel);
132 rc = (-1);
133 } else if (rsp->ccode != 0) {
134 lprintf(LOG_ERR, "Error %sabling SOL payload for user %d on channel %d: %s",
135 enable ? "en" : "dis", userid, channel,
136 val2str(rsp->ccode, completion_code_vals));
137 rc = (-1);
138 } else {
139 rc = 0;
140 }
141 return rc;
142 }
143
144 int
ipmi_sol_payload_access_status(struct ipmi_intf * intf,uint8_t channel,uint8_t userid)145 ipmi_sol_payload_access_status(struct ipmi_intf * intf,
146 uint8_t channel,
147 uint8_t userid)
148 {
149 struct ipmi_rq req;
150 struct ipmi_rs *rsp;
151 uint8_t data[2];
152
153 memset(&req, 0, sizeof(req));
154 req.msg.netfn = IPMI_NETFN_APP;
155 req.msg.cmd = IPMI_GET_USER_PAYLOAD_ACCESS;
156 req.msg.data = data;
157 req.msg.data_len = sizeof(data);
158
159 data[0] = channel & 0xf; /* channel */
160 data[1] = userid & 0x3f; /* user id */
161 rsp = intf->sendrecv(intf, &req);
162
163 if (rsp == NULL) {
164 lprintf(LOG_ERR, "Error. No valid response received.");
165 return -1;
166 }
167
168 switch(rsp->ccode) {
169 case 0x00:
170 if (rsp->data_len != 4) {
171 lprintf(LOG_ERR, "Error parsing SOL payload status for user %d on channel %d",
172 userid, channel);
173 return -1;
174 }
175
176 printf("User %d on channel %d is %sabled\n",
177 userid, channel, (rsp->data[0] & 0x02) ? "en":"dis");
178 return 0;
179
180 default:
181 lprintf(LOG_ERR, "Error getting SOL payload status for user %d on channel %d: %s",
182 userid, channel,
183 val2str(rsp->ccode, completion_code_vals));
184 return -1;
185 }
186 }
187
188
189 /*
190 * ipmi_get_sol_info
191 */
192 int
ipmi_get_sol_info(struct ipmi_intf * intf,uint8_t channel,struct sol_config_parameters * params)193 ipmi_get_sol_info(
194 struct ipmi_intf * intf,
195 uint8_t channel,
196 struct sol_config_parameters * params)
197 {
198 struct ipmi_rs * rsp;
199 struct ipmi_rq req;
200 uint8_t data[4];
201
202 memset(&req, 0, sizeof(req));
203 req.msg.netfn = IPMI_NETFN_TRANSPORT;
204 req.msg.cmd = IPMI_GET_SOL_CONFIG_PARAMETERS;
205 req.msg.data_len = 4;
206 req.msg.data = data;
207
208 /*
209 * set in progress
210 */
211 memset(data, 0, sizeof(data));
212 data[0] = channel; /* channel number */
213 data[1] = SOL_PARAMETER_SET_IN_PROGRESS; /* parameter selector */
214 data[2] = 0x00; /* set selector */
215 data[3] = 0x00; /* block selector */
216
217 rsp = intf->sendrecv(intf, &req);
218 if (rsp == NULL) {
219 lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'",
220 val2str(data[1], sol_parameter_vals));
221 return (-1);
222 }
223
224 switch (rsp->ccode) {
225 case 0x00:
226 if (rsp->data_len == 2) {
227 params->set_in_progress = rsp->data[1];
228 } else {
229 lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
230 "for SOL parameter '%s'",
231 rsp->data_len,
232 val2str(data[1], sol_parameter_vals));
233 }
234 break;
235 case 0x80:
236 lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported",
237 val2str(data[1], sol_parameter_vals));
238 break;
239 default:
240 lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s",
241 val2str(data[1], sol_parameter_vals),
242 val2str(rsp->ccode, completion_code_vals));
243 return (-1);
244 }
245
246 /*
247 * SOL enable
248 */
249 memset(data, 0, sizeof(data));
250 data[0] = channel; /* channel number */
251 data[1] = SOL_PARAMETER_SOL_ENABLE; /* parameter selector */
252 data[2] = 0x00; /* set selector */
253 data[3] = 0x00; /* block selector */
254
255 rsp = intf->sendrecv(intf, &req);
256 if (rsp == NULL) {
257 lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'",
258 val2str(data[1], sol_parameter_vals));
259 return (-1);
260 }
261
262 switch (rsp->ccode) {
263 case 0x00:
264 if (rsp->data_len == 2) {
265 params->enabled = rsp->data[1];
266 } else {
267 lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
268 "for SOL parameter '%s'",
269 rsp->data_len,
270 val2str(data[1], sol_parameter_vals));
271 }
272 break;
273 case 0x80:
274 lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported",
275 val2str(data[1], sol_parameter_vals));
276 break;
277 default:
278 lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s",
279 val2str(data[1], sol_parameter_vals),
280 val2str(rsp->ccode, completion_code_vals));
281 return (-1);
282 }
283
284 /*
285 * SOL authentication
286 */
287 memset(data, 0, sizeof(data));
288 data[0] = channel; /* channel number */
289 data[1] = SOL_PARAMETER_SOL_AUTHENTICATION; /* parameter selector */
290 data[2] = 0x00; /* set selector */
291 data[3] = 0x00; /* block selector */
292
293 rsp = intf->sendrecv(intf, &req);
294 if (rsp == NULL) {
295 lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'",
296 val2str(data[1], sol_parameter_vals));
297 return (-1);
298 }
299
300 switch (rsp->ccode) {
301 case 0x00:
302 if (rsp->data_len == 2) {
303 params->force_encryption = ((rsp->data[1] & 0x80)? 1 : 0);
304 params->force_authentication = ((rsp->data[1] & 0x40)? 1 : 0);
305 params->privilege_level = rsp->data[1] & 0x0F;
306 } else {
307 lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
308 "for SOL parameter '%s'",
309 rsp->data_len,
310 val2str(data[1], sol_parameter_vals));
311 }
312 break;
313 case 0x80:
314 lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported",
315 val2str(data[1], sol_parameter_vals));
316 break;
317 default:
318 lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s",
319 val2str(data[1], sol_parameter_vals),
320 val2str(rsp->ccode, completion_code_vals));
321 return (-1);
322 }
323
324 /*
325 * Character accumulate interval and character send interval
326 */
327 memset(data, 0, sizeof(data));
328 data[0] = channel; /* channel number */
329 data[1] = SOL_PARAMETER_CHARACTER_INTERVAL; /* parameter selector */
330 data[2] = 0x00; /* set selector */
331 data[3] = 0x00; /* block selector */
332
333 rsp = intf->sendrecv(intf, &req);
334 if (rsp == NULL) {
335 lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'",
336 val2str(data[1], sol_parameter_vals));
337 return (-1);
338 }
339
340 switch (rsp->ccode) {
341 case 0x00:
342 if (rsp->data_len == 3) {
343 params->character_accumulate_level = rsp->data[1];
344 params->character_send_threshold = rsp->data[2];
345 } else {
346 lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
347 "for SOL parameter '%s'",
348 rsp->data_len,
349 val2str(data[1], sol_parameter_vals));
350 }
351 break;
352 case 0x80:
353 lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported",
354 val2str(data[1], sol_parameter_vals));
355 break;
356 default:
357 lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s",
358 val2str(data[1], sol_parameter_vals),
359 val2str(rsp->ccode, completion_code_vals));
360 return (-1);
361 }
362
363 /*
364 * SOL retry
365 */
366 memset(data, 0, sizeof(data));
367 data[0] = channel; /* channel number */
368 data[1] = SOL_PARAMETER_SOL_RETRY; /* parameter selector */
369 data[2] = 0x00; /* set selector */
370 data[3] = 0x00; /* block selector */
371
372 rsp = intf->sendrecv(intf, &req);
373 if (rsp == NULL) {
374 lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'",
375 val2str(data[1], sol_parameter_vals));
376 return (-1);
377 }
378
379 switch (rsp->ccode) {
380 case 0x00:
381 if (rsp->data_len == 3) {
382 params->retry_count = rsp->data[1];
383 params->retry_interval = rsp->data[2];
384 } else {
385 lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
386 "for SOL parameter '%s'",
387 rsp->data_len,
388 val2str(data[1], sol_parameter_vals));
389 }
390 break;
391 case 0x80:
392 lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported",
393 val2str(data[1], sol_parameter_vals));
394 break;
395 default:
396 lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s",
397 val2str(data[1], sol_parameter_vals),
398 val2str(rsp->ccode, completion_code_vals));
399 return (-1);
400 }
401
402 /*
403 * SOL non-volatile bit rate
404 */
405 memset(data, 0, sizeof(data));
406 data[0] = channel; /* channel number */
407 data[1] = SOL_PARAMETER_SOL_NON_VOLATILE_BIT_RATE; /* parameter selector */
408 data[2] = 0x00; /* set selector */
409 data[3] = 0x00; /* block selector */
410
411 rsp = intf->sendrecv(intf, &req);
412 if (rsp == NULL) {
413 lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'",
414 val2str(data[1], sol_parameter_vals));
415 return (-1);
416 }
417
418 switch (rsp->ccode) {
419 case 0x00:
420 if (rsp->data_len == 2) {
421 params->non_volatile_bit_rate = rsp->data[1] & 0x0F;
422 } else {
423 lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
424 "for SOL parameter '%s'",
425 rsp->data_len,
426 val2str(data[1], sol_parameter_vals));
427 }
428 break;
429 case 0x80:
430 lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported",
431 val2str(data[1], sol_parameter_vals));
432 break;
433 default:
434 lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s",
435 val2str(data[1], sol_parameter_vals),
436 val2str(rsp->ccode, completion_code_vals));
437 return (-1);
438 }
439
440 /*
441 * SOL volatile bit rate
442 */
443 memset(data, 0, sizeof(data));
444 data[0] = channel; /* channel number */
445 data[1] = SOL_PARAMETER_SOL_VOLATILE_BIT_RATE; /* parameter selector */
446 data[2] = 0x00; /* set selector */
447 data[3] = 0x00; /* block selector */
448
449 rsp = intf->sendrecv(intf, &req);
450 if (rsp == NULL) {
451 lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'",
452 val2str(data[1], sol_parameter_vals));
453 return (-1);
454 }
455
456 switch (rsp->ccode) {
457 case 0x00:
458 if (rsp->data_len == 2) {
459 params->volatile_bit_rate = rsp->data[1] & 0x0F;
460 } else {
461 lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
462 "for SOL parameter '%s'",
463 rsp->data_len,
464 val2str(data[1], sol_parameter_vals));
465 }
466 break;
467 case 0x80:
468 lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported",
469 val2str(data[1], sol_parameter_vals));
470 break;
471 default:
472 lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s",
473 val2str(data[1], sol_parameter_vals),
474 val2str(rsp->ccode, completion_code_vals));
475 return (-1);
476 }
477
478 /*
479 * SOL payload channel
480 */
481 memset(data, 0, sizeof(data));
482 data[0] = channel; /* channel number */
483 data[1] = SOL_PARAMETER_SOL_PAYLOAD_CHANNEL; /* parameter selector */
484 data[2] = 0x00; /* set selector */
485 data[3] = 0x00; /* block selector */
486
487 rsp = intf->sendrecv(intf, &req);
488 if (rsp == NULL) {
489 lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'",
490 val2str(data[1], sol_parameter_vals));
491 return (-1);
492 }
493
494 switch (rsp->ccode) {
495 case 0x00:
496 if (rsp->data_len == 2) {
497 params->payload_channel = rsp->data[1];
498 } else {
499 lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
500 "for SOL parameter '%s'",
501 rsp->data_len,
502 val2str(data[1], sol_parameter_vals));
503 }
504 break;
505 case 0x80:
506 lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported - defaulting to 0x%02x",
507 val2str(data[1], sol_parameter_vals), channel);
508 params->payload_channel = channel;
509 break;
510 default:
511 lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s",
512 val2str(data[1], sol_parameter_vals),
513 val2str(rsp->ccode, completion_code_vals));
514 return (-1);
515 }
516
517 /*
518 * SOL payload port
519 */
520 memset(data, 0, sizeof(data));
521 data[0] = channel; /* channel number */
522 data[1] = SOL_PARAMETER_SOL_PAYLOAD_PORT; /* parameter selector */
523 data[2] = 0x00; /* set selector */
524 data[3] = 0x00; /* block selector */
525
526 rsp = intf->sendrecv(intf, &req);
527 if (rsp == NULL) {
528 lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'",
529 val2str(data[1], sol_parameter_vals));
530 return (-1);
531 }
532
533 switch (rsp->ccode) {
534 case 0x00:
535 if (rsp->data_len == 3) {
536 params->payload_port = (rsp->data[1]) | (rsp->data[2] << 8);
537 } else {
538 lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
539 "for SOL parameter '%s'",
540 rsp->data_len,
541 val2str(data[1], sol_parameter_vals));
542 }
543 break;
544 case 0x80:
545 if( intf->session != NULL ) {
546 lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported - defaulting to %d",
547 val2str(data[1], sol_parameter_vals), intf->ssn_params.port);
548 params->payload_port = intf->ssn_params.port;
549 } else {
550 lprintf(LOG_ERR,
551 "Info: SOL parameter '%s' not supported - can't determine which "
552 "payload port to use on NULL session",
553 val2str(data[1], sol_parameter_vals));
554 return (-1);
555 }
556 break;
557 default:
558 lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s",
559 val2str(data[1], sol_parameter_vals),
560 val2str(rsp->ccode, completion_code_vals));
561 return (-1);
562 }
563
564 return 0;
565 }
566
567
568
569 /*
570 * ipmi_print_sol_info
571 */
572 static int
ipmi_print_sol_info(struct ipmi_intf * intf,uint8_t channel)573 ipmi_print_sol_info(struct ipmi_intf * intf, uint8_t channel)
574 {
575 struct sol_config_parameters params = {0};
576 if (ipmi_get_sol_info(intf, channel, ¶ms))
577 return -1;
578
579 if (csv_output)
580 {
581 printf("%s,",
582 val2str(params.set_in_progress & 0x03,
583 ipmi_set_in_progress_vals));
584 printf("%s,", params.enabled?"true": "false");
585 printf("%s,", params.force_encryption?"true":"false");
586 printf("%s,", params.force_encryption?"true":"false");
587 printf("%s,",
588 val2str(params.privilege_level, ipmi_privlvl_vals));
589 printf("%d,", params.character_accumulate_level * 5);
590 printf("%d,", params.character_send_threshold);
591 printf("%d,", params.retry_count);
592 printf("%d,", params.retry_interval * 10);
593
594 printf("%s,",
595 val2str(params.volatile_bit_rate, ipmi_bit_rate_vals));
596
597 printf("%s,",
598 val2str(params.non_volatile_bit_rate, ipmi_bit_rate_vals));
599
600 printf("%d,", params.payload_channel);
601 printf("%d\n", params.payload_port);
602 }
603 else
604 {
605 printf("Set in progress : %s\n",
606 val2str(params.set_in_progress & 0x03,
607 ipmi_set_in_progress_vals));
608 printf("Enabled : %s\n",
609 params.enabled?"true": "false");
610 printf("Force Encryption : %s\n",
611 params.force_encryption?"true":"false");
612 printf("Force Authentication : %s\n",
613 params.force_authentication?"true":"false");
614 printf("Privilege Level : %s\n",
615 val2str(params.privilege_level, ipmi_privlvl_vals));
616 printf("Character Accumulate Level (ms) : %d\n",
617 params.character_accumulate_level * 5);
618 printf("Character Send Threshold : %d\n",
619 params.character_send_threshold);
620 printf("Retry Count : %d\n",
621 params.retry_count);
622 printf("Retry Interval (ms) : %d\n",
623 params.retry_interval * 10);
624
625 printf("Volatile Bit Rate (kbps) : %s\n",
626 val2str(params.volatile_bit_rate, ipmi_bit_rate_vals));
627
628 printf("Non-Volatile Bit Rate (kbps) : %s\n",
629 val2str(params.non_volatile_bit_rate, ipmi_bit_rate_vals));
630
631 printf("Payload Channel : %d (0x%02x)\n",
632 params.payload_channel, params.payload_channel);
633 printf("Payload Port : %d\n",
634 params.payload_port);
635 }
636
637 return 0;
638 }
639
640
641
642 /*
643 * Small function to validate that user-supplied SOL
644 * configuration parameter values we store in uint8_t
645 * data type falls within valid range. With minval
646 * and maxval parameters we can use the same function
647 * to validate parameters that have different ranges
648 * of values.
649 *
650 * function will return -1 if value is not valid, or
651 * will return 0 if valid.
652 */
ipmi_sol_set_param_isvalid_uint8_t(const char * strval,const char * name,int base,uint8_t minval,uint8_t maxval,uint8_t * out_value)653 int ipmi_sol_set_param_isvalid_uint8_t( const char *strval,
654 const char *name,
655 int base,
656 uint8_t minval,
657 uint8_t maxval,
658 uint8_t *out_value)
659 {
660 if (str2uchar(strval, out_value) != 0 || (*out_value < minval)
661 || (*out_value > maxval)) {
662 lprintf(LOG_ERR, "Invalid value %s for parameter %s",
663 strval, name);
664 lprintf(LOG_ERR, "Valid values are %d-%d", minval, maxval);
665 return -1;
666 }
667 return 0;
668 }
669
670
671 /*
672 * ipmi_sol_set_param
673 *
674 * Set the specified Serial Over LAN value to the specified
675 * value
676 *
677 * return 0 on success,
678 * -1 on failure
679 */
680 static int
ipmi_sol_set_param(struct ipmi_intf * intf,uint8_t channel,const char * param,const char * value,uint8_t guarded)681 ipmi_sol_set_param(struct ipmi_intf * intf,
682 uint8_t channel,
683 const char * param,
684 const char * value,
685 uint8_t guarded)
686 {
687 struct ipmi_rs * rsp;
688 struct ipmi_rq req;
689 uint8_t data[4];
690 int bGuarded = guarded; /* Use set-in-progress indicator? */
691
692 memset(&req, 0, sizeof(req));
693 req.msg.netfn = IPMI_NETFN_TRANSPORT; /* 0x0c */
694 req.msg.cmd = IPMI_SET_SOL_CONFIG_PARAMETERS; /* 0x21 */
695 req.msg.data = data;
696
697 data[0] = channel;
698
699 /*
700 * set-in-progress
701 */
702 if (! strcmp(param, "set-in-progress"))
703 {
704 bGuarded = 0; /* We _ARE_ the set-in-progress indicator */
705 req.msg.data_len = 3;
706 data[1] = SOL_PARAMETER_SET_IN_PROGRESS;
707
708 if (! strcmp(value, "set-complete"))
709 data[2] = 0x00;
710 else if (! strcmp(value, "set-in-progress"))
711 data[2] = 0x01;
712 else if (! strcmp(value, "commit-write"))
713 data[2] = 0x02;
714 else
715 {
716 lprintf(LOG_ERR, "Invalid value %s for parameter %s",
717 value, param);
718 lprintf(LOG_ERR, "Valid values are set-complete, set-in-progress "
719 "and commit-write");
720 return -1;
721 }
722 }
723
724
725 /*
726 * enabled
727 */
728 else if (! strcmp(param, "enabled"))
729 {
730 req.msg.data_len = 3;
731 data[1] = SOL_PARAMETER_SOL_ENABLE;
732
733 if (! strcmp(value, "true"))
734 data[2] = 0x01;
735 else if (! strcmp(value, "false"))
736 data[2] = 0x00;
737 else
738 {
739 lprintf(LOG_ERR, "Invalid value %s for parameter %s",
740 value, param);
741 lprintf(LOG_ERR, "Valid values are true and false");
742 return -1;
743 }
744 }
745
746
747 /*
748 * force-payload-encryption
749 */
750 else if (! strcmp(param, "force-encryption"))
751 {
752 struct sol_config_parameters params;
753
754 req.msg.data_len = 3;
755 data[1] = SOL_PARAMETER_SOL_AUTHENTICATION;
756
757 if (! strcmp(value, "true"))
758 data[2] = 0x80;
759 else if (! strcmp(value, "false"))
760 data[2] = 0x00;
761 else
762 {
763 lprintf(LOG_ERR, "Invalid value %s for parameter %s",
764 value, param);
765 lprintf(LOG_ERR, "Valid values are true and false");
766 return -1;
767 }
768
769
770 /* We need other values to complete the request */
771 if (ipmi_get_sol_info(intf, channel, ¶ms))
772 {
773 lprintf(LOG_ERR, "Error fetching SOL parameters for %s update",
774 param);
775 return -1;
776 }
777
778 data[2] |= params.force_authentication? 0x40 : 0x00;
779 data[2] |= params.privilege_level;
780 }
781
782
783 /*
784 * force-payload-authentication
785 */
786 else if (! strcmp(param, "force-authentication"))
787 {
788 struct sol_config_parameters params;
789
790 req.msg.data_len = 3;
791 data[1] = SOL_PARAMETER_SOL_AUTHENTICATION;
792
793 if (! strcmp(value, "true"))
794 data[2] = 0x40;
795 else if (! strcmp(value, "false"))
796 data[2] = 0x00;
797 else
798 {
799 lprintf(LOG_ERR, "Invalid value %s for parameter %s",
800 value, param);
801 lprintf(LOG_ERR, "Valid values are true and false");
802 return -1;
803 }
804
805
806 /* We need other values to complete the request */
807 if (ipmi_get_sol_info(intf, channel, ¶ms))
808 {
809 lprintf(LOG_ERR, "Error fetching SOL parameters for %s update",
810 param);
811 return -1;
812 }
813
814 data[2] |= params.force_encryption? 0x80 : 0x00;
815 data[2] |= params.privilege_level;
816 }
817
818
819 /*
820 * privilege-level
821 */
822 else if (! strcmp(param, "privilege-level"))
823 {
824 struct sol_config_parameters params;
825
826 req.msg.data_len = 3;
827 data[1] = SOL_PARAMETER_SOL_AUTHENTICATION;
828
829 if (! strcmp(value, "user"))
830 data[2] = 0x02;
831 else if (! strcmp(value, "operator"))
832 data[2] = 0x03;
833 else if (! strcmp(value, "admin"))
834 data[2] = 0x04;
835 else if (! strcmp(value, "oem"))
836 data[2] = 0x05;
837 else
838 {
839 lprintf(LOG_ERR, "Invalid value %s for parameter %s",
840 value, param);
841 lprintf(LOG_ERR, "Valid values are user, operator, admin, and oem");
842 return -1;
843 }
844
845
846 /* We need other values to complete the request */
847 if (ipmi_get_sol_info(intf, channel, ¶ms))
848 {
849 lprintf(LOG_ERR, "Error fetching SOL parameters for %s update",
850 param);
851 return -1;
852 }
853
854 data[2] |= params.force_encryption? 0x80 : 0x00;
855 data[2] |= params.force_authentication? 0x40 : 0x00;
856 }
857
858
859 /*
860 * character-accumulate-level
861 */
862 else if (! strcmp(param, "character-accumulate-level"))
863 {
864 struct sol_config_parameters params;
865
866 req.msg.data_len = 4;
867 data[1] = SOL_PARAMETER_CHARACTER_INTERVAL;
868
869 /* validate user-supplied input */
870 if (ipmi_sol_set_param_isvalid_uint8_t(value, param, 0, 1, 255, &data[2]))
871 return -1;
872
873 /* We need other values to complete the request */
874 if (ipmi_get_sol_info(intf, channel, ¶ms))
875 {
876 lprintf(LOG_ERR, "Error fetching SOL parameters for %s update",
877 param);
878 return -1;
879 }
880
881 data[3] = params.character_send_threshold;
882 }
883
884
885 /*
886 * character-send-threshold
887 */
888 else if (! strcmp(param, "character-send-threshold"))
889 {
890 struct sol_config_parameters params;
891
892 req.msg.data_len = 4;
893 data[1] = SOL_PARAMETER_CHARACTER_INTERVAL;
894
895 /* validate user-supplied input */
896 if (ipmi_sol_set_param_isvalid_uint8_t(value, param, 0, 0, 255, &data[3]))
897 return -1;
898
899 /* We need other values to complete the request */
900 if (ipmi_get_sol_info(intf, channel, ¶ms))
901 {
902 lprintf(LOG_ERR, "Error fetching SOL parameters for %s update",
903 param);
904 return -1;
905 }
906
907 data[2] = params.character_accumulate_level;
908 }
909
910
911 /*
912 * retry-count
913 */
914 else if (! strcmp(param, "retry-count"))
915 {
916 struct sol_config_parameters params;
917
918 req.msg.data_len = 4;
919 data[1] = SOL_PARAMETER_SOL_RETRY;
920
921 /* validate user input, 7 is max value */
922 if (ipmi_sol_set_param_isvalid_uint8_t(value, param, 0, 0, 7, &data[2]))
923 return -1;
924
925 /* We need other values to complete the request */
926 if (ipmi_get_sol_info(intf, channel, ¶ms))
927 {
928 lprintf(LOG_ERR, "Error fetching SOL parameters for %s update",
929 param);
930 return -1;
931 }
932
933 data[3] = params.retry_interval;
934 }
935
936
937 /*
938 * retry-interval
939 */
940 else if (! strcmp(param, "retry-interval"))
941 {
942 struct sol_config_parameters params;
943
944 req.msg.data_len = 4;
945 data[1] = SOL_PARAMETER_SOL_RETRY;
946
947 /* validate user-supplied input */
948 if (ipmi_sol_set_param_isvalid_uint8_t(value, param, 0, 0, 255, &data[3]))
949 return -1;
950
951 /* We need other values to complete the request */
952 if (ipmi_get_sol_info(intf, channel, ¶ms))
953 {
954 lprintf(LOG_ERR, "Error fetching SOL parameters for %s update",
955 param);
956 return -1;
957 }
958
959 data[2] = params.retry_count;
960 }
961
962
963 /*
964 * non-volatile-bit-rate
965 */
966 else if (! strcmp(param, "non-volatile-bit-rate"))
967 {
968 req.msg.data_len = 3;
969 data[1] = SOL_PARAMETER_SOL_NON_VOLATILE_BIT_RATE;
970
971 if (!strcmp(value, "serial"))
972 {
973 data[2] = 0x00;
974 }
975 else if (!strcmp(value, "9.6"))
976 {
977 data[2] = 0x06;
978 }
979 else if (!strcmp(value, "19.2"))
980 {
981 data[2] = 0x07;
982 }
983 else if (!strcmp(value, "38.4"))
984 {
985 data[2] = 0x08;
986 }
987 else if (!strcmp(value, "57.6"))
988 {
989 data[2] = 0x09;
990 }
991 else if (!strcmp(value, "115.2"))
992 {
993 data[2] = 0x0A;
994 }
995 else
996 {
997 lprintf(LOG_ERR, "Invalid value \"%s\" for parameter \"%s\"",
998 value,
999 param);
1000 lprintf(LOG_ERR, "Valid values are serial, 9.6 19.2, 38.4, 57.6 and 115.2");
1001 return -1;
1002 }
1003 }
1004
1005
1006 /*
1007 * volatile-bit-rate
1008 */
1009 else if (! strcmp(param, "volatile-bit-rate"))
1010 {
1011 req.msg.data_len = 3;
1012 data[1] = SOL_PARAMETER_SOL_VOLATILE_BIT_RATE;
1013
1014 if (!strcmp(value, "serial"))
1015 {
1016 data[2] = 0x00;
1017 }
1018 else if (!strcmp(value, "9.6"))
1019 {
1020 data[2] = 0x06;
1021 }
1022 else if (!strcmp(value, "19.2"))
1023 {
1024 data[2] = 0x07;
1025 }
1026 else if (!strcmp(value, "38.4"))
1027 {
1028 data[2] = 0x08;
1029 }
1030 else if (!strcmp(value, "57.6"))
1031 {
1032 data[2] = 0x09;
1033 }
1034 else if (!strcmp(value, "115.2"))
1035 {
1036 data[2] = 0x0A;
1037 }
1038 else
1039 {
1040 lprintf(LOG_ERR, "Invalid value \"%s\" for parameter \"%s\"",
1041 value,
1042 param);
1043 lprintf(LOG_ERR, "Valid values are serial, 9.6 19.2, 38.4, 57.6 and 115.2");
1044 return -1;
1045 }
1046 }
1047 else
1048 {
1049 lprintf(LOG_ERR, "Error: invalid SOL parameter %s", param);
1050 return -1;
1051 }
1052
1053
1054 /*
1055 * Execute the request
1056 */
1057 if (bGuarded &&
1058 (ipmi_sol_set_param(intf,
1059 channel,
1060 "set-in-progress",
1061 "set-in-progress",
1062 bGuarded)))
1063 {
1064 lprintf(LOG_ERR, "Error: set of parameter \"%s\" failed", param);
1065 return -1;
1066 }
1067
1068
1069 /* The command proper */
1070 rsp = intf->sendrecv(intf, &req);
1071
1072 if (rsp == NULL) {
1073 lprintf(LOG_ERR, "Error setting SOL parameter '%s'", param);
1074 return -1;
1075 }
1076
1077 if (!(!strncmp(param, "set-in-progress", 15) && !strncmp(value, "commit-write", 12)) &&
1078 rsp->ccode > 0) {
1079 switch (rsp->ccode) {
1080 case 0x80:
1081 lprintf(LOG_ERR, "Error setting SOL parameter '%s': "
1082 "Parameter not supported", param);
1083 break;
1084 case 0x81:
1085 lprintf(LOG_ERR, "Error setting SOL parameter '%s': "
1086 "Attempt to set set-in-progress when not in set-complete state",
1087 param);
1088 break;
1089 case 0x82:
1090 lprintf(LOG_ERR, "Error setting SOL parameter '%s': "
1091 "Attempt to write read-only parameter", param);
1092 break;
1093 case 0x83:
1094 lprintf(LOG_ERR, "Error setting SOL parameter '%s': "
1095 "Attempt to read write-only parameter", param);
1096 break;
1097 default:
1098 lprintf(LOG_ERR, "Error setting SOL parameter '%s' to '%s': %s",
1099 param, value, val2str(rsp->ccode, completion_code_vals));
1100 break;
1101 }
1102
1103 if (bGuarded &&
1104 (ipmi_sol_set_param(intf,
1105 channel,
1106 "set-in-progress",
1107 "set-complete",
1108 bGuarded)))
1109 {
1110 lprintf(LOG_ERR, "Error could not set \"set-in-progress\" "
1111 "to \"set-complete\"");
1112 }
1113
1114 return -1;
1115 }
1116
1117
1118 /*
1119 * The commit write could very well fail, but that's ok.
1120 * It may not be implemented.
1121 */
1122 if (bGuarded)
1123 ipmi_sol_set_param(intf,
1124 channel,
1125 "set-in-progress",
1126 "commit-write",
1127 bGuarded);
1128
1129
1130 if (bGuarded &&
1131 ipmi_sol_set_param(intf,
1132 channel,
1133 "set-in-progress",
1134 "set-complete",
1135 bGuarded))
1136 {
1137 lprintf(LOG_ERR, "Error could not set \"set-in-progress\" "
1138 "to \"set-complete\"");
1139 return -1;
1140 }
1141
1142 return 0;
1143 }
1144
1145
1146
1147 void
leave_raw_mode(void)1148 leave_raw_mode(void)
1149 {
1150 if (!_in_raw_mode)
1151 return;
1152 if (tcsetattr(fileno(stdin), TCSADRAIN, &_saved_tio) == -1)
1153 perror("tcsetattr");
1154 else
1155 _in_raw_mode = 0;
1156 }
1157
1158
1159
1160 void
enter_raw_mode(void)1161 enter_raw_mode(void)
1162 {
1163 struct termios tio;
1164 if (tcgetattr(fileno(stdin), &tio) == -1) {
1165 perror("tcgetattr");
1166 return;
1167 }
1168 _saved_tio = tio;
1169 tio.c_iflag |= IGNPAR;
1170 tio.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF);
1171 tio.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
1172 // #ifdef IEXTEN
1173 tio.c_lflag &= ~IEXTEN;
1174 // #endif
1175 tio.c_oflag &= ~OPOST;
1176 tio.c_cc[VMIN] = 1;
1177 tio.c_cc[VTIME] = 0;
1178 if (tcsetattr(fileno(stdin), TCSADRAIN, &tio) == -1)
1179 perror("tcsetattr");
1180 else
1181 _in_raw_mode = 1;
1182 }
1183
1184
1185 static void
sendBreak(struct ipmi_intf * intf)1186 sendBreak(struct ipmi_intf * intf)
1187 {
1188 struct ipmi_v2_payload v2_payload;
1189
1190 memset(&v2_payload, 0, sizeof(v2_payload));
1191
1192 v2_payload.payload.sol_packet.character_count = 0;
1193 v2_payload.payload.sol_packet.generate_break = 1;
1194
1195 intf->send_sol(intf, &v2_payload);
1196 }
1197
1198
1199
1200 /*
1201 * suspendSelf
1202 *
1203 * Put ourself in the background
1204 *
1205 * param bRestoreTty specifies whether we will put our self back
1206 * in raw mode when we resume
1207 */
1208 static void
suspendSelf(int bRestoreTty)1209 suspendSelf(int bRestoreTty)
1210 {
1211 leave_raw_mode();
1212 kill(getpid(), SIGTSTP);
1213
1214 if (bRestoreTty)
1215 enter_raw_mode();
1216 }
1217
1218
1219
1220 /*
1221 * printSolEscapeSequences
1222 *
1223 * Send some useful documentation to the user
1224 */
1225 static void
printSolEscapeSequences(struct ipmi_intf * intf)1226 printSolEscapeSequences(struct ipmi_intf * intf)
1227 {
1228 printf(
1229 "%c?\n\
1230 Supported escape sequences:\n\
1231 %c. - terminate connection\n\
1232 %c^Z - suspend ipmitool\n\
1233 %c^X - suspend ipmitool, but don't restore tty on restart\n\
1234 %cB - send break\n\
1235 %c? - this message\n\
1236 %c%c - send the escape character by typing it twice\n\
1237 (Note that escapes are only recognized immediately after newline.)\n",
1238 intf->ssn_params.sol_escape_char,
1239 intf->ssn_params.sol_escape_char,
1240 intf->ssn_params.sol_escape_char,
1241 intf->ssn_params.sol_escape_char,
1242 intf->ssn_params.sol_escape_char,
1243 intf->ssn_params.sol_escape_char,
1244 intf->ssn_params.sol_escape_char,
1245 intf->ssn_params.sol_escape_char);
1246 }
1247
1248
1249
1250 /*
1251 * output
1252 *
1253 * Send the specified data to stdout
1254 */
1255 static void
output(struct ipmi_rs * rsp)1256 output(struct ipmi_rs * rsp)
1257 {
1258 /* Add checks to make sure it is actually SOL data, in general I see
1259 * outside code mostly trying to guard against this happening, but
1260 * some places fail to do so, so I do so here to make sure nothing gets
1261 * through. If non-sol data comes through here, there is probably
1262 * a packet that won't get processed somewhere else, but the alternative
1263 * of outputting corrupt data is worse. Generally I see the get device
1264 * id response make it here somehow. I assume it is a heartbeat and the
1265 * other code will retry if it cares about the response and misses it.
1266 */
1267 if (rsp &&
1268 (rsp->session.authtype == IPMI_SESSION_AUTHTYPE_RMCP_PLUS) &&
1269 (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL))
1270 {
1271 int i;
1272
1273 for (i = 0; i < rsp->data_len; ++i)
1274 putc(rsp->data[i], stdout);
1275
1276 fflush(stdout);
1277 }
1278 }
1279
1280
1281
1282 /*
1283 * ipmi_sol_deactivate
1284 */
1285 static int
ipmi_sol_deactivate(struct ipmi_intf * intf,int instance)1286 ipmi_sol_deactivate(struct ipmi_intf * intf, int instance)
1287 {
1288 struct ipmi_rs * rsp;
1289 struct ipmi_rq req;
1290 uint8_t data[6];
1291
1292 if ((instance <= 0) || (instance > 15)) {
1293 lprintf(LOG_ERR, "Error: Instance must range from 1 to 15");
1294 return -1;
1295 }
1296
1297 memset(&req, 0, sizeof(req));
1298 req.msg.netfn = IPMI_NETFN_APP;
1299 req.msg.cmd = IPMI_DEACTIVATE_PAYLOAD;
1300 req.msg.data_len = 6;
1301 req.msg.data = data;
1302
1303 memset(data, 0, sizeof(data));
1304 data[0] = IPMI_PAYLOAD_TYPE_SOL; /* payload type */
1305 data[1] = instance; /* payload instance. */
1306
1307 /* Lots of important data */
1308 data[2] = 0;
1309 data[3] = 0;
1310 data[4] = 0;
1311 data[5] = 0;
1312
1313 rsp = intf->sendrecv(intf, &req);
1314
1315 if (NULL != rsp) {
1316 switch (rsp->ccode) {
1317 case 0x00:
1318 return 0;
1319 case 0x80:
1320 lprintf(LOG_ERR, "Info: SOL payload already de-activated");
1321 break;
1322 case 0x81:
1323 lprintf(LOG_ERR, "Info: SOL payload type disabled");
1324 break;
1325 default:
1326 lprintf(LOG_ERR, "Error de-activating SOL payload: %s",
1327 val2str(rsp->ccode, completion_code_vals));
1328 break;
1329 }
1330 } else {
1331 lprintf(LOG_ERR, "Error: No response de-activating SOL payload");
1332 }
1333
1334 return -1;
1335 }
1336
1337
1338
1339 /*
1340 * processSolUserInput
1341 *
1342 * Act on user input into the SOL session. The only reason this
1343 * is complicated is that we have to process escape sequences.
1344 *
1345 * return 0 on success
1346 * 1 if we should exit
1347 * < 0 on error (BMC probably closed the session)
1348 */
1349 static int
processSolUserInput(struct ipmi_intf * intf,uint8_t * input,uint16_t buffer_length)1350 processSolUserInput(
1351 struct ipmi_intf * intf,
1352 uint8_t * input,
1353 uint16_t buffer_length)
1354 {
1355 static int escape_pending = 0;
1356 static int last_was_cr = 1;
1357 struct ipmi_v2_payload v2_payload;
1358 int length = 0;
1359 int retval = 0;
1360 char ch;
1361 int i;
1362
1363 memset(&v2_payload, 0, sizeof(v2_payload));
1364
1365 /*
1366 * Our first order of business is to check the input for escape
1367 * sequences to act on.
1368 */
1369 for (i = 0; i < buffer_length; ++i)
1370 {
1371 ch = input[i];
1372
1373 if (escape_pending){
1374 escape_pending = 0;
1375
1376 /*
1377 * Process a possible escape sequence.
1378 */
1379 switch (ch) {
1380 case '.':
1381 printf("%c. [terminated ipmitool]\n",
1382 intf->ssn_params.sol_escape_char);
1383 retval = 1;
1384 break;
1385
1386 case 'Z' - 64:
1387 printf("%c^Z [suspend ipmitool]\n",
1388 intf->ssn_params.sol_escape_char);
1389 suspendSelf(1); /* Restore tty back to raw */
1390 continue;
1391
1392 case 'X' - 64:
1393 printf("%c^Z [suspend ipmitool]\n",
1394 intf->ssn_params.sol_escape_char);
1395 suspendSelf(0); /* Don't restore to raw mode */
1396 continue;
1397
1398 case 'B':
1399 printf("%cB [send break]\n",
1400 intf->ssn_params.sol_escape_char);
1401 sendBreak(intf);
1402 continue;
1403
1404 case '?':
1405 printSolEscapeSequences(intf);
1406 continue;
1407
1408 default:
1409 if (ch != intf->ssn_params.sol_escape_char)
1410 v2_payload.payload.sol_packet.data[length++] =
1411 intf->ssn_params.sol_escape_char;
1412 v2_payload.payload.sol_packet.data[length++] = ch;
1413 }
1414 }
1415
1416 else
1417 {
1418 if (last_was_cr && (ch == intf->ssn_params.sol_escape_char)) {
1419 escape_pending = 1;
1420 continue;
1421 }
1422
1423 v2_payload.payload.sol_packet.data[length++] = ch;
1424 }
1425
1426
1427 /*
1428 * Normal character. Record whether it was a newline.
1429 */
1430 last_was_cr = (ch == '\r' || ch == '\n');
1431 }
1432
1433
1434 /*
1435 * If there is anything left to process we dispatch it to the BMC,
1436 * send intf->session->sol_data.max_outbound_payload_size bytes
1437 * at a time.
1438 */
1439 if (length)
1440 {
1441 struct ipmi_rs * rsp = NULL;
1442 int try = 0;
1443
1444 while (try < intf->ssn_params.retry) {
1445
1446 v2_payload.payload.sol_packet.character_count = length;
1447
1448 rsp = intf->send_sol(intf, &v2_payload);
1449
1450 if (rsp)
1451 {
1452 break;
1453 }
1454
1455 usleep(5000);
1456 try++;
1457 }
1458
1459 if (! rsp)
1460 {
1461 lprintf(LOG_ERR, "Error sending SOL data: FAIL");
1462 retval = -1;
1463 }
1464
1465 /* If the sequence number is set we know we have new data */
1466 if (retval == 0)
1467 if ((rsp->session.authtype == IPMI_SESSION_AUTHTYPE_RMCP_PLUS) &&
1468 (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL) &&
1469 (rsp->payload.sol_packet.packet_sequence_number))
1470 output(rsp);
1471 }
1472
1473 return retval;
1474 }
1475
1476 static int
ipmi_sol_keepalive_using_sol(struct ipmi_intf * intf)1477 ipmi_sol_keepalive_using_sol(struct ipmi_intf * intf)
1478 {
1479 struct ipmi_v2_payload v2_payload;
1480 struct timeval end;
1481
1482 if (_disable_keepalive)
1483 return 0;
1484
1485 gettimeofday(&end, 0);
1486
1487 if (end.tv_sec - _start_keepalive.tv_sec > SOL_KEEPALIVE_TIMEOUT) {
1488 memset(&v2_payload, 0, sizeof(v2_payload));
1489 v2_payload.payload.sol_packet.character_count = 0;
1490 if (intf->send_sol(intf, &v2_payload) == NULL)
1491 return -1;
1492 /* good return, reset start time */
1493 gettimeofday(&_start_keepalive, 0);
1494 }
1495 return 0;
1496 }
1497
1498 static int
ipmi_sol_keepalive_using_getdeviceid(struct ipmi_intf * intf)1499 ipmi_sol_keepalive_using_getdeviceid(struct ipmi_intf * intf)
1500 {
1501 struct timeval end;
1502
1503 if (_disable_keepalive)
1504 return 0;
1505
1506 gettimeofday(&end, 0);
1507
1508 if (end.tv_sec - _start_keepalive.tv_sec > SOL_KEEPALIVE_TIMEOUT) {
1509 if (intf->keepalive(intf) != 0)
1510 return -1;
1511 /* good return, reset start time */
1512 gettimeofday(&_start_keepalive, 0);
1513 }
1514 return 0;
1515 }
1516
1517
1518
1519 /*
1520 * ipmi_sol_red_pill
1521 */
1522 static int
ipmi_sol_red_pill(struct ipmi_intf * intf,int instance)1523 ipmi_sol_red_pill(struct ipmi_intf * intf, int instance)
1524 {
1525 char * buffer;
1526 int numRead;
1527 int bShouldExit = 0;
1528 int bBmcClosedSession = 0;
1529 fd_set read_fds;
1530 struct timeval tv;
1531 int retval;
1532 int buffer_size = intf->session->sol_data.max_inbound_payload_size;
1533 int keepAliveRet = 0;
1534 int retrySol = 0;
1535
1536 /* Subtract SOL header from max_inbound_payload_size */
1537 if (buffer_size > 4)
1538 buffer_size -= 4;
1539
1540 buffer = (char*)malloc(buffer_size);
1541 if (buffer == NULL) {
1542 lprintf(LOG_ERR, "ipmitool: malloc failure");
1543 return -1;
1544 }
1545
1546 /* Initialize keepalive start time */
1547 gettimeofday(&_start_keepalive, 0);
1548
1549 enter_raw_mode();
1550
1551 while (! bShouldExit)
1552 {
1553 FD_ZERO(&read_fds);
1554 FD_SET(0, &read_fds);
1555 FD_SET(intf->fd, &read_fds);
1556
1557 if (!ipmi_oem_active(intf,"i82571spt"))
1558 {
1559 /* Send periodic keepalive packet */
1560 if(_use_sol_for_keepalive == 0)
1561 {
1562 keepAliveRet = ipmi_sol_keepalive_using_getdeviceid(intf);
1563 }
1564 else
1565 {
1566 keepAliveRet = ipmi_sol_keepalive_using_sol(intf);
1567 }
1568
1569 if (keepAliveRet != 0)
1570 {
1571 /*
1572 * Retrying the keep Alive before declaring a communication
1573 * lost state with the IPMC. Helpful when the payload is
1574 * reset and brings down the connection temporarily. Otherwise,
1575 * if we send getDevice Id to check the status of IPMC during
1576 * this down time when the connection is restarting, SOL will
1577 * exit even though the IPMC is available and the session is open.
1578 */
1579 if (retrySol == MAX_SOL_RETRY)
1580 {
1581 /* no response to Get Device ID keepalive message */
1582 bShouldExit = 1;
1583 continue;
1584 }
1585 else
1586 {
1587 retrySol++;
1588 }
1589 }
1590 else
1591 {
1592 /* if the keep Alive is successful reset retries to zero */
1593 retrySol = 0;
1594 }
1595 } /* !oem="i82571spt" */
1596 /* Wait up to half a second */
1597 tv.tv_sec = 0;
1598 tv.tv_usec = 500000;
1599
1600 retval = select(intf->fd + 1, &read_fds, NULL, NULL, &tv);
1601
1602 if (retval)
1603 {
1604 if (retval == -1)
1605 {
1606 /* ERROR */
1607 perror("select");
1608 return -1;
1609 }
1610
1611
1612 /*
1613 * Process input from the user
1614 */
1615 if (FD_ISSET(0, &read_fds))
1616 {
1617 memset(buffer, 0, buffer_size);
1618 numRead = read(fileno(stdin),
1619 buffer,
1620 buffer_size);
1621
1622 if (numRead > 0)
1623 {
1624 int rc = processSolUserInput(intf, (uint8_t *)buffer, numRead);
1625
1626 if (rc)
1627 {
1628 if (rc < 0)
1629 bShouldExit = bBmcClosedSession = 1;
1630 else
1631 bShouldExit = 1;
1632 }
1633 }
1634 else
1635 {
1636 bShouldExit = 1;
1637 }
1638 }
1639
1640
1641 /*
1642 * Process input from the BMC
1643 */
1644 else if (FD_ISSET(intf->fd, &read_fds))
1645 {
1646 struct ipmi_rs * rs =intf->recv_sol(intf);
1647 if ( rs)
1648 {
1649 output(rs);
1650 }
1651 /*
1652 * Should recv_sol come back null, the incoming packet was not ours.
1653 * Just fall through, the keepalive logic will determine if
1654 * the BMC has dropped the session.
1655 */
1656 }
1657
1658
1659 /*
1660 * ERROR in select
1661 */
1662 else
1663 {
1664 lprintf(LOG_ERR, "Error: Select returned with nothing to read");
1665 bShouldExit = 1;
1666 }
1667 }
1668 }
1669
1670 leave_raw_mode();
1671
1672 if (keepAliveRet != 0)
1673 {
1674 lprintf(LOG_ERR, "Error: No response to keepalive - Terminating session");
1675 /* attempt to clean up anyway */
1676 ipmi_sol_deactivate(intf, instance);
1677 exit(1);
1678 }
1679
1680 if (bBmcClosedSession)
1681 {
1682 lprintf(LOG_ERR, "SOL session closed by BMC");
1683 exit(1);
1684 }
1685 else
1686 ipmi_sol_deactivate(intf, instance);
1687
1688 return 0;
1689 }
1690
1691
1692
1693
1694 /*
1695 * ipmi_sol_activate
1696 */
1697 static int
ipmi_sol_activate(struct ipmi_intf * intf,int looptest,int interval,int instance)1698 ipmi_sol_activate(struct ipmi_intf * intf, int looptest, int interval,
1699 int instance)
1700 {
1701 struct ipmi_rs * rsp;
1702 struct ipmi_rq req;
1703 struct activate_payload_rsp ap_rsp;
1704 uint8_t data[6];
1705 uint8_t bSolEncryption = 1;
1706 uint8_t bSolAuthentication = 1;
1707
1708 /*
1709 * This command is only available over RMCP+ (the lanplus
1710 * interface).
1711 */
1712 if (strncmp(intf->name, "lanplus", 7) != 0)
1713 {
1714 lprintf(LOG_ERR, "Error: This command is only available over the "
1715 "lanplus interface");
1716 return -1;
1717 }
1718
1719 if ((instance <= 0) || (instance > 15)) {
1720 lprintf(LOG_ERR, "Error: Instance must range from 1 to 15");
1721 return -1;
1722 }
1723
1724
1725 /*
1726 * Setup a callback so that the lanplus processing knows what
1727 * to do with packets that come unexpectedly (while waiting for
1728 * an ACK, perhaps.
1729 */
1730 intf->session->sol_data.sol_input_handler = output;
1731
1732
1733 memset(&req, 0, sizeof(req));
1734 req.msg.netfn = IPMI_NETFN_APP;
1735 req.msg.cmd = IPMI_ACTIVATE_PAYLOAD;
1736 req.msg.data_len = 6;
1737 req.msg.data = data;
1738
1739 data[0] = IPMI_PAYLOAD_TYPE_SOL; /* payload type */
1740 data[1] = instance; /* payload instance */
1741
1742 /* Lots of important data. Most is default */
1743 data[2] = bSolEncryption? 0x80 : 0;
1744 data[2] |= bSolAuthentication? 0x40 : 0;
1745 data[2] |= IPMI_SOL_SERIAL_ALERT_MASK_DEFERRED;
1746
1747 if (ipmi_oem_active(intf, "intelplus")) {
1748 data[2] |= IPMI_SOL_BMC_ASSERTS_CTS_MASK_TRUE;
1749 } else if (ipmi_oem_active(intf, "i82571spt")) {
1750 /*
1751 * A quote from Intel: "Engineering believes the problem
1752 * lies within the Auxiliary data being sent with the
1753 * 'Activate Payload' command from IPMITool. IPMITool
1754 * sends a C6h which sets some bits having to do with
1755 * encryption and some behavior dealing with CTS DCD/DSR.
1756 * I recommend that the customer modify this request
1757 * to send 08h instead. This is what our internal utility
1758 * sends and it works without issue. I will work with
1759 * engineering to ensure the settings that IPMITool uses
1760 * (C6h) are supported in the future.
1761 */
1762 data[2] = 0x08;
1763 } else {
1764 data[2] |= IPMI_SOL_BMC_ASSERTS_CTS_MASK_FALSE;
1765 }
1766
1767 data[3] = 0x00; /* reserved */
1768 data[4] = 0x00; /* reserved */
1769 data[5] = 0x00; /* reserved */
1770
1771 rsp = intf->sendrecv(intf, &req);
1772
1773 if (NULL != rsp) {
1774 switch (rsp->ccode) {
1775 case 0x00:
1776 if (rsp->data_len == 12) {
1777 break;
1778 } else {
1779 lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
1780 "in payload activation response",
1781 rsp->data_len);
1782 return -1;
1783 }
1784 break;
1785 case 0x80:
1786 lprintf(LOG_ERR, "Info: SOL payload already active on another session");
1787 return -1;
1788 case 0x81:
1789 lprintf(LOG_ERR, "Info: SOL payload disabled");
1790 return -1;
1791 case 0x82:
1792 lprintf(LOG_ERR, "Info: SOL payload activation limit reached");
1793 return -1;
1794 case 0x83:
1795 lprintf(LOG_ERR, "Info: cannot activate SOL payload with encryption");
1796 return -1;
1797 case 0x84:
1798 lprintf(LOG_ERR, "Info: cannot activate SOL payload without encryption");
1799 return -1;
1800 default:
1801 lprintf(LOG_ERR, "Error activating SOL payload: %s",
1802 val2str(rsp->ccode, completion_code_vals));
1803 return -1;
1804 }
1805 } else {
1806 lprintf(LOG_ERR, "Error: No response activating SOL payload");
1807 return -1;
1808 }
1809
1810
1811 memcpy(&ap_rsp, rsp->data, sizeof(struct activate_payload_rsp));
1812
1813 intf->session->sol_data.max_inbound_payload_size =
1814 (ap_rsp.inbound_payload_size[1] << 8) |
1815 ap_rsp.inbound_payload_size[0];
1816
1817 intf->session->sol_data.max_outbound_payload_size =
1818 (ap_rsp.outbound_payload_size[1] << 8) |
1819 ap_rsp.outbound_payload_size[0];
1820
1821 intf->session->sol_data.port =
1822 (ap_rsp.payload_udp_port[1] << 8) |
1823 ap_rsp.payload_udp_port[0];
1824
1825 intf->session->timeout = 1;
1826
1827
1828 /* NOTE: the spec does allow for SOL traffic to be sent on
1829 * a different port. we do not yet support that feature. */
1830 if (intf->session->sol_data.port != intf->ssn_params.port)
1831 {
1832 /* try byteswapping port in case BMC sent it incorrectly */
1833 uint16_t portswap = BSWAP_16(intf->session->sol_data.port);
1834
1835 if (portswap == intf->ssn_params.port) {
1836 intf->session->sol_data.port = portswap;
1837 }
1838 else {
1839 lprintf(LOG_ERR, "Error: BMC requests SOL session on different port");
1840 return -1;
1841 }
1842 }
1843
1844 printf("[SOL Session operational. Use %c? for help]\n",
1845 intf->ssn_params.sol_escape_char);
1846
1847 if(looptest == 1)
1848 {
1849 ipmi_sol_deactivate(intf, instance);
1850 usleep(interval*1000);
1851 return 0;
1852 }
1853
1854 /*
1855 * At this point we are good to go with our SOL session. We
1856 * need to listen to
1857 * 1) STDIN for user input
1858 * 2) The FD for incoming SOL packets
1859 */
1860 if (ipmi_sol_red_pill(intf, instance))
1861 {
1862 lprintf(LOG_ERR, "Error in SOL session");
1863 return -1;
1864 }
1865
1866 return 0;
1867 }
1868
1869
1870
1871 /*
1872 * print_sol_usage
1873 */
1874 static void
print_sol_usage(void)1875 print_sol_usage(void)
1876 {
1877 lprintf(LOG_NOTICE, "SOL Commands: info [<channel number>]");
1878 lprintf(LOG_NOTICE, " set <parameter> <value> [channel]");
1879 lprintf(LOG_NOTICE, " payload <enable|disable|status> [channel] [userid]");
1880 lprintf(LOG_NOTICE, " activate [<usesolkeepalive|nokeepalive>] [instance=<number>]");
1881 lprintf(LOG_NOTICE, " deactivate [instance=<number>]");
1882 lprintf(LOG_NOTICE, " looptest [<loop times> [<loop interval(in ms)> [<instance>]]]");
1883 }
1884
1885
1886
1887 /*
1888 * print_sol_set_usage
1889 */
1890 static void
print_sol_set_usage(void)1891 print_sol_set_usage(void)
1892 {
1893 lprintf(LOG_NOTICE, "\nSOL set parameters and values: \n");
1894 lprintf(LOG_NOTICE, " set-in-progress set-complete | "
1895 "set-in-progress | commit-write");
1896 lprintf(LOG_NOTICE, " enabled true | false");
1897 lprintf(LOG_NOTICE, " force-encryption true | false");
1898 lprintf(LOG_NOTICE, " force-authentication true | false");
1899 lprintf(LOG_NOTICE, " privilege-level user | operator | admin | oem");
1900 lprintf(LOG_NOTICE, " character-accumulate-level <in 5 ms increments>");
1901 lprintf(LOG_NOTICE, " character-send-threshold N");
1902 lprintf(LOG_NOTICE, " retry-count N");
1903 lprintf(LOG_NOTICE, " retry-interval <in 10 ms increments>");
1904 lprintf(LOG_NOTICE, " non-volatile-bit-rate "
1905 "serial | 9.6 | 19.2 | 38.4 | 57.6 | 115.2");
1906 lprintf(LOG_NOTICE, " volatile-bit-rate "
1907 "serial | 9.6 | 19.2 | 38.4 | 57.6 | 115.2");
1908 lprintf(LOG_NOTICE, "");
1909 }
1910
1911
1912
1913 /* ipmi_sol_main */
1914 int
ipmi_sol_main(struct ipmi_intf * intf,int argc,char ** argv)1915 ipmi_sol_main(struct ipmi_intf * intf, int argc, char ** argv)
1916 {
1917 int retval = 0;
1918 if (!argc || !strncmp(argv[0], "help", 4)) {
1919 /* Help */
1920 print_sol_usage();
1921 } else if (!strncmp(argv[0], "info", 4)) {
1922 /* Info */
1923 uint8_t channel;
1924 if (argc == 1) {
1925 /* Ask about the current channel */
1926 channel = 0x0E;
1927 } else if (argc == 2) {
1928 if (is_ipmi_channel_num(argv[1], &channel) != 0) {
1929 return (-1);
1930 }
1931 } else {
1932 print_sol_usage();
1933 return -1;
1934 }
1935 retval = ipmi_print_sol_info(intf, channel);
1936 } else if (!strncmp(argv[0], "payload", 7)) {
1937 /* Payload enable or disable */
1938 uint8_t channel = 0xe;
1939 uint8_t userid = 1;
1940 int enable = -1;
1941 if (argc == 1 || argc > 4) {
1942 print_sol_usage();
1943 return -1;
1944 }
1945 if (argc >= 3) {
1946 if (is_ipmi_channel_num(argv[2], &channel) != 0) {
1947 return (-1);
1948 }
1949 }
1950 if (argc == 4) {
1951 if (is_ipmi_user_id(argv[3], &userid) != 0) {
1952 return (-1);
1953 }
1954 }
1955 if (!strncmp(argv[1], "enable", 6)) {
1956 enable = 1;
1957 } else if (!strncmp(argv[1], "disable", 7)) {
1958 enable = 0;
1959 } else if (!strncmp(argv[1], "status", 6)) {
1960 return ipmi_sol_payload_access_status(intf, channel, userid);
1961 } else {
1962 print_sol_usage();
1963 return -1;
1964 }
1965 retval = ipmi_sol_payload_access(intf, channel, userid, enable);
1966 } else if (!strncmp(argv[0], "set", 3)) {
1967 /* Set a parameter value */
1968 uint8_t channel = 0xe;
1969 uint8_t guard = 1;
1970 if (argc == 3) {
1971 channel = 0xe;
1972 } else if (argc == 4) {
1973 if (!strncmp(argv[3], "noguard", 7)) {
1974 guard = 0;
1975 } else {
1976 if (is_ipmi_channel_num(argv[3], &channel) != 0) {
1977 return (-1);
1978 }
1979 }
1980 } else if (argc == 5) {
1981 if (is_ipmi_channel_num(argv[3], &channel) != 0) {
1982 return (-1);
1983 }
1984 if (!strncmp(argv[4], "noguard", 7)) {
1985 guard = 0;
1986 }
1987 } else {
1988 print_sol_set_usage();
1989 return -1;
1990 }
1991 retval = ipmi_sol_set_param(intf, channel, argv[1], argv[2], guard);
1992 } else if (!strncmp(argv[0], "activate", 8)) {
1993 /* Activate */
1994 int i;
1995 uint8_t instance = 1;
1996 for (i = 1; i < argc; i++) {
1997 if (!strncmp(argv[i], "usesolkeepalive", 15)) {
1998 _use_sol_for_keepalive = 1;
1999 } else if (!strncmp(argv[i], "nokeepalive", 11)) {
2000 _disable_keepalive = 1;
2001 } else if (!strncmp(argv[i], "instance=", 9)) {
2002 if (str2uchar(argv[i] + 9, &instance) != 0) {
2003 lprintf(LOG_ERR, "Given instance '%s' is invalid.", argv[i] + 9);
2004 print_sol_usage();
2005 return -1;
2006 }
2007 } else {
2008 print_sol_usage();
2009 return -1;
2010 }
2011 }
2012 retval = ipmi_sol_activate(intf, 0, 0, instance);
2013 } else if (!strncmp(argv[0], "deactivate", 10)) {
2014 /* Dectivate */
2015 int i;
2016 uint8_t instance = 1;
2017 for (i = 1; i < argc; i++) {
2018 if (!strncmp(argv[i], "instance=", 9)) {
2019 if (str2uchar(argv[i] + 9, &instance) != 0) {
2020 lprintf(LOG_ERR,
2021 "Given instance '%s' is invalid.",
2022 argv[i] + 9);
2023 print_sol_usage();
2024 return -1;
2025 }
2026 } else {
2027 print_sol_usage();
2028 return -1;
2029 }
2030 }
2031 retval = ipmi_sol_deactivate(intf, instance);
2032 } else if (!strncmp(argv[0], "looptest", 8)) {
2033 /* SOL loop test: Activate and then Dectivate */
2034 int cnt = 200;
2035 int interval = 100; /* Unit is: ms */
2036 uint8_t instance = 1;
2037 if (argc > 4) {
2038 print_sol_usage();
2039 return -1;
2040 }
2041 if (argc != 1) {
2042 /* at least 2 */
2043 if (str2int(argv[1], &cnt) != 0) {
2044 lprintf(LOG_ERR, "Given cnt '%s' is invalid.",
2045 argv[1]);
2046 return (-1);
2047 }
2048 if (cnt <= 0) {
2049 cnt = 200;
2050 }
2051 }
2052 if (argc >= 3) {
2053 if (str2int(argv[2], &interval) != 0) {
2054 lprintf(LOG_ERR, "Given interval '%s' is invalid.",
2055 argv[2]);
2056 return (-1);
2057 }
2058 if (interval < 0) {
2059 interval = 0;
2060 }
2061 }
2062 if (argc >= 4) {
2063 if (str2uchar(argv[3], &instance) != 0) {
2064 lprintf(LOG_ERR, "Given instance '%s' is invalid.",
2065 argv[3]);
2066 print_sol_usage();
2067 return -1;
2068 }
2069 }
2070
2071 while (cnt > 0) {
2072 printf("remain loop test counter: %d\n", cnt);
2073 retval = ipmi_sol_activate(intf, 1, interval, instance);
2074 if (retval) {
2075 printf("SOL looptest failed: %d\n",
2076 retval);
2077 break;
2078 }
2079 cnt -= 1;
2080 }
2081 } else {
2082 print_sol_usage();
2083 retval = -1;
2084 }
2085 return retval;
2086 }
2087