From a7f89980e5b3f4b9a74c70dbc5ffe8aabd28be28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Sun, 6 Jul 2014 18:04:32 +0200 Subject: Imported Upstream version 2.9.3 --- util/AnsiTerm.cpp | 1892 +++++++++++++++ util/AnsiTerm.h | 316 +++ util/Makefile.am | 200 ++ util/Makefile.am-so | 241 ++ util/Makefile.in | 766 ++++++ util/Makefile.sample | 28 + util/ialarms.c | 689 ++++++ util/icmd.c | 366 +++ util/iconfig.c | 2680 +++++++++++++++++++++ util/idcmi.c | 976 ++++++++ util/idcmi.h | 69 + util/idiscover.c | 1055 +++++++++ util/iekanalyzer.c | 4131 ++++++++++++++++++++++++++++++++ util/iekanalyzer.h | 521 +++++ util/ievents.c | 2505 ++++++++++++++++++++ util/ievents.h | 64 + util/ifirewall.c | 1154 +++++++++ util/ifirewall.h | 111 + util/ifru.c | 2123 +++++++++++++++++ util/ifru.h | 13 + util/ifru_picmg.c | 486 ++++ util/ifruset.c | 1658 +++++++++++++ util/ifwum.c | 1697 ++++++++++++++ util/ifwum.h | 76 + util/igetevent.c | 1439 ++++++++++++ util/ihealth.c | 1153 +++++++++ util/ihpm.c | 4003 +++++++++++++++++++++++++++++++ util/ihpm.h | 117 + util/ilan.c | 5149 ++++++++++++++++++++++++++++++++++++++++ util/imb_api.h | 708 ++++++ util/imbapi.c | 2594 +++++++++++++++++++++ util/ipicmg.c | 1911 +++++++++++++++ util/ipicmg.h | 313 +++ util/ipmi_port.c | 146 ++ util/ipmi_sample.c | 312 +++ util/ipmi_sample.mak | 57 + util/ipmi_sample_evt.c | 445 ++++ util/ipmibmc.c | 231 ++ util/ipmicmd.c | 1429 ++++++++++++ util/ipmicmd.h | 543 +++++ util/ipmidir.c | 1513 ++++++++++++ util/ipmidir.h | 301 +++ util/ipmilan.c | 2430 +++++++++++++++++++ util/ipmilan.h | 83 + util/ipmilan2.c | 68 + util/ipmilan2.h | 62 + util/ipmilanplus.c | 790 +++++++ util/ipmilanplus.h | 64 + util/ipmild.c | 250 ++ util/ipmilipmi.c | 182 ++ util/ipmims.cpp | 638 +++++ util/ipmimv.c | 784 +++++++ util/ipmiutil.c | 229 ++ util/ipmiutil.h | 66 + util/ipmiutil.mak | 424 ++++ util/ipmiutil2-64.mak | 425 ++++ util/ipmiutil2.mak | 425 ++++ util/ipmiutil64.mak | 423 ++++ util/ipmiutillib.def | 31 + util/ireset.c | 751 ++++++ util/isel.c | 884 +++++++ util/iseltime.c | 260 +++ util/isensor.c | 3680 +++++++++++++++++++++++++++++ util/isensor.h | 176 ++ util/iserial.c | 1592 +++++++++++++ util/isol.c | 1347 +++++++++++ util/isolwin.c | 293 +++ util/itsol.c | 725 ++++++ util/itsol.h | 66 + util/iwdt.c | 415 ++++ util/md2.c | 99 + util/md2.h | 269 +++ util/md5.c | 413 ++++ util/mem_if.c | 900 +++++++ util/mem_if_cpp.cpp | 5 + util/oem_dell.c | 6095 ++++++++++++++++++++++++++++++++++++++++++++++++ util/oem_dell.h | 629 +++++ util/oem_fujitsu.c | 773 ++++++ util/oem_fujitsu.h | 130 ++ util/oem_hp.c | 149 ++ util/oem_intel.c | 1842 +++++++++++++++ util/oem_intel.h | 79 + util/oem_kontron.c | 1107 +++++++++ util/oem_kontron.h | 80 + util/oem_newisys.c | 129 + util/oem_quanta.c | 142 ++ util/oem_sun.c | 1058 +++++++++ util/oem_sun.h | 137 ++ util/oem_supermicro.c | 595 +++++ util/oem_supermicro.h | 56 + util/subs.c | 848 +++++++ 91 files changed, 79279 insertions(+) create mode 100644 util/AnsiTerm.cpp create mode 100644 util/AnsiTerm.h create mode 100644 util/Makefile.am create mode 100644 util/Makefile.am-so create mode 100644 util/Makefile.in create mode 100644 util/Makefile.sample create mode 100644 util/ialarms.c create mode 100644 util/icmd.c create mode 100644 util/iconfig.c create mode 100644 util/idcmi.c create mode 100644 util/idcmi.h create mode 100644 util/idiscover.c create mode 100644 util/iekanalyzer.c create mode 100644 util/iekanalyzer.h create mode 100644 util/ievents.c create mode 100644 util/ievents.h create mode 100644 util/ifirewall.c create mode 100644 util/ifirewall.h create mode 100755 util/ifru.c create mode 100644 util/ifru.h create mode 100644 util/ifru_picmg.c create mode 100644 util/ifruset.c create mode 100644 util/ifwum.c create mode 100644 util/ifwum.h create mode 100644 util/igetevent.c create mode 100644 util/ihealth.c create mode 100644 util/ihpm.c create mode 100644 util/ihpm.h create mode 100644 util/ilan.c create mode 100644 util/imb_api.h create mode 100644 util/imbapi.c create mode 100644 util/ipicmg.c create mode 100644 util/ipicmg.h create mode 100644 util/ipmi_port.c create mode 100644 util/ipmi_sample.c create mode 100644 util/ipmi_sample.mak create mode 100644 util/ipmi_sample_evt.c create mode 100644 util/ipmibmc.c create mode 100644 util/ipmicmd.c create mode 100644 util/ipmicmd.h create mode 100644 util/ipmidir.c create mode 100644 util/ipmidir.h create mode 100644 util/ipmilan.c create mode 100644 util/ipmilan.h create mode 100644 util/ipmilan2.c create mode 100644 util/ipmilan2.h create mode 100644 util/ipmilanplus.c create mode 100644 util/ipmilanplus.h create mode 100644 util/ipmild.c create mode 100644 util/ipmilipmi.c create mode 100644 util/ipmims.cpp create mode 100644 util/ipmimv.c create mode 100644 util/ipmiutil.c create mode 100644 util/ipmiutil.h create mode 100644 util/ipmiutil.mak create mode 100644 util/ipmiutil2-64.mak create mode 100644 util/ipmiutil2.mak create mode 100644 util/ipmiutil64.mak create mode 100644 util/ipmiutillib.def create mode 100644 util/ireset.c create mode 100644 util/isel.c create mode 100644 util/iseltime.c create mode 100644 util/isensor.c create mode 100644 util/isensor.h create mode 100644 util/iserial.c create mode 100644 util/isol.c create mode 100644 util/isolwin.c create mode 100644 util/itsol.c create mode 100644 util/itsol.h create mode 100644 util/iwdt.c create mode 100644 util/md2.c create mode 100644 util/md2.h create mode 100644 util/md5.c create mode 100644 util/mem_if.c create mode 100644 util/mem_if_cpp.cpp create mode 100644 util/oem_dell.c create mode 100644 util/oem_dell.h create mode 100644 util/oem_fujitsu.c create mode 100644 util/oem_fujitsu.h create mode 100644 util/oem_hp.c create mode 100644 util/oem_intel.c create mode 100644 util/oem_intel.h create mode 100644 util/oem_kontron.c create mode 100644 util/oem_kontron.h create mode 100644 util/oem_newisys.c create mode 100644 util/oem_quanta.c create mode 100644 util/oem_sun.c create mode 100644 util/oem_sun.h create mode 100644 util/oem_supermicro.c create mode 100644 util/oem_supermicro.h create mode 100644 util/subs.c (limited to 'util') diff --git a/util/AnsiTerm.cpp b/util/AnsiTerm.cpp new file mode 100644 index 0000000..be94465 --- /dev/null +++ b/util/AnsiTerm.cpp @@ -0,0 +1,1892 @@ +/* + * AnsiTerm.cpp + * Windows ANSI Terminal Emulation + * + * Author: Robert Nelson robertnelson at users.sourceforge.net + * Copyright (c) 2009 Robert Nelson + * + * 10/07/09 Robert Nelson - Created + * 10/08/09 Robert Nelson + * - Fixed bug with resetting attribute to Black on Black on exit + * - Fixed setting of attribute when erasing + * - Added automatic handling of buffer resize events + * - Added display of unrecognized escape sequences + * 10/15/09 Robert Nelson + * - Fixed display problems caused by custom ColorTable used by cmd.exe + * - Fixed cursor positioning problems with OriginMode. + * - Changed to use block cursor because I think its more terminal like :-) + * - Added Reset handling + * - Added Cursor Show / Hide + * 10/16/09 Robert Nelson + * - Better handling of ColorTable. + * 10/17/09 Robert Nelson + * - Use GetProcAddress for (Get/Set)ConsoleScreenBufferInfoEx since they + * are only available on Vista and beyond. + * + * Todo: + * - Implement soft tabs + */ + +/* +Copyright (c) 2009, Robert Nelson +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions 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. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#include +#include +#include +#include "AnsiTerm.h" + +extern "C" unsigned char fCRLF; +extern "C" void dbglog( char *pattn, ... ); + +CAnsiTerm::CSICode CAnsiTerm::s_CSITable[] = +{ + { '[', DS_CSIParam }, + { '#', DS_DECPrivate }, + { '(', DS_SelectG0 }, + { ')', DS_SelectG1 }, + { '=', DS_None, &ProcessDECKPAM }, // Keypad Application Mode + { '>', DS_None, &ProcessDECKPNM }, // Keypad Numeric Mode + { '7', DS_None, &ProcessDECSC }, // Save Cursor + { '8', DS_None, &ProcessDECRC }, // Restore Cursor + { 'D', DS_None, &ProcessIND }, // Index + { 'E', DS_None, &ProcessNEL }, // Next Line + { 'H', DS_None, &ProcessHTS }, // Horizontal Tab Set + { 'M', DS_None, &ProcessRI }, // Reverse Index + { 'Z', DS_None, &ProcessDECID }, // Identify Terminal + { 'c', DS_None, &ProcessRIS }, // Reset to Initial State + { 's', DS_None, &ProcessSCP }, // Save Cursor Position + { 'u', DS_None, &ProcessRCP }, // Restore Cursor Position + { '\0' } +}; + +CAnsiTerm::CSIFunction CAnsiTerm::s_DECFunction[] = +{ + { '3', &ProcessDECDHLT }, // Double Height Line Top + { '4', &ProcessDECDHLB }, // Double Height Line Bottom + { '5', &ProcessDECSWL }, // Single Width Line + { '6', &ProcessDECDWL }, // Double Width Line + { '8', &ProcessDECALN }, // Screen Alignment Display + { '\0' } +}; + +CAnsiTerm::CSIFunction CAnsiTerm::s_CSIFunction[] = +{ + { 'A', &ProcessCUU }, // Cursor Up + { 'B', &ProcessCUD }, // Cursor Down + { 'C', &ProcessCUF }, // Cursor Forward + { 'D', &ProcessCUB }, // Cursor Backward + { 'H', &ProcessCUP }, // Cursor Position + { 'J', &ProcessED }, // Erase in Display + { 'K', &ProcessEL }, // Erase in Line + { 'c', &ProcessDA }, // Device Attributes + { 'f', &ProcessHVP }, // Horizontal and Vertical Position + { 'g', &ProcessTBC }, // Tabulation Clear + { 'h', &ProcessSM }, // Set Mode + { 'l', &ProcessRM }, // Reset Mode + { 'm', &ProcessSGR }, // Select Graphics Rendition + { 'n', &ProcessDSR }, // Device Status Report + { 'q', &ProcessDECLL }, // DEC Load LEDs + { 'r', &ProcessDECSTBM }, // DEC Set Top and Bottom Margins + { 'x', &ProcessDECREQTPARM }, // Request Terminal Parameters + { 'y', &ProcessDECTST }, // Invoke Confidence Test + { '\0' } +}; + +wchar_t CAnsiTerm::s_GraphicChars[kMaxGraphicsChar - kMinGraphicsChar + 1] = +{ + 0x0020, // 0137 5F 95 _ Blank + 0x2666, // 0140 60 96 ` Diamond + 0x2592, // 0141 61 97 a Checkerboard + 0x2409, // 0142 62 98 b Horizontal Tab + 0x240C, // 0143 63 99 c Form Feed + 0x240D, // 0144 64 100 d Carriage Return + 0x240A, // 0145 65 101 e Line Feed + 0x00B0, // 0146 66 102 f Degree Symbol + 0x00B1, // 0147 67 103 g Plus/Minus + 0x2424, // 0150 68 104 h New Line + 0x240B, // 0151 69 105 i Vertical Tab + 0x2518, // 0152 6A 106 j Lower-right corner + 0x2510, // 0153 6B 107 k Upper-right corner + 0x250C, // 0154 6C 108 l Upper-left corner + 0x2514, // 0155 6D 109 m Lower-left corner + 0x253C, // 0156 6E 110 n Crossing Lines + 0x00AF, // 0157 6F 111 o Horizontal Line - Scan 1 + 0x0070, // 0160 70 112 p Horizontal Line - Scan 3 (No translation) + 0x2500, // 0161 71 113 q Horizontal Line - Scan 5 + 0x0072, // 0162 72 114 r Horizontal Line - Scan 7 (No translation) + 0x005F, // 0163 73 115 s Horizontal Line - Scan 9 + 0x251C, // 0164 74 116 t Left "T" + 0x2524, // 0165 75 117 u Right "T" + 0x2534, // 0166 76 118 v Bottom "T" + 0x252C, // 0167 77 119 w Top "T" + 0x2502, // 0170 78 120 x | Vertical bar + 0x2264, // 0171 79 121 y Less than or equal to + 0x2265, // 0172 7A 122 z Greater than or equal to + 0x03C0, // 0173 7B 123 { Pi + 0x2260, // 0174 7C 124 | Not equal to + 0x00A3, // 0175 7D 125 } UK Pound Sign + 0x00B7 // 0176 7E 126 ~ Centered dot +}; + +wchar_t CAnsiTerm::s_OemToUnicode[256] = +{ + 0x2007, 0x263A, 0x263B, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, // 00-07 + 0x25D8, 0x25CB, 0x25D9, 0x2642, 0x2640, 0x266A, 0x266B, 0x263C, // 08-0F + 0x25BA, 0x25C4, 0x2195, 0x203C, 0x00B6, 0x00A7, 0x25AC, 0x21A8, // 10-17 + 0x2191, 0x2193, 0x2192, 0x2190, 0x221F, 0x2194, 0x25B2, 0x25BC, // 18-1F + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, // 20-27 + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, // 28-2F + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, // 30-37 + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, // 38-3F + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, // 40-47 + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, // 48-4F + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, // 50-57 + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, // 58-5F + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, // 60-67 + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, // 68-6F + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, // 70-77 + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, // 78-7F + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, // 80-87 + 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, // 88-8F + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, // 90-97 + 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, // 98-9F + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, // A0-A7 + 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, // A8-AF + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, // B0-B7 + 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, // B8-BF + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, // C0-C7 + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, // C8-CF + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, // D0-D7 + 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, // D8-DF + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, // E0-E7 + 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, // E8-EF + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, // F0-F7 + 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 // F8-FF +}; + +COLORREF CAnsiTerm::s_ColorTable[kColorTableSize] = +{ + RGB(0, 0, 0), + RGB(0, 0, 128), + RGB(0, 128, 0), + RGB(0, 128, 128), + RGB(128, 0, 0), + RGB(128, 0, 128), + RGB(128, 128, 0), + RGB(192, 192, 192), + RGB(128, 128, 128), + RGB(0, 0, 255), + RGB(0, 255, 0), + RGB(0, 255, 255), + RGB(255, 0, 0), + RGB(255, 0, 255), + RGB(255, 255, 0), + RGB(255, 255, 255) +}; + +CAnsiTerm::PFN_GetConsoleScreenBufferInfoEx CAnsiTerm::s_pfnGetConsoleScreenBufferInfoEx; +CAnsiTerm::PFN_SetConsoleScreenBufferInfoEx CAnsiTerm::s_pfnSetConsoleScreenBufferInfoEx; + +CAnsiTerm::CAnsiTerm(void) +{ + m_hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + + GetConsoleMode(m_hConsole, &m_dwOrigConsoleMode); + + SetConsoleMode(m_hConsole, ENABLE_PROCESSED_OUTPUT); + + CONSOLE_CURSOR_INFO cursorInfo; + + GetConsoleCursorInfo(m_hConsole, &cursorInfo); + + m_dwOrigCursorSize = cursorInfo.dwSize; + + WindowSizeChanged(true); +} + +CAnsiTerm::~CAnsiTerm(void) +{ + CONSOLE_CURSOR_INFO cursorInfo = { m_dwOrigCursorSize, TRUE }; + + SetConsoleCursorInfo(m_hConsole, &cursorInfo); + + SetConsoleMode(m_hConsole, m_dwOrigConsoleMode); + + SetConsoleTextAttribute(m_hConsole, m_wOrigConsoleAttribute); + + if (m_bResetColorTable) + { + CONSOLE_SCREEN_BUFFER_INFOEX consoleInfo = { sizeof(consoleInfo) }; + + s_pfnGetConsoleScreenBufferInfoEx(m_hConsole, &consoleInfo); + + memcpy(consoleInfo.ColorTable, m_OrigColorTable, kColorTableSize * sizeof(consoleInfo.ColorTable[0])); + + // There is a bug between GetConsoleScreenBufferInfoEx and SetConsoleScreenBufferInfoEx. + // The first treats srWindow.Right and srWindow.Bottom as inclusive and the latter as exclusive. + consoleInfo.srWindow.Right++; + consoleInfo.srWindow.Bottom++; + + s_pfnSetConsoleScreenBufferInfoEx(m_hConsole, &consoleInfo); + + // Reset the attributes on existing lines so that at least white on black looks + // correct. + COORD coordStart = { 0, 0 }; + DWORD dwWritten; + + FillConsoleOutputAttribute(m_hConsole, m_wOrigConsoleAttribute, m_BufferSize.X * m_BufferSize.Y, coordStart, &dwWritten); + } + + CloseHandle(m_hConsole); +} + +void +CAnsiTerm::WindowSizeChanged(bool bInitial) +{ + WORD wCurrentAttribute; + COORD dwCurrentCursorPosition; + + if (bInitial) + { + HMODULE hKernel32 = GetModuleHandle("kernel32"); + + if (hKernel32 != NULL) + { + s_pfnGetConsoleScreenBufferInfoEx = (PFN_GetConsoleScreenBufferInfoEx)GetProcAddress(hKernel32, "GetConsoleScreenBufferInfoEx"); + s_pfnSetConsoleScreenBufferInfoEx = (PFN_SetConsoleScreenBufferInfoEx)GetProcAddress(hKernel32, "SetConsoleScreenBufferInfoEx"); + + if (s_pfnGetConsoleScreenBufferInfoEx == NULL || s_pfnSetConsoleScreenBufferInfoEx == NULL) + { + s_pfnGetConsoleScreenBufferInfoEx = NULL; + s_pfnSetConsoleScreenBufferInfoEx = NULL; + } + } + + m_bResetColorTable = false; + } + + if (s_pfnGetConsoleScreenBufferInfoEx != NULL) + { + CONSOLE_SCREEN_BUFFER_INFOEX consoleInfo = { sizeof(consoleInfo) }; + + s_pfnGetConsoleScreenBufferInfoEx(m_hConsole, &consoleInfo); + + m_BufferSize = consoleInfo.dwSize; + + m_WindowSize.X = consoleInfo.srWindow.Right - consoleInfo.srWindow.Left + 1; + m_WindowSize.Y = consoleInfo.srWindow.Bottom - consoleInfo.srWindow.Top + 1; + + wCurrentAttribute = consoleInfo.wAttributes; + dwCurrentCursorPosition = consoleInfo.dwCursorPosition; + + if (bInitial) + { + m_bResetColorTable = memcmp(consoleInfo.ColorTable, s_ColorTable, sizeof(s_ColorTable)) != 0; + + if (m_bResetColorTable) + { + // The command prompt (cmd.exe) uses a nonstandard color table + // So we save it away and reset it to match the Console API documentation + size_t colorCopyLen = kColorTableSize * sizeof(consoleInfo.ColorTable[0]); + + memcpy(m_OrigColorTable, consoleInfo.ColorTable, colorCopyLen); + + memcpy(consoleInfo.ColorTable, s_ColorTable, colorCopyLen); + + // There is a bug between GetConsoleScreenBufferInfoEx and SetConsoleScreenBufferInfoEx. + // The first treats srWindow.Right and srWindow.Bottom as inclusive and the latter as exclusive. + consoleInfo.srWindow.Right++; + consoleInfo.srWindow.Bottom++; + + s_pfnSetConsoleScreenBufferInfoEx(m_hConsole, &consoleInfo); + + // Reset the attributes on existing lines so that at least white on black looks + // correct. + COORD coordStart = { 0, 0 }; + DWORD dwWritten; + + FillConsoleOutputAttribute(m_hConsole, kDefaultAttribute, m_BufferSize.X * m_BufferSize.Y, coordStart, &dwWritten); + } + } + } + else + { + CONSOLE_SCREEN_BUFFER_INFO consoleInfo; + + GetConsoleScreenBufferInfo(m_hConsole, &consoleInfo); + + m_BufferSize = consoleInfo.dwSize; + + m_WindowSize.X = consoleInfo.srWindow.Right - consoleInfo.srWindow.Left + 1; + m_WindowSize.Y = consoleInfo.srWindow.Bottom - consoleInfo.srWindow.Top + 1; + + wCurrentAttribute = consoleInfo.wAttributes; + dwCurrentCursorPosition = consoleInfo.dwCursorPosition; + } + + m_WindowOrigin.X = 0; + m_WindowOrigin.Y = m_BufferSize.Y - m_WindowSize.Y; + + if (bInitial) + { + m_wOrigConsoleAttribute = wCurrentAttribute; + + SHORT nLines = dwCurrentCursorPosition.Y - m_WindowOrigin.Y; + + if (nLines != 0) + { + SMALL_RECT rectSource = { 0, 0, m_BufferSize.X - 1, m_BufferSize.Y - 1 }; + COORD coordDest = { 0, 0 }; + CHAR_INFO charInfo = { ' ', kDefaultAttribute }; + + if (nLines > 0) + { + rectSource.Top = nLines; + } + else + { + coordDest.Y -= nLines; + rectSource.Bottom += nLines; + } + + ScrollConsoleScreenBuffer(m_hConsole, &rectSource, NULL, coordDest, &charInfo); + } + } + + ResetTerm(); +} + +int +CAnsiTerm::ProcessInput(CAnsiTerm::KeyCode keyCode, unsigned char *pOutput, int iOutputSize) +{ + int iOutputLength = 0; + + if (pOutput == NULL || iOutputSize < 1) + { + return 0; + } + + if (!keyCode.bKeyDown) + { + return 0; + } + + if (VK_F1 <= keyCode.VirtualKeyCode && keyCode.VirtualKeyCode <= VK_F12) + { + pOutput[iOutputLength++] = CH_ESC; + pOutput[iOutputLength++] = 'O'; + pOutput[iOutputLength++] = 'P' + keyCode.VirtualKeyCode - VK_F1; + } + else + if (keyCode.VirtualKeyCode == VK_UP || + keyCode.VirtualKeyCode == VK_DOWN || + keyCode.VirtualKeyCode == VK_RIGHT || + keyCode.VirtualKeyCode == VK_LEFT) + { + pOutput[iOutputLength++] = CH_ESC; + + if ((m_bCursorKeyMode && !keyCode.bControl) || + (!m_bCursorKeyMode && keyCode.bControl)) + { + pOutput[iOutputLength++] = 'O'; + } + else + { + pOutput[iOutputLength++] = '['; + } + + switch (keyCode.VirtualKeyCode) + { + case VK_UP: + pOutput[iOutputLength++] = 'A'; + break; + + case VK_DOWN: + pOutput[iOutputLength++] = 'B'; + break; + + case VK_RIGHT: + pOutput[iOutputLength++] = 'C'; + break; + + case VK_LEFT: + pOutput[iOutputLength++] = 'D'; + break; + } + } + else + if (keyCode.VirtualKeyCode == VK_HOME || + keyCode.VirtualKeyCode == VK_INSERT || + keyCode.VirtualKeyCode == VK_DELETE || + keyCode.VirtualKeyCode == VK_END || + keyCode.VirtualKeyCode == VK_PRIOR || + keyCode.VirtualKeyCode == VK_NEXT) + { + pOutput[iOutputLength++] = CH_ESC; + pOutput[iOutputLength++] = '['; + + switch (keyCode.VirtualKeyCode) + { + case VK_HOME: + pOutput[iOutputLength++] = '1'; + break; + + case VK_INSERT: + pOutput[iOutputLength++] = '2'; + break; + + case VK_DELETE: + pOutput[iOutputLength++] = '3'; + break; + + case VK_END: + pOutput[iOutputLength++] = '4'; + break; + + case VK_PRIOR: + pOutput[iOutputLength++] = '5'; + break; + + case VK_NEXT: + pOutput[iOutputLength++] = '6'; + break; + } + + pOutput[iOutputLength++] = '~'; + } + else + if (keyCode.VirtualKeyCode == VK_RETURN) + { + pOutput[iOutputLength++] = CH_CR; + if (fCRLF == 1) + { + pOutput[iOutputLength++] = CH_LF; + } + } + else + if (keyCode.AsciiChar != '\0') + { + pOutput[iOutputLength++] = keyCode.AsciiChar; + } + + return iOutputLength; +} + +bool +CAnsiTerm::ProcessOutput(const unsigned char *szData, int iLength) +{ + const unsigned char *pEnd = &szData[iLength]; + + for (const unsigned char *pCurrent = szData; pCurrent < pEnd; pCurrent++) + { + if (*pCurrent < 0x20 || *pCurrent == 0x7F) + { + dbglog("ProcessOutput: control_ch = %02x\n",*pCurrent); + OutputText(); + + switch (*pCurrent) + { + case CH_NUL: + case CH_ENQ: + case CH_DEL: + // These are ignored + break; + + case CH_BEL: + MessageBeep(MB_ICONASTERISK); + break; + + case CH_BS: + ProcessBackspace(); + break; + + case CH_HT: + ProcessTab(); + break; + + case CH_LF: + case CH_VT: + case CH_FF: + ProcessLinefeed(m_bLineFeedNewLineMode); + break; + + case CH_CR: + ProcessReturn(); + break; + + case CH_SO: + m_SelectedCharset = CharsetG1; + break; + + case CH_SI: + m_SelectedCharset = CharsetG0; + break; + + case CH_XON: + // Not yet implemented + break; + + case CH_XOF: + // Not yet implemented + break; + +#if 0 + case CH_CAN: + case CH_SUB: + // Output error character + break; +#endif + + case CH_ESC: + m_State = DS_Escape; + break; + + default: + AddOutputData(s_OemToUnicode[*pCurrent]); + break; + } + } + else + { + /* db b3 or b0 b3 */ + if (*pCurrent & 0x80) + dbglog("ProcessOutput: state=%d ch=%02x\n",m_State,*pCurrent); + switch (m_State) + { + case DS_Normal: + if (*pCurrent & 0x80) + { + // Could be start of a UTF-8 sequence or an ANSI extended character + + if ((*pCurrent & 0xE0) == 0xC0) + { + m_UTF8Size = 2; + } + else if ((*pCurrent & 0xF0) == 0xE0) + { + m_UTF8Size = 3; + } + else + { + // Not a UTF-8 lead character + AddOutputData(s_OemToUnicode[*pCurrent]); + break; + } + m_UTF8Count = 1; + m_UTF8Buffer[0] = *pCurrent; + m_State = DS_UTF8; + break; + } + + if ((m_SelectedCharset == CharsetG0 && m_G0Charset == SpecialGraphicsCharset) || + (m_SelectedCharset == CharsetG1 && m_G1Charset == SpecialGraphicsCharset)) + { + if (kMinGraphicsChar <= *pCurrent && *pCurrent <= kMaxGraphicsChar) + { + AddOutputData(s_GraphicChars[*pCurrent - kMinGraphicsChar]); + } + else + { + AddOutputData(*pCurrent); + } + } + else + { + AddOutputData(*pCurrent); + } + break; + + case DS_UTF8: + if ((*pCurrent & 0xC0) != 0x80) + { + for (int index = 0; index < m_UTF8Count; index++) + { + AddOutputData(s_OemToUnicode[m_UTF8Buffer[index]]); + } + + if (*pCurrent & 0x80) + { + AddOutputData(s_OemToUnicode[*pCurrent]); + } + else + { + AddOutputData(*pCurrent); + } + m_State = DS_Normal; + } + else + { + m_UTF8Buffer[m_UTF8Count++] = *pCurrent; + + if (m_UTF8Count == m_UTF8Size) + { + wchar_t wchUTF16; + if (m_UTF8Size == 2) + { + wchUTF16 = ((m_UTF8Buffer[0] & 0x1F) << 6) | (m_UTF8Buffer[1] & 0x3F); + } + else + { + wchUTF16 = ((m_UTF8Buffer[0] & 0x0F) << 12) | ((m_UTF8Buffer[1] & 0x3F) << 6) | (m_UTF8Buffer[2] & 0x3F); + } + + AddOutputData(wchUTF16); + m_State = DS_Normal; + } + } + break; + + case DS_Escape: + for (int index = 0; s_CSITable[index].chCode != '\0'; index++) + { + if (*pCurrent == s_CSITable[index].chCode) + { + if (s_CSITable[index].dsNextState != DS_None) + { + m_State = s_CSITable[index].dsNextState; + m_Parameters[0] = 0; + m_ParameterCount = 0; + m_bParametersStart = true; + } + else + { + (this->*s_CSITable[index].pfnProcess)(); + m_State = DS_Normal; + } + break; + } + } + + if (m_State == DS_Escape) + { + AddOutputData(L'^'); + AddOutputData(L'['); + AddOutputData(*pCurrent); + m_State = DS_Normal; + } + break; + + case DS_CSIParam: + if (m_bParametersStart) + { + m_bParametersStart = false; + + if (*pCurrent == '?') + { + m_bPrivateParameters = true; + break; + } + else + { + m_bPrivateParameters = false; + } + } + if ('0' <= *pCurrent && *pCurrent <= '9') + { + if (m_ParameterCount < kMaxParameterCount) + { + m_Parameters[m_ParameterCount] *= 10; + m_Parameters[m_ParameterCount] += *pCurrent - '0'; + } + } + else if (*pCurrent == ';') + { + if (m_ParameterCount < kMaxParameterCount) + { + m_ParameterCount++; + } + + if (m_ParameterCount < kMaxParameterCount) + { + m_Parameters[m_ParameterCount] = 0; + } + } + else + { + if (m_ParameterCount < kMaxParameterCount) + { + m_ParameterCount++; + } + + for (int index = 0; s_CSIFunction[index].chCode != '\0'; index++) + { + if (*pCurrent == s_CSIFunction[index].chCode) + { + (this->*s_CSIFunction[index].pfnProcess)(); + m_State = DS_Normal; + break; + } + } + if (m_State != DS_Normal) + { + DisplayCSI(*pCurrent); + m_State = DS_Normal; + } + } + break; + + case DS_DECPrivate: + for (int index = 0; s_DECFunction[index].chCode != '\0'; index++) + { + if (*pCurrent == s_DECFunction[index].chCode) + { + (this->*s_DECFunction[index].pfnProcess)(); + m_State = DS_Normal; + break; + } + } + + if (m_State != DS_Normal) + { + AddOutputData(L'^'); + AddOutputData(L'['); + AddOutputData(L'#'); + AddOutputData(*pCurrent); + } + break; + + case DS_SelectG0: + ProcessSCSG0(*pCurrent); + m_State = DS_Normal; + break; + + case DS_SelectG1: + ProcessSCSG1(*pCurrent); + m_State = DS_Normal; + break; + + default: + dbglog("ProcessOutput: illegal m_State=%d\n",m_State); + assert(false); + break; + } + } + } + + OutputText(); + + return true; +} + +void +CAnsiTerm::DisplayCSI(char ch) +{ + char szParam[15]; + + AddOutputData(L'^'); + AddOutputData(L'['); + AddOutputData(L'['); + for (int idxParam = 0; idxParam < m_ParameterCount; idxParam++) + { + if (idxParam > 0) + { + AddOutputData(L';'); + } + + int iLenParam = sprintf(szParam, "%d", m_Parameters[idxParam]); + + for (int idxChar = 0; idxChar < iLenParam; idxChar++) + { + AddOutputData(szParam[idxChar]); + } + } + AddOutputData(ch); +} + +bool +CAnsiTerm::ResetTerm(void) +{ + m_State = DS_Normal; + + m_SelectedCharset = CharsetG0; + m_G0Charset = AsciiCharset; + m_G1Charset = SpecialGraphicsCharset; + + m_Cursor.X = 0; + m_Cursor.Y = 0; + + m_SavedCursor = m_Cursor; + + m_sTopMargin = 0; + m_sBottomMargin = m_WindowSize.Y - 1; + + m_Attribute = kDefaultAttribute; + + UpdateTextAttribute(); + + m_dwOutputCount = 0; + + // if (fCRLF == 1) + m_bLineFeedNewLineMode = true; /*was false*/ + m_bCursorKeyMode = false; + m_bAnsiMode = true; + m_bColumnMode = true; + m_bScrollingMode = false; + m_bScreenMode = false; + m_bOriginMode = false; + m_bAutoRepeatingMode = true; + m_bInterlaceMode = false; + m_bDisplayCursor = true; + m_bAutoWrapMode = true; /*default to wrap*/ + + EraseDisplay(EraseAll); + + SetCursorPosition(); + + DisplayCursor(); + + return true; +} + +bool +CAnsiTerm::DisplayCursor(void) +{ + CONSOLE_CURSOR_INFO cursorInfo = { 100, m_bDisplayCursor }; + + return SetConsoleCursorInfo(m_hConsole, &cursorInfo) != FALSE; +} + +bool +CAnsiTerm::UpdateTextAttribute(void) +{ + return SetConsoleTextAttribute(m_hConsole, m_Attribute) != FALSE; +} + +bool +CAnsiTerm::GetCursorPosition(void) +{ + CONSOLE_SCREEN_BUFFER_INFO bufferInfo; + + if (GetConsoleScreenBufferInfo(m_hConsole, &bufferInfo)) + { + m_Cursor = bufferInfo.dwCursorPosition; + m_Cursor.Y -= m_WindowOrigin.Y + (m_bOriginMode ? m_sTopMargin : 0); + + return true; + } + + return false; +} + +bool +CAnsiTerm::SetCursorPosition(void) +{ + COORD cursor = m_Cursor; + + cursor.Y += m_WindowOrigin.Y + (m_bOriginMode ? m_sTopMargin : 0); + + return SetConsoleCursorPosition(m_hConsole, cursor) != FALSE; +} + +bool +CAnsiTerm::ScrollDisplay(int n, bool bWindowOnly) +{ + SHORT nLines = (SHORT)n; + if (nLines == 0) + { + return true; + } + + SMALL_RECT rectSource = { 0, 0, m_BufferSize.X - 1, m_BufferSize.Y - 1 }; + COORD coordDest = { 0, 0 }; + CHAR_INFO charInfo = { ' ', m_Attribute }; + + if (nLines > 0) + { + if (bWindowOnly || m_sTopMargin > 0) + { + coordDest.Y = m_WindowOrigin.Y + m_sTopMargin; + rectSource.Top = m_WindowOrigin.Y + m_sTopMargin + nLines; + rectSource.Bottom = m_WindowOrigin.Y + m_sBottomMargin; + } + else + { + rectSource.Top = nLines; + rectSource.Bottom = m_WindowOrigin.Y + m_sBottomMargin; + } + } + else + { + if (bWindowOnly) + { + coordDest.Y = m_WindowOrigin.Y + m_sTopMargin - nLines; + rectSource.Top = m_WindowOrigin.Y + m_sTopMargin; + rectSource.Bottom = m_WindowOrigin.Y + m_sBottomMargin + 1 + nLines; + } + else + { + coordDest.Y -= nLines; + } + + rectSource.Bottom += nLines; + } + + return ScrollConsoleScreenBuffer(m_hConsole, &rectSource, NULL, coordDest, &charInfo) != FALSE; +} + +bool +CAnsiTerm::EraseLine(EraseType eType) +{ + DWORD dwLength; + + COORD coordStart = m_WindowOrigin; + + coordStart.Y += m_Cursor.Y + (m_bOriginMode ? m_sTopMargin : 0); + + switch (eType) + { + case EraseCursorToEnd: + if (m_Cursor.X < m_WindowSize.X) + { + coordStart.X += m_Cursor.X; + dwLength = m_BufferSize.X - m_Cursor.X; + } + else + { + dwLength = 0; + } + break; + + case EraseBeginningToCursor: + if (m_Cursor.X < m_WindowSize.X) + { + dwLength = m_Cursor.X + 1; + } + else + { + dwLength = m_BufferSize.X; + } + break; + + case EraseAll: + dwLength = m_BufferSize.X; + break; + + default: + return false; + } + + if (dwLength > 0) + { + DWORD dwWritten; + + FillConsoleOutputAttribute(m_hConsole, m_Attribute, dwLength, coordStart, &dwWritten); + return FillConsoleOutputCharacter(m_hConsole, ' ', dwLength, coordStart, &dwWritten) != FALSE; + } + else + { + return true; + } +} + +bool +CAnsiTerm::EraseDisplay(EraseType eType) +{ + COORD coordStart = m_WindowOrigin; + DWORD dwLength; + + switch (eType) + { + case EraseCursorToEnd: + if (m_Cursor.X < m_WindowSize.X) + { + coordStart.X += m_Cursor.X; + coordStart.Y += m_Cursor.Y + (m_bOriginMode ? m_sTopMargin : 0); + dwLength = (m_WindowSize.Y - m_Cursor.Y - (m_bOriginMode ? m_sTopMargin : 0)) * m_BufferSize.X - m_Cursor.X; + } + else if (m_Cursor.Y < (m_WindowSize.Y - 1)) + { + coordStart.X = 0; + coordStart.Y += m_Cursor.Y + 1; + dwLength = (m_WindowSize.Y - m_Cursor.Y - (m_bOriginMode ? m_sTopMargin : 0) - 1) * m_BufferSize.X; + } + else + { + dwLength = 0; + } + break; + + case EraseBeginningToCursor: + if (m_Cursor.X < m_WindowSize.X) + { + dwLength = (m_Cursor.Y + (m_bOriginMode ? m_sTopMargin : 0)) * m_BufferSize.X + m_Cursor.X; + } + else + { + dwLength = (m_Cursor.Y + (m_bOriginMode ? m_sTopMargin : 0) + 1) * m_BufferSize.X; + } + break; + + case EraseAll: + dwLength = m_BufferSize.X * m_WindowSize.Y; + break; + + default: + return false; + } + + if (dwLength > 0) + { + DWORD dwWritten; + + FillConsoleOutputAttribute(m_hConsole, m_Attribute, dwLength, coordStart, &dwWritten); + return FillConsoleOutputCharacter(m_hConsole, ' ', dwLength, coordStart, &dwWritten) != FALSE; + } + else + { + return true; + } +} + +DWORD +CAnsiTerm::OutputText(void) +{ + if (m_dwOutputCount == 0) + { + return 0; + } + + DWORD dwTotalWritten = 0; + wchar_t * pwszCurrent = m_OutputBuffer; + DWORD dwLeftToWrite = m_dwOutputCount; + + while (dwLeftToWrite > 0) + { + DWORD dwWritten; + + if (m_Cursor.X >= m_WindowSize.X) + { + if (m_bAutoWrapMode) + { + ProcessLinefeed(true); + } + else + { + m_Cursor.X = m_WindowSize.X - 1; + + SetCursorPosition(); + + if (WriteConsoleW(m_hConsole, &m_OutputBuffer[m_dwOutputCount - 1], 1, &dwWritten, NULL)) + { + assert(dwWritten == 1); + } + + m_Cursor.X++; + dwTotalWritten += dwLeftToWrite; + break; + } + } + + DWORD dwPartialCount = min(dwLeftToWrite, (DWORD)(m_WindowSize.X - m_Cursor.X)); + + if (WriteConsoleW(m_hConsole, pwszCurrent, dwPartialCount, &dwWritten, NULL)) + { + assert(dwWritten == dwPartialCount); + } + else + { + DWORD dwError = GetLastError(); + } + + m_Cursor.X += (SHORT)dwPartialCount; + pwszCurrent += dwPartialCount; + dwTotalWritten += dwPartialCount; + dwLeftToWrite -= dwPartialCount; + } + + m_dwOutputCount = 0; + + return dwTotalWritten; +} + +bool +CAnsiTerm::ProcessBackspace(void) +{ + if (m_Cursor.X > 0) + { + if (m_Cursor.X < m_WindowSize.X) + { + m_Cursor.X--; + } + else + { + m_Cursor.X = m_WindowSize.X - 1; + } + + return SetCursorPosition(); + } + return true; +} + +bool +CAnsiTerm::ProcessTab(void) +{ + if (m_Cursor.X >= m_WindowSize.X) + { + if (m_bAutoWrapMode) + { + ProcessLinefeed(true); + } + else + { + return true; + } + } + + int newX = m_Cursor.X + 8; + + newX &= ~7; + + if (newX >= m_WindowSize.X) + { + newX = m_WindowSize.X - 1; + } + + int cntSpaces = newX - m_Cursor.X; + + for (int index = 0; index < cntSpaces; index++) + { + AddOutputData(L' '); + } + + return true; +} + +bool +CAnsiTerm::ProcessReverseLinefeed(void) +{ + if (m_Cursor.Y == 0) + { + ScrollDisplay(-1, true); + } + else + { + m_Cursor.Y--; + } + + return SetCursorPosition(); +} + +bool +CAnsiTerm::ProcessLinefeed(bool bNewLine) +{ + if (bNewLine) + { + m_Cursor.X = 0; + } + + if (m_bOriginMode || (m_Cursor.Y >= m_sTopMargin && m_Cursor.Y <= m_sBottomMargin)) + { + if (m_Cursor.Y >= (m_sBottomMargin - m_sTopMargin)) + { + ScrollDisplay(1, false); + m_Cursor.Y = m_sBottomMargin; + } + else + { + m_Cursor.Y++; + } + } + else if (m_Cursor.Y < m_sBottomMargin) + { + m_Cursor.Y++; + } + + return SetCursorPosition(); +} + +bool +CAnsiTerm::ProcessReturn(void) +{ + m_Cursor.X = 0; + + return SetCursorPosition(); +} + +bool +CAnsiTerm::ProcessDECALN(void) +{ + // Fill the display with 'E' for adjusting the CRT on a VT100 - Ignore it + return true; +} + +bool +CAnsiTerm::ProcessDECDHLB(void) +{ + // Double Height Line Bottom - Not supported + return true; +} + +bool +CAnsiTerm::ProcessDECDHLT(void) +{ + // Double Height Line Top - Not supported + return true; +} + +bool +CAnsiTerm::ProcessDECDWL(void) +{ + // Double Width Line - Not supported + return true; +} + +bool +CAnsiTerm::ProcessDECID(void) +{ + return ProcessDA(); +} + +bool +CAnsiTerm::ProcessDECKPAM(void) +{ + // Keypad Application Mode - Not yet implemented + return true; +} + +bool +CAnsiTerm::ProcessDECKPNM(void) +{ + // Keypad Numeric Mode - Not yet implemented + return true; +} + +bool +CAnsiTerm::ProcessDECLL(void) +{ + // Load LEDs - Not Supported + return true; +} + +bool +CAnsiTerm::ProcessDECRC(void) +{ + return ProcessRCP(); +} + +bool +CAnsiTerm::ProcessDECREQTPARM(void) +{ + // Request Terminal Parameters (Baud Rate, Parity, etc) - Not supported + return true; +} + +bool +CAnsiTerm::ProcessDECSC(void) +{ + return ProcessSCP(); +} + +bool +CAnsiTerm::ProcessDECSTBM(void) +{ + assert(m_ParameterCount >= 1); + + if (m_Parameters[0] > 0) + { + m_Parameters[0]--; + } + + if (m_ParameterCount < 2) + { + m_Parameters[1] = m_WindowSize.Y - 1; + } + else + { + if (m_Parameters[1] > 0) + { + m_Parameters[1]--; + } + else + { + m_Parameters[1] = m_WindowSize.Y - 1; + } + } + + if (m_Parameters[0] >= m_WindowSize.Y || + m_Parameters[1] >= m_WindowSize.Y || + m_Parameters[0] >= m_Parameters[1]) + { + return false; + } + + m_sTopMargin = (SHORT)m_Parameters[0]; + m_sBottomMargin = (SHORT)m_Parameters[1]; + + m_Cursor.X = 0; + m_Cursor.Y = 0; + + SetCursorPosition(); + + return true; +} + +bool +CAnsiTerm::ProcessDECSWL(void) +{ + // Single Width Line - Since Double Width Line isn't supported, this isn't necessary + return true; +} + +bool +CAnsiTerm::ProcessDECTST(void) +{ + // Perform Self Test - Not supported + return true; +} + +bool +CAnsiTerm::ProcessCUB(void) +{ + if (m_Parameters[0] == 0) + { + m_Parameters[0]++; + } + + m_Cursor.X -= min(m_Cursor.X, m_Parameters[0]); + + return SetCursorPosition(); +} + +bool +CAnsiTerm::ProcessCUD(void) +{ + if (m_Parameters[0] == 0) + { + m_Parameters[0]++; + } + + m_Cursor.Y += min((m_bOriginMode ? m_sBottomMargin : m_WindowSize.Y - 1) - m_Cursor.Y, m_Parameters[0]); + + return SetCursorPosition(); +} + +bool +CAnsiTerm::ProcessCUF(void) +{ + if (m_Parameters[0] == 0) + { + m_Parameters[0]++; + } + + m_Cursor.X += min(m_WindowSize.X - m_Cursor.X - 1, m_Parameters[0]); + + return SetCursorPosition(); +} + +bool +CAnsiTerm::ProcessCUP(void) +{ + return ProcessHVP(); +} + +bool +CAnsiTerm::ProcessCUU(void) +{ + if (m_Parameters[0] == 0) + { + m_Parameters[0]++; + } + + m_Cursor.Y -= min(m_Cursor.Y, m_Parameters[0]); + + return SetCursorPosition(); +} + +bool +CAnsiTerm::ProcessDA(void) +{ + // Send Device Attributes - Not supported + return true; +} + +bool +CAnsiTerm::ProcessDSR(void) +{ + // Send Device Status Request - Not supported + return true; +} + +bool +CAnsiTerm::ProcessED(void) +{ + return EraseDisplay((EraseType)m_Parameters[0]); +} + +bool +CAnsiTerm::ProcessEL(void) +{ + return EraseLine((EraseType)m_Parameters[0]); +} + +bool +CAnsiTerm::ProcessHTS(void) +{ + // Soft Tab Set - Not implemented yet + return true; +} + +bool +CAnsiTerm::ProcessHVP(void) +{ + assert(m_ParameterCount >= 1); + + if (m_Parameters[0] > 0) + { + m_Parameters[0]--; + } + + if (m_ParameterCount < 2) + { + m_Parameters[1] = 0; + } + else + { + if (m_Parameters[1] > 0) + { + m_Parameters[1]--; + } + } + + if (m_bOriginMode) + { + if (m_Parameters[0] >= (m_sBottomMargin - m_sTopMargin + 1)) + { + m_Parameters[0] = m_sBottomMargin - m_sTopMargin; + } + } + else + { + if (m_Parameters[0] >= m_WindowSize.Y) + { + m_Parameters[0] = m_WindowSize.Y - 1; + } + } + + if (m_Parameters[1] >= m_WindowSize.X) + { + m_Parameters[1] = m_WindowSize.X - 1; + } + + m_Cursor.Y = (SHORT)m_Parameters[0]; + m_Cursor.X = (SHORT)m_Parameters[1]; + + return SetCursorPosition(); +} + +bool +CAnsiTerm::ProcessIND(void) +{ + return ProcessLinefeed(false); +} + +bool +CAnsiTerm::ProcessNEL(void) +{ + return ProcessLinefeed(true); +} + +bool +CAnsiTerm::ProcessRCP(void) +{ + m_Cursor = m_SavedCursor; + + return SetCursorPosition(); +} + +bool +CAnsiTerm::ProcessRI(void) +{ + return ProcessReverseLinefeed(); +} + +bool +CAnsiTerm::ProcessRIS(void) +{ + return ResetTerm(); +} + +bool +CAnsiTerm::ProcessRM(void) +{ + if (m_bPrivateParameters) + { + for (int index = 0; index < m_ParameterCount; index++) + { + switch (m_Parameters[index]) + { + case 0: + default: + assert(false); + break; + case DECCKM: + m_bCursorKeyMode = false; + break; + case DECANM: + m_bAnsiMode = false; + break; + case DECCOLM: + m_bColumnMode = false; + break; + case DECSCLM: + m_bScrollingMode = false; + break; + case DECSCNM: + m_bScreenMode = false; + break; + case DECOM: + m_bOriginMode = false; + m_Cursor.X = 0; + m_Cursor.Y = 0; + SetCursorPosition(); + break; + case DECAWM: + m_bAutoWrapMode = false; + break; + case DECARM: + m_bAutoRepeatingMode = false; + break; + case DECINLM: + m_bInterlaceMode = false; + break; + case DECTCEM: + m_bDisplayCursor = false; + DisplayCursor(); + break; + } + } + } + else + { + for (int index = 0; index < m_ParameterCount; index++) + { + switch (m_Parameters[index]) + { + case 20: m_bLineFeedNewLineMode = false; break; // LNM + default: assert(false); break; + } + } + } + return true; +} + +bool +CAnsiTerm::ProcessSCP(void) +{ + m_SavedCursor = m_Cursor; + return true; +} + +bool +CAnsiTerm::ProcessSCSG0(char ch) +{ + switch (ch) + { + case 'B': // ASCII Charset + m_G0Charset = AsciiCharset; + break; + + case '0': // Special Graphics Charset + m_G0Charset = SpecialGraphicsCharset; + break; + + case 'A': // UK Charset + case '1': // Alternate Character ROM Standard Charset + case '2': // Alternate Character ROM Special Graphics Charset + default: // Unsupported + return false; + + } + return true; +} + +bool +CAnsiTerm::ProcessSCSG1(char ch) +{ + switch (ch) + { + case 'B': // ASCII Charset + m_G1Charset = AsciiCharset; + break; + + case '0': // Special Graphics Charset + m_G1Charset = SpecialGraphicsCharset; + break; + + case 'A': // UK Charset + case '1': // Alternate Character ROM Standard Charset + case '2': // Alternate Character ROM Special Graphics Charset + default: // Unsupported + return false; + + } + return true; +} + +bool +CAnsiTerm::ProcessSGR(void) +{ + for (int index = 0; index < m_ParameterCount; index++) + { + switch (m_Parameters[index]) + { + case 0: + m_Attribute = kDefaultAttribute; + break; + + case 1: + m_Attribute |= FOREGROUND_INTENSITY; + break; + + case 4: + m_Attribute |= COMMON_LVB_UNDERSCORE; + break; + + case 5: + // Blinking isn't supported + break; + + case 7: + m_Attribute |= COMMON_LVB_REVERSE_VIDEO; + break; + + case 22: + m_Attribute &= ~FOREGROUND_INTENSITY; + break; + + case 24: + m_Attribute &= ~COMMON_LVB_UNDERSCORE; + break; + + case 25: + // Blinking isn't supported + break; + + case 27: + m_Attribute &= ~COMMON_LVB_REVERSE_VIDEO; + break; + + case 30: // Black text + m_Attribute &= ~(FOREGROUND_INTENSITY | COMMON_LVB_UNDERSCORE | + FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); + break; + + case 31: // Red text + m_Attribute &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); + m_Attribute |= FOREGROUND_RED; + break; + + case 32: // Green text + m_Attribute &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); + m_Attribute |= FOREGROUND_GREEN; + break; + + case 33: // Yellow text + m_Attribute &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); + m_Attribute |= FOREGROUND_RED | FOREGROUND_GREEN; + break; + + case 34: // Blue text + m_Attribute &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); + m_Attribute |= FOREGROUND_BLUE; + break; + + case 35: // Magenta text + m_Attribute &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); + m_Attribute |= FOREGROUND_RED | FOREGROUND_BLUE; + break; + + case 36: // Cyan text + m_Attribute &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); + m_Attribute |= FOREGROUND_GREEN | FOREGROUND_BLUE; + break; + + case 37: // White text + m_Attribute |= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; + break; + + case 40: // Black background + m_Attribute &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE); + break; + + case 41: // Red background + m_Attribute &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE); + m_Attribute |= BACKGROUND_RED; + break; + + case 42: // Green background + m_Attribute &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE); + m_Attribute |= BACKGROUND_GREEN; + break; + + case 43: // Yellow background + m_Attribute &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE); + m_Attribute |= BACKGROUND_RED | BACKGROUND_GREEN; + break; + + case 44: // Blue background + m_Attribute &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE); + m_Attribute |= BACKGROUND_BLUE; + break; + + case 45: // Magenta background + m_Attribute &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE); + m_Attribute |= BACKGROUND_RED | BACKGROUND_BLUE; + break; + + case 46: // Cyan background + m_Attribute &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE); + m_Attribute |= BACKGROUND_GREEN | BACKGROUND_BLUE; + break; + + case 47: // White background + m_Attribute |= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE; + break; + + default: + assert(false); + break; + } + } + + UpdateTextAttribute(); + + return true; +} + +bool +CAnsiTerm::ProcessSM(void) +{ + + dbglog("ProcessSM: start, priv=%d param0=%d cnt=%d\n", + m_bPrivateParameters,m_Parameters[0],m_ParameterCount); + if (m_bPrivateParameters) + { + for (int index = 0; index < m_ParameterCount; index++) + { + switch (m_Parameters[0]) + { + case 0: + default: + assert(false); + break; + case DECCKM: + m_bCursorKeyMode = true; + break; + case DECANM: + m_bAnsiMode = true; + break; + case DECCOLM: + m_bColumnMode = true; + break; + case DECSCLM: + m_bScrollingMode = true; + break; + case DECSCNM: + m_bScreenMode = true; + break; + case DECOM: + m_bOriginMode = true; + m_Cursor.X = 0; + m_Cursor.Y = 0; + m_SavedCursor = m_Cursor; + SetCursorPosition(); + break; + case DECAWM: + m_bAutoWrapMode = true; + break; + case DECARM: + m_bAutoRepeatingMode = true; + break; + case DECINLM: + m_bInterlaceMode = true; + break; + case DECTCEM: + m_bDisplayCursor = true; + DisplayCursor(); + break; + } + } + } + else + { + for (int index = 0; index < m_ParameterCount; index++) + { + switch (m_Parameters[0]) + { + case 20: m_bLineFeedNewLineMode = true; break; // LNM + default: + dbglog("ProcessSM: param %d != 20\n",m_Parameters[0]); + assert(false); break; + } + } + } + return true; +} + +bool +CAnsiTerm::ProcessTBC(void) +{ + // Soft Tab Clear - Not implemented yet + return true; +} + +static CAnsiTerm *g_pDisplay; + +typedef unsigned char uchar; + +extern "C" +{ + +void console_open(char fdebugcmd) +{ + g_pDisplay = new CAnsiTerm(); +} + +void console_close(void) +{ + delete g_pDisplay; + g_pDisplay = NULL; +} + +int console_in(DWORD keydata, uchar *pdata, int len) +{ + if (keydata == ~0) + { + g_pDisplay->WindowSizeChanged(false); + return 0; + } + + return g_pDisplay->ProcessInput(*(CAnsiTerm::KeyCode *)&keydata, pdata, len); +} + +void console_out(uchar *pdata, int len) +{ + if (len > 0) + { + g_pDisplay->ProcessOutput(pdata, len); + } +} + +} diff --git a/util/AnsiTerm.h b/util/AnsiTerm.h new file mode 100644 index 0000000..13d10f2 --- /dev/null +++ b/util/AnsiTerm.h @@ -0,0 +1,316 @@ +/* + * AnsiTerm.h + * Windows ANSI Terminal Emulation + * + * Author: Robert Nelson robertnelson at users.sourceforge.net + * Copyright (c) 2009 Robert Nelson + * + * 10/07/09 Robert Nelson - Created + * See ChangeLog for further changes + */ + +/* +Copyright (c) 2009, Robert Nelson +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions 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. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#pragma once + +class CAnsiTerm +{ +public: + struct KeyCode + { + unsigned char bKeyDown:1; + unsigned char bEnhanced:1; + unsigned char bCapsLock:1; + unsigned char bScrollLock:1; + unsigned char bNumLock:1; + unsigned char bShift:1; + unsigned char bControl:1; + unsigned char bAlt:1; + unsigned char RepeatCount; + unsigned char VirtualKeyCode; + unsigned char AsciiChar; + }; + +private: + enum ControlCharacters + { + CH_NUL = 0x00, // Ignored on input + CH_ENQ = 0x05, // Transmit answerback + CH_BEL = 0x07, // Ring Bell + CH_BS = 0x08, // Move left one character, no effect in column 0 + CH_HT = 0x09, // Tab + CH_LF = 0x0A, // Line feed or new line depending on line mode + CH_VT = 0x0B, // Vertical tab, same as line feed + CH_FF = 0x0C, // Form feed, same as line feed + CH_CR = 0x0D, // Carriage return, return to column 0 + CH_SO = 0x0E, // Shift Out, Invoke G1 charset + CH_SI = 0x0F, // Shift In, Invoke G0 charset + CH_XON = 0x11, // Resume transmission + CH_XOF = 0x13, // Suspend transmission + CH_CAN = 0x18, // Cancel, aborts the current control sequence + CH_SUB = 0x1A, // Same as Cancel + CH_ESC = 0x1B, // Escape, start of control sequence + CH_DEL = 0x7F // Delete, ignored + }; + + enum DECModes + { + DECCKM = 1, // Cursor Key Mode (set = application codes) + DECANM = 2, // Ansi Mode (set = ansi) + DECCOLM = 3, // 80/132 Column Mode (set = 132) + DECSCLM = 4, // Scroll Mode (set = smooth) + DECSCNM = 5, // Screen Mode (set = black on white) + DECOM = 6, // Origin Mode (set = origin relative to top margin) + DECAWM = 7, // Autowrap Mode (set = wrap) + DECARM = 8, // Autorepeat Mode (set = repeat) + DECINLM = 9, // Interlace Mode (set = interlace) + DECTCEM = 25 // Text Cursor Enable Mode + + }; + + enum DisplayState + { + DS_None, + DS_Normal, + DS_UTF8, + DS_Escape, + DS_CSIParam, + DS_DECPrivate, + DS_SelectG0, + DS_SelectG1 + }; + + enum SelectedCharset + { + CharsetG0, + CharsetG1 + }; + + enum CharacterSet + { + AsciiCharset = 0, + SpecialGraphicsCharset = 1, + UKCharset = 2 + }; + + enum EraseType + { + EraseCursorToEnd = 0, + EraseBeginningToCursor = 1, + EraseAll = 2 + }; + + static const int kMaxParameterCount = 16; + + static const int kOutputBufferSize = 256; + + static const int kMinGraphicsChar = 0x5F; + static const int kMaxGraphicsChar = 0x7E; + + static const int kColorTableSize = 16; + + static const WORD kDefaultAttribute = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; + + struct CSICode + { + char chCode; + DisplayState dsNextState; + bool (CAnsiTerm::*pfnProcess)(void); + }; + + struct CSIFunction + { + char chCode; + bool (CAnsiTerm::*pfnProcess)(void); + }; + +protected: + typedef struct _CONSOLE_SCREEN_BUFFER_INFOEX { + ULONG cbSize; + COORD dwSize; + COORD dwCursorPosition; + WORD wAttributes; + SMALL_RECT srWindow; + COORD dwMaximumWindowSize; + WORD wPopupAttributes; + BOOL bFullscreenSupported; + COLORREF ColorTable[16]; + } CONSOLE_SCREEN_BUFFER_INFOEX, *PCONSOLE_SCREEN_BUFFER_INFOEX; + + typedef BOOL (WINAPI *PFN_GetConsoleScreenBufferInfoEx)( + HANDLE hConsoleOutput, + PCONSOLE_SCREEN_BUFFER_INFOEX lpConsoleScreenBufferInfoEx); + + typedef BOOL (WINAPI *PFN_SetConsoleScreenBufferInfoEx)( + HANDLE hConsoleOutput, + PCONSOLE_SCREEN_BUFFER_INFOEX lpConsoleScreenBufferInfoEx); + + static PFN_GetConsoleScreenBufferInfoEx s_pfnGetConsoleScreenBufferInfoEx; + static PFN_SetConsoleScreenBufferInfoEx s_pfnSetConsoleScreenBufferInfoEx; + +private: + static CSICode s_CSITable[]; + static CSIFunction s_DECFunction[]; + static CSIFunction s_CSIFunction[]; + static wchar_t s_GraphicChars[kMaxGraphicsChar - kMinGraphicsChar + 1]; + static wchar_t s_OemToUnicode[256]; + static COLORREF s_ColorTable[kColorTableSize]; + + +public: + CAnsiTerm(void); + virtual ~CAnsiTerm(void); + + void WindowSizeChanged(bool bInitial); + + int ProcessInput(KeyCode keyCode, unsigned char *pOutput, int iOutputLen); + + bool ProcessOutput(const unsigned char *szData, int iLength); + +protected: + virtual bool ResetTerm(void); + virtual bool GetCursorPosition(void); + virtual bool SetCursorPosition(void); + virtual bool DisplayCursor(void); + + virtual bool ScrollDisplay(int nLines, bool bWindowOnly); + virtual bool EraseLine(EraseType eType); + virtual bool EraseDisplay(EraseType eType); + virtual bool UpdateTextAttribute(void); + + virtual DWORD OutputText(void); + +private: + bool ProcessBackspace(void); + bool ProcessTab(void); + bool ProcessLinefeed(bool bNewLine); + bool ProcessReverseLinefeed(void); + bool ProcessReturn(void); + + void AddOutputData(wchar_t wchData) + { + m_OutputBuffer[m_dwOutputCount++] = wchData; + + if (m_dwOutputCount >= kOutputBufferSize) + { + OutputText(); + } + } + + void DisplayCSI(char ch); + + bool ProcessSCSG0(char ch); + bool ProcessSCSG1(char ch); + + bool ProcessDECALN(void); + bool ProcessDECDHLB(void); + bool ProcessDECDHLT(void); + bool ProcessDECDWL(void); + bool ProcessDECID(void); + bool ProcessDECKPAM(void); + bool ProcessDECKPNM(void); + bool ProcessDECLL(void); + bool ProcessDECRC(void); + bool ProcessDECREQTPARM(void); + bool ProcessDECSC(void); + bool ProcessDECSTBM(void); + bool ProcessDECSWL(void); + bool ProcessDECTST(void); + + bool ProcessCUB(void); + bool ProcessCUD(void); + bool ProcessCUF(void); + bool ProcessCUP(void); + bool ProcessCUU(void); + bool ProcessDA(void); + bool ProcessDSR(void); + bool ProcessED(void); + bool ProcessEL(void); + bool ProcessHTS(void); + bool ProcessHVP(void); + bool ProcessIND(void); + bool ProcessNEL(void); + bool ProcessRCP(void); + bool ProcessRI(void); + bool ProcessRIS(void); + bool ProcessRM(void); + bool ProcessSCP(void); + bool ProcessSGR(void); + bool ProcessSM(void); + bool ProcessTBC(void); + +private: + HANDLE m_hConsole; + DWORD m_dwOrigConsoleMode; + WORD m_wOrigConsoleAttribute; + DWORD m_dwOrigCursorSize; + COLORREF m_OrigColorTable[kColorTableSize]; + bool m_bResetColorTable; + DisplayState m_State; + + SelectedCharset m_SelectedCharset; + CharacterSet m_G0Charset; + CharacterSet m_G1Charset; + + COORD m_BufferSize; + COORD m_WindowSize; + COORD m_WindowOrigin; + COORD m_Cursor; + COORD m_SavedCursor; + SHORT m_sTopMargin; + SHORT m_sBottomMargin; + WORD m_Attribute; + wchar_t m_OutputBuffer[kOutputBufferSize]; + DWORD m_dwOutputCount; + + unsigned char m_UTF8Buffer[3]; + int m_UTF8Count; + int m_UTF8Size; + + int m_Parameters[kMaxParameterCount]; + int m_ParameterCount; + bool m_bParametersStart; + bool m_bPrivateParameters; + + // Modes + bool m_bLineFeedNewLineMode; // LNM + bool m_bCursorKeyMode; // DECCKM +// Always set - VT52 not supported + bool m_bAnsiMode; // DECANM +// Not used - column width is based on width of console window + bool m_bColumnMode; // DECCOLM +// Not used - always reset + bool m_bScrollingMode; // DECSCLM +// Not implemented - always reset + bool m_bScreenMode; // DECSCNM + bool m_bOriginMode; // DECOM + bool m_bAutoWrapMode; // DECAWM +// Not implemented - always set + bool m_bAutoRepeatingMode; // DECARM +// Not implemented - always reset + bool m_bInterlaceMode; // DECINLM + bool m_bDisplayCursor; // DECTCEM +}; diff --git a/util/Makefile.am b/util/Makefile.am new file mode 100644 index 0000000..3726107 --- /dev/null +++ b/util/Makefile.am @@ -0,0 +1,200 @@ + +localedir = $(datadir)/locale +INCLUDES = -I.. +OS_CF = @OS_CFLAGS@ @CROSS_CFLAGS@ +OS_LF = @OS_LFLAGS@ @CROSS_LFLAGS@ +AM_CPPFLAGS = $(OS_CF) -DLOCALEDIR=\"$(localedir)\" +AM_CPPFLAGS += @IA64_CFLAGS@ @GPL_CFLAGS@ +LDADD = $(OS_LF) +LDSAM = $(OS_LF) @LD_SAMX@ +CFLAGS_SAMX = -O2 -g -I. -I.. $(OS_CF) @LANPLUS_CFLAGS@ +CFLAGS_SAM = -O2 -g -I. -I.. $(OS_CF) +# May be /usr/bin/install or /bin/install +INSTALLBIN = install -c +extradir = $(datadir)/ipmiutil +inc_dir = $(includedir) +tmpobj = obj +tmpwin = tmp +LIBDIR = @LIB_DIR@ + +CMDMOD = ipmicmd.c mem_if.c ipmidir.c imbapi.c ipmimv.c ipmild.c ipmibmc.c ipmilipmi.c subs.c +CMDMOD += md5.c md2.c ipmilan.c +CMDMOD += ipmilanplus.c +# CMDMOD = ipmicmd.c mem_if.c @OS_DRIVERS@ +# am: configure substitutions are not allowed in _SOURCES variables +LIBOBJ = ipmicmd.o mem_if.o ipmidir.o imbapi.o ipmimv.o ipmild.o ipmibmc.o ipmilipmi.o subs.o md5.o md2.o $(tmpobj)/ipmilan.o $(tmpobj)/ipmilanplus.o +OEMMOD = oem_kontron.c oem_fujitsu.c oem_intel.c oem_sun.c oem_supermicro.c oem_dell.c oem_quanta.c oem_hp.c oem_newisys.c iekanalyzer.c + + +AM_CPPFLAGS += -I. -I.. -DMETACOMMAND +METASOURCE = ipmiutil.c ialarms.c ihealth.c ievents.c ifru.c ifru_picmg.c igetevent.c ireset.c icmd.c ilan.c isensor.c isel.c iserial.c iwdt.c isol.c idiscover.c iconfig.c ipicmg.c ifirewall.c ifwum.c ihpm.c itsol.c idcmi.c $(OEMMOD) $(CMDMOD) +LDADD += -lpthread + +# The LanDesk library is proprietary, so it is incompatible with ALLOW_GPL. +# To build with LanDesk support: +# First copy the library to ../lib/libipmiapi.a +# Then ./configure --enable-landesk +# Result: +# AM_CPPFLAGS += -DLINK_LANDESK +# LDADD += -lipmiapi -L../lib +AM_CPPFLAGS += @LANDESK_CFLAGS@ +LDADD += @LANDESK_LDADD@ + +# For lanplus plugin support (IPMI LAN 2.0 RMCP+) used by SOL: +# If ./configure --disable-lanplus +# AM_CPPFLAGS += +# LDADD += +# Otherwise default result is lanplus enabled: +# AM_CPPFLAGS += -DHAVE_LANPLUS +# LDADD += -L../lib -lipmi_lanplus -L/usr/local/lib -lcrypto +# LDADD += -L../lib -lintf_lanplus -L/usr/local/lib -lcrypto (older) +# Could also use CMDMOD += ipmilan2.c instead, if completed. +AM_CPPFLAGS += @LANPLUS_CFLAGS@ +LDADD += @LANPLUS_LIB@ @LANPLUS_CRYPTO@ +LANPLUS_OBJ = $(shell ar t @LANPLUS_LIB@ 2>/dev/null) + +# sbin_PROGRAMS are built by default and copied to /usr/sbin at install time +# EXTRA_PROGRAMS are built by default but not included in the install package +# TESTPROGS are not built by default. To build, do 'make ifruset', for example. +bin_PROGRAMS = ipmiutil ievents idiscover +sbin_PROGRAMS = ipmi_port iseltime +DEV_LIB = libipmiutil.a +SHR_LIB = libipmiutil.so +SHRLINK = @SHR_LINK@ +EXTRA_PROGRAMS = ipmi_sample ipmi_sample_evt +TESTPROGS = libimbapi.a iconfig ipmimv ifruset ipmi_sample2 ialarms_enc +# OLDPROGS are old/previous binaries that may exist and need to be deleted. +OLDPROGS = alarms bmchealth fruconfig getevent hwreset icmd isolconsole pefconfig sensor showsel tmconfig wdt + +# To build an imb api library (libimbapi.a): +libimbapi.a: imbapi.c + mkdir -p $(tmpobj) + $(CC) -I. -I.. $(OS_CF) -fPIC $(CFLAGS) -o $(tmpobj)/imbapi.o -c imbapi.c + $(AR) cru libimbapi.a $(tmpobj)/imbapi.o + $(RANLIB) libimbapi.a + rm -f $(tmpobj)/imbapi.o + +# Build a lib to support all of the IPMI drivers (libipmiutil.a) +# If LANPLUS_SAM = yes, include LANPLUS_OBJ, else do not. +# See configure --enable-liblanplus to change this +$(DEV_LIB): $(CMDMOD:.c=.o) @LANPLUS_LIB@ + mkdir -p $(tmpobj) + if [ "x@LANPLUS_SAM@" = "xyes" ]; then \ + $(CC) $(CFLAGS_SAMX) -o $(tmpobj)/ipmilanplus.o -c ipmilanplus.c; \ + $(CC) $(CFLAGS_SAMX) -o $(tmpobj)/ipmilan.o -c ipmilan.c; \ + ar x @LANPLUS_LIB@ ; \ + $(AR) cru $(DEV_LIB) $(LIBOBJ) $(LANPLUS_OBJ); \ + $(RANLIB) $(DEV_LIB); \ + else \ + $(CC) $(CFLAGS_SAM) -o $(tmpobj)/ipmilanplus.o -c ipmilanplus.c; \ + $(CC) $(CFLAGS_SAM) -o $(tmpobj)/ipmilan.o -c ipmilan.c; \ + $(AR) cru $(DEV_LIB) $(LIBOBJ) ; \ + $(RANLIB) $(DEV_LIB) ; \ + fi + +$(SHR_LIB): $(CMDMOD:.c=.o) @LANPLUS_LIB@ + mkdir -p $(tmpobj) + if [ "x@LANPLUS_SAM@" = "xyes" ]; then \ + $(CC) $(CFLAGS_SAMX) -o $(tmpobj)/ipmilanplus.o -c ipmilanplus.c; \ + $(CC) $(CFLAGS_SAMX) -o $(tmpobj)/ipmilan.o -c ipmilan.c; \ + ar x @LANPLUS_LIB@ ; \ + $(CC) $(LDFLAGS) -shared -o $(SHR_LIB) $(LIBOBJ) $(LANPLUS_OBJ); \ + else \ + $(CC) $(CFLAGS_SAM) -o $(tmpobj)/ipmilanplus.o -c ipmilanplus.c; \ + $(CC) $(CFLAGS_SAM) -o $(tmpobj)/ipmilan.o -c ipmilan.c; \ + $(CC) $(LDFLAGS) -shared -o $(SHR_LIB) $(LIBOBJ) ; \ + fi + +# To build ipmiutil, need to use METACFLAGS for each .c/.o + +idiscover$(EXEEXT): idiscover.c + $(CC) $(CFLAGS_SAM) $(LDFLAGS) $(OS_LF) -o idiscover idiscover.c + +ipmimv: ipmimv.c + $(CC) $(CFLAGS_SAM) $(LDFLAGS) -DTEST_BIN -o ipmimv ipmimv.c + +ievents$(EXEEXT): ievents.c + $(CC) $(CFLAGS_SAM) $(LDFLAGS) -DALONE -o ievents ievents.c + +ipmi_sample: $(DEV_LIB) ipmi_sample.c isensor.c ievents.c + $(CC) $(CFLAGS_SAM) -c ipmi_sample.c + $(CC) -g -O2 -o ipmi_sample ipmi_sample.o $(DEV_LIB) $(LDFLAGS) $(LDSAM) + +ialarms_enc: $(DEV_LIB) ialarms.c oem_intel.c + $(CC) $(CFLAGS_SAM) -DTEST_ENC -o ialarms2.o -c ialarms.c + $(CC) $(CFLAGS_SAM) -DNO_EVENTS -o oem_intel2.o -c oem_intel.c + $(CC) -g -O2 -o ialarms_enc ialarms2.o oem_intel2.o $(DEV_LIB) $(LDFLAGS) $(LDSAM) + +ifru_picmg2.o: ifru_picmg.c + $(CC) $(CFLAGS_SAM) -o ifru_picmg2.o -c ifru_picmg.c + +# To build ipmi_sample with GET_SENSORS enabled, need isensors.o, ievents.o +# Note that this does not include oem_intel, etc. for OEM SEL decoding. +ipmi_sample2: $(DEV_LIB) ipmi_sample.c isensor.c ievents.c ifru.c isel.c ifru_picmg2.o + $(CC) $(CFLAGS_SAM) -D GET_SENSORS -D GET_FRU -o ipmi_sample2.o -c ipmi_sample.c + $(CC) $(CFLAGS_SAM) -o isensor2.o -c isensor.c + $(CC) $(CFLAGS_SAM) -o ievents2.o -c ievents.c + $(CC) $(CFLAGS_SAM) -o ifru2.o -c ifru.c + $(CC) $(CFLAGS_SAM) -o isel2.o -c isel.c + $(CC) -g -O2 -o ipmi_sample2 ipmi_sample2.o isensor2.o ievents2.o ifru2.o ifru_picmg2.o isel2.o $(DEV_LIB) $(LDFLAGS) $(LDSAM) + +ipmi_sample_evt: $(DEV_LIB) ipmi_sample_evt.c isensor.c ievents.c + $(CC) $(CFLAGS_SAM) -o ipmi_sample_evt.o -c ipmi_sample_evt.c + $(CC) $(CFLAGS_SAM) -o isensor2.o -c isensor.c + $(CC) $(CFLAGS_SAM) -DSENSORS_OK -o ievents2.o -c ievents.c + $(CC) -g -O2 -o ipmi_sample_evt ipmi_sample_evt.o isensor2.o ievents2.o $(DEV_LIB) $(LDFLAGS) $(LDSAM) + +ifruset: $(DEV_LIB) ifruset.c ifru_picmg2.o + $(CC) $(CFLAGS_SAM) -c ifruset.c + $(CC) -g -O2 -o ifruset ifruset.o ifru_picmg2.o $(DEV_LIB) $(LDFLAGS) $(LDADD) + +iseltime: $(DEV_LIB) iseltime.c + $(CC) $(CFLAGS_SAM) -c iseltime.c + $(CC) -g -O2 -o iseltime iseltime.o $(DEV_LIB) $(LDFLAGS) $(LDADD) + +ipmi_port$(EXEEXT): ipmi_port.c + $(CC) $(CFLAGS_SAM) $(LDFLAGS) -o ipmi_port ipmi_port.c + +iconfig: iconfig.c $(DEV_LIB) + $(CC) $(CFLAGS_SAM) $(LDFLAGS) -o iconfig iconfig.c $(DEV_LIB) @LANPLUS_CRYPTO@ + +# @LANPLUS_LIB@ is ../lib/libipmi_lanplus.a +../lib/libipmi_lanplus.a: + cd ../lib; make + +ipmiutil_SOURCES = $(METASOURCE) + +ipmiutil$(EXEEXT): $(METASOURCE:.c=.o) @LANPLUS_LIB@ + $(CC) $(CFLAGS) $(LDFLAGS) -o ipmiutil $(METASOURCE:.c=.o) $(LDADD) + +ievents_SOURCES = ievents.c + +idiscover_SOURCES = idiscover.c + +ipmi_port_SOURCES = ipmi_port.c + + +EXTRA_DIST = imb_api.h ipmicmd.h ipmidir.h ipmilan.h ipmilanplus.h AnsiTerm.h ifirewall.h ifwum.h ihpm.h ipicmg.h ipmiutil.h md2.h oem_dell.h oem_fujitsu.h oem_intel.h oem_kontron.h oem_sun.h idcmi.h isensor.h iekanalyzer.h + +all-am: Makefile $(bin_PROGRAMS) $(sbin_PROGRAMS) $(EXTRA_PROGRAMS) $(DEV_LIB) $(SHRLINK) + +install-data-am: $(EXTRA_PROGRAMS) $(DEV_LIB) $(SHRLINK) + @INS_LIB@ mkdir -p $(DESTDIR)$(extradir) + @INS_LIB@ mkdir -p $(DESTDIR)$(LIBDIR) + @INS_LIB@ mkdir -p $(DESTDIR)$(inc_dir) + @INS_LIB@ cp -f ipmi_sample.c $(DESTDIR)$(extradir) + @INS_LIB@ cp -f ipmi_sample_evt.c $(DESTDIR)$(extradir) + @INS_LIB@ cp -f ipmicmd.h $(DESTDIR)$(inc_dir) + @INS_LIB@ cp -f isensor.c ievents.c $(DESTDIR)$(extradir) + @INS_LIB@ cp -f isensor.h ievents.h $(DESTDIR)$(extradir) + @INS_LIB@ cp -f Makefile.sample $(DESTDIR)$(extradir)/Makefile + @INS_LIB@ cp -f $(DEV_LIB) $(DESTDIR)$(LIBDIR) + if [ "x$(SHRLINK)" != "x" ]; then \ + @INS_LIB@ cp -f $(SHR_LIB) $(DESTDIR)$(LIBDIR) ; \ + fi + +clean-generic: + rm -f $(DEV_LIB) $(EXTRA_PROGRAMS) $(OLDPROGS) $(TESTPROGS) $(SHRLINK) + if [ -d $(tmpobj) ]; then rm -rf $(tmpobj) ; fi + if [ -d $(tmpwin) ]; then rm -rf $(tmpwin) ; fi + rm -f *.log *.tmp debug*.list *.o *.pdb *.lo *.la *.so diff --git a/util/Makefile.am-so b/util/Makefile.am-so new file mode 100644 index 0000000..97d9c34 --- /dev/null +++ b/util/Makefile.am-so @@ -0,0 +1,241 @@ + +localedir = $(datadir)/locale +INCLUDES = -I. -I.. +OS_CF = @OS_CFLAGS@ @CROSS_CFLAGS@ +OS_LF = @OS_LFLAGS@ @CROSS_LFLAGS@ +AM_CPPFLAGS = $(OS_CF) -DLOCALEDIR=\"$(localedir)\" +AM_CPPFLAGS += @IA64_CFLAGS@ @GPL_CFLAGS@ +LDADD = $(OS_LF) +LDSAM = $(OS_LF) @LD_SAMX@ +CFLAGS_SAMX = -O2 -g -I. -I.. $(OS_CF) @LANPLUS_CFLAGS@ +CFLAGS_SAM = -O2 -g -I. -I.. $(OS_CF) +# May be /usr/bin/install or /bin/install +INSTALLBIN = install -c +extradir = $(datadir)/ipmiutil +inc_dir = $(includedir) +tmpobj = obj +tmpwin = tmp +LIBDIR = @LIB_DIR@ + +CMDSRC = ipmicmd.c mem_if.c ipmidir.c imbapi.c ipmimv.c ipmild.c ipmibmc.c ipmilipmi.c subs.c +CMDSRC += md5.c md2.c ipmilan.c +CMDSRC += ipmilanplus.c +# CMDSRC = ipmicmd.c mem_if.c @OS_DRIVERS@ +# am: configure substitutions are not allowed in _SOURCES variables +CMDOBJ = $(tmpobj)/ipmicmd.o $(tmpobj)/mem_if.o $(tmpobj)/ipmidir.o $(tmpobj)/imbapi.o $(tmpobj)/ipmimv.o $(tmpobj)/ipmild.o $(tmpobj)/ipmibmc.o $(tmpobj)/ipmilipmi.o $(tmpobj)/subs.o $(tmpobj)/md5.o $(tmpobj)/md2.o $(tmpobj)/ipmilan.o $(tmpobj)/ipmilanplus.o +LIBOBJ = $(CMDOBJ) +OEMMOD = oem_kontron.c oem_fujitsu.c oem_intel.c oem_sun.c iekanalyzer.c oem_supermicro.c oem_dell.c oem_quanta.c oem_hp.c oem_newisys.c + + +AM_CPPFLAGS += -I. -I.. -DMETACOMMAND +METASOURCE = ipmiutil.c ialarms.c ihealth.c ievents.c ifru.c ifru_picmg.c igetevent.c ireset.c icmd.c ilan.c isensor.c isel.c iserial.c iwdt.c isol.c idiscover.c iconfig.c ipicmg.c ifirewall.c ifwum.c ihpm.c itsol.c idcmi.c $(OEMMOD) +LDADD += -lpthread + +# The LanDesk library is proprietary, so it is incompatible with ALLOW_GPL. +# To build with LanDesk support: +# First copy the library to ../lib/libipmiapi.a +# Then ./configure --enable-landesk +# Result: +# AM_CPPFLAGS += -DLINK_LANDESK +# LDADD += -lipmiapi -L../lib +AM_CPPFLAGS += @LANDESK_CFLAGS@ +LDADD += @LANDESK_LDADD@ + +# For lanplus plugin support (IPMI LAN 2.0 RMCP+) required by SOL: +# If ./configure --disable-lanplus +# AM_CPPFLAGS += +# LDADD += +# LANPLUS_SRC = +# Otherwise default result is lanplus enabled: +# AM_CPPFLAGS += -DHAVE_LANPLUS +# LDADD += -L../lib -lipmi_lanplus -L/usr/local/lib -lcrypto +# LDADD += -L../lib -lintf_lanplus -L/usr/local/lib -lcrypto (older) +# LANPLUS_SRC = $(LANPLUS_DIR)/lanplus.c ... +AM_CPPFLAGS += @LANPLUS_CFLAGS@ -I../lib/lanplus -I../lib/lanplus/inc +LDADD += @LANPLUS_LIB@ @LANPLUS_CRYPTO@ +LANPLUS_OBJ = $(shell ar t @LANPLUS_LIB@ 2>/dev/null) +LANPLUS_DIR = ../lib/lanplus +LANPLUS_SRC = $(LANPLUS_DIR)/lanplus.c $(LANPLUS_DIR)/lanplus_dump.c \ + $(LANPLUS_DIR)/lanplus_strings.c $(LANPLUS_DIR)/lanplus_crypt.c \ + $(LANPLUS_DIR)/lanplus_crypt_impl.c $(LANPLUS_DIR)/helper.c \ + $(LANPLUS_DIR)/ipmi_strings.c + +# sbin_PROGRAMS are built by default and copied to /usr/sbin at install time +# EXTRA_PROGRAMS are built by default but not included in the install package +# TESTPROGS are not built by default. To build, do 'make ifruset', for example. +bin_PROGRAMS = ipmiutil ievents idiscover +sbin_PROGRAMS = ipmi_port +DEV_LIB = libipmiutil.a +EXTRA_PROGRAMS = ipmi_sample ipmi_sample_evt +TESTPROGS = libimbapi.a iconfig ipmimv ifruset ipmi_sample2 ialarms_enc iseltime +# OLDPROGS are old/previous binaries that may exist and need to be deleted. +OLDPROGS = alarms bmchealth fruconfig getevent hwreset icmd isolconsole pefconfig sensor showsel tmconfig wdt + +lib_LTLIBRARIES = libipmiutil.la +libipmiutil_la_SOURCES = $(CMDSRC) $(LANPLUS_SRC) +libipmiutil_la_LDFLAGS = -export-dynamic + +# To build an imb api library (libimbapi.a): +libimbapi.a: imbapi.c + mkdir -p $(tmpobj) + $(CC) -I. -I.. $(OS_CF) -fPIC $(CFLAGS) -o $(tmpobj)/imbapi.o -c imbapi.c + $(AR) cru libimbapi.a $(tmpobj)/imbapi.o + $(RANLIB) libimbapi.a + rm -f $(tmpobj)/imbapi.o + +# Build a lib to support all of the IPMI drivers (libipmiutil.a) +# If LANPLUS_SAM = yes, include LANPLUS_OBJ, else do not. +# See configure --enable-liblanplus to change this +$(DEV_LIB): $(CMDOBJ) @LANPLUS_LIB@ + mkdir -p $(tmpobj) + if [ "x@LANPLUS_SAM@" = "xyes" ]; then \ + $(CC) $(CFLAGS_SAMX) -o $(tmpobj)/ipmilanplus.o -c ipmilanplus.c; \ + $(CC) $(CFLAGS_SAMX) -o $(tmpobj)/ipmilan.o -c ipmilan.c; \ + ar x @LANPLUS_LIB@ ; \ + $(AR) cru $(DEV_LIB) $(LIBOBJ) $(LANPLUS_OBJ); \ + $(RANLIB) $(DEV_LIB); \ + else \ + $(CC) $(CFLAGS_SAM) -o $(tmpobj)/ipmilanplus.o -c ipmilanplus.c; \ + $(CC) $(CFLAGS_SAM) -o $(tmpobj)/ipmilan.o -c ipmilan.c; \ + $(AR) cru $(DEV_LIB) $(LIBOBJ) ; \ + $(RANLIB) $(DEV_LIB) ; \ + fi + rm -f $(tmpobj)/ipmilan.o $(tmpobj)/ipmilanplus.o + +# To build ipmiutil, need to use METACFLAGS for each .c/.o + +idiscover: idiscover.c + $(CC) $(OS_CF) $(CFLAGS) $(LDFLAGS) $(OS_LF) -o idiscover idiscover.c + +ipmimv: ipmimv.c + $(CC) $(OS_CF) $(CFLAGS) $(LDFLAGS) -DTEST_BIN -o ipmimv ipmimv.c + +ievents: ievents.c + $(CC) $(OS_CF)$(CFLAGS) $(LDFLAGS) -DALONE -o ievents ievents.c + +ipmi_sample: $(DEV_LIB) ipmi_sample.c isensor.c ievents.c + $(CC) $(CFLAGS_SAM) -c ipmi_sample.c + $(CC) -g -O2 -o ipmi_sample ipmi_sample.o $(DEV_LIB) $(LDFLAGS) $(LDSAM) + +ialarms_enc: $(DEV_LIB) ialarms.c oem_intel.c + $(CC) $(CFLAGS_SAM) -DTEST_ENC -o ialarms2.o -c ialarms.c + $(CC) $(CFLAGS_SAM) -DNO_EVENTS -o oem_intel2.o -c oem_intel.c + $(CC) -g -O2 -o ialarms_enc ialarms2.o oem_intel2.o $(DEV_LIB) $(LDFLAGS) $(LDSAM) + +ifru_picmg2.o: ifru_picmg.c + $(CC) $(CFLAGS_SAM) -o ifru_picmg2.o -c ifru_picmg.c + +# To build ipmi_sample with GET_SENSORS enabled, need isensors.o, ievents.o +# Note that this does not include oem_intel, etc. for OEM SEL decoding. +ipmi_sample2: $(DEV_LIB) ipmi_sample.c isensor.c ievents.c ifru.c isel.c ifru_picmg2.o + $(CC) $(CFLAGS_SAM) -D GET_SENSORS -D GET_FRU -o ipmi_sample2.o -c ipmi_sample.c + $(CC) $(CFLAGS_SAM) -o isensor2.o -c isensor.c + $(CC) $(CFLAGS_SAM) -o ievents2.o -c ievents.c + $(CC) $(CFLAGS_SAM) -o ifru2.o -c ifru.c + $(CC) $(CFLAGS_SAM) -o isel2.o -c isel.c + $(CC) -g -O2 -o ipmi_sample2 ipmi_sample2.o isensor2.o ievents2.o ifru2.o ifru_picmg2.o isel2.o $(DEV_LIB) $(LDFLAGS) $(LDSAM) + +ipmi_sample_evt: $(DEV_LIB) ipmi_sample_evt.c isensor.c ievents.c + $(CC) $(CFLAGS_SAM) -o ipmi_sample_evt.o -c ipmi_sample_evt.c + $(CC) $(CFLAGS_SAM) -o isensor2.o -c isensor.c + $(CC) $(CFLAGS_SAM) -DSENSORS_OK -o ievents2.o -c ievents.c + $(CC) -g -O2 -o ipmi_sample_evt ipmi_sample_evt.o isensor2.o ievents2.o $(DEV_LIB) $(LDFLAGS) $(LDSAM) + +ifruset: $(DEV_LIB) ifruset.c ifru_picmg2.o + $(CC) $(CFLAGS_SAM) -c ifruset.c + $(CC) -g -O2 -o ifruset ifruset.o ifru_picmg2.o $(DEV_LIB) $(LDFLAGS) $(LDADD) + +iseltime: $(DEV_LIB) iseltime.c + $(CC) $(CFLAGS_SAM) -c iseltime.c + $(CC) -g -O2 -o iseltime iseltime.o $(DEV_LIB) $(LDFLAGS) $(LDADD) + +ipmi_port: ipmi_port.c + $(CC) $(CFLAGS) $(LDFLAGS) -o ipmi_port ipmi_port.c + +#xmlconfig: xmlconfig.c $(DEV_LIB) +# $(CC) $(CFLAGS) $(LDFLAGS) -o xmlconfig xmlconfig.c libipmiutil.a @LANPLUS_CRYPTO@ + +iconfig: iconfig.c $(DEV_LIB) + $(CC) $(CFLAGS) $(LDFLAGS) -o iconfig iconfig.c $(DEV_LIB) @LANPLUS_CRYPTO@ + +# @LANPLUS_LIB@ is ../lib/libipmi_lanplus.a +../lib/libipmi_lanplus.a: + cd ../lib; make + +ipmiutil_SOURCES = $(METASOURCE) + +ipmiutil: $(METASOURCE:.c=.o) $(CMDOBJ) @LANPLUS_LIB@ + $(CC) $(CFLAGS) $(LDFLAGS) -o ipmiutil $(METASOURCE:.c=.o) $(CMDOBJ) $(LDADD) + +$(tmpobj)/ipmicmd.o: ipmicmd.c + mkdir -p $(tmpobj) + @$(CC) $(CFLAGS_SAMX) -o $(tmpobj)/ipmicmd.o -c ipmicmd.c + +$(tmpobj)/subs.o: subs.c + @$(CC) $(CFLAGS_SAMX) -o $(tmpobj)/subs.o -c subs.c + +$(tmpobj)/mem_if.o: mem_if.c + @$(CC) $(CFLAGS_SAMX) -o $(tmpobj)/mem_if.o -c mem_if.c + +$(tmpobj)/ipmidir.o: ipmidir.c + @$(CC) $(CFLAGS_SAMX) -o $@ -c ipmidir.c + +$(tmpobj)/imbapi.o: imbapi.c + @$(CC) $(CFLAGS_SAMX) -o $@ -c imbapi.c + +$(tmpobj)/ipmimv.o: ipmimv.c + @$(CC) $(CFLAGS_SAMX) -o $@ -c ipmimv.c + +$(tmpobj)/ipmild.o: ipmild.c + @$(CC) $(CFLAGS_SAMX) -o $@ -c ipmild.c + +$(tmpobj)/ipmibmc.o: ipmibmc.c + @$(CC) $(CFLAGS_SAMX) -o $@ -c ipmibmc.c + +$(tmpobj)/ipmilipmi.o: ipmilipmi.c + @$(CC) $(CFLAGS_SAMX) -o $@ -c ipmilipmi.c + +$(tmpobj)/ipmilan.o: ipmilan.c + @$(CC) $(CFLAGS_SAMX) -o $@ -c ipmilan.c + +$(tmpobj)/ipmilanplus.o: ipmilanplus.c + @$(CC) $(CFLAGS_SAMX) -o $@ -c ipmilanplus.c + +$(tmpobj)/md5.o: md5.c + @$(CC) $(CFLAGS_SAMX) -o $@ -c md5.c + +$(tmpobj)/md2.o: md2.c + @$(CC) $(CFLAGS_SAMX) -o $@ -c md2.c + +#%.o: %.c +# $(CC) -c $(OS_CF) $(CFLAGS) $(AM_CPPFLAGS) -o $@ $< + +ievents_SOURCES = ievents.c + +idiscover_SOURCES = idiscover.c + +ipmi_port_SOURCES = ipmi_port.c + +# xmlconfig_SOURCES = xmlconfig.c $(CMDSRC) + +EXTRA_DIST = imb_api.h ipmicmd.h ipmidir.h ipmilan.h ipmilanplus.h AnsiTerm.h iekanalyzer.h ifirewall.h ifwum.h ihpm.h ipicmg.h ipmiutil.h md2.h oem_dell.h oem_fujitsu.h oem_intel.h oem_kontron.h oem_sun.h idcmi.h isensor.h + +all-am: Makefile $(DEV_LIB) $(bin_PROGRAMS) $(sbin_PROGRAMS) $(EXTRA_PROGRAMS) + +install-data-am: $(EXTRA_PROGRAMS) $(DEV_LIB) + @INS_LIB@ mkdir -p $(DESTDIR)$(extradir) + @INS_LIB@ mkdir -p $(DESTDIR)$(LIBDIR) + @INS_LIB@ mkdir -p $(DESTDIR)$(inc_dir) + @INS_LIB@ cp -f ipmi_sample.c $(DESTDIR)$(extradir) + @INS_LIB@ cp -f ipmi_sample_evt.c $(DESTDIR)$(extradir) + @INS_LIB@ cp -f ipmicmd.h $(DESTDIR)$(inc_dir) + @INS_LIB@ cp -f isensor.c ievents.c $(DESTDIR)$(extradir) + @INS_LIB@ cp -f isensor.h ievents.h $(DESTDIR)$(extradir) + @INS_LIB@ cp -f Makefile.sample $(DESTDIR)$(extradir)/Makefile + @INS_LIB@ cp -f $(DEV_LIB) $(DESTDIR)$(LIBDIR) + +clean-generic: + rm -f $(DEV_LIB) $(EXTRA_PROGRAMS) $(OLDPROGS) $(TESTPROGS) + if [ -d $(tmpobj) ]; then rm -rf $(tmpobj) ; fi + if [ -d $(tmpwin) ]; then rm -rf $(tmpwin) ; fi + rm -f *.log *.tmp debug*.list *.o *.pdb *.lo *.so *.la diff --git a/util/Makefile.in b/util/Makefile.in new file mode 100644 index 0000000..a8eb9b9 --- /dev/null +++ b/util/Makefile.in @@ -0,0 +1,766 @@ +# Makefile.in generated by automake 1.9.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +bin_PROGRAMS = ipmiutil$(EXEEXT) ievents$(EXEEXT) idiscover$(EXEEXT) +sbin_PROGRAMS = ipmi_port$(EXEEXT) iseltime$(EXEEXT) +EXTRA_PROGRAMS = ipmi_sample$(EXEEXT) ipmi_sample_evt$(EXEEXT) +subdir = util +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)" +binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +PROGRAMS = $(bin_PROGRAMS) $(sbin_PROGRAMS) +am_idiscover_OBJECTS = idiscover.$(OBJEXT) +idiscover_OBJECTS = $(am_idiscover_OBJECTS) +idiscover_LDADD = $(LDADD) +am__DEPENDENCIES_1 = +idiscover_DEPENDENCIES = $(am__DEPENDENCIES_1) +am_ievents_OBJECTS = ievents.$(OBJEXT) +ievents_OBJECTS = $(am_ievents_OBJECTS) +ievents_LDADD = $(LDADD) +ievents_DEPENDENCIES = $(am__DEPENDENCIES_1) +am_ipmi_port_OBJECTS = ipmi_port.$(OBJEXT) +ipmi_port_OBJECTS = $(am_ipmi_port_OBJECTS) +ipmi_port_LDADD = $(LDADD) +ipmi_port_DEPENDENCIES = $(am__DEPENDENCIES_1) +ipmi_sample_SOURCES = ipmi_sample.c +ipmi_sample_OBJECTS = ipmi_sample.$(OBJEXT) +ipmi_sample_LDADD = $(LDADD) +ipmi_sample_DEPENDENCIES = $(am__DEPENDENCIES_1) +ipmi_sample_evt_SOURCES = ipmi_sample_evt.c +ipmi_sample_evt_OBJECTS = ipmi_sample_evt.$(OBJEXT) +ipmi_sample_evt_LDADD = $(LDADD) +ipmi_sample_evt_DEPENDENCIES = $(am__DEPENDENCIES_1) +am__objects_1 = oem_kontron.$(OBJEXT) oem_fujitsu.$(OBJEXT) \ + oem_intel.$(OBJEXT) oem_sun.$(OBJEXT) oem_supermicro.$(OBJEXT) \ + oem_dell.$(OBJEXT) oem_quanta.$(OBJEXT) oem_hp.$(OBJEXT) \ + oem_newisys.$(OBJEXT) iekanalyzer.$(OBJEXT) +am__objects_2 = ipmicmd.$(OBJEXT) mem_if.$(OBJEXT) ipmidir.$(OBJEXT) \ + imbapi.$(OBJEXT) ipmimv.$(OBJEXT) ipmild.$(OBJEXT) \ + ipmibmc.$(OBJEXT) ipmilipmi.$(OBJEXT) subs.$(OBJEXT) \ + md5.$(OBJEXT) md2.$(OBJEXT) ipmilan.$(OBJEXT) \ + ipmilanplus.$(OBJEXT) +am__objects_3 = ipmiutil.$(OBJEXT) ialarms.$(OBJEXT) ihealth.$(OBJEXT) \ + ievents.$(OBJEXT) ifru.$(OBJEXT) ifru_picmg.$(OBJEXT) \ + igetevent.$(OBJEXT) ireset.$(OBJEXT) icmd.$(OBJEXT) \ + ilan.$(OBJEXT) isensor.$(OBJEXT) isel.$(OBJEXT) \ + iserial.$(OBJEXT) iwdt.$(OBJEXT) isol.$(OBJEXT) \ + idiscover.$(OBJEXT) iconfig.$(OBJEXT) ipicmg.$(OBJEXT) \ + ifirewall.$(OBJEXT) ifwum.$(OBJEXT) ihpm.$(OBJEXT) \ + itsol.$(OBJEXT) idcmi.$(OBJEXT) $(am__objects_1) \ + $(am__objects_2) +am_ipmiutil_OBJECTS = $(am__objects_3) +ipmiutil_OBJECTS = $(am_ipmiutil_OBJECTS) +ipmiutil_LDADD = $(LDADD) +ipmiutil_DEPENDENCIES = $(am__DEPENDENCIES_1) +iseltime_SOURCES = iseltime.c +iseltime_OBJECTS = iseltime.$(OBJEXT) +iseltime_LDADD = $(LDADD) +iseltime_DEPENDENCIES = $(am__DEPENDENCIES_1) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(idiscover_SOURCES) $(ievents_SOURCES) $(ipmi_port_SOURCES) \ + ipmi_sample.c ipmi_sample_evt.c $(ipmiutil_SOURCES) iseltime.c +DIST_SOURCES = $(idiscover_SOURCES) $(ievents_SOURCES) \ + $(ipmi_port_SOURCES) ipmi_sample.c ipmi_sample_evt.c \ + $(ipmiutil_SOURCES) iseltime.c +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CROSS_CFLAGS = @CROSS_CFLAGS@ +CROSS_LFLAGS = @CROSS_LFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +GPL_CFLAGS = @GPL_CFLAGS@ +IA64_CFLAGS = @IA64_CFLAGS@ +INIT_DIR = @INIT_DIR@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INS_LIB = @INS_LIB@ +LANDESK_CFLAGS = @LANDESK_CFLAGS@ +LANDESK_LDADD = @LANDESK_LDADD@ +LANPLUS_CFLAGS = @LANPLUS_CFLAGS@ +LANPLUS_CRYPTO = @LANPLUS_CRYPTO@ +LANPLUS_LDADD = @LANPLUS_LDADD@ +LANPLUS_LIB = @LANPLUS_LIB@ +LANPLUS_SAM = @LANPLUS_SAM@ +LDFLAGS = @LDFLAGS@ +LD_SAMX = @LD_SAMX@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIB_DIR = @LIB_DIR@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +OS_CFLAGS = @OS_CFLAGS@ +OS_DRIVERS = @OS_DRIVERS@ +OS_LFLAGS = @OS_LFLAGS@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_DIR = @PKG_DIR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SHR_LINK = @SHR_LINK@ +STRIP = @STRIP@ +SUBDIR_S = @SUBDIR_S@ +SYSTEMD_DIR = @SYSTEMD_DIR@ +VERSION = @VERSION@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +localedir = $(datadir)/locale +INCLUDES = -I.. +OS_CF = @OS_CFLAGS@ @CROSS_CFLAGS@ +OS_LF = @OS_LFLAGS@ @CROSS_LFLAGS@ + +# The LanDesk library is proprietary, so it is incompatible with ALLOW_GPL. +# To build with LanDesk support: +# First copy the library to ../lib/libipmiapi.a +# Then ./configure --enable-landesk +# Result: +# AM_CPPFLAGS += -DLINK_LANDESK +# LDADD += -lipmiapi -L../lib + +# For lanplus plugin support (IPMI LAN 2.0 RMCP+) used by SOL: +# If ./configure --disable-lanplus +# AM_CPPFLAGS += +# LDADD += +# Otherwise default result is lanplus enabled: +# AM_CPPFLAGS += -DHAVE_LANPLUS +# LDADD += -L../lib -lipmi_lanplus -L/usr/local/lib -lcrypto +# LDADD += -L../lib -lintf_lanplus -L/usr/local/lib -lcrypto (older) +# Could also use CMDMOD += ipmilan2.c instead, if completed. +AM_CPPFLAGS = $(OS_CF) -DLOCALEDIR=\"$(localedir)\" @IA64_CFLAGS@ \ + @GPL_CFLAGS@ -I. -I.. -DMETACOMMAND @LANDESK_CFLAGS@ \ + @LANPLUS_CFLAGS@ $(am__empty) +LDADD = $(OS_LF) -lpthread @LANDESK_LDADD@ @LANPLUS_LIB@ \ + @LANPLUS_CRYPTO@ $(am__empty) +LDSAM = $(OS_LF) @LD_SAMX@ +CFLAGS_SAMX = -O2 -g -I. -I.. $(OS_CF) @LANPLUS_CFLAGS@ +CFLAGS_SAM = -O2 -g -I. -I.. $(OS_CF) +# May be /usr/bin/install or /bin/install +INSTALLBIN = install -c +extradir = $(datadir)/ipmiutil +inc_dir = $(includedir) +tmpobj = obj +tmpwin = tmp +LIBDIR = @LIB_DIR@ +CMDMOD = ipmicmd.c mem_if.c ipmidir.c imbapi.c ipmimv.c ipmild.c \ + ipmibmc.c ipmilipmi.c subs.c md5.c md2.c ipmilan.c \ + ipmilanplus.c +# CMDMOD = ipmicmd.c mem_if.c @OS_DRIVERS@ +# am: configure substitutions are not allowed in _SOURCES variables +LIBOBJ = ipmicmd.o mem_if.o ipmidir.o imbapi.o ipmimv.o ipmild.o ipmibmc.o ipmilipmi.o subs.o md5.o md2.o $(tmpobj)/ipmilan.o $(tmpobj)/ipmilanplus.o +OEMMOD = oem_kontron.c oem_fujitsu.c oem_intel.c oem_sun.c oem_supermicro.c oem_dell.c oem_quanta.c oem_hp.c oem_newisys.c iekanalyzer.c +METASOURCE = ipmiutil.c ialarms.c ihealth.c ievents.c ifru.c ifru_picmg.c igetevent.c ireset.c icmd.c ilan.c isensor.c isel.c iserial.c iwdt.c isol.c idiscover.c iconfig.c ipicmg.c ifirewall.c ifwum.c ihpm.c itsol.c idcmi.c $(OEMMOD) $(CMDMOD) +LANPLUS_OBJ = $(shell ar t @LANPLUS_LIB@ 2>/dev/null) +DEV_LIB = libipmiutil.a +SHR_LIB = libipmiutil.so +SHRLINK = @SHR_LINK@ +TESTPROGS = libimbapi.a iconfig ipmimv ifruset ipmi_sample2 ialarms_enc +# OLDPROGS are old/previous binaries that may exist and need to be deleted. +OLDPROGS = alarms bmchealth fruconfig getevent hwreset icmd isolconsole pefconfig sensor showsel tmconfig wdt +ipmiutil_SOURCES = $(METASOURCE) +ievents_SOURCES = ievents.c +idiscover_SOURCES = idiscover.c +ipmi_port_SOURCES = ipmi_port.c +EXTRA_DIST = imb_api.h ipmicmd.h ipmidir.h ipmilan.h ipmilanplus.h AnsiTerm.h ifirewall.h ifwum.h ihpm.h ipicmg.h ipmiutil.h md2.h oem_dell.h oem_fujitsu.h oem_intel.h oem_kontron.h oem_sun.h idcmi.h isensor.h iekanalyzer.h +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign util/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --foreign util/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + || test -f $$p1 \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ + rm -f "$(DESTDIR)$(bindir)/$$f"; \ + done + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f $$p $$f"; \ + rm -f $$p $$f ; \ + done +install-sbinPROGRAMS: $(sbin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(sbindir)" || $(mkdir_p) "$(DESTDIR)$(sbindir)" + @list='$(sbin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + || test -f $$p1 \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(sbinPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(sbindir)/$$f'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(sbinPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(sbindir)/$$f" || exit 1; \ + else :; fi; \ + done + +uninstall-sbinPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(sbin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f '$(DESTDIR)$(sbindir)/$$f'"; \ + rm -f "$(DESTDIR)$(sbindir)/$$f"; \ + done + +clean-sbinPROGRAMS: + @list='$(sbin_PROGRAMS)'; for p in $$list; do \ + f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f $$p $$f"; \ + rm -f $$p $$f ; \ + done + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ialarms.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/icmd.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iconfig.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/idcmi.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/idiscover.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iekanalyzer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ievents.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifirewall.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifru.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifru_picmg.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ifwum.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/igetevent.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ihealth.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ihpm.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ilan.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imbapi.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipicmg.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmi_port.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmi_sample.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmi_sample_evt.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmibmc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmicmd.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmidir.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmilan.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmilanplus.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmild.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmilipmi.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmimv.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmiutil.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ireset.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isel.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iseltime.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isensor.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iserial.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isol.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/itsol.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iwdt.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md2.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md5.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mem_if.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oem_dell.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oem_fujitsu.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oem_hp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oem_intel.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oem_kontron.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oem_newisys.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oem_quanta.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oem_sun.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oem_supermicro.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/subs.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) +installdirs: + for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic clean-libtool \ + clean-sbinPROGRAMS mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-exec-am: install-binPROGRAMS install-sbinPROGRAMS + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-info-am \ + uninstall-sbinPROGRAMS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-generic clean-libtool clean-sbinPROGRAMS ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-binPROGRAMS install-data \ + install-data-am install-exec install-exec-am install-info \ + install-info-am install-man install-sbinPROGRAMS install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-binPROGRAMS \ + uninstall-info-am uninstall-sbinPROGRAMS + + +# To build an imb api library (libimbapi.a): +libimbapi.a: imbapi.c + mkdir -p $(tmpobj) + $(CC) -I. -I.. $(OS_CF) -fPIC $(CFLAGS) -o $(tmpobj)/imbapi.o -c imbapi.c + $(AR) cru libimbapi.a $(tmpobj)/imbapi.o + $(RANLIB) libimbapi.a + rm -f $(tmpobj)/imbapi.o + +# Build a lib to support all of the IPMI drivers (libipmiutil.a) +# If LANPLUS_SAM = yes, include LANPLUS_OBJ, else do not. +# See configure --enable-liblanplus to change this +$(DEV_LIB): $(CMDMOD:.c=.o) @LANPLUS_LIB@ + mkdir -p $(tmpobj) + if [ "x@LANPLUS_SAM@" = "xyes" ]; then \ + $(CC) $(CFLAGS_SAMX) -o $(tmpobj)/ipmilanplus.o -c ipmilanplus.c; \ + $(CC) $(CFLAGS_SAMX) -o $(tmpobj)/ipmilan.o -c ipmilan.c; \ + ar x @LANPLUS_LIB@ ; \ + $(AR) cru $(DEV_LIB) $(LIBOBJ) $(LANPLUS_OBJ); \ + $(RANLIB) $(DEV_LIB); \ + else \ + $(CC) $(CFLAGS_SAM) -o $(tmpobj)/ipmilanplus.o -c ipmilanplus.c; \ + $(CC) $(CFLAGS_SAM) -o $(tmpobj)/ipmilan.o -c ipmilan.c; \ + $(AR) cru $(DEV_LIB) $(LIBOBJ) ; \ + $(RANLIB) $(DEV_LIB) ; \ + fi + +$(SHR_LIB): $(CMDMOD:.c=.o) @LANPLUS_LIB@ + mkdir -p $(tmpobj) + if [ "x@LANPLUS_SAM@" = "xyes" ]; then \ + $(CC) $(CFLAGS_SAMX) -o $(tmpobj)/ipmilanplus.o -c ipmilanplus.c; \ + $(CC) $(CFLAGS_SAMX) -o $(tmpobj)/ipmilan.o -c ipmilan.c; \ + ar x @LANPLUS_LIB@ ; \ + $(CC) $(LDFLAGS) -shared -o $(SHR_LIB) $(LIBOBJ) $(LANPLUS_OBJ); \ + else \ + $(CC) $(CFLAGS_SAM) -o $(tmpobj)/ipmilanplus.o -c ipmilanplus.c; \ + $(CC) $(CFLAGS_SAM) -o $(tmpobj)/ipmilan.o -c ipmilan.c; \ + $(CC) $(LDFLAGS) -shared -o $(SHR_LIB) $(LIBOBJ) ; \ + fi + +# To build ipmiutil, need to use METACFLAGS for each .c/.o + +idiscover$(EXEEXT): idiscover.c + $(CC) $(CFLAGS_SAM) $(LDFLAGS) $(OS_LF) -o idiscover idiscover.c + +ipmimv: ipmimv.c + $(CC) $(CFLAGS_SAM) $(LDFLAGS) -DTEST_BIN -o ipmimv ipmimv.c + +ievents$(EXEEXT): ievents.c + $(CC) $(CFLAGS_SAM) $(LDFLAGS) -DALONE -o ievents ievents.c + +ipmi_sample: $(DEV_LIB) ipmi_sample.c isensor.c ievents.c + $(CC) $(CFLAGS_SAM) -c ipmi_sample.c + $(CC) -g -O2 -o ipmi_sample ipmi_sample.o $(DEV_LIB) $(LDFLAGS) $(LDSAM) + +ialarms_enc: $(DEV_LIB) ialarms.c oem_intel.c + $(CC) $(CFLAGS_SAM) -DTEST_ENC -o ialarms2.o -c ialarms.c + $(CC) $(CFLAGS_SAM) -DNO_EVENTS -o oem_intel2.o -c oem_intel.c + $(CC) -g -O2 -o ialarms_enc ialarms2.o oem_intel2.o $(DEV_LIB) $(LDFLAGS) $(LDSAM) + +ifru_picmg2.o: ifru_picmg.c + $(CC) $(CFLAGS_SAM) -o ifru_picmg2.o -c ifru_picmg.c + +# To build ipmi_sample with GET_SENSORS enabled, need isensors.o, ievents.o +# Note that this does not include oem_intel, etc. for OEM SEL decoding. +ipmi_sample2: $(DEV_LIB) ipmi_sample.c isensor.c ievents.c ifru.c isel.c ifru_picmg2.o + $(CC) $(CFLAGS_SAM) -D GET_SENSORS -D GET_FRU -o ipmi_sample2.o -c ipmi_sample.c + $(CC) $(CFLAGS_SAM) -o isensor2.o -c isensor.c + $(CC) $(CFLAGS_SAM) -o ievents2.o -c ievents.c + $(CC) $(CFLAGS_SAM) -o ifru2.o -c ifru.c + $(CC) $(CFLAGS_SAM) -o isel2.o -c isel.c + $(CC) -g -O2 -o ipmi_sample2 ipmi_sample2.o isensor2.o ievents2.o ifru2.o ifru_picmg2.o isel2.o $(DEV_LIB) $(LDFLAGS) $(LDSAM) + +ipmi_sample_evt: $(DEV_LIB) ipmi_sample_evt.c isensor.c ievents.c + $(CC) $(CFLAGS_SAM) -o ipmi_sample_evt.o -c ipmi_sample_evt.c + $(CC) $(CFLAGS_SAM) -o isensor2.o -c isensor.c + $(CC) $(CFLAGS_SAM) -DSENSORS_OK -o ievents2.o -c ievents.c + $(CC) -g -O2 -o ipmi_sample_evt ipmi_sample_evt.o isensor2.o ievents2.o $(DEV_LIB) $(LDFLAGS) $(LDSAM) + +ifruset: $(DEV_LIB) ifruset.c ifru_picmg2.o + $(CC) $(CFLAGS_SAM) -c ifruset.c + $(CC) -g -O2 -o ifruset ifruset.o ifru_picmg2.o $(DEV_LIB) $(LDFLAGS) $(LDADD) + +iseltime: $(DEV_LIB) iseltime.c + $(CC) $(CFLAGS_SAM) -c iseltime.c + $(CC) -g -O2 -o iseltime iseltime.o $(DEV_LIB) $(LDFLAGS) $(LDADD) + +ipmi_port$(EXEEXT): ipmi_port.c + $(CC) $(CFLAGS_SAM) $(LDFLAGS) -o ipmi_port ipmi_port.c + +iconfig: iconfig.c $(DEV_LIB) + $(CC) $(CFLAGS_SAM) $(LDFLAGS) -o iconfig iconfig.c $(DEV_LIB) @LANPLUS_CRYPTO@ + +# @LANPLUS_LIB@ is ../lib/libipmi_lanplus.a +../lib/libipmi_lanplus.a: + cd ../lib; make + +ipmiutil$(EXEEXT): $(METASOURCE:.c=.o) @LANPLUS_LIB@ + $(CC) $(CFLAGS) $(LDFLAGS) -o ipmiutil $(METASOURCE:.c=.o) $(LDADD) + +all-am: Makefile $(bin_PROGRAMS) $(sbin_PROGRAMS) $(EXTRA_PROGRAMS) $(DEV_LIB) $(SHRLINK) + +install-data-am: $(EXTRA_PROGRAMS) $(DEV_LIB) $(SHRLINK) + @INS_LIB@ mkdir -p $(DESTDIR)$(extradir) + @INS_LIB@ mkdir -p $(DESTDIR)$(LIBDIR) + @INS_LIB@ mkdir -p $(DESTDIR)$(inc_dir) + @INS_LIB@ cp -f ipmi_sample.c $(DESTDIR)$(extradir) + @INS_LIB@ cp -f ipmi_sample_evt.c $(DESTDIR)$(extradir) + @INS_LIB@ cp -f ipmicmd.h $(DESTDIR)$(inc_dir) + @INS_LIB@ cp -f isensor.c ievents.c $(DESTDIR)$(extradir) + @INS_LIB@ cp -f isensor.h ievents.h $(DESTDIR)$(extradir) + @INS_LIB@ cp -f Makefile.sample $(DESTDIR)$(extradir)/Makefile + @INS_LIB@ cp -f $(DEV_LIB) $(DESTDIR)$(LIBDIR) + if [ "x$(SHRLINK)" != "x" ]; then \ + @INS_LIB@ cp -f $(SHR_LIB) $(DESTDIR)$(LIBDIR) ; \ + fi + +clean-generic: + rm -f $(DEV_LIB) $(EXTRA_PROGRAMS) $(OLDPROGS) $(TESTPROGS) $(SHRLINK) + if [ -d $(tmpobj) ]; then rm -rf $(tmpobj) ; fi + if [ -d $(tmpwin) ]; then rm -rf $(tmpwin) ; fi + rm -f *.log *.tmp debug*.list *.o *.pdb *.lo *.la *.so +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/util/Makefile.sample b/util/Makefile.sample new file mode 100644 index 0000000..2976dd5 --- /dev/null +++ b/util/Makefile.sample @@ -0,0 +1,28 @@ +# Makefile for ipmi_sample program +# +TARGETS = ipmi_sample ipmi_sample_evt +incl_dir = /usr/include +CFLAGS_SAM = -O2 -g -I. -DLINUX +LDFLAGS = -lpthread +# if building without lanplus, comment out these two lines +CFLAGS_SAM += -DHAVE_LANPLUS +LDFLAGS += -lcrypto + +# see /usr/lib/libipmiutil.a +LDFLAGS += -lipmiutil + +all: $(TARGETS) + +ipmi_sample: ipmi_sample.c $(incl_dir)/ipmicmd.h + $(CC) $(CFLAGS_SAM) -c ipmi_sample.c + $(CC) -g -O2 -o ipmi_sample ipmi_sample.o $(LDFLAGS) + +ipmi_sample_evt: ipmi_sample_evt.c isensor.c ievents.c + $(CC) $(CFLAGS_SAM) -c ipmi_sample_evt.c + $(CC) $(CFLAGS_SAM) -o isensor2.o -c isensor.c + $(CC) $(CFLAGS_SAM) -DSENSORS_OK -o ievents2.o -c ievents.c + $(CC) -g -O2 -o ipmi_sample_evt ipmi_sample_evt.o isensor2.o ievents2.o $(LDFLAGS) + +clean-generic: + rm -f $(TARGETS) *.o *.tmp + diff --git a/util/ialarms.c b/util/ialarms.c new file mode 100644 index 0000000..dbbdf0c --- /dev/null +++ b/util/ialarms.c @@ -0,0 +1,689 @@ +/* + * ialarms.c + * + * This tool reads and sets the alarms panel on an Intel Telco chassis. + * Note that the Intel Server Management software will set these alarms + * based on firmware-detected thresholds and events. + * + * Author: Andy Cress arcress at users.sourceforge.net + * Copyright (c) 2003-2006 Intel Corporation. + * Copyright (c) 2009 Kontron America, Inc. + * + * 02/25/03 Andy Cress - created + * 04/08/03 Andy Cress - added -i for ChassisIdentify + * 04/30/03 Andy Cress - only try to set ID on/off if option specified + * 01/20/04 Andy Cress - mods for mBMC w Chesnee platform + * 05/05/04 Andy Cress - call ipmi_close before exit + * 10/11/04 Andy Cress 1.4 - if -o set relays too (fsetall) + * 11/01/04 Andy Cress 1.5 - add -N / -R for remote nodes + * 03/07/05 Andy Cress 1.6 - add bus for Intel TIGI2U + * 03/28/05 Andy Cress 1.7 - add check for BMC TAM if setting alarms + * 06/22/05 Andy Cress 1.8 - adding fpicmg for ATCA alarm LEDs + * 03/17/06 Andy Cress 1.9 - adding BUS_ID7 for Harbison + * 04/20/07 Andy Cress 1.25 - adding disk Enclosure HSC LEDs + */ +/*M* +Copyright (c) 2003-2006, Intel Corporation +Copyright (c) 2009 Kontron America, 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: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions 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. + c.. Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ +#include +#include +#include +#include +#include +#include +#ifdef WIN32 +#include "getopt.h" +#elif defined(DOS) +#include +#include "getopt.h" +#elif defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include +#else +#include +#endif +#include "ipmicmd.h" +#include "oem_intel.h" + +/* + * Global variables + */ +static char * progver = "2.93"; +static char * progname = "ialarms"; +static char fdebug = 0; +static char fbmctam = 0; +static char fpicmg = 0; +static char fHasAlarms = 0; +static char fNSC = 0; +static char fHasEnc = 0; /* Has disk Enclosure HSC? */ +static int maxdisks = 6; /* default to max of 6 disks */ +static uchar fdoencl = 1; +static uchar picmg_id = 0; /* always 0 for picmg */ +static uchar fru_id = 0; /* fru device id */ +//static uchar led_id = 0; /* 0 = blue led, 1,2,3=led1,2,3 */ +static uchar ipmi_maj, ipmi_min; + +#define ENC_LED_WRITE 0x21 // only used for Ballenger-CT HSC +#define ENC_LED_READ 0x20 // only used for Ballenger-CT HSC + +#define NETFN_ENC 0x30 +#define NETFN_PICMG 0x2c +#define PICMG_GET_LED_PROPERTIES 0x05 +#define PICMG_SET_LED_STATE 0x07 +#define PICMG_GET_LED_STATE 0x08 + +#ifdef METACOMMAND +extern int get_alarms_fujitsu(uchar *rgalarms); +extern int show_alarms_fujitsu(uchar *rgalarms); +extern int set_alarms_fujitsu(uchar num, uchar val); +extern int get_led_status_intel(uchar *pstate); +#endif +#ifdef ALONE +extern int get_led_status_intel(uchar *pstate); +#endif + +static uchar busid = PRIVATE_BUS_ID; +static uchar enc_sa = HSC_SA; +static char fRomley = 0; + +static int get_enc_leds(uchar *val) +{ + uchar idata[16]; + uchar rdata[16]; + int rlen, i; + int rv = 0; + uchar cc; + char *pstr = NULL; + rlen = sizeof(rdata); + for (i = 0; i < 3; i++) { + rv = ipmi_cmdraw( ENC_LED_READ, NETFN_ENC, enc_sa, PUBLIC_BUS,BMC_LUN, + idata,0, rdata, &rlen, &cc, fdebug); + if (fdebug) + printf("get_enc_leds() rv=%d cc=%x val=%02x\n",rv,cc,rdata[0]); + if (rv == 0 && cc == 0x83) os_usleep(0,50000); /* HSC busy, wait 50ms */ + else break; + } + if (rv != 0) pstr = decode_rv(rv); + else if (cc != 0) pstr = decode_cc(0,cc); + /* if get cc==0x83 here, the power state may be soft-off */ + if (rv == 0 && cc != 0) rv = cc; + if (rv == 0) { /*success*/ + *val = rdata[0]; + } else /*error*/ + printf("get_enc_leds: error %s\n",pstr); + return(rv); +} + +static int set_enc_leds(uchar val) +{ + uchar idata[16]; + uchar rdata[16]; + int rlen; + int rv = 0; + uchar cc; + + idata[0] = val; + rlen = sizeof(rdata); + rv = ipmi_cmdraw( ENC_LED_WRITE, NETFN_ENC, enc_sa, PUBLIC_BUS,BMC_LUN, + idata,1, rdata, &rlen, &cc, fdebug); + if (fdebug) printf("set_enc_leds(%02x) rv = %d, cc = %x\n",val,rv,cc); + if (rv == 0 && cc != 0) rv = cc; + return(rv); +} + +static void show_enc_leds(uchar val) +{ + char *enc_pattn = "disk slot %d LED: %s\n"; + uchar mask; + int i, n; + if (fdebug) printf("val = %02x\n",val); + n = maxdisks; + if (n > 8) n = 8; + mask = 0x01; + /* Ballenger HSC only supports 6 slots, some support 8 */ + for (i = 0; i < n; i++) { + if (val & mask) printf(enc_pattn,i,"ON"); + else printf(enc_pattn,i,"off"); + mask = (mask << 1); + } +} + +static int set_chassis_id(uchar val) +{ + uchar inputData[4]; + uchar responseData[16]; + int responseLength = 4; + uchar completionCode; + int ret; + uchar ilen; + + ilen = 1; + inputData[0] = val; /* #seconds to turn on id, 0=turn off */ + /* IPMI 2.0 has an optional 2nd byte, + * if 01, turn ID on indefinitely. */ + if (val == 255 && ipmi_maj >= 2) { + inputData[1] = 1; + ilen = 2; + } + /* CHASSIS_IDENTIFY=0x04, using NETFN_CHAS (=00) */ + ret = ipmi_cmd(CHASSIS_IDENTIFY, inputData, ilen, responseData, + &responseLength, &completionCode, fdebug); + if (ret == 0 && completionCode != 0) ret = completionCode; + if (ret != 0) { + printf("set_chassis_id: ret = %d, ccode %02x, value = %02x\n", + ret, completionCode, val); + } + return(ret); +} /*end set_chassis_id*/ + + +static int get_alarms_picmg(uchar *rgv, uchar picmgid, uchar fruid, uchar led) +{ + uchar inputData[4]; + uchar responseData[16]; + int responseLength; + uchar completionCode; + int ret, i; + + if (rgv == NULL) return(ERR_BAD_PARAM); + inputData[0] = picmgid; + inputData[1] = fruid; + inputData[2] = led; // 0 = blue led + responseLength = sizeof(responseData); + ret = ipmi_cmdraw( PICMG_GET_LED_STATE, NETFN_PICMG, + BMC_SA, PUBLIC_BUS,BMC_LUN, + inputData,3, responseData, &responseLength, + &completionCode, fdebug); + if ((ret != 0) || (completionCode != 0)) { + if (fdebug) + printf("get_alarms_picmg(%d,%d,%d): ret = %d, ccode %02x\n", + picmgid,fruid,led,ret, completionCode); + if (ret == 0) ret = completionCode; + return(ret); + } + /* if here, success */ + if (fdebug) { + printf("get_alarms_picmg(%d,%d,%d): ", picmgid,fruid,led); + for (i = 0; i < responseLength; i++) + printf("%02x ",responseData[i]); + printf("\n"); + } + memcpy(rgv,responseData,responseLength); + return(ret); +} + +static int set_alarms_picmg(uchar val, uchar picmgid, uchar fruid, uchar led, + char color) +{ + uchar inputData[6]; + uchar responseData[16]; + int responseLength; + uchar completionCode; + int ret, i; + + inputData[0] = picmgid; + inputData[1] = fruid; + inputData[2] = led; // 0 = blue led + inputData[3] = val; + inputData[4] = 0; + switch(color) { + case 'w': i = 6; break; + case 'o': i = 5; break; + case 'a': i = 4; break; + case 'g': i = 3; break; + case 'r': i = 2; break; + case 'b': + default: i = 1; break; + } + inputData[5] = (uchar)i; // 1 = blue + responseLength = sizeof(responseData); + ret = ipmi_cmdraw( PICMG_SET_LED_STATE, NETFN_PICMG, + BMC_SA, PUBLIC_BUS,BMC_LUN, + inputData,6, responseData, &responseLength, + &completionCode, fdebug); + if ((ret != 0) || (completionCode != 0)) { + printf("set_alarms_picmg(%02x,%d,%d,%d): ret = %d, ccode %02x\n", + val,picmgid,fruid,led,ret, completionCode); + if (ret == 0) ret = completionCode; + return(ret); + } + printf("set_alarms_picmg(%02x,%d,%d,%d): ", val,picmgid,fruid,led); + for (i = 0; i < responseLength; i++) + printf("%02x ",responseData[i]); + printf("\n"); + return(ret); /* success */ +} + +static void show_alarms_picmg(uchar *v, uchar pid, uchar fruid, uchar led) +{ + char led_str[10]; + char state_str[20]; + char *func_str; + char *color_str; + if (v == NULL) return; + if (fdebug) + printf("picmg(%d,%d,%d) alarm LED state is %02x %02x %02x %02x %02x\n", + pid,fruid,led,v[0],v[1],v[2],v[3],v[4]); + switch(led) { + case 0: strcpy(led_str,"HSLed"); break; /*Blue LED*/ + default: sprintf(led_str," Led%d",led); break; + } + state_str[0] = 0; + if (v[1] & 0x01) strcat(state_str,"local"); + if (v[1] & 0x02) strcat(state_str," override"); + if (v[1] & 0x04) strcat(state_str," lamptest"); + switch(v[2]) { + case 0x00: func_str = "off"; break; + case 0xFF: func_str = "ON"; break; + default: func_str = "Blink"; break; /*duration of blink/off*/ + } + /* v[3] is duration of blink/on in tens of msec */ + switch(v[4]) { + case 6: color_str = "white"; break; + case 5: color_str = "orange"; break; + case 4: color_str = "amber"; break; + case 3: color_str = "green"; break; + case 2: color_str = "red"; break; + case 1: + default: color_str = "blue"; break; + } + printf("picmg(%d,%d) %s is %s,%s,%s\n",fruid,led,led_str, + state_str,func_str,color_str); +} + + +#ifdef METACOMMAND +int i_alarms(int argc, char **argv) +#else +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#endif +{ + int ret = 0; + int c; + uchar fsetled = 0; + uchar fsetall = 0; + uchar fsetdisk = 0; + uchar fsetid = 0; + uchar fcrit = 2; + uchar fmaj = 2; + uchar fmin = 2; + uchar fpow = 2; + uchar fdiska = 2; + uchar fdiskb = 2; + uchar fdiskn = 2; + uchar ndisk = 0; + int fid = 0; + uchar alarms = 0; + uchar rgalarms[10] = {0,0,0,0,0,0}; + uchar newvalue = 0xff; + uchar diskled = 0xff; + uchar encled = 0; + uchar devrec[16]; + uchar ledn = 0; + uchar ledv = 0; + char ledc = 'c'; + int i; + int flags = 0; + int prod_id, vend_id; + + printf("%s ver %s\n", progname,progver); + /* default to admin privilege if get/set alarms remotely */ + parse_lan_options('V',"4",0); + + while ( (c = getopt( argc, argv,"rxa:b:c:d:efm:n:p:i:ow:Z:EF:P:N:R:U:T:V:J:Y?")) != EOF ) + switch(c) { + case 'r': fsetled=0; fsetid=0; fsetdisk = 0; break; /* read only */ + case 'a': fdiska = atob(optarg); /* set disk A LED value */ + fsetdisk = 1; break; + case 'b': fdiskb = atob(optarg); /* set disk B LED value */ + fsetdisk = 2; break; + case 'c': fcrit = atob(optarg); /* set critical alarm value */ + fsetled = 1; break; + case 'd': ndisk = optarg[0] & 0x0f; /* set disk N LED on or off */ + fdiskn = optarg[1] & 0x0f; + fsetdisk = 3; break; + case 'e': fdoencl = 0; /* skip disk/enclosure LEDs */ + case 'f': fdiska = 10; /* set all disk LEDs off */ + fsetdisk = 1; break; + case 'm': fmaj = atob(optarg); /* set major alarm value */ + fsetled = 1; break; + case 'n': fmin = atob(optarg); /* set minor alarm value */ + fsetled = 1; break; + case 'p': fpow = atob(optarg); /* set power alarm value */ + fsetled = 1; break; + case 'w': ledn = optarg[0] & 0x0f; /* set picmg LED N on or off */ + ledv = optarg[1] & 0x0f; + ledc = optarg[2]; /*color char, usu 'b' for blue*/ + fsetled = 1; break; + case 'i': fid = atoi(optarg); /* set chassis id on/off */ + if (fid > 255) { + printf("Adjusting %d to max 255 sec for ID\n",fid); + fid = 255; + } + fsetid=1; break; + case 'o': fcrit=0; fmaj=0; fmin=0; fpow=0; /* set all alarms off */ + fsetdisk = 1; fdiska = 0; fdiskb = 0; fsetall=1; + fsetled = 1; fsetid=1; fid=0; break; + case 'x': fdebug = 1; break; /* debug messages */ + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'V': /* priv level */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + break; + default: + printf("Usage: %s [-abcdfimnoprx -NUPRETVFY]\n", progname); + printf(" where -r means read-only\n"); + printf(" -i5 sets Chassis ID on for 5 sec\n"); + printf(" -i0 sets Chassis ID off\n"); + printf(" -a1 sets Disk A Fault on\n"); + printf(" -a0 sets Disk A Fault off\n"); + printf(" -b1 sets Disk B Fault on\n"); + printf(" -b0 sets Disk B Fault off\n"); + printf(" -c1 sets Critical Alarm on\n"); + printf(" -c0 sets Critical Alarm off\n"); + printf(" -d31 sets Disk 3 Fault on (disks 0-6)\n"); + printf(" -d30 sets Disk 3 Fault off\n"); + printf(" -e skip disk Enclosure LEDs\n"); + printf(" -f sets all Disk Fault LEDs off\n"); + printf(" -m1 sets Major Alarm on\n"); + printf(" -m0 sets Major Alarm off\n"); + printf(" -n1 sets Minor Alarm on\n"); + printf(" -n0 sets Minor Alarm off\n"); + printf(" -p1 sets Power Alarm on\n"); + printf(" -p0 sets Power Alarm off\n"); + printf(" -o sets all Alarms off\n"); + printf(" -w21b writes picmg LED 2 on(1) color=blue(b)\n"); + printf(" -x show eXtra debug messages\n"); + print_lan_opt_usage(); + ret = ERR_USAGE; + goto do_exit; + } + + /* + * Check the Device ID to determine which bus id to use. + */ + ret = ipmi_getdeviceid(devrec,16,fdebug); + if (ret != 0) { + goto do_exit; + } else { + int j; + + if (fdebug) { + printf("devid: "); + for (j = 0; j < 16; j++) printf("%02x ",devrec[j]); + printf("\n"); + } + ipmi_maj = devrec[4] & 0x0f; + ipmi_min = devrec[4] >> 4; + prod_id = devrec[9] + (devrec[10] << 8); + vend_id = devrec[6] + (devrec[7] << 8) + (devrec[8] << 16); + + printf("-- %s version %x.%x, IPMI version %d.%d \n", + "BMC", devrec[2], devrec[3], ipmi_maj, ipmi_min); + } + +#ifdef TEST_ENC + fHasEnc = 1; + fHasAlarms = 0; + fbmctam = 0; + fpicmg = 0; + fRomley = 1; + maxdisks = 8; +#else + ret = ipmi_getpicmg(devrec,16,fdebug); + if (ret == 0) { + fpicmg = 1; + fHasAlarms = 1; + } else ret = 0; /* ignore error if not picmg */ + +#if defined(METACOMMAND) || defined(ALONE) + { + uchar rgalarms[3]; + uchar idstate; + char *pmsg; + switch(vend_id) { + case VENDOR_NSC: /* for Intel TIGPT1U */ + case VENDOR_INTEL: /* requires oem_intel.c */ + /* check_prod_capab */ + ret = detect_capab_intel(vend_id,prod_id,&flags,&maxdisks,fdebug); + busid = (uchar)ret; + if (fdebug) printf("prod_capab: busid=%x, flags=%02x\n",busid,flags); + if ((flags & HAS_ALARMS_MASK) != 0) fHasAlarms = 1; + if ((flags & HAS_BMCTAM_MASK) != 0) fbmctam = 1; + if ((flags & HAS_ENCL_MASK) != 0) fHasEnc = 1; + if ((flags & HAS_PICMG_MASK) != 0) fpicmg = 1; + if ((flags & HAS_NSC_MASK) != 0) fNSC = 1; + if ((flags & HAS_ROMLEY_MASK) != 0) fRomley = 1; + /* get ID LED status */ + ret = get_led_status_intel(&idstate); + if (ret == 0) { + switch(idstate) { + case 1: pmsg = "ON"; break; + case 2: pmsg = "Blink"; break; + default: pmsg = "off"; break; + } + printf("ID LED: %s\n",pmsg); + } + break; +#ifdef METACOMMAND + case VENDOR_KONTRON: + if (prod_id == 1590) { fHasEnc = 1; maxdisks = 8; } + break; + case VENDOR_FUJITSU: + printf("Getting Fujitsu alarm LEDs ...\n"); + ret = get_alarms_fujitsu(rgalarms); + if (fdebug) printf("get_alarms_fujitsu ret = %d\n",ret); + /* if ret != 0, fall through and try default methods */ + if (ret == 0) { + show_alarms_fujitsu(rgalarms); + if (fsetid) { + printf("\nSetting fujitsu ID LED to %02x ...\n", fid); + ret = set_alarms_fujitsu(0, (uchar)fid); + printf("set_alarms_fujitsu ret = %d\n",ret); + ret = get_alarms_fujitsu(rgalarms); + if (ret == 0) show_alarms_fujitsu(rgalarms); + } + fHasAlarms = 0; /*skip the other LED functions*/ + } + break; + case VENDOR_SUN: + printf("Do get_alarms_sun() \n"); // TODO: add this +/* + ret = get_alarms_sun(); + if (ret == 0) show_alarms_sun() + if (fsetled) { + printf("\nSetting sun(%d) alarm LED to %02x %c...\n", + ledn,ledv,ledc); + ret = set_alarms_sun(ledv,ledn,ledc); + printf("set_alarms_sun ret = %d\n",ret); + ret = get_alarms_sun(rgalarms,ledn); + if (ret == 0) show_alarms_sun(rgalarms,ledn); + } +*/ + break; +#endif + default: + break; + } + } +#endif + +#endif + if (fHasAlarms) + { /* get the telco picmg or intel alarm LED states */ + if (fpicmg) { + for (i = 0; i < 5; i++) { + ret = get_alarms_picmg(rgalarms,picmg_id,fru_id,(uchar)i); + if (ret == 0) + show_alarms_picmg(rgalarms,picmg_id,fru_id,(uchar)i); + } + } else { + alarms = get_alarms_intel(busid); + if (alarms == 0) { /* failed to get alarm panel data */ + if (fHasAlarms) { /* baseboard which may have Telco alarm panel*/ + printf("Could not obtain Telco LED states, Telco alarm panel " + "may not be present.\n\n"); + } + fHasAlarms = 0; + } else { /* have Telco alarm panel data */ + ret = 0; + show_alarms_intel(alarms); + } + } + + if (fsetled) { + if (fpicmg) { + printf("\nSetting picmg(%d,%d) alarm LED to %02x %c...\n", + fru_id,ledn,ledv,ledc); + ret = set_alarms_picmg(ledv,picmg_id,fru_id,ledn,ledc); + printf("set_alarms_picmg ret = %d\n",ret); + ret = get_alarms_picmg(rgalarms,picmg_id,fru_id,ledn); + if (ret == 0) show_alarms_picmg(rgalarms,picmg_id,fru_id,ledn); + } else { /* not picmg, set Intel Telco Alarm LEDs */ + if (fbmctam) { /* Platform supports BMC Telco Alarms Manager */ + ret = check_bmctam_intel(); + } /*endif fbmctam*/ + if (ret == LAN_ERR_ABORT) { + printf("Conflict with BMC TAM - Skipping TAM LEDs.\n"); + } else { + if (fsetall) newvalue = 0xFF; /* alarms and relays */ + else { + newvalue = alarms; + if (fcrit == 1) newvalue &= 0xFD; /*bit1 = 0*/ + else if (fcrit == 0) newvalue |= 0xF2; + if (fmaj == 1) newvalue &= 0xFB; /*bit2 = 0*/ + else if (fmaj == 0) newvalue |= 0xF4; + if (fmin == 1) newvalue &= 0xF7; /*bit3 = 0*/ + else if (fmin == 0) newvalue |= 0xF8; + if (fpow == 1) newvalue &= 0xFE; /*bit0 = 0*/ + else if (fpow == 0) newvalue |= 0xF1; + } + printf("\nSetting alarms to %02x ...\n",newvalue); + ret = set_alarms_intel(newvalue,busid); + alarms = get_alarms_intel(busid); + show_alarms_intel(alarms); + } + } /*end else Intel*/ + } /*endif fsetled*/ + } /*endif fHasAlarms*/ + + if (fsetid) { + printf("Setting ID LED to %d ...\n\n",fid); + ret = set_chassis_id((uchar)fid); + } + + if (fHasEnc && fdoencl) { /* disk enclosure exists */ + if (fRomley) { /* Romley (Patsburg) */ + int rv; /*do not change ret*/ + rv = get_enc_leds_intel(&encled); + if (rv == 0) { + show_enc_leds_intel(encled,maxdisks); + if (fsetdisk) { + /* Set fault if user param, and disk is present. */ + if (fsetall) newvalue = 0x00; /* all LEDs off */ + else if (fdiska == 10) newvalue = 0x00; + else { + newvalue = encled; + if (fdiskb == 1) newvalue |= 0x02; + else if (fdiskb == 0) newvalue &= 0xFD; + if (fdiska == 1) newvalue |= 0x01; + else if (fdiska == 0) newvalue &= 0xFE; + if (fdiskn == 1) newvalue |= (0x01 << ndisk); + else if (fdiskn == 0) newvalue &= ~(0x01 << ndisk); + } + printf("\nSetting Enclosure LEDs to %02x ...\n",newvalue); + ret = set_enc_leds_intel(newvalue); + ret = get_enc_leds_intel(&encled); + show_enc_leds_intel(encled,maxdisks); + } + } + } else { /* Vitesse disk Enclosure chipset */ + ret = get_enc_leds(&encled); + if (ret == 0) { + show_enc_leds(encled); + if (fsetdisk) { + /* Set fault if user param, and disk is present. */ + if (fsetall) newvalue = 0x00; /* all LEDs off */ + else if (fdiska == 10) newvalue = 0x00; + else { + newvalue = encled; + if (fdiskb == 1) newvalue |= 0x02; + else if (fdiskb == 0) newvalue &= 0xFD; + if (fdiska == 1) newvalue |= 0x01; + else if (fdiska == 0) newvalue &= 0xFE; + if (fdiskn == 1) newvalue |= (0x01 << ndisk); + else if (fdiskn == 0) newvalue &= ~(0x01 << ndisk); + } + printf("\nSetting Enclosure LEDs to %02x ...\n",newvalue); + ret = set_enc_leds(newvalue); + ret = get_enc_leds(&encled); + show_enc_leds(encled); + } + } + } /*end-else Vitesse*/ + } /*endif fHasEnc*/ + else if (fNSC && fdoencl) { /*Chesnee NSC platform has special disk LEDs*/ + diskled = get_nsc_diskleds(busid); + show_nsc_diskleds(diskled); + if (fsetdisk) { + newvalue = diskled; + // newvalue |= 0xFC; /*leave upper bits high (off) */ + /* Set fault if user param, and disk is present. */ + if (fdiskb == 1) newvalue &= 0xFE; /*bit0=0*/ + else if (fdiskb == 0) newvalue |= 0x01; + if (fdiska == 1) newvalue &= 0xFD; /*bit1=0*/ + else if (fdiska == 0) newvalue |= 0x02; + else if (fdiska == 10) newvalue = 0x00; + printf("\nSetting Disk LEDs to %02x ...\n",newvalue); + ret = set_nsc_diskleds(newvalue,busid); + diskled = get_nsc_diskleds(busid); + show_nsc_diskleds(diskled); + } + } +do_exit: + ipmi_close_(); + // show_outcome(progname,ret); + return (ret); +} /* end main()*/ + +/* end ialarms.c */ diff --git a/util/icmd.c b/util/icmd.c new file mode 100644 index 0000000..5911262 --- /dev/null +++ b/util/icmd.c @@ -0,0 +1,366 @@ +/* + * icmd.c + * + * This tool takes command line input as an IPMI command. + * + * Author: Andy Cress arcress at users.sourceforge.net + * Copyright (c) 2003-2006 Intel Corporation. + * Copyright (c) 2009 Kontron America, Inc. + * + * 03/30/04 Andy Cress - created + * 04/08/04 Andy Cress - display response data, changed usage order + * 05/05/04 Andy Cress - call ipmi_close before exit + * 11/01/04 Andy Cress - add -N / -R for remote nodes + * 12/08/04 Andy Cress v1.5 changed usage order, moved bus to first byte, + * gives better compatibility with ipmicmd.exe. + * 04/13/06 Andy Cress v1.6 fixed istart for -U -R + */ +/*M* +Copyright (c) 2006, Intel Corporation +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions 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. + c.. Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ +#if defined(EFI) + #ifndef NULL + #define NULL 0 + #endif + #include + #include + #include + #include +#else + /* Linux, Solaris, BSD, Windows */ + #include + #include + #include + #include + #include + #include + #ifdef WIN32 + #include "getopt.h" + #elif defined(DOS) + #include + #include "getopt.h" + #elif defined(HPUX) + /* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include + #else + #include + #endif +#endif +#include "ipmicmd.h" +extern void ipmi_lan_set_timeout(int ipmito, int tries, int pingto); + +/* + * Global variables + */ +static char * progver = "2.93"; +static char * progname = "icmd"; +static char fdebug = 0; +static char fquiet = 0; +static char fset_mc = 0; +static char ftest = 0; +static int vend_id; +static int prod_id; +static char fmBMC = 0; +static char fdecimal = 0; +extern int fjustpass; /*see ipmicmd.c*/ + +#define PRIVATE_BUS_ID 0x03 // w Sahalee, the 8574 is on Private Bus 1 +#define PERIPHERAL_BUS_ID 0x24 // w mBMC, the 8574 is on the Peripheral Bus +#define MAXRQLEN 64 +#define MAXRSLEN 200 + +static char usagemsg[] = "Usage: %s [-kqmsxEFNPRTUV] bus rsSa netFn/lun cmd [data bytes]\n"; +static uchar busid = PRIVATE_BUS_ID; +static uchar g_bus = PUBLIC_BUS; +static uchar g_sa = 0; /*0x20*/ +static uchar g_lun = BMC_LUN; +static uchar g_addrtype = ADDR_SMI; + +static int send_icmd(uchar *cmd, int len) +{ + uchar responseData[MAXRSLEN]; + int responseLength; + uchar completionCode; + int ret, i; + uchar netfn, lun; + ushort icmd; + + /* icmd format: 0=bus, 1=rsSa, 2=netFn/lun, 3=cmd, 4-n=data */ + netfn = cmd[2] >> 2; + lun = cmd[2] & 0x03; + icmd = cmd[3] + (netfn << 8); + if (fjustpass) { + ret = ipmi_cmdraw(IPMB_SEND_MESSAGE,NETFN_APP,BMC_SA,0,0, + &cmd[0],(uchar)(len), responseData, &responseLength, + &completionCode, fdebug); + } else { + responseLength = sizeof(responseData); + if (g_addrtype == ADDR_IPMB) { /* && (g_sa != 0) */ + /* if -m used, do ipmi_cmd_mc for IPMB commands */ + ipmi_set_mc(g_bus,g_sa,g_lun,g_addrtype); + ret = ipmi_cmd_mc(icmd, &cmd[4], (uchar)(len-4), responseData, + &responseLength, &completionCode, fdebug); + ipmi_restore_mc(); + } else { + /* ipmi_cmdraw: bus, cmd, netfn, sa, lun, pdata, ... */ + ret = ipmi_cmdraw(cmd[3], netfn, cmd[1], cmd[0], lun, &cmd[4], + (uchar)(len-4), responseData, &responseLength, + &completionCode, fdebug); + } + } + if (ret < 0) { + printf("ipmi_cmd: ret = %d %s\n",ret,decode_rv(ret)); + return(ret); + } else if ((ret != 0) || (completionCode != 0)) { + printf("ipmi_cmd: ret = %d, ccode %02x %s\n", + ret, completionCode, decode_cc(icmd,completionCode)); + return(ret); + } else if (responseLength > 0) { + /* show the response data */ + printf("respData[len=%d]: ",responseLength); + for (i = 0; i < responseLength; i++) + printf("%02x ",responseData[i]); + printf("\n"); + } + return(ret); +} /*end send_icmd()*/ + + +#ifdef METACOMMAND +int i_cmd(int argc, char **argv) +#else +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#endif +{ + int ret = 0; + int c; + uchar devrec[17]; + uchar cmdbuf[MAXRQLEN]; + int maxlen = MAXRQLEN; + int i, j, istart, cmdlen; + int fskipdevid = 0; + int fprivset = 0; + int cmdmin; + char *s1; + + istart = 1; + while ( (c = getopt( argc, argv,"djkm:qst:xN:P:R:U:EF:J:T:V:YZ:?")) != EOF ) + switch(c) { + case 'j': /* just pass the bytes to KCS */ + fjustpass = 1; + break; + case 'd': /* decimal command bytes, skipping bus and sa, + which matches 'ipmitool raw' format. */ + fdecimal = 1; + break; + case 'm': /* specific MC, 3-byte address, e.g. "409600" */ + g_bus = htoi(&optarg[0]); /*bus/channel*/ + g_sa = htoi(&optarg[2]); /*device slave address*/ + g_lun = htoi(&optarg[4]); /*LUN*/ + if (optarg[6] == 's') { + g_addrtype = ADDR_SMI; s1 = "SMI"; + } else { g_addrtype = ADDR_IPMB; s1 = "IPMB"; } + fset_mc = 1; + printf("set MC at %s bus=%x sa=%x lun=%x\n", + s1,g_bus,g_sa,g_lun); + break; + case 'q': fquiet = 1; fskipdevid = 1; break; /* minimal output */ + case 's': fskipdevid = 1; break; /* skip devid */ + case 't': /* set IPMI timeout for ipmilan, usu 2 * 4 = 8 sec */ + i = atoi(optarg); + if (i >= 2) { j = i / 2; i = j; } + else { i = 1; j = 1; } + ipmi_lan_set_timeout(i,j,1); + break; + case 'k': /* check for IPMI access */ + ftest = 1; + break; + case 'x': fdebug = 1; break; /* debug messages */ + case 'V': /* priv level */ + fprivset = 1; + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + break; + default: + printf("%s ver %s\n", progname,progver); + printf(usagemsg, progname); + printf(" where -x shows eXtra debug messages\n"); + printf(" -d decimal input, matching ipmitool syntax\n"); + printf(" -k check for IPMI access\n"); + printf(" -m002000 specific MC (bus 00,sa 20,lun 00)\n"); + printf(" -q quiet mode, with minimal headers\n"); + printf(" -s skips the GetDeviceID command\n"); + print_lan_opt_usage(); + ret = ERR_USAGE; + goto do_exit; + } + + if (ftest) { + ret = ipmi_getdeviceid(devrec,16,fdebug); + if (ret == 0) { + /*check if a driver is loaded, or direct*/ + i = get_driver_type(); + printf("IPMI access is ok, driver type = %s\n",show_driver_type(i)); + if ((i == DRV_KCS) || (i == DRV_SMB)) + printf("Using driverless method\n"); + } + else printf("IPMI access error %d\n",ret); + goto do_exit; + } + + if (!fquiet) { + printf("%s ver %s\n", progname,progver); + printf("This is a test tool to compose IPMI commands.\n"); + printf("Do not use without knowledge of the IPMI specification.\n"); + } + istart = optind; + if (fdebug) printf("icmd: argc=%d istart=%d\n",argc,istart); + + if (fset_mc == 1) { + /* target a specific MC via IPMB (usu a picmg blade) */ + ipmi_set_mc(g_bus,g_sa,g_lun,g_addrtype); + } else g_sa = BMC_SA; + + for (i = 0; i < istart; i++) { + argv++; argc--; + } + if (argc < maxlen) maxlen = argc; + if (fdebug) printf("icmd: len=%d, cmd byte0=%s\n",maxlen,argv[0]); + if (fdecimal) { + uchar b; + cmdbuf[0] = g_bus; + cmdbuf[1] = g_sa; + for (i = 0; i < maxlen; i++) { + if (argv[i][0] == '0' && argv[i][1] == 'x') /*0x00*/ + b = htoi(&argv[i][2]); + else b = atob(argv[i]); /*decimal default, or 0x00*/ + if (i == 0) { /*special handling for netfn */ + cmdbuf[i+2] = (b << 2) | (g_lun & 0x03); + } else + cmdbuf[i+2] = b; + } + cmdlen = i + 2; + } else { + for (i = 0; i < maxlen; i++) { + cmdbuf[i] = htoi(argv[i]); + } + cmdlen = i; + } + + if (fdebug) { + printf("ipmi_cmd: "); + for (i = 0; i < cmdlen; i++) + printf("%02x ",cmdbuf[i]); + printf("\n"); + } + + if (is_remote() && fprivset == 0) { /*IPMI LAN, privilege not set by user*/ + /* commands to other MCs require admin privilege */ + if ((g_sa != BMC_SA) || (cmdbuf[1] != BMC_SA)) + parse_lan_options('V',"4",0); + } + + if (!fskipdevid) { + /* + * Check the Device ID to determine which bus id to use. + */ + ret = ipmi_getdeviceid(devrec,16,fdebug); + if (ret != 0) { + goto do_exit; + } else { + uchar b, j; + char *pstr; + + if (fdebug) { + printf("devid: "); + for (j = 0; j < 16; j++) printf("%02x ",devrec[j]); + printf("\n"); + } + b = devrec[4] & 0x0f; + j = devrec[4] >> 4; + prod_id = devrec[9] + (devrec[10] << 8); + vend_id = devrec[6] + (devrec[7] << 8) + (devrec[8] << 16); + if (vend_id == VENDOR_NSC) { /* NSC = 0x000322 */ + fmBMC = 1; /*NSC miniBMC*/ + } else if (vend_id == VENDOR_INTEL) { /* Intel = 0x000157 */ + switch(prod_id) { + case 0x4311: /* Intel NSI2U*/ + fmBMC = 1; /* Intel miniBMC*/ + break; + case 0x003E: /* NSN2U or CG2100*/ + set_max_kcs_loops(URNLOOPS); /*longer for cmds (default 300)*/ + break; + default: + break; + } + } + if (fmBMC) { /*NSC mini-BMC*/ + pstr = "mBMC"; + busid = PERIPHERAL_BUS_ID; /*used by alarms MWR*/ + } else { /* treat like Intel Sahalee = 57 01 */ + pstr = "BMC"; + busid = PRIVATE_BUS_ID; /*used by alarms MWR*/ + } + printf("-- %s version %x.%x, IPMI version %d.%d \n", + pstr, devrec[2], devrec[3], b, j); + } + // ret = ipmi_getpicmg( devrec, sizeof(devrec),fdebug); + // if (ret == 0) fpicmg = 1; + } /*endif skip devid*/ + + if (fjustpass) cmdmin = 2; + else cmdmin = 4; + if (cmdlen < cmdmin) { + printf("command length (%d) is too short\n",cmdlen); + printf(usagemsg, progname); + } else { + ret = send_icmd(cmdbuf,cmdlen); + if (!fquiet) printf("send_icmd ret = %d\n",ret); + } +do_exit: + ipmi_close_(); + // if (!fquiet) show_outcome(progname,ret); + return (ret); +} /* end main()*/ + +/* end icmd.c */ diff --git a/util/iconfig.c b/util/iconfig.c new file mode 100644 index 0000000..0bb54e9 --- /dev/null +++ b/util/iconfig.c @@ -0,0 +1,2680 @@ +/*--------------------------------------------------------------------------- + * Filename: iconfig.c (was bmcconfig.c) + * + * Author: arcress at users.sourceforge.net + * Copyright (c) 2009 Kontron America, Inc. + * + * Abstract: + * This tool saves and restores the BMC Configuration parameters. + * This includes BMC PEF, LAN, Serial, User, Channel, and SOL parameters. + * + * ----------- Change History ----------------------------------------------- + * 08/18/08 Andy Cress - created from pefconfig.c + */ +/*M* + *--------------------------------------------------------------------------- +Copyright (c) 2009 Kontron America, 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: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions 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. + c.. Neither the name of Kontron nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *--------------------------------------------------------------------------- + *M*/ +#ifdef WIN32 +#include +#include +#include +#include +#include +#include +#include "getopt.h" +#elif defined(DOS) +#include +#include +#include +#include +#include "getopt.h" +#else +#include +#include +#include +#include +#include +#include +#if defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#endif +#ifdef SOLARIS +#include +#define SIOCGIFHWADDR SIOCGENADDR +#define ifr_netmask ifr_ifru.ifru_addr +#elif defined(BSD) +#include +#define SIOCGIFHWADDR SIOCGIFMAC +#define ifr_netmask ifr_ifru.ifru_addr +#elif defined(MACOS) +#include +// #define SIOCGIFHWADDR SIOCGIFMAC +#define ifr_netmask ifr_ifru.ifru_addr +#endif +#include "ipmicmd.h" +#include "oem_intel.h" + +extern int find_ifname(char *ifname); /*see idiscover.c*/ +/* atoip was moved to subs.c, defined in ipmicmd.h */ + +#define SELprintf printf +#define RTF_UP 0x0001 /* route usable */ + +#define SOL_ENABLE_FLAG 0x01 +#define SOL_DISABLE_FLAG 0x00 +#define SOL_PRIVILEGE_LEVEL_USER 0x02 +#define SOL_PREFERRED_BAUD_RATE 0x07 /*19.2k*/ +/* For IPMI 1.5, use Intel SOL commands & subfunctions */ +#define SOL_ENABLE_PARAM 0x01 +#define SOL_AUTHENTICATION_PARAM 0x02 +#define SOL_ACC_INTERVAL_PARAM 0x03 +#define SOL_RETRY_PARAM 0x04 +#define SOL_BAUD_RATE_PARAM 0x05 /*non-volatile*/ +#define SOL_VOL_BAUD_RATE_PARAM 0x06 /*volatile*/ +/* For IPMI 2.0, use IPMI SOL commands & subfunctions */ +#define SOL_ENABLE_PARAM2 0x08 +#define SOL_AUTHENTICATION_PARAM2 0x09 +#define SOL_BAUD_RATE_PARAM2 0x11 + +/* IPMI 2.0 SOL PAYLOAD commands */ +#define SET_PAYLOAD_ACCESS 0x4C +#define GET_PAYLOAD_ACCESS 0x4D +#define GET_PAYLOAD_SUPPORT 0x4E + +/* Channel Access values */ +#define CHAN_ACC_DISABLE 0x20 /* PEF off, disabled*/ +#define CHAN_ACC_PEFON 0x02 /* PEF on, always avail */ +#define CHAN_ACC_PEFOFF 0x22 /* PEF off, always avail*/ +/* special channel access values for ia64 */ +#define CHAN_ACC_PEFON64 0x0A /* PEF on, always avail, UserLevelAuth=off */ +#define CHAN_ACC_PEFOFF64 0x2A /* PEF off, always avail, UserLevelAuth=off */ + + /* TSRLT2/TIGPR2U Channels: 0=IPMB, 1=Serial/EMP, 6=LAN2, 7=LAN1 */ + /* S5000/other Channels: 1=LAN1, 2=LAN2, 3=LAN3, 4=Serial, 6=pci, 7=sys */ +#define LAN_CH 1 +#define SER_CH 4 +#define MAXCHAN 12 /*was 16, reduced for gnu ipmi_lan*/ +#define NUM_DEVICES_TO_CHECK 32 /*for GetBmcEthDevice()*/ +#define MAC_LEN 6 /*length of MAC Address*/ +#define PSW_LEN 16 /*see also PSW_MAX=20 in ipmicmd.h*/ +#define MAXPEF 41 /* max pefnum offset = 40 (41 entries) */ + + /* IP address source values */ +#define SRC_STATIC 0x01 +#define SRC_DHCP 0x02 /* BMC running DHCP */ +#define SRC_BIOS 0x03 /* BIOS, sometimes DHCP */ +#define SRC_OTHER 0x04 + +/* PEF event severities */ +#define PEF_SEV_UNSPEC 0x00 +#define PEF_SEV_MON 0x01 +#define PEF_SEV_INFO 0x02 +#define PEF_SEV_OK 0x04 +#define PEF_SEV_WARN 0x08 +#define PEF_SEV_CRIT 0x10 +#define PEF_SEV_NORECOV 0x20 + +typedef struct +{ /* See IPMI Table 15-2 */ + uchar rec_id; + uchar fconfig; + uchar action; + uchar policy; + uchar severity; + uchar genid1; + uchar genid2; + uchar sensor_type; + uchar sensor_no; + uchar event_trigger; + uchar data1; + uchar mask1; + uchar res[9]; +} PEF_RECORD; + +/* + * Global variables + */ +static char * progver = "2.93"; +static char * progname = "iconfig"; +static char fdebug = 0; +static char fipmilan = 0; +static FILE * fd_bmc = NULL; +static char fIPMI10 = 0; /* =1 if IPMI v1.0 or less */ +static char fIPMI20 = 0; /* =1 if IPMI v2.0 or greater */ +static char fSOL20 = 1; /* =1 if SOL v2.0 is ok */ +static char freadonly = 1; /* =1 to only read LAN & PEF parameters */ +static char func = 'd'; /* function: display, save, restore */ +static char fdomac = 0; /* =1 to restore MAC also */ +static char fpassword = 0; /* =1 user-specified a password, so set it. */ +static uchar fmBMC = 0; +static uchar fiBMC = 0; +static uchar fRomley = 0; +static char fipv6 = 0; +static char fcanonical = 0; +static char fchan2wart = 0; /* =1 if need wart to skip channel 2 */ +static char bdelim = BCOLON; /*':' as default*/ +static char bcomment = BCOMMENT; /* '#' */ +static char pefmax = MAXPEF; /* 20 for Sahalee, 30 for miniBMC */ +static int nerrs = 0; +static int ngood = 0; +static int lasterr = 0; +static uchar nusers = 5; +static uchar max_users = 5; +static uchar enabled_users = 0; +static uchar last_user_enable = 0; /* last user enabled */ +static uchar passwordData[16]; +static uchar fsetifn = 0; +static ushort setsolcmd; +static ushort getsolcmd; +static uchar sol_bchan = 0; +static uchar authmask = 0; +static uchar lan_access = 0x04; /* see SetPassword*/ + +static uchar pefnum = 12; +static uchar fsharedMAC = 0; +//static uchar alertnum = 1; +//static uchar rgdestip[4]; +static uchar rgdestmac[6]; +static uchar rggwymac[6]; +#ifdef WIN32 +static uchar rggwyip[4] = {0,0,0,0}; +static uchar rgmyip [4] = {0,0,0,0}; /*WIN32*/ +static uchar rgmymac[6] = {0xFF,0,0,0,0,0}; /*WIN32*/ +static uchar rgsubnet[4] = {0,0,0,0}; /*WIN32*/ +static uchar osmyip[4] = {0,0,0,0}; +static uchar osmymac[6] = {0xff,0,0,0,0,0}; +#endif +static uchar bmcmyip[4] = {0,0,0,0}; +static uchar bmcdestip[4] = {0,0,0,0}; +static uchar bmcmymac[6] = {0xFF,0,0,0,0,0}; +static char ifname[16] = "eth0"; /* interface name */ +static char ifname0[16] = "eth0"; /* first interface name */ +static char ifpattn[14] = "eth"; /* default, discovered via find_ifname */ +static int vend_id; +static int prod_id; +static uchar ser_ch = 0; /*was SER_CH==4*/ +static uchar lan_ch = LAN_CH; +static uchar lan_ch_parm = 0xff; +static uchar lan_ch_sav = 0xff; +static uchar gcm_ch = 0; +static uchar SessInfo[16]; +static uchar chan_type[MAXCHAN]; +static int nlans = 0; +#define MAX_PEFPARAMS 14 /* max pef params = 14 */ +static char **pefdesc; +static char *pefdesc1[MAXPEF] = { /* for Sahalee BMC */ +/* 0 0x00 */ "", +/* 1 0x01 */ "Temperature Sensor", +/* 2 0x02 */ "Voltage Sensor", +/* 3 0x04 */ "Fan Failure", +/* 4 0x05 */ "Chassis Intrusion", +/* 5 0x08 */ "Power Supply Fault", +/* 6 0x0c */ "Memory ECC Error", +/* 7 0x0f */ "FRB Failure", +/* 8 0x07 */ "BIOS POST Error", +/* 9 0x13 */ "Fatal NMI", +/*10 0x23 */ "Watchdog Timer Reset", +/*11 0x12 */ "System Restart", +/*12 0x20 */ "OS Critical Stop", +/*13 0x09 */ "Power Redundancy Lost", +/*14 0x00 */ "reserved", +/*15 0x00 */ "reserved", +/*16 0x00 */ "reserved", +/*17 */ "reserved", +/*18 */ "reserved", +/*19 */ "reserved", +/*20 */ "reserved", +/*21 */ "reserved", +/*22 */ "reserved", +/*23 */ "reserved", +/*24 */ "reserved", +/*25 */ "reserved", +/*26 */ "reserved", +/*27 */ "reserved", +/*28 */ "reserved", +/*29 */ "unused", +/*30 */ "unused" }; + +static char *pefdesc2[MAXPEF] = { /* for NSC miniBMC */ +/* 0 */ "", +/* 1 0x02*/ "Voltage Sensor Assert", +/* 2 0x23*/ "Watchdog FRB Timeout", /* was "Proc FRB Thermal", */ +/* 3 0x02*/ "Voltage Sensor Deassert", +/* 4 0x07*/ "Proc1 IERR", +/* 5 0xff*/ "Digital Sensor OK", +/* 6 0x14*/ "Chassis Identify", +/* 7 0x13*/ "NMI Button", +/* 8 0x14*/ "Clear CMOS via Panel", +/* 9 0x0f*/ "OS Load POST Code", +/*10 0x20*/ "OS Critical Stop", +/*11 0x09 */ "Power Redundancy Lost", +/*12 0x00*/ "reserved", +/*13 */ "reserved", +/*14 */ "reserved", +/*15 */ "reserved", +/*16 */ "reserved", +/*17 */ "reserved", +/*18 */ "reserved", +/*19 */ "reserved", +/*20 */ "reserved", +/*21 */ "reserved", +/*22 */ "reserved", +/*23 */ "reserved", +/*24 */ "reserved", +/*25 */ "reserved", +/*26 0x05*/ "Chassis Intrusion", +/*27 0x0f*/ "POST Code Error", +/*28 0x02*/ "Voltage Failure", +/*29 0x04*/ "Fan Failure", +/*30 0x01*/ "Temperature Failure"}; + +#define NLAN 39 +static struct { + int cmd; + int sz; + char desc[28]; +} lanparams[NLAN] = { /* see IPMI Table 19-4 */ + /* 0 */ { 0, 1, "Set in progress"}, + /* 1 */ { 1, 1, "Auth type support"}, + /* 2 */ { 2, 5, "Auth type enables"}, + /* 3 */ { 3, 4, "IP address"}, + /* 4 */ { 4, 1, "IP addr src"}, /* (DHCP/Static) */ + /* 5 */ { 5, 6, "MAC addr"}, + /* 6 */ { 6, 4, "Subnet mask"}, + /* 7 */ { 7, 3, "IPv4 header"}, + /* 8 */ { 8, 2, "Prim RMCP port"}, + /* 9 */ { 9, 2, "Sec RMCP port"}, + /* 10 */ {10, 1, "BMC grat ARP"}, + /* 11 */ {11, 1, "grat ARP interval"}, + /* 12 */ {12, 4, "Def gateway IP"}, + /* 13 */ {13, 6, "Def gateway MAC"}, + /* 14 */ {14, 4, "Sec gateway IP"}, + /* 15 */ {15, 6, "Sec gateway MAC"}, + /* 16 */ {16,18, "Community string"}, + /* 17 */ {17, 1, "Num dest"}, + /* 18 */ {18, 5, "Dest type"}, + /* 19 */ {19, 13, "Dest address"}, + /* 20 */ {20, 2, "VLAN ID"}, + /* 21 */ {21, 1, "VLAN Priority"}, + /* 22 */ {22, 1, "Cipher Suite Support"}, + /* 23 */ {23,17, "Cipher Suites"}, + /* 24 */ {24, 9, "Cipher Suite Privilege"}, + /* 25 */ {25, 4, "VLAN Dest Tag"}, + /* 26 */ {96, 28, "OEM Alert String"}, + /* 27 */ {97, 1, "Alert Retry Algorithm"}, + /* 28 */ {98, 3, "UTC Offset"}, + /* 29 */ {102, 1, "IPv6 Enable"}, + /* 30 */ {103, 1, "IPv6 Addr Source"}, + /* 31 */ {104,16, "IPv6 Address"}, + /* 32 */ {105, 1, "IPv6 Prefix Len"}, + /* 33 */ {106,16, "IPv6 Default Gateway"}, + /* 34 */ {108,17, "IPv6 Dest address"}, + /* 35 */ {192, 4, "DHCP Server IP"}, + /* 36 */ {193, 6, "DHCP MAC Address"}, + /* 37 */ {194, 1, "DHCP Enable"}, + /* 38 */ {201, 2, "Channel Access Mode(Lan)"} +}; + +#define NSER 22 /* max=32 */ +static struct { + int cmd; + int sz; + char desc[28]; +} serparams[NSER] = { /* see IPMI Table 20-4 */ + /* 0 */ { 0, 1, "Set in progress"}, + /* 1 */ { 1, 1, "Auth type support"}, + /* 2 */ { 2, 5, "Auth type enables"}, + /* 3 */ { 3, 1, "Connection Mode"}, + /* 4 */ { 4, 1, "Sess Inactiv Timeout"}, + /* 5 */ { 5, 5, "Channel Callback"}, + /* 6 */ { 6, 1, "Session Termination"}, + /* 7 */ { 7, 2, "IPMI Msg Comm"}, + /* 8 */ { 8, 2, "Mux Switch"}, + /* 9 */ { 9, 2, "Modem Ring Time"}, + /* 10 */ {10,17, "Modem Init String"}, + /* 11 */ {11, 5, "Modem Escape Seq"}, + /* 12 */ {12, 8, "Modem Hangup Seq"}, + /* 13 */ {13, 8, "Modem Dial Command"}, + /* 14 */ {14, 1, "Page Blackout Interval"}, + /* 15 */ {15,18, "Community String"}, + /* 16 */ {16, 1, "Num of Alert Dest"}, + /* 17 */ {17, 5, "Destination Info"}, + /* 18 */ {18, 1, "Call Retry Interval"}, + /* 19 */ {19, 3, "Destination Comm Settings"}, + /* 20 */ {29, 2, "Terminal Mode Config"}, + /* 21 */ {201, 2,"Channel Access Mode (Ser)"} +}; + +#define NSYS 6 /* num SystemParam */ +#define CHAS_RESTORE 0x00 /*chassis power restore policy*/ +#define SYS_INFO 0x01 /*System Info (1,2,3,4) */ +#define LAN_FAILOVER 0x02 /*Intel LAN Failover*/ +/* TODO: Future DCMI 1.5 params */ +#define DCMI_POWER 0x03 /*DCMI Power limit*/ +#define DCMI_THERMAL 0x04 /*DCMI Thermal params*/ +#define DCMI_CONFIG 0x05 /*DCMI Config params*/ + +static int GetDeviceID(uchar *pLanRecord) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + int status; + uchar inputData[24]; + uchar completionCode; + + if (pLanRecord == NULL) return(-1); + + status = ipmi_cmd(GET_DEVICE_ID, inputData, 0, responseData, + &responseLength, &completionCode, fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + SELprintf("GetDeviceID: completion code=%x\n", + completionCode); + status = completionCode; + } else { + memcpy(pLanRecord,&responseData[0],responseLength); + set_mfgid(&responseData[0],responseLength); + return(0); // successful, done + } + } /* endif */ + /* if get here, error */ + return(status); +} /*end GetDeviceID() */ + +static int GetChanAcc(uchar chan, uchar parm, uchar *pLanRecord) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + int status; + uchar inputData[24]; + uchar completionCode; + + if (pLanRecord == NULL) return(-1); + responseLength = 3; + inputData[0] = chan; + inputData[1] = parm; /* 0x80 = active, 0x40 = non-volatile */ + responseLength = sizeof(responseData); + status = ipmi_cmd(GET_CHANNEL_ACC, inputData, 2, responseData, + &responseLength, &completionCode, fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + SELprintf("%c GetChanAcc: completion code=%x\n", + bcomment,completionCode); + status = completionCode; + } else { + // dont copy first byte (Parameter revision, usu 0x11) + memcpy(pLanRecord,&responseData[0],responseLength); + return(0); // successful, done + } + } /* endif */ + /* if get here, error */ + return(status); +} /*GetChanAcc()*/ + +static int SetChanAcc(uchar chan, uchar parm, uchar val, uchar access) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + int status; + uchar inputData[24]; + uchar completionCode; + + if (fmBMC) return(0); /* mBMC doesn't support this */ + /* parm: 0x80 = active, 0x40 = set non-vol*/ + responseLength = 1; + inputData[0] = chan; /* channel */ + inputData[1] = (parm & 0xc0) | (val & 0x3F); + inputData[2] = (parm & 0xc0) | access; /* set priv level */ + + responseLength = sizeof(responseData); + status = ipmi_cmd(SET_CHANNEL_ACC, inputData, 3, responseData, + &responseLength, &completionCode, fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + SELprintf("SetChanAcc: completion code=%x\n", + completionCode); + status = completionCode; + } else { + return(0); // successful, done + } + } /* endif */ + /* if get here, error */ + return(status); +} /*SetChanAcc()*/ + +static int GetUser(int user_num) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + int status, i; + uchar completionCode; + char inputData[24]; + + inputData[0] = lan_ch; + inputData[1] = (uchar)user_num; /* usually = 1 for BMC LAN */ + responseLength = sizeof(responseData); + status = ipmi_cmd(GET_USER_ACCESS, inputData, 2, responseData, + &responseLength, &completionCode, fdebug); + if (status == 0 && completionCode == 0) { + uchar c; + if (user_num == 1) { + max_users = responseData[0] & 0x3f; + enabled_users = responseData[1] & 0x3f; + if (enabled_users > nusers) nusers = enabled_users; + } + fprintf(fd_bmc,"UserAccess %d,%d%c %02x %02x %02x %02x \n", + lan_ch,user_num,bdelim,responseData[0],responseData[1], + responseData[2], responseData[3]); + c = responseData[3]; + inputData[0] = (uchar)user_num; /* usually = 1 for BMC LAN */ + responseLength = sizeof(responseData); + status = ipmi_cmd(GET_USER_NAME, inputData, 1, responseData, + &responseLength, &completionCode, fdebug); + if (status != 0 || completionCode != 0) + responseData[0] = 0; + else { + fprintf(fd_bmc,"UserName %d%c",user_num,bdelim); + for (i=0; i< responseLength; i++) + fprintf(fd_bmc," %02x",responseData[i]); + fprintf(fd_bmc,"\n"); + fprintf(fd_bmc,"%c UserPassword %d%c",bcomment,user_num,bdelim); + for (i=0; i< PSW_LEN; i++) + fprintf(fd_bmc," 00"); + fprintf(fd_bmc,"\n"); + } + } else + printf("%c GetUserAccess(%d,%d), status=%x, ccode=%x\n", + bcomment,lan_ch,user_num, status, completionCode); + return(status); +} /*end GetUser()*/ + +static int GetSerEntry(uchar subfunc, uchar bset, uchar *pLanRecord) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + uchar inputData[24]; + int status; + uchar completionCode; + uchar chan; + + if (pLanRecord == NULL) + { + if (fdebug) + printf("GetSerEntry(%d): error, output buffer is NULL\n",subfunc); + return (-1); + } + + chan = ser_ch; /* 1=EMP, 0=IPMB, 6=LAN2, 7=LAN1 */ + + inputData[0] = chan; // flags, channel 3:0 (1=EMP) + inputData[1] = subfunc; // Param selector + inputData[2] = bset; // Set selector + inputData[3] = 0; // Block selector + if (subfunc == 10) { + inputData[2] = 0; + inputData[3] = 1; + } + + status = ipmi_cmd(GET_SER_CONFIG, inputData, 4, responseData, + &responseLength, &completionCode, fdebug); + if (status == ACCESS_OK) { + if( completionCode ) { + if (fdebug) + SELprintf("GetSerEntry(%d,%d): completion code=%x\n", + chan,subfunc,completionCode); + status = completionCode; + } else { + // dont copy first byte (Parameter revision, usu 0x11) + memcpy(pLanRecord,&responseData[1],responseLength-1); + pLanRecord[responseLength-1] = 0; + //successful, done + return(0); + } + } + + // we are here because completionCode is not COMPLETION_CODE_OK + if (fdebug) + SELprintf("GetSerEntry(%d,%d): ipmi_cmd status=%x ccode=%x\n", + chan,subfunc,status,completionCode); + return status; +} + +static int SetSerEntry(uchar subfunc, uchar *pSerRecord, int reqlen) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + uchar inputData[24]; + int status; + uchar completionCode; + + if (pSerRecord == NULL) { + if (fdebug) + printf("SetSerEntry(%d): error, input buffer is NULL\n", + subfunc); + return (-1); + } + inputData[0] = ser_ch; // flags, channel 3:0 (EMP) + inputData[1] = subfunc; // Param selector + memcpy(&inputData[2],pSerRecord,reqlen); + status = ipmi_cmd(SET_SER_CONFIG, inputData, (uchar)(reqlen+2), + responseData, &responseLength, &completionCode, fdebug); + + if (fdebug) + printf("SetSerEntry: ipmi_cmd status=%d, completion code=%d\n", + status,completionCode); + if (status == ACCESS_OK) { + if( completionCode ) { + status = completionCode; + if (completionCode == 0x80) + printf("SetSerEntry(%d): Parameter not supported\n", + subfunc); + else + printf("SetSerEntry(%d): completion code=%x\n", + subfunc, completionCode); + } + // else successful, done + } + return status; +} /* end SetSerEntry() */ + +static int GetLanEntry(uchar subfunc, uchar bset, uchar *pLanRecord) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + uchar inputData[24]; + int status, n; + uchar completionCode; + uchar chan; + + if (pLanRecord == NULL) { + if (fdebug) printf("GetLanEntry: error, output buffer is NULL\n"); + return (-1); + } + + chan = lan_ch; /* LAN 1 = 7 */ + + inputData[0] = chan; // flags, channel 3:0 (LAN 1) + inputData[1] = subfunc; // Param selector (3 = ip addr) + inputData[2] = bset; // Set selector + inputData[3] = 0; // Block selector + + status = ipmi_cmd(GET_LAN_CONFIG, inputData, 4, responseData, + &responseLength, &completionCode, fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + if (fdebug) + SELprintf("GetLanEntry(%d,%d): completion code=%x\n", + chan,subfunc,completionCode); + status = completionCode; + } else { + // dont copy first byte (Parameter revision, usu 0x11) + if (responseLength > 0) { + n = responseLength-1; + memcpy(pLanRecord,&responseData[1],n); + } else n = 0; + pLanRecord[n] = 0; + //successful, done + return(0); + } + } + + // we are here because completionCode is not COMPLETION_CODE_OK + if (fdebug) + SELprintf("GetLanEntry(%d,%d): status=%d completionCode=%x\n", + chan,subfunc,status,completionCode); + return (status); +} /* end GetLanEntry() */ + +static int SetLanEntry(uchar subfunc, uchar *pLanRecord, int reqlen) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + uchar inputData[24]; + int status; + uchar completionCode; + + if (pLanRecord == NULL) + { + if (fdebug) + printf("SetLanEntry(%d): error, input buffer is NULL\n",subfunc); + return (-1); + } + + if ((vend_id == VENDOR_SUPERMICROX) || + (vend_id == VENDOR_SUPERMICRO)) { + /* SUPERMICRO cannot set grat arp or grat arp interval */ + if (subfunc == 10 || subfunc == 11) return(0); + } + inputData[0] = lan_ch; // flags, channel 3:0 (LAN 1) + inputData[1] = subfunc; // Param selector (3 = ip addr) + memcpy(&inputData[2],pLanRecord,reqlen); + + status = ipmi_cmd(SET_LAN_CONFIG, inputData, (uchar)(reqlen+2), + responseData, &responseLength,&completionCode,fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + if (fdebug) + SELprintf("SetLanEntry(%d,%d): completion code=%x\n", + lan_ch,subfunc,completionCode); + return(completionCode); + } else { + //successful, done + return(0); + } + } + + // we are here because completionCode is not COMPLETION_CODE_OK + if (fdebug) + SELprintf("SetLanEntry(%d,%d): ipmi_cmd status=%d ccode=%x\n", + lan_ch,subfunc,status,completionCode); + return (status); +} /* end SetLanEntry() */ + +static int GetPefEntry(uchar subfunc, ushort rec_id, PEF_RECORD *pPefRecord) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + uchar inputData[24]; + int status, n; + uchar completionCode; + + if (pPefRecord == NULL) + { + if (fdebug) + printf("GetPefEntry(%d): error, output buffer is NULL\n",subfunc); + return (-1); + } + + inputData[0] = subfunc; // Parameter = Evt Filter Table + inputData[1] = (uchar)rec_id; + inputData[2] = 0; + + status = ipmi_cmd(GET_PEF_CONFIG, inputData, 3, responseData, + &responseLength, &completionCode, fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + if (fdebug) + SELprintf("GetPefEntry(%d/%d): completion code=%x\n", + subfunc,rec_id,completionCode); + status = completionCode; + } else { + /* expect PEF record to be >=21 bytes */ + if (responseLength > 1) n = responseLength-1; + else n = 0; + if (n > 21) n = 21; + // dont copy first byte (Parameter revision, usu 0x11) + if (n == 0) memset(pPefRecord,0,21); + else memcpy(pPefRecord,&responseData[1],n); + //successful, done + return(0); + } + } + + // we are here because completionCode is not COMPLETION_CODE_OK + if (fdebug) + SELprintf("GetPefEntry: ipmi_cmd status=%x completionCode=%x\n", + status, completionCode); + return status; +} /* end GetPefEntry() */ + +static int SetPefEntry(PEF_RECORD *pPefRecord) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + uchar inputData[24]; /* sizeof(PEF_RECORD) = 21 +1=22 */ + int status; + uchar completionCode; + uchar subfunc; + + subfunc = 0x06; // Parameter = Evt Filter Table + + if (pPefRecord == NULL) { + if (fdebug) + printf("SetPefEntry: error, output buffer is NULL\n"); + return (-1); + } + + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 + // 06 0c 80 01 01 00 ff ff 20 ff 6f ff 00 00 00 00 00 00 00 00 00 00 + // memset(&inputData[0],0,requestData.dataLength); + inputData[0] = subfunc; + memcpy(&inputData[1],pPefRecord,sizeof(PEF_RECORD)); + + status = ipmi_cmd(SET_PEF_CONFIG, inputData, sizeof(PEF_RECORD)+1, + responseData, &responseLength, &completionCode, fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + if (fdebug) + SELprintf("SetPefEntry: completion code=%x\n", + completionCode); // responseData[0]); + status = completionCode; + } else { + //successful, done + return(0); + } + + } + + // we are here because completionCode is not COMPLETION_CODE_OK + if (fdebug) + SELprintf("SetPefEntry: ipmi_cmd status=%d ccode=%x\n", + status,completionCode); + return(status); + +} /* end SetPefEntry() */ + +static int MacIsValid(uchar *mac) +{ + int fvalid = 0; + int i; + /* check for initial invalid value of FF:00:... */ + if (mac[0] == 0xFF && mac[1] == 0x00) /* marked as invalid */ + return(fvalid); + /* check for all zeros */ + for (i = 0; i < MAC_LEN; i++) + if (mac[i] != 0) { /* not all zeros */ + fvalid = 1; + break; + } + return(fvalid); +} + +static int IpIsValid(uchar *ipadr) +{ + int fvalid = 1; + if (ipadr[0] == 0) fvalid = 0; + return(fvalid); +} + +static int SubnetIsValid(uchar *subnet) +{ + int fvalid = 0; + /* if masking off at least one bit, say valid */ + if ((subnet[0] & 0x80) == 0x80) fvalid = 1; + return(fvalid); +} + +#ifdef WIN32 +/* + * Obtain network adapter information (Windows). + */ +static PIP_ADAPTER_ADDRESSES GetAdapters() { + PIP_ADAPTER_ADDRESSES AdapterAddresses = NULL; + ULONG OutBufferLength = 0; + ULONG RetVal = 0, i; + + // The size of the buffer can be different + // between consecutive API calls. + // In most cases, i < 2 is sufficient; + // One call to get the size and one call to get the actual parameters. + // But if one more interface is added or addresses are added, + // the call again fails with BUFFER_OVERFLOW. + // So the number is picked slightly greater than 2. + // We use i <5 in the example + for (i = 0; i < 5; i++) { + RetVal = GetAdaptersAddresses( + AF_INET, 0, NULL, + AdapterAddresses, + &OutBufferLength); + + if (RetVal != ERROR_BUFFER_OVERFLOW) { + break; + } + + if (AdapterAddresses != NULL) { + free(AdapterAddresses); + } + + AdapterAddresses = (PIP_ADAPTER_ADDRESSES) malloc(OutBufferLength); + if (AdapterAddresses == NULL) { + RetVal = GetLastError(); + break; + } + } + if (RetVal == NO_ERROR) { + // If successful, return pointer to structure + return AdapterAddresses; + } + else { + LPVOID MsgBuf; + + printf("Call to GetAdaptersAddresses failed.\n"); + if (FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + RetVal, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &MsgBuf, + 0, + NULL )) { + printf("\tError: %s", MsgBuf); + } + LocalFree(MsgBuf); + } + return NULL; +} + +/* + * Set BMC MAC corresponding to current BMC IP address (Windows). + */ +static int GetLocalMACByIP() { + PIP_ADAPTER_ADDRESSES AdapterAddresses = NULL; + PIP_ADAPTER_ADDRESSES AdapterList; + int result = 0; + + struct sockaddr_in *si; + + AdapterAddresses = GetAdapters(); + AdapterList = AdapterAddresses; + + while (AdapterList) { + PIP_ADAPTER_UNICAST_ADDRESS addr; + addr = AdapterList->FirstUnicastAddress; + if (addr == NULL) si = NULL; + else si = (struct sockaddr_in*)addr->Address.lpSockaddr; + if (si != NULL) { + if(memcmp(&si->sin_addr.s_addr, rgmyip, 4) == 0) { + memcpy(rgmymac, AdapterList->PhysicalAddress, MAC_LEN); + result = 1; + break; + } + } + AdapterList = AdapterList->Next; + } + + if (AdapterAddresses != NULL) { + free(AdapterAddresses); + } + return result; +} + +/* + * Set BMC MAC corresponding to current BMC IP address (Windows). + */ +static int GetLocalIPByMAC(uchar *macadr) { + PIP_ADAPTER_ADDRESSES AdapterAddresses = NULL; + PIP_ADAPTER_ADDRESSES AdapterList; + int result = 0; + + struct sockaddr_in *si; + + AdapterAddresses = GetAdapters(); + AdapterList = AdapterAddresses; + + while (AdapterList) { + PIP_ADAPTER_UNICAST_ADDRESS addr; + if(memcmp(AdapterList->PhysicalAddress, macadr, MAC_LEN) == 0) { + addr = AdapterList->FirstUnicastAddress; + + si = (struct sockaddr_in*)addr->Address.lpSockaddr; + if (fdebug) { + uchar *psaddr; + psaddr = (uchar *)&si->sin_addr.s_addr; + printf("mac match: rgmyip=%d.%d.%d.%d s_addr=%d.%d.%d.%d\n", + rgmyip[0], rgmyip[1], rgmyip[2], rgmyip[3], + psaddr[0], psaddr[1], psaddr[2], psaddr[3]); + } + if (!IpIsValid(rgmyip) && (fsharedMAC==1)) /*not specified, shared*/ + memcpy(rgmyip, &si->sin_addr.s_addr, 4); + memcpy(osmyip, &si->sin_addr.s_addr, 4); + memcpy(osmymac, AdapterList->PhysicalAddress, MAC_LEN); + wcstombs(ifname,AdapterList->FriendlyName, sizeof(ifname)); + result = 1; + break; + } + AdapterList = AdapterList->Next; + } + + if (AdapterAddresses != NULL) { + free(AdapterAddresses); + } + return result; +} + +/* + * Set MAC and IP address from given interface name (Windows). + */ +static int GetLocalDataByIface() { + PIP_ADAPTER_ADDRESSES AdapterAddresses = NULL; + PIP_ADAPTER_ADDRESSES AdapterList; + int result = 0; + + size_t origsize, newsize, convertedChars; + wchar_t* wcstring; + struct sockaddr_in *si; + + AdapterAddresses = GetAdapters(); + AdapterList = AdapterAddresses; + + origsize = strlen(ifname) + 1; + newsize = origsize; + convertedChars = 0; + wcstring = (wchar_t*) malloc(sizeof(wchar_t) * newsize) ; + if (wcstring == NULL) AdapterList = NULL; /*skip loop, do free*/ + else mbstowcs(wcstring, ifname, origsize ); + + while (AdapterList) { + PIP_ADAPTER_UNICAST_ADDRESS addr; + if(wcsstr(AdapterList->FriendlyName, wcstring)) { + printf("Using interface: %S\n", AdapterList->FriendlyName); + printf("\t%S\n", AdapterList->Description); + addr = AdapterList->FirstUnicastAddress; + + si = (struct sockaddr_in*)addr->Address.lpSockaddr; + memcpy(rgmyip, &si->sin_addr.s_addr, 4); + memcpy(rgmymac, AdapterList->PhysicalAddress, MAC_LEN); + + result = 1; + break; + } + AdapterList = AdapterList->Next; + } + + if (AdapterAddresses != NULL) { + free(AdapterAddresses); + } + return result; +} + +static int FindEthNum(uchar *macadrin) +{ + int i; + uchar macadr[MAC_LEN]; + memcpy(macadr,macadrin,MAC_LEN); + if (fsharedMAC == 0 && vend_id == VENDOR_INTEL) { + /* Intel factory assigns them this way, so use that to compare */ + macadr[MAC_LEN-1] -= 2; /*OS MAC = BMC MAC - 2*/ + } + i = GetLocalIPByMAC(macadr); + if (fdebug) /* show the local OS eth if and MAC */ + printf("FindEth: OS %s IP=%d.%d.%d.%d MAC=%02x:%02x:%02x:%02x:%02x:%02x\n", + ifname, rgmyip[0], rgmyip[1], rgmyip[2], rgmyip[3], + rgmymac[0], rgmymac[1], rgmymac[2], rgmymac[3], + rgmymac[4], rgmymac[5]); + /* The actual Windows ethernet interface is determined + * in Get_IPMac_Addr using ipconfig, so + * init eth interface number as eth0 for Windows. */ + return(i); +} +#elif defined(HPUX) +static int FindEthNum(uchar *macadrin) +{ + return(0); +} +#else +/* Linux, BSD, Solaris */ +static char *get_ifreq_mac(struct ifreq *ifrq) +{ + char *ptr; +#ifdef SOLARIS + ptr = (char *)&ifrq->ifr_ifru.ifru_enaddr[0]; +#elif BSD + ptr = (char *)&ifrq->ifr_ifru.ifru_addr.sa_data[0]; +#elif MACOS + static uchar mactmp[MAC_LEN]; + ptr = &mactmp[0]; + MacSetInvalid(ptr); +#else + ptr = (char *)&ifrq->ifr_hwaddr.sa_data[0]; +#endif + return (ptr); +} + + +static int FindEthNum(uchar *macadrin) +{ /*only used for Linux*/ + struct ifreq ifr; + int skfd; + int nCurDevice; + uchar macadr[MAC_LEN]; + char szDeviceName[ 16 ]; /* sizeof(ifpattn), MAX_DEVICE_NAME_LENGTH + 1 */ + int devnum = -1; + int n; + + memcpy(macadr,macadrin,MAC_LEN); + if (fsharedMAC == 0 && vend_id == VENDOR_INTEL) { + /* Intel factory assigns them this way, so use that to compare */ + macadr[MAC_LEN-1] -= 2; /*OS MAC = BMC MAC - 2*/ + } + n = find_ifname(szDeviceName); + if (n >= 0) { + n = strlen_(szDeviceName); + if (n < sizeof(ifpattn)) { + strcpy(ifname0,szDeviceName); + strcpy(ifpattn,szDeviceName); + ifpattn[n - 1] = 0; /*truncate last digit*/ + } + if (fdebug) + printf("found ifname %s, pattern %s\n",szDeviceName,ifpattn); + } + + if ( ( skfd = socket(AF_INET, SOCK_DGRAM, 0 ) ) < 0) { + if ( fdebug ) { + perror("socket"); + return devnum; + } + } + + for( nCurDevice = 0 ; + (nCurDevice < NUM_DEVICES_TO_CHECK) && (devnum == -1); + nCurDevice++ ) + { + sprintf( szDeviceName, "%s%d", ifpattn, nCurDevice ); + strcpy(ifr.ifr_name, szDeviceName ); +#ifdef SIOCGIFHWADDR + if (ioctl(skfd, SIOCGIFHWADDR, &ifr) > 0) { + if ( fdebug ) + printf("FindEthNum: Could not get MAC address for %s\n", + szDeviceName); + } else +#endif + { + if (memcmp(get_ifreq_mac(&ifr), macadr, MAC_LEN) == 0) { + devnum = nCurDevice; + break; + } + } + } + close(skfd); + return(devnum); +} +#endif + +/* + * GetBmcEthDevice + * Attempt to auto-detect the BMC LAN channel and matching OS eth port. + * INPUT: lan_parm = lan channel from user -L option, 0xFF if not specified + * OUTPUT: lan_ch is set to BMC LAN channel number + * if success, returns index of OS eth port (0, 1, ...). + * if no lan channels found, returns -2. + * if other error, returns -1. + */ +static int GetBmcEthDevice(uchar lan_parm) +{ + uchar LanRecord[30]; + int devnum = -1; + int ret; + uchar bmcMacAddress[ MAC_LEN ]; /*MAC_LEN = 6*/ + int rlen; + uchar iData[2]; + uchar rData[10]; + uchar cc; + int i = 0; + int j, jstart, jend, jlan; + uchar mtype; + uchar *pb; + int fchgmac; + + /* Find the LAN channel(s) via Channel Info */ + if (lan_parm < MAXCHAN) { /* try user-specified channel only */ + lan_ch = lan_parm; + jstart = lan_parm; + jend = lan_parm+1; + } else { + jstart = 1; + jend = MAXCHAN; + for (j = 0; j < MAXCHAN; j++) chan_type[j] = 0; + } + memset(bmcMacAddress,0xff,sizeof(bmcMacAddress)); /*initialize to invalid*/ + for (j = jstart; j < jend; j++) { + rlen = sizeof(rData); + iData[0] = (uchar)j; /*channel #*/ + memset(rData,0,9); /*initialize recv data*/ + ret = ipmi_cmd(GET_CHANNEL_INFO, iData, 1, rData, &rlen, &cc, fdebug); + if (ret == 0xcc || cc == 0xcc) /* special case for ipmi_lan */ + continue; + if (ret != 0) { + if (fdebug) printf("get_chan_info rc = %x\n",ret); + break; + } + mtype = rData[1]; /* channel medium type */ + chan_type[j] = mtype; + if (mtype == 4) { /* 802.3 LAN type*/ + if (fdebug) printf("chan[%d] = lan\n",j); + jlan = lan_ch; /*save prev lan chan */ + /* Get BMC MAC for this LAN channel. */ + /* Note: BMC MAC may not be valid yet. */ + lan_ch = (uchar)j; /*set lan channel for GetLanEntry()*/ + ret = GetLanEntry( 5 /*MAC_ADDRESS_LAN_PARAM*/,0, LanRecord); + if ( ret < 0 ) { + lan_ch = (uchar)jlan; /*restore lan_ch*/ + printf( "GetBmcEthDevice: GetLanEntry failed\n" ); + return devnum; + } + pb = &LanRecord[0]; + if (fdebug) printf("chan[%d] BMC MAC %x:%x:%x:%x:%x:%x\n",j, + pb[0], pb[1], pb[2], pb[3], pb[4], pb[5] ); + fchgmac = 0; + if (!MacIsValid(bmcMacAddress)) /* old MAC not valid */ + fchgmac = 1; + else if (MacIsValid(pb) && /* new MAC is valid and */ + (memcmp(bmcMacAddress,pb, sizeof(bmcMacAddress)) > 0)) + fchgmac = 1; /* new MAC lower */ + if (fchgmac) { /* use lowest valid MAC */ + memcpy(bmcMacAddress,pb,sizeof(bmcMacAddress)); + lan_ch = (uchar)j; + } else lan_ch = (uchar)jlan; /* restore prev lan chan */ + i++; /* i = num lan channels found */ + } else if (mtype == 5) { /* serial type*/ + if (fdebug) printf("chan[%d] = serial\n",j); + ser_ch = (uchar)j; /* set to last serial channel */ + } else if (mtype == 7) { /* PCI SMBus */ + if (fdebug) printf("chan[%d] = pci_smbus\n",j); + } else if (mtype == 12) { /* system interface */ + if (fdebug) printf("chan[%d] = system_interface\n",j); + } else /* other channel medium types, see IPMI 1.5 Table 6-3 */ + if (fdebug) printf("chan[%d] = %d\n",j,mtype); + } + nlans = i; + if (i == 0) return(-2); /* no lan channels found */ + if (fdebug) printf("lan_ch detected = %d\n",lan_ch); + + devnum = FindEthNum(bmcMacAddress); + if ( fdebug ) + printf("GetBmcEthDevice: channel %d, %s%d\n",lan_ch,ifpattn,devnum); + return devnum; +} + +/* + * atomac - converts ASCII string to binary MAC address (array). + * Accepts input formatted as 11:22:33:44:55:66 or 11-22-33-44-55-66. + */ +static void atomac(uchar *array, char *instr) +{ + int i,j,n; + char *pi; + j = 0; + pi = instr; + n = strlen_(instr); + for (i = 0; i <= n; i++) { + if (instr[i] == ':') { + array[j++] = htoi(pi); + pi = &instr[i+1]; + } else if (instr[i] == '-') { + array[j++] = htoi(pi); + pi = &instr[i+1]; + } else if (instr[i] == 0) { + array[j++] = htoi(pi); + } + if (j >= MAC_LEN) break; /*safety valve*/ + } + if (fdebug) + printf("atomac: %02x %02x %02x %02x %02x %02x\n", + array[0],array[1],array[2],array[3], array[4],array[5]); +} /*end atomac()*/ + +/* file_grep/findmatch no longer used here, see ievents.c */ + +/* + * Get_Mac + * This routine finds a MAC address from a given IP address. + * Usually for the Alert destination. + * It uses ARP cache to do this. + */ +#ifdef WIN32 +static int Get_Mac(uchar *ipadr,uchar *macadr) +{ + DWORD dwRetVal; + IPAddr DestIp = 0; + IPAddr SrcIp = 0; /* default for src ip */ + ULONG MacAddr[2]; /* for 6-byte hardware addresses */ + ULONG PhysAddrLen = MAC_LEN; /* default to length of six bytes */ + BYTE *bPhysAddr; + + + memcpy(&DestIp, ipadr, 4); + + /* invoke system ARP query */ + dwRetVal = SendARP(DestIp, SrcIp, MacAddr, &PhysAddrLen); + + if (dwRetVal == NO_ERROR) + { /* no error - get the MAC */ + bPhysAddr = (BYTE *) & MacAddr; + if (PhysAddrLen) { + memcpy(macadr, bPhysAddr, MAC_LEN); + } else + printf("Warning: SendArp completed successfully, but returned length=0\n"); + } else if (dwRetVal == ERROR_GEN_FAILURE) + { /* MAC not available in this netowork - get gateway MAC */ + memcpy(macadr, rggwymac, MAC_LEN); + } else + { /* other errors */ + printf("Error: SendArp failed with error: %d", dwRetVal); + switch (dwRetVal) { + case ERROR_INVALID_PARAMETER: + printf(" (ERROR_INVALID_PARAMETER)\n"); + break; + case ERROR_INVALID_USER_BUFFER: + printf(" (ERROR_INVALID_USER_BUFFER)\n"); + break; + case ERROR_BAD_NET_NAME: + printf(" (ERROR_GEN_FAILURE)\n"); + break; + case ERROR_BUFFER_OVERFLOW: + printf(" (ERROR_BUFFER_OVERFLOW)\n"); + break; + case ERROR_NOT_FOUND: + printf(" (ERROR_NOT_FOUND)\n"); + break; + default: + printf("\n"); + break; + } + return 1; + } + return 0; +} /* end Get_Mac()*/ +/*endif WIN32 */ +#else +/*else Linux */ +static int Get_Mac(uchar *ipadr,uchar *macadr) +{ + FILE *fparp; + char buff[1024]; + /* char arpfile[] = "/proc/net/arp"; */ + char alertfile[] = "/tmp/dest.arping"; + char arping_cmd[128]; + char *pb, *pm, *px; + int num, i; + int foundit = 0; + int ret = 0; + char *_ifname; + + if (strcmp(ifname,"gcm") == 0) _ifname = ifname0; + else _ifname = ifname; + + /* Get a MAC address for a given IP address */ + if (ipadr[0] != 0) { /* if valid IP address */ + + /* make sure the destination is in the arp cache */ + sprintf(arping_cmd, + "arping -I %s -c 2 %d.%d.%d.%d |grep reply |tail -n1 >%s\n", + _ifname,ipadr[0],ipadr[1],ipadr[2],ipadr[3],alertfile); + if (fdebug) printf("%s", arping_cmd); + system(arping_cmd); + + fparp = fopen(alertfile,"r"); + if (fparp == NULL) { + fprintf(stdout,"Get_Mac: Cannot open %s, errno = %d\n", + alertfile,get_errno()); + ret = -1; + } else { + while (fgets(buff, 1023, fparp)) { + /* should only run through loop once */ + num = strcspn(buff," \t"); /* skip 1st word ("Unicast") */ + i = strspn(&buff[num]," \t"); + pb = &buff[num+i]; + if (strncmp(pb,"reply",5) == 0) { /* valid output */ + /* Find the ip address */ + pb += 6 + 5; /* skip "reply from " */ + num = strcspn(pb," \t"); + pb[num] = 0; + if (fdebug) printf("Alert ip=%s\n",pb); + /* IP address should already match input param */ + /* if (rgdestip[0] == 0) atoip(rgdestip,pb); */ + /* Now find the mac address */ + pm = strchr(&pb[num+1],'['); + if (pm == NULL) pm = &pb[num+2]; /* just in case */ + pm++; + px = strchr(pm,']'); + if (px == NULL) px = pm + 17; /* just in case */ + px[0] = 0; + if (fdebug) printf("Alert mac=%s\n",pm); + foundit = 1; + if (!MacIsValid(macadr)) atomac(macadr,pm); + break; + } + } /*end while*/ + fclose(fparp); + } /*end else file opened*/ + } /*endif valid IP */ + else ret = -1; + + if (ret == -1 || foundit == 0) { /* couldn't get it */ + if (MacIsValid(rggwymac) && !MacIsValid(rgdestmac)) + memcpy(rgdestmac,rggwymac,6); /* get to it from the default gateway */ + } + return(ret); +} /* end Get_Mac()*/ +/*end else Linux*/ +#endif + +#ifdef WIN32 + +/* + * Set subnet mask based on current IP address (Windows). + */ +static int SetSubnetMask() { + PMIB_IPADDRTABLE pIPAddrTable; + unsigned int i; + DWORD dwSize = 0, dwRetVal; + LPVOID lpMsgBuf; + + pIPAddrTable = (MIB_IPADDRTABLE*) malloc( sizeof( MIB_IPADDRTABLE) ); + + if ( pIPAddrTable ) { + // Make an initial call to GetIpAddrTable to get the + // necessary size into the dwSize variable + if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) { + free( pIPAddrTable ); + pIPAddrTable = (MIB_IPADDRTABLE *) malloc ( dwSize ); + } + } else + printf("Memory allocation failed.\n"); + + if ( pIPAddrTable ) { + // Make a second call to GetIpAddrTable to get the + // actual data we want + if ( (dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 )) == NO_ERROR ) { + for(i = 0; i < pIPAddrTable->dwNumEntries; ++i) { + if(memcmp(&(pIPAddrTable->table[i].dwAddr), rgmyip, 4) == 0) { + memcpy(rgsubnet, &(pIPAddrTable->table[i].dwMask), 4); + free( pIPAddrTable ); + return 1; + } + } + } else { + if (FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + dwRetVal, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &lpMsgBuf, + 0, + NULL )) { + printf("\tError: %s", lpMsgBuf); + } + + printf("Call to GetIpAddrTable failed.\n"); + } + } + + if ( pIPAddrTable ) + free( pIPAddrTable ); + + return 0; +} + +/* + * Extract gateway address from routing table (Windows). + */ +static int SetDefaultGateway() { + PMIB_IPFORWARDTABLE pIpForwardTable; + DWORD dwRetVal, dwSize; + + unsigned int nord_mask; + unsigned int nord_ip; + unsigned int nord_net; + + unsigned int i; + + nord_mask = *((unsigned int *)rgsubnet); + nord_ip = *((unsigned int *)rgmyip); + + nord_net = nord_ip & nord_mask; + + pIpForwardTable = (MIB_IPFORWARDTABLE*) malloc(sizeof(MIB_IPFORWARDTABLE)); + if (pIpForwardTable == NULL) { + printf("Error allocating memory\n"); + return 0; + } + + dwSize = 0; + if (GetIpForwardTable(pIpForwardTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) { + free(pIpForwardTable); + pIpForwardTable = (MIB_IPFORWARDTABLE*) malloc(dwSize); + if (pIpForwardTable == NULL) { + printf("Error allocating memory\n"); + return 0; + } + } + + /* + * Note that the IPv4 addresses returned in + * GetIpForwardTable entries are in network byte order + */ + if ((dwRetVal = GetIpForwardTable(pIpForwardTable, &dwSize, 0)) == NO_ERROR) { + for (i = 0; i < (int) pIpForwardTable->dwNumEntries; i++) { + unsigned int gwaddr = pIpForwardTable->table[i].dwForwardNextHop; + if(nord_net == (gwaddr & nord_mask) && nord_ip != gwaddr) + { /* searching for gateways from our network with different address than ours */ + memcpy(rggwyip, &gwaddr, 4); + return 0; + } + } + free(pIpForwardTable); + return 1; + } + else { + printf("\tGetIpForwardTable failed.\n"); + free(pIpForwardTable); + return 0; + } + +} +/*endif WIN32*/ +#endif + +static int ShowChanAcc(uchar bchan) +{ + uchar LanRecord[30]; + int ret = 0; + + ret = GetChanAcc(bchan, 0x40, LanRecord); + if (fdebug) + printf(" GetChanAcc(%d) ret = %d, data = %02x %02x\n", + bchan,ret, LanRecord[0], LanRecord[1]); + if (ret == 0) + fprintf(fd_bmc,"ChannelAccess %d%c %02x %02x \n", + bchan,bdelim,LanRecord[0],LanRecord[1]); + return(ret); +} + +static int GetSerialOverLan( uchar chan, uchar bset, uchar block ) +{ + uchar requestData[24]; + uchar rData[MAX_BUFFER_SIZE]; + int rlen; + int status, i; + uchar ccode; + uchar enable_parm, auth_parm, baud_parm; + uchar user; + + if (fIPMI20 && fSOL20) { + getsolcmd = GET_SOL_CONFIG2; + enable_parm = SOL_ENABLE_PARAM; + auth_parm = SOL_AUTHENTICATION_PARAM; + baud_parm = SOL_BAUD_RATE_PARAM; + } else { + getsolcmd = GET_SOL_CONFIG; + enable_parm = SOL_ENABLE_PARAM; + auth_parm = SOL_AUTHENTICATION_PARAM; + baud_parm = SOL_BAUD_RATE_PARAM; + chan = 0; /*override chan for IPMI 1.5*/ + } + printf("%c## %s, GetSOL for channel %d ...\n",bcomment,progname,chan); + + requestData[0] = chan; /*channel*/ + requestData[1] = enable_parm; + requestData[2] = bset; /*set*/ + requestData[3] = block; /*block*/ + rlen = sizeof(rData); + status = ipmi_cmd(getsolcmd, requestData,4, rData, &rlen,&ccode,fdebug); + if (status != 0) return(status); + if (ccode) { + if (ccode == 0xC1) { /* unsupported command */ + printf("%c Serial-Over-Lan not available on this platform\n", + bcomment); + return(status); + } else { + printf("%c SOL Enable ccode = %x\n",bcomment,ccode); + status = ccode; + } + } else { /*success*/ + fprintf(fd_bmc,"SOLParam %d,%d,%d%c",chan,enable_parm,bset,bdelim); + for (i = 1; i < rlen; i++) fprintf(fd_bmc," %02x",rData[i]); + fprintf(fd_bmc,"\n"); + } + + requestData[0] = chan; + requestData[1] = auth_parm; + requestData[2] = bset; // selector + requestData[3] = block; // block + rlen = sizeof(rData); + status = ipmi_cmd(getsolcmd, requestData,4,rData, &rlen,&ccode,fdebug); + if (status != 0) return(status); + if (ccode) { + printf("%c SOL Auth ccode = %x\n",bcomment,ccode); + status = ccode; + } else { /*success*/ + fprintf(fd_bmc,"SOLParam %d,%d,%d%c",chan,auth_parm,bset,bdelim); + for (i = 1; i < rlen; i++) fprintf(fd_bmc," %02x",rData[i]); + fprintf(fd_bmc,"\n"); + } + + requestData[0] = chan; + requestData[1] = SOL_ACC_INTERVAL_PARAM; + requestData[2] = bset; + requestData[3] = block; + rlen = sizeof(rData); + status = ipmi_cmd(getsolcmd, requestData,4,rData, &rlen,&ccode,fdebug); + if (status != 0) return(status); + if (ccode) { + printf("%c SOL Accum Interval ccode = %x\n",bcomment,ccode); + status = ccode; + } else { /*success*/ + fprintf(fd_bmc,"SOLParam %d,%d,%d%c",chan,SOL_ACC_INTERVAL_PARAM,bset,bdelim); + for (i = 1; i < rlen; i++) fprintf(fd_bmc," %02x",rData[i]); + fprintf(fd_bmc,"\n"); + } + + requestData[0] = chan; + requestData[1] = SOL_RETRY_PARAM; + requestData[2] = bset; + requestData[3] = block; + rlen = sizeof(rData); + status = ipmi_cmd(getsolcmd, requestData,4,rData, &rlen,&ccode,fdebug); + if (status != 0) return(status); + if (ccode) { + printf("%c SOL Retry ccode = %x\n",bcomment,ccode); + status = ccode; + } else { /*success*/ + fprintf(fd_bmc,"SOLParam %d,%d,%d%c",chan,SOL_RETRY_PARAM,bset,bdelim); + for (i = 1; i < rlen; i++) fprintf(fd_bmc," %02x",rData[i]); + fprintf(fd_bmc,"\n"); + } + + if (!fRomley) { + requestData[0] = chan; + requestData[1] = baud_parm; + requestData[2] = bset; + requestData[3] = block; + rlen = sizeof(rData); + status = ipmi_cmd(getsolcmd,requestData,4,rData,&rlen,&ccode,fdebug); + if (status != 0) return(status); + if (ccode) { + printf("%c SOL nvol Baud ccode = %x\n",bcomment,ccode); + status = ccode; + } else { /*success*/ + fprintf(fd_bmc,"SOLParam %d,%d,%d%c",chan,baud_parm,bset,bdelim); + for (i = 1; i < rlen; i++) fprintf(fd_bmc," %02x",rData[i]); + fprintf(fd_bmc,"\n"); + } + + requestData[0] = chan; + requestData[1] = SOL_VOL_BAUD_RATE_PARAM; /*0x06*/ + requestData[2] = bset; + requestData[3] = block; + rlen = sizeof(rData); + status = ipmi_cmd(getsolcmd,requestData,4,rData,&rlen,&ccode,fdebug); + if (status != 0) return(status); + if (ccode) { + printf("%c SOL vol Baud ccode = %x\n",bcomment,ccode); + status = ccode; + } else { /*success*/ + fprintf(fd_bmc,"SOLParam %d,%d,%d%c",chan,SOL_VOL_BAUD_RATE_PARAM,bset,bdelim); + for (i = 1; i < rlen; i++) fprintf(fd_bmc," %02x",rData[i]); + fprintf(fd_bmc,"\n"); + } + } + + if (fIPMI20) { + requestData[0] = chan; + rlen = sizeof(rData); + status = ipmi_cmdraw(GET_PAYLOAD_SUPPORT, NETFN_APP, + BMC_SA,PUBLIC_BUS,BMC_LUN, + requestData,1,rData, &rlen, &ccode, fdebug); + if ((status != 0) || (ccode != 0)) { + printf("%c SOL Payload Support(%d) error %d, ccode = %x\n", + bcomment,chan,status,ccode); + if (status == 0) status = ccode; + } else { /*success*/ + fprintf(fd_bmc,"SOLPayloadSupport %d%c",chan,bdelim); + for (i = 1; i < rlen; i++) fprintf(fd_bmc," %02x",rData[i]); + fprintf(fd_bmc,"\n"); + } + /* get Payload Access for nusers, not just lan_user */ + for (user = 1; user <= nusers; user++) + { + /* IPMI 2.0 nusers >= 4 users */ + requestData[0] = chan; + requestData[1] = user; + rlen = sizeof(rData); + status = ipmi_cmdraw(GET_PAYLOAD_ACCESS, NETFN_APP, + BMC_SA,PUBLIC_BUS,BMC_LUN, + requestData,2,rData, &rlen, &ccode, fdebug); + if ((status != 0) || (ccode != 0)) { + printf("%c SOL Payload Access(%d,%d) error %d, ccode = %x\n", + bcomment,chan,user,status,ccode); + if (status == 0) status = ccode; + } else { /*success*/ + fprintf(fd_bmc,"SOLPayloadAccess %d,%d%c",chan,user,bdelim); + for (i = 0; i < rlen; i++) fprintf(fd_bmc," %02x",rData[i]); + fprintf(fd_bmc,"\n"); + } + } /*end user loop*/ + } + + return(status); +} /*end GetSerialOverLan */ + +static char *PefDesc(int idx, uchar stype) +{ + char *pdesc; + if (pefdesc == NULL) pdesc = "reserved"; + else pdesc = pefdesc[idx]; + if ((stype != 0) && (strcmp(pdesc,"reserved") == 0)) { + /* pefdesc may not match on some non-Intel systems. */ + /* so use sensor type */ + switch(stype) { + case 0x01: pdesc = "Temperature"; break; + case 0x02: pdesc = "Voltage"; break; + case 0x04: pdesc = "Fan"; break; + case 0x05: pdesc = "Chassis"; break; + case 0x07: pdesc = "BIOS"; break; + case 0x08: pdesc = "Power Supply"; break; + case 0x09: pdesc = "Power Unit"; break; + case 0x0c: pdesc = "Memory"; break; + case 0x0f: pdesc = "Boot"; break; + case 0x12: pdesc = "System Restart"; break; + case 0x13: pdesc = "NMI"; break; + case 0x23: pdesc = "Watchdog"; break; + case 0x20: pdesc = "OS Critical Stop"; break; + default: pdesc = "Other"; break; + } + } + return(pdesc); +} + +static int GetSessionInfo(uchar *rData, int sz) +{ + int rv, rlen; + uchar ccode; + uchar iData[5]; + + iData[0] = 0x00; /*get data for this session*/ + rlen = sz; + rv = ipmi_cmdraw(CMD_GET_SESSION_INFO,NETFN_APP, BMC_SA,PUBLIC_BUS,BMC_LUN, + iData,1,rData, &rlen, &ccode, fdebug); + if ((rv == 0) && (ccode != 0)) rv = ccode; + return(rv); +} + +static int GetPefCapabilities(uchar *bmax) +{ + int rv, rlen; + uchar ccode; + uchar rData[MAX_BUFFER_SIZE]; + + rlen = sizeof(rData); + rv = ipmi_cmdraw(0x10, NETFN_SEVT, BMC_SA,PUBLIC_BUS,BMC_LUN, + NULL,0,rData, &rlen, &ccode, fdebug); + if ((rv == 0) && (ccode != 0)) rv = ccode; + if ((rv == 0) && (bmax != NULL)) + *bmax = rData[2]; /*max num PEF table entries*/ + return(rv); +} + +int WaitForSetComplete(int limit) +{ + int rv = 0; + int i; + uchar bdata[4]; + + for (i = 0; i < limit; i++) { + rv = GetLanEntry(0, 0, bdata); + if (fdebug) printf("WaitForSetComplete(%d): i=%d rv=%d val=%x\n", + limit,i,rv,bdata[1]); + if ((rv == 0) && (bdata[1] == 0)) break; + else os_usleep(0,100); + } + return(rv); +} + +int SerialIsOptional(int bparam) +{ + /* These Serial Parameters are for optional Modem/Callback functions. */ + int optvals[9] = { 5, 9, 10, 11, 12, 13, 14, 20, 21 }; + int rv = 0; + int i; + for (i = 0; i < sizeof(optvals); i++) { + if (optvals[i] == bparam) { rv = 1; break; } + } + return(rv); +} + +static int parse_line(char *line, char *keyret, char *value) +{ + char *eol; + char *key; + char *val; + int i, n; + + key = &line[0]; + eol = &line[strlen(line)]; + while( *key < 0x21 && key < eol ) + key++; /*remove leading whitespace */ + if( key[0] == bcomment ) return 2; /*skip comments */ + /* + * find the value set, delimited by bdelim (':' or '|') + */ + val = strchr( line, bdelim ); + if( val == NULL ) return 1; /* skip if empty or no delimeter */ + val[0] = 0; /*stringify the key*/ + val++; + while( val[0] < 0x21 && val < eol ) + val++; /*remove leading whitespace */ + /* + * truncate trailing newline/whitespace after last word + */ + n = strlen_( val ); + for( i = n; i >= 0; i-- ) /*decrease from end*/ + if( val[i] >= 0x21 ) break; /*found last valid char */ + if (i < n) val[i + 1] = 0; + + strcpy(keyret, key); /*has keyword and params*/ + strcpy(value, val); /*has list of hex values*/ + return 0; +} + +#ifdef METACOMMAND +int i_config(int argc, char **argv) +#else +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#endif +{ + int ret; + PEF_RECORD *pPefRecord; + PEF_RECORD PefRecord; + uchar LanRecord[64]; + uchar bParams[5]; + char filename[80] = ""; + int i, j, c, n; + uchar idx; + // char *pstr; + uchar bset = 0; + int ndest = 4; + int idest; + // char mystr[80]; + uchar * pc; int sz; + char line[240]; /* hdr(18) + data(192 = 64 * 3) + '\0' = 211 */ + char key[40]; + char value[100]; + uchar rData[50]; + int rlen; + uchar cc; + uchar chan; + char *pk; + char fpefok = 1; + char fignore_err; + + // progname = argv[0]; + printf("%s ver %s \n",progname,progver); + func = 'l'; freadonly = 1; /*list is default*/ + + while ((c = getopt(argc, argv,"cdmlr:s:xL:T:V:J:EYF:P:N:R:U:Z:?")) != EOF) + switch(c) { + case 'c': fcanonical = 1; bdelim = BDELIM; break; + case 'd': func = 'd'; freadonly = 0; break; /*set Defaults*/ + case 'l': func = 'l'; freadonly = 1; break; /*list*/ + case 'm': fdomac = 1; break; /*restore mac*/ + case 'r': func = 'r'; freadonly = 0; /*restore*/ + sz = strlen_(optarg); + if (sz > sizeof(filename)) sz = sizeof(filename); + strncpy(filename,optarg,sz); + break; + case 's': func = 's'; freadonly = 1; /*save*/ + sz = strlen_(optarg); + if (sz > sizeof(filename)) sz = sizeof(filename); + strncpy(filename,optarg,sz); + break; + case 'x': fdebug = 1; break; + case 'p': /* password to set */ + fpassword = 1; + if (strlen_(optarg) > 16) optarg[16] = 0; + strcpy(passwordData,optarg); + if (fdebug) printf("Password = %s\n",passwordData); + /* Hide password from 'ps' */ + memset(optarg, ' ', strlen_(optarg)); + break; + case 'L': + lan_ch_parm = atob(optarg); + if (lan_ch_parm >= MAXCHAN) lan_ch_parm = 0xff; /*invalid*/ + break; + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'V': /* priv level */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + break; + default: + printf("Usage: %s [-clmpxLNUPREFTJVY -r -s ]\n", + progname); + printf("where -l Lists BMC configuration parameters\n"); + printf(" -r Restores BMC configuration from \n"); + printf(" -s Saves BMC configuration to \n"); + printf(" -c canonical output with delimiter '%c'\n",BDELIM); + printf(" -m Set BMC MAC during restore\n"); + printf(" -x show eXtra debug messages\n"); + printf(" -p specify a user password to set\n"); + printf(" -L 3 specify lan channel number 3\n"); + print_lan_opt_usage(); + ret = ERR_USAGE; + goto do_exit; + } + + switch(func) { + case 'l': fd_bmc = stdout; break; + case 'r': fd_bmc = fopen(filename,"r"); break; + case 's': fd_bmc = fopen(filename,"w"); break; + default: break; + } + if (fd_bmc == NULL) { + printf("Error: cannot open %s\n",filename); + ret = ERR_FILE_OPEN; + fd_bmc = stdout; + goto do_exit; + } + fipmilan = is_remote(); + + if (fipmilan) parse_lan_options('V',"4",0); + + ret = GetDeviceID( LanRecord); + if (ret != 0) { + goto do_exit; + } else { /* success */ + uchar ipmi_maj, ipmi_min; + ipmi_maj = LanRecord[4] & 0x0f; + ipmi_min = LanRecord[4] >> 4; + show_devid( LanRecord[2], LanRecord[3], ipmi_maj, ipmi_min); + if (ipmi_maj == 0) fIPMI10 = 1; + else if (ipmi_maj == 1 && ipmi_min < 5) fIPMI10 = 1; + else fIPMI10 = 0; /* >= IPMI 1.5 is ok */ + if (ipmi_maj >= 2) fIPMI20 = 1; + /* nusers can be up to 15 max */ + if (fIPMI20) nusers = 5; + else nusers = 3; + if (fIPMI10) { + printf("%c This IPMI v%d.%d system does not support PEF records.\n", + bcomment,ipmi_maj,ipmi_min); + /* Wont handle PEF, but continue and look for BMC LAN anyway */ + // fIPMI10 = 1; + // ipmi_close_(); + // exit(1); + } + prod_id = LanRecord[9] + (LanRecord[10] << 8); + vend_id = LanRecord[6] + (LanRecord[7] << 8) + + (LanRecord[8] << 16); + /* check Device ID response for Manufacturer ID = 0x0322 (NSC) */ + if (vend_id == VENDOR_NSC) { /* NSC = 0x000322 */ + fmBMC = 1; /*NSC miniBMC*/ + if (pefnum == 12) pefnum = 10; /* change CritStop pefnum to 0x0a */ + pefdesc = &pefdesc2[0]; + pefmax = 30; + fsharedMAC = 1; /*LAN1 shares MAC with OS*/ + } else if (vend_id == VENDOR_LMC) { /* LMC (on SuperMicro) = 0x000878 */ + fmBMC = 0; + pefdesc = NULL; /* unknown, see PefDesc() */ + if (pefnum == 12) pefnum = 15; /* change CritStop pefnum */ + pefmax = 16; + fsharedMAC = 0; /* not-shared BMC LAN port */ + } else if (vend_id == VENDOR_INTEL) { /* Intel = 0x000157 */ + pefdesc = &pefdesc1[0]; /*Intel defaults*/ + pefmax = 20; /*Intel default pefmax = 20*/ + switch(prod_id) { + case 0x4311: /* Intel NSI2U*/ + fmBMC = 1; /* Intel miniBMC*/ + if (pefnum == 12) pefnum = 14; /* change CritStop pefnum */ + pefdesc = &pefdesc2[0]; + pefmax = 30; + fsharedMAC = 1; /*LAN1 shares MAC with OS*/ + break; + case 0x0026: + case 0x0028: + case 0x0811: /* Alcolu & TIGW1U */ + fmBMC = 0; /* Intel Sahalee BMC*/ + fsharedMAC = 0; /* not-shared BMC LAN port, separate MAC */ + gcm_ch = 3; + break; + case 0x003E: /*NSN2U or CG2100 Urbanna*/ + fiBMC = 1; /* Intel iBMC */ + fsharedMAC = 0; /* not-shared BMC LAN port, separate MAC */ + set_max_kcs_loops(URNLOOPS); /*longer for SetLan cmds (default 300)*/ + break; + case 0x0107: /* Intel Caneland*/ + fsharedMAC = 0; /* not-shared BMC LAN port, separate MAC */ + gcm_ch = 3; + break; + case 0x0022: /* Intel TIGI2U*/ + fsharedMAC = 1; /*LAN1 shares MAC with OS*/ + gcm_ch = 3; + nusers = 4; + break; + default: /* else other Intel */ + if (fIPMI20) fsharedMAC = 0; /* recent, not-shared BMC MAC */ + else fsharedMAC = 1; /* usu IPMI 1.x has shared BMC MAC */ +#ifdef TEST + /* also check for ia64, and set chan_pefon, chan_pefoff accordingly*/ + if (prod_id == 0x0100) { /* Intel Tiger2, Itanium2 */ + chan_pefon = CHAN_ACC_PEFON64; + chan_pefoff = CHAN_ACC_PEFOFF64; + } +#endif + break; + } /*end switch*/ + if (is_romley(vend_id,prod_id)) { + fRomley = 1; + fiBMC = 1; /* Intel iBMC */ + fsharedMAC = 0; /* not-shared BMC LAN port, separate MAC */ + set_max_kcs_loops(URNLOOPS); /*longer for SetLan cmds */ + fipv6 = 1; + } + } else if (vend_id == VENDOR_KONTRON) { + //if (prod_id == 0x1590) fchan2wart = 1; /* KTC5520 chan2 wart */ + fsharedMAC = 0; /* not-shared BMC MAC */ + pefdesc = NULL; /* unknown, see PefDesc() */ + if (pefnum == 12) pefnum = 15; /* change CritStop pefnum to 15 */ + } else { /* else other vendors */ + if (fIPMI20) fsharedMAC = 0; /* recent, not-shared BMC MAC */ + else fsharedMAC = 1; /* usu IPMI 1.x has shared BMC MAC */ + fmBMC = 0; + pefdesc = NULL; /* unknown, see PefDesc() */ + if (pefnum == 12) pefnum = 15; /* change CritStop pefnum to 15? */ + pefmax = 20; + } + if (fmBMC) nusers = 1; + } + + ret = GetPefCapabilities(&bset); + if ((ret == 0) && (bset <= MAXPEF)) pefmax = bset; + + /* Get the BMC LAN channel & match it to an OS eth if. */ + i = GetBmcEthDevice(lan_ch_parm); + if (i == -2) { /* no lan channels */ + printf("This system does not support BMC LAN channels.\n"); + ret = ERR_NOT_ALLOWED; + goto do_exit; + } else if (i < 0) { /* mac not found, use platform defaults */ + i = 0; /* default to eth0, lan_ch set already. */ + if (vend_id == VENDOR_INTEL) { + if ((prod_id == 0x001B) || (prod_id == 0x000c)) { + /* Intel TIGPR2U or TSRLT2 defaults are special */ + if (lan_ch_parm == 6) + { i = 0; lan_ch = 6; } + else { i = 1; lan_ch = 7; } + ser_ch = 1; + } + } + } + if ((gcm_ch != 0) && (lan_ch_parm == 0xff)) { + /* Has a GCM, and user didn't specify -L */ + /* Need this to avoid picking channel 3, the IMM GCM channel. */ + lan_ch = 1; /*default BMC LAN channel*/ + // i = 1; /*default eth1*/ + } + if (fsetifn == 0) { + if (lan_ch == gcm_ch) strcpy(ifname,"gcm"); + else sprintf(ifname,"%s%d",ifpattn,i); + } + if (fdebug) printf("lan_ch = %d, ifname = %s\n",lan_ch,ifname); + + /* initialize the correct SOL command values */ + if (fIPMI20 && fSOL20) { + setsolcmd = SET_SOL_CONFIG2; + getsolcmd = GET_SOL_CONFIG2; + sol_bchan = lan_ch; + } else { + setsolcmd = SET_SOL_CONFIG; + getsolcmd = GET_SOL_CONFIG; + sol_bchan = 0x00; /*override chan for IPMI 1.5*/ + } + + memset(SessInfo,0,sizeof(SessInfo)); + ret = GetSessionInfo(SessInfo,sizeof(SessInfo)); + // rlen = sizeof(SessInfo)); ret = get_session_info(0,0,SessInfo,&rlen); + if (fdebug) printf("GetSessionInfo ret=%d, data: %02x %02x %02x %02x \n", + ret,SessInfo[0],SessInfo[1],SessInfo[2],SessInfo[3]); + if (!freadonly && fipmilan) { /* setting LAN params, and using IPMI LAN */ + if (SessInfo[2] > 1) { /* another session is active also */ + printf("Another session is also active, cannot change IPMI LAN settings now.\n"); + ret = ERR_NOT_ALLOWED; + goto do_exit; + } + } + + /* set the lan_user appropriately */ + if (freadonly) + { + if (!fIPMI10) { + printf("%c## %s, GetPefEntry ...\n",bcomment,progname); + for (idx = 1; idx <= pefmax; idx++) + { + ret = GetPefEntry( 0x06, (ushort)idx, &PefRecord); + if (ret == 0) { // Show the PEF record + pc = (uchar *)&PefRecord; + sz = 21; // sizeof(PEF_RECORD) = 21 + printf("%c PefParam(%d): %s\n",bcomment,idx,PefDesc(idx,pc[7])); + fprintf(fd_bmc,"PEFParam %d,%02d%c",6,idx,bdelim); + for (i = 0; i < sz; i++) fprintf(fd_bmc," %02x",pc[i]); + fprintf(fd_bmc,"\n"); + } else { + char *pstr; + if (ret > 0) pstr = decode_cc(0,(uchar)ret); + else pstr = ""; + printf("%c GetPefEntry(%d): ret = %d %s\n",bcomment,idx,ret,pstr); + if (ret == 0xC1) { + fpefok = 0; + ndest = 0; + break; + } + } + } + if (fpefok) { + ret = GetPefEntry(0x01, 0,(PEF_RECORD *)&LanRecord); + if (ret == 0) { + fprintf(fd_bmc,"PEFParam %d%c %02x\n",1,bdelim,LanRecord[0]); + } + ret = GetPefEntry(0x02, 0,(PEF_RECORD *)&LanRecord); + if (ret == 0) { + fprintf(fd_bmc,"PEFParam %d%c %02x\n",2,bdelim,LanRecord[0]); + } + ret = GetPefEntry(0x03, 0,(PEF_RECORD *)&LanRecord); + if (ret == 0) + fprintf(fd_bmc,"PEFParam %d%c %02x\n", 3,bdelim,LanRecord[0]); + if (!fmBMC) { + ret = GetPefEntry(0x04, 0,(PEF_RECORD *)&LanRecord); + if (ret == 0) + fprintf(fd_bmc,"PEFParam %d%c %02x\n",4,bdelim,LanRecord[0]); + /* fmBMC gets cc=0x80 here */ + } + /* note that ndest should be read from lan param 17 below. */ + for (i = 1; i <= ndest; i++) + { + ret = GetPefEntry(0x09, (ushort)i,(PEF_RECORD *)&LanRecord); + if (ret == 0) { + fprintf(fd_bmc,"PEFParam %d,%d%c %02x %02x %02x %02x \n",9,i,bdelim, + LanRecord[0], LanRecord[1],LanRecord[2], LanRecord[3]); + } + } /*endfor ndest*/ + } /*endif fpefok*/ + } /*endif not fIPMI10*/ + + for (chan = lan_ch; chan < MAXCHAN; chan++ ) + { + if (chan_type[chan] != 4) continue; /*chan != LAN, skip it*/ + lan_ch = chan; + printf("%c## %s, GetLanEntry for channel %d ...\n",bcomment,progname,lan_ch); + idest = 1; + for (idx = 0; idx < NLAN; idx++) + { + int ival; + if (idx == 8 || idx == 9) continue; /* not implemented */ + ival = lanparams[idx].cmd; + if (ival >= 96 && ival <= 98) continue; /* not implemented */ + if (ival >= 102 && ival <= 108) { /*custom IPv6 parameters*/ + if (fipv6 == 0) continue; /*skip these*/ + } + if (ival == 194 && vend_id == VENDOR_KONTRON) { /*oem hostname parm*/ + lanparams[idx].sz = 36; + strcpy(lanparams[idx].desc,"IPMI Hostname"); + } else if (ival >= 192 && ival <= 194) { /*custom DHCP parameters*/ + if (vend_id != VENDOR_INTEL) continue; + if (fmBMC || fiBMC || fRomley || fcanonical) continue; /*skip*/ + } + /* VLAN params 20-25, fIPMI20 only*/ + if (ival >= 20 && ival <= 25) { if (!fIPMI20) continue; } + if (ival == 11) { /*grat arp interval*/ + if (vend_id == VENDOR_SUPERMICROX) continue; + if (vend_id == VENDOR_SUPERMICRO) continue; + } + if (ival == 14 || ival == 15) { /*secondary gateway is optional*/ + if (vend_id == VENDOR_KONTRON) continue; + } + if (ival == 201) { /*Get Channel Access*/ + ret = ShowChanAcc(lan_ch); + } else { + if (ival == 18 || ival == 19) { /*dest params*/ + if (ndest == 0) continue; /*skip if none*/ + bset = (uchar)idest; /* dest id = 1 thru n */ + } else bset = 0; + ret = GetLanEntry((uchar)ival, bset, LanRecord); + } + if (ret == 0) { // Show the LAN record + pc = (uchar *)&LanRecord; + sz = lanparams[idx].sz; + if (ival == 201) ; /* ShowChanAcc(lan_ch) above */ + else { + fprintf(fd_bmc,"LanParam %d,%d,%d%c ",lan_ch,ival,bset,bdelim); + for (i = 0; i < sz; i++) fprintf(fd_bmc," %02x",pc[i]); + fprintf(fd_bmc,"\n"); + if (ival == 3) + printf("%c LanParam(%d,%d,%d) IP address: %d.%d.%d.%d\n", + bcomment, lan_ch,ival,bset, + pc[0], pc[1], pc[2], pc[3]); + } + + if (ival == 1) { + authmask = pc[0]; /* auth type support mask */ + /* if (fmBMC) authmask is usually 0x15, else 0x14 */ + } else if (ival == 3) { + if (IpIsValid(pc)) memcpy(bmcmyip,pc,4); + } else if (ival == 5) { + if (MacIsValid(pc)) memcpy(bmcmymac,pc,MAC_LEN); + } else if (ival == 17) { /* num dest */ + ndest = pc[0]; /* save the number of destinations */ + } else if (ival == 19) { /* dest addr */ + if (IpIsValid(&pc[3])) memcpy(bmcdestip,&pc[3],4); + } + + if (ival == 18 || ival == 19) { + if (idest < ndest) { + idest++; + idx--; /* repeat this param*/ + } else idest = 1; + } + } else { /* ret != 0 */ + if (ival >= 20 && ival <= 25) ; + else + printf("%c GetLanEntry(%d,%d,%d), ret = %d\n",bcomment,lan_ch,ival,bset,ret); + if (ival == 17) ndest = 0; /*error getting num dest*/ + } + } /*end for NLAN*/ + if (!fIPMI10) { /* Get SOL params */ + ret = GetSerialOverLan(lan_ch,0,0); + if (ret != 0) printf("%c GetSOL error %d\n",bcomment,ret); + } + for (idx = 1; idx <= nusers; idx++) + GetUser(idx); + if (lan_ch_parm != 0xff) chan = MAXCHAN; + } /*end-for chan*/ + + printf("%c## %s, GetSerEntry for channel %d ...\n",bcomment,progname,ser_ch); + if (fmBMC || (ser_ch == 0)) { /* mBMC doesn't support serial */ + printf("%cNo serial channel support on this platform\n", + bcomment); + } else { + idest = 1; + for (idx = 0; idx < NSER; idx++) { + int ival; + // if (idx == 9) continue; /* not implemented */ + ival = serparams[idx].cmd; + if (vend_id == VENDOR_SUPERMICRO && ival == 8) continue; + if (ival == 201) { + j = ShowChanAcc(ser_ch); + } else { + if (ival == 17 || ival == 19 || ival == 21 || ival == 23) + bset = (uchar)idest; + else bset = 0; /*default*/ + ret = GetSerEntry((uchar)ival, bset, LanRecord); + if (ret == 0) { // Show the SER record + pc = (uchar *)&LanRecord; + sz = serparams[idx].sz; + fprintf(fd_bmc,"SerialParam %d,%d,%d%c", + ser_ch,ival,bset,bdelim); + for (i = 0; i < sz; i++) + fprintf(fd_bmc," %02x",pc[i]); /* show in hex */ + fprintf(fd_bmc,"\n"); + if (ival == 16) ndest = pc[0]; + } else { /*ret != 0, error*/ + char *pstr; + char *tag; + if (SerialIsOptional(ival)) tag = "Optional"; + else tag = ""; + if (ret > 0) pstr = decode_cc(0,ret); + else pstr = ""; + printf("%c GetSerEntry(%d,%d): %s ret = %d %s\n", + bcomment,ser_ch,ival,tag,ret,pstr); + if (ival == 16) ndest = 0; + if (ret == 0xC1) { + ret = 0; + break; /*not supported, exit for loop*/ + } + } + } + if (ival == 17 || ival == 19 || ival == 21 || ival == 23) { + if (idest < ndest) { + idest++; + idx--; /* repeat this param*/ + } else idest = 1; + } + } /*end for NSER*/ + lan_ch_sav = lan_ch; + lan_ch = ser_ch; /* use ser_ch for User functions now */ + for (idx = 1; idx <= nusers; idx++) + GetUser(idx); + lan_ch = lan_ch_sav; + } /*endif serial*/ + + printf("%c## %s, GetSystemParams ...\n",bcomment,progname); + for (idx = 0; idx < NSYS; idx++) { /*Get System Params*/ + switch(idx) { + case 0: j = CHAS_RESTORE; bset = 0; break; + case 1: j = SYS_INFO; bset = 1; break; + case 2: j = SYS_INFO; bset = 2; break; + case 3: j = SYS_INFO; bset = 3; break; + case 4: j = SYS_INFO; bset = 4; break; + case 5: + default: j = LAN_FAILOVER; bset = 0; break; + } + fignore_err = 0; + pc = (uchar *)&LanRecord; + switch(j) { + case CHAS_RESTORE: /* Chassis Status, Power Restore Policy */ + sz = 0; + rlen = sizeof(rData); + ret = ipmi_cmdraw(CHASSIS_STATUS, NETFN_CHAS, + BMC_SA,PUBLIC_BUS,BMC_LUN, + pc,0,rData,&rlen,&cc,fdebug); + if (ret == 0 && cc != 0) ret = cc; + if (ret == 0) { + sz = rlen; + memcpy(pc,&rData,sz); /*should be 3 bytes*/ + } + break; + case SYS_INFO: /* System Info */ + if (! fIPMI20) continue; /*skip if not IPMI 2.0*/ + rlen = sizeof(LanRecord); /* param from read */ + ret = get_system_info(bset,LanRecord,&rlen); + /* find actual string size (ends at first 0x00) */ + for (i=0; i 0) pstr = decode_cc(0,ret); + else pstr = ""; + if (fdebug || !fignore_err) + printf("%c GetSystemParam(%d,%d): ret = %d %s\n", + bcomment,j,bset,ret,pstr); + if (fignore_err) ret = 0; + } + } /*end-for System Params*/ + + } /*endif readonly*/ + + if (!freadonly) /* Set parameters via Restore */ + { + if (fipmilan) { /* Sets not valid via ipmi_lan if same channel. */ + printf("\nWarning: Setting LAN %d params while using a LAN channel.\n", lan_ch); + } + GetUser(1); /*sets num enabled_users */ + + /* Set BMC parameters. (restore) */ + /* read each record from the file */ + while ( fgets( line, sizeof(line), fd_bmc) != NULL ) + { + ret = parse_line(line, key, value); + if (ret != 0) { + if (ret == 2) ret = 0; /*just skip comment*/ + else if (fdebug) printf("parse error on line: %s\n",line); + continue; + } + + /* get parameters from key */ + sz = sizeof(bParams); + memset(bParams,0,sz); + pk = strchr(key,' '); /*skip keyword, to first param*/ + if (pk == NULL) { + pk = &key[0]; + } + for (n=0; n= 22 && idx <= 24) continue; /*read-only Cipher*/ + else if (idx >= 20 && idx <= 25) { /*VLAN*/ + if (!fIPMI20) continue; + } + if (idx == 18) j--; /*one less byte for Set than from Get*/ + lan_ch = chan; + if (idx == 3) { /* 3 = IP address */ + uchar bdata[2]; + bdata[0] = 0x00; /*disable grat arp while setting IP*/ + ret = SetLanEntry(10, &bdata[0], 1); + if (fdebug) printf("SetLanEntry(%d,10,0), ret = %d\n",chan,ret); + WaitForSetComplete(4); /*wait if it is a slow MC */ + bdata[0] = SRC_STATIC; /*set src to static before setting IP*/ + ret = SetLanEntry(4, &bdata[0], 1); + if (fdebug) printf("SetLanEntry(%d,4,0), ret = %d\n",chan,ret); + WaitForSetComplete(4); /*wait if it is a slow MC */ + } + else if ((idx == 6) || (idx == 12)) WaitForSetComplete(4); + ret = SetLanEntry(idx, LanRecord, j); + if ((ret != 0) && (idx >= 20 && idx <= 25)) ; /*VLAN optional*/ + else { + printf("SetLanEntry(%d,%d), ret = %d\n",chan,idx,ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + + } else if (strncasecmp(key,"PEFParam",8) == 0) { + if (fpefok == 0) continue; + idx = bParams[0]; + bset = bParams[1]; + if (idx == 6) { /*PEF table rules*/ + pPefRecord = (PEF_RECORD *)&LanRecord[0]; + if (pPefRecord->fconfig == 0xC0) { + pPefRecord->fconfig = 0x80; /* enabled, software */ + ret = SetPefEntry(pPefRecord); + if (fdebug) + printf("SetPefEntry(%d,%d/80) ret = %d\n",idx,bset,ret); + pPefRecord->fconfig = 0xC0; + } + ret = SetPefEntry(pPefRecord); + printf("SetPefEntry(%d,%d) ret = %d\n",idx,bset,ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } else { + pc = (uchar *)&PefRecord; + pc[0] = idx; + for (i=0; i 1) && (ret != 0)); /*9=PEF Policy*/ + else { + printf("SetPefEntry(%d,%d) ret = %d\n",idx,bset,ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + } + if (ret == 0xC1) { fpefok = 0; ndest = 0; } + + } else if (strncasecmp(key,"SerialParam",11) == 0) { + if (idx == 0) continue; /*skip Set in progress*/ + if (idx == 1 || idx == 16) continue; /*read-only param*/ + if (vend_id == VENDOR_PEPPERCON) { + if ((idx >= 3) && (idx <= 6)) continue; + } + if ((vend_id == VENDOR_SUPERMICROX) || + (vend_id == VENDOR_SUPERMICRO)) { + if (idx == 3) continue; + if ((idx >= 6) && (idx <= 8)) continue; + if (idx == 29) continue; + } + if (fmBMC || (ser_ch == 0)) continue; /*doesn't support serial*/ + ser_ch = chan; + ret = SetSerEntry(idx, LanRecord, j); + if ((ret != 0) && SerialIsOptional(idx)) ; /*ignore errors if opt*/ + else { + printf("SetSerEntry(%d,%d,%d), ret = %d\n",chan,idx,bset,ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + } else if (strncasecmp(key,"ChannelAccess",13) == 0) { + if (((vend_id == VENDOR_SUPERMICROX) || + (vend_id == VENDOR_SUPERMICRO)) && chan == 3) ; /*skip serial*/ + else { + ret = SetChanAcc(chan, 0x80, LanRecord[0], LanRecord[1]); + if (fdebug) printf("SetChanAcc(%d/active), ret = %d\n",chan,ret); + ret = SetChanAcc(chan, 0x40, LanRecord[0], LanRecord[1]); + printf("SetChanAcc(%d), ret = %d\n",chan,ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + + } else if (strncasecmp(key,"UserName",8) == 0) { + if (fchan2wart && (lan_ch == 2)) continue; + idx = bParams[0]; + if (idx <= 1) ; /*skip if anonymous user 1*/ + else if (idx == 2 && vend_id == VENDOR_SUPERMICROX) ; /*skip user2*/ + else if (idx == 2 && vend_id == VENDOR_SUPERMICRO) ; /*skip user2*/ + else { + pc = (uchar *)&PefRecord; + pc[0] = idx; /*user num*/ + memcpy(&pc[1],&LanRecord[0],16); + rlen = sizeof(rData); + ret = ipmi_cmd(SET_USER_NAME,pc,17, rData,&rlen, &cc,fdebug); + if (ret == 0 && cc != 0) ret = cc; + if (ret == 0xCC) ; /*SetUserName matching previous gives this*/ + else { + printf("SetUserName(%d) ret = %d\n",idx,ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + } + if (fpassword) { + pc = (uchar *)&PefRecord; + pc[0] = idx; /*user num*/ + pc[1] = 0x02; /*set password*/ + memset(&pc[2],0, PSW_LEN); + strcpy(&pc[2],passwordData); + rlen = sizeof(rData); + ret = ipmi_cmd(SET_USER_PASSWORD,pc,2+PSW_LEN,rData,&rlen, + &cc,fdebug); + printf("SetUserPassword(%d) ret = %d\n",idx,ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + } else if (strncasecmp(key,"UserPassword",12) == 0) { + if (fchan2wart && (lan_ch == 2)) continue; + idx = bParams[0]; + pc = (uchar *)&PefRecord; + pc[0] = idx; /*user num*/ + pc[1] = 0x02; /*set password*/ + memset(&pc[2],0,PSW_LEN); + strcpy(&pc[2],passwordData); + rlen = sizeof(rData); + ret = ipmi_cmd(SET_USER_PASSWORD,pc,2+PSW_LEN,rData,&rlen, + &cc,fdebug); + printf("SetUserPassword(%d) ret = %d\n",idx,ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } else if (strncasecmp(key,"UserAccess",10) == 0) { + if ((idx > enabled_users) && ((LanRecord[3] & 0x10) == 0)) continue; + if (vend_id == VENDOR_KONTRON) { + if (idx == 1) continue; + if (idx > enabled_users) continue; + } + if (ipmi_reserved_user(vend_id,idx) == 1) continue; + if (fchan2wart && (lan_ch == 2)) continue; + pc = (uchar *)&PefRecord;; + pc[0] = 0x80 | (LanRecord[3] & 0x70) | chan; /*User Channel Access*/ + pc[1] = idx; /*user id*/ + pc[2] = (LanRecord[3] & 0x0F); /*User Privilege (Admin,User,Oper)*/ + pc[3] = 0x00; /* User Session Limit, 0=not limited*/ + rlen = sizeof(rData); + ret = ipmi_cmd(SET_USER_ACCESS,pc,4, rData,&rlen, &cc,fdebug); + if (ret == 0 && cc != 0) ret = cc; + if (ret != 0xCC) { /*if invalid user, ignore errors*/ + printf("SetUserAccess (%x %x %x %x) ret = %d\n", + pc[0],pc[1],pc[2],pc[3],ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + if ((LanRecord[3] & 0x0f) != 0x0F) { /*not NoAccess, enable user*/ + if (idx > last_user_enable) last_user_enable = idx; + pc[0] = idx; /*user number, 1=null_user */ + pc[1] = 0x01; /*enable user*/ + rlen = sizeof(rData); + ret = ipmi_cmd(SET_USER_PASSWORD,pc,2, rData,&rlen, &cc,fdebug); + if (ret == 0 && cc != 0) ret = cc; + printf("SetUserEnable (%x %x) ret = %d\n",pc[0],pc[1],ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + } else if (strncasecmp(key,"SOLParam",8) == 0) { + if (fchan2wart && (chan == 2)) continue; + pc = (uchar *)&PefRecord;; + pc[0] = chan; + pc[1] = idx; /*sol parameter number*/ + memcpy(&pc[2],&LanRecord,j); + rlen = sizeof(rData); + ret = ipmi_cmd(setsolcmd, pc, j+2, rData,&rlen, &cc,fdebug); + if (ret == 0 && cc != 0) ret = cc; + printf("SetSOLParam (%d,%d) ret = %d\n",chan,idx,ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + + } else if (strncasecmp(key,"SOLPayloadSupport",17) == 0) { + ; /* Nothing to do, this is a read-only parameter */ + + } else if (strncasecmp(key,"SOLPayloadAccess",16) == 0) { + if (fIPMI20) { + if (ipmi_reserved_user(vend_id,idx) == 1) continue; + pc = (uchar *)&PefRecord;; + pc[0] = chan; + pc[1] = idx; // lan_user + memcpy(&pc[2],&LanRecord,j); + rlen = sizeof(rData); + ret = ipmi_cmdraw(SET_PAYLOAD_ACCESS,NETFN_APP, + BMC_SA,PUBLIC_BUS,BMC_LUN, + pc,j+2,rData,&rlen,&cc,fdebug); + if (ret == 0 && cc != 0) ret = cc; + printf("SetSOLPayloadAccess (%d,%d) ret = %d\n", + chan,idx,ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + } else if (strncasecmp(key,"SystemParam",11) == 0) { + idx = bParams[0]; + bset = bParams[1]; + switch(idx) { + case CHAS_RESTORE: /* Chassis Power Restore Policy*/ + if (vend_id == VENDOR_KONTRON) continue; /*N/A, cannot set it*/ + pc = (uchar *)&PefRecord;; + i = (LanRecord[0] & 0x60); /*restore policy bits*/ + if (i & 0x20) pc[0] = 0x01; /*last_state*/ + else if (i & 0x40) pc[0] = 0x02; /*turn_on*/ + else pc[0] = 0x00; /*stay_off*/ + rlen = sizeof(rData); + ret = ipmi_cmdraw(0x06 , NETFN_CHAS, + BMC_SA,PUBLIC_BUS,BMC_LUN, + pc,1,rData,&rlen,&cc,fdebug); + if (ret == 0 && cc != 0) ret = cc; + break; + case SYS_INFO: /* System Info */ + if (! fIPMI20) continue; /*skip if not IPMI 2.0*/ + /* j = #bytes read into LanRecord */ + ret = set_system_info(bset,LanRecord,j); + break; + case LAN_FAILOVER: /* Intel LAN Failover */ + if (is_romley(vend_id,prod_id)) + ret = lan_failover_intel(LanRecord[0],(uchar *)&i); + else continue; /*skip if not Intel Romley*/ + break; + default: + ret = LAN_ERR_NOTSUPPORT; + } + printf("SetSystemParam(%d,%d) ret = %d\n",idx,bset,ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } /*end-else*/ + + } /*end-while*/ + + /* Disable any users not enabled above */ + for (i = last_user_enable+1; i < max_users; i++) { + pc[0] = (uchar)i; /*user number, 1=null_user */ + pc[1] = 0x00; /*disable user*/ + rlen = sizeof(rData); + ret = ipmi_cmd(SET_USER_PASSWORD,pc,2, rData,&rlen, &cc,fdebug); + if (ret == 0 && cc != 0) ret = cc; + printf("SetUserEnable (%x %x) ret = %d\n",pc[0],pc[1],ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + } /*endif not readonly*/ + +do_exit: + if (fd_bmc != stdout) fclose(fd_bmc); + ipmi_close_(); + if (nerrs > 0) { + printf("Warning: %d ok, %d errors occurred, last error = %d\n",ngood,nerrs,lasterr); + ret = lasterr; + } + // show_outcome(progname,ret); + return(ret); +} /* end main()*/ + +/* end iconfig.c */ diff --git a/util/idcmi.c b/util/idcmi.c new file mode 100644 index 0000000..1e53ae8 --- /dev/null +++ b/util/idcmi.c @@ -0,0 +1,976 @@ +/* + * idcmi.c + * Data Center Manageability Interface (DCMI) command support + * + * Change history: + * 11/17/2011 ARCress - created + * + *--------------------------------------------------------------------- + */ +/*M* +Copyright (c) 2011 Kontron America, 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: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions 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. + c.. Neither the name of Kontron nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ + +#ifdef WIN32 +#include +#include +#include "getopt.h" +#else +#include +#if defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include +#include +#else +#include +#include +#endif +#endif +#include +#include +#include +#include + +#include "ipmicmd.h" +#include "isensor.h" +#include "idcmi.h" + +static char * progname = "idcmi"; +static char * progver = "2.93"; +extern char fdebug; /*from ipmicmd.c*/ +static uchar g_bus = PUBLIC_BUS; +static uchar g_sa = BMC_SA; +static uchar g_lun = BMC_LUN; +static uchar g_addrtype = ADDR_SMI; +static uchar dcmi_ver = 0x00; /* 0x10, 0x11, or 0x15 */ +static uchar fpwm = 0; /* =1 if Power Management supported */ +static uchar do_sensors = 0; +static uchar set_asset = 0; +static uchar set_mcid = 0; +static char *asset_new = NULL; +static char *mcid_new = NULL; +static int asset_len = 0; +static int mcid_len = 0; +static char mc_id[64]; +static char asset[64]; + +#ifdef NOT +/* see idcmi.h */ +#define NETFN_DCMI 0x2C +#define CMD_DCMI_GET_CAPAB 0x01 +#define CMD_DCMI_GET_POWREAD 0x02 +#define CMD_DCMI_GET_POWLIMIT 0x03 +#define CMD_DCMI_SET_POWLIMIT 0x04 +#define CMD_DCMI_ACT_POWLIMIT 0x05 +#define CMD_DCMI_GET_ASSETTAG 0x06 +#define CMD_DCMI_GET_SENSORINF 0x07 +#define CMD_DCMI_SET_ASSETTAG 0x08 +#define CMD_DCMI_GET_MCIDSTR 0x09 +#define CMD_DCMI_SET_MCIDSTR 0x0A +/* for DCMI 1.5 only */ +#define CMD_DCMI_SET_THERMLIM 0x0B +#define CMD_DCMI_GET_THERMLIM 0x0C +#define CMD_DCMI_GET_TEMPRDNGS 0x10 +#define CMD_DCMI_SET_CONFIG 0x12 +#define CMD_DCMI_GET_CONFIG 0x13 +#endif + +static int dcmi_usage(void) +{ + printf("Usage: %s [-admsx -NUPREFTVY] \n", progname); + printf(" -a Set DCMI Asset Tag to this string\n"); + printf(" -d Set DCMI MC ID to this string\n"); + printf(" -m002000 specific MC (bus 00,sa 20,lun 00)\n"); + printf(" -s Get DCMI sensor info\n"); + printf(" -x Display extra debug messages\n"); + print_lan_opt_usage(); + printf("where is one of:\n"); + printf(" info Get DCMI Capabilities, MC ID, asset tag (default)\n"); + printf(" power [get] Get Power reading & limit\n"); + printf(" power set_limit Set Power limit\n"); + printf(" power set_action Set Power limit exception action\n"); + printf(" (action = no_action | power_off | log_sel)\n"); + printf(" power set_correction Set Power limit correction time (in ms)\n"); + printf(" power set_sample Set Power limit sampling period (in sec)\n"); + printf(" power activate Activate Power limit\n"); + printf(" power deactivate Deactivate Power limit\n"); + printf(" thermal Get/Set DCMI Thermal parameters\n"); + printf(" config Get/Set DCMI Configuration parameters\n"); + printf(" help Show this help message\n"); + return(ERR_USAGE); +} + +static int dcmi_get_capab(int param, uchar *pdata, int sdata) +{ + uchar idata[4]; + uchar rdata[32]; + int rlen; + uchar cc; + int rv, i; + + if (pdata == NULL || sdata == 0) return(ERR_BAD_PARAM); + idata[0] = 0xDC; + idata[1] = (uchar)param; + rlen = sizeof(rdata); + rv = ipmi_cmdraw( CMD_DCMI_GET_CAPAB, NETFN_DCMI, + g_sa, g_bus, g_lun, + idata,2, rdata, &rlen, &cc, fdebug); + if ((rv != 0) || (cc != 0)) { + if (fdebug) + printf("dcmi_get_capab(%d): rv = %d, ccode %02x\n",param,rv,cc); + if (rv == 0) rv = cc; + return(rv); + } + /* if here, success */ + if (fdebug) { /*show raw response*/ + printf("dcmi_get_capab(%d): rlen = %d\n",param,rlen); + for (i = 0; i < rlen; i++) printf("%02x ",rdata[i]); + printf("\n"); + } + if (rlen > sdata) { + if (fdebug) + printf("dcmi_get_capab(%d): data truncated from %d to %d\n", + param,rlen,sdata); + rlen = sdata; + } + memcpy(pdata,rdata,rlen); + return(rv); +} + +static int dcmi_get_power_read(int param, uchar *pdata, int sdata) +{ + uchar idata[5]; + uchar rdata[32]; + int rlen; + uchar cc; + int rv, i; + + if (pdata == NULL || sdata == 0) return(ERR_BAD_PARAM); + idata[0] = 0xDC; + idata[1] = (uchar)param; /*mode 1 or 2*/ + idata[2] = 0x00; + idata[3] = 0x00; + rlen = sizeof(rdata); + rv = ipmi_cmdraw( CMD_DCMI_GET_POWREAD, NETFN_DCMI, + g_sa, g_bus, g_lun, + idata,4, rdata, &rlen, &cc, fdebug); + if (rv == 0) rv = cc; + if (fdebug) { /*show raw response*/ + printf("dcmi_get_power_read(%d): rv = %d rlen = %d\n",param,rv,rlen); + for (i = 0; i < rlen; i++) printf("%02x ",rdata[i]); + printf("\n"); + } + if (rv == 0) { /* if here, success */ + if (rlen > sdata) { + if (fdebug) + printf("dcmi_get_power_read(%d): data truncated from %d to %d\n", + param,rlen,sdata); + rlen = sdata; + } + memcpy(pdata,rdata,rlen); + } + return(rv); +} + +static int dcmi_get_power_limit( uchar *pdata, int sdata) +{ + uchar idata[5]; + uchar rdata[32]; + int rlen; + uchar cc; + int rv, i; + + if (pdata == NULL || sdata == 0) return(ERR_BAD_PARAM); + idata[0] = 0xDC; + idata[1] = 0x00; + idata[2] = 0x00; + rlen = sizeof(rdata); + rv = ipmi_cmdraw( CMD_DCMI_GET_POWLIMIT, NETFN_DCMI, + g_sa, g_bus, g_lun, + idata,3, rdata, &rlen, &cc, fdebug); + if (rv == 0) rv = cc; + if (fdebug) { /*show raw response*/ + printf("dcmi_get_power_limit: rv = %d rlen = %d\n",rv,rlen); + for (i = 0; i < rlen; i++) printf("%02x ",rdata[i]); + printf("\n"); + } + if (rv == 0) { /* if here, success */ + if (rlen > sdata) { + if (fdebug) + printf("dcmi_get_power_limit: data truncated from %d to %d\n", + rlen,sdata); + rlen = sdata; + } + memcpy(pdata,rdata,rlen); + } + return(rv); +} + +static int dcmi_set_power_limit(int param,int value, uchar *pow, int spow) +{ + int rv = 0; + uchar idata[32]; + uchar rdata[32]; + int rlen; + uchar cc; + + if (spow > 15) spow = 15; + memcpy(idata,pow,spow); + switch(param) + { + case CORRECTION_TIME: + idata[10]=(uchar)((value >> 24) & 0xff); + idata[9] =(uchar)((value >> 16) & 0xff); + idata[8] =(uchar)((value >> 8) & 0xff); + idata[7] =(uchar)((value) & 0xff); + break; + case EXCEPTION_ACTION: + idata[4] = (uchar)(value & 0xff); + break; + case POWER_LIMIT: + idata[5] = (uchar)(value & 0xff); + idata[6] = (uchar)((value >> 8) & 0xff); + break; + case SAMPLE_PERIOD: + idata[14] = (uchar)((value >> 8) & 0xff); + idata[13] = (uchar)(value & 0xff); + break; + default: + return ERR_BAD_PARAM; + break; + } + rlen = sizeof(rdata); + rv = ipmi_cmdraw( CMD_DCMI_SET_POWLIMIT, NETFN_DCMI, + g_sa, g_bus, g_lun, + idata,15, rdata, &rlen,&cc, fdebug); + if (fdebug) + printf("dcmi_set_power_limit(%d,%d): rv = %d cc = %x\n", + param,value,rv,cc); + if (rv == 0) rv = cc; + return (rv); +} + + +static int dcmi_power_limit_activate ( int yes) +{ + int rv; + uchar idata[5]; + uchar rdata[32]; + int rlen; + uchar cc; + if (yes < 0) return (ERR_BAD_PARAM); + if (yes > 1) return (ERR_BAD_PARAM); + + idata[0] = 0xDC; + idata[1] = yes; + idata[2] = 0x00; + idata[3] = 0x00; + rlen = sizeof(rdata); + rv = ipmi_cmdraw( CMD_DCMI_ACT_POWLIMIT, NETFN_DCMI, + g_sa, g_bus, g_lun, + idata,4, rdata, &rlen, &cc, fdebug); + if (fdebug) + printf("dcmi_power_limit_activate(%d): rv = %d cc = %x\n",yes,rv,cc); + if (rv == 0) rv = cc; + return(rv); +} + +void dcmi_show_power_read(int parm, uchar *cdata, int sdata) +{ + int i; + ulong sample_period; + time_t t = 0; + uchar state; + + if (fdebug) { /*++++*/ + printf("dcmi_show_power_read(%d,%p,%d) called\n",parm,cdata,sdata); + for (i = 0; i < sdata; i++) printf("%02x ",cdata[i]); + printf("\n"); + } + if (sdata < 18) { + printf("power_read data length %d is too short\n",sdata); + return; + } + if (cdata[0] != 0xDC) { + printf("power_read: invalid first data byte (0x%02x)\n",cdata[0]); + return; + } + memcpy(&t,&cdata[9],4); + sample_period = cdata[13]; + sample_period += (cdata[14] << 8); + sample_period += (cdata[15] << 16); + sample_period += (cdata[16] << 24); + state = cdata[17]; + switch(parm) { + case 1: /* Mode 1 - System Power Statistics */ + printf(" Current Power: %d Watts\n",cdata[1]+(cdata[2]<<8)); + printf(" Min Power over sample duration: %d Watts\n",cdata[3]+(cdata[4]<<8)); + printf(" Max Power over sample duration: %d Watts\n",cdata[5]+(cdata[6]<<8)); + printf(" Avg Power over sample duration: %d Watts\n",cdata[7]+(cdata[8]<<8)); + printf(" Timestamp: %s\n",ctime(&t)); + printf(" Sampling period: %d ms\n",sample_period); + printf(" Power reading state is: %s\n",(state&0x40)? "active":"not active"); + break; + case 2: /* Mode 2 - Enhanced System Power Statistics */ + printf("Enhanced Power Mode 2 decoding not yet implemented\n"); + /* TODO */ + // break; + default: + for (i = 0; i < sdata; i++) printf("%02x ",cdata[i]); + printf("\n"); + break; + } +} + +void dcmi_show_power_limit(uchar *cdata, int sdata, int rv) +{ + ulong correction_time; + char *pstr; + + correction_time = cdata[6]; + correction_time += (cdata[7] << 8); + correction_time += (cdata[8] << 16); + correction_time += (cdata[9] << 24); + + if (rv == 0) pstr = "(active)"; + else if (rv == 0x80) pstr = "(inactive)"; + else pstr = "(error)"; + printf(" Exception Action: "); + if (cdata[3] & 0x01) + printf("Hard Power off\n"); + else if ((cdata[3] & 0x11) == 0x11) + printf("SEL logging\n"); + else + printf("OEM defined\n"); + printf(" Power Limit: %d Watts %s\n",cdata[4]+(cdata[5]<<8), pstr); + printf(" Correction Time: %d ms\n", correction_time); + printf(" Sampling period: %d sec\n", cdata[12]+(cdata[13]<<8)); +} + +static int dcmi_get_sensorinf(uchar styp, uchar snum, uchar offset, + uchar *pdata, int sdata) +{ + uchar idata[5]; + uchar rdata[32]; + int rlen; + uchar cc; + int rv, i; + + if (pdata == NULL || sdata == 0) return(ERR_BAD_PARAM); + idata[0] = 0xDC; + idata[1] = styp; /*sensor type, 0x01 = Temperature*/ + idata[2] = snum; /*sensor number */ + idata[3] = 0x00; /*Entity Instance, 0 = all instances*/ + idata[4] = offset; /*Entity Instance start/offset */ + rlen = sizeof(rdata); + rv = ipmi_cmdraw( CMD_DCMI_GET_SENSORINF, NETFN_DCMI, + g_sa, g_bus, g_lun, + idata,5, rdata, &rlen, &cc, fdebug); + if (rv == 0) rv = cc; + if (fdebug) { /*show raw response*/ + printf("dcmi_get_sensorinf(%d): rlen = %d\n",snum,rlen); + for (i = 0; i < rlen; i++) printf("%02x ",rdata[i]); + printf("\n"); + } + if (rv == 0) { /* if here, success */ + if (rlen > sdata) { + if (fdebug) + printf("dcmi_get_sensorinf(%d): data truncated from %d to %d\n", + snum,rlen,sdata); + rlen = sdata; + } + memcpy(pdata,rdata,rlen); + } + return(rv); +} + +static char *entstr(int i) +{ + char *pstr = NULL; + switch(i) { + case 0: pstr = "Inlet"; break; + case 1: pstr = "CPU"; break; + case 2: + default: + pstr = "Baseboard"; break; + } + return(pstr); +} + +static int dcmi_get_sensors(int styp) +{ + int i, j, n, r, recs; + uchar offset, id; + uchar dbuf[20]; + uchar s1; + int rv; + uchar *sdrs = NULL; + uchar sdr[128]; + + offset = 0; + r = 1; n = 8; + s1 = 0x40; /*0x40,0x41,0x42*/ + rv = get_sdr_cache(&sdrs); + + printf("---Sensors---\n"); + for (i = 0; i < 3; i++) + { + rv = dcmi_get_sensorinf(styp,s1+i,offset,dbuf,sizeof(dbuf)); + if (rv != 0) break; + n = dbuf[1]; + recs = dbuf[2]; + printf(" %d %s temp sensors: \tn_returned=%d\n",n,entstr(i),recs); + for (r = 0; r < n; r += recs) + { + recs = dbuf[2]; + if (recs == 0) break; + for (j = 0; j < r; j++) { + id = (dbuf[4 + (2*j)] << 8) + dbuf[3 + (2*j)]; + if (fdebug) printf("j=%d id=%x \n",j,id); + /* get the sensor info for each record id */ + rv = find_sdr_next(sdr,sdrs,(id-1)); + ShowSDR("",sdr); + } + offset += recs; + rv = dcmi_get_sensorinf(1,s1+i,offset,dbuf,sizeof(dbuf)); + if (rv != 0) break; + } + } + if (rv != 0) printf("dcmi_get_sensors(%d,%d) error %d\n",styp,i,rv); + free_sdr_cache(sdrs); + return(rv); +} + +static int dcmi_get_asset_tag(char *pdata, int sdata, int *dlen) +{ + uchar idata[4]; + uchar rdata[32]; + int rlen; + uchar cc; + int n, rv = -1; + int sz_chunk = 16; + int sz_all; + + if (pdata == NULL || sdata < 16) return(ERR_BAD_PARAM); + memset(pdata,0,sdata); + sz_all = sdata; + for (n = 0; (n < sdata && n < sz_all); n += sz_chunk) { + idata[0] = 0xDC; + idata[1] = n; /*offset*/ + idata[2] = sz_chunk; /*bytes to read*/ + rlen = sizeof(rdata); + rv = ipmi_cmdraw( CMD_DCMI_GET_ASSETTAG, NETFN_DCMI, + g_sa, g_bus, g_lun, + idata,3, rdata, &rlen, &cc, fdebug); + if (fdebug) + printf("dcmi_get_asset(%d): rv=%d ccode=%02x rlen=%d\n", + n,rv,cc,rlen); + if (rv == 0) rv = cc; + if (rv == 0) { /* if here, success */ + if (n == 0) sz_all = rdata[1]; + if ((n + sz_chunk) > sdata) { + if (fdebug) + printf("dcmi_get_asset(%d): data truncated from %d to %d\n", + n,(n+sz_chunk),sdata); + sz_chunk = (sdata - n); + } + memcpy(&pdata[n],&rdata[2],sz_chunk); + } else break; + } /*end-for loop*/ + pdata[n] = 0; /*stringify*/ + if (dlen != NULL) *dlen = n; + return(rv); +} + +static int dcmi_get_mc_id(char *pdata, int sdata, int *dlen) +{ + uchar idata[4]; + uchar rdata[32]; + int rlen; + uchar cc; + int n, rv = -1; + int sz_chunk = 16; + int sz_all; + + if (pdata == NULL || sdata < 16) return(ERR_BAD_PARAM); + memset(pdata,0,sdata); + sz_all = sdata; + for (n = 0; (n < sdata && n < sz_all); n += sz_chunk) { + idata[0] = 0xDC; + idata[1] = n; /*offset*/ + idata[2] = sz_chunk; /*bytes to read*/ + rlen = sizeof(rdata); + rv = ipmi_cmdraw( CMD_DCMI_GET_MCIDSTR, NETFN_DCMI, + g_sa, g_bus, g_lun, + idata,3, rdata, &rlen, &cc, fdebug); + if (fdebug) + printf("dcmi_get_mc_id(%d): rv=%d ccode=%02x rlen=%d\n", + n,rv,cc,rlen); + if (rv == 0) rv = cc; + if (rv == 0) { /* if here, success */ + if (n == 0) sz_all = rdata[1]; + if ((n + sz_chunk) > sdata) { + if (fdebug) + printf("dcmi_get_mc_id(%d): data truncated from %d to %d\n", + n,(n+sz_chunk),sdata); + sz_chunk = (sdata - n); + } + memcpy(&pdata[n],&rdata[2],sz_chunk); + } else break; + } /*end-for loop*/ + pdata[n] = 0; /*stringify*/ + if (dlen != NULL) *dlen = n; + return(rv); +} + +static int dcmi_set_asset_tag(char *pdata, int sdata) +{ + int rv = -1; + uchar idata[32]; + uchar rdata[8]; + uchar cc; + int ilen, rlen, n; + int sz_chunk = 16; + + if (pdata == NULL || sdata < 2) return(ERR_BAD_PARAM); + for (n = 0; (n < sdata); n += sz_chunk) { + idata[0] = 0xDC; + idata[1] = n; /*offset*/ + idata[2] = sz_chunk; /*bytes to read*/ + memset(&idata[3],0x20,sz_chunk); + ilen = 3 + sz_chunk; + if ((n + sz_chunk) > sdata) sz_chunk = sdata - n; + memcpy(&idata[3],&pdata[n],sz_chunk); + rlen = sizeof(rdata); + rv = ipmi_cmdraw( CMD_DCMI_SET_ASSETTAG, NETFN_DCMI, + g_sa, g_bus, g_lun, + idata,ilen, rdata, &rlen, &cc, fdebug); + if (rv == 0) { + if (fdebug) + printf("dcmi_set_asset_tag(%d,%d,%d) cc=%x resp: %02x %02x %02x\n", + sdata,n,sz_chunk,cc,rdata[0],rdata[1],rdata[2]); + rv = cc; + } + if (rv != 0) break; + } + return(rv); +} + +static int dcmi_set_mc_id(char *pdata, int sdata) +{ + int rv = -1; + uchar idata[32]; + uchar rdata[8]; + uchar cc; + int ilen, rlen, n; + int sz_chunk = 16; + + if (pdata == NULL || sdata < 2) return(ERR_BAD_PARAM); + for (n = 0; (n < sdata); n += sz_chunk) { + if ((n + sz_chunk) > sdata) sz_chunk = sdata - n; + idata[0] = 0xDC; + idata[1] = n; /*offset*/ + idata[2] = sz_chunk; /*bytes to read*/ + memset(&idata[3],0x20,sz_chunk); + ilen = 3 + sz_chunk; + if ((n + sz_chunk) > sdata) sz_chunk = sdata - n; + memcpy(&idata[3],&pdata[n],sz_chunk); + rlen = sizeof(rdata); + rv = ipmi_cmdraw( CMD_DCMI_SET_MCIDSTR, NETFN_DCMI, + g_sa, g_bus, g_lun, + idata,ilen, rdata, &rlen, &cc, fdebug); + if (rv == 0) { + if (fdebug) printf("dcmi_set_mc_id(%d,%d,%d) resp: %02x %02x %02x\n", + sdata,n,sz_chunk,rdata[0], rdata[1], rdata[2]); + rv = cc; + } + if (rv != 0) break; + } + return(rv); +} + +static int dcmi_show_asset_tag(void) +{ + int rv = -1; + rv = dcmi_get_asset_tag(asset,sizeof(asset),&asset_len); + if (rv == 0) printf("DCMI Asset Tag: \t%s\n",asset); + return(rv); +} + +static int dcmi_show_mc_id(void) +{ + int rv = -1; + rv = dcmi_get_mc_id(mc_id,sizeof(mc_id),&mcid_len); + if (rv == 0) printf("DCMI Mgt Controller ID: \t%s\n",mc_id); + return(rv); +} + +static char *supported[2] = { "Unsupported", "Supported" }; + +void dcmi_show_capab(int parm, uchar *cdata, int sdata) +{ + char mystr[64] = ""; + int i, j, k, n, f; + switch(parm) + { + case 1: + printf("DCMI Version: \t%d.%d\n",cdata[1],cdata[2]); + dcmi_ver = ((cdata[1] & 0x0f) << 4) + (cdata[2] & 0x0f); + if (cdata[5] & 0x01) { fpwm = 1; } + else { fpwm = 0; } + printf("DCMI Power Management: \t%s\n",supported[fpwm]); + if (cdata[6] & 0x01) f = 1; + else f = 0; + printf("DCMI System Interface Access:\t%s\n",supported[f]); + if (cdata[6] & 0x02) f = 1; + else f = 0; + printf("DCMI Serial TMode Access:\t%s\n",supported[f]); + if (cdata[6] & 0x02) f = 1; + else f = 0; + printf("DCMI Secondary LAN Channel:\t%s\n",supported[f]); + break; + case 2: + mystr[0] = 0; + if (cdata[5] & 0x80) strcat(mystr,"Overwrite "); + else strcat(mystr,"NoOverwrite "); + if (cdata[5] & 0x40) strcat(mystr,"FlushAll "); + if (cdata[5] & 0x20) strcat(mystr,"FlushRec"); + printf("DCMI SEL Management: \t%s\n",mystr); + n = ((cdata[5] & 0x0F) << 8) + cdata[4]; + printf("DCMI SEL num entries: \t%d\n",n); + i = cdata[8]; + printf("DCMI Temperature Polling: \t%d sec\n",i); + break; + case 3: + n = ((cdata[4] & 0xFE) >> 1); + printf("DCMI PWM Slave_Address: \t%02x\n",n); + n = ((cdata[5] & 0xF0) >> 4); + printf("DCMI PWM Channel: \t%02x\n",n); + printf("DCMI PWM Dev_Rev: \t%02x\n",(cdata[5] & 0x0F)); + break; + case 4: + printf("DCMI LanPlus primary chan:\t%02x\n",cdata[4]); + printf("DCMI LanPlus secondary chan:\t%02x\n",cdata[5]); + printf("DCMI Serial channel: \t%02x\n",cdata[6]); + break; + case 5: + n = cdata[4]; + if (n > (5 + sdata)) n = sdata - 5; /*truncate*/ + for (i = 0; i < n; i++) { + j = (cdata[5+i] & 0x0f); + k = ((cdata[5+i] & 0xf0) >> 4); + switch(k) { + case 3: strcpy(mystr,"days"); break; + case 2: strcpy(mystr,"hrs"); break; + case 1: strcpy(mystr,"min"); break; + case 0: + default: strcpy(mystr,"sec"); break; + } + printf("DCMI Power Stats Duration(%d):\t%d %s\n",i,j,mystr); + } + break; + default: + printf("DCMI(%d) data: %02x %02x %02x %02x %02x %02x %02x %02x\n", + parm,cdata[1],cdata[2],cdata[3],cdata[4], + cdata[5], cdata[6], cdata[7], cdata[8]); + break; + } +} + +static int dcmi_show_all_capab(void) +{ + int rv = -1; + int i; + uchar cdata[32]; + + for (i = 1; i <= 5; i++) + { + /* only read power stats(5) when power management is supported */ + if (i == 5 && fpwm == 0) continue; + rv = dcmi_get_capab(i, cdata, sizeof(cdata)); + if (rv != 0) { + if (i == 1 && rv == CC_DCMI_INVALID_COMMAND) { /*0xC1 on first*/ + printf("DCMI not supported on this platform\n"); + break; + } else if (i == 5 && rv == CC_DCMI_RECORD_NOT_PRESENT) /*0xCB*/ + rv = 0; /*optional, ignore this error*/ + /*else just dont show the param*/ + } else dcmi_show_capab(i,cdata,sizeof(cdata)); + + } /*end-for dcmi_capab loop */ + return(rv); +} + +#ifdef METACOMMAND +int i_dcmi(int argc, char **argv) +#else +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#endif +{ + int rv = 0; + int c, i; + char *s1; + uchar cdata[32]; + uchar powdata[32]; + + printf("%s ver %s\n", progname,progver); + parse_lan_options('V',"4",0); /*default to admin priv*/ + + while ( (c = getopt( argc, argv,"a:d:m:sT:V:J:EYF:P:N:R:U:Z:x?")) != EOF ) + switch (c) { + case 'a': set_asset = 1; asset_new = optarg; break; + case 'd': set_mcid = 1; mcid_new = optarg; break; + case 'm': /* specific IPMB MC, 3-byte address, e.g. "409600" */ + g_bus = htoi(&optarg[0]); /*bus/channel*/ + g_sa = htoi(&optarg[2]); /*device slave address*/ + g_lun = htoi(&optarg[4]); /*LUN*/ + g_addrtype = ADDR_IPMB; + if (optarg[6] == 's') { + g_addrtype = ADDR_SMI; s1 = "SMI"; + } else { g_addrtype = ADDR_IPMB; s1 = "IPMB"; } + ipmi_set_mc(g_bus,g_sa,g_lun,g_addrtype); + printf("Use MC at %s bus=%x sa=%x lun=%x\n", + s1,g_bus,g_sa,g_lun); + break; + case 's': do_sensors = 1; break; + case 'x': fdebug = 1; break; /* debug messages */ + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'V': /* priv level */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + break; + case '?': + return(dcmi_usage()); + break; + } + for (i = 0; i < optind; i++) { argv++; argc--; } + + if ((argc > 0) && strcmp(argv[0], "help") == 0) { + return(dcmi_usage()); + } + + rv = ipmi_getdeviceid( cdata, sizeof(cdata),fdebug); + if (rv == 0) { + uchar ipmi_maj, ipmi_min; + ipmi_maj = cdata[4] & 0x0f; + ipmi_min = cdata[4] >> 4; + show_devid( cdata[2], cdata[3], ipmi_maj, ipmi_min); + } else goto do_exit; + + if (set_asset) { + rv = dcmi_get_asset_tag(asset,sizeof(asset),&asset_len); + memset(asset,' ',asset_len); /*fill with spaces*/ + asset_len = strlen_(asset_new); + if (asset_len >= sizeof(asset)) asset_len = sizeof(asset) - 1; + memcpy(asset,asset_new,asset_len); + asset[asset_len] = 0; + rv = dcmi_set_asset_tag(asset, asset_len); + printf("Set DCMI Asset Tag to %s, ret = %d\n",asset_new,rv); + } + if (set_mcid) { + rv = dcmi_get_mc_id(mc_id,sizeof(mc_id),&mcid_len); + memset(mc_id,' ',mcid_len); /*fill with spaces*/ + mcid_len = strlen_(mcid_new); + if (mcid_len >= sizeof(mc_id)) mcid_len = sizeof(mc_id) - 1; + memcpy(mc_id,mcid_new,mcid_len); + mc_id[mcid_len] = 0; + rv = dcmi_set_mc_id(mcid_new, mcid_len); + printf("Set DCMI MC ID to %s, ret = %d\n",mcid_new,rv); + } + + if ( (argc == 0) || (strcmp(argv[0], "info") == 0) ) { + rv = dcmi_show_all_capab(); + if (rv == 0) { + rv = dcmi_show_mc_id(); + rv = dcmi_show_asset_tag(); + if (do_sensors) rv = dcmi_get_sensors(1); /*temp sensors*/ + rv = 0; /*ignore errors for optional features*/ + } + } else + { + rv = dcmi_get_capab(1, cdata, sizeof(cdata)); + if (rv == 0) dcmi_show_capab(1,cdata,sizeof(cdata)); + else if (rv == CC_DCMI_INVALID_COMMAND) /*0xC1 on first*/ + printf("DCMI not supported on this platform\n"); + + if (strncmp(argv[0], "power",5) == 0) { + if (fpwm == 0) { /*not supported in capab */ + printf("DCMI Power functions not supported on this platform.\n"); + rv = LAN_ERR_NOTSUPPORT; + } else { + rv = dcmi_get_power_read(1, cdata, sizeof(cdata)); + if (rv == 0) { + dcmi_show_power_read(1,cdata,sizeof(cdata)); + rv = dcmi_get_power_limit(powdata, sizeof(powdata)); + if (rv == 0) + dcmi_show_power_limit(powdata,sizeof(powdata),rv); + else if (rv == 0x80) { + dcmi_show_power_limit(powdata,sizeof(powdata),rv); + rv = 0; + } + } + if (argc < 2) ; /*just get, done above*/ + else if (strncmp(argv[1],"get",3) == 0) ; /*done above*/ + else if (strncmp(argv[1],"set_limit",9) == 0) { + if (argc < 3) return(dcmi_usage()); + i = atoi(argv[2]); + { /*let range checking be done by DCMI*/ + rv = dcmi_set_power_limit (POWER_LIMIT, i, powdata,16); + switch(rv) { + case 0: + printf("DCMI Power limit applied successfully.\n"); + break; + case 0x84: printf("Power limit out of range\n"); break; + case 0x85: printf("Correction time out of range\n"); + break; + case 0x89: + printf("Statistics reporting period out of range\n"); + break; + default: + printf("DCMI Power Limit Set error %d\n",rv); break; + } + if (rv == 0) { + rv = dcmi_power_limit_activate(1); + printf ("DCMI Power Limit Activate returned %d\n",rv); + } + } + } + else if (strncmp(argv[1],"activate",8) == 0) { + rv = dcmi_power_limit_activate(1); + if (rv == 0) + printf ("DCMI Power Limit Activated.\n"); + else printf("DCMI Power Limit Activate error %d\n",rv); + } + else if (strncmp(argv[1],"deactivate",10) == 0) { + rv = dcmi_power_limit_activate(0); + if (rv == 0) + printf("DCMI Power Limit Deactivated.\n"); + else printf("DCMI Power Limit Deactivate error %d\n",rv); + } + else if (strcmp(argv[1],"set_action")==0) { + if (argc < 3) return(dcmi_usage()); + else if (strcmp(argv[2],"no_action") == 0) + rv = dcmi_set_power_limit(EXCEPTION_ACTION,0x00, + powdata,16); + else if (strcmp(argv[2],"log_sel") == 0) + rv = dcmi_set_power_limit(EXCEPTION_ACTION,0x11, + powdata,16); + else if (strcmp(argv[2],"power_off") == 0) + rv = dcmi_set_power_limit(EXCEPTION_ACTION,0x01, + powdata,16); + else return(dcmi_usage()); + if (rv == 0) + printf("exception action set successfully.\n"); + else printf("set_exception action error %d\n",rv); + } + else if (strcmp(argv[1],"set_sample")==0) { + if (argc < 3) return(dcmi_usage()); + i = atoi(argv[2]); + if (i != 0) { + rv = dcmi_set_power_limit (SAMPLE_PERIOD,i,powdata,16); + if (rv == 0x00) + printf("sample period set successfully\n"); + else if (rv == 0x89) + printf("sample period %d out of range\n",i); + else printf("set_sample period error %d\n",rv); + } + else { printf("invalid sample period %d\n",i); + rv = ERR_USAGE; } + } + else if (strcmp(argv[1],"set_correction")==0) { + if (argc < 3) return(dcmi_usage()); + i = atoi(argv[2]); + if (i != 0) { + rv = dcmi_set_power_limit(CORRECTION_TIME,i,powdata,16); + if (rv == 0x00) + printf("correction time set successfully\n"); + else if (rv == 0x85) + printf("correction time %d out of range\n",i); + else { + dcmi_usage(); + rv = ERR_USAGE; + } + } + else { printf("correction time %d invalid\n",i); + rv = ERR_USAGE; } + } + else { + printf("invalid subfunction %s\n",argv[1]); + rv = ERR_USAGE; + } + } /* endif power functions supported */ + + } else if (strcmp(argv[0], "thermal") == 0) { + if (dcmi_ver < 0x15) { /*not supported in DCMI < 1.5 */ + printf("DCMI 1.5 Thermal functions not supported on this platform.\n"); + rv = LAN_ERR_NOTSUPPORT; + } else { + rv = dcmi_get_sensors(1); /*temp sensors*/ +/* These are DCMI 1.5 commands */ +// #define CMD_DCMI_SET_THERMLIM 0x0B +// #define CMD_DCMI_GET_THERMLIM 0x0C +// #define CMD_DCMI_GET_TEMPRDNGS 0x10 +/* TODO: implement these 3 DCMI thermal commands */ + printf("DCMI 1.5 Thermal functions not yet implemented\n"); + rv = ERR_USAGE; + } + } else if (strcmp(argv[0], "config") == 0) { + if (dcmi_ver < 0x15) { /*not supported in DCMI < 1.5 */ + printf("DCMI 1.5 Config functions not supported on this platform.\n"); + rv = LAN_ERR_NOTSUPPORT; + } else { /* These are DCMI 1.5 commands */ +// #define CMD_DCMI_SET_CONFIG 0x12 +// #define CMD_DCMI_GET_CONFIG 0x13 +/* TODO: implement these 2 DCMI config commands */ + printf("DCMI 1.5 Config get/set functions not yet implemented\n"); + rv = ERR_USAGE; + } + } else { + return(dcmi_usage()); + } + } /*else not info command*/ + +do_exit: + ipmi_close_(); + return rv; +} +/* end idcmi.c */ diff --git a/util/idcmi.h b/util/idcmi.h new file mode 100644 index 0000000..a528831 --- /dev/null +++ b/util/idcmi.h @@ -0,0 +1,69 @@ +/* + * idcmi.h + * Data Center Manageability Interface (DCMI) command support + * + * Change history: + * 11/17/2011 ARCress - created + * + *--------------------------------------------------------------------- + */ +/*M* +Copyright (c) 2011 Kontron America, 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: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions 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. + c.. Neither the name of Kontron nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ + +#ifndef IPMI_DCMI_H +#define IPMI_DCMI_H + +#define CC_DCMI_INVALID_COMMAND 0xC1 +#define CC_DCMI_RECORD_NOT_PRESENT 0xCB +#define NETFN_DCMI 0x2C +/* for DCMI 1.0 and greater */ +#define CMD_DCMI_GET_CAPAB 0x01 +#define CMD_DCMI_GET_POWREAD 0x02 +#define CMD_DCMI_GET_POWLIMIT 0x03 +#define CMD_DCMI_SET_POWLIMIT 0x04 +#define CMD_DCMI_ACT_POWLIMIT 0x05 +#define CMD_DCMI_GET_ASSETTAG 0x06 +#define CMD_DCMI_GET_SENSORINF 0x07 +#define CMD_DCMI_SET_ASSETTAG 0x08 +#define CMD_DCMI_GET_MCIDSTR 0x09 +#define CMD_DCMI_SET_MCIDSTR 0x0A +/* for DCMI 1.5 only */ +#define CMD_DCMI_SET_THERMLIM 0x0B +#define CMD_DCMI_GET_THERMLIM 0x0C +#define CMD_DCMI_GET_TEMPRDNGS 0x10 +#define CMD_DCMI_SET_CONFIG 0x12 +#define CMD_DCMI_GET_CONFIG 0x13 + +/* CMD_DCMI_SET_POWLIMIT options */ +#define CORRECTION_TIME 0x01 +#define EXCEPTION_ACTION 0x02 +#define POWER_LIMIT 0x03 +#define SAMPLE_PERIOD 0x04 + +#endif +/* end idcmi.h */ diff --git a/util/idiscover.c b/util/idiscover.c new file mode 100644 index 0000000..57471e3 --- /dev/null +++ b/util/idiscover.c @@ -0,0 +1,1055 @@ +/* + * idiscover.c + * Discover all IPMI-LAN-enabled nodes on this network or subnet. + * This program is not completely reliable yet, not all IPMI-LAN-enabled + * nodes respond. + * Currently this utility is compiled with NO_THREADS, but threads can + * be enabled by commenting out this flag. + * + * Author: Andy Cress arcress at users.sourceforge.net + * Copyright (c) 2006 Intel Corporation. + * Copyright (c) 2009 Kontron America, Inc. + * + * 10/27/06 Andy Cress - created + * 05/01/07 Andy Cress - added -g for GetChannelAuthCap method, + * added -a logic for broadcast ping, + * updated WIN32 logic + * 09/20/07 Andy Cress - fixed send/receive thread order + * 07/15/08 Andy Cress - added -r for ping repeats + * 11/21/08 Andy Cress - detect eth intf and broadcast ip addr + */ +/*M* +Copyright (c) 2006, Intel Corporation +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions 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. + c.. Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ +#if defined(HAVE_CONFIG_H) +#include "config.h" +#endif + +#ifdef WIN32 +#include +#include +#include +#include +#include +#include +#include "getopt.h" +#define NO_THREADS 1 +typedef unsigned int socklen_t; +WSADATA lan_ws; /*global for WSA*/ + +#elif defined(DOS) +#include +#include +#include +#include +#include "getopt.h" +#define NO_THREADS 1 + +#else +/* Linux, BSD, Solaris */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include +#include +#ifndef HAVE_CONFIG_H +typedef unsigned int socklen_t; +#endif +#else +#include +#endif + +/* comment out NO_THREADS to use this utility in Linux with threads */ +#define NO_THREADS 1 +#endif +#ifndef ETH_P_IP +#define ETH_P_IP 0x0800 /* Internet Protocol packet, see linux/if_ether.h */ +#endif + +/* TODO: fix RAW for -m in Solaris, FreeBSD, Windows (works in Linux) */ +#ifdef SOLARIS +#include +#define RAW_DOMAIN AF_INET +#define RAW_PROTO IPPROTO_RAW +static char frawok = 0; /*raw not working in Solaris*/ +#elif BSD +#define RAW_DOMAIN AF_INET +#define RAW_PROTO IPPROTO_RAW +static char frawok = 0; /*raw not working in FreeBSD*/ +#elif MACOS +#define RAW_DOMAIN AF_INET +#define RAW_PROTO IPPROTO_RAW +static char frawok = 0; /*raw not working in FreeBSD*/ +#elif WIN32 +#define RAW_DOMAIN AF_INET +#define RAW_PROTO IPPROTO_ICMP +static char frawok = 0; /*raw not working in Windows*/ +#else +#define RAW_DOMAIN AF_PACKET +#define RAW_PROTO htons(ETH_P_IP) +static char frawok = 1; /*raw works in Linux*/ +#endif + +#include +#include "ipmicmd.h" + +#ifndef INET_ADDRSTRLEN +#define INET_ADDRSTRLEN 16 +#endif +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 64 +#endif + +#define RMCP_PRI_RMCP_PORT 0x26F +#define SZ_PING 12 +#define IPMI_PING_MAX_LEN 50 /* usu 28 */ +#define CMD_GET_CHAN_AUTH_CAP 0x38 + +#ifdef WIN32 +int GetFirstIP(uchar *ipaddr, uchar *macadr, char *ipname, char fdb); /*ilan.c*/ +#endif + +/* + * Global variables + */ +static char * progver = "1.9"; +static char * progname = "idiscover"; +static char fdebug = 0; +static char fping = 1; +static char fraw = 0; +static char fBroadcastOk = 0; +static char fcanonical = 0; +static int broadcast_pings = 1; +//static uchar ipmi_maj = 0; +//static uchar ipmi_min = 0; +//static uchar netfn; +static ushort g_port = RMCP_PRI_RMCP_PORT; +static SockType g_sockfd = 0; +static SockType g_sockraw = 0; +static int g_limit = 30; /* after this many 'other' packets, stop. */ +static struct sockaddr_in _srcaddr; +// static struct sockaddr_in _destaddrlist[255]; +static struct in_addr _startAddr, _endAddr; +static char g_startDest[MAXHOSTNAMELEN+1] = {'\0'}; +static char g_endDest[MAXHOSTNAMELEN+1] = {'\0'}; +static char g_interface[INET_ADDRSTRLEN+1] = {""}; /*e.g. "eth0"*/ +static int g_num_packets = 0; +static int g_npings = 0; +static int g_npongs = 0; +static int g_recv_status = 0; +static int g_wait = 1; /* num sec to wait */ +static int g_delay = 0; /* num usec between sends */ +static int g_repeat = 1; /* number of times to repeat ping to each node */ +static char bdelim = BDELIM; /* '|' */ + +#ifdef METACOMMAND +extern FILE *fpdbg; /*from ipmicmd.c*/ +extern char *strlasterr(int rv); /*from ipmilan.c*/ +#else +void dump_buf(char *tag, uchar *pbuf, int sz, char fshowascii) +{ + uchar line[17]; + uchar a; + int i, j; + FILE *fpdbg; + + fpdbg = stdout; + line[0] = 0; line[16] = 0; + j = 0; + fprintf(fpdbg,"%s (len=%d): ", tag,sz); + for (i = 0; i < sz; i++) { + if (i % 16 == 0) { j = 0; fprintf(fpdbg,"%s\n %04x: ",line,i); } + if (fshowascii) { + a = pbuf[i]; + if (a < 0x20 || a > 0x7f) a = '.'; + line[j++] = a; + } + fprintf(fpdbg,"%02x ",pbuf[i]); + } + if (j < 16) { + line[j] = 0; + for (i = 0; i < (16-j); i++) fprintf(fpdbg," "); + } + fprintf(fpdbg,"%s\n",line); + return; +} +#endif + +void printerr( const char *pattn, ...) +{ + va_list arglist; + FILE *fderr; + + // fderr = fopen("/tmp/idiscover.log","a+"); + // if (fderr == NULL) return; + fderr = stderr; + + va_start(arglist, pattn); + vfprintf(fderr, pattn, arglist); + va_end(arglist); + + // fclose(fderr); +} + +static char *showlasterr(void) +{ + char *str; +#ifdef WIN32 + static char strbuf[80]; + int rv; + char *desc; + rv = WSAGetLastError(); +#ifdef METACOMMAND + /* get descriptions from strlasterr in ipmilan.c */ + desc = strlasterr(rv); +#else + if (rv == WSAECONNRESET) desc = "Connection reset"; /*10054*/ + else if (rv == WSAECONNREFUSED) desc = "Connection refused"; /*10061*/ + else if (rv == WSAEHOSTUNREACH) desc = "No route to host"; /*10065*/ + else desc = ""; +#endif + sprintf(strbuf,"LastError = %d %s",rv,desc); + str = strbuf; +#else + str = strerror(errno); +#endif + return(str); +} + +static void cleanup(void) +{ + SockType *pfd; + int i; + for (i = 0; i < 2; i++) { + if (i == 0) pfd = &g_sockfd; + else pfd = &g_sockraw; + if (*pfd > 0) { +#ifdef WIN32 + closesocket(*pfd); + WSACleanup(); +#else + close(*pfd); +#endif + } + *pfd = 0; + } +} + +void show_usage(void) +{ + printf("Usage: %s [-abegix] \n",progname); + printf(" -a all nodes, enables broadcast ping\n"); + printf(" -b beginning IP address (x.x.x.x), required\n"); + printf(" -e ending IP address (x.x.x.x), default is begin IP\n"); + printf(" -g use GetChanAuthCap instead of RMCP ping\n"); + printf(" -i interface name, default is eth0\n"); + printf(" -m get MAC addresses with a raw broadcast ping\n"); + printf(" -p N specific Port (IPMI LAN port=623)\n"); + printf(" -r N number of Repeat pings to each node (default=1)\n"); + // printf(" -s specific subnet\n"); + printf(" -x show eXtra debug messages\n"); +} + +static int os_sleep(unsigned int s, unsigned int u) +{ +#ifdef WIN32 + if (s == 0) { + if (u >= 1000) Sleep(u/1000); + } else { + Sleep(s * 1000); + } +#else +/*Linux*/ +#ifdef SELECT_TIMER + struct timeval tv; + tv.tv_sec = s; + tv.tv_usec = u; + if (select(1, NULL, NULL, NULL, &tv) < 0) + printerr("select: %s\n", showlasterr()); +#else + if (s == 0) { + usleep(u); + } else { + sleep(s); + } +#endif +#endif + return 0; +} + +void split_ip(uint addr, uchar *ip) +{ + ip[3] = (addr & 0x000000ff); + ip[2] = (addr & 0x0000ff00) >> 8; + ip[1] = (addr & 0x00ff0000) >> 16; + ip[0] = (addr & 0xff000000) >> 24; +} + +int ntoi(int addr) +{ + return(addr); +} + +void show_ip(int saddr) +{ + uchar ip[4]; + split_ip(saddr,ip); + printerr("%d.%d.%d.%d\n",ip[0],ip[1],ip[2],ip[3]); +} + +static int ipmilan_sendto(SockType s, const void *msg, size_t len, int flags, + const struct sockaddr *to, socklen_t tolen) +{ + int n; +#ifdef NEED_PAD + int fusepad = 0; + /* Never need a pad byte for ping/pong packets */ + if (len == 56 || len == 84 || len == 112 || len == 128 || len == 156) { + fusepad = 1; + len += 1; + } +#endif + n = (int)sendto(s,msg,len,flags,to,tolen); + // if (fusepad && (n > 0)) n--; + return(n); +} + +static int ipmilan_recvfrom(SockType s, void *buf, size_t len, int flags, + struct sockaddr *from, socklen_t *fromlen) +{ + int rv; + rv = (int)recvfrom(s,buf,len,flags,from,fromlen); + /* Sometimes the OS sends an ECONNREFUSED error, but + * retrying will catch the BMC's reply packet. */ +#ifdef WIN32 + if (rv < 0) { + int err; + err = WSAGetLastError(); + if (err == WSAECONNREFUSED) /*10061*/ + rv = (int)recvfrom(s,buf,len,flags,from,fromlen); + } +#else + if ((rv < 0) && (errno == ECONNREFUSED)) + rv = (int)recvfrom(s,buf,len,flags,from,fromlen); +#endif + return(rv); +} + +#if defined(WIN32) +int inet_aton(const char *cp, struct in_addr *inp) +{ + int rv; + int adr; + inp->s_addr = inet_addr(cp); + adr = (int)inp->s_addr; + if (adr == INADDR_NONE) rv = 0; + else rv = 1; /*success*/ + return(rv); +} +#elif defined(SOLARIS) +int find_ifname(char *ifname) +{ return(-1); } +#else +#include +int find_ifname(char *ifname) +{ + struct ifaddrs *ifaddr, *ifa; + int rv = -1; + if (getifaddrs(&ifaddr) == -1) return(rv); + for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr == NULL) continue; + if ((ifa->ifa_addr->sa_family != AF_INET) && + (ifa->ifa_addr->sa_family != AF_INET6)) continue; + if (strcmp(ifa->ifa_name,"lo") == 0) continue; + /* if here, we have a valid ifname */ + strcpy(ifname,ifa->ifa_name); + if (fdebug) printf("find_ifname: found %s\n",ifname); + rv = 0; + break; + } + freeifaddrs(ifaddr); + return(rv); +} +#endif + +int sock_init( char *_interface, char *_startIP, char *_endIP) +{ + int rv; + uchar *pb; + uchar val; + +#ifdef WIN32 + DWORD rvl; + rvl = WSAStartup(0x0101,&lan_ws); + if (rvl != 0) { + printerr("init: WSAStartup(1.1) error %ld\n", rvl); + return((int)rvl); + } +#else + char findif; +#endif + + if ((g_sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == SockInvalid) { + printerr("socket: %s\n", showlasterr()); + return(-1); + } + + memset(&_srcaddr, 0, sizeof(_srcaddr)); + _srcaddr.sin_family = AF_INET; + _srcaddr.sin_port = htons(0); + _srcaddr.sin_addr.s_addr = htonl(INADDR_ANY); + +#ifdef WIN32 + { + int ret; + uchar osip[4]; + uchar osmac[6]; + uchar osname[64]; + char ipstr[20]; + char *temp_start; + if (fBroadcastOk && (g_startDest[0] == 0)) { + ret = GetFirstIP(osip,osmac,osname,fdebug); /*ilan.c*/ + if (ret == 0) { + // osip[3] = 0xFF; /*255 for broadcast*/ + sprintf(ipstr,"%d.%d.%d.255",osip[0],osip[1],osip[2]); + temp_start = ipstr; + strcpy(g_startDest,temp_start); + strcpy(g_endDest,temp_start); + } else { /*use some defaults*/ + strcpy(g_startDest,"255.255.255.255"); + strcpy(g_endDest,"255.255.255.255"); + } + } + } +#elif defined(HPUX) + { /*find the OS eth interface to use*/ + char devname[INET_ADDRSTRLEN+1]; + int i, n; + n = 0; + sprintf(devname,"lan%d",n); + } +#else + { /*find the OS eth interface to use*/ + struct sockaddr_in temp_sockaddr; + char *temp_start; + struct ifreq ifr; + char devname[INET_ADDRSTRLEN+1]; + int i, n; + if (_interface == NULL) findif = 1; + else if (_interface[0] == 0) findif = 1; + else findif = 0; + if (findif) { + n = find_ifname(devname); + if (n >= 0) { + _interface = devname; + findif = 0; + } + } + if (findif) + { /* try again to find the first active ethN interface */ + n = -1; + for (i = 0; (i < 16) && (n == -1); i++) { +#ifdef SOLARIS + sprintf(devname,"e1000g%d",i); +#elif BSD + sprintf(devname,"em%d",i); +#else + sprintf(devname,"eth%d",i); +#endif + strcpy(ifr.ifr_name, devname); + ifr.ifr_addr.sa_family = AF_INET; + if (ioctl(g_sockfd, SIOCGIFADDR, &ifr) >= 0) { + /* valid IP address, so active interface, use it */ + temp_sockaddr = *((struct sockaddr_in *)&ifr.ifr_addr); + memcpy(&_srcaddr.sin_addr.s_addr, &temp_sockaddr.sin_addr.s_addr, + sizeof(_srcaddr.sin_addr.s_addr)); + strcpy(g_interface, devname); + temp_start = inet_ntoa(temp_sockaddr.sin_addr); + if (temp_start == NULL) temp_start = ""; + else if (fBroadcastOk && (g_startDest[0] == 0)) { + pb = (uchar *)&temp_sockaddr.sin_addr.s_addr; + pb[3] = 0xFF; /*255 for broadcast*/ + temp_start = inet_ntoa(temp_sockaddr.sin_addr); + strcpy(g_startDest,temp_start); + strcpy(g_endDest,temp_start); + } + printf("sock_init: found %s with %s\n",devname,temp_start); + n = i; + break; + } + } + if (n < 0) rv = LAN_ERR_OTHER; /*-13*/ + } else { /* valid _interface string */ + if (strchr(_interface, '.') != NULL) + { /* assume it is an IP address*/ + if ((rv = inet_pton(AF_INET, _interface, &_srcaddr.sin_addr)) < 0) + printerr("inet_pton: %s\n", showlasterr()); + if (rv == 0) + printerr("invalid interface address\n"); + return(rv); + } + else + { /* assume interface name, like eth0 */ + strncpy(ifr.ifr_name, _interface, IFNAMSIZ); + ifr.ifr_addr.sa_family = AF_INET; + if (ioctl(g_sockfd, SIOCGIFADDR, &ifr) < 0) { + printerr("ioctl(%s): %s\n", _interface, showlasterr()); + return(-1); + } + + temp_sockaddr = *((struct sockaddr_in *)&ifr.ifr_addr); + memcpy(&_srcaddr.sin_addr.s_addr, &temp_sockaddr.sin_addr.s_addr, + sizeof(_srcaddr.sin_addr.s_addr)); + if (fBroadcastOk && (g_startDest[0] == 0)) { + pb = (uchar *)&temp_sockaddr.sin_addr.s_addr; + pb[3] = 0xFF; /*255 for broadcast*/ + temp_start = inet_ntoa(temp_sockaddr.sin_addr); + strcpy(g_startDest,temp_start); + strcpy(g_endDest,temp_start); + } + } + } + } +#endif + + if (fBroadcastOk) { + rv = setsockopt(g_sockfd, SOL_SOCKET, SO_BROADCAST, + (char *)&broadcast_pings, sizeof(broadcast_pings)); + if (rv) { + printerr("setsockopt: %s\n", showlasterr()); + return(-1); + } + } + + if (bind(g_sockfd, (struct sockaddr *)&_srcaddr, sizeof(_srcaddr)) < 0) { + printerr("bind: %s\n", showlasterr()); + return(-1); + } + + rv = inet_aton(_startIP, &_startAddr); + if (rv ) { + _startAddr.s_addr = ntohl(_startAddr.s_addr); + if (fdebug) show_ip(_startAddr.s_addr); + pb = (unsigned char*)&_startAddr.s_addr; + if (pb[0] < 1) + printerr("Malformed begin IP: %s\n", _startIP); + else if (!fBroadcastOk && (pb[0] >254) ) + printerr("Malformed begin IP: %s\n", _startIP); + else if (fBroadcastOk) { + val = pb[0] & 0x0f; + if (val == 0x0f) rv = 0; + else printerr("Malformed begin broadcast IP: %s\n", _startIP); + } else rv = 0; + } else { + printerr("Invalid begin IP: %s\n", _startIP); + } + if (rv) return(rv); + + rv = inet_aton(_endIP, &_endAddr); + if (rv ) { + _endAddr.s_addr = ntohl(_endAddr.s_addr); + if (fdebug) show_ip(_endAddr.s_addr); + pb = (unsigned char*)&_endAddr.s_addr; + if (pb[0] < 1) + printerr("Malformed end IP: %s\n", _endIP); + else if (!fBroadcastOk && (pb[0] >254) ) + printerr("Malformed end IP: %s\n", _endIP); + else rv = 0; + } else { + printerr("Invalid end IP: %s\n", _endIP); + } + + /* calculate g_num_packets */ + g_num_packets = ntoi(_endAddr.s_addr) - ntoi(_startAddr.s_addr) + 1; + if (fdebug) printerr("g_num_packets = %d\n",g_num_packets); + if (g_num_packets < 1) g_num_packets = 0; + + return(rv); +} /*end sock_init*/ + +void *receiveThread(void *p) +{ + uchar buffer[IPMI_PING_MAX_LEN]; + struct timeval tv; + fd_set rset; + int rv, len; + static int needlf = 0; + char host[200]; + SockType sockrecv; + int nothers = 0; + int addr_type = AF_INET; /*or AF_INET6*/ +#ifndef WIN32 + struct hostent *h_ent = NULL; + char serv[200]; + int r; +#endif + + sockrecv = g_sockfd; + if (fraw) { /* opening SOCK_RAW requires admin/root privilege. */ + if ((g_sockraw = socket(RAW_DOMAIN, SOCK_RAW,RAW_PROTO)) == SockInvalid) + { + printerr("raw socket: %s\n", showlasterr()); + fraw = 0; + } else { + sockrecv = g_sockraw; + if (fdebug) printf("g_sockraw = %d\n",g_sockraw); + } + } + + /* receive while loop */ + do + { + tv.tv_sec = g_wait; + tv.tv_usec = 0; + FD_ZERO(&rset); + FD_SET(sockrecv, &rset); + g_recv_status = 0; + + if (fdebug) printerr("waiting for ping %d response\n",g_npings); + if ((rv = select((int)(sockrecv+1), &rset, NULL, NULL, &tv)) < 0) { + printerr("select: %s\n", showlasterr()); + cleanup(); + exit(rv); // error, exit idiscover recv thread + } + + if (fdebug) printerr("select rv = %d\n",rv); + if (rv > 0) + { + struct sockaddr_in from; + socklen_t fromlen; + char rstr[40]; + char macstr[20]; + struct in_addr from_ip; + char estr[40]; + + if (needlf) { printf("\n"); needlf = 0; } + g_recv_status = 1; + fromlen = sizeof(from); + len = ipmilan_recvfrom(sockrecv, buffer, IPMI_PING_MAX_LEN, 0, + (struct sockaddr *)&from, &fromlen); + if (fdebug) printerr("recvfrom rv = %d\n",rv); + if (len < 0) { + printerr("ipmilan_recvfrom: %s\n", showlasterr()); + continue; + } + if (fdebug) { + /* can we get the MAC addr of the responder also? */ + // dump_buf("from_addr",(uchar *)&from,fromlen,0); + dump_buf("recvfrom",buffer,len,0); + } + g_recv_status = 2; + g_npongs++; + macstr[0] = 0; + if (fraw) { /* Raw packet, include MAC address string */ + /* + * Sample raw packet for UDP ping response + * dst_mac src_mac eth_p iphdr + * 0000: 00 07 e9 06 15 31 00 0e 0c 2b b5 81 08 00 45 00 + * udp src_ip dst_ip + * 0010: 00 38 00 00 40 00 40 11 b6 01 c0 a8 01 c2 c0 a8 + * rmcp + * 0020: 01 a1 02 6f 80 1e 00 24 0e d1 06 00 ff 06 00 00 + * 0030: 11 be + */ + if ((buffer[23] != 0x11) || (buffer[42] != 0x06)) { + /* [23]: 0x11==UDP, 0x06==TCP ; [42]: 0x06 ==RMCP */ + if (nothers > g_limit) { + if (fdebug) + printf("got %d other packets, stop.\n",nothers); + break; + } + nothers++; + continue; + } + if (buffer[6] == 0xFF || buffer[26] == 0xFF) /*broadcast*/ + continue; + sprintf(macstr,"%02x:%02x:%02x:%02x:%02x:%02x %c", + buffer[6], buffer[7], buffer[8], /*06=src_mac*/ + buffer[9], buffer[10], buffer[11], bdelim); + memcpy(&from_ip,&buffer[26],4); /*26=src_ip*/ + } else { + memcpy(&from_ip,&from.sin_addr,4); + } + host[0] = 0; +#ifndef WIN32 +/* Linux, BSD, Solaris, MacOS */ +#if !defined(CROSS_COMPILE) + h_ent = gethostbyaddr((void *)&from_ip,4,addr_type); + if (h_ent != NULL) { + strncpy(host,h_ent->h_name,sizeof(host)); + } else if (!fraw) +#endif + { + r = getnameinfo((struct sockaddr *)&from, fromlen, + host, sizeof(host), serv, sizeof(serv), 0); + if (r) host[0] = 0; + else if (host[0] >= '0' && host[0] <= '9') host[0] = 0; + } +#endif + // parse the received pong + rstr[0] = 0; + if (fping == 0 && len > 0) { /* -g and got rsp data */ + /* parse GetChanAuthcap response into rstr */ + /* 4 bytes RMCP, 10 bytes IPMI session, then msg */ + /* 6 bytes msg hdr, then rsp data */ + /* 20 = ccode, 21 = chan, 22 = auth type support */ + if (buffer[20] != 0) /*ccode error*/ + sprintf(rstr,"%c (ccode=0x%02x)",bdelim,buffer[20]); + else /*ccode is ok*/ + sprintf(rstr,"%c (channel %d)",bdelim,buffer[21]); + } + if (fcanonical) { + estr[0] = 0; + rstr[0] = 0; + } else { + sprintf(estr,"response from %c ",bdelim); + } + /* &buffer[0] = source MAC, &buffer[6] = destination MAC */ + printf("%.2d%c %s%s %s \t%c %s %s\n", + g_npongs,bdelim,estr,macstr,inet_ntoa(from_ip), + bdelim,host,rstr); + } + else { /*ping, no answer*/ + if (!fBroadcastOk) { + printf("."); fflush(stdout); /*show progress*/ + needlf = 1; + } + } + } +#ifdef NO_THREADS + while(fBroadcastOk && rv > 0); +#else + while(1); +#endif + return(p); +} + +/* + * send_ping_pkt: + * RMCP Ping buffer, sent as a UDP packet to port 0x026f. + * rmcp.ver = 0x06 // RMCP Version 1.0 + * rmcp.resvd = 0x00 // RESERVED + * rmcp.seq = 0xff // no RMCP ACK + * rmcp.class = 0x06 // RMCP_CLASS_ASF + * asf.iana = 0x000011BE // ASF_RMCP_IANA (hi-lo) + * asf.type = 0x80 // ASF_TYPE_PING + * asf.tag = 0x00 // ASF sequence number + * asf.resvd = 0x00 // RESERVED + * asf.len = 0x00 + */ +int send_ping_pkt(struct sockaddr_in *_daddr, uchar seq) +{ + uchar pingbuf[SZ_PING] = {06,0,0xFF,06,0x00,0x00,0x11,0xBE,0x80,0,0,0 }; + int rv, len; + + pingbuf[9] = seq; + len = sizeof(pingbuf); + if (fdebug) dump_buf("send_ping",pingbuf,len,0); + rv = ipmilan_sendto(g_sockfd, pingbuf, len, 0, + (struct sockaddr *)_daddr, sizeof(struct sockaddr_in)); + return(rv); +} + +static int send_poke1(struct sockaddr_in *_daddr) +{ + int rv; + uchar asfpkt[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x20, 0x18, 0xc8, 0xc2, 0x01, 0x01, 0x3c }; + if (fdebug) dump_buf("send_poke1",asfpkt,16,0); + rv = ipmilan_sendto(g_sockfd, asfpkt, 16, 0, + (struct sockaddr *)_daddr, sizeof(struct sockaddr_in)); + return rv; +} + +static uchar cksum(const uchar *buf, register int len) +{ + register uchar csum; + register int i; + + /* 8-bit 2s compliment checksum */ + csum = 0; + for (i = 0; i < len; i++) + csum = (csum + buf[i]) % 256; + csum = -csum; + return(csum); +} + +static int send_getauth(struct sockaddr_in *_daddr, uchar seq) +{ + int rv, len; + // static uchar swseq = 0; + uchar getauthpkt[23] = { 0x06, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x20, 0x18, + 0xc8, 0x81, 0x04, 0x38, 0x0e, 0x04, 0x31 }; + /* + * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 + * 06 00 ff 07 00 00 00 00 00 00 00 00 00 09 20 18 c8 81 04 38 0e 04 31 + * [RMCP hdr ] [IPMI session hdr (len)] [IPMI msg ] [data] + */ + // getauthpkt[8] = 0x00; /* seq always 00 for GetChanAuthCap */ + getauthpkt[21] = 0x02; /*requested priv_level: 2=user, 4=admin*/ + getauthpkt[22] = cksum(&getauthpkt[17],5); + len = sizeof(getauthpkt); + if (fdebug) dump_buf("send_getauth",getauthpkt,len,0); + rv = ipmilan_sendto(g_sockfd, getauthpkt, len, 0, + (struct sockaddr *)_daddr, sizeof(struct sockaddr_in)); + if (fdebug) + printf("send_getauth: rv = %d\n",rv); + return rv; +} + +int send_probe(struct sockaddr_in *_daddr, uchar seq) +{ + int rv; + + if (fBroadcastOk) { + rv = setsockopt(g_sockfd, SOL_SOCKET, SO_BROADCAST, + (char *)&broadcast_pings, sizeof(broadcast_pings)); + if (fdebug) { + char *estr; + if (rv) estr = showlasterr(); + else estr = ""; + printerr("setsockopt(broadcast): rv=%d %s\n", rv,estr); + } + } + if (fping) + rv = send_ping_pkt( _daddr, seq); + else + rv = send_getauth( _daddr, seq); + return(rv); +} + +void *sendThread(void *p) +{ + int i, j, n; + // char _dest[MAXHOSTNAMELEN+1]; + char _dest_ip[INET_ADDRSTRLEN+1]; + struct sockaddr_in _destaddr; + uchar o[4]; + uint ip; + uchar _seq; + int rv; + + n = g_num_packets; /*num*/ + ip = _startAddr.s_addr; + + for (i = 0; i < n; i++) + { + split_ip(ip,o); + if (o[3] == 0) continue; + if (!fBroadcastOk && (o[3] == 255)) continue; + sprintf(_dest_ip,"%d.%d.%d.%d",o[0],o[1],o[2],o[3]); + + /* set _destaddr */ + _destaddr.sin_family = AF_INET; + _destaddr.sin_port = htons(g_port); + if ( !inet_aton( _dest_ip, &_destaddr.sin_addr)) { + printerr("inet_aton error %s\n",_dest_ip); + continue; + } + + for (j=0; j= 0) { + receiveThread(NULL); + } + } +#endif + + /* sleep an interval (g_delay usec) */ + if (g_delay > 0) os_sleep(0,g_delay); + } /*end-for g_repeat*/ + + ip++; /* increment to next IP */ + } + return(p); +} + +#ifdef METACOMMAND +int i_discover(int argc, char **argv) +#else +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#endif +{ + int rv = 0; + int c; +#ifndef NO_THREADS + char message[32]; + pthread_t thread[2]; + int iret[2]; +#endif + +#ifdef METACOMMAND + fpdbg = stdout; +#endif + printf("%s ver %s\n", progname,progver); + + while ( (c = getopt( argc, argv,"ab:ce:gi:l:mp:r:s:x?")) != EOF ) + switch(c) { + case 'a': fBroadcastOk = 1; fping = 1; + break; /*all (broadcast ping)*/ + case 'c': /*canonical, CSV*/ + fcanonical = 1; + bdelim = BCOMMA; + break; + case 'm': /* show MAC address, use raw, requires root priv */ + fBroadcastOk = 1; fping = 1; fraw = 1; + break; /*all (broadcast ping)*/ + case 'l': g_limit = atoi(optarg); break; + case 'g': fping = 0; break; /*use get chan auth cap method */ + case 'b': /*begin*/ + strncpy(g_startDest,optarg,MAXHOSTNAMELEN); + break; + case 'e': /*end*/ + strncpy(g_endDest,optarg,MAXHOSTNAMELEN); + break; + case 'i': /*interface*/ + strncpy(g_interface,optarg,sizeof(g_interface)); + break; + case 'p': /*port/socket*/ + g_port = (ushort)atoi(optarg); + break; + case 'r': /*repeat N times*/ + g_repeat = atoi(optarg); + break; + case 's': /*subnet*/ + /* copy optarg from 10.243.42.0 or similar, to + * begin/end range. */ + break; + case 'x': fdebug = 1; break; /* debug messages */ + default: + if (fdebug) printerr("getopt(%c) default\n",c); + show_usage(); + rv = ERR_USAGE; + goto do_exit; + } +#ifdef WIN32 + /* Winsock inet_aton() does not like 255.255.255.255 */ + if (!fBroadcastOk && (g_startDest[0] == 0) ) { + show_usage(); + printerr("A beginning IP is required, using -b\n"); + goto do_exit; + } +#else + if (g_startDest[0] == 0) { + strcpy(g_startDest,"255.255.255.255"); /* INADDR_BROADCAST */ + fBroadcastOk = 1; + } +#endif + if (fraw == 1) { + if (frawok == 0) { + printf("Warning: SOCK_RAW not yet implemented on this OS\n"); + } +#ifdef LINUX + else { + c = geteuid(); + if (c > 1) printf("Must be root/superuser to use SOCK_RAW\n"); + } +#endif + } + if (g_endDest[0] == 0 || fBroadcastOk) + strcpy(g_endDest,g_startDest); /*only one IP address*/ + if (fdebug) + printerr("intf=%s begin=%s end=%s port=%d\n", + g_interface,g_startDest,g_endDest,g_port); + + rv = sock_init(g_interface, g_startDest, g_endDest); + if (fdebug) printerr("sock_init rv = %d, sockfd = %d\n",rv,g_sockfd); + if (rv != 0) { + show_usage(); + printerr("sock_init error %d\n",rv); + goto do_exit; + } + + printf("Discovering IPMI Devices:\n"); +#ifdef NO_THREADS + sendThread(NULL); +#else + iret[1] = pthread_create( &thread[1], NULL, receiveThread, (void*) message); + iret[0] = pthread_create( &thread[0], NULL, sendThread, (void*) message); + pthread_join( thread[0], NULL); + pthread_join( thread[1], NULL); +#endif + + // if (fdebug) + printf("\n%s: %d pings sent, %d responses\n",progname,g_npings,g_npongs); + +do_exit: + cleanup(); + return(rv); +} /* end main()*/ + +/* end idiscover.c */ diff --git a/util/iekanalyzer.c b/util/iekanalyzer.c new file mode 100644 index 0000000..ddeeba8 --- /dev/null +++ b/util/iekanalyzer.c @@ -0,0 +1,4131 @@ +/* + * iekanalyzer.c + * Handle FRU EKey Analyzer functions + * + * Change history: + * 09/08/2010 ARCress - included in source tree + * + *--------------------------------------------------------------------- + */ +/* + * Copyright (c) 2007 Kontron Canada, Inc. All Rights Reserved. + * + * Base on code from + * 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. + */ + +#include +#include +#include +#include +#ifdef WIN32 +#include +#include "getopt.h" +#else +#include +#if defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include +#else +#include +#endif +#endif +#include "ipmicmd.h" +#include "iekanalyzer.h" + +extern int verbose; /*ipmilanplus.c*/ +extern void lprintf(int level, const char * format, ...); /*ipmilanplus.c*/ +extern void set_loglevel(int level); + +/* fseek wrapper for size_t/long compile warnings */ +static int fseek_(FILE *fp, size_t offset, int whence) +{ return(fseek(fp, (long)offset, whence)); } + +/***************************************************************** +* CONSTANT +*****************************************************************/ +const int ERROR_STATUS = -1; +const int OK_STATUS = 0; + +const char * STAR_LINE_LIMITER = + "*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*"; +const char * EQUAL_LINE_LIMITER = + "================================================================="; +const int SIZE_OF_FILE_TYPE = 3; +const unsigned char AMC_MODULE = 0x80; +const int PICMG_ID_OFFSET = 3; +#define MAX_ARGC (MAX_FILE_NUMBER+4) /*8+4=12*/ +#define COMPARE_CANDIDATE 2 +/*In AMC.0 or PICMG 3.0 specification offset start from 0 with 3 bytes of +* Mfg.ID, 1 byte of Picmg record Id, and +* 1 byte of format version, so the data offset start from 5 +*/ +#define LOWER_OEM_TYPE 0xf0 +#define UPPER_OEM_TYPE 0xfe +const int START_DATA_OFFSET = 5; +const unsigned char DISABLE_PORT = 0x1f; + +const struct valstr ipmi_ekanalyzer_module_type[] = { + { ON_CARRIER_FRU_FILE, "On-Carrier Device" }, + { A1_AMC_FRU_FILE, "AMC slot A1" }, + { A2_AMC_FRU_FILE, "AMC slot A2" }, + { A3_AMC_FRU_FILE, "AMC slot A3" }, + { A4_AMC_FRU_FILE, "AMC slot A4" }, + { B1_AMC_FRU_FILE, "AMC slot B1" }, + { B2_AMC_FRU_FILE, "AMC slot B2" }, + { B3_AMC_FRU_FILE, "AMC slot B3" }, + { B4_AMC_FRU_FILE, "AMC slot B4" }, + { RTM_FRU_FILE, "RTM" }, /*This is OEM specific module*/ + { CONFIG_FILE, "Configuration file" }, + { SHELF_MANAGER_FRU_FILE, "Shelf Manager" }, + { 0xffff , NULL }, +}; + +const struct valstr ipmi_ekanalyzer_IPMBL_addr[] = { + { 0x72, "AMC slot A1" }, + { 0x74, "AMC slot A2" }, + { 0x76, "AMC slot A3" }, + { 0x78, "AMC slot A4" }, + { 0x7a, "AMC slot B1" }, + { 0x7c, "AMC slot B2" }, + { 0x7e, "AMC slot B3" }, + { 0x80, "AMC slot B4" }, + { 0x90, "RTM"}, /*This is OEM specific module*/ + { 0xffff , NULL }, +}; + +const struct valstr ipmi_ekanalyzer_link_type[] = { + { 0x00, "Reserved" }, + { 0x01, "Reserved" }, + { 0x02, "AMC.1 PCI Express" }, + { 0x03, "AMC.1 PCI Express Advanced Switching" }, + { 0x04, "AMC.1 PCI Express Advanced Switching" }, + { 0x05, "AMC.2 Ethernet" }, + { 0x06, "AMC.4 Serial RapidIO" }, + { 0x07, "AMC.3 Storage" }, + /*This is OEM specific module*/ + { 0xf0, "OEM Type 0"}, + { 0xf1, "OEM Type 1"}, + { 0xf2, "OEM Type 2"}, + { 0xf3, "OEM Type 3"}, + { 0xf4, "OEM Type 4"}, + { 0xf5, "OEM Type 5"}, + { 0xf6, "OEM Type 6"}, + { 0xf7, "OEM Type 7"}, + { 0xf8, "OEM Type 8"}, + { 0xf9, "OEM Type 9"}, + { 0xfa, "OEM Type 10"}, + { 0xfb, "OEM Type 11"}, + { 0xfc, "OEM Type 12"}, + { 0xfd, "OEM Type 13"}, + { 0xfe, "OEM Type 14"}, + { 0xff , "Reserved" }, +}; + +/*Reference: AMC.1 specification*/ +const struct valstr ipmi_ekanalyzer_extension_PCIE[] = { + { 0x00, "Gen 1 capable - non SSC" }, + { 0x01, "Gen 1 capable - SSC" }, + { 0x02, "Gen 2 capable - non SSC" }, + { 0x03, "Gen 3 capable - SSC" }, + { 0x0f, "Reserved"}, +}; +/*Reference: AMC.2 specification*/ +const struct valstr ipmi_ekanalyzer_extension_ETHERNET[] = { + { 0x00, "1000BASE-BX (SerDES Gigabit) Ethernet link" }, + { 0x01, "10GBASE-BX4 10 Gigabit Ethernet link" }, +}; +/*Reference: AMC.3 specification*/ +const struct valstr ipmi_ekanalyzer_extension_STORAGE[] = { + { 0x00, "Fibre Channel (FC)" }, + { 0x01, "Serial ATA (SATA)" }, + { 0x02, "Serial Attached SCSI (SAS/SATA)" }, +}; + +const struct valstr ipmi_ekanalyzer_asym_PCIE[] = { + { 0x00, "exact match"}, + { 0x01, "provides a Primary PCI Express Port" }, + { 0x02, "provides a Secondary PCI Express Port" }, +}; + +const struct valstr ipmi_ekanalyzer_asym_STORAGE[] = { + { 0x00, "FC or SAS interface {exact match}" }, + { 0x01, "SATA Server interface" }, + { 0x02, "SATA Client interface" }, + { 0x03, "Reserved" }, +}; + +const struct valstr ipmi_ekanalyzer_picmg_record_id[] = { + { 0x04, "Backplane Point to Point Connectivity Record" }, + { 0x10, "Address Table Record" }, + { 0x11, "Shelf Power Distribution Record" }, + { 0x12, "Shelf Activation and Power Management Record" }, + { 0x13, "Shelf Manager IP Connection Record" }, + { 0x14, "Board Point to Point Connectivity Record" }, + { 0x15, "Radial IPMB-0 Link Mapping Record" }, + { 0x16, "Module Current Requirements Record" }, + { 0x17, "Carrier Activation and Power Management Record" }, + { 0x18, "Carrier Point-to-Point Connectivity Record" }, + { 0x19, "AdvancedMC Point-to-Point Connectivity Record" }, + { 0x1a, "Carrier Information Table" }, + { 0x1b, "Shelf Fan Geography Record" }, + { 0x2c, "Carrier Clock Point-to-Point Connectivity Record" }, + { 0x2d, "Clock Configuration Record" }, +}; + +struct ipmi_ek_multi_header { + struct fru_multirec_header header; + unsigned char * data; + struct ipmi_ek_multi_header * prev; + struct ipmi_ek_multi_header * next; +}; + +struct ipmi_ek_amc_p2p_connectivity_record{ + unsigned char guid_count; + struct fru_picmgext_guid * oem_guid; + unsigned char rsc_id; + unsigned char ch_count; + struct fru_picmgext_amc_channel_desc_record * ch_desc; + unsigned char link_desc_count; + struct fru_picmgext_amc_link_desc_record * link_desc; + int * matching_result; /*For link descriptor comparision*/ +}; + +/***************************************************************************** +* Function prototype +******************************************************************************/ +/* global variables */ +static char * progname = "iekanalyzer"; +static char * progver = "1.00"; +static char fdebug = 0; +static uchar g_bus = PUBLIC_BUS; +static uchar g_sa = BMC_SA; +static uchar g_lun = BMC_LUN; +static uchar g_addrtype = ADDR_SMI; + +#ifndef HAVE_LANPLUS +/* define these routines in ipmilanplus.c if no lanplus/helper.c */ +extern const char * val2str(uint16_t val, const struct valstr *vs); +#endif +/**************************************************************************** +* command Functions +*****************************************************************************/ +static int ipmi_ekanalyzer_print( int argc, char * opt, + char ** filename, int * file_type ); + +static tboolean ipmi_ekanalyzer_ekeying_match( int argc, char * opt, + char ** filename, int * file_type ); + + +/**************************************************************************** +* Linked list Functions +*****************************************************************************/ +static void ipmi_ek_add_record2list( struct ipmi_ek_multi_header ** record, + struct ipmi_ek_multi_header ** list_head, + struct ipmi_ek_multi_header ** list_last ); + +static void ipmi_ek_display_record( struct ipmi_ek_multi_header * record, + struct ipmi_ek_multi_header * list_head, + struct ipmi_ek_multi_header * list_last ); + +static void ipmi_ek_remove_record_from_list( + struct ipmi_ek_multi_header * record, + struct ipmi_ek_multi_header ** list_head, + struct ipmi_ek_multi_header ** list_last ); + +static int ipmi_ekanalyzer_fru_file2structure( char * filename, + struct ipmi_ek_multi_header ** list_head, + struct ipmi_ek_multi_header ** list_record, + struct ipmi_ek_multi_header ** list_last ); + +/**************************************************************************** +* Ekeying match Functions +*****************************************************************************/ +static int ipmi_ek_matching_process( int * file_type, int index1, int index2, + struct ipmi_ek_multi_header ** list_head, + struct ipmi_ek_multi_header ** list_last, char * opt, + struct ipmi_ek_multi_header * pphysical ); + +static int ipmi_ek_get_resource_descriptor( int port_count, int index, + struct fru_picmgext_carrier_p2p_descriptor * port_desc, + struct ipmi_ek_multi_header * record ); + +static int ipmi_ek_create_amc_p2p_record( struct ipmi_ek_multi_header * record, + struct ipmi_ek_amc_p2p_connectivity_record * amc_record ); + +static int ipmi_ek_compare_link( struct ipmi_ek_multi_header * physic_record, + struct ipmi_ek_amc_p2p_connectivity_record record1, + struct ipmi_ek_amc_p2p_connectivity_record record2, + char * opt, int file_type1, int file_type2 ); + +static tboolean ipmi_ek_compare_channel_descriptor( + struct fru_picmgext_amc_channel_desc_record ch_desc1, + struct fru_picmgext_amc_channel_desc_record ch_desc2, + struct fru_picmgext_carrier_p2p_descriptor * port_desc, + int index_port, unsigned char rsc_id ); + +static int ipmi_ek_compare_link_descriptor( + struct ipmi_ek_amc_p2p_connectivity_record record1, int index1, + struct ipmi_ek_amc_p2p_connectivity_record record2, int index2 ); + +static int ipmi_ek_compare_asym( unsigned char asym[COMPARE_CANDIDATE] ); + +static int ipmi_ek_compare_number_of_enable_port( + struct fru_picmgext_amc_link_desc_record link_desc[COMPARE_CANDIDATE] ); + +static int ipmi_ek_check_physical_connectivity( + struct ipmi_ek_amc_p2p_connectivity_record record1, int index1, + struct ipmi_ek_amc_p2p_connectivity_record record2, int index2, + struct ipmi_ek_multi_header * record, + int filetype1, int filetype2, char * option ); + +/**************************************************************************** +* Display Functions +*****************************************************************************/ +static int ipmi_ek_display_fru_header( char * filename ); + +static void ipmi_ek_display_fru_header_detail( char * filename ); + +static void ipmi_ek_display_chassis_info_area( FILE * input_file, long offset ); + +static size_t ipmi_ek_display_board_info_area( FILE * input_file, + char * board_type, unsigned int * board_length ); + +static void ipmi_ek_display_product_info_area( FILE * input_file, long offset ); + +static tboolean ipmi_ek_display_link_descriptor( int file_type, + unsigned char rsc_id, char * str, + struct fru_picmgext_amc_link_desc_record link_desc ); + +static void ipmi_ek_display_oem_guid( + struct ipmi_ek_amc_p2p_connectivity_record amc_record1 ); + +static int ipmi_ek_diplay_carrier_connectivity( + struct ipmi_ek_multi_header * record ); + +static int ipmi_ek_display_power( int argc, char * opt, + char ** filename, int * file_type ); + +static void ipmi_ek_display_current_descriptor( + struct fru_picmgext_carrier_activation_record car, + struct fru_picmgext_activation_record * cur_desc, char * filename ); + +static void ipmi_ek_display_backplane_p2p_record( + struct ipmi_ek_multi_header * record ); + +static void ipmi_ek_display_address_table_record( + struct ipmi_ek_multi_header * record ); + +static void ipmi_ek_display_shelf_power_distribution_record( + struct ipmi_ek_multi_header * record ); + +static void ipmi_ek_display_shelf_activation_record( + struct ipmi_ek_multi_header * record ); + +static void ipmi_ek_display_shelf_ip_connection_record( + struct ipmi_ek_multi_header * record ); + +static void ipmi_ek_display_board_p2p_record( + struct ipmi_ek_multi_header * record ); + +static void ipmi_ek_display_radial_ipmb0_record( + struct ipmi_ek_multi_header * record ); + +static void ipmi_ek_display_amc_current_record( + struct ipmi_ek_multi_header * record ); + +static void ipmi_ek_display_amc_activation_record ( + struct ipmi_ek_multi_header * record ); + +static void ipmi_ek_display_amc_p2p_record( + struct ipmi_ek_multi_header * record ); + +static void ipmi_ek_display_amc_carrier_info_record( + struct ipmi_ek_multi_header * record ); + +static void ipmi_ek_display_clock_carrier_p2p_record( + struct ipmi_ek_multi_header * record ); + +static void ipmi_ek_display_clock_config_record( + struct ipmi_ek_multi_header * record ); + +/************************************************************************** +* +* Function name: ipmi_ekanalyzer_usage +* +* Description : Print the usage (help menu) of ekeying analyzer tool +* +* Restriction : None +* +* Input : None +* +* Output : None +* +* Global : None +* +* Return : None +* +***************************************************************************/ +static void +ipmi_ekanalyzer_usage( void ) +{ + char * help_message = +"Ekeying analyzer tool version 1.00 \r\n\ +ekanalyzer Commands: \r\n\ + print [carrier | power | all] ... \r\n\ + frushow \r\n\ + summary [match | unmatch | all] ... \r\n\ +"; + printf("%s",help_message); + fflush(stdout); +} + +/************************************************************************** +* +* Function name: ipmi_ek_get_file_type +* +* Description: this function takes an argument, then xtract the file type and +* convert into module type (on carrier, AMC,...) value. +* +* +* Restriction: None +* +* Input: argument: strings contain the type and the name of the file +* together +* +* Output: None +* +* Global: None +* +* Return: Return value of module type: On carrier FRU file, A1 FRUM file... +* if the file type is invalid, it return -1. See structure +* ipmi_ekanalyzer_module_type for a list of valid type. +***************************************************************************/ +static int +ipmi_ek_get_file_type( char * argument ) +{ + // int index_name=0; + int filetype = ERROR_STATUS; + + if( strlen (argument) > MIN_ARGUMENT ){ + if( strncmp( argument, "oc=", SIZE_OF_FILE_TYPE ) == 0 ) { + filetype = ON_CARRIER_FRU_FILE; + } + else if( strncmp( argument, "a1=", SIZE_OF_FILE_TYPE ) == 0 ) { + filetype = A1_AMC_FRU_FILE; + } + else if( strncmp( argument, "a2=", SIZE_OF_FILE_TYPE ) == 0 ) { + filetype = A2_AMC_FRU_FILE; + } + else if( strncmp( argument, "a3=", SIZE_OF_FILE_TYPE ) == 0 ) { + filetype = A3_AMC_FRU_FILE; + } + else if( strncmp( argument, "a4=", SIZE_OF_FILE_TYPE ) == 0 ) { + filetype = A4_AMC_FRU_FILE; + } + else if( strncmp( argument, "b1=", SIZE_OF_FILE_TYPE ) == 0 ) { + filetype = B1_AMC_FRU_FILE; + } + else if( strncmp( argument, "b2=", SIZE_OF_FILE_TYPE ) == 0 ) { + filetype = B2_AMC_FRU_FILE; + } + else if( strncmp( argument, "b3=", SIZE_OF_FILE_TYPE ) == 0 ) { + filetype = B3_AMC_FRU_FILE; + } + else if( strncmp( argument, "b4=", SIZE_OF_FILE_TYPE ) == 0 ) { + filetype = B4_AMC_FRU_FILE; + } + else if( strncmp( argument, "rt=", SIZE_OF_FILE_TYPE ) == 0 ) { + filetype = RTM_FRU_FILE; + } + else if( strncmp( argument, "rc=", SIZE_OF_FILE_TYPE ) == 0 ) { + filetype = CONFIG_FILE; + } + else if( strncmp( argument, "sm=", SIZE_OF_FILE_TYPE ) == 0 ) { + filetype = SHELF_MANAGER_FRU_FILE; + } + else{ + filetype = ERROR_STATUS; + } + } + return filetype; +} + +/************************************************************************** +* +* Function name: ipmi_ekanalyzer_main +* +* Description: Main program of ekeying analyzer. It calls the appropriate +* function according to the command received. +* +* Restriction: None +* +* Input: ipmi_intf * intf: ? +* int argc : number of argument received +* int ** argv: argument strings +* +* Output: None +* +* Global: None +* +* Return: OK_STATUS as success or ERROR_STATUS as error +* +***************************************************************************/ +int +ipmi_ekanalyzer_main( void * intf, int argc, char ** argv ) +{ + int rc = ERROR_STATUS; + int file_type[MAX_FILE_NUMBER]; + char * filename[MAX_FILE_NUMBER]; + unsigned int argument_offset = 0; + unsigned int type_offset = 0; + /*list des multi record*/ + struct ipmi_ek_multi_header * list_head = NULL; + struct ipmi_ek_multi_header * list_record = NULL; + struct ipmi_ek_multi_header * list_last = NULL; + + set_loglevel(LOG_NOTICE); + if ( (argc == 0) || ( (argc - 1) > MAX_FILE_NUMBER ) ){ + lprintf(LOG_ERR, "Too few or too many arguments."); + ipmi_ekanalyzer_usage(); + rc = ERR_BAD_PARAM; + } + else if ( strcmp(argv[argument_offset], "help") == 0) { + ipmi_ekanalyzer_usage(); + rc = ERR_USAGE; + } + else if ( (strcmp(argv[argument_offset], "frushow") == 0) + && (argc > (MIN_ARGUMENT-1) ) + ){ + for ( type_offset = 0; (int)type_offset < (argc-1); type_offset++ ){ + argument_offset++; + file_type[type_offset] = ipmi_ek_get_file_type (argv[argument_offset]); + if ( file_type[type_offset] != ERROR_STATUS ){ + if ( file_type[type_offset] != CONFIG_FILE ){ + /* because of strlen doesn't count '\0', we need to add 1 byte for + * this character to filename size + */ + filename[type_offset] = malloc( strlen(argv[argument_offset]) + 1 + - SIZE_OF_FILE_TYPE + ); + if( filename[type_offset] != NULL ){ + strcpy(filename[type_offset], + &argv[argument_offset][SIZE_OF_FILE_TYPE]); + printf("Start converting file '%s'...\n", filename[type_offset]); + /* Display FRU header offset */ + rc = ipmi_ek_display_fru_header (filename[type_offset]); + + if ( rc != ERROR_STATUS ){ + /* Display FRU header info in detail record */ + ipmi_ek_display_fru_header_detail (filename[type_offset]); + /* Convert from binary data into multi record structure */ + rc = ipmi_ekanalyzer_fru_file2structure ( filename[type_offset], + &list_head, &list_record, &list_last ); + + ipmi_ek_display_record ( list_record, list_head, list_last ); + /* Remove record of list */ + while ( list_head != NULL ){ + ipmi_ek_remove_record_from_list( list_head, + &list_head,&list_last ); + if (verbose > 1) + printf("record has been removed!\n"); + } + } + free (filename[type_offset]); + } + } + } + else{ + lprintf(LOG_ERR, "Invalid file type!"); + lprintf(LOG_ERR, " ekanalyzer frushow ..."); + } + } + } + else if ( (strcmp(argv[argument_offset], "print") == 0) + || (strcmp(argv[argument_offset], "summary") == 0) + ){ + /*Display help of the correspond command if there is not enought argument + * passing in command line + */ + if ( argc < MIN_ARGUMENT ){ + printf("Too few argument! \n"); + if ( strcmp(argv[argument_offset], "print") == 0 ){ + lprintf(LOG_ERR, " ekanalyzer print [carrier/power/all]" + " [xx=frufile]" + ); + } + else{ + lprintf(LOG_ERR, " ekanalyzer summary [match/ unmatch/ all]" + " [xx=frufile]" + ); + } + } + else{ + char * option; + /*index=1 indicates start position of first file name in command line*/ + int index = 1; + int filename_size=0; + + argument_offset++; + if ( (strcmp(argv[argument_offset], "carrier") == 0) + || (strcmp(argv[argument_offset], "power") == 0) + || (strcmp(argv[argument_offset], "all") == 0) + ){ + option = argv[argument_offset]; + index ++; + argc--; + } + else if ( ( strcmp(argv[argument_offset], "match") == 0 ) + || ( strcmp(argv[argument_offset], "unmatch") == 0 ) + ){ + option = argv[argument_offset]; + index ++; + argc--; + } + /*since the command line must receive xx=filename, so the position of + * "=" sign is 2 + */ + else if ( strncmp(&argv[argument_offset][2], "=", 1) == 0 ){ + option = "default"; + /* Since there is no option from user, the first argument + * becomes first file type */ + index = 1; /* index of argument */ + } + else{ + option = "invalid"; + printf("Invalid option '%s'\n", argv[argument_offset]); + argument_offset--; + if (strcmp(argv[0], "print") == 0){ + lprintf (LOG_ERR, " ekanalyzer print [carrier/power/all]" + " [xx=frufile]" + ); + } + else{ + lprintf (LOG_ERR, " ekanalyzer summary [match/ unmatch/ all]" + " [xx=frufile]" + ); + } + rc = ERROR_STATUS; + } + if ( strcmp(option, "invalid") != 0 ){ + int i=0; + + for ( i = 0; i < (argc-1); i++){ + file_type[i] = ipmi_ek_get_file_type (argv[index]); + if ( file_type[i] == ERROR_STATUS ){ + /* display the first 2 charactors (file type) of argument */ + lprintf(LOG_ERR, "Invalid file type: %c%c\n", argv[index][0], + argv[index][1]); + ipmi_ekanalyzer_usage(); + rc = ERROR_STATUS; + break; + } + /*size is equal to string size minus 3 bytes of file type plus + * 1 byte of '\0' since the strlen doesn't count the '\0' + */ + filename_size = strlen_( argv[index] ) - SIZE_OF_FILE_TYPE + 1; + if ( filename_size > 0 ){ + filename[i] = malloc( filename_size ); + if (filename[i] != NULL) + strcpy( filename[i], &argv[index][SIZE_OF_FILE_TYPE] ); + } + rc = OK_STATUS; + index++; + } + if ( rc != ERROR_STATUS ){ + if (verbose > 0){ + for (i = 0; i < (argc-1); i++){ + printf ("Type: %s, ", + val2str((uint16_t)file_type[i], + ipmi_ekanalyzer_module_type)); + printf("file name: %s\n", filename[i]); + } + } + if (strcmp(argv[0], "print") == 0){ + rc = ipmi_ekanalyzer_print( + (argc-1), option, filename, file_type); + } + else{ + rc = ipmi_ekanalyzer_ekeying_match( + (argc-1), option, filename, file_type); + } + for (i = 0; i < (argc-1); i++){ + if (filename[i] != NULL){ + free (filename[i]); + } + } + } /* End of ERROR_STATUS */ + } /* End of comparison of invalid option */ + } /* End of else MIN_ARGUMENT */ + } /* End of print or summary option */ + else{ + lprintf(LOG_ERR, "Invalid ekanalyzer command: %s", argv[0]); + ipmi_ekanalyzer_usage(); + rc = ERROR_STATUS; + } + + return rc; +} + +/************************************************************************** +* +* Function name: ipmi_ekanalyzer_print +* +* Description: this function will display the topology, power or both +* information together according to the option that it received. +* +* Restriction: None +* +* Input: int argc: number of the argument received +* char* opt: option string that will tell what to display +* char** filename: strings that contained filename of FRU data binary file +* int* file_type: a pointer that contain file type (on carrier file, +* a1 file, b1 file...). See structure +* ipmi_ekanalyzer_module_type for a list of valid type +* +* Output: None +* +* Global: None +* +* Return: return 0 as success and -1 as error. +* +***************************************************************************/ +static int +ipmi_ekanalyzer_print( int argc,char * opt, char ** filename, int * file_type ) +{ + int return_value = OK_STATUS; + + /*Display carrier topology*/ + if ( (strcmp(opt, "carrier") == 0) || (strcmp(opt, "default") == 0) ){ + tboolean found_flag = FALSE; + int index = 0; + int index_name[MAX_ARGC]; + int list = 0; + /*list of multi record*/ + struct ipmi_ek_multi_header * list_head[MAX_ARGC]; + struct ipmi_ek_multi_header * list_record[MAX_ARGC]; + struct ipmi_ek_multi_header * list_last[MAX_ARGC]; + + for ( list=0; list < argc; list++ ){ + list_head[list] = NULL; + list_record[list] = NULL; + list_last[list] = NULL; + } + + list=0; /* reset list count */ + for ( index = 0; index < argc; index++ ){ + if ( file_type[index] == ON_CARRIER_FRU_FILE ){ + index_name[list] = index; + return_value = ipmi_ekanalyzer_fru_file2structure( filename[index], + &list_head[list], &list_record[list], &list_last[list] ); + list++; + found_flag = TRUE; + } + } + if ( !found_flag ){ + printf("No carrier file has been found\n"); + return_value = ERROR_STATUS; + } + else{ + int i = 0; + for ( i = 0; i < argc; i++ ){ + /*this is a flag to advoid displaying the same data multiple time*/ + tboolean first_data = TRUE; + for ( list_record[i] = list_head[i]; + list_record[i] != NULL; + list_record[i] = list_record[i]->next ){ + if ( list_record[i]->data[PICMG_ID_OFFSET] + == + FRU_AMC_CARRIER_P2P ){ + if ( first_data ){ + printf("%s\n", STAR_LINE_LIMITER); + printf("From Carrier file: %s\n", filename[index_name[i]]); + first_data = FALSE; + } + return_value = ipmi_ek_diplay_carrier_connectivity( + list_record[i] ); + } + else if ( list_record[i]->data[PICMG_ID_OFFSET] + == + FRU_AMC_CARRIER_INFO ){ + /*See AMC.0 specification Table3-3 for mor detail*/ + #define COUNT_OFFSET 6 + if ( first_data ){ + printf("From Carrier file: %s\n", filename[index_name[i]]); + first_data = FALSE; + } + printf(" Number of AMC bays supported by Carrier: %d\n", + list_record[i]->data[COUNT_OFFSET] ); + } + } + } + /*Destroy the list of record*/ + for ( i = 0; i < argc; i++ ){ + while ( list_head[i] != NULL ){ + ipmi_ek_remove_record_from_list( list_head[i], + &list_head[i], &list_last[i] ); + } + /* display deleted result when we reach the last record */ + if ( ( i == (list-1) ) && verbose ) + printf("Record list has been removed successfully\n"); + } + } + } + else if ( (strcmp(opt, "power") == 0) ){ + printf("Print power information\n"); + return_value = ipmi_ek_display_power(argc, opt, filename, file_type); + } + else if ( strcmp(opt, "all") == 0 ){ + printf("Print all information\n"); + return_value = ipmi_ek_display_power(argc, opt, filename, file_type); + } + else{ + lprintf(LOG_ERR, "Invalid option %s", opt); + return_value = ERROR_STATUS; + } + return return_value; +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_carrier_connectivity +* +* Description: Display the topology between a Carrier and all AMC modules by +* using carrier p2p connectivity record +* +* Restriction: Ref: AMC.0 Specification: Table 3-13 and Table 3-14 +* +* Input: struct ipmi_ek_multi_header* record: a pointer to the carrier p2p +* connectivity record. +* +* Output: None +* +* Global: None +* +* Return: return 0 on success and -1 if the record doesn't exist. +* +***************************************************************************/ +static int +ipmi_ek_diplay_carrier_connectivity( struct ipmi_ek_multi_header * record ) +{ + int return_value = ERROR_STATUS; + struct fru_picmgext_carrier_p2p_record rsc_desc; + struct fru_picmgext_carrier_p2p_descriptor port_desc; + + if ( record == NULL ){ + lprintf(LOG_ERR, "P2P connectivity record is invalid\n"); + return_value = ERROR_STATUS; + } + else{ + int offset = START_DATA_OFFSET; + if ( verbose > 1 ){ + int k = 0; + printf("Binary data of Carrier p2p connectivity"\ + " record starting from mfg id\n"); + for ( k = 0; k < ( record->header.len ); k++ ){ + printf("%02x ", record->data[k]); + } + printf("\n"); + } + while ( offset <= (record->header.len - START_DATA_OFFSET) ){ + rsc_desc.resource_id = record->data[offset++]; + rsc_desc.p2p_count = record->data[offset++]; + if ( verbose > 0 ){ + printf("resource id= %02x port count= %d\n", + rsc_desc.resource_id,rsc_desc.p2p_count); + } + /*check if it is an AMC Module*/ + if ( ( (rsc_desc.resource_id & AMC_MODULE) ) == AMC_MODULE ) { + /*check if it is an RTM module*/ + if (rsc_desc.resource_id == AMC_MODULE) { + printf(" %s topology:\n", val2str( RTM_IPMB_L, + ipmi_ekanalyzer_IPMBL_addr)); + } + else{ + /*The last four bits of resource ID represent site number + * (mask = 0x0f) + */ + printf(" %s topology:\n", + val2str( (rsc_desc.resource_id & 0x0f), + ipmi_ekanalyzer_module_type)); + } + } + else{ + printf(" On Carrier Device ID %d topology: \n", + (rsc_desc.resource_id & 0x0f)); + } + while ( rsc_desc.p2p_count > 0 ){ + memcpy ( &port_desc, &record->data[offset], + sizeof ( struct fru_picmgext_carrier_p2p_descriptor ) ); + offset += sizeof ( struct fru_picmgext_carrier_p2p_descriptor ); + if ( (port_desc.remote_resource_id & AMC_MODULE) == AMC_MODULE ){ + printf("\tPort %d =====> %s, Port %d\n", port_desc.local_port, + val2str( (port_desc.remote_resource_id & 0x0f), + ipmi_ekanalyzer_module_type), port_desc.remote_port ); + } + else{ + printf("\tPort %d =====> On Carrier Device ID %d, Port %d\n", + port_desc.local_port,(port_desc.remote_resource_id & 0x0f), + port_desc.remote_port ); + } + rsc_desc.p2p_count--; + } + } + return_value = OK_STATUS; + } + return return_value; +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_power +* +* Description: Display the power management of the Carrier and AMC module by +* using current management record. If the display option equal to all, +* it will display power and carrier topology together. +* +* Restriction: Reference: AMC.0 Specification, Table 3-11 +* +* Input: int argc: number of the argument received +* char* opt: option string that will tell what to display +* char** filename: strings that contained filename of FRU data binary file +* int* file_type: a pointer that contain file type (on carrier file, +* a1 file, b1 file...) +* +* Output: None +* +* Global: None +* +* Return: return 0 on success and -1 if the record doesn't exist. +* +***************************************************************************/ +static int +ipmi_ek_display_power(int argc, char * opt, char ** filename, int * file_type) +{ + int num_file=0; + int return_value = ERROR_STATUS; + int index = 0; + + /*list des multi record*/ + struct ipmi_ek_multi_header * list_head[MAX_ARGC]; + struct ipmi_ek_multi_header * list_record[MAX_ARGC]; + struct ipmi_ek_multi_header * list_last[MAX_ARGC]; + + for ( num_file = 0; num_file < argc; num_file++ ){ + list_head[num_file] = NULL; + list_record[num_file] = NULL; + list_last[num_file] = NULL; + } + + for ( num_file = 0; num_file < argc; num_file++ ){ + tboolean is_first_data = TRUE; + if ( file_type[num_file] == CONFIG_FILE ){ + num_file++; + } + + if ( is_first_data ){ + printf("%s\n", STAR_LINE_LIMITER); + printf("\nFrom %s file '%s'\n", + val2str( (uint16_t)file_type[num_file], + ipmi_ekanalyzer_module_type), + filename[num_file]); + is_first_data = FALSE; + } + + return_value = ipmi_ekanalyzer_fru_file2structure( filename[num_file], + &list_head[num_file], &list_record[num_file], &list_last[num_file]); + + if ( list_head[num_file] != NULL ){ + for ( list_record[num_file] = list_head[num_file]; + list_record[num_file] != NULL; + list_record[num_file] = list_record[num_file]->next + ){ + if ( ( strcmp(opt, "all") == 0 ) + && ( file_type[num_file] == ON_CARRIER_FRU_FILE ) + ){ + if ( list_record[num_file]->data[PICMG_ID_OFFSET] + == + FRU_AMC_CARRIER_P2P + ){ + return_value = ipmi_ek_diplay_carrier_connectivity( + list_record[num_file] ); + } + else if ( list_record[num_file]->data[PICMG_ID_OFFSET] + == + FRU_AMC_CARRIER_INFO + ){ + /*Ref: See AMC.0 Specification Table 3-3: Carrier Information + * Table about offset value + */ + printf( " Number of AMC bays supported by Carrier: %d\n", + list_record[num_file]->data[START_DATA_OFFSET+1] ); + } + } + /*Ref: AMC.0 Specification: Table 3-11 + * Carrier Activation and Current Management Record + */ + if ( list_record[num_file]->data[PICMG_ID_OFFSET] + == + FRU_AMC_ACTIVATION + ){ + int index_data = START_DATA_OFFSET; + struct fru_picmgext_carrier_activation_record car; + struct fru_picmgext_activation_record * cur_desc; + + memcpy ( &car, &list_record[num_file]->data[index_data], + sizeof (struct fru_picmgext_carrier_activation_record) ); + index_data += + sizeof (struct fru_picmgext_carrier_activation_record); + cur_desc = malloc (car.module_activation_record_count * \ + sizeof (struct fru_picmgext_activation_record) ); + for(index=0; indexdata[index_data], + sizeof (struct fru_picmgext_activation_record) ); + + index_data += sizeof (struct fru_picmgext_activation_record); + } + /*Display the current*/ + ipmi_ek_display_current_descriptor( car, + cur_desc, filename[num_file] ); + free (cur_desc); + } + /*Ref: AMC.0 specification, Table 3-10: Module Current Requirement*/ + else if ( list_record[num_file]->data[PICMG_ID_OFFSET] + == FRU_AMC_CURRENT + ){ + float power_in_watt = 0; + float current_in_amp = 0; + + printf(" %s power required (Current Draw): ", + val2str ( (uint16_t)file_type[num_file], ipmi_ekanalyzer_module_type) ); + current_in_amp = + (float)(list_record[num_file]->data[START_DATA_OFFSET]*0.1); + power_in_watt = current_in_amp * AMC_VOLTAGE; + printf("%.2f Watts (%.2f Amps)\n",power_in_watt, current_in_amp); + } + } + return_value = OK_STATUS; + /*Destroy the list of record*/ + for ( index = 0; index < argc; index++ ){ + while ( list_head[index] != NULL ){ + ipmi_ek_remove_record_from_list ( list_head[index], + &list_head[index],&list_last[index] ); + } + if ( verbose > 1 ) + printf("Record list has been removed successfully\n"); + } + } + } + printf("%s\n", STAR_LINE_LIMITER); + return return_value; +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_current_descriptor +* +* Description: Display the current descriptor under format xx Watts (xx Amps) +* +* Restriction: None +* +* Input: struct fru_picmgext_carrier_activation_record car: contain binary data +* of carrier activation record +* struct fru_picmgext_activation_record * cur_desc: contain current +* descriptor +* char* filename: strings that contained filename of FRU data binary file +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_current_descriptor( + struct fru_picmgext_carrier_activation_record car, + struct fru_picmgext_activation_record * cur_desc, char * filename ) +{ + int index = 0; + float power_in_watt = 0.0; + float current_in_amp = 0.0; + + for ( index = 0; index < car.module_activation_record_count; index++ ){ + /*See AMC.0 specification, Table 3-12 for detail about calculation*/ + current_in_amp = (float)(cur_desc[index].max_module_curr * 0.1); + power_in_watt = (float) current_in_amp * AMC_VOLTAGE; + + printf(" Carrier AMC power available on %s:\n", + val2str( cur_desc[index].ibmb_addr, ipmi_ekanalyzer_IPMBL_addr ) ); + printf("\t- Local IPMB Address \t: %02x\n", cur_desc[index].ibmb_addr); + printf("\t- Maximum module Current\t: %.2f Watts (%.2f Amps)\n", + power_in_watt, current_in_amp ); + } + /*Display total power on Carrier*/ + current_in_amp = (float)(car.max_internal_curr * 0.1); + power_in_watt = (float) current_in_amp * AMC_VOLTAGE; + printf(" Carrier AMC total power available for all bays from file '%s':", + filename); + printf(" %.2f Watts (%.2f Amps)\n", power_in_watt, current_in_amp ); +} + +/************************************************************************** +* +* Function name: ipmi_ekanalyzer_ekeying_match +* +* Description: Check for possible Ekeying match between two FRU files +* +* Restriction: None +* +* Input: argc: number of the argument received +* opt: string that contains display option received from user. +* filename: strings that contained filename of FRU data binary file +* file_type: a pointer that contain file type (on carrier file, +* a1 file, b1 file...) +* +* Output: None +* +* Global: None +* +* Return: return TRUE on success and FALSE if the record doesn't exist. +* +***************************************************************************/ +static tboolean +ipmi_ekanalyzer_ekeying_match( int argc, char * opt, + char ** filename, int * file_type ) +{ + tboolean return_value = FALSE; + + if ( (strcmp(opt, "carrier") == 0 ) || (strcmp(opt, "power") == 0) ){ + lprintf(LOG_ERR, " ekanalyzer summary [match/ unmatch/ all]"\ + " [xx=frufile]"); + return_value = ERROR_STATUS; + } + else{ + int num_file=0; + // int index_data = 0; + // int first_data = 1; + tboolean amc_file = FALSE; /*used to indicate the present of AMC file*/ + tboolean oc_file = FALSE; /*used to indicate the present of Carrier file*/ + + /*Check for possible ekeying match between files*/ + for ( num_file=0; num_file < argc; num_file++ ){ + if ( ( file_type[num_file] == ON_CARRIER_FRU_FILE ) + || ( file_type[num_file] == CONFIG_FILE ) + || ( file_type[num_file] == SHELF_MANAGER_FRU_FILE ) + ){ + amc_file = FALSE; + } + else { /*there is an amc file*/ + amc_file = TRUE; + break; + } + } + if ( amc_file == FALSE ){ + printf("\nNo AMC FRU file is provided --->" \ + " No possible ekeying match!\n"); + return_value = ERROR_STATUS; + } + else{ + /*If no carrier file is provided, return error*/ + for ( num_file=0; num_file < argc; num_file++ ){ + if ( (file_type[num_file] == ON_CARRIER_FRU_FILE ) + || ( file_type[num_file] == CONFIG_FILE ) + || ( file_type[num_file] == SHELF_MANAGER_FRU_FILE ) + ){ + oc_file = TRUE; + break; + } + } + if ( !oc_file ){ + printf("\nNo Carrier FRU file is provided" \ + " ---> No possible ekeying match!\n"); + return_value = ERROR_STATUS; + } + else{ + /*list des multi record*/ + struct ipmi_ek_multi_header * list_head[MAX_ARGC]; + struct ipmi_ek_multi_header * list_record[MAX_ARGC]; + struct ipmi_ek_multi_header * list_last[MAX_ARGC]; + struct ipmi_ek_multi_header * pcarrier_p2p = NULL; + int list = 0; + int match_pair = 0; + // tboolean match_result = FALSE; + + /*Create an empty list*/ + for ( list=0; listnext + ){ + if ( pcarrier_p2p->data[PICMG_ID_OFFSET] + == FRU_AMC_CARRIER_P2P + ){ + break; + } + } + break; + } + } + /*Determine the match making pair*/ + while ( match_pair < argc ){ + for ( num_file = (match_pair+1); num_file0){ + printf("Start matching process\n"); + } + return_value = ipmi_ek_matching_process( file_type, + match_pair, num_file, list_head, + list_last, opt, pcarrier_p2p); + } + } + } + match_pair ++; + } + for( num_file=0; num_file < argc; num_file++ ){ + if (list_head[num_file] != NULL ){ + ipmi_ek_remove_record_from_list( list_head[num_file], + &list_record[num_file], &list_last[num_file]); + } + if ( ( num_file == argc-1 ) && verbose ) + printf("Record list has been removed successfully\n"); + } + return_value = OK_STATUS; + } + } + } + return return_value; +} + +/************************************************************************** +* +* Function name: ipmi_ek_matching_process +* +* Description: This function process the OEM check, Physical Connectivity check, +* and Link Descriptor comparison to do Ekeying match +* +* Restriction: None +* +* Input: file_type: a pointer that contain file type (on carrier file, +* a1 file, b1 file...) +* index1: position of the first record in the list of the record +* index2: position of the second record in the list of the record +* ipmi_ek_multi_header ** list_head: pointer to the header of a +* linked list that contain FRU multi record +* ipmi_ek_multi_header ** list_last: pointer to the tale of a +* linked list that contain FRU multi record +* opt: string that contain display option such as "match", "unmatch", or +* "all". +* pphysical: a pointer that contain a carrier p2p connectivity record +* to perform physical check +* +* Output: None +* +* Global: None +* +* Return: return OK_STATUS on success and ERROR_STATUS if the record doesn't +* exist. +* +***************************************************************************/ +static int ipmi_ek_matching_process( int * file_type, int index1, int index2, + struct ipmi_ek_multi_header ** list_head, + struct ipmi_ek_multi_header ** list_last, char * opt, + struct ipmi_ek_multi_header * pphysical ) +{ + int result = ERROR_STATUS; + struct ipmi_ek_multi_header * record; + int num_amc_record1 = 0;/*Number of AMC records in the first module*/ + int num_amc_record2 = 0;/*Number of AMC records in the second module*/ + + /* Comparison between an On-Carrier and an AMC*/ + if ( file_type[index2] == ON_CARRIER_FRU_FILE ){ + int index_temp = 0; + index_temp = index1; + index1 = index2; /*index1 indicate on carrier*/ + index2 = index_temp; /*index2 indcate an AMC*/ + } + /*Calculate record size for Carrier file*/ + for ( record=list_head[index1]; record != NULL;record = record->next ){ + if ( record->data[PICMG_ID_OFFSET] == FRU_AMC_P2P ){ + num_amc_record2++; + } + } + /*Calculate record size for amc file*/ + for ( record=list_head[index2]; record != NULL;record = record->next){ + if ( record->data[PICMG_ID_OFFSET] == FRU_AMC_P2P ){ + num_amc_record1++; + } + } + if ( (num_amc_record1 > 0) && (num_amc_record2 > 0) ){ + int index_record1 = 0; + int index_record2 = 0; + /* Multi records of AMC module */ + struct ipmi_ek_amc_p2p_connectivity_record * amc_record1 = NULL; + /* Multi records of Carrier or an AMC module */ + struct ipmi_ek_amc_p2p_connectivity_record * amc_record2 = NULL; + + amc_record1 = malloc ( num_amc_record1 * \ + sizeof(struct ipmi_ek_amc_p2p_connectivity_record)); + amc_record2 = malloc ( num_amc_record2 * \ + sizeof(struct ipmi_ek_amc_p2p_connectivity_record)); + + for (record=list_head[index2]; record != NULL;record = record->next){ + if ( record->data[PICMG_ID_OFFSET] == FRU_AMC_P2P ){ + result = ipmi_ek_create_amc_p2p_record( record, + &amc_record1[index_record1] ); + if (result != ERROR_STATUS){ + struct ipmi_ek_multi_header * current_record = NULL; + + for ( current_record=list_head[index1]; + current_record != NULL ; + current_record = current_record->next + ){ + if ( current_record->data[PICMG_ID_OFFSET] == FRU_AMC_P2P ){ + result = ipmi_ek_create_amc_p2p_record( current_record, + &amc_record2[index_record2] ); + if ( result != ERROR_STATUS ){ + if ( result == OK_STATUS ){ + /*Compare Link descriptor*/ + result = ipmi_ek_compare_link ( pphysical, + amc_record1[index_record1], + amc_record2[index_record2], + opt, file_type[index1], file_type[index2]); + } + index_record2++; + } + } /*end of FRU_AMC_P2P */ + } /* end of for loop */ + index_record1++; + } + } + } + free(amc_record1) ; + free(amc_record2) ; + } + else{ + printf("No amc record is found!\n"); + } + + return result; +} + +/************************************************************************** +* +* Function name: ipmi_ek_check_physical_connectivity +* +* Description: This function check for point to point connectivity between +* two modules by comparing each enable port in link descriptor +* with local and remote ports of port descriptor in +* carrier point-to-point connectivity record according to the +* corresponding file type ( a1, b1, b2...). +* +* Restriction: In order to perform physical check connectivity, it needs to +* compare between 2 AMC Modules, so the use of index ( 1 and 2 ) +* can facilitate the comparison in this case. +* +* Input: record1: is an AMC p2p record for an AMC module +* record2 is an AMC p2p record for an On-Carrier record or an AMC module +* char* opt: option string that will tell if a matching result, unmatched +* result or all the results will be displayed. +* file_type1: indicates type of the first module +* file_type2: indicates type of the second module +* +* Output: None +* +* Global: None +* +* Return: return OK_STATUS if both link are matched, otherwise +* return ERROR_STATUS +* +***************************************************************************/ +static int +ipmi_ek_check_physical_connectivity( + struct ipmi_ek_amc_p2p_connectivity_record record1, int index1, + struct ipmi_ek_amc_p2p_connectivity_record record2, int index2, + struct ipmi_ek_multi_header * record, + int filetype1, int filetype2, char * option ) +{ + int return_status = OK_STATUS; + + if ( record == NULL ){ + printf("NO Carrier p2p connectivity !\n"); + return_status = ERROR_STATUS; + } + else{ + #define INVALID_AMC_SITE_NUMBER -1 + int index = START_DATA_OFFSET; + int amc_site = INVALID_AMC_SITE_NUMBER; + struct fru_picmgext_carrier_p2p_record rsc_desc; + struct fru_picmgext_carrier_p2p_descriptor * port_desc = NULL; + + /* Get the physical connectivity record */ + while ( index < record->header.len ) { + rsc_desc.resource_id = record->data[index++]; + rsc_desc.p2p_count = record->data[index++]; + /* carrier p2p record starts with on-carrier device */ + if ( (rsc_desc.resource_id == record1.rsc_id) + || + (rsc_desc.resource_id == record2.rsc_id) + ){ + if (rsc_desc.p2p_count <= 0){ + printf("No p2p count\n"); + return_status = ERROR_STATUS; + } + else{ + port_desc = malloc ( rsc_desc.p2p_count * + sizeof(struct fru_picmgext_carrier_p2p_descriptor) ); + index = ipmi_ek_get_resource_descriptor( rsc_desc.p2p_count, + index, port_desc, record ); + amc_site = INVALID_AMC_SITE_NUMBER; + break; + } + } + else{ /* carrier p2p record starts with AMC module */ + if (rsc_desc.resource_id == AMC_MODULE){ + if (filetype1 != ON_CARRIER_FRU_FILE){ + amc_site = filetype1; + } + else{ + amc_site = filetype2; + } + } + else{ + amc_site = rsc_desc.resource_id & 0x0f; + } + if ( amc_site > 0 ){ + if ( (amc_site == filetype1) || (amc_site == filetype2) ){ + port_desc = malloc ( rsc_desc.p2p_count * + sizeof(struct fru_picmgext_carrier_p2p_descriptor) ); + index = ipmi_ek_get_resource_descriptor( rsc_desc.p2p_count, + index, port_desc, record ); + break; + } + } + else{ + return_status = ERROR_STATUS; + } + } + /*If the record doesn't contain the same AMC site number in command + * line, go to the next record + */ + index += ( sizeof(struct fru_picmgext_carrier_p2p_descriptor) * + rsc_desc.p2p_count ); + } + + if ( (port_desc != NULL) && (return_status != ERROR_STATUS) ){ + int j=0; + + for ( j = 0; j < rsc_desc.p2p_count; j++ ){ + /* Compare only enable channel descriptor */ + if ( record1.ch_desc[index1].lane0port != DISABLE_PORT ){ + /* matching result from channel descriptor comparison */ + tboolean match_lane = FALSE; + + match_lane = ipmi_ek_compare_channel_descriptor ( + record1.ch_desc[index1], record2.ch_desc[index2], + port_desc, j, rsc_desc.resource_id ); + + if ( match_lane ){ + if ( filetype1 != ON_CARRIER_FRU_FILE ){ + if ( ( + (filetype1 == (rsc_desc.resource_id & 0x0f)) + && + (filetype2 ==(port_desc[j].remote_resource_id &0x0f)) + ) + || + ( + (filetype2 == (rsc_desc.resource_id & 0x0f)) + && + (filetype1 ==(port_desc[j].remote_resource_id &0x0f)) + ) + ){ + if ( ! (strcmp(option, "unmatch") == 0) ){ + printf("%s port %d ==> %s port %d\n", + val2str((uint16_t)filetype2, ipmi_ekanalyzer_module_type), + record1.ch_desc[index1].lane0port, + val2str((uint16_t)filetype1, ipmi_ekanalyzer_module_type), + record2.ch_desc[index2].lane0port); + } + return_status = OK_STATUS; + + break; + } + else{ + if (verbose >= 2){ //was == LOG_DEBUG) + printf("No point 2 point connectivity\n"); + } + return_status = ERROR_STATUS; + } + } + else{ + if ( (record2.rsc_id == (rsc_desc.resource_id) ) + && + (filetype2 == (port_desc[j].remote_resource_id & 0x0f)) + ){ + if ( ! (strcmp(option, "unmatch") == 0) ){ + printf("%s port %d ==> %s port %d\n", + val2str((uint16_t)filetype2, ipmi_ekanalyzer_module_type), + record1.ch_desc[index1].lane0port, + val2str((uint16_t)filetype1, ipmi_ekanalyzer_module_type), + record2.ch_desc[index2].lane0port); + } + return_status = OK_STATUS; + break; + } + else if ( (filetype2 == (rsc_desc.resource_id & 0x0f) ) + && + (record2.rsc_id == (port_desc[j].remote_resource_id)) + ){ + if ( ! (strcmp(option, "unmatch") == 0) ){ + printf("%s port %d ==> %s %x port %d\n", + val2str((uint16_t)filetype2, ipmi_ekanalyzer_module_type), + record1.ch_desc[index1].lane0port, + val2str((uint16_t)filetype1, ipmi_ekanalyzer_module_type), + record2.rsc_id,record2.ch_desc[index2].lane0port); + } + return_status = OK_STATUS; + break; + } + else{ + if (verbose >= 2){ //was == LOG_DEBUG + printf("No point 2 point connectivity\n"); + } + return_status = ERROR_STATUS; + } + } + } + else{ + if (verbose >= 2){ //was == LOG_DEBUG + printf("No point 2 point connectivity\n"); + } + return_status = ERROR_STATUS; + } + } + else{ /*If the link is disable, the result is always true*/ + return_status = OK_STATUS; + } + } + } + else{ + if (verbose >= 2) { //was == LOG_WARN + printf("Invalid Carrier p2p connectivity record\n"); + } + return_status = ERROR_STATUS; + } + if (port_desc != NULL){ + free (port_desc); + } + } + return return_status; +} + +/************************************************************************** +* +* Function name: ipmi_ek_compare_link +* +* Description: This function compares link grouping id of each +* amc p2p connectiviy record +* +* Restriction: None +* +* Input: record1: is an AMC p2p record for an AMC module +* record2 is an AMC p2p record for an On-Carrier record or an AMC module +* char* opt: option string that will tell if a matching result, unmatched +* result or all the results will be displayed. +* file_type1: indicates type of the first module +* file_type2: indicates type of the second module +* +* Output: None +* +* Global: None +* +* Return: return 0 if both link are matched, otherwise return -1 +* +***************************************************************************/ +static int +ipmi_ek_compare_link( struct ipmi_ek_multi_header * physic_record, + struct ipmi_ek_amc_p2p_connectivity_record record1, + struct ipmi_ek_amc_p2p_connectivity_record record2, char * opt, + int file_type1, int file_type2 ) +{ + int result = ERROR_STATUS; + int index1 = 0; /*index for AMC module*/ + int index2 = 0; /*index for On-carrier type*/ + + record1.matching_result = malloc ( record1.link_desc_count * sizeof(int) ); + record2.matching_result = malloc ( record2.link_desc_count * sizeof(int) ); + /*Initialize all the matching_result to false*/ + for( index2 = 0; index2 < record2.link_desc_count; index2++ ){ + record2.matching_result[index2] = FALSE; + } + for( index1 = 0; index1 < record1.link_desc_count; index1++ ){ + for( index2 = 0; index2 < record2.link_desc_count; index2++ ){ + if( record1.link_desc[index1].group_id == 0 ){ + if( record2.link_desc[index2].group_id == 0 ){ + result = ipmi_ek_compare_link_descriptor( + record1, index1, record2, index2 ); + if ( result == OK_STATUS ){ + /*Calculate the index for Channel descriptor in function of + * link designator channel ID + */ + /*first channel_id in the AMC Link descriptor of record1*/ + static int flag_first_link1; + int index_ch_desc1; /*index of channel descriptor */ + /*first channel_id in the AMC Link descriptor of record2*/ + static int flag_first_link2; + int index_ch_desc2; /*index of channel descriptor*/ + + if (index1==0){ /*this indicate the first link is encounter*/ + flag_first_link1 = record1.link_desc[index1].channel_id; + } + index_ch_desc1 = record1.link_desc[index1].channel_id - + flag_first_link1; + if (index2==0){ + flag_first_link2 = record2.link_desc[index2].channel_id; + } + index_ch_desc2 = record2.link_desc[index2].channel_id - + flag_first_link2; + /*Check for physical connectivity for each link*/ + result = ipmi_ek_check_physical_connectivity ( record1, + index_ch_desc1, record2, index_ch_desc2, + physic_record, file_type1, file_type2, opt ); + if ( result == OK_STATUS ){ + /*Display the result if option = match or all*/ + if ( (strcmp( opt, "match" ) == 0) + || (strcmp( opt, "all" ) == 0) + || (strcmp( opt, "default" ) == 0) + ){ + tboolean isOEMtype = FALSE; + printf(" Matching Result\n"); + isOEMtype = ipmi_ek_display_link_descriptor( file_type1, + record2.rsc_id, + "From", record2.link_desc[index2]); + if (isOEMtype){ + ipmi_ek_display_oem_guid (record2); + } + isOEMtype = ipmi_ek_display_link_descriptor( file_type2, + record1.rsc_id, + "To", record1.link_desc[index1] ); + if (isOEMtype){ + ipmi_ek_display_oem_guid (record1); + } + printf(" %s\n", STAR_LINE_LIMITER); + } + record2.matching_result[index2] = TRUE; + record1.matching_result[index1] = TRUE; + /*quit the fist loop since the match is found*/ + index2 = record2.link_desc_count; + } + } + } + } + else { /*Link Grouping ID is non zero, Compare all link descriptor + * that has non-zero link grouping id together + */ + if (record2.link_desc[index2].group_id != 0 ){ + result = ipmi_ek_compare_link_descriptor( + record1, index1, record2, index2 ); + if ( result == OK_STATUS ){ + /*Calculate the index for Channel descriptor in function of + * link designator channel ID + */ + /*first channel_id in the AMC Link descriptor of record1*/ + static int flag_first_link1; + int index_ch_desc1; /*index of channel descriptor */ + /*first channel_id in the AMC Link descriptor of record2*/ + static int flag_first_link2; + int index_ch_desc2; /*index of channel descriptor*/ + + if (index1==0){ /*this indicate the first link is encounter*/ + flag_first_link1 = record1.link_desc[index1].channel_id; + } + index_ch_desc1 = record1.link_desc[index1].channel_id - + flag_first_link1; + if (index2==0){ + flag_first_link2 = record2.link_desc[index2].channel_id; + } + index_ch_desc2 = record2.link_desc[index2].channel_id - + flag_first_link2; + /*Check for physical connectivity for each link*/ + result = ipmi_ek_check_physical_connectivity ( + record1, index_ch_desc1, record2, index_ch_desc2, + physic_record, file_type1, file_type2, opt ); + if ( result == OK_STATUS ){ + if ( (strcmp( opt, "match" ) == 0) + || (strcmp( opt, "all" ) == 0) + || (strcmp( opt, "default" ) == 0) + ){ + tboolean isOEMtype = FALSE; + printf(" Matching Result\n"); + isOEMtype = ipmi_ek_display_link_descriptor( file_type1, + record2.rsc_id, + "From", record2.link_desc[index2] ); + if ( isOEMtype ){ + ipmi_ek_display_oem_guid (record2); + } + isOEMtype = ipmi_ek_display_link_descriptor( file_type2, + record1.rsc_id, + "To", record1.link_desc[index1] ); + if (isOEMtype){ + ipmi_ek_display_oem_guid (record1); + } + printf(" %s\n", STAR_LINE_LIMITER); + } + record2.matching_result[index2] = TRUE; + record1.matching_result[index1] = TRUE; + /*leave the fist loop since the match is found*/ + index2 = record2.link_desc_count; + } + } + } + } + } + } + + if ( (strcmp(opt, "unmatch") == 0) || (strcmp(opt, "all") == 0) ){ + int isOEMtype = FALSE; + printf(" Unmatching result\n"); + for (index1 = 0; index1 < record1.link_desc_count; index1++){ + isOEMtype = ipmi_ek_display_link_descriptor( file_type2, + record1.rsc_id, "", record1.link_desc[index1] ); + if ( isOEMtype ){ + ipmi_ek_display_oem_guid (record1); + } + printf(" %s\n", STAR_LINE_LIMITER); + } + for ( index2 = 0; index2 < record2.link_desc_count; index2++){ + if ( !record2.matching_result[index2] ){ + isOEMtype = ipmi_ek_display_link_descriptor( file_type1, + record2.rsc_id, "", record2.link_desc[index2] ); + if ( isOEMtype ){ + ipmi_ek_display_oem_guid (record2); + } + printf(" %s\n", STAR_LINE_LIMITER); + } + } + } + + free (record1.matching_result); + free (record2.matching_result); + + return result; +} + +/************************************************************************** +* +* Function name: ipmi_ek_compare_channel_descriptor +* +* Description: This function compares 2 channel descriptors of 2 AMC +* point-to-point connectivity records with port descriptor of +* carrier point-to-point connectivity record. The comparison is +* made between each enable port only. +* +* Restriction: Reference: AMC.0 specification: +* - Table 3-14 for port descriptor +* - Table 3-17 for channel descriptor +* +* Input: ch_desc1: first channel descriptor +* ch_desc2: second channel descriptor +* port_desc: a pointer that contain a list of port descriptor +* index_port: index of the port descriptor +* rsc_id: resource id that represents as local resource id in the +* resource descriptor table. +* +* Output: None +* +* Global: None +* +* Return: return TRUE if both channel descriptor are matched, +* or FALSE otherwise +* +***************************************************************************/ +static tboolean +ipmi_ek_compare_channel_descriptor( + struct fru_picmgext_amc_channel_desc_record ch_desc1, + struct fru_picmgext_amc_channel_desc_record ch_desc2, + struct fru_picmgext_carrier_p2p_descriptor * port_desc, + int index_port, unsigned char rsc_id ) +{ + tboolean match_lane = FALSE; + + /* carrier p2p record start with AMC_MODULE as local port */ + if ( (rsc_id & AMC_MODULE) == AMC_MODULE ){ + if ( (ch_desc1.lane0port == port_desc[index_port].local_port) + && + (ch_desc2.lane0port == port_desc[index_port].remote_port) + ){ + /*check if the port is enable*/ + if (ch_desc1.lane1port != DISABLE_PORT){ + index_port ++; + if ( (ch_desc1.lane1port == port_desc[index_port].local_port) + && + (ch_desc2.lane1port == port_desc[index_port].remote_port) + ){ + if (ch_desc1.lane2port != DISABLE_PORT){ + index_port++; + if ( (ch_desc1.lane2port == port_desc[index_port].local_port) + && + (ch_desc2.lane2port == port_desc[index_port].remote_port) + ){ + if (ch_desc1.lane3port != DISABLE_PORT){ + index_port++; + if ( (ch_desc1.lane3port == + port_desc[index_port].local_port) + && + (ch_desc2.lane3port == + port_desc[index_port].remote_port) + ){ + match_lane = TRUE; + } + } + else{ + match_lane = TRUE; + } + } /* end of if lane2port */ + } + else{ + match_lane = TRUE; + } + } /* end of if lane1port */ + } + else{ /*if the port is disable, the compare result is always true*/ + match_lane = TRUE; + } + }/* end of if lane0port */ + } + /* carrier p2p record start with Carrier as local port */ + else{ + if ( (ch_desc1.lane0port == port_desc[index_port].remote_port) + && + (ch_desc2.lane0port == port_desc[index_port].local_port) + ){ + if (ch_desc1.lane1port != DISABLE_PORT){ + index_port ++; + if ( (ch_desc1.lane1port == port_desc[index_port].remote_port) + && + (ch_desc2.lane1port == port_desc[index_port].local_port) + ){ + if (ch_desc1.lane2port != DISABLE_PORT){ + index_port++; + if ( (ch_desc1.lane2port == port_desc[index_port].remote_port) + && + (ch_desc2.lane2port == port_desc[index_port].local_port) + ){ + if (ch_desc1.lane3port != DISABLE_PORT){ + index_port++; + if ( (ch_desc1.lane3port == + port_desc[index_port].remote_port) + && + (ch_desc2.lane3port == + port_desc[index_port].local_port) + ){ + match_lane = TRUE; + } + } + else{ + match_lane = TRUE; + } + } /* end of if lane2port */ + } + else{ + match_lane = TRUE; + } + } /* end of if lane1port */ + } + else{ + match_lane = TRUE; + } + } /* end of if lane0port */ + } + + return match_lane; +} + +/************************************************************************** +* +* Function name: ipmi_ek_compare_link_descriptor +* +* Description: This function compares 2 link descriptors of 2 +* amc p2p connectiviy record +* +* Restriction: None +* +* Input: record1: AMC p2p connectivity record of the 1rst AMC or Carrier Module +* index1: index of AMC link descriptor in 1rst record +* record2: AMC p2p connectivity record of the 2nd AMC or Carrier Module +* index1: index of AMC link descriptor in 2nd record +* +* Output: None +* +* Global: None +* +* Return: return OK_STATUS if both link are matched, +* otherwise return ERROR_STATUS +* +***************************************************************************/ +static int +ipmi_ek_compare_link_descriptor( + struct ipmi_ek_amc_p2p_connectivity_record record1, int index1, + struct ipmi_ek_amc_p2p_connectivity_record record2, int index2 ) +{ + int result = ERROR_STATUS; + + if (record1.link_desc[index1].type == record2.link_desc[index2].type){ + /*if it is an OEM type, we compare the OEM GUID*/ + if ( (record1.link_desc[index1].type >= LOWER_OEM_TYPE) + && (record1.link_desc[index1].type <= UPPER_OEM_TYPE) + ){ + if ( (record1.guid_count == 0) && (record2.guid_count == 0) ){ + /*there is no GUID for comparison, so the result is always OK*/ + result = OK_STATUS; + } + else{ + int i=0; + int j=0; + + for( i=0; i= LOWER_OEM_TYPE) + && + (link_desc.type <= UPPER_OEM_TYPE) + ){ + isOEMtype = TRUE; + } + + return isOEMtype; +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_oem_guid +* +* Description: Display the oem guid of an AMC p2p connectivity record +* +* Restriction: None +* +* Input: amc_record: AMC p2p connectivity record +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_oem_guid( + struct ipmi_ek_amc_p2p_connectivity_record amc_record ) +{ + int index_oem = 0; + int index = 0; + + if ( amc_record.guid_count == 0 ){ + printf("\tThere is no OEM GUID for this module\n"); + } + for (index_oem = 0; index_oem < amc_record.guid_count; index_oem++){ + printf(" - GUID: "); + for(index = 0; index < SIZE_OF_GUID; index++){ + printf("%02x", amc_record.oem_guid[index_oem].guid[index]); + /*For a better look: putting a "-" after displaying four bytes of GUID*/ + if (!(index % 4)){ + printf("-"); + } + } + printf("\n"); + } +} + +/************************************************************************** +* +* Function name: ipmi_ek_create_amc_p2p_record +* +* Description: this function create an AMC point 2 point connectivity record +* that contain link descriptor, channel descriptor, oem guid +* +* Restriction: Reference: AMC.0 Specification Table 3-16 +* +* Input: record: a pointer to FRU multi record +* +* Output: amc_record: a pointer to the created AMC p2p record +* +* Global: None +* +* Return: Return OK_STATUS on success, or ERROR_STATUS if no record has been +* created. +* +***************************************************************************/ +static int +ipmi_ek_create_amc_p2p_record( struct ipmi_ek_multi_header * record, + struct ipmi_ek_amc_p2p_connectivity_record * amc_record ) +{ + int return_status = OK_STATUS; + int index_data = START_DATA_OFFSET; + + amc_record->guid_count = record->data[index_data++]; + if ( amc_record->guid_count > 0){ + int index_oem = 0; + amc_record->oem_guid = malloc (amc_record->guid_count * \ + sizeof(struct fru_picmgext_guid) ); + for (index_oem = 0; index_oem < amc_record->guid_count; index_oem++){ + memcpy ( &amc_record->oem_guid[index_oem].guid, + &record->data[index_data], + SIZE_OF_GUID ); + index_data += (int)SIZE_OF_GUID; + } + amc_record->rsc_id = record->data[index_data++]; + amc_record->ch_count = record->data[index_data++]; + /*Calculate link descriptor count*/ + amc_record->link_desc_count = ( (record->header.len) - 8 - + (SIZE_OF_GUID*amc_record->guid_count) - + ( sizeof(struct fru_picmgext_amc_channel_desc_record)* + amc_record->ch_count ) + )/5 ; + } + else{ + amc_record->rsc_id = record->data[index_data++]; + amc_record->ch_count = record->data[index_data++]; + /*Calculate link descriptor count see spec AMC.0 for detail*/ + amc_record->link_desc_count = ( (record->header.len) - 8 - + ( sizeof(struct fru_picmgext_amc_channel_desc_record)* + amc_record->ch_count ) + ) / 5; + } + + if (amc_record->ch_count > 0){ + int ch_index = 0; + amc_record->ch_desc = malloc ( (amc_record->ch_count) * \ + sizeof(struct fru_picmgext_amc_channel_desc_record)); + for (ch_index = 0; ch_index < amc_record->ch_count; ch_index++){ + memcpy(&amc_record->ch_desc[ch_index], &record->data[index_data], + sizeof(struct fru_picmgext_amc_channel_desc_record) ); + + index_data += sizeof(struct fru_picmgext_amc_channel_desc_record) ; + } + } + if (amc_record->link_desc_count > 0){ + int i=0; + amc_record->link_desc = malloc ( amc_record->link_desc_count * + sizeof(struct fru_picmgext_amc_link_desc_record) ); + for (i = 0; i< amc_record->link_desc_count; i++ ){ + memcpy (&amc_record->link_desc[i], &record->data[index_data], + sizeof(struct fru_picmgext_amc_link_desc_record) ); + index_data += sizeof (struct fru_picmgext_amc_link_desc_record); + } + } + else{ + return_status = ERROR_STATUS; + } + + return return_status; +} + +/************************************************************************** +* +* Function name: ipmi_ek_get_resource_descriptor +* +* Description: this function create the resource descriptor of Carrier p2p +* connectivity record. +* +* Restriction: None +* +* Input: port_count: number of port count +* index: index to the position of data start offset +* record: a pointer to FRU multi record +* +* Output: port_desc: a pointer to the created resource descriptor +* +* Global: None +* +* Return: Return index that indicates the current position of data in record. +* +***************************************************************************/ +static int +ipmi_ek_get_resource_descriptor( int port_count, int index, + struct fru_picmgext_carrier_p2p_descriptor * port_desc, + struct ipmi_ek_multi_header * record ) +{ + int num_port = 0; + + while ( num_port < port_count ){ + memcpy ( &port_desc[num_port], &record->data[index], + sizeof (struct fru_picmgext_carrier_p2p_descriptor) ); + index += sizeof (struct fru_picmgext_carrier_p2p_descriptor); + num_port++; + } + + return index; +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_fru_header +* +* Description: this function display FRU header offset from a FRU binary file +* +* Restriction: Reference: IPMI Platform Management FRU Information Storage +* Definition V1.0, Section 8 +* +* Input: filename: name of FRU binary file +* +* Output: None +* +* Global: None +* +* Return: Return OK_STATUS on sucess, ERROR_STATUS on error +* +***************************************************************************/ +static int +ipmi_ek_display_fru_header( char * filename ) +{ + FILE * input_file; + /* this structure is declared in ipmi_fru.h */ + struct fru_header header; + int return_status = ERROR_STATUS; + + input_file = fopen ( filename, "r"); + if ( input_file == NULL ){ + lprintf(LOG_ERR, "file: '%s' is not found", filename); + return_status = ERROR_STATUS; + } + else{ + if ( !feof (input_file) ){ + fread ( &header, sizeof (struct fru_header), 1, input_file ); + printf("%s\n", EQUAL_LINE_LIMITER); + printf("FRU Header Info\n"); + printf("%s\n", EQUAL_LINE_LIMITER); + printf("Format Version :0x%02x %s\n", (header.version & 0x0f), + ((header.version & 0x0f)==1) ? "" : "{unsupported}"); + printf("Internal Use Offset :0x%02x\n", header.offset.internal); + printf("Chassis Info Offset :0x%02x\n", header.offset.chassis); + printf("Board Info Offset :0x%02x\n", header.offset.board); + printf("Product Info Offset :0x%02x\n", header.offset.product); + printf("MultiRecord Offset :0x%02x\n", header.offset.multi); + printf("Common header Checksum :0x%02x\n", header.checksum); + + return_status = OK_STATUS; + } + else{ + lprintf(LOG_ERR, "Invalid FRU header!"); + return_status = ERROR_STATUS; + } + fclose( input_file ); + } + return return_status; +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_fru_header_detail +* +* Description: this function display detail FRU header information +* from a FRU binary file. + +* +* Restriction: Reference: IPMI Platform Management FRU Information Storage +* Definition V1.0, Section 8 +* +* Input: filename: name of FRU binary file +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_fru_header_detail( char * filename ) +{ + FILE * input_file; + struct fru_header header; + + input_file = fopen ( filename, "r"); + if ( input_file == NULL ){ + lprintf(LOG_ERR, "file: '%s' is not found", filename); + } + else{ + /* the offset in each fru is in multiple of 8 bytes + * See IPMI Platform Management FRU Information Storage Definition + * for detail + */ + #define FACTOR_OFFSET 8 + + if ( !feof (input_file) ){ + fread ( &header, sizeof( struct fru_header ), 1, input_file ); + } + else{ + lprintf(LOG_ERR, "Invalid FRU header!"); + } + /*** Display FRU Internal Use Info ***/ + if ( !feof (input_file) ){ + unsigned char format_version; + unsigned long len; + + printf("%s\n", EQUAL_LINE_LIMITER); + printf("FRU Internal Use Info\n"); + printf("%s\n", EQUAL_LINE_LIMITER); + + fread ( &format_version, 1, 1, input_file ); + printf("Format Version: %d\n", (format_version & 0x0f) ); + + if ( header.offset.chassis > 0 ){ + len = (header.offset.chassis * FACTOR_OFFSET) + - (header.offset.internal * FACTOR_OFFSET); + } + else{ + len = (header.offset.board * FACTOR_OFFSET) + - (header.offset.internal * FACTOR_OFFSET); + } + printf("Length: %d\n", len); + printf("Data dump:\n"); + while ( (len > 0) && ( !feof (input_file) ) ) { + unsigned char data; + fread ( &data, 1, 1, input_file ); + printf("0x%02x ", data); + len --; + } + printf("\n"); + } + /*** Chassis Info Area ***/ + if (header.offset.chassis != 0){ + long offset = 0; + + offset = header.offset.chassis * FACTOR_OFFSET; + ipmi_ek_display_chassis_info_area (input_file, offset); + } + /*** Display FRU Board Info Area ***/ + if (header.offset.board != 0){ + fseek_( input_file, (header.offset.board * FACTOR_OFFSET), SEEK_SET); + if ( !feof(input_file) ){ + unsigned char data; + unsigned int board_length; + size_t file_offset = ftell (input_file); + + printf("%s\n", EQUAL_LINE_LIMITER); + printf("FRU Board Info Area\n"); + printf("%s\n", EQUAL_LINE_LIMITER); + + fread ( &data, 1, 1, input_file ); /* Format version */ + printf("Format Version: %d\n", (data & 0x0f)); + if ( !feof(input_file) ){ + fread ( &data, 1, 1, input_file ); /* Board Area Length */ + board_length = (data * FACTOR_OFFSET); + printf("Area Length: %d\n", board_length); + /* Decrease the length of board area by 1 byte of format version + * and 1 byte for area length itself. the rest of this length will + * be used to check for additional custom mfg. byte + */ + board_length -= 2; + } + if ( !feof(input_file) ){ + unsigned char lan_code; + fread ( &lan_code, 1, 1, input_file ); /* Language Code */ + printf("Language Code: %d\n", lan_code ); + board_length --; + } + /* Board Mfg Date */ + if ( !feof(input_file) ){ + #define SIZE_MFG_DATE 3 + time_t tval; + unsigned char mfg_date[SIZE_MFG_DATE]; + + fread ( mfg_date, SIZE_MFG_DATE, 1, input_file ); + tval=((mfg_date[2] << 16) + (mfg_date[1] << 8) + (mfg_date[0])); + tval = tval * 60; + tval = (time_t)(tval + secs_from_1970_1996); + printf("Board Mfg Date: %ld, %s", tval, + asctime(localtime(&tval))); + board_length -= SIZE_MFG_DATE; + + /* Board Mfg */ + file_offset = ipmi_ek_display_board_info_area ( + input_file, "Board Manufacture Data", &board_length); + fseek_(input_file, file_offset, SEEK_SET); + /* Board Product */ + file_offset = ipmi_ek_display_board_info_area ( + input_file, "Board Product Name", &board_length); + fseek_(input_file, file_offset, SEEK_SET); + /* Board Serial */ + file_offset = ipmi_ek_display_board_info_area ( + input_file, "Board Serial Number", &board_length); + fseek_(input_file, file_offset, SEEK_SET); + /* Board Part */ + file_offset = ipmi_ek_display_board_info_area ( + input_file, "Board Part Number", &board_length); + fseek_(input_file, file_offset, SEEK_SET); + /* FRU file ID */ + file_offset = ipmi_ek_display_board_info_area ( + input_file, "FRU File ID", &board_length); + fseek_(input_file, file_offset, SEEK_SET); + /* Additional Custom Mfg. */ + file_offset = ipmi_ek_display_board_info_area ( + input_file, "Custom", &board_length); + } + } + } + /*** Product Info Area ***/ + if ( header.offset.product ){ + if ( !feof(input_file) ){ + long offset = 0; + offset = header.offset.product * FACTOR_OFFSET; + ipmi_ek_display_product_info_area (input_file, offset); + } + } + fclose( input_file ); + } +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_chassis_info_area +* +* Description: this function displays detail format of product info area record +* into humain readable text format +* +* Restriction: Reference: IPMI Platform Management FRU Information Storage +* Definition V1.0, Section 10 +* +* Input: input_file: pointer to file stream +* offset: start offset of chassis info area +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_chassis_info_area( FILE * input_file, long offset ) +{ + if ( input_file != NULL ){ + printf("%s\n", EQUAL_LINE_LIMITER); + printf("Chassis Info Area\n"); + printf("%s\n", EQUAL_LINE_LIMITER); + + fseek_(input_file, offset, SEEK_SET); + if ( !feof(input_file) ){ + unsigned char data = 0; + unsigned int len = 0; + + fread (&data, 1, 1, input_file); + printf("Format Version Number: %d\n", (data & 0x0f) ); + if ( !feof(input_file) ){ + fread (&len, 1, 1, input_file); + /* len is in factor of 8 bytes */ + len = len * 8; + printf("Area Length: %d\n", len); + len -= 2; + } + if ( !feof(input_file) ){ + unsigned char ch_type = 0; + size_t file_offset = ftell (input_file); + /* Chassis Type*/ + fread (&ch_type, 1, 1, input_file); + printf("Chassis Type: %d\n", ch_type); + len --; + /* Chassis Part Number*/ + file_offset = ipmi_ek_display_board_info_area ( input_file, + "Chassis Part Number", &len); + fseek_(input_file, file_offset, SEEK_SET); + /* Chassis Serial */ + file_offset = ipmi_ek_display_board_info_area ( input_file, + "Chassis Serial Number", &len); + fseek_(input_file, file_offset, SEEK_SET); + /* Custom product info area */ + file_offset = ipmi_ek_display_board_info_area ( + input_file, "Custom", &len); + } + } + } + else{ + lprintf(LOG_ERR, "Invalid Chassis Info Area!"); + } +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_board_info_area +* +* Description: this function displays board info area depending on board type +* that pass in argument. Board type can be: +* Manufacturer, Serial, Product or Part... +* +* Restriction: IPMI Platform Management FRU Information Storage +* Definition V1.0, Section 11 +* +* Input: input_file: pointer to file stream +* board_type: a string that contain board type +* board_length: length of info area +* +* Output: None +* +* Global: None +* +* Return: the current position of input_file +* +***************************************************************************/ +static size_t +ipmi_ek_display_board_info_area( FILE * input_file, char * board_type, + unsigned int * board_length ) +{ + size_t file_offset = ftell (input_file); + unsigned char len = 0; + /* Board length*/ + if ( !feof(input_file) ){ + fread ( &len, 1, 1, input_file ); + (*board_length)--; + } + /* Board Data */ + if ( !feof(input_file) ){ + unsigned int size_board = 0; + + /*Bit 5:0 of Board Mfg type represent legnth*/ + size_board = (len & 0x3f); + if (size_board > 0){ + if ( strncmp( board_type, "Custom", 6 ) == 0 ){ + #define NO_MORE_INFO_FIELD 0xc1 + while ( !feof(input_file) && (*board_length > 0) ){ + if (len != NO_MORE_INFO_FIELD){ + printf("Additional Custom Mfg. length: 0x%02x\n", len); + if ( (size_board > 0) && (size_board < (*board_length)) ){ + unsigned char * additional_data = NULL; + int i=0; + additional_data = malloc (size_board); + if (additional_data != NULL){ + fread ( additional_data, size_board, 1, input_file ); + printf("Additional Custom Mfg. Data: %02x", + additional_data[0]); + for ( i =1; i<(int)size_board; i++){ + printf("-%02x", additional_data[i]); + } + printf("\n"); + free (additional_data); + (*board_length) -= size_board; + } + } + else{ + printf("No Additional Custom Mfg. %d\n", *board_length); + board_length = 0; + } + } + else{ + unsigned char padding; + /*take the rest of data in the area minus 1 byte of checksum*/ + printf("Additional Custom Mfg. length: 0x%02x\n", len); + padding = (*board_length) - 1; + /*we reach the end of the record, so its length is set to 0*/ + board_length = 0; + if ( ( padding > 0 ) && ( !feof(input_file) ) ){ + printf("Unused space: %d (bytes)\n", padding); + fseek_(input_file, padding, SEEK_CUR); + } + if ( !feof(input_file) ){ + unsigned char checksum = 0; + fread ( &checksum, 1, 1, input_file ); + printf("Checksum: 0x%02x\n", checksum); + + } + } + } + } + else{ + unsigned char * data; + unsigned int i=0; + #define TYPE_CODE 0xc0 /*Language code*/ + + data = malloc (size_board); + fread ( data, size_board, 1, input_file ); + printf("%s type: 0x%02x\n", board_type, len); + printf("%s: ", board_type); + for ( i = 0; i < size_board; i++ ){ + if ( (len & TYPE_CODE) == TYPE_CODE ){ + printf("%c", data[i]); + } + /*other than language code (binary, BCD, ASCII 6 bit...) is not + * supported */ + else{ + printf("%02x", data[i]); + } + } + printf("\n"); + free (data); + (*board_length) -= size_board; + file_offset = ftell (input_file); + } + } + else{ + printf("%s: None\n", board_type); + file_offset = ftell (input_file); + } + } + + return file_offset; +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_product_info_area +* +* Description: this function displays detail format of product info area record +* into humain readable text format +* +* Restriction: Reference: IPMI Platform Management FRU Information Storage +* Definition V1.0, Section 12 +* +* Input: input_file: pointer to file stream +* offset: start offset of product info area +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_product_info_area( FILE * input_file, long offset ) +{ + if ( input_file != NULL ){ + printf("%s\n", EQUAL_LINE_LIMITER); + printf("Product Info Area\n"); + printf("%s\n", EQUAL_LINE_LIMITER); + + fseek_(input_file, offset, SEEK_SET); + if ( !feof(input_file) ){ + unsigned char data = 0; + unsigned int len = 0; + + fread (&data, 1, 1, input_file); + printf("Format Version Number: %d\n", (data & 0x0f) ); + if ( !feof(input_file) ){ + fread (&len, 1, 1, input_file); + /* length is in factor of 8 bytes */ + len = len * 8; + printf("Area Length: %d\n", len); + len -= 2; /* -1 byte of format version and -1 byte itself */ + } + if ( !feof(input_file) ){ + size_t file_offset = ftell (input_file); + + fread (&data, 1, 1, input_file); + printf("Language Code: %d\n", data); + len --; + /* Product Mfg */ + file_offset = ipmi_ek_display_board_info_area ( input_file, + "Product Manufacture Data", &len); + fseek_(input_file, file_offset, SEEK_SET); + /* Product Name */ + file_offset = ipmi_ek_display_board_info_area ( input_file, + "Product Name", &len); + fseek_(input_file, file_offset, SEEK_SET); + /* Product Part */ + file_offset = ipmi_ek_display_board_info_area ( input_file, + "Product Part/Model Number", &len); + fseek_(input_file, file_offset, SEEK_SET); + /* Product Version */ + file_offset = ipmi_ek_display_board_info_area ( input_file, + "Product Version", &len); + fseek_(input_file, file_offset, SEEK_SET); + /* Product Serial */ + file_offset = ipmi_ek_display_board_info_area ( input_file, + "Product Serial Number", &len); + fseek_(input_file, file_offset, SEEK_SET); + /* Product Asset Tag */ + file_offset = ipmi_ek_display_board_info_area ( input_file, + "Asset Tag", &len); + fseek_(input_file, file_offset, SEEK_SET); + /* FRU file ID */ + file_offset = ipmi_ek_display_board_info_area ( + input_file, "FRU File ID", &len); + fseek_(input_file, file_offset, SEEK_SET); + /* Custom product info area */ + file_offset = ipmi_ek_display_board_info_area ( + input_file, "Custom", &len); + } + } + } + else{ + lprintf(LOG_ERR, "Invalid Product Info Area!"); + } +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_record +* +* Description: this function displays FRU multi record information. +* +* Restriction: None +* +* Input: record: a pointer to current record +* list_head: a pointer to header of the list +* list_last: a pointer to tale of the list +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_record( struct ipmi_ek_multi_header * record, + struct ipmi_ek_multi_header * list_head, + struct ipmi_ek_multi_header * list_last ) +{ + if ( list_head == NULL ){ + printf("***empty list***\n"); + } + else{ + printf("%s\n", EQUAL_LINE_LIMITER); + printf("FRU Multi Info area\n"); + printf("%s\n", EQUAL_LINE_LIMITER); + for ( record = list_head; record != NULL; record = record->next ){ + printf("Record Type ID: 0x%02x\n", record->header.type); + printf("Record Format version: 0x%02x\n", record->header.format); + if (record->header.len > PICMG_ID_OFFSET){ + /* In picmg3.0 specification, picmg record id lower than 4 or + * greater than 0x2d is not supported + */ + #define PICMG_ID_LOWER_LIMIT 0x04 + #define PICMG_ID_UPPER_LIMIT 0x2d + unsigned char picmg_id; + + picmg_id = record->data[PICMG_ID_OFFSET]; + printf("Manufacturer ID: %02x%02x%02x h\n", record->data[2], + record->data[1], record->data[0] ); + if( ( picmg_id < PICMG_ID_LOWER_LIMIT ) + || + ( picmg_id > PICMG_ID_UPPER_LIMIT ) ){ + printf("Picmg record ID: Unsupported {0x%02x}\n", picmg_id ); + } + else{ + printf("Picmg record ID: %s {0x%02x}\n", + val2str(picmg_id, ipmi_ekanalyzer_picmg_record_id), + picmg_id ); + } + switch (picmg_id){ + case FRU_PICMG_BACKPLANE_P2P: /*0x04*/ + ipmi_ek_display_backplane_p2p_record (record); + break; + case FRU_PICMG_ADDRESS_TABLE: /*0x10*/ + ipmi_ek_display_address_table_record (record); + break; + case FRU_PICMG_SHELF_POWER_DIST: /*0x11*/ + ipmi_ek_display_shelf_power_distribution_record (record); + break; + case FRU_PICMG_SHELF_ACTIVATION: /*/0x12*/ + ipmi_ek_display_shelf_activation_record (record); + break; + case FRU_PICMG_SHMC_IP_CONN: /*0x13*/ + ipmi_ek_display_shelf_ip_connection_record (record); + break; + case FRU_PICMG_BOARD_P2P: /*0x14*/ + ipmi_ek_display_board_p2p_record (record); + break; + case FRU_RADIAL_IPMB0_LINK_MAPPING: /*0x15*/ + ipmi_ek_display_radial_ipmb0_record (record); + break; + case FRU_AMC_CURRENT: /*0x16*/ + ipmi_ek_display_amc_current_record (record); + break; + case FRU_AMC_ACTIVATION: /*0x17*/ + ipmi_ek_display_amc_activation_record (record); + break; + case FRU_AMC_CARRIER_P2P: /*0x18*/ + ipmi_ek_diplay_carrier_connectivity (record); + break; + case FRU_AMC_P2P: /*0x19*/ + ipmi_ek_display_amc_p2p_record (record); + break; + case FRU_AMC_CARRIER_INFO: /*0x1a*/ + ipmi_ek_display_amc_carrier_info_record (record); + break; + case FRU_PICMG_CLK_CARRIER_P2P: /*0x2c*/ + ipmi_ek_display_clock_carrier_p2p_record (record); + break; + case FRU_PICMG_CLK_CONFIG: /*0x2d*/ + ipmi_ek_display_clock_config_record (record); + break; + default: + if (verbose > 0){ + int i; + printf("%02x %02x %02x %02x %02x ", record->header.type, + record->header.format, record->header.len, + record->header.record_checksum, + record->header.header_checksum ); + for ( i = 0; i < record->header.len; i++ ){ + printf("%02x ", record->data[i]); + } + printf("\n"); + } + break; + } + printf("%s\n", STAR_LINE_LIMITER); + } + } + } +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_backplane_p2p_record +* +* Description: this function displays backplane p2p record. +* +* Restriction: Reference: PICMG 3.0 Specification Table 3-40 +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_backplane_p2p_record( struct ipmi_ek_multi_header * record ) +{ + uint8_t index; + int offset = START_DATA_OFFSET; + struct fru_picmgext_slot_desc * slot_d + = (struct fru_picmgext_slot_desc*) &record->data[offset]; + + offset += sizeof(struct fru_picmgext_slot_desc); + + while ( offset <= record->header.len ) { + printf(" Channel Type: "); + switch ( slot_d -> chan_type ) + { + case 0x00: + case 0x07: + printf("PICMG 2.9\n"); + break; + case 0x08: + printf("Single Port Fabric IF\n"); + break; + case 0x09: + printf("Double Port Fabric IF\n"); + break; + case 0x0a: + printf("Full Channel Fabric IF\n"); + break; + case 0x0b: + printf("Base IF\n"); + break; + case 0x0c: + printf("Update Channel IF\n"); + break; + default: + printf("Unknown IF\n"); + break; + } + printf(" Slot Address: %02x\n", slot_d -> slot_addr); + printf(" Channel Count: %i\n", slot_d -> chn_count); + + for ( index = 0; index < (slot_d -> chn_count); index++ ) { + struct fru_picmgext_chn_desc * d + = (struct fru_picmgext_chn_desc *) &record->data[offset]; + + if ( verbose ){ + printf( "\t" + "Chn: %02x --> " + "Chn: %02x in " + "Slot: %02x\n", + d->local_chn, d->remote_chn, d->remote_slot + ); + } + offset += sizeof(struct fru_picmgext_chn_desc); + } + slot_d = (struct fru_picmgext_slot_desc*) &record->data[offset]; + offset += sizeof(struct fru_picmgext_slot_desc); + } +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_address_table_record +* +* Description: this function displays address table record. +* +* Restriction: Reference: PICMG 3.0 Specification Table 3-6 +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_address_table_record( struct ipmi_ek_multi_header * record ) +{ + unsigned char entries = 0; + unsigned char i; + int offset = START_DATA_OFFSET; + #define SIZE_SHELF_ADDRESS_BYTE 20 + + printf(" Type/Len: 0x%02x\n", record->data[offset++]); + printf(" Shelf Addr: "); + for ( i = 0; i < SIZE_SHELF_ADDRESS_BYTE; i++ ){ + printf("0x%02x ", record->data[offset++]); + } + printf("\n"); + + entries = record->data[offset++]; + printf(" Addr Table Entries count: 0x%02x\n", entries); + + for ( i = 0; i < entries; i++ ){ + printf("\tHWAddr: 0x%02x - SiteNum: 0x%02x - SiteType: 0x%02x \n", + record->data[offset+0], + record->data[offset+1], + record->data[offset+2]); + offset += 3; + } +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_shelf_power_distribution_record +* +* Description: this function displays shelf power distribution record. +* +* Restriction: Reference: PICMG 3.0 Specification Table 3-70 +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_shelf_power_distribution_record( + struct ipmi_ek_multi_header * record ) +{ + int offset = START_DATA_OFFSET; + unsigned char i,j; + unsigned char feeds = 0; + + feeds = record->data[offset++]; + printf(" Number of Power Feeds: 0x%02x\n", feeds); + + for (i=0; idata[offset+0] | (record->data[offset+1]<<8); + printf(" Max External Available Current: %ld Amps\n", (max_ext*10) ); + + offset += 2; + + max_int = record->data[offset+0] | (record->data[offset+1]<<8); + printf(" Max Internal Current:\t %ld Amps\n", (max_int*10)); + offset += 2; + printf(" Min Expected Operating Voltage: %ld Volts\n", + (record->data[offset++]/2)); + entries = record->data[offset++]; + printf(" Feed to FRU count: 0x%02x\n", entries); + for (j=0; jdata[offset++]); + printf("\tFRU ID: 0x%02x\n", record->data[offset++]); + } + } +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_shelf_activation_record +* +* Description: this function displays shelf activation record. +* +* Restriction: Reference: PICMG 3.0 Specification Table 3-73 +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_shelf_activation_record( + struct ipmi_ek_multi_header * record ) +{ + unsigned char count = 0; + int offset = START_DATA_OFFSET; + + printf(" Allowance for FRU Act Readiness: 0x%02x\n", + record->data[offset++]); + count = record->data[offset++]; + printf(" FRU activation and Power Desc Cnt: 0x%02x\n", count); + + while ( count > 0 ) { + printf(" FRU activation and Power descriptor:\n"); + printf("\tHardware Address:\t\t0x%02x\n", record->data[offset++]); + printf("\tFRU Device ID:\t\t\t0x%02x\n", record->data[offset++]); + printf("\tMax FRU Power Capability:\t0x%04x Watts\n", + ( record->data[offset+0] | (record->data[offset+1]<<8) )); + offset += 2; + printf("\tConfiguration parameter:\t0x%02x\n", record->data[offset++]); + count --; + } +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_shelf_ip_connection_record +* +* Description: this function displays shelf ip connection record. +* +* Restriction: Fix me: Don't test yet +* Reference: PICMG 3.0 Specification Table 3-31 +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_shelf_ip_connection_record( + struct ipmi_ek_multi_header * record ) +{ + int ioffset = START_DATA_OFFSET; + if (ioffset > record->header.len){ + printf(" Shelf Manager IP Address: %d.%d.%d.%d\n", + record->data[ioffset+0], record->data[ioffset+1], + record->data[ioffset+2], record->data[ioffset+3]); + ioffset += 4; + } + if (ioffset > record->header.len){ + printf(" Default Gateway Address: %d.%d.%d.%d\n", + record->data[ioffset+0], record->data[ioffset+1], + record->data[ioffset+2], record->data[ioffset+3]); + ioffset += 4; + } + if (ioffset > record->header.len){ + printf(" Subnet Mask: %d.%d.%d.%d\n", + record->data[ioffset+0], record->data[ioffset+1], + record->data[ioffset+2], record->data[ioffset+3]); + ioffset += 4; + } +} + +#ifdef NOT_USED +static void ipmi_ek_display_shelf_fan_geography_record( + struct ipmi_ek_multi_header * record ); + +/************************************************************************** +* +* Function name: ipmi_ek_display_shelf_fan_geography_record +* +* Description: this function displays shelf fan geography record. +* +* Restriction: Fix me: Don't test yet +* Reference: PICMG 3.0 Specification Table 3-75 +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_shelf_fan_geography_record( + struct ipmi_ek_multi_header * record ) +{ + int ioffset = START_DATA_OFFSET; + unsigned char fan_count = 0; + + fan_count = record->data[ioffset]; + ioffset ++; + printf(" Fan-to-FRU Entry Count: 0x%02x\n", fan_count); + + while ( (fan_count > 0) && (ioffset <= record->header.len) ){ + printf(" Fan-to-FRU Mapping Entry: {%2x%2x%2x%2x}\n", + record->data[ioffset], record->data[ioffset+1], + record->data[ioffset+2], record->data[ioffset+3] + ); + printf(" Hardware Address: 0x%02x\n", record->data[ioffset++]); + printf(" FRU device ID: 0x%02x\n", record->data[ioffset++]); + printf(" Site Number: 0x%02x\n", record->data[ioffset++]); + printf(" Site Type: 0x%02x\n", record->data[ioffset++]); + fan_count --; + } + +} +#endif + +/************************************************************************** +* +* Function name: ipmi_ek_display_board_p2p_record +* +* Description: this function displays board pont-to-point record. +* +* Restriction: Reference: PICMG 3.0 Specification Table 3-44 +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_board_p2p_record( struct ipmi_ek_multi_header * record ) +{ + unsigned char guid_count; + int offset = START_DATA_OFFSET; + int i = 0; + + guid_count = record->data[offset++]; + printf(" GUID count: %2d\n", guid_count); + + for (i = 0 ; i < guid_count; i++ ) { + int j; + printf("\tGUID: "); + for (j=0; j < sizeof(struct fru_picmgext_guid); j++) { + printf("%02x", record->data[offset+j]); + } + printf("\n"); + offset += sizeof(struct fru_picmgext_guid); + } + + for ( /*offset set above*/ ; + offset < record->header.len; + offset += sizeof(struct fru_picmgext_link_desc) + ) { + /* to solve little endian /big endian problem */ + unsigned long data; + struct fru_picmgext_link_desc * d; + + data = (record->data[offset+0]) | (record->data[offset+1] << 8)\ + | (record->data[offset+2] << 16)\ + | (record->data[offset+3] << 24); + + d = (struct fru_picmgext_link_desc *) &data; + + printf(" Link Descriptor\n"); + printf("\tLink Grouping ID:\t0x%02x\n", d->grouping); + printf("\tLink Type Extension:\t0x%02x - ", d->ext); + + if (d->type == FRU_PICMGEXT_LINK_TYPE_BASE){ + switch (d->ext){ + case 0: + printf("10/100/1000BASE-T Link (four-pair)\n"); + break; + case 1: + printf("ShMC Cross-connect (two-pair)\n"); + break; + default: + printf("Unknwon\n"); + break; + } + } + else if (d->type == FRU_PICMGEXT_LINK_TYPE_FABRIC_ETHERNET){ + switch (d->ext){ + case 0: + printf("Fixed 1000Base-BX\n"); + break; + case 1: + printf("Fixed 10GBASE-BX4 [XAUI]\n"); + break; + case 2: + printf("FC-PI\n"); + break; + default: + printf("Unknwon\n"); + break; + } + } + else if (d->type == FRU_PICMGEXT_LINK_TYPE_FABRIC_INFINIBAND){ + printf("Unknwon\n"); + } + else if (d->type == FRU_PICMGEXT_LINK_TYPE_FABRIC_STAR){ + printf("Unknwon\n"); + } + else if (d->type == FRU_PICMGEXT_LINK_TYPE_PCIE){ + printf("Unknwon\n"); + } + else{ + printf("Unknwon\n"); + } + + printf("\tLink Type:\t\t0x%02x - ",d->type); + if (d->type == 0 || d->type == 0xff){ + printf("Reserved\n"); + } + else if (d->type >= 0x06 && d->type <= 0xef) { + printf("Reserved\n"); + } + else if (d->type >= LOWER_OEM_TYPE && d->type <= UPPER_OEM_TYPE) { + printf("OEM GUID Definition\n"); + } + else { + switch (d->type){ + case FRU_PICMGEXT_LINK_TYPE_BASE: + printf("PICMG 3.0 Base Interface 10/100/1000\n"); + break; + case FRU_PICMGEXT_LINK_TYPE_FABRIC_ETHERNET: + printf("PICMG 3.1 Ethernet Fabric Interface\n"); + break; + case FRU_PICMGEXT_LINK_TYPE_FABRIC_INFINIBAND: + printf("PICMG 3.2 Infiniband Fabric Interface\n"); + break; + case FRU_PICMGEXT_LINK_TYPE_FABRIC_STAR: + printf("PICMG 3.3 Star Fabric Interface\n"); + break; + case FRU_PICMGEXT_LINK_TYPE_PCIE: + printf("PICMG 3.4 PCI Express Fabric Interface\n"); + break; + default: + printf("Invalid\n"); + break; + } + } + printf("\tLink Designator: \n"); + printf("\t Port 0 Flag: %s\n", + (d->desig_port & 0x01) ? "enable" : "disable"); + printf("\t Port 1 Flag: %s\n", + (d->desig_port & 0x02) ? "enable" : "disable"); + printf("\t Port 2 Flag: %s\n", + (d->desig_port & 0x04) ? "enable" : "disable"); + printf("\t Port 3 Flag: %s\n", + (d->desig_port & 0x08) ? "enable" : "disable"); + + printf("\t Interface: 0x%02x - ", d->desig_if); + switch (d->desig_if){ + case FRU_PICMGEXT_DESIGN_IF_BASE: + printf("Base Interface\n"); + break; + case FRU_PICMGEXT_DESIGN_IF_FABRIC: + printf("Fabric Interface\n"); + break; + case FRU_PICMGEXT_DESIGN_IF_UPDATE_CHANNEL: + printf("Update Channel\n"); + break; + case FRU_PICMGEXT_DESIGN_IF_RESERVED: + printf("Reserved\n"); + break; + default: + printf("Invalid"); + break; + } + printf("\t Channel Number: 0x%02x\n", d->desig_channel); + } +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_radial_ipmb0_record +* +* Description: this function displays radial IPMB-0 record. +* +* Restriction: Fix me: Don't test yet +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_radial_ipmb0_record( struct ipmi_ek_multi_header * record ) +{ + int offset = START_DATA_OFFSET; + #define SIZE_OF_CONNECTOR_DEFINER 3; /*bytes*/ + + /*Ref: PICMG 3.0 Specification Revision 2.0, Table 3-59*/ + printf(" IPMB-0 Connector Definer: "); + #ifndef WORDS_BIGENDIAN + printf("%02x %02x %02x h\n", record->data[offset], + record->data[offset+1], record->data[offset+2]); + #else + printf("%02x %02x %02x h\n", record->data[offset+2], + record->data[offset+1], record->data[offset]); + #endif + /*3 bytes of connector definer was used*/ + offset += SIZE_OF_CONNECTOR_DEFINER; + + printf (" IPMB-0 Connector version ID: "); + #ifndef WORDS_BIGENDIAN + printf("%02x %02x h\n", record->data[offset], record->data[offset+1]); + #else + printf("%02x %02x h\n", record->data[offset+1], record->data[offset]); + #endif + offset += 2; + + printf(" IPMB-0 Hub Descriptor Count: 0x%02x", record->data[offset++]); + if (record->data[offset] > 0){ + for (/*offset*/; offset < record->header.len;){ + unsigned char entry_count = 0; + printf(" IPMB-0 Hub Descriptor\n"); + printf("\tHardware Address: 0x%02x\n", record->data[offset++]); + printf("\tHub Info {0x%02x}: ", record->data[offset]); + /* Bit mask specified in Table 3-59 of PICMG 3.0 Specification */ + if ( (record->data[offset] & 0x01) == 0x01 ){ + printf("IPMB-A only\n"); + } + else if ( (record->data[offset] & 0x02) == 0x02 ){ + printf("IPMB-B only\n"); + } + else if ( (record->data[offset] & 0x03) == 0x03 ){ + printf("IPMB-A and IPMB-B\n"); + } + else{ + printf("Reserved.\n"); + } + offset ++; + + entry_count = record->data[offset++]; + printf("\tAddress Entry count: 0x%02x", entry_count); + while (entry_count > 0){ + printf("\t Hardware Address: 0x%02x\n", record->data[offset++]); + printf("\t IPMB-0 Link Entry: 0x%02x\n",record->data[offset++]); + entry_count --; + } + } + } + +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_amc_current_record +* +* Description: this function displays AMC current record. +* +* Restriction: None +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_amc_current_record( struct ipmi_ek_multi_header * record ) +{ + unsigned char current; + current = record->data[START_DATA_OFFSET]; + printf(" Current draw: %.1f A @ 12V => %.2f Watt\n", + (float) current/10.0, ((float)current/10.0)*12.0 ); + printf("\n"); +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_amc_activation_record +* +* Description: this function displays carrier activation and current management +* record. +* +* Restriction: Reference: AMC.0 Specification Table 3-11 and Table 3-12 +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_amc_activation_record( struct ipmi_ek_multi_header * record ) +{ + uint16_t max_current; + int offset = START_DATA_OFFSET; + + max_current = record->data[offset]; + max_current |= record->data[++offset] << 8; + printf(" Maximum Internal Current(@12V): %.2f A [ %.2f Watt ]\n", + (float) max_current / 10, + (float) max_current / 10 * 12); + printf(" Module Activation Readiness: %i sec.\n", + record->data[++offset]); + + printf(" Descriptor Count: %i\n", record->data[++offset]); + for(++offset; (offset < record->header.len); offset += 3 ) + { + struct fru_picmgext_activation_record * a = + (struct fru_picmgext_activation_record *) &record->data[offset]; + + printf("\tIPMB-Address:\t\t0x%x\n", a->ibmb_addr); + printf("\tMax. Module Current:\t%.2f A\n", (float)a->max_module_curr/10); + printf("\n"); + } +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_amc_p2p_record +* +* Description: this function display amc p2p connectivity record in humain +* readable text format +* +* Restriction: Reference: AMC.0 Specification Table 3-16 +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_amc_p2p_record( struct ipmi_ek_multi_header * record ) +{ + int index_data = START_DATA_OFFSET; + int oem_count = 0; + int ch_count = 0; + int index=0; + + oem_count = record->data[index_data++]; + printf("OEM GUID count: %02x\n", oem_count); + + if ( oem_count > 0 ){ + while ( oem_count > 0 ){ + printf("OEM GUID: "); + for ( index = 1; index <= SIZE_OF_GUID; index++ ){ + printf("%02x", record->data[index_data++]); + /* For a better look, display a "-" character after each 5 bytes + * of OEM GUID */ + if ( !(index % 5) ){ + printf("-"); + } + } + printf("\n"); + oem_count--; + } + } + if ( ( record->data[index_data] & AMC_MODULE ) == AMC_MODULE ){ + printf("AMC module connection\n"); + } + else{ + printf("On-Carrier Device %02x h\n", ( record->data[index_data] & 0x0f )); + } + index_data ++; + ch_count = record->data[index_data++]; + printf("AMC Channel Descriptor count: %02x h\n", ch_count); + + if ( ch_count > 0 ){ + for ( index = 0; index < ch_count; index++ ){ + struct fru_picmgext_amc_channel_desc_record * ch_desc; + printf(" AMC Channel Descriptor {%02x%02x%02x}\n", + record->data[index_data+2], record->data[index_data+1], + record->data[index_data] + ); + /*Warning: For gcc version between 4.0 and 4.3 this code doesnt work*/ + ch_desc = ( struct fru_picmgext_amc_channel_desc_record * )\ + &record->data[index_data]; + printf(" Lane 0 Port: 0x%02x\n", ch_desc->lane0port); + printf(" Lane 1 Port: 0x%02x\n", ch_desc->lane1port); + printf(" Lane 2 Port: 0x%02x\n", ch_desc->lane2port); + printf(" Lane 3 Port: 0x%02x\n\n", ch_desc->lane3port); + index_data += sizeof (struct fru_picmgext_amc_channel_desc_record) ; + } + } + while ( index_data < record->header.len ){ + /*Warning: For gcc version between 4.0 and 4.3 this code doesnt work*/ + struct fru_picmgext_amc_link_desc_record * link_desc = + (struct fru_picmgext_amc_link_desc_record *)&record->data[index_data]; + + printf(" AMC Link Descriptor:\n" ); + + printf("\t- Link Type: %s \n", + val2str (link_desc->type, ipmi_ekanalyzer_link_type)); + switch ( link_desc->type ){ + case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE: + case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS1: + case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS2: + printf("\t- Link Type extension: %s\n", + val2str (link_desc->type_ext, ipmi_ekanalyzer_extension_PCIE)); + printf("\t- Link Group ID: %d\n ", link_desc->group_id ); + printf("\t- Link Asym. Match: %s\n", + val2str (link_desc->asym_match, ipmi_ekanalyzer_asym_PCIE)); + break; + case FRU_PICMGEXT_AMC_LINK_TYPE_ETHERNET: + printf("\t- Link Type extension: %s\n", + val2str (link_desc->type_ext, + ipmi_ekanalyzer_extension_ETHERNET)); + printf("\t- Link Group ID: %d \n", link_desc->group_id ); + printf("\t- Link Asym. Match: %s\n", + val2str (link_desc->asym_match, ipmi_ekanalyzer_asym_PCIE)); + break; + case FRU_PICMGEXT_AMC_LINK_TYPE_STORAGE: + printf("\t- Link Type extension: %s\n", + val2str (link_desc->type_ext, + ipmi_ekanalyzer_extension_STORAGE)); + printf("\t- Link Group ID: %d \n", link_desc->group_id ); + printf("\t- Link Asym. Match: %s\n", + val2str (link_desc->asym_match, ipmi_ekanalyzer_asym_STORAGE)); + break; + default: + printf("\t- Link Type extension: %i\n", link_desc->type_ext ); + printf("\t- Link Group ID: %d \n", link_desc->group_id ); + printf("\t- Link Asym. Match: %i\n", link_desc->asym_match); + break; + } + printf("\t- AMC Link Designator:\n"); + printf("\t Channel ID: %i\n", link_desc->channel_id); + printf("\t\t Lane 0: %s\n", (link_desc->port_flag_0)?"enable":"disable"); + printf("\t\t Lane 1: %s\n", (link_desc->port_flag_1)?"enable":"disable"); + printf("\t\t Lane 2: %s\n", (link_desc->port_flag_2)?"enable":"disable"); + printf("\t\t Lane 3: %s\n", (link_desc->port_flag_3)?"enable":"disable"); + index_data += sizeof (struct fru_picmgext_amc_link_desc_record); + } +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_amc_carrier_info_record +* +* Description: this function displays Carrier information table. +* +* Restriction: Reference: AMC.0 Specification Table 3-3 +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: START_DATA_OFFSET +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_amc_carrier_info_record( struct ipmi_ek_multi_header * record ) +{ + unsigned char extVersion; + unsigned char siteCount; + int offset = START_DATA_OFFSET; + + extVersion = record->data[offset++]; + siteCount = record->data[offset++]; + + printf(" AMC.0 extension version: R%d.%d\n", (extVersion >> 0)& 0x0F, + (extVersion >> 4)& 0x0F ); + printf(" Carrier Sie Number Count: %d\n", siteCount); + + while (siteCount > 0){ + printf("\tSite ID (%d): %s \n", record->data[offset], + val2str(record->data[offset], ipmi_ekanalyzer_module_type) ); + offset++; + siteCount--; + } + printf("\n"); +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_clock_carrier_p2p_record +* +* Description: this function displays Carrier clock point-to-pont +* connectivity record. +* +* Restriction: the following code is copy from ipmi_fru.c with modification in +* reference to AMC.0 Specification Table 3-29 +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_display_clock_carrier_p2p_record( + struct ipmi_ek_multi_header * record ) +{ + unsigned char desc_count; + int i,j; + int offset = START_DATA_OFFSET; + + desc_count = record->data[offset++]; + + for(i=0; idata[offset++]; + channel_count = record->data[offset++]; + + printf(" Clock Resource ID: 0x%02x\n", resource_id); + printf(" Type: "); + if((resource_id & 0xC0)>>6 == 0) { + printf("On-Carrier-Device\n"); + } + else if((resource_id & 0xC0)>>6 == 1) { + printf("AMC slot\n"); + } + else if((resource_id & 0xC0)>>6 == 2) { + printf("Backplane\n"); + } + else{ + printf("reserved\n"); + } + printf(" Channel Count: 0x%02x\n", channel_count); + + for(j=0; jdata[offset++]; + rem_channel = record->data[offset++]; + rem_resource = record->data[offset++]; + + printf("\tCLK-ID: 0x%02x ---> ", loc_channel); + printf(" remote CLKID: 0x%02x ", rem_channel); + if((rem_resource & 0xC0)>>6 == 0) { + printf("[ Carrier-Dev"); + } + else if((rem_resource & 0xC0)>>6 == 1) { + printf("[ AMC slot "); + } + else if((rem_resource & 0xC0)>>6 == 2) { + printf("[ Backplane "); + } + else{ + printf("reserved "); + } + printf(" 0x%02x ]\n", rem_resource&0xF); + } + } + printf("\n"); +} + +/************************************************************************** +* +* Function name: ipmi_ek_display_clock_config_record +* +* Description: this function displays clock configuration record. +* +* Restriction: the following codes are copy from ipmi_fru.c with modification +* in reference to AMC.0 Specification Table 3-35 and Table 3-36 +* +* Input: record: a pointer to current record to be displayed +* +* Output: None +* +* Global: START_DATA_OFFSET +* +* Return: None +* +***************************************************************************/ +void +ipmi_ek_display_clock_config_record( struct ipmi_ek_multi_header * record ) +{ + unsigned char resource_id, descr_count; + int i; + int offset = START_DATA_OFFSET; + + resource_id = record->data[offset++]; + descr_count = record->data[offset++]; + printf(" Clock Resource ID: 0x%02x\n", resource_id); + printf(" Clock Configuration Descriptor Count: 0x%02x\n", descr_count); + + for(i=0; idata[offset++]; + control = record->data[offset++]; + printf("\tCLK-ID: 0x%02x - ", channel_id); + printf("CTRL 0x%02x [ %12s ]\n", control, + ((control&0x1)==0)?"Carrier IPMC":"Application"); + + indirect_cnt = record->data[offset++]; + direct_cnt = record->data[offset++]; + printf("\t Count: Indirect 0x%02x / Direct 0x%02x\n", indirect_cnt, + direct_cnt ); + + /* indirect desc */ + for(j=0; jdata[offset++]; + dep_chn_id = record->data[offset++]; + printf("\t\tFeature: 0x%02x [%8s] - ", feature, + (feature&0x1)==1?"Source":"Receiver"); + printf(" Dep. CLK-ID: 0x%02x\n", dep_chn_id); + } + + /* direct desc */ + for(j=0; jdata[offset++]; + family = record->data[offset++]; + accuracy = record->data[offset++]; + freq = (record->data[offset+0] << 0 ) + | (record->data[offset+1] << 8 ) + | (record->data[offset+2] << 16) + | (record->data[offset+3] << 24); + offset += 4; + min_freq = (record->data[offset+0] << 0 ) + | (record->data[offset+1] << 8 ) + | (record->data[offset+2] << 16) + | (record->data[offset+3] << 24); + offset += 4; + max_freq = (record->data[offset+0] << 0 ) + | (record->data[offset+1] << 8 ) + | (record->data[offset+2] << 16) + | (record->data[offset+3] << 24); + offset += 4; + + printf("\t- Feature: 0x%02x - PLL: %x / Asym: %s\n", + feature, + (feature > 1) & 1, + (feature&1)?"Source":"Receiver"); + printf("\tFamily: 0x%02x - AccLVL: 0x%02x\n", family, accuracy); + printf("\tFRQ: %-9d - min: %-9d - max: %-9d\n", + freq, min_freq, max_freq); + } + printf("\n"); + } +} + +/************************************************************************** +* +* Function name: ipmi_ekanalyzer_fru_file2structure +* +* Description: this function convert a FRU binary file into a linked list of +* FRU multi record +* +* Restriction: None +* +* Input/Ouput: filename1: name of the file that contain FRU binary data +* record: a pointer to current record +* list_head: a pointer to header of the list +* list_last: a pointer to tale of the list +* +* Global: None +* +* Return: return -1 as Error status, and 0 as Ok status +* +***************************************************************************/ +static int +ipmi_ekanalyzer_fru_file2structure( char * filename, + struct ipmi_ek_multi_header ** list_head, + struct ipmi_ek_multi_header ** list_record, + struct ipmi_ek_multi_header ** list_last ) +{ + int return_status = ERROR_STATUS; + FILE * input_file; + + + input_file = fopen ( filename, "r"); + if ( input_file == NULL ){ + lprintf(LOG_ERR, "File: '%s' is not found", filename); + return_status = ERROR_STATUS; + } + else{ + long multi_offset = 0; + fseek_( input_file, START_DATA_OFFSET, SEEK_SET ); + fread ( &multi_offset, 1, 1, input_file ); + if ( multi_offset <= 0 ){ + lprintf(LOG_NOTICE, "There is no multi record in the file %s\n", + filename); + } + else{ + int record_count = 0; + + if ( verbose >= 2) { // was == LOG_DEBUG + printf( "start multi offset = 0x%02x\n", multi_offset ); + } + /*the offset value is in multiple of 8 bytes.*/ + multi_offset = multi_offset * 8; + fseek_( input_file, multi_offset, SEEK_SET ); + while ( !feof( input_file ) ){ + *list_record = malloc ( sizeof (struct ipmi_ek_multi_header) ); + fread ( &(*list_record)->header, START_DATA_OFFSET, 1, input_file); + if ( (*list_record)->header.len > 0 ){ + (*list_record)->data = + malloc ((*list_record)->header.len); + if ( (*list_record)->data == NULL ){ + lprintf(LOG_ERR, "Lack of memory"); + } + else{ + unsigned char last_record = 0; + + fread ( (*list_record)->data, + ((*list_record)->header.len), 1, input_file); + if ( verbose > 0 ) + printf("Record %d has length = %02x\n", record_count, + (*list_record)->header.len); + if ( verbose > 1 ){ + int i; + printf("%02x\t", (*list_record)->header.type); + for ( i = 0; i < ( (*list_record)->header.len ); i++ ){ + printf("%02x\t", (*list_record)->data[i]); + } + printf("\n"); + } + ipmi_ek_add_record2list ( list_record, list_head, list_last ); + /*mask the 8th bits to see if it is the last record*/ + last_record = ((*list_record)->header.format) & 0x80; + if ( last_record ){ + break; + } + } + } + record_count++; + } + } + fclose( input_file ); + return_status = OK_STATUS; + } + return return_status; +} + + +/************************************************************************** +* +* Function name: ipmi_ek_add_record2list +* +* Description: this function adds a sigle FRU multi record to a linked list of +* FRU multi record. +* +* Restriction: None +* +* Input/Output: record: a pointer to current record +* list_head: a pointer to header of the list +* list_last: a pointer to tale of the list +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_add_record2list( struct ipmi_ek_multi_header ** record, + struct ipmi_ek_multi_header ** list_head, + struct ipmi_ek_multi_header ** list_last ) +{ + if (*list_head == NULL) { + *list_head = *record; + (*record)->prev = NULL; + if (verbose > 2) + printf("Adding first record to list\n"); + } + else { + (*list_last)->next = *record; + (*record)->prev = *list_last; + if (verbose > 2) + printf("Add 1 record to list\n"); + } + *list_last = *record; + (*record)->next = NULL; +} + +/************************************************************************** +* +* Function name: ipmi_ek_remove_record_from_list +* +* Description: this function removes a sigle FRU multi record from a linked +* list of FRU multi record. +* +* Restriction: None +* +* Input/Output: record: a pointer to record to be deleted +* list_head: a pointer to header of the list +* list_last: a pointer to tale of the list +* +* Global: None +* +* Return: None +* +***************************************************************************/ +static void +ipmi_ek_remove_record_from_list( struct ipmi_ek_multi_header * record, + struct ipmi_ek_multi_header ** list_head, + struct ipmi_ek_multi_header ** list_last ) +{ + if (record->prev == NULL) + *list_head = record->next; + else + record->prev->next = record->next; + if ( record->next == NULL ) + (*list_last) = record->prev; + else + record->next->prev = record->prev; + free (record); +} + +#ifdef METACOMMAND +int i_ekanalyzer(int argc, char **argv) +#else +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#endif +{ + void *intf = NULL; + int rc = 0; + int c, i; + char *s1; + + printf("%s ver %s\n", progname,progver); + + while ( (c = getopt( argc, argv,"m:T:V:J:EYF:P:N:R:U:Z:x?")) != EOF ) + switch (c) { + case 'm': /* specific IPMB MC, 3-byte address, e.g. "409600" */ + g_bus = htoi(&optarg[0]); /*bus/channel*/ + g_sa = htoi(&optarg[2]); /*device slave address*/ + g_lun = htoi(&optarg[4]); /*LUN*/ + g_addrtype = ADDR_IPMB; + if (optarg[6] == 's') { + g_addrtype = ADDR_SMI; s1 = "SMI"; + } else { g_addrtype = ADDR_IPMB; s1 = "IPMB"; } + ipmi_set_mc(g_bus,g_sa,g_lun,g_addrtype); + printf("Use MC at %s bus=%x sa=%x lun=%x\n", + s1,g_bus,g_sa,g_lun); + break; + case 'x': fdebug = 1; verbose = 2; + break; /* debug messages */ + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'V': /* priv level */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + break; + case '?': + ipmi_ekanalyzer_usage(); + return ERR_USAGE; + break; + } + for (i = 0; i < optind; i++) { argv++; argc--; } + + rc = ipmi_ekanalyzer_main(intf, argc, argv); + + ipmi_close_(); + return rc; +} + +/*end iekanalyzer.c*/ diff --git a/util/iekanalyzer.h b/util/iekanalyzer.h new file mode 100644 index 0000000..452b935 --- /dev/null +++ b/util/iekanalyzer.h @@ -0,0 +1,521 @@ +/* + * Copyright (c) 2007 Kontron Canada, Inc. All Rights Reserved. + * + * Base on code from + * 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. + */ + +#ifndef IPMI_EKANALYZER_H +#define IPMI_EKANALYZER_H + +#define uint8_t unsigned char +#define uint16_t unsigned short +#define uint32_t unsigned int +#if __WORDSIZE == 64 +#define uint64_t unsigned long int +#else +#define uint64_t unsigned long long +#endif +#define TRUE 1 +#define FALSE 0 +#ifndef tboolean +#define tboolean int +#endif +// struct ipmi_intf; + +#define RTM_FRU_FILE 0x00 +#define A1_AMC_FRU_FILE 0x01 +#define A2_AMC_FRU_FILE 0x02 +#define A3_AMC_FRU_FILE 0x03 +#define A4_AMC_FRU_FILE 0x04 +#define B1_AMC_FRU_FILE 0x05 +#define B2_AMC_FRU_FILE 0x06 +#define B3_AMC_FRU_FILE 0x07 +#define B4_AMC_FRU_FILE 0x08 +#define ON_CARRIER_FRU_FILE 0x09 +#define CONFIG_FILE 0x0A +#define SHELF_MANAGER_FRU_FILE 0x0B + +#define MIN_ARGUMENT 0x02 +#define RTM_IPMB_L 0x90 + +#define MAX_FILE_NUMBER 8 +/* this voltag is specified in AMC.0 specification Table 3-10 */ +#define AMC_VOLTAGE 12 /*volts*/ + +#define SIZE_OF_GUID 16 +#define FRU_RADIAL_IPMB0_LINK_MAPPING 0x15 + +//struct valstr { + // uint16_t val; + // const char * str; +//}; +//const char * val2str(ushort val, const struct valstr *vs); + +#ifndef OEM_FRU_H +#define OEM_FRU_H + +#define GET_FRU_INFO 0x10 +#define GET_FRU_DATA 0x11 +#define SET_FRU_DATA 0x12 + +enum { + FRU_CHASSIS_PARTNO, + FRU_CHASSIS_SERIAL, + FRU_BOARD_MANUF, + FRU_BOARD_PRODUCT, + FRU_BOARD_SERIAL, + FRU_BOARD_PARTNO, + FRU_PRODUCT_MANUF, + FRU_PRODUCT_NAME, + FRU_PRODUCT_PARTNO, + FRU_PRODUCT_VERSION, + FRU_PRODUCT_SERIAL, + FRU_PRODUCT_ASSET, +}; + +struct fru_area_chassis { + uint8_t area_ver; + uint8_t type; + uint16_t area_len; + char * part; + char * serial; +}; + +struct fru_area_board { + uint8_t area_ver; + uint8_t lang; + uint16_t area_len; + uint32_t mfg_date_time; + char * mfg; + char * prod; + char * serial; + char * part; + char * fru; +}; + +struct fru_area_product { + uint8_t area_ver; + uint8_t lang; + uint16_t area_len; + char * mfg; + char * name; + char * part; + char * version; + char * serial; + char * asset; + char * fru; +}; + +#pragma pack(1) +struct fru_info { + uint16_t size; + uint8_t access:1; +}; //__attribute__ ((packed)); + +struct fru_header { + uint8_t version; + struct { + uint8_t internal; + uint8_t chassis; + uint8_t board; + uint8_t product; + uint8_t multi; + } offset; + uint8_t pad; + uint8_t checksum; +}; //__attribute__ ((packed)); + +struct fru_multirec_header { +#define FRU_RECORD_TYPE_POWER_SUPPLY_INFORMATION 0x00 +#define FRU_RECORD_TYPE_DC_OUTPUT 0x01 +#define FRU_RECORD_TYPE_DC_LOAD 0x02 +#define FRU_RECORD_TYPE_MANAGEMENT_ACCESS 0x03 +#define FRU_RECORD_TYPE_BASE_COMPATIBILITY 0x04 +#define FRU_RECORD_TYPE_EXTENDED_COMPATIBILITY 0x05 +#define FRU_RECORD_TYPE_OEM_EXTENSION 0xc0 + uint8_t type; + uint8_t format; + uint8_t len; + uint8_t record_checksum; + uint8_t header_checksum; +}; //__attribute__ ((packed)); + +struct fru_multirec_powersupply { +#if WORDS_BIGENDIAN + uint16_t capacity; +#else + uint16_t capacity:12; + uint16_t __reserved1:4; +#endif + uint16_t peak_va; + uint8_t inrush_current; + uint8_t inrush_interval; + uint16_t lowend_input1; + uint16_t highend_input1; + uint16_t lowend_input2; + uint16_t highend_input2; + uint8_t lowend_freq; + uint8_t highend_freq; + uint8_t dropout_tolerance; +#if WORDS_BIGENDIAN + uint8_t __reserved2:3; + uint8_t tach:1; + uint8_t hotswap:1; + uint8_t autoswitch:1; + uint8_t pfc:1; + uint8_t predictive_fail:1; +#else + uint8_t predictive_fail:1; + uint8_t pfc:1; + uint8_t autoswitch:1; + uint8_t hotswap:1; + uint8_t tach:1; + uint8_t __reserved2:3; +#endif + uint16_t peak_cap_ht; +#if WORDS_BIGENDIAN + uint8_t combined_voltage1:4; + uint8_t combined_voltage2:4; +#else + uint8_t combined_voltage2:4; + uint8_t combined_voltage1:4; +#endif + uint16_t combined_capacity; + uint8_t rps_threshold; +}; //__attribute__ ((packed)); + +struct fru_multirec_dcoutput { +#if WORDS_BIGENDIAN + uint8_t standby:1; + uint8_t __reserved:3; + uint8_t output_number:4; +#else + uint8_t output_number:4; + uint8_t __reserved:3; + uint8_t standby:1; +#endif + short nominal_voltage; + short max_neg_dev; + short max_pos_dev; + uint16_t ripple_and_noise; + uint16_t min_current; + uint16_t max_current; +}; //__attribute__ ((packed)); + +struct fru_multirec_dcload { +#if WORDS_BIGENDIAN + uint8_t __reserved:4; + uint8_t output_number:4; +#else + uint8_t output_number:4; + uint8_t __reserved:4; +#endif + short nominal_voltage; + short min_voltage; + short max_voltage; + uint16_t ripple_and_noise; + uint16_t min_current; + uint16_t max_current; +}; //__attribute__ ((packed)); + +struct fru_multirec_oem_header { + unsigned char mfg_id[3]; +#define FRU_PICMG_BACKPLANE_P2P 0x04 +#define FRU_PICMG_ADDRESS_TABLE 0x10 +#define FRU_PICMG_SHELF_POWER_DIST 0x11 +#define FRU_PICMG_SHELF_ACTIVATION 0x12 +#define FRU_PICMG_SHMC_IP_CONN 0x13 +#define FRU_PICMG_BOARD_P2P 0x14 +#define FRU_AMC_CURRENT 0x16 +#define FRU_AMC_ACTIVATION 0x17 +#define FRU_AMC_CARRIER_P2P 0x18 +#define FRU_AMC_P2P 0x19 +#define FRU_AMC_CARRIER_INFO 0x1a +#define FRU_UTCA_FRU_INFO_TABLE 0x20 +#define FRU_UTCA_CARRIER_MNG_IP 0x21 +#define FRU_UTCA_CARRIER_INFO 0x22 +#define FRU_UTCA_CARRIER_LOCATION 0x23 +#define FRU_UTCA_SHMC_IP_LINK 0x24 +#define FRU_UTCA_POWER_POLICY 0x25 +#define FRU_UTCA_ACTIVATION 0x26 +#define FRU_UTCA_PM_CAPABILTY 0x27 +#define FRU_UTCA_FAN_GEOGRAPHY 0x28 +#define FRU_UTCA_CLOCK_MAPPING 0x29 +#define FRU_UTCA_MSG_BRIDGE_POLICY 0x2A +#define FRU_UTCA_OEM_MODULE_DESC 0x2B +#define FRU_PICMG_CLK_CARRIER_P2P 0x2C +#define FRU_PICMG_CLK_CONFIG 0x2D + unsigned char record_id; + unsigned char record_version; +}; //__attribute__ ((packed)); + +struct fru_picmgext_guid { + unsigned char guid[16]; +}; //__attribute__ ((packed)); + +#ifndef HAVE_FRU_PICMG_EXT +#define HAVE_FRU_PICMG_EXT +struct fru_picmgext_link_desc { +#ifndef WORDS_BIGENDIAN + unsigned int desig_channel:6; + unsigned int desig_if:2; + unsigned int desig_port:4; +#define FRU_PICMGEXT_LINK_TYPE_BASE 0x01 +#define FRU_PICMGEXT_LINK_TYPE_FABRIC_ETHERNET 0x02 +#define FRU_PICMGEXT_LINK_TYPE_FABRIC_INFINIBAND 0x03 +#define FRU_PICMGEXT_LINK_TYPE_FABRIC_STAR 0x04 +#define FRU_PICMGEXT_LINK_TYPE_PCIE 0x05 + unsigned int type:8; + unsigned int ext:4; + unsigned int grouping:8; +#else + unsigned int grouping:8; + unsigned int ext:4; +#define FRU_PICMGEXT_LINK_TYPE_BASE 0x01 +#define FRU_PICMGEXT_LINK_TYPE_FABRIC_ETHERNET 0x02 +#define FRU_PICMGEXT_LINK_TYPE_FABRIC_INFINIBAND 0x03 +#define FRU_PICMGEXT_LINK_TYPE_FABRIC_STAR 0x04 +#define FRU_PICMGEXT_LINK_TYPE_PCIE 0x05 + unsigned int type:8; + unsigned int desig_port:4; + unsigned int desig_if:2; + unsigned int desig_channel:6; +#endif +}; //__attribute__ ((packed)); + + +#define FRU_PICMGEXT_AMC_LINK_TYPE_RESERVED 0x00 +#define FRU_PICMGEXT_AMC_LINK_TYPE_RESERVED1 0x01 +#define FRU_PICMGEXT_AMC_LINK_TYPE_PCI_EXPRESS 0x02 +#define FRU_PICMGEXT_AMC_LINK_TYPE_ADVANCED_SWITCHING1 0x03 +#define FRU_PICMGEXT_AMC_LINK_TYPE_ADVANCED_SWITCHING2 0x04 +#define FRU_PICMGEXT_AMC_LINK_TYPE_ETHERNET 0x05 +#define FRU_PICMGEXT_AMC_LINK_TYPE_RAPIDIO 0x06 +#define FRU_PICMGEXT_AMC_LINK_TYPE_STORAGE 0x07 + +/* This is used in command, not in FRU */ +struct fru_picmgext_amc_link_info { + unsigned char linkInfo[3]; +}; //__attribute__ ((packed)); + +#endif + +struct fru_picmgext_amc_link_desc_core { +#ifndef WORDS_BIGENDIAN + unsigned int designator:12; + unsigned int type:8; + unsigned int ext:4; + unsigned int grouping:8; +#else + unsigned int grouping:8; + unsigned int ext:4; + unsigned int type:8; + unsigned int designator:12; +#endif +}; //__attribute__ ((packed)); + +struct fru_picmgext_amc_link_desc_extra { +#ifndef WORDS_BIGENDIAN + unsigned char asymetricMatch:2; + unsigned char reserved:6; +#else + unsigned char reserved:6; + unsigned char asymetricMatch:2; +#endif +}; //__attribute__ ((packed)); + + +struct fru_picmgext_amc_link_desc { +#ifndef WORDS_BIGENDIAN + struct fru_picmgext_amc_link_desc_core core;/* lsb */ + struct fru_picmgext_amc_link_desc_extra extra; +#else + struct fru_picmgext_amc_link_desc_extra extra; + struct fru_picmgext_amc_link_desc_core core;/* lsb */ +#endif +}; //__attribute__ ((packed)); + + +#define FRU_PICMGEXT_OEM_SWFW 0x03 +#define OEM_SWFW_NBLOCK_OFFSET 0x05 +#define OEM_SWFW_FIELD_START_OFFSET 0x06 + + +struct fru_picmgext_chn_desc { +#ifndef WORDS_BIGENDIAN + unsigned char remote_slot:8; + unsigned char remote_chn:5; + unsigned char local_chn:5; + unsigned char:6; +#else + unsigned char:6; + unsigned char local_chn:5; + unsigned char remote_chn:5; + unsigned char remote_slot:8; +#endif +}; //__attribute__ ((packed)); + +struct fru_picmgext_slot_desc { + unsigned char chan_type; + unsigned char slot_addr; + unsigned char chn_count; +}; //__attribute__ ((packed)); + +#define FRU_PICMGEXT_DESIGN_IF_BASE 0x00 +#define FRU_PICMGEXT_DESIGN_IF_FABRIC 0x01 +#define FRU_PICMGEXT_DESIGN_IF_UPDATE_CHANNEL 0x02 +#define FRU_PICMGEXT_DESIGN_IF_RESERVED 0x03 + +struct fru_picmgext_carrier_activation_record { + unsigned short max_internal_curr; + unsigned char allowance_for_readiness; + unsigned char module_activation_record_count; +}; //__attribute__ ((packed)); + +struct fru_picmgext_activation_record { + unsigned char ibmb_addr; + unsigned char max_module_curr; + unsigned char reserved; +}; //__attribute__ ((packed)); + +struct fru_picmgext_carrier_p2p_record { + unsigned char resource_id; + unsigned char p2p_count; +}; //__attribute__ ((packed)); + +struct fru_picmgext_carrier_p2p_descriptor { +#ifndef WORDS_BIGENDIAN + unsigned char remote_resource_id; + unsigned short remote_port:5; + unsigned short local_port:5; + unsigned short reserved:6; +#else + unsigned short reserved:6; + unsigned short local_port:5; + unsigned short remote_port:5; + unsigned char remote_resource_id; +#endif +}; //__attribute__ ((packed)); + +struct fru_picmgext_amc_p2p_record { +#ifndef WORDS_BIGENDIAN + unsigned char resource_id :4; + unsigned char /* reserved */ :3; + unsigned char record_type :1; +#else + unsigned char record_type :1; + unsigned char /* reserved */ :3; + unsigned char resource_id :4; +#endif +}; //__attribute__ ((packed)); + +struct fru_picmgext_amc_channel_desc_record { +#ifndef WORDS_BIGENDIAN + unsigned char lane0port :5; + unsigned char lane1port :5; + unsigned char lane2port :5; + unsigned char lane3port :5; + unsigned char /*reserved */ :4; +#else + unsigned char /*reserved */ :4; + unsigned char lane3port :5; + unsigned char lane2port :5; + unsigned char lane1port :5; + unsigned char lane0port :5; +#endif +}; //__attribute__ ((packed)); + +struct fru_picmgext_amc_link_desc_record { + #define FRU_PICMGEXT_AMC_LINK_TYPE_PCIE 0x02 + #define FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS1 0x03 + #define FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS2 0x04 + #define FRU_PICMGEXT_AMC_LINK_TYPE_ETHERNET 0x05 + #define FRU_PICMGEXT_AMC_LINK_TYPE_RAPIDIO 0x06 + #define FRU_PICMGEXT_AMC_LINK_TYPE_STORAGE 0x07 + + #define AMC_LINK_TYPE_EXT_PCIE_G1_NSSC 0x00 + #define AMC_LINK_TYPE_EXT_PCIE_G1_SSC 0x01 + #define AMC_LINK_TYPE_EXT_PCIE_G2_NSSC 0x02 + #define AMC_LINK_TYPE_EXT_PCIE_G2_SSC 0x03 + + #define AMC_LINK_TYPE_EXT_ETH_1000_BX 0x00 + #define AMC_LINK_TYPE_EXT_ETH_10G_XAUI 0x01 + + #define AMC_LINK_TYPE_EXT_STORAGE_FC 0x00 + #define AMC_LINK_TYPE_EXT_STORAGE_SATA 0x01 + #define AMC_LINK_TYPE_EXT_STORAGE_SAS 0x02 +#ifndef WORDS_BIGENDIAN + unsigned short channel_id :8; + unsigned short port_flag_0 :1; + unsigned short port_flag_1 :1; + unsigned short port_flag_2 :1; + unsigned short port_flag_3 :1; + unsigned short type :8; + unsigned short type_ext :4; + unsigned short group_id :8; + unsigned char asym_match :2; + unsigned char /* reserved */ :6; +#else + unsigned char /* reserved */ :6; + unsigned char asym_match :2; + unsigned short group_id :8; + unsigned short type_ext :4; + unsigned short type :8; + unsigned short port_flag_3 :1; + unsigned short port_flag_2 :1; + unsigned short port_flag_1 :1; + unsigned short port_flag_0 :1; + unsigned short channel_id :8; +#endif +}; //__attribute__ ((packed)); +#pragma pack() + +/* FRU Board manufacturing date */ +static const uint64_t secs_from_1970_1996 = 820450800; + +#ifdef NOT_USED +static const char * combined_voltage_desc[] = { //__attribute__((unused)) +"12 V", "-12 V", "5 V", "3.3 V"}; +static const char * chassis_type_desc[] = { //__attribute__((unused)) + "Unspecified", "Other", "Unknown", + "Desktop", "Low Profile Desktop", "Pizza Box", + "Mini Tower", "Tower", + "Portable", "LapTop", "Notebook", "Hand Held", + "Docking Station", "All in One", "Sub Notebook", + "Space-saving", "Lunch Box", "Main Server Chassis", + "Expansion Chassis", "SubChassis", "Bus Expansion Chassis", + "Peripheral Chassis", "RAID Chassis", "Rack Mount Chassis"}; +#endif + +#endif /* OEM_FRU_H */ + +#endif /* IPMI_EKANALYZER_H */ diff --git a/util/ievents.c b/util/ievents.c new file mode 100644 index 0000000..72c0b24 --- /dev/null +++ b/util/ievents.c @@ -0,0 +1,2505 @@ +/* + * ievents.c + * + * This file decodes the IPMI event into a readable string. + * It is used by showsel.c and getevent.c. + * + * ievents.c compile flags: + * METACOMMAND - defined if building for ipmiutil meta-command binary + * ALONE - defined if building for ievents standalone binary + * else it could be compiled with libipmiutil.a + * LINUX, BSD, WIN32, DOS - defined for that OS + * + * Author: Andy Cress arcress at users.sourceforge.net + * + * Copyright (c) 2009 Kontron America, Inc. + * Copyright (c) 2006 Intel Corporation. + * + * 05/26/05 Andy Cress - created from showsel.c (see there for history) + * 06/20/05 Andy Cress - changed PowerSupply present/not to Inserted/Removed + * 08/01/05 Andy Cress - added more Power Unit & Battery descriptions + * 03/02/06 Andy Cress - more decoding for Power Unit 0b vs. 6f + * 04/11/07 Andy Cress - added events -p decoding for PET data + * 10/03/07 Andy Cress - added file_grep for -p in Windows + * 03/03/08 Andy Cress - added -f to interpret raw SEL file + */ +/*M* +Copyright (c) 2009 Kontron America, Inc. +Copyright (c) 2006, Intel Corporation +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions 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. + c.. Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ +#include +#ifdef WIN32 +#include +#include +#include +#elif defined(DOS) +#include +#include +#include +#else +#include +#include +#include +#include +#include +#include +#endif +#include + +#include "ipmicmd.h" +#include "ievents.h" + +#define SELprintf printf +#define SMS_SA 0x41 +#define SMI_SA 0x21 +static char *progver = "2.93"; +static char *progname = "ievents"; +static char fsensdesc = 0; /* 1= get extended sensor descriptions*/ +static char fcanonical = 0; /* 1= show canonical, delimited output*/ +static char fgetdevid = 0; /* 1= get device ID */ +static char fnewevt = 0; /* 1= generate New event */ +static char futc = 0; /* 1= raw UTC time */ +static uchar thr_sa = SMS_SA; /* 0x41 (Sms) used by ipmitool PlarformEvents */ +static void *sdrcache = NULL; +static int pet_guid = 8; /*bytes in the input data for the GUID*/ +static char bcomma = ','; +static char bdelim = BDELIM; /* '|' */ +#ifdef ALONE + char fdebug = 0; /* 1= debug output, standalone*/ +static char fsm_debug = 0; +#else +extern char fdebug; /* 1= debug output, from ipmicmd.c*/ +extern char fsm_debug; /*mem_if.c*/ +#endif +#define SDR_SZ 80 + +#pragma pack(1) +typedef struct +{ + ushort record_id; + uchar record_type; + uint timestamp; + ushort generator_id; /*slave_addr/channel*/ + uchar evm_rev; //event message revision + uchar sensor_type; + uchar sensor_number; + uchar event_trigger; + uchar event_data1; + uchar event_data2; + uchar event_data3; +} SEL_RECORD; +#pragma pack() + +#ifdef WIN32 + static char sensfil[80] = "sensor_out.txt"; + static char sensfil2[80] = "%ipmiutildir%\\sensor_out.txt"; + // static char outfil[64] = "stype.tmp"; +#else + static char sensfil[80] = "/var/lib/ipmiutil/sensor_out.txt"; + static char sensfil2[80] = "/usr/share/ipmiutil/sensor_out.txt"; + // static char outfil[] = "/tmp/stype.tmp"; +#endif + static char rawfil[80] = ""; + +char *evt_hdr = "RecId Date/Time_______ SEV Src_ Evt_Type___ Sens# Evt_detail - Trig [Evt_data]\n"; +char *evt_hdr2 = "RecId | Date/Time | SEV | Src | Evt_Type | Sensor | Evt_detail \n"; +#ifdef MOVED +/* moved SEV_* to ipmicmd.h */ +#define SEV_INFO 0 +#define SEV_MIN 1 +#define SEV_MAJ 2 +#define SEV_CRIT 3 +#endif +#define NSEV 4 +char *sev_str[NSEV] = { + /*0*/ "INF", + /*1*/ "MIN", + /*2*/ "MAJ", + /*3*/ "CRT" }; + +/* sensor_types: See IPMI 1.5 Table 36-3, IPMI 2.0 Table 42-3 */ +#define NSTYPES 0x2F +static const char *sensor_types[NSTYPES] = { +/* 00h */ "reserved", +/* 01h */ "Temperature", +/* 02h */ "Voltage", +/* 03h */ "Current", +/* 04h */ "Fan", +/* 05h */ "Platform Security", +/* 06h */ "Security Violation", +/* 07h */ "Processor", +/* 08h */ "Power Supply", +/* 09h */ "Power Unit", +/* 0Ah */ "Cooling Device", +/* 0Bh */ "FRU Sensor", +/* 0Ch */ "Memory", +/* 0Dh */ "Drive Slot", +/* 0Eh */ "POST Memory Resize", +/* 0Fh */ "System Firmware", /*incl POST code errors*/ +/* 10h */ "Event Log", /*SEL Disabled or Cleared */ +/* 11h */ "Watchdog_1", +/* 12h */ "System Event", /* offset 0,1,2 */ +/* 13h */ "Critical Interrupt", /* offset 0,1,2 */ +/* 14h */ "Button", /* offset 0,1,2 */ +/* 15h */ "Board", +/* 16h */ "Microcontroller", +/* 17h */ "Add-in Card", +/* 18h */ "Chassis", +/* 19h */ "Chip Set", +/* 1Ah */ "Other FRU", +/* 1Bh */ "Cable/Interconnect", +/* 1Ch */ "Terminator", +/* 1Dh */ "System Boot Initiated", +/* 1Eh */ "Boot Error", +/* 1Fh */ "OS Boot", +/* 20h */ "OS Critical Stop", +/* 21h */ "Slot/Connector", +/* 22h */ "ACPI Power State", +/* 23h */ "Watchdog_2", +/* 24h */ "Platform Alert", +/* 25h */ "Entity Presence", +/* 26h */ "Monitor ASIC", +/* 27h */ "LAN", +/* 28h */ "Management Subsystem Health", +/* 29h */ "Battery", +/* 2Ah */ "SessionAudit", +/* 2Bh */ "Version Change", +/* 2Ch */ "FRU State", +/* 2Dh */ "SMI Timeout", /* 0xF3 == OEM SMI Timeout */ +/* 2Eh */ "ME" /* 0xDC == ME Node Manager */ +}; + +#define NFWERRS 15 +static struct { /* See Table 36-3, type 0Fh, offset 00h */ + int code; char *msg; + } fwerrs[NFWERRS] = { + { 0x00, "Unspecified"}, + { 0x01, "No system memory"}, + { 0x02, "No usable memory"}, + { 0x03, "Unrecovered Hard Disk"}, + { 0x04, "Unrecovered System Board"}, + { 0x05, "Unrecovered Diskette"}, + { 0x06, "Unrecovered Hard Disk Ctlr"}, + { 0x07, "Unrecovered PS2 USB"}, + { 0x08, "Boot media not found"}, + { 0x09, "Unrecovered video controller"}, + { 0x0A, "No video device"}, + { 0x0B, "Firmware ROM corruption"}, + { 0x0C, "CPU voltage mismatch"}, + { 0x0D, "CPU speed mismatch"}, + { 0x0E, "Reserved" } +}; + +#define NFWSTAT 27 +static struct { /* See Table 36-3, type 0Fh, offset 01h & 02h */ + int code; char *msg; + } fwstat[NFWSTAT] = { + { 0x00, "Unspecified"}, + { 0x01, "Memory init"}, + { 0x02, "Hard disk init"}, + { 0x03, "Secondary processor"}, + { 0x04, "User authentication"}, + { 0x05, "User-init sys setup"}, + { 0x06, "USB configuration"}, + { 0x07, "PCI configuration"}, + { 0x08, "Option ROM init"}, + { 0x09, "Video init"}, + { 0x0a, "Cache init"}, + { 0x0b, "SM Bus init"}, + { 0x0c, "Keyboard init"}, + { 0x0d, "Mgt controller"}, + { 0x0e, "Docking attach"}, + { 0x0f, "Enabling docking"}, + { 0x10, "Docking eject"}, + { 0x11, "Disabling docking"}, + { 0x12, "OS wake-up"}, + { 0x13, "Starting OS boot"}, + { 0x14, "Baseboard init"}, + { 0x15, "reserved"}, + { 0x16, "Floppy init"}, + { 0x17, "Keyboard test"}, + { 0x18, "Mouse test"}, + { 0x19, "Primary processor"}, + { 0x1A, "Reserved"} +}; + +#define NGDESC 12 +static struct { + ushort g_id; + const char desc[8]; +} gen_desc[NGDESC] = { /*empirical, format defined in IPMI 1.5 Table 23-5 */ + { 0x0000, "IPMB"}, + { 0x0001, "EFI "}, + { 0x0003, "BIOS"}, /* BIOS POST */ + { BMC_SA, "BMC "}, /* 0x0020==BMC_SA*/ + { SMI_SA, "SMI "}, /* 0x0021==SMI_SA, platform events */ + { 0x0028, "CHAS"}, /* Chassis Bridge Controller */ + { 0x0031, "mSMI"}, /* BIOS SMI/POST errors on miniBMC or ia64 */ + { 0x0033, "Bios"}, /* BIOS SMI (runtime), usually for memory errors */ + { SMS_SA, "Sms "}, /* 0x0041==SmsOs for MS Win2008 Boot, ipmitool event */ + { 0x002C, "ME "}, /* ME Node Manager for S5500 */ + { 0x602C, "ME "}, /* ME Node Manager for S5500/i7 bus=0x6, sa=0x2C */ + { HSC_SA, "HSC "} /* 0x00C0==HSC_SA for SAF-TE Hot-Swap Controller*/ +}; + +#define NCRITS 10 +char * crit_int_str[NCRITS] = { /* Critical Interrupt descriptions */ + /*00*/ "FP NMI ", /* Front Panel NMI */ + /*01*/ "Bus Timout", + /*02*/ "IOch NMI ", /* IO channel check NMI */ + /*03*/ "Soft NMI ", + /*04*/ "PCI PERR ", + /*05*/ "PCI SERR ", + /*06*/ "EISA Timout", + /*07*/ "Bus Warn ", /* Bus Correctable Error */ + /*08*/ "Bus Error", /* Bus Uncorrectable Error */ + /*09*/ "Fatal NMI" }; + +#define NBOOTI 8 +char * boot_init_str[NBOOTI] = { /* System Boot Initiated */ + /*00*/ "Power Up ", + /*01*/ "Hard Reset", + /*02*/ "Warm Reset", + /*03*/ "PXE Boot ", + /*04*/ "Diag Boot ", + /*05*/ "SW Hard Reset", + /*06*/ "SW Warm Reset", + /*07*/ "RestartCause" }; + +#define NOSBOOT 8 +char * osboot_str[NOSBOOT] = { /* OS Boot */ + /*00*/ "A: boot completed", + /*01*/ "C: boot completed", + /*02*/ "PXE boot completed", + /*03*/ "Diag boot completed", + /*04*/ "CDROM boot completed", + /*05*/ "ROM boot completed", + /*06*/ "Other boot completed" }; + +#define NSLOTC 9 +char * slot_str[NSLOTC] = { /* Slot/Connector descriptions */ + /*00*/ "Fault ", + /*01*/ "Identify", + /*02*/ "Inserted", + /*03*/ "InsReady", + /*04*/ "RemReady", + /*05*/ "PowerOff", + /*06*/ "RemRequest", + /*07*/ "Interlock", + /*08*/ "Disabled" }; + +#define NBATT 3 +char * batt_str[NBATT] = { /* Battery assert descriptions */ + /*00*/ "Low", + /*01*/ "Failed", + /*02*/ "Present" }; +char * batt_clr[NBATT] = { /* Battery deassert descriptions */ + /*00*/ "Low OK", + /*01*/ "Failed OK", + /*02*/ "Absent" }; + +#define N_NMH 6 +char * nmh_str[N_NMH] = { /* ME Node Manager Health (73) descriptions */ + /*10*/ "Policy Misconfig", + /*11*/ "Power Sensor Err", + /*12*/ "Inlet Temp Sensor Err", + /*13*/ "Host Comm Err", + /*14*/ "RTC Sync Err" , + /*15*/ "Plat Shutdown" }; + +#define N_NMFW 6 +char * nmfw_str[N_NMFW] = { /* ME Firmware Health (75) descriptions */ + /*00*/ "Forced GPIO Recov", + /*01*/ "Image Exec Fail", + /*02*/ "Flash Erase Error", + /*03*/ "Flash Corrupt" , + /*04*/ "Internal Watchdog Timeout", // FW Watchdog Timeout, need to flash ME + /*05*/ "BMC Comm Error" }; + +#define N_NM 4 +char * nm_str[N_NM] = { /* Node Manager descriptions */ + /*72*/ "NM Exception", /*or NM Alert Threshold*/ + /*73*/ "NM Health", + /*74*/ "NM Capabilities", + /*75*/ "FW Health" }; + +#define NPROC 11 +char * proc_str[NPROC] = { /* Processor descriptions */ + /*00*/ "IERR", + /*01*/ "Thermal Trip", + /*02*/ "FRB1/BIST failure", + /*03*/ "FRB2 timeout", + /*04*/ "FRB3 Proc error", + /*05*/ "Config error", + /*06*/ "SMBIOS CPU error", + /*07*/ "Present", + /*08*/ "Disabled", + /*09*/ "Terminator", + /*0A*/ "Throttled" }; + +#define NACPIP 15 +char * acpip_str[NACPIP] = { /* ACPI Power State descriptions */ + /*00*/ "S0/G0 Working", + /*01*/ "S1 sleeping, proc/hw context maintained", + /*02*/ "S2 sleeping, proc context lost", + /*03*/ "S3 sleeping, proc/hw context lost, mem ok", /*42 chars*/ + /*04*/ "S4 non-volatile sleep/suspend", + /*05*/ "S5/G2 soft-off", + /*06*/ "S4/S5 soft-off, no specific state", + /*07*/ "G3/Mechanical off", + /*08*/ "Sleeping in an S1/S2/S3 state", + /*09*/ "G1 sleeping", + /*0A*/ "S5 entered by override", + /*0B*/ "Legacy ON state", + /*0C*/ "Legacy OFF state", + /*0D*/ "Unknown", + /*0E*/ "Unknown" }; + +#define NAUDIT 2 +char * audit_str[NAUDIT] = { /* Session Audit descriptions */ + /*00*/ "Activated", + /*01*/ "Deactivated"}; + +#define N_AVAIL 9 +char * avail_str[N_AVAIL] = { /* Discrete Availability, evtype 0x0A */ + /*00*/ "chg to Running", + /*01*/ "chg to In Test", + /*02*/ "chg to Power Off", + /*03*/ "chg to On Line", + /*04*/ "chg to Off Line", + /*05*/ "chg to Off Duty", + /*06*/ "chg to Degraded", + /*07*/ "chg to Power Save", + /*08*/ "Install Error"}; + + +#define NSDESC 87 +struct { + ushort genid; /* generator id: BIOS, BMC, etc. (slave_addr/channel) */ + uchar s_typ; /* 1=temp,2=voltage,4=fan,... */ + uchar s_num; + uchar evtrg; /* event trigger/type, see IPMI 1.5 table 36.1 & 36.2 */ + uchar data1; + uchar data2; + uchar data3; + uchar sev; /* 0=SEV_INFO, 1=SEV_MIN, 2=SEV_MAJ, 3=SEV_CRIT */ + const char desc[40]; +} sens_desc[NSDESC] = { /* if value is 0xff, matches any value */ +{0xffff,0x05, 0xff, 0x6f, 0x40,0xff,0xff, 1,"Chassis Intrusion"}, /*chassis*/ +{0xffff,0x05, 0xff, 0xef, 0x40,0xff,0xff, 0,"Chassis OK"}, /*chassis*/ +{0xffff,0x05, 0xff, 0x6f, 0x44,0xff,0xff, 1,"LAN unplugged"}, /*chassis*/ +{0xffff,0x05, 0xff, 0xef, 0x44,0xff,0xff, 0,"LAN restored "}, /*chassis*/ +{0xffff,0x06, 0xff, 0xff, 0x45,0xff,0xff, 0,"Password"}, /*security*/ +{0xffff,0x07, 0xff, 0xff, 0x41,0xff,0xff, 3,"Thermal trip"}, /*processor*/ +{0xffff,0x08, 0xff, 0x6f, 0x40,0xff,0xff, 0,"Inserted"}, /*PowerSupply*/ +{0xffff,0x08, 0xff, 0x6f, 0x41,0xff,0xff, 2,"Failure detected"},/*PowerSupply*/ +{0xffff,0x08, 0xff, 0x6f, 0x42,0xff,0xff, 1,"Predictive failure"}, +{0xffff,0x08, 0xff, 0x6f, 0x43,0xff,0xff, 0,"AC Lost"}, +{0xffff,0x08, 0xff, 0x6f, 0x46,0xff,0xff, 2,"Config Error"}, +{0xffff,0x08, 0xff, 0xef, 0x40,0xff,0xff, 1,"Removed"}, /*PowerSupply*/ +{0xffff,0x08, 0xff, 0xef, 0x41,0xff,0xff, 0,"is OK "}, /*PowerSupply*/ +{0xffff,0x08, 0xff, 0xef, 0x42,0xff,0xff, 0,"Predictive OK"}, +{0xffff,0x08, 0xff, 0xef, 0x43,0xff,0xff, 0,"AC Regained"}, /*PowerSupply*/ +{0xffff,0x08, 0xff, 0xef, 0x46,0xff,0xff, 0,"Config OK now"}, +{0xffff,0x0c, 0xff, 0xff, 0x00,0xff,0xff, 1,"Correctable ECC"}, /*memory*/ +{0xffff,0x0f, 0x06, 0xff, 0xff,0xff,0xff, 2,"POST Code"}, +{0xffff,0x10, 0x09, 0xff, 0x42,0x0f,0xff, 0,"Log Cleared"}, +{0xffff,0x10, 0xff, 0xff, 0x02,0xff,0xff, 0,"Log Cleared"}, +{0xffff,0x10, 0xff, 0xff, 0xc0,0x03,0xff, 1,"ECC Memory Errors"}, + /* Often see these 3 Boot records with reboot: + * 0003 12 83 6f 05 00 ff = System/SEL ClockSync_1 (start of POST) + * 0003 12 83 6f 05 80 ff = System/SEL ClockSync_2 (end of POST) + * 0003 12 83 6f 01 ff ff = OEM System Boot Event (after POST, loader), or + * 0003 12 83 6f 41 0f ff = OEM System Boot Event (same w 01 & 41) + * can be either 0003 (BIOS) or 0001 (EFI) + */ +{0xffff,0x12, 0xfe, 0xff, 0xc5,0x00,0xff, 0,"Boot: ClockSync_1"}, +{0xffff,0x12, 0xfe, 0xff, 0xc5,0x80,0xff, 0,"Boot: ClockSync_2"}, +{0xffff,0x12, 0x83, 0xff, 0x05,0x00,0xff, 0,"Boot: ClockSync_1"}, +{0xffff,0x12, 0x83, 0xff, 0x05,0x80,0xff, 0,"Boot: ClockSync_2"}, +{0xffff,0x12, 0x83, 0xff, 0x01,0xff,0xff, 0,"OEM System Booted"}, +{0x0001,0x12, 0x08, 0xff, 0x01,0xff,0xff, 0,"OEM System Booted"}, /*ia64*/ +{0xffff,0x12, 0x01, 0x6f, 0x01,0xff,0xff, 0,"OEM System Booted"}, /*S5000*/ +{0xffff,0x12, 0x38, 0x6f, 0x00,0xff,0xff, 0,"OEM System Booted"}, /*KTC*/ +{0xffff,0x12, 0x38, 0xef, 0x00,0xff,0xff, 0,"OEM System Booted"}, /*KTC*/ +{0x0031,0x12, 0x00, 0x6f, 0xc3,0xff,0xff, 0,"PEF Action"}, /*ia64*/ +{BMC_SA,0x12, 0x83, 0x6f, 0x80,0xff,0xff, 0,"System Reconfigured"}, /*BMC*/ +{BMC_SA,0x12, 0x83, 0x0b, 0x80,0xff,0xff, 0,"System Reconfigured"}, /*BMC*/ +{BMC_SA,0x12, 0x0b, 0x6f, 0x80,0xff,0xff, 0,"System Reconfigured"}, /*BMC*/ +{BMC_SA,0x12, 0x83, 0xff, 0x41,0xff,0xff, 0,"OEM System Boot"}, /*BMC*/ +{BMC_SA,0x12, 0x83, 0x6f, 0x42,0xff,0xff, 2,"System HW failure"}, /*BMC*/ +{BMC_SA,0x12, 0x83, 0x6f, 0x04,0xff,0xff, 0,"PEF Action"}, /*BMC*/ +{HSC_SA,0x0d, 0xff, 0x08, 0x00,0xff,0xff, 1,"Device Removed"}, /*HSC*/ +{HSC_SA,0x0d, 0xff, 0x08, 0x01,0xff,0xff, 0,"Device Inserted"}, /*HSC*/ +{0xffff,0x0d, 0xff, 0x6f, 0x00,0xff,0xff, 0,"Drive present"}, /*Romley BMC*/ +{0xffff,0x0d, 0xff, 0xef, 0x00,0xff,0xff, 0,"Drive removed"}, /*BMC*/ +{0xffff,0x0d, 0xff, 0x6f, 0x01,0xff,0xff, 2,"Drive fault"}, +{0xffff,0x0d, 0xff, 0xef, 0x01,0xff,0xff, 0,"Drive fault OK"}, +{0xffff,0x0d, 0xff, 0x6f, 0x02,0xff,0xff, 1,"Drive predict fail"}, +{0xffff,0x0d, 0xff, 0x6f, 0x07,0xff,0xff, 0,"Rebuild in progress"}, +{0xffff,0x0d, 0xff, 0xef, 0x07,0xff,0xff, 0,"Rebuild complete"}, +{0xffff,0x14, 0xff, 0xff, 0x42,0xff,0xff, 1,"Reset Button pressed"}, +{0xffff,0x14, 0xff, 0xff, 0x40,0xff,0xff, 1,"Power Button pressed"}, +{0xffff,0x14, 0xff, 0xff, 0x01,0xff,0xff, 0,"ID Button pressed"}, +{0xffff,0x23, 0xff, 0xff, 0x40,0xff,0xff, 2,"Expired, no action"},/*watchdog2*/ +{0xffff,0x23, 0xff, 0xff, 0x41,0xff,0xff, 3,"Hard Reset action"}, /*watchdog2*/ +{0xffff,0x23, 0xff, 0xff, 0x42,0xff,0xff, 3,"Power down action"}, /*watchdog2*/ +{0xffff,0x23, 0xff, 0xff, 0x43,0xff,0xff, 3,"Power cycle action"},/*watchdog2*/ +{0xffff,0x23, 0xff, 0xff, 0x48,0xff,0xff, 2,"Timer interrupt"}, /*watchdog2*/ +{0xffff,0xf3, 0xff, 0x83, 0x41,0xff,0xff, 0,"SMI de-asserted"}, +{0xffff,0xf3, 0xff, 0x03, 0x41,0xff,0xff, 3,"SMI asserted"}, +{0xffff,0x20, 0x00, 0xff, 0xff,0xff,0xff, 3,"OS Kernel Panic"}, +{0xffff,0x01, 0xff, 0x03, 0x01,0xff,0xff, 2,"Temp Asserted"}, /*Discrete temp*/ +{0xffff,0x01, 0xff, 0x83, 0x01,0xff,0xff, 0,"Temp OK"}, /*Discrete ok*/ +{0xffff,0x01, 0xff, 0x05, 0x01,0xff,0xff, 2,"Temp Asserted"}, /*CPU Hot */ +{0xffff,0x01, 0xff, 0x85, 0x01,0xff,0xff, 0,"Temp OK"}, /*CPU Hot ok*/ +{0xffff,0x01, 0xff, 0x07, 0x01,0xff,0xff, 2,"Temp Asserted"}, /*Discrete temp*/ +{0xffff,0x01, 0xff, 0x87, 0x01,0xff,0xff, 0,"Temp OK"}, /*Discrete ok*/ + /*Thresholds apply to sensor types 1=temp, 2=voltage, 3=current, 4=fan*/ + /*Note that last 2 bytes usu show actual & threshold values*/ + /*evtrg: 0x01=thresh, 0x81=restored/deasserted */ +{0xffff,0xff, 0xff, 0x01, 0x50,0xff,0xff, 1,"Lo Noncrit thresh"}, +{0xffff,0xff, 0xff, 0x01, 0x51,0xff,0xff, 0,"Lo NoncritH OK now"}, +{0xffff,0xff, 0xff, 0x01, 0x52,0xff,0xff, 2,"Lo Crit thresh"}, +{0xffff,0xff, 0xff, 0x01, 0x53,0xff,0xff, 0,"Lo CritHi OK now"}, +{0xffff,0xff, 0xff, 0x01, 0x54,0xff,0xff, 3,"Lo Unrec thresh"}, +{0xffff,0xff, 0xff, 0x01, 0x55,0xff,0xff, 0,"Lo UnrecH OK now"}, +{0xffff,0xff, 0xff, 0x01, 0x56,0xff,0xff, 0,"Hi NoncritL OK now"}, +{0xffff,0xff, 0xff, 0x01, 0x57,0xff,0xff, 1,"Hi Noncrit thresh"}, +{0xffff,0xff, 0xff, 0x01, 0x58,0xff,0xff, 0,"Hi CritLo OK now"}, +{0xffff,0xff, 0xff, 0x01, 0x59,0xff,0xff, 2,"Hi Crit thresh"}, +{0xffff,0xff, 0xff, 0x01, 0x5A,0xff,0xff, 0,"Hi UnrecL OK now"}, +{0xffff,0xff, 0xff, 0x01, 0x5B,0xff,0xff, 3,"Hi Unrec thresh"}, +{0xffff,0xff, 0xff, 0x81, 0x50,0xff,0xff, 0,"LoN thresh OK now"}, +{0xffff,0xff, 0xff, 0x81, 0x51,0xff,0xff, 1,"LoNoncrit thresh"}, +{0xffff,0xff, 0xff, 0x81, 0x52,0xff,0xff, 0,"LoC thresh OK now"}, +{0xffff,0xff, 0xff, 0x81, 0x53,0xff,0xff, 2,"LoCritHi thresh"}, +{0xffff,0xff, 0xff, 0x81, 0x54,0xff,0xff, 0,"LoU thresh OK now"}, +{0xffff,0xff, 0xff, 0x81, 0x55,0xff,0xff, 3,"LoUnrecH thresh"}, +{0xffff,0xff, 0xff, 0x81, 0x56,0xff,0xff, 1,"HiNoncrit thresh"}, +{0xffff,0xff, 0xff, 0x81, 0x57,0xff,0xff, 0,"HiN thresh OK now"}, +{0xffff,0xff, 0xff, 0x81, 0x58,0xff,0xff, 2,"HiCritLo thresh"}, +{0xffff,0xff, 0xff, 0x81, 0x59,0xff,0xff, 0,"HiC thresh OK now"}, +{0xffff,0xff, 0xff, 0x81, 0x5A,0xff,0xff, 3,"HiURecLo thresh"}, +{0xffff,0xff, 0xff, 0x81, 0x5B,0xff,0xff, 0,"HiU thresh OK now"} +}; + +#define NENTID 53 +static struct { char * str; uchar styp; } entitymap[NENTID] = { +/* 00 */ { "unspecified", 0x00 }, +/* 01 */ { "other", 0x00 }, +/* 02 */ { "unknown", 0x00 }, +/* 03 */ { "Processor", 0x07 }, +/* 04 */ { "Disk", 0x00 }, +/* 05 */ { "Peripheral bay", 0x0D }, +/* 06 */ { "Management module", 0x00 }, +/* 07 */ { "System board", 0x00 }, +/* 08 */ { "Memory module", 0x00 }, +/* 09 */ { "Processor module", 0x00 }, +/* 10 */ { "Power supply", 0x08 }, +/* 11 */ { "Add-in card", 0x00 }, +/* 12 */ { "Front panel bd", 0x00 }, +/* 13 */ { "Back panel board", 0x00 }, +/* 14 */ { "Power system bd", 0x00 }, +/* 15 */ { "Drive backplane", 0x00 }, +/* 16 */ { "Expansion board", 0x00 }, +/* 17 */ { "Other system board", 0x15 }, +/* 18 */ { "Processor board", 0x15 }, +/* 19 */ { "Power unit", 0x09 }, +/* 20 */ { "Power module", 0x08 }, +/* 21 */ { "Power distr board", 0x09 }, +/* 22 */ { "Chassis back panel bd", 0x00 }, +/* 23 */ { "System Chassis", 0x00 }, +/* 24 */ { "Sub-chassis", 0x00 }, +/* 25 */ { "Other chassis board", 0x15 }, +/* 26 */ { "Disk Drive Bay", 0x0D }, +/* 27 */ { "Peripheral Bay", 0x00 }, +/* 28 */ { "Device Bay", 0x00 }, +/* 29 */ { "Fan", 0x04 }, +/* 30 */ { "Cooling unit", 0x0A }, +/* 31 */ { "Cable/interconnect", 0x1B }, +/* 32 */ { "Memory device ", 0x0C }, +/* 33 */ { "System Mgt Software", 0x28 }, +/* 34 */ { "BIOS", 0x00 }, +/* 35 */ { "Operating System", 0x1F }, +/* 36 */ { "System bus", 0x00 }, +/* 37 */ { "Group", 0x00 }, +/* 38 */ { "Remote Mgt Comm Device", 0x00 }, +/* 39 */ { "External Environment", 0x00 }, +/* 40 */ { "battery", 0x29 }, +/* 41 */ { "Processing blade", 0x00 }, +/* 43 */ { "Processor/memory module", 0x0C }, +/* 44 */ { "I/O module", 0x15 }, +/* 45 */ { "Processor/IO module", 0x00 }, +/* 46 */ { "Mgt Controller Firmware", 0x0F }, +/* 47 */ { "IPMI Channel", 0x00 }, +/* 48 */ { "PCI Bus", 0x00 }, +/* 49 */ { "PCI Express Bus", 0x00 }, +/* 50 */ { "SCSI Bus", 0x00 }, +/* 51 */ { "SATA/SAS bus", 0x00, }, +/* 52 */ { "Processor FSB", 0x00 } +}; + +char *decode_entity_id(int id) +{ + char *str = NULL; + if (id < 0) id = 0; + if (id > NENTID) { + if (id >= 0x90 && id < 0xB0) str = "Chassis-specific"; + else if (id >= 0xB0 && id < 0xD0) str = "Board-specific"; + else if (id >= 0xD0 && id <= 0xFF) str = "OEM-specific"; + else str = "invalid"; + } else str = entitymap[id].str; + return(str); +} + +uchar entity2sensor_type(uchar ent) +{ + uchar stype = 0x12; + uchar b; + if (ent < NENTID) { + b = entitymap[ent].styp; + if (fdebug) printf("entity2sensor_type(%x,%s), stype=%x\n",ent, + entitymap[ent].str,b); + if (b != 0) stype = b; + } + return(stype); +} + + +static char *mem_str(int off) +{ + char *pstr; + switch(off) { + case 0x00: pstr = "Correctable ECC"; break; + case 0x01: pstr = "Uncorrectable ECC"; break; + case 0x02: pstr = "Parity"; break; + case 0x03: pstr = "Memory Scrub Failed"; break; + case 0x04: pstr = "Memory Device Disabled"; break; + case 0x05: pstr = "ECC limit reached" ; break; + case 0x07: pstr = "SMI Link Lane Fail Over"; break; /*Quanta QSSC_S4R*/ + default: pstr = "Other Memory Error"; break; + } + return(pstr); +} + + +#if defined(METACOMMAND) +/* METACOMMAND is defined for ipmiutil meta-command build. */ +/* These can only be external if linked with non-core objects. */ +extern int GetSDR(int recid, int *recnext, uchar *sdr, int szsdr, int *slen); +extern double RawToFloat(uchar raw, uchar *psdr); +extern char *get_unit_type(uchar iunit, uchar ibase, uchar imod, int flg); +extern int find_sdr_by_snum(uchar *psdr,uchar *pcache, uchar snum, uchar sa); +extern int GetSensorType(int snum, uchar *stype, uchar *rtype); +extern char * get_mfg_str(uchar *rgmfg, int *pmfg); /*from ihealth.c*/ +extern int decode_post_intel(int prod, ushort code, char *outbuf,int szbuf); +extern int decode_sel_kontron(uchar *evt, char *obuf,int sz,char fdesc,char fdbg); /*oem_kontron.c*/ +extern int decode_sel_fujitsu(uchar *evt, char *obuf,int sz,char fdesc,char fdbg); /*oem_fujitsu.c*/ +extern int decode_sel_intel(uchar *evt, char *obuf,int sz,char fdesc,char fdbg); /*oem_intel.c*/ +extern int decode_sel_supermicro(uchar *evt, char *obuf,int sz,char fdesc,char fdbg); /*oem_supermicro.c*/ +extern int decode_sel_quanta(uchar *evt, char *obuf,int sz,char fdesc,char fdbg); /*oem_quanta.c*/ +extern int decode_sel_newisys(uchar *evt, char *obuf,int sz,char fdesc,char fdbg); /*oem_newisys.c*/ +extern int decode_sel_dell(uchar *evt, char *obuf,int sz,char fdesc,char fdbg); /*oem_dell.c*/ +extern int decode_mem_intel(int prod, uchar b2, uchar b3, char *desc, int *psz); /*oem_intel.c*/ +extern int decode_mem_supermicro(int prod, uchar b2, uchar b3, char *desc, int *psz); /*oem_intel.c*/ +#else +/* else it could be ALONE or for a libipmiutil.a build */ +static int default_mem_desc(uchar b2, uchar b3, char *desc, int *psz) +{ + int array, dimm, n; + uchar bdata; + if (desc == NULL || psz == NULL) return -1; + if (b3 == 0xff) bdata = b2; /*ff is reserved*/ + else bdata = b3; /* normal case */ + array = (bdata & 0xc0) >> 6; + dimm = bdata & 0x3f; + n = sprintf(desc,"DIMM[%d]",dimm); + *psz = n; + return(0); +} +static int decode_mem_intel(int prod, uchar b2, uchar b3, char *desc, int *psz) +{ return(default_mem_desc(b2,b3,desc,psz)); } +static int decode_mem_supermicro(int prod, uchar b2, uchar b3, char *desc, int *psz) +{ return(default_mem_desc(b2,b3,desc,psz)); } +static char * get_mfg_str(uchar *rgmfg, int *pmfg) +{ /* standalone routine here for minimal set of strings*/ + char *mfgstr; + int mfg; + mfg = rgmfg[0] + (rgmfg[1] << 8) + (rgmfg[2] << 16); + if (pmfg != NULL) *pmfg = mfg; + if (mfg == VENDOR_INTEL) mfgstr = "Intel"; + else if (mfg == VENDOR_MICROSOFT) mfgstr = "Microsoft"; + else if (mfg == VENDOR_KONTRON) mfgstr = "Kontron"; + else if (mfg == VENDOR_SUPERMICROX) mfgstr = "SuperMicro"; + else if (mfg == VENDOR_SUPERMICRO) mfgstr = "SuperMicro"; + else mfgstr = " "; + return (mfgstr); +} +#ifdef SENSORS_OK +extern int GetSDR(int recid, int *recnext, uchar *sdr, int szsdr, int *slen); +extern double RawToFloat(uchar raw, uchar *psdr); +extern char *get_unit_type(uchar iunit, uchar ibase, uchar imod, int flg); +extern int find_sdr_by_snum(uchar *psdr,uchar *pcache, uchar snum, uchar sa); +extern int GetSensorType(int snum, uchar *stype, uchar *rtype); +#else +static int GetSDR(int recid, int *recnext, uchar *sdr, int szsdr, int *slen) +{ return(-1); } +static double RawToFloat(uchar raw, uchar *psdr) +{ return((double)raw); } +static char *get_unit_type(uchar iunit, uchar ibase, uchar imod, int flg) +{ return(""); }; +static int find_sdr_by_snum(uchar *psdr,uchar *pcache, uchar snum, uchar sa) +{ return(-1); } +static int GetSensorType(int snum, uchar *stype, uchar *rtype) +{ return(-1); } +#endif +#endif + +#if defined(ALONE) +/* ALONE is defined for ievents standalone build. */ +/* IPMI Spec says that this is an index into the DIMMs. + * Walking through the SDRs dynamically would be too slow, + * but isel -e has an SDR cache which could be leveraged, + * however not all platforms have DIMM slot SDRs. + * The BIOS references the DIMM Locator descriptors from + * SMBIOS type 17, and the descriptions vary for each baseboard. + * We'll just show the index here by default. + * Do the SMBIOS lookup if not standalone build. */ + +int strlen_(const char *s) { return((int)strlen(s)); } +// char * get_iana_str(int vend) { return(""); } *from subs.c*/ +void set_iana(int vend) { return; } +int get_MemDesc(int array, int idimm, char *desc, int *psz) +{ + /* standalone, so use the default method for the DIMM index */ + return(default_mem_desc(array,idimm,desc,psz)); +} + +void get_mfgid(int *vend, int *prod) +{ + if ((vend == NULL) || (prod == NULL)) return; + *vend = VENDOR_INTEL; /*assume a default of Intel*/ + *prod = 0; +} +char is_remote(void) +{ return(1); /* act as if remote with standalone utility */ } +char * decode_rv(int rv) +{ + static char mystr[30]; + char *pstr; + switch(rv) { + case 0: pstr = "completed successfully"; break; + case ERR_BAD_PARAM: pstr = "invalid parameter"; break; + case ERR_USAGE: pstr = "usage or help requested"; break; + case ERR_FILE_OPEN: pstr = "cannot open file"; break; + case ERR_NOT_FOUND: pstr = "item not found"; break; + default: sprintf(mystr,"error = %d",rv); pstr = mystr; break; + } + return(pstr); +} +void dump_buf(char *tag, uchar *pbuf, int sz, char fshowascii) +{ + uchar line[17]; + uchar a; + int i, j; + char *stag; + FILE *fpdbg1; + + fpdbg1 = stdout; + if (tag == NULL) stag = "dump_buf"; /*safety valve*/ + else stag = tag; + fprintf(fpdbg1,"%s (len=%d): ", stag,sz); + line[0] = 0; line[16] = 0; + j = 0; + if (sz < 0) { fprintf(fpdbg1,"\n"); return; } /*safety valve*/ + for (i = 0; i < sz; i++) { + if (i % 16 == 0) { + line[j] = 0; + j = 0; + fprintf(fpdbg1,"%s\n %04x: ",line,i); + } + if (fshowascii) { + a = pbuf[i]; + if (a < 0x20 || a > 0x7f) a = '.'; + line[j++] = a; + } + fprintf(fpdbg1,"%02x ",pbuf[i]); + } + if (fshowascii) { + if ((j > 0) && (j < 16)) { + /* space over the remaining number of hex bytes */ + for (i = 0; i < (16-j); i++) fprintf(fpdbg1," "); + } + else j = 16; + line[j] = 0; + } + fprintf(fpdbg1,"%s\n",line); + return; +} +int ipmi_cmdraw(uchar cmd, uchar netfn, uchar sa, uchar bus, uchar lun, + uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd) +{ return(-9); } +#else +/* ipmicmd.h has ipmi_cmdraw() */ +extern int get_MemDesc(int array, int dimm, char *desc, int *psz); /*mem_if.c*/ +extern void get_mfgid(int *vend, int *prod); /*from ipmicmd.c*/ +extern char is_remote(void); /*from ipmicmd.c*/ +extern char * decode_rv(int rv); /*from ipmilan.c*/ +extern void dump_buf(char *tag, uchar *pbuf, int sz, char fshowascii); +#endif + +int new_event(uchar *buf, int len) +{ + int rlen, rv; + uchar idata[8]; + uchar rdata[4]; + uchar cc; + /* + Platform Event Message command, inputs: + offset + 0 = GeneratorID, 0x20 for BMC, 0x21 for SMI/kernel, 0x33 for BIOS + 1 = EVM Rev, 3=IPMI10, 4=IPMI15 + 2 = Sensor Type + 3 = Sensor Number + 4 = Event Type (0x6f = sensor specific) + 5 = data1 + 6 = data2 + 7 = data3 + */ + idata[0] = buf[0]; /*GenID on input is two bytes, but one byte here*/ + idata[1] = buf[2]; + idata[2] = buf[3]; + idata[3] = buf[4]; + idata[4] = buf[5]; + idata[5] = buf[6]; + idata[6] = buf[7]; + idata[7] = buf[8]; + rlen = sizeof(rdata); + rv = ipmi_cmdraw(0x02, NETFN_SEVT, BMC_SA, PUBLIC_BUS, BMC_LUN, + idata,8, rdata,&rlen,&cc, fdebug); + if (fdebug) printf("platform_event: rv = %d, cc = %02x\n",rv,cc); + if ((rv == 0) && (cc != 0)) rv = cc; + return(rv); +} + +char *get_sensor_type_desc(uchar stype) +{ + int i; + static char stype_desc[25]; + char *pstr; + if (stype == 0xF3) i = 0x2D; /*OEM SMI*/ + else if (stype == 0xDC) i = 0x2E; /*NM*/ + else if (stype == SMI_SA) i = BMC_SA; /*SMI -> BMC*/ + else if (stype >= NSTYPES) i = 0; + else i = stype; + if (i == 0) { /* reserved, show the raw sensor_type also */ + if (stype == 0xCF) + strncpy(stype_desc,"OEM Board Reset", sizeof(stype_desc)); + else if (stype >= 0xC0) + sprintf(stype_desc,"OEM(%02x)",stype); + else sprintf(stype_desc,"%s(%02x)",sensor_types[i],stype); /*reserved*/ + pstr = (char *)stype_desc; + } else { + pstr = (char *)sensor_types[i]; + } + return(pstr); +} + +/*------------------------------------------------------------------------ + * get_misc_desc + * Uses the sens_desc array to decode misc entries not otherwise handled. + * Called by decode_sel_entry + *------------------------------------------------------------------------*/ +char * +get_misc_desc(ushort genid, uchar type, uchar num, uchar trig, + uchar data1, uchar data2, uchar data3, uchar *sev) +{ + int i; + char *pstr = NULL; + + /* Use sens_desc array for other misc descriptions */ + data1 &= 0x0f; /*ignore top half of sensor offset for matching */ + for (i = 0; i < NSDESC; i++) { + if ((sens_desc[i].s_typ == 0xff) || + (sens_desc[i].s_typ == type)) { + if (sens_desc[i].s_num != 0xff && + sens_desc[i].s_num != num) + continue; + if (sens_desc[i].genid != 0xffff && + sens_desc[i].genid != genid) + continue; + if (sens_desc[i].evtrg != 0xff && + sens_desc[i].evtrg != trig) + continue; + if (sens_desc[i].data1 != 0xff && + (sens_desc[i].data1 & 0x0f) != (data1 & 0x0f)) + continue; + if (sens_desc[i].data2 != 0xff && + sens_desc[i].data2 != data2) + continue; + if (sens_desc[i].data3 != 0xff && + sens_desc[i].data3 != data3) + continue; + /* have a match, use description */ + pstr = (char *)sens_desc[i].desc; + if (sev != NULL) *sev = sens_desc[i].sev; + break; + } + } /*end for*/ + return(pstr); +} /* end get_misc_desc() */ + +time_t utc2local(time_t t) +{ + struct tm * tm_tmp; + int gt_year,gt_yday,gt_hour,lt_year,lt_yday,lt_hour; + int delta_hour; + time_t lt; + // convert UTC time to local time + // i.e. number of seconds from 1/1/70 0:0:0 1970 GMT + tm_tmp=gmtime(&t); + gt_year=tm_tmp->tm_year; + gt_yday=tm_tmp->tm_yday; + gt_hour=tm_tmp->tm_hour; + tm_tmp=localtime(&t); + lt_year=tm_tmp->tm_year; + lt_yday=tm_tmp->tm_yday; + lt_hour=tm_tmp->tm_hour; + delta_hour=lt_hour - gt_hour; + if ( (lt_year > gt_year) || ((lt_year == gt_year) && (lt_yday > gt_yday)) ) + delta_hour += 24; + if ( (lt_year < gt_year) || ((lt_year == gt_year) && (lt_yday < gt_yday)) ) + delta_hour -= 24; + if (fdebug) printf("utc2local: delta_hour = %d\n",delta_hour); + lt = t + (delta_hour * 60 * 60); + return(lt); +} + +void fmt_time(time_t etime, char *buf, int bufsz) +{ + time_t t; + if (bufsz < 18) printf("fmt_time: buffer size should be >= 18\n"); + if (futc) t = etime; + else t = utc2local(etime); /*assume input time is UTC*/ + strncpy(buf,"00/00/00 00:00:00",bufsz); + strftime(buf,bufsz, "%x %H:%M:%S", gmtime(&t)); /*or "%x %T"*/ + return; +} + +/* + * findmatch + * Finds a matching pattern within a string buffer. + * returns offset of the match if found, or -1 if not found. + */ +int +findmatch(char *buffer, int sbuf, char *pattern, int spattern, char figncase) +{ + int c, i, j, imatch; + + j = 0; + imatch = 0; + for (j = 0; j < sbuf; j++) { + if ((sbuf - j) < spattern && imatch == 0) return(-1); + c = buffer[j]; + if (c == pattern[imatch]) { + imatch++; + } else if ((figncase == 1) && + ((c & 0x5f) == (pattern[imatch] & 0x5f))) { + imatch++; + } else if (pattern[imatch] == '?') { /*wildcard char*/ + imatch++; + } else { + if (imatch > 0) { + if (j > 0) j--; /* try again with the first match char */ + imatch = 0; + } + } + if (imatch == spattern) break; + } + if (imatch == spattern) { + i = (j+1) - imatch; /*buffer[i] is the match */ + return(i); + } else return (-1); /*not found*/ +} /*end findmatch */ + +/* + * file_grep + * Search (grep) for a pattern within a file. + * Inputs: fname = file name to search + * pattn = pattern string to search for + * line = line buffer + * sline = size of line buffer + * bmode = 0 to use last match, + * 1 to use first match, + * 2 to specify starting line number & use first match. + * nret = IN: starting char offset, OUT: num chars read + * Outputs: line = resulting line (stringified) that matches pattn + * nret = resulting line number within file (0-based) + * returns 0 if match, < 0 if error + */ +int file_grep(char *fname, char *pattn, char *line, int sline, + char bmode, int *nret) +{ + FILE *fp; + char buff[1024]; + int ret = ERR_NOT_FOUND; + int i, plen, blen; + int n = 0; + int nstart = 0; + int bufsz; + + if (bmode == 2) nstart = *nret; + bufsz = sizeof(buff); + fp = fopen(fname,"r"); + if (fp == NULL) { + if (fdebug) printf("file_grep: Cannot open %s\n",fname); + ret = ERR_FILE_OPEN; /*cannot open file*/ + } else { + plen = strlen_(pattn); + fseek(fp, nstart, SEEK_SET); + n = nstart; + while (fgets(buff, bufsz, fp) != NULL) + { + blen = strlen_(buff); + /* check for pattern in this line */ + i = findmatch(&buff[0],blen,pattn,plen,0); + if (i >= 0) { + ret = 0; /* found it, success */ + if ((line != NULL) && sline > 1) { + if (blen >= sline) blen = sline - 1; + strncpy(line,buff,blen); + line[blen] = 0; /*stringify*/ + } + if (nret != NULL) *nret = n + i + plen; + if (bmode > 0) break; + /* else keep looking, use last one if multiples */ + } + n += blen; /*number of chars*/ + } /*end while*/ + fclose(fp); + } /*end else file opened*/ + return(ret); +} /*end file_grep*/ + +char *get_sev_str(int val) +{ + if (val >= NSEV) val = SEV_CRIT; + return(sev_str[val]); +} + +/* The htoi() routine is available in subs.c, but ievents.c also + * needs a local copy of it if built with -DALONE. */ +static uchar _htoi(char *inhex) +{ + // char rghex[16] = "0123456789ABCDEF"; + uchar val; + char c; + c = inhex[0] & 0x5f; /* force cap */ + if (c > '9') c += 9; /* c >= 'A' */ + val = (c & 0x0f) << 4; + c = inhex[1] & 0x5f; /* force cap */ + if (c > '9') c += 9; /* c >= 'A' */ + val += (c & 0x0f); + return(val); +} + +/* + * set_sel_opts is used to specify options for showing/decoding SEL events. + * sensdesc : 0 = simple, no sensor descriptions + * 1 = get sensor descriptions from sdr cache + * 2 = get sensor descriptions from sensor file (-s) + * canon : 0 = normal output + * 1 = canonical, delimited output + * sdrs : NULL = no sdr cache, dynamically get sdr cache if sensdesc==1 + * ptr = use this pointer as existing sdr cache if sensdesc==1 + * fdbg : 0 = normal mode + * 1 = debug mode + * futc : 0 = normal mode + * 1 = show raw UTC time + */ +void set_sel_opts(int sensdesc, int canon, void *sdrs, char fdbg, char utc) +{ + fsensdesc = (char)sensdesc; /*get extended sensor descriptions*/ + fcanonical = (char)canon; /*show canonical, delimited output*/ + if (sdrcache == NULL) sdrcache = sdrs; + else printf("Warning: attempted to set_sel_opts(sdrcache) twice\n"); + fdebug = fdbg; + futc = utc; +} + +/* get_sensdesc - get the sensor tag/description from the sensor.out file */ +int get_sensdesc(uchar sa, int snum, char *sensdesc, int *pstyp, int *pidx) +{ + int rv, i, j, len, idx; + char pattn[20]; + char sensline[100]; + int nline = 0; + uchar sa2; + char *sfil; + char *p; + + if (sensdesc == NULL) return ERR_BAD_PARAM; + sensdesc[0] = 0; + if (fdebug) printf("sensdesc(%02x,%02x) with %s\n",sa,snum,sensfil); + sprintf(pattn,"snum %02x",snum); + for (j = 0; j < 3; j++) + { + sfil = sensfil; + /* Use this logic for both Linux and Windows */ + rv = file_grep(sfil,pattn, sensline, sizeof(sensline), 2, &nline); + if (rv != 0) { + if (rv == ERR_FILE_OPEN) { + if (fdebug) fprintf(stdout,"Cannot open file %s\n",sfil); + sfil = sensfil2; + rv = file_grep(sfil, pattn, sensline,sizeof(sensline), 2, &nline); + if (fdebug && rv == ERR_FILE_OPEN) + fprintf(stdout,"Cannot open file %s\n",sfil); + } + if (rv != ERR_FILE_OPEN) { + if (fdebug) printf("Cannot find snum %02x in file %s\n",snum,sfil); + rv = ERR_NOT_FOUND; + } + break; + } + if (rv == 0) { + idx = _htoi(&sensline[2]) + (_htoi(&sensline[0]) << 8); + sa2 = _htoi(&sensline[20]); + if (fdebug) + printf("sensdesc(%02x,%02x) found snum for sa %02x at offset %d\n", sa,snum,sa2,nline); + if (sa == sa2) { + /* truncate the sensor line to omit the reading */ + len = strlen_(sensline); + for (i = 0; i < len; i++) + if (sensline[i] == '=') { sensline[i] = 0; break; } + if (sensline[i-1] != ' ') { + sensline[i] = ' '; sensline[++i] = 0; + } + /* skip to just the sensor description from the SDR */ + p = strstr(sensline,"snum"); + p += 8; /* skip 'snum 11 ' */ + strcpy(sensdesc,p); + if (pstyp != NULL) *pstyp = _htoi(&sensline[25]); + if (pidx != NULL) *pidx = idx; + break; + } + } + } /*end-for j*/ + if (j >= 3) rv = ERR_NOT_FOUND; /*not found*/ + return(rv); +} + +char *get_genid_str(ushort genid) +{ + static char genstr[10]; + char *gstr; + int i; + + sprintf(genstr,"%04x",genid); + gstr = genstr; /* default */ + for (i = 0; i < NGDESC; i++) + { + if (gen_desc[i].g_id == genid) { + gstr = (char *)gen_desc[i].desc; + break; + } + } + return(gstr); +} + +static int is_threshold(uchar evtrg, ushort genid) +{ + int val = 0; /*false*/ + /* It would be better to check the SDR (if Full supports thresholds), + * but we do not always have that available. */ + if ( ((genid == BMC_SA) || /*from BMC*/ + (genid == SMI_SA) || /*from SMI (simulated)*/ + (genid == thr_sa)) && /*from HSC, or other*/ + ((evtrg == 0x01) || /*threshold evt*/ + (evtrg == 0x81))) /*threshold ok*/ + val = 1; + return(val); +} + +static void get_sdr_tag(uchar *sdr, char *tagstr) +{ + int i, j, k, len; + len = sdr[4] + 5; + switch(sdr[3]) { + case 0x01: k = 48; break; /*full sensor*/ + case 0x02: k = 32; break; /*compact sensor*/ + case 0x03: k = 17; break; /*compact sensor*/ + case 0x10: k = 16; break; /*compact sensor*/ + case 0x11: k = 16; break; /*compact sensor*/ + case 0x12: k = 16; break; /*compact sensor*/ + default: k = 0; break; + } + if (k > 0 && k < len) { + i = len - k; + for (j = 0; j < i; j++) { + if (sdr[k+j] == 0) break; + tagstr[j] = sdr[k+j]; + } + tagstr[j++] = ' '; + tagstr[j] = 0; + } +} + +/* + * get_sensor_tag + * + * Get the sensor tag (name) based on the sensor number, etc. + * Use one of 3 methods to get this: + * 1) Parse the sensor_out.txt (sensfil) if fsensdesc==2. + * Use this method if not METACOMMAND or if user-specified. + * 2) Find this SDR in the SDR cache, if available. + * 3) Do a GetSDR command function now (can be slow) + * Input parameters: + * isdr = index of SDR, use 0 if unknown + * genid = genid or sa (slave address) of this sensor + * snum = sensor number of this sensor + * tag = pointer to a buffer for the sensor tag (min 17 bytes) + * sdr = pointer to buffer for the SDR if found (usu <= 65 bytes) + * szsdr = size of the SDR buffer + * Output parameters: + * tag = filled in with sensor tag (name) + * sdr = filled in with SDR, if found. + * Returns: + * 0 if tag and sdr are found. + * ERR_NOT_FOUND if SDR is not found (but tag may be found) + * other errors, see ipmicmd.h + */ +int get_sensor_tag(int isdr, int genid, uchar snum, char *tag, + uchar *sdr, int szsdr) +{ + int rv, i, j = 0; + if (tag == NULL) return(ERR_BAD_PARAM); + if (sdr == NULL) return(ERR_BAD_PARAM); + if (genid == SMS_SA) genid = BMC_SA; /*parse Sms as if BMC*/ + if (genid == SMI_SA) genid = BMC_SA; /*parse SMI as if BMC*/ + tag[0] = 0; + if (fsensdesc == 2) { /*not connected, so do not try to GetSDR*/ + rv = get_sensdesc((uchar)genid, snum, tag,NULL,&isdr); + rv = ERR_NOT_FOUND; /*got tag, but did not get SDR*/ + } else if (sdrcache != NULL) { /*valid sdr cache*/ + rv = find_sdr_by_snum(sdr,sdrcache, snum, (uchar)genid); + if (rv == 0) { + get_sdr_tag(sdr,tag); + } + } else { /* try to get this SDR */ + rv = GetSDR(isdr, &i,sdr,szsdr,&j); + if (fdebug) printf("get_sensor_tag GetSDR[%x] rv=%d sz=%d\n",isdr,rv,j); + if (rv == 0) { + get_sdr_tag(sdr,tag); + } else { /* use a saved sensor.out file */ + rv = get_sensdesc((uchar)genid, snum, tag,NULL,&isdr); + if (rv != 0) tag[0] = 0; + rv = ERR_NOT_FOUND; /*got tag, but did not get SDR*/ + } + } + if (fdebug) printf("get_sensor_tag(%d): find_sdr(%x,%x) rv=%d tag=/%s/\n", + fsensdesc,snum,genid,rv,tag); + return(rv); +} + +static +int decode_post_oem(int vend, int prod, ushort code, char *outbuf,int szbuf) +{ + int rv = -1; + if (outbuf == NULL || szbuf == 0) return(rv); +#if defined(METACOMMAND) + switch(vend) { + case VENDOR_INTEL: + rv = decode_post_intel(prod,code,outbuf,szbuf); + break; + default: + break; + } +#endif + if (rv != 0) snprintf(outbuf,szbuf,"POST Code %04x",code); + return(rv); +} + +static +int decode_sel_oem(int vend, uchar *pevt, char *outbuf,int szbuf, + char fdesc, char fdbg) +{ + int rv = -1; +#ifdef METACOMMAND + switch(vend) { + case VENDOR_KONTRON: + rv = decode_sel_kontron(pevt,outbuf,szbuf,fdesc,fdbg); + break; + case VENDOR_FUJITSU: + /* Fujitsu does an OEM IPMI command to return the decoded string. */ + rv = decode_sel_fujitsu(pevt,outbuf,szbuf,fdesc,fdbg); + break; + case VENDOR_INTEL: + thr_sa = HSC_SA; /* HSC_SA(0xC0) by default */ + rv = decode_sel_intel(pevt,outbuf,szbuf,fdesc,fdbg); + break; + case VENDOR_PEPPERCON: /*SuperMicro AOC-SIMSO*/ + if (pevt[7] == 0x40) pevt[7] = BMC_SA; /*genid broken, fix it*/ + break; + case VENDOR_MAGNUM: + case VENDOR_SUPERMICRO: + case VENDOR_SUPERMICROX: + rv = decode_sel_supermicro(pevt,outbuf,szbuf,fdesc,fdbg); + break; + case VENDOR_QUANTA: + rv = decode_sel_quanta(pevt,outbuf,szbuf,fdesc,fdbg); + break; + case VENDOR_NEWISYS: + rv = decode_sel_newisys(pevt,outbuf,szbuf,fdesc,fdbg); + break; + case VENDOR_DELL: + rv = decode_sel_dell(pevt,outbuf,szbuf,fdesc,fdbg); + break; + default: + break; + } +#endif + if (fdebug) printf("decode_sel_oem(0x%04x) rv=%d\n",vend,rv); + return(rv); +} + +#define N_PWRUNIT 12 +static struct { + uchar trg; uchar data1; uchar sev; char *msg; + } pwrunit_evts[N_PWRUNIT] = { +{ 0x6f, 0x00, 0,"Power Off "}, +{ 0x6f, 0x01, 0,"Power Cycle "}, +{ 0x6f, 0x02, 0,"240VA power down"}, +{ 0x6f, 0x03, 0,"Interlock power down"}, +{ 0x6f, 0x04, 1,"AC Lost"}, +{ 0x6f, 0x05, 2,"Soft Powerup failure"}, +{ 0x6f, 0x06, 2,"Failure detected"}, +{ 0x6f, 0x07, 1,"Predictive failure"}, +{ 0xef, 0x00, 0,"Power Restored"}, +{ 0xef, 0x01, 0,"Power Cycle ok"}, +{ 0xef, 0x04, 0,"AC Regained"}, +{ 0xef, 0x06, 0,"Failure OK now"} +}; +static int decode_pwrunit(uchar trg, uchar data1, char *pstr, uchar *psev) +{ + int rv = -1; + int i, j; + j = data1 & 0x0f; + if (psev == NULL || pstr == NULL) return(rv); + sprintf(pstr,"_"); + for (i = 0; i < N_PWRUNIT; i++) + { + if ((trg == pwrunit_evts[i].trg) && + (j == pwrunit_evts[i].data1)) { + *psev = pwrunit_evts[i].sev; + sprintf(pstr,"%s",pwrunit_evts[i].msg); + rv = 0; + } + } + return(rv); +} + +#define N_REDUN 16 +static struct { + uchar trg; uchar data1; uchar sev; char *msg; + } redund_evts[N_REDUN] = { +{ 0x0B, 0x00, SEV_INFO,"Redundancy OK "}, +{ 0x0B, 0x01, SEV_MAJ, "Redundancy Lost"}, +{ 0x0B, 0x02, SEV_MAJ, "Redundancy Degraded"}, +{ 0x0B, 0x03, SEV_MAJ, "Not Redundant"}, +{ 0x0B, 0x04, SEV_MAJ, "Sufficient Resources"}, +{ 0x0B, 0x05, SEV_CRIT,"Insufficient Resources"}, +{ 0x0B, 0x06, SEV_MAJ, "Fully-to-Degraded"}, +{ 0x0B, 0x07, SEV_MIN, "NonR-to-Degraded"}, +{ 0x8B, 0x00, SEV_MAJ, "Redundancy NOT ok"}, +{ 0x8B, 0x01, SEV_INFO,"Redundancy Regained"}, +{ 0x8B, 0x02, SEV_INFO,"Redundancy Restored"}, +{ 0x8B, 0x03, SEV_INFO,"Redundant"}, +{ 0x8B, 0x04, SEV_MAJ, "Not Sufficient"}, +{ 0x8B, 0x05, SEV_INFO,"Not Insufficient"}, +{ 0x8B, 0x06, SEV_INFO,"Degraded-to-Fully"}, +{ 0x8B, 0x07, SEV_MIN, "Degraded-to-NonR"} +}; +static int decode_redund(uchar trg, uchar data1, char *pstr, uchar *psev) +{ + int rv = -1; + int i, j; + j = data1 & 0x0f; + if (psev == NULL || pstr == NULL) return(rv); + sprintf(pstr,"_"); + for (i = 0; i < N_REDUN; i++) + { + if ((trg == redund_evts[i].trg) && + (j == redund_evts[i].data1)) { + *psev = redund_evts[i].sev; + sprintf(pstr,"%s",redund_evts[i].msg); + rv = 0; + } + } + return(rv); +} + +#define N_PRESENT 2 +static char * present_str[N_PRESENT] = { /* Availability, evtype 0x08 */ + /*00*/ "Absent", /*Absent/Removed*/ + /*01*/ "Present"}; /*Present/Inserted*/ + +static int decode_presence(uchar trg, uchar data1, char *pstr, uchar *psev) +{ + int rv = -1; + int i; + if (psev == NULL || pstr == NULL) return(rv); + sprintf(pstr,"_"); + *psev = SEV_INFO; + i = data1 & 0x0f; + if (trg == 0x08) { + if (i >= N_PRESENT) i = N_PRESENT - 1; + sprintf(pstr,"%s",present_str[i]); + rv = 0; + } else if (trg == 0x88) { + if (data1 & 0x01) i = 0; + else i = 1; + sprintf(pstr,"%s",present_str[i]); + } + return(rv); +} + +void format_event(ushort id, time_t timestamp, int sevid, ushort genid, + char *ptype, uchar snum, char *psens, char *pstr, char *more, + char *outbuf, int outsz) +{ + char sensdesc[36]; + char timestr[40]; + uchar sdr[MAX_BUFFER_SIZE]; /*sdr usu <= 65 bytes*/ + char *gstr; + int isdr = 0; + int rv; + + if (more == NULL) more = ""; + if (psens != NULL) ; /* use what was passed in */ + else { /*psens==NULL, may need to get tag*/ + psens = &sensdesc[0]; + sensdesc[0] = 0; + if (fsensdesc) { + rv = get_sensor_tag(isdr,genid,snum,psens,sdr,sizeof(sdr)); + if (fdebug) printf("get_sensor_tag(%x) rv = %d\n",snum,rv); + } + } + fmt_time(timestamp, timestr, sizeof(timestr)); + gstr = get_genid_str(genid); /*get Generator ID / Source string*/ + + if (fcanonical) { + snprintf(outbuf,outsz,"%04x %c %s %c %s %c %s %c %s %c %s %c %s %s\n", + id, bdelim, timestr, bdelim, + get_sev_str(sevid), bdelim, + gstr, bdelim, ptype, bdelim, + psens, bdelim, pstr, more ); + } else { + snprintf(outbuf,outsz,"%04x %s %s %s %s #%02x %s%s %s\n", + id, timestr, get_sev_str(sevid), + gstr, ptype, snum, psens, pstr, more); + } + return; +} + +/*------------------------------------------------------------------------ + * decode_sel_entry + * Parse and decode the SEL record into readable format. + * This routine is constructed so that it could be used as a library + * function. + * Note that this routine outputs 14 of the 16 bytes in either text or + * raw hex form. For the two bytes not shown: + * . record type: usually = 02, is shown otherwise (e.g. OEM type) + * . event msg revision: =03 if IPMI 1.0, =04 if IPMI 1.5 or IPMI 2.0 + * + * Input: psel, a pointer to the IPMI SEL record (16 bytes) + * Output: outbuf, a description of the event, max 80 chars. + * Called by: ReadSEL() + * Calls: fmt_time() get_misc_desc() + * + * IPMI SEL record format (from IPMI Table 32-1): + * Offset Meaning + * 0-1 Record ID (LSB, MSB) + * 2 Record Type (usu 0x02) + * 3-6 Timestamp (LS byte first) + * 7-8 Generator ID (LS first, usually 20 00) + * 9 Event message format (=0x04, or =0x03 if IPMI 1.0) + * 10 Sensor type + * 11 Sensor number + * 12 Event Dir | Event Type + * 13 Event Data 1 + * 14 Event Data 2 + * 15 Event Data 3 + *------------------------------------------------------------------------*/ +int decode_sel_entry( uchar *pevt, char *outbuf, int szbuf) +{ + char mystr[80] = "panic(123)"; /*used for panic string*/ + char *pstr; + char poststr[80] = "OEM Post Code = %x%x"; + char sensstr[50]; + char datastr[64]; + char cstr[4]; + char *psensstr; + int i, j, k, n; + time_t eventTime; + uchar *evtime; + char timebuf[40]; + uchar *pc; + SEL_RECORD *psel; + uchar fdeassert = 0; + uchar sev = SEV_INFO; + uchar sdr[MAX_BUFFER_SIZE]; /*sdr usu <= 65 bytes*/ + int isdr = 0; + int vend, prod; + int rv = 0; + char fhave_sdr = 0; + char mdesc[80]; /*used for oem memory description*/ + int msz; + + if (outbuf == NULL) return(ERR_BAD_PARAM); + if (pevt == NULL) { + outbuf[0] = 0; + return(ERR_BAD_PARAM); + } + get_mfgid(&vend,&prod); /*saved from ipmi_getdeviceid */ + psel = (SEL_RECORD *)pevt; + + j = decode_sel_oem(vend,pevt,outbuf,szbuf,fsensdesc,fdebug); + if (j == 0) return(0); /*successful, have the description*/ + + if (psel->record_type == 0xDC) { + /* OEM Record: these are usually Microsoft */ + char *mfgstr; + int mfg; + evtime = (uchar *)&psel->timestamp; + eventTime = evtime[0] + (evtime[1] << 8) + + (evtime[2] << 16) + (evtime[3] << 24); + fmt_time(eventTime, timebuf, sizeof(timebuf)); + pc = (uchar *)&psel->generator_id; /* offset 7 */ + mfgstr = get_mfg_str(&pc[0],&mfg); + + if (fcanonical) + sprintf(outbuf,"%04x %c %s %c %s %c %02x %c %06x %c %s %c OEM Event ", + psel->record_id, bdelim, timebuf, bdelim, + get_sev_str(sev), bdelim, psel->record_type, bdelim, + mfg, bdelim, mfgstr, bdelim); + else + sprintf(outbuf,"%04x %s %s %02x %06x %s OEM Event ", + psel->record_id, timebuf, get_sev_str(sev), + psel->record_type, mfg, mfgstr); + j = strlen_(outbuf); + for (i = 3; i < 9; i++) { /* 10:16 = 6 bytes data */ + sprintf(&outbuf[j],"%02x ",pc[i]); + j += 3; + } + outbuf[j++] = '\n'; + outbuf[j++] = 0; + } else if (psel->record_type == 0xDD) { /* usu Intel OEM string */ + char *mfgstr; + int mfg; + int ix = 0; + /* Windows reboot reason string from MS ipmidrv.sys */ + evtime = (uchar *)&psel->timestamp; + eventTime = evtime[0] + (evtime[1] << 8) + + (evtime[2] << 16) + (evtime[3] << 24); + fmt_time(eventTime, timebuf, sizeof(timebuf)); + pc = (uchar *)&psel->generator_id; /* IANA at offset 7 */ + mfgstr = get_mfg_str(&pc[0],&mfg); + if (fcanonical) + sprintf(outbuf,"%04x %c %s %c %s %c %02x %c %06x %c %s %c OEM Event ", + psel->record_id, bdelim, timebuf, bdelim, + get_sev_str(sev), bdelim, psel->record_type, bdelim, + mfg, bdelim, mfgstr, bdelim); + else + sprintf(outbuf,"%04x %s %s %02x %06x %s OEM Event ", + psel->record_id, timebuf, get_sev_str(sev), + psel->record_type, mfg, mfgstr ); + j = strlen_(outbuf); + for (i = 3; i < 9; i++) { /* 10:16 = 6 bytes data */ + if (i == 3 || ix == 0) { + if (i == 3) ix = pc[i]; + sprintf(&outbuf[j],"%02x ",pc[i]); + j += 3; + } else { + if (pc[i] == 0) outbuf[j] = ' '; + else sprintf(&outbuf[j],"%c",pc[i]); + j += 1; + } + } + outbuf[j++] = '\n'; + outbuf[j++] = 0; + } else if (psel->record_type >= 0xe0) { /*OEM Record 26.3*/ + /* 3 bytes header, 13 bytes data, no timestamp */ + pc = (uchar *)&psel->timestamp; /*bytes 4:16*/ + if (fcanonical) + sprintf(outbuf,"%04x %c %s %c %s %c %02x %c %s %c %s %c OEM Event ", + psel->record_id, bdelim, "", bdelim, + get_sev_str(sev), bdelim, psel->record_type, bdelim, + "", bdelim, "", bdelim); + else + sprintf(outbuf,"%04x %s %02x OEM Event ", + psel->record_id,get_sev_str(sev),psel->record_type); + j = strlen_(outbuf); + for (i = 0; i < 13; i++) { /* 5:16 = 11 bytes data */ + if ((psel->record_type == 0xf0) && (i >= 2)) { + /* Linux panic string will be type 0xf0 */ + if (pc[i] == 0) break; + outbuf[j++] = pc[i]; + } else if (psel->record_type == 0xf1) { + /* custom ascii string record, type 0xf1 */ + if (i == 0) { /*linux panic*/ + outbuf[j++] = ':'; + outbuf[j++] = ' '; + } + if (pc[i] == 0) break; + outbuf[j++] = pc[i]; + } else { + sprintf(&outbuf[j],"%02x ",pc[i]); + j += 3; + } + } + outbuf[j++] = '\n'; + outbuf[j++] = 0; + } else if (psel->record_type >= 0xc0) { /*OEM Record 26.3*/ + /* 10 bytes header, 6 bytes data, has timestamp */ + evtime = (uchar *)&psel->timestamp; + eventTime = evtime[0] + (evtime[1] << 8) + + (evtime[2] << 16) + (evtime[3] << 24); + fmt_time(eventTime, timebuf, sizeof(timebuf)); + pc = (uchar *)&psel->generator_id; /* IANA at offset 7 */ + if (fcanonical) + sprintf(outbuf,"%04x %c %s %c %s %c %02x %c %02x%02x%02x %c %s %c OEM Event ", + psel->record_id, bdelim, timebuf, bdelim, + get_sev_str(sev), bdelim, psel->record_type, bdelim, + pc[2],pc[1],pc[0], bdelim, "", bdelim); + else + sprintf(outbuf,"%04x %s %s %02x %02x%02x%02x OEM Event ", + psel->record_id, timebuf, get_sev_str(sev), + psel->record_type, pc[2],pc[1],pc[0] ); + j = strlen_(outbuf); + for (i = 3; i < 9; i++) { /* 10:16 = 6 bytes data */ + sprintf(&outbuf[j],"%02x ",pc[i]); + j += 3; + } + outbuf[j++] = '\n'; + outbuf[j++] = 0; + } else if (psel->record_type == 0x02) { + uchar c = 0; + /* most records are record type 2 */ + /* Interpret the event by sensor type */ + switch(psel->sensor_type) + { + case 0x20: /*OS Crit Stop*/ + i = psel->event_data1 & 0x0f; + switch(i) { + case 0x00: pstr = "Startup Crit Stop"; + sev = SEV_CRIT; break; + case 0x02: pstr = "OS Graceful Stop"; break; + case 0x03: pstr = "OS Graceful Shutdown"; break; + case 0x04: pstr = "PEF Soft-Shutdown"; break; + case 0x05: pstr = "Agent Not Responding"; break; + case 0x01: /*OS Runtime Critical Stop (panic)*/ + default: + sev = SEV_CRIT; + if (psel->sensor_number == 0) { /*Windows*/ + pstr = "Runtime Crit Stop"; + } else { /*Linux panic, get string*/ + /* Show first 3 chars of panic string */ + pstr = mystr; + strcpy(mystr,"panic("); + for (i = 6; i <= 8; i++) { + switch(i) { + case 6: c = psel->sensor_number; break; + case 7: c = psel->event_data2; break; + case 8: c = psel->event_data3; break; + } + c &= 0x7f; + if (c < 0x20) c = '.'; + mystr[i] = c; + } + mystr[9] = ')'; + mystr[10] = 0; + if (psel->sensor_number & 0x80) + strcat(mystr,"Oops!"); + if (psel->event_data2 & 0x80) + strcat(mystr,"Int!"); + if (psel->event_data3 & 0x80) + strcat(mystr,"NullPtr!"); + } + break; + } /*end data1 switch*/ + break; + case 0x01: /*Temperature events*/ + if (is_threshold(psel->event_trigger, + psel->generator_id)) { + pstr = get_misc_desc( psel->generator_id, + psel->sensor_type, + psel->sensor_number, + psel->event_trigger, + psel->event_data1, + psel->event_data2, + psel->event_data3, &sev); + } else { /*else discrete temp event*/ + /* data1 should usually be 0x01 */ + if (psel->event_trigger & 0x80) + strcpy(mystr,"Temp OK"); + else strcpy(mystr,"Temp Asserted"); + pstr = mystr; + } /*end-else discrete*/ + break; + /* case 0X04 for Fan events is further below. */ + case 0x07: /*Processor (CPU)*/ + i = psel->event_data1 & 0x0f; + if (psel->event_trigger == 0x6f) { + /* Processor status sensor */ + if (i >= NPROC) i = NPROC - 1; + if (i == 7) sev = SEV_INFO; + else if (i > 7) sev = SEV_MIN; + else sev = SEV_CRIT; + sprintf(mystr,"%s",proc_str[i]); + pstr = mystr; + } else if (psel->event_trigger == 0xef) { + sev = SEV_CRIT; + if (i >= NPROC) i = NPROC - 1; + sprintf(mystr,"%s deasserted",proc_str[i]); + pstr = mystr; + } else if (psel->sensor_number == 0x80) { /*CATERR*/ + char *p1, *p2; + sev = SEV_CRIT; + switch( psel->event_data2 & 0x0F) + { + case 1: p1 = "CATERR"; break; + case 2: p1 = "CPU Core Error"; break; + case 3: p1 = "MSID Mismatch"; break; + default: p1 = "Unknown Error"; break; + } + if (psel->event_data2 & 0x01) p2 = "CPU0"; + else if (psel->event_data2 & 0x02) p2 = "CPU1"; + else if (psel->event_data2 & 0x04) p2 = "CPU2"; + else if (psel->event_data2 & 0x08) p2 = "CPU3"; + else p2 = "CPU4"; + sprintf(mystr,"%s on %s",p1,p2); + pstr = mystr; + } else if (psel->event_trigger == 0x03) { + if (i) {pstr = "Proc Config Error"; sev = SEV_CRIT;} + else {pstr = "Proc Config OK"; sev = SEV_INFO; } + } else if (psel->event_trigger == 0x83) { + if (i) { pstr = "Proc Config OK"; sev = SEV_INFO; } + else { pstr = "Proc Config Error"; sev = SEV_CRIT; } + } else { /* else other processor sensor */ + i = ((psel->event_trigger & 0x80) >> 7); + if (i) { pstr = "ProcErr Deasserted"; sev = SEV_INFO;} + else { pstr = "ProcErr Asserted"; sev = SEV_CRIT; } + } + break; + case 0x09: /*Power Unit*/ + if ((psel->event_trigger == 0x0b) || + (psel->event_trigger == 0x8b)) { + rv = decode_redund(psel->event_trigger, + psel->event_data1, mystr, &sev); + } else { /*sensor-specific 0x6f/0xef*/ + rv = decode_pwrunit(psel->event_trigger, + psel->event_data1, mystr, &sev); + } + if (rv == 0) pstr = mystr; + else pstr = NULL; /*falls through to unknown*/ + break; + case 0x0C: /*Memory*/ + i = psel->event_data1 & 0x0f; /*memstr index*/ + { /* now get the DIMM index from data2 or data3 */ + uchar b2, b3, bdata; + b2 = psel->event_data2; + b3 = psel->event_data3; + if ((vend == VENDOR_INTEL && prod == 0x4311) || + (vend == VENDOR_NSC)) { /*mini-BMC*/ + bdata = b2; + } else if (b3 == 0xff) { /* FF is reserved */ + bdata = b2; + } else { /* normal case */ + bdata = b3; + } + j = bdata & 0x3f; + /* Now i==data1(lo nib) for memstr, j==DIMM index */ + if (i == 0) sev = SEV_MIN; /*correctable ECC*/ + else sev = SEV_MAJ; + if (fdebug) printf("DIMM(%d) vend=%x prod=%x\n",j,vend,prod); + /* For Intel S5500/S2600 see decode_mem_intel */ + if (vend == VENDOR_INTEL) { + decode_mem_intel(prod,b2,b3,mdesc,&msz); + sprintf(mystr,"%s%c %s",mem_str(i),bcomma,mdesc); + } else if ((vend == VENDOR_SUPERMICRO) || + (vend == VENDOR_SUPERMICROX)) { + decode_mem_supermicro(prod,b2,b3,mdesc,&msz); + sprintf(mystr,"%s%c %s",mem_str(i),bcomma,mdesc); + } else { + sprintf(mystr,"%s%c DIMM[%d]",mem_str(i),bcomma,j); + /* DIMM[2] = 3rd one (zero-based index) */ + } + } + pstr = mystr; + break; + case 0x0F: /*System Firmware events, incl POST Errs*/ + sev = SEV_MAJ; /*usu major, but platform-specific*/ + switch (psel->event_data1) + { + case 0x00: /* System firmware errors */ + i = psel->event_data2; + if (i > NFWERRS) i = NFWERRS; + pstr = fwerrs[i].msg; + break; + case 0x01: /* System firmware hang */ + i = psel->event_data2; + if (i > NFWSTAT) i = NFWSTAT; + sprintf(poststr,"hang%c %s",bcomma, + fwstat[i].msg); + pstr = poststr; + break; + case 0x02: /* System firmware progress */ + sev = SEV_INFO; + i = psel->event_data2; + if (i > NFWSTAT) i = NFWSTAT; + sprintf(poststr,"prog%c %s",bcomma, + fwstat[i].msg); + pstr = poststr; + break; + case 0xa0: /* OEM post codes */ + /* OEM post codes in bytes 2 & 3 (lo-hi) */ + j = psel->event_data2 | + (psel->event_data3 << 8); + /* interpret some OEM post codes if -e */ + i = decode_post_oem(vend,prod,(ushort)j, + poststr,sizeof(poststr)); + pstr = poststr; + break; + default: + pstr = get_misc_desc( psel->generator_id, + psel->sensor_type, + psel->sensor_number, + psel->event_trigger, + psel->event_data1, + psel->event_data2, + psel->event_data3, &sev); + if (pstr == NULL) + pstr = "POST Error"; /*default string*/ + } /*end switch(data1)*/ + break; + case 0x13: /*Crit Int*/ + sev = SEV_CRIT; + i = psel->event_data1 & 0x0f; + if (i >= NCRITS) i = NCRITS - 1; + pstr = crit_int_str[i]; + if ((psel->event_trigger == 0x70) || + (psel->event_trigger == 0x71)) { + uchar bus,dev,func; + /* Intel AER< decode PCI bus:dev.func data */ + bus = psel->event_data2; + dev = ((psel->event_data3 & 0xf8) >> 3); + func = (psel->event_data3 & 0x07); + sprintf(mystr,"%s (on %02x:%02x.%d)", + crit_int_str[i],bus,dev,func); + pstr = mystr; + } + break; + case 0x15: /*Board (e.g. IO Module)*/ + if ((psel->event_trigger == 0x08) || + (psel->event_trigger == 0x88)) { + rv = decode_presence(psel->event_trigger, + psel->event_data1, mystr, &sev); + pstr = mystr; + } else pstr = NULL; /*falls through to unknown*/ + break; + case 0x16: /*Microcontroller (e.g. ME or HDD)*/ + // if (psel->event_trigger == 0x0A) // Availability + { + i = psel->event_data1 & 0x0f; + if (i >= N_AVAIL) i = N_AVAIL - 1; + if (i >= 4) sev = SEV_MIN; + else sev = SEV_INFO; + pstr = avail_str[i]; + } + break; + case 0x1D: /*System Boot Initiated*/ + i = psel->event_data1 & 0x0f; + if (i >= NBOOTI) i = NBOOTI - 1; + pstr = boot_init_str[i]; + break; + case 0x1F: /*OS Boot */ + i = psel->event_data1 & 0x0f; + if (i >= NOSBOOT) i = NOSBOOT - 1; + pstr = osboot_str[i]; + break; + case 0x21: /*Slot/Con*/ + i = psel->event_data1 & 0x0f; + if (i >= NSLOTC) i = NSLOTC - 1; + if (i == 0) sev = SEV_MAJ; /*Fault*/ + else if (i == 8) sev = SEV_MIN; + sprintf(mystr,"%s",slot_str[i]); + /* could also decode data2/data3 here if valid */ + pstr = mystr; + break; + case 0x22: /*ACPI Power state*/ + i = psel->event_data1 & 0x0f; + if (i >= NACPIP) i = NACPIP - 1; + sprintf(mystr,"%s",acpip_str[i]); + pstr = mystr; + break; + case 0x28: /*Management Subsystem Health*/ + i = psel->event_data1 & 0x0f; + if (i == 0x04) /*sensor error*/ + sprintf(mystr,"Sensor %02x fault",psel->event_data2); + else + sprintf(mystr,"Other FW HAL error"); + pstr = mystr; + break; + case 0x29: /*Battery*/ + if (is_threshold(psel->event_trigger, + psel->generator_id)) + { + pstr = get_misc_desc( psel->generator_id, + psel->sensor_type, + psel->sensor_number, + psel->event_trigger, + psel->event_data1, + psel->event_data2, + psel->event_data3, &sev); + } else { + i = psel->event_data1 & 0x0f; + if (i >= NBATT) i = NBATT - 1; + /* sev defaults to SEV_INFO */ + if (psel->event_trigger & 0x80) { /*deasserted*/ + sprintf(mystr,"%s",batt_clr[i]); + } else { /*asserted*/ + sprintf(mystr,"%s",batt_str[i]); + if (i == 0) sev = SEV_MIN; + else if (i == 1) sev = SEV_MAJ; + } + pstr = mystr; + } + break; + case 0x2A: /*Session Audit, new for IPMI 2.0*/ + i = psel->event_data1 & 0x0f; + if (i >= NAUDIT) i = NAUDIT - 1; + sprintf(mystr,"%s User%d",audit_str[i], + psel->event_data2); + /* see also psel->event_data3 for cause/channel*/ + pstr = mystr; + break; + case 0xDC: /*ME Node Manager, for S5500 Urbanna*/ + i = psel->event_trigger; + if (i & 0x80) { fdeassert = 1; i &= 0x7f; } + if (i >= 0x72) i -= 0x72; + if (i >= N_NM) i = N_NM - 1; + sprintf(mystr,"%s",nm_str[i]); + if (fdeassert) strcat(mystr," OK"); + n = strlen_(mystr); + sprintf(cstr,"%c ",bcomma); + j = psel->event_data2; + switch(i) { + case 0x00: /*0x72 NM Exception*/ + j = psel->event_data1; + if ((j & 0x08) == 0) { + k = j & 0x03; + sprintf(&mystr[n], + "%sThreshold %d Exceeded",cstr,k); + } else { /*Policy event*/ + sprintf(&mystr[n], + "%sPolicy Time Exceeded",cstr); + } + sev = SEV_MIN; + break; + case 0x01: /*0x73 NM Health*/ + j &= 0x0f; // if (j >= 0x10) j -= 0x10; + if (j >= N_NMH) j = N_NMH - 1; + if (j != 5) sev = SEV_MAJ; + strcat(mystr,cstr); /*", "*/ + strcat(mystr,nmh_str[j]); + break; + case 0x03: /*0x75 FW Health*/ + if (j >= N_NMFW) j = N_NMFW - 1; + sev = SEV_MAJ; + strcat(mystr,cstr); /*", "*/ + strcat(mystr,nmfw_str[j]); + break; + case 0x02: /*0x74 NM Capabilities*/ + default: + sev = SEV_MIN; + break; + } + pstr = mystr; + break; + case 0x04: /*Fan sensor events */ + if ((psel->event_trigger == 0x0b) || + (psel->event_trigger == 0x8b)) { + rv = decode_redund(psel->event_trigger, + psel->event_data1, mystr, &sev); + pstr = mystr; + break; + } else if ((psel->event_trigger == 0x08) || + (psel->event_trigger == 0x88)) { + rv = decode_presence(psel->event_trigger, + psel->event_data1, mystr, &sev); + pstr = mystr; + break; + } else if (psel->event_trigger == 0x06) { + /* usu psel->event_data1 == 0x01 */ + sev = SEV_MIN; + strcpy(mystr,"Performance Lags"); + pstr = mystr; + break; + } else if (psel->event_trigger == 0x86) { + sev = SEV_INFO; + strcpy(mystr,"Performance OK"); + pstr = mystr; + break; + } + /* else Fan threshold events handled below, trig=01/81*/ + default: /* all other sensor types, see sens_desc */ + pstr = get_misc_desc( psel->generator_id, + psel->sensor_type, + psel->sensor_number, + psel->event_trigger, + psel->event_data1, + psel->event_data2, + psel->event_data3, &sev); + break; + } /*end switch(sensor_type)*/ + + if (pstr == NULL) { /* none found, unknown */ + mystr[0] = '-'; mystr[1] = 0; + pstr = mystr; + } + + + /*firmware timestamp is #seconds since 1/1/1970 localtime*/ + evtime = (uchar *)&psel->timestamp; + eventTime = evtime[0] + (evtime[1] << 8) + + (evtime[2] << 16) + (evtime[3] << 24); + if (fdebug) { + char tbuf[40]; + char *tz; char *lctime; + strftime(timebuf,sizeof(timebuf), "%x %H:%M:%S %Z", + localtime(&eventTime)); + strftime(tbuf,sizeof(tbuf), "%x %H:%M:%S %Z", + gmtime(&eventTime)); + tz = getenv("TZ"); + if (tz == NULL) tz = ""; + lctime = getenv("LC_TIME"); + if (lctime == NULL) lctime = ""; + SELprintf("%s\nTZ=%s, LC_TIME=%s, gmtime=%s\n", + timebuf,tz,lctime,tbuf); + } + psensstr = NULL; + sensstr[0] = 0; + if (fsensdesc) { + rv = get_sensor_tag(isdr,psel->generator_id, + psel->sensor_number, sensstr, + sdr, sizeof(sdr)); + if (rv == 0) { + fhave_sdr = 1; + psensstr = &sensstr[0]; + } else rv = 0; /*no sdr but not an error*/ + } /*endif fsensdesc*/ + + if (is_threshold(psel->event_trigger,psel->generator_id)) { + /* Also usually ((psel->event_data1 & 0x50) == 0x50) */ + /* We know that these two MCs should include the + * actual and threshold raw values in data2 & data3 */ + if (fsensdesc && fhave_sdr) { + double v1, v2; + char *u; + /* if sdrcache, find_sdr_by_snum got the sdr above */ + /* else, GetSDR tried to get the sdr above */ + v1 = RawToFloat(psel->event_data2,sdr); + v2 = RawToFloat(psel->event_data3,sdr); + u = get_unit_type(sdr[20],sdr[21],sdr[22],1); + sprintf(datastr, "actual=%.2f %s, threshold=%.2f %s", + v1,u, v2,u); + } else { // if (fsensdesc == 0 || (rv != 0)) { + sprintf(datastr,"act=%02x thr=%02x", + psel->event_data2, /*actual raw reading*/ + psel->event_data3 ); /*threshold raw value*/ + } + } else { + if (fcanonical) datastr[0] = 0; + else sprintf(datastr,"%02x [%02x %02x %02x]", + psel->event_trigger, + psel->event_data1, + psel->event_data2, + psel->event_data3 ); + } + + format_event(psel->record_id, eventTime, sev, + psel->generator_id, + get_sensor_type_desc(psel->sensor_type), + psel->sensor_number, psensstr, + pstr, datastr, outbuf,szbuf); + + } /*endif type 2 */ + else { /* other misc record type */ + if (fdebug) printf("Unrecognized record type %02x\n", + psel->record_type); + rv = ERR_NOT_FOUND; + pc = (uchar *)&psel->record_type; + sprintf(outbuf,"%04x Type%02x %s ", + psel->record_id,pc[0],get_sev_str(sev)); + j = strlen_(outbuf); + for (i = 1; i < 14; i++) { + sprintf(mystr,"%02x ",pc[i]); + strcat(outbuf,mystr); + } + strcat(outbuf,"\n"); + } /*endif misc type*/ + return(rv); +} /*end decode_sel_entry()*/ + +static void show_usage(void) +{ + printf("Usage: %s [-bdfhprstux] 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10\n",progname); + printf("where -b = interpret Binary raw SEL file, from ipmitool sel writeraw\n"); + printf(" -d = get DeviceID for vendor/product-specific events\n"); + printf(" -f = interpret File with raw ascii SEL data, from ipmiutil sel -r\n"); + printf(" -h = interpret Hex binary raw SEL file (same as -b)\n"); +#ifndef ALONE + printf(" -o = specify the target vendor IANA number.\n"); +#endif + printf(" -n = generate New platform event, use last 9 event bytes\n"); + printf(" -p = decode PET event bytes, use 34 PET data bytes,\n"); + printf(" skipping the first 8 of the 47-byte PET data (-t=all).\n"); + printf(" If not specified, assumes a 16-byte IPMI event.\n"); + printf(" -r = interpret RAW ascii SEL file (same as -f)\n"); + printf(" -s = sensor file with output of 'ipmiutil sensor', used\n"); + printf(" to get the PET sensor_type from the sensor_num.\n"); + printf(" The default is %s\n",sensfil); + printf(" -t = decode PET trap bytes, use all 47 PET data bytes (-p=34)\n"); + printf(" If not specified, assumes a 16-byte IPMI event.\n"); + printf(" -u = use raw UTC time\n"); + printf(" -x = show eXtra debug messages\n"); +} + +/* + * decode_raw_sel + * input parameters: + * raw_file : filename of raw SEL file + * mode : 1 = ascii raw from ipmiutil sel -r + * 2 = binary hex from ipmiutil sel writeraw {raw_file} + */ +int decode_raw_sel(char *raw_file, int mode) +{ + FILE *fp; + char buff[256]; + uchar msg[132]; + uchar hbuf[50]; + int fvalid = 0; + int len, i; + + fp = fopen(raw_file,"r"); + if (fp == NULL) { + printf("Cannot open file %s\n",raw_file); + return(ERR_FILE_OPEN); + } else { + printf("%s",evt_hdr); /*"RecId Date/Time_______*/ + if (mode == 1) { /*ascii raw*/ + if (fdebug) + printf("decoding raw ascii file with IPMI event bytes\n"); + while (fgets(buff, 255, fp)) { + len = strlen_(buff); + fvalid = 0; + if (buff[0] >= '0' && (buff[0] <= '9')) fvalid = 1; + else if (buff[0] >= 'a' && (buff[0] <= 'f')) fvalid = 1; + else if (buff[0] >= 'A' && (buff[0] <= 'F')) fvalid = 1; + if (fvalid == 0) continue; + for (i = 0; i < 16; i++) { + hbuf[i] = _htoi(&buff[i*3]); + } + decode_sel_entry(hbuf,msg,sizeof(msg)); + printf("%s", msg); + } /*end while*/ + } else { /*hex raw*/ + if (fdebug) + printf("decoding binary hex file with IPMI event bytes\n"); + while (fread(hbuf, 1, 16, fp) == 16) { + decode_sel_entry(hbuf,msg,sizeof(msg)); + printf("%s", msg); + } /*end while*/ + } + fclose(fp); + } + return(0); +} + +/* + * The events utility interprets standard 16-byte IPMI events into + * human-readable form by default. + * User must pass raw 16-byte event data from some log text for decoding. + * + * Sample IPMI event usage: + * # ievents fb 07 02 e5 1a b8 44 21 00 03 1d 9a 6f 40 8f ff + * RecId Date/Time_______ SEV Src_ Evt_Type___ Sens# Evt_detail - Trig [Evt_data] + * 07fb 07/14/06 18:29:57 INF SMI System Boot Initiated #9a Power Up 6f [40 8f ff] + * # ievents 14 04 02 BE 35 13 45 33 40 04 0C 08 6F 20 00 04 + * RecId Date/Time_______ SEV Src_ Evt_Type___ Sens# Evt_detail - Trig [Evt_data] + * 0414 09/21/06 21:00:46 MIN 4033 Memory #08 Correctable ECC, DIMM[4] 6f [20 00 04] + * + * If fPET, interpret the SNMP Platform Event Trap hex varbind data. + * For interpreting the 47-byte hex data from SNMP Platform Event Traps, + * specify events -p with the 34 data bytes following the 16-byte GUID. + * + * Sample SNMP PET Data for events: + * 0000: 3C A7 56 85 08 C5 11 D7 C3 A2 00 04 23 BC AC 12 + * 0010: 51 14 11 72 38 58 FF FF 20 20 00 10 83 07 01 41 + * 0020: 0F FF 00 00 00 00 00 19 00 00 01 57 00 22 C1 + * + * Sample events -p command from above data: + * # ievents -p C3 A2 00 04 23 BC AC 12 51 14 11 72 38 58 FF FF 20 20 00 10 83 07 01 41 0F FF 00 00 00 00 + * RecId Date/Time_______ SEV Src_ Evt_Type___ Sens# Evt_detail - Trig [Evt_data] + * 0014 04/11/07 12:03:20 INF BMC System Event #83 OEM System Booted 6f [41 0f ff] + * + * Platform Event Trap Format + * Offset Len Meaning + * 0 16 System GUID + * 16 2 Sequence Number/Cookie + * 18 4 Local Timestamp + * 22 2 UTC Offset + * 24 1 Trap Source Type (usu 0x20) + * 25 1 Event Source Type (usu 0x20) + * 26 1 Event Severity + * 27 1 Sensor Device + * 28 1 Sensor Number + * 29 1 Entity + * 30 1 Entity Instance + * 31 8 Event Data (8 bytes max, 3 bytes used) + * 39 1 Language Code (usu 0x19/25. = English) + * 40 4 Manufacturer IANA number (Intel=0x000157) + * 44 1-N OEM data, C1="No more fields" + * If Intel (0x000157): + * 44 2 Product ID + * 46 1 0xC1 (No more fields) + */ +#if defined(ALONE) +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#else +/* #elif defined(METACOMMAND) or if libipmiutil */ +int i_events(int argc, char **argv) +#endif +{ + uchar buf[50]; + uchar msg[132]; + uchar *pmsg; + int i, j, len; + char fPET = 0; + char frawfile = 0; + char fhexfile = 0; + int rv = 0; + char c; + uchar b = 0; +#ifndef ALONE + uchar devid[16]; +#endif +#if defined(METACOMMAND) + char *p; +#endif + + printf("%s version %s\n",progname,progver); + if (argc > 0) { argc--; argv++; } /*skip argv[0], program name*/ + /* ievents getopt: [ -bdfhnoprstux -NPRUEFJTVY */ + while ((argc > 0) && argv[0][0] == '-') + { + c = argv[0][1]; + switch(c) { + case 'x': fdebug = 1; break; + case 'd': fgetdevid = 1; break; /*get device id (vendor, product)*/ + case 'n': fnewevt = 1; break; /* generate New event */ + case 'p': /* PET format, minus first 8 bytes*/ + /* This is important for some SNMP trap receivers that obscure + * the first 8 bytes of the trap data */ + fPET = 1; /*incoming data is in PET format*/ + break; + case 'u': futc = 1; break; /*use raw UTC time*/ +#ifndef ALONE + case 'o': /*specify OEM IANA manufacturer id */ + if (argc > 1) { /*next argv is IANA number */ + i = atoi(argv[1]); + printf("setting IANA to %d (%s)\n",i,get_iana_str(i)); + set_iana(i); + argc--; argv++; + } else { + printf("option -%c requires an argument\n",c); + rv = ERR_BAD_PARAM; + } + break; +#endif + case 't': /*PET format Trap, use all data*/ + /* This may be helpful if all bytes are available, or if + * the GUID is relevant. */ + fPET = 1; /*incoming data is in PET format*/ + pet_guid = 16; + break; + case 'f': + case 'r': + /* interpret raw ascii SEL file from optarg */ + frawfile = 1; + if (argc > 1) { /*next argv is filename*/ + len = strlen_(argv[1]); + if (len >= sizeof(rawfil)) + len = sizeof(rawfil) - 1; + strncpy(rawfil,argv[1],len); + rawfil[len] = 0; /*stringify*/ + argc--; argv++; + } else { + printf("option -%c requires a filename argument\n",c); + rv = ERR_BAD_PARAM; + } + break; + case 'b': + case 'h': + /* interpret raw binary/hex SEL file from optarg */ + fhexfile = 1; + if (argc > 1) { /*next argv is filename*/ + len = strlen_(argv[1]); + if (len >= sizeof(rawfil)) + len = sizeof(rawfil) - 1; + strncpy(rawfil,argv[1],len); + rawfil[len] = 0; /*stringify*/ + argc--; argv++; + } else { + printf("option -%c requires a filename argument\n",c); + rv = ERR_BAD_PARAM; + } + break; + case 's': /* get sensor file from optarg */ + if (argc > 1) { /*next argv is filename*/ + FILE *fp; + len = strlen_(argv[1]); + if (len >= sizeof(sensfil)) + len = sizeof(sensfil) - 1; + strncpy(sensfil,argv[1],len); + sensfil[len] = 0; /*stringify*/ + fp = fopen(sensfil,"r"); + if (fp == NULL) { + printf("cannot open file %s\n",sensfil); + rv = ERR_FILE_OPEN; + } else fclose(fp); + argc--; argv++; + } else { + printf("option -%c requires a filename argument\n",c); + rv = ERR_BAD_PARAM; + } + fsensdesc = 2; + break; +#if defined(METACOMMAND) + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'V': /* priv level */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + if (c == 'Y' || c == 'E') p = NULL; + else if (argc <= 1) { + printf("option -%c requires an argument\n",c); + rv = ERR_BAD_PARAM; + } else { /* has an optarg */ + p = argv[1]; + argc--; argv++; + } + if (rv == 0) parse_lan_options(c,p,fdebug); + break; +#endif + default: /*unknown option*/ + printf("Unknown option -%c\n",c); + show_usage(); + rv = ERR_USAGE; + goto do_exit; + break; + } + argc--; argv++; + } /*end while options*/ + + len = argc; /*number of data bytes*/ + if (!fPET && len > 16) len = 16; /* IPMI event max is 16 */ + if (frawfile || fhexfile) len = 0; + else if (fnewevt) { + if (len < 9) { + printf("Need 9 bytes for a New event, got %d bytes input\n",len); + show_usage(); + rv = ERR_BAD_PARAM; + } + } else if (len < 16) { + printf("Need 16 bytes for an IPMI event, got %d bytes input\n",len); + show_usage(); + rv = ERR_BAD_PARAM; + } + if (rv != 0) goto do_exit; + +#ifndef ALONE + if (fgetdevid || fsensdesc) + rv = ipmi_getdeviceid( devid, sizeof(devid),fdebug); /*sets mfgid*/ +#endif + + for (i = 0; i < len; i++) + { + if (fPET) msg[i] = _htoi(argv[i]); + else buf[i] = _htoi(argv[i]); + } + if (fPET != 0) /*PET, reorder bytes to std event format*/ + { + uchar snum, styp; + int timestamp; + int yrs, time2; + char sensdesc[100]; + int mfg; + + pmsg = &msg[pet_guid]; /*pet_guid=8, skip the GUID*/ + if (fdebug) { + printf("decoding IPMI PET event bytes\n"); + dump_buf("PET buffer",msg,len,1); + } + /* pmsg[ 9] is event source type (gen id, usu 0x20) */ + /* pmsg[10] is event severity */ + /* pmsg[11] is sensor device */ + /* pmsg[12] is sensor number */ + /* pmsg[13] is Entity */ + snum = pmsg[12]; + styp = entity2sensor_type(pmsg[13]); + rv = get_sensdesc(pmsg[9],snum,sensdesc,&i,NULL); + if (rv == 0) { + styp = (uchar)i; + if (fdebug) printf("sensor[%02x]: %s\n",snum,sensdesc); + set_sel_opts(2,0, NULL,fdebug,futc); + } else { + if (rv == ERR_NOT_FOUND) { + printf("Cannot find snum %02x in %s\n",snum,sensfil); + printf("Resolve this by doing 'ipmiutil sensor >sensorX.txt' " + "on a system similar\nto the target, then use " + "'ipmiutil events -s sensorX.txt ...'\n"); + } + /* Try GetSensorType(), which will work if local IPMI. */ + rv = GetSensorType(snum,&b,NULL); + if (fdebug) printf("sensor[%02x]: GetSensorType rv=%d stype=%x\n", + snum,rv,b); + if (rv == 0) styp = b; + } + + buf[0] = pmsg[1]; /*record id (sequence num)*/ + buf[1] = 0; /* was pmsg[0]; */ + buf[2] = 0x02; /*event type*/ +#ifdef RAW + buf[3] = pmsg[5]; /*timestamp*/ + buf[4] = pmsg[4]; /*timestamp*/ + buf[5] = pmsg[3]; /*timestamp*/ + buf[6] = pmsg[2]; /*timestamp*/ +#else + timestamp = pmsg[5] + (pmsg[4] << 8) + (pmsg[3] << 16) + (pmsg[2] << 24); + /* add 28 years, includes 7 leap days, less 1 hour TZ fudge */ + // yrs = ((3600 * 24) * 365 * 28) + (7 * (3600 * 24)) - 3600; + yrs = 0x34aace70; + time2 = timestamp + yrs; + if (fdebug) + printf("timestamp: %08x + %08x = %08x\n",timestamp,yrs,time2); + buf[3] = time2 & 0x000000ff; /*timestamp*/ + buf[4] = (time2 & 0x0000ff00) >> 8; /*timestamp*/ + buf[5] = (time2 & 0x00ff0000) >> 16; /*timestamp*/ + buf[6] = (time2 & 0xff000000) >> 24; /*timestamp*/ +#endif + buf[7] = pmsg[9]; /*generator_id*/ + buf[8] = 0; + buf[9] = 0x04; /*evm_rev*/ + buf[10] = styp; /*derived sensor type, from above */ + buf[11] = snum; /*sensor number*/ + /* set the event trigger based on context */ + switch(styp) { /*set the event trigger*/ + case 0x12: buf[12] = 0x6f; break; /*system event (sensor-specific)*/ + case 0x09: buf[12] = 0x0b; break; /*Power Unit*/ + case 0x01: /*temp*/ + case 0x02: /*voltage*/ + case 0x03: /*current*/ + case 0x04: /*fan*/ + if (pmsg[10] == 0x04) buf[12] = 0x81; /*info severity, ok*/ + else buf[12] = 0x01; /* threshold asserted*/ + break; + default: + buf[12] = pmsg[14]; /*event trigger = Entity Instance */ + /*Note that Entity Instance will not match an event trigger*/ + buf[12] = 0x6f; /*set trigger to sensor-specific*/ + break; + } + memcpy(&buf[13],&pmsg[15],3); /*event data*/ + mfg = pmsg[27] + (pmsg[26] << 8) + (pmsg[25] << 16); + if (fdebug) { + printf("PET severity=%02x, mfgId=%02x%02x%02x%02x\n", + pmsg[10], pmsg[24], pmsg[25], pmsg[26], pmsg[27]); + dump_buf("IPMI event",buf,16,0); + } + if (mfg == VENDOR_SUN) { /* Sun = 0x00002A, extra OEM data */ + j = 28 + pet_guid; /*offset 28+16=44 (OEM data) */ + pmsg = &msg[j]; + for (i = 0; (i+j) < len; ) { + if (pmsg[i] == 0xC1) break; + if (i == 0) i += 2; /* 2-byte header 0x0c 0x01 */ + else if (pmsg[i] == 0x80) { /* 3-byte header, usu strings */ + if (pmsg[i+2] == 0x03) printf(" %s\n",&pmsg[i+3]); + i += (3 + pmsg[i+1]); + } else i++; + } + } + decode_sel_entry(buf,msg,sizeof(msg)); + printf("%s", evt_hdr); /*"RecId Date/Time_______*/ + printf("%s", msg); + } else if (fnewevt) { + rv = new_event(buf,len); /*do new platform event*/ + } else if (frawfile) { + rv = decode_raw_sel(rawfil,1); /*ascii raw data from file */ + } else if (fhexfile) { + rv = decode_raw_sel(rawfil,2); /*binary/hex raw data from file*/ + } else { + if (fdebug) printf("decoding standard IPMI event bytes\n"); + if (fdebug) dump_buf("IPMI event",buf,16,0); + set_sel_opts(2,0, NULL,fdebug,futc); + rv = decode_sel_entry(buf,msg,sizeof(msg)); + /* show header for the event record */ + printf("%s", evt_hdr); /*"RecId Date/Time_______*/ + printf("%s", msg); + } +do_exit: +#ifndef METACOMMAND + printf("%s, %s\n",progname,decode_rv(rv)); +#endif + return(rv); +} +// #endif + +/* end ievents.c */ diff --git a/util/ievents.h b/util/ievents.h new file mode 100644 index 0000000..71bc449 --- /dev/null +++ b/util/ievents.h @@ -0,0 +1,64 @@ +/* + * ievents.h + * + * Author: Andy Cress arcress at users.sourceforge.net + * Copyright (c) 2011 Kontron America, Inc. + * + * 12/12/11 Andy Cress - created + */ +/*M* +Copyright (c) 2011 Kontron America, 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: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions 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. + c.. Neither the name of Kontron nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ + +/* Public routines from ievents.c */ +int decode_sel_entry( uchar *psel, char *outbuf, int sz); +char *decode_entity_id(int id); +char *get_sensor_type_desc(uchar stype); +char *get_sev_str(int val); +void fmt_time(time_t etime, char *buf, int bufsz); +int get_sensor_tag(int isdr, int genid, uchar snum, char *tag, + uchar *sdr, int szsdr); +void format_event(ushort id, time_t timestamp, int sevid, ushort genid, + char *ptype, uchar snum, char *psens, char *pstr, char *more, + char *outbuf, int outsz); +/* + * set_sel_opts is used to specify options for showing/decoding SEL events. + * sensdesc : 0 = simple, no sensor descriptions + * 1 = get sensor descriptions from sdr cache + * 2 = get sensor descriptions from sensor file (-s) + * canon : 0 = normal output + * 1 = canonical, delimited output + * sdrs : NULL = no sdr cache, dynamically get sdr cache if sensdesc==1 + * ptr = use this pointer as existing sdr cache if sensdesc==1 + * fdbg : 0 = normal mode + * 1 = debug mode + * futc : 0 = normal mode + * 1 = show raw UTC time + */ +void set_sel_opts(int sensdsc, int canon, void *sdrs, char fdbg, char futc); + +/*end ievents.h*/ diff --git a/util/ifirewall.c b/util/ifirewall.c new file mode 100644 index 0000000..b92d7d5 --- /dev/null +++ b/util/ifirewall.c @@ -0,0 +1,1154 @@ +/* + * ifirewall.c + * Handle firmware firewall IPMI command functions + * + * Change history: + * 06/04/2010 ARCress - included in source tree + * + *--------------------------------------------------------------------- + * Copyright (c) 2010 Kontron America Inc. All Rights Reserved, + * Copyright (c) 2005 International Business Machines, Inc. All Rights Reserved + * 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. + *--------------------------------------------------------------------- + */ +#ifdef WIN32 +#include +#include +#include +#include +#include "getopt.h" +#else +#include +#include +#include +#include +#if defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include +#else +#include +#endif +#endif +#include "ipmicmd.h" +#include "ifirewall.h" + +/* global variables */ +static char * progname = "ifirewall"; +static char * progver = "2.93"; +static char fdebug = 0; +static uchar g_bus = PUBLIC_BUS; +static uchar g_sa = BMC_SA; +static uchar g_lun = BMC_LUN; +static uchar g_addrtype = ADDR_SMI; +extern int verbose; /*see ipmilanplus.c*/ + +extern void lprintf(int level, const char * format, ...); /*ipmilanplus.c*/ + +static void +printf_firewall_usage(void) +{ + printf("Firmware Firewall Commands:\n"); + printf("\tinfo [channel H] [lun L]\n"); + printf("\tinfo [channel H] [lun L [netfn N [command C [subfn S]]]]\n"); + printf("\tenable [channel H] [lun L [netfn N [command C [subfn S]]]]\n"); + printf("\tdisable [channel H] [lun L [netfn N [command C [subfn S]]]] [force])\n"); + printf("\treset [channel H] \n"); + printf("\t\twhere H is a Channel, L is a LUN, N is a NetFn,\n"); + printf("\t\tC is a Command and S is a Sub-Function\n"); +} + +// print n bytes of bit field bf (if invert, print ~bf) +static void print_bitfield(const unsigned char * bf, int n, int invert, int loglevel) { + int i = 0; + if (loglevel < 0) { + while (ichannel = atob(argv[i]); + } + else if (strncmp(argv[i], "lun", 3) == 0) { + if (++i < argc) + p->lun = atob(argv[i]); + } + else if (strncmp(argv[i], "force", 5) == 0) { + p->force = 1; + } + else if (strncmp(argv[i], "netfn", 5) == 0) { + if (++i < argc) + p->netfn = atob(argv[i]); + } + else if (strncmp(argv[i], "command", 7) == 0) { + if (++i < argc) + p->command = atob(argv[i]); + } + else if (strncmp(argv[i], "subfn", 5) == 0) { + if (++i < argc) + p->subfn = atob(argv[i]); + } + } + if (p->subfn >= MAX_SUBFN) { + printf("subfn is out of range (0-%d)\n", MAX_SUBFN-1); + return -1; + } + if (p->command >= MAX_COMMAND) { + printf("command is out of range (0-%d)\n", MAX_COMMAND-1); + return -1; + } + if (p->netfn >= MAX_NETFN) { + printf("netfn is out of range (0-%d)\n", MAX_NETFN-1); + return -1; + } + if (p->lun >= MAX_LUN) { + printf("lun is out of range (0-%d)\n", MAX_LUN-1); + return -1; + } + if (p->netfn >= 0 && p->lun < 0) { + printf("if netfn is set, lun must be set also\n"); + return -1; + } + if (p->command >= 0 && p->netfn < 0) { + printf("if command is set, netfn must be set also\n"); + return -1; + } + if (p->subfn >= 0 && p->command < 0) { + printf("if subfn is set, command must be set also\n"); + return -1; + } + return 0; +} + +/* _get_netfn_suport + * + * @intf: ipmi interface + * @channel: ipmi channel + * @lun: a pointer to a 4 byte field + * @netfn: a pointer to a 128-bit bitfield (16 bytes) + * + * returns 0 on success and fills in the bitfield for + * the 32 netfn * 4 LUN pairs that support commands + * returns -1 on error + */ +static int +_get_netfn_support(void * intf, int channel, unsigned char * lun, unsigned char * netfn) +{ + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + unsigned char * d, rqdata; + unsigned int l; + + if (!lun || !netfn) { + lprintf(LOG_ERR, "_get_netfn_suport: lun or netfn is NULL"); + return -1; + } + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = BMC_GET_NETFN_SUPPORT; + rqdata = (unsigned char) channel; + req.msg.data = &rqdata; + req.msg.data_len = 1; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Get NetFn Support command failed: %d (0x%02x)\n",rv,rv); + return(rv); + } + + d = &rsp[0]; + for (l=0; l<4; l++) { + lun[l] = (*d)>>(2*l) & 0x3; + } + d++; + + memcpy(netfn, d, 16); + + return 0; +} + +/* _get_command_suport + * + * @intf: ipmi interface + * @p: a pointer to a struct ipmi_function_params + * @lnfn: a pointer to a struct lun_netfn_support + * + * returns 0 on success and fills in lnfn according to the request in p + * returns -1 on error + */ +static int +_get_command_support(void * intf, + struct ipmi_function_params * p, struct lun_netfn_support * lnfn) +{ + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + unsigned char * d, rqdata[3]; + unsigned int c; + + if (!p || !lnfn) { + lprintf(LOG_ERR, "_get_command_suport: p or lnfn is NULL"); + return -1; + } + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = BMC_GET_COMMAND_SUPPORT; + rqdata[0] = (unsigned char)p->channel; + rqdata[1] = (unsigned char)p->netfn; + rqdata[2] = (unsigned char)p->lun; + req.msg.data = rqdata; + req.msg.data_len = 3; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Get Command Support (LUN=%d, NetFn=%d, op=0) command failed: %d (0x%02x)\n", p->lun, p->netfn, rv,rv); + return(rv); + } + + d = &rsp[0]; + for (c=0; c<128; c++) { + if (!(d[c>>3] & (1<<(c%8)))) + lnfn->command[c].support |= BIT_AVAILABLE; + } + memcpy(lnfn->command_mask, d, MAX_COMMAND_BYTES/2); + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = BMC_GET_COMMAND_SUPPORT; + rqdata[0] = (unsigned char)p->channel; + rqdata[1] = (unsigned char)(0x40 | p->netfn); + rqdata[2] = (unsigned char)p->lun; + req.msg.data = rqdata; + req.msg.data_len = 3; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Get Command Support (LUN=%d, NetFn=%d, op=1) command failed: %d (0x%02x)\n", p->lun, p->netfn, rv,rv); + return(rv); + } + + d = &rsp[0]; + for (c=0; c<128; c++) { + if (!(d[c>>3] & (1<<(c%8)))) + lnfn->command[128+c].support |= BIT_AVAILABLE; + } + memcpy(lnfn->command_mask+MAX_COMMAND_BYTES/2, d, MAX_COMMAND_BYTES/2); + return 0; +} + +/* _get_command_configurable + * + * @intf: ipmi interface + * @p: a pointer to a struct ipmi_function_params + * @lnfn: a pointer to a struct lun_netfn_support + * + * returns 0 on success and fills in lnfn according to the request in p + * returns -1 on error + */ +static int +_get_command_configurable(void * intf, + struct ipmi_function_params * p, struct lun_netfn_support * lnfn) +{ + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + unsigned char * d, rqdata[3]; + unsigned int c; + + if (!p || !lnfn) { + lprintf(LOG_ERR, "_get_command_configurable: p or lnfn is NULL"); + return -1; + } + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = BMC_GET_CONFIGURABLE_COMMANDS; + rqdata[0] = (unsigned char)p->channel; + rqdata[1] = (unsigned char)p->netfn; + rqdata[2] = (unsigned char)p->lun; + req.msg.data = rqdata; + req.msg.data_len = 3; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Get Configurable Command (LUN=%d, NetFn=%d, op=0) command failed: %d (0x%02x)\n", p->lun, p->netfn, rv,rv); + return(rv); + } + + d = rsp; + for (c=0; c<128; c++) { + if (d[c>>3] & (1<<(c%8))) + lnfn->command[c].support |= BIT_CONFIGURABLE; + } + memcpy(lnfn->config_mask, d, MAX_COMMAND_BYTES/2); + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = BMC_GET_CONFIGURABLE_COMMANDS; + rqdata[0] = (unsigned char) p->channel; + rqdata[1] = (unsigned char)(0x40 | p->netfn); + rqdata[2] = (unsigned char)p->lun; + req.msg.data = rqdata; + req.msg.data_len = 3; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Get Configurable Command (LUN=%d, NetFn=%d, op=1) command failed: %d (0x%02x)\n", p->lun, p->netfn, rv,rv); + return(rv); + } + + d = rsp; + for (c=0; c<128; c++) { + if (d[c>>3] & (1<<(c%8))) + lnfn->command[128+c].support |= BIT_CONFIGURABLE; + } + memcpy(lnfn->config_mask+MAX_COMMAND_BYTES/2, d, MAX_COMMAND_BYTES/2); + return 0; +} + +/* _get_command_enables + * + * @intf: ipmi interface + * @p: a pointer to a struct ipmi_function_params + * @lnfn: a pointer to a struct lun_netfn_support + * + * returns 0 on success and fills in lnfn according to the request in p + * returns -1 on error + */ +static int +_get_command_enables(void * intf, + struct ipmi_function_params * p, struct lun_netfn_support * lnfn) +{ + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + unsigned char * d, rqdata[3]; + unsigned int c; + + if (!p || !lnfn) { + lprintf(LOG_ERR, "_get_command_enables: p or lnfn is NULL"); + return -1; + } + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = BMC_GET_COMMAND_ENABLES; + rqdata[0] = (unsigned char) p->channel; + rqdata[1] = (unsigned char)p->netfn; + rqdata[2] = (unsigned char)p->lun; + req.msg.data = rqdata; + req.msg.data_len = 3; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Get Command Enables (LUN=%d, NetFn=%d, op=0) command failed: %d (0x%02x)\n", p->lun, p->netfn, rv,rv); + return(rv); + } + + d = rsp; + for (c=0; c<128; c++) { + if (d[c>>3] & (1<<(c%8))) + lnfn->command[c].support |= BIT_ENABLED; + } + memcpy(lnfn->enable_mask, d, MAX_COMMAND_BYTES/2); + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = BMC_GET_COMMAND_ENABLES; + rqdata[0] = (unsigned char) p->channel; + rqdata[1] = (unsigned char)(0x40 | p->netfn); + rqdata[2] = (unsigned char)p->lun; + req.msg.data = rqdata; + req.msg.data_len = 3; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Get Command Enables (LUN=%d, NetFn=%d, op=1) command failed: %d (0x%02x)\n", p->lun, p->netfn, rv,rv); + return(rv); + } + + d = rsp; + for (c=0; c<128; c++) { + if (d[c>>3] & (1<<(c%8))) + lnfn->command[128+c].support |= BIT_ENABLED; + } + memcpy(lnfn->enable_mask+MAX_COMMAND_BYTES/2, d, MAX_COMMAND_BYTES/2); + return 0; +} + +/* _set_command_enables + * + * @intf: ipmi interface + * @p: a pointer to a struct ipmi_function_params + * @lnfn: a pointer to a struct lun_netfn_support that contains current info + * @enable: a pointer to a 32 byte bitfield that contains the desired enable state + * @gun: here is a gun to shoot yourself in the foot. If this is true + * you are allowed to disable this command + * + * returns 0 on success + * returns -1 on error + */ +static int +_set_command_enables(void * intf, + struct ipmi_function_params * p, struct lun_netfn_support * lnfn, + unsigned char * enable, int gun) +{ + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + unsigned char * d, rqdata[19]; + unsigned int c; + + if (!p || !lnfn) { + lprintf(LOG_ERR, "_set_command_enables: p or lnfn is NULL"); + return -1; + } + + lprintf(LOG_INFO, "support: "); + print_bitfield(lnfn->command_mask, MAX_COMMAND_BYTES, 1, LOG_INFO); + lprintf(LOG_INFO, "configurable: "); + print_bitfield(lnfn->config_mask, MAX_COMMAND_BYTES, 0, LOG_INFO); + lprintf(LOG_INFO, "enabled: "); + print_bitfield(lnfn->enable_mask, MAX_COMMAND_BYTES, 0, LOG_INFO); + lprintf(LOG_INFO, "enable mask before: "); + print_bitfield(enable, MAX_COMMAND_BYTES, 0, LOG_INFO); + + // mask off the appropriate bits (if not configurable, set enable bit + // must be the same as the current enable bit) + for (c=0; c<(MAX_COMMAND_BYTES); c++) { + enable[c] = (lnfn->config_mask[c] & enable[c]) | + (~lnfn->config_mask[c] & lnfn->enable_mask[c]); + } + + // take the gun out of their hand if they are not supposed to have it + if (!gun) { + enable[SET_COMMAND_ENABLE_BYTE] = + (lnfn->config_mask[SET_COMMAND_ENABLE_BYTE] + & SET_COMMAND_ENABLE_BIT) | + (~lnfn->config_mask[SET_COMMAND_ENABLE_BYTE] + & lnfn->enable_mask[SET_COMMAND_ENABLE_BYTE]); + } + lprintf(LOG_INFO, "enable mask after: "); + print_bitfield(enable, MAX_COMMAND_BYTES, 0, LOG_INFO); + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = BMC_SET_COMMAND_ENABLES; + rqdata[0] = (unsigned char) p->channel; + rqdata[1] = (unsigned char)p->netfn; + rqdata[2] = (unsigned char)p->lun; + memcpy(&rqdata[3], enable, MAX_COMMAND_BYTES/2); + req.msg.data = rqdata; + req.msg.data_len = 19; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Set Command Enables (LUN=%d, NetFn=%d, op=0) command failed: %d (0x%02x)\n", p->lun, p->netfn, rv,rv); + return(rv); + } + d = &rsp[0]; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = BMC_SET_COMMAND_ENABLES; + rqdata[0] = (unsigned char) p->channel; + rqdata[1] = (unsigned char)(0x40 | p->netfn); + rqdata[2] = (unsigned char)p->lun; + memcpy(&rqdata[3], enable+MAX_COMMAND_BYTES/2, MAX_COMMAND_BYTES/2); + req.msg.data = rqdata; + req.msg.data_len = 19; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Set Command Enables (LUN=%d, NetFn=%d, op=1) command failed: %d (0x%02x)\n", p->lun, p->netfn, rv,rv); + return(rv); + } + d = &rsp[0]; + + return 0; +} + +/* _get_subfn_support + * + * @intf: ipmi interface + * @p: a pointer to a struct ipmi_function_params + * @cmd: a pointer to a struct command_support + * + * returns 0 on success and fills in cmd according to the request in p + * returns -1 on error + */ +static int +_get_subfn_support(void * intf, + struct ipmi_function_params * p, struct command_support * cmd) +{ + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + unsigned char rqdata[4]; + + if (!p || !cmd) { + lprintf(LOG_ERR, "_get_subfn_support: p or cmd is NULL"); + return -1; + } + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = BMC_GET_COMMAND_SUBFUNCTION_SUPPORT; + rqdata[0] = (unsigned char) p->channel; + rqdata[1] = (unsigned char)p->netfn; + rqdata[2] = (unsigned char)p->lun; + rqdata[3] = (unsigned char)p->command; + req.msg.data = rqdata; + req.msg.data_len = 4; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Get Command Subfunction Support (LUN=%d, NetFn=%d, cmd=%d) command failed: %d (0x%02x)\n", p->lun, p->netfn, p->command, rv,rv); + return(rv); + } + + memcpy(cmd->subfn_support, rsp, sizeof(cmd->subfn_support)); + return 0; +} + +/* _get_subfn_configurable + * + * @intf: ipmi interface + * @p: a pointer to a struct ipmi_function_params + * @cmd: a pointer to a struct command_support + * + * returns 0 on success and fills in cmd according to the request in p + * returns -1 on error + */ +static int +_get_subfn_configurable(void * intf, + struct ipmi_function_params * p, struct command_support * cmd) +{ + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + unsigned char rqdata[4]; + + if (!p || !cmd) { + lprintf(LOG_ERR, "_get_subfn_configurable: p or cmd is NULL"); + return -1; + } + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = BMC_GET_CONFIGURABLE_COMMAND_SUBFUNCTIONS; + rqdata[0] = (unsigned char) p->channel; + rqdata[1] = (unsigned char)p->netfn; + rqdata[2] = (unsigned char)p->lun; + rqdata[3] = (unsigned char)p->command; + req.msg.data = rqdata; + req.msg.data_len = 4; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Get Configurable Command Subfunction Support (LUN=%d, NetFn=%d, cmd=%d) command failed: %d (0x%02x)\n", p->lun, p->netfn, p->command, rv,rv); + return(rv); + } + + memcpy(cmd->subfn_config, rsp, sizeof(cmd->subfn_config)); + return 0; +} + +/* _get_subfn_enables + * + * @intf: ipmi interface + * @p: a pointer to a struct ipmi_function_params + * @cmd: a pointer to a struct command_support + * + * returns 0 on success and fills in cmd according to the request in p + * returns -1 on error + */ +static int +_get_subfn_enables(void * intf, + struct ipmi_function_params * p, struct command_support * cmd) +{ + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + unsigned char rqdata[4]; + + if (!p || !cmd) { + lprintf(LOG_ERR, "_get_subfn_enables: p or cmd is NULL"); + return -1; + } + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = BMC_GET_COMMAND_SUBFUNCTION_ENABLES; + rqdata[0] = (unsigned char) p->channel; + rqdata[1] = (unsigned char)p->netfn; + rqdata[2] = (unsigned char)p->lun; + rqdata[3] = (unsigned char)p->command; + req.msg.data = rqdata; + req.msg.data_len = 4; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Get Command Subfunction Enables (LUN=%d, NetFn=%d, cmd=%d) command failed: %d (0x%02x)\n", p->lun, p->netfn, p->command, rv,rv); + return(rv); + } + + memcpy(cmd->subfn_enable, rsp, sizeof(cmd->subfn_enable)); + return 0; +} + +/* _set_subfn_enables + * + * @intf: ipmi interface + * @p: a pointer to a struct ipmi_function_params + * @cmd: a pointer to a struct command_support + * @enable: a pointer to a 4 byte bitfield that contains the desired enable state + * + * returns 0 on success (and modifies enable to be the bits it actually set) + * returns -1 on error + */ +static int +_set_subfn_enables(void * intf, + struct ipmi_function_params * p, struct command_support * cmd, + unsigned char * enable) +{ + struct ipmi_rq req; + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + unsigned char rqdata[8]; + unsigned int c; + + if (!p || !cmd) { + lprintf(LOG_ERR, "_set_subfn_enables: p or cmd is NULL"); + return -1; + } + + lprintf(LOG_INFO, "support: "); + print_bitfield(cmd->subfn_support, MAX_SUBFN_BYTES, 1, LOG_INFO); + lprintf(LOG_INFO, "configurable: "); + print_bitfield(cmd->subfn_config, MAX_SUBFN_BYTES, 0, LOG_INFO); + lprintf(LOG_INFO, "enabled: "); + print_bitfield(cmd->subfn_enable, MAX_SUBFN_BYTES, 0, LOG_INFO); + lprintf(LOG_INFO, "enable mask before: "); + print_bitfield(enable, MAX_SUBFN_BYTES, 0, LOG_INFO); + // mask off the appropriate bits (if not configurable, set enable bit + // must be the same as the current enable bit) + for (c=0; csubfn_enable); c++) { + enable[c] = (cmd->subfn_config[c] & enable[c]) | + (~cmd->subfn_config[c] & cmd->subfn_enable[c]); + } + lprintf(LOG_INFO, "enable mask after: "); + print_bitfield(enable, MAX_SUBFN_BYTES, 0, LOG_INFO); + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = BMC_SET_COMMAND_SUBFUNCTION_ENABLES; + rqdata[0] = (unsigned char) p->channel; + rqdata[1] = (unsigned char)p->netfn; + rqdata[2] = (unsigned char)p->lun; + rqdata[3] = (unsigned char)p->command; + memcpy(&rqdata[4], enable, MAX_SUBFN_BYTES); + req.msg.data = rqdata; + req.msg.data_len = 8; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Set Command Subfunction Enables (LUN=%d, NetFn=%d, cmd=%d) command failed: %d (0x%02x)\n", p->lun, p->netfn, p->command, rv,rv); + return(rv); + } + + return 0; +} + +/* _gather_info + * + * @intf: ipmi interface + * @p: a pointer to a struct ipmi_function_params + * @bmc: a pointer to a struct bmc_fn_support + * @enable: a pointer to a 4 byte bitfield that contains the desired enable state + * + * returns 0 on success and fills in bmc according to request p + * returns -1 on error + */ +static int _gather_info(void * intf, struct ipmi_function_params * p, struct bmc_fn_support * bmc) +{ + int ret, l, n; + unsigned char lun[MAX_LUN], netfn[16]; + + ret = _get_netfn_support(intf, p->channel, lun, netfn); + if (ret != 0) return (ret); + else { /*success*/ + for (l=0; llun >= 0 && p->lun != l) + continue; + bmc->lun[l].support = lun[l]; + if (lun[l]) { + for (n=0; nlun[l].netfn[n].support = + !!(netfn[offset>>3] & (1<<(offset%8))); + } + } + } + } + if (p->netfn >= 0) { + if (!((p->lun < 0 || bmc->lun[p->lun].support) && + (p->netfn < 0 || bmc->lun[p->lun].netfn[p->netfn>>1].support))) { + lprintf(LOG_ERR, "LUN or LUN/NetFn pair %d,%d not supported", p->lun, p->netfn); + return 0; + } + ret = _get_command_support(intf, p, &(bmc->lun[p->lun].netfn[p->netfn>>1])); + ret |= _get_command_configurable(intf, p, &(bmc->lun[p->lun].netfn[p->netfn>>1])); + ret |= _get_command_enables(intf, p, &(bmc->lun[p->lun].netfn[p->netfn>>1])); + if (!ret && p->command >= 0) { + ret = _get_subfn_support(intf, p, + &(bmc->lun[p->lun].netfn[p->netfn>>1].command[p->command])); + ret |= _get_subfn_configurable(intf, p, + &(bmc->lun[p->lun].netfn[p->netfn>>1].command[p->command])); + ret |= _get_subfn_enables(intf, p, + &(bmc->lun[p->lun].netfn[p->netfn>>1].command[p->command])); + } + } + else if (p->lun >= 0) { + l = p->lun; + if (bmc->lun[l].support) { + for (n=0; nnetfn = n*2; + if (bmc->lun[l].netfn[n].support) { + ret = _get_command_support(intf, p, &(bmc->lun[l].netfn[n])); + ret |= _get_command_configurable(intf, p, &(bmc->lun[l].netfn[n])); + ret |= _get_command_enables(intf, p, &(bmc->lun[l].netfn[n])); + } + if (ret) + bmc->lun[l].netfn[n].support = 0; + } + } + p->netfn = -1; + } else { + for (l=0; l<4; l++) { + p->lun = l; + if (bmc->lun[l].support) { + for (n=0; nnetfn = n*2; + if (bmc->lun[l].netfn[n].support) { + ret = _get_command_support(intf, p, &(bmc->lun[l].netfn[n])); + ret |= _get_command_configurable(intf, p, &(bmc->lun[l].netfn[n])); + ret |= _get_command_enables(intf, p, &(bmc->lun[l].netfn[n])); + } + if (ret) + bmc->lun[l].netfn[n].support = 0; + } + } + } + p->lun = -1; + p->netfn = -1; + } + + return 0; +} + +/* ipmi_firewall_info - print out info for firewall functions + * + * @intf: ipmi inteface + * @argc: argument count + * @argv: argument list + * + * returns 0 on success + * returns -1 on error + */ +static int +ipmi_firewall_info(void * intf, int argc, char ** argv) +{ + int ret = 0; + struct ipmi_function_params p = {0xe, -1, -1, -1, -1}; + struct bmc_fn_support * bmc_fn_support; + unsigned int l, n, c; + + if ((argc > 0 && strncmp(argv[0], "help", 4) == 0) || ipmi_firewall_parse_args(argc, argv, &p) < 0) + { + printf("info [channel H]\n"); + printf("\tlist all of the firewall information for all LUNs, NetFns, and Commands\n"); + printf("\tthis is a long list and is not very human readable\n"); + printf("info [channel H] lun L\n"); + printf("\tthis also prints a long list that is not very human readable\n"); + printf("info [channel H] lun L netfn N\n"); + printf("\tthis prints out information for a single LUN/NetFn pair\n"); + printf("\tthat is not really very usable, but at least it is short\n"); + printf("info [channel H] lun L netfn N command C\n"); + printf("\tthis is the one you want -- it prints out detailed human\n"); + printf("\treadable information. It shows the support, configurable, and\n"); + printf("\tenabled bits for the Command C on LUN/NetFn pair L,N and the\n"); + printf("\tsame information about each of its Sub-functions\n"); + return 0; + } + + bmc_fn_support = malloc(sizeof(struct bmc_fn_support)); + if (!bmc_fn_support) { + lprintf(LOG_ERR, "malloc struct bmc_fn_support failed"); + return -1; + } + + ret = _gather_info(intf, &p, bmc_fn_support); + + if (p.command >= 0) { + struct command_support * cmd; + if (!((p.lun < 0 || bmc_fn_support->lun[p.lun].support) && + (p.netfn < 0 || bmc_fn_support->lun[p.lun].netfn[p.netfn>>1].support) && + bmc_fn_support->lun[p.lun].netfn[p.netfn>>1].command[p.command].support)) + { + lprintf(LOG_ERR, "Command 0x%02x not supported on LUN/NetFn pair %02x,%02x", + p.command, p.lun, p.netfn); + free(bmc_fn_support); + return 0; + } + cmd = + &bmc_fn_support->lun[p.lun].netfn[p.netfn>>1].command[p.command]; + c = cmd->support; + printf("(A)vailable, (C)onfigurable, (E)nabled: | A | C | E |\n"); + printf("-----------------------------------------------------\n"); + printf("LUN %01d, NetFn 0x%02x, Command 0x%02x: | %c | %c | %c |\n", + p.lun, p.netfn, p.command, + (c & BIT_AVAILABLE) ? 'X' : ' ', + (c & BIT_CONFIGURABLE) ? 'X' : ' ', + (c & BIT_ENABLED) ? 'X': ' '); + + for (n=0; nsubfn_support, n)) ? 'X' : ' ', + (bit_test(cmd->subfn_config, n)) ? 'X' : ' ', + (bit_test(cmd->subfn_enable, n)) ? 'X' : ' '); + } + } + else if (p.netfn >= 0) { + if (!((p.lun < 0 || bmc_fn_support->lun[p.lun].support) && + (bmc_fn_support->lun[p.lun].netfn[p.netfn>>1].support))) + { + lprintf(LOG_ERR, "LUN or LUN/NetFn pair %02x,%02x not supported", + p.lun, p.netfn); + free(bmc_fn_support); + return 0; + } + n = p.netfn >> 1; + l = p.lun; + printf("Commands on LUN 0x%02x, NetFn 0x%02x\n", p.lun, p.netfn); + printf("support: "); + print_bitfield(bmc_fn_support->lun[l].netfn[n].command_mask, + MAX_COMMAND_BYTES, 1, -1); + printf("configurable: "); + print_bitfield(bmc_fn_support->lun[l].netfn[n].config_mask, + MAX_COMMAND_BYTES, 0, -1); + printf("enabled: "); + print_bitfield(bmc_fn_support->lun[l].netfn[n].enable_mask, + MAX_COMMAND_BYTES, 0, -1); + } + else { + for (l=0; l<4; l++) { + p.lun = l; + if (bmc_fn_support->lun[l].support) { + for (n=0; nlun[l].netfn[n].support) { + printf("%02x,%02x support: ", p.lun, p.netfn); + print_bitfield(bmc_fn_support->lun[l].netfn[n].command_mask, + MAX_COMMAND_BYTES, 1, -1); + printf("%02x,%02x configurable: ", p.lun, p.netfn); + print_bitfield(bmc_fn_support->lun[l].netfn[n].config_mask, + MAX_COMMAND_BYTES, 0, -1); + printf("%02x,%02x enabled: ", p.lun, p.netfn); + print_bitfield(bmc_fn_support->lun[l].netfn[n].enable_mask, + MAX_COMMAND_BYTES, 0, -1); + } + } + } + } + p.lun = -1; + p.netfn = -1; + } + + free(bmc_fn_support); + return ret; +} + +/* ipmi_firewall_enable_disable - enable/disable BMC functions + * + * @intf: ipmi inteface + * @enable: whether to enable or disable + * @argc: argument count + * @argv: argument list + * + * returns 0 on success + * returns -1 on error + */ +static int +ipmi_firewall_enable_disable(void * intf, int enable, int argc, char ** argv) +{ + struct ipmi_function_params p = {0xe, -1, -1, -1, -1}; + struct bmc_fn_support * bmc_fn_support; + unsigned int l, n, c; + int ret; + unsigned char enables[MAX_COMMAND_BYTES]; + + if (argc < 1 || strncmp(argv[0], "help", 4) == 0) { + char * s1 = enable?"en":"dis"; + char * s2 = enable?"":" [force]"; + printf("%sable [channel H] lun L netfn N%s\n", s1, s2); + printf("\t%sable all commands on this LUN/NetFn pair\n", s1); + printf("%sable [channel H] lun L netfn N command C%s\n", s1, s2); + printf("\t%sable Command C and all its Sub-functions for this LUN/NetFn pair\n", s1); + printf("%sable [channel H] lun L netfn N command C subfn S\n", s1); + printf("\t%sable Sub-function S for Command C for this LUN/NetFn pair\n", s1); + if (!enable) { + printf("* force will allow you to disable the \"Command Set Enable\" command\n"); + printf("\tthereby letting you shoot yourself in the foot\n"); + printf("\tthis is only recommended for advanced users\n"); + } + return 0; + } + if (ipmi_firewall_parse_args(argc, argv, &p) < 0) + return -1; + + bmc_fn_support = malloc(sizeof(struct bmc_fn_support)); + if (!bmc_fn_support) { + lprintf(LOG_ERR, "malloc struct bmc_fn_support failed"); + return -1; + } + + ret = _gather_info(intf, &p, bmc_fn_support); + if (ret < 0) { + free(bmc_fn_support); + return ret; + } + + l = p.lun; + n = p.netfn>>1; + c = p.command; + if (p.subfn >= 0) { + // firewall (en|dis)able [channel c] lun l netfn n command m subfn s + // (en|dis)able this sub-function for this commnad on this lun/netfn pair + memcpy(enables, + bmc_fn_support->lun[l].netfn[n].command[c].subfn_enable, + MAX_SUBFN_BYTES); + bit_set(enables, p.subfn, enable); + ret = _set_subfn_enables(intf, &p, + &bmc_fn_support->lun[l].netfn[n].command[c], enables); + + } else if (p.command >= 0) { + // firewall (en|dis)able [channel c] lun l netfn n command m + // (en|dis)able all subfn and command for this commnad on this lun/netfn pair + memset(enables, enable?0xff:0, MAX_SUBFN_BYTES); + ret = _set_subfn_enables(intf, &p, + &bmc_fn_support->lun[l].netfn[n].command[c], enables); + memcpy(enables, + &bmc_fn_support->lun[l].netfn[n].enable_mask, sizeof(enables)); + bit_set(enables, p.command, enable); + ret |= _set_command_enables(intf, &p, + &bmc_fn_support->lun[l].netfn[n], enables, p.force); + } else if (p.netfn >= 0) { + // firewall (en|dis)able [channel c] lun l netfn n + // (en|dis)able all commnads on this lun/netfn pair + memset(enables, enable?0xff:0, sizeof(enables)); + ret = _set_command_enables(intf, &p, + &bmc_fn_support->lun[l].netfn[n], enables, p.force); + /* + } else if (p.lun >= 0) { + // firewall (en|dis)able [channel c] lun l + // (en|dis)able all commnads on all netfn pairs for this lun + */ + } + free(bmc_fn_support); + return ret; +} + +/* ipmi_firewall_reset - reset firmware firewall to enable everything + * + * @intf: ipmi inteface + * @argc: argument count + * @argv: argument list + * + * returns 0 on success + * returns -1 on error + */ +static int +ipmi_firewall_reset(void * intf, int argc, char ** argv) +{ + struct ipmi_function_params p = {0xe, -1, -1, -1, -1}; + struct bmc_fn_support * bmc_fn_support; + unsigned int l, n, c; + int ret; + unsigned char enables[MAX_COMMAND_BYTES]; + + if (argc > 0 || (argc > 0 && strncmp(argv[0], "help", 4) == 0)) { + printf_firewall_usage(); + return 0; + } + if (ipmi_firewall_parse_args(argc, argv, &p) < 0) + return -1; + + bmc_fn_support = malloc(sizeof(struct bmc_fn_support)); + if (!bmc_fn_support) { + lprintf(LOG_ERR, "malloc struct bmc_fn_support failed"); + return -1; + } + + ret = _gather_info(intf, &p, bmc_fn_support); + if (ret < 0) { + free(bmc_fn_support); + return ret; + } + + for (l=0; llun[l].netfn[n].command[c], enables); + } + printf("reset lun %d, netfn %d, command\n", l, n); + memset(enables, 0xff, sizeof(enables)); + ret = _set_command_enables(intf, &p, + &bmc_fn_support->lun[l].netfn[n], enables, 0); + } + } + + free(bmc_fn_support); + return ret; +} + +#ifdef METACOMMAND +int i_firewall(int argc, char **argv) +#else +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#endif +{ + void *intf = NULL; + int rc = 0; + int c, i; + char *s1; + + printf("%s ver %s\n", progname,progver); + + while ( (c = getopt( argc, argv,"m:T:V:J:EYF:P:N:R:U:Z:x?")) != EOF ) + switch (c) { + case 'm': /* specific IPMB MC, 3-byte address, e.g. "409600" */ + g_bus = htoi(&optarg[0]); /*bus/channel*/ + g_sa = htoi(&optarg[2]); /*device slave address*/ + g_lun = htoi(&optarg[4]); /*LUN*/ + g_addrtype = ADDR_IPMB; + if (optarg[6] == 's') { + g_addrtype = ADDR_SMI; s1 = "SMI"; + } else { g_addrtype = ADDR_IPMB; s1 = "IPMB"; } + ipmi_set_mc(g_bus,g_sa,g_lun,g_addrtype); + printf("Use MC at %s bus=%x sa=%x lun=%x\n", + s1,g_bus,g_sa,g_lun); + break; + case 'x': fdebug = 1; verbose = 1; + break; /* debug messages */ + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'V': /* priv level */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + break; + case '?': + printf_firewall_usage(); + return 0; + break; + } + for (i = 0; i < optind; i++) { argv++; argc--; } + + if (argc < 1 || strncmp(argv[0], "help", 4) == 0) { + printf_firewall_usage(); + } + else if (strncmp(argv[0], "info", 4) == 0) { + rc = ipmi_firewall_info(intf, argc-1, &(argv[1])); + } + else if (strncmp(argv[0], "enable", 6) == 0) { + rc = ipmi_firewall_enable_disable(intf, 1, argc-1, &(argv[1])); + } + else if (strncmp(argv[0], "disable", 7) == 0) { + rc = ipmi_firewall_enable_disable(intf, 0, argc-1, &(argv[1])); + } + else if (strncmp(argv[0], "reset", 5) == 0) { + rc = ipmi_firewall_reset(intf, argc-1, &(argv[1])); + } + else { + printf_firewall_usage(); + rc = ERR_BAD_PARAM; + } + + ipmi_close_(); + // show_outcome(progname,rc); + return rc; +} diff --git a/util/ifirewall.h b/util/ifirewall.h new file mode 100644 index 0000000..14a04f4 --- /dev/null +++ b/util/ifirewall.h @@ -0,0 +1,111 @@ +/* + * 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. + */ + +#ifndef IPMI_FIREWALL_H +#define IPMI_FIREWALL_H + +#define uint8_t unsigned char +#define uint16_t unsigned short + +// struct ipmi_rq definition was moved to ipmicmd.h +#define IPMI_NETFN_APP 0x06 + +#define BMC_GET_NETFN_SUPPORT 0x09 +#define BMC_GET_COMMAND_SUPPORT 0x0A +#define BMC_GET_COMMAND_SUBFUNCTION_SUPPORT 0x0B +#define BMC_GET_CONFIGURABLE_COMMANDS 0x0C +#define BMC_GET_CONFIGURABLE_COMMAND_SUBFUNCTIONS 0x0D +#define BMC_SET_COMMAND_ENABLES 0x60 +#define BMC_GET_COMMAND_ENABLES 0x61 +#define BMC_SET_COMMAND_SUBFUNCTION_ENABLES 0x62 +#define BMC_GET_COMMAND_SUBFUNCTION_ENABLES 0x63 +#define BMC_OEM_NETFN_IANA_SUPPORT 0x64 + +#define SET_COMMAND_ENABLE_BYTE (BMC_SET_COMMAND_ENABLES / 8) +#define SET_COMMAND_ENABLE_BIT (BMC_SET_COMMAND_ENABLES % 8) + +#define MAX_LUN 4 +#define MAX_NETFN 64 +#define MAX_NETFN_PAIR (MAX_NETFN/2) +#define MAX_COMMAND 256 +#define MAX_SUBFN 32 +#define MAX_COMMAND_BYTES (MAX_COMMAND>>3) +#define MAX_SUBFN_BYTES (MAX_SUBFN>>3) + +// support is a bitfield with the following bits set... +#define BIT_AVAILABLE 0x01 +#define BIT_CONFIGURABLE 0x02 +#define BIT_ENABLED 0x04 + +struct command_support { + unsigned char support; + unsigned char version[3]; + unsigned char subfn_support[MAX_SUBFN_BYTES]; + unsigned char subfn_config[MAX_SUBFN_BYTES]; + unsigned char subfn_enable[MAX_SUBFN_BYTES]; +}; +struct lun_netfn_support { + unsigned char support; + struct command_support command[MAX_COMMAND]; + unsigned char command_mask[MAX_COMMAND_BYTES]; + unsigned char config_mask[MAX_COMMAND_BYTES]; + unsigned char enable_mask[MAX_COMMAND_BYTES]; +}; +struct lun_support { + unsigned char support; + struct lun_netfn_support netfn[MAX_NETFN_PAIR]; +}; +struct bmc_fn_support { + struct lun_support lun[MAX_LUN]; +}; +struct ipmi_function_params { + int channel; + int lun; + int netfn; + int command; + int subfn; + unsigned char force; +}; + +#ifdef WIN32 +#define INLINE /*nop*/ +#else +#define INLINE inline +#endif +static INLINE int bit_test(const unsigned char * bf, int n) { + return !!(bf[n>>3]&(1<<(n%8))); +} +static INLINE void bit_set(unsigned char * bf, int n, int v) { + bf[n>>3] = (bf[n>>3] & ~(1<<(n%8))) | ((v?1:0)<<(n%8)); +} + +#endif /*IPMI_FIREWALL_H */ diff --git a/util/ifru.c b/util/ifru.c new file mode 100755 index 0000000..ba834e6 --- /dev/null +++ b/util/ifru.c @@ -0,0 +1,2123 @@ +/* + * ifru (was fruconfig.c) + * + * This tool reads the FRU configuration, and optionally sets the asset + * tag field in the FRU data. See IPMI v1.5 spec section 28. + * It can use either the Intel /dev/imb driver or VALinux /dev/ipmikcs. + * + * Author: Andy Cress arcress at users.sourceforge.net + * + * Copyright (c) 2009 Kontron America, Inc. + * + * 10/28/02 Andy Cress - created + * 12/11/02 Andy Cress v0.9 - disable write until checksum fixed. + * 12/13/02 Andy Cress v0.91 - don't abort if cc=c9 in load_fru loop. + * 01/27/03 Andy Cress v0.92 - more debug, do checksums, + * 01/28/03 Andy Cress v1.0 do writes in small chunks, tested w SCB2 & STL2 + * 02/19/03 Andy Cress v1.1 also get System GUID + * 03/10/03 Andy Cress v1.2 do better bounds checking on FRU size + * 04/30/03 Andy Cress v1.3 Board Part# & Serial# reversed + * 05/13/03 Andy Cress v1.4 Added Chassis fields + * 06/19/03 Andy Cress v1.5 added errno.h (email from Travers Carter) + * 05/03/04 Andy Cress v1.6 BladeCenter has no product area, only board area + * 05/05/04 Andy Cress v1.7 call ipmi_close before exit, + * added WIN32 compile options. + * 11/01/04 Andy Cress v1.8 add -N / -R for remote nodes + * 12/10/04 Andy Cress v1.9 add gnu freeipmi interface + * 01/13/05 Andy Cress v1.10 add logic to scan SDRs for all FRU devices, + * and interpret them + * 01/17/05 Andy Cress v1.11 decode SPD Manufacturer + * 01/21/05 Andy Cress v1.12 format SystemGUID display + * 02/03/05 Andy Cress v1.13 fixed fwords bit mask in load_fru, + * decode DIMM size from SPD also. + * 02/04/05 Andy Cress v1.14 decode FRU Board Mfg DateTime + * 03/16/05 Andy Cress v1.15 show Asset Tag Length earlier + * 05/24/05 Andy Cress v1.16 only do write_asset if successful show_fru + * 06/20/05 Andy Cress v1.17 handle Device SDRs also for ATCA + * 08/22/05 Andy Cress v1.18 allow setting Product Serial Number also (-s), + * also add -b option to show only baseboard data. + * 10/31/06 Andy Cress v1.25 handle 1-char asset/serial strings (avoid c1) + */ +/*M* +Copyright (c) 2009 Kontron America, 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: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions 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. + c.. Neither the name of Kontron nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ +#ifdef WIN32 +#include +#include +#include +#include +#include "getopt.h" +#elif defined(DOS) +#include +#include +#include +#include +#include "getopt.h" +#else +#include +#include +#include +#include +#include +#include +#include +#if defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include +#else +#include +#endif +#endif +#include + +#include "ipmicmd.h" +#include "ipicmg.h" +#include "oem_intel.h" +#include "ifru.h" + +#define PICMG_CHILD 1 +#define MIN_SDR_SZ 8 +#ifndef URNLOOPS +#define URNLOOPS 1000 +#endif +extern int get_BiosVersion(char *str); +extern int get_SystemGuid(uchar *guid); +extern void fmt_time(time_t etime, char *buf, int bufsz); /*see ievents.c*/ +extern int get_LastError( void ); /* ipmilan.c */ +extern int GetSDRRepositoryInfo(int *nret, int *fdev); /*isensor.h*/ +#ifdef METACOMMAND +extern int ipmi_kontronoem_main(void * intf, int argc, char ** argv); +#endif + +static char *progname = "ifru"; +static char *progver = "2.93"; +static int vend_id = 0; +static int prod_id = 0; +static char fdebug = 0; +static char fpicmg = 0; +static char fonlybase = 0; +static char fonlyhsc = 0; +static int fwritefru = 0; +static int fdevsdrs = 0; +static char fshowlen = 0; +static char ftestshow = 0; +// static char fgetfru = 0; +static char fdoanyway = 0; +static char fprivset = 0; +static char fset_mc = 0; +static char fcanonical = 0; +static char foemkontron = 0; +static char fbasefru = 1; +static char fdump = 0; +static char frestore = 0; +static char fchild = 0; /* =1 follow child MCs if picmg bladed*/ +static char do_systeminfo = 1; +static char do_guid = 1; +static char bdelim = ':'; +static uchar bmc_sa = BMC_SA; /*defaults to 0x20*/ +static uchar guid[17] = ""; +static char *binfile = NULL; +static uchar *frubuf = NULL; +#define FIELD_LEN 20 +#define SZ_PRODAREA 520 /* product area max is 8*32 + 3 = 259 mod 8 = 264 */ +static int sfru = 0; +static int asset_offset = -1; +static int asset_len = 0; +static int sernum_offset = -1; +static int sernum_len = 0; +static int prodver_offset = -1; +static int prodver_len = 0; +static int chassis_offset = -1; +static int chassis_len = 0; +static char asset_tag[FIELD_LEN] = {0}; +static char serial_num[FIELD_LEN] = {0}; +static char prod_ver[FIELD_LEN] = {0}; +static char chassis_name[FIELD_LEN] = {0}; +static char ps_prod[FIELD_LEN] = {0}; +static int maxprod = 0; +static int ctype; +static uchar g_bus = PUBLIC_BUS; +static uchar g_sa = 0; +static uchar g_lun = BMC_LUN; +static uchar g_addrtype = ADDR_SMI; +static uchar g_fruid = 0; /* default to fruid 0 */ +static uchar g_frutype = 0; +static uchar lastfru[3] = {0,0,0}; +/* g_frutype values (detected), see also FruTypeString + * --TAG---- FRU IPMB + * Baseboard = 0x0c 0x07 + * PowerSply = 0x0a + * PowerCage = 0x15 + * DIMM = 0x20 + * HotSwapCt = 0x0f + * ME = 0x2e + * SysInfo = 0x40 + * Component = * * (all others) + */ +#ifdef METACOMMAND +extern int verbose; +extern int sdr_get_reservation(uchar *res_id, int fdev); +#else +static int verbose; +static int sdr_get_reservation(uchar *res_id, int fdev) { return(-1); } +#endif + +#define ERR_LENMAX -7 /*same as LAN_ERR_BADLENGTH */ +#define ERR_LENMIN -10 /*same as LAN_ERR_TOO_SHORT */ +#define ERR_OTHER -13 /*same as LAN_ERR_OTHER */ + +#define STRING_DATA_TYPE_BINARY 0x00 +#define STRING_DATA_TYPE_BCD_PLUS 0x01 +#define STRING_DATA_TYPE_SIX_BIT_ASCII 0x02 +#define STRING_DATA_TYPE_LANG_DEPENDENT 0x03 + +#define FRUCHUNK_SZ 16 +#define FRU_END 0xC1 +#define FRU_EMPTY_FIELD 0xC0 +#define FRU_TYPE_MASK 0xC0 +#define FRU_LEN_MASK 0x3F + +#define NUM_BOARD_FIELDS 6 +#define NUM_PRODUCT_FIELDS 8 +#define NUM_CHASSIS_FIELDS 3 +#define MAX_CTYPE 26 +char *ctypes[MAX_CTYPE] = { "", "Other", "Unknown", "Desktop", + "Low Profile Desktop", "Pizza Box", "Mini-Tower", "Tower", + "Portable", "Laptop", "Notebook", "Handheld", "Docking Station", + "All-in-One", "Sub-Notebook", "Space-saving", "Lunch Box", + "Main Server Chassis", "Expansion Chassis", "SubChassis", + "Bus Expansion Chassis", "Peripheral Chassis", + "RAID Chassis", /*0x17=23.*/ "Rack-Mount Chassis", + "New24" , "New25"}; + /* what about bladed chassies? */ +char *ctype_hdr = +"Chassis Type "; +char *chassis[NUM_CHASSIS_FIELDS] = { +"Chassis Part Number ", +"Chassis Serial Num ", +"Chassis OEM Field " }; +char *board[NUM_BOARD_FIELDS] = { +"Board Manufacturer ", +"Board Product Name ", +"Board Serial Number ", +"Board Part Number ", +"Board FRU File ID ", +"Board OEM Field " }; +char *product[NUM_PRODUCT_FIELDS] = { +"Product Manufacturer", +"Product Name ", +"Product Part Number ", +"Product Version ", +"Product Serial Num ", +"Product Asset Tag ", +"Product FRU File ID ", +"Product OEM Field " }; +char *asset_hdr = +" Asset Tag Length "; + +#if 0 +typedef struct { + uchar len :6; + uchar type:2; + } TYPE_LEN; /*old, assumes lo-hi byte order*/ +#else +typedef struct { + uchar len; + uchar type; + } TYPE_LEN; +#endif + +void +free_fru(uchar *pfrubuf) +{ + if (pfrubuf != NULL) { + if (frubuf != NULL) free(frubuf); + frubuf = NULL; + } + return; +} + +int +load_fru(uchar sa, uchar frudev, uchar frutype, uchar **pfrubuf) +{ + int ret = 0; + uchar indata[16]; + uchar resp[18]; + int sresp; + uchar cc; + int sz; + char fwords; + ushort fruoff = 0; + int i, rv; + int chunk; + + if (pfrubuf == NULL) return(ERR_BAD_PARAM); + *pfrubuf = NULL; + indata[0] = frudev; + sresp = sizeof(resp); + if (fdebug) printf("load_fru: sa=%02x, frudev=%02x, addrtype=%d\n", + sa,frudev,g_addrtype); + ret = ipmi_cmd_mc(GET_FRU_INV_AREA,indata,1,resp,&sresp,&cc,fdebug); + if (fdebug) printf("load_fru: inv ret=%d, cc=%x, resp=%02x %02x %02x\n", + ret,cc, resp[0], resp[1], resp[2]); + if (ret != 0) return(ret); + if (cc != 0) { ret = (cc & 0x00ff); return(ret); } + + sz = resp[0] + (resp[1] << 8); + if (resp[2] & 0x01) { fwords = 1; sz = sz * 2; } + else fwords = 0; + + frubuf = malloc(sz); + if (frubuf == NULL) return(get_errno()); + *pfrubuf = frubuf; + sfru = sz; + + /* Loop on READ_FRU_DATA */ + for (i = 0, chunk=FRUCHUNK_SZ; i < sz; i+=chunk) + { + if ((i+chunk) >= sz) chunk = sz - i; + indata[0] = frudev; /* FRU Device ID */ + if (fwords) { + indata[3] = chunk / 2; + fruoff = (i/2); + } else { + indata[3] = (uchar)chunk; + fruoff = (ushort)i; + } + indata[1] = fruoff & 0x00FF; + indata[2] = (fruoff & 0xFF00) >> 8; + sresp = sizeof(resp); + ret = ipmi_cmd_mc(READ_FRU_DATA,indata,4,resp,&sresp,&cc,fdebug); + if (ret != 0) break; + else if (cc != 0) { + if (i == 0) ret = cc & 0x00ff; + if (fdebug) printf("read_fru[%d]: ret = %d cc = %x\n",i,ret,cc); + break; + } + memcpy(&frubuf[i],&resp[1],chunk); + } + + if ((frudev == 0) && (sa == bmc_sa) && do_guid) + { /*main system fru, so get GUID*/ + sresp = sizeof(resp); + rv = ipmi_cmd_mc(GET_SYSTEM_GUID,indata,0,resp,&sresp,&cc,fdebug); + if (fdebug) printf("system_guid: ret = %d, cc = %x\n",rv,cc); + if (rv == 0) rv = cc; + if ((rv != 0) && !is_remote()) { /* get UUID from SMBIOS */ + cc = 0; sresp = 16; + rv = get_SystemGuid(resp); + if (fdebug) printf("get_SystemGuid: ret = %d\n",rv); + } + if (rv == 0 && cc == 0) { + if (fdebug) { + printf("system guid (%d): ",sresp); + for (i=0; i<16; i++) printf("%02x ",resp[i]); + printf("\n"); + } + memcpy(&guid,&resp,16); + guid[16] = 0; + } else { + printf("WARNING: GetSystemGuid error %d, %s\n",rv,decode_rv(rv)); + /*do not pass this error upstream*/ + } + } /*endif*/ + return(ret); +} + +static void decode_string(unsigned char type, + unsigned char language_code, + unsigned char *source, + int slen, + char *target, + int tsize) +{ + static const char bcd_plus[] = "0123456789 -.:,_"; + unsigned char *s = &source[0]; + int len, i, j, k; + union { uint32_t bits; char chars[4]; } u; + + if (slen == 0 || slen == 1) return; + switch(type) { + case STRING_DATA_TYPE_BINARY: /* 00: binary/unspecified */ + len = (slen*2); break; /* hex dump -> 2x length */ + case STRING_DATA_TYPE_SIX_BIT_ASCII: /*type 2 6-bit ASCII*/ + /* 4 chars per group of 1-3 bytes */ + len = ((((slen+2)*4)/3) & ~3); break; + case STRING_DATA_TYPE_LANG_DEPENDENT: /* 03 language dependent */ + case STRING_DATA_TYPE_BCD_PLUS: /* 01b: BCD plus */ + default: + len = slen; break; + } + if (len >= tsize) len = tsize - 1; + memset(target, 0, len); + if (type == STRING_DATA_TYPE_BCD_PLUS) { /*type 1: BCD plus*/ + for (k=0; k 1 ? s[i+1] : 0); + u.chars[1] = (k > 2 ? s[i+2] : 0); +#define CHAR_IDX 3 +#else + memcpy((void *)&u.bits, &s[i], k); +#define CHAR_IDX 0 +#endif + for (k=0; k<4; k++) { + target[j++] = ((u.chars[CHAR_IDX] & 0x3f) + 0x20); + u.bits >>= 6; + } + } + target[j] = '\0'; + } else if (type == STRING_DATA_TYPE_LANG_DEPENDENT) { /*type 3*/ + if ((language_code == 0x00) || (language_code == 0x25) || + (language_code == 0x19)) { + memcpy(target, source, len); + target[len] = 0; + } else { + printf("Language 0x%x dependent decode not supported\n",language_code); + } + } else if (type == STRING_DATA_TYPE_BINARY) { /* 00: binary/unspecified */ + strncpy(target, buf2str(s, slen), len); + target[len] = '\0'; /* add end-of-string char */ + } else { /* other */ + printf("Unable to decode type 0x%.2x\n",type); + } + return; +} + +uchar calc_cksum(uchar *pbuf,int len) +{ + int i; + uchar cksum; + uchar sum = 0; + + for (i = 0; i < len; i++) sum += pbuf[i]; + cksum = 0 - sum; + return(cksum); +} + +static void dumpbuf(uchar *pbuf,int sz) +{ + uchar line[17]; + uchar a; + int i, j; + + line[0] = 0; line[16] = 0; + j = 0; + for (i = 0; i < sz; i++) { + if (i % 16 == 0) { j = 0; printf("%s\n %04d: ",line,i); } + a = pbuf[i]; + if (a < 0x20 || a > 0x7f) a = '.'; + line[j++] = a; + printf("%02x ",pbuf[i]); + } + line[j] = 0; + printf("%s\n",line); + return; +} + +#define NSPDMFG 10 +static struct { + uchar id; char *str; +} spd_mfg[NSPDMFG] = { /* see JEDEC JEP106 doc */ +{ 0x02, "AMI" }, +{ 0x04, "Fujitsu" }, +{ 0x15, "Philips Semi" }, +{ 0x1c, "Mitsubishi" }, +{ 0x2c, "Micron" }, +{ 0x89, "Intel" }, +{ 0x98, "Kingston" }, +{ 0xA8, "US Modular" }, +{ 0xc1, "Infineon" }, +{ 0xce, "Samsung" } +}; + +int ValidTL(uchar typelen) +{ + if (vend_id != VENDOR_INTEL) return 1; + if ((typelen & 0xC0) == 0xC0) return 1; /* validate C type */ + if ((typelen & 0x00) == 0x00) return 1; /* validate 0 type too */ + else return 0; +} + +#define SYS_FRUTYPE 0x40 +char * FruTypeString(uchar frutype, uchar dev) +{ + char *pstr; + switch (frutype) { + case 0x07: /*IPMB*/ + case 0x0c: /*FRU*/ + if (dev == 0) pstr = "Baseboard"; + else pstr = "Board "; + break; + case 0x0a: pstr = "PowerSply"; break; /*FRU*/ + case 0x15: pstr = "PowerCage"; break; /*FRU*/ + case 0x20: pstr = "DIMM "; break; /*FRU*/ + case 0x0f: pstr = "HotSwapCt"; break; /*IPMB*/ + case 0x2e: pstr = "ME "; break; /*IPMB*/ + case SYS_FRUTYPE: pstr = "SysInfo "; break; /*SysInfo*/ + default: pstr = "Component"; break; + } + return(pstr); +} + +static int ChkOverflow(int idx, int sz, uchar len) +{ + if (idx >= sz) { + printf(" ERROR - FRU Buffer Overflow (%d >= %d), last len=%d\n", + idx,sz,len); + return 1; /*overflow error*/ + } + return 0; +} + +static void +show_spd(uchar *spd, int lenspd, uchar frudev, uchar frutype) +{ + int sz; + char *pstr; + int sdcap, ranks, busw, sdw, totcap; + uchar srev, mfgid, mrev1, mrev2, yr, wk; + uchar isdcap, iranks, ibusw, isdw; + uchar iparity, iser, ipart, irev; + int i; + char devstr[24]; + + /* Sample SPD Headers: + 80 08 07 0c 0a 01 48 00 (DDR SDRAM DIMM) + 92 10 0b 01 03 1a 02 00 (DDR3 SDRAM DIMMs) */ + sz = spd[0]; /* sz should == lenspd */ + srev = spd[1]; /* SPD Rev: 8 for DDR, 10 for DDR3 SPD spec */ + if (fcanonical) devstr[0] = 0; /*default is empty string*/ + else sprintf(devstr,"[%s, %02x] ",FruTypeString(frutype,frudev),frudev); + printf("%sMemory SPD Size %c %d\n", + devstr,bdelim,lenspd); + switch (spd[2]) { + case 0x02: pstr = "EDO"; break; + case 0x04: pstr = "SDRAM"; break; + case 0x05: pstr = "ROM"; break; + case 0x06: pstr = "DDR SGRAM"; break; + case 0x07: pstr = "DDR SDRAM"; break; + case 0x08: pstr = "DDR2 SDRAM"; break; + case 0x09: pstr = "DDR2 SDRAM FB"; break; + case 0x0A: pstr = "DDR2 SDRAM FB PROBE"; break; + case 0x0B: pstr = "DDR3 SDRAM"; break; + default: pstr = "DRAM"; break; /*FPM DRAM or other*/ + } + printf("%sMemory Type %c %s\n", devstr,bdelim,pstr); + if (srev < 0x10) { /*used rev 0.8 of SPD spec*/ + printf("%sModule Density %c %d MB per bank\n", + devstr,bdelim, (spd[31] * 4)); + printf("%sModule Banks %c %d banks\n", + devstr,bdelim,spd[5]); + printf("%sModule Rows, Cols %c %d rows, %d cols\n", + devstr,bdelim, spd[3], spd[4]); + iparity = spd[11]; + mfgid = spd[64]; + } else { /* use 1.0 SPD spec with DDR3 */ + /* SDRAM CAPACITY = SPD byte 4 bits 3~0 */ + /* PRIMARY BUS WIDTH = SPD byte 8 bits 2~0 */ + /* SDRAM WIDTH = SPD byte 7 bits 2~0 */ + /* RANKS = SPD byte 7 bits 5~3 */ + isdcap = (spd[4] & 0x0f); + iranks = (spd[7] & 0x38) >> 3; + isdw = (spd[7] & 0x07); + ibusw = (spd[8] & 0x07); + iparity = (spd[8] & 0x38) >> 3; + mfgid = spd[118]; + switch(isdcap) { + case 0: sdcap = 256; /*MB*/ break; + case 1: sdcap = 512; /*MB*/ break; + case 2: sdcap = 1024; /*MB*/ break; + case 3: sdcap = 2048; /*MB*/ break; + case 4: sdcap = 4096; /*MB*/ break; + case 5: sdcap = 8192; /*MB*/ break; + case 6: sdcap = 16384; /*MB*/ break; + default: sdcap = 32768; /*MB*/ break; + } + switch(iranks) { + case 0: ranks = 1; break; + case 1: ranks = 2; break; + case 2: ranks = 3; break; + case 3: + default: ranks = 4; break; + } + switch(isdw) { + case 0: sdw = 4; break; + case 1: sdw = 8; break; + case 2: sdw = 16; break; + case 3: + default: sdw = 32; break; + } + switch(ibusw) { + case 0: busw = 8; break; + case 1: busw = 16; break; + case 2: busw = 32; break; + case 3: + default: busw = 64; break; + } + totcap = sdcap / 8 * busw / sdw * ranks; + printf("%sModule Density %c %d Mbits\n",devstr,bdelim,sdcap); + printf("%sModule Ranks %c %d ranks\n",devstr,bdelim,ranks); + printf("%sModule Capacity %c %d MB\n",devstr,bdelim,totcap); + } + if (iparity == 0x00) pstr = "Non-parity"; + else /* usu 0x02 */ pstr = "ECC"; + printf("%sDIMM Config Type %c %s\n", devstr,bdelim,pstr); + for (i = 0; i < NSPDMFG; i++) + if (spd_mfg[i].id == mfgid) break; + if (i == NSPDMFG) pstr = ""; /* not found, use null string */ + else pstr = spd_mfg[i].str; + printf("%sManufacturer ID %c %s (0x%02x)\n", devstr,bdelim,pstr,mfgid); + if (srev < 0x10) { + yr = spd[93]; + wk = spd[94]; + iser = 95; + ipart = 73; + irev = 91; + } else { /* 1.0 SPD spec with DDR3 */ + yr = spd[120]; + wk = spd[121]; + iser = 122; + ipart = 128; + irev = 146; + } + mrev1 = spd[irev]; /* save this byte for later */ + mrev2 = spd[irev+1]; + spd[irev] = 0; /*stringify part number */ + printf("%sManufacturer Part# %c %s\n", + devstr,bdelim,&spd[ipart]); + printf("%sManufacturer Rev %c %02x %02x\n", + devstr,bdelim,mrev1,mrev2); + printf("%sManufacturer Date %c year=%02x week=%02x\n", + devstr,bdelim, yr,wk); + printf("%sAssembly Serial Num %c %02x%02x%02x%02x\n", + devstr,bdelim,spd[iser],spd[iser+1],spd[iser+2],spd[iser+3]); + spd[irev] = mrev1; /* restore byte, so ok to repeat later */ + return; +} + +void show_guid(uchar *pguid) +{ + char *s; + int i; + for (i=0; i<16; i++) { + if ((i == 4) || (i == 6) || (i == 8) || (i == 10)) s = "-"; + else s = ""; + printf("%s%02x",s,pguid[i]); + } +} + +static char *volt_desc(uchar b) +{ + char *s; + switch(b) { + case 0x03: s = "5V"; break; + case 0x02: s = "3.3V"; break; + case 0x01: s = "-12V"; break; + case 0x00: + default: s = "12V"; break; + } + return(s); +} + +static char *mgt_type(uchar b) +{ + char *s; + switch(b) { + case 0x01: s = "SysMgt_URL"; break; + case 0x02: s = "SystemName"; break; + case 0x03: s = "SysPingAddr"; break; + case 0x04: s = "Compon_URL"; break; + case 0x05: s = "ComponName"; break; + case 0x06: s = "ComponPing"; break; + case 0x07: + default: s = "SysGUID"; break; + } + return(s); +} + + +static +void show_fru_multi(char *tag, int midx, uchar mtype, uchar *pdata, int dlen) +{ + int vend; + char mystr[256]; + char *s1; + int v1, v2, v3, v4, v5, v6, v7; + uchar b1, b2; + + if (fdebug) dumpbuf(pdata,dlen); /*multi-record area dump*/ + sprintf(mystr,"%sMulti[%d] ",tag,midx); + switch(mtype) { + case 0x00: /*Power Supply*/ + printf("%sPower Supply Record %c \n",mystr,bdelim); + v1 = pdata[0] + ((pdata[1] & 0x0f) << 8); + printf("\t Capacity \t%c %d W\n",bdelim, v1); + v2 = pdata[2] + (pdata[3] << 8); + printf("\t Peak VA \t%c %d VA\n",bdelim, v2); + printf("\t Inrush Current\t%c %d A\n",bdelim, pdata[4]); + printf("\t Inrush Interval\t%c %d ms\n",bdelim, pdata[5]); + v3 = pdata[6] + (pdata[7] << 8); + v4 = pdata[8] + (pdata[9] << 8); + printf("\t Input Voltage Range1\t%c %d-%d V\n", + bdelim,v3/100,v4/100); + v3 = pdata[10] + (pdata[11] << 8); + v4 = pdata[12] + (pdata[13] << 8); + printf("\t Input Voltage Range2\t%c %d-%d V\n", + bdelim,v3/100,v4/100); + printf("\t Input Frequency Range\t%c %d-%d Hz\n", + bdelim,pdata[14],pdata[15]); + printf("\t AC Dropout Tolerance\t%c %d ms\n",bdelim, pdata[16]); + b1 = pdata[17]; + b2 = (b1 & 0x01); + if (b2) { /*predictive fail*/ + if ((b1 & 0x10) != 0) s1 = "DeassertFail "; + else s1 = "AssertFail "; + } else { + if ((b1 & 0x10) != 0) s1 = "2pulses/rot "; + else s1 = "1pulse/rot "; + } + printf("\t Flags \t%c %s%s%s%s%s\n",bdelim, + b2 ? "PredictFail " : "", + ((b1 & 0x02) == 0) ? "" : "PowerFactorCorrect ", + ((b1 & 0x04) == 0) ? "" : "AutoswitchVolt ", + ((b1 & 0x08) == 0) ? "" : "Hotswap ", s1); + v5 = pdata[18] + ((pdata[19] & 0x0f) << 8); + v6 = (pdata[19] & 0xf0) >> 4; + printf("\t Peak Capacity \t%c %d W for %d s\n",bdelim, v5,v6); + if (pdata[20] == 0) { + printf("\t Combined Capacity\t%c not specified\n",bdelim); + } else { + b1 = pdata[20] & 0x0f; + b2 = (pdata[20] & 0xf0) >> 4; + v7 = pdata[21] + (pdata[22] << 8); + printf("\t Combined Capacity\t%c %d W (%s and %s)\n", + bdelim, v7,volt_desc(b1),volt_desc(b2)); + } + if (b2) /*predictive fail*/ + printf("\t Fan low threshold\t%c %d RPS\n",bdelim,pdata[23]); + break; + case 0x01: /*DC Output*/ + b1 = pdata[0] & 0x0f; + b2 = ((pdata[0] & 0x80) != 0); + printf("%sDC Output %c number %d\n",mystr,bdelim,b1); + printf("\t Standby power \t%c %s\n", bdelim, + (b2 ? "Yes" : "No")); + v1 = pdata[1] + (pdata[2] << 8); + printf("\t Nominal voltage \t%c %.2f V\n", bdelim, v1 / 100); + v2 = pdata[3] + (pdata[4] << 8); + v3 = pdata[5] + (pdata[6] << 8); + printf("\t Voltage deviation \t%c + %.2f V / - %.2f V\n", + bdelim, v3/100, v2/100); + v4 = pdata[7] + (pdata[8] << 8); + printf("\t Ripple and noise pk-pk \t%c %d mV\n", bdelim, v4); + v5 = pdata[9] + (pdata[10] << 8); + printf("\t Min current draw \t%c %.3f A\n", bdelim, v5/1000); + v6 = pdata[11] + (pdata[12] << 8); + printf("\t Max current draw \t%c %.3f A\n", bdelim, v6/1000); + break; + case 0x02: /*DC Load*/ + b1 = pdata[0] & 0x0f; + printf("%sDC Load %c number %d\n",mystr,bdelim,b1); + v1 = pdata[1] + (pdata[2] << 8); + printf("\t Nominal voltage \t%c %.2f V\n", bdelim, v1 / 100); + v2 = pdata[3] + (pdata[4] << 8); + v3 = pdata[5] + (pdata[6] << 8); + printf("\t Min voltage allowed \t%c %.2f A\n", bdelim, v2); + printf("\t Max voltage allowed \t%c %.2f A\n", bdelim, v3); + v4 = pdata[7] + (pdata[8] << 8); + printf("\t Ripple and noise pk-pk \t%c %d mV\n", bdelim, v4); + v5 = pdata[9] + (pdata[10] << 8); + printf("\t Min current load \t%c %.3f A\n", bdelim, v5/1000); + v6 = pdata[11] + (pdata[12] << 8); + printf("\t Max current load \t%c %.3f A\n", bdelim, v6/1000); + break; + case 0x03: /*Management Access*/ + b1 = pdata[0]; + printf("%sManagemt Access %c %s ",mystr,bdelim,mgt_type(b1)); + memcpy(mystr,&pdata[1],dlen-1); + mystr[dlen-1] = 0; + printf("%s\n",mystr); + break; + case 0x04: /*Base Compatibility*/ + vend = pdata[0] + (pdata[1] << 8) + (pdata[2] << 16); + printf("%sBasic Compat %c %06x\n",mystr,bdelim,vend); + break; + case 0x05: /*Extended Compatibility*/ + vend = pdata[0] + (pdata[1] << 8) + (pdata[2] << 16); + printf("%sExtended Compat %c %06x\n",mystr,bdelim,vend); + break; + case 0xC0: /*OEM Extension*/ + vend = pdata[0] + (pdata[1] << 8) + (pdata[2] << 16); + if (vend == OEM_PICMG) { + printf("%sOEM PICMG %c \n", mystr,bdelim); + show_fru_picmg(pdata,dlen); + } else + printf("%sOEM Ext %c %06x %02x\n", + mystr,bdelim, vend, pdata[3]); + break; + default: + printf("%s %02x %c %02x\n", mystr,mtype,bdelim, pdata[0]); + break; + } +} + +int +show_fru(uchar sa, uchar frudev, uchar frutype, uchar *pfrubuf) +{ + int ret = 0; + int i, j, n, sz; + uchar *pfru0; + uchar *pfru; + uchar lang; + TYPE_LEN tl; + char newstr[64]; + int iaoff, ialen, bdoff, bdlen; + int proff, prlen, choff, chlen; + int moff, mlen; + char devstr[24]; + char *pstr; + + if ((pfrubuf[0] & 0x80) == 0x80) { /* 0x80 = type for DIMMs (SPD) */ + /* FRU Header: 80 08 07 0c 0a 01 48 00 (DIMM) */ + /* FRU Header: 92 10 0b 01 03 1a 02 00 (DDR3 DIMMs) */ + sz = pfrubuf[0]; + if (fdebug) { + printf("DIMM SPD Body (size=%d/%d): ",sz,sfru); + dumpbuf(pfrubuf,sfru); + } + show_spd(pfrubuf,sfru, frudev,frutype); + return(ret); + } + + pstr = FruTypeString(frutype,frudev); + if (fcanonical) devstr[0] = 0; /*default is empty string*/ + else sprintf(devstr,"[%s,%02x,%02x] ",pstr,sa,frudev); + printf("%s%s FRU Size %c %d\n",devstr,pstr,bdelim,sfru); + + /* + * FRU header: + * 0 = format_ver (01 is std, usu 0x80 if DIMM) + * 1 = internal_use offset + * 2 = chassis_info offset + * 3 = board_info offset (usu 6 fields) + * 4 = product_info offset (usu 8 fields) + * 5 = multirecord offset + * 6 = pad (00) + * 7 = header checksum (zero checksum) + * FRU Header: 01 01 02 09 13 00 00 e0 (BMC) + * FRU Header: 01 00 00 00 01 07 00 f7 (Power Cage) + */ + pfru0 = &pfrubuf[0]; /*pointer to fru start*/ + pfru = &pfrubuf[0]; + sz = 8; /*minimum for common header*/ + for (i = 1; i < 6; i++) /* walk thru offsets */ + if (pfrubuf[i] != 0) sz = pfrubuf[i] * 8; + if (sz > 8) { /* if have at least one section */ + if (pfrubuf[5] != 0) j = 5 + pfrubuf[sz+2]; /*if multi-record area*/ + else j = pfrubuf[sz+1] * 8; /* else add length of last section */ + sz += j; + } + + /* Now, sz = size used, sfru = total available size */ + if (sz > sfru) { + if (fdebug) { + uchar hsum; + printf("FRU Header: "); + for (i = 0; i < 8; i++) printf("%02x ",pfrubuf[i]); + printf("\n"); + hsum = calc_cksum(&pfrubuf[0],7); + if (pfrubuf[7] != hsum) + printf("FRU Header checksum mismatch (%x != %x)\n",pfrubuf[7],hsum); + } + printf("FRU size used=%d > available=%d\n",sz,sfru); + if (fpicmg || fdoanyway) sz = sfru; /*do it anyway*/ + else { + printf("Please apply the correct FRU/SDR diskette\n"); + return(ERR_OTHER); + } + } + /* internal area offset, length */ + iaoff = pfrubuf[1] * 8; + ialen = pfrubuf[iaoff + 1] * 8; + /* chassis area offset, length */ + choff = pfrubuf[2] * 8; + chlen = pfrubuf[choff + 1] * 8; + /* board area offset, length */ + bdoff = pfrubuf[3] * 8; + bdlen = pfrubuf[bdoff + 1] * 8; + /* product area offset, length */ + proff = pfrubuf[4] * 8; + prlen = pfrubuf[proff + 1] * 8; + /* multi-record area offset, length */ + moff = pfrubuf[5] * 8; + mlen = 0; + if (moff > 0) { + for (i = moff; i < sfru; ) { + j = 5 + pfrubuf[i+2]; + mlen += j; + if (pfrubuf[i+1] & 0x80) break; + i += j; + } + } + + if (fdebug) { + printf("FRU Header: "); + for (i = 0; i < 8; i++) printf("%02x ",pfrubuf[i]); + printf("\n"); + printf("FRU Body (size=%d/%d): ",sz,sfru); + dumpbuf(pfrubuf,sfru); + printf("header, len=%d, cksum0 = %02x, cksum1 = %02x\n", + 8,pfrubuf[7],calc_cksum(&pfrubuf[0],7)); + printf("internal off=%d, len=%d, cksum = %02x\n", + iaoff,ialen,calc_cksum(&pfrubuf[iaoff],ialen-1)); + printf("chassis off=%d, len=%d, cksum = %02x\n", + choff,chlen,calc_cksum(&pfrubuf[choff],chlen-1)); + printf("board off=%d, len=%d, cksum = %02x\n", + bdoff,bdlen,calc_cksum(&pfrubuf[bdoff],bdlen-1)); + printf("prod off=%d, len=%d, cksum = %02x\n", + proff,prlen,calc_cksum(&pfrubuf[proff],prlen-1)); + /* Multi-record area */ + printf("multi off=%d, len=%d, fru sz=%d\n", moff,mlen,sz); + } /*endif fdebug, show header*/ + + if (choff != 0) { + /* show Chassis area fields */ + pfru = &pfrubuf[choff]; + lang = 25; /* English */ + ctype = pfru[2]; /*chassis type*/ + if (fdebug) printf("ctype=%x\n",ctype); + if (ctype >= MAX_CTYPE) ctype = MAX_CTYPE - 1; + printf("%s%s%c %s\n",devstr, ctype_hdr,bdelim,ctypes[ctype]); + pfru += 3; /* skip chassis header */ + tl.len = 0; + for (i = 0; i < NUM_CHASSIS_FIELDS; i++) + { + if (ChkOverflow((int)(pfru - pfru0),sfru,tl.len)) break; + if (pfru[0] == FRU_END) break; /*0xC1 = end of FRU area*/ + if (!ValidTL(pfru[0])) + printf(" ERROR - Invalid Type/Length %02x for %s\n", + pfru[0],chassis[i]); + tl.type = (pfru[0] & FRU_TYPE_MASK) >> 6; + tl.len = pfru[0] & FRU_LEN_MASK; + if (i == 2) { /* OEM field for chassis_name */ + chassis_offset = (int)(pfru - pfrubuf); + chassis_len = tl.len; + if (fdebug) printf("chassis oem dtype=%d lang=%d len=%d\n", + tl.type,lang,tl.len); + } + pfru++; + { + newstr[0] = 0; + decode_string(tl.type,lang,pfru,tl.len,newstr,sizeof(newstr)); + printf("%s%s%c %s\n",devstr, chassis[i],bdelim,newstr); + } + pfru += tl.len; + } + if (fdebug) printf("num Chassis fields = %d\n",i); + } + + if (bdoff != 0) { + long nMin, nSec; + time_t tsec; + /* show Board area fields */ + pfru = &pfrubuf[bdoff]; + lang = pfru[2]; + /* Decode board mfg date-time (num minutes since 1/1/96) */ + nMin = pfru[3] + (pfru[4] << 8) + (pfru[5] << 16); + /* 820,454,400 sec from 1/1/70 to 1/1/96 */ + nSec = (nMin * 60) + 820454400; + tsec = (time_t)(nSec & 0x0ffffffff); + // fmt_time(tsec,newstr,sizeof(newstr)); + printf("%sBoard Mfg DateTime %c %s",devstr,bdelim,ctime(&tsec)); + pfru += 6; /* skip board header */ + tl.len = 0; + for (i = 0; i < NUM_BOARD_FIELDS; i++) + { + if (ChkOverflow((int)(pfru - pfru0),sfru,tl.len)) break; + if (pfru[0] == FRU_END) break; /*0xC1 = end*/ + if (!ValidTL(pfru[0])) + printf(" ERROR - Invalid Type/Length %02x for %s\n", + pfru[0],board[i]); + tl.type = (pfru[0] & FRU_TYPE_MASK) >> 6; + tl.len = pfru[0] & FRU_LEN_MASK; + pfru++; + { + newstr[0] = 0; + decode_string(tl.type,lang,pfru,tl.len,newstr,sizeof(newstr)); + printf("%s%s%c %s\n",devstr, board[i],bdelim,newstr); + } + pfru += tl.len; + } + if (fdebug) printf("num Board fields = %d\n",i); + } + + if (proff != 0) + { + /* show Product area fields */ + pfru = &pfrubuf[proff]; + maxprod = pfru[1] * 8; + lang = pfru[2]; + pfru += 3; /* skip product header */ + tl.len = 0; + for (i = 0; i < NUM_PRODUCT_FIELDS; i++) + { + if (ChkOverflow((int)(pfru - pfru0),sfru,tl.len)) break; + if (*pfru == FRU_END) { /*0xC1 = end*/ + /* Wart for known Kontron 1-byte Product Version anomaly. */ + if (vend_id == VENDOR_KONTRON && i == 3) ; + else break; + } + if (*pfru == 0) *pfru = FRU_EMPTY_FIELD; /* fix a broken table */ + if (!ValidTL(pfru[0])) + printf(" ERROR - Invalid Type/Length %02x for %s\n", + pfru[0],product[i]); + tl.type = (pfru[0] & FRU_TYPE_MASK) >> 6; + tl.len = pfru[0] & FRU_LEN_MASK; + if ((frudev == 0) && (sa == bmc_sa)) { /*baseboard FRU*/ + if (i == 5) { /* asset tag */ + asset_offset = (int)(pfru - pfrubuf); + asset_len = tl.len; + if (fdebug) printf("asset off=%d dtype=%d lang=%d len=%d\n", + asset_offset,tl.type,lang,tl.len); + if (fshowlen) /* show asset tag length for main board */ + printf("%s%c %d\n",asset_hdr,bdelim,asset_len); + } else if (i == 4) { /* serial number */ + sernum_offset = (int)(pfru - pfrubuf); + sernum_len = tl.len; + if (fdebug) printf("sernum dtype=%d lang=%d len=%d\n", + tl.type, lang, tl.len); + } else if (i == 3) { /* product version number */ + prodver_offset = (int)(pfru - pfrubuf); + prodver_len = tl.len; + if (fdebug) printf("prodver dtype=%d lang=%d len=%d\n", + tl.type, lang, tl.len); + } + } /*if baseboard sa*/ + pfru++; + { + newstr[0] = 0; + decode_string(tl.type,lang,pfru,tl.len,newstr,sizeof(newstr)); + printf("%s%s%c %s\n",devstr, product[i],bdelim,newstr); + } + pfru += tl.len; + } + if (fdebug) + printf("num Product fields = %d, last=%x, max = %d\n", + i,*pfru,maxprod ); + if (*pfru == 0x00) *pfru = FRU_END; /* insert end char if broken */ + } + + if (moff != 0) + { + /* multi-record area may contain several record headers + * 0 = record type id + * 1 = 0x02 or 0x82 if End-of-List + * 2 = record len + * 3 = record chksum + * 4 = header chksum + */ + pfru = &pfrubuf[moff]; + j = moff; + for (i = 0; j < sz ; i++) + { + n = pfru[2]; /* len of this record */ + show_fru_multi(devstr,i,pfru[0],&pfru[5],n); + j += (5 + n); + if (pfru[1] & 0x80) j = sz; /*0x80 = last in list, break*/ + pfru += (5 + n); + } + } + + if ((frudev == 0) && (sa == bmc_sa) && do_guid) { + printf("%sSystem GUID %c ",devstr,bdelim); + show_guid(guid); + printf("\n"); + } + return(ret); +} + +int write_fru_data(uchar id, ushort offset, uchar *data, int dlen, char fdebug) +{ + int ret = -1; + int chunk; + ushort fruoff; + uchar req[25]; + uchar resp[16]; + int sresp; + uchar cc; + int i, j; + + /* Write the buffer in small 16-byte (FRUCHUNK_SZ) chunks */ + req[0] = 0x00; /* override FRU Device ID (fruid) */ + fruoff = offset; + chunk = FRUCHUNK_SZ; + for (i = 0; i < dlen; i += chunk) { + req[1] = fruoff & 0x00ff; + req[2] = (fruoff & 0xff00) >> 8; + if ((i + chunk) > dlen) chunk = dlen - i; + memcpy(&req[3],&data[i],chunk); + if (fdebug) { + printf("write_fru_data[%d] (len=%d): ",i,chunk+3); + for (j = 0; j < chunk+3; j++) printf("%02x ",req[j]); + printf("\n"); + } + sresp = sizeof(resp); + ret = ipmi_cmd_mc(WRITE_FRU_DATA,req,(uchar)(chunk+3),resp,&sresp, + &cc,fdebug); + if ((ret == 0) && (cc != 0)) ret = cc & 0x00ff; + if (fdebug && ret == 0) + printf("write_fru_data[%d]: %d bytes written\n",i,resp[0]); + if (ret != 0) break; + fruoff += (ushort)chunk; + } + return(ret); +} + +/* write_asset updates the FRU Product area only. */ +int +write_asset(char *tag, char *sernum, char *prodver, int flag, uchar *pfrubuf) +{ + int ret = -1; + uchar newdata[SZ_PRODAREA]; + int alen, clen; + int snlen, verlen; + uchar *pfru0; + uchar *pfru; + uchar *pnew; + int i, j, m, n, newlen, max; + int chas_offset; + int prod_offset, prod_len; + int mult_offset, mult_len; + uchar chksum; + char fdoasset = 0; + char fdosernum = 0; + char fdoprodver = 0; + char fdochassis = 0; + + if (flag == 0) return ERR_OTHER; + if (pfrubuf == NULL) pfrubuf = frubuf; + if (pfrubuf == NULL) return ERR_OTHER; + if ((flag & 0x01) != 0) { + fdoasset = 1; + alen = strlen_(tag); /*new*/ + } else { + alen = asset_len; /*old*/ + } + if ((flag & 0x02) != 0) { + fdosernum = 1; + snlen = strlen_(sernum); /*new*/ + } else { + snlen = sernum_len; /*old*/ + } + if ((flag & 0x200) != 0) { + fdochassis = 1; + // clen = strlen(chassis_nm); /*new, ignore*/ + // if (clen <= 1) return ERR_LENMIN; + clen = chassis_len; + } else { + clen = chassis_len; /*old*/ + } + if ((flag & 0x08) != 0) { + fdoprodver = 1; + verlen = strlen_(prodver); /*new*/ + } else verlen = prodver_len; /*old*/ + /* + * Abort if offset is negative or if it would clobber + * fru header (8 bytes). + * Abort if asset tag is too big for fru buffer. + */ + if (fdebug) { + printf("write_asset: asset_off=%d asset_len=%d alen=%d sFRU=%d\n", + asset_offset,asset_len,alen,sfru); + printf(" sernum_off=%d sernm_len=%d snlen=%d maxprod=%d\n", + sernum_offset,sernum_len,snlen,maxprod); + printf(" prodver=%d prodver_len=%d verlen=%d maxprod=%d\n", + prodver_offset,prodver_len,verlen,maxprod); + } + if (fdoasset && (alen <= 1)) return ERR_LENMIN; + if (fdosernum && (snlen <= 1)) return ERR_LENMIN; + if (asset_offset < 8) return ERR_LENMIN; + if (asset_offset + alen > sfru) return ERR_LENMAX; + if (sernum_offset < 8) return ERR_LENMIN; + if (sernum_offset + snlen > sfru) return ERR_LENMAX; + if (prodver_offset < 8) return ERR_LENMIN; + if (prodver_offset + verlen > sfru) return ERR_LENMAX; + + pfru0 = &pfrubuf[0]; + chas_offset = pfrubuf[2] * 8; // offset of chassis data + prod_offset = pfrubuf[4] * 8; // offset of product data + prod_len = pfrubuf[prod_offset+1] * 8; // length of product data + mult_offset = pfrubuf[5] * 8; + mult_len = 0; + if (mult_offset > 0) { + for (i = mult_offset; i < sfru; ) { + mult_len += (5 + pfrubuf[i+2]); + if (pfrubuf[i+1] & 0x80) break; + i = mult_len; + } + } + /* Check if asset tag will fit in product data area of FRU. */ + if (fdebug) + printf("write_asset: fru[4,p]=[%02x,%02x] prod_off=%d plen=%d veroff=%d\n", + pfrubuf[4],pfrubuf[prod_offset+1],prod_offset,prod_len, prodver_offset); + /* asset comes after sernum, so this check works for both */ + if (prod_offset > prodver_offset) return ERR_LENMAX; // offsets wrong + if (prod_len > sizeof(newdata)) return ERR_LENMAX; // product > buffer + + memset(newdata,0,prod_len); + pnew = &newdata[0]; + /* Copy fru data from start to chassis OEM */ + pfru = &pfrubuf[chas_offset]; + + /* Copy fru data before serial number */ + pfru = &pfrubuf[prod_offset]; + j = prodver_offset - prod_offset; + memcpy(pnew,pfru,j); + pfru += j; + pnew += j; + if (fdebug) { + printf("write_asset: fru[4,p]=[%02x,%02x] sernum_off=%d snlen=%d plen=%d\n", + pfrubuf[4],pfrubuf[sernum_offset+1],sernum_offset,snlen,prod_len); + } + if (fdoprodver) { + pnew[0] = (verlen | FRU_TYPE_MASK); /*add type=3 to snlen*/ + memcpy(++pnew,prodver,verlen); + } else { + pnew[0] = (verlen | FRU_TYPE_MASK); /*type/len byte*/ + memcpy(++pnew,&pfrubuf[prodver_offset+1],verlen); + } + j += prodver_len + 1; + pfru += prodver_len + 1; + pnew += verlen; /*already ++pnew above*/ + + /* Copy new or old serial number */ + if (fdebug) printf("pfrubuf[%ld]: %02x %02x %02x, j=%d, snlen=%d/%d\n", + (pfru-pfrubuf),pfru[0],pfru[1],pfru[2],j,snlen,sernum_len); + if (fdosernum) { + pnew[0] = (snlen | FRU_TYPE_MASK); /*add type=3 to snlen*/ + memcpy(++pnew,sernum,snlen); + } else { + pnew[0] = (snlen | FRU_TYPE_MASK); /*type/len byte*/ + memcpy(++pnew,&pfrubuf[sernum_offset+1],snlen); + } + /* increment past serial number, to asset tag */ + j += sernum_len + 1; + pfru += sernum_len + 1; + pnew += snlen; /*already ++pnew above*/ + + /* Copy new or old asset tag */ + if (fdebug) printf("pfrubuf[%ld]: %02x %02x %02x, j=%d, alen=%d/%d\n", + (pfru-pfrubuf),pfru[0],pfru[1],pfru[2],j,alen,asset_len); + if (fdoasset) { + pnew[0] = (alen | FRU_TYPE_MASK); /*add type=3 to len*/ + memcpy(++pnew,tag,alen); + } else { + pnew[0] = (alen | FRU_TYPE_MASK); /*type/len byte*/ + memcpy(++pnew,&pfrubuf[asset_offset+1],alen); + } + j += asset_len + 1; + pfru += asset_len + 1; + pnew += alen; + + /* copy trailing fru data from saved copy */ + n = (int)(pnew - newdata); /* new num bytes used */ + m = (int)(pfru - pfru0); /* old num bytes used */ + if (fdebug) printf("pfrubuf[%d]: %02x %02x %02x, j=%d, n=%d, plen=%d\n", + m,pfru[0],pfru[1],pfru[2],j,n,prod_len); + if (mult_offset > 0) { /* do not expand if multi-record area there */ + max = prod_len - j; + } else /* nothing else, can expand product area, up to sfru */ + max = sfru - (j + prod_offset); + if (fdebug) printf("pfrubuf[%ld]: %02x %02x %02x, j=%d n=%d remainder=%d\n", + (pfru-pfrubuf),pfru[0],pfru[1],pfru[2],j,n,max); + if (max < 0) max = 0; + for (i = 0; i < max; i++) { + pnew[i] = pfru[i]; + if (pfru[i] == FRU_END) { i++; break; } + } + if (i == max) { /*never found 0xC1 FRU_END*/ + pnew[0] = FRU_END; + i = 1; + } + + newlen = n + i; + if (fdebug) printf("newbuf[%d]: %02x %02x %02x, j=%d, newlen=%d\n", + n,pnew[0],pnew[1],pnew[2],j,newlen); + /* round up to next 8-byte boundary */ + /* need one more byte for checksum, so if mod=0, adds 8 anyway */ + j = 8 - (newlen % 8); + for (i = 0; i < j; i++) newdata[newlen++] = 0; + + if (newlen < prod_len) newlen = prod_len; /* don't shrink product area */ + newdata[1] = newlen / 8; // set length of product data + + /* include new checksum (calc over Product area) */ + chksum = calc_cksum(&newdata[0],newlen-1); + newdata[newlen-1] = chksum; + +#ifdef NEEDED + /* This caused a problem on Radisys systems, and is not needed, so skip it.*/ + if (mult_offset > 0) { + /* add on any more data from multi-record area */ + pnew = &newdata[newlen]; + pfru = &pfrubuf[mult_offset]; + memcpy(pnew,pfru,mult_len); + newlen += mult_len; + } +#endif + + if (fdebug) { + printf("old buffer (%d):",prod_len); + dumpbuf(&pfrubuf[prod_offset],prod_len); + printf("new buffer (%d):",newlen); + dumpbuf(newdata,newlen); + } + if (prod_offset + newlen >= sfru) return ERR_LENMAX; + if ((mult_offset > 0) && (newlen > prod_len)) return ERR_LENMAX; +#ifdef TEST + newlen = 0; +#endif + + ret = write_fru_data(0, (ushort)prod_offset, newdata, newlen, fdebug); + return(ret); +} + +#define SDR_CHUNKSZ 16 +#define LAST_REC 0xffff +#define SDR_STR_OFF 16 + +int get_sdr(ushort recid, ushort resid, ushort *recnext, + uchar *sdr, int *slen, uchar *pcc) +{ + uchar idata[6]; + uchar rdata[64]; + int sresp; + ushort cmd; + uchar cc = 0; + int len = 0; + int szsdr, thislen; + int rc; + + memset(sdr,0,*slen); /*clear sdr */ + idata[0] = resid & 0x00ff; + idata[1] = (resid & 0xff00) >> 8; + idata[2] = recid & 0x00ff; + idata[3] = (recid & 0xff00) >> 8; + idata[4] = 0; /*offset*/ + idata[5] = SDR_CHUNKSZ; /*bytes to read*/ + if (fdevsdrs) cmd = GET_DEVICE_SDR; + else cmd = GET_SDR; + sresp = sizeof(rdata); + rc = ipmi_cmd_mc(cmd, idata, 6, rdata, &sresp,&cc, fdebug); + if (fdebug) printf("get_sdr[%x] ret = %d cc = %x sresp = %d\n", + recid,rc,cc,sresp); + if (rc == 0 && cc == 0xCA) { /*cannot read SDR_CHUNKSZ bytes*/ + idata[5] = 8; /*bytes to read*/ + sresp = sizeof(rdata); + rc = ipmi_cmd_mc(cmd, idata, 6, rdata, &sresp,&cc, fdebug); + if (fdebug) printf("get_sdr[%x] ret = %d cc = %x sresp = %d\n", + recid,rc,cc,sresp); + } + *pcc = cc; + if (rc == 0 && cc == 0) { + *recnext = rdata[0] + (rdata[1] << 8); + if (sresp < 2) len = 0; + else len = sresp-2; + if (len > *slen) len = *slen; + memcpy(sdr,&rdata[2],len); + szsdr = sdr[4] + 5; /*get actual SDR size*/ + if (szsdr > *slen) szsdr = *slen; + /* if an SDR locator record, get the rest of it. */ + if (sdr[3] == 0x11 || sdr[3] == 0x12) + if (szsdr > SDR_CHUNKSZ) { + ushort resid2; + rc = sdr_get_reservation((uchar *)&resid2,fdevsdrs); + if (fdebug) printf("2nd sdr_get_reservation ret=%d\n",rc); + thislen = szsdr - SDR_CHUNKSZ; + if (thislen > SDR_CHUNKSZ) thislen = SDR_CHUNKSZ; + idata[0] = resid2 & 0x00ff; + idata[1] = (resid2 & 0xff00) >> 8; + idata[2] = recid & 0x00ff; + idata[3] = (recid & 0xff00) >> 8; + idata[4] = SDR_CHUNKSZ; /*offset*/ + idata[5] = (uchar)thislen; /*bytes to read*/ + sresp = sizeof(rdata); + rc = ipmi_cmd_mc(cmd, idata, 6, rdata, &sresp,&cc, fdebug); + if (fdebug) printf("get_sdr[%x] 2nd ret=%d cc=%x sresp=%d\n", + recid,rc,cc,sresp); + if (rc == 0 && cc == 0) { + if (sresp < 2) sresp = 0; + else sresp -= 2; + if (sresp > thislen) sresp = thislen; + memcpy(&sdr[len],&rdata[2],sresp); + len += sresp; + } else rc = 0; /*ok because got first part*/ + } /*endif got first chunk, need more*/ + *slen = len; + } else *slen = 0; + return(rc); +} + +void show_loadfru_error(uchar sa, uchar fruid, int ret) +{ + if (ret == 0) return; + switch(ret) { + case 0x081: printf("\tFRU(%x,%x) device busy\n",sa,fruid); break; + case 0x0C3: printf("\tFRU(%x,%x) timeout, not found\n",sa,fruid); break; + case 0x0CB: printf("\tFRU(%x,%x) not present\n",sa,fruid); break; + default: printf("load_fru(%x,%x) error = %d (0x%x)\n", + sa,fruid,ret,ret); + break; + } + return; +} + +int get_show_fru(ushort recid, uchar *sdr, int sdrlen) +{ + int ret = 0; + int ilen; + char idstr[32]; + uchar sa, fruid =0; + uchar frutype = 0; + char fgetfru = 0; + char fisbase = 0; + uchar *pfru; + + if (sdrlen > SDR_STR_OFF) { + ilen = sdrlen - SDR_STR_OFF; + if (ilen >= sizeof(idstr)) ilen = sizeof(idstr) - 1; + memcpy(idstr,&sdr[SDR_STR_OFF],ilen); + idstr[ilen] = 0; + } else idstr[0] = 0; + sa = sdr[5]; /* usu 0x20 for bmc_sa */ + if (fbasefru) fisbase = 1; + + /* Get its FRU data */ + if ((sdr[3] == 0x11) && (sdr[7] & 0x80)) { /* FRU SDRs */ + /* It is a logical FRU device */ + if (fcanonical) + printf("SDR[%04x] FRU %c %s\n", recid, bdelim, idstr); + else + printf("SDR[%04x] FRU %02x %02x %02x %02x %s\n", recid, + sdr[5],sdr[6],sdr[12],sdr[13],idstr); + fruid = sdr[6]; + if (sdrlen > 12) frutype = sdr[12]; + if (sa == bmc_sa && fruid == 0) { /*dont repeat base fru */ + frutype = 0x0c; + fisbase = 1; + if (fbasefru) fgetfru = 1; + } else + switch(frutype) /*FRU entity id*/ + { + case 0x0a: /*Power Supply*/ + case 0x20: /*DIMM*/ + case 0x15: /*Power Cage*/ + default: + fgetfru = 1; + break; + } + } else if (sdr[3] == 0x12) { /* IPMB SDRs (DLRs for MCs) */ + if (fcanonical) + printf("SDR[%04x] IPMB %c %s\n", recid, bdelim, idstr); + else + printf("SDR[%04x] IPMB %02x %02x %02x %02x %s\n", recid, + sdr[5],sdr[6],sdr[12],sdr[13],idstr); + fruid = 0; /*every MC must have fruid 0*/ + if (sdrlen > 12) frutype = sdr[12]; + if (sa == bmc_sa && fruid == 0) { /*dont repeat base fru */ + fisbase = 1; + frutype = 0x07; + if (fdebug) printf("do bmc_sa %02x once\n",sa); + g_frutype = frutype; + if (fbasefru) fgetfru = 1; + } else if (frutype == 0x2e) { /*skip ME*/ + if (fdebug) printf("skipping ME sa %02x, %02x\n",sa,fruid); + } else if (sa == 0x28) { /*do nothing for Bridge Ctlr sa=0x28*/ + if (fdebug) printf("skipping IPMB sa %02x, %02x\n",sa,fruid); + } else if (sa == 0xC0) { /* HotSwap Backplane (sa=0xC0) */ + /* Note: Loading sa 0xC0 over ipmi lan gives a timeout + * error, but it works locally. */ + fgetfru = 1; + } else { /* other misc sa,fruid */ + fgetfru = 1; + } + } + + /* Check if matches previous FRU, if so don't repeat */ + if ((sa == lastfru[0]) && (fruid == lastfru[1]) ) + fgetfru = 0; + + if (fgetfru) { + uchar adrtype; + adrtype = g_addrtype; + if (fdebug) printf("set_mc %02x:%02x:%02x type=%d fruid=%02x\n", + g_bus,sa,g_lun,adrtype,fruid); + ipmi_set_mc(g_bus, sa, g_lun,adrtype); + ret = load_fru(sa,fruid,frutype,&pfru); + if (ret != 0) { + show_loadfru_error(sa,fruid,ret); + } else { + ret = show_fru(sa,fruid,frutype,pfru); + if (ret != 0) printf("show_fru error = %d\n",ret); + if (sa == bmc_sa && fruid == 0) fbasefru = 0; + } + free_fru(pfru); + pfru = NULL; + ipmi_restore_mc(); + lastfru[0] = sa; + lastfru[1] = fruid; + lastfru[2] = frutype; + } + return(ret); +} + +/* + * test_show_fru + * + * Reads the FRU buffer dump from a file to test decoding the FRU. + * This file uses the format output from 'ipmiutil fru -x'. + * +[Component,20,00] Component FRU Size : 4096 +FRU Header: 01 0a 00 01 20 00 00 d4 +FRU Body (size=256/4096): + 0000: 01 0a 00 01 20 00 00 d4 01 09 00 c0 3b 7e 83 64 .... .......;~.d + * + */ +static int test_show_fru(char *infile) +{ + int rv = -1; + FILE *fp; + int len, i, idx, sz, off; + uchar buff[256]; + uchar sa = 0x20; + uchar fruid =0; + uchar frutype = 0; + uchar *pfru = NULL; + char *p1; + char *p2; + + fp = fopen(infile,"r"); + if (fp == NULL) { + printf("Cannot open file %s\n",infile); + return(ERR_FILE_OPEN); + } else { + if (fdebug) printf("decoding text file with FRU buffer bytes\n"); + idx = 0; + off = 0; + sz = sizeof(buff); + while (fgets(buff, 255, fp)) { + len = strlen_(buff); + if (fdebug) printf("fgets[%d]: %s",idx,buff); /*has '\n'*/ + if (idx == 0) { /* the FRU Size line*/ + p1 = strstr(buff,"FRU Size"); + if (p1 == NULL) continue; + p1 = strchr(buff,','); + if (p1 == NULL) continue; + p1++; + p2 = strchr(p1,','); + if (p2 == NULL) p2 = &buff[len]; + *p2 = 0; /*stringify*/ + sa = htoi(p1); + p1 = p2 + 1; + p2 = strchr(p1,']'); + if (p2 == NULL) p2 = &buff[len]; + *p2 = 0; /*stringify*/ + fruid = htoi(p1); + frutype = 0; + if (fdebug) printf("read[%d] sa=%x fruid=%x\n",idx,sa,fruid); + idx++; + } else if (idx == 1) { /* the FRU Header line*/ + p1 = strstr(buff,"FRU Header"); + // if (p1 == NULL) continue; + if (fdebug) printf("read[%d] p1=%p\n",idx,p1); + idx++; + } else if (idx == 2) { /* the FRU Bodu line*/ + p1 = strstr(buff,"FRU Body"); + if (p1 == NULL) continue; + p1 = strchr(buff,'='); + if (p1 == NULL) continue; + ++p1; + p2 = strchr(p1,'/'); + if (p2 == NULL) p2 = &buff[len]; + *p2 = 0; /*stringify*/ + sz = atoi(p1); + p1 = p2 + 1; + p2 = strchr(p1,')'); + if (p2 == NULL) p2 = &buff[len]; + *p2 = 0; /*stringify*/ + sfru = atoi(p1); /*global sfru*/ + pfru = malloc(sfru); + if (fdebug) + printf("read[%d] sz=%d/%d pfru=%p\n",idx,sz,sfru,pfru); + idx++; + } else { /*idx==3, this has the FRU buffer data */ + p1 = strchr(buff,':'); + if (p1 == NULL) continue; + p1 += 2; + for (i = 0; i < 16; i++) { + pfru[off+i] = htoi(&p1[i*3]); + } + off += 16; + if (fdebug) printf("read[%d] offset=%d\n",idx,off); + } /*endif */ + if (off >= sz) { rv = 0; break; } + } /*end while*/ + + fclose(fp); + if (rv == 0) { + if (pfru == NULL) { + printf("Invalid input file format (mode %d)\n",idx); + return(ERR_BAD_FORMAT); + } + rv = show_fru(sa,fruid,frutype,pfru); + if (rv != 0) printf("show_fru error = %d\n",rv); + } + free_fru(pfru); + } + return(rv); +} + +#ifdef ALONE +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#else +/* METACOMMAND */ +int i_fru(int argc, char **argv) +#endif +{ + int ret, rv; + int c; + char DevRecord[16]; + ushort recid; + ushort nextid; + ushort rsvid; + uchar sdr[48]; + char biosver[80]; + uchar cc; + uchar sa; + //uchar fruid = 0; + //uchar frutype = 0; + int len, i, j; + char *s1; + uchar *pfru = NULL; + FILE *fp; + int ipass, npass, nsdrs; + char *tag; + char do_reserve = 1; + char devstr[32]; + + printf("%s: version %s\n",progname,progver); + + parse_lan_options('V',"4",0); /*default to admin privilege*/ + while ( (c = getopt( argc, argv,"a:bcd:efhkl:m:n:i:p:r:s:t:v:xyzT:V:J:EYF:P:N:R:U:Z:?")) != EOF ) + switch(c) { + case 'x': fdebug = 1; break; + case 'z': fdebug = 3; break; /*do more LAN debug detail*/ + case 'b': fonlybase = 1; + g_frutype = 0x07; break; + case 'c': fcanonical = 1; bdelim = BDELIM; break; + case 'd': fdump = 1; /*dump fru to a file*/ + binfile = optarg; + break; + case 'e': fchild = 1; break; /*extra child MCs if bladed*/ + case 'f': fchild = 1; break; /*follow child MCs if bladed*/ + case 'h': fonlyhsc = 1; /* show HSC FRU, same as -m00c000s */ + g_frutype = 0x0f; break; + case 'k': foemkontron = 1; break; + case 'n': + fwritefru |= 0x200; + if (optarg) { + len = strlen_(optarg); + if (len >= FIELD_LEN) len = FIELD_LEN - 1; + strncpy(chassis_name,optarg,len); + if (len == 1) { /* add a space */ + chassis_name[1] = ' '; + chassis_name[2] = 0; + } + } + break; + case 'p': /*Power Supply Product */ + // fwritefru |= 0x10; + if (optarg) { + len = strlen_(optarg); + if (len >= FIELD_LEN) len = FIELD_LEN - 1; + strncpy(ps_prod,optarg,len); + if (len == 1) { /* add a space */ + ps_prod[1] = ' '; + ps_prod[2] = 0; + } + } + break; + case 'r': frestore = 1; /*restore fru from a file*/ + fwritefru = 0x100; + binfile = optarg; + break; + case 't': ftestshow = 1; /*test show_fru from a file*/ + binfile = optarg; + break; + case 'a': + fwritefru |= 0x01; + if (optarg) { + len = strlen_(optarg); + if (len >= FIELD_LEN) len = FIELD_LEN - 1; + strncpy(asset_tag,optarg,len); + if (len == 1) { /* add a space */ + asset_tag[1] = ' '; + asset_tag[2] = 0; + } + } + break; + case 's': + fwritefru |= 0x02; + if (optarg) { + len = strlen_(optarg); + if (len >= FIELD_LEN) len = FIELD_LEN - 1; + strncpy(serial_num,optarg,len); + if (len == 1) { /* add a space */ + serial_num[1] = ' '; + serial_num[2] = 0; + } + } + break; + case 'v': + fwritefru |= 0x08; + if (optarg) { + len = strlen_(optarg); + if (len >= FIELD_LEN) len = FIELD_LEN - 1; + strncpy(prod_ver,optarg,len); + if (len == 1) { /* add a space */ + prod_ver[1] = ' '; + prod_ver[2] = 0; + } + } + break; + case 'm': /* specific IPMB MC, 3-byte address, e.g. "409600" */ + g_bus = htoi(&optarg[0]); /*bus/channel*/ + g_sa = htoi(&optarg[2]); /*device slave address*/ + g_lun = htoi(&optarg[4]); /*LUN*/ + g_addrtype = ADDR_IPMB; + if (optarg[6] == 's') { + g_addrtype = ADDR_SMI; s1 = "SMI"; + } else { g_addrtype = ADDR_IPMB; s1 = "IPMB"; } + fset_mc = 1; + printf("set MC at %s bus=%x sa=%x lun=%x\n", + s1,g_bus,g_sa,g_lun); + break; + case 'l': /* set local IPMB MC sa (same as -Z but sets bmc_sa) */ + sa = htoi(&optarg[0]); /*device slave address*/ + ipmi_set_mymc(g_bus, sa, g_lun,ADDR_IPMB); + bmc_sa = sa; + break; + case 'i': fonlybase = 1; /*specify a fru id*/ + if (strncmp(optarg,"0x",2) == 0) g_fruid = htoi(&optarg[2]); + else g_fruid = htoi(optarg); + printf("Using FRU ID 0x%02x\n",g_fruid); + break; + case 'y': fdoanyway = 1; break; + case 'V': /* priv level */ + fprivset = 1; + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + break; + default: + printf("Usage: %s [-bceikmtvx -a asset_tag -s ser_num -NUPREFTVY]\n", + progname); + printf(" -a tag Sets the Product Asset Tag\n"); + printf(" -b Only show Baseboard FRU data\n"); + printf(" -c show canonical, delimited output\n"); + printf(" -d file Dump the binary FRU data to a file\n"); + printf(" -e walk Every child FRU, for blade MCs\n"); + printf(" -i 00 Get a specific FRU ID\n"); + printf(" -k Kontron setsn, setmfgdate\n"); + printf(" -m002000 specific MC (bus 00,sa 20,lun 00)\n"); + printf(" -s snum Sets the Product Serial Number\n"); + printf(" -v pver Sets the Product Version Number\n"); + printf(" -x Display extra debug messages\n"); + print_lan_opt_usage(); + ret = ERR_USAGE; + goto do_exit; + } + + if (ftestshow) { + ret = test_show_fru(binfile); + goto do_exit; + } + + if (is_remote() && (!fprivset)) { + /* If priv not specified, not writing, and only targetted FRU, + can default to request user privilege. */ + if (!fwritefru && fonlybase) parse_lan_options('V',"2",0); + } + + ret = ipmi_getdeviceid( DevRecord, sizeof(DevRecord),fdebug); + if (ret == 0) { + uchar ipmi_maj, ipmi_min; + ipmi_maj = DevRecord[4] & 0x0f; + ipmi_min = DevRecord[4] >> 4; + vend_id = DevRecord[6] + (DevRecord[7] << 8) + (DevRecord[8] << 16); + prod_id = DevRecord[9] + (DevRecord[10] << 8); + show_devid( DevRecord[2], DevRecord[3], ipmi_maj, ipmi_min); + if (ipmi_maj < 2) do_systeminfo = 0; + if ((DevRecord[1] & 0x80) == 0x80) fdevsdrs = 1; + if (vend_id == VENDOR_NEC) fdevsdrs = 0; + else if (vend_id == VENDOR_SUN) { + do_guid = 0; /*Sun doesn't support GUID*/ + do_systeminfo = 0; /*Sun doesn't support system info*/ + } else if (vend_id == VENDOR_INTEL) { + if (is_thurley(vend_id,prod_id) || is_romley(vend_id,prod_id)) + set_max_kcs_loops(URNLOOPS); /*longer for cmds (default 300)*/ + } + } else { + goto do_exit; + } + + ret = ipmi_getpicmg( DevRecord, sizeof(DevRecord),fdebug); + if (ret == 0) fpicmg = 1; + if (!fpicmg) fdevsdrs = 0; /* override, use SDR repository for FRU */ + if (fdebug) printf("bmc_sa = %02x, fdevsdrs = %d\n",bmc_sa,fdevsdrs); + + if (fset_mc) { + /* target a specific MC via IPMB (usu a picmg blade) */ + if (fdebug) printf("set_mc: %02x:%02x:%02x type=%d\n", + g_bus,g_sa,g_lun,g_addrtype); + ipmi_set_mc(g_bus,g_sa,g_lun,g_addrtype); + fonlybase = 1; /*only show this MC*/ + } else { + g_sa = bmc_sa; /* BMC_SA = 0x20 */ + } + if (g_frutype == 0) { + g_frutype = 0x01; /* other = "Component" */ + } + + if (foemkontron) { +#ifdef METACOMMAND + for (i = 0; i < optind; i++) { argv++; argc--; } + if (fdebug) verbose = 1; + ret = ipmi_kontronoem_main(NULL,argc,argv); +#else + ret = LAN_ERR_NOTSUPPORT; +#endif + goto do_exit; + } + npass = 1; + + if (fonlybase || fonlyhsc) fbasefru = 1; + else { + /* find FRU devices from SDRs */ + if (fpicmg && fdevsdrs) { + /* npass = 2 will get both SdrRep & DevSdr passes on CMM */ + npass = 2; + g_addrtype = ADDR_IPMB; + } + + nsdrs = 0; + for (ipass = 0; ipass < npass; ipass++) + { + ret = GetSDRRepositoryInfo(&j,&fdevsdrs); + if (fdebug) printf("GetSDRRepositoryInfo: ret=%x nSDRs=%d fdevsdrs=%d\n", + ret,j,fdevsdrs); + if (j == 0) { + /* this is an error, probably because fdevsdrs is wrong.*/ + fdevsdrs = (fdevsdrs ^ 1); + if (fdebug) printf("nsdrs=0, retrying with fdevsdrs=%d\n",fdevsdrs); + j = 60; /*try some default num SDRs*/ + } + nsdrs = j; + if (fdevsdrs) tag="Device SDRs"; + else tag="SDR Repository"; + printf("--- Scanning %s for %d SDRs ---\n",tag,nsdrs); + + /* loop thru SDRs to find FRU devices */ + recid = 0; + while (recid != LAST_REC) + { + if (do_reserve) { + /* reserve the SDR repository */ + ret = sdr_get_reservation((uchar *)&rsvid,fdevsdrs); + if (fdebug) printf("sdr_get_reservation ret=%d\n",ret); + if (ret == 0) do_reserve = 0; + } + + len = sizeof(sdr); /*sizeof(sdr); get 32 sdr bytes*/ + ret = get_sdr(recid,rsvid,&nextid,sdr,&len,&cc); + if ((ret != 0) || (cc != 0)) { + printf("SDR[%04x] error %d ccode = %x\n",recid,ret,cc); + if ((cc == 0xC5) || (cc == 0x83)) ; /*do not stop (ARC)*/ + else break; /*stop if errors*/ + } + if (len >= MIN_SDR_SZ) { + if ((sdr[3] == 0x11) || (sdr[3] == 0x12)) /*SDR FRU or IPMB type*/ + ret = get_show_fru(recid, sdr,len); + do_reserve = 1; + } /*endif get_show_fru */ +#ifdef PICMG_CHILD + /* + * Special logic for blade child MCs in PICMG ATCA systems + * if fchild, try all child MCs within the chassis. + * SDR type 12 capabilities bits (sdrdata[8]): + * 80 = Chassis Device + * 40 = Bridge + * 20 = IPMB Event Generator + * 10 = IPMB Event Receiver + * 08 = FRU Device + * 04 = SEL Device + * 02 = SDR Repository Device + * 01 = Sensor Device + * But all child MCs use Device SDRs anyway. + */ + if (fpicmg && fchild && (sdr[3] == 0x12)) { /* PICMG MC DLR */ + ushort _recid, _recnext; + int _sz; + uchar _sdrdata[MAX_SDR_SIZE]; + int devsdrs_save; + uchar cc; + + /* save the BMC globals, use IPMB MC */ + devsdrs_save = fdevsdrs; + fdevsdrs = 1; /* use Device SDRs for the children*/ + if (fdebug) + printf(" --- IPMB MC (sa=%02x cap=%02x id=%02x devsdrs=%d):\n", + sdr[5],sdr[8],sdr[12],fdevsdrs); + ipmi_set_mc(PICMG_SLAVE_BUS,sdr[5],sdr[6],g_addrtype); + + _sz = 16; + ret = ipmi_cmd_mc(GET_DEVICE_ID,NULL,0,_sdrdata,&_sz,&cc,fdebug); + if (ret == 0 && cc == 0) { + /* get a new SDR Reservation ID */ + ret = sdr_get_reservation((uchar *)&rsvid,fdevsdrs); + if (fdebug) printf("sdr_get_reservation ret=%d\n",ret); + /* Get the SDRs from the IPMB MC */ + _recid = 0; + while (_recid != 0xffff) + { + _sz = sizeof(_sdrdata); + ret = get_sdr(_recid,rsvid,&_recnext,_sdrdata,&_sz,&cc); + if (fdebug) printf("get_sdr(%x) rv=%d cc=%x rlen=%d\n", + _recid,ret,cc,_sz); + if (ret != 0) { + printf("%04x get_sdr error %d, rlen=%d\n",_recid,ret,_sz); + break; + } + else if (_sz >= MIN_SDR_SZ) { + if ((_sdrdata[3] == 0x11) || (_sdrdata[3] == 0x12)) + ret = get_show_fru(_recid, _sdrdata, _sz); + } + if (_recnext == _recid) _recid = 0xffff; + else _recid = _recnext; + } /*end while*/ + } /*endif ret==0*/ + + /* restore BMC globals */ + fdevsdrs = devsdrs_save; + ipmi_restore_mc(); + do_reserve = 1; /* get a new SDR Reservation ID */ + } /*endif fpicmg && fchild*/ +#endif + + recid = nextid; + } /*end while sdrs*/ + if (npass > 1) { /*npass==2 for PICMG child*/ + /* Switch fdevsdrs from Device to Repository (or vice-versa) */ + if (fdevsdrs == 0) fdevsdrs = 1; + else fdevsdrs = 0; + } + } /*end ipass loop*/ + } /*endif not fonlybase*/ + + /* load the FRU data for Baseboard (address 0x20) */ + printf("\n"); + sa = g_sa; /* bmc_sa = BMC_SA = 0x20 */ + if (fonlyhsc) { sa = 0xC0; g_addrtype = ADDR_SMI; + ipmi_set_mc(g_bus,sa,g_lun,g_addrtype); + } + if (g_addrtype == ADDR_IPMB) + ipmi_set_mc(g_bus,sa,g_lun,g_addrtype); + + if (fbasefru) { + /* get and display the Baseboard FRU data */ + ret = load_fru(sa,g_fruid,g_frutype,&pfru); + if (ret != 0) { + show_loadfru_error(sa,g_fruid,ret); + free_fru(pfru); + pfru = NULL; + goto do_exit; + } + ret = show_fru(sa,g_fruid,g_frutype,pfru); + if (ret != 0) printf("show_fru error = %d\n",ret); + } + + if (fcanonical) devstr[0] = 0; /*default is empty string*/ + else sprintf(devstr,"[%s,%02x,%02x] ", /*was by g_frutype*/ + FruTypeString(SYS_FRUTYPE,g_fruid),sa,g_fruid); + + if (!is_remote()) { + i = get_BiosVersion(biosver); + if (i == 0) + printf("%sBIOS Version %c %s\n",devstr,bdelim,biosver); + } + + if (do_systeminfo) { + char infostr[64]; + int len; + len = sizeof(infostr); + rv = get_system_info(1,infostr,&len); /*Firmware Version*/ + if (rv == 0) { + len = sizeof(infostr); + rv = get_system_info(2,infostr,&len); + if (rv == 0) printf("%sSystem Name %c %s\n",devstr,bdelim,infostr); + len = sizeof(infostr); + rv = get_system_info(3,infostr,&len); + if (rv == 0) printf("%sPri Operating System%c %s\n",devstr,bdelim,infostr); + len = sizeof(infostr); + rv = get_system_info(4,infostr,&len); + if (rv == 0) printf("%sSec Operating System%c %s\n",devstr,bdelim,infostr); + } else { + if (fdebug && (rv == 0xC1)) /*only supported on later IPMI 2.0 fw */ + printf("GetSystemInfo not supported on this platform\n"); + } + } + + if (fdump && ret == 0) { + /* Dump FRU to a binary file */ + fp = fopen(binfile,"w"); + if (fp == NULL) { + ret = get_LastError(); + printf("Cannot open file %s, error %d\n",binfile,ret); + } else { + printf("Writing FRU size %d to %s ...\n",sfru,binfile); + len = (int)fwrite(frubuf, 1, sfru, fp); + fclose(fp); + if (len <= 0) { + ret = get_LastError(); + printf("Error %d writing file %s\n",ret,binfile); + } else ret = 0; + } + goto do_exit; + } + else if (frestore) { + uchar cksum; + /* Restore FRU from a binary file */ + fp = fopen(binfile,"r"); + if (fp == NULL) { + ret = get_LastError(); + printf("Cannot open file %s, error %d\n",binfile,ret); + } else { + ret = 0; + /* sfru and frubuf were set from load_fru above. */ + len = (int)fread(frubuf, 1, sfru, fp); + if (len <= 0) { + ret = get_LastError(); + printf("Error %d reading file %s\n",ret,binfile); + sfru = 0; /*for safety*/ + } + fclose(fp); + if (fdebug) { + printf("FRU buffer from file (%d):",sfru); + dumpbuf(frubuf,sfru); + } + /* Do some validation of the FRU buffer header */ + cksum = calc_cksum(&frubuf[0],7); + if (fdebug) + printf("header, len=8, cksum0 = %02x, cksum1 = %02x\n", + frubuf[7],cksum); + if (frubuf[7] != cksum) { + printf("Not a valid FRU file\n"); + ret = ERR_BAD_FORMAT; + free_fru(frubuf); + } + if (ret == 0) { /*successfully read data*/ + printf("Writing FRU size %d from %s ...\n",sfru,binfile); + ret = write_fru_data(g_fruid, 0, frubuf, sfru, fdebug); + free_fru(frubuf); + if (ret != 0) printf("write_fru error %d (0x%02x)\n",ret,ret); + else { /* successful, show new data */ + ret = load_fru(sa,g_fruid,g_frutype,&pfru); + if (ret != 0) show_loadfru_error(sa,g_fruid,ret); + else ret = show_fru(sa,g_fruid,g_frutype,pfru); + free_fru(pfru); + pfru = NULL; + } + } + } + } /*end-else frestore */ + else if ((fwritefru != 0) && ret == 0) { + if (fbasefru == 0) { + /* if not fbasefru, must reload fru because freed in get_show_fru */ + ret = load_fru(sa,g_fruid,g_frutype,&pfru); + if (ret != 0) { + show_loadfru_error(sa,g_fruid,ret); + free_fru(pfru); + pfru = NULL; + goto do_exit; + } + if (fdebug) printf("Baseboard FRU buffer reloaded (%d):",sfru); + } + printf("\nWriting new product data (%s,%s,%s) ...\n", + prod_ver,serial_num,asset_tag); + ret = write_asset(asset_tag,serial_num,prod_ver,fwritefru,pfru); + free_fru(pfru); + if (ret != 0) printf("write_asset error %d (0x%02x)\n",ret,ret); + else { /* successful, show new data */ + ret = load_fru(sa,g_fruid,g_frutype,&pfru); + if (ret != 0) show_loadfru_error(sa,g_fruid,ret); + else ret = show_fru(sa,g_fruid,g_frutype,pfru); + free_fru(pfru); + } + pfru = NULL; + } + else + free_fru(pfru); + +do_exit: + ipmi_close_(); + // show_outcome(progname,ret); + return(ret); +} + +/* end ifru.c */ diff --git a/util/ifru.h b/util/ifru.h new file mode 100644 index 0000000..f3efaf6 --- /dev/null +++ b/util/ifru.h @@ -0,0 +1,13 @@ +/* + * ifru.h + * common routines from ifru.c + */ +#ifndef uchar +#define uchar unsigned char +#endif + +int load_fru(uchar sa, uchar frudev, uchar frutype, uchar **pfrubuf); +int show_fru(uchar sa, uchar frudev, uchar frutype, uchar *pfrubuf); +void free_fru(uchar *pfrubuf); + +/* end ifru.h */ diff --git a/util/ifru_picmg.c b/util/ifru_picmg.c new file mode 100644 index 0000000..fd6234f --- /dev/null +++ b/util/ifru_picmg.c @@ -0,0 +1,486 @@ +/* + * ifru_picmg.c + * These are helper routines for FRU PICMG decoding. + * + * Author: Andy Cress arcress at users.sourceforge.net + * + * Copyright (c) 2009 Kontron America, Inc. + * + * 09/08/10 Andy Cress - created + */ +/*M* +Copyright (c) 2010 Kontron America, 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: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions 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. + c.. Neither the name of Kontron nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ +#ifdef WIN32 +#include +#include +#include "getopt.h" +#else +#include +#include +#include +#include +#endif +#include + +#include "ipmicmd.h" +#include "ipicmg.h" + +extern int verbose; +extern void show_guid(uchar *pguid); /*from ifru.c*/ + +static char *picmg_link_type(uchar b) +{ + char *s; + if (b >= 0xf0 && b <= 0xf3) s = "OEM GUID Definition"; + else switch(b) { + case 0x01: s = "PICMG 3.0 Base Interface 10/100/1000"; break; + case 0x02: s = "PICMG 3.1 Ethernet Fabric Interface"; break; + case 0x03: s = "PICMG 3.2 Infiniband Fabric Interface"; break; + case 0x04: s = "PICMG 3.3 Star Fabric Interface"; break; + case 0x05: s = "PICMG 3.4 PCI Express Fabric Interface"; break; + default: s = "Reserved"; break; + } + return(s); +} + +static char *picmg_if_type(uchar b) +{ + char *s; + switch(b) { + case 0x00: s = "Base Interface"; break; + case 0x01: s = "Fabric Interface"; break; + case 0x02: s = "Update Channel"; break; + case 0x03: + default: s = "Reserved"; break; + } + return(s); +} + +static char *picmg_chan_type(uchar b) +{ + char *s; + switch(b) { + case 0x00: + case 0x07: s = "PICMG 2.9"; break; + case 0x08: s = "Single Port Fabric IF"; break; + case 0x09: s = "Double Port Fabric IF"; break; + case 0x0a: s = "Full Port Fabric IF"; break; + case 0x0b: s = "Base IF"; break; + case 0x0c: s = "Update Channel IF"; break; + default: s = "Unknown IF"; break; + } + return(s); +} + +void show_fru_picmg(uchar *pdata, int dlen) +{ + int id, i, j, k, m, n; + float f; + uchar *p; + uchar b0, b1, b2, b3, b4, b5, b6, b7, b8; + char *s1, *s2; + long l1, l2, l3; + + id = pdata[3]; + i = 5; + switch(id) { + case FRU_PICMG_BACKPLANE_P2P: + printf("\tFRU_PICMG_BACKPLANE_P2P\n"); + while (i <= dlen) { + b1 = pdata[i]; + b2 = pdata[i+1]; + b3 = pdata[i+2]; + printf("\t Channel Type : %02x - %s\n",b1, + picmg_chan_type(b1)); + printf("\t Slot Address : %02x\n",b2); + printf("\t Channel Count : %02x\n",b3); + i += 3; + for (j = 0; j < b3; j++) { + if (i > dlen) break; + if (verbose) + printf("\t Channel[%d] : %02x -> %02x in slot %02x\n", + j,pdata[i],pdata[i+1],pdata[i+2]); + i += 3; + } + } + break; + case FRU_PICMG_ADDRESS_TABLE: + printf("\tFRU_PICMG_ADDRESS_TABLE\n"); + printf("\t Type/Len : %02x\n", pdata[i++]); + printf("\t Shelf Addr : "); + for (j = 0; j < 20; j++) + printf("%02x ",pdata[i++]); + printf("\n"); + n = pdata[i++]; + printf("\t AddrTable Entries: %02x\n",n); + for (j = 0; j < n; j++) { + if (i >= dlen) break; + printf("\t HWAddr %02x, SiteNum %02x, SiteType %02x\n", + pdata[i], pdata[i+1], pdata[i+2]); + i += 3; + } + break; + case FRU_PICMG_SHELF_POWER_DIST: + printf("\tFRU_PICMG_SHELF_POWER_DIST\n"); + n = pdata[i++]; + printf("\t Num Power Feeds : %02x\n",n); + for (j = 0; j < n; j++) { + if (i >= dlen) break; + printf("\t Max Ext Current : %04x\n", + (pdata[i] | (pdata[i+1] << 8))); + i += 2; + printf("\t Max Int Current : %04x\n", + (pdata[i] | (pdata[i+1] << 8))); + i += 2; + printf("\t Min Exp Voltage : %02x\n", pdata[i++]); + m = pdata[i++]; /*num entries*/ + printf("\t Feed to FRU count: %02x\n", m); + for (k = 0; k < m; k++) { + if (i >= dlen) break; + printf("\t HW: %02x",pdata[i++]); + printf(" FRU ID: %02x\n",pdata[i++]); + } + } + break; + case FRU_PICMG_SHELF_ACTIVATION: + printf("\tFRU_PICMG_SHELF_ACTIVATION\n"); + printf("\t Allowance for FRU Act Readiness : %02x\n", + pdata[i++]); + n = pdata[i++]; + printf("\t FRU activation and Power desc Cnt: %02x\n",n); + for (j = 0; j < n; j++) { + if (i >= dlen) break; + printf("\t HW Addr: %02x, ", pdata[i++]); + printf(" FRU ID: %02x, ", pdata[i++]); + printf(" Max FRU Power: %04x, ", pdata[i] | (pdata[i+1]<<8)); + i += 2; + printf(" Config: %02x\n", pdata[i++]); + } + break; + case FRU_PICMG_SHMC_IP_CONN: + printf("\tFRU_PICMG_SHMC_IP_CONN\n"); + printf("\t Conn Data: "); + for ( ; i < dlen; i++) { + printf("%02x ",pdata[i]); + } + printf("\n"); + break; + case FRU_PICMG_BOARD_P2P: /*0x14*/ + printf("\tFRU_PICMG_BOARD_P2P\n"); + n = pdata[i++]; /*guid count*/ + printf("\t GUID count : %d\n",n); + for (j = 0; j < n; j++) { + printf("\t GUID[%d] : ",j); + show_guid(&pdata[i]); + printf("\n"); + i += 16; + } + for (j = 1; i < dlen; i += 4) { + p = &pdata[i]; + b1 = (p[0] & 0x3f); /*chan*/ + b2 = (p[0] & 0xc0) >> 6; /*if*/ + b3 = (p[1] & 0x0f); /*port*/ + b4 = ((p[1] & 0xf0) >> 4) + (p[2] & 0xf0); /*type*/ + b5 = (p[2] & 0x0f); /*ext*/ + b6 = p[3]; /*grouping*/ + printf("\t Link%d Grouping : %02x\n",j,b6); + printf("\t Link%d Extension : %02x\n",j,b5); + printf("\t Link%d Type : %02x - %s\n", + j,b4,picmg_link_type(b4)); + printf("\t Link%d Port : %02x\n",j,b3); + printf("\t Link%d Interface : %02x - %s\n", + j,b2,picmg_if_type(b2)); + printf("\t Link%d Channel : %02x\n",j,b1); + j++; + } + break; + case FRU_AMC_CURRENT: + printf("\tFRU_AMC_CURRENT\n"); + b1 = pdata[i]; /*current*/ + f = (float)(b1/10.0); + printf("\t Current draw: %.1f A @ 12V => %.2f Watt\n", + f, (f*12.0)); + break; + case FRU_AMC_ACTIVATION: + printf("\tFRU_AMC_ACTIVATION\n"); + b1 = pdata[i] | (pdata[i+1]<<8); /*max current*/ + i += 2; + f = (float)b1 / 10; + printf("\t Max Internal Current(@12V) : %.2f A [ %.2f Watt ]\n", + f, f*12); + printf("\t Module Activation Readiness: %i sec.\n",pdata[i++]); + n = pdata[i++]; + printf("\t Descriptor Count: %i\n",n); + for (j = 0; i < dlen; i += 3) { + if (j >= n) break; + printf("\t IPMB Address : %02x\n",pdata[i]); + printf("\t Max Module Current: %.2f A\n", + (float)(pdata[i+1]/10)); + j++; + } + break; + case FRU_AMC_CARRIER_P2P: + printf("\tFRU_AMC_CARRIER_P2P\n"); + for ( ; i < dlen; ) { + b1 = pdata[i]; /*resource id*/ + n = pdata[i+1]; /*desc count*/ + i += 2; + b2 = (b1 >> 7); + printf("\t Resource ID: %i, Type: %s\n", + (b1 & 0x07), (b2 == 1 ? "AMC" : "Local")); + printf("\t Descriptor Count: %i\n",n); + for (j = 0; j < n; j++) { + if (i >= dlen) break; + p = &pdata[i]; + b3 = p[0]; /*remote resource id*/ + b4 = (p[1] & 0x1f); /*remote port*/ + b5 = (p[1] & 0xe0 >> 5) + (p[2] & 0x03 << 3); /*local*/ + printf("\t Port %02d -> Remote Port %02d " + "[ %s ID: %02d ]\n", b5, b4, + ((b3 >> 7) == 1)? "AMC " : "local", b3 & 0x0f); + i += 3; + } + } + break; + case FRU_AMC_P2P: + printf("\tFRU_AMC_P2P\n"); + n = pdata[i++]; /*guid count*/ + printf("\t GUID count : %d\n",n); + for (j = 0; j < n; j++) { + printf("\t GUID[%d] : ",j); + show_guid(&pdata[i]); + printf("\n"); + i += 16; + } + b1 = pdata[i] & 0x0f; /*resource id*/ + b2 = (pdata[i] & 0x80) >> 7; /*resource type*/ + i++; + printf("\t Resource ID: %i - %s\n",b1, + b2 ? "AMC Module" : "On-Carrier Device"); + n = pdata[i++]; /*descriptor count*/ + printf("\t Descriptor Count: %i\n",n); + for (j = 0; j < n; j++) { /*channel desc loop*/ + if (i >= dlen) break; + p = &pdata[i]; + b0 = p[0] & 0x1f; + b1 = ((p[0] & 0xe0) >> 5) + ((p[1] & 0x03) << 3); + b2 = ((p[1] & 0x7c) >> 2); + b3 = ((p[1] & 0x80) >> 7) + ((p[2] & 0x0f) << 1); + printf("\t Lane 0 Port: %i\n",b0); + printf("\t Lane 1 Port: %i\n",b1); + printf("\t Lane 2 Port: %i\n",b2); + printf("\t Lane 3 Port: %i\n",b3); + i += 3; + } + for ( ; i < dlen; i += 5) { /*ext descriptor loop*/ + p = &pdata[i]; + b0 = p[0]; /*channel id*/ + b1 = p[1] & 0x01; /*port flag 0*/ + b2 = (p[1] & 0x02) >> 1; /*port flag 1*/ + b3 = (p[1] & 0x04) >> 2; /*port flag 2*/ + b4 = (p[1] & 0x08) >> 3; /*port flag 3*/ + b5 = ((p[1] & 0xf0) >> 4) + ((p[2] & 0x0f) << 4); /*type*/ + b6 = (p[2] & 0xf0) >> 4; /*type ext*/ + b7 = p[3]; /*group id*/ + b8 = (p[4] & 0x03); /*asym match*/ + printf("\t Link Designator: Channel ID: %i, " + "Port Flag 0: %s%s%s%s\n",b0, + b1 ? "o" : "-", + b2 ? "o" : "-", + b3 ? "o" : "-", + b4 ? "o" : "-" ); + switch(b5) { /*link type*/ + case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE: + printf("\t Link Type: %02x - %s\n", b5, + "AMC.1 PCI Express"); + switch(b6) { /*link type ext*/ + case AMC_LINK_TYPE_EXT_PCIE_G1_NSSC: + s2 = "Gen 1 capable - non SSC"; break; + case AMC_LINK_TYPE_EXT_PCIE_G1_SSC: + s2 = "Gen 1 capable - SSC"; break; + case AMC_LINK_TYPE_EXT_PCIE_G2_NSSC: + s2 = "Gen 2 capable - non SSC"; break; + case AMC_LINK_TYPE_EXT_PCIE_G2_SSC: + s2 = "Gen 2 capable - SSC"; break; + default: + s2 = "Invalid"; break; + } + printf("\t Link Type Ext: %02x - %s\n", b6,s2); + break; + case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS1: + case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS2: + printf("\t Link Type: %02x - %s\n", b5, + "AMC.1 PCI Express Advanced Switching"); + printf("\t Link Type Ext: %02x\n", b6); + break; + case FRU_PICMGEXT_AMC_LINK_TYPE_ETHERNET: + s1 = "AMC.2 Ethernet"; + printf("\t Link Type: %02x - %s\n", b5,s1); + switch(b6) { /*link type ext*/ + case AMC_LINK_TYPE_EXT_ETH_1000_BX: + s2 = "1000Base-Bx (SerDES Gigabit) Ethernet Link"; + break; + case AMC_LINK_TYPE_EXT_ETH_10G_XAUI: + s2 = "10Gbit XAUI Ethernet Link"; break; + default: + s2 = "Invalid"; break; + } + printf("\t Link Type Ext: %02x - %s\n", b6,s2); + break; + case FRU_PICMGEXT_AMC_LINK_TYPE_STORAGE: + printf("\t Link Type: %02x - %s\n", b5, + "AMC.3 Storage"); + switch(b6) { /*link type ext*/ + case AMC_LINK_TYPE_EXT_STORAGE_FC: + s2 = "Fibre Channel"; break; + case AMC_LINK_TYPE_EXT_STORAGE_SATA: + s2 = "Serial ATA"; break; + case AMC_LINK_TYPE_EXT_STORAGE_SAS: + s2 = "Serial Attached SCSI"; break; + default: + s2 = "Invalid"; break; + } + printf("\t Link Type Ext: %02x - %s\n", b6,s2); + break; + case FRU_PICMGEXT_AMC_LINK_TYPE_RAPIDIO: + printf("\t Link Type: %02x - %s\n", b5, + "AMC.4 Serial Rapid IO"); + printf("\t Link Type Ext: %02x\n", b6); + break; + default: + printf("\t Link Type: %02x - %s\n", b5, + "reserved or OEM GUID"); + printf("\t Link Type Ext: %02x\n", b6); + break; + } /*end switch(link_type)*/ + printf("\t Link group Id: %i\n", b7); + printf("\t Link Asym Match: %i\n", b8); + } /*end ext descriptor loop*/ + break; + case FRU_AMC_CARRIER_INFO: + printf("\tFRU_AMC_CARRIER_INFO\n"); + b1 = pdata[i++]; /*extVersion*/ + n = pdata[i++]; /*siteCount*/ + printf("\t AMC.0 extension version: R%d.%d\n", + b1 & 0x0f, (b1 >> 4) & 0x0f); + printf("\t Carrier Site Count: %d\n",n); + for (j = 0; j < n; j++) { + if (i >= dlen) break; + printf("\t Site ID: %i\n", pdata[i++]); + } + break; + case FRU_PICMG_CLK_CARRIER_P2P: + printf("\tFRU_PICMG_CLK_CARRIER_P2P\n"); + b0 = pdata[i++]; + n = pdata[i++]; + k = (b0 & 0xC0) >> 6; + switch(k) { + case 0: s1 = "On-Carrier-Device"; break; + case 1: s1 = "AMC slot"; break; + case 2: s1 = "Backplane"; break; + default: s1 = "reserved"; break; + } + printf("\t Clock Resource ID: %02x, Type: %s\n",b0,s1 ); + printf("\t Channel Count : %02x\n",n); + for (j = 0; j < n; j++) { + b1 = pdata[i++]; /*local channel*/ + b2 = pdata[i++]; /*remote channel*/ + b3 = pdata[i++]; /*remote resource*/ + k = (b3 & 0xC0) >> 6; + switch(k) { + case 0: s1 = "Carrier-Dev"; break; + case 1: s1 = "AMC slot "; break; + case 2: s1 = "Backplane "; break; + default: s1 = "reserved "; break; + } + printf("\t CLK-ID: %02x -> %02x [ %s %02x ]\n",b1,b2,s1,b3); + } + break; + case FRU_PICMG_CLK_CONFIG: + printf("\tFRU_PICMG_CLK_CONFIG\n"); + b0 = pdata[i++]; + n = pdata[i++]; + printf("\t Clock Resource ID: %02x\n",b0); + printf("\t Descriptor Count : %02x\n",n); + for (j = 0; j < n; j++) { + b1 = pdata[i++]; /*channel id*/ + b2 = pdata[i++]; /*control*/ + printf("\t CLK-ID: %02x - CTRL %02x [ %12s ]\n", b1, b2, + (b2 & 0x01) == 0 ? "Carrier IPMC":"Application"); + b3 = pdata[i++]; /*indirect_cnt*/ + b4 = pdata[i++]; /*direct_cnt*/ + printf("\t Cnt: Indirect %02x / Direct %02x\n",b3,b4); + for (k = 0; k < b3; k++) { + b5 = pdata[i++]; /*feature*/ + b6 = pdata[i++]; /*dep_chn_id*/ + printf("\t Feature: %02x [%8s] - ", + b5, (b5 & 0x01)==1 ? "Source":"Receiver"); + printf("Dep. CLK-ID: %02x\n",b6); + } + for (k = 0; k < b4; k++) { + b5 = pdata[i++]; /*feature*/ + b6 = pdata[i++]; /*family*/ + b7 = pdata[i++]; /*accuracy*/ + l1 = pdata[i] | (pdata[i+1] << 8) | /*frequency*/ + (pdata[i+2] << 8) | (pdata[i+3] << 8); + i += 4; + l2 = pdata[i] | (pdata[i+1] << 8) | /*min frequency*/ + (pdata[i+2] << 8) | (pdata[i+3] << 8); + i += 4; + l3 = pdata[i] | (pdata[i+1] << 8) | /*max frequency*/ + (pdata[i+2] << 8) | (pdata[i+3] << 8); + i += 4; + printf("\t Feature: %02x - PLL: %x / Asym: %s\n", + b5, (b5 >> 1) & 0x01, (b5 & 1) ? "Source":"Receiver"); + printf("\t Family : %02x - AccLVL: %02x\n", b6, b7); + printf("\t FRQ : %-9d, min: %-9d, max: %-9d\n", + (int)l1, (int)l2, (int)l3); + } + } + break; + case FRU_UTCA_FRU_INFO_TABLE: + case FRU_UTCA_CARRIER_MNG_IP: + case FRU_UTCA_CARRIER_INFO: + case FRU_UTCA_CARRIER_LOCATION: + case FRU_UTCA_SHMC_IP_LINK: + case FRU_UTCA_POWER_POLICY: + case FRU_UTCA_ACTIVATION: + case FRU_UTCA_PM_CAPABILTY: + case FRU_UTCA_FAN_GEOGRAPHY: + case FRU_UTCA_CLOCK_MAPPING: + case FRU_UTCA_MSG_BRIDGE_POLICY: + case FRU_UTCA_OEM_MODULE_DESC: + printf("\tNot yet implemented uTCA record %x\n",id); + break; + default: + printf("\tUnknown PICMG Extension %x\n",id); + break; + } +} /*end show_fru_picmg*/ + +/*end ifru_picmg.c */ diff --git a/util/ifruset.c b/util/ifruset.c new file mode 100644 index 0000000..3e0299a --- /dev/null +++ b/util/ifruset.c @@ -0,0 +1,1658 @@ +/* + * ifruset (copy of ifru.c with extended FRU writing) + * + * This tool reads the FRU configuration, and optionally sets the asset + * tag field in the FRU data. See IPMI v1.5 spec section 28. + * It can use either the Intel /dev/imb driver or VALinux /dev/ipmikcs. + * + * Author: Andy Cress arcress at users.sourceforge.net + * + * Copyright (c) 2009 Kontron America, Inc. + * + * 04/01/10 Andy Cress - created from ifru.c 2.6.1 + */ +/*M* +Copyright (c) 2009 Kontron America, 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: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions 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. + c.. Neither the name of Kontron nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ +#ifdef WIN32 +#include +#include +#include +#include +#include "getopt.h" +#elif defined(DOS) +#include +#include +#include +#include +#include "getopt.h" +#else +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include +#else +#include +#endif +#endif +#include + +#include "ipmicmd.h" +#include "ipicmg.h" // #define OEM_PICMG 12634 + +extern int get_LastError( void ); /* ipmilan.c */ +extern int get_BiosVersion(char *str); +extern int get_SystemGuid(uchar *str); +extern void fmt_time(time_t etime, char *buf, int bufsz); /*see ievents.c*/ + +#define FIELD_LEN 24 +#define NUM_BOARD_FIELDS 6 +#define NUM_PRODUCT_FIELDS 8 +#define NUM_CHASSIS_FIELDS 3 +#define ERR_LENMAX -7 /*same as LAN_ERR_BADLENGTH */ +#define ERR_LENMIN -10 /*same as LAN_ERR_TOO_SHORT */ +#define ERR_OTHER -13 /*same as LAN_ERR_OTHER */ + +#define STRING_DATA_TYPE_BINARY 0x00 +#define STRING_DATA_TYPE_BCD_PLUS 0x01 +#define STRING_DATA_TYPE_SIX_BIT_ASCII 0x02 +#define STRING_DATA_TYPE_LANG_DEPENDENT 0x03 + +#define FRUCHUNK_SZ 16 +#define FRU_END 0xC1 +#define FRU_EMPTY_FIELD 0xC0 +#define FRU_TYPE_MASK 0xC0 +#define FRU_LEN_MASK 0x3F +#define IPROD_MANUF 0 +#define IPROD_NAME 1 +#define IPROD_PART 2 +#define IPROD_VERS 3 +#define IPROD_SERNUM 4 +#define IPROD_ASSET 5 +#define IPROD_FRUID 6 +#define IPROD_OEM 7 + +static char *progname = "ifruset"; +static char *progver = "2.93"; +static char fdebug = 0; +static char fpicmg = 0; +static char fonlybase = 0; +static char fonlyhsc = 0; +static char fdevsdrs = 0; +static char fshowlen = 0; +static char fgetfru = 0; +static char fdoanyway = 0; +static char fset_mc = 0; +static char fcanonical = 0; +static char fdump = 0; +static char frestore = 0; +static int fwritefru = 0; +static int prod_id, vend_id = 0; +static char bdelim = ':'; +static char *binfile = NULL; +static uchar bmc_sa = BMC_SA; /*defaults to 0x20*/ +static uchar guid[17] = ""; +static uchar *frubuf = NULL; +static uchar *newdata = NULL; /* new FRU data, including the product area */ + /* usually 4*64 + 3 = 259 bytes */ +static int sfru = 0; +static int chassis_offset = -1; +static int chassis_len = 0; +static char chassis_name[FIELD_LEN] = {0}; +static int product_num = NUM_PRODUCT_FIELDS; +typedef struct { + int offset; + int len; + char tag[FIELD_LEN]; + } FIELDTYPE; +static FIELDTYPE prodarea[NUM_PRODUCT_FIELDS] = { + -1, 0, {0}, + -1, 0, {0}, + -1, 0, {0}, + -1, 0, {0}, + -1, 0, {0}, + -1, 0, {0}, + -1, 0, {0}, + -1, 0, {0} }; +static FIELDTYPE prodnew[NUM_PRODUCT_FIELDS] = { + -1, 0, {0}, + -1, 0, {0}, + -1, 0, {0}, + -1, 0, {0}, + -1, 0, {0}, + -1, 0, {0}, + -1, 0, {0}, + -1, 0, {0} }; +static int maxprod = 0; +static int ctype; +static uchar g_bus = PUBLIC_BUS; +static uchar g_sa = 0; +static uchar g_lun = BMC_LUN; +static uchar g_addrtype = ADDR_SMI; +static uchar g_fruid = 0; /* default to fruid 0 */ +static uchar g_frutype = 0; +/* g_frutype values (detected), see also FruTypeString + * --TAG---- FRU IPMB + * Baseboard = 0x0c 0x07 + * PowerSply = 0x0a + * PowerCage = 0x15 + * DIMM = 0x20 + * HotSwapCt = 0x0f + * ME = 0x2e + * Component = * * (all others) + */ + +#define MAX_CTYPE 26 +char *ctypes[MAX_CTYPE] = { "", "Other", "Unknown", "Desktop", + "Low Profile Desktop", "Pizza Box", "Mini-Tower", "Tower", + "Portable", "Laptop", "Notebook", "Handheld", "Docking Station", + "All-in-One", "Sub-Notebook", "Space-saving", "Lunch Box", + "Main Server Chassis", "Expansion Chassis", "SubChassis", + "Bus Expansion Chassis", "Peripheral Chassis", + "RAID Chassis", /*0x17=23.*/ "Rack-Mount Chassis", + "New24" , "New25"}; + /* what about bladed chassies? */ +char *ctype_hdr = +"Chassis Type "; +char *chassis[NUM_CHASSIS_FIELDS] = { +"Chassis Part Number ", +"Chassis Serial Num ", +"Chassis OEM Field " }; +char *board[NUM_BOARD_FIELDS] = { +"Board Manufacturer ", +"Board Product Name ", +"Board Serial Number ", +"Board Part Number ", +"Board FRU File ID ", +"Board OEM Field " }; +char *product[NUM_PRODUCT_FIELDS] = { +"Product Manufacturer", +"Product Name ", +"Product Part Number ", +"Product Version ", +"Product Serial Num ", +"Product Asset Tag ", +"Product FRU File ID ", +"Product OEM Field " }; +char *asset_hdr = +" Asset Tag Length "; + +#if 0 +typedef struct { + uchar len :6; + uchar type:2; + } TYPE_LEN; /*old, assumes lo-hi byte order*/ +#else +typedef struct { + uchar len; + uchar type; + } TYPE_LEN; +#endif + +void +free_fru(void) +{ + if (frubuf != NULL) { + free(frubuf); + frubuf = NULL; + } + if (newdata != NULL) { + free(newdata); + newdata = NULL; + } + return; +} + +int +load_fru(uchar sa, uchar frudev, uchar frutype) +{ + int ret = 0; + uchar indata[16]; + uchar resp[18]; + int sresp; + uchar cc; + int sz; + char fwords; + ushort fruoff = 0; + int i; + int chunk; + + indata[0] = frudev; + sresp = sizeof(resp); + if (fdebug) printf("load_fru: sa = %02x, frudev = %02x\n",sa,frudev); + ret = ipmi_cmd_mc(GET_FRU_INV_AREA,indata,1,resp,&sresp,&cc,fdebug); + if (fdebug) printf("load_fru: inv ret = %d, cc = %x\n",ret,cc); + if (ret != 0) return(ret); + if (cc != 0) { ret = (cc & 0x00ff); return(ret); } + + sz = resp[0] + (resp[1] << 8); + if (resp[2] & 0x01) { fwords = 1; sz = sz * 2; } + else fwords = 0; + + frubuf = malloc(sz); + if (frubuf == NULL) return(get_errno()); + sfru = sz; + + /* Loop on READ_FRU_DATA */ + for (i = 0, chunk=FRUCHUNK_SZ; i < sz; i+=chunk) + { + if ((i+chunk) >= sz) chunk = sz - i; + indata[0] = frudev; /* FRU Device ID */ + if (fwords) { + indata[3] = chunk / 2; + fruoff = (i/2); + } else { + indata[3] = chunk; + fruoff = i; + } + indata[1] = fruoff & 0x00FF; + indata[2] = (fruoff & 0xFF00) >> 8; + sresp = sizeof(resp); + ret = ipmi_cmd_mc(READ_FRU_DATA,indata,4,resp,&sresp,&cc,fdebug); + if (ret != 0) break; + else if (cc != 0) { + if (i == 0) ret = cc & 0x00ff; + if (fdebug) printf("read_fru[%d]: ret = %d cc = %x\n",i,ret,cc); + break; + } + memcpy(&frubuf[i],&resp[1],chunk); + } + if ((frudev == 0) && (sa == bmc_sa)) { /*main system fru*/ + sresp = sizeof(resp); + ret = ipmi_cmd_mc(GET_SYSTEM_GUID,indata,0,resp,&sresp,&cc,fdebug); + if ((ret != 0) && !is_remote()) { /* get UUID from SMBIOS */ + cc = 0; sresp = 16; + ret = get_SystemGuid(resp); + } + if (fdebug) printf("system_guid: ret = %d, cc = %x\n",ret,cc); + if (ret == 0 && cc == 0) { + if (fdebug) { + printf("system guid (%d): ",sresp); + for (i=0; i<16; i++) printf("%02x ",resp[i]); + printf("\n"); + } + memcpy(&guid,&resp,16); + guid[16] = 0; + } + } /*endif*/ + + return(ret); +} + +static void decode_string(unsigned char type, + unsigned char language_code, + unsigned char *source, + int slen, + char *target, + int tsize) +{ + static const char bcd_plus[] = "0123456789 -.:,_"; + unsigned char *s = &source[0]; + unsigned char *d = &target[0]; + int len, i, j, k; + union { uint32_t bits; char chars[4]; } u; + + if (slen == 0 || slen == 1) return; + switch(type) { + case STRING_DATA_TYPE_BINARY: /* 00: binary/unspecified */ + len = (slen*2); break; /* hex dump -> 2x length */ + case STRING_DATA_TYPE_SIX_BIT_ASCII: /*type 2 6-bit ASCII*/ + /* 4 chars per group of 1-3 bytes */ + len = ((((slen+2)*4)/3) & ~3); break; + case STRING_DATA_TYPE_LANG_DEPENDENT: /* 03 language dependent */ + case STRING_DATA_TYPE_BCD_PLUS: /* 01b: BCD plus */ + default: + len = slen; break; + } + if (len >= tsize) len = tsize - 1; + memset(target, 0, len); + if (type == STRING_DATA_TYPE_BCD_PLUS) { /*type 1 BCD plus*/ + for (k=0; k 1 ? s[i+1] : 0); + u.chars[1] = (k > 2 ? s[i+2] : 0); +#define CHAR_IDX 3 +#else + memcpy((void *)&u.bits, &s[i], k); +#define CHAR_IDX 0 +#endif + for (k=0; k<4; k++) { + target[j++] = ((u.chars[CHAR_IDX] & 0x3f) + 0x20); + u.bits >>= 6; + } + } + target[j] = '\0'; + } else if (type == STRING_DATA_TYPE_LANG_DEPENDENT) { /*type 3*/ + if ((language_code == 0x00) || (language_code == 0x25) || + (language_code == 0x19)) { + memcpy(target, source, len); + target[len] = 0x0; + } else { + printf("Language 0x%x dependent decode not supported\n",language_code); + } + } else if (type == STRING_DATA_TYPE_BINARY) { /* 00: binary/unspecified */ + strncpy(target, buf2str(s, slen), len); + } else { /* other */ + printf("Unable to decode type 0x%.2x\n",type); + } + return; +} + +uchar calc_cksum(uchar *pbuf,int len) +{ + int i; + uchar cksum; + uchar sum = 0; + + for (i = 0; i < len; i++) sum += pbuf[i]; + cksum = 0 - sum; + return(cksum); +} + +static void dumpbuf(uchar *pbuf,int sz) +{ + uchar line[17]; + uchar a; + int i, j; + + line[0] = 0; line[16] = 0; + j = 0; + for (i = 0; i < sz; i++) { + if (i % 16 == 0) { j = 0; printf("%s\n %04d: ",line,i); } + a = pbuf[i]; + if (a < 0x20 || a > 0x7f) a = '.'; + line[j++] = a; + printf("%02x ",pbuf[i]); + } + line[j] = 0; + printf("%s\n",line); + return; +} + +#define NSPDMFG 7 +static struct { + uchar id; char *str; +} spd_mfg[NSPDMFG] = { /* see JEDEC JEP106 doc */ +{ 0x2c, "Micron" }, +{ 0x15, "Philips Semi" }, +{ 0x1c, "Mitsubishi" }, +{ 0xce, "Samsung" }, +{ 0xc1, "Infineon" }, +{ 0x98, "Kingston" }, +{ 0x89, "Intel" } +}; + +int ValidTL(uchar typelen) +{ + if (vend_id != VENDOR_INTEL) return 1; + if ((typelen & 0xC0) == 0xC0) return 1; + else return 0; +} + +char * FruTypeString(uchar frutype) +{ + char *pstr; + switch (frutype) { + case 0x07: pstr = "Baseboard"; break; /*IPMB*/ + case 0x0c: pstr = "Baseboard"; break; /*FRU*/ + case 0x0a: pstr = "PowerSply"; break; /*FRU*/ + case 0x15: pstr = "PowerCage"; break; /*FRU*/ + case 0x20: pstr = "DIMM "; break; /*FRU*/ + case 0x0f: pstr = "HotSwapCt"; break; /*IPMB*/ + case 0x2e: pstr = "ME "; break; /*IPMB*/ + default: pstr = "Component"; break; + } + return(pstr); +} + +static void +show_spd(uchar *spd, int lenspd, uchar frudev, uchar frutype) +{ + int sz; + char *pstr; + uchar mrev; + int i; + char devstr[20]; + + sz = spd[0]; /* sz should == lenspd */ + if (fcanonical) devstr[0] = 0; /*default is empty string*/ + else sprintf(devstr,"[%s,%02x] ",FruTypeString(frutype),frudev); + printf("%sMemory SPD Size %c %d\n", + devstr,bdelim,lenspd); + if (spd[2] == 0x07) pstr = "DDR"; + else /* usu 0x04 */ pstr = "SDRAM"; + printf("%sMemory Type %c %s\n", + devstr,bdelim,pstr); + printf("%sModule Density %c %d MB per bank\n", + devstr,bdelim, (spd[31] * 4)); + printf("%sModule Banks %c %d banks\n", + devstr,bdelim,spd[5]); + printf("%sModule Rows, Cols %c %d rows, %d cols\n", + devstr,bdelim, spd[3], spd[4]); + if (spd[11] == 0x00) pstr = "Non-parity"; + else /* usu 0x02 */ pstr = "ECC"; + printf("%sDIMM Config Type %c %s\n",devstr,bdelim,pstr); + for (i = 0; i < NSPDMFG; i++) + if (spd_mfg[i].id == spd[64]) break; + if (i == NSPDMFG) pstr = ""; /* not found, use null string */ + else pstr = spd_mfg[i].str; + printf("%sManufacturer ID %c %s (0x%02x)\n", + devstr,bdelim, pstr, spd[64]); + mrev = spd[91]; /* save this byte for later */ + spd[91] = 0; /*stringify part number */ + printf("%sManufacturer Part# %c %s\n", + devstr,bdelim,&spd[73]); + printf("%sManufacturer Rev %c %02x %02x\n", + devstr,bdelim,mrev,spd[92]); + printf("%sManufacturer Date %c year=%02d week=%02d\n", + devstr,bdelim,spd[93],spd[94]); + printf("%sAssembly Serial Num %c %02x%02x%02x%02x\n", + devstr,bdelim,spd[95], spd[96], spd[97], spd[98]); + spd[91] = mrev; /* restore byte, so ok to repeat later */ + return; +} + +void show_guid(uchar *pguid) +{ + char *s; + int i; + for (i=0; i<16; i++) { + if ((i == 4) || (i == 6) || (i == 8) || (i == 10)) s = "-"; + else s = ""; + printf("%s%02x",s,pguid[i]); + } +} + +static char *volt_desc(uchar b) +{ + char *s; + switch(b) { + case 0x03: s = "5V"; break; + case 0x02: s = "3.3V"; break; + case 0x01: s = "-12V"; break; + case 0x00: + default: s = "12V"; break; + } + return(s); +} + +static char *mgt_type(uchar b) +{ + char *s; + switch(b) { + case 0x01: s = "SysMgt_URL"; break; + case 0x02: s = "SystemName"; break; + case 0x03: s = "SysPingAddr"; break; + case 0x04: s = "Compon_URL"; break; + case 0x05: s = "ComponName"; break; + case 0x06: s = "ComponPing"; break; + case 0x07: + default: s = "SysGUID"; break; + } + return(s); +} + +static +void show_fru_multi(char *tag, int midx, uchar mtype, uchar *pdata, int dlen) +{ + int vend, i; + char mystr[256]; + char *s1, *s2; + int v1, v2, v3, v4, v5, v6, v7, v8; + uchar b1, b2; + + if (fdebug) dumpbuf(pdata,dlen); /*multi-record area dump*/ + sprintf(mystr,"%sMulti[%d] ",tag,midx); + i = strlen(mystr); + switch(mtype) { + case 0x00: /*Power Supply*/ + printf("%sPower Supply Record %c \n",mystr,bdelim); + v1 = pdata[0] + ((pdata[1] & 0x0f) << 8); + printf("\t Capacity \t%c %d W\n",bdelim, v1); + v2 = pdata[2] + (pdata[3] << 8); + printf("\t Peak VA \t%c %d VA\n",bdelim, v2); + printf("\t Inrush Current\t%c %d A\n",bdelim, pdata[4]); + printf("\t Inrush Interval\t%c %d ms\n",bdelim, pdata[5]); + v3 = pdata[6] + (pdata[7] << 8); + v4 = pdata[8] + (pdata[9] << 8); + printf("\t Input Voltage Range1\t%c %d-%d V\n", + bdelim,v3/100,v4/100); + v3 = pdata[10] + (pdata[11] << 8); + v4 = pdata[12] + (pdata[13] << 8); + printf("\t Input Voltage Range2\t%c %d-%d V\n", + bdelim,v3/100,v4/100); + printf("\t Input Frequency Range\t%c %d-%d Hz\n", + bdelim,pdata[14],pdata[15]); + printf("\t AC Dropout Tolerance\t%c %d ms\n",bdelim, pdata[16]); + b1 = pdata[17]; + b2 = (b1 & 0x01); + if (b2) { /*predictive fail*/ + if (b1 & 0x10 != 0) s1 = "DeassertFail "; + else s1 = "AssertFail "; + } else { + if (b1 & 0x10 != 0) s1 = "2pulses/rot "; + else s1 = "1pulse/rot "; + } + printf("\t Flags \t%c %s%s%s%s%s\n",bdelim, + (b2 ? "PredictFail " : ""), + ((b1 & 0x02 == 0) ? "" : "PowerFactorCorrect "), + ((b1 & 0x04 == 0) ? "" : "AutoswitchVolt "), + ((b1 & 0x08 == 0) ? "" : "Hotswap "), s1); + v5 = pdata[18] + ((pdata[19] & 0x0f) << 8); + v6 = (pdata[19] & 0xf0) >> 4; + printf("\t Peak Capacity \t%c %d W for %d s\n",bdelim, v5,v6); + if (pdata[20] == 0) { + printf("\t Combined Capacity\t%c not specified\n",bdelim); + } else { + b1 = pdata[20] & 0x0f; + b2 = (pdata[20] & 0xf0) >> 4; + v7 = pdata[21] + (pdata[22] << 8); + printf("\t Combined Capacity\t%c %d W (%s and %s)\n", + bdelim, v7,volt_desc(b1),volt_desc(b2)); + } + if (b2) /*predictive fail*/ + printf("\t Fan low threshold\t%c %d RPS\n",bdelim,pdata[23]); + break; + case 0x01: /*DC Output*/ + b1 = pdata[0] & 0x0f; + b2 = (pdata[0] & 0x80 != 0); + printf("%sDC Output %c number %d\n",mystr,bdelim,b1); + printf("\t Standby power \t%c %s\n", bdelim, + (b2 ? "Yes" : "No")); + v1 = pdata[1] + (pdata[2] << 8); + printf("\t Nominal voltage \t%c %.2f V\n", bdelim, v1 / 100); + v2 = pdata[3] + (pdata[4] << 8); + v3 = pdata[5] + (pdata[6] << 8); + printf("\t Voltage deviation \t%c + %.2f V / - %.2f V\n", + bdelim, v3/100, v2/100); + v4 = pdata[7] + (pdata[8] << 8); + printf("\t Ripple and noise pk-pk \t%c %d mV\n", bdelim, v4); + v5 = pdata[9] + (pdata[10] << 8); + printf("\t Min current draw \t%c %.3f A\n", bdelim, v5/1000); + v6 = pdata[11] + (pdata[12] << 8); + printf("\t Max current draw \t%c %.3f A\n", bdelim, v6/1000); + break; + case 0x02: /*DC Load*/ + b1 = pdata[0] & 0x0f; + printf("%sDC Load %c number %d\n",mystr,bdelim,b1); + v1 = pdata[1] + (pdata[2] << 8); + printf("\t Nominal voltage \t%c %.2f V\n", bdelim, v1 / 100); + v2 = pdata[3] + (pdata[4] << 8); + v3 = pdata[5] + (pdata[6] << 8); + printf("\t Min voltage allowed \t%c %.2f A\n", bdelim, v2); + printf("\t Max voltage allowed \t%c %.2f A\n", bdelim, v3); + v4 = pdata[7] + (pdata[8] << 8); + printf("\t Ripple and noise pk-pk \t%c %d mV\n", bdelim, v4); + v5 = pdata[9] + (pdata[10] << 8); + printf("\t Min current load \t%c %.3f A\n", bdelim, v5/1000); + v6 = pdata[11] + (pdata[12] << 8); + printf("\t Max current load \t%c %.3f A\n", bdelim, v6/1000); + break; + case 0x03: /*Management Access*/ + b1 = pdata[0]; + printf("%sManagemt Access %c %s ",mystr,bdelim,mgt_type(b1)); + memcpy(mystr,&pdata[1],dlen-1); + mystr[dlen-1] = 0; + printf("%s\n",mystr); + break; + case 0x04: /*Base Compatibility*/ + vend = pdata[0] + (pdata[1] << 8) + (pdata[2] << 16); + printf("%sBasic Compat %c %06x\n",mystr,bdelim,vend); + break; + case 0x05: /*Extended Compatibility*/ + vend = pdata[0] + (pdata[1] << 8) + (pdata[2] << 16); + printf("%sExtended Compat %c %06x\n",mystr,bdelim,vend); + break; + case 0xC0: /*OEM Extension*/ + vend = pdata[0] + (pdata[1] << 8) + (pdata[2] << 16); + if (vend == OEM_PICMG) { + printf("%sOEM PICMG %c \n", mystr,bdelim); + show_fru_picmg(pdata,dlen); + } else + printf("%sOEM Ext %c %06x %02x\n", + mystr,bdelim, vend, pdata[3]); + break; + default: + printf("%s %02x %c %02x\n", mystr,mtype,bdelim, pdata[0]); + break; + } +} + +int +show_fru(uchar sa, uchar frudev, uchar frutype) +{ + int ret = 0; + int i, j, n, sz; + uchar *pfru; + uchar lang; + TYPE_LEN tl; + char newstr[64]; + int iaoff, ialen, bdoff, bdlen; + int proff, prlen, choff, chlen; + int moff, mlen; + char devstr[24]; + char *pstr; + int extra = 0; + + if (frubuf[0] == 0x80) { /* 0x80 = type for DIMMs (SPD) */ + /* FRU Header: 80 08 07 0c 0a 01 48 00 (DIMM) */ + sz = frubuf[0]; + if (fdebug) { + printf("DIMM SPD Body (size=%d/%d): ",sz,sfru); + dumpbuf(frubuf,sfru); + } + show_spd(frubuf,sfru, frudev,frutype); + return(ret); + } + + pstr = FruTypeString(frutype); + if (fcanonical) devstr[0] = 0; /*default is empty string*/ + else sprintf(devstr,"[%s,%02x] ",pstr,frudev); + printf("%s%s FRU Size %c %d\n",devstr,pstr,bdelim,sfru); + + /* + * FRU header: + * 0 = format_ver (01 is std, usu 0x80 if DIMM) + * 1 = internal_use offset + * 2 = chassis_info offset + * 3 = board_info offset (usu 6 fields) + * 4 = product_info offset (usu 8 fields) + * 5 = multirecord offset + * 6 = pad (00) + * 7 = header checksum (zero checksum) + * FRU Header: 01 01 02 09 13 00 00 e0 (BMC) + * FRU Header: 01 00 00 00 01 07 00 f7 (Power Cage) + */ + pfru = &frubuf[0]; + sz = 8; /*minimum for common header*/ + for (i = 1; i < 6; i++) /* walk thru offsets */ + if (frubuf[i] != 0) sz = frubuf[i] * 8; + if (sz > 8) /* if have at least one section */ + sz += frubuf[sz+1] * 8; /* add length of last section */ + /* Now, sz = size used, sfru = total available size */ + if (sz > sfru) { + if (fdebug) { + printf("FRU Header: "); + for (i = 0; i < 8; i++) printf("%02x ",frubuf[i]); + printf("\n"); + } + printf("FRU size out of bounds: available=%d used=%d\n",sfru,sz); + printf("Please apply the correct FRU/SDR diskette\n"); + if (fdoanyway) { + extra = sz - sfru; + sz = sfru; + } else return(ERR_OTHER); + } + /* internal area offset, length */ + iaoff = frubuf[1] * 8; + ialen = frubuf[iaoff + 1] * 8; + /* chassis area offset, length */ + choff = frubuf[2] * 8; + chlen = frubuf[choff + 1] * 8; + /* board area offset, length */ + bdoff = frubuf[3] * 8; + bdlen = frubuf[bdoff + 1] * 8; + /* product area offset, length */ + proff = frubuf[4] * 8; + prlen = frubuf[proff + 1] * 8; + if (extra > 0) { /*do fixup of extra in product area*/ + prlen -= extra; + j = prlen / 8; + prlen = j * 8; /*resolve to 8-byte bound*/ + frubuf[proff + 1] = j; + } + /* multi-record area offset, length */ + moff = frubuf[5] * 8; + mlen = 0; + if (moff > 0) { + for (i = moff; i < sfru; ) { + j = 5 + frubuf[i+2]; + mlen += j; + if (frubuf[i+1] & 0x80) break; + i += j; + } + } + + if (fdebug) { + printf("FRU Header: "); + for (i = 0; i < 8; i++) printf("%02x ",frubuf[i]); + printf("\n"); + printf("FRU Body (size=%d/%d): ",sz,sfru); + dumpbuf(frubuf,sfru); + printf("header, len=%d, cksum0 = %02x, cksum1 = %02x\n", + 8,frubuf[7],calc_cksum(&frubuf[0],7)); + printf("internal off=%d, len=%d, cksum = %02x\n", + iaoff,ialen,calc_cksum(&frubuf[iaoff],ialen-1)); + printf("chassis off=%d, len=%d, cksum = %02x\n", + choff,chlen,calc_cksum(&frubuf[choff],chlen-1)); + printf("board off=%d, len=%d, cksum = %02x\n", + bdoff,bdlen,calc_cksum(&frubuf[bdoff],bdlen-1)); + printf("prod off=%d, len=%d, cksum = %02x\n", + proff,prlen,calc_cksum(&frubuf[proff],prlen-1)); + /* Multi-record area */ + printf("multi off=%d, len=%d, fru sz=%d\n", moff,mlen,sz); + } /*endif fdebug, show header*/ + + if (choff != 0) { + /* show Chassis area fields */ + pfru = &frubuf[choff]; + lang = 25; /* English */ + ctype = pfru[2]; /*chassis type*/ + if (fdebug) printf("ctype=%x\n",ctype); + if (ctype >= MAX_CTYPE) ctype = MAX_CTYPE - 1; + printf("%s%s%c %s\n",devstr, ctype_hdr,bdelim,ctypes[ctype]); + pfru += 3; /* skip chassis header */ + for (i = 0; i < NUM_CHASSIS_FIELDS; i++) + { + if (pfru[0] == FRU_END) break; /*0xC1 = end of FRU area*/ + if (!ValidTL(pfru[0])) + printf(" ERROR - Invalid Type/Length %02x for %s\n", + pfru[0],chassis[i]); + tl.type = (pfru[0] & FRU_TYPE_MASK) >> 6; + tl.len = pfru[0] & FRU_LEN_MASK; + if (i == 2) { /* OEM field for chassis_name */ + chassis_offset = (int)(pfru - frubuf); + chassis_len = tl.len; + if (fdebug) printf("chassis oem dtype=%d lang=%d len=%d\n", + tl.type,lang,tl.len); + } + pfru++; + { + newstr[0] = 0; + decode_string(tl.type,lang,pfru,tl.len,newstr,sizeof(newstr)); + printf("%s%s%c %s\n",devstr, chassis[i],bdelim,newstr); + } + pfru += tl.len; + } + if (fdebug) printf("num Chassis fields = %d\n",i); + } + + if (bdoff != 0) { + long nMin, nSec; + time_t tsec; + /* show Board area fields */ + pfru = &frubuf[bdoff]; + lang = pfru[2]; + /* Decode board mfg date-time (num minutes since 1/1/96) */ + nMin = pfru[3] + (pfru[4] << 8) + (pfru[5] << 16); + /* 13674540 min from 1/1/70 to 1/1/96 */ + nSec = (nMin + 13674540) * 60; + tsec = (time_t)(nSec & 0x0ffffffff); + // fmt_time(tsec,newstr,sizeof(newstr)); + printf("%sBoard Mfg DateTime %c %s",devstr,bdelim,ctime(&tsec)); + pfru += 6; /* skip board header */ + for (i = 0; i < NUM_BOARD_FIELDS; i++) + { + if (pfru[0] == FRU_END) break; /*0xC1 = end*/ + if (!ValidTL(pfru[0])) + printf(" ERROR - Invalid Type/Length %02x for %s\n", + pfru[0],board[i]); + tl.type = (pfru[0] & FRU_TYPE_MASK) >> 6; + tl.len = pfru[0] & FRU_LEN_MASK; + pfru++; + { + newstr[0] = 0; + decode_string(tl.type,lang,pfru,tl.len,newstr,sizeof(newstr)); + printf("%s%s%c %s\n",devstr, board[i],bdelim,newstr); + } + pfru += tl.len; + } + if (fdebug) printf("num Board fields = %d\n",i); + } + + if (proff != 0) { + /* show Product area fields */ + pfru = &frubuf[proff]; + maxprod = pfru[1] * 8; + lang = pfru[2]; + pfru += 3; /* skip product header */ + for (i = 0; i < NUM_PRODUCT_FIELDS; i++) + { + if (*pfru == FRU_END) { /*0xC1 = end*/ + /* Wart for known Kontron 1-byte Product Version anomaly. */ + if ((vend_id == VENDOR_KONTRON) && (i == 3)) ; + else break; + } + if (*pfru == 0) *pfru = FRU_EMPTY_FIELD; /* fix a broken table */ + if (!ValidTL(pfru[0])) + printf(" ERROR - Invalid Type/Length %02x for %s\n", + pfru[0],product[i]); + tl.type = (pfru[0] & FRU_TYPE_MASK) >> 6; + tl.len = pfru[0] & FRU_LEN_MASK; + n = (int)(pfru - frubuf); + prodarea[i].offset = n; + prodarea[i].len = tl.len; + memcpy(prodarea[i].tag, &frubuf[n+1] ,tl.len); + pfru++; + { + newstr[0] = 0; + decode_string(tl.type,lang,pfru,tl.len,newstr,sizeof(newstr)); + printf("%s%s%c %s\n",devstr, product[i],bdelim,newstr); + } + pfru += tl.len; + } + if (fdebug) + printf("num Product fields = %d, last=%x, max = %d\n", + i,*pfru,maxprod ); + product_num = i; /*save number of existing product fields*/ + if (*pfru == 0x00) *pfru = FRU_END; /* insert end char if broken */ + } + + if (moff != 0) + { + /* multi-record area may contain several record headers + * 0 = record type id + * 1 = 0x02 or 0x80 if End-of-List + * 2 = record len + * 3 = record chksum + * 4 = header chksum + */ + pfru = &frubuf[moff]; + j = moff; + for (i = 0; j < sz; i++) + { + n = pfru[2]; /* len of this record */ + show_fru_multi(devstr,i,pfru[0],&pfru[5],n); + j += (5 + n); + if (pfru[1] & 0x80) j = sz; /*0x80 = end of list*/ + pfru += (5 + n); + } + } + + if ((frudev == 0) && (sa == bmc_sa)) { + char *s; + printf("%sSystem GUID %c ",devstr,bdelim); + for (i=0; i<16; i++) { + if ((i == 4) || (i == 6) || (i == 8) || (i == 10)) s = "-"; + else s = ""; + printf("%s%02x",s,guid[i]); + } + printf("\n"); + } + return(ret); +} + +static int +write_fru_data(uchar id, ushort offset, uchar *data, int dlen, char fdebug) +{ + int ret = -1; + int chunk; + ushort fruoff; + uchar req[25]; + uchar resp[16]; + int sresp; + uchar cc; + int i, j; + + /* Write the buffer in small 16-byte (FRUCHUNK_SZ) chunks */ + req[0] = id; /* FRU Device ID (fruid) */ + fruoff = offset; + chunk = FRUCHUNK_SZ; + for (i = 0; i < dlen; i += chunk) { + req[1] = fruoff & 0x00ff; + req[2] = (fruoff & 0xff00) >> 8; + if ((i + chunk) > dlen) chunk = dlen - i; + memcpy(&req[3],&data[i],chunk); + if (fdebug) { + printf("write_fru_data[%d] (len=%d): ",i,chunk+3); + for (j = 0; j < chunk+3; j++) printf("%02x ",req[j]); + printf("\n"); + } + sresp = sizeof(resp); + ret = ipmi_cmd_mc(WRITE_FRU_DATA,req,(uchar)(chunk+3),resp,&sresp, + &cc,fdebug); + if ((ret == 0) && (cc != 0)) ret = cc & 0x00ff; + if (fdebug && ret == 0) + printf("write_fru_data[%d]: %d bytes written\n",i,resp[0]); + if (ret != 0) break; + fruoff += chunk; + } + return(ret); +} + +/* + * write_product + * Updates the FRU Product area only. + * Note that this function will always provide >=8 product fields, + * even if the original had less than 8. + * inputs: prodnew = array of new strings to write + * frubuf = contains existing FRU data + * newdata = new product area buffer, malloc'd + * outputs: returns 0 if successful + */ +int +write_product(void) +{ + int ret = -1; + uchar req[25]; + uchar resp[16]; + int sresp; + uchar cc; + ushort fruoff; + int alen, clen; + int snlen, verlen; + uchar *pfru0; + uchar *pfru; + uchar *pnew; + int i, j, k, n, plen, newlen, max, plimit; + int chas_offset; + int prod_offset; + int mult_offset, mult_len; + uchar chksum; + int chunk; + + chas_offset = frubuf[2] * 8; // offset of chassis data + prod_offset = frubuf[4] * 8; // offset of product data + plen = frubuf[prod_offset+1] * 8; // length of product data + mult_offset = frubuf[5] * 8; + mult_len = 0; + if (mult_offset > 0) { + for (i = mult_offset; i < sfru; ) { + mult_len += (5 + frubuf[i+2]); + if (frubuf[i+1] & 0x80) break; + i = mult_len; + } + } + /* Check if asset tag will fit in product data area of FRU. */ + if (fdebug) + printf("write_product: fru[4,p]=[%02x,%02x] prod_off=%d, plen=%d\n", + frubuf[4],frubuf[prod_offset+1],prod_offset,plen); + if (plen > sfru) return ERR_LENMAX; // product bigger than buffer + if (prodnew[IPROD_ASSET].len > plen) return ERR_LENMAX; + /* if asset bigger than product data, error. */ + /* asset comes after sernum, so this check works for both */ + + newdata = malloc(sfru); /* but should not need more than plen bytes */ + if (newdata == NULL) return(get_errno()); + memset(newdata,0,sfru); + pnew = &newdata[0]; + /* Set pointer to start of chassis area */ + pfru = &frubuf[chas_offset]; + + /* Product Area Header (3 bytes): + [0] = 0x01; * format ver 1 * + [1] = 0x0a; *product area size (in 8-byte mult)* + [2] = 0x00; *lang=english * + Usually max product area is 3 + 8*32 = 259 mod 8 = 264. + */ + pfru0 = &frubuf[prod_offset]; + pfru = &frubuf[prod_offset]; + j = 3; + memcpy(pnew,pfru,j); + pfru += j; + pnew += j; + n = j; + if (mult_offset > 0) plimit = plen; + else plimit = sfru - prod_offset; /*plen can expand*/ + + for (i = 0; i < NUM_PRODUCT_FIELDS; i++) + { + j = prodarea[i].len; /*new len*/ + k = pfru[0] & FRU_LEN_MASK; /*old len*/ + if (k == 1) { /*was 0xC1 FRU_END*/ + if ((vend_id == VENDOR_KONTRON) && (i == 3) && (j == 1)) { + /* fix Kontron 1-byte Version */ + prodarea[i].tag[1] = ' '; + j++; + } else + k = 0; + } + /* check for product area overflow */ + if (n + 2 >= plimit) { + if (fdebug) printf("Field %d is at %d, beyond product area size %d\n", + i+1,n+2,plimit); + break; + } else if ((n + 1 + j) >= plimit) { + if (fdebug) printf("Field %d at %d + %d, truncated, product size %d\n", + i+1,n+1,j,plimit); + j = 0; + } + pnew[0] = (j | FRU_TYPE_MASK); /*add type=3 to len*/ + memcpy(&pnew[1],prodarea[i].tag,j); + if (fdebug) { + printf("i=%d frubuf[%d]: %02x %02x %02x, j=%d k=%d n=%d\n", + i,(pfru-frubuf),pfru[0],pfru[1],pfru[2],j,k,n); + if (i >= product_num) + printf("Field %d is beyond existing %d fields\n",i+1,product_num); + } + pnew += j + 1; + pfru += k + 1; + n += j + 1; + } + + // n = (int)(pnew - newdata); /*new product area index*/ + k = (int)(pfru - pfru0); /*old product area index*/ + if (mult_offset > 0) /* do not expand if multi-record area there */ + max = plen - k; + else /* nothing else, can expand product area, up to sfru */ + max = sfru - (k + prod_offset); + if (fdebug) + printf("frubuf[%d]: %02x %02x %02x, j=%d k=%d n=%d remainder=%d\n", + (pfru-frubuf),pfru[0],pfru[1],pfru[2],j,k,n,max); + if (max < 0) max = 0; + /* copy trailing fru data from saved copy */ + for (i = 0; i < max; i++) { + pnew[i] = pfru[i]; + if (pfru[i] == FRU_END) { i++; break; } /*0xC1*/ + } + if (i == max) { /*never found 0xC1 FRU_END*/ + pnew[0] = FRU_END; /*mark this trailing field as empty*/ + i = 1; + } + newlen = n + i; + if (fdebug) printf("newbuf[%d]: %02x %02x %02x, j=%d newlen=%d plen=%d\n", + n,pnew[0],pnew[1],pnew[2],j,newlen,plen); + + /* round up to next 8-byte boundary */ + /* need one more byte for checksum, so if j=0, add 8 anyway */ + j = 8 - (newlen % 8); + for (i = 0; i < j; i++) newdata[newlen++] = 0; + if (newlen < plen) newlen = plen; /* don't shrink the product area */ + newdata[1] = newlen / 8; // set length of product data + + /* include new checksum (calc over Product area) */ + chksum = calc_cksum(&newdata[0],newlen-1); + newdata[newlen-1] = chksum; + + if (fdebug) { + printf("old prod_area buffer (%d):",plen); + dumpbuf(&frubuf[prod_offset],plen); + printf("new prod_area buffer (%d):",newlen); + dumpbuf(newdata,newlen); + } + if (prod_offset + newlen >= sfru) return ERR_LENMAX; + if ((mult_offset > 0) && (newlen > plen)) return ERR_LENMAX; +#ifdef TEST + newlen = 0; /*don't actually write the new data, if testing*/ +#endif + + ret = write_fru_data(g_fruid, prod_offset, newdata, newlen, fdebug); + return(ret); +} + +#define CHUNKSZ 16 +#define LAST_REC 0xffff +#define STR_OFF 16 + +int get_sdr(ushort recid, ushort resid, ushort *recnext, + uchar *sdr, int *slen, uchar *pcc) +{ + uchar idata[6]; + uchar rdata[64]; + int sresp; + ushort cmd; + uchar cc = 0; + int len = 0; + int rc; + + idata[0] = resid & 0x00ff; + idata[1] = (resid & 0xff00) >> 8; + idata[2] = recid & 0x00ff; + idata[3] = (recid & 0xff00) >> 8; + idata[4] = 0; /*offset*/ + idata[5] = CHUNKSZ; /*bytes to read*/ + if (fdevsdrs) cmd = GET_DEVICE_SDR; + else cmd = GET_SDR; + sresp = sizeof(rdata); + rc = ipmi_cmd_mc(cmd, idata, 6, rdata, &sresp,&cc, fdebug); + if (fdebug) printf("get_sdr[%x] ret = %d cc = %x sresp = %d\n", + recid,rc,cc,sresp); + if (rc == 0 && cc == 0xCA) { + idata[5] = 8; /*bytes to read*/ + sresp = sizeof(rdata); + rc = ipmi_cmd_mc(cmd, idata, 6, rdata, &sresp,&cc, fdebug); + if (fdebug) printf("get_sdr[%x] ret = %d cc = %x sresp = %d\n", + recid,rc,cc,sresp); + } + *pcc = cc; + if (rc == 0 && cc == 0) { + *recnext = rdata[0] + (rdata[1] << 8); + memcpy(sdr,&rdata[2],sresp-2); + *slen = sdr[6] + 5; /*get actual SDR size*/ + len = sresp-2; + /* if an SDR locator record, get the rest of it. */ + if (sdr [3] == 0x11 || sdr[3] == 0x12) + if (*slen > CHUNKSZ) { + idata[0] = resid & 0x00ff; + idata[1] = (resid & 0xff00) >> 8; + idata[2] = recid & 0x00ff; + idata[3] = (recid & 0xff00) >> 8; + idata[4] = CHUNKSZ; /*offset*/ + idata[5] = *slen - CHUNKSZ; /*bytes to read*/ + sresp = sizeof(rdata); + rc = ipmi_cmd_mc(cmd, idata, 6, rdata, &sresp,&cc, fdebug); + if (fdebug) printf("get_sdr[%x] 2nd ret=%d cc=%x sresp=%d\n", + recid,rc,cc,sresp); + if (rc == 0 && cc == 0) { + sresp -= 2; + memcpy(&sdr[len],&rdata[2],sresp); + len += sresp; + } + } + *slen = len; + } + return(rc); +} + +void show_loadfru_error(uchar sa, uchar fruid, int ret) +{ + if (ret == 0) return; + switch(ret) { + case 0x081: printf("\tFRU(%x,%x) device busy\n",sa,fruid); break; + case 0x0C3: printf("\tFRU(%x,%x) timeout, not found\n",sa,fruid); break; + case 0x0CB: printf("\tFRU(%x,%x) not present\n",sa,fruid); break; + default: printf("load_fru(%x,%x) error = %d (0x%x)\n", + sa,fruid,ret,ret); + break; + } + return; +} + +#ifdef METACOMMAND +int i_ifruset(int argc, char **argv) +#else +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#endif +{ + int ret; + int c; + char DevRecord[16]; + ushort recid; + ushort nextid; + ushort rsvid; + uchar sdr[40]; + char biosver[80]; + uchar cc; + uchar sa; + uchar fruid = 0; + uchar frutype = 0; + int len, i; + char *s1; + FILE *fp; + + printf("%s: version %s\n",progname,progver); + parse_lan_options('V',"4",0); /*request admin priv by default*/ + while ( (c = getopt( argc, argv,"a:bcd:h:i:f:m:n:o:p:r:s:u:v:xyz:T:V:J:EYF:P:N:R:U:Z:?")) != EOF ) + switch(c) { + case 'x': fdebug = 1; break; + case 'y': fdoanyway = 1; break; + case 'b': fonlybase = 1; + g_frutype = 0x07; break; + case 'c': fcanonical = 1; bdelim = BDELIM; break; +#ifdef TEST + case 'h': + if (optarg) { + len = strlen(optarg); + if (len >= FIELD_LEN) len = FIELD_LEN - 1; + strncpy(chassis_name,optarg,len); + if (len == 1) { /* add a space */ + chassis_name[1] = ' '; + chassis_name[2] = 0; + } + } + break; +#else + case 'h': fonlyhsc = 1; /* can use -m00c000s instead */ + g_frutype = 0x0f; break; +#endif + case 'a': + fwritefru |= 0x01; + if (optarg) { + len = strlen(optarg); + if (len >= FIELD_LEN) len = FIELD_LEN - 1; + /* if (len == 1), handle it in write_product() */ + strncpy(prodnew[IPROD_ASSET].tag,optarg,len); + prodnew[IPROD_ASSET].len = len; + } + break; + case 'f': + fwritefru |= 0x04; + if (optarg) { + len = strlen(optarg); + if (len >= FIELD_LEN) len = FIELD_LEN - 1; + /* if (len == 1), handle it in write_product() */ + strncpy(prodnew[IPROD_FRUID].tag,optarg,len); + prodnew[IPROD_FRUID].len = len; + } + break; + case 'n': + fwritefru |= 0x20; + if (optarg) { + len = strlen(optarg); + if (len >= FIELD_LEN) len = FIELD_LEN - 1; + /* if (len == 1), handle it in write_product() */ + strncpy(prodnew[IPROD_NAME].tag,optarg,len); + prodnew[IPROD_NAME].len = len; + } + break; + case 'o': + fwritefru |= 0x10; + if (optarg) { + len = strlen(optarg); + if (len >= FIELD_LEN) len = FIELD_LEN - 1; + /* if (len == 1), handle it in write_product() */ + strncpy(prodnew[IPROD_OEM].tag,optarg,len); + prodnew[IPROD_OEM].len = len; + } + break; + case 'p': + fwritefru |= 0x40; + if (optarg) { + len = strlen(optarg); + if (len >= FIELD_LEN) len = FIELD_LEN - 1; + /* if (len == 1), handle it in write_product() */ + strncpy(prodnew[IPROD_PART].tag,optarg,len); + prodnew[IPROD_PART].len = len; + } + break; + case 'u': + fwritefru |= 0x80; + if (optarg) { + len = strlen(optarg); + if (len >= FIELD_LEN) len = FIELD_LEN - 1; + /* if (len == 1), handle it in write_product() */ + strncpy(prodnew[IPROD_MANUF].tag,optarg,len); + prodnew[IPROD_MANUF].len = len; + } + break; + case 's': + fwritefru |= 0x02; + if (optarg) { + len = strlen(optarg); + if (len >= FIELD_LEN) len = FIELD_LEN - 1; + /* if (len == 1), handle it in write_product() */ + strncpy(prodnew[IPROD_SERNUM].tag,optarg,len); + prodnew[IPROD_SERNUM].len = len; + } + break; + case 'v': + fwritefru |= 0x08; + if (optarg) { + len = strlen(optarg); + if (len >= FIELD_LEN) len = FIELD_LEN - 1; + /* if (len == 1), handle it in write_product() */ + strncpy(prodnew[IPROD_VERS].tag,optarg,len); + prodnew[IPROD_VERS].len = len; + } + break; + case 'm': /* specific IPMB MC, 3-byte address, e.g. "409600" */ + g_bus = htoi(&optarg[0]); /*bus/channel*/ + g_sa = htoi(&optarg[2]); /*device slave address*/ + g_lun = htoi(&optarg[4]); /*LUN*/ + g_addrtype = ADDR_IPMB; + if (optarg[6] == 's') { + g_addrtype = ADDR_SMI; s1 = "SMI"; + } else { g_addrtype = ADDR_IPMB; s1 = "IPMB"; } + fset_mc = 1; + printf("set MC at %s bus=%x sa=%x lun=%x\n", + s1,g_bus,g_sa,g_lun); + break; + case 'z': /* set local IPMB MC sa */ + sa = htoi(&optarg[0]); /*device slave address*/ + ipmi_set_mymc(g_bus, sa, g_lun,ADDR_IPMB); + bmc_sa = sa; + case 'i': fonlybase = 1; /*specify a fru id*/ + if (strncmp(optarg,"0x",2) == 0) g_fruid = htoi(&optarg[2]); + else g_fruid = htoi(optarg); + printf("Using FRU ID 0x%02x\n",g_fruid); + break; + case 'd': fdump = 1; /*dump fru to a file*/ + binfile = optarg; + break; + case 'r': frestore = 1; /*restore fru from a file*/ + fwritefru = 0x100; + binfile = optarg; + break; + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'V': /* priv level */ + case 'Y': /* prompt for remote password */ + parse_lan_options(c,optarg,fdebug); + break; + default: + printf("Usage: %s [-bcimx -unpvsafo -NUPREFTVY]\n",progname); + printf(" -u manu Sets Product Manufacturer (0)\n"); + printf(" -n name Sets Product Name (1)\n"); + printf(" -p part Sets Product Part Number (2)\n"); + printf(" -v vers Sets Product Version (3)\n"); + printf(" -s snum Sets Product Serial Num (4)\n"); + printf(" -a tag Sets Product Asset Tag (5)\n"); + printf(" -f fru Sets Product FRU File ID (6)\n"); + printf(" -o oem Sets Product OEM Field (7)\n"); + // printf(" -h chname Sets the Chassis Name \n"); + printf(" -b Only show Baseboard FRU data\n"); + printf(" -c show Canonical, delimited output\n"); + printf(" -d Dump FRU to a file\n"); + printf(" -r Restore FRU from a file\n"); + printf(" -i 00 Get/Set a specific FRU ID\n"); + printf(" -m002000 specific MC (bus 00,sa 20,lun 00)\n"); + printf(" -x Display extra debug messages\n"); + print_lan_opt_usage(); + ret = ERR_USAGE; + goto do_exit; + } + + // if (is_remote() && fwritefru) parse_lan_options('V',"4",0); + + ret = ipmi_getdeviceid( DevRecord, sizeof(DevRecord),fdebug); + if (ret == 0) { + uchar ipmi_maj, ipmi_min; + ipmi_maj = DevRecord[4] & 0x0f; + ipmi_min = DevRecord[4] >> 4; + vend_id = DevRecord[6] + (DevRecord[7] << 8) + (DevRecord[8] << 16); + prod_id = DevRecord[9] + (DevRecord[10] << 8); + show_devid( DevRecord[2], DevRecord[3], ipmi_maj, ipmi_min); + if ((DevRecord[1] & 0x80) == 0x80) fdevsdrs = 1; + if (vend_id == VENDOR_NEC) fdevsdrs = 0; + else if (vend_id == VENDOR_INTEL) { + if (prod_id == 0x003E) { + set_max_kcs_loops(URNLOOPS); /*longer for cmds (default 300)*/ + } + } + } else { + goto do_exit; + } + + ret = ipmi_getpicmg( DevRecord, sizeof(DevRecord),fdebug); + if (ret == 0) fpicmg = 1; + if ((vend_id == VENDOR_INTEL) && (!fpicmg)) + fdevsdrs = 0; /* override, use SDR repository*/ + if (fdebug) printf("bmc_sa = %02x fdevsdrs = %d\n",bmc_sa,fdevsdrs); + + if (fset_mc) { + /* target a specific MC via IPMB (usu a picmg blade) */ + if (fdebug) printf("set_mc: %02x:%02x:%02x type=%d\n", + g_bus,g_sa,g_lun,g_addrtype); + ipmi_set_mc(g_bus,g_sa,g_lun,g_addrtype); + fonlybase = 1; /*only show this MC*/ + } else { + g_sa = bmc_sa; /* BMC_SA = 0x20 */ + } + if (g_frutype == 0) { + g_frutype = 0x01; /* other = "Component" */ + } + + if (!fonlybase && !fonlyhsc) { + /* loop thru SDRs to find FRU devices */ +#ifdef NOT_YET + { /* get SDR Repository Info (needs to be copied here)*/ + ret = GetSDRRepositoryInfo(&j,&fdevsdrs); + if (fdebug) printf("GetSDRRepositoryInfo: ret=%x nSDRs=%d\n",ret,j); + } +#endif + { /* reserve the SDR repository */ + uchar resp[16]; + int sresp; + uchar cc; + ushort cmd; + sresp = sizeof(resp); + if (fdevsdrs) cmd = RESERVE_DEVSDR_REP; + else cmd = RESERVE_SDR_REP; + ret = ipmi_cmd_mc(cmd, NULL, 0, resp, &sresp, &cc, 0); + if (fdebug) printf("ipmi_cmd RESERVE status = %d, cc = %x\n",ret,cc); + rsvid = resp[0] + (resp[1] << 8); + } + recid = 0; + while (recid != LAST_REC) + { + char idstr[32]; + int ilen; + + len = sizeof(sdr); /*sizeof(sdr); get 32 sdr bytes*/ + ret = get_sdr(recid,rsvid,&nextid,sdr,&len,&cc); + if ((ret != 0) || (cc != 0)) { + printf("SDR[%04x] error %d ccode = %x\n",recid,ret,cc); + break; + } + fgetfru = 0; + if ((sdr[3] == 0x11) || (sdr[3] == 0x12)) /* SDR FRU or IPMB type */ + { + if (len > STR_OFF) { + ilen = len - STR_OFF; + if (ilen >= sizeof(idstr)) ilen = sizeof(idstr) - 1; + memcpy(idstr,&sdr[STR_OFF],ilen); + idstr[ilen] = 0; + } else idstr[0] = 0; + sa = sdr[5]; /* usu 0x20 for bmc_sa */ + /* Get its FRU data */ + if ((sdr[3] == 0x11) && (sdr[7] & 0x80)) { /* FRU SDRs */ + /* It is a logical FRU device */ + if (fcanonical) + printf("SDR[%04x] FRU %c %s\n", recid, bdelim, idstr); + else + printf("SDR[%04x] FRU %02x %02x %02x %02x %s\n", recid, + sdr[5],sdr[6],sdr[12],sdr[13],idstr); + fruid = sdr[6]; + frutype = sdr[12]; + if (sa == bmc_sa && fruid == 0) /*do this below*/; + else + switch(sdr[12]) /*FRU entity id*/ + { + case 0x0a: /*Power Supply*/ + case 0x20: /*DIMM*/ + case 0x15: /*Power Cage*/ + default: + fgetfru = 1; + break; + } + } else if (sdr[3] == 0x12) { /* IPMB SDRs (DLRs for MCs) */ + if (fcanonical) + printf("SDR[%04x] IPMB %c %s\n", recid, bdelim, idstr); + else + printf("SDR[%04x] IPMB %02x %02x %02x %02x %s\n", recid, + sdr[5],sdr[6],sdr[12],sdr[13],idstr); + fruid = 0; /*every MC must have fruid 0*/ + frutype = sdr[12]; + if (sa == bmc_sa && fruid == 0) { /*do bmc_sa,0 below*/ + if (fdebug) printf("do bmc_sa %02x below\n",sa); + g_frutype = frutype; + } else if (frutype == 0x2e) { /*skip ME*/ + if (fdebug) printf("skipping ME sa %02x, %02x\n",sa,fruid); + } else if (sa == 0x28) { /*do nothing for Bridge Ctlr sa=0x28*/ + if (fdebug) printf("skipping IPMB sa %02x, %02x\n",sa,fruid); + } else if (sa == 0xC0) { /* HotSwap Backplane (sa=0xC0) */ + /* Note: Loading sa 0xC0 over ipmi lan gives a timeout + * error, but it works locally. */ + fgetfru = 1; + } else { /* other misc sa,fruid */ + fgetfru = 1; + } + } + if (fgetfru) { + uchar adrtype; + adrtype = g_addrtype; + if (fdebug) printf("set_mc %02x:%02x:%02x type=%d fruid=%02x\n", + g_bus,sa,g_lun,adrtype,fruid); + ipmi_set_mc(g_bus, sa, g_lun,adrtype); + ret = load_fru(sa,fruid,frutype); + if (ret != 0) { + show_loadfru_error(sa,fruid,ret); + free_fru(); + } else { + ret = show_fru(sa,fruid,frutype); + if (ret != 0) printf("show_fru error = %d\n",ret); + free_fru(); + } + ipmi_restore_mc(); + } + } /*endif FRU/IPMB SDR */ + recid = nextid; + } /*end while sdrs*/ + } /*endif not fonlybase*/ + + /* load the FRU data for Baseboard (address 0x20) */ + printf("\n"); + sa = g_sa; /* bmc_sa = BMC_SA = 0x20 */ + if (fonlyhsc) { sa = 0xC0; g_addrtype = ADDR_SMI; + ipmi_set_mc(g_bus,sa,g_lun,g_addrtype); + } + if (g_addrtype == ADDR_IPMB) + ipmi_set_mc(g_bus,sa,g_lun,g_addrtype); + ret = load_fru(sa,g_fruid,g_frutype); + if (ret != 0) { + show_loadfru_error(sa,g_fruid,ret); + free_fru(); + goto do_exit; + } + + /* display the Baseboard FRU data */ + ret = show_fru(sa,g_fruid,g_frutype); + if (ret != 0) printf("show_fru error = %d\n",ret); + + if (!is_remote()) { + char devstr[24]; + if (fcanonical) devstr[0] = 0; /*default is empty string*/ + else sprintf(devstr,"[%s,%02x] ",FruTypeString(g_frutype),g_fruid); + i = get_BiosVersion(biosver); + if (i == 0) + printf("%sBIOS Version %c %s\n",devstr,bdelim,biosver); + } + + if (fdump && ret == 0) { + /* Dump FRU to a binary file */ + fp = fopen(binfile,"w"); + if (fp == NULL) { + ret = get_LastError(); + printf("Cannot open file %s, error %d\n",binfile,ret); + } else { + printf("Writing FRU size %d to %s ...\n",sfru,binfile); + len = fwrite(frubuf, 1, sfru, fp); + fclose(fp); + if (len <= 0) { + ret = get_LastError(); + printf("Error %d writing file %s\n",ret,binfile); + } else ret = 0; + } + } else if (frestore) { + uchar cksum; + /* Restore FRU from a binary file */ + fp = fopen(binfile,"r"); + if (fp == NULL) { + ret = get_LastError(); + printf("Cannot open file %s, error %d\n",binfile,ret); + } else { + ret = 0; + /* sfru and frubuf were set from load_fru above. */ + len = fread(frubuf, 1, sfru, fp); + if (len <= 0) { + ret = get_LastError(); + printf("Error %d reading file %s\n",ret,binfile); + sfru = 0; /*for safety*/ + } + fclose(fp); + if (fdebug) { + printf("FRU buffer from file (%d):",sfru); + dumpbuf(frubuf,sfru); + } + /* Do some validation of the FRU buffer header */ + cksum = calc_cksum(&frubuf[0],7); + if (fdebug) + printf("header, len=8, cksum0 = %02x, cksum1 = %02x\n", + frubuf[7],cksum); + if (frubuf[7] != cksum) { + printf("Not a valid FRU file\n"); + ret = ERR_BAD_FORMAT; + free_fru(); + } + if (ret == 0) { /*successfully read data*/ + printf("Writing FRU size %d from %s ...\n",sfru,binfile); + ret = write_fru_data(g_fruid, 0, frubuf, sfru, fdebug); + free_fru(); + if (ret != 0) printf("write_fru error %d (0x%02x)\n",ret,ret); + else { /* successful, show new data */ + ret = load_fru(sa,g_fruid,g_frutype); + if (ret != 0) show_loadfru_error(sa,g_fruid,ret); + else ret = show_fru(sa,g_fruid,g_frutype); + free_fru(); + } + } + } + } /*end-else frestore */ + else if ((fwritefru != 0) && ret == 0) { + printf("\nWriting new product data (%s,%s,%s,%s,%s,%s,%s,%s) ...\n", + prodnew[0].tag, prodnew[1].tag, prodnew[2].tag, + prodnew[3].tag, prodnew[4].tag, prodnew[5].tag, + prodnew[6].tag, prodnew[7].tag); + for (i = 0; i < NUM_PRODUCT_FIELDS; i++) { + len = prodnew[i].len; + if (len > 0) { + if (len >= FIELD_LEN) len = FIELD_LEN - 1; + if (len == 1) { + prodnew[i].tag[1] = ' '; + len++; + } + prodarea[i].len = len; + memcpy(prodarea[i].tag,prodnew[i].tag,len); + } + } + ret = write_product(); + free_fru(); + if (ret != 0) printf("write_product error %d (0x%02x)\n",ret,ret); + else { /* successful, show new data */ + ret = load_fru(sa,g_fruid,g_frutype); + if (ret != 0) show_loadfru_error(sa,g_fruid,ret); + else ret = show_fru(sa,g_fruid,g_frutype); + free_fru(); + } + } + else + free_fru(); + +do_exit: + ipmi_close_(); + show_outcome(progname,ret); + return(ret); +} + +/* end ifruset.c */ diff --git a/util/ifwum.c b/util/ifwum.c new file mode 100644 index 0000000..1e7d547 --- /dev/null +++ b/util/ifwum.c @@ -0,0 +1,1697 @@ +/* + * ifwum.c + * Handle firmware update manager IPMI command functions + * + * Change history: + * 08/20/2010 ARCress - ported from ipmitool/lib/ipmi_fwum.c + * + *--------------------------------------------------------------------- + */ +/* + * Copyright (c) 2004 Kontron Canada, Inc. All Rights Reserved. + * + * Base on code from + * 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. + */ + +#ifdef WIN32 +#include +#include "getopt.h" +#elif defined(HPUX) +/* getopt defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include +#else +#include +#endif +#include +#include +#include +#include +#ifdef LINUX +#include +#endif +#include "ipmicmd.h" +#include "ifwum.h" + +/****************************************************************************** +* HISTORY +* =========================================================================== +* 2007-01-11 [FI] +* - Incremented to version 1.3 +* - Added lan packet size reduction mechanism to workaround fact +* that lan iface will not return C7 on excessive length +* +*****************************************************************************/ + +extern int verbose; /*see ipmilanplus.c*/ +extern void lprintf(int level, const char * format, ...); /*ipmilanplus.c*/ +// extern int ipmi_sendrecv(struct ipmi_rq * req, uint8_t *rsp, int *rsp_len); +extern char * get_mfg_str(uchar *rgmfg, int *pmfg); /*ihealth.c*/ +#ifndef HAVE_LANPLUS +/* define these routines here if no lanplus/helper.c */ +extern uint16_t buf2short(uint8_t * buf); /*ipmilanplus.c*/ +// const char * val2str(uint16_t val, const struct valstr *vs); +#endif + +#define VERSION_MAJ 1 +#define VERSION_MIN 3 + +/* global variables */ +static char * progname = "ifwum"; +static char * progver = "1.3"; +static char fdebug = 0; +static uchar g_bus = PUBLIC_BUS; +static uchar g_sa = BMC_SA; +static uchar g_lun = BMC_LUN; +static uchar g_addrtype = ADDR_SMI; + +typedef enum eKFWUM_Task +{ + KFWUM_TASK_INFO, + KFWUM_TASK_STATUS, + KFWUM_TASK_DOWNLOAD, + KFWUM_TASK_UPGRADE, + KFWUM_TASK_START_UPGRADE, + KFWUM_TASK_ROLLBACK, + KFWUM_TASK_TRACELOG +}tKFWUM_Task; + +typedef enum eKFWUM_BoardList +{ + KFWUM_BOARD_KONTRON_UNKNOWN = 0, + KFWUM_BOARD_KONTRON_5002 = 5002, +}tKFWUM_BoardList; + +typedef enum eKFWUM_IanaList +{ + KFWUM_IANA_KONTRON = 15000, +}tKFWUM_IanaList; + +typedef struct sKFWUM_BoardInfo +{ + tKFWUM_BoardList boardId; + tKFWUM_IanaList iana; +}tKFWUM_BoardInfo; + + +#define KFWUM_STATUS_OK 0 +#define KFWUM_STATUS_ERROR -1 +typedef int tKFWUM_Status; +//typedef enum eKFWUM_Status +//{ +// KFWUM_STATUS_OK, +// KFWUM_STATUS_ERROR +//}tKFWUM_Status; + +typedef enum eKFWUM_DownloadType +{ + KFWUM_DOWNLOAD_TYPE_ADDRESS = 0, + KFWUM_DOWNLOAD_TYPE_SEQUENCE, +}tKFWUM_DownloadType; + +typedef enum eKFWUM_DownloadBuffferType +{ + KFWUM_SMALL_BUFFER_TYPE = 0, + KFUMW_BIG_BUFFER_TYPE +}tKFWUM_DownloadBuffferType; + +typedef struct sKFWUM_InFirmwareInfo +{ + unsigned long fileSize; + unsigned short checksum; + unsigned short sumToRemoveFromChecksum; + /* Since the checksum is added in the bin + after the checksum is calculated, we + need to remove the each byte value. This + byte will contain the addition of both bytes*/ + tKFWUM_BoardList boardId; + unsigned char deviceId; + unsigned char tableVers; + unsigned char implRev; + unsigned char versMajor; + unsigned char versMinor; + unsigned char versSubMinor; + unsigned char sdrRev; + tKFWUM_IanaList iana; +}tKFWUM_InFirmwareInfo; + +typedef struct sKFWUM_SaveFirmwareInfo +{ + tKFWUM_DownloadType downloadType; + unsigned char bufferSize; + unsigned char overheadSize; +}tKFWUM_SaveFirmwareInfo; + +#define KFWUM_SMALL_BUFFER 32 /* Minimum size (IPMB/IOL/old protocol) */ +#define KFWUM_BIG_BUFFER 32 /* Maximum size on KCS interface */ + +#define KFWUM_OLD_CMD_OVERHEAD 6 /*3 address + 1 size + 1 checksum + 1 command*/ +#define KFWUM_NEW_CMD_OVERHEAD 4 /*1 sequence+ 1 size + 1 checksum + 1 command*/ +#define KFWUM_PAGE_SIZE 256 + +static unsigned char fileName[512]; +static unsigned char firmBuf[1024*512]; +static tKFWUM_SaveFirmwareInfo saveFirmwareInfo; + +static void KfwumOutputHelp(void); +static int KfwumMain(void * intf, tKFWUM_Task task); +static tKFWUM_Status KfwumGetFileSize(unsigned char * pFileName, + unsigned long * pFileSize); +static tKFWUM_Status KfwumSetupBuffersFromFile(unsigned char * pFileName, + unsigned long fileSize); +static void KfwumShowProgress( const unsigned char * task, + unsigned long current, unsigned long total); +static unsigned short KfwumCalculateChecksumPadding(unsigned char * pBuffer, + unsigned long totalSize); + + +static tKFWUM_Status KfwumGetInfo(void * intf, unsigned char output, + unsigned char *pNumBank); +static tKFWUM_Status KfwumGetDeviceInfo(void * intf, + unsigned char output, tKFWUM_BoardInfo * pBoardInfo); +static tKFWUM_Status KfwumGetStatus(void * intf); +static tKFWUM_Status KfwumManualRollback(void * intf); +static tKFWUM_Status KfwumStartFirmwareImage(void * intf, + unsigned long length,unsigned short padding); +static tKFWUM_Status KfwumSaveFirmwareImage(void * intf, + unsigned char sequenceNumber, unsigned long address, + unsigned char *pFirmBuf, unsigned char * pInBufLength); +static tKFWUM_Status KfwumFinishFirmwareImage(void * intf, + tKFWUM_InFirmwareInfo firmInfo); +static tKFWUM_Status KfwumUploadFirmware(void * intf, + unsigned char * pBuffer, unsigned long totalSize); +static tKFWUM_Status KfwumStartFirmwareUpgrade(void * intf); + +static tKFWUM_Status KfwumGetInfoFromFirmware(unsigned char * pBuf, + unsigned long bufSize, tKFWUM_InFirmwareInfo * pInfo); +static void KfwumFixTableVersionForOldFirmware(tKFWUM_InFirmwareInfo * pInfo); + +static tKFWUM_Status KfwumGetTraceLog(void * intf); + +tKFWUM_Status KfwumValidFirmwareForBoard(tKFWUM_BoardInfo boardInfo, + tKFWUM_InFirmwareInfo firmInfo); +static void KfwumOutputInfo(tKFWUM_BoardInfo boardInfo, + tKFWUM_InFirmwareInfo firmInfo); + + +/* ipmi_fwum_main - entry point for this ipmitool mode + * + * @intf: ipmi interface + * @arc : number of arguments + * @argv : point to argument array + * + * returns 0 on success + * returns -1 on error + */ +int ipmi_fwum_main(void * intf, int argc, char ** argv) +{ + int rv = ERR_USAGE; /*1*/ + printf("FWUM extension Version %d.%d\n", VERSION_MAJ, VERSION_MIN); + if ((!argc) || ( !strncmp(argv[0], "help", 4))) + { + KfwumOutputHelp(); + } + else + { + if (!strncmp(argv[0], "info", 4)) + { + rv = KfwumMain(intf, KFWUM_TASK_INFO); + } + else if (!strncmp(argv[0], "status", 6)) + { + rv = KfwumMain(intf, KFWUM_TASK_STATUS); + } + else if (!strncmp(argv[0], "rollback", 8)) + { + rv = KfwumMain(intf, KFWUM_TASK_ROLLBACK); + } + else if (!strncmp(argv[0], "download", 8)) + { + if((argc >= 2) && (strlen(argv[1]) > 0)) + { + /* There is a file name in the parameters */ + if(strlen(argv[1]) < 512) + { + strcpy((char *)fileName, argv[1]); + printf("Firmware File Name : %s\n", fileName); + + rv = KfwumMain(intf, KFWUM_TASK_DOWNLOAD); + } + else + { + fprintf(stderr,"File name must be smaller than 512 bytes\n"); + } + } + else + { + fprintf(stderr,"A path and a file name must be specified\n"); + } + } + else if (!strncmp(argv[0], "upgrade", 7)) + { + if((argc >= 2) && (strlen(argv[1]) > 0)) + { + /* There is a file name in the parameters */ + if(strlen(argv[1]) < 512) + { + strcpy((char *)fileName, argv[1]); + printf("Upgrading using file name %s\n", fileName); + rv = KfwumMain(intf, KFWUM_TASK_UPGRADE); + } + else + { + fprintf(stderr,"File name must be smaller than 512 bytes\n"); + } + } + else + { + rv = KfwumMain(intf, KFWUM_TASK_START_UPGRADE); + } + + } + else if (!strncmp(argv[0], "tracelog", 8)) + { + rv = KfwumMain(intf, KFWUM_TASK_TRACELOG); + } + else + { + printf("Invalid KFWUM command: %s\n", argv[0]); + } + } + return rv; +} + + +static void KfwumOutputHelp(void) +{ + printf("KFWUM Commands: info status download upgrade rollback tracelog\n"); +} + + +/****************************************/ +/** private definitions and macros **/ +/****************************************/ +typedef enum eFWUM_CmdId +{ + KFWUM_CMD_ID_GET_FIRMWARE_INFO = 0, + KFWUM_CMD_ID_KICK_IPMC_WATCHDOG = 1, + KFWUM_CMD_ID_GET_LAST_ANSWER = 2, + KFWUM_CMD_ID_BOOT_HANDSHAKE = 3, + KFWUM_CMD_ID_REPORT_STATUS = 4, + KFWUM_CMD_ID_GET_FIRMWARE_STATUS = 7, + KFWUM_CMD_ID_START_FIRMWARE_UPDATE = 9, + KFWUM_CMD_ID_START_FIRMWARE_IMAGE = 0x0a, + KFWUM_CMD_ID_SAVE_FIRMWARE_IMAGE = 0x0b, + KFWUM_CMD_ID_FINISH_FIRMWARE_IMAGE = 0x0c, + KFWUM_CMD_ID_READ_FIRMWARE_IMAGE = 0x0d, + KFWUM_CMD_ID_MANUAL_ROLLBACK = 0x0e, + KFWUM_CMD_ID_GET_TRACE_LOG = 0x0f, + KFWUM_CMD_ID_STD_MAX_CMD, + KFWUM_CMD_ID_EXTENDED_CMD = 0xC0 +} tKFWUM_CmdId; + + + +/****************************************/ +/** global/static variables definition **/ +/****************************************/ + +/****************************************/ +/** functions definition **/ +/****************************************/ + +/******************************************************************************* +* +* Function Name: KfwumMain +* +* Description: This function implements the upload of the firware data +* received as parameters. +* +* Restriction: Called only from main +* +* Input: unsigned char * pBuffer[] : The buffers +* unsigned long bufSize : The size of the buffers +* +* Output: None +* +* Global: none +* +* Return: tIFWU_Status (success or failure) +* +*******************************************************************************/ +static int KfwumMain(void * intf, tKFWUM_Task task) +{ + tKFWUM_Status status = KFWUM_STATUS_OK; + tKFWUM_BoardInfo boardInfo; + tKFWUM_InFirmwareInfo firmInfo = { 0 }; + unsigned long fileSize = 0; + static unsigned short padding; + + if((status == KFWUM_STATUS_OK) && (task == KFWUM_TASK_INFO)) + { + unsigned char notUsed; + if(verbose) + { + printf("Getting Kontron FWUM Info\n"); + } + status = KfwumGetDeviceInfo(intf, 1, &boardInfo); + status = KfwumGetInfo(intf, 1, ¬Used); + + } + + + if((status == KFWUM_STATUS_OK) && (task == KFWUM_TASK_STATUS)) + { + if(verbose) + { + printf("Getting Kontron FWUM Status\n"); + } + status = KfwumGetStatus(intf); + } + + if( (status == KFWUM_STATUS_OK) && (task == KFWUM_TASK_ROLLBACK) ) + { + status = KfwumManualRollback(intf); + } + + if( + (status == KFWUM_STATUS_OK) && + ( + (task == KFWUM_TASK_UPGRADE) || (task == KFWUM_TASK_DOWNLOAD) + ) + ) + { + status = KfwumGetFileSize(fileName, &fileSize); + if(status == KFWUM_STATUS_OK) + { + status = KfwumSetupBuffersFromFile(fileName, fileSize); + if(status == KFWUM_STATUS_OK) + { + padding = KfwumCalculateChecksumPadding(firmBuf, fileSize); + } + } + if(status == KFWUM_STATUS_OK) + { + status = KfwumGetInfoFromFirmware(firmBuf, fileSize, &firmInfo); + } + if(status == KFWUM_STATUS_OK) + { + status = KfwumGetDeviceInfo(intf, 0, &boardInfo); + } + + if(status == KFWUM_STATUS_OK) + { + status = KfwumValidFirmwareForBoard(boardInfo,firmInfo); + } + + if (status == KFWUM_STATUS_OK) + { + unsigned char notUsed; + KfwumGetInfo(intf, 0, ¬Used); + } + + KfwumOutputInfo(boardInfo,firmInfo); + } + + if( + (status == KFWUM_STATUS_OK) && + ( + (task == KFWUM_TASK_UPGRADE) || (task == KFWUM_TASK_DOWNLOAD) + ) + ) + { + status = KfwumStartFirmwareImage(intf, fileSize, padding); + } + + + if( + (status == KFWUM_STATUS_OK) && + ( + (task == KFWUM_TASK_UPGRADE) || (task == KFWUM_TASK_DOWNLOAD) + ) + ) + { + status = KfwumUploadFirmware(intf, firmBuf, fileSize); + } + + if( + (status == KFWUM_STATUS_OK) && + ( + (task == KFWUM_TASK_UPGRADE) || (task == KFWUM_TASK_DOWNLOAD) + ) + ) + { + status = KfwumFinishFirmwareImage(intf, firmInfo); + } + + if( + (status == KFWUM_STATUS_OK) && + ( + (task == KFWUM_TASK_UPGRADE) || (task == KFWUM_TASK_DOWNLOAD) + ) + ) + { + status = KfwumGetStatus(intf); + } + + if( + (status == KFWUM_STATUS_OK) && + ( + (task == KFWUM_TASK_UPGRADE) || (task == KFWUM_TASK_START_UPGRADE) + ) + ) + { + status = KfwumStartFirmwareUpgrade(intf); + } + + if((status == KFWUM_STATUS_OK) && (task == KFWUM_TASK_TRACELOG)) + { + status = KfwumGetTraceLog(intf); + } + + return(status); +} + +/* KfwumGetFileSize - gets the file size + * + * @pFileName : filename ptr + * @pFileSize : output ptr for filesize + * + * returns KFWUM_STATUS_OK or KFWUM_STATUS_ERROR + */ +static tKFWUM_Status KfwumGetFileSize(unsigned char * pFileName, + unsigned long * pFileSize) +{ + tKFWUM_Status status = KFWUM_STATUS_ERROR; + FILE * pFileHandle; + + pFileHandle = fopen((const char *)pFileName, "rb"); + + if(pFileHandle) + { + if(fseek(pFileHandle, 0L , SEEK_END) == 0) + { + *pFileSize = ftell(pFileHandle); + + if( *pFileSize != 0) + { + status = KFWUM_STATUS_OK; + } + } + fclose(pFileHandle); + } + + return(status); +} + +/* KfwumSetupBuffersFromFile - small buffers are used to store the file data + * + * @pFileName : filename ptr + * unsigned long : filesize + * + * returns KFWUM_STATUS_OK or KFWUM_STATUS_ERROR + */ +#define MAX_FW_BUFFER_SIZE 1024*16 +static tKFWUM_Status KfwumSetupBuffersFromFile(unsigned char * pFileName, + unsigned long fileSize) +{ + tKFWUM_Status status = KFWUM_STATUS_OK; + FILE * pFileHandle; + + pFileHandle = fopen((const char *)pFileName, "rb"); + + if(pFileHandle) + { + int count = fileSize / MAX_FW_BUFFER_SIZE; + int modulus = fileSize % MAX_FW_BUFFER_SIZE; + int qty =0; + + rewind(pFileHandle); + + for(qty=0;qtyprotocolRevision); + printf("Controller Device Id : %02Xh\n", + pGetInfo->controllerDeviceId); + printf("Firmware Revision : %u.%u%u", + pGetInfo->firmRev1, pGetInfo->firmRev2 >> 4, + pGetInfo->firmRev2 & 0x0f); + if(pGetInfo->byte.mode != 0) + { + printf(" - DEBUG BUILD\n"); + } + else + { + printf("\n"); + } + printf("Number Of Memory Bank : %u\n",pGetInfo->numBank); + } + * pNumBank = pGetInfo->numBank; + + /* Determine wich type of download to use: */ + /* Old FWUM or Old IPMC fw (data_len < 7) --> + Address with small buffer size */ + if ( (pGetInfo->protocolRevision) <= 0x05 || (rsp_len < 7 ) ) + { + saveFirmwareInfo.downloadType = KFWUM_DOWNLOAD_TYPE_ADDRESS; + saveFirmwareInfo.bufferSize = KFWUM_SMALL_BUFFER; + saveFirmwareInfo.overheadSize = KFWUM_OLD_CMD_OVERHEAD; + + if(verbose) + { + printf("Protocol Revision :"); + printf(" <= 5 detected, adjusting buffers\n"); + } + } + else /* Both fw are using the new protocol */ + { + saveFirmwareInfo.downloadType = KFWUM_DOWNLOAD_TYPE_SEQUENCE; + saveFirmwareInfo.overheadSize = KFWUM_NEW_CMD_OVERHEAD; + /* Buffer size depending on access type (Local or remote) */ + /* Look if we run remote or locally */ + + if(verbose) + { + printf("Protocol Revision :"); + printf(" > 5 optimizing buffers\n"); + } + + ipmi_get_mc(&bus, &sa, &lun, &mtype); + dtype = get_driver_type(); + if(is_remote()) /* covers lan and lanplus */ + { + saveFirmwareInfo.bufferSize = KFWUM_SMALL_BUFFER; + if(verbose) + { + printf("IOL payload size : %d\r\n" , + saveFirmwareInfo.bufferSize); + } + } else if ( (dtype == DRV_MV) && (sa != IPMI_BMC_SLAVE_ADDR) && + (mtype == ADDR_IPMB) ) + { + saveFirmwareInfo.bufferSize = KFWUM_SMALL_BUFFER; + if(verbose) + { + printf("IPMB payload size : %d\r\n" , + saveFirmwareInfo.bufferSize); + } + } + else + { + saveFirmwareInfo.bufferSize = KFWUM_BIG_BUFFER; + if(verbose) + { + printf("SMI payload size : %d\r\n", + saveFirmwareInfo.bufferSize); + } + } + } + } + return status; +} + +/* KfwumGetDeviceInfo - Get IPMC/Board information + * + * * intf : IPMI interface + * output : when set to non zero, queried information is displayed + * tKFWUM_BoardInfo: output ptr for IPMC/Board information + */ +static tKFWUM_Status KfwumGetDeviceInfo(void * intf, + unsigned char output, tKFWUM_BoardInfo * pBoardInfo) +{ + struct ipm_devid_rsp *pGetDevId; + tKFWUM_Status status = KFWUM_STATUS_OK; + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + char *mstr; + + /* Send Get Device Id */ + if(status == KFWUM_STATUS_OK) + { + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = BMC_GET_DEVICE_ID; + req.msg.data_len = 0; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Error in Get Device Id Command %d (0x%02x)\n",rv,rv); + status = rv; // KFWUM_STATUS_ERROR + } + } + + if(status == KFWUM_STATUS_OK) + { + pGetDevId = (struct ipm_devid_rsp *) rsp; + pBoardInfo->iana = IPM_DEV_MANUFACTURER_ID(pGetDevId->manufacturer_id); + pBoardInfo->boardId = buf2short(pGetDevId->product_id); + if(output) + { + mstr = get_mfg_str(pGetDevId->manufacturer_id,NULL); + printf("\nIPMC Info\n"); + printf("=========\n"); + printf("Manufacturer Id : %u \t%s\n",pBoardInfo->iana,mstr); + printf("Board Id : %u\n",pBoardInfo->boardId); + printf("Firmware Revision : %u.%u%u", + pGetDevId->fw_rev1, pGetDevId->fw_rev2 >> 4, + pGetDevId->fw_rev2 & 0x0f); + if( + ( + ( pBoardInfo->iana == KFWUM_IANA_KONTRON) + && + (pBoardInfo->boardId == KFWUM_BOARD_KONTRON_5002) + ) + ) + { + printf(" SDR %u\n", pGetDevId->aux_fw_rev[0]); + } + else + { + printf("\n"); + } + } + } + + return status; +} + +#pragma pack(1) +struct KfwumGetStatusResp { + unsigned char bankState; + unsigned char firmLengthLSB; + unsigned char firmLengthMid; + unsigned char firmLengthMSB; + unsigned char firmRev1; + unsigned char firmRev2; + unsigned char firmRev3; +}; // __attribute__ ((packed)); +#pragma pack() + +const struct valstr bankStateValS[] = { + { 0x00, "Not programmed" }, + { 0x01, "New firmware" }, + { 0x02, "Wait for validation" }, + { 0x03, "Last Known Good" }, + { 0x04, "Previous Good" } +}; + +/* KfwumGetStatus - Get (and prints) FWUM banks information + * + * * intf : IPMI interface + */ +static tKFWUM_Status KfwumGetStatus(void * intf) +{ + tKFWUM_Status status = KFWUM_STATUS_OK; + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + struct KfwumGetStatusResp *pGetStatus; + unsigned char numBank; + unsigned char counter; + + if(verbose) + { + printf(" Getting Status!\n"); + } + + /* Retreive the number of bank */ + status = KfwumGetInfo(intf, 0, &numBank); + + for( + counter = 0; + (counter < numBank) && (status == KFWUM_STATUS_OK); + counter ++ + ) + { + /* Retreive the status of each bank */ + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_FIRMWARE; + req.msg.cmd = KFWUM_CMD_ID_GET_FIRMWARE_STATUS; + req.msg.data = &counter; + req.msg.data_len = 1; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("FWUM Firmware Get Status Error %d (0x%02x)\n",rv,rv); + status = rv; // KFWUM_STATUS_ERROR + } + + if(status == KFWUM_STATUS_OK) + { + pGetStatus = (struct KfwumGetStatusResp *) rsp; + printf("\nBank State %d : %s\n", counter, val2str( + pGetStatus->bankState, bankStateValS)); + if(pGetStatus->bankState) + { + unsigned long firmLength; + firmLength = pGetStatus->firmLengthMSB; + firmLength = firmLength << 8; + firmLength |= pGetStatus->firmLengthMid; + firmLength = firmLength << 8; + firmLength |= pGetStatus->firmLengthLSB; + + printf("Firmware Length : %ld bytes\n", firmLength); + printf("Firmware Revision : %u.%u%u SDR %u\n", + pGetStatus->firmRev1, pGetStatus->firmRev2 >> 4, + pGetStatus->firmRev2 & 0x0f, pGetStatus->firmRev3); + } + } + } + printf("\n"); + return status; +} +#pragma pack(1) +struct KfwumManualRollbackReq{ + unsigned char type; +}; // __attribute__ ((packed)); +#pragma pack() + + +/* KfwumManualRollback - Ask IPMC to rollback to previous version + * + * * intf : IPMI interface + */ +static tKFWUM_Status KfwumManualRollback(void * intf) +{ + tKFWUM_Status status = KFWUM_STATUS_OK; + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + struct KfwumManualRollbackReq thisReq; + + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_FIRMWARE; + req.msg.cmd = KFWUM_CMD_ID_MANUAL_ROLLBACK; + + thisReq.type = 0; /* Wait BMC shutdown */ + + req.msg.data = (unsigned char *) &thisReq; + req.msg.data_len = 1; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Error in FWUM Manual Rollback Command %d (0x%02x)\n",rv,rv); + status = rv; // KFWUM_STATUS_ERROR + } + + if(status == KFWUM_STATUS_OK) + { + printf("FWUM Starting Manual Rollback \n"); + } + return status; +} + +#pragma pack(1) +struct KfwumStartFirmwareDownloadReq{ + unsigned char lengthLSB; + unsigned char lengthMid; + unsigned char lengthMSB; + unsigned char paddingLSB; + unsigned char paddingMSB; + unsigned char useSequence; +}; // __attribute__ ((packed)); +struct KfwumStartFirmwareDownloadResp { + unsigned char bank; +}; // __attribute__ ((packed)); +#pragma pack() + +static tKFWUM_Status KfwumStartFirmwareImage(void * intf, + unsigned long length,unsigned short padding) +{ + tKFWUM_Status status = KFWUM_STATUS_OK; + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + struct KfwumStartFirmwareDownloadResp *pResp; + struct KfwumStartFirmwareDownloadReq thisReq; + + thisReq.lengthLSB = (uchar)(length & 0x000000ff); + thisReq.lengthMid = (uchar)((length >> 8) & 0x000000ff); + thisReq.lengthMSB = (uchar)((length >> 16) & 0x000000ff); + thisReq.paddingLSB = padding & 0x00ff; + thisReq.paddingMSB = (padding>> 8) & 0x00ff; + thisReq.useSequence = 0x01; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_FIRMWARE; + req.msg.cmd = KFWUM_CMD_ID_START_FIRMWARE_IMAGE; + req.msg.data = (unsigned char *) &thisReq; + + /* Look for download type */ + if ( saveFirmwareInfo.downloadType == KFWUM_DOWNLOAD_TYPE_ADDRESS ) + { + req.msg.data_len = 5; + } + else + { + req.msg.data_len = 6; + } + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("FWUM Firmware Start Firmware Image Download returned %d (0x%02x)\n",rv,rv); + status = rv; // KFWUM_STATUS_ERROR + } + + if(status == KFWUM_STATUS_OK) + { + pResp = (struct KfwumStartFirmwareDownloadResp *) rsp; + printf("Bank holding new firmware : %d\n", pResp->bank); + os_usleep(5,0); + } + return status; +} + +#pragma pack(1) +struct KfwumSaveFirmwareAddressReq +{ + unsigned char addressLSB; + unsigned char addressMid; + unsigned char addressMSB; + unsigned char numBytes; + unsigned char txBuf[KFWUM_SMALL_BUFFER-KFWUM_OLD_CMD_OVERHEAD]; +}; // __attribute__ ((packed)); + +struct KfwumSaveFirmwareSequenceReq +{ + unsigned char sequenceNumber; + unsigned char txBuf[KFWUM_BIG_BUFFER]; +}; // __attribute__ ((packed)); +#pragma pack() + + +#define FWUM_SAVE_FIRMWARE_NO_RESPONSE_LIMIT ((unsigned char)6) + +static tKFWUM_Status KfwumSaveFirmwareImage(void * intf, + unsigned char sequenceNumber, unsigned long address, unsigned char *pFirmBuf, + unsigned char * pInBufLength) +{ + tKFWUM_Status status = KFWUM_STATUS_OK; + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + unsigned char out = 0; + unsigned char retry = 0; + unsigned char noResponse = 0 ; + + struct KfwumSaveFirmwareAddressReq addressReq; + struct KfwumSaveFirmwareSequenceReq sequenceReq; + + do + { + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_FIRMWARE; + req.msg.cmd = KFWUM_CMD_ID_SAVE_FIRMWARE_IMAGE; + + if (saveFirmwareInfo.downloadType == KFWUM_DOWNLOAD_TYPE_ADDRESS ) + { + addressReq.addressLSB = (uchar)(address & 0x000000ff); + addressReq.addressMid = (uchar)((address >> 8) & 0x000000ff); + addressReq.addressMSB = (uchar)((address >> 16) & 0x000000ff); + addressReq.numBytes = (* pInBufLength); + memcpy(addressReq.txBuf, pFirmBuf, (* pInBufLength)); + req.msg.data = (unsigned char *) &addressReq; + req.msg.data_len = (* pInBufLength)+4; + } + else + { + sequenceReq.sequenceNumber = sequenceNumber; + memcpy(sequenceReq.txBuf, pFirmBuf, (* pInBufLength)); + req.msg.data = (unsigned char *) &sequenceReq; + req.msg.data_len = (* pInBufLength)+sizeof(unsigned char); /* + 1 => sequenceNumber*/ + } + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv < 0) + { + printf("Error in FWUM Firmware Save Firmware Image Download Command\n"); + + out = 0; + status = KFWUM_STATUS_OK; + + /* With IOL, we don't receive "C7" on errors, instead we receive + nothing */ + if(is_remote()) + { + noResponse++; + + if(noResponse < FWUM_SAVE_FIRMWARE_NO_RESPONSE_LIMIT ) + { + (* pInBufLength) -= 1; + out = 0; + } + else + { + printf("Error, too many commands without response\n"); + (* pInBufLength) = 0 ; + out = 1; + } + } /* For other interface keep trying */ + } + else if (rv > 0) /*ccode*/ + { + if(rv == 0xc0) + { + status = KFWUM_STATUS_OK; + os_usleep(1,0); + } + else if( + (rv == 0xc7) + || + ( + (rv == 0xC3) && + (sequenceNumber == 0) + ) + ) + { + (* pInBufLength) -= 1; + status = KFWUM_STATUS_OK; + retry = 1; + } + else if(rv == 0x82) + { + /* Double sent, continue */ + status = KFWUM_STATUS_OK; + out = 1; + } + else if(rv == 0x83) + { + if(retry == 0) + { + retry = 1; + status = KFWUM_STATUS_OK; + } + else + { + status = rv; // KFWUM_STATUS_ERROR + out = 1; + } + } + else if(rv == 0xcf) /* Ok if receive duplicated request */ + { + retry = 1; + status = KFWUM_STATUS_OK; + } + else if(rv == 0xC3) + { + if(retry == 0) + { + retry = 1; + status = KFWUM_STATUS_OK; + } + else + { + status = rv; // KFWUM_STATUS_ERROR + out = 1; + } + } + else + { + printf("FWUM Firmware Save Firmware Image Download returned %x\n", + rv); + status = rv; // KFWUM_STATUS_ERROR + out = 1; + } + } + else + { + out = 1; + } + }while(out == 0); + return status; +} + +#pragma pack(1) +struct KfwumFinishFirmwareDownloadReq{ + unsigned char versionMaj; + unsigned char versionMinSub; + unsigned char versionSdr; + unsigned char reserved; +}; // __attribute__ ((packed)); +#pragma pack() +static tKFWUM_Status KfwumFinishFirmwareImage(void * intf, + tKFWUM_InFirmwareInfo firmInfo) +{ + tKFWUM_Status status = KFWUM_STATUS_OK; + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + struct KfwumFinishFirmwareDownloadReq thisReq; + + thisReq.versionMaj = firmInfo.versMajor; + thisReq.versionMinSub = ((firmInfo.versMinor <<4) | firmInfo.versSubMinor); + thisReq.versionSdr = firmInfo.sdrRev; + thisReq.reserved = 0; + /* Byte 4 reserved, write 0 */ + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_FIRMWARE; + req.msg.cmd = KFWUM_CMD_ID_FINISH_FIRMWARE_IMAGE; + req.msg.data = (unsigned char *) &thisReq; + req.msg.data_len = 4; + + do + { + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + }while (rv == 0xc0); + + if (rv < 0) + { + printf("Error in FWUM Firmware Finish Firmware Image Download Command\n"); + status = rv; // KFWUM_STATUS_ERROR + } + else if (rv > 0) + { + printf("FWUM Firmware Finish Firmware Image Download returned %x\n", + rv); + status = rv; // KFWUM_STATUS_ERROR + } + + return status; +} + + +#define FWUM_MAX_UPLOAD_RETRY 6 +static tKFWUM_Status KfwumUploadFirmware(void * intf, + unsigned char * pBuffer, unsigned long totalSize) +{ + tKFWUM_Status status = KFWUM_STATUS_ERROR; + unsigned long address = 0x0; + unsigned char writeSize; + unsigned char oldWriteSize; + unsigned long lastAddress = 0; + unsigned char sequenceNumber = 0; + unsigned char retry = FWUM_MAX_UPLOAD_RETRY; + // unsigned char isLengthValid = 1; + + do + { + writeSize = saveFirmwareInfo.bufferSize - saveFirmwareInfo.overheadSize; + + /* Reach the end */ + if( address + writeSize > totalSize ) + { + writeSize = (uchar)(totalSize - address); + } + /* Reach boundary end */ + else if(((address % KFWUM_PAGE_SIZE) + writeSize) > KFWUM_PAGE_SIZE) + { + writeSize = (KFWUM_PAGE_SIZE - (uchar)(address % KFWUM_PAGE_SIZE)); + } + + oldWriteSize = writeSize; + status = KfwumSaveFirmwareImage(intf, sequenceNumber, address, + &pBuffer[address], &writeSize); + + if((status != KFWUM_STATUS_OK) && (retry-- != 0)) + { + address = lastAddress; + status = KFWUM_STATUS_OK; + } + else if( writeSize == 0 ) + { + status = KFWUM_STATUS_ERROR; + } + else + { + if(writeSize != oldWriteSize) + { + printf("Adjusting length to %d bytes \n", writeSize); + saveFirmwareInfo.bufferSize -= (oldWriteSize - writeSize); + } + + retry = FWUM_MAX_UPLOAD_RETRY; + lastAddress = address; + address+= writeSize; + } + + if(status == KFWUM_STATUS_OK) + { + if((address % 1024) == 0) + { + KfwumShowProgress((const unsigned char *)\ + "Writing Firmware in Flash",address,totalSize); + } + sequenceNumber++; + } + + }while((status == KFWUM_STATUS_OK) && (address < totalSize )); + + if(status == KFWUM_STATUS_OK) + { + KfwumShowProgress((const unsigned char *)\ + "Writing Firmware in Flash", 100 , 100 ); + } + + return(status); +} + +static tKFWUM_Status KfwumStartFirmwareUpgrade(void * intf) +{ + tKFWUM_Status status = KFWUM_STATUS_OK; + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + unsigned char upgType = 0 ; /* Upgrade type, wait BMC shutdown */ + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_FIRMWARE; + req.msg.cmd = KFWUM_CMD_ID_START_FIRMWARE_UPDATE; + req.msg.data = (unsigned char *) &upgType; + req.msg.data_len = 1; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv < 0) + { + printf("Error in FWUM Firmware Start Firmware Upgrade Command\n"); + status = rv; // KFWUM_STATUS_ERROR + } + else if (rv > 0) + { + if(rv == 0xd5) + { + printf("No firmware available for upgrade. Download Firmware first\n"); + } + else + { + printf("FWUM Firmware Start Firmware Upgrade returned %x\n", + rv); + } + status = rv; // KFWUM_STATUS_ERROR + } + + return status; +} + +#define TRACE_LOG_CHUNK_COUNT 7 +#define TRACE_LOG_CHUNK_SIZE 7 +#define TRACE_LOG_ATT_COUNT 3 +/* String table */ +/* Must match eFWUM_CmdId */ +static const char* CMD_ID_STRING[] = { + "GetFwInfo", + "KickWatchdog", + "GetLastAnswer", + "BootHandshake", + "ReportStatus", + "CtrlIPMBLine", + "SetFwState", + "GetFwStatus", + "GetSpiMemStatus", + "StartFwUpdate", + "StartFwImage", + "SaveFwImage", + "FinishFwImage", + "ReadFwImage", + "ManualRollback", + "GetTraceLog" }; + +static const char* EXT_CMD_ID_STRING[] = { + "FwUpgradeLock", + "ProcessFwUpg", + "ProcessFwRb", + "WaitHSAfterUpg", + "WaitFirstHSUpg", + "FwInfoStateChange" }; + + +static const char* CMD_STATE_STRING[] = { + "Invalid", + "Begin", + "Progress", + "Completed" }; + + +static tKFWUM_Status KfwumGetTraceLog(void * intf) +{ + tKFWUM_Status status = KFWUM_STATUS_OK; + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + unsigned char chunkIdx; + unsigned char cmdIdx; + + if(verbose) + { + printf(" Getting Trace Log!\n"); + } + + for( chunkIdx = 0; (chunkIdx < TRACE_LOG_CHUNK_COUNT) && (status == KFWUM_STATUS_OK); chunkIdx++ ) + { + /* Retreive each log chunk and print it */ + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_FIRMWARE; + req.msg.cmd = KFWUM_CMD_ID_GET_TRACE_LOG; + req.msg.data = &chunkIdx; + req.msg.data_len = 1; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("FWUM Firmware Get Trace Log returned %d (0x%02x)\n",rv,rv); + status = rv; // KFWUM_STATUS_ERROR + } + + if(status == KFWUM_STATUS_OK) + { + for (cmdIdx=0; cmdIdx < TRACE_LOG_CHUNK_SIZE; cmdIdx++) + { + /* Don't diplay commands with an invalid state */ + if ( (rsp[TRACE_LOG_ATT_COUNT*cmdIdx+1] != 0) && + (rsp[TRACE_LOG_ATT_COUNT*cmdIdx] < KFWUM_CMD_ID_STD_MAX_CMD)) + { + printf(" Cmd ID: %17s -- CmdState: %10s -- CompCode: %2x\n", + CMD_ID_STRING[rsp[TRACE_LOG_ATT_COUNT*cmdIdx]], + CMD_STATE_STRING[rsp[TRACE_LOG_ATT_COUNT*cmdIdx+1]], + rsp[TRACE_LOG_ATT_COUNT*cmdIdx+2]); + } + else if ( (rsp[TRACE_LOG_ATT_COUNT*cmdIdx+1] != 0) && + (rsp[TRACE_LOG_ATT_COUNT*cmdIdx] >= KFWUM_CMD_ID_EXTENDED_CMD)) + { + printf(" Cmd ID: %17s -- CmdState: %10s -- CompCode: %2x\n", + EXT_CMD_ID_STRING[rsp[TRACE_LOG_ATT_COUNT*cmdIdx] - KFWUM_CMD_ID_EXTENDED_CMD], + CMD_STATE_STRING[rsp[TRACE_LOG_ATT_COUNT*cmdIdx+1]], + rsp[TRACE_LOG_ATT_COUNT*cmdIdx+2]); + } + } + } + } + printf("\n"); + return status; +} + + +/******************************************************************************* +* Function Name: KfwumGetInfoFromFirmware +* +* Description: This function retreive from the firmare the following info : +* +* o Checksum +* o File size (expected) +* o Board Id +* o Device Id +* +* Restriction: None +* +* Input: char * fileName - File to get info from +* +* Output: pInfo - container that will hold all the informations gattered. +* see structure for all details +* +* Global: None +* +* Return: IFWU_SUCCESS - file ok +* IFWU_ERROR - file error +* +*******************************************************************************/ +#define IN_FIRMWARE_INFO_OFFSET_LOCATION 0x5a0 +#define IN_FIRMWARE_INFO_SIZE 20 +#define IN_FIRMWARE_INFO_OFFSET_FILE_SIZE 0 +#define IN_FIRMWARE_INFO_OFFSET_CHECKSUM 4 +#define IN_FIRMWARE_INFO_OFFSET_BOARD_ID 6 +#define IN_FIRMWARE_INFO_OFFSET_DEVICE_ID 8 +#define IN_FIRMWARE_INFO_OFFSET_TABLE_VERSION 9 +#define IN_FIRMWARE_INFO_OFFSET_IMPLEMENT_REV 10 +#define IN_FIRMWARE_INFO_OFFSET_VERSION_MAJOR 11 +#define IN_FIRMWARE_INFO_OFFSET_VERSION_MINSUB 12 +#define IN_FIRMWARE_INFO_OFFSET_SDR_REV 13 +#define IN_FIRMWARE_INFO_OFFSET_IANA0 14 +#define IN_FIRMWARE_INFO_OFFSET_IANA1 15 +#define IN_FIRMWARE_INFO_OFFSET_IANA2 16 + +#define KWUM_GET_BYTE_AT_OFFSET(pBuffer,os) pBuffer[os] + +tKFWUM_Status KfwumGetInfoFromFirmware(unsigned char * pBuf, + unsigned long bufSize, tKFWUM_InFirmwareInfo * pInfo) +{ + tKFWUM_Status status = KFWUM_STATUS_ERROR; + + if(bufSize >= (IN_FIRMWARE_INFO_OFFSET_LOCATION + IN_FIRMWARE_INFO_SIZE)) + { + unsigned long offset = IN_FIRMWARE_INFO_OFFSET_LOCATION; + + /* Now, fill the structure with read informations */ + pInfo->checksum = (unsigned short)KWUM_GET_BYTE_AT_OFFSET(pBuf, + offset+0+IN_FIRMWARE_INFO_OFFSET_CHECKSUM ) << 8; + pInfo->checksum |= (unsigned short)KWUM_GET_BYTE_AT_OFFSET(pBuf, + offset+1+IN_FIRMWARE_INFO_OFFSET_CHECKSUM ); + + + pInfo->sumToRemoveFromChecksum= + KWUM_GET_BYTE_AT_OFFSET(pBuf, + offset+IN_FIRMWARE_INFO_OFFSET_CHECKSUM); + + pInfo->sumToRemoveFromChecksum+= + KWUM_GET_BYTE_AT_OFFSET(pBuf , + offset+IN_FIRMWARE_INFO_OFFSET_CHECKSUM+1); + + pInfo->fileSize = + KWUM_GET_BYTE_AT_OFFSET(pBuf , + offset+IN_FIRMWARE_INFO_OFFSET_FILE_SIZE+0) << 24; + pInfo->fileSize |= + (unsigned long)KWUM_GET_BYTE_AT_OFFSET(pBuf, + offset+IN_FIRMWARE_INFO_OFFSET_FILE_SIZE+1) << 16; + pInfo->fileSize |= + (unsigned long)KWUM_GET_BYTE_AT_OFFSET(pBuf, + offset+IN_FIRMWARE_INFO_OFFSET_FILE_SIZE+2) << 8; + pInfo->fileSize |= + (unsigned long)KWUM_GET_BYTE_AT_OFFSET(pBuf, + offset+IN_FIRMWARE_INFO_OFFSET_FILE_SIZE+3); + + pInfo->boardId = + KWUM_GET_BYTE_AT_OFFSET(pBuf, + offset+IN_FIRMWARE_INFO_OFFSET_BOARD_ID+0) << 8; + pInfo->boardId |= + KWUM_GET_BYTE_AT_OFFSET(pBuf, + offset+IN_FIRMWARE_INFO_OFFSET_BOARD_ID+1); + + pInfo->deviceId = + KWUM_GET_BYTE_AT_OFFSET(pBuf, + offset+IN_FIRMWARE_INFO_OFFSET_DEVICE_ID); + + pInfo->tableVers = + KWUM_GET_BYTE_AT_OFFSET(pBuf, + offset+IN_FIRMWARE_INFO_OFFSET_TABLE_VERSION); + pInfo->implRev = + KWUM_GET_BYTE_AT_OFFSET(pBuf, + offset+IN_FIRMWARE_INFO_OFFSET_IMPLEMENT_REV); + pInfo->versMajor = + (KWUM_GET_BYTE_AT_OFFSET(pBuf, + offset+IN_FIRMWARE_INFO_OFFSET_VERSION_MAJOR)) & 0x0f; + pInfo->versMinor = + (KWUM_GET_BYTE_AT_OFFSET(pBuf, + offset+IN_FIRMWARE_INFO_OFFSET_VERSION_MINSUB)>>4) & 0x0f; + pInfo->versSubMinor = + (KWUM_GET_BYTE_AT_OFFSET(pBuf, + offset+IN_FIRMWARE_INFO_OFFSET_VERSION_MINSUB)) & 0x0f; + pInfo->sdrRev = + KWUM_GET_BYTE_AT_OFFSET(pBuf, + offset+IN_FIRMWARE_INFO_OFFSET_SDR_REV); + pInfo->iana = + KWUM_GET_BYTE_AT_OFFSET(pBuf , + offset+IN_FIRMWARE_INFO_OFFSET_IANA2) << 16; + pInfo->iana |= + (unsigned long)KWUM_GET_BYTE_AT_OFFSET(pBuf, + offset+IN_FIRMWARE_INFO_OFFSET_IANA1) << 8; + pInfo->iana |= + (unsigned long)KWUM_GET_BYTE_AT_OFFSET(pBuf, + offset+IN_FIRMWARE_INFO_OFFSET_IANA0); + + KfwumFixTableVersionForOldFirmware(pInfo); + + status = KFWUM_STATUS_OK; + } + return(status); +} + + +void KfwumFixTableVersionForOldFirmware(tKFWUM_InFirmwareInfo * pInfo) +{ + switch(pInfo->boardId) + { + case KFWUM_BOARD_KONTRON_UNKNOWN: + pInfo->tableVers = 0xff; + break; + default: + /* pInfo->tableVers is already set for the right version */ + break; + } +} + + +tKFWUM_Status KfwumValidFirmwareForBoard(tKFWUM_BoardInfo boardInfo, + tKFWUM_InFirmwareInfo firmInfo) +{ + tKFWUM_Status status = KFWUM_STATUS_OK; + + if(boardInfo.iana != firmInfo.iana) + { + printf("Board IANA does not match firmware IANA\n"); + status = KFWUM_STATUS_ERROR; + } + + if(boardInfo.boardId != firmInfo.boardId) + { + printf("Board IANA does not match firmware IANA\n"); + status = KFWUM_STATUS_ERROR; + } + + if(status == KFWUM_STATUS_ERROR) + { + printf("Firmware invalid for target board. Download of upgrade aborted\n"); + } + return status; +} + + +static void KfwumOutputInfo(tKFWUM_BoardInfo boardInfo, + tKFWUM_InFirmwareInfo firmInfo) +{ + printf("Target Board Id : %u\n",boardInfo.boardId); + printf("Target IANA number : %u\n",boardInfo.iana); + printf("File Size : %lu bytes\n",firmInfo.fileSize); + printf("Firmware Version : %d.%d%d SDR %d\n",firmInfo.versMajor, + firmInfo.versMinor, firmInfo.versSubMinor, firmInfo.sdrRev); +} + +#ifdef METACOMMAND +int i_fwum(int argc, char **argv) +#else +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#endif +{ + void *intf = NULL; + int rc = 0; + int c, i; + char *s1; + + printf("%s ver %s\n", progname,progver); + + while ( (c = getopt( argc, argv,"m:T:V:J:EYF:P:N:R:U:Z:x?")) != EOF ) + switch (c) { + case 'm': /* specific IPMB MC, 3-byte address, e.g. "409600" */ + g_bus = htoi(&optarg[0]); /*bus/channel*/ + g_sa = htoi(&optarg[2]); /*device slave address*/ + g_lun = htoi(&optarg[4]); /*LUN*/ + g_addrtype = ADDR_IPMB; + if (optarg[6] == 's') { + g_addrtype = ADDR_SMI; s1 = "SMI"; + } else { g_addrtype = ADDR_IPMB; s1 = "IPMB"; } + ipmi_set_mc(g_bus,g_sa,g_lun,g_addrtype); + printf("Use MC at %s bus=%x sa=%x lun=%x\n", + s1,g_bus,g_sa,g_lun); + break; + case 'x': fdebug = 1; verbose = 1; + break; /* debug messages */ + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'V': /* priv level */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + break; + case '?': + KfwumOutputHelp(); + return ERR_USAGE; + break; + } + for (i = 0; i < optind; i++) { argv++; argc--; } + + rc = ipmi_fwum_main(intf, argc, argv); + + ipmi_close_(); + // show_outcome(progname,rc); + return rc; +} diff --git a/util/ifwum.h b/util/ifwum.h new file mode 100644 index 0000000..e6c228c --- /dev/null +++ b/util/ifwum.h @@ -0,0 +1,76 @@ +/* + * 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. + */ + +#ifndef IPMI_KFWUM_H +#define IPMI_KFWUM_H + +// #include +// #include + +#define uint8_t unsigned char +#define uint16_t unsigned short +#define uint32_t unsigned int + +#define IPMI_NETFN_APP 0x6 +#define IPMI_NETFN_FIRMWARE 0x8 + +#define IPMI_BMC_SLAVE_ADDR 0x20 + +#define BMC_GET_DEVICE_ID 0x1 + +#define IPM_DEV_MANUFACTURER_ID(x) \ + ((uint32_t) ((x[2] & 0x0F) << 16 | x[1] << 8 | x[0])) + +//struct valstr { + // uint16_t val; + // const char * str; +//}; + +#pragma pack(1) +struct ipm_devid_rsp { + uint8_t device_id; + uint8_t device_revision; + uint8_t fw_rev1; + uint8_t fw_rev2; + uint8_t ipmi_version; + uint8_t adtl_device_support; + uint8_t manufacturer_id[3]; + uint8_t product_id[2]; + uint8_t aux_fw_rev[4]; +}; // __attribute__ ((packed)); +#pragma pack() + +/* routines from lib/lanplus/helper.c */ +uint16_t buf2short(uint8_t * buf); +//const char * val2str(uint16_t val, const struct valstr * vs); + +#endif /* IPMI_KFWUM_H */ diff --git a/util/igetevent.c b/util/igetevent.c new file mode 100644 index 0000000..6e2fe27 --- /dev/null +++ b/util/igetevent.c @@ -0,0 +1,1439 @@ +/* + * igetevent.c + * + * This utility waits for IPMI Event Messages. + * Some server management functions want to trigger custom actions or + * alerts when IPMI hardware-related events occur, but do not want to + * track all events, just newly occurring events. + * The IPMI events also include BIOS events such as Memory and POST errors, + * which would not be captured by reading the IPMI sensors. + * This utility waits a specified timeout period for any events, and + * returns interpreted output for each event. It is designed as a + * scriptable command-line utility, but if the timeout is infinite + * (-t 0), then this code could be used for a sample service as well. + * + * There are several methods to do this which are implemented here. + * The SEL method (-s): + * This method polls the SEL once a second, keeps track of the last + * SEL event read, and only new events are processed. This ensures + * that in a series of rapid events, all events are received in order, + * however, some transition-to-OK events may not be configured to + * write to the SEL on certain platforms. + * This method is used if getevent -s is specified. + * The ReadEventMessageBuffer method (-m getmessage option): + * This uses an IPMI Message Buffer in the BMC firmware to read + * each new event. This receives any event, but if two events + * occur nearly simultaneously, only the most recent of the two + * will be returned with this method. An example of simultaneous + * events might be, if a fan stops/fails, both the non-critical + * and critical fan threshold events would occur at that time. + * This is the default method for getevent. It would be used + * locally with the Intel IMB driver or with direct/driverless. + * The OpenIPMI custom method (-m getmessage_mv option if DRV_MV): + * Different IPMI drivers may have varying behavior. For instance, + * the OpenIPMI driver uses the IPMI GetMessage commands internally + * and does not allow client programs to use those commands. It has + * its own custom mechanism, see getevent_mv(). + * This method is used locally if the OpenIPMI driver is detected. + * The Async Event method (-a): + * This only gets certain Asynchronous events, like a shutdown + * request from the BMC to an SMS OS service, and get_software_id. + * This is supported for Intel IMB driver and OpenIPMI driver only. + * This method is only used locally if getevent option -a is used, + * and if either MV (openipmi) or IMB driver is loaded. + * The ipmiutil_asy init script controls the getevent -a service. + * (see DO_ASYNC compile flag comments) + * + * Author: Andy Cress arcress at users.sourceforge.net + * Copyright (c) 2005-2006 Intel Corporation. + * Copyright (c) 2009 Kontron America, Inc. + * + * 02/11/05 Andy Cress - created + * 05/18/05 Andy Cress - modified bmc_enable bits + * 05/26/05 Andy Cress - added call to decode_sel_entry + * 09/09/05 Andy Cress - added sensor_type filtering & return type. + * 03/16/05 Andy Cress - added loop, and -o for frunOnce + * 06/27/06 Andy Cress 1.1 - specific message for cc=0x80 (no data) + * 07/18/06 Andy Cress 1.1 - added getevent_mv, etc. + * 07/26/06 Andy Cress 1.1 - added msgout() routine for fflush + * 08/08/06 Andy Cress 1.2 - added -s for SEL method + * 08/08/06 Andy Cress 1.2 - added -s for SEL method + * 08/22/06 Andy Cress 1.3 - direct IOs added with ipmiutil-1.7.5 + * 09/13/06 Andy Cress 1.4 - handle empty SEL (0xCB), + * call syncevent_sel after every new event. + * 09/21/07 Andy Cress 1.21 - implemented IMB Async method for remote + * OS shutdown via SMS requests. + */ +/*M* +Copyright (c) 2009 Kontron America, Inc. +Copyright (c) 2013 Andy Cress +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions 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. + c.. Neither the name of Kontron nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ +#ifdef WIN32 +#include +#include +#include +#include "getopt.h" +#elif defined(DOS) +#include +#include +#include +#include +#include +#include "getopt.h" +#else +#include +#include +#include +#include +#include +#include +#if defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include +#else +#include +#include +#endif +#include +#include +#endif +#include +#ifdef SOLARIS +/* Solaris */ +#define HandleType long +#elif WIN32 +#include "imb_api.h" +#define DO_ASYNC 1 +#elif LINUX +#define LINUX 1 +#include "imb_api.h" +#define DO_ASYNC 1 +#define DO_MVL 1 +#elif BSD +#define DO_MVL 1 +#define HandleType long +#else +/* other OS */ +#define HandleType long +#endif +#include "ipmicmd.h" + +#define THREADS_OK 1 +#define IMBPTIMEOUT 200 /*200 ms*/ +// #define IPMB_CHANNEL 0x00 +// #define LAN_CHANNEL 0x02 +#define ulong unsigned long +#define uint unsigned int +#define ushort unsigned short +#define uchar unsigned char + +#define CMD_GET_SOFTWARE_ID 0x00 +#define CMD_SMS_OS_REQUEST 0x10 + +extern int decode_sel_entry(uchar *evt, char *obuf, int sz); /*see ievents.c*/ +extern void set_sel_opts(int sensdesc, int canon, void *sdrs, char fdbg, char utc); /* ievents.c */ +extern char *get_sensor_type_desc(uchar stype); /*see ievents.c*/ +extern int write_syslog(char *msg); /*see isel.c*/ +extern char *show_driver_type(int idx); /*see ipmicmd.h*/ +extern int get_sdr_cache(uchar **pret); /*see isensor.c*/ +extern void free_sdr_cache(uchar *pret); /*see isensor.c*/ + +/* + * Global variables + */ +static char * progname = "igetevent"; +static char * progver = "2.93"; +static char fdebug = 0; +static char fipmilan = 0; +static char frunonce = 0; +static char futc = 0; +static char fAsync = 0; +static char fAsyncOK = 0; /*=1 if drvtype detected for it*/ +static char fAsyncNOP = 0; /*=1 if skip Async actions*/ +static char fbackground = 0; +static char frunscript = 0; +static char fcanonical = 0; +static char fsettime = 0; /* =1 if timeout is set by -t */ +static uchar evt_stype = 0xff; /* event sensor type, 0xff = get any events */ +static uchar evt_snum = 0xff; /* event sensor num, 0xff = get any events */ +static int timeout = 120; /* 120 seconds default timeout */ +static int wait_interval = 1; /* 1 second between calls */ +static FILE *fdout = NULL; +static char *run_script = NULL; +static uchar ipmi_maj = 0; +static uchar ipmi_min = 0; +static HandleType imb_handle = 0; +static int drvtype = 0; /* driver_type from ipmicmd.h: 1=Intel_imb, 3=MV_OpenIPMI */ +static int vend_id = 0; +static int prod_id = 0; +static char fselevts = 0; +static char fmsgevts = 0; +static ushort sel_recid = 0; +static uint sel_time = 0; +static uchar sms_sa = 0x81; +static uchar *sdrs = NULL; +#define LAST_REC 0xFFFF +#ifdef WIN32 +#define IDXFILE "ipmi_evt.idx" +static char idxfile[80] = IDXFILE; +static char idxfile2[80] = "c:\\ipmi_evt.idx"; +static char outfile[80] = "c:\\ipmiutil_evt.log"; +#define SHUTDOWN_CMD "shutdown -s -d p:01:01 -t 10" +#define REBOOT_CMD "shutdown -r -d p:01:01 -t 10" +#else +static char idxfile[80] = "/var/lib/ipmiutil/evt.idx"; +static char idxfile2[80] = "/usr/share/ipmiutil/evt.idx"; +static char outfile[80] = "/var/log/ipmiutil_evt.log"; +#define SHUTDOWN_CMD "init 0" // or shutdown now +#define REBOOT_CMD "init 6" +#endif +#ifdef METACOMMAND +extern FILE *fpdbg; /*from ipmicmd.c*/ +extern FILE *fperr; /*from ipmicmd.c*/ +#endif +/* prototypes */ +static void iclose(void); +static void ievt_siginit(void); +static void ievt_cleanup(void); + +#define METHOD_UNKNOWN 0 +#define METHOD_SEL_EVTS 1 +#define METHOD_MSG_GET 2 +#define METHOD_MSG_MV 3 +#define METHOD_ASYNC_MV 4 +#define METHOD_ASYNC_IMB 5 +static char *methodstr[6] = { + "unknown", + "SEL_events", + "GetMessage", + "GetMessage_mv", + "Async_mv", + "Async_imb" }; + +static int do_wait(int nsec) +{ + int rv = 0; + if (nsec > 0) os_usleep(nsec,0); /*declared in ipmicmd.h*/ + return(rv); +} + +static int get_event_receiver(uchar *sa, uchar *lun) +{ + uchar rdata[30]; + int rlen; + uchar ccode; + int ret; + + rlen = 2; +#if 0 + ret = ipmi_cmdraw( 0x01,NETFN_SEVT,BMC_SA,PUBLIC_BUS,BMC_LUN, + idata,0, rdata,&rlen,&ccode, fdebug); +#endif + ret = ipmi_cmd(GET_EVENT_RECEIVER,NULL,0, rdata,&rlen,&ccode, 0); + if (ret == 0 && ccode != 0) ret = ccode; + if (ret == 0) { + *sa = rdata[0]; + *lun = rdata[1]; + } + return(ret); +} + +static int get_msg_flags(uchar *flags) +{ + uchar rdata[8]; + int rlen = 1; + uchar ccode; + int ret; + ret = ipmi_cmdraw( 0x31,NETFN_APP,BMC_SA,PUBLIC_BUS,BMC_LUN, + NULL,0, rdata,&rlen,&ccode, fdebug); + if (ret == 0 && ccode != 0) ret = ccode; + if ((ret == 0) && (flags != NULL)) *flags = rdata[0]; + return(ret); +} + +static int set_bmc_enables(uchar enab) +{ + uchar idata[8]; + uchar rdata[30]; + int rlen; + uchar ccode; + int ret; + + idata[0] = enab; + rlen = 1; + ret = ipmi_cmdraw( 0x2E,NETFN_APP,BMC_SA,PUBLIC_BUS,BMC_LUN, + idata,1, rdata,&rlen,&ccode, fdebug); + if (ret == 0 && ccode != 0) ret = ccode; + return(ret); +} + +static int get_bmc_enables(uchar *enab) +{ + uchar rdata[30]; + int rlen; + uchar ccode; + int ret; + + rlen = 1; + ret = ipmi_cmdraw( 0x2F,NETFN_APP,BMC_SA,PUBLIC_BUS,BMC_LUN, + NULL,0, rdata,&rlen,&ccode, fdebug); + if (ret == 0 && ccode != 0) ret = ccode; + + if (ret == 0) *enab = rdata[0]; + return(ret); +} + +/* + * msgout + * wrapper for printf() to include fflush + */ +void msgout(char *pattn, ...) +{ + va_list arglist; + + if (fdout == NULL) return; + va_start( arglist, pattn ); + vfprintf( fdout, pattn, arglist ); + va_end( arglist ); + fflush( fdout ); +} + +#ifdef DO_ASYNC +/* The DO_ASYNC flag enables the IMB Async Message method via get_imb_event. + * This requires the Intel IMB driver, and is used only for remote shutdown + * and software ID events. */ + +/* The LANDesk library has the same function names as the imbapi.c */ +#ifdef LINK_LANDESK +#define StartAsyncMesgPoll ia_StartAsyncMesgPoll +#define SendAsyncImbpRequest ia_SendAsyncImbpRequest +#define GetAsyncImbpMessage ia_GetAsyncImbpMessage +#define GetAsyncImbpMessage_Ex ia_GetAsyncImbpMessage_Ex +#define IsAsyncMessageAvailable ia_IsAsyncMessageAvailable +#define RegisterForImbAsyncMessageNotification ia_RegisterForImbAsyncMessageNotification +#define UnRegisterForImbAsyncMessageNotification ia_UnRegisterForImbAsyncMessageNotification +#define SendTimedLanMessageResponse_Ex ia_SendTimedLanMessageResponse_Ex +#define SendTimedEmpMessageResponse_Ex ia_SendTimedEmpMessageResponse_Ex +#endif /*endif LINK_LANDESK*/ + +typedef struct { + uchar rsSa; + uchar nfLn; + uchar cSum1; + uchar rqSa; + uchar seqLn; + uchar cmd; + uchar data[1]; +} AsyImbPacket; + +#ifdef THREADS_OK + char message[32]; +#ifdef WIN32 + HANDLE threadid = NULL; +#else + pthread_t threadid = 0; +#endif +#endif + +#ifdef WIN32 +#define ThreadRType DWORD +ThreadRType WINAPI pollThread( LPVOID p) +#else +#define ThreadRType void * +ThreadRType pollThread(void *p) +#endif +{ + int i; + int ret, limit; +#ifdef THREADS_OK + limit = 0; +#else + limit = 30; +#endif + for (i = 0; (limit == 0) || (i < limit); i++) + { + ret = StartAsyncMesgPoll(); + if (fdebug && i < 5) + msgout("StartAsyncMesgPoll [%d] ret = %d\n",i,ret); + // os_usleep(0,5000); /* poll interval 5 msec */ + os_usleep(1,0); /* poll interval 1 sec */ + } + return((ThreadRType)0); +} + +static int GetBmcLanChannel(uchar *chan) +{ + int ret = 0; + int j; + int rlen; + uchar iData[2]; + uchar rData[10]; + uchar cc; + uchar mtype; + uchar chn = 1; + + if (vend_id == VENDOR_INTEL) { + if (prod_id == 0x000C || prod_id == 0x001B) { + *chan = 7; + return(ret); + } + } + for (j = 1; j < 12; j++) { + rlen = sizeof(rData); + iData[0] = (uchar)j; /*channel #*/ + memset(rData,0,9); /*initialize recv data*/ + ret = ipmi_cmd(GET_CHANNEL_INFO, iData, 1, rData, &rlen, &cc, fdebug); + if (ret == 0xcc || cc == 0xcc) /* special case for ipmi_lan */ + continue; + if (ret != 0) { + if (fdebug) printf("get_chan_info rc = %x\n",ret); + break; + } + mtype = rData[1]; /* channel medium type */ + if (mtype == 4) { /* 802.3 LAN type*/ + if (fdebug) printf("chan[%d] = lan\n",j); + chn = (uchar)j; + break; + } + } + *chan = chn; + return(ret); +} + +int SoftwareIdResponse(uchar *buf, int blen, uchar hnd, uchar chan) +{ + int rv = 0; + uchar resp[12] = {0,0xa6,0,0,0,1,0,0x00,0x01,0x57,0x00,0x01}; +#ifdef WIN32 + /* check OS version & arch (32/64) */ +#else + struct utsname uts; + rv = uname(&uts); + // uts.release=`uname -r` uts.machine=x86_64,ia64,i586,i386 + // kver <= 24 bytes, mach/arch <= 6 bytes +#endif + +#ifdef USE_LANMSG + rv = SendTimedLanMessageResponse_Ex( (ImbPacket *)buf, (char *)(&resp), 12, + IMBPTIMEOUT, hnd, chan); +#else + rv = SendTimedEmpMessageResponse_Ex((ImbPacket *)buf, (char *)(&resp), 12, + IMBPTIMEOUT, hnd,chan); +#endif + if (fdebug) msgout("SoftwareIdResponse(%d) ret = %d\n",chan,rv); + return(rv); +} + + +int SmsOsResponse(uchar *buf, int blen, uchar func, uchar hnd, uchar chan) +{ + int rv = 0; + char cc = 0; + if (frunscript) { + write_syslog("igetevent -a running script\n"); + rv = system(run_script); + if (fdebug) msgout("run(%s) ret = %d\n",run_script,rv); + } + switch(func) /*data byte has function*/ + { + case 0x01: /*shutdown & power down*/ + rv = SendTimedEmpMessageResponse_Ex((ImbPacket *)buf, &cc,1, + IMBPTIMEOUT, hnd,chan); + if (fdebug) msgout("OsResponse(%d) ret = %d\n",chan,rv); + if (!fAsyncNOP) { + write_syslog("igetevent -a initiating OS shutdown\n"); + rv = system(SHUTDOWN_CMD); + if (fdebug) msgout("shutdown ret = %d\n",rv); + } + break; + case 0x02: /*shutdown & reset*/ + rv = SendTimedEmpMessageResponse_Ex((ImbPacket *)buf, &cc,1, + IMBPTIMEOUT, hnd,chan); + if (fdebug) msgout("OsResponse(%d) ret = %d\n",chan,rv); + if (!fAsyncNOP) { + write_syslog("igetevent -a initiating OS reboot\n"); + rv = system(REBOOT_CMD); + if (fdebug) msgout("reboot ret = %d\n",rv); + } + break; + default: + if (fdebug) msgout("igetevent -a unknown function %d\n",func); + rv = 1; + break; + } + return(rv); +} + +/* + * get_imb_event + * This only gets certain IMB events, like + * OS requests (e.g. shutdown), and get_software_id + */ +static int get_imb_event(uchar etype, int timeout, uchar *evt) +{ + int ret = -1; + int i; + int done = 0; + ulong mlen; + uchar buffer[512]; + uchar sendbuf[18]; + static uint asyseqnum = 0; + uchar chan; + uchar sessHandle = 0; + uchar privilege = 0; + uchar cmd, func; + // uchar *pbuf; + + ret = GetBmcLanChannel(&chan); + + /* clean out pre-existing async messages */ + while(1) { + mlen = sizeof(buffer); + if (GetAsyncImbpMessage((ImbPacket *)buffer,&mlen, IMBPTIMEOUT, + &asyseqnum, IPMB_CHANNEL) != 0) + break; + if (fdebug) msgout("cleaned out an IPMB message seq=%d\n",asyseqnum); + } + while(1) { + mlen = sizeof(buffer); + if (GetAsyncImbpMessage((ImbPacket *)buffer,&mlen, IMBPTIMEOUT, + &asyseqnum, LAN_CHANNEL) != 0) + break; + if (fdebug) msgout("cleaned out a LAN message seq=%d\n",asyseqnum); + } + ret = RegisterForImbAsyncMessageNotification(&imb_handle); + if (fdebug) + msgout("RegisterForImbAsync ret=%d, handle=%x\n",ret,imb_handle); + if (ret != 0) { + msgout("RegisterAsync error %d\n",ret); + return(ret); + } + + for (i = 0; (timeout == 0) || (i < timeout); i++) + { /*get one imb event*/ + if (fdebug) msgout("IsAsyncMessageAvailable ...\n"); + if (IsAsyncMessageAvailable(imb_handle) == 0) + { + if (fdebug) msgout("Async Message is Available\n"); + mlen = sizeof(buffer); + ret = GetAsyncImbpMessage_Ex ((ImbPacket *)buffer, &mlen, + IMBPTIMEOUT, &asyseqnum, ANY_CHANNEL, + &sessHandle, &privilege); + /* Hack: buffer contains an extra byte to return channel */ + if (fdebug) + msgout("GetAsync(%d,%d) ret = %d, newchan=%x\n", + asyseqnum,chan,ret,buffer[mlen]); + if (ret == 0) { + /* get the async message command */ + if (fdebug) dump_buf("async msg",buffer,mlen+1,0); + chan = buffer[mlen]; + if (mlen > 16) mlen = 16; + if (buffer[0] == sms_sa) { + memcpy(&sendbuf[0],buffer,mlen); + } else { /* handle shorter format for some BMCs */ + sendbuf[0] = sms_sa; + memcpy(&sendbuf[1],buffer,mlen); + } + cmd = sendbuf[5]; func = sendbuf[6]; + msgout("got async msg: cmd=%02x len=%d\n",cmd,mlen); + memcpy(evt,sendbuf,mlen); + + switch(cmd) { + case CMD_GET_SOFTWARE_ID: /*Get Software ID*/ + ret = SoftwareIdResponse(sendbuf,mlen,sessHandle,chan); + break; + case CMD_SMS_OS_REQUEST: /*SMS OS Request*/ + ret = SmsOsResponse(sendbuf,mlen,func,sessHandle,chan); + if (ret == 0) done = 1; + break; + default: + ret = LAN_ERR_INVPARAM; + msgout("SmsOS cmd %02x unknown, ret = %d\n",cmd,ret); + } + if (fdebug) + msgout("async msg cmd=%02x ret = %d\n",cmd,ret); + if (done == 1) { + if (func == 0x01) msgout("shutting down\n"); + else msgout("rebooting\n"); + ret = 0x81; + break; + } + } + } /*endif have an event*/ + else ret = 0x80; /* no event yet */ + } /*loop for one event*/ + if (fdebug) msgout("Unregister for imb events\n"); + UnRegisterForImbAsyncMessageNotification (imb_handle,0); + return(ret); +} +#endif + /*endif DO_ASYNC*/ + +#ifdef DO_MVL +/* Linux, enable MV OpenIPMI interface */ +extern int register_async_mv(uchar cmd, uchar netfn); /*see ipmimv.c*/ +extern int unregister_async_mv(uchar cmd, uchar netfn); /*see ipmimv.c*/ +extern int getevent_mv(uchar *evt_data, int *evt_len, uchar *cc, int t); +extern int ipmi_rsp_mv(uchar cmd, uchar netfn, uchar lun, uchar sa, uchar bus, + uchar *pdata, int sdata, char fdebugcmd); + +static int send_mv_asy_resp(uchar *evt) +{ + uchar cmd, sa, bus, cc; + uchar data0[12] = {0,0xa6,0,0,0,1,0,0x00,0x01,0x57,0x00,0x01}; + uchar data1[1] = { 0x00 }; + uchar rdata[80]; + int sdata, rlen, i; + uchar *pdata; + int rv = -1; + + cmd = evt[2]; + sa = sms_sa; /* sa = SMS_SA (0x81) */ + bus = 0x01; /* usu lan_ch == 1 */ + switch(cmd) { + case CMD_GET_SOFTWARE_ID: /*software id*/ + pdata = &data0[0]; + sdata = sizeof(data0); + break; + case CMD_SMS_OS_REQUEST: /*restart*/ + pdata = &data1[0]; + sdata = sizeof(data1); + break; + default: rv = LAN_ERR_INVPARAM; return (rv); + break; + } + rv = ipmi_rsp_mv(cmd, (NETFN_APP | 0x01), sa, bus, BMC_LUN, + pdata,sdata, fdebug); + if (rv == 0) { + for (i = 0; i < 5; i++) + { + rlen = sizeof(rdata); + rv = getevent_mv(rdata,&rlen,&cc,1); + if (fdebug) msgout("send_mv_asy_resp: rv=%d cc=%x\n",rv,cc); + if (rv == 0 && cc == 0) { + if (fdebug) msgout("got rsp ccode: type=%02x len=%d cc=%x\n", + rdata[0],rlen,rdata[3]); + if (rlen > 0) rv = rdata[3]; /*cc*/ + break; + } + os_usleep(0,5000); /*wait 5 ms*/ + } + } + return (rv); +} + +static int get_mv_asy_event(uchar cmd, int timeout, uchar *evt) +{ + int ret = -1; + int rv = -1; + uchar cc = 0; + uchar rdata[120]; + int rlen, i; + + rv = register_async_mv(cmd,NETFN_APP); /*reserved,GetSoftwareID*/ + if (rv != 0) return(rv); + + for (i = 0; (timeout == 0) || (i < timeout); i++) + { /*get one async event*/ + rv = getevent_mv(rdata,&rlen,&cc,timeout); + if (fdebug) + msgout("get_mv_asy_event: i=%d cmd=%x rv=%d cc=%x\n",i,cmd,rv,cc); + if (rv == 0 && cc == 0) { + msgout("got async msg: type=%02x cmd=%x len=%d\n", + rdata[0],rdata[2],rlen); + if (fdebug) dump_buf("async msg",rdata,rlen,0); + /* check recv_type == 3 (IPMI_CMD_RECV_TYPE) */ + if (rdata[0] == 3 && rdata[2] == cmd) { + if (rlen > 16) rlen = 16; + memcpy(evt,rdata,rlen); + break; + } else { /*else msg, but no match*/ + rv = ERR_BAD_PARAM; + break; + } + } + else do_wait(wait_interval); /*wait 1 sec*/ + } + ret = unregister_async_mv(cmd,NETFN_APP); /*reserved,GetSoftwareID*/ + return(rv); +} +#endif + +static int get_evt_method(char *evtmethod) +{ + int method = METHOD_UNKNOWN; + if (fAsync) { + if (drvtype == DRV_MV) method = METHOD_ASYNC_MV; + else /* if (drvtype == DRV_IMB) */ method = METHOD_ASYNC_IMB; + } else if (fselevts) method = METHOD_SEL_EVTS; + else { /*fmsgevts*/ + if (drvtype == DRV_MV) method = METHOD_MSG_MV; + else method = METHOD_MSG_GET; + } + if (evtmethod != NULL) + strcpy(evtmethod,methodstr[method]); + return(method); +} + +static int get_sel_entry(ushort recid, ushort *nextid, uchar *rec) +{ + uchar ibuf[6]; + uchar rbuf[32]; + int rlen; + ushort xid, id = 0; + uchar cc; + int rv; + + ibuf[0] = 0; + ibuf[1] = 0; + ibuf[2] = (recid & 0x00ff); + ibuf[3] = (recid & 0xff00) >> 8; + ibuf[4] = 0; + ibuf[5] = 0xFF; /*get entire record*/ + rlen = sizeof(rbuf); + rv = ipmi_cmd(GET_SEL_ENTRY, ibuf, 6, rbuf, &rlen, &cc, fdebug); + if (rv == 0) { + if (cc != 0) rv = cc; + else { /*success*/ + xid = rbuf[0] + (rbuf[1] << 8); /*next rec id*/ + memcpy(rec,&rbuf[2],16); + *nextid = xid; + id = rbuf[2] + (rbuf[3] << 8); /*curr rec id*/ + /* recid (requested) should match newid (received) */ + if (fdebug) { + if ((recid != id) && (recid != LAST_REC) && (recid != 0)) { + /* the OpenIPMI driver does this sometimes */ + msgout("get_sel MISMATCH: recid=%x newid=%x next=%x\n", + recid,id,xid); + dump_buf("get_sel cmd",ibuf,6,0); + dump_buf("get_sel rsp",rbuf,rlen,0); + } + } + } + } + if (fdebug) msgout("get_sel(%x) rv=%d cc=%x id=%x next=%x\n", + recid,rv,cc,id,*nextid); + return(rv); +} + +static int startevent_sel(ushort *precid, uint *ptime) +{ + FILE *fd; + uchar rec[24]; + uint t = 0; + ushort r = 0; + ushort r2 = 0; + int rv = -1; + + fd = fopen(idxfile,"r"); + if (fd == NULL) fd = fopen(idxfile2,"r"); /*handle old location*/ + if (fdebug) msgout("start: idxfile=%s fd=%p\n",idxfile,fd); + if (fd != NULL) { + // Read the file, get savtime & savid + rv = fscanf(fd,"%x %x",&t,&r); + fclose(fd); + if (r == LAST_REC) r = 0; + rv = 0; /*read it, success*/ + } else { /* treat as first time */ + r = LAST_REC; + rv = get_sel_entry(r,&r2,rec); + if (rv == 0) { + memcpy(&t,&rec[3],4); + r = rec[0] + (rec[1] << 8); /*use current rec id*/ + } else r = 0; + rv = 1; /*first time*/ + } + if (fdebug) msgout("start: recid=%x time=%x\n",r,t); + *ptime = t; + *precid = r; + return(rv); +} + +static int syncevent_sel(ushort recid, uint itime) +{ + FILE *fd; + int rv; + // Rewrite the saved time & record id + if (fdebug) msgout("sync: recid=%x time=%x\n",recid,itime); + fd = fopen(idxfile,"w"); + if (fd == NULL) { + msgout("syncevent: cannot open %s for writing\n",idxfile); + rv = -1; + } else { + fprintf(fd,"%x %x\n",itime,recid); + fclose(fd); + rv = 0; + } + return(rv); +} + +int getevent_sel(uchar *rdata, int *rlen, uchar *ccode) +{ + uchar rec[24]; + int rv = 0; + ushort newid; + ushort nextid; + ushort recid; + + /* get current last record */ + recid = sel_recid; + rv = get_sel_entry(recid,&nextid,rec); + if (rv == 0xCB && recid == 0) { /* SEL is empty */ + *ccode = (uchar)rv; /* save the real ccode */ + rv = 0x80; /* this is ok, just keep waiting */ + } + if (rv == 0) { + if (fdebug) msgout("sel ok, id=%x next=%x\n",recid,nextid); + if ((nextid == LAST_REC) || (recid == nextid)) { + *ccode = 0x80; /*nothing new*/ + } else { + recid = nextid; /* else get new one */ + rv = get_sel_entry(recid,&nextid,rec); + if (rv == 0) { /* new event */ + newid = rec[0] + (rec[1] << 8); + if (drvtype == DRV_MV && recid != newid) { + /* handle MV driver bug, try to get next one. */ + if (fdebug) msgout("%s bug, record mismatch\n", + show_driver_type(DRV_MV)); + } + if (fdebug) msgout("recid=%x newid=%x next=%x\n", + recid,newid,nextid); + memcpy(rdata,rec,16); + *rlen = 16; + *ccode = 0; + sel_recid = recid; /*or newid*/ + memcpy(&sel_time,&rec[3],4); + } + } + } + else { /* Error reading last recid saved */ + if (fdebug) msgout("sel recid %x error, rv = %d\n",recid,rv); + /* We want to set sel_recid = 0 here for some errors. */ + if (rv == 0xCB || rv == 0xCD) { /* empty, or wrong SDR id */ + sel_recid = 0; + *ccode = (uchar)rv; + rv = 0x80; /* wait again */ + } + } + return(rv); +} + +static int get_event(uchar etype, uchar snum, int timeout, + uchar *evt, uchar *stype) +{ + int ret = 0; + uchar rdata[64]; + int rlen; + uchar ccode; + int fretry; + int i; + + for (i = 0; (timeout == 0) || (i < timeout); i++) + { + rlen = sizeof(rdata); + fretry = 0; ccode = 0; + if (fselevts) { + ret = getevent_sel(rdata,&rlen,&ccode); + } else +#ifdef DO_MVL + if (drvtype == DRV_MV) { /* if MV OpenIPMI driver (Linux only) */ + if (timeout == 0) wait_interval = 0; + /* use special MV API instead (see ipmimv.c) */ + ret = getevent_mv(rdata,&rlen,&ccode,timeout); + } else +#endif + ret = ipmi_cmd(READ_EVENT_MSGBUF,NULL,0,rdata,&rlen,&ccode,fdebug); + /* now we have an event from one of the above methods*/ + + /* IPMI 1.5 spec, section 18.8 says cc 0x80 means + * "data not available (queue/buffer empty)" */ + if (ret == 0 && ccode != 0) { ret = ccode; } + if (ret == 0x80) { + fretry = 1; + do_wait(wait_interval); /*wait 1 sec*/ + } else { + if (ret == 0) { + char ismatch = 0; + /* parse event types for a specified type */ + /* etype param == 0xff means get any event */ + /* rdata[10] is sensor_type, rdata[11] is sensor_num */ + if ((etype == 0xff) || (etype == rdata[10])) ismatch++; + if ((snum == 0xff) || (snum == rdata[11])) ismatch++; + if (ismatch == 2) { + /*event sensor type matches*/ + memcpy(evt,rdata,rlen); + *stype = rdata[10]; /* return sensor type */ + } else { /* keep looking */ + do_wait(wait_interval); + continue; + } + } + /* if here, either got one, or need to return error */ + break; + } + } /*end for loop*/ + return(ret); +} + +int send_nmi(void) +{ + uchar idata[8]; + uchar rdata[30]; + int rlen; + uchar ccode; + int ret; + + idata[0] = 4; /* do NMI */ + rlen = sizeof(rdata); + ret = ipmi_cmdraw( CHASSIS_CTL, NETFN_CHAS, BMC_SA,PUBLIC_BUS,BMC_LUN, + idata,1, rdata,&rlen,&ccode, fdebug); + if (ret == 0 && ccode != 0) ret = ccode; + return(ret); +} + +void show_event(uchar *evt,char *obuf, int sz) +{ + int i; + char sysbuf[250]; + /* obuf should be 132 chars or more */ + + msgout("event data: "); + for (i=0; i<16; i++) msgout("%02x ",evt[i]); + msgout("\n"); + + decode_sel_entry(evt,obuf,sz); + msgout(obuf); /*writes to outfile*/ + /* write the message to syslog also. */ + snprintf(sysbuf,sizeof(sysbuf),"%s: %s",progname,obuf); + write_syslog(sysbuf); +} + +static void ievt_cleanup(void) +{ + char obuf[48]; + if (fselevts) syncevent_sel(sel_recid,sel_time); + snprintf(obuf,sizeof(obuf),"%s exiting.\n",progname); + msgout(obuf); + write_syslog(obuf); + free_sdr_cache(sdrs); + iclose(); + exit(EXIT_SUCCESS); +} + +#if defined(WIN32) | defined(DOS) +/* no daemon code */ +static void ievt_siginit(void) { return; } +#else +/* Linux daemon code */ +#include +static void ievt_sighnd(int sig) +{ + ievt_cleanup(); + exit(EXIT_SUCCESS); +} + +static void ievt_siginit(void); +static void ievt_siginit(void) +{ + struct sigaction sact; + + /* handle signals for cleanup */ + sact.sa_handler = ievt_sighnd; + sact.sa_flags = 0; + sigemptyset(&sact.sa_mask); + sigaction(SIGINT, &sact, NULL); + sigaction(SIGQUIT, &sact, NULL); + sigaction(SIGTERM, &sact, NULL); +} + +static int mkdaemon(int fchdir, int fclose); +static int mkdaemon(int fchdir, int fclose) +{ + int fdlimit = sysconf(_SC_OPEN_MAX); /*fdlimit usu = 1024.*/ + int fd = 0; + + + fdlimit = fileno(stderr); /*only close files up to stderr*/ + switch (fork()) { + case 0: break; + case -1: return -1; + default: _exit(0); /* exit the original process */ + } + if (setsid() < 0) return -1; /* shouldn't fail */ + switch (fork()) { + case 0: break; + case -1: return -1; + default: _exit(0); /* exit the original process */ + } + if (fchdir) { + chdir("/"); + /* umask(0022); * leave file creation mask at default (0022) & 0777 */ + } + if (fclose) { + /* Close stdin,stdout,stderr and replace them with /dev/null */ + for (fd = 0; fd < fdlimit; fd++) close(fd); + open("/dev/null",O_RDWR); + dup(0); dup(0); + } + return 0; +} +#endif + +static void iclose() +{ + /* close out any IPMI handles or sessions */ +#ifdef THREADS_OK +#ifdef WIN32 + if (threadid != NULL) CloseHandle(threadid); +#else + /* thread close not needed in Linux */ +#endif +#endif + ipmi_close_(); + if (fbackground && fdout != NULL) fclose(fdout); +} + +#ifdef METACOMMAND +int i_getevt(int argc, char **argv) +#else +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#endif +{ + int ret = 0; + int c, j; + uchar devrec[16]; + uchar event[16]; + uchar sa, lun; + uchar enables = 0; + uchar fevmsgok = 0; + uchar sensor_type = 0; + uchar msg_flags = 0; + FILE *fp; + char outbuf[160]; + char tmpout[20]; + char *sdesc; + + fdout = stdout; + msgout("%s ver %s\n", progname,progver); + + while ( (c = getopt(argc,argv,"abce:lmn:or:st:uvT:V:J:YEF:P:N:R:U:Z:x?")) != EOF ) + switch(c) { + case 'a': fAsync = 1; /* imb async message method */ + /* chenge the output log filename */ + sdesc = strstr(outfile,"evt.log"); + if (sdesc != NULL) strcpy(sdesc,"asy.log"); + break; + case 'b': fbackground = 1; break; /* background */ + case 'c': fcanonical = 1; break; /* canonical */ + case 'e': /* event sensor type */ + if (strncmp(optarg,"0x",2) == 0) + evt_stype = htoi(&optarg[2]); + else evt_stype = atob(optarg); + break; + case 'l': fAsyncNOP = 1; break; /* do not reset (for testing)*/ + case 'm': fmsgevts = 1; break; /* use local getmessage method */ + case 'n': /* event sensor num, always hex */ + if (strncmp(optarg,"0x",2) == 0) + evt_snum = htoi(&optarg[2]); + else evt_snum = htoi(&optarg[0]); + break; + case 'o': frunonce = 1; break; /* only run once for first event */ + case 'r': /* run script (or binary) on an event */ + run_script = optarg; + fp = fopen(run_script,"r"); + if (fp == NULL) { + printf("cannot open %s\n",run_script); + ret = ERR_FILE_OPEN; + goto do_exit; + } else { + fclose(fp); + frunscript = 1; + } + break; + case 's': fselevts = 1; break; /* use SEL event method*/ + case 't': timeout = atoi(optarg); fsettime = 1; break; /*timeout*/ + case 'u': futc = 1; break; + case 'x': fdebug = 1; break; /* debug messages */ + case 'v': fdebug = 3; break; /* verbose debug with lan */ + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'V': /* priv level */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + break; + default: + printf("Usage: %s [-abenorsux -t sec -NPRUEFTVY]\n", progname); + printf(" where -a use Async method\n"); + printf(" -b run in Background\n"); + printf(" -c use Canonical/delimited event format\n"); + printf(" -e T wait for specific event sensor type T\n"); + printf(" -n N wait for specific event sensor num N\n"); + printf(" -o run Once for the first event\n"); + printf(" -r F Run file F when an event occurs\n"); + printf(" -s use SEL event method\n"); + printf(" -t N set timeout to N seconds\n"); + printf(" -u use raw UTC time\n"); + printf(" -x show eXtra debug messages\n"); + print_lan_opt_usage(); + ret = ERR_USAGE; + goto do_exit; + } + + fipmilan = is_remote(); + ret = ipmi_getdeviceid(devrec,16,fdebug); + if (ret != 0) { + goto do_exit; + } else { + ipmi_maj = devrec[4] & 0x0f; + ipmi_min = devrec[4] >> 4; + show_devid( devrec[2], devrec[3], ipmi_maj, ipmi_min); + vend_id = devrec[6] + (devrec[7] << 8) + (devrec[8] << 16); + prod_id = devrec[9] + (devrec[10] << 8); + if (vend_id == VENDOR_INTEL) { + if (prod_id == 0x003E) /* NSN2U or CG2100 Urbanna */ + sms_sa = 0x41; + } + } + + /* get event receiver */ + ret = get_event_receiver(&sa ,&lun); + if (ret != 0) + msgout("event receiver error %d\n",ret); + else msgout("event receiver sa = %02x lun = %02x\n",sa,lun); + + ret = get_bmc_enables(&enables); + if (ret != 0) msgout("bmc enables error %d\n",ret); + else { + msgout("bmc enables = %02x\n",enables); + if ((enables & 0x02) == 2) fevmsgok = 1; + else fevmsgok = 0; + } + if (fevmsgok == 0 && !fipmilan) { + msgout("Event Message Buffers not enabled.\n"); + enables |= 0x0f; /* 0x08=SEL, 0x02=EvtMsgBuf, rest is gravy */ + ret = set_bmc_enables(enables); + if (ret != 0) { + msgout("set_bmc_enables error 0x%x\n",ret); + } + else msgout("set_bmc_enables success\n"); + } + if (fipmilan && !fselevts) { + msgout("Only the SEL method (-s) is supported over IPMI LAN\n"); + ret = LAN_ERR_NOTSUPPORT; + goto do_exit; + } + ret = get_msg_flags(&msg_flags); + msgout("igetevent reading sensors ...\n"); + write_syslog("igetevent reading sensors ...\n"); + ret = get_sdr_cache(&sdrs); + // if (!fipmilan) set_sel_opts(1,0, NULL,fdebug); + if (fdebug) msgout("get_sdr_cache ret = %d\n",ret); + if (ret == 0) set_sel_opts(1, fcanonical, sdrs,fdebug,futc); + else ret = 0; /*if error, keep going anyway*/ + + if (fselevts) { +#ifdef WIN32 + { /*resolve path of idxfile*/ + char *ipath; + ipath = getenv("ipmiutildir"); /*ipmiutil directory path*/ + if (ipath != NULL) { + if (strlen(ipath)+12 < sizeof(idxfile)) { + sprintf(idxfile,"%s\\%s",ipath,"\\",IDXFILE); + } + } + } +#endif + + if (fipmilan) { + char *node; + node = get_nodename(); + strcat(idxfile,"-"); + strcat(idxfile,node); + strcat(idxfile2,"-"); + strcat(idxfile2,node); + strcat(outfile,"-"); + strcat(outfile,node); + } + ret = startevent_sel(&sel_recid,&sel_time); + ret = 0; /*ignore any earlier errors, keep going*/ + } + + drvtype = get_driver_type(); + if (fdebug) msgout("driver_type = %d (%s)\n", + drvtype,show_driver_type(drvtype)); + + if (evt_stype == 0xFF) sdesc = "any event"; + else sdesc = get_sensor_type_desc(evt_stype); + if (evt_snum == 0xFF) tmpout[0] = 0; + else sprintf(tmpout,"with snum %02x",evt_snum); + if (evt_stype != 0xFF || evt_snum != 0xFF) + msgout("Look for event sensor type %02x (%s) %s\n", evt_stype,sdesc,tmpout); + +#ifdef TEST_SEL + /* This is used to verify that the interface returns valid next ids, + * and that the get_sel_entry is ok. */ + { + int i; + ushort r, r1, r2; + uchar rec[40]; + int rv; + r = 0; + for (i = 0; i < 4; i++) + { + rv = get_sel_entry(r,&r2,rec); + if (rv == 0) { + r1 = rec[0] + (rec[1] << 8); /*get current rec id*/ + if (fdebug) msgout("get_sel: r=%x r1=%x rnext=%x\n",r,r1,r2); + show_event(&rec[0],outbuf,sizeof(outbuf)); + r = r2; + } else break; + } + } +#endif + if (drvtype == DRV_IMB) fAsyncOK = 1; + else if (drvtype == DRV_MV) { + if (fsettime == 0) timeout = 0; /*DRV_MV default to infinite*/ + fAsyncOK = 1; + } else fAsyncOK = 0; + + if (fAsync && (!fAsyncOK)) { + msgout("Cannot open %s or %s driver, required for -a\n", + show_driver_type(DRV_IMB),show_driver_type(DRV_MV)); + ret = ERR_NO_DRV; + goto do_exit; + } + + if (fbackground) { /* convert to a daemon if background */ +#ifdef WIN32 + msgout("Background not implemented for Windows\n"); + ret = LAN_ERR_NOTSUPPORT; + goto do_exit; +#elif defined(DOS) + msgout("Background not implemented for DOS\n"); + ret = LAN_ERR_NOTSUPPORT; + goto do_exit; +#else + /* make sure we can open the log file before doing mkdaemon */ + fdout = fopen(outfile,"a"); + if (fdout == NULL) + printf("%s: Cannot open %s\n", progname,outfile); + else { + pid_t p; + fclose(fdout); + + ret = mkdaemon(1,1); + if (ret != 0) { + msgout("%s: Cannot become daemon, ret = %d\n", progname,ret); + goto do_exit; + } + /* open a log file for messages, set fdout */ + fdout = fopen(outfile,"a"); +#ifdef METACOMMAND + /* make sure driver debug also goes to log */ + fpdbg = fdout; + fperr = fdout; +#endif + p = getpid(); + msgout("PID %d: %s ver %s\n",p,progname,progver); /*log start message*/ + } +#endif + } + ievt_siginit(); + + if (fAsync && (fAsyncOK)) /*use imb/mv async messages*/ + { + msgout("Wait for an async event\n"); /* no timeout */ + if (drvtype == DRV_IMB) + { +#ifdef DO_ASYNC +#ifdef THREADS_OK +#ifdef WIN32 + /* Windows threads */ + threadid = CreateThread(NULL, 0, &pollThread, NULL, 0, NULL); + if (threadid == NULL) pollThread(NULL); +#else + /* Linux threads */ + ret = pthread_create( &threadid, NULL, pollThread, (void*) message); + // if (ret == 0) pthread_join( threadid, NULL); + // if (ret == 0) pthread_detach( threadid); +#endif + if (fdebug) msgout("pollThread create ret=%d handle=%x\n",ret,threadid); +#else + /* no threads */ + pollThread(NULL); +#endif + while (ret == 0) + { /*wait for imb message events*/ + msgout("Waiting %d seconds for an async event ...\n",timeout); + ret = get_imb_event(0xff,timeout,event); + if (ret == 0x81) { /*ok, shutting down OS*/ + ret = 0; + break; + } + if (frunonce) break; + if (timeout == 0 && ret == 0x80) { /*0x80 = no data yet */ + if (fdebug) msgout("get_event timeout, no event yet.\n"); + do_wait(wait_interval); + ret = 0; /*ok, keep going*/ + } + } +#endif + } /*endif DRV_IMB*/ +#ifdef DO_MVL + else { /*DRV_MV*/ + int stage; + stage = 0; + while (stage < 3) + { /*wait for mv message events*/ + if (fdebug) msgout("Waiting for async_mv event, stage %d\n",stage); + if (stage == 0) { + ret = get_mv_asy_event(CMD_GET_SOFTWARE_ID,timeout,event); + if (fdebug) msgout("got SmsOS GetSWID event ret = %d\n",ret); + /* send a reply */ + if (ret == 0) ret = send_mv_asy_resp(event); + if (ret == 0) stage = 1; /* got the SoftwareID request/response */ + else stage = 0; + } + if (stage == 1) { + /* get the reset command */ + memset(event,0,sizeof(event)); + ret = get_mv_asy_event(CMD_SMS_OS_REQUEST,timeout,event); + if (fdebug) msgout("got SmsOS GetSmsOS event ret = %d\n",ret); + if (ret == 0) ret = send_mv_asy_resp(event); + if (ret == 0) stage = 2; + else stage = 0; + } + if (stage == 2) { /* got the SmsOs request in event */ + uchar cmd, func; + cmd = event[2]; + func = event[3]; + if (cmd != CMD_SMS_OS_REQUEST) { /*cmd*/ + ret = LAN_ERR_INVPARAM; + if (fdebug) msgout("SmsOS cmd %x ret = %d\n",cmd,ret); + } else { + if (frunscript) { + write_syslog("igetevent -a running script\n"); + ret = system(run_script); + if (fdebug) msgout("run(%s) ret = %d\n",run_script,ret); + } + if (!fAsyncNOP) + switch(func) { /*subfunction*/ + case 0x01: /*shutdown & power down*/ + write_syslog("igetevent -a OS shutdown\n"); + ret = system(SHUTDOWN_CMD); + msgout("SmsOs shutdown, ret = %d\n",ret); + break; + case 0x02: /*shutdown & reboot*/ + write_syslog("igetevent -a OS reboot\n"); + ret = system(REBOOT_CMD); + msgout("SmsOs reboot, ret = %d\n",ret); + break; + case 0x03: /*send NMI locally*/ + write_syslog("igetevent -a NMI\n"); + ret = send_nmi(); + msgout("SmsOs NMI, ret = %d\n",ret); + default: + ret = LAN_ERR_INVPARAM; + msgout("SmsOS func %02x, ret = %d\n",func,ret); + break; + } + } + if (ret == 0) stage = 3; /*done, exit loop*/ + else { + if (fdebug) msgout("SmsOS error = %d, start over\n",ret); + stage = 0; /*start over*/ + } + } /*endif stage 2*/ + } /*end-while*/ + } /*end else DRV_MV*/ +#endif + + } else { /*not Async, std IPMI events */ + if (fselevts) { + msgout("Get IPMI SEL events after ID %04x\n",sel_recid); + } else + msgout("Get IPMI events from %s driver\n",show_driver_type(drvtype)); + j = get_evt_method(tmpout); + sprintf(outbuf,"igetevent waiting for events via method %d (%s)\n", + j, tmpout); + msgout(outbuf); + write_syslog(outbuf); + + /* loop on events here, like a daemon would. */ + while (ret == 0) + { /*wait for bmc message events*/ + msgout("Waiting %d seconds for an event ...\n",timeout); + /* note: could also get message flags here */ + ret = get_event(evt_stype,evt_snum,timeout,event,&sensor_type); + if (fdebug) msgout("get_event ret = %d\n",ret); + if (ret == 0) { /* got an event successfully */ + msgout("got event id %04x, sensor_type = %02x\n", + sel_recid, sensor_type); + show_event(event,outbuf,sizeof(outbuf)); + if (fselevts) syncevent_sel(sel_recid,sel_time); + if (frunscript) { /*run some script for each event*/ + char run_cmd[256]; + sprintf(run_cmd,"%s \"%s\"\n",run_script,outbuf); + j = system(run_cmd); + msgout("run(%s $1), ret = %d\n",run_script,j); + ret = j; /*if that failed, exit loop*/ + } + } else { + if (ret == 0x80) msgout("get_event timeout\n"); + else msgout("get_event error: ret = 0x%x\n",ret); + } + if (frunonce) break; + if (timeout == 0 && ret == 0x80) { /*0x80 = no data yet */ + if (fdebug) msgout("get_event timeout, no data yet.\n"); + do_wait(wait_interval); + ret = 0; /*ok, keep going*/ + } + } /*end while loop*/ + } + +do_exit: + ievt_cleanup(); + if (ret == 0x80) ret = 0; + // show_outcome(progname,ret); /*inert if background*/ + return(ret); +} /* end main()*/ + +/* end getevent.c */ diff --git a/util/ihealth.c b/util/ihealth.c new file mode 100644 index 0000000..6f6f0e1 --- /dev/null +++ b/util/ihealth.c @@ -0,0 +1,1153 @@ +/* + * ihealth.c (was bmchealth.c) + * + * This tool checks the health of the BMC via IPMI. + * + * Author: Andy Cress arcress at users.sourceforge.net + * Copyright (c) 2006 Intel Corporation. + * Copyright (c) 2009 Kontron America, Inc. + * + * 03/22/06 Andy Cress - created + * 06/20/06 Andy Cress 0.6 - more vendor strings, add ping_node() stub for now + * 10/20/06 Andy Cress 1.1 - added -g for guid + * 01/10/07 Andy Cress 1.4 - added product strings + * 02/25/07 Andy Cress 2.8 - added more Chassis Status decoding + */ +/*M* +Copyright (c) 2006, Intel Corporation +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions 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. + c.. Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ +#ifdef WIN32 +#include +#include +#include +#include "getopt.h" +#elif defined(DOS) +#include +#include +#include +#include "getopt.h" +#else +#include +#include +#include +#include +#include +#if defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include +#else +#include +#endif +#endif +#include +#include "ipmicmd.h" +#include "oem_intel.h" + +#define SELFTEST_STATUS 0x04 +#define GET_POWER_STATE 0x07 +extern int get_BiosVersion(char *str); +extern int get_SystemGuid(uchar *guid); +extern int GetSDR(int id, int *next, uchar *recdata, int srecdata, int *rlen); +extern int get_device_guid(char *pbuf, int *sz); /*subs.c*/ +extern int oem_supermicro_get_health(char *pstr, int sz); /*oem_supermicro.c*/ +extern int oem_supermicro_get_firmware_str(char *pstr, int sz); /*oem_supermicro.c*/ + +/* + * Global variables + */ +static char * progname = "ihealth"; +static char * progver = "2.93"; +static char fdebug = 0; +static char fipmilan = 0; +static char fcanonical = 0; +static char do_hsc = 0; +static char do_me = 0; +static char do_frusdr = 0; +static char do_guid = 0; +static char do_powerstate = 1; +static char do_lanstats = 0; +static char do_session = 0; +static char do_systeminfo = 0; +static char set_restore = 0; +static char set_name = 0; +static char set_os = 0; +static char set_os2 = 0; +static uchar restore_policy = 0; +static uchar bChan = 0x0e; +static char fmBMC = 0; +static char bdelim = '='; /*delimiter to separate name/value pairs*/ +static char bcomma = ','; /*comma delimiter, may change if CSV*/ +static char lan_ch_restrict = 0; +static int kcs_loops = 0; +static int vend_id = 0; +static int prod_id = 0; +static char *pname = NULL; +static char *pos = NULL; +static char *pos2 = NULL; +static uchar g_bus = PUBLIC_BUS; +static uchar g_sa = BMC_SA; +static uchar g_lun = BMC_LUN; +static uchar g_addrtype = ADDR_SMI; + + +int oem_get_health(char *pstr, int sz) +{ + int rv; + switch(vend_id) { + case VENDOR_PEPPERCON: + case VENDOR_SUPERMICRO: + rv = oem_supermicro_get_health(pstr, sz); + break; + case VENDOR_SUPERMICROX: + rv = oem_supermicro_get_firmware_str(pstr,sz); + break; + default: + rv = LAN_ERR_NOTSUPPORT; + break; + } + if (fdebug) printf("oem_get_health rv = %d\n",rv); + return rv; +} + +int get_lan_stats(uchar chan) +{ + uchar idata[2]; + uchar rdata[20]; + int rlen, rv; + uchar cc; + ushort *rw; + + /* get BMC LAN Statistics */ + idata[0] = chan; + idata[1] = 0x00; /*do not clear stats*/ + rlen = sizeof(rdata); + rv = ipmi_cmd(GET_LAN_STATS, idata,2, rdata,&rlen, &cc, fdebug); + if (fdebug) printf("get_lan_stats: rv = %d, cc = %02x\n",rv,cc); + if (rv == 0) { + if (cc == 0) { /*success, show BMC LAN stats*/ + rw = (ushort *)&rdata[0]; + printf("IPMI LAN channel %d statistics: \n",chan); + printf(" \tReceived IP Packets %c %d\n",bdelim,rw[0]); + printf(" \tRecvd IP Header errors %c %d\n",bdelim,rw[1]); + printf(" \tRecvd IP Address errors %c %d\n",bdelim,rw[2]); + printf(" \tRecvd IP Fragments %c %d\n",bdelim,rw[3]); + printf(" \tTransmitted IP Packets %c %d\n",bdelim,rw[4]); + printf(" \tReceived UDP Packets %c %d\n",bdelim,rw[5]); + printf(" \tReceived Valid RMCP Pkts %c %d\n",bdelim,rw[6]); + printf(" \tReceived UDP Proxy Pkts %c %d\n",bdelim,rw[7]); + printf(" \tDropped UDP Proxy Pkts %c %d\n",bdelim,rw[8]); + } else if (cc == 0xc1) { + printf("IPMI LAN channel %d statistics: not supported\n",chan); + } + } + return(rv); +} + +int get_session_info(uchar idx, int hnd, uchar *rdata, int *len) +{ + uchar idata[5]; + int ilen, rlen, rv; + uchar cc; + + ilen = 1; + idata[0] = idx; + if (idx == 0xFE) { + idata[1] = (uchar)hnd; + ilen = 2; + } else if (idx == 0xFF) { + idata[1] = (uchar)(hnd & 0x000000FF); + idata[2] = (uchar)((hnd & 0x0000FF00) >> 8); + idata[3] = (uchar)((hnd & 0x00FF0000) >> 16); + idata[4] = (uchar)((hnd & 0xFF000000) >> 24); + ilen = 5; + } + rlen = *len; + *len = 0; + rv = ipmi_cmdraw(CMD_GET_SESSION_INFO,NETFN_APP, + g_sa, g_bus, g_lun, + idata,ilen, rdata,&rlen,&cc, fdebug); + if (fdebug) printf("get_lan_stats: rv = %d, cc = %02x\n",rv,cc); + if (rv == 0) *len = rlen; + if ((rv == 0) && (cc != 0)) rv = cc; + return(rv); +} + +static char *sesstype_str(uchar c) +{ + uchar b; + char *s; + b = ((c & 0xf0) >> 4); + switch(b) { + case 0: s = "IPMIv1.5"; break; + case 1: s = "IPMIv2/RMCP+"; break; + default: s = "Other"; break; + } + return s; +} + +static void show_session_info(uchar idx, uchar *sinfo,int len) +{ + int i; + char lan_type = 1; + if (fdebug) { + printf("Raw Session Info[%d]: ",idx); + for (i = 0; i < len; i++) printf("%02x ",sinfo[i]); + printf("\n"); + } + + printf("Session Info[%d]:\n",idx); + printf("\tSession Handle %c %d\n",bdelim,sinfo[0]); + printf("\tSession Slot Count %c %d\n",bdelim,(sinfo[1] & 0x3f)); + printf("\tActive Sessions %c %d\n",bdelim,(sinfo[2] & 0x3f)); + if (len <= 3) return; + printf("\tUser ID %c %d\n",bdelim,(sinfo[3] & 0x3f)); + printf("\tPrivilege Level %c %d\n",bdelim,(sinfo[4] & 0x0f)); + printf("\tSession Type %c %s\n",bdelim,sesstype_str(sinfo[5])); + printf("\tChannel Number %c %d\n",bdelim,(sinfo[5] & 0x0f)); + if (len <= 6) return; + if (lan_type) { + printf("\tConsole IP %c %d.%d.%d.%d\n",bdelim, + sinfo[6],sinfo[7],sinfo[8],sinfo[9]); + printf("\tConsole MAC %c %02x:%02x:%02x:%02x:%02x:%02x\n",bdelim, + sinfo[10], sinfo[11], sinfo[12], + sinfo[13], sinfo[14], sinfo[15]); + printf("\tConsole Port %c %d\n",bdelim, + sinfo[16]+ (sinfo[17] << 8)); + } +} + +int get_session_info_all(void) +{ + int rv, len, nslots, i; + uchar sinfo[24]; + nslots = 1; + for (i = 1; i <= nslots; i++) { + len = sizeof(sinfo); + rv = get_session_info(i,0,sinfo,&len); + if (fdebug) printf("get_session_info(%d): rv = %d\n",i,rv); + if (rv != 0) { + if ((rv == 0xCB) || (rv == 0xCC)) { + if (len >= 3) show_session_info(i,sinfo,len); + if (i > 1) rv = 0; /*no such idx, end */ + } + break; + } + nslots = (sinfo[1] & 0x3F); + show_session_info(i,sinfo,len); + } + return(rv); +} + +static int get_selftest_status(uchar *rdata, int rlen) +{ + uchar idata[4]; + uchar ccode; + int ret; + + ret = ipmi_cmdraw( SELFTEST_STATUS, NETFN_APP, + g_sa, g_bus, g_lun, + idata,0, rdata,&rlen,&ccode, fdebug); + if (ret == 0 && ccode != 0) ret = ccode; + return(ret); +} /*end get_selftest_status()*/ + +static int get_last_selftest(uchar *val, int vlen) +{ + uchar idata[4]; + uchar rdata[16]; + int rlen; + uchar ccode; + int ret; + + if (val == NULL) return(ERR_BAD_PARAM); + idata[0] = 0; /*0=first, 1=next*/ + memset(rdata,0xFF,2); /*initial value = end-of-list*/ + rlen = sizeof(rdata); + ret = ipmi_cmdraw( 0x16, 0x30, g_sa, g_bus, g_lun, + idata,1, rdata,&rlen,&ccode, fdebug); + if (ret == 0 && ccode != 0) ret = ccode; + if (ret == 0) { + if (rlen <= 0) ret = LAN_ERR_BADLENGTH; + else { + if (rlen > vlen) rlen = vlen; /*truncate if too long*/ + memcpy(val,rdata,rlen); + } + } + return(ret); +} + +static int get_chassis_status(uchar *rdata, int *rsz) +{ + uchar idata[4]; + uchar ccode; + int rlen; + int ret; + + rlen = *rsz; + ret = ipmi_cmdraw( CHASSIS_STATUS, NETFN_CHAS, + g_sa, g_bus, g_lun, + idata,0, rdata,&rlen,&ccode, fdebug); + if (ret == 0 && ccode != 0) ret = ccode; + if (ret == 0) *rsz = rlen; + return(ret); +} /*end chassis_status()*/ + +static void show_chs_status(uchar *sbuf, int slen) +{ + char chs_strbuf[80]; + char *pstr; + uchar state, b2, b3, b4; + + pstr = &chs_strbuf[0]; + state = sbuf[0] & 0x7f; + b2 = sbuf[1]; + b3 = sbuf[2]; + sprintf(pstr,"%s",(state & 0x01) ? "on" : "off"); + printf("Chassis Status %c %02x %02x %02x %02x (%s, see below)\n", + bdelim,state,sbuf[1],sbuf[2],sbuf[3],pstr); + sprintf(pstr,"\tchassis_power %c ",bdelim); + if (state & 0x01) strcat(pstr,"on"); + else strcat(pstr,"off"); + if (state & 0x02) strcat(pstr,", overload"); + if (state & 0x04) strcat(pstr,", interlock"); + if (state & 0x08) strcat(pstr,", fault"); + if (state & 0x10) strcat(pstr,", control error"); + printf("%s\n",pstr); + + sprintf(pstr,"\tpwr_restore_policy %c ",bdelim); + if (state & 0x20) strcat(pstr,"last_state"); + else if (state & 0x40) strcat(pstr,"turn_on"); + else strcat(pstr,"stay_off"); + printf("%s\n",pstr); + + if (b2 != 0) { + sprintf(pstr,"\tlast_power_event %c ",bdelim); + if (b2 & 0x10) strcat(pstr,"IPMI "); + if (b2 & 0x08) strcat(pstr,"fault "); + if (b2 & 0x04) strcat(pstr,"interlock "); + if (b2 & 0x02) strcat(pstr,"overload "); + if (b2 & 0x01) strcat(pstr,"ACfailed"); + printf("%s\n",pstr); + } + printf("\tchassis_intrusion %c %s\n", bdelim, + (b3 & 0x01) ? "active":"inactive"); + printf("\tfront_panel_lockout %c %s\n", bdelim, + (b3 & 0x02) ? "active":"inactive"); + printf("\tdrive_fault %c %s\n", bdelim, + (b3 & 0x04) ? "true":"false"); + printf("\tcooling_fan_fault %c %s\n", bdelim, + (b3 & 0x08) ? "true":"false"); + if (slen > 3) { + b4 = sbuf[3]; + if (b4 & 0x80) { + printf("\tFP sleep_button_disable %c allowed, button %s\n",bdelim, + (b4 & 0x08) ? "disabled":"enabled"); + } + if (b4 & 0x40) { + printf("\tFP diag_button_disable %c allowed, button %s\n",bdelim, + (b4 & 0x04) ? "disabled":"enabled"); + } + if (b4 & 0x20) { + printf("\tFP reset_button_disable %c allowed, button %s\n",bdelim, + (b4 & 0x02) ? "disabled":"enabled"); + } + if (b4 & 0x10) { + printf("\tFP power_button_disable %c allowed, button %s\n",bdelim, + (b4 & 0x01) ? "disabled":"enabled"); + } + } + return; +} + +static int get_power_state(uchar *rdata, int rlen) +{ + uchar idata[4]; + uchar ccode; + int ret; + + ret = ipmi_cmdraw( GET_POWER_STATE, NETFN_APP, + g_sa, g_bus, g_lun, + idata,0, rdata,&rlen,&ccode, fdebug); + if (ret == 0 && ccode != 0) ret = ccode; + return(ret); +} /*end get_power_state()*/ + +static char *pwr_string(uchar pstate) +{ + char *pstr; + switch(pstate) { + case 0x00: pstr = "S0: working"; break; + case 0x01: pstr = "S1: clock stopped, context ok"; break; + case 0x02: pstr = "S2: clock stopped, context lost"; break; + case 0x03: pstr = "S3: suspend-to-RAM"; break; + case 0x04: pstr = "S4: suspend-to-Disk"; break; + case 0x05: pstr = "S5: soft off"; break; + case 0x06: pstr = "S4/S5: soft off, either S4 or S5"; break; + case 0x07: pstr = "G3: mechanical off"; break; + case 0x08: pstr = "S1-S3: sleeping"; break; + case 0x09: pstr = "S1-S4: sleeping"; break; + case 0x0A: pstr = "S5/o: soft off by override"; break; + case 0x20: pstr = "legacy on"; break; + case 0x21: pstr = "legacy soft-off"; break; + case 0x2a: /* not initialized or device lost track of state */ + default: pstr = "unknown"; break; + } + return(pstr); +} + +#ifdef PING_OK +extern int ping_bmc(char *node, char fdebug); + +static int ping_node(char *node) +{ + int rv = 0; + /* verify that the BMC LAN channel is configured & active */ + /* send rmcp_ping to node's BMC */ + rv = ping_bmc(node,fdebug); + return(rv); +} +#endif + +#define MIN_SDR_SZ 8 +static int get_frusdr_version(char *pver, int sver) +{ + ushort recid; + int recnext; + int ret, sz, i, len; + uchar sdr[MAX_BUFFER_SIZE]; + char verstr[30]; + char fIntel; + int verlen; + + recid = 0; + verstr[0] = 0; + verlen = 0; + while (recid != 0xffff) + { + memset(sdr,0,sizeof(sdr)); + ret = GetSDR(recid,&recnext,sdr,sizeof(sdr),&sz); + if (fdebug) + printf("GetSDR[%04x]: ret = %x, next=%x\n",recid,ret,recnext); + if (ret != 0) { + if (ret > 0) { /* ret is a completion code error */ + if (fdebug) + printf("%04x GetSDR error 0x%02x %s, rlen=%d\n",recid,ret, + decode_cc((ushort)0,(uchar)ret),sz); + } else printf("%04x GetSDR error %d, rlen = %d\n", recid,ret,sz); + if (sz < MIN_SDR_SZ) { /* don't have recnext, so abort */ + break; + } /* else fall through & continue */ + } else { /*got SDR */ + len = sdr[4] + 5; + if (sdr[3] == 0xC0) { /* OEM SDR */ + /* check for Intel mfg id */ + if ((sdr[5] == 0x57) && (sdr[6] == 0x01) && (sdr[7] == 0x00)) + fIntel = 1; + else fIntel = 0; + if (sdr[8] == 0x53) { /*Intel OEM subtype, ASCII 'S' */ + verlen = 0; + for (i = 8; i < len; i++) { + if (sdr[i] == 0) break; + if (i >= sizeof(verstr)) break; + verstr[verlen++] = sdr[i]; + } + verstr[verlen] = 0; /*stringify*/ + /* continue on past SDR File, get SDR Package version */ + // break; + } + } /*endif OEM SDR*/ + } + if (recnext == recid) recid = 0xffff; /*break;*/ + else recid = (ushort)recnext; + } + if (verlen > sver) verlen = sver; + if (fdebug) + printf("get_frusdr_version: verstr=%s, verlen=%d\n",verstr,verlen); + strncpy(pver,verstr,verlen); + return(ret); +} + +static int get_hsc_devid(uchar *rdata, int rlen) +{ + uchar ccode; + int ret; + + ret = ipmi_cmdraw( 0x01, /*(GET_DEVICEID & 0x00ff)*/ + NETFN_APP, 0xC0,PUBLIC_BUS,BMC_LUN, + NULL,0, rdata,&rlen,&ccode, fdebug); + if (ret == 0 && ccode != 0) ret = ccode; + return(ret); +} /*end get_hsc_devid*/ + +static int get_chan_auth(uchar chan, uchar *rdata, int rlen) +{ + uchar idata[4]; + uchar ccode; + int ret; + + idata[0] = chan; /*0x0e = this channel*/ + idata[1] = 0x02; /*priv level = user*/ + ret = ipmi_cmdraw( 0x38, NETFN_APP, /*CMD_GET_CHAN_AUTH_CAP*/ + g_sa, g_bus, g_lun, + idata,2, rdata,&rlen,&ccode, fdebug); + if (ret == 0 && ccode != 0) ret = ccode; + return(ret); +} /*end get_chan_auth*/ + +void show_chan_auth(char *tag, uchar *rec, int srec) +{ + char pstr[40]; + pstr[0] = 0; + if (rec[1] & 0x01) strcat(pstr,"None "); + if (rec[1] & 0x02) strcat(pstr,"MD2 "); + if (rec[1] & 0x04) strcat(pstr,"MD5 "); + if (rec[1] & 0x10) strcat(pstr,"Straight_Passwd "); + if (rec[1] & 0x20) strcat(pstr,"OEM "); + printf("Chan %d AuthTypes %c %s\n",rec[0],bdelim,pstr); + if (do_hsc) /*only show this if extra output*/ + printf("Chan %d Status %c %02x, OEM ID %02x%02x%02x OEM Aux %02x\n", + rec[0],bdelim,rec[2],rec[4],rec[5],rec[6],rec[7]); +} + +#define BMC 1 +#define HSC 2 + +#ifdef MOVED +/* moved to subs.c*/ +#define N_MFG 41 +struct { int val; char *pstr; } mfgs[N_MFG] = { }; +char * get_iana_str(int mfg); +#endif + +char * get_mfg_str(uchar *rgmfg, int *pmfg) +{ + char *mfgstr = ""; + int mfg; + mfg = rgmfg[0] + (rgmfg[1] << 8) + (rgmfg[2] << 16); + if (pmfg != NULL) *pmfg = mfg; /*vend_id*/ + mfgstr = get_iana_str(mfg); + return(mfgstr); +} + +/* int get_system_info(uchar parm, char *pbuf, int *szbuf); *see subs.c*/ +/* int set_system_info(uchar parm, uchar *pbuf, int *szbuf); *see subs.c*/ + +void show_devid_all(int dtype, uchar *devrec, int sdevrec) +{ + uchar ipmi_maj = 0; + uchar ipmi_min = 0; + char *tag; + int mfg, prod; + char *mfgstr = ""; + char *prodstr = ""; + char prodoem[40]; + char extraver[32]; + int i, j, k, l, rv; + + ipmi_maj = devrec[4] & 0x0f; + ipmi_min = devrec[4] >> 4; + prod = devrec[9] + (devrec[10] << 8); + mfgstr = get_mfg_str(&devrec[6],&mfg); + vend_id = mfg; + prod_id = prod; + extraver[0] = 0; + if (dtype == HSC) tag = "HSC"; + else { + tag = "BMC"; + /* The product ids below only apply to BMCs */ + switch(mfg) { + case VENDOR_NSC: /*=0x000322*/ + fmBMC = 1; + if (dtype == BMC) tag="mBMC"; + if (prod == 0x4311) prodstr = "(TIGPT1U)"; /*Intel*/ + break; + case VENDOR_SUN: /*=0x00002a*/ + if (prod == 0x4701) prodstr = "(X4140)"; + break; + case VENDOR_TYAN: /*=0x0019fd*/ + switch(prod) { /* show product names for some */ + case 0x0b41: prodstr = "(M3289)"; break; + case 0x0f98: prodstr = "(M3291)"; break; + case 0x137d: prodstr = "(S4989)"; break; + case 0x13ee: prodstr = "(S5102)"; break; + case 0x14fc: prodstr = "(S5372)"; break; + default: prodstr = ""; break; + } + break; + case VENDOR_FUJITSU: /*=0x002880*/ + if (prod >= 0x200) prodstr = "(iRMC S2)"; + else prodstr = ""; + break; + case VENDOR_CISCO: /*=0x00168b*/ + if (prod == 0x0005) prodstr = "(UCS C200)"; + else prodstr = ""; + if (fipmilan) lan_ch_restrict = 1; /*fw bug, gets 0xC1 on ipmilan*/ + break; + case VENDOR_INTEL: /*=0x000157*/ + if (do_hsc && (dtype == BMC)) /*if HSC option, also show extra*/ + sprintf(extraver," (Boot %x.%x PIA %x.%x)", /*BMC extra*/ + devrec[11],devrec[12],devrec[13],devrec[14]); + switch(prod) { /* show product names for some */ + case 0x000C: prodstr = "(TSRLT2)"; /*SCB2*/ + bChan = 7; break; + case 0x001B: prodstr = "(TIGPR2U)"; /*SWV2*/ + bChan = 7; break; + case 0x0022: prodstr = "(TIGI2U)"; break; /*SJR2*/ + case 0x0026: prodstr = "(Bridgeport)"; break; + case 0x0028: prodstr = "(S5000PAL)"; break; /*Alcolu*/ + case 0x0029: prodstr = "(S5000PSL)"; break; /*StarLake*/ + case 0x002B: prodstr = "(S5000VSA)"; break; + case 0x002D: prodstr = "(MFSYS25)"; break; /*ClearBay*/ + case 0x003E: prodstr = "(S5520UR)"; /*CG2100 or NSN2U*/ + do_me = 1; kcs_loops = URNLOOPS; + bChan = 1; break; + case 0x0040: prodstr = "(QSSC-S4R)"; /*Stoutland*/ + do_me = 1; kcs_loops = URNLOOPS; + bChan = 1; break; + case 0x0100: prodstr = "(Tiger4)"; break; + case 0x0103: prodstr = "(McCarran)"; /*BladeCenter*/ + do_powerstate = 0; break; + case 0x0800: prodstr = "(ZT5504)"; /*ZiaTech*/ + do_powerstate = 0; break; + case 0x0808: prodstr = "(MPCBL0001)"; /*ATCA Blade*/ + do_powerstate = 0; break; + case 0x0841: prodstr = "(MPCMM0001)"; /*ATCA CMM*/ + do_powerstate = 0; break; + case 0x0811: prodstr = "(TIGW1U)"; break; /*S5000PHB*/ + case 0x4311: prodstr = "(NSI2U)"; /*SE7520JR23*/ + if (dtype == BMC) tag="mBMC"; + fmBMC = 1; break; + default: prodstr = ""; break; + } + if (is_romley(mfg,prod)) { + intel_romley_desc(mfg,prod,&prodstr); + snprintf(prodoem,sizeof(prodoem),"(%s)",prodstr); + prodstr = prodoem; + do_me = 1; kcs_loops = URNLOOPS; + do_hsc = 1; /*the HSC is embedded, so not the same*/ + sprintf(extraver,".%d (Boot %x.%x)", /*BMC extra*/ + (devrec[13] + (devrec[14] << 8)),devrec[11],devrec[12]); + } + break; + case VENDOR_KONTRON: /*=0x003A98=15000.*/ + i = devrec[11] + (devrec[12] << 8); + j = devrec[13] + (devrec[14] << 8); + k = 0; l = 0; + { /* get Kontron firmware version with OEM cmd */ + int rlen; + uchar idata[4]; + uchar rdata[16]; + uchar cc; + rlen = sizeof(rdata); + idata[0] = 0; + idata[1] = 0; + idata[2] = 1; + rv = ipmi_cmdraw(0x2f, 0x2c, g_sa, g_bus, g_lun, + idata,3,rdata,&rlen,&cc,fdebug); + if (rv == 0 && cc == 0) { + k = rdata[1]; + l = rdata[2]; + } + } + sprintf(extraver,".%02d.%02d (FW %x.%x)",i,j,k,l); + switch(prod) { /* show product names for some */ + case 0x1590: prodstr = "(KTC5520)"; break; + default: prodstr = ""; break; + } + break; + case VENDOR_PEPPERCON: /*=0x0028c5 Peppercon/Raritan */ + if (prod == 0x0004) prodstr = "(AOC-IPMI20)"; /*SuperMicro*/ + else if (prod == 0x0007) prodstr = "(RMM2)"; /*Intel RMM2*/ + break; + case VENDOR_HP: /*=0x00000B*/ + switch(prod) { /* show product names for some */ + case 0x2000: prodstr = "(Proliant ML/DL)"; break; /*DL380*/ + case 0x2020: prodstr = "(Proliant BL)"; break; + default: if ((prod & 0xff00) == 0x8300) + prodstr = "(Proliant SL)"; + else prodstr = ""; + break; + } + do_powerstate = 0; /*HP does not support get_power_state cmd*/ + break; + case VENDOR_DELL: /*=0x0002A2*/ + switch(prod) { /* show product names for some */ + case 0x0100: prodstr = "(PE R610)"; break; + default: prodstr = ""; break; + } + break; + case VENDOR_MAGNUM: /* =5593. used by SuperMicro*/ + switch(prod) { /* show product names for some */ + case 6: prodstr = "(X8DTL)"; break; + default: prodstr = ""; break; + } + break; + case VENDOR_SUPERMICRO: /* =10876. used by SuperMicro*/ + case VENDOR_SUPERMICROX: /* =47488. used by Winbond/SuperMicro*/ + switch(prod) { /* decode some SuperMicro product ids */ + case 4: prodstr = "(X7DBR)"; break; + case 6: prodstr = "(X8DTL)"; break; + case 1037: prodstr = "(X8SIE)"; break; + case 1541: prodstr = "(X8SIL)"; break; + case 1547: prodstr = "(X8SIA)"; break; /*0x060b*/ + case 1549: prodstr = "(X8DTU)"; break; + case 1551: prodstr = "(X8DTN)"; break; + case 1562: prodstr = "(X8SIU-F)"; break; /*0x061a*/ + case 1572: prodstr = "(X9SCM)"; break; /*or X9SCL*/ + case 1576: prodstr = "(X9DRi)"; break; + case 1585: prodstr = "(X9SCA)"; break; + case 1603: prodstr = "(X9SPU)"; break; /*0x0643*/ + case 1643: prodstr = "(X9SRL)"; break; /*0x066b*/ + case 1797: prodstr = "(X9DR7)"; break; /*0x0705*/ + case 43025: prodstr = "(H8DGU)"; break; + case 43707: prodstr = "(X8DTH)"; break; + default: prodstr = ""; break; + } + if (!fipmilan) lan_ch_restrict = 1; /*fw bug, gets 0xd4 locally*/ + break; + case VENDOR_QUANTA: /*=7244.*/ + switch(prod) { /* show product names for some */ + case 21401: prodstr = "(S99Q)"; break; + default: prodstr = ""; break; + } + break; + default: + prodstr = ""; + break; + } /*end switch(prod)*/ + if (kcs_loops != 0) set_max_kcs_loops(kcs_loops); + } /*end-else BMC*/ + + printf("%s manufacturer %c %06x (%s)%c product %c %04x %s\n", + tag, bdelim,mfg,mfgstr,bcomma,bdelim,prod,prodstr); + { /* BMC version */ + printf("%s version %c %x.%02x%s%c IPMI v%d.%d\n", tag,bdelim, + devrec[2],devrec[3],extraver,bcomma,ipmi_maj,ipmi_min); + } + /* could show product rev, if available (sdevrec > 14) */ + return; +} + +int GetPowerOnHours(unsigned int *val) +{ + uchar resp[MAX_BUFFER_SIZE]; + int sresp = MAX_BUFFER_SIZE; + uchar cc; + int rc = -1; + int i; + unsigned int hrs; + + *val = 0; + if (fmBMC) return(rc); + sresp = MAX_BUFFER_SIZE; + memset(resp,0,6); /* default response size is 5 */ + rc = ipmi_cmd_mc(GET_POWERON_HOURS, NULL, 0, resp, &sresp, &cc, fdebug); + if (rc == 0 && cc == 0) { + /* show the hours (32-bits) */ + hrs = resp[1] | (resp[2] << 8) | (resp[3] << 16) | (resp[4] << 24); + if (resp[0] == 60) /*normal*/ i = 1; + else { + i = 60 / resp[0]; + hrs = hrs / i; + } + *val = hrs; + } + return(rc); +} + +char *decode_selftest(int stat) +{ + uchar *s; + uchar b; + if (stat == 0x0055) s = "(OK)"; + else { + s = "(Error)"; + if ((stat & 0x00ff) == 0x0057) { + b = ((stat & 0xff00) >> 8); + if (b & 0x80) s = "(No SEL Access)"; + if (b & 0x40) s = "(No SDR Access)"; + if (b & 0x20) s = "(No FRU Access)"; + if (b & 0x10) s = "(IPMB Error)"; + if (b & 0x08) s = "(SDR Empty)"; + if (b & 0x02) s = "(BootCode Corrupt)"; + if (b & 0x01) s = "(OpCode Corrupt)"; + } + } + return(s); +} + +#ifdef METACOMMAND +int i_health(int argc, char **argv) +#else +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#endif +{ + int ret = 0; + int c; + uchar selfbuf[16]; + uchar devrec[30]; + char biosver[80]; + uchar cc; + int selfstatus; + uchar pwr_state; + char selfstr[36]; + char *s; + char *s1; + int i, sresp; + uint n; + int rlen, len; + uchar idata[4]; + uchar rdata[16]; + + printf("%s ver %s\n", progname,progver); + + while ( (c = getopt( argc, argv,"cfghiln:o:p:q:sT:V:J:YEF:P:N:R:U:Z:x?")) != EOF ) + switch(c) { + case 'c': fcanonical = 1; + bdelim = BDELIM; break; /* canonical output */ + case 'f': do_frusdr = 1; break; /* check the FRUSDR too */ + case 'g': do_guid = 1; break; /* get the System GUID also */ + case 'h': do_hsc = 1; break; /* check the HSC too */ + case 'i': do_systeminfo = 1; break; /* get system info too */ + case 'l': do_lanstats = 1; break; /* get the LAN stats too */ + case 'm': /* specific IPMB MC, 3-byte address, e.g. "409600" */ + g_bus = htoi(&optarg[0]); /*bus/channel*/ + g_sa = htoi(&optarg[2]); /*device slave address*/ + g_lun = htoi(&optarg[4]); /*LUN*/ + g_addrtype = ADDR_IPMB; + if (optarg[6] == 's') { + g_addrtype = ADDR_SMI; s1 = "SMI"; + } else { g_addrtype = ADDR_IPMB; s1 = "IPMB"; } + ipmi_set_mc(g_bus,g_sa,g_lun,g_addrtype); + printf("Use MC at %s bus=%x sa=%x lun=%x\n", + s1,g_bus,g_sa,g_lun); + break; + case 'n': set_name = 1; /* set the system name*/ + pname = optarg; + break; + case 'o': set_os = 1; /* set the Operating System*/ + pos = optarg; + break; + case 'q': set_os2 = 1; /* set the Operating System*/ + pos2 = optarg; + break; + case 'p': set_restore = 1; /* set the restore policy */ + restore_policy = atob(optarg); + if (restore_policy > 2) restore_policy = 1; + break; + case 's': do_session = 1; break; /* get session info too */ + case 'x': fdebug = 1; break; /* debug messages */ + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'V': /* priv level */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + break; + default: + printf("Usage: %s [-cfghilnopsx -N node -U user -P/-R pswd -EFTVY]\n", progname); + printf(" where -x show eXtra debug messages\n"); + printf(" -c canonical output\n"); + printf(" -f get the FRUSDR version also\n"); + printf(" -g get the System GUID also\n"); + printf(" -h check the HotSwap Controller also\n"); + printf(" -i get System Info also: Name and OS\n"); + printf(" -l get the IPMI LAN statistics also\n"); + printf(" -n set System Name to this string \n"); + printf(" -o set Operating System to this string\n"); + printf(" -p1 set restore policy: 0=off, 1=last, 2=on\n"); + printf(" -s get the IPMI Session info also\n"); + print_lan_opt_usage(); + ret = ERR_USAGE; + goto health_end; + } + + fipmilan = is_remote(); + if (fipmilan && set_restore) + parse_lan_options('V',"4",0); /*if set, request admin priv*/ + + ret = ipmi_getdeviceid(devrec,16,fdebug); + if (ret != 0) { + goto health_end; + } else { + show_devid_all(BMC,devrec,16); + } + + if (!fipmilan) { /*get local BIOS version*/ + biosver[0] = 0; + ret = get_BiosVersion(biosver); + if (ret == 0) printf("BIOS Version %c %s\n",bdelim,biosver); + } + if (do_me) { /* ME version for Intel S5500 motherboards */ + rlen = sizeof(rdata); + ret = ipmi_cmdraw((GET_DEVICE_ID & 0xff), NETFN_APP,ME_SA,ME_BUS,0x00, + idata,0,rdata,&rlen,&cc,fdebug); + if (ret == 0 && cc != 0) ret = cc; + if (ret == 0) { + uchar m,n; + m = (rdata[3] & 0xf0) >> 4; + n = (rdata[3] & 0x0f); + printf("ME Firmware Ver %c %02x.%02x.%02x.%02x%02x\n",bdelim, + rdata[2],m,n,rdata[12],rdata[13]); + /* If rdata[2] has 0x80 bit on, ME is in update/recovery mode. + That can be cleared by removing input power. */ + } else + if (fdebug) printf("GetDeviceID(ME) error ret = %d\n",ret); + } + + if (do_hsc) { + if (fmBMC) printf("No HSC present\n"); + else { + /* Get HSC status */ + if (is_romley(vend_id, prod_id)) { + uchar maj, min; + ret = get_hsbp_version_intel(&maj, &min); + if (fdebug) printf("get_hsbp_version_intel ret = %d\n",ret); + if (ret == 0) + printf("HSC version %c %d.%02d\n", bdelim,maj,min); + } else { + ret = get_hsc_devid(&devrec[0],sizeof(devrec)); + if (fdebug) printf("get_hsc_devid ret = %d\n",ret); + if (ret == 0) /* only if HSC is detected */ + show_devid_all(HSC,devrec,14); + } + } + } + + i = get_driver_type(); + printf("IPMI driver type %c %d (%s)\n",bdelim,i,show_driver_type(i)); + + if (do_powerstate) + { /* Some BMCs dont support get_power_state*/ + ret = get_power_state(selfbuf,4); + if (ret != 0) { + printf("ipmi_getpowerstate error, ret = %d\n",ret); + goto health_end; + } else { + pwr_state = selfbuf[0] & 0x7f; + printf("Power State %c %02x (%s)\n", + bdelim,pwr_state,pwr_string(pwr_state)); + } + } + + ret = get_selftest_status(&selfbuf[0],sizeof(selfbuf)); + if (ret != 0) { + printf("get_selftest_status error, ret = %x\n",ret); + goto health_end; + } else { + selfstatus = selfbuf[0] + (selfbuf[1] << 8); + s = decode_selftest(selfstatus); + if (fmBMC) { + sprintf(selfstr,"%s",s); + } else { + ret = get_last_selftest(&selfbuf[0],sizeof(selfbuf)); + if (fdebug) printf("get_last_selftest ret = %x, %02x%02x\n", + ret, selfbuf[1],selfbuf[0]); + if (ret == 0 && (selfbuf[0] != 0xFF)) { + sprintf(selfstr,"%s, last = %02x%02x",s,selfbuf[1],selfbuf[0]); + } else sprintf(selfstr,"%s",s); + ret = 0; /*ignore any errors with get_last_selftest*/ + } + printf("Selftest status %c %04x %s\n",bdelim,selfstatus,selfstr); + } + + ret = oem_get_health(&selfstr[0],sizeof(selfstr)); + if (ret == 0) { + printf("%s\n",selfstr); + } + + rlen = 4; + ret = get_chassis_status(selfbuf,&rlen); + if (ret != 0) { + printf("Cannot do get_chassis_status, ret = %d\n",ret); + goto health_end; + } else { + show_chs_status(selfbuf,rlen); + } + + if (vend_id == VENDOR_INTEL) { + int pwr_delay = 0; + ret = get_power_restore_delay_intel(&pwr_delay); + if (fdebug) printf("get_power_restore_delay_intel ret = %d\n",ret); + if (ret == 0) { + printf("PowerRestoreDelay %c %d seconds\n",bdelim,pwr_delay); + } else ret = 0; + } + + if (do_guid) { + sresp = sizeof(devrec); + ret = ipmi_cmd(GET_SYSTEM_GUID,NULL,0,devrec,&sresp,&cc,fdebug); + if (ret != 0) { + if (!is_remote()) { /* get UUID from SMBIOS */ + cc = 0; sresp = 16; + ret = get_SystemGuid(devrec); + } else { + cc = 0; + sresp = sizeof(devrec); + ret = get_device_guid(devrec,&sresp); + } + } + if (fdebug) printf("system_guid: ret = %d, cc = %x\n",ret,cc); + if (ret == 0 && cc == 0) { + printf("System GUID %c ",bdelim); + for (i=0; i<16; i++) { + if ((i == 4) || (i == 6) || (i == 8) || (i == 10)) s = "-"; + else s = ""; + printf("%s%02x",s,devrec[i]); + } + printf("\n"); + } + } + + if (bChan != 7) /* do not get first lan chan if set above */ + ret = get_lan_channel(1,&bChan); + + if (fmBMC == 0) { + ret = GetPowerOnHours(&n); + if (ret == 0) + printf("Power On Hours %c %d hours (%d days)\n",bdelim,n,(n/24)); + if (ret == 0xC1) ret = 0; /* not supporting poweron hours is ok. */ + + printf("BMC LAN Channels %c ",bdelim); + for (i = 1; i<= 16; ) { + c = get_lan_channel(i,&cc); + if (c != 0) break; + printf("%d ",cc); + i = cc+1; + } + printf("\n"); + + if (lan_ch_restrict) ; /*skip if vendor fw bug*/ + else { + ret = get_chan_auth(bChan,&devrec[0],sizeof(devrec)); + if (ret == 0) + show_chan_auth("Channel Auth Cap",devrec,8); + else + printf("get_chan_auth error: ret = %x\n",ret); + } + } + + if (do_systeminfo) { + char infostr[64]; + len = sizeof(infostr); + ret = get_system_info(1,infostr,&len); /*Firmware Version*/ + len = sizeof(infostr); + ret = get_system_info(2,infostr,&len); + if (ret == 0) { + printf("System Name %c %s\n",bdelim,infostr); + len = sizeof(infostr); + ret = get_system_info(3,infostr,&len); + if (ret == 0) printf("Pri Operating System %c %s\n",bdelim,infostr); + len = sizeof(infostr); + ret = get_system_info(4,infostr,&len); + if (ret == 0) printf("Sec Operating System %c %s\n",bdelim,infostr); + } else { + if (ret == 0xC1) /*only supported on later IPMI 2.0 firmware */ + printf("GetSystemInfo not supported on this platform\n"); + } + } + + if (do_frusdr) { + ret = get_frusdr_version((char *)&devrec[0],sizeof(devrec)); + if (ret == 0) printf("FRU/SDR Version %c %s\n",bdelim,devrec); + else printf("FRU/SDR Version %c error %d\n",bdelim,ret); + } + + if (do_lanstats) { + ret = get_lan_stats(bChan); + } + + if (do_session) { + i = get_session_info_all(); + if (i != 0) printf("get_session_info error %d, %s\n",i,decode_rv(i)); + } + +#ifdef PING_OK + { + char *node; + /* Currently some problems with this: + * works first time, but locks up BMC LAN on subsequent attempts. + */ + node = get_nodename(); + ret = ping_node(node); + printf("ping_node(%s): ret = %d\n",node,ret); + } +#endif + + if (set_name) { + len = (int)strlen(pname); + ret = set_system_info(2,pname,len); + printf("Set System Name to '%s', ret = %d\n",pname,ret); + if (ret == 0xC1) /*only supported on later IPMI 2.0 firmware */ + printf("SetSystemInfo not supported on this platform\n"); + } + + if (set_os) { + len = (int)strlen(pos); + ret = set_system_info(3,pos,len); + printf("Set Pri Operating System to '%s', ret = %d\n",pos,ret); + if (ret == 0xC1) /*only supported on later IPMI 2.0 firmware */ + printf("SetSystemInfo not supported on this platform\n"); + } + + if (set_os2) { + len = (int)strlen(pos2); + ret = set_system_info(4,pos2,len); + printf("Set Sec Operating System to '%s', ret = %d\n",pos2,ret); + if (ret == 0xC1) /*only supported on later IPMI 2.0 firmware */ + printf("SetSystemInfo not supported on this platform\n"); + } + + if (set_restore) { + idata[0] = restore_policy; /* 1=last_state, 2=turn_on, 0=stay_off*/ + rlen = sizeof(rdata); + ret = ipmi_cmdraw(0x06 , NETFN_CHAS, g_sa, g_bus, g_lun, + idata,1,rdata,&rlen,&cc,fdebug); + if (ret == 0 && cc != 0) ret = cc; + printf("set_restore_policy(%x): ret = %d\n",restore_policy,ret); + } + +health_end: + ipmi_close_(); + // show_outcome(progname,ret); + return (ret); +} /* end main()*/ + +/* end bmchealth.c */ diff --git a/util/ihpm.c b/util/ihpm.c new file mode 100644 index 0000000..740ab74 --- /dev/null +++ b/util/ihpm.c @@ -0,0 +1,4003 @@ +/* + * ihpm.c + * Hardware Platform Management, IPM Controller Firmware Upgrade Procedure + * + * Change history: + * 08/25/2010 ARCress - ported from ipmitool/lib/ipmi_hpmfwupg.c + * 08/24/2011 ARcress - updated to Kontron 1.08 (K17) version, + * added hpm_decode_cc(), etc. + * + *--------------------------------------------------------------------- + */ +/* + * Copyright (c) 2006 Kontron Canada, Inc. All Rights Reserved. + * 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. + */ + +#ifdef WIN32 +#include +#include +#include +#define uint8_t unsigned char +#define uint16_t unsigned short +#define uint32_t unsigned int +typedef uint32_t socklen_t; +#include "getopt.h" +#else +#include +#include +#include +#include +#include /*for toupper*/ +#if defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include +#else +#include +#endif +#endif +#include +#include +#include +#include + +#include "ipmicmd.h" +#include "ihpm.h" + +/**************************************************************************** +* +* Copyright (c) 2006 Kontron Canada, Inc. All Rights Reserved. +* +* HPM.1 +* Hardware Platform Management +* IPM Controller Firmware Upgrade Procedure +* +* This module implements an Upgrade Agent for the IPM Controller +* Firmware Upgrade Procedure (HPM.1) specification version 1.0. +* +* author: +* Frederic.Lelievre@ca.kontron.com +* Francois.Isabelle@ca.kontron.com +* Jean-Michel.Audet@ca.kontron.com +* MarieJosee.Blais@ca.kontron.com +* +***************************************************************************** +* +* HISTORY +* =========================================================================== +* 2007-01-11 +* +* - Incremented to version 0.2 +* - Added lan packet size reduction mechanism to workaround fact +* that lan iface will not return C7 on excessive length +* - Fixed some typos +* - now uses lprintf() +* +* - Incremented to version 0.3 +* - added patch for openipmi si driver V39 (send message in driver does not +* retry on 82/83 completion code and return 82/83 as response from target +* [conditionnaly built with ENABLE_OPENIPMI_V39_PATCH] +* +* see: ipmi-fix-send-msg-retry.pacth in openipmi-developer mailing list +* +* 2007-01-16 +* +* - Incremented to version 0.4 +* - Fixed lan iface inaccesiblity timeout handling. Waiting for firmware +* activation completion (fixed sleep) before re-opening a session and +* get the final firmware upgrade status. +* - Fixed some user interface stuff. +* +* 2007-05-09 +* +* - Incremented to version 1.0 +* - Modifications for compliancy with HPM.1 specification version 1.0 +* +* 2007-06-05 +* +* - Modified the display of upgrade of Firmware version. +* - Added new options like "check" and "component" and "all" to hpm commands. +* - By default we skip the upgrade if we have the same firmware version +* as compared to the Image file (*.hpm).This will ensure that user does +* not update the target incase its already been updated +* +* 2008-01-25 +* - Reduce buffer length more aggressively when no response from iol. +* - Incremented version to 1.02 +* +* 2009-02-11 +* - With multi-component HPM file, if one component need to be skipped because +* the component is already up-to-date, ipmitool sends "Initiate upgrade +* action / Upload for upgrade" anyway. +* +* If the component needs to be skipped, ipmitool will not send "Initiate +* upgrade action / Upload for upgrade" +* +* - Incremented version to 1.03 +* +* 2009-02-11 +* - Fixed side effect introduced by last version, "forced" update didn't +* work anymore +* - Incremented version to 1.04 +* +* 2009-03-25 +* - Fix the case where ipmitool loses the iol connection during the upload +* block process. Once IPMITool was successfully sent the first byte, +* IPMITool will not resize the block size. +* +* 2009-03-26 +* - Fix the problem when we try to upgrade specific component and the component +* is already updated, IPMITool sends a "prepare action" but IPMITool skips +* the upload firmware block process. +* So, if we specify a specific component, we want to force to upload this +* specific component. +* - Incremented version to 1.05 +* +* 2009-04-20 +* - Reworked previous update, when 'component' is specified, the other +* components are now skipped. +* - Incremented version to 1.06 +* +* =========================================================================== +* TODO +* =========================================================================== +* 2007-01-11 +* - Add interpretation of GetSelftestResults +* - Add interpretation of component ID string +* +*****************************************************************************/ + +extern int verbose; + +/* + * Agent version + */ +#define HPMFWUPG_VERSION_MAJOR 1 +#define HPMFWUPG_VERSION_MINOR 0 +#define HPMFWUPG_VERSION_SUBMINOR 9 +static char * progname = "ihpm"; +static char * progver = "1.09"; /* HPMFWUPG_VERSION */ +extern char fdebug; /*from ipmicmd.c*/ +static uchar g_bus = PUBLIC_BUS; +static uchar g_sa = BMC_SA; +static uchar g_lun = BMC_LUN; +static uchar g_addrtype = ADDR_SMI; +static int g_channel_buf_size = 0; + +/* + * HPM.1 FIRMWARE UPGRADE COMMANDS (part of PICMG) + */ + +#define HPMFWUPG_GET_TARGET_UPG_CAPABILITIES 0x2E +#define HPMFWUPG_GET_COMPONENT_PROPERTIES 0x2F +#define HPMFWUPG_ABORT_UPGRADE 0x30 +#define HPMFWUPG_INITIATE_UPGRADE_ACTION 0x31 +#define HPMFWUPG_UPLOAD_FIRMWARE_BLOCK 0x32 +#define HPMFWUPG_FINISH_FIRMWARE_UPLOAD 0x33 +#define HPMFWUPG_GET_UPGRADE_STATUS 0x34 +#define HPMFWUPG_ACTIVATE_FIRMWARE 0x35 +#define HPMFWUPG_QUERY_SELFTEST_RESULT 0x36 +#define HPMFWUPG_QUERY_ROLLBACK_STATUS 0x37 +#define HPMFWUPG_MANUAL_FIRMWARE_ROLLBACK 0x38 + +/* + * HPM.1 SPECIFIC COMPLETION CODES + */ +#define HPMFWUPG_ROLLBACK_COMPLETED 0x00 +#define HPMFWUPG_COMMAND_IN_PROGRESS 0x80 +#define HPMFWUPG_NOT_SUPPORTED 0x81 +#define HPMFWUPG_SIZE_MISMATCH 0x81 +#define HPMFWUPG_ROLLBACK_FAILURE 0x81 +#define HPMFWUPG_INV_COMP_MASK 0x81 +#define HPMFWUPG__ABORT_FAILURE 0x81 +#define HPMFWUPG_INV_COMP_ID 0x82 +#define HPMFWUPG_INT_CHECKSUM_ERROR 0x82 +#define HPMFWUPG_INV_UPLOAD_MODE 0x82 +#define HPMFWUPG_ROLLBACK_OVERRIDE 0x82 +#define HPMFWUPG_INV_COMP_PROP 0x83 +#define HPMFWUPG_FW_MISMATCH 0x83 +#define HPMFWUPG_ROLLBACK_DENIED 0x83 +#define HPMFWUPG_NOT_SUPPORTED_NOW 0xd5 + +/* + * This error code is used as a temporary PATCH to + * the latest Open ipmi driver. This PATCH + * will be removed once a new Open IPMI driver is released. + * (Buggy version = 39) + */ +#define ENABLE_OPENIPMI_V39_PATCH + +#ifdef ENABLE_OPENIPMI_V39_PATCH + +#define RETRY_COUNT_MAX 3 + +static int errorCount; + +#define HPMFWUPG_IS_RETRYABLE(error) \ +((((error==0x83)||(error==0x82)||(error==0x80)) && (errorCount++descString,11); + /* + * If the cold reset is required then we can display * on it + * so that user is aware that he needs to do payload power + * cycle after upgrade + */ + printf("|%c%-2d|%-11s|",pVersion->coldResetRequired?'*':' ',pVersion->componentId,descString); + + if (mode & TARGET_VER) + { + if (pVersion->targetMajor == 0xFF && pVersion->targetMinor == 0xFF) + printf(" ---.-- -------- |"); + else + printf(" %3d.%02x %02X%02X%02X%02X |", + pVersion->targetMajor, + pVersion->targetMinor, + pVersion->targetAux[0], + pVersion->targetAux[1], + pVersion->targetAux[2], + pVersion->targetAux[3] + ); + + if (mode & ROLLBACK_VER) + { + if (pVersion->rollbackMajor == 0xFF && pVersion->rollbackMinor == 0xFF) + printf(" ---.-- -------- |"); + else + printf(" %3d.%02x %02X%02X%02X%02X |", + pVersion->rollbackMajor, + pVersion->rollbackMinor, + pVersion->rollbackAux[0], + pVersion->rollbackAux[1], + pVersion->rollbackAux[2], + pVersion->rollbackAux[3]); + } + else + { + printf(" ---.-- -------- |"); + } + } + + if (mode & IMAGE_VER) + { + if (pVersion->imageMajor == 0xFF && pVersion->imageMinor == 0xFF) + printf(" ---.-- |"); + else + printf(" %3d.%02x %02X%02X%02X%02X |", + pVersion->imageMajor, + pVersion->imageMinor, + pVersion->imageAux[0], + pVersion->imageAux[1], + pVersion->imageAux[2], + pVersion->imageAux[3]); + } + return 0; +} + + +/**************************************************************************** +* +* Function Name: HpmfwupgTargerCheck +* +* Description: This function gets the target information and displays it on the +* screen +* +*****************************************************************************/ +int HpmfwupgTargetCheck(void * intf, int option) +{ + // struct HpmfwupgUpgradeCtx fwupgCtx; + struct HpmfwupgGetTargetUpgCapabilitiesCtx targetCapCmd; + int rc = HPMFWUPG_SUCCESS; + int componentId = 0; + int flagColdReset = FALSE; + struct ipm_devid_rsp devIdrsp; + struct HpmfwupgGetComponentPropertiesCtx getCompProp; + int mode = 0; + + + rc = HpmfwupgGetDeviceId(intf, &devIdrsp); + + if (rc != HPMFWUPG_SUCCESS) + { + lprintf(LOG_NOTICE,"Verify whether the Target board is present \n"); + return rc; + } + + rc = HpmfwupgGetTargetUpgCapabilities(intf, &targetCapCmd); + if (rc != HPMFWUPG_SUCCESS) + { + /* + * That indicates the target is not responding to the command + * May be that there is no HPM support + */ + lprintf(LOG_NOTICE,"Board might not be supporting the HPM.1 Standards\n"); + return rc; + } + if (option & VIEW_MODE) + { + lprintf(LOG_NOTICE,"-------Target Information-------"); + lprintf(LOG_NOTICE,"Device Id : 0x%x", devIdrsp.device_id); + lprintf(LOG_NOTICE,"Device Revision : 0x%x", devIdrsp.device_revision); + lprintf(LOG_NOTICE,"Product Id : 0x%04x", buf2short(devIdrsp.product_id)); + lprintf(LOG_NOTICE,"Manufacturer Id : 0x%04x (%s)\n\n", + buf2short(devIdrsp.manufacturer_id), + get_mfg_str(devIdrsp.manufacturer_id,NULL)); + HpmDisplayVersionHeader(TARGET_VER|ROLLBACK_VER); + } + + for ( componentId = HPMFWUPG_COMPONENT_ID_0; componentId < HPMFWUPG_COMPONENT_ID_MAX; + componentId++ ) + { + /* If the component is supported */ + if ( ((1 << componentId) & targetCapCmd.resp.componentsPresent.ComponentBits.byte) ) + { + memset((PVERSIONINFO)&gVersionInfo[componentId],0x00,sizeof(VERSIONINFO)); + + getCompProp.req.componentId = componentId; + getCompProp.req.selector = HPMFWUPG_COMP_GEN_PROPERTIES; + rc = HpmfwupgGetComponentProperties(intf, &getCompProp); + if (rc != HPMFWUPG_SUCCESS) + { + lprintf(LOG_NOTICE,"Get CompGenProp Failed for component Id %d\n",componentId); + return rc; + } + + gVersionInfo[componentId].rollbackSupported = getCompProp.resp.Response. + generalPropResp.GeneralCompProperties.bitfield.rollbackBackup; + gVersionInfo[componentId].coldResetRequired = getCompProp.resp.Response. + generalPropResp.GeneralCompProperties.bitfield.payloadColdReset; + + getCompProp.req.selector = HPMFWUPG_COMP_DESCRIPTION_STRING; + rc = HpmfwupgGetComponentProperties(intf, &getCompProp); + if (rc != HPMFWUPG_SUCCESS) + { + lprintf(LOG_NOTICE,"Get CompDescString Failed for component Id %d\n",componentId); + return rc; + } + strcpy((char *)&gVersionInfo[componentId].descString, + getCompProp.resp.Response.descStringResp.descString); + + getCompProp.req.selector = HPMFWUPG_COMP_CURRENT_VERSION; + rc = HpmfwupgGetComponentProperties(intf, &getCompProp); + if (rc != HPMFWUPG_SUCCESS) + { + lprintf(LOG_NOTICE,"Get CompCurrentVersion Failed for component Id %d\n",componentId); + return rc; + } + + gVersionInfo[componentId].componentId = componentId; + gVersionInfo[componentId].targetMajor = getCompProp.resp.Response. + currentVersionResp.currentVersion[0]; + gVersionInfo[componentId].targetMinor = getCompProp.resp.Response. + currentVersionResp.currentVersion[1]; + gVersionInfo[componentId].targetAux[0] = getCompProp.resp.Response. + currentVersionResp.currentVersion[2]; + gVersionInfo[componentId].targetAux[1] = getCompProp.resp.Response. + currentVersionResp.currentVersion[3]; + gVersionInfo[componentId].targetAux[2] = getCompProp.resp.Response. + currentVersionResp.currentVersion[4]; + gVersionInfo[componentId].targetAux[3] = getCompProp.resp.Response. + currentVersionResp.currentVersion[5]; + mode = TARGET_VER; + + if (gVersionInfo[componentId].rollbackSupported) + { + getCompProp.req.selector = HPMFWUPG_COMP_ROLLBACK_FIRMWARE_VERSION; + rc = HpmfwupgGetComponentProperties(intf, &getCompProp); + if (rc != HPMFWUPG_SUCCESS) + { + lprintf(LOG_NOTICE,"Get CompRollbackVersion Failed for component Id %d\n",componentId); + } else { + gVersionInfo[componentId].rollbackMajor = getCompProp.resp + .Response.rollbackFwVersionResp.rollbackFwVersion[0]; + gVersionInfo[componentId].rollbackMinor = getCompProp.resp + .Response.rollbackFwVersionResp.rollbackFwVersion[1]; + gVersionInfo[componentId].rollbackAux[0] = getCompProp.resp.Response. + rollbackFwVersionResp.rollbackFwVersion[2]; + gVersionInfo[componentId].rollbackAux[1] = getCompProp.resp.Response. + rollbackFwVersionResp.rollbackFwVersion[3]; + gVersionInfo[componentId].rollbackAux[2] = getCompProp.resp.Response. + rollbackFwVersionResp.rollbackFwVersion[4]; + gVersionInfo[componentId].rollbackAux[3] = getCompProp.resp.Response. + rollbackFwVersionResp.rollbackFwVersion[5]; + } + mode |= ROLLBACK_VER; + } + + if (gVersionInfo[componentId].coldResetRequired) + { + /* + * If any of the component indicates that the Payload Cold reset is required + * then set the flag + */ + flagColdReset = TRUE; + } + if (option & VIEW_MODE) + { + HpmDisplayVersion(mode,&gVersionInfo[componentId]); + printf("\n"); + } + } + } + + if (option & VIEW_MODE) + { + HpmDisplayLine("-",53 ); + if (flagColdReset) + { + fflush(stdout); + lprintf(LOG_NOTICE,"(*) Component requires Payload Cold Reset"); + } + printf("\n\n"); + } + return HPMFWUPG_SUCCESS; +} + +/***************************************************************************** +* Function Name: HpmfwupgUpgrade +* +* Description: This function performs the HPM.1 firmware upgrade procedure as +* defined the IPM Controller Firmware Upgrade Specification +* version 1.0 +* +*****************************************************************************/ +int HpmfwupgUpgrade(void *intf, char* imageFilename, + int activate,int componentToUpload, int option) +{ + int rc = HPMFWUPG_SUCCESS; + // struct HpmfwupgImageHeader imageHeader; + struct HpmfwupgUpgradeCtx fwupgCtx; + + /* + * GET IMAGE BUFFER FROM FILE + */ + + rc = HpmfwupgGetBufferFromFile(imageFilename, &fwupgCtx); + + /* + * VALIDATE IMAGE INTEGRITY + */ + + if ( rc == HPMFWUPG_SUCCESS ) + { + printf("Validating firmware image integrity..."); + fflush(stdout); + rc = HpmfwupgValidateImageIntegrity(&fwupgCtx); + if ( rc == HPMFWUPG_SUCCESS ) + { + printf("OK\n"); + fflush(stdout); + } + else + { + free(fwupgCtx.pImageData); + } + } + + /* + * PREPARATION STAGE + */ + + if ( rc == HPMFWUPG_SUCCESS ) + { + printf("Performing preparation stage..."); + fflush(stdout); + rc = HpmfwupgPreparationStage(intf, &fwupgCtx, option); + if ( rc == HPMFWUPG_SUCCESS ) + { + printf("OK\n"); + fflush(stdout); + } + else + { + free(fwupgCtx.pImageData); + } + } + + /* + * UPGRADE STAGE + */ + + if ( rc == HPMFWUPG_SUCCESS ) + { + if (option & VIEW_MODE) + { + lprintf(LOG_NOTICE,"\nComparing Target & Image File version"); + } + else + { + lprintf(LOG_NOTICE,"\nPerforming upgrade stage:"); + } + if (option & VIEW_MODE) + { + rc = HpmfwupgPreUpgradeCheck(intf, &fwupgCtx,componentToUpload,VIEW_MODE); + } + else + { + rc = HpmfwupgPreUpgradeCheck(intf, &fwupgCtx,componentToUpload,option); + if (rc == HPMFWUPG_SUCCESS ) + { + if( verbose ) { + printf("Component update mask : 0x%02x\n", fwupgCtx.compUpdateMask.ComponentBits.byte); + } + rc = HpmfwupgUpgradeStage(intf, &fwupgCtx,componentToUpload,option); + } + } + + if ( rc != HPMFWUPG_SUCCESS ) + { + if (verbose) printf("HPM Upgrade error %d\n",rc); + free(fwupgCtx.pImageData); + } + } + + /* + * ACTIVATION STAGE + */ + if ( rc == HPMFWUPG_SUCCESS && activate ) + { + lprintf(LOG_NOTICE,"Performing activation stage: "); + rc = HpmfwupgActivationStage(intf, &fwupgCtx); + if ( rc != HPMFWUPG_SUCCESS ) + { + if (verbose) printf("HPM Activation error %d\n",rc); + free(fwupgCtx.pImageData); + } + } + + if ( rc == HPMFWUPG_SUCCESS ) + { + if (option & VIEW_MODE) + { + // Dont display anything here in case we are just viewing it + lprintf(LOG_NOTICE," "); + } + else + { + lprintf(LOG_NOTICE,"\nFirmware upgrade procedure successful\n"); + } + free(fwupgCtx.pImageData); + } + else + { + lprintf(LOG_NOTICE,"Firmware upgrade procedure failed\n"); + } + + return rc; +} + +/**************************************************************************** +* +* Function Name: HpmfwupgValidateImageIntegrity +* +* Description: This function validates a HPM.1 firmware image file as defined +* in section 4 of the IPM Controller Firmware Upgrade +* Specification version 1.0 +* +*****************************************************************************/ +int HpmfwupgValidateImageIntegrity(struct HpmfwupgUpgradeCtx* pFwupgCtx) +{ + int rc = HPMFWUPG_SUCCESS; + struct HpmfwupgImageHeader* pImageHeader = (struct HpmfwupgImageHeader*) + pFwupgCtx->pImageData; + md5_state_t ctx; + static unsigned char md[HPMFWUPG_MD5_SIGNATURE_LENGTH]; + unsigned char* pMd5Sig = pFwupgCtx->pImageData + + (pFwupgCtx->imageSize - + HPMFWUPG_MD5_SIGNATURE_LENGTH); + + /* Validate MD5 checksum */ + memset(md, 0, HPMFWUPG_MD5_SIGNATURE_LENGTH); + memset(&ctx, 0, sizeof(md5_state_t)); + md5_init(&ctx); + md5_append(&ctx, pFwupgCtx->pImageData, pFwupgCtx->imageSize - + HPMFWUPG_MD5_SIGNATURE_LENGTH); + md5_finish(&ctx, md); + if ( memcmp(md, pMd5Sig,HPMFWUPG_MD5_SIGNATURE_LENGTH) != 0 ) + { + lprintf(LOG_NOTICE,"\n Invalid MD5 signature"); + rc = HPMFWUPG_ERROR; + } + + if ( rc == HPMFWUPG_SUCCESS ) + { + /* Validate Header signature */ + if( strncmp(pImageHeader->signature, HPMFWUPG_IMAGE_SIGNATURE, HPMFWUPG_HEADER_SIGNATURE_LENGTH) == 0 ) + { + /* Validate Header image format version */ + if ( pImageHeader->formatVersion == HPMFWUPG_IMAGE_HEADER_VERSION ) + { + /* Validate header checksum */ + if ( HpmfwupgCalculateChecksum((unsigned char*)pImageHeader, + sizeof(struct HpmfwupgImageHeader) + + pImageHeader->oemDataLength + + sizeof(unsigned char)/*checksum*/) != 0 ) + { + lprintf(LOG_NOTICE,"\n Invalid header checksum"); + rc = HPMFWUPG_ERROR; + } + } + else + { + lprintf(LOG_NOTICE,"\n Unrecognized image version"); + rc = HPMFWUPG_ERROR; + } + } + else + { + lprintf(LOG_NOTICE,"\n Invalid image signature"); + rc = HPMFWUPG_ERROR; + } + } + return rc; +} + +/**************************************************************************** +* +* Function Name: HpmfwupgPreparationStage +* +* Description: This function the preperation stage of a firmware upgrade +* procedure as defined in section 3.2 of the IPM Controller +* Firmware Upgrade Specification version 1.0 +* +*****************************************************************************/ +int HpmfwupgPreparationStage(void *intf, struct HpmfwupgUpgradeCtx* pFwupgCtx, int option) +{ + int rc = HPMFWUPG_SUCCESS; + struct HpmfwupgImageHeader* pImageHeader = (struct HpmfwupgImageHeader*) + pFwupgCtx->pImageData; + + /* Get device ID */ + rc = HpmfwupgGetDeviceId(intf, &pFwupgCtx->devId); + + /* Match current IPMC IDs with upgrade image */ + if ( rc == HPMFWUPG_SUCCESS ) + { + /* Validate device ID */ + if ( pImageHeader->deviceId == pFwupgCtx->devId.device_id ) + { + /* Validate product ID */ + if ( memcmp(pImageHeader->prodId, pFwupgCtx->devId.product_id, HPMFWUPG_PRODUCT_ID_LENGTH ) == 0 ) + { + /* Validate man ID */ + if ( memcmp(pImageHeader->manId, pFwupgCtx->devId.manufacturer_id, + HPMFWUPG_MANUFATURER_ID_LENGTH ) != 0 ) + { + lprintf(LOG_NOTICE,"\n Invalid image file for manufacturer %u", + buf2short(pFwupgCtx->devId.manufacturer_id)); + rc = HPMFWUPG_ERROR; + } + } + else + { + lprintf(LOG_NOTICE,"\n Invalid image file for product %u", + buf2short(pFwupgCtx->devId.product_id)); + rc = HPMFWUPG_ERROR; + } + + } + else + { + lprintf(LOG_NOTICE,"\n Invalid device ID %x", pFwupgCtx->devId.device_id); + rc = HPMFWUPG_ERROR; + } + + if (rc != HPMFWUPG_SUCCESS) + { + /* + * Giving one more chance to user to check whether its OK to continue even if the + * product ID does not match. This is helpful as sometimes we just want to update + * and dont care whether we have a different product Id. If the user says NO then + * we need to just bail out from here + */ + if ( (option & FORCE_MODE) || (option & VIEW_MODE) ) + { + printf("\n Image Information"); + printf("\n Device Id : 0x%x",pImageHeader->deviceId); + printf("\n Prod Id : 0x%02x%02x",pImageHeader->prodId[1], pImageHeader->prodId[0]); + printf("\n Manuf Id : 0x%02x%02x%02x",pImageHeader->manId[2], + pImageHeader->manId[1],pImageHeader->manId[0]); + printf("\n Board Information"); + printf("\n Device Id : 0x%x", pFwupgCtx->devId.device_id); + printf("\n Prod Id : 0x%02x%02x",pFwupgCtx->devId.product_id[1], pFwupgCtx->devId.product_id[0]); + printf("\n Manuf Id : 0x%02x%02x%02x",pFwupgCtx->devId.manufacturer_id[2], + pFwupgCtx->devId.manufacturer_id[1],pFwupgCtx->devId.manufacturer_id[0]); + if (HpmGetUserInput("\n Continue ignoring DeviceID/ProductID/ManufacturingID (Y/N) :")) + rc = HPMFWUPG_SUCCESS; + } + else + { + /* + * If you use all option its kind of FORCE command where we need to upgrade all the components + */ + printf("\n\n Use \"all\" option for uploading all the components\n"); + } + } + } + + /* Validate earliest compatible revision */ + if ( rc == HPMFWUPG_SUCCESS ) + { + /* Validate major & minor revision */ + if ( pImageHeader->compRevision[0] < pFwupgCtx->devId.fw_rev1 ) + { + /* Do nothing, upgrade accepted */ + } + else if ( pImageHeader->compRevision[0] == pFwupgCtx->devId.fw_rev1 ) + { + /* Must validate minor revision */ + if ( pImageHeader->compRevision[1] > pFwupgCtx->devId.fw_rev2 ) + { + /* Version not compatible for upgrade */ + lprintf(LOG_NOTICE,"\n Version: Major: %d", pImageHeader->compRevision[0]); + lprintf(LOG_NOTICE," Minor: %x", pImageHeader->compRevision[1]); + lprintf(LOG_NOTICE," Not compatible with "); + lprintf(LOG_NOTICE," Version: Major: %d", pFwupgCtx->devId.fw_rev1); + lprintf(LOG_NOTICE," Minor: %x", pFwupgCtx->devId.fw_rev2); + rc = HPMFWUPG_ERROR; + } + } + else + { + /* Version not compatible for upgrade */ + lprintf(LOG_NOTICE,"\n Version: Major: %d", pImageHeader->compRevision[0]); + lprintf(LOG_NOTICE," Minor: %x", pImageHeader->compRevision[1]); + lprintf(LOG_NOTICE," Not compatible with "); + lprintf(LOG_NOTICE," Version: Major: %d", pFwupgCtx->devId.fw_rev1); + lprintf(LOG_NOTICE," Minor: %x", pFwupgCtx->devId.fw_rev2); + rc = HPMFWUPG_ERROR; + } + + if (rc != HPMFWUPG_SUCCESS) + { + /* Confirming it once again */ + if ( (option & FORCE_MODE) || (option & VIEW_MODE) ) + { + if( HpmGetUserInput("\n Continue IGNORING Earliest compatibility (Y/N) :")) + rc = HPMFWUPG_SUCCESS; + } + } + } + + /* Get target upgrade capabilities */ + if ( rc == HPMFWUPG_SUCCESS ) + { + struct HpmfwupgGetTargetUpgCapabilitiesCtx targetCapCmd; + + rc = HpmfwupgGetTargetUpgCapabilities(intf, &targetCapCmd); + + if ( rc == HPMFWUPG_SUCCESS ) + { + /* Copy response to context */ + memcpy(&pFwupgCtx->targetCap, + &targetCapCmd.resp, + sizeof(struct HpmfwupgGetTargetUpgCapabilitiesResp)); + + if (option & VIEW_MODE) + { + return rc; + } + else + { + /* Make sure all component IDs defined in the upgrade + image are supported by the IPMC */ + if ( (pImageHeader->components.ComponentBits.byte & + pFwupgCtx->targetCap.componentsPresent.ComponentBits.byte ) != + pImageHeader->components.ComponentBits.byte ) + { + lprintf(LOG_NOTICE,"\n Some components present in the image file are not supported by the IPMC"); + rc = HPMFWUPG_ERROR; + } + + /* Make sure the upgrade is desirable rigth now */ + if ( pFwupgCtx->targetCap.GlobalCapabilities.bitField.fwUpgUndesirable == 1 ) + { + lprintf(LOG_NOTICE,"\n Upgrade undesirable at this moment"); + rc = HPMFWUPG_ERROR; + } + + /* Get confimation from the user if he wants to continue when service + affected during upgrade */ + if ( pFwupgCtx->targetCap.GlobalCapabilities.bitField.servAffectDuringUpg == 1 || + pImageHeader->imageCapabilities.bitField.servAffected == 1 ) + { + if (HpmGetUserInput("\nServices may be affected during upgrade. Do you wish to continue? y/n ")) + { + rc = HPMFWUPG_SUCCESS; + } + else + { + rc = HPMFWUPG_ERROR; + } + } + } + } + } + + /* Get the general properties of each component present in image */ + if ( rc == HPMFWUPG_SUCCESS ) + { + int componentId; + + for ( componentId = HPMFWUPG_COMPONENT_ID_0; + componentId < HPMFWUPG_COMPONENT_ID_MAX; + componentId++ ) + { + /* Reset component properties */ + memset(&pFwupgCtx->genCompProp[componentId], 0, sizeof (struct HpmfwupgGetGeneralPropResp)); + + if ( (1 << componentId & pImageHeader->components.ComponentBits.byte) ) + { + struct HpmfwupgGetComponentPropertiesCtx getCompPropCmd; + + /* Get general component properties */ + getCompPropCmd.req.componentId = componentId; + getCompPropCmd.req.selector = HPMFWUPG_COMP_GEN_PROPERTIES; + + rc = HpmfwupgGetComponentProperties(intf, &getCompPropCmd); + + if ( rc == HPMFWUPG_SUCCESS ) + { + /* Copy response to context */ + memcpy(&pFwupgCtx->genCompProp[componentId], + &getCompPropCmd.resp, + sizeof(struct HpmfwupgGetGeneralPropResp)); + } + } + } + } + + return rc; +} + +/**************************************************************************** +* +* Function Name: HpmfwupgPreUpgradeCheck +* +* Description: This function the pre Upgrade check, this mainly helps in checking +* which all version upgrade is skippable because the image version +* is same as target version. +* +*****************************************************************************/ +int HpmfwupgPreUpgradeCheck(void *intf, struct HpmfwupgUpgradeCtx* pFwupgCtx, + int componentToUpload,int option) +{ + int rc = HPMFWUPG_SUCCESS; + unsigned char* pImagePtr; + struct HpmfwupgActionRecord* pActionRecord; + unsigned int actionsSize; + int flagColdReset = FALSE; + struct HpmfwupgImageHeader* pImageHeader = (struct HpmfwupgImageHeader*) + pFwupgCtx->pImageData; + + /* Put pointer after image header */ + pImagePtr = (unsigned char*) + (pFwupgCtx->pImageData + sizeof(struct HpmfwupgImageHeader) + + pImageHeader->oemDataLength + sizeof(unsigned char)/*checksum*/); + + /* Deternime actions size */ + actionsSize = pFwupgCtx->imageSize - sizeof(struct HpmfwupgImageHeader); + + if (option & VIEW_MODE) + { + HpmDisplayVersionHeader(TARGET_VER|ROLLBACK_VER|IMAGE_VER); + } + + /* Perform actions defined in the image */ + while( ( pImagePtr < (pFwupgCtx->pImageData + pFwupgCtx->imageSize - + HPMFWUPG_MD5_SIGNATURE_LENGTH)) && + ( rc == HPMFWUPG_SUCCESS) ) + { + /* Get action record */ + pActionRecord = (struct HpmfwupgActionRecord*)pImagePtr; + + /* Validate action record checksum */ + if ( HpmfwupgCalculateChecksum((unsigned char*)pActionRecord, + sizeof(struct HpmfwupgActionRecord)) != 0 ) + { + lprintf(LOG_NOTICE," Invalid Action record."); + rc = HPMFWUPG_ERROR; + } + + if ( rc == HPMFWUPG_SUCCESS ) + { + switch( pActionRecord->actionType ) + { + case HPMFWUPG_ACTION_BACKUP_COMPONENTS: + { + pImagePtr += sizeof(struct HpmfwupgActionRecord); + } + break; + + case HPMFWUPG_ACTION_PREPARE_COMPONENTS: + { + if (componentToUpload != DEFAULT_COMPONENT_UPLOAD) + { + if (!(1<components.ComponentBits.byte)) + { + lprintf(LOG_NOTICE,"\nComponent Id given is not supported\n"); + return HPMFWUPG_ERROR; + } + } + pImagePtr += sizeof(struct HpmfwupgActionRecord); + } + break; + + case HPMFWUPG_ACTION_UPLOAD_FIRMWARE: + /* Upload all firmware blocks */ + { + struct HpmfwupgFirmwareImage* pFwImage; + unsigned char* pData; + unsigned int firmwareLength = 0; + unsigned char mode = 0; + unsigned char componentId = 0x00; + unsigned char componentIdByte = 0x00; + VERSIONINFO *pVersionInfo; + // struct HpmfwupgGetComponentPropertiesCtx getCompProp; + + /* Save component ID on which the upload is done */ + componentIdByte = pActionRecord->components.ComponentBits.byte; + + while ((componentIdByte>>=1)!=0) + { + componentId++; + } + pFwupgCtx->componentId = componentId; + + pFwImage = (struct HpmfwupgFirmwareImage*)(pImagePtr + + sizeof(struct HpmfwupgActionRecord)); + + pData = ((unsigned char*)pFwImage + sizeof(struct HpmfwupgFirmwareImage)); + + /* Get firmware length */ + firmwareLength = pFwImage->length[0]; + firmwareLength |= (pFwImage->length[1] << 8) & 0xff00; + firmwareLength |= (pFwImage->length[2] << 16) & 0xff0000; + firmwareLength |= (pFwImage->length[3] << 24) & 0xff000000; + + pVersionInfo = &gVersionInfo[componentId]; + + pVersionInfo->imageMajor = pFwImage->version[0]; + pVersionInfo->imageMinor = pFwImage->version[1]; + pVersionInfo->imageAux[0] = pFwImage->version[2]; + pVersionInfo->imageAux[1] = pFwImage->version[3]; + pVersionInfo->imageAux[2] = pFwImage->version[4]; + pVersionInfo->imageAux[3] = pFwImage->version[5]; + + mode = TARGET_VER | IMAGE_VER; + + if (pVersionInfo->coldResetRequired) + { + flagColdReset = TRUE; + } + pVersionInfo->skipUpgrade = FALSE; + + if (option & FORCE_MODE_ALL) + { + /* user has given all to upload all the components on the command line */ + if(verbose) { + lprintf(LOG_NOTICE,"Forcing ALL components"); + } + } + else if( option & FORCE_MODE_COMPONENT ) + { + if( componentToUpload != componentId ) + { + if(verbose) { + lprintf(LOG_NOTICE,"Forcing component %d skip", componentId); + } + /* user has given the component Id to upload on the command line */ + pVersionInfo->skipUpgrade = TRUE; + } + else if(verbose) + { + lprintf(LOG_NOTICE,"Forcing component %d update", componentId); + /* user has given the component Id to upload on the command line */ + } + } + else + { + if + ( + (pVersionInfo->imageMajor == pVersionInfo->targetMajor) + && + (pVersionInfo->imageMinor == pVersionInfo->targetMinor)) + { + if (pVersionInfo->rollbackSupported) + { + /*If the Image Versions are same as Target Versions then check for the + * rollback version*/ + if + ( + (pVersionInfo->imageMajor == pVersionInfo->rollbackMajor) + && + (pVersionInfo->imageMinor == pVersionInfo->rollbackMinor) + ) + { + /* This indicates that the Rollback version is also same as + * Image version -- So now we must skip it */ + pVersionInfo->skipUpgrade = TRUE; + } + mode |= ROLLBACK_VER; + } + else + { + pVersionInfo->skipUpgrade = TRUE; + } + } + if ( verbose ) { + lprintf(LOG_NOTICE,"Component %d: %s", componentId , (pVersionInfo->skipUpgrade?"skipped":"to update")); + } + } + if( pVersionInfo->skipUpgrade == FALSE ) + { + pFwupgCtx->compUpdateMask.ComponentBits.byte |= 1<pImageData; + struct HpmfwupgActionRecord* pActionRecord; + + int rc = HPMFWUPG_SUCCESS; + unsigned char* pImagePtr; + unsigned int actionsSize; + int flagColdReset = FALSE; + // time_t start,end; + + /* Put pointer after image header */ + pImagePtr = (unsigned char*) + (pFwupgCtx->pImageData + sizeof(struct HpmfwupgImageHeader) + + pImageHeader->oemDataLength + sizeof(unsigned char)/*checksum*/); + + /* Deternime actions size */ + actionsSize = pFwupgCtx->imageSize - sizeof(struct HpmfwupgImageHeader); + + if (option & VERSIONCHECK_MODE || option & FORCE_MODE) + { + HpmDisplayUpgradeHeader(0); + } + + /* Perform actions defined in the image */ + while( ( pImagePtr < (pFwupgCtx->pImageData + pFwupgCtx->imageSize - + HPMFWUPG_MD5_SIGNATURE_LENGTH)) && + ( rc == HPMFWUPG_SUCCESS) ) + { + /* Get action record */ + pActionRecord = (struct HpmfwupgActionRecord*)pImagePtr; + + /* Validate action record checksum */ + if ( HpmfwupgCalculateChecksum((unsigned char*)pActionRecord, + sizeof(struct HpmfwupgActionRecord)) != 0 ) + { + lprintf(LOG_NOTICE," Invalid Action record."); + rc = HPMFWUPG_ERROR; + } + + if ( rc == HPMFWUPG_SUCCESS ) + { + switch( pActionRecord->actionType ) + { + case HPMFWUPG_ACTION_BACKUP_COMPONENTS: + { + /* Send prepare components command */ + struct HpmfwupgInitiateUpgradeActionCtx initUpgActionCmd; + + initUpgActionCmd.req.componentsMask = pFwupgCtx->compUpdateMask; + /* Action is prepare components */ + initUpgActionCmd.req.upgradeAction = HPMFWUPG_UPGRADE_ACTION_BACKUP; + rc = HpmfwupgInitiateUpgradeAction(intf, &initUpgActionCmd, pFwupgCtx); + pImagePtr += sizeof(struct HpmfwupgActionRecord); + + } + break; + case HPMFWUPG_ACTION_PREPARE_COMPONENTS: + { + int componentId; + /* Make sure every components specified by this action + supports the prepare components */ + + /* Component 'filtering' is done in PreUpdateCheck() and pFwupgCtx is set accordiongly */ + + for ( componentId = HPMFWUPG_COMPONENT_ID_0; + componentId < HPMFWUPG_COMPONENT_ID_MAX; + componentId++ ) + { + if ( (1 << componentId & pFwupgCtx->compUpdateMask.ComponentBits.byte) ) + { + if ( pFwupgCtx->genCompProp[componentId].GeneralCompProperties.bitfield.preparationSupport == 0 ) + { + lprintf(LOG_NOTICE," Prepare component not supported by component ID %d", componentId); + rc = HPMFWUPG_ERROR; + break; + } + } + } + + if ( rc == HPMFWUPG_SUCCESS ) + { + if ( pFwupgCtx->compUpdateMask.ComponentBits.byte != 0x00 ) + { + /* Send prepare components command */ + struct HpmfwupgInitiateUpgradeActionCtx initUpgActionCmd; + initUpgActionCmd.req.componentsMask = pFwupgCtx->compUpdateMask; + /* Action is prepare components */ + initUpgActionCmd.req.upgradeAction = HPMFWUPG_UPGRADE_ACTION_PREPARE; + rc = HpmfwupgInitiateUpgradeAction(intf, &initUpgActionCmd, pFwupgCtx); + + } + pImagePtr += sizeof(struct HpmfwupgActionRecord); + } + } + break; + + case HPMFWUPG_ACTION_UPLOAD_FIRMWARE: + /* Upload all firmware blocks */ + rc = HpmFwupgActionUploadFirmware + ( + pActionRecord->components, + pFwupgCtx, + &pImagePtr, + componentToUpload, + intf, + option, + &flagColdReset + ); + + break; + default: + lprintf(LOG_NOTICE," Invalid Action type. Cannot continue"); + rc = HPMFWUPG_ERROR; + break; + } + } + } + + HpmDisplayLine("-",78); + + if (flagColdReset) + { + fflush(stdout); + lprintf(LOG_NOTICE,"(*) Component requires Payload Cold Reset"); + } + return rc; +} + +static int HpmFwupgActionUploadFirmware +( + struct HpmfwupgComponentBitMask components, + struct HpmfwupgUpgradeCtx* pFwupgCtx, + unsigned char** pImagePtr, + int componentToUpload, + void *intf, + int option, + int *pFlagColdReset +) +{ + struct HpmfwupgFirmwareImage* pFwImage; + struct HpmfwupgInitiateUpgradeActionCtx initUpgActionCmd; + struct HpmfwupgUploadFirmwareBlockCtx uploadCmd; + struct HpmfwupgFinishFirmwareUploadCtx finishCmd; + // struct HpmfwupgGetComponentPropertiesCtx getCompProp; + VERSIONINFO *pVersionInfo; + time_t start,end; + + int rc = HPMFWUPG_SUCCESS; + int skip = TRUE; + unsigned char* pData, *pDataInitial; + unsigned char count; + unsigned int totalSent = 0; + unsigned char bufLength = 0; + unsigned int firmwareLength = 0; + + unsigned int displayFWLength = 0; + unsigned char *pDataTemp; + unsigned int imageOffset = 0x00; + unsigned int blockLength = 0x00; + unsigned int lengthOfBlock = 0x00; + unsigned int numTxPkts = 0; + unsigned int numRxPkts = 0; + unsigned char mode = 0; + unsigned char componentId = 0x00; + unsigned char componentIdByte = 0x00; + + /* Save component ID on which the upload is done */ + componentIdByte = components.ComponentBits.byte; + while ((componentIdByte>>=1)!=0) + { + componentId++; + } + pFwupgCtx->componentId = componentId; + + pVersionInfo = (VERSIONINFO*) &gVersionInfo[componentId]; + + pFwImage = (struct HpmfwupgFirmwareImage*)((*pImagePtr) + + sizeof(struct HpmfwupgActionRecord)); + + pDataInitial = ((unsigned char*)pFwImage + sizeof(struct HpmfwupgFirmwareImage)); + pData = pDataInitial; + + /* Get firmware length */ + firmwareLength = pFwImage->length[0]; + firmwareLength |= (pFwImage->length[1] << 8) & 0xff00; + firmwareLength |= (pFwImage->length[2] << 16) & 0xff0000; + firmwareLength |= (pFwImage->length[3] << 24) & 0xff000000; + + mode = TARGET_VER | IMAGE_VER; + + if (pVersionInfo->rollbackSupported) + { + mode |= ROLLBACK_VER; + } + + if ((option & DEBUG_MODE)) + { + printf("\n\n Comp ID : %d [%-20s]\n",pVersionInfo->componentId,pFwImage->desc); + } + else + { + HpmDisplayVersion(mode,pVersionInfo); + } + + if( (1 << componentId) & pFwupgCtx->compUpdateMask.ComponentBits.byte) + { + if( verbose ) { + lprintf(LOG_NOTICE,"Do not skip %d" , componentId); + } + skip = FALSE; + } + + if(!skip) + { + /* Initialize parameters */ + uploadCmd.req.blockNumber = 0; + + /* Check if we receive size in parameters */ + if(g_channel_buf_size != 0) + { + if (g_sa == BMC_SA) + { + bufLength = g_channel_buf_size - 9; /* Plan for overhead */ + } + else + { + bufLength = g_channel_buf_size - 11; /* Plan for overhead */ + } + } + else + { + /* Find max buffer length according the connection parameters */ + if ( is_remote() ) /*IPMI LAN*/ + { + bufLength = HPMFWUPG_SEND_DATA_COUNT_LAN - 2; + if (g_sa != BMC_SA) + bufLength -= 8; + } + else + { + int i; + i = get_driver_type(); + if ((i == DRV_MV || i == DRV_KCS) && /*open driver*/ + (g_sa == BMC_SA) ) + { + bufLength = HPMFWUPG_SEND_DATA_COUNT_KCS - 2; + } + else + { + if ( g_bus == 7 ) + { + bufLength = HPMFWUPG_SEND_DATA_COUNT_IPMBL; + } + else + { + bufLength = HPMFWUPG_SEND_DATA_COUNT_IPMB; + } + } + } + } + if (verbose) + printf("Upgrade buffer size = %d (%d)\n",bufLength,g_channel_buf_size); + + /* Send Initiate Upgrade Action */ + initUpgActionCmd.req.componentsMask = components; + /* Action is upgrade */ + initUpgActionCmd.req.upgradeAction = HPMFWUPG_UPGRADE_ACTION_UPGRADE; + rc = HpmfwupgInitiateUpgradeAction(intf, &initUpgActionCmd, pFwupgCtx); + + if (rc != HPMFWUPG_SUCCESS) + { + skip = TRUE; + } + + if ( (pVersionInfo->coldResetRequired) && (!skip)) + { + *pFlagColdReset = TRUE; + } + /* pDataInitial is the starting pointer of the image data */ + /* pDataTemp is one which we will move across */ + pData = pDataInitial; + pDataTemp = pDataInitial; + lengthOfBlock = firmwareLength; + totalSent = 0x00; + displayFWLength= firmwareLength; + time(&start); + + + while ( (pData < (pDataTemp+lengthOfBlock)) && (rc == HPMFWUPG_SUCCESS) ) + { + if ( (pData+bufLength) <= (pDataTemp+lengthOfBlock) ) + { + count = bufLength; + } + else + { + count = (unsigned char)((pDataTemp+lengthOfBlock) - pData); + } + memcpy(&uploadCmd.req.data, pData, bufLength); + + imageOffset = 0x00; + blockLength = 0x00; + numTxPkts++; + rc = HpmfwupgUploadFirmwareBlock(intf, &uploadCmd, pFwupgCtx, count, + &imageOffset,&blockLength); + numRxPkts++; + + if ( rc != HPMFWUPG_SUCCESS) + { + if ( rc == HPMFWUPG_UPLOAD_BLOCK_LENGTH ) + { + /* Retry with a smaller buffer length */ + if ( is_remote() ) // strstr(intf->name,"lan") != NULL + { + bufLength -= (unsigned char)8; + lprintf(LOG_INFO,"Trying reduced buffer length: %d", bufLength); + } + else + { + bufLength -= (unsigned char)1; + lprintf(LOG_INFO,"Trying reduced buffer length: %d", bufLength); + } + rc = HPMFWUPG_SUCCESS; + } + else if ( rc == HPMFWUPG_UPLOAD_RETRY ) + { + rc = HPMFWUPG_SUCCESS; + } + else + { + fflush(stdout); + lprintf(LOG_NOTICE,"\n Error in Upload FIRMWARE command [rc=%d]\n",rc); + lprintf(LOG_NOTICE,"\n TotalSent:0x%x ",totalSent); + /* Exiting from the function */ + rc = HPMFWUPG_ERROR; + } + } + else + { + if (blockLength > firmwareLength) + { + /* + * blockLength is the remaining length of the firmware to upload so + * if its greater than the firmware length then its kind of error + */ + lprintf(LOG_NOTICE,"\n Error in Upload FIRMWARE command [rc=%d]\n",rc); + lprintf(LOG_NOTICE,"\n TotalSent:0x%x Img offset:0x%x Blk length:0x%x Fwlen:0x%x\n", + totalSent,imageOffset,blockLength,firmwareLength); + rc = HPMFWUPG_ERROR; + } + totalSent += count; + if (imageOffset != 0x00) + { + /* block Length is valid */ + lengthOfBlock = blockLength; + pDataTemp = pDataInitial + imageOffset; + pData = pDataTemp; + if ( displayFWLength == firmwareLength) + { + /* This is basically used only to make sure that we display uptil 100% */ + displayFWLength = blockLength + totalSent; + } + } + else + { + pData += count; + } + time(&end); + /* + * Just added debug mode in case we need to see exactly how many bytes have + * gone through - Its a hidden option used mainly should be used for debugging + */ + if ( option & DEBUG_MODE) + { + fflush(stdout); + printf(" Blk Num : %02x Bytes : %05x \r\n", + uploadCmd.req.blockNumber,totalSent); + if (imageOffset || blockLength) + { + printf("\r--> ImgOff : %x BlkLen : %x\n",imageOffset,blockLength); + } + if (displayFWLength == totalSent) + { + printf(" Time Taken %02d:%02d\n",(end-start)/60, (end-start)%60); + printf("\n"); + } + } + else + { + HpmDisplayUpgrade(0,totalSent,displayFWLength,(end-start)); + } + uploadCmd.req.blockNumber++; + } + } + } + + if (skip) + { + + HpmDisplayUpgrade(1,0,0,0); + *pImagePtr = pDataInitial + firmwareLength; + } + + if + ( + (rc == HPMFWUPG_SUCCESS) + && + (!skip) + ) + { + /* Send finish component */ + /* Set image length */ + finishCmd.req.componentId = componentId; + /* We need to send the actual data that is sent + * not the comlete firmware image length + */ + finishCmd.req.imageLength[0] = totalSent & 0xFF; + finishCmd.req.imageLength[1] = (totalSent >> 8) & 0xFF; + finishCmd.req.imageLength[2] = (totalSent >> 16) & 0xFF; + finishCmd.req.imageLength[3] = (totalSent >> 24) & 0xFF; + rc = HpmfwupgFinishFirmwareUpload(intf, &finishCmd, pFwupgCtx); + if ( option & DEBUG_MODE) + printf("HpmfwupgFinishFirmwareUpload rc = %d sent = %d\n",rc,totalSent); + *pImagePtr = pDataInitial + firmwareLength; + } + + return rc; +} + +/**************************************************************************** +* +* Function Name: HpmfwupgActivationStage +* +* Description: This function the validation stage of a firmware upgrade +* procedure as defined in section 3.4 of the IPM Controller +* Firmware Upgrade Specification version 1.0 +* +*****************************************************************************/ +static int HpmfwupgActivationStage(void *intf, struct HpmfwupgUpgradeCtx* pFwupgCtx) +{ + int rc = HPMFWUPG_SUCCESS; + struct HpmfwupgActivateFirmwareCtx activateCmd; + struct HpmfwupgImageHeader* pImageHeader = (struct HpmfwupgImageHeader*) + pFwupgCtx->pImageData; + + /* Print out stuf...*/ + printf(" "); + fflush(stdout); + /* Activate new firmware */ + rc = HpmfwupgActivateFirmware(intf, &activateCmd, pFwupgCtx); + + if ( rc == HPMFWUPG_SUCCESS ) + { + /* Query self test result if supported by target and new image */ + if ( (pFwupgCtx->targetCap.GlobalCapabilities.bitField.ipmcSelftestCap == 1) || + (pImageHeader->imageCapabilities.bitField.imageSelfTest == 1) ) + { + struct HpmfwupgQuerySelftestResultCtx selfTestCmd; + rc = HpmfwupgQuerySelftestResult(intf, &selfTestCmd, pFwupgCtx); + + if ( rc == HPMFWUPG_SUCCESS ) + { + /* Get the self test result */ + if ( selfTestCmd.resp.result1 != 0x55 ) + { + /* Perform manual rollback if necessary */ + /* BACKUP/ MANUAL ROLLBACK not supported by this UA */ + lprintf(LOG_NOTICE," Self test failed:"); + lprintf(LOG_NOTICE," Result1 = %x", selfTestCmd.resp.result1); + lprintf(LOG_NOTICE," Result2 = %x", selfTestCmd.resp.result2); + rc = HPMFWUPG_ERROR; + } + } + else + { + /* Perform manual rollback if necessary */ + /* BACKUP / MANUAL ROLLBACK not supported by this UA */ + lprintf(LOG_NOTICE," Self test failed."); + } + } + } + + /* If activation / self test failed, query rollback status if automatic rollback supported */ + if ( rc == HPMFWUPG_ERROR ) + { + if ( (pFwupgCtx->targetCap.GlobalCapabilities.bitField.autRollback == 1) && + (pFwupgCtx->genCompProp[pFwupgCtx->componentId].GeneralCompProperties.bitfield.rollbackBackup != 0x00) ) + { + struct HpmfwupgQueryRollbackStatusCtx rollCmd; + lprintf(LOG_NOTICE," Getting rollback status..."); + fflush(stdout); + rc = HpmfwupgQueryRollbackStatus(intf, &rollCmd, pFwupgCtx); + } + } + + return rc; +} + +int HpmfwupgGetBufferFromFile(char* imageFilename, struct HpmfwupgUpgradeCtx* pFwupgCtx) +{ + int rc = HPMFWUPG_SUCCESS; + FILE* pImageFile = fopen(imageFilename, "rb"); + + if ( pImageFile == NULL ) + { + lprintf(LOG_NOTICE,"Cannot open image file %s", imageFilename); + rc = HPMFWUPG_ERROR; + } + + if ( rc == HPMFWUPG_SUCCESS ) + { + /* Get the raw data in file */ + fseek(pImageFile, 0, SEEK_END); + pFwupgCtx->imageSize = ftell(pImageFile); + pFwupgCtx->pImageData = malloc(sizeof(unsigned char)*pFwupgCtx->imageSize); + pFwupgCtx->compUpdateMask.ComponentBits.byte = 0; + rewind(pImageFile); + if ( pFwupgCtx->pImageData != NULL ) + { + fread(pFwupgCtx->pImageData, sizeof(unsigned char), pFwupgCtx->imageSize, pImageFile); + } + else + { + rc = HPMFWUPG_ERROR; + } + + fclose(pImageFile); + } + + return rc; +} + +int HpmfwupgGetDeviceId(void *intf, struct ipm_devid_rsp* pGetDevId) +{ + int rc = HPMFWUPG_SUCCESS; + struct ipmi_rs * rsp; + struct ipmi_rq req; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = BMC_GET_DEVICE_ID; + req.msg.data_len = 0; + + rsp = HpmfwupgSendCmd(intf, req, NULL); + + if ( rsp ) + { + if ( rsp->ccode == 0x00 ) + { + memcpy(pGetDevId, rsp->data, sizeof(struct ipm_devid_rsp)); + } + else + { + lprintf(LOG_NOTICE,"Error getting device ID, compcode = %x\n", rsp->ccode); + rc = HPMFWUPG_ERROR; + } + } + else + { + lprintf(LOG_NOTICE,"Error getting device ID\n"); + rc = HPMFWUPG_ERROR; + } + return rc; +} + +int HpmfwupgGetTargetUpgCapabilities(void *intf, + struct HpmfwupgGetTargetUpgCapabilitiesCtx* pCtx) +{ + int rc = HPMFWUPG_SUCCESS; + struct ipmi_rs * rsp; + struct ipmi_rq req; + + pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = HPMFWUPG_GET_TARGET_UPG_CAPABILITIES; + req.msg.data = (unsigned char*)&pCtx->req; + req.msg.data_len = sizeof(struct HpmfwupgGetTargetUpgCapabilitiesReq); + + rsp = HpmfwupgSendCmd(intf, req, NULL); + + if ( rsp ) + { + if ( rsp->ccode == 0x00 ) + { + memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgGetTargetUpgCapabilitiesResp)); + if ( verbose ) + { + lprintf(LOG_NOTICE,"TARGET UPGRADE CAPABILITIES"); + lprintf(LOG_NOTICE,"-------------------------------"); + lprintf(LOG_NOTICE,"HPM.1 version............%d ", pCtx->resp.hpmVersion); + lprintf(LOG_NOTICE,"Component 0 presence....[%c] ", pCtx->resp.componentsPresent.ComponentBits. + bitField.component0 ? 'y' : 'n'); + lprintf(LOG_NOTICE,"Component 1 presence....[%c] ", pCtx->resp.componentsPresent.ComponentBits. + bitField.component1 ? 'y' : 'n'); + lprintf(LOG_NOTICE,"Component 2 presence....[%c] ", pCtx->resp.componentsPresent.ComponentBits. + bitField.component2 ? 'y' : 'n'); + lprintf(LOG_NOTICE,"Component 3 presence....[%c] ", pCtx->resp.componentsPresent.ComponentBits. + bitField.component3 ? 'y' : 'n'); + lprintf(LOG_NOTICE,"Component 4 presence....[%c] ", pCtx->resp.componentsPresent.ComponentBits. + bitField.component4 ? 'y' : 'n'); + lprintf(LOG_NOTICE,"Component 5 presence....[%c] ", pCtx->resp.componentsPresent.ComponentBits. + bitField.component5 ? 'y' : 'n'); + lprintf(LOG_NOTICE,"Component 6 presence....[%c] ", pCtx->resp.componentsPresent.ComponentBits. + bitField.component6 ? 'y' : 'n'); + lprintf(LOG_NOTICE,"Component 7 presence....[%c] ", pCtx->resp.componentsPresent.ComponentBits. + bitField.component7 ? 'y' : 'n'); + lprintf(LOG_NOTICE,"Upgrade undesirable.....[%c] ", pCtx->resp.GlobalCapabilities. + bitField.fwUpgUndesirable ? 'y' : 'n'); + lprintf(LOG_NOTICE,"Aut rollback override...[%c] ", pCtx->resp.GlobalCapabilities. + bitField.autRollbackOverride ? 'y' : 'n'); + lprintf(LOG_NOTICE,"IPMC degraded...........[%c] ", pCtx->resp.GlobalCapabilities. + bitField.ipmcDegradedDurinUpg ? 'y' : 'n'); + lprintf(LOG_NOTICE,"Defered activation......[%c] ", pCtx->resp.GlobalCapabilities. + bitField.deferActivation ? 'y' : 'n'); + lprintf(LOG_NOTICE,"Service affected........[%c] ", pCtx->resp.GlobalCapabilities. + bitField.servAffectDuringUpg ? 'y' : 'n'); + lprintf(LOG_NOTICE,"Manual rollback.........[%c] ", pCtx->resp.GlobalCapabilities. + bitField.manualRollback ? 'y' : 'n'); + lprintf(LOG_NOTICE,"Automatic rollback......[%c] ", pCtx->resp.GlobalCapabilities. + bitField.autRollback ? 'y' : 'n'); + lprintf(LOG_NOTICE,"Self test...............[%c] ", pCtx->resp.GlobalCapabilities. + bitField.ipmcSelftestCap ? 'y' : 'n'); + lprintf(LOG_NOTICE,"Upgrade timeout.........[%d sec] ", pCtx->resp.upgradeTimeout*5); + lprintf(LOG_NOTICE,"Self test timeout.......[%d sec] ", pCtx->resp.selftestTimeout*5); + lprintf(LOG_NOTICE,"Rollback timeout........[%d sec] ", pCtx->resp.rollbackTimeout*5); + lprintf(LOG_NOTICE,"Inaccessibility timeout.[%d sec] \n", pCtx->resp.inaccessTimeout*5); + } + } + else + { + lprintf(LOG_NOTICE,"Error getting target upgrade capabilities\n", rsp->ccode); + rc = HPMFWUPG_ERROR; + } + } + else + { + lprintf(LOG_NOTICE,"Error getting target upgrade capabilities\n"); + rc = HPMFWUPG_ERROR; + } + + + + return rc; +} + + +int HpmfwupgGetComponentProperties(void *intf, struct HpmfwupgGetComponentPropertiesCtx* pCtx) +{ + int rc = HPMFWUPG_SUCCESS; + struct ipmi_rs * rsp; + struct ipmi_rq req; + + pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = HPMFWUPG_GET_COMPONENT_PROPERTIES; + req.msg.data = (unsigned char*)&pCtx->req; + req.msg.data_len = sizeof(struct HpmfwupgGetComponentPropertiesReq); + + rsp = HpmfwupgSendCmd(intf, req, NULL); + + if ( rsp ) + { + if ( rsp->ccode == 0x00 ) + { + switch ( pCtx->req.selector ) + { + case HPMFWUPG_COMP_GEN_PROPERTIES: + memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgGetGeneralPropResp)); + if ( verbose ) + { + lprintf(LOG_NOTICE,"GENERAL PROPERTIES"); + lprintf(LOG_NOTICE,"-------------------------------"); + lprintf(LOG_NOTICE,"Payload cold reset req....[%c] ", pCtx->resp.Response.generalPropResp. + GeneralCompProperties.bitfield.payloadColdReset ? 'y' : 'n'); + lprintf(LOG_NOTICE,"Def. activation supported.[%c] ", pCtx->resp.Response.generalPropResp. + GeneralCompProperties.bitfield.deferredActivation ? 'y' : 'n'); + lprintf(LOG_NOTICE,"Comparison supported......[%c] ", pCtx->resp.Response.generalPropResp. + GeneralCompProperties.bitfield.comparisonSupport ? 'y' : 'n'); + lprintf(LOG_NOTICE,"Preparation supported.....[%c] ", pCtx->resp.Response.generalPropResp. + GeneralCompProperties.bitfield.preparationSupport ? 'y' : 'n'); + lprintf(LOG_NOTICE,"Rollback supported........[%c] \n", pCtx->resp.Response.generalPropResp. + GeneralCompProperties.bitfield.rollbackBackup ? 'y' : 'n'); + } + break; + case HPMFWUPG_COMP_CURRENT_VERSION: + memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgGetCurrentVersionResp)); + if ( verbose ) + { + lprintf(LOG_NOTICE,"Current Version: "); + lprintf(LOG_NOTICE," Major: %d", pCtx->resp.Response.currentVersionResp.currentVersion[0]); + lprintf(LOG_NOTICE," Minor: %x", pCtx->resp.Response.currentVersionResp.currentVersion[1]); + lprintf(LOG_NOTICE," Aux : %03d %03d %03d %03d\n", pCtx->resp.Response.currentVersionResp.currentVersion[2], + pCtx->resp.Response.currentVersionResp.currentVersion[3], + pCtx->resp.Response.currentVersionResp.currentVersion[4], + pCtx->resp.Response.currentVersionResp.currentVersion[5]); + } + break; + case HPMFWUPG_COMP_DESCRIPTION_STRING: + memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgGetDescStringResp)); + if ( verbose ) + { + lprintf(LOG_NOTICE,"Description string: %s\n", pCtx->resp.Response.descStringResp.descString); + } + break; + case HPMFWUPG_COMP_ROLLBACK_FIRMWARE_VERSION: + memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgGetRollbackFwVersionResp)); + if ( verbose ) + { + lprintf(LOG_NOTICE,"Rollback FW Version: "); + lprintf(LOG_NOTICE," Major: %d", pCtx->resp.Response.rollbackFwVersionResp.rollbackFwVersion[0]); + lprintf(LOG_NOTICE," Minor: %x", pCtx->resp.Response.rollbackFwVersionResp.rollbackFwVersion[1]); + lprintf(LOG_NOTICE," Aux : %03d %03d %03d %03d\n", pCtx->resp.Response.rollbackFwVersionResp.rollbackFwVersion[2], + pCtx->resp.Response.rollbackFwVersionResp.rollbackFwVersion[3], + pCtx->resp.Response.rollbackFwVersionResp.rollbackFwVersion[4], + pCtx->resp.Response.rollbackFwVersionResp.rollbackFwVersion[5]); + } + break; + case HPMFWUPG_COMP_DEFERRED_FIRMWARE_VERSION: + memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgGetDeferredFwVersionResp)); + if ( verbose ) + { + lprintf(LOG_NOTICE,"Deferred FW Version: "); + lprintf(LOG_NOTICE," Major: %d", pCtx->resp.Response.deferredFwVersionResp.deferredFwVersion[0]); + lprintf(LOG_NOTICE," Minor: %x", pCtx->resp.Response.deferredFwVersionResp.deferredFwVersion[1]); + lprintf(LOG_NOTICE," Aux : %03d %03d %03d %03d\n", pCtx->resp.Response.deferredFwVersionResp.deferredFwVersion[2], + pCtx->resp.Response.deferredFwVersionResp.deferredFwVersion[3], + pCtx->resp.Response.deferredFwVersionResp.deferredFwVersion[4], + pCtx->resp.Response.deferredFwVersionResp.deferredFwVersion[5]); + } + break; + // OEM Properties command + case HPMFWUPG_COMP_OEM_PROPERTIES: + memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgGetOemProperties)); + if ( verbose ) + { + unsigned char i = 0; + lprintf(LOG_NOTICE,"OEM Properties: "); + for (i=0; i < HPMFWUPG_OEM_LENGTH; i++) + { + lprintf(LOG_NOTICE," 0x%x ", pCtx->resp.Response.oemProperties.oemRspData[i]); + } + } + break; + default: + lprintf(LOG_NOTICE,"Unsupported component selector"); + rc = HPMFWUPG_ERROR; + break; + } + } + else + { + lprintf(LOG_NOTICE,"Error getting component properties, compcode = %x\n", rsp->ccode); + rc = HPMFWUPG_ERROR; + } + } + else + { + lprintf(LOG_NOTICE,"Error getting component properties\n"); + rc = HPMFWUPG_ERROR; + } + + + return rc; +} + +int HpmfwupgAbortUpgrade(void *intf, struct HpmfwupgAbortUpgradeCtx* pCtx) +{ + int rc = HPMFWUPG_SUCCESS; + struct ipmi_rs * rsp; + struct ipmi_rq req; + + pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = HPMFWUPG_ABORT_UPGRADE; + req.msg.data = (unsigned char*)&pCtx->req; + req.msg.data_len = sizeof(struct HpmfwupgAbortUpgradeReq); + + rsp = HpmfwupgSendCmd(intf, req, NULL); + + if ( rsp ) + { + if ( rsp->ccode != 0x00 ) + { + lprintf(LOG_NOTICE,"Error aborting upgrade, compcode = %x\n", rsp->ccode); + rc = HPMFWUPG_ERROR; + } + } + else + { + lprintf(LOG_NOTICE,"Error aborting upgrade\n"); + rc = HPMFWUPG_ERROR; + } + return rc; +} + +int HpmfwupgInitiateUpgradeAction(void *intf, struct HpmfwupgInitiateUpgradeActionCtx* pCtx, + struct HpmfwupgUpgradeCtx* pFwupgCtx) +{ + int rc = HPMFWUPG_SUCCESS; + struct ipmi_rs * rsp; + struct ipmi_rq req; + + pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = HPMFWUPG_INITIATE_UPGRADE_ACTION; + req.msg.data = (unsigned char*)&pCtx->req; + req.msg.data_len = sizeof(struct HpmfwupgInitiateUpgradeActionReq); + + rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx); + + if ( rsp ) + { + /* Long duration command handling */ + if ( rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS ) + { + rc = HpmfwupgWaitLongDurationCmd(intf, pFwupgCtx); + } + else if ( rsp->ccode != 0x00 ) + { + lprintf(LOG_NOTICE,"Error initiating upgrade action, compcode = %x %s\n", + rsp->ccode, hpm_decode_cc(req.msg.cmd,rsp->ccode)); + rc = HPMFWUPG_ERROR; + } + } + else + { + lprintf(LOG_NOTICE,"Error initiating upgrade action\n"); + rc = HPMFWUPG_ERROR; + } + + return rc; +} + +int HpmfwupgUploadFirmwareBlock(void *intf, struct HpmfwupgUploadFirmwareBlockCtx* pCtx, + struct HpmfwupgUpgradeCtx* pFwupgCtx, int count + ,unsigned int *imageOffset, unsigned int *blockLength ) +{ + int rc = HPMFWUPG_SUCCESS; + struct ipmi_rs * rsp; + struct ipmi_rq req; + + pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = HPMFWUPG_UPLOAD_FIRMWARE_BLOCK; + req.msg.data = (unsigned char*)&pCtx->req; + /* 2 is the size of the upload struct - data */ + req.msg.data_len = 2 + count; + + rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx); + + if ( rsp ) + { + if ( rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS || + rsp->ccode == 0x00 ) + { + /* + * We need to check if the response also contains the next upload firmware offset + * and the firmware length in its response - These are optional but very vital + */ + if ( rsp->data_len > 1 ) + { + /* + * If the response data length is greater than 1 it should contain both the + * the Section offset and section length. Because we cannot just have + * Section offset without section length so the length should be 9 + */ + if ( rsp->data_len == 9 ) + { + /* rsp->data[1] - LSB rsp->data[2] - rsp->data[3] = MSB */ + *imageOffset = (rsp->data[4] << 24) + (rsp->data[3] << 16) + (rsp->data[2] << 8) + rsp->data[1]; + *blockLength = (rsp->data[8] << 24) + (rsp->data[7] << 16) + (rsp->data[6] << 8) + rsp->data[5]; + } + else + { + /* + * The Spec does not say much for this kind of errors where the + * firmware returned only offset and length so currently returning it + * as 0x82 - Internal CheckSum Error + */ + lprintf(LOG_NOTICE,"Error wrong rsp->datalen %d for Upload Firmware block command\n",rsp->data_len); + rsp->ccode = HPMFWUPG_INT_CHECKSUM_ERROR; + } + } + } + /* Long duration command handling */ + if ( rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS ) + { + rc = HpmfwupgWaitLongDurationCmd(intf, pFwupgCtx); + } + else if (rsp->ccode != 0x00) + { + /* + * PATCH --> This validation is to handle retryables errors codes on IPMB bus. + * This will be fixed in the next release of open ipmi and this + * check will have to be removed. (Buggy version = 39) + */ + if ( HPMFWUPG_IS_RETRYABLE(rsp->ccode) ) + { + lprintf(LOG_DEBUG,"HPM: [PATCH]Retryable error detected"); + rc = HPMFWUPG_UPLOAD_RETRY; + } + /* + * If completion code = 0xc7, we will retry with a reduced buffer length. + * Do not print error. + */ + else if ( rsp->ccode == IPMI_CC_REQ_DATA_INV_LENGTH ) + { + rc = HPMFWUPG_UPLOAD_BLOCK_LENGTH; + } + else + { + lprintf(LOG_NOTICE,"Error uploading firmware block, compcode = %x\n", rsp->ccode); + rc = HPMFWUPG_ERROR; + } + } + } + else + { + lprintf(LOG_NOTICE,"Error uploading firmware block\n"); + rc = HPMFWUPG_ERROR; + } + + return rc; +} + +int HpmfwupgFinishFirmwareUpload(void *intf, struct HpmfwupgFinishFirmwareUploadCtx* pCtx, + struct HpmfwupgUpgradeCtx* pFwupgCtx) +{ + int rc = HPMFWUPG_SUCCESS; + struct ipmi_rs * rsp; + struct ipmi_rq req; + + pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = HPMFWUPG_FINISH_FIRMWARE_UPLOAD; + req.msg.data = (unsigned char*)&pCtx->req; + req.msg.data_len = sizeof(struct HpmfwupgFinishFirmwareUploadReq); + + rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx); + + if ( rsp ) + { + /* Long duration command handling */ + if ( rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS) + { + rc = HpmfwupgWaitLongDurationCmd(intf, pFwupgCtx); + } + else if ( rsp->ccode != IPMI_CC_OK ) + { + lprintf(LOG_NOTICE,"Error finishing firmware upload, compcode = %x %s\n", + rsp->ccode, hpm_decode_cc(req.msg.cmd,rsp->ccode)); + rc = HPMFWUPG_ERROR; + } + } + else + { + lprintf(LOG_NOTICE,"Error finishing firmware upload\n"); + rc = HPMFWUPG_ERROR; + } + + return rc; +} + +int HpmfwupgActivateFirmware(void *intf, struct HpmfwupgActivateFirmwareCtx* pCtx, + struct HpmfwupgUpgradeCtx* pFwupgCtx) +{ + int rc = HPMFWUPG_SUCCESS; + struct ipmi_rs * rsp; + struct ipmi_rq req; + + pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = HPMFWUPG_ACTIVATE_FIRMWARE; + req.msg.data = (unsigned char*)&pCtx->req; + req.msg.data_len = sizeof(struct HpmfwupgActivateFirmwareReq) - + (!pCtx->req.rollback_override ? 1 : 0); + + rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx); + + if ( rsp ) + { + /* Long duration command handling */ + if (rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS) + { + printf("Waiting firmware activation..."); + fflush(stdout); + + rc = HpmfwupgWaitLongDurationCmd(intf, pFwupgCtx); + + if ( rc == HPMFWUPG_SUCCESS ) + { + lprintf(LOG_NOTICE,"OK"); + } + else + { + lprintf(LOG_NOTICE,"Failed"); + } + } + else if (rsp->ccode == HPMFWUPG_NOT_SUPPORTED_NOW) /*0xd5*/ + { + printf("Activation already completed.\n"); + rc = HPMFWUPG_SUCCESS; + } + else if ( rsp->ccode != IPMI_CC_OK ) + { + lprintf(LOG_NOTICE,"Error activating firmware, compcode = %x\n", + rsp->ccode); + rc = HPMFWUPG_ERROR; + } + } + else + { + lprintf(LOG_NOTICE,"Error activating firmware\n"); + rc = HPMFWUPG_ERROR; + } + + return rc; +} + +int HpmfwupgGetUpgradeStatus(void *intf, struct HpmfwupgGetUpgradeStatusCtx* pCtx, + struct HpmfwupgUpgradeCtx* pFwupgCtx) +{ + int rc = HPMFWUPG_SUCCESS; + struct ipmi_rs * rsp; + struct ipmi_rq req; + + pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = HPMFWUPG_GET_UPGRADE_STATUS; + req.msg.data = (unsigned char*)&pCtx->req; + req.msg.data_len = sizeof(struct HpmfwupgGetUpgradeStatusReq); + + rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx); + + if ( rsp ) + { + if ( rsp->ccode == 0x00 ) + { + memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgGetUpgradeStatusResp)); + if ( verbose > 1 ) + { + lprintf(LOG_NOTICE,"Upgrade status:"); + lprintf(LOG_NOTICE," Command in progress: %x", pCtx->resp.cmdInProcess); + lprintf(LOG_NOTICE," Last command completion code: %x", pCtx->resp.lastCmdCompCode); + } + } + /* + * PATCH --> This validation is to handle retryables errors codes on IPMB bus. + * This will be fixed in the next release of open ipmi and this + * check will have to be removed. (Buggy version = 39) + */ + else if ( HPMFWUPG_IS_RETRYABLE(rsp->ccode) ) + { + lprintf(LOG_DEBUG,"HPM: [PATCH]Retryable error detected"); + + pCtx->resp.lastCmdCompCode = HPMFWUPG_COMMAND_IN_PROGRESS; + } + else + { + if ( verbose ) + { + lprintf(LOG_NOTICE,"Error getting upgrade status, compcode = %x\n", rsp->ccode); + rc = HPMFWUPG_ERROR; + } + } + } + else + { + if ( verbose ) + { + lprintf(LOG_NOTICE,"Error getting upgrade status"); + rc = HPMFWUPG_ERROR; + } + } + + return rc; +} + +int HpmfwupgManualFirmwareRollback(void *intf, struct HpmfwupgManualFirmwareRollbackCtx* pCtx, + struct HpmfwupgUpgradeCtx* pFwupgCtx) +{ + int rc = HPMFWUPG_SUCCESS; + struct ipmi_rs * rsp; + struct ipmi_rq req; + + pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = HPMFWUPG_MANUAL_FIRMWARE_ROLLBACK; + req.msg.data = (unsigned char*)&pCtx->req; + req.msg.data_len = sizeof(struct HpmfwupgManualFirmwareRollbackReq); + + rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx); + + if ( rsp ) + { + /* Long duration command handling */ + if ( rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS ) + { + struct HpmfwupgQueryRollbackStatusCtx resCmd; + printf("Waiting firmware rollback..."); + fflush(stdout); + rc = HpmfwupgQueryRollbackStatus(intf, &resCmd, pFwupgCtx); + } + else if ( rsp->ccode != 0x00 ) + { + lprintf(LOG_NOTICE,"Error sending manual rollback, compcode = %x\n", rsp->ccode); + rc = HPMFWUPG_ERROR; + } + } + else + { + lprintf(LOG_NOTICE,"Error sending manual rollback\n"); + rc = HPMFWUPG_ERROR; + } + return rc; +} + +int HpmfwupgQueryRollbackStatus(void *intf, struct HpmfwupgQueryRollbackStatusCtx* pCtx, + struct HpmfwupgUpgradeCtx* pFwupgCtx) +{ + int rc = HPMFWUPG_SUCCESS; + struct ipmi_rs * rsp; + struct ipmi_rq req; + unsigned int rollbackTimeout = 0; + unsigned int timeoutSec1, timeoutSec2; + + pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = HPMFWUPG_QUERY_ROLLBACK_STATUS; + req.msg.data = (unsigned char*)&pCtx->req; + req.msg.data_len = sizeof(struct HpmfwupgQueryRollbackStatusReq); + + /* + * If we are not in upgrade context, we use default timeout values + */ + if ( pFwupgCtx != NULL ) + { + rollbackTimeout = pFwupgCtx->targetCap.rollbackTimeout*5; + } + else + { + struct HpmfwupgGetTargetUpgCapabilitiesCtx targetCapCmd; + verbose--; + rc = HpmfwupgGetTargetUpgCapabilities(intf, &targetCapCmd); + verbose++; + if ( rc == HPMFWUPG_SUCCESS ) + { + rollbackTimeout = targetCapCmd.resp.rollbackTimeout *5; + } + else + { + rollbackTimeout = HPMFWUPG_DEFAULT_UPGRADE_TIMEOUT; + } + } + + /* Poll rollback status until completion or timeout */ + timeoutSec1 = (uint32_t)time(NULL); + timeoutSec2 = (uint32_t)time(NULL); + do + { + /* Must wait at least 100 ms between status requests */ + os_usleep(0,100000); + rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx); + /* + * PATCH --> This validation is to handle retryables errors codes on IPMB bus. + * This will be fixed in the next release of open ipmi and this + * check will have to be removed. (Buggy version = 39) + */ + if ( rsp ) + { + if ( HPMFWUPG_IS_RETRYABLE(rsp->ccode) ) + { + lprintf(LOG_DEBUG,"HPM: [PATCH]Retryable error detected"); + rsp->ccode = HPMFWUPG_COMMAND_IN_PROGRESS; + } + } + timeoutSec2 = (uint32_t)time(NULL); + + }while( rsp && + (rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS) && + (timeoutSec2 - timeoutSec1 < rollbackTimeout ) ); + + if ( rsp ) + { + if ( rsp->ccode == 0x00 ) + { + memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgQueryRollbackStatusResp)); + if ( pCtx->resp.rollbackComp.ComponentBits.byte != 0 ) + { + /* Rollback occured */ + lprintf(LOG_NOTICE,"Rollback occured on component mask: 0x%02x", + pCtx->resp.rollbackComp.ComponentBits.byte); + } + else + { + lprintf(LOG_NOTICE,"No Firmware rollback occured"); + } + } + else if ( rsp->ccode == 0x81 ) + { + lprintf(LOG_NOTICE,"Rollback failed on component mask: 0x%02x", + pCtx->resp.rollbackComp.ComponentBits.byte); + rc = HPMFWUPG_ERROR; + } + else + { + lprintf(LOG_NOTICE,"Error getting rollback status, compcode = %x", rsp->ccode); + rc = HPMFWUPG_ERROR; + } + } + else + { + lprintf(LOG_NOTICE,"Error getting upgrade status\n"); + rc = HPMFWUPG_ERROR; + } + + return rc; +} + +int HpmfwupgQuerySelftestResult(void *intf, struct HpmfwupgQuerySelftestResultCtx* pCtx, + struct HpmfwupgUpgradeCtx* pFwupgCtx) +{ + int rc = HPMFWUPG_SUCCESS; + struct ipmi_rs * rsp; + struct ipmi_rq req; + unsigned char selfTestTimeout = 0; + unsigned int timeoutSec1, timeoutSec2; + + pCtx->req.picmgId = HPMFWUPG_PICMG_IDENTIFIER; + + /* + * If we are not in upgrade context, we use default timeout values + */ + if ( pFwupgCtx != NULL ) + { + /* Getting selftest timeout from new image */ + struct HpmfwupgImageHeader* pImageHeader = (struct HpmfwupgImageHeader*) + pFwupgCtx->pImageData; + selfTestTimeout = pImageHeader->selfTestTimeout; + } + else + { + selfTestTimeout = HPMFWUPG_DEFAULT_UPGRADE_TIMEOUT; + } + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = HPMFWUPG_QUERY_SELFTEST_RESULT; + req.msg.data = (unsigned char*)&pCtx->req; + req.msg.data_len = sizeof(struct HpmfwupgQuerySelftestResultReq); + + + /* Poll rollback status until completion or timeout */ + timeoutSec1 = (uint32_t)time(NULL); + timeoutSec2 = (uint32_t)time(NULL); + do + { + /* Must wait at least 100 ms between status requests */ + os_usleep(0,100000); + rsp = HpmfwupgSendCmd(intf, req, pFwupgCtx); + /* + * PATCH --> This validation is to handle retryables errors codes on IPMB bus. + * This will be fixed in the next release of open ipmi and this + * check will have to be removed. (Buggy version = 39) + */ + if ( rsp ) + { + if ( HPMFWUPG_IS_RETRYABLE(rsp->ccode) ) + { + lprintf(LOG_DEBUG,"HPM: [PATCH]Retryable error detected"); + rsp->ccode = HPMFWUPG_COMMAND_IN_PROGRESS; + } + } + timeoutSec2 = (uint32_t)time(NULL); + + }while( rsp && + (rsp->ccode == HPMFWUPG_COMMAND_IN_PROGRESS) && + (timeoutSec2 - timeoutSec1 < selfTestTimeout ) ); + + if ( rsp ) + { + if ( rsp->ccode == 0x00 ) + { + memcpy(&pCtx->resp, rsp->data, sizeof(struct HpmfwupgQuerySelftestResultResp)); + if ( verbose ) + { + lprintf(LOG_NOTICE,"Self test results:"); + lprintf(LOG_NOTICE,"Result1 = %x", pCtx->resp.result1); + lprintf(LOG_NOTICE,"Result2 = %x", pCtx->resp.result2); + } + } + else + { + lprintf(LOG_NOTICE,"Error getting self test results, compcode = %x\n", rsp->ccode); + rc = HPMFWUPG_ERROR; + } + } + else + { + lprintf(LOG_NOTICE,"Error getting upgrade status\n"); + rc = HPMFWUPG_ERROR; + } + + return rc; +} + +struct ipmi_rs * HpmfwupgSendCmd(void *intf, struct ipmi_rq req, + struct HpmfwupgUpgradeCtx* pFwupgCtx ) +{ + struct ipmi_rs * rsp; + unsigned int inaccessTimeout = 0, inaccessTimeoutCounter = 0; + unsigned int upgradeTimeout = 0, upgradeTimeoutCounter = 0; + unsigned int timeoutSec1, timeoutSec2; + unsigned char retry = 0; + static struct ipmi_rs fakeRsp; + int rv, rsp_len; + + /* + * If we are not in upgrade context, we use default timeout values + */ + if ( pFwupgCtx != NULL ) + { + inaccessTimeout = pFwupgCtx->targetCap.inaccessTimeout*5; + upgradeTimeout = pFwupgCtx->targetCap.upgradeTimeout*5; + } + else + { + /* keeping the inaccessTimeout to 60 seconds results in almost 2900 retries + * So if the target is not available it will be retrying the command for 2900 + * times which is not effecient -So reducing the Timout to 5 seconds which is + * almost 200 retries if it continuously recieves 0xC3 as completion code. + */ + inaccessTimeout = HPMFWUPG_DEFAULT_UPGRADE_TIMEOUT; + upgradeTimeout = HPMFWUPG_DEFAULT_UPGRADE_TIMEOUT; + } + + timeoutSec1 = (uint32_t)time(NULL); + + do + { + static unsigned char isValidSize = FALSE; + rv = ipmi_sendrecv(&req, fakeRsp.data, &rsp_len); + if( rv < 0) + { + #define HPM_LAN_PACKET_RESIZE_LIMIT 6 + + if(is_remote()) /* also covers lanplus */ + { + static int errorCount=0; + + lprintf(LOG_DEBUG,"HPM: no response available"); + lprintf(LOG_DEBUG,"HPM: the command may be rejected for " \ + "security reasons"); + + if + ( + req.msg.netfn == IPMI_NETFN_PICMG + && + req.msg.cmd == HPMFWUPG_UPLOAD_FIRMWARE_BLOCK + && + errorCount < HPM_LAN_PACKET_RESIZE_LIMIT + && + (!isValidSize) + ) + { + lprintf(LOG_DEBUG,"HPM: upload firmware block API called"); + lprintf(LOG_DEBUG,"HPM: returning length error to force resize"); + + fakeRsp.ccode = IPMI_CC_REQ_DATA_INV_LENGTH; + rv = fakeRsp.ccode; + rsp = &fakeRsp; + errorCount++; + } + else if + ( + req.msg.netfn == IPMI_NETFN_PICMG + && + ( req.msg.cmd == HPMFWUPG_ACTIVATE_FIRMWARE || + req.msg.cmd == HPMFWUPG_MANUAL_FIRMWARE_ROLLBACK ) + ) + { + /* + * rsp == NULL and command activate firmware or manual firmware + * rollback most likely occurs when we have sent a firmware activation + * request. Fake a command in progress response. + */ + lprintf(LOG_DEBUG,"HPM: activate/rollback firmware API called"); + lprintf(LOG_DEBUG,"HPM: returning in progress to handle IOL session lost"); + + fakeRsp.ccode = HPMFWUPG_COMMAND_IN_PROGRESS; + rv = fakeRsp.ccode; + rsp = &fakeRsp; + } + else if + ( + req.msg.netfn == IPMI_NETFN_PICMG + && + ( req.msg.cmd == HPMFWUPG_QUERY_ROLLBACK_STATUS || + req.msg.cmd == HPMFWUPG_GET_UPGRADE_STATUS ) + ) + { + /* + * rsp == NULL and command get upgrade status or query rollback + * status most likely occurs when we are waiting for firmware + * activation. Try to re-open the IOL session (re-open will work + * once the IPMC recovers from firmware activation. + */ + + lprintf(LOG_DEBUG,"HPM: upg/rollback status firmware API called"); + lprintf(LOG_DEBUG,"HPM: try to re-open IOL session"); + + { + /* force session re-open */ + ipmi_close_(); + os_usleep(inaccessTimeout,0); + + /* Fake timeout to retry command */ + fakeRsp.ccode = 0xc3; + rv = fakeRsp.ccode; + rsp = &fakeRsp; + } + } + } + } + + /* Handle inaccessibility timeout (rsp = NULL if IOL) */ + if ( rv < 0 || rv == 0xff || rv == 0xc3 || rv == 0xd3 ) + { + if ( inaccessTimeoutCounter < inaccessTimeout ) + { + timeoutSec2 = (uint32_t)time(NULL); + if ( timeoutSec2 > timeoutSec1 ) + { + inaccessTimeoutCounter += timeoutSec2 - timeoutSec1; + timeoutSec1 = (uint32_t)time(NULL); + } + os_usleep(0,100000); + retry = 1; + } + else + { + retry = 0; + } + } + /* Handle node busy timeout */ + else if ( rv == 0xc0 ) + { + if ( upgradeTimeoutCounter < upgradeTimeout ) + { + timeoutSec2 = (uint32_t)time(NULL); + if ( timeoutSec2 > timeoutSec1 ) + { + timeoutSec1 = (uint32_t)time(NULL); + // upgradeTimeoutCounter += timeoutSec2 - timeoutSec1; + upgradeTimeoutCounter += 1; + } + os_usleep(0,100000); + retry = 1; + } + else + { + retry = 0; + } + } + else + { + #ifdef ENABLE_OPENIPMI_V39_PATCH + if( rv == IPMI_CC_OK ) + { + errorCount = 0 ; + } + #endif + retry = 0; + + if + ( + req.msg.netfn == IPMI_NETFN_PICMG + && + req.msg.cmd == HPMFWUPG_UPLOAD_FIRMWARE_BLOCK + && + (!isValidSize) + ) + { + lprintf(LOG_INFO,"Buffer length is now considered valid" ); + + isValidSize = TRUE; + } + } + }while( retry ); + + if (rv < 0) rsp = NULL; + else { + rsp = &fakeRsp; /*has data already*/ + rsp->ccode = (uchar)rv; + rsp->session.payloadtype = 0; /*IPMI_PAYLOAD_TYPE_IPMI*/ + rsp->data_len = rsp_len; + } + return rsp; +} + +int HpmfwupgWaitLongDurationCmd(void *intf, struct HpmfwupgUpgradeCtx* pFwupgCtx) +{ + int rc = HPMFWUPG_SUCCESS; + unsigned int upgradeTimeout = 0; + unsigned int timeoutSec1, timeoutSec2; + struct HpmfwupgGetUpgradeStatusCtx upgStatusCmd; + + /* + * If we are not in upgrade context, we use default timeout values + */ + if ( pFwupgCtx != NULL ) + { + upgradeTimeout = pFwupgCtx->targetCap.upgradeTimeout*5; + if ( verbose ) + printf("Use File Upgrade Capabilities: %i seconds\n", upgradeTimeout); + } + else + { + /* Try to retreive from Caps */ + struct HpmfwupgGetTargetUpgCapabilitiesCtx targetCapCmd; + + if(HpmfwupgGetTargetUpgCapabilities(intf, &targetCapCmd) != HPMFWUPG_SUCCESS) + { + upgradeTimeout = HPMFWUPG_DEFAULT_UPGRADE_TIMEOUT; + + if ( verbose ) + printf("Use default timeout: %i seconds\n", upgradeTimeout); + } + else + { + upgradeTimeout = (targetCapCmd.resp.upgradeTimeout * 5); + if ( verbose ) + printf("Use Command Upgrade Capabilities Timeout: %i seconds\n", upgradeTimeout); + } + } + + if(rc == HPMFWUPG_SUCCESS) + { + /* Poll upgrade status until completion or timeout*/ + timeoutSec1 = (uint32_t)time(NULL); + timeoutSec2 = (uint32_t)time(NULL); + rc = HpmfwupgGetUpgradeStatus(intf, &upgStatusCmd, pFwupgCtx); + } + + while( + (upgStatusCmd.resp.lastCmdCompCode == HPMFWUPG_COMMAND_IN_PROGRESS ) && + (timeoutSec2 - timeoutSec1 < upgradeTimeout ) && + (rc == HPMFWUPG_SUCCESS) + ) + { + /* Must wait at least 1000 ms between status requests */ + os_usleep(0,1000000); + rc = HpmfwupgGetUpgradeStatus(intf, &upgStatusCmd, pFwupgCtx); + //printf("Get Status: %x - %x = %x _ %x [%x]\n", timeoutSec2, timeoutSec1,(timeoutSec2 - timeoutSec1),upgradeTimeout, rc); + } + + if ( upgStatusCmd.resp.lastCmdCompCode != 0x00 ) + { + if ( verbose ) + { + lprintf(LOG_NOTICE,"Error waiting for command %x, compcode = %x", + upgStatusCmd.resp.cmdInProcess, + upgStatusCmd.resp.lastCmdCompCode, + hpm_decode_cc(upgStatusCmd.resp.cmdInProcess, + upgStatusCmd.resp.lastCmdCompCode)); + } + rc = HPMFWUPG_ERROR; + } + + return rc; +} + +unsigned char HpmfwupgCalculateChecksum(unsigned char* pData, unsigned int length) +{ + unsigned char checksum = 0; + int dataIdx = 0; + + for ( dataIdx = 0; dataIdx < (int)length; dataIdx++ ) + { + checksum += pData[dataIdx]; + } + return checksum; +} + +static void HpmfwupgPrintUsage(void) +{ + lprintf(LOG_NOTICE,"help - This help menu"); + lprintf(LOG_NOTICE,"check - Check the target information"); + lprintf(LOG_NOTICE,"check - If the user is unsure of what update is going to be "); + lprintf(LOG_NOTICE," This will display the existing target version and image "); + lprintf(LOG_NOTICE," version on the screen"); + lprintf(LOG_NOTICE,"upgrade - Upgrade the firmware using a valid HPM.1 image "); + lprintf(LOG_NOTICE," This checks the version from the file and image and "); + lprintf(LOG_NOTICE," if it differs then only updates else skips"); + lprintf(LOG_NOTICE,"upgrade all - Updates all the components present in the file on the target board"); + lprintf(LOG_NOTICE," without skipping (use this only after using \"check\" command"); + lprintf(LOG_NOTICE,"upgrade component x - Upgrade only component from the given "); + lprintf(LOG_NOTICE," component 0 - BOOT"); + lprintf(LOG_NOTICE," component 1 - RTK"); + lprintf(LOG_NOTICE,"upgrade activate - Upgrade the firmware using a valid HPM.1 image "); + lprintf(LOG_NOTICE," If activate is specified, activate new firmware rigth"); + lprintf(LOG_NOTICE," away"); + lprintf(LOG_NOTICE,"activate [norollback] - Activate the newly uploaded firmware"); + lprintf(LOG_NOTICE,"targetcap - Get the target upgrade capabilities"); + lprintf(LOG_NOTICE,"compprop can be one of the following: "); + lprintf(LOG_NOTICE," 0- General properties"); + lprintf(LOG_NOTICE," 1- Current firmware version"); + lprintf(LOG_NOTICE," 2- Description string"); + lprintf(LOG_NOTICE," 3- Rollback firmware version"); + lprintf(LOG_NOTICE," 4- Deferred firmware version"); + lprintf(LOG_NOTICE,"abort - Abort the on-going firmware upgrade"); + lprintf(LOG_NOTICE,"upgstatus - Returns the status of the last long duration command"); + lprintf(LOG_NOTICE,"rollback - Performs a manual rollback on the IPM Controller"); + lprintf(LOG_NOTICE," firmware"); + lprintf(LOG_NOTICE,"rollbackstatus - Query the rollback status"); + lprintf(LOG_NOTICE,"selftestresult - Query the self test results\n"); +} + +int ipmi_hpmfwupg_main(void * intf, int argc, char ** argv) +{ + int rc = HPMFWUPG_SUCCESS; + int activateFlag = 0x00; + int componentId = DEFAULT_COMPONENT_UPLOAD; + int option = VERSIONCHECK_MODE; + + lprintf(LOG_DEBUG,"ipmi_hpmfwupg_main()"); + + + lprintf(LOG_NOTICE,"\nPICMG HPM.1 Upgrade Agent %d.%d.%d: \n", + HPMFWUPG_VERSION_MAJOR, HPMFWUPG_VERSION_MINOR, HPMFWUPG_VERSION_SUBMINOR); + + if ( (argc == 0) || (strcmp(argv[0], "help") == 0) ) + { + HpmfwupgPrintUsage(); + return ERR_USAGE; + } + if ( (strcmp(argv[0], "check") == 0) ) + { + /* hpm check */ + if (argv[1] == NULL) + { + rc = HpmfwupgTargetCheck(intf,VIEW_MODE); + } + else + { + /* hpm check */ + rc = HpmfwupgTargetCheck(intf,0); + if (rc == HPMFWUPG_SUCCESS) + { + rc = HpmfwupgUpgrade(intf, argv[1],0,DEFAULT_COMPONENT_UPLOAD,VIEW_MODE); + } + } + } + + else if ( strcmp(argv[0], "upgrade") == 0) + { + int i =0; + if (fdebug) option |= DEBUG_MODE; + if (g_channel_buf_size > 0) + printf("Large buffer size %d specified\n", g_channel_buf_size ); + for (i=1; i< argc ; i++) + { + if (strcmp(argv[i],"activate") == 0) + { + activateFlag = 1; + } + /* hpm upgrade all */ + if (strcmp(argv[i],"all") == 0) + { + option &= ~(VERSIONCHECK_MODE); + option &= ~(VIEW_MODE); + option |= FORCE_MODE_ALL; + } + /* hpm upgrade component */ + if (strcmp(argv[i],"component") == 0) + { + if (i+1 < argc) + { + componentId = atoi(argv[i+1]); + option &= ~(VERSIONCHECK_MODE); + option &= ~(VIEW_MODE); + option |= FORCE_MODE_COMPONENT; + + if( verbose ) { + lprintf(LOG_NOTICE,"Component Id %d provided",componentId ); + } + + /* Error Checking */ + if (componentId >= HPMFWUPG_COMPONENT_ID_MAX) + { + lprintf(LOG_NOTICE,"Given component ID %d exceeds Max Comp ID %d\n", + componentId, HPMFWUPG_COMPONENT_ID_MAX-1); + return HPMFWUPG_ERROR; + } + } + if (componentId == DEFAULT_COMPONENT_UPLOAD) + { + /* That indicates the user has given component on console but not + * given any ID */ + lprintf(LOG_NOTICE,"No component Id provided\n"); + return HPMFWUPG_ERROR; + } + } + if (strcmp(argv[i],"debug") == 0) + { + option |= DEBUG_MODE; + } + } + rc = HpmfwupgTargetCheck(intf,0); + if (rc == HPMFWUPG_SUCCESS) + { + /* Call the Upgrade function to start the upgrade */ + rc = HpmfwupgUpgrade(intf, argv[1],activateFlag,componentId,option); + } + } + + else if ( (argc >= 1) && (strcmp(argv[0], "activate") == 0) ) + { + struct HpmfwupgActivateFirmwareCtx cmdCtx; + if ( (argc == 2) && (strcmp(argv[1], "norollback") == 0) ) + cmdCtx.req.rollback_override = 1; + else + cmdCtx.req.rollback_override = 0; + rc = HpmfwupgActivateFirmware(intf, &cmdCtx, NULL); + } + else if ( (argc == 1) && (strcmp(argv[0], "targetcap") == 0) ) + { + struct HpmfwupgGetTargetUpgCapabilitiesCtx cmdCtx; + verbose++; + rc = HpmfwupgGetTargetUpgCapabilities(intf, &cmdCtx); + } + else if ( (argc == 3) && (strcmp(argv[0], "compprop") == 0) ) + { + struct HpmfwupgGetComponentPropertiesCtx cmdCtx; + cmdCtx.req.componentId = atob(argv[1]); + cmdCtx.req.selector = atob(argv[2]); + verbose++; + rc = HpmfwupgGetComponentProperties(intf, &cmdCtx); + } + else if ( (argc == 1) && (strcmp(argv[0], "abort") == 0) ) + { + struct HpmfwupgAbortUpgradeCtx cmdCtx; + verbose++; + rc = HpmfwupgAbortUpgrade(intf, &cmdCtx); + } + else if ( (argc == 1) && (strcmp(argv[0], "upgstatus") == 0) ) + { + struct HpmfwupgGetUpgradeStatusCtx cmdCtx; + verbose++; + rc = HpmfwupgGetUpgradeStatus(intf, &cmdCtx, NULL); + } + else if ( (argc == 1) && (strcmp(argv[0], "rollback") == 0) ) + { + struct HpmfwupgManualFirmwareRollbackCtx cmdCtx; + verbose++; + rc = HpmfwupgManualFirmwareRollback(intf, &cmdCtx, NULL); + } + else if ( (argc == 1) && (strcmp(argv[0], "rollbackstatus") == 0) ) + { + struct HpmfwupgQueryRollbackStatusCtx cmdCtx; + verbose++; + rc = HpmfwupgQueryRollbackStatus(intf, &cmdCtx, NULL); + } + else if ( (argc == 1) && (strcmp(argv[0], "selftestresult") == 0) ) + { + struct HpmfwupgQuerySelftestResultCtx cmdCtx; + verbose++; + rc = HpmfwupgQuerySelftestResult(intf, &cmdCtx, NULL); + } + else + { + HpmfwupgPrintUsage(); + } + + return rc; +} + +#ifdef METACOMMAND +int i_hpm(int argc, char **argv) +#else +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#endif +{ + void *intf = NULL; + int rc = 0; + int c, i; + char *s1; + + printf("%s ver %s\n", progname,progver); + set_loglevel(LOG_NOTICE); + + while ( (c = getopt( argc, argv,"m:z:T:V:J:EYF:P:N:R:U:Z:x?")) != EOF ) + switch (c) { + case 'm': /* specific IPMB MC, 3-byte address, e.g. "409600" */ + g_bus = htoi(&optarg[0]); /*bus/channel*/ + g_sa = htoi(&optarg[2]); /*device slave address*/ + g_lun = htoi(&optarg[4]); /*LUN*/ + g_addrtype = ADDR_IPMB; + if (optarg[6] == 's') { + g_addrtype = ADDR_SMI; s1 = "SMI"; + } else { g_addrtype = ADDR_IPMB; s1 = "IPMB"; } + ipmi_set_mc(g_bus,g_sa,g_lun,g_addrtype); + printf("Use MC at %s bus=%x sa=%x lun=%x\n", + s1,g_bus,g_sa,g_lun); + break; + case 'z': + g_channel_buf_size = atoi(optarg); + if (g_channel_buf_size < HPMFWUPG_SEND_DATA_COUNT_LAN) + rc = ERR_BAD_LENGTH; + else if (g_channel_buf_size > IPMI_REQBUF_SIZE) + rc = LAN_ERR_BADLENGTH; + if (rc != 0) { + printf("Invalid buffer size %d\n",g_channel_buf_size); + return rc; + } + break; + case 'x': fdebug = 1; verbose = 1; + set_loglevel(LOG_DEBUG); + break; /* debug messages */ + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'V': /* priv level */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + break; + case '?': + HpmfwupgPrintUsage(); + return ERR_USAGE; + break; + } + for (i = 0; i < optind; i++) { argv++; argc--; } + + rc = ipmi_hpmfwupg_main(intf, argc, argv); + + ipmi_close_(); + // show_outcome(progname,rc); + return rc; +} +/* end ihpm.c */ + diff --git a/util/ihpm.h b/util/ihpm.h new file mode 100644 index 0000000..00d6dc9 --- /dev/null +++ b/util/ihpm.h @@ -0,0 +1,117 @@ +/* + * 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. + */ + +#ifndef IPMI_HPMFWUPG_H +#define IPMI_HPMFWUPG_H + +#define IPMI_BUF_SIZE 1024 +#ifdef HAVE_LANPLUS +#include "../lib/lanplus/lanplus_defs.h" +#else +#define _IPMI_RS_ +struct ipmi_rs { + uint8_t ccode; + uint8_t data[IPMI_BUF_SIZE]; + + /* + * Looks like this is the length of the entire packet, including the RMC +P + * stuff, then modified to be the length of the extra IPMI message data + */ + int data_len; + + struct { + uint8_t netfn; + uint8_t cmd; + uint8_t seq; + uint8_t lun; + } msg; + struct { + uint8_t authtype; + uint32_t seq; + uint32_t id; + uint8_t bEncrypted; /* IPMI v2 only */ + uint8_t bAuthenticated; /* IPMI v2 only */ + uint8_t payloadtype; /* IPMI v2 only */ + uint16_t msglen; + } session; +}; +#endif + +#define TRUE 1 +#define FALSE 0 + +#define IPMI_NETFN_APP 0x06 +#define IPMI_NETFN_PICMG 0x2C + +#define IPMI_BMC_SLAVE_ADDR 0x20 + +#define BMC_GET_DEVICE_ID 0x1 + +#define IPMI_CC_OK 0x00 +#define IPMI_CC_REQ_DATA_INV_LENGTH 0xc7 + +#define ATTRIBUTE_PACKING /* */ +#define PRAGMA_PACK 1 + +#pragma pack(1) +struct ipm_devid_rsp { + uint8_t device_id; + uint8_t device_revision; + uint8_t fw_rev1; + uint8_t fw_rev2; + uint8_t ipmi_version; + uint8_t adtl_device_support; + uint8_t manufacturer_id[3]; + uint8_t product_id[2]; + uint8_t aux_fw_rev[4]; +}; +#pragma pack() + +typedef struct md5_state_s { + uint count[2]; /* message length in bits, lsw first */ + uint abcd[4]; /* digest buffer */ + uchar buf[64]; /* accumulate block */ +} md5_state_t; + +void md5_init(md5_state_t *pms); /*md5.c*/ +void md5_append(md5_state_t *pms, const uchar *data, int nbytes); /*md5.c*/ +void md5_finish(md5_state_t *pms, uchar digest[16]); /*md5.c*/ + +void lprintf(int level, const char * format, ...); /*ipmilanplus.c*/ +void set_loglevel(int level); +char * get_mfg_str(uchar *rgmfg, int *pmfg); +ushort buf2short(uchar * buf); + +int ipmi_hpmfwupg_main(void *, int, char **); + +#endif /* IPMI_KFWUM_H */ diff --git a/util/ilan.c b/util/ilan.c new file mode 100644 index 0000000..a1ed76a --- /dev/null +++ b/util/ilan.c @@ -0,0 +1,5149 @@ +/*--------------------------------------------------------------------------- + * Filename: ilan.c (was pefconfig.c) + * + * Author: arcress at users.sourceforge.net + * Copyright (c) 2009 Kontron America, Inc. + * + * Abstract: + * This tool sets up the custom Platform Event Filter for the panicSEL + * record (0x20, OS Critical Stop) to send a PEF SNMP alert for Linux + * panics. It also configures the BMC LAN parameters, which are needed + * to support PEF alerts. + * + * ----------- Change History ----------------------------------------------- + * 10/16/01 Andy Cress - created + * 10/24/01 Andy Cress - mods for SetPefEntry(0c) + * 11/02/01 Andy Cress - added option to disable a given PefEntry + * 11/15/01 Andy Cress - added function to GetLanEntry + * 11/19/01 Andy Cress - added function to SetLanEntry + * 01/18/02 Andy Cress - added GetCfgData function + * 01/31/02 Andy Cress - converted to use ipmi_cmd_ia + * 02/06/02 Andy Cress - removed GetCfgData + * 02/06/02 Andy Cress - added ipmi_cmd_va + * 02/08/02 Andy Cress - added GetChanAcc + * 02/14/02 Andy Cress - added Get_IPMac_Addr() + * 02/21/02 Andy Cress - added Alert IP/MAC logic to Get_IPMac_Addr() + * 03/21/02 Andy Cress - do SetChanAcc(0x80) with every SetChanAcc(0x40) + * 04/15/02 Andy Cress v1.2 - fix bug with user-specified Alert IP: + * (ccode=c7 on SetLanEntry(16 & 18), also + * added Get_Mac() for user-specified Alert IP. + * 04/16/02 Andy Cress v1.3 added SetUser() to set password if specified, + * also changed unset mac[0] to be 0xFF, not 0. + * 05/09/02 Andy Cress v1.4 fixed bug 504 gwymac[0]=00 (mymac overwrote it), + * also fixed alert scan to pick last trapsink + * 05/31/02 Andy Cress v1.5 for gwy mac, changed arping -c 1 to -c 2, + * also get com2sec community from snmpd.conf, + * set dest type for no ack, no retry, + * special handling to set preset PEF entries + * 07/02/02 Andy Cress v1.6 added more Usage text + * 07/08/02 Andy Cress v1.7 SetUserAccess length change + * 08/02/02 Andy Cress v1.8 moved common ipmi_cmd() code to ipmicmd.c + * 08/27/02 Andy Cress v1.9 fixed 0xc7 on SETUSER_ACCESS with pefconfig -P "", + * show message if alert dest not found + * 09/10/02 Andy Cress v1.10 make channel nums into defines (16) + * 09/17/02 Andy Cress v1.11 decode Dest Addr IP (19) in decimal, + * fix enable user padding in SetUser, + * display new community string when setting + * 12/09/02 Andy Cress v1.12 fix error w -C & snmpd.conf conflict + * 01/29/03 Andy Cress v1.13 added MV OpenIPMI support + * 02/05/03 Andy Cress v1.14 show pef entry descriptions, + * added EnablePef routine + * show correct Alert dest mac if -A only + * 04/04/03 Andy Cress v1.15 add eth interface option (-i) + * 05/13/03 Andy Cress v1.16 fix EnablePef if startup delay not supported + * 06/19/03 Andy Cress v1.17 added errno.h (email from Travers Carter) + * 07/25/03 Andy Cress v1.18 add SerialOverLan configuration + * mod to SetUser, added GetBmcEthDevice, + * use 'arping -I' if eth1. + * 08/18/03 Andy Cress v1.19 Don't abort if IPMI 1.0, just skip PEF, + * SetLanEntry(10 & 11) for bmc grat arp, + * SetLanEntry(2) to 0x17 for auth priv + * 09/10/03 Andy Cress v1.20 Don't enable a PEF entry if it is empty, + * added -L lan_ch parameter, + * scan for lan_ch in GetBmcEthDevice + * 09/22/03 Andy Cress v1.21 Add DHCP option (-D), from Jerry Yu. + * 12/05/03 Andy Cress v1.22 Fix auth type enables for ServerConfig + * 12/16/03 Andy Cress v1.23 Allow flexible auth types via authmask + * 03/19/04 Andy Cress v1.24 Change default pefnum for mBMC to 10 + * 04/15/04 Andy Cress v1.25 Init each response for channel info, avoids + * 0xcc error with /dev/ipmi0 due to wrong lan_ch + * 05/05/04 Andy Cress v1.26 call ipmi_close before exit. Note that + * Get_IPMac_Addr and GetBmcEthDevice + * routines need more work for WIN32. + * 05/24/04 Andy Cress v1.27 added CHAN_ACC params for ia64 + * 06/28/04 Andy Cress v1.28 added parsing to get community from trapsink + * 07/23/04 Andy Cress v1.29 use lan_ch variable to set Alert Policy Table + * 08/23/04 Andy Cress v1.30 fixed decoding of PE Table entries, + * added -e option (same as no params) + * 08/25/04 Andy Cress v1.31 added some WIN32 logic to Get_Mac, Get_IPMac_Addr + * 11/01/04 Andy Cress v1.32 add -N / -R for remote nodes + * added -U for remote username + * 11/18/04 Andy Cress v1.33 added -u to configure a lan username (user 2) + * 11/23/04 Andy Cress v1.34 added pef_defaults if first 11 empty + * 01/11/05 Andy Cress v1.35 allow scan for BMC LAN if fIPMI10 + * 01/20/05 Andy Cress v1.36 fix to allow IPMI 2.0 + * 02/16/05 Andy Cress v1.37 added IPMI 2.0 VLAN parameters, + * if DHCP, can set DHCP Server via -I param + * 03/02/05 Andy Cress v1.38 show Serial-Over-Lan params, + * fix -L with lan_ch_parm. mods to GetBmcEthDevice + * 03/18/05 Andy Cress v1.39 fix GetBmcEthDevice for invalid MAC compares + * 06/03/05 Andy Cress v1.40 For my MAC in BMC, check user-specified, then + check existing BMC MAC, then check OS MAC. + * 06/10/05 Andy Cress v1.41 Display multiple Alert Destinations, + * handle fSOL20 commands + * 07/07/05 Andy Cress v1.42 Fix GetBmcEthDevice for TIGI2U to skip GCM ch 3 + * 07/08/05 Andy Cress v1.43 Mods to handle Intel NSI2U miniBMC, + * 08/01/05 Andy Cress v1.44 added -t option to test if BMC LAN configured + * 08/10/05 Andy Cress v1.45 truncate extra string chars, + * decode more PEF params + * 09/07/05 Andy Cress v1.46 enable mBMC PEF entries 26 thru 30 + * 04/06/06 Andy Cress v1.47 show "gcm" as ifname if -L 3. + * 06/20/06 Andy Cress v1.48 fix strcmp(gcm), show all 4 alert policies, + * add PefDesc() for misc vendor pefdesc, add -a. + * 08/08/06 Andy Cress v1.49 add Alcolu to fsharedMAC + * 09/29/06 Andy Cress v1.52 use bmcmymac if valid, use bmcmyip if ok, + * added -q for user number, + * enhanced Get_IPMac_Addr for Windows + * 10/12/06 Andy Cress v1.53 FindEthNum updates, always use gwy iface for mac + * 11/02/06 Andy Cress v1.55 add user names, EnablePef mods for non-Intel. + * 05/02/07 Brian Johnson v1.65 add fpefenable flag to not do SetPefEntry + * if no Alert Destination. Previously did + * SetPefEntry but not EnablePef in this case. + * 05/04/07 Andy Cress v1.65 Use 0x02 for DHCP source instead of 0x03, + * fix 1714748 missing "X:" in getopt line + * 05/23/07 Jakub Gorgolewski + * v1.66 Use iphlpapi for Windows detection + * 10/31/07 Andy Cress v2.3 Fixed PEF entry for Power Redundancy Lost + * 11/15/07 Andy Cress v2.4 Move custom PEF to #14, add to usage, + * Allow broadcast MAC for -X + * 12/17/07 Andy Cress v2.5 Add fSetPEFOks & secondary Gateway + */ +/*M* + *--------------------------------------------------------------------------- +Copyright (c) 2009 Kontron America, 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: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions 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. + c.. Neither the name of Kontron nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *--------------------------------------------------------------------------- + *M*/ +#ifdef WIN32 +#include +#include +#include +#include +#include +#include +#include "getopt.h" +#elif defined(DOS) +#include +#include +#include +#include +#include "getopt.h" +#else +/* Linux or similar */ +#include +#include +#include +#include +#include +#if defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#endif +#ifdef LINUX +#include +#endif +#ifdef SOLARIS +#include +#define SIOCGIFHWADDR SIOCGENADDR +#define ifr_netmask ifr_ifru.ifru_addr +// #define ifr_hwaddr.sa_data ifr_ifru.ifru_enaddr +#elif defined(BSD) +#include +#define SIOCGIFHWADDR SIOCGIFMAC +#define ifr_netmask ifr_ifru.ifru_addr +// #define ifr_hwaddr.sa_data ifr_ifru.ifru_addr +#elif defined(MACOS) +#include +#define ifr_netmask ifr_ifru.ifru_addr +#endif +#include "ipmicmd.h" +#include "oem_intel.h" +#include "oem_supermicro.h" + +#define SELprintf printf +#define RTF_UP 0x0001 /* route usable */ + +#define SOL_ENABLE_FLAG 0x01 +#define SOL_DISABLE_FLAG 0x00 +#define SOL_PRIVILEGE_LEVEL_USER 0x02 +#define SOL_PRIVILEGE_LEVEL_OPERATOR 0x03 +#define SOL_PRIVILEGE_LEVEL_ADMIN 0x04 +#define SOL_PREFERRED_BAUD_RATE 0x0a /*115.2k*/ +/* For IPMI 1.5, use Intel SOL commands & subfunctions */ +#define SOL_ENABLE_PARAM 0x01 +#define SOL_AUTHENTICATION_PARAM 0x02 +#define SOL_ACC_INTERVAL_PARAM 0x03 +#define SOL_RETRY_PARAM 0x04 +#define SOL_BAUD_RATE_PARAM 0x05 /*non-volatile*/ +#define SOL_VOL_BAUD_RATE_PARAM 0x06 /*volatile*/ +/* For IPMI 2.0, use IPMI SOL commands & subfunctions */ +#define SOL_ENABLE_PARAM2 0x08 +#define SOL_AUTHENTICATION_PARAM2 0x09 +#define SOL_BAUD_RATE_PARAM2 0x11 + +/* IPMI 2.0 SOL PAYLOAD commands */ +#define SET_PAYLOAD_ACCESS 0x4C +#define GET_PAYLOAD_ACCESS 0x4D +#define GET_PAYLOAD_SUPPORT 0x4E + +/* Channel Access values */ +#define CHAN_ACC_DISABLE 0x20 /* PEF off, disabled*/ +#define CHAN_ACC_PEFON 0x02 /* PEF on, always avail */ +#define CHAN_ACC_PEFOFF 0x22 /* PEF off, always avail*/ +/* special channel access values for ia64 */ +#define CHAN_ACC_PEFON64 0x0A /* PEF on, always avail, UserLevelAuth=off */ +#define CHAN_ACC_PEFOFF64 0x2A /* PEF off, always avail, UserLevelAuth=off */ +#define OS_LINUX 1 +#define OS_WINDOWS 2 +#define OS_SOLARIS 3 +#define OS_BSD 4 +#define OS_HPUX 5 + + /* TSRLT2 Channels: 0=IPMB, 1=Serial/EMP, 6=LAN2, 7=LAN1 */ + /* S5000 Channels: 0=IPMB, 1=LAN1, 2=LAN2, 3=RMM2, 4=Serial, 6=pci, 7=sys */ + /* For TIGPT1U/mBMC: 1=LAN channel, no serial */ +#define LAN_CH 1 +#define SER_CH 4 +#define MAXCHAN 12 /*was 16, reduced for gnu ipmi_lan*/ +#define NUM_DEVICES_TO_CHECK 32 /*for GetBmcEthDevice()*/ +#define MAC_LEN 6 /*length of MAC Address*/ +#define PSW_LEN 16 /* see also PSW_MAX =20 in ipmicmd.h*/ +/* Note: The optional IPMI 2.0 20-byte passwords are not supported here, + * due to back-compatibility issues. */ + + /* IP address source values */ +#define SRC_STATIC 0x01 +#define SRC_DHCP 0x02 /* BMC running DHCP */ +#define SRC_BIOS 0x03 /* BIOS, sometimes DHCP */ +#define SRC_OTHER 0x04 + +/* PEF event severities */ +#define PEF_SEV_UNSPEC 0x00 +#define PEF_SEV_MON 0x01 +#define PEF_SEV_INFO 0x02 +#define PEF_SEV_OK 0x04 +#define PEF_SEV_WARN 0x08 +#define PEF_SEV_CRIT 0x10 +#define PEF_SEV_NORECOV 0x20 +#define FLAG_INIT 99 /*initial value of char flag, beyond scope*/ +#define PARM_INIT 0xff + +typedef struct +{ /* See IPMI Table 15-2 */ + uchar rec_id; + uchar fconfig; + uchar action; + uchar policy; + uchar severity; + uchar genid1; + uchar genid2; + uchar sensor_type; + uchar sensor_no; + uchar event_trigger; + uchar data1; + uchar mask1; + uchar res[9]; +} PEF_RECORD; + +typedef struct +{ /* See IPMI Table 19-3 */ + uchar data[36]; +} LAN_RECORD; /*LanRecord*/ + +#ifdef METACOMMAND +extern int get_lan_stats(uchar chan); /*see bmchealth.c */ +extern char *get_sensor_type_desc(uchar stype); /*from ievents.c*/ +#endif + +#define MYIP 0x01 +#define GWYIP 0x02 +#define DESTIP 0x04 +#define MAXPEF 41 /* max pefnum offset = 40 (41 entries) */ +/* + * Global variables + */ +static char * progver = "2.93"; +static char * progname = "ilan"; +static char fdebug = 0; +static char fipmilan = 0; +static char fIPMI10 = 0; /* =1 if IPMI v1.0 or less */ +static char fIPMI20 = 0; /* =1 if IPMI v2.0 or greater */ +static char fSOL20 = 1; /* =1 if use Serial-Over-Lan 2.0 w IPMI 2.0 */ +static char fsharedMAC = 0; /* =1 if special shared-MAC BMC LAN port */ +static char fAdjustPefNum = 0; /* =1 adjust pefnum to first empty index */ +static char fUserPefNum = 0; /* =1 if user specified a valid pefnum value*/ +static char freadonly = 1; /* =1 to only read LAN & PEF parameters */ +static char fcanonical = 0; /* =1 to show only canonical output */ +static char bdelim = BCOLON; /* delimiter ':' or '|' if canonical output*/ +static char ftestonly = 0; +static char fprivset = 0; +static char flanstats = 0; /* =1 to show the IPMI LAN statistics */ +static char foptmsg = 0; /* =1 to show the option warning msg */ +static char fshowchan = 0; /* =1 to show the IPMI channels */ +static char nopts = 0; /* number of pefconfig options specified*/ +static int nerrs = 0; /* number of errors during processing */ +static int ngood = 0; /* number of good results */ +static int lasterr = 0; /* value of the last error */ +static char fCustomPEF = 0; /* =1 if -j to input a custom PEF record */ +static char fSetPEFOks = 0; /* =1 if -k to set PEF OK rules */ +static char fdisable = 0; +static char fenable = 0; /* =1 to config BMC LAN and PEF */ +static char fpefenable = 0; /* =1 enable PEF if Alert Dest is specified*/ +static char fdisableSOL = 0; +static char fgetser = 0; +static char fsetifn = 0; /* =1 if user specified ifname[] with -i */ +static char fethfound = 0; /* =1 if FindEthNum successful */ +static char fset_ip = 0; /* !=0 if options used to specify an IP addr*/ +static char fpassword = 0; /* =1 user-specified a password, so set it. */ +static uchar fmBMC = 0; /* =1 mini-BMC, =0 Sahalee BMC */ +static uchar fiBMC = 0; /* =1 Intel iBMC */ +static uchar fRomley = 0; /* =1 Intel Romley BMC */ +static uchar fipv6 = 0; /* =1 if BMC supports IPv6 */ +static uchar bmcpefctl = 0; /* existing BMC PEF Control, !0 = enabled */ +static char alertnum = 1; /* alert dest num (usu 1 thru 4) */ +static char alertmax = 9; /* alert dest num max (usu 4, error if >9) */ +static char pefnum = 12; /* 11 pre-defined entries, adding 12th */ +static char pefadd = 0; /* num PEF rules added (usu 2, could be 5 */ +static char pefmax = MAXPEF; /* 20 for Sahalee, 30 for miniBMC */ +static char *myuser = NULL; /* username to set, specified by -u */ +static uchar usernum = 0; /* set non-zero to specify user number */ +static uchar rgmyip[4] = {0,0,0,0}; +static uchar rggwyip[4] = {0,0,0,0}; +static uchar rggwy2ip[4] = {0,0,0,0}; +static uchar rgdestip[4] = {0,0,0,0}; +static uchar rgsubnet[4] = {0,0,0,0}; +static uchar bmcsubnet[4] = {255,255,255,0}; /* default subnet */ +static uchar ossubnet[4] = {0,0,0,0}; +static uchar osmyip[4] = {0,0,0,0}; +static uchar bmcmyip[4] = {0,0,0,0}; +static uchar bmcdestip[4] = {0,0,0,0}; +static uchar bmcdestmac[6]= {0xff,0,0,0,0,0}; +static uchar bmcmymac[6] = {0xff,0,0,0,0,0}; +static uchar rgmymac[6] = {0xff,0,0,0,0,0}; +static uchar osmymac[6] = {0xff,0,0,0,0,0}; +static uchar rggwymac[6] = {0xff,0,0,0,0,0}; +static uchar rggwy2mac[6] = {0xff,0,0,0,0,0}; +static uchar rgdestmac[6] = {0xff,0,0,0,0,0}; +static uchar rgdhcpmac[6] = {0xff,0,0,0,0,0}; +static char rghostname[32] = {'\0'}; +static uchar custPEF[20]; /* max used = 18 bytes */ +static char rgcommunity[19] = "public"; /* default community */ +static char fsetcommunity = 0; /* =1 if user-specified community */ +static char passwordData[PSW_MAX+1] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +static uchar authmask = 0; /* usu 0x17, mBMC = 0x15 */ +static uchar bAuth = 0x16; /*exclude auth=None for security*/ +static uchar lan_access = 0x04; /* usu 4=Admin, 3=Operator, 2=User */ +static uchar lan_user = 0x02; /* if -u specified, use user 2 for lan */ +static uchar arp_interval = 0x04; /* in 500 ms increments, 0-based */ +static uchar arp_ctl = 0x01; /* 01=grat arp, 02=arp resp, 03=both*/ +static uchar fsetarp = 0; /* 1=user-specified arp_ctl */ +#ifdef WIN32 +static uchar ostype = OS_WINDOWS; /*windows*/ +static char ifname[64] = "Local Area Connection "; /* interface name */ +static char ifpattn[25] = "Local Area Connection "; +#elif SOLARIS +/* for i86pc use "e1000g0", but for sun4u(sparc) this might be "eri0" */ +static uchar ostype = OS_SOLARIS; +#ifdef __SPARC__ +static char ifname[16] = "eri0"; /* SPARC interface name */ +static char ifname0[16] = "eri0"; +static char ifpattn[14] = "eri"; +#else +static char ifname[16] = "e1000g0"; /* Solaris x86 interface name */ +static char ifname0[16] = "e1000g0"; +static char ifpattn[14] = "e1000g"; +#endif +#elif defined(BSD) +static uchar ostype = OS_BSD; +static char ifname[16] = "em0"; /* interface name */ +static char ifname0[16] = "em0"; +static char ifpattn[14] = "em"; +#elif defined(HPUX) +static uchar ostype = OS_HPUX; +static char ifname[16] = "lan0"; /* interface name */ +static char ifname0[16] = "lan0"; +static char ifpattn[14] = "lan"; +#else +static uchar ostype = OS_LINUX; +static char ifname[16] = "eth0"; /* interface name */ +static char ifname0[16] = "eth0"; +static char ifpattn[14] = "eth"; +#endif +static char *pspace1 = "\t"; /*used for fcanonical output*/ +static char *pspace2 = "\t\t"; +static char *pspace3 = "\t\t\t"; +static char *pspace4 = "\t\t\t\t"; +static int vend_id; +static int prod_id; +static int lan_dhcp = 0; /*=1 if using DHCP for bmc lan channel*/ +static uchar ser_ch = SER_CH; +static uchar lan_ch = LAN_CH; +static uchar lan_ch_parm = PARM_INIT; +static uchar gcm_ch = PARM_INIT; +static uchar vlan_enable = PARM_INIT; +static uchar failover_enable = PARM_INIT; +static uchar vlan_prio = 0; /*default = 0*/ +static ushort vlan_id = 0; /*max 12 bits used*/ +static uchar max_users = 5; /* set in GetUser(1); */ +static uchar enabled_users = 0; /* set in GetUser(1); */ +static uchar show_users = 5; /* default, adjusted based on DeviceID */ +static uchar fnewbaud = 0; /* =1 if user specified baud */ +static uchar sol_baud = SOL_PREFERRED_BAUD_RATE; /*115.2k default*/ +static uchar sol_accum[2] = { 0x04, 0x32 }; +static uchar sol_retry[2] = { 0x06, 0x14 }; +static uchar sol_bvalid = 0; /* =1 if SOL baud is valid */ +static uchar chan_pefon = CHAN_ACC_PEFON; +static uchar chan_pefoff = CHAN_ACC_PEFOFF; +static uchar SessInfo[18]; /* Session Info data */ +// static uchar bparm7[3] = {0x00, 0x00, 0x00}; /*ipv4 header before*/ +static uchar iparm7[3] = {0x1E, 0x00, 0x00}; /*intel ipv4 TTL,Flags,Service*/ +static uchar oparm7[3] = {0x40, 0x40, 0x10}; /*other ipv4 TTL,Flags,Service*/ +static uchar *parm7 = &oparm7[0]; +#define MAX_PEFPARAMS 14 /* max pef params = 14 */ +uchar peflen[MAX_PEFPARAMS] = {0,1,1,1,1,1,21,2,1,4,17,1,3,18}; /*for ShowPef*/ +uchar pef_array[MAXPEF][21]; /* array of all PEF entries read, */ + /* sizeof(PEF_RECORD) = 21 */ +uchar pef_defaults[11][21] = { /* array of first 11 default PEF entries */ +{0x01,0x80,1,1,PEF_SEV_CRIT,0xff,0xff,0x01,0xff,0x01,0x95,0x0a,0,0,0,0,0,0,0,0,0}, /*Temp*/ +{0x02,0x80,1,1,PEF_SEV_CRIT,0xff,0xff,0x02,0xff,0x01,0x95,0x0a,0,0,0,0,0,0,0,0,0}, /*Volt*/ +{0x03,0x80,1,1,PEF_SEV_CRIT,0xff,0xff,0x04,0xff,0x01,0x95,0x0a,0,0,0,0,0,0,0,0,0}, /*Fan*/ +{0x04,0x80,1,1,PEF_SEV_WARN,0xff,0xff,0x05,0x05,0x03,0x01,0x00,0,0,0,0,0,0,0,0,0}, /*Chass*/ +{0x05,0x80,1,1,PEF_SEV_WARN,0xff,0xff,0x08,0xff,0x6f,0x06,0x00,0,0,0,0,0,0,0,0,0}, /*PS*/ +{0x06,0x80,1,1,PEF_SEV_WARN,0xff,0xff,0x0c,0x08,0x6f,0x02,0x00,0,0,0,0,0,0,0,0,0}, /*ECC*/ +{0x07,0x80,1,1,PEF_SEV_CRIT,0xff,0xff,0x0f,0x06,0x6f,0x01,0x00,0,0,0,0,0,0,0,0,0}, /*FRB*/ +{0x08,0x80,1,1,PEF_SEV_WARN,0xff,0xff,0x07,0xff,0x6f,0x1c,0x00,0,0,0,0,0,0,0,0,0}, /*POST*/ +{0x09,0x80,1,1,PEF_SEV_CRIT,0xff,0xff,0x13,0xff,0x6f,0x3e,0x03,0,0,0,0,0,0,0,0,0}, /*NMI*/ +{0x0a,0x80,1,1,PEF_SEV_INFO,0xff,0xff,0x23,0x03,0x6f,0x0e,0x00,0,0,0,0,0,0,0,0,0}, /*WDT*/ +{0x0b,0x80,1,1,PEF_SEV_MON,0xff,0xff,0x12,0xff,0x6f,0x02,0x00,0,0,0,0,0,0,0,0,0} };/*Restart*/ + +char **pefdesc; +char *pefdesc1[MAXPEF] = { /* for Sahalee BMC */ +/* 0 0x00 */ "", +/* 1 0x01 */ "Temperature Sensor", +/* 2 0x02 */ "Voltage Sensor", +/* 3 0x04 */ "Fan Failure", +/* 4 0x05 */ "Chassis Intrusion", +/* 5 0x08 */ "Power Supply Fault", +/* 6 0x0c */ "Memory ECC Error", +/* 7 0x0f */ "BIOS POST Error", +/* 8 0x07 */ "FRB Failure", +/* 9 0x13 */ "Fatal NMI", +/*10 0x23 */ "Watchdog Timer Reset", +/*11 0x12 */ "System Restart", +/*12 0x20 */ "OS Critical Stop", +/*13 0x09 */ "Power Redundancy Lost", +/*14 0x00 */ "reserved", +/*15 0x00 */ "reserved", +/*16 0x00 */ "reserved", +/*17 */ "reserved", +/*18 */ "reserved", +/*19 */ "reserved", +/*20 */ "reserved", +/*21 */ "reserved", +/*22 */ "reserved", +/*23 */ "reserved", +/*24 */ "reserved", +/*25 */ "reserved", +/*26 */ "reserved", +/*27 */ "reserved", +/*28 */ "reserved", +/*29 */ "unused", +/*30 */ "unused" }; + +char *pefdesc2[MAXPEF] = { /* for NSC miniBMC */ +/* 0 */ "", +/* 1 0x02*/ "Voltage Sensor Assert", +/* 2 0x23*/ "Watchdog FRB Timeout", /* was "Proc FRB Thermal", */ +/* 3 0x02*/ "Voltage Sensor Deassert", +/* 4 0x07*/ "Proc1 IERR", +/* 5 0xff*/ "Digital Sensor OK", +/* 6 0x14*/ "Chassis Identify", +/* 7 0x13*/ "NMI Button", +/* 8 0x14*/ "Clear CMOS via Panel", +/* 9 0x0f*/ "OS Load POST Code", +/*10 0x20*/ "OS Critical Stop", +/*11 0x09 */ "Power Redundancy Lost", +/*12 0x00*/ "reserved", +/*13 */ "reserved", +/*14 */ "reserved", +/*15 */ "reserved", +/*16 */ "reserved", +/*17 */ "reserved", +/*18 */ "reserved", +/*19 */ "reserved", +/*20 */ "reserved", +/*21 */ "reserved", +/*22 */ "reserved", +/*23 */ "reserved", +/*24 */ "reserved", +/*25 */ "reserved", +/*26 0x05*/ "Chassis Intrusion", +/*27 0x0f*/ "POST Code Error", +/*28 0x02*/ "Voltage Failure", +/*29 0x04*/ "Fan Failure", +/*30 0x01*/ "Temperature Failure"}; + +#define NLAN 39 +char canon_param[NLAN] = { 0,0,0,1,1,1,1,0,0,0,0,0,1,1,0,0,1,0,0,1, + 0,0,0,0,0,0,1,1,1,1}; +struct { + int cmd; + int sz; + char desc[28]; +} lanparams[NLAN] = { /* see IPMI Table 19-4 */ + /* 0 */ { 0, 1, "Set in progress"}, + /* 1 */ { 1, 1, "Auth type support"}, + /* 2 */ { 2, 5, "Auth type enables"}, + /* 3 */ { 3, 4, "IP address"}, + /* 4 */ { 4, 1, "IP addr src"}, /* (DHCP/Static) */ + /* 5 */ { 5, 6, "MAC addr"}, + /* 6 */ { 6, 4, "Subnet mask"}, + /* 7 */ { 7, 3, "IPv4 header"}, + /* 8 */ { 8, 2, "Prim RMCP port"}, + /* 9 */ { 9, 2, "Sec RMCP port"}, + /* 10 */ {10, 1, "BMC grat ARP"}, + /* 11 */ {11, 1, "grat ARP interval"}, + /* 12 */ {12, 4, "Def gateway IP"}, + /* 13 */ {13, 6, "Def gateway MAC"}, + /* 14 */ {14, 4, "Sec gateway IP"}, + /* 15 */ {15, 6, "Sec gateway MAC"}, + /* 16 */ {16,18, "Community string"}, + /* 17 */ {17, 1, "Num dest"}, + /* 18 */ {18, 5, "Dest type"}, + /* 19 */ {19, 13, "Dest address"}, + /* 20 */ {20, 2, "VLAN ID"}, + /* 21 */ {21, 1, "VLAN Priority"}, + /* 22 */ {22, 1, "Cipher Suite Support"}, + /* 23 */ {23,17, "Cipher Suites "}, + /* 24 */ {24, 9, "Cipher Suite Priv"}, + /* 25 */ {25, 4, "VLAN Dest Tag"}, + /* 26 */ {96, 28, "OEM Alert String"}, + /* 27 */ {97, 1, "Alert Retry Algorithm"}, + /* 28 */ {98, 3, "UTC Offset"}, + /* 29 */ {102, 1, "IPv6 Enable"}, + /* 30 */ {103, 1, "IPv6 Addr Source"}, + /* 31 */ {104,16, "IPv6 Address"}, + /* 32 */ {105, 1, "IPv6 Prefix Len"}, + /* 33 */ {106,16, "IPv6 Default Gateway"}, + /* 34 */ {108,17, "IPv6 Dest address"}, + /* 35 */ {192, 4, "DHCP Server IP"}, + /* 36 */ {193, 6, "DHCP MAC Address"}, + /* 37 */ {194, 1, "DHCP Enable"}, + /* 38 */ {201, 2, "Channel Access Mode(Lan)"} +}; + +#define NSER 22 /* max=32 */ +struct { + int cmd; + int sz; + char desc[28]; +} serparams[NSER] = { /* see IPMI Table 20-4 */ + /* 0 */ { 0, 1, "Set in progress"}, + /* 1 */ { 1, 1, "Auth type support"}, + /* 2 */ { 2, 5, "Auth type enables"}, + /* 3 */ { 3, 1, "Connection Mode"}, + /* 4 */ { 4, 1, "Sess Inactiv Timeout"}, + /* 5 */ { 5, 5, "Channel Callback"}, + /* 6 */ { 6, 1, "Session Termination"}, + /* 7 */ { 7, 2, "IPMI Msg Comm"}, + /* 8 */ { 8, 2, "Mux Switch"}, + /* 9 */ { 9, 2, "Modem Ring Time"}, + /* 10 */ {10,17, "Modem Init String"}, + /* 11 */ {11, 5, "Modem Escape Seq"}, + /* 12 */ {12, 8, "Modem Hangup Seq"}, + /* 13 */ {13, 8, "Modem Dial Command"}, + /* 14 */ {14, 1, "Page Blackout Interval"}, + /* 15 */ {15,18, "Community String"}, + /* 16 */ {16, 1, "Num of Alert Dest"}, + /* 17 */ {17, 5, "Destination Info"}, + /* 18 */ {18, 1, "Call Retry Interval"}, + /* 19 */ {19, 3, "Destination Comm Settings"}, + /* 20 */ {29, 2, "Terminal Mode Config"}, + /* 21 */ {201, 2,"Channel Access Mode (Ser)"} +}; + +static void getauthstr(uchar auth, char *s) +{ + if (s == NULL) return; + s[0] = 0; + if (auth & 0x01) strcat(s,"None "); + if (auth & 0x02) strcat(s,"MD2 "); + if (auth & 0x04) strcat(s,"MD5 "); + if (auth & 0x10) strcat(s,"Pswd "); + if (auth & 0x20) strcat(s,"OEM "); + return; +} + +static int GetDeviceID(LAN_RECORD *pLanRecord) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + int status; + uchar inputData[24]; + uchar completionCode; + + if (pLanRecord == NULL) return(-1); + + status = ipmi_cmd(GET_DEVICE_ID, inputData, 0, responseData, + &responseLength, &completionCode, fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + SELprintf("GetDeviceID: completion code=%x\n", + completionCode); + status = completionCode; + } else { + memcpy(pLanRecord,&responseData[0],responseLength); + set_mfgid(&responseData[0],responseLength); + return(0); // successful, done + } + } /* endif */ + /* if get here, error */ + return(status); +} /*end GetDeviceID() */ + +static int GetChanAcc(uchar chan, uchar parm, LAN_RECORD *pLanRecord) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + int status; + uchar inputData[24]; + uchar completionCode; + + if (pLanRecord == NULL) return(-1); + responseLength = 3; + inputData[0] = chan; + inputData[1] = parm; /* 0x80 = active, 0x40 = non-volatile */ + responseLength = sizeof(responseData); + status = ipmi_cmd(GET_CHANNEL_ACC, inputData, 2, responseData, + &responseLength, &completionCode, fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + SELprintf("GetChanAcc: completion code=%x\n", + completionCode); + status = completionCode; + } else { + // dont copy first byte (Parameter revision, usu 0x11) + memcpy(pLanRecord,&responseData[0],responseLength); + return(0); // successful, done + } + } /* endif */ + /* if get here, error */ + return(status); +} /*GetChanAcc()*/ + +static int SetChanAcc(uchar chan, uchar parm, uchar val) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + int status; + uchar inputData[24]; + uchar completionCode; + + if (fmBMC) return(0); /* mBMC doesn't support this */ + /* parm: 0x80 = active, 0x40 = set non-vol*/ + responseLength = 1; + inputData[0] = chan; /* channel */ + inputData[1] = (parm & 0xc0) | (val & 0x3F); + inputData[2] = (parm & 0xc0) | lan_access; /* set priv level to Admin */ + + responseLength = sizeof(responseData); + status = ipmi_cmd(SET_CHANNEL_ACC, inputData, 3, responseData, + &responseLength, &completionCode, fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + SELprintf("SetChanAcc: completion code=%x\n", + completionCode); + status = completionCode; + } else { + return(0); // successful, done + } + } /* endif */ + /* if get here, error */ + return(status); +} /*SetChanAcc()*/ + +int +SetPasswd(int unum, char *uname, char *upswd) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + int status, i, psw_len; + uchar completionCode; + char inputData[24]; + int ret = 0; + + inputData[0] = (uchar)unum; /*user 1 = null user */ + responseLength = sizeof(responseData); + status = ipmi_cmd(GET_USER_NAME, inputData, 1, responseData, + &responseLength, &completionCode, fdebug); + SELprintf("GET_USERNAME: %x %x %x, status = %x, ccode=%x\n", + responseData[0],responseData[1],responseData[2], + status,completionCode); + if (fdebug) { + char aname[17]; + printf("User %d: ",unum); + for (i = 0; i < responseLength; i++) { + printf("%02x ",responseData[i]); + if (responseData[i] < 0x20) aname[i] = '.'; + else aname[i] = responseData[i]; + } + aname[16] = 0; + printf(" %s\n",aname); + } + + if (unum != 1) + { /* user specified a lan username */ + if (fiBMC && (unum == 2)) { + /* cannot set user 2 name */ + if (uname != NULL) { + if (strcmp(uname,"root") != 0) + printf("SETUSERNAME - user2 name %s must be root\n",uname); + } + } else if (unum == 2 && (vend_id == VENDOR_SUPERMICROX || + vend_id == VENDOR_SUPERMICRO) ) { + /* cannot set user 2 name */ + if (uname != NULL) { + if (strcmp(uname,"ADMIN") != 0) + printf("SETUSERNAME - user2 name %s must be ADMIN\n",uname); + } + } else { + inputData[0] = (uchar)unum; + memset(&inputData[1],0,16); + if (uname != NULL) + memcpy(&inputData[1],uname,strlen(uname)); + status = ipmi_cmd(SET_USER_NAME, inputData, 17, responseData, + &responseLength, &completionCode, fdebug); + if (completionCode == 0xCC) + status = 0; /*setting username to previous gives 0xCC, ok*/ + else { + SELprintf("SETUSERNAME - %x %x %x status = %x, ccode=%x\n", + inputData[0],inputData[1],inputData[2], + status,completionCode); + if (status == 0) status = completionCode; + if (status != 0) ret = status; + } + } + } + + if ((unum != 1) && (uname == NULL)) { + ; /* if no username, do not enable user */ + } else { + inputData[0] = (uchar)unum; /*user 1 = null user */ + inputData[1] = 0x01; /*enable user*/ + responseLength = sizeof(responseData); + status = ipmi_cmd(SET_USER_PASSWORD, inputData, 2, responseData, + &responseLength, &completionCode, fdebug); + printf("SETUSERENAB - inputData %x %x %x, status = %x, ccode=%x\n", + inputData[0],inputData[1],inputData[2], + status,completionCode); + if (status == 0) status = completionCode; + if (status != 0) ret = status; + } + + inputData[0] = (uchar)unum; /*user 1 = null user */ + inputData[1] = 0x02; /*set password*/ + psw_len = PSW_LEN; /*=16 change if 20-byte passwords supported */ + memset(&inputData[2],0,psw_len); + if (upswd != NULL) + strcpy(&inputData[2],upswd); + if (fdebug) { + char apsw[PSW_MAX+1]; + char c; + printf("Pswd %d: ",unum); + for (i = 0; i < psw_len; i++) { + c = inputData[i+2]; + printf("%02x ",(unsigned char)c); + if (c < 0x20) apsw[i] = '.'; + else apsw[i] = c; + } + apsw[psw_len] = 0; + printf(" %s\n",apsw); + } + responseLength = sizeof(responseData); + status = ipmi_cmd(SET_USER_PASSWORD, inputData, 2+psw_len, + responseData,&responseLength, &completionCode,fdebug); + SELprintf("SETUSERPSW - inputData %x %x %x, status = %x, ccode=%x\n", + inputData[0],inputData[1],inputData[2], + status,completionCode); + if (status == 0) status = completionCode; + if (status != 0) ret = status; + + inputData[0] = (uchar)unum; /*user 1 = null user */ + inputData[1] = 0x03; /*test password*/ + memset(&inputData[2],0,psw_len); + if (upswd != NULL) + strcpy(&inputData[2],upswd); + responseLength = sizeof(responseData); + status = ipmi_cmd(SET_USER_PASSWORD, inputData, 2+psw_len, + responseData,&responseLength, &completionCode,fdebug); + SELprintf("TESTUSERPSW - inputData %x %x %x, status = %x, ccode=%x\n", + inputData[0],inputData[1],inputData[2], + status,completionCode); + + if (fiBMC && (unum == 2)) { /*iBMC doesn't support this on user 2*/ + if (fdebug) + printf("skipping SETUSER_ACCESS on iBMC for user %d\n",unum); + } else { + inputData[0] = 0x90 | lan_ch; /* = 0x97 */ + inputData[1] = (uchar)unum; /* user num */ + inputData[2] = lan_access; /* usu admin */ + inputData[3] = 0x00; /* User Session Limit, 0=not limited*/ + responseLength = sizeof(responseData); + status = ipmi_cmd(SET_USER_ACCESS, inputData, 4, responseData, + &responseLength, &completionCode, fdebug); + printf("SETUSER_ACCESS - inputData %x %x %x, status = %x ccode=%x\n", + (uchar)inputData[0],inputData[1],inputData[2], + status,completionCode); + if (status == 0) status = completionCode; + if (status != 0) ret = status; + } + + return(ret); +} /*end SetPswd()*/ + +int SetUser(int unum, char *uname, char *passwd) +{ + int ret = 0; + /* if the user specified a username or password, set it. */ + if ((fpassword) || (uname != NULL)) { + ret = SetPasswd(unum, uname,passwd); /*set username and password*/ + } + return(ret); +} /*end SetUser()*/ + +int +DisableUser(int unum) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + int status; + uchar completionCode; + char inputData[24]; + + inputData[0] = 0x80 | lan_ch; /* = 0x87, no IPMI */ + inputData[1] = (uchar)unum; /* user 1 */ + inputData[2] = 0x0F; /* No access */ + inputData[3] = 0x00; /* User Session Limit, 0=not limited*/ + responseLength = sizeof(responseData); + status = ipmi_cmd(SET_USER_ACCESS, inputData, 4, responseData, + &responseLength, &completionCode, fdebug); + if (status == 0) status = completionCode; + return(status); +} + +static char *parse_priv(uchar c) +{ + char *p; + c = (c & 0x0f); + switch(c) { + case 1: p = "Callback"; break; + case 2: p = "User "; break; + case 3: p = "Operator"; break; + case 4: p = "Admin "; break; + case 5: p = "OEM "; break; + case 0x0f: p = "No access"; break; + default: p = "Reserved"; + } + return(p); +} + +static void show_priv(uchar c) +{ + char *privstr; + privstr = parse_priv(c); + printf("%s",privstr); +} + +static int valid_priv(int c) +{ + int rv; + switch(c) { + case 1: + case 2: + case 3: + case 4: + case 5: + case 0x0f: + rv = 1; + break; + default: + rv = 0; + break; + } + return rv; +} + +int GetUser(uchar user_num) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + int status; + uchar completionCode; + char inputData[24]; + + inputData[0] = lan_ch; + inputData[1] = user_num; /* usually = 1 for BMC LAN */ + responseLength = sizeof(responseData); + status = ipmi_cmd(GET_USER_ACCESS, inputData, 2, responseData, + &responseLength, &completionCode, fdebug); + if (status == 0 && completionCode == 0) { + uchar c; + if (user_num == 1) { /*get max_users and enabled_users*/ + max_users = responseData[0] & 0x3f; + enabled_users = responseData[1] & 0x3f; + if (enabled_users > show_users) show_users = enabled_users; + if (show_users > max_users) show_users = max_users; + if (!fcanonical) + SELprintf("Users: showing %d of max %d users (%d enabled)\n", + show_users,max_users,enabled_users); + } + if (fcanonical) + SELprintf("Channel %d User %d Access %s%c ", lan_ch, user_num, + pspace2,bdelim); + else + SELprintf("User Access(chan%d,user%d): %02x %02x %02x %02x : ", + lan_ch, user_num, (uchar)responseData[0], + responseData[1],responseData[2], responseData[3]); + c = responseData[3]; + inputData[0] = user_num; /* usually = 1 for BMC LAN */ + responseLength = sizeof(responseData); + status = ipmi_cmd(GET_USER_NAME, inputData, 1, responseData, + &responseLength, &completionCode, fdebug); + if (status != 0 || completionCode != 0) + responseData[0] = 0; + if (c & 0x10) printf("IPMI, "); + show_priv(c); + printf(" (%s)\n",responseData); /*show user name */ + } else + SELprintf("Get User Access(%d,%d), status=%x, ccode=%x\n", + lan_ch, user_num, status, completionCode); + return(status); +} /*end GetUser()*/ + +static int GetSerEntry(uchar subfunc, LAN_RECORD *pLanRecord) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + uchar inputData[24]; + int status; + uchar completionCode; + uchar chan; uchar bset; + + if (pLanRecord == NULL) + { + if (fdebug) + printf("GetSerEntry(%d): error, output buffer is NULL\n",subfunc); + return (-1); + } + + chan = ser_ch; /* 1=EMP, 0=IPMB, 6=LAN2, 7=LAN1 */ + bset = 0; + + inputData[0] = chan; // flags, channel 3:0 (1=EMP) + inputData[1] = subfunc; // Param selector + inputData[2] = bset; // Set selector + inputData[3] = 0; // Block selector + if (subfunc == 10) { + inputData[2] = 0; + inputData[3] = 1; + } + + status = ipmi_cmd(GET_SER_CONFIG, inputData, 4, responseData, + &responseLength, &completionCode, fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + if (fdebug) + SELprintf("GetSerEntry(%d,%d): completion code=%x\n", + chan,subfunc,completionCode); + } else { + // dont copy first byte (Parameter revision, usu 0x11) + memcpy(pLanRecord,&responseData[1],responseLength-1); + pLanRecord->data[responseLength-1] = 0; + //successful, done + return(0); + } + } + + // we are here because completionCode is not COMPLETION_CODE_OK + if (fdebug) + SELprintf("GetSerEntry(%d,%d): ipmi_cmd status=%x ccode=%x\n", + chan,subfunc,status,completionCode); + return -1; +} + +static int GetLanEntry(uchar subfunc, uchar bset, LAN_RECORD *pLanRecord) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + uchar inputData[24]; + int status, n; + uchar completionCode; + uchar chan; + + if (pLanRecord == NULL) + { + if (fdebug) + printf("GetLanEntry: error, output buffer is NULL\n"); + return (-1); + } + + chan = lan_ch; /* LAN 1 = 7 */ + + inputData[0] = chan; // flags, channel 3:0 (LAN 1) + inputData[1] = subfunc; // Param selector (3 = ip addr) + inputData[2] = bset; // Set selector + inputData[3] = 0; // Block selector + + status = ipmi_cmd(GET_LAN_CONFIG, inputData, 4, responseData, + &responseLength, &completionCode, fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + if (fdebug) + SELprintf("GetLanEntry: completion code=%x\n", + completionCode); + status = completionCode; + } else { + // dont copy first byte (Parameter revision, usu 0x11) + if (responseLength > 0) { + n = responseLength-1; + memcpy(pLanRecord,&responseData[1],n); + } else n = 0; + pLanRecord->data[n] = 0; + //successful, done + return(0); + } + } + + // we are here because completionCode is not COMPLETION_CODE_OK + if (fdebug) + SELprintf("GetLanEntry: ipmi_cmd status=%d completionCode=%x\n", + status,completionCode); + return status; +} /* end GetLanEntry() */ + +static int SetLanEntry(uchar subfunc, LAN_RECORD *pLanRecord, int reqlen) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + uchar inputData[24]; + int status; + uchar completionCode; + + if (pLanRecord == NULL) + { + if (fdebug) + printf("SetLanEntry(%d): error, input buffer is NULL\n",subfunc); + return (-1); + } + if (vend_id == VENDOR_SUPERMICROX || vend_id == VENDOR_SUPERMICRO) { + /* SUPERMICRO cannot set grat arp or grat arp interval */ + if (subfunc == 10 || subfunc == 11) return(0); + } + + inputData[0] = lan_ch; // flags, channel 3:0 (LAN 1) + inputData[1] = subfunc; // Param selector (3 = ip addr) + memcpy(&inputData[2],pLanRecord,reqlen); + + status = ipmi_cmd(SET_LAN_CONFIG, inputData, (uchar)(reqlen+2), + responseData, &responseLength,&completionCode,fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + if (fdebug) + SELprintf("SetLanEntry(%d): completion code=%x\n", + subfunc,completionCode); // responseData[0]); + return(completionCode); + } else { + //successful, done + return(0); + } + } + + // we are here because completionCode is not COMPLETION_CODE_OK + if (fdebug) + SELprintf("SetLanEntry(%d): ipmi_cmd status=%d ccode=%x\n", + subfunc,status,completionCode); + return status; +} /* end SetLanEntry() */ + +int GetPefEntry(uchar subfunc, ushort rec_id, PEF_RECORD *pPefRecord) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + uchar inputData[24]; /* only use 3 bytes for input */ + int status, n; + uchar completionCode; + + if (pPefRecord == NULL) + { + if (fdebug) + printf("GetPefEntry(%d): error, output buffer is NULL\n",subfunc); + return (-1); + } + + inputData[0] = subfunc; // Parameter = Evt Filter Table + inputData[1] = (uchar)rec_id; + inputData[2] = 0; + + status = ipmi_cmd(GET_PEF_CONFIG, inputData, 3, responseData, + &responseLength, &completionCode, fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + if (fdebug) + SELprintf("GetPefEntry(%d/%d): completion code=%x\n", + subfunc,rec_id,completionCode); + status = completionCode; + } else { + /* expect PEF record to be >=21 bytes */ + if (responseLength > 1) n = responseLength-1; + else n = 0; + if (n > 21) n = 21; /*only use 21 bytes*/ + if ((subfunc == 6) && (n < 21)) { + if (fdebug) + printf("GetPefEntry(%d/%d): length %d too short\n", + subfunc,rec_id,responseLength); + } + // dont copy first byte (Parameter revision, usu 0x11) + if (n == 0) memset(pPefRecord,0,21); + else memcpy(pPefRecord,&responseData[1],n); + //successful, done + return(0); + } + } + + // we are here because completionCode is not COMPLETION_CODE_OK + if (fdebug) + SELprintf("GetPefEntry: ipmi_cmd status=%x completionCode=%x\n", + status, completionCode); + return status; +} /* end GetPefEntry() */ + +int SetPefEntry(PEF_RECORD *pPefRecord) +{ + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + uchar inputData[32]; /* sizeof(PEF_RECORD) = 21 +1=22 */ + int status; + uchar completionCode; + uchar subfunc; + + subfunc = 0x06; // Parameter = Evt Filter Table + + if (pPefRecord == NULL) { + if (fdebug) + printf("SetPefEntry: error, output buffer is NULL\n"); + return (-1); + } + + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 + // 06 0c 80 01 01 00 ff ff 20 ff 6f ff 00 00 00 00 00 00 00 00 00 00 + // memset(&inputData[0],0,requestData.dataLength); + inputData[0] = subfunc; + memcpy(&inputData[1],pPefRecord,sizeof(PEF_RECORD)); + + status = ipmi_cmd(SET_PEF_CONFIG, inputData, sizeof(PEF_RECORD)+1, + responseData, &responseLength, &completionCode, fdebug); + + if (status == ACCESS_OK) { + if( completionCode ) { + if (fdebug) + SELprintf("SetPefEntry: completion code=%x\n", + completionCode); // responseData[0]); + status = completionCode; + } else { + //successful, done + return(0); + } + + } + + // we are here because completionCode is not COMPLETION_CODE_OK + if (fdebug) + SELprintf("SetPefEntry: ipmi_cmd status=%d completion code=%x\n", + status,completionCode); + return(status); + +} /* end SetPefEntry() */ + +int DisablePef(int anum) +{ + uchar iData[24]; /* sizeof(PEF_RECORD) = 21 +1=22 */ + uchar rData[MAX_BUFFER_SIZE]; + int rLength = MAX_BUFFER_SIZE; + uchar cc; + int status; + + if (fmBMC) { + SELprintf("mini-BMC does not support disabling BMC LAN\n"); + return(-1); + } else { + status = SetChanAcc(lan_ch, 0x80, CHAN_ACC_DISABLE); + if (fdebug) SELprintf("SetChanAcc(lan/active), ret = %d\n",status); + status = SetChanAcc(lan_ch, 0x40, CHAN_ACC_DISABLE); + SELprintf("SetChanAcc(lan), ret = %d\n",status); + if (status != 0) return(status); + } + + iData[0] = 0x01; /* PEF Control Param */ + iData[1] = 0x00; /* PEF disable */ + rLength = MAX_BUFFER_SIZE; + status = ipmi_cmd(SET_PEF_CONFIG, iData, 2, rData, &rLength, + &cc, fdebug); + if (status != 0) return(status); + if( cc ) { + SELprintf("DisablePef[%d]: completion code=%x\n",iData[0],cc); + return(-1); + } + + if (anum != 0) { + iData[0] = 0x09; /* PEF Alert Policy Table */ + iData[1] = (uchar)anum; /* Policy number (default 0x01) */ + iData[2] = 0x10; /* PEF LAN, policy disable */ + iData[3] = 0x00; /* LAN_CH=00, default dest=00 */ + iData[4] = 0x00; /* No alert string */ + rLength = MAX_BUFFER_SIZE; + status = ipmi_cmd(SET_PEF_CONFIG, iData, 5, rData, &rLength, + &cc, fdebug); + if (status != 0) return(status); + if( cc ) { + SELprintf("DisablePef[%d]: completion code=%x\n",iData[0],cc); + return(-1); + } + } + return(status); +} + +int ShowPef(void) +{ + uchar iData[24]; /* sizeof(PEF_RECORD) = 21 +1=22 */ + uchar rData[MAX_BUFFER_SIZE]; + int rLength = MAX_BUFFER_SIZE; + uchar cc; + int status, i,j; + + for (j = 1; j < MAX_PEFPARAMS; j++) { + if (j == 4 && fmBMC) { + /* fmBMC gets cc=0x80 for param 4, so skip it. */ + continue; + } + iData[0] = (uchar)j; /* PEF Control Param */ + if (j == 6 || j == 7 || j == 9) iData[1] = 1; + else iData[1] = 0x00; /* PEF Set Selector */ + if (j == 13) iData[2] = 1; + else iData[2] = 0x00; /* PEF Block Selector */ + rLength = MAX_BUFFER_SIZE; + status = ipmi_cmd(GET_PEF_CONFIG, iData, 3, rData, &rLength, + &cc, fdebug); + if (status == 0 && cc == 0) { + SELprintf("PefParam[%d]: ",iData[0]); + if (rLength > 0) + for (i=0;i= 'a' && str[i] <= 'z') str[i] &= 0x5F; + for (i = 0; i < NBAUDS; i++) { + n = strlen_(mapbaud[i].str); + if (strncmp(str,mapbaud[i].str,n) == 0) { + baud = mapbaud[i].val; + break; + } + } + if (i == NBAUDS || baud == 0) { + printf("Invalid -B parameter value (%s), using 19.2K.\n",str); + i = 1; /* default is 19.2K */ + baud = mapbaud[i].val; /* =7 */ + } + if (fdebug) printf("new baud = %02x (%s)\n",baud,mapbaud[i].str); + return(baud); +} + +static char *Baud2Str(unsigned char bin) +{ + char *baudstr; + unsigned char b; + b = bin & 0x0f; + switch(b) { + case 6: baudstr = "9600 "; break; + case 7: baudstr = "19.2k"; break; + case 8: baudstr = "38.4k"; break; + case 9: baudstr = "57.6k"; break; + case 10: baudstr = "115.2k"; break; + default: baudstr = "nobaud"; + } + return(baudstr); +} + +static int BaudValid(unsigned char b) +{ + int val = 0; + switch(b) { + case 6: val = 1; break; + case 7: val = 1; break; + case 8: val = 1; break; + case 9: val = 1; break; + case 10: val = 1; break; + default: val = 0; break; + } + return(val); +} + +/* + * atomac - converts ASCII string to binary MAC address (array). + * Accepts input formatted as 11:22:33:44:55:66 or 11-22-33-44-55-66. + */ +void atomac(uchar *array, char *instr) +{ + int i,j,n; + char *pi; + j = 0; + pi = instr; + n = strlen_(instr); + for (i = 0; i <= n; i++) { + if (instr[i] == ':') { + array[j++] = htoi(pi); + pi = &instr[i+1]; + } else if (instr[i] == '-') { + array[j++] = htoi(pi); + pi = &instr[i+1]; + } else if (instr[i] == 0) { + array[j++] = htoi(pi); + } + if (j >= MAC_LEN) break; /*safety valve*/ + } + if (fdebug) + printf("atomac: %02x %02x %02x %02x %02x %02x\n", + array[0],array[1],array[2],array[3], array[4],array[5]); +} /*end atomac()*/ + +/* extern void atoip(uchar *array,char *instr); *from subs.c*/ +void MacSetInvalid(uchar *mac) +{ + int i; + if (mac == NULL) return; + for (i = 0; i < MAC_LEN; i++) { + if (i == 0) mac[i] = 0xFF; + else mac[i] = 0x00; + } +} + +int MacIsValid(uchar *mac) +{ + int fvalid = 0; + int i; + /* check for initial invalid value of FF:00:... */ + if (mac[0] == 0xff && mac[1] == 0x00) /* marked as invalid */ + return(fvalid); + /* check for all zeros */ + for (i = 0; i < MAC_LEN; i++) + if (mac[i] != 0) { /* not all zeros */ + fvalid = 1; + break; + } + return(fvalid); +} + +int IpIsValid(uchar *ipadr) +{ + int fvalid = 1; + if (ipadr[0] == 0) fvalid = 0; + return(fvalid); +} + +int SubnetIsValid(uchar *subnet) +{ + int fvalid = 0; + /* if masking off at least one bit, say valid */ + if (subnet[0] != 0) fvalid = 1; + return(fvalid); +} + +int SubnetIsSame(uchar *ip1, uchar *ip2, uchar *subnet) +{ + int i; + uchar c1, c2; + for (i = 0; i < 4; i ++) { + c1 = ip1[i] & subnet[i]; + c2 = ip2[i] & subnet[i]; + if (c1 != c2) return 0; + } + return 1; /*same, return true*/ +} + +#ifdef WIN32 +/* + * Obtain network adapter information (Windows). + */ +PIP_ADAPTER_ADDRESSES GetAdapters() { + PIP_ADAPTER_ADDRESSES AdapterAddresses = NULL; + ULONG OutBufferLength = 0; + ULONG RetVal = 0, i; + + // The size of the buffer can be different + // between consecutive API calls. + // In most cases, i < 2 is sufficient; + // One call to get the size and one call to get the actual parameters. + // But if one more interface is added or addresses are added, + // the call again fails with BUFFER_OVERFLOW. + // So the number is picked slightly greater than 2. + // We use i <5 in the example + for (i = 0; i < 5; i++) { + RetVal = GetAdaptersAddresses( + AF_INET, 0, NULL, + AdapterAddresses, + &OutBufferLength); + + if (RetVal != ERROR_BUFFER_OVERFLOW) { + break; + } + + if (AdapterAddresses != NULL) { + free(AdapterAddresses); + } + + AdapterAddresses = (PIP_ADAPTER_ADDRESSES) malloc(OutBufferLength); + if (AdapterAddresses == NULL) { + RetVal = GetLastError(); + break; + } + } + if (RetVal == NO_ERROR) { + // If successful, return pointer to structure + return AdapterAddresses; + } + else { + LPVOID MsgBuf; + + printf("Call to GetAdaptersAddresses failed.\n"); + if (FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + RetVal, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &MsgBuf, + 0, + NULL )) { + printf("\tError: %s", MsgBuf); + } + LocalFree(MsgBuf); + } + return NULL; +} + +/* + * Set BMC MAC corresponding to current BMC IP address (Windows). + */ +int GetLocalMACByIP() { + PIP_ADAPTER_ADDRESSES AdapterAddresses = NULL; + PIP_ADAPTER_ADDRESSES AdapterList; + int result = 0; + + struct sockaddr_in *si; + + AdapterAddresses = GetAdapters(); + AdapterList = AdapterAddresses; + + while (AdapterList) { + PIP_ADAPTER_UNICAST_ADDRESS addr; + addr = AdapterList->FirstUnicastAddress; + if (addr == NULL) si = NULL; + else si = (struct sockaddr_in*)addr->Address.lpSockaddr; + if (si != NULL) { + if(memcmp(&si->sin_addr.s_addr, rgmyip, 4) == 0) { + if (!MacIsValid(rgmymac)) + memcpy(rgmymac, AdapterList->PhysicalAddress, MAC_LEN); + memcpy(osmyip, &si->sin_addr.s_addr, 4); + memcpy(osmymac, AdapterList->PhysicalAddress, MAC_LEN); + wcstombs(ifname,AdapterList->FriendlyName, sizeof(ifname)); + result = 1; + break; + } + } + AdapterList = AdapterList->Next; + } + + if (AdapterAddresses != NULL) { + free(AdapterAddresses); + } + return result; +} + +/* + * Get First IP Address in Windows OS + * ipaddr is 4 bytes, macaddr is 6 bytes, ipname can be 64 bytes. + * (called by idiscover.c) + */ +int GetFirstIP(uchar *ipaddr, uchar *macadr, char *ipname, char fdbg) +{ + PIP_ADAPTER_ADDRESSES AdapterAddresses = NULL; + PIP_ADAPTER_ADDRESSES AdapterList; + struct sockaddr_in *si; + uchar *psaddr; + int result = -1; + + AdapterAddresses = GetAdapters(); + AdapterList = AdapterAddresses; + + while (AdapterList) { + PIP_ADAPTER_UNICAST_ADDRESS addr; + + addr = AdapterList->FirstUnicastAddress; + si = (struct sockaddr_in*)addr->Address.lpSockaddr; + psaddr = (uchar *)&si->sin_addr.s_addr; + if ((psaddr[0] != 0) && (psaddr[0] != 169)) { + if (fdbg) printf("found IP: s_addr=%d.%d.%d.%d\n", + psaddr[0], psaddr[1], psaddr[2], psaddr[3]); + if (ipaddr != NULL) + memcpy(ipaddr, &si->sin_addr.s_addr, 4); + if (macadr != NULL) { + memcpy(macadr, AdapterList->PhysicalAddress, MAC_LEN); + if (fdbg) printf("found MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", + macadr[0], macadr[1], macadr[2], macadr[3], + macadr[4], macadr[5]); + } + if (ipname != NULL) { + wcstombs(ipname,AdapterList->FriendlyName, sizeof(ifname)); + if (fdbg) printf("found Adapter: %d\n",ipname); + } + result = 0; + break; + } + AdapterList = AdapterList->Next; + } + + if (AdapterAddresses != NULL) { + free(AdapterAddresses); + } + return result; +} + +/* + * Set BMC MAC corresponding to current BMC IP address (Windows). + */ +int GetLocalIPByMAC(uchar *macadr) { + PIP_ADAPTER_ADDRESSES AdapterAddresses = NULL; + PIP_ADAPTER_ADDRESSES AdapterList; + int result = 0; + + struct sockaddr_in *si; + + AdapterAddresses = GetAdapters(); + AdapterList = AdapterAddresses; + + while (AdapterList) { + PIP_ADAPTER_UNICAST_ADDRESS addr; + if(memcmp(AdapterList->PhysicalAddress, macadr, MAC_LEN) == 0) { + addr = AdapterList->FirstUnicastAddress; + + si = (struct sockaddr_in*)addr->Address.lpSockaddr; + if (fdebug) { + uchar *psaddr; + psaddr = (uchar *)&si->sin_addr.s_addr; + printf("mac match: rgmyip=%d.%d.%d.%d s_addr=%d.%d.%d.%d\n", + rgmyip[0], rgmyip[1], rgmyip[2], rgmyip[3], + psaddr[0], psaddr[1], psaddr[2], psaddr[3]); + } + if (!IpIsValid(rgmyip) && (fsharedMAC==1)) /*not specified, shared*/ + memcpy(rgmyip, &si->sin_addr.s_addr, 4); + memcpy(osmyip, &si->sin_addr.s_addr, 4); + memcpy(osmymac, AdapterList->PhysicalAddress, MAC_LEN); + wcstombs(ifname,AdapterList->FriendlyName, sizeof(ifname)); + result = 1; + break; + } + AdapterList = AdapterList->Next; + } + + if (AdapterAddresses != NULL) { + free(AdapterAddresses); + } + return result; +} +/* + * Set MAC and IP address from given interface name (Windows). + */ +int GetLocalDataByIface() { + PIP_ADAPTER_ADDRESSES AdapterAddresses = NULL; + PIP_ADAPTER_ADDRESSES AdapterList; + int result = 0; + + size_t origsize, newsize, convertedChars; + wchar_t* wcstring; + struct sockaddr_in *si; + + AdapterAddresses = GetAdapters(); + AdapterList = AdapterAddresses; + + origsize = strlen(ifname) + 1; + newsize = origsize; + convertedChars = 0; + wcstring = (wchar_t*) malloc(sizeof(wchar_t) * newsize) ; + if (wcstring == NULL) AdapterList = NULL; /*skip loop, do free*/ + else mbstowcs(wcstring, ifname, origsize ); + + while (AdapterList) { + PIP_ADAPTER_UNICAST_ADDRESS addr; + if(wcsstr(AdapterList->FriendlyName, wcstring)) { + printf("Using interface: %S\n", AdapterList->FriendlyName); + printf("\t%S\n", AdapterList->Description); + addr = AdapterList->FirstUnicastAddress; + + si = (struct sockaddr_in*)addr->Address.lpSockaddr; + if (fdebug) { + uchar *psaddr; + psaddr = (uchar *)&si->sin_addr.s_addr; + printf("mac match: rgmyip=%d.%d.%d.%d s_addr=%d.%d.%d.%d " + "fsharedMAC=%d\n", + rgmyip[0], rgmyip[1], rgmyip[2], rgmyip[3], + psaddr[0], psaddr[1], psaddr[2], psaddr[3], + fsharedMAC); + } + if (!IpIsValid(rgmyip)) { /*IP not specified*/ + memcpy(rgmyip, &si->sin_addr.s_addr, 4); + memcpy(rgmymac, AdapterList->PhysicalAddress, MAC_LEN); + } + memcpy(osmyip, &si->sin_addr.s_addr, 4); + memcpy(osmymac, AdapterList->PhysicalAddress, MAC_LEN); + /* FriendlyName == ifname already */ + result = 1; + break; + } + AdapterList = AdapterList->Next; + } + + if (AdapterAddresses != NULL) { + free(AdapterAddresses); + } + return result; +} + +int FindEthNum(uchar *macadrin) +{ + int i; + uchar macadr[MAC_LEN]; + memcpy(macadr,macadrin,MAC_LEN); + if (fsharedMAC == 0 && vend_id == VENDOR_INTEL) { + /* Intel factory assigns them this way, so use that to compare */ + macadr[MAC_LEN-1] -= 2; /*OS MAC = BMC MAC - 2*/ + } + i = GetLocalIPByMAC(macadr); + if (i == 1) fethfound = 1; + if (fdebug) /* show the local OS eth if and MAC */ + printf("FindEth: OS %s IP=%d.%d.%d.%d MAC=%02x:%02x:%02x:%02x:%02x:%02x\n", + ifname, osmyip[0], osmyip[1], osmyip[2], osmyip[3], + osmymac[0], osmymac[1], osmymac[2], osmymac[3], + osmymac[4], osmymac[5]); + /* The actual Windows ethernet interface is determined + * in Get_IPMac_Addr using ipconfig, so + * init eth interface number as eth0 for Windows. */ + return(0); +} +#elif defined(HPUX) +#define INSAP 22 +#define OUTSAP 24 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define bcopy(source, destination, length) memcpy(destination, source, length) +#define AREA_SZ 5000 /*=* buffer length in bytes *=*/ +#define GOT_CTRL 1 +#define GOT_DATA 2 +#define GOT_BOTH 3 +#define GOT_INTR 4 +#define GOT_ERR 128 +static u_long ctl_area[AREA_SZ]; +static u_long dat_area[AREA_SZ]; +static struct strbuf ctl = {AREA_SZ, 0, (char *)ctl_area}; +static struct strbuf dat = {AREA_SZ, 0, (char *)dat_area}; +static char *dlpi_dev[] = {"/dev/dlpi", ""}; + +/*=* get a message from a stream; return type of message *=*/ +static int get_msg(int fd) +{ + int flags = 0; + int res, ret; + ctl_area[0] = 0; + dat_area[0] = 0; + ret = 0; + res = getmsg(fd, &ctl, &dat, &flags); + if(res < 0) { + if(errno == EINTR) { + return(GOT_INTR); + } else { + return(GOT_ERR); + } + } + if(ctl.len > 0) { + ret |= GOT_CTRL; + } + if(dat.len > 0) { + ret |= GOT_DATA; + } + return(ret); +} + +/*=* verify that dl_primitive in ctl_area = prim *=*/ +static int check_ctrl(int prim) +{ + dl_error_ack_t *err_ack = (dl_error_ack_t *)ctl_area; + if(err_ack->dl_primitive != prim) { + return GOT_ERR; + } + return 0; +} + +/*=* put a control message on a stream *=*/ +static int put_ctrl(int fd, int len, int pri) +{ + ctl.len = len; + if(putmsg(fd, &ctl, 0, pri) < 0) { + return GOT_ERR; + } + return 0; +} + +/*=* put a control + data message on a stream *=*/ +static int put_both(int fd, int clen, int dlen, int pri) +{ + ctl.len = clen; + dat.len = dlen; + if(putmsg(fd, &ctl, &dat, pri) < 0) { + return GOT_ERR; + } + return 0; +} + +/*=* open file descriptor and attach *=*/ +static int dl_open(const char *dev, int ppa, int *fd) +{ + dl_attach_req_t *attach_req = (dl_attach_req_t *)ctl_area; + if((*fd = open(dev, O_RDWR)) == -1) { + return GOT_ERR; + } + attach_req->dl_primitive = DL_ATTACH_REQ; + attach_req->dl_ppa = ppa; + put_ctrl(*fd, sizeof(dl_attach_req_t), 0); + get_msg(*fd); + return check_ctrl(DL_OK_ACK); +} + +/*=* send DL_BIND_REQ *=*/ +static int dl_bind(int fd, int sap, u_char *addr) +{ + dl_bind_req_t *bind_req = (dl_bind_req_t *)ctl_area; + dl_bind_ack_t *bind_ack = (dl_bind_ack_t *)ctl_area; + bind_req->dl_primitive = DL_BIND_REQ; + bind_req->dl_sap = sap; + bind_req->dl_max_conind = 1; + bind_req->dl_service_mode = DL_CLDLS; + bind_req->dl_conn_mgmt = 0; + bind_req->dl_xidtest_flg = 0; + put_ctrl(fd, sizeof(dl_bind_req_t), 0); + get_msg(fd); + if (GOT_ERR == check_ctrl(DL_BIND_ACK)) { + return GOT_ERR; + } + bcopy((u_char *)bind_ack + bind_ack->dl_addr_offset, addr, + bind_ack->dl_addr_length); + return 0; +} + +int FindEthNum(uchar *addr) +{ /* Need to use DLPI for HPUX */ + /*See http://cplus.kompf.de/artikel/macaddr.html */ + int fd; + int ppa; + u_char mac_addr[25]; + char **dev; + int i = 0; + + for (dev = dlpi_dev; **dev != ''; ++dev) { + for (ppa=0; ppa<10; ++ppa) { + if (GOT_ERR != dl_open(*dev, ppa, &fd)) { + if (GOT_ERR != dl_bind(fd, INSAP, mac_addr)) { + // bcopy( mac_addr, addr, 6); + i = ppa; + if (memcmp(mac_addr,addr,MAC_LEN) == 0) { + memcpy(osmymac, addr, MAC_LEN); + return(ppa); + } + } + } + close(fd); + } + } + return(i); +} +#else + +static char *get_ifreq_mac(struct ifreq *ifrq) +{ + char *ptr; +#ifdef SOLARIS + ptr = (char *)&ifrq->ifr_ifru.ifru_enaddr[0]; +#elif BSD + ptr = (char *)&ifrq->ifr_ifru.ifru_addr.sa_data[0]; +#elif MACOS + static uchar mactmp[MAC_LEN]; + ptr = &mactmp[0]; + MacSetInvalid(ptr); +#else + ptr = (char *)&ifrq->ifr_hwaddr.sa_data[0]; +#endif + return (ptr); +} + +extern int find_ifname(char *ifname); /*see idiscover.c*/ + +int FindEthNum(uchar *macadrin) +{ /*only used for Linux*/ + struct ifreq ifr; + int skfd; + int nCurDevice; + int devnum = -1; + int devos = 0; + uchar macadr[MAC_LEN]; + uchar macsav[MAC_LEN]; + uchar mactmp[MAC_LEN]; + uchar ipsav[4]; + char szDeviceName[ 16 ]; /* MAX_DEVICE_NAME_LENGTH + 1 */ + uchar fipvalid = 0; + int n; + + memcpy(macadr,macadrin,MAC_LEN); + if (fsharedMAC == 0 && vend_id == VENDOR_INTEL) { + /* Intel factory assigns them this way, so use that to compare */ + macadr[MAC_LEN-1] -= 2; /*OS MAC = BMC MAC - 2*/ + } +#ifdef DBG + if (fdebug) { + uchar *pb; + pb = macadrin; + printf("input mac:%02x:%02x:%02x:%02x:%02x:%02x " + "tmp mac:%02x:%02x:%02x:%02x:%02x:%02x\n", + pb[0],pb[1],pb[2],pb[3],pb[4],pb[5], + macadr[0],macadr[1],macadr[2],macadr[3],macadr[4],macadr[5]); + } +#endif + + n = find_ifname(szDeviceName); + if (n >= 0) { + n = strlen_(szDeviceName); + if (n < sizeof(ifpattn)) { + strcpy(ifpattn,szDeviceName); + ifpattn[n - 1] = 0; /*truncate last digit*/ + } + if (fdebug) + printf("found ifname %s, pattern %s\n",szDeviceName,ifpattn); + } + + if ( ( skfd = socket(AF_INET, SOCK_DGRAM, 0 ) ) < 0) { + if ( fdebug ) { + perror("socket"); + return devnum; + } + } + + for( nCurDevice = 0 ; + (nCurDevice < NUM_DEVICES_TO_CHECK) && (devnum == -1); + nCurDevice++ ) + { + sprintf( szDeviceName, "%s%d", ifpattn, nCurDevice ); /*eth%d*/ + memset((char *)&ifr,0,sizeof(ifr)); + strcpy(ifr.ifr_name, szDeviceName ); +#ifdef SIOCGIFHWADDR + if (ioctl(skfd, SIOCGIFHWADDR, &ifr) > 0) { + if ( fdebug ) + printf("FindEthNum: Could not get MAC address for %s\n", + szDeviceName); + } else +#endif + { + uchar *pb; + pb = get_ifreq_mac(&ifr); +#ifdef DBG + if (fdebug) { + printf("%s mac: %02x:%02x:%02x:%02x:%02x:%02x\n", + szDeviceName, pb[0],pb[1],pb[2],pb[3],pb[4],pb[5]); + } +#endif + memcpy(macsav, pb, MAC_LEN); + /* check if this device is configured for IP addr */ + memset((char *)&ifr,0,sizeof(ifr)); + strcpy(ifr.ifr_name, szDeviceName); + ifr.ifr_addr.sa_family = AF_INET; + if (ioctl(skfd, SIOCGIFADDR, &ifr) >= 0) { + fipvalid = 1; + memcpy(ipsav, &ifr.ifr_addr.sa_data[2], 4); + } else fipvalid = 0; + if (memcmp(macsav, macadr, MAC_LEN) == 0) { /*found match*/ + devnum = nCurDevice; + memcpy(osmymac, macsav, MAC_LEN); + if (fipvalid) memcpy(osmyip, ipsav, 4); + break; + } + if (nCurDevice == 0) { /*set a default of eth0*/ + devos = nCurDevice; + memcpy(osmymac,macsav, MAC_LEN); + if (fipvalid) memcpy(osmyip, ipsav, 4); + } else if (fipvalid) { /*check if NIC1 is eth1,2,3,...*/ + memcpy(mactmp,osmymac,MAC_LEN); + mactmp[MAC_LEN-1] -= 1; + if (memcmp(mactmp,macsav,MAC_LEN) == 0) { + devos = nCurDevice; + memcpy(osmymac, macsav, MAC_LEN); + memcpy(osmyip, ipsav, 4); + } + } + } /*end else*/ + } + if (!fsetifn) { + if (devnum == -1) { /*not found, use devos default*/ + devnum = devos; + sprintf( ifname, "%s%d", ifpattn, devnum ); /*eth%d*/ + } else { /* match was found, devnum set */ + fethfound = 1; + strcpy(ifname, szDeviceName ); + } + } + close(skfd); + if (fdebug) /* show the local OS eth if and MAC */ + printf("FindEth: OS %s IP=%d.%d.%d.%d MAC=%02x:%02x:%02x:%02x:%02x:%02x\n", + ifname, osmyip[0], osmyip[1], osmyip[2], osmyip[3], + osmymac[0], osmymac[1], osmymac[2], osmymac[3], + osmymac[4], osmymac[5]); + return(devnum); +} +#endif + +int show_channels(void) +{ + int ret, rlen; + uchar iData[2]; + uchar rData[10]; + uchar cc, mtype; + int j; + int rv = -1; + + for (j = 1; j < MAXCHAN; j++) { + rlen = sizeof(rData); + iData[0] = (uchar)j; /*channel #*/ + memset(rData,0,9); /*initialize recv data*/ + ret = ipmi_cmd(GET_CHANNEL_INFO, iData, 1, rData, &rlen, &cc, fdebug); + if (rv != 0) rv = ret; + if (ret == 0xcc || cc == 0xcc) /* special case for ipmi_lan */ + continue; + if (ret != 0) { + if (fdebug) printf("get_chan_info rc = %x\n",ret); + break; + } + mtype = rData[1]; /* channel medium type */ + switch(mtype) { + case 4: printf("channel[%d] type = lan\n",j); break; /*802.3 LAN type*/ + case 5: printf("channel[%d] type = serial\n",j); break; + case 7: printf("channel[%d] type = pci_smbus\n",j); break; + case 12: printf("channel[%d] type = system_interface\n",j); break; + default: printf("channel[%d] type = other %d\n",j,mtype); break; + } + rv = 0; + } /*end for j*/ + return(rv); +} + +/* + * GetBmcEthDevice + * Attempt to auto-detect the BMC LAN channel and matching OS eth port. + * INPUT: lan_parm = lan channel from user -L option, 0xFF if not specified + * OUTPUT: lan_ch is set to BMC LAN channel number + * if success, returns index of OS eth port (0, 1, ...). + * if no lan channels found, returns -2. + * if other error, returns -1. + */ +int GetBmcEthDevice(uchar lan_parm) +{ + LAN_RECORD LanRecord; + int devnum = -1; + int ret; + uchar bmcMacAddress[ MAC_LEN ]; /*MAC_LEN = 6*/ + int rlen; + uchar iData[2]; + uchar rData[10]; + uchar cc; + int i = 0; + int j, jstart, jend, jlan; + uchar mtype; + uchar *pb; + int fchgmac; + // int found = 0; + + /* Find the LAN channel(s) via Channel Info */ + if (lan_parm < MAXCHAN) { /* try user-specified channel only */ + lan_ch = lan_parm; + jstart = lan_parm; + jend = lan_parm+1; + } else { + jstart = 1; + jend = MAXCHAN; + } + memset(bmcMacAddress,0xff,sizeof(bmcMacAddress)); /*initialize to invalid*/ + for (j = jstart; j < jend; j++) { + rlen = sizeof(rData); + iData[0] = (uchar)j; /*channel #*/ + memset(rData,0,9); /*initialize recv data*/ + ret = ipmi_cmd(GET_CHANNEL_INFO, iData, 1, rData, &rlen, &cc, fdebug); + if (ret == 0xcc || cc == 0xcc) /* special case for ipmi_lan */ + continue; + if (ret != 0) { + if (fdebug) printf("get_chan_info rc = %x\n",ret); + break; + } + mtype = rData[1]; /* channel medium type */ + if (mtype == 4) { /* 802.3 LAN type*/ + if (fdebug) printf("chan[%d] = lan\n",j); + jlan = lan_ch; /*save prev lan chan */ + /* Get BMC MAC for this LAN channel. */ + /* Note: BMC MAC may not be valid yet. */ + lan_ch = (uchar)j; /*set lan channel for GetLanEntry*/ + ret = GetLanEntry( 5 /*MAC_ADDRESS_LAN_PARAM*/,0, &LanRecord); + if ( ret != 0 ) { + lan_ch = (uchar)jlan; /*restore lan_ch*/ + printf( "GetBmcEthDevice: GetLanEntry failed\n" ); + return devnum; + } else { + pb = &LanRecord.data[0]; + if (fdebug) printf("chan[%d] BMC MAC %x:%x:%x:%x:%x:%x\n",j, + pb[0], pb[1], pb[2], pb[3], pb[4], pb[5] ); + fchgmac = 0; + /* use the lowest valid lan channel MAC address */ + if (!MacIsValid(bmcMacAddress)) /* old MAC not valid*/ + fchgmac = 1; + else if (MacIsValid(pb) && /* new MAC is valid and*/ + (memcmp(bmcMacAddress,pb, sizeof(bmcMacAddress)) > 0)) + fchgmac = 1; /* new MAC lower */ + /* if no -L 3 and this is gcm, do not pick it. */ + if ((j == gcm_ch) && (lan_parm == PARM_INIT)) + fchgmac = 0; + if (fchgmac) { /* pick this channel & MAC */ + memcpy(bmcMacAddress,pb,sizeof(bmcMacAddress)); + lan_ch = (uchar)j; + } else lan_ch = (uchar)jlan; /*restore prev lan chan*/ + } + i++; /* i = num lan channels found */ + } else if (mtype == 5) { /* serial type*/ + if (fdebug) printf("chan[%d] = serial\n",j); + ser_ch = (uchar)j; /* set to last serial channel */ + } else if (mtype == 7) { /* PCI SMBus */ + if (fdebug) printf("chan[%d] = pci_smbus\n",j); + } else if (mtype == 12) { /* system interface */ + if (fdebug) printf("chan[%d] = system_interface\n",j); + } else /* other channel medium types, see IPMI 1.5 Table 6-3 */ + if (fdebug) printf("chan[%d] = %d\n",j,mtype); + } + if (i == 0) return(-2); /* no lan channels found */ + if (fdebug) printf("lan_ch detected = %d\n",lan_ch); + + /* This will work if the BMC MAC is shared with the OS */ + /* Otherwise, wait until we get the eth dev from the gateway below */ + devnum = FindEthNum(bmcMacAddress); + if ( fdebug ) + printf("GetBmcEthDevice: channel %d, %s%d\n",lan_ch,ifpattn,devnum); + return devnum; +} + +/* file_grep/findmatch - No longer used here, see ievents.c */ + +/* + * Get_Mac + * This routine finds a MAC address from a given IP address. + * Usually for the Alert destination. + * It uses ARP cache to do this. + */ +#if defined(WIN32) +int Get_Mac(uchar *ipadr,uchar *macadr, char *nodname) +{ + DWORD dwRetVal; + IPAddr DestIp = 0; + IPAddr SrcIp = 0; /* default for src ip */ + ULONG MacAddr[2]; /* for 6-byte hardware addresses */ + ULONG PhysAddrLen = MAC_LEN; /* default to length of six bytes */ + BYTE *bPhysAddr; + + if (!IpIsValid(ipadr)) { + if (fdebug) printf("Get_Mac: invalid IP addr\n"); + return 1; /*error*/ + } + memcpy(&DestIp, ipadr, 4); + + /* invoke system ARP query */ + dwRetVal = SendARP(DestIp, SrcIp, MacAddr, &PhysAddrLen); + + if (dwRetVal == NO_ERROR) + { /* no error - get the MAC */ + bPhysAddr = (BYTE *) & MacAddr; + if (PhysAddrLen) { + memcpy(macadr, bPhysAddr, MAC_LEN); + } else + printf("Warning: SendArp completed successfully, but returned length=0\n"); + } else if (dwRetVal == ERROR_GEN_FAILURE) + { /* MAC not available in this network - get gateway MAC */ + memcpy(macadr, rggwymac, MAC_LEN); + } else + { /* other errors */ + printf("Error: SendArp failed with error: %d", dwRetVal); + switch (dwRetVal) { + case ERROR_INVALID_PARAMETER: + printf(" (ERROR_INVALID_PARAMETER)\n"); + break; + case ERROR_INVALID_USER_BUFFER: + printf(" (ERROR_INVALID_USER_BUFFER)\n"); + break; + case ERROR_BAD_NET_NAME: + printf(" (ERROR_GEN_FAILURE)\n"); + break; + case ERROR_BUFFER_OVERFLOW: + printf(" (ERROR_BUFFER_OVERFLOW)\n"); + break; + case ERROR_NOT_FOUND: + printf(" (ERROR_NOT_FOUND)\n"); + break; + default: + printf("\n"); + break; + } + return 1; + } + return 0; +} /* end Get_Mac() for WIN32*/ +#elif defined(SOLARIS) +int Get_Mac(uchar *ipadr,uchar *macadr, char *nodename) +{ + FILE *fparp; + char buff[1024]; + /* char arpfile[] = "/proc/net/arp"; */ + char alertfile[] = "/tmp/dest.arping"; + char arping_cmd[128]; + char *pb, *pm; + int num, i; + int foundit = 0; + int ret = 0; + + if (IpIsValid(ipadr)) { /* if valid IP address */ + sprintf(arping_cmd, + "ping %d.%d.%d.%d >/dev/null; arp -a -n |grep %d.%d.%d.%d >%s\n", + ipadr[0],ipadr[1],ipadr[2],ipadr[3], + ipadr[0],ipadr[1],ipadr[2],ipadr[3], alertfile); + } else if (nodename != NULL) { /*if valid nodename */ + sprintf(arping_cmd, + "ping %s >/dev/null; arp -a |grep %s >%s\n", + nodename,nodename,alertfile); + } else ret = -1; + + if (ret == 0) { /* if valid IP address */ + /* make sure the destination is in the arp cache */ + if (fdebug) printf("%s", arping_cmd); + system(arping_cmd); + + fparp = fopen(alertfile,"r"); + if (fparp == NULL) { + fprintf(stdout,"Get_Mac: Cannot open %s, errno = %d\n", + alertfile,get_errno()); + ret = -1; + } else { + /* sample output: */ + /* e1000g0 cooper9 255.255.255.255 o 00:07:e9:06:55:c8 */ + while (fgets(buff, 1023, fparp)) { + /* should only run through loop once */ + num = strcspn(buff," \t"); /* skip 1st word ("e1000g0") */ + i = strspn(&buff[num]," \t"); /* skip whitespace */ + pb = &buff[num+i]; + num = strcspn(pb," \t"); /* skip 2nd word (nodename/IP) */ + i = strspn(&pb[num]," \t"); /* skip whitespace */ + pb += (num+i); + pm = &pb[25]; /* Now pb[25] has the MAC address */ + { /*validate new address?*/ + if (fdebug) printf("Get_Mac: mac=%s\n",pm); + foundit = 1; + if (!MacIsValid(macadr)) atomac(macadr,pm); + break; + } + } /*end while*/ + fclose(fparp); + } /*end else file opened*/ + } /*endif valid IP */ + + if (foundit == 0) { /* no errors, but no mac reply */ + if (MacIsValid(rggwymac) && !MacIsValid(macadr)) + /* this is useful if the ipadr is not in the local subnet */ + memcpy(macadr,rggwymac,6); /* get to it from the default gateway */ + } + return(ret); +} /*end Get_Mac for Solaris*/ +#elif defined(BSD) +int Get_Mac(uchar *ipadr,uchar *macadr, char *nodename) +{ + FILE *fparp; + char buff[1024]; + /* char arpfile[] = "/proc/net/arp"; */ + char alertfile[] = "/tmp/dest.arping"; + char arping_cmd[128]; + char *pb, *pm; + int num, i, j; + int foundit = 0; + int ret = 0; + + if (IpIsValid(ipadr)) { /* if valid IP address */ + sprintf(arping_cmd, + "ping -c2 %d.%d.%d.%d >/dev/null; arp -a -n |grep %d.%d.%d.%d >%s\n", + ipadr[0],ipadr[1],ipadr[2],ipadr[3], + ipadr[0],ipadr[1],ipadr[2],ipadr[3], alertfile); + } else if (nodename != NULL) { /*if valid nodename */ + sprintf(arping_cmd, + "ping -c2 %s >/dev/null; arp -a |grep %s >%s\n", + nodename,nodename,alertfile); + } else ret = -1; + + if (ret == 0) { /* if valid IP address */ + /* make sure the destination is in the arp cache */ + if (fdebug) printf("%s", arping_cmd); + system(arping_cmd); + + fparp = fopen(alertfile,"r"); + if (fparp == NULL) { + fprintf(stdout,"Get_Mac: Cannot open %s, errno = %d\n", + alertfile,get_errno()); + ret = -1; + } else { + /* sample output of arp -a -n: */ + /* ? (192.168.1.200) at 00:0e:0c:e5:df:65 on em0 [ethernet] */ + /* sample output of arp -a: */ + /* telcoserv (192.168.1.200) at 00:0e:0c:e5:df:65 on em0 [ethernet] */ + while (fgets(buff, 1023, fparp)) { + /* should only run through loop once */ + pb = &buff[0]; + for (j = 0; j < 3; j++) { /* skip 3 words */ + num = strcspn(pb," \t"); /* skip jth word */ + i = strspn(&pb[num]," \t"); /* skip whitespace */ + pb += (num+i); + } + pm = &pb[0]; /* Now pb[0] has the MAC address */ + { /* no need to validate new address*/ + if (fdebug) printf("Get_Mac: mac=%s\n",pm); + foundit = 1; + if (!MacIsValid(macadr)) atomac(macadr,pm); + break; + } + } /*end while*/ + fclose(fparp); + } /*end else file opened*/ + } /*endif valid IP */ + + if (foundit == 0) { /* no errors, but no mac reply */ + if (MacIsValid(rggwymac) && !MacIsValid(macadr)) + /* this is useful if the ipadr is not in the local subnet */ + memcpy(macadr,rggwymac,6); /* get to it from the default gateway */ + } + return(ret); +} /*end Get_Mac for BSD */ +#else +int Get_Mac(uchar *ipadr,uchar *macadr, char *nodename) +{ /* Get_Mac for Linux */ + FILE *fparp; + char buff[1024]; + /* char arpfile[] = "/proc/net/arp"; */ + char alertfile[] = "/tmp/dest.arping"; + char arping_cmd[128]; + char *pb, *pm, *px; + int num, i; + int foundit = 0; + int ret = 0; + char *_ifname; + + if (strcmp(ifname,"gcm") == 0) _ifname = ifname0; /*see gcm_ch instead*/ + else _ifname = ifname; + + /* Get a MAC address for a given IP address or nodename */ + if (IpIsValid(ipadr)) { /* if valid IP address */ + sprintf(arping_cmd, + "arping -I %s -c 2 %d.%d.%d.%d |grep reply |tail -n1 >%s\n", + _ifname,ipadr[0],ipadr[1],ipadr[2],ipadr[3],alertfile); + } else if (nodename != NULL) { /*if valid nodename */ + sprintf(arping_cmd, + "arping -I %s -c 2 %s |grep reply |tail -n1 >%s\n", + _ifname,nodename,alertfile); + } else ret = -1; + + if (ret == 0) { /* if valid IP address */ + /* make sure the destination is in the arp cache */ + if (fdebug) printf("%s", arping_cmd); + ret = system(arping_cmd); + + fparp = fopen(alertfile,"r"); + if (fparp == NULL) { + fprintf(stdout,"Get_Mac: Cannot open %s, errno = %d\n", + alertfile,get_errno()); + ret = -1; + } else { + ret = 0; + while (fgets(buff, 1023, fparp)) { + /* should only run through loop once */ + num = strcspn(buff," \t"); /* skip 1st word ("Unicast") */ + i = strspn(&buff[num]," \t"); + pb = &buff[num+i]; + if (strncmp(pb,"reply",5) == 0) { /* valid output */ + /* Find the ip address */ + pb += 6 + 5; /* skip "reply from " */ + num = strcspn(pb," \t"); + pb[num] = 0; + if (fdebug) printf("Get_Mac: ip=%s\n",pb); + /* IP address should already match input param */ + if (!IpIsValid(ipadr)) /* had nodname only*/ + atoip(ipadr,pb); /* fill in ipadr */ + /* Now find the mac address */ + pm = strchr(&pb[num+1],'['); + if (pm == NULL) pm = &pb[num+2]; /* just in case */ + pm++; + px = strchr(pm,']'); + if (px == NULL) px = pm + 17; /* just in case */ + px[0] = 0; + if (fdebug) printf("Get_Mac: mac=%s\n",pm); + foundit = 1; + if (!MacIsValid(macadr)) atomac(macadr,pm); + break; + } + } /*end while*/ + fclose(fparp); + } /*end else file opened*/ + } /*endif valid IP */ + + if (foundit == 0) { /* no errors, but no mac reply */ + if (MacIsValid(rggwymac) && !MacIsValid(macadr)) + /* this is useful if the ipadr is not in the local subnet */ + memcpy(macadr,rggwymac,6); /* get to it from the default gateway */ + } + return(ret); +} /* end Get_Mac() for Linux*/ +#endif + +#ifdef WIN32 +/* + * Set subnet mask based on current IP address (Windows). + */ +int SetSubnetMask() { + PMIB_IPADDRTABLE pIPAddrTable; + unsigned int i; + DWORD dwSize = 0, dwRetVal; + LPVOID lpMsgBuf; + + pIPAddrTable = (MIB_IPADDRTABLE*) malloc( sizeof( MIB_IPADDRTABLE) ); + + if ( pIPAddrTable ) { + // Make an initial call to GetIpAddrTable to get the + // necessary size into the dwSize variable + if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) { + free( pIPAddrTable ); + pIPAddrTable = (MIB_IPADDRTABLE *) malloc ( dwSize ); + } + } else + printf("Memory allocation failed.\n"); + + if ( pIPAddrTable ) { + // Make a second call to GetIpAddrTable to get the + // actual data we want + if ( (dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 )) == NO_ERROR ) { + for(i = 0; i < pIPAddrTable->dwNumEntries; ++i) { + if(memcmp(&(pIPAddrTable->table[i].dwAddr), rgmyip, 4) == 0) { + memcpy(rgsubnet, &(pIPAddrTable->table[i].dwMask), 4); + free( pIPAddrTable ); + return 1; + } + } + } else { + if (FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + dwRetVal, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &lpMsgBuf, + 0, + NULL )) { + printf("\tError: %s", lpMsgBuf); + } + + printf("Call to GetIpAddrTable failed.\n"); + } + } + + if ( pIPAddrTable ) + free( pIPAddrTable ); + + return 0; +} + +/* + * Extract gateway address from routing table (Windows). + */ +int SetDefaultGateway() { + PMIB_IPFORWARDTABLE pIpForwardTable; + DWORD dwRetVal, dwSize; + + unsigned int nord_mask; + unsigned int nord_ip; + unsigned int nord_net; + + unsigned int i; + + nord_mask = *((unsigned int *)rgsubnet); + nord_ip = *((unsigned int *)rgmyip); + + nord_net = nord_ip & nord_mask; + + pIpForwardTable = (MIB_IPFORWARDTABLE*) malloc(sizeof(MIB_IPFORWARDTABLE)); + if (pIpForwardTable == NULL) { + printf("Error allocating memory\n"); + return 0; + } + + dwSize = 0; + if (GetIpForwardTable(pIpForwardTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) { + free(pIpForwardTable); + pIpForwardTable = (MIB_IPFORWARDTABLE*) malloc(dwSize); + if (pIpForwardTable == NULL) { + printf("Error allocating memory\n"); + return 0; + } + } + + /* + * Note that the IPv4 addresses returned in + * GetIpForwardTable entries are in network byte order + */ + if ((dwRetVal = GetIpForwardTable(pIpForwardTable, &dwSize, 0)) == NO_ERROR) { + for (i = 0; i < (int) pIpForwardTable->dwNumEntries; i++) { + unsigned int gwaddr = pIpForwardTable->table[i].dwForwardNextHop; + if(nord_net == (gwaddr & nord_mask) && nord_ip != gwaddr) + { /* searching for gateways from our network with different address than ours */ + memcpy(rggwyip, &gwaddr, 4); + return 0; + } + } + free(pIpForwardTable); + return 1; + } + else { + printf("\tGetIpForwardTable failed.\n"); + free(pIpForwardTable); + return 0; + } + +} +/*endif WIN32*/ +#endif + +/* + * Get_IPMac_Addr + * This routine finds the IP and MAC for the local interface, + * the default gateway, and SNMP alert destination from the + * BMC and OS information. + * + * Linux snmpd.conf locations (see ipmiutil.spec): + * RedHat, MontaVista: /etc/snmp/snmpd.conf + * SuSE SLES 8: /etc/ucdsnmpd.conf + * SuSE SLES 9: /etc/snmpd.conf + */ +#ifdef WIN32 +int Get_IPMac_Addr() +{ /*for Windows*/ + char ipstr[] = "IP Address"; + char macstr[] = "Physical Address"; + char gwystr[] = "Default Gateway"; + char substr[] = "Subnet Mask"; + int found = 0; + char fgetmac; + + if (IpIsValid(rgmyip)) + { /* user-specified ip, get mac */ + if (fdebug) printf("User IP was specified\n"); + if (!MacIsValid(rgmymac)) + { /* no user-specified MAC, get it from IP */ + if (fdebug) printf("No user MAC specified\n"); + if(!GetLocalMACByIP()) + { /* couldn't get MAC from IP, get old one */ + if (fdebug) printf("No MAC from IP, use old\n"); + if(IpIsValid(bmcmyip) && MacIsValid(bmcmymac)) + { + printf("Using current BMC MAC %02x:%02x:%02x:%02x:%02x:%02x\n", + bmcmymac[0], bmcmymac[1], + bmcmymac[2], bmcmymac[3], + bmcmymac[4], bmcmymac[5]); + memcpy(rgmymac,bmcmymac,MAC_LEN); + } else { + printf("Failed to obtain valid MAC\n"); + } + } else { + printf("Using adapter MAC %02x:%02x:%02x:%02x:%02x:%02x\n", + rgmymac[0], rgmymac[1], + rgmymac[2], rgmymac[3], + rgmymac[4], rgmymac[5]); + } + } else { /* user MAC available */ + printf("Using user MAC %02x:%02x:%02x:%02x:%02x:%02x\n", + rgmymac[0], rgmymac[1], + rgmymac[2], rgmymac[3], + rgmymac[4], rgmymac[5]); + } + } else { /* no user-specified IP */ + if (fdebug) printf("No user IP specified\n"); + if (!MacIsValid(rgmymac)) + { /* no user-specified MAC, get it from interface */ + if(!GetLocalDataByIface()) + { /* use existing MAC an IP */ + printf("Using current BMC IP %d.%d.%d.%d\n", + bmcmyip[0], bmcmyip[1], + bmcmyip[2], bmcmyip[3]); + memcpy(rgmyip,bmcmyip,4); + printf("Using current BMC MAC %02x:%02x:%02x:%02x:%02x:%02x\n", + bmcmymac[0], bmcmymac[1], + bmcmymac[2], bmcmymac[3], + bmcmymac[4], bmcmymac[5]); + memcpy(rgmymac,bmcmymac,MAC_LEN); + + } + } else { /* user-specified MAC */ + if(!GetLocalIPByMAC(rgmymac)) + { /* use existing MAC and IP */ + printf("Using current BMC IP %d.%d.%d.%d\n", + bmcmyip[0], bmcmyip[1], + bmcmyip[2], bmcmyip[3]); + memcpy(rgmyip,bmcmyip,4); + printf("Using current BMC MAC %02x:%02x:%02x:%02x:%02x:%02x\n", + bmcmymac[0], bmcmymac[1], + bmcmymac[2], bmcmymac[3], + bmcmymac[4], bmcmymac[5]); + memcpy(rgmymac,bmcmymac,MAC_LEN); + } + } + } + + if (rghostname[0] == 0) { /*hostname not specified*/ + if (!fipmilan) + gethostname(rghostname,sizeof(rghostname)); + } + if (fdebug) /* show the local OS eth if and MAC */ + printf("OS %s IP=%d.%d.%d.%d %s MAC=%02x:%02x:%02x:%02x:%02x:%02x used for arp\n", + ifname, osmyip[0],osmyip[1],osmyip[2],osmyip[3], rghostname, + osmymac[0], osmymac[1], osmymac[2], osmymac[3], + osmymac[4], osmymac[5]); + + if(!SubnetIsValid(rgsubnet)) { + SetSubnetMask(); + } + if (!IpIsValid(rggwyip)) { /* if gwy ip not user-specified */ + SetDefaultGateway(); + } + + if (lan_ch == gcm_ch) { + if (SubnetIsSame(rgmyip,rggwyip,rgsubnet)) fgetmac = 1; + else fgetmac = 0; + } else fgetmac = 1; + + if (fgetmac) { + if (IpIsValid(rggwyip) && !MacIsValid(rggwymac)) /*gwy mac not specified*/ + Get_Mac(rggwyip,rggwymac,NULL); + + if (IpIsValid(rggwy2ip) && !MacIsValid(rggwy2mac)) /*gwy2 mac not valid*/ + Get_Mac(rggwy2ip,rggwy2mac,NULL); + } + + return(0); +} /* end Get_IPMac_Addr for Windows */ + +#elif defined(HPUX) +int Get_IPMac_Addr() +{ /*for HP-UX*/ + return(-1); +} +#else +int Get_IPMac_Addr() +{ /*for Linux*/ +#if defined(SOLARIS) + char rtfile[] = "/tmp/route"; + char snmpfile[] = "/etc/snmp/conf/snmpd.conf"; +#elif defined(BSD) + char rtfile[] = "/tmp/route"; + char snmpfile[] = "/etc/snmpd.config"; +#else + char rtfile[] = "/proc/net/route"; + char snmpfile[] = "/etc/snmp/snmpd.conf"; +#endif + // char alertfile[] = "/tmp/alert.arping"; + // FILE *fparp; + FILE *fprt; + int fd = -1; + int skfd; + uchar *pc; + int rc = 0; + int i,j; + uchar bnetadr[4]; + uchar bgateadr[4]; + char gate_addr[128]; + char iface[16]; + char defcommunity[19] = "public"; + char buff[1024]; + char alertname[60]; + int num, nmatch; + struct ifreq ifr; + char *_ifname; + char fgetmac; + + /* Get the IP address and associated MAC address specified. */ + /* Local for ethN; Default Gateway; Alert Destination */ + + /* Get the default gateway IP */ +#if defined(SOLARIS) || defined(BSD) + char rtcmd[80]; + sprintf(rtcmd,"netstat -r -n |grep default |awk '{ print $2 }' >%s",rtfile); + system(rtcmd); + /* use rtfile output from netstat -r, see also /etc/defaultroute */ + fprt = fopen(rtfile,"r"); + if (fprt == NULL) { + fprintf(stdout,"netstat: Cannot open %s, errno = %d\n",rtfile,get_errno()); + } else { + while (fgets(buff, 1023, fprt)) { + if ((buff[0] > '0') && (buff[0] <= '9')) { /*valid*/ + atoip(bgateadr,buff); + if (fdebug) + printf("default gateway: %s, %d.%d.%d.%d %s\n",buff, + bgateadr[0], bgateadr[1], bgateadr[2], bgateadr[3],ifname); + if (!IpIsValid(rggwyip)) /* if not user-specified */ + memcpy(rggwyip,bgateadr,4); + break; + } + } + fclose(fprt); + } /*end-else good open */ +#else + /* cat /proc/net/route and save Gwy if Dest == 0 and Gateway != 0 */ + fprt = fopen(rtfile,"r"); + if (fprt == NULL) { + fprintf(stdout,"route: Cannot open %s, errno = %d\n",rtfile,get_errno()); + } else { + char rtfmt[] = "%16s %128s %128s %X %d %d %d %128s %d %d %d\n"; + int iflags, refcnt, use, metric, mss, window, irtt; + char mask_addr[128], net_addr[128]; + uint *pnet; + uint *pgate; + + pnet = (uint *)&bnetadr[0]; + pgate = (uint *)&bgateadr[0]; + while (fgets(buff, 1023, fprt)) { + num = sscanf(buff, rtfmt, + iface, net_addr, gate_addr, + &iflags, &refcnt, &use, &metric, mask_addr, + &mss, &window, &irtt); + if (num < 10 || !(iflags & RTF_UP)) + continue; + + j = 6; + for (i = 0; i < 4; i ++) { + bnetadr[i] = htoi(&net_addr[j]); + bgateadr[i] = htoi(&gate_addr[j]); + j -= 2; + } + if ((*pnet == 0) && (*pgate != 0)) { /* found default gateway */ + if (fdebug) + printf("default gateway: %s, %d.%d.%d.%d %s\n",gate_addr, + bgateadr[0], bgateadr[1], bgateadr[2], bgateadr[3],iface); + if (!IpIsValid(rggwyip)) /* if not user-specified */ + memcpy(rggwyip,bgateadr,4); + _ifname = iface; /*use this iface for gwy mac */ + if (!fsetifn) strncpy(ifname,iface,16); + break; + } + } /*end while*/ + fclose(fprt); + } /*end-else good open */ +#endif + + /* Create a channel to the NET kernel. */ + if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + perror("socket"); + return(-3); + } + + /* Find a valid local BMC MAC Address */ + if (lan_ch == gcm_ch) { + /* GCM has its own unique mac address */ + if (!MacIsValid(rgmymac)) { + if (MacIsValid(bmcmymac)) { + memcpy(rgmymac,bmcmymac,MAC_LEN); /*use existing*/ + } else { /*error*/ + printf("invalid MAC address for gcm\n"); + } + } /*else use rgmymac if specified*/ + _ifname = iface; /*use the iface from gwy (e.g. eth0) */ + fsharedMAC = 0; /*gcm has separate NIC, separate MAC*/ + + // fd = -1; + fd = skfd; // get_socket_for_af(AF_INET) below; + } else { /*else not gcm*/ + if (!fsetifn && !fethfound) { /*do not have ifname yet*/ + i = FindEthNum(bmcmymac); + if (i >= 0) sprintf(ifname,"%s%d",ifpattn,i); + } + ifr.ifr_addr.sa_family = AF_INET; + if (fdebug) printf("getipmac: ifname=%s\n",ifname); + _ifname = ifname; + strcpy(ifr.ifr_name, _ifname); + +#ifdef SIOCGIFHWADDR + /* Get the local if HWADDR (MAC Address) from OS */ + if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) { + if (fdebug) + printf("ioctl(SIOCGIFHWADDR,%s) error, errno = %d\n",_ifname,get_errno()); + } else memcpy(osmymac,get_ifreq_mac(&ifr),MAC_LEN); /*OS mac*/ +#endif + + if (memcmp(bmcmymac,osmymac,MAC_LEN) == 0) { + /* osmymac and ifname were set above by FindEthNum */ + printf("\tBMC shares IP/MAC with OS NIC %s\n",_ifname); + fsharedMAC = 1; + } /* else fsharedMAC = 0; */ + + if (fsharedMAC == 0) { /* then BMC has separate MAC */ + if (!MacIsValid(rgmymac) && MacIsValid(bmcmymac)) + memcpy(rgmymac,bmcmymac,MAC_LEN); /*use existing*/ + } else { /* else OS & BMC share a MAC */ + /* Use the local if HWADDR (MAC Address) from OS */ + if (!MacIsValid(rgmymac)) { /* if not user-specified */ + if (MacIsValid(bmcmymac)) + memcpy(rgmymac,bmcmymac,MAC_LEN); /*use existing*/ + else memcpy(rgmymac,osmymac,MAC_LEN); /*use OS mac*/ + } + } + fd = skfd; // get_socket_for_af(AF_INET) below; + } + + if (fd >= 0) { /* if valid fd, find OS IP */ + strcpy(ifr.ifr_name, _ifname); + ifr.ifr_addr.sa_family = AF_INET; + /* Get the IFADDR (IP Address) from OS */ + if (ioctl(fd, SIOCGIFADDR, &ifr) < 0) { + int err; + err = get_errno(); + /* errno 99 here means that eth0 is not enabled/up/defined. */ + if (err == 99) + printf("ioctl(SIOCGIFADDR) error, %s not enabled\n",_ifname); + else if (fdebug) + printf("ioctl(SIOCGIFADDR,%s) error, errno=%d\n",_ifname,err); + } else { /* got the local OS IP successfully */ + pc = &ifr.ifr_addr.sa_data[2]; + if (fdebug) + printf("%s addr = %d.%d.%d.%d\n",_ifname,pc[0],pc[1],pc[2],pc[3]); + memcpy(osmyip, pc, 4); + if (!IpIsValid(rgmyip) && (fsharedMAC==1)) /*not specified, shared*/ + memcpy(rgmyip, osmyip, 4); + + /* get the local OS netmask */ + strcpy(ifr.ifr_name, _ifname); + if (ioctl(fd, SIOCGIFNETMASK, &ifr) < 0) { + if (fdebug) + printf("ioctl(SIOCGIFNETMASK) error, errno=%d\n",get_errno()); + /* if leave invalid, will use default rgsubnet */ + } else { // sizeof(struct sockaddr) + pc = &ifr.ifr_netmask.sa_data[2]; + if (fdebug) + printf("subnet = %d.%d.%d.%d \n", pc[0],pc[1],pc[2],pc[3]); + memcpy(ossubnet, pc, 4); + if (!SubnetIsValid(rgsubnet) && fsharedMAC) /*not specified*/ + memcpy(rgsubnet, pc, 4); + } + +#ifdef SIOCGIFHWADDR + /* Get the localhost OS HWADDR (MAC Address) */ + if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) { + if (fdebug) + printf("ioctl(SIOCGIFHWADDR,%s) error, errno = %d\n", + _ifname,get_errno()); + } else memcpy(osmymac,get_ifreq_mac(&ifr),MAC_LEN); /*OS mac*/ +#endif + } + } + close(skfd); /* done, close the socket */ + + if (rghostname[0] == 0) { /*hostname not specified*/ + if (!fipmilan) + gethostname(rghostname,sizeof(rghostname)); + } + if (fdebug) /* show the local OS eth if and MAC */ + printf("OS %s IP=%d.%d.%d.%d %s MAC=%02x:%02x:%02x:%02x:%02x:%02x used for arp\n", + _ifname, osmyip[0],osmyip[1],osmyip[2],osmyip[3], rghostname, + osmymac[0], osmymac[1], osmymac[2], osmymac[3], + osmymac[4], osmymac[5]); + + if (!IpIsValid(rgmyip) && IpIsValid(bmcmyip)) { + /* If no user-specified IP and there is a valid IP already in the + * BMC LAN configuration, use the existing BMC LAN IP. */ + memcpy(rgmyip,bmcmyip,4); + if (fdebug) printf("Using current IP %d.%d.%d.%d\n", + bmcmyip[0], bmcmyip[1], + bmcmyip[2], bmcmyip[3]); + } + + /* Get the default gateway MAC */ + if (lan_ch == gcm_ch) { + if (SubnetIsSame(osmyip,rggwyip,ossubnet)) fgetmac = 1; + else { /* gateway is not on the same subnet as RMM/GCM */ + fgetmac = 0; /*don't try to get mac if not the same subnet*/ + if ((fset_ip & GWYIP) == 0) memset(rggwyip,0,4); + } + } else fgetmac = 1; + if (fgetmac && IpIsValid(rggwyip) && !MacIsValid(rggwymac)) + Get_Mac(rggwyip,rggwymac,NULL); /*gwy mac not specified, so get mac*/ + + /* Get the Alert Destination IP */ + /* By default, attempt to obtain this from /etc/snmp/snmpd.conf. */ + /* cat /etc/snmp/snmpd.conf | grep trapsink |tail -n1 | cut -f2 -d' ' */ + alertname[0] = 0; /* default to null string */ + fprt = fopen(snmpfile,"r"); + if (fprt == NULL) { + printf("snmp: Cannot open %s, errno = %d\n",snmpfile,get_errno()); + } else { + // char snmpfmt[] = "%20s %60s\n"; + // char *keywd, *value; + while (fgets(buff, 1023, fprt)) { + /* parse each line */ + if (buff[0] == '#') continue; /*skip comment lines*/ + /* skip leading whitespace here */ + j = strspn(&buff[0]," \t"); + if (strncmp(&buff[j],"com2sec",7) == 0) { /* found community line */ + /* usu like this: "com2sec demouser default public" */ + i = j + 7; + for (j = 0; j < 3; j++) { + num = strspn(&buff[i]," \t"); + i += num; + num = strcspn(&buff[i]," \t\r\n"); + if (j < 2) i += num; + } + buff[i+num] = 0; + if (fsetcommunity == 0) { /* if not user-specified */ + strcpy(rgcommunity,&buff[i]); + strcpy(defcommunity,&buff[i]); + } + } +#ifdef BSD + if (strncmp(&buff[j],"traphost :=",11) == 0) nmatch = 11; + else nmatch = 0; +#else + if (strncmp(&buff[j],"trapsink",8) == 0) nmatch = 8; + else if (strncmp(&buff[j],"trap2sink",9) == 0) nmatch = 9; + else nmatch = 0; +#endif + if (nmatch > 0) { /* found trapsink line match */ + if (fdebug) printf("%s: %s",snmpfile,&buff[j]); + num = strspn(&buff[j+nmatch]," \t"); + i = j + nmatch + num; + if (buff[i] == '`') continue; + num = strcspn(&buff[i]," \t\r\n"); + strncpy(alertname,&buff[i],num); /* save alert destination */ + alertname[num] = 0; + i += num; + num = strspn(&buff[i]," \t"); /*skip whitespace*/ + i += num; + num = strcspn(&buff[i]," \t\r\n"); /*span next word*/ + if (num != 0) { /* there is another word, that is community */ + if (fsetcommunity == 0) { /* if not user-specified */ + strncpy(rgcommunity,&buff[i],num); /* save community */ + rgcommunity[num] = 0; + } + } else { /*have trapsink node with no community*/ + /* use previously discovered default community from above */ + strcpy(rgcommunity,defcommunity); + } + /* dont break, keep looking, use the last one */ + } + } /*end while*/ + fclose(fprt); + if (fdebug) + printf("snmp alertname=%s community=%s\n",alertname,rgcommunity); + } /*end else snmpfile*/ + + /* Get the Alert Destination MAC from the alertname. */ + if (alertname[0] != 0) { +#ifdef TEST + char arping_cmd[128]; + char *pb, *pm, *px; + int num, i; + if (fdebug) printf("alert %s ip=%d.%d.%d.%d osip=%d.%d.%d.%d " + "mac=%02x:%02x:%02x:%02x:%02x:%02x " + "osmac=%02x:%02x:%02x:%02x:%02x:%02x\n", + alertname, + rgdestip[0], rgdestip[1], rgdestip[2], rgdestip[3], + osmyip[0], osmyip[1], osmyip[2], osmyip[3], + rgdestmac[0], rgdestmac[1], rgdestmac[2], rgdestmac[3], + rgdestmac[4], rgdestmac[5], + osmymac[0], osmymac[1], osmymac[2], osmymac[3], + osmymac[4], osmymac[5]); +#endif + if (!IpIsValid(rgdestip)) { /* if not user-specified with -A */ + if (IpIsValid(bmcdestip)) { /* use existing if valid */ + memcpy(rgdestip,bmcdestip,4); + if (MacIsValid(bmcdestmac)) + memcpy(rgdestmac,bmcdestmac,MAC_LEN); + } + else if ((strncmp(alertname,"localhost",9) == 0) ) + { /* snmpd.conf = localhost (self) is the SNMP alert destination */ + if (IpIsValid(osmyip)) + memcpy(rgdestip,osmyip,4); + if (!MacIsValid(rgdestmac)) { /* if not user-specified */ + // Get_Mac(rgdestip,rgdestmac,alertname); (wont work for local) + memcpy(rgdestmac,osmymac,MAC_LEN); + } + } /*endif local */ + } + if (!MacIsValid(rgdestmac)) /* if MAC not vaild or user-specified */ + { + /* Use arping to get MAC from alertname or IP */ + Get_Mac(rgdestip,rgdestmac,alertname); + } + } /*endif have alertname*/ + + return(rc); +} /* end Get_IPMac_Addr */ +#endif + +int ShowChanAcc(uchar bchan) +{ + LAN_RECORD LanRecord; + int ret = 0; + uchar access; + char *pstr; + uchar pb0, pb1; + + if (bchan == lan_ch) pstr = "lan"; + else if (bchan == ser_ch) pstr = "ser"; + else pstr = "?"; + ret = GetChanAcc(bchan, 0x40, &LanRecord); + if (fdebug) + printf(" GetChanAcc(%d), ret = %d, data = %02x %02x\n", + bchan,ret, LanRecord.data[0], LanRecord.data[1]); + pb0 = LanRecord.data[0]; + pb1 = LanRecord.data[1]; + if (fcanonical) + printf("Channel %d Access Mode %s%c ",bchan,pspace3,bdelim); + else + printf("Channel(%d=%s) Access Mode: %02x %02x : ",bchan,pstr,pb0,pb1); + access = pb0; + switch (access & 0x03) { + case 0: printf("Disabled, "); break; + case 1: printf("Pre-Boot, "); break; + case 2: printf("Always Avail, "); break; + case 3: printf("Shared, "); break; + } + if (access & 0x20) printf("PEF Alerts Disabled\n"); /*0*/ + else printf("PEF Alerts Enabled\n"); /*1*/ + return(ret); +} + +static int GetSessionInfo(uchar *rData, int sz) +{ + int rv, rlen; + uchar ccode; + uchar iData[5]; + + iData[0] = 0x00; /*get data for this session*/ + rlen = sz; + rv = ipmi_cmdraw(CMD_GET_SESSION_INFO,NETFN_APP, BMC_SA,PUBLIC_BUS,BMC_LUN, + iData,1,rData, &rlen, &ccode, fdebug); + if ((rv == 0) && (ccode != 0)) rv = ccode; + return(rv); +} + +static int GetPefCapabilities(uchar *bmax) +{ + int rv, rlen; + uchar ccode; + uchar rData[MAX_BUFFER_SIZE]; + + rlen = sizeof(rData); + rv = ipmi_cmdraw(0x10, NETFN_SEVT, BMC_SA,PUBLIC_BUS,BMC_LUN, + NULL,0,rData, &rlen, &ccode, fdebug); + if ((rv == 0) && (ccode != 0)) rv = ccode; + if ((rv == 0) && (bmax != NULL)) + *bmax = rData[2]; /*max num PEF table entries*/ + return(rv); +} + +int GetSerialOverLan( uchar chan, uchar bset, uchar block ) +{ + uchar requestData[24]; + uchar rData[MAX_BUFFER_SIZE]; + int rlen; + int status, i; + uchar ccode; + uchar enable_parm, auth_parm, baud_parm; + ushort getsolcmd; + uchar user; + + if (fIPMI20 && fSOL20) { + getsolcmd = GET_SOL_CONFIG2; + enable_parm = SOL_ENABLE_PARAM; + auth_parm = SOL_AUTHENTICATION_PARAM; + baud_parm = SOL_BAUD_RATE_PARAM; + } else { + getsolcmd = GET_SOL_CONFIG; + enable_parm = SOL_ENABLE_PARAM; + auth_parm = SOL_AUTHENTICATION_PARAM; + baud_parm = SOL_BAUD_RATE_PARAM; + chan = 0; /*override chan for IPMI 1.5*/ + } + if (!fcanonical) + printf("%s, GetSOL for channel %d ...\n",progname,chan); + + requestData[0] = chan; /*channel*/ + requestData[1] = enable_parm; + requestData[2] = bset; /*set*/ + requestData[3] = block; /*block*/ + rlen = sizeof(rData); + status = ipmi_cmd(getsolcmd, requestData,4, rData, &rlen,&ccode,fdebug); + if (status != 0) return(status); + if (ccode) { + if (ccode == 0xC1) { /* unsupported command */ + printf("Serial-Over-Lan not available on this platform\n"); + return(status); + } else { + printf("SOL Enable ccode = %x\n",ccode); + status = ccode; + } + } else { /*success*/ + if (fcanonical) { + printf("Channel %d SOL Enable %s",chan,pspace3); + } else { + printf("SOL Enable: "); + for (i = 1; i < rlen; i++) printf("%02x ",rData[i]); + } + if (rData[1] == 0x01) printf("%c enabled\n",bdelim); + else printf("%c disabled\n",bdelim); + } + + if (!fcanonical) + { + requestData[0] = chan; + requestData[1] = auth_parm; + requestData[2] = bset; // selector + requestData[3] = block; // block + rlen = sizeof(rData); + status = ipmi_cmd(getsolcmd,requestData,4,rData,&rlen,&ccode,fdebug); + if (status != 0) return(status); + if (ccode) { + printf("SOL Auth ccode = %x\n",ccode); + status = ccode; + } else { /*success*/ + printf("SOL Auth: "); + for (i = 1; i < rlen; i++) printf("%02x ",rData[i]); + printf(": "); + show_priv(rData[1]); /* priv level = User,Admin,... */ + printf("\n"); + } + + requestData[0] = chan; + requestData[1] = SOL_ACC_INTERVAL_PARAM; + requestData[2] = bset; + requestData[3] = block; + rlen = sizeof(rData); + status = ipmi_cmd(getsolcmd,requestData,4,rData,&rlen,&ccode,fdebug); + if (status != 0) return(status); + if (ccode) { + printf("SOL Accum Interval ccode = %x\n",ccode); + status = ccode; + } else { /*success*/ + printf("SOL Accum Interval: "); + for (i = 1; i < rlen; i++) printf("%02x ",rData[i]); + printf(": %d msec\n",(rData[1] * 5)); + } + + requestData[0] = chan; + requestData[1] = SOL_RETRY_PARAM; + requestData[2] = bset; + requestData[3] = block; + rlen = sizeof(rData); + status = ipmi_cmd(getsolcmd,requestData,4,rData,&rlen,&ccode,fdebug); + if (status != 0) return(status); + if (ccode) { + printf("SOL Retry ccode = %x\n",ccode); + status = ccode; + } else { /*success*/ + printf("SOL Retry Interval: "); + for (i = 1; i < rlen; i++) printf("%02x ",rData[i]); + printf(": %d msec\n",(rData[2] * 10)); + } + } + + if (!fRomley) + { + requestData[0] = chan; + requestData[1] = baud_parm; + requestData[2] = bset; + requestData[3] = block; + rlen = sizeof(rData); + status = ipmi_cmd(getsolcmd,requestData,4,rData, &rlen,&ccode,fdebug); + if (status != 0) return(status); + if (ccode) { + printf("SOL nvol Baud ccode = %x\n",ccode); + status = ccode; + } else { /*success*/ + uchar b; + if (fcanonical) { + printf("Channel %d SOL Baud Rate%s",chan,pspace3); + } else { + printf("SOL nvol Baud Rate: "); + for (i = 1; i < rlen; i++) printf("%02x ",rData[i]); + } + /* if not user-specified and previously enabled, use existing */ + b = (rData[1] & 0x0f); + if ((fnewbaud == 0) && BaudValid(b)) { + sol_baud = b; + sol_bvalid = 1; + } + printf("%c %s\n",bdelim,Baud2Str(b)); + } + + if (!fcanonical) + { + requestData[0] = chan; + requestData[1] = SOL_VOL_BAUD_RATE_PARAM; /*0x06*/ + requestData[2] = bset; + requestData[3] = block; + rlen = sizeof(rData); + status = ipmi_cmd(getsolcmd,requestData,4,rData,&rlen,&ccode,fdebug); + if (status != 0) return(status); + if (ccode) { + printf("SOL vol Baud ccode = %x\n",ccode); + status = ccode; + } else { /*success*/ + printf("SOL vol Baud Rate: "); + for (i = 1; i < rlen; i++) printf("%02x ",rData[i]); + printf("%c %s\n",bdelim,Baud2Str(rData[1])); + } + } + } + if (fIPMI20) { + if (vend_id != VENDOR_IBM) { + /* IBM 0x00DC returns invalid cmd for SOL Payload commands. */ + if (!fcanonical) { + requestData[0] = chan; + rlen = sizeof(rData); + status = ipmi_cmdraw(GET_PAYLOAD_SUPPORT, NETFN_APP, + BMC_SA,PUBLIC_BUS,BMC_LUN, + requestData,1,rData, &rlen, &ccode, fdebug); + if ((status != 0) || (ccode != 0)) { + printf("SOL Payload Support error %d, ccode = %x\n",status,ccode); + if (status == 0) status = ccode; + } else { /*success*/ + printf("SOL Payload Support(%d): ",chan); + for (i = 0; i < rlen; i++) printf("%02x ",rData[i]); + printf("\n"); + } + } /*endif not canonical*/ + /* get Payload Access for 4 users, not just lan_user */ + for (user = 1; user <= show_users; user++) + { + /* mBMC doesn't support more than 1 user */ + if (fmBMC && (user > 1)) break; + /* IPMI 2.0 has >= 4 users */ + requestData[0] = chan; + requestData[1] = user; + rlen = sizeof(rData); + status = ipmi_cmdraw(GET_PAYLOAD_ACCESS, NETFN_APP, + BMC_SA,PUBLIC_BUS,BMC_LUN, + requestData,2,rData, &rlen, &ccode, fdebug); + if ((status != 0) || (ccode != 0)) { + printf("SOL Payload Access(%d,%d) error %d, ccode = %x\n", + chan,user,status,ccode); + if (status == 0) status = ccode; + } else { /*success*/ + if (fcanonical) { + printf("Channel %d SOL Payload Access(user%d)%s",chan,user, + pspace1); + } else { + printf("SOL Payload Access(%d,%d): ",chan,user); + for (i = 0; i < rlen; i++) printf("%02x ",rData[i]); + } + if ((rData[0] & 0x02) != 0) printf("%c enabled\n",bdelim); + else printf("%c disabled\n",bdelim); + } + } /*end user loop*/ + } /*endif not IBM*/ + } + + return(status); +} /*end GetSerialOverLan */ + +/* +ECHO SOL Config Enable +CMDTOOL 20 30 21 %1 01 01 + +ECHO SOL Authentication (Administrator) +CMDTOOL 20 30 21 %1 02 04 + +ECHO SOL Accumlate Interval and threshold +CMDTOOL 20 30 21 %1 03 06 14 + +ECHO SOL Retry Interval and threshold +CMDTOOL 20 30 21 %1 04 06 14 + +ECHO SOL non-volatile baud rate +CMDTOOL 20 30 21 %1 05 07 + +ECHO SOL volatile baud rate +CMDTOOL 20 30 21 %1 06 07 + +ECHO Set user Payload Access for user 1 +CMDTOOL 20 18 4c %1 01 02 00 00 00 + */ +int SetupSerialOverLan( int benable ) +{ + uchar requestData[24]; + uchar responseData[MAX_BUFFER_SIZE]; + int responseLength = MAX_BUFFER_SIZE; + int status; + uchar completionCode; + uchar enable_parm, auth_parm, baud_parm; + ushort setsolcmd; + ushort getsolcmd; + uchar bchan, b; + + if (fIPMI20 && fSOL20) { + setsolcmd = SET_SOL_CONFIG2; + getsolcmd = GET_SOL_CONFIG2; + enable_parm = SOL_ENABLE_PARAM; + auth_parm = SOL_AUTHENTICATION_PARAM; + baud_parm = SOL_BAUD_RATE_PARAM; + bchan = lan_ch; + } else { + setsolcmd = SET_SOL_CONFIG; + getsolcmd = GET_SOL_CONFIG; + enable_parm = SOL_ENABLE_PARAM; + auth_parm = SOL_AUTHENTICATION_PARAM; + baud_parm = SOL_BAUD_RATE_PARAM; + bchan = 0x00; /*override chan for IPMI 1.5*/ + } + memset(requestData, 0, sizeof(requestData)); /* zero-fill */ + requestData[0] = bchan; + requestData[1] = enable_parm; + if (benable == 0) + requestData[2] = SOL_DISABLE_FLAG; + else + requestData[2] = SOL_ENABLE_FLAG; + responseLength = MAX_BUFFER_SIZE; + status = ipmi_cmd(setsolcmd, requestData,3,responseData, + &responseLength, &completionCode, fdebug); + if (status == ACCESS_OK) { + switch( completionCode ) { + case 0x00: /* success */ + break; + case 0xC1: /* unsupported command */ + SELprintf("SetupSerialOverLan: SOL not available on this platform\n"); + return 0; + default: /* other error */ + SELprintf("SetupSerialOverLan: SOL_ENABLE_PARAM ccode=%x\n", + completionCode); + return -1; + break; + } + } else { + SELprintf( "SET_SOL_CONFIG, enable SOL failed\n" ); + return -1; + } + if (benable == 0) return 0; + + requestData[0] = bchan; /* channel */ + requestData[1] = auth_parm; + requestData[2] = 0x00; /* set selector */ + requestData[3] = 0x00; /* block selector */ + responseLength = MAX_BUFFER_SIZE; + status = ipmi_cmd(getsolcmd, requestData,4,responseData, + &responseLength, &completionCode, fdebug); + if (status == ACCESS_OK) { + if( completionCode ) { + SELprintf("SetupSerialOverLan: GET_SOL_AUTHENTICATION_PARAM code=%x\n", + completionCode); + + return -1; + } + } else { + SELprintf( "SOL_CONFIG, get SOL authentication failed\n" ); + return -1; + } + + if ((vend_id == VENDOR_SUPERMICROX) || + (vend_id == VENDOR_SUPERMICRO)) b = SOL_PRIVILEGE_LEVEL_OPERATOR; + else b = SOL_PRIVILEGE_LEVEL_USER; + requestData[0] = bchan; + requestData[1] = auth_parm; + requestData[2] = b | ( responseData[1] & 0x80 ); /* priv | enable */ + responseLength = MAX_BUFFER_SIZE; + status = ipmi_cmd(setsolcmd, requestData,3,responseData, + &responseLength, &completionCode, fdebug); + if (status == ACCESS_OK) { + if( completionCode ) { + SELprintf("SET_SOL_AUTHENTICATION_PARAM code=%x\n", + completionCode); + + return -1; + } + } else { + SELprintf( "SET_SOL_CONFIG, set SOL authentication failed\n" ); + return -1; + } + + requestData[0] = bchan; + requestData[1] = SOL_ACC_INTERVAL_PARAM; + requestData[2] = sol_accum[0]; //0x04; + requestData[3] = sol_accum[1]; //0x32; + responseLength = MAX_BUFFER_SIZE; + if (fdebug) SELprintf("Setting SOL AccumInterval\n"); + status = ipmi_cmd(setsolcmd, requestData,4,responseData, + &responseLength, &completionCode, fdebug); + if (status != ACCESS_OK || completionCode) { + SELprintf("SET SOL AccumInterval ret=%d ccode=%x\n", + status,completionCode); + return -1; + } + + /* Some BMCs return sporadic errors for SOL params (e.g. Kontron)*/ + // if (vend_id == VENDOR_KONTRON) ; + // else + { + requestData[0] = bchan; + requestData[1] = SOL_RETRY_PARAM; + requestData[2] = sol_retry[0]; //0x06; + requestData[3] = sol_retry[1]; //0x14; + responseLength = MAX_BUFFER_SIZE; + if (fdebug) SELprintf("Setting SOL RetryInterval\n"); + status = ipmi_cmd(setsolcmd, requestData,4,responseData, + &responseLength, &completionCode, fdebug); + if (status != ACCESS_OK || completionCode) { + SELprintf("SET SOL RetryInterval ret=%d ccode=%x\n", + status,completionCode); + return -1; + } + } + + if (fRomley) ; /* skip SOL BAUD */ + else { /* else SOL BAUD is used, so set it. */ + if (fnewbaud == 0) { /* no user-specified SOL baud */ + /* if sol_bvalid, sol_baud was set to existing value above */ + if (!sol_bvalid) { + status = GetSerEntry(7, (LAN_RECORD *)&responseData); + if (status == 0) { /* use Serial baud for SOL */ + sol_baud = responseData[1]; + if (fdebug) SELprintf("Serial Baud is %s\n",Baud2Str(sol_baud)); + } + } + } + requestData[0] = bchan; + requestData[1] = baud_parm; + requestData[2] = sol_baud; + responseLength = MAX_BUFFER_SIZE; + if (fdebug) SELprintf("Setting SOL BAUD to %s\n",Baud2Str(sol_baud)); + status = ipmi_cmd(setsolcmd, requestData,3,responseData, + &responseLength, &completionCode, fdebug); + if (status != ACCESS_OK || completionCode) { + SELprintf("SET SOL BAUD ret=%d ccode=%x\n", status,completionCode); + return -1; + } + + requestData[0] = bchan; + requestData[1] = SOL_VOL_BAUD_RATE_PARAM; + requestData[2] = sol_baud; + responseLength = MAX_BUFFER_SIZE; + if (fdebug) + printf("Setting SOL vol BAUD to %s\n",Baud2Str(sol_baud)); + status = ipmi_cmd(setsolcmd, requestData,3,responseData, + &responseLength, &completionCode, fdebug); + if (status != ACCESS_OK || completionCode) { + printf("SET SOL vol BAUD ret=%d ccode=%x\n",status,completionCode); + return -1; + } + } + + if (fIPMI20 && fSOL20) { + if (vend_id == VENDOR_KONTRON && lan_user == 1) { + if (fdebug) SELprintf("Skipping SOL Payload Access for user %d\n", + lan_user); + } else if (vend_id == VENDOR_IBM) { /*non-conformance*/ + if (fdebug) SELprintf("Skipping SOL Payload Access for user %d\n", + lan_user); + } else { + if (fdebug) SELprintf("Setting SOL Payload Access for user %d\n", + lan_user); + requestData[0] = bchan; + requestData[1] = lan_user; /*enable this user*/ + requestData[2] = 0x02; /*enable std 2.0 SOL*/ + requestData[3] = 0; + requestData[4] = 0; + requestData[5] = 0; + responseLength = MAX_BUFFER_SIZE; + status = ipmi_cmdraw(SET_PAYLOAD_ACCESS, NETFN_APP, + BMC_SA,PUBLIC_BUS,BMC_LUN, + requestData,6,responseData, &responseLength, + &completionCode, fdebug); + if (status != ACCESS_OK || completionCode) { + SELprintf("SET SOL Payload Access ret=%d ccode=%x\n", + status,completionCode); + return -1; + } + } + } + return 0; +} /*end SetupSerialOverLan */ + +static char *PefDesc(int idx, uchar stype) +{ + char *pdesc, *p; + static char mystr[60]; + int mylen = sizeof(mystr); + pdesc = &mystr[0]; + if (pefdesc != NULL) strcpy(pdesc,pefdesc[idx]); /* if Intel, pre-defined */ + else strcpy(pdesc,"reserved"); /* else set default to detect */ + if ((stype != 0) && (strcmp(pdesc,"reserved") == 0)) { + /* Dynamically set the pef desc string from the sensor type */ + switch(stype) { + case 0x01: strcpy(pdesc,"Temperature"); break; + case 0x02: strcpy(pdesc,"Voltage"); break; + case 0x04: strcpy(pdesc,"Fan"); break; + case 0x05: strcpy(pdesc,"Chassis"); break; + case 0x07: strcpy(pdesc,"BIOS"); break; + case 0x08: strcpy(pdesc,"Power Supply"); break; + case 0x09: strcpy(pdesc,"Power Unit"); break; + case 0x0c: strcpy(pdesc,"Memory"); break; + case 0x0f: strcpy(pdesc,"Boot"); break; + case 0x12: strcpy(pdesc,"System Restart"); break; + case 0x13: strcpy(pdesc,"NMI"); break; + case 0x23: strcpy(pdesc,"Watchdog"); break; + case 0x20: strcpy(pdesc,"OS Critical Stop"); break; + default: +#ifdef METACOMMAND + p = get_sensor_type_desc(stype); + if (p != NULL) { + strncpy(pdesc,p,mylen); + mystr[mylen-1] = 0; /*stringify*/ + } +#else + sprintf(pdesc,"Other[%02x]",stype); +#endif + break; + } + if (pef_array[idx-1][4] == PEF_SEV_OK) strcat(pdesc," OK"); + } + return(pdesc); +} + + +#ifdef METACOMMAND +int i_lan(int argc, char **argv) +#else +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#endif +{ + int ret; + PEF_RECORD PefRecord; + LAN_RECORD LanRecord; + int i, idx, j; + int c; + char *pstr; + uchar bset; + int ndest = 4; + int idest; + int nciphers = 16; + char mystr[80]; + char fpefok = 1; + uchar * pc; int sz; + + // progname = argv[0]; + printf("%s ver %s \n",progname,progver); + j = 0; freadonly = FLAG_INIT; + idx = argc; /*getopt loop counter*/ + /* available opt chars: y O Q + = ~ _ */ + while ((c = getopt(argc, argv,"a:b:cdef:gh:i:j:klm:n:op:q:rstu:v:w:xy:z#::A:B:C:DEF:G:H:I:J:K:L:M:N:P:Q:R:S:T:U:V:X:YZ:?")) != EOF) { + switch(c) { + case 'a': /* alert dest number (usu 1 thru 4) */ + alertnum = atob(optarg); + if (alertnum > alertmax) alertnum = 1; + j++; + break; + case 'b': bAuth = htoi(optarg); j++; break; /*undocumented*/ + case 'c': fcanonical = 1; bdelim = BDELIM; break; + case 'd': fenable = 0; fdisable = 1; freadonly = 0; break; + case 'e': fenable = 1; fdisable = 0; freadonly = 0; break; + case 'f': i = atoi(optarg); /*set arp_ctl*/ + if (i < 0 || i > 3) printf("Invalid ARP control %d\n",i); + else { + arp_ctl = i; + fsetarp = 1; + j++; + } + break; + case 'l': fpefenable = 0; fenable = 2; + fdisable = 0; freadonly = 0; break; + case 'h': /* VLAN ID */ + i = atoi(optarg); + if (i > 4095) vlan_enable = 0; + else { + vlan_enable = 1; + vlan_id = (ushort)i; + } + j++; + break; + case 'y': /* OEM LAN Failover enable/disable */ + i = atoi(optarg); + if (i < 0) printf("Failover(-y) parameter is negative\n"); + else failover_enable = i; + j++; + break; + case 'Q': /* VLAN Priority */ + i = atoi(optarg); + if (i > 7 || i < 0) vlan_enable = 0; + else { + vlan_enable = 1; + vlan_prio = (uchar)i; + } + j++; + break; + case 'i': /* eth interface (ifname) */ + fsetifn = 1; + i = sizeof(ifname); + if (strlen(optarg) > (uint)i) optarg[i] = 0; + strcpy(ifname,optarg); + if (fdebug) printf("ifname = %s\n",ifname); + j++; + break; + case 'j': fCustomPEF = 1; /*custom 10 PEF bytes */ + fpefenable = 1; /* PEF is implied here */ + freadonly = 0; + memset(custPEF,0,sizeof(custPEF)); + custPEF[0] = htoi(&optarg[0]); /*action */ + custPEF[1] = htoi(&optarg[2]); /*policy */ + custPEF[2] = htoi(&optarg[4]); /*severity*/ + custPEF[3] = htoi(&optarg[6]); /*genid1 */ + custPEF[4] = htoi(&optarg[8]); /*genid2 */ + custPEF[5] = htoi(&optarg[10]); /*sensor_type*/ + custPEF[6] = htoi(&optarg[12]); /*sensor_num */ + custPEF[7] = htoi(&optarg[14]); /*evt_trigger*/ + custPEF[8] = htoi(&optarg[16]); /*data1offset*/ + custPEF[9] = htoi(&optarg[18]); /*data1mask */ + if (optarg[20] != 0) { + /* optionally get 8 extra PEF entry bytes */ + custPEF[10] = htoi(&optarg[20]); /*data1cmp1 */ + custPEF[11] = htoi(&optarg[22]); /*data1cmp2 */ + custPEF[12] = htoi(&optarg[24]); /*data2mask */ + custPEF[13] = htoi(&optarg[26]); /*data2cmp1 */ + custPEF[14] = htoi(&optarg[28]); /*data2cmp2 */ + custPEF[15] = htoi(&optarg[30]); /*data3mask */ + custPEF[16] = htoi(&optarg[32]); /*data3cmp1 */ + custPEF[17] = htoi(&optarg[34]); /*data3cmp2 */ + } + j++; + break; + case 'k': fSetPEFOks = 1; j++; break; /*configure PEF OK rules */ + case 'm': set_max_kcs_loops(atoi(optarg)); break; + case 'n': /* number/index in PEF table to insert new entry */ + fpefenable = 1; + pefnum = atob(optarg); + if (pefnum >= MAXPEF) { + pefnum = MAXPEF - 1; + fAdjustPefNum = 1; + } else fUserPefNum = 1; + j++; + break; + case 'o': fdisableSOL = 1; /*disable SOL only*/ + fpefenable = 0; /*no change to PEF*/ + freadonly = 0; + break; + case 'r': freadonly = 1; fenable = 0; break; + case 's': fgetser = 1; break; + case 't': ftestonly = 1; freadonly = 1; break; + case 'v': /* user access privilege level */ + i = atoi(optarg); + if (valid_priv(i)) lan_access = i & 0x0f; + else printf("Invalid privilege -v %d, using Admin\n",i); + j++; + break; + case 'w': i = atoi(optarg); /*set grat arp interval, in #sec*/ + if (i >= 0 && i < 256) arp_interval = i * 2; + else printf("Invalid arp interval -w %d, skipping\n",i); + break; + case 'x': fdebug = 1; break; + case 'z': flanstats = 1; break; + case 'D': lan_dhcp = 1; j++; break; + case 'I': /* My BMC IP Address */ + fset_ip |= MYIP; + atoip(rgmyip,optarg); + j++; + break; + case 'M': /* My BMC MAC Address */ + atomac(rgmymac,optarg); + if (!MacIsValid(rgmymac)) printf("Invalid MAC for -M\n"); + j++; + break; + case 'S': /* Subnet IP Address */ + atoip(rgsubnet,optarg); + j++; + break; + case 'G': /* Gateway IP Address */ + fset_ip |= GWYIP; + atoip(rggwyip,optarg); + j++; + break; + case 'g': /* Secondary Gateway IP Address */ + fset_ip |= GWYIP; + atoip(rggwy2ip,optarg); + j++; + break; + case 'H': /* Gateway MAC Address */ + atomac(rggwymac,optarg); + if (!MacIsValid(rggwymac)) printf("Invalid MAC for -H\n"); + j++; + break; + case 'B': /* SOL Baud rate */ + fnewbaud = 1; + sol_baud = Str2Baud(optarg); + j++; + break; + case 'A': /* Alert Dest IP Address */ + fset_ip |= DESTIP; + /* allow name or ip here via Get_Mac() ? */ + atoip(rgdestip,optarg); + fpefenable = 1; /* PEF is implied here */ + j++; + break; + case 'X': /* Alert Dest MAC Address */ + atomac(rgdestmac,optarg); + if (!MacIsValid(rgdestmac)) printf("Invalid MAC for -X\n"); + fpefenable = 1; /* PEF is implied here */ + j++; + break; + case 'K': /* Kontron IPMI hostname */ + i = sizeof(rghostname); /*usu 18*/ + if (strlen(optarg) > (uint)i) optarg[i] = 0; + strcpy(rghostname,optarg); + j++; + break; + case 'C': /* Community String */ + fsetcommunity = 1; + i = sizeof(rgcommunity); /*usu 18*/ + if (strlen(optarg) > (uint)i) optarg[i] = 0; + strcpy(rgcommunity,optarg); + fpefenable = 1; /* PEF is implied here */ + j++; + break; + case 'u': /* username to set */ + myuser = strdup_(optarg); /*remote username */ + j++; + break; + case 'p': /* password to set */ + fpassword = 1; + if (strlen(optarg) > PSW_MAX) optarg[PSW_MAX] = 0; + strcpy(passwordData,optarg); + if (fdebug) printf("Password = %s\n",passwordData); + /* Hide password from 'ps' */ + memset(optarg, ' ', strlen(optarg)); + j++; + break; + case 'q': + case '#': + usernum = atob(optarg); + if (usernum > 15) usernum = 0; /*MAX_IPMI_USERS = 15*/ + j++; + break; + case 'L': + if (strcmp(optarg,"list") == 0) fshowchan = 1; + lan_ch_parm = atob(optarg); + if (lan_ch_parm > MAXCHAN) lan_ch_parm = PARM_INIT; /*invalid*/ + break; + case 'V': /* priv level */ + fprivset = 1; + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + break; + default: + printf("Usage: %s [-abcdefghijklmnopq#rstuvwxyzBDQK]\n",progname); + printf(" \t [-a alertnum -i eth1 -n pefnum ]\n"); + printf(" \t [-I ipadr -M macadr -S subnet ]\n"); + printf(" \t [-G gwyip -H gwymac -L lan_channel_num]\n"); + printf(" \t [-A alertip -X alertmac -C community ]\n"); + printf(" \t [-g 2nd_gwyip -v priv -B sol_baud ]\n"); + printf(" \t [-j 10_bytes_custom_pef -b authmask ]\n"); + printf("where -c shows Canonical, simpler output format\n"); + printf(" -d Disables BMC LAN & PEF\n"); + printf(" -e Enables BMC LAN & PEF\n"); + printf(" -f set ARP Control to 1=grat, 2=resp, 3=both\n"); + printf(" -g secondary Gateway IP (-G=primary_gwy_ip)\n"); + printf(" -h VLAN ID (>=4096 to disable)\n"); + printf(" -j specify custom PEF rule (10 or 18 hex bytes)\n"); + printf(" -k add PEF oK rules, if PEF enable\n"); + printf(" -l Enables BMC LAN only, not PEF\n"); + printf(" -o disable Only SOL\n"); + printf(" -p password to set \n"); + printf(" -q/-# User number of LAN username_to_set\n"); + printf(" -r Read-only BMC LAN & PEF settings\n"); + printf(" -s Show some Serial settings also \n"); + printf(" -t Test if BMC LAN is already configured\n"); + printf(" -u username to set \n"); + printf(" -v access priVilege: 4=Admin,3=Operator,2=User\n"); + printf(" -w set Grat ARP Interval to specified # seconds\n"); + printf(" -x Show eXtra debug messages\n"); + printf(" -y OEM LAN Failover (1=enable,0=disable if Intel)\n"); + printf(" -z Show IPMI LAN statistics\n"); + printf(" -B Baud for SerialOverLan (19.2K,115.2K,...)\n"); + printf(" -D Use DHCP instead of static IP (-I for server)\n"); + printf(" -K (Kontron) IPMI hostname to set\n"); + printf(" -Q VLAN Priority (default =0)\n"); + print_lan_opt_usage(); + ret = ERR_USAGE; + goto do_exit; + } /*end switch*/ + nopts++; + } /*end while*/ + + if ((freadonly == FLAG_INIT) && (j > 0)) { + /* got some options implying set, but no -e -l -d option specified. */ + foptmsg = 1; /*show warning message later*/ + freadonly = 1; /*assume read only*/ + } + fipmilan = is_remote(); + if (fipmilan && !fprivset) + parse_lan_options('V',"4",0); /*even if freadonly request admin*/ + if ((fsetarp == 0) && ostype == OS_WINDOWS) + arp_ctl = 0x03; /*grat arp & arp resp enabled */ + + ret = GetDeviceID( &LanRecord); + if (ret != 0) { + goto do_exit; + } else { /* success */ + uchar ipmi_maj, ipmi_min; + ipmi_maj = LanRecord.data[4] & 0x0f; + ipmi_min = LanRecord.data[4] >> 4; + show_devid( LanRecord.data[2], LanRecord.data[3], ipmi_maj, ipmi_min); + if (ipmi_maj == 0) fIPMI10 = 1; + else if (ipmi_maj == 1 && ipmi_min < 5) fIPMI10 = 1; + else fIPMI10 = 0; /* >= IPMI 1.5 is ok */ + if (ipmi_maj >= 2) fIPMI20 = 1; + if (fIPMI20) show_users = 5; + else show_users = 3; + if (fIPMI10) { + printf("This IPMI v%d.%d system does not support PEF records.\n", + ipmi_maj,ipmi_min); + /* Wont handle PEF, but continue and look for BMC LAN anyway */ + // fIPMI10 = 1; + // ipmi_close_(); + // exit(1); + } + prod_id = LanRecord.data[9] + (LanRecord.data[10] << 8); + vend_id = LanRecord.data[6] + (LanRecord.data[7] << 8) + + (LanRecord.data[8] << 16); + /* check Device ID response for Manufacturer ID = 0x0322 (NSC) */ + if (vend_id == VENDOR_NSC) { /* NSC = 0x000322 */ + fmBMC = 1; /*NSC miniBMC*/ + if (pefnum == 12) pefnum = 10; /* change CritStop pefnum to 0x0a */ + pefdesc = &pefdesc2[0]; /*mini-BMC PEF*/ + pefmax = 30; + fsharedMAC = 1; /* shared MAC with OS */ + } else if (vend_id == VENDOR_LMC) { /* LMC (on SuperMicro) = 0x000878 */ + pefdesc = NULL; /* unknown, see PefDesc() */ + if (pefnum == 12) pefnum = 15; /* change CritStop pefnum */ + pefmax = 16; + fsharedMAC = 0; /* not-shared BMC LAN port */ + } else if (vend_id == VENDOR_INTEL) { /* Intel = 0x000157 */ + pefdesc = &pefdesc1[0]; /*default Intel PEF*/ + pefmax = 20; /*default Intel PEF*/ + switch(prod_id) { + case 0x4311: /* Intel NSI2U w SE7520JR23 */ + fmBMC = 1; /* Intel miniBMC*/ + if (pefnum == 12) pefnum = 14; /* change CritStop pefnum */ + pefdesc = &pefdesc2[0]; /*mini-BMC PEF*/ + pefmax = 30; + fsharedMAC = 1; /* shared-MAC BMC LAN port, same MAC */ + break; + case 0x0022: /* Intel TIGI2U w SE7520JR23 +IMM*/ + fsharedMAC = 1; /* shared-MAC BMC LAN port, same MAC */ + gcm_ch = 3; /* IMM GCM port, dedicated MAC */ + show_users = 4; + break; + case 0x000C: /*TSRLT2*/ + case 0x001B: /*TIGPR2U*/ + /* fmBMC=0; Intel Sahalee BMC*/ + fsharedMAC = 1; /* shared-MAC BMC LAN port, same MAC */ + break; + case 0x0026: /*S5000 Bridgeport*/ + case 0x0028: /*S5000PAL Alcolu*/ + case 0x0029: /*S5000PSL StarLake*/ + case 0x0811: /*S5000PHB TIGW1U */ + /* fmBMC=0; Intel Sahalee ESB2 BMC*/ + fsharedMAC = 0; /* not-shared BMC LAN port, separate MAC */ + gcm_ch = 3; + parm7 = &iparm7[0]; /*TTL=30*/ + break; + case 0x003E: /*NSN2U or CG2100 Urbanna*/ + fiBMC = 1; /* Intel iBMC */ + fsharedMAC = 0; /* not-shared BMC LAN port, separate MAC */ + // gcm_ch = 3; + parm7 = &iparm7[0]; /*TTL=30*/ + if (fsetarp == 0) + arp_ctl = 0x02; /*grat arp disabled, arp resp enabled */ + arp_interval = 0x00; /*0 sec, since grat arp disabled */ + sol_accum[0] = 0x0c; /*Intel defaults*/ + sol_accum[1] = 0x60; /*Intel defaults*/ + sol_retry[0] = 0x07; /*Intel defaults*/ + sol_retry[1] = 0x32; /*Intel defaults*/ + set_max_kcs_loops(URNLOOPS); /*longer for SetLan cmds (default 300)*/ + break; + case 0x0107: /* Intel Caneland*/ + fsharedMAC = 0; /* not-shared BMC LAN port, separate MAC */ + gcm_ch = 3; + break; + case 0x0100: /*Tiger2 ia64*/ + /* for ia64 set chan_pefon, chan_pefoff accordingly*/ + chan_pefon = CHAN_ACC_PEFON64; + chan_pefoff = CHAN_ACC_PEFOFF64; + /* fall through */ + default: /* else other Intel */ + /* fmBMC = 0; * Intel Sahalee BMC*/ + if (fIPMI20) fsharedMAC = 0; /* recent, not-shared BMC MAC */ + else fsharedMAC = 1; /* usu IPMI 1.x has shared BMC MAC */ + break; + } /*end switch*/ + if (is_romley(vend_id,prod_id)) { + fRomley = 1; + fiBMC = 1; /* Intel iBMC */ + fsharedMAC = 0; /* not-shared BMC LAN port, separate MAC */ + set_max_kcs_loops(URNLOOPS); /*longer for SetLan (default 300)*/ + fipv6 = 1; + if (fsetarp == 0) arp_ctl = 0x03; /*default to both for Romley*/ + } + } else { /* else other vendors */ + if (fIPMI20) fsharedMAC = 0; /* recent, not-shared BMC MAC */ + else fsharedMAC = 1; /* usu IPMI 1.x has shared BMC MAC */ + pefdesc = NULL; /* unknown, see PefDesc() */ + if (pefnum == 12) pefnum = 15; /* change CritStop pefnum to 15? */ + pefmax = 20; + if (!fUserPefNum) fAdjustPefNum = 1; + } + if (fmBMC) show_users = 1; /* mBMC doesn't support more than 1 user */ + } + + if (fshowchan) { + ret = show_channels(); + exit(ret); + } + + ret = GetPefCapabilities(&bset); + if ((ret == 0) && (bset <= MAXPEF)) pefmax = bset; + + /* Get the BMC LAN channel & match it to an OS eth if. */ + i = GetBmcEthDevice(lan_ch_parm); + if (i == -2) { /* no lan channels found (see lan_ch) */ + if (lan_ch_parm == PARM_INIT) + printf("This system does not support IPMI LAN channels.\n"); + else /*specified a LAN channel*/ + printf("BMC channel %d does not support IPMI LAN.\n",lan_ch_parm); + ret = LAN_ERR_NOTSUPPORT; + goto do_exit; + } else if (i < 0) { /* mac not found, use platform defaults */ + i = 0; /* default to eth0, lan_ch set already. */ + if (vend_id == VENDOR_INTEL) { + if ((prod_id == 0x001B) || (prod_id == 0x000c)) { + /* Intel TIGPR2U or TSRLT2 defaults are special */ + if (lan_ch_parm == 6) + { i = 0; lan_ch = 6; } + else { i = 1; lan_ch = 7; } + ser_ch = 1; + } + } + } + if ((i == gcm_ch) && (gcm_ch != PARM_INIT) && (lan_ch_parm == PARM_INIT)) { + /* Has a GCM, defaulted to it, and user didn't specify -L */ + /* Need this to avoid picking channel 3, the IMM/RMM GCM channel. */ + lan_ch = 1; /*default BMC LAN channel*/ + // i = 0; /*default eth0 (was eth1) */ + } + if (fsetifn == 0) { /*not user specified, use the detected one*/ + // if (lan_ch == gcm_ch) strcpy(ifname,"gcm"); + sprintf(ifname,"%s%d",ifpattn,i); /*eth%d*/ + } + if (fdebug) printf("lan_ch = %d, ifname = %s\n",lan_ch,ifname); + + /* set the lan_user appropriately */ + if (myuser == NULL) { /* if no -u param */ + if (ipmi_reserved_user(vend_id, 1)) lan_user = 2; + else lan_user = 1; /*use default null user */ + } else if (usernum != 0) lan_user = usernum; /*use -q specified usernum*/ + /* else use default lan_user (=2) if -u and not -q */ + + if (ftestonly) { /*test only if BMC LAN is configured or not */ + /* TODO: test gcm also, if present */ + ret = GetLanEntry(4, 0, &LanRecord); /*ip addr src*/ + if (ret == 0) { + if ((LanRecord.data[0] == SRC_BIOS) || + (LanRecord.data[0] == SRC_DHCP)) ret = 0; /* DHCP, so ok */ + else { /*static IP*/ + ret = GetLanEntry(3, 0, &LanRecord); /* ip address */ + if (ret == 0) { + if (!IpIsValid(LanRecord.data)) { + printf("invalid BMC IP address\n"); + ret = 1; /* invalid ip */ + } else ret = GetLanEntry(12, 0, &LanRecord); /*gateway ip*/ + if (ret == 0) { + if (!IpIsValid(LanRecord.data)) { + printf("invalid gateway ip\n"); + ret = 2; /*invalid gwy ip*/ + } else ret = GetLanEntry(13, 0, &LanRecord); + if (ret == 0) { + if (!MacIsValid(&LanRecord.data[0])) { + printf("invalid gateway mac\n"); + ret = 3; /*invalid gwy mac */ + } + } + } + } + } + } /*endif GetLanEntry ok*/ + if (ret == 0) printf("BMC LAN already configured\n"); + else printf("BMC LAN not configured\n"); + goto do_exit; + } /*endif ftestonly*/ + + memset(SessInfo,0,sizeof(SessInfo)); + ret = GetSessionInfo(SessInfo,sizeof(SessInfo)); + // rlen = sizeof(SessInfo)); ret = get_session_info(0,0,SessInfo,&rlen); + if (fdebug) printf("GetSessionInfo ret=%d, data: %02x %02x %02x %02x \n", + ret,SessInfo[0],SessInfo[1],SessInfo[2],SessInfo[3]); + if (!freadonly && fipmilan) { /* setting LAN params, and using IPMI LAN */ + if (SessInfo[2] > 1) { /* another session is active also */ + printf("Another session is also active, cannot change IPMI LAN settings now.\n"); + ret = ERR_NOT_ALLOWED; + goto do_exit; + } + } + + if (!fIPMI10) { + if (fcanonical) + { /* canonical/simple output */ + ret = GetPefEntry(0x01, 0,(PEF_RECORD *)&LanRecord); + if (ret != 0) ndest = 0; + else { /*success*/ + j = LanRecord.data[0]; + mystr[0] = 0; + if (j == 0) strcat(mystr,"none "); + else { + if (j & 0x01) strcat(mystr,"PEFenable "); + if (j & 0x02) strcat(mystr,"DoEventMsgs "); + if (j & 0x04) strcat(mystr,"Delay "); + if (j & 0x08) strcat(mystr,"AlertDelay "); + } + printf("PEF Control %s%c %s\n",pspace4,bdelim,mystr); + } + } else { /* normal/full output */ + ret = GetPefEntry(0x01, 0,(PEF_RECORD *)&LanRecord); + if (ret == 0 && (LanRecord.data[0] != 0)) { + fpefok = 1; + bmcpefctl = LanRecord.data[0]; + } else { /* skip PEF rules/params if disabled */ + printf("PEF Control %s%c %s\n",pspace4,bdelim,"none "); + ndest = 0; + fpefok = 0; + } + + if (fpefok) { + printf("%s, GetPefEntry ...\n",progname); + for (idx = 1; idx <= pefmax; idx++) + { + ret = GetPefEntry( 0x06, (ushort)idx, &PefRecord); + if (ret == 0) { // Show the PEF record + char *pa; + pc = (uchar *)&PefRecord; + sz = 21; // sizeof(PEF_RECORD) = 21 + if (PefRecord.sensor_type == 0) { + if (idx <= pefnum) + printf("PEFilter(%02d): empty\n",idx); + memcpy(pef_array[idx-1], &PefRecord, sz); + if (fAdjustPefNum) pefnum = (char)idx; + } else { + memcpy(pef_array[idx-1], &PefRecord, sz); + if (PefRecord.fconfig & 0x80) pc = "enabled"; + else pc = "disabled"; + i = PefRecord.rec_id; + switch(PefRecord.action) { + case 0x01: pa = "alert"; break; + case 0x02: pa = "poweroff"; break; + case 0x04: pa = "reset"; break; + case 0x08: pa = "powercycle"; break; + case 0x10: pa = "OEMaction"; break; + case 0x20: pa = "NMI"; break; + default: pa = "no action"; + } + printf("PEFilter(%02d): %02x %s event - %s for %s\n", + idx, PefRecord.sensor_type, + PefDesc(i,PefRecord.sensor_type), pc,pa); + } + if (fdebug) { /* show raw PEFilter record */ + pc = &PefRecord.rec_id; + printf("raw PEF(%.2d): ",pc[0]); + for (i = 0; i < sz; i++) printf("%02x ",pc[i]); + printf("\n"); + } + } else { + printf("GetPefEntry(%d), ret = %d\n",idx,ret); + if (ret == 0xC1) { /*PEF is not supported, so skip the rest. */ + fpefok = 0; + ndest = 0; /* if no PEF, no alerts & no alert dest */ + break; + } + } + } + } /*endif fpefok*/ + if (fpefok) { + if (fdebug) ShowPef(); + ret = GetPefEntry(0x01, 0,(PEF_RECORD *)&LanRecord); + if (ret == 0) { + j = LanRecord.data[0]; + mystr[0] = 0; + if (j & 0x01) strcat(mystr,"PEFenable "); + if (j & 0x02) strcat(mystr,"DoEventMsgs "); + if (j & 0x04) strcat(mystr,"Delay "); + if (j & 0x08) strcat(mystr,"AlertDelay "); + printf("PEF Control: %02x : %s\n",j, mystr); + } + ret = GetPefEntry(0x02, 0,(PEF_RECORD *)&LanRecord); + if (ret == 0) { + j = LanRecord.data[0]; + mystr[0] = 0; + if (j & 0x01) strcat(mystr,"Alert "); + if (j & 0x02) strcat(mystr,"PwrDn "); + if (j & 0x04) strcat(mystr,"Reset "); + if (j & 0x08) strcat(mystr,"PwrCyc "); + if (j & 0x10) strcat(mystr,"OEM "); + if (j & 0x20) strcat(mystr,"DiagInt "); + printf("PEF Actions: %02x : %s\n",j, mystr); + } + ret = GetPefEntry(0x03, 0,(PEF_RECORD *)&LanRecord); + if (ret == 0) printf("PEF Startup Delay: %02x : %d sec\n", + LanRecord.data[0],LanRecord.data[0]); + if (!fmBMC) { + ret = GetPefEntry(0x04, 0,(PEF_RECORD *)&LanRecord); + if (ret == 0) printf("PEF Alert Startup Delay: %02x: %d sec\n", + LanRecord.data[0],LanRecord.data[0]); + /* fmBMC gets cc=0x80 here */ + } + /* note that ndest should be read from lan param 17 below. */ + for (i = 1; i <= ndest; i++) + { + ret = GetPefEntry(0x09, (ushort)i,(PEF_RECORD *)&LanRecord); + if (ret == 0) { + mystr[0] = 0; + j = LanRecord.data[2]; + if (LanRecord.data[1] & 0x08) { + sprintf(mystr,"Chan[%d] Dest[%d] ",((j & 0xf0) >> 4),(j & 0x0f)); + strcat(mystr,"Enabled "); + } else strcpy(mystr,"Disabled "); + printf("PEF Alert Policy[%d]: %02x %02x %02x %02x : %s\n",i, + LanRecord.data[0], LanRecord.data[1], + LanRecord.data[2], LanRecord.data[3],mystr); + } + } /*endfor ndest*/ + } /*endif fpefok*/ + } /*endif not canonical*/ + + if (fpefenable && !freadonly) { /* fenable or fdisable */ + if (fSetPEFOks) pefadd = 5; + else pefadd = 2; + sz = (pefnum - 1) + pefadd + fCustomPEF; + printf("\n%s, SetPefEntry(1-%d) ...\n",progname,sz); + if (fdebug) printf("pefnum = %d, pefmax = %d\n",pefnum,pefmax); + for (idx = 1; idx <= pefmax; idx++) + { + // Set & Enable all PEF records + memset(&PefRecord.rec_id,0,sizeof(PEF_RECORD)); + PefRecord.rec_id = (uchar)idx; /* next record, or user-specified */ + if (idx < pefnum) { /* pefnum defaults to 12.(0x0c) */ + if (pef_array[idx-1][7] == 0) /*empty pef record, set to default*/ + memcpy(&PefRecord.rec_id,pef_defaults[idx-1],sizeof(PEF_RECORD)); + else { /* set config however it was previously */ + memcpy(&PefRecord.rec_id,pef_array[idx-1],sizeof(PEF_RECORD)); + if (PefRecord.severity == 0) + PefRecord.severity = pef_defaults[idx-1][4]; + } + } else if ((idx == pefnum) && /* new OS Crit Stop entry */ + (PefRecord.sensor_type == 0)) { + // Set PEF values for 0x20, OS Critical Stop event + PefRecord.severity = PEF_SEV_CRIT; + PefRecord.genid1 = 0xff; + PefRecord.genid2 = 0xff; + PefRecord.sensor_type = 0x20; /* OS Critical Stop */ + PefRecord.sensor_no = 0xff; + PefRecord.event_trigger = 0x6f; + PefRecord.data1 = 0xff; + PefRecord.mask1 = 0x00; + } else if ((idx == pefnum+1) && /* new Power Redundancy entry */ + (PefRecord.sensor_type == 0)) { + // Set PEF values for 0x09/0x02/0x0b/0x41, Power Redundancy Lost + PefRecord.severity = PEF_SEV_WARN; + PefRecord.genid1 = 0xff; + PefRecord.genid2 = 0xff; + PefRecord.sensor_type = 0x09; /* Power Unit */ + PefRecord.sensor_no = 0xff; /* usu 01 or 02 */ + PefRecord.event_trigger = 0x0b; /* event trigger */ + PefRecord.data1 = 0x02; /* 02 -> 41=Redundancy Lost */ + PefRecord.mask1 = 0x00; + } else if (fSetPEFOks && idx == (pefnum+2)) { + PefRecord.severity = PEF_SEV_OK; + PefRecord.genid1 = 0xff; + PefRecord.genid2 = 0xff; + PefRecord.sensor_type = 0x09; /* Power Unit, Redund OK */ + PefRecord.sensor_no = 0xff; /* usu 01 or 02 */ + PefRecord.event_trigger = 0x0b; /* event trigger */ + PefRecord.data1 = 0x01; /* 01 -> 40=Redundancy OK */ + PefRecord.mask1 = 0x00; + } else if (fSetPEFOks && idx == (pefnum+3)) { + PefRecord.severity = PEF_SEV_OK; + PefRecord.genid1 = 0xff; + PefRecord.genid2 = 0xff; + PefRecord.sensor_type = 0x01; /* Temp OK */ + PefRecord.sensor_no = 0xff; /* usu 01 or 02 */ + PefRecord.event_trigger = 0x81; /* event trigger */ + PefRecord.data1 = 0x95; /* 95 -> 50(NC),52(Crit) match */ + PefRecord.mask1 = 0x0a; + } else if (fSetPEFOks && idx == (pefnum+4)) { + PefRecord.severity = PEF_SEV_OK; + PefRecord.genid1 = 0xff; + PefRecord.genid2 = 0xff; + PefRecord.sensor_type = 0x02; /* Voltage OK */ + PefRecord.sensor_no = 0xff; /* usu 01 or 02 */ + PefRecord.event_trigger = 0x81; /* event trigger */ + PefRecord.data1 = 0x95; /* 95 -> 50(NC),52(Crit) match */ + PefRecord.mask1 = 0x0a; + } else if (fCustomPEF && idx == (pefnum+pefadd)) { + /* user entered 10 or 18 PEF entry bytes */ + PefRecord.action = custPEF[0]; + PefRecord.policy = custPEF[1]; + PefRecord.severity = custPEF[2]; + PefRecord.genid1 = custPEF[3]; + PefRecord.genid2 = custPEF[4]; + PefRecord.sensor_type = custPEF[5]; + PefRecord.sensor_no = custPEF[6]; + PefRecord.event_trigger = custPEF[7]; + PefRecord.data1 = custPEF[8]; + PefRecord.mask1 = custPEF[9]; + memcpy(&PefRecord.action,custPEF,18); + } else { + memcpy(&PefRecord.rec_id,pef_array[idx-1],sizeof(PEF_RECORD)); + if (PefRecord.sensor_type == 0) continue; /* if reserved, skip it */ + } + if (fdebug && (PefRecord.rec_id != idx)) { + /* memcpy from pef_defaults or pef_array clobbered rec_id */ + printf("Warning: SetPef idx=%d, rec_id=%d\n",idx,PefRecord.rec_id); + PefRecord.rec_id = (uchar)idx; /*fix it*/ + } + if (fdisable) { + /* Disable all PEF rules */ + if (idx >= pefnum) PefRecord.fconfig = 0x00; /*disabled, software*/ + else PefRecord.fconfig = 0x40; /*disabled, preset */ + PefRecord.action = 0x00; + PefRecord.policy = 0x00; + } else { /*fenable*/ + if (PefRecord.sensor_type != 0) { /* not an empty PEF entry */ + /* Enable all non-empty PEF rules */ + if (fCustomPEF && (idx == (pefnum+pefadd))) { + PefRecord.action = custPEF[0]; + PefRecord.policy = custPEF[1]; + } else { + PefRecord.action = 0x01; /*Alert*/ + PefRecord.policy = 0x01; /*see Alert Policy #1*/ + } + if (idx < pefnum) { /* special handling for presets, 1 thru 11 */ + PefRecord.fconfig = 0x80; /* enabled, software */ + ret = SetPefEntry(&PefRecord); + if (fdebug) + printf("SetPefEntry(%d/80) ret=%d\n",PefRecord.rec_id,ret); + // if (ret != 0) { nerrs++; lasterr = ret; } + // else ngood++; + PefRecord.fconfig = 0xC0; /* enabled, preset */ + } else { + PefRecord.fconfig = 0x80; /* enabled, software */ + } + } /*endif not empty*/ + } + { // Show the new PEF record before setting it. + pc = (uchar *)&PefRecord; + sz = 21; + printf("PEFilter(%d): ",PefRecord.rec_id); + for (i = 0; i < sz; i++) printf("%02x ",pc[i]); + printf("\n"); + } + ret = SetPefEntry(&PefRecord); + if (fdebug) + printf("SetPefEntry(%d) ret = %d\n", PefRecord.rec_id,ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } /*end for*/ + } + } /*end if not fIPMI10*/ + + if (!fcanonical) + printf("\n%s, GetLanEntry for channel %d ...\n",progname,lan_ch); + idest = 1; + for (idx = 0; idx < NLAN; idx++) + { + int ival; + if (fcanonical && (canon_param[idx] == 0)) continue; + if (idx == 8 || idx == 9) continue; /* not implemented */ + ival = lanparams[idx].cmd; + if (ival >= 96 && ival <= 98) continue; /* not implemented */ + if (ival >= 102 && ival <= 108) { /*custom IPv6 parameters*/ + if (fipv6 == 0) continue; /*skip these*/ + } + if (ival == 194 && vend_id == VENDOR_KONTRON) { /*oem hostname parm*/ + lanparams[idx].sz = 36; + strcpy(lanparams[idx].desc,"IPMI Hostname"); + } else if (ival >= 192 && ival <= 194) { /*custom DHCP parameters*/ + if (vend_id != VENDOR_INTEL) continue; + if (fmBMC || fiBMC || fcanonical) continue; /*skip these*/ + } + if (ival >= 20 && ival <= 25) { + if (!fIPMI20) continue; /*VLAN params 20-25, fIPMI20 only/opt*/ + } + if ((ndest == 0) && (ival >= 18 && ival <= 19)) continue; /*skip dest*/ + if (ival == 11) { /*grat arp interval*/ + if (vend_id == VENDOR_SUPERMICROX) continue; + if (vend_id == VENDOR_SUPERMICRO) continue; + } + if (ival == 14 || ival == 15) { /*secondary gateway is optional*/ + if (vend_id == VENDOR_KONTRON) continue; + } + if (ival == 201) { /*Get Channel Access*/ + ret = ShowChanAcc(lan_ch); + } else { + if (ival == 18 || ival == 19) { /*dest params*/ + if (ndest == 0) continue; /*skip if ndest==0 */ + bset = (uchar)idest; /* dest id = 1 thru n */ + } else bset = 0; + ret = GetLanEntry((uchar)ival, bset, &LanRecord); + } + if (ret == 0) { // Show the LAN record + pc = (uchar *)&LanRecord; + sz = lanparams[idx].sz; + if (ival == 18) { /*skip if invalid dest type param*/ + if ((idest > 1) && (pc[2] == 0)) { idest = 1; continue; } + } else if (ival == 19) { /*skip if invalid dest addr param*/ + if ((idest > 1) && !IpIsValid(&pc[3])) { idest = 1; continue; } + } + if (ival == 201) ; /* did it above */ + else { + if (fcanonical) { + if ((ival == 19) && (idest > 1)) ; /*skip it*/ + else { + j = strlen_(lanparams[idx].desc); + // (ival < 7) || (ival == 19) || ival == 102) + if (j <= 12) pstr = pspace3; + else pstr = pspace2; + printf("Channel %d %s %s%c ",lan_ch, + lanparams[idx].desc,pstr,bdelim); + } + } else + printf("Lan Param(%d) %s: ",ival,lanparams[idx].desc); + } + if (ival == 1) { + authmask = pc[0]; /* auth type support mask */ + /* if (fmBMC) authmask is usually 0x15, else 0x14 */ + } else if (ival == 3) { + if (IpIsValid(pc)) memcpy(bmcmyip,pc,4); + } else if (ival == 5) { + if (MacIsValid(pc)) memcpy(bmcmymac,pc,MAC_LEN); + } else if (ival == 6) { + if (SubnetIsValid(pc)) memcpy(bmcsubnet,pc,4); + /* else if invalid, leave default as 255.255.255.0 */ + //} else if (ival == 7) { + // if (pc[0] >= 30) memcpy(bparm7,pc,3); + } else if (ival == 17) { /* num dest */ + ndest = pc[0]; /* save the number of destinations */ + } else if (ival == 19) { /* dest addr */ + if (IpIsValid(&pc[3])) memcpy(bmcdestip,&pc[3],4); + if (MacIsValid(&pc[7])) memcpy(bmcdestmac,&pc[7],MAC_LEN); + } else if (ival == 22) { /*Cipher Suite Support*/ + nciphers = pc[0]; + } + /* now start to display data */ + if (ival == 16) { printf("%s \n",pc); /* string */ + } else if (ival == 194 && vend_id == VENDOR_KONTRON) { + printf("%s \n",pc); /* string */ + } else if (ival == 201) { ; /* did it above */ + } else { /* print results for all other ival's */ + pstr = ""; /*interpreted meaning*/ + if (fcanonical) { + switch(ival) { + case 4: /*param 4, ip src*/ + if (pc[0] == SRC_STATIC) pstr = "Static"; /*0x01*/ + else if (pc[0] == SRC_DHCP) pstr = "DHCP"; /*0x02*/ + else if (pc[0] == SRC_BIOS) pstr = "BIOS"; /*0x03*/ + else pstr = "Other"; + printf("%s\n",pstr); + break; + case 5: /*param 5, mac addr*/ + case 13: /*param 6, def gwy mac*/ + printf("%02x:%02x:%02x:%02x:%02x:%02x\n", + pc[0], pc[1], pc[2], pc[3], pc[4], pc[5]); + break; + case 3: /*param 4, ip address*/ + case 6: /*param 6, subnet mask*/ + case 12: /*param 12, def gwy ip*/ + case 14: /*param 14, sec gwy ip*/ + case 192: /*param 192, DHCP svr ip*/ + printf("%d.%d.%d.%d\n",pc[0], pc[1], pc[2], pc[3]); + break; + case 19: /*param 19, dest address*/ + if (idest == 1) { + printf("IP=%d.%d.%d.%d " + "MAC=%02x:%02x:%02x:%02x:%02x:%02x\n", + pc[3], pc[4], pc[5], pc[6], + pc[7], pc[8], pc[9], pc[10], pc[11], pc[12]); + } + break; + case 102: /*param 102, IPv6 enable*/ + if (pc[0] == 0x01) printf("enabled\n"); + else printf("disabled\n"); + break; + default: + printf("%02x \n",pc[0]); + break; + } + } else { /*not canonical */ + if (ival == 3 || ival == 6 || ival == 12 || ival == 14 + || ival == 192) { + printf("%d.%d.%d.%d",pc[0], pc[1], pc[2], pc[3]); + } else if (ival == 23) { /*Cipher Suites*/ + for (i = 1; i <= nciphers; i++) printf("%2d ",pc[i]); + } else if (ival == 24) { /*Cipher Suite Privi Levels*/ + for (i = 1; i < 9; i++) { + char c1, c2; + char *p; + p = parse_priv((pc[i] & 0x0f)); + c1 = p[0]; + p = parse_priv((pc[i] & 0xf0) >> 4); + c2 = p[0]; + if ((i*2) >= nciphers) c2 = ' '; + printf(" %c %c ",c1,c2); + if ((i*2) > nciphers) break; + } + } else + for (i = 0; i < sz; i++) + { + /* print in hex, decimal, or string, based on ival */ + if (ival == 1) { /* Auth type support */ + pstr = &mystr[0]; + getauthstr(authmask,pstr); + printf("%02x ",authmask); + } else if (ival == 4) { /* IP addr source */ + if (pc[i] == SRC_STATIC) pstr = "Static"; /*0x01*/ + else if (pc[i] == SRC_DHCP) pstr = "DHCP"; /*0x02*/ + else if (pc[i] == SRC_BIOS) pstr = "BIOS"; /*0x03*/ + else pstr = "Other"; + printf("%02x ",pc[i]); + } else if (ival == 10) { /* grat ARP */ + mystr[0] = 0; + if (pc[i] == 0) strcat(mystr,"ARP disabled "); + else if (pc[i] & 0x01) strcat(mystr,"Grat-ARP enabled"); + else strcat(mystr,"Grat-ARP disabled"); + if (pc[i] & 0x02) strcat(mystr,", ARP-resp enabled"); + pstr = &mystr[0]; + printf("%02x ",pc[i]); + } else if (ival == 11) { /* grat ARP interval */ + float f; + f = (float)pc[i] / (float)2; /*500msec increments*/ + sprintf(mystr,"%.1f sec",f); + pstr = &mystr[0]; + printf("%02x ",pc[i]); + } else if (ival == 19) { /* dest addr */ + if (i > 2 && i < 7) { + char *sepstr; + if (i == 3) printf("["); + if (i == 6) sepstr = "] "; + else if (i >=3 && i < 6) sepstr = "."; + else sepstr = " "; + printf("%d%s",pc[i],sepstr); /* IP address in dec */ + } + else printf("%02x ",pc[i]); /* show mac/etc. in hex */ + } + else printf("%02x ",pc[i]); /* show in hex */ + } /*end for*/ + if (ival == 2) { /*Auth type enables*/ + pstr = &mystr[0]; + i = 0; + if (lan_ch > 0) i = lan_ch - 1; + getauthstr(pc[i],pstr); + } + if (pstr[0] != 0) printf(": %s\n",pstr); + else printf("\n"); + } /*end-else not canonical*/ + } /*end-else others*/ + if (ival == 18 || ival == 19) { + if (idest < ndest) { + idest++; + idx--; /* repeat this param*/ + } else idest = 1; + } + } else { /* ret != 0 */ + if (ival >= 20 && ival <= 25) { /*if errors, optional*/ + if (fdebug) printf("GetLanEntry(%d), ret = %d\n",ival,ret); + } else + printf("GetLanEntry(%d), ret = %d\n",ival,ret); + if (ival == 17) ndest = 0; /*error getting num dest*/ + } + } /*end for*/ + if (fRomley) { /*get LAN Failover param*/ + uchar b; + ret = lan_failover_intel(0xFF,(uchar *)&b); + if (ret != 0) + printf("Intel Lan Failover, ret = %d\n",ret); + else { + if (b == 1) pstr = "enabled"; + else pstr = "disabled"; + if (fcanonical) + printf("Intel Lan Failover %s%c %s\n", + pspace3, bdelim,pstr); + else printf("Intel Lan Failover %s%c %02x %c %s\n", + pspace2, bdelim,b,bdelim,pstr); + } + } + if (vend_id == VENDOR_SUPERMICROX || vend_id == VENDOR_SUPERMICRO) { + ret = oem_supermicro_get_lan_port(&bset); + if (ret == 0) { + pstr = oem_supermicro_lan_port_string(bset); + if (fcanonical) + printf("SuperMicro Lan Interface %s%c %s\n", + pspace2, bdelim,pstr); + else printf("SuperMicro Lan Interface %c %02x %c %s\n", + bdelim,bset,bdelim,pstr); + } else { + if (fdebug) printf("oem_supermicro_get_lan_port error %d\n",ret); + ret = 0; /*may not be supported on all smc plaforms*/ + } + } + // if (fmBMC) lan_access = 0x04; /*Admin*/ + // else lan_access = 0x04; /*Admin*/ + if (!fIPMI10) { /* Get SOL params */ + ret = GetSerialOverLan(lan_ch,0,0); + if (ret != 0) printf("GetSOL error %d\n",ret); + } + for (i = 1; i <= show_users; i++) + GetUser((uchar)i); + + if (fgetser && !fcanonical) { + printf("\n%s, GetSerEntry ...\n",progname); + if (fmBMC) /* mBMC doesn't support serial */ + printf("No serial channel support on this platform\n"); + else + for (idx = 0; idx < NSER; idx++) { + int ival; + // if (idx == 9) continue; /* not implemented */ + ival = serparams[idx].cmd; + if (ival == 201) { + ret = GetChanAcc(ser_ch, 0x40, &LanRecord); + } else { + ret = GetSerEntry((uchar)ival, &LanRecord); + } + if (ret == 0) { // Show the SER record + pc = (uchar *)&LanRecord; + sz = serparams[idx].sz; + printf("Serial Param(%d) %s: ",ival,serparams[idx].desc); + if (idx == 10) { /* modem init string */ + pc[sz] = 0; + printf("%02x %s\n",pc[0],&pc[1]); + } + else if ((idx >= 11 && idx <= 13) || idx == 15) { /* strings */ + printf("%s\n",pc); + } + else { + for (i = 0; i < sz; i++) { + printf("%02x ",pc[i]); /* show in hex */ + } + printf("\n"); + } /*end else*/ + } + } /*end for*/ + } /*endif fgetser*/ + + if (!freadonly) /* Set IPMI LAN enable/disable params. */ + { + if (fipmilan) /* Sets not valid via ipmi_lan if same channel. */ + printf("\nWarning: Setting LAN %d params while using a LAN channel.\n", lan_ch); + + { + if (fenable && (fsharedMAC==0) && !lan_dhcp) { + /* must have an IP from -I option */ + if (!IpIsValid(rgmyip)) { /* if not user-specified */ + if (IpIsValid(bmcmyip)) { + memcpy(rgmyip,bmcmyip,4); + if (fdebug) printf("Using current IP %d.%d.%d.%d\n", + bmcmyip[0], bmcmyip[1], + bmcmyip[2], bmcmyip[3]); + } else { + printf("\nNot shared BMC LAN, must specify a unique " + "IP address via -I\n"); + ret = ERR_BAD_PARAM; + goto do_exit; + } + } + } + /* Set LAN parameters. fenable or fdisable */ + printf("\n%s, SetLanEntry for channel %d ...\n",progname,lan_ch); + /* use ifname to resolve MAC addresses below */ + if (fdisable) { + if (!fIPMI10) { + ret = DisablePef(alertnum); + printf("DisablePef, ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + if (lan_user != 0) { + j = DisableUser(lan_user); /*disable this lan user*/ + printf("DisableUser(%d), ret = %d\n",lan_user,j); + if (j != 0) { nerrs++; lasterr = j; } + else ngood++; + } + LanRecord.data[0] = 0x01; /* static IP address source */ + ret = SetLanEntry(4, &LanRecord, 1); + printf("SetLanEntry(4), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + /* clear the BMC IP address */ + memset(&LanRecord,0,4); + ret = SetLanEntry(3, &LanRecord, 4); + printf("SetLanEntry(3), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + /* clear the gateway IP address */ + memset(&LanRecord,0,4); + ret = SetLanEntry(12, &LanRecord, 4); + printf("SetLanEntry(12), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + /* clear the gateway MAC address */ + memset(&LanRecord,0,6); + ret = SetLanEntry(13, &LanRecord, 6); + printf("SetLanEntry(13), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } else if (fdisableSOL) { + ret = SetupSerialOverLan(0); /*disable*/ + SELprintf("SetupSerialOverLan: ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } else { /*fenable*/ + uchar chanctl; + if (bmcpefctl != 0) chanctl = chan_pefon; /*previously on*/ + else chanctl = chan_pefoff; + ret = SetChanAcc(lan_ch, 0x80, chanctl); + if (fdebug) printf("SetChanAcc(lan/active), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + ret = SetChanAcc(lan_ch, 0x40, chanctl); + if (fdebug) printf("SetChanAcc(lan/nonvol), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + ret = SetUser(lan_user,myuser,passwordData); + printf("SetUser(%d), ret = %d\n",lan_user,ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + if (fdisable && (vend_id == VENDOR_SUPERMICROX + || vend_id == VENDOR_SUPERMICRO) ) { + failover_enable = 0; /*dedicated*/ + ret = oem_supermicro_set_lan_port(failover_enable); + printf("Set SuperMicro Lan port to %s, ret = %d\n", + oem_supermicro_lan_port_string(failover_enable),ret); + if (ret != 0) { nerrs++; lasterr = ret; } + } + + if (fdisable || fdisableSOL) { + // if (nerrs > 0) printf("Warning: %d errors occurred\n",nerrs); + goto do_exit; + } + + if (authmask == 0) authmask = 0x17; /*if none from GetLanEntry(1)*/ + LanRecord.data[0] = (bAuth & authmask); /*Callback level*/ + LanRecord.data[1] = (bAuth & authmask); /*User level */ + LanRecord.data[2] = (bAuth & authmask); /*Operator level*/ + LanRecord.data[3] = (bAuth & authmask); /*Admin level */ + LanRecord.data[4] = 0; /*OEM level*/ + if (fdebug) printf("SetLanEntry(2): %02x %02x %02x %02x %02x\n", + LanRecord.data[0],LanRecord.data[1],LanRecord.data[2], + LanRecord.data[3],LanRecord.data[4]); + ret = SetLanEntry(2, &LanRecord, 5); + printf("SetLanEntry(2), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + + /* Get the values to use from Linux eth0, etc. */ + ret = Get_IPMac_Addr(); + if (lan_dhcp) { /* use DHCP */ + LanRecord.data[0] = SRC_DHCP; /* BMC running DHCP */ + /* = SRC_BIOS; * address source = BIOS using DHCP */ + ret = SetLanEntry(4, &LanRecord, 1); + printf("SetLanEntry(4), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + if (MacIsValid(rgmymac)) { + memcpy(&LanRecord,rgmymac,6); + ret = SetLanEntry(5, &LanRecord, 6); + if (ret == 0x82) { /*BMC may not allow the MAC to be set*/ + if (fdebug) + printf("SetLanEntry(5), ret = %x cannot modify MAC\n",ret); + } else { + printf("SetLanEntry(5), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + } + + /* DHCP also relates to OEM LAN params 192, 193, 194 */ + if ((vend_id == VENDOR_INTEL) && !fmBMC && !fiBMC) + { /*DHCP params 192-194 are Intel only*/ + if (IpIsValid(rgmyip)) + { + /* Set DHCP Server IP in param 192 from -I param. */ + memcpy(&LanRecord,rgmyip,4); + ret = SetLanEntry(192, &LanRecord, 4); + printf("SetLanEntry(192), ret = %d\n",ret); + if (!MacIsValid(rgdhcpmac)) /* if MAC not set yet */ + ret = Get_Mac(rgmyip,rgdhcpmac,NULL); + if (ret == 0) { + memcpy(&LanRecord,rgdhcpmac,MAC_LEN); + ret = SetLanEntry(193, &LanRecord, MAC_LEN); + printf("SetLanEntry(193), ret = %d\n",ret); + } + } + LanRecord.data[0] = 0x01; /*enable DHCP*/ + ret = SetLanEntry(194, &LanRecord, 1); + printf("SetLanEntry(194), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + } else { /* use static IP */ + printf("LAN%d (%s)\tip=%d.%d.%d.%d mac=%02x:%02x:%02x:%02x:%02x:%02x\n", + lan_ch,ifname, rgmyip[0], rgmyip[1], rgmyip[2], rgmyip[3], + rgmymac[0], rgmymac[1], rgmymac[2], rgmymac[3], + rgmymac[4], rgmymac[5]); + if (IpIsValid(rgmyip)) { + if (lan_ch != gcm_ch) { /*skip if gcm*/ + LanRecord.data[0] = 0x00; /*disable grat arp while setting IP*/ + ret = SetLanEntry(10, &LanRecord, 1); + if (fdebug) printf("SetLanEntry(10,0), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + } + LanRecord.data[0] = 0x01; /* static IP address source */ + ret = SetLanEntry(4, &LanRecord, 1); + printf("SetLanEntry(4), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + memcpy(&LanRecord,rgmyip,4); + ret = SetLanEntry(3, &LanRecord, 4); + printf("SetLanEntry(3), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + if (MacIsValid(rgmymac)) { + memcpy(&LanRecord,rgmymac,6); + ret = SetLanEntry(5, &LanRecord, 6); + if (ret == 0x82) { + /* Do not show anything, not an error if BMC does not + allow the BMC MAC to be changed. */ + if (fdebug) + printf("SetLanEntry(5), ret = %x cannot modify MAC\n",ret); + } else { + printf("SetLanEntry(5), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + } + if (!SubnetIsValid(rgsubnet)) /* not specified, use previous */ + memcpy(rgsubnet,bmcsubnet,4); + memcpy(&LanRecord,rgsubnet,4); + ret = SetLanEntry(6, &LanRecord, 4); + printf("SetLanEntry(6), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + if (vend_id != VENDOR_PEPPERCON) { + /* may want to check bparm7 here */ + LanRecord.data[0] = parm7[0]; /*IPv4 header, TTL */ + LanRecord.data[1] = parm7[1]; /*IPv4 header, Flags */ + LanRecord.data[2] = parm7[2]; /*IPv4 hdr, Precedence/Service */ + ret = SetLanEntry(7, &LanRecord, 3); + printf("SetLanEntry(7), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + /* if lan_ch == 3, gcm gets error setting grat arp (ccode=0xCD) */ + if (lan_ch != gcm_ch) { /*skip if gcm*/ + /* 01=enable grat arp, 02=enable arp resp, 03=both */ + LanRecord.data[0] = arp_ctl; /*grat arp*/ + ret = SetLanEntry(10, &LanRecord, 1); + printf("SetLanEntry(10,%x), ret = %d\n",arp_ctl,ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + LanRecord.data[0] = arp_interval; /*grat arp interval*/ + ret = SetLanEntry(11, &LanRecord, 1); + printf("SetLanEntry(11), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + if ((vend_id == VENDOR_INTEL) && !fmBMC && !fiBMC) { + LanRecord.data[0] = 0x00; /*disable DHCP*/ + ret = SetLanEntry(194, &LanRecord, 1); + printf("SetLanEntry(194), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + } else { /* error, don't continue */ + printf("Missing IP Address, can't continue. Use -I to specify\n"); + ret = ERR_BAD_PARAM; + goto do_exit; + } + if (vend_id == VENDOR_KONTRON && rghostname[0] != 0) { + /* set the IPMI Hostname if specified */ + sz = strlen_(rghostname); + /* LanRecord is larger than rghostname, bounds ok */ + strncpy((char *)&LanRecord.data,rghostname,sz); + ret = SetLanEntry(194, &LanRecord, sz); + printf("SetLanEntry(194), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else { + LanRecord.data[0] = 0x31; + ret = SetLanEntry(195, &LanRecord, 1); /*re-read hostname*/ + // printf("SetLanEntry(195), ret = %d\n",ret); + // if (ret != 0) { nerrs++; lasterr = ret; } + } + } + if (IpIsValid(rggwyip)) { + if (!MacIsValid(rggwymac)) /* if gwy MAC not set by user */ + ret = Get_Mac(rggwyip,rggwymac,NULL); + printf("gateway \tip=%d.%d.%d.%d mac=%02x:%02x:%02x:%02x:%02x:%02x\n", + rggwyip[0], rggwyip[1], rggwyip[2], rggwyip[3], + rggwymac[0], rggwymac[1], rggwymac[2], rggwymac[3], + rggwymac[4], rggwymac[5]); + if (!SubnetIsSame(rgmyip,rggwyip,rgsubnet)) + printf("WARNING: IP Address and Gateway are not on the same subnet.\n"); + + /* Set the Default Gateway IP & MAC */ + memcpy(&LanRecord,rggwyip,4); + ret = SetLanEntry(12, &LanRecord, 4); + printf("SetLanEntry(12), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + if (!MacIsValid(rggwymac)) { /* if gwy MAC not resolved */ + printf(" Warning: Gateway MAC address was not resolved! " + "Check %s interface, use -i ethN, or use -H gwymac.\n", + ifname); + } else { + memcpy(&LanRecord,rggwymac,6); + ret = SetLanEntry(13, &LanRecord, 6); + printf("SetLanEntry(13), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + } + if (IpIsValid(rggwy2ip)) { + if (!MacIsValid(rggwy2mac)) /* if gwy2 MAC not set by user */ + ret = Get_Mac(rggwy2ip,rggwy2mac,NULL); + /* Set the Secondary Gateway IP & MAC */ + memcpy(&LanRecord,rggwy2ip,4); + ret = SetLanEntry(14, &LanRecord, 4); + printf("SetLanEntry(14), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + memcpy(&LanRecord,rggwy2mac,6); + ret = SetLanEntry(15, &LanRecord, 6); + printf("SetLanEntry(15), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + } /* end-else static IP */ + ret = SetupSerialOverLan(1); /*enable*/ + SELprintf("SetupSerialOverLan: ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + if (!IpIsValid(rgdestip) && IpIsValid(bmcdestip)) { + memcpy(rgdestip,bmcdestip,4); + if (fdebug) printf("Using current dest IP %d.%d.%d.%d\n", + bmcdestip[0], bmcdestip[1], + bmcdestip[2], bmcdestip[3]); + } + if (ndest == 0) { + if (fdebug) printf("ndest==0, anum=%d rgdestip=%d.%d.%d.%d\n", + alertnum, rgdestip[0], rgdestip[1], rgdestip[2], rgdestip[3]); + printf("alert dest \tnot supported\n"); + } else if (!IpIsValid(rgdestip)) { + printf("alert dest \taddress not specified\n"); + } else { /* valid alert dest ip */ + if (!MacIsValid(rgdestmac)) /* if dest MAC not set by user */ + ret = Get_Mac(rgdestip,rgdestmac,NULL); /*try to resolve MAC */ + if (!MacIsValid(rgdestmac)) { /* if dest MAC not resolved */ + printf(" Warning: Alert mac address was not resolved!" + " Check %s interface or use -i.\n",ifname); + /* use existing BMC alert dest mac (as best guess) */ + memcpy(rgdestmac,bmcdestmac,6); + } + /* show destination data */ + printf("alert dest %d\tip=%d.%d.%d.%d mac=%02x:%02x:%02x:%02x:%02x:%02x\n", + alertnum, rgdestip[0], rgdestip[1], rgdestip[2], rgdestip[3], + rgdestmac[0], rgdestmac[1], rgdestmac[2], rgdestmac[3], + rgdestmac[4], rgdestmac[5]); + printf("snmp community \t%s\n",rgcommunity); + /* Only need the SNMP community if there is an Alert Destination */ + memset(&LanRecord.data[0], 0, 18); /* make sure zero-filled */ + strcpy(&LanRecord.data[0],rgcommunity); + ret = SetLanEntry(16, &LanRecord, 18); + printf("SetLanEntry(16), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + /* Set Alert Destination Type */ + LanRecord.data[0] = alertnum; /* dest id = 1 */ + LanRecord.data[1] = 0x00; /* dest type = PET, no ack */ + LanRecord.data[2] = 0x01; /* ack timeout / retry interval */ + LanRecord.data[3] = 0x00; /* no retries */ + // LanRecord.data[4] = 0x69; + ret = SetLanEntry(18, &LanRecord, 4); + printf("SetLanEntry(18), ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + { + /* Set the Alert Destination IP & MAC (param 19) */ + LanRecord.data[0] = alertnum; /* dest id = 1 */ + LanRecord.data[1] = 0x00; + LanRecord.data[2] = 0x00; + memcpy(&LanRecord.data[3],rgdestip,4); + memcpy(&LanRecord.data[7],rgdestmac,6); + ret = SetLanEntry(19, &LanRecord, 13); + printf("SetLanEntry(19), ret = %d\n", ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + } /*endif valid alert*/ + + /* Now enable PEF since we have an Alert destination. */ + if (!fdisable && !fIPMI10 && fpefenable) { /*fpefenable*/ + ret = EnablePef(alertnum); + printf("EnablePef, ret = %d\n",ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + /* ChanAcc changed, so show it again */ + j = ShowChanAcc(lan_ch); + } + + if ((vlan_enable != PARM_INIT) && (fIPMI20)) { + if (vlan_enable == 0) { /*disable vlan*/ + LanRecord.data[0] = 0x00; + LanRecord.data[1] = 0x00; + ret = SetLanEntry(20, &LanRecord, 2); + printf("SetLanEntry(20,disable) ret = %d\n", ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } else { /*vlan_enable == 1, enable vlan with id */ + LanRecord.data[0] = (vlan_id & 0x00ff); + LanRecord.data[1] = ((vlan_id & 0x0f00) >> 8) | 0x80; + ret = SetLanEntry(20, &LanRecord, 2); + printf("SetLanEntry(20,%d), ret = %d\n", vlan_id,ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + LanRecord.data[0] = vlan_prio; + ret = SetLanEntry(21, &LanRecord, 1); + printf("SetLanEntry(21), ret = %d\n", ret); + if (ret != 0) { nerrs++; lasterr = ret; } + else ngood++; + } + } + if (failover_enable != PARM_INIT) { + if (fRomley) { + if (failover_enable > 1) failover_enable = 0; /*default*/ + ret = lan_failover_intel(failover_enable,(uchar *)&i); + printf("Set Intel Lan Failover (%d), ret = %d\n", + failover_enable,ret); + if (ret != 0) { nerrs++; lasterr = ret; } + } else if (vend_id == VENDOR_SUPERMICROX + || vend_id == VENDOR_SUPERMICRO) { + if (failover_enable > 2) failover_enable = 2; /*default*/ + ret = oem_supermicro_set_lan_port(failover_enable); + printf("Set SuperMicro Lan port to %s, ret = %d\n", + oem_supermicro_lan_port_string(failover_enable),ret); + if (ret != 0) { nerrs++; lasterr = ret; } + } + } /*endif failover specified*/ + } /*end-else not via ipmi_lan*/ + } /*endif not readonly*/ + + if (flanstats) + { /* get BMC LAN Statistics */ +#ifdef METACOMMAND + j = get_lan_stats(lan_ch); +#else + uchar idata[2]; + uchar rdata[20]; + int rlen; + uchar cc; + idata[0] = lan_ch; + idata[1] = 0x00; /*do not clear stats*/ + rlen = sizeof(rdata); + j = ipmi_cmd(GET_LAN_STATS, idata,2, rdata,&rlen, &cc, fdebug); + if (j == 0) { /*show BMC LAN stats*/ + ushort *rw; + rw = (ushort *)&rdata[0]; + printf("IPMI LAN channel %d statistics: \n",lan_ch); + printf(" \tReceived IP Packets = %d\n",rw[0]); + printf(" \tRecvd IP Header errors = %d\n",rw[1]); + printf(" \tRecvd IP Address errors = %d\n",rw[2]); + printf(" \tRecvd IP Fragments = %d\n",rw[3]); + printf(" \tTransmitted IP Packets = %d\n",rw[4]); + printf(" \tReceived UDP Packets = %d\n",rw[5]); + printf(" \tReceived Valid RMCP Pkts = %d\n",rw[6]); + printf(" \tReceived UDP Proxy Pkts = %d\n",rw[7]); + printf(" \tDropped UDP Proxy Pkts = %d\n",rw[8]); + } +#endif + } + +do_exit: + ipmi_close_(); + if (foptmsg) { + if (fset_ip != 0) + printf("WARNING: IP address options were specified, but no -e,-l,-d option.\n"); + else + printf("WARNING: %d options were specified, but no -e,-l,-d option.\n", + nopts); + printf("Read-only usage assumed.\n"); + } + if (nerrs > 0) { + printf("Warning: %d ok, %d errors occurred, last error = %d\n",ngood,nerrs,lasterr); + ret = lasterr; + } + // show_outcome(progname,ret); + return(ret); +} /* end main()*/ + +/* end ilan.c */ diff --git a/util/imb_api.h b/util/imb_api.h new file mode 100644 index 0000000..56a940c --- /dev/null +++ b/util/imb_api.h @@ -0,0 +1,708 @@ +/*M* +// PVCS: +// $Workfile: imb_api.h $ +// $Revision: 1.0 $ +// $Modtime: Jul 22 2002 16:40:32 $ +// $Author: arcress at users.sf.net $ +// +// Combined include files needed for imbapi.c +// + *M*/ +/*----------------------------------------------------------------------* +The BSD License +Copyright (c) 2002, Intel Corporation +Copyright (c) 2009 Kontron America, 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: + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions 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. + c.. Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *----------------------------------------------------------------------*/ +#ifndef _WINDEFS_H +#define _WINDEFS_H + +#ifndef NULL +#define NULL 0 +#endif +#define TRUE 1 +#define FALSE 0 + +#if defined(WIN32) | defined(BSD) | defined(DOS) +/* WIN32 defines wchar_t in stdio.h */ +/* BSD defines wchar_t in stdlib.h */ +/* DOS defines wchar_t in stdlib.h */ +#else + // defined(LINUX) | defined(SOLARIS) +#ifndef _WCHAR_T +#define _WCHAR_T +typedef long wchar_t; +#endif +#endif + +#define far +#define near +#define FAR far +#define NEAR near +#ifndef CONST +#define CONST const +#endif +typedef unsigned int UINT32; +typedef unsigned long DWORD; +typedef int BOOL; +typedef unsigned char BYTE; +typedef unsigned short WORD; +typedef float FLOAT; +typedef FLOAT *PFLOAT; +typedef BOOL near *PBOOL; +typedef BOOL far *LPBOOL; +typedef BYTE near *PBYTE; +typedef BYTE far *LPBYTE; +typedef int near *PINT; +typedef int far *LPINT; +typedef WORD near *PWORD; +typedef WORD far *LPWORD; +typedef long far *LPLONG; +typedef DWORD near *PDWORD; +typedef DWORD far *LPDWORD; +typedef void far *LPVOID; +typedef CONST void far *LPCVOID; +typedef int INT; +typedef unsigned int UINT; +typedef unsigned int *PUINT; +#ifndef NTSTATUS +typedef DWORD NTSTATUS; +#endif +/* + File structures +*/ +#ifndef WIN32 +typedef struct _OVERLAPPED { + DWORD Internal; + DWORD InternalHigh; + DWORD Offset; + DWORD OffsetHigh; +/* HANDLE hEvent; */ +} OVERLAPPED, *LPOVERLAPPED; +#endif +/* + * Data structure redefines + */ +typedef char CHAR; +typedef short SHORT; +typedef long LONG; +typedef char * PCHAR; +typedef short * PSHORT; +typedef long * PLONG; +typedef unsigned char UCHAR; +typedef unsigned short USHORT; +typedef unsigned long ULONG; +typedef char CCHAR; +typedef short CSHORT; +typedef ULONG CLONG; +typedef CCHAR * PCCHAR; +typedef CSHORT * PCSHORT; +typedef CLONG * PCLONG; +typedef void * PVOID; +#ifndef WIN32 +typedef void VOID; +typedef struct _LARGE_INTEGER { + ULONG LowPart; + LONG HighPart; +} LARGE_INTEGER; +typedef struct _ULARGE_INTEGER { + ULONG LowPart; + ULONG HighPart; +} ULARGE_INTEGER; +#endif +typedef LARGE_INTEGER * PLARGE_INTEGER; +typedef LARGE_INTEGER PHYSICAL_ADDRESS; +typedef LARGE_INTEGER * PPHYSICAL_ADDRESS; +typedef ULARGE_INTEGER * PULARGE_INTEGER; +typedef UCHAR BOOLEAN; +typedef BOOLEAN *PBOOLEAN; +typedef wchar_t WCHAR; +typedef WCHAR *PWCHAR, *PWSTR; +typedef CONST WCHAR *LPCWSTR, *PCWSTR; + +/* + Unicode strings are counted 16-bit character strings. If they are + NULL terminated, Length does not include trailing NULL. +*/ +typedef struct _UNICODE_STRING { + USHORT Length; + USHORT MaximumLength; + PWSTR Buffer; +} UNICODE_STRING; +typedef UNICODE_STRING *PUNICODE_STRING; +#define UNICODE_NULL ((WCHAR)0) /* winnt*/ +#define IN /* */ +#define OUT /* */ +#define OPTIONAL /* */ + +#ifdef WIN32 +#define HandleType HANDLE +#else +#define HandleType long +#define FIELD_OFFSET(type, field) ((LONG)&(((type *)0)->field)) +#define UNREFERENCED_PARAMETER(x) +#define INVALID_HANDLE_VALUE ((HandleType)-1) +#endif +typedef HandleType *PHANDLE; +/* + Define the method codes for how buffers are passed for I/O and FS controls +*/ +#define METHOD_BUFFERED 0 +/* + Define the access check value for any access + The FILE_READ_ACCESS and FILE_WRITE_ACCESS constants are also defined in + ntioapi.h as FILE_READ_DATA and FILE_WRITE_DATA. The values for these + constants *MUST* always be in sync. +*/ +#define FILE_ANY_ACCESS 0 +/* + These are the generic rights. +*/ +#define MAX_PATH 260 +// #define GetLastError() (NTstatus.Status) +/* + Macro definition for defining IOCTL and FSCTL function control codes. Note + that function codes 0-2047 are reserved for Microsoft Corporation, and + 2048-4095 are reserved for customers. +*/ +/* + * Linux drivers expect ioctls defined using macros defined in ioctl.h. + * So, instead of using the CTL_CODE defined for NT and UW, I define CTL_CODE + * using these macros. That way imb_if.h, where the ioctls are defined get + * to use the correct ioctl command we expect. + * Notes: I am using the generic _IO macro instead of the more specific + * ones. The macros expect 8bit entities, so I am cleaning what is sent to + * us from imb_if.h - Mahendra + */ +#ifdef LINUX +#define CTL_CODE(DeviceType, Function, Method, Access)\ + _IO(DeviceType & 0x00FF, Function & 0x00FF) +#else +/* WIN32 may have this defined in winsdk\include\winioctl.h */ +#ifndef CTL_CODE +#define CTL_CODE( DeviceType, Function, Method, Access ) ((ULONG)( \ + ((ULONG)(DeviceType) << 16) | ((ULONG)(Access) << 14) | ((ULONG)(Function) << 2) | ((ULONG)Method) \ +)) +#endif +#endif +#endif /*_WINDEFS_H */ +/*----------------------------------------------------------------------*/ +#ifndef _SMI_H +#define _SMI_H +#define SMI_Version1_00 0x00001000 +#define SMI_Version2_00 0x00002000 +/* LPVOID = (void far *) */ +/* DWORD = (unsigned long ) */ +/* typedef DWORD far *LPDWORD; */ +/* LPOVERLAPPED = struct w 4 DWORDs */ +struct smi { + DWORD smi_VersionNo; + DWORD smi_Reserved1; + DWORD smi_Reserved2; + LPVOID ntstatus; /* address of NT status block*/ + LPVOID lpvInBuffer; /* address of buffer for input data*/ + DWORD cbInBuffer; /* size of input buffer*/ + LPVOID lpvOutBuffer; /* address of output buffer*/ + DWORD cbOutBuffer; /* size of output buffer*/ + LPDWORD lpcbBytesReturned; /* address of actual bytes of output*/ + LPOVERLAPPED lpoOverlapped; /* address of overlapped structure*/ +}; +struct smi32 { + UINT32 smi_VersionNo; + UINT32 smi_Reserved1; + UINT32 smi_Reserved2; + UINT32 ntstatus; /* address of NT status block*/ + UINT32 lpvInBuffer; /* address of buffer for input data*/ + UINT32 cbInBuffer; /* size of input buffer*/ + UINT32 lpvOutBuffer; /* address of output buffer*/ + UINT32 cbOutBuffer; /* size of output buffer*/ + UINT32 lpcbBytesReturned; /* address of actual bytes of output*/ + struct { UINT32 h[4]; } lpoOverlapped; /* address of overlapped structure*/ +}; +#ifndef STATUS_SUCCESS +typedef struct _IO_STATUS_BLOCK { + ULONG Status; + ULONG Information; +} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; +/* + * I2C ioctl's return NTStatus codes + */ +#define STATUS_SUCCESS (0x00000000U) +#define STATUS_UNSUCCESSFUL (0xC0000001U) +#define STATUS_DEVICE_BUSY (0x80000011U) +#ifndef WIN32 +// see \inc\winnt.h(1171) +#define STATUS_PENDING (0x00000103U) +#define STATUS_INVALID_PARAMETER (0xC000000DU) +#endif +#define STATUS_INVALID_DEVICE_REQUEST (0xC0000010U) +#define STATUS_BUFFER_TOO_SMALL (0xC0000023U) +#define STATUS_FILE_CLOSED (0xC0000128U) +#define STATUS_INSUFFICIENT_RESOURCES (0xC000009AU) +#define STATUS_NO_DATA_DETECTED (0x80000022U) +#define STATUS_NO_SUCH_DEVICE (0xC000000EU) +#define STATUS_ALLOTTED_EXCEEDED (0xC000000FU) +#define STATUS_IO_DEVICE_ERROR (0xC0000185U) +#define STATUS_TOO_MANY_OPEN_FILES (0xC000011FU) +#define STATUS_ACCESS_DENIED (0xC0000022U) +#define STATUS_BUFFER_OVERFLOW (0x80000005U) +#define STATUS_CANCELLED (0xC0000120U) +#endif /* STATUS_SUCCESS*/ +#endif /* _SMI_H*/ +/*----------------------------------------------------------------------*/ +#ifndef IMB_IF__ +#define IMB_IF__ +/* + * This is the structure passed in to the IOCTL_IMB_SHUTDOWN_CODE request + */ +typedef struct { + int code; + int delayTime; +} ShutdownCmdBuffer; +#define SD_NO_ACTION 0 +#define SD_RESET 1 +#define SD_POWER_OFF 2 + +#pragma pack(1) +/* + * This is the generic IMB packet format, the final checksum cant be + * represented in this structure and will show up as the last data byte + */ +typedef struct { + BYTE rsSa; + BYTE nfLn; + BYTE cSum1; + BYTE rqSa; + BYTE seqLn; + BYTE cmd; + BYTE data[1]; +} ImbPacket; +#define MIN_IMB_PACKET_SIZE 7 +#define MAX_IMB_PACKET_SIZE 57 /*was 33, now 64-7=57*/ +// #define MAX_IMB_PACKET_SIZE 135 (if using flashupdt large packets) +#define MAX_RBUFFER_SIZE 64 /*no longer used*/ +/* + * This is the standard IMB response format where the first byte of + * IMB packet data is interpreted as a command completion code. +*/ +typedef struct { + BYTE rsSa; + BYTE nfLn; + BYTE cSum1; + BYTE rqSa; + BYTE seqLn; + BYTE cmd; + BYTE cCode; + BYTE data[1]; +} ImbRespPacket; +#define MIN_IMB_RESPONSE_SIZE 7 /* min packet + completion code */ +#define MAX_IMB_RESPONSE_SIZE MAX_IMB_PACKET_SIZE +/************************ + * ImbRequestBuffer + ************************/ +/*D* +// Name: ImbRequestBuffer +// Purpose: Structure definition for holding IMB message data +// Context: Used by SendTimedImbpMessage and SendTimedI2cMessge +// functions in the library interface. In use, it is overlayed on a +// char buffer of size MIN_IMB_REQ_BUF_SIZE + +// Fields: +// respBufSize size of the response buffer +// +// timeout timeout value in milli seconds +// +// req body of request to send +// +*D*/ +typedef struct { + BYTE rsSa; + BYTE cmd; + BYTE netFn; + BYTE rsLun; + BYTE dataLength; + BYTE data[16]; +} ImbRequest; +typedef struct { + UINT32 flags; /* request flags*/ +#define NO_RESPONSE_EXPECTED 0x01 /*dont wait around for an IMB response*/ + UINT32 timeOut; /* in uSec units*/ + ImbRequest req; /* message buffer*/ +} ImbRequestBuffer; +#define MIN_IMB_REQ_BUF_SIZE 13 /* a buffer without any request data*/ +#define MAX_IMB_REQ_SIZE (MIN_IMB_RESP_BUF_SIZE + MAX_IMB_PACKET_SIZE) +/************************ + * ImbResponseBuffer + ************************/ +/*D* +// Name: ImbResponseBuffer +// Purpose: Structure definition for response of a previous send +// Context: Used by DeviceIoControl to pass the message to be sent to +// MISSMIC port +// Fields: +// cCode completion code returned by firmware +// data buffer for response data from firmware +*D*/ +typedef struct { + BYTE cCode; + BYTE data[1]; +} ImbResponseBuffer; +#define MIN_IMB_RESP_BUF_SIZE 1 +#define MAX_IMB_RESP_SIZE (MIN_IMB_RESP_BUF_SIZE + MAX_IMB_RESPONSE_SIZE) +#pragma pack() + +/* + * Async message access structures and types + */ +typedef UINT32 ImbAsyncSeq; +/* + * This is the structure passed in to IOCTL_IMB_GET_ASYNC_MSG +*/ +typedef struct { + UINT32 timeOut; + ImbAsyncSeq lastSeq; +} ImbAsyncRequest; +#define ASYNC_SEQ_START 0 +typedef struct { + ImbAsyncSeq thisSeq; + BYTE data[1]; +} ImbAsyncResponse; +#define MIN_ASYNC_RESP_SIZE sizeof( ImbAsyncSeq ) +#define MAX_ASYNC_RESP_SIZE (MIN_ASYNC_RESP_SIZE + MAX_IMB_PACKET_SIZE) +/* +** Driver Ioctls +** In Linux, these calculate to: +** IOCTL_IMB_SEND_MESSAGE =1082 +** IOCTL_IMB_GET_ASYNC_MSG =1088 +** IOCTL_IMB_MAP_MEMORY =108e +** IOCTL_IMB_UNMAP_MEMORY =1090 +** IOCTL_IMB_SHUTDOWN_CODE =1092 +** IOCTL_IMB_REGISTER_ASYNC_OBJ =1098 +** IOCTL_IMB_DEREGISTER_ASYNC_OBJ=109a +** IOCTL_IMB_CHECK_EVENT =109c +** IOCTL_IMB_POLL_ASYNC =1094 +*/ +#define FILE_DEVICE_IMB 0x00008010 +#define IOCTL_IMB_BASE 0x00000880 +#define IOCTL_IMB_SEND_MESSAGE CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 2), METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_IMB_GET_ASYNC_MSG CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 8), METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_IMB_MAP_MEMORY CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 14),METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_IMB_UNMAP_MEMORY CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 16),METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_IMB_SHUTDOWN_CODE CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 18),METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_IMB_REGISTER_ASYNC_OBJ CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 24),METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_IMB_DEREGISTER_ASYNC_OBJ CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 26),METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_IMB_CHECK_EVENT CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 28),METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_IMB_POLL_ASYNC CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 20),METHOD_BUFFERED, FILE_ANY_ACCESS) +#endif /* IMB_IF__ */ +/*----------------------------------------------------------------------*/ +/* No asynchronous messages available */ +#define IMB_MSG_NOT_AVAILABLE ((NTSTATUS)0xE0070012L) +#ifdef IMBLOG_H__ +/* Define the facility codes */ +#define FACILITY_RPC_STUBS 0x3 +#define FACILITY_RPC_RUNTIME 0x2 +#define FACILITY_IO_ERROR_CODE 0x4 +#define IMB_IO_ERROR_CODE 0x7 + +#define STATUS_SEVERITY_WARNING 0x2 +#define STATUS_SEVERITY_SUCCESS 0x0 +#define STATUS_SEVERITY_INFORMATIONAL 0x1 +#define STATUS_SEVERITY_ERROR 0x3 +/* Not enough memory for internal storage of device %1. */ +#define INSUFFICIENT_RESOURCES ((NTSTATUS)0xE0070001L) + +#define INVALID_INPUT_BUFFER ((NTSTATUS)0xE0070002L) + +#define INVALID_OUTPUT_BUFFER ((NTSTATUS)0xE0070003L) + +#define IMB_SEND_TIMEOUT ((NTSTATUS)0xE0070004L) + +#define IMB_RECEIVE_TIMEOUT ((NTSTATUS)0xE0070005L) + +#define IMB_IF_SEND_TIMEOUT ((NTSTATUS)0xE0070006L) + +#define IMB_IF_RECEIVE_TIMEOUT ((NTSTATUS)0xE0040007L) + +#define HARDWARE_FAILURE ((NTSTATUS)0xE0040008L) + +#define DRIVER_FAILURE ((NTSTATUS)0xE0040009L) + +#define IMB_INVALID_IF_RESPONSE ((NTSTATUS)0xE004000AL) + +#define IMB_INVALID_PACKET ((NTSTATUS)0xE004000BL) + +#define IMB_RESPONSE_DATA_OVERFLOW ((NTSTATUS)0xE004000CL) + +#define IMB_INVALID_REQUEST ((NTSTATUS)0xE007000DL) + +#define INVALID_DRIVER_IOCTL ((NTSTATUS)0xE007000EL) + +#define INVALID_DRIVER_REQUEST ((NTSTATUS)0xE007000FL) + +#define IMB_CANT_GET_SMS_BUFFER ((NTSTATUS)0xE0070010L) + +#define INPUT_BUFFER_TOO_SMALL ((NTSTATUS)0xE0070011L) + +#define IMB_SEND_ERROR ((NTSTATUS)0xE0070013L) +#endif /* IMBLOG_H__ */ +/*----------------------------------------------------------------------*/ +#ifndef IMBAPI_H__ +#define IMBAPI_H__ +#include +#if defined(MACOS) +/* has caddr_t */ +#else +#ifndef _SYS_TYPES_H +#ifndef _CADDR_T +#define _CADDR_T + typedef char * caddr_t; +#endif +#endif +#endif + +#define WRITE_READ_I2C 0x52 +#define WRITE_EMP_BUFFER 0x7a +#define GET_DEVICE_ID 0x1 +#define CMD_GET_DEVICE_ID 0x01 +#define SEND_MESSAGE 0x34 +#define GET_MESSAGE 0x33 +#define BMC_SA 0x20 +#define BMC_LUN 0 +#define APP_NETFN 0x06 +#define IPMI_09_VERSION 0x90 +#define IPMI_10_VERSION 0x01 + +#define IPMI_15_VERSION 0x51 + +#ifndef IPMI10_GET_DEVICE_ID_RESP_LENGTH +#define IPMI10_GET_DEVICE_ID_RESP_LENGTH 12 +#endif + +#define IPMB_CHANNEL 0x0 +#define EMP_CHANNEL 0x1 +#define LAN_CHANNEL 0x2 +#define ANY_CHANNEL 0xFF +#define RESERVED_LUN 0x3 +#define IPMB_LUN 0x2 +#define EMP_LUN 0x0 + +#define PUBLIC_BUS 0 + +#define BMC_CONTROLLER 0x20 +#define FPC_CONTROLLER 0x22 +typedef enum { + ACCESN_OK, + ACCESN_ERROR, + ACCESN_OUT_OF_RANGE, + ACCESN_END_OF_DATA, + ACCESN_UNSUPPORTED, + ACCESN_INVALID_TRANSACTION, + ACCESN_TIMED_OUT +} ACCESN_STATUS; +#pragma pack(1) +/* + * Request structure provided to SendTimedImbpRequest() +*/ +typedef struct { + unsigned char cmdType; + unsigned char rsSa; + unsigned char busType; + unsigned char netFn; + unsigned char rsLun; + unsigned char * data; + int dataLength; +} IMBPREQUESTDATA; +/* + * Request structure provided to SendTimedI2cRequest() +*/ +typedef struct { + unsigned char rsSa; + unsigned char busType; + unsigned char numberOfBytesToRead; + unsigned char * data; + int dataLength; +} I2CREQUESTDATA; +#pragma pack() +/*#ifdef IMB_API + * + * This section is provided to be able to compile using imb_if.h + * + * + * function return type. This is also defined in the local instrumentation + * so we ifdef here to avoid conflict. +*/ +#define METHOD_BUFFERED 0 +#define FILE_ANY_ACCESS 0 +/* + * This is necessary to compile using memIf.h + */ +typedef enum _INTERFACE_TYPE +{ + Internal, + Isa, + Eisa, + MicroChannel, + TurboChannel, + MaximumInterfaceType +} INTERFACE_TYPE, * PINTERFACE_TYPE; +#ifdef WIN32 +/* From memIf.h */ +#pragma pack(1) +typedef struct +{ + INTERFACE_TYPE InterfaceType; // Isa, Eisa, etc.... + ULONG BusNumber; // Bus number + PHYSICAL_ADDRESS BusAddress; // Bus-relative address + ULONG AddressSpace; // 0 is memory, 1 is I/O + ULONG Length; // Length of section to map +} PHYSICAL_MEMORY_INFO, * PPHYSICAL_MEMORY_INFO; +#pragma pack() +#endif +/*#else // not IMB_API */ +/* + * These are defined in imb_if.h but are needed by users of the imbapi library +*/ +#define ASYNC_SEQ_START 0 +/* + * This is the generic IMB packet format, the final checksum cant be + * represented in this structure and will show up as the last data byte + */ +/*#endif // IMB_API */ + +/****************************** + * FUNCTION PROTOTYPES + ******************************/ +#ifdef LINK_LANDESK +#define SendTimedImbpRequest ia_SendTimedImbpRequest +#define StartAsyncMesgPoll ia_StartAsyncMesgPoll +#define SendTimedI2cRequest ia_SendTimedI2cRequest +#define SendTimedEmpMessageResponse ia_SendTimedEmpMessageResponse +#define SendTimedEmpMessageResponse_Ex ia_SendTimedEmpMessageResponse_Ex +#define SendTimedLanMessageResponse ia_SendTimedLanMessageResponse +#define SendTimedLanMessageResponse_Ex ia_SendTimedLanMessageResponse_Ex +#define SendAsyncImbpRequest ia_SendAsyncImbpRequest +#define GetAsyncImbpMessage ia_GetAsyncImbpMessage +#define GetAsyncImbpMessage_Ex ia_GetAsyncImbpMessage_Ex +#define IsAsyncMessageAvailable ia_IsAsyncMessageAvailable +#define RegisterForImbAsyncMessageNotification ia_RegisterForImbAsyncMessageNotification +#define UnRegisterForImbAsyncMessageNotification ia_UnRegisterForImbAsyncMessageNotification +#define SetShutDownCode ia_SetShutDownCode +#define GetIpmiVersion ia_GetIpmiVersion +#else +int initIPMI(void); +int termIPMI(void); +#endif + +ACCESN_STATUS +SendTimedImbpRequest ( + IMBPREQUESTDATA *reqPtr, + int timeOut, + BYTE * respDataPtr, + int * respDataLen, + BYTE * completionCode + ); +ACCESN_STATUS +SendTimedI2cRequest ( + I2CREQUESTDATA *reqPtr, + int timeOut, + BYTE * respDataPtr, + int * respDataLen, + BYTE * completionCode + ); +ACCESN_STATUS +SendAsyncImbpRequest ( + IMBPREQUESTDATA *reqPtr, + BYTE * seqNo + ); +ACCESN_STATUS +GetAsyncImbpMessage ( + ImbPacket * msgPtr, + DWORD * msgLen, + DWORD timeOut, + ImbAsyncSeq * seqNo, + DWORD channelNumber + ); +ACCESN_STATUS +GetAsyncImbpMessage_Ex ( + ImbPacket * msgPtr, + DWORD * msgLen, + DWORD timeOut, + ImbAsyncSeq * seqNo, + DWORD channelNumber, + BYTE * sessionHandle, + BYTE * privilege + ); +ACCESN_STATUS +UnmapPhysicalMemory( int virtualAddress, int Length ); +ACCESN_STATUS +StartAsyncMesgPoll(void); +ACCESN_STATUS +MapPhysicalMemory ( + int startAddress, + int addressLength, + int *virtualAddress + ); +ACCESN_STATUS +SetShutDownCode ( + int delayTime, + int code + ); +ACCESN_STATUS +SendTimedEmpMessageResponse ( + ImbPacket * ptr, + char *responseDataBuf, + int responseDataLen, + int timeOut + ); +ACCESN_STATUS +SendTimedEmpMessageResponse_Ex ( + ImbPacket * ptr, + char *responseDataBuf, + int responseDataLen, + int timeOut, + BYTE sessionHandle, + BYTE channelNumber + ); +ACCESN_STATUS +SendTimedLanMessageResponse ( + ImbPacket * ptr, + char *responseDataBuf, + int responseDataLen, + int timeOut + ); +ACCESN_STATUS +SendTimedLanMessageResponse_Ex ( + ImbPacket * ptr, + char *responseDataBuf, + int responseDataLen, + int timeOut , + BYTE sessionHandle, + BYTE channelNumber + ); +ACCESN_STATUS +IsAsyncMessageAvailable (HandleType eventId); +ACCESN_STATUS +RegisterForImbAsyncMessageNotification (HandleType *handleId); +ACCESN_STATUS +UnRegisterForImbAsyncMessageNotification (HandleType handleId,int iFlag); +BYTE GetIpmiVersion(void); +#endif /* IMBAPI_H__ */ diff --git a/util/imbapi.c b/util/imbapi.c new file mode 100644 index 0000000..cbc8fa1 --- /dev/null +++ b/util/imbapi.c @@ -0,0 +1,2594 @@ +/*M* +// PVCS: +// $Workfile: imbapi.c $ +// $Revision: 1.12 $ +// $Modtime: 06 Aug 2001 13:16:56 $ +// +// Purpose: This file contains the entry point that opens the IMB device +// in order to issue the IMB driver API related IOCTLs. +// This file implements the IMB driver API for the Server +// Management Agents. +// +// $Log: //epg-scc/sst/projectdatabases/isc/isc3x/LNWORK/SRC/imbapi/imbapi.c.v $ +// +// 04/04/02 ARCress - Mods for open-source & various compile cleanup mods +// 05/28/02 ARCress - fixed buffer size error +// 04/08/03 ARCress - misc cleanup +// 01/20/04 ARCress - added WIN32 flags +// 05/24/05 ARCress - added LINK_LANDESK flags +// 08/24/06 ARCress - mods for addtl DEBUG (dbgmsg) +// 03/19/08 ARCress - fix for SendTimedLan(IpmiVersion) if IPMI 2.0 +*M*/ +/*----------------------------------------------------------------------* +The BSD License +Copyright (c) 2002-2006, Intel Corporation +Copyright (c) 2009 Kontron America, 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: + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions 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. + c.. Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *----------------------------------------------------------------------*/ + +#if defined(SOLARIS) || defined(BSD) +#undef IMB_API +#else +/* Ok for WIN32, LINUX, SCO_UW, etc., but not Solaris */ +#define IMB_API 1 +#endif + +#ifdef IMB_API + +#ifdef WIN32 +#define NO_MACRO_ARGS 1 +#include +#include +#define uint unsigned int + +#else /* LINUX, SCO_UW, UNIX */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif +#include "imb_api.h" + +#ifdef SCO_UW +#define NO_MACRO_ARGS 1 +#define __FUNCTION__ "func" +#define IMB_DEVICE "/dev/instru/mismic" +#else +#define IMB_DEVICE "/dev/imb" +#define PAGESIZE EXEC_PAGESIZE +#endif + +/*Just to make the DEBUG code cleaner.*/ +#if defined(DBG_IPMI) || defined(LINUX_DEBUG) +#include +static void dbgmsg( char *pattn, ... ) +{ + va_list arglist; + FILE *fdlog; + + fdlog = fopen( "imbdbg.log", "a+" ); + if (fdlog == NULL) fdlog = stdout; + va_start( arglist, pattn ); + vfprintf( fdlog, pattn, arglist ); + va_end( arglist ); + fclose(fdlog); +} +#endif +#ifdef NO_MACRO_ARGS +#define DEBUG(format, args) /*not_debug*/ +#else +#ifdef LINUX_DEBUG +#define DEBUG(format, args...) dbgmsg(format, ##args) +// #define DEBUG(format, args...) printf(format, ##args) +#else +#define DEBUG(format, args...) /*not_debug*/ +#endif +#endif + +#define IMB_OPEN_TIMEOUT 400 +#define IMB_MAX_RETRIES 2 +#define IMB_DEFAULT_TIMEOUT (1000) /*timeout for SendTimedImb in msec*/ +#define ERR_NO_DRV -16 /*cannot open IPMI driver*/ + +#define LOCAL_IPMB 1 /*instead of METACOMMAND_IPMB*/ + +int ipmi_timeout_ia = IMB_DEFAULT_TIMEOUT; /* in msec */ +#ifdef METACOMMAND_IPMB /*++++ not used*/ +extern int ipmi_cmd_ipmb(BYTE cmd, BYTE netfn, BYTE sa, BYTE bus, BYTE lun, + BYTE *pdata, int sdata, BYTE *presp, + int *sresp, BYTE *pcc, char fdebugcmd); /*ipmilan.c*/ +#endif +#ifdef METACOMMAND +extern FILE *fpdbg; +extern FILE *fperr; +#else +static FILE *fpdbg = NULL; +static FILE *fperr = NULL; +#endif + +/* uncomment out the #define below or use -DLINUX_DEBUG_MAX in the makefile +// if you want a dump of the memory to debug mmap system call in +// MapPhysicalMemory() below. +// +//#define LINUX_DEBUG_MAX 1 */ +//#define IMB_MEMORY 1 */ + +/*keep it simple. use global varibles for event objects and handles +//pai 10/8 */ + +/* UnixWare should eventually have its own source code file. Right now +// new code has been added based on the existing policy of using +// pre-processor directives to separate os-specific code (pai 11/21) */ + +static int IpmiVersion; +static HandleType AsyncEventHandle = 0; +// static void * AsyncEventObject = 0; + +/*//////////////////////////////////////////////////////////////////////////// +// GLOBAL VARIABLES +///////////////////////////////////////////////////////////////////////////// */ + +#if defined(__i386__) || defined(__i586__) || defined(__i686__) +// static DWORD ioctl_sendmsg = 0x1082; /* force 0x1082 if 32-bit */ +static DWORD ioctl_sendmsg = IOCTL_IMB_SEND_MESSAGE; +#else +static DWORD ioctl_sendmsg = IOCTL_IMB_SEND_MESSAGE; +#endif + +static IO_STATUS_BLOCK NTstatus; /*dummy place holder. See deviceiocontrol. */ +static HandleType hDevice1; /*used in open_imb() */ +static HandleType hDevice; /*used to call DeviceIoControl()*/ +/*mutex_t deviceMutex; */ +#ifdef LINUX_DEBUG +static char fdebug = 1; +#else +static char fdebug = 0; +#endif + +#ifdef LINK_LANDESK +#define SendTimedImbpRequest ia_SendTimedImbpRequest +#define StartAsyncMesgPoll ia_StartAsyncMesgPoll +#define SendTimedI2cRequest ia_SendTimedI2cRequest +#define SendTimedEmpMessageResponse ia_SendTimedEmpMessageResponse +#define SendTimedEmpMessageResponse_Ex ia_SendTimedEmpMessageResponse_Ex +#define SendTimedLanMessageResponse ia_SendTimedLanMessageResponse +#define SendTimedLanMessageResponse_Ex ia_SendTimedLanMessageResponse_Ex +#define SendAsyncImbpRequest ia_SendAsyncImbpRequest +#define GetAsyncImbpMessage ia_GetAsyncImbpMessage +#define GetAsyncImbpMessage_Ex ia_GetAsyncImbpMessage_Ex +#define IsAsyncMessageAvailable ia_IsAsyncMessageAvailable +#define RegisterForImbAsyncMessageNotification ia_RegisterForImbAsyncMessageNotification +#define UnRegisterForImbAsyncMessageNotification ia_UnRegisterForImbAsyncMessageNotification +#define SetShutDownCode ia_SetShutDownCode +#define GetIpmiVersion ia_GetIpmiVersion +#endif + +int open_imb(int fskipcmd); + +void set_fps(void) +{ + if (fpdbg == NULL) fpdbg = stdout; + if (fperr == NULL) fperr = stdout; +} + +#ifndef WIN32 +DWORD GetLastError(void) { return(NTstatus.Status); } + +/*/////////////////////////////////////////////////////////////////////////// +// DeviceIoControl +///////////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: DeviceIoControl +// Purpose: Simulate NT DeviceIoControl using unix calls and structures. +// Context: called for every NT DeviceIoControl +// Returns: FALSE for fail and TRUE for success. Same as standarad NTOS call +// as it also sets Ntstatus.status. +// Parameters: Standard NT call parameters, see below. +// Notes: none +*F*/ +static BOOL +DeviceIoControl( + HandleType dummy_hDevice, /* handle of device */ + DWORD dwIoControlCode, /* control code of operation to perform*/ + LPVOID lpvInBuffer, /* address of buffer for input data */ + DWORD cbInBuffer, /* size of input buffer */ + LPVOID lpvOutBuffer, /* address of output buffer */ + DWORD cbOutBuffer, /* size of output buffer */ + LPDWORD lpcbBytesReturned, /* address of actual bytes of output */ + LPOVERLAPPED lpoOverlapped /* address of overlapped struct */ + ) +{ + struct smi s; + int rc, max_i; + int ioctl_status; + + DEBUG("DeviceIoControl: hDevice1=%x hDevice=%x ioctl=%x\n", + hDevice1,hDevice,dwIoControlCode); + rc = open_imb(1); /*open if needed, set fskipcmd to avoid recursion*/ + if (rc == 0) { +#ifdef DBG_IPMI + dbgmsg("DeviceIoControl: open_imb failed %d\n", rc); +#endif + return FALSE; + } + + /*-------------dont use locking-------------- + //lock the mutex, before making the request.... + if(mutex_lock(&deviceMutex) != 0) { + return(FALSE); + } + *-------------------------------------------*/ +#ifndef NO_MACRO_ARGS + DEBUG("%s: ioctl cmd = 0x%lx ", __FUNCTION__,dwIoControlCode); + DEBUG("cbInBuffer %d cbOutBuffer %d\n", cbInBuffer, cbOutBuffer); +#endif + /* Test for Intel imb driver max buf size */ + /* Max was 41, too small. Calculate real max - ARCress 6/01/05 */ + max_i = MAX_IMB_PACKET_SIZE + MIN_IMB_REQ_BUF_SIZE; /*33 + 13*/ + if (cbInBuffer > max_i) cbInBuffer = max_i; + + s.lpvInBuffer = lpvInBuffer; + s.cbInBuffer = cbInBuffer; + s.lpvOutBuffer = lpvOutBuffer; + s.cbOutBuffer = cbOutBuffer; + s.lpcbBytesReturned = lpcbBytesReturned; + s.lpoOverlapped = lpoOverlapped; + s.ntstatus = (LPVOID)&NTstatus; /*dummy place holder. Linux IMB driver + //doesnt return status or info via it.*/ +#ifdef IMB_DEBUG + if (fdebug) { + int j, n; + char *tag; + unsigned int *bi; + unsigned char *b; + + printf("ioctl %x smi buffer:\n",dwIoControlCode); + /* show arg/smi structure */ + bi = (unsigned int *)&s; + n = ( sizeof(struct smi) / sizeof(int) ); + printf("smi(%p), (sz=%d/szint=%d)->%d:\n", bi, sizeof(struct smi), + sizeof(int),n); + for (j = 0; j < n; j++) { + switch(j) { + case 0: tag = "version "; break; + case 2: tag = "reserved1"; break; + case 4: tag = "reserved2"; break; + case 6: tag = "ntstatus "; break; + case 8: tag = "pinbuf "; break; + case 10: tag = "sinbuf "; break; + case 12: tag = "poutbuf"; break; + case 14: tag = "soutbuf"; break; + case 16: tag = "cbRet "; break; + case 18: tag = "pOverlap"; break; + default: tag = "other "; + } + printf("bi[%d]%s: %08x \n",j,tag,bi[j]); + } /*end for*/ + } +#endif + + if ( (ioctl_status = ioctl(hDevice1, dwIoControlCode,&s) ) <0) { +#ifndef NO_MACRO_ARGS + DEBUG("%s %s: ioctl cmd = 0x%x failed %d \n", + __FILE__,__FUNCTION__,dwIoControlCode,ioctl_status); +#endif +#ifdef DBG_IPMI + dbgmsg("DeviceIoControl: ioctl cmd = 0x%x failed %d \n", + dwIoControlCode,ioctl_status); +#endif + /* mutex_unlock(&deviceMutex); */ + return FALSE; + } + /*-------------dont use locking-------------- + mutex_unlock(&deviceMutex); + *-------------------------------------------*/ + +#ifndef NO_MACRO_ARGS + DEBUG("%s: ioctl_status %d bytes returned = %d \n", + __FUNCTION__, ioctl_status, *lpcbBytesReturned); +#endif + +/*MR commented this just as in Sol1.10. lpcbBytesReturned has the right data +// *lpcbBytesReturned = NTstatus.Information; */ + + if (ioctl_status == STATUS_SUCCESS) { +#ifndef NO_MACRO_ARGS + DEBUG("%s returning true\n", __FUNCTION__); +#endif + return (TRUE); + } + else { +#ifndef NO_MACRO_ARGS + DEBUG("%s returning false\n", __FUNCTION__); +#endif + return (FALSE); + } +} +#endif + +static void _dump_buf(char *tag, BYTE *pbuf, int sz, char fshowascii) +{ + BYTE line[17]; + BYTE a; + int i, j; + char *stag; + FILE *fpdbg1; + +#ifdef DBG_IPMI + fpdbg1 = fopen( "imbdbg.log", "a+" ); + if (fpdbg1 == NULL) fpdbg1 = stdout; +#else + fpdbg1 = stdout; +#endif + if (tag == NULL) stag = "dump_buf"; /*safety valve*/ + else stag = tag; + fprintf(fpdbg1,"%s (len=%d): ", stag,sz); + line[0] = 0; line[16] = 0; + j = 0; + if (sz < 0) { fprintf(fpdbg1,"\n"); return; } /*safety valve*/ + for (i = 0; i < sz; i++) { + if (i % 16 == 0) { + line[j] = 0; + j = 0; + fprintf(fpdbg1,"%s\n %04x: ",line,i); + } + if (fshowascii) { + a = pbuf[i]; + if (a < 0x20 || a > 0x7f) a = '.'; + line[j++] = a; + } + fprintf(fpdbg1,"%02x ",pbuf[i]); + } + if (fshowascii) { + if ((j > 0) && (j < 16)) { + /* space over the remaining number of hex bytes */ + for (i = 0; i < (16-j); i++) fprintf(fpdbg1," "); + } + else j = 16; + line[j] = 0; + } + fprintf(fpdbg1,"%s\n",line); +#ifdef DBG_IPMI + if (fpdbg1 != stdout) fclose(fpdbg1); +#endif + return; +} + +#ifdef LOCAL_IPMB +#define SMS_MSG_LUN 0x02 +extern void os_usleep(int s, int u); /*subs.c*/ +static int sendSeq = 1; +static BYTE cksum(const BYTE *buf, register int len) +{ /* 8-bit 2s compliment checksum */ + register BYTE csum; + register int i; + csum = 0; + for (i = 0; i < len; i++) csum = (csum + buf[i]) % 256; + csum = -csum; + return(csum); +} + +// SendTimedIpmbpRequest +ACCESN_STATUS +SendTimedIpmbpRequest ( + IMBPREQUESTDATA *reqPtr, /* request info and data */ + int timeOut, /* how long to wait, in mSec units */ + BYTE *respDataPtr, /* where to put response data */ + int *respDataLen, /* how much response data there is */ + BYTE *completionCode /* request status from bmc controller*/ + ) +{ + BYTE responseData[MAX_IMB_REQ_SIZE]; + ImbResponseBuffer * resp = (ImbResponseBuffer *) responseData; + DWORD respLength = sizeof( responseData ); + DWORD reqLength; + BYTE requestData[MAX_IMB_RESP_SIZE]; + ImbRequestBuffer * req = (ImbRequestBuffer *) requestData; + BOOL status; + int i; + + req->req.rsSa = BMC_SA; + req->req.cmd = SEND_MESSAGE; + req->req.netFn = APP_NETFN; + req->req.rsLun = BMC_LUN; /*=0*/ + req->req.data[0] = reqPtr->busType; + req->req.data[1] = reqPtr->rsSa; + req->req.data[2] = ((reqPtr->netFn << 2) | (reqPtr->rsLun & 0x03)); + req->req.data[3] = cksum(&req->req.data[1],2); + req->req.data[4] = BMC_SA; + req->req.data[5] = ((sendSeq << 2) | (SMS_MSG_LUN & 0x03)); + req->req.data[6] = reqPtr->cmdType; + for (i = 0; i < reqPtr->dataLength; i++) + req->req.data[7+i] = reqPtr->data[i]; + req->req.data[7+i] = cksum(&req->req.data[4], reqPtr->dataLength + 3); + req->req.dataLength = reqPtr->dataLength + 8; + + req->flags = 0; + req->timeOut = timeOut * 1000; /* convert to uSec units */ + reqLength = req->req.dataLength + MIN_IMB_REQ_BUF_SIZE; + status = DeviceIoControl( hDevice, + ioctl_sendmsg, + requestData, + reqLength, + & responseData, + sizeof( responseData ), + & respLength, + NULL); + if (fdebug) printf("sendIpmb: send_message status=%d rlen=%d cc=%x\n", + status,respLength,resp->cCode); + if ( status != TRUE ) { + DWORD error; + error = GetLastError(); + return ACCESN_ERROR; + } + if ( respLength == 0 ) { + return ACCESN_ERROR; + } + sendSeq++; + if ( resp->cCode != 0) { + *completionCode = resp->cCode; + *respDataLen = 0; + return ACCESN_OK; + } + + /* + * Sent ok, wait for GetMessage response + */ + for (i=0; i < 10; i++) /* RETRIES=10 for GetMessage */ + { + //req->req.busType = PUBLIC_BUS; /*=0*/ + req->req.rsSa = BMC_SA; + req->req.cmd = GET_MESSAGE; + req->req.netFn = APP_NETFN; + req->req.rsLun = BMC_LUN; /*=0*/ + req->req.dataLength = 0; + reqLength = req->req.dataLength + MIN_IMB_REQ_BUF_SIZE; + status = DeviceIoControl( hDevice, + ioctl_sendmsg, + requestData, + reqLength, + & responseData, + sizeof( responseData ), + & respLength, + NULL); + if (fdebug) printf("sendIpmb: get_message status=%d rlen=%d cc=%x\n", + status,respLength,resp->cCode); + if ( status != TRUE ) { + DWORD error; + error = GetLastError(); + return ACCESN_ERROR; + } + if ( respLength == 0 ) { + return ACCESN_ERROR; + } + if ( (resp->cCode != 0x80) && (resp->cCode != 0x83) ) + break; /*success, exit loop*/ + os_usleep(0,1000); /* 1 msec*/ + } /*end-for*/ + + /* + * give the caller his response + */ + *completionCode = resp->cCode; + *respDataLen = 0; + if (( respLength > 1 ) && ( respDataPtr)) { + /* check that resp cmd & netfn match */ + *respDataLen = respLength - 7; + memcpy( respDataPtr, &resp->data[7], *respDataLen); + } + return ACCESN_OK; +} +#endif + +/*/////////////////////////////////////////////////////////////////////////// +// SendTimedImbpRequest +///////////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: SendTimedImbpRequest +// Purpose: This function sends a request for BMC implemented function +// Context: Used by Upper level agents (sis modules) to access BMC implemented functionality. +// Returns: OK else error status code +// Parameters: +// reqPtr +// timeOut +// respDataPtr +// respLen +// Notes: none +*F*/ +ACCESN_STATUS +SendTimedImbpRequest ( + IMBPREQUESTDATA *reqPtr, /* request info and data */ + int timeOut, /* how long to wait, in mSec units */ + BYTE *respDataPtr, /* where to put response data */ + int *respDataLen, /* how much response data there is */ + BYTE *completionCode /* request status from bmc controller*/ + ) +{ + BYTE responseData[MAX_IMB_REQ_SIZE]; + ImbResponseBuffer * resp = (ImbResponseBuffer *) responseData; + DWORD respLength = sizeof( responseData ); + DWORD reqLength; + BYTE requestData[MAX_IMB_RESP_SIZE]; + ImbRequestBuffer * req = (ImbRequestBuffer *) requestData; + BOOL status; + + + req->req.rsSa = reqPtr->rsSa; + req->req.cmd = reqPtr->cmdType; + req->req.netFn = reqPtr->netFn; + req->req.rsLun = reqPtr->rsLun; + req->req.dataLength = (BYTE)reqPtr->dataLength; + +#ifndef NO_MACRO_ARGS + DEBUG("cmd=%02x, pdata=%p, datalen=%d, size=%d\n", req->req.cmd, + reqPtr->data, reqPtr->dataLength, sizeof(requestData)); +#endif + memcpy( req->req.data, reqPtr->data, reqPtr->dataLength ); + + req->flags = 0; + req->timeOut = timeOut * 1000; /* convert to uSec units */ + +#ifndef NO_MACRO_ARGS + DEBUG("%s: rsSa 0x%x cmd 0x%x netFn 0x%x rsLun 0x%x\n", __FUNCTION__, + req->req.rsSa, req->req.cmd, req->req.netFn, req->req.rsLun); +#endif + reqLength = req->req.dataLength + MIN_IMB_REQ_BUF_SIZE; + + status = DeviceIoControl( hDevice, + ioctl_sendmsg, + requestData, + reqLength, + & responseData, + sizeof( responseData ), + & respLength, + NULL + ); +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl returned status = %d\n",__FUNCTION__, status); +#endif +#ifdef DBG_IPMI + printf("%s: rsSa %x cmd %x netFn %x lun %x, status=%d, cc=%x, rlen=%d\n", + __FUNCTION__, req->req.rsSa, req->req.cmd, req->req.netFn, + req->req.rsLun, status, resp->cCode, respLength ); + dbgmsg("SendTimedImb: rsSa %x cmd %x netFn %x lun %x, status=%d, cc=%x, rlen=%d\n", + req->req.rsSa, req->req.cmd, req->req.netFn, + req->req.rsLun, status, resp->cCode, respLength ); + if (req->req.cmd == 0x34) { + _dump_buf("requestData",requestData,reqLength,0); //if DBG_IPMI + _dump_buf("responseData",responseData,respLength,0); //if DBG_IPMI + } +#endif + + if( status != TRUE ) { + DWORD error; + error = GetLastError(); + return ACCESN_ERROR; + } + if( respLength == 0 ) { + return ACCESN_ERROR; + } + + /* + * give the caller his response + */ + *completionCode = resp->cCode; + *respDataLen = 0; + + if(( respLength > 1 ) && ( respDataPtr)) + { + *respDataLen = respLength - 1; + memcpy( respDataPtr, resp->data, *respDataLen); + } + + + return ACCESN_OK; +} + + +/*//////////////////////////////////////////////////////////////////// +// open_imb +////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: open_imb +// Purpose: To open imb device +// Context: Called from each routine to make sure that open is done. +// Returns: returns 0 for Fail and 1 for Success, sets hDevice to open +// handle. +// Parameters: none +// Notes: none +*F*/ +#ifdef WIN32 +#define IMB_DEVICE_WIN "\\\\.\\Imb" +int open_imb(int fskipcmd) +{ +/* This routine will be called from all other routines before doing any + interfacing with imb driver. It will open only once. */ + IMBPREQUESTDATA requestData; + BYTE respBuffer[MAX_IMB_RESP_SIZE]; + DWORD respLength; + BYTE completionCode; + int ret; + + set_fps(); + if (hDevice1 == 0) /*INVALID_HANDLE_VALUE*/ + { + // + // Open IMB driver device + // + hDevice = CreateFile( IMB_DEVICE_WIN, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL + ); + if (hDevice == NULL || hDevice == INVALID_HANDLE_VALUE) { + if (fdebug) printf("ipmi_open_ia: error opening %s to imbdrv.sys\n", + IMB_DEVICE_WIN); + return (0); /*FALSE*/ + } + + if (fskipcmd) { + IpmiVersion = IPMI_15_VERSION; + return (1); /*TRUE*/ + } + // Detect the IPMI version for processing requests later. + // This is a crude but most reliable method to differentiate + // between old IPMI versions and the 1.0 version. If we had used the + // version field instead then we would have had to revalidate all the + // older platforms (pai 4/27/99) + requestData.cmdType = GET_DEVICE_ID; + requestData.rsSa = BMC_SA; + requestData.rsLun = BMC_LUN; + requestData.netFn = APP_NETFN ; + requestData.busType = PUBLIC_BUS; + requestData.data = NULL; + requestData.dataLength = 0; + respLength = sizeof(respBuffer); + ret = SendTimedImbpRequest ( &requestData, IMB_OPEN_TIMEOUT, + respBuffer, &respLength, &completionCode); + if ( (ret != ACCESN_OK ) || ( completionCode != 0) ) + { + if (fdebug) /*GetDeviceId failed*/ + printf("ipmi_open_ia: imbdrv request error, ret=%d ccode=%x\n", + ret,completionCode); + CloseHandle(hDevice); + return (0); /*FALSE*/ + } + hDevice1 = hDevice; + + if (respLength < (IPMI10_GET_DEVICE_ID_RESP_LENGTH-1)) + IpmiVersion = IPMI_09_VERSION; + else { + if ( respBuffer[4] == 0x01 ) + IpmiVersion = IPMI_10_VERSION; + else /* IPMI 1.5 or 2.0 */ + IpmiVersion = IPMI_15_VERSION; + } + } + return (1); /*TRUE*/ + +} /*end open_imb for Win32 */ + +#else /* LINUX, SCO_UW, etc. */ + +int open_imb(int fskipcmd) +{ +/* This routine will be called from all other routines before doing any + interfacing with imb driver. It will open only once. */ + IMBPREQUESTDATA requestData; + BYTE respBuffer[MAX_IMB_RESP_SIZE]; + int respLength; + BYTE completionCode; + + int ret_code; + + set_fps(); + + if (hDevice1 == 0) + { +#ifndef NO_MACRO_ARGS + DEBUG("%s: opening the driver, ioctl_sendmsg = %x\n", + __FUNCTION__, ioctl_sendmsg); +#endif + /* %%%%* IOCTL_IMB_SEND_MESSAGE = 0x1082 + printf("ipmi_open_ia: " + "IOCTL_IMB_SEND_MESSAGE =%x \n" "IOCTL_IMB_GET_ASYNC_MSG=%x \n" + "IOCTL_IMB_MAP_MEMORY = %x \n" "IOCTL_IMB_UNMAP_MEMORY= %x \n" + "IOCTL_IMB_SHUTDOWN_CODE=%x \n" "IOCTL_IMB_REGISTER_ASYNC_OBJ =%x \n" + "IOCTL_IMB_DEREGISTER_ASYNC_OBJ=%x \n" + "IOCTL_IMB_CHECK_EVENT =%x \n" "IOCTL_IMB_POLL_ASYNC =%x \n", + IOCTL_IMB_SEND_MESSAGE, IOCTL_IMB_GET_ASYNC_MSG, + IOCTL_IMB_MAP_MEMORY, IOCTL_IMB_UNMAP_MEMORY, IOCTL_IMB_SHUTDOWN_CODE, + IOCTL_IMB_REGISTER_ASYNC_OBJ, IOCTL_IMB_DEREGISTER_ASYNC_OBJ, + IOCTL_IMB_CHECK_EVENT , IOCTL_IMB_POLL_ASYNC); *%%%%*/ + + /*O_NDELAY flag will cause problems later when driver makes + //you wait. Hence removing it. */ + /*if ((hDevice1 = open(IMB_DEVICE,O_RDWR|O_NDELAY)) <0) */ + if ((hDevice1 = open(IMB_DEVICE,O_RDWR)) <0) + { + hDevice1 = 0; +#ifndef WIN32 + /* dont always display open errors if Linux */ + if (fdebug) +#endif + { + /*debug or not 1st time */ + printf("imbapi ipmi_open_ia: open(%s) failed, %s\n", + IMB_DEVICE,strerror(errno)); + } + return (0); + } + + if (fskipcmd) { + IpmiVersion = IPMI_15_VERSION; + return (1); /*TRUE*/ + } + /* Detect the IPMI version for processing requests later. + // This is a crude but most reliable method to differentiate + // between old IPMI versions and the 1.0 version. If we had used the + // version field instead then we would have had to revalidate all + // the older platforms (pai 4/27/99) */ + requestData.cmdType = GET_DEVICE_ID; + requestData.rsSa = BMC_SA; + requestData.rsLun = BMC_LUN; + requestData.netFn = APP_NETFN ; + requestData.busType = PUBLIC_BUS; + requestData.data = NULL; + requestData.dataLength = 0; + respLength = sizeof(respBuffer); +#ifndef NO_MACRO_ARGS + DEBUG("%s: opened driver, getting IPMI version\n", __FUNCTION__); +#endif + ret_code = SendTimedImbpRequest(&requestData, + IMB_OPEN_TIMEOUT, respBuffer, &respLength, + &completionCode); + if ( (ret_code != ACCESN_OK) || (completionCode != 0) ) + { + printf("ipmi_open_ia: SendTimedImbpRequest error. Ret = %d CC = 0x%02X\n", + ret_code, completionCode); + close(hDevice1); + hDevice1 = 0; + return (0); + } + + if (respLength < (IPMI10_GET_DEVICE_ID_RESP_LENGTH-1)) + IpmiVersion = IPMI_09_VERSION; + else { + if ( respBuffer[4] == 0x01 ) + IpmiVersion = IPMI_10_VERSION; + else /* IPMI 1.5 or 2.0 */ + IpmiVersion = IPMI_15_VERSION; + } +#ifndef NO_MACRO_ARGS + DEBUG("%s: IPMI version 0x%x\n", __FUNCTION__, IpmiVersion); +#endif + +/* +//initialise a mutex + if(mutex_init(&deviceMutex , USYNC_THREAD, NULL) != 0) + { + return(0); + } +*/ + + } + + return (1); +} /*end open_imb()*/ + +#endif + +int close_imb(void) +{ + int rc = 0; + if (hDevice1 != 0) { +#ifdef WIN32 + CloseHandle(hDevice1); +#else + rc = close(hDevice1); +#endif + } + return(rc); +} + +#ifndef LINK_LANDESK +/* If there is not a LANDESK lib, provide these 2 functions for apps + * that may be already be coded to that interface. + */ +int initIPMI(void) +{ /* for compatibility with LanDesk programs*/ + int rc; + rc = open_imb(0); /*sets hDevice1*/ + if (rc == 1) rc = 0; + else rc = -1; + return(rc); +} +int termIPMI(void) +{ /* for compatibility with LanDesk programs*/ + return(close_imb()); +} +#endif + +/*---------------------------------------------------------------------* + * ipmi_open_ia & ipmi_close_ia + *---------------------------------------------------------------------*/ +int ipmi_open_ia(char fdebugcmd) +{ + int rc = 0; + fdebug = fdebugcmd; + rc = open_imb(0); /*sets hDevice1*/ + if (rc == 1) rc = 0; + else rc = -1; + return(rc); +} + +int ipmi_close_ia(void) +{ + int rc = 0; + rc = close_imb(); + return(rc); +} + + +int ipmi_cmdraw_ia(BYTE cmd, BYTE netfn, BYTE lun, BYTE sa, BYTE bus, + BYTE *pdata, BYTE sdata, BYTE *presp, int *sresp, + BYTE *pcc, char fdebugcmd) +{ + IMBPREQUESTDATA requestData; + int status = 0; + char *imbDev; + BYTE * pc; + int sz, i; +#ifndef WIN32 + struct stat stbuf; +#endif + + if (fdebug) printf("ipmi_cmdraw_ia(%02x,%02x,%02x,%02x,bus=%02x)\n", + cmd,netfn,lun,sa,bus); +#ifdef METACOMMAND_IPMB /*++++ not used*/ + if (bus != PUBLIC_BUS) { + if (fdebug) printf("ipmi_cmdraw_ia: bus=%x, using ipmb\n",bus); + status = ipmi_cmd_ipmb(cmd,netfn,lun,sa,bus,pdata,sdata,presp,sresp, + pcc,fdebugcmd); + return(status); + } +#endif + set_fps(); + + requestData.cmdType = cmd; + requestData.rsSa = sa; + requestData.busType = bus; + requestData.netFn = netfn; + requestData.rsLun = lun; + requestData.dataLength = sdata; + requestData.data = pdata; + + if (fdebugcmd) { + sz = sizeof(IMBPREQUESTDATA); + pc = (BYTE *)&requestData.cmdType; + fprintf(fpdbg,"ipmi_cmdraw_ia: request (len=%d): ",sz); + for (i = 0; i < sz; i++) fprintf(fpdbg,"%02x ",pc[i]); + fprintf(fpdbg,"\n"); + pc = requestData.data; + sz = requestData.dataLength; + fprintf(fpdbg," req.data=%p, dlen=%d: ", pc, sz); + for (i = 0; i < sz; i++) fprintf(fpdbg,"%02x ",pc[i]); + fprintf(fpdbg,"\n"); + } + +#ifdef WIN32 + imbDev = "[imbdrv]"; + if (1) +#else + imbDev = "/dev/imb"; + if (stat(imbDev, &stbuf) == -1) { + fprintf(fperr,"ipmi_cmdraw_ia: No IMB driver found (%s)\n",imbDev); + return(ERR_NO_DRV); + } else /* imb device node is there */ +#endif + { + sz = *sresp; /* note that sresp must be pre-set */ + memset(presp, 0, sz); + for ( i =0 ; i < IMB_MAX_RETRIES; i++) + { + *sresp = sz; /* retries may need to re-init *sresp */ +#ifdef LOCAL_IPMB + if (bus != PUBLIC_BUS) + status = SendTimedIpmbpRequest(&requestData, ipmi_timeout_ia, presp, sresp, pcc); + else +#endif + status = SendTimedImbpRequest(&requestData, ipmi_timeout_ia, presp, sresp, pcc); + if((status) == 0 ) { break; } + if (fdebugcmd) // only gets here if error + fprintf(fpdbg,"ipmi_cmdraw_ia: sendImbRequest error status=%x, ccode=%x\n", + (uint)status, *pcc); + } + } + + if (fdebugcmd) { /* if debug, show both good and bad statuses */ + fprintf(fpdbg,"ipmi_cmdraw_ia: sendImbRequest status=%x, ccode=%x\n", + (uint)status, *pcc); + if (status == 0) { + BYTE * pc; int sz; + sz = *sresp; + pc = (BYTE *)presp; + fprintf(fpdbg,"ipmi_cmdraw_ia: response (len=%d): ",sz); + for (i = 0; i < sz; i++) fprintf(fpdbg,"%02x ",pc[i]); + fprintf(fpdbg,"\n"); + } + } + if (status == 1) status = -3; /*LAN_ERR_RECV_FAIL, a meaningful error*/ + return(status); +} /* end ipmi_cmdraw_ia() */ + +/*---------------------------------------------------------------------*/ +/*Used only by UW. Left here for now. IMB driver will not accept this +//ioctl. */ +ACCESN_STATUS +StartAsyncMesgPoll() +{ + + DWORD retLength; + BOOL status; + +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl cmd = %x\n",__FUNCTION__,IOCTL_IMB_POLL_ASYNC); +#endif + status = DeviceIoControl ( hDevice, + IOCTL_IMB_POLL_ASYNC, + NULL, + 0, + NULL, + 0, + & retLength, + 0 + ); + +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + + if( status == TRUE ) { + return ACCESN_OK; + } else { + return ACCESN_ERROR; + } + +} + +/*///////////////////////////////////////////////////////////////////////////// +// SendTimedI2cRequest +///////////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: SendTimedI2cRequest +// Purpose: This function sends a request to a I2C device +// Context: Used by Upper level agents (sis modules) to access dumb I2c devices +// Returns: ACCESN_OK else error status code +// Parameters: +// reqPtr +// timeOut +// respDataPtr +// respLen +// Notes: none +*F*/ + +ACCESN_STATUS +SendTimedI2cRequest ( + I2CREQUESTDATA *reqPtr, /* I2C request */ + int timeOut, /* how long to wait, mSec units */ + BYTE *respDataPtr, /* where to put response data */ + int *respDataLen, /* size of response buffer and */ + /* size of returned data */ + BYTE *completionCode /* request status from BMC */ + ) +{ + BOOL status; + BYTE responseData[MAX_IMB_RESP_SIZE]; + ImbResponseBuffer * resp = (ImbResponseBuffer *) responseData; + DWORD respLength = sizeof( responseData ); + BYTE requestData[MAX_IMB_RESP_SIZE]; + ImbRequestBuffer * req = (ImbRequestBuffer *) requestData; + + struct WriteReadI2C { /* format of a write/read I2C request */ + BYTE busType; + BYTE rsSa; + BYTE count; + BYTE data[1]; + } * wrReq = (struct WriteReadI2C *) req->req.data; + +#define MIN_WRI2C_SIZE 3 /* size of write/read request minus any data */ + + + /* + // If the Imb driver is not present return AccessFailed + */ + + req->req.rsSa = BMC_SA; + req->req.cmd = WRITE_READ_I2C; + req->req.netFn = APP_NETFN; + req->req.rsLun = BMC_LUN; + req->req.dataLength = reqPtr->dataLength + MIN_WRI2C_SIZE; + + wrReq->busType = reqPtr->busType; + wrReq->rsSa = reqPtr->rsSa; + wrReq->count = reqPtr->numberOfBytesToRead; + + memcpy( wrReq->data, reqPtr->data, reqPtr->dataLength ); + + req->flags = 0; + req->timeOut = timeOut * 1000; /* convert to uSec units */ + + status = DeviceIoControl( hDevice, + ioctl_sendmsg, + requestData, + sizeof( requestData ), + & responseData, + sizeof( responseData ), + & respLength, + NULL + ); +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + + if( status != TRUE ) { + DWORD error; + error = GetLastError(); + return ACCESN_ERROR; + } + if( respLength == 0 ) { + return ACCESN_ERROR; + } + + /* + // give the caller his response + */ + *completionCode = resp->cCode; + *respDataLen = respLength - 1; + + if(( *respDataLen ) && (respDataPtr)) + memcpy( respDataPtr, resp->data, *respDataLen); + + return ACCESN_OK; + +} + +/*This is not a API exported by the driver in stricter sense. It is +//added to support EMP functionality. Upper level software could have +//implemented this function.(pai 5/4/99) */ +/*///////////////////////////////////////////////////////////////////////////// +// SendTimedEmpMessageResponse +///////////////////////////////////////////////////////////////////////////// */ + +/*F* +// Name: SendTimedEmpMessageResponse +// Purpose: This function sends a response message to the EMP port +// Context: +// Returns: OK else error status code +// Parameters: +// +// Notes: none +*F*/ + +ACCESN_STATUS +SendTimedEmpMessageResponse ( + ImbPacket *ptr, /* pointer to the original request from EMP */ + char *responseDataBuf, + int responseDataLen, + int timeOut /* how long to wait, in mSec units */ + ) +{ + BOOL status; + BYTE responseData[MAX_IMB_RESP_SIZE]; + /*ImbResponseBuffer * resp = (ImbResponseBuffer *) responseData; */ + DWORD respLength = sizeof( responseData ); + BYTE requestData[MAX_IMB_RESP_SIZE]; + ImbRequestBuffer * req = (ImbRequestBuffer *) requestData; + int i,j; + + /*form the response packet first */ + req->req.rsSa = BMC_SA; + if (IpmiVersion == IPMI_09_VERSION) + req->req.cmd = WRITE_EMP_BUFFER; + else + req->req.cmd = SEND_MESSAGE; + req->req.netFn = APP_NETFN; + req->req.rsLun = 0; + + i = 0; + if (IpmiVersion != IPMI_09_VERSION) + req->req.data[i++] = EMP_CHANNEL; + + req->req.data[i++] = ptr->rqSa; + req->req.data[i++] = (((ptr->nfLn & 0xfc) | 0x4) | ((ptr->seqLn) & 0x3)); + if (IpmiVersion == IPMI_09_VERSION) + req->req.data[i++] = ((~(req->req.data[0] + req->req.data[1])) +1); + else + req->req.data[i++] = ((~(req->req.data[1] + req->req.data[2])) +1); + + req->req.data[i++] = BMC_SA; /*though software is responding, we have to + //provide BMCs slave address as responder + //address. */ + + req->req.data[i++] = ( (ptr->seqLn & 0xfc) | (ptr->nfLn & 0x3) ); + + req->req.data[i++] = ptr->cmd; + for ( j = 0 ; j < responseDataLen ; ++j,++i) + req->req.data[i] = responseDataBuf[j]; + + req->req.data[i] = 0; + if (IpmiVersion == IPMI_09_VERSION) + j = 0; + else + j = 1; + for ( ; j < ( i -3); ++j) + req->req.data[i] += req->req.data[j+3]; + req->req.data[i] = ~(req->req.data[i]) +1; + ++i; + req->req.dataLength = (BYTE)i; + + req->flags = 0; + req->timeOut = timeOut * 1000; /* convert to uSec units */ + + + status = DeviceIoControl( hDevice, + ioctl_sendmsg, + requestData, + sizeof(requestData), + responseData, + sizeof( responseData ), + & respLength, + NULL + ); + +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + + + if ( (status != TRUE) || (respLength != 1) || (responseData[0] != 0) ) + { + return ACCESN_ERROR; + } + return ACCESN_OK; +} + + +/*This is not a API exported by the driver in stricter sense. It is added to support +// EMP functionality. Upper level software could have implemented this function.(pai 5/4/99) */ +/*/////////////////////////////////////////////////////////////////////////// +// SendTimedEmpMessageResponse_Ex +//////////////////////////////////////////////////////////////////////////// */ + +/*F* +// Name: SendTimedEmpMessageResponse_Ex +// Purpose: This function sends a response message to the EMP port +// Context: +// Returns: OK else error status code +// Parameters: +// +// Notes: none +*F*/ + +ACCESN_STATUS +SendTimedEmpMessageResponse_Ex ( + + ImbPacket * ptr, /* pointer to the original request from EMP */ + char *responseDataBuf, + int responseDataLen, + int timeOut, /* how long to wait, in mSec units*/ + BYTE sessionHandle, /*This is introduced in IPMI1.5,this is required to be sent in + //send message command as a parameter,which is then used by BMC + //to identify the correct DPC session to send the mesage to. */ + BYTE channelNumber /*There are 3 different channels on which DPC communication goes on + //Emp - 1,Lan channel one - 6,Lan channel two(primary channel) - 7. */ + ) +{ + BOOL status; + BYTE responseData[MAX_IMB_RESP_SIZE]; + /* ImbResponseBuffer * resp = (ImbResponseBuffer *) responseData; */ + DWORD respLength = sizeof( responseData ); + BYTE requestData[MAX_IMB_RESP_SIZE]; + ImbRequestBuffer * req = (ImbRequestBuffer *) requestData; + int i,j; + + /*form the response packet first */ + req->req.rsSa = BMC_SA; + if (IpmiVersion == IPMI_09_VERSION) + req->req.cmd = WRITE_EMP_BUFFER; + else + req->req.cmd = SEND_MESSAGE; + req->req.netFn = APP_NETFN; + req->req.rsLun = 0; + + i = 0; + + /*checking for the IPMI version & then assigning the channel number for EMP + //Actually the channel number is same in both the versions.This is just to + //maintain the consistancy with the same method for LAN. + //This is the 1st byte of the SEND MESSAGE command. */ + if (IpmiVersion == IPMI_10_VERSION) + req->req.data[i++] = EMP_CHANNEL; + else if (IpmiVersion == IPMI_15_VERSION) + req->req.data[i++] = channelNumber; + + /*The second byte of data for SEND MESSAGE starts with session handle */ + req->req.data[i++] = sessionHandle; + + /*Then it is the response slave address for SEND MESSAGE. */ + req->req.data[i++] = ptr->rqSa; + + /*Then the net function + lun for SEND MESSAGE command. */ + req->req.data[i++] = (((ptr->nfLn & 0xfc) | 0x4) | ((ptr->seqLn) & 0x3)); + + /*Here the checksum is calculated.The checksum calculation starts after the channel number. + //so for the IPMI 1.5 version its a checksum of 3 bytes that is session handle,response slave + //address & netfun+lun. */ + if (IpmiVersion == IPMI_09_VERSION) + req->req.data[i++] = ((~(req->req.data[0] + req->req.data[1])) +1); + else + { + if (IpmiVersion == IPMI_10_VERSION) + req->req.data[i++] = ((~(req->req.data[1] + req->req.data[2])) +1); + else + req->req.data[i++] = ((~(req->req.data[2]+ req->req.data[3])) +1); + } + + /*This is the next byte of the message data for SEND MESSAGE command.It is the request + //slave address. */ + req->req.data[i++] = BMC_SA; /*though software is responding, we have to + //provide BMCs slave address as responder + //address. */ + + /*This is just the sequence number,which is the next byte of data for SEND MESSAGE */ + req->req.data[i++] = ( (ptr->seqLn & 0xfc) | (ptr->nfLn & 0x3) ); + + /*The next byte is the command like get software ID(00).*/ + req->req.data[i++] = ptr->cmd; + + /*after the cmd the data ,which is sent by DPC & is retrived using the get message earlier + // is sent back to DPC. */ + for ( j = 0 ; j < responseDataLen ; ++j,++i) + req->req.data[i] = responseDataBuf[j]; + + req->req.data[i] = 0; + + /*The last byte of data for SEND MESSAGE command is the check sum ,which is calculated + //from the next byte of the previous checksum that is the request slave address. */ + if (IpmiVersion == IPMI_09_VERSION) + j = 0; + else + { + if (IpmiVersion == IPMI_10_VERSION) + j = 1; + else + j = 2; + } + for ( ; j < ( i -3); ++j) + req->req.data[i] += req->req.data[j+3]; + req->req.data[i] = ~(req->req.data[i]) +1; + ++i; + req->req.dataLength = (BYTE)i; + + /*The flags & timeouts are used by the driver internally. */ + req->flags = 0; + req->timeOut = timeOut * 1000; /* convert to uSec units */ + + status = DeviceIoControl( hDevice, + ioctl_sendmsg, + requestData, + sizeof(requestData), + responseData, + sizeof( responseData ), + & respLength, + NULL + ); + + +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + + if (fdebug) { + printf("SendTimedEmp(%x,%x): status=%d cc=%x rlen=%d i=%d\n", + sessionHandle, channelNumber, + status,responseData[0],respLength,i); + _dump_buf("requestData",requestData,sizeof(requestData),0); + } + if ( (status != TRUE) || (respLength != 1) || (responseData[0] != 0) ) + { + return ACCESN_ERROR; + } + return ACCESN_OK; + + +} + +/*This is not a API exported by the driver in stricter sense. It is +//added to support EMP functionality. Upper level software could have +//implemented this function.(pai 5/4/99) */ +/*/////////////////////////////////////////////////////////////////////////// +// SendTimedLanMessageResponse +///////////////////////////////////////////////////////////////////////////// */ + +/*F* +// Name: SendTimedLanMessageResponse +// Purpose: This function sends a response message to the DPC Over Lan +// Context: +// Returns: OK else error status code +// Parameters: +// +// Notes: none +*F*/ + +ACCESN_STATUS +SendTimedLanMessageResponse( + ImbPacket *ptr, /* pointer to the original request from EMP */ + char *responseDataBuf, + int responseDataLen, + int timeOut /* how long to wait, in mSec units */ + ) +{ + BOOL status; + BYTE responseData[MAX_IMB_RESP_SIZE]; + /* ImbResponseBuffer * resp = (ImbResponseBuffer *) responseData; */ + DWORD respLength = sizeof( responseData ); + BYTE requestData[MAX_IMB_RESP_SIZE]; + ImbRequestBuffer * req = (ImbRequestBuffer *) requestData; + int i,j; + + /*form the response packet first */ + req->req.rsSa = BMC_SA; + if (IpmiVersion == IPMI_09_VERSION) + req->req.cmd = WRITE_EMP_BUFFER; + else + req->req.cmd = SEND_MESSAGE; + req->req.netFn = APP_NETFN; + + /* After discussion with firmware team (Shailendra), the lun number needs to stay at 0 + // even though the DPC over Lan firmware EPS states that the lun should be 1 for DPC + // Over Lan. - Simont (5/17/00) */ + req->req.rsLun = 0; + + i = 0; + if (IpmiVersion != IPMI_09_VERSION) + req->req.data[i++] = LAN_CHANNEL; + + req->req.data[i++] = ptr->rqSa; + req->req.data[i++] = (((ptr->nfLn & 0xfc) | 0x4) | ((ptr->seqLn) & 0x3)); + if (IpmiVersion == IPMI_09_VERSION) + req->req.data[i++] = ((~(req->req.data[0] + req->req.data[1])) +1); + else + req->req.data[i++] = ((~(req->req.data[1] + req->req.data[2])) +1); + + req->req.data[i++] = BMC_SA; /*though software is responding, we have to + //provide BMCs slave address as responder + //address. */ + + req->req.data[i++] = ( (ptr->seqLn & 0xfc) | (ptr->nfLn & 0x3) ); + + req->req.data[i++] = ptr->cmd; + for ( j = 0 ; j < responseDataLen ; ++j,++i) + req->req.data[i] = responseDataBuf[j]; + + req->req.data[i] = 0; + if (IpmiVersion == IPMI_09_VERSION) + j = 0; + else + j = 1; + for ( ; j < ( i -3); ++j) + req->req.data[i] += req->req.data[j+3]; + req->req.data[i] = ~(req->req.data[i]) +1; + ++i; + req->req.dataLength = (BYTE)i; + + req->flags = 0; + req->timeOut = timeOut * 1000; /* convert to uSec units */ + + status = DeviceIoControl( hDevice, + ioctl_sendmsg, + requestData, + sizeof(requestData), + responseData, + sizeof( responseData ), + & respLength, + NULL + ); + + if (fdebug) { + printf("SendTimedLan(): status=%d cc=%x rlen=%d i=%d\n", + status, responseData[0],respLength,i); + _dump_buf("requestData",requestData,sizeof(requestData),0); + } +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + + if ( (status != TRUE) || (respLength != 1) || (responseData[0] != 0) ) + { + return ACCESN_ERROR; + } + return ACCESN_OK; +} + + +/*This is not a API exported by the driver in stricter sense. It is +//added to support EMP functionality. Upper level software could have +//implemented this function.(pai 5/4/99) */ +/*/////////////////////////////////////////////////////////////////////////// +// SendTimedLanMessageResponse_Ex +///////////////////////////////////////////////////////////////////////////// */ + +/*F* +// Name: SendTimedLanMessageResponse_Ex +// Purpose: This function sends a response message to the DPC Over Lan +// Context: +// Returns: OK else error status code +// Parameters: +// +// Notes: none +*F*/ + +ACCESN_STATUS +SendTimedLanMessageResponse_Ex( + ImbPacket *ptr, /* pointer to the original request from EMP */ + char *responseDataBuf, + int responseDataLen, + int timeOut , /* how long to wait, in mSec units */ + BYTE sessionHandle, /*This is introduced in IPMI1.5,this is required to be sent in + //send message command as a parameter,which is then used by BMC + //to identify the correct DPC session to send the mesage to. */ + BYTE channelNumber /*There are 3 different channels on which DPC communication goes on + //Emp - 1,Lan channel one - 6,Lan channel two(primary channel) - 7. */ + ) +{ + BOOL status; + BYTE responseData[MAX_IMB_RESP_SIZE]; + /* ImbResponseBuffer * resp = (ImbResponseBuffer *) responseData; */ + DWORD respLength = sizeof( responseData ); + BYTE requestData[MAX_IMB_RESP_SIZE]; + ImbRequestBuffer * req = (ImbRequestBuffer *) requestData; + int i,j; + + /*form the response packet first */ + req->req.rsSa = BMC_SA; + if (IpmiVersion == IPMI_09_VERSION) + req->req.cmd = WRITE_EMP_BUFFER; + else + req->req.cmd = SEND_MESSAGE; + req->req.netFn = APP_NETFN; + + /* After discussion with firmware team (Shailendra), the lun number needs to stay at 0 + // even though the DPC over Lan firmware EPS states that the lun should be 1 for DPC + // Over Lan. - Simont (5/17/00) */ + req->req.rsLun = 0; + + i = 0; + + /*checking for the IPMI version & then assigning the channel number for Lan accordingly. + //This is the 1st byte of the SEND MESSAGE command. */ + if (IpmiVersion == IPMI_10_VERSION) + req->req.data[i++] = LAN_CHANNEL; + else if (IpmiVersion == IPMI_15_VERSION) + req->req.data[i++] = channelNumber; + + /*The second byte of data for SEND MESSAGE starts with session handle */ + req->req.data[i++] = sessionHandle; + + /*Then it is the response slave address for SEND MESSAGE. */ + req->req.data[i++] = ptr->rqSa; + + /*Then the net function + lun for SEND MESSAGE command. */ + req->req.data[i++] = (((ptr->nfLn & 0xfc) | 0x4) | ((ptr->seqLn) & 0x3)); + + /*Here the checksum is calculated.The checksum calculation starts after the channel number. + //so for the IPMI 1.5 version its a checksum of 3 bytes that is session handle,response slave + //address & netfun+lun. */ + if (IpmiVersion == IPMI_09_VERSION) + req->req.data[i++] = ((~(req->req.data[0] + req->req.data[1])) +1); + else + { + if (IpmiVersion == IPMI_10_VERSION) + req->req.data[i++] = ((~(req->req.data[1] + req->req.data[2])) +1); + else + req->req.data[i++] = ((~(req->req.data[2]+ req->req.data[3])) +1); + } + + /*This is the next byte of the message data for SEND MESSAGE command.It is the request + //slave address. */ + req->req.data[i++] = BMC_SA; /*though software is responding, we have to + //provide BMC's slave address as responder + //address. */ + + /*This is just the sequence number,which is the next byte of data for SEND MESSAGE */ + req->req.data[i++] = ( (ptr->seqLn & 0xfc) | (ptr->nfLn & 0x3) ); + + /*The next byte is the command like get software ID(00). */ + req->req.data[i++] = ptr->cmd; + + /*after the cmd the data ,which is sent by DPC & is retrived using the get message earlier + // is sent back to DPC. */ + for ( j = 0 ; j < responseDataLen ; ++j,++i) + req->req.data[i] = responseDataBuf[j]; + + req->req.data[i] = 0; + + /*The last byte of data for SEND MESSAGE command is the check sum ,which is calculated + //from the next byte of the previous checksum that is the request slave address. */ + if (IpmiVersion == IPMI_09_VERSION) + j = 0; + else + { + if (IpmiVersion == IPMI_10_VERSION) + j = 1; + else + j = 2; + } + for ( ; j < ( i -3); ++j) + req->req.data[i] += req->req.data[j+3]; + req->req.data[i] = ~(req->req.data[i]) +1; + ++i; + req->req.dataLength = (BYTE)i; + + /*The flags & timeouts are used by the driver internally */ + req->flags = 0; + req->timeOut = timeOut * 1000; /* convert to uSec units */ + + status = DeviceIoControl( hDevice, + ioctl_sendmsg, + requestData, + sizeof(requestData), + responseData, + sizeof( responseData ), + & respLength, + NULL + ); +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + if (fdebug) { + printf("SendTimedLan(%x,%x): status=%d cc=%x rlen=%d i=%d\n", + sessionHandle, channelNumber, + status,responseData[0],respLength,i); + if (responseData[0] != 0) /*0xcc == invalid request data*/ + { + BYTE *pb; + pb = (BYTE *)req->req.data; + printf("SendMessage data: %02x %02x %02x %02x %02x %02x %02x %02x\n", + pb[0], pb[1], pb[2], pb[3], pb[4], pb[5], pb[6], pb[7]); + _dump_buf("requestData",requestData,sizeof(requestData),0); + } + } + + if ( (status != TRUE) || (respLength != 1) || (responseData[0] != 0) ) + { + return ACCESN_ERROR; + } + return ACCESN_OK; +} + + + +/*///////////////////////////////////////////////////////////////////////// +//SendAsyncImbpRequest +/////////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: SendAsyncImbpRequest +// Purpose: This function sends a request for Asynchronous IMB implemented function +// Context: Used by Upper level agents (sis modules) to access Asynchronous IMB implemented functionality. +// Returns: OK else error status code +// Parameters: +// reqPtr Pointer to Async IMB request +// seqNo Sequence Munber +// Notes: none +*F*/ +ACCESN_STATUS +SendAsyncImbpRequest ( + IMBPREQUESTDATA *reqPtr, /* request info and data */ + BYTE * seqNo /* sequence number used in creating IMB msg */ + ) +{ + + BOOL status; + BYTE responseData[MAX_IMB_RESP_SIZE]; + ImbResponseBuffer * resp = (ImbResponseBuffer *) responseData; + DWORD respLength = sizeof( responseData ); + BYTE requestData[MAX_IMB_RESP_SIZE]; + ImbRequestBuffer * req = (ImbRequestBuffer *) requestData; + + req->req.rsSa = reqPtr->rsSa; + req->req.cmd = reqPtr->cmdType; + req->req.netFn = reqPtr->netFn; + req->req.rsLun = reqPtr->rsLun; + req->req.dataLength = (BYTE)reqPtr->dataLength; + + memcpy( req->req.data, reqPtr->data, reqPtr->dataLength ); + + req->flags = NO_RESPONSE_EXPECTED; + req->timeOut = 0; /* no timeouts for async sends */ + + status = DeviceIoControl( hDevice, + ioctl_sendmsg, + requestData, + sizeof( requestData ), + & responseData, + sizeof( responseData ), + & respLength, + NULL + ); +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + + if( status != TRUE ) { + DWORD error; + error = GetLastError(); + return ACCESN_ERROR; + } + if( respLength != 2 ) { + return ACCESN_ERROR; + } + /* + // give the caller his sequence number + */ + *seqNo = resp->data[0]; + + return ACCESN_OK; + +} + +/*/////////////////////////////////////////////////////////////////////////// +//GetAsyncImbpMessage +///////////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: GetAsyncImbpMessage +// Purpose: This function gets the next available async message with a message id +// greater than SeqNo. The message looks like an IMB packet +// and the length and Sequence number is returned +// Context: Used by Upper level agents (sis modules) to access Asynchronous IMB implemented functionality. +// Returns: OK else error status code +// Parameters: +// msgPtr Pointer to Async IMB request +// msgLen Length +// timeOut Time to wait +// seqNo Sequence Munber +// Notes: none +*F*/ + +ACCESN_STATUS +GetAsyncImbpMessage ( + ImbPacket * msgPtr, /* request info and data */ + DWORD *msgLen, /* IN - length of buffer, OUT - msg len */ + DWORD timeOut, /* how long to wait for the message */ + ImbAsyncSeq *seqNo, /* previously returned seq number */ + /* (or ASYNC_SEQ_START) */ + DWORD channelNumber + ) +{ + + BOOL status; + BYTE responseData[MAX_ASYNC_RESP_SIZE], lun, b; + ImbAsyncResponse * resp = (ImbAsyncResponse *) responseData; + DWORD respLength = sizeof( responseData ); + ImbAsyncRequest req; + BYTE *msgb; + + while(1) + { + + + if( (msgPtr == NULL) || (msgLen == NULL) || ( seqNo == NULL) ) + return ACCESN_ERROR; + + msgb = (BYTE *)msgPtr; + req.timeOut = timeOut * 1000; /* convert to uSec units */ + req.lastSeq = *seqNo; + + + status = DeviceIoControl( hDevice, + IOCTL_IMB_GET_ASYNC_MSG, + & req, + sizeof( req ), + & responseData, + sizeof( responseData ), + & respLength, + NULL + ); + +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + + if( status != TRUE ) { + DWORD error = GetLastError(); + /* + // handle "msg not available" specially. it is + // different from a random old error. + */ + switch( error ) { + case IMB_MSG_NOT_AVAILABLE: + return ACCESN_END_OF_DATA; + default: + return ACCESN_ERROR; + } + return ACCESN_ERROR; + } + if( respLength < MIN_ASYNC_RESP_SIZE ) { + return ACCESN_ERROR; + } + respLength -= MIN_ASYNC_RESP_SIZE; + + if( *msgLen < respLength ) { + return ACCESN_ERROR; + } + + + /*same code as in NT section */ + if ( IpmiVersion == IPMI_09_VERSION) + { + + switch( channelNumber) { + case IPMB_CHANNEL: + lun = IPMB_LUN; + break; + + case EMP_CHANNEL: + lun = EMP_LUN; + break; + + default: + lun = RESERVED_LUN; + break; + } + + b = (((ImbPacket *)(resp->data))->nfLn) & 0x3; + if (channelNumber != ANY_CHANNEL) { + if ( (lun == RESERVED_LUN) || + (lun != b) ) + { + *seqNo = resp->thisSeq; + continue; + } + } + + memcpy( msgPtr, resp->data, respLength ); + *msgLen = respLength; + /* Hack to return actual lun */ + if (channelNumber == ANY_CHANNEL) + msgb[respLength] = b; + } + else + { + /* it is a 1.0 or above version */ + + b = resp->data[0]; + if ((channelNumber != ANY_CHANNEL) && + (channelNumber != b)) + { + *seqNo = resp->thisSeq; + continue; + } + + memcpy(msgPtr, &(resp->data[1]), respLength-1); + *msgLen = respLength-1; + /* Hack to return actual channel */ + if (channelNumber == ANY_CHANNEL) + msgb[respLength-1] = b; + + } + + /* + // give the caller his sequence number + */ + *seqNo = resp->thisSeq; + + return ACCESN_OK; + + } /*while (1) */ +} + + +/*/////////////////////////////////////////////////////////////////////////// +//GetAsyncImbpMessage_Ex +///////////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: GetAsyncImbpMessage_Ex +// Purpose: This function gets the next available async message with a message id +// greater than SeqNo. The message looks like an IMB packet +// and the length and Sequence number is returned +// Context: Used by Upper level agents (sis modules) to access Asynchronous IMB implemented functionality. +// Returns: OK else error status code +// Parameters: +// msgPtr Pointer to Async IMB request +// msgLen Length +// timeOut Time to wait +// seqNo Sequence Munber +// Notes: none +*F*/ + +ACCESN_STATUS +GetAsyncImbpMessage_Ex ( + ImbPacket * msgPtr, /* request info and data */ + DWORD *msgLen, /* IN - length of buffer, OUT - msg len */ + DWORD timeOut, /* how long to wait for the message */ + ImbAsyncSeq *seqNo, /* previously returned seq number */ + /* (or ASYNC_SEQ_START) */ + DWORD channelNumber, + BYTE * sessionHandle, + BYTE * privilege + ) +{ + + BOOL status; + BYTE responseData[MAX_ASYNC_RESP_SIZE], lun, b; + ImbAsyncResponse * resp = (ImbAsyncResponse *) responseData; + DWORD respLength = sizeof( responseData ); + ImbAsyncRequest req; + BYTE *msgb; + + while(1) + { + + + if( (msgPtr == NULL) || (msgLen == NULL) || ( seqNo == NULL) ) + return ACCESN_ERROR; + + msgb = (BYTE *)msgPtr; + req.timeOut = timeOut * 1000; /* convert to uSec units */ + req.lastSeq = *seqNo; + + + status = DeviceIoControl( hDevice, + IOCTL_IMB_GET_ASYNC_MSG, + & req, + sizeof( req ), + & responseData, + sizeof( responseData ), + & respLength, + NULL + ); + +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + + if( status != TRUE ) { + DWORD error = GetLastError(); + /* + // handle "msg not available" specially. it is + // different from a random old error. + */ + switch( error ) { + case IMB_MSG_NOT_AVAILABLE: + return ACCESN_END_OF_DATA; + default: + return ACCESN_ERROR; + } + return ACCESN_ERROR; + } + if( respLength < MIN_ASYNC_RESP_SIZE ) { + return ACCESN_ERROR; + } + respLength -= MIN_ASYNC_RESP_SIZE; + + if( *msgLen < respLength ) { + return ACCESN_ERROR; + } + + + /*same code as in NT section */ + if ( IpmiVersion == IPMI_09_VERSION) + { + + switch( channelNumber) { + case IPMB_CHANNEL: + lun = IPMB_LUN; + break; + + case EMP_CHANNEL: + lun = EMP_LUN; + break; + + default: + lun = RESERVED_LUN; + break; + } + + b = ((((ImbPacket *)(resp->data))->nfLn) & 0x3); + if (channelNumber != ANY_CHANNEL) { + if ( (lun == RESERVED_LUN) || + (lun != b) ) + { + *seqNo = resp->thisSeq; + continue; + } + } + + memcpy( msgPtr, resp->data, respLength ); + *msgLen = respLength; + /* Hack to return actual lun */ + if (channelNumber == ANY_CHANNEL) + msgb[respLength] = b; + + } + else + { + if((sessionHandle ==NULL) || (privilege ==NULL)) + return ACCESN_ERROR; + + /*With the new IPMI version the get message command returns the + //channel number along with the privileges.The 1st 4 bits of the + //second byte of the response data for get message command represent + //the channel number & the last 4 bits are the privileges. */ + *privilege = (resp->data[0] & 0xf0)>> 4; + +#ifndef NO_MACRO_ARGS + DEBUG("GetAsy: chan=%x chan_parm=%x\n",resp->data[0],channelNumber); +#endif + b = (resp->data[0] & 0x0f); + if ((channelNumber != ANY_CHANNEL) && + (channelNumber != b) ) + { + *seqNo = resp->thisSeq; + continue; + } + + + /*The get message command according to IPMI 1.5 spec now even + //returns the session handle.This is required to be captured + //as it is required as request data for send message command. */ + *sessionHandle = resp->data[1]; + memcpy( msgPtr, &(resp->data[2]), respLength-1 ); + *msgLen = respLength-1; + + /* Hack to return actual channel */ + if (channelNumber == ANY_CHANNEL) + msgb[respLength-1] = b; + + } + + /* + // give the caller his sequence number + */ + *seqNo = resp->thisSeq; + + return ACCESN_OK; + + } /*while (1) */ +} + + + +/*////////////////////////////////////////////////////////////////////////////// +//IsAsyncMessageAvailable +///////////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: IsMessageAvailable +// Purpose: This function waits for an Async Message +// +// Context: Used by Upper level agents access Asynchronous IMB based +// messages +// Returns: OK else error status code +// Parameters: +// eventId +// +// Notes: This call will block the calling thread if no Async events are +// are available in the queue. +// +*F*/ +ACCESN_STATUS +IsAsyncMessageAvailable (HandleType eventId ) +{ + int dummy; + int respLength = 0; + BOOL status; + + /* confirm that app is not using a bad Id */ + + + if ( AsyncEventHandle != eventId) { +#ifdef LINUX + printf("Invalid AsyncHandle %x!=%x\n",AsyncEventHandle,eventId); +#endif + return ACCESN_ERROR; + } + + dummy = 0; + status = DeviceIoControl(hDevice, + IOCTL_IMB_CHECK_EVENT, + &AsyncEventHandle, + sizeof(HandleType), + &dummy, + sizeof(int), + (LPDWORD) & respLength, + NULL + ); + // if (fdebug) + // printf("IsAsyncMessageAvail: status=%d rlen=%d dummy=%x\n", + // status, respLength, dummy); +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + + if( status != TRUE ) + return ACCESN_ERROR; + + + return ACCESN_OK; +} + + +/*I have retained this commented code because later we may want to use +//DPC message specific Processing (pai 11/21) */ + +#ifdef NOT_COMPILED_BUT_LEFT_HERE_FOR_NOW + +/*////////////////////////////////////////////////////////////////////////////// +//GetAsyncDpcMessage +///////////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: GetAsyncDpcMessage +// Purpose: This function gets the next available async message from +// the DPC client. +// +// Context: Used by Upper level agents access Asynchronous IMB based +// messages sent by the DPC client. +// Returns: OK else error status code +// Parameters: +// msgPtr Pointer to Async IMB request +// msgLen Length +// timeOut Time to wait +// seqNo Sequence Munber +// Notes: This call will block the calling thread if no Async events are +// are available in the queue. +// +*F*/ + +ACCESN_STATUS +GetAsyncDpcMessage ( + ImbPacket * msgPtr, /* request info and data */ + DWORD * msgLen, /* IN - length of buffer, OUT - msg len */ + DWORD timeOut, /* how long to wait for the message */ + ImbAsyncSeq * seqNo, /* previously returned seq number (or ASYNC_SEQ_START) */ + ) +{ + BOOL status; + BYTE responseData[MAX_ASYNC_RESP_SIZE]; + ImbAsyncResponse * resp = (ImbAsyncResponse *) responseData; + DWORD respLength = sizeof( responseData ); + ImbAsyncRequest req; + + if( msgPtr == NULL || msgLen == NULL || seqNo == NULL ) + return ACCESN_ERROR; + + req.lastSeq = *seqNo; + + + hEvt = CreateEvent (NULL, TRUE, FALSE, NULL) ; + if (!hEvt) { + return ACCESN_ERROR; + } + + status = DeviceIoControl( hDevice, + IOCTL_IMB_GET_DPC_MSG, + & req, + sizeof( req ), + & responseData, + sizeof( responseData ), + & respLength, + &ovl + ); + + if( status != TRUE ) { + DWORD error = GetLastError(); + /* + // handle "msg not available" specially. it is different from + // a random old error. + // + */ + if (!status) + { + switch (error ) + { + case ERROR_IO_PENDING: + + WaitForSingleObject (hEvt, INFINITE) ; + ResetEvent (hEvt) ; + break; + + case IMB_MSG_NOT_AVAILABLE: + + CloseHandle(hEvt); + return ACCESN_END_OF_DATA; + + default: + CloseHandle(hEvt); + return ACCESN_ERROR; + + } + } + + + + if ( + ( GetOverlappedResult(hDevice, + &ovl, + (LPDWORD)&respLength, + TRUE + ) == 0 ) || (respLength <= 0) + ) + + { + + CloseHandle(hEvt); + return ACCESN_ERROR; + + } + + + } + + if( respLength < MIN_ASYNC_RESP_SIZE ) { + CloseHandle(hEvt); + return ACCESN_ERROR; + } + + respLength -= MIN_ASYNC_RESP_SIZE; + + if( *msgLen < respLength ) { + + /* The following code should have been just return ACCESN_out_of_range */ + CloseHandle(hEvt); + return ACCESN_ERROR; + } + + memcpy( msgPtr, resp->data, respLength ); + + *msgLen = respLength; + /* + // give the caller his sequence number + */ + *seqNo = resp->thisSeq; + + CloseHandle(hEvt); + + + return ACCESN_OK; + +} +#endif /*NOT_COMPILED_BUT_LEFT_HERE_FOR_NOW*/ + + + +/*///////////////////////////////////////////////////////////////////////////// +//RegisterForImbAsyncMessageNotification +///////////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: RegisterForImbAsyncMessageNotification +// Purpose: This function Registers the calling application +// for Asynchronous notification when a sms message +// is available with the IMB driver. +// +// Context: Used by Upper level agents to know that an async +// SMS message is available with the driver. +// Returns: OK else error status code +// Parameters: +// handleId pointer to the registration handle +// +// Notes: The calling application should use the returned handle to +// get the Async messages.. +*F*/ +ACCESN_STATUS +RegisterForImbAsyncMessageNotification (HandleType *handleId) + +{ + BOOL status; + DWORD respLength ; + int dummy; + + /*allow only one app to register */ + + if( (handleId == NULL ) || (AsyncEventHandle) ) + return ACCESN_ERROR; + + + status = DeviceIoControl(hDevice, + IOCTL_IMB_REGISTER_ASYNC_OBJ, + &dummy, + sizeof( int ), + &AsyncEventHandle, + sizeof(HandleType), + (LPDWORD) & respLength, + NULL + ); +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + + if( (respLength != sizeof(int)) || (status != TRUE )) { + if (fdebug) { + printf("RegisterForImbAsync error status=%d, len=%d sizeint=%d\n", status, respLength, sizeof(int)); + if( respLength != sizeof(int)) printf("Async len err\n"); + if( status != TRUE) printf("Async status err\n"); + } + return ACCESN_ERROR; + } + + *handleId = AsyncEventHandle; + +#ifndef NO_MACRO_ARGS + DEBUG("handleId = %x AsyncEventHandle %x\n", *handleId, AsyncEventHandle); +#endif + return ACCESN_OK; +} + + + + + +/*///////////////////////////////////////////////////////////////////////////// +//UnRegisterForImbAsyncMessageNotification +///////////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: UnRegisterForImbAsyncMessageNotification +// Purpose: This function un-registers the calling application +// for Asynchronous notification when a sms message +// is available with the IMB driver. +// +// Context: Used by Upper level agents to un-register +// for async. notification of sms messages +// Returns: OK else error status code +// Parameters: +// handleId pointer to the registration handle +// iFlag value used to determine where this function was called from +// _it is used currently on in NetWare environment_ +// +// Notes: +*F*/ +ACCESN_STATUS +UnRegisterForImbAsyncMessageNotification (HandleType handleId, int iFlag) + +{ + BOOL status; + DWORD respLength ; + int dummy; + + iFlag = iFlag; /* to keep compiler happy We are not using this flag*/ + + if ( AsyncEventHandle != handleId) + return ACCESN_ERROR; + + status = DeviceIoControl(hDevice, + IOCTL_IMB_DEREGISTER_ASYNC_OBJ, + &AsyncEventHandle, + sizeof(HandleType), + &dummy, + (DWORD)sizeof(int ), + (LPDWORD) & respLength, + NULL + ); +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + + if( status != TRUE ) + return ACCESN_ERROR; + + return ACCESN_OK; +} + + +/*/////////////////////////////////////////////////////////////////////////// +// SetShutDownCode +///////////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: SetShutDownCode +// Purpose: To set the shutdown action code +// Context: Called by the System Control Subsystem +// Returns: none +// Parameters: +// code shutdown action code which can be either +// SD_NO_ACTION, SD_RESET, SD_POWER_OFF as defined in imb_if.h +*F*/ + +ACCESN_STATUS +SetShutDownCode ( + int delayTime, /* time to delay in 100ms units */ + int code /* what to do when time expires */ + ) +{ + DWORD retLength; + BOOL status; + ShutdownCmdBuffer cmd; + + /* + // If Imb driver is not present return AccessFailed + */ + if(hDevice == INVALID_HANDLE_VALUE) + return ACCESN_ERROR; + + cmd.code = code; + cmd.delayTime = delayTime; + + status = DeviceIoControl( hDevice, + IOCTL_IMB_SHUTDOWN_CODE, + & cmd, + sizeof( cmd ), + NULL, + 0, + & retLength, + NULL + ); +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + + if(status == TRUE) + return ACCESN_OK; + else + return ACCESN_ERROR; +} + +#ifdef IMB_MEMORY +/*///////////////////////////////////////////////////////////////////////// +// MapPhysicalMemory +/////////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: MapPhysicalMemory +// Purpose: This function maps specified range of physical memory in calling +// pocesse's address space +// Context: Used by Upper level agents (sis modules) to access +// system physical memory +// Returns: ACCESN_OK else error status code +// Parameters: +// +// startAddress starting physical address of the memory to be mapped +// addressLength length of the physical memory to be mapped +// virtualAddress pointer to the mapped virtual address +// Notes: none +*F*/ +/*/////////////////////////////////////////////////////////////////////////// +// UnmapPhysicalMemory +//////////////////////////////////////////////////////////////////////////// */ +/*F* +// Name: UnMapPhysicalMemory +// Purpose: This function unmaps the previously mapped physical memory +// Context: Used by Upper level agents (sis modules) +// Returns: ACCESN_OK else error status code +// Parameters: +// +// addressLength length of the physical memory to be mapped +// virtualAddress pointer to the mapped virtual address +// Notes: none +*F*/ +#ifdef WIN32 +ACCESN_STATUS +MapPhysicalMemory ( + int startAddress, // physical address to map in + int addressLength, // how much to map + int *virtualAddress // where it got mapped to + ) +{ + DWORD retLength; + BOOL status; + PHYSICAL_MEMORY_INFO pmi; + + if ( startAddress == (int) NULL || addressLength <= 0 ) + return ACCESN_OUT_OF_RANGE; + + pmi.InterfaceType = Internal; + pmi.BusNumber = 0; + pmi.BusAddress.HighPart = (LONG)0x0; + pmi.BusAddress.LowPart = (LONG)startAddress; + pmi.AddressSpace = (LONG) 0; + pmi.Length = addressLength; + + status = DeviceIoControl ( hDevice, + IOCTL_IMB_MAP_MEMORY, + & pmi, + sizeof(PHYSICAL_MEMORY_INFO), + virtualAddress, + sizeof(PVOID), + & retLength, + 0 + ); + if( status == TRUE ) { + return ACCESN_OK; + } else { + return ACCESN_ERROR; + } +} + +ACCESN_STATUS +UnmapPhysicalMemory ( + int virtualAddress, // what memory to unmap + int Length ) +{ + DWORD retLength; + BOOL status; + + status = DeviceIoControl ( hDevice, + IOCTL_IMB_UNMAP_MEMORY, + & virtualAddress, + sizeof(PVOID), + NULL, + 0, + & retLength, + 0 + ); + + if( status == TRUE ) { + return ACCESN_OK; + } else { + return ACCESN_ERROR; + } +} + +#else /*Linux, SCO, UNIX, etc.*/ + +ACCESN_STATUS +MapPhysicalMemory(int startAddress,int addressLength, int *virtualAddress ) +{ + int fd, i; + unsigned int length = addressLength; + off_t startpAddress = (off_t)startAddress; + unsigned int diff; + caddr_t startvAddress; + + if ((startAddress == (int) NULL) || (addressLength <= 0)) + return ACCESN_ERROR; + + if ( (fd = open("/dev/mem", O_RDONLY)) < 0) { + char buf[128]; + + sprintf(buf,"%s %s: open(%s) failed", + __FILE__,__FUNCTION__,"/dev/mem"); + perror(buf); + return ACCESN_ERROR ; + } + + /* aliging the offset to a page boundary and adjusting the length */ + diff = (int)startpAddress % PAGESIZE; + startpAddress -= diff; + length += diff; + + if ( (startvAddress = mmap( (caddr_t)0, + length, + PROT_READ, + MAP_SHARED, + fd, + startpAddress + ) ) == (caddr_t)-1) + { + char buf[128]; + + sprintf(buf,"%s %s: mmap failed", __FILE__,__FUNCTION__); + perror(buf); + close(fd); + return ACCESN_ERROR; + } +#ifndef NO_MACRO_ARGS + DEBUG("%s: mmap of 0x%x success\n",__FUNCTION__,startpAddress); +#endif +#ifdef LINUX_DEBUG_MAX +/* dont want this memory dump for normal level of debugging. +// So, I have put it under a stronger debug symbol. mahendra */ + + for(i=0; i < length; i++) + { + printf("0x%x ", (startvAddress[i])); + if(isascii(startvAddress[i])) { + printf("%c ", (startvAddress[i])); + } + } +#endif /*LINUX_DEBUG_MAX */ + + *virtualAddress = (int)(startvAddress + diff); + return ACCESN_OK; +} + +ACCESN_STATUS +UnmapPhysicalMemory( int virtualAddress, int Length ) +{ + unsigned int diff = 0; + + /* page align the virtual address and adjust length accordingly */ + diff = ((unsigned int) virtualAddress) % PAGESIZE; + virtualAddress -= diff; + Length += diff; +#ifndef NO_MACRO_ARGS + DEBUG("%s: calling munmap(0x%x,%d)\n",__FUNCTION__,virtualAddress,Length); +#endif + + if(munmap((caddr_t)virtualAddress, Length) != 0) + { + char buf[128]; + + sprintf(buf,"%s %s: munmap failed", __FILE__,__FUNCTION__); + perror(buf); + return ACCESN_ERROR; + + } +#ifndef NO_MACRO_ARGS + DEBUG("%s: munmap(0x%x,%d) success\n",__FUNCTION__,virtualAddress,Length); +#endif + + return ACCESN_OK; +} +#endif /*unix*/ + +#endif /*IMB_MEMORY*/ + + +/*///////////////////////////////////////////////////////////////////////////// +// GetIpmiVersion +//////////////////////////////////////////////////////////////////////////// */ + +/*F* +// Name: GetIpmiVersion +// Purpose: This function returns current IPMI version +// Context: +// Returns: IPMI version +// Parameters: +// reqPtr +// timeOut +// respDataPtr +// respLen +// Notes: svuppula +*F*/ +BYTE GetIpmiVersion() +{ + return ((BYTE)IpmiVersion); +} + +#ifdef IMBDLL +/* Inlude this routine if building WIN32 imbapi.dll */ +BOOL WINAPI DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved) +{ + switch(ulReason) + { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + break; + case DLL_PROCESS_DETACH: + case DLL_THREAD_DETACH: + break; + default: + return FALSE; + } + return TRUE; +} +#endif + +#endif +/*end of imbapi.c*/ diff --git a/util/ipicmg.c b/util/ipicmg.c new file mode 100644 index 0000000..c549151 --- /dev/null +++ b/util/ipicmg.c @@ -0,0 +1,1911 @@ +/* + * ipicmg.c + * + * This module handles PICMG extended IPMI commands. + * + * Change History: + * 06/03/2010 ARCress - new, included in source tree + * 08/15/2011 ARCress - updated with PICMG 2.3 + * + *---------------------------------------------------------------------- + * Copyright (c) 2010 Kontron. All right 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 Kontron, 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. + * THE COPYRIGHT HOLDER 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 THE + * COPYRIGHT HOLDER 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 COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + *---------------------------------------------------------------------- + */ +#ifdef WIN32 +#include +#include +#include +#include +#include "getopt.h" +#else +#include +#include +#include +#if defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include +#else +#include +#endif +#endif +#include "ipmicmd.h" +#include "ipicmg.h" + +/* Misc PICMG defines */ +#define PICMG_EXTENSION_ATCA_MAJOR_VERSION 2 +#define PICMG_EXTENSION_AMC0_MAJOR_VERSION 4 +#define PICMG_EXTENSION_UTCA_MAJOR_VERSION 5 + + +#define PICMG_EKEY_MODE_QUERY 0 +#define PICMG_EKEY_MODE_PRINT_ALL 1 +#define PICMG_EKEY_MODE_PRINT_ENABLED 2 +#define PICMG_EKEY_MODE_PRINT_DISABLED 3 + +#define PICMG_EKEY_MAX_CHANNEL 16 +#define PICMG_EKEY_MAX_FABRIC_CHANNEL 15 +#define PICMG_EKEY_MAX_INTERFACE 3 + +#define PICMG_EKEY_AMC_MAX_CHANNEL 16 +#define PICMG_EKEY_AMC_MAX_DEVICE 15 /* 4 bits */ + +/* Global data */ +static char * progname = "ipicmg"; +static char * progver = "2.93"; +static char fdebug = 0; +static char fset_mc = 0; +static uint8_t g_bus = PUBLIC_BUS; +static uint8_t g_sa = BMC_SA; +static uint8_t g_lun = BMC_LUN; +static uint8_t g_addrtype = ADDR_SMI; +static uint8_t g_fruid = 0; +static unsigned char PicmgExtMajorVersion; + +typedef enum picmg_bused_resource_mode { + PICMG_BUSED_RESOURCE_SUMMARY, +} t_picmg_bused_resource_mode ; + + +typedef enum picmg_card_type { + PICMG_CARD_TYPE_CPCI, + PICMG_CARD_TYPE_ATCA, + PICMG_CARD_TYPE_AMC, + PICMG_CARD_TYPE_RESERVED +} t_picmg_card_type ; + +/* This is the version of the PICMG Extenstion */ +static t_picmg_card_type PicmgCardType = PICMG_CARD_TYPE_RESERVED; + +const struct valstr picmg_frucontrol_vals[] = { + { 0, "Cold Reset" }, + { 1, "Warm Reset" }, + { 2, "Graceful Reboot" }, + { 3, "Issue Diagnostic Interrupt" }, + { 4, "Quiesce" }, + { 5, NULL }, +}; + +const struct valstr picmg_clk_family_vals[] = { + { 0x00, "Unspecified" }, + { 0x01, "SONET/SDH/PDH" }, + { 0x02, "Reserved for PCI Express" }, + { 0x03, "Reserved" }, /* from 03h to C8h */ + { 0xC9, "Vendor defined clock family" }, /* from C9h to FFh */ + { 0x00, NULL }, +}; + +const struct oemvalstr picmg_clk_accuracy_vals[] = { + { 0x01, 10, "PRS" }, + { 0x01, 20, "STU" }, + { 0x01, 30, "ST2" }, + { 0x01, 40, "TNC" }, + { 0x01, 50, "ST3E" }, + { 0x01, 60, "ST3" }, + { 0x01, 70, "SMC" }, + { 0x01, 80, "ST4" }, + { 0x01, 90, "DUS" }, + { 0x02, 0xE0, "PCI Express Generation 2" }, + { 0x02, 0xF0, "PCI Express Generation 1" }, + { 0xffffff, 0x00, NULL } +}; + +const struct oemvalstr picmg_clk_resource_vals[] = { + { 0x0, 0, "On-Carrier Device 0" }, + { 0x0, 1, "On-Carrier Device 1" }, + { 0x1, 1, "AMC Site 1 - A1" }, + { 0x1, 2, "AMC Site 1 - A2" }, + { 0x1, 3, "AMC Site 1 - A3" }, + { 0x1, 4, "AMC Site 1 - A4" }, + { 0x1, 5, "AMC Site 1 - B1" }, + { 0x1, 6, "AMC Site 1 - B2" }, + { 0x1, 7, "AMC Site 1 - B3" }, + { 0x1, 8, "AMC Site 1 - B4" }, + { 0x2, 0, "ATCA Backplane" }, + { 0xffffff, 0x00, NULL } +}; + +const struct oemvalstr picmg_clk_id_vals[] = { + { 0x0, 0, "Clock 0" }, + { 0x0, 1, "Clock 1" }, + { 0x0, 2, "Clock 2" }, + { 0x0, 3, "Clock 3" }, + { 0x0, 4, "Clock 4" }, + { 0x0, 5, "Clock 5" }, + { 0x0, 6, "Clock 6" }, + { 0x0, 7, "Clock 7" }, + { 0x0, 8, "Clock 8" }, + { 0x0, 9, "Clock 9" }, + { 0x0, 10, "Clock 10" }, + { 0x0, 11, "Clock 11" }, + { 0x0, 12, "Clock 12" }, + { 0x0, 13, "Clock 13" }, + { 0x0, 14, "Clock 14" }, + { 0x0, 15, "Clock 15" }, + { 0x1, 1, "TCLKA" }, + { 0x1, 2, "TCLKB" }, + { 0x1, 3, "TCLKC" }, + { 0x1, 4, "TCLKD" }, + { 0x1, 5, "FLCKA" }, + { 0x2, 1, "CLK1A" }, + { 0x2, 2, "CLK1A" }, + { 0x2, 3, "CLK1A" }, + { 0x2, 4, "CLK1A" }, + { 0x2, 5, "CLK1A" }, + { 0x2, 6, "CLK1A" }, + { 0x2, 7, "CLK1A" }, + { 0x2, 8, "CLK1A" }, + { 0x2, 9, "CLK1A" }, + { 0xffffff, 0x00, NULL } +}; + +const struct valstr picmg_busres_id_vals[] = { + { 0x0, "Metallic Test Bus pair #1" }, + { 0x1, "Metallic Test Bus pair #2" }, + { 0x2, "Synch clock group 1 (CLK1)" }, + { 0x3, "Synch clock group 2 (CLK2)" }, + { 0x4, "Synch clock group 3 (CLK3)" }, + { 0x5, NULL } +}; +const struct valstr picmg_busres_board_cmd_vals[] = { + { 0x0, "Query" }, + { 0x1, "Release" }, + { 0x2, "Force" }, + { 0x3, "Bus Free" }, + { 0x4, NULL } +}; + +const struct valstr picmg_busres_shmc_cmd_vals[] = { + { 0x0, "Request" }, + { 0x1, "Relinquish" }, + { 0x2, "Notify" }, + { 0x3, NULL } +}; + +const struct oemvalstr picmg_busres_board_status_vals[] = { + { 0x0, 0x0, "In control" }, + { 0x0, 0x1, "No control" }, + { 0x1, 0x0, "Ack" }, + { 0x1, 0x1, "Refused" }, + { 0x1, 0x2, "No control" }, + { 0x2, 0x0, "Ack" }, + { 0x2, 0x1, "No control" }, + { 0x3, 0x0, "Accept" }, + { 0x3, 0x1, "Not Needed" }, + { 0xffffff, 0x00, NULL } +}; + +const struct oemvalstr picmg_busres_shmc_status_vals[] = { + { 0x0, 0x0, "Grant" }, + { 0x0, 0x1, "Busy" }, + { 0x0, 0x2, "Defer" }, + { 0x0, 0x3, "Deny" }, + + { 0x1, 0x0, "Ack" }, + { 0x1, 0x1, "Error" }, + + { 0x2, 0x0, "Ack" }, + { 0x2, 0x1, "Error" }, + { 0x2, 0x2, "Deny" }, + + { 0xffffff, 0x00, NULL } +}; + +void +ipmi_picmg_help (void) +{ + printf(" properties - get PICMG properties\n"); + printf(" frucontrol - FRU control\n"); + printf(" addrinfo - get address information\n"); + printf(" activate - activate a FRU\n"); + printf(" deactivate - deactivate a FRU\n"); + printf(" policy get - get the FRU activation policy\n"); + printf(" policy set - set the FRU activation policy\n"); + printf(" portstate get - get port state \n"); + printf(" portstate getdenied - get all denied[disabled] port description\n"); + printf(" portstate getgranted - get all granted[enabled] port description\n"); + printf(" portstate getall - get all port state description\n"); + printf(" portstate set - set port state \n"); + printf(" amcportstate get - get port state \n"); + printf(" amcportstate set - set port state \n"); + printf(" led prop - get led properties\n"); + printf(" led cap - get led color capabilities\n"); + printf(" led get - get led state\n"); + printf(" led set - set led state\n"); + printf(" power get - get power level info\n"); + printf(" power set - set power level\n"); + printf(" clk get - get clk state\n"); + printf(" clk getdenied - get all(up to 16) denied[disabled] clock descriptions\n"); + printf(" clk getgranted - get all(up to 16) granted[enabled] clock descriptions\n"); + printf(" clk getall - get all(up to 16) clock descriptions\n"); + printf(" clk set - set clk state\n"); + printf(" busres summary - display brief bused resource status info \n"); +} + +struct sAmcAddrMap { + unsigned char ipmbLAddr; + char* amcBayId; + unsigned char siteNum; +} amcAddrMap[] = { + {0xFF, "reserved", 0}, + {0x72, "A1" , 1}, + {0x74, "A2" , 2}, + {0x76, "A3" , 3}, + {0x78, "A4" , 4}, + {0x7A, "B1" , 5}, + {0x7C, "B2" , 6}, + {0x7E, "B3" , 7}, + {0x80, "B4" , 8}, + {0x82, "reserved", 0}, + {0x84, "reserved", 0}, + {0x86, "reserved", 0}, + {0x88, "reserved", 0}, +}; + +int +ipmi_picmg_getaddr(void * intf, int argc, char ** argv) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + unsigned char msg_data[5]; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = PICMG_GET_ADDRESS_INFO_CMD; + req.msg.data = msg_data; + req.msg.data_len = 2; + msg_data[0] = 0; /* picmg identifier */ + msg_data[1] = 0; /* default fru id */ + + if(argc > 0) { + msg_data[1] = (uint8_t)strtoul(argv[0], NULL,0); /* FRU ID */ + } + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Error getting address information CC: 0x%02x\n", rv); + return rv; + } + + printf("Hardware Address : 0x%02x\n", rsp[1]); + printf("IPMB-0 Address : 0x%02x\n", rsp[2]); + printf("FRU ID : 0x%02x\n", rsp[4]); + printf("Site ID : 0x%02x\n", rsp[5]); + + printf("Site Type : "); + switch (rsp[6]) { + case PICMG_ATCA_BOARD: + printf("ATCA board\n"); + break; + case PICMG_POWER_ENTRY: + printf("Power Entry Module\n"); + break; + case PICMG_SHELF_FRU: + printf("Shelf FRU\n"); + break; + case PICMG_DEDICATED_SHMC: + printf("Dedicated Shelf Manager\n"); + break; + case PICMG_FAN_TRAY: + printf("Fan Tray\n"); + break; + case PICMG_FAN_FILTER_TRAY: + printf("Fan Filter Tray\n"); + break; + case PICMG_ALARM: + printf("Alarm module\n"); + break; + case PICMG_AMC: + printf("AMC"); + printf(" -> IPMB-L Address: 0x%02x\n", amcAddrMap[rsp[5]].ipmbLAddr); + break; + case PICMG_PMC: + printf("PMC\n"); + break; + case PICMG_RTM: + printf("RTM\n"); + break; + default: + if (rsp[6] >= 0xc0 && rsp[6] <= 0xcf) { + printf("OEM\n"); + } else { + printf("unknown\n"); + } + } + + return 0; +} + +int +ipmi_picmg_properties(void * intf, int show ) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + unsigned char PicmgExtMajorVersion; + struct ipmi_rq req; + unsigned char msg_data; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = PICMG_GET_PICMG_PROPERTIES_CMD; + req.msg.data = &msg_data; + req.msg.data_len = 1; + msg_data = 0; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Error %d getting picmg properties\n", rv); + return rv; + } + + if( show ) + { + printf("PICMG identifier : 0x%02x\n", rsp[0]); + printf("PICMG Ext. Version : %i.%i\n", rsp[1]&0x0f, + (rsp[1]&0xf0) >> 4); + printf("Max FRU Device ID : 0x%02x\n", rsp[2]); + printf("FRU Device ID : 0x%02x\n", rsp[3]); + } + + /* We cache the major extension version ... + to know how to format some commands */ + PicmgExtMajorVersion = rsp[1]&0x0f; + + if( PicmgExtMajorVersion == PICMG_CPCI_MAJOR_VERSION ) { + PicmgCardType = PICMG_CARD_TYPE_CPCI; + } + else if( PicmgExtMajorVersion == PICMG_ATCA_MAJOR_VERSION) { + PicmgCardType = PICMG_CARD_TYPE_ATCA; + } + else if( PicmgExtMajorVersion == PICMG_AMC_MAJOR_VERSION) { + PicmgCardType = PICMG_CARD_TYPE_AMC; + } + + return 0; +} + + + +#define PICMG_FRU_DEACTIVATE (unsigned char) 0x00 +#define PICMG_FRU_ACTIVATE (unsigned char) 0x01 + +int +ipmi_picmg_fru_activation(void * intf, int argc, char ** argv, unsigned char state) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + + struct picmg_set_fru_activation_cmd cmd; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = PICMG_FRU_ACTIVATION_CMD; + req.msg.data = (unsigned char*) &cmd; + req.msg.data_len = 3; + + cmd.picmg_id = 0; /* PICMG identifier */ + cmd.fru_id = atob(argv[0]); /* FRU ID */ + cmd.fru_state = state; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + printf("Error %d on activation/deactivation of FRU\n",rv); + return rv; + } + if (rsp[0] != 0x00) { + printf("Error, invalid response\n"); + } + + return 0; +} + + +int +ipmi_picmg_fru_activation_policy_get(void * intf, int argc, char ** argv) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + + unsigned char msg_data[4]; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = PICMG_GET_FRU_POLICY_CMD; + req.msg.data = msg_data; + req.msg.data_len = 2; + + msg_data[0] = 0; /* PICMG identifier */ + msg_data[1] = atob(argv[0]); /* FRU ID */ + + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + if (rv < 0) printf("no response\n"); + else printf("returned Completion Code 0x%02x\n", rv); + return rv; + } + + printf(" %s\n", ((rsp[1] & 0x01) == 0x01) ? + "activation locked" : "activation not locked"); + printf(" %s\n", ((rsp[1] & 0x02) == 0x02) ? + "deactivation locked" : "deactivation not locked"); + + return 0; +} + +int +ipmi_picmg_fru_activation_policy_set(void * intf, int argc, char ** argv) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + + unsigned char msg_data[4]; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = PICMG_SET_FRU_POLICY_CMD; + req.msg.data = msg_data; + req.msg.data_len = 4; + + msg_data[0] = 0; /* PICMG identifier */ + msg_data[1] = atob(argv[0]); /* FRU ID */ + msg_data[2] = atob(argv[1])& 0x03; /* FRU act policy mask */ + msg_data[3] = atob(argv[2])& 0x03; /* FRU act policy set bits */ + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + if (rv < 0) printf("no response\n"); + else printf("returned Completion Code 0x%02x\n", rv); + return rv; + } + + return 0; +} + +#define PICMG_MAX_LINK_PER_CHANNEL 4 + +int +ipmi_picmg_portstate_get(void * intf, int interfc, uchar channel, int mode) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + unsigned char msg_data[4]; + struct fru_picmgext_link_desc* d; /* descriptor pointer for rec. data */ + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = PICMG_GET_PORT_STATE_CMD; + req.msg.data = msg_data; + req.msg.data_len = 2; + + msg_data[0] = 0x00; /* PICMG identifier */ + msg_data[1] = (interfc & 0x3)<<6; /* interface */ + msg_data[1] |= (channel & 0x3F); /* channel number */ + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + if (rv < 0) printf("no response\n"); + else if( mode == PICMG_EKEY_MODE_QUERY ) + printf("returned Completion Code 0x%02x\n", rv); + return rv; + } + + if (rsp_len >= 6) { + int index; + /* add support for more than one link per channel */ + for(index=0;index (1+ (index*5))){ + d = (struct fru_picmgext_link_desc *) &(rsp[1 + (index*5)]); + + if + ( + mode == PICMG_EKEY_MODE_PRINT_ALL + || + mode == PICMG_EKEY_MODE_QUERY + || + ( + mode == PICMG_EKEY_MODE_PRINT_ENABLED + && + rsp[5 + (index*5) ] == 0x01 + ) + || + ( + mode == PICMG_EKEY_MODE_PRINT_DISABLED + && + rsp[5 + (index*5) ] == 0x00 + ) + ) + { + printf(" Link Grouping ID: 0x%02x\n", d->grouping); + printf(" Link Type Extension: 0x%02x\n", d->ext); + printf(" Link Type: 0x%02x ", d->type); + if (d->type == 0 || d->type == 0xff) + { + printf("Reserved %d\n",d->type); + } + else if (d->type >= 0x06 && d->type <= 0xef) + { + printf("Reserved %d\n",d->type); + } + else if (d->type >= 0xf0 && d->type <= 0xfe) + { + printf("OEM GUID Definition %d\n",d->type); + } + else + { + switch (d->type) + { + case FRU_PICMGEXT_LINK_TYPE_BASE: + printf("PICMG 3.0 Base Interface 10/100/1000\n"); + break; + case FRU_PICMGEXT_LINK_TYPE_FABRIC_ETHERNET: + printf("PICMG 3.1 Ethernet Fabric Interface\n"); + break; + case FRU_PICMGEXT_LINK_TYPE_FABRIC_INFINIBAND: + printf("PICMG 3.2 Infiniband Fabric Interface\n"); + break; + case FRU_PICMGEXT_LINK_TYPE_FABRIC_STAR: + printf("PICMG 3.3 Star Fabric Interface\n"); + break; + case FRU_PICMGEXT_LINK_TYPE_PCIE: + printf("PCI Express Fabric Interface\n"); + break; + default: + printf("Invalid\n"); + break; + } + } + printf(" Link Designator: \n"); + printf(" Port Flag: 0x%02x\n", d->desig_port); + printf(" Interface: 0x%02x - ", d->desig_if); + switch (d->desig_if) + { + case FRU_PICMGEXT_DESIGN_IF_BASE: + printf("Base Interface\n"); + break; + case FRU_PICMGEXT_DESIGN_IF_FABRIC: + printf("Fabric Interface\n"); + break; + case FRU_PICMGEXT_DESIGN_IF_UPDATE_CHANNEL: + printf("Update Channel\n"); + break; + case FRU_PICMGEXT_DESIGN_IF_RESERVED: + printf("Reserved\n"); + break; + default: + printf("Invalid"); + break; + } + printf(" Channel Number: 0x%02x\n", d->desig_channel); + printf(" STATE: %s\n", + ( rsp[5 +(index*5)] == 0x01) ?"enabled":"disabled"); + printf("\n"); + } + } + } + } + else + { + printf("Unexpected answer len %d, can't print result\n",rsp_len); + } + + return 0; +} + + +int +ipmi_picmg_portstate_set(void * intf, int interfc, uchar channel, + uchar port, int type, int typeext, int group, int enable) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + unsigned char msg_data[6]; + // struct fru_picmgext_link_desc* d; + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = PICMG_SET_PORT_STATE_CMD; + req.msg.data = msg_data; + req.msg.data_len = 6; + + msg_data[0] = 0x00; /* PICMG identifier */ + msg_data[1] = (channel & 0x3f) | ((interfc & 3) << 6); + msg_data[2] = (port & 0xf) | ((type & 0xf) << 4); + msg_data[3] = ((type >> 4) & 0xf) | ((typeext & 0xf) << 4); + msg_data[4] = group & 0xff; + msg_data[5] = (unsigned char) (enable & 0x01); /* en/dis */ + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + if (rv < 0) printf("no response\n"); + else printf("returned Completion Code 0x%02x\n", rv); + return rv; + } + + return 0; +} + + + +/* AMC.0 commands */ + +#define PICMG_AMC_MAX_LINK_PER_CHANNEL 4 + +int +ipmi_picmg_amc_portstate_get(void * intf,int device,uchar channel, + int mode) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + + unsigned char msg_data[4]; + + struct fru_picmgext_amc_link_info* d; /* descriptor pointer for rec. data */ + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = PICMG_AMC_GET_PORT_STATE_CMD; + req.msg.data = msg_data; + + /* FIXME : add check for AMC or carrier device */ + if(device == -1 || PicmgCardType != PICMG_CARD_TYPE_ATCA ){ + req.msg.data_len = 2; /* for amc only channel */ + }else{ + req.msg.data_len = 3; /* for carrier channel and device */ + } + + msg_data[0] = 0x00; /* PICMG identifier */ + msg_data[1] = channel ; + msg_data[2] = (uchar)device ; + + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + if (rv < 0) printf("no response\n"); + else if ( mode == PICMG_EKEY_MODE_QUERY ) + printf("returned Completion Code 0x%02x\n", rv); + return rv; + } + + if (rsp_len >= 5) { + int index; + + /* add support for more than one link per channel */ + for(index=0;index (1+ (index*4))){ + unsigned char type; + unsigned char ext; + unsigned char grouping; + unsigned char port; + unsigned char enabled; + d = (struct fru_picmgext_amc_link_info *)&(rsp[1 + (index*4)]); + + + /* Removed endianness check here, probably not required + as we dont use bitfields */ + port = d->linkInfo[0] & 0x0F; + type = ((d->linkInfo[0] & 0xF0) >> 4 )|(d->linkInfo[1] & 0x0F ); + ext = ((d->linkInfo[1] & 0xF0) >> 4 ); + grouping = d->linkInfo[2]; + + + enabled = rsp[4 + (index*4) ]; + + if + ( + mode == PICMG_EKEY_MODE_PRINT_ALL + || + mode == PICMG_EKEY_MODE_QUERY + || + ( + mode == PICMG_EKEY_MODE_PRINT_ENABLED + && + enabled == 0x01 + ) + || + ( + mode == PICMG_EKEY_MODE_PRINT_DISABLED + && + enabled == 0x00 + ) + ) + { + if(device == -1 || PicmgCardType != PICMG_CARD_TYPE_ATCA ){ + printf(" Link device : AMC\n"); + }else{ + printf(" Link device : 0x%02x\n", device ); + } + + printf(" Link Grouping ID: 0x%02x\n", grouping); + + if (type == 0 || type == 1 ||type == 0xff) + { + printf(" Link Type Extension: 0x%02x\n", ext); + printf(" Link Type: Reserved\n"); + } + else if (type >= 0xf0 && type <= 0xfe) + { + printf(" Link Type Extension: 0x%02x\n", ext); + printf(" Link Type: OEM GUID Definition\n"); + } + else + { + if (type <= FRU_PICMGEXT_AMC_LINK_TYPE_STORAGE ) + { + printf(" Link Type Extension: %s\n", + amc_link_type_ext_str[type][ext]); + printf(" Link Type: %s\n", + amc_link_type_str[type]); + } + else{ + printf(" Link Type Extension: 0x%02x\n", ext); + printf(" Link Type: undefined\n"); + } + } + printf(" Link Designator: \n"); + printf(" Channel Number: 0x%02x\n", channel); + printf(" Port Flag: 0x%02x\n", port ); + printf(" STATE: %s\n", + ( enabled == 0x01 )?"enabled":"disabled"); + printf("\n"); + } + } + } + } + else + { + printf("ipmi_picmg_amc_portstate_get: " + "Unexpected answer, can't print result\n"); + } + + return 0; +} + + +int +ipmi_picmg_amc_portstate_set(void * intf, uchar channel, uchar port, + int type, int typeext, int group, int enable, int device) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + unsigned char msg_data[7]; + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = PICMG_AMC_SET_PORT_STATE_CMD; + req.msg.data = msg_data; + + msg_data[0] = 0x00; /* PICMG identifier*/ + msg_data[1] = channel; /* channel id */ + msg_data[2] = port & 0xF; /* port flags */ + msg_data[2] |= (type & 0x0F)<<4; /* type */ + msg_data[3] = (type & 0xF0)>>4; /* type */ + msg_data[3] |= (typeext & 0x0F)<<4; /* extension */ + msg_data[4] = (group & 0xFF); /* group */ + msg_data[5] = (enable & 0x01); /* state */ + req.msg.data_len = 6; + + /* device id - only for carrier needed */ + if (device >= 0) { + msg_data[6] = (uchar)device; + req.msg.data_len = 7; + } + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + if (rv < 0) printf("no response\n"); + else printf("returned Completion Code 0x%02x\n", rv); + return rv; + } + + return 0; +} + + +int +ipmi_picmg_get_led_properties(void * intf, int argc, char ** argv) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + + unsigned char msg_data[6]; + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = PICMG_GET_FRU_LED_PROPERTIES_CMD; + req.msg.data = msg_data; + req.msg.data_len = 2; + + msg_data[0] = 0x00; /* PICMG identifier */ + msg_data[1] = atob(argv[0]); /* FRU-ID */ + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + if (rv < 0) printf("no response\n"); + else printf("returned Completion Code 0x%02x\n", rv); + return rv; + } + + printf("General Status LED Properties: 0x%2x\n\r", rsp[1] ); + printf("App. Specific LED Count: 0x%2x\n\r", rsp[2] ); + + return 0; +} + +int +ipmi_picmg_get_led_capabilities(void * intf, int argc, char ** argv) +{ + int i; + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + + unsigned char msg_data[6]; + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = PICMG_GET_LED_COLOR_CAPABILITIES_CMD; + req.msg.data = msg_data; + req.msg.data_len = 3; + + msg_data[0] = 0x00; /* PICMG identifier */ + msg_data[1] = atob(argv[0]); /* FRU-ID */ + msg_data[2] = atob(argv[1]); /* LED-ID */ + + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + if (rv < 0) printf("no response\n"); + else printf("returned Completion Code 0x%02x\n", rv); + return rv; + } + + printf("LED Color Capabilities: %02x", rsp[1] ); + for ( i=0 ; i<8 ; i++ ) { + if ( rsp[1] & (0x01 << i) ) { + printf("%s, ", led_color_str[ i ]); + } + } + printf("\n\r"); + + printf("Default LED Color in\n\r"); + printf(" LOCAL control: %s\n\r", led_color_str[ rsp[2] ] ); + printf(" OVERRIDE state: %s\n\r", led_color_str[ rsp[3] ] ); + + return 0; +} + +int +ipmi_picmg_get_led_state(void * intf, int argc, char ** argv) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + + unsigned char msg_data[6]; + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = PICMG_GET_FRU_LED_STATE_CMD; + req.msg.data = msg_data; + req.msg.data_len = 3; + + msg_data[0] = 0x00; /* PICMG identifier */ + msg_data[1] = atob(argv[0]); /* FRU-ID */ + msg_data[2] = atob(argv[1]); /* LED-ID */ + + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + if (rv < 0) printf("no response\n"); + else printf("returned Completion Code 0x%02x\n", rv); + return rv; + } + + printf("LED states: %x ", rsp[1] ); + if (rsp[1] == 0x1) + printf("[LOCAL CONTROL]\n\r"); + else if (rsp[1] == 0x2) + printf("[OVERRIDE]\n\r"); + else if (rsp[1] == 0x4) + printf("[LAMPTEST]\n\r"); + else + printf("\n\r"); + + printf(" Local Control function: %x ", rsp[2] ); + if (rsp[2] == 0x0) + printf("[OFF]\n\r"); + else if (rsp[2] == 0xff) + printf("[ON]\n\r"); + else + printf("[BLINKING]\n\r"); + + printf(" Local Control On-Duration: %x\n\r", rsp[3] ); + printf(" Local Control Color: %x [%s]\n\r", rsp[4], led_color_str[ rsp[4] ]); + + /* override state or lamp test */ + if (rsp[1] == 0x02) { + printf(" Override function: %x ", rsp[5] ); + if (rsp[2] == 0x0) + printf("[OFF]\n\r"); + else if (rsp[2] == 0xff) + printf("[ON]\n\r"); + else + printf("[BLINKING]\n\r"); + + printf(" Override On-Duration: %x\n\r", rsp[6] ); + printf(" Override Color: %x [%s]\n\r", rsp[7], led_color_str[ rsp[7] ]); + + }else if (rsp[1] == 0x06) { + printf(" Override function: %x ", rsp[5] ); + if (rsp[2] == 0x0) + printf("[OFF]\n\r"); + else if (rsp[2] == 0xff) + printf("[ON]\n\r"); + else + printf("[BLINKING]\n\r"); + printf(" Override On-Duration: %x\n\r", rsp[6] ); + printf(" Override Color: %x [%s]\n\r", rsp[7], led_color_str[ rsp[7] ]); + printf(" Lamp test duration: %x\n\r", rsp[8] ); + } + + return 0; +} + +int +ipmi_picmg_set_led_state(void * intf, int argc, char ** argv) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + + unsigned char msg_data[6]; + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = PICMG_SET_FRU_LED_STATE_CMD; + req.msg.data = msg_data; + req.msg.data_len = 6; + + msg_data[0] = 0x00; /* PICMG identifier */ + msg_data[1] = atob(argv[0]); /* FRU-ID */ + msg_data[2] = atob(argv[1]); /* LED-ID */ + msg_data[3] = atob(argv[2]); /* LED function */ + msg_data[4] = atob(argv[3]); /* LED on duration */ + msg_data[5] = atob(argv[4]); /* LED color */ + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + if (rv < 0) printf("no response\n"); + else printf("returned Completion Code 0x%02x\n", rv); + return rv; + } + + + return 0; +} + +int +ipmi_picmg_get_power_level(void * intf, int argc, char ** argv) +{ + int i; + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + + unsigned char msg_data[6]; + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = PICMG_GET_POWER_LEVEL_CMD; + req.msg.data = msg_data; + req.msg.data_len = 3; + + msg_data[0] = 0x00; /* PICMG identifier */ + msg_data[1] = atob(argv[0]); /* FRU-ID */ + msg_data[2] = atob(argv[1]); /* Power type */ + + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + if (rv < 0) printf("no response\n"); + else printf("returned Completion Code 0x%02x\n", rv); + return rv; + } + + printf("Dynamic Power Configuration: %s\n", (rsp[1]&0x80)==0x80?"enabled":"disabled" ); + printf("Actual Power Level: %i\n", (rsp[1] & 0xf)); + printf("Delay to stable Power: %i\n", rsp[2]); + printf("Power Multiplier: %i\n", rsp[3]); + + + for ( i = 1; i+3 < rsp_len ; i++ ) { + printf(" Power Draw %i: %i\n", i, (rsp[i+3]) * rsp[3] / 10); + } + return 0; +} + +int +ipmi_picmg_set_power_level(void * intf, int argc, char ** argv) +{ + // int i; + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + + unsigned char msg_data[6]; + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = PICMG_SET_POWER_LEVEL_CMD; + req.msg.data = msg_data; + req.msg.data_len = 4; + + msg_data[0] = 0x00; /* PICMG identifier */ + msg_data[1] = atob(argv[0]); /* FRU-ID */ + msg_data[2] = atob(argv[1]); /* power level */ + msg_data[3] = atob(argv[2]); /* present to desired */ + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + if (rv < 0) printf("no response\n"); + else printf("returned Completion Code 0x%02x\n", rv); + return rv; + } + + return 0; +} + +int +ipmi_picmg_bused_resource(void * intf, t_picmg_bused_resource_mode mode) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + + unsigned char msg_data[6]; + memset(&req, 0, sizeof(req)); + + switch ( mode ) { + case PICMG_BUSED_RESOURCE_SUMMARY: + { + t_picmg_busres_resource_id resource; + t_picmg_busres_board_cmd_types cmd =PICMG_BUSRES_BOARD_CMD_QUERY; + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = PICMG_BUSED_RESOURCE_CMD; + req.msg.data = msg_data; + req.msg.data_len = 3; + + /* IF BOARD + query for all resources + */ + for( resource=PICMG_BUSRES_METAL_TEST_BUS_1;resource<=PICMG_BUSRES_SYNC_CLOCK_GROUP_3;resource+=(t_picmg_busres_resource_id)1 ) { + msg_data[0] = 0x00; /* PICMG identifier */ + msg_data[1] = (unsigned char) cmd; + msg_data[2] = (unsigned char) resource; + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + if (rv < 0) printf("bused resource control: no response\n"); + else printf("bused resource control: returned Completion Code 0x%02x\n",rv); + return rv; + } else { + printf("Resource 0x%02x '%-26s' : 0x%02x [%s] \n" , + resource, val2str(resource,picmg_busres_id_vals), + rsp[1], oemval2str(cmd,rsp[1], + picmg_busres_board_status_vals)); + } + } + } + break; + default: rv = -1; + break; + } + + return rv; +} + +int +ipmi_picmg_fru_control(void * intf, int argc, char ** argv) +{ + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + + unsigned char msg_data[6]; + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = PICMG_FRU_CONTROL_CMD; + req.msg.data = msg_data; + req.msg.data_len = 3; + + msg_data[0] = 0x00; /* PICMG identifier */ + msg_data[1] = atob(argv[0]); /* FRU-ID */ + msg_data[2] = atob(argv[1]); /* control option */ + + printf("FRU Device Id: %d FRU Control Option: %s\n\r", msg_data[1], \ + val2str( msg_data[2], picmg_frucontrol_vals)); + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + if (rv < 0) printf("frucontrol: no response\n"); + else printf("frucontrol: returned Completion Code 0x%02x\n",rv); + return rv; + } else { + printf("frucontrol: ok\n"); + } + + return 0; +} + + +int +ipmi_picmg_clk_get(void * intf, int clk_id,int clk_res,int mode) +{ + // int i; + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + + unsigned char enabled; + unsigned char direction; + + unsigned char msg_data[6]; + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = PICMG_AMC_GET_CLK_STATE_CMD; + req.msg.data = msg_data; + + msg_data[0] = 0x00; /* PICMG identifier */ + msg_data[1] = clk_id; + + if(clk_res == -1 || PicmgCardType != PICMG_CARD_TYPE_ATCA ){ + req.msg.data_len = 2; /* for amc only channel */ + }else{ + req.msg.data_len = 3; /* for carrier channel and device */ + msg_data[2] = clk_res; + } + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + if (rv < 0) printf("no response\n"); + else printf("returned Completion Code 0x%02x\n", rv); + return rv; + } + + { + enabled = (rsp[1]&0x8)!=0; + direction = (rsp[1]&0x4)!=0; + + if + ( + mode == PICMG_EKEY_MODE_QUERY + || + mode == PICMG_EKEY_MODE_PRINT_ALL + || + ( + mode == PICMG_EKEY_MODE_PRINT_DISABLED + && + enabled == 0 + ) + || + ( + mode == PICMG_EKEY_MODE_PRINT_ENABLED + && + enabled == 1 + ) + ) { + if( PicmgCardType != PICMG_CARD_TYPE_AMC ) { + printf("CLK resource id : %3d [ %s ]\n", clk_res , + oemval2str( ((clk_res>>6)&0x03), (clk_res&0x0F), + picmg_clk_resource_vals)); + } else { + printf("CLK resource id : N/A [ AMC Module ]\n"); + clk_res = 0x40; /* Set */ + } + printf("CLK id : %3d [ %s ]\n", clk_id, + oemval2str( ((clk_res>>6)&0x03), clk_id , + picmg_clk_id_vals)); + + + printf("CLK setting : 0x%02x\n", rsp[1]); + printf(" - state: %s\n", (enabled)?"enabled":"disabled"); + printf(" - direction: %s\n", (direction)?"Source":"Receiver"); + printf(" - PLL ctrl: 0x%x\n", rsp[1]&0x3); + + if(enabled){ + unsigned long freq = 0; + freq = ( rsp[5] << 0 + | rsp[6] << 8 + | rsp[7] << 16 + | rsp[8] << 24 ); + printf(" - Index: %3d\n", rsp[2]); + printf(" - Family: %3d [ %s ]\n", rsp[3], + val2str( rsp[3], picmg_clk_family_vals)); + printf(" - AccLVL: %3d [ %s ]\n", rsp[4], + oemval2str(rsp[3],rsp[4],picmg_clk_accuracy_vals)); + printf(" - Freq: %d\n", freq); + } + } + } + return 0; +} + + +int +ipmi_picmg_clk_set(void * intf, int argc, char ** argv) +{ + // int i; + uint8_t rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + + unsigned char msg_data[11]; + unsigned long freq=0; + + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_PICMG; + req.msg.cmd = PICMG_AMC_SET_CLK_STATE_CMD; + req.msg.data = msg_data; + + msg_data[0] = 0x00; /* PICMG identifier */ + msg_data[1] = (uchar)strtoul(argv[0], NULL,0); /* clk id */ + msg_data[2] = (uchar)strtoul(argv[1], NULL,0); /* clk index */ + msg_data[3] = (uchar)strtoul(argv[2], NULL,0); /* setting */ + msg_data[4] = (uchar)strtoul(argv[3], NULL,0); /* family */ + msg_data[5] = (uchar)strtoul(argv[4], NULL,0); /* acc */ + + freq = strtoul(argv[5], NULL,0); + msg_data[6] = (uchar)((freq >> 0)& 0xFF); /* freq */ + msg_data[7] = (uchar)((freq >> 8)& 0xFF); /* freq */ + msg_data[8] = (uchar)((freq >>16)& 0xFF); /* freq */ + msg_data[9] = (uchar)((freq >>24)& 0xFF); /* freq */ + + req.msg.data_len = 10; + if( PicmgCardType == PICMG_CARD_TYPE_ATCA ) + { + if( argc > 7) + { + req.msg.data_len = 11; + msg_data[10] = (uchar)strtoul(argv[6], NULL,0); /* resource id */ + } + else + { + printf("missing resource id for atca board\n"); + return -1; + } + } + +#if 1 +printf("## ID: %d\n", msg_data[1]); +printf("## index: %d\n", msg_data[2]); +printf("## setting: 0x%02x\n", msg_data[3]); +printf("## family: %d\n", msg_data[4]); +printf("## acc: %d\n", msg_data[5]); +printf("## freq: %d\n", freq ); +printf("## res: %d\n", msg_data[10]); +#endif + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv) { + if (rv < 0) printf("no response\n"); + else printf("returned Completion Code 0x%02x\n", rv); + return rv; + } + + return 0; +} + + +#ifdef METACOMMAND +int i_picmg(int argc, char **argv) +#else +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#endif +{ + int rc = 0; + int showProperties = 0; + void *intf = NULL; + int c, i; + char *s1; + + printf("%s ver %s\n", progname,progver); + + while ( (c = getopt( argc, argv,"m:i:T:V:J:EYF:P:N:R:U:Z:x?")) != EOF) + switch (c) { + case 'm': /* specific IPMB MC, 3-byte address, e.g. "409600" */ + g_bus = htoi(&optarg[0]); /*bus/channel*/ + g_sa = htoi(&optarg[2]); /*device slave address*/ + g_lun = htoi(&optarg[4]); /*LUN*/ + g_addrtype = ADDR_IPMB; + if (optarg[6] == 's') { + g_addrtype = ADDR_SMI; s1 = "SMI"; + } else { g_addrtype = ADDR_IPMB; s1 = "IPMB"; } + fset_mc = 1; + ipmi_set_mc(g_bus,g_sa,g_lun,g_addrtype); + printf("Use MC at %s bus=%x sa=%x lun=%x\n", + s1,g_bus,g_sa,g_lun); + break; + case 'i': /*specify a fru id*/ + if (strncmp(optarg,"0x",2) == 0) g_fruid = htoi(&optarg[2]); + else g_fruid = htoi(optarg); + printf("Using FRU ID 0x%02x\n",g_fruid); + break; + case 'x': fdebug = 1; break; /* debug messages */ + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'V': /* priv level */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + break; + case '?': + ipmi_picmg_help(); + return ERR_USAGE; + break; + } + for (i = 0; i < optind; i++) { argv++; argc--; } + + /* Get PICMG properties is called to obtain version information */ + if (argc !=0 && !strncmp(argv[0], "properties", 10)) { + showProperties =1; + } + + if (argc == 0 || (!strncmp(argv[0], "help", 4))) { + ipmi_picmg_help(); + return ERR_USAGE; + } + + rc = ipmi_picmg_properties(intf,showProperties); + if (rc < 0) { /*cannot contact MC, so exit*/ + goto do_exit; + } + + /* address info command */ + else if (!strncmp(argv[0], "addrinfo", 8)) { + rc = ipmi_picmg_getaddr(intf, argc-1, &argv[1]); + } + else if (!strncmp(argv[0], "busres", 6)) { + if (argc > 1) { + if (!strncmp(argv[1], "summary", 7)) { + ipmi_picmg_bused_resource(intf, PICMG_BUSED_RESOURCE_SUMMARY ); + } + } else { + printf("usage: busres summary\n"); + } + } + /* fru control command */ + else if (!strncmp(argv[0], "frucontrol", 10)) { + if (argc > 2) { + rc = ipmi_picmg_fru_control(intf, argc-1, &(argv[1])); + } + else { + printf("usage: frucontrol