From 42c2ef79e18d66fdcd5ba1bd068519c09947a6d3 Mon Sep 17 00:00:00 2001 From: Christian Wiese Date: Thu, 25 Apr 2013 16:44:44 +0200 Subject: [PATCH] nut: add patch with cherry-picked upstream fixes --- .../nut/nut-2.6.5-0000-upstream-fixes.patch | 1931 +++++++++++++++++ 1 file changed, 1931 insertions(+) create mode 100644 monitor/nut/nut-2.6.5-0000-upstream-fixes.patch diff --git a/monitor/nut/nut-2.6.5-0000-upstream-fixes.patch b/monitor/nut/nut-2.6.5-0000-upstream-fixes.patch new file mode 100644 index 000000000..71267ed6e --- /dev/null +++ b/monitor/nut/nut-2.6.5-0000-upstream-fixes.patch @@ -0,0 +1,1931 @@ +From 6df63fe455745d8d74010d9ad4f85a30f40b5c08 Mon Sep 17 00:00:00 2001 +From: Frederic Bohe +Date: Mon, 10 Sep 2012 13:28:35 +0000 +Subject: [PATCH] [nut-scanner] Fix a crash when no start IP is provided. + +Fossil-ID: SVN r3722 +--- + tools/nut-scanner/nut-scanner.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/tools/nut-scanner/nut-scanner.c b/tools/nut-scanner/nut-scanner.c +index db582be..52e0da7 100644 +--- a/tools/nut-scanner/nut-scanner.c ++++ b/tools/nut-scanner/nut-scanner.c +@@ -371,6 +371,7 @@ display_help: + if( allow_snmp && nutscan_avail_snmp ) { + if( start_ip == NULL ) { + printq(quiet,"No start IP, skipping SNMP\n"); ++ nutscan_avail_snmp = 0; + } + else { + printq(quiet,"Scanning SNMP bus.\n"); +@@ -398,6 +399,7 @@ display_help: + if( allow_oldnut && nutscan_avail_nut) { + if( start_ip == NULL ) { + printq(quiet,"No start IP, skipping NUT bus (old connect method)\n"); ++ nutscan_avail_nut = 0; + } + else { + printq(quiet,"Scanning NUT bus (old connect method).\n"); +-- +1.7.10.2 + + +From dc729c5c3da7efb4632f7d9f7a031108540282d9 Mon Sep 17 00:00:00 2001 +From: Arnaud Quette +Date: Wed, 19 Sep 2012 19:35:45 +0000 +Subject: [PATCH] Support for FreeIPMI 1.1.x and 1.2.x (#2) + +Prepare for supporting API changes in FreeIPMI 1.1.x and 1.2.x. This 2nd +patch, which completes [[SVN:3675]], addresses FRU API changes, and removes +code redundancy. This code has been tested with FreeIPMI 0.8.12 and +the latest [[FreeIPMI SVN]] trunk r9505 (reported as 1.2.0.beta2 by pkgconfig) + +[[SVN:3675]] = 2012-07-16T13:18:18Z!arnaud.quette@free.fr + +Fossil-ID: SVN r3733 +--- + drivers/nut-libfreeipmi.c | 375 ++++++++++++++--------------------------- + m4/nut_check_libfreeipmi.m4 | 1 - + tools/nut-scanner/scan_ipmi.c | 103 +++++++---- + 3 files changed, 192 insertions(+), 287 deletions(-) + +diff --git a/drivers/nut-libfreeipmi.c b/drivers/nut-libfreeipmi.c +index 1539e75..dd06369 100644 +--- a/drivers/nut-libfreeipmi.c ++++ b/drivers/nut-libfreeipmi.c +@@ -42,10 +42,12 @@ + #include + #include + #include "timehead.h" ++#include "common.h" + #include + #include ++#if HAVE_FREEIPMI_MONITORING + #include +-#include "common.h" ++#endif + #include "nut-ipmi.h" + #include "dstate.h" + +@@ -57,18 +59,46 @@ + + /* FreeIPMI contexts and configuration*/ + ipmi_ctx_t ipmi_ctx = NULL; +-ipmi_fru_parse_ctx_t fru_parse_ctx = NULL; + ipmi_monitoring_ctx_t mon_ctx = NULL; + struct ipmi_monitoring_ipmi_config ipmi_config; ++ + /* SDR management API has changed with 1.1.X and later */ + #ifdef HAVE_FREEIPMI_11X_12X + ipmi_sdr_ctx_t sdr_ctx = NULL; ++ ipmi_fru_ctx_t fru_ctx = NULL; ++ #define SDR_PARSE_CTX sdr_ctx + #else +- ipmi_sdr_cache_ctx_t sdr_cache_ctx = NULL; ++ ipmi_sdr_cache_ctx_t sdr_ctx = NULL; + ipmi_sdr_parse_ctx_t sdr_parse_ctx = NULL; +-#ifndef IPMI_SDR_MAX_RECORD_LENGTH +- #define IPMI_SDR_MAX_RECORD_LENGTH IPMI_SDR_CACHE_MAX_SDR_RECORD_LENGTH +-#endif ++ #define SDR_PARSE_CTX sdr_parse_ctx ++ ipmi_fru_parse_ctx_t fru_ctx = NULL; ++ /* Functions remapping */ ++ #define ipmi_sdr_ctx_create ipmi_sdr_cache_ctx_create ++ #define ipmi_sdr_ctx_destroy ipmi_sdr_cache_ctx_destroy ++ #define ipmi_sdr_ctx_errnum ipmi_sdr_cache_ctx_errnum ++ #define ipmi_sdr_ctx_errormsg ipmi_sdr_cache_ctx_errormsg ++ #define ipmi_fru_ctx_create ipmi_fru_parse_ctx_create ++ #define ipmi_fru_ctx_destroy ipmi_fru_parse_ctx_destroy ++ #define ipmi_fru_ctx_set_flags ipmi_fru_parse_ctx_set_flags ++ #define ipmi_fru_ctx_strerror ipmi_fru_parse_ctx_strerror ++ #define ipmi_fru_ctx_errnum ipmi_fru_parse_ctx_errnum ++ #define ipmi_fru_open_device_id ipmi_fru_parse_open_device_id ++ #define ipmi_fru_close_device_id ipmi_fru_parse_close_device_id ++ #define ipmi_fru_ctx_errormsg ipmi_fru_parse_ctx_errormsg ++ #define ipmi_fru_read_data_area ipmi_fru_parse_read_data_area ++ #define ipmi_fru_next ipmi_fru_parse_next ++ #define ipmi_fru_type_length_field_to_string ipmi_fru_parse_type_length_field_to_string ++ #define ipmi_fru_multirecord_power_supply_information ipmi_fru_parse_multirecord_power_supply_information ++ #define ipmi_fru_board_info_area ipmi_fru_parse_board_info_area ++ #define ipmi_fru_field_t ipmi_fru_parse_field_t ++ /* Constants */ ++ #define IPMI_SDR_MAX_RECORD_LENGTH IPMI_SDR_CACHE_MAX_SDR_RECORD_LENGTH ++ #define IPMI_SDR_ERR_CACHE_READ_CACHE_DOES_NOT_EXIST IPMI_SDR_CACHE_ERR_CACHE_READ_CACHE_DOES_NOT_EXIST ++ #define IPMI_FRU_AREA_SIZE_MAX IPMI_FRU_PARSE_AREA_SIZE_MAX ++ #define IPMI_FRU_FLAGS_SKIP_CHECKSUM_CHECKS IPMI_FRU_PARSE_FLAGS_SKIP_CHECKSUM_CHECKS ++ #define IPMI_FRU_AREA_TYPE_BOARD_INFO_AREA IPMI_FRU_PARSE_AREA_TYPE_BOARD_INFO_AREA ++ #define IPMI_FRU_AREA_TYPE_MULTIRECORD_POWER_SUPPLY_INFORMATION IPMI_FRU_PARSE_AREA_TYPE_MULTIRECORD_POWER_SUPPLY_INFORMATION ++ #define IPMI_FRU_AREA_STRING_MAX IPMI_FRU_PARSE_AREA_STRING_MAX + #endif /* HAVE_FREEIPMI_11X_12X */ + + /* FIXME: freeipmi auto selects a cache based on the hostname you are +@@ -78,7 +108,7 @@ struct ipmi_monitoring_ipmi_config ipmi_config; + + /* Support functions */ + static const char* libfreeipmi_getfield (uint8_t language_code, +- ipmi_fru_parse_field_t *field); ++ ipmi_fru_field_t *field); + + static void libfreeipmi_cleanup(); + +@@ -97,7 +127,7 @@ static int libfreeipmi_get_sensors_info (IPMIDevice_t *ipmi_dev); + int nut_ipmi_open(int ipmi_id, IPMIDevice_t *ipmi_dev) + { + int ret = -1; +- uint8_t areabuf[IPMI_FRU_PARSE_AREA_SIZE_MAX+1]; ++ uint8_t areabuf[IPMI_FRU_AREA_SIZE_MAX+1]; + unsigned int area_type = 0; + unsigned int area_length = 0; + +@@ -134,26 +164,26 @@ int nut_ipmi_open(int ipmi_id, IPMIDevice_t *ipmi_dev) + upsdebugx(1, "FreeIPMI initialized..."); + + /* Parse FRU information */ +- if (!(fru_parse_ctx = ipmi_fru_parse_ctx_create (ipmi_ctx))) ++ if (!(fru_ctx = ipmi_fru_ctx_create (ipmi_ctx))) + { + libfreeipmi_cleanup(); +- fatal_with_errno(EXIT_FAILURE, "ipmi_fru_parse_ctx_create()"); ++ fatal_with_errno(EXIT_FAILURE, "ipmi_fru_ctx_create()"); + } + + /* lots of motherboards calculate checksums incorrectly */ +- if (ipmi_fru_parse_ctx_set_flags (fru_parse_ctx, IPMI_FRU_PARSE_FLAGS_SKIP_CHECKSUM_CHECKS) < 0) ++ if (ipmi_fru_ctx_set_flags (fru_ctx, IPMI_FRU_FLAGS_SKIP_CHECKSUM_CHECKS) < 0) + { + libfreeipmi_cleanup(); +- fatalx(EXIT_FAILURE, "ipmi_fru_parse_ctx_set_flags: %s\n", +- ipmi_fru_parse_ctx_strerror (ipmi_fru_parse_ctx_errnum (fru_parse_ctx))); ++ fatalx(EXIT_FAILURE, "ipmi_fru_ctx_set_flags: %s\n", ++ ipmi_fru_ctx_strerror (ipmi_fru_ctx_errnum (fru_ctx))); + } + + /* Now open the requested (local) PSU */ +- if (ipmi_fru_parse_open_device_id (fru_parse_ctx, ipmi_id) < 0) ++ if (ipmi_fru_open_device_id (fru_ctx, ipmi_id) < 0) + { + libfreeipmi_cleanup(); +- fatalx(EXIT_FAILURE, "ipmi_fru_parse_open_device_id: %s\n", +- ipmi_fru_parse_ctx_errormsg (fru_parse_ctx)); ++ fatalx(EXIT_FAILURE, "ipmi_fru_open_device_id: %s\n", ++ ipmi_fru_ctx_errormsg (fru_ctx)); + } + + /* Set IPMI identifier */ +@@ -164,19 +194,19 @@ int nut_ipmi_open(int ipmi_id, IPMIDevice_t *ipmi_dev) + /* clear fields */ + area_type = 0; + area_length = 0; +- memset (areabuf, '\0', IPMI_FRU_PARSE_AREA_SIZE_MAX + 1); ++ memset (areabuf, '\0', IPMI_FRU_AREA_SIZE_MAX + 1); + + /* parse FRU buffer */ +- if (ipmi_fru_parse_read_data_area (fru_parse_ctx, ++ if (ipmi_fru_read_data_area (fru_ctx, + &area_type, + &area_length, + areabuf, +- IPMI_FRU_PARSE_AREA_SIZE_MAX) < 0) ++ IPMI_FRU_AREA_SIZE_MAX) < 0) + { + libfreeipmi_cleanup(); + fatal_with_errno(EXIT_FAILURE, +- "ipmi_fru_parse_open_device_id: %s\n", +- ipmi_fru_parse_ctx_errormsg (fru_parse_ctx)); ++ "ipmi_fru_read_data_area: %s\n", ++ ipmi_fru_ctx_errormsg (fru_ctx)); + } + + if (area_length) +@@ -184,7 +214,7 @@ int nut_ipmi_open(int ipmi_id, IPMIDevice_t *ipmi_dev) + switch (area_type) + { + /* get generic board information */ +- case IPMI_FRU_PARSE_AREA_TYPE_BOARD_INFO_AREA: ++ case IPMI_FRU_AREA_TYPE_BOARD_INFO_AREA: + + if(libfreeipmi_get_board_info (areabuf, area_length, + ipmi_dev) < 0) +@@ -193,7 +223,7 @@ int nut_ipmi_open(int ipmi_id, IPMIDevice_t *ipmi_dev) + } + break; + /* get specific PSU information */ +- case IPMI_FRU_PARSE_AREA_TYPE_MULTIRECORD_POWER_SUPPLY_INFORMATION: ++ case IPMI_FRU_AREA_TYPE_MULTIRECORD_POWER_SUPPLY_INFORMATION: + + if(libfreeipmi_get_psu_info (areabuf, area_length, ipmi_dev) < 0) + { +@@ -205,13 +235,13 @@ int nut_ipmi_open(int ipmi_id, IPMIDevice_t *ipmi_dev) + break; + } + } +- } while ((ret = ipmi_fru_parse_next (fru_parse_ctx)) == 1); ++ } while ((ret = ipmi_fru_next (fru_ctx)) == 1); + + /* check for errors */ + if (ret < 0) { + libfreeipmi_cleanup(); +- fatal_with_errno(EXIT_FAILURE, "ipmi_fru_parse_next: %s", +- ipmi_fru_parse_ctx_errormsg (fru_parse_ctx)); ++ fatal_with_errno(EXIT_FAILURE, "ipmi_fru_next: %s", ++ ipmi_fru_ctx_errormsg (fru_ctx)); + } + else { + /* Get all related sensors information */ +@@ -232,25 +262,25 @@ void nut_ipmi_close(void) + } + + static const char* libfreeipmi_getfield (uint8_t language_code, +- ipmi_fru_parse_field_t *field) ++ ipmi_fru_field_t *field) + { +- static char strbuf[IPMI_FRU_PARSE_AREA_STRING_MAX + 1]; +- unsigned int strbuflen = IPMI_FRU_PARSE_AREA_STRING_MAX; ++ static char strbuf[IPMI_FRU_AREA_STRING_MAX + 1]; ++ unsigned int strbuflen = IPMI_FRU_AREA_STRING_MAX; + + if (!field->type_length_field_length) + return NULL; + +- memset (strbuf, '\0', IPMI_FRU_PARSE_AREA_STRING_MAX + 1); ++ memset (strbuf, '\0', IPMI_FRU_AREA_STRING_MAX + 1); + +- if (ipmi_fru_parse_type_length_field_to_string (fru_parse_ctx, ++ if (ipmi_fru_type_length_field_to_string (fru_ctx, + field->type_length_field, + field->type_length_field_length, + language_code, + strbuf, + &strbuflen) < 0) + { +- upsdebugx (2, "ipmi_fru_parse_type_length_field_to_string: %s", +- ipmi_fru_parse_ctx_errormsg (fru_parse_ctx)); ++ upsdebugx (2, "ipmi_fru_type_length_field_to_string: %s", ++ ipmi_fru_ctx_errormsg (fru_ctx)); + return NULL; + } + +@@ -279,24 +309,20 @@ static float libfreeipmi_get_voltage (uint8_t voltage_code) + static void libfreeipmi_cleanup() + { + /* cleanup */ +- if (fru_parse_ctx) { +- ipmi_fru_parse_close_device_id (fru_parse_ctx); +- ipmi_fru_parse_ctx_destroy (fru_parse_ctx); ++ if (fru_ctx) { ++ ipmi_fru_close_device_id (fru_ctx); ++ ipmi_fru_ctx_destroy (fru_ctx); + } + +-#ifdef HAVE_FREEIPMI_11X_12X + if (sdr_ctx) { + ipmi_sdr_ctx_destroy (sdr_ctx); + } +-#else /* HAVE_FREEIPMI_11X_12X */ +- if (sdr_cache_ctx) { +- ipmi_sdr_cache_ctx_destroy (sdr_cache_ctx); +- } + ++#ifndef HAVE_FREEIPMI_11X_12X + if (sdr_parse_ctx) { + ipmi_sdr_parse_ctx_destroy (sdr_parse_ctx); + } +-#endif /* HAVE_FREEIPMI_11X_12X */ ++#endif + + if (ipmi_ctx) { + ipmi_ctx_close (ipmi_ctx); +@@ -342,7 +368,7 @@ static int libfreeipmi_get_psu_info (const void *areabuf, + + upsdebugx(1, "entering libfreeipmi_get_psu_info()"); + +- if (ipmi_fru_parse_multirecord_power_supply_information (fru_parse_ctx, ++ if (ipmi_fru_multirecord_power_supply_information (fru_ctx, + areabuf, + area_length, + &overall_capacity, +@@ -368,8 +394,8 @@ static int libfreeipmi_get_psu_info (const void *areabuf, + &total_combined_wattage, + &predictive_fail_tachometer_lower_threshold) < 0) + { +- fatalx(EXIT_FAILURE, "ipmi_fru_parse_multirecord_power_supply_information: %s", +- ipmi_fru_parse_ctx_errormsg (fru_parse_ctx)); ++ fatalx(EXIT_FAILURE, "ipmi_fru_multirecord_power_supply_information: %s", ++ ipmi_fru_ctx_errormsg (fru_ctx)); + } + + ipmi_dev->overall_capacity = overall_capacity; +@@ -383,6 +409,8 @@ static int libfreeipmi_get_psu_info (const void *areabuf, + + ipmi_dev->voltage = libfreeipmi_get_voltage(voltage_1); + ++ upsdebugx(1, "libfreeipmi_get_psu_info() retrieved successfully"); ++ + return (0); + } + +@@ -392,12 +420,12 @@ static int libfreeipmi_get_board_info (const void *areabuf, + { + uint8_t language_code; + uint32_t mfg_date_time; +- ipmi_fru_parse_field_t board_manufacturer; +- ipmi_fru_parse_field_t board_product_name; +- ipmi_fru_parse_field_t board_serial_number; +- ipmi_fru_parse_field_t board_part_number; +- ipmi_fru_parse_field_t board_fru_file_id; +- ipmi_fru_parse_field_t board_custom_fields[IPMI_FRU_CUSTOM_FIELDS]; ++ ipmi_fru_field_t board_manufacturer; ++ ipmi_fru_field_t board_product_name; ++ ipmi_fru_field_t board_serial_number; ++ ipmi_fru_field_t board_part_number; ++ ipmi_fru_field_t board_fru_file_id; ++ ipmi_fru_field_t board_custom_fields[IPMI_FRU_CUSTOM_FIELDS]; + const char *string = NULL; + time_t timetmp; + struct tm mfg_date_time_tm; +@@ -406,15 +434,15 @@ static int libfreeipmi_get_board_info (const void *areabuf, + upsdebugx(1, "entering libfreeipmi_get_board_info()"); + + /* clear fields */ +- memset (&board_manufacturer, '\0', sizeof (ipmi_fru_parse_field_t)); +- memset (&board_product_name, '\0', sizeof (ipmi_fru_parse_field_t)); +- memset (&board_serial_number, '\0', sizeof (ipmi_fru_parse_field_t)); +- memset (&board_fru_file_id, '\0', sizeof (ipmi_fru_parse_field_t)); ++ memset (&board_manufacturer, '\0', sizeof (ipmi_fru_field_t)); ++ memset (&board_product_name, '\0', sizeof (ipmi_fru_field_t)); ++ memset (&board_serial_number, '\0', sizeof (ipmi_fru_field_t)); ++ memset (&board_fru_file_id, '\0', sizeof (ipmi_fru_field_t)); + memset (&board_custom_fields[0], '\0', +- sizeof (ipmi_fru_parse_field_t) * IPMI_FRU_CUSTOM_FIELDS); ++ sizeof (ipmi_fru_field_t) * IPMI_FRU_CUSTOM_FIELDS); + + /* parse FRU buffer */ +- if (ipmi_fru_parse_board_info_area (fru_parse_ctx, ++ if (ipmi_fru_board_info_area (fru_ctx, + areabuf, + area_length, + &language_code, +@@ -428,8 +456,8 @@ static int libfreeipmi_get_board_info (const void *areabuf, + IPMI_FRU_CUSTOM_FIELDS) < 0) + { + libfreeipmi_cleanup(); +- fatalx(EXIT_FAILURE, "ipmi_fru_parse_board_info_area: %s", +- ipmi_fru_parse_ctx_errormsg (fru_parse_ctx)); ++ fatalx(EXIT_FAILURE, "ipmi_fru_board_info_area: %s", ++ ipmi_fru_ctx_errormsg (fru_ctx)); + } + + +@@ -498,113 +526,64 @@ static int libfreeipmi_get_sensors_info (IPMIDevice_t *ipmi_dev) + ipmi_dev->sensors_count = 0; + memset(ipmi_dev->sensors_id_list, 0, sizeof(ipmi_dev->sensors_id_list)); + +-#ifdef HAVE_FREEIPMI_11X_12X + if (!(sdr_ctx = ipmi_sdr_ctx_create ())) + { + libfreeipmi_cleanup(); + fatal_with_errno(EXIT_FAILURE, "ipmi_sdr_ctx_create()"); + } + +- if (ipmi_sdr_cache_open (sdr_ctx, ipmi_ctx, CACHE_LOCATION) < 0) +- { +- if (ipmi_sdr_ctx_errnum (sdr_ctx) != IPMI_SDR_ERR_CACHE_READ_CACHE_DOES_NOT_EXIST) +- { +- libfreeipmi_cleanup(); +- fatal_with_errno(EXIT_FAILURE, "ipmi_sdr_cache_open: %s", +- ipmi_sdr_ctx_errormsg (sdr_ctx)); +- } +- } +-#else /* HAVE_FREEIPMI_11X_12X */ +- if (!(sdr_cache_ctx = ipmi_sdr_cache_ctx_create ())) +- { +- libfreeipmi_cleanup(); +- fatal_with_errno(EXIT_FAILURE, "ipmi_sdr_cache_ctx_create()"); +- } +- ++#ifndef HAVE_FREEIPMI_11X_12X + if (!(sdr_parse_ctx = ipmi_sdr_parse_ctx_create ())) + { + libfreeipmi_cleanup(); + fatal_with_errno(EXIT_FAILURE, "ipmi_sdr_parse_ctx_create()"); + } ++#endif + +- if (ipmi_sdr_cache_open (sdr_cache_ctx, ipmi_ctx, CACHE_LOCATION) < 0) ++ if (ipmi_sdr_cache_open (sdr_ctx, ipmi_ctx, CACHE_LOCATION) < 0) + { +- if (ipmi_sdr_cache_ctx_errnum (sdr_cache_ctx) != IPMI_SDR_CACHE_ERR_CACHE_READ_CACHE_DOES_NOT_EXIST) ++ if (ipmi_sdr_ctx_errnum (sdr_ctx) != IPMI_SDR_ERR_CACHE_READ_CACHE_DOES_NOT_EXIST) + { + libfreeipmi_cleanup(); + fatal_with_errno(EXIT_FAILURE, "ipmi_sdr_cache_open: %s", +- ipmi_sdr_cache_ctx_errormsg (sdr_cache_ctx)); ++ ipmi_sdr_ctx_errormsg (sdr_ctx)); + } + } +-#endif /* HAVE_FREEIPMI_11X_12X */ + +-#ifdef HAVE_FREEIPMI_11X_12X + if (ipmi_sdr_ctx_errnum (sdr_ctx) == IPMI_SDR_ERR_CACHE_READ_CACHE_DOES_NOT_EXIST) + { + if (ipmi_sdr_cache_create (sdr_ctx, + ipmi_ctx, CACHE_LOCATION, + IPMI_SDR_CACHE_CREATE_FLAGS_DEFAULT, ++#ifndef HAVE_FREEIPMI_11X_12X ++ IPMI_SDR_CACHE_VALIDATION_FLAGS_DEFAULT, ++#endif + NULL, NULL) < 0) + { + libfreeipmi_cleanup(); + fatal_with_errno(EXIT_FAILURE, "ipmi_sdr_cache_create: %s", + ipmi_sdr_ctx_errormsg (sdr_ctx)); + } +- if (ipmi_sdr_cache_open (sdr_ctx, +- ipmi_ctx, CACHE_LOCATION) < 0) ++ if (ipmi_sdr_cache_open (sdr_ctx, ipmi_ctx, CACHE_LOCATION) < 0) + { + if (ipmi_sdr_ctx_errnum (sdr_ctx) != IPMI_SDR_ERR_CACHE_READ_CACHE_DOES_NOT_EXIST) + { +- libfreeipmi_cleanup(); +- fatal_with_errno(EXIT_FAILURE, "ipmi_sdr_cache_open: %s", +- ipmi_sdr_ctx_errormsg (sdr_ctx)); +- } +- } +- } +-#else /* HAVE_FREEIPMI_11X_12X */ +- if (ipmi_sdr_cache_ctx_errnum (sdr_cache_ctx) == IPMI_SDR_CACHE_ERR_CACHE_READ_CACHE_DOES_NOT_EXIST) +- { +- if (ipmi_sdr_cache_create (sdr_cache_ctx, +- ipmi_ctx, CACHE_LOCATION, +- IPMI_SDR_CACHE_CREATE_FLAGS_DEFAULT, +- IPMI_SDR_CACHE_VALIDATION_FLAGS_DEFAULT, +- NULL, NULL) < 0) +- { +- libfreeipmi_cleanup(); +- fatal_with_errno(EXIT_FAILURE, "ipmi_sdr_cache_create: %s", +- ipmi_sdr_cache_ctx_errormsg (sdr_cache_ctx)); +- } +- if (ipmi_sdr_cache_open (sdr_cache_ctx, +- ipmi_ctx, CACHE_LOCATION) < 0) +- { +- if (ipmi_sdr_cache_ctx_errnum (sdr_cache_ctx) != IPMI_SDR_CACHE_ERR_CACHE_READ_CACHE_DOES_NOT_EXIST) +- { +- libfreeipmi_cleanup(); +- fatal_with_errno(EXIT_FAILURE, "ipmi_sdr_cache_open: %s", +- ipmi_sdr_cache_ctx_errormsg (sdr_cache_ctx)); ++ libfreeipmi_cleanup(); ++ fatal_with_errno(EXIT_FAILURE, "ipmi_sdr_cache_open: %s", ++ ipmi_sdr_ctx_errormsg (sdr_ctx)); + } + } + } +-#endif /* HAVE_FREEIPMI_11X_12X */ + +-#ifdef HAVE_FREEIPMI_11X_12X +- if (ipmi_sdr_cache_record_count (sdr_ctx, &record_count) < 0) { ++ if (ipmi_sdr_cache_record_count (sdr_ctx, &record_count) < 0) { + fprintf (stderr, +- "ipmi_sdr_cache_record_count: %s", ++ "ipmi_sdr_cache_record_count: %s\n", + ipmi_sdr_ctx_errormsg (sdr_ctx)); + goto cleanup; + } +-#else +- if (ipmi_sdr_cache_record_count (sdr_cache_ctx, &record_count) < 0) +- { +- fprintf (stderr, +- "ipmi_sdr_cache_record_count: %s", +- ipmi_sdr_cache_ctx_errormsg (sdr_cache_ctx)); +- goto cleanup; +- } +-#endif /* HAVE_FREEIPMI_11X_12X */ + +-#ifdef HAVE_FREEIPMI_11X_12X ++ upsdebugx(3, "Found %i records in SDR cache", record_count); ++ + for (i = 0; i < record_count; i++, ipmi_sdr_cache_next (sdr_ctx)) + { + memset (sdr_record, '\0', IPMI_SDR_MAX_RECORD_LENGTH); +@@ -613,50 +592,29 @@ static int libfreeipmi_get_sensors_info (IPMIDevice_t *ipmi_dev) + sdr_record, + IPMI_SDR_MAX_RECORD_LENGTH)) < 0) + { +- fprintf (stderr, "ipmi_sdr_cache_record_read: %s", ++ fprintf (stderr, "ipmi_sdr_cache_record_read: %s\n", + ipmi_sdr_ctx_errormsg (sdr_ctx)); + goto cleanup; + } +- if (ipmi_sdr_parse_record_id_and_type (sdr_ctx, ++ if (ipmi_sdr_parse_record_id_and_type (SDR_PARSE_CTX, + sdr_record, + sdr_record_len, + NULL, + &record_type) < 0) + { +- fprintf (stderr, "ipmi_sdr_parse_record_id_and_type: %s", ++ fprintf (stderr, "ipmi_sdr_parse_record_id_and_type: %s\n", + ipmi_sdr_ctx_errormsg (sdr_ctx)); + goto cleanup; + } +-#else +- for (i = 0; i < record_count; i++, ipmi_sdr_cache_next (sdr_cache_ctx)) +- { +- memset (sdr_record, '\0', IPMI_SDR_MAX_RECORD_LENGTH); + +- if ((sdr_record_len = ipmi_sdr_cache_record_read (sdr_cache_ctx, +- sdr_record, +- IPMI_SDR_MAX_RECORD_LENGTH)) < 0) +- { +- fprintf (stderr, "ipmi_sdr_cache_record_read: %s", +- ipmi_sdr_cache_ctx_errormsg (sdr_cache_ctx)); +- goto cleanup; +- } +- if (ipmi_sdr_parse_record_id_and_type (sdr_parse_ctx, +- sdr_record, +- sdr_record_len, +- NULL, +- &record_type) < 0) +- { +- fprintf (stderr, "ipmi_sdr_parse_record_id_and_type: %s", +- ipmi_sdr_parse_ctx_errormsg (sdr_parse_ctx)); +- goto cleanup; +- } +-#endif /* HAVE_FREEIPMI_11X_12X */ ++ upsdebugx (5, "Checking record %i (/%i)", i, record_count); + +- if (record_type != IPMI_SDR_FORMAT_FRU_DEVICE_LOCATOR_RECORD) ++ if (record_type != IPMI_SDR_FORMAT_FRU_DEVICE_LOCATOR_RECORD) { ++ upsdebugx(1, "=======> not device locator (%i)!!", record_type); + continue; ++ } + +-#ifdef HAVE_FREEIPMI_11X_12X +- if (ipmi_sdr_parse_fru_device_locator_parameters (sdr_ctx, ++ if (ipmi_sdr_parse_fru_device_locator_parameters (SDR_PARSE_CTX, + sdr_record, + sdr_record_len, + NULL, +@@ -666,86 +624,49 @@ static int libfreeipmi_get_sensors_info (IPMIDevice_t *ipmi_dev) + &logical_physical_fru_device, + NULL) < 0) + { +- fprintf (stderr, "ipmi_sdr_parse_fru_device_locator_parameters: %s", ++ fprintf (stderr, "ipmi_sdr_parse_fru_device_locator_parameters: %s\n", + ipmi_sdr_ctx_errormsg (sdr_ctx)); + goto cleanup; + } +-#else /* HAVE_FREEIPMI_11X_12X */ +- if (ipmi_sdr_parse_fru_device_locator_parameters (sdr_parse_ctx, +- sdr_record, +- sdr_record_len, +- NULL, +- &logical_fru_device_device_slave_address, +- NULL, +- NULL, +- &logical_physical_fru_device, +- NULL) < 0) +- { +- fprintf (stderr, "ipmi_sdr_parse_fru_device_locator_parameters: %s", +- ipmi_sdr_parse_ctx_errormsg (sdr_parse_ctx)); +- goto cleanup; +- } +-#endif /* HAVE_FREEIPMI_11X_12X */ ++ ++ upsdebugx(2, "Checking device %i/%i", logical_physical_fru_device, ++ logical_fru_device_device_slave_address); + + if (logical_physical_fru_device + && logical_fru_device_device_slave_address == ipmi_dev->ipmi_id) + { + found_device_id++; + +-#ifdef HAVE_FREEIPMI_11X_12X +- if (ipmi_sdr_parse_fru_entity_id_and_instance (sdr_ctx, ++ if (ipmi_sdr_parse_fru_entity_id_and_instance (SDR_PARSE_CTX, + sdr_record, + sdr_record_len, + &entity_id, + &entity_instance) < 0) + { + fprintf (stderr, +- "ipmi_sdr_parse_fru_entity_id_and_instance: %s", ++ "ipmi_sdr_parse_fru_entity_id_and_instance: %s\n", + ipmi_sdr_ctx_errormsg (sdr_ctx)); + goto cleanup; + } +-#else /* HAVE_FREEIPMI_11X_12X */ +- if (ipmi_sdr_parse_fru_entity_id_and_instance (sdr_parse_ctx, +- sdr_record, +- sdr_record_len, +- &entity_id, +- &entity_instance) < 0) +- { +- fprintf (stderr, +- "ipmi_sdr_parse_fru_entity_id_and_instance: %s", +- ipmi_sdr_parse_ctx_errormsg (sdr_parse_ctx)); +- goto cleanup; +- } +-#endif /* HAVE_FREEIPMI_11X_12X */ + break; + } + } + + if (!found_device_id) + { +- fprintf (stderr, "Couldn't find device id %d", ipmi_dev->ipmi_id); ++ fprintf (stderr, "Couldn't find device id %d\n", ipmi_dev->ipmi_id); + goto cleanup; + } + else + upsdebugx(1, "Found device id %d", ipmi_dev->ipmi_id); + +-#ifdef HAVE_FREEIPMI_11X_12X + if (ipmi_sdr_cache_first (sdr_ctx) < 0) + { +- fprintf (stderr, "ipmi_sdr_cache_first: %s", ++ fprintf (stderr, "ipmi_sdr_cache_first: %s\n", + ipmi_sdr_ctx_errormsg (sdr_ctx)); + goto cleanup; + } +-#else /* HAVE_FREEIPMI_11X_12X */ +- if (ipmi_sdr_cache_first (sdr_cache_ctx) < 0) +- { +- fprintf (stderr, "ipmi_sdr_cache_first: %s", +- ipmi_sdr_cache_ctx_errormsg (sdr_cache_ctx)); +- goto cleanup; +- } +-#endif /* HAVE_FREEIPMI_11X_12X */ + +-#ifdef HAVE_FREEIPMI_11X_12X + for (i = 0; i < record_count; i++, ipmi_sdr_cache_next (sdr_ctx)) + { + /* uint8_t sdr_record[IPMI_SDR_CACHE_MAX_SDR_RECORD_LENGTH]; +@@ -757,49 +678,21 @@ static int libfreeipmi_get_sensors_info (IPMIDevice_t *ipmi_dev) + sdr_record, + IPMI_SDR_MAX_RECORD_LENGTH)) < 0) + { +- fprintf (stderr, "ipmi_sdr_cache_record_read: %s", ++ fprintf (stderr, "ipmi_sdr_cache_record_read: %s\n", + ipmi_sdr_ctx_errormsg (sdr_ctx)); + goto cleanup; + } + +- if (ipmi_sdr_parse_record_id_and_type (sdr_ctx, ++ if (ipmi_sdr_parse_record_id_and_type (SDR_PARSE_CTX, + sdr_record, + sdr_record_len, + &record_id, + &record_type) < 0) + { +- fprintf (stderr, "ipmi_sdr_parse_record_id_and_type: %s", ++ fprintf (stderr, "ipmi_sdr_parse_record_id_and_type: %s\n", + ipmi_sdr_ctx_errormsg (sdr_ctx)); + goto cleanup; + } +-#else /* HAVE_FREEIPMI_11X_12X */ +- for (i = 0; i < record_count; i++, ipmi_sdr_cache_next (sdr_cache_ctx)) +- { +- /* uint8_t sdr_record[IPMI_SDR_CACHE_MAX_SDR_RECORD_LENGTH]; +- uint8_t record_type, tmp_entity_id, tmp_entity_instance; +- int sdr_record_len; */ +- +- memset (sdr_record, '\0', IPMI_SDR_MAX_RECORD_LENGTH); +- if ((sdr_record_len = ipmi_sdr_cache_record_read (sdr_cache_ctx, +- sdr_record, +- IPMI_SDR_MAX_RECORD_LENGTH)) < 0) +- { +- fprintf (stderr, "ipmi_sdr_cache_record_read: %s", +- ipmi_sdr_cache_ctx_errormsg (sdr_cache_ctx)); +- goto cleanup; +- } +- +- if (ipmi_sdr_parse_record_id_and_type (sdr_parse_ctx, +- sdr_record, +- sdr_record_len, +- &record_id, +- &record_type) < 0) +- { +- fprintf (stderr, "ipmi_sdr_parse_record_id_and_type: %s", +- ipmi_sdr_parse_ctx_errormsg (sdr_parse_ctx)); +- goto cleanup; +- } +-#endif /* HAVE_FREEIPMI_11X_12X */ + + upsdebugx (5, "Checking record %i (/%i)", record_id, record_count); + +@@ -809,31 +702,17 @@ static int libfreeipmi_get_sensors_info (IPMIDevice_t *ipmi_dev) + continue; + } + +-#ifdef HAVE_FREEIPMI_11X_12X +- if (ipmi_sdr_parse_entity_id_instance_type (sdr_ctx, ++ if (ipmi_sdr_parse_entity_id_instance_type (SDR_PARSE_CTX, + sdr_record, + sdr_record_len, + &tmp_entity_id, + &tmp_entity_instance, + NULL) < 0) + { +- fprintf (stderr, "ipmi_sdr_parse_entity_instance_type: %s", ++ fprintf (stderr, "ipmi_sdr_parse_entity_instance_type: %s\n", + ipmi_sdr_ctx_errormsg (sdr_ctx)); + goto cleanup; + } +-#else /* HAVE_FREEIPMI_11X_12X */ +- if (ipmi_sdr_parse_entity_id_instance_type (sdr_parse_ctx, +- sdr_record, +- sdr_record_len, +- &tmp_entity_id, +- &tmp_entity_instance, +- NULL) < 0) +- { +- fprintf (stderr, "ipmi_sdr_parse_entity_instance_type: %s", +- ipmi_sdr_parse_ctx_errormsg (sdr_parse_ctx)); +- goto cleanup; +- } +-#endif /* HAVE_FREEIPMI_11X_12X */ + + if (tmp_entity_id == entity_id + && tmp_entity_instance == entity_instance) +@@ -850,15 +729,11 @@ static int libfreeipmi_get_sensors_info (IPMIDevice_t *ipmi_dev) + + cleanup: + /* Cleanup */ +-#ifdef HAVE_FREEIPMI_11X_12X + if (sdr_ctx) { + ipmi_sdr_ctx_destroy (sdr_ctx); + } +-#else /* HAVE_FREEIPMI_11X_12X */ +- if (sdr_cache_ctx) { +- ipmi_sdr_cache_ctx_destroy (sdr_cache_ctx); +- } + ++#ifndef HAVE_FREEIPMI_11X_12X + if (sdr_parse_ctx) { + ipmi_sdr_parse_ctx_destroy (sdr_parse_ctx); + } +diff --git a/m4/nut_check_libfreeipmi.m4 b/m4/nut_check_libfreeipmi.m4 +index 72e7819..5b2eae9 100644 +--- a/m4/nut_check_libfreeipmi.m4 ++++ b/m4/nut_check_libfreeipmi.m4 +@@ -66,7 +66,6 @@ if test -z "${nut_have_libfreeipmi_seen}"; then + dnl when version cannot be tested (prior to 1.0.5, with no pkg-config) + dnl we have to check for some specific functions + AC_SEARCH_LIBS([ipmi_ctx_find_inband], [freeipmi], [], [nut_have_freeipmi=no]) +- AC_SEARCH_LIBS([ipmi_fru_parse_ctx_create], [freeipmi], [], [nut_have_freeipmi=no]) + + AC_SEARCH_LIBS([ipmi_monitoring_init], [ipmimonitoring], [nut_have_freeipmi_monitoring=yes], [nut_have_freeipmi_monitoring=no]) + AC_SEARCH_LIBS([ipmi_monitoring_sensor_read_record_id], [ipmimonitoring], [], [nut_have_freeipmi_monitoring=no]) +diff --git a/tools/nut-scanner/scan_ipmi.c b/tools/nut-scanner/scan_ipmi.c +index d650efa..c1ec78a 100644 +--- a/tools/nut-scanner/scan_ipmi.c ++++ b/tools/nut-scanner/scan_ipmi.c +@@ -34,24 +34,51 @@ static char * libname = "libfreeipmi"; + static lt_dlhandle dl_handle = NULL; + static const char *dl_error = NULL; + +-static int (*nut_ipmi_fru_parse_close_device_id) (ipmi_fru_parse_ctx_t ctx); +-static void (*nut_ipmi_fru_parse_ctx_destroy) (ipmi_fru_parse_ctx_t ctx); + #ifdef HAVE_FREEIPMI_11X_12X +-static void (*nut_ipmi_sdr_ctx_destroy) (ipmi_sdr_ctx_t ctx); ++ /* Functions symbols remapping */ ++ #define IPMI_FRU_CLOSE_DEVICE_ID "ipmi_fru_close_device_id" ++ #define IPMI_FRU_CTX_DESTROY "ipmi_fru_ctx_destroy" ++ #define IPMI_FRU_CTX_CREATE "ipmi_fru_ctx_create" ++ #define IPMI_FRU_CTX_SET_FLAGS "ipmi_fru_ctx_set_flags" ++ #define IPMI_FRU_OPEN_DEVICE_ID "ipmi_fru_open_device_id" ++ #define IPMI_FRU_CTX_ERRORMSG "ipmi_fru_ctx_errormsg" ++ #define IPMI_FRU_READ_DATA_AREA "ipmi_fru_read_data_area" ++ #define IPMI_FRU_PARSE_NEXT "ipmi_fru_next" ++ typedef ipmi_fru_ctx_t ipmi_fru_parse_ctx_t; ++ typedef ipmi_sdr_ctx_t ipmi_sdr_cache_ctx_t; ++ /* Functions remapping */ ++ static void (*nut_ipmi_sdr_ctx_destroy) (ipmi_sdr_ctx_t ctx); + #else /* HAVE_FREEIPMI_11X_12X */ +-static void (*nut_ipmi_sdr_cache_ctx_destroy) (ipmi_sdr_cache_ctx_t ctx); +-static void (*nut_ipmi_sdr_parse_ctx_destroy) (ipmi_sdr_parse_ctx_t ctx); ++ #define IPMI_FRU_AREA_SIZE_MAX IPMI_FRU_PARSE_AREA_SIZE_MAX ++ #define IPMI_FRU_FLAGS_SKIP_CHECKSUM_CHECKS IPMI_FRU_PARSE_FLAGS_SKIP_CHECKSUM_CHECKS ++ #define IPMI_FRU_AREA_TYPE_MULTIRECORD_POWER_SUPPLY_INFORMATION IPMI_FRU_PARSE_AREA_TYPE_MULTIRECORD_POWER_SUPPLY_INFORMATION ++ /* Functions symbols remapping */ ++ #define IPMI_FRU_CLOSE_DEVICE_ID "ipmi_fru_parse_close_device_id" ++ #define IPMI_FRU_CTX_DESTROY "ipmi_fru_parse_ctx_destroy" ++ #define IPMI_FRU_CTX_CREATE "ipmi_fru_parse_ctx_create" ++ #define IPMI_FRU_CTX_SET_FLAGS "ipmi_fru_parse_ctx_set_flags" ++ #define IPMI_FRU_OPEN_DEVICE_ID "ipmi_fru_parse_open_device_id" ++ #define IPMI_FRU_CTX_ERRORMSG "ipmi_fru_parse_ctx_errormsg" ++ #define IPMI_FRU_READ_DATA_AREA "ipmi_fru_parse_read_data_area" ++ #define IPMI_FRU_PARSE_NEXT "ipmi_fru_parse_next" ++ /* Functions remapping */ ++ static void (*nut_ipmi_sdr_cache_ctx_destroy) (ipmi_sdr_cache_ctx_t ctx); ++ static void (*nut_ipmi_sdr_parse_ctx_destroy) (ipmi_sdr_parse_ctx_t ctx); + #endif /* HAVE_FREEIPMI_11X_12X */ +-static ipmi_fru_parse_ctx_t (*nut_ipmi_fru_parse_ctx_create) (ipmi_ctx_t ipmi_ctx); +-static int (*nut_ipmi_fru_parse_ctx_set_flags) (ipmi_fru_parse_ctx_t ctx, unsigned int flags); +-static int (*nut_ipmi_fru_parse_open_device_id) (ipmi_fru_parse_ctx_t ctx, uint8_t fru_device_id); +-static char * (*nut_ipmi_fru_parse_ctx_errormsg) (ipmi_fru_parse_ctx_t ctx); +-static int (*nut_ipmi_fru_parse_read_data_area) (ipmi_fru_parse_ctx_t ctx, ++ ++ ++static int (*nut_ipmi_fru_close_device_id) (ipmi_fru_parse_ctx_t ctx); ++static void (*nut_ipmi_fru_ctx_destroy) (ipmi_fru_parse_ctx_t ctx); ++static ipmi_fru_parse_ctx_t (*nut_ipmi_fru_ctx_create) (ipmi_ctx_t ipmi_ctx); ++static int (*nut_ipmi_fru_ctx_set_flags) (ipmi_fru_parse_ctx_t ctx, unsigned int flags); ++static int (*nut_ipmi_fru_open_device_id) (ipmi_fru_parse_ctx_t ctx, uint8_t fru_device_id); ++static char * (*nut_ipmi_fru_ctx_errormsg) (ipmi_fru_parse_ctx_t ctx); ++static int (*nut_ipmi_fru_read_data_area) (ipmi_fru_parse_ctx_t ctx, + unsigned int *area_type, + unsigned int *area_length, + void *areabuf, + unsigned int areabuflen); +-static int (*nut_ipmi_fru_parse_next) (ipmi_fru_parse_ctx_t ctx); ++static int (*nut_ipmi_fru_next) (ipmi_fru_parse_ctx_t ctx); + static ipmi_ctx_t (*nut_ipmi_ctx_create) (void); + static int (*nut_ipmi_ctx_find_inband) (ipmi_ctx_t ctx, + ipmi_driver_type_t *driver_type, +@@ -92,12 +119,12 @@ int nutscan_load_ipmi_library() + /* Clear any existing error */ + lt_dlerror(); + +- *(void **) (&nut_ipmi_fru_parse_close_device_id) = lt_dlsym(dl_handle, "ipmi_fru_parse_close_device_id"); ++ *(void **) (&nut_ipmi_fru_close_device_id) = lt_dlsym(dl_handle, IPMI_FRU_CLOSE_DEVICE_ID); + if ((dl_error = lt_dlerror()) != NULL) { + goto err; + } + +- *(void **) (&nut_ipmi_fru_parse_ctx_destroy) = lt_dlsym(dl_handle, "ipmi_fru_parse_ctx_destroy"); ++ *(void **) (&nut_ipmi_fru_ctx_destroy) = lt_dlsym(dl_handle, IPMI_FRU_CTX_DESTROY); + if ((dl_error = lt_dlerror()) != NULL) { + goto err; + } +@@ -122,32 +149,32 @@ int nutscan_load_ipmi_library() + } + #endif /* HAVE_FREEIPMI_11X_12X */ + +- *(void **) (&nut_ipmi_fru_parse_ctx_create) = lt_dlsym(dl_handle, "ipmi_fru_parse_ctx_create"); ++ *(void **) (&nut_ipmi_fru_ctx_create) = lt_dlsym(dl_handle, IPMI_FRU_CTX_CREATE); + if ((dl_error = lt_dlerror()) != NULL) { + goto err; + } + +- *(void **) (&nut_ipmi_fru_parse_ctx_set_flags) = lt_dlsym(dl_handle, "ipmi_fru_parse_ctx_set_flags"); ++ *(void **) (&nut_ipmi_fru_ctx_set_flags) = lt_dlsym(dl_handle, IPMI_FRU_CTX_SET_FLAGS); + if ((dl_error = lt_dlerror()) != NULL) { + goto err; + } + +- *(void **) (&nut_ipmi_fru_parse_open_device_id) = lt_dlsym(dl_handle, "ipmi_fru_parse_open_device_id"); ++ *(void **) (&nut_ipmi_fru_open_device_id) = lt_dlsym(dl_handle, IPMI_FRU_OPEN_DEVICE_ID); + if ((dl_error = lt_dlerror()) != NULL) { + goto err; + } + +- *(void **) (&nut_ipmi_fru_parse_ctx_errormsg) = lt_dlsym(dl_handle, "ipmi_fru_parse_ctx_errormsg"); ++ *(void **) (&nut_ipmi_fru_ctx_errormsg) = lt_dlsym(dl_handle, IPMI_FRU_CTX_ERRORMSG); + if ((dl_error = lt_dlerror()) != NULL) { + goto err; + } + +- *(void **) (&nut_ipmi_fru_parse_read_data_area) = lt_dlsym(dl_handle, "ipmi_fru_parse_read_data_area"); ++ *(void **) (&nut_ipmi_fru_read_data_area) = lt_dlsym(dl_handle, IPMI_FRU_READ_DATA_AREA); + if ((dl_error = lt_dlerror()) != NULL) { + goto err; + } + +- *(void **) (&nut_ipmi_fru_parse_next) = lt_dlsym(dl_handle, "ipmi_fru_parse_next"); ++ *(void **) (&nut_ipmi_fru_next) = lt_dlsym(dl_handle, IPMI_FRU_PARSE_NEXT); + if ((dl_error = lt_dlerror()) != NULL) { + goto err; + } +@@ -179,7 +206,7 @@ int nutscan_load_ipmi_library() + + return 1; + err: +- fprintf(stderr, "Cannot load IPMI library (%s) : %s. IPMI search disabled.\n", libname, dl_error); ++ fprintf(stderr, "Cannot load IPMI library (%s) : %s. IPMI search disabled.\n", libname, dl_error); + dl_handle = (void *)1; + lt_dlexit(); + return 0; +@@ -197,8 +224,8 @@ static void nut_freeipmi_cleanup(ipmi_fru_parse_ctx_t fru_parse_ctx, + #endif /* HAVE_FREEIPMI_11X_12X */ + { + if (fru_parse_ctx) { +- (*nut_ipmi_fru_parse_close_device_id) (fru_parse_ctx); +- (*nut_ipmi_fru_parse_ctx_destroy) (fru_parse_ctx); ++ (*nut_ipmi_fru_close_device_id) (fru_parse_ctx); ++ (*nut_ipmi_fru_ctx_destroy) (fru_parse_ctx); + } + + #ifdef HAVE_FREEIPMI_11X_12X +@@ -226,7 +253,7 @@ int is_ipmi_device_supported(ipmi_ctx_t ipmi_ctx, int ipmi_id) + int ret = -1; + unsigned int area_type = 0; + unsigned int area_length = 0; +- uint8_t areabuf[IPMI_FRU_PARSE_AREA_SIZE_MAX+1]; ++ uint8_t areabuf[IPMI_FRU_AREA_SIZE_MAX+1]; + ipmi_fru_parse_ctx_t fru_parse_ctx = NULL; + #ifdef HAVE_FREEIPMI_11X_12X + ipmi_sdr_ctx_t sdr_ctx = NULL; +@@ -236,14 +263,14 @@ int is_ipmi_device_supported(ipmi_ctx_t ipmi_ctx, int ipmi_id) + #endif /* HAVE_FREEIPMI_11X_12X */ + + /* Parse FRU information */ +- if (!(fru_parse_ctx = (*nut_ipmi_fru_parse_ctx_create) (ipmi_ctx))) ++ if (!(fru_parse_ctx = (*nut_ipmi_fru_ctx_create) (ipmi_ctx))) + { + fprintf(stderr, "ipmi_fru_parse_ctx_create()\n"); + return 0; + } +- ++fprintf(stdout, "There.1\n"); + /* lots of motherboards calculate checksums incorrectly */ +- if ((*nut_ipmi_fru_parse_ctx_set_flags) (fru_parse_ctx, IPMI_FRU_PARSE_FLAGS_SKIP_CHECKSUM_CHECKS) < 0) ++ if ((*nut_ipmi_fru_ctx_set_flags) (fru_parse_ctx, IPMI_FRU_FLAGS_SKIP_CHECKSUM_CHECKS) < 0) + { + #ifdef HAVE_FREEIPMI_11X_12X + nut_freeipmi_cleanup(fru_parse_ctx, sdr_ctx); +@@ -252,8 +279,8 @@ int is_ipmi_device_supported(ipmi_ctx_t ipmi_ctx, int ipmi_id) + #endif /* HAVE_FREEIPMI_11X_12X */ + return 0; + } +- +- if ((*nut_ipmi_fru_parse_open_device_id) (fru_parse_ctx, ipmi_id) < 0) ++fprintf(stdout, "There.2\n"); ++ if ((*nut_ipmi_fru_open_device_id) (fru_parse_ctx, ipmi_id) < 0) + { + #ifdef HAVE_FREEIPMI_11X_12X + nut_freeipmi_cleanup(fru_parse_ctx, sdr_ctx); +@@ -265,17 +292,18 @@ int is_ipmi_device_supported(ipmi_ctx_t ipmi_ctx, int ipmi_id) + + do + { ++fprintf(stdout, "There.3\n"); + /* clear fields */ + area_type = 0; + area_length = 0; +- memset (areabuf, '\0', IPMI_FRU_PARSE_AREA_SIZE_MAX + 1); ++ memset (areabuf, '\0', IPMI_FRU_AREA_SIZE_MAX + 1); + + /* parse FRU buffer */ +- if ((*nut_ipmi_fru_parse_read_data_area) (fru_parse_ctx, ++ if ((*nut_ipmi_fru_read_data_area) (fru_parse_ctx, + &area_type, + &area_length, + areabuf, +- IPMI_FRU_PARSE_AREA_SIZE_MAX) < 0) ++ IPMI_FRU_AREA_SIZE_MAX) < 0) + { + #ifdef HAVE_FREEIPMI_11X_12X + nut_freeipmi_cleanup(fru_parse_ctx, sdr_ctx); +@@ -287,7 +315,7 @@ int is_ipmi_device_supported(ipmi_ctx_t ipmi_ctx, int ipmi_id) + + if (area_length) + { +- if (area_type == IPMI_FRU_PARSE_AREA_TYPE_MULTIRECORD_POWER_SUPPLY_INFORMATION) ++ if (area_type == IPMI_FRU_AREA_TYPE_MULTIRECORD_POWER_SUPPLY_INFORMATION) + { + /* Found a POWER_SUPPLY record */ + #ifdef HAVE_FREEIPMI_11X_12X +@@ -298,7 +326,7 @@ int is_ipmi_device_supported(ipmi_ctx_t ipmi_ctx, int ipmi_id) + return 1; + } + } +- } while ((ret = (*nut_ipmi_fru_parse_next) (fru_parse_ctx)) == 1); ++ } while ((ret = (*nut_ipmi_fru_next) (fru_parse_ctx)) == 1); + + /* No need for further errors checking */ + #ifdef HAVE_FREEIPMI_11X_12X +@@ -322,7 +350,7 @@ nutscan_device_t * nutscan_scan_ipmi() + if( !nutscan_avail_ipmi ) { + return NULL; + } +- ++fprintf(stdout, "There1\n"); + /* Initialize the FreeIPMI library. */ + if (!(ipmi_ctx = (*nut_ipmi_ctx_create) ())) + { +@@ -331,6 +359,7 @@ nutscan_device_t * nutscan_scan_ipmi() + return NULL; + } + ++fprintf(stdout, "There2\n"); + if ((ret = (*nut_ipmi_ctx_find_inband) (ipmi_ctx, + NULL, + 0, /* don't disable auto-probe */ +@@ -338,7 +367,7 @@ nutscan_device_t * nutscan_scan_ipmi() + 0, + NULL, + 0, /* workaround flags, none by default */ +- 0 /* flags */ ++ IPMI_FLAGS_NONBLOCKING /* flags */ + )) < 0) + { + fprintf(stderr, "ipmi_ctx_find_inband: %s\n", +@@ -350,12 +379,14 @@ nutscan_device_t * nutscan_scan_ipmi() + /* No local IPMI device detected */ + return NULL; + } ++fprintf(stdout, "There3 (ret = %i)\n", ret); + + /* Loop through all possible components */ + for (ipmi_id = 0 ; ipmi_id <= IPMI_FRU_DEVICE_ID_MAX ; ipmi_id++) { +- ++fprintf(stdout, "There4\n"); + if (is_ipmi_device_supported(ipmi_ctx, ipmi_id)) { + ++fprintf(stdout, "There4.%i\n", ipmi_id); + if ( (nut_dev = nutscan_new_device()) == NULL ) { + fprintf(stderr,"Memory allocation error\n"); + nutscan_free_device(current_nut_dev); +-- +1.7.10.2 + + +From 64add831fe9cd779f125f52782c4c58cbd62d64b Mon Sep 17 00:00:00 2001 +From: Arnaud Quette +Date: Thu, 4 Oct 2012 22:50:52 +0000 +Subject: [PATCH] Support power supplies scan over the network + +nut-scanner can now scan for power supplies with IPMI over LAN. This is +currently limited to IPMI 1.5 only + +Fossil-ID: SVN r3739 +--- + docs/man/nut-scanner.txt | 108 +++++++++-------- + drivers/nut-ipmipsu.c | 15 ++- + tools/nut-scanner/nut-scan.h | 39 ++++++- + tools/nut-scanner/nut-scanner.c | 74 +++++++++++- + tools/nut-scanner/scan_ipmi.c | 243 ++++++++++++++++++++++++++++++++++----- + 5 files changed, 388 insertions(+), 91 deletions(-) + +diff --git a/docs/man/nut-scanner.txt b/docs/man/nut-scanner.txt +index 6948449..efe0e58 100644 +--- a/docs/man/nut-scanner.txt ++++ b/docs/man/nut-scanner.txt +@@ -36,118 +36,128 @@ DISPLAY OPTIONS + --------------- + + *-N* | *--disp_nut_conf*:: +- +- Display result in the 'ups.conf' format. ++Display result in the 'ups.conf' format. + + *-P* | *--disp_parsable*:: +- +- Display result in a parsable format. ++Display result in a parsable format. + + BUS OPTIONS + ----------- + + *-C* | *--complete_scan*:: +- +- Scan all available communication buses (default behavior) ++Scan all available communication buses (default behavior) + + *-U* | *--usb_scan*:: +- +- List all NUT-compatible USB devices currently plugged in. ++List all NUT-compatible USB devices currently plugged in. + + *-S* | *--snmp_scan*:: +- +- Scan SNMP devices. Requires at least a 'start IP', and optionally, an 'end IP'. See specific SNMP OPTIONS for community and security settings. ++Scan SNMP devices. Requires at least a 'start IP', and optionally, an 'end IP'. See specific SNMP OPTIONS for community and security settings. + + *-M* | *--xml_scan*:: +- +- Scan XML/HTTP devices. Broadcast a network message on the current network interfaces to retrieve XML/HTTP capable devices. No IP required. ++Scan XML/HTTP devices. Broadcast a network message on the current network interfaces to retrieve XML/HTTP capable devices. No IP required. + + *-O* | *--oldnut_scan*:: +- +- Scan NUT devices (i.e. upsd daemon) on IP ranging from 'start IP' to 'end IP'. ++Scan NUT devices (i.e. upsd daemon) on IP ranging from 'start IP' to 'end IP'. + + *-A* | *--avahi_scan*:: +- +- Scan NUT servers using Avahi request on the current network interfaces. No IP required. ++Scan NUT servers using Avahi request on the current network interfaces. No IP required. + + *-I* | *--ipmi_scan*:: +- +- Scan NUT compatible devices available via IPMI on the current host. ++Scan NUT compatible power supplies available via IPMI on the current host, or over the network. + + NETWORK OPTIONS + --------------- + + *-t* | *--timeout* 'timeout':: +- +- Set the network timeout in seconds. Default timeout is 5 seconds. ++Set the network timeout in seconds. Default timeout is 5 seconds. + + *-s* | *--start_ip* 'start IP':: +- +- Set the first IP (IPv4 or IPv6) when a range of IP is required (SNMP, old_nut). ++Set the first IP (IPv4 or IPv6) when a range of IP is required (SNMP, old_nut). + + *-e* | *--end_ip* 'end IP':: +- +- Set the last IP (IPv4 or IPv6) when a range of IP is required (SNMP, old_nut). If this parameter is omitted, only the 'start IP' is scanned. If 'end IP' is less than 'start IP', both parameters are internally permuted. ++Set the last IP (IPv4 or IPv6) when a range of IP is required (SNMP, old_nut). If this parameter is omitted, only the 'start IP' is scanned. If 'end IP' is less than 'start IP', both parameters are internally permuted. + + *-m* | *--mask_cidr* 'IP address/mask':: +- +- Set a range of IP using CIDR notation. ++Set a range of IP using CIDR notation. + + NUT DEVICE OPTION + ----------------- + + *-p* | *--port* 'port number':: +- +- Set the port number of scanned NUT devices (default 3493). ++Set the port number of scanned NUT devices (default 3493). + + SNMP V1 OPTION + -------------- + + *-c* | *--community* 'community':: +- +- Set SNMP v1 community name (default = public). ++Set SNMP v1 community name (default = public). + + SNMP V3 OPTIONS + --------------- + + *-l* | *--secLevel* 'security level':: +- +- Set the 'security level' used for SNMPv3 messages. Allowed values are: noAuthNoPriv, authNoPriv and authPriv. ++Set the 'security level' used for SNMPv3 messages. Allowed values are: noAuthNoPriv, authNoPriv and authPriv. + + *-u* | *--secName* 'security name':: +- +- Set the 'security name' used for authenticated SNMPv3 messages. This parameter is mandatory if you set 'security level'. ++Set the 'security name' used for authenticated SNMPv3 messages. This parameter is mandatory if you set 'security level'. + + *-w* | *--authProtocol* 'authentication protocol':: +- +- Set the 'authentication protocol' used for authenticated SNMPv3 messages. Allowed values are MD5 or SHA. Default value is MD5. ++Set the 'authentication protocol' used for authenticated SNMPv3 messages. Allowed values are MD5 or SHA. Default value is MD5. + + *-W* | *--authPassword* 'authentication pass phrase':: +- +- Set the 'authentication pass phrase' used for authenticated SNMPv3 messages. This parameter is mandatory if you set 'security level' to authNoPriv or authPriv. ++Set the 'authentication pass phrase' used for authenticated SNMPv3 messages. This parameter is mandatory if you set 'security level' to authNoPriv or authPriv. + + *-x* | *--privProtocol* 'privacy protocol':: +- +- Set the 'privacy protocol' used for encrypted SNMPv3 messages. Allowed values are DES or AES. Default value is DES. ++Set the 'privacy protocol' used for encrypted SNMPv3 messages. Allowed values are DES or AES. Default value is DES. + + *-X* | *--privPassword* 'privacy pass phrase':: ++Set the 'privacy pass phrase' used for encrypted SNMPv3 messages. This parameter is mandatory if you set 'security level' to authPriv. + +- Set the 'privacy pass phrase' used for encrypted SNMPv3 messages. This parameter is mandatory if you set 'security level' to authPriv. ++IPMI OPTIONS ++------------ ++ ++*-b* | *--username* 'username':: ++Set the username used for authenticating IPMI over LAN connections (mandatory for IPMI over LAN. No default). ++ ++*-B* | *--password* 'password':: ++Specify the password to use when authenticationg with the remote host (mandatory for IPMI over LAN. No default). ++ ++*-d* | *--authType* 'authentication type':: ++Specify the IPMI 1.5 authentication type to use (NONE, STRAIGHT_PASSWORD_KEY, MD2, and MD5) with the remote host (default=MD5). ++This forces connection through the 'lan' IPMI interface , thus in IPMI 1.5 mode. ++ ++*-D* | *--cipher_suite_id* 'cipher suite identifier':: ++Specify the IPMI 2.0 cipher suite ID to use. The Cipher Suite ID identifies a set of authentication, integrity, and ++confidentiality algorithms to use for IPMI 2.0 communication. The authentication algorithm identifies the algorithm ++to use for session setup, the integrity algorithm identifies the algorithm to use for session packet signatures, and the ++confidentiality algorithm identifies the algorithm to use for payload encryption (default=3). +++ ++The following cipher suite ids are currently supported (Authentication; Integrity; Confidentiality): ++ ++- *0*: None; None; None ++- *1*: HMAC-SHA1; None; None ++- *2*: HMAC-SHA1; HMAC-SHA1-96; None ++- *3*: HMAC-SHA1; HMAC-SHA1-96; AES-CBC-128 ++- *6*: HMAC-MD5; None; None ++- *7*: HMAC-MD5; HMAC-MD5-128; None ++- *8*: HMAC-MD5; HMAC-MD5-128; AES-CBC-128 ++- *11*: HMAC-MD5; MD5-128; None ++- *12*: HMAC-MD5; MD5-128; AES-CBC-128 ++- *15*: HMAC-SHA256; None; None ++- *16*: HMAC-SHA256; HMAC_SHA256_128; None ++- *17*: HMAC-SHA256; HMAC_SHA256_128; AES-CBC-128 + + MISCELLANEOUS OPTIONS + --------------------- + + *-V* | *--version*:: +- +- Display NUT version. ++Display NUT version. + + *-a* | *--available*:: +- +- Display available bus that can be scanned , depending on how the binary has been compiled. (OLDNUT, USB, SNMP, XML, AVAHI, IPMI). ++Display available bus that can be scanned , depending on how the binary has been compiled. (OLDNUT, USB, SNMP, XML, AVAHI, IPMI). + + *-q* | *--quiet*:: +- +- Display only scan result. No information on currently scanned bus is displayed. ++Display only scan result. No information on currently scanned bus is displayed. + + EXAMPLES + -------- +@@ -168,6 +178,10 @@ To scan NUT servers with a timeout of 10 seconds on IP range 192.168.0.0 to 192. + + *nut-scanner -O -t 10 -m 192.168.0.0/25* + ++To scan for power supplies, through IPMI (1.5 mode) over the network, on address range 192.168.0.0 to 192.168.0.255: ++ ++*nut-scanner -I -m 192.168.0.0/24 -b username -B password* ++ + SEE ALSO + -------- + +diff --git a/drivers/nut-ipmipsu.c b/drivers/nut-ipmipsu.c +index b7382a8..2991cfc 100644 +--- a/drivers/nut-ipmipsu.c ++++ b/drivers/nut-ipmipsu.c +@@ -27,7 +27,7 @@ + #include "nut-ipmi.h" + + #define DRIVER_NAME "IPMI PSU driver" +-#define DRIVER_VERSION "0.07" ++#define DRIVER_VERSION "0.30" + + /* driver description structure */ + upsdrv_info_t upsdrv_info = { +@@ -183,17 +183,20 @@ void upsdrv_makevartable(void) + "Type of the device to match ('psu' for \"Power Supply\")"); + + addvar(VAR_VALUE, "serial", "Serial number to match a specific device"); +- addvar(VAR_VALUE, "fruid", "FRU identifier to match a specific device"); +- addvar(VAR_VALUE, "sensorid", "Sensor identifier to match a specific device"); */ ++ addvar(VAR_VALUE, "fruid", "FRU identifier to match a specific device"); */ + } + + void upsdrv_initups(void) + { + upsdebugx(1, "upsdrv_initups..."); + +- /* port can be expressed using: +- * "id?" for device (FRU) ID 0x? +- * "psu?" for PSU number ? ++ /* port can be expressed in various forms: ++ * - inband: ++ * "id?" for device (FRU) ID 0x? ++ * "psu?" for PSU number ? ++ * - out of band ++ * "id?@host" ++ * "host" => requires serial or ... + */ + if (!strncmp( device_path, "id", 2)) + { +diff --git a/tools/nut-scanner/nut-scan.h b/tools/nut-scanner/nut-scan.h +index affcc77..8b9f1ab 100644 +--- a/tools/nut-scanner/nut-scan.h ++++ b/tools/nut-scanner/nut-scan.h +@@ -1,6 +1,8 @@ + /* nut-scan.h: detect NUT services + * +- * Copyright (C) 2011 - Frederic Bohe ++ * Copyright (C) ++ * 2011 - Frederic Bohe ++ * 2012 - Arnaud Quette + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by +@@ -16,6 +18,7 @@ + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ ++ + #ifndef NUT_SCAN_H + #define NUT_SCAN_H + +@@ -23,6 +26,10 @@ + #include + #include + ++#ifdef WITH_IPMI ++#include ++#endif ++ + /* SNMP structure */ + typedef struct nutscan_snmp { + char * community; +@@ -36,8 +43,34 @@ typedef struct nutscan_snmp { + void * handle; + } nutscan_snmp_t; + ++/* IPMI structure */ ++/* Settings for OutofBand (remote) connection */ ++typedef struct nutscan_ipmi { ++ char* username; /* IPMI 1.5 and 2.0 */ ++ char* password; /* IPMI 1.5 and 2.0 */ ++ int authentication_type; /* IPMI 1.5 */ ++ int cipher_suite_id; /* IPMI 2.0 */ ++ char* K_g_BMC_key; /* IPMI 2.0, optional key for 2 key auth. */ ++ int privilege_level; /* for both */ ++ unsigned int workaround_flags; /* for both */ ++ int ipmi_version; /* IPMI 1.5 or 2.0? */ ++} nutscan_ipmi_t; ++ ++/* IPMI auth defines, simply using FreeIPMI defines */ ++#ifndef IPMI_AUTHENTICATION_TYPE_NONE ++ #define IPMI_AUTHENTICATION_TYPE_NONE 0x00 ++ #define IPMI_AUTHENTICATION_TYPE_MD2 0x01 ++ #define IPMI_AUTHENTICATION_TYPE_MD5 0x02 ++ #define IPMI_AUTHENTICATION_TYPE_STRAIGHT_PASSWORD_KEY 0x04 ++ #define IPMI_AUTHENTICATION_TYPE_OEM_PROP 0x05 ++ #define IPMI_AUTHENTICATION_TYPE_RMCPPLUS 0x06 ++#endif /* IPMI_AUTHENTICATION_TYPE_NONE */ ++ ++#define IPMI_1_5 1 ++#define IPMI_2_0 0 ++ + /* Scanning */ +-nutscan_device_t * nutscan_scan_snmp(const char * start_ip,const char * stop_ip,long usec_timeout, nutscan_snmp_t * sec); ++nutscan_device_t * nutscan_scan_snmp(const char * start_ip, const char * stop_ip, long usec_timeout, nutscan_snmp_t * sec); + + nutscan_device_t * nutscan_scan_usb(); + +@@ -47,7 +80,7 @@ nutscan_device_t * nutscan_scan_nut(const char * startIP, const char * stopIP, c + + nutscan_device_t * nutscan_scan_avahi(long usec_timeout); + +-nutscan_device_t * nutscan_scan_ipmi(void); ++nutscan_device_t * nutscan_scan_ipmi(const char * startIP, const char * stopIP, nutscan_ipmi_t * sec); + + /* Display functions */ + void nutscan_display_ups_conf(nutscan_device_t * device); +diff --git a/tools/nut-scanner/nut-scanner.c b/tools/nut-scanner/nut-scanner.c +index 52e0da7..7ca1554 100644 +--- a/tools/nut-scanner/nut-scanner.c ++++ b/tools/nut-scanner/nut-scanner.c +@@ -35,7 +35,7 @@ + + #define ERR_BAD_OPTION (-1) + +-const char optstring[] = "?ht:s:e:c:l:u:W:X:w:x:p:CUSMOAm:NPqIVa"; ++const char optstring[] = "?ht:s:e:c:l:u:W:X:w:x:p:b:B:d:D:CUSMOAm:NPqIVa"; + + #ifdef HAVE_GETOPT_LONG + const struct option longopts[] = +@@ -50,6 +50,10 @@ const struct option longopts[] = + { "privPassword",required_argument,NULL,'X' }, + { "authProtocol",required_argument,NULL,'w' }, + { "privProtocol",required_argument,NULL,'x' }, ++ { "username",required_argument,NULL,'b' }, ++ { "password",required_argument,NULL,'B' }, ++ { "authType",required_argument,NULL,'d' }, ++ { "cipher_suite_id",required_argument,NULL,'D' }, + { "port",required_argument,NULL,'p' }, + { "complete_scan",no_argument,NULL,'C' }, + { "usb_scan",no_argument,NULL,'U' }, +@@ -110,7 +114,9 @@ static void * run_avahi(void * arg) + } + static void * run_ipmi(void * arg) + { +- dev[TYPE_IPMI] = nutscan_scan_ipmi(); ++ nutscan_ipmi_t * sec = (nutscan_ipmi_t *)arg; ++ ++ dev[TYPE_IPMI] = nutscan_scan_ipmi(start_ip,end_ip,sec); + return NULL; + } + #endif /* HAVE_PTHREAD */ +@@ -133,6 +139,7 @@ static int printq(int quiet,const char *fmt, ...) + int main(int argc, char *argv[]) + { + nutscan_snmp_t snmp_sec; ++ nutscan_ipmi_t ipmi_sec; + int opt_ret; + char * cidr = NULL; + int allow_all = 0; +@@ -147,6 +154,12 @@ int main(int argc, char *argv[]) + int ret_code = EXIT_SUCCESS; + + memset(&snmp_sec, 0, sizeof(snmp_sec)); ++ memset(&ipmi_sec, 0, sizeof(ipmi_sec)); ++ /* Set the default values for IPMI */ ++ ipmi_sec.authentication_type = IPMI_AUTHENTICATION_TYPE_MD5; ++ ipmi_sec.ipmi_version = IPMI_1_5; /* default to IPMI 1.5, if not otherwise specified */ ++ ipmi_sec.cipher_suite_id = 3; /* default to HMAC-SHA1; HMAC-SHA1-96; AES-CBC-128 */ ++ ipmi_sec.privilege_level = IPMI_PRIVILEGE_LEVEL_ADMIN; /* should be sufficient */ + + nutscan_init(); + +@@ -220,6 +233,45 @@ int main(int argc, char *argv[]) + } + allow_snmp = 1; + break; ++ case 'b': ++ if(!nutscan_avail_ipmi) { ++ goto display_help; ++ } ++ ipmi_sec.username = strdup(optarg); ++ break; ++ case 'B': ++ if(!nutscan_avail_ipmi) { ++ goto display_help; ++ } ++ ipmi_sec.password = strdup(optarg); ++ break; ++ case 'd': ++ if(!nutscan_avail_ipmi) { ++ goto display_help; ++ } ++ if (!strcmp(optarg, "NONE")) { ++ ipmi_sec.authentication_type = IPMI_AUTHENTICATION_TYPE_NONE; ++ } ++ else if (!strcmp(optarg, "STRAIGHT_PASSWORD_KEY")) { ++ ipmi_sec.authentication_type = IPMI_AUTHENTICATION_TYPE_STRAIGHT_PASSWORD_KEY; ++ } ++ else if (!strcmp(optarg, "MD2")) { ++ ipmi_sec.authentication_type = IPMI_AUTHENTICATION_TYPE_MD2; ++ } ++ else if (!strcmp(optarg, "MD5")) { ++ ipmi_sec.authentication_type = IPMI_AUTHENTICATION_TYPE_MD5; ++ } ++ else { ++ fprintf(stderr,"Unknown authentication type (%s). Defaulting to MD5\n", optarg); ++ } ++ break; ++ case 'D': ++ if(!nutscan_avail_ipmi) { ++ goto display_help; ++ } ++ ipmi_sec.cipher_suite_id = atoi(optarg); ++ /* Force IPMI 2.0! */ ++ ipmi_sec.ipmi_version = IPMI_2_0; + case 'p': + port = strdup(optarg); + break; +@@ -307,6 +359,8 @@ display_help: + if( nutscan_avail_ipmi ) { + printf(" -I, --ipmi_scan: Scan IPMI devices.\n"); + } ++ ++ printf("\nNetwork specific options:\n"); + printf(" -t, --timeout : network operation timeout (default %d).\n",DEFAULT_TIMEOUT); + printf(" -s, --start_ip : First IP address to scan.\n"); + printf(" -e, --end_ip : Last IP address to scan.\n"); +@@ -325,6 +379,18 @@ display_help: + printf(" -X, --privPassword : Set the privacy pass phrase used for encrypted SNMPv3 messages (mandatory if you set secLevel to authPriv)\n"); + } + ++ if( nutscan_avail_ipmi ) { ++ printf("\nIPMI over LAN specific options:\n"); ++ printf(" -b, --username : Set the username used for authenticating IPMI over LAN connections (mandatory for IPMI over LAN. No default)\n"); ++ /* Specify the username to use when authenticating with the remote host. If not specified, a null (i.e. anonymous) username is assumed. The user must have ++ * at least ADMIN privileges in order for this tool to operate fully. */ ++ printf(" -B, --password : Specify the password to use when authenticationg with the remote host (mandatory for IPMI over LAN. No default)\n"); ++ /* Specify the password to use when authenticationg with the remote host. If not specified, a null password is assumed. Maximum password length is 16 for IPMI ++ * 1.5 and 20 for IPMI 2.0. */ ++ printf(" -d, --authType : Specify the IPMI 1.5 authentication type to use (NONE, STRAIGHT_PASSWORD_KEY, MD2, and MD5) with the remote host (default=MD5)\n"); ++ printf(" -D, --cipher_suite_id : Specify the IPMI 2.0 cipher suite ID to use, for authentication, integrity, and confidentiality (default=3)\n"); ++ } ++ + printf("\nNUT specific options:\n"); + printf(" -p, --port : Port number of remote NUT upsd\n"); + printf("\ndisplay specific options:\n"); +@@ -427,11 +493,11 @@ display_help: + if( allow_ipmi && nutscan_avail_ipmi) { + printq(quiet,"Scanning IPMI bus.\n"); + #ifdef HAVE_PTHREAD +- if(pthread_create(&thread[TYPE_IPMI],NULL,run_ipmi,NULL)) { ++ if(pthread_create(&thread[TYPE_IPMI],NULL,run_ipmi,&ipmi_sec)) { + nutscan_avail_ipmi = 0; + } + #else +- dev[TYPE_IPMI] = nutscan_scan_ipmi(); ++ dev[TYPE_IPMI] = nutscan_scan_ipmi(start_ip,end_ip,timeout,&ipmi_sec); + #endif /* HAVE_PTHREAD */ + } + +diff --git a/tools/nut-scanner/scan_ipmi.c b/tools/nut-scanner/scan_ipmi.c +index c1ec78a..0288ad4 100644 +--- a/tools/nut-scanner/scan_ipmi.c ++++ b/tools/nut-scanner/scan_ipmi.c +@@ -29,6 +29,11 @@ + + #define NUT_IPMI_DRV_NAME "nut-ipmipsu" + ++/* IPMI defines */ ++/* 5 seconds for establishing an IPMI connection */ ++#define IPMI_SESSION_TIMEOUT_LENGTH_DEFAULT 5000 ++#define IPMI_RETRANSMISSION_TIMEOUT_LENGTH_DEFAULT 250 ++ + /* dynamic link library stuff */ + static char * libname = "libfreeipmi"; + static lt_dlhandle dl_handle = NULL; +@@ -88,10 +93,23 @@ static int (*nut_ipmi_ctx_find_inband) (ipmi_ctx_t ctx, + const char *driver_device, + unsigned int workaround_flags, + unsigned int flags); ++static int (*nut_ipmi_ctx_open_outofband) (ipmi_ctx_t ctx, ++ const char *hostname, ++ const char *username, ++ const char *password, ++ uint8_t authentication_type, ++ uint8_t privilege_level, ++ unsigned int session_timeout, ++ unsigned int retransmission_timeout, ++ unsigned int workaround_flags, ++ unsigned int flags); ++static int (*nut_ipmi_ctx_errnum) (ipmi_ctx_t ctx); + static char * (*nut_ipmi_ctx_errormsg) (ipmi_ctx_t ctx); + static int (*nut_ipmi_ctx_close) (ipmi_ctx_t ctx); + static void (*nut_ipmi_ctx_destroy) (ipmi_ctx_t ctx); + ++/* Internal functions */ ++static nutscan_device_t * nutscan_scan_ipmi_device(const char * IPaddr, nutscan_ipmi_t * sec); + + /* Return 0 on error */ + int nutscan_load_ipmi_library() +@@ -189,6 +207,16 @@ int nutscan_load_ipmi_library() + goto err; + } + ++ *(void **) (&nut_ipmi_ctx_open_outofband) = lt_dlsym(dl_handle, "ipmi_ctx_open_outofband"); ++ if ((dl_error = lt_dlerror()) != NULL) { ++ goto err; ++ } ++ ++ *(void **) (&nut_ipmi_ctx_errnum) = lt_dlsym(dl_handle, "ipmi_ctx_errnum"); ++ if ((dl_error = lt_dlerror()) != NULL) { ++ goto err; ++ } ++ + *(void **) (&nut_ipmi_ctx_errormsg) = lt_dlsym(dl_handle, "ipmi_ctx_errormsg"); + if ((dl_error = lt_dlerror()) != NULL) { + goto err; +@@ -265,10 +293,10 @@ int is_ipmi_device_supported(ipmi_ctx_t ipmi_ctx, int ipmi_id) + /* Parse FRU information */ + if (!(fru_parse_ctx = (*nut_ipmi_fru_ctx_create) (ipmi_ctx))) + { +- fprintf(stderr, "ipmi_fru_parse_ctx_create()\n"); ++ fprintf(stderr, "Error with %s(): %s\n", IPMI_FRU_CTX_CREATE, (*nut_ipmi_ctx_errormsg)(ipmi_ctx)); + return 0; + } +-fprintf(stdout, "There.1\n"); ++ + /* lots of motherboards calculate checksums incorrectly */ + if ((*nut_ipmi_fru_ctx_set_flags) (fru_parse_ctx, IPMI_FRU_FLAGS_SKIP_CHECKSUM_CHECKS) < 0) + { +@@ -279,7 +307,7 @@ fprintf(stdout, "There.1\n"); + #endif /* HAVE_FREEIPMI_11X_12X */ + return 0; + } +-fprintf(stdout, "There.2\n"); ++ + if ((*nut_ipmi_fru_open_device_id) (fru_parse_ctx, ipmi_id) < 0) + { + #ifdef HAVE_FREEIPMI_11X_12X +@@ -292,7 +320,6 @@ fprintf(stdout, "There.2\n"); + + do + { +-fprintf(stdout, "There.3\n"); + /* clear fields */ + area_type = 0; + area_length = 0; +@@ -337,20 +364,21 @@ fprintf(stdout, "There.3\n"); + return 0; + } + +-/* return NULL on error */ +-nutscan_device_t * nutscan_scan_ipmi() ++/* Check for IPMI support on a specific (local or remote) system ++ * Return NULL on error, or a valid nutscan_device_t otherwise */ ++nutscan_device_t * nutscan_scan_ipmi_device(const char * IPaddr, nutscan_ipmi_t * ipmi_sec) + { + ipmi_ctx_t ipmi_ctx = NULL; + nutscan_device_t * nut_dev = NULL; + nutscan_device_t * current_nut_dev = NULL; + int ret = -1; + int ipmi_id = 0; +- char port_id[10]; ++ char port_id[64]; + + if( !nutscan_avail_ipmi ) { + return NULL; + } +-fprintf(stdout, "There1\n"); ++ + /* Initialize the FreeIPMI library. */ + if (!(ipmi_ctx = (*nut_ipmi_ctx_create) ())) + { +@@ -359,34 +387,138 @@ fprintf(stdout, "There1\n"); + return NULL; + } + +-fprintf(stdout, "There2\n"); +- if ((ret = (*nut_ipmi_ctx_find_inband) (ipmi_ctx, +- NULL, +- 0, /* don't disable auto-probe */ +- 0, +- 0, +- NULL, +- 0, /* workaround flags, none by default */ +- IPMI_FLAGS_NONBLOCKING /* flags */ +- )) < 0) ++ /* Are we scanning locally, or over the network? */ ++ if (IPaddr == NULL) + { +- fprintf(stderr, "ipmi_ctx_find_inband: %s\n", +- (*nut_ipmi_ctx_errormsg) (ipmi_ctx)); +- return NULL; ++ /* FIXME: we need root right to access local IPMI! ++ if (!ipmi_is_root ()) { ++ fprintf(stderr, "IPMI scan: %s\n", ipmi_ctx_strerror (IPMI_ERR_PERMISSION)); ++ } */ ++ ++ if ((ret = (*nut_ipmi_ctx_find_inband) (ipmi_ctx, ++ NULL, ++ 0, /* don't disable auto-probe */ ++ 0, ++ 0, ++ NULL, ++ 0, /* workaround flags, none by default */ ++ 0 /* flags */ ++ )) < 0) ++ { ++ fprintf(stderr, "ipmi_ctx_find_inband: %s\n", ++ (*nut_ipmi_ctx_errormsg) (ipmi_ctx)); ++ return NULL; ++ } ++ if (!ret) ++ { ++ /* No local IPMI device detected */ ++ return NULL; ++ } + } +- if (!ret) +- { +- /* No local IPMI device detected */ +- return NULL; ++ else { ++ ++#if 0 ++ if (ipmi_sec->ipmi_version == IPMI_2_0) { ++ ++ /* FIXME: need processing?! ++ * int parse_kg (void *out, unsigned int outlen, const char *in) ++ * if ((rv = parse_kg (common_cmd_args_config->k_g, IPMI_MAX_K_G_LENGTH + 1, data->string)) < 0) ++ * { ++ * fprintf (stderr, "Config File Error: k_g input formatted incorrectly\n"); ++ * exit (EXIT_FAILURE); ++ * }*/ ++ if ((ret = (*nut_ipmi_ctx_open_outofband_2_0) (ipmi_ctx, ++ IPaddr, ++ ipmi_sec->username, ++ ipmi_sec->password, ++ ipmi_sec->K_g_BMC_key, ++??? (ipmi_sec->K_g_BMC_key) ? config->k_g_len : 0, ++ ipmi_sec->privilege_level, ++ ipmi_sec->cipher_suite_id, ++ IPMI_SESSION_TIMEOUT_LENGTH_DEFAULT, ++ IPMI_RETRANSMISSION_TIMEOUT_LENGTH_DEFAULT, ++ ipmi_dev->workaround_flags, ++ flags) < 0) ++ { ++ IPMI_MONITORING_DEBUG (("ipmi_ctx_open_outofband_2_0: %s", ipmi_ctx_errormsg (c->ipmi_ctx))); ++ if (ipmi_ctx_errnum (c->ipmi_ctx) == IPMI_ERR_USERNAME_INVALID) ++ c->errnum = IPMI_MONITORING_ERR_USERNAME_INVALID; ++ else if (ipmi_ctx_errnum (c->ipmi_ctx) == IPMI_ERR_PASSWORD_INVALID) ++ c->errnum = IPMI_MONITORING_ERR_PASSWORD_INVALID; ++ else if (ipmi_ctx_errnum (c->ipmi_ctx) == IPMI_ERR_PRIVILEGE_LEVEL_INSUFFICIENT) ++ c->errnum = IPMI_MONITORING_ERR_PRIVILEGE_LEVEL_INSUFFICIENT; ++ else if (ipmi_ctx_errnum (c->ipmi_ctx) == IPMI_ERR_PRIVILEGE_LEVEL_CANNOT_BE_OBTAINED) ++ c->errnum = IPMI_MONITORING_ERR_PRIVILEGEL_LEVEL_CANNOT_BE_OBTAINED; ++ else if (ipmi_ctx_errnum (c->ipmi_ctx) == IPMI_ERR_K_G_INVALID) ++ c->errnum = IPMI_MONITORING_ERR_K_G_INVALID; ++ else if (ipmi_ctx_errnum (c->ipmi_ctx) == IPMI_ERR_CIPHER_SUITE_ID_UNAVAILABLE) ++ c->errnum = IPMI_MONITORING_ERR_CIPHER_SUITE_ID_UNAVAILABLE; ++ else if (ipmi_ctx_errnum (c->ipmi_ctx) == IPMI_ERR_PASSWORD_VERIFICATION_TIMEOUT) ++ c->errnum = IPMI_MONITORING_ERR_PASSWORD_VERIFICATION_TIMEOUT; ++ else if (ipmi_ctx_errnum (c->ipmi_ctx) == IPMI_ERR_IPMI_2_0_UNAVAILABLE) ++ c->errnum = IPMI_MONITORING_ERR_IPMI_2_0_UNAVAILABLE; ++ else if (ipmi_ctx_errnum (c->ipmi_ctx) == IPMI_ERR_CONNECTION_TIMEOUT) ++ c->errnum = IPMI_MONITORING_ERR_CONNECTION_TIMEOUT; ++ else if (ipmi_ctx_errnum (c->ipmi_ctx) == IPMI_ERR_SESSION_TIMEOUT) ++ c->errnum = IPMI_MONITORING_ERR_SESSION_TIMEOUT; ++ else if (ipmi_ctx_errnum (c->ipmi_ctx) == IPMI_ERR_BAD_COMPLETION_CODE ++ || ipmi_ctx_errnum (c->ipmi_ctx) == IPMI_ERR_IPMI_ERROR) ++ c->errnum = IPMI_MONITORING_ERR_IPMI_ERROR; ++ else if (ipmi_ctx_errnum (c->ipmi_ctx) == IPMI_ERR_BMC_BUSY) ++ c->errnum = IPMI_MONITORING_ERR_BMC_BUSY; ++ else if (ipmi_ctx_errnum (c->ipmi_ctx) == IPMI_ERR_OUT_OF_MEMORY) ++ c->errnum = IPMI_MONITORING_ERR_OUT_OF_MEMORY; ++ else if (ipmi_ctx_errnum (c->ipmi_ctx) == IPMI_ERR_HOSTNAME_INVALID) ++ c->errnum = IPMI_MONITORING_ERR_HOSTNAME_INVALID; ++ else if (ipmi_ctx_errnum (c->ipmi_ctx) == IPMI_ERR_PARAMETERS) ++ c->errnum = IPMI_MONITORING_ERR_PARAMETERS; ++ else if (ipmi_ctx_errnum (c->ipmi_ctx) == IPMI_ERR_SYSTEM_ERROR) ++ c->errnum = IPMI_MONITORING_ERR_SYSTEM_ERROR; ++ else ++ c->errnum = IPMI_MONITORING_ERR_INTERNAL_ERROR; ++ return (-1); ++ } ++ } ++ else { /* Not IPMI 2.0 */ ++ ++#endif /* 0 */ ++ ++ /* Fall back to IPMI 1.5 */ ++ if ((ret = (*nut_ipmi_ctx_open_outofband) (ipmi_ctx, ++ IPaddr, ++ ipmi_sec->username, ++ ipmi_sec->password, ++ ipmi_sec->authentication_type, ++ ipmi_sec->privilege_level, ++ IPMI_SESSION_TIMEOUT_LENGTH_DEFAULT, ++ IPMI_RETRANSMISSION_TIMEOUT_LENGTH_DEFAULT, ++ ipmi_sec->workaround_flags, ++ IPMI_FLAGS_DEFAULT ++ )) < 0) ++ { ++ /* No IPMI device detected on this host! ++ if ((*nut_ipmi_ctx_errnum) (ipmi_ctx) == IPMI_ERR_USERNAME_INVALID ++ || (*nut_ipmi_ctx_errnum) (ipmi_ctx) == IPMI_ERR_PASSWORD_INVALID ++ || (*nut_ipmi_ctx_errnum) (ipmi_ctx) == IPMI_ERR_PRIVILEGE_LEVEL_INSUFFICIENT ++ || (*nut_ipmi_ctx_errnum) (ipmi_ctx) == IPMI_ERR_PRIVILEGE_LEVEL_CANNOT_BE_OBTAINED ++ || (*nut_ipmi_ctx_errnum) (ipmi_ctx) == IPMI_ERR_AUTHENTICATION_TYPE_UNAVAILABLE ++ || (*nut_ipmi_ctx_errnum) (ipmi_ctx) == IPMI_ERR_PASSWORD_VERIFICATION_TIMEOUT ++ || (*nut_ipmi_ctx_errnum) (ipmi_ctx) == IPMI_ERR_HOSTNAME_INVALID ++ || (*nut_ipmi_ctx_errnum) (ipmi_ctx) == IPMI_ERR_CONNECTION_TIMEOUT) { */ ++ ++ /* FIXME: don't log timeout errors */ ++ fprintf(stderr, "nut_ipmi_ctx_open_outofband: %s\n", ++ (*nut_ipmi_ctx_errormsg) (ipmi_ctx)); ++ return NULL; ++ /*}*/ ++ } + } +-fprintf(stdout, "There3 (ret = %i)\n", ret); + + /* Loop through all possible components */ + for (ipmi_id = 0 ; ipmi_id <= IPMI_FRU_DEVICE_ID_MAX ; ipmi_id++) { +-fprintf(stdout, "There4\n"); ++ + if (is_ipmi_device_supported(ipmi_ctx, ipmi_id)) { + +-fprintf(stdout, "There4.%i\n", ipmi_id); + if ( (nut_dev = nutscan_new_device()) == NULL ) { + fprintf(stderr,"Memory allocation error\n"); + nutscan_free_device(current_nut_dev); +@@ -396,9 +528,17 @@ fprintf(stdout, "There4.%i\n", ipmi_id); + /* Fill the device structure (sufficient with driver and port) */ + nut_dev->type = TYPE_IPMI; + nut_dev->driver = strdup(NUT_IPMI_DRV_NAME); +- sprintf(port_id, "id%x", ipmi_id); ++ if (IPaddr == NULL) { ++ sprintf(port_id, "id%x", ipmi_id); ++ } ++ else { ++ /* FIXME: also check against "localhost" and its IPv{4,6} */ ++ sprintf(port_id, "id%x@%s", ipmi_id, IPaddr); ++ } + nut_dev->port = strdup(port_id); +- ++ /* FIXME: also dump device.serial? ++ * using drivers/libfreeipmi_get_board_info() */ ++ + current_nut_dev = nutscan_add_device_to_device( + current_nut_dev, + nut_dev); +@@ -415,9 +555,50 @@ fprintf(stdout, "There4.%i\n", ipmi_id); + + return current_nut_dev; + } ++ ++/* General IPMI scan entry point: scan 1 to n devices, local or remote, ++ * for IPMI support ++ * Return NULL on error, or a valid nutscan_device_t otherwise */ ++nutscan_device_t * nutscan_scan_ipmi(const char * start_ip, const char * stop_ip, nutscan_ipmi_t * sec) ++{ ++ nutscan_ip_iter_t ip; ++ char * ip_str = NULL; ++ nutscan_ipmi_t * tmp_sec; ++ nutscan_device_t * nut_dev = NULL; ++ nutscan_device_t * current_nut_dev = NULL; ++ ++ if( !nutscan_avail_ipmi ) { ++ return NULL; ++ } ++ ++ ++ /* Are we scanning locally, or through the network? */ ++ if (start_ip == NULL) ++ { ++ /* Local PSU scan */ ++ current_nut_dev = nutscan_scan_ipmi_device(NULL, NULL); ++ } ++ else { ++ ip_str = nutscan_ip_iter_init(&ip, start_ip, stop_ip); ++ ++ while(ip_str != NULL) { ++ tmp_sec = malloc(sizeof(nutscan_ipmi_t)); ++ memcpy(tmp_sec, sec, sizeof(nutscan_ipmi_t)); ++ ++ if ((current_nut_dev = nutscan_scan_ipmi_device(ip_str, tmp_sec)) != NULL) { ++ /* Store the positive result */ ++ current_nut_dev = nutscan_add_device_to_device(current_nut_dev, nut_dev); ++ } ++ /* Prepare the next iteration */ ++ ip_str = nutscan_ip_iter_inc(&ip); ++ }; ++ } ++ ++ return current_nut_dev; ++} + #else /* WITH_IPMI */ + /* stub function */ +-nutscan_device_t * nutscan_scan_ipmi() ++nutscan_device_t * nutscan_scan_ipmi(const char * startIP, const char * stopIP, nutscan_ipmi_t * sec) + { + return NULL; + } +-- +1.7.10.2 + + +From 3d0002653a506f2acb24be2201724e7b785de784 Mon Sep 17 00:00:00 2001 +From: Arnaud Quette +Date: Fri, 5 Oct 2012 10:27:55 +0000 +Subject: [PATCH] Fix compilation error + +Define IPMI_PRIVILEGE_LEVEL_ADMIN value, in case FreeIPMI is not +available + +Fossil-ID: SVN r3741 +--- + tools/nut-scanner/nut-scan.h | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/tools/nut-scanner/nut-scan.h b/tools/nut-scanner/nut-scan.h +index 8b9f1ab..b853d96 100644 +--- a/tools/nut-scanner/nut-scan.h ++++ b/tools/nut-scanner/nut-scan.h +@@ -64,7 +64,10 @@ typedef struct nutscan_ipmi { + #define IPMI_AUTHENTICATION_TYPE_STRAIGHT_PASSWORD_KEY 0x04 + #define IPMI_AUTHENTICATION_TYPE_OEM_PROP 0x05 + #define IPMI_AUTHENTICATION_TYPE_RMCPPLUS 0x06 +-#endif /* IPMI_AUTHENTICATION_TYPE_NONE */ ++#endif ++#ifndef IPMI_PRIVILEGE_LEVEL_ADMIN ++ #define IPMI_PRIVILEGE_LEVEL_ADMIN 0x04 ++#endif + + #define IPMI_1_5 1 + #define IPMI_2_0 0 +-- +1.7.10.2 + + +From 605ef0a46fbb8519b849683028f7e6cf35eb2fdd Mon Sep 17 00:00:00 2001 +From: Arnaud Quette +Date: Thu, 11 Apr 2013 23:15:51 +0200 +Subject: [PATCH] Set USB timeout to 5 seconds + +Set the low level USB timeout back to the standard +5 seconds. This was set to 4 seconds, for performance +reasons, but is now causing issues with some devices +(reported by Stefan "stevenbg", GitHub issue #23) +--- + drivers/libusb.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/drivers/libusb.c b/drivers/libusb.c +index 50bfc7f..234b9f1 100644 +--- a/drivers/libusb.c ++++ b/drivers/libusb.c +@@ -33,12 +33,11 @@ + #include "usb-common.h" + #include "libusb.h" + +-/* USB standard state 5000, but we've decreased it to +- * improve reactivity */ +-#define USB_TIMEOUT 4000 ++/* USB standard timeout */ ++#define USB_TIMEOUT 5000 + + #define USB_DRIVER_NAME "USB communication driver" +-#define USB_DRIVER_VERSION "0.31" ++#define USB_DRIVER_VERSION "0.32" + + /* driver description structure */ + upsdrv_info_t comm_upsdrv_info = { +-- +1.7.10.2 +