1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086 |
- /*
- * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * Redistribution of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * Redistribution in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * Neither the name of Sun Microsystems, Inc. or the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * This software is provided "AS IS," without a warranty of any kind.
- * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
- * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
- * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
- * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
- * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
- * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
- * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
- * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
- * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
- * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
- * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- */
- #define _XOPEN_SOURCE
- #define _BSD_SOURCE || \
- (_XOPEN_SOURCE >= 500 || \
- _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED) && \
- !(_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700)
- #include <stdlib.h>
- #include <string.h>
- #include <strings.h>
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/select.h>
- #include <sys/time.h>
- #include <time.h>
- #include <signal.h>
- #include <unistd.h>
- #if defined(HAVE_CONFIG_H)
- # include <config.h>
- #endif
- #if defined(HAVE_TERMIOS_H)
- # include <termios.h>
- #elif defined (HAVE_SYS_TERMIOS_H)
- # include <sys/termios.h>
- #endif
- #include <ipmitool/helper.h>
- #include <ipmitool/log.h>
- #include <ipmitool/ipmi.h>
- #include <ipmitool/ipmi_intf.h>
- #include <ipmitool/ipmi_sol.h>
- #include <ipmitool/ipmi_strings.h>
- #include <ipmitool/bswap.h>
- #define SOL_PARAMETER_SET_IN_PROGRESS 0x00
- #define SOL_PARAMETER_SOL_ENABLE 0x01
- #define SOL_PARAMETER_SOL_AUTHENTICATION 0x02
- #define SOL_PARAMETER_CHARACTER_INTERVAL 0x03
- #define SOL_PARAMETER_SOL_RETRY 0x04
- #define SOL_PARAMETER_SOL_NON_VOLATILE_BIT_RATE 0x05
- #define SOL_PARAMETER_SOL_VOLATILE_BIT_RATE 0x06
- #define SOL_PARAMETER_SOL_PAYLOAD_CHANNEL 0x07
- #define SOL_PARAMETER_SOL_PAYLOAD_PORT 0x08
- #define MAX_SOL_RETRY 6
- const struct valstr sol_parameter_vals[] = {
- { SOL_PARAMETER_SET_IN_PROGRESS, "Set In Progress (0)" },
- { SOL_PARAMETER_SOL_ENABLE, "Enable (1)" },
- { SOL_PARAMETER_SOL_AUTHENTICATION, "Authentication (2)" },
- { SOL_PARAMETER_CHARACTER_INTERVAL, "Character Interval (3)" },
- { SOL_PARAMETER_SOL_RETRY, "Retry (4)" },
- { SOL_PARAMETER_SOL_NON_VOLATILE_BIT_RATE, "Nonvolatile Bitrate (5)" },
- { SOL_PARAMETER_SOL_VOLATILE_BIT_RATE, "Volatile Bitrate (6)" },
- { SOL_PARAMETER_SOL_PAYLOAD_CHANNEL, "Payload Channel (7)" },
- { SOL_PARAMETER_SOL_PAYLOAD_PORT, "Payload Port (8)" },
- { 0x00, NULL },
- };
- static struct timeval _start_keepalive;
- static struct termios _saved_tio;
- static int _in_raw_mode = 0;
- static int _disable_keepalive = 0;
- static int _use_sol_for_keepalive = 0;
- extern int verbose;
- /*
- * ipmi_sol_payload_access
- */
- int
- ipmi_sol_payload_access(struct ipmi_intf * intf, uint8_t channel,
- uint8_t userid, int enable)
- {
- struct ipmi_rq req;
- struct ipmi_rs *rsp;
- int rc = (-1);
- uint8_t data[6];
- memset(&req, 0, sizeof(req));
- req.msg.netfn = IPMI_NETFN_APP;
- req.msg.cmd = IPMI_SET_USER_PAYLOAD_ACCESS;
- req.msg.data = data;
- req.msg.data_len = 6;
- memset(data, 0, 6);
- /* channel */
- data[0] = channel & 0xf;
- /* user id */
- data[1] = userid & 0x3f;
- if (!enable) {
- /* disable */
- data[1] |= 0x40;
- }
- /* payload 1 is SOL */
- data[2] = 0x02;
- rsp = intf->sendrecv(intf, &req);
- if (rsp == NULL) {
- lprintf(LOG_ERR, "Error %sabling SOL payload for user %d on channel %d",
- enable ? "en" : "dis", userid, channel);
- rc = (-1);
- } else if (rsp->ccode != 0) {
- lprintf(LOG_ERR, "Error %sabling SOL payload for user %d on channel %d: %s",
- enable ? "en" : "dis", userid, channel,
- val2str(rsp->ccode, completion_code_vals));
- rc = (-1);
- } else {
- rc = 0;
- }
- return rc;
- }
- int
- ipmi_sol_payload_access_status(struct ipmi_intf * intf,
- uint8_t channel,
- uint8_t userid)
- {
- struct ipmi_rq req;
- struct ipmi_rs *rsp;
- uint8_t data[2];
- memset(&req, 0, sizeof(req));
- req.msg.netfn = IPMI_NETFN_APP;
- req.msg.cmd = IPMI_GET_USER_PAYLOAD_ACCESS;
- req.msg.data = data;
- req.msg.data_len = sizeof(data);
- data[0] = channel & 0xf; /* channel */
- data[1] = userid & 0x3f; /* user id */
- rsp = intf->sendrecv(intf, &req);
- if (rsp == NULL) {
- lprintf(LOG_ERR, "Error. No valid response received.");
- return -1;
- }
- switch(rsp->ccode) {
- case 0x00:
- if (rsp->data_len != 4) {
- lprintf(LOG_ERR, "Error parsing SOL payload status for user %d on channel %d",
- userid, channel);
- return -1;
- }
- printf("User %d on channel %d is %sabled\n",
- userid, channel, (rsp->data[0] & 0x02) ? "en":"dis");
- return 0;
- default:
- lprintf(LOG_ERR, "Error getting SOL payload status for user %d on channel %d: %s",
- userid, channel,
- val2str(rsp->ccode, completion_code_vals));
- return -1;
- }
- }
- /*
- * ipmi_get_sol_info
- */
- int
- ipmi_get_sol_info(
- struct ipmi_intf * intf,
- uint8_t channel,
- struct sol_config_parameters * params)
- {
- struct ipmi_rs * rsp;
- struct ipmi_rq req;
- uint8_t data[4];
- memset(&req, 0, sizeof(req));
- req.msg.netfn = IPMI_NETFN_TRANSPORT;
- req.msg.cmd = IPMI_GET_SOL_CONFIG_PARAMETERS;
- req.msg.data_len = 4;
- req.msg.data = data;
- /*
- * set in progress
- */
- memset(data, 0, sizeof(data));
- data[0] = channel; /* channel number */
- data[1] = SOL_PARAMETER_SET_IN_PROGRESS; /* parameter selector */
- data[2] = 0x00; /* set selector */
- data[3] = 0x00; /* block selector */
- rsp = intf->sendrecv(intf, &req);
- if (rsp == NULL) {
- lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'",
- val2str(data[1], sol_parameter_vals));
- return (-1);
- }
- switch (rsp->ccode) {
- case 0x00:
- if (rsp->data_len == 2) {
- params->set_in_progress = rsp->data[1];
- } else {
- lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
- "for SOL parameter '%s'",
- rsp->data_len,
- val2str(data[1], sol_parameter_vals));
- }
- break;
- case 0x80:
- lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported",
- val2str(data[1], sol_parameter_vals));
- break;
- default:
- lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s",
- val2str(data[1], sol_parameter_vals),
- val2str(rsp->ccode, completion_code_vals));
- return (-1);
- }
- /*
- * SOL enable
- */
- memset(data, 0, sizeof(data));
- data[0] = channel; /* channel number */
- data[1] = SOL_PARAMETER_SOL_ENABLE; /* parameter selector */
- data[2] = 0x00; /* set selector */
- data[3] = 0x00; /* block selector */
- rsp = intf->sendrecv(intf, &req);
- if (rsp == NULL) {
- lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'",
- val2str(data[1], sol_parameter_vals));
- return (-1);
- }
- switch (rsp->ccode) {
- case 0x00:
- if (rsp->data_len == 2) {
- params->enabled = rsp->data[1];
- } else {
- lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
- "for SOL parameter '%s'",
- rsp->data_len,
- val2str(data[1], sol_parameter_vals));
- }
- break;
- case 0x80:
- lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported",
- val2str(data[1], sol_parameter_vals));
- break;
- default:
- lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s",
- val2str(data[1], sol_parameter_vals),
- val2str(rsp->ccode, completion_code_vals));
- return (-1);
- }
- /*
- * SOL authentication
- */
- memset(data, 0, sizeof(data));
- data[0] = channel; /* channel number */
- data[1] = SOL_PARAMETER_SOL_AUTHENTICATION; /* parameter selector */
- data[2] = 0x00; /* set selector */
- data[3] = 0x00; /* block selector */
- rsp = intf->sendrecv(intf, &req);
- if (rsp == NULL) {
- lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'",
- val2str(data[1], sol_parameter_vals));
- return (-1);
- }
- switch (rsp->ccode) {
- case 0x00:
- if (rsp->data_len == 2) {
- params->force_encryption = ((rsp->data[1] & 0x80)? 1 : 0);
- params->force_authentication = ((rsp->data[1] & 0x40)? 1 : 0);
- params->privilege_level = rsp->data[1] & 0x0F;
- } else {
- lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
- "for SOL parameter '%s'",
- rsp->data_len,
- val2str(data[1], sol_parameter_vals));
- }
- break;
- case 0x80:
- lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported",
- val2str(data[1], sol_parameter_vals));
- break;
- default:
- lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s",
- val2str(data[1], sol_parameter_vals),
- val2str(rsp->ccode, completion_code_vals));
- return (-1);
- }
- /*
- * Character accumulate interval and character send interval
- */
- memset(data, 0, sizeof(data));
- data[0] = channel; /* channel number */
- data[1] = SOL_PARAMETER_CHARACTER_INTERVAL; /* parameter selector */
- data[2] = 0x00; /* set selector */
- data[3] = 0x00; /* block selector */
- rsp = intf->sendrecv(intf, &req);
- if (rsp == NULL) {
- lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'",
- val2str(data[1], sol_parameter_vals));
- return (-1);
- }
- switch (rsp->ccode) {
- case 0x00:
- if (rsp->data_len == 3) {
- params->character_accumulate_level = rsp->data[1];
- params->character_send_threshold = rsp->data[2];
- } else {
- lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
- "for SOL parameter '%s'",
- rsp->data_len,
- val2str(data[1], sol_parameter_vals));
- }
- break;
- case 0x80:
- lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported",
- val2str(data[1], sol_parameter_vals));
- break;
- default:
- lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s",
- val2str(data[1], sol_parameter_vals),
- val2str(rsp->ccode, completion_code_vals));
- return (-1);
- }
- /*
- * SOL retry
- */
- memset(data, 0, sizeof(data));
- data[0] = channel; /* channel number */
- data[1] = SOL_PARAMETER_SOL_RETRY; /* parameter selector */
- data[2] = 0x00; /* set selector */
- data[3] = 0x00; /* block selector */
- rsp = intf->sendrecv(intf, &req);
- if (rsp == NULL) {
- lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'",
- val2str(data[1], sol_parameter_vals));
- return (-1);
- }
- switch (rsp->ccode) {
- case 0x00:
- if (rsp->data_len == 3) {
- params->retry_count = rsp->data[1];
- params->retry_interval = rsp->data[2];
- } else {
- lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
- "for SOL parameter '%s'",
- rsp->data_len,
- val2str(data[1], sol_parameter_vals));
- }
- break;
- case 0x80:
- lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported",
- val2str(data[1], sol_parameter_vals));
- break;
- default:
- lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s",
- val2str(data[1], sol_parameter_vals),
- val2str(rsp->ccode, completion_code_vals));
- return (-1);
- }
- /*
- * SOL non-volatile bit rate
- */
- memset(data, 0, sizeof(data));
- data[0] = channel; /* channel number */
- data[1] = SOL_PARAMETER_SOL_NON_VOLATILE_BIT_RATE; /* parameter selector */
- data[2] = 0x00; /* set selector */
- data[3] = 0x00; /* block selector */
- rsp = intf->sendrecv(intf, &req);
- if (rsp == NULL) {
- lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'",
- val2str(data[1], sol_parameter_vals));
- return (-1);
- }
- switch (rsp->ccode) {
- case 0x00:
- if (rsp->data_len == 2) {
- params->non_volatile_bit_rate = rsp->data[1] & 0x0F;
- } else {
- lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
- "for SOL parameter '%s'",
- rsp->data_len,
- val2str(data[1], sol_parameter_vals));
- }
- break;
- case 0x80:
- lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported",
- val2str(data[1], sol_parameter_vals));
- break;
- default:
- lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s",
- val2str(data[1], sol_parameter_vals),
- val2str(rsp->ccode, completion_code_vals));
- return (-1);
- }
- /*
- * SOL volatile bit rate
- */
- memset(data, 0, sizeof(data));
- data[0] = channel; /* channel number */
- data[1] = SOL_PARAMETER_SOL_VOLATILE_BIT_RATE; /* parameter selector */
- data[2] = 0x00; /* set selector */
- data[3] = 0x00; /* block selector */
- rsp = intf->sendrecv(intf, &req);
- if (rsp == NULL) {
- lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'",
- val2str(data[1], sol_parameter_vals));
- return (-1);
- }
- switch (rsp->ccode) {
- case 0x00:
- if (rsp->data_len == 2) {
- params->volatile_bit_rate = rsp->data[1] & 0x0F;
- } else {
- lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
- "for SOL parameter '%s'",
- rsp->data_len,
- val2str(data[1], sol_parameter_vals));
- }
- break;
- case 0x80:
- lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported",
- val2str(data[1], sol_parameter_vals));
- break;
- default:
- lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s",
- val2str(data[1], sol_parameter_vals),
- val2str(rsp->ccode, completion_code_vals));
- return (-1);
- }
- /*
- * SOL payload channel
- */
- memset(data, 0, sizeof(data));
- data[0] = channel; /* channel number */
- data[1] = SOL_PARAMETER_SOL_PAYLOAD_CHANNEL; /* parameter selector */
- data[2] = 0x00; /* set selector */
- data[3] = 0x00; /* block selector */
- rsp = intf->sendrecv(intf, &req);
- if (rsp == NULL) {
- lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'",
- val2str(data[1], sol_parameter_vals));
- return (-1);
- }
- switch (rsp->ccode) {
- case 0x00:
- if (rsp->data_len == 2) {
- params->payload_channel = rsp->data[1];
- } else {
- lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
- "for SOL parameter '%s'",
- rsp->data_len,
- val2str(data[1], sol_parameter_vals));
- }
- break;
- case 0x80:
- lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported - defaulting to 0x%02x",
- val2str(data[1], sol_parameter_vals), channel);
- params->payload_channel = channel;
- break;
- default:
- lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s",
- val2str(data[1], sol_parameter_vals),
- val2str(rsp->ccode, completion_code_vals));
- return (-1);
- }
- /*
- * SOL payload port
- */
- memset(data, 0, sizeof(data));
- data[0] = channel; /* channel number */
- data[1] = SOL_PARAMETER_SOL_PAYLOAD_PORT; /* parameter selector */
- data[2] = 0x00; /* set selector */
- data[3] = 0x00; /* block selector */
- rsp = intf->sendrecv(intf, &req);
- if (rsp == NULL) {
- lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'",
- val2str(data[1], sol_parameter_vals));
- return (-1);
- }
- switch (rsp->ccode) {
- case 0x00:
- if (rsp->data_len == 3) {
- params->payload_port = (rsp->data[1]) | (rsp->data[2] << 8);
- } else {
- lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
- "for SOL parameter '%s'",
- rsp->data_len,
- val2str(data[1], sol_parameter_vals));
- }
- break;
- case 0x80:
- if( intf->session != NULL ) {
- lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported - defaulting to %d",
- val2str(data[1], sol_parameter_vals), intf->ssn_params.port);
- params->payload_port = intf->ssn_params.port;
- } else {
- lprintf(LOG_ERR,
- "Info: SOL parameter '%s' not supported - can't determine which "
- "payload port to use on NULL session",
- val2str(data[1], sol_parameter_vals));
- return (-1);
- }
- break;
- default:
- lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s",
- val2str(data[1], sol_parameter_vals),
- val2str(rsp->ccode, completion_code_vals));
- return (-1);
- }
- return 0;
- }
- /*
- * ipmi_print_sol_info
- */
- static int
- ipmi_print_sol_info(struct ipmi_intf * intf, uint8_t channel)
- {
- struct sol_config_parameters params = {0};
- if (ipmi_get_sol_info(intf, channel, ¶ms))
- return -1;
- if (csv_output)
- {
- printf("%s,",
- val2str(params.set_in_progress & 0x03,
- ipmi_set_in_progress_vals));
- printf("%s,", params.enabled?"true": "false");
- printf("%s,", params.force_encryption?"true":"false");
- printf("%s,", params.force_encryption?"true":"false");
- printf("%s,",
- val2str(params.privilege_level, ipmi_privlvl_vals));
- printf("%d,", params.character_accumulate_level * 5);
- printf("%d,", params.character_send_threshold);
- printf("%d,", params.retry_count);
- printf("%d,", params.retry_interval * 10);
- printf("%s,",
- val2str(params.volatile_bit_rate, ipmi_bit_rate_vals));
- printf("%s,",
- val2str(params.non_volatile_bit_rate, ipmi_bit_rate_vals));
- printf("%d,", params.payload_channel);
- printf("%d\n", params.payload_port);
- }
- else
- {
- printf("Set in progress : %s\n",
- val2str(params.set_in_progress & 0x03,
- ipmi_set_in_progress_vals));
- printf("Enabled : %s\n",
- params.enabled?"true": "false");
- printf("Force Encryption : %s\n",
- params.force_encryption?"true":"false");
- printf("Force Authentication : %s\n",
- params.force_authentication?"true":"false");
- printf("Privilege Level : %s\n",
- val2str(params.privilege_level, ipmi_privlvl_vals));
- printf("Character Accumulate Level (ms) : %d\n",
- params.character_accumulate_level * 5);
- printf("Character Send Threshold : %d\n",
- params.character_send_threshold);
- printf("Retry Count : %d\n",
- params.retry_count);
- printf("Retry Interval (ms) : %d\n",
- params.retry_interval * 10);
- printf("Volatile Bit Rate (kbps) : %s\n",
- val2str(params.volatile_bit_rate, ipmi_bit_rate_vals));
- printf("Non-Volatile Bit Rate (kbps) : %s\n",
- val2str(params.non_volatile_bit_rate, ipmi_bit_rate_vals));
- printf("Payload Channel : %d (0x%02x)\n",
- params.payload_channel, params.payload_channel);
- printf("Payload Port : %d\n",
- params.payload_port);
- }
- return 0;
- }
- /*
- * Small function to validate that user-supplied SOL
- * configuration parameter values we store in uint8_t
- * data type falls within valid range. With minval
- * and maxval parameters we can use the same function
- * to validate parameters that have different ranges
- * of values.
- *
- * function will return -1 if value is not valid, or
- * will return 0 if valid.
- */
- int 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)
- {
- if (str2uchar(strval, out_value) != 0 || (*out_value < minval)
- || (*out_value > maxval)) {
- lprintf(LOG_ERR, "Invalid value %s for parameter %s",
- strval, name);
- lprintf(LOG_ERR, "Valid values are %d-%d", minval, maxval);
- return -1;
- }
- return 0;
- }
- /*
- * ipmi_sol_set_param
- *
- * Set the specified Serial Over LAN value to the specified
- * value
- *
- * return 0 on success,
- * -1 on failure
- */
- static int
- ipmi_sol_set_param(struct ipmi_intf * intf,
- uint8_t channel,
- const char * param,
- const char * value,
- uint8_t guarded)
- {
- struct ipmi_rs * rsp;
- struct ipmi_rq req;
- uint8_t data[4];
- int bGuarded = guarded; /* Use set-in-progress indicator? */
- memset(&req, 0, sizeof(req));
- req.msg.netfn = IPMI_NETFN_TRANSPORT; /* 0x0c */
- req.msg.cmd = IPMI_SET_SOL_CONFIG_PARAMETERS; /* 0x21 */
- req.msg.data = data;
- data[0] = channel;
- /*
- * set-in-progress
- */
- if (! strcmp(param, "set-in-progress"))
- {
- bGuarded = 0; /* We _ARE_ the set-in-progress indicator */
- req.msg.data_len = 3;
- data[1] = SOL_PARAMETER_SET_IN_PROGRESS;
- if (! strcmp(value, "set-complete"))
- data[2] = 0x00;
- else if (! strcmp(value, "set-in-progress"))
- data[2] = 0x01;
- else if (! strcmp(value, "commit-write"))
- data[2] = 0x02;
- else
- {
- lprintf(LOG_ERR, "Invalid value %s for parameter %s",
- value, param);
- lprintf(LOG_ERR, "Valid values are set-complete, set-in-progress "
- "and commit-write");
- return -1;
- }
- }
- /*
- * enabled
- */
- else if (! strcmp(param, "enabled"))
- {
- req.msg.data_len = 3;
- data[1] = SOL_PARAMETER_SOL_ENABLE;
- if (! strcmp(value, "true"))
- data[2] = 0x01;
- else if (! strcmp(value, "false"))
- data[2] = 0x00;
- else
- {
- lprintf(LOG_ERR, "Invalid value %s for parameter %s",
- value, param);
- lprintf(LOG_ERR, "Valid values are true and false");
- return -1;
- }
- }
- /*
- * force-payload-encryption
- */
- else if (! strcmp(param, "force-encryption"))
- {
- struct sol_config_parameters params;
- req.msg.data_len = 3;
- data[1] = SOL_PARAMETER_SOL_AUTHENTICATION;
- if (! strcmp(value, "true"))
- data[2] = 0x80;
- else if (! strcmp(value, "false"))
- data[2] = 0x00;
- else
- {
- lprintf(LOG_ERR, "Invalid value %s for parameter %s",
- value, param);
- lprintf(LOG_ERR, "Valid values are true and false");
- return -1;
- }
- /* We need other values to complete the request */
- if (ipmi_get_sol_info(intf, channel, ¶ms))
- {
- lprintf(LOG_ERR, "Error fetching SOL parameters for %s update",
- param);
- return -1;
- }
- data[2] |= params.force_authentication? 0x40 : 0x00;
- data[2] |= params.privilege_level;
- }
- /*
- * force-payload-authentication
- */
- else if (! strcmp(param, "force-authentication"))
- {
- struct sol_config_parameters params;
- req.msg.data_len = 3;
- data[1] = SOL_PARAMETER_SOL_AUTHENTICATION;
- if (! strcmp(value, "true"))
- data[2] = 0x40;
- else if (! strcmp(value, "false"))
- data[2] = 0x00;
- else
- {
- lprintf(LOG_ERR, "Invalid value %s for parameter %s",
- value, param);
- lprintf(LOG_ERR, "Valid values are true and false");
- return -1;
- }
- /* We need other values to complete the request */
- if (ipmi_get_sol_info(intf, channel, ¶ms))
- {
- lprintf(LOG_ERR, "Error fetching SOL parameters for %s update",
- param);
- return -1;
- }
- data[2] |= params.force_encryption? 0x80 : 0x00;
- data[2] |= params.privilege_level;
- }
- /*
- * privilege-level
- */
- else if (! strcmp(param, "privilege-level"))
- {
- struct sol_config_parameters params;
- req.msg.data_len = 3;
- data[1] = SOL_PARAMETER_SOL_AUTHENTICATION;
- if (! strcmp(value, "user"))
- data[2] = 0x02;
- else if (! strcmp(value, "operator"))
- data[2] = 0x03;
- else if (! strcmp(value, "admin"))
- data[2] = 0x04;
- else if (! strcmp(value, "oem"))
- data[2] = 0x05;
- else
- {
- lprintf(LOG_ERR, "Invalid value %s for parameter %s",
- value, param);
- lprintf(LOG_ERR, "Valid values are user, operator, admin, and oem");
- return -1;
- }
- /* We need other values to complete the request */
- if (ipmi_get_sol_info(intf, channel, ¶ms))
- {
- lprintf(LOG_ERR, "Error fetching SOL parameters for %s update",
- param);
- return -1;
- }
- data[2] |= params.force_encryption? 0x80 : 0x00;
- data[2] |= params.force_authentication? 0x40 : 0x00;
- }
- /*
- * character-accumulate-level
- */
- else if (! strcmp(param, "character-accumulate-level"))
- {
- struct sol_config_parameters params;
- req.msg.data_len = 4;
- data[1] = SOL_PARAMETER_CHARACTER_INTERVAL;
- /* validate user-supplied input */
- if (ipmi_sol_set_param_isvalid_uint8_t(value, param, 0, 1, 255, &data[2]))
- return -1;
- /* We need other values to complete the request */
- if (ipmi_get_sol_info(intf, channel, ¶ms))
- {
- lprintf(LOG_ERR, "Error fetching SOL parameters for %s update",
- param);
- return -1;
- }
- data[3] = params.character_send_threshold;
- }
- /*
- * character-send-threshold
- */
- else if (! strcmp(param, "character-send-threshold"))
- {
- struct sol_config_parameters params;
- req.msg.data_len = 4;
- data[1] = SOL_PARAMETER_CHARACTER_INTERVAL;
- /* validate user-supplied input */
- if (ipmi_sol_set_param_isvalid_uint8_t(value, param, 0, 0, 255, &data[3]))
- return -1;
- /* We need other values to complete the request */
- if (ipmi_get_sol_info(intf, channel, ¶ms))
- {
- lprintf(LOG_ERR, "Error fetching SOL parameters for %s update",
- param);
- return -1;
- }
- data[2] = params.character_accumulate_level;
- }
- /*
- * retry-count
- */
- else if (! strcmp(param, "retry-count"))
- {
- struct sol_config_parameters params;
- req.msg.data_len = 4;
- data[1] = SOL_PARAMETER_SOL_RETRY;
- /* validate user input, 7 is max value */
- if (ipmi_sol_set_param_isvalid_uint8_t(value, param, 0, 0, 7, &data[2]))
- return -1;
- /* We need other values to complete the request */
- if (ipmi_get_sol_info(intf, channel, ¶ms))
- {
- lprintf(LOG_ERR, "Error fetching SOL parameters for %s update",
- param);
- return -1;
- }
- data[3] = params.retry_interval;
- }
- /*
- * retry-interval
- */
- else if (! strcmp(param, "retry-interval"))
- {
- struct sol_config_parameters params;
- req.msg.data_len = 4;
- data[1] = SOL_PARAMETER_SOL_RETRY;
- /* validate user-supplied input */
- if (ipmi_sol_set_param_isvalid_uint8_t(value, param, 0, 0, 255, &data[3]))
- return -1;
- /* We need other values to complete the request */
- if (ipmi_get_sol_info(intf, channel, ¶ms))
- {
- lprintf(LOG_ERR, "Error fetching SOL parameters for %s update",
- param);
- return -1;
- }
- data[2] = params.retry_count;
- }
- /*
- * non-volatile-bit-rate
- */
- else if (! strcmp(param, "non-volatile-bit-rate"))
- {
- req.msg.data_len = 3;
- data[1] = SOL_PARAMETER_SOL_NON_VOLATILE_BIT_RATE;
- if (!strcmp(value, "serial"))
- {
- data[2] = 0x00;
- }
- else if (!strcmp(value, "9.6"))
- {
- data[2] = 0x06;
- }
- else if (!strcmp(value, "19.2"))
- {
- data[2] = 0x07;
- }
- else if (!strcmp(value, "38.4"))
- {
- data[2] = 0x08;
- }
- else if (!strcmp(value, "57.6"))
- {
- data[2] = 0x09;
- }
- else if (!strcmp(value, "115.2"))
- {
- data[2] = 0x0A;
- }
- else
- {
- lprintf(LOG_ERR, "Invalid value \"%s\" for parameter \"%s\"",
- value,
- param);
- lprintf(LOG_ERR, "Valid values are serial, 9.6 19.2, 38.4, 57.6 and 115.2");
- return -1;
- }
- }
- /*
- * volatile-bit-rate
- */
- else if (! strcmp(param, "volatile-bit-rate"))
- {
- req.msg.data_len = 3;
- data[1] = SOL_PARAMETER_SOL_VOLATILE_BIT_RATE;
- if (!strcmp(value, "serial"))
- {
- data[2] = 0x00;
- }
- else if (!strcmp(value, "9.6"))
- {
- data[2] = 0x06;
- }
- else if (!strcmp(value, "19.2"))
- {
- data[2] = 0x07;
- }
- else if (!strcmp(value, "38.4"))
- {
- data[2] = 0x08;
- }
- else if (!strcmp(value, "57.6"))
- {
- data[2] = 0x09;
- }
- else if (!strcmp(value, "115.2"))
- {
- data[2] = 0x0A;
- }
- else
- {
- lprintf(LOG_ERR, "Invalid value \"%s\" for parameter \"%s\"",
- value,
- param);
- lprintf(LOG_ERR, "Valid values are serial, 9.6 19.2, 38.4, 57.6 and 115.2");
- return -1;
- }
- }
- else
- {
- lprintf(LOG_ERR, "Error: invalid SOL parameter %s", param);
- return -1;
- }
- /*
- * Execute the request
- */
- if (bGuarded &&
- (ipmi_sol_set_param(intf,
- channel,
- "set-in-progress",
- "set-in-progress",
- bGuarded)))
- {
- lprintf(LOG_ERR, "Error: set of parameter \"%s\" failed", param);
- return -1;
- }
- /* The command proper */
- rsp = intf->sendrecv(intf, &req);
- if (rsp == NULL) {
- lprintf(LOG_ERR, "Error setting SOL parameter '%s'", param);
- return -1;
- }
- if (!(!strncmp(param, "set-in-progress", 15) && !strncmp(value, "commit-write", 12)) &&
- rsp->ccode > 0) {
- switch (rsp->ccode) {
- case 0x80:
- lprintf(LOG_ERR, "Error setting SOL parameter '%s': "
- "Parameter not supported", param);
- break;
- case 0x81:
- lprintf(LOG_ERR, "Error setting SOL parameter '%s': "
- "Attempt to set set-in-progress when not in set-complete state",
- param);
- break;
- case 0x82:
- lprintf(LOG_ERR, "Error setting SOL parameter '%s': "
- "Attempt to write read-only parameter", param);
- break;
- case 0x83:
- lprintf(LOG_ERR, "Error setting SOL parameter '%s': "
- "Attempt to read write-only parameter", param);
- break;
- default:
- lprintf(LOG_ERR, "Error setting SOL parameter '%s' to '%s': %s",
- param, value, val2str(rsp->ccode, completion_code_vals));
- break;
- }
- if (bGuarded &&
- (ipmi_sol_set_param(intf,
- channel,
- "set-in-progress",
- "set-complete",
- bGuarded)))
- {
- lprintf(LOG_ERR, "Error could not set \"set-in-progress\" "
- "to \"set-complete\"");
- }
- return -1;
- }
- /*
- * The commit write could very well fail, but that's ok.
- * It may not be implemented.
- */
- if (bGuarded)
- ipmi_sol_set_param(intf,
- channel,
- "set-in-progress",
- "commit-write",
- bGuarded);
- if (bGuarded &&
- ipmi_sol_set_param(intf,
- channel,
- "set-in-progress",
- "set-complete",
- bGuarded))
- {
- lprintf(LOG_ERR, "Error could not set \"set-in-progress\" "
- "to \"set-complete\"");
- return -1;
- }
- return 0;
- }
- void
- leave_raw_mode(void)
- {
- if (!_in_raw_mode)
- return;
- if (tcsetattr(fileno(stdin), TCSADRAIN, &_saved_tio) == -1)
- perror("tcsetattr");
- else
- _in_raw_mode = 0;
- }
- void
- enter_raw_mode(void)
- {
- struct termios tio;
- if (tcgetattr(fileno(stdin), &tio) == -1) {
- perror("tcgetattr");
- return;
- }
- _saved_tio = tio;
- tio.c_iflag |= IGNPAR;
- tio.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF);
- tio.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
- // #ifdef IEXTEN
- tio.c_lflag &= ~IEXTEN;
- // #endif
- tio.c_oflag &= ~OPOST;
- tio.c_cc[VMIN] = 1;
- tio.c_cc[VTIME] = 0;
- if (tcsetattr(fileno(stdin), TCSADRAIN, &tio) == -1)
- perror("tcsetattr");
- else
- _in_raw_mode = 1;
- }
- static void
- sendBreak(struct ipmi_intf * intf)
- {
- struct ipmi_v2_payload v2_payload;
- memset(&v2_payload, 0, sizeof(v2_payload));
- v2_payload.payload.sol_packet.character_count = 0;
- v2_payload.payload.sol_packet.generate_break = 1;
- intf->send_sol(intf, &v2_payload);
- }
- /*
- * suspendSelf
- *
- * Put ourself in the background
- *
- * param bRestoreTty specifies whether we will put our self back
- * in raw mode when we resume
- */
- static void
- suspendSelf(int bRestoreTty)
- {
- leave_raw_mode();
- kill(getpid(), SIGTSTP);
- if (bRestoreTty)
- enter_raw_mode();
- }
- /*
- * printSolEscapeSequences
- *
- * Send some useful documentation to the user
- */
- static void
- printSolEscapeSequences(struct ipmi_intf * intf)
- {
- printf(
- "%c?\n\
- Supported escape sequences:\n\
- %c. - terminate connection\n\
- %c^Z - suspend ipmitool\n\
- %c^X - suspend ipmitool, but don't restore tty on restart\n\
- %cB - send break\n\
- %c? - this message\n\
- %c%c - send the escape character by typing it twice\n\
- (Note that escapes are only recognized immediately after newline.)\n",
- intf->ssn_params.sol_escape_char,
- intf->ssn_params.sol_escape_char,
- intf->ssn_params.sol_escape_char,
- intf->ssn_params.sol_escape_char,
- intf->ssn_params.sol_escape_char,
- intf->ssn_params.sol_escape_char,
- intf->ssn_params.sol_escape_char,
- intf->ssn_params.sol_escape_char);
- }
- /*
- * output
- *
- * Send the specified data to stdout
- */
- static void
- output(struct ipmi_rs * rsp)
- {
- /* Add checks to make sure it is actually SOL data, in general I see
- * outside code mostly trying to guard against this happening, but
- * some places fail to do so, so I do so here to make sure nothing gets
- * through. If non-sol data comes through here, there is probably
- * a packet that won't get processed somewhere else, but the alternative
- * of outputting corrupt data is worse. Generally I see the get device
- * id response make it here somehow. I assume it is a heartbeat and the
- * other code will retry if it cares about the response and misses it.
- */
- if (rsp &&
- (rsp->session.authtype == IPMI_SESSION_AUTHTYPE_RMCP_PLUS) &&
- (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL))
- {
- int i;
- for (i = 0; i < rsp->data_len; ++i)
- putc(rsp->data[i], stdout);
- fflush(stdout);
- }
- }
- /*
- * ipmi_sol_deactivate
- */
- static int
- ipmi_sol_deactivate(struct ipmi_intf * intf, int instance)
- {
- struct ipmi_rs * rsp;
- struct ipmi_rq req;
- uint8_t data[6];
- if ((instance <= 0) || (instance > 15)) {
- lprintf(LOG_ERR, "Error: Instance must range from 1 to 15");
- return -1;
- }
- memset(&req, 0, sizeof(req));
- req.msg.netfn = IPMI_NETFN_APP;
- req.msg.cmd = IPMI_DEACTIVATE_PAYLOAD;
- req.msg.data_len = 6;
- req.msg.data = data;
- memset(data, 0, sizeof(data));
- data[0] = IPMI_PAYLOAD_TYPE_SOL; /* payload type */
- data[1] = instance; /* payload instance. */
- /* Lots of important data */
- data[2] = 0;
- data[3] = 0;
- data[4] = 0;
- data[5] = 0;
- rsp = intf->sendrecv(intf, &req);
- if (NULL != rsp) {
- switch (rsp->ccode) {
- case 0x00:
- return 0;
- case 0x80:
- lprintf(LOG_ERR, "Info: SOL payload already de-activated");
- break;
- case 0x81:
- lprintf(LOG_ERR, "Info: SOL payload type disabled");
- break;
- default:
- lprintf(LOG_ERR, "Error de-activating SOL payload: %s",
- val2str(rsp->ccode, completion_code_vals));
- break;
- }
- } else {
- lprintf(LOG_ERR, "Error: No response de-activating SOL payload");
- }
- return -1;
- }
- /*
- * processSolUserInput
- *
- * Act on user input into the SOL session. The only reason this
- * is complicated is that we have to process escape sequences.
- *
- * return 0 on success
- * 1 if we should exit
- * < 0 on error (BMC probably closed the session)
- */
- static int
- processSolUserInput(
- struct ipmi_intf * intf,
- uint8_t * input,
- uint16_t buffer_length)
- {
- static int escape_pending = 0;
- static int last_was_cr = 1;
- struct ipmi_v2_payload v2_payload;
- int length = 0;
- int retval = 0;
- char ch;
- int i;
- memset(&v2_payload, 0, sizeof(v2_payload));
- /*
- * Our first order of business is to check the input for escape
- * sequences to act on.
- */
- for (i = 0; i < buffer_length; ++i)
- {
- ch = input[i];
- if (escape_pending){
- escape_pending = 0;
- /*
- * Process a possible escape sequence.
- */
- switch (ch) {
- case '.':
- printf("%c. [terminated ipmitool]\n",
- intf->ssn_params.sol_escape_char);
- retval = 1;
- break;
- case 'Z' - 64:
- printf("%c^Z [suspend ipmitool]\n",
- intf->ssn_params.sol_escape_char);
- suspendSelf(1); /* Restore tty back to raw */
- continue;
- case 'X' - 64:
- printf("%c^Z [suspend ipmitool]\n",
- intf->ssn_params.sol_escape_char);
- suspendSelf(0); /* Don't restore to raw mode */
- continue;
- case 'B':
- printf("%cB [send break]\n",
- intf->ssn_params.sol_escape_char);
- sendBreak(intf);
- continue;
- case '?':
- printSolEscapeSequences(intf);
- continue;
- default:
- if (ch != intf->ssn_params.sol_escape_char)
- v2_payload.payload.sol_packet.data[length++] =
- intf->ssn_params.sol_escape_char;
- v2_payload.payload.sol_packet.data[length++] = ch;
- }
- }
- else
- {
- if (last_was_cr && (ch == intf->ssn_params.sol_escape_char)) {
- escape_pending = 1;
- continue;
- }
- v2_payload.payload.sol_packet.data[length++] = ch;
- }
- /*
- * Normal character. Record whether it was a newline.
- */
- last_was_cr = (ch == '\r' || ch == '\n');
- }
- /*
- * If there is anything left to process we dispatch it to the BMC,
- * send intf->session->sol_data.max_outbound_payload_size bytes
- * at a time.
- */
- if (length)
- {
- struct ipmi_rs * rsp = NULL;
- int try = 0;
- while (try < intf->ssn_params.retry) {
- v2_payload.payload.sol_packet.character_count = length;
- rsp = intf->send_sol(intf, &v2_payload);
- if (rsp)
- {
- break;
- }
- usleep(5000);
- try++;
- }
- if (! rsp)
- {
- lprintf(LOG_ERR, "Error sending SOL data: FAIL");
- retval = -1;
- }
- /* If the sequence number is set we know we have new data */
- if (retval == 0)
- if ((rsp->session.authtype == IPMI_SESSION_AUTHTYPE_RMCP_PLUS) &&
- (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL) &&
- (rsp->payload.sol_packet.packet_sequence_number))
- output(rsp);
- }
- return retval;
- }
- static int
- ipmi_sol_keepalive_using_sol(struct ipmi_intf * intf)
- {
- struct ipmi_v2_payload v2_payload;
- struct timeval end;
- if (_disable_keepalive)
- return 0;
- gettimeofday(&end, 0);
- if (end.tv_sec - _start_keepalive.tv_sec > SOL_KEEPALIVE_TIMEOUT) {
- memset(&v2_payload, 0, sizeof(v2_payload));
- v2_payload.payload.sol_packet.character_count = 0;
- if (intf->send_sol(intf, &v2_payload) == NULL)
- return -1;
- /* good return, reset start time */
- gettimeofday(&_start_keepalive, 0);
- }
- return 0;
- }
- static int
- ipmi_sol_keepalive_using_getdeviceid(struct ipmi_intf * intf)
- {
- struct timeval end;
- if (_disable_keepalive)
- return 0;
- gettimeofday(&end, 0);
- if (end.tv_sec - _start_keepalive.tv_sec > SOL_KEEPALIVE_TIMEOUT) {
- if (intf->keepalive(intf) != 0)
- return -1;
- /* good return, reset start time */
- gettimeofday(&_start_keepalive, 0);
- }
- return 0;
- }
- /*
- * ipmi_sol_red_pill
- */
- static int
- ipmi_sol_red_pill(struct ipmi_intf * intf, int instance)
- {
- char * buffer;
- int numRead;
- int bShouldExit = 0;
- int bBmcClosedSession = 0;
- fd_set read_fds;
- struct timeval tv;
- int retval;
- int buffer_size = intf->session->sol_data.max_inbound_payload_size;
- int keepAliveRet = 0;
- int retrySol = 0;
- /* Subtract SOL header from max_inbound_payload_size */
- if (buffer_size > 4)
- buffer_size -= 4;
- buffer = (char*)malloc(buffer_size);
- if (buffer == NULL) {
- lprintf(LOG_ERR, "ipmitool: malloc failure");
- return -1;
- }
- /* Initialize keepalive start time */
- gettimeofday(&_start_keepalive, 0);
- enter_raw_mode();
- while (! bShouldExit)
- {
- FD_ZERO(&read_fds);
- FD_SET(0, &read_fds);
- FD_SET(intf->fd, &read_fds);
- if (!ipmi_oem_active(intf,"i82571spt"))
- {
- /* Send periodic keepalive packet */
- if(_use_sol_for_keepalive == 0)
- {
- keepAliveRet = ipmi_sol_keepalive_using_getdeviceid(intf);
- }
- else
- {
- keepAliveRet = ipmi_sol_keepalive_using_sol(intf);
- }
-
- if (keepAliveRet != 0)
- {
- /*
- * Retrying the keep Alive before declaring a communication
- * lost state with the IPMC. Helpful when the payload is
- * reset and brings down the connection temporarily. Otherwise,
- * if we send getDevice Id to check the status of IPMC during
- * this down time when the connection is restarting, SOL will
- * exit even though the IPMC is available and the session is open.
- */
- if (retrySol == MAX_SOL_RETRY)
- {
- /* no response to Get Device ID keepalive message */
- bShouldExit = 1;
- continue;
- }
- else
- {
- retrySol++;
- }
- }
- else
- {
- /* if the keep Alive is successful reset retries to zero */
- retrySol = 0;
- }
- } /* !oem="i82571spt" */
- /* Wait up to half a second */
- tv.tv_sec = 0;
- tv.tv_usec = 500000;
- retval = select(intf->fd + 1, &read_fds, NULL, NULL, &tv);
- if (retval)
- {
- if (retval == -1)
- {
- /* ERROR */
- perror("select");
- return -1;
- }
- /*
- * Process input from the user
- */
- if (FD_ISSET(0, &read_fds))
- {
- memset(buffer, 0, buffer_size);
- numRead = read(fileno(stdin),
- buffer,
- buffer_size);
- if (numRead > 0)
- {
- int rc = processSolUserInput(intf, (uint8_t *)buffer, numRead);
- if (rc)
- {
- if (rc < 0)
- bShouldExit = bBmcClosedSession = 1;
- else
- bShouldExit = 1;
- }
- }
- else
- {
- bShouldExit = 1;
- }
- }
- /*
- * Process input from the BMC
- */
- else if (FD_ISSET(intf->fd, &read_fds))
- {
- struct ipmi_rs * rs =intf->recv_sol(intf);
- if (rs) {
- output(rs);
- } else {
- bShouldExit = bBmcClosedSession = 1;
- }
- }
- /*
- * ERROR in select
- */
- else
- {
- lprintf(LOG_ERR, "Error: Select returned with nothing to read");
- bShouldExit = 1;
- }
- }
- }
- leave_raw_mode();
- if (keepAliveRet != 0)
- {
- lprintf(LOG_ERR, "Error: No response to keepalive - Terminating session");
- /* attempt to clean up anyway */
- ipmi_sol_deactivate(intf, instance);
- exit(1);
- }
- if (bBmcClosedSession)
- {
- lprintf(LOG_ERR, "SOL session closed by BMC");
- exit(1);
- }
- else
- ipmi_sol_deactivate(intf, instance);
- return 0;
- }
- /*
- * ipmi_sol_activate
- */
- static int
- ipmi_sol_activate(struct ipmi_intf * intf, int looptest, int interval,
- int instance)
- {
- struct ipmi_rs * rsp;
- struct ipmi_rq req;
- struct activate_payload_rsp ap_rsp;
- uint8_t data[6];
- uint8_t bSolEncryption = 1;
- uint8_t bSolAuthentication = 1;
- /*
- * This command is only available over RMCP+ (the lanplus
- * interface).
- */
- if (strncmp(intf->name, "lanplus", 7) != 0)
- {
- lprintf(LOG_ERR, "Error: This command is only available over the "
- "lanplus interface");
- return -1;
- }
- if ((instance <= 0) || (instance > 15)) {
- lprintf(LOG_ERR, "Error: Instance must range from 1 to 15");
- return -1;
- }
- /*
- * Setup a callback so that the lanplus processing knows what
- * to do with packets that come unexpectedly (while waiting for
- * an ACK, perhaps.
- */
- intf->session->sol_data.sol_input_handler = output;
- memset(&req, 0, sizeof(req));
- req.msg.netfn = IPMI_NETFN_APP;
- req.msg.cmd = IPMI_ACTIVATE_PAYLOAD;
- req.msg.data_len = 6;
- req.msg.data = data;
- data[0] = IPMI_PAYLOAD_TYPE_SOL; /* payload type */
- data[1] = instance; /* payload instance */
- /* Lots of important data. Most is default */
- data[2] = bSolEncryption? 0x80 : 0;
- data[2] |= bSolAuthentication? 0x40 : 0;
- data[2] |= IPMI_SOL_SERIAL_ALERT_MASK_DEFERRED;
- if (ipmi_oem_active(intf, "intelplus")) {
- data[2] |= IPMI_SOL_BMC_ASSERTS_CTS_MASK_TRUE;
- } else if (ipmi_oem_active(intf, "i82571spt")) {
- /*
- * A quote from Intel: "Engineering believes the problem
- * lies within the Auxiliary data being sent with the
- * 'Activate Payload' command from IPMITool. IPMITool
- * sends a C6h which sets some bits having to do with
- * encryption and some behavior dealing with CTS DCD/DSR.
- * I recommend that the customer modify this request
- * to send 08h instead. This is what our internal utility
- * sends and it works without issue. I will work with
- * engineering to ensure the settings that IPMITool uses
- * (C6h) are supported in the future.
- */
- data[2] = 0x08;
- } else {
- data[2] |= IPMI_SOL_BMC_ASSERTS_CTS_MASK_FALSE;
- }
- data[3] = 0x00; /* reserved */
- data[4] = 0x00; /* reserved */
- data[5] = 0x00; /* reserved */
- rsp = intf->sendrecv(intf, &req);
- if (NULL != rsp) {
- switch (rsp->ccode) {
- case 0x00:
- if (rsp->data_len == 12) {
- break;
- } else {
- lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
- "in payload activation response",
- rsp->data_len);
- return -1;
- }
- break;
- case 0x80:
- lprintf(LOG_ERR, "Info: SOL payload already active on another session");
- return -1;
- case 0x81:
- lprintf(LOG_ERR, "Info: SOL payload disabled");
- return -1;
- case 0x82:
- lprintf(LOG_ERR, "Info: SOL payload activation limit reached");
- return -1;
- case 0x83:
- lprintf(LOG_ERR, "Info: cannot activate SOL payload with encryption");
- return -1;
- case 0x84:
- lprintf(LOG_ERR, "Info: cannot activate SOL payload without encryption");
- return -1;
- default:
- lprintf(LOG_ERR, "Error activating SOL payload: %s",
- val2str(rsp->ccode, completion_code_vals));
- return -1;
- }
- } else {
- lprintf(LOG_ERR, "Error: No response activating SOL payload");
- return -1;
- }
- memcpy(&ap_rsp, rsp->data, sizeof(struct activate_payload_rsp));
- intf->session->sol_data.max_inbound_payload_size =
- (ap_rsp.inbound_payload_size[1] << 8) |
- ap_rsp.inbound_payload_size[0];
- intf->session->sol_data.max_outbound_payload_size =
- (ap_rsp.outbound_payload_size[1] << 8) |
- ap_rsp.outbound_payload_size[0];
- intf->session->sol_data.port =
- (ap_rsp.payload_udp_port[1] << 8) |
- ap_rsp.payload_udp_port[0];
- intf->session->timeout = 1;
- /* NOTE: the spec does allow for SOL traffic to be sent on
- * a different port. we do not yet support that feature. */
- if (intf->session->sol_data.port != intf->ssn_params.port)
- {
- /* try byteswapping port in case BMC sent it incorrectly */
- uint16_t portswap = BSWAP_16(intf->session->sol_data.port);
- if (portswap == intf->ssn_params.port) {
- intf->session->sol_data.port = portswap;
- }
- else {
- lprintf(LOG_ERR, "Error: BMC requests SOL session on different port");
- return -1;
- }
- }
- printf("[SOL Session operational. Use %c? for help]\n",
- intf->ssn_params.sol_escape_char);
- if(looptest == 1)
- {
- ipmi_sol_deactivate(intf, instance);
- usleep(interval*1000);
- return 0;
- }
- /*
- * At this point we are good to go with our SOL session. We
- * need to listen to
- * 1) STDIN for user input
- * 2) The FD for incoming SOL packets
- */
- if (ipmi_sol_red_pill(intf, instance))
- {
- lprintf(LOG_ERR, "Error in SOL session");
- return -1;
- }
- return 0;
- }
- /*
- * print_sol_usage
- */
- static void
- print_sol_usage(void)
- {
- lprintf(LOG_NOTICE, "SOL Commands: info [<channel number>]");
- lprintf(LOG_NOTICE, " set <parameter> <value> [channel]");
- lprintf(LOG_NOTICE, " payload <enable|disable|status> [channel] [userid]");
- lprintf(LOG_NOTICE, " activate [<usesolkeepalive|nokeepalive>] [instance=<number>]");
- lprintf(LOG_NOTICE, " deactivate [instance=<number>]");
- lprintf(LOG_NOTICE, " looptest [<loop times> [<loop interval(in ms)> [<instance>]]]");
- }
- /*
- * print_sol_set_usage
- */
- static void
- print_sol_set_usage(void)
- {
- lprintf(LOG_NOTICE, "\nSOL set parameters and values: \n");
- lprintf(LOG_NOTICE, " set-in-progress set-complete | "
- "set-in-progress | commit-write");
- lprintf(LOG_NOTICE, " enabled true | false");
- lprintf(LOG_NOTICE, " force-encryption true | false");
- lprintf(LOG_NOTICE, " force-authentication true | false");
- lprintf(LOG_NOTICE, " privilege-level user | operator | admin | oem");
- lprintf(LOG_NOTICE, " character-accumulate-level <in 5 ms increments>");
- lprintf(LOG_NOTICE, " character-send-threshold N");
- lprintf(LOG_NOTICE, " retry-count N");
- lprintf(LOG_NOTICE, " retry-interval <in 10 ms increments>");
- lprintf(LOG_NOTICE, " non-volatile-bit-rate "
- "serial | 9.6 | 19.2 | 38.4 | 57.6 | 115.2");
- lprintf(LOG_NOTICE, " volatile-bit-rate "
- "serial | 9.6 | 19.2 | 38.4 | 57.6 | 115.2");
- lprintf(LOG_NOTICE, "");
- }
- /* ipmi_sol_main */
- int
- ipmi_sol_main(struct ipmi_intf * intf, int argc, char ** argv)
- {
- int retval = 0;
- if (!argc || !strncmp(argv[0], "help", 4)) {
- /* Help */
- print_sol_usage();
- } else if (!strncmp(argv[0], "info", 4)) {
- /* Info */
- uint8_t channel;
- if (argc == 1) {
- /* Ask about the current channel */
- channel = 0x0E;
- } else if (argc == 2) {
- if (is_ipmi_channel_num(argv[1], &channel) != 0) {
- return (-1);
- }
- } else {
- print_sol_usage();
- return -1;
- }
- retval = ipmi_print_sol_info(intf, channel);
- } else if (!strncmp(argv[0], "payload", 7)) {
- /* Payload enable or disable */
- uint8_t channel = 0xe;
- uint8_t userid = 1;
- int enable = -1;
- if (argc == 1 || argc > 4) {
- print_sol_usage();
- return -1;
- }
- if (argc >= 3) {
- if (is_ipmi_channel_num(argv[2], &channel) != 0) {
- return (-1);
- }
- }
- if (argc == 4) {
- if (is_ipmi_user_id(argv[3], &userid) != 0) {
- return (-1);
- }
- }
- if (!strncmp(argv[1], "enable", 6)) {
- enable = 1;
- } else if (!strncmp(argv[1], "disable", 7)) {
- enable = 0;
- } else if (!strncmp(argv[1], "status", 6)) {
- return ipmi_sol_payload_access_status(intf, channel, userid);
- } else {
- print_sol_usage();
- return -1;
- }
- retval = ipmi_sol_payload_access(intf, channel, userid, enable);
- } else if (!strncmp(argv[0], "set", 3)) {
- /* Set a parameter value */
- uint8_t channel = 0xe;
- uint8_t guard = 1;
- if (argc == 3) {
- channel = 0xe;
- } else if (argc == 4) {
- if (!strncmp(argv[3], "noguard", 7)) {
- guard = 0;
- } else {
- if (is_ipmi_channel_num(argv[3], &channel) != 0) {
- return (-1);
- }
- }
- } else if (argc == 5) {
- if (is_ipmi_channel_num(argv[3], &channel) != 0) {
- return (-1);
- }
- if (!strncmp(argv[4], "noguard", 7)) {
- guard = 0;
- }
- } else {
- print_sol_set_usage();
- return -1;
- }
- retval = ipmi_sol_set_param(intf, channel, argv[1], argv[2], guard);
- } else if (!strncmp(argv[0], "activate", 8)) {
- /* Activate */
- int i;
- uint8_t instance = 1;
- for (i = 1; i < argc; i++) {
- if (!strncmp(argv[i], "usesolkeepalive", 15)) {
- _use_sol_for_keepalive = 1;
- } else if (!strncmp(argv[i], "nokeepalive", 11)) {
- _disable_keepalive = 1;
- } else if (!strncmp(argv[i], "instance=", 9)) {
- if (str2uchar(argv[i] + 9, &instance) != 0) {
- lprintf(LOG_ERR, "Given instance '%s' is invalid.", argv[i] + 9);
- print_sol_usage();
- return -1;
- }
- } else {
- print_sol_usage();
- return -1;
- }
- }
- retval = ipmi_sol_activate(intf, 0, 0, instance);
- } else if (!strncmp(argv[0], "deactivate", 10)) {
- /* Dectivate */
- int i;
- uint8_t instance = 1;
- for (i = 1; i < argc; i++) {
- if (!strncmp(argv[i], "instance=", 9)) {
- if (str2uchar(argv[i] + 9, &instance) != 0) {
- lprintf(LOG_ERR,
- "Given instance '%s' is invalid.",
- argv[i] + 9);
- print_sol_usage();
- return -1;
- }
- } else {
- print_sol_usage();
- return -1;
- }
- }
- retval = ipmi_sol_deactivate(intf, instance);
- } else if (!strncmp(argv[0], "looptest", 8)) {
- /* SOL loop test: Activate and then Dectivate */
- int cnt = 200;
- int interval = 100; /* Unit is: ms */
- uint8_t instance = 1;
- if (argc > 4) {
- print_sol_usage();
- return -1;
- }
- if (argc != 1) {
- /* at least 2 */
- if (str2int(argv[1], &cnt) != 0) {
- lprintf(LOG_ERR, "Given cnt '%s' is invalid.",
- argv[1]);
- return (-1);
- }
- if (cnt <= 0) {
- cnt = 200;
- }
- }
- if (argc >= 3) {
- if (str2int(argv[2], &interval) != 0) {
- lprintf(LOG_ERR, "Given interval '%s' is invalid.",
- argv[2]);
- return (-1);
- }
- if (interval < 0) {
- interval = 0;
- }
- }
- if (argc >= 4) {
- if (str2uchar(argv[3], &instance) != 0) {
- lprintf(LOG_ERR, "Given instance '%s' is invalid.",
- argv[3]);
- print_sol_usage();
- return -1;
- }
- }
- while (cnt > 0) {
- printf("remain loop test counter: %d\n", cnt);
- retval = ipmi_sol_activate(intf, 1, interval, instance);
- if (retval) {
- printf("SOL looptest failed: %d\n",
- retval);
- break;
- }
- cnt -= 1;
- }
- } else {
- print_sol_usage();
- retval = -1;
- }
- return retval;
- }
|